[
  {
    "path": ".codecov.yaml",
    "content": "coverage:\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 0.3%\n      windows:\n        target: auto\n        flags: [windows]\n      ubuntu:\n        target: auto\n        flags: [ubuntu]\n\nflags:\n  windows:\n  ubuntu:\n"
  },
  {
    "path": ".dockerignore",
    "content": "k6\ndist\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\nindent_style = tab\nindent_size = 4\n\n[*.md]\nindent_style = space\ntrim_trailing_whitespace = false\n\n[*.yml]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug.yaml",
    "content": "name: Bug report\ndescription: Use this template for reporting bugs. Please search existing issues first.\nlabels: bug\nbody:\n  - type: textarea\n    attributes:\n      label: Brief summary\n    validations:\n      required: true\n  - type: markdown\n    attributes:\n      value: '## Environment'\n  - type: input\n    attributes:\n      label: k6 version\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: OS\n      description: e.g. Windows 10, Arch Linux, macOS 11, etc.\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: Docker version and image (if applicable)\n  - type: markdown\n    attributes:\n      value: '## Detailed issue description'\n  - type: textarea\n    attributes:\n      label: Steps to reproduce the problem\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Expected behaviour\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Actual behaviour\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: k6 Community Forum\n    url: https://community.grafana.com/c/grafana-k6/70\n    about: Please ask and answer questions here.\n  - name: k6 Documentation\n    url: https://github.com/grafana/k6-docs\n    about: Please add any documentation related issues here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feat_req.yaml",
    "content": "name: Feature Request\ndescription: Use this template for suggesting new features.\nlabels: feature\nbody:\n  - type: textarea\n    attributes:\n      label: Feature Description\n      description: A clear and concise description of the problem or missing capability\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Suggested Solution (optional)\n      description: If you have a solution in mind, please describe it.\n  - type: textarea\n    attributes:\n      label: Already existing or connected issues / PRs (optional)\n      description: If you have found some issues or pull requests that are related to your new issue, please link them here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/release.md",
    "content": "---\nname: k6 Release\nabout: k6 release accommodates activities and a checklist with the k6 open-source release process.\ntitle: 'k6 release v1.x.0'\nlabels: [\"release\"]\n---\n\n**Release Date**:\n\n25th May 2026 **<- WRITE HERE THE UPDATED RELEASE DATE**\n\n## Release Activities\n\n### At the beginning of the cycle\n\n- [ ] Create a new `release-v{major}.{minor}.0` branch.\n    - [ ] Add a new release notes file using the available [template](https://github.com/grafana/k6/blob/master/release%20notes/template.md) to the [repository's `release notes` folder](https://github.com/grafana/k6/blob/master/release%20notes).\n    - [ ] Go through the potential [dependencies updates](https://github.com/grafana/k6/blob/master/Dependencies.md) and create a dedicated PR if any of them is relevant to this release.\n- [ ] Create a new `release-v{major}.{minor}.0` branch on the [grafana/k6-DefinitelyTyped](https://github.com/grafana/k6-DefinitelyTyped) fork repository.\n    - [ ] Bump the version in [types/k6/package.json](https://github.com/grafana/k6-DefinitelyTyped/blob/master/types/k6/package.json#L4) to the next one.\n- [ ] [Lock the conversation](https://docs.github.com/en/communities/moderating-comments-and-conversations/locking-conversations) of the current issue to prevent any abuse or misuse of the issue. Note, it still allow the maintainers to edit the issue's description and to add comments.\n\n### Release Preparation\n\n#### ~ 2 weeks before the release date\n\n- [ ] Ensure that all PRs from a release milestone are merged.\n- [ ] Ensure experimental modules (if needed) have been updated to their latest version.\n\n#### ~ 1 week before the release date\n\n- [ ] Ensure that all merged PRs referenced in the release notes are linked to the release milestone.\n- [ ] Ensure all PRs in the `k6-docs` repository related to new or modified functionalities introduced by the new version have been created.\n- [ ] Ensure all PRs in the `k6` repository, part of the current [milestone](https://github.com/grafana/k6/milestones), have been merged.\n- [ ] Open a PR with the release notes for the new version\n  - [ ] Ask teams that might have contributed to the release (e.g., k6-ecosystem, k6-docs, k6-devrel teams) to contribute their notes and review the existing ones.\n  - [ ] Remember to mention and thank [external contributors](https://github.com/search?q=user%3Agrafana+repo%3Ak6+milestone%3A%22v1.3.0%22+-author%3Amstoykov+-author%3Aoleiade+-author%3Ana--+-author%3Acodebien+-author%3Aolegbespalov+-author%3Aandrewslotin+-author%3Ajoanlopez+-author%3Aankur22+-author%3Ainancgumus+-author%3aszkiba+-author%3aAgnesToulet+-author%3Adependabot%5Bbot%5D&type=pullrequests). (**<- Update the query with the correct milestone version**).\n- [ ] Share the release notes PR with the k6 open-source teams. Request contributions from all affected teams (k6-chaos, k6-docs, k6-devrel, etc.) and any other stakeholders involved in the new release.\n- [ ] Open a separate PR for bumping [the k6 Go project's version](https://github.com/grafana/k6/blob/master/internal/build/version.go#L6).\n- [ ] Open a PR in the `DefinitelyTyped/DefinitelyTyped` repository using the release branch created in the grafana/k6-DefinitelyTyped fork to update the k6 type definitions for the new release.\n- [ ] Open a PR to add the new k6 version to the extensions registry (similar to [this one](https://github.com/grafana/k6-extension-registry/pull/104) for v1.3.0).\n\n#### ~ 1 day before the release date\n\n- [ ] Ensure all PRs in the `k6-docs` repository related to new or modified functionalities introduced by the new version have been merged.\n\n### Release Day\n\n#### Documentation\n\n- [ ] Open and merge a PR from `main` in the `k6-docs` repository:\n  - [ ] Creating a new `v{major}.{minor}.0` file in the [next release notes folder](https://github.com/grafana/k6-docs/tree/main/docs/sources/k6/next/release-notes) and copy/paste the main sections of the release notes (new features, deprecations and roadmap).\n  - [ ] Copying the current k6's `next` (including the newly created release note file) to a folder named with the k6 version (e.g., `v1.3.x`).\n- [ ] Ensure the `k6` repository release notes PR contains the correct links to the docs.\n\n#### In k6 repository\n\n- [ ] Merge the PR bumping [the k6 Go project's version](https://github.com/grafana/k6/blob/master/lib/consts/consts.go#L11-L12).\n- [ ] Merge the release notes PR.\n- [ ] Pull locally the previously merged changes.\n- [ ] Create a new long-lived `v{major}.{minor}.x` release branch from the `master` branch.\n- [ ] Create and push a new tag of the form `v{major}.{minor}.0`.\n\n!!! Update the below when making the issue\n\n```\ngit checkout master && git pull && git checkout -b v1.3.x && git tag v1.3.0 -m \"v1.3.0\" && git push origin v1.3.0\n```\n\n#### In k6-extension-registry\n\n- [ ] Merge the PR adding [the new k6 version](https://github.com/grafana/k6-extension-registry/blob/main/registry.yaml#L8).\n\n#### Announcements\n\n- [ ] Notify the larger team in the #k6 and #k6-changelog channels, letting them know that the release is published by linking the release on GitHub.\n- [ ] Close the release's milestone.\n\n## Wrapping Release\n\n- [ ] Ensure the `DefinitelyTyped/DefinitelyTyped` PR(s) are merged.\n- [ ] Ensure to sync `grafana/k6-DefinitelyTyped` fork with the latest changes from the `DefinitelyTyped/DefinitelyTyped` repository.\n- [ ] Update the k6 repository's `.github/ISSUE_TEMPLATE/release.md` in the event steps from this checklist were incorrect or missing.\n"
  },
  {
    "path": ".github/actions/lint/action.yml",
    "content": "name: golangci-lint-k6\ndescription: Run golangci-lint with the k6 ruleset\n\nruns:\n  using: composite\n  steps:\n    - name: Install Go\n      uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n      with:\n        go-version: 1.26.x\n        check-latest: true\n    - name: Get golangci-lint version and download rules\n      shell: bash\n      env:\n        GITHUB_ACTION_REF: ${{ github.action_ref }}\n        GITHUB_HEAD_REF: ${{  github.head_ref }}\n        REPO_FULL_NAME: ${{ github.event.pull_request.head.repo.full_name }}\n      run: |\n        branch=\"master\"\n        if [ \"${REPO_FULL_NAME}\" = \"grafana/k6\" ]; then\n          branch=\"${GITHUB_ACTION_REF:-${GITHUB_HEAD_REF}}\"\n        fi\n        rules_url=\"https://raw.githubusercontent.com/grafana/k6/${branch}/.golangci.yml\"\n        echo \"Downloading '${rules_url}' ...\"\n        curl --silent --show-error --fail --no-location \"${rules_url}\" --output \"${{ github.action_path }}/.golangci.yml\"\n\n        echo \"GolangCIVersion=$(head -n 1 \"${{ github.action_path }}/.golangci.yml\" | tr -d '# ')\" >> \"${GITHUB_OUTPUT}\"\n      id: getenv\n    - name: golangci-lint\n      uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0\n      with:\n        version: ${{ steps.getenv.outputs.GolangCIVersion }}\n        args: \"--config=${{ github.action_path }}/.golangci.yml\"\n"
  },
  {
    "path": ".github/actions/test/action.yml",
    "content": "name: \"Test\"\ndescription: \"Run all tests except ones in browser/tests package\"\n\ninputs:\n  platform:\n    description: \"matrix.platform value (used for windows/arm detection).\"\n    required: true\n  use_gotip:\n    description: \"whether to set up gotip env variables or not\"\n    required: false\n    default: \"false\"\n\nruns:\n  using: \"composite\"\n  steps:\n    - name: Run tests\n      shell: bash\n      env:\n        PLATFORM: ${{ inputs.platform }}\n        USE_GOTIP: ${{ inputs.use_gotip }}\n      run: |\n        set -x\n\n        if [[ ${USE_GOTIP} == 'true' ]]; then\n          export GOROOT=\"$HOME/sdk/gotip\"\n          export GOPATH=\"$HOME/go\"\n          export PATH=\"$HOME/sdk/gotip/bin:$HOME/go/bin:$PATH\" > /dev/null\n        fi\n\n        which go\n        go version\n        export GOMAXPROCS=2\n        args=(\"-p\" \"2\" \"-race\")\n        # Run with less concurrency on Windows/ARM to minimize flakiness.\n        if [[ \"${PLATFORM}\" == windows* || \"${PLATFORM}\" == *arm ]]; then\n          args[1]=\"1\"\n          export GOMAXPROCS=1\n          if [[ \"${PLATFORM}\" == windows* ]]; then\n            unset args[2]\n          fi\n        fi\n        go test \"${args[@]}\" -timeout 1600s `go list ./... | grep -v browser/tests`\n"
  },
  {
    "path": ".github/actions/test-browser/action.yml",
    "content": "name: \"Test browser\"\ndescription: \"Run only tests in browser/tests package without parallel execution\"\n\ninputs:\n  use_gotip:\n    description: \"whether to set up gotip env variables or not\"\n    required: false\n    default: \"false\"\n\nruns:\n  using: \"composite\"\n  steps:\n    - name: Run tests\n      shell: bash\n      env:\n        USE_GOTIP: ${{ inputs.use_gotip }}\n      run: |\n        set -x\n\n        if [[ ${USE_GOTIP} == 'true' ]]; then\n          export GOROOT=\"$HOME/sdk/gotip\"\n          export GOPATH=\"$HOME/go\"\n          export PATH=\"$HOME/sdk/gotip/bin:$HOME/go/bin:$PATH\" > /dev/null\n        fi\n\n        which go\n        go version\n        export GOMAXPROCS=1\n        go test -p 1 -timeout 1600s ./internal/js/modules/k6/browser/tests/...\n"
  },
  {
    "path": ".github/actions/test-common/action.yml",
    "content": "name: \"Test common\"\ndescription: \"Pre-test steps: Go install and optional Chromium install\"\n\ninputs:\n  go_version:\n    description: \"Go version (eg 1.26.x) or gotip.\"\n    required: false\n    default: \"1.26.x\"\n  platform:\n    description: \"matrix.platform value (used for windows/arm detection).\"\n    required: true\n\nruns:\n  using: \"composite\"\n  steps:\n    - name: Install Go\n      if: ${{ inputs.go_version != 'gotip' }}\n      uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n      with:\n        go-version: ${{ inputs.go_version }}\n        check-latest: true\n\n    - name: Download and install Go tip\n      if: ${{ inputs.go_version == 'gotip' }}\n      shell: bash\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        PLATFORM: ${{ inputs.platform }}\n      run: |\n        gh release download ${PLATFORM} --repo grafana/gotip --pattern 'go.zip'\n        unzip go.zip -d $HOME/sdk\n\n    - name: Install chromium\n      # This is only needed on arm images, chromium comes preinstalled on amd64 runner images.\n      if: ${{contains(inputs.platform, 'arm') }}\n      shell: bash\n      run: |\n        sudo apt update && sudo apt install chromium-browser\n        chromium --version || true\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "## What?\n\n<!-- A short (or detailed) description of what this PR does. -->\n\n## Why?\n\n<!-- A short (or detailed) explanation of why these changes are made and needed. -->\n\n## Checklist\n\n<!-- \nIf you haven't read the contributing guidelines https://github.com/grafana/k6/blob/master/CONTRIBUTING.md \nand code of conduct https://github.com/grafana/k6/blob/master/CODE_OF_CONDUCT.md yet, please do so\n-->\n\n- [ ] I have performed a self-review of my code.\n- [ ] I have commented on my code, particularly in hard-to-understand areas.\n- [ ] I have added tests for my changes.\n- [ ] I have run linter and tests locally (`make check`) and all pass.\n\n## Checklist: Documentation (only for k6 maintainers and if relevant)\n\n**Please do not merge this PR until the following items are filled out.**\n\n- [ ] I have added the correct milestone and labels to the PR.\n- [ ] I have updated the release notes: _link_\n- [ ] I have updated or added an issue to the [k6-documentation](https://github.com/grafana/k6-docs): grafana/k6-docs#NUMBER if applicable\n- [ ] I have updated or added an issue to the [TypeScript definitions](https://github.com/grafana/k6-DefinitelyTyped/tree/master/types/k6): grafana/k6-DefinitelyTyped#NUMBER if applicable\n\n<!-- - [ ] Any other relevant item -->\n\n## Related PR(s)/Issue(s)\n\n<!-- - <https://github.com/grafana/...> -->\n\n<!-- Does it close an issue? -->\n\n<!-- Closes #ISSUE-ID -->\n\n<!-- Thanks for your contribution! 🙏🏼 -->\n"
  },
  {
    "path": ".github/workflows/browser_e2e.yml",
    "content": "name: E2E\non:\n  # Enable manually triggering this workflow via the API or web UI\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n  pull_request:\n  schedule:\n    # At 06:00 AM UTC from Monday through Friday\n    - cron:  '0 6 * * 1-5'\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    strategy:\n      fail-fast: false\n      matrix:\n        go: [stable, tip]\n        platform: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Install Go\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n        with:\n          go-version: 1.x\n      - name: Install Go tip\n        if: matrix.go == 'tip'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          gh release download ${{ matrix.platform }} --repo grafana/gotip --pattern 'go.zip'\n          unzip go.zip -d $HOME/sdk\n          echo \"GOROOT=$HOME/sdk/gotip\" >> \"$GITHUB_ENV\"\n          echo \"GOPATH=$HOME/go\" >> \"$GITHUB_ENV\"\n          echo \"$HOME/go/bin\" >> \"$GITHUB_PATH\"\n          echo \"$HOME/sdk/gotip/bin\" >> \"$GITHUB_PATH\"\n      - name: Install chromium\n        # This is only needed on arm images, chromium comes preinstalled on amd64 runner images.\n        if: contains(matrix.platform, 'arm')\n        run: |\n          sudo apt update && sudo apt install chromium-browser\n          chromium --version\n      - name: Build k6\n        run: |\n          which go\n          go version\n\n          go build .\n          ./k6 version\n      - name: Run E2E tests\n        run: |\n          set -x\n          if [ \"$RUNNER_OS\" == \"Linux\" ] && [ \"$RUNNER_ARCH\" == \"X64\" ]; then\n            export K6_BROWSER_EXECUTABLE_PATH=/usr/bin/google-chrome\n          fi\n          export K6_BROWSER_HEADLESS=true\n          export K6_NO_USAGE_REPORT=true\n          for f in examples/browser/*.js; do\n            if [ \"$f\" == \"examples/browser/hosts.js\" ] && [ \"$RUNNER_OS\" == \"Windows\" ]; then\n              echo \"skipping $f on Windows\"\n              continue\n            fi\n            ./k6 run -q \"$f\"\n          done\n      - name: Check screenshot\n        # TODO: Do something more sophisticated?\n        run: test -s screenshot.png\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build\non:\n  workflow_dispatch:\n    inputs:\n      k6_version:\n        description: 'The version of the release, it must use the semantic versioning format with the v prefix. It is a development release so it is suggested to append a build metadata (e.g. v0.38.0-dev).'\n        required: true\n      go_version:\n        description: 'Go version for building binaries'\n        default: '1.x'\n        required: true\n  push:\n    branches:\n      - master\n    tags:\n      - v*\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\nenv:\n  APP_NAME: \"k6\"\n  DOCKER_IMAGE_ID: \"grafana/k6\"\n  GHCR_IMAGE_ID: ${{ github.repository }}\n  DEFAULT_GO_VERSION: \"1.26.x\"\n\njobs:\n  configure:\n    runs-on: ubuntu-latest\n    outputs:\n      k6_version: ${{ steps.get_k6_version.outputs.k6_version }}\n      go_version: ${{ steps.get_go_version.outputs.go_version }}\n      sign_windows_artifacts: ${{ steps.determine_windows_signing.outputs.sign_windows_artifacts }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n      - name: Get the k6 version\n        id: get_k6_version\n        env:\n          INPUT_K6_VERSION: ${{ github.event.inputs.k6_version  }}\n        run: |\n          set -x # Show exactly what commands are executed\n          if [[ \"${GITHUB_EVENT_NAME}\" == \"workflow_dispatch\" ]] && [[ \"${INPUT_K6_VERSION}\" != \"\" ]]; then\n            VERSION=\"${INPUT_K6_VERSION}\"\n            echo \"Building custom dev build with version '${VERSION}' from manual workflow_dispatch...\"\n          elif [[ \"${GITHUB_REF}\" =~ ^refs/tags/v.+$ ]]; then\n            VERSION=\"${GITHUB_REF##*/}\"\n            echo \"Building real version tag '${GITHUB_REF}', parsed '${VERSION}' as the actual version...\"\n          else\n            VERSION=\"$(git describe --tags --always --long --dirty)\"\n            echo \"Building a non-version ref '${GITHUB_REF}', use '${VERSION}' as the version instead...\"\n          fi\n          echo \"VERSION=${VERSION}\"\n          echo \"k6_version=${VERSION}\" >> $GITHUB_OUTPUT\n      - name: Get the used Go version\n        id: get_go_version\n        env:\n          INPUT_GO_VERSION: ${{ github.event.inputs.go_version  }}\n        run: |\n          set -x # Show exactly what commands are executed\n          if [[ \"${GITHUB_EVENT_NAME}\" == \"workflow_dispatch\" ]] && [[ \"${INPUT_GO_VERSION}\" != \"\" ]]; then\n            GO_VERSION=\"${INPUT_GO_VERSION}\"\n            echo \"Using custom Go version '${GO_VERSION}' from manual workflow_dispatch...\"\n          else\n            GO_VERSION=\"${DEFAULT_GO_VERSION}\"\n            echo \"Using the default Go version '${GO_VERSION}'...\"\n          fi\n          echo \"GO_VERSION=${GO_VERSION}\"\n          echo \"go_version=${GO_VERSION}\" >> $GITHUB_OUTPUT\n\n      # Secrets are unavailable when building from project forks, so this\n      # will fail for external PRs, even if we wanted to do it. And we don't.\n      # We are only going to sign packages that are built from the default branch\n      # or a version tag, or manually triggered dev builds, so we have enough\n      # assurance that package signing works, but don't sign every PR build.\n      - name: Determine whether to sign the Windows artifacts\n        id: determine_windows_signing\n        env:\n          SIGN_FILES: ${{ github.ref_name == github.event.repository.default_branch || startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }}\n        run: |\n          set -x # Show exactly what commands are executed\n          if [[ \"${SIGN_FILES}\" == \"true\" ]]; then\n            echo \"Windows artifacts will be signed\"\n            sign_windows_artifacts=\"true\"\n          else\n            echo \"Windows artifacts will not be signed\"\n            sign_windows_artifacts=\"false\"\n          fi\n          echo \"sign_windows_artifacts=${sign_windows_artifacts}\" >> ${GITHUB_OUTPUT}\n\n  build:\n    runs-on: ubuntu-latest\n    needs: [configure]\n    env:\n      VERSION: ${{ needs.configure.outputs.k6_version }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n      - name: Install Go\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n        with:\n          go-version: ${{ needs.configure.outputs.go_version }}\n          check-latest: true\n          cache: false # against cache-poisoning\n      - name: Install nfpm (dep and rpm package builder)\n        run: |\n          go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.16.0\n      - name: Install goversioninfo (.syso file creator)\n        run: |\n          go install github.com/josephspurrier/goversioninfo/cmd/goversioninfo@v1.4.0\n      - name: Generate Windows binary metadata (.syso files)\n        run: |\n          IFS=. read -a version_parts <<< \"${VERSION#v}\"\n          IFS=- read -a version_patch <<< \"${version_parts[2]}\"\n\n          # Need a blank versioninfo.json for the CLI overrides to work.\n          echo '{}' > versioninfo.json\n          set -x\n          goversioninfo -64 \\\n            -platform-specific=true \\\n            -charset=\"1200\" \\\n            -company=\"Raintank Inc. d.b.a. Grafana Labs\" \\\n            -copyright=\"© Raintank Inc. d.b.a. Grafana Labs. Licensed under AGPL.\" \\\n            -description=\"A modern load testing tool, using Go and JavaScript\" \\\n            -icon=packaging/k6.ico \\\n            -internal-name=\"k6\" \\\n            -original-name=\"k6.exe\" \\\n            -product-name=\"k6\" \\\n            -translation=\"0x0409\" \\\n            -ver-major=\"${version_parts[0]}\" \\\n            -ver-minor=\"${version_parts[1]}\" \\\n            -ver-patch=\"${version_patch[0]}\" \\\n            -special-build=$(IFS='-'; echo \"${version_patch[*]:1}\";) \\\n            -product-version=\"${VERSION#v}\"\n\n          set +x\n          ls -lah | grep -i syso\n\n      - name: Build\n        run: |\n          go version\n          ./build-release.sh \"dist\" \"${VERSION}\"\n      - name: Upload artifacts\n        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5\n        with:\n          name: binaries\n          path: dist/\n          retention-days: 7\n\n  build-docker:\n    permissions:\n      contents: read\n      packages: write\n      id-token: write\n    runs-on: ubuntu-latest\n    needs: [configure]\n    env:\n      VERSION: ${{ needs.configure.outputs.k6_version }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n      - name: Build\n        run: |\n          docker buildx create \\\n            --name multibuilder \\\n            --platform linux/amd64,linux/arm64 \\\n            --bootstrap --use\n          docker buildx build \\\n            --target release \\\n            --platform linux/amd64,linux/arm64 \\\n            -t $DOCKER_IMAGE_ID .\n      - name: Check\n        run: |\n          docker buildx build --load -t $DOCKER_IMAGE_ID .\n          # Assert that simple cases works for the new built image\n          docker run $DOCKER_IMAGE_ID version\n          docker run $DOCKER_IMAGE_ID --help\n          docker run $DOCKER_IMAGE_ID help\n          docker run $DOCKER_IMAGE_ID run --help\n          docker run $DOCKER_IMAGE_ID inspect --help\n          docker run $DOCKER_IMAGE_ID status --help\n          docker run $DOCKER_IMAGE_ID stats --help\n          docker run $DOCKER_IMAGE_ID scale --help\n          docker run $DOCKER_IMAGE_ID pause --help\n          docker run $DOCKER_IMAGE_ID resume --help\n      - name: Login to DockerHub\n        if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }}\n        uses: grafana/shared-workflows/actions/dockerhub-login@081a366728379fd0426b9cfef190e9a21c2d5418 # dockerhub-login/v1.0.3\n      - name: Login to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        env:\n          GITHUB_ACTOR: ${{ github.actor }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          registry: ghcr.io\n          username: ${{ env.GITHUB_ACTOR }}\n          password: ${{ env.GITHUB_TOKEN }}\n        if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }}\n      - name: Publish k6:master images\n        if: ${{ github.ref == 'refs/heads/master' }}\n        run: |\n          echo \"Publish $GHCR_IMAGE_ID:master* images\"\n          docker buildx build --push \\\n            --target release \\\n            --platform linux/amd64,linux/arm64 \\\n            -t $DOCKER_IMAGE_ID:master \\\n            -t ghcr.io/$GHCR_IMAGE_ID:master .\n          docker buildx build --push \\\n            --target with-browser \\\n            --platform linux/amd64,linux/arm64 \\\n            -t $DOCKER_IMAGE_ID:master-with-browser \\\n            -t ghcr.io/$GHCR_IMAGE_ID:master-with-browser .\n      - name: Publish tagged version images\n        if: ${{ startsWith(github.ref, 'refs/tags/v') }}\n        run: |\n          VERSION=\"${VERSION#v}\"\n          echo \"Publish $GHCR_IMAGE_ID:$VERSION images\"\n          docker buildx build --push \\\n            --target release \\\n            --platform linux/amd64,linux/arm64 \\\n            -t $DOCKER_IMAGE_ID:$VERSION \\\n            -t ghcr.io/$GHCR_IMAGE_ID:$VERSION .\n          docker buildx build --push \\\n            --target with-browser \\\n            --platform linux/amd64,linux/arm64 \\\n            -t $DOCKER_IMAGE_ID:$VERSION-with-browser \\\n            -t ghcr.io/$GHCR_IMAGE_ID:$VERSION-with-browser .\n          # We also want to tag the latest stable version as latest\n          echo \"Publish $GHCR_IMAGE_ID:latest\"\n          docker buildx build --push \\\n            --target release \\\n            --platform linux/amd64,linux/arm64 \\\n            -t $DOCKER_IMAGE_ID:latest \\\n            -t ghcr.io/$GHCR_IMAGE_ID:latest .\n          docker buildx build --push \\\n            --target with-browser \\\n            --platform linux/amd64,linux/arm64 \\\n            -t $DOCKER_IMAGE_ID:latest-with-browser \\\n            -t ghcr.io/$GHCR_IMAGE_ID:latest-with-browser .\n\n  # Forks, PRs etc. won't actually sign the binary, but the workflow will run most of the same steps as\n  # GitHub Actions workflows don't support conditional `needs` so we have to run the signing step unconditionally.\n  sign-binaries:\n    permissions:\n      contents: read\n      actions: read\n      id-token: write # Required for Vault\n\n    env:\n      VERSION: ${{ needs.configure.outputs.k6_version }}\n\n    environment:\n      name: azure-trusted-signing\n\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: pwsh\n    needs: [configure, build]\n    outputs:\n      binary_artifact_name: ${{ steps.assign-artifact-names.outputs.binary-artifact-name }}\n      windows_binary_artifact_name: ${{ steps.assign-artifact-names.outputs.windows-binary-artifact-name }}\n    steps:\n      - name: Download binaries\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        with:\n          name: binaries\n          path: dist\n\n      - name: Unzip Windows binary\n        run: |\n          Expand-Archive -Path \".\\dist\\k6-${env:VERSION}-windows-amd64.zip\" -DestinationPath .\\packaging\\\n\n      - name: Upload artifact for Windows installer build\n        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5\n        with:\n          name: windows-binary\n          path: 'packaging/k6-${{ env.VERSION }}-windows-amd64/k6.exe'\n          retention-days: 7\n          if-no-files-found: error\n\n      - name: Get secrets for Azure Trusted Signing\n        uses: grafana/shared-workflows/actions/get-vault-secrets@f1614b210386ac420af6807a997ac7f6d96e477a # get-vault-secrets/v1.3.1\n        id: get-signing-secrets\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        with:\n          export_env: false\n          repo_secrets: |\n            client-id=azure-trusted-signing:client-id\n            subscription-id=azure-trusted-signing:subscription-id\n            tenant-id=azure-trusted-signing:tenant-id\n\n      - name: Sign Windows binary\n        uses: grafana/shared-workflows/actions/azure-trusted-signing@e86cdb1c0a8cf5df57d3078f285261f7c9577174 # azure-trusted-signing/v1.0.0\n        id: sign-artifacts\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        with:\n          application-description: 'Grafana k6'\n          artifact-to-sign: 'windows-binary'\n          azure-client-id: ${{ fromJSON(steps.get-signing-secrets.outputs.secrets).client-id }}\n          azure-subscription-id: ${{ fromJSON(steps.get-signing-secrets.outputs.secrets).subscription-id }}\n          azure-tenant-id: ${{ fromJSON(steps.get-signing-secrets.outputs.secrets).tenant-id }}\n          signed-artifact-name: 'windows-binary-signed'\n\n      - name: Download signed Windows binary\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        with:\n          name: ${{ steps.sign-artifacts.outputs.artifact-name }}\n          path: 'packaging/k6-${{ env.VERSION }}-windows-amd64'\n\n      # Re-zip the signed Windows binary to replace the original unsigned version\n      - name: Zip signed Windows binary\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        run: |\n          Compress-Archive -Path \".\\packaging\\*\" -DestinationPath \".\\dist\\k6-${env:VERSION}-windows-amd64.zip\" -Force\n\n      - name: Upload signed artifacts\n        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        with:\n          name: binaries-signed\n          path: dist/\n          retention-days: 7\n          if-no-files-found: error\n\n      - name: Assign artifact name for Windows binary for installer build\n        id: assign-artifact-names\n        env:\n          BINARY_ARTIFACT_NAME: ${{ needs.configure.outputs.sign_windows_artifacts == 'true' && 'binaries-signed' || 'binaries' }}\n          WINDOWS_BINARY_ARTIFACT_NAME: ${{ needs.configure.outputs.sign_windows_artifacts == 'true' && steps.sign-artifacts.outputs.artifact-name || 'windows-binary' }}\n        run: |\n          echo \"binary-artifact-name=${env:BINARY_ARTIFACT_NAME}\" >> ${env:GITHUB_OUTPUT}\n          echo \"windows-binary-artifact-name=${env:WINDOWS_BINARY_ARTIFACT_NAME}\" >> ${env:GITHUB_OUTPUT}\n\n  package:\n    permissions:\n      contents: read\n      actions: read\n\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: pwsh\n    needs: [configure, build, sign-binaries]\n    env:\n      VERSION: ${{ needs.configure.outputs.k6_version }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Install pandoc\n        uses: crazy-max/ghaction-chocolatey@2526f467ccbd337d307fe179959cabbeca0bc8c0 # v3.4.0\n        with:\n          args: install -y pandoc\n      - name: Install wix tools\n        run: |\n          curl -Lso wix311-binaries.zip https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip\n          Expand-Archive -Path .\\wix311-binaries.zip -DestinationPath .\\wix311\\\n          echo \"$pwd\\wix311\" | Out-File -FilePath $env:GITHUB_PATH -Append\n      - name: Download Windows binary\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        with:\n          name: ${{ needs.sign-binaries.outputs.windows_binary_artifact_name }}\n          path: packaging\n\n      - name: Create the MSI package\n        run: |\n          $env:VERSION = $env:VERSION -replace 'v(\\d+\\.\\d+\\.\\d+).*','$1'\n          pandoc -s -f markdown -t rtf -o packaging\\LICENSE.rtf LICENSE.md\n          cd .\\packaging\n          candle.exe -arch x64 \"-dVERSION=${env:VERSION}\" k6.wxs\n          light.exe -ext WixUIExtension k6.wixobj\n\n      - name: Rename MSI package\n        # To keep it consistent with the other artifacts\n        run: move \"packaging\\k6.msi\" \"packaging\\k6-${env:VERSION}-windows-amd64.msi\"\n\n      - name: Upload Windows installer\n        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5\n        with:\n          name: binaries-windows\n          path: |\n            packaging/k6-*.msi\n          retention-days: 7\n          if-no-files-found: error\n\n  # Forks, PRs etc. won't actually sign the installer, but the workflow will run most of the same steps as\n  # GitHub Actions workflows don't support conditional `needs` so we have to run the signing step unconditionally.\n  sign-packages:\n    permissions:\n      actions: read\n      contents: read\n      id-token: write # Required for Vault\n\n    environment:\n      name: azure-trusted-signing\n\n    outputs:\n      artifact_name: ${{ steps.assign-artifact-name.outputs.artifact-name }}\n\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: pwsh\n    needs: [configure, package]\n    steps:\n      - name: Download Windows artifacts\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        with:\n          name: binaries-windows\n          path: packaging\n\n      - name: Get secrets for Azure Trusted Signing\n        uses: grafana/shared-workflows/actions/get-vault-secrets@f1614b210386ac420af6807a997ac7f6d96e477a # get-vault-secrets/v1.3.1\n        id: get-signing-secrets\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        with:\n          export_env: false\n          repo_secrets: |\n            client-id=azure-trusted-signing:client-id\n            subscription-id=azure-trusted-signing:subscription-id\n            tenant-id=azure-trusted-signing:tenant-id\n\n      - name: Sign Windows installer\n        uses: grafana/shared-workflows/actions/azure-trusted-signing@e86cdb1c0a8cf5df57d3078f285261f7c9577174 # azure-trusted-signing/v1.0.0\n        id: sign-artifacts\n        if: needs.configure.outputs.sign_windows_artifacts == 'true'\n        with:\n          application-description: 'Grafana k6'\n          artifact-to-sign: 'binaries-windows'\n          azure-client-id: ${{ fromJSON(steps.get-signing-secrets.outputs.secrets).client-id }}\n          azure-subscription-id: ${{ fromJSON(steps.get-signing-secrets.outputs.secrets).subscription-id }}\n          azure-tenant-id: ${{ fromJSON(steps.get-signing-secrets.outputs.secrets).tenant-id }}\n          signed-artifact-name: 'binaries-windows-signed'\n\n      - name: Assign artifact name for Windows installer\n        id: assign-artifact-name\n        env:\n          ARTIFACT_NAME: ${{ needs.configure.outputs.sign_windows_artifacts == 'true' && steps.sign-artifacts.outputs.artifact-name || 'binaries-windows' }}\n        run: |\n          echo \"artifact-name=${env:ARTIFACT_NAME}\" >> ${env:GITHUB_OUTPUT}\n\n  publish-github:\n    runs-on: ubuntu-latest\n    needs: [configure, sign-binaries, sign-packages]\n    if: ${{ startsWith(github.ref, 'refs/tags/v') && github.event_name != 'workflow_dispatch' }}\n    env:\n      VERSION: ${{ needs.configure.outputs.k6_version }}\n    permissions:\n       actions: read\n       contents: write\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Download binaries\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        with:\n          name: ${{ needs.sign-binaries.outputs.binary_artifact_name }}\n          path: dist\n      - name: Download Windows binaries\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        with:\n          name: ${{ needs.sign-packages.outputs.artifact_name }}\n          path: dist\n      - name: Generate checksum file\n        run: cd dist && sha256sum * > \"k6-${VERSION}-checksums.txt\"\n      - name: Anchore SBOM Action\n        continue-on-error: true\n        uses: anchore/sbom-action@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2\n        with:\n          artifact-name: k6-${{ env.VERSION }}-spdx.json\n          upload-release-assets: false\n          output-file: dist/k6-${{ env.VERSION }}-spdx.json\n      - name: Create release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          set -x\n          assets=()\n          for asset in ./dist/*; do\n            assets+=(\"$asset\")\n          done\n          gh release create \"$VERSION\" \"${assets[@]}\" --target \"$GITHUB_SHA\" -F \"./release notes/${VERSION}.md\"\n\n  submit-winget-manifest:\n    needs: [configure, publish-github]\n    runs-on: windows-2025\n    permissions:\n      contents: read\n      id-token: write\n    steps:\n\n    - name: Install WingetCreate\n      shell: pwsh\n      run: |\n        Import-Module Appx -UseWindowsPowerShell\n        $appxBundleFile = Join-Path ${env:RUNNER_TEMP} \"wingetcreate.msixbundle\"\n        Invoke-WebRequest https://aka.ms/wingetcreate/latest/msixbundle -OutFile $appxBundleFile\n        Add-AppxPackage $appxBundleFile\n\n    - name: Get WinGet token\n      uses: grafana/shared-workflows/actions/get-vault-secrets@f1614b210386ac420af6807a997ac7f6d96e477a # get-vault-secrets/v1.3.1\n      id: get-token\n      with:\n        export_env: false\n        common_secrets: |\n          token=winget-packages:token\n\n    - name: Submit WinGet Manifest\n      env:\n        PACKAGE_ID: GrafanaLabs.k6\n        PACKAGE_VERSION: ${{ needs.configure.outputs.k6_version }}\n        WINGET_CREATE_GITHUB_TOKEN: ${{ fromJSON(steps.get-token.outputs.secrets).token }}\n      shell: pwsh\n      run: |\n        wingetcreate token --store\n        wingetcreate update ${env:PACKAGE_ID} `\n          --urls \"${env:GITHUB_SERVER_URL}/${env:GITHUB_REPOSITORY}/releases/download/${env:PACKAGE_VERSION}/k6-${env:PACKAGE_VERSION}-windows-amd64.msi\" `\n          --version ${env:PACKAGE_VERSION}.TrimStart(\"v\") `\n          --submit\n\n  publish-packages:\n    runs-on: ubuntu-latest\n    needs: [configure, sign-binaries, sign-packages]\n    if: ${{ startsWith(github.ref, 'refs/tags/v') && github.event_name != 'workflow_dispatch' }}\n    env:\n      VERSION: ${{ needs.configure.outputs.k6_version }}\n    permissions:\n      actions: read\n      contents: read\n      packages: write\n      id-token: write # Required for Vault\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Download binaries\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        with:\n          name: ${{ needs.sign-binaries.outputs.binary_artifact_name }}\n          path: dist\n      - name: Download Windows binaries\n        uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6\n        with:\n          name: ${{ needs.sign-packages.outputs.artifact_name }}\n          path: dist\n      - name: Rename binaries\n        # To be consistent with the filenames used in dl.k6.io\n        run: |\n          mv \"dist/k6-$VERSION-windows-amd64.msi\" \"dist/k6-$VERSION-amd64.msi\"\n          mv \"dist/k6-$VERSION-linux-amd64.rpm\" \"dist/k6-$VERSION-amd64.rpm\"\n          mv \"dist/k6-$VERSION-linux-amd64.deb\" \"dist/k6-$VERSION-amd64.deb\"\n      - uses: grafana/shared-workflows/actions/get-vault-secrets@f1614b210386ac420af6807a997ac7f6d96e477a # get-vault-secrets/v1.3.1\n        with:\n          repo_secrets: |\n            IAM_ROLE_ARN=deploy:packager-iam-role\n            AWS_CF_DISTRIBUTION=cloudfront:AWS_CF_DISTRIBUTION\n            PGP_SIGN_KEY_PASSPHRASE=pgp:PGP_SIGN_KEY_PASSPHRASE\n            PGP_SIGN_KEY=pgp:PGP_SIGN_KEY\n            S3_BUCKET=s3:AWS_S3_BUCKET\n      - uses: grafana/shared-workflows/actions/aws-auth@85022085ed5314601c05d10e846de56bdd71e369 # aws-auth/v1.0.3\n        with:\n          aws-region: \"us-east-2\"\n          role-arn: ${{ env.IAM_ROLE_ARN }}\n          set-creds-in-environment: true\n      - name: Setup docker compose environment\n        run: |\n          cat > packaging/.env <<EOF\n          AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}\n          AWS_CF_DISTRIBUTION=\"${AWS_CF_DISTRIBUTION}\"\n          AWS_DEFAULT_REGION=us-east-2\n          AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}\n          AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}\n          PGP_SIGN_KEY_PASSPHRASE=${PGP_SIGN_KEY_PASSPHRASE}\n          S3_BUCKET=${S3_BUCKET}\n          EOF\n          echo \"${PGP_SIGN_KEY}\" > packaging/sign-key.gpg\n      - name: Login to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        env:\n          GITHUB_ACTOR: ${{ github.actor }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        with:\n          registry: ghcr.io\n          username: ${{ env.GITHUB_ACTOR }}\n          password: ${{ env.GITHUB_TOKEN }}\n      - name: Publish packages\n        run: |\n          cd packaging\n          docker compose pull packager\n          docker compose run --rm packager\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ master ]\n\npermissions:\n  contents: read\n  security-events: write\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Checkout repo\n      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n      with:\n        persist-credentials: false\n\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4\n      with:\n        languages: go\n\n    - name: CodeQL Analysis\n      uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4\n"
  },
  {
    "path": ".github/workflows/issue-auto-assign.yml",
    "content": "name: \"Auto assign maintainer to issue\"\non:\n  # makes this workflow re-usable\n  workflow_call:\n  issues:\n    types: [opened]\n  issue_comment:\n    types: [created]\n\npermissions:\n  issues: write\n\njobs:\n  assign-user:\n    runs-on: ubuntu-latest\n    # issue_comment triggers for both, issues and prs,\n    # as we need to run only on issues, it filter out prs.\n    if: ${{ !github.event.issue.pull_request }}\n    steps:\n      - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8\n        with:\n          script: |\n            const assignees = ['ankur22', 'codebien', 'inancgumus', 'joanlopez', 'mstoykov', 'oleiade', 'szkiba'];\n            const teamMembers = assignees.concat(['andrewslotin']);\n            const assigneeCount = 1;\n\n            // Do not automatically assign users if someone was already assigned or it was opened by a team member\n            if (context.payload.issue.assignees.length > 0 || teamMembers.includes(context.actor)) {\n              return;\n            }\n            const crypto = require(\"node:crypto\");\n\n            const getNRandom = (n, array) => {\n              let result = new Array();\n              for (;n > 0 && array.length > 0; n--) {\n                const chosen = array[crypto.randomInt(array.length)];\n                result.push(chosen);\n                array = array.filter(el => el != chosen);\n              }\n              return result;\n            }\n\n            github.rest.issues.addAssignees({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n              assignees: getNRandom(assigneeCount, assignees),\n            });\n            github.rest.issues.addLabels({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n              labels: [\"triage\"]\n            });\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Lint\non:\n  # Enable manually triggering this workflow via the API or web UI\n  workflow_dispatch:\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\njobs:\n  deps:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n          fetch-depth: 0\n      - name: Install Go\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n        with:\n          go-version: 1.26.x\n          check-latest: true\n      - name: Check dependencies\n        run: |\n            go version\n            test -z \"$(go mod tidy && go mod vendor && git status --porcelain)\"\n            go mod verify\n      - name: Check code generation\n        run: |\n          make generate\n          test -z \"$(git status --porcelain | tee >(cat 1>&2))\"\n\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n          fetch-depth: 0\n      - name: Run linters\n        uses: ./.github/actions/lint/\n"
  },
  {
    "path": ".github/workflows/packager.yml",
    "content": "name: k6packager\non:\n  # Enable manually triggering this workflow via the API or web UI\n  workflow_dispatch:\n  schedule:\n    - cron: '0 0 * * 0' # weekly (Sundays at 00:00)\n\ndefaults:\n  run:\n    shell: bash\n\njobs:\n  publish-packager:\n    runs-on: ubuntu-latest\n    env:\n      VERSION: 0.0.4\n      DOCKER_IMAGE_ID: ghcr.io/grafana/k6packager\n      GITHUB_ACTOR: ${{ github.actor }}\n      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n    permissions:\n      contents: read\n      id-token: write\n      packages: write\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Build\n        run: |\n          cd packaging\n          docker compose build packager\n      - name: Login to GitHub Container Registry\n        uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0\n        with:\n          registry: ghcr.io\n          username: ${{ env.GITHUB_ACTOR }}\n          password: ${{ env.GITHUB_TOKEN }}\n      - name: Publish\n        run: |\n          docker push \"${DOCKER_IMAGE_ID}:latest\"\n          docker tag \"${DOCKER_IMAGE_ID}\" \"${DOCKER_IMAGE_ID}:${VERSION}\"\n          docker push \"${DOCKER_IMAGE_ID}:${VERSION}\"\n"
  },
  {
    "path": ".github/workflows/publish-techdocs.yaml",
    "content": "name: Publish TechDocs\non:\n  push:\n    branches:\n      - master\n    paths:\n      - 'docs/docs/**'\n      - 'docs/mkdocs.yml'\n      - 'catalog-info.yaml'\n      - '.github/workflows/publish-techdocs.yaml'\nconcurrency:\n  group: '${{ github.workflow }}-${{ github.ref }}'\n  cancel-in-progress: true\npermissions: {}\njobs:\n  publish-docs:\n    uses: grafana/shared-workflows/.github/workflows/publish-techdocs.yaml@main\n    permissions:\n      contents: read\n      id-token: write\n    with:\n      namespace: default\n      kind: component\n      name: k6\n      default-working-directory: .\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Close stale PRs\n\non:\n  schedule:\n    - cron: \"0 8 * * 1\" # once per week, at 08:00 on Mondays\n\npermissions:\n  pull-requests: write\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Run stale action\n        uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n          operations-per-run: 50\n          ascending: true # process oldest PRs first\n\n          days-before-pr-stale: 61\n          days-before-pr-close: 7\n\n          stale-pr-label: stale\n          exempt-pr-labels: \"wip\"\n\n          stale-pr-message: |\n            This pull request has been automatically marked as stale because it has not had\n            activity in the last two months. It will be closed in one week if no further activity occurs. Please\n            feel free to give a status update or ping for review. Thank you for your contributions!\n          close-pr-message: |\n            Closing this pull request due to two months of inactivity after being marked stale. Thank you for your contributions!\n"
  },
  {
    "path": ".github/workflows/summary-code-generation.yml",
    "content": "name: Summary code generation\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\njobs:\n  check-generated-code:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n\n      - name: Install cog\n        run: |\n          COG_VERSION=\"v0.0.46\"\n          curl -sSL \"https://github.com/grafana/cog/releases/download/${COG_VERSION}/cog_Linux_x86_64.tar.gz\" \\\n            | sudo tar -xz -C /usr/local/bin\n          cog --version\n\n      - name: Checkout schemas\n        run: |\n          ./internal/lib/summary/machinereadable/checkout.sh\n\n      - name: Generate code\n        run: |\n          ./internal/lib/summary/machinereadable/generate.sh\n\n      - name: Check for uncommitted changes\n        run: |\n          # Check if there are any changes in the Git working directory\n          if ! git diff --exit-code; then\n            echo \"❌ Generated code is not up-to-date!\"\n            echo \"\"\n            echo \"The following files have uncommitted changes:\"\n            git diff --name-only\n            echo \"\"\n            echo \"Please run the following commands to update the generated code:\"\n            echo \"  ./internal/lib/summary/machinereadable/checkout.sh\"\n            echo \"  ./internal/lib/summary/machinereadable/generate.sh\"\n            echo \"\"\n            echo \"Then commit the changes.\"\n            exit 1\n          fi\n\n          # Also check for untracked files\n          if [ -n \"$(git ls-files --others --exclude-standard internal/lib/summary/machinereadable/ | grep -v k6-summary/)\" ]; then\n            echo \"❌ There are untracked generated files!\"\n            echo \"\"\n            echo \"Untracked files:\"\n            git ls-files --others --exclude-standard internal/lib/summary/machinereadable/ | grep -v k6-summary/\n            echo \"\"\n            echo \"Please run the generation scripts and commit all generated files.\"\n            exit 1\n          fi\n\n          echo \"✅ Generated code is up-to-date!\"\n"
  },
  {
    "path": ".github/workflows/tc39.yml",
    "content": "name: TC39\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n  pull_request:\n      paths:\n          - 'js/**'\n          - 'internal/js/**'\n          - 'vendor/github.com/grafana/sobek/**'\n          - 'vendor/github.com/evanw/esbuild**'\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\n\njobs:\n  tc39:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Install Go\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n        with:\n          go-version: 1.26.x\n          check-latest: true\n      - name: Run tests\n        run: |\n          set -x\n          cd internal/js/tc39\n          sh checkout.sh\n          go test -timeout 1h\n"
  },
  {
    "path": ".github/workflows/test-browser.yml",
    "content": "name: Browser tests\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\njobs:\n  test-prev:\n    if: ${{ github.ref == 'refs/heads/master' }}\n    strategy:\n      fail-fast: false\n      matrix:\n        go-version: [1.25.x]\n        platform:\n          [ubuntu-22.04, ubuntu-arm64-large, github-hosted-windows-x64-large]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n      - name: Run common test steps\n        uses: ./.github/actions/test-common\n        with:\n          go_version: ${{ matrix.go-version }}\n          platform: ${{ matrix.platform }}\n      - name: Get the k6 version\n        id: get_k6_version\n        run: |\n          echo \"Running tests on '${GITHUB_REF}' with '$(git describe --tags --always --long --dirty)' checked out...\"\n      - name: Run tests\n        uses: ./.github/actions/test-browser\n\n  test-tip:\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - platform: ubuntu-22.04\n            gotip_platform: ubuntu-22.04\n          - platform: ubuntu-arm64-large\n            gotip_platform: ubuntu-24.04-arm\n          - platform: github-hosted-windows-x64-large\n            gotip_platform: windows-latest\n    runs-on: ${{ matrix.platform }}\n    continue-on-error: true\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Run common test steps\n        uses: ./.github/actions/test-common\n        with:\n          go_version: \"gotip\"\n          platform: ${{ matrix.gotip_platform }}\n      - name: Run tests\n        uses: ./.github/actions/test-browser\n        with:\n          use_gotip: \"true\"\n\n  test-latest:\n    strategy:\n      fail-fast: false\n      matrix:\n        go-version: [1.26.x]\n        platform:\n          [ubuntu-22.04, ubuntu-arm64-large, github-hosted-windows-x64-large]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Run common test steps\n        uses: ./.github/actions/test-common\n        with:\n          go_version: ${{ matrix.go-version }}\n          platform: ${{ matrix.platform }}\n      - name: Run tests\n        uses: ./.github/actions/test-browser\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\njobs:\n  test-prev:\n    if: ${{ github.ref == 'refs/heads/master' }}\n    strategy:\n      fail-fast: false\n      matrix:\n        go-version: [1.25.x]\n        platform: [ubuntu-22.04, ubuntu-24.04-arm, windows-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          fetch-depth: 0\n          persist-credentials: false\n      - name: Run common test steps\n        uses: ./.github/actions/test-common\n        with:\n          go_version: ${{ matrix.go-version }}\n          platform: ${{ matrix.platform }}\n      - name: Get the k6 version\n        id: get_k6_version\n        run: |\n          echo \"Running tests on '${GITHUB_REF}' with '$(git describe --tags --always --long --dirty)' checked out...\"\n      - name: Run tests\n        uses: ./.github/actions/test\n        with:\n          platform: ${{ matrix.platform }}\n\n  test-tip:\n    strategy:\n      fail-fast: false\n      matrix:\n        platform: [ubuntu-22.04, ubuntu-24.04-arm, windows-latest]\n    runs-on: ${{ matrix.platform }}\n    continue-on-error: true\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Run common test steps\n        uses: ./.github/actions/test-common\n        with:\n          go_version: \"gotip\"\n          platform: ${{ matrix.platform }}\n      - name: Run tests\n        uses: ./.github/actions/test\n        with:\n          use_gotip: \"true\"\n          platform: ${{ matrix.platform }}\n  \n  test-latest:\n    strategy:\n      fail-fast: false\n      matrix:\n        go-version: [1.26.x]\n        platform: [ubuntu-22.04, ubuntu-24.04-arm, windows-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Run common test steps\n        uses: ./.github/actions/test-common\n        with:\n          go_version: ${{ matrix.go-version }}\n          platform: ${{ matrix.platform }}\n      - name: Run tests\n        uses: ./.github/actions/test\n        with:\n          platform: ${{ matrix.platform }}\n"
  },
  {
    "path": ".github/workflows/wpt.yml",
    "content": "name: Web Platform Tests\non:\n  workflow_dispatch:\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Install Go\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n        with:\n          go-version: 1.26.x\n          check-latest: true\n      # TODO: combine WebPlatform tests checkout & patch into the single step\n      - name: Run Streams Tests\n        run: |\n          set -x\n          cd internal/js/modules/k6/experimental/streams/tests\n          sh checkout.sh\n          go test -race ../...\n      - name: Run Webcrypto Tests\n        run: |\n          set -x\n          cd internal/js/modules/k6/webcrypto/tests\n          sh checkout.sh\n          go test -race ./...\n"
  },
  {
    "path": ".github/workflows/xk6-tests/xk6-js-test/go.mod",
    "content": "module github.com/grafana/xk6-js-test\n\ngo 1.23.0\n\ntoolchain go1.23.7\n\nrequire go.k6.io/k6 v0.57.0\n\nrequire (\n\tgithub.com/cenkalti/backoff/v4 v4.3.0 // indirect\n\tgithub.com/dlclark/regexp2 v1.11.4 // indirect\n\tgithub.com/evanw/esbuild v0.24.2 // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/go-logr/logr v1.4.2 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect\n\tgithub.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/grafana/sobek v0.0.0-20241024150027-d91f02b05e9b // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/mailru/easyjson v0.9.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.14 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd // indirect\n\tgithub.com/onsi/ginkgo v1.16.5 // indirect\n\tgithub.com/onsi/gomega v1.27.1 // indirect\n\tgithub.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e // indirect\n\tgithub.com/sirupsen/logrus v1.9.3 // indirect\n\tgithub.com/spf13/afero v1.1.2 // indirect\n\tgo.opentelemetry.io/otel v1.31.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.31.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.31.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.31.0 // indirect\n\tgo.opentelemetry.io/proto/otlp v1.3.1 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.33.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgolang.org/x/time v0.9.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect\n\tgoogle.golang.org/grpc v1.69.4 // indirect\n\tgoogle.golang.org/protobuf v1.36.3 // indirect\n\tgopkg.in/guregu/null.v3 v3.3.0 // indirect\n)\n"
  },
  {
    "path": ".github/workflows/xk6-tests/xk6-js-test/go.sum",
    "content": "github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=\ngithub.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=\ngithub.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=\ngithub.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=\ngithub.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=\ngithub.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=\ngithub.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=\ngithub.com/evanw/esbuild v0.24.2 h1:PQExybVBrjHjN6/JJiShRGIXh1hWVm6NepVnhZhrt0A=\ngithub.com/evanw/esbuild v0.24.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=\ngithub.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=\ngithub.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=\ngithub.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 h1:ZgoomqkdjGbQ3+qQXCkvYMCDvGDNg2k5JJDjjdTB6jY=\ngithub.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grafana/sobek v0.0.0-20241024150027-d91f02b05e9b h1:hzfIt1lf19Zx1jIYdeHvuWS266W+jL+7dxbpvH2PZMQ=\ngithub.com/grafana/sobek v0.0.0-20241024150027-d91f02b05e9b/go.mod h1:FmcutBFPLiGgroH42I4/HBahv7GxVjODcVWFTw1ISes=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=\ngithub.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=\ngithub.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=\ngithub.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mccutchen/go-httpbin v1.1.2-0.20190116014521-c5cb2f4802fa h1:lx8ZnNPwjkXSzOROz0cg69RlErRXs+L3eDkggASWKLo=\ngithub.com/mccutchen/go-httpbin v1.1.2-0.20190116014521-c5cb2f4802fa/go.mod h1:fhpOYavp5g2K74XDl/ao2y4KvhqVtKlkg1e+0UaQv7I=\ngithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd h1:AC3N94irbx2kWGA8f/2Ks7EQl2LxKIRQYuT9IJDwgiI=\ngithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd/go.mod h1:9vRHVuLCjoFfE3GT06X0spdOAO+Zzo4AMjdIwUHBvAk=\ngithub.com/mstoykov/envconfig v1.5.0 h1:E2FgWf73BQt0ddgn7aoITkQHmgwAcHup1s//MsS5/f8=\ngithub.com/mstoykov/envconfig v1.5.0/go.mod h1:vk/d9jpexY2Z9Bb0uB4Ndesss1Sr0Z9ZiGUrg5o9VGk=\ngithub.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=\ngithub.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=\ngithub.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=\ngithub.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\ngithub.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=\ngithub.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=\ngithub.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\ngithub.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=\ngithub.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=\ngithub.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e h1:zWKUYT07mGmVBH+9UgnHXd/ekCK99C8EbDSAt5qsjXE=\ngithub.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=\ngithub.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=\ngithub.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=\ngithub.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=\ngithub.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngo.k6.io/k6 v0.57.0 h1:l1jivNtbCQYNhgvl+O6SfzwabqNlazr8OLYjxm8lNGw=\ngo.k6.io/k6 v0.57.0/go.mod h1:AXTOq8X59VqigGvoI59Al/+8F/5h4iHO0CoX0lNbq/4=\ngo.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=\ngo.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc=\ngo.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=\ngo.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=\ngo.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=\ngo.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=\ngo.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=\ngo.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=\ngo.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=\ngo.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=\ngo.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=\ngo.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=\ngolang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=\ngolang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=\ngolang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=\ngolang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=\ngolang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=\ngoogle.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=\ngoogle.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=\ngoogle.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\ngopkg.in/guregu/null.v3 v3.3.0 h1:8j3ggqq+NgKt/O7mbFVUFKUMWN+l1AmT5jQmJ6nPh2c=\ngopkg.in/guregu/null.v3 v3.3.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": ".github/workflows/xk6-tests/xk6-js-test/jstest.go",
    "content": "package jstest\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc init() {\n\tmodules.Register(\"k6/x/jsexttest\", New())\n}\n\ntype (\n\tRootModule struct{}\n\n\t// JSTest is meant to test xk6 and the JS extension sub-system of k6.\n\tJSTest struct {\n\t\tvu modules.VU\n\n\t\tfoos *metrics.Metric\n\t}\n)\n\n// Ensure the interfaces are implemented correctly.\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &JSTest{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface and returns\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &JSTest{\n\t\tvu:   vu,\n\t\tfoos: vu.InitEnv().Registry.MustNewMetric(\"foos\", metrics.Counter),\n\t}\n}\n\n// Exports implements the modules.Instance interface and returns the exports\n// of the JS module.\nfunc (j *JSTest) Exports() modules.Exports {\n\treturn modules.Exports{Default: j}\n}\n\n// Foo emits a foo metric\nfunc (j *JSTest) Foo(arg float64) (bool, error) {\n\tstate := j.vu.State()\n\tif state == nil {\n\t\treturn false, fmt.Errorf(\"the VU State is not available in the init context\")\n\t}\n\n\tctx := j.vu.Context()\n\n\ttags := state.Tags.GetCurrentValues().Tags.With(\"foo\", \"bar\")\n\tmetrics.PushIfNotDone(ctx, state.Samples, metrics.Sample{\n\t\tTime:       time.Now(),\n\t\tTimeSeries: metrics.TimeSeries{Metric: j.foos, Tags: tags},\n\t\tValue:      arg,\n\t})\n\n\treturn true, nil\n}\n"
  },
  {
    "path": ".github/workflows/xk6-tests/xk6-output-test/go.mod",
    "content": "module github.com/grafana/xk6-output-test\n\ngo 1.23.0\n\ntoolchain go1.23.7\n\nrequire go.k6.io/k6 v0.57.0\n\nrequire (\n\tgithub.com/cenkalti/backoff/v4 v4.3.0 // indirect\n\tgithub.com/fatih/color v1.18.0 // indirect\n\tgithub.com/go-logr/logr v1.4.2 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/mailru/easyjson v0.9.0 // indirect\n\tgithub.com/mattn/go-colorable v0.1.14 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd // indirect\n\tgithub.com/sirupsen/logrus v1.9.3 // indirect\n\tgithub.com/spf13/afero v1.1.2 // indirect\n\tgo.opentelemetry.io/otel v1.31.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect\n\tgo.opentelemetry.io/otel/metric v1.31.0 // indirect\n\tgo.opentelemetry.io/otel/sdk v1.31.0 // indirect\n\tgo.opentelemetry.io/otel/trace v1.31.0 // indirect\n\tgo.opentelemetry.io/proto/otlp v1.3.1 // indirect\n\tgolang.org/x/net v0.40.0 // indirect\n\tgolang.org/x/sys v0.33.0 // indirect\n\tgolang.org/x/text v0.25.0 // indirect\n\tgolang.org/x/time v0.9.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect\n\tgoogle.golang.org/grpc v1.69.4 // indirect\n\tgoogle.golang.org/protobuf v1.36.3 // indirect\n\tgopkg.in/guregu/null.v3 v3.3.0 // indirect\n)\n"
  },
  {
    "path": ".github/workflows/xk6-tests/xk6-output-test/go.sum",
    "content": "github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=\ngithub.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=\ngithub.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=\ngithub.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=\ngithub.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=\ngithub.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=\ngithub.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=\ngithub.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mccutchen/go-httpbin v1.1.2-0.20190116014521-c5cb2f4802fa h1:lx8ZnNPwjkXSzOROz0cg69RlErRXs+L3eDkggASWKLo=\ngithub.com/mccutchen/go-httpbin v1.1.2-0.20190116014521-c5cb2f4802fa/go.mod h1:fhpOYavp5g2K74XDl/ao2y4KvhqVtKlkg1e+0UaQv7I=\ngithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd h1:AC3N94irbx2kWGA8f/2Ks7EQl2LxKIRQYuT9IJDwgiI=\ngithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd/go.mod h1:9vRHVuLCjoFfE3GT06X0spdOAO+Zzo4AMjdIwUHBvAk=\ngithub.com/mstoykov/envconfig v1.5.0 h1:E2FgWf73BQt0ddgn7aoITkQHmgwAcHup1s//MsS5/f8=\ngithub.com/mstoykov/envconfig v1.5.0/go.mod h1:vk/d9jpexY2Z9Bb0uB4Ndesss1Sr0Z9ZiGUrg5o9VGk=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=\ngithub.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=\ngithub.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=\ngithub.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngo.k6.io/k6 v0.57.0 h1:l1jivNtbCQYNhgvl+O6SfzwabqNlazr8OLYjxm8lNGw=\ngo.k6.io/k6 v0.57.0/go.mod h1:AXTOq8X59VqigGvoI59Al/+8F/5h4iHO0CoX0lNbq/4=\ngo.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=\ngo.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 h1:nSiV3s7wiCam610XcLbYOmMfJxB9gO4uK3Xgv5gmTgg=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0/go.mod h1:hKn/e/Nmd19/x1gvIHwtOwVWM+VhuITSWip3JUDghj0=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc=\ngo.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=\ngo.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=\ngo.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=\ngo.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=\ngo.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=\ngo.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=\ngo.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=\ngo.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=\ngo.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=\ngo.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngolang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=\ngolang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=\ngolang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=\ngolang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=\ngolang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=\ngolang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=\ngolang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=\ngolang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=\ngoogle.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=\ngoogle.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=\ngoogle.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=\ngoogle.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/guregu/null.v3 v3.3.0 h1:8j3ggqq+NgKt/O7mbFVUFKUMWN+l1AmT5jQmJ6nPh2c=\ngopkg.in/guregu/null.v3 v3.3.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": ".github/workflows/xk6-tests/xk6-output-test/outputtest.go",
    "content": "package outputtest\n\nimport (\n\t\"io\"\n\t\"strconv\"\n\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc init() {\n\toutput.RegisterExtension(\"outputtest\", func(params output.Params) (output.Output, error) {\n\t\treturn &Output{params: params}, nil\n\t})\n}\n\n// Output is meant to test xk6 and the output extension sub-system of k6.\ntype Output struct {\n\tparams     output.Params\n\tcalcResult float64\n\toutputFile io.WriteCloser\n}\n\n// Description returns a human-readable description of the output.\nfunc (o *Output) Description() string {\n\treturn \"test output extension\"\n}\n\n// Start opens the specified output file.\nfunc (o *Output) Start() error {\n\tout, err := o.params.FS.Create(o.params.ConfigArgument)\n\tif err != nil {\n\t\treturn err\n\t}\n\to.outputFile = out\n\n\treturn nil\n}\n\n// AddMetricSamples just plucks out the metric we're interested in.\nfunc (o *Output) AddMetricSamples(sampleContainers []metrics.SampleContainer) {\n\tfor _, sc := range sampleContainers {\n\t\tfor _, sample := range sc.GetSamples() {\n\t\t\tif sample.Metric.Name == \"foos\" {\n\t\t\t\to.calcResult += sample.Value\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Stop saves the dummy results and closes the file.\nfunc (o *Output) Stop() error {\n\t_, err := o.outputFile.Write([]byte(strconv.FormatFloat(o.calcResult, 'f', 0, 64)))\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn o.outputFile.Close()\n}\n"
  },
  {
    "path": ".github/workflows/xk6-tests/xk6-test.js",
    "content": "\nimport { check } from 'k6';\nimport jsexttest from 'k6/x/jsexttest';\n\nexport let options = {\n    iterations: 5,\n    thresholds: {\n        checks: ['rate===1'],\n    }\n};\n\nexport function handleSummary(data) {\n    return {\n        'summary-results.txt': data.metrics.foos.values.count.toString(),\n    };\n}\n\n\nexport default function () {\n    check(null, {\n        \"foo is true\": () => jsexttest.foo(__ITER),\n    });\n}"
  },
  {
    "path": ".github/workflows/xk6.yml",
    "content": "name: xk6\non:\n  # Enable manually triggering this workflow via the API or web UI\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n  pull_request:\n\ndefaults:\n  run:\n    shell: bash\n\npermissions:\n  contents: read\n\njobs:\n  test-xk6:\n    strategy:\n      fail-fast: false\n      matrix:\n        go: [stable, tip]\n        platform: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]\n    runs-on: ${{ matrix.platform }}\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          persist-credentials: false\n      - name: Install Go\n        if: matrix.go != 'tip'\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6\n        with:\n          go-version: 1.26.x\n          check-latest: true\n      - name: Download Go tip\n        if: matrix.go == 'tip'\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          gh release download ${{ matrix.platform }} --repo grafana/gotip --pattern 'go.zip'\n      - name: Install Go tip\n        if: matrix.go == 'tip'\n        run: |\n          unzip go.zip -d $HOME/sdk\n          echo \"GOROOT=$HOME/sdk/gotip\" >> \"$GITHUB_ENV\"\n          echo \"GOPATH=$HOME/go\" >> \"$GITHUB_ENV\"\n          echo \"$HOME/go/bin\" >> \"$GITHUB_PATH\"\n          echo \"$HOME/sdk/gotip/bin\" >> \"$GITHUB_PATH\"\n      - name: Run tests\n        env:\n          PR_REPO: ${{  github.event.pull_request.head.repo.full_name  }}\n        run: |\n          set -x\n          which go\n          go version\n\n          export CGO_ENABLED=0\n\n          COMMIT_ID=\"${{ github.event.pull_request.head.sha }}\"\n          if [[ \"$COMMIT_ID\" == \"\" ]]; then\n            COMMIT_ID=\"$(git rev-parse HEAD)\" # branch, not PR merge commit\n          fi\n          echo \"COMMIT_ID=$COMMIT_ID\"\n          cd .github/workflows/xk6-tests\n          go install go.k6.io/xk6/cmd/xk6@master\n          if [ \"${{ github.event_name }}\" == \"pull_request\" -a \\\n               \"${PR_REPO}\" != \"${{ github.repository }}\" ]; then\n            export XK6_K6_REPO=\"github.com/${PR_REPO}\"\n          fi\n          # The following is a workaround for Windows, cause when using 'shell: bash', the PATH is expressed\n          # with ':' as separator, but Go code, running on a Windows OS, expects ';' as separator.\n          XPATH=\"$PATH\"\n          if [[ \"${{ matrix.platform }}\" == \"windows-latest\" || \"${{ matrix.platform }}\" == \"windows-latest\" ]]; then\n            XPATH=\"$HOME/sdk/gotip/bin;$XPATH\"\n          fi\n          PATH=\"$XPATH\" \\\n          GOPRIVATE=\"go.k6.io/k6\" xk6 build \"$COMMIT_ID\" \\\n            --output ./k6ext \\\n            --with github.com/grafana/xk6-js-test=\"$(pwd)/xk6-js-test\" \\\n            --with github.com/grafana/xk6-output-test=\"$(pwd)/xk6-output-test\"\n          export K6_NO_USAGE_REPORT=true\n          ./k6ext version\n          ./k6ext run --out outputtest=output-results.txt xk6-test.js\n\n          OUTPUT_RESULT=\"$(cat output-results.txt)\"\n          if [[ \"$OUTPUT_RESULT\" != \"10\" ]]; then\n            echo \"output result was not as expected: $OUTPUT_RESULT\"\n            exit 11\n          fi\n\n          SUMMARY_RESULT=\"$(cat summary-results.txt)\"\n          if [[ \"$SUMMARY_RESULT\" != \"10\" ]]; then\n            echo \"summary result was not as expected: $SUMMARY_RESULT\"\n            exit 12\n          fi\n"
  },
  {
    "path": ".github/zizmor.yml",
    "content": "# This is also used as the default configuration for the Zizmor reusable\n# workflow.\n\nrules:\n  unpinned-uses:\n    config:\n      policies:\n        actions/*: any # trust GitHub\n        grafana/*: any # trust Grafana\n\n"
  },
  {
    "path": ".gitignore",
    "content": "/k6\n/k6.exe\n/dist\n/pkg-build\n/internal/lib/summary/machinereadable/k6-summary\n/internal/js/tc39/TestTC39\n/internal/js/modules/k6/experimental/streams/tests/wpt\n/internal/js/modules/k6/webcrypto/tests/wpt/\n/.protoc\n\n.vscode\n*.sublime-workspace\n*.log\n*.syso\n.idea\n*.DS_Store\n# Excluding as it is the file generated by the k6 init command\n/script.js\n\n/versioninfo.json\n\n/vendor/**/.editorconfig\n/vendor/**/*.jpg\n/vendor/**/*.json\n# Excluding as it is required (embedded) configuration file for web-dashboard\n!/vendor/github.com/grafana/xk6-dashboard/dashboard/assets/packages/config/dist/config.json\n!/vendor/github.com/grafana/xk6-dashboard-assets/packages/config/dist/config.json\n/vendor/github.com/grafana/xk6-dashboard-assets/yarn.lock\n/vendor/**/.*.json\n/vendor/**/Makefile\n/vendor/**/*.png\n/vendor/**/*.tmpl\n/vendor/**/*.txt\n!/vendor/**/*LICENSE*\n!/vendor/modules.txt\n/vendor/**/*.y*ml\n/vendor/**/.*.y*ml\n/vendor/**/CODEOWNERS\n/vendor/**/CONTRIBUTING.md\n/vendor/**/CODE_OF_CONDUCT.md\n/vendor/**/README.md\n/vendor/**/.gitignore\n/vendor/github.com/dlclark/regexp2/testoutput1\n\n/packaging/.env\n/packaging/*.gpg\n"
  },
  {
    "path": ".golangci.yml",
    "content": "# v2.10.1\n# Please don't remove the first line. It uses in CI to determine the golangci version\nversion: \"2\"\nlinters:\n  default: none\n  enable:\n    - asasalint\n    - asciicheck\n    - bidichk\n    - bodyclose\n    - canonicalheader\n    - contextcheck\n    - copyloopvar\n    - cyclop\n    - dogsled\n    - dupl\n    - durationcheck\n    - errcheck\n    - errchkjson\n    - errname\n    - errorlint\n    - exhaustive\n    - fatcontext\n    - forbidigo\n    - forcetypeassert\n    - funlen\n    - gocheckcompilerdirectives\n    - gochecknoglobals\n    - gocognit\n    - goconst\n    - gocritic\n    - gomoddirectives\n    - goprintffuncname\n    - gosec\n    - govet\n    - importas\n    - ineffassign\n    - interfacebloat\n    - lll\n    - makezero\n    - misspell\n    - modernize\n    - nakedret\n    - nestif\n    - nilerr\n    - nilnil\n    - noctx\n    - nolintlint\n    - nosprintfhostport\n    - paralleltest\n    - prealloc\n    - predeclared\n    - promlinter\n    - reassign\n    - revive\n    - rowserrcheck\n    - sqlclosecheck\n    - staticcheck\n    - tparallel\n    - unconvert\n    - unparam\n    - unused\n    - usestdlibvars\n    - usetesting\n    - wastedassign\n    - whitespace\n  settings:\n    cyclop:\n      max-complexity: 25\n    dupl:\n      threshold: 150\n    exhaustive:\n      default-signifies-exhaustive: true\n    forbidigo:\n      forbid:\n        - pattern: ^(fmt\\\\.Print(|f|ln)|print|println)$\n        - pattern: ^os\\.(.*)$(# Using anything except Signal and SyscallError from the os package is forbidden )?\n        - pattern: ^syscall\\.[^A-Z_]+$(# Using anything except constants from the syscall package is forbidden )?\n        - pattern: ^logrus\\.Logger$\n        - pattern: ^afero\\.(.*)$(# Using afero outside of the fsext package is forbidden )?\n    funlen:\n      lines: 80\n      statements: 60\n    goconst:\n      min-len: 10\n      min-occurrences: 4\n    usetesting:\n      os-setenv: true\n  exclusions:\n    generated: lax\n    rules:\n      - linters:\n          - canonicalheader\n          - cyclop\n          - dupl\n          - forcetypeassert\n          - funlen\n          - gocognit\n          - lll\n          - gosec\n        path: _(test|gen)\\.go\n      - linters:\n          - contextcheck\n          - revive\n        path: js\\/modules\\/k6\\/browser\\/.*\\.go\n      - linters:\n          - revive\n        path: js\\/modules\\/k6\\/html\\/.*\\.go\n        text: 'exported: exported '\n      - linters:\n          - paralleltest\n          - tparallel\n        path: js\\/modules\\/k6\\/html\\/.*\\.go\n      - linters:\n          - paralleltest\n          - tparallel\n        path: js\\/modules\\/k6\\/http\\/.*_test\\.go\n      - linters:\n          - forbidigo\n        text: use of `os\\.(SyscallError|Signal|Interrupt)` forbidden\n      - linters:\n          - forbidigo\n        text: use of `afero\\.(.*)` forbidden\n        path: lib/fsext/.*\\.go\n      - linters:\n          - revive\n        text: avoid meaningless package names\n      - linters:\n          - revive\n        text: avoid package names that conflict with Go standard library\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\nissues:\n  max-issues-per-linter: 0\n  max-same-issues: 0\nformatters:\n  enable:\n    - gofmt\n    - gofumpt\n    - goimports\n  exclusions:\n    generated: lax\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\n"
  },
  {
    "path": "AGENTS.md",
    "content": "@CLAUDE.md"
  },
  {
    "path": "CLAUDE.md",
    "content": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\nk6 is a modern load testing tool built in Go. It allows developers to write JavaScript test scripts to simulate user behavior and measure system performance. The tool features configurable load generation, multiple protocol support (HTTP, WebSockets, gRPC, Browser), and flexible metrics output.\n\n## Common Development Commands\n\n### Building and Testing\n```bash\n# Build the k6 binary\nmake build\n# or\ngo build\n\n# Run all tests with race detection  \nmake tests\n# or\ngo test -race -timeout 210s ./...\n\n# Run linting\nmake lint\n\n# Run both linting and tests\nmake check\n\n# Format code\nmake format\n```\n\n### Single Test Execution\n```bash\n# Run tests for a specific package\ngo test ./lib/executor/\ngo test ./internal/js/modules/k6/http/\ngo test -v -run TestSpecificFunction ./path/to/package/\n\n# Run browser tests (requires special setup)\ngo test ./internal/js/modules/k6/browser/tests/\n```\n\n### Code Generation\n```bash\n# Install tools and regenerate generated code\nmake generate-tools-installs\nmake generate\n```\n\n### Working with Examples\n```bash\n# Run gRPC server example\nmake grpc-server-run\n\n# Test scripts are in examples/ directory\n./k6 run examples/http_get.js\n./k6 run examples/browser/querying.js\n```\n\n## Architecture Overview\n\n### Core Components\n\n**Main Entry Point**: `main.go` → `cmd/execute.go` → `internal/cmd/root.go`\n- The CLI is built with Cobra and organized into subcommands in `internal/cmd/`\n- Key commands: `run`, `archive`, `cloud`, `inspect`, `new`, `pause`, `resume`, `scale`, `stats`, `status`, `version`\n\n**JavaScript Runtime**: `internal/js/` and `js/`\n- `internal/js/`: Core JavaScript execution engine using Sobek (Goja fork)\n- `js/modules/`: Built-in k6 modules (http, browser, crypto, etc.)\n- `js/common/`: Shared JavaScript runtime utilities\n\n**Load Testing Core**: `lib/`\n- `lib/executor/`: Different execution strategies (constant VUs, ramping, arrival rate, etc.)\n- `lib/netext/`: Network extensions and HTTP transport\n- `lib/types/`: Core type definitions\n- `lib/options.go`: Test configuration options\n\n**Outputs**: `internal/output/` and `output/`\n- Multiple output formats: JSON, CSV, InfluxDB, Prometheus, Cloud, OpenTelemetry\n- Each output has its own package with config and implementation\n\n**Browser Testing**: `internal/js/modules/k6/browser/`\n- CDP-based browser automation using chromium\n- Page, frame, element handle abstractions\n- Browser context and session management\n\n### Key Patterns\n\n**Module System**: k6 modules are Go packages that expose JavaScript APIs\n- `internal/js/modules/k6/`: Built-in k6 modules  \n- Modules follow a mapping pattern to bridge Go and JavaScript\n- Example: `k6/http` module maps HTTP functionality\n\n**Executor Pattern**: Different load testing strategies implemented as executors\n- `constant-vus`: Fixed number of virtual users\n- `ramping-vus`: Gradually increasing/decreasing VUs  \n- `constant-arrival-rate`: Fixed rate of iterations\n- `per-vu-iterations`: Fixed iterations per VU\n\n**Extension System**: `ext/` package allows extending k6 with custom functionality\n- Extensions can add new JavaScript modules\n- Used by xk6 ecosystem for community extensions\n\n## Testing Structure\n\n**Unit Tests**: Co-located with source code (`*_test.go`)\n**Integration Tests**: `internal/cmd/tests/` for CLI integration tests  \n**Browser E2E Tests**: `internal/js/modules/k6/browser/tests/` with static HTML fixtures\n**TC39/WPT Conformance**: `internal/js/tc39/` and modules with WPT test suites\n\n## Important Configuration Files\n\n- `.golangci.yml`: Linter configuration (version pinned at top)\n- `Makefile`: Build targets and development commands\n- `go.mod`: Go module dependencies (use Go 1.23+)\n- `Dependencies.md`: Dependency update policy and guidelines\n- `modtools_frozen.yml`: Dependencies that should not be auto-updated\n\n## Development Guidelines\n\n**Code Style**: \n- Use `gofmt -s` for formatting\n- Follow golangci-lint rules (run `make lint`)\n- Comments should wrap at 100 characters\n\n**Dependencies**:\n- Update direct dependencies only after releases\n- Some dependencies are intentionally frozen (see Dependencies.md)\n- Use `modtools check --direct-only` to check for updates\n\n**Testing**:\n- All new code should have tests\n- Use `go test -race` for concurrency testing\n- Browser tests require additional setup and fixtures\n\n**Generated Code**: \n- Several files are auto-generated (look for `*_gen.go`)\n- Run `make generate` after modifying source templates\n- Protobuf definitions in `internal/cloudapi/insights/proto/`\n\n## Git Workflow and Branching Strategy\n\n**Branching Strategy**:\n- Create a new branch for each feature or bugfix\n- Branch names must be descriptive and reflect the problem being solved\n- Examples: `fix-http-timeout-handling`, `add-websocket-compression`, `improve-browser-element-selection`\n- Base new branches off the `master` branch\n\n**Allowed Git Commands**:\n```bash\n# Create and switch to new branch\ngit checkout -b descriptive-branch-name\ngit switch -c descriptive-branch-name\n\n# Regular commits (using user from git config)\ngit add .\ngit commit -m \"descriptive commit message\"\n\n# Push branch to remote\ngit push origin branch-name\ngit push -u origin branch-name  # first push with upstream\n\n# Check status and view changes\ngit status\ngit diff\ngit log\n```\n\n**Strictly Forbidden Git Operations**:\n- **NO force pushes**: `git push --force`, `git push -f`\n- **NO history modification**: `git reset --hard`, `git rebase`, `git rebase -i`\n- **NO direct pushes to master**: `git push origin master`\n- **NO commit author overrides**: Always use the default git config user\n\n**Commit Guidelines**:\n- All commits must be created on behalf of the user listed in Git config (default behavior)\n- Write clear, descriptive commit messages that could be included in a changelog\n- Close related issues with commit messages: `Closes #123`, `Fixes #456`\n- Follow existing commit message style in the repository\n\n**Pull Request Process**:\n- Create pull requests from feature branches to `master`\n- Ensure all tests pass before creating PR\n- Follow the existing PR template and guidelines\n\n## Common File Locations\n\n**CLI Commands**: `internal/cmd/` (run.go, cloud.go, etc.)\n**HTTP Module**: `js/modules/k6/http/` and `internal/js/modules/k6/http/`  \n**Browser Module**: `internal/js/modules/k6/browser/`\n**Metrics**: `metrics/` package for metric definitions\n**Examples**: `examples/` directory with various test script examples\n**Test Data**: `internal/cmd/testdata/` and module-specific test fixtures"
  },
  {
    "path": "CODEOWNERS",
    "content": "# by default the k6-core team is the owner of all files\n* @grafana/k6-core\n\n# The release notes are shared across different teams,\n# especially with the browser team.\n# It turned out to be less noisy if the author picks manually every time\n# the best reviewers based on the context of the working area.\n/release\\ notes/\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting our Developer Relations team, avocados@k6.io.\n\nAll complaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to k6\n\nThank you for your interest in contributing to k6!\n\n(ﾉ◕ヮ◕)ﾉ*:・ﾟ✧\n\nBefore you begin, make sure to familiarize yourself with the [Code of Conduct](CODE_OF_CONDUCT.md). If you've previously contributed to other open source project, you may recognize it as the classic [Contributor Covenant](https://contributor-covenant.org/).\n\nIf you want to chat with the team or the community, you can [join our community forums](https://community.k6.io/).\n\n> **Note:** To disclose security issues, refer to [SECURITY.md](https://github.com/grafana/k6?tab=security-ov-file).\n\n## Filing issues\n\nDon't be afraid to file issues! Nobody can fix a bug we don't know exists, or add a feature we didn't think of.\n\nThe worst that can happen is that someone closes it and points you in the right direction.\n\nThat said, \"how do I...\"-type questions are often more suited for community forums.\n\n## Contributing code\n\nIf you'd like to contribute code to k6, this is the basic procedure. Make sure to follow the [style guide](#code-style) described below.\n\n1. Find an issue you'd like to fix. If there is none already, or you'd like to add a feature, please open one, and we can talk about how to do it.  Out of respect for your time, please start a discussion regarding any bigger contributions either in a GitHub Issue, in the community forums **before** you get started on the implementation.\n  \n   Remember, there's more to software development than code; if it's not properly planned, stuff gets messy real fast.\n\n2. Create a fork and open a feature branch - `feature/my-cool-feature` is the classic way to name these, but it really doesn't matter.\n\n3. Create a pull request!\n\n4. Sign the [Contributor License Agreement](https://cla-assistant.io/grafana/k6) (the process is integrated with the pull request flow through cla-assistant.io).\n\n5. We will discuss implementation details until everyone is happy, then a maintainer will merge it.\n\n### Development setup\n\nTo get a basic development environment for Go and k6 up and running, first make sure you have **[Git](https://git-scm.com/downloads)** and **[Go](https://golang.org/doc/install)** (see our [go.mod](https://github.com/grafana/k6/blob/master/go.mod#L3) for minimum required version) installed and working properly.\n\nWe recommend using the Git command-line interface to download the source code for the k6:\n\n* Open a terminal and run `git clone https://github.com/grafana/k6.git`. This command downloads k6's sources to a new `k6` directory in your current directory.\n* Open the `k6` directory in your favorite code editor.\n\nFor alternative ways of cloning the k6 repository, please refer to [GitHub's cloning a repository](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository) documentation.\n\n#### Running the linter\n\nWe make use of the [golangci-lint](https://github.com/golangci/golangci-lint) tool to lint the code in CI. The actual version you can find in our [`.golangci.yml`](https://github.com/grafana/k6/blob/master/.golangci.yml#L1). To run it locally, first [install it](https://golangci-lint.run/welcome/install/#local-installation), then run:\n\n```bash\nmake lint\n```\n\n#### Running the test suite\n\nTo exercise the entire test suite, please run the following command\n\n```bash\nmake tests\n```\n\n#### Dependencies\n\nConsult [Dependencies.md](Dependencies.md) to find out more about how we manage k6's dependencies, and our policy regarding dependencies management and update.\n\n#### Code style\n\nAs you'd expect, please adhere to good ol' `gofmt` (there are plugins for most editors that can autocorrect this), but also `gofmt -s` (code simplification), and don't leave unused functions laying around.\n\nContinuous integration will catch all of this if you don't, and it's fine to just fix linter complaints with another commit, but you can also run the linter yourself:\n\n```bash\nmake check\n```\n\nComments in the source should wrap at 100 characters, but there's no maximum length or need to be brief here - please include anything one might need to know in order to understand the code, that you could reasonably expect any reader to not already know (you probably don't need to explain what a goroutine is).\n\n#### Commit format\n\nWe don't have any explicit rules about commit message formatting, but try to write something that could be included as-is in a changelog.\n\nIf your commit closes an issue, please [close it with your commit message](https://help.github.com/articles/closing-issues-via-commit-messages/), for example:\n\n```text\nAdded this really rad feature\n\nCloses #420\n```\n\n#### Language and text formatting\n\nAny human-readable text you add must be non-gendered and should be fairly concise without devolving into grammatical horrors, dropped words, and shorthands. This isn't Twitter, you don't have a character cap, but don't write a novel where a single sentence would suffice.\n\nIf you're writing a longer block of text to a terminal, wrap it at 80 characters - this ensures it will display properly at the de facto default terminal size of 80x25. As an example, this is the help text of the `scale` sub-command:\n\n```text\n   Scale will change the number of active VUs of a running test.\n\n   It is an error to scale a test beyond vus-max; this is because instantiating\n   new VUs is a very expensive operation, which may skew test results if done\n   during a running test. To raise vus-max, use --max/-m.\n\n   Endpoint: /v1/status\n```\n"
  },
  {
    "path": "Dependencies.md",
    "content": "# Updating dependencies in k6\n\nk6 has a not small amount of dependencies, some of which are used more than others which affects how often if at all they should be updated.\n\nSome original discussions can be found in [this issue](https://github.com/grafana/k6/issues/1933).\n\n## General rule\n\nThe general rule is to update *direct* dependencies just after the release has been made.\n\nThis is mostly so that we keep up with dependencies for which we want new features or bug fixes and can be skipped on case by case basis if there is no bandwidth to be done or any other good reason.\n\nFor example some dependencies that were in the middle of big updates were skipped as they didn't add anything of value at the time, but were being updated day after day seemingly fixing bugs added the previous day. As in that case that wasn't a dependency we wanted to be on top off - we skipped it.\n\nThrough the rest of the development cycle dependencies shouldn't be updated unless:\n1. required for development\n2. a particular bug fix/feature is really important\n\n\nThe last part predominantly goes for `golang.org/x/*` and particularly `golang.org/x/net` which usually have updates through the development of Go itself.\n[Sobek](https://github.com/grafana/sobek) has special considerations as it's heavily used and bug fixes there or new features usually have high impact on k6. Which means that we usually try to update it whenever something new lands there.\n\nAs the stability of any k6 release is pretty essential, this should be done only when adequate testing can be done, and in general, the changelog for each dependency should be consulted on what has changed.\n\nThe latter also serves as a time to open/close issues that are related to the updates. There might be a bug fix for an open issue - we should test it and close the issue. Or there might be new functionality that can be used - probably an issue should be open.\n\n## Go versions\n\nWe aim to support a building of the k6 binary with the two latest versions of golang, which reflects the support [policy](https://go.dev/doc/devel/release#policy) of the Go team.\n\n## Exceptions\n\nThere are some dependencies that we really don't use all that much, intend on removing and as a general note don't need anything else from them. Given that we currently have no problems that updates will fix - we prefer to not update them as not to introduce bugs. Also, for some they bring additional dependencies that we do not want, which is just one more reason not to update them.\n\nList (as of March 2022):\n- github.com/andybalholm/cascadia - a dependency of `github.com/PuerkitoBio/goquery`\n- github.com/sirupsen/logrus - it's in maintenance mode and we want to remove it - also no update for a long time, but also no bugs.\n- github.com/spf13/afero - there are plans to be [replaced by io/fs](https://github.com/grafana/k6/issues/1079) and we don't need anything from it. We have already worked around some bugs so updating might break something\n- github.com/spf13/cobra - none of the newer features are particularly needed, but adds a bunch of new dependencies.\n- github.com/spf13/pflag - similar to above\n- gopkg.in/guregu/null.v3 - no new interesting features and we probably want to drop it in favor of [croconf](https://github.com/grafana/croconf)\n- gopkg.in/yaml.v3 - no new features wanted - actually used directly in only one place to output yaml to stdout.\n\n## How to do it\n\nFor updating dependencies we recommend to use [modtools](https://github.com/dop251/modtools).\n\nRunning `modtools check --direct-only` will give you a list of packages that aren't frozen (the ones above in the exceptions). Alternatively just running `go get <dependency>` for each direct dependency, which also will tell you if there was an update.\n\nThen take a look at the changelog between the versions.\n\nYou can use the command `modtools check --direct-only` provided you, to update it. Run tests and if relevant check that bugs are fixed or any other verification that is appropriate.\n\nCommit dependencies one by one with a message like `Update <dependency> from vX.Y.Z to vX.Y.Z` and a relevant changelog for k6. Sometimes that means \"nothing of relevance for k6\", sometimes it means a list of bug fixes or new features.\n\nIt's preferable to make multiple PRs - in most cases you can split them in three:\n- update for Sobek - which usually needs to happen.\n- update for `golang.org/x/*` - also again happen literally every release\n- everything else - this in general doesn't include more than 5-6 small updates.\n\nFurther splitting is recommended if PRs become too big.\n\nWhen updating Sobek it's recommended to run the tc39 tests in `js/tc39`. And if needed, update the breaking ones as explained in an [Introduction to a k6's TC39 testing](./js/tc39/README.md).\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM --platform=$BUILDPLATFORM golang:1.26.1-alpine@sha256:2389ebfa5b7f43eeafbd6be0c3700cc46690ef842ad962f6c5bd6be49ed82039 as builder\nWORKDIR $GOPATH/src/go.k6.io/k6\nCOPY . .\nARG TARGETOS TARGETARCH\nRUN apk --no-cache add git=~2\nRUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -trimpath -o /usr/bin/k6\n\n# Runtime stage\nFROM alpine:3.23.3@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 as release\n\nRUN adduser -D -u 12345 -g 12345 k6\nCOPY --from=builder /usr/bin/k6 /usr/bin/k6\n\nUSER 12345\nWORKDIR /home/k6\n\nENTRYPOINT [\"k6\"]\n\n# Browser-enabled bundle\nFROM release as with-browser\n\nUSER root\n\nCOPY --from=release /usr/bin/k6 /usr/bin/k6\nRUN apk --no-cache add chromium chromium-swiftshader\n\nUSER 12345\n\nENV CHROME_BIN=/usr/bin/chromium-browser\nENV CHROME_PATH=/usr/lib/chromium/\n\nENV K6_BROWSER_HEADLESS=true\n# no-sandbox chrome arg is required to run chrome browser in\n# alpine and avoids the usage of SYS_ADMIN Docker capability\nENV K6_BROWSER_ARGS=no-sandbox\n\nENTRYPOINT [\"k6\"]\n"
  },
  {
    "path": "LICENSE.md",
    "content": "### GNU AFFERO GENERAL PUBLIC LICENSE\n\nVersion 3, 19 November 2007\n\nCopyright (C) 2007 Free Software Foundation, Inc.\n<http://fsf.org/>\n\nEveryone is permitted to copy and distribute verbatim copies of this\nlicense document, but changing it is not allowed.\n\n### Preamble\n\nThe GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\nThe licenses for most software and other practical works are designed\nto take away your freedom to share and change the works. By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains\nfree software for all its users.\n\nWhen we speak of free software, we are referring to freedom, not\nprice. Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\nDevelopers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\nA secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate. Many developers of free software are heartened and\nencouraged by the resulting cooperation. However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\nThe GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community. It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server. Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\nAn older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals. This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing\nunder this license.\n\nThe precise terms and conditions for copying, distribution and\nmodification follow.\n\n### TERMS AND CONDITIONS\n\n#### 0. Definitions.\n\n\"This License\" refers to version 3 of the GNU Affero General Public\nLicense.\n\n\"Copyright\" also means copyright-like laws that apply to other kinds\nof works, such as semiconductor masks.\n\n\"The Program\" refers to any copyrightable work licensed under this\nLicense. Each licensee is addressed as \"you\". \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\nTo \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of\nan exact copy. The resulting work is called a \"modified version\" of\nthe earlier work or a work \"based on\" the earlier work.\n\nA \"covered work\" means either the unmodified Program or a work based\non the Program.\n\nTo \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy. Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\nTo \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies. Mere interaction with a user\nthrough a computer network, with no transfer of a copy, is not\nconveying.\n\nAn interactive user interface displays \"Appropriate Legal Notices\" to\nthe extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License. If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n#### 1. Source Code.\n\nThe \"source code\" for a work means the preferred form of the work for\nmaking modifications to it. \"Object code\" means any non-source form of\na work.\n\nA \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\nThe \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form. A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\nThe \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities. However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work. For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\nThe Corresponding Source need not include anything that users can\nregenerate automatically from other parts of the Corresponding Source.\n\nThe Corresponding Source for a work in source code form is that same\nwork.\n\n#### 2. Basic Permissions.\n\nAll rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met. This License explicitly affirms your unlimited\npermission to run the unmodified Program. The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work. This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\nYou may make, run and propagate covered works that you do not convey,\nwithout conditions so long as your license otherwise remains in force.\nYou may convey covered works to others for the sole purpose of having\nthem make modifications exclusively for you, or provide you with\nfacilities for running those works, provided that you comply with the\nterms of this License in conveying all material for which you do not\ncontrol copyright. Those thus making or running the covered works for\nyou must do so exclusively on your behalf, under your direction and\ncontrol, on terms that prohibit them from making any copies of your\ncopyrighted material outside their relationship with you.\n\nConveying under any other circumstances is permitted solely under the\nconditions stated below. Sublicensing is not allowed; section 10 makes\nit unnecessary.\n\n#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\nNo covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\nWhen you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such\ncircumvention is effected by exercising rights under this License with\nrespect to the covered work, and you disclaim any intention to limit\noperation or modification of the work as a means of enforcing, against\nthe work's users, your or third parties' legal rights to forbid\ncircumvention of technological measures.\n\n#### 4. Conveying Verbatim Copies.\n\nYou may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\nYou may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n#### 5. Conveying Modified Source Versions.\n\nYou may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these\nconditions:\n\n-   a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n-   b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under\n    section 7. This requirement modifies the requirement in section 4\n    to \"keep intact all notices\".\n-   c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy. This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged. This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n-   d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\nA compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit. Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n#### 6. Conveying Non-Source Forms.\n\nYou may convey a covered work in object code form under the terms of\nsections 4 and 5, provided that you also convey the machine-readable\nCorresponding Source under the terms of this License, in one of these\nways:\n\n-   a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n-   b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the Corresponding\n    Source from a network server at no charge.\n-   c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source. This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n-   d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge. You need not require recipients to copy the\n    Corresponding Source along with the object code. If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source. Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n-   e) Convey the object code using peer-to-peer transmission,\n    provided you inform other peers where the object code and\n    Corresponding Source of the work are being offered to the general\n    public at no charge under subsection 6d.\n\nA separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\nA \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal,\nfamily, or household purposes, or (2) anything designed or sold for\nincorporation into a dwelling. In determining whether a product is a\nconsumer product, doubtful cases shall be resolved in favor of\ncoverage. For a particular product received by a particular user,\n\"normally used\" refers to a typical or common use of that class of\nproduct, regardless of the status of the particular user or of the way\nin which the particular user actually uses, or expects or is expected\nto use, the product. A product is a consumer product regardless of\nwhether the product has substantial commercial, industrial or\nnon-consumer uses, unless such uses represent the only significant\nmode of use of the product.\n\n\"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to\ninstall and execute modified versions of a covered work in that User\nProduct from a modified version of its Corresponding Source. The\ninformation must suffice to ensure that the continued functioning of\nthe modified object code is in no case prevented or interfered with\nsolely because modification has been made.\n\nIf you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information. But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\nThe requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or\nupdates for a work that has been modified or installed by the\nrecipient, or for the User Product in which it has been modified or\ninstalled. Access to a network may be denied when the modification\nitself materially and adversely affects the operation of the network\nor violates the rules and protocols for communication across the\nnetwork.\n\nCorresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n#### 7. Additional Terms.\n\n\"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law. If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\nWhen you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit. (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.) You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\nNotwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders\nof that material) supplement the terms of this License with terms:\n\n-   a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n-   b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n-   c) Prohibiting misrepresentation of the origin of that material,\n    or requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n-   d) Limiting the use for publicity purposes of names of licensors\n    or authors of the material; or\n-   e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n-   f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions\n    of it) with contractual assumptions of liability to the recipient,\n    for any liability that these contractual assumptions directly\n    impose on those licensors and authors.\n\nAll other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10. If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term. If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\nIf you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\nAdditional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions; the\nabove requirements apply either way.\n\n#### 8. Termination.\n\nYou may not propagate or modify a covered work except as expressly\nprovided under this License. Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\nHowever, if you cease all violation of this License, then your license\nfrom a particular copyright holder is reinstated (a) provisionally,\nunless and until the copyright holder explicitly and finally\nterminates your license, and (b) permanently, if the copyright holder\nfails to notify you of the violation by some reasonable means prior to\n60 days after the cessation.\n\nMoreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\nTermination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License. If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n#### 9. Acceptance Not Required for Having Copies.\n\nYou are not required to accept this License in order to receive or run\na copy of the Program. Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance. However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work. These actions infringe copyright if you do\nnot accept this License. Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n#### 10. Automatic Licensing of Downstream Recipients.\n\nEach time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License. You are not responsible\nfor enforcing compliance by third parties with this License.\n\nAn \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations. If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\nYou may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License. For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n#### 11. Patents.\n\nA \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based. The\nwork thus licensed is called the contributor's \"contributor version\".\n\nA contributor's \"essential patent claims\" are all patent claims owned\nor controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version. For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\nEach contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\nIn the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement). To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\nIf you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients. \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\nIf, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\nA patent license is \"discriminatory\" if it does not include within the\nscope of its coverage, prohibits the exercise of, or is conditioned on\nthe non-exercise of one or more of the rights that are specifically\ngranted under this License. You may not convey a covered work if you\nare a party to an arrangement with a third party that is in the\nbusiness of distributing software, under which you make payment to the\nthird party based on the extent of your activity of conveying the\nwork, and under which the third party grants, to any of the parties\nwho would receive the covered work from you, a discriminatory patent\nlicense (a) in connection with copies of the covered work conveyed by\nyou (or copies made from those copies), or (b) primarily for and in\nconnection with specific products or compilations that contain the\ncovered work, unless you entered into that arrangement, or that patent\nlicense was granted, prior to 28 March 2007.\n\nNothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n#### 12. No Surrender of Others' Freedom.\n\nIf conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License. If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under\nthis License and any other pertinent obligations, then as a\nconsequence you may not convey it at all. For example, if you agree to\nterms that obligate you to collect a royalty for further conveying\nfrom those to whom you convey the Program, the only way you could\nsatisfy both those terms and this License would be to refrain entirely\nfrom conveying the Program.\n\n#### 13. Remote Network Interaction; Use with the GNU General Public License.\n\nNotwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your\nversion supports such interaction) an opportunity to receive the\nCorresponding Source of your version by providing access to the\nCorresponding Source from a network server at no charge, through some\nstandard or customary means of facilitating copying of software. This\nCorresponding Source shall include the Corresponding Source for any\nwork covered by version 3 of the GNU General Public License that is\nincorporated pursuant to the following paragraph.\n\nNotwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work. The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n#### 14. Revised Versions of this License.\n\nThe Free Software Foundation may publish revised and/or new versions\nof the GNU Affero General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Program\nspecifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation. If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever\npublished by the Free Software Foundation.\n\nIf the Program specifies that a proxy can decide which future versions\nof the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\nLater license versions may give you additional or different\npermissions. However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n#### 15. Disclaimer of Warranty.\n\nTHERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT\nWARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND\nPERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE\nDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR\nCORRECTION.\n\n#### 16. Limitation of Liability.\n\nIN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR\nCONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES\nARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT\nNOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR\nLOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM\nTO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER\nPARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n#### 17. Interpretation of Sections 15 and 16.\n\nIf the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\nEND OF TERMS AND CONDITIONS\n\n### How to Apply These Terms to Your New Programs\n\nIf you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these\nterms.\n\nTo do so, attach the following notices to the program. It is safest to\nattach them to the start of each source file to most effectively state\nthe exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n        <one line to give the program's name and a brief idea of what it does.>\n        Copyright (C) <year>  <name of author>\n\n        This program is free software: you can redistribute it and/or modify\n        it under the terms of the GNU Affero General Public License as\n        published by the Free Software Foundation, either version 3 of the\n        License, or (at your option) any later version.\n\n        This program is distributed in the hope that it will be useful,\n        but WITHOUT ANY WARRANTY; without even the implied warranty of\n        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n        GNU Affero General Public License for more details.\n\n        You should have received a copy of the GNU Affero General Public License\n        along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper\nmail.\n\nIf your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source. For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code. There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for\nthe specific requirements.\n\nYou should also get your employer (if you work as a programmer) or\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary. For more information on this, and how to apply and follow\nthe GNU AGPL, see <http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "Makefile",
    "content": "MAKEFLAGS += --silent\nGOLANGCI_LINT_VERSION = $(shell head -n 1 .golangci.yml | tr -d '\\# ')\nPROTOC_VERSION := 21.12\n\nifeq ($(OS),Windows_NT)\n    DETECTED_OS := Windows\n    PROTOC_ARCHIVE := protoc-$(PROTOC_VERSION)-win64.zip\nelse\n    UNAME := $(shell uname)\n    ifeq ($(UNAME),Linux)\n        DETECTED_OS := Linux\n        PROTOC_ARCHIVE := protoc-$(PROTOC_VERSION)-linux-x86_64.zip\n    else ifeq ($(UNAME),Darwin)\n        DETECTED_OS := Darwin\n        PROTOC_ARCHIVE := protoc-$(PROTOC_VERSION)-osx-universal_binary.zip\n    endif\nendif\n\nPROTOC_DOWNLOAD_URL := https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/$(PROTOC_ARCHIVE)\n\nproto-dependencies:\n\tgo install google.golang.org/protobuf/cmd/protoc-gen-go@v1.31.0\n\tgo install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0\n\t@if [ -z \"$(DETECTED_OS)\" ]; then \\\n\t\techo \"Error: Can't install protoc on your OS, please install protoc-$(PROTOC_VERSION) manually.\" >&2; \\\n\t\texit 1; \\\n\tfi\n\t@echo \"Downloading $(PROTOC_ARCHIVE)\"\n\tcurl --show-error --fail --no-location -LO $(PROTOC_DOWNLOAD_URL)\n\tunzip -o $(PROTOC_ARCHIVE) -d ./.protoc\n\trm $(PROTOC_ARCHIVE)\n\ngenerate-tools-installs: proto-dependencies\n\tgo install github.com/mstoykov/enumer@v0.0.1 # TODO figure out if we shouldn't move to a different fork\n\tgo install mvdan.cc/gofumpt@v0.8.0 # TODO maybe just use go fmt for this case\n\tgo install github.com/mailru/easyjson/easyjson@v0.7.7 # TODO remove this in the future\n\ngenerate: generate-tools-installs\n\tPATH=\"$(PWD)/.protoc/bin:$(PATH)\" go generate ./...\n\nall: clean format tests build\n\n## build: Builds the 'k6' binary.\nbuild:\n\tgo build\n\n## format: Applies Go formatting to code.\nformat:\n\tfind . -name '*.go' -exec gofmt -s -w {} +\n\n## grpc-server-run: Runs the gRPC server example.\ngrpc-server-run:\n\tgo run -mod=mod examples/grpc_server/*.go\n\n## check-linter-version: Checks if the linter version is the same as the one specified in the linter config.\ncheck-linter-version:\n\t(golangci-lint version | grep -E \"version v?$(shell head -n 1 .golangci.yml | tr -d '\\# v')\") || echo \"Your installation of golangci-lint is different from the one that is specified in k6's linter config (there it's $(shell head -n 1 .golangci.yml | tr -d '\\# ')). Results could be different in the CI.\"\n\n## lint: Runs the linters.\nlint: check-linter-version\n\techo \"Running linters...\"\n\tgolangci-lint run ./...\n\n## tests: Executes any unit tests.\ntests:\n\tgo test -race -timeout 210s ./...\n\n## check: Runs the linters and tests.\ncheck: lint tests\n\n## help: Prints a list of available build targets.\nhelp:\n\techo \"Usage: make <OPTIONS> ... <TARGETS>\"\n\techo \"\"\n\techo \"Available targets are:\"\n\techo ''\n\tsed -n 's/^##//p' ${PWD}/Makefile | column -t -s ':' | sed -e 's/^/ /'\n\techo\n\techo \"Targets run by default are: `sed -n 's/^all: //p' ./Makefile | sed -e 's/ /, /g' | sed -e 's/\\(.*\\), /\\1, and /'`\"\n\n## clean: Removes any previously created build artifacts.\nclean:\n\t@echo \"cleaning\"\n\trm -f ./k6\n\n.PHONY: build format lint tests check check-linter-version help\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://grafana.com/oss/k6/\">\n    <picture>\n      <img src=\"assets/logo.svg\" alt=\"Grafana k6\" width=\"210\" height=\"210\" /><br>\n    </picture>\n    <br>\n    <picture>\n      <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/grafana-labs-dark-theme.svg\">\n      <source media=\"(prefers-color-scheme: light)\" srcset=\"assets/grafana-labs.svg\">\n      <img src=\"assets/grafana-labs.svg\" alt=\"Grafana Labs\" width=\"210\" />\n    </picture>\n    <br>\n  </a>\n</p>\n\n<h3 align=\"center\">Like unit testing, for performance</h3>\n<p align=\"center\">Modern load testing for developers and testers in the DevOps era.</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/grafana/k6/releases\"><img src=\"https://img.shields.io/github/release/grafana/k6.svg\" alt=\"Github release\"></a>\n  <a href=\"https://github.com/grafana/k6/actions/workflows/all.yml\"><img src=\"https://github.com/grafana/k6/actions/workflows/build.yml/badge.svg\" alt=\"Build status\"></a>\n  <a href=\"https://goreportcard.com/report/github.com/grafana/k6\"><img src=\"https://goreportcard.com/badge/github.com/grafana/k6\" alt=\"Go Report Card\"></a>\n <a href=\"https://codecov.io/gh/grafana/k6\"><img src=\"https://img.shields.io/codecov/c/github/grafana/k6/master.svg\" alt=\"Codecov branch\"></a>\n  <br>\n  <a href=\"https://twitter.com/k6_io\"><img src=\"https://img.shields.io/badge/twitter-@k6_io-55acee.svg\" alt=\"@k6_io on Twitter\"></a>\n</p>\n<p align=\"center\">\n    <a href=\"https://github.com/grafana/k6/releases\">Download</a> ·\n    <a href=\"https://grafana.com/docs/k6/latest/\">Documentation</a> ·\n    <a href=\"https://community.grafana.com/c/grafana-k6/70\">Community Forum</a> ·\n    <a href=\"https://github.com/orgs/grafana/projects/443/views/1\">Public Roadmap</a>\n</p>\n\n<br/>\n<img src=\"assets/github-hr.png\" alt=\"---\" />\n<br/>\n\n**k6** is a modern load-testing tool, built on [our years of experience](https://k6.io/about) in the performance and testing industries.\nIt's built to be powerful, extensible, and full-featured. The key design goal is to provide **the best developer experience**.\n\nIts core features are:\n\n- **Configurable load generation.** Even lower-end machines can simulate lots of traffic.\n- **Tests as code.** Reuse scripts, modularize logic, version control, and integrate tests with your CI.\n- **A full-featured API.** The scripting API is packed with features that help you simulate real application traffic.\n- **An embedded JavaScript engine.** The performance of Go, the scripting familiarity of JavaScript.\n- **Multiple Protocol support**. HTTP, WebSockets, gRPC, Browser, and more.\n- **Large extension ecosystem.** You can extend k6 to support your needs. And many people have already shared their extensions with the community! [Explore](https://grafana.com/docs/k6/latest/extensions/explore) the available extensions.\n- **Flexible metrics storage and visualization**. Summary statistics or granular metrics, exported to the service of your choice.\n- **Native integration with Grafana cloud**. [SaaS solution](https://grafana.com/products/cloud/k6/) for test execution, metrics correlation, data analysis, and more.\n\nThis is what load testing looks like in the 21st century.\n\n## Example script\n\n\n```js\nimport http from \"k6/http\";\nimport { check, sleep } from \"k6\";\n\n// Test configuration\nexport const options = {\n  thresholds: {\n    // Assert that 99% of requests finish within 3000ms.\n    http_req_duration: [\"p(99) < 3000\"],\n  },\n  // Ramp the number of virtual users up and down\n  stages: [\n    { duration: \"30s\", target: 15 },\n    { duration: \"1m\", target: 15 },\n    { duration: \"20s\", target: 0 },\n  ],\n};\n\n// Simulated user behavior\nexport default function () {\n  let res = http.get(\"https://quickpizza.grafana.com\");\n  // Validate response status\n  check(res, { \"status was 200\": (r) => r.status == 200 });\n  sleep(1);\n}\n```\n\nYou can run scripts like this on the CLI, or in your CI, or across a Kubernetes cluster.\n\n> [!NOTE]\n> Don't want to write code ?\n> \n> We got you! Meet [k6 Studio](https://github.com/grafana/k6-studio), a desktop application made to help you generate k6 scripts without having to touch code!\n\n## Documentation\n\nThe docs cover all aspects of using k6. Some highlights include:\n\n- [Get Started](https://grafana.com/docs/k6/latest/). Install, run a test, inspect results.\n- [HTTP requests](https://grafana.com/docs/k6/latest/using-k6/http-requests/). Have your virtual users use HTTP methods.\n  Or, check the other [Protocols](https://grafana.com/docs/k6/latest/using-k6/protocols/).\n- [Thresholds](https://grafana.com/docs/k6/latest/using-k6/thresholds/). Set goals for your test, and codify your SLOs.\n- [Options](https://grafana.com/docs/k6/latest/using-k6/k6-options/). Configure your load, duration, TLS certificates, and much, much more.\n- [Scenarios](https://grafana.com/docs/k6/latest/using-k6/scenarios/).\n  Choose how to model your workload: open models, closed models, constant RPS, fixed iterations, and more.\n- [Results output](https://grafana.com/docs/k6/latest/results-output/). Study, filter, and export your test results.\n- [JavaScript API](https://grafana.com/docs/k6/latest/javascript-api/). Reference and examples of all k6 modules.\n- [Extensions](https://grafana.com/docs/k6/latest/extensions/). Extend k6 for new protocols and use cases.\n\nThese links barely scratch the surface! If you're looking for conceptual information, you can read about [Test types](https://grafana.com/docs/k6/latest/testing-guides/test-types/), [Test strategies](https://grafana.com/docs/k6/latest/testing-guides/), or one of the many informative [Blog posts](https://k6.io/blog).\n\n## Roadmap\n\nOur team is dedicated to continuously improving and providing the best user experience possible. The [public roadmap](https://github.com/orgs/grafana/projects/443/views/1) covers user-oriented features, UX improvements and JavaScript support that our team will focus on. Remember that timeframes and priorities may shift, but we believe it's important to share our vision.\n\nWe hope it provides a clear overview of our plans for future development. We welcome feedback, corrections, and suggestions via GitHub to make it more comprehensive, accessible, and valuable for the community.\n\nIt's worth mentioning that we consider [upvotes (thumbs-up)](https://github.com/grafana/k6/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc) to be one of the essential metrics for determining community needs. If you want to show us the importance of a feature, please give it a thumbs-up.\n\n## Contribute\n\nIf you want to contribute or help with the development of k6, start by reading [CONTRIBUTING.md](CONTRIBUTING.md). Before you start coding, it might be a good idea to first discuss your plans and implementation details with the k6 maintainers—especially when it comes to big changes and features. You can do this in the [GitHub issue](https://github.com/grafana/k6/issues) for the problem you're solving (create one if it doesn't exist).\n\n> **Note:** To disclose security issues, refer to [SECURITY.md](https://github.com/grafana/k6?tab=security-ov-file).\n\n## Support\n\nTo get help, report bugs, suggest features, and discuss k6 with others, refer to [SUPPORT.md](SUPPORT.md).\n\n## License\n\nk6 is distributed under the [AGPL-3.0 license](https://github.com/grafana/k6/blob/master/LICENSE.md).\n"
  },
  {
    "path": "SUPPORT.md",
    "content": "# Support\n\nTypes of questions and where to ask:\n\n- How do I? -- the Discourse forum at [community.k6.io](https://community.k6.io/) or [Stack Overflow](https://stackoverflow.com/questions/tagged/k6) (use tags: k6, javascript, load-testing)\n- I got this error, why? -- [community.k6.io](https://community.k6.io/) or [Stack Overflow](https://stackoverflow.com/questions/tagged/k6)\n- I got this error and I'm sure it's a bug -- [open a new issue](https://github.com/grafana/k6/issues), if there isn't one for this specific bug already\n- I have an idea/request -- search the [GitHub issues](https://github.com/grafana/k6/issues) to see if it was already requested and give the issue a :+1: if so. If it wasn't, search [community.k6.io](https://community.k6.io/) or post a forum thread to discuss the idea with the developers before creating a GitHub issue.\n- Why do you? -- [community.k6.io](https://community.k6.io/)\n- When will you? -- check the [public roadmap](https://github.com/orgs/grafana/projects/443/views/1). They are not development promises, they are insights of what is on the radar for the team.\n\nIf your questions are related to the commercial [Grafana Cloud k6](https://grafana.com/products/cloud/k6) service, check the available options on the dedicated page on [Grafana Cloud documentation](https://grafana.com/docs/grafana-cloud/account-management/support).\n"
  },
  {
    "path": "api/v1/client/client.go",
    "content": "// Package client provides a simple go-client for the k6's REST API.\npackage client\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\tv1 \"go.k6.io/k6/api/v1\"\n)\n\n// Client is a simple HTTP client for the REST API.\ntype Client struct {\n\tBaseURL    *url.URL\n\thttpClient *http.Client\n\tlogger     *logrus.Entry\n}\n\n// Option function are helpers that enable the flexible configuration of the\n// REST API client.\ntype Option func(*Client)\n\n// New returns a newly configured REST API Client.\nfunc New(base string, options ...Option) (*Client, error) {\n\tbaseURL, err := url.Parse(\"http://\" + base)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc := &Client{\n\t\tBaseURL:    baseURL,\n\t\thttpClient: http.DefaultClient,\n\t}\n\n\tfor _, option := range options {\n\t\toption(c)\n\t}\n\n\treturn c, nil\n}\n\n// WithHTTPClient configures the supplied HTTP client to be used when making\n// REST API requests.\nfunc WithHTTPClient(httpClient *http.Client) Option {\n\treturn Option(func(c *Client) {\n\t\tc.httpClient = httpClient\n\t})\n}\n\n// WithLogger sets the specified logger to the client.\nfunc WithLogger(logger *logrus.Entry) Option {\n\treturn Option(func(c *Client) {\n\t\tc.logger = logger\n\t})\n}\n\n// CallAPI executes the desired REST API request.\n// it's expected that the body and out are the structs that follows the JSON:API\nfunc (c *Client) CallAPI(ctx context.Context, method string, rel *url.URL, body, out any) (err error) {\n\tif c.logger != nil {\n\t\tc.logger.Debugf(\"[REST API] Making a %s request to '%s'\", method, rel.String())\n\t\tdefer func() {\n\t\t\tif err != nil {\n\t\t\t\tc.logger.WithError(err).Error(\"[REST API] Error\")\n\t\t\t}\n\t\t}()\n\t}\n\n\tvar bodyReader io.ReadCloser\n\tif body != nil {\n\t\tvar bodyData []byte\n\t\tswitch val := body.(type) {\n\t\tcase []byte:\n\t\t\tbodyData = val\n\t\tcase string:\n\t\t\tbodyData = []byte(val)\n\t\tdefault:\n\t\t\tbodyData, err = json.Marshal(body)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tbodyReader = io.NopCloser(bytes.NewBuffer(bodyData))\n\t}\n\n\treq := &http.Request{\n\t\tMethod: method,\n\t\tURL:    c.BaseURL.ResolveReference(rel),\n\t\tBody:   bodyReader,\n\t}\n\treq = req.WithContext(ctx)\n\n\tres, err := c.httpClient.Do(req) //nolint:gosec\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() { _ = res.Body.Close() }()\n\n\tdata, err := io.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif res.StatusCode >= 400 {\n\t\tvar errs v1.ErrorResponse\n\t\tif err := json.Unmarshal(data, &errs); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn errs.Errors[0]\n\t}\n\n\tif out != nil {\n\t\treturn json.Unmarshal(data, out)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "api/v1/client/metrics.go",
    "content": "package client\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\n\tv1 \"go.k6.io/k6/api/v1\"\n)\n\n// Metrics returns the current metrics summary.\nfunc (c *Client) Metrics(ctx context.Context) (ret []v1.Metric, err error) {\n\tvar resp v1.MetricsJSONAPI\n\n\terr = c.CallAPI(ctx, http.MethodGet, &url.URL{Path: \"/v1/metrics\"}, nil, &resp)\n\tif err != nil {\n\t\treturn ret, err\n\t}\n\n\treturn resp.Metrics(), nil\n}\n"
  },
  {
    "path": "api/v1/client/status.go",
    "content": "package client\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/url\"\n\n\tv1 \"go.k6.io/k6/api/v1\"\n)\n\n// Status returns the current k6 status.\nfunc (c *Client) Status(ctx context.Context) (ret v1.Status, err error) {\n\tvar resp v1.StatusJSONAPI\n\n\tif err = c.CallAPI(ctx, http.MethodGet, &url.URL{Path: \"/v1/status\"}, nil, &resp); err != nil {\n\t\treturn ret, err\n\t}\n\n\treturn resp.Status(), nil\n}\n\n// SetStatus tries to change the current status and returns the new one if it\n// was successful.\nfunc (c *Client) SetStatus(ctx context.Context, patch v1.Status) (ret v1.Status, err error) {\n\tvar resp v1.StatusJSONAPI\n\n\tapiURL := &url.URL{Path: \"/v1/status\"}\n\tif err = c.CallAPI(ctx, http.MethodPatch, apiURL, v1.NewStatusJSONAPI(patch), &resp); err != nil {\n\t\treturn ret, err\n\t}\n\n\treturn resp.Status(), nil\n}\n"
  },
  {
    "path": "api/v1/control_surface.go",
    "content": "package v1\n\nimport (\n\t\"context\"\n\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/metrics/engine\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// ControlSurface includes the methods the REST API can use to control and\n// communicate with the rest of k6.\ntype ControlSurface struct {\n\tRunCtx        context.Context\n\tSamples       chan metrics.SampleContainer\n\tMetricsEngine *engine.MetricsEngine\n\tScheduler     *execution.Scheduler\n\tRunState      *lib.TestRunState\n}\n"
  },
  {
    "path": "api/v1/errors.go",
    "content": "package v1\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n)\n\n// Error is an api error\ntype Error struct {\n\tStatus string `json:\"status,omitempty\"`\n\tTitle  string `json:\"title,omitempty\"`\n\tDetail string `json:\"detail,omitempty\"`\n}\n\nfunc (e Error) Error() string {\n\treturn fmt.Sprintf(\"%s: %s\", e.Title, e.Detail)\n}\n\n// ErrorResponse is a struct wrapper around multiple errors\ntype ErrorResponse struct {\n\tErrors []Error `json:\"errors\"`\n}\n\nfunc apiError(rw http.ResponseWriter, title, detail string, status int) {\n\tdoc := ErrorResponse{\n\t\tErrors: []Error{\n\t\t\t{\n\t\t\t\tStatus: strconv.Itoa(status),\n\t\t\t\tTitle:  title,\n\t\t\t\tDetail: detail,\n\t\t\t},\n\t\t},\n\t}\n\tdata, err := json.Marshal(doc)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\trw.WriteHeader(status)\n\t_, _ = rw.Write(data)\n}\n"
  },
  {
    "path": "api/v1/group.go",
    "content": "package v1\n\nimport (\n\t\"fmt\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\n// Check represents a k6's check in a k6 REST API\ntype Check struct {\n\tID     string `json:\"id\" yaml:\"id\"`\n\tPath   string `json:\"path\" yaml:\"path\"`\n\tName   string `json:\"name\" yaml:\"name\"`\n\tPasses int64  `json:\"passes\" yaml:\"passes\"`\n\tFails  int64  `json:\"fails\" yaml:\"fails\"`\n}\n\n// NewCheck constructs a new v1.Check struct that is used for\n// a check representation in a k6 REST API\nfunc NewCheck(c *lib.Check) Check {\n\treturn Check{\n\t\tID:     c.ID,\n\t\tPath:   c.Path,\n\t\tName:   c.Name,\n\t\tPasses: c.Passes,\n\t\tFails:  c.Fails,\n\t}\n}\n\n// Group represents a k6's group in a k6 REST API\ntype Group struct {\n\tID     string  `json:\"-\" yaml:\"id\"`\n\tPath   string  `json:\"path\" yaml:\"path\"`\n\tName   string  `json:\"name\" yaml:\"name\"`\n\tChecks []Check `json:\"checks\" yaml:\"checks\"`\n\n\tParent   *Group   `json:\"-\" yaml:\"-\"`\n\tParentID string   `json:\"-\" yaml:\"parent-id\"`\n\tGroups   []*Group `json:\"-\" yaml:\"-\"`\n\tGroupIDs []string `json:\"-\" yaml:\"group-ids\"`\n}\n\n// NewGroup constructs a new v1.Group struct that is used for\n// a group representation in a k6 REST API\nfunc NewGroup(g *lib.Group, parent *Group) *Group {\n\tgroup := &Group{\n\t\tID:   g.ID,\n\t\tPath: g.Path,\n\t\tName: g.Name,\n\t}\n\n\tif parent != nil {\n\t\tgroup.Parent = parent\n\t\tgroup.ParentID = parent.ID\n\t} else if g.Parent != nil {\n\t\tgroup.Parent = NewGroup(g.Parent, nil)\n\t\tgroup.ParentID = g.Parent.ID\n\t}\n\n\tfor _, gp := range g.Groups {\n\t\tgroup.Groups = append(group.Groups, NewGroup(gp, group))\n\t\tgroup.GroupIDs = append(group.GroupIDs, gp.ID)\n\t}\n\tfor _, c := range g.Checks {\n\t\tgroup.Checks = append(group.Checks, NewCheck(c))\n\t}\n\n\treturn group\n}\n\n// SetToManyReferenceIDs sets to-many relations (groups) for a group\nfunc (g *Group) SetToManyReferenceIDs(name string, ids []string) error {\n\tswitch name {\n\tcase \"groups\":\n\t\tg.Groups = nil\n\t\tg.GroupIDs = ids\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown to many relation: %s\", name)\n\t}\n}\n\n// SetToOneReferenceID sets to-one relation (parent) for a group\nfunc (g *Group) SetToOneReferenceID(name, id string) error {\n\tswitch name {\n\tcase \"parent\":\n\t\tg.Parent = nil\n\t\tg.ParentID = id\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown to one relation: %s\", name)\n\t}\n}\n\n// FlattenGroup flattens a group and all its subgroups\n// into a slice of groups\nfunc FlattenGroup(g *Group) []*Group {\n\tgroups := make([]*Group, 0, 1+len(g.Groups))\n\tgroups = append(groups, g)\n\tfor _, gp := range g.Groups {\n\t\tgroups = append(groups, FlattenGroup(gp)...)\n\t}\n\treturn groups\n}\n"
  },
  {
    "path": "api/v1/group_jsonapi.go",
    "content": "package v1\n\nimport \"encoding/json\"\n\ntype groupJSONAPI struct {\n\tData groupData `json:\"data\"`\n}\n\ntype groupsJSONAPI struct {\n\tData []groupData `json:\"data\"`\n}\n\ntype groupData struct {\n\tType          string         `json:\"type\"`\n\tID            string         `json:\"id\"`\n\tAttributes    Group          `json:\"attributes\"`\n\tRelationships groupRelations `json:\"relationships\"`\n}\n\ntype groupRelations struct {\n\tGroups struct {\n\t\tData []groupRelation `json:\"data\"`\n\t} `json:\"groups\"`\n\tParent struct {\n\t\tData *groupRelation `json:\"data\"`\n\t} `json:\"parent\"`\n}\n\ntype groupRelation struct {\n\tType string `json:\"type\"`\n\tID   string `json:\"id\"`\n}\n\n// UnmarshalJSON unmarshal group data properly (extract the ID)\nfunc (g *groupData) UnmarshalJSON(data []byte) error {\n\tvar raw struct {\n\t\tType          string         `json:\"type\"`\n\t\tID            string         `json:\"id\"`\n\t\tAttributes    Group          `json:\"attributes\"`\n\t\tRelationships groupRelations `json:\"relationships\"`\n\t}\n\n\tif err := json.Unmarshal(data, &raw); err != nil {\n\t\treturn err\n\t}\n\n\tg.ID = raw.ID\n\tg.Type = raw.Type\n\tg.Relationships = raw.Relationships\n\tg.Attributes = raw.Attributes\n\n\tif g.Attributes.ID == \"\" {\n\t\tg.Attributes.ID = raw.ID\n\t}\n\n\tif g.Relationships.Parent.Data != nil {\n\t\tg.Attributes.ParentID = g.Relationships.Parent.Data.ID\n\t}\n\n\tg.Attributes.GroupIDs = make([]string, 0, len(g.Relationships.Groups.Data))\n\tfor _, rel := range g.Relationships.Groups.Data {\n\t\tg.Attributes.GroupIDs = append(g.Attributes.GroupIDs, rel.ID)\n\t}\n\n\treturn nil\n}\n\nfunc newGroupJSONAPI(g *Group) groupJSONAPI {\n\treturn groupJSONAPI{\n\t\tData: newGroupData(g),\n\t}\n}\n\nfunc newGroupsJSONAPI(groups []*Group) groupsJSONAPI {\n\tenvelop := groupsJSONAPI{\n\t\tData: make([]groupData, 0, len(groups)),\n\t}\n\n\tfor _, g := range groups {\n\t\tenvelop.Data = append(envelop.Data, newGroupData(g))\n\t}\n\n\treturn envelop\n}\n\nfunc newGroupData(group *Group) groupData {\n\tdata := groupData{\n\t\tType:       \"groups\",\n\t\tID:         group.ID,\n\t\tAttributes: *group,\n\t\tRelationships: groupRelations{\n\t\t\tGroups: struct {\n\t\t\t\tData []groupRelation `json:\"data\"`\n\t\t\t}{\n\t\t\t\tData: make([]groupRelation, 0, len(group.Groups)),\n\t\t\t},\n\t\t\tParent: struct {\n\t\t\t\tData *groupRelation `json:\"data\"`\n\t\t\t}{},\n\t\t},\n\t}\n\n\tif group.Parent != nil {\n\t\tdata.Relationships.Parent.Data = &groupRelation{\n\t\t\tType: \"groups\",\n\t\t\tID:   group.Parent.ID,\n\t\t}\n\t}\n\n\tfor _, gp := range group.Groups {\n\t\tdata.Relationships.Groups.Data = append(data.Relationships.Groups.Data, groupRelation{\n\t\t\tID:   gp.ID,\n\t\t\tType: \"groups\",\n\t\t})\n\t}\n\n\treturn data\n}\n"
  },
  {
    "path": "api/v1/group_routes.go",
    "content": "package v1\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\nfunc handleGetGroups(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request) {\n\troot := NewGroup(cs.RunState.GroupSummary.Group(), nil)\n\tgroups := FlattenGroup(root)\n\n\tdata, err := json.Marshal(newGroupsJSONAPI(groups))\n\tif err != nil {\n\t\tapiError(rw, \"Encoding error\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\t_, _ = rw.Write(data)\n}\n\nfunc handleGetGroup(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request, id string) {\n\troot := NewGroup(cs.RunState.GroupSummary.Group(), nil)\n\tgroups := FlattenGroup(root)\n\n\tvar group *Group\n\tfor _, g := range groups {\n\t\tif g.ID == id {\n\t\t\tgroup = g\n\t\t\tbreak\n\t\t}\n\t}\n\tif group == nil {\n\t\tapiError(rw, \"Not Found\", \"No group with that ID was found\", http.StatusNotFound)\n\t\treturn\n\t}\n\n\tdata, err := json.Marshal(newGroupJSONAPI(group))\n\tif err != nil {\n\t\tapiError(rw, \"Encoding error\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\t_, _ = rw.Write(data)\n}\n"
  },
  {
    "path": "api/v1/group_routes_test.go",
    "content": "package v1\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/internal/metrics/engine\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc getTestPreInitState(tb testing.TB) *lib.TestPreInitState {\n\treg := metrics.NewRegistry()\n\tlogger := testutils.NewLogger(tb)\n\treturn &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tRuntimeOptions: lib.RuntimeOptions{},\n\t\tRegistry:       reg,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(reg),\n\t\tUsage:          usage.New(),\n\t}\n}\n\nfunc getTestRunState(tb testing.TB, options lib.Options, runner lib.Runner) *lib.TestRunState {\n\trequire.NoError(tb, runner.SetOptions(runner.GetOptions().Apply(options)))\n\tpiState := getTestPreInitState(tb)\n\treturn &lib.TestRunState{\n\t\tTestPreInitState: piState,\n\t\tOptions:          options,\n\t\tRunner:           runner,\n\t\tGroupSummary:     lib.NewGroupSummary(piState.Logger),\n\t\tRunTags:          piState.Registry.RootTagSet().WithTagsFromMap(options.RunTags),\n\t}\n}\n\nfunc getControlSurface(tb testing.TB, testState *lib.TestRunState) *ControlSurface {\n\texecScheduler, err := execution.NewScheduler(testState, local.NewController())\n\trequire.NoError(tb, err)\n\n\tme, err := engine.NewMetricsEngine(testState.Registry, testState.Logger)\n\trequire.NoError(tb, err)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\ttb.Cleanup(cancel)\n\tctx, _ = execution.NewTestRunContext(ctx, testState.Logger)\n\n\treturn &ControlSurface{\n\t\tRunCtx:        ctx,\n\t\tSamples:       make(chan metrics.SampleContainer, 1000),\n\t\tMetricsEngine: me,\n\t\tScheduler:     execScheduler,\n\t\tRunState:      testState,\n\t}\n}\n\nfunc TestGetGroups(t *testing.T) {\n\tt.Parallel()\n\n\tcs := getControlSurface(t, getTestRunState(t, lib.Options{}, &minirunner.MiniRunner{}))\n\trequire.NoError(t, cs.RunState.GroupSummary.Start())\n\tcs.RunState.GroupSummary.AddMetricSamples([]metrics.SampleContainer{\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: cs.RunState.BuiltinMetrics.GroupDuration,\n\t\t\t\tTags:   cs.RunState.Registry.RootTagSet().With(\"group\", \"::group 1\"),\n\t\t\t},\n\t\t},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: cs.RunState.BuiltinMetrics.GroupDuration,\n\t\t\t\tTags:   cs.RunState.Registry.RootTagSet().With(\"group\", \"\"),\n\t\t\t},\n\t\t},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: cs.RunState.BuiltinMetrics.GroupDuration,\n\t\t\t\tTags:   cs.RunState.Registry.RootTagSet().With(\"group\", \"::group 1::group 2\"),\n\t\t\t},\n\t\t},\n\t})\n\trequire.NoError(t, cs.RunState.GroupSummary.Stop())\n\n\tg0, err := lib.NewGroup(\"\", nil)\n\tassert.NoError(t, err)\n\tg1, err := g0.Group(\"group 1\")\n\tassert.NoError(t, err)\n\tg2, err := g1.Group(\"group 2\")\n\tassert.NoError(t, err)\n\n\tt.Run(\"list\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trw := httptest.NewRecorder()\n\t\tNewHandler(cs).ServeHTTP(rw, httptest.NewRequest(http.MethodGet, \"/v1/groups\", nil))\n\t\tres := rw.Result()\n\t\tt.Cleanup(func() {\n\t\t\tassert.NoError(t, res.Body.Close())\n\t\t})\n\t\tbody := rw.Body.Bytes()\n\t\tassert.Equal(t, http.StatusOK, res.StatusCode)\n\t\tassert.NotEmpty(t, body)\n\n\t\tt.Run(\"document\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar doc groupsJSONAPI\n\t\t\tassert.NoError(t, json.Unmarshal(body, &doc))\n\t\t\tif assert.NotEmpty(t, doc.Data) {\n\t\t\t\tassert.Equal(t, \"groups\", doc.Data[0].Type)\n\t\t\t}\n\t\t})\n\n\t\tt.Run(\"groups\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar envelop groupsJSONAPI\n\t\t\trequire.NoError(t, json.Unmarshal(body, &envelop))\n\t\t\trequire.Len(t, envelop.Data, 3)\n\n\t\t\tfor _, data := range envelop.Data {\n\t\t\t\tcurrent := data.Attributes\n\n\t\t\t\tswitch current.ID {\n\t\t\t\tcase g0.ID:\n\t\t\t\t\tassert.Equal(t, \"\", current.Name)\n\t\t\t\t\tassert.Nil(t, current.Parent)\n\t\t\t\t\tassert.Equal(t, \"\", current.ParentID)\n\t\t\t\t\tassert.Len(t, current.GroupIDs, 1)\n\t\t\t\t\tassert.EqualValues(t, []string{g1.ID}, current.GroupIDs)\n\t\t\t\tcase g1.ID:\n\t\t\t\t\tassert.Equal(t, \"group 1\", current.Name)\n\t\t\t\t\tassert.Nil(t, current.Parent)\n\t\t\t\t\tassert.Equal(t, g0.ID, current.ParentID)\n\t\t\t\t\tassert.EqualValues(t, []string{g2.ID}, current.GroupIDs)\n\t\t\t\tcase g2.ID:\n\t\t\t\t\tassert.Equal(t, \"group 2\", current.Name)\n\t\t\t\t\tassert.Nil(t, current.Parent)\n\t\t\t\t\tassert.Equal(t, g1.ID, current.ParentID)\n\t\t\t\t\tassert.EqualValues(t, []string{}, current.GroupIDs)\n\t\t\t\tdefault:\n\t\t\t\t\tassert.Fail(t, \"Unknown ID: \"+current.ID)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t})\n\tfor _, gp := range []*lib.Group{g0, g1, g2} {\n\t\tt.Run(gp.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trw := httptest.NewRecorder()\n\t\t\tNewHandler(cs).ServeHTTP(rw, httptest.NewRequest(http.MethodGet, \"/v1/groups/\"+gp.ID, nil))\n\t\t\tres := rw.Result()\n\t\t\tt.Cleanup(func() {\n\t\t\t\tassert.NoError(t, res.Body.Close())\n\t\t\t})\n\t\t\tassert.Equal(t, http.StatusOK, res.StatusCode)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "api/v1/group_test.go",
    "content": "package v1\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\nfunc TestNewCheck(t *testing.T) {\n\tt.Parallel()\n\n\tog, err := lib.NewGroup(\"\", nil)\n\tassert.NoError(t, err)\n\toc, err := lib.NewCheck(\"my check\", og)\n\tassert.NoError(t, err)\n\toc.Passes = 1234\n\toc.Fails = 5678\n\n\tc := NewCheck(oc)\n\tassert.Equal(t, oc.ID, c.ID)\n\tassert.Equal(t, \"my check\", c.Name)\n\tassert.Equal(t, int64(1234), c.Passes)\n\tassert.Equal(t, int64(5678), c.Fails)\n}\n\nfunc TestNewGroup(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"simple\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tog, err := lib.NewGroup(\"My Group\", nil)\n\t\tassert.NoError(t, err)\n\n\t\tg := NewGroup(og, nil)\n\t\tassert.Equal(t, og.ID, g.ID)\n\t\tassert.Equal(t, og.Name, g.Name)\n\t\tassert.Nil(t, g.Parent)\n\t\tassert.Empty(t, g.Groups)\n\t})\n\tt.Run(\"groups\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\troot, _ := lib.NewGroup(\"My Group\", nil)\n\t\tchild, _ := root.Group(\"Child\")\n\t\tinner, _ := child.Group(\"Inner\")\n\n\t\tg := NewGroup(root, nil)\n\t\tassert.Equal(t, root.ID, g.ID)\n\t\tassert.Equal(t, \"My Group\", g.Name)\n\t\tassert.Nil(t, g.Parent)\n\t\tassert.Len(t, g.Groups, 1)\n\t\tassert.Len(t, g.Checks, 0)\n\n\t\tassert.Equal(t, \"Child\", g.Groups[0].Name)\n\t\tassert.Equal(t, child.ID, g.Groups[0].ID)\n\t\tassert.Equal(t, \"My Group\", g.Groups[0].Parent.Name)\n\t\tassert.Equal(t, root.ID, g.Groups[0].Parent.ID)\n\n\t\tassert.Equal(t, \"Inner\", g.Groups[0].Groups[0].Name)\n\t\tassert.Equal(t, inner.ID, g.Groups[0].Groups[0].ID)\n\t\tassert.Equal(t, \"Child\", g.Groups[0].Groups[0].Parent.Name)\n\t\tassert.Equal(t, child.ID, g.Groups[0].Groups[0].Parent.ID)\n\t\tassert.Equal(t, \"My Group\", g.Groups[0].Groups[0].Parent.Parent.Name)\n\t\tassert.Equal(t, root.ID, g.Groups[0].Groups[0].Parent.Parent.ID)\n\t})\n\tt.Run(\"checks\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tog, _ := lib.NewGroup(\"My Group\", nil)\n\t\tcheck, _ := og.Check(\"my check\")\n\n\t\tg := NewGroup(og, nil)\n\t\tassert.Equal(t, og.ID, g.ID)\n\t\tassert.Equal(t, \"My Group\", g.Name)\n\t\tassert.Nil(t, g.Parent)\n\t\tassert.Len(t, g.Groups, 0)\n\t\tassert.Len(t, g.Checks, 1)\n\n\t\tassert.Equal(t, check.ID, g.Checks[0].ID)\n\t\tassert.Equal(t, \"my check\", g.Checks[0].Name)\n\t})\n}\n\nfunc TestFlattenGroup(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"blank\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tg := &Group{}\n\t\tassert.EqualValues(t, []*Group{g}, FlattenGroup(g))\n\t})\n\tt.Run(\"one level\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tg := &Group{}\n\t\tg1 := &Group{Parent: g}\n\t\tg2 := &Group{Parent: g}\n\t\tg.Groups = []*Group{g1, g2}\n\t\tassert.EqualValues(t, []*Group{g, g1, g2}, FlattenGroup(g))\n\t})\n\tt.Run(\"two levels\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tg := &Group{}\n\t\tg1 := &Group{Parent: g}\n\t\tg1a := &Group{Parent: g1}\n\t\tg1b := &Group{Parent: g1}\n\t\tg1.Groups = []*Group{g1a, g1b}\n\t\tg2 := &Group{Parent: g}\n\t\tg.Groups = []*Group{g1, g2}\n\t\tassert.EqualValues(t, []*Group{g, g1, g1a, g1b, g2}, FlattenGroup(g))\n\t})\n}\n"
  },
  {
    "path": "api/v1/metric.go",
    "content": "package v1\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"time\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\n// NullMetricType a nullable metric struct\ntype NullMetricType struct {\n\tType  metrics.MetricType\n\tValid bool\n}\n\n// MarshalJSON implements the json.Marshaler interface.\nfunc (t NullMetricType) MarshalJSON() ([]byte, error) {\n\tif !t.Valid {\n\t\treturn []byte(\"null\"), nil\n\t}\n\treturn t.Type.MarshalJSON()\n}\n\n// UnmarshalJSON implements the json.Unmarshaler interface.\nfunc (t *NullMetricType) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(\"null\")) {\n\t\tt.Valid = false\n\t\treturn nil\n\t}\n\tt.Valid = true\n\treturn json.Unmarshal(data, &t.Type)\n}\n\n// NullValueType a nullable metric value struct\ntype NullValueType struct {\n\tType  metrics.ValueType\n\tValid bool\n}\n\n// MarshalJSON implements the json.Marshaler interface.\nfunc (t NullValueType) MarshalJSON() ([]byte, error) {\n\tif !t.Valid {\n\t\treturn []byte(\"null\"), nil\n\t}\n\treturn t.Type.MarshalJSON()\n}\n\n// UnmarshalJSON implements the json.Unmarshaler interface.\nfunc (t *NullValueType) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(\"null\")) {\n\t\tt.Valid = false\n\t\treturn nil\n\t}\n\tt.Valid = true\n\treturn json.Unmarshal(data, &t.Type)\n}\n\n// Metric represents a metric that is being collected by k6.\ntype Metric struct {\n\tName string `json:\"-\" yaml:\"name\"`\n\n\tType     NullMetricType `json:\"type\" yaml:\"type\"`\n\tContains NullValueType  `json:\"contains\" yaml:\"contains\"`\n\tTainted  null.Bool      `json:\"tainted\" yaml:\"tainted\"`\n\n\tSample map[string]float64 `json:\"sample\" yaml:\"sample\"`\n}\n\n// NewMetric constructs a new v1.Metric struct that is used for\n// a metric representation in a k6 REST API\nfunc NewMetric(m *metrics.Metric, t time.Duration) Metric {\n\treturn Metric{\n\t\tName:     m.Name,\n\t\tType:     NullMetricType{m.Type, true},\n\t\tContains: NullValueType{m.Contains, true},\n\t\tTainted:  m.Tainted,\n\t\tSample:   m.Sink.Format(t),\n\t}\n}\n"
  },
  {
    "path": "api/v1/metric_jsonapi.go",
    "content": "package v1\n\nimport (\n\t\"time\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\n// MetricsJSONAPI is JSON API envelop for metrics\ntype MetricsJSONAPI struct {\n\tData []metricData `json:\"data\"`\n}\n\ntype metricJSONAPI struct {\n\tData metricData `json:\"data\"`\n}\n\ntype metricData struct {\n\tType       string `json:\"type\"`\n\tID         string `json:\"id\"`\n\tAttributes Metric `json:\"attributes\"`\n}\n\nfunc newMetricEnvelope(m *metrics.Metric, t time.Duration) metricJSONAPI {\n\treturn metricJSONAPI{\n\t\tData: newMetricData(m, t),\n\t}\n}\n\nfunc newMetricsJSONAPI(list map[string]*metrics.Metric, t time.Duration) MetricsJSONAPI {\n\tmetrics := make([]metricData, 0, len(list))\n\n\tfor _, m := range list {\n\t\tmetrics = append(metrics, newMetricData(m, t))\n\t}\n\n\treturn MetricsJSONAPI{\n\t\tData: metrics,\n\t}\n}\n\nfunc newMetricData(m *metrics.Metric, t time.Duration) metricData {\n\tmetric := NewMetric(m, t)\n\n\treturn metricData{\n\t\tType:       \"metrics\",\n\t\tID:         metric.Name,\n\t\tAttributes: metric,\n\t}\n}\n\n// Metrics extract the []v1.Metric from the JSON API envelop\nfunc (m MetricsJSONAPI) Metrics() []Metric {\n\tlist := make([]Metric, 0, len(m.Data))\n\n\tfor _, metric := range m.Data {\n\t\tm := metric.Attributes\n\t\tm.Name = metric.ID\n\t\tlist = append(list, m)\n\t}\n\n\treturn list\n}\n"
  },
  {
    "path": "api/v1/metric_routes.go",
    "content": "package v1\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"time\"\n)\n\nfunc handleGetMetrics(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request) {\n\tvar t time.Duration\n\tif cs.Scheduler != nil {\n\t\tt = cs.Scheduler.GetState().GetCurrentTestRunDuration()\n\t}\n\n\tcs.MetricsEngine.MetricsLock.Lock()\n\tmetrics := newMetricsJSONAPI(cs.MetricsEngine.ObservedMetrics, t)\n\tcs.MetricsEngine.MetricsLock.Unlock()\n\n\tdata, err := json.Marshal(metrics)\n\tif err != nil {\n\t\tapiError(rw, \"Encoding error\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\t_, _ = rw.Write(data)\n}\n\nfunc handleGetMetric(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request, id string) {\n\tvar t time.Duration\n\tif cs.Scheduler != nil {\n\t\tt = cs.Scheduler.GetState().GetCurrentTestRunDuration()\n\t}\n\n\tcs.MetricsEngine.MetricsLock.Lock()\n\tmetric, ok := cs.MetricsEngine.ObservedMetrics[id]\n\tif !ok {\n\t\tcs.MetricsEngine.MetricsLock.Unlock()\n\t\tapiError(rw, \"Not Found\", \"No metric with that ID was found\", http.StatusNotFound)\n\t\treturn\n\t}\n\twrappedMetric := newMetricEnvelope(metric, t)\n\tcs.MetricsEngine.MetricsLock.Unlock()\n\n\tdata, err := json.Marshal(wrappedMetric)\n\tif err != nil {\n\t\tapiError(rw, \"Encoding error\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\t_, _ = rw.Write(data)\n}\n"
  },
  {
    "path": "api/v1/metric_routes_test.go",
    "content": "package v1\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestGetMetrics(t *testing.T) {\n\tt.Parallel()\n\n\ttestState := getTestRunState(t, lib.Options{}, &minirunner.MiniRunner{})\n\ttestMetric, err := testState.Registry.NewMetric(\"my_metric\", metrics.Trend, metrics.Time)\n\trequire.NoError(t, err)\n\tcs := getControlSurface(t, testState)\n\n\tcs.MetricsEngine.ObservedMetrics = map[string]*metrics.Metric{\n\t\t\"my_metric\": testMetric,\n\t}\n\tcs.MetricsEngine.ObservedMetrics[\"my_metric\"].Tainted = null.BoolFrom(true)\n\n\trw := httptest.NewRecorder()\n\tNewHandler(cs).ServeHTTP(rw, httptest.NewRequest(http.MethodGet, \"/v1/metrics\", nil))\n\tres := rw.Result()\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, res.Body.Close())\n\t})\n\tassert.Equal(t, http.StatusOK, res.StatusCode)\n\n\tt.Run(\"document\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar doc MetricsJSONAPI\n\t\tassert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &doc))\n\t\tif !assert.NotNil(t, doc.Data) {\n\t\t\treturn\n\t\t}\n\t\tassert.Equal(t, \"metrics\", doc.Data[0].Type)\n\t})\n\n\tt.Run(\"metrics\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar envelop MetricsJSONAPI\n\t\tassert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &envelop))\n\n\t\tmetricsData := envelop.Data\n\t\tif !assert.Len(t, metricsData, 1) {\n\t\t\treturn\n\t\t}\n\n\t\tmetric := metricsData[0].Attributes\n\n\t\tassert.Equal(t, \"my_metric\", metricsData[0].ID)\n\t\tassert.True(t, metric.Type.Valid)\n\t\tassert.Equal(t, metrics.Trend, metric.Type.Type)\n\t\tassert.True(t, metric.Contains.Valid)\n\t\tassert.Equal(t, metrics.Time, metric.Contains.Type)\n\t\tassert.True(t, metric.Tainted.Valid)\n\t\tassert.True(t, metric.Tainted.Bool)\n\n\t\tresMetrics := envelop.Metrics()\n\t\tassert.Len(t, resMetrics, 1)\n\t\tassert.Equal(t, \"my_metric\", resMetrics[0].Name)\n\t})\n}\n\nfunc TestGetMetric(t *testing.T) {\n\tt.Parallel()\n\n\ttestState := getTestRunState(t, lib.Options{}, &minirunner.MiniRunner{})\n\ttestMetric, err := testState.Registry.NewMetric(\"my_metric\", metrics.Trend, metrics.Time)\n\trequire.NoError(t, err)\n\tcs := getControlSurface(t, testState)\n\n\tcs.MetricsEngine.ObservedMetrics = map[string]*metrics.Metric{\n\t\t\"my_metric\": testMetric,\n\t}\n\tcs.MetricsEngine.ObservedMetrics[\"my_metric\"].Tainted = null.BoolFrom(true)\n\n\tt.Run(\"nonexistent\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trw := httptest.NewRecorder()\n\t\tNewHandler(cs).ServeHTTP(rw, httptest.NewRequest(http.MethodGet, \"/v1/metrics/notreal\", nil))\n\t\tres := rw.Result()\n\t\tt.Cleanup(func() {\n\t\t\tassert.NoError(t, res.Body.Close())\n\t\t})\n\t\tassert.Equal(t, http.StatusNotFound, res.StatusCode)\n\t})\n\n\tt.Run(\"real\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trw := httptest.NewRecorder()\n\t\tNewHandler(cs).ServeHTTP(rw, httptest.NewRequest(http.MethodGet, \"/v1/metrics/my_metric\", nil))\n\t\tres := rw.Result()\n\t\tt.Cleanup(func() {\n\t\t\tassert.NoError(t, res.Body.Close())\n\t\t})\n\t\tassert.Equal(t, http.StatusOK, res.StatusCode)\n\n\t\tt.Run(\"document\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar doc metricJSONAPI\n\t\t\tassert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &doc))\n\n\t\t\tassert.Equal(t, \"metrics\", doc.Data.Type)\n\t\t})\n\n\t\tt.Run(\"metric\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar envelop metricJSONAPI\n\n\t\t\tassert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &envelop))\n\n\t\t\tmetric := envelop.Data.Attributes\n\n\t\t\tassert.Equal(t, \"my_metric\", envelop.Data.ID)\n\t\t\tassert.True(t, metric.Type.Valid)\n\t\t\tassert.Equal(t, metrics.Trend, metric.Type.Type)\n\t\t\tassert.True(t, metric.Contains.Valid)\n\t\t\tassert.Equal(t, metrics.Time, metric.Contains.Type)\n\t\t\tassert.True(t, metric.Tainted.Valid)\n\t\t\tassert.True(t, metric.Tainted.Bool)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "api/v1/metric_test.go",
    "content": "package v1\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestNullMetricTypeJSON(t *testing.T) {\n\tt.Parallel()\n\n\tvalues := map[NullMetricType]string{\n\t\t{}:                      `null`,\n\t\t{metrics.Counter, true}: `\"counter\"`,\n\t\t{metrics.Gauge, true}:   `\"gauge\"`,\n\t\t{metrics.Trend, true}:   `\"trend\"`,\n\t\t{metrics.Rate, true}:    `\"rate\"`,\n\t}\n\tt.Run(\"Marshal\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor mt, val := range values {\n\t\t\tt.Run(val, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tdata, err := json.Marshal(mt)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, val, string(data))\n\t\t\t})\n\t\t}\n\t})\n\tt.Run(\"Unmarshal\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor mt, val := range values {\n\t\t\tt.Run(val, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tvar value NullMetricType\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(val), &value))\n\t\t\t\tassert.Equal(t, mt, value)\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestNullValueTypeJSON(t *testing.T) {\n\tt.Parallel()\n\n\tvalues := map[NullValueType]string{\n\t\t{}:                      `null`,\n\t\t{metrics.Default, true}: `\"default\"`,\n\t\t{metrics.Time, true}:    `\"time\"`,\n\t}\n\tt.Run(\"Marshal\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor mt, val := range values {\n\t\t\tt.Run(val, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tdata, err := json.Marshal(mt)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, val, string(data))\n\t\t\t})\n\t\t}\n\t})\n\tt.Run(\"Unmarshal\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor mt, val := range values {\n\t\t\tt.Run(val, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tvar value NullValueType\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(val), &value))\n\t\t\t\tassert.Equal(t, mt, value)\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestNewMetric(t *testing.T) {\n\tt.Parallel()\n\n\told, err := metrics.NewRegistry().NewMetric(\"test_metric\", metrics.Trend, metrics.Time)\n\trequire.NoError(t, err)\n\told.Tainted = null.BoolFrom(true)\n\tm := NewMetric(old, 0)\n\tassert.Equal(t, \"test_metric\", m.Name)\n\tassert.True(t, m.Type.Valid)\n\tassert.Equal(t, metrics.Trend, m.Type.Type)\n\tassert.True(t, m.Contains.Valid)\n\tassert.True(t, m.Tainted.Bool)\n\tassert.True(t, m.Tainted.Valid)\n\tassert.Equal(t, metrics.Time, m.Contains.Type)\n\tassert.NotEmpty(t, m.Sample)\n}\n"
  },
  {
    "path": "api/v1/routes.go",
    "content": "// Package v1 implements the v1 of the k6's REST API\npackage v1\n\nimport (\n\t\"net/http\"\n)\n\n// NewHandler returns the top handler for the v1 REST APIs\nfunc NewHandler(cs *ControlSurface) http.Handler {\n\tmux := http.NewServeMux()\n\n\tmux.HandleFunc(\"/v1/status\", func(rw http.ResponseWriter, r *http.Request) {\n\t\tswitch r.Method {\n\t\tcase http.MethodGet:\n\t\t\thandleGetStatus(cs, rw, r)\n\t\tcase http.MethodPatch:\n\t\t\thandlePatchStatus(cs, rw, r)\n\t\tdefault:\n\t\t\trw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t}\n\t})\n\n\tmux.HandleFunc(\"/v1/metrics\", func(rw http.ResponseWriter, r *http.Request) {\n\t\tif r.Method != http.MethodGet {\n\t\t\trw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\t\thandleGetMetrics(cs, rw, r)\n\t})\n\n\tmux.HandleFunc(\"/v1/metrics/\", func(rw http.ResponseWriter, r *http.Request) {\n\t\tif r.Method != http.MethodGet {\n\t\t\trw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\n\t\tid := r.URL.Path[len(\"/v1/metrics/\"):]\n\t\thandleGetMetric(cs, rw, r, id)\n\t})\n\n\tmux.HandleFunc(\"/v1/groups\", func(rw http.ResponseWriter, r *http.Request) {\n\t\tif r.Method != http.MethodGet {\n\t\t\trw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\n\t\thandleGetGroups(cs, rw, r)\n\t})\n\n\tmux.HandleFunc(\"/v1/groups/\", func(rw http.ResponseWriter, r *http.Request) {\n\t\tif r.Method != http.MethodGet {\n\t\t\trw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\n\t\tid := r.URL.Path[len(\"/v1/groups/\"):]\n\t\thandleGetGroup(cs, rw, r, id)\n\t})\n\n\tmux.HandleFunc(\"/v1/setup\", func(rw http.ResponseWriter, r *http.Request) {\n\t\tswitch r.Method {\n\t\tcase http.MethodPost:\n\t\t\thandleRunSetup(cs, rw, r)\n\t\tcase http.MethodPut:\n\t\t\thandleSetSetupData(cs, rw, r)\n\t\tcase http.MethodGet:\n\t\t\thandleGetSetupData(cs, rw, r)\n\t\tdefault:\n\t\t\trw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t}\n\t})\n\n\tmux.HandleFunc(\"/v1/teardown\", func(rw http.ResponseWriter, r *http.Request) {\n\t\tif r.Method != http.MethodPost {\n\t\t\trw.WriteHeader(http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\n\t\thandleRunTeardown(cs, rw, r)\n\t})\n\n\treturn mux\n}\n"
  },
  {
    "path": "api/v1/setup_jsonapi.go",
    "content": "package v1\n\ntype setUpJSONAPI struct {\n\tData setUpData `json:\"data\"`\n}\n\ntype setUpData struct {\n\tType       string `json:\"type\"`\n\tID         string `json:\"id\"`\n\tAttributes any    `json:\"attributes\"`\n}\n\nfunc newSetUpJSONAPI(setup any) setUpJSONAPI {\n\treturn setUpJSONAPI{\n\t\tData: setUpData{\n\t\t\tType:       \"setupData\",\n\t\t\tID:         \"default\",\n\t\t\tAttributes: setup,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "api/v1/setup_teardown_routes.go",
    "content": "package v1\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n)\n\n// NullSetupData is wrapper around null to satisfy jsonapi\ntype NullSetupData struct {\n\tSetupData\n\tData any `json:\"data,omitempty\" yaml:\"data\"`\n}\n\n// SetupData is just a simple wrapper to satisfy jsonapi\ntype SetupData struct {\n\tData any `json:\"data\" yaml:\"data\"`\n}\n\nfunc handleSetupDataOutput(rw http.ResponseWriter, setupData json.RawMessage) {\n\trw.Header().Set(\"Content-Type\", \"application/json\")\n\tvar err error\n\tvar data []byte\n\n\tif setupData == nil {\n\t\tdata, err = json.Marshal(newSetUpJSONAPI(NullSetupData{Data: nil}))\n\t} else {\n\t\tdata, err = json.Marshal(newSetUpJSONAPI(SetupData{setupData}))\n\t}\n\tif err != nil {\n\t\tapiError(rw, \"Encoding error\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t_, _ = rw.Write(data)\n}\n\n// handleGetSetupData just returns the current JSON-encoded setup data\nfunc handleGetSetupData(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request) {\n\thandleSetupDataOutput(rw, cs.RunState.Runner.GetSetupData())\n}\n\n// handleSetSetupData just parses the JSON request body and sets the result as setup data for the runner\nfunc handleSetSetupData(cs *ControlSurface, rw http.ResponseWriter, r *http.Request) {\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\tapiError(rw, \"Error reading request body\", err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tvar data any\n\tif len(body) > 0 {\n\t\tif err := json.Unmarshal(body, &data); err != nil {\n\t\t\tapiError(rw, \"Error parsing request body\", err.Error(), http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t}\n\n\trunner := cs.RunState.Runner\n\tif len(body) == 0 {\n\t\trunner.SetSetupData(nil)\n\t} else {\n\t\trunner.SetSetupData(body)\n\t}\n\n\thandleSetupDataOutput(rw, runner.GetSetupData())\n}\n\n// handleRunSetup executes the runner's Setup() method and returns the result\nfunc handleRunSetup(cs *ControlSurface, rw http.ResponseWriter, r *http.Request) {\n\trunner := cs.RunState.Runner\n\n\tif err := cs.RunState.Runner.Setup(r.Context(), cs.Samples); err != nil {\n\t\tcs.RunState.Logger.WithError(err).Error(\"Error executing setup\")\n\t\tapiError(rw, \"Error executing setup\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\thandleSetupDataOutput(rw, runner.GetSetupData())\n}\n\n// handleRunTeardown executes the runner's Teardown() method\nfunc handleRunTeardown(cs *ControlSurface, rw http.ResponseWriter, r *http.Request) {\n\tif err := cs.RunState.Runner.Teardown(r.Context(), cs.Samples); err != nil {\n\t\tcs.RunState.Logger.WithError(err).Error(\"Error executing teardown\")\n\t\tapiError(rw, \"Error executing teardown\", err.Error(), http.StatusInternalServerError)\n\t}\n}\n"
  },
  {
    "path": "api/v1/setup_teardown_routes_test.go",
    "content": "package v1\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/js\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/metrics/engine\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc TestSetupData(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tname      string\n\t\tscript    []byte\n\t\tsetupRuns [][3]string\n\t}{\n\t\t{\n\t\t\tname: \"setupReturns\",\n\t\t\tscript: []byte(`\n\t\t\texport function setup() {\n\t\t\t\treturn {\"v\": 1};\n\t\t\t}\n\n\t\t\texport default function(data) {\n\t\t\t\tif (data !== undefined) {\n\t\t\t\t\tthrow new Error(\"incorrect data: \" + JSON.stringify(data));\n\t\t\t\t}\n\t\t\t};\n\n\t\t\texport function teardown(data) {\n\t\t\t\tif (data !== undefined) {\n\t\t\t\t\tthrow new Error(\"incorrect teardown data: \" + JSON.stringify(data));\n\t\t\t\t}\n\t\t\t} `),\n\t\t\tsetupRuns: [][3]string{\n\t\t\t\t{\"GET\", \"\", \"{}\"},\n\t\t\t\t{\"POST\", \"\", `{\"data\": {\"v\":1}}`},\n\t\t\t\t{\"GET\", \"\", `{\"data\": {\"v\":1}}`},\n\t\t\t\t{\"PUT\", `{\"v\":2, \"test\":\"mest\"}`, `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t\t{\"GET\", \"\", `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t\t{\"PUT\", \"\", `{}`},\n\t\t\t\t{\"GET\", \"\", `{}`},\n\t\t\t},\n\t\t}, {\n\t\t\tname: \"noSetup\",\n\t\t\tscript: []byte(`\n\t\t\texport default function(data) {\n\t\t\t\tif (!data || data.v != 2) {\n\t\t\t\t\tthrow new Error(\"incorrect data: \" + JSON.stringify(data));\n\t\t\t\t}\n\t\t\t};\n\n\t\t\texport function teardown(data) {\n\t\t\t\tif (!data || data.v != 2) {\n\t\t\t\t\tthrow new Error(\"incorrect teardown data: \" + JSON.stringify(data));\n\t\t\t\t}\n\t\t\t} `),\n\t\t\tsetupRuns: [][3]string{\n\t\t\t\t{\"GET\", \"\", \"{}\"},\n\t\t\t\t{\"POST\", \"\", `{}`},\n\t\t\t\t{\"GET\", \"\", `{}`},\n\t\t\t\t{\"PUT\", `{\"v\":2, \"test\":\"mest\"}`, `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t\t{\"GET\", \"\", `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t\t{\"PUT\", \"\", `{}`},\n\t\t\t\t{\"GET\", \"\", `{}`},\n\t\t\t\t{\"PUT\", `{\"v\":2, \"test\":\"mest\"}`, `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t\t{\"GET\", \"\", `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t},\n\t\t}, {\n\t\t\tname: \"setupNoReturn\",\n\t\t\tscript: []byte(`\n\t\t\texport function setup() {\n\t\t\t\tlet a = {\"v\": 1};\n\t\t\t}\n\t\t\texport default function(data) {\n\t\t\t\tif (data === undefined || data !== \"\") {\n\t\t\t\t\tthrow new Error(\"incorrect data: \" + JSON.stringify(data));\n\t\t\t\t}\n\t\t\t};\n\n\t\t\texport function teardown(data) {\n\t\t\t\tif (data === undefined || data !== \"\") {\n\t\t\t\t\tthrow new Error(\"incorrect teardown data: \" + JSON.stringify(data));\n\t\t\t\t}\n\t\t\t} `),\n\t\t\tsetupRuns: [][3]string{\n\t\t\t\t{\"GET\", \"\", \"{}\"},\n\t\t\t\t{\"POST\", \"\", `{}`},\n\t\t\t\t{\"GET\", \"\", `{}`},\n\t\t\t\t{\"PUT\", `{\"v\":2, \"test\":\"mest\"}`, `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t\t{\"GET\", \"\", `{\"data\": {\"v\":2, \"test\":\"mest\"}}`},\n\t\t\t\t{\"PUT\", \"\\\"\\\"\", `{\"data\": \"\"}`},\n\t\t\t\t{\"GET\", \"\", `{\"data\": \"\"}`},\n\t\t\t},\n\t\t},\n\t}\n\n\trunTestCase := func(t *testing.T, tcid int) {\n\t\ttestCase := testCases[tcid]\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tpiState := getTestPreInitState(t)\n\t\t\tsourceData := &loader.SourceData{\n\t\t\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\t\t\tData: testCase.script,\n\t\t\t}\n\t\t\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\t\t\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestState := getTestRunState(t, lib.Options{\n\t\t\t\tPaused:          null.BoolFrom(true),\n\t\t\t\tVUs:             null.IntFrom(2),\n\t\t\t\tIterations:      null.IntFrom(3),\n\t\t\t\tNoSetup:         null.BoolFrom(true),\n\t\t\t\tSetupTimeout:    types.NullDurationFrom(5 * time.Second),\n\t\t\t\tTeardownTimeout: types.NullDurationFrom(5 * time.Second),\n\t\t\t}, runner)\n\n\t\t\texecScheduler, err := execution.NewScheduler(testState, local.NewController())\n\t\t\trequire.NoError(t, err)\n\t\t\tmetricsEngine, err := engine.NewMetricsEngine(testState.Registry, testState.Logger)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tglobalCtx := t.Context()\n\t\t\trunCtx, runAbort := execution.NewTestRunContext(globalCtx, testState.Logger)\n\t\t\tdefer runAbort(fmt.Errorf(\"unexpected abort\"))\n\n\t\t\toutputManager := output.NewManager([]output.Output{metricsEngine.CreateIngester()}, testState.Logger, runAbort)\n\t\t\tsamples := make(chan metrics.SampleContainer, 1000)\n\t\t\t_, stopOutputs, err := outputManager.Start(samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer stopOutputs(nil)\n\n\t\t\tcs := &ControlSurface{\n\t\t\t\tRunCtx:        runCtx,\n\t\t\t\tSamples:       samples,\n\t\t\t\tMetricsEngine: metricsEngine,\n\t\t\t\tScheduler:     execScheduler,\n\t\t\t\tRunState:      testState,\n\t\t\t}\n\n\t\t\terrC := make(chan error)\n\t\t\tgo func() { errC <- execScheduler.Run(globalCtx, runCtx, samples) }()\n\n\t\t\thandler := NewHandler(cs)\n\n\t\t\tcheckSetup := func(method, body, expResult string) {\n\t\t\t\trw := httptest.NewRecorder()\n\t\t\t\thandler.ServeHTTP(rw, httptest.NewRequest(method, \"/v1/setup\", bytes.NewBufferString(body)))\n\t\t\t\tres := rw.Result()\n\t\t\t\tt.Cleanup(func() {\n\t\t\t\t\tassert.NoError(t, res.Body.Close())\n\t\t\t\t})\n\t\t\t\tif !assert.Equal(t, http.StatusOK, res.StatusCode) {\n\t\t\t\t\tt.Logf(\"body: %s\\n\", rw.Body.String())\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tvar doc setUpJSONAPI\n\t\t\t\tassert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &doc))\n\t\t\t\tassert.Equal(t, \"setupData\", doc.Data.Type)\n\n\t\t\t\tencoded, err := json.Marshal(doc.Data.Attributes)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.JSONEq(t, expResult, string(encoded))\n\t\t\t}\n\n\t\t\tfor _, setupRun := range testCase.setupRuns {\n\t\t\t\tcheckSetup(setupRun[0], setupRun[1], setupRun[2])\n\t\t\t}\n\n\t\t\trequire.NoError(t, cs.Scheduler.SetPaused(false))\n\n\t\t\tselect {\n\t\t\tcase <-time.After(10 * time.Second):\n\t\t\t\tt.Fatal(\"Test timed out\")\n\t\t\tcase err := <-errC:\n\t\t\t\tclose(samples)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n\n\tfor id := range testCases {\n\t\tt.Run(fmt.Sprintf(\"testcase_%d\", id), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trunTestCase(t, id)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "api/v1/status.go",
    "content": "package v1\n\nimport (\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\n// Status represents the current status of the test run.\ntype Status struct {\n\tStatus lib.ExecutionStatus `json:\"status\" yaml:\"status\"`\n\n\tPaused  null.Bool `json:\"paused\" yaml:\"paused\"`\n\tVUs     null.Int  `json:\"vus\" yaml:\"vus\"`\n\tVUsMax  null.Int  `json:\"vus-max\" yaml:\"vus-max\"`\n\tStopped bool      `json:\"stopped\" yaml:\"stopped\"`\n\tRunning bool      `json:\"running\" yaml:\"running\"`\n\tTainted bool      `json:\"tainted\" yaml:\"tainted\"`\n}\n\nfunc newStatus(cs *ControlSurface) Status {\n\texecutionState := cs.Scheduler.GetState()\n\tisStopped := false\n\tselect {\n\tcase <-cs.RunCtx.Done():\n\t\tisStopped = true\n\tdefault:\n\t}\n\treturn Status{\n\t\tStatus:  executionState.GetCurrentExecutionStatus(),\n\t\tRunning: executionState.HasStarted() && !executionState.HasEnded(),\n\t\tPaused:  null.BoolFrom(executionState.IsPaused()),\n\t\tStopped: isStopped,\n\t\tVUs:     null.IntFrom(executionState.GetCurrentlyActiveVUsCount()),\n\t\tVUsMax:  null.IntFrom(executionState.GetInitializedVUsCount()),\n\t\tTainted: cs.MetricsEngine.GetMetricsWithBreachedThresholdsCount() > 0,\n\t}\n}\n"
  },
  {
    "path": "api/v1/status_jsonapi.go",
    "content": "package v1\n\n// StatusJSONAPI is JSON API envelop for metrics\ntype StatusJSONAPI struct {\n\tData statusData `json:\"data\"`\n}\n\n// NewStatusJSONAPI creates the JSON API status envelop\nfunc NewStatusJSONAPI(s Status) StatusJSONAPI {\n\treturn StatusJSONAPI{\n\t\tData: statusData{\n\t\t\tID:         \"default\",\n\t\t\tType:       \"status\",\n\t\t\tAttributes: s,\n\t\t},\n\t}\n}\n\n// Status extract the v1.Status from the JSON API envelop\nfunc (s StatusJSONAPI) Status() Status {\n\treturn s.Data.Attributes\n}\n\ntype statusData struct {\n\tType       string `json:\"type\"`\n\tID         string `json:\"id\"`\n\tAttributes Status `json:\"attributes\"`\n}\n\nfunc newStatusJSONAPIFromEngine(cs *ControlSurface) StatusJSONAPI {\n\treturn NewStatusJSONAPI(newStatus(cs))\n}\n"
  },
  {
    "path": "api/v1/status_routes.go",
    "content": "package v1\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/lib/executor\"\n)\n\nfunc handleGetStatus(cs *ControlSurface, rw http.ResponseWriter, _ *http.Request) {\n\tstatus := newStatusJSONAPIFromEngine(cs)\n\tdata, err := json.Marshal(status)\n\tif err != nil {\n\t\tapiError(rw, \"Encoding error\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\trw.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\t_, _ = rw.Write(data)\n}\n\nfunc getFirstExternallyControlledExecutor(execScheduler *execution.Scheduler) (*executor.ExternallyControlled, error) {\n\texecutors := execScheduler.GetExecutors()\n\tfor _, s := range executors {\n\t\tif mex, ok := s.(*executor.ExternallyControlled); ok {\n\t\t\treturn mex, nil\n\t\t}\n\t}\n\treturn nil, errors.New(\"an externally-controlled executor needs to be configured for live configuration updates\")\n}\n\nfunc handlePatchStatus(cs *ControlSurface, rw http.ResponseWriter, r *http.Request) {\n\trw.Header().Set(\"Content-Type\", \"application/json; charset=utf-8\")\n\n\tbody, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\tapiError(rw, \"Couldn't read request\", err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tvar statusEnvelop StatusJSONAPI\n\tif err = json.Unmarshal(body, &statusEnvelop); err != nil {\n\t\tapiError(rw, \"Invalid data\", err.Error(), http.StatusBadRequest)\n\t\treturn\n\t}\n\n\tstatus := statusEnvelop.Status()\n\n\tif status.Stopped { //nolint:nestif\n\t\texecution.AbortTestRun( //nolint:contextcheck // false-positive cs.RunCtx a right way of passing context there\n\t\t\tcs.RunCtx,\n\t\t\terrext.WithAbortReasonIfNone(\n\t\t\t\terrext.WithExitCodeIfNone(fmt.Errorf(\"test run stopped from REST API\"), exitcodes.ScriptStoppedFromRESTAPI),\n\t\t\t\terrext.AbortedByUser,\n\t\t\t),\n\t\t)\n\t} else {\n\t\tif status.Paused.Valid {\n\t\t\tif err = cs.Scheduler.SetPaused(status.Paused.Bool); err != nil {\n\t\t\t\tapiError(rw, \"Pause error\", err.Error(), http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif status.VUsMax.Valid || status.VUs.Valid {\n\t\t\t// TODO: add ability to specify the actual executor id? Though this should\n\t\t\t// likely be in the v2 REST API, where we could implement it in a way that\n\t\t\t// may allow us to eventually support other executor types.\n\t\t\texecutor, updateErr := getFirstExternallyControlledExecutor(cs.Scheduler)\n\t\t\tif updateErr != nil {\n\t\t\t\tapiError(rw, \"Execution config error\", updateErr.Error(), http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tnewConfig := executor.GetCurrentConfig().ExternallyControlledConfigParams\n\t\t\tif status.VUsMax.Valid {\n\t\t\t\tnewConfig.MaxVUs = status.VUsMax\n\t\t\t}\n\t\t\tif status.VUs.Valid {\n\t\t\t\tnewConfig.VUs = status.VUs\n\t\t\t}\n\t\t\tif updateErr := executor.UpdateConfig(r.Context(), newConfig); updateErr != nil {\n\t\t\t\tapiError(rw, \"Config update error\", updateErr.Error(), http.StatusBadRequest)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tdata, err := json.Marshal(newStatusJSONAPIFromEngine(cs))\n\tif err != nil {\n\t\tapiError(rw, \"Encoding error\", err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\t_, _ = rw.Write(data)\n}\n"
  },
  {
    "path": "api/v1/status_routes_test.go",
    "content": "package v1\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/internal/metrics/engine\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc TestGetStatus(t *testing.T) {\n\tt.Parallel()\n\n\ttestState := getTestRunState(t, lib.Options{}, &minirunner.MiniRunner{})\n\tcs := getControlSurface(t, testState)\n\n\trw := httptest.NewRecorder()\n\tNewHandler(cs).ServeHTTP(rw, httptest.NewRequest(http.MethodGet, \"/v1/status\", nil))\n\tres := rw.Result()\n\tt.Cleanup(func() {\n\t\tassert.NoError(t, res.Body.Close())\n\t})\n\tassert.Equal(t, http.StatusOK, res.StatusCode)\n\n\tt.Run(\"document\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar doc StatusJSONAPI\n\t\tassert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &doc))\n\t\tassert.Equal(t, \"status\", doc.Data.Type)\n\t})\n\n\tt.Run(\"status\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar statusEnvelop StatusJSONAPI\n\n\t\terr := json.Unmarshal(rw.Body.Bytes(), &statusEnvelop)\n\t\tassert.NoError(t, err)\n\n\t\tstatus := statusEnvelop.Status()\n\n\t\tassert.True(t, status.Paused.Valid)\n\t\tassert.True(t, status.VUs.Valid)\n\t\tassert.True(t, status.VUsMax.Valid)\n\t\tassert.False(t, status.Stopped)\n\t\tassert.False(t, status.Tainted)\n\t})\n}\n\nfunc TestPatchStatus(t *testing.T) {\n\tt.Parallel()\n\n\ttestData := map[string]struct {\n\t\tExpectedStatusCode int\n\t\tExpectedStatus     Status\n\t\tPayload            []byte\n\t}{\n\t\t\"nothing\": {\n\t\t\tExpectedStatusCode: 200,\n\t\t\tExpectedStatus:     Status{},\n\t\t\tPayload:            []byte(`{\"data\":{\"type\":\"status\",\"id\":\"default\",\"attributes\":{\"status\":0,\"paused\":null,\"vus\":null,\"vus-max\":null,\"stopped\":false,\"running\":false,\"tainted\":false}}}`),\n\t\t},\n\t\t\"paused\": {\n\t\t\tExpectedStatusCode: 200,\n\t\t\tExpectedStatus:     Status{Paused: null.BoolFrom(true)},\n\t\t\tPayload:            []byte(`{\"data\":{\"type\":\"status\",\"id\":\"default\",\"attributes\":{\"status\":0,\"paused\":true,\"vus\":null,\"vus-max\":null,\"stopped\":false,\"running\":false,\"tainted\":false}}}`),\n\t\t},\n\t\t\"max vus\": {\n\t\t\tExpectedStatusCode: 200,\n\t\t\tExpectedStatus:     Status{VUsMax: null.IntFrom(20)},\n\t\t\tPayload:            []byte(`{\"data\":{\"type\":\"status\",\"id\":\"default\",\"attributes\":{\"status\":0,\"paused\":null,\"vus\":null,\"vus-max\":20,\"stopped\":false,\"running\":false,\"tainted\":false}}}`),\n\t\t},\n\t\t\"max vus below initial\": {\n\t\t\tExpectedStatusCode: 400,\n\t\t\tExpectedStatus:     Status{VUsMax: null.IntFrom(5)},\n\t\t\tPayload:            []byte(`{\"data\":{\"type\":\"status\",\"id\":\"default\",\"attributes\":{\"status\":0,\"paused\":null,\"vus\":null,\"vus-max\":5,\"stopped\":false,\"running\":false,\"tainted\":false}}}`),\n\t\t},\n\t\t\"too many vus\": {\n\t\t\tExpectedStatusCode: 400,\n\t\t\tExpectedStatus:     Status{VUs: null.IntFrom(10), VUsMax: null.IntFrom(0)},\n\t\t\tPayload:            []byte(`{\"data\":{\"type\":\"status\",\"id\":\"default\",\"attributes\":{\"status\":0,\"paused\":null,\"vus\":10,\"vus-max\":0,\"stopped\":false,\"running\":false,\"tainted\":false}}}`),\n\t\t},\n\t\t\"vus\": {\n\t\t\tExpectedStatusCode: 200,\n\t\t\tExpectedStatus:     Status{VUs: null.IntFrom(10), VUsMax: null.IntFrom(10)},\n\t\t\tPayload:            []byte(`{\"data\":{\"type\":\"status\",\"id\":\"default\",\"attributes\":{\"status\":0,\"paused\":null,\"vus\":10,\"vus-max\":10,\"stopped\":false,\"running\":false,\"tainted\":false}}}`),\n\t\t},\n\t}\n\n\tfor name, testCase := range testData {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tscenarios := lib.ScenarioConfigs{}\n\t\t\terr := json.Unmarshal([]byte(`\n\t\t\t{\"external\": {\"executor\": \"externally-controlled\",\n\t\t\t\"vus\": 0, \"maxVUs\": 10, \"duration\": \"0\"}}`), &scenarios)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestState := getTestRunState(t, lib.Options{Scenarios: scenarios}, &minirunner.MiniRunner{})\n\t\t\texecScheduler, err := execution.NewScheduler(testState, local.NewController())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmetricsEngine, err := engine.NewMetricsEngine(testState.Registry, testState.Logger)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tglobalCtx := t.Context()\n\t\t\trunCtx, runAbort := execution.NewTestRunContext(globalCtx, testState.Logger)\n\t\t\tdefer runAbort(fmt.Errorf(\"unexpected abort\"))\n\n\t\t\toutputManager := output.NewManager([]output.Output{metricsEngine.CreateIngester()}, testState.Logger, runAbort)\n\t\t\tsamples := make(chan metrics.SampleContainer, 1000)\n\t\t\twaitMetricsFlushed, stopOutputs, err := outputManager.Start(samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer stopOutputs(nil)\n\n\t\t\tcs := &ControlSurface{\n\t\t\t\tRunCtx:        runCtx,\n\t\t\t\tSamples:       samples,\n\t\t\t\tMetricsEngine: metricsEngine,\n\t\t\t\tScheduler:     execScheduler,\n\t\t\t\tRunState:      testState,\n\t\t\t}\n\n\t\t\tstopEmission, err := execScheduler.Init(runCtx, samples)\n\t\t\trequire.NoError(t, err)\n\n\t\t\twg := &sync.WaitGroup{}\n\t\t\twg.Add(1)\n\t\t\tdefer func() {\n\t\t\t\trunAbort(fmt.Errorf(\"custom cancel signal\"))\n\t\t\t\twaitMetricsFlushed()\n\t\t\t\twg.Wait()\n\t\t\t}()\n\n\t\t\tgo func() {\n\t\t\t\tassert.ErrorContains(t, execScheduler.Run(globalCtx, runCtx, samples), \"custom cancel signal\")\n\t\t\t\tstopEmission()\n\t\t\t\tclose(samples)\n\t\t\t\twg.Done()\n\t\t\t}()\n\t\t\t// wait for the executor to initialize to avoid a potential data race below\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\n\t\t\trw := httptest.NewRecorder()\n\t\t\tNewHandler(cs).ServeHTTP(rw, httptest.NewRequest(http.MethodPatch, \"/v1/status\", bytes.NewReader(testCase.Payload)))\n\t\t\tres := rw.Result()\n\t\t\tt.Cleanup(func() {\n\t\t\t\tassert.NoError(t, res.Body.Close())\n\t\t\t})\n\n\t\t\trequire.Equal(t, \"application/json; charset=utf-8\", rw.Header().Get(\"Content-Type\"))\n\n\t\t\trequire.Equal(t, testCase.ExpectedStatusCode, res.StatusCode)\n\n\t\t\tif testCase.ExpectedStatusCode != 200 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tstatus := newStatus(cs)\n\t\t\tif testCase.ExpectedStatus.Paused.Valid {\n\t\t\t\tassert.Equal(t, testCase.ExpectedStatus.Paused, status.Paused)\n\t\t\t}\n\t\t\tif testCase.ExpectedStatus.VUs.Valid {\n\t\t\t\tassert.Equal(t, testCase.ExpectedStatus.VUs, status.VUs)\n\t\t\t}\n\t\t\tif testCase.ExpectedStatus.VUsMax.Valid {\n\t\t\t\tassert.Equal(t, testCase.ExpectedStatus.VUsMax, status.VUsMax)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "build-release.sh",
    "content": "#!/bin/bash\n\nset -eEuo pipefail\n\neval \"$(go env)\"\n\nset -x\nexport OUT_DIR=\"${1-dist}\"\n# To override the latest git tag as the version, pass something else as the second arg.\nexport VERSION=${2:-$(git describe --tags --always --dirty)}\n\nset +x\n\nbuild() {\n    local ALIAS=\"$1\" SUFFIX=\"${2}\"  # Any other arguments are passed to the go build command as env vars\n    local NAME=\"k6-${VERSION}-${ALIAS}\"\n\n    local BUILD_ARGS=(-o \"${OUT_DIR}/${NAME}/k6${SUFFIX}\" -trimpath)\n\n    local PACKAGE_FORMATS\n    IFS=\",\" read -ra PACKAGE_FORMATS <<< \"${3}\"\n\n    local ENV_VARS\n    IFS=\",\" read -ra ENV_VARS <<< \"${4}\"\n\n    echo \"- Building platform: ${ALIAS} (\" \"${ENV_VARS[@]}\" \"go build\" \"${BUILD_ARGS[@]}\" \")\"\n\n    mkdir -p \"${OUT_DIR}/${NAME}\"\n\n    # Subshell to not mess with the current env vars or CWD\n    (\n        export \"${ENV_VARS[@]}\"\n        # Build a binary\n        go build \"${BUILD_ARGS[@]}\"\n\n        for format in \"${PACKAGE_FORMATS[@]}\"; do\n            package \"$format\"\n        done\n    )\n}\n\npackage() {\n    local FMT=\"$1\"\n    echo \"- Creating ${NAME}.${FMT} package...\"\n    case $FMT in\n    deb|rpm)\n        # nfpm can't substitute env vars in file paths, so we have to cd...\n        cd \"${OUT_DIR}/${NAME}\"\n        set -x # Show exactly what command was executed\n        nfpm package --config ../../packaging/nfpm.yaml --packager \"${FMT}\" \\\n            --target \"../k6-${VERSION}-linux-${GOARCH}.${FMT}\"\n        set +x\n        cd -\n        ;;\n    tgz)\n        tar -C \"${OUT_DIR}\" -zcf \"${OUT_DIR}/${NAME}.tar.gz\" \"$NAME\"\n        ;;\n    zip)\n        (cd \"${OUT_DIR}\" && zip -rq9 - \"$NAME\") > \"${OUT_DIR}/${NAME}.zip\"\n        ;;\n    *)\n        echo \"Unknown format: $FMT\"\n        return 1\n        ;;\n    esac\n}\n\ncleanup() {\n    find \"$OUT_DIR\" -mindepth 1 -maxdepth 1 -type d -exec rm -rf {} \\;\n    echo \"--- Cleaned ${OUT_DIR}\"\n}\ntrap cleanup EXIT\n\necho \"--- Building Release: ${VERSION}\"\n\nmkdir -p \"$OUT_DIR\"\n\nbuild linux-amd64   \"\"      tgz,rpm,deb     GOOS=linux,GOARCH=amd64,CGO_ENABLED=0\nbuild linux-arm64   \"\"      tgz             GOOS=linux,GOARCH=arm64,CGO_ENABLED=0 # TODO: package rpm and dep too\nbuild macos-amd64   \"\"      zip             GOOS=darwin,GOARCH=amd64\nbuild macos-arm64   \"\"      zip             GOOS=darwin,GOARCH=arm64\nbuild windows-amd64 .exe    zip             GOOS=windows,GOARCH=amd64\n"
  },
  {
    "path": "catalog-info.yaml",
    "content": "apiVersion: backstage.io/v1alpha1\nkind: Component\nmetadata:\n  name: k6\n  title: k6\n  description: |\n    k6 is a modern load-testing tool\n  annotations:\n    backstage.io/techdocs-ref: dir:./docs\n    github.com/project-slug: grafana/k6\nspec:\n  type: tool\n  owner: group:default/k6-core\n  lifecycle: production\n"
  },
  {
    "path": "cloudapi/api.go",
    "content": "package cloudapi\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/lib\"\n)\n\n// ResultStatus represents the result status of a test.\ntype ResultStatus int\n\nconst (\n\t// ResultStatusPassed means the test has passed\n\tResultStatusPassed ResultStatus = 0\n\t// ResultStatusFailed means the test has failed\n\tResultStatusFailed ResultStatus = 1\n)\n\n// ThresholdResult is a helper type to make sending the thresholds result to the cloud.\ntype ThresholdResult map[string]map[string]bool\n\n// TestRun represents a test run.\ntype TestRun struct {\n\tName       string              `json:\"name\"`\n\tProjectID  int64               `json:\"project_id,omitempty\"`\n\tVUsMax     int64               `json:\"vus\"`\n\tThresholds map[string][]string `json:\"thresholds\"`\n\t// Duration of test in seconds. -1 for unknown length, 0 for continuous running.\n\tDuration int64 `json:\"duration\"`\n\t// Archive is the test script archive to (maybe) upload to the cloud.\n\tArchive *lib.Archive `json:\"-\"`\n}\n\n// LogEntry can be used by the cloud to tell k6 to log something to the console,\n// so the user can see it.\ntype LogEntry struct {\n\tLevel   string `json:\"level\"`\n\tMessage string `json:\"message\"`\n}\n\n// CreateTestRunResponse represents the response of successfully created test run in the cloud.\ntype CreateTestRunResponse struct {\n\tReferenceID    string     `json:\"reference_id\"`\n\tConfigOverride *Config    `json:\"config\"`\n\tLogs           []LogEntry `json:\"logs\"`\n}\n\n// TestProgressResponse represents the progress of a cloud test.\ntype TestProgressResponse struct {\n\tRunStatusText string       `json:\"run_status_text\"`\n\tRunStatus     RunStatus    `json:\"run_status\"`\n\tResultStatus  ResultStatus `json:\"result_status\"`\n\tProgress      float64      `json:\"progress\"`\n}\n\n// LoginResponse includes the token after a successful login.\ntype LoginResponse struct {\n\tToken string `json:\"token\"`\n}\n\n// ValidateTokenResponse is the response of a token validation.\ntype ValidateTokenResponse struct {\n\tIsValid bool   `json:\"is_valid\"`\n\tMessage string `json:\"message\"`\n\tToken   string `json:\"token-info\"`\n}\n\nfunc (c *Client) handleLogEntriesFromCloud(ctrr CreateTestRunResponse) {\n\tlogger := c.logger.WithField(\"source\", \"grafana-k6-cloud\")\n\tfor _, logEntry := range ctrr.Logs {\n\t\tlevel, err := logrus.ParseLevel(logEntry.Level)\n\t\tif err != nil {\n\t\t\tlogger.Debugf(\"invalid message level '%s' for message '%s': %s\", logEntry.Level, logEntry.Message, err)\n\t\t\tlevel = logrus.ErrorLevel\n\t\t}\n\t\tlogger.Log(level, logEntry.Message)\n\t}\n}\n\n// CreateTestRun is used when a test run is being executed locally, while the\n// results are streamed to the cloud, i.e. `k6 cloud run --local-execution` or `k6 run --out cloud script.js`.\nfunc (c *Client) CreateTestRun(testRun *TestRun) (*CreateTestRunResponse, error) {\n\turl := fmt.Sprintf(\"%s/tests\", c.baseURL)\n\n\t// Because the kind of request we make can vary depending on the test run configuration, we delegate\n\t// its creation to a helper.\n\trequest, err := c.makeCreateTestRunRequest(url, testRun)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresponse := CreateTestRunResponse{}\n\terr = c.Do(request, &response)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc.handleLogEntriesFromCloud(response)\n\tif response.ReferenceID == \"\" {\n\t\treturn nil, fmt.Errorf(\"failed to get a reference ID\")\n\t}\n\n\treturn &response, nil\n}\n\n// makeCreateTestRunRequest creates a new HTTP request for creating a test run.\n//\n// If the test run archive isn't set, the request will be a regular JSON request with the test run information.\n// Otherwise, the request will be a multipart form request containing the test run information and the archive file.\nfunc (c *Client) makeCreateTestRunRequest(url string, testRun *TestRun) (*http.Request, error) {\n\t// If the test run archive isn't set, we are not uploading an archive and can use the regular request JSON format.\n\tif testRun.Archive == nil {\n\t\treturn c.NewRequest(http.MethodPost, url, testRun)\n\t}\n\n\t// Otherwise, we need to create a multipart form request containing the test run information as\n\t// well as the archive file.\n\tfields := [][2]string{\n\t\t{\"name\", testRun.Name},\n\t\t{\"project_id\", strconv.FormatInt(testRun.ProjectID, 10)},\n\t\t{\"vus\", strconv.FormatInt(testRun.VUsMax, 10)},\n\t\t{\"duration\", strconv.FormatInt(testRun.Duration, 10)},\n\t}\n\n\tvar buffer bytes.Buffer\n\tmultipartWriter := multipart.NewWriter(&buffer)\n\n\tfor _, field := range fields {\n\t\tif err := multipartWriter.WriteField(field[0], field[1]); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tfw, err := multipartWriter.CreateFormFile(\"file\", \"archive.tar\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = testRun.Archive.Write(fw); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Close the multipart writer to finalize the form data\n\terr = multipartWriter.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Create a new POST request with the multipart form data\n\treq, err := http.NewRequest(http.MethodPost, url, &buffer) //nolint:noctx\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Set the content type to the one generated by the multipart writer\n\treq.Header.Set(\"Content-Type\", multipartWriter.FormDataContentType())\n\n\treturn req, nil\n}\n\n// StartCloudTestRun starts a cloud test run, i.e. `k6 cloud script.js`.\nfunc (c *Client) StartCloudTestRun(name string, projectID int64, arc *lib.Archive) (*CreateTestRunResponse, error) {\n\tfields := [][2]string{{\"name\", name}}\n\n\tif projectID != 0 {\n\t\tfields = append(fields, [2]string{\"project_id\", strconv.FormatInt(projectID, 10)})\n\t}\n\n\treturn c.uploadArchive(fields, arc)\n}\n\n// UploadTestOnly uploads a test run to the cloud without actually starting it.\nfunc (c *Client) UploadTestOnly(name string, projectID int64, arc *lib.Archive) (*CreateTestRunResponse, error) {\n\tfields := [][2]string{{\"name\", name}, {\"upload_only\", \"true\"}}\n\n\tif projectID != 0 {\n\t\tfields = append(fields, [2]string{\"project_id\", strconv.FormatInt(projectID, 10)})\n\t}\n\n\treturn c.uploadArchive(fields, arc)\n}\n\nfunc (c *Client) uploadArchive(fields [][2]string, arc *lib.Archive) (*CreateTestRunResponse, error) {\n\trequestURL := fmt.Sprintf(\"%s/archive-upload\", c.baseURL)\n\n\tvar buf bytes.Buffer\n\tmp := multipart.NewWriter(&buf)\n\n\tfor _, field := range fields {\n\t\tif err := mp.WriteField(field[0], field[1]); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tfw, err := mp.CreateFormFile(\"file\", \"archive.tar\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = arc.Write(fw); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = mp.Close(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treq, err := http.NewRequest(http.MethodPost, requestURL, &buf) //nolint:noctx\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq.Header.Set(\"Content-Type\", mp.FormDataContentType())\n\n\tctrr := CreateTestRunResponse{}\n\tif err := c.Do(req, &ctrr); err != nil {\n\t\treturn nil, err\n\t}\n\tc.handleLogEntriesFromCloud(ctrr)\n\treturn &ctrr, nil\n}\n\n// TestFinished sends the result and run status values to the cloud, along with\n// information for the test thresholds, and marks the test run as finished.\nfunc (c *Client) TestFinished(referenceID string, thresholds ThresholdResult, tained bool, runStatus RunStatus) error {\n\turl := fmt.Sprintf(\"%s/tests/%s\", c.baseURL, referenceID)\n\n\tresultStatus := ResultStatusPassed\n\tif tained {\n\t\tresultStatus = ResultStatusFailed\n\t}\n\n\tdata := struct {\n\t\tResultStatus ResultStatus    `json:\"result_status\"`\n\t\tRunStatus    RunStatus       `json:\"run_status\"`\n\t\tThresholds   ThresholdResult `json:\"thresholds\"`\n\t}{\n\t\tresultStatus,\n\t\trunStatus,\n\t\tthresholds,\n\t}\n\n\treq, err := c.NewRequest(\"POST\", url, data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn c.Do(req, nil)\n}\n\n// GetTestProgress for the provided referenceID.\nfunc (c *Client) GetTestProgress(referenceID string) (*TestProgressResponse, error) {\n\treq, err := c.NewRequest(http.MethodGet, c.baseURL+\"/test-progress/\"+referenceID, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tctrr := TestProgressResponse{}\n\terr = c.Do(req, &ctrr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &ctrr, nil\n}\n\n// StopCloudTestRun tells the cloud to stop the test with the provided referenceID.\nfunc (c *Client) StopCloudTestRun(referenceID string) error {\n\treq, err := c.NewRequest(\"POST\", c.baseURL+\"/tests/\"+referenceID+\"/stop\", nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn c.Do(req, nil)\n}\n\ntype validateOptionsRequest struct {\n\tOptions lib.Options `json:\"options\"`\n}\n\n// ValidateOptions sends the provided options to the cloud for validation.\nfunc (c *Client) ValidateOptions(options lib.Options) error {\n\tdata := validateOptionsRequest{Options: options}\n\treq, err := c.NewRequest(\"POST\", c.baseURL+\"/validate-options\", data)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn c.Do(req, nil)\n}\n\ntype loginRequest struct {\n\tEmail    string `json:\"email\"`\n\tPassword string `json:\"password\"` //nolint:gosec\n}\n\n// Login the user with the specified email and password.\nfunc (c *Client) Login(email string, password string) (*LoginResponse, error) {\n\tdata := loginRequest{Email: email, Password: password}\n\treq, err := c.NewRequest(\"POST\", c.baseURL+\"/login\", data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlr := LoginResponse{}\n\terr = c.Do(req, &lr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &lr, nil\n}\n\ntype validateTokenRequest struct {\n\tToken string `json:\"token\"`\n}\n\n// ValidateToken calls the endpoint to validate the Client's token and returns the result.\nfunc (c *Client) ValidateToken() (*ValidateTokenResponse, error) {\n\tdata := validateTokenRequest{Token: c.token}\n\treq, err := c.NewRequest(\"POST\", c.baseURL+\"/validate-token\", data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvtr := ValidateTokenResponse{}\n\terr = c.Do(req, &vtr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &vtr, nil\n}\n"
  },
  {
    "path": "cloudapi/api_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n\n\t\"go.k6.io/k6/lib\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestNewClient(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttimeout := 5 * time.Second\n\t\tc := NewClient(testutils.NewLogger(t), \"token\", \"server-url\", \"1.0\", 5*time.Second)\n\t\tassert.Equal(t, timeout, c.client.Timeout)\n\t})\n}\n\nfunc TestCreateTestRun(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"creating a test run should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tb, err := io.ReadAll(r.Body)\n\t\t\trequire.NoError(t, err)\n\n\t\t\texp := `{\"name\":\"test\",\"vus\":0,\"thresholds\":null,\"duration\":0}`\n\t\t\tassert.JSONEq(t, exp, string(b))\n\n\t\t\tfprint(t, w, `{\"reference_id\": \"1\", \"config\": {\"aggregationPeriod\": \"2s\"}}`)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\n\t\tresp, err := client.CreateTestRun(&TestRun{\n\t\t\tName: \"test\",\n\t\t})\n\t\tassert.NoError(t, err)\n\n\t\tassert.Equal(t, \"1\", resp.ReferenceID)\n\t\tassert.NotNil(t, resp.ConfigOverride)\n\t\tassert.True(t, resp.ConfigOverride.AggregationPeriod.Valid)\n\t\tassert.Equal(t, types.Duration(2*time.Second), resp.ConfigOverride.AggregationPeriod.Duration)\n\t\tassert.False(t, resp.ConfigOverride.MaxTimeSeriesInBatch.Valid)\n\t})\n\n\tt.Run(\"creating a test run with an archive should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t// Parse the multipart form data\n\t\t\treader, err := r.MultipartReader()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Initialize a map to store the parsed form data\n\t\t\tformData := make(map[string]string)\n\n\t\t\t// Iterate through the parts\n\t\t\tfor {\n\t\t\t\tpart, nextErr := reader.NextPart()\n\t\t\t\tif errors.Is(nextErr, io.EOF) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\trequire.NoError(t, nextErr)\n\n\t\t\t\t// Read the part content\n\t\t\t\tbuf := new(bytes.Buffer)\n\t\t\t\t_, err = io.Copy(buf, part)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// Store the part content in the map\n\t\t\t\tformData[part.FormName()] = buf.String()\n\t\t\t}\n\n\t\t\tassert.Equal(t, \"test\", formData[\"name\"])\n\t\t\tassert.Equal(t, \"0\", formData[\"vus\"])\n\t\t\tassert.Equal(t, \"\", formData[\"thresholds\"])\n\t\t\tassert.Equal(t, \"0\", formData[\"duration\"])\n\n\t\t\tfprint(t, w, `{\"reference_id\": \"1\", \"config\": {\"aggregationPeriod\": \"2s\"}}`)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\n\t\t// Produce a test archive\n\t\tfs := fsext.NewMemMapFs()\n\t\terr := fsext.WriteFile(fs, \"/path/to/a.js\", []byte(`// a contents`), 0o644)\n\t\trequire.NoError(t, err)\n\n\t\tarc := &lib.Archive{\n\t\t\tType:        \"js\",\n\t\t\tK6Version:   build.Version,\n\t\t\tOptions:     lib.Options{},\n\t\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/path/to/a.js\"},\n\t\t\tData:        []byte(`// a contents`),\n\t\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/path/to\"},\n\t\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\t\"file\": fs,\n\t\t\t},\n\t\t}\n\n\t\tresp, err := client.CreateTestRun(&TestRun{\n\t\t\tName:    \"test\",\n\t\t\tArchive: arc,\n\t\t})\n\t\tassert.NoError(t, err)\n\n\t\tassert.Equal(t, \"1\", resp.ReferenceID)\n\t\tassert.NotNil(t, resp.ConfigOverride)\n\t\tassert.True(t, resp.ConfigOverride.AggregationPeriod.Valid)\n\t\tassert.Equal(t, types.Duration(2*time.Second), resp.ConfigOverride.AggregationPeriod.Duration)\n\t\tassert.False(t, resp.ConfigOverride.MaxTimeSeriesInBatch.Valid)\n\t})\n\n\tt.Run(\"invalid authorization should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcalled := 0\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tcalled++\n\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\tfprint(t, w, `{\"error\": {\"code\": 5, \"message\": \"Not allowed\"}}`)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\n\t\tresp, err := client.CreateTestRun(&TestRun{Name: \"test\"})\n\n\t\tassert.Equal(t, 1, called)\n\t\tassert.Nil(t, resp)\n\t\tassert.EqualError(t, err, \"(403/E5) Not allowed\")\n\t})\n\n\tt.Run(\"invalid payload should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcalled := 0\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tcalled++\n\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\tfprint(t, w, `{\"error\": {\"code\": 0, \"message\": \"Validation failed\", \"details\": { \"name\": [\"Shorter than minimum length 2.\"]}}}`)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\n\t\tresp, err := client.CreateTestRun(&TestRun{Name: \"test\"})\n\n\t\tassert.Equal(t, 1, called)\n\t\tassert.Nil(t, resp)\n\t\tassert.EqualError(t, err, \"(403) Validation failed\\n name: Shorter than minimum length 2.\")\n\t})\n\n\t// FIXME (@oleiade): improve test name\n\tt.Run(\"retry should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcalled := 0\n\t\tidempotencyKey := \"\"\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tgotK6IdempotencyKey := r.Header.Get(k6IdempotencyKeyHeader)\n\t\t\tif idempotencyKey == \"\" {\n\t\t\t\tidempotencyKey = gotK6IdempotencyKey\n\t\t\t}\n\t\t\tassert.NotEmpty(t, gotK6IdempotencyKey)\n\t\t\tassert.Equal(t, idempotencyKey, gotK6IdempotencyKey)\n\t\t\tcalled++\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\t\tclient.retryInterval = 1 * time.Millisecond\n\t\tresp, err := client.CreateTestRun(&TestRun{Name: \"test\"})\n\n\t\tassert.Equal(t, 3, called)\n\t\tassert.Nil(t, resp)\n\t\tassert.NotNil(t, err)\n\t})\n\n\t// FIXME (@oleiade): improve test name\n\tt.Run(\"second retry should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcalled := 1\n\t\tidempotencyKey := \"\"\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tgotK6IdempotencyKey := r.Header.Get(k6IdempotencyKeyHeader)\n\t\t\tif idempotencyKey == \"\" {\n\t\t\t\tidempotencyKey = gotK6IdempotencyKey\n\t\t\t}\n\t\t\tassert.NotEmpty(t, gotK6IdempotencyKey)\n\t\t\tassert.Equal(t, idempotencyKey, gotK6IdempotencyKey)\n\t\t\tcalled++\n\t\t\tif called == 2 {\n\t\t\t\tfprint(t, w, `{\"reference_id\": \"1\"}`)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\t\tclient.retryInterval = 1 * time.Millisecond\n\t\tresp, err := client.CreateTestRun(&TestRun{Name: \"test\"})\n\n\t\tassert.Equal(t, 2, called)\n\t\tassert.NotNil(t, resp)\n\t\tassert.Nil(t, err)\n\t})\n\n\tt.Run(\"invalid project ID and stack ID should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcalled := 0\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\tb, err := io.ReadAll(r.Body)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar testRun TestRun\n\t\t\trequire.NoError(t, json.Unmarshal(b, &testRun))\n\n\t\t\tvar stackID int64\n\t\t\tif r.Header.Get(\"X-Stack-Id\") != \"\" {\n\t\t\t\tstackID, err = strconv.ParseInt(r.Header.Get(\"X-Stack-Id\"), 10, 64)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\tcalled++\n\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\terrorMsg := fmt.Sprintf(\"Project matching ID %d not found in stack %d.\", testRun.ProjectID, stackID)\n\t\t\tfprint(t, w, fmt.Sprintf(`{\"error\": {\"code\": 2, \"message\": \"Validation failed\", \"errors\": [\"%s\"]}}`, errorMsg))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\t\tclient.SetStackID(1)\n\n\t\tresp, err := client.CreateTestRun(&TestRun{\n\t\t\tName:      \"test\",\n\t\t\tProjectID: 2,\n\t\t})\n\n\t\tassert.Equal(t, 1, called)\n\t\tassert.Nil(t, resp)\n\t\tassert.EqualError(t, err, \"(403/E2) Validation failed\\n Project matching ID 2 not found in stack 1.\")\n\t})\n\n\tt.Run(\"invalid project ID and stack ID with archive should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcalled := 0\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t// Parse the multipart form data\n\t\t\treader, err := r.MultipartReader()\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Initialize a map to store the parsed form data\n\t\t\tformData := make(map[string]string)\n\n\t\t\t// Iterate through the parts\n\t\t\tfor {\n\t\t\t\tpart, nextErr := reader.NextPart()\n\t\t\t\tif errors.Is(nextErr, io.EOF) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\trequire.NoError(t, nextErr)\n\n\t\t\t\t// Read the part content\n\t\t\t\tbuf := new(bytes.Buffer)\n\t\t\t\t_, err = io.Copy(buf, part)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// Store the part content in the map\n\t\t\t\tformData[part.FormName()] = buf.String()\n\t\t\t}\n\n\t\t\t// Extract metadata.json from the tar archive\n\t\t\tarchiveData := formData[\"file\"]\n\t\t\ttarReader := tar.NewReader(bytes.NewReader([]byte(archiveData)))\n\n\t\t\tvar metadata struct {\n\t\t\t\tOptions struct {\n\t\t\t\t\tCloud struct {\n\t\t\t\t\t\tProjectID int64 `json:\"project_id\"`\n\t\t\t\t\t\tStackID   int64 `json:\"stack_id\"`\n\t\t\t\t\t} `json:\"cloud\"`\n\t\t\t\t} `json:\"options\"`\n\t\t\t}\n\n\t\t\t// Find and read metadata.json from the tar archive\n\t\t\tfor {\n\t\t\t\theader, tarErr := tarReader.Next()\n\t\t\t\tif errors.Is(tarErr, io.EOF) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\trequire.NoError(t, tarErr)\n\n\t\t\t\tif header.Name == \"metadata.json\" {\n\t\t\t\t\tmetadataBytes, readErr := io.ReadAll(tarReader)\n\t\t\t\t\trequire.NoError(t, readErr)\n\t\t\t\t\terr = json.Unmarshal(metadataBytes, &metadata)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcalled++\n\t\t\tw.WriteHeader(http.StatusForbidden)\n\t\t\terrorMsg := fmt.Sprintf(\"Project matching ID %d not found in stack %d.\", metadata.Options.Cloud.ProjectID, metadata.Options.Cloud.StackID)\n\t\t\tfprint(t, w, fmt.Sprintf(`{\"error\": {\"code\": 2, \"message\": \"Validation failed\", \"errors\": [\"%s\"]}}`, errorMsg))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\n\t\t// Produce a test archive\n\t\tfs := fsext.NewMemMapFs()\n\t\terr := fsext.WriteFile(fs, \"/path/to/a.js\", []byte(`// a contents`), 0o644)\n\t\trequire.NoError(t, err)\n\n\t\tarc := &lib.Archive{\n\t\t\tType:      \"js\",\n\t\t\tK6Version: build.Version,\n\t\t\tOptions: lib.Options{\n\t\t\t\tCloud: json.RawMessage(`{\"project_id\":2,\"stack_id\":1}`),\n\t\t\t},\n\t\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/path/to/a.js\"},\n\t\t\tData:        []byte(`// a contents`),\n\t\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/path/to\"},\n\t\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\t\"file\": fs,\n\t\t\t},\n\t\t}\n\n\t\tresp, err := client.CreateTestRun(&TestRun{\n\t\t\tName:    \"test\",\n\t\t\tArchive: arc,\n\t\t})\n\n\t\tassert.Equal(t, 1, called)\n\t\tassert.Nil(t, resp)\n\t\tassert.EqualError(t, err, \"(403/E2) Validation failed\\n Project matching ID 2 not found in stack 1.\")\n\t})\n}\n\nfunc TestFinished(t *testing.T) {\n\tt.Parallel()\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tfprint(t, w, \"\")\n\t}))\n\tdefer server.Close()\n\n\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\n\tthresholds := map[string]map[string]bool{\n\t\t\"threshold\": {\n\t\t\t\"max < 10\": true,\n\t\t},\n\t}\n\terr := client.TestFinished(\"1\", thresholds, true, 0)\n\n\tassert.Nil(t, err)\n}\n\nfunc TestIdempotencyKey(t *testing.T) {\n\tt.Parallel()\n\tconst idempotencyKey = \"xxx\"\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tgotK6IdempotencyKey := r.Header.Get(k6IdempotencyKeyHeader)\n\t\tswitch r.Method {\n\t\tcase http.MethodPost:\n\t\t\tassert.NotEmpty(t, gotK6IdempotencyKey)\n\t\t\tassert.Equal(t, idempotencyKey, gotK6IdempotencyKey)\n\t\tdefault:\n\t\t\tassert.Empty(t, gotK6IdempotencyKey)\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\tdefer server.Close()\n\n\tclient := NewClient(testutils.NewLogger(t), \"token\", server.URL, \"1.0\", 1*time.Second)\n\tclient.retryInterval = 1 * time.Millisecond\n\treq, err := client.NewRequest(http.MethodPost, server.URL, nil)\n\tassert.NoError(t, err)\n\treq.Header.Set(k6IdempotencyKeyHeader, idempotencyKey)\n\tassert.NoError(t, client.Do(req, nil))\n\n\treq, err = client.NewRequest(http.MethodGet, server.URL, nil)\n\tassert.NoError(t, err)\n\tassert.NoError(t, client.Do(req, nil))\n}\n\nfunc fprint(t *testing.T, w io.Writer, format string) int {\n\tn, err := fmt.Fprint(w, format)\n\trequire.NoError(t, err)\n\treturn n\n}\n"
  },
  {
    "path": "cloudapi/client.go",
    "content": "package cloudapi\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\nconst (\n\t// RetryInterval is the default cloud request retry interval\n\tRetryInterval = 500 * time.Millisecond\n\t// MaxRetries specifies max retry attempts\n\tMaxRetries = 3\n\n\tk6IdempotencyKeyHeader = \"K6-Idempotency-Key\"\n)\n\n// Client handles communication with the k6 Cloud API.\ntype Client struct {\n\tclient  *http.Client\n\ttoken   string\n\tstackID int64\n\tbaseURL string\n\tversion string\n\n\tlogger logrus.FieldLogger\n\n\tretries       int\n\tretryInterval time.Duration\n}\n\n// NewClient return a new client for the cloud API\nfunc NewClient(logger logrus.FieldLogger, token, host, version string, timeout time.Duration) *Client {\n\tc := &Client{\n\t\tclient:        &http.Client{Timeout: timeout},\n\t\ttoken:         token,\n\t\tbaseURL:       fmt.Sprintf(\"%s/v1\", host),\n\t\tversion:       version,\n\t\tretries:       MaxRetries,\n\t\tretryInterval: RetryInterval,\n\t\tlogger:        logger,\n\t}\n\treturn c\n}\n\n// SetStackID sets the stack ID for the client.\nfunc (c *Client) SetStackID(stackID int64) {\n\tc.stackID = stackID\n}\n\n// BaseURL returns configured host.\nfunc (c *Client) BaseURL() string {\n\treturn c.baseURL\n}\n\n// NewRequest creates new HTTP request.\n//\n// This is the same as http.NewRequest, except that data if not nil\n// will be serialized in json format.\nfunc (c *Client) NewRequest(method, url string, data any) (*http.Request, error) {\n\tvar buf io.Reader\n\n\tif data != nil {\n\t\tb, err := json.Marshal(&data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tbuf = bytes.NewBuffer(b)\n\t}\n\n\treq, err := http.NewRequest(method, url, buf) //nolint:noctx // the user can add this\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn req, nil\n}\n\n// Do is simpler to http.Do but also unmarshals the response in the provided v\nfunc (c *Client) Do(req *http.Request, v any) error {\n\tif req.Body != nil && req.GetBody == nil {\n\t\toriginalBody, err := io.ReadAll(req.Body)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err = req.Body.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treq.GetBody = func() (io.ReadCloser, error) {\n\t\t\treturn io.NopCloser(bytes.NewReader(originalBody)), nil\n\t\t}\n\t\treq.Body, _ = req.GetBody()\n\t}\n\n\t// TODO(cuonglm): finding away to move this back to NewRequest\n\tc.prepareHeaders(req)\n\n\tfor i := 1; i <= c.retries; i++ {\n\t\tretry, err := c.do(req, v, i)\n\n\t\tif retry {\n\t\t\ttime.Sleep(c.retryInterval)\n\t\t\tif req.GetBody != nil {\n\t\t\t\treq.Body, _ = req.GetBody()\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) prepareHeaders(req *http.Request) {\n\tif req.Header.Get(\"Content-Type\") == \"\" {\n\t\treq.Header.Set(\"Content-Type\", \"application/json\")\n\t}\n\n\tif c.token != \"\" {\n\t\treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Token %s\", c.token))\n\t}\n\n\tif shouldAddIdempotencyKey(req) {\n\t\treq.Header.Set(k6IdempotencyKeyHeader, randomStrHex())\n\t}\n\n\treq.Header.Set(\"User-Agent\", \"k6cloud/\"+c.version)\n\n\tif c.stackID != 0 {\n\t\treq.Header.Set(\"X-Stack-Id\", strconv.FormatInt(c.stackID, 10))\n\t}\n}\n\nfunc (c *Client) do(req *http.Request, v any, attempt int) (retry bool, err error) {\n\tresp, err := c.client.Do(req) //nolint:gosec\n\n\tdefer func() {\n\t\tif resp != nil {\n\t\t\t_, _ = io.Copy(io.Discard, resp.Body)\n\t\t\tif cerr := resp.Body.Close(); cerr != nil && err == nil {\n\t\t\t\terr = cerr\n\t\t\t}\n\t\t}\n\t}()\n\n\tif shouldRetry(resp, err, attempt, c.retries) {\n\t\treturn true, err\n\t}\n\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif err = CheckResponse(resp); err != nil {\n\t\treturn false, err\n\t}\n\n\tif v != nil {\n\t\tif err = json.NewDecoder(resp.Body).Decode(v); errors.Is(err, io.EOF) {\n\t\t\terr = nil // Ignore EOF from empty body\n\t\t}\n\t}\n\n\treturn false, err\n}\n\n// CheckResponse checks the parsed response.\n// It returns nil if the code is in the successful range,\n// otherwise it tries to parse the body and return a parsed error.\nfunc CheckResponse(r *http.Response) error {\n\tif r == nil {\n\t\treturn errUnknown\n\t}\n\n\tif c := r.StatusCode; c >= 200 && c <= 299 {\n\t\treturn nil\n\t}\n\n\tdata, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar payload struct {\n\t\tError ResponseError `json:\"error\"`\n\t}\n\tif err := json.Unmarshal(data, &payload); err != nil {\n\t\tif r.StatusCode == http.StatusUnauthorized {\n\t\t\treturn errNotAuthenticated\n\t\t}\n\t\tif r.StatusCode == http.StatusForbidden {\n\t\t\treturn errNotAuthorized\n\t\t}\n\t\treturn fmt.Errorf(\n\t\t\t\"unexpected HTTP error from %s: %d %s\",\n\t\t\tr.Request.URL,\n\t\t\tr.StatusCode,\n\t\t\thttp.StatusText(r.StatusCode),\n\t\t)\n\t}\n\tpayload.Error.Response = r\n\treturn payload.Error\n}\n\nfunc shouldRetry(resp *http.Response, err error, attempt, maxAttempts int) bool {\n\tif attempt >= maxAttempts {\n\t\treturn false\n\t}\n\n\tif resp == nil || err != nil {\n\t\treturn true\n\t}\n\n\tif resp.StatusCode >= 500 || resp.StatusCode == http.StatusTooManyRequests {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc shouldAddIdempotencyKey(req *http.Request) bool {\n\tswitch req.Method {\n\tcase http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodTrace:\n\t\treturn false\n\tdefault:\n\t\treturn req.Header.Get(k6IdempotencyKeyHeader) == \"\"\n\t}\n}\n\n// randomStrHex returns a hex string which can be used\n// for session token id or idempotency key.\nfunc randomStrHex() string {\n\t// 16 hex characters\n\tb := make([]byte, 8)\n\t_, _ = rand.Read(b)\n\treturn hex.EncodeToString(b)\n}\n"
  },
  {
    "path": "cloudapi/cloudapi_easyjson.go",
    "content": "// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.\n\npackage cloudapi\n\nimport (\n\tjson \"encoding/json\"\n\teasyjson \"github.com/mailru/easyjson\"\n\tjlexer \"github.com/mailru/easyjson/jlexer\"\n\tjwriter \"github.com/mailru/easyjson/jwriter\"\n)\n\n// suppress unused package warning\nvar (\n\t_ *json.RawMessage\n\t_ *jlexer.Lexer\n\t_ *jwriter.Writer\n\t_ easyjson.Marshaler\n)\n\nfunc easyjsonC9ac27e5DecodeGoK6IoK6Cloudapi(in *jlexer.Lexer, out *msgStreams) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"stream\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t} else {\n\t\t\t\tin.Delim('{')\n\t\t\t\tout.Stream = make(map[string]string)\n\t\t\t\tfor !in.IsDelim('}') {\n\t\t\t\t\tkey := string(in.String())\n\t\t\t\t\tin.WantColon()\n\t\t\t\t\tvar v1 string\n\t\t\t\t\tv1 = string(in.String())\n\t\t\t\t\t(out.Stream)[key] = v1\n\t\t\t\t\tin.WantComma()\n\t\t\t\t}\n\t\t\t\tin.Delim('}')\n\t\t\t}\n\t\tcase \"values\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t\tout.Values = nil\n\t\t\t} else {\n\t\t\t\tin.Delim('[')\n\t\t\t\tif out.Values == nil {\n\t\t\t\t\tif !in.IsDelim(']') {\n\t\t\t\t\t\tout.Values = make([][2]string, 0, 2)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tout.Values = [][2]string{}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tout.Values = (out.Values)[:0]\n\t\t\t\t}\n\t\t\t\tfor !in.IsDelim(']') {\n\t\t\t\t\tvar v2 [2]string\n\t\t\t\t\tif in.IsNull() {\n\t\t\t\t\t\tin.Skip()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tin.Delim('[')\n\t\t\t\t\t\tv3 := 0\n\t\t\t\t\t\tfor !in.IsDelim(']') {\n\t\t\t\t\t\t\tif v3 < 2 {\n\t\t\t\t\t\t\t\t(v2)[v3] = string(in.String())\n\t\t\t\t\t\t\t\tv3++\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tin.SkipRecursive()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tin.WantComma()\n\t\t\t\t\t\t}\n\t\t\t\t\t\tin.Delim(']')\n\t\t\t\t\t}\n\t\t\t\t\tout.Values = append(out.Values, v2)\n\t\t\t\t\tin.WantComma()\n\t\t\t\t}\n\t\t\t\tin.Delim(']')\n\t\t\t}\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjsonC9ac27e5EncodeGoK6IoK6Cloudapi(out *jwriter.Writer, in msgStreams) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"stream\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tif in.Stream == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 {\n\t\t\tout.RawString(`null`)\n\t\t} else {\n\t\t\tout.RawByte('{')\n\t\t\tv4First := true\n\t\t\tfor v4Name, v4Value := range in.Stream {\n\t\t\t\tif v4First {\n\t\t\t\t\tv4First = false\n\t\t\t\t} else {\n\t\t\t\t\tout.RawByte(',')\n\t\t\t\t}\n\t\t\t\tout.String(string(v4Name))\n\t\t\t\tout.RawByte(':')\n\t\t\t\tout.String(string(v4Value))\n\t\t\t}\n\t\t\tout.RawByte('}')\n\t\t}\n\t}\n\t{\n\t\tconst prefix string = \",\\\"values\\\":\"\n\t\tout.RawString(prefix)\n\t\tif in.Values == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {\n\t\t\tout.RawString(\"null\")\n\t\t} else {\n\t\t\tout.RawByte('[')\n\t\t\tfor v5, v6 := range in.Values {\n\t\t\t\tif v5 > 0 {\n\t\t\t\t\tout.RawByte(',')\n\t\t\t\t}\n\t\t\t\tout.RawByte('[')\n\t\t\t\tfor v7 := range v6 {\n\t\t\t\t\tif v7 > 0 {\n\t\t\t\t\t\tout.RawByte(',')\n\t\t\t\t\t}\n\t\t\t\t\tout.String(string((v6)[v7]))\n\t\t\t\t}\n\t\t\t\tout.RawByte(']')\n\t\t\t}\n\t\t\tout.RawByte(']')\n\t\t}\n\t}\n\tout.RawByte('}')\n}\n\n// MarshalEasyJSON supports easyjson.Marshaler interface\nfunc (v msgStreams) MarshalEasyJSON(w *jwriter.Writer) {\n\teasyjsonC9ac27e5EncodeGoK6IoK6Cloudapi(w, v)\n}\n\n// UnmarshalEasyJSON supports easyjson.Unmarshaler interface\nfunc (v *msgStreams) UnmarshalEasyJSON(l *jlexer.Lexer) {\n\teasyjsonC9ac27e5DecodeGoK6IoK6Cloudapi(l, v)\n}\nfunc easyjsonC9ac27e5DecodeGoK6IoK6Cloudapi1(in *jlexer.Lexer, out *msgDroppedEntries) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"labels\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t} else {\n\t\t\t\tin.Delim('{')\n\t\t\t\tout.Labels = make(map[string]string)\n\t\t\t\tfor !in.IsDelim('}') {\n\t\t\t\t\tkey := string(in.String())\n\t\t\t\t\tin.WantColon()\n\t\t\t\t\tvar v8 string\n\t\t\t\t\tv8 = string(in.String())\n\t\t\t\t\t(out.Labels)[key] = v8\n\t\t\t\t\tin.WantComma()\n\t\t\t\t}\n\t\t\t\tin.Delim('}')\n\t\t\t}\n\t\tcase \"timestamp\":\n\t\t\tout.Timestamp = string(in.String())\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjsonC9ac27e5EncodeGoK6IoK6Cloudapi1(out *jwriter.Writer, in msgDroppedEntries) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"labels\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tif in.Labels == nil && (out.Flags&jwriter.NilMapAsEmpty) == 0 {\n\t\t\tout.RawString(`null`)\n\t\t} else {\n\t\t\tout.RawByte('{')\n\t\t\tv9First := true\n\t\t\tfor v9Name, v9Value := range in.Labels {\n\t\t\t\tif v9First {\n\t\t\t\t\tv9First = false\n\t\t\t\t} else {\n\t\t\t\t\tout.RawByte(',')\n\t\t\t\t}\n\t\t\t\tout.String(string(v9Name))\n\t\t\t\tout.RawByte(':')\n\t\t\t\tout.String(string(v9Value))\n\t\t\t}\n\t\t\tout.RawByte('}')\n\t\t}\n\t}\n\t{\n\t\tconst prefix string = \",\\\"timestamp\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.String(string(in.Timestamp))\n\t}\n\tout.RawByte('}')\n}\n\n// MarshalEasyJSON supports easyjson.Marshaler interface\nfunc (v msgDroppedEntries) MarshalEasyJSON(w *jwriter.Writer) {\n\teasyjsonC9ac27e5EncodeGoK6IoK6Cloudapi1(w, v)\n}\n\n// UnmarshalEasyJSON supports easyjson.Unmarshaler interface\nfunc (v *msgDroppedEntries) UnmarshalEasyJSON(l *jlexer.Lexer) {\n\teasyjsonC9ac27e5DecodeGoK6IoK6Cloudapi1(l, v)\n}\nfunc easyjsonC9ac27e5DecodeGoK6IoK6Cloudapi2(in *jlexer.Lexer, out *msg) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"streams\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t\tout.Streams = nil\n\t\t\t} else {\n\t\t\t\tin.Delim('[')\n\t\t\t\tif out.Streams == nil {\n\t\t\t\t\tif !in.IsDelim(']') {\n\t\t\t\t\t\tout.Streams = make([]msgStreams, 0, 2)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tout.Streams = []msgStreams{}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tout.Streams = (out.Streams)[:0]\n\t\t\t\t}\n\t\t\t\tfor !in.IsDelim(']') {\n\t\t\t\t\tvar v10 msgStreams\n\t\t\t\t\t(v10).UnmarshalEasyJSON(in)\n\t\t\t\t\tout.Streams = append(out.Streams, v10)\n\t\t\t\t\tin.WantComma()\n\t\t\t\t}\n\t\t\t\tin.Delim(']')\n\t\t\t}\n\t\tcase \"dropped_entries\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t\tout.DroppedEntries = nil\n\t\t\t} else {\n\t\t\t\tin.Delim('[')\n\t\t\t\tif out.DroppedEntries == nil {\n\t\t\t\t\tif !in.IsDelim(']') {\n\t\t\t\t\t\tout.DroppedEntries = make([]msgDroppedEntries, 0, 2)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tout.DroppedEntries = []msgDroppedEntries{}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tout.DroppedEntries = (out.DroppedEntries)[:0]\n\t\t\t\t}\n\t\t\t\tfor !in.IsDelim(']') {\n\t\t\t\t\tvar v11 msgDroppedEntries\n\t\t\t\t\t(v11).UnmarshalEasyJSON(in)\n\t\t\t\t\tout.DroppedEntries = append(out.DroppedEntries, v11)\n\t\t\t\t\tin.WantComma()\n\t\t\t\t}\n\t\t\t\tin.Delim(']')\n\t\t\t}\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjsonC9ac27e5EncodeGoK6IoK6Cloudapi2(out *jwriter.Writer, in msg) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"streams\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tif in.Streams == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {\n\t\t\tout.RawString(\"null\")\n\t\t} else {\n\t\t\tout.RawByte('[')\n\t\t\tfor v12, v13 := range in.Streams {\n\t\t\t\tif v12 > 0 {\n\t\t\t\t\tout.RawByte(',')\n\t\t\t\t}\n\t\t\t\t(v13).MarshalEasyJSON(out)\n\t\t\t}\n\t\t\tout.RawByte(']')\n\t\t}\n\t}\n\t{\n\t\tconst prefix string = \",\\\"dropped_entries\\\":\"\n\t\tout.RawString(prefix)\n\t\tif in.DroppedEntries == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {\n\t\t\tout.RawString(\"null\")\n\t\t} else {\n\t\t\tout.RawByte('[')\n\t\t\tfor v14, v15 := range in.DroppedEntries {\n\t\t\t\tif v14 > 0 {\n\t\t\t\t\tout.RawByte(',')\n\t\t\t\t}\n\t\t\t\t(v15).MarshalEasyJSON(out)\n\t\t\t}\n\t\t\tout.RawByte(']')\n\t\t}\n\t}\n\tout.RawByte('}')\n}\n\n// MarshalEasyJSON supports easyjson.Marshaler interface\nfunc (v msg) MarshalEasyJSON(w *jwriter.Writer) {\n\teasyjsonC9ac27e5EncodeGoK6IoK6Cloudapi2(w, v)\n}\n\n// UnmarshalEasyJSON supports easyjson.Unmarshaler interface\nfunc (v *msg) UnmarshalEasyJSON(l *jlexer.Lexer) {\n\teasyjsonC9ac27e5DecodeGoK6IoK6Cloudapi2(l, v)\n}\n"
  },
  {
    "path": "cloudapi/config.go",
    "content": "package cloudapi\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// LegacyCloudConfigKey is the key used in the JSON config for the cloud output.\nconst LegacyCloudConfigKey = \"loadimpact\"\n\n// Config holds all the necessary data and options for sending metrics to the k6 Cloud.\n//\n//nolint:lll\ntype Config struct {\n\t// TODO: refactor common stuff between cloud execution and output\n\tStackID          null.Int    `json:\"stackID\" envconfig:\"K6_CLOUD_STACK_ID\"`\n\tStackURL         null.String `json:\"stackURL\" envconfig:\"K6_CLOUD_STACK_URL\"`\n\tDefaultProjectID null.Int    `json:\"defaultProjectID\"`\n\tToken            null.String `json:\"token\" envconfig:\"K6_CLOUD_TOKEN\"`\n\tProjectID        null.Int    `json:\"projectID\" envconfig:\"K6_CLOUD_PROJECT_ID\"`\n\tName             null.String `json:\"name\" envconfig:\"K6_CLOUD_NAME\"`\n\n\tHost    null.String        `json:\"host\" envconfig:\"K6_CLOUD_HOST\"`\n\tHostv6  null.String        `json:\"hostv6\" envconfig:\"K6_CLOUD_HOST_V6\"` // For test purposes only\n\tTimeout types.NullDuration `json:\"timeout\" envconfig:\"K6_CLOUD_TIMEOUT\"`\n\n\tLogsTailURL    null.String `json:\"-\" envconfig:\"K6_CLOUD_LOGS_TAIL_URL\"`\n\tWebAppURL      null.String `json:\"webAppURL\" envconfig:\"K6_CLOUD_WEB_APP_URL\"`\n\tTestRunDetails null.String `json:\"testRunDetails\" envconfig:\"K6_CLOUD_TEST_RUN_DETAILS\"`\n\tNoCompress     null.Bool   `json:\"noCompress\" envconfig:\"K6_CLOUD_NO_COMPRESS\"`\n\tStopOnError    null.Bool   `json:\"stopOnError\" envconfig:\"K6_CLOUD_STOP_ON_ERROR\"`\n\tAPIVersion     null.Int    `json:\"apiVersion\" envconfig:\"K6_CLOUD_API_VERSION\"`\n\n\t// PushRefID is the identifier used by k6 Cloud to correlate all the things that\n\t// belong to the same test run/execution. Currently, it is equivalent to the test run id.\n\t// But, in the future, or in future solutions (e.g. Synthetic Monitoring), there might be\n\t// no test run id, and we may still need an identifier to correlate all the things.\n\tPushRefID null.String `json:\"pushRefID\" envconfig:\"K6_CLOUD_PUSH_REF_ID\"`\n\n\t// Defines the max allowed number of time series in a single batch.\n\tMaxTimeSeriesInBatch null.Int `json:\"maxTimeSeriesInBatch\" envconfig:\"K6_CLOUD_MAX_TIME_SERIES_IN_BATCH\"`\n\n\t// The time interval between periodic API calls for sending samples to the cloud ingest service.\n\tMetricPushInterval types.NullDuration `json:\"metricPushInterval\" envconfig:\"K6_CLOUD_METRIC_PUSH_INTERVAL\"`\n\n\t// This is how many concurrent pushes will be done at the same time to the cloud\n\tMetricPushConcurrency null.Int `json:\"metricPushConcurrency\" envconfig:\"K6_CLOUD_METRIC_PUSH_CONCURRENCY\"`\n\n\t// If specified and is greater than 0, sample aggregation with that period is enabled\n\tAggregationPeriod types.NullDuration `json:\"aggregationPeriod\" envconfig:\"K6_CLOUD_AGGREGATION_PERIOD\"`\n\n\t// If aggregation is enabled, this specifies how long we'll wait for period samples to accumulate before trying to aggregate them.\n\tAggregationWaitPeriod types.NullDuration `json:\"aggregationWaitPeriod\" envconfig:\"K6_CLOUD_AGGREGATION_WAIT_PERIOD\"`\n\n\t// Indicates whether to send traces to the k6 Insights backend service.\n\tTracesEnabled null.Bool `json:\"tracesEnabled\" envconfig:\"K6_CLOUD_TRACES_ENABLED\"`\n\n\t// The host of the k6 Insights backend service.\n\tTracesHost null.String `json:\"traceHost\" envconfig:\"K6_CLOUD_TRACES_HOST\"`\n\n\t// This is how many concurrent pushes will be done at the same time to the cloud\n\tTracesPushConcurrency null.Int `json:\"tracesPushConcurrency\" envconfig:\"K6_CLOUD_TRACES_PUSH_CONCURRENCY\"`\n\n\t// The time interval between periodic API calls for sending samples to the cloud ingest service.\n\tTracesPushInterval types.NullDuration `json:\"tracesPushInterval\" envconfig:\"K6_CLOUD_TRACES_PUSH_INTERVAL\"`\n}\n\n// NewConfig creates a new Config instance with default values for some fields.\nfunc NewConfig() Config {\n\treturn Config{\n\t\tAPIVersion:            null.NewInt(2, false),\n\t\tHost:                  null.NewString(\"https://ingest.k6.io\", false),\n\t\tHostv6:                null.NewString(\"https://api.k6.io\", false),\n\t\tLogsTailURL:           null.NewString(\"wss://cloudlogs.k6.io/api/v1/tail\", false),\n\t\tWebAppURL:             null.NewString(\"https://app.k6.io\", false),\n\t\tMetricPushInterval:    types.NewNullDuration(1*time.Second, false),\n\t\tMetricPushConcurrency: null.NewInt(1, false),\n\t\tTimeout:               types.NewNullDuration(1*time.Minute, false),\n\n\t\t// The set value (1000) is selected for performance reasons.\n\t\t// Any change to this value should be first discussed with internal stakeholders.\n\t\tMaxTimeSeriesInBatch: null.NewInt(1000, false),\n\n\t\t// TODO: the following values were used by the previous default version (v1).\n\t\t// We decided to keep the same values mostly for having a smoother migration to v2.\n\t\t// Because the previous version's aggregation config, a few lines below, is overwritten\n\t\t// by the remote service with the same values that we are now setting here for v2.\n\t\t// When the migration will be completed we may evaluate to re-discuss them\n\t\t// as we may evaluate to reduce these values - especially the waiting period.\n\t\t// A more specific request about waiting period is mentioned in the link below:\n\t\t// https://github.com/grafana/k6/blob/44e1e63aadb66784ff0a12b8d9821a0fdc9e7467/output/cloud/expv2/collect.go#L72-L77\n\t\tAggregationPeriod:     types.NewNullDuration(3*time.Second, false),\n\t\tAggregationWaitPeriod: types.NewNullDuration(8*time.Second, false),\n\n\t\tTracesEnabled:         null.NewBool(true, false),\n\t\tTracesHost:            null.NewString(\"grpc-k6-api-prod-prod-us-east-0.grafana.net:443\", false),\n\t\tTracesPushInterval:    types.NewNullDuration(1*time.Second, false),\n\t\tTracesPushConcurrency: null.NewInt(1, false),\n\t}\n}\n\n// Apply saves config non-zero config values from the passed config in the receiver.\n//\n//nolint:cyclop,gocognit\nfunc (c Config) Apply(cfg Config) Config {\n\tif cfg.StackID.Valid {\n\t\tc.StackID = cfg.StackID\n\t}\n\tif cfg.StackURL.Valid && !c.StackURL.Valid {\n\t\tc.StackURL = cfg.StackURL\n\t}\n\tif cfg.DefaultProjectID.Valid {\n\t\tc.DefaultProjectID = cfg.DefaultProjectID\n\t}\n\tif cfg.Token.Valid {\n\t\tc.Token = cfg.Token\n\t}\n\tif cfg.ProjectID.Valid && cfg.ProjectID.Int64 > 0 {\n\t\tc.ProjectID = cfg.ProjectID\n\t}\n\tif cfg.Name.Valid && cfg.Name.String != \"\" {\n\t\tc.Name = cfg.Name\n\t}\n\tif cfg.Host.Valid && cfg.Host.String != \"\" {\n\t\tc.Host = cfg.Host\n\t}\n\tif cfg.Hostv6.Valid && cfg.Hostv6.String != \"\" {\n\t\tc.Hostv6 = cfg.Hostv6\n\t}\n\tif cfg.LogsTailURL.Valid && cfg.LogsTailURL.String != \"\" {\n\t\tc.LogsTailURL = cfg.LogsTailURL\n\t}\n\tif cfg.PushRefID.Valid {\n\t\tc.PushRefID = cfg.PushRefID\n\t}\n\tif cfg.WebAppURL.Valid {\n\t\tc.WebAppURL = cfg.WebAppURL\n\t}\n\tif cfg.TestRunDetails.Valid {\n\t\tc.TestRunDetails = cfg.TestRunDetails\n\t}\n\tif cfg.NoCompress.Valid {\n\t\tc.NoCompress = cfg.NoCompress\n\t}\n\tif cfg.StopOnError.Valid {\n\t\tc.StopOnError = cfg.StopOnError\n\t}\n\tif cfg.Timeout.Valid {\n\t\tc.Timeout = cfg.Timeout\n\t}\n\tif cfg.APIVersion.Valid {\n\t\tc.APIVersion = cfg.APIVersion\n\t}\n\tif cfg.MaxTimeSeriesInBatch.Valid {\n\t\tc.MaxTimeSeriesInBatch = cfg.MaxTimeSeriesInBatch\n\t}\n\tif cfg.MetricPushInterval.Valid {\n\t\tc.MetricPushInterval = cfg.MetricPushInterval\n\t}\n\tif cfg.MetricPushConcurrency.Valid {\n\t\tc.MetricPushConcurrency = cfg.MetricPushConcurrency\n\t}\n\tif cfg.TracesEnabled.Valid {\n\t\tc.TracesEnabled = cfg.TracesEnabled\n\t}\n\tif cfg.TracesHost.Valid {\n\t\tc.TracesHost = cfg.TracesHost\n\t}\n\tif cfg.TracesPushInterval.Valid {\n\t\tc.TracesPushInterval = cfg.TracesPushInterval\n\t}\n\tif cfg.TracesPushConcurrency.Valid {\n\t\tc.TracesPushConcurrency = cfg.TracesPushConcurrency\n\t}\n\tif cfg.AggregationPeriod.Valid {\n\t\tc.AggregationPeriod = cfg.AggregationPeriod\n\t}\n\tif cfg.AggregationWaitPeriod.Valid {\n\t\tc.AggregationWaitPeriod = cfg.AggregationWaitPeriod\n\t}\n\treturn c\n}\n\n// GetConsolidatedConfig combines the default config values with the JSON config\n// values and environment variables and returns the final result.\n// it also returns a warning message that could be shown to the user.\n// to bring some attention to the fact that the user.\nfunc GetConsolidatedConfig(\n\tjsonRawConf json.RawMessage,\n\tenv map[string]string,\n\tconfigArg string,\n\tcloudConfig json.RawMessage,\n\texternal map[string]json.RawMessage,\n) (Config, string, error) {\n\twarn := \"\"\n\n\tresult := NewConfig()\n\tif jsonRawConf != nil {\n\t\tjsonConf := Config{}\n\t\tif err := json.Unmarshal(jsonRawConf, &jsonConf); err != nil {\n\t\t\treturn result, warn, err\n\t\t}\n\t\tresult = result.Apply(jsonConf)\n\t}\n\n\tif err := mergeFromCloudOptionAndExternal(cloudConfig, external, &result); err != nil {\n\t\treturn result, warn, err\n\t}\n\n\t// We want to show a warning if the user is using the only old way of defining the config.\n\t// Note: Since the migration to the options.cloud is a long process, this warning is planned\n\t// to be emitted for a long time (1-2 years), after some point, and depending on the state\n\t// of migration we could re-evaluate this warning.\n\tif cloudConfig == nil && external != nil {\n\t\tif _, ok := external[LegacyCloudConfigKey]; ok {\n\t\t\twarn = \"The options.ext.loadimpact option is deprecated, please use options.cloud instead\"\n\t\t}\n\t}\n\n\tenvConfig := Config{}\n\tif err := envconfig.Process(\"\", &envConfig, func(key string) (string, bool) {\n\t\tv, ok := env[key]\n\t\treturn v, ok\n\t}); err != nil {\n\t\t// TODO: get rid of envconfig and actually use the env parameter...\n\t\treturn result, warn, err\n\t}\n\tresult = result.Apply(envConfig)\n\n\tif configArg != \"\" {\n\t\tresult.Name = null.StringFrom(configArg)\n\t}\n\n\treturn result, warn, nil\n}\n\n// mergeFromCloudOptionAndExternal merges three fields from the JSON in a cloud key of\n// the provided external map. Used for options.cloud settings.\nfunc mergeFromCloudOptionAndExternal(\n\tcloudConfig json.RawMessage,\n\texternal map[string]json.RawMessage,\n\tconf *Config,\n) error {\n\tsource := pickSource(cloudConfig, external)\n\tif source == nil {\n\t\treturn nil\n\t}\n\n\t// Original comment\n\t// TODO: Important! Separate configs and fix the whole 2 configs mess!\n\ttmpConfig := Config{}\n\tif err := json.Unmarshal(source, &tmpConfig); err != nil {\n\t\treturn err\n\t}\n\n\t// Only merge ProjectID, Name, Token, and StackID from options.\n\t// StackURL and DefaultProjectID can only be set via login.\n\tif tmpConfig.ProjectID.Valid {\n\t\tconf.ProjectID = tmpConfig.ProjectID\n\t}\n\tif tmpConfig.Name.Valid {\n\t\tconf.Name = tmpConfig.Name\n\t}\n\tif tmpConfig.Token.Valid {\n\t\tconf.Token = tmpConfig.Token\n\t}\n\tif tmpConfig.StackID.Valid {\n\t\tconf.StackID = tmpConfig.StackID\n\t}\n\n\treturn nil\n}\n\n// GetTemporaryCloudConfig returns a temporary cloud config.\n// Original comment\n// TODO: Fix this\n// We reuse cloud.Config for parsing options.cloud (or legacy loadimpact struct), but this probably shouldn't be\n// done, as the idea of options.ext is that they are extensible without touching k6. But in\n// order for this to happen, we shouldn't actually marshal cloud.Config on top of it, because\n// it will be missing some fields that aren't actually mentioned in the struct.\n// So in order for use to copy the fields that we need for k6 cloud's api we unmarshal in\n// map[string]any and copy what we need if it isn't set already\nfunc GetTemporaryCloudConfig(\n\tcloudConfig json.RawMessage,\n\texternal map[string]json.RawMessage,\n) (map[string]any, error) {\n\ttmpCloudConfig := make(map[string]any, 3)\n\n\tsource := pickSource(cloudConfig, external)\n\tif source == nil {\n\t\treturn tmpCloudConfig, nil\n\t}\n\n\tdec := json.NewDecoder(bytes.NewReader(source))\n\tdec.UseNumber() // otherwise float64 are used\n\tif err := dec.Decode(&tmpCloudConfig); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tmpCloudConfig, nil\n}\n\n// pickSource returns the config source to use.\nfunc pickSource(\n\tcloudConfig json.RawMessage,\n\texternal map[string]json.RawMessage,\n) json.RawMessage {\n\t// priority is the new way of defining the config\n\t// via options.cloud\n\tif cloudConfig != nil {\n\t\treturn cloudConfig\n\t}\n\n\t// fallback to the old way of defining the config\n\tif val, ok := external[LegacyCloudConfigKey]; ok {\n\t\treturn val\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "cloudapi/config_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestConfigApply(t *testing.T) {\n\tt.Parallel()\n\tempty := Config{}\n\tdefaults := NewConfig()\n\n\tassert.Equal(t, empty, empty.Apply(empty))\n\tassert.Equal(t, empty, empty.Apply(defaults))\n\tassert.Equal(t, defaults, defaults.Apply(defaults))\n\tassert.Equal(t, defaults, defaults.Apply(empty))\n\tassert.Equal(t, defaults, defaults.Apply(empty).Apply(empty))\n\n\tfull := Config{\n\t\tToken:                 null.NewString(\"Token\", true),\n\t\tStackID:               null.NewInt(1, true),\n\t\tProjectID:             null.NewInt(1, true),\n\t\tName:                  null.NewString(\"Name\", true),\n\t\tHost:                  null.NewString(\"Host\", true),\n\t\tHostv6:                null.NewString(\"Hostv6\", true),\n\t\tTimeout:               types.NewNullDuration(5*time.Second, true),\n\t\tLogsTailURL:           null.NewString(\"LogsTailURL\", true),\n\t\tPushRefID:             null.NewString(\"PushRefID\", true),\n\t\tWebAppURL:             null.NewString(\"foo\", true),\n\t\tNoCompress:            null.NewBool(true, true),\n\t\tStopOnError:           null.NewBool(true, true),\n\t\tAPIVersion:            null.NewInt(2, true),\n\t\tAggregationPeriod:     types.NewNullDuration(2*time.Second, true),\n\t\tAggregationWaitPeriod: types.NewNullDuration(4*time.Second, true),\n\t\tMaxTimeSeriesInBatch:  null.NewInt(3, true),\n\t\tMetricPushInterval:    types.NewNullDuration(1*time.Second, true),\n\t\tMetricPushConcurrency: null.NewInt(3, true),\n\t\tTracesEnabled:         null.NewBool(true, true),\n\t\tTracesHost:            null.NewString(\"TracesHost\", true),\n\t\tTracesPushInterval:    types.NewNullDuration(10*time.Second, true),\n\t\tTracesPushConcurrency: null.NewInt(6, true),\n\t}\n\n\tassert.Equal(t, full, full.Apply(empty))\n\tassert.Equal(t, full, full.Apply(defaults))\n\tassert.Equal(t, full, full.Apply(full))\n\tassert.Equal(t, full, empty.Apply(full))\n\tassert.Equal(t, full, defaults.Apply(full))\n}\n\nfunc TestGetConsolidatedConfig(t *testing.T) {\n\tt.Parallel()\n\tconfig, warn, err := GetConsolidatedConfig(json.RawMessage(`{\"token\":\"jsonraw\"}`), nil, \"\", nil, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"jsonraw\", config.Token.String)\n\trequire.Empty(t, warn)\n\n\tconfig, warn, err = GetConsolidatedConfig(\n\t\tjson.RawMessage(`{\"token\":\"jsonraw\"}`),\n\t\tnil,\n\t\t\"\",\n\t\tjson.RawMessage(`{\"token\":\"ext\"}`),\n\t\tnil,\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"ext\", config.Token.String)\n\trequire.Empty(t, warn)\n\n\tconfig, warn, err = GetConsolidatedConfig(\n\t\tjson.RawMessage(`{\"token\":\"jsonraw\"}`),\n\t\tmap[string]string{\"K6_CLOUD_TOKEN\": \"envvalue\"},\n\t\t\"\",\n\t\tjson.RawMessage(`{\"token\":\"ext\"}`),\n\t\tnil,\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"envvalue\", config.Token.String)\n\trequire.Empty(t, warn)\n}\n\nfunc TestGetConsolidatedConfig_WithLegacyOnly(t *testing.T) {\n\tt.Parallel()\n\n\tconfig, warn, err := GetConsolidatedConfig(json.RawMessage(`{\"token\":\"jsonraw\"}`), nil, \"\", nil,\n\t\tmap[string]json.RawMessage{\"loadimpact\": json.RawMessage(`{\"token\":\"ext\"}`)})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"ext\", config.Token.String)\n\trequire.NotEmpty(t, warn)\n\n\tconfig, warn, err = GetConsolidatedConfig(json.RawMessage(`{\"token\":\"jsonraw\"}`), map[string]string{\"K6_CLOUD_TOKEN\": \"envvalue\"}, \"\", nil,\n\t\tmap[string]json.RawMessage{\"loadimpact\": json.RawMessage(`{\"token\":\"ext\"}`)})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"envvalue\", config.Token.String)\n\trequire.NotEmpty(t, warn)\n}\n\nfunc TestGetConsolidatedConfig_LegacyHasLowerPriority(t *testing.T) {\n\tt.Parallel()\n\n\tconfig, warn, err := GetConsolidatedConfig(\n\t\tjson.RawMessage(`{\"token\":\"jsonraw\"}`),\n\t\tnil,\n\t\t\"\",\n\t\tjson.RawMessage(`{\"token\":\"cloud\"}`),\n\t\tmap[string]json.RawMessage{\"loadimpact\": json.RawMessage(`{\"token\":\"ext\"}`)},\n\t)\n\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"cloud\", config.Token.String)\n\trequire.Empty(t, warn)\n}\n\nfunc TestGetConsolidatedConfig_EnvHasHigherPriority(t *testing.T) {\n\tt.Parallel()\n\n\tconfig, warn, err := GetConsolidatedConfig(\n\t\tjson.RawMessage(`{\"token\":\"jsonraw\"}`),\n\t\tmap[string]string{\"K6_CLOUD_TOKEN\": \"envvalue\"},\n\t\t\"\",\n\t\tjson.RawMessage(`{\"token\":\"cloud\"}`),\n\t\tmap[string]json.RawMessage{\"loadimpact\": json.RawMessage(`{\"token\":\"ext\"}`)},\n\t)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"envvalue\", config.Token.String)\n\trequire.Empty(t, warn)\n}\n"
  },
  {
    "path": "cloudapi/doc.go",
    "content": "// Package cloudapi contains several things related to the k6 cloud - various\n// data and config structures, a REST API client, log streaming logic, etc. They\n// are all used in cloud tests (i.e. `k6 cloud`), and in local tests emitting\n// their results to the k6 cloud output (i.e. `k6 run --out cloud`).\npackage cloudapi\n"
  },
  {
    "path": "cloudapi/errors.go",
    "content": "package cloudapi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"slices\"\n\t\"strings\"\n)\n\nvar (\n\terrNotAuthorized    = errors.New(\"not allowed to upload result to k6 Cloud\")\n\terrNotAuthenticated = errors.New(\"failed to authenticate with k6 Cloud\")\n\terrUnknown          = errors.New(\"an error occurred communicating with k6 Cloud\")\n)\n\n// ResponseError represents an error cause by talking to the API\ntype ResponseError struct {\n\tResponse *http.Response `json:\"-\"`\n\n\tCode        int                 `json:\"code\"`\n\tMessage     string              `json:\"message\"`\n\tDetails     map[string][]string `json:\"details\"`\n\tFieldErrors map[string][]string `json:\"field_errors\"`\n\tErrors      []string            `json:\"errors\"`\n}\n\nfunc contains(s []string, e string) bool {\n\treturn slices.Contains(s, e)\n}\n\nfunc (e ResponseError) Error() string {\n\tmsg := e.Message\n\n\tfor _, v := range e.Errors {\n\t\t// atm: `errors` and `message` could be duplicated\n\t\t// TODO: remove condition when the API changes\n\t\tif v != msg {\n\t\t\tmsg += \"\\n \" + v\n\t\t}\n\t}\n\n\t// `e.Details` is the old API version\n\t// TODO: do not handle `details` when the old API becomes obsolete\n\tvar details []string\n\tvar detail string\n\tfor k, v := range e.Details {\n\t\tdetail = k + \": \" + strings.Join(v, \", \")\n\t\tdetails = append(details, detail)\n\t}\n\n\tfor k, v := range e.FieldErrors {\n\t\tdetail = k + \": \" + strings.Join(v, \", \")\n\t\t// atm: `details` and `field_errors` could be duplicated\n\t\tif !contains(details, detail) {\n\t\t\tdetails = append(details, detail)\n\t\t}\n\t}\n\n\tif len(details) > 0 {\n\t\tmsg += \"\\n \" + strings.Join(details, \"\\n\")\n\t}\n\n\tvar code string\n\tswitch {\n\tcase e.Code > 0 && e.Response != nil:\n\t\tcode = fmt.Sprintf(\"%d/E%d\", e.Response.StatusCode, e.Code)\n\tcase e.Response != nil:\n\t\tcode = fmt.Sprintf(\"%d\", e.Response.StatusCode)\n\tcase e.Code > 0:\n\t\tcode = fmt.Sprintf(\"E%d\", e.Code)\n\t}\n\n\tif len(code) > 0 {\n\t\tmsg = fmt.Sprintf(\"(%s) %s\", code, msg)\n\t}\n\n\treturn msg\n}\n"
  },
  {
    "path": "cloudapi/errors_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestContains(t *testing.T) {\n\tt.Parallel()\n\n\ts := []string{\"a\", \"b\", \"c\"}\n\n\tassert.False(t, contains(s, \"e\"))\n\tassert.True(t, contains(s, \"b\"))\n}\n\nfunc TestErrorResponse_Error(t *testing.T) {\n\tt.Parallel()\n\n\tmsg1 := \"some message\"\n\tmsg2 := \"some other message\"\n\n\terrResp := ResponseError{\n\t\tMessage: msg1,\n\t\tErrors:  []string{msg2},\n\t\tFieldErrors: map[string][]string{\n\t\t\t\"field1\": {\"error1\", \"error2\"},\n\t\t},\n\t\tCode: 123,\n\t}\n\n\texpected := \"(E123) \" + msg1 + \"\\n \" + msg2 + \"\\n field1: error1, error2\"\n\tassert.Equal(t, expected, errResp.Error())\n}\n"
  },
  {
    "path": "cloudapi/logs.go",
    "content": "package cloudapi\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\" // nosemgrep: math-random-used // This is being used retry jitter\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/mailru/easyjson\"\n\t\"github.com/sirupsen/logrus\"\n)\n\n//go:generate easyjson -pkg -no_std_marshalers -gen_build_flags -mod=mod .\n\n//easyjson:json\ntype msg struct {\n\tStreams        []msgStreams        `json:\"streams\"`\n\tDroppedEntries []msgDroppedEntries `json:\"dropped_entries\"`\n}\n\n//easyjson:json\ntype msgStreams struct {\n\tStream map[string]string `json:\"stream\"`\n\tValues [][2]string       `json:\"values\"` // this can be optimized\n}\n\n//easyjson:json\ntype msgDroppedEntries struct {\n\tLabels    map[string]string `json:\"labels\"`\n\tTimestamp string            `json:\"timestamp\"`\n}\n\n// Log writes the Streams and Dropped Entries to the passed logger.\n// It returns the most recent timestamp seen overall messages.\nfunc (m *msg) Log(logger logrus.FieldLogger) int64 {\n\tvar level string\n\tvar ts int64\n\n\tfor _, stream := range m.Streams {\n\t\tfields := labelsToLogrusFields(stream.Stream)\n\t\tvar ok bool\n\t\tif level, ok = stream.Stream[\"level\"]; ok {\n\t\t\tdelete(fields, \"level\")\n\t\t}\n\n\t\tfor _, value := range stream.Values {\n\t\t\tnsec, _ := strconv.ParseInt(value[0], 10, 64)\n\t\t\te := logger.WithFields(fields).WithTime(time.Unix(0, nsec))\n\t\t\tlvl, err := logrus.ParseLevel(level)\n\t\t\tif err != nil {\n\t\t\t\te.Info(value[1])\n\t\t\t\te.Warn(\"last message had unknown level \" + level)\n\t\t\t} else {\n\t\t\t\te.Log(lvl, value[1])\n\t\t\t}\n\n\t\t\t// find the latest seen message\n\t\t\tif nsec > ts {\n\t\t\t\tts = nsec\n\t\t\t}\n\t\t}\n\t}\n\n\tfor _, dropped := range m.DroppedEntries {\n\t\tnsec, _ := strconv.ParseInt(dropped.Timestamp, 10, 64)\n\t\tlogger.WithFields(labelsToLogrusFields(dropped.Labels)).WithTime(time.Unix(0, nsec)).Warn(\"dropped\")\n\n\t\tif nsec > ts {\n\t\t\tts = nsec\n\t\t}\n\t}\n\n\treturn ts\n}\n\nfunc labelsToLogrusFields(labels map[string]string) logrus.Fields {\n\tfields := make(logrus.Fields, len(labels))\n\n\tfor key, val := range labels {\n\t\tfields[key] = val\n\t}\n\n\treturn fields\n}\n\nfunc (c *Config) logtailConn(ctx context.Context, referenceID string, since time.Time) (*websocket.Conn, error) {\n\tu, err := url.Parse(c.LogsTailURL.String)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"couldn't parse cloud logs host %w\", err)\n\t}\n\n\tu.RawQuery = fmt.Sprintf(`query={test_run_id=\"%s\"}&start=%d`, referenceID, since.UnixNano())\n\n\theaders := make(http.Header)\n\theaders.Add(\"Sec-WebSocket-Protocol\", \"token=\"+c.Token.String)\n\theaders.Add(\"Authorization\", \"token \"+c.Token.String)\n\theaders.Add(\"X-K6testrun-Id\", referenceID)\n\n\tvar conn *websocket.Conn\n\terr = retry(sleeperFunc(time.Sleep), 3, 5*time.Second, 2*time.Minute, func() (err error) {\n\t\t// We don't need to close the http body or use it for anything until we want to actually log\n\t\t// what the server returned as body when it errors out\n\t\tconn, _, err = websocket.DefaultDialer.DialContext(ctx, u.String(), headers) //nolint:bodyclose\n\t\treturn err\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn conn, nil\n}\n\n// StreamLogsToLogger streams the logs for the configured test to the provided logger until ctx is\n// Done or an error occurs.\nfunc (c *Config) StreamLogsToLogger(\n\tctx context.Context, logger logrus.FieldLogger, referenceID string, tailFrom time.Duration,\n) error {\n\tvar mconn sync.Mutex\n\n\tconn, err := c.logtailConn(ctx, referenceID, time.Now().Add(-tailFrom))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tgo func() {\n\t\t<-ctx.Done()\n\n\t\tmconn.Lock()\n\t\tdefer mconn.Unlock()\n\n\t\t_ = conn.WriteControl(\n\t\t\twebsocket.CloseMessage,\n\t\t\twebsocket.FormatCloseMessage(websocket.CloseGoingAway, \"closing\"),\n\t\t\ttime.Now().Add(time.Second))\n\n\t\t_ = conn.Close()\n\t}()\n\n\tmsgBuffer := make(chan []byte, 10)\n\tdefer close(msgBuffer)\n\n\tvar mostRecent int64\n\tgo func() {\n\t\tfor message := range msgBuffer {\n\t\t\tvar m msg\n\t\t\terr := easyjson.Unmarshal(message, &m)\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithError(err).Errorf(\"couldn't unmarshal a message from the cloud: %s\", string(message))\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tts := m.Log(logger)\n\t\t\tatomic.StoreInt64(&mostRecent, ts)\n\t\t}\n\t}()\n\n\tfor {\n\t\t_, message, err := conn.ReadMessage()\n\t\tselect { // check if we should stop before continuing\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\n\t\tif err != nil {\n\t\t\tlogger.WithError(err).Warn(\"error reading a log message from the cloud, trying to establish a fresh connection with the logs service...\") //nolint:lll\n\n\t\t\tvar since time.Time\n\t\t\tif ts := atomic.LoadInt64(&mostRecent); ts > 0 {\n\t\t\t\t// add 1ns for avoid possible repetition\n\t\t\t\tsince = time.Unix(0, ts).Add(time.Nanosecond)\n\t\t\t} else {\n\t\t\t\tsince = time.Now()\n\t\t\t}\n\n\t\t\t// TODO: avoid the \"logical\" race condition\n\t\t\t// The case explained:\n\t\t\t// * The msgBuffer consumer is slow\n\t\t\t// * ReadMessage is fast and adds at least one more message in the buffer\n\t\t\t// * An error is got in the meantime and the re-dialing procedure is tried\n\t\t\t// * Then the latest timestamp used will not be the real latest received\n\t\t\t// * because it is still waiting to be processed.\n\t\t\t// In the case the connection will be restored then the first message will be a duplicate.\n\t\t\tnewconn, errd := c.logtailConn(ctx, referenceID, since)\n\t\t\tif errd != nil {\n\t\t\t\t// return the main error\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tmconn.Lock()\n\t\t\tconn = newconn\n\t\t\tmconn.Unlock()\n\t\t\tcontinue\n\t\t}\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase msgBuffer <- message:\n\t\t}\n\t}\n}\n\n// sleeper represents an abstraction for waiting an amount of time.\ntype sleeper interface {\n\tSleep(d time.Duration)\n}\n\n// sleeperFunc uses the underhood function for implementing the wait operation.\ntype sleeperFunc func(time.Duration)\n\nfunc (sfn sleeperFunc) Sleep(d time.Duration) {\n\tsfn(d)\n}\n\n// retry retries to execute a provided function until it isn't successful\n// or the maximum number of attempts is hit. It waits the specified interval\n// between the latest iteration and the next retry.\n// Interval is used as the base to compute an exponential backoff,\n// if the computed interval overtakes the max interval then max will be used.\nfunc retry(s sleeper, attempts int, interval, maxDuration time.Duration, do func() error) (err error) {\n\tbaseInterval := math.Abs(interval.Truncate(time.Second).Seconds())\n\tr := rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\n\tfor i := range attempts {\n\t\tif i > 0 {\n\t\t\t// wait = (interval ^ i) + random milliseconds\n\t\t\twait := time.Duration(math.Pow(baseInterval, float64(i))) * time.Second\n\t\t\twait += time.Duration(r.Int63n(1000)) * time.Millisecond\n\n\t\t\tif wait > maxDuration {\n\t\t\t\twait = maxDuration\n\t\t\t}\n\t\t\ts.Sleep(wait)\n\t\t}\n\t\terr = do()\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "cloudapi/logs_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/mailru/easyjson\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n)\n\nfunc TestMsgParsing(t *testing.T) {\n\tt.Parallel()\n\tm := `{\n  \"streams\": [\n    {\n      \"stream\": {\n      \t\"key1\": \"value1\",\n\t   \t\"key2\": \"value2\"\n      },\n      \"values\": [\n        [\n      \t\"1598282752000000000\",\n\t\t\"something to log\"\n        ]\n      ]\n    }\n  ],\n  \"dropped_entries\": [\n    {\n      \"labels\": {\n      \t\"key3\": \"value1\",\n\t   \t\"key4\": \"value2\"\n      },\n      \"timestamp\": \"1598282752000000000\"\n    }\n  ]\n}\n`\n\texpectMsg := msg{\n\t\tStreams: []msgStreams{\n\t\t\t{\n\t\t\t\tStream: map[string]string{\"key1\": \"value1\", \"key2\": \"value2\"},\n\t\t\t\tValues: [][2]string{{\"1598282752000000000\", \"something to log\"}},\n\t\t\t},\n\t\t},\n\t\tDroppedEntries: []msgDroppedEntries{\n\t\t\t{\n\t\t\t\tLabels:    map[string]string{\"key3\": \"value1\", \"key4\": \"value2\"},\n\t\t\t\tTimestamp: \"1598282752000000000\",\n\t\t\t},\n\t\t},\n\t}\n\tvar message msg\n\trequire.NoError(t, easyjson.Unmarshal([]byte(m), &message))\n\trequire.Equal(t, expectMsg, message)\n}\n\nfunc TestMSGLog(t *testing.T) {\n\tt.Parallel()\n\texpectMsg := msg{\n\t\tStreams: []msgStreams{\n\t\t\t{\n\t\t\t\tStream: map[string]string{\"key1\": \"value1\", \"key2\": \"value2\"},\n\t\t\t\tValues: [][2]string{{\"1598282752000000000\", \"something to log\"}},\n\t\t\t},\n\t\t\t{\n\t\t\t\tStream: map[string]string{\"key1\": \"value1\", \"key2\": \"value2\", \"level\": \"warn\"},\n\t\t\t\tValues: [][2]string{{\"1598282752000000000\", \"something else log\"}},\n\t\t\t},\n\t\t},\n\t\tDroppedEntries: []msgDroppedEntries{\n\t\t\t{\n\t\t\t\tLabels:    map[string]string{\"key3\": \"value1\", \"key4\": \"value2\", \"level\": \"panic\"},\n\t\t\t\tTimestamp: \"1598282752000000000\",\n\t\t\t},\n\t\t},\n\t}\n\n\tlogger := logrus.New()\n\tlogger.Out = io.Discard\n\thook := testutils.NewLogHook()\n\tlogger.AddHook(hook)\n\texpectMsg.Log(logger)\n\tlogLines := hook.Drain()\n\tassert.Equal(t, 4, len(logLines))\n\texpectTime := time.Unix(0, 1598282752000000000)\n\tfor i, entry := range logLines {\n\t\tvar expectedMsg string\n\t\tswitch i {\n\t\tcase 0:\n\t\t\texpectedMsg = \"something to log\"\n\t\tcase 1:\n\t\t\texpectedMsg = \"last message had unknown level \"\n\t\tcase 2:\n\t\t\texpectedMsg = \"something else log\"\n\t\tcase 3:\n\t\t\texpectedMsg = \"dropped\"\n\t\t}\n\t\trequire.Equal(t, expectedMsg, entry.Message)\n\t\trequire.Equal(t, expectTime, entry.Time)\n\t}\n}\n\nfunc TestRetry(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Success\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttests := []struct {\n\t\t\tname     string\n\t\t\tattempts int\n\t\t\texpWaits []time.Duration // pow(abs(interval), attempt index)\n\t\t}{\n\t\t\t{\n\t\t\t\tname:     \"NoRetry\",\n\t\t\t\tattempts: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"TwoAttempts\",\n\t\t\t\tattempts: 2,\n\t\t\t\texpWaits: []time.Duration{5 * time.Second},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"MaximumExceeded\",\n\t\t\t\tattempts: 4,\n\t\t\t\texpWaits: []time.Duration{5 * time.Second, 25 * time.Second, 2 * time.Minute},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"AttemptsLimit\",\n\t\t\t\tattempts: 5,\n\t\t\t\texpWaits: []time.Duration{5 * time.Second, 25 * time.Second, 2 * time.Minute, 2 * time.Minute},\n\t\t\t},\n\t\t}\n\n\t\tfor _, tt := range tests {\n\t\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar sleepRequests []time.Duration\n\t\t\t\t// sleepCollector tracks the request duration value for sleep requests.\n\t\t\t\tsleepCollector := sleeperFunc(func(d time.Duration) {\n\t\t\t\t\tsleepRequests = append(sleepRequests, d)\n\t\t\t\t})\n\n\t\t\t\tvar iterations int\n\t\t\t\terr := retry(sleepCollector, 5, 5*time.Second, 2*time.Minute, func() error {\n\t\t\t\t\titerations++\n\t\t\t\t\tif iterations < tt.attempts {\n\t\t\t\t\t\treturn fmt.Errorf(\"unexpected error\")\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tt.attempts, iterations)\n\t\t\t\trequire.Equal(t, len(tt.expWaits), len(sleepRequests))\n\n\t\t\t\t// the added random milliseconds makes difficult to know the exact value\n\t\t\t\t// so it asserts that expwait <= actual <= expwait + 1s\n\t\t\t\tfor i, expwait := range tt.expWaits {\n\t\t\t\t\tassert.GreaterOrEqual(t, sleepRequests[i], expwait)\n\t\t\t\t\tassert.LessOrEqual(t, sleepRequests[i], expwait+(1*time.Second))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n\tt.Run(\"Fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tmock := sleeperFunc(func(time.Duration) { /* noop - nowait */ })\n\t\terr := retry(mock, 5, 5*time.Second, 30*time.Second, func() error {\n\t\t\treturn fmt.Errorf(\"unexpected error\")\n\t\t})\n\n\t\tassert.Error(t, err, \"unexpected error\")\n\t})\n}\n\nfunc TestStreamLogsToLogger(t *testing.T) {\n\tt.Parallel()\n\n\t// It registers an handler for the logtail endpoint\n\t// It upgrades as websocket the HTTP handler and invokes the provided callback.\n\tlogtailHandleFunc := func(tb *httpmultibin.HTTPMultiBin, fn func(*websocket.Conn, *http.Request)) {\n\t\tupgrader := websocket.Upgrader{\n\t\t\tReadBufferSize:  1024,\n\t\t\tWriteBufferSize: 1024,\n\t\t}\n\t\ttb.Mux.HandleFunc(\"/api/v1/tail\", func(w http.ResponseWriter, req *http.Request) {\n\t\t\tconn, err := upgrader.Upgrade(w, req, nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfn(conn, req)\n\t\t\t_ = conn.Close()\n\t\t})\n\t}\n\n\t// a basic config with the logtail endpoint set\n\tconfigFromHTTPMultiBin := func(tb *httpmultibin.HTTPMultiBin) Config {\n\t\twsurl := strings.TrimPrefix(tb.ServerHTTP.URL, \"http://\")\n\t\treturn Config{\n\t\t\tLogsTailURL: null.NewString(fmt.Sprintf(\"ws://%s/api/v1/tail\", wsurl), false),\n\t\t}\n\t}\n\n\t// get all messages from the mocked logger\n\tlogLines := func(hook *testutils.SimpleLogrusHook) (lines []string) {\n\t\tfor _, e := range hook.Drain() {\n\t\t\tlines = append(lines, e.Message)\n\t\t}\n\t\treturn lines\n\t}\n\n\tgenerateLogline := func(key string, ts uint64, msg string) string {\n\t\treturn fmt.Sprintf(`{\"streams\":[{\"stream\":{\"key\":%q,\"level\":\"warn\"},\"values\":[[\"%d\",%q]]}],\"dropped_entities\":[]}`, key, ts, msg)\n\t}\n\n\tt.Run(\"Success\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tlogtailHandleFunc(tb, func(conn *websocket.Conn, _ *http.Request) {\n\t\t\trawmsg := json.RawMessage(generateLogline(\"stream1\", 1598282752000000000, \"logline1\"))\n\t\t\terr := conn.WriteJSON(rawmsg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trawmsg = json.RawMessage(generateLogline(\"stream2\", 1598282752000000001, \"logline2\"))\n\t\t\terr = conn.WriteJSON(rawmsg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// wait the flush on the network\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tcancel()\n\t\t})\n\n\t\tlogger := logrus.New()\n\t\tlogger.Out = io.Discard\n\t\thook := testutils.NewLogHook()\n\t\tlogger.AddHook(hook)\n\n\t\tc := configFromHTTPMultiBin(tb)\n\t\terr := c.StreamLogsToLogger(ctx, logger, \"ref_id\", 0)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, []string{\"logline1\", \"logline2\"}, logLines(hook))\n\t})\n\n\tt.Run(\"RestoreConnFromLatestMessage\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\n\t\tstartFilter := func(u url.URL) (start time.Time, err error) {\n\t\t\trawstart, err := strconv.ParseInt(u.Query().Get(\"start\"), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn start, err\n\t\t\t}\n\n\t\t\tstart = time.Unix(0, rawstart)\n\t\t\treturn start, err\n\t\t}\n\n\t\tvar requestsCount uint64\n\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tlogtailHandleFunc(tb, func(conn *websocket.Conn, req *http.Request) {\n\t\t\trequests := atomic.AddUint64(&requestsCount, 1)\n\n\t\t\tstart, err := startFilter(*req.URL)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif requests <= 1 {\n\t\t\t\tt0 := time.Date(2021, time.July, 27, 0, 0, 0, 0, time.UTC).UnixNano()\n\t\t\t\tt1 := time.Date(2021, time.July, 27, 1, 0, 0, 0, time.UTC).UnixNano()\n\t\t\t\tt2 := time.Date(2021, time.July, 27, 2, 0, 0, 0, time.UTC).UnixNano()\n\n\t\t\t\t// send a correct logline so we will able to assert\n\t\t\t\t// that the connection is restored from t2 as expected\n\t\t\t\trawmsg := json.RawMessage(fmt.Sprintf(`{\"streams\":[{\"stream\":{\"key\":\"stream1\",\"level\":\"warn\"},\"values\":[[\"%d\",\"newest logline\"],[\"%d\",\"second logline\"],[\"%d\",\"oldest logline\"]]}],\"dropped_entities\":[]}`, t2, t1, t0))\n\t\t\t\terr = conn.WriteJSON(rawmsg)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t// wait the flush of the message on the network\n\t\t\t\ttime.Sleep(20 * time.Millisecond)\n\n\t\t\t\t// it generates a failure closing the connection\n\t\t\t\t// in a rude way\n\t\t\t\terr = conn.Close()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// assert that the client created the request with `start`\n\t\t\t// populated from the most recent seen value (t2+1ns)\n\t\t\trequire.Equal(t, time.Unix(0, 1627351200000000001), start)\n\n\t\t\t// send a correct logline so we will able to assert\n\t\t\t// that the connection is restored as expected\n\t\t\terr = conn.WriteJSON(json.RawMessage(generateLogline(\"stream3\", 1627358400000000000, \"logline-after-restored-conn\")))\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// wait the flush of the message on the network\n\t\t\ttime.Sleep(20 * time.Millisecond)\n\t\t\tcancel()\n\t\t})\n\n\t\tlogger := logrus.New()\n\t\tlogger.Out = io.Discard\n\t\thook := testutils.NewLogHook()\n\t\tlogger.AddHook(hook)\n\n\t\tc := configFromHTTPMultiBin(tb)\n\t\terr := c.StreamLogsToLogger(ctx, logger, \"ref_id\", 0)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t,\n\t\t\t[]string{\n\t\t\t\t\"newest logline\",\n\t\t\t\t\"second logline\",\n\t\t\t\t\"oldest logline\",\n\t\t\t\t\"error reading a log message from the cloud, trying to establish a fresh connection with the logs service...\",\n\t\t\t\t\"logline-after-restored-conn\",\n\t\t\t}, logLines(hook))\n\t})\n\n\tt.Run(\"RestoreConnFromTimeNow\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\n\t\tstartFilter := func(u url.URL) (start time.Time, err error) {\n\t\t\trawstart, err := strconv.ParseInt(u.Query().Get(\"start\"), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\treturn start, err\n\t\t\t}\n\n\t\t\tstart = time.Unix(0, rawstart)\n\t\t\treturn start, err\n\t\t}\n\n\t\tvar requestsCount uint64\n\t\tt0 := time.Now()\n\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tlogtailHandleFunc(tb, func(conn *websocket.Conn, req *http.Request) {\n\t\t\trequests := atomic.AddUint64(&requestsCount, 1)\n\n\t\t\tstart, err := startFilter(*req.URL)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif requests <= 1 {\n\t\t\t\t// if it's the first attempt then\n\t\t\t\t// it generates a failure closing the connection\n\t\t\t\t// in a rude way\n\t\t\t\terr = conn.Close()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// it asserts that the second attempt\n\t\t\t// has a `start` after the test run\n\t\t\trequire.True(t, start.After(t0))\n\n\t\t\t// send a correct logline so we will able to assert\n\t\t\t// that the connection is restored as expected\n\t\t\terr = conn.WriteJSON(json.RawMessage(`{\"streams\":[{\"stream\":{\"key\":\"stream1\",\"level\":\"warn\"},\"values\":[[\"1598282752000000000\",\"logline-after-restored-conn\"]]}],\"dropped_entities\":[]}`))\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// wait the flush of the message on the network\n\t\t\ttime.Sleep(20 * time.Millisecond)\n\t\t\tcancel()\n\t\t})\n\n\t\tlogger := logrus.New()\n\t\tlogger.Out = io.Discard\n\t\thook := testutils.NewLogHook()\n\t\tlogger.AddHook(hook)\n\n\t\tc := configFromHTTPMultiBin(tb)\n\t\terr := c.StreamLogsToLogger(ctx, logger, \"ref_id\", 0)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t,\n\t\t\t[]string{\n\t\t\t\t\"error reading a log message from the cloud, trying to establish a fresh connection with the logs service...\",\n\t\t\t\t\"logline-after-restored-conn\",\n\t\t\t}, logLines(hook))\n\t})\n}\n"
  },
  {
    "path": "cloudapi/run_status.go",
    "content": "package cloudapi\n\n// RunStatus values are used to tell the cloud output how a local test run\n// ended, and to get that information from the cloud for cloud tests.\ntype RunStatus int\n\n// Possible run status values; iota isn't used intentionally\nconst (\n\tRunStatusCreated            RunStatus = -2\n\tRunStatusValidated          RunStatus = -1\n\tRunStatusQueued             RunStatus = 0\n\tRunStatusInitializing       RunStatus = 1\n\tRunStatusRunning            RunStatus = 2\n\tRunStatusFinished           RunStatus = 3\n\tRunStatusTimedOut           RunStatus = 4\n\tRunStatusAbortedUser        RunStatus = 5\n\tRunStatusAbortedSystem      RunStatus = 6\n\tRunStatusAbortedScriptError RunStatus = 7\n\tRunStatusAbortedThreshold   RunStatus = 8\n\tRunStatusAbortedLimit       RunStatus = 9\n\tRunStatusArchived           RunStatus = 10\n)\n"
  },
  {
    "path": "cloudapi/util.go",
    "content": "package cloudapi\n\n// URLForResults returns the cloud URL with the test run results.\nfunc URLForResults(refID string, config Config) string {\n\tif config.TestRunDetails.Valid {\n\t\treturn config.TestRunDetails.String\n\t}\n\n\treturn config.WebAppURL.String + \"/runs/\" + refID\n}\n"
  },
  {
    "path": "cloudapi/util_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestURLForResults(t *testing.T) {\n\tt.Parallel()\n\n\twebAppURL := \"http://example.com\"\n\ttestRunDetails := \"http://example-new.com\"\n\trefID := \"1234\"\n\n\tconf := Config{\n\t\tWebAppURL: null.NewString(webAppURL, true),\n\t}\n\n\texpected := fmt.Sprintf(\"%s/runs/%s\", webAppURL, refID)\n\trequire.Equal(t, expected, URLForResults(refID, conf))\n\tconf.TestRunDetails = null.NewString(testRunDetails, true)\n\trequire.Equal(t, testRunDetails, URLForResults(refID, conf))\n}\n"
  },
  {
    "path": "cmd/execute.go",
    "content": "// Package cmd is here to provide a way for xk6 to build a binary with added extensions\npackage cmd\n\nimport (\n\t\"context\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\tinternalcmd \"go.k6.io/k6/internal/cmd\"\n)\n\n// Execute executes the k6 command\n// It only is exported here for backwards compatibility and the ability to use xk6 to build extended k6\nfunc Execute() {\n\tgs := state.NewGlobalState(context.Background())\n\n\tinternalcmd.ExecuteWithGlobalState(gs)\n}\n"
  },
  {
    "path": "cmd/state/doc.go",
    "content": "// Package state contains the types and functionality used for keeping track of\n// cmd-related values that are used globally throughout k6. It also exposes some\n// related test types and helpers.\npackage state\n"
  },
  {
    "path": "cmd/state/env.go",
    "content": "package state\n\nimport \"strings\"\n\n// ParseEnvKeyValue splits an environment variable string into key and value.\nfunc ParseEnvKeyValue(kv string) (string, string) {\n\tif idx := strings.IndexRune(kv, '='); idx != -1 {\n\t\treturn kv[:idx], kv[idx+1:]\n\t}\n\treturn kv, \"\"\n}\n\n// BuildEnvMap returns a map from raw environment values, such as returned from\n// os.Environ().\nfunc BuildEnvMap(environ []string) map[string]string {\n\tenv := make(map[string]string, len(environ))\n\tfor _, kv := range environ {\n\t\tk, v := ParseEnvKeyValue(kv)\n\t\tenv[k] = v\n\t}\n\treturn env\n}\n"
  },
  {
    "path": "cmd/state/state.go",
    "content": "package state\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"go.k6.io/k6/lib\"\n\n\t\"github.com/mattn/go-colorable\"\n\t\"github.com/mattn/go-isatty\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/ui/console\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/secretsource\"\n)\n\nconst (\n\t// AutoExtensionResolution defines the environment variable that enables using extensions natively\n\tAutoExtensionResolution = \"K6_AUTO_EXTENSION_RESOLUTION\"\n\n\t// DependenciesManifest defines the default values for dependency resolution\n\tDependenciesManifest = \"K6_DEPENDENCIES_MANIFEST\"\n\n\t// communityExtensionsCatalog defines the catalog for community extensions\n\tcommunityExtensionsCatalog = \"oss\"\n\n\t// defaultBuildServiceURL defines the URL to the default (grafana hosted) build service\n\tdefaultBuildServiceURL = \"https://ingest.k6.io/builder/api/v1\"\n\n\tdefaultConfigFileName = \"config.json\"\n\tdefaultBinaryCacheDir = \"builds\"\n)\n\n// GlobalState contains the GlobalFlags and accessors for most of the global\n// process-external state like CLI arguments, env vars, standard input, output\n// and error, etc. In practice, most of it is normally accessed through the `os`\n// package from the Go stdlib.\n//\n// We group them here so we can prevent direct access to them from the rest of\n// the k6 codebase. This gives us the ability to mock them and have robust and\n// easy-to-write integration-like tests to check the k6 end-to-end behavior in\n// any simulated conditions.\n//\n// `NewGlobalState()` returns a globalState object with the real `os`\n// parameters, while `NewGlobalTestState()` can be used in tests to create\n// simulated environments.\ntype GlobalState struct {\n\tCtx context.Context\n\n\tFS              fsext.Fs\n\tGetwd           func() (string, error)\n\tUserOSConfigDir string\n\tBinaryName      string\n\tCmdArgs         []string\n\tEnv             map[string]string\n\tEvents          *event.System\n\n\tDefaultFlags, Flags GlobalFlags\n\n\tOutMutex       *sync.Mutex\n\tStdout, Stderr *console.Writer\n\tStdin          io.Reader\n\n\tOSExit       func(int)\n\tSignalNotify func(chan<- os.Signal, ...os.Signal)\n\tSignalStop   func(chan<- os.Signal)\n\n\tLogger         *logrus.Logger //nolint:forbidigo //TODO:change to FieldLogger\n\tFallbackLogger logrus.FieldLogger\n\n\tSecretsManager *secretsource.Manager\n\tUsage          *usage.Usage\n\tTestStatus     *lib.TestStatus\n}\n\n// NewGlobalState returns a new GlobalState with the given ctx.\n// Ideally, this should be the only function in the whole codebase where we use\n// global variables and functions from the os package. Anywhere else, things\n// like os.Stdout, os.Stderr, os.Stdin, os.Getenv(), etc. should be removed and\n// the respective properties of globalState used instead.\n//\n//nolint:forbidigo\nfunc NewGlobalState(ctx context.Context) *GlobalState {\n\tisDumbTerm := os.Getenv(\"TERM\") == \"dumb\"\n\tstdoutTTY := !isDumbTerm && (isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()))\n\tstderrTTY := !isDumbTerm && (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd()))\n\toutMutex := &sync.Mutex{}\n\tstdout := &console.Writer{\n\t\tRawOutFd: int(os.Stdout.Fd()), //nolint:gosec\n\t\tMutex:    outMutex,\n\t\tWriter:   colorable.NewColorable(os.Stdout),\n\t\tIsTTY:    stdoutTTY,\n\t}\n\tstderr := &console.Writer{\n\t\tRawOutFd: int(os.Stderr.Fd()), //nolint:gosec\n\t\tMutex:    outMutex,\n\t\tWriter:   colorable.NewColorable(os.Stderr),\n\t\tIsTTY:    stderrTTY,\n\t}\n\n\tconfDir, err := os.UserConfigDir()\n\tif err != nil {\n\t\tconfDir = \".config\"\n\t}\n\n\tcacheDir, err := os.UserCacheDir()\n\tif err != nil {\n\t\tcacheDir = \".cache\"\n\t}\n\n\tbinary, err := os.Executable()\n\tif err != nil {\n\t\tbinary = \"k6\"\n\t}\n\n\tenv := BuildEnvMap(os.Environ())\n\tdefaultFlags := GetDefaultFlags(confDir, cacheDir)\n\tglobalFlags := getFlags(defaultFlags, env, os.Args)\n\n\tlogLevel := logrus.InfoLevel\n\tif globalFlags.Verbose {\n\t\tlogLevel = logrus.DebugLevel\n\t}\n\n\tlogger := &logrus.Logger{\n\t\tOut: stderr,\n\t\tFormatter: &logrus.TextFormatter{\n\t\t\tForceColors:   stderrTTY,\n\t\t\tDisableColors: !stderrTTY || globalFlags.NoColor,\n\t\t},\n\t\tHooks: make(logrus.LevelHooks),\n\t\tLevel: logLevel,\n\t}\n\n\treturn &GlobalState{\n\t\tCtx:             ctx,\n\t\tFS:              fsext.NewOsFs(),\n\t\tGetwd:           os.Getwd,\n\t\tUserOSConfigDir: confDir,\n\t\tBinaryName:      filepath.Base(binary),\n\t\tCmdArgs:         os.Args,\n\t\tEnv:             env,\n\t\tEvents:          event.NewEventSystem(100, logger),\n\t\tDefaultFlags:    defaultFlags,\n\t\tFlags:           globalFlags,\n\t\tOutMutex:        outMutex,\n\t\tStdout:          stdout,\n\t\tStderr:          stderr,\n\t\tStdin:           os.Stdin,\n\t\tOSExit:          os.Exit,\n\t\tSignalNotify:    signal.Notify,\n\t\tSignalStop:      signal.Stop,\n\t\tLogger:          logger,\n\t\tFallbackLogger: &logrus.Logger{ // we may modify the other one\n\t\t\tOut:       stderr,\n\t\t\tFormatter: new(logrus.TextFormatter), // no fancy formatting here\n\t\t\tHooks:     make(logrus.LevelHooks),\n\t\t\tLevel:     logrus.InfoLevel,\n\t\t},\n\t\tUsage:      usage.New(),\n\t\tTestStatus: lib.NewTestStatus(),\n\t}\n}\n\n// GlobalFlags contains global config values that apply for all k6 sub-commands.\ntype GlobalFlags struct {\n\tConfigFilePath   string\n\tQuiet            bool\n\tNoColor          bool\n\tAddress          string\n\tProfilingEnabled bool\n\tLogOutput        string\n\tSecretSource     []string\n\tLogFormat        string\n\tVerbose          bool\n\n\tAutoExtensionResolution   bool\n\tBuildServiceURL           string\n\tBinaryCache               string\n\tEnableCommunityExtensions bool\n\tDependenciesManifest      string\n}\n\n// GetDefaultFlags returns the default global flags.\nfunc GetDefaultFlags(homeDir string, cacheDir string) GlobalFlags {\n\treturn GlobalFlags{\n\t\tAddress:                   \"localhost:6565\",\n\t\tProfilingEnabled:          false,\n\t\tConfigFilePath:            filepath.Join(homeDir, \"k6\", defaultConfigFileName),\n\t\tLogOutput:                 \"stderr\",\n\t\tAutoExtensionResolution:   true,\n\t\tBuildServiceURL:           defaultBuildServiceURL,\n\t\tEnableCommunityExtensions: false,\n\t\tBinaryCache:               filepath.Join(cacheDir, \"k6\", defaultBinaryCacheDir),\n\t}\n}\n\nfunc getFlags(defaultFlags GlobalFlags, env map[string]string, args []string) GlobalFlags {\n\tresult := defaultFlags\n\n\t// TODO: add env vars for the rest of the values (after adjusting\n\t// rootCmdPersistentFlagSet(), of course)\n\n\tif val, ok := env[\"K6_CONFIG\"]; ok {\n\t\tresult.ConfigFilePath = val\n\t}\n\tif val, ok := env[\"K6_LOG_OUTPUT\"]; ok {\n\t\tresult.LogOutput = val\n\t}\n\tif val, ok := env[\"K6_LOG_FORMAT\"]; ok {\n\t\tresult.LogFormat = val\n\t}\n\tif env[\"K6_NO_COLOR\"] != \"\" {\n\t\tresult.NoColor = true\n\t}\n\t// Support https://no-color.org/, even an empty value should disable the\n\t// color output from k6.\n\tif _, ok := env[\"NO_COLOR\"]; ok {\n\t\tresult.NoColor = true\n\t}\n\tif _, ok := env[\"K6_PROFILING_ENABLED\"]; ok {\n\t\tresult.ProfilingEnabled = true\n\t}\n\t//  old name for the K6_AUTO_EXTENSION_RESOLUTION feature flag\n\t//  maintained for backward compatibility to be removed in a future release\n\tif v, ok := env[\"K6_BINARY_PROVISIONING\"]; ok {\n\t\tvb, err := strconv.ParseBool(v)\n\t\tif err == nil {\n\t\t\tresult.AutoExtensionResolution = vb\n\t\t}\n\t}\n\tif v, ok := env[\"K6_AUTO_EXTENSION_RESOLUTION\"]; ok {\n\t\tvb, err := strconv.ParseBool(v)\n\t\tif err == nil {\n\t\t\tresult.AutoExtensionResolution = vb\n\t\t}\n\t}\n\tif val, ok := env[\"K6_BUILD_SERVICE_URL\"]; ok {\n\t\tresult.BuildServiceURL = val\n\t}\n\tif v, ok := env[\"K6_ENABLE_COMMUNITY_EXTENSIONS\"]; ok {\n\t\tvb, err := strconv.ParseBool(v)\n\t\tif err == nil {\n\t\t\tresult.EnableCommunityExtensions = vb\n\t\t}\n\t}\n\tif val, ok := env[\"K6_DEPENDENCIES_MANIFEST\"]; ok {\n\t\tresult.DependenciesManifest = val\n\t}\n\n\t// adjust BuildServiceURL if community extensions are enable\n\t// community extensions flag only takes effect if the default build service is used\n\t// for custom build service URLs it has no effect (because the /oss path may not be implemented)\n\tif result.EnableCommunityExtensions && result.BuildServiceURL == defaultBuildServiceURL {\n\t\tresult.BuildServiceURL = fmt.Sprintf(\"%s/%s\", defaultBuildServiceURL, communityExtensionsCatalog)\n\t}\n\n\tif val, ok := env[\"K6_SECRET_SOURCE\"]; ok {\n\t\tresult.SecretSource = []string{val}\n\t}\n\n\t// check if verbose flag is set\n\tif slices.Contains(args, \"-v\") || slices.Contains(args, \"--verbose\") {\n\t\tresult.Verbose = true\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "cmd/tests/global_state.go",
    "content": "// Package tests contains types needed for running integration tests that run k6 commands.\npackage tests\n\nimport (\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/cmd/tests\"\n)\n\n// GlobalTestState is a wrapper around GlobalState for use in tests.\ntype GlobalTestState = tests.GlobalTestState\n\n// NewGlobalTestState returns an initialized GlobalTestState, mocking all\n// GlobalState fields for use in tests.\nfunc NewGlobalTestState(tb testing.TB) *GlobalTestState {\n\treturn tests.NewGlobalTestState(tb)\n}\n"
  },
  {
    "path": "docs/design/018-new-http-api.md",
    "content": "# New HTTP API\n\n## Authors\nThe k6 core team\n\n## Why is this needed?\n\nThe HTTP API (in k6 <=v0.43.0) used by k6 scripts has many limitations, inconsistencies and performance issues, that lead to a poor user experience. Considering that it's the most commonly used JS API, improving it would benefit most k6 users.\n\nThe list of issues with the current API is too long to mention in this document, but you can see a detailed list of [GitHub issues labeled `new-http`](https://github.com/grafana/k6/issues?q=is%3Aopen+is%3Aissue+label%3Anew-http) that should be fixed by this proposal, as well as the [epic issue #2461](https://github.com/grafana/k6/issues/2461). Here we'll only mention the relatively more significant ones:\n\n* [#2311](https://github.com/grafana/k6/issues/2311): files being uploaded are copied several times in memory, causing more memory usage than necessary. Related issue: [#1931](https://github.com/grafana/k6/issues/1931)\n* [#857](https://github.com/grafana/k6/issues/857), [#1045](https://github.com/grafana/k6/issues/1045): it's not possible to configure transport options, such as proxies or DNS, per VU or group of requests.\n* [#761](https://github.com/grafana/k6/issues/761): specifying configuration options globally is not supported out-of-the-box, and workarounds like the [httpx library](https://k6.io/docs/javascript-api/jslib/httpx/) are required.\n* [#746](https://github.com/grafana/k6/issues/746): async functionality like Server-sent Events is not supported.\n* Related to the previous point, all (except asyncRequest) current methods are synchronous, which is inflexible, and doesn't align with modern APIs from other JS runtimes.\n* [#436](https://github.com/grafana/k6/issues/436): the current API is not very friendly or ergonomic. Different methods also have parameters that change places, e.g. `params` is the second argument in `http.get()`, but the third one in `http.post()`.\n\n\n## Proposed solution(s)\n\n### Design\n\nHTTP is an application-layer protocol that is built upon lower level transport protocols, such as TCP, UDP, or local IPC mechanisms in most operating systems. It's also closely related to the DNS protocol, which all browsers use when resolving a host name before establishing an HTTP connection. As such, we can't implement a flexible and modern HTTP API without exposing APIs for these lower level protocols. In fact, some user requested functionality would be difficult, if not impossible, without access to these APIs (e.g. issues [#1393](https://github.com/grafana/k6/issues/1393), [#1098](https://github.com/grafana/k6/issues/1098), [#2510](https://github.com/grafana/k6/issues/2510), [#857](https://github.com/grafana/k6/issues/857), [#2366](https://github.com/grafana/k6/issues/2366)).\n\nIn this sense, we propose designing the HTTP API in such a way that it's built _on top_ of these lower level APIs. By making our networking namespace composable in this way, we open the door for other application-layer protocols to be implemented using the same low level primitives. For example, WebSockets could be implemented on top of the TCP API, gRPC on top of the HTTP/2 API, and so on.\n\nThis approach also follows other modern JavaScript runtimes such as Node and Deno, which ensures we're building a familiar and extensible API, instead of a purpose-built library just for HTTP and unique to k6.\n\n\nWith that said, the design of the API should follow these guidelines:\n\n- It should be familiar to users of HTTP APIs from other JS runtimes, and easy for new users to pick up.\n\n  As such, it would serve us well to draw inspiration from existing runtimes and frameworks. Particularly:\n\n  - The [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), a [WHATWG standard](https://fetch.spec.whatwg.org/) supported by most modern browsers.\n    [Deno's implementation](https://deno.land/manual/examples/fetch_data) and [GitHub's polyfill](https://github.com/github/fetch) are good references to follow.\n\n    This was already suggested in [issue #2424](https://github.com/grafana/k6/issues/2424).\n\n  - The [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API), a [WHATWG standard](https://streams.spec.whatwg.org/) supported by most modern browsers.\n    [Deno's implementation](https://deno.land/manual@v1.30.3/examples/fetch_data#files-and-streams) is a good reference to follow.\n\n    The work to implement it is tracked in [issue #2978](https://github.com/grafana/k6/issues/2978).\n\n    Streaming files both from disk to RAM to the network, and from network to RAM and possibly disk, would also partly solve our [performance and memory issues with loading large files](https://github.com/grafana/k6/issues/2311).\n\n  - Native support for the [`FormData` API](https://developer.mozilla.org/en-US/docs/Web/API/FormData).\n\n    Currently this is supported with a [JS polyfill](https://k6.io/docs/examples/data-uploads/#advanced-multipart-request), which should be deprecated.\n\n  - Aborting requests or any other async process with the [`AbortSignal`/`AbortController` API](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal), part of the [WHATWG DOM standard](https://dom.spec.whatwg.org/#aborting-ongoing-activities).\n\n    This is slightly out of scope for the initial phases of implementation, but aborting async processes like `fetch()` is an important feature.\n\n- The Fetch API alone would not address all our requirements (e.g. specifying global and transport options), so we still need more flexible and composable interfaces.\n\n  One source of inspiration is the Go `net/http` package, which the k6 team is already familiar with. Based on this, our JS API could have similar entities:\n\n  - `Dialer`: a low-level interface for configuring TCP/IP options, such as TCP timeout and keep-alive, TLS settings, DNS resolution, IP version preference, etc.\n\n  - `Transport`: interface for configuring HTTP connection options, such as proxies, HTTP version preferences, etc.\n\n    It enables advanced behaviors like intercepting requests before they're sent to the server.\n\n  - `Client`: the main entrypoint for making requests, it encompasses all of the above options. A k6 script should be able to initialize more than one `Client`, each with their separate configuration.\n\n    In order to simplify the API, the creation of a `Client` should use sane defaults for `Dialer` and `Transport`.\n\n  There should be some research into existing JS APIs that offer similar features (e.g. Node/Deno), as we want to offer an API familiar to JS developers, not necessarily Go developers.\n\n  - `Request`/`Response`: represent objects sent by the client, and received from the server. In contrast to the current API, the k6 script should be able to construct `Request` objects declaratively, and then reuse them to make multiple requests with the same (or similar) data.\n\n- All methods that perform I/O calls must be asynchronous. Now that we have `Promise`, event loop and `async`/`await` support natively in k6, there's no reason for these to be synchronous anymore.\n\n- The API should avoid any automagic behavior. That is, it should not attempt to infer desired behavior or options based on some implicit value.\n\n  We've historically had many issues with this ([#878](https://github.com/grafana/k6/issues/878), [#1185](https://github.com/grafana/k6/issues/1185)), resulting in confusion for users, and we want to avoid it in the new API. Even though we want to have sane defaults for most behavior, instead of guessing what the user wants, all behavior should be explicitly configured by the user. In cases where some behavior is ambiguous, the API should raise an error indicating so.\n\n\n#### Sockets\n\nA Socket represents the file or network socket over which client/server or peer communication happens.\n\nIt can be of three types:\n- `tcp`: a stream-oriented network socket using the Transmission Control Protocol.\n- `udp`: a message-oriented network socket using the User Datagram Protocol.\n- `ipc`: a mechanism for communicating between processes on the same machine, typically using files.\n\nThe Socket state can either be _active_—meaning connected for a TCP socket, bound for a UDP socket, or open for an IPC socket—, or _inactive_—meaning disconnected, unbound, or closed, respectively.\n\n##### Example\n\n- TCP:\n```javascript\nimport { TCP } from 'k6/x/net';\n\nexport default async function () {\n  const socket = await TCP.open('192.168.1.1:80', {\n                            // default      | possible values\n    ipVersion: 0,           // 0            | 4 (IPv4), 6 (IPv6), 0 (both)\n    keepAlive: true,        // false        |\n    lookup: null,           // dns.lookup() |\n    proxy: 'myproxy:3030',  // ''           |\n  });\n  console.log(socket.active); // true\n\n  // Writing directly to the socket.\n  // Requires TextEncoder implementation, otherwise typed arrays can be used as well.\n  await socket.write(new TextEncoder().encode('GET / HTTP/1.1\\r\\n\\r\\n'));\n\n  // And reading...\n  socket.on('data', data => {\n    console.log(`received ${data}`);\n    socket.close();\n  });\n\n  await socket.done();\n}\n```\n\n- UDP:\n```javascript\nimport { UDP } from 'k6/x/net';\n\nexport default async function () {\n  const socket = await UDP.open('192.168.1.1:9090');\n  await socket.write(new TextEncoder().encode('GET / HTTP/1.1\\r\\n\\r\\n'));\n  socket.close();\n}\n```\n\n- IPC:\n```javascript\nimport { IPC } from 'k6/x/net';\nimport { Client } from 'k6/x/net/http';\n\nexport default async function () {\n  // The HTTP client supports communicating over a Unix socket.\n  const client = new Client({\n    dial: async () => {\n      return await IPC.open('/tmp/unix.sock');\n    },\n  });\n  await client.get('http://unix/get');\n\n  console.log(client.socket.file.path); // /tmp/unix.sock\n\n  client.socket.close();\n}\n```\n\n#### Client\n\nAn HTTP Client is used to communicate with an HTTP server.\n\n##### Examples\n\n- Using a client with default transport settings, and making a GET request:\n```javascript\nimport { Client } from 'k6/x/net/http';\n\nexport default async function () {\n  const client = new Client();\n  const response = await client.get('https://httpbin.test.k6.io/get');\n  const jsonData = await response.json();\n  console.log(jsonData);\n}\n```\n\n- Creating a client with custom transport settings, some HTTP options, and making a POST request:\n```javascript\nimport { TCP } from 'k6/x/net';\nimport { Client } from 'k6/x/net/http';\n\nexport default async function () {\n  const client = new Client({\n    dial: async address => {\n      return await TCP.open(address, { keepAlive: true });\n    },\n    proxy: 'https://myproxy',\n    headers: { 'User-Agent': 'k6' },  // set some global headers\n  });\n  await client.post('http://10.0.0.10/post', {\n    json: { name: 'k6' }, // automatically adds 'Content-Type: application/json' header\n  });\n}\n```\n\n- Configuring TLS with a custom CA certificate and forcing HTTP/2:\n```javascript\nimport { TCP } from 'k6/x/net';\nimport { Client } from 'k6/x/net/http';\nimport { open } from 'k6/x/file';\n\nconst caCert = await open('./custom_cacert.pem');\n\nexport default async function () {\n  const client = new Client({\n    dial: async address => {\n      return await TCP.open(address, {\n        tls: {\n          alpn: ['h2'],\n          caCerts: [caCert],\n        }\n      });\n    },\n  });\n  await client.get('https://10.0.0.10/');\n}\n```\n\n- Forcing unencrypted HTTP/2 (h2c):\n```javascript\nimport { TCP } from 'k6/x/net';\nimport { Client } from 'k6/x/net/http';\n\nexport default async function () {\n  const client = new Client({\n    dial: async address => {\n      return await TCP.open(address, { tls: false });\n    },\n    version: [2],\n  });\n  await client.get('http://10.0.0.10/');\n```\n\n\n#### Host name resolution\n\nHost names can be resolved to IP addresses in several ways:\n\n- Via a static lookup map defined in the script.\n- Via the operating system's facilities (`/etc/hosts`, `/etc/resolv.conf`, etc.).\n- By querying specific DNS servers.\n\nWhen connecting to an address using a host name, the resolution can be controlled via the `lookup` function passed to the socket constructor. By default, the mechanism provided by the operating system is used (`dns.lookup()`).\n\nFor example:\n```javascript\nimport { TCP } from 'k6/x/net';\nimport dns from 'k6/x/net/dns';\n\nconst hosts = {\n  'hostA': '10.0.0.10',\n  'hostB': '10.0.0.11',\n};\n\nexport default async function () {\n  const socket = await TCP.open('myhost', {\n    lookup: async hostname => {\n      // Return either the IP from the static map, or do an OS lookup,\n      // or fallback to making a DNS query to specific servers.\n      return hosts[hostname] || await dns.lookup(hostname) ||\n        await dns.resolve(hostname, {\n          rrtype: 'A',\n          servers: ['1.1.1.1:53', '8.8.8.8:53'],\n        });\n    },\n  });\n}\n```\n\n#### Requests and responses\n\nHTTP requests can be created declaratively, and sent only when needed. This allows reusing request data to send many similar requests.\n\nFor example:\n```javascript\nimport { Client, Request } from 'k6/x/net/http';\n\nexport default async function () {\n  const client = new Client({\n    headers: { 'User-Agent': 'k6' },  // set some global headers\n  });\n  const request = new Request('https://httpbin.test.k6.io/get', {\n    // These will be merged with the Client options.\n    headers: { 'Case-Sensitive-Header': 'somevalue' },\n  });\n  const response = await client.get(request, {\n    // These will override any options for this specific submission.\n    headers: { 'Case-Sensitive-Header': 'anothervalue' },\n  });\n  const jsonData = await response.json();\n  console.log(jsonData);\n}\n```\n\n\n#### Data streaming\n\nThe [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) allows streaming data that is received or sent over the network, or read from or written to the local filesystem. This enables more efficient usage of memory, as only chunks of it need to be allocated at once.\n\nThis is a separate project from the HTTP API, tracked in [issue #2978](https://github.com/grafana/k6/issues/2978), and involves changes in other parts of k6. Certain HTTP API functionality, however, depends on this API being available.\n\nAn example inspired by [Deno](https://deno.land/manual/examples/fetch_data#files-and-streams) of how this might work in k6:\n```javascript\nimport { open } from 'k6/x/file';\nimport { Client } from 'k6/x/net/http';\n\n// Will need supporting await in init context\nconst file = await open('./logo.svg');  // by default assumes 'read'\n\nexport default async function () {\n  const client = new Client();\n  await client.post('https://httpbin.test.k6.io/post', { body: file.readable });\n}\n```\n\n\n#### Fetch API\n\nThe [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) is a convenience wrapper over existing Client, Socket and other low-level interfaces, with the benefit of being easy to use, and having sane defaults. It's a quick way to fire off some HTTP requests and get some responses, without worrying about advanced configuration.\n\nThe implementation in k6 differs slightly from the web API, but we've tried to make it familiar to use wherever possible.\n\nExample:\n```javascript\nimport { fetch } from 'k6/x/net/http';\n\nexport default async function () {\n  await fetch('https://httpbin.test.k6.io/get');\n  await fetch('https://httpbin.test.k6.io/post', {\n    // Supports the same options as Client.request()\n    method: 'POST',\n    headers: { 'User-Agent': 'k6' },\n    json: { name: 'k6' },\n  });\n}\n```\n\n#### Events\n\nThe new HTTP API will emit events which scripts can subscribe to, in order to implement advanced functionality.\n\nFor example, a `requestToBeSent` event is emitted when the request was processed by k6, and just before it is sent to the server. This allows changing the request body or headers, or introducing artificial delays.\n\n```javascript\nimport { Client } from 'k6/x/net/http';\n\nexport default async function () {\n  const client = new Client();\n  client.on('requestToBeSent', event => {\n    console.log(event.type);    // 'requestToBeSent'\n    const request = event.data;\n    request.headers['Cookie'] = 'somecookie=somevalue;'  // overwrites all previously set cookies\n    request.body += ' world!';  // the final body will be 'Hello world!'\n  });\n\n  await client.post('https://httpbin.test.k6.io/post', { body: 'Hello' });\n}\n```\n\nSimilarly, a `responseReceived` event is emitted when a response is received from the server, but before it's been fully processed by k6. This can be useful to alter the response in some way, or edit the metrics emitted by k6.\n\nFor example:\n\n```javascript\nimport { Client } from 'k6/x/net/http';\n\nexport default async function () {\n  const client = new Client();\n  let requestID;  // used to correlate a specific response with the request that initiated it\n\n  client.on('requestToBeSent', event => {\n    const request = event.data;\n    if (!requestID && request.url == 'https://httpbin.test.k6.io/get?name=k6'\n        && request.method == 'GET') {\n      // The request ID is a UUIDv4 string that uniquely identifies a single request.\n      // This is a contrived check and example, but you can imagine that in a complex\n      // script there would be many similar requests.\n      requestID = request.id;\n    }\n  });\n\n  client.on('responseReceived', event => {\n    const response = event.data;\n    if (requestID && response.request.id == requestID) {\n      // Change the request duration metric to any value\n      response.metrics['http_req_duration'].value = 3.1415;\n      // Consider the request successful regardless of its response\n      response.metrics['http_req_failed'].value = false;\n      // Or drop a single metric\n      delete response.metrics['http_req_duration'];\n      // Or drop all metrics\n      response.metrics = {};\n    }\n  });\n\n  await client.get('https://httpbin.test.k6.io/get', { query: { name: 'k6' } });\n}\n```\n\nEvent handlers can also be attached directly to a single request/response cycle. This avoids having to correlate responses with requests as done above.\n\n```javascript\nimport { Client } from 'k6/x/net/http';\n\nexport default async function () {\n  const client = new Client();\n  await client.get('https://httpbin.test.k6.io/get', {\n    eventHandlers: {\n      'responseReceived': event => {\n        const response = event.data;\n        // ...\n      }\n    }\n  });\n}\n```\n\n**TODO**: List other possible event types, and their use cases.\n\n\n### Implementation\n\nTrying to solve all `new-http` issues with a single large and glorious change wouldn't be reasonable, so improvements will undoubtedly need to be done gradually, in several phases, and over several k6 development cycles.\n\nNote that the implementation process described below is not finalized, and will go through several changes during development.\n\nWith this in mind, we propose the following phases:\n\n#### Phase 1: create initial k6 extension\n\n**Goals**:\n\n- Implement a barebones async API that serves as a proof-of-concept for what the final developer experience will look and feel like.\n\n  By barebones, we mean that there must be a `Client` interface with only one method: `request()`, which will work similarly to the current `http.asyncRequest()`. Only `GET` and `POST` methods must be supported.\n\n  The code must be in a state that allows it to be easily extended. Take into account the other design goals of this document, even if they're not ready to be implemented.\n\n- This initial API must solve at least one minor, but concrete, issue of the current API. It should fix something that's currently not possible and doesn't have a good workaround.\n\n  Addressing [#761](https://github.com/grafana/k6/issues/761) would be a good first step.\n\n  As an optional stretch goal, once we settle on the API to configure the transport layer, [#936](https://github.com/grafana/k6/issues/936) and [#970](https://github.com/grafana/k6/issues/970) are good issues to tackle next.\n\n\n**Non-goals**:\n\n- We won't yet try to solve performance/memory issues of the current API, or implement major new features like data streaming.\n\n\n#### Phase 2: work on major issues, merge into k6 core as experimental module\n\n**Goals**:\n\n- Work should be started on some of the most impactful issues from the current API.\n  Issues like high memory usage when uploading files ([#2311](https://github.com/grafana/k6/issues/2311)), and data streaming ([#592](https://github.com/grafana/k6/issues/592)), are good candidates to focus on first.\n\n- At the end of this phase the API should resolve major limitations of `k6/http`, and it would be a good time to merge it into k6 core as an experimental module (`k6/experimental/net/http`).\n  This would make it available to more users, including in the k6 Cloud.\n\n\n#### Phase 3: work on leftover issues\n\n**Goals**:\n\n- All leftover `new-http` issues should be worked on in this phase.\n  **TODO**: Specify which issues and in what order should be worked on here.\n\n- The extension should be thoroughly tested, by both internal and external users.\n\n\n#### Phase 4: expand, polish and stabilize the API\n\n**Goals**:\n\n- The API should be expanded to include all HTTP methods supported by the current API.\n  For the most part, it should reach feature parity with the current API.\n\n- A standalone `fetch()` function should be added that resembles the web Fetch API. There will be some differences in the options compared to the web API, as we want to make parts of the transport/client configurable.\n\n    Internally, this function will create a new client (or reuse a global one?), and will simply act as a convenience wrapper over the underlying `Client`/`Dialer`/`Transport` implementations, which will be initialized with sane default values.\n\n- Towards the end of this phase, the API should be mostly stable, based on community feedback.\n  Small changes will be inevitable, but there should be no discussion about the overall design.\n\n\n#### Phase 5: more testing, deprecating old API\n\nAt this point the extension should be relatively featureful and stable to be useful to all k6 users.\n\n**Goals**:\n\n- Continue to gather and address feedback from users, thorough testing and polishing.\n\n- As the final step, we should add deprecation warnings when `k6/http` is used, and point users to the new API. We can also consider promoting the API from experimental to a main module under `k6/net/http`.\n  We'll have to maintain both `k6/http` and `k6/net/http` for likely years to come, though any new development will happen in `k6/net/http`, and `k6/http` would only receive bug and security fixes.\n\n\n## Potential risks\n\n* Long implementation time.\n\n  Not so much of a risk, but more of a necessary side-effect of spreading the work in phases, and over several development cycles. We need this approach in order to have ample time for community feedback, to implement any unplanned features, and to make sure the new API fixes all existing issues.\n  Given this, it's likely that the entire process will take many months, possibly more than a year to finalize.\n\n\n## Technical decisions\n\nTBD after team discussion. In the meantime, see the \"Proposed solution(s)\" section.\n"
  },
  {
    "path": "docs/design/019-file-api.md",
    "content": "# Introduce a File API module for k6\n\n|                      |                                                                                                                                                                                                           |\n| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **author**           | @oleiade                                                                                                                                                                                                  |\n| **status**           | 🔧 proposal                                                                                                                                                                                              |\n| **revisions**        | [previous](https://github.com/grafana/k6/pull/3101/commits/e2b8ddad40d013b56789cb4c89dd8f9c338f42d4), [initial](https://github.com/grafana/k6/pull/3101/commits/0669d16e76791241b75a2622729327880cd814e2) |\n| **Proof of concept** | [branch](https://github.com/grafana/k6/tree/poc/experimental/fs-module/js/modules/k6/experimental/fs)                                                                                                     |\n| **references**       | [#2977](https://github.com/grafana/k6/issues/2977) [#2974](https://github.com/grafana/k6/issues/2974)                                                                                                   |\n\n## Problem definition\n\nThe current version of k6 lets users load file content via [the `open` function](https://k6.io/docs/javascript-api/init-context/open/), which is only accessible in the init context. However, the `open` function diverges from its counterparts in other languages and the Linux stack as it reads the whole file into memory rather than opening it for further interaction. This process leads to considerable memory consumption when loading large binary files (as the content ends up copied in each VUs) or when the `SharedArray` cannot be used.\n\nIn line with [our commitment to optimize large file handling in k6](https://github.com/grafana/k6/issues/2974), we propose introducing a new `fs` module. This module is intended to offer an intuitive and user-friendly API for file interactions within k6 scripts. We'll also provide some ideas for efficient file handling to minimize memory consumption during k6 execution.\n\n### Context\n\nCurrently, files cannot be opened from within a function executed by a VU, only in the init context.\n\nThis is due to k6's design for distributed execution, particularly in the cloud. K6 runs the init context once, gathers resources, including files, and sends them to other instances where VU code runs.\n\n### Requirements\n\n- The solution must be native to k6, with the code being in the k6 repository and maintained by the k6 OSS team.\n- The solution must use asynchronous operations.\n- The solution restricts opening files in the init context only.\n- The solution allows read-only operations on files in the init context and the vu, setup and teardown stages.\n- The solution must provide support for reading text and binary files.\n- The solution must support local and cloud execution seamlessly.\n- The solution must provide substantial improvements to memory usage, compared to using the current `open()` function.\n- The solution's API should be intuitive and hard to misuse for users familiar with filesystem APIs from other languages and technologies.\n\n### Scope\n\n#### In scope\n- The proposed solution will offer an alternative to the existing `open` function.\n- The solution will provide a File concept that supports read-only operations: reading file chunks into a buffer, reading the entire file content, and file seeking.\n- The proposal could suggest changes to improve overall memory usage in k6 scripts.\n\n#### Out of scope\n- This proposal doesn't aim to solve memory consumption issues when using file content in HTTP requests, although minor improvements might be suggested.\n- Changes to how k6 gathers resources, particularly files, are out of scope (ideas are proposed in the \"Future Improvements\" section).\n- Despite the proposed API's potential to support them, write operations are beyond this proposal's scope:\n  - The scope of this proposal is to be a drop-in replacement for the current `open` function.\n  - The support of write operations would require substantial implementation effort and is out of the scope of this proposal.\n  - There is no immediate need for k6 to support write operations on files.\n\n## Proposed solution\n\nWe suggest implementing a minimalist, experimental file system (`fs`) module based on [Deno's fs module](https://deno.land/api@v1.32.3?s=Deno.open). The new module will allow users to interact with files, separating text and binary files. The module will provide an `open` function that returns a file handle/view for performing read operations.\n\nThe initial API will mostly be asynchronous, except for the `open` functionality which will be synchronous due to the current lack of support for `await` operations within the init context.\n\nThe API will have the following characteristics:\n- Load file content exactly once into memory.\n- As opening files is restricted to the init context, each VU receives a copy of each unique file handle, pointing to a unique memory area to avoid copying the whole buffer for each VU.\n- Ensure each file handle has unique offsets allowing each VU to work independently.\n\nA working [proof of concept](https://github.com/grafana/k6/tree/poc/experimental/fs-module/js/modules/k6/experimental/fs) of the new API is available on GitHub.\n\n### Proposed API:\n\n```typescript\n/*\n * openSync opens a file and returns an instance of a\n * `File`.\n */\nopenSync(path: string): File\n\n/*\n * open opens a file and resolves to an instance of a\n * `File`.\n *\n * Because the k6 init context does not support using await yet,\n * to use this function, users must use a workaround:\n *\n * ```\n * let f;\n * (async function() {\n *   f = await asyncOpen(\"./somefile\"); // name for emphasis not as a proposal\n * }());\n * ```\n */\nopen(path: string): Promise<File>\n\n/*\n * File is an abstraction to interact with\n * files which exposes read-only operations.\n */\ninterface File {\n    /*\n     * read reads the file into an array buffer.\n     * resolves to either the number of bytes read during the operation\n     * or `null` if there was nothing to read.\n     */\n\tread(p ArrayBuffer | TypedArray | DataView): Promise<number>\n\n\t/*\n\t * readAll reads the whole content of the file and\n\t * returns a promise that will resolve to its content\n\t * as an `ArrayBuffer`.\n\t */\n\treadAll(): Promise<ArrayBuffer>\n\n\t/*\n\t * Seek to the given `offset` under mode given by `whence`.\n\t * The call resolves to the new position within the resource\n\t * (bytes from the start).\n\t */\n\tseek(offset: number, whence: SeekMode): Promise<number>\n\n\t/*\n\t * Resolves to a `FileInfo` describing the file.\n\t */\n\tstat(): Promise<FileInfo>\n\n    /*\n     * close closes the file.\n     */\n    close(): Promise<void>\n}\n\n/*\n * FileInfo provides information about a file.\n */\ninterface FileInfo {\n\t/*\n\t * the filename of the file\n\t */\n\tname: string\n\n\t/*\n\t * the size of the file, in bytes.\n\t */\n\tsize: number\n}\n```\n\n**N.B**: the `File` operations only support working with `ArrayBuffer` as of this proposal. This is based on the assumption we could somewhat easily add `TextDecoder` support to k6 (see comments [#2291](https://github.com/grafana/k6/issues/2291) and [#2440](https://github.com/grafana/k6/issues/2440)). If this assumption was to be invalidated, we could adopt the same API format and have two different read-operation variants on the File, or even expose two different kinds of files `TextFileHandle` and `BinaryFileHandle` for instance.\n\n## Example usage\n\n```javascript\nimport { openSync, SeekMode } from 'k6/experimental/fs';\n\nexport const options = {\n    scenarios: {\n      default: {\n        executor: 'constant-vus',\n        vus: 100,\n        duration: '1m',\n      },\n    },\n};\n\nconst file = openSync(\"./data.csv\");\n\nexport default async function () {\n    let resultString = \"\"\n\n    let buffer = new Uint8Array(10);\n    let n = await file.read(buffer);\n    resultString += ab2str(buffer)\n\n    // Read the same data again\n    n = await file.read(buffer);\n    resultString += ab2str(buffer)\n\n    // Read the same data again\n    n = await file.read(buffer);\n    resultString += ab2str(buffer)\n\n    await file.seek(0, SeekMode.Start);\n\n    console.log(`[vu ${__VU}] resultString: ${resultString}`);\n}\n\nexport default function teardown() {\n    file.close();\n}\n\nfunction ab2str(buf) {\n    return String.fromCharCode.apply(null, new Uint16Array(buf));\n}\n```\n\n### Implementation details\n\nThe proposed API is made feasible through the following implementation aspects:\n\n-   A file's content is loaded into memory only once:\n    -   When a file is opened, its content is buffered at the module's root in a dedicated registry, returning a handle with a pointer to that buffer.\n    -   Each VU receives a copy of the file handle, enabling them to interact with files using the unique memory area linked to the handle, instead of each receiving a full copy of the buffer.\n    - As each invocation of `open*` receives a unique file handle linked to the same memory area, they each have unique offsets. This setup allows each VU to process file data independently without conflict or race conditions.\n\n### Possible future improvements\n\n#### Introduce stream support\n\nThe Deno API's `FsFile` our proposal is inspired by exposes a `readable` read-only property which is a [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) `ReadableStream` allowing to stream the content of the file. We have an open issue tracking the implementation of the Streams API in k6 [#2978](https://github.com/grafana/k6/issues/2978).\n\n#### Enable file opening within VU context\n\nSee [#3020](https://github.com/grafana/k6/issues/3020)\n\nThis is currently unachievable because we must anticipate which files will be opened. While some quick fixes might appear feasible (e.g., parsing the AST before execution to identify files), they quickly fall apart: What if the filename resides in a variable? A plausible solution would involve requiring users to declare necessary resources (files/folders) ahead of time. This approach would ensure these resources are captured and included in the archive for future VU code access.\n\n## Conclusion\n\nWe believe the [proof of concept](https://github.com/grafana/k6/tree/poc/experimental/fs-module/js/modules/k6/experimental/fs) developed with this proposal illustrates the feasibility and benefits of developing such an API.\n"
  },
  {
    "path": "docs/design/020-distributed-execution-and-test-suites.md",
    "content": "# Distributed Execution\n\nNative distributed execution https://github.com/grafana/k6/issues/140 is simultaneously the oldest and still open k6 issue (opened on Mar 7th 2017, over 6 years ago! :scream:) and [the most upvoted issue ever](https://github.com/grafana/k6/issues?q=is%3Aissue+sort%3Areactions-%2B1-desc), open or closed! It currently has 93 :+1:, which is almost 3 times the upvote count of the next issues after it... And all of that is despite the fact that [Grafana Cloud k6](https://grafana.com/products/cloud/k6/) and [k6-operator](https://github.com/grafana/k6-operator) already allow some kinds of distributed k6 execution!\n\nThis document aims to explain some of the historical steps we have made in this direction, some of the context and reasons why it was complicated to implement this before, and a proposal for how we can finally implement it nicely now :tada: :crossed_fingers:\n\n### What is Native distributed execution?\n\nRun a single k6 test-run across several instances and/or machines. Ideally, having the same and consistent user experience that k6 provides running on a single instance. \n\n### Why?\n\n>There are at least a couple of reasons why you would want to do this:\n>\n>- You run everything else in Kubernetes, or any other kind of similar infrastructure, and would like k6 to be executed in the same fashion as all your other infrastructure components.\n>- You want to run your tests within your private network for security and/or privacy reasons.\n\nhttps://grafana.com/blog/2022/06/23/running-distributed-load-tests-on-kubernetes\n\n## Context\n\n### Ancient History :t-rex:\n\nAt the dawn of time, before [k6 v0.27.0](https://github.com/grafana/k6/releases/tag/v0.27.0) and the infamous [#1007](https://github.com/grafana/k6/pull/1007), test execution in k6 happened somewhat weirdly. Chief among other weird things, there were two distinct test execution paths and that caused a lot of problems.\n\nThe first execution path was used for regular `k6 run script.js` local test runs. When using it, k6 basically adjusted the number of currently looping VUs once every millisecond to be whatever they were supposed to be at that moment. In essence, it adjusted the active VU count based on the current test run time and the value of the `stages` option. However, when using the second execution path, the k6 process suspended its own \"judgement\" and just listened for external instructions via its REST API to \"know\" how many VUs were supposed to be looping at any given moment.\n\nThis second execution path is how distributed cloud execution happened before: a central testcoordinator process calculated how many VUs were supposed to be running on every k6 instance and it sent instructions to all of them once every second to adjust their VUs to the correct number. This architecture caused a bunch of problems (e.g. minor network problems or delays caused serious issues, semi-duplicate code paths caused subtle bugs and slightly different behaviors between local and cloud execution, etc., etc.), but it was a reasonably serviceable solution for the time.\n\nHowever, it would have been nearly impossible to adapt that architecture to nicely support multiple [scenarios](https://k6.io/docs/using-k6/scenarios/) with different [executors](https://k6.io/docs/using-k6/scenarios/executors/), [arrival-rate executors especially](https://k6.io/docs/using-k6/scenarios/concepts/open-vs-closed/), as well as scenario options like [`gracefulStop` and `gracefulRampDown`](https://k6.io/docs/using-k6/scenarios/concepts/graceful-stop/). Due to issues like the variability and unpredictability of script iteration durations, a central testcoordinator node would not have had enough information to adequately control the various instances without a lot more bi-directional communication between it and the instances. Even if we ignore the hellish complexity of such an approach, this would have greatly exacerbated the already existing architectural problems and introduced a bunch of new ones...\n\n### Origins of the Current State\n\nSo, a different solution was needed! :bulb: Instead of having an uber-complicated and all-knowing central testcoordinator node, I chose to go the other way and actually make it \"dumber\". The way I chose to do that was to make individual k6 instances \"smarter\" and somewhat aware that they are a part of a distributed test run via [the execution segment and sequence options](https://k6.io/docs/using-k6/k6-options/reference/#execution-segment).\n\nNow, when a test run is partitioned between multiple k6 instances, each k6 instance is started with its own execution segment. If we represent 100% of the test run as the interval between `0` and `1`, an execution segment is a non-overlapping subsection of that interval defined by 2 rational numbers. For example, a test run can be equally split between 4 instances with the execution segments of `0:1/4`, `1/4:1/2`,`1/2:3/4`, and `3/4:1`, each representing 25% of the whole test. If we start each k6 instance with its own execution segment (and, for somewhat complicated reasons, the sequence of all instance segments), it allows it to independently and efficiently execute only its own piece of the test. That is, each k6 instance will only initialize and spin up the VUs it is supposed to and start the iterations it is supposed to, regardless of how many scenarios were configured. _(The algorithms here are interesting and probably deserve their own long post, but they are out of scope for this already quite long document...)_\n\nIf the whole interval between `0` and `1` is covered by execution segments, then a distributed k6 test on multiple machines with these segments should behave **exactly** as if a big k6 test was run on a single beefy machine (ignoring any network delays due to geo-distribution, of course). One of the big benefits of this approach is that k6 now uses the exact same code paths for normal local `k6 run script.js` tests and for distributed tests (where we have multiple instances with `k6 run --execution-segment=X:Y --execution-segment-sequence=0,X,Y,Z,...,1`). That is because `k6 run script.js` is actually a shorthand for `k6 run --execution-segment=0:1 script.js`, i.e. the default execution segment value is `0:1`. Or, in human terms, by default k6 just runs the whole test, with the exact same logic and code that is capable of running only a very specific segment of the test. There is _(*mostly :sweat_smile:)_ no second execution path anymore! :tada:\n\nAnother big benefit of this architecture is that every k6 instance in a distributed test knows what it's supposed to be doing, without any network communication between it and the other k6 instances. And, _once the test fully starts_, there isn't even a need for communication between it and the central testcoordinator!\n\n### Missing Parts in the Current State\n\nWhile the current distributed execution solution is much better than before, it's still very, very far from perfect... :disappointed:\n\nOne big shortcoming is hidden behind the \"_once the test fully starts_\" caveat above. While execution segments allow the actual test execution to happen independently on multiple machines so that \"the sum of the parts\" is equal to the whole test run (as if it was executed on a single machine), they don't do anything for all of the initialization logic and actions that happen before the test run starts and after it ends, or for error handling, or for metric crunching and thresholds.\n\nLet's assume we have somehow fully partitioned a test run into multiple execution segments and we have initialized all of these planned \"instances\" (e.g. containers, k8s pods, VMs, etc.). Here is a list of (hopefully) all of the tasks that need to be handled so that distributed k6 execution has good UX and works nicely:\n1. **Pass the archive**: We _somehow_ need to distribute the script [.tar archive bundle](https://k6.io/docs/misc/archive-command/) among all of the \"instances\" that will run the test. Ideally without the user having to manually do anything except point the instances to a central node or registry of some sort.\n2. **Run setup once**: We _somehow_ need to ensure that [`setup()`](https://k6.io/docs/using-k6/test-lifecycle/) is executed only once (i.e. on a single instance), but that any errors in it are correctly handled, and that its results are distributed to the other instances that didn't execute it.\n3. **Ready status**: _Something_ needs to ensure that all instances have finished initializing their VUs before we _somehow_ start the actual test run on all of them simultaneously. This simultaneous start is important because, without it, a distributed test run will behave very differently to the same test run on a single big machine. Everything will be out of whack and k6 will behave unpredictably, which is something we don't want in a tool that is used to measure other services. Predictable performance is key when you are the measuring stick!\n4. **Failure detection**: While the test execution will be autonomously handled by each k6 instance for its own execution segment, _something_ needs to handle failures in a user-friendly way. For example, some of the k6 instances might suffer network problems or might die due to a bad test script or out-of-memory issues, so we somehow need to detect such problems and potentially stop the whole test.\n5. **Metric aggregation**: While the test is executing, we _somehow_ need to collect all of the metrics from all instances and crunch them, because we need the aggregated metrics to produce the [end-of-test summary](https://k6.io/docs/results-output/end-of-test/) and to calculate whether the [script thresholds](https://k6.io/docs/using-k6/thresholds/) were crossed. For these calculations to be correct, we can't do them separately on every k6 instance in a distributed test, we need to first aggregate the results centrally and use that for the calculations. This is particularly important because some thresholds might be [configured with `abortOnFail`](https://k6.io/docs/using-k6/thresholds/#abort), which means that we need to be continuously crunching the data, since they can require us to stop the test run mid-test!\n6. **Abort the test-run**: Besides thresholds with `abortOnFail` and errors, there are also a lot of other ways to prematurely stop a k6 test run, e.g. by calling [`test.abort()` from `k6/execution`](https://k6.io/docs/javascript-api/k6-execution/#test) or simply hitting Ctrl+C. _Something_ needs to handle such cases nicely. See https://github.com/grafana/k6/issues/2804 for more details, but ideally we should have the same nice UX in distributed k6 test that we have in regular local k6 tests, including the same exit codes that can be checked in a CI system.\n7. **Done status**: Even if the test hasn't finished prematurely, _something_ needs to detect that all instances are done with their part of the test run. Because of executors like [`shared-iterations`](https://k6.io/docs/using-k6/scenarios/executors/shared-iterations/) and [`per-vu-iterations`](https://k6.io/docs/using-k6/scenarios/executors/per-vu-iterations/) and because iteration durations vary, only the maximum test duration is predictable and bounded, but the test might finish a lot sooner than that max possible duration and good UX would be to not force the user to wait needlessly.\n8. **Run teardown once**: Regardless of whether the test has finished nominally or prematurely, _something_ needs to detect that it _has_ finished and must run `teardown()` on only one of the available instances, even if there were errors during the test. This is important because `setup()` might have potentially allocated costly resources. That said, any errors during `teardown()` execution must also be handled nicely.\n9. **End-of-test and handleSummary**: After `teardown()` has been executed, we _somehow_ need to produce the [end-of-test summary](https://k6.io/docs/results-output/end-of-test/) by executing the [`handleSummary()` function](https://k6.io/docs/results-output/end-of-test/custom-summary/) on a k6 instance _somewhere_. For the best UX, the differences between local and distributed k6 runs should be as minimal as possible, so the user should be able to see the end-of-test summary in their terminal or CI system, regardless of whether the k6 test was local or distributed.\n\nSo, yeah, while execution segments handle most of the heavy lifting during the test execution, there are plenty of other peripheral things that need to be handled separately in order to have fully-featured distributed k6 execution... :sweat_smile:\n\n### Problems of the Current State\n\nAt the moment, to reduce the already huge scope of https://github.com/grafana/k6/pull/1007, most of these jobs are handled by a remnant of the old pre-#1007 k6 cloud distributed architecture. There is still a central testcoordinator, albeit a somewhat dumber one, which works together with a thin wrapper around k6 to handle tasks 1, 2, 3, 4, 7 and 8 (and a few other cloud-specific things). Metric crunching (tasks 5 and 6) is handled by every k6 instance streaming its results to the k6 cloud backend (basically `k6 run --out cloud`). However, even so, `handleSummary()` (task 9) is still unsupported in `k6 cloud` (https://github.com/grafana/k6-cloud-feature-requests/issues/24) and remains a heavily requested feature.\n\nThe lack of support for `handleSummary()` in `k6 cloud` is only one of several major reasons why we can't just open-source some of our current cloud components and consider \"native distributed execution\" in k6 to be done :sweat_smile: Besides a host of other implementation details that closely tie the current solution to specifics in our cloud service and prevent us from directly open-sourcing it, the current cloud solution has at least 2 major architectural problems.\n\nFirst, now is the time to qualify what I meant by \"_mostly_\" in the \"There is _(*mostly :sweat_smile:)_ no second execution path anymore!\" sentence above. While there is no second _test_ execution path anymore, because of the execution segments, everything at the periphery I described in the points above kind of needs at least two separate implementations... :disappointed:\n\nk6 handles all of these operations perfectly well on its own, when it is run locally in a single `k6 run` instance. It knows how to run `setup()` and `teardown()` and `handleSummary()`, how to handle errors and correctly stop the test prematurely, how to crunch metrics and thresholds, etc. However, as soon as we run multiples k6 instances (either from k6 cloud or [k6-operator](https://github.com/grafana/k6-operator) or manually), we actually need to disable that built-in k6 logic (e.g. with `--no-setup`, `--no-teardown`, `--no-summary`, etc.) and re-implement some of it externally. So we end up with two (or more!) re-implementations of some of the same things. That costs a ton of effort, is unevenly implemented (e.g. https://github.com/grafana/k6-operator/issues/223) and even when it's implemented, there are often subtle differences in behavior between the implementations that might surprise users unpleasantly!\n\nSecondly, a big architectural problem of the current distributed execution solutions is that they have a push-based and top-down control mechanism. _Something_ centrally needs to \"see\" all k6 instances, so it can connect to them and send them commands. Besides the logistical problem of having one node connect to many, there is also no way for these k6 instances to synchronize some more subtle things between themselves.\n\nThis limited control mechanism is what's actually causing the need to re-implement some of the current k6 logic externally (e.g. top-down instance synchronization, `setup()` and `teardown()` handling, etc.). And it's also preventing us from implementing a lot of very heavily requested features like test suites (i.e. executing multiple scripts with a single k6 run, see https://github.com/grafana/k6/issues/1342), `SharedArray` improvements (https://github.com/grafana/k6/issues/2043 / https://github.com/grafana/k6/issues/2962), https://github.com/grafana/k6/issues/1638, etc.\n\n## Proposed Solution\n\nSo, ideally, instead of figuring out how to open the limited cloud solution we currently have, we should probably create a new and better distributed execution solution that is suitable for both k6 cloud and k6 open-source users (both via [k6-operator](https://github.com/grafana/k6-operator) or otherwise).\n\n### Goals\n\nLet's start with the goals first:\n1. Ideally, implement all 9 points from the list :arrow_up:, as well as anything else required, to get native distributed execution with great UX in k6 :sweat_smile:\n2. Have a distributed execution solution that works well for all k6 open-source users, regardless of whether they want to use it directly or via something like k6-operator. At the same time, k6-operator and k6 cloud both should also be able to make use of some of the new features and become even better than they currently are!\n3. As much as practically possible, do it in a backwards compatible manner. Some changes in k6 cloud and k6-operator are expected and even wanted, but if we keep `k6 run` backwards compatible, these changes don't _need_ to happen immediately, they can be incremental and non-breaking improvements over time.\n4. As much as practically possible, have only one way to do a certain thing. We want to avoid re-implementing the same logic in multiple places whenever possible.\n\n### Architecture\n\nThe good news is that all of these goals seem achievable :tada: Or at least this is my opinion after making the proof-of-concept implementation (https://github.com/grafana/k6/pull/2816).\n\n#### Reverse the pattern\n\nMy proposal is to basically continue what [#1007](https://github.com/grafana/k6/pull/1007) started... :sweat_smile: That is, continue moving more and more of the logic out of the center and towards the edge, towards the individual k6 \"worker\" instances that actually execute the distributed test run. For the best UX we should probably still have some sort of a central coordinator node, but if we reverse the control flow, so that k6 \"worker\" instances connect to it and are the main actors instead of the central node, then the central coordinator node can be relatively \"dumb\".\n\nAfter all, a single k6 instance is already perfectly capable of executing all the steps in a local `k6 run script.js` test run, from start to finish, completely on its own! And while every single k6 instance in a distributed test run is aware of its own execution segment, it is also already _somewhat_ aware of the existence of the other instances in the test run, from the execution segment sequence. It may not know their IPs or any other details, but it already knows that they exist and even their total number and segments!\n\n![reverse the pattern](020-architecture.png)\n\n#### Instance Synchronization API\n\nLet's suppose for a moment that k6 instances in a distributed test run have _some way_ to communicate indirectly, _some central service or registry_ they can all connect to and use in _some manner_ (I'll get back to that later). What types of synchronization and communication operations would be sufficient for a bunch of k6 instances that already know how to execute tests to self-organize and run a distributed test cooperatively?\n\nMy suggestion is that we can call this API `execution.Controller`, and that we might need only a few very simple operations in it. For example:\n```go\ntype Controller interface {\n    // GetOrCreateData requests the data chunk with the given ID, if it already\n    // exists. If it doesn't (i.e. this was the first time this function was\n    // called with that ID), the given callback is called and its result and\n    // error are saved for the ID and returned for all other calls with it.\n    //\n    // This is an atomic function, so any calls to it while the callback is\n    // being executed the same ID will wait for the first call to finish\n    // and receive its result.\n    GetOrCreateData(id string, callback func() ([]byte, error)) ([]byte, error)\n\n    // SignalAndWait implements a rendezvous point / barrier, a way for all\n    // instances to reach the same execution point and wait for each other, before\n    // they all ~simultaneously continue with the execution.\n    //\n    // It subscribes for the given event ID, signals that the current instance has\n    // reached it without an error, and then waits until all other instances have\n    // reached it or until there is an error in one of them.\n    SignalAndWait(eventID string, err error) error\n}\n```\n\nThe idea behind this API is that, for local single-instance execution (i.e. for `k6 run script.js`), these functions would basically be no-ops and nothing will change when they are called. Because we have only a single instance, `Controller.GetOrCreateData()` will immediately call the `callback` and `Controller.SignalAndWait()` will immediately reach the required number of 1 total instances, so it will not need to actually block and wait for anything. In essence, adding these calls to the test execution code of k6 will not affect local `k6 run` tests in any way, that will continue working exactly as it currently works... :tada:\n\nHowever, when multiple k6 instances are simultaneously running the same test run, we can inject a different distributed implementation of the `execution.Controller` API! Then all of the instances can use this API (e.g. as implemented by some central place they can all access, a \"coordinator\" node) to cooperatively synchronize with each other! For example:\n- Instead of that central coordinator querying and waiting for all instance to initialize their VUs, so it can synchronize their test start, the instances themselves can all call `SignalAndWait(\"test-ready-to-run-setup\")` when they have initialized their allotted VUs and are ready to run `setup()` :tada:\n- After that, instead of that central coordinator node managing `setup()` execution manually and duplicating already existing k6 code, all of the k6 instances can just call `GetOrCreateData(\"setup\", func() ([]byte, error) { /* actual code that runs setup */ })`. Because of the synchronization promises of the API, the `actual code that runs setup` is guaranteed to be executed only once, on a single instance, while all other instances wait for it to be done and get its result! :sparkles:\n- After that, all instances can synchronize again with `SignalAndWait(\"setup-done\")`, to ensure that all of them have received and saved the `setup()` result, so that they simultaneously start the actual test execution, all at the same time.\n\nThat's basically it... :sweat_smile: As I said, every k6 instance already knows how to run tests from start to finish. In a distributed test run, it just needs a bit of help to synchronize itself and cooperate with the other instances! Because most of the heavy lifting is done by the execution segments, the rest of the synchronization can be done with a very simple and lightweight API! :tada:\n\n##### Instance Synchronization API Details\n\nThe above API proposal was mostly for illustrative purposes, since it maps very directly to the current k6 operations that need to be synchronized in a distributed k6 test run.\n\nWhile it would be sufficient to get the job done, it might be better to split these multi-action methods into their simpler constituent synchronization primitives. For practical implementation purposes that will make everything easier and the complex logic can be moved to helpers that use the simpler primitives the `Controller` API would provide. That way both the usage and the implementation of these APIs would be easier to write, especially when it comes to error-handling. It will also allow us to reuse some of the same APIs for test suites!\n\nFor example, the `SignalAndWait()` API call can be made into a helper function if the API had separate `Signal(eventID, error)` and `Subscribe(eventID)` simpler methods that it can use. See how something like this [could look like in the `proofs-of-concept` branch of the k6 repo](https://github.com/grafana/k6/blob/proofs-of-concept/execution/controller.go). The `GetOrCreateData(id, callback)` can also be refactored into separate `Once(callback)`, `SetData(id)` and `GetData(id)` calls, though that would mean that the `local` implementation of the `execution.Controller` will need to actually do a tiny amount of work :sweat_smile:\n\nIn any case, the exact `execution.Controller` API is not even all that important. There are multiple ways it can be done, including on top of some non-k6 services like etcd (_see the \"Alternative Solutions\" section below_). The important bit is that all we need to get distributed execution is a relatively simple API that can have 2 implementations: a (mostly) no-op one for local `k6 run` tests and a somewhat more complex (but still quite lightweight) API for distributed tests! :tada:\n\n#### User-facing Commands\n\nLet me get back to the actual user-facing functionality. My proposal is to introduce 2 new k6 sub-commands, e.g. let's call them `k6 coordinator` and `k6 agent` for now _(though if anyone has better name suggestions, please share!)_. Each of these new sub-commands will do a part of the work that `k6 run` currently does, by reusing the same underlying functions and code, so no actual code duplication! And when you combine a single instance running `k6 coordinator` and an arbitrary number of instances that are running `k6 agent`, you get distributed execution :tada: :sparkles:\n\n`k6 coordinator` details:\n- it expects the JS script file as its argument (e.g. `k6 coordinator script.js`) and is responsible for a packaging the JS file and its dependencies in a .tar archive bundle (i.e. basically what `k6 archive` and `k6 cloud` already do)\n- it can receive the same CLI flags that `k6 run`, `k6 archive` and `k6 cloud` can, e.g. you can have `k6 coordinator --vus 5 --duration 10m script.js`\n- it can also accept information for how many `k6 agent` instances to expect; in the [PoC PR](https://github.com/grafana/k6/pull/2816) I did this with a simple `--instance-count` integer CLI flag, but in the real implementation we'd probably want to be able to specify the full `ExecutionSegmentSequence` and maybe even some tag-based rules (e.g. segment N should go to instance with tags `{foo: bar, baz: 123}` or something like that) :thinking: or more than one set of `ExecutionSegmentSequence`+tag-based rules, considering that different tests in a test suite (see below) can have different distributions between instances... :thinking:\n- after it has parsed the options and packaged the archive bundle, it starts up a gRPC server on a configurable address and waits for connections from `k6 agent` instances\n- in the PoC I haven't added any authentication, but given that this will be a server that's potentially exposed over the internet, some token and/or TLS-based auth of the gRPC connection by agents is probably a good idea\n- when a `k6 agent` instance has successfully connected to the `k6 coordinator` gRPC server, the server sends it the packaged `.tar` archive bundle as well as the unique options for that instance (e.g. its execution segment)\n- the `k6 coordinator` gRPC server also provides the simple `execution.Controller` synchronization API that I described above, so that `k6 agent` instances can use it to themselves; it is also responsible for some of the error handling (e.g. when an instance dies or gets disconnected)\n- finally, it can accept metric snapshots (more on this below) from `k6 agent` instances and is responsible for crunching the thresholds during the test run and for calling `handleSummary()` at the end of the test run\n\n`k6 agent` details:\n- it expects the address of the gRPC server as its only argument and doesn't support any CLI flags except the ones that are needed for that connection (e.g. for gRPC authentication, instance tags it can identify itself with to get its own segment, etc.), so something like this `k6 agent <k6-coordinator-addr:port> --auth <whatever> --instance-tag foo=bar --instance-tag baz=123`\n- once it has connected to the `k6 coordinator` server, it receives the .tar archive bundle from it (in the current PoC that is pushed by the server on connection, but a better architecture might be pull-based one on top of `Controller.GetData()` :thinking:)\n- after that, `k6 agent` behaves identically to `k6 run` (even reusing the same code), with two major differences:\n  1. instead of a the no-op local execution `execution.Controller` that `k6 run` uses, `k6 agent` uses a real distributed execution implementation of the `execution.Controller` synchronization API, built on top of the `k6 coordinator` gRPC service\n  2. instead of crunching the metrics locally for the end-of-test summary and thresholds, `k6 agent` streams them periodically to the `k6 coordinator` service\n\nAnd that's basically it :tada:\n\n#### Metrics Handling\n\nThe only missing piece is efficiently streaming the metrics from agents to the coordinator. And one big prerequisite for that was already merged in k6 v0.43.0! A series of refactoring efforts spanning many PRs and culminating in https://github.com/grafana/k6/pull/2815 removed the problematic `core.Engine` component! It had a bunch of problems, but the biggest issue was that it was simultaneously responsible for two very different jobs: managing the test execution and crunching metrics. While `k6 run` still continues to do both of them even now, we needed to be able to split them in different and simpler components so that `k6 agent` does only the test execution orchestration (i.e. the 9 tasks above and the actual test execution) while `k6 coordinator` does only the metrics crunching!\n\nOne remaining prerequisite is efficient metric transmission over the network and efficient metric processing by the coordinator node. That can be easily implemented for `Counter`, `Gauge`, and `Rate` metrics because all of their raw `Sample` values are easily aggregated without a data loss (at least when it concerns the end-of-test summary and the current k6 thresholds), and aggregations of their aggregations will also be correct (we are basically just summing numbers or comparing times :sweat_smile:). However, for `Trend` values, we probably should implement HDR/sparse histograms (https://github.com/grafana/k6/issues/763) before we have distributed execution. Not just because of the more efficient network transmission, but mostly because we don't want to overwhelm the `k6 coordinator` node or have it run out of memory (`Trend` metric sinks currently keep all of the raw observation values in memory...).\n\nAs these days, most of the observability world is using OpenTelemetry protocol for emitting metrics, we may benefit from it as well. The coordinator node should expose an OpenTelemetry endpoint for ingesting metrics, with the following advantages:\n- It supports an efficient binary format over gRPC\n- It supports delta temporality as k6\n- It supports histogram aggregation\n- An OpenTelemetry metrics output is something we want to add independently from the distributed execution feature\n\nIn any case, when performance matters or a high cardinality of metrics is generated then we should encourage people to use a proper storage systems for metrics, via outputs. As k6 is not a metrics database, it is expected to be good enough at store a non-intensive metrics generation but in case of high volume then it may be better if we use the right tool for the job.\nOtherwise, as explained below, the coordinator could be flooded and become unstable, potentially we may mitigate the issue in case of spikes having classic back pressure and retry mechanisms.\n\n#### Test abortion\n\nA test can be aborted in several ways, as described in [this summary issue](https://github.com/grafana/k6/issues/2804). For example, in the event the running script invokes the `test.abort()` function, below the expected flow:\n\n1. The agent will intercept the abortion as done by a non-distributed run, and it emits an event for aborting the distributed test\n2. Then the agent will continue the abort flow for the single instance that will lead to stop the test on the instance and exit\n3. TC reacts to the received event broadcasting it to all instances, as they should have a dedicated routine listening for any abortion event\n4. All the instances executes the abortion flow as the point `3`, returning the same error received from the event.\n\nInstead, if the abortion process is started by the Coordinator, for example, if it has received a SIGTERM signal, the following is the expected flow:\n1. Declare the test abort emitting a dedicated event for it\n2. Close the connections with instances using the gRPC GOAWAY flow\n3. Each Agent instances listening for abortion event will process it stopping the run and exiting\n\n#### High Availability\n\nAs you might have noticed, the central `k6 coordinator` node is a single point of failure in the proposed architecture. Because of its simple API, it can actually be made highly-available fairly easily (or maybe even replaced with already fault-tolerant/HA components), but I'd argue it is not worth it to spend the time on that, at least in the first version.\n\nGiven the fact that k6 is used as a measuring stick for other systems, it needs to perform well. But even more importantly, it needs to have a consistent and predictable performance! Our users rely on k6 to spot performance changes in their own services, so two runs of the same script with the same k6 version on the same hardware and with the same execution type (local or distributed) should perform as identically as possible. It'd be difficult to measure things if your ruler changed sizes before every measurement... :sweat_smile:\n\nThat's why I think it'd be better for a test to completely fail than for us to have k6 performance be variable between different runs of the same test. So, generally, if one of the \"worker\" instances fails for some reason (e.g. OOM, script errors, network problems), the whole test should probably fail. The only (arguable) exception is huge tests that with a lot of instances and provisioned resources, where it might be better to allow a very small percentage of the total number of instances (e.g. 1%, 5%) to fail before we scrap the whole test and waste all of the allocated resources. But it's important to acknowledge that test failure is not the worst option around, we don't need to (and we actually can't) ensure 100% reliability of every single k6 test, be it local or distributed.\n\nBecause of the potential complexity of k6 scripts (especially ones with multiple scanarios), and because of the stateful nature of k6 VUs, we actually can't just replace failed instances with \"hot spare\" ones mid-test, even if we ignore problems with performance consistency. Something like this might only be possible with test suites (see bottom of this document), but not within an individual k6 test.\n\nIn summary, if we make the `k6 coordinator` node dumb enough and the metric transmission efficient enough, it'd be much more likely for a test to fail because of a bad script that eats up all of the RAM, or because of network issues, or due to all sorts of other potential problems on the `agent` side... So, a non-highly-available `k6 coordinator` is probably good enough, at least to start with.\n\n#### Disruption resilience\n\nBased on the high availability assumption described, the architecture is intentionally not very highly resilient to disruption. Below, the process described for the components in the event of disruption.\n\n##### Coordinator\n\nFor its nature of being a single point of failure, the `Coordinator` results to be the most impactful part of the architecture in case of disruption.\n\nIn the event, Testcoordinator disappear the agent instances will not be able to complete the test as they will remain in a stuck status waiting for the connection to return reliable, after the gRPC connection's defined timeout expires, each agent instance will abort the ongoing test run and will shut down.\n\nIn the event, a graceful shutdown (SIGTERM signal received) is initiated by Testcoordinator then it is expected to execute the flow described in test abortion section.\n\n##### Agent\n\nEventually, Agent instances could be more resilient.\n\nIf an instance at some point disappear, the system should tolerate this failure in some percentage requested by the user or by the default value. It means that a rendezvous point on the Sync API will have a timeout and if all the instances haven't reached the same point in a specified time frame then the Testcoordinator will remove those instances from the number of required instances for the sync consensus. \n\nHowever, in a first experimental version, is not expected to implement and support this described scenario. The flow will let the instances stuck on the rendezvous point that at some point will make the request timing out and the Agent instance will start the abortion flow.\n\n### An end-to-end example\n\nIt shows the end-to-end flow for the simplest use-case in a distributed test-run.\nThe first step requires to startup the `cordinator`:\n```sh\nk6 coordinator script.js\n```\n\nthat starts the gRPC server for synchronization API:\n```sh\nk6 coordinator --instance-count 2 script.js\nINFO[0000] Starting gRPC server on localhost:6566\n```\n\nAt this point, the coordinator listens for a number of connected agent instances equals to the value defined. For this reason, at this point, we need to startup the agent instances:\n```\nk6 agent localhost:6566\n```\nand again in a different terminal session:\n```\nk6 agent localhost:6566\n```\n\nAt this point the coordinator reached the expected status and it will notify the agent instances to start the test-run. When the agents will have been finished the coordinator will close the gathering process for metrics and it will publish the summary.\n```\nk6 coordinator --instance-count 2 script.js\nINFO[0000] Starting gRPC server on localhost:6566\nINFO[0005] Instance 1 of 2 connected!\nINFO[0017] Instance 2 of 2 connected!\nINFO[0018] All instances ready!\nINFO[0018] Test 1 (script.js) started...\nINFO[0049] Test 1 (script.js) ended!\nINFO[0049] Instances finished with the test suite\nINFO[0049] Instance 1 disconnected\nINFO[0049] Instance 2 disconnected\nINFO[0049] All done!\n\n     data_received..................: 3.1 MB 99 kB/s\n     data_sent......................: 19 kB  597 B/s\n     http_req_blocked...............: avg=18.43ms  min=4.09µs med=8.67µs   max=290ms p(90)=12.4µs   p(95)=249.54ms\n     http_req_connecting............: avg=8.33ms   min=0s     med=0s       max=130ms p(90)=0s       p(95)=114.66ms\n     http_req_duration..............: avg=129.33ms min=110ms  med=123.2ms  max=260ms p(90)=135.66ms p(95)=227.74ms\n       { expected_response:true }...: avg=129.33ms min=110ms  med=123.2ms  max=260ms p(90)=135.66ms p(95)=227.74ms\n     http_req_failed................: 0.00%  ✓ 0        ✗ 270\n     http_req_receiving.............: avg=7.17ms   min=63µs   med=140.57µs max=130ms p(90)=209.36µs p(95)=111.86ms\n     http_req_sending...............: avg=36.95µs  min=12µs   med=36.13µs  max=84µs  p(90)=50.1µs   p(95)=66.54µs\n     http_req_tls_handshaking.......: avg=8.61ms   min=0s     med=0s       max=140ms p(90)=0s       p(95)=117.16ms\n     http_req_waiting...............: avg=122.13ms min=110ms  med=122.44ms max=150ms p(90)=129.48ms p(95)=133.08ms\n     http_reqs......................: 270    8.516465/s\n     iteration_duration.............: avg=1.17s    min=1.1s   med=1.15s    max=1.5s  p(90)=1.25s    p(95)=1.35s\n     iterations.....................: 267    8.421837/s\n     vus............................: 5      min=5      max=5\n     vus_max........................: 5      min=5      max=5\n```\n\n### Alternative Solutions\n\nOne proposal in the original posts of https://github.com/grafana/k6/issues/140 was to build the distributed execution on top of something like [etcd](https://github.com/etcd-io/etcd) (or Consul, Redis, etc.) and a central metrics storage like InfluxDB (or, more likely nowadays, Prometheus/Mimir :sweat_smile:)\n\nWhile there were some details in the original proposal that are no longer applicable because of the big architectural changes in k6 in the meantime, the overall proposal is probably still valid. I am pretty sure that the architecture I proposed above can be built on top of these technologies and in a way where instances don't need to hold a persistent connection to a central `k6 coordinator` node!\n\nHowever, I think that the benefits of such an approach would be outweighed by the drawbacks in terms of implementation and deployment complexity. In short, it can probably work, but IMO the UX will be worse. Even if we ignore the complications of deploying multiple software stacks (vs. just the k6 binary), it'd be difficult to implement great error handling and timely handling of things like `abortOnFail` thresholds and `test.abort()` API calls. It can certainly be done, but it'd be a ton of effort to not get a flaky experience...\n\nAnd, as I explained in the \"High Availability\" section above, a k6 test failing is not the worst thing that can happen. An inconsistent or a flaky test is a worse user experience in my mind.\n\n### Review of \"Missing Parts in the Current State\"\n\nLet's get back to my actual proposal of a `execution.Controller` API + new `k6 coordinator` and `k6 agent` sub-commands.\n\nTo show that the proposed solution is a viable one, I'll go through the 9 items from the list in the \"Missing Parts in the Current State\" section and show how the proposal can be used to easily implement them:\n1. `k6 coordinator` assembles the script and its dependencies into a [.tar archive bundle](https://k6.io/docs/misc/archive-command/) and distributes it to all `k6 agent` nodes automatically once they connect to it (either pull-based or push-based).\n2. I showed how `setup()` can be cooperatively execuded only on a single instance and how its result can be distributed to the rest of the instances with the `GetOrCreateData()` pseudo-API described in the \"Instance Synchronization API\" section.\n3. Similarly, in the \"Instance Synchronization API\" section I showed how the `SignalAndWait()` pseudo-API can be used to ensure that all instances have finished initializing their VUs and executed `setup()` before they start the actual test execution simultaneously\n4. Most failures will be handled by the coordinator and propaged to waiting instances. For the best UX, instances might subscribe to a special error channel so they can be interupted even during the test execution.\n5. Metric collection was described in the \"Metrics Handling\" section, and the coordinator will be able to stop the test if a threshold is crossed.\n6. We can probably handle `test.abort()` calls from an instance with a `GetOrCreateData()` call that uses a special `dataID` watched by the coordinator, but it might be simpler to just add a custom API for that... :thinking:\n7. Detecting when the test has finished is trivial with `SignalAndWait()`.\n8. `teardown()` can also be executed the same way we do `setup()`. Though, because it doesn't return any data, it is one of the reasons I think it makes sense to split `GetOrCreateData(id, callback)` into separate `Once(callback)`, `SetData(id)` amd `GetData(id)` calls...\n9. The `k6 coordinator` node can run `handleSummary()` after the test is done, no problems there :tada:\n\n### Additional Benefits\n\nBecause `setup()` will no longer be special and because we'll have a generic mechanism for an instance to generate some data and make it available to all other instances, there is nothing stopping us from implementing support for `SharedArray` (and other similar constructs) outside of the init context (https://github.com/grafana/k6/issues/2043 / https://github.com/grafana/k6/issues/2962) :tada: Or even things like per-scenario `setup()` (https://github.com/grafana/k6/issues/1638) or per-VU init functions (https://github.com/grafana/k6/issues/785) can now be actually useful.\n\nAnd maybe even more importantly, because k6 instances will now basically self-synchronize, test suites (https://github.com/grafana/k6/issues/1342) become much, much easier to implement :tada: See below for details, but we basically no longer need to have a super-smart coordinator node that knows the details for how tests are a part of the test suite, only k6 itself needs to know that and use the same `SignalAndWait()` API to synchronize even multiple tests simultaneously :tada:\n\nA potential improvement for getting a simplified user experience, when the API will be defined as stable, could be to hide the coordinator interface just behind the classic `k6 run` command. When a dedicated flag like `k6 run --distributed` is passed then the command will act as a coordinator. In this way, we are not forcing to the users the requirement to know what a _coordinator_ is. Only users with advanced cases will may require to know it and its dedicated command. \n\n# Test suites\n\nhttps://github.com/grafana/k6/issues/1342 is far behind https://github.com/grafana/k6/issues/140 when it comes to upvotes, but it is still one of our most requested features after it.\n\n## Limitations of `scenarios`\n\nIn theory, `scenarios` were supposed to solve some of the issues that we are currently hoping that test suites will solve, but in practice they have quite a few limitations:\n- No \"start after\" logic or chaining of scenarios, only limited `startTime` capabilities.\n- No CI-like capabilities (e.g. run `B` only if `A` succeeds, run `A` and `B` in parallel and run `C` only of both succeed, etc.).\n- VUs in all scenarios have the same global options.\n- It's difficult to execute only a subset of all `scenarios` (https://github.com/grafana/k6/issues/2780)\n- It's difficult to combine scenarios from different files.\n- There is no way to have `setup()` or `teardown()` per scenario (https://github.com/grafana/k6/issues/1638)\n- Users cannot share data between scenarios\n- Users cannot mix local and cloud scenarios (https://github.com/grafana/k6-cloud-feature-requests/issues/19)\n- Users cannot have different geo-distribution between scenarios (https://github.com/grafana/k6-cloud-feature-requests/issues/20)\n- VUs are reused between scenarios, which adds complexity when managing state.\n\nIn hindsight, while the current `scenarios` have their uses and benefits (especially when it comes to efficiency and support for different executors), they were not the greatest abstraction when it comes to actually partitioning work. https://github.com/grafana/k6/pull/1007 might have been better off had I ignored them or focused on something like the current idea of test suites instead... Though, given how long it has taken us to even reach the point where implementing test suites is feasible, maybe not... :sweat_smile:\n\nIn any case, both can exist together and have their valid and complimentary uses, so let's explore how we can implement test suites, even in distributed test runs that follow the architecture from the start of this document!\n\n## Proposed Solution\n\n### Test Execution Control\n\nOnce we have the `execution.Controller` API from the \"Instance Synchronization API\" section above, implementing test suites becomes almost trivial. Though, for this, we will actually to split the composite functions into their constituent parts (e.g. split `SignalAndWait()` into separate `Signal(eventID)` and `Wait(eventID)`), and the local execution implementation of the `execution.Controller` API might need to not be a no-op placeholder anymore and actually do some work... :sweat_smile:\n\nFirst, let's imagine a somewhat complicated test suite, where you have the following fan-in and fan-out behaviors:\n```mermaid\ngraph TD;\n    A-->B;\n    A-->C;\n    B-->D;\n    C-->D;\n    D-->E;\n```\n\nThat is, tests `B` and `C` are executed simultaneously, but only after test `A` has finished executing, then test `D` should start running only after both `B` and `C` have finished, and test `E` should start running after `D`. This can become even more complex if we start introducing conditional dependencies, e.g. \"if `C` succeeds run `D` otherwise run `E`, but let's consider that out-of-scope, for now :sweat_smile:\n\nFirst, how can we run this at all? One way is to just use the unique test names as a prefix to the `eventID` and `dataID` identifiers in the `execution.Controller` API :tada: This allows us to keep the API simple but usable for arbitrarily complex test suites.\n\nAnd we can also reuse the deconstructed `execution.Controller` API to model these dependencies between tests in the suite. In the above example, before test `B` and test `C` can start initializing their VUs, they can just call `Controller.Wait(\"test-A/test-finished\")` (or whatever the actual convention is). Similarly, before test `D` can start, it can call `Controller.Wait(\"test-B/test-finished\"); Controller.Wait(\"test-C/test-finished\")`. And all of this would work in both local and distributed execution! :tada:\n\nSimilarly, if we split `GetOrCreateData(id, callback)` into separate `Once(id, callback)`, `SetData(id)` and `GetData(id)` functions, tests down the chain would be able to even reference data from other tests in the suite before them. For example, if we save the result of `handleSummary()` under a `test-X/summary-result` identifier, then, if we want to, other tests would be able to retrieve that data with a simple JS API directly in the test script! And again, all of this would work even in distributed execution, since it relies on the same primitives it does! :tada:\n\n### Bundling Multiple Tests Together\n\nOne unknown here is how to bundle multiple independent tests in a single suite, especially if we want to have complex (but still acyclic!) `startAfter` relationships between tests in the suite.\n\nIn my PoC I didn't have a ton of time to make a complex solution, so I just added support for a list of tests. `k6 coordinator` basically transmitted them in a slice... :sweat_smile: But we probably want some sort of a more complicated and flexible configuration. My thoughts are that we can have a custom exported variable (e.g. `export const tests`) which k6 knows to interpret as a test suite when it encounters it.\n\nIdeally, we also want to be able to configure custom script entry points and custom environment variables, global script `options`, etc. for every test in the suite, without actually `import`-ing the scripts themselves. This offers the maximum amount of flexibility, see https://github.com/grafana/k6/issues/2919#issuecomment-1437254679 for details.\n\nAdditionally, we probably want to support custom thresholds and end-of-test summaries (or disabling them!) both for individual tests in the suite, as well as for the whole test suite together.\n\nFinally, how and if all of these things are packaged in a single (or more than one) .tar (or other) archive bundle is still an open question... :sweat_smile: There are other potential complications here as well, e.g. https://github.com/grafana/k6/issues/2974.\n"
  },
  {
    "path": "docs/mkdocs.yml",
    "content": "# To run locally\n# npx @techdocs/cli serve -v -c ./docs/mkdocs.yml\n# \nsite_name: 'k6 Internal Documentation'\nrepo_url: https://github.com/grafana/k6\nedit_uri: edit/main/docs\n\ntheme:\n  name: material\n  features:\n    - navigation.sections\n\nplugins:\n  - techdocs-core\n"
  },
  {
    "path": "errext/abort_reason.go",
    "content": "package errext\n\nimport \"errors\"\n\n// AbortReason is used to signal to outputs what type of error caused the test\n// run to be stopped prematurely.\ntype AbortReason uint8\n\n// These are the various reasons why a test might have been aborted prematurely.\nconst (\n\tAbortedByUser AbortReason = iota + 1\n\tAbortedByThreshold\n\tAbortedByThresholdsAfterTestEnd // TODO: rename?\n\tAbortedByScriptError\n\tAbortedByScriptAbort\n\tAbortedByTimeout\n\tAbortedByOutput\n)\n\n// HasAbortReason is a wrapper around an error with an attached abort reason.\ntype HasAbortReason interface {\n\terror\n\tAbortReason() AbortReason\n}\n\n// WithAbortReasonIfNone can attach an abort reason to the given error, if it\n// doesn't have one already. It won't do anything if the error already had an\n// abort reason attached. Similarly, if there is no error (i.e. the given error\n// is nil), it also won't do anything and will return nil.\nfunc WithAbortReasonIfNone(err error, abortReason AbortReason) error {\n\tif err == nil {\n\t\treturn nil // No error, do nothing\n\t}\n\tvar arerr HasAbortReason\n\tif errors.As(err, &arerr) {\n\t\t// The given error already has an abort reason, do nothing\n\t\treturn err\n\t}\n\treturn withAbortReasonError{err, abortReason}\n}\n\ntype withAbortReasonError struct {\n\terror\n\tabortReason AbortReason\n}\n\nfunc (ar withAbortReasonError) Unwrap() error {\n\treturn ar.error\n}\n\nfunc (ar withAbortReasonError) AbortReason() AbortReason {\n\treturn ar.abortReason\n}\n\nvar _ HasAbortReason = withAbortReasonError{}\n"
  },
  {
    "path": "errext/errext_test.go",
    "content": "package errext\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n)\n\nfunc assertHasHint(t *testing.T, err error, hint string) {\n\tvar typederr HasHint\n\trequire.ErrorAs(t, err, &typederr)\n\tassert.Equal(t, hint, typederr.Hint())\n\tassert.Contains(t, err.Error(), typederr.Error())\n}\n\nfunc assertHasExitCode(t *testing.T, err error, exitcode exitcodes.ExitCode) {\n\tvar typederr HasExitCode\n\trequire.ErrorAs(t, err, &typederr)\n\tassert.Equal(t, exitcode, typederr.ExitCode())\n\tassert.Contains(t, err.Error(), typederr.Error())\n}\n\nfunc TestErrextHelpers(t *testing.T) {\n\tt.Parallel()\n\n\tconst testExitCode exitcodes.ExitCode = 13\n\tassert.Nil(t, WithHint(nil, \"test hint\"))\n\tassert.Nil(t, WithExitCodeIfNone(nil, testExitCode))\n\n\terrBase := errors.New(\"base error\")\n\terrBaseWithHint := WithHint(errBase, \"test hint\")\n\tassertHasHint(t, errBaseWithHint, \"test hint\")\n\terrBaseWithTwoHints := WithHint(errBaseWithHint, \"better hint\")\n\tassertHasHint(t, errBaseWithTwoHints, \"better hint (test hint)\")\n\n\terrWrapperWithHints := fmt.Errorf(\"wrapper error: %w\", errBaseWithTwoHints)\n\tassertHasHint(t, errWrapperWithHints, \"better hint (test hint)\")\n\n\terrWithExitCode := WithExitCodeIfNone(errWrapperWithHints, testExitCode)\n\tassertHasHint(t, errWithExitCode, \"better hint (test hint)\")\n\tassertHasExitCode(t, errWithExitCode, testExitCode)\n\n\terrWithExitCodeAgain := WithExitCodeIfNone(errWithExitCode, exitcodes.ExitCode(27))\n\tassertHasHint(t, errWithExitCodeAgain, \"better hint (test hint)\")\n\tassertHasExitCode(t, errWithExitCodeAgain, testExitCode)\n\n\terrBaseWithThreeHints := WithHint(errWithExitCodeAgain, \"best hint\")\n\tassertHasHint(t, errBaseWithThreeHints, \"best hint (better hint (test hint))\")\n\n\tfinalErrorMess := fmt.Errorf(\"woot: %w\", errBaseWithThreeHints)\n\tassert.Equal(t, \"woot: wrapper error: base error\", finalErrorMess.Error())\n\tassertHasHint(t, finalErrorMess, \"best hint (better hint (test hint))\")\n\tassertHasExitCode(t, finalErrorMess, testExitCode)\n}\n"
  },
  {
    "path": "errext/exception.go",
    "content": "// Package errext contains extensions for normal Go errors that are used in k6.\npackage errext\n\n// Exception represents errors that resulted from a script exception and contain\n// a stack trace that lead to them.\ntype Exception interface {\n\terror\n\tHasAbortReason\n\tStackTrace() string\n}\n"
  },
  {
    "path": "errext/exit_code.go",
    "content": "package errext\n\nimport (\n\t\"errors\"\n\n\t\"go.k6.io/k6/errext/exitcodes\"\n)\n\n// ExitCode is the code with which the application should exit if this error\n// bubbles up to the top of the scope. Values should be between 0 and 125:\n// https://unix.stackexchange.com/questions/418784/what-is-the-min-and-max-values-of-exit-codes-in-linux\n\n// HasExitCode is a wrapper around an error with an attached exit code.\ntype HasExitCode interface {\n\terror\n\tExitCode() exitcodes.ExitCode\n}\n\n// WithExitCodeIfNone can attach an exit code to the given error, if it doesn't\n// have one already. It won't do anything if the error already had an exit code\n// attached. Similarly, if there is no error (i.e. the given error is nil), it\n// also won't do anything.\nfunc WithExitCodeIfNone(err error, exitCode exitcodes.ExitCode) error {\n\tif err == nil {\n\t\t// No error, do nothing\n\t\treturn nil\n\t}\n\tvar ecerr HasExitCode\n\tif errors.As(err, &ecerr) {\n\t\t// The given error already has an exit code, do nothing\n\t\treturn err\n\t}\n\treturn withExitCodeError{err, exitCode}\n}\n\ntype withExitCodeError struct {\n\terror\n\texitCode exitcodes.ExitCode\n}\n\nfunc (wh withExitCodeError) Unwrap() error {\n\treturn wh.error\n}\n\nfunc (wh withExitCodeError) ExitCode() exitcodes.ExitCode {\n\treturn wh.exitCode\n}\n\nvar _ HasExitCode = withExitCodeError{}\n"
  },
  {
    "path": "errext/exitcodes/codes.go",
    "content": "// Package exitcodes contains the constants representing possible k6 exit error codes.\npackage exitcodes\n\n// ExitCode is just a type representing a process exit code for k6\ntype ExitCode uint8\n\n// list of exit codes used by k6\nconst (\n\t// CloudTestRunFailed indicates that the cloud test run failed.\n\t// Its value used to be 99 before k6 v0.33.0.\n\tCloudTestRunFailed ExitCode = 97 // This used to be 99 before k6 v0.33.0\n\n\t// CloudFailedToGetProgress indicates that k6 was unable to synchronize the\n\t// test progress with the cloud.\n\tCloudFailedToGetProgress ExitCode = 98\n\n\t// ThresholdsHaveFailed indicates that one or more thresholds have failed.\n\tThresholdsHaveFailed ExitCode = 99\n\n\t// SetupTimeout indicates the execution of the test setup function timed out.\n\tSetupTimeout ExitCode = 100\n\n\t// TeardownTimeout indicates the execution of the test teardown function timed out.\n\tTeardownTimeout ExitCode = 101\n\n\t// GenericTimeout indicates a timeout with an unspecified reason.\n\tGenericTimeout ExitCode = 102 // TODO: remove?\n\n\t// ScriptStoppedFromRESTAPI indicates the execution has been\n\t// stopped by a call to the k6's REST API.\n\tScriptStoppedFromRESTAPI ExitCode = 103\n\n\t// InvalidConfig indicates an invalid configuration.\n\tInvalidConfig ExitCode = 104\n\n\t// ExternalAbort indicates the test was aborted by an external signal\n\t// (e.g. SIGINT, SIGTERM, etc.) and should be considered aborted rather\n\t// than a failure.\n\tExternalAbort ExitCode = 105\n\n\t// CannotStartRESTAPI indicates the k6's REST API server could not be started.\n\tCannotStartRESTAPI ExitCode = 106\n\n\t// ScriptException indicates an exception was thrown during the\n\t// test script's execution.\n\tScriptException ExitCode = 107\n\n\t// ScriptAborted indicates the script was aborted by a call to the\n\t// k6 execution module's `test.abort()` function.\n\tScriptAborted ExitCode = 108\n\n\t// GoPanic indicates the script was aborted by a panic in the Go runtime.\n\tGoPanic ExitCode = 109\n\n\t// MarkedAsFailed indicates that the test was marked as failed.\n\tMarkedAsFailed ExitCode = 110\n)\n"
  },
  {
    "path": "errext/format.go",
    "content": "package errext\n\nimport (\n\t\"errors\"\n)\n\n// Format formats the given error as a message (string) and a map of fields.\n// In case of [Exception], it uses the stack trace as the error message.\n// In case of [HasHint], it also adds the hint as a field.\nfunc Format(err error) (string, map[string]any) {\n\tif err == nil {\n\t\treturn \"\", nil\n\t}\n\n\terrText := err.Error()\n\tvar xerr Exception\n\tif errors.As(err, &xerr) {\n\t\terrText = xerr.StackTrace()\n\t}\n\n\tfields := make(map[string]any)\n\tvar herr HasHint\n\tif errors.As(err, &herr) {\n\t\tfields[\"hint\"] = herr.Hint()\n\t}\n\n\treturn errText, fields\n}\n"
  },
  {
    "path": "errext/format_test.go",
    "content": "package errext_test\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"go.k6.io/k6/errext\"\n)\n\nfunc TestFormat(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Nil\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\terrorText, fields := errext.Format(nil)\n\t\tassert.Equal(t, \"\", errorText)\n\t\tassert.Empty(t, fields)\n\t})\n\n\tt.Run(\"Simple\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\terrorText, fields := errext.Format(errors.New(\"simple error\"))\n\t\tassert.Equal(t, \"simple error\", errorText)\n\t\tassert.Empty(t, fields)\n\t})\n\n\tt.Run(\"Exception\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\terr := fakeExceptionError{error: errors.New(\"simple error\"), stack: \"stack trace\"}\n\t\terrorText, fields := errext.Format(err)\n\t\tassert.Equal(t, \"stack trace\", errorText)\n\t\tassert.Empty(t, fields)\n\t})\n\n\tt.Run(\"Hint\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\terr := errext.WithHint(errors.New(\"error with hint\"), \"hint message\")\n\t\terrorText, fields := errext.Format(err)\n\t\tassert.Equal(t, \"error with hint\", errorText)\n\t\tassert.Equal(t, map[string]any{\"hint\": \"hint message\"}, fields)\n\t})\n\n\tt.Run(\"ExceptionWithHint\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\terr := fakeExceptionError{error: errext.WithHint(errors.New(\"error with hint\"), \"hint message\"), stack: \"stack trace\"}\n\t\terrorText, fields := errext.Format(err)\n\t\tassert.Equal(t, \"stack trace\", errorText)\n\t\tassert.Equal(t, map[string]any{\"hint\": \"hint message\"}, fields)\n\t})\n}\n\ntype fakeExceptionError struct {\n\terror\n\tstack string\n\tabort errext.AbortReason\n}\n\nfunc (e fakeExceptionError) StackTrace() string {\n\treturn e.stack\n}\n\nfunc (e fakeExceptionError) AbortReason() errext.AbortReason {\n\treturn e.abort\n}\n\nfunc (e fakeExceptionError) Unwrap() error {\n\treturn e.error\n}\n"
  },
  {
    "path": "errext/hint.go",
    "content": "package errext\n\nimport \"errors\"\n\n// HasHint is a wrapper around an error with an attached user hint. These hints\n// can be used to give extra human-readable information about the error,\n// including suggestions on how the error can be fixed.\ntype HasHint interface {\n\terror\n\tHint() string\n}\n\n// WithHint is a helper that can attach a hint to the given error. If there is\n// no error (i.e. the given error is nil), it won't do anything. If the given\n// error already had a hint, this helper will wrap it so that the new hint is\n// \"new hint (old hint)\".\nfunc WithHint(err error, hint string) error {\n\tif err == nil {\n\t\treturn nil // No error, do nothing\n\t}\n\treturn withHintError{err, hint}\n}\n\ntype withHintError struct {\n\terror\n\thint string\n}\n\nfunc (wh withHintError) Unwrap() error {\n\treturn wh.error\n}\n\nfunc (wh withHintError) Hint() string {\n\thint := wh.hint\n\tvar oldhint HasHint\n\tif errors.As(wh.error, &oldhint) {\n\t\t// The given error already had a hint, wrap it\n\t\thint = hint + \" (\" + oldhint.Hint() + \")\"\n\t}\n\n\treturn hint\n}\n\nvar _ HasHint = withHintError{}\n"
  },
  {
    "path": "errext/interrupt_error.go",
    "content": "package errext\n\nimport (\n\t\"errors\"\n\n\t\"go.k6.io/k6/errext/exitcodes\"\n)\n\n// InterruptError is an error that halts engine execution\ntype InterruptError struct {\n\tReason string\n}\n\nvar _ interface {\n\tHasExitCode\n\tHasAbortReason\n} = &InterruptError{}\n\n// Error returns the reason of the interruption.\nfunc (i *InterruptError) Error() string {\n\treturn i.Reason\n}\n\n// ExitCode returns the status code used when the k6 process exits.\nfunc (i *InterruptError) ExitCode() exitcodes.ExitCode {\n\treturn exitcodes.ScriptAborted\n}\n\n// AbortReason is used to signal that an InterruptError is caused by the\n// test.abort() functin in k6/execution.\nfunc (i *InterruptError) AbortReason() AbortReason {\n\treturn AbortedByScriptAbort\n}\n\n// AbortTest is the reason emitted when a test script calls test.abort()\nconst AbortTest = \"test aborted\"\n\n// MarkedAsFailedTest is the reason emitted when a test script fails\nconst MarkedAsFailedTest = \"test marked as failed\"\n\n// IsInterruptError returns true if err is *InterruptError.\nfunc IsInterruptError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tvar intErr *InterruptError\n\treturn errors.As(err, &intErr)\n}\n"
  },
  {
    "path": "examples/base64.js",
    "content": "import { check } from \"k6\";\nimport encoding from \"k6/encoding\";\n\nexport default function() {\n    // Standard base64 encoding/decoding with '=' padding\n    let str = \"hello world\";\n    let enc = \"aGVsbG8gd29ybGQ=\";\n    check(null, {\n        \"is std encoding correct\": () => encoding.b64encode(str) === enc,\n        \"is std decoding correct\": () => encoding.b64decode(enc, null, \"s\") === str\n    });\n\n    // Standard base64 encoding/decoding without '=' padding\n    str = \"hello world\";\n    enc = \"aGVsbG8gd29ybGQ\";\n    check(null, {\n        \"is rawstd encoding correct\": () => encoding.b64encode(str, 'rawstd') === enc,\n        \"is rawstd decoding correct\": () => encoding.b64decode(enc, 'rawstd', \"s\") === str\n    });\n\n    // URL-safe base64 encoding/decoding with '=' padding\n    str = \"小飼弾..\";\n    enc = \"5bCP6aO85by-Li4=\";\n    check(null, {\n        \"is url encoding correct\": () => encoding.b64encode(str, 'url') === enc,\n        \"is url decoding correct\": () => encoding.b64decode(enc, 'url', \"s\") === str\n    });\n\n    // URL-safe base64 encoding/decoding without '=' padding\n    str = \"小飼弾..\";\n    enc = \"5bCP6aO85by-Li4\";\n    check(null, {\n        \"is rawurl encoding correct\": () => encoding.b64encode(str, 'rawurl') === enc,\n        \"is rawurl decoding correct\": () => encoding.b64decode(enc, 'rawurl', \"s\") === str\n    });\n};\n"
  },
  {
    "path": "examples/browser/colorscheme.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext({\n    // valid values are \"light\", \"dark\" or \"no-preference\"\n    colorScheme: 'dark',\n  });\n  const page = await context.newPage();\n\n  try {\n    await page.goto(\n      'https://quickpizza.grafana.com/test.k6.io',\n      { waitUntil: 'load' },\n    )\n    await check(page, {\n      'isDarkColorScheme':\n        p => p.evaluate(() => window.matchMedia('(prefers-color-scheme: dark)').matches)\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/cookies.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n  const context = page.context();\n\n  try {\n    // get cookies from the browser context\n    await check(await context.cookies(), {\n        'initial number of cookies should be zero': c => c.length === 0,\n    });\n\n    // add some cookies to the browser context\n    const unixTimeSinceEpoch = Math.round(new Date() / 1000);\n    const day = 60*60*24;\n    const dayAfter = unixTimeSinceEpoch+day;\n    const dayBefore = unixTimeSinceEpoch-day;\n    await context.addCookies([\n      // this cookie expires at the end of the session\n      {\n        name: 'testcookie',\n        value: '1',\n        sameSite: 'Strict',\n        domain: '127.0.0.1',\n        path: '/',\n        httpOnly: true,\n        secure: true,\n      },\n      // this cookie expires in a day\n      {\n        name: 'testcookie2', \n        value: '2', \n        sameSite: 'Lax', \n        domain: '127.0.0.1', \n        path: '/', \n        expires: dayAfter,\n      },\n      // this cookie expires in the past, so it will be removed.\n      {\n        name: 'testcookie3',\n        value: '3',\n        sameSite: 'Lax',\n        domain: '127.0.0.1',\n        path: '/',\n        expires: dayBefore\n      }\n    ]);\n    let cookies = await context.cookies();\n    await check(cookies.length, {\n      'number of cookies should be 2': n => n === 2,\n    });\n    await check(cookies[0], {\n      'cookie 1 name should be testcookie': c => c.name === 'testcookie',\n      'cookie 1 value should be 1': c => c.value === '1',\n      'cookie 1 should be session cookie': c => c.expires === -1,\n      'cookie 1 should have domain': c => c.domain === '127.0.0.1',\n      'cookie 1 should have path': c => c.path === '/',\n      'cookie 1 should have sameSite': c => c.sameSite == 'Strict',\n      'cookie 1 should be httpOnly': c => c.httpOnly === true,\n      'cookie 1 should be secure': c => c.secure === true,\n    });\n    await check(cookies[1], {\n      'cookie 2 name should be testcookie2': c => c.name === 'testcookie2',\n      'cookie 2 value should be 2': c => c.value === '2',\n    });\n\n    // let's add more cookies to filter by urls.\n    await context.addCookies([\n      {\n        name: \"foo\",\n        value: \"42\",\n        sameSite: \"Strict\",\n        url: \"http://foo.com\",\n      },\n      {\n        name: \"bar\",\n        value: \"43\",\n        sameSite: \"Lax\",\n        url: \"https://bar.com\",\n      },\n      {\n        name: \"baz\",\n        value: \"44\",\n        sameSite: \"Lax\",\n        url: \"https://baz.com\",\n      },\n    ]);\n    cookies = await context.cookies(\"http://foo.com\", \"https://baz.com\");\n    await check(cookies.length, {\n      'number of filtered cookies should be 2': n => n === 2,\n    });\n    await check(cookies[0], {\n      'the first filtered cookie name should be foo': c => c.name === 'foo',\n      'the first filtered cookie value should be 42': c => c.value === '42',\n    });\n    await check(cookies[1], {\n      'the second filtered cookie name should be baz': c => c.name === 'baz',\n      'the second filtered cookie value should be 44': c => c.value === '44',\n    });\n\n    // clear cookies\n    await context.clearCookies();\n    await check(await context.cookies(), {\n      'number of cookies should be zero': c => c.length === 0,\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/device_emulation.js",
    "content": "import { browser, devices } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const device = devices['iPhone X'];\n  // The spread operator is currently unsupported by k6's Babel, so use\n  // Object.assign instead to merge browser context and device options.\n  // See https://github.com/grafana/k6/issues/2296\n  const options = Object.assign({ locale: 'es-ES' }, device);\n  const context = await browser.newContext(options);\n  const page = await context.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/', { waitUntil: 'networkidle' });\n    const dimensions = await page.evaluate(() => {\n      return {\n        width: document.documentElement.clientWidth,\n        height: document.documentElement.clientHeight,\n        deviceScaleFactor: window.devicePixelRatio\n      };\n    });\n\n    await check(dimensions, {\n      'width': d => d.width === device.viewport.width,\n      'height': d => d.height === device.viewport.height,\n      'scale': d => d.deviceScaleFactor === device.deviceScaleFactor,\n    });\n\n    if (!__ENV.K6_BROWSER_HEADLESS) {\n      await page.waitForTimeout(10000);\n    }\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/dispatch.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/', { waitUntil: 'networkidle' });\n\n    const contacts = page.getByRole('link', { name: '/contacts.php' });\n    await contacts.dispatchEvent(\"click\");\n\n    await check(page.locator('h3'), {\n      'header': async lo => {\n        const text = await lo.textContent();\n        return text == 'Contact us';\n      }\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/elementstate.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  // Inject page content\n  await page.setContent(`\n    <div class=\"visible\">Hello world</div>\n    <div style=\"display:none\" class=\"hidden\"></div>\n    <div class=\"editable\" editable>Edit me</div>\n    <input type=\"checkbox\" enabled class=\"enabled\">\n    <input type=\"checkbox\" disabled class=\"disabled\">\n    <input type=\"checkbox\" checked class=\"checked\">\n    <input type=\"checkbox\" class=\"unchecked\">\n  `);\n\n  // Check state\n  await check(page, {\n    'is visible': async p => {\n      const e = await p.$('.visible');\n      return await e.isVisible();\n    },\n    'is hidden': async p => {\n      const e = await p.$('.hidden');\n      return await e.isHidden()\n    },\n    'is editable': async p => {\n      const e = await p.$('.editable');\n      return await e.isEditable();\n    },\n    'is enabled': async p => {\n      const e = await p.$('.enabled');\n      return await e.isEnabled();\n    },\n    'is disabled': async p => {\n      const e = await p.$('.disabled');\n      return await e.isDisabled();\n    },\n    'is checked': async p => {\n      const e = await p.$('.checked');\n      return await e.isChecked();\n    },\n    'is unchecked': async p => {\n      const e = await p.$('.unchecked');\n      return !await e.isChecked();\n    }\n  });\n\n  // Change state and check again\n  await check(page, {\n    'is unchecked checked': async p => {\n      const e = await p.$(\".unchecked\");\n      await e.setChecked(true);\n      return e.isChecked();\n    },\n    'is checked unchecked': async p => {\n      const e = await p.$(\".checked\");\n      await e.setChecked(false);\n      return !await e.isChecked();\n    }\n  });\n\n  await page.close();\n}\n"
  },
  {
    "path": "examples/browser/evaluate.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.goto(\"https://quickpizza.grafana.com/test.k6.io/\", { waitUntil: \"load\" });\n\n    // calling evaluate without arguments\n    await check(page, {\n      'result should be 210': async p => {\n        const n = await p.evaluate(() => 5 * 42);\n        return n == 210;\n      }\n    });\n\n    // calling evaluate with arguments\n    await check(page, {\n      'result should be 25': async p => {\n        const n = await p.evaluate((x, y) => x * y, 5, 5);\n        return n == 25;\n      }\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/fillform.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    // Goto front page, find login link and click it\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/', { waitUntil: 'networkidle' });\n    await Promise.all([\n      page.waitForNavigation(),\n      page.getByRole('link', {name: '/my_messages.php'}).click(),\n    ]);\n\n    // Enter login credentials and login\n    await page.locator('input[name=\"login\"]').type('admin');\n    await page.locator('input[name=\"password\"]').type(\"123\");\n\n    // We expect the form submission to trigger a navigation, so to prevent a\n    // race condition, setup a waiter concurrently while waiting for the click\n    // to resolve.\n    await Promise.all([\n      page.waitForNavigation(),\n      page.getByText('Go!').click(),\n    ]);\n\n    await check(page.locator('h2'), {\n      'header': async lo => {\n        return await lo.textContent() == 'Welcome, admin!'\n      }\n    });\n\n    // Check whether we receive cookies from the logged site.\n    await check(context, {\n      'session cookie is set': async ctx => {\n        const cookies = await ctx.cookies();\n        return cookies.find(c => c.name == 'AWSALB') !== undefined;\n      }\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/framelocator.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'k6';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  try {\n    // create a page with an iframe\n    await page.setContent(`\n      <html>\n        <body>\n          <h1>Main Page</h1>\n          <iframe id=\"my-iframe\" srcdoc=\"\n            <html>\n              <body>\n                <h2>Inside iframe</h2>\n                <button id='submit-btn'>Submit</button>\n              </body>\n            </html>\n          \"></iframe>\n        </body>\n      </html>\n    `);\n\n    /*\n    The frameLocator() method is a shorthand for locator(selector).contentFrame().\n    Both approaches are equivalent:\n\n      // Using frameLocator():\n      const button = page.frameLocator('#my-iframe').locator('#submit-btn');\n\n      // Using locator().contentFrame():\n      const frame = page.locator('#my-iframe').contentFrame();\n      const button = frame.locator('#submit-btn');\n    */\n\n    const button = page.frameLocator('#my-iframe').locator('#submit-btn');\n    const buttonText = await button.textContent();\n    console.log(`Button text: ${buttonText}`);\n\n    check(buttonText, {\n      'found button inside iframe': (text) => text === 'Submit',\n    });\n\n    const heading = await page.frameLocator('#my-iframe').getByRole('heading').textContent();\n    console.log(`Heading inside iframe: ${heading}`);\n\n    check(heading, {\n      'found heading inside iframe': (text) => text === 'Inside iframe',\n    });\n\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/getattribute.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.goto('https://googlechromelabs.github.io/dark-mode-toggle/demo/', {\n      waitUntil: 'load',\n    });\n    await check(page, {\n      \"GetAttribute('mode')\": async p => {\n        const e = await p.$('#dark-mode-toggle-3');\n        return await e.getAttribute('mode') === 'light';\n      }\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/grant_permission.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  // grant camera and microphone permissions to the\n  // new browser context.\n  const context = await browser.newContext({\n    permissions: [\"camera\", \"microphone\"],\n  });\n\n  const page = await context.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/');\n    await page.screenshot({ path: `example-chromium.png` });\n    await context.clearPermissions();\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/hosts.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  hosts: { 'quickpizza.grafana.com': '127.0.0.254' },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n};\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    const res = await page.goto('http://quickpizza.grafana.com/test.k6.io/', {\n      waitUntil: 'load'\n    });\n    await check(res, {\n      'null response': r => r === null,\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/keyboard.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  }\n}\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  await page.goto('https://quickpizza.grafana.com/my_messages.php', { waitUntil: 'networkidle' });\n\n  const userInput = page.locator('input[name=\"login\"]');\n  await userInput.click();\n  await page.keyboard.type(\"admin\");\n\n  const pwdInput = page.locator('input[name=\"password\"]');\n  await pwdInput.click();\n  await page.keyboard.type(\"123\");\n\n  await page.keyboard.press('Enter'); // submit\n  await page.waitForNavigation();\n\n  await page.close();\n}\n"
  },
  {
    "path": "examples/browser/locator.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.goto(\"https://quickpizza.grafana.com/flip_coin.php\", {\n      waitUntil: \"networkidle\",\n    })\n\n    /*\n    In this example, we will use two locators, matching a\n    different betting button on the page. If you were to query\n    the buttons once and save them as below, you would see an\n    error after the initial navigation. Try it!\n\n      const heads = page.$(\"input[value='Bet on heads!']\");\n      const tails = page.$(\"input[value='Bet on tails!']\");\n\n    The Locator API allows you to get a fresh element handle each\n    time you use one of the locator methods. And, you can carry a\n    locator across frame navigations. Let's create two locators;\n    each locates a button on the page.\n    */\n    const heads = page.getByRole(\"button\", { name: \"Bet on heads!\" });\n    const tails = page.getByRole(\"button\", { name: \"Bet on tails!\" });\n\n    const currentBet = page.getByText(/Your bet\\: .*/);\n\n    // In the following Promise.all the tails locator clicks\n    // on the tails button by using the locator's selector.\n    // Since clicking on each button causes page navigation,\n    // waitForNavigation is needed -- this is because the page\n    // won't be ready until the navigation completes.\n    // Setting up the waitForNavigation first before the click\n    // is important to avoid race conditions.\n    await Promise.all([\n      page.waitForNavigation(),\n      tails.click(),\n    ]);\n    console.log(await currentBet.innerText());\n    // the heads locator clicks on the heads button\n    // by using the locator's selector.\n    await Promise.all([\n      page.waitForNavigation(),\n      heads.click(),\n    ]);\n    console.log(await currentBet.innerText());\n    await Promise.all([\n      page.waitForNavigation(),\n      tails.click(),\n    ]);\n    console.log(await currentBet.innerText());\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/locator_filter.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios:  {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium'\n        }\n      }\n    }\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const page = await browser.newPage();\n\n  await page.setContent(`\n    <ul>\n      <li>\n        <h3>Product 1</h3>\n        <button>Add to cart 1</button>\n      </li>\n      <li>\n        <h3>Product 2</h3>\n        <button>Add to cart 2</button>\n      </li>\n    </ul>\n  `);\n\n  // Filter the 2nd item by filtering items with the \"Product 2\" text.\n  await check(page, {\n    'Filter the Add to cart 2 button': async p => {\n      const txt = await p\n        .getByRole('listitem')\n        .filter({ hasText: 'Product 2' })\n        .first()\n        .textContent();\n      return txt.includes(`Add to cart 2`);\n    }\n  });\n\n  // Using a regex, filter the 1st item by filtering items without the \"Product 2\" text.\n  await check(page, {\n    'Filter the Add to cart 1 button': async p => {\n      const txt = await p\n        .getByRole('listitem')\n        .filter({ hasNotText: /Product 2/ })\n        .first()\n        .textContent();\n      return txt.includes(`Add to cart 1`);\n    }\n  });\n\n  // Filtering with the locator.locator options instead of the locator.filter method.\n  await check(page, {\n    'Filter the Add to cart 1 button with locator options': async p => {\n      const txt = await p\n        .getByRole('list')\n        .locator('li', { hasText: 'Product' })\n        .locator('button', { hasText: /Add to cart 1/ })\n        .first()\n        .textContent();\n      return txt.includes(`Add to cart 1`);\n    }\n  });\n\n  await page.close();\n}\n"
  },
  {
    "path": "examples/browser/locator_pom.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\n/*\nPage Object Model is a well-known pattern to abstract a web page.\n\nThe Locator API enables using the Page Object Model pattern to organize\nand simplify test code.\n\nNote: For comparison, you can see another example that does not use\nthe Page Object Model pattern in locator.js.\n*/\nexport class Bet {\n  constructor(page) {\n    this.page = page;\n    this.headsButton = page.getByRole(\"button\", { name: \"Bet on heads!\" });\n    this.tailsButton = page.getByRole(\"button\", { name: \"Bet on tails!\" });\n    this.currentBet = page.getByText(/Your bet\\: .*/);\n  }\n\n  goto() {\n    return this.page.goto(\"https://quickpizza.grafana.com/flip_coin.php\", { waitUntil: \"networkidle\" });\n  }\n\n  heads() {\n    return Promise.all([\n      this.page.waitForNavigation(),\n      this.headsButton.click(),\n    ]);\n  }\n\n  tails() {\n    return Promise.all([\n      this.page.waitForNavigation(),\n      this.tailsButton.click(),\n    ]);\n  }\n\n  current() {\n    return this.currentBet.innerText();\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  const bet = new Bet(page);\n  try {\n    await bet.goto()\n    await bet.tails();\n    console.log(\"Current bet:\", await bet.current());\n    await bet.heads();\n    console.log(\"Current bet:\", await bet.current());\n    await bet.tails();\n    console.log(\"Current bet:\", await bet.current());\n    await bet.heads();\n    console.log(\"Current bet:\", await bet.current());\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/mouse.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  }\n}\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  await page.goto('https://quickpizza.grafana.com/test.k6.io/', { waitUntil: 'networkidle' });\n\n  // Obtain ElementHandle for news link and navigate to it\n  // by clicking in the 'a' element's bounding box\n  const newsLinkBox = await page.$('a[href=\"/news.php\"]').then(e => e.boundingBox());\n\n  await Promise.all([\n    page.waitForNavigation(),\n    page.mouse.click(newsLinkBox.x + newsLinkBox.width / 2, newsLinkBox.y)\n  ]);\n\n  await page.close();\n}\n"
  },
  {
    "path": "examples/browser/multiple-scenario.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    messages: {\n      executor: 'constant-vus',\n      exec: 'messages',\n      vus: 1,\n      duration: '2s',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n    news: {\n      executor: 'per-vu-iterations',\n      exec: 'news',\n      vus: 1,\n      iterations: 2,\n      maxDuration: '5s',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    browser_web_vital_fcp: ['max < 5000'],\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport async function messages() {\n  const page = await browser.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/my_messages.php', { waitUntil: 'networkidle' });\n  } finally {\n    await page.close();\n  }\n}\n\nexport async function news() {\n  const page = await browser.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/news.php', { waitUntil: 'networkidle' });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/page_waitForEvent.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    browser: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function() {\n  const page = await browser.newPage();\n\n  try {\n    // Wait for console event with predicate function shorthand\n    const consolePromise = page.waitForEvent('console', (msg) => msg.text().includes('hello'));\n\n    // Evaluate triggers console.log which will emit console events\n    await page.evaluate(() => {\n      console.log('some other message');\n      console.log('hello from page');\n    });\n\n    // Only matches the message containing 'hello'\n    const msg = await consolePromise;\n    console.log(`Console message received: ${msg.text()}`);\n\n    // Wait for response event with options object\n    const responsePromise = page.waitForEvent('response', {\n      predicate: (res) => res.url().includes('example.com'),\n      timeout: 5000,\n    });\n\n    await page.goto('https://example.com');\n\n    const response = await responsePromise;\n    console.log(`Response received: ${response.url()}`);\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/pageon-metric.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function() {\n  const page = await browser.newPage();\n\n  page.on('metric', (metric) => {\n    metric.tag({\n      name:'test',\n      matches: [\n        {url: /^https:\\/\\/test\\.k6\\.io\\/\\?q=[0-9a-z]+$/, method: 'GET'},\n      ]\n    });\n  });\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/?q=abc123');\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/?q=def456');\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/pageon-request.js",
    "content": "import { browser } from 'k6/browser'\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function () {\n  const page = await browser.newPage()\n\n  // registers a handler that logs all requests made by the page\n  page.on('request', async request => console.log(request.url()))\n\n  await page.goto('https://quickpizza.grafana.com/', { waitUntil: 'networkidle' })\n\n  await page.close();\n}"
  },
  {
    "path": "examples/browser/pageon-requestfailed.js",
    "content": "import { browser } from 'k6/browser'\n\nexport const options = {\n    scenarios: {\n        ui: {\n            executor: 'shared-iterations',\n            options: {\n                browser: {\n                    type: 'chromium',\n                },\n            },\n        },\n    },\n}\n\nexport default async function () {\n    const page = await browser.newPage()\n\n    // Register a handler for failed requests (e.g., DNS errors, connection refused)\n    page.on('requestfailed', request => {\n        const failure = request.failure()\n        console.log(`Request failed: ${request.url()}`)\n        console.log(`  Method: ${request.method()}`)\n        console.log(`  Error: ${failure ? failure.errorText : 'unknown'}`)\n    })\n\n    try {\n        // This will trigger a requestfailed event due to DNS failure\n        await page.goto('https://does-not-exist.invalid/')\n    } catch (e) {\n        // Navigation error expected\n    }\n\n    await page.close()\n}\n"
  },
  {
    "path": "examples/browser/pageon-requestfinished.js",
    "content": "import { browser } from 'k6/browser'\n\nexport const options = {\n\tscenarios: {\n\t\tui: {\n\t\t\texecutor: 'shared-iterations',\n\t\t\toptions: {\n\t\t\t\tbrowser: {\n\t\t\t\t\ttype: 'chromium',\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n}\n\nexport default async function () {\n\tconst page = await browser.newPage()\n\n\t// Track all completed requests\n\tconst finishedRequests = []\n\n\tpage.on('requestfinished', request => {\n\t\tfinishedRequests.push({\n\t\t\turl: request.url(),\n\t\t\tmethod: request.method(),\n\t\t\tresourceType: request.resourceType(),\n\t\t})\n\n\t\tconsole.log(`✓ Request finished: ${request.method()} ${request.url()}`)\n\t})\n\n\tawait page.goto('https://quickpizza.grafana.com/', { waitUntil: 'networkidle' })\n\n\tconsole.log(`Total requests completed: ${finishedRequests.length}`)\n\n\t// Log all API requests\n\tconst apiRequests = finishedRequests.filter(r => r.url.includes('/api/'))\n\tconsole.log(`API requests: ${apiRequests.length}`)\n\n\tawait page.close()\n}\n"
  },
  {
    "path": "examples/browser/pageon.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const page = await browser.newPage();\n  \n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/');\n\n    page.on('console', async msg => check(msg, {\n      'assert console message type': msg =>\n        msg.type() == 'log',\n      'assert console message text': msg =>\n        msg.text() == 'this is a console.log message 42',\n      'assert console message first argument': async msg => {\n        const arg1 = await msg.args()[0].jsonValue();\n        return arg1 == 'this is a console.log message';\n      },\n      'assert console message second argument': async msg => {\n        const arg2 = await msg.args()[1].jsonValue();\n        return arg2 == 42;\n      }\n    }));\n\n    await page.evaluate(() => console.log('this is a console.log message', 42));\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/querying.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/');\n\n    await check(page, {\n      'Title with CSS selector': async p => {\n        const e = await p.$('header h1.title');\n        return await e.textContent() === 'QuickPizza Legacy';\n      },\n      'Title with XPath selector': async p => {\n        const e = await p.$('//header//h1[@class=\"title\"]');\n        return await e.textContent() === 'QuickPizza Legacy';\n      }\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/route.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'k6';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  try {\n    await page.route(\n      'https://quickpizza.grafana.com/api/tools',\n      function (route) {\n        route.abort();\n      }\n    );\n\n    await page.route(/(\\.png$)|(\\.jpg$)/, function (route) {\n      route.abort();\n    });\n\n    page.on('request', function (request) {\n      console.log('on request', 'url', request.url());\n    });\n\n    page.on('response', function (response) {\n      console.log('on response', 'url', response.url());\n    });\n\n    // Test waitForResponse alongside page.on('response')\n    const responsePromise = page.waitForResponse('https://quickpizza.grafana.com/');\n\n    await page.goto('https://quickpizza.grafana.com/', {\n      waitUntil: 'networkidle',\n    });\n\n    const response = await responsePromise;\n\n    // Check that the main page loaded successfully\n    check(response, {\n      'main page status is 200': (r) => r.status() === 200,\n      'main page URL is correct': (r) => r.url() === 'https://quickpizza.grafana.com/',\n    });\n\n    // Test waitForResponse with user interaction\n    const pizzaResponsePromise = page.waitForResponse('https://quickpizza.grafana.com/api/pizza');\n\n    await page.getByRole('button', { name: /pizza/i }).click();\n\n    const pizzaResponse = await pizzaResponsePromise;\n\n    // Check that the pizza API call was successful\n    check(pizzaResponse, {\n      'pizza API status is 200': (r) => r.status() === 200,\n      'pizza API URL is correct': (r) => r.url() === 'https://quickpizza.grafana.com/api/pizza',\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/route_continue.js",
    "content": "import { sleep } from 'k6';\nimport { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  try {\n    await page.route(/.*\\/api\\/pizza/, function (route) {\n      route.continue({\n        postData: JSON.stringify({\n          customName: 'My Pizza',\n        }),\n      });\n    });\n\n    await page.goto('https://quickpizza.grafana.com/');\n\n    await page.getByRole('button', { name: 'pizza, please' }).click();\n    sleep(1);\n\n    const e = page.getByText('Name:')\n    check(null, {\n      pizzaName: await e.innerText() === 'Name: My Pizza',\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/screenshot.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n  \n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/');\n    await page.screenshot({ path: 'screenshot.png' });\n    // TODO: Assert this somehow. Upload as CI artifact or just an external `ls`?\n    // Maybe even do a fuzzy image comparison against a preset known good screenshot?\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/shadowdom.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const page = await browser.newPage();\n  \n  await page.setContent(\"<html><head><style></style></head><body>hello!</body></html>\")\n\n  await page.evaluate(() => {\n    const shadowRoot = document.createElement('div');\n    shadowRoot.id = 'shadow-root';\n    shadowRoot.attachShadow({mode: 'open'});\n    shadowRoot.shadowRoot.innerHTML = '<p id=\"shadow-dom\">Shadow DOM</p>';\n    document.body.appendChild(shadowRoot);\n  });\n\n  await check(page.locator('#shadow-dom'), {\n    'shadow element exists': e => e !== null,\n    'shadow element text is correct': async e => {\n      return await e.innerText() === 'Shadow DOM';\n    }\n  });\n\n  await page.close();\n}\n"
  },
  {
    "path": "examples/browser/throttle.js",
    "content": "import { browser, networkProfiles } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    normal: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n      exec: 'normal',\n    },\n    networkThrottled: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n      exec: 'networkThrottled',\n      startTime: \"10s\",\n    },\n    cpuThrottled: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n      exec: 'cpuThrottled',\n      startTime: \"5s\",\n    },\n  },\n  thresholds: {\n    'browser_http_req_duration{scenario:normal}': ['p(99)<3000'],\n    'browser_http_req_duration{scenario:networkThrottled}': ['p(99)<6000'],\n    'iteration_duration{scenario:normal}': ['p(99)<5000'],\n    'iteration_duration{scenario:cpuThrottled}': ['p(99)<10000'],\n  },\n}\n\nexport async function normal() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/', { waitUntil: 'networkidle' });\n  } finally {\n    await page.close();\n  }\n}\n\nexport async function networkThrottled() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.throttleNetwork(networkProfiles[\"Slow 3G\"]);\n\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/', { waitUntil: 'networkidle' });\n  } finally {\n    await page.close();\n  }\n}\n\nexport async function cpuThrottled() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.throttleCPU({ rate: 4 });\n\n    await page.goto('https://quickpizza.grafana.com/test.k6.io/', { waitUntil: 'networkidle' });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/browser/touchscreen.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  }\n}\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  await page.goto(\"https://quickpizza.grafana.com/test.k6.io/\", { waitUntil: \"networkidle\" });\n\n  // Obtain ElementHandle for news link and navigate to it\n  // by tapping in the 'a' element's bounding box\n  const newsLinkBox = await page.$('a[href=\"/news.php\"]').then((e) => e.boundingBox());\n\n  // Wait until the navigation is done before closing the page.\n  // Otherwise, there will be a race condition between the page closing\n  // and the navigation.\n  await Promise.all([\n    page.waitForNavigation(),\n    page.touchscreen.tap(newsLinkBox.x + newsLinkBox.width / 2, newsLinkBox.y),\n  ]);\n\n  await page.close();\n}\n"
  },
  {
    "path": "examples/browser/useragent.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  let context = await browser.newContext({\n    userAgent: 'k6 test user agent',\n  })\n  let page = await context.newPage();\n  await check(page, {\n    'user agent is set': async p => {\n        const userAgent = await p.evaluate(() => navigator.userAgent);\n        return userAgent.includes('k6 test user agent');\n    }\n  });\n  await page.close();\n  await context.close();\n\n  context = await browser.newContext();\n  check(context.browser(), {\n    'user agent does not contain headless': b => {\n        return b.userAgent().includes('Headless') === false;\n    }\n  });\n\n  page = await context.newPage();\n  await check(page, {\n    'chromium user agent does not contain headless': async p => {\n        const userAgent = await p.evaluate(() => navigator.userAgent);\n        return userAgent.includes('Headless') === false;\n    }\n  });\n  await page.close();\n}\n"
  },
  {
    "path": "examples/browser/waitForEvent.js",
    "content": "import { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    browser: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function() {\n  const context = await browser.newContext()\n\n  // We want to wait for two page creations before carrying on.\n  var counter = 0\n  const promise = context.waitForEvent(\"page\", { predicate: page => {\n    if (++counter == 2) {\n      return true\n    }\n    return false\n  } })\n  \n  // Now we create two pages.\n  const page = await context.newPage();\n  const page2 = await context.newPage();\n\n  // We await for the page creation events to be processed and the predicate\n  // to pass.\n  await promise\n  console.log('predicate passed')\n\n  await page.close()\n  await page2.close();\n};\n"
  },
  {
    "path": "examples/browser/waitforfunction.js",
    "content": "import { browser } from 'k6/browser';\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n  thresholds: {\n    checks: [\"rate==1.0\"]\n  }\n}\n\nexport default async function() {\n  const context = await browser.newContext();\n  const page = await context.newPage();\n\n  try {\n    await page.evaluate(() => {\n      setTimeout(() => {\n        const el = document.createElement('h1');\n        el.innerHTML = 'Hello';\n        document.body.appendChild(el);\n      }, 1000);\n    });\n\n    const e = await page.waitForFunction(\n      \"document.querySelector('h1')\", {\n        polling: 'mutation',\n        timeout: 2000\n      }\n    );\n    await check(e, {\n      'waitForFunction successfully resolved': async e => {\n        return await e.innerHTML() === 'Hello';\n      }\n    });\n  } finally {\n    await page.close();\n  }\n}\n"
  },
  {
    "path": "examples/config.json",
    "content": "{\n  \"vus\": 100,\n  \"collectors\": {\n    \"influxdb\": {\n      \"tagsAsFields\": [\"vu\",\"iter\", \"url\", \"name\"]\n    }\n  }\n}\n"
  },
  {
    "path": "examples/cookies.js",
    "content": "import http from \"k6/http\";\nimport { check, group } from \"k6\";\n\nexport let options = {\n    maxRedirects: 3\n};\n\nexport default function() {\n    // VU cookie jar\n    group(\"Simple cookies send with VU jar\", function() {\n        let cookies = {\n            name: \"value1\",\n            name2: \"value2\"\n        };\n        let res = http.get(\"http://httpbin.org/cookies\", { cookies: cookies });\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"has cookie 'name'\": (r) => r.json().cookies.name.length > 0,\n            \"has cookie 'name2'\": (r) => r.json().cookies.name2.length > 0\n        });\n\n        // Since the cookies are set as \"request cookies\" they won't be added to VU cookie jar\n        let vuJar = http.cookieJar();\n        let cookiesForURL = vuJar.cookiesForURL(res.url);\n        check(null, {\n            \"vu jar doesn't have cookie 'name'\": () => cookiesForURL.name === undefined,\n            \"vu jar doesn't have cookie 'name2'\": () => cookiesForURL.name2 === undefined\n        });\n    });\n\n    group(\"Simple cookies set with VU jar\", function() {\n        // Since this request redirects the `res.cookies` property won't contain the cookies\n        let res = http.get(\"http://httpbin.org/cookies/set?name3=value3&name4=value4\");\n        check(res, {\n            \"status is 200\": (r) => r.status === 200\n        });\n\n        // Make sure cookies have been added to VU cookie jar\n        let vuJar = http.cookieJar();\n        let cookiesForURL = vuJar.cookiesForURL(res.url);\n        check(null, {\n            \"vu jar has cookie 'name3'\": () => cookiesForURL.name3.length > 0,\n            \"vu jar has cookie 'name4'\": () => cookiesForURL.name4.length > 0\n        });\n    });\n\n    // Local cookie jar\n    group(\"Simple cookies send with local jar\", function() {\n        let jar = new http.CookieJar();\n        let cookies = {\n            name5: \"value5\",\n            name6: \"value6\"\n        };\n        let res = http.get(\"http://httpbin.org/cookies\", { cookies: cookies, jar: jar });\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"has cookie 'name5'\": (r) => r.json().cookies.name5.length > 0,\n            \"has cookie 'name6'\": (r) => r.json().cookies.name6.length > 0\n        });\n\n        // Since the cookies are set as \"request cookies\" they won't be added to VU cookie jar\n        let cookiesForURL = jar.cookiesForURL(res.url);\n        check(null, {\n            \"local jar doesn't have cookie 'name5'\": () => cookiesForURL.name5 === undefined,\n            \"local jar doesn't have cookie 'name6'\": () => cookiesForURL.name6 === undefined\n        });\n\n        // Make sure cookies have NOT been added to VU cookie jar\n        let vuJar = http.cookieJar();\n        cookiesForURL = vuJar.cookiesForURL(res.url);\n        check(null, {\n            \"vu jar doesn't have cookie 'name5'\": () => cookiesForURL.name === undefined,\n            \"vu jar doesn't have cookie 'name6'\": () => cookiesForURL.name2 === undefined\n        });\n    });\n\n    group(\"Advanced send with local jar\", function() {\n        let jar = new http.CookieJar();\n        jar.set(\"http://httpbin.org/cookies\", \"name7\", \"value7\");\n        jar.set(\"http://httpbin.org/cookies\", \"name8\", \"value8\");\n        let res = http.get(\"http://httpbin.org/cookies\", { jar: jar });\n        let cookiesForURL = jar.cookiesForURL(res.url);\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"has cookie 'name7'\": (r) => r.json().cookies.name7.length > 0,\n            \"has cookie 'name8'\": (r) => r.json().cookies.name8.length > 0\n        });\n\n        cookiesForURL = jar.cookiesForURL(res.url);\n        check(null, {\n            \"local jar has cookie 'name7'\": () => cookiesForURL.name7.length > 0,\n            \"local jar has cookie 'name8'\": () => cookiesForURL.name8.length > 0\n        });\n\n        // Make sure cookies have NOT been added to VU cookie jar\n        let vuJar = http.cookieJar();\n        cookiesForURL = vuJar.cookiesForURL(res.url);\n        check(null, {\n            \"vu jar doesn't have cookie 'name7'\": () => cookiesForURL.name7 === undefined,\n            \"vu jar doesn't have cookie 'name8'\": () => cookiesForURL.name8 === undefined\n        });\n    });\n\n    group(\"Advanced cookie attributes\", function() {\n        let jar = http.cookieJar();\n        jar.set(\"http://httpbin.org/cookies\", \"name9\", \"value9\", { domain: \"httpbin.org\", path: \"/cookies\" });\n\n        let res = http.get(\"http://httpbin.org/cookies\", { jar: jar });\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"has cookie 'name9'\": (r) => r.json().cookies.name9 === \"value9\"\n        });\n\n        jar.set(\"http://httpbin.org/cookies\", \"name10\", \"value10\", { domain: \"example.com\", path: \"/\" });\n        res = http.get(\"http://httpbin.org/cookies\", { jar: jar });\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"doesn't have cookie 'name10'\": (r) => r.json().cookies.name10 === undefined\n        });\n    });\n}\n"
  },
  {
    "path": "examples/crypto.js",
    "content": "import crypto from 'k6/crypto';\n\nexport default function() {\n    // Shorthand API\n    let hash = crypto.sha1(\"some text\", \"hex\");\n    console.log(hash);\n\n    // Flexible API\n    let hasher = crypto.createHash(\"sha1\")\n    hasher.update(\"some other text\")\n    console.log(hasher.digest(\"hex\"))\n    console.log(hasher.digest(\"base64\"))\n}\n"
  },
  {
    "path": "examples/custom_metrics.js",
    "content": "import http from \"k6/http\";\nimport { Counter, Gauge, Rate, Trend } from \"k6/metrics\";\nimport { check } from \"k6\";\n\n/*\n * Custom metrics are useful when you want to track something that is not\n * provided out of the box.\n *\n * There are four types of custom metrics: Counter, Gauge, Rate and Trend.\n *\n * - Counter: a sum of all values added to the metric\n * - Gauge: a value that change to whatever you set it to\n * - Rate: rate of \"truthiness\", how many values out of total are !=0\n * - Trend: time series, all values are recorded, statistics can be calculated\n *          on it\n */\n\nlet myCounter = new Counter(\"my_counter\");\nlet myGauge = new Gauge(\"my_gauge\");\nlet myRate = new Rate(\"my_rate\");\nlet myTrend = new Trend(\"my_trend\");\n\nlet maxResponseTime = 0.0;\n\nexport default function () {\n    let res = http.get(\"http://httpbin.org/\");\n    let passed = check(res, { \"status is 200\": (r) => r.status === 200 });\n\n    // Add one for number of requests\n    myCounter.add(1);\n    console.log(myCounter.name, \" is config ready\")\n\n    // Set max response time seen\n    maxResponseTime = Math.max(maxResponseTime, res.timings.duration);\n    myGauge.add(maxResponseTime);\n\n    // Add check success or failure to keep track of rate\n    myRate.add(passed);\n\n    // Keep track of TCP-connecting and TLS handshaking part of the response time\n    myTrend.add(res.timings.connecting + res.timings.tls_handshaking);\n}\n"
  },
  {
    "path": "examples/docker-compose/influxdb-v1/README.md",
    "content": "# InfluxDB v1\n\nThis example shows how to use the k6 performance test with InfluxDB v1.\n\n## Prerequisites\n\n- Docker\n- Docker Compose\n\n## Run the example\n\n```bash\ndocker-compose up -d\n```\n\n## Access the k6 performance test dashboard\n\nOpen the k6 performance test dashboard in your browser http://localhost:3000/d/Le2Ku9NMk/k6-performance-test\n\n## Run the k6 test\n\nThe test will run for 20 iterations and use 5 virtual users.\n\n```bash\nk6 -i 20 --vus 5 --out influxdb=http://localhost:8086/k6 run script.js\n```\n"
  },
  {
    "path": "examples/docker-compose/influxdb-v1/docker-compose.yml",
    "content": "version: '3.4'\n\nnetworks:\n  grafana:\n\nservices:\n  influxdb:\n    image: influxdb:1.8@sha256:299ebda2c7e308dbef42e26ac9b8fd1d9b3bcb8a0aee80c6509aa0219c1d0290\n    networks:\n      - grafana\n    ports:\n      - \"8086:8086\"\n    environment:\n      - INFLUXDB_DB=k6\n\n  grafana:\n    image: grafana/grafana:9.3.8@sha256:a49f7d74630f47507e7e1ba92f6204f3c7b525d17108a90d489294030a9d507a\n    networks:\n      - grafana\n    ports:\n      - \"3000:3000\"\n    environment:\n      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin\n      - GF_AUTH_ANONYMOUS_ENABLED=true\n      - GF_AUTH_BASIC_ENABLED=false\n    volumes:\n      - ./grafana:/etc/grafana/provisioning/\n"
  },
  {
    "path": "examples/docker-compose/influxdb-v1/grafana/dashboards/dashboard.yml",
    "content": "\napiVersion: 1\n\nproviders:\n- name: 'myinfluxdb'\n  orgId: 1\n  folder: ''\n  type: file\n  disableDeletion: false\n  editable: true\n  options:\n    path: /etc/grafana/provisioning/dashboards"
  },
  {
    "path": "examples/docker-compose/influxdb-v1/grafana/dashboards/performance-test-dasboard.json",
    "content": "{\n  \"annotations\": {\n    \"list\": [\n      {\n        \"builtIn\": 1,\n        \"datasource\": \"-- Grafana --\",\n        \"enable\": true,\n        \"hide\": true,\n        \"iconColor\": \"rgba(0, 211, 255, 1)\",\n        \"name\": \"Annotations & Alerts\",\n        \"type\": \"dashboard\"\n      }\n    ]\n  },\n  \"editable\": true,\n  \"gnetId\": null,\n  \"graphTooltip\": 0,\n  \"id\": 2,\n  \"links\": [],\n  \"panels\": [\n    {\n      \"aliasColors\": {},\n      \"bars\": true,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"myinfluxdb\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"fill\": 1,\n      \"fillGradient\": 0,\n      \"gridPos\": {\n        \"h\": 9,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 0\n      },\n      \"hiddenSeries\": false,\n      \"id\": 2,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"nullPointMode\": \"null\",\n      \"options\": {\n        \"dataLinks\": []\n      },\n      \"percentage\": false,\n      \"pointradius\": 1,\n      \"points\": true,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": true,\n      \"targets\": [\n        {\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$__interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"measurement\": \"http_req_duration\",\n          \"orderByTime\": \"ASC\",\n          \"policy\": \"default\",\n          \"query\": \"SELECT mean(\\\"value\\\") FROM \\\"http_req_duration\\\" WHERE $timeFilter GROUP BY time($__interval) fill(null)\",\n          \"rawQuery\": false,\n          \"refId\": \"A\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"value\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              }\n            ]\n          ],\n          \"tags\": []\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeRegions\": [],\n      \"timeShift\": null,\n      \"title\": \"http-req duration\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    },\n    {\n      \"aliasColors\": {},\n      \"bars\": true,\n      \"dashLength\": 10,\n      \"dashes\": false,\n      \"datasource\": \"myinfluxdb\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"custom\": {}\n        },\n        \"overrides\": []\n      },\n      \"fill\": 3,\n      \"fillGradient\": 0,\n      \"gridPos\": {\n        \"h\": 9,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 0\n      },\n      \"hiddenSeries\": false,\n      \"id\": 3,\n      \"legend\": {\n        \"avg\": false,\n        \"current\": false,\n        \"max\": false,\n        \"min\": false,\n        \"show\": true,\n        \"total\": false,\n        \"values\": false\n      },\n      \"lines\": true,\n      \"linewidth\": 1,\n      \"nullPointMode\": \"null\",\n      \"options\": {\n        \"dataLinks\": []\n      },\n      \"percentage\": false,\n      \"pointradius\": 1,\n      \"points\": true,\n      \"renderer\": \"flot\",\n      \"seriesOverrides\": [],\n      \"spaceLength\": 10,\n      \"stack\": false,\n      \"steppedLine\": false,\n      \"targets\": [\n        {\n          \"groupBy\": [\n            {\n              \"params\": [\n                \"$__interval\"\n              ],\n              \"type\": \"time\"\n            },\n            {\n              \"params\": [\n                \"null\"\n              ],\n              \"type\": \"fill\"\n            }\n          ],\n          \"measurement\": \"vus\",\n          \"orderByTime\": \"ASC\",\n          \"policy\": \"default\",\n          \"query\": \"SELECT mean(\\\"value\\\") FROM \\\"http_req_duration\\\" WHERE $timeFilter GROUP BY time($__interval) fill(null)\",\n          \"rawQuery\": false,\n          \"refId\": \"A\",\n          \"resultFormat\": \"time_series\",\n          \"select\": [\n            [\n              {\n                \"params\": [\n                  \"value\"\n                ],\n                \"type\": \"field\"\n              },\n              {\n                \"params\": [],\n                \"type\": \"mean\"\n              }\n            ]\n          ],\n          \"tags\": []\n        }\n      ],\n      \"thresholds\": [],\n      \"timeFrom\": null,\n      \"timeRegions\": [],\n      \"timeShift\": null,\n      \"title\": \"vus\",\n      \"tooltip\": {\n        \"shared\": true,\n        \"sort\": 0,\n        \"value_type\": \"individual\"\n      },\n      \"type\": \"graph\",\n      \"xaxis\": {\n        \"buckets\": null,\n        \"mode\": \"time\",\n        \"name\": null,\n        \"show\": true,\n        \"values\": []\n      },\n      \"yaxes\": [\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        },\n        {\n          \"format\": \"short\",\n          \"label\": null,\n          \"logBase\": 1,\n          \"max\": null,\n          \"min\": null,\n          \"show\": true\n        }\n      ],\n      \"yaxis\": {\n        \"align\": false,\n        \"alignLevel\": null\n      }\n    }\n  ],\n  \"schemaVersion\": 25,\n  \"style\": \"dark\",\n  \"tags\": [],\n  \"templating\": {\n    \"list\": []\n  },\n  \"time\": {\n    \"from\": \"now-5m\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {\n    \"refresh_intervals\": [\n      \"10s\",\n      \"30s\",\n      \"1m\",\n      \"5m\",\n      \"15m\",\n      \"30m\",\n      \"1h\",\n      \"2h\",\n      \"1d\"\n    ]\n  },\n  \"timezone\": \"\",\n  \"title\": \"k6 performance test\",\n  \"uid\": \"Le2Ku9NMk\",\n  \"version\": 2\n}"
  },
  {
    "path": "examples/docker-compose/influxdb-v1/grafana/datasources/datasource.yml",
    "content": "apiVersion: 1\n\ndatasources:\n  - name: myinfluxdb\n    type: influxdb\n    access: proxy\n    database: k6\n    orgId: 1\n    url: http://influxdb:8086\n    isDefault: true\n"
  },
  {
    "path": "examples/docker-compose/influxdb-v1/script.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function () {\n  check(http.get(\"https://quickpizza.grafana.com\"), {\n    \"status is 200\": (r) => r.status == 200,\n    \"protocol is HTTP/2\": (r) => r.proto == \"HTTP/2.0\",\n  });\n}\n"
  },
  {
    "path": "examples/docker-compose/opentelemetry/README.md",
    "content": "# OpenTelemetry Output\n\nThis example demonstrates how to integrate k6 performance testing with OpenTelemetry. The test metrics are sent to an OpenTelemetry collector (OTEL Collector), which forwards them to Prometheus for storage. These metrics can then be visualized using Grafana dashboards.\n\n## Prerequisites\n\n- Docker\n- Docker Compose\n\n## Run the example\n\n```bash\ndocker-compose up -d\n```\n\n## Access the k6 performance test dashboard\n\nOpen the k6 performance test dashboard in your browser http://localhost:3000/d/demo-uid/k6-opentelemetry-prometheus\n\n## Run the k6 test\n\nThis will run the test for 3 minutes with 10 virtual users and send the metrics to the OTEL Collector.\n\n```bash\nK6_OTEL_GRPC_EXPORTER_ENDPOINT=localhost:4317 \\\nK6_OTEL_GRPC_EXPORTER_INSECURE=true \\\nK6_OTEL_METRIC_PREFIX=k6_ \\\nk6 run --tag testid=1 -o experimental-opentelemetry script.js\n```\n"
  },
  {
    "path": "examples/docker-compose/opentelemetry/docker-compose.yml",
    "content": "networks:\n  k6:\n\nservices:\n  prometheus:\n    image: prom/prometheus:v3.5.0@sha256:63805ebb8d2b3920190daf1cb14a60871b16fd38bed42b857a3182bc621f4996\n    command:\n      - --web.enable-remote-write-receiver\n      - --enable-feature=native-histograms\n      - --config.file=/etc/prometheus/prometheus.yml\n    networks:\n      - k6\n    ports:\n      - \"9090:9090\"\n\n  alloy:\n    image: grafana/alloy:v1.10.2@sha256:bcf27f18c4402869af112fb39e35e1db3804a404686f4caa20bdf77814219223\n    networks:\n      - k6\n    volumes:\n      - ./grafana/alloy:/etc/alloy\n    environment:\n      REMOTE_WRITE_HOST: prometheus:9090\n    depends_on:\n      - prometheus\n    command:\n      - run\n      - /etc/alloy/config.alloy\n      - --storage.path=/var/lib/alloy/data\n      - --server.http.listen-addr=0.0.0.0:12345\n      - --stability.level=experimental # Enable all functionality\n    ports:\n      - \"12345:12345\" # Alloy UI\n      - \"4317:4317\" # gRPC receiver\n      - \"4318:4318\" # HTTP receiver\n\n  grafana:\n    image: grafana/grafana:12.1.1@sha256:a1701c2180249361737a99a01bc770db39381640e4d631825d38ff4535efa47d\n    networks:\n      - k6\n    ports:\n      - \"3000:3000\"\n    environment:\n      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin\n      - GF_AUTH_ANONYMOUS_ENABLED=true\n      - GF_AUTH_BASIC_ENABLED=false\n    volumes:\n      - ./grafana:/etc/grafana/provisioning/\n"
  },
  {
    "path": "examples/docker-compose/opentelemetry/grafana/alloy/config.alloy",
    "content": "// expose OTEL receivers\n// https://grafana.com/docs/alloy/latest/reference/components/otelcol.receiver.otlp/\notelcol.receiver.otlp \"default\" {\n\t// configures the default gRPC receiver endpoint \"0.0.0.0:4317\"\n\t// https://grafana.com/docs/alloy/latest/reference/components/otelcol.receiver.otlp/#grpc-block\n\tgrpc {}\n\t\n\t// configures the default HTTP receiver endpoint \"0.0.0.0:4318\"\n\t// https://grafana.com/docs/alloy/latest/reference/components/otelcol.receiver.otlp/#http-block\n\thttp {}\n\n\toutput {\n\t\tmetrics = [otelcol.processor.batch.default.input]\n\t}\n}\n\notelcol.processor.batch \"default\" {\n\t// https://grafana.com/docs/alloy/latest/reference/components/otelcol.processor.batch/\n\toutput {\n\t\tmetrics = [otelcol.exporter.prometheus.default.input]\t\t\n\t}\n}\n\notelcol.exporter.prometheus \"default\" {\n\tadd_metric_suffixes = false\n\tforward_to          = [prometheus.remote_write.default.receiver]\n}\n\n// Collect metrics from the local running Alloy instance and forward to\n// Prometheus.\nprometheus.exporter.self \"alloy\" {}\nprometheus.scrape \"alloy\" {\n\ttargets    = prometheus.exporter.self.alloy.targets\n\tforward_to = [prometheus.remote_write.default.receiver]\n}\n\nprometheus.remote_write \"default\" {\n\tendpoint {\n\t\turl = format(\n\t\t\t\"http://%s/api/v1/write\",\n\t\t\tcoalesce(env(\"REMOTE_WRITE_HOST\"), \"localhost:9090\"),\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "examples/docker-compose/opentelemetry/grafana/dashboards/dashboards.yaml",
    "content": "# For configuration options, see\n#   https://grafana.com/docs/grafana/latest/administration/provisioning/#dashboards\n\napiVersion: 1\n\nproviders:\n  # We're defining a directory from which to load file-based dashboards\n  - name: 'prometheus'\n    type: file\n    disableDeletion: false\n    updateIntervalSeconds: 10\n    editable: true\n    options:\n      path: /etc/grafana/provisioning/dashboards\n"
  },
  {
    "path": "examples/docker-compose/opentelemetry/grafana/dashboards/k6-prometheus.json",
    "content": "{\n  \"annotations\": {\n    \"list\": [\n      {\n        \"builtIn\": 1,\n        \"datasource\": {\n          \"type\": \"grafana\",\n          \"uid\": \"-- Grafana --\"\n        },\n        \"enable\": true,\n        \"hide\": true,\n        \"iconColor\": \"rgba(0, 211, 255, 1)\",\n        \"name\": \"Annotations & Alerts\",\n        \"type\": \"dashboard\"\n      }\n    ]\n  },\n  \"description\": \"Visualize k6 OSS results stored in Prometheus\",\n  \"editable\": true,\n  \"fiscalYearStartMonth\": 0,\n  \"gnetId\": 19665,\n  \"graphTooltip\": 2,\n  \"links\": [\n    {\n      \"asDropdown\": false,\n      \"icon\": \"external link\",\n      \"includeVars\": false,\n      \"keepTime\": false,\n      \"tags\": [],\n      \"targetBlank\": true,\n      \"title\": \"Grafana k6 OpenTelemetry Output\",\n      \"tooltip\": \"Open docs in a new tab\",\n      \"type\": \"link\",\n      \"url\": \"https://grafana.com/docs/k6/latest/results-output/real-time/opentelemetry/\"\n    }\n  ],\n  \"liveNow\": false,\n  \"panels\": [\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisBorderShow\": false,\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"insertNulls\": false,\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"ms\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"http_req_s_errors\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"red\",\n                  \"mode\": \"fixed\"\n                }\n              },\n              {\n                \"id\": \"custom.lineStyle\",\n                \"value\": {\n                  \"dash\": [\n                    10,\n                    10\n                  ],\n                  \"fill\": \"dash\"\n                }\n              },\n              {\n                \"id\": \"custom.axisPlacement\",\n                \"value\": \"right\"\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"reqps\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"http_req_s\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"reqps\"\n              },\n              {\n                \"id\": \"custom.axisPlacement\",\n                \"value\": \"right\"\n              },\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"yellow\",\n                  \"mode\": \"fixed\"\n                }\n              },\n              {\n                \"id\": \"custom.lineStyle\",\n                \"value\": {\n                  \"dash\": [\n                    10,\n                    10\n                  ],\n                  \"fill\": \"dash\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"vus\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"mode\": \"fixed\"\n                }\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"VUs\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"http_req_duration_[a-zA-Z0-9_]+\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"ms\"\n              },\n              {\n                \"id\": \"custom.axisPlacement\",\n                \"value\": \"right\"\n              },\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"blue\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 11,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 0\n      },\n      \"id\": 10,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"multi\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"avg(k6_vus{testid=~\\\"$testid\\\"})\",\n          \"instant\": false,\n          \"legendFormat\": \"vus\",\n          \"range\": true,\n          \"refId\": \"A\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by (le) (rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_duration_q$quantile\",\n          \"range\": true,\n          \"refId\": \"C\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(irate(k6_http_reqs{testid=~\\\"$testid\\\"}[$__rate_interval]))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_s\",\n          \"range\": true,\n          \"refId\": \"B\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"avg(rate(k6_http_req_failed_total{testid=~\\\"$testid\\\", condition=\\\"nonzero\\\"}[$__rate_interval]) / rate(k6_http_req_failed_total{testid=~\\\"$testid\\\"}[$__rate_interval]) * 100)\",\n          \"hide\": true,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_failed\",\n          \"range\": true,\n          \"refId\": \"E\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"rate(k6_http_reqs{testid=~\\\"$testid\\\", expected_response=\\\"false\\\"}[$__rate_interval])\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_s_errors\",\n          \"range\": true,\n          \"refId\": \"D\"\n        }\n      ],\n      \"title\": \"Performance Overview\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 11\n      },\n      \"id\": 1,\n      \"panels\": [],\n      \"title\": \"Performance Overview\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 6,\n        \"x\": 0,\n        \"y\": 12\n      },\n      \"id\": 4,\n      \"options\": {\n        \"colorMode\": \"value\",\n        \"graphMode\": \"none\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"showPercentChange\": false,\n        \"textMode\": \"auto\",\n        \"wideLayout\": true\n      },\n      \"pluginVersion\": \"10.4.0\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(k6_http_reqs{testid=~\\\"$testid\\\"})\",\n          \"instant\": false,\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"HTTP requests\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              },\n              {\n                \"color\": \"red\",\n                \"value\": 1\n              }\n            ]\n          },\n          \"unit\": \"none\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 6,\n        \"x\": 6,\n        \"y\": 12\n      },\n      \"id\": 22,\n      \"options\": {\n        \"colorMode\": \"value\",\n        \"graphMode\": \"none\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"showPercentChange\": false,\n        \"textMode\": \"auto\",\n        \"wideLayout\": true\n      },\n      \"pluginVersion\": \"10.4.0\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(k6_http_req_failed_total{testid=~\\\"$testid\\\", condition=\\\"nonzero\\\"}) or vector(0)\",\n          \"instant\": false,\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"HTTP request failures\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"reqps\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 6,\n        \"x\": 12,\n        \"y\": 12\n      },\n      \"id\": 20,\n      \"options\": {\n        \"colorMode\": \"value\",\n        \"graphMode\": \"none\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"showPercentChange\": false,\n        \"textMode\": \"auto\",\n        \"wideLayout\": true\n      },\n      \"pluginVersion\": \"10.4.0\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(k6_http_reqs{testid=~\\\"$testid\\\"}[$__rate_interval]))\",\n          \"instant\": false,\n          \"interval\": \"\",\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Peak RPS\",\n      \"transformations\": [\n        {\n          \"id\": \"reduce\",\n          \"options\": {}\n        }\n      ],\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Select a different Stat to change the query\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"ms\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 3,\n        \"w\": 6,\n        \"x\": 18,\n        \"y\": 12\n      },\n      \"id\": 21,\n      \"options\": {\n        \"colorMode\": \"value\",\n        \"graphMode\": \"none\",\n        \"justifyMode\": \"auto\",\n        \"orientation\": \"auto\",\n        \"reduceOptions\": {\n          \"calcs\": [],\n          \"fields\": \"\",\n          \"values\": false\n        },\n        \"showPercentChange\": false,\n        \"textMode\": \"auto\",\n        \"wideLayout\": true\n      },\n      \"pluginVersion\": \"10.4.0\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"instant\": false,\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"HTTP Request Duration\",\n      \"type\": \"stat\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisBorderShow\": false,\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"insertNulls\": false,\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"bytes\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 15\n      },\n      \"id\": 8,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"avg(rate(k6_data_sent{testid=~\\\"$testid\\\"}[$__rate_interval]))\",\n          \"instant\": false,\n          \"legendFormat\": \"data_sent\",\n          \"range\": true,\n          \"refId\": \"A\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"avg(rate(k6_data_received{testid=~\\\"$testid\\\"}[$__rate_interval]))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"data_received\",\n          \"range\": true,\n          \"refId\": \"B\"\n        }\n      ],\n      \"title\": \"Transfer Rate\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisBorderShow\": false,\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"insertNulls\": false,\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"ms\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"dropped_iterations\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"none\"\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 15\n      },\n      \"id\": 9,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_iteration_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"instant\": false,\n          \"legendFormat\": \"iteration_duration_q$quantile\",\n          \"range\": true,\n          \"refId\": \"A\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"avg(k6_dropped_iterations_total{testid=~\\\"$testid\\\"})\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"dropped_iterations\",\n          \"range\": true,\n          \"refId\": \"B\"\n        }\n      ],\n      \"title\": \"Iterations\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"collapsed\": false,\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 23\n      },\n      \"id\": 16,\n      \"panels\": [],\n      \"title\": \"HTTP\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Select a different Stat to change the query\\n\\n<a href=\\\"https://k6.io/docs/using-k6/metrics/reference/#http\\\" target=\\\"_blank\\\">HTTP-specific built-in metrics</a>\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisBorderShow\": false,\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"insertNulls\": false,\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"ms\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"http_req_duration_[a-zA-Z0-9_]+\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"blue\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 8,\n        \"x\": 0,\n        \"y\": 24\n      },\n      \"id\": 14,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_blocked_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_blocked_q$quantile\",\n          \"range\": true,\n          \"refId\": \"B\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_tls_handshaking_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_tls_handshaking_q$quantile\",\n          \"range\": true,\n          \"refId\": \"C\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_sending_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_sending_q$quantile\",\n          \"range\": true,\n          \"refId\": \"D\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_waiting_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_waiting_q$quantile\",\n          \"range\": true,\n          \"refId\": \"E\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_receiving_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_receiving_q$quantile\",\n          \"range\": true,\n          \"refId\": \"F\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_duration_q$quantile\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"HTTP Latency Timings\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Select a different Stat to change the query\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisBorderShow\": false,\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"axisSoftMin\": 0,\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"insertNulls\": false,\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"ms\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"errors_http_req_duration_[a-zA-Z0-9_]+\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"red\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"success_http_req_duration_[a-zA-Z0-9_]+\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"green\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"http_req_duration_[a-zA-Z0-9_]+\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"yellow\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byRegexp\",\n              \"options\": \"http_req_duration_[a-zA-Z0-9_]+\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"blue\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 8,\n        \"x\": 8,\n        \"y\": 24\n      },\n      \"id\": 15,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by (le) ((rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval]))))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_duration_q$quantile\",\n          \"range\": true,\n          \"refId\": \"A\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_waiting_bucket{testid=~\\\"$testid\\\", expected_response=\\\"true\\\"}[$__rate_interval])))\",\n          \"instant\": false,\n          \"legendFormat\": \"success_http_req_duration_q$quantile\",\n          \"range\": true,\n          \"refId\": \"C\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile($quantile, sum by(le) (rate(k6_http_req_waiting_bucket{testid=~\\\"$testid\\\", expected_response=\\\"false\\\"}[$__rate_interval])))\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"errors_http_req_duration_q$quantile\",\n          \"range\": true,\n          \"refId\": \"B\"\n        }\n      ],\n      \"title\": \"HTTP Latency Stats\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisBorderShow\": false,\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"axisSoftMin\": 0,\n            \"barAlignment\": 0,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"insertNulls\": false,\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 1,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"reqps\"\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"http_req_s_errors\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"red\",\n                  \"mode\": \"fixed\"\n                }\n              },\n              {\n                \"id\": \"custom.lineStyle\",\n                \"value\": {\n                  \"dash\": [\n                    10,\n                    10\n                  ],\n                  \"fill\": \"dash\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"http_req_s\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"yellow\",\n                  \"mode\": \"fixed\"\n                }\n              },\n              {\n                \"id\": \"custom.lineStyle\",\n                \"value\": {\n                  \"dash\": [\n                    10,\n                    10\n                  ],\n                  \"fill\": \"dash\"\n                }\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"http_req_s_success\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.lineStyle\",\n                \"value\": {\n                  \"dash\": [\n                    10,\n                    10\n                  ],\n                  \"fill\": \"dash\"\n                }\n              },\n              {\n                \"id\": \"color\",\n                \"value\": {\n                  \"fixedColor\": \"green\",\n                  \"mode\": \"fixed\"\n                }\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 8,\n        \"x\": 16,\n        \"y\": 24\n      },\n      \"id\": 18,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"sum(rate(k6_http_reqs_total{testid=~\\\"$testid\\\"}[$__rate_interval]))\",\n          \"instant\": false,\n          \"legendFormat\": \"http_req_s\",\n          \"range\": true,\n          \"refId\": \"A\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"rate(k6_http_reqs{testid=~\\\"$testid\\\", expected_response=\\\"false\\\"}[$__rate_interval])\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_s_errors\",\n          \"range\": true,\n          \"refId\": \"B\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"rate(k6_http_reqs{testid=~\\\"$testid\\\", expected_response=\\\"true\\\"}[$__rate_interval])\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"http_req_s_success\",\n          \"range\": true,\n          \"refId\": \"C\"\n        }\n      ],\n      \"title\": \"HTTP Request Rate\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"min/max/p95/p99 depends on the available Quantile Stats\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"custom\": {\n            \"align\": \"auto\",\n            \"cellOptions\": {\n              \"type\": \"auto\"\n            },\n            \"inspect\": false\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          }\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"name\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"filterable\",\n                \"value\": false\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"method\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"filterable\",\n                \"value\": false\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"status\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"filterable\",\n                \"value\": false\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"min\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"ms\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"max\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"ms\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"p95\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"ms\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"p99\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"unit\",\n                \"value\": \"ms\"\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 7,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 32\n      },\n      \"id\": 17,\n      \"options\": {\n        \"cellHeight\": \"sm\",\n        \"footer\": {\n          \"countRows\": false,\n          \"enablePagination\": true,\n          \"fields\": \"\",\n          \"reducer\": [\n            \"sum\"\n          ],\n          \"show\": false\n        },\n        \"frameIndex\": 2,\n        \"showHeader\": true\n      },\n      \"pluginVersion\": \"10.4.0\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0, sum by(le, name, method, status) (rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"format\": \"table\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"min\",\n          \"range\": true,\n          \"refId\": \"B\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(1, sum by(le, name, method, status) (rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"format\": \"table\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"max\",\n          \"range\": true,\n          \"refId\": \"C\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.95, sum by(le, name, method, status) (rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"format\": \"table\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"p95\",\n          \"range\": true,\n          \"refId\": \"D\"\n        },\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"histogram_quantile(0.99, sum by(le, name, method, status) (rate(k6_http_req_duration_bucket{testid=~\\\"$testid\\\"}[$__rate_interval])))\",\n          \"format\": \"table\",\n          \"hide\": false,\n          \"instant\": false,\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"E\"\n        }\n      ],\n      \"title\": \"Requests by URL\",\n      \"transformations\": [\n        {\n          \"id\": \"merge\",\n          \"options\": {}\n        },\n        {\n          \"id\": \"groupBy\",\n          \"options\": {\n            \"fields\": {\n              \"Value #B\": {\n                \"aggregations\": [\n                  \"min\"\n                ],\n                \"operation\": \"aggregate\"\n              },\n              \"Value #C\": {\n                \"aggregations\": [\n                  \"max\"\n                ],\n                \"operation\": \"aggregate\"\n              },\n              \"Value #D\": {\n                \"aggregations\": [\n                  \"mean\"\n                ],\n                \"operation\": \"aggregate\"\n              },\n              \"Value #E\": {\n                \"aggregations\": [\n                  \"mean\"\n                ],\n                \"operation\": \"aggregate\"\n              },\n              \"method\": {\n                \"aggregations\": [],\n                \"operation\": \"groupby\"\n              },\n              \"name\": {\n                \"aggregations\": [],\n                \"operation\": \"groupby\"\n              },\n              \"status\": {\n                \"aggregations\": [],\n                \"operation\": \"groupby\"\n              }\n            }\n          }\n        },\n        {\n          \"id\": \"organize\",\n          \"options\": {\n            \"excludeByName\": {\n              \"Time\": true\n            },\n            \"indexByName\": {\n              \"Time\": 0,\n              \"Value #B\": 4,\n              \"Value #C\": 5,\n              \"Value #D\": 6,\n              \"Value #E\": 7,\n              \"method\": 2,\n              \"name\": 1,\n              \"status\": 3\n            },\n            \"renameByName\": {\n              \"Value #B\": \"min\",\n              \"Value #B (min)\": \"min\",\n              \"Value #C\": \"max\",\n              \"Value #C (max)\": \"max\",\n              \"Value #D\": \"p95\",\n              \"Value #D (mean)\": \"p95\",\n              \"Value #E\": \"p99\",\n              \"Value #E (mean)\": \"p99\"\n            }\n          }\n        }\n      ],\n      \"type\": \"table\"\n    },\n    {\n      \"collapsed\": false,\n      \"gridPos\": {\n        \"h\": 1,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 39\n      },\n      \"id\": 11,\n      \"panels\": [],\n      \"title\": \"Checks\",\n      \"type\": \"row\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"thresholds\"\n          },\n          \"custom\": {\n            \"align\": \"auto\",\n            \"cellOptions\": {\n              \"type\": \"auto\"\n            },\n            \"inspect\": false\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          }\n        },\n        \"overrides\": [\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Success Rate\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hidden\",\n                \"value\": false\n              },\n              {\n                \"id\": \"unit\",\n                \"value\": \"%\"\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"Value (mean)\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"custom.hidden\",\n                \"value\": true\n              }\n            ]\n          },\n          {\n            \"matcher\": {\n              \"id\": \"byName\",\n              \"options\": \"check\"\n            },\n            \"properties\": [\n              {\n                \"id\": \"filterable\",\n                \"value\": false\n              }\n            ]\n          }\n        ]\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 0,\n        \"y\": 40\n      },\n      \"id\": 12,\n      \"options\": {\n        \"cellHeight\": \"sm\",\n        \"footer\": {\n          \"countRows\": false,\n          \"enablePagination\": true,\n          \"fields\": \"\",\n          \"reducer\": [\n            \"sum\"\n          ],\n          \"show\": false\n        },\n        \"frameIndex\": 2,\n        \"showHeader\": true,\n        \"sortBy\": [\n          {\n            \"desc\": true,\n            \"displayName\": \"Value (count)\"\n          }\n        ]\n      },\n      \"pluginVersion\": \"10.4.0\",\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"exemplar\": false,\n          \"expr\": \"rate(k6_checks_total{testid=~\\\"$testid\\\", condition=\\\"nonzero\\\"}[$__rate_interval]) / rate(k6_checks_total{testid=~\\\"$testid\\\"}[$__rate_interval])\",\n          \"format\": \"table\",\n          \"instant\": false,\n          \"legendFormat\": \"__auto\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Checks list\",\n      \"transformations\": [\n        {\n          \"id\": \"labelsToFields\",\n          \"options\": {\n            \"keepLabels\": [\n              \"__name__\",\n              \"check\"\n            ],\n            \"mode\": \"columns\"\n          }\n        },\n        {\n          \"id\": \"groupBy\",\n          \"options\": {\n            \"fields\": {\n              \"Value\": {\n                \"aggregations\": [\n                  \"mean\"\n                ],\n                \"operation\": \"aggregate\"\n              },\n              \"check\": {\n                \"aggregations\": [],\n                \"operation\": \"groupby\"\n              },\n              \"k6_checks_rate\": {\n                \"aggregations\": [\n                  \"sum\",\n                  \"count\"\n                ],\n                \"operation\": \"aggregate\"\n              }\n            }\n          }\n        },\n        {\n          \"id\": \"calculateField\",\n          \"options\": {\n            \"alias\": \"Success Rate\",\n            \"binary\": {\n              \"left\": \"Value (mean)\",\n              \"operator\": \"*\",\n              \"reducer\": \"sum\",\n              \"right\": \"100\"\n            },\n            \"mode\": \"binary\",\n            \"reduce\": {\n              \"reducer\": \"sum\"\n            }\n          }\n        },\n        {\n          \"id\": \"convertFieldType\",\n          \"options\": {\n            \"conversions\": [],\n            \"fields\": {}\n          }\n        }\n      ],\n      \"type\": \"table\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"description\": \"Filter by check name to query a particular check\",\n      \"fieldConfig\": {\n        \"defaults\": {\n          \"color\": {\n            \"mode\": \"palette-classic\"\n          },\n          \"custom\": {\n            \"axisBorderShow\": false,\n            \"axisCenteredZero\": false,\n            \"axisColorMode\": \"text\",\n            \"axisLabel\": \"\",\n            \"axisPlacement\": \"auto\",\n            \"axisSoftMax\": 100,\n            \"axisSoftMin\": 0,\n            \"barAlignment\": -1,\n            \"drawStyle\": \"line\",\n            \"fillOpacity\": 0,\n            \"gradientMode\": \"none\",\n            \"hideFrom\": {\n              \"legend\": false,\n              \"tooltip\": false,\n              \"viz\": false\n            },\n            \"insertNulls\": false,\n            \"lineInterpolation\": \"linear\",\n            \"lineWidth\": 2,\n            \"pointSize\": 5,\n            \"scaleDistribution\": {\n              \"type\": \"linear\"\n            },\n            \"showPoints\": \"auto\",\n            \"spanNulls\": false,\n            \"stacking\": {\n              \"group\": \"A\",\n              \"mode\": \"none\"\n            },\n            \"thresholdsStyle\": {\n              \"mode\": \"off\"\n            }\n          },\n          \"mappings\": [],\n          \"thresholds\": {\n            \"mode\": \"absolute\",\n            \"steps\": [\n              {\n                \"color\": \"green\",\n                \"value\": null\n              }\n            ]\n          },\n          \"unit\": \"%\"\n        },\n        \"overrides\": []\n      },\n      \"gridPos\": {\n        \"h\": 8,\n        \"w\": 12,\n        \"x\": 12,\n        \"y\": 40\n      },\n      \"id\": 13,\n      \"options\": {\n        \"legend\": {\n          \"calcs\": [],\n          \"displayMode\": \"list\",\n          \"placement\": \"bottom\",\n          \"showLegend\": true\n        },\n        \"tooltip\": {\n          \"mode\": \"single\",\n          \"sort\": \"none\"\n        }\n      },\n      \"targets\": [\n        {\n          \"datasource\": {\n            \"type\": \"prometheus\",\n            \"uid\": \"${DS_PROMETHEUS}\"\n          },\n          \"editorMode\": \"code\",\n          \"expr\": \"avg(rate(k6_checks_total{testid=~\\\"$testid\\\", condition=\\\"nonzero\\\"}[$__rate_interval]) / rate(k6_checks_total{testid=~\\\"$testid\\\"}[$__rate_interval]) * 100)\",\n          \"instant\": false,\n          \"legendFormat\": \"k6_checks_rate\",\n          \"range\": true,\n          \"refId\": \"A\"\n        }\n      ],\n      \"title\": \"Checks Success Rate (aggregate individual checks)\",\n      \"type\": \"timeseries\"\n    },\n    {\n      \"datasource\": {\n        \"type\": \"prometheus\",\n        \"uid\": \"${DS_PROMETHEUS}\"\n      },\n      \"gridPos\": {\n        \"h\": 5,\n        \"w\": 24,\n        \"x\": 0,\n        \"y\": 48\n      },\n      \"id\": 23,\n      \"options\": {\n        \"code\": {\n          \"language\": \"plaintext\",\n          \"showLineNumbers\": false,\n          \"showMiniMap\": false\n        },\n        \"content\": \"### Visualize other k6 results  \\n\\nAt the top of the dashboard, click `Add` and select `Visualization` from the dropdown menu. Choose the visualization type and input the PromQL queries for the `k6_` metric(s).\\n\\nAlternatively, click on the `Explore` icon on the menu bar and input the queries for the `k6_` metric(s). From `Explore`, you can add new Panels to this dashboard. \\n\\nNote that all <a href=\\\"https://k6.io/docs/using-k6/metrics/\\\" target=\\\"_blank\\\">k6 metrics</a> are prefixed with the `k6_` namespace when sent to Prometheus.\",\n        \"mode\": \"markdown\"\n      },\n      \"pluginVersion\": \"10.4.0\",\n      \"type\": \"text\"\n    }\n  ],\n  \"refresh\": \"\",\n  \"schemaVersion\": 39,\n  \"tags\": [\n    \"prometheus\",\n    \"k6\"\n  ],\n  \"templating\": {\n    \"list\": [\n      {\n        \"current\": {\n          \"selected\": false,\n          \"text\": \"prometheus\",\n          \"value\": \"${DS_PROMETHEUS}\"\n        },\n        \"description\": \"Choose a Prometheus Data Source\",\n        \"hide\": 0,\n        \"includeAll\": false,\n        \"label\": \"Prometheus DS\",\n        \"multi\": false,\n        \"name\": \"DS_PROMETHEUS\",\n        \"options\": [],\n        \"query\": \"prometheus\",\n        \"queryValue\": \"\",\n        \"refresh\": 1,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"type\": \"datasource\"\n      },\n      {\n        \"current\": {\n          \"selected\": true,\n          \"text\": [\n            \"All\"\n          ],\n          \"value\": [\n            \"$__all\"\n          ]\n        },\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_PROMETHEUS}\"\n        },\n        \"definition\": \"label_values(testid)\",\n        \"description\": \"Filter by \\\"testid\\\" tag. Define it by tagging: k6 run --tag testid=xyz\",\n        \"hide\": 0,\n        \"includeAll\": true,\n        \"label\": \"Test ID\",\n        \"multi\": true,\n        \"name\": \"testid\",\n        \"options\": [],\n        \"query\": {\n          \"query\": \"label_values(testid)\",\n          \"refId\": \"PrometheusVariableQueryEditor-VariableQuery\"\n        },\n        \"refresh\": 2,\n        \"regex\": \"\",\n        \"skipUrlSync\": false,\n        \"sort\": 0,\n        \"type\": \"query\"\n      },\n      {\n        \"current\": {\n          \"selected\": false,\n          \"text\": \"0.99\",\n          \"value\": \"0.99\"\n        },\n        \"description\": \"Statistic for Trend Metrics Queries. Calculate the φ-quantile (0 ≤ φ ≤ 1) in native histogram metrics.  0=min, 0.5=mean, 0.9=p90, 0.95=p95, 0.99=p99, 1=max\",\n        \"hide\": 0,\n        \"label\": \"Trend Metrics Query\",\n        \"name\": \"quantile\",\n        \"options\": [\n          {\n            \"selected\": true,\n            \"text\": \"0.95\",\n            \"value\": \"0.95\"\n          }\n        ],\n        \"query\": \"0.99\",\n        \"skipUrlSync\": false,\n        \"type\": \"textbox\"\n      },\n      {\n        \"datasource\": {\n          \"type\": \"prometheus\",\n          \"uid\": \"${DS_PROMETHEUS}\"\n        },\n        \"description\": \"Adhoc filters are applied to all panels. To enable it, go to Dashboard Settings / Variables / adhoc_filter and select the target Prometheus data source.\",\n        \"filters\": [],\n        \"hide\": 0,\n        \"label\": \"AdhocFilter\",\n        \"name\": \"adhoc_filter\",\n        \"skipUrlSync\": false,\n        \"type\": \"adhoc\"\n      }\n    ]\n  },\n  \"time\": {\n    \"from\": \"now-5m\",\n    \"to\": \"now\"\n  },\n  \"timepicker\": {},\n  \"timezone\": \"\",\n  \"title\": \"k6 OpenTelemetry Prometheus\",\n  \"uid\": \"demo-uid\",\n  \"version\": 2,\n  \"weekStart\": \"\"\n}\n"
  },
  {
    "path": "examples/docker-compose/opentelemetry/grafana/datasources/datasource.yaml",
    "content": "# For configuration options, see \n#   https://grafana.com/docs/grafana/latest/administration/provisioning/#example-data-source-config-file\n\napiVersion: 1\n\ndatasources:\n  - name: prometheus\n    type: prometheus\n    access: proxy\n    url: http://prometheus:9090\n    basicAuth: false\n    isDefault: true\n    jsonData:\n      tlsAuth: false\n      tlsAuthWithCACert: false\n    editable: false\n"
  },
  {
    "path": "examples/docker-compose/opentelemetry/script.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport const options = {\n  vus: 10,\n  duration: '3m',\n  thresholds: {\n    'http_reqs{expected_response:true}': ['rate>10'],\n  },\n};\n\nexport default function () {\n  check(http.get(\"https://quickpizza.grafana.com/\"), {\n    \"status is 200\": (r) => r.status == 200,\n    \"protocol is HTTP/2\": (r) => r.proto == \"HTTP/2.0\",\n  });\n}\n"
  },
  {
    "path": "examples/enhanced/abort.ts",
    "content": "import exec from \"k6/execution\";\n\nexport default function () {\n\texec.test.abort(\"failed\");\n}\n"
  },
  {
    "path": "examples/enhanced/script.ts",
    "content": "import { User, newUser } from \"./user.ts\";\n\nexport default () => {\n\tconst user: User = newUser(\"John\");\n\tconsole.log(user);\n};\n"
  },
  {
    "path": "examples/enhanced/user.ts",
    "content": "interface User {\n\tname: string;\n\tid: number;\n}\n\nclass UserAccount implements User {\n\tname: string;\n\tid: number;\n\n\tconstructor(name: string) {\n\t\tthis.name = name;\n\t\tthis.id = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);\n\t}\n}\n\nfunction newUser(name: string): User {\n\treturn new UserAccount(name);\n}\n\nexport { User, newUser };\n"
  },
  {
    "path": "examples/es6sample.js",
    "content": "import { group, check, sleep } from \"k6\";\nimport { Counter, Rate } from \"k6/metrics\";\nimport http from \"k6/http\";\n\nexport let options = {\n\tthresholds: {\n\t\tmy_rate: [\"rate>=0.4\"], // Require my_rate's success rate to be >=40%\n\t\thttp_req_duration: [\"avg<1000\"], // Require http_req_duration's average to be <1000ms\n\t}\n};\n\nlet mCounter = new Counter(\"my_counter\");\nlet mRate = new Rate(\"my_rate\");\n\nexport default function() {\n\tcheck(Math.random(), {\n\t\t\"top-level test\": (v) => v < 1/3\n\t});\n\tgroup(\"my group\", function() {\n\t\tmCounter.add(1, { tag: \"test\" });\n\n\t\tcheck(Math.random(), {\n\t\t\t\"random value is < 0.5\": (v) => mRate.add(v < 0.5),\n\t\t});\n\n\t\tgroup(\"json\", function() {\n\t\t\tlet res = http.get(\"https://httpbin.org/get\", {\n\t\t\t\theaders: { \"X-Test\": \"abc123\" },\n\t\t\t});\n\n\t\t\tcheck(res, {\n\t\t\t\t\"status is 200\": (res) => res.status === 200,\n\t\t\t\t\"X-Test header is correct\": (res) => res.json().headers['X-Test'] === \"abc123\",\n\t\t\t});\n\t\t});\n\n\t\tgroup(\"html\", function() {\n\t\t\tconst res = http.get(\"https://quickpizza.grafana.com/test.k6.io/\")\n\t\t\tconsole.log(res.html(\"p.description\").text())\n\t\t\tcheck(res, {\n\t\t\t\t\"status is 200\": (res) => res.status === 200,\n\t\t\t\t\"content type is html\": (res) => res.headers['Content-Type'].startsWith(\"text/html\"),\n\t\t\t\t\"welcome message is correct\": (res) => res.html(\"p.description\").text().includes(\"This is a replacement\"),\n\t\t\t});\n\t\t});\n\n\t\tgroup(\"nested\", function() {\n\t\t\tcheck(null, {\n\t\t\t\t\"always passes\": true,\n\t\t\t\t\"always fails\": false,\n\t\t\t});\n\t\t});\n\t});\n\tsleep(10 * Math.random());\n};\n"
  },
  {
    "path": "examples/experimental/csv-parse.js",
    "content": "import { open } from 'k6/experimental/fs'\nimport csv from 'k6/experimental/csv'\nimport { scenario } from 'k6/execution'\n\nexport const options = {\n\titerations: 10,\n}\n\n// Open the csv file, and parse it ahead of time.\nconst file = await open('data.csv');\n// The `csv.parse` function consumes the entire file at once, and returns\n// the parsed records as a SharedArray object.\nconst csvRecords = await csv.parse(file, { delimiter: ',' })\n\nexport default async function() {\n\t// The csvRecords a SharedArray. Each element is a record from the CSV file, represented as an array\n\t// where each element is a field from the CSV record.\n\t//\n\t// Thus, `csvRecords[scenario.iterationInTest]` will give us the record for the current iteration.\n\tconsole.log(csvRecords[scenario.iterationInTest])\n}\n\n"
  },
  {
    "path": "examples/experimental/csv-parser.js",
    "content": "import { open } from 'k6/experimental/fs'\nimport csv from 'k6/experimental/csv'\n\nexport const options = {\n\titerations: 10,\n}\n\nconst file = await open('data.csv');;\nconst parser = new csv.Parser(file);;\n\nexport default async function() {\n\t// The parser `next` method attempts to read the next row from the CSV file.\n\t//\n\t// It returns an iterator-like object with a `done` property that indicates whether\n\t// there are more rows to read, and a `value` property that contains the row fields\n\t// as an array.\n\tconst { done, value } = await parser.next();\n\tif (done) {\n\t\tthrow new Error(\"No more rows to read\");\n\t}\n\n\t// We expect the `value` property to be an array of strings, where each string is a field\n\t// from the CSV record.\n\tconsole.log(done, value);\n}\n"
  },
  {
    "path": "examples/experimental/data.csv",
    "content": "firstname,lastname,age\nfariha,ehlenfeldt,72\nqudratullah,gillfillan,50\njeleah,rodina,41\nthaisia,nowalk,99\njoey-lynn,wilsford,75\ntudur,granville,81\naytek,umber,56\naynoor,hisaw,30\nfiadh-rose,iravani,31\nannely,ooley,70\n"
  },
  {
    "path": "examples/experimental/docker-compose.yml",
    "content": "version: '3.3'\n\nservices:\n  k6-experimental-redis:\n    image: 'redis:alpine@sha256:59b6e694653476de2c992937ebe1c64182af4728e54bb49e9b7a6c26614d8933'\n    ports:\n      - '6379:6379'\n    command: redis-server\n"
  },
  {
    "path": "examples/experimental/fs/bonjour.txt",
    "content": "Bonjour, tout le monde!"
  },
  {
    "path": "examples/experimental/fs/fs.js",
    "content": "import { open, SeekMode } from \"k6/experimental/fs\";\n\nexport const options = {\n\tvus: 100,\n\titerations: 1000,\n};\n\n// Each Virtual User gets its own `file` copy.\n// So, operations like `seek` or `read` won't impact other VUs.\nconst file = await open(\"bonjour.txt\");\n\nexport default async function() {\n\t// About information about the file\n\tconst fileinfo = await file.stat();\n\tif (fileinfo.name != \"bonjour.txt\") {\n\t\tthrow new Error(\"Unexpected file name\");\n\t}\n\n\tconst buffer = new Uint8Array(4);\n\n\tlet totalBytesRead = 0;\n\twhile (true) {\n\t\t// Read into the buffer\n\t\tconst bytesRead = await file.read(buffer);\n\t\tif (bytesRead == null) {\n\t\t\t// EOF\n\t\t\tbreak;\n\t\t}\n\n\t\t// Do something useful with the content of the buffer\n\t\ttotalBytesRead += bytesRead;\n\n\t\t// If bytesRead is less than the buffer size, we've read the whole file\n\t\tif (bytesRead < buffer.byteLength) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Check that we read the expected number of bytes\n\tif (totalBytesRead != fileinfo.size) {\n\t\tthrow new Error(\"Unexpected number of bytes read\");\n\t}\n\n\t// Seek back to the beginning of the file\n\tawait file.seek(0, SeekMode.Start);\n}\n"
  },
  {
    "path": "examples/experimental/redis.js",
    "content": "import { check } from 'k6';\nimport http from 'k6/http';\nimport redis from 'k6/experimental/redis';\nimport exec from 'k6/execution';\nimport { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js';\n\nexport const options = {\n\tscenarios: {\n\t\tredisPerformance: {\n\t\t\texecutor: 'shared-iterations',\n\t\t\tvus: 10,\n\t\t\titerations: 200,\n\t\t\texec: 'measureRedisPerformance',\n\t\t},\n\t\tusingRedisData: {\n\t\t\texecutor: 'shared-iterations',\n\t\t\tvus: 10,\n\t\t\titerations: 200,\n\t\t\texec: 'measureUsingRedisData',\n\t\t},\n\t},\n};\n\n// Instantiate a new redis client\nconst redisClient = new redis.Client(`redis://localhost:6379`);\n\n// Prepare an array of rating ids for later use\n// in the context of the measureUsingRedisData function.\nconst ratingIDs = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);\n\nexport async function measureRedisPerformance() {\n\t// VUs are executed in a parallel fashion,\n\t// thus, to ensure that parallel VUs are not\n\t// modifying the same key at the same time,\n\t// we use keys indexed by the VU id.\n\tconst key = `foo-${exec.vu.idInTest}`;\n\n\tawait redisClient.set(key, 1);\n\tawait redisClient.incrBy(key, 10);\n\tconst value = await redisClient.get(key);\n\tif (value !== '11') {\n\t\tthrow new Error('foo should have been incremented to 11');\n\t}\n\n\tawait redisClient.del(key);\n\tif ((await redisClient.exists(key)) !== 0) {\n\t\tthrow new Error('foo should have been deleted');\n\t}\n}\n\nexport async function setup() {\n\tawait redisClient.sadd('rating_ids', ...ratingIDs);\n}\n\nexport async function measureUsingRedisData() {\n\t// Pick a random rating id from the dedicated redis set,\n\t// we have filled in setup().\n\tconst randomID = await redisClient.srandmember('rating_ids');\n\tconst url = `https://quickpizza.grafana.com/api/ratings/${randomID}`;\n\tconst res = await http.asyncRequest('GET', url, {\n\t\theaders: { Authorization: 'token abcdef0123456789' },\n\t});\n\n\tcheck(res, { 'status is 200': (r) => r.status === 200 });\n\n\tawait redisClient.hincrby('k6_rating_fetched', url, 1);\n}\n\nexport async function teardown() {\n\tawait redisClient.del('rating_ids');\n}\n\nexport function handleSummary(data) {\n\tredisClient\n\t\t.hgetall('k6_rating_fetched')\n\t\t.then((fetched) => Object.assign(data, { k6_rating_fetched: fetched }))\n\t\t.then((data) => redisClient.set(`k6_report_${Date.now()}`, JSON.stringify(data)))\n\t\t.then(() => redisClient.del('k6_rating_fetched'));\n\n\treturn {\n\t\tstdout: textSummary(data, { indent: '  ', enableColors: true }),\n\t};\n}\n"
  },
  {
    "path": "examples/experimental/streams.js",
    "content": "import { ReadableStream } from 'k6/experimental/streams'\nimport { setTimeout } from 'k6/timers'\n\nfunction numbersStream() {\n\tlet currentNumber = 0\n\n\treturn new ReadableStream({\n\t\tstart(controller) {\n\t\t\tconst fn = () => {\n\t\t\t\tif (currentNumber < 5) {\n\t\t\t\t\tcontroller.enqueue(++currentNumber)\n\t\t\t\t\tsetTimeout(fn, 1000)\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontroller.close()\n\t\t\t}\n\t\t\tsetTimeout(fn, 1000)\n\t\t},\n\t})\n}\n\nexport default async function () {\n\tconst stream = numbersStream()\n\tconst reader = stream.getReader()\n\n\twhile (true) {\n\t\tconst { done, value } = await reader.read()\n\t\tif (done) break\n\t\tconsole.log(`received number ${value} from stream`)\n\t}\n\n\tconsole.log('we are done')\n}\n"
  },
  {
    "path": "examples/grafana_dashboard_influxdb.json",
    "content": "{\n  \"__inputs\": [\n    {\n      \"name\": \"DS_K6\",\n      \"label\": \"k6\",\n      \"description\": \"\",\n      \"type\": \"datasource\",\n      \"pluginId\": \"influxdb\",\n      \"pluginName\": \"InfluxDB\"\n    }\n  ],\n  \"__requires\": [\n    {\n      \"type\": \"grafana\",\n      \"id\": \"grafana\",\n      \"name\": \"Grafana\",\n      \"version\": \"4.3.2\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"graph\",\n      \"name\": \"Graph\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"panel\",\n      \"id\": \"heatmap\",\n      \"name\": \"Heatmap\",\n      \"version\": \"\"\n    },\n    {\n      \"type\": \"datasource\",\n      \"id\": \"influxdb\",\n      \"name\": \"InfluxDB\",\n      \"version\": \"1.0.0\"\n    }\n  ],\n  \"annotations\": {\n    \"list\": []\n  },\n  \"editable\": true,\n  \"gnetId\": null,\n  \"graphTooltip\": 0,\n  \"hideControls\": false,\n  \"id\": null,\n  \"links\": [],\n  \"refresh\": false,\n  \"rows\": [\n    {\n      \"collapse\": false,\n      \"height\": \"250px\",\n      \"panels\": [\n        {\n          \"aliasColors\": {},\n          \"bars\": true,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"${DS_K6}\",\n          \"fill\": 1,\n          \"id\": 1,\n          \"interval\": \">1s\",\n          \"legend\": {\n            \"alignAsTable\": true,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": true,\n            \"min\": true,\n            \"show\": true,\n            \"total\": false,\n            \"values\": true\n          },\n          \"lines\": false,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 4,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"alias\": \"Active VUs\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"vus\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"A\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [],\n                    \"type\": \"mean\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Virtual Users\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            },\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"aliasColors\": {},\n          \"bars\": true,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"${DS_K6}\",\n          \"fill\": 1,\n          \"id\": 7,\n          \"interval\": \">1s\",\n          \"legend\": {\n            \"alignAsTable\": true,\n            \"avg\": true,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"show\": true,\n            \"total\": true,\n            \"values\": true\n          },\n          \"lines\": false,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"seriesOverrides\": [\n            {\n              \"alias\": \"Num Errors\",\n              \"color\": \"#BF1B00\"\n            }\n          ],\n          \"spaceLength\": 10,\n          \"span\": 4,\n          \"stack\": true,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"alias\": \"Num Errors\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"errors\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"C\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [],\n                    \"type\": \"count\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Errors Per Second\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            },\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"aliasColors\": {},\n          \"bars\": true,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"${DS_K6}\",\n          \"fill\": 1,\n          \"id\": 10,\n          \"interval\": \">1s\",\n          \"legend\": {\n            \"alignAsTable\": true,\n            \"avg\": true,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"show\": true,\n            \"total\": true,\n            \"values\": true\n          },\n          \"lines\": false,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"seriesOverrides\": [\n            {\n              \"alias\": \"Num Errors\",\n              \"color\": \"#BF1B00\"\n            }\n          ],\n          \"spaceLength\": 10,\n          \"span\": 4,\n          \"stack\": true,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"alias\": \"Num Checks\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"checks\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"C\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [],\n                    \"type\": \"count\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"Checks Per Second\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            },\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            }\n          ]\n        }\n      ],\n      \"repeat\": null,\n      \"repeatIteration\": null,\n      \"repeatRowId\": null,\n      \"showTitle\": false,\n      \"title\": \"Dashboard Row\",\n      \"titleSize\": \"h6\"\n    },\n    {\n      \"collapse\": false,\n      \"height\": 250,\n      \"panels\": [\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"${DS_K6}\",\n          \"description\": \"Grouped by 1 sec intervals\",\n          \"fill\": 1,\n          \"id\": 5,\n          \"interval\": \">1s\",\n          \"legend\": {\n            \"alignAsTable\": false,\n            \"avg\": false,\n            \"current\": false,\n            \"max\": false,\n            \"min\": false,\n            \"show\": true,\n            \"total\": false,\n            \"values\": false\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"alias\": \"max\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_duration\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"C\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [],\n                    \"type\": \"max\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            },\n            {\n              \"alias\": \"p95\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_duration\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"D\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [\n                      95\n                    ],\n                    \"type\": \"percentile\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            },\n            {\n              \"alias\": \"p80\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_duration\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"A\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [\n                      \"80\"\n                    ],\n                    \"type\": \"percentile\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            },\n            {\n              \"alias\": \"p50\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_duration\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"B\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [\n                      \"50\"\n                    ],\n                    \"type\": \"percentile\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            },\n            {\n              \"alias\": \"min\",\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_duration\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"E\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [],\n                    \"type\": \"min\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"http_req_duration\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"ms\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": \"0\",\n              \"show\": true\n            },\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"cards\": {\n            \"cardPadding\": null,\n            \"cardRound\": null\n          },\n          \"color\": {\n            \"cardColor\": \"rgb(0, 234, 255)\",\n            \"colorScale\": \"sqrt\",\n            \"colorScheme\": \"interpolateSpectral\",\n            \"exponent\": 0.5,\n            \"mode\": \"opacity\"\n          },\n          \"dataFormat\": \"timeseries\",\n          \"datasource\": \"${DS_K6}\",\n          \"heatmap\": {},\n          \"highlightCards\": true,\n          \"id\": 8,\n          \"interval\": \">1s\",\n          \"links\": [],\n          \"span\": 6,\n          \"targets\": [\n            {\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"null\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_duration\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"A\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [],\n                    \"type\": \"mean\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            }\n          ],\n          \"title\": \"http_req_duration\",\n          \"tooltip\": {\n            \"show\": true,\n            \"showHistogram\": false\n          },\n          \"type\": \"heatmap\",\n          \"xAxis\": {\n            \"show\": true\n          },\n          \"xBucketNumber\": null,\n          \"xBucketSize\": null,\n          \"yAxis\": {\n            \"decimals\": null,\n            \"format\": \"ms\",\n            \"logBase\": 2,\n            \"max\": null,\n            \"min\": null,\n            \"show\": true,\n            \"splitFactor\": null\n          },\n          \"yBucketNumber\": null,\n          \"yBucketSize\": null\n        }\n      ],\n      \"repeat\": null,\n      \"repeatIteration\": null,\n      \"repeatRowId\": null,\n      \"showTitle\": false,\n      \"title\": \"Dashboard Row\",\n      \"titleSize\": \"h6\"\n    },\n    {\n      \"collapse\": false,\n      \"height\": 250,\n      \"panels\": [\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"${DS_K6}\",\n          \"fill\": 1,\n          \"id\": 4,\n          \"interval\": \">1s\",\n          \"legend\": {\n            \"alignAsTable\": true,\n            \"avg\": true,\n            \"current\": false,\n            \"max\": true,\n            \"min\": true,\n            \"show\": true,\n            \"total\": false,\n            \"values\": true\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_connecting\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"C\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [\n                      95\n                    ],\n                    \"type\": \"percentile\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"http_req_connecting (95%ile)\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"ms\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            },\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            }\n          ]\n        },\n        {\n          \"aliasColors\": {},\n          \"bars\": false,\n          \"dashLength\": 10,\n          \"dashes\": false,\n          \"datasource\": \"${DS_K6}\",\n          \"fill\": 1,\n          \"id\": 9,\n          \"interval\": \">1s\",\n          \"legend\": {\n            \"alignAsTable\": true,\n            \"avg\": true,\n            \"current\": false,\n            \"max\": true,\n            \"min\": true,\n            \"show\": true,\n            \"total\": false,\n            \"values\": true\n          },\n          \"lines\": true,\n          \"linewidth\": 1,\n          \"links\": [],\n          \"nullPointMode\": \"null\",\n          \"percentage\": false,\n          \"pointradius\": 5,\n          \"points\": false,\n          \"renderer\": \"flot\",\n          \"seriesOverrides\": [],\n          \"spaceLength\": 10,\n          \"span\": 6,\n          \"stack\": false,\n          \"steppedLine\": false,\n          \"targets\": [\n            {\n              \"dsType\": \"influxdb\",\n              \"groupBy\": [\n                {\n                  \"params\": [\n                    \"$__interval\"\n                  ],\n                  \"type\": \"time\"\n                },\n                {\n                  \"params\": [\n                    \"none\"\n                  ],\n                  \"type\": \"fill\"\n                }\n              ],\n              \"measurement\": \"http_req_blocked\",\n              \"orderByTime\": \"ASC\",\n              \"policy\": \"default\",\n              \"refId\": \"C\",\n              \"resultFormat\": \"time_series\",\n              \"select\": [\n                [\n                  {\n                    \"params\": [\n                      \"value\"\n                    ],\n                    \"type\": \"field\"\n                  },\n                  {\n                    \"params\": [\n                      95\n                    ],\n                    \"type\": \"percentile\"\n                  }\n                ]\n              ],\n              \"tags\": []\n            }\n          ],\n          \"thresholds\": [],\n          \"timeFrom\": null,\n          \"timeShift\": null,\n          \"title\": \"http_req_blocked (95%ile)\",\n          \"tooltip\": {\n            \"shared\": true,\n            \"sort\": 0,\n            \"value_type\": \"individual\"\n          },\n          \"type\": \"graph\",\n          \"xaxis\": {\n            \"buckets\": null,\n            \"mode\": \"time\",\n            \"name\": null,\n            \"show\": true,\n            \"values\": []\n          },\n          \"yaxes\": [\n            {\n              \"format\": \"ms\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            },\n            {\n              \"format\": \"short\",\n              \"label\": null,\n              \"logBase\": 1,\n              \"max\": null,\n              \"min\": null,\n              \"show\": true\n            }\n          ]\n        }\n      ],\n      \"repeat\": null,\n      \"repeatIteration\": null,\n      \"repeatRowId\": null,\n      \"showTitle\": false,\n      \"title\": \"Dashboard Row\",\n      \"titleSize\": \"h6\"\n    }\n  ],\n  \"schemaVersion\": 14,\n  \"style\": \"dark\",\n  \"tags\": [],\n  \"templating\": {\n    \"list\": []\n  },\n  \"time\": {\n    \"from\": \"2017-05-10T17:34:01.817Z\",\n    \"to\": \"2017-05-10T17:39:07.343Z\"\n  },\n  \"timepicker\": {\n    \"refresh_intervals\": [\n      \"5s\",\n      \"10s\",\n      \"30s\",\n      \"1m\",\n      \"5m\",\n      \"15m\",\n      \"30m\",\n      \"1h\",\n      \"2h\",\n      \"1d\"\n    ],\n    \"time_options\": [\n      \"5m\",\n      \"15m\",\n      \"1h\",\n      \"6h\",\n      \"12h\",\n      \"24h\",\n      \"2d\",\n      \"7d\",\n      \"30d\"\n    ]\n  },\n  \"timezone\": \"browser\",\n  \"title\": \"k6\",\n  \"version\": 7\n}"
  },
  {
    "path": "examples/graphql.js",
    "content": "import http from \"k6/http\";\nimport { sleep } from \"k6\";\n\nlet accessToken = \"YOUR_GITHUB_ACCESS_TOKEN\";\n\nexport default function() {\n\n  let query = `\n    query FindFirstIssue {\n      repository(owner:\"grafana\", name:\"k6\") {\n        issues(first:1) {\n          edges {\n            node {\n              id\n              number\n              title\n            }\n          }\n        }\n      }\n    }`;\n\n  let headers = {\n    'Authorization': `Bearer ${accessToken}`,\n    \"Content-Type\": \"application/json\"\n  };\n\n  let res = http.post(\"https://api.github.com/graphql\",\n    JSON.stringify({ query: query }),\n    {headers: headers}\n  );\n\n  if (res.status === 200) {\n    console.log(JSON.stringify(res.body));\n    let body = JSON.parse(res.body);\n    let issue = body.data.repository.issues.edges[0].node;\n    console.log(issue.id, issue.number, issue.title);\n\n    let mutation = `\n      mutation AddReactionToIssue {\n        addReaction(input:{subjectId:\"${issue.id}\",content:HOORAY}) {\n          reaction {\n            content\n          }\n          subject {\n            id\n          }\n        }\n    }`;\n\n    res = http.post(\"https://api.github.com/graphql\",\n      JSON.stringify({query: mutation}),\n      {headers: headers}\n    );\n  }\n  sleep(0.3);\n}\n"
  },
  {
    "path": "examples/grpc_client_streaming.js",
    "content": "import { Client, Stream } from 'k6/net/grpc';\nimport { sleep } from 'k6';\n\nconst COORD_FACTOR = 1e7;\n// to run this sample, you need to start the grpc server first.\n// to start the grpc server, run the following command in k6 repository's root:\n// go run -mod=mod examples/grpc_server/*.go\n// (golang should be installed)\nconst GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';\nconst GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../lib/testutils/grpcservice/route_guide.proto';\n\nlet client = new Client();\nclient.load([], GRPC_PROTO_PATH);\n\n// a sample DB of points\nconst DB = [\n  {\n    location: { latitude: 407838351, longitude: -746143763 },\n    name: 'Patriots Path, Mendham, NJ 07945, USA',\n  },\n  {\n    location: { latitude: 408122808, longitude: -743999179 },\n    name: '101 New Jersey 10, Whippany, NJ 07981, USA',\n  },\n  {\n    location: { latitude: 413628156, longitude: -749015468 },\n    name: 'U.S. 6, Shohola, PA 18458, USA',\n  },\n  {\n    location: { latitude: 419999544, longitude: -740371136 },\n    name: '5 Conners Road, Kingston, NY 12401, USA',\n  },\n  {\n    location: { latitude: 414008389, longitude: -743951297 },\n    name: 'Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA',\n  },\n  {\n    location: { latitude: 419611318, longitude: -746524769 },\n    name: '287 Flugertown Road, Livingston Manor, NY 12758, USA',\n  },\n  {\n    location: { latitude: 406109563, longitude: -742186778 },\n    name: '4001 Tremley Point Road, Linden, NJ 07036, USA',\n  },\n  {\n    location: { latitude: 416802456, longitude: -742370183 },\n    name: '352 South Mountain Road, Wallkill, NY 12589, USA',\n  },\n  {\n    location: { latitude: 412950425, longitude: -741077389 },\n    name: 'Bailey Turn Road, Harriman, NY 10926, USA',\n  },\n  {\n    location: { latitude: 412144655, longitude: -743949739 },\n    name: '193-199 Wawayanda Road, Hewitt, NJ 07421, USA',\n  },\n];\n\n// to run this sample, you need to start the grpc server first.\n// to start the grpc server, run the following command in k6 repository's root:\n// go run -mod=mod examples/grpc_server/*.go\n// (golang should be installed)\n\n// the example below is based on the original GRPC client streaming example\n//\n// It sends several randomly chosen points from the pre-generated\n// feature database with a variable delay in between. Prints the\n// statistics when they are sent from the server.\nexport default () => {\n  if (__ITER == 0) {\n    client.connect(GRPC_ADDR, { plaintext: true });\n  }\n\n  const stream = new Stream(client, 'main.RouteGuide/RecordRoute');\n\n  stream.on('data', (stats) => {\n    console.log('Finished trip with', stats.pointCount, 'points');\n    console.log('Passed', stats.featureCount, 'features');\n    console.log('Travelled', stats.distance, 'meters');\n    console.log('It took', stats.elapsedTime, 'seconds');\n  });\n\n  stream.on('error', (err) => {\n    console.log('Stream Error: ' + JSON.stringify(err));\n  });\n\n  stream.on('end', () => {\n    client.close();\n    console.log('All done');\n  })\n\n  // send 5 random items\n  for (var i = 0; i < 5; i++) {\n    let point = DB[Math.floor(Math.random() * DB.length)];\n    pointSender(stream, point);\n  }\n\n  // close the client stream\n  stream.end();\n};\n\nconst pointSender = (stream, point) => {\n  console.log(\n    'Visiting point ' +\n      point.name +\n      ' ' +\n      point.location.latitude / COORD_FACTOR +\n      ', ' +\n      point.location.longitude / COORD_FACTOR\n  );\n\n  // send the location to the server\n  stream.write(point.location);\n\n  sleep(0.5);\n};\n"
  },
  {
    "path": "examples/grpc_healthcheck.js",
    "content": "import grpc from 'k6/net/grpc';\nimport { check } from \"k6\";\n\n// to run this sample, you need to start the grpc server first.\n// to start the grpc server, run the following command in k6 repository's root:\n// go run -mod=mod examples/grpc_server/*.go\n// (golang should be installed)\nconst GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';\n\nlet client = new grpc.Client();\n\nexport default () => {\n\tclient.connect(GRPC_ADDR, { plaintext: true });\n\n\tconst response = client.healthCheck()\n\n\tcheck(response, { \"healthcheck status is OK\": (r) => r && r.status === grpc.HealthCheckServing });\n\n\tclient.close()\n}\n"
  },
  {
    "path": "examples/grpc_invoke.js",
    "content": "import grpc from 'k6/net/grpc';\nimport { check } from \"k6\";\n\n// to run this sample, you need to start the grpc server first.\n// to start the grpc server, run the following command in k6 repository's root:\n// go run -mod=mod examples/grpc_server/*.go\n// (golang should be installed)\nconst GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';\nconst GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../internal/lib/testutils/grpcservice/route_guide.proto';\n\nlet client = new grpc.Client();\n\nclient.load([], GRPC_PROTO_PATH);\n\nexport default () => {\n  client.connect(GRPC_ADDR, { plaintext: true });\n\n    const response = client.invoke(\"main.FeatureExplorer/GetFeature\", {\n        latitude: 410248224,\n        longitude: -747127767\n    })\n\n    check(response, { \"status is OK\": (r) => r && r.status === grpc.StatusOK });\n    console.log(JSON.stringify(response.message))\n\n    client.close()\n}\n\n"
  },
  {
    "path": "examples/grpc_reflection.js",
    "content": "import grpc from 'k6/net/grpc';\nimport {check} from \"k6\";\n\n// to run this sample, you need to start the grpc server first.\n// to start the grpc server, run the following command in k6 repository's root:\n// go run -mod=mod examples/grpc_server/*.go\n// (golang should be installed)\nconst GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';\n\nlet client = new grpc.Client();\n\nexport default () => {\n  client.connect(GRPC_ADDR, { plaintext: true, reflect: true });\n  const response = client.invoke('main.FeatureExplorer/GetFeature', {\n    latitude: 410248224,\n    longitude: -747127767,\n  });\n\n  check(response, { 'status is OK': (r) => r && r.status === grpc.StatusOK });\n  console.log(JSON.stringify(response.message));\n\n  client.close();\n};\n"
  },
  {
    "path": "examples/grpc_server/go.mod",
    "content": "module go.k6.io/k6/examples/grpc_server\n\ngo 1.24.0\n\ntoolchain go1.24.7\n\nreplace go.k6.io/k6 => ../../\n\nrequire (\n\tgo.k6.io/k6 v0.0.0-00010101000000-000000000000\n\tgoogle.golang.org/grpc v1.77.0\n)\n\nrequire (\n\tgolang.org/x/net v0.49.0 // indirect\n\tgolang.org/x/sys v0.40.0 // indirect\n\tgolang.org/x/text v0.33.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect\n\tgoogle.golang.org/protobuf v1.36.11 // indirect\n)\n"
  },
  {
    "path": "examples/grpc_server/go.sum",
    "content": "github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=\ngo.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=\ngo.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=\ngo.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=\ngo.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=\ngo.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=\ngo.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=\ngo.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=\ngo.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=\ngolang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=\ngolang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=\ngolang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=\ngolang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=\ngolang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=\ngonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=\ngonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=\ngoogle.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=\ngoogle.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\n"
  },
  {
    "path": "examples/grpc_server/main.go",
    "content": "/*\n *\n * Copyright 2015 gRPC authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n// Package main implements a simple gRPC server that demonstrates how to use gRPC-Go libraries\n// to perform unary, client streaming, server streaming and full duplex RPCs.\n//\n// It implements the route guide service whose definition can be found in routeguide/route_guide.proto.\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/health\"\n\thealthpb \"google.golang.org/grpc/health/grpc_health_v1\"\n\t\"google.golang.org/grpc/reflection\"\n\t\"google.golang.org/grpc/testdata\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/grpcservice\"\n)\n\nvar (\n\ttls        = flag.Bool(\"tls\", false, \"Connection uses TLS if true, else plain TCP\")\n\tcertFile   = flag.String(\"cert_file\", \"\", \"The TLS cert file\")\n\tkeyFile    = flag.String(\"key_file\", \"\", \"The TLS key file\")\n\tjsonDBFile = flag.String(\"json_db_file\", \"\", \"A json file containing a list of features\")\n\tport       = flag.Int(\"port\", 10000, \"The server port\")\n)\n\nfunc main() {\n\tflag.Parse()\n\n\tlog.Printf(\"gRPC server starting on localhost:%d\\n\", *port)\n\n\tlis, err := net.Listen(\"tcp\", fmt.Sprintf(\"localhost:%d\", *port))\n\tif err != nil {\n\t\tlog.Fatalf(\"failed to listen: %v\", err)\n\t}\n\tvar opts []grpc.ServerOption\n\tif *tls {\n\t\tif *certFile == \"\" {\n\t\t\t*certFile = testdata.Path(\"server1.pem\")\n\t\t}\n\t\tif *keyFile == \"\" {\n\t\t\t*keyFile = testdata.Path(\"server1.key\")\n\t\t}\n\t\tcreds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)\n\t\tif err != nil {\n\t\t\tlog.Fatalf(\"Failed to generate credentials %v\", err)\n\t\t}\n\t\topts = []grpc.ServerOption{grpc.Creds(creds)}\n\t}\n\tfeatures := grpcservice.LoadFeatures(*jsonDBFile)\n\tgrpcServer := grpc.NewServer(opts...)\n\tgrpcservice.RegisterRouteGuideServer(grpcServer, grpcservice.NewRouteGuideServer(features...))\n\tgrpcservice.RegisterFeatureExplorerServer(grpcServer, grpcservice.NewFeatureExplorerServer(features...))\n\thealthcheck := health.NewServer()\n\thealthpb.RegisterHealthServer(grpcServer, healthcheck)\n\thealthcheck.SetServingStatus(\"\", healthpb.HealthCheckResponse_SERVING)\n\treflection.Register(grpcServer)\n\tgrpcServer.Serve(lis)\n}\n"
  },
  {
    "path": "examples/grpc_server_streaming.js",
    "content": "import { Client, Stream } from 'k6/net/grpc';\nimport { sleep } from 'k6';\n\nconst COORD_FACTOR = 1e7;\n// to run this sample, you need to start the grpc server first.\n// to start the grpc server, run the following command in k6 repository's root:\n// go run -mod=mod examples/grpc_server/*.go\n// (golang should be installed)\nconst GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';\nconst GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../internal/lib/testutils/grpcservice/route_guide.proto';\n\nlet client = new Client();\n\nclient.load([], GRPC_PROTO_PATH);\n\nexport default () => {\n  client.connect(GRPC_ADDR, { plaintext: true });\n\n  const stream = new Stream(client, 'main.FeatureExplorer/ListFeatures', null);\n\n  stream.on('data', function (feature) {\n    console.log(\n      'Found feature called \"' +\n        feature.name +\n        '\" at ' +\n        feature.location.latitude / COORD_FACTOR +\n        ', ' +\n        feature.location.longitude / COORD_FACTOR\n    );\n  });\n\n  stream.on('end', function () {\n    // The server has finished sending\n    client.close();\n    console.log('All done');\n  });\n\n  stream.on('error', function (e) {\n    // An error has occurred and the stream has been closed.\n    console.log('Error: ' + JSON.stringify(e));\n  });\n\n  // send a message to the server\n  stream.write({\n    lo: {\n      latitude: 400000000,\n      longitude: -750000000,\n    },\n    hi: {\n      latitude: 420000000,\n      longitude: -730000000,\n    },\n  });\n\n  sleep(0.5);\n};\n"
  },
  {
    "path": "examples/html_form_post.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\n// Our form data, to be URL-encoded and POSTed\nconst form_data = {\n    name: \"Test Name\",\n    telephone: \"123456789\",\n    email: \"test@example.com\",\n    comment: \"Hello world!\",\n    topping: [\n        'onion',\n        'bacon',\n        'cheese'\n    ]\n};\n\nexport default function() {\n    // Passing an object as the data parameter will automatically form-urlencode it\n    let res = http.post(\"http://httpbin.org/post\", form_data);\n\n    // Verify response\n    check(res, {\n        \"status is 200\": (r) => r.status === 200,\n        \"has correct name\": (r) => r.json().form.name === form_data.name,\n        \"has correct telephone number\": (r) => r.json().form.telephone === form_data.telephone,\n        \"has correct email\": (r) => r.json().form.email === form_data.email,\n        \"has correct comment\": (r) => r.json().form.comment === form_data.comment,\n        \"has correct toppings\": (r) => JSON.stringify(r.json().form.topping) === JSON.stringify(form_data.topping)\n    });\n}\n"
  },
  {
    "path": "examples/http_2.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function () {\n  check(http.get(\"https://quickpizza.grafana.com\"), {\n    \"status is 200\": (r) => r.status == 200,\n    \"protocol is HTTP/2\": (r) => r.proto == \"HTTP/2.0\",\n  });\n}\n"
  },
  {
    "path": "examples/http_basic_auth.js",
    "content": "import encoding from \"k6/encoding\";\nimport http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function() {\n    // Passing username and password as part of URL will authenticate using HTTP Basic Auth\n    let res = http.get(\"http://user:passwd@httpbin.org/basic-auth/user/passwd\");\n\n    // Verify response\n    check(res, {\n        \"status is 200\": (r) => r.status === 200,\n        \"is authenticated\": (r) => r.json().authenticated === true,\n        \"is correct user\": (r) => r.json().user === \"user\"\n    });\n\n    // Alternatively you can create the header yourself to authenticate using HTTP Basic Auth\n    res = http.get(\"http://httpbin.org/basic-auth/user/passwd\", { headers: { \"Authorization\": \"Basic \" + encoding.b64encode(\"user:passwd\") }});\n\n    // Verify response\n    check(res, {\n        \"status is 200\": (r) => r.status === 200,\n        \"is authenticated\": (r) => r.json().authenticated === true,\n        \"is correct user\": (r) => r.json().user === \"user\"\n    });\n}\n"
  },
  {
    "path": "examples/http_batch.js",
    "content": "import { check } from 'k6';\nimport http from 'k6/http';\n\nexport default function() {\n  const responses = http.batch([\n    \"https://quickpizza.grafana.com/test.k6.io\",\n    \"https://quickpizza.grafana.com/pi.php\"\n  ]);\n\n  check(responses[0], {\n    \"main page 200\": res => res.status === 200,\n  });\n\n  check(responses[1], {\n    \"pi page 200\": res => res.status === 200,\n    \"pi page has right content\": res => res.body === \"3.14\",\n  });\n};\n"
  },
  {
    "path": "examples/http_digest_auth.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function() {\n    // Passing username and password as part of URL plus the auth option will authenticate using HTTP Digest authentication\n    let res = http.get(\"http://user:passwd@httpbin.org/digest-auth/auth/user/passwd\", {auth: \"digest\"});\n\n    // Verify response\n    check(res, {\n        \"status is 200\": (r) => r.status === 200,\n        \"is authenticated\": (r) => r.json().authenticated === true,\n        \"is correct user\": (r) => r.json().user === \"user\"\n    });\n}\n"
  },
  {
    "path": "examples/http_get.js",
    "content": "import http from 'k6/http';\n\nexport default function () {\n  http.get('https://quickpizza.grafana.com');\n};\n"
  },
  {
    "path": "examples/http_verbs.js",
    "content": "import http from \"k6/http\";\nimport { check, group } from \"k6\";\n\n/*\n * k6 supports all standard HTTP verbs/methods:\n * CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT and TRACE.\n * \n * Below are examples showing how to use the most common of these.\n */\n\nexport default function() {\n    // GET request\n    group(\"GET\", function() {\n        let res = http.get(\"http://httpbin.org/get?verb=get\");\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"is verb correct\": (r) => r.json().args.verb === \"get\",\n        });\n    });\n\n    // POST request\n    group(\"POST\", function() {\n        let res = http.post(\"http://httpbin.org/post\", { verb: \"post\" });\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"is verb correct\": (r) => r.json().form.verb === \"post\",\n        });\n    });\n\n    // PUT request\n    group(\"PUT\", function() {\n        let res = http.put(\"http://httpbin.org/put\", JSON.stringify({ verb: \"put\" }), { headers: { \"Content-Type\": \"application/json\" }});\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"is verb correct\": (r) => r.json().json.verb === \"put\",\n        });\n    });\n\n    // PATCH request\n    group(\"PATCH\", function() {\n        let res = http.patch(\"http://httpbin.org/patch\", JSON.stringify({ verb: \"patch\" }), { headers: { \"Content-Type\": \"application/json\" }});\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"is verb correct\": (r) => r.json().json.verb === \"patch\",\n        });\n    });\n\n    // DELETE request\n    group(\"DELETE\", function() {\n        let res = http.del(\"http://httpbin.org/delete?verb=delete\");\n        check(res, {\n            \"status is 200\": (r) => r.status === 200,\n            \"is verb correct\": (r) => r.json().args.verb === \"delete\",\n        });\n    });\n}\n"
  },
  {
    "path": "examples/json.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function() {\n    // Send a JSON encoded POST request\n    let body = JSON.stringify({ key: \"value\" });\n    let res = http.post(\"http://httpbin.org/post\", body, { headers: { \"Content-Type\": \"application/json\" }});\n\n    // Use JSON.parse to deserialize the JSON (instead of using the r.json() method)\n    let j = JSON.parse(res.body);\n\n    // Verify response\n    check(res, {\n        \"status is 200\": (r) => r.status === 200,\n        \"is key correct\": (r) => j.json.key === \"value\",\n    });\n}\n"
  },
  {
    "path": "examples/jwt.js",
    "content": "import crypto from \"k6/crypto\";\nimport encoding from \"k6/encoding\";\nimport {sleep} from \"k6\";\n\nconst algToHash = {\n    HS256: \"sha256\",\n    HS384: \"sha384\",\n    HS512: \"sha512\"\n};\n\nfunction sign(data, hashAlg, secret) {\n    let hasher = crypto.createHMAC(hashAlg, secret);\n    hasher.update(data);\n\n    // Some manual base64 rawurl encoding as `Hasher.digest(encodingType)`\n    // doesn't support that encoding type yet.\n    return hasher.digest(\"base64\").replace(/\\//g, \"_\").replace(/\\+/g, \"-\").replace(/=/g, \"\");\n}\n\nfunction encode(payload, secret, algorithm) {\n    algorithm = algorithm || \"HS256\";\n    let header = encoding.b64encode(JSON.stringify({ typ: \"JWT\", alg: algorithm }), \"rawurl\");\n    payload = encoding.b64encode(JSON.stringify(payload), \"rawurl\", \"s\");\n    let sig = sign(header + \".\" + payload, algToHash[algorithm], secret);\n    return [header, payload, sig].join(\".\");\n}\n\nfunction decode(token, secret, algorithm) {\n    let parts = token.split('.');\n    let header = JSON.parse(encoding.b64decode(parts[0], \"rawurl\", \"s\"));\n    let payload = JSON.parse(encoding.b64decode(parts[1], \"rawurl\", \"s\"));\n    algorithm = algorithm || algToHash[header.alg];\n    if (sign(parts[0] + \".\" + parts[1], algorithm, secret) != parts[2]) {\n        throw Error(\"JWT signature verification failed\");\n    }\n    return payload;\n}\n\nexport default function() {\n    let message = { key2: \"value2\" };\n    let token = encode(message, \"secret\");\n    console.log(\"encoded\", token);\n    let payload = decode(token, \"secret\");\n    console.log(\"decoded\", JSON.stringify(payload));\n    sleep(1)\n}\n"
  },
  {
    "path": "examples/localhost.js",
    "content": "import { group, check } from \"k6\";\nimport http from \"k6/http\";\n\nexport let options = {\n\tthresholds: {\n\t\t'http_req_duration{kind:html}': [\"avg<=10\"],\n\t\t'http_req_duration{kind:css}': [\"avg<=10\"],\n\t\t'http_req_duration{kind:img}': [\"avg<=100\"],\n\t\t'http_reqs': [\"rate>100\"],\n\t}\n};\n\nexport default function() {\n\tgroup(\"front page\", function() {\n\t\tcheck(http.get(\"http://localhost:8080/\", {\n\t\t\ttags: {'kind': 'html' },\n\t\t}), {\n\t\t\t\"status is 200\": (res) => res.status === 200,\n\t\t});\n\t});\n\tgroup(\"stylesheet\", function() {\n\t\tcheck(http.get(\"http://localhost:8080/style.css\", {\n\t\t\ttags: {'kind': 'css' },\n\t\t}), {\n\t\t\t\"status is 200\": (res) => res.status === 200,\n\t\t});\n\t});\n\tgroup(\"image\", function() {\n\t\tcheck(http.get(\"http://localhost:8080/teddy.jpg\", {\n\t\t\ttags: {'kind': 'img' },\n\t\t}), {\n\t\t\t\"status is 200\": (res) => res.status === 200,\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "examples/logging.js",
    "content": "export default function() {\n\tconsole.log(\"log\", \"a\", \"b\");\n\tconsole.debug(\"debug\", \"a\", \"b\");\n\tconsole.info(\"info\", \"a\", \"b\");\n\tconsole.warn(\"warn\", \"a\", \"b\");\n\tconsole.error(\"error\", \"a\", \"b\");\n}\n"
  },
  {
    "path": "examples/malicious.js",
    "content": "export default function() {\n\twhile (true) {\n\t\t// do nothing, forever!!\n\t}\n}\n"
  },
  {
    "path": "examples/ocsp.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function() {\n    let res = http.get(\"https://stackoverflow.com\");\n    check(res, {\n        \"is OCSP response good\": (r) => r.ocsp.status === http.OCSP_STATUS_GOOD\n    });\n};\n"
  },
  {
    "path": "examples/pantheon.js",
    "content": "//\n// This is an advanced k6 script sample that simulates users\n// logging into an e-commerce site and purchasing things there.\n//\n\nimport { group, check, sleep, fail } from \"k6\";\nimport http from \"k6/http\";\n\nexport let options = {\n\tmaxRedirects: 10,\n}\n\n// Base URL where the site is located\nconst baseURL = \"https://dev-li-david.pantheonsite.io\";\n\n// User think time in between page loads etc. (change this to 0 when debugging)\nconst thinkTime = 30;\n\n// List of login usernames and passwords\nconst credentials = [\n\t{ username: \"testuser1\", password: \"testuser1\" },\n];\n\n// Main function that gets executed by VUs repeatedly\nexport default function() {\n\t// Load front/home page on site\n\tgroup(\"front page\", doFrontPage);\n\tsleep(thinkTime);\n\n\t// Go to user login page and log in\n\tgroup(\"login page\", doLogin);\n\tsleep(thinkTime);\n\n\t// Visit a random selection of available product category pages, and \n\t// randomly add products from each category to our cart\n\tfor (name in categories) {\n\t\tif (Math.random() <= categories[name].chance) {\n\t\t\tgroup(name, function() { doCategory(categories[name]); });\n\t\t\tsleep(thinkTime);\n\t\t}\n\t}\n\n\t// Check out our cart, perform payment\n\tgroup(\"checkout\", doCheckout);\n\tsleep(thinkTime);\n\n\t// Log out the user\n\tgroup(\"logout\", doLogout);\n\tsleep(thinkTime);\n}\n\n// \"categories\" is an object containing information about the various \n// product categories and the products available in each category:\n//\n// categories[name].url      = the URL for the product category page.\n//\n// categories[name].chance   = the likelihood that the product category \n//                             gets visited by the VU on each VU iteration.\n//\n// categories[name].title    = the HTML <title> text to look for, to determine \n//                             that the category page was loaded correctly.\n//\n// categories[name].products = an object containing info about the different\n//                             products available under that category. See\n//                             below for a description of the product object.\n//\n//\n// products[name].url    = the URL for the product page.\n//\n// products[name].chance = the likelihood that a) the product page gets \n//                         visited when its parent product category page\n//                         gets visited, and b) the product gets added to\n//                         the VUs shopping cart when the product page is\n//                         visited.\n//              \n// products[name].title  = the HTML <title> text to look for, when trying\n//                         to determine if the product page was loaded \n//                         correctly.\n//\nconst categories = {\n\t\"To Carry\": {\n\t\turl: `${baseURL}/collection/carry`,\n\t\ttitle: \"To carry | David li commerce-test\",\n\t\tchance: 0.5,\n\t\tproducts: {\n\t\t\t\"Laptop bag\": {\n\t\t\t\turl: `${baseURL}/bags-cases/commerce-guys-laptop-bag`,\n\t\t\t\ttitle: \"Commerce Guys Laptop Bag | David li commerce-test\",\n\t\t\t\tchance: 0.25,\n\t\t\t},\n\t\t\t\"Drupal Bag\": {\n\t\t\t\turl: `${baseURL}/bags-cases/drupal-commerce-messenger-bag`,\n\t\t\t\ttitle: \"Drupal Commerce Messenger Bag | David li commerce-test\",\n\t\t\t\tchance: 0.25,\n\t\t\t},\n\t\t}\n\t},\n\t\"To Drink With\": {\n\t\turl: `${baseURL}/collection/drink`,\n\t\ttitle: \"To drink with | David li commerce-test\",\n\t\tchance: 0.5,\n\t\tproducts: {\n\t\t\t\"Drupal Commerce to Wake You Up\": {\n\t\t\t\turl: `${baseURL}/drinks/drupal-commerce-wake-you`,\n\t\t\t\ttitle: \"Drupal Commerce to Wake You Up | David li commerce-test\",\n\t\t\t\tchance: 0.25,\n\t\t\t},\n\t\t\t\"The Guy Mug\": {\n\t\t\t\turl: `${baseURL}/drinks/guy-mug`,\n\t\t\t\ttitle: \"\\\"The Guy\\\" Mug  | David li commerce-test\",\n\t\t\t\tchance: 0.25,\n\t\t\t},\n\t\t}\n\t}\n};\n\n\n// Request the front/home page, plus static resources\nfunction doFrontPage() {\n\t// Load the front page.\n\tcheck(http.get(baseURL + \"/\"), {\n\t\t\"title is correct\": (res) => res.html(\"title\").text() == \"Welcome to David li commerce-test | David li commerce-test\",\n\t});\n\n\t// Load static assets.\n\tgroup(\"static resources\", function() { http.batch(staticAssets); });\n}\n\n// Request the login page and perform a user login\nfunction doLogin() {\n\t// Request the login page.\n\tlet res = http.get(baseURL + \"/user/login\");\n\tcheck(res, {\n\t\t\"title is correct\": (res) => res.html(\"title\").text() == \"User account | David li commerce-test\",\n\t});\n\n\t// TODO: Add attr() to k6/html!\n\t// Extract hidden input fields.\n\tlet formBuildID = res.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n\n\tgroup(\"login\", function() {\n\t\t// Pick a random set of credentials.\n\t\tlet creds = credentials[Math.floor(Math.random()*credentials.length)];\n\n\t\t// Create login request.\n\t\tlet formdata = {\n\t\t\tname: creds.username,\n\t\t\tpass: creds.password,\n\t\t\tform_build_id: formBuildID,\n\t\t\tform_id: \"user_login\",\n\t\t\top: \"Log in\",\n\t\t};\n\t\tlet headers = { \"Content-Type\": \"application/x-www-form-urlencoded\" };\n\t\t// Send login request\n\t\tlet res = http.post(baseURL + \"/user/login\", formdata, { headers: headers });\n\t\t// Verify that we ended up on the user page\n\t\tcheck(res, {\n\t\t\t\"login succeeded\": (res) => res.url == `${baseURL}/users/${creds.username}`,\n\t\t}) || fail(\"login failed\");\n\t});\n}\n\n// Load a product category page, then potentially load some product pages\nfunction doCategory(category) {\n\tcheck(http.get(category.url), {\n\t\t\"title is correct\": (res) => res.html(\"title\").text() == category.title,\n\t});\n\n\tfor (prodName in category.products) {\n\t\tif (Math.random() <= category.products[prodName].chance) {\n\t\t\tgroup(prodName, function() { doProductPage(category.products[prodName]) });\n\t\t}\n\t}\n}\n\n// Load product page and potentially add product to cart\nfunction doProductPage(product) {\n\tlet res = http.get(product.url);\n\tcheck(res, {\n\t\t\"title is correct\": (res) => res.html(\"title\").text() == product.title,\n\t});\n\tif (Math.random() <= product.chance) {\n\t\tlet formBuildID = res.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n\t\tlet formID = res.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n\t\tlet formToken = res.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n\t\tlet productID = res.body.match('name=\"product_id\" value=\"(.*)\"')[1];\n\t\tgroup(\"add to cart\", function() { \n\t\t\taddProductToCart(product.url, productID, formID, formBuildID, formToken)\n\t\t});\n\t}\n}\n\n// Add a product to our shopping cart\nfunction addProductToCart(url, productID, formID, formBuildID, formToken) {\n\tlet formdata = {\n\t\tproduct_id: productID,\n\t\tform_id: formID,\n\t\tform_build_id: formBuildID,\n\t\tform_token: formToken,\n\t\tquantity: 1,\n\t\top: \"Add to cart\",\n\t};\n\tlet headers = { \"Content-Type\": \"application/x-www-form-urlencoded\" };\n\tlet res = http.post(url, formdata, { headers: headers });\n\t// verify add to cart succeeded\n\tcheck(res, {\n\t\t\"add to cart succeeded\": (res) => res.body.includes('Item successfully added to your cart')\n\t}) || fail(\"add to cart failed\");\n}\n\n// Perform multi-step (multi-page) checkout\nfunction doCheckout() {\n\tvar res;\n\n\tgroup(\"Checkout 1: review cart\", function() {\n\t\t// Checkout step 1: Review cart\n\t\tres = http.get(baseURL + \"/cart\");\n\t\tcheck(res, {\n\t\t\t\"title is correct\": (res) => res.html(\"title\").text() === 'Shopping cart | David li commerce-test'\n\t\t});\n\t});\n\n\t// Did we add any products to our cart?  If not, skip the rest of the checkout process\n\tif (res.body.includes(\"Your shopping cart is empty.\")) {\n\t\treturn;\n\t}\n\n\tgroup(\"Checkout 2: submit cart\", function() {\n\t\tlet formID = res.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n\t\tlet formToken = res.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n\t\tlet formBuildID = res.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n\t\tlet formdata = {\n\t\t\t\"form_build_id\": formBuildID,\n\t\t\t\"form_token\": formToken,\n\t\t\t\"form_id\": formID,\n\t\t\t\"op\": \"Checkout\"\n\t\t};\n\t\tlet headers = { \"Content-Type\": \"application/x-www-form-urlencoded\" };\n\t\tres = http.post(baseURL + \"/cart\", formdata, { headers: headers });\n\t\tcheck(res, {\n\t\t\t\"cart submit succeeded\": (res) => res.url.includes(\"/checkout/\")\n\t\t}) || fail(\"cart submit failed\");\n\t});\n\n\t// The previous POST operation should get redirected to a dynamic URL that has a\n\t// path that looks like e.g. \"/checkout/7\". Later checkout steps get redirected\n\t// to paths that are prefixed with this dynamic string, which means we need to\n\t// save it in order to be able to (easily) verify that later POSTs are successful\n\t// and get redirected to e.g. \"/checkout/7/shipping\"\n\tlet checkoutBaseURL = res.url;\n\n\tgroup(\"Checkout 3: billing details\", function() {\n\t\tlet formID = res.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n\t\tlet formToken = res.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n\t\tlet formBuildID = res.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n\t\t// try without setting Referer\n\t\tlet formdata = {\n\t\t\t\"customer_profile_billing[commerce_customer_address][und][0][country]\": \"SE\",\n\t\t\t\"customer_profile_billing[commerce_customer_address][und][0][name_line]\": \"Mr Test\",\n\t\t\t\"customer_profile_billing[commerce_customer_address][und][0][thoroughfare]\": \"Gotgatan 14\",\n\t\t\t\"customer_profile_billing[commerce_customer_address][und][0][premise]\": \"\",\n\t\t\t\"customer_profile_billing[commerce_customer_address][und][0][postal_code]\": \"11846\",\n\t\t\t\"customer_profile_billing[commerce_customer_address][und][0][locality]\": \"Stockholm\",\n\t\t\t\"customer_profile_shipping[commerce_customer_profile_copy]\": \"1\",\n\t\t\t\"form_build_id\": formBuildID,\n\t\t\t\"form_token\": formToken,\n\t\t\t\"form_id\": formID,\n\t\t\t\"op\": \"Continue to next step\"\n\t\t};\n\t\tlet headers = { \"Content-Type\": \"application/x-www-form-urlencoded\" };\n\t\tres = http.post(checkoutBaseURL, formdata, { headers: headers });\n\t\tcheck(res, {\n\t\t\t\"billing details succeeded\": (res) => res.url === (checkoutBaseURL + \"/shipping\")\n\t\t}) || fail(\"billing details failed\"); \n\t});\n\n\tgroup(\"Checkout 4: shipping options\", function() {\n\t\tlet formID = res.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n\t\tlet formToken = res.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n\t\tlet formBuildID = res.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n\t\tlet formdata = {\n\t\t\t\"commerce_shipping[shipping_service]\": \"express_shipping\",\n\t\t\t\"form_build_id\": formBuildID,\n\t\t\t\"form_token\": formToken,\n\t\t\t\"form_id\": formID,\n\t\t\t\"op\": \"Continue to next step\"\n\t\t};\n\t\tlet headers = { \"Content-Type\": \"application/x-www-form-urlencoded\" };\n\t\tres = http.post(checkoutBaseURL + \"/shipping\", formdata, { headers: headers });\n\t\tcheck(res, {\n\t\t\t\"shipping options succeeded\": (res) => res.url === (checkoutBaseURL + \"/review\")\n\t\t}) || console.log(\"Select shipping failed!\");\n\t});\n\t\n\tgroup(\"Checkout 5: review and submit\", function() {\n\t\tlet formID = res.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n\t\tlet formToken = res.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n\t\tlet formBuildID = res.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n\t\tlet formdata = {\n\t\t\t\"commerce_payment[payment_method]\": \"commerce_payment_example|commerce_payment_commerce_payment_example\",\n\t\t\t\"commerce_payment[payment_details][credit_card][number]\": \"4111111111111111\",\n\t\t\t\"commerce_payment[payment_details][credit_card][exp_month]\": \"03\",\n\t\t\t\"commerce_payment[payment_details][credit_card][exp_year]\": \"2019\",\n\t\t\t\"form_build_id\": formBuildID,\n\t\t\t\"form_token\": formToken,\n\t\t\t\"form_id\": formID,\n\t\t\t\"op\": \"Continue to next step\"\n\t\t};\n\t\tlet headers = { \"Content-Type\": \"application/x-www-form-urlencoded\" };\n\t\tres = http.post(checkoutBaseURL + \"/review\", formdata, { headers: headers });\n\t\t// if this POST succeeds, it will redirect to e.g. /checkout/7/payment\n\t\t// /checkout/7/payment, in turn, will redirect to /checkout/7/paypal_ec\n\t\t// /checkout/7/paypal_ec, in turn, will redirect to /checkout/7/complete\n\t\tcheck(res, {\n\t\t\t\"Checkout 6: checkout complete\": (res) => res.html(\"h1\").text() === \"Checkout complete\"\n\t\t}) || fail(\"review and submit failed\");\n\t});\n}\n\n// Log out the user\nfunction doLogout() {\n\tcheck(http.get(baseURL + \"/user/logout\"), {\n\t\t\"logout succeeded\": (res) => res.body.includes('<a href=\"/user/login\">Log in')\n\t}) || fail(\"logout failed\");\n}\n\n// Static resources to be loaded once per VU iteration\nconst staticAssets = [\n\tbaseURL + \"/modules/system/system.base.css?olqap9\",\n\tbaseURL + \"/modules/system/system.menus.css?olqap9\",\n\tbaseURL + \"/modules/system/system.messages.css?olqap9\",\n\tbaseURL + \"/modules/system/system.theme.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/cloud_zoom/css/cloud_zoom.css?olqap9\",\n\tbaseURL + \"/misc/ui/jquery.ui.core.css?olqap9\",\n\tbaseURL + \"/misc/ui/jquery.ui.theme.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/libraries/jquery_ui_spinner/ui.spinner.css?olqap9\",\n\tbaseURL + \"/modules/comment/comment.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/commerce_add_to_cart_confirmation/css/commerce_add_to_cart_confirmation.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/date/date_api/date.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/date/date_popup/themes/datepicker.1.7.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/fences/field.css?olqap9\",\n\tbaseURL + \"/modules/node/node.css?olqap9\",\n\tbaseURL + \"/modules/user/user.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/views/css/views.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/ctools/css/ctools.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/commerce/modules/line_item/theme/commerce_line_item.theme.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/commerce/modules/product/theme/commerce_product.theme.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/commerce_fancy_attributes/commerce_fancy_attributes.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/alpha-reset.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/alpha-mobile.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/alpha-alpha.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/formalize.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-text.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-branding.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-menu.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-forms.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/global.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce_kickstart_style.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/omega-kickstart-alpha-default.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/omega-kickstart-alpha-default-narrow.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce-kickstart-theme-alpha-default.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce-kickstart-theme-alpha-default-narrow.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/grid/alpha_default/narrow/alpha-default-narrow-24.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/omega-kickstart-alpha-default-normal.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce-kickstart-theme-alpha-default-normal.css?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/grid/alpha_default/normal/alpha-default-normal-24.css?olqap9\",\n\tbaseURL + \"/misc/jquery.js?v=1.4.4\",\n\tbaseURL + \"/misc/jquery.once.js?v=1.2\",\n\tbaseURL + \"/misc/drupal.js?olqap9\",\n\tbaseURL + \"/misc/ui/jquery.ui.core.min.js?v=1.8.7\",\n\tbaseURL + \"/misc/ui/jquery.ui.widget.min.js?v=1.8.7\",\n\tbaseURL + \"/profiles/commerce_kickstart/libraries/cloud-zoom/cloud-zoom.1.0.3.min.js?v=1.0.3\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/cloud_zoom/js/cloud_zoom.js?v=1.0.3\",\n\tbaseURL + \"/profiles/commerce_kickstart/libraries/jquery_expander/jquery.expander.min.js?v=1.4.2\",\n\tbaseURL + \"/profiles/commerce_kickstart/libraries/jquery_ui_spinner/ui.spinner.min.js?v=1.8\",\n\tbaseURL + \"/profiles/commerce_kickstart/libraries/selectnav.js/selectnav.min.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/commerce_add_to_cart_confirmation/js/commerce_add_to_cart_confirmation.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_search/commerce_kickstart_search.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/service_links/js/twitter_button.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/service_links/js/facebook_like.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/service_links/js/google_plus_one.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/contrib/commerce_fancy_attributes/commerce_fancy_attributes.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product_ui/commerce_kickstart_product_ui.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/js/omega_kickstart.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/js/jquery.formalize.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/js/omega-mediaqueries.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/js/commerce_kickstart_theme_custom.js?olqap9\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/logo.png\",\n\tbaseURL + \"/sites/default/files/styles/product_full/public/messenger-1v1.jpg?itok=hPe-GkYY\",\n\tbaseURL + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v1.jpg?itok=cXkqMlMc\",\n\tbaseURL + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v2.jpg?itok=yyhLIuCD\",\n\tbaseURL + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v3.jpg?itok=uQsNvRiQ\",\n\tbaseURL + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v4.jpg?itok=ns9kHz1T\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/bg.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/picto_cart.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_magnifying_glass.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/bg_product_attributes_bottom.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/bg_product_attributes_top.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/bg_add_to_cart.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/bg_block_footer_title.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/icon_facebook.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/icon_twitter.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/icon_pinterest.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_mastercard.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_paypal.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_visa_premier.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_american_express.png\",\n\tbaseURL + \"/misc/ui/images/ui-bg_glass_75_e6e6e6_1x400.png\",\n\tbaseURL + \"/misc/ui/images/ui-icons_888888_256x240.png\",\n\tbaseURL + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/btn_read_more.png\",\n\tbaseURL + \"/sites/default/files/messenger-1v1.jpg\",\n\tbaseURL + \"/profiles/commerce_kickstart/libraries/cloud-zoom/blank.png\",\n];"
  },
  {
    "path": "examples/pantheontest.js",
    "content": "import { group, check, sleep } from \"k6\";\nimport http from \"k6/http\";\n\nexport let options = {\n    maxRedirects: 10\n};\n\n//\n// This is an advanced k6 script sample that simulates users\n// logging into an e-commerce site and purchasing things there.\n//\n\n// Emulate Chrome on MacOS\nlet defaultheaders = {\n    \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36\",\n    \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\",\n//    \"Accept-Encoding\": \"gzip, deflate, sdch\",  --- we do not want compressed content\n    \"Accept-Language\": \"en-US,en;q=0.8,sv;q=0.6\"\n};\n\n// Create a version of our default headers with a static If-Modified-Since header. We use this\n// to ask for cached resources where we want the server to return a 304 rather than the actual content.\nlet cacheheaders = defaultheaders;\ncacheheaders[\"If-Modified-Since\"] = \"Tue, 21 Feb 2017 14:24:11 GMT\";\n\n// Read our username and password from the users.json file, which should have the following format:\n// [ { \"username\": \"joe\", \"password\": \"secret\" }, { \"username\": \"anne\", \"password\": \"alsosecret\" }, ... ]\n// Use our unique VU id number to index the contents of the file and find our particular user data\n//\n//let users = JSON.parse(open(\"users.json\"));\nlet users = [ \n    { \"username\": \"testuser1\", \"password\": \"testuser1\" }\n];\n\n// Base URL for the site\nlet baseurl = \"http://dev-li-david.pantheonsite.io\";\n\n// A few globals used in the purchase flow\nlet form_build_id = \"\";\nlet form_id = \"\";\nlet form_token= \"\";\nlet checkout_url = \"\";\nlet referer = \"\";\n\n// Simpler, alternate main loop that logs in, performs a purchase and logs out again.\n// export default function() {\n//    loginpage();\n//    do_login(username, password);\n//    drupalbag();\n//    add_drupalbag();\n//    cartreview();\n//    cartsubmit();\n//    checkout();\n//    shipping();\n//    review_submit();\n//    logout();\n//}\n\n// main loop\nexport default function() {\n    // 1. Load home page\n    firstpage();\n    // Load dependencies (images etc). Simulate not having anything cached.\n    page_dependencies(false);\n    // 0-30 second user think time\n    thinktime(30);\n\n    // 2. Load login page and save the hidden form field needed to logon\n    loginpage();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time. Takes a while to type in username and password.\n    thinktime(30);\n\n    // 3. Perform login\n    do_login(users[__VU-1][\"username\"], users[__VU-1][\"password\"]);\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n\n    // 4. Look at \"carry\" product section\n    carrypage();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n\n    // 5. Choose \"drupalbag\" product\n    drupalbag();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n\n    // 6. Add product to our shopping cart\n    add_drupalbag();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n\n    // 7. View our shopping cart\n    cartreview();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n\n    // 8. Proceed to checkout\n    cartsubmit();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n    \n    // 9. Perform checkout\n    checkout();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n    \n    // 10. Select shipping method\n    shipping();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n\n    // 11. Review and submit order\n    review_submit();\n    // Ask server for updated (If-Modified-Since) dependencies\n    page_dependencies(true);\n    // User think time.\n    thinktime(30);\n\n    // 12. Logout\n    logout();\n    // User thinktime\n    thinktime(30);\n}\n\nfunction thinktime(t) {\n    return;\n    sleep(t * Math.random());\n}\n\n// This function loads the home page HTML\nfunction firstpage() {\n    let params = { \"headers\": defaultheaders };\n    let url = baseurl + \"/\";\n    // Load main HTML\n    let response = http.get(url, null, params);\n    check(response, {\n        \"1: first page content OK\": (res) => res.html(\"title\").text() === 'Welcome to David li commerce-test | David li commerce-test'\n    }) || console.log(\"First page content invalid\");\n    // We always update the \"Referer\" header to contain the most recently accessed URL\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// This function loads the login page, where the login form is (wher you enter your\n// username and password to login)\nfunction loginpage() {\n    let params = { \"headers\": defaultheaders };\n    let url = baseurl + \"/user/login\";\n    let response = http.get(url, null, params);\n    check(response, {\n        \"2: login page OK\": (res) => res.html(\"title\").text() === 'User account | David li commerce-test'\n    }) || console.log(\"Login page content invalid\");\n    // Now we look for some hidden form fields, and extract their values so we can use them \n    // when submitting the form later on:\n    // <input type=\"hidden\" name=\"form_build_id\" value=\"form-euqedAF5cQGec_Z9qqgjNMQsMzNAkiF37BGokRobLNg\" />\n    form_build_id = response.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n    form_id = response.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// This function performs a login POST operation to authenticate the user.\n// It uses the previously stored hidden form fields when submitting the form.\nfunction do_login(username, password) {\n    let headers = defaultheaders;\n    // We set the content type specifically for form POSTs\n    headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n    let params = { \"headers\": headers };\n    let url = baseurl + \"/user/login\";\n    formdata = {\n        \"name\": username,\n        \"pass\": password,\n        \"form_build_id\": form_build_id,\n        \"form_id\": \"user_login\",\n        \"op\": \"Log in\"\n    };\n    let response = http.post(url, formdata, params);\n    // verify login succeeded\n    check(response, {\n        \"3: login succeeded\": (res) => res.url === ( baseurl + \"/users/\" + username)\n    }) || console.log(\"Login failed!  Effective URL was \" + response.url);\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// This function loads the /collection/carry page\nfunction carrypage() {\n    let params = { \"headers\": defaultheaders }\n    let url = baseurl + \"/collection/carry\";\n    let response = http.get(url, null, params);\n    check(response, {\n        \"4: carry page OK\": (res) => res.html(\"title\").text() === 'To carry | David li commerce-test'\n    }) || console.log(\"Carry page content invalid\");\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// And here we check out the \"drupal bag\", going to its product page\nfunction drupalbag() {\n    let params = { \"headers\": defaultheaders };\n    let url = baseurl + \"/bags-cases/drupal-commerce-messenger-bag\";\n    let response = http.get(url, null, params);\n    check(response, {\n        \"5: drupal bag page OK\": (res) => res.html(\"title\").text() === 'Drupal Commerce Messenger Bag | David li commerce-test'\n    }) || console.log(\"Drupal bag page content invalid\");\n    form_build_id = response.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n    form_id = response.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n    form_token = response.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// Then we add the Drupal bag to our shopping cart\nfunction add_drupalbag() {\n    let headers = defaultheaders;\n    headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n    //headers[\"Origin\"] = baseurl;\n    params = { \"headers\": headers };\n    let url = baseurl + \"/bags-cases/drupal-commerce-messenger-bag\";\n    let formdata = {\n        \"product_id\": 2,\n        \"form_build_id\": form_build_id,\n        \"form_id\": form_id,\n        \"form_token\": form_token,\n        \"quantity\": 1,\n        \"op\": \"Add to cart\"\n    };    \n    let response = http.post(url, formdata, params);\n    // verify add to cart succeeded\n    check(response, {\n        \"6: add to cart succeeded\": (res) => res.body.includes('Item successfully added to your cart')\n    }) || console.log(\"Add to cart failed\");\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// Then we click the checkout link to go to our shopping cart\nfunction cartreview() {\n    let params = { \"headers\": defaultheaders };\n    let url = baseurl + \"/cart\";\n    let response = http.get(url, null, params);\n    check(response, {\n        \"7: shopping cart page OK\": (res) => res.html(\"title\").text() === 'Shopping cart | David li commerce-test'\n    }) || console.log(\"Shopping cart page content invalid\");\n    form_build_id = response.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n    form_token = response.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n    form_id = response.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n    checkout_url = response.url;\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// Go to checkout\nfunction cartsubmit() {\n    let headers = defaultheaders;\n    headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n    //headers[\"Origin\"] = baseurl;\n    let params = { \"headers\": headers };\n    let url = baseurl + \"/cart\";\n    let formdata = {\n        \"form_build_id\": form_build_id,\n        \"form_token\": form_token,\n        \"form_id\": form_id,\n        \"edit_quantity[0]\": 1,\n        \"op\": \"Checkout\"\n    };\n    let response = http.post(url, formdata, params);\n    check(response, {\n        \"8: cart submit succeeded\": (res) => res.url.includes(\"/checkout/\")\n    }) || console.log(\"Cart submit failed\");\n    // This POST redirects to checkout page, which has a dynamic path, e.g \"/checkout/7\"\n    // so we save the redirected URL in a global variable.\n    checkout_url = response.url;\n    form_build_id = response.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n    form_token = response.body.match('name=\"form_token\" value=\"(.*)\"')[1];\n    form_id = response.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// Enter billing address etc\nfunction checkout() {\n    let headers = defaultheaders\n    headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n    params = { \"headers\": headers }\n    // We use the URL we saved earlier\n    let url = checkout_url;\n    formdata = {\n        \"customer_profile_billing[commerce_customer_address][und][0][country]\": \"SE\",\n        \"customer_profile_billing[commerce_customer_address][und][0][name_line]\": \"Mr Test\",\n        \"customer_profile_billing[commerce_customer_address][und][0][thoroughfare]\": \"Gotgatan 14\",\n        \"customer_profile_billing[commerce_customer_address][und][0][premise]\": \"\",\n        \"customer_profile_billing[commerce_customer_address][und][0][postal_code]\": \"11846\",\n        \"customer_profile_billing[commerce_customer_address][und][0][locality]\": \"Stockholm\",\n        \"customer_profile_shipping[commerce_customer_profile_copy]\": \"1\",\n        \"form_build_id\": form_build_id,\n        \"form_token\": form_token,\n        \"form_id\": form_id,\n        \"op\": \"Continue to next step\"\n    }\n    let response = http.post(url, formdata, params);\n    // verify checkout step 1 succeeded\n    check(response, {\n        \"9: checkout succeeded\": (res) => res.url === (checkout_url + \"/shipping\")\n    }) || console.log(\"Checkout failed!\");\n    form_build_id = response.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n    form_token = response.body.match('name=\"form_token\" value=\"(.*)\"')[1];     \n    form_id = response.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// Checkout step 2: choose shipping option\nfunction shipping() {\n    let headers = defaultheaders;\n    headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n    params = { \"headers\": headers };\n    let url = checkout_url + \"/shipping\";\n    formdata = {\n        \"commerce_shipping[shipping_service]\": \"express_shipping\",\n        \"form_build_id\": form_build_id,\n        \"form_token\": form_token,\n        \"form_id\": form_id,\n        \"op\": \"Continue to next step\"\n    }\n    let response = http.post(url, formdata, params);\n    // verify checkout step 2 succeeded\n    check(response, {\n        \"10: select shipping succeeded\": (res) => res.url === (checkout_url + \"/review\")\n    }) || console.log(\"Select shipping failed!\");\n    form_build_id = response.body.match('name=\"form_build_id\" value=\"(.*)\"')[1];\n    form_token = response.body.match('name=\"form_token\" value=\"(.*)\"')[1];    \n    form_id = response.body.match('name=\"form_id\" value=\"(.*)\"')[1];\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// Checkout step 3: review and submit order\nfunction review_submit() {\n    let headers = defaultheaders;\n    headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n    params = { \"headers\": headers };\n    let url = checkout_url + \"/review\";\n    formdata = {\n        \"commerce_payment[payment_method]\": \"commerce_payment_example|commerce_payment_commerce_payment_example\",\n        \"commerce_payment[payment_details][credit_card][number]\": \"4111111111111111\",\n        \"commerce_payment[payment_details][credit_card][exp_month]\": \"03\",\n        \"commerce_payment[payment_details][credit_card][exp_year]\": \"2019\",\n        \"form_build_id\": form_build_id,\n        \"form_token\": form_token,\n        \"form_id\": form_id,\n        \"op\": \"Continue to next step\"\n    }\n    let response = http.post(url, formdata, params);\n    // if this POST succeeds, it will redirect to e.g. /checkout/7/payment\n    // /checkout/7/payment, in turn, will redirect to /checkout/7/paypal_ec\n    // /checkout/7/paypal_ec, in turn, will redirect to /checkout/7/complete\n    check(response, {\n        \"11: checkout complete\": (res) => res.html(\"h1\").text() === \"Checkout complete\"\n    }) || console.log(\"Checkout review-submit failed\");\n    defaultheaders[\"Referer\"] = cacheheaders[\"Referer\"] = response.url;\n}\n\n// Finally, we log out our user\nfunction logout() {\n    let headers = defaultheaders;\n    let params = { \"headers\": headers };\n    let url = baseurl + \"/user/logout\";\n    let response = http.get(url, null, params);\n    check(response, {\n        \"12: logout succeeded\": (res) => res.body.includes('<a href=\"/user/login\">Log in')\n    }) || console.log(\"Logout failed\");\n}\n\n\n// page_dependencies() loads a bunch of dependencies (images, css files etc.)\n// either using \"defaultheaders\" or \"cacheheaders\", where the latter contains\n// an If-Modified-Since header that allows the server to just respond with 304\n// (content has not been modified) instead of sending the actual content.\n//\n// We use this function as \"filler\" in between the requests that are part of the\n// user flow, in order to behave like a real browser would. We always ask for the\n// same set of files, while in reality the files asked for varies slightly \n// between one page and another. The overlap is substantial, however, and it is\n// likely that this simplification is not going to affect results in the\n// slightest.\n//\nfunction page_dependencies(cached) {\n    let params = { \"headers\": defaultheaders };\n    if (cached) {\n        params = { \"headers\": cacheheaders };\n    }\n    let responses = http.batch([\n        { \"url\": baseurl + \"/modules/system/system.base.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/modules/system/system.menus.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/modules/system/system.messages.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/modules/system/system.theme.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/cloud_zoom/css/cloud_zoom.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/ui/jquery.ui.core.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/ui/jquery.ui.theme.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/libraries/jquery_ui_spinner/ui.spinner.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/modules/comment/comment.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/commerce_add_to_cart_confirmation/css/commerce_add_to_cart_confirmation.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/date/date_api/date.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/date/date_popup/themes/datepicker.1.7.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/fences/field.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/modules/node/node.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/modules/user/user.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/views/css/views.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/ctools/css/ctools.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/commerce/modules/line_item/theme/commerce_line_item.theme.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/commerce/modules/product/theme/commerce_product.theme.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/commerce_fancy_attributes/commerce_fancy_attributes.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/alpha-reset.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/alpha-mobile.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/alpha-alpha.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/formalize.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-text.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-branding.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-menu.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/css/omega-forms.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/global.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce_kickstart_style.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/omega-kickstart-alpha-default.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/omega-kickstart-alpha-default-narrow.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce-kickstart-theme-alpha-default.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce-kickstart-theme-alpha-default-narrow.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/grid/alpha_default/narrow/alpha-default-narrow-24.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/css/omega-kickstart-alpha-default-normal.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/css/commerce-kickstart-theme-alpha-default-normal.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/alpha/css/grid/alpha_default/normal/alpha-default-normal-24.css?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/jquery.js?v=1.4.4\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/jquery.once.js?v=1.2\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/drupal.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/ui/jquery.ui.core.min.js?v=1.8.7\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/ui/jquery.ui.widget.min.js?v=1.8.7\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/libraries/cloud-zoom/cloud-zoom.1.0.3.min.js?v=1.0.3\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/cloud_zoom/js/cloud_zoom.js?v=1.0.3\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/libraries/jquery_expander/jquery.expander.min.js?v=1.4.2\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/libraries/jquery_ui_spinner/ui.spinner.min.js?v=1.8\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/libraries/selectnav.js/selectnav.min.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/commerce_add_to_cart_confirmation/js/commerce_add_to_cart_confirmation.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_search/commerce_kickstart_search.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/service_links/js/twitter_button.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/service_links/js/facebook_like.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/service_links/js/google_plus_one.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/contrib/commerce_fancy_attributes/commerce_fancy_attributes.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product_ui/commerce_kickstart_product_ui.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/js/omega_kickstart.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/js/jquery.formalize.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega/omega/js/omega-mediaqueries.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/js/commerce_kickstart_theme_custom.js?olqap9\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/logo.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/sites/default/files/styles/product_full/public/messenger-1v1.jpg?itok=hPe-GkYY\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v1.jpg?itok=cXkqMlMc\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v2.jpg?itok=yyhLIuCD\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v3.jpg?itok=uQsNvRiQ\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/sites/default/files/styles/product_thumbnail/public/messenger-1v4.jpg?itok=ns9kHz1T\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/bg.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/picto_cart.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_magnifying_glass.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/bg_product_attributes_bottom.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/bg_product_attributes_top.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/bg_add_to_cart.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/bg_block_footer_title.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/icon_facebook.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/icon_twitter.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/commerce_kickstart_theme/images/icon_pinterest.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_mastercard.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_paypal.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_visa_premier.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/picto_american_express.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/ui/images/ui-bg_glass_75_e6e6e6_1x400.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/misc/ui/images/ui-icons_888888_256x240.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/themes/contrib/omega_kickstart/images/btn_read_more.png\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/sites/default/files/messenger-1v1.jpg\", \"method\": \"GET\", \"params\": params },\n        { \"url\": baseurl + \"/profiles/commerce_kickstart/libraries/cloud-zoom/blank.png\", \"method\": \"GET\", \"params\": params }\n    ]);\n}\n\n\n\n\n\n\n"
  },
  {
    "path": "examples/redirects.js",
    "content": "import http from \"k6/http\";\nimport {check} from \"k6\";\n\nexport let options = {\n    // Max redirects to follow (default is 10)\n    maxRedirects: 5\n};\n\nexport default function() {\n    // If redirecting more than options.maxRedirects times, the last response will be returned\n    let res = http.get(\"https://httpbin.org/redirect/6\");\n    check(res, {\n        \"is status 302\": (r) => r.status === 302\n    });\n\n    // The number of redirects to follow can be controlled on a per-request level as well\n    res = http.get(\"https://httpbin.org/redirect/1\", {redirects: 1});\n    console.log(res.status);\n    check(res, {\n        \"is status 200\": (r) => r.status === 200,\n        \"url is correct\": (r) => r.url === \"https://httpbin.org/get\"\n    });\n}\n"
  },
  {
    "path": "examples/secrets/file.secret",
    "content": "cool=some\nelse=source\n"
  },
  {
    "path": "examples/secrets/mock_server.go",
    "content": "// Package main implements a mock HTTP secrets server for testing k6's URL secret source.\n//\n// The server mimics a secret management API like Vault or Google Secret Manager,\n// providing HTTP endpoints to retrieve secrets.\n//\n// Usage:\n//\n//\tgo run examples/secrets/mock_server.go\n//\n// The server listens on localhost:8888 by default and requires Bearer token\n// authentication.\n//\n// Example k6 command with inline configuration:\n//\n//\t./k6 run --secret-source='url=urlTemplate=http://localhost:8888/secrets/{key}/decrypt,\\\n//\t  headers.Authorization=Bearer YOUR_API_TOKEN_HERE,responsePath=plaintext' \\\n//\t  examples/secrets/url-test.js\npackage main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\nconst (\n\tserverAddr = \":8888\"\n\t// expectedToken is the test bearer token for authentication in examples\n\texpectedToken = \"Bearer YOUR_API_TOKEN_HERE\" //nolint:gosec // Test token for examples\n\treadTimeout   = 10 * time.Second\n\twriteTimeout  = 10 * time.Second\n)\n\n// Response structure for secret API\ntype secretResponse struct {\n\tPlaintext string `json:\"plaintext\"`\n\tName      string `json:\"name\"`\n}\n\nfunc main() {\n\t// Mock secret store\n\tmockSecrets := map[string]string{ //nolint:gosec\n\t\t\"api-key\":        \"super-secret-api-key-12345\",\n\t\t\"database-pass\":  \"db-password-xyz789\",\n\t\t\"jwt-secret\":     \"jwt-signing-key-abc123\",\n\t\t\"stripe-key\":     \"sk_test_mock_stripe_key\",\n\t\t\"github-token\":   \"ghp_mock_github_token_12345\",\n\t\t\"test-secret\":    \"this-is-a-test-secret\",\n\t\t\"my-secret\":      \"my-secret-value\",\n\t\t\"my-secret-key\":  \"my-secret-key-value\",\n\t\t\"another-secret\": \"another-secret-value\",\n\t}\n\n\tmux := http.NewServeMux()\n\n\t// Handle secret decryption requests\n\tmux.HandleFunc(\"/secrets/\", createSecretHandler(mockSecrets))\n\n\t// Health check endpoint\n\tmux.HandleFunc(\"/health\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t\t_, _ = fmt.Fprint(w, `{\"status\":\"healthy\"}`)\n\t})\n\n\tserver := &http.Server{\n\t\tAddr:         serverAddr,\n\t\tHandler:      mux,\n\t\tReadTimeout:  readTimeout,\n\t\tWriteTimeout: writeTimeout,\n\t}\n\n\tlog.Printf(\"Starting mock secrets API server on %s\", serverAddr)\n\tlog.Printf(\"Available secrets: %v\", getSecretKeys(mockSecrets))\n\tlog.Printf(\"Expected Authorization header: %s\", expectedToken)\n\tlog.Println()\n\tlog.Println(\"Example curl command:\")\n\tlog.Println(`  curl -H \"Authorization: Bearer YOUR_API_TOKEN_HERE\" http://localhost:8888/secrets/api-key/decrypt`)\n\tlog.Println()\n\tlog.Println(\"Example k6 command with inline config:\")\n\tlog.Println(`  ./k6 run \\`)\n\tlog.Println(`    --secret-source='url=urlTemplate=http://localhost:8888/secrets/{key}/decrypt,\\`)\n\tlog.Println(`      headers.Authorization=Bearer YOUR_API_TOKEN_HERE,responsePath=plaintext' \\`)\n\tlog.Println(`    examples/secrets/url-test.js`)\n\tlog.Println()\n\n\t// Get the actual port after server starts\n\tlc := net.ListenConfig{}\n\tln, err := lc.Listen(context.Background(), \"tcp\", serverAddr)\n\tif err != nil {\n\t\tlog.Fatalf(\"Server failed to listen: %v\", err)\n\t}\n\n\tlog.Printf(\"Server listening at %v\\n\", ln.Addr())\n\n\tif err := server.Serve(ln); err != nil && err != http.ErrServerClosed {\n\t\tlog.Fatalf(\"Server failed: %v\", err)\n\t}\n}\n\nfunc createSecretHandler(mockSecrets map[string]string) http.HandlerFunc {\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\t\t// Log incoming request\n\t\tlog.Printf(\"%s %s from %s\", r.Method, r.URL.Path, r.RemoteAddr) //nolint:gosec\n\n\t\t// Check HTTP method\n\t\tif r.Method != http.MethodGet {\n\t\t\tlog.Printf(\"  ❌ Invalid method: %s\", r.Method) //nolint:gosec\n\t\t\thttp.Error(w, `{\"error\":\"method not allowed\"}`, http.StatusMethodNotAllowed)\n\t\t\treturn\n\t\t}\n\n\t\t// Check Authorization header\n\t\tauthHeader := r.Header.Get(\"Authorization\")\n\t\tif authHeader == \"\" {\n\t\t\tlog.Println(\"  ❌ Missing Authorization header\")\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\t_, _ = fmt.Fprint(w, `{\"error\":\"missing authorization header\"}`)\n\t\t\treturn\n\t\t}\n\n\t\t// Validate Bearer token\n\t\tif authHeader != expectedToken {\n\t\t\tlog.Printf(\"  ❌ Invalid token: %s\", authHeader) //nolint:gosec\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\t_, _ = fmt.Fprint(w, `{\"error\":\"invalid authorization token\"}`)\n\t\t\treturn\n\t\t}\n\n\t\t// Extract secret key from URL path\n\t\t// Expected format: /secrets/{key}/decrypt\n\t\tpath := strings.TrimPrefix(r.URL.Path, \"/secrets/\")\n\t\tpath = strings.TrimSuffix(path, \"/decrypt\")\n\n\t\tif path == \"\" || path == r.URL.Path {\n\t\t\tlog.Println(\"  ❌ Invalid path format\")\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\t_, _ = fmt.Fprint(w, `{\"error\":\"invalid path format, expected /secrets/{key}/decrypt\"}`)\n\t\t\treturn\n\t\t}\n\n\t\tsecretKey := path\n\n\t\t// Look up secret\n\t\tsecretValue, exists := mockSecrets[secretKey]\n\t\tif !exists {\n\t\t\tlog.Printf(\"  ❌ Secret not found: %s\", secretKey) //nolint:gosec\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t_, _ = fmt.Fprintf(w, `{\"error\":\"secret %q not found\"}`, secretKey) //nolint:gosec\n\t\t\treturn\n\t\t}\n\n\t\t// Build response\n\t\tresponse := secretResponse{\n\t\t\tPlaintext: secretValue,\n\t\t\tName:      fmt.Sprintf(\"projects/test-project/secrets/%s\", secretKey),\n\t\t}\n\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\tw.WriteHeader(http.StatusOK)\n\n\t\tif err := json.NewEncoder(w).Encode(response); err != nil {\n\t\t\tlog.Printf(\"  ❌ Failed to encode response: %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\tlog.Printf(\"  ✅ Returned secret: %s (length: %d)\", secretKey, len(secretValue)) //nolint:gosec\n\t}\n}\n\nfunc getSecretKeys(secrets map[string]string) []string {\n\tkeys := make([]string, 0, len(secrets))\n\tfor k := range secrets {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys\n}\n"
  },
  {
    "path": "examples/secrets/multi-source.test.js",
    "content": "// k6 run --secret-source=mock=default,cool=\"cool secret\" --secret-source=mock=name=another,cool=\"not cool secret\" multi-source.test.js\nimport secrets from \"k6/secrets\";\n\nexport default async () => {\n\tconst my_secret = await secrets.get(\"cool\"); // get secret from a source with the provided identifier\n\tconst anothersource = secrets.source(\"another\")\n\tconst my_other_secret = await anothersource.get(\"cool\");\n\tconsole.log(\"Secret from default source \", my_secret)\n\tconsole.log(\"Secret from another source \", my_other_secret)\n\tconsole.log(\"Are they equal? \", my_other_secret== my_secret)\n}\n"
  },
  {
    "path": "examples/secrets/secrets.test.js",
    "content": "// k6 run --secret-source=file=file.secret secrets.test.js\nimport secrets from \"k6/secrets\";\n\nexport default async () => {\n\tconst my_secret = await secrets.get(\"cool\"); // get secret from a source with the provided identifier\n\tconsole.log(my_secret);\n\tawait secrets.get(\"else\"); // get secret from a source with the provided identifier\n\tconsole.log(my_secret);\n}\n"
  },
  {
    "path": "examples/secrets/totp.test.js",
    "content": "// TOTP generation with secrets API\n//\n// Run with:\n//   k6 run --secret-source=mock=totp_secret=\"GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ\" examples/secrets/totp.test.js\n//\n// Note:\n// Don't use the mock secret source in production. This source is designed for testing purposes only.\n\nimport secrets from 'k6/secrets';\nimport { TOTP } from 'https://jslib.k6.io/totp/1.0.0/index.js';\nimport { check } from 'k6';\n\nexport default async function () {\n    // Get TOTP secret from secrets API\n    const secret = await secrets.get('totp_secret');\n\n    // Create TOTP instance with 6-digit codes\n    const totp = new TOTP(secret, 6);\n\n    // Generate current TOTP code\n    const code = await totp.gen();\n    console.log(`Generated TOTP code: ${code}`);\n\n    // Verify the code (should be valid since we just generated it)\n    const isValid = await totp.verify(code);\n\n    check(isValid, {\n        'TOTP code is valid': (v) => v === true,\n    });\n\n    console.log(`Code verification: ${isValid ? 'PASSED' : 'FAILED'}`);\n}\n"
  },
  {
    "path": "examples/secrets/url-config.json",
    "content": "{\n  \"urlTemplate\": \"http://localhost:8888/secrets/{key}/decrypt\",\n  \"headers\": {\n    \"Authorization\": \"Bearer YOUR_API_TOKEN_HERE\"\n  },\n  \"responsePath\": \"plaintext\",\n  \"maxRetries\": 3,\n  \"retryBackoff\": \"1s\",\n  \"timeout\": \"10s\"\n}\n"
  },
  {
    "path": "examples/secrets/url-source.test.js",
    "content": "// Example: Using URL-based secret source with local mock server\n//\n// SETUP:\n// ======\n// 1. Start the mock server in a separate terminal:\n//    go run examples/secrets/mock_server.go\n//\n// 2. Run this test with one of the following configurations:\n//\n// USAGE OPTIONS:\n// ==============\n//\n// Option 1: File-based configuration (using url-config.json)\n// -----------------------------------------------------------\n// k6 run --secret-source=url=config=examples/secrets/url-config.json \\\n//   examples/secrets/url-source.test.js\n//\n// Option 2: File-based with local mock server settings (using url-local.json)\n// ----------------------------------------------------------------------------\n// k6 run --secret-source=url=config=examples/secrets/url-local.json \\\n//   examples/secrets/url-source.test.js\n//\n// Option 3: Inline configuration (no config file needed)\n// -------------------------------------------------------\n// k6 run \\\n//   --secret-source='url=urlTemplate=http://localhost:8888/secrets/{key}/decrypt,\\\n//     headers.Authorization=Bearer YOUR_API_TOKEN_HERE,\\\n//     responsePath=plaintext' \\\n//   examples/secrets/url-source.test.js\n//\n// Option 4: Inline with custom timeout and retry settings\n// --------------------------------------------------------\n// k6 run \\\n//   --secret-source='url=urlTemplate=http://localhost:8888/secrets/{key}/decrypt,\\\n//     headers.Authorization=Bearer YOUR_API_TOKEN_HERE,\\\n//     responsePath=plaintext,\\\n//     timeout=5s,\\\n//     maxRetries=2' \\\n//   examples/secrets/url-source.test.js\n//\n// Option 5: Mixed - Load config file and override specific settings\n// ------------------------------------------------------------------\n// k6 run \\\n//   --secret-source='url=config=examples/secrets/url-config.json,\\\n//     timeout=60s,\\\n//     maxRetries=5' \\\n//   examples/secrets/url-source.test.js\n//\n// Option 6: Environment variable configuration\n// ---------------------------------------------\n// Environment variables are ALWAYS considered and follow k6's order of precedence:\n// 1. Defaults (lowest priority)\n// 2. Environment variables (K6_SECRET_SOURCE_URL_*)\n// 3. Config file (if specified with config=path)\n// 4. Inline CLI flags (highest priority)\n//\n// To use ONLY environment variables (no config file or inline flags):\n// export K6_SECRET_SOURCE_URL_URL_TEMPLATE=\"http://localhost:8888/secrets/{key}/decrypt\"\n// export K6_SECRET_SOURCE_URL_HEADER_AUTHORIZATION=\"Bearer YOUR_API_TOKEN_HERE\"\n// export K6_SECRET_SOURCE_URL_RESPONSE_PATH=\"plaintext\"\n// k6 run --secret-source=url examples/secrets/url-source.test.js\n//\n// You can also combine environment variables with other options:\n// export K6_SECRET_SOURCE_URL_URL_TEMPLATE=\"http://localhost:8888/secrets/{key}/decrypt\"\n// export K6_SECRET_SOURCE_URL_RESPONSE_PATH=\"plaintext\"\n// k6 run --secret-source='url=headers.Authorization=Bearer YOUR_API_TOKEN_HERE' \\\n//   examples/secrets/url-source.test.js\n// (The Authorization header from CLI will override the env var if set)\n\nimport secrets from \"k6/secrets\";\nimport { check } from \"k6\";\n\nexport default async function () {\n\tconsole.log(\"Testing URL-based secret source with mock server...\\n\");\n\n\t// Test 1: Get a secret\n\tconsole.log(\"1. Fetching 'my-secret-key'...\");\n\tconst mySecret = await secrets.get(\"my-secret-key\");\n\tconsole.log(`   Retrieved: ${mySecret}`);\n\n\tcheck(mySecret, {\n\t\t\"my-secret-key retrieved\": (val) => val === \"my-secret-key-value\",\n\t\t\"secret not empty\": (val) => val.length > 0,\n\t});\n\n\t// Test 2: Get another secret\n\tconsole.log(\"\\n2. Fetching 'api-key'...\");\n\tconst apiKey = await secrets.get(\"api-key\");\n\tconsole.log(`   Retrieved: ${apiKey}`);\n\n\tcheck(apiKey, {\n\t\t\"api-key retrieved\": (val) => val === \"super-secret-api-key-12345\",\n\t\t\"api-key not empty\": (val) => val.length > 0,\n\t});\n\n\t// Test 3: Get database password\n\tconsole.log(\"\\n3. Fetching 'database-pass'...\");\n\tconst dbPass = await secrets.get(\"database-pass\");\n\tconsole.log(`   Retrieved: ${dbPass}`);\n\n\tcheck(dbPass, {\n\t\t\"database-pass retrieved\": (val) => val === \"db-password-xyz789\",\n\t});\n\n\tconsole.log(\"\\n✓ All secrets retrieved successfully!\");\n\n\t// Example: Use secrets in HTTP requests\n\t// const response = http.get(\"https://api.example.com/data\", {\n\t//   headers: {\n\t//     \"Authorization\": `Bearer ${apiKey}`,\n\t//     \"X-Database-Auth\": dbPass\n\t//   }\n\t// });\n}\n"
  },
  {
    "path": "examples/source_map/issue_1804/imported.js",
    "content": "export function f1() {\n  throw \"line 2\";\n}\n\nexport function f2() {\n  throw \"line 6\";\n}\n\nexport function f3() {\n  throw \"line 10\";\n}\n"
  },
  {
    "path": "examples/source_map/issue_1804/main.js",
    "content": "import { f2 } from \"./imported.js\"\n\nexport default function() {\n  f2();\n}\n"
  },
  {
    "path": "examples/source_map/typescript_template/test1.js",
    "content": "var o={d:(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o:(o,e)=>Object.prototype.hasOwnProperty.call(o,e)},e={};o.d(e,{Z:()=>r});const r=()=>{!function(o){throw\"cool is cool\"}()};var t=e.Z;export{t as default};\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vL3dlYnBhY2svcnVudGltZS9kZWZpbmUgcHJvcGVydHkgZ2V0dGVycyIsIndlYnBhY2s6Ly8vd2VicGFjay9ydW50aW1lL2hhc093blByb3BlcnR5IHNob3J0aGFuZCIsIndlYnBhY2s6Ly8vLi90ZXN0MS50cyJdLCJuYW1lcyI6WyJfX3dlYnBhY2tfcmVxdWlyZV9fIiwiZXhwb3J0cyIsImRlZmluaXRpb24iLCJrZXkiLCJvIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwiZ2V0Iiwib2JqIiwicHJvcCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsInMiLCJjb29sVGhyb3ciXSwibWFwcGluZ3MiOiJBQUNBLElBQUlBLEVBQXNCLENDQTFCLEVBQXdCLENBQUNDLEVBQVNDLEtBQ2pDLElBQUksSUFBSUMsS0FBT0QsRUFDWEYsRUFBb0JJLEVBQUVGLEVBQVlDLEtBQVNILEVBQW9CSSxFQUFFSCxFQUFTRSxJQUM1RUUsT0FBT0MsZUFBZUwsRUFBU0UsRUFBSyxDQUFFSSxZQUFZLEVBQU1DLElBQUtOLEVBQVdDLE1DSjNFLEVBQXdCLENBQUNNLEVBQUtDLElBQVVMLE9BQU9NLFVBQVVDLGVBQWVDLEtBQUtKLEVBQUtDLEksc0JDR2xGLGNBSEEsU0FBbUJJLEdBQ2YsS0FBTSxlQUdOQyxJIiwiZmlsZSI6InRlc3QxLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gVGhlIHJlcXVpcmUgc2NvcGVcbnZhciBfX3dlYnBhY2tfcmVxdWlyZV9fID0ge307XG5cbiIsIi8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb25zIGZvciBoYXJtb255IGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uZCA9IChleHBvcnRzLCBkZWZpbml0aW9uKSA9PiB7XG5cdGZvcih2YXIga2V5IGluIGRlZmluaXRpb24pIHtcblx0XHRpZihfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZGVmaW5pdGlvbiwga2V5KSAmJiAhX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIGtleSkpIHtcblx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBrZXksIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBkZWZpbml0aW9uW2tleV0gfSk7XG5cdFx0fVxuXHR9XG59OyIsIl9fd2VicGFja19yZXF1aXJlX18ubyA9IChvYmosIHByb3ApID0+IChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKSkiLCJmdW5jdGlvbiBjb29sVGhyb3coczogc3RyaW5nKSB7XG4gICAgdGhyb3cgXCJjb29sIFwiKyBzXG59XG5leHBvcnQgZGVmYXVsdCAoKSA9PiB7XG4gICAgY29vbFRocm93KFwiaXMgY29vbFwiKVxufTtcbiJdLCJzb3VyY2VSb290IjoiIn0="
  },
  {
    "path": "examples/source_map/typescript_template/test1.ts",
    "content": "function coolThrow(s: string) {\n    throw \"cool \"+ s\n}\nexport default () => {\n    coolThrow(\"is cool\")\n};\n"
  },
  {
    "path": "examples/stages.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\n\n/*\n * Stages (aka ramping) is how you, in code, specify the ramping of VUs.\n * That is, how many VUs should be active and generating traffic against\n * the target system at any specific point in time for the duration of\n * the test.\n * \n * The following stages configuration will result in up-flat-down ramping\n * profile over a 20s total test duration.\n */ \n\nexport let options = {\n    stages: [\n        // Ramp-up from 1 to 5 VUs in 10s\n        { duration: \"10s\", target: 5 },\n\n        // Stay at rest on 5 VUs for 5s\n        { duration: \"5s\", target: 5 },\n\n        // Ramp-down from 5 to 0 VUs for 5s\n        { duration: \"5s\", target: 0 }\n    ]\n};\n\nexport default function() {\n    let res = http.get(\"http://httpbin.org/\");\n    check(res, { \"status is 200\": (r) => r.status === 200 });\n}\n"
  },
  {
    "path": "examples/tagging.js",
    "content": "import http from \"k6/http\";\nimport { Trend } from \"k6/metrics\";\nimport { check } from \"k6\";\n\n/*\n * Checks, custom metrics and requests can be tagged with any number of tags.\n *\n * Tags can be used for:\n * - Creating metric thresholds by filtering the metric data stream based on tags\n * - Aid result analysis by allowing for more precise filtering of metrics\n */\n\nlet myTrend = new Trend(\"my_trend\");\n\nexport default function() {\n    // Add tag to request metric data\n    let res = http.get(\"http://httpbin.org/\", { tags: { my_tag: \"I'm a tag\" } });\n\n    // Add tag to check\n    check(res, { \"status is 200\": (r) => r.status === 200 }, { my_tag: \"I'm a tag\" });\n\n    // Add tag to custom metric\n    myTrend.add(res.timings.connecting, { my_tag: \"I'm a tag\" });\n}\n"
  },
  {
    "path": "examples/thresholds.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\n/*\n * Thresholds are used to specify where a metric crosses into unacceptable\n * territory. If a threshold is crossed the test is considered a failure\n * and is marked as such by the program through a non-zero exit code.\n * \n * Thresholds are specified as part of the options structure. It's a set of\n * key/value pairs where the name specifies the metric to watch (with optional \n * tag filtering) and the values are JS expressions. Which could be a simple\n * number or involve a statistical aggregate like avg, max, percentiles etc.\n */\n\nexport let options = {\n    thresholds: {\n        // Declare a threshold over all HTTP response times,\n        // the 95th percentile should not cross 500ms\n        http_req_duration: [\"p(95)<500\"],\n\n        // Declare a threshold over HTTP response times for all data points\n        // where the URL tag is equal to \"http://httpbin.org/post\",\n        // the max should not cross 1000ms\n        \"http_req_duration{name:http://httpbin.org/post}\": [\"max<1000\"],\n    }\n};\n\nexport default function() {\n    http.get(\"http://httpbin.org/\");\n    http.post(\"http://httpbin.org/post\", {data: \"some data\"});\n}\n"
  },
  {
    "path": "examples/thresholds_readme_example.js",
    "content": "import http from \"k6/http\";\nimport { check, group, sleep } from \"k6\";\nimport { Rate } from \"k6/metrics\";\n\n// A custom metric to track failure rates\nvar failureRate = new Rate(\"check_failure_rate\");\n\n// Options\nexport let options = {\n    stages: [\n        // Linearly ramp up from 1 to 50 VUs during first minute\n        { target: 50, duration: \"1m\" },\n        // Hold at 50 VUs for the next 3 minutes and 30 seconds\n        { target: 50, duration: \"3m30s\" },\n        // Linearly ramp down from 50 to 0 50 VUs over the last 30 seconds\n        { target: 0, duration: \"30s\" }\n        // Total execution time will be ~5 minutes\n    ],\n    thresholds: {\n        // We want the 95th percentile of all HTTP request durations to be less than 500ms\n        \"http_req_duration\": [\"p(95)<750\"],\n        // Requests with the staticAsset tag should finish even faster\n        \"http_req_duration{staticAsset:yes}\": [\"p(99)<500\"],\n        // Thresholds based on the custom metric we defined and use to track application failures\n        \"check_failure_rate\": [\n            // Global failure rate should be less than 1%\n            \"rate<0.01\",\n            // Abort the test early if it climbs over 5%\n            { threshold: \"rate<=0.05\", abortOnFail: true },\n        ],\n    },\n};\n\n// Main function\nexport default function () {\n    let response = http.get(\"https://quickpizza.grafana.com/test.k6.io/\");\n\n    // check() returns false if any of the specified conditions fail\n    let checkRes = check(response, {\n        \"http2 is used\": (r) => r.proto === \"HTTP/2.0\",\n        \"status is 200\": (r) => r.status === 200,\n        \"content is present\": (r) => r.body.indexOf(\"This is a replacement of the service \") !== -1,\n    });\n\n    // We reverse the check() result since we want to count the failures\n    failureRate.add(!checkRes);\n\n    // Load static assets, all requests\n    group(\"Static Assets\", function () {\n        // Execute multiple requests in parallel like a browser, to fetch some static resources\n        let resps = http.batch([\n            [\"GET\", \"https://quickpizza.grafana.com/test.k6.io/static/css/site.css\", null, { tags: { staticAsset: \"yes\" } }],\n            [\"GET\", \"https://quickpizza.grafana.com/test.k6.io/static/favicon.ico\", null, { tags: { staticAsset: \"yes\" } }],\n            [\"GET\", \"https://quickpizza.grafana.com/test.k6.io/static/js/prisms.js\", null, { tags: { staticAsset: \"yes\" } }],\n        ]);\n        // Combine check() call with failure tracking\n        failureRate.add(!check(resps, {\n            \"status is 200\": (r) => r[0].status === 200 && r[1].status === 200,\n            \"reused connection\": (r) => r[0].timings.connecting == 0,\n        }));\n    });\n\n    sleep(Math.random() * 3 + 2); // Random sleep between 2s and 5s\n}\n"
  },
  {
    "path": "examples/timers.js",
    "content": "// based on https://developer.mozilla.org/en-US/docs/Web/API/setTimeout#reasons_for_delays_longer_than_specified\nimport { setTimeout } from \"k6/timers\";\nlet last = 0;\nlet iterations = 10;\n\nfunction timeout() {\n\t// log the time of this call\n\tlogline(new Date().getMilliseconds());\n\n\t// if we are not finished, schedule the next call\n\tif (iterations-- > 0) {\n\t\tsetTimeout(timeout, 0);\n\t}\n}\n\nexport default function () {\n\t// initialize iteration count and the starting timestamp\n\titerations = 10;\n\tlast = new Date().getMilliseconds();\n\n\t// start timer\n\tsetTimeout(timeout, 0);\n}\n\nfunction pad(number) {\n\treturn number.toString().padStart(3, \"0\");\n}\n\nfunction logline(now) {\n\t// log the last timestamp, the new timestamp, and the difference\n\tconsole.log(`${pad(last)}         ${pad(now)}          ${now - last}`);\n\tlast = now;\n}\n"
  },
  {
    "path": "examples/tls_skip_cert_verification.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport let options = {\n    // When this option is enabled (set to true), all of the verifications\n    // that would otherwise be done to establish trust in a server provided\n    // TLS certificate will be ignored.\n    insecureSkipTLSVerify: true\n};\n\nexport default function() {\n    let res = http.get(\"https://httpbin.org/\");\n    check(res, { \"status is 200\": (r) => r.status === 200 });\n}\n"
  },
  {
    "path": "examples/tlsconfig.js",
    "content": "import http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport let options = {\n    tlsCipherSuites: [\n        \"TLS_RSA_WITH_RC4_128_SHA\",\n        \"TLS_RSA_WITH_AES_128_GCM_SHA256\",\n    ],\n    tlsVersion: {\n        min: \"tls1.0\",\n        max: \"tls1.2\"\n    }\n};\n\nexport default function() {\n    let res = http.get(\"https://sha256.badssl.com\");\n    check(res, {\n        \"is TLSv1.2\": (r) => r.tls_version === http.TLS_1_2,\n        \"is sha256 cipher suite\": (r) => r.tls_cipher_suite === \"TLS_RSA_WITH_AES_128_GCM_SHA256\"\n    });\n};\n"
  },
  {
    "path": "examples/webcrypto/README.md",
    "content": "# k6 webcrypto examples\n\nIn this directory, you will find examples of how to use the k6's `webcrypto` module in your k6 scripts.\n\n> [!IMPORTANT]\n> We do run the tests based on these examples; that's why we have a simple convention for each example:\n>\n> * Success condition: Example SHOULD output an `INFO` keyword using `console.log` at least once.\n> * Failure condition: Example SHOULD NOT `try/catch` exceptions so that we can detect failures. The log output SHOULD NOT contain any keywords like `\"Uncaught\"` and `\"ERRO\"`.\n\nSee [`../../internal/js/modules/k6/webcrypto/cmd_run_test.go`](../../internal/js/modules/k6/webcrypto/cmd_run_test.go) for more details.\n"
  },
  {
    "path": "examples/webcrypto/derive_bits/derive-bits-ecdh.js",
    "content": "export default async function () {\n  // Generate a key pair for Alice\n  const aliceKeyPair = await crypto.subtle.generateKey(\n    {\n      name: \"ECDH\",\n      namedCurve: \"P-256\",\n    },\n    true,\n    [\"deriveKey\", \"deriveBits\"]\n  );\n\n  // Generate a key pair for Bob\n  const bobKeyPair = await crypto.subtle.generateKey(\n    {\n      name: \"ECDH\",\n      namedCurve: \"P-256\",\n    },\n    true,\n    [\"deriveKey\", \"deriveBits\"]\n  );\n\n  // Derive shared secret for Alice\n  const aliceSharedSecret = await deriveSharedSecret(\n    aliceKeyPair.privateKey,\n    bobKeyPair.publicKey\n  );\n\n  // Derive shared secret for Bob\n  const bobSharedSecret = await deriveSharedSecret(\n    bobKeyPair.privateKey,\n    aliceKeyPair.publicKey\n  );\n\n  console.log(\"alice shared secret: \" + printArrayBuffer(aliceSharedSecret));\n  console.log(\"bob shared secret: \" + printArrayBuffer(bobSharedSecret));\n}\n\nasync function deriveSharedSecret(privateKey, publicKey) {\n  return crypto.subtle.deriveBits(\n    {\n      name: \"ECDH\",\n      public: publicKey, // An ECDH public key from the other party\n    },\n    privateKey, // Your ECDH private key\n    256 // the number of bits to derive\n  );\n}\n\nconst printArrayBuffer = (buffer) => {\n  let view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n"
  },
  {
    "path": "examples/webcrypto/derive_bits/derive-bits-pbkdf2.js",
    "content": "function stringToArrayBuffer(str) {\n    const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n    const bufView = new Uint16Array(buf);\n    for (let i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n    }\n    return buf;\n}\n\nconst printArrayBuffer = (buffer) => {\n    const view = new Uint8Array(buffer);\n    return Array.from(view);\n};\n\nexport default async function () {\n    // create a low entropy password as array of bytes \n    const password = stringToArrayBuffer(\"hello world password!\")\n\n    // import password as CryptoKey\n    const importedKey = await crypto.subtle.importKey('raw', password, 'pbkdf2', false, [\n    'deriveBits', 'deriveKey'\n    ]);\n\n    // generate random salt\n    const saltArray = new Uint8Array(16)\n    crypto.getRandomValues(saltArray)\n    const salt = saltArray.buffer\n\n    // derive base key bits using pbkdf2\n    const derivedBits = await crypto.subtle.deriveBits(\n    {\n        name: \"PBKDF2\",\n        hash: \"SHA-256\",\n        salt,\n        iterations: 310000 \n    },\n    importedKey,\n    256\n    )\n\n    console.log(\"Derived Bits: \", printArrayBuffer(derivedBits))\n}"
  },
  {
    "path": "examples/webcrypto/derive_key/derive-key-pbkdf2.js",
    "content": "function stringToArrayBuffer(str) {\n    const buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n    const bufView = new Uint16Array(buf);\n    for (let i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n    }\n    return buf;\n}\n\nexport default async function () {\n    // create a low entropy password as array of bytes \n    const password = stringToArrayBuffer(\"hello world password!\")\n\n    // import password as CryptoKey\n    const importedKey = await crypto.subtle.importKey('raw', password, 'pbkdf2', false, [\n    'deriveBits', 'deriveKey'\n    ]);\n\n    // generate random salt\n    const saltArray = new Uint8Array(16)\n    crypto.getRandomValues(saltArray)\n    const salt = saltArray.buffer\n\n    // derive AES-GCM 256 key using  deriveKey \n    const derivedKey = await crypto.subtle.deriveKey(\n      {\n        name: \"PBKDF2\",\n        salt,\n        iterations: 310000,\n        hash: \"SHA-256\"\n      },\n      importedKey,\n      {\n        name : \"AES-GCM\",\n        length: 256,\n      },\n      true,\n      [\"encrypt\", 'decrypt']\n    )\n\n    console.log(derivedKey)\n}"
  },
  {
    "path": "examples/webcrypto/digest.js",
    "content": "export default function () {\n  crypto.subtle.digest(\"SHA-256\", stringToArrayBuffer(\"Hello, world!\")).then(\n    (hash) => {\n      console.log(arrayBufferToHex(hash));\n    },\n    (err) => {\n      throw err;\n    }\n  );\n}\n\nfunction arrayBufferToHex(buffer) {\n  return [...new Uint8Array(buffer)]\n    .map((x) => x.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n}\n\nfunction stringToArrayBuffer(s) {\n  return Uint8Array.from(new String(s), (x) => x.charCodeAt(0));\n}\n"
  },
  {
    "path": "examples/webcrypto/encrypt_decrypt/encrypt-decrypt-aes-cbc.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"AES-CBC\",\n      length: 256,\n    },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  const encoded = stringToArrayBuffer(\"Hello, World!\");\n  const iv = crypto.getRandomValues(new Uint8Array(16));\n\n  const ciphertext = await crypto.subtle.encrypt(\n    {\n      name: \"AES-CBC\",\n      iv: iv,\n    },\n    key,\n    encoded\n  );\n\n  const plaintext = await crypto.subtle.decrypt(\n    {\n      name: \"AES-CBC\",\n      iv: iv,\n    },\n    key,\n    ciphertext\n  );\n\n  console.log(\n    \"deciphered text == original text: \",\n    arrayBufferToHex(plaintext) === arrayBufferToHex(encoded)\n  );\n}\n\nfunction arrayBufferToHex(buffer) {\n  return [...new Uint8Array(buffer)]\n    .map((x) => x.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n}\n\nfunction stringToArrayBuffer(str) {\n  var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  var bufView = new Uint16Array(buf);\n  for (var i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n}\n"
  },
  {
    "path": "examples/webcrypto/encrypt_decrypt/encrypt-decrypt-aes-ctr.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"AES-CTR\",\n      length: 256,\n    },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  const encoded = string2ArrayBuffer(\"Hello World\");\n  const counter = crypto.getRandomValues(new Uint8Array(16));\n\n  const ciphertext = await crypto.subtle.encrypt(\n    {\n      name: \"AES-CTR\",\n      counter,\n      length: 64,\n    },\n    key,\n    encoded\n  );\n\n  const plaintext = await crypto.subtle.decrypt(\n    {\n      name: \"AES-CTR\",\n      counter,\n      length: 64,\n    },\n    key,\n    ciphertext\n  );\n\n  console.log(\n    \"deciphered text == original text: \",\n    arrayBufferToHex(plaintext) === arrayBufferToHex(encoded)\n  );\n}\n\nfunction arrayBufferToHex(buffer) {\n  return [...new Uint8Array(buffer)]\n    .map((x) => x.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n}\n\nfunction string2ArrayBuffer(str) {\n  var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  var bufView = new Uint16Array(buf);\n  for (var i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n}\n"
  },
  {
    "path": "examples/webcrypto/encrypt_decrypt/encrypt-decrypt-aes-gcm.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"AES-GCM\",\n      length: 256,\n    },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  const encoded = string2ArrayBuffer(\"Hello World\");\n  const iv = crypto.getRandomValues(new Uint8Array(12));\n\n  const ciphertext = await crypto.subtle.encrypt(\n    {\n      name: \"AES-GCM\",\n      iv: iv,\n    },\n    key,\n    encoded\n  );\n\n  const plaintext = await crypto.subtle.decrypt(\n    {\n      name: \"AES-GCM\",\n      iv: iv,\n    },\n    key,\n    ciphertext\n  );\n\n  console.log(\n    \"deciphered text == original text: \",\n    arrayBufferToHex(plaintext) === arrayBufferToHex(encoded)\n  );\n}\n\nfunction arrayBufferToHex(buffer) {\n  return [...new Uint8Array(buffer)]\n    .map((x) => x.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n}\n\nfunction string2ArrayBuffer(str) {\n  var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  var bufView = new Uint16Array(buf);\n  for (var i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n}\n"
  },
  {
    "path": "examples/webcrypto/encrypt_decrypt/encrypt-decrypt-rsa.js",
    "content": "export default async function () {\n  const keyPair = await crypto.subtle.generateKey(\n    {\n      name: \"RSA-OAEP\",\n      modulusLength: 2048,\n      publicExponent: new Uint8Array([1, 0, 1]),\n      hash: { name: \"SHA-1\" },\n    },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  const encoded = stringToArrayBuffer(\"Hello, World!\");\n\n  const cipherText = await crypto.subtle.encrypt(\n    {\n      name: \"RSA-OAEP\",\n    },\n    keyPair.publicKey,\n    encoded\n  );\n\n  // ciphertext.byteLength * 8, vector.privateKey.algorithm.modulusLength\n  console.log(\"cipherText's byteLength: \", cipherText.byteLength * 8);\n  console.log(\n    \"algorithm's modulusLength: \",\n    keyPair.privateKey.algorithm.modulusLength\n  );\n\n  const plaintext = await crypto.subtle.decrypt(\n    {\n      name: \"RSA-OAEP\",\n    },\n    keyPair.privateKey,\n    cipherText\n  );\n\n  console.log(\n    \"deciphered text == original text: \",\n    arrayBufferToHex(plaintext) === arrayBufferToHex(encoded)\n  );\n}\n\nfunction arrayBufferToHex(buffer) {\n  return [...new Uint8Array(buffer)]\n    .map((x) => x.toString(16).padStart(2, \"0\"))\n    .join(\"\");\n}\n\nfunction stringToArrayBuffer(str) {\n  var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  var bufView = new Uint16Array(buf);\n  for (var i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n}\n"
  },
  {
    "path": "examples/webcrypto/generateKey/generateKey-RSA-PSS.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"RSA-PSS\",\n      modulusLength: 2048, // Can be 1024, 2048, or 4096\n      publicExponent: new Uint8Array([1, 0, 1]), // 24-bit representation of 65537\n      hash: { name: \"SHA-1\" }, // Could be \"SHA-1\", \"SHA-256\", \"SHA-384\", or \"SHA-512\"\n    },\n    true,\n    [\"sign\", \"verify\"] // Key usages\n  );\n\n  console.log(JSON.stringify(key));\n}\n"
  },
  {
    "path": "examples/webcrypto/generateKey/generateKey-RSASSA-PKCS1-v1_5.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"RSASSA-PKCS1-v1_5\",\n      modulusLength: 1024, // Can be 1024, 2048, or 4096\n      publicExponent: new Uint8Array([1, 0, 1]), // 24-bit representation of 65537\n      hash: { name: \"SHA-256\" }, // Could be \"SHA-1\", \"SHA-256\", \"SHA-384\", or \"SHA-512\"\n    },\n    true,\n    [\"sign\", \"verify\"] // Key usages\n  );\n\n  console.log(JSON.stringify(key));\n}\n"
  },
  {
    "path": "examples/webcrypto/generateKey/generateKey-aes.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"AES-CBC\",\n      length: 256,\n    },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  console.log(JSON.stringify(key));\n}\n"
  },
  {
    "path": "examples/webcrypto/generateKey/generateKey-ecdh.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"ECDH\",\n      namedCurve: \"P-256\",\n    },\n    true,\n    [\"deriveKey\", \"deriveBits\"]\n  );\n\n  console.log(JSON.stringify(key));\n}\n"
  },
  {
    "path": "examples/webcrypto/generateKey/generateKey-ecdsa.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"ECDSA\",\n      namedCurve: \"P-256\",\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(JSON.stringify(key));\n}\n"
  },
  {
    "path": "examples/webcrypto/generateKey/generateKey-hmac.js",
    "content": "export default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: \"HMAC\",\n      hash: { name: \"SHA-512\" },\n      length: 256,\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(JSON.stringify(key));\n}\n"
  },
  {
    "path": "examples/webcrypto/getRandomValues.js",
    "content": "export default function () {\n  const array = new Uint32Array(10);\n  crypto.getRandomValues(array);\n\n  for (const num of array) {\n    console.log(num);\n  }\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/export-ecdh-keys.js",
    "content": "export default async function () {\n  const generatedKeyPair = await crypto.subtle.generateKey(\n    {\n      name: \"ECDH\",\n      namedCurve: \"P-256\",\n    },\n    true,\n    [\"deriveKey\", \"deriveBits\"]\n  );\n\n  const exportedPrivateKey = await crypto.subtle.exportKey(\n    \"pkcs8\",\n    generatedKeyPair.privateKey\n  );\n  console.log(\"exported private key: \" + printArrayBuffer(exportedPrivateKey));\n\n  const exportedPublicKey = await crypto.subtle.exportKey(\n    \"raw\",\n    generatedKeyPair.publicKey\n  );\n  console.log(\"exported public key: \" + printArrayBuffer(exportedPublicKey));\n}\n\nconst printArrayBuffer = (buffer) => {\n  let view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n"
  },
  {
    "path": "examples/webcrypto/import_export/export-ecdsa-keys.js",
    "content": "export default async function () {\n  const generatedKeyPair = await crypto.subtle.generateKey(\n    {\n      name: \"ECDSA\",\n      namedCurve: \"P-256\",\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  const exportedPrivateKey = await crypto.subtle.exportKey(\n    \"pkcs8\",\n    generatedKeyPair.privateKey\n  );\n  console.log(\"exported private key: \" + printArrayBuffer(exportedPrivateKey));\n\n  const exportedPublicKey = await crypto.subtle.exportKey(\n    \"raw\",\n    generatedKeyPair.publicKey\n  );\n  console.log(\"exported public key: \" + printArrayBuffer(exportedPublicKey));\n}\n\nconst printArrayBuffer = (buffer) => {\n  let view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n"
  },
  {
    "path": "examples/webcrypto/import_export/export-rsa-spki.js",
    "content": "export default async function () {\n  const generatedKeyPair = await await crypto.subtle.generateKey(\n    {\n      name: \"RSASSA-PKCS1-v1_5\",\n      modulusLength: 1024,\n      publicExponent: new Uint8Array([1, 0, 1]), // 24-bit representation of 65537\n      hash: { name: \"SHA-256\" },\n    },\n    true,\n    [\"sign\", \"verify\"] // Key usages\n  );\n\n  const exportedPrivateKey = await crypto.subtle.exportKey(\n    \"pkcs8\",\n    generatedKeyPair.privateKey\n  );\n  console.log(\"exported private key: \" + printArrayBuffer(exportedPrivateKey));\n\n  const exportedPublicKey = await crypto.subtle.exportKey(\n    \"spki\",\n    generatedKeyPair.publicKey\n  );\n  console.log(\"exported public key: \" + printArrayBuffer(exportedPublicKey));\n}\n\nconst printArrayBuffer = (buffer) => {\n  let view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-ecdh-key.js",
    "content": "export default async function () {\n  const aliceKeyPair = await importKeys(\n    alicePublicKeyData,\n    alicePrivateKeyData\n  );\n\n  const bobKeyPair = await importKeys(bobPublicKeyData, bobPrivateKeyData);\n\n  console.log(\"alice: \", JSON.stringify(aliceKeyPair));\n  console.log(\"bob: \", JSON.stringify(bobKeyPair));\n\n  // Derive shared secret for Alice\n  const aliceSharedSecret = await deriveSharedSecret(\n    aliceKeyPair.privateKey,\n    bobKeyPair.publicKey\n  );\n\n  // Derive shared secret for Bob\n  const bobSharedSecret = await deriveSharedSecret(\n    bobKeyPair.privateKey,\n    aliceKeyPair.publicKey\n  );\n\n  console.log(\"alice shared secret: \" + printArrayBuffer(aliceSharedSecret));\n  console.log(\"bob shared secret: \" + printArrayBuffer(bobSharedSecret));\n}\n\nconst importKeys = async (publicKeyData, privateKeyData) => {\n  const publicKey = await crypto.subtle.importKey(\n    \"raw\",\n    publicKeyData,\n    { name: \"ECDH\", namedCurve: \"P-256\" },\n    true,\n    []\n  );\n\n  const privateKey = await crypto.subtle.importKey(\n    \"pkcs8\",\n    privateKeyData,\n    { name: \"ECDH\", namedCurve: \"P-256\" },\n    true,\n    [\"deriveKey\", \"deriveBits\"]\n  );\n\n  return { publicKey: publicKey, privateKey: privateKey };\n};\nasync function deriveSharedSecret(privateKey, publicKey) {\n  return crypto.subtle.deriveBits(\n    {\n      name: \"ECDH\",\n      public: publicKey, // An ECDH public key from the other party\n    },\n    privateKey, // Your ECDH private key\n    256 // the number of bits to derive\n  );\n}\n\nconst printArrayBuffer = (buffer) => {\n  let view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n\nconst alicePublicKeyData = new Uint8Array([\n  4, 8, 249, 89, 225, 84, 28, 108, 246, 144, 7, 182, 109, 32, 155, 16, 102, 22,\n  66, 253, 148, 220, 48, 6, 106, 21, 123, 98, 229, 191, 20, 200, 35, 5, 208,\n  131, 136, 154, 125, 18, 20, 202, 231, 168, 184, 127, 53, 186, 6, 136, 114,\n  101, 127, 109, 179, 44, 96, 108, 193, 126, 217, 131, 163, 131, 135,\n]);\n\nconst alicePrivateKeyData = new Uint8Array([\n  48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42,\n  134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 194, 150, 86, 186,\n  233, 47, 132, 192, 213, 56, 60, 179, 112, 7, 89, 65, 116, 88, 8, 158, 228,\n  172, 190, 234, 143, 152, 33, 175, 47, 0, 39, 79, 161, 68, 3, 66, 0, 4, 8, 249,\n  89, 225, 84, 28, 108, 246, 144, 7, 182, 109, 32, 155, 16, 102, 22, 66, 253,\n  148, 220, 48, 6, 106, 21, 123, 98, 229, 191, 20, 200, 35, 5, 208, 131, 136,\n  154, 125, 18, 20, 202, 231, 168, 184, 127, 53, 186, 6, 136, 114, 101, 127,\n  109, 179, 44, 96, 108, 193, 126, 217, 131, 163, 131, 135,\n]);\n\nconst bobPublicKeyData = new Uint8Array([\n  4, 218, 134, 37, 137, 90, 68, 101, 112, 234, 68, 87, 110, 182, 85, 178, 161,\n  106, 223, 50, 150, 9, 155, 68, 191, 51, 138, 185, 186, 226, 211, 25, 203, 96,\n  193, 213, 68, 7, 181, 238, 52, 154, 113, 56, 76, 86, 44, 245, 128, 194, 103,\n  14, 81, 229, 124, 189, 13, 252, 138, 98, 196, 218, 39, 34, 42,\n]);\n\nconst bobPrivateKeyData = new Uint8Array([\n  48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42,\n  134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 59, 168, 213, 160,\n  115, 123, 19, 203, 62, 86, 50, 152, 17, 210, 42, 35, 174, 230, 191, 11, 65,\n  239, 223, 130, 73, 53, 161, 46, 9, 210, 50, 4, 161, 68, 3, 66, 0, 4, 218, 134,\n  37, 137, 90, 68, 101, 112, 234, 68, 87, 110, 182, 85, 178, 161, 106, 223, 50,\n  150, 9, 155, 68, 191, 51, 138, 185, 186, 226, 211, 25, 203, 96, 193, 213, 68,\n  7, 181, 238, 52, 154, 113, 56, 76, 86, 44, 245, 128, 194, 103, 14, 81, 229,\n  124, 189, 13, 252, 138, 98, 196, 218, 39, 34, 42,\n]);\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-ecdsa-keys.js",
    "content": "export default async function () {\n  const aliceKeyPair = await importKeys(\n    alicePublicKeyData,\n    alicePrivateKeyData\n  );\n\n  console.log(\"alice: \", JSON.stringify(aliceKeyPair));\n}\n\nconst importKeys = async (publicKeyData, privateKeyData) => {\n  const publicKey = await crypto.subtle.importKey(\n    \"raw\",\n    publicKeyData,\n    { name: \"ECDSA\", namedCurve: \"P-256\" },\n    true,\n    [\"verify\"]\n  );\n\n  const privateKey = await crypto.subtle.importKey(\n    \"pkcs8\",\n    privateKeyData,\n    { name: \"ECDSA\", namedCurve: \"P-256\" },\n    true,\n    [\"sign\"]\n  );\n\n  return { publicKey: publicKey, privateKey: privateKey };\n};\n\nconst alicePublicKeyData = new Uint8Array([\n  4, 106, 149, 34, 76, 184, 103, 101, 35, 234, 57, 76, 231, 21, 188, 244, 15,\n  179, 101, 113, 24, 6, 17, 21, 195, 60, 181, 73, 154, 170, 206, 21, 244, 102,\n  50, 21, 235, 66, 107, 55, 97, 177, 160, 21, 167, 210, 15, 233, 76, 31, 135,\n  131, 215, 123, 149, 171, 153, 231, 152, 197, 87, 176, 32, 39, 137,\n]);\n\nconst alicePrivateKeyData = new Uint8Array([\n  48, 129, 135, 2, 1, 0, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42,\n  134, 72, 206, 61, 3, 1, 7, 4, 109, 48, 107, 2, 1, 1, 4, 32, 41, 167, 202, 58,\n  174, 179, 236, 224, 240, 214, 91, 12, 207, 12, 10, 4, 200, 252, 81, 163, 175,\n  76, 120, 60, 102, 201, 132, 40, 177, 74, 244, 226, 161, 68, 3, 66, 0, 4, 106,\n  149, 34, 76, 184, 103, 101, 35, 234, 57, 76, 231, 21, 188, 244, 15, 179, 101,\n  113, 24, 6, 17, 21, 195, 60, 181, 73, 154, 170, 206, 21, 244, 102, 50, 21,\n  235, 66, 107, 55, 97, 177, 160, 21, 167, 210, 15, 233, 76, 31, 135, 131, 215,\n  123, 149, 171, 153, 231, 152, 197, 87, 176, 32, 39, 137,\n]);\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-export-aes-key.js",
    "content": "export default async function () {\n  const generatedKey = await crypto.subtle.generateKey(\n    {\n      name: \"AES-CBC\",\n      length: \"256\",\n    },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  const exportedKey = await crypto.subtle.exportKey(\"raw\", generatedKey);\n\n  const importedKey = await crypto.subtle.importKey(\n    \"raw\",\n    exportedKey,\n    \"AES-CBC\",\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  console.log(JSON.stringify(importedKey));\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-export-hmac-key.js",
    "content": "export default async function () {\n  const generatedKey = await crypto.subtle.generateKey(\n    {\n      name: \"HMAC\",\n      hash: { name: \"SHA-256\" },\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  const exportedKey = await crypto.subtle.exportKey(\"raw\", generatedKey);\n\n  const importedKey = await crypto.subtle.importKey(\n    \"raw\",\n    exportedKey,\n    { name: \"HMAC\", hash: { name: \"SHA-256\" } },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(JSON.stringify(importedKey));\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-export-jwk-aes-key.js",
    "content": "export default async function () {\n  const generatedKey = await crypto.subtle.generateKey(\n    {\n      name: \"AES-CBC\",\n      length: \"256\",\n    },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  console.log(\"generated: \" + JSON.stringify(generatedKey));\n\n  const exportedKey = await crypto.subtle.exportKey(\"jwk\", generatedKey);\n\n  console.log(\"exported: \" + JSON.stringify(exportedKey));\n\n  const importedKey = await crypto.subtle.importKey(\n    \"jwk\",\n    exportedKey,\n    \"AES-CBC\",\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  console.log(\"imported: \" + JSON.stringify(importedKey));\n\n  const exportedAgain = await crypto.subtle.exportKey(\"jwk\", importedKey);\n\n  console.log(\"exported again: \" + JSON.stringify(exportedAgain));\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-export-jwk-aes-static-key.js",
    "content": "export default async function () {\n  const jwk = {\n    alg: \"A256CBC\",\n    ext: true,\n    k: \"LhR2VJFb1NJ8HORgOn7LNKLXhUqPsTjC65UAWFb4GKI\",\n    key_ops: [\"encrypt\", \"decrypt\"],\n    kty: \"oct\",\n  };\n\n  console.log(\"static key: \" + JSON.stringify(jwk));\n\n  const importedKey = await crypto.subtle.importKey(\n    \"jwk\",\n    jwk,\n    { name: \"AES-CBC\", length: 256 },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  console.log(\"imported: \" + JSON.stringify(importedKey));\n\n  const exportedAgain = await crypto.subtle.exportKey(\"jwk\", importedKey);\n\n  console.log(\"exported again: \" + JSON.stringify(exportedAgain));\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-export-jwk-ecdsa.js",
    "content": "export default async function () {\n  const jwk = {\n    kty: \"EC\",\n    crv: \"P-521\",\n    x: \"AVb0efjfHiCn_8BM5CDD4VSuJRmWvuQvA0uE1Bt0PzTkXzEbgTqc3sjNpZu7vTHUYLMpJSHnwbci5WZ8A9svrnU_\",\n    y: \"AVAXNs_iRzlDINjkr8L9ObWpMxBhuB4iQSgrnheJGCK1t54FL0WXtZZD_Tk3nFG9USXE9IvD8CXOPNNpUyhsyzj7\",\n    d: \"APQIdYNoupMPMPdq4FT-XNLOf9osn3am1DbPddZsRAv-YzHHwXKhJHgZPIJRSHvJEmP6UCF_hf9jb1nNVG46tIO0\",\n  };\n\n  console.log(\"static key: \" + JSON.stringify(jwk));\n\n  const importedKey = await crypto.subtle.importKey(\n    \"jwk\",\n    jwk,\n    { name: \"ECDSA\", namedCurve: \"P-256\" },\n    true,\n    [\"sign\"]\n  );\n\n  console.log(\"imported: \" + JSON.stringify(importedKey));\n\n  const exportedAgain = await crypto.subtle.exportKey(\"jwk\", importedKey);\n\n  console.log(\"exported again: \" + JSON.stringify(exportedAgain));\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-export-jwk-hmac-key.js",
    "content": "export default async function () {\n  const generatedKey = await crypto.subtle.generateKey(\n    {\n      name: \"HMAC\",\n      hash: { name: \"SHA-256\" },\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(\"generated: \" + JSON.stringify(generatedKey));\n\n  const exportedKey = await crypto.subtle.exportKey(\"jwk\", generatedKey);\n\n  console.log(\"exported: \" + JSON.stringify(exportedKey));\n\n  const importedKey = await crypto.subtle.importKey(\n    \"jwk\",\n    exportedKey,\n    { name: \"HMAC\", hash: { name: \"SHA-256\" } },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(\"imported: \" + JSON.stringify(importedKey));\n\n  const exportedAgain = await crypto.subtle.exportKey(\"jwk\", importedKey);\n\n  console.log(\"exported again: \" + JSON.stringify(exportedAgain));\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-export-jwk-hmac-static-key.js",
    "content": "export default async function () {\n  const jwk = {\n    alg: \"HS256\",\n    ext: true,\n    k: \"H6gLp3lw7w27NrPUn00WpcKU-IJojJdNzhL_8F6se2k\",\n    key_ops: [\"sign\", \"verify\"],\n    kty: \"oct\",\n  };\n\n  console.log(\"static key: \" + JSON.stringify(jwk));\n\n  const importedKey = await crypto.subtle.importKey(\n    \"jwk\",\n    jwk,\n    { name: \"HMAC\", hash: { name: \"SHA-256\" } },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(\"imported: \" + JSON.stringify(importedKey));\n\n  const exportedAgain = await crypto.subtle.exportKey(\"jwk\", importedKey);\n\n  console.log(\"exported again: \" + JSON.stringify(exportedAgain));\n}\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-jwk-base64-decrypt.js",
    "content": "import { b64decode } from \"k6/encoding\";\n\nexport default async function () {\n  // transmitted data is the base64 of the initialization vector + encrypted data\n  // that unusually transmitted over the network\n  const transmittedData = base64Decode(\n    \"drCfxl4O+5FcrHe8Bs0CvKlw3gZpv+S5if3zn7c4BJzHJ35QDFV4sJB0pbDT\"\n  );\n\n  // keyData is the key used to decrypt the data, that is usually stored in a secure location\n  // for the purpose of this example, we are using a static key\n  const jwkKeyData = {\n    kty: \"oct\",\n    ext: true,\n    key_ops: [\"decrypt\", \"encrypt\"],\n    alg: \"A256GCM\",\n    k: \"9Id_8iG6FkGOWmc1S203vGVnTExtpDGxdQN7v7OV9Uc\",\n  };\n\n  const result = await decrypt(jwkKeyData, transmittedData);\n\n  // should output decrypted message\n  // INFO[0000] result: 'my secret message'  source=console\n  console.log(\"result: '\" + result + \"'\");\n}\n\nconst decrypt = async (keyData, transmittedData) => {\n  const initializeVectorLength = 12;\n\n  // the first 12 bytes are the initialization vector\n  const iv = new Uint8Array(\n    transmittedData.subarray(0, initializeVectorLength)\n  );\n\n  // the rest of the transmitted data is the encrypted data\n  const encryptedData = new Uint8Array(\n    transmittedData.subarray(initializeVectorLength)\n  );\n\n  const importedKey = await crypto.subtle.importKey(\n    \"jwk\",\n    keyData,\n    { name: \"AES-GCM\", length: 256 },\n    true,\n    [\"encrypt\", \"decrypt\"]\n  );\n\n  const plain = await crypto.subtle.decrypt(\n    { name: \"AES-GCM\", iv: iv },\n    importedKey,\n    encryptedData\n  );\n\n  return arrayBufferToString(plain);\n};\n\nconst arrayBufferToString = (buffer) => {\n  return String.fromCharCode.apply(null, new Uint8Array(buffer));\n};\n\nconst base64Decode = (base64String) => {\n  return new Uint8Array(b64decode(base64String));\n};\n"
  },
  {
    "path": "examples/webcrypto/import_export/import-raw-base64-decrypt.js",
    "content": "import { b64decode } from \"k6/encoding\";\n\nexport default async function () {\n  // transmitted data is the base64 of the initialization vector + encrypted data\n  // that unusually transmitted over the network\n  const transmittedData = base64Decode(\n    \"whzEN310mrlWIH/icf0dMquRZ2ENyfOzkvPuu92WR/9F8dbeFM8EGUVNIhaS\"\n  );\n\n  // keyData is the key used to decrypt the data, that is usually stored in a secure location\n  // for the purpose of this example, we are using a static key\n  const keyData = new Uint8Array([\n    109, 151, 76, 33, 232, 253, 176, 90, 94, 40, 146, 227, 139, 208, 245, 139,\n    69, 215, 55, 197, 43, 122, 160, 178, 228, 104, 4, 115, 138, 159, 119, 49,\n  ]);\n\n  const result = await decrypt(keyData, transmittedData);\n\n  // should output decrypted message\n  // INFO[0000] result: 'my secret message'  source=console\n  console.log(\"result: '\" + result + \"'\");\n}\n\nconst decrypt = async (keyData, transmittedData) => {\n  const initializeVectorLength = 12;\n\n  // the first 12 bytes are the initialization vector\n  const iv = new Uint8Array(\n    transmittedData.subarray(0, initializeVectorLength)\n  );\n\n  // the rest of the transmitted data is the encrypted data\n  const encryptedData = new Uint8Array(\n    transmittedData.subarray(initializeVectorLength)\n  );\n\n  const importedKey = await crypto.subtle.importKey(\n    \"raw\",\n    keyData,\n    { name: \"AES-GCM\", length: \"256\" },\n    true,\n    [\"decrypt\"]\n  );\n\n  const plain = await crypto.subtle.decrypt(\n    { name: \"AES-GCM\", iv: iv },\n    importedKey,\n    encryptedData\n  );\n\n  return arrayBufferToString(plain);\n};\n\nconst arrayBufferToString = (buffer) => {\n  return String.fromCharCode.apply(null, new Uint8Array(buffer));\n};\n\nconst base64Decode = (base64String) => {\n  return new Uint8Array(b64decode(base64String));\n};\n"
  },
  {
    "path": "examples/webcrypto/randomUUID.js",
    "content": "export default function () {\n  const myUUID = crypto.randomUUID();\n\n  console.log(myUUID);\n}\n"
  },
  {
    "path": "examples/webcrypto/sign_verify/sign-verify-ecdsa.js",
    "content": "export default async function () {\n  const keyPair = await crypto.subtle.generateKey(\n    {\n      name: \"ECDSA\",\n      namedCurve: \"P-256\",\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  const data = string2ArrayBuffer(\"Hello World\");\n\n  const alg = { name: \"ECDSA\", hash: { name: \"SHA-256\" } };\n\n  // makes a signature of the encoded data with the provided key\n  const signature = await crypto.subtle.sign(alg, keyPair.privateKey, data);\n\n  console.log(\"signature: \", printArrayBuffer(signature));\n\n  //Verifies the signature of the encoded data with the provided key\n  const verified = await crypto.subtle.verify(\n    alg,\n    keyPair.publicKey,\n    signature,\n    data\n  );\n\n  console.log(\"verified: \", verified);\n}\n\nconst string2ArrayBuffer = (str) => {\n  let buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  let bufView = new Uint16Array(buf);\n  for (let i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n};\n\nconst printArrayBuffer = (buffer) => {\n  let view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n"
  },
  {
    "path": "examples/webcrypto/sign_verify/sign-verify-hmac.js",
    "content": "export default async function () {\n  const generatedKey = await crypto.subtle.generateKey(\n    {\n      name: \"HMAC\",\n      hash: { name: \"SHA-1\" },\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  const encoded = string2ArrayBuffer(\"Hello World\");\n\n  // Signs the encoded data with the provided key using the HMAC algorithm\n  // the returned signature can be verified using the verify method.\n  const signature = await crypto.subtle.sign(\"HMAC\", generatedKey, encoded);\n\n  // Verifies the signature of the encoded data with the provided key using the HMAC algorithm\n  const verified = await crypto.subtle.verify(\n    \"HMAC\",\n    generatedKey,\n    signature,\n    encoded\n  );\n\n  console.log(\"verified: \", verified);\n}\n\nfunction string2ArrayBuffer(str) {\n  var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  var bufView = new Uint16Array(buf);\n  for (var i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n}\n"
  },
  {
    "path": "examples/webcrypto/sign_verify/verify-spki-ecdsa-invalid.js",
    "content": "export default async function () {\n  const publicKey = await crypto.subtle.importKey(\n    \"spki\",\n    spkiPublicKeyData,\n    { name: \"ECDSA\", namedCurve: \"P-384\" },\n    true,\n    [\"verify\"]\n  );\n\n  //Verifies the signature of the encoded data with the provided key\n  const verified = await crypto.subtle.verify(\n    {\n      name: \"ECDSA\",\n      hash: \"SHA-384\",\n    },\n    publicKey,\n    invalidSignature,\n    plainText\n  );\n\n  console.log(\"verified: \", verified);\n}\n\nconst spkiPublicKeyData = new Uint8Array([\n  48, 118, 48, 16, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 5, 43, 129, 4, 0, 34, 3,\n  98, 0, 4, 29, 49, 157, 105, 45, 202, 95, 87, 84, 186, 123, 50, 193, 22, 66,\n  198, 216, 210, 180, 251, 130, 73, 195, 242, 20, 215, 30, 144, 181, 37, 41,\n  102, 217, 127, 123, 235, 31, 170, 177, 228, 243, 226, 96, 85, 73, 194, 238,\n  219, 82, 3, 41, 179, 190, 166, 181, 229, 86, 36, 161, 81, 80, 161, 105, 102,\n  99, 95, 25, 22, 239, 4, 221, 117, 142, 105, 64, 157, 6, 51, 203, 75, 37, 153,\n  65, 121, 178, 42, 118, 156, 116, 52, 54, 145, 14, 121, 153, 81,\n]);\n\nconst plainText = new Uint8Array([\n  95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248,\n  62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213,\n  93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60,\n  177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162,\n  175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206,\n  2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149,\n  44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234,\n  93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77,\n  131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108,\n  215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19,\n  137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204,\n  157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72,\n  2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171,\n]);\n\nconst invalidSignature = new Uint8Array([\n  13, 217, 194, 199, 240, 182, 244, 217, 50, 130, 84, 169, 2, 232, 115, 116,\n  179, 192, 146, 25, 94, 107, 226, 26, 161, 166, 220, 216, 235, 166, 15, 123,\n  11, 56, 196, 0, 109, 250, 33, 70, 212, 233, 253, 35, 220, 51, 97, 121, 151,\n  64, 23, 73, 58, 31, 79, 116, 238, 207, 228, 85, 190, 61, 169, 237, 153, 100,\n  29, 129, 97, 13, 254, 180, 104, 182, 7, 218, 148, 29, 87, 20, 231, 181, 26,\n  238, 44, 69, 170, 14, 156, 77, 160, 33, 178, 55, 0,\n]);\n"
  },
  {
    "path": "examples/webcrypto/sign_verify/verify-spki-ecdsa-valid.js",
    "content": "export default async function () {\n  const publicKey = await crypto.subtle.importKey(\n    \"spki\",\n    spkiPublicKeyData,\n    { name: \"ECDSA\", namedCurve: \"P-256\" },\n    true,\n    [\"verify\"]\n  );\n\n  //Verifies the signature of the encoded data with the provided key\n  const verified = await crypto.subtle.verify(\n    {\n      name: \"ECDSA\",\n      hash: \"SHA-256\",\n    },\n    publicKey,\n    signature,\n    plaintText\n  );\n\n  console.log(\"verified: \", verified);\n}\n\nconst spkiPublicKeyData = new Uint8Array([\n  48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134, 72, 206, 61,\n  3, 1, 7, 3, 66, 0, 4, 10, 5, 30, 56, 111, 103, 196, 166, 225, 229, 203, 238,\n  125, 55, 116, 91, 88, 142, 190, 114, 15, 117, 89, 22, 40, 111, 150, 41, 105,\n  122, 57, 23, 17, 216, 106, 234, 201, 103, 8, 210, 58, 38, 35, 216, 198, 237,\n  187, 84, 217, 164, 63, 100, 6, 105, 49, 128, 15, 53, 29, 158, 117, 235, 238,\n  30,\n]);\n\nconst plaintText = new Uint8Array([\n  95, 77, 186, 79, 50, 12, 12, 232, 118, 114, 90, 252, 229, 251, 210, 91, 248,\n  62, 90, 113, 37, 160, 140, 175, 231, 60, 62, 186, 196, 33, 119, 157, 249, 213,\n  93, 24, 12, 58, 233, 148, 38, 69, 225, 216, 47, 238, 140, 157, 41, 75, 60,\n  177, 160, 138, 153, 49, 32, 27, 60, 14, 129, 252, 71, 202, 207, 131, 21, 162,\n  175, 102, 50, 65, 19, 195, 182, 98, 48, 195, 70, 8, 196, 244, 89, 54, 52, 206,\n  2, 178, 103, 54, 34, 119, 240, 168, 64, 202, 116, 188, 61, 26, 98, 54, 149,\n  44, 94, 215, 170, 248, 168, 254, 203, 221, 250, 117, 132, 230, 151, 140, 234,\n  93, 42, 91, 159, 183, 241, 180, 140, 139, 11, 229, 138, 48, 82, 2, 117, 77,\n  131, 118, 16, 115, 116, 121, 60, 240, 38, 170, 238, 83, 0, 114, 125, 131, 108,\n  215, 30, 113, 179, 69, 221, 178, 228, 68, 70, 255, 197, 185, 1, 99, 84, 19,\n  137, 13, 145, 14, 163, 128, 152, 74, 144, 25, 16, 49, 50, 63, 22, 219, 204,\n  157, 107, 225, 104, 184, 72, 133, 56, 76, 160, 62, 18, 96, 10, 193, 194, 72,\n  2, 138, 243, 114, 108, 201, 52, 99, 136, 46, 168, 192, 42, 171,\n]);\n\nconst signature = new Uint8Array([\n  83, 223, 63, 226, 42, 29, 106, 105, 225, 145, 197, 180, 118, 154, 109, 110,\n  66, 67, 47, 251, 53, 190, 203, 65, 207, 36, 19, 57, 49, 122, 124, 118, 59, 74,\n  222, 134, 42, 235, 180, 229, 134, 24, 205, 81, 171, 156, 100, 218, 127, 242,\n  126, 53, 27, 77, 249, 101, 157, 132, 244, 30, 67, 30, 64, 12,\n]);\n"
  },
  {
    "path": "examples/webcrypto/sign_verify/verify-spki-rsa-valid.js",
    "content": "export default async function () {\n  const keyPair = await crypto.subtle.generateKey(\n    {\n      name: \"RSASSA-PKCS1-v1_5\",\n      modulusLength: 1024, // Can be 1024, 2048, or 4096\n      publicExponent: new Uint8Array([1, 0, 1]), // 24-bit representation of 65537\n      hash: { name: \"SHA-256\" }, // Could be \"SHA-1\", \"SHA-256\", \"SHA-384\", or \"SHA-512\"\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(\"keyPair: \", JSON.stringify(keyPair));\n\n  const data = string2ArrayBuffer(\"Hello World\");\n\n  const alg = { name: \"RSASSA-PKCS1-v1_5\", hash: { name: \"SHA-256\" } };\n\n  console.log(\"private key type: \" + keyPair.privateKey.type);\n  console.log(\"public key type: \" + keyPair.publicKey.type);\n\n  // makes a signature of the encoded data with the provided key\n  const signature = await crypto.subtle.sign(alg, keyPair.privateKey, data);\n\n  console.log(\"signature: \", printArrayBuffer(signature));\n\n  //Verifies the signature of the encoded data with the provided key\n  const verified = await crypto.subtle.verify(\n    alg,\n    keyPair.publicKey,\n    signature,\n    data\n  );\n\n  console.log(\"verified: \", verified);\n}\n\nconst string2ArrayBuffer = (str) => {\n  let buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  let bufView = new Uint16Array(buf);\n  for (let i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n};\n\nconst printArrayBuffer = (buffer) => {\n  let view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n"
  },
  {
    "path": "examples/websocket.js",
    "content": "import ws from \"k6/ws\";\nimport { check } from \"k6\";\n\nexport default function () {\n    var url = \"ws://echo.websocket.org\";\n    var params = { \"tags\": { \"my_tag\": \"hello\" } };\n\n    var response = ws.connect(url, params, function (socket) {\n        socket.on('open', function open() {\n            console.log('connected');\n            socket.send(Date.now());\n\n            socket.setInterval(function timeout() {\n                socket.ping();\n                console.log(\"Pinging every 1sec (setInterval test)\");\n            }, 1000);\n        });\n\n        socket.on('ping', function () {\n            console.log(\"PING!\");\n        });\n\n        socket.on('pong', function () {\n            console.log(\"PONG!\");\n        });\n\n        socket.on('pong', function () {\n            // Multiple event handlers on the same event\n            console.log(\"OTHER PONG!\");\n        });\n\n        socket.on('message', function incoming(data) {\n            console.log(`Roundtrip time: ${Date.now() - data} ms`);\n            socket.setTimeout(function timeout() {\n                socket.send(Date.now());\n            }, 500);\n        });\n\n        socket.on('close', function close() {\n            console.log('disconnected');\n        });\n\n        socket.on('error', function (e) {\n            if (e.error() != \"websocket: close sent\") {\n                console.log('An unexpected error occurred: ', e.error());\n            }\n        });\n\n        socket.setTimeout(function () {\n            console.log('2 seconds passed, closing the socket');\n            socket.close();\n        }, 2000);\n    });\n\n    check(response, { \"status is 101\": (r) => r && r.status === 101 });\n};\n"
  },
  {
    "path": "examples/websockets/test-echo.js",
    "content": "import { WebSocket } from \"k6/websockets\"\n\nconst CLOSED_STATE = 3\n\nexport default function() {\n\t// local echo server should be launched with `make ws-echo-server-run`\n\tvar url = \"wss://echo.websocket.org/\"\n\tvar params = { \"tags\": { \"my_tag\": \"hello\" } };\n\n\tlet ws = new WebSocket(url, null, params)\n\tws.binaryType = \"arraybuffer\";\n\tws.onopen = () => {\n\t\tconsole.log('connected')\n\t\tws.send(Date.now().toString())\n\t}\n\n\tlet intervalId = setInterval(() => {\n\t\tws.ping();\n\t\tconsole.log(\"Pinging every 1 sec (setInterval test)\")\n\t}, 1000);\n\n\tlet timeout1id = setTimeout(function() {\n\t\tconsole.log('2 seconds passed, closing the socket')\n\t\tclearInterval(intervalId)\n\t\tws.close()\n\n\t}, 2000);\n\n\tws.onclose = () => {\n\t\tclearTimeout(timeout1id);\n\n\t\tconsole.log('disconnected')\n\t}\n\n\n\tws.onping = () => {\n\t\tconsole.log(\"PING!\")\n\t}\n\n\tws.onpong = () => {\n\t\tconsole.log(\"PONG!\")\n\t}\n\n\t// Multiple event handlers on the same event\n\tws.addEventListener(\"pong\", () => {\n\t\tconsole.log(\"OTHER PONG!\")\n\t})\n\n\tws.onmessage = (m) => {\n\t\tlet parsed = parseInt(m.data, 10)\n\t\tif (Number.isNaN(parsed)) {\n\t\t\tconsole.log('Not a number received: ', m.data)\n\n\t\t\treturn\n\t\t}\n\n\t\tconsole.log(`Roundtrip time: ${Date.now() - parsed} ms`);\n\n\t\tlet timeoutId = setTimeout(function() {\n\t\t\tif (ws.readyState == CLOSED_STATE) {\n\t\t\t\tconsole.log(\"Socket closed, not sending anything\");\n\n\t\t\t\tclearTimeout(timeoutId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tws.send(Date.now().toString())\n\t\t}, 500);\n\t}\n\n\tws.onerror = (e) => {\n\t\tif (e.error != \"websocket: close sent\") {\n\t\t\tconsole.log('An unexpected error occurred: ', e.error);\n\t\t}\n\t};\n};\n"
  },
  {
    "path": "examples/websockets/ws.js",
    "content": "import { randomString, randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.1.0/index.js';\nimport { WebSocket } from 'k6/websockets';\n\nconst sessionDuration = randomIntBetween(1000, 3000); // user session between 1s and 3s\n\nexport default function () {\n\tfor (let i = 0; i < 4; i++) {\n\t\tstartWSWorker(i);\n\t}\n}\n\nfunction startWSWorker(id) {\n\t// create a new websocket connection\n\tconst ws = new WebSocket(`wss://quickpizza.grafana.com/ws`);\n\tws.binaryType = 'arraybuffer';\n\n\tws.addEventListener('open', () => {\n\t\t// change the user name\n\t\tws.send(JSON.stringify({ event: 'SET_NAME', new_name: `VU ${__VU}:${id}` }));\n\n\t\t// listen for messages/errors and log them into console\n\t\tws.addEventListener('message', (e) => {\n\t\t\tconst msg = JSON.parse(e.data);\n\t\t\tif (msg.event === 'CHAT_MSG') {\n\t\t\t\tconsole.log(`VU ${__VU}:${id} received: ${msg.user} says: ${msg.message}`);\n\t\t\t} else if (msg.event === 'ERROR') {\n\t\t\t\tconsole.error(`VU ${__VU}:${id} received:: ${msg.message}`);\n\t\t\t} else {\n\t\t\t\tconsole.log(`VU ${__VU}:${id} received unhandled message: ${msg.message}`);\n\t\t\t}\n\t\t});\n\n\t\t// send a message every 2-8 seconds\n\t\tconst intervalId = setInterval(() => {\n\t\t\tws.send(JSON.stringify({ event: 'SAY', message: `I'm saying ${randomString(5)}` }));\n\t\t}, randomIntBetween(2000, 8000)); // say something every 2-8 seconds\n\n\t\t// after a sessionDuration stop sending messages and leave the room\n\t\tconst timeout1id = setTimeout(function () {\n\t\t\tclearInterval(intervalId);\n\t\t\tconsole.log(`VU ${__VU}:${id}: ${sessionDuration}ms passed, leaving the chat`);\n\t\t\tws.send(JSON.stringify({ event: 'LEAVE' }));\n\t\t}, sessionDuration);\n\n\t\t// after a sessionDuration + 3s close the connection\n\t\tconst timeout2id = setTimeout(function () {\n\t\t\tconsole.log(`Closing the socket forcefully 3s after graceful LEAVE`);\n\t\t\tws.close();\n\t\t}, sessionDuration + 3000);\n\n\t\t// when connection is closing, clean up the previously created timers\n\t\tws.addEventListener('close', () => {\n\t\t\tclearTimeout(timeout1id);\n\t\t\tclearTimeout(timeout2id);\n\t\t\tconsole.log(`VU ${__VU}:${id}: disconnected`);\n\t\t});\n\t});\n}\n"
  },
  {
    "path": "ext/doc.go",
    "content": "// Package ext contains the extension registry and all generic functionality for\n// k6 extensions.\npackage ext\n"
  },
  {
    "path": "ext/ext.go",
    "content": "package ext\n\nimport (\n\t\"fmt\"\n\t\"maps\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n)\n\n// TODO: Make an ExtensionRegistry?\n//\n//nolint:gochecknoglobals\nvar (\n\tmx         sync.RWMutex\n\textensions = make(map[ExtensionType]map[string]*Extension)\n)\n\n// ExtensionType is the type of all supported k6 extensions.\ntype ExtensionType uint8\n\n// All supported k6 extension types.\nconst (\n\tJSExtension ExtensionType = iota + 1\n\tOutputExtension\n\tSecretSourceExtension\n\tSubcommandExtension\n)\n\nfunc (e ExtensionType) String() string {\n\tvar s string\n\tswitch e {\n\tcase JSExtension:\n\t\ts = \"js\"\n\tcase OutputExtension:\n\t\ts = \"output\"\n\tcase SecretSourceExtension:\n\t\ts = \"secret-source\"\n\tcase SubcommandExtension:\n\t\ts = \"subcommand\"\n\t}\n\treturn s\n}\n\n// Extension is a generic container for any k6 extension.\ntype Extension struct {\n\tName, Path, Version string\n\tType                ExtensionType\n\tModule              any\n}\n\nfunc (e Extension) String() string {\n\treturn fmt.Sprintf(\"%s %s, %s [%s]\", e.Path, e.Version, e.Name, e.Type)\n}\n\n// Register a new extension with the given name and type. This function will\n// panic if an unsupported extension type is provided, or if an extension of the\n// same type and name is already registered.\nfunc Register(name string, typ ExtensionType, mod any) {\n\tmx.Lock()\n\tdefer mx.Unlock()\n\n\texts, ok := extensions[typ]\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"unsupported extension type: %T\", typ))\n\t}\n\n\tif _, ok := exts[name]; ok {\n\t\tpanic(fmt.Sprintf(\"extension already registered: %s\", name))\n\t}\n\n\tpath, version := extractModuleInfo(mod)\n\n\texts[name] = &Extension{\n\t\tName:    name,\n\t\tType:    typ,\n\t\tModule:  mod,\n\t\tPath:    path,\n\t\tVersion: version,\n\t}\n}\n\n// Get returns all extensions of the specified type.\nfunc Get(typ ExtensionType) map[string]*Extension {\n\tmx.RLock()\n\tdefer mx.RUnlock()\n\n\texts, ok := extensions[typ]\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"unsupported extension type: %T\", typ))\n\t}\n\n\tresult := make(map[string]*Extension, len(exts))\n\n\tmaps.Copy(result, exts)\n\n\treturn result\n}\n\n// GetAll returns all extensions, sorted by their import path and name.\nfunc GetAll() []*Extension {\n\tmx.RLock()\n\tdefer mx.RUnlock()\n\n\tjs, out, subcommand := extensions[JSExtension], extensions[OutputExtension], extensions[SubcommandExtension]\n\tresult := make([]*Extension, 0, len(js)+len(out)+len(subcommand))\n\n\tfor _, e := range js {\n\t\tresult = append(result, e)\n\t}\n\tfor _, e := range out {\n\t\tresult = append(result, e)\n\t}\n\tfor _, e := range subcommand {\n\t\tresult = append(result, e)\n\t}\n\n\tsort.Slice(result, func(i, j int) bool {\n\t\tif result[i].Path == result[j].Path {\n\t\t\treturn result[i].Name < result[j].Name\n\t\t}\n\t\treturn result[i].Path < result[j].Path\n\t})\n\n\treturn result\n}\n\n// extractModuleInfo attempts to return the package path and version of the Go\n// module that created the given value.\nfunc extractModuleInfo(mod any) (path, version string) {\n\tt := reflect.TypeOf(mod)\n\n\tswitch t.Kind() {\n\tcase reflect.Ptr:\n\t\tif t.Elem() != nil {\n\t\t\tpath = t.Elem().PkgPath()\n\t\t}\n\tcase reflect.Func:\n\t\tpath = runtime.FuncForPC(reflect.ValueOf(mod).Pointer()).Name()\n\tdefault:\n\t\treturn path, version\n\t}\n\n\tbuildInfo, ok := debug.ReadBuildInfo()\n\tif !ok {\n\t\treturn path, version\n\t}\n\n\tfor _, dep := range buildInfo.Deps {\n\t\tdepPath := strings.TrimSpace(dep.Path)\n\t\tif strings.HasPrefix(path, depPath) {\n\t\t\tif dep.Replace != nil {\n\t\t\t\treturn depPath, dep.Replace.Version\n\t\t\t}\n\t\t\treturn depPath, dep.Version\n\t\t}\n\t}\n\n\treturn path, version\n}\n\nfunc init() {\n\textensions[JSExtension] = make(map[string]*Extension)\n\textensions[OutputExtension] = make(map[string]*Extension)\n\textensions[SecretSourceExtension] = make(map[string]*Extension)\n\textensions[SubcommandExtension] = make(map[string]*Extension)\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module go.k6.io/k6\n\ngo 1.25.0\n\ntoolchain go1.25.8\n\nrequire (\n\tbuf.build/gen/go/prometheus/prometheus/protocolbuffers/go v1.36.11-20251118093737-4105057cc7d4.1\n\tgithub.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358\n\tgithub.com/Masterminds/semver/v3 v3.4.0\n\tgithub.com/PuerkitoBio/goquery v1.11.0\n\tgithub.com/Soontao/goHttpDigestClient v0.0.0-20170320082612-6d28bb1415c5\n\tgithub.com/andybalholm/brotli v1.2.0\n\tgithub.com/bufbuild/protocompile v0.14.1\n\tgithub.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d\n\tgithub.com/evanw/esbuild v0.27.2\n\tgithub.com/fatih/color v1.18.0\n\tgithub.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535\n\tgithub.com/go-sourcemap/sourcemap v2.1.4+incompatible\n\tgithub.com/golang/protobuf v1.5.4\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/gorilla/websocket v1.5.3\n\tgithub.com/grafana/k6provider v0.2.0\n\tgithub.com/grafana/sobek v0.0.0-20260219184149-bdae4a158e94\n\tgithub.com/grafana/xk6-dashboard v0.8.1\n\tgithub.com/grafana/xk6-redis v0.3.6\n\tgithub.com/grpc-ecosystem/go-grpc-middleware v1.4.0\n\tgithub.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc\n\tgithub.com/jhump/protoreflect v1.18.0\n\tgithub.com/klauspost/compress v1.18.4\n\tgithub.com/mailru/easyjson v0.9.0\n\tgithub.com/mattn/go-colorable v0.1.14\n\tgithub.com/mattn/go-isatty v0.0.20\n\tgithub.com/mccutchen/go-httpbin/v2 v2.20.0\n\tgithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd\n\tgithub.com/mstoykov/envconfig v1.5.0\n\tgithub.com/mstoykov/k6-taskqueue-lib v0.1.3\n\tgithub.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e\n\tgithub.com/sirupsen/logrus v1.9.3\n\tgithub.com/spf13/afero v1.1.2\n\tgithub.com/spf13/cobra v1.4.0\n\tgithub.com/spf13/pflag v1.0.5\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/tidwall/gjson v1.18.0\n\tgo.opentelemetry.io/otel v1.40.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0\n\tgo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0\n\tgo.opentelemetry.io/otel/metric v1.40.0\n\tgo.opentelemetry.io/otel/sdk v1.40.0\n\tgo.opentelemetry.io/otel/sdk/metric v1.40.0\n\tgo.opentelemetry.io/otel/trace v1.40.0\n\tgo.opentelemetry.io/proto/otlp v1.9.0\n\tgo.uber.org/goleak v1.3.0\n\tgolang.org/x/crypto v0.47.0\n\tgolang.org/x/crypto/x509roots/fallback v0.0.0-20260113154411-7d0074ccc6f1\n\tgolang.org/x/net v0.49.0\n\tgolang.org/x/sync v0.19.0\n\tgolang.org/x/term v0.39.0\n\tgolang.org/x/time v0.14.0\n\tgoogle.golang.org/grpc v1.78.0\n\tgoogle.golang.org/protobuf v1.36.11\n\tgopkg.in/guregu/null.v3 v3.3.0\n\tgopkg.in/yaml.v3 v3.0.1\n)\n\nrequire (\n\tgithub.com/grafana/xk6-dashboard-assets v0.1.2 // indirect\n\tgithub.com/jhump/protoreflect/v2 v2.0.0-beta.1 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgo.yaml.in/yaml/v2 v2.4.2 // indirect\n\tgopkg.in/validator.v2 v2.0.1 // indirect\n)\n\nrequire (\n\tbuf.build/gen/go/gogo/protobuf/protocolbuffers/go v1.36.11-20240617172848-e1dbca2775a7.1 // indirect\n\tgithub.com/andybalholm/cascadia v1.3.3 // indirect\n\tgithub.com/beorn7/perks v1.0.1 // indirect\n\tgithub.com/cenkalti/backoff/v5 v5.0.3 // indirect\n\tgithub.com/cespare/xxhash/v2 v2.3.0 // indirect\n\tgithub.com/chromedp/sysutil v1.1.0 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect\n\tgithub.com/dlclark/regexp2 v1.11.5 // indirect\n\tgithub.com/go-logr/logr v1.4.3 // indirect\n\tgithub.com/go-logr/stdr v1.2.2 // indirect\n\tgithub.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 // indirect\n\tgithub.com/grafana/k6-cloud-openapi-client-go v0.0.0-20260106090513-285631296b5d\n\tgithub.com/grafana/k6build v0.5.15 // indirect\n\tgithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.0.0 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect\n\tgithub.com/nxadm/tail v1.4.11 // indirect\n\tgithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/prometheus/client_golang v1.23.2\n\tgithub.com/prometheus/client_model v0.6.2\n\tgithub.com/prometheus/common v0.66.1 // indirect\n\tgithub.com/prometheus/procfs v0.16.1 // indirect\n\tgithub.com/r3labs/sse/v2 v2.10.0 // indirect\n\tgithub.com/redis/go-redis/v9 v9.17.2 // indirect\n\tgithub.com/tidwall/match v1.1.1 // indirect\n\tgithub.com/tidwall/pretty v1.2.1 // indirect\n\tgo.opentelemetry.io/auto/sdk v1.2.1 // indirect\n\tgolang.org/x/sys v0.40.0 // indirect\n\tgolang.org/x/text v0.33.0 // indirect\n\tgoogle.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda // indirect\n\tgoogle.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect\n\tgopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect\n)\n\nretract v1.2.0 // mistakenly pushed old tag from the old xk6-browser repo before it was merged in k6\n"
  },
  {
    "path": "go.sum",
    "content": "buf.build/gen/go/gogo/protobuf/protocolbuffers/go v1.36.11-20240617172848-e1dbca2775a7.1 h1:FlXwksX9wjddXoyW88Jw3tz1DEGbXBSGZW6fg0frZ0M=\nbuf.build/gen/go/gogo/protobuf/protocolbuffers/go v1.36.11-20240617172848-e1dbca2775a7.1/go.mod h1:mwDA6SccUlW4ebUkJTpKoHZzCrLFh/WI48oQRvUTGAA=\nbuf.build/gen/go/prometheus/prometheus/protocolbuffers/go v1.36.11-20251118093737-4105057cc7d4.1 h1:tk/yD1MiQW1n5U/07iphh2Pksv0HDiQ1VOYC6alZJR0=\nbuf.build/gen/go/prometheus/prometheus/protocolbuffers/go v1.36.11-20251118093737-4105057cc7d4.1/go.mod h1:6rM4oiNLtvSABJBFC+GReCtGUaWLYwhsadnb9FgJ/2k=\ncloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=\ngithub.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=\ngithub.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=\ngithub.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=\ngithub.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=\ngithub.com/Soontao/goHttpDigestClient v0.0.0-20170320082612-6d28bb1415c5 h1:k+1+doEm31k0rRjCjLnGG3YRkuO9ljaEyS2ajZd6GK8=\ngithub.com/Soontao/goHttpDigestClient v0.0.0-20170320082612-6d28bb1415c5/go.mod h1:5Q4+CyR7+Q3VMG8f78ou+QSX/BNUNUx5W48eFRat8DQ=\ngithub.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=\ngithub.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=\ngithub.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=\ngithub.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=\ngithub.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=\ngithub.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=\ngithub.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=\ngithub.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=\ngithub.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=\ngithub.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=\ngithub.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=\ngithub.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=\ngithub.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d h1:ZtA1sedVbEW7EW80Iz2GR3Ye6PwbJAJXjv7D74xG6HU=\ngithub.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k=\ngithub.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=\ngithub.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=\ngithub.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=\ngithub.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=\ngithub.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/evanw/esbuild v0.27.2 h1:3xBEws9y/JosfewXMM2qIyHAi+xRo8hVx475hVkJfNg=\ngithub.com/evanw/esbuild v0.27.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=\ngithub.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=\ngithub.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=\ngithub.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=\ngithub.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=\ngithub.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 h1:yE7argOs92u+sSCRgqqe6eF+cDaVhSPlioy1UkA0p/w=\ngithub.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535/go.mod h1:BWmvoE1Xia34f3l/ibJweyhrT+aROb/FQ6d+37F0e2s=\ngithub.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=\ngithub.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=\ngithub.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=\ngithub.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=\ngithub.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=\ngithub.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=\ngithub.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q=\ngithub.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 h1:ZgoomqkdjGbQ3+qQXCkvYMCDvGDNg2k5JJDjjdTB6jY=\ngithub.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=\ngithub.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\ngithub.com/grafana/k6-cloud-openapi-client-go v0.0.0-20260106090513-285631296b5d h1:fb0Y2ejWxOv0f/VlMLyE7GErwM499C3+ct3JlYHi9IA=\ngithub.com/grafana/k6-cloud-openapi-client-go v0.0.0-20260106090513-285631296b5d/go.mod h1:RBPBP7qIR/K6qzQEQYESVhp/XJspiBTOyBEBCbPXrvI=\ngithub.com/grafana/k6build v0.5.15 h1:4I5dkAWSMvXsElS1OpLbHj6ZXnebXZGnmwDXy5vcwSQ=\ngithub.com/grafana/k6build v0.5.15/go.mod h1:Sk7SUiCnx2AgkirG3PrCtmJKYL+a8EeRdTzFfbxP0X8=\ngithub.com/grafana/k6foundry v0.4.7 h1:1YXkTBwO/2dSx0pqJrraJATsFlsIX0vEpaEjV7E35w4=\ngithub.com/grafana/k6foundry v0.4.7/go.mod h1:eLsr0whhH+5Y1y7YpDxJi3Jv5wHMuf+80vdRyMH10pg=\ngithub.com/grafana/k6provider v0.2.0 h1:Zu8FBnk6cJyTTkpCA+y+Ravc2YFeAQjsIfPpcbZtfB0=\ngithub.com/grafana/k6provider v0.2.0/go.mod h1:TJ6vzPm4yDQ2ji/Fet0dFOpdjktrKZp4hsnLZhRoZVA=\ngithub.com/grafana/sobek v0.0.0-20260219184149-bdae4a158e94 h1:yB8ad5rnZcJ6Aun/tobcYMMLtb3+tZp46M5Cs5v4j9w=\ngithub.com/grafana/sobek v0.0.0-20260219184149-bdae4a158e94/go.mod h1:YtuqiJX1W3XvRSilL/kUZzduJG3phPJWyzM9DiIEfBo=\ngithub.com/grafana/xk6-dashboard v0.8.1 h1:QTEXPhkSYxiSN1lnl/cIlrnA97dUvOW+0yxQQCa9AAU=\ngithub.com/grafana/xk6-dashboard v0.8.1/go.mod h1:H1d7bUniuCFWWACgBdJBvpM5dC9vXehycQyMKzCC8CE=\ngithub.com/grafana/xk6-dashboard-assets v0.1.2 h1:n2wqytPICn2ZYsKa9HE6GlvFXk+WjByMfT4eM+ms3gE=\ngithub.com/grafana/xk6-dashboard-assets v0.1.2/go.mod h1:SeoRjvmFF8UhLIFDfvjqqwBtE8MtaIPYIDWqVJZEHDo=\ngithub.com/grafana/xk6-redis v0.3.6 h1:RS7AZwiHqIxU2gb4PxkZnqspI75xffRSKKldc6znjIg=\ngithub.com/grafana/xk6-redis v0.3.6/go.mod h1:wvauBdzoa0ZPUdLPQaucxppNC5Df6fIFwkg2ge/BG9g=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=\ngithub.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=\ngithub.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc h1:KpMgaYJRieDkHZJWY3LMafvtqS/U8xX6+lUN+OKpl/Y=\ngithub.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=\ngithub.com/jhump/protoreflect v1.18.0 h1:TOz0MSR/0JOZ5kECB/0ufGnC2jdsgZ123Rd/k4Z5/2w=\ngithub.com/jhump/protoreflect v1.18.0/go.mod h1:ezWcltJIVF4zYdIFM+D/sHV4Oh5LNU08ORzCGfwvTz8=\ngithub.com/jhump/protoreflect/v2 v2.0.0-beta.1 h1:Dw1rslK/VotaUGYsv53XVWITr+5RCPXfvvlGrM/+B6w=\ngithub.com/jhump/protoreflect/v2 v2.0.0-beta.1/go.mod h1:D9LBEowZyv8/iSu97FU2zmXG3JxVTmNw21mu63niFzU=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=\ngithub.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=\ngithub.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=\ngithub.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=\ngithub.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mccutchen/go-httpbin/v2 v2.20.0 h1:iMUzhdbAcjo9hepfG5W3hz1yWAyxiYlJMzKQtwyGDms=\ngithub.com/mccutchen/go-httpbin/v2 v2.20.0/go.mod h1:GBy5I7XwZ4ZLhT3hcq39I4ikwN9x4QUt6EAxNiR8Jus=\ngithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd h1:AC3N94irbx2kWGA8f/2Ks7EQl2LxKIRQYuT9IJDwgiI=\ngithub.com/mstoykov/atlas v0.0.0-20220811071828-388f114305dd/go.mod h1:9vRHVuLCjoFfE3GT06X0spdOAO+Zzo4AMjdIwUHBvAk=\ngithub.com/mstoykov/envconfig v1.5.0 h1:E2FgWf73BQt0ddgn7aoITkQHmgwAcHup1s//MsS5/f8=\ngithub.com/mstoykov/envconfig v1.5.0/go.mod h1:vk/d9jpexY2Z9Bb0uB4Ndesss1Sr0Z9ZiGUrg5o9VGk=\ngithub.com/mstoykov/k6-taskqueue-lib v0.1.3 h1:sdiSc5NEK/qpQkTQe505vgRYQocZevdO9ON+yMudFqo=\ngithub.com/mstoykov/k6-taskqueue-lib v0.1.3/go.mod h1:e9R2vtLFHCKT+CMiEjTJVMQiJAi17M1KiXXRs7FYc6w=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=\ngithub.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=\ngithub.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=\ngithub.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=\ngithub.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=\ngithub.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=\ngithub.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE=\ngithub.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14=\ngithub.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=\ngithub.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=\ngithub.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=\ngithub.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=\ngithub.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=\ngithub.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=\ngithub.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=\ngithub.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=\ngithub.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=\ngithub.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=\ngithub.com/redis/go-redis/v9 v9.17.2 h1:P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI=\ngithub.com/redis/go-redis/v9 v9.17.2/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=\ngithub.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=\ngithub.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e h1:zWKUYT07mGmVBH+9UgnHXd/ekCK99C8EbDSAt5qsjXE=\ngithub.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=\ngithub.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=\ngithub.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=\ngithub.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=\ngithub.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=\ngithub.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=\ngithub.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=\ngithub.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=\ngithub.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=\ngithub.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=\ngithub.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=\ngo.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=\ngo.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=\ngo.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=\ngo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8=\ngo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw=\ngo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk=\ngo.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=\ngo.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=\ngo.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=\ngo.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=\ngo.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=\ngo.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=\ngo.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=\ngo.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=\ngo.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=\ngo.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=\ngo.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=\ngo.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=\ngo.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=\ngo.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=\ngo.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=\ngo.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=\ngolang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=\ngolang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=\ngolang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=\ngolang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=\ngolang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=\ngolang.org/x/crypto/x509roots/fallback v0.0.0-20260113154411-7d0074ccc6f1 h1:EBHQuS9qI8xJ96+YRgVV2ahFLUYbWpt1rf3wPfXN2wQ=\ngolang.org/x/crypto/x509roots/fallback v0.0.0-20260113154411-7d0074ccc6f1/go.mod h1:MEIPiCnxvQEjA4astfaKItNwEVZA5Ki+3+nyGbJ5N18=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=\ngolang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=\ngolang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=\ngolang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=\ngolang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=\ngolang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=\ngolang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=\ngolang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=\ngolang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=\ngolang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=\ngolang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngolang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=\ngolang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=\ngolang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=\ngolang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=\ngolang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=\ngolang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=\ngolang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=\ngolang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=\ngolang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=\ngolang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=\ngolang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=\ngolang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=\ngonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE=\ngoogle.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0=\ngoogle.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=\ngoogle.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=\ngoogle.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=\ngoogle.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=\ngopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=\ngopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/guregu/null.v3 v3.3.0 h1:8j3ggqq+NgKt/O7mbFVUFKUMWN+l1AmT5jQmJ6nPh2c=\ngopkg.in/guregu/null.v3 v3.3.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\ngopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY=\ngopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\n"
  },
  {
    "path": "internal/api/server.go",
    "content": "// Package api contains the REST API implementation for k6.\n// It also registers the services endpoints like pprof\npackage api\n\nimport (\n\t\"context\"\n\t\"expvar\"\n\t\"fmt\"\n\t\"net/http\"\n\t_ \"net/http/pprof\" //nolint:gosec // Register pprof handlers\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus/promhttp\"\n\t\"github.com/sirupsen/logrus\"\n\n\tv1 \"go.k6.io/k6/api/v1\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/metrics/engine\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc newHandler(cs *v1.ControlSurface, profilingEnabled bool) http.Handler {\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/v1/\", v1.NewHandler(cs))\n\tmux.Handle(\"/ping\", handlePing(cs.RunState.Logger))\n\tmux.Handle(\"/\", handlePing(cs.RunState.Logger))\n\n\tinjectProfilerHandler(mux, profilingEnabled)\n\n\treturn mux\n}\n\nfunc injectProfilerHandler(mux *http.ServeMux, profilingEnabled bool) {\n\tvar handler http.Handler\n\n\thandler = http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {\n\t\trw.Header().Add(\"Content-Type\", \"text/plain; charset=utf-8\")\n\t\t_, _ = rw.Write([]byte(\"To enable profiling, please run k6 with the --profiling-enabled flag\"))\n\t})\n\n\tif profilingEnabled {\n\t\thandler = http.DefaultServeMux\n\t}\n\n\tmux.Handle(\"/debug/pprof/\", handler)\n\tmux.Handle(\"/debug/vars/\", expvar.Handler())\n\tmux.Handle(\"/metrics\", promhttp.Handler())\n}\n\n// GetServer returns a http.Server instance that can serve k6's REST API.\nfunc GetServer(\n\trunCtx context.Context,\n\taddr string,\n\tprofilingEnabled bool,\n\trunState *lib.TestRunState,\n\tsamples chan metrics.SampleContainer,\n\tme *engine.MetricsEngine,\n\tes *execution.Scheduler,\n) *http.Server {\n\t// TODO: reduce the control surface as much as possible? For example, if\n\t// we refactor the Runner API, we won't need to send the Samples channel.\n\tcs := &v1.ControlSurface{\n\t\tRunCtx:        runCtx,\n\t\tSamples:       samples,\n\t\tMetricsEngine: me,\n\t\tScheduler:     es,\n\t\tRunState:      runState,\n\t}\n\n\tmux := withLoggingHandler(runState.Logger, newHandler(cs, profilingEnabled))\n\treturn &http.Server{Addr: addr, Handler: mux, ReadHeaderTimeout: 10 * time.Second}\n}\n\ntype wrappedResponseWriter struct {\n\thttp.ResponseWriter\n\tstatus int\n}\n\nfunc (w *wrappedResponseWriter) WriteHeader(status int) {\n\tw.status = status\n\tw.ResponseWriter.WriteHeader(w.status)\n}\n\n// withLoggingHandler returns the middleware which logs response status for request.\nfunc withLoggingHandler(l logrus.FieldLogger, next http.Handler) http.HandlerFunc {\n\treturn func(rw http.ResponseWriter, r *http.Request) {\n\t\twrapped := &wrappedResponseWriter{ResponseWriter: rw, status: 200} // The default status code is 200 if it's not set\n\t\tnext.ServeHTTP(wrapped, r)\n\n\t\tl.WithField(\"status\", wrapped.status).Debugf(\"%s %s\", r.Method, r.URL.Path)\n\t}\n}\n\nfunc handlePing(logger logrus.FieldLogger) http.Handler {\n\treturn http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {\n\t\trw.Header().Add(\"Content-Type\", \"text/plain; charset=utf-8\")\n\t\tif _, err := fmt.Fprint(rw, \"ok\"); err != nil {\n\t\t\tlogger.WithError(err).Error(\"Error while printing ok\")\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/api/server_test.go",
    "content": "package api\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\tlogtest \"github.com/sirupsen/logrus/hooks/test\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n)\n\nfunc testHTTPHandler(rw http.ResponseWriter, _ *http.Request) {\n\trw.Header().Add(\"Content-Type\", \"text/plain; charset=utf-8\")\n\tif _, err := fmt.Fprint(rw, \"ok\"); err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n\nfunc TestLogger(t *testing.T) {\n\tt.Parallel()\n\tfor _, method := range []string{\"GET\", \"POST\", \"PUT\", \"PATCH\"} {\n\t\tt.Run(\"method=\"+method, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor _, path := range []string{\"/\", \"/test\", \"/test/path\"} {\n\t\t\t\tt.Run(\"path=\"+path, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\trw := httptest.NewRecorder()\n\t\t\t\t\tr := httptest.NewRequest(method, \"http://example.com\"+path, nil)\n\n\t\t\t\t\tl, hook := logtest.NewNullLogger()\n\t\t\t\t\tl.Level = logrus.DebugLevel\n\t\t\t\t\twithLoggingHandler(l, http.HandlerFunc(testHTTPHandler))(rw, r)\n\n\t\t\t\t\tres := rw.Result()\n\t\t\t\t\tassert.Equal(t, http.StatusOK, res.StatusCode)\n\t\t\t\t\tassert.Equal(t, \"text/plain; charset=utf-8\", res.Header.Get(\"Content-Type\"))\n\t\t\t\t\tassert.NoError(t, res.Body.Close())\n\n\t\t\t\t\tif !assert.Len(t, hook.Entries, 1) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\te := hook.LastEntry()\n\t\t\t\t\tassert.Equal(t, logrus.DebugLevel, e.Level)\n\t\t\t\t\tassert.Equal(t, fmt.Sprintf(\"%s %s\", method, path), e.Message)\n\t\t\t\t\tassert.Equal(t, http.StatusOK, e.Data[\"status\"])\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPing(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tmux := handlePing(logger)\n\n\trw := httptest.NewRecorder()\n\tr := httptest.NewRequest(http.MethodGet, \"/ping\", nil)\n\tmux.ServeHTTP(rw, r)\n\n\tres := rw.Result()\n\tassert.Equal(t, http.StatusOK, res.StatusCode)\n\tassert.Equal(t, []byte{'o', 'k'}, rw.Body.Bytes())\n\tassert.NoError(t, res.Body.Close())\n}\n"
  },
  {
    "path": "internal/build/version.go",
    "content": "// Package build handles information and processes about the k6 binary's build.\npackage build\n\n// Version contains the current version of k6\n// represented using Semantic Versioning expression.\nconst Version = \"1.6.1\"\n"
  },
  {
    "path": "internal/cloudapi/insights/client.go",
    "content": "package insights\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tgrpcRetry \"github.com/grpc-ecosystem/go-grpc-middleware/retry\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights/proto/v1/ingester\"\n)\n\nconst (\n\ttestRunIDHeader     = \"X-K6TestRun-Id\"\n\tauthorizationHeader = \"Authorization\"\n)\n\nvar (\n\t// ErrClientAlreadyInitialized is returned when the client is already initialized.\n\tErrClientAlreadyInitialized = errors.New(\"insights client already initialized\")\n\n\t// ErrClientClosed is returned when the client is closed.\n\tErrClientClosed = errors.New(\"insights client closed\")\n)\n\n// ClientConfig is the configuration for the client.\ntype ClientConfig struct {\n\tIngesterHost  string\n\tTimeout       time.Duration\n\tConnectConfig ClientConnectConfig\n\tAuthConfig    ClientAuthConfig\n\tTLSConfig     ClientTLSConfig\n\tRetryConfig   ClientRetryConfig\n}\n\n// ClientConnectConfig is the configuration for the client connection.\ntype ClientConnectConfig struct {\n\tBlock                  bool\n\tFailOnNonTempDialError bool\n\tTimeout                time.Duration\n\tDialer                 func(context.Context, string) (net.Conn, error)\n}\n\n// ClientAuthConfig is the configuration for the client authentication.\ntype ClientAuthConfig struct {\n\tEnabled                  bool\n\tTestRunID                int64\n\tToken                    string\n\tRequireTransportSecurity bool\n}\n\n// ClientTLSConfig is the configuration for the client TLS.\ntype ClientTLSConfig struct {\n\tInsecure bool\n\tCertFile string\n}\n\n// ClientRetryConfig is the configuration for the client retries.\ntype ClientRetryConfig struct {\n\tRetryableStatusCodes string\n\tMaxAttempts          uint\n\tPerRetryTimeout      time.Duration\n\tBackoffConfig        ClientBackoffConfig\n}\n\n// ClientBackoffConfig is the configuration for the client retries using the backoff exponential with jitter algorithm.\ntype ClientBackoffConfig struct {\n\tEnabled        bool\n\tJitterFraction float64\n\tWaitBetween    time.Duration\n}\n\n// Client is the client for the k6 Insights ingester service.\ntype Client struct {\n\tcfg    ClientConfig\n\tclient ingester.IngesterServiceClient\n\tconn   *grpc.ClientConn\n\tconnMu *sync.RWMutex\n}\n\n// NewDefaultClientConfigForTestRun creates a new default client config for a test run.\nfunc NewDefaultClientConfigForTestRun(ingesterHost, authToken string, testRunID int64) ClientConfig {\n\treturn ClientConfig{\n\t\tIngesterHost: ingesterHost,\n\t\tTimeout:      90 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{\n\t\t\tBlock:                  false,\n\t\t\tFailOnNonTempDialError: false,\n\t\t\tTimeout:                10 * time.Second,\n\t\t\tDialer:                 nil,\n\t\t},\n\t\tAuthConfig: ClientAuthConfig{\n\t\t\tEnabled:                  true,\n\t\t\tTestRunID:                testRunID,\n\t\t\tToken:                    authToken,\n\t\t\tRequireTransportSecurity: true,\n\t\t},\n\t\tTLSConfig: ClientTLSConfig{\n\t\t\tInsecure: false,\n\t\t},\n\t\tRetryConfig: ClientRetryConfig{\n\t\t\tRetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`,\n\t\t\tMaxAttempts:          3,\n\t\t\tPerRetryTimeout:      30 * time.Second,\n\t\t\tBackoffConfig: ClientBackoffConfig{\n\t\t\t\tEnabled:        true,\n\t\t\t\tJitterFraction: 0.1,\n\t\t\t\tWaitBetween:    1 * time.Second,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// NewClient creates a new client.\nfunc NewClient(cfg ClientConfig) *Client {\n\treturn &Client{\n\t\tcfg:    cfg,\n\t\tclient: nil,\n\t\tconn:   nil,\n\t\tconnMu: &sync.RWMutex{},\n\t}\n}\n\n// Dial creates a client connection using ClientConfig.\nfunc (c *Client) Dial(ctx context.Context) error {\n\tc.connMu.Lock()\n\tdefer c.connMu.Unlock()\n\n\tif c.conn != nil {\n\t\treturn ErrClientAlreadyInitialized\n\t}\n\n\topts, err := dialOptionsFromClientConfig(c.cfg)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create dial options: %w\", err)\n\t}\n\n\tctx, cancel := context.WithTimeout(ctx, c.cfg.ConnectConfig.Timeout)\n\tdefer cancel()\n\n\tconn, err := grpc.DialContext(ctx, c.cfg.IngesterHost, opts...) //nolint:staticcheck\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to dial: %w\", err)\n\t}\n\n\tc.client = ingester.NewIngesterServiceClient(conn)\n\tc.conn = conn\n\n\treturn nil\n}\n\n// IngestRequestMetadatasBatch ingests a batch of request metadatas.\nfunc (c *Client) IngestRequestMetadatasBatch(ctx context.Context, requestMetadatas RequestMetadatas) error {\n\tc.connMu.RLock()\n\tclosed := c.conn == nil\n\tc.connMu.RUnlock()\n\tif closed {\n\t\treturn ErrClientClosed\n\t}\n\n\tif len(requestMetadatas) < 1 {\n\t\treturn nil\n\t}\n\n\treq, err := newBatchCreateRequestMetadatasRequest(requestMetadatas)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create request from request metadatas: %w\", err)\n\t}\n\n\tctx, cancel := context.WithTimeout(ctx, c.cfg.Timeout)\n\tdefer cancel()\n\t_, err = c.client.BatchCreateRequestMetadatas(ctx, req)\n\tif err != nil {\n\t\tst := status.Convert(err)\n\t\treturn fmt.Errorf(\"failed to ingest request metadatas batch: code=%s, msg=%s\", st.Code().String(), st.Message())\n\t}\n\n\treturn nil\n}\n\n// Close closes the client.\nfunc (c *Client) Close() error {\n\tc.connMu.Lock()\n\tdefer c.connMu.Unlock()\n\n\tif c.conn == nil {\n\t\treturn ErrClientClosed\n\t}\n\n\tconn := c.conn\n\tc.client = nil\n\tc.conn = nil\n\n\treturn conn.Close()\n}\n\nfunc dialOptionsFromClientConfig(cfg ClientConfig) ([]grpc.DialOption, error) {\n\tvar opts []grpc.DialOption\n\n\tif cfg.ConnectConfig.Block {\n\t\topts = append(opts, grpc.WithBlock()) //nolint:staticcheck\n\t}\n\n\tif cfg.ConnectConfig.FailOnNonTempDialError {\n\t\topts = append(opts, grpc.FailOnNonTempDialError(true)) //nolint:staticcheck\n\t}\n\n\tif cfg.ConnectConfig.Dialer != nil {\n\t\topts = append(opts, grpc.WithContextDialer(cfg.ConnectConfig.Dialer))\n\t}\n\n\tif cfg.TLSConfig.Insecure { //nolint: nestif\n\t\topts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))\n\t} else {\n\t\tif cfg.TLSConfig.CertFile != \"\" {\n\t\t\tcreds, err := credentials.NewClientTLSFromFile(cfg.TLSConfig.CertFile, \"\")\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to load TLS credentials from file: %w\", err)\n\t\t\t}\n\t\t\topts = append(opts, grpc.WithTransportCredentials(creds))\n\t\t} else {\n\t\t\topts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS13})))\n\t\t}\n\t}\n\n\tif cfg.AuthConfig.Enabled {\n\t\topts = append(opts, grpc.WithPerRPCCredentials(newPerRPCCredentials(cfg.AuthConfig)))\n\t}\n\n\trI, err := retryInterceptor(cfg.RetryConfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create retry interceptors: %w\", err)\n\t}\n\n\topts = append(opts, grpc.WithChainUnaryInterceptor([]grpc.UnaryClientInterceptor{rI}...))\n\n\treturn opts, nil\n}\n\nfunc retryInterceptor(retryConfig ClientRetryConfig) (grpc.UnaryClientInterceptor, error) {\n\trSC, err := retryableStatusCodes(retryConfig.RetryableStatusCodes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse retryable status codes: %w\", err)\n\t}\n\twithCodes := grpcRetry.WithCodes(rSC...)\n\twithMax := grpcRetry.WithMax(retryConfig.MaxAttempts)\n\twithPerRetryTimeout := grpcRetry.WithPerRetryTimeout(retryConfig.PerRetryTimeout)\n\tcallOptions := []grpcRetry.CallOption{withCodes, withMax, withPerRetryTimeout}\n\n\tbackoffConfig := retryConfig.BackoffConfig\n\tif backoffConfig.Enabled {\n\t\tbackoff := grpcRetry.WithBackoff(\n\t\t\tgrpcRetry.BackoffExponentialWithJitter(backoffConfig.WaitBetween, backoffConfig.JitterFraction))\n\t\tcallOptions = append(callOptions, backoff)\n\t}\n\n\tunaryInterceptor := grpcRetry.UnaryClientInterceptor(callOptions...)\n\treturn unaryInterceptor, nil\n}\n\nfunc retryableStatusCodes(retryableStatusCodes string) ([]codes.Code, error) {\n\tif len(retryableStatusCodes) == 0 {\n\t\treturn nil, fmt.Errorf(\"no retryable status codes provided\")\n\t}\n\n\tstatusCodes := strings.Split(retryableStatusCodes, \",\")\n\terrorCodes := make([]codes.Code, len(statusCodes))\n\tfor i, code := range statusCodes {\n\t\terr := errorCodes[i].UnmarshalJSON([]byte(code))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid status code %s provided\", code)\n\t\t}\n\t}\n\n\treturn errorCodes, nil\n}\n\ntype perRPCCredentials struct {\n\tmetadata                 map[string]string\n\trequireTransportSecurity bool\n}\n\nfunc newPerRPCCredentials(cfg ClientAuthConfig) perRPCCredentials {\n\treturn perRPCCredentials{\n\t\tmetadata: map[string]string{\n\t\t\ttestRunIDHeader:     fmt.Sprintf(\"%d\", cfg.TestRunID),\n\t\t\tauthorizationHeader: fmt.Sprintf(\"Token %s\", cfg.Token),\n\t\t},\n\t\trequireTransportSecurity: cfg.RequireTransportSecurity,\n\t}\n}\n\nfunc (c perRPCCredentials) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {\n\treturn c.metadata, nil\n}\n\nfunc (c perRPCCredentials) RequireTransportSecurity() bool {\n\treturn c.requireTransportSecurity\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/client_test.go",
    "content": "package insights\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/grpc/test/bufconn\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights/proto/v1/ingester\"\n)\n\nfunc newMockListener(t *testing.T, ingesterServer ingester.IngesterServiceServer) *bufconn.Listener {\n\tt.Helper()\n\n\tconst size = 1024 * 1024\n\tl := bufconn.Listen(size)\n\tt.Cleanup(func() { _ = l.Close() })\n\n\ts := grpc.NewServer()\n\tingester.RegisterIngesterServiceServer(s, ingesterServer)\n\tgo func() { _ = s.Serve(l) }()\n\tt.Cleanup(func() { s.GracefulStop() })\n\n\treturn l\n}\n\nfunc newMockContextDialer(t *testing.T, l *bufconn.Listener) func(context.Context, string) (net.Conn, error) {\n\tt.Helper()\n\n\treturn func(ctx context.Context, _ string) (net.Conn, error) {\n\t\treturn l.DialContext(ctx)\n\t}\n}\n\ntype mockWorkingIngesterServer struct {\n\tingester.UnimplementedIngesterServiceServer\n\tbatchCreateRequestMetadatasInvoked bool\n\tdataUploaded                       bool\n\tmaxAttemptsTillSuccess             uint\n\tattempts                           uint\n}\n\nfunc (s *mockWorkingIngesterServer) BatchCreateRequestMetadatas(ctx context.Context, _ *ingester.BatchCreateRequestMetadatasRequest) (*ingester.BatchCreateRequestMetadatasResponse, error) {\n\ts.batchCreateRequestMetadatasInvoked = true\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn nil, ctx.Err()\n\tdefault:\n\t}\n\n\ts.dataUploaded = true\n\n\tif s.attempts >= s.maxAttemptsTillSuccess {\n\t\treturn &ingester.BatchCreateRequestMetadatasResponse{\n\t\t\tRequestMetadatas: nil,\n\t\t}, nil\n\t}\n\n\ts.attempts++\n\n\treturn nil, status.Error(codes.Unavailable, \"unavailable\")\n}\n\ntype mockFailingIngesterServer struct {\n\tingester.UnimplementedIngesterServiceServer\n\terr error\n}\n\nfunc (m *mockFailingIngesterServer) BatchCreateRequestMetadatas(_ context.Context, _ *ingester.BatchCreateRequestMetadatasRequest) (*ingester.BatchCreateRequestMetadatasResponse, error) {\n\treturn nil, m.err\n}\n\ntype fatalError struct{}\n\nfunc (*fatalError) Error() string   { return \"context dialer error\" }\nfunc (*fatalError) Temporary() bool { return false }\n\nfunc TestClient_Dial_ReturnsNoErrorWithWorkingDialer(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\n\t// When\n\terr := cli.Dial(context.Background())\n\n\t// Then\n\trequire.NoError(t, err)\n}\n\nfunc TestClient_Dial_ReturnsErrorWhenCalledTwice(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\n\t// When\n\tnoErr := cli.Dial(context.Background())\n\terr := cli.Dial(context.Background())\n\n\t// Then\n\trequire.NoError(t, noErr)\n\trequire.ErrorIs(t, err, ErrClientAlreadyInitialized)\n}\n\nfunc TestClient_Dial_ReturnsNoErrorWithFailingDialer(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tcfg := ClientConfig{\n\t\tConnectConfig: ClientConnectConfig{\n\t\t\tBlock:                  true,\n\t\t\tFailOnNonTempDialError: true,\n\t\t\tTimeout:                1 * time.Second,\n\t\t\tDialer: func(_ context.Context, _ string) (net.Conn, error) {\n\t\t\t\treturn nil, &fatalError{}\n\t\t\t},\n\t\t},\n\t\tTLSConfig:   ClientTLSConfig{Insecure: true},\n\t\tRetryConfig: ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\n\t// When\n\terr := cli.Dial(context.Background())\n\n\t// Then\n\tvar fatalErr *fatalError\n\trequire.ErrorAs(t, err, &fatalErr)\n}\n\nfunc TestClient_Dial_ReturnsErrorWithoutRetryableStatusCodes(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t}\n\tcli := NewClient(cfg)\n\n\t// When\n\terr := cli.Dial(context.Background())\n\n\t// Then\n\trequire.Error(t, err)\n}\n\nfunc TestClient_Dial_ReturnsErrorWithInvalidRetryableStatusCodes(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: \"RANDOM,INTERNAL\"},\n\t}\n\tcli := NewClient(cfg)\n\n\t// When\n\terr := cli.Dial(context.Background())\n\n\t// Then\n\trequire.Error(t, err)\n}\n\nfunc TestClient_IngestRequestMetadatasBatch_ReturnsNoErrorWithWorkingServerAndNonCancelledContextAndNoData(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\n\t// When\n\terr := cli.IngestRequestMetadatasBatch(context.Background(), nil)\n\n\t// Then\n\trequire.NoError(t, err)\n\trequire.False(t, ser.batchCreateRequestMetadatasInvoked)\n\trequire.False(t, ser.dataUploaded)\n}\n\nfunc TestClient_IngestRequestMetadatasBatch_ReturnsNoErrorWithWorkingServerAndNonCancelledContextAndData(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\tdata := RequestMetadatas{\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-2\",\n\t\t\tStart:          time.Unix(19, 0),\n\t\t\tEnd:            time.Unix(20, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-2\", Group: \"test-group-2\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-2\", Method: \"test-method-2\", StatusCode: 401},\n\t\t},\n\t}\n\n\t// When\n\terr := cli.IngestRequestMetadatasBatch(context.Background(), data)\n\n\t// Then\n\trequire.NoError(t, err)\n\trequire.True(t, ser.batchCreateRequestMetadatasInvoked)\n\trequire.True(t, ser.dataUploaded)\n}\n\nfunc TestClient_IngestRequestMetadatasBatch_ReturnsErrorWithWorkingServerAndCancelledContext(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\tctx, cancel := context.WithCancel(context.Background())\n\tcancel()\n\tdata := RequestMetadatas{\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t}\n\n\t// When\n\terr := cli.IngestRequestMetadatasBatch(ctx, data)\n\n\t// Then\n\trequire.Error(t, err)\n\trequire.False(t, ser.batchCreateRequestMetadatasInvoked)\n\trequire.False(t, ser.dataUploaded)\n}\n\nfunc TestClient_IngestRequestMetadatasBatch_ReturnsErrorWithUninitializedClient(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t}\n\tcli := NewClient(cfg)\n\tdata := RequestMetadatas{\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t}\n\n\t// When\n\terr := cli.IngestRequestMetadatasBatch(context.Background(), data)\n\n\t// Then\n\trequire.ErrorIs(t, err, ErrClientClosed)\n\trequire.False(t, ser.batchCreateRequestMetadatasInvoked)\n\trequire.False(t, ser.dataUploaded)\n}\n\nfunc TestClient_IngestRequestMetadatasBatch_ReturnsErrorWithFailingServerAndNonCancelledContext(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\ttestErr := errors.New(\"test error\")\n\tser := &mockFailingIngesterServer{err: testErr}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\tdata := RequestMetadatas{\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t}\n\n\t// When\n\terr := cli.IngestRequestMetadatasBatch(context.Background(), data)\n\n\t// Then\n\trequire.ErrorContains(t, err, testErr.Error())\n}\n\nfunc TestClient_IngestRequestMetadatasBatch_ReturnsNoErrorAfterRetrySeveralTimes(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{maxAttemptsTillSuccess: 10}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig: ClientRetryConfig{\n\t\t\tMaxAttempts:          20,\n\t\t\tRetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`,\n\t\t\tBackoffConfig: ClientBackoffConfig{\n\t\t\t\tEnabled:        true,\n\t\t\t\tJitterFraction: 0.1,\n\t\t\t},\n\t\t},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\tdata := RequestMetadatas{\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-2\",\n\t\t\tStart:          time.Unix(19, 0),\n\t\t\tEnd:            time.Unix(20, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-2\", Group: \"test-group-2\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-2\", Method: \"test-method-2\", StatusCode: 401},\n\t\t},\n\t}\n\n\t// When\n\terr := cli.IngestRequestMetadatasBatch(context.Background(), data)\n\n\t// Then\n\trequire.NoError(t, err)\n\trequire.True(t, ser.batchCreateRequestMetadatasInvoked)\n\trequire.True(t, ser.dataUploaded)\n\trequire.Equal(t, uint(10), ser.attempts)\n}\n\nfunc TestClient_IngestRequestMetadatasBatch_ReturnsErrorAfterExhaustingMaxRetryAttempts(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{maxAttemptsTillSuccess: 10}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tTimeout:       1 * time.Second,\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig: ClientRetryConfig{\n\t\t\tBackoffConfig: ClientBackoffConfig{\n\t\t\t\tEnabled:        true,\n\t\t\t\tJitterFraction: 0.1,\n\t\t\t},\n\t\t\tMaxAttempts:          5,\n\t\t\tRetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`,\n\t\t},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\tdata := RequestMetadatas{\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-2\",\n\t\t\tStart:          time.Unix(19, 0),\n\t\t\tEnd:            time.Unix(20, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-2\", Group: \"test-group-2\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-2\", Method: \"test-method-2\", StatusCode: 401},\n\t\t},\n\t}\n\n\t// When\n\terr := cli.IngestRequestMetadatasBatch(context.Background(), data)\n\n\t// Then\n\trequire.Error(t, err)\n\trequire.Equal(t, uint(5), ser.attempts)\n}\n\nfunc TestClient_Close_ReturnsNoErrorWhenClosedOnce(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\n\t// When\n\terr := cli.Close()\n\n\t// Then\n\trequire.NoError(t, err)\n}\n\nfunc TestClient_Close_ReturnsNoErrorWhenClosedTwice(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tser := &mockWorkingIngesterServer{}\n\tlis := newMockListener(t, ser)\n\n\tcfg := ClientConfig{\n\t\tConnectConfig: ClientConnectConfig{Timeout: 1 * time.Second, Dialer: newMockContextDialer(t, lis)},\n\t\tTLSConfig:     ClientTLSConfig{Insecure: true},\n\t\tRetryConfig:   ClientRetryConfig{RetryableStatusCodes: `\"UNKNOWN\",\"INTERNAL\",\"UNAVAILABLE\",\"DEADLINE_EXCEEDED\"`},\n\t}\n\tcli := NewClient(cfg)\n\trequire.NoError(t, cli.Dial(context.Background()))\n\n\t// When\n\tnoErr := cli.Close()\n\terr := cli.Close()\n\n\t// Then\n\trequire.NoError(t, noErr)\n\trequire.ErrorIs(t, err, ErrClientClosed)\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/doc.go",
    "content": "// Package insights contains the domain data structures and client logic\n// for the k6 cloud Insights API.\npackage insights\n"
  },
  {
    "path": "internal/cloudapi/insights/domain.go",
    "content": "package insights\n\nimport (\n\t\"time\"\n)\n\n// TestRunLabels describes labels associated with a single test run.\ntype TestRunLabels struct {\n\tID       int64\n\tScenario string\n\tGroup    string\n}\n\n// ProtocolLabels is a dummy interface that is used for compile-time type checking.\ntype ProtocolLabels interface {\n\tIsProtocolLabels()\n}\n\n// ProtocolHTTPLabels describes labels associated with a single HTTP request.\ntype ProtocolHTTPLabels struct {\n\tURL        string\n\tMethod     string\n\tStatusCode int64\n}\n\n// IsProtocolLabels is a dummy implementation to satisfy the ProtocolLabels interface.\nfunc (ProtocolHTTPLabels) IsProtocolLabels() {\n\t// Do nothing\n}\n\n// RequestMetadatas is a slice of RequestMetadata.\ntype RequestMetadatas []RequestMetadata\n\n// RequestMetadata describes metadata associated with a single *traced* request.\ntype RequestMetadata struct {\n\tTraceID        string\n\tStart          time.Time\n\tEnd            time.Time\n\tTestRunLabels  TestRunLabels\n\tProtocolLabels ProtocolLabels\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/mappers.go",
    "content": "package insights\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights/proto/v1/ingester\"\n\t\"go.k6.io/k6/internal/cloudapi/insights/proto/v1/k6\"\n)\n\nfunc newBatchCreateRequestMetadatasRequest(\n\trequestMetadatas RequestMetadatas,\n) (*ingester.BatchCreateRequestMetadatasRequest, error) {\n\treqs := make([]*ingester.CreateRequestMetadataRequest, 0, len(requestMetadatas))\n\tfor _, rm := range requestMetadatas {\n\t\treq, err := newCreateRequestMetadataRequest(rm)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create request metadata request: %w\", err)\n\t\t}\n\n\t\treqs = append(reqs, req)\n\t}\n\n\treturn &ingester.BatchCreateRequestMetadatasRequest{\n\t\tRequests: reqs,\n\t}, nil\n}\n\nfunc newCreateRequestMetadataRequest(requestMetadata RequestMetadata) (*ingester.CreateRequestMetadataRequest, error) {\n\trm := &k6.RequestMetadata{\n\t\tTraceID:           requestMetadata.TraceID,\n\t\tStartTimeUnixNano: requestMetadata.Start.UnixNano(),\n\t\tEndTimeUnixNano:   requestMetadata.End.UnixNano(),\n\t\tTestRunLabels: &k6.TestRunLabels{\n\t\t\tID:       requestMetadata.TestRunLabels.ID,\n\t\t\tScenario: requestMetadata.TestRunLabels.Scenario,\n\t\t\tGroup:    requestMetadata.TestRunLabels.Group,\n\t\t},\n\t\tProtocolLabels: nil,\n\t}\n\n\tif err := setProtocolLabels(rm, requestMetadata.ProtocolLabels); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to set protocol labels: %w\", err)\n\t}\n\n\treturn &ingester.CreateRequestMetadataRequest{\n\t\tRequestMetadata: rm,\n\t}, nil\n}\n\nfunc setProtocolLabels(rm *k6.RequestMetadata, labels ProtocolLabels) error {\n\t// TODO(lukasz, other-proto-support): Set other protocol labels.\n\tswitch l := labels.(type) {\n\tcase ProtocolHTTPLabels:\n\t\trm.ProtocolLabels = &k6.RequestMetadata_HTTPLabels{\n\t\t\tHTTPLabels: &k6.HTTPLabels{\n\t\t\t\tUrl:        l.URL,\n\t\t\t\tMethod:     l.Method,\n\t\t\t\tStatusCode: l.StatusCode,\n\t\t\t},\n\t\t}\n\tdefault:\n\t\treturn errors.New(\"unknown protocol labels type\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/mappers_test.go",
    "content": "package insights\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights/proto/v1/ingester\"\n\t\"go.k6.io/k6/internal/cloudapi/insights/proto/v1/k6\"\n)\n\nfunc Test_newBatchCreateRequestMetadatasRequest_CorrectlyMapsDomainTypeToProtoDefinition(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\trms := RequestMetadatas{\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t\t{\n\t\t\tTraceID:        \"test-trace-id-2\",\n\t\t\tStart:          time.Unix(19, 0),\n\t\t\tEnd:            time.Unix(20, 0),\n\t\t\tTestRunLabels:  TestRunLabels{ID: 1337, Scenario: \"test-scenario-2\", Group: \"test-group-2\"},\n\t\t\tProtocolLabels: ProtocolHTTPLabels{URL: \"test-url-2\", Method: \"test-method-2\", StatusCode: 401},\n\t\t},\n\t}\n\n\t// When\n\tgot, err := newBatchCreateRequestMetadatasRequest(rms)\n\n\t// Then\n\texpected := []*ingester.CreateRequestMetadataRequest{\n\t\t{\n\t\t\tRequestMetadata: &k6.RequestMetadata{\n\t\t\t\tTraceID:           \"test-trace-id-1\",\n\t\t\t\tStartTimeUnixNano: time.Unix(9, 0).UnixNano(),\n\t\t\t\tEndTimeUnixNano:   time.Unix(10, 0).UnixNano(),\n\t\t\t\tTestRunLabels:     &k6.TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\t\tProtocolLabels: &k6.RequestMetadata_HTTPLabels{\n\t\t\t\t\tHTTPLabels: &k6.HTTPLabels{\n\t\t\t\t\t\tUrl: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tRequestMetadata: &k6.RequestMetadata{\n\t\t\t\tTraceID:           \"test-trace-id-2\",\n\t\t\t\tStartTimeUnixNano: time.Unix(19, 0).UnixNano(),\n\t\t\t\tEndTimeUnixNano:   time.Unix(20, 0).UnixNano(),\n\t\t\t\tTestRunLabels:     &k6.TestRunLabels{ID: 1337, Scenario: \"test-scenario-2\", Group: \"test-group-2\"},\n\t\t\t\tProtocolLabels: &k6.RequestMetadata_HTTPLabels{\n\t\t\t\t\tHTTPLabels: &k6.HTTPLabels{\n\t\t\t\t\t\tUrl: \"test-url-2\", Method: \"test-method-2\", StatusCode: 401,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trequire.NoError(t, err)\n\trequire.Len(t, got.Requests, 2)\n\trequire.ElementsMatch(t, got.Requests, expected)\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/gen.go",
    "content": "// Package proto contains the Protobuf definitions used\n// by the k6 Insights.\npackage proto\n\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./v1/common/common.proto\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./v1/ingester/ingester.proto\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./v1/k6/labels.proto\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./v1/k6/request_metadata.proto\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./v1/trace/labels.proto\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./v1/trace/span.proto\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/common/common.pb.go",
    "content": "// Copyright 2019, OpenTelemetry Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Messages below are copied from https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/common/v1/common.proto\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: v1/common/common.proto\n\npackage common\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// AnyValue is used to represent any type of attribute value. AnyValue may contain a\n// primitive value such as a string or integer or it may contain an arbitrary nested\n// object containing arrays, key-value lists and primitives.\ntype AnyValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The value is one of the listed fields. It is valid for all values to be unspecified\n\t// in which case this AnyValue is considered to be \"empty\".\n\t//\n\t// Types that are assignable to Value:\n\t//\n\t//\t*AnyValue_StringValue\n\t//\t*AnyValue_BoolValue\n\t//\t*AnyValue_IntValue\n\t//\t*AnyValue_DoubleValue\n\t//\t*AnyValue_ArrayValue\n\t//\t*AnyValue_KvlistValue\n\t//\t*AnyValue_BytesValue\n\tValue isAnyValue_Value `protobuf_oneof:\"value\"`\n}\n\nfunc (x *AnyValue) Reset() {\n\t*x = AnyValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_common_common_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *AnyValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*AnyValue) ProtoMessage() {}\n\nfunc (x *AnyValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_common_common_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use AnyValue.ProtoReflect.Descriptor instead.\nfunc (*AnyValue) Descriptor() ([]byte, []int) {\n\treturn file_v1_common_common_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (m *AnyValue) GetValue() isAnyValue_Value {\n\tif m != nil {\n\t\treturn m.Value\n\t}\n\treturn nil\n}\n\nfunc (x *AnyValue) GetStringValue() string {\n\tif x, ok := x.GetValue().(*AnyValue_StringValue); ok {\n\t\treturn x.StringValue\n\t}\n\treturn \"\"\n}\n\nfunc (x *AnyValue) GetBoolValue() bool {\n\tif x, ok := x.GetValue().(*AnyValue_BoolValue); ok {\n\t\treturn x.BoolValue\n\t}\n\treturn false\n}\n\nfunc (x *AnyValue) GetIntValue() int64 {\n\tif x, ok := x.GetValue().(*AnyValue_IntValue); ok {\n\t\treturn x.IntValue\n\t}\n\treturn 0\n}\n\nfunc (x *AnyValue) GetDoubleValue() float64 {\n\tif x, ok := x.GetValue().(*AnyValue_DoubleValue); ok {\n\t\treturn x.DoubleValue\n\t}\n\treturn 0\n}\n\nfunc (x *AnyValue) GetArrayValue() *ArrayValue {\n\tif x, ok := x.GetValue().(*AnyValue_ArrayValue); ok {\n\t\treturn x.ArrayValue\n\t}\n\treturn nil\n}\n\nfunc (x *AnyValue) GetKvlistValue() *KeyValueList {\n\tif x, ok := x.GetValue().(*AnyValue_KvlistValue); ok {\n\t\treturn x.KvlistValue\n\t}\n\treturn nil\n}\n\nfunc (x *AnyValue) GetBytesValue() []byte {\n\tif x, ok := x.GetValue().(*AnyValue_BytesValue); ok {\n\t\treturn x.BytesValue\n\t}\n\treturn nil\n}\n\ntype isAnyValue_Value interface {\n\tisAnyValue_Value()\n}\n\ntype AnyValue_StringValue struct {\n\tStringValue string `protobuf:\"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof\"`\n}\n\ntype AnyValue_BoolValue struct {\n\tBoolValue bool `protobuf:\"varint,2,opt,name=bool_value,json=boolValue,proto3,oneof\"`\n}\n\ntype AnyValue_IntValue struct {\n\tIntValue int64 `protobuf:\"varint,3,opt,name=int_value,json=intValue,proto3,oneof\"`\n}\n\ntype AnyValue_DoubleValue struct {\n\tDoubleValue float64 `protobuf:\"fixed64,4,opt,name=double_value,json=doubleValue,proto3,oneof\"`\n}\n\ntype AnyValue_ArrayValue struct {\n\tArrayValue *ArrayValue `protobuf:\"bytes,5,opt,name=array_value,json=arrayValue,proto3,oneof\"`\n}\n\ntype AnyValue_KvlistValue struct {\n\tKvlistValue *KeyValueList `protobuf:\"bytes,6,opt,name=kvlist_value,json=kvlistValue,proto3,oneof\"`\n}\n\ntype AnyValue_BytesValue struct {\n\tBytesValue []byte `protobuf:\"bytes,7,opt,name=bytes_value,json=bytesValue,proto3,oneof\"`\n}\n\nfunc (*AnyValue_StringValue) isAnyValue_Value() {}\n\nfunc (*AnyValue_BoolValue) isAnyValue_Value() {}\n\nfunc (*AnyValue_IntValue) isAnyValue_Value() {}\n\nfunc (*AnyValue_DoubleValue) isAnyValue_Value() {}\n\nfunc (*AnyValue_ArrayValue) isAnyValue_Value() {}\n\nfunc (*AnyValue_KvlistValue) isAnyValue_Value() {}\n\nfunc (*AnyValue_BytesValue) isAnyValue_Value() {}\n\n// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message\n// since oneof in AnyValue does not allow repeated fields.\ntype ArrayValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Array of values. The array may be empty (contain 0 elements).\n\tValues []*AnyValue `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *ArrayValue) Reset() {\n\t*x = ArrayValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_common_common_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ArrayValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ArrayValue) ProtoMessage() {}\n\nfunc (x *ArrayValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_common_common_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ArrayValue.ProtoReflect.Descriptor instead.\nfunc (*ArrayValue) Descriptor() ([]byte, []int) {\n\treturn file_v1_common_common_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *ArrayValue) GetValues() []*AnyValue {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\n// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message\n// since `oneof` in AnyValue does not allow repeated fields. Everywhere else where we need\n// a list of KeyValue messages (e.g. in Span) we use `repeated KeyValue` directly to\n// avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches\n// are semantically equivalent.\ntype KeyValueList struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// A collection of key/value pairs of key-value pairs. The list may be empty (may\n\t// contain 0 elements).\n\t// The keys MUST be unique (it is not allowed to have more than one\n\t// value with the same key).\n\tValues []*KeyValue `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *KeyValueList) Reset() {\n\t*x = KeyValueList{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_common_common_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *KeyValueList) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KeyValueList) ProtoMessage() {}\n\nfunc (x *KeyValueList) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_common_common_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KeyValueList.ProtoReflect.Descriptor instead.\nfunc (*KeyValueList) Descriptor() ([]byte, []int) {\n\treturn file_v1_common_common_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *KeyValueList) GetValues() []*KeyValue {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\n// KeyValue is a key-value pair that is used to store Span attributes, Link\n// attributes, etc.\ntype KeyValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tKey   string    `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue *AnyValue `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *KeyValue) Reset() {\n\t*x = KeyValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_common_common_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *KeyValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*KeyValue) ProtoMessage() {}\n\nfunc (x *KeyValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_common_common_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use KeyValue.ProtoReflect.Descriptor instead.\nfunc (*KeyValue) Descriptor() ([]byte, []int) {\n\treturn file_v1_common_common_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *KeyValue) GetKey() string {\n\tif x != nil {\n\t\treturn x.Key\n\t}\n\treturn \"\"\n}\n\nfunc (x *KeyValue) GetValue() *AnyValue {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn nil\n}\n\nvar File_v1_common_common_proto protoreflect.FileDescriptor\n\nvar file_v1_common_common_proto_rawDesc = []byte{\n\t0x0a, 0x16, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f,\n\t0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x22, 0xe8, 0x02, 0x0a, 0x08,\n\t0x41, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69,\n\t0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,\n\t0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a,\n\t0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d,\n\t0x0a, 0x09, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,\n\t0x03, 0x48, 0x00, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a,\n\t0x0c, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20,\n\t0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c,\n\t0x75, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f,\n\t0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x72, 0x72, 0x61,\n\t0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x72, 0x72, 0x61, 0x79, 0x56,\n\t0x61, 0x6c, 0x75, 0x65, 0x12, 0x54, 0x0a, 0x0c, 0x6b, 0x76, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6b, 0x36, 0x2e,\n\t0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b,\n\t0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6b,\n\t0x76, 0x6c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x62, 0x79,\n\t0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48,\n\t0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x07, 0x0a,\n\t0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x51, 0x0a, 0x0a, 0x41, 0x72, 0x72, 0x61, 0x79, 0x56,\n\t0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,\n\t0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76,\n\t0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x41, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x75,\n\t0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x53, 0x0a, 0x0c, 0x4b, 0x65, 0x79,\n\t0x56, 0x61, 0x6c, 0x75, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x43, 0x0a, 0x06, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6b, 0x36, 0x2e, 0x63,\n\t0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65,\n\t0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x5f,\n\t0x0a, 0x08, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,\n\t0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6b, 0x36,\n\t0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,\n\t0x41, 0x6e, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42,\n\t0x38, 0x5a, 0x36, 0x67, 0x6f, 0x2e, 0x6b, 0x36, 0x2e, 0x69, 0x6f, 0x2f, 0x6b, 0x36, 0x2f, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x70, 0x69,\n\t0x2f, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,\n\t0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x33,\n}\n\nvar (\n\tfile_v1_common_common_proto_rawDescOnce sync.Once\n\tfile_v1_common_common_proto_rawDescData = file_v1_common_common_proto_rawDesc\n)\n\nfunc file_v1_common_common_proto_rawDescGZIP() []byte {\n\tfile_v1_common_common_proto_rawDescOnce.Do(func() {\n\t\tfile_v1_common_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_common_common_proto_rawDescData)\n\t})\n\treturn file_v1_common_common_proto_rawDescData\n}\n\nvar file_v1_common_common_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_v1_common_common_proto_goTypes = []interface{}{\n\t(*AnyValue)(nil),     // 0: k6.cloud.insights.proto.v1.common.AnyValue\n\t(*ArrayValue)(nil),   // 1: k6.cloud.insights.proto.v1.common.ArrayValue\n\t(*KeyValueList)(nil), // 2: k6.cloud.insights.proto.v1.common.KeyValueList\n\t(*KeyValue)(nil),     // 3: k6.cloud.insights.proto.v1.common.KeyValue\n}\nvar file_v1_common_common_proto_depIdxs = []int32{\n\t1, // 0: k6.cloud.insights.proto.v1.common.AnyValue.array_value:type_name -> k6.cloud.insights.proto.v1.common.ArrayValue\n\t2, // 1: k6.cloud.insights.proto.v1.common.AnyValue.kvlist_value:type_name -> k6.cloud.insights.proto.v1.common.KeyValueList\n\t0, // 2: k6.cloud.insights.proto.v1.common.ArrayValue.values:type_name -> k6.cloud.insights.proto.v1.common.AnyValue\n\t3, // 3: k6.cloud.insights.proto.v1.common.KeyValueList.values:type_name -> k6.cloud.insights.proto.v1.common.KeyValue\n\t0, // 4: k6.cloud.insights.proto.v1.common.KeyValue.value:type_name -> k6.cloud.insights.proto.v1.common.AnyValue\n\t5, // [5:5] is the sub-list for method output_type\n\t5, // [5:5] is the sub-list for method input_type\n\t5, // [5:5] is the sub-list for extension type_name\n\t5, // [5:5] is the sub-list for extension extendee\n\t0, // [0:5] is the sub-list for field type_name\n}\n\nfunc init() { file_v1_common_common_proto_init() }\nfunc file_v1_common_common_proto_init() {\n\tif File_v1_common_common_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_v1_common_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*AnyValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_common_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ArrayValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_common_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*KeyValueList); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_common_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*KeyValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_v1_common_common_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*AnyValue_StringValue)(nil),\n\t\t(*AnyValue_BoolValue)(nil),\n\t\t(*AnyValue_IntValue)(nil),\n\t\t(*AnyValue_DoubleValue)(nil),\n\t\t(*AnyValue_ArrayValue)(nil),\n\t\t(*AnyValue_KvlistValue)(nil),\n\t\t(*AnyValue_BytesValue)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_v1_common_common_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_v1_common_common_proto_goTypes,\n\t\tDependencyIndexes: file_v1_common_common_proto_depIdxs,\n\t\tMessageInfos:      file_v1_common_common_proto_msgTypes,\n\t}.Build()\n\tFile_v1_common_common_proto = out.File\n\tfile_v1_common_common_proto_rawDesc = nil\n\tfile_v1_common_common_proto_goTypes = nil\n\tfile_v1_common_common_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/common/common.proto",
    "content": "// Copyright 2019, OpenTelemetry Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Messages below are copied from https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/common/v1/common.proto\n\nsyntax = \"proto3\";\n\npackage k6.cloud.insights.proto.v1.common;\n\noption go_package = \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/common\";\n\n// AnyValue is used to represent any type of attribute value. AnyValue may contain a\n// primitive value such as a string or integer or it may contain an arbitrary nested\n// object containing arrays, key-value lists and primitives.\nmessage AnyValue {\n  // The value is one of the listed fields. It is valid for all values to be unspecified\n  // in which case this AnyValue is considered to be \"empty\".\n  oneof value {\n    string string_value = 1;\n    bool bool_value = 2;\n    int64 int_value = 3;\n    double double_value = 4;\n    ArrayValue array_value = 5;\n    KeyValueList kvlist_value = 6;\n    bytes bytes_value = 7;\n  }\n}\n\n// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message\n// since oneof in AnyValue does not allow repeated fields.\nmessage ArrayValue {\n  // Array of values. The array may be empty (contain 0 elements).\n  repeated AnyValue values = 1;\n}\n\n// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message\n// since `oneof` in AnyValue does not allow repeated fields. Everywhere else where we need\n// a list of KeyValue messages (e.g. in Span) we use `repeated KeyValue` directly to\n// avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches\n// are semantically equivalent.\nmessage KeyValueList {\n  // A collection of key/value pairs of key-value pairs. The list may be empty (may\n  // contain 0 elements).\n  // The keys MUST be unique (it is not allowed to have more than one\n  // value with the same key).\n  repeated KeyValue values = 1;\n}\n\n// KeyValue is a key-value pair that is used to store Span attributes, Link\n// attributes, etc.\nmessage KeyValue {\n  string key = 1;\n  AnyValue value = 2;\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/ingester/ingester.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: v1/ingester/ingester.proto\n\npackage ingester\n\nimport (\n\tk6 \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/k6\"\n\ttrace \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/trace\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype BatchCreateRequestMetadatasRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRequests []*CreateRequestMetadataRequest `protobuf:\"bytes,1,rep,name=Requests,proto3\" json:\"Requests,omitempty\"`\n}\n\nfunc (x *BatchCreateRequestMetadatasRequest) Reset() {\n\t*x = BatchCreateRequestMetadatasRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_ingester_ingester_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BatchCreateRequestMetadatasRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BatchCreateRequestMetadatasRequest) ProtoMessage() {}\n\nfunc (x *BatchCreateRequestMetadatasRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_ingester_ingester_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BatchCreateRequestMetadatasRequest.ProtoReflect.Descriptor instead.\nfunc (*BatchCreateRequestMetadatasRequest) Descriptor() ([]byte, []int) {\n\treturn file_v1_ingester_ingester_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *BatchCreateRequestMetadatasRequest) GetRequests() []*CreateRequestMetadataRequest {\n\tif x != nil {\n\t\treturn x.Requests\n\t}\n\treturn nil\n}\n\ntype CreateRequestMetadataRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRequestMetadata *k6.RequestMetadata `protobuf:\"bytes,1,opt,name=RequestMetadata,proto3\" json:\"RequestMetadata,omitempty\"`\n}\n\nfunc (x *CreateRequestMetadataRequest) Reset() {\n\t*x = CreateRequestMetadataRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_ingester_ingester_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateRequestMetadataRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateRequestMetadataRequest) ProtoMessage() {}\n\nfunc (x *CreateRequestMetadataRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_ingester_ingester_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateRequestMetadataRequest.ProtoReflect.Descriptor instead.\nfunc (*CreateRequestMetadataRequest) Descriptor() ([]byte, []int) {\n\treturn file_v1_ingester_ingester_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *CreateRequestMetadataRequest) GetRequestMetadata() *k6.RequestMetadata {\n\tif x != nil {\n\t\treturn x.RequestMetadata\n\t}\n\treturn nil\n}\n\ntype BatchCreateRequestMetadatasResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRequestMetadatas []*k6.RequestMetadata `protobuf:\"bytes,1,rep,name=RequestMetadatas,proto3\" json:\"RequestMetadatas,omitempty\"`\n}\n\nfunc (x *BatchCreateRequestMetadatasResponse) Reset() {\n\t*x = BatchCreateRequestMetadatasResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_ingester_ingester_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BatchCreateRequestMetadatasResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BatchCreateRequestMetadatasResponse) ProtoMessage() {}\n\nfunc (x *BatchCreateRequestMetadatasResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_ingester_ingester_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BatchCreateRequestMetadatasResponse.ProtoReflect.Descriptor instead.\nfunc (*BatchCreateRequestMetadatasResponse) Descriptor() ([]byte, []int) {\n\treturn file_v1_ingester_ingester_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *BatchCreateRequestMetadatasResponse) GetRequestMetadatas() []*k6.RequestMetadata {\n\tif x != nil {\n\t\treturn x.RequestMetadatas\n\t}\n\treturn nil\n}\n\ntype BatchCreateSpansRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tRequests []*CreateSpanRequest `protobuf:\"bytes,1,rep,name=Requests,proto3\" json:\"Requests,omitempty\"`\n}\n\nfunc (x *BatchCreateSpansRequest) Reset() {\n\t*x = BatchCreateSpansRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_ingester_ingester_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BatchCreateSpansRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BatchCreateSpansRequest) ProtoMessage() {}\n\nfunc (x *BatchCreateSpansRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_ingester_ingester_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BatchCreateSpansRequest.ProtoReflect.Descriptor instead.\nfunc (*BatchCreateSpansRequest) Descriptor() ([]byte, []int) {\n\treturn file_v1_ingester_ingester_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *BatchCreateSpansRequest) GetRequests() []*CreateSpanRequest {\n\tif x != nil {\n\t\treturn x.Requests\n\t}\n\treturn nil\n}\n\ntype CreateSpanRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSpan *trace.Span `protobuf:\"bytes,1,opt,name=Span,proto3\" json:\"Span,omitempty\"`\n}\n\nfunc (x *CreateSpanRequest) Reset() {\n\t*x = CreateSpanRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_ingester_ingester_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CreateSpanRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CreateSpanRequest) ProtoMessage() {}\n\nfunc (x *CreateSpanRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_ingester_ingester_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CreateSpanRequest.ProtoReflect.Descriptor instead.\nfunc (*CreateSpanRequest) Descriptor() ([]byte, []int) {\n\treturn file_v1_ingester_ingester_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *CreateSpanRequest) GetSpan() *trace.Span {\n\tif x != nil {\n\t\treturn x.Span\n\t}\n\treturn nil\n}\n\ntype BatchCreateSpansResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tSpans []*trace.Span `protobuf:\"bytes,1,rep,name=Spans,proto3\" json:\"Spans,omitempty\"`\n}\n\nfunc (x *BatchCreateSpansResponse) Reset() {\n\t*x = BatchCreateSpansResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_ingester_ingester_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BatchCreateSpansResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BatchCreateSpansResponse) ProtoMessage() {}\n\nfunc (x *BatchCreateSpansResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_ingester_ingester_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BatchCreateSpansResponse.ProtoReflect.Descriptor instead.\nfunc (*BatchCreateSpansResponse) Descriptor() ([]byte, []int) {\n\treturn file_v1_ingester_ingester_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *BatchCreateSpansResponse) GetSpans() []*trace.Span {\n\tif x != nil {\n\t\treturn x.Spans\n\t}\n\treturn nil\n}\n\nvar File_v1_ingester_ingester_proto protoreflect.FileDescriptor\n\nvar file_v1_ingester_ingester_proto_rawDesc = []byte{\n\t0x0a, 0x1a, 0x76, 0x31, 0x2f, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x69, 0x6e,\n\t0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x23, 0x6b, 0x36,\n\t0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65,\n\t0x72, 0x1a, 0x1c, 0x76, 0x31, 0x2f, 0x6b, 0x36, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a,\n\t0x13, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x22, 0x83, 0x01, 0x0a, 0x22, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72,\n\t0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64,\n\t0x61, 0x74, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x5d, 0x0a, 0x08, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e,\n\t0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74,\n\t0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73,\n\t0x74, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x52, 0x08, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x78, 0x0a, 0x1c, 0x43, 0x72,\n\t0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64,\n\t0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x58, 0x0a, 0x0f, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20,\n\t0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69,\n\t0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31,\n\t0x2e, 0x6b, 0x36, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64,\n\t0x61, 0x74, 0x61, 0x52, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61,\n\t0x64, 0x61, 0x74, 0x61, 0x22, 0x81, 0x01, 0x0a, 0x23, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72,\n\t0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64,\n\t0x61, 0x74, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x10,\n\t0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x73,\n\t0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75,\n\t0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x2e, 0x76, 0x31, 0x2e, 0x6b, 0x36, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65,\n\t0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x10, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,\n\t0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x73, 0x22, 0x6d, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63,\n\t0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x12, 0x52, 0x0a, 0x08, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18,\n\t0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64,\n\t0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,\n\t0x76, 0x31, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61,\n\t0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x08, 0x52,\n\t0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x4f, 0x0a, 0x11, 0x43, 0x72, 0x65, 0x61, 0x74,\n\t0x65, 0x53, 0x70, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x04,\n\t0x53, 0x70, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6b, 0x36, 0x2e,\n\t0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x70,\n\t0x61, 0x6e, 0x52, 0x04, 0x53, 0x70, 0x61, 0x6e, 0x22, 0x58, 0x0a, 0x18, 0x42, 0x61, 0x74, 0x63,\n\t0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x05, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69,\n\t0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31,\n\t0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x52, 0x05, 0x53, 0x70, 0x61,\n\t0x6e, 0x73, 0x32, 0xda, 0x02, 0x0a, 0x0f, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x53,\n\t0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xb2, 0x01, 0x0a, 0x1b, 0x42, 0x61, 0x74, 0x63, 0x68,\n\t0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74,\n\t0x61, 0x64, 0x61, 0x74, 0x61, 0x73, 0x12, 0x47, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75,\n\t0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x2e, 0x76, 0x31, 0x2e, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74,\n\t0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,\n\t0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,\n\t0x48, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67,\n\t0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x69, 0x6e, 0x67,\n\t0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74,\n\t0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,\n\t0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x91, 0x01, 0x0a, 0x10,\n\t0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73,\n\t0x12, 0x3c, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69,\n\t0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x69, 0x6e,\n\t0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61,\n\t0x74, 0x65, 0x53, 0x70, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d,\n\t0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68,\n\t0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x69, 0x6e, 0x67, 0x65,\n\t0x73, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,\n\t0x53, 0x70, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,\n\t0x3a, 0x5a, 0x38, 0x67, 0x6f, 0x2e, 0x6b, 0x36, 0x2e, 0x69, 0x6f, 0x2f, 0x6b, 0x36, 0x2f, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x70, 0x69,\n\t0x2f, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,\n\t0x76, 0x31, 0x2f, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_v1_ingester_ingester_proto_rawDescOnce sync.Once\n\tfile_v1_ingester_ingester_proto_rawDescData = file_v1_ingester_ingester_proto_rawDesc\n)\n\nfunc file_v1_ingester_ingester_proto_rawDescGZIP() []byte {\n\tfile_v1_ingester_ingester_proto_rawDescOnce.Do(func() {\n\t\tfile_v1_ingester_ingester_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_ingester_ingester_proto_rawDescData)\n\t})\n\treturn file_v1_ingester_ingester_proto_rawDescData\n}\n\nvar file_v1_ingester_ingester_proto_msgTypes = make([]protoimpl.MessageInfo, 6)\nvar file_v1_ingester_ingester_proto_goTypes = []interface{}{\n\t(*BatchCreateRequestMetadatasRequest)(nil),  // 0: k6.cloud.insights.proto.v1.ingester.BatchCreateRequestMetadatasRequest\n\t(*CreateRequestMetadataRequest)(nil),        // 1: k6.cloud.insights.proto.v1.ingester.CreateRequestMetadataRequest\n\t(*BatchCreateRequestMetadatasResponse)(nil), // 2: k6.cloud.insights.proto.v1.ingester.BatchCreateRequestMetadatasResponse\n\t(*BatchCreateSpansRequest)(nil),             // 3: k6.cloud.insights.proto.v1.ingester.BatchCreateSpansRequest\n\t(*CreateSpanRequest)(nil),                   // 4: k6.cloud.insights.proto.v1.ingester.CreateSpanRequest\n\t(*BatchCreateSpansResponse)(nil),            // 5: k6.cloud.insights.proto.v1.ingester.BatchCreateSpansResponse\n\t(*k6.RequestMetadata)(nil),                  // 6: k6.cloud.insights.proto.v1.k6.RequestMetadata\n\t(*trace.Span)(nil),                          // 7: k6.cloud.insights.proto.v1.trace.Span\n}\nvar file_v1_ingester_ingester_proto_depIdxs = []int32{\n\t1, // 0: k6.cloud.insights.proto.v1.ingester.BatchCreateRequestMetadatasRequest.Requests:type_name -> k6.cloud.insights.proto.v1.ingester.CreateRequestMetadataRequest\n\t6, // 1: k6.cloud.insights.proto.v1.ingester.CreateRequestMetadataRequest.RequestMetadata:type_name -> k6.cloud.insights.proto.v1.k6.RequestMetadata\n\t6, // 2: k6.cloud.insights.proto.v1.ingester.BatchCreateRequestMetadatasResponse.RequestMetadatas:type_name -> k6.cloud.insights.proto.v1.k6.RequestMetadata\n\t4, // 3: k6.cloud.insights.proto.v1.ingester.BatchCreateSpansRequest.Requests:type_name -> k6.cloud.insights.proto.v1.ingester.CreateSpanRequest\n\t7, // 4: k6.cloud.insights.proto.v1.ingester.CreateSpanRequest.Span:type_name -> k6.cloud.insights.proto.v1.trace.Span\n\t7, // 5: k6.cloud.insights.proto.v1.ingester.BatchCreateSpansResponse.Spans:type_name -> k6.cloud.insights.proto.v1.trace.Span\n\t0, // 6: k6.cloud.insights.proto.v1.ingester.IngesterService.BatchCreateRequestMetadatas:input_type -> k6.cloud.insights.proto.v1.ingester.BatchCreateRequestMetadatasRequest\n\t3, // 7: k6.cloud.insights.proto.v1.ingester.IngesterService.BatchCreateSpans:input_type -> k6.cloud.insights.proto.v1.ingester.BatchCreateSpansRequest\n\t2, // 8: k6.cloud.insights.proto.v1.ingester.IngesterService.BatchCreateRequestMetadatas:output_type -> k6.cloud.insights.proto.v1.ingester.BatchCreateRequestMetadatasResponse\n\t5, // 9: k6.cloud.insights.proto.v1.ingester.IngesterService.BatchCreateSpans:output_type -> k6.cloud.insights.proto.v1.ingester.BatchCreateSpansResponse\n\t8, // [8:10] is the sub-list for method output_type\n\t6, // [6:8] is the sub-list for method input_type\n\t6, // [6:6] is the sub-list for extension type_name\n\t6, // [6:6] is the sub-list for extension extendee\n\t0, // [0:6] is the sub-list for field type_name\n}\n\nfunc init() { file_v1_ingester_ingester_proto_init() }\nfunc file_v1_ingester_ingester_proto_init() {\n\tif File_v1_ingester_ingester_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_v1_ingester_ingester_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BatchCreateRequestMetadatasRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_ingester_ingester_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateRequestMetadataRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_ingester_ingester_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BatchCreateRequestMetadatasResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_ingester_ingester_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BatchCreateSpansRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_ingester_ingester_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CreateSpanRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_ingester_ingester_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BatchCreateSpansResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_v1_ingester_ingester_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   6,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_v1_ingester_ingester_proto_goTypes,\n\t\tDependencyIndexes: file_v1_ingester_ingester_proto_depIdxs,\n\t\tMessageInfos:      file_v1_ingester_ingester_proto_msgTypes,\n\t}.Build()\n\tFile_v1_ingester_ingester_proto = out.File\n\tfile_v1_ingester_ingester_proto_rawDesc = nil\n\tfile_v1_ingester_ingester_proto_goTypes = nil\n\tfile_v1_ingester_ingester_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/ingester/ingester.proto",
    "content": "syntax = \"proto3\";\n\npackage k6.cloud.insights.proto.v1.ingester;\n\noption go_package = \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/ingester\";\n\nimport \"v1/k6/request_metadata.proto\";\nimport \"v1/trace/span.proto\";\n\n// The IngesterService contains the methods to ingest Spans and Request Metadata,\n// which include information about a k6 load tests.\nservice IngesterService {\n  rpc BatchCreateRequestMetadatas(BatchCreateRequestMetadatasRequest) returns (BatchCreateRequestMetadatasResponse) {}\n  rpc BatchCreateSpans(BatchCreateSpansRequest) returns (BatchCreateSpansResponse) {}\n}\n\nmessage BatchCreateRequestMetadatasRequest {\n  repeated CreateRequestMetadataRequest Requests = 1;\n}\n\nmessage CreateRequestMetadataRequest {\n  k6.RequestMetadata RequestMetadata = 1;\n}\n\nmessage BatchCreateRequestMetadatasResponse {\n  repeated k6.RequestMetadata RequestMetadatas = 1;\n}\n\nmessage BatchCreateSpansRequest {\n  repeated CreateSpanRequest Requests = 1;\n}\n\nmessage CreateSpanRequest {\n  trace.Span Span = 1;\n}\n\nmessage BatchCreateSpansResponse {\n  repeated trace.Span Spans = 1;\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/ingester/ingester_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.3.0\n// - protoc             v3.21.12\n// source: v1/ingester/ingester.proto\n\npackage ingester\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.32.0 or later.\nconst _ = grpc.SupportPackageIsVersion7\n\nconst (\n\tIngesterService_BatchCreateRequestMetadatas_FullMethodName = \"/k6.cloud.insights.proto.v1.ingester.IngesterService/BatchCreateRequestMetadatas\"\n\tIngesterService_BatchCreateSpans_FullMethodName            = \"/k6.cloud.insights.proto.v1.ingester.IngesterService/BatchCreateSpans\"\n)\n\n// IngesterServiceClient is the client API for IngesterService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype IngesterServiceClient interface {\n\tBatchCreateRequestMetadatas(ctx context.Context, in *BatchCreateRequestMetadatasRequest, opts ...grpc.CallOption) (*BatchCreateRequestMetadatasResponse, error)\n\tBatchCreateSpans(ctx context.Context, in *BatchCreateSpansRequest, opts ...grpc.CallOption) (*BatchCreateSpansResponse, error)\n}\n\ntype ingesterServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewIngesterServiceClient(cc grpc.ClientConnInterface) IngesterServiceClient {\n\treturn &ingesterServiceClient{cc}\n}\n\nfunc (c *ingesterServiceClient) BatchCreateRequestMetadatas(ctx context.Context, in *BatchCreateRequestMetadatasRequest, opts ...grpc.CallOption) (*BatchCreateRequestMetadatasResponse, error) {\n\tout := new(BatchCreateRequestMetadatasResponse)\n\terr := c.cc.Invoke(ctx, IngesterService_BatchCreateRequestMetadatas_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *ingesterServiceClient) BatchCreateSpans(ctx context.Context, in *BatchCreateSpansRequest, opts ...grpc.CallOption) (*BatchCreateSpansResponse, error) {\n\tout := new(BatchCreateSpansResponse)\n\terr := c.cc.Invoke(ctx, IngesterService_BatchCreateSpans_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// IngesterServiceServer is the server API for IngesterService service.\n// All implementations must embed UnimplementedIngesterServiceServer\n// for forward compatibility\ntype IngesterServiceServer interface {\n\tBatchCreateRequestMetadatas(context.Context, *BatchCreateRequestMetadatasRequest) (*BatchCreateRequestMetadatasResponse, error)\n\tBatchCreateSpans(context.Context, *BatchCreateSpansRequest) (*BatchCreateSpansResponse, error)\n\tmustEmbedUnimplementedIngesterServiceServer()\n}\n\n// UnimplementedIngesterServiceServer must be embedded to have forward compatible implementations.\ntype UnimplementedIngesterServiceServer struct {\n}\n\nfunc (UnimplementedIngesterServiceServer) BatchCreateRequestMetadatas(context.Context, *BatchCreateRequestMetadatasRequest) (*BatchCreateRequestMetadatasResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method BatchCreateRequestMetadatas not implemented\")\n}\nfunc (UnimplementedIngesterServiceServer) BatchCreateSpans(context.Context, *BatchCreateSpansRequest) (*BatchCreateSpansResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method BatchCreateSpans not implemented\")\n}\nfunc (UnimplementedIngesterServiceServer) mustEmbedUnimplementedIngesterServiceServer() {}\n\n// UnsafeIngesterServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to IngesterServiceServer will\n// result in compilation errors.\ntype UnsafeIngesterServiceServer interface {\n\tmustEmbedUnimplementedIngesterServiceServer()\n}\n\nfunc RegisterIngesterServiceServer(s grpc.ServiceRegistrar, srv IngesterServiceServer) {\n\ts.RegisterService(&IngesterService_ServiceDesc, srv)\n}\n\nfunc _IngesterService_BatchCreateRequestMetadatas_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(BatchCreateRequestMetadatasRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(IngesterServiceServer).BatchCreateRequestMetadatas(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: IngesterService_BatchCreateRequestMetadatas_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(IngesterServiceServer).BatchCreateRequestMetadatas(ctx, req.(*BatchCreateRequestMetadatasRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _IngesterService_BatchCreateSpans_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(BatchCreateSpansRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(IngesterServiceServer).BatchCreateSpans(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: IngesterService_BatchCreateSpans_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(IngesterServiceServer).BatchCreateSpans(ctx, req.(*BatchCreateSpansRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\n// IngesterService_ServiceDesc is the grpc.ServiceDesc for IngesterService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar IngesterService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"k6.cloud.insights.proto.v1.ingester.IngesterService\",\n\tHandlerType: (*IngesterServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"BatchCreateRequestMetadatas\",\n\t\t\tHandler:    _IngesterService_BatchCreateRequestMetadatas_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"BatchCreateSpans\",\n\t\t\tHandler:    _IngesterService_BatchCreateSpans_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"v1/ingester/ingester.proto\",\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/k6/labels.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: v1/k6/labels.proto\n\npackage k6\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype TestRunLabels struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tID       int64  `protobuf:\"varint,1,opt,name=ID,proto3\" json:\"ID,omitempty\"`\n\tScenario string `protobuf:\"bytes,2,opt,name=Scenario,proto3\" json:\"Scenario,omitempty\"`\n\tGroup    string `protobuf:\"bytes,3,opt,name=Group,proto3\" json:\"Group,omitempty\"`\n}\n\nfunc (x *TestRunLabels) Reset() {\n\t*x = TestRunLabels{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_k6_labels_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TestRunLabels) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TestRunLabels) ProtoMessage() {}\n\nfunc (x *TestRunLabels) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_k6_labels_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TestRunLabels.ProtoReflect.Descriptor instead.\nfunc (*TestRunLabels) Descriptor() ([]byte, []int) {\n\treturn file_v1_k6_labels_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *TestRunLabels) GetID() int64 {\n\tif x != nil {\n\t\treturn x.ID\n\t}\n\treturn 0\n}\n\nfunc (x *TestRunLabels) GetScenario() string {\n\tif x != nil {\n\t\treturn x.Scenario\n\t}\n\treturn \"\"\n}\n\nfunc (x *TestRunLabels) GetGroup() string {\n\tif x != nil {\n\t\treturn x.Group\n\t}\n\treturn \"\"\n}\n\ntype HTTPLabels struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tUrl        string `protobuf:\"bytes,1,opt,name=Url,proto3\" json:\"Url,omitempty\"`\n\tMethod     string `protobuf:\"bytes,2,opt,name=Method,proto3\" json:\"Method,omitempty\"`\n\tStatusCode int64  `protobuf:\"varint,3,opt,name=StatusCode,proto3\" json:\"StatusCode,omitempty\"`\n}\n\nfunc (x *HTTPLabels) Reset() {\n\t*x = HTTPLabels{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_k6_labels_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *HTTPLabels) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*HTTPLabels) ProtoMessage() {}\n\nfunc (x *HTTPLabels) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_k6_labels_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use HTTPLabels.ProtoReflect.Descriptor instead.\nfunc (*HTTPLabels) Descriptor() ([]byte, []int) {\n\treturn file_v1_k6_labels_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *HTTPLabels) GetUrl() string {\n\tif x != nil {\n\t\treturn x.Url\n\t}\n\treturn \"\"\n}\n\nfunc (x *HTTPLabels) GetMethod() string {\n\tif x != nil {\n\t\treturn x.Method\n\t}\n\treturn \"\"\n}\n\nfunc (x *HTTPLabels) GetStatusCode() int64 {\n\tif x != nil {\n\t\treturn x.StatusCode\n\t}\n\treturn 0\n}\n\nvar File_v1_k6_labels_proto protoreflect.FileDescriptor\n\nvar file_v1_k6_labels_proto_rawDesc = []byte{\n\t0x0a, 0x12, 0x76, 0x31, 0x2f, 0x6b, 0x36, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69,\n\t0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31,\n\t0x2e, 0x6b, 0x36, 0x22, 0x51, 0x0a, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x52, 0x75, 0x6e, 0x4c, 0x61,\n\t0x62, 0x65, 0x6c, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,\n\t0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x63, 0x65, 0x6e, 0x61, 0x72, 0x69, 0x6f,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x53, 0x63, 0x65, 0x6e, 0x61, 0x72, 0x69, 0x6f,\n\t0x12, 0x14, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x56, 0x0a, 0x0a, 0x48, 0x54, 0x54, 0x50, 0x4c, 0x61,\n\t0x62, 0x65, 0x6c, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x09, 0x52, 0x03, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x1e,\n\t0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x34,\n\t0x5a, 0x32, 0x67, 0x6f, 0x2e, 0x6b, 0x36, 0x2e, 0x69, 0x6f, 0x2f, 0x6b, 0x36, 0x2f, 0x69, 0x6e,\n\t0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x70, 0x69, 0x2f,\n\t0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76,\n\t0x31, 0x2f, 0x6b, 0x36, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_v1_k6_labels_proto_rawDescOnce sync.Once\n\tfile_v1_k6_labels_proto_rawDescData = file_v1_k6_labels_proto_rawDesc\n)\n\nfunc file_v1_k6_labels_proto_rawDescGZIP() []byte {\n\tfile_v1_k6_labels_proto_rawDescOnce.Do(func() {\n\t\tfile_v1_k6_labels_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_k6_labels_proto_rawDescData)\n\t})\n\treturn file_v1_k6_labels_proto_rawDescData\n}\n\nvar file_v1_k6_labels_proto_msgTypes = make([]protoimpl.MessageInfo, 2)\nvar file_v1_k6_labels_proto_goTypes = []interface{}{\n\t(*TestRunLabels)(nil), // 0: k6.cloud.insights.proto.v1.k6.TestRunLabels\n\t(*HTTPLabels)(nil),    // 1: k6.cloud.insights.proto.v1.k6.HTTPLabels\n}\nvar file_v1_k6_labels_proto_depIdxs = []int32{\n\t0, // [0:0] is the sub-list for method output_type\n\t0, // [0:0] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_v1_k6_labels_proto_init() }\nfunc file_v1_k6_labels_proto_init() {\n\tif File_v1_k6_labels_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_v1_k6_labels_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TestRunLabels); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_v1_k6_labels_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*HTTPLabels); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_v1_k6_labels_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   2,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_v1_k6_labels_proto_goTypes,\n\t\tDependencyIndexes: file_v1_k6_labels_proto_depIdxs,\n\t\tMessageInfos:      file_v1_k6_labels_proto_msgTypes,\n\t}.Build()\n\tFile_v1_k6_labels_proto = out.File\n\tfile_v1_k6_labels_proto_rawDesc = nil\n\tfile_v1_k6_labels_proto_goTypes = nil\n\tfile_v1_k6_labels_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/k6/labels.proto",
    "content": "syntax = \"proto3\";\n\npackage k6.cloud.insights.proto.v1.k6;\n\noption go_package = \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/k6\";\n\nmessage TestRunLabels {\n  int64 ID = 1;\n  string Scenario = 2;\n  string Group = 3;\n}\n\nmessage HTTPLabels {\n  string Url = 1;\n  string Method = 2;\n  int64 StatusCode = 3;\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/k6/request_metadata.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: v1/k6/request_metadata.proto\n\npackage k6\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype RequestMetadata struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tTraceID           string         `protobuf:\"bytes,1,opt,name=TraceID,proto3\" json:\"TraceID,omitempty\"`\n\tStartTimeUnixNano int64          `protobuf:\"varint,2,opt,name=StartTimeUnixNano,proto3\" json:\"StartTimeUnixNano,omitempty\"`\n\tEndTimeUnixNano   int64          `protobuf:\"varint,3,opt,name=EndTimeUnixNano,proto3\" json:\"EndTimeUnixNano,omitempty\"`\n\tTestRunLabels     *TestRunLabels `protobuf:\"bytes,4,opt,name=TestRunLabels,proto3\" json:\"TestRunLabels,omitempty\"`\n\t// Types that are assignable to ProtocolLabels:\n\t//\n\t//\t*RequestMetadata_HTTPLabels\n\tProtocolLabels isRequestMetadata_ProtocolLabels `protobuf_oneof:\"ProtocolLabels\"`\n}\n\nfunc (x *RequestMetadata) Reset() {\n\t*x = RequestMetadata{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_k6_request_metadata_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RequestMetadata) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RequestMetadata) ProtoMessage() {}\n\nfunc (x *RequestMetadata) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_k6_request_metadata_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RequestMetadata.ProtoReflect.Descriptor instead.\nfunc (*RequestMetadata) Descriptor() ([]byte, []int) {\n\treturn file_v1_k6_request_metadata_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *RequestMetadata) GetTraceID() string {\n\tif x != nil {\n\t\treturn x.TraceID\n\t}\n\treturn \"\"\n}\n\nfunc (x *RequestMetadata) GetStartTimeUnixNano() int64 {\n\tif x != nil {\n\t\treturn x.StartTimeUnixNano\n\t}\n\treturn 0\n}\n\nfunc (x *RequestMetadata) GetEndTimeUnixNano() int64 {\n\tif x != nil {\n\t\treturn x.EndTimeUnixNano\n\t}\n\treturn 0\n}\n\nfunc (x *RequestMetadata) GetTestRunLabels() *TestRunLabels {\n\tif x != nil {\n\t\treturn x.TestRunLabels\n\t}\n\treturn nil\n}\n\nfunc (m *RequestMetadata) GetProtocolLabels() isRequestMetadata_ProtocolLabels {\n\tif m != nil {\n\t\treturn m.ProtocolLabels\n\t}\n\treturn nil\n}\n\nfunc (x *RequestMetadata) GetHTTPLabels() *HTTPLabels {\n\tif x, ok := x.GetProtocolLabels().(*RequestMetadata_HTTPLabels); ok {\n\t\treturn x.HTTPLabels\n\t}\n\treturn nil\n}\n\ntype isRequestMetadata_ProtocolLabels interface {\n\tisRequestMetadata_ProtocolLabels()\n}\n\ntype RequestMetadata_HTTPLabels struct {\n\tHTTPLabels *HTTPLabels `protobuf:\"bytes,5,opt,name=HTTPLabels,proto3,oneof\"`\n}\n\nfunc (*RequestMetadata_HTTPLabels) isRequestMetadata_ProtocolLabels() {}\n\nvar File_v1_k6_request_metadata_proto protoreflect.FileDescriptor\n\nvar file_v1_k6_request_metadata_proto_rawDesc = []byte{\n\t0x0a, 0x1c, 0x76, 0x31, 0x2f, 0x6b, 0x36, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f,\n\t0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d,\n\t0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74,\n\t0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x6b, 0x36, 0x1a, 0x12, 0x76,\n\t0x31, 0x2f, 0x6b, 0x36, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x22, 0xb6, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74,\n\t0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x54, 0x72, 0x61, 0x63, 0x65, 0x49, 0x44,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x54, 0x72, 0x61, 0x63, 0x65, 0x49, 0x44, 0x12,\n\t0x2c, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78,\n\t0x4e, 0x61, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x53, 0x74, 0x61, 0x72,\n\t0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x28, 0x0a,\n\t0x0f, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f,\n\t0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x55,\n\t0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x52, 0x0a, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x52,\n\t0x75, 0x6e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c,\n\t0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68,\n\t0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x6b, 0x36, 0x2e, 0x54,\n\t0x65, 0x73, 0x74, 0x52, 0x75, 0x6e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x0d, 0x54, 0x65,\n\t0x73, 0x74, 0x52, 0x75, 0x6e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x4b, 0x0a, 0x0a, 0x48,\n\t0x54, 0x54, 0x50, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x29, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67,\n\t0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x6b, 0x36, 0x2e,\n\t0x48, 0x54, 0x54, 0x50, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x48, 0x00, 0x52, 0x0a, 0x48, 0x54,\n\t0x54, 0x50, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x42, 0x10, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x74,\n\t0x6f, 0x63, 0x6f, 0x6c, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x6f,\n\t0x2e, 0x6b, 0x36, 0x2e, 0x69, 0x6f, 0x2f, 0x6b, 0x36, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,\n\t0x61, 0x6c, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x70, 0x69, 0x2f, 0x69, 0x6e, 0x73, 0x69,\n\t0x67, 0x68, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x2f, 0x6b, 0x36,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_v1_k6_request_metadata_proto_rawDescOnce sync.Once\n\tfile_v1_k6_request_metadata_proto_rawDescData = file_v1_k6_request_metadata_proto_rawDesc\n)\n\nfunc file_v1_k6_request_metadata_proto_rawDescGZIP() []byte {\n\tfile_v1_k6_request_metadata_proto_rawDescOnce.Do(func() {\n\t\tfile_v1_k6_request_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_k6_request_metadata_proto_rawDescData)\n\t})\n\treturn file_v1_k6_request_metadata_proto_rawDescData\n}\n\nvar file_v1_k6_request_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_v1_k6_request_metadata_proto_goTypes = []interface{}{\n\t(*RequestMetadata)(nil), // 0: k6.cloud.insights.proto.v1.k6.RequestMetadata\n\t(*TestRunLabels)(nil),   // 1: k6.cloud.insights.proto.v1.k6.TestRunLabels\n\t(*HTTPLabels)(nil),      // 2: k6.cloud.insights.proto.v1.k6.HTTPLabels\n}\nvar file_v1_k6_request_metadata_proto_depIdxs = []int32{\n\t1, // 0: k6.cloud.insights.proto.v1.k6.RequestMetadata.TestRunLabels:type_name -> k6.cloud.insights.proto.v1.k6.TestRunLabels\n\t2, // 1: k6.cloud.insights.proto.v1.k6.RequestMetadata.HTTPLabels:type_name -> k6.cloud.insights.proto.v1.k6.HTTPLabels\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_v1_k6_request_metadata_proto_init() }\nfunc file_v1_k6_request_metadata_proto_init() {\n\tif File_v1_k6_request_metadata_proto != nil {\n\t\treturn\n\t}\n\tfile_v1_k6_labels_proto_init()\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_v1_k6_request_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RequestMetadata); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_v1_k6_request_metadata_proto_msgTypes[0].OneofWrappers = []interface{}{\n\t\t(*RequestMetadata_HTTPLabels)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_v1_k6_request_metadata_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_v1_k6_request_metadata_proto_goTypes,\n\t\tDependencyIndexes: file_v1_k6_request_metadata_proto_depIdxs,\n\t\tMessageInfos:      file_v1_k6_request_metadata_proto_msgTypes,\n\t}.Build()\n\tFile_v1_k6_request_metadata_proto = out.File\n\tfile_v1_k6_request_metadata_proto_rawDesc = nil\n\tfile_v1_k6_request_metadata_proto_goTypes = nil\n\tfile_v1_k6_request_metadata_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/k6/request_metadata.proto",
    "content": "syntax = \"proto3\";\n\npackage k6.cloud.insights.proto.v1.k6;\n\noption go_package = \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/k6\";\n\nimport \"v1/k6/labels.proto\";\n\nmessage RequestMetadata {\n\tstring TraceID = 1;\n\tint64 StartTimeUnixNano = 2;\n\tint64 EndTimeUnixNano = 3;\n\tTestRunLabels TestRunLabels = 4;\n\toneof ProtocolLabels {\n\t\tHTTPLabels HTTPLabels = 5;\n\t}\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/trace/labels.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: v1/trace/labels.proto\n\npackage trace\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype SpanLabels struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tName        string         `protobuf:\"bytes,1,opt,name=Name,proto3\" json:\"Name,omitempty\"`\n\tServiceName string         `protobuf:\"bytes,2,opt,name=ServiceName,proto3\" json:\"ServiceName,omitempty\"`\n\tKind        SpanKind       `protobuf:\"varint,3,opt,name=Kind,proto3,enum=k6.cloud.insights.proto.v1.trace.SpanKind\" json:\"Kind,omitempty\"`\n\tStatusCode  SpanStatusCode `protobuf:\"varint,4,opt,name=StatusCode,proto3,enum=k6.cloud.insights.proto.v1.trace.SpanStatusCode\" json:\"StatusCode,omitempty\"`\n}\n\nfunc (x *SpanLabels) Reset() {\n\t*x = SpanLabels{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_trace_labels_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SpanLabels) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SpanLabels) ProtoMessage() {}\n\nfunc (x *SpanLabels) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_trace_labels_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SpanLabels.ProtoReflect.Descriptor instead.\nfunc (*SpanLabels) Descriptor() ([]byte, []int) {\n\treturn file_v1_trace_labels_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *SpanLabels) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *SpanLabels) GetServiceName() string {\n\tif x != nil {\n\t\treturn x.ServiceName\n\t}\n\treturn \"\"\n}\n\nfunc (x *SpanLabels) GetKind() SpanKind {\n\tif x != nil {\n\t\treturn x.Kind\n\t}\n\treturn SpanKind_SPAN_KIND_UNSPECIFIED\n}\n\nfunc (x *SpanLabels) GetStatusCode() SpanStatusCode {\n\tif x != nil {\n\t\treturn x.StatusCode\n\t}\n\treturn SpanStatusCode_STATUS_CODE_UNSET\n}\n\nvar File_v1_trace_labels_proto protoreflect.FileDescriptor\n\nvar file_v1_trace_labels_proto_rawDesc = []byte{\n\t0x0a, 0x15, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c,\n\t0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x20, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75,\n\t0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x2e, 0x76, 0x31, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x1a, 0x13, 0x76, 0x31, 0x2f, 0x74, 0x72,\n\t0x61, 0x63, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd4,\n\t0x01, 0x0a, 0x0a, 0x53, 0x70, 0x61, 0x6e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x12, 0x0a,\n\t0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d,\n\t0x65, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e,\n\t0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,\n\t0x0e, 0x32, 0x2a, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73,\n\t0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x74,\n\t0x72, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x04, 0x4b,\n\t0x69, 0x6e, 0x64, 0x12, 0x50, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64,\n\t0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f,\n\t0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x53,\n\t0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75,\n\t0x73, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x6f, 0x2e, 0x6b, 0x36, 0x2e, 0x69,\n\t0x6f, 0x2f, 0x6b, 0x36, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x63, 0x6c,\n\t0x6f, 0x75, 0x64, 0x61, 0x70, 0x69, 0x2f, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x62, 0x06,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_v1_trace_labels_proto_rawDescOnce sync.Once\n\tfile_v1_trace_labels_proto_rawDescData = file_v1_trace_labels_proto_rawDesc\n)\n\nfunc file_v1_trace_labels_proto_rawDescGZIP() []byte {\n\tfile_v1_trace_labels_proto_rawDescOnce.Do(func() {\n\t\tfile_v1_trace_labels_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_trace_labels_proto_rawDescData)\n\t})\n\treturn file_v1_trace_labels_proto_rawDescData\n}\n\nvar file_v1_trace_labels_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_v1_trace_labels_proto_goTypes = []interface{}{\n\t(*SpanLabels)(nil),  // 0: k6.cloud.insights.proto.v1.trace.SpanLabels\n\t(SpanKind)(0),       // 1: k6.cloud.insights.proto.v1.trace.SpanKind\n\t(SpanStatusCode)(0), // 2: k6.cloud.insights.proto.v1.trace.SpanStatusCode\n}\nvar file_v1_trace_labels_proto_depIdxs = []int32{\n\t1, // 0: k6.cloud.insights.proto.v1.trace.SpanLabels.Kind:type_name -> k6.cloud.insights.proto.v1.trace.SpanKind\n\t2, // 1: k6.cloud.insights.proto.v1.trace.SpanLabels.StatusCode:type_name -> k6.cloud.insights.proto.v1.trace.SpanStatusCode\n\t2, // [2:2] is the sub-list for method output_type\n\t2, // [2:2] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_v1_trace_labels_proto_init() }\nfunc file_v1_trace_labels_proto_init() {\n\tif File_v1_trace_labels_proto != nil {\n\t\treturn\n\t}\n\tfile_v1_trace_span_proto_init()\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_v1_trace_labels_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SpanLabels); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_v1_trace_labels_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_v1_trace_labels_proto_goTypes,\n\t\tDependencyIndexes: file_v1_trace_labels_proto_depIdxs,\n\t\tMessageInfos:      file_v1_trace_labels_proto_msgTypes,\n\t}.Build()\n\tFile_v1_trace_labels_proto = out.File\n\tfile_v1_trace_labels_proto_rawDesc = nil\n\tfile_v1_trace_labels_proto_goTypes = nil\n\tfile_v1_trace_labels_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/trace/labels.proto",
    "content": "syntax = \"proto3\";\n\npackage k6.cloud.insights.proto.v1.trace;\n\noption go_package = \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/trace\";\n\nimport \"v1/trace/span.proto\";\n\nmessage SpanLabels {\n  string Name = 1;\n  string ServiceName = 2;\n  SpanKind Kind = 3;\n  SpanStatusCode StatusCode = 4;\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/trace/span.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: v1/trace/span.proto\n\npackage trace\n\nimport (\n\tcommon \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/common\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// SpanKind is the type of span.\ntype SpanKind int32\n\nconst (\n\t// Unspecified. Do NOT use as default.\n\tSpanKind_SPAN_KIND_UNSPECIFIED SpanKind = 0\n\t// Indicates that the span represents an internal operation within an application,\n\t// as opposed to an operation happening at the boundaries. Default value.\n\tSpanKind_SPAN_KIND_INTERNAL SpanKind = 1\n\t// Indicates that the span covers server-side handling of an RPC or other\n\t// remote network request.\n\tSpanKind_SPAN_KIND_SERVER SpanKind = 2\n\t// Indicates that the span describes a request to some remote service.\n\tSpanKind_SPAN_KIND_CLIENT SpanKind = 3\n\t// Indicates that the span describes a producer sending a message to a broker.\n\tSpanKind_SPAN_KIND_PRODUCER SpanKind = 4\n\t// Indicates that the span describes consumer receiving a message from a broker.\n\tSpanKind_SPAN_KIND_CONSUMER SpanKind = 5\n)\n\n// Enum value maps for SpanKind.\nvar (\n\tSpanKind_name = map[int32]string{\n\t\t0: \"SPAN_KIND_UNSPECIFIED\",\n\t\t1: \"SPAN_KIND_INTERNAL\",\n\t\t2: \"SPAN_KIND_SERVER\",\n\t\t3: \"SPAN_KIND_CLIENT\",\n\t\t4: \"SPAN_KIND_PRODUCER\",\n\t\t5: \"SPAN_KIND_CONSUMER\",\n\t}\n\tSpanKind_value = map[string]int32{\n\t\t\"SPAN_KIND_UNSPECIFIED\": 0,\n\t\t\"SPAN_KIND_INTERNAL\":    1,\n\t\t\"SPAN_KIND_SERVER\":      2,\n\t\t\"SPAN_KIND_CLIENT\":      3,\n\t\t\"SPAN_KIND_PRODUCER\":    4,\n\t\t\"SPAN_KIND_CONSUMER\":    5,\n\t}\n)\n\nfunc (x SpanKind) Enum() *SpanKind {\n\tp := new(SpanKind)\n\t*p = x\n\treturn p\n}\n\nfunc (x SpanKind) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (SpanKind) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_v1_trace_span_proto_enumTypes[0].Descriptor()\n}\n\nfunc (SpanKind) Type() protoreflect.EnumType {\n\treturn &file_v1_trace_span_proto_enumTypes[0]\n}\n\nfunc (x SpanKind) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use SpanKind.Descriptor instead.\nfunc (SpanKind) EnumDescriptor() ([]byte, []int) {\n\treturn file_v1_trace_span_proto_rawDescGZIP(), []int{0}\n}\n\n// For the semantics of status codes see\n// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status\ntype SpanStatusCode int32\n\nconst (\n\t// The default status.\n\tSpanStatusCode_STATUS_CODE_UNSET SpanStatusCode = 0\n\t// The Span has been validated by an Application developers or Operator to have completed successfully.\n\tSpanStatusCode_STATUS_CODE_OK SpanStatusCode = 1\n\t// The Span contains an error.\n\tSpanStatusCode_STATUS_CODE_ERROR SpanStatusCode = 2\n)\n\n// Enum value maps for SpanStatusCode.\nvar (\n\tSpanStatusCode_name = map[int32]string{\n\t\t0: \"STATUS_CODE_UNSET\",\n\t\t1: \"STATUS_CODE_OK\",\n\t\t2: \"STATUS_CODE_ERROR\",\n\t}\n\tSpanStatusCode_value = map[string]int32{\n\t\t\"STATUS_CODE_UNSET\": 0,\n\t\t\"STATUS_CODE_OK\":    1,\n\t\t\"STATUS_CODE_ERROR\": 2,\n\t}\n)\n\nfunc (x SpanStatusCode) Enum() *SpanStatusCode {\n\tp := new(SpanStatusCode)\n\t*p = x\n\treturn p\n}\n\nfunc (x SpanStatusCode) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (SpanStatusCode) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_v1_trace_span_proto_enumTypes[1].Descriptor()\n}\n\nfunc (SpanStatusCode) Type() protoreflect.EnumType {\n\treturn &file_v1_trace_span_proto_enumTypes[1]\n}\n\nfunc (x SpanStatusCode) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use SpanStatusCode.Descriptor instead.\nfunc (SpanStatusCode) EnumDescriptor() ([]byte, []int) {\n\treturn file_v1_trace_span_proto_rawDescGZIP(), []int{1}\n}\n\ntype Span struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// A unique identifier for a trace.\n\tTraceID string `protobuf:\"bytes,1,opt,name=TraceID,proto3\" json:\"TraceID,omitempty\"`\n\t// A unique identifier for a span within a trace.\n\tSpanID string `protobuf:\"bytes,2,opt,name=SpanID,proto3\" json:\"SpanID,omitempty\"`\n\t// The start time of the span.\n\tStartTimeUnixNano int64 `protobuf:\"fixed64,3,opt,name=StartTimeUnixNano,proto3\" json:\"StartTimeUnixNano,omitempty\"`\n\t// The end time of the span.\n\tEndTimeUnixNano int64 `protobuf:\"fixed64,4,opt,name=EndTimeUnixNano,proto3\" json:\"EndTimeUnixNano,omitempty\"`\n\t// A description of the span's operation.\n\tName string `protobuf:\"bytes,5,opt,name=Name,proto3\" json:\"Name,omitempty\"`\n\t// Logical name of the service.\n\tServiceName string `protobuf:\"bytes,6,opt,name=ServiceName,proto3\" json:\"ServiceName,omitempty\"`\n\t// Distinguishes between spans generated in a particular context.\n\tKind SpanKind `protobuf:\"varint,7,opt,name=Kind,proto3,enum=k6.cloud.insights.proto.v1.trace.SpanKind\" json:\"Kind,omitempty\"`\n\t// The status code.\n\tStatusCode SpanStatusCode `protobuf:\"varint,8,opt,name=StatusCode,proto3,enum=k6.cloud.insights.proto.v1.trace.SpanStatusCode\" json:\"StatusCode,omitempty\"`\n\t// The attributes associated with the span.\n\t// https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/resource/semantic_conventions\n\t// https://github.com/opentracing/specification/blob/master/semantic_conventions.md#span-tags-table\n\tAttributes []*common.KeyValue `protobuf:\"bytes,9,rep,name=Attributes,proto3\" json:\"Attributes,omitempty\"`\n}\n\nfunc (x *Span) Reset() {\n\t*x = Span{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_v1_trace_span_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Span) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Span) ProtoMessage() {}\n\nfunc (x *Span) ProtoReflect() protoreflect.Message {\n\tmi := &file_v1_trace_span_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Span.ProtoReflect.Descriptor instead.\nfunc (*Span) Descriptor() ([]byte, []int) {\n\treturn file_v1_trace_span_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Span) GetTraceID() string {\n\tif x != nil {\n\t\treturn x.TraceID\n\t}\n\treturn \"\"\n}\n\nfunc (x *Span) GetSpanID() string {\n\tif x != nil {\n\t\treturn x.SpanID\n\t}\n\treturn \"\"\n}\n\nfunc (x *Span) GetStartTimeUnixNano() int64 {\n\tif x != nil {\n\t\treturn x.StartTimeUnixNano\n\t}\n\treturn 0\n}\n\nfunc (x *Span) GetEndTimeUnixNano() int64 {\n\tif x != nil {\n\t\treturn x.EndTimeUnixNano\n\t}\n\treturn 0\n}\n\nfunc (x *Span) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Span) GetServiceName() string {\n\tif x != nil {\n\t\treturn x.ServiceName\n\t}\n\treturn \"\"\n}\n\nfunc (x *Span) GetKind() SpanKind {\n\tif x != nil {\n\t\treturn x.Kind\n\t}\n\treturn SpanKind_SPAN_KIND_UNSPECIFIED\n}\n\nfunc (x *Span) GetStatusCode() SpanStatusCode {\n\tif x != nil {\n\t\treturn x.StatusCode\n\t}\n\treturn SpanStatusCode_STATUS_CODE_UNSET\n}\n\nfunc (x *Span) GetAttributes() []*common.KeyValue {\n\tif x != nil {\n\t\treturn x.Attributes\n\t}\n\treturn nil\n}\n\nvar File_v1_trace_span_proto protoreflect.FileDescriptor\n\nvar file_v1_trace_span_proto_rawDesc = []byte{\n\t0x0a, 0x13, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x6e, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x20, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,\n\t0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76,\n\t0x31, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x1a, 0x16, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,\n\t0xa5, 0x03, 0x0a, 0x04, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x54, 0x72, 0x61, 0x63,\n\t0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x54, 0x72, 0x61, 0x63, 0x65,\n\t0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x70, 0x61, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x06, 0x53, 0x70, 0x61, 0x6e, 0x49, 0x44, 0x12, 0x2c, 0x0a, 0x11, 0x53, 0x74,\n\t0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x18,\n\t0x03, 0x20, 0x01, 0x28, 0x10, 0x52, 0x11, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65,\n\t0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x12, 0x28, 0x0a, 0x0f, 0x45, 0x6e, 0x64, 0x54,\n\t0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61, 0x6e, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28,\n\t0x10, 0x52, 0x0f, 0x45, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x55, 0x6e, 0x69, 0x78, 0x4e, 0x61,\n\t0x6e, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,\n\t0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,\n\t0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, 0x65, 0x72,\n\t0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64,\n\t0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75,\n\t0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x2e, 0x76, 0x31, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0x53, 0x70, 0x61, 0x6e, 0x4b, 0x69,\n\t0x6e, 0x64, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x50, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74,\n\t0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x6b,\n\t0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x73,\n\t0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e,\n\t0x53, 0x70, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x0a,\n\t0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x4b, 0x0a, 0x0a, 0x41, 0x74,\n\t0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b,\n\t0x2e, 0x6b, 0x36, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68,\n\t0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x31, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,\n\t0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x41, 0x74, 0x74,\n\t0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2a, 0x99, 0x01, 0x0a, 0x08, 0x53, 0x70, 0x61, 0x6e,\n\t0x4b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e,\n\t0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12,\n\t0x16, 0x0a, 0x12, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x49, 0x4e, 0x54,\n\t0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x50, 0x41, 0x4e, 0x5f,\n\t0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x10, 0x02, 0x12, 0x14, 0x0a,\n\t0x10, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e,\n\t0x54, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44,\n\t0x5f, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x45, 0x52, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x53,\n\t0x50, 0x41, 0x4e, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x53, 0x55, 0x4d, 0x45,\n\t0x52, 0x10, 0x05, 0x2a, 0x52, 0x0a, 0x0e, 0x53, 0x70, 0x61, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75,\n\t0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f,\n\t0x43, 0x4f, 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e,\n\t0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x4f, 0x4b, 0x10, 0x01,\n\t0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x4f, 0x44, 0x45, 0x5f,\n\t0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x42, 0x37, 0x5a, 0x35, 0x67, 0x6f, 0x2e, 0x6b, 0x36,\n\t0x2e, 0x69, 0x6f, 0x2f, 0x6b, 0x36, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,\n\t0x63, 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x70, 0x69, 0x2f, 0x69, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74,\n\t0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x72, 0x61, 0x63, 0x65,\n\t0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_v1_trace_span_proto_rawDescOnce sync.Once\n\tfile_v1_trace_span_proto_rawDescData = file_v1_trace_span_proto_rawDesc\n)\n\nfunc file_v1_trace_span_proto_rawDescGZIP() []byte {\n\tfile_v1_trace_span_proto_rawDescOnce.Do(func() {\n\t\tfile_v1_trace_span_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_trace_span_proto_rawDescData)\n\t})\n\treturn file_v1_trace_span_proto_rawDescData\n}\n\nvar file_v1_trace_span_proto_enumTypes = make([]protoimpl.EnumInfo, 2)\nvar file_v1_trace_span_proto_msgTypes = make([]protoimpl.MessageInfo, 1)\nvar file_v1_trace_span_proto_goTypes = []interface{}{\n\t(SpanKind)(0),           // 0: k6.cloud.insights.proto.v1.trace.SpanKind\n\t(SpanStatusCode)(0),     // 1: k6.cloud.insights.proto.v1.trace.SpanStatusCode\n\t(*Span)(nil),            // 2: k6.cloud.insights.proto.v1.trace.Span\n\t(*common.KeyValue)(nil), // 3: k6.cloud.insights.proto.v1.common.KeyValue\n}\nvar file_v1_trace_span_proto_depIdxs = []int32{\n\t0, // 0: k6.cloud.insights.proto.v1.trace.Span.Kind:type_name -> k6.cloud.insights.proto.v1.trace.SpanKind\n\t1, // 1: k6.cloud.insights.proto.v1.trace.Span.StatusCode:type_name -> k6.cloud.insights.proto.v1.trace.SpanStatusCode\n\t3, // 2: k6.cloud.insights.proto.v1.trace.Span.Attributes:type_name -> k6.cloud.insights.proto.v1.common.KeyValue\n\t3, // [3:3] is the sub-list for method output_type\n\t3, // [3:3] is the sub-list for method input_type\n\t3, // [3:3] is the sub-list for extension type_name\n\t3, // [3:3] is the sub-list for extension extendee\n\t0, // [0:3] is the sub-list for field type_name\n}\n\nfunc init() { file_v1_trace_span_proto_init() }\nfunc file_v1_trace_span_proto_init() {\n\tif File_v1_trace_span_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_v1_trace_span_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Span); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_v1_trace_span_proto_rawDesc,\n\t\t\tNumEnums:      2,\n\t\t\tNumMessages:   1,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_v1_trace_span_proto_goTypes,\n\t\tDependencyIndexes: file_v1_trace_span_proto_depIdxs,\n\t\tEnumInfos:         file_v1_trace_span_proto_enumTypes,\n\t\tMessageInfos:      file_v1_trace_span_proto_msgTypes,\n\t}.Build()\n\tFile_v1_trace_span_proto = out.File\n\tfile_v1_trace_span_proto_rawDesc = nil\n\tfile_v1_trace_span_proto_goTypes = nil\n\tfile_v1_trace_span_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/cloudapi/insights/proto/v1/trace/span.proto",
    "content": "syntax = \"proto3\";\n\npackage k6.cloud.insights.proto.v1.trace;\n\noption go_package = \"go.k6.io/k6/internal/cloudapi/insights/proto/v1/trace\";\n\nimport \"v1/common/common.proto\";\n\nmessage Span {\n  // A unique identifier for a trace.\n  string TraceID = 1;\n\n  // A unique identifier for a span within a trace.\n  string SpanID = 2;\n\n  // The start time of the span.\n  sfixed64 StartTimeUnixNano = 3;\n\n  // The end time of the span.\n  sfixed64 EndTimeUnixNano = 4;\n\n  // A description of the span's operation.\n  string Name = 5;\n\n  // Logical name of the service.\n  string ServiceName = 6;\n\n  // Distinguishes between spans generated in a particular context.\n  SpanKind Kind = 7;\n\n  // The status code.\n  SpanStatusCode StatusCode = 8;\n\n  // The attributes associated with the span.\n  // https://github.com/open-telemetry/opentelemetry-specification/tree/main/specification/resource/semantic_conventions\n  // https://github.com/opentracing/specification/blob/master/semantic_conventions.md#span-tags-table\n  repeated common.KeyValue Attributes = 9;\n}\n\n// SpanKind is the type of span.\nenum SpanKind {\n  // Unspecified. Do NOT use as default.\n  SPAN_KIND_UNSPECIFIED = 0;\n\n  // Indicates that the span represents an internal operation within an application,\n  // as opposed to an operation happening at the boundaries. Default value.\n  SPAN_KIND_INTERNAL = 1;\n\n  // Indicates that the span covers server-side handling of an RPC or other\n  // remote network request.\n  SPAN_KIND_SERVER = 2;\n\n  // Indicates that the span describes a request to some remote service.\n  SPAN_KIND_CLIENT = 3;\n\n  // Indicates that the span describes a producer sending a message to a broker.\n  SPAN_KIND_PRODUCER = 4;\n\n  // Indicates that the span describes consumer receiving a message from a broker.\n  SPAN_KIND_CONSUMER = 5;\n}\n\n// For the semantics of status codes see\n// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status\nenum SpanStatusCode {\n  // The default status.\n  STATUS_CODE_UNSET = 0;\n  // The Span has been validated by an Application developers or Operator to have completed successfully.\n  STATUS_CODE_OK = 1;\n  // The Span contains an error.\n  STATUS_CODE_ERROR = 2;\n};\n"
  },
  {
    "path": "internal/cloudapi/v6/api.go",
    "content": "package cloudapi\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\n\tk6cloud \"github.com/grafana/k6-cloud-openapi-client-go/k6\"\n)\n\n// ValidateToken calls the endpoint to validate the Client's token and returns the result.\nfunc (c *Client) ValidateToken(stackURL string) (_ *k6cloud.AuthenticationResponse, err error) {\n\tif stackURL == \"\" {\n\t\treturn nil, errors.New(\"stack URL is required to validate token\")\n\t}\n\n\tif _, err := url.Parse(stackURL); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid stack URL: %w\", err)\n\t}\n\n\tctx := context.WithValue(context.Background(), k6cloud.ContextAccessToken, c.token)\n\treq := c.apiClient.AuthorizationAPI.\n\t\tAuth(ctx).\n\t\tXStackUrl(stackURL)\n\n\tresp, httpRes, rerr := req.Execute()\n\tdefer func() {\n\t\tif httpRes != nil {\n\t\t\t_, _ = io.Copy(io.Discard, httpRes.Body)\n\t\t\tif cerr := httpRes.Body.Close(); cerr != nil && err == nil {\n\t\t\t\terr = cerr\n\t\t\t}\n\t\t}\n\t}()\n\n\tif rerr != nil {\n\t\tvar apiErr *k6cloud.GenericOpenAPIError\n\t\tif !errors.As(rerr, &apiErr) {\n\t\t\treturn nil, fmt.Errorf(\"failed to validate token: %w\", rerr)\n\t\t}\n\t}\n\n\tif err := CheckResponse(httpRes); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to validate token: %w\", err)\n\t}\n\n\treturn resp, err\n}\n"
  },
  {
    "path": "internal/cloudapi/v6/api_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n)\n\nfunc TestValidateToken(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"successful token validation\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t// Verify the authorization header\n\t\t\tauthHeader := r.Header.Get(\"Authorization\")\n\t\t\tassert.Equal(t, \"Bearer test-token\", authHeader)\n\n\t\t\t// Verify the stack URL\n\t\t\tstackURL := r.Header.Get(\"X-Stack-Url\")\n\t\t\tassert.Equal(t, stackURL, \"https://stack.grafana.net\")\n\n\t\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\t\t\tfprint(t, w, `{\n\t\t\t\t\"stack_id\": 123,\n\t\t\t\t\"default_project_id\": 456\n\t\t\t}`)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient, err := NewClient(testutils.NewLogger(t), \"test-token\", server.URL, \"1.0\", 1*time.Second)\n\t\trequire.NoError(t, err)\n\n\t\tresp, err := client.ValidateToken(\"https://stack.grafana.net\")\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, resp)\n\t\tassert.Equal(t, int32(123), resp.StackId)\n\t\tassert.Equal(t, int32(456), resp.DefaultProjectId)\n\t})\n\n\tt.Run(\"unauthorized token should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tw.Header().Add(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\tfprint(t, w, `{\n\t\t\t\t\"error\": {\n\t\t\t\t\t\"code\": \"error\",\n\t\t\t\t\t\"message\": \"Invalid token\"\n\t\t\t\t}\n\t\t\t}`)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\tclient, err := NewClient(testutils.NewLogger(t), \"invalid-token\", server.URL, \"1.0\", 1*time.Second)\n\t\trequire.NoError(t, err)\n\n\t\tresp, err := client.ValidateToken(\"https://stack.grafana.net\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, resp)\n\t\tassert.Contains(t, err.Error(), \"(401/error) Invalid token\")\n\t})\n\n\tt.Run(\"network error should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Use an invalid URL to simulate network error\n\t\tclient, err := NewClient(testutils.NewLogger(t), \"test-token\", \"http://invalid-url-that-does-not-exist\", \"1.0\", 1*time.Second)\n\t\trequire.NoError(t, err)\n\n\t\tresp, err := client.ValidateToken(\"https://stack.grafana.net\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, resp)\n\t})\n\n\tt.Run(\"missing stack URL should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tclient, err := NewClient(testutils.NewLogger(t), \"test-token\", \"http://example.com\", \"1.0\", 1*time.Second)\n\t\trequire.NoError(t, err)\n\n\t\tresp, err := client.ValidateToken(\"\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, resp)\n\t\tassert.Equal(t, \"stack URL is required to validate token\", err.Error())\n\t})\n\n\tt.Run(\"invalid stack URL should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tclient, err := NewClient(testutils.NewLogger(t), \"test-token\", \"http://example.com\", \"1.0\", 1*time.Second)\n\t\trequire.NoError(t, err)\n\n\t\tresp, err := client.ValidateToken(\"://invalid-url\")\n\t\tassert.Error(t, err)\n\t\tassert.Nil(t, resp)\n\t\tassert.Contains(t, err.Error(), \"invalid stack URL\")\n\t})\n}\n\nfunc fprint(t *testing.T, w io.Writer, format string) int {\n\tn, err := fmt.Fprint(w, format)\n\trequire.NoError(t, err)\n\treturn n\n}\n"
  },
  {
    "path": "internal/cloudapi/v6/client.go",
    "content": "package cloudapi\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"time\"\n\n\tk6cloud \"github.com/grafana/k6-cloud-openapi-client-go/k6\"\n\t\"github.com/sirupsen/logrus\"\n)\n\nconst (\n\t// RetryInterval is the default cloud request retry interval\n\tRetryInterval = 500 * time.Millisecond\n\t// MaxRetries specifies max retry attempts\n\tMaxRetries = 3\n)\n\n// Client handles communication with the k6 Cloud API.\ntype Client struct {\n\tapiClient *k6cloud.APIClient\n\ttoken     string\n\tstackID   int64\n\tbaseURL   string\n\n\tlogger logrus.FieldLogger\n\n\tretries       int\n\tretryInterval time.Duration\n}\n\n// NewClient return a new client for the cloud API\nfunc NewClient(logger logrus.FieldLogger, token, host, version string, timeout time.Duration) (*Client, error) {\n\tif token == \"\" {\n\t\treturn nil, fmt.Errorf(\"token is required to create cloud API client\")\n\t}\n\n\tcfg := &k6cloud.Configuration{\n\t\tDefaultHeader: make(map[string]string),\n\t\tUserAgent:     \"k6cloud/\" + version,\n\t\tServers: k6cloud.ServerConfigurations{\n\t\t\t{\n\t\t\t\tURL:         host,\n\t\t\t\tDescription: \"Global k6 Cloud API.\",\n\t\t\t},\n\t\t},\n\t\tOperationServers: map[string]k6cloud.ServerConfigurations{},\n\t\tHTTPClient:       &http.Client{Timeout: timeout},\n\t}\n\n\tc := &Client{\n\t\tapiClient:     k6cloud.NewAPIClient(cfg),\n\t\ttoken:         token,\n\t\tbaseURL:       fmt.Sprintf(\"%s/cloud/v6\", host),\n\t\tretries:       MaxRetries,\n\t\tretryInterval: RetryInterval,\n\t\tlogger:        logger,\n\t}\n\treturn c, nil\n}\n\n// SetStackID sets the stack ID for the client.\nfunc (c *Client) SetStackID(stackID int64) {\n\tc.stackID = stackID\n}\n\n// BaseURL returns configured host.\nfunc (c *Client) BaseURL() string {\n\treturn c.baseURL\n}\n\n// CheckResponse checks the parsed response.\n// It returns nil if the code is in the successful range,\n// otherwise it tries to parse the body and return a parsed error.\nfunc CheckResponse(r *http.Response) error {\n\tif r == nil {\n\t\treturn errUnknown\n\t}\n\n\tif c := r.StatusCode; c >= 200 && c <= 299 {\n\t\treturn nil\n\t}\n\n\tdata, err := io.ReadAll(r.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar payload ResponseError\n\tif err := json.Unmarshal(data, &payload); err != nil {\n\t\tif r.StatusCode == http.StatusUnauthorized {\n\t\t\treturn errNotAuthenticated\n\t\t}\n\t\tif r.StatusCode == http.StatusForbidden {\n\t\t\treturn errNotAuthorized\n\t\t}\n\t\treturn fmt.Errorf(\n\t\t\t\"unexpected HTTP error from %s: %d %s\",\n\t\t\tr.Request.URL,\n\t\t\tr.StatusCode,\n\t\t\thttp.StatusText(r.StatusCode),\n\t\t)\n\t}\n\tpayload.Response = r\n\treturn payload\n}\n"
  },
  {
    "path": "internal/cloudapi/v6/client_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCheckResponse(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname                string\n\t\tresponse            *http.Response\n\t\texpectResponseError bool\n\t\texpectedError       string\n\t}{\n\t\t{\n\t\t\tname:          \"nil response\",\n\t\t\tresponse:      nil,\n\t\t\texpectedError: errUnknown.Error(),\n\t\t},\n\t\t{\n\t\t\tname:          \"successful response 200\",\n\t\t\tresponse:      &http.Response{StatusCode: http.StatusOK},\n\t\t\texpectedError: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"unauthorized 401 with invalid JSON\",\n\t\t\tresponse: &http.Response{\n\t\t\t\tStatusCode: http.StatusUnauthorized,\n\t\t\t\tBody:       io.NopCloser(strings.NewReader(\"invalid json\")),\n\t\t\t},\n\t\t\texpectedError: errNotAuthenticated.Error(),\n\t\t},\n\t\t{\n\t\t\tname: \"forbidden 403 with invalid JSON\",\n\t\t\tresponse: &http.Response{\n\t\t\t\tStatusCode: http.StatusForbidden,\n\t\t\t\tBody:       io.NopCloser(strings.NewReader(\"invalid json\")),\n\t\t\t},\n\t\t\texpectedError: errNotAuthorized.Error(),\n\t\t},\n\t\t{\n\t\t\tname: \"server error 500 with invalid JSON\",\n\t\t\tresponse: &http.Response{\n\t\t\t\tStatusCode: http.StatusInternalServerError,\n\t\t\t\tBody:       io.NopCloser(strings.NewReader(\"invalid json\")),\n\t\t\t\tRequest:    &http.Request{URL: mustParseURL(t, \"https://api.k6.io/test\")},\n\t\t\t},\n\t\t\texpectedError: \"unexpected HTTP error from https://api.k6.io/test: 500 Internal Server Error\",\n\t\t},\n\t\t{\n\t\t\tname: \"error with valid JSON payload\",\n\t\t\tresponse: &http.Response{\n\t\t\t\tStatusCode: http.StatusBadRequest,\n\t\t\t\tBody: io.NopCloser(strings.NewReader(`{\n\t\t\t\t\t\"error\": {\n\t\t\t\t\t\t\"message\": \"validation failed\",\n\t\t\t\t\t\t\"code\": \"error\"\n\t\t\t\t\t}\n\t\t\t\t}`)),\n\t\t\t\tRequest: &http.Request{URL: mustParseURL(t, \"https://api.k6.io/test\")},\n\t\t\t},\n\t\t\texpectResponseError: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\terr := CheckResponse(tt.response)\n\n\t\t\tif tt.expectedError == \"\" && !tt.expectResponseError {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.Error(t, err)\n\n\t\t\tif tt.expectResponseError {\n\t\t\t\tvar respErr ResponseError\n\t\t\t\tassert.True(t, errors.As(err, &respErr))\n\t\t\t\tassert.Equal(t, tt.response, respErr.Response)\n\t\t\t} else {\n\t\t\t\tassert.Equal(t, tt.expectedError, err.Error())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc mustParseURL(t *testing.T, rawURL string) *url.URL {\n\tu, err := url.Parse(rawURL)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\treturn u\n}\n"
  },
  {
    "path": "internal/cloudapi/v6/config.go",
    "content": "package cloudapi\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// Config holds all the necessary data and options for sending metrics to the k6 Cloud.\n//\n//nolint:lll\ntype Config struct {\n\t// TODO: refactor common stuff between cloud execution and output\n\tToken     null.String `json:\"token\" envconfig:\"K6_CLOUD_TOKEN\"`\n\tStackID   null.Int    `json:\"stackID\" envconfig:\"K6_CLOUD_STACK_ID\"`\n\tProjectID null.Int    `json:\"projectID\" envconfig:\"K6_CLOUD_PROJECT_ID\"`\n\tName      null.String `json:\"name\" envconfig:\"K6_CLOUD_NAME\"`\n\n\tHost    null.String        `json:\"host\" envconfig:\"K6_CLOUD_HOST\"`\n\tTimeout types.NullDuration `json:\"timeout\" envconfig:\"K6_CLOUD_TIMEOUT\"`\n\n\tLogsTailURL    null.String `json:\"-\" envconfig:\"K6_CLOUD_LOGS_TAIL_URL\"`\n\tWebAppURL      null.String `json:\"webAppURL\" envconfig:\"K6_CLOUD_WEB_APP_URL\"`\n\tTestRunDetails null.String `json:\"testRunDetails\" envconfig:\"K6_CLOUD_TEST_RUN_DETAILS\"`\n\tNoCompress     null.Bool   `json:\"noCompress\" envconfig:\"K6_CLOUD_NO_COMPRESS\"`\n\tStopOnError    null.Bool   `json:\"stopOnError\" envconfig:\"K6_CLOUD_STOP_ON_ERROR\"`\n\tAPIVersion     null.Int    `json:\"apiVersion\" envconfig:\"K6_CLOUD_API_VERSION\"`\n\n\t// PushRefID is the identifier used by k6 Cloud to correlate all the things that\n\t// belong to the same test run/execution. Currently, it is equivalent to the test run id.\n\t// But, in the future, or in future solutions (e.g. Synthetic Monitoring), there might be\n\t// no test run id, and we may still need an identifier to correlate all the things.\n\tPushRefID null.String `json:\"pushRefID\" envconfig:\"K6_CLOUD_PUSH_REF_ID\"`\n\n\t// Defines the max allowed number of time series in a single batch.\n\tMaxTimeSeriesInBatch null.Int `json:\"maxTimeSeriesInBatch\" envconfig:\"K6_CLOUD_MAX_TIME_SERIES_IN_BATCH\"`\n\n\t// The time interval between periodic API calls for sending samples to the cloud ingest service.\n\tMetricPushInterval types.NullDuration `json:\"metricPushInterval\" envconfig:\"K6_CLOUD_METRIC_PUSH_INTERVAL\"`\n\n\t// This is how many concurrent pushes will be done at the same time to the cloud\n\tMetricPushConcurrency null.Int `json:\"metricPushConcurrency\" envconfig:\"K6_CLOUD_METRIC_PUSH_CONCURRENCY\"`\n\n\t// If specified and is greater than 0, sample aggregation with that period is enabled\n\tAggregationPeriod types.NullDuration `json:\"aggregationPeriod\" envconfig:\"K6_CLOUD_AGGREGATION_PERIOD\"`\n\n\t// If aggregation is enabled, this specifies how long we'll wait for period samples to accumulate before trying to aggregate them.\n\tAggregationWaitPeriod types.NullDuration `json:\"aggregationWaitPeriod\" envconfig:\"K6_CLOUD_AGGREGATION_WAIT_PERIOD\"`\n\n\t// Indicates whether to send traces to the k6 Insights backend service.\n\tTracesEnabled null.Bool `json:\"tracesEnabled\" envconfig:\"K6_CLOUD_TRACES_ENABLED\"`\n\n\t// The host of the k6 Insights backend service.\n\tTracesHost null.String `json:\"traceHost\" envconfig:\"K6_CLOUD_TRACES_HOST\"`\n\n\t// This is how many concurrent pushes will be done at the same time to the cloud\n\tTracesPushConcurrency null.Int `json:\"tracesPushConcurrency\" envconfig:\"K6_CLOUD_TRACES_PUSH_CONCURRENCY\"`\n\n\t// The time interval between periodic API calls for sending samples to the cloud ingest service.\n\tTracesPushInterval types.NullDuration `json:\"tracesPushInterval\" envconfig:\"K6_CLOUD_TRACES_PUSH_INTERVAL\"`\n}\n\n// NewConfig creates a new Config instance with default values for some fields.\nfunc NewConfig() Config {\n\treturn Config{\n\t\tStackID:               null.NewInt(0, false),\n\t\tAPIVersion:            null.NewInt(2, false),\n\t\tHost:                  null.NewString(\"https://api.k6.io\", false),\n\t\tLogsTailURL:           null.NewString(\"wss://cloudlogs.k6.io/api/v1/tail\", false),\n\t\tWebAppURL:             null.NewString(\"https://app.k6.io\", false),\n\t\tMetricPushInterval:    types.NewNullDuration(1*time.Second, false),\n\t\tMetricPushConcurrency: null.NewInt(1, false),\n\t\tTimeout:               types.NewNullDuration(1*time.Minute, false),\n\n\t\t// The set value (1000) is selected for performance reasons.\n\t\t// Any change to this value should be first discussed with internal stakeholders.\n\t\tMaxTimeSeriesInBatch: null.NewInt(1000, false),\n\n\t\t// TODO: the following values were used by the previous default version (v1).\n\t\t// We decided to keep the same values mostly for having a smoother migration to v2.\n\t\t// Because the previous version's aggregation config, a few lines below, is overwritten\n\t\t// by the remote service with the same values that we are now setting here for v2.\n\t\t// When the migration will be completed we may evaluate to re-discuss them\n\t\t// as we may evaluate to reduce these values - especially the waiting period.\n\t\t// A more specific request about waiting period is mentioned in the link below:\n\t\t// https://github.com/grafana/k6/blob/44e1e63aadb66784ff0a12b8d9821a0fdc9e7467/output/cloud/expv2/collect.go#L72-L77\n\t\tAggregationPeriod:     types.NewNullDuration(3*time.Second, false),\n\t\tAggregationWaitPeriod: types.NewNullDuration(8*time.Second, false),\n\n\t\tTracesEnabled:         null.NewBool(true, false),\n\t\tTracesHost:            null.NewString(\"grpc-k6-api-prod-prod-us-east-0.grafana.net:443\", false),\n\t\tTracesPushInterval:    types.NewNullDuration(1*time.Second, false),\n\t\tTracesPushConcurrency: null.NewInt(1, false),\n\t}\n}\n\n// Apply saves config non-zero config values from the passed config in the receiver.\n//\n//nolint:cyclop\nfunc (c Config) Apply(cfg Config) Config {\n\tif cfg.Token.Valid {\n\t\tc.Token = cfg.Token\n\t}\n\tif cfg.ProjectID.Valid && cfg.ProjectID.Int64 > 0 {\n\t\tc.ProjectID = cfg.ProjectID\n\t}\n\tif cfg.Name.Valid && cfg.Name.String != \"\" {\n\t\tc.Name = cfg.Name\n\t}\n\tif cfg.Host.Valid && cfg.Host.String != \"\" {\n\t\tc.Host = cfg.Host\n\t}\n\tif cfg.LogsTailURL.Valid && cfg.LogsTailURL.String != \"\" {\n\t\tc.LogsTailURL = cfg.LogsTailURL\n\t}\n\tif cfg.PushRefID.Valid {\n\t\tc.PushRefID = cfg.PushRefID\n\t}\n\tif cfg.WebAppURL.Valid {\n\t\tc.WebAppURL = cfg.WebAppURL\n\t}\n\tif cfg.TestRunDetails.Valid {\n\t\tc.TestRunDetails = cfg.TestRunDetails\n\t}\n\tif cfg.NoCompress.Valid {\n\t\tc.NoCompress = cfg.NoCompress\n\t}\n\tif cfg.StopOnError.Valid {\n\t\tc.StopOnError = cfg.StopOnError\n\t}\n\tif cfg.Timeout.Valid {\n\t\tc.Timeout = cfg.Timeout\n\t}\n\tif cfg.APIVersion.Valid {\n\t\tc.APIVersion = cfg.APIVersion\n\t}\n\tif cfg.MaxTimeSeriesInBatch.Valid {\n\t\tc.MaxTimeSeriesInBatch = cfg.MaxTimeSeriesInBatch\n\t}\n\tif cfg.MetricPushInterval.Valid {\n\t\tc.MetricPushInterval = cfg.MetricPushInterval\n\t}\n\tif cfg.MetricPushConcurrency.Valid {\n\t\tc.MetricPushConcurrency = cfg.MetricPushConcurrency\n\t}\n\tif cfg.TracesEnabled.Valid {\n\t\tc.TracesEnabled = cfg.TracesEnabled\n\t}\n\tif cfg.TracesHost.Valid {\n\t\tc.TracesHost = cfg.TracesHost\n\t}\n\tif cfg.TracesPushInterval.Valid {\n\t\tc.TracesPushInterval = cfg.TracesPushInterval\n\t}\n\tif cfg.TracesPushConcurrency.Valid {\n\t\tc.TracesPushConcurrency = cfg.TracesPushConcurrency\n\t}\n\tif cfg.AggregationPeriod.Valid {\n\t\tc.AggregationPeriod = cfg.AggregationPeriod\n\t}\n\tif cfg.AggregationWaitPeriod.Valid {\n\t\tc.AggregationWaitPeriod = cfg.AggregationWaitPeriod\n\t}\n\treturn c\n}\n\n// GetConsolidatedConfig combines the default config values with the JSON config\n// values and environment variables and returns the final result.\nfunc GetConsolidatedConfig(\n\tjsonRawConf json.RawMessage,\n\tenv map[string]string,\n\tconfigArg string,\n\tcloudConfig json.RawMessage,\n) (Config, error) {\n\tresult := NewConfig()\n\tif jsonRawConf != nil {\n\t\tjsonConf := Config{}\n\t\tif err := json.Unmarshal(jsonRawConf, &jsonConf); err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tresult = result.Apply(jsonConf)\n\t}\n\n\tif err := mergeFromCloudOption(cloudConfig, &result); err != nil {\n\t\treturn result, err\n\t}\n\n\tenvConfig := Config{}\n\tif err := envconfig.Process(\"\", &envConfig, func(key string) (string, bool) {\n\t\tv, ok := env[key]\n\t\treturn v, ok\n\t}); err != nil {\n\t\t// TODO: get rid of envconfig and actually use the env parameter...\n\t\treturn result, err\n\t}\n\tresult = result.Apply(envConfig)\n\n\tif configArg != \"\" {\n\t\tresult.Name = null.StringFrom(configArg)\n\t}\n\n\treturn result, nil\n}\n\n// mergeFromCloudOption merges three fields from the JSON in a cloud key of\n// the provided external map. Used for options.cloud settings.\nfunc mergeFromCloudOption(\n\tcloudConfig json.RawMessage,\n\tconf *Config,\n) error {\n\tif cloudConfig == nil {\n\t\treturn nil\n\t}\n\n\t// Original comment\n\t// TODO: Important! Separate configs and fix the whole 2 configs mess!\n\ttmpConfig := Config{}\n\tif err := json.Unmarshal(cloudConfig, &tmpConfig); err != nil {\n\t\treturn err\n\t}\n\t// Only take out the ProjectID, Name and Token from the options.cloud map:\n\tif tmpConfig.ProjectID.Valid {\n\t\tconf.ProjectID = tmpConfig.ProjectID\n\t}\n\tif tmpConfig.Name.Valid {\n\t\tconf.Name = tmpConfig.Name\n\t}\n\tif tmpConfig.Token.Valid {\n\t\tconf.Token = tmpConfig.Token\n\t}\n\n\treturn nil\n}\n\n// GetTemporaryCloudConfig returns a temporary cloud config.\n// Original comment\n// TODO: Fix this\n// We reuse cloud.Config for parsing options.cloud, but this probably shouldn't be\n// done, as the idea of options.ext is that they are extensible without touching k6. But in\n// order for this to happen, we shouldn't actually marshal cloud.Config on top of it, because\n// it will be missing some fields that aren't actually mentioned in the struct.\n// So in order for use to copy the fields that we need for k6 cloud's api we unmarshal in\n// map[string]any and copy what we need if it isn't set already\nfunc GetTemporaryCloudConfig(cloudConfig json.RawMessage) (map[string]any, error) {\n\ttmpCloudConfig := make(map[string]any, 3)\n\tif cloudConfig == nil {\n\t\treturn tmpCloudConfig, nil\n\t}\n\n\tdec := json.NewDecoder(bytes.NewReader(cloudConfig))\n\tdec.UseNumber() // otherwise float64 are used\n\tif err := dec.Decode(&tmpCloudConfig); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tmpCloudConfig, nil\n}\n"
  },
  {
    "path": "internal/cloudapi/v6/config_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestConfigApply(t *testing.T) {\n\tt.Parallel()\n\tempty := Config{}\n\tdefaults := NewConfig()\n\n\tassert.Equal(t, empty, empty.Apply(empty))\n\tassert.Equal(t, empty, empty.Apply(defaults))\n\tassert.Equal(t, defaults, defaults.Apply(defaults))\n\tassert.Equal(t, defaults, defaults.Apply(empty))\n\tassert.Equal(t, defaults, defaults.Apply(empty).Apply(empty))\n\n\tfull := Config{\n\t\tToken:                 null.NewString(\"Token\", true),\n\t\tProjectID:             null.NewInt(1, true),\n\t\tName:                  null.NewString(\"Name\", true),\n\t\tHost:                  null.NewString(\"Host\", true),\n\t\tTimeout:               types.NewNullDuration(5*time.Second, true),\n\t\tLogsTailURL:           null.NewString(\"LogsTailURL\", true),\n\t\tPushRefID:             null.NewString(\"PushRefID\", true),\n\t\tWebAppURL:             null.NewString(\"foo\", true),\n\t\tNoCompress:            null.NewBool(true, true),\n\t\tStopOnError:           null.NewBool(true, true),\n\t\tAPIVersion:            null.NewInt(2, true),\n\t\tAggregationPeriod:     types.NewNullDuration(2*time.Second, true),\n\t\tAggregationWaitPeriod: types.NewNullDuration(4*time.Second, true),\n\t\tMaxTimeSeriesInBatch:  null.NewInt(3, true),\n\t\tMetricPushInterval:    types.NewNullDuration(1*time.Second, true),\n\t\tMetricPushConcurrency: null.NewInt(3, true),\n\t\tTracesEnabled:         null.NewBool(true, true),\n\t\tTracesHost:            null.NewString(\"TracesHost\", true),\n\t\tTracesPushInterval:    types.NewNullDuration(10*time.Second, true),\n\t\tTracesPushConcurrency: null.NewInt(6, true),\n\t}\n\n\tassert.Equal(t, full, full.Apply(empty))\n\tassert.Equal(t, full, full.Apply(defaults))\n\tassert.Equal(t, full, full.Apply(full))\n\tassert.Equal(t, full, empty.Apply(full))\n\tassert.Equal(t, full, defaults.Apply(full))\n}\n\nfunc TestGetConsolidatedConfig(t *testing.T) {\n\tt.Parallel()\n\tconfig, err := GetConsolidatedConfig(json.RawMessage(`{\"token\":\"jsonraw\"}`), nil, \"\", nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"jsonraw\", config.Token.String)\n\n\tconfig, err = GetConsolidatedConfig(\n\t\tjson.RawMessage(`{\"token\":\"jsonraw\"}`),\n\t\tnil,\n\t\t\"\",\n\t\tjson.RawMessage(`{\"token\":\"ext\"}`),\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"ext\", config.Token.String)\n\n\tconfig, err = GetConsolidatedConfig(\n\t\tjson.RawMessage(`{\"token\":\"jsonraw\"}`),\n\t\tmap[string]string{\"K6_CLOUD_TOKEN\": \"envvalue\"},\n\t\t\"\",\n\t\tjson.RawMessage(`{\"token\":\"ext\"}`),\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"envvalue\", config.Token.String)\n}\n\nfunc TestGetConsolidatedConfig_EnvHasHigherPriority(t *testing.T) {\n\tt.Parallel()\n\n\tconfig, err := GetConsolidatedConfig(\n\t\tjson.RawMessage(`{\"token\":\"jsonraw\"}`),\n\t\tmap[string]string{\"K6_CLOUD_TOKEN\": \"envvalue\"},\n\t\t\"\",\n\t\tjson.RawMessage(`{\"token\":\"cloud\"}`),\n\t)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, \"envvalue\", config.Token.String)\n}\n"
  },
  {
    "path": "internal/cloudapi/v6/doc.go",
    "content": "// Package cloudapi contains several things related to the k6 cloud API v6- various\n// data and config structures, a REST API client, error handling, etc. They\n// are all used in cloud tests (i.e. `k6 cloud`), and in local tests emitting\n// their results to the k6 cloud output (i.e. `k6 run --out cloud`).\npackage cloudapi\n"
  },
  {
    "path": "internal/cloudapi/v6/errors.go",
    "content": "package cloudapi\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\tk6cloud \"github.com/grafana/k6-cloud-openapi-client-go/k6\"\n)\n\nvar (\n\terrNotAuthorized    = errors.New(\"not allowed to upload result to k6 Cloud\")\n\terrNotAuthenticated = errors.New(\"failed to authenticate with k6 Cloud\")\n\terrUnknown          = errors.New(\"an error occurred communicating with k6 Cloud\")\n)\n\n// ResponseError represents an error cause by talking to the API\ntype ResponseError struct {\n\tResponse *http.Response        `json:\"-\"`\n\tAPIError k6cloud.ErrorApiModel `json:\"error\"`\n}\n\nfunc (e ResponseError) Error() string {\n\terr := e.APIError\n\tmsg := err.Message\n\n\tif err.Target.IsSet() {\n\t\tmsg += \" (target: '\" + *err.Target.Get() + \"')\"\n\t}\n\n\tdetails := make([]string, len(err.Details))\n\tfor i, v := range err.Details {\n\t\tdetails[i] = v.Message\n\t\tif v.Target.IsSet() {\n\t\t\tdetails[i] += \" (target: '\" + *v.Target.Get() + \"')\"\n\t\t}\n\t}\n\n\tif len(details) > 0 {\n\t\tmsg += \"\\n\" + strings.Join(details, \"\\n\")\n\t}\n\n\tvar code string\n\tswitch {\n\tcase err.Code != \"\" && e.Response != nil:\n\t\tcode = fmt.Sprintf(\"%d/%s\", e.Response.StatusCode, err.Code)\n\tcase e.Response != nil:\n\t\tcode = fmt.Sprintf(\"%d\", e.Response.StatusCode)\n\tcase err.Code != \"\":\n\t\tcode = err.Code\n\t}\n\n\tif len(code) > 0 {\n\t\tmsg = fmt.Sprintf(\"(%s) %s\", code, msg)\n\t}\n\n\treturn msg\n}\n"
  },
  {
    "path": "internal/cloudapi/v6/errors_test.go",
    "content": "package cloudapi\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\n\tk6cloud \"github.com/grafana/k6-cloud-openapi-client-go/k6\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestResponseError_Error(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\trespErr  ResponseError\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"basic error message\",\n\t\t\trespErr: ResponseError{\n\t\t\t\tAPIError: k6cloud.ErrorApiModel{\n\t\t\t\t\tMessage: \"test error\",\n\t\t\t\t\tCode:    \"error\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"(error) test error\",\n\t\t},\n\t\t{\n\t\t\tname: \"error with target\",\n\t\t\trespErr: ResponseError{\n\t\t\t\tAPIError: k6cloud.ErrorApiModel{\n\t\t\t\t\tMessage: \"validation failed\",\n\t\t\t\t\tTarget:  *k6cloud.NewNullableString(k6cloud.PtrString(\"field_name\")),\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"validation failed (target: 'field_name')\",\n\t\t},\n\t\t{\n\t\t\tname: \"error with details\",\n\t\t\trespErr: ResponseError{\n\t\t\t\tAPIError: k6cloud.ErrorApiModel{\n\t\t\t\t\tMessage: \"validation error\",\n\t\t\t\t\tDetails: []k6cloud.ErrorDetailsApiModel{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMessage: \"field is required\",\n\t\t\t\t\t\t\tTarget:  *k6cloud.NewNullableString(k6cloud.PtrString(\"first_property\")),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMessage: \"field must be positive\",\n\t\t\t\t\t\t\tTarget:  *k6cloud.NewNullableString(k6cloud.PtrString(\"second_property\")),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"validation error\\nfield is required (target: 'first_property')\\nfield must be positive (target: 'second_property')\",\n\t\t},\n\t\t{\n\t\t\tname: \"error with HTTP response and API code\",\n\t\t\trespErr: ResponseError{\n\t\t\t\tResponse: &http.Response{StatusCode: http.StatusBadRequest},\n\t\t\t\tAPIError: k6cloud.ErrorApiModel{\n\t\t\t\t\tMessage: \"bad request\",\n\t\t\t\t\tCode:    \"error\",\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: \"(400/error) bad request\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tresult := tt.respErr.Error()\n\t\t\tassert.Equal(t, tt.expected, result)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/archive.go",
    "content": "package cmd\n\nimport (\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"go.k6.io/k6/cmd/state\"\n)\n\n// cmdArchive handles the `k6 archive` sub-command\ntype cmdArchive struct {\n\tgs *state.GlobalState\n\n\tarchiveOut     string\n\texcludeEnvVars bool\n}\n\nfunc (c *cmdArchive) run(cmd *cobra.Command, args []string) error {\n\ttest, err := loadAndConfigureLocalTest(c.gs, cmd, args, getPartialConfig)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// It's important to NOT set the derived options back to the runner\n\t// here, only the consolidated ones. Otherwise, if the script used\n\t// an execution shortcut option (e.g. `iterations` or `duration`),\n\t// we will have multiple conflicting execution options since the\n\t// derivation will set `scenarios` as well.\n\ttestRunState, err := test.buildTestRunState(test.consolidatedConfig.Options)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Archive.\n\tarc := testRunState.Runner.MakeArchive()\n\n\tif c.excludeEnvVars {\n\t\tc.gs.Logger.Debug(\"environment variables will be excluded from the archive\")\n\n\t\tarc.Env = nil\n\t}\n\n\tif c.archiveOut == \"-\" {\n\t\treturn arc.Write(c.gs.Stdout)\n\t}\n\n\tf, err := c.gs.FS.Create(c.archiveOut)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = arc.Write(f)\n\tif cerr := f.Close(); err == nil && cerr != nil {\n\t\terr = cerr\n\t}\n\treturn err\n}\n\nfunc (c *cmdArchive) flagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", pflag.ContinueOnError)\n\tflags.SortFlags = false\n\tflags.AddFlagSet(optionFlagSet())\n\tflags.AddFlagSet(runtimeOptionFlagSet(false))\n\tflags.StringVarP(\n\t\t&c.archiveOut, \"archive-out\", \"O\", c.archiveOut,\n\t\t\"archive output filename. Dash (-) is a reserved value that causes the archive to be output to stdout.\",\n\t)\n\tflags.BoolVarP(\n\t\t&c.excludeEnvVars,\n\t\t\"exclude-env-vars\",\n\t\t\"\",\n\t\tfalse,\n\t\t\"do not embed any environment variables (either from --env or the actual environment) in the archive metadata\",\n\t)\n\n\treturn flags\n}\n\nfunc getCmdArchive(gs *state.GlobalState) *cobra.Command {\n\tc := &cmdArchive{\n\t\tgs:         gs,\n\t\tarchiveOut: \"archive.tar\",\n\t}\n\n\texampleText := getExampleText(gs, `\n  # Archive a test run.\n  {{.}} archive -u 10 -d 10s -O myarchive.tar script.js\n\n  # Run the resulting archive.\n  {{.}} run myarchive.tar`[1:])\n\n\tarchiveCmd := &cobra.Command{\n\t\tUse:   \"archive\",\n\t\tShort: \"Create an archive\",\n\t\tLong: `Create an archive.\n\nAn archive is a fully self-contained test run, and can be executed identically elsewhere.`,\n\t\tExample: exampleText,\n\t\tArgs:    cobra.ExactArgs(1),\n\t\tRunE:    c.run,\n\t}\n\n\tarchiveCmd.Flags().SortFlags = false\n\tarchiveCmd.Flags().AddFlagSet(c.flagSet())\n\n\treturn archiveCmd\n}\n"
  },
  {
    "path": "internal/cmd/archive_test.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestArchiveThresholds(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname         string\n\t\tnoThresholds bool\n\t\ttestFilename string\n\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname:         \"archive should fail with exit status 104 on a malformed threshold expression\",\n\t\t\tnoThresholds: false,\n\t\t\ttestFilename: \"testdata/thresholds/malformed_expression.js\",\n\t\t\twantErr:      true,\n\t\t},\n\t\t{\n\t\t\tname:         \"archive should on a malformed threshold expression but --no-thresholds flag set\",\n\t\t\tnoThresholds: true,\n\t\t\ttestFilename: \"testdata/thresholds/malformed_expression.js\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"run should fail with exit status 104 on a threshold applied to a non existing metric\",\n\t\t\tnoThresholds: false,\n\t\t\ttestFilename: \"testdata/thresholds/non_existing_metric.js\",\n\t\t\twantErr:      true,\n\t\t},\n\t\t{\n\t\t\tname:         \"run should succeed on a threshold applied to a non existing metric with the --no-thresholds flag set\",\n\t\t\tnoThresholds: true,\n\t\t\ttestFilename: \"testdata/thresholds/non_existing_metric.js\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"run should succeed on a threshold applied to a non existing submetric with the --no-thresholds flag set\",\n\t\t\tnoThresholds: true,\n\t\t\ttestFilename: \"testdata/thresholds/non_existing_metric.js\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"run should fail with exit status 104 on a threshold applying an unsupported aggregation method to a metric\",\n\t\t\tnoThresholds: false,\n\t\t\ttestFilename: \"testdata/thresholds/unsupported_aggregation_method.js\",\n\t\t\twantErr:      true,\n\t\t},\n\t\t{\n\t\t\tname:         \"run should succeed on a threshold applying an unsupported aggregation method to a metric with the --no-thresholds flag set\",\n\t\t\tnoThresholds: true,\n\t\t\ttestFilename: \"testdata/thresholds/unsupported_aggregation_method.js\",\n\t\t\twantErr:      false,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestScript, err := os.ReadFile(testCase.testFilename) //nolint:forbidigo\n\t\t\trequire.NoError(t, err)\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, testCase.testFilename), testScript, 0o644))\n\t\t\tts.CmdArgs = []string{\"k6\", \"archive\", testCase.testFilename}\n\t\t\tif testCase.noThresholds {\n\t\t\t\tts.CmdArgs = append(ts.CmdArgs, \"--no-thresholds\")\n\t\t\t}\n\n\t\t\tif testCase.wantErr {\n\t\t\t\tts.ExpectedExitCode = int(exitcodes.InvalidConfig)\n\t\t\t}\n\t\t\tnewRootCommand(ts.GlobalState).execute()\n\t\t})\n\t}\n}\n\nfunc TestArchiveContainsEnv(t *testing.T) {\n\tt.Parallel()\n\n\t// given some script that will be archived\n\tfileName := \"script.js\"\n\ttestScript := []byte(`export default function () {}`)\n\tts := tests.NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, fileName), testScript, 0o644))\n\n\t// when we do archiving and passing the `--env` flags\n\tts.CmdArgs = []string{\"k6\", \"--env\", \"ENV1=lorem\", \"--env\", \"ENV2=ipsum\", \"archive\", fileName}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\trequire.NoError(t, testutils.Untar(t, ts.FS, \"archive.tar\", \"tmp/\"))\n\n\tdata, err := fsext.ReadFile(ts.FS, \"tmp/metadata.json\")\n\trequire.NoError(t, err)\n\n\tmetadata := struct {\n\t\tEnv map[string]string\n\t}{}\n\n\t// then unpacked metadata should contain the environment variables with the proper values\n\trequire.NoError(t, json.Unmarshal(data, &metadata))\n\trequire.Len(t, metadata.Env, 2)\n\n\trequire.Contains(t, metadata.Env, \"ENV1\")\n\trequire.Contains(t, metadata.Env, \"ENV2\")\n\n\trequire.Equal(t, \"lorem\", metadata.Env[\"ENV1\"])\n\trequire.Equal(t, \"ipsum\", metadata.Env[\"ENV2\"])\n}\n\nfunc TestArchiveContainsLegacyCloudSettings(t *testing.T) {\n\tt.Parallel()\n\n\t// given a script with the cloud options\n\tfileName := \"script.js\"\n\ttestScript := []byte(`\n\t\texport let options = {\n\t\t\text: {\n\t\t\t\tloadimpact: {\n\t\t\t\t\tdistribution: {\n\t\t\t\t\t\tone: { loadZone: 'amazon:us:ashburn', percent: 30 },\n\t\t\t\t\t\ttwo: { loadZone: 'amazon:ie:dublin', percent: 70 },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\texport default function () {}\n\t`)\n\tts := tests.NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, fileName), testScript, 0o644))\n\n\t// when we do archiving\n\tts.CmdArgs = []string{\"k6\", \"archive\", fileName}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\trequire.NoError(t, testutils.Untar(t, ts.FS, \"archive.tar\", \"tmp/\"))\n\n\tdata, err := fsext.ReadFile(ts.FS, \"tmp/metadata.json\")\n\trequire.NoError(t, err)\n\n\t// we just need some basic struct\n\tmetadata := struct {\n\t\tOptions struct {\n\t\t\tExt struct {\n\t\t\t\tLoadImpact struct {\n\t\t\t\t\tDistribution map[string]struct {\n\t\t\t\t\t\tLoadZone string  `json:\"loadZone\"`\n\t\t\t\t\t\tPercent  float64 `json:\"percent\"`\n\t\t\t\t\t} `json:\"distribution\"`\n\t\t\t\t} `json:\"loadimpact\"`\n\t\t\t} `json:\"ext\"`\n\t\t} `json:\"options\"`\n\t}{}\n\n\t// then unpacked metadata should contain a ext.loadimpact struct the proper values\n\trequire.NoError(t, json.Unmarshal(data, &metadata))\n\trequire.Len(t, metadata.Options.Ext.LoadImpact.Distribution, 2)\n\n\trequire.Equal(t, \"amazon:us:ashburn\", metadata.Options.Ext.LoadImpact.Distribution[\"one\"].LoadZone)\n\trequire.Equal(t, 30., metadata.Options.Ext.LoadImpact.Distribution[\"one\"].Percent)\n\trequire.Equal(t, \"amazon:ie:dublin\", metadata.Options.Ext.LoadImpact.Distribution[\"two\"].LoadZone)\n\trequire.Equal(t, 70., metadata.Options.Ext.LoadImpact.Distribution[\"two\"].Percent)\n}\n\nfunc TestArchiveContainsCloudSettings(t *testing.T) {\n\tt.Parallel()\n\n\t// given a script with the cloud options\n\tfileName := \"script.js\"\n\ttestScript := []byte(`\n\t\texport let options = {\n\t\t\tcloud: {\n\t\t\t\tdistribution: {\n\t\t\t\t\tone: { loadZone: 'amazon:us:ashburn', percent: 30 },\n\t\t\t\t\ttwo: { loadZone: 'amazon:ie:dublin', percent: 70 },\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\texport default function () {}\n\t`)\n\tts := tests.NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, fileName), testScript, 0o644))\n\n\t// when we do archiving\n\tts.CmdArgs = []string{\"k6\", \"archive\", fileName}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\trequire.NoError(t, testutils.Untar(t, ts.FS, \"archive.tar\", \"tmp/\"))\n\n\tdata, err := fsext.ReadFile(ts.FS, \"tmp/metadata.json\")\n\trequire.NoError(t, err)\n\n\t// we just need some basic struct\n\tmetadata := struct {\n\t\tOptions struct {\n\t\t\tCloud struct {\n\t\t\t\tDistribution map[string]struct {\n\t\t\t\t\tLoadZone string  `json:\"loadZone\"`\n\t\t\t\t\tPercent  float64 `json:\"percent\"`\n\t\t\t\t} `json:\"distribution\"`\n\t\t\t} `json:\"cloud\"`\n\t\t} `json:\"options\"`\n\t}{}\n\n\t// then unpacked metadata should contain options.cloud\n\trequire.NoError(t, json.Unmarshal(data, &metadata))\n\trequire.Len(t, metadata.Options.Cloud.Distribution, 2)\n\n\trequire.Equal(t, \"amazon:us:ashburn\", metadata.Options.Cloud.Distribution[\"one\"].LoadZone)\n\trequire.Equal(t, 30., metadata.Options.Cloud.Distribution[\"one\"].Percent)\n\trequire.Equal(t, \"amazon:ie:dublin\", metadata.Options.Cloud.Distribution[\"two\"].LoadZone)\n\trequire.Equal(t, 70., metadata.Options.Cloud.Distribution[\"two\"].Percent)\n}\n\nfunc TestArchiveNotContainsEnv(t *testing.T) {\n\tt.Parallel()\n\n\t// given some script that will be archived\n\tfileName := \"script.js\"\n\ttestScript := []byte(`export default function () {}`)\n\tts := tests.NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, fileName), testScript, 0o644))\n\n\t// when we do archiving and passing the `--env` flags altogether with `--exclude-env-vars` flag\n\tts.CmdArgs = []string{\"k6\", \"--env\", \"ENV1=lorem\", \"--env\", \"ENV2=ipsum\", \"archive\", \"--exclude-env-vars\", fileName}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\trequire.NoError(t, testutils.Untar(t, ts.FS, \"archive.tar\", \"tmp/\"))\n\n\tdata, err := fsext.ReadFile(ts.FS, \"tmp/metadata.json\")\n\trequire.NoError(t, err)\n\n\tmetadata := struct {\n\t\tEnv map[string]string\n\t}{}\n\n\t// then unpacked metadata should not contain any environment variables passed at the moment of archive creation\n\trequire.NoError(t, json.Unmarshal(data, &metadata))\n\trequire.Len(t, metadata.Env, 0)\n}\n\nfunc TestArchiveStdout(t *testing.T) {\n\tt.Parallel()\n\n\t// given some script that will be archived\n\tfileName := \"script.js\"\n\ttestScript := []byte(`export default function () {}`)\n\tts := tests.NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, fileName), testScript, 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"archive\", \"-O\", \"-\", fileName}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tfor _, filename := range []string{\"-\", \"archive.tar\"} {\n\t\t_, err := ts.FS.Stat(filename)\n\t\trequire.ErrorIsf(t, err, fs.ErrNotExist, \"%q should not exist\", filename)\n\t}\n\n\trequire.GreaterOrEqual(t, len(ts.Stdout.Bytes()), 32)\n}\n"
  },
  {
    "path": "internal/cmd/builtin_output_gen.go",
    "content": "// Code generated by \"enumer -type=builtinOutput -trimprefix builtinOutput -transform=kebab -output builtin_output_gen.go\"; DO NOT EDIT.\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _builtinOutputName = \"cloudcsvdatadogexperimental-prometheus-rwinfluxdbjsonkafkastatsdexperimental-opentelemetryopentelemetrysummary\"\n\nvar _builtinOutputIndex = [...]uint8{0, 5, 8, 15, 41, 49, 53, 58, 64, 90, 103, 110}\n\nconst _builtinOutputLowerName = \"cloudcsvdatadogexperimental-prometheus-rwinfluxdbjsonkafkastatsdexperimental-opentelemetryopentelemetrysummary\"\n\nfunc (i builtinOutput) String() string {\n\tif i >= builtinOutput(len(_builtinOutputIndex)-1) {\n\t\treturn fmt.Sprintf(\"builtinOutput(%d)\", i)\n\t}\n\treturn _builtinOutputName[_builtinOutputIndex[i]:_builtinOutputIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _builtinOutputNoOp() {\n\tvar x [1]struct{}\n\t_ = x[builtinOutputCloud-(0)]\n\t_ = x[builtinOutputCSV-(1)]\n\t_ = x[builtinOutputDatadog-(2)]\n\t_ = x[builtinOutputExperimentalPrometheusRW-(3)]\n\t_ = x[builtinOutputInfluxdb-(4)]\n\t_ = x[builtinOutputJSON-(5)]\n\t_ = x[builtinOutputKafka-(6)]\n\t_ = x[builtinOutputStatsd-(7)]\n\t_ = x[builtinOutputExperimentalOpentelemetry-(8)]\n\t_ = x[builtinOutputOpentelemetry-(9)]\n\t_ = x[builtinOutputSummary-(10)]\n}\n\nvar _builtinOutputValues = []builtinOutput{builtinOutputCloud, builtinOutputCSV, builtinOutputDatadog, builtinOutputExperimentalPrometheusRW, builtinOutputInfluxdb, builtinOutputJSON, builtinOutputKafka, builtinOutputStatsd, builtinOutputExperimentalOpentelemetry, builtinOutputOpentelemetry, builtinOutputSummary}\n\nvar _builtinOutputNameToValueMap = map[string]builtinOutput{\n\t_builtinOutputName[0:5]:          builtinOutputCloud,\n\t_builtinOutputLowerName[0:5]:     builtinOutputCloud,\n\t_builtinOutputName[5:8]:          builtinOutputCSV,\n\t_builtinOutputLowerName[5:8]:     builtinOutputCSV,\n\t_builtinOutputName[8:15]:         builtinOutputDatadog,\n\t_builtinOutputLowerName[8:15]:    builtinOutputDatadog,\n\t_builtinOutputName[15:41]:        builtinOutputExperimentalPrometheusRW,\n\t_builtinOutputLowerName[15:41]:   builtinOutputExperimentalPrometheusRW,\n\t_builtinOutputName[41:49]:        builtinOutputInfluxdb,\n\t_builtinOutputLowerName[41:49]:   builtinOutputInfluxdb,\n\t_builtinOutputName[49:53]:        builtinOutputJSON,\n\t_builtinOutputLowerName[49:53]:   builtinOutputJSON,\n\t_builtinOutputName[53:58]:        builtinOutputKafka,\n\t_builtinOutputLowerName[53:58]:   builtinOutputKafka,\n\t_builtinOutputName[58:64]:        builtinOutputStatsd,\n\t_builtinOutputLowerName[58:64]:   builtinOutputStatsd,\n\t_builtinOutputName[64:90]:        builtinOutputExperimentalOpentelemetry,\n\t_builtinOutputLowerName[64:90]:   builtinOutputExperimentalOpentelemetry,\n\t_builtinOutputName[90:103]:       builtinOutputOpentelemetry,\n\t_builtinOutputLowerName[90:103]:  builtinOutputOpentelemetry,\n\t_builtinOutputName[103:110]:      builtinOutputSummary,\n\t_builtinOutputLowerName[103:110]: builtinOutputSummary,\n}\n\nvar _builtinOutputNames = []string{\n\t_builtinOutputName[0:5],\n\t_builtinOutputName[5:8],\n\t_builtinOutputName[8:15],\n\t_builtinOutputName[15:41],\n\t_builtinOutputName[41:49],\n\t_builtinOutputName[49:53],\n\t_builtinOutputName[53:58],\n\t_builtinOutputName[58:64],\n\t_builtinOutputName[64:90],\n\t_builtinOutputName[90:103],\n\t_builtinOutputName[103:110],\n}\n\n// builtinOutputString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc builtinOutputString(s string) (builtinOutput, error) {\n\tif val, ok := _builtinOutputNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _builtinOutputNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to builtinOutput values\", s)\n}\n\n// builtinOutputValues returns all values of the enum\nfunc builtinOutputValues() []builtinOutput {\n\treturn _builtinOutputValues\n}\n\n// builtinOutputStrings returns a slice of all String values of the enum\nfunc builtinOutputStrings() []string {\n\tstrs := make([]string, len(_builtinOutputNames))\n\tcopy(strs, _builtinOutputNames)\n\treturn strs\n}\n\n// IsAbuiltinOutput returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i builtinOutput) IsAbuiltinOutput() bool {\n\tfor _, v := range _builtinOutputValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/cmd/cloud.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n)\n\n// errUserUnauthenticated represents an authentication error when trying to use\n// Grafana Cloud without being logged in or having a valid token.\n//\n//nolint:staticcheck // the error is shown to the user so here punctuation and capital are required\nvar errUserUnauthenticated = errors.New(\"To run tests in Grafana Cloud, you must first authenticate.\" +\n\t\" Run the `k6 cloud login` command, or check the docs\" +\n\t\" https://grafana.com/docs/grafana-cloud/testing/k6/author-run/tokens-and-cli-authentication\" +\n\t\" for additional authentication methods.\")\n\n// cmdCloud handles the `k6 cloud` sub-command\ntype cmdCloud struct {\n\tgs *state.GlobalState\n\n\tshowCloudLogs bool\n\texitOnRunning bool\n\tuploadOnly    bool\n}\n\nfunc (c *cmdCloud) preRun(cmd *cobra.Command, _ []string) error {\n\t// TODO: refactor (https://github.com/loadimpact/k6/issues/883)\n\t//\n\t// We deliberately parse the env variables, to validate for wrong\n\t// values, even if we don't subsequently use them (if the respective\n\t// CLI flag was specified, since it has a higher priority).\n\tif showCloudLogsEnv, ok := c.gs.Env[\"K6_SHOW_CLOUD_LOGS\"]; ok {\n\t\tshowCloudLogsValue, err := strconv.ParseBool(showCloudLogsEnv)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing K6_SHOW_CLOUD_LOGS returned an error: %w\", err)\n\t\t}\n\t\tif !cmd.Flags().Changed(\"show-logs\") {\n\t\t\tc.showCloudLogs = showCloudLogsValue\n\t\t}\n\t}\n\n\tif exitOnRunningEnv, ok := c.gs.Env[\"K6_EXIT_ON_RUNNING\"]; ok {\n\t\texitOnRunningValue, err := strconv.ParseBool(exitOnRunningEnv)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing K6_EXIT_ON_RUNNING returned an error: %w\", err)\n\t\t}\n\t\tif !cmd.Flags().Changed(\"exit-on-running\") {\n\t\t\tc.exitOnRunning = exitOnRunningValue\n\t\t}\n\t}\n\tif uploadOnlyEnv, ok := c.gs.Env[\"K6_CLOUD_UPLOAD_ONLY\"]; ok {\n\t\tuploadOnlyValue, err := strconv.ParseBool(uploadOnlyEnv)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing K6_CLOUD_UPLOAD_ONLY returned an error: %w\", err)\n\t\t}\n\t\tif !cmd.Flags().Changed(\"upload-only\") {\n\t\t\tc.uploadOnly = uploadOnlyValue\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// TODO: split apart some more\n//\n//nolint:funlen,gocognit,cyclop\nfunc (c *cmdCloud) run(cmd *cobra.Command, args []string) error {\n\t// If no args provided and called from main cloud command, show helpful error\n\tif cmd.Name() == \"cloud\" && len(args) == 0 {\n\t\treturn errors.New(\"the \\\"k6 cloud\\\" command expects either a subcommand such as \\\"run\\\" or \\\"login\\\", \" +\n\t\t\t\"or a single argument consisting in a path to a script/archive, or the `-` symbol instructing \" +\n\t\t\t\"the command to read the test content from stdin; received no arguments\")\n\t}\n\n\t// Show deprecation warning only when running tests directly via \"k6 cloud <file>\"\n\t// (not when using subcommands like \"k6 cloud run\")\n\tif cmd.Name() == \"cloud\" && len(args) > 0 {\n\t\tc.gs.Logger.Warn(\"Running tests directly with \\\"k6 cloud <file>\\\" is deprecated. \" +\n\t\t\t\"Use \\\"k6 cloud run <file>\\\" instead. This behavior will be removed in a future release.\")\n\t}\n\n\ttest, err := loadAndConfigureLocalTest(c.gs, cmd, args, getPartialConfig)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// It's important to NOT set the derived options back to the runner\n\t// here, only the consolidated ones. Otherwise, if the script used\n\t// an execution shortcut option (e.g. `iterations` or `duration`),\n\t// we will have multiple conflicting execution options since the\n\t// derivation will set `scenarios` as well.\n\ttestRunState, err := test.buildTestRunState(test.consolidatedConfig.Options)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// TODO: validate for usage of execution segment\n\t// TODO: validate for externally controlled executor (i.e. executors that aren't distributable)\n\t// TODO: move those validations to a separate function and reuse validateConfig()?\n\tprintBanner(c.gs)\n\n\tprogressBar := pb.New(\n\t\tpb.WithConstLeft(\"Init\"),\n\t\tpb.WithConstProgress(0, \"Loading test script...\"),\n\t)\n\tprintBar(c.gs, progressBar)\n\n\tmodifyAndPrintBar(c.gs, progressBar, pb.WithConstProgress(0, \"Building the archive...\"))\n\tarc := testRunState.Runner.MakeArchive()\n\n\ttmpCloudConfig, err := cloudapi.GetTemporaryCloudConfig(arc.Options.Cloud, arc.Options.External)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Cloud config\n\tcloudConfig, warn, err := cloudapi.GetConsolidatedConfig(\n\t\ttest.derivedConfig.Collectors[\"cloud\"], c.gs.Env, \"\", arc.Options.Cloud, arc.Options.External)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !cloudConfig.Token.Valid {\n\t\treturn errUserUnauthenticated\n\t}\n\n\t// Display config warning if needed\n\tif warn != \"\" {\n\t\tmodifyAndPrintBar(c.gs, progressBar, pb.WithConstProgress(0, \"Warning: \"+warn))\n\t}\n\n\tif cloudConfig.Token.Valid {\n\t\ttmpCloudConfig[\"token\"] = cloudConfig.Token\n\t}\n\tif cloudConfig.Name.Valid {\n\t\ttmpCloudConfig[\"name\"] = cloudConfig.Name\n\t}\n\tif cloudConfig.ProjectID.Valid {\n\t\ttmpCloudConfig[\"projectID\"] = cloudConfig.ProjectID\n\t}\n\n\tif arc.Options.External == nil {\n\t\tarc.Options.External = make(map[string]json.RawMessage)\n\t}\n\n\tb, err := json.Marshal(tmpCloudConfig)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tarc.Options.Cloud = b\n\tarc.Options.External[cloudapi.LegacyCloudConfigKey] = b\n\n\tname := cloudConfig.Name.String\n\tif !cloudConfig.Name.Valid || cloudConfig.Name.String == \"\" {\n\t\tname = filepath.Base(test.sourceRootPath)\n\t}\n\n\tglobalCtx, globalCancel := context.WithCancel(c.gs.Ctx)\n\tdefer globalCancel()\n\n\tlogger := c.gs.Logger\n\n\t// Start cloud test run\n\tmodifyAndPrintBar(c.gs, progressBar, pb.WithConstProgress(0, \"Validating script options\"))\n\tclient := cloudapi.NewClient(\n\t\tlogger, cloudConfig.Token.String, cloudConfig.Host.String, build.Version, cloudConfig.Timeout.TimeDuration())\n\tif cloudConfig.StackID.Valid {\n\t\tclient.SetStackID(cloudConfig.StackID.Int64)\n\t}\n\tif err = client.ValidateOptions(arc.Options); err != nil {\n\t\treturn err\n\t}\n\n\tif cloudConfig.ProjectID.Int64 == 0 {\n\t\tif err := resolveAndSetProjectID(c.gs, &cloudConfig, tmpCloudConfig, arc); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tmodifyAndPrintBar(c.gs, progressBar, pb.WithConstProgress(0, \"Uploading archive\"))\n\n\tvar cloudTestRun *cloudapi.CreateTestRunResponse\n\tif c.uploadOnly {\n\t\tcloudTestRun, err = client.UploadTestOnly(name, cloudConfig.ProjectID.Int64, arc)\n\t} else {\n\t\tcloudTestRun, err = client.StartCloudTestRun(name, cloudConfig.ProjectID.Int64, arc)\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\trefID := cloudTestRun.ReferenceID\n\tif cloudTestRun.ConfigOverride != nil {\n\t\tcloudConfig = cloudConfig.Apply(*cloudTestRun.ConfigOverride)\n\t}\n\n\t// Trap Interrupts, SIGINTs and SIGTERMs.\n\tgracefulStop := func(sig os.Signal) {\n\t\tlogger.WithField(\"sig\", sig).Print(\"Stopping cloud test run in response to signal...\")\n\t\t// Do this in a separate goroutine so that if it blocks, the\n\t\t// second signal can still abort the process execution.\n\t\tgo func() {\n\t\t\tstopErr := client.StopCloudTestRun(refID)\n\t\t\tif stopErr != nil {\n\t\t\t\tlogger.WithError(stopErr).Error(\"Stop cloud test error\")\n\t\t\t} else {\n\t\t\t\tlogger.Info(\"Successfully sent signal to stop the cloud test, now waiting for it to actually stop...\")\n\t\t\t}\n\t\t\tglobalCancel()\n\t\t}()\n\t}\n\tonHardStop := func(sig os.Signal) {\n\t\tlogger.WithField(\"sig\", sig).Error(\"Aborting k6 in response to signal, we won't wait for the test to end.\")\n\t}\n\tstopSignalHandling := handleTestAbortSignals(c.gs, gracefulStop, onHardStop)\n\tdefer stopSignalHandling()\n\n\tet, err := lib.NewExecutionTuple(test.derivedConfig.ExecutionSegment, test.derivedConfig.ExecutionSegmentSequence)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttestURL := cloudapi.URLForResults(refID, cloudConfig)\n\texecutionPlan := test.derivedConfig.Scenarios.GetFullExecutionRequirements(et)\n\tprintExecutionDescription(\n\t\tc.gs, \"cloud\", test.sourceRootPath, testURL, test.derivedConfig, et, executionPlan, nil,\n\t)\n\n\tmodifyAndPrintBar(\n\t\tc.gs, progressBar,\n\t\tpb.WithConstLeft(\"Run \"), pb.WithConstProgress(0, \"Initializing the cloud test\"),\n\t)\n\n\tprogressCtx, progressCancel := context.WithCancel(globalCtx)\n\tprogressBarWG := &sync.WaitGroup{}\n\tprogressBarWG.Add(1)\n\tdefer progressBarWG.Wait()\n\tdefer progressCancel()\n\tgo func() {\n\t\tshowProgress(progressCtx, c.gs, []*pb.ProgressBar{progressBar}, logger)\n\t\tprogressBarWG.Done()\n\t}()\n\n\tvar (\n\t\tstartTime   time.Time\n\t\tmaxDuration time.Duration\n\t)\n\tmaxDuration, _ = lib.GetEndOffset(executionPlan)\n\n\ttestProgressLock := &sync.Mutex{}\n\tvar testProgress *cloudapi.TestProgressResponse\n\tprogressBar.Modify(\n\t\tpb.WithProgress(func() (float64, []string) {\n\t\t\ttestProgressLock.Lock()\n\t\t\tdefer testProgressLock.Unlock()\n\n\t\t\tif testProgress == nil {\n\t\t\t\treturn 0, []string{\"Waiting...\"}\n\t\t\t}\n\n\t\t\tstatusText := testProgress.RunStatusText\n\n\t\t\tswitch testProgress.RunStatus { //nolint:exhaustive\n\t\t\tcase cloudapi.RunStatusFinished:\n\t\t\t\ttestProgress.Progress = 1\n\t\t\tcase cloudapi.RunStatusRunning:\n\t\t\t\tif startTime.IsZero() {\n\t\t\t\t\tstartTime = time.Now()\n\t\t\t\t}\n\t\t\t\tspent := time.Since(startTime)\n\t\t\t\tif spent > maxDuration {\n\t\t\t\t\tstatusText = maxDuration.String()\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = fmt.Sprintf(\"%s/%s\", pb.GetFixedLengthDuration(spent, maxDuration), maxDuration)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn testProgress.Progress, []string{statusText}\n\t\t}),\n\t)\n\n\tticker := time.NewTicker(time.Millisecond * 2000)\n\tif c.showCloudLogs {\n\t\tgo func() {\n\t\t\tlogger.Debug(\"Connecting to cloud logs server...\")\n\t\t\tif err := cloudConfig.StreamLogsToLogger(globalCtx, logger, refID, 0); err != nil {\n\t\t\t\tlogger.WithError(err).Error(\"error while tailing cloud logs\")\n\t\t\t}\n\t\t}()\n\t}\n\n\tfor range ticker.C {\n\t\tnewTestProgress, progressErr := client.GetTestProgress(refID)\n\t\tif progressErr != nil {\n\t\t\tlogger.WithError(progressErr).Error(\"Test progress error\")\n\t\t\tcontinue\n\t\t}\n\n\t\ttestProgressLock.Lock()\n\t\ttestProgress = newTestProgress\n\t\ttestProgressLock.Unlock()\n\n\t\tif (newTestProgress.RunStatus > cloudapi.RunStatusRunning) ||\n\t\t\t(c.exitOnRunning && newTestProgress.RunStatus == cloudapi.RunStatusRunning) {\n\t\t\tglobalCancel()\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif testProgress == nil {\n\t\t//nolint:staticcheck\n\t\treturn errext.WithExitCodeIfNone(errors.New(\"Test progress error\"), exitcodes.CloudFailedToGetProgress)\n\t}\n\n\tif !c.gs.Flags.Quiet {\n\t\tvalueColor := getColor(c.gs.Flags.NoColor || !c.gs.Stdout.IsTTY, color.FgCyan)\n\t\tprintToStdout(c.gs, fmt.Sprintf(\n\t\t\t\"     test status: %s\\n\", valueColor.Sprint(testProgress.RunStatusText),\n\t\t))\n\t} else {\n\t\tlogger.WithField(\"run_status\", testProgress.RunStatusText).Debug(\"Test finished\")\n\t}\n\n\tif testProgress.ResultStatus == cloudapi.ResultStatusFailed {\n\t\t// Although by looking at [ResultStatus] and [RunStatus] isn't self-explanatory,\n\t\t// the scenario when the test run has finished, but it failed is an exceptional case for those situations\n\t\t// when thresholds have been crossed (failed). So, we report this situation as such.\n\t\tif testProgress.RunStatus == cloudapi.RunStatusFinished ||\n\t\t\ttestProgress.RunStatus == cloudapi.RunStatusAbortedThreshold {\n\t\t\t//nolint:staticcheck\n\t\t\treturn errext.WithExitCodeIfNone(errors.New(\"Thresholds have been crossed\"), exitcodes.ThresholdsHaveFailed)\n\t\t}\n\n\t\t// TODO: use different exit codes for failed thresholds vs failed test (e.g. aborted by system/limit)\n\t\treturn errext.WithExitCodeIfNone(errors.New(\"The test has failed\"), exitcodes.CloudTestRunFailed) //nolint:staticcheck\n\t}\n\n\treturn nil\n}\n\nfunc (c *cmdCloud) flagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", pflag.ContinueOnError)\n\tflags.SortFlags = false\n\tflags.AddFlagSet(optionFlagSet())\n\tflags.AddFlagSet(runtimeOptionFlagSet(false))\n\n\t// TODO: Figure out a better way to handle the CLI flags\n\tflags.BoolVar(&c.exitOnRunning, \"exit-on-running\", c.exitOnRunning,\n\t\t\"exits when test reaches the running status\")\n\tflags.BoolVar(&c.showCloudLogs, \"show-logs\", c.showCloudLogs,\n\t\t\"enable showing of logs when a test is executed in the cloud\")\n\tflags.BoolVar(&c.uploadOnly, \"upload-only\", c.uploadOnly,\n\t\t\"only upload the test to the cloud without actually starting a test run\")\n\tif err := flags.MarkDeprecated(\"upload-only\", \"use \\\"k6 cloud upload\\\" instead\"); err != nil {\n\t\tpanic(err) // Should never happen\n\t}\n\n\treturn flags\n}\n\nfunc getCmdCloud(gs *state.GlobalState) *cobra.Command {\n\tc := &cmdCloud{\n\t\tgs:            gs,\n\t\tshowCloudLogs: true,\n\t\texitOnRunning: false,\n\t\tuploadOnly:    false,\n\t}\n\n\texampleText := getExampleText(gs, `\n  # [deprecated] Run a test script in Grafana Cloud\n  $ {{.}} cloud script.js\n\n  # [deprecated] Run a test archive in Grafana Cloud\n  $ {{.}} cloud archive.tar\n\n  # Authenticate with Grafana Cloud\n  $ {{.}} cloud login\n\n  # Run a test script in Grafana Cloud\n  $ {{.}} cloud run script.js\n\n  # Run a test archive in Grafana Cloud\n  $ {{.}} cloud run archive.tar`[1:])\n\n\tcloudCmd := &cobra.Command{\n\t\tUse:     \"cloud\",\n\t\tShort:   \"Run and manage Grafana Cloud tests\",\n\t\tLong:    \"Run and manage tests in Grafana Cloud.\",\n\t\tExample: exampleText,\n\t\tPreRunE: c.preRun,\n\t\tRunE:    c.run,\n\t}\n\n\t// Register `k6 cloud` subcommands with default usage template\n\tdefaultUsageTemplate := (&cobra.Command{}).UsageTemplate()\n\tdefaultUsageTemplate = strings.ReplaceAll(defaultUsageTemplate, \"FlagUsages\", \"FlagUsagesWrapped 120\")\n\n\trunCmd := getCmdCloudRun(c)\n\trunCmd.SetUsageTemplate(defaultUsageTemplate)\n\tcloudCmd.AddCommand(runCmd)\n\n\tloginCmd := getCmdCloudLogin(gs)\n\tloginCmd.SetUsageTemplate(defaultUsageTemplate)\n\tcloudCmd.AddCommand(loginCmd)\n\n\tuploadCmd := getCmdCloudUpload(c)\n\tuploadCmd.SetUsageTemplate(defaultUsageTemplate)\n\tcloudCmd.AddCommand(uploadCmd)\n\n\tcloudCmd.Flags().SortFlags = false\n\tcloudCmd.Flags().AddFlagSet(c.flagSet())\n\n\tcloudCmd.SetUsageTemplate(`Usage:\n  {{.CommandPath}} [command]\n\nCommands:{{range .Commands}}{{if (or (eq .Name \"login\") (eq .Name \"run\"))}}\n  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{range .Commands}}` +\n\t\t`{{if and .IsAvailableCommand (ne .Name \"login\") (ne .Name \"run\")}}\n  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}\n\nFlags:\n  -h, --help   Show help\n{{if .HasExample}}\nExamples:\n{{.Example}}\n{{end}}\nUse \"{{.CommandPath}} [command] --help\" for more information about a command.\n`)\n\n\treturn cloudCmd\n}\n\nfunc resolveDefaultProjectID(\n\tgs *state.GlobalState,\n\tcloudConfig *cloudapi.Config,\n) (int64, error) {\n\t// Priority: projectID -> default stack from config\n\tif cloudConfig.ProjectID.Valid && cloudConfig.ProjectID.Int64 > 0 {\n\t\treturn cloudConfig.ProjectID.Int64, nil\n\t}\n\tif cloudConfig.StackID.Valid && cloudConfig.StackID.Int64 != 0 {\n\t\tif cloudConfig.DefaultProjectID.Valid && cloudConfig.DefaultProjectID.Int64 > 0 {\n\t\t\tstackName := cloudConfig.StackURL.String\n\t\t\tif !cloudConfig.StackURL.Valid {\n\t\t\t\tstackName = fmt.Sprintf(\"stack-%d\", cloudConfig.StackID.Int64)\n\t\t\t}\n\t\t\tgs.Logger.Warnf(\"No projectID specified, using default project of the %s stack\\n\", stackName)\n\t\t\treturn cloudConfig.DefaultProjectID.Int64, nil\n\t\t}\n\t\treturn 0, fmt.Errorf(\n\t\t\t\"default stack configured but the default project ID is not available - \" +\n\t\t\t\t\"please run `k6 cloud login` to refresh your configuration\")\n\t}\n\n\t// Return 0 to let the backend pick the project (old behavior)\n\treturn 0, nil\n}\n\nfunc resolveAndSetProjectID(\n\tgs *state.GlobalState,\n\tcloudConfig *cloudapi.Config,\n\ttmpCloudConfig map[string]any,\n\tarc *lib.Archive,\n) error {\n\tprojectID, err := resolveDefaultProjectID(gs, cloudConfig)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif projectID > 0 {\n\t\ttmpCloudConfig[\"projectID\"] = projectID\n\n\t\tb, err := json.Marshal(tmpCloudConfig)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tarc.Options.Cloud = b\n\t\tarc.Options.External[cloudapi.LegacyCloudConfigKey] = b\n\n\t\tcloudConfig.ProjectID = null.IntFrom(projectID)\n\t}\n\tif !cloudConfig.StackID.Valid || cloudConfig.StackID.Int64 == 0 {\n\t\tfallBackMsg := \"\"\n\t\tif !cloudConfig.ProjectID.Valid || cloudConfig.ProjectID.Int64 == 0 {\n\t\t\tfallBackMsg = \"Falling back to the first available stack. \"\n\t\t}\n\t\tgs.Logger.Warn(\"DEPRECATED: No stack specified. \" + fallBackMsg +\n\t\t\t\"Consider setting a default stack via the `k6 cloud login` command or the `K6_CLOUD_STACK_ID` \" +\n\t\t\t\"environment variable as this will become mandatory in the next major release.\")\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/cmd/cloud_login.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/term\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/build\"\n\tv6cloudapi \"go.k6.io/k6/internal/cloudapi/v6\"\n\t\"go.k6.io/k6/internal/ui\"\n)\n\nconst cloudLoginCommandName = \"login\"\n\ntype cmdCloudLogin struct {\n\tglobalState *state.GlobalState\n}\n\nfunc getCmdCloudLogin(gs *state.GlobalState) *cobra.Command {\n\tc := &cmdCloudLogin{\n\t\tglobalState: gs,\n\t}\n\n\t// loginCloudCommand represents the 'cloud login' command\n\texampleText := getExampleText(gs, `\n  # Authenticate interactively with Grafana Cloud\n  $ {{.}} cloud login\n\n  # Store a token in k6's persistent configuration\n  $ {{.}} cloud login -t <YOUR_TOKEN>\n\n  # Store a token in k6's persistent configuration and set the stack\n  $ {{.}} cloud login -t <YOUR_TOKEN> --stack <YOUR_STACK_URL_OR_SLUG>\n\n  # Display the stored token and stack info\n  $ {{.}} cloud login -s\n\n  # Reset the stored token and stack info\n  $ {{.}} cloud login -r`[1:])\n\n\tloginCloudCommand := &cobra.Command{\n\t\tUse:     cloudLoginCommandName,\n\t\tShort:   \"Authenticate with Grafana Cloud\",\n\t\tLong:    \"Authenticate with Grafana Cloud. Required before running cloud tests.\",\n\t\tExample: exampleText,\n\t\tArgs:    cobra.NoArgs,\n\t\tRunE:    c.run,\n\t}\n\n\tloginCloudCommand.Flags().StringP(\"token\", \"t\", \"\", \"specify `token` to use\")\n\tloginCloudCommand.Flags().BoolP(\"show\", \"s\", false, \"display saved token, stack info and exit\")\n\tloginCloudCommand.Flags().BoolP(\"reset\", \"r\", false, \"reset stored token and stack info\")\n\tloginCloudCommand.Flags().String(\"stack\", \"\", \"specify the stack (URL or slug) where commands will run by default\")\n\n\treturn loginCloudCommand\n}\n\n// run is the code that runs when the user executes `k6 cloud login`\n//\n//nolint:funlen\nfunc (c *cmdCloudLogin) run(cmd *cobra.Command, _ []string) error {\n\tif !checkIfMigrationCompleted(c.globalState) {\n\t\terr := migrateLegacyConfigFileIfAny(c.globalState)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tcurrentDiskConf, err := readDiskConfig(c.globalState)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcurrentJSONConfig := cloudapi.Config{}\n\tcurrentJSONConfigRaw := currentDiskConf.Collectors[\"cloud\"]\n\tif currentJSONConfigRaw != nil {\n\t\t// We only want to modify this config, see comment below\n\t\tif jsonerr := json.Unmarshal(currentJSONConfigRaw, &currentJSONConfig); jsonerr != nil {\n\t\t\treturn jsonerr\n\t\t}\n\t}\n\n\t// But we don't want to save them back to the JSON file, we only\n\t// want to save what already existed there and the login details.\n\tnewCloudConf := currentJSONConfig\n\n\tshow := getNullBool(cmd.Flags(), \"show\")\n\treset := getNullBool(cmd.Flags(), \"reset\")\n\ttoken := getNullString(cmd.Flags(), \"token\")\n\tstackInput := getNullString(cmd.Flags(), \"stack\")\n\n\tswitch {\n\tcase reset.Valid:\n\t\tnewCloudConf.Token = null.StringFromPtr(nil)\n\t\tnewCloudConf.StackID = null.IntFromPtr(nil)\n\t\tnewCloudConf.StackURL = null.StringFromPtr(nil)\n\t\tnewCloudConf.DefaultProjectID = null.IntFromPtr(nil)\n\t\tprintToStdout(c.globalState, \"  token and stack info reset\\n\")\n\tcase show.Bool:\n\t\tprintConfig(c.globalState, newCloudConf)\n\t\treturn nil\n\tcase token.Valid:\n\t\terr := validateInputs(c.globalState, &newCloudConf, currentJSONConfigRaw, token, stackInput)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\tgs := c.globalState\n\n\t\t/* Token form */\n\t\ttokenForm := ui.Form{\n\t\t\tBanner: \"Enter your token to authenticate with Grafana Cloud.\\n\" +\n\t\t\t\t\"Please, consult the documentation for instructions on how to generate one:\\n\" +\n\t\t\t\t\"https://grafana.com/docs/grafana-cloud/testing/k6/author-run/tokens-and-cli-authentication\",\n\t\t\tFields: []ui.Field{\n\t\t\t\tui.PasswordField{\n\t\t\t\t\tKey:   \"Token\",\n\t\t\t\t\tLabel: \"Token\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tif !term.IsTerminal(int(syscall.Stdin)) { //nolint:unconvert\n\t\t\tgs.Logger.Warn(\"Stdin is not a terminal, falling back to plain text input\")\n\t\t}\n\t\ttokenVals, err := tokenForm.Run(gs.Stdin, gs.Stdout)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttokenInput := null.StringFrom(tokenVals[\"Token\"])\n\t\tif !tokenInput.Valid {\n\t\t\treturn errors.New(\"token cannot be empty\")\n\t\t}\n\n\t\t/* Stack form */\n\t\tstackForm := ui.Form{\n\t\t\tBanner: \"\\nEnter the stack where you want to run k6's commands by default.\\n\" +\n\t\t\t\t\"You can enter a full URL (e.g. https://my-team.grafana.net) or just the slug (e.g. my-team):\",\n\t\t\tFields: []ui.Field{\n\t\t\t\tui.StringField{\n\t\t\t\t\tKey:     \"Stack\",\n\t\t\t\t\tLabel:   \"Stack\",\n\t\t\t\t\tDefault: \"None\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tstackVals, err := stackForm.Run(gs.Stdin, gs.Stdout)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tstackInput := null.StringFrom(strings.TrimSpace(stackVals[\"Stack\"]))\n\n\t\terr = validateInputs(gs, &newCloudConf, currentJSONConfigRaw, tokenInput, stackInput)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif currentDiskConf.Collectors == nil {\n\t\tcurrentDiskConf.Collectors = make(map[string]json.RawMessage)\n\t}\n\tcurrentDiskConf.Collectors[\"cloud\"], err = json.Marshal(newCloudConf)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := writeDiskConfig(c.globalState, currentDiskConf); err != nil {\n\t\treturn err\n\t}\n\n\tif !newCloudConf.Token.Valid {\n\t\treturn nil\n\t}\n\n\tprintToStdout(c.globalState, fmt.Sprintf(\n\t\t\"\\nLogged in successfully, token and stack info saved in %s\\n\", c.globalState.Flags.ConfigFilePath,\n\t))\n\tif !c.globalState.Flags.Quiet {\n\t\tprintConfig(c.globalState, newCloudConf)\n\t}\n\n\treturn nil\n}\n\nfunc printConfig(gs *state.GlobalState, cloudConf cloudapi.Config) {\n\tvalueColor := getColor(gs.Flags.NoColor || !gs.Stdout.IsTTY, color.FgCyan)\n\tprintToStdout(gs, fmt.Sprintf(\"  token: %s\\n\", valueColor.Sprint(cloudConf.Token.String)))\n\n\tif !cloudConf.StackID.Valid && !cloudConf.StackURL.Valid {\n\t\tprintToStdout(gs, \"  stack-id: <not set>\\n\")\n\t\tprintToStdout(gs, \"  stack-url: <not set>\\n\")\n\t\tprintToStdout(gs, \"  default-project-id: <not set>\\n\")\n\n\t\treturn\n\t}\n\n\tif cloudConf.StackID.Valid {\n\t\tprintToStdout(gs, fmt.Sprintf(\"  stack-id: %s\\n\", valueColor.Sprint(cloudConf.StackID.Int64)))\n\t}\n\tif cloudConf.StackURL.Valid {\n\t\tprintToStdout(gs, fmt.Sprintf(\"  stack-url: %s\\n\", valueColor.Sprint(cloudConf.StackURL.String)))\n\t}\n\tif cloudConf.DefaultProjectID.Valid {\n\t\tprintToStdout(gs, fmt.Sprintf(\"  default-project-id: %s\\n\",\n\t\t\tvalueColor.Sprint(cloudConf.DefaultProjectID.Int64)))\n\t}\n}\n\n// validateInputs validates a token and a stack if provided\n// and update the config with the given inputs\nfunc validateInputs(\n\tgs *state.GlobalState,\n\tconfig *cloudapi.Config,\n\trawConfig json.RawMessage,\n\ttoken, stackInput null.String,\n) error {\n\tconfig.Token = token\n\tconsolidatedCurrentConfig, warn, err := cloudapi.GetConsolidatedConfig(\n\t\trawConfig, gs.Env, \"\", nil, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif warn != \"\" {\n\t\tgs.Logger.Warn(warn)\n\t}\n\n\tstackValue := stackInput.String\n\tif stackInput.Valid && stackValue != \"\" && stackValue != \"None\" {\n\t\tstackURL, stackID, defaultProjectID, err := validateTokenV6(\n\t\t\tgs, consolidatedCurrentConfig, token.String, stackValue)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"your stack is invalid - please, consult the documentation \"+\n\t\t\t\t\t\"for instructions on how to get yours: \"+\n\t\t\t\t\t\"https://grafana.com/docs/grafana-cloud/testing/k6/author-run/configure-stack. \"+\n\t\t\t\t\t\"Error details: %w\",\n\t\t\t\terr)\n\t\t}\n\t\tconfig.StackURL = null.StringFrom(stackURL)\n\t\tconfig.StackID = null.IntFrom(stackID)\n\t\tconfig.DefaultProjectID = null.IntFrom(defaultProjectID)\n\t} else {\n\t\terr = validateTokenV1(gs, consolidatedCurrentConfig, config.Token.String)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// validateTokenV1 validates a token using v1 cloud API.\n//\n// Deprecated: use validateTokenV6 instead if a stack name is provided.\nfunc validateTokenV1(gs *state.GlobalState, config cloudapi.Config, token string) error {\n\tclient := cloudapi.NewClient(\n\t\tgs.Logger,\n\t\ttoken,\n\t\tconfig.Host.String,\n\t\tbuild.Version,\n\t\tconfig.Timeout.TimeDuration(),\n\t)\n\n\tres, err := client.ValidateToken()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"can't validate the API token: %s\", err.Error())\n\t}\n\n\tif !res.IsValid {\n\t\treturn errors.New(\"your API token is invalid - \" +\n\t\t\t\"please, consult the documentation for instructions on how to generate a new one:\\n\" +\n\t\t\t\"https://grafana.com/docs/grafana-cloud/testing/k6/author-run/tokens-and-cli-authentication\")\n\t}\n\n\treturn nil\n}\n\n// validateTokenV6 validates a token and a stack URL/slug and returns the normalized URL, stack ID,\n// and default project ID.\n// The stackInput can be either a full URL (e.g., https://my-team.grafana.net) or just a slug (e.g., my-team).\nfunc validateTokenV6(\n\tgs *state.GlobalState,\n\tconfig cloudapi.Config,\n\ttoken, stackInput string,\n) (stackURL string, stackID int64, defaultProjectID int64, err error) {\n\tnormalizedURL := normalizeStackURL(stackInput)\n\n\tclient, err := v6cloudapi.NewClient(\n\t\tgs.Logger,\n\t\ttoken,\n\t\tconfig.Hostv6.String,\n\t\tbuild.Version,\n\t\tconfig.Timeout.TimeDuration(),\n\t)\n\tif err != nil {\n\t\treturn \"\", 0, 0, err\n\t}\n\n\tauthResp, err := client.ValidateToken(normalizedURL)\n\tif err != nil {\n\t\treturn \"\", 0, 0, err\n\t}\n\n\treturn normalizedURL, int64(authResp.StackId), int64(authResp.DefaultProjectId), nil\n}\n\n// normalizeStackURL converts a stack slug to a full URL if needed.\n// The stackInput can be either a full URL (e.g., https://my-team.grafana.net) or just a slug (e.g., my-team).\nfunc normalizeStackURL(stackInput string) string {\n\t// If it's already a full URL, return it as is\n\tif strings.HasPrefix(stackInput, \"http://\") || strings.HasPrefix(stackInput, \"https://\") {\n\t\treturn stackInput\n\t}\n\t// Otherwise, treat it as a slug and construct the URL\n\tslug := stripGrafanaNetSuffix(stackInput)\n\treturn fmt.Sprintf(\"https://%s.grafana.net\", slug)\n}\n\n// stripGrafanaNetSuffix removes .grafana.net suffix if present.\nfunc stripGrafanaNetSuffix(s string) string {\n\tconst suffix = \".grafana.net\"\n\tif len(s) > len(suffix) && s[len(s)-len(suffix):] == suffix {\n\t\treturn s[:len(s)-len(suffix)]\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "internal/cmd/cloud_run.go",
    "content": "package cmd\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"go.k6.io/k6/errext/exitcodes\"\n\n\t\"go.k6.io/k6/errext\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n)\n\nconst cloudRunCommandName string = \"run\"\n\ntype cmdCloudRun struct {\n\t// localExecution stores the state of the --local-execution flag.\n\tlocalExecution bool\n\n\t// linger stores the state of the --linger flag.\n\tlinger bool\n\n\t// noUsageReport stores the state of the --no-usage-report flag.\n\tnoUsageReport bool\n\n\t// noArchiveUpload stores the state of the --no-archive-upload flag.\n\t//\n\t// This flag indicates to the local execution mode to not send the test\n\t// archive to the cloud service.\n\tnoArchiveUpload bool\n\n\t// runCmd holds an instance of the k6 run command that we store\n\t// in order to be able to call its run method to support\n\t// the --local-execution flag mode.\n\trunCmd *cmdRun\n\n\t// deprecatedCloudCmd holds an instance of the k6 cloud command that we store\n\t// in order to be able to call its run method to support the cloud execution\n\t// feature, and to have access to its flagSet if necessary.\n\tdeprecatedCloudCmd *cmdCloud\n}\n\nfunc getCmdCloudRun(cloudCmd *cmdCloud) *cobra.Command {\n\t// We instantiate the run command here to be able to call its run method\n\t// when the --local-execution flag is set.\n\trunCmd := &cmdRun{\n\t\tgs: cloudCmd.gs,\n\n\t\t// We override the loadConfiguredTest func to use the local execution\n\t\t// configuration which enforces the use of the cloud output among other\n\t\t// side effects.\n\t\tloadConfiguredTest: func(cmd *cobra.Command, args []string) (\n\t\t\t*loadedAndConfiguredTest,\n\t\t\texecution.Controller,\n\t\t\terror,\n\t\t) {\n\t\t\ttest, err := loadAndConfigureLocalTest(cloudCmd.gs, cmd, args, getCloudRunLocalExecutionConfig)\n\t\t\treturn test, local.NewController(), err\n\t\t},\n\t}\n\n\tcloudRunCmd := &cmdCloudRun{\n\t\tdeprecatedCloudCmd: cloudCmd,\n\t\trunCmd:             runCmd,\n\t}\n\n\texampleText := getExampleText(cloudCmd.gs, `\n  # Run a test script in Grafana Cloud\n  $ {{.}} cloud run script.js\n\n  # Run a test archive in Grafana Cloud\n  $ {{.}} cloud run archive.tar\n\n  # Read a test script or archive from stdin\n  $ {{.}} cloud run - < script.js`[1:])\n\n\tthisCmd := &cobra.Command{\n\t\tUse:     cloudRunCommandName,\n\t\tShort:   \"Run a test in Grafana Cloud\",\n\t\tLong:    \"Run a test in Grafana Cloud. Requires authentication via \\\"k6 cloud login\\\".\",\n\t\tExample: exampleText,\n\t\tArgs: exactArgsWithMsg(1,\n\t\t\t\"the k6 cloud run command expects a single argument consisting in either a path to a script or \"+\n\t\t\t\t\"archive file, or the \\\"-\\\" symbol indicating the script or archive should be read from stdin\",\n\t\t),\n\t\tPreRunE: cloudRunCmd.preRun,\n\t\tRunE:    cloudRunCmd.run,\n\t}\n\n\tthisCmd.Flags().SortFlags = false\n\tthisCmd.Flags().AddFlagSet(cloudRunCmd.flagSet())\n\tthisCmd.Flags().AddFlagSet(cloudCmd.flagSet())\n\n\treturn thisCmd\n}\n\nfunc (c *cmdCloudRun) preRun(cmd *cobra.Command, args []string) error {\n\tif c.localExecution {\n\t\tif cmd.Flags().Changed(\"exit-on-running\") {\n\t\t\treturn errext.WithExitCodeIfNone(\n\t\t\t\tfmt.Errorf(\"the --local-execution flag is not compatible with the --exit-on-running flag\"),\n\t\t\t\texitcodes.InvalidConfig,\n\t\t\t)\n\t\t}\n\n\t\tif cmd.Flags().Changed(\"show-logs\") {\n\t\t\treturn errext.WithExitCodeIfNone(\n\t\t\t\tfmt.Errorf(\"the --local-execution flag is not compatible with the --show-logs flag\"),\n\t\t\t\texitcodes.InvalidConfig,\n\t\t\t)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif c.linger {\n\t\treturn errext.WithExitCodeIfNone(\n\t\t\tfmt.Errorf(\"the --linger flag can only be used in conjunction with the --local-execution flag\"),\n\t\t\texitcodes.InvalidConfig,\n\t\t)\n\t}\n\n\treturn c.deprecatedCloudCmd.preRun(cmd, args)\n}\n\nfunc (c *cmdCloudRun) run(cmd *cobra.Command, args []string) error {\n\tif c.localExecution {\n\t\tc.runCmd.loadConfiguredTest = func(*cobra.Command, []string) (*loadedAndConfiguredTest, execution.Controller, error) {\n\t\t\ttest, err := loadAndConfigureLocalTest(c.runCmd.gs, cmd, args, getCloudRunLocalExecutionConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"could not load and configure the test: %w\", err)\n\t\t\t}\n\n\t\t\tif err := createCloudTest(c.runCmd.gs, test); err != nil {\n\t\t\t\tif errors.Is(err, errUserUnauthenticated) {\n\t\t\t\t\treturn nil, nil, err\n\t\t\t\t}\n\t\t\t\treturn nil, nil, fmt.Errorf(\"could not create the cloud test run: %w\", err)\n\t\t\t}\n\n\t\t\treturn test, local.NewController(), nil\n\t\t}\n\t\treturn c.runCmd.run(cmd, args)\n\t}\n\n\t// When running the `k6 cloud run` command explicitly disable the usage report.\n\tc.noUsageReport = true\n\n\treturn c.deprecatedCloudCmd.run(cmd, args)\n}\n\nfunc (c *cmdCloudRun) flagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", pflag.ContinueOnError)\n\tflags.SortFlags = false\n\n\tflags.BoolVar(&c.localExecution, \"local-execution\", c.localExecution,\n\t\t\"executes the test locally instead of in the cloud\")\n\tflags.BoolVar(\n\t\t&c.linger,\n\t\t\"linger\",\n\t\tc.linger,\n\t\t\"only when using the local-execution mode, keeps the API server alive past the test end\",\n\t)\n\tflags.BoolVar(\n\t\t&c.noUsageReport,\n\t\t\"no-usage-report\",\n\t\tc.noUsageReport,\n\t\t\"only when using the local-execution mode, don't send anonymous usage \"+\n\t\t\t\"stats (https://grafana.com/docs/k6/latest/set-up/usage-collection/)\",\n\t)\n\tflags.BoolVar(\n\t\t&c.noArchiveUpload,\n\t\t\"no-archive-upload\",\n\t\tc.noArchiveUpload,\n\t\t\"only when using the local-execution mode, don't upload the test archive to the cloud service\",\n\t)\n\n\treturn flags\n}\n\nfunc getCloudRunLocalExecutionConfig(flags *pflag.FlagSet) (Config, error) {\n\topts, err := getOptions(flags)\n\tif err != nil {\n\t\treturn Config{}, err\n\t}\n\n\t// When running locally, we force the output to be cloud.\n\tout := []string{\"cloud\"}\n\n\treturn Config{\n\t\tOptions:         opts,\n\t\tOut:             out,\n\t\tLinger:          getNullBool(flags, \"linger\"),\n\t\tNoUsageReport:   getNullBool(flags, \"no-usage-report\"),\n\t\tNoArchiveUpload: getNullBool(flags, \"no-archive-upload\"),\n\t}, nil\n}\n"
  },
  {
    "path": "internal/cmd/cloud_test.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestResolveDefaultProjectID(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname              string\n\t\tcloudConfig       *cloudapi.Config\n\t\texpectedProjectID int64\n\t\texpectedError     string\n\t\tlogContains       string\n\t}{\n\t\t{\n\t\t\tname: \"returns ProjectID when valid and greater than 0\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID: null.IntFrom(123),\n\t\t\t},\n\t\t\texpectedProjectID: 123,\n\t\t\texpectedError:     \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"returns DefaultProjectID when ProjectID is 0 but StackID and DefaultProjectID are valid\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID:        null.IntFrom(0),\n\t\t\t\tStackID:          null.IntFrom(456),\n\t\t\t\tDefaultProjectID: null.IntFrom(789),\n\t\t\t\tStackURL:         null.StringFrom(\"test-stack\"),\n\t\t\t},\n\t\t\texpectedProjectID: 789,\n\t\t\texpectedError:     \"\",\n\t\t\tlogContains:       \"test-stack\",\n\t\t},\n\t\t{\n\t\t\tname: \"uses generated stack name when StackURL is not valid\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID:        null.IntFrom(0),\n\t\t\t\tStackID:          null.IntFrom(456),\n\t\t\t\tDefaultProjectID: null.IntFrom(789),\n\t\t\t\tStackURL:         null.String{},\n\t\t\t},\n\t\t\texpectedProjectID: 789,\n\t\t\texpectedError:     \"\",\n\t\t\tlogContains:       \"stack-456\",\n\t\t},\n\t\t{\n\t\t\tname: \"returns error when StackID is valid but DefaultProjectID is not available\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID:        null.IntFrom(0),\n\t\t\t\tStackID:          null.IntFrom(456),\n\t\t\t\tDefaultProjectID: null.Int{},\n\t\t\t},\n\t\t\texpectedProjectID: 0,\n\t\t\texpectedError:     \"default stack configured but the default project ID is not available\",\n\t\t},\n\t\t{\n\t\t\tname: \"returns 0 when nothing is configured\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID: null.IntFrom(0),\n\t\t\t},\n\t\t\texpectedProjectID: 0,\n\t\t\texpectedError:     \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"returns 0 when StackID is 0\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID:        null.IntFrom(0),\n\t\t\t\tStackID:          null.IntFrom(0),\n\t\t\t\tDefaultProjectID: null.IntFrom(789),\n\t\t\t},\n\t\t\texpectedProjectID: 0,\n\t\t\texpectedError:     \"\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := tests.NewGlobalTestState(t)\n\n\t\t\tprojectID, err := resolveDefaultProjectID(ts.GlobalState, tc.cloudConfig)\n\n\t\t\tif tc.expectedError != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tc.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\tassert.Equal(t, tc.expectedProjectID, projectID)\n\n\t\t\t// Check log messages if specified\n\t\t\tif tc.logContains != \"\" {\n\t\t\t\tlogs := ts.LoggerHook.Drain()\n\t\t\t\tassert.True(t, testutils.LogContains(logs, logrus.WarnLevel, tc.logContains))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResolveAndSetProjectID(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname              string\n\t\tcloudConfig       *cloudapi.Config\n\t\texpectedError     string\n\t\texpectedProjectID int64\n\t\tlogContains       string\n\t}{\n\t\t{\n\t\t\tname: \"sets projectID in all places when projectID > 0\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID: null.IntFrom(123),\n\t\t\t},\n\t\t\texpectedError:     \"\",\n\t\t\texpectedProjectID: 123,\n\t\t\tlogContains:       \"No stack specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"logs warnings when projectID is 0 and no StackID\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID: null.IntFrom(0),\n\t\t\t},\n\t\t\texpectedError:     \"\",\n\t\t\texpectedProjectID: 0,\n\t\t\tlogContains:       \"No stack specified\",\n\t\t},\n\t\t{\n\t\t\tname: \"propagates error from resolveDefaultProjectID\",\n\t\t\tcloudConfig: &cloudapi.Config{\n\t\t\t\tProjectID:        null.IntFrom(0),\n\t\t\t\tStackID:          null.IntFrom(456),\n\t\t\t\tDefaultProjectID: null.Int{}, // Invalid - should cause error\n\t\t\t},\n\t\t\texpectedError:     \"default stack configured but the default project ID is not available\",\n\t\t\texpectedProjectID: 0,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := tests.NewGlobalTestState(t)\n\n\t\t\ttmpCloudConfig := map[string]any{}\n\t\t\tarc := &lib.Archive{\n\t\t\t\tOptions: lib.Options{\n\t\t\t\t\tExternal: make(map[string]json.RawMessage),\n\t\t\t\t},\n\t\t\t}\n\n\t\t\terr := resolveAndSetProjectID(ts.GlobalState, tc.cloudConfig, tmpCloudConfig, arc)\n\n\t\t\tif tc.expectedError != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tc.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\tif tc.expectedProjectID > 0 {\n\t\t\t\tassert.Equal(t, tc.expectedProjectID, tmpCloudConfig[\"projectID\"])\n\t\t\t\tassert.Equal(t, tc.expectedProjectID, tc.cloudConfig.ProjectID.Int64)\n\n\t\t\t\t// Verify arc.Options.Cloud contains the projectID\n\t\t\t\tvar cloudData map[string]any\n\t\t\t\trequire.NoError(t, json.Unmarshal(arc.Options.Cloud, &cloudData))\n\t\t\t\tassert.Equal(t, float64(tc.expectedProjectID), cloudData[\"projectID\"])\n\n\t\t\t\t// Verify arc.Options.External contains the projectID\n\t\t\t\tvar externalData map[string]any\n\t\t\t\trequire.NoError(t, json.Unmarshal(arc.Options.External[cloudapi.LegacyCloudConfigKey], &externalData))\n\t\t\t\tassert.Equal(t, float64(tc.expectedProjectID), externalData[\"projectID\"])\n\t\t\t}\n\n\t\t\tlogs := ts.LoggerHook.Drain()\n\t\t\tif tc.logContains != \"\" {\n\t\t\t\tassert.True(t, testutils.LogContains(logs, logrus.WarnLevel, tc.logContains))\n\t\t\t} else {\n\t\t\t\tassert.Len(t, logs, 0)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/cloud_upload.go",
    "content": "package cmd\n\nimport (\n\t\"go.k6.io/k6/cmd/state\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n)\n\nconst cloudUploadCommandName = \"upload\"\n\ntype cmdCloudUpload struct {\n\tglobalState *state.GlobalState\n\n\t// deprecatedCloudCmd holds an instance of the k6 cloud command that we store\n\t// in order to be able to call its run method to support the cloud upload\n\t// feature\n\tdeprecatedCloudCmd *cmdCloud\n}\n\nfunc getCmdCloudUpload(cloudCmd *cmdCloud) *cobra.Command {\n\tc := &cmdCloudUpload{\n\t\tglobalState:        cloudCmd.gs,\n\t\tdeprecatedCloudCmd: cloudCmd,\n\t}\n\n\t// uploadCloudCommand represents the 'cloud upload' command\n\texampleText := getExampleText(cloudCmd.gs, `\n  # Upload a test to Grafana Cloud without running it\n  $ {{.}} cloud upload script.js`[1:])\n\n\tuploadCloudCommand := &cobra.Command{\n\t\tUse:     cloudUploadCommandName,\n\t\tShort:   \"Upload a test to Grafana Cloud\",\n\t\tLong:    \"Upload a test to Grafana Cloud without running it. Requires authentication via \\\"k6 cloud login\\\".\",\n\t\tExample: exampleText,\n\t\tArgs:    exactArgsWithMsg(1, \"arg should either be \\\"-\\\", if reading script from stdin, or a path to a script file\"),\n\t\tPreRunE: c.preRun,\n\t\tRunE:    c.run,\n\t}\n\n\tuploadCloudCommand.Flags().AddFlagSet(c.flagSet())\n\n\treturn uploadCloudCommand\n}\n\nfunc (c *cmdCloudUpload) preRun(cmd *cobra.Command, args []string) error {\n\treturn c.deprecatedCloudCmd.preRun(cmd, args)\n}\n\n// run is the code that runs when the user executes `k6 cloud upload`\nfunc (c *cmdCloudUpload) run(cmd *cobra.Command, args []string) error {\n\tc.deprecatedCloudCmd.uploadOnly = true\n\treturn c.deprecatedCloudCmd.run(cmd, args)\n}\n\nfunc (c *cmdCloudUpload) flagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", pflag.ContinueOnError)\n\tflags.SortFlags = false\n\tflags.AddFlagSet(optionFlagSet())\n\tflags.AddFlagSet(runtimeOptionFlagSet(false))\n\treturn flags\n}\n"
  },
  {
    "path": "internal/cmd/common.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"os\"\n\t\"syscall\"\n\t\"text/template\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/lib/types\"\n\n\t// Blank-importing golang.org/x/crypto/x509roots/fallback bundles a set of\n\t// root fallback certificates from Mozilla into the resulting binary. This\n\t// allows the program to run in environments where the system root\n\t// certificates are not available, for example inside a minimal container.\n\t// These are _fallbacks_, meaning that if the system _does have_ a set of\n\t// root certificates, those will be given priority.\n\t_ \"golang.org/x/crypto/x509roots/fallback\"\n)\n\n// Panic if the given error is not nil.\nfunc must(err error) {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n\n// TODO: refactor the CLI config so these functions aren't needed - they\n// can mask errors by failing only at runtime, not at compile time\nfunc getNullBool(flags *pflag.FlagSet, key string) null.Bool {\n\tv, err := flags.GetBool(key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn null.NewBool(v, flags.Changed(key))\n}\n\nfunc getNullInt64(flags *pflag.FlagSet, key string) null.Int {\n\tv, err := flags.GetInt64(key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn null.NewInt(v, flags.Changed(key))\n}\n\nfunc getNullDuration(flags *pflag.FlagSet, key string) types.NullDuration {\n\t// TODO: use types.ParseExtendedDuration? not sure we should support\n\t// unitless durations (i.e. milliseconds) here...\n\tv, err := flags.GetDuration(key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn types.NullDuration{Duration: types.Duration(v), Valid: flags.Changed(key)}\n}\n\nfunc getNullString(flags *pflag.FlagSet, key string) null.String {\n\tv, err := flags.GetString(key)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn null.NewString(v, flags.Changed(key))\n}\n\n//nolint:unparam // this is only currently used with 1 as its first argument\nfunc exactArgsWithMsg(n int, msg string) cobra.PositionalArgs {\n\treturn func(_ *cobra.Command, args []string) error {\n\t\tif len(args) != n {\n\t\t\treturn fmt.Errorf(\"accepts %d arg(s), received %d: %s\", n, len(args), msg)\n\t\t}\n\t\treturn nil\n\t}\n}\n\nfunc printToStdout(gs *state.GlobalState, s string) {\n\tif _, err := fmt.Fprint(gs.Stdout, s); err != nil {\n\t\tgs.Logger.Errorf(\"could not print '%s' to stdout: %s\", s, err.Error())\n\t}\n}\n\nfunc getExampleText(gs *state.GlobalState, tpl string) string {\n\tvar exampleText bytes.Buffer\n\texampleTemplate := template.Must(template.New(\"\").Parse(tpl))\n\n\tif err := exampleTemplate.Execute(&exampleText, gs.BinaryName); err != nil {\n\t\tgs.Logger.WithError(err).Error(\"Error during help example generation\")\n\t}\n\n\treturn exampleText.String()\n}\n\n// Trap Interrupts, SIGINTs and SIGTERMs and call the given.\nfunc handleTestAbortSignals(gs *state.GlobalState, gracefulStopHandler, onHardStop func(os.Signal)) (stop func()) {\n\tgs.Logger.Debug(\"Trapping interrupt signals so k6 can handle them gracefully...\")\n\tsigC := make(chan os.Signal, 2)\n\tdone := make(chan struct{})\n\tgs.SignalNotify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)\n\n\tgo func() {\n\t\tselect {\n\t\tcase sig := <-sigC:\n\t\t\tgracefulStopHandler(sig)\n\t\tcase <-done:\n\t\t\treturn\n\t\t}\n\n\t\tselect {\n\t\tcase sig := <-sigC:\n\t\t\tif onHardStop != nil {\n\t\t\t\tonHardStop(sig)\n\t\t\t}\n\t\t\t// If we get a second signal, we immediately exit, so something like\n\t\t\t// https://github.com/k6io/k6/issues/971 never happens again\n\t\t\tgs.OSExit(int(exitcodes.ExternalAbort))\n\t\tcase <-done:\n\t\t\treturn\n\t\t}\n\t}()\n\n\treturn func() {\n\t\tgs.Logger.Debug(\"Releasing signal trap...\")\n\t\tclose(done)\n\t\tgs.SignalStop(sigC)\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/config.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/pflag\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/executor\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// configFlagSet returns a FlagSet with the default run configuration flags.\nfunc configFlagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", 0)\n\tflags.SortFlags = false\n\tflags.StringArrayP(\"out\", \"o\", []string{}, \"`uri` for an external metrics database\")\n\tflags.BoolP(\"linger\", \"l\", false, \"keep the API server alive past test end\")\n\tflags.Bool(\n\t\t\"no-usage-report\",\n\t\tfalse,\n\t\t\"don't send anonymous usage\"+\"stats (https://grafana.com/docs/k6/latest/set-up/usage-collection/)\",\n\t)\n\treturn flags\n}\n\n// Config ...\ntype Config struct {\n\tlib.Options\n\n\tOut           []string  `json:\"out\" envconfig:\"K6_OUT\"`\n\tLinger        null.Bool `json:\"linger\" envconfig:\"K6_LINGER\"`\n\tNoUsageReport null.Bool `json:\"noUsageReport\" envconfig:\"K6_NO_USAGE_REPORT\"`\n\tWebDashboard  null.Bool `json:\"webDashboard\" envconfig:\"K6_WEB_DASHBOARD\"`\n\n\t// NoArchiveUpload is an option that is only used when running in local-execution mode with the cloud run\n\t// command.\n\t//\n\t// Because the implementation of k6 cloud run calls the same code as the k6 run command under the hood, we\n\t// need to be able to pass down a configuration option that is only relevant to the cloud run command.\n\tNoArchiveUpload null.Bool `json:\"noArchiveUpload\" envconfig:\"K6_NO_ARCHIVE_UPLOAD\"`\n\n\t// TODO: deprecate\n\tCollectors map[string]json.RawMessage `json:\"collectors\"`\n}\n\n// Validate checks if all of the specified options make sense\nfunc (c Config) Validate() []error {\n\terrors := c.Options.Validate()\n\t// TODO: validate all of the other options... that we should have already been validating...\n\t// TODO: maybe integrate an external validation lib: https://github.com/avelino/awesome-go#validation\n\n\treturn errors\n}\n\n// Apply the provided config on top of the current one, returning a new one. The provided config has priority.\nfunc (c Config) Apply(cfg Config) Config {\n\tc.Options = c.Options.Apply(cfg.Options)\n\tif len(cfg.Out) > 0 {\n\t\tc.Out = cfg.Out\n\t}\n\tif cfg.Linger.Valid {\n\t\tc.Linger = cfg.Linger\n\t}\n\tif cfg.NoUsageReport.Valid {\n\t\tc.NoUsageReport = cfg.NoUsageReport\n\t}\n\tif cfg.WebDashboard.Valid {\n\t\tc.WebDashboard = cfg.WebDashboard\n\t}\n\tif cfg.NoArchiveUpload.Valid {\n\t\tc.NoArchiveUpload = cfg.NoArchiveUpload\n\t}\n\tif len(cfg.Collectors) > 0 {\n\t\tc.Collectors = cfg.Collectors\n\t}\n\treturn c\n}\n\n// getPartialConfig returns a Config but only parses the Options inside.\nfunc getPartialConfig(flags *pflag.FlagSet) (Config, error) {\n\topts, err := getOptions(flags)\n\tif err != nil {\n\t\treturn Config{}, err\n\t}\n\n\treturn Config{Options: opts}, nil\n}\n\n// Gets configuration from CLI flags.\nfunc getConfig(flags *pflag.FlagSet) (Config, error) {\n\topts, err := getOptions(flags)\n\tif err != nil {\n\t\treturn Config{}, err\n\t}\n\tout, err := flags.GetStringArray(\"out\")\n\tif err != nil {\n\t\treturn Config{}, err\n\t}\n\treturn Config{\n\t\tOptions:       opts,\n\t\tOut:           out,\n\t\tLinger:        getNullBool(flags, \"linger\"),\n\t\tNoUsageReport: getNullBool(flags, \"no-usage-report\"),\n\n\t\t// As the \"run\" and the \"cloud run\" commands share the same implementation\n\t\t// we enforce the run command to ignore the no-archive-upload flag, and always\n\t\t// set it to true (do not upload).\n\t\tNoArchiveUpload: null.NewBool(true, true),\n\t}, nil\n}\n\n// readDiskConfig reads the configuration file from the supplied filesystem and returns it or\n// an error. The only situation in which an error won't be returned is if the\n// user didn't explicitly specify a config file path and the default config file\n// doesn't exist.\nfunc readDiskConfig(gs *state.GlobalState) (Config, error) {\n\t// Try to see if the file exists in the supplied filesystem\n\tif _, err := gs.FS.Stat(gs.Flags.ConfigFilePath); err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) && gs.Flags.ConfigFilePath == gs.DefaultFlags.ConfigFilePath {\n\t\t\t// If the file doesn't exist, but it was the default config file (i.e. the user\n\t\t\t// didn't specify anything), silence the error\n\t\t\terr = nil\n\t\t}\n\t\treturn Config{}, err\n\t}\n\n\tdata, err := fsext.ReadFile(gs.FS, gs.Flags.ConfigFilePath)\n\tif err != nil {\n\t\treturn Config{}, fmt.Errorf(\"couldn't load the configuration from %q: %w\", gs.Flags.ConfigFilePath, err)\n\t}\n\tvar conf Config\n\terr = json.Unmarshal(data, &conf)\n\tif err != nil {\n\t\treturn Config{}, fmt.Errorf(\"couldn't parse the configuration from %q: %w\", gs.Flags.ConfigFilePath, err)\n\t}\n\treturn conf, nil\n}\n\n// legacyConfigFilePath returns the path of the old location,\n// which is now deprecated and superseded by a new default.\nfunc legacyConfigFilePath(gs *state.GlobalState) string {\n\treturn filepath.Join(gs.UserOSConfigDir, \"loadimpact\", \"k6\", \"config.json\")\n}\n\n// readLegacyDiskConfig reads the configuration file stored on the old default path.\nfunc readLegacyDiskConfig(gs *state.GlobalState) (Config, error) {\n\t// Check if the legacy config exists in the supplied filesystem\n\tlegacyPath := legacyConfigFilePath(gs)\n\tif _, err := gs.FS.Stat(legacyPath); err != nil {\n\t\treturn Config{}, err\n\t}\n\tdata, err := fsext.ReadFile(gs.FS, legacyPath)\n\tif err != nil {\n\t\treturn Config{}, fmt.Errorf(\"couldn't load the configuration from %q: %w\", legacyPath, err)\n\t}\n\tvar conf Config\n\terr = json.Unmarshal(data, &conf)\n\tif err != nil {\n\t\treturn Config{}, fmt.Errorf(\"couldn't parse the configuration from %q: %w\", legacyPath, err)\n\t}\n\treturn conf, nil\n}\n\n// writeDiskConfig serializes the configuration to a JSON file and writes it in the supplied\n// location on the supplied filesystem.\nfunc writeDiskConfig(gs *state.GlobalState, conf Config) error {\n\tdata, err := json.MarshalIndent(conf, \"\", \"  \")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := gs.FS.MkdirAll(filepath.Dir(gs.Flags.ConfigFilePath), 0o755); err != nil {\n\t\treturn err\n\t}\n\n\treturn fsext.WriteFile(gs.FS, gs.Flags.ConfigFilePath, data, 0o644)\n}\n\n// readEnvConfig reads configuration variables from the environment.\nfunc readEnvConfig(envMap map[string]string) (Config, error) {\n\t// TODO: replace envconfig and refactor the whole configuration from the ground up :/\n\tconf := Config{}\n\terr := envconfig.Process(\"\", &conf, func(key string) (string, bool) {\n\t\tv, ok := envMap[key]\n\t\treturn v, ok\n\t})\n\treturn conf, err\n}\n\n// loadConfigFile wraps the ordinary readDiskConfig operation.\n// It adds the capability to fallbacks on the legacy default path if required.\n//\n// Unfortunately, readDiskConfig() silences the NotFound error.\n// We don't want to change it as it is used across several places;\n// and, hopefully, this code will be available only for a single major version.\n// After we should restore to lookup only in a single location for config file (the default).\nfunc loadConfigFile(gs *state.GlobalState) (Config, error) {\n\t// use directly the main flow if the user passed a custom path\n\tif gs.Flags.ConfigFilePath != gs.DefaultFlags.ConfigFilePath {\n\t\treturn readDiskConfig(gs)\n\t}\n\n\t_, err := gs.FS.Stat(gs.Flags.ConfigFilePath)\n\tif err != nil && errors.Is(err, fs.ErrNotExist) {\n\t\t// if the passed path (the default) does not exist\n\t\t// then we attempt to load the legacy path\n\t\tlegacyConf, legacyErr := readLegacyDiskConfig(gs)\n\t\tif legacyErr != nil && !errors.Is(legacyErr, fs.ErrNotExist) {\n\t\t\treturn Config{}, legacyErr\n\t\t}\n\t\t// a legacy file has been found\n\t\tif legacyErr == nil {\n\t\t\tgs.Logger.Warnf(\"The configuration file has been found on the old default path (%q). \"+\n\t\t\t\t\"Please, run again `k6 cloud login` or `k6 login` commands to migrate to the new default path.\\n\\n\",\n\t\t\t\tlegacyConfigFilePath(gs))\n\t\t\treturn legacyConf, nil\n\t\t}\n\t\t// the legacy file doesn't exist, then we fallback on the main flow\n\t\t// to return the silenced error for not existing config file\n\t}\n\treturn readDiskConfig(gs)\n}\n\n// getConsolidatedConfig assemble the final consolidated configuration from all of the different sources:\n// - start with the CLI-provided options to get shadowed (non-Valid) defaults in there\n// - add the global file config options\n// - add the Runner-provided options (they may come from Bundle too if applicable)\n// - add the environment variables\n// - merge the user-supplied CLI flags back in on top, to give them the greatest priority\n// - set some defaults if they weren't previously specified\n// TODO: add better validation, more explicit default values and improve consistency between formats\n// TODO: accumulate all errors and differentiate between the layers?\nfunc getConsolidatedConfig(gs *state.GlobalState, cliConf Config, runnerOpts lib.Options) (Config, error) {\n\tfileConf, err := loadConfigFile(gs)\n\tif err != nil {\n\t\terr = fmt.Errorf(\"failed to load the configuration file from the local file system: %w\", err)\n\t\treturn Config{}, errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)\n\t}\n\n\tenvConf, err := readEnvConfig(gs.Env)\n\tif err != nil {\n\t\treturn Config{}, errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)\n\t}\n\n\tconf := cliConf.Apply(fileConf)\n\n\twarnOnShortHandOverride(conf.Options, runnerOpts, \"script\", gs.Logger)\n\tconf = conf.Apply(Config{Options: runnerOpts})\n\n\twarnOnShortHandOverride(conf.Options, envConf.Options, \"env\", gs.Logger)\n\tconf = conf.Apply(envConf)\n\n\twarnOnShortHandOverride(conf.Options, cliConf.Options, \"cli\", gs.Logger)\n\tconf = conf.Apply(cliConf)\n\n\tconf = applyDefault(conf)\n\n\t// TODO(imiric): Move this validation where it makes sense in the configuration\n\t// refactor of #883. This repeats the trend stats validation already done\n\t// for CLI flags in cmd.getOptions, in case other configuration sources\n\t// (e.g. env vars) overrode our default value. This is not done in\n\t// lib.Options.Validate to avoid circular imports.\n\tif _, err = metrics.GetResolversForTrendColumns(conf.SummaryTrendStats); err != nil {\n\t\treturn Config{}, err\n\t}\n\n\treturn conf, nil\n}\n\nfunc warnOnShortHandOverride(a, b lib.Options, bName string, logger logrus.FieldLogger) {\n\tif a.Scenarios != nil &&\n\t\t(b.Duration.Valid || b.Iterations.Valid || b.Stages != nil || b.Scenarios != nil) {\n\t\tlogger.Warnf(\n\t\t\t\"%q level configuration overrode scenarios configuration entirely\",\n\t\t\tbName)\n\t}\n}\n\n// applyDefault applies the default options value if it is not specified.\n// This happens with types which are not supported by \"gopkg.in/guregu/null.v3\".\n//\n// Note that if you add option default value here, also add it in command line argument help text.\nfunc applyDefault(conf Config) Config {\n\tif conf.SystemTags == nil {\n\t\tconf.SystemTags = &metrics.DefaultSystemTagSet\n\t}\n\tif conf.SummaryTrendStats == nil {\n\t\tconf.SummaryTrendStats = lib.DefaultSummaryTrendStats\n\t}\n\tdefDNS := types.DefaultDNSConfig()\n\tif !conf.DNS.TTL.Valid {\n\t\tconf.DNS.TTL = defDNS.TTL\n\t}\n\tif !conf.DNS.Select.Valid {\n\t\tconf.DNS.Select = defDNS.Select\n\t}\n\tif !conf.DNS.Policy.Valid {\n\t\tconf.DNS.Policy = defDNS.Policy\n\t}\n\tif !conf.SetupTimeout.Valid {\n\t\tconf.SetupTimeout.Duration = types.Duration(60 * time.Second)\n\t}\n\tif !conf.TeardownTimeout.Valid {\n\t\tconf.TeardownTimeout.Duration = types.Duration(60 * time.Second)\n\t}\n\treturn conf\n}\n\nfunc deriveAndValidateConfig(\n\tconf Config, isExecutable func(string) bool, logger logrus.FieldLogger,\n) (result Config, err error) {\n\tresult = conf\n\tresult.Options, err = executor.DeriveScenariosFromShortcuts(conf.Options, logger)\n\tif err == nil {\n\t\terr = validateConfig(result, isExecutable)\n\t}\n\treturn result, errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)\n}\n\nfunc validateConfig(conf Config, isExecutable func(string) bool) error {\n\terrList := conf.Validate()\n\n\tfor _, ec := range conf.Scenarios {\n\t\tif err := validateScenarioConfig(ec, isExecutable); err != nil {\n\t\t\terrList = append(errList, err)\n\t\t}\n\t}\n\n\treturn consolidateErrorMessage(errList, \"There were problems with the specified script configuration:\")\n}\n\nfunc consolidateErrorMessage(errList []error, title string) error {\n\tif len(errList) == 0 {\n\t\treturn nil\n\t}\n\n\terrMsgParts := []string{title}\n\tfor _, err := range errList {\n\t\terrMsgParts = append(errMsgParts, fmt.Sprintf(\"\\t- %s\", err.Error()))\n\t}\n\n\treturn errors.New(strings.Join(errMsgParts, \"\\n\"))\n}\n\nfunc validateScenarioConfig(conf lib.ExecutorConfig, isExecutable func(string) bool) error {\n\texecFn := conf.GetExec()\n\tif !isExecutable(execFn) {\n\t\treturn fmt.Errorf(\"executor %s: function '%s' not found in exports\", conf.GetName(), execFn)\n\t}\n\treturn nil\n}\n\n// migrateLegacyConfigFileIfAny copies the configuration file from\n// the old default `~/.config/loadimpact/...` folder\n// to the new `~/.config/k6/...` default folder.\n// If the old file is not found no error is returned.\n// It keeps the old file as a backup.\nfunc migrateLegacyConfigFileIfAny(gs *state.GlobalState) error {\n\tfn := func() error {\n\t\tlegacyFpath := legacyConfigFilePath(gs)\n\t\t_, err := gs.FS.Stat(legacyFpath)\n\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tnewPath := gs.DefaultFlags.ConfigFilePath\n\t\tif err := gs.FS.MkdirAll(filepath.Dir(newPath), 0o755); err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// copy the config file leaving the old available as a backup\n\t\tf, err := fsext.ReadFile(gs.FS, legacyFpath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = fsext.WriteFile(gs.FS, newPath, f, 0o644)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tgs.Logger.Infof(\"Note, the configuration file has been migrated \"+\n\t\t\t\"from the old default path (%q) to the new one (%q). \"+\n\t\t\t\"Clean up the old path after you verified that you can run tests by using the new configuration.\\n\\n\",\n\t\t\tlegacyFpath, newPath)\n\t\treturn nil\n\t}\n\tif err := fn(); err != nil {\n\t\treturn fmt.Errorf(\"move from the old to the new configuration's filepath failed: %w\", err)\n\t}\n\treturn nil\n}\n\n// checkIfMigrationCompleted checks if the migration has been done by verifying that\n// the new config file exists and contains valid data.\nfunc checkIfMigrationCompleted(gs *state.GlobalState) bool {\n\tnewData, err := fsext.ReadFile(gs.FS, gs.DefaultFlags.ConfigFilePath)\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\treturn false\n\t}\n\tif err != nil {\n\t\tgs.Logger.Errorf(\"Failed to check if the migration has been done: %v\", err)\n\t\treturn false\n\t}\n\n\tvar newConf Config\n\tif err := json.Unmarshal(newData, &newConf); err != nil {\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "internal/cmd/config_consolidation_test.go",
    "content": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/executor\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc verifyOneIterPerOneVU(t *testing.T, c Config) {\n\t// No config anywhere should result in a 1 VU with a 1 iteration config\n\texec := c.Scenarios[lib.DefaultScenarioName]\n\trequire.NotEmpty(t, exec)\n\trequire.IsType(t, executor.PerVUIterationsConfig{}, exec)\n\tperVuIters, ok := exec.(executor.PerVUIterationsConfig)\n\trequire.True(t, ok)\n\tassert.Equal(t, null.NewInt(1, false), perVuIters.Iterations)\n\tassert.Equal(t, null.NewInt(1, false), perVuIters.VUs)\n}\n\nfunc verifySharedIters(vus, iters null.Int) func(t *testing.T, c Config) {\n\treturn func(t *testing.T, c Config) {\n\t\texec := c.Scenarios[lib.DefaultScenarioName]\n\t\trequire.NotEmpty(t, exec)\n\t\trequire.IsType(t, executor.SharedIterationsConfig{}, exec)\n\t\tsharedIterConfig, ok := exec.(executor.SharedIterationsConfig)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, vus, sharedIterConfig.VUs)\n\t\tassert.Equal(t, iters, sharedIterConfig.Iterations)\n\t\tassert.Equal(t, vus, c.VUs)\n\t\tassert.Equal(t, iters, c.Iterations)\n\t}\n}\n\nfunc verifyConstLoopingVUs(vus null.Int, duration time.Duration) func(t *testing.T, c Config) {\n\treturn func(t *testing.T, c Config) {\n\t\texec := c.Scenarios[lib.DefaultScenarioName]\n\t\trequire.NotEmpty(t, exec)\n\t\trequire.IsType(t, executor.ConstantVUsConfig{}, exec)\n\t\tclvc, ok := exec.(executor.ConstantVUsConfig)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, vus, clvc.VUs)\n\t\tassert.Equal(t, types.NullDurationFrom(duration), clvc.Duration)\n\t\tassert.Equal(t, vus, c.VUs)\n\t\tassert.Equal(t, types.NullDurationFrom(duration), c.Duration)\n\t}\n}\n\nfunc verifyExternallyExecuted(scenarioName string, vus null.Int, duration time.Duration) func(t *testing.T, c Config) {\n\treturn func(t *testing.T, c Config) {\n\t\texec := c.Scenarios[scenarioName]\n\t\trequire.NotEmpty(t, exec)\n\t\trequire.IsType(t, executor.ExternallyControlledConfig{}, exec)\n\t\tecc, ok := exec.(executor.ExternallyControlledConfig)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, vus, ecc.VUs)\n\t\tassert.Equal(t, types.NullDurationFrom(duration), ecc.Duration)\n\t\tassert.Equal(t, vus, ecc.MaxVUs) // MaxVUs defaults to VUs unless specified\n\t}\n}\n\nfunc verifyRampingVUs(startVus null.Int, stages []executor.Stage) func(t *testing.T, c Config) {\n\treturn func(t *testing.T, c Config) {\n\t\texec := c.Scenarios[lib.DefaultScenarioName]\n\t\trequire.NotEmpty(t, exec)\n\t\trequire.IsType(t, executor.RampingVUsConfig{}, exec)\n\t\tclvc, ok := exec.(executor.RampingVUsConfig)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, startVus, clvc.StartVUs)\n\t\tassert.Equal(t, startVus, c.VUs)\n\t\tassert.Equal(t, stages, clvc.Stages)\n\t\tassert.Len(t, c.Stages, len(stages))\n\t\tfor i, s := range stages {\n\t\t\tassert.Equal(t, s.Duration, c.Stages[i].Duration)\n\t\t\tassert.Equal(t, s.Target, c.Stages[i].Target)\n\t\t}\n\t}\n}\n\n// A helper function that accepts (duration in second, VUs) pairs and returns\n// a valid slice of stage structs\nfunc buildStages(durationsAndVUs ...int64) []executor.Stage {\n\tl := len(durationsAndVUs)\n\tif l%2 != 0 {\n\t\tpanic(\"wrong len\")\n\t}\n\tresult := make([]executor.Stage, 0, l/2)\n\tfor i := 0; i < l; i += 2 {\n\t\tresult = append(result, executor.Stage{\n\t\t\tDuration: types.NullDurationFrom(time.Duration(durationsAndVUs[i]) * time.Second),\n\t\t\tTarget:   null.IntFrom(durationsAndVUs[i+1]),\n\t\t})\n\t}\n\treturn result\n}\n\ntype file struct {\n\tfilepath, contents string\n}\n\nfunc getFS(files []file) fsext.Fs {\n\tfs := fsext.NewMemMapFs()\n\tfor _, f := range files {\n\t\tmust(fsext.WriteFile(fs, f.filepath, []byte(f.contents), 0o644)) // modes don't matter in the afero.MemMapFs\n\t}\n\treturn fs\n}\n\ntype opts struct {\n\tcli    []string\n\tenv    []string\n\trunner *lib.Options\n\tfs     fsext.Fs\n\tcmds   []string\n}\n\n// exp contains the different events or errors we expect our test case to trigger.\n// for space and clarity, we use the fact that by default, all of the struct values are false\ntype exp struct {\n\tcliParseError      bool\n\tcliReadError       bool\n\tconsolidationError bool // Note: consolidationError includes validation errors from envconfig.Process()\n\tderivationError    bool\n\tvalidationErrors   bool\n\tlogWarning         bool\n}\n\n// A hell of a complicated test case, that still doesn't test things fully...\ntype configConsolidationTestCase struct {\n\toptions         opts\n\texpected        exp\n\tcustomValidator func(t *testing.T, c Config)\n}\n\nfunc getConfigConsolidationTestCases() []configConsolidationTestCase {\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tdefaultConfig := func(jsonConfig string) fsext.Fs {\n\t\treturn getFS([]file{{defaultFlags.ConfigFilePath, jsonConfig}})\n\t}\n\tI := null.IntFrom // shortcut for \"Valid\" (i.e. user-specified) ints\n\t// This is a function, because some of these test cases actually need for the init() functions\n\t// to be executed, since they depend on defaultConfigFilePath\n\treturn []configConsolidationTestCase{\n\t\t// Check that no options will result in 1 VU 1 iter value for execution\n\t\t{opts{}, exp{}, verifyOneIterPerOneVU},\n\t\t// Verify some CLI errors\n\t\t{opts{cli: []string{\"--blah\", \"blah\"}}, exp{cliParseError: true}, nil},\n\t\t{opts{cli: []string{\"--duration\", \"blah\"}}, exp{cliParseError: true}, nil},\n\t\t{opts{cli: []string{\"--duration\", \"1000\"}}, exp{cliParseError: true}, nil}, // intentionally unsupported\n\t\t{opts{cli: []string{\"--iterations\", \"blah\"}}, exp{cliParseError: true}, nil},\n\t\t{opts{cli: []string{\"--execution\", \"\"}}, exp{cliParseError: true}, nil},\n\t\t{opts{cli: []string{\"--stage\", \"10:20s\"}}, exp{cliReadError: true}, nil},\n\t\t{opts{cli: []string{\"--stage\", \"1000:20\"}}, exp{cliReadError: true}, nil}, // intentionally unsupported\n\t\t// Check if CLI shortcuts generate correct execution values\n\t\t{opts{cli: []string{\"--vus\", \"1\", \"--iterations\", \"5\"}}, exp{}, verifySharedIters(I(1), I(5))},\n\t\t{opts{cli: []string{\"-u\", \"2\", \"-i\", \"6\"}}, exp{}, verifySharedIters(I(2), I(6))},\n\t\t{opts{cli: []string{\"-d\", \"123s\"}}, exp{}, verifyConstLoopingVUs(null.NewInt(1, false), 123*time.Second)},\n\t\t{opts{cli: []string{\"-u\", \"3\", \"-d\", \"30s\"}}, exp{}, verifyConstLoopingVUs(I(3), 30*time.Second)},\n\t\t{opts{cli: []string{\"-u\", \"4\", \"--duration\", \"60s\"}}, exp{}, verifyConstLoopingVUs(I(4), 1*time.Minute)},\n\t\t{\n\t\t\topts{cli: []string{\"--stage\", \"20s:10\", \"-s\", \"3m:5\"}},\n\t\t\texp{},\n\t\t\tverifyRampingVUs(null.NewInt(1, false), buildStages(20, 10, 180, 5)),\n\t\t},\n\t\t{\n\t\t\topts{cli: []string{\"-s\", \"1m6s:5\", \"--vus\", \"10\"}},\n\t\t\texp{},\n\t\t\tverifyRampingVUs(null.NewInt(10, true), buildStages(66, 5)),\n\t\t},\n\t\t{opts{cli: []string{\"-u\", \"1\", \"-i\", \"6\", \"-d\", \"10s\"}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tverifySharedIters(I(1), I(6))(t, c)\n\t\t\tsharedIterConfig, ok := c.Scenarios[lib.DefaultScenarioName].(executor.SharedIterationsConfig)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.Equal(t, 10*time.Second, sharedIterConfig.MaxDuration.TimeDuration())\n\t\t}},\n\t\t// This should get a validation error since VUs are more than the shared iterations\n\t\t{opts{cli: []string{\"--vus\", \"10\", \"-i\", \"6\"}}, exp{validationErrors: true}, verifySharedIters(I(10), I(6))},\n\t\t{opts{cli: []string{\"-s\", \"10s:5\", \"-s\", \"10s:\"}}, exp{validationErrors: true}, nil},\n\t\t{opts{fs: defaultConfig(`{\"stages\": [{\"duration\": \"20s\"}], \"vus\": 10}`)}, exp{validationErrors: true}, nil},\n\t\t// These should emit a derivation error\n\t\t{opts{cli: []string{\"-u\", \"2\", \"-d\", \"10s\", \"-s\", \"10s:20\"}}, exp{derivationError: true}, nil},\n\t\t{opts{cli: []string{\"-u\", \"3\", \"-i\", \"5\", \"-s\", \"10s:20\"}}, exp{derivationError: true}, nil},\n\t\t{opts{cli: []string{\"-u\", \"3\", \"-d\", \"0\"}}, exp{derivationError: true}, nil},\n\t\t{\n\t\t\topts{runner: &lib.Options{\n\t\t\t\tVUs:      null.IntFrom(5),\n\t\t\t\tDuration: types.NullDurationFrom(44 * time.Second),\n\t\t\t\tStages: []lib.Stage{\n\t\t\t\t\t{Duration: types.NullDurationFrom(3 * time.Second), Target: I(20)},\n\t\t\t\t},\n\t\t\t}}, exp{derivationError: true}, nil,\n\t\t},\n\t\t{opts{fs: defaultConfig(`{\"scenarios\": {}}`)}, exp{logWarning: true}, verifyOneIterPerOneVU},\n\t\t// Test if environment variable shortcuts are working as expected\n\t\t{opts{env: []string{\"K6_VUS=5\", \"K6_ITERATIONS=15\"}}, exp{}, verifySharedIters(I(5), I(15))},\n\t\t{opts{env: []string{\"K6_VUS=10\", \"K6_DURATION=20s\"}}, exp{}, verifyConstLoopingVUs(I(10), 20*time.Second)},\n\t\t{opts{env: []string{\"K6_VUS=10\", \"K6_DURATION=10000\"}}, exp{}, verifyConstLoopingVUs(I(10), 10*time.Second)},\n\t\t{\n\t\t\topts{env: []string{\"K6_STAGES=2m30s:11,1h1m:100\"}},\n\t\t\texp{},\n\t\t\tverifyRampingVUs(null.NewInt(1, false), buildStages(150, 11, 3660, 100)),\n\t\t},\n\t\t{\n\t\t\topts{env: []string{\"K6_STAGES=100s:100,0m30s:0\", \"K6_VUS=0\"}},\n\t\t\texp{},\n\t\t\tverifyRampingVUs(null.NewInt(0, true), buildStages(100, 100, 30, 0)),\n\t\t},\n\t\t{opts{env: []string{\"K6_STAGES=1000:100\"}}, exp{consolidationError: true}, nil}, // intentionally unsupported\n\t\t// Test if JSON configs work as expected\n\t\t{opts{fs: defaultConfig(`{\"iterations\": 77, \"vus\": 7}`)}, exp{}, verifySharedIters(I(7), I(77))},\n\t\t{opts{fs: defaultConfig(`wrong-json`)}, exp{consolidationError: true}, nil},\n\t\t{opts{fs: getFS(nil), cli: []string{\"--config\", \"/my/config.file\"}}, exp{consolidationError: true}, nil},\n\n\t\t// Test combinations between options and levels\n\t\t{opts{cli: []string{\"--vus\", \"1\"}}, exp{}, verifyOneIterPerOneVU},\n\t\t{opts{cli: []string{\"--vus\", \"10\"}}, exp{logWarning: true}, verifyOneIterPerOneVU},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:  getFS([]file{{\"/my/config.file\", `{\"vus\": 8, \"duration\": \"2m\"}`}}),\n\t\t\t\tcli: []string{\"--config\", \"/my/config.file\"},\n\t\t\t}, exp{}, verifyConstLoopingVUs(I(8), 120*time.Second),\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:  getFS([]file{{\"/my/config.file\", `{\"duration\": 20000}`}}),\n\t\t\t\tcli: []string{\"--config\", \"/my/config.file\"},\n\t\t\t}, exp{}, verifyConstLoopingVUs(null.NewInt(1, false), 20*time.Second),\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:  defaultConfig(`{\"stages\": [{\"duration\": \"20s\", \"target\": 20}], \"vus\": 10}`),\n\t\t\t\tenv: []string{\"K6_DURATION=15s\"},\n\t\t\t\tcli: []string{\"--stage\", \"\"},\n\t\t\t},\n\t\t\texp{logWarning: true},\n\t\t\tverifyOneIterPerOneVU,\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\trunner: &lib.Options{VUs: null.IntFrom(5), Duration: types.NullDurationFrom(50 * time.Second)},\n\t\t\t\tcli:    []string{\"--stage\", \"5s:5\"},\n\t\t\t},\n\t\t\texp{},\n\t\t\tverifyRampingVUs(I(5), buildStages(5, 5)),\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:     defaultConfig(`{\"stages\": [{\"duration\": \"20s\", \"target\": 10}]}`),\n\t\t\t\trunner: &lib.Options{VUs: null.IntFrom(5)},\n\t\t\t},\n\t\t\texp{},\n\t\t\tverifyRampingVUs(I(5), buildStages(20, 10)),\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:     defaultConfig(`{\"stages\": [{\"duration\": \"20s\", \"target\": 10}]}`),\n\t\t\t\trunner: &lib.Options{VUs: null.IntFrom(5)},\n\t\t\t\tenv:    []string{\"K6_VUS=15\", \"K6_ITERATIONS=17\"},\n\t\t\t},\n\t\t\texp{},\n\t\t\tverifySharedIters(I(15), I(17)),\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:     defaultConfig(`{\"stages\": [{\"duration\": \"11s\", \"target\": 11}]}`),\n\t\t\t\trunner: &lib.Options{VUs: null.IntFrom(22)},\n\t\t\t\tenv:    []string{\"K6_VUS=33\"},\n\t\t\t\tcli:    []string{\"--stage\", \"44s:44\", \"-s\", \"55s:55\"},\n\t\t\t},\n\t\t\texp{},\n\t\t\tverifyRampingVUs(null.NewInt(33, true), buildStages(44, 44, 55, 55)),\n\t\t},\n\n\t\t// TODO: test the future full overwriting of the duration/iterations/stages/execution options\n\t\t{\n\t\t\topts{\n\t\t\t\tfs: defaultConfig(`{\n\t\t\t\t\t\"scenarios\": { \"someKey\": {\n\t\t\t\t\t\t\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"60s\", \"gracefulStop\": \"10s\",\n\t\t\t\t\t\t\"startTime\": \"70s\", \"env\": {\"test\": \"mest\"}, \"exec\": \"someFunc\"\n\t\t\t\t\t}}}`),\n\t\t\t\tenv: []string{\"K6_ITERATIONS=25\"},\n\t\t\t\tcli: []string{\"--vus\", \"12\"},\n\t\t\t},\n\t\t\texp{\n\t\t\t\tlogWarning: true,\n\t\t\t},\n\t\t\tverifySharedIters(I(12), I(25)),\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs: defaultConfig(`{\"scenarios\": { \"foo\": {\n\t\t\t\t\t\"executor\": \"constant-vus\", \"vus\": 2, \"duration\": \"1d\",\n\t\t\t\t\t\"gracefulStop\": \"10000\", \"startTime\": 1000.5\n\t\t\t\t}}}`),\n\t\t\t}, exp{}, func(t *testing.T, c Config) {\n\t\t\t\texec := c.Scenarios[\"foo\"]\n\t\t\t\trequire.NotEmpty(t, exec)\n\t\t\t\trequire.IsType(t, executor.ConstantVUsConfig{}, exec)\n\t\t\t\tclvc, ok := exec.(executor.ConstantVUsConfig)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\tassert.Equal(t, null.IntFrom(2), clvc.VUs)\n\t\t\t\tassert.Equal(t, types.NullDurationFrom(24*time.Hour), clvc.Duration)\n\t\t\t\tassert.Equal(t, types.NullDurationFrom(time.Second+500*time.Microsecond), clvc.StartTime)\n\t\t\t\tassert.Equal(t, types.NullDurationFrom(10*time.Second), clvc.GracefulStop)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs: defaultConfig(`{\"scenarios\": { \"def\": {\n\t\t\t\t\t\"executor\": \"externally-controlled\", \"vus\": 15, \"duration\": \"2h\"\n\t\t\t\t}}}`),\n\t\t\t},\n\t\t\texp{},\n\t\t\tverifyExternallyExecuted(\"def\", I(15), 2*time.Hour),\n\t\t},\n\t\t// TODO: test execution-segment\n\n\t\t// Just in case, verify that no options will result in the same 1 vu 1 iter config\n\t\t{opts{}, exp{}, verifyOneIterPerOneVU},\n\n\t\t// Test system tags\n\t\t{opts{}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, &metrics.DefaultSystemTagSet, c.SystemTags)\n\t\t}},\n\t\t{opts{cli: []string{\"--system-tags\", `\"\"`}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, metrics.SystemTagSet(0), *c.SystemTags)\n\t\t}},\n\t\t{opts{env: []string{`K6_SYSTEM_TAGS=\"\"`}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, metrics.SystemTagSet(0), *c.SystemTags)\n\t\t}},\n\t\t{opts{env: []string{`K6_SYSTEM_TAGS=proto,method`}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, metrics.SystemTagSet(metrics.TagProto|metrics.TagMethod), *c.SystemTags)\n\t\t}},\n\t\t{\n\t\t\topts{\n\t\t\t\trunner: &lib.Options{\n\t\t\t\t\tSystemTags: metrics.NewSystemTagSet(metrics.TagSubproto, metrics.TagURL),\n\t\t\t\t},\n\t\t\t},\n\t\t\texp{},\n\t\t\tfunc(t *testing.T, c Config) {\n\t\t\t\tassert.Equal(\n\t\t\t\t\tt,\n\t\t\t\t\t*metrics.NewSystemTagSet(metrics.TagSubproto, metrics.TagURL),\n\t\t\t\t\t*c.SystemTags,\n\t\t\t\t)\n\t\t\t},\n\t\t},\n\n\t\t// Test-wide Tags\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:  defaultConfig(`{\"tags\": { \"codeTagKey\": \"codeTagValue\"}}`),\n\t\t\t\tcli: []string{\"--tag\", \"clitagkey=clitagvalue\"},\n\t\t\t},\n\t\t\texp{},\n\t\t\tfunc(t *testing.T, c Config) {\n\t\t\t\texp := map[string]string{\"clitagkey\": \"clitagvalue\"}\n\t\t\t\tassert.Equal(t, exp, c.RunTags)\n\t\t\t},\n\t\t},\n\n\t\t// Test summary trend stats\n\t\t{opts{}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, lib.DefaultSummaryTrendStats, c.SummaryTrendStats)\n\t\t}},\n\t\t{opts{cli: []string{\"--summary-trend-stats\", \"\"}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, []string{}, c.SummaryTrendStats)\n\t\t}},\n\t\t{opts{cli: []string{\"--summary-trend-stats\", \"coun\"}}, exp{cliReadError: true}, nil},\n\t\t{opts{cli: []string{\"--summary-trend-stats\", \"med,avg,p(\"}}, exp{cliReadError: true}, nil},\n\t\t{opts{cli: []string{\"--summary-trend-stats\", \"med,avg,p(-1)\"}}, exp{cliReadError: true}, nil},\n\t\t{opts{cli: []string{\"--summary-trend-stats\", \"med,avg,p(101)\"}}, exp{cliReadError: true}, nil},\n\t\t{opts{cli: []string{\"--summary-trend-stats\", \"med,avg,p(99.999)\"}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, []string{\"med\", \"avg\", \"p(99.999)\"}, c.SummaryTrendStats)\n\t\t}},\n\t\t{\n\t\t\topts{runner: &lib.Options{SummaryTrendStats: []string{\"avg\", \"p(90)\", \"count\"}}},\n\t\t\texp{},\n\t\t\tfunc(t *testing.T, c Config) {\n\t\t\t\tassert.Equal(t, []string{\"avg\", \"p(90)\", \"count\"}, c.SummaryTrendStats)\n\t\t\t},\n\t\t},\n\t\t{opts{cli: []string{}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\tTTL:    null.NewString(\"5m\", false),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSrandom, Valid: false},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv4, Valid: false},\n\t\t\t}, c.DNS)\n\t\t}},\n\t\t{opts{env: []string{\"K6_DNS=ttl=5,select=roundRobin\"}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\tTTL:    null.StringFrom(\"5\"),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSroundRobin, Valid: true},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv4, Valid: false},\n\t\t\t}, c.DNS)\n\t\t}},\n\t\t{opts{env: []string{\"K6_DNS=ttl=inf,select=random,policy=preferIPv6\"}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\tTTL:    null.StringFrom(\"inf\"),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSrandom, Valid: true},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv6, Valid: true},\n\t\t\t}, c.DNS)\n\t\t}},\n\t\t// This is functionally invalid, but will error out in validation done in js.parseTTL().\n\t\t{opts{cli: []string{\"--dns\", \"ttl=-1\"}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\tTTL:    null.StringFrom(\"-1\"),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSrandom, Valid: false},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv4, Valid: false},\n\t\t\t}, c.DNS)\n\t\t}},\n\t\t{opts{cli: []string{\"--dns\", \"ttl=0,blah=nope\"}}, exp{cliReadError: true}, nil},\n\t\t{opts{cli: []string{\"--dns\", \"ttl=0\"}}, exp{}, func(t *testing.T, c Config) {\n\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\tTTL:    null.StringFrom(\"0\"),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSrandom, Valid: false},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv4, Valid: false},\n\t\t\t}, c.DNS)\n\t\t}},\n\t\t{opts{cli: []string{\"--dns\", \"ttl=5s,select=\"}}, exp{cliReadError: true}, nil},\n\t\t{\n\t\t\topts{fs: defaultConfig(`{\"dns\": {\"ttl\": \"0\", \"select\": \"roundRobin\", \"policy\": \"onlyIPv4\"}}`)},\n\t\t\texp{},\n\t\t\tfunc(t *testing.T, c Config) {\n\t\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\t\tTTL:    null.StringFrom(\"0\"),\n\t\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSroundRobin, Valid: true},\n\t\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSonlyIPv4, Valid: true},\n\t\t\t\t}, c.DNS)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tfs:  defaultConfig(`{\"dns\": {\"ttl\": \"0\"}}`),\n\t\t\t\tenv: []string{\"K6_DNS=ttl=30,policy=any\"},\n\t\t\t},\n\t\t\texp{},\n\t\t\tfunc(t *testing.T, c Config) {\n\t\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\t\tTTL:    null.StringFrom(\"30\"),\n\t\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSrandom, Valid: false},\n\t\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSany, Valid: true},\n\t\t\t\t}, c.DNS)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// CLI overrides all, falling back to env\n\t\t\topts{\n\t\t\t\tfs:  defaultConfig(`{\"dns\": {\"ttl\": \"60\", \"select\": \"first\"}}`),\n\t\t\t\tenv: []string{\"K6_DNS=ttl=30,select=random,policy=any\"},\n\t\t\t\tcli: []string{\"--dns\", \"ttl=5\"},\n\t\t\t},\n\t\t\texp{},\n\t\t\tfunc(t *testing.T, c Config) {\n\t\t\t\tassert.Equal(t, types.DNSConfig{\n\t\t\t\t\tTTL:    null.StringFrom(\"5\"),\n\t\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSrandom, Valid: true},\n\t\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSany, Valid: true},\n\t\t\t\t}, c.DNS)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\topts{env: []string{\"K6_NO_SETUP=true\", \"K6_NO_TEARDOWN=false\"}},\n\t\t\texp{},\n\t\t\tfunc(t *testing.T, c Config) {\n\t\t\t\tassert.Equal(t, null.BoolFrom(true), c.NoSetup)\n\t\t\t\tassert.Equal(t, null.BoolFrom(false), c.NoTeardown)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\topts{env: []string{\"K6_NO_SETUP=false\", \"K6_NO_TEARDOWN=bool\"}},\n\t\t\texp{\n\t\t\t\tconsolidationError: true,\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t{\n\t\t\topts{\n\t\t\t\tenv: []string{\"K6_PROFILING_ENABLED=true\"},\n\t\t\t\tcli: []string{\"--profiling-enabled\"},\n\t\t\t},\n\t\t\texp{\n\t\t\t\tconsolidationError: false,\n\t\t\t},\n\t\t\tnil,\n\t\t},\n\t\t// TODO: test for differences between flagsets\n\t\t// TODO: more tests in general, especially ones not related to execution parameters...\n\t}\n}\n\nfunc runTestCase(t *testing.T, testCase configConsolidationTestCase, subCmd string) {\n\tt.Logf(\"Test for `k6 %s` with opts=%#v and exp=%#v\\n\", subCmd, testCase.options, testCase.expected)\n\n\tts := tests.NewGlobalTestState(t)\n\tts.CmdArgs = append([]string{\"k6\", subCmd}, testCase.options.cli...)\n\tts.Env = state.BuildEnvMap(testCase.options.env)\n\tif testCase.options.fs != nil {\n\t\tts.FS = testCase.options.fs\n\t}\n\n\trootCmd := newRootCommand(ts.GlobalState)\n\tcmd, args, err := rootCmd.cmd.Find(ts.CmdArgs[1:])\n\trequire.NoError(t, err)\n\n\terr = cmd.ParseFlags(args)\n\tif testCase.expected.cliParseError {\n\t\trequire.Error(t, err)\n\t\treturn\n\t}\n\trequire.NoError(t, err)\n\n\tflagSet := cmd.Flags()\n\n\t// TODO: remove these hacks when we improve the configuration...\n\tvar cliConf Config\n\tif flagSet.Lookup(\"out\") != nil {\n\t\tcliConf, err = getConfig(flagSet)\n\t} else {\n\t\topts, errOpts := getOptions(flagSet)\n\t\tcliConf, err = Config{Options: opts}, errOpts\n\t}\n\tif testCase.expected.cliReadError {\n\t\trequire.Error(t, err)\n\t\treturn\n\t}\n\trequire.NoError(t, err)\n\n\tvar opts lib.Options\n\tif testCase.options.runner != nil {\n\t\topts = *testCase.options.runner\n\t}\n\tconsolidatedConfig, err := getConsolidatedConfig(ts.GlobalState, cliConf, opts)\n\tif testCase.expected.consolidationError {\n\t\trequire.Error(t, err)\n\t\treturn\n\t}\n\trequire.NoError(t, err)\n\n\tderivedConfig := consolidatedConfig\n\tderivedConfig.Options, err = executor.DeriveScenariosFromShortcuts(consolidatedConfig.Options, ts.Logger)\n\tif testCase.expected.derivationError {\n\t\trequire.Error(t, err)\n\t\treturn\n\t}\n\trequire.NoError(t, err)\n\n\tif warnings := ts.LoggerHook.Drain(); testCase.expected.logWarning {\n\t\tassert.NotEmpty(t, warnings)\n\t} else {\n\t\tassert.Empty(t, warnings)\n\t}\n\n\tvalidationErrors := derivedConfig.Validate()\n\tif testCase.expected.validationErrors {\n\t\tassert.NotEmpty(t, validationErrors)\n\t} else {\n\t\tassert.Empty(t, validationErrors)\n\t}\n\n\tif testCase.customValidator != nil {\n\t\ttestCase.customValidator(t, derivedConfig)\n\t}\n}\n\nfunc TestConfigConsolidation(t *testing.T) {\n\tt.Parallel()\n\n\tfor tcNum, testCase := range getConfigConsolidationTestCases() {\n\t\tsubCommands := testCase.options.cmds\n\t\tif subCommands == nil { // handle the most common case\n\t\t\tsubCommands = []string{\"run\", \"archive\", \"cloud\"}\n\t\t}\n\t\tfor fsNum, subCmd := range subCommands {\n\t\t\tt.Run(\n\t\t\t\tfmt.Sprintf(\"TestCase#%d_FlagSet#%d\", tcNum, fsNum),\n\t\t\t\tfunc(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\trunTestCase(t, testCase, subCmd)\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/config_test.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"io/fs\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/executor\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\ntype testCmdData struct {\n\tName  string\n\tTests []testCmdTest\n}\n\ntype testCmdTest struct {\n\tArgs     []string\n\tExpected []string\n\tName     string\n}\n\nfunc TestConfigCmd(t *testing.T) {\n\tt.Parallel()\n\ttestdata := []testCmdData{\n\t\t{\n\t\t\tName: \"Out\",\n\n\t\t\tTests: []testCmdTest{\n\t\t\t\t{\n\t\t\t\t\tName:     \"NoArgs\",\n\t\t\t\t\tArgs:     []string{\"\"},\n\t\t\t\t\tExpected: []string{},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:     \"SingleArg\",\n\t\t\t\t\tArgs:     []string{\"--out\", \"influxdb=http://localhost:8086/k6\"},\n\t\t\t\t\tExpected: []string{\"influxdb=http://localhost:8086/k6\"},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:     \"MultiArg\",\n\t\t\t\t\tArgs:     []string{\"--out\", \"influxdb=http://localhost:8086/k6\", \"--out\", \"json=test.json\"},\n\t\t\t\t\tExpected: []string{\"influxdb=http://localhost:8086/k6\", \"json=test.json\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, data := range testdata {\n\t\tt.Run(data.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor _, test := range data.Tests {\n\t\t\t\tt.Run(`\"`+test.Name+`\"`, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tfs := configFlagSet()\n\t\t\t\t\tfs.AddFlagSet(optionFlagSet())\n\t\t\t\t\tassert.NoError(t, fs.Parse(test.Args))\n\n\t\t\t\t\tconfig, err := getConfig(fs)\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, test.Expected, config.Out)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestConfigEnv(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[struct{ Name, Key string }]map[string]func(Config){\n\t\t{\"Linger\", \"K6_LINGER\"}: {\n\t\t\t\"\":      func(c Config) { assert.Equal(t, null.Bool{}, c.Linger) },\n\t\t\t\"true\":  func(c Config) { assert.Equal(t, null.BoolFrom(true), c.Linger) },\n\t\t\t\"false\": func(c Config) { assert.Equal(t, null.BoolFrom(false), c.Linger) },\n\t\t},\n\t\t{\"NoUsageReport\", \"K6_NO_USAGE_REPORT\"}: {\n\t\t\t\"\":      func(c Config) { assert.Equal(t, null.Bool{}, c.NoUsageReport) },\n\t\t\t\"true\":  func(c Config) { assert.Equal(t, null.BoolFrom(true), c.NoUsageReport) },\n\t\t\t\"false\": func(c Config) { assert.Equal(t, null.BoolFrom(false), c.NoUsageReport) },\n\t\t},\n\t\t{\"WebDashboard\", \"K6_WEB_DASHBOARD\"}: {\n\t\t\t\"\":      func(c Config) { assert.Equal(t, null.Bool{}, c.WebDashboard) },\n\t\t\t\"true\":  func(c Config) { assert.Equal(t, null.BoolFrom(true), c.WebDashboard) },\n\t\t\t\"false\": func(c Config) { assert.Equal(t, null.BoolFrom(false), c.WebDashboard) },\n\t\t},\n\t\t{\"Out\", \"K6_OUT\"}: {\n\t\t\t\"\":         func(c Config) { assert.Equal(t, []string{}, c.Out) },\n\t\t\t\"influxdb\": func(c Config) { assert.Equal(t, []string{\"influxdb\"}, c.Out) },\n\t\t},\n\t}\n\tfor field, data := range testdata {\n\t\tt.Run(field.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor value, fn := range data {\n\t\t\t\tt.Run(`\"`+value+`\"`, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tvar config Config\n\t\t\t\t\tassert.NoError(t, envconfig.Process(\"\", &config, func(key string) (string, bool) {\n\t\t\t\t\t\tif key == field.Key {\n\t\t\t\t\t\t\treturn value, true\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn \"\", false\n\t\t\t\t\t}))\n\t\t\t\t\tfn(config)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestConfigApply(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Linger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tconf := Config{}.Apply(Config{Linger: null.BoolFrom(true)})\n\t\tassert.Equal(t, null.BoolFrom(true), conf.Linger)\n\t})\n\tt.Run(\"NoUsageReport\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tconf := Config{}.Apply(Config{NoUsageReport: null.BoolFrom(true)})\n\t\tassert.Equal(t, null.BoolFrom(true), conf.NoUsageReport)\n\t})\n\tt.Run(\"Out\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tconf := Config{}.Apply(Config{Out: []string{\"influxdb\"}})\n\t\tassert.Equal(t, []string{\"influxdb\"}, conf.Out)\n\n\t\tconf = Config{}.Apply(Config{Out: []string{\"influxdb\", \"json\"}})\n\t\tassert.Equal(t, []string{\"influxdb\", \"json\"}, conf.Out)\n\t})\n}\n\nfunc TestDeriveAndValidateConfig(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname   string\n\t\tconf   Config\n\t\tisExec bool\n\t\terr    string\n\t}{\n\t\t{\"defaultOK\", Config{}, true, \"\"},\n\t\t{\n\t\t\t\"defaultErr\",\n\t\t\tConfig{},\n\t\t\tfalse,\n\t\t\t\"executor default: function 'default' not found in exports\",\n\t\t},\n\t\t{\n\t\t\t\"nonDefaultOK\", Config{Options: lib.Options{Scenarios: lib.ScenarioConfigs{\n\t\t\t\t\"per_vu_iters\": executor.PerVUIterationsConfig{\n\t\t\t\t\tBaseConfig: executor.BaseConfig{\n\t\t\t\t\t\tName: \"per_vu_iters\", Type: \"per-vu-iterations\", Exec: null.StringFrom(\"nonDefault\"),\n\t\t\t\t\t},\n\t\t\t\t\tVUs:         null.IntFrom(1),\n\t\t\t\t\tIterations:  null.IntFrom(1),\n\t\t\t\t\tMaxDuration: types.NullDurationFrom(time.Second),\n\t\t\t\t},\n\t\t\t}}}, true, \"\",\n\t\t},\n\t\t{\n\t\t\t\"nonDefaultErr\",\n\t\t\tConfig{Options: lib.Options{Scenarios: lib.ScenarioConfigs{\n\t\t\t\t\"per_vu_iters\": executor.PerVUIterationsConfig{\n\t\t\t\t\tBaseConfig: executor.BaseConfig{\n\t\t\t\t\t\tName: \"per_vu_iters\", Type: \"per-vu-iterations\", Exec: null.StringFrom(\"nonDefaultErr\"),\n\t\t\t\t\t},\n\t\t\t\t\tVUs:         null.IntFrom(1),\n\t\t\t\t\tIterations:  null.IntFrom(1),\n\t\t\t\t\tMaxDuration: types.NullDurationFrom(time.Second),\n\t\t\t\t},\n\t\t\t}}},\n\t\t\tfalse,\n\t\t\t\"executor per_vu_iters: function 'nonDefaultErr' not found in exports\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := deriveAndValidateConfig(tc.conf,\n\t\t\t\tfunc(_ string) bool { return tc.isExec }, nil)\n\t\t\tif tc.err != \"\" {\n\t\t\t\tvar ecerr errext.HasExitCode\n\t\t\t\tassert.ErrorAs(t, err, &ecerr)\n\t\t\t\tassert.Equal(t, exitcodes.InvalidConfig, ecerr.ExitCode())\n\t\t\t\tassert.Contains(t, err.Error(), tc.err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestReadDiskConfigWithDefaultFlags(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tconf := []byte(`{\"iterations\":1028,\"cloud\":{\"field1\":\"testvalue\"}}`)\n\tdefaultConfigPath := \".config/k6/config.json\"\n\trequire.NoError(t, fsext.WriteFile(memfs, defaultConfigPath, conf, 0o644))\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\tc, err := readDiskConfig(gs)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, c.Iterations.Int64, int64(1028))\n\tassert.JSONEq(t, `{\"field1\":\"testvalue\"}`, string(c.Cloud))\n}\n\nfunc TestReadDiskConfigCustomFilePath(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tconf := []byte(`{\"iterations\":1028,\"cloud\":{\"field1\":\"testvalue\"}}`)\n\trequire.NoError(t, fsext.WriteFile(memfs, \"custom-path/config.json\", conf, 0o644))\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\tgs.Flags.ConfigFilePath = \"custom-path/config.json\"\n\n\tc, err := readDiskConfig(gs)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, c.Iterations.Int64, int64(1028))\n\tassert.JSONEq(t, `{\"field1\":\"testvalue\"}`, string(c.Cloud))\n}\n\nfunc TestReadDiskConfigNotFoundSilenced(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\t// Put the file into a different and unexpected directory\n\tconf := []byte(`{\"iterations\":1028,\"cloud\":{\"field1\":\"testvalue\"}}`)\n\tdefaultConfigPath := \".config/unknown-folder/k6/config.json\"\n\trequire.NoError(t, fsext.WriteFile(memfs, defaultConfigPath, conf, 0o644))\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\tc, err := readDiskConfig(gs)\n\tassert.NoError(t, err)\n\tassert.Empty(t, c)\n}\n\nfunc TestReadDiskConfigNotJSONExtension(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tconf := []byte(`{\"iterations\":1028,\"cloud\":{\"field1\":\"testvalue\"}}`)\n\trequire.NoError(t, fsext.WriteFile(memfs, \"custom-path/config.txt\", conf, 0o644))\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tDefaultFlags: defaultFlags,\n\t\tFlags:        defaultFlags,\n\t}\n\tgs.Flags.ConfigFilePath = \"custom-path/config.txt\"\n\n\tc, err := readDiskConfig(gs)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, c.Iterations.Int64, int64(1028))\n\tassert.JSONEq(t, `{\"field1\":\"testvalue\"}`, string(c.Cloud))\n}\n\nfunc TestReadDiskConfigNotJSONContentError(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tconf := []byte(`bad json format`)\n\tdefaultConfigPath := \".config/k6/config.json\"\n\trequire.NoError(t, fsext.WriteFile(memfs, defaultConfigPath, conf, 0o644))\n\n\tgs := &state.GlobalState{\n\t\tFS:    memfs,\n\t\tFlags: state.GetDefaultFlags(\".config\", \".cache\"),\n\t}\n\t_, err := readDiskConfig(gs)\n\tvar serr *json.SyntaxError\n\tassert.ErrorAs(t, err, &serr)\n}\n\nfunc TestReadDiskConfigNotFoundErrorWithCustomPath(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\tgs.Flags.ConfigFilePath = \".config/my-custom-path/k6/config.json\"\n\n\tc, err := readDiskConfig(gs)\n\tassert.ErrorIs(t, err, fs.ErrNotExist)\n\tassert.Empty(t, c)\n}\n\nfunc TestWriteDiskConfigWithDefaultFlags(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\n\tc := Config{WebDashboard: null.BoolFrom(true)}\n\terr := writeDiskConfig(gs, c)\n\trequire.NoError(t, err)\n\n\tfinfo, err := memfs.Stat(\".config/k6/config.json\")\n\trequire.NoError(t, err)\n\tassert.NotEmpty(t, finfo.Size())\n}\n\nfunc TestWriteDiskConfigOverwrite(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tconf := []byte(`{\"iterations\":1028,\"cloud\":{\"field1\":\"testvalue\"}}`)\n\tdefaultConfigPath := \".config/k6/config.json\"\n\trequire.NoError(t, fsext.WriteFile(memfs, defaultConfigPath, conf, 0o644))\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\n\tc := Config{WebDashboard: null.BoolFrom(true)}\n\terr := writeDiskConfig(gs, c)\n\trequire.NoError(t, err)\n}\n\nfunc TestWriteDiskConfigCustomPath(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\tgs.Flags.ConfigFilePath = \"my-custom-path/config.json\"\n\n\tc := Config{WebDashboard: null.BoolFrom(true)}\n\terr := writeDiskConfig(gs, c)\n\trequire.NoError(t, err)\n}\n\nfunc TestWriteDiskConfigNoJSONContentError(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:           memfs,\n\t\tFlags:        defaultFlags,\n\t\tDefaultFlags: defaultFlags,\n\t}\n\n\tc := Config{\n\t\tWebDashboard: null.BoolFrom(true),\n\t\tOptions: lib.Options{\n\t\t\tCloud: []byte(`invalid-json`),\n\t\t},\n\t}\n\terr := writeDiskConfig(gs, c)\n\tvar serr *json.SyntaxError\n\tassert.ErrorAs(t, err, &serr)\n}\n\nfunc TestMigrateLegacyConfigFileIfAny(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tconf := []byte(`{\"iterations\":1028,\"cloud\":{\"field1\":\"testvalue\"}}`)\n\tlegacyConfigPath := \".config/loadimpact/k6/config.json\"\n\trequire.NoError(t, fsext.WriteFile(memfs, legacyConfigPath, conf, 0o644))\n\n\tl, hook := testutils.NewLoggerWithHook(t)\n\tlogger := l.(*logrus.Logger) //nolint:forbidigo // no alternative, required\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:              memfs,\n\t\tFlags:           defaultFlags,\n\t\tDefaultFlags:    defaultFlags,\n\t\tUserOSConfigDir: \".config\",\n\t\tLogger:          logger,\n\t}\n\n\terr := migrateLegacyConfigFileIfAny(gs)\n\trequire.NoError(t, err)\n\n\tf, err := fsext.ReadFile(memfs, \".config/k6/config.json\")\n\trequire.NoError(t, err)\n\tassert.Equal(t, f, conf)\n\n\ttestutils.LogContains(hook.Drain(), logrus.InfoLevel, \"migrated\")\n}\n\nfunc TestMigrateLegacyConfigFileIfAnyWhenFileDoesNotExist(t *testing.T) {\n\tt.Parallel()\n\tmemfs := fsext.NewMemMapFs()\n\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tgs := &state.GlobalState{\n\t\tFS:              memfs,\n\t\tFlags:           defaultFlags,\n\t\tDefaultFlags:    defaultFlags,\n\t\tUserOSConfigDir: \".config\",\n\t}\n\n\terr := migrateLegacyConfigFileIfAny(gs)\n\trequire.NoError(t, err)\n\n\t_, err = fsext.ReadFile(memfs, \".config/k6/config.json\")\n\tassert.ErrorIs(t, err, fs.ErrNotExist)\n}\n\nfunc TestLoadConfig(t *testing.T) {\n\tt.Parallel()\n\n\ttestcases := []struct {\n\t\tname          string\n\t\tmemfs         fsext.Fs\n\t\texpConf       Config\n\t\texpLegacyWarn bool\n\t}{\n\t\t{\n\t\t\tname: \"old and new default paths both populated\",\n\t\t\tmemfs: testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\".config/loadimpact/k6/config.json\": []byte(`{\"iterations\":1028}`),\n\t\t\t\t\".config/k6/config.json\":            []byte(`{\"iterations\":1027}`), // use different conf to be sure on assertions\n\t\t\t}),\n\t\t\texpConf:       Config{Options: lib.Options{Iterations: null.IntFrom(1027)}},\n\t\t\texpLegacyWarn: false,\n\t\t},\n\t\t{\n\t\t\tname: \"only old path\",\n\t\t\tmemfs: testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\".config/loadimpact/k6/config.json\": []byte(`{\"iterations\":1028}`),\n\t\t\t}),\n\t\t\texpConf:       Config{Options: lib.Options{Iterations: null.IntFrom(1028)}},\n\t\t\texpLegacyWarn: true,\n\t\t},\n\t\t{\n\t\t\tname: \"only new path\",\n\t\t\tmemfs: testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\".config/k6/config.json\": []byte(`{\"iterations\":1028}`),\n\t\t\t}),\n\t\t\texpConf:       Config{Options: lib.Options{Iterations: null.IntFrom(1028)}},\n\t\t\texpLegacyWarn: false,\n\t\t},\n\t\t{\n\t\t\tname:          \"no config files\", // the startup condition\n\t\t\tmemfs:         fsext.NewMemMapFs(),\n\t\t\texpConf:       Config{},\n\t\t\texpLegacyWarn: false,\n\t\t},\n\t}\n\tfor _, tc := range testcases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tl, hook := testutils.NewLoggerWithHook(t)\n\t\t\tlogger := l.(*logrus.Logger) //nolint:forbidigo // no alternative, required\n\n\t\t\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\t\t\tgs := &state.GlobalState{\n\t\t\t\tFS:              tc.memfs,\n\t\t\t\tFlags:           defaultFlags,\n\t\t\t\tDefaultFlags:    defaultFlags,\n\t\t\t\tUserOSConfigDir: \".config\",\n\t\t\t\tLogger:          logger,\n\t\t\t}\n\n\t\t\tc, err := loadConfigFile(gs)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tc.expConf, c)\n\n\t\t\t// it reads only the new one and it doesn't care about the old path\n\t\t\tassert.Equal(t, tc.expLegacyWarn, testutils.LogContains(hook.Drain(), logrus.WarnLevel, \"old default path\"))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/deps.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/build\"\n)\n\ntype depsCmd struct {\n\tgs     *state.GlobalState\n\tisJSON bool\n}\n\nfunc getCmdDeps(gs *state.GlobalState) *cobra.Command {\n\tdepsCmd := &depsCmd{gs: gs}\n\n\tcmd := &cobra.Command{\n\t\tUse:   \"deps\",\n\t\tShort: \"Resolve and list the dependencies of a test\",\n\t\tLong: \"deps command provides users a clear overview of all dependencies needed for running a script. \" +\n\t\t\t\"By analyzing imports (excluding `require` calls), the command resolves and lists the test's dependencies.\" +\n\t\t\t\" Additionally, it tells whether a custom build is required to run the script.\",\n\t\tArgs:    exactArgsWithMsg(1, \"arg should either be \\\"-\\\", if reading script from stdin, or a path to a script file\"),\n\t\tExample: getExampleText(gs, `  {{.}} deps script.js`),\n\t\tRunE:    depsCmd.run,\n\t}\n\n\tcmd.Flags().BoolVar(&depsCmd.isJSON, \"json\", false, \"if set, output dependencies information will be in JSON format\")\n\tcmd.Flags().SortFlags = false\n\tcmd.Flags().AddFlagSet(runtimeOptionFlagSet(false))\n\n\treturn cmd\n}\n\nfunc (c *depsCmd) run(cmd *cobra.Command, args []string) error {\n\ttest, err := loadLocalTestWithoutRunner(c.gs, cmd, args)\n\tif err != nil {\n\t\tvar unsatisfiedErr binaryIsNotSatisfyingDependenciesError\n\t\tif !errors.As(err, &unsatisfiedErr) {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tdeps := test.Dependencies()\n\tdepsMap := map[string]string{}\n\tfor name, constraint := range test.Dependencies() {\n\t\tif constraint == nil {\n\t\t\tdepsMap[name] = \"*\"\n\t\t\tcontinue\n\t\t}\n\t\tdepsMap[name] = constraint.String()\n\t}\n\timports := test.Imports()\n\tslices.Sort(imports)\n\n\tcustomBuildRequired := isCustomBuildRequired(deps, build.Version, ext.GetAll())\n\n\tif c.isJSON {\n\t\treturn c.outputJSON(depsMap, imports, customBuildRequired)\n\t}\n\n\treturn c.outputHumanReadable(depsMap, imports, customBuildRequired)\n}\n\nfunc (c *depsCmd) outputJSON(depsMap map[string]string, imports []string, customBuildRequired bool) error {\n\tresult := struct {\n\t\tBuildDependencies   map[string]string `json:\"buildDependencies\"`\n\t\tImports             []string          `json:\"imports\"`\n\t\tCustomBuildRequired bool              `json:\"customBuildRequired\"`\n\t}{\n\t\tBuildDependencies:   depsMap,\n\t\tImports:             imports,\n\t\tCustomBuildRequired: customBuildRequired,\n\t}\n\n\tbuf := &bytes.Buffer{}\n\tenc := json.NewEncoder(buf)\n\tenc.SetEscapeHTML(false)\n\tenc.SetIndent(\"\", \"  \")\n\tif err := enc.Encode(result); err != nil {\n\t\treturn err\n\t}\n\n\tprintToStdout(c.gs, buf.String())\n\treturn nil\n}\n\nfunc (c *depsCmd) outputHumanReadable(depsMap map[string]string, imports []string, customBuildRequired bool) error {\n\tvar output strings.Builder\n\n\t// Build Dependencies section\n\tif len(depsMap) > 0 {\n\t\toutput.WriteString(\"Build Dependencies:\\n\")\n\t\t// Sort dependencies for consistent output\n\t\tdepNames := make([]string, 0, len(depsMap))\n\t\tfor name := range depsMap {\n\t\t\tdepNames = append(depNames, name)\n\t\t}\n\t\tslices.Sort(depNames)\n\n\t\tfor _, name := range depNames {\n\t\t\tconstraint := depsMap[name]\n\t\t\tfmt.Fprintf(&output, \"  %s: %s\\n\", name, constraint)\n\t\t}\n\t\toutput.WriteString(\"\\n\")\n\t} else {\n\t\toutput.WriteString(\"Build Dependencies: (none)\\n\\n\")\n\t}\n\n\t// Imports section\n\tif len(imports) > 0 {\n\t\toutput.WriteString(\"Imports:\\n\")\n\t\tfor _, imp := range imports {\n\t\t\tfmt.Fprintf(&output, \"  %s\\n\", imp)\n\t\t}\n\t\toutput.WriteString(\"\\n\")\n\t} else {\n\t\toutput.WriteString(\"Imports: (none)\\n\\n\")\n\t}\n\n\t// Custom Build Required section\n\tif customBuildRequired {\n\t\toutput.WriteString(\"Custom Build Required: yes\\n\")\n\t} else {\n\t\toutput.WriteString(\"Custom Build Required: no\\n\")\n\t}\n\n\tprintToStdout(c.gs, output.String())\n\treturn nil\n}\n"
  },
  {
    "path": "internal/cmd/deps_test.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n)\n\nfunc TestGetCmdDeps(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tname              string\n\t\tfiles             map[string][]byte\n\t\tmanifest          string\n\t\texpectedDeps      map[string]string\n\t\texpectCustomBuild bool\n\t\texpectedImports   []string\n\t}{\n\t\t{\n\t\t\tname: \"single external dependency\",\n\t\t\tfiles: map[string][]byte{\n\t\t\t\t\"/main.js\": []byte(`import http from \"k6/http\";\nimport foo from \"k6/x/foo\";\n\nexport default function () {\n  http.get(\"https://example.com\");\n  foo();\n}\n`),\n\t\t\t},\n\t\t\texpectedDeps:      map[string]string{\"k6\": \"*\", \"k6/x/foo\": \"*\"},\n\t\t\texpectCustomBuild: true,\n\t\t\texpectedImports:   []string{\"/main.js\", \"k6/http\", \"k6/x/foo\"},\n\t\t},\n\t\t{\n\t\t\tname: \"no external dependency\",\n\t\t\tfiles: map[string][]byte{\n\t\t\t\t\"/main.js\": []byte(`import http from \"k6/http\";\n\nexport default function () {\n  http.get(\"https://example.com\");\n}\n`),\n\t\t\t},\n\t\t\texpectedDeps:      map[string]string{\"k6\": \"*\"},\n\t\t\texpectCustomBuild: false,\n\t\t\texpectedImports:   []string{\"/main.js\", \"k6/http\"},\n\t\t},\n\t\t{\n\t\t\tname: \"nested local imports\",\n\t\t\tfiles: map[string][]byte{\n\t\t\t\t\"/main.js\": []byte(`import helper from \"./lib/helper.js\";\n\nexport default function () {\n  helper();\n}\n`),\n\t\t\t\t\"/lib/helper.js\": []byte(`import nested from \"../shared/nested.js\";\nimport ext from \"k6/x/bar\";\n\nexport default function () {\n  nested();\n  ext();\n}\n`),\n\t\t\t\t\"/shared/nested.js\": []byte(`export default function () {\n  return \"nested\";\n}\n`),\n\t\t\t},\n\t\t\texpectedDeps:      map[string]string{\"k6\": \"*\", \"k6/x/bar\": \"*\"},\n\t\t\texpectCustomBuild: true,\n\t\t\texpectedImports:   []string{\"/lib/helper.js\", \"/main.js\", \"/shared/nested.js\", \"k6/x/bar\"},\n\t\t},\n\t\t{\n\t\t\tname: \"use directive across files\",\n\t\t\tfiles: map[string][]byte{\n\t\t\t\t\"/main.js\": []byte(`import directive from \"./modules/with-directive.js\";\n\nexport default function () {\n  directive();\n}\n`),\n\t\t\t\t\"/modules/with-directive.js\": []byte(`\"use k6 with k6/x/alpha >= 1.2.3\";\nimport beta from \"k6/x/beta\";\nimport util from \"./util.js\";\n\nexport default function () {\n  util();\n  beta();\n}\n`),\n\t\t\t\t\"/modules/util.js\": []byte(`export default function () {\n  return \"util\";\n}\n`),\n\t\t\t},\n\t\t\texpectedDeps:      map[string]string{\"k6\": \"*\", \"k6/x/alpha\": \">=1.2.3\", \"k6/x/beta\": \"*\"},\n\t\t\texpectCustomBuild: true,\n\t\t\texpectedImports:   []string{\"/main.js\", \"/modules/util.js\", \"/modules/with-directive.js\", \"k6/x/beta\"},\n\t\t},\n\t\t{\n\t\t\tname: \"manifest overrides default k6 constraint without use directive\",\n\t\t\tfiles: map[string][]byte{\n\t\t\t\t\"/main.js\": []byte(`import http from \"k6/http\";\n\nexport default function () {\n  http.get(\"https://example.com\");\n}\n`),\n\t\t\t},\n\t\t\tmanifest:          `{\"k6\": \">=1.6.0\"}`,\n\t\t\texpectedDeps:      map[string]string{\"k6\": \">=1.6.0\"},\n\t\t\texpectCustomBuild: false, // current k6 version satisfies >=1.6.0\n\t\t\texpectedImports:   []string{\"/main.js\", \"k6/http\"},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\tts.FS = testutils.MakeMemMapFs(t, prependCWDToFileMap(ts.Cwd, tc.files))\n\t\t\tts.Flags.DependenciesManifest = tc.manifest\n\n\t\t\tcmd := getCmdDeps(ts.GlobalState)\n\t\t\tcmd.SetArgs([]string{\"--json\", \"main.js\"})\n\t\t\trequire.NoError(t, cmd.Execute())\n\n\t\t\tvar output struct {\n\t\t\t\tBuildDependencies   map[string]string `json:\"buildDependencies\"`\n\t\t\t\tImports             []string          `json:\"imports\"`\n\t\t\t\tCustomBuildRequired bool              `json:\"customBuildRequired\"`\n\t\t\t}\n\t\t\trequire.NoError(t, json.Unmarshal(ts.Stdout.Bytes(), &output))\n\t\t\trequire.Equal(t, tc.expectedDeps, output.BuildDependencies)\n\t\t\trequire.Equal(t, tc.expectCustomBuild, output.CustomBuildRequired)\n\n\t\t\texpectedImports := slices.Clone(tc.expectedImports)\n\t\t\tfor i, expectedImport := range tc.expectedImports {\n\t\t\t\tif !strings.HasPrefix(expectedImport, \"k6\") {\n\t\t\t\t\texpectedImports[i] = \"file://\" + path.Join(\"/\", filepath.ToSlash(ts.Cwd), expectedImport)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequire.EqualValues(t, expectedImports, output.Imports)\n\t\t})\n\t}\n}\n\nfunc TestGetCmdDepsHumanReadable(t *testing.T) {\n\tt.Parallel()\n\tts := tests.NewGlobalTestState(t)\n\tts.FS = testutils.MakeMemMapFs(t, prependCWDToFileMap(ts.Cwd, map[string][]byte{\n\t\t\"/main.js\": []byte(`import http from \"k6/http\";\nimport foo from \"k6/x/foo\";\n\nexport default function () {\n  http.get(\"https://example.com\");\n  foo();\n}\n`),\n\t}))\n\n\tcmd := getCmdDeps(ts.GlobalState)\n\tcmd.SetArgs([]string{\"main.js\"})\n\trequire.NoError(t, cmd.Execute())\n\n\toutput := ts.Stdout.String()\n\t// Verify human-readable format\n\trequire.Contains(t, output, \"Build Dependencies:\")\n\trequire.Contains(t, output, \"k6: *\")\n\trequire.Contains(t, output, \"k6/x/foo: *\")\n\trequire.Contains(t, output, \"Imports:\")\n\trequire.Contains(t, output, \"Custom Build Required:\")\n\t// Should not contain JSON structure\n\trequire.NotContains(t, output, `\"buildDependencies\"`)\n\trequire.NotContains(t, output, `\"customBuildRequired\"`)\n}\n\nfunc prependCWDToFileMap(cwd string, files map[string][]byte) map[string][]byte {\n\tresult := make(map[string][]byte, len(files))\n\tfor n, b := range files {\n\t\tresult[cwd+n] = b\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "internal/cmd/doc.go",
    "content": "// Package cmd implements the command-line interface of k6.\npackage cmd\n"
  },
  {
    "path": "internal/cmd/inspect.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// TODO: split apart like `k6 run` and `k6 archive`\nfunc getCmdInspect(gs *state.GlobalState) *cobra.Command {\n\tvar addExecReqs bool\n\n\t// inspectCmd represents the inspect command\n\tinspectCmd := &cobra.Command{\n\t\tUse:   \"inspect [file]\",\n\t\tShort: \"Inspect a script or archive\",\n\t\tLong:  `Inspect a script or archive.`,\n\t\tArgs:  cobra.ExactArgs(1),\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\ttest, err := loadLocalTest(gs, cmd, args)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// At the moment, `k6 inspect` output can take 2 forms: standard\n\t\t\t// (equal to the lib.Options struct) and extended, with additional\n\t\t\t// fields with execution requirements.\n\t\t\tvar inspectOutput any\n\t\t\tif addExecReqs {\n\t\t\t\tinspectOutput, err = inspectOutputWithExecRequirements(gs, cmd, test)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tinspectOutput = test.initRunner.GetOptions()\n\t\t\t}\n\n\t\t\tdata, err := json.MarshalIndent(inspectOutput, \"\", \"  \")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tprintToStdout(gs, string(data))\n\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tinspectCmd.Flags().SortFlags = false\n\tinspectCmd.Flags().AddFlagSet(runtimeOptionFlagSet(false))\n\tinspectCmd.Flags().BoolVar(&addExecReqs,\n\t\t\"execution-requirements\",\n\t\tfalse,\n\t\t\"include calculations of execution requirements for the test\")\n\n\treturn inspectCmd\n}\n\n// If --execution-requirements is enabled, this will consolidate the config,\n// derive the value of `scenarios` and calculate the max test duration and VUs.\nfunc inspectOutputWithExecRequirements(\n\tgs *state.GlobalState, cmd *cobra.Command, test *loadedTest,\n) (any, error) {\n\t// we don't actually support CLI flags here, so we pass nil as the getter\n\tconfiguredTest, err := test.consolidateDeriveAndValidateConfig(gs, cmd, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tet, err := lib.NewExecutionTuple(\n\t\tconfiguredTest.derivedConfig.ExecutionSegment,\n\t\tconfiguredTest.derivedConfig.ExecutionSegmentSequence,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\texecutionPlan := configuredTest.derivedConfig.Scenarios.GetFullExecutionRequirements(et)\n\tduration, _ := lib.GetEndOffset(executionPlan)\n\n\treturn struct {\n\t\tlib.Options\n\t\tTotalDuration types.NullDuration `json:\"totalDuration\"`\n\t\tMaxVUs        uint64             `json:\"maxVUs\"`\n\t}{\n\t\tconfiguredTest.derivedConfig.Options,\n\t\ttypes.NewNullDuration(duration, true),\n\t\tlib.GetMaxPossibleVUs(executionPlan),\n\t}, nil\n}\n"
  },
  {
    "path": "internal/cmd/launcher.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"syscall\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/Masterminds/semver/v3\"\n\t\"github.com/grafana/k6provider\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/ext\"\n)\n\n// commandExecutor executes the requested k6 command line command.\n// It abstract the execution path from the concrete binary.\ntype commandExecutor interface {\n\trun(*state.GlobalState) error\n}\n\n// provisioner defines the interface for provisioning a commandExecutor for a set of dependencies\ntype provisioner interface {\n\tprovision(map[string]string) (commandExecutor, error)\n}\n\nfunc constraintsMapToProvisionDependency(deps map[string]*semver.Constraints) k6provider.Dependencies {\n\tresult := make(k6provider.Dependencies)\n\tfor name, constraint := range deps {\n\t\tif constraint == nil {\n\t\t\t// If dependency's constraint is nil, assume it is \"*\" and consider it satisfied.\n\t\t\t// See https://github.com/grafana/k6deps/issues/91\n\t\t\tresult[name] = \"*\"\n\t\t\tcontinue\n\t\t}\n\t\tresult[name] = constraint.String()\n\t}\n\n\treturn result\n}\n\n// customBinary runs the requested commands on a different binary on a subprocess passing the\n// original arguments\ntype customBinary struct {\n\t// path represents the local file path\n\t// on the file system of the binary\n\tpath string\n}\n\n//nolint:forbidigo\nfunc (b *customBinary) run(gs *state.GlobalState) error {\n\tcmd := exec.CommandContext(gs.Ctx, b.path, gs.CmdArgs[1:]...) //nolint:gosec\n\n\t// we pass os stdout, err, in because passing them from GlobalState changes how\n\t// the subprocess detects the type of terminal\n\tcmd.Stderr = os.Stderr\n\tcmd.Stdout = os.Stdout\n\n\t// If stdin was used by the analyze function, the content has been preserved\n\t// in `gs.Stdin` and should be passed to the command\n\tcmd.Stdin = gs.Stdin\n\n\t// Copy environment variables to the k6 process skipping auto extension resolution feature flag.\n\tenv := []string{}\n\tfor k, v := range gs.Env {\n\t\tif k == state.AutoExtensionResolution {\n\t\t\tcontinue\n\t\t}\n\t\tenv = append(env, fmt.Sprintf(\"%s=%s\", k, v))\n\t}\n\t// If auto extension resolution is enabled then\n\t// this avoids unnecessary re-processing of dependencies in the sub-process.\n\tenv = append(env, state.AutoExtensionResolution+\"=false\")\n\t// legacy envvar used in versions v1.0.x and v1.1.x\n\tenv = append(env, \"K6_BINARY_PROVISIONING=false\")\n\tcmd.Env = env\n\n\t// handle signals\n\tsigC := make(chan os.Signal, 2)\n\tgs.SignalNotify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)\n\n\tgs.Logger.Debug(\"Launching the provisioned k6 binary\")\n\n\tif err := cmd.Start(); err != nil {\n\t\tgs.Logger.\n\t\t\tWithError(err).\n\t\t\tError(\"Failed to run the provisioned k6 binary\")\n\t\treturn err\n\t}\n\n\t// wait for the subprocess to end\n\tdone := make(chan error)\n\tgo func() {\n\t\tdone <- cmd.Wait()\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase err := <-done:\n\t\t\tvar exitError *exec.ExitError\n\t\t\tif errors.As(err, &exitError) {\n\t\t\t\treturn errext.WithExitCodeIfNone(errAlreadyReported, exitcodes.ExitCode(exitError.ExitCode())) //nolint:gosec\n\t\t\t}\n\t\t\treturn err\n\t\tcase sig := <-sigC:\n\t\t\tgs.Logger.\n\t\t\t\tWithField(\"signal\", sig.String()).\n\t\t\t\tDebug(\"Signal received, waiting for the subprocess to handle it and return.\")\n\t\t}\n\t}\n}\n\n// used just to signal we shouldn't print error again\nvar errAlreadyReported = fmt.Errorf(\"already reported error\")\n\n// isCustomBuildRequired checks if there is at least one dependency that are not satisfied by the binary\n// considering the version of k6 and any built-in extension\nfunc isCustomBuildRequired(deps dependencies, k6Version string, exts []*ext.Extension) bool {\n\tif len(deps) == 0 {\n\t\treturn false\n\t}\n\n\t// collect modules that this binary contain, including k6 itself\n\tbuiltIn := map[string]string{\"k6\": k6Version}\n\tfor _, e := range exts {\n\t\tbuiltIn[e.Name] = e.Version\n\t}\n\n\tfor name, constraint := range deps {\n\t\tversion, provided := builtIn[name]\n\t\t// if the binary does not contain a required module, we need a custom\n\t\tif !provided {\n\t\t\treturn true\n\t\t}\n\n\t\t// If dependency's constraint is null, assume it is \"*\" and consider it satisfied.\n\t\t// See https://github.com/grafana/k6deps/issues/91\n\t\tif constraint == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tsemver, err := semver.NewVersion(version)\n\t\tif err != nil {\n\t\t\t// ignore built in module if version is not a valid sem ver (e.g. a development version)\n\t\t\t// if user wants to use this built-in, must disable the automatic extension resolution\n\t\t\treturn true\n\t\t}\n\n\t\t// if the current version does not satisfies the constrains, binary provisioning is required\n\t\tif !constraint.Check(semver) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// k6buildProvisioner provisions a k6 binary that satisfies the dependencies using the k6build service\ntype k6buildProvisioner struct {\n\tgs *state.GlobalState\n}\n\nfunc newK6BuildProvisioner(gs *state.GlobalState) provisioner {\n\treturn &k6buildProvisioner{gs: gs}\n}\n\nfunc (p *k6buildProvisioner) provision(deps map[string]string) (commandExecutor, error) {\n\tconfig := getProviderConfig(p.gs)\n\n\tprovider, err := k6provider.NewProvider(config)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbinary, err := provider.GetBinary(p.gs.Ctx, deps)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tp.gs.Logger.\n\t\tInfo(\"A new k6 binary has been provisioned with version(s): \", formatDependencies(binary.Dependencies))\n\n\treturn &customBinary{binary.Path}, nil\n}\n\nfunc getProviderConfig(gs *state.GlobalState) k6provider.Config {\n\tconfig := k6provider.Config{\n\t\tBuildServiceURL: gs.Flags.BuildServiceURL,\n\t\tBinaryCacheDir:  gs.Flags.BinaryCache,\n\t}\n\n\ttoken, err := extractToken(gs)\n\tif err != nil {\n\t\tgs.Logger.WithError(err).Debug(\"Failed to get cloud token\")\n\t}\n\n\tif token != \"\" {\n\t\tconfig.BuildServiceAuth = token\n\t}\n\n\treturn config\n}\n\nfunc formatDependencies(deps map[string]string) string {\n\tbuffer := &bytes.Buffer{}\n\tfor dep, version := range deps {\n\t\tfmt.Fprintf(buffer, \"%s:%s \", dep, version)\n\t}\n\treturn strings.Trim(buffer.String(), \" \")\n}\n\n// extractToken gets the cloud token required to access the build service\n// from the environment or from the config file\nfunc extractToken(gs *state.GlobalState) (string, error) {\n\tdiskConfig, err := readDiskConfig(gs)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tconfig, _, err := cloudapi.GetConsolidatedConfig(diskConfig.Collectors[\"cloud\"], gs.Env, \"\", nil, nil)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn config.Token.String, nil\n}\n\nfunc processUseDirectives(name string, text []byte, deps dependencies) error {\n\tdirectives := findDirectives(text)\n\n\tfor _, directive := range directives {\n\t\t// normalize spaces\n\t\tdirective = strings.ReplaceAll(directive, \"  \", \" \")\n\t\tif !strings.HasPrefix(directive, \"use k6\") {\n\t\t\tcontinue\n\t\t}\n\t\tdirective = strings.TrimSpace(strings.TrimPrefix(directive, \"use k6\"))\n\t\tdep := \"k6\"\n\t\tconstraint := directive\n\t\tif strings.HasPrefix(directive, \"with k6/x/\") {\n\t\t\tdirective = strings.TrimSpace(strings.TrimPrefix(directive, \"with \"))\n\t\t\tdep, constraint, _ = strings.Cut(directive, \" \")\n\t\t}\n\t\tvar con *semver.Constraints\n\t\tvar err error\n\t\tif len(constraint) > 0 {\n\t\t\tcon, err = semver.NewConstraint(constraint)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error while parsing use directives constraint %q for %q in %q: %w\", constraint, dep, name, err)\n\t\t\t}\n\t\t}\n\n\t\terr = deps.update(dep, con)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error while parsing use directives in %q: %w\", name, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc findDirectives(text []byte) []string {\n\t// parse #! at beginning of file\n\tif bytes.HasPrefix(text, []byte(\"#!\")) {\n\t\t_, text, _ = bytes.Cut(text, []byte(\"\\n\"))\n\t}\n\n\tvar result []string\n\n\tfor i := 0; i < len(text); {\n\t\tr, width := utf8.DecodeRune(text[i:])\n\t\tswitch {\n\t\tcase unicode.IsSpace(r) || r == rune(';'): // skip all spaces and ;\n\t\t\ti += width\n\t\tcase r == '\"' || r == '\\'': // string literals\n\t\t\tidx := bytes.IndexRune(text[i+width:], r)\n\t\t\tif idx < 0 {\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tresult = append(result, string(text[i+width:i+width+idx]))\n\t\t\ti += width + idx + 1\n\t\tcase bytes.HasPrefix(text[i:], []byte(\"//\")):\n\t\t\tidx := bytes.IndexRune(text[i+width:], '\\n')\n\t\t\tif idx < 0 {\n\t\t\t\treturn result\n\t\t\t}\n\t\t\ti += width + idx + 1\n\t\tcase bytes.HasPrefix(text[i:], []byte(\"/*\")):\n\t\t\tidx := bytes.Index(text[i+width:], []byte(\"*/\"))\n\t\t\tif idx < 0 {\n\t\t\t\treturn result\n\t\t\t}\n\t\t\ti += width + idx + 2\n\t\tdefault:\n\t\t\treturn result\n\t\t}\n\t}\n\treturn result\n}\n\nfunc parseManifest(manifestString string) (dependencies, error) {\n\tif manifestString == \"\" {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\tmanifestMap := make(map[string]string)\n\tif err := json.Unmarshal([]byte(manifestString), &manifestMap); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid dependencies manifest %w\", err)\n\t}\n\treturn dependenciesFromMap(manifestMap)\n}\n"
  },
  {
    "path": "internal/cmd/launcher_test.go",
    "content": "package cmd\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/Masterminds/semver/v3\"\n\t\"github.com/grafana/k6provider\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/ext\"\n\n\t\"go.k6.io/k6/internal/cmd/tests\"\n)\n\nfunc TestIsCustomBuildRequired(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\ttitle  string\n\t\tdeps   map[string]string\n\t\texts   []*ext.Extension\n\t\texpect bool\n\t}{\n\t\t{\n\t\t\ttitle:  \"k6 satisfied\",\n\t\t\tdeps:   map[string]string{\"k6\": \"=v1.0.0\"},\n\t\t\texts:   []*ext.Extension{},\n\t\t\texpect: false,\n\t\t},\n\t\t{\n\t\t\ttitle:  \"k6 not satisfied\",\n\t\t\tdeps:   map[string]string{\"k6\": \">v1.0.0\"},\n\t\t\texts:   []*ext.Extension{},\n\t\t\texpect: true,\n\t\t},\n\t\t{\n\t\t\ttitle:  \"extension not present\",\n\t\t\tdeps:   map[string]string{\"k6\": \"*\", \"k6/x/faker\": \"*\"},\n\t\t\texts:   []*ext.Extension{},\n\t\t\texpect: true,\n\t\t},\n\t\t{\n\t\t\ttitle: \"extension satisfied\",\n\t\t\tdeps:  map[string]string{\"k6/x/faker\": \"=v0.4.0\"},\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{Name: \"k6/x/faker\", Module: \"github.com/grafana/xk6-faker\", Version: \"v0.4.0\"},\n\t\t\t},\n\t\t\texpect: false,\n\t\t},\n\t\t{\n\t\t\ttitle: \"extension not satisfied\",\n\t\t\tdeps:  map[string]string{\"k6/x/faker\": \">v0.4.0\"},\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{Name: \"k6/x/faker\", Module: \"github.com/grafana/xk6-faker\", Version: \"v0.4.0\"},\n\t\t\t},\n\t\t\texpect: true,\n\t\t},\n\t\t{\n\t\t\ttitle: \"k6 and extension satisfied\",\n\t\t\tdeps:  map[string]string{\"k6\": \"=v1.0.0\", \"k6/x/faker\": \"=v0.4.0\"},\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{Name: \"k6/x/faker\", Module: \"github.com/grafana/xk6-faker\", Version: \"v0.4.0\"},\n\t\t\t},\n\t\t\texpect: false,\n\t\t},\n\t\t{\n\t\t\ttitle: \"k6 satisfied, extension not satisfied\",\n\t\t\tdeps:  map[string]string{\"k6\": \"=v1.0.0\", \"k6/x/faker\": \">v0.4.0\"},\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{Name: \"k6/x/faker\", Module: \"github.com/grafana/xk6-faker\", Version: \"v0.4.0\"},\n\t\t\t},\n\t\t\texpect: true,\n\t\t},\n\t\t{\n\t\t\ttitle: \"k6 not satisfied, extension satisfied\",\n\t\t\tdeps:  map[string]string{\"k6\": \">v1.0.0\", \"k6/x/faker\": \"=v0.4.0\"},\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{Name: \"k6/x/faker\", Module: \"github.com/grafana/xk6-faker\", Version: \"v0.4.0\"},\n\t\t\t},\n\t\t\texpect: true,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.title, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tdeps := make(map[string]*semver.Constraints)\n\t\t\tfor name, constraintStr := range tc.deps {\n\t\t\t\tconstraint, err := semver.NewConstraint(constraintStr)\n\t\t\t\tif err != nil {\n\t\t\t\t\tt.Fatalf(\"parsing %q constraint: %v\", constraintStr, err)\n\t\t\t\t}\n\t\t\t\tdeps[name] = constraint\n\t\t\t}\n\n\t\t\tk6Version := \"v1.0.0\"\n\t\t\trequired := isCustomBuildRequired(deps, k6Version, tc.exts)\n\t\t\tassert.Equal(t, tc.expect, required)\n\t\t})\n\t}\n}\n\nfunc TestGetProviderConfig(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname         string\n\t\ttoken        string\n\t\texpectConfig k6provider.Config\n\t}{\n\t\t{\n\t\t\tname:  \"no token\",\n\t\t\ttoken: \"\",\n\t\t\texpectConfig: k6provider.Config{\n\t\t\t\tBuildServiceURL:  \"https://ingest.k6.io/builder/api/v1\",\n\t\t\t\tBinaryCacheDir:   filepath.Join(\".cache\", \"k6\", \"builds\"),\n\t\t\t\tBuildServiceAuth: \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"K6_CLOUD_TOKEN set\",\n\t\t\ttoken: \"K6CLOUDTOKEN\",\n\t\t\texpectConfig: k6provider.Config{\n\t\t\t\tBuildServiceURL:  \"https://ingest.k6.io/builder/api/v1\",\n\t\t\t\tBinaryCacheDir:   filepath.Join(\".cache\", \"k6\", \"builds\"),\n\t\t\t\tBuildServiceAuth: \"K6CLOUDTOKEN\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\tif tc.token != \"\" {\n\t\t\t\tts.Env[\"K6_CLOUD_TOKEN\"] = tc.token\n\t\t\t}\n\n\t\t\tconfig := getProviderConfig(ts.GlobalState)\n\n\t\t\tassert.Equal(t, tc.expectConfig, config)\n\t\t})\n\t}\n}\n\nfunc TestProcessUseDirectives(t *testing.T) {\n\tt.Parallel()\n\ttests := map[string]struct {\n\t\tinput          string\n\t\texpectedOutput map[string]string\n\t\texpectedError  string\n\t}{\n\t\t\"nothing\": {\n\t\t\tinput: \"export default function() {}\",\n\t\t},\n\t\t\"nothing really\": {\n\t\t\tinput: `\"use k6\"`,\n\t\t\texpectedOutput: map[string]string{\n\t\t\t\t\"k6\": \"\",\n\t\t\t},\n\t\t},\n\t\t\"k6 pinning\": {\n\t\t\tinput: `\"use k6 > 1.4.0\"`,\n\t\t\texpectedOutput: map[string]string{\n\t\t\t\t\"k6\": \"> 1.4.0\",\n\t\t\t},\n\t\t},\n\t\t\"a extension\": {\n\t\t\tinput: `\"use k6 with k6/x/sql\"`,\n\t\t\texpectedOutput: map[string]string{\n\t\t\t\t\"k6/x/sql\": \"\",\n\t\t\t},\n\t\t},\n\t\t\"an extension with constraint\": {\n\t\t\tinput: `\"use k6 with k6/x/sql > 1.4.0\"`,\n\t\t\texpectedOutput: map[string]string{\n\t\t\t\t\"k6/x/sql\": \"> 1.4.0\",\n\t\t\t},\n\t\t},\n\t\t\"complex\": {\n\t\t\tinput: `\n\t\t\t\t// something here\n\t\t\t\t\"use k6 with k6/x/A\"\n\t\t\t\tfunction a (){\n\t\t\t\t\t\"use k6 with k6/x/B\"\n\t\t\t\t\tlet s = JSON.stringify( \"use k6 with k6/x/C\")\n\t\t\t\t\t\"use k6 with k6/x/D\"\n\n\t\t\t\t\treturn s\n\t\t\t\t}\n\n\t\t\t\texport const b = \"use k6 with k6/x/E\"\n\t\t\t\t\"use k6 with k6/x/F\"\n\n\t\t\t\t// Here for esbuild and k6 warnings\n\t\t\t\ta()\n\t\t\t\texport default function(){}\n\t\t\t\t`,\n\t\t\texpectedOutput: map[string]string{\n\t\t\t\t\"k6/x/A\": \"\",\n\t\t\t},\n\t\t},\n\n\t\t\"repeat\": {\n\t\t\tinput: `\n\t\t\t\t\"use k6 with k6/x/A\"\n\t\t\t\t\"use k6 with k6/x/A\"\n\t\t\t\t`,\n\t\t\texpectedOutput: map[string]string{\n\t\t\t\t\"k6/x/A\": \"\",\n\t\t\t},\n\t\t},\n\t\t\"repeat with constraint first\": {\n\t\t\tinput: `\n\t\t\t\t\"use k6 with k6/x/A > 1.4.0\"\n\t\t\t\t\"use k6 with k6/x/A\"\n\t\t\t\t`,\n\t\t\texpectedOutput: map[string]string{\n\t\t\t\t\"k6/x/A\": \"> 1.4.0\",\n\t\t\t},\n\t\t},\n\t\t\"constraint difference\": {\n\t\t\tinput: `\n\t\t\t\t\"use k6 > 1.4.0\"\n\t\t\t\t\"use k6 = 1.2.3\"\n\t\t\t\t`,\n\t\t\texpectedError: `error while parsing use directives in \"name.js\": already have constraint for \"k6\", when parsing \"=1.2.3\"`,\n\t\t},\n\t\t\"constraint difference for extensions\": {\n\t\t\tinput: `\n\t\t\t\t\"use k6 with k6/x/A > 1.4.0\"\n\t\t\t\t\"use k6 with k6/x/A = 1.2.3\"\n\t\t\t\t`,\n\t\t\texpectedError: `error while parsing use directives in \"name.js\": already have constraint for \"k6/x/A\", when parsing \"=1.2.3\"`,\n\t\t},\n\t\t\"constraint bad format\": {\n\t\t\tinput: `\n\t\t\t\t\"use k6 with k6/x/A +1.4.0\"\n\t\t\t\t`,\n\t\t\texpectedError: `error while parsing use directives constraint \"+1.4.0\" for \"k6/x/A\" in \"name.js\": improper constraint: +1.4.0`,\n\t\t},\n\t}\n\n\tfor name, test := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tdeps, err := dependenciesFromMap(test.expectedOutput)\n\t\t\trequire.NoError(t, err)\n\t\t\texpected := constraintsMapToProvisionDependency(deps)\n\t\t\tif len(test.expectedError) > 0 {\n\t\t\t\texpected = nil\n\t\t\t}\n\n\t\t\tm := make(dependencies)\n\t\t\terr = processUseDirectives(\"name.js\", []byte(test.input), m)\n\t\t\tif len(test.expectedError) > 0 {\n\t\t\t\trequire.ErrorContains(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.EqualValues(t, expected, constraintsMapToProvisionDependency(m))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestFindDirectives(t *testing.T) {\n\tt.Parallel()\n\ttests := map[string]struct {\n\t\tinput          string\n\t\texpectedOutput []string\n\t}{\n\t\t\"nothing\": {\n\t\t\tinput:          \"export default function() {}\",\n\t\t\texpectedOutput: nil,\n\t\t},\n\t\t\"nothing really\": {\n\t\t\tinput:          `\"use k6\"`,\n\t\t\texpectedOutput: []string{\"use k6\"},\n\t\t},\n\t\t\"multiline\": {\n\t\t\tinput: `\n\t\t\t\"use k6 with k6/x/sql\"\n\t\t\t\"something\"\n\t\t\t`,\n\t\t\texpectedOutput: []string{\"use k6 with k6/x/sql\", \"something\"},\n\t\t},\n\t\t\"multiline start at beginning\": {\n\t\t\tinput: `\n\"use k6 with k6/x/sql\"\n\"something\"\n\t\t\t`,\n\t\t\texpectedOutput: []string{\"use k6 with k6/x/sql\", \"something\"},\n\t\t},\n\t\t\"multiline comments\": {\n\t\t\tinput: `#!/bin/sh\n\t\t\t// here comment \"hello\"\n\"use k6 with k6/x/sql\";\n\t\t\t/*\n\t\t\t\"something else here as well\"\n\t\t\t*/\n\t;\n\"something\";\nconst l = 5\n\"more\"\n\t\t\t`,\n\t\t\texpectedOutput: []string{\"use k6 with k6/x/sql\", \"something\"},\n\t\t},\n\t}\n\n\tfor name, test := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tm := findDirectives([]byte(test.input))\n\t\t\tassert.EqualValues(t, test.expectedOutput, m)\n\t\t})\n\t}\n}\n\nfunc TestDependenciesApplyManifest(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname          string\n\t\tdeps          map[string]string\n\t\tmanifest      string\n\t\texpected      map[string]string\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:     \"default constraint with no manifest\",\n\t\t\tdeps:     map[string]string{\"k6/x/dep\": \"*\"},\n\t\t\tmanifest: \"\",\n\t\t\texpected: map[string]string{\"k6/x/dep\": \"*\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"empty constraint with no manifest\",\n\t\t\tdeps:     map[string]string{\"k6/x/dep\": \"\"},\n\t\t\tmanifest: \"\",\n\t\t\texpected: map[string]string{\"k6/x/dep\": \"\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"default constraint with empty manifest\",\n\t\t\tdeps:     map[string]string{\"k6/x/dep\": \"*\"},\n\t\t\tmanifest: \"{}\",\n\t\t\texpected: map[string]string{\"k6/x/dep\": \"*\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"default constraint with manifest overrides\",\n\t\t\tdeps:     map[string]string{\"k6/x/dep\": \"*\"},\n\t\t\tmanifest: `{\"k6/x/dep\": \"=v0.0.0\"}`,\n\t\t\texpected: map[string]string{\"k6/x/dep\": \"=v0.0.0\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"dependency with version constraint\",\n\t\t\tdeps:     map[string]string{\"k6/x/dep\": \"=v0.0.1\"},\n\t\t\tmanifest: `{\"k6/x/dep\": \"=v0.0.0\"}`,\n\t\t\texpected: map[string]string{\"k6/x/dep\": \"=v0.0.1\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"manifest with different dependency\",\n\t\t\tdeps:     map[string]string{\"k6/x/dep\": \"*\"},\n\t\t\tmanifest: `{\"k6/x/another\": \"=v0.0.0\"}`,\n\t\t\texpected: map[string]string{\"k6/x/dep\": \"*\"},\n\t\t},\n\t\t{\n\t\t\tname:     \"no dependencies\",\n\t\t\tdeps:     map[string]string{},\n\t\t\tmanifest: `{\"k6/x/dep\": \"=v0.0.0\"}`,\n\t\t\texpected: map[string]string{},\n\t\t},\n\t\t{\n\t\t\tname:          \"malformed manifest\",\n\t\t\tdeps:          map[string]string{\"k6/x/dep\": \"*\"},\n\t\t\tmanifest:      `{\"k6/x/dep\": }`,\n\t\t\texpectedError: \"invalid dependencies manifest\",\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar err error\n\t\t\tdeps := make(dependencies)\n\t\t\tfor k, v := range test.deps {\n\t\t\t\tif v == \"\" {\n\t\t\t\t\tdeps[k] = nil\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdeps[k], _ = semver.NewConstraint(v)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\tdepsMan, err := parseManifest(test.manifest)\n\t\t\trequire.NoError(t, deps.applyManifest(depsMan))\n\t\t\tif len(test.expectedError) > 0 {\n\t\t\t\trequire.ErrorContains(t, err, test.expectedError)\n\t\t\t} else {\n\t\t\t\trequire.EqualValues(t, test.expected, (map[string]string)(constraintsMapToProvisionDependency(deps)))\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/login.go",
    "content": "package cmd\n\nimport (\n\t\"github.com/spf13/cobra\"\n\n\t\"go.k6.io/k6/cmd/state\"\n)\n\n// getCmdLogin returns the `k6 login` sub-command, together with its children.\nfunc getCmdLogin(gs *state.GlobalState) *cobra.Command {\n\tloginCmd := &cobra.Command{\n\t\tUse:   \"login\",\n\t\tShort: \"Authenticate with a service\",\n\t\tLong: `Authenticate with a service.\n\nLogging into a service changes the default when just \"-o [type]\" is passed with\nno parameters, you can always override the stored credentials by passing some\non the commandline.`,\n\t\tDeprecated: `and will be removed in a future release. Please use the \"k6 cloud login\" command instead.\n`,\n\t\tRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\treturn cmd.Usage()\n\t\t},\n\t}\n\tloginCmd.AddCommand(\n\t\tgetCmdLoginCloud(gs),\n\t\tgetCmdLoginInfluxDB(gs),\n\t)\n\n\treturn loginCmd\n}\n"
  },
  {
    "path": "internal/cmd/login_cloud.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"syscall\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/term\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/ui\"\n)\n\n//nolint:funlen,gocognit\nfunc getCmdLoginCloud(gs *state.GlobalState) *cobra.Command {\n\t// loginCloudCommand represents the 'login cloud' command\n\texampleText := getExampleText(gs, `\n  # Show the stored token.\n  {{.}} login cloud -s\n\n  # Store a token.\n  {{.}} login cloud -t YOUR_TOKEN\n\n  # Log in with an email/password.\n  {{.}} login cloud`[1:])\n\n\tloginCloudCommand := &cobra.Command{\n\t\tUse:   \"cloud\",\n\t\tShort: \"Authenticate with k6 Cloud\",\n\t\tLong: `Authenticate with Grafana Cloud k6.\n\nThis will set the default token used when just \"k6 run -o cloud\" is passed.`,\n\t\tExample: exampleText,\n\t\tArgs:    cobra.NoArgs,\n\t\tDeprecated: `and will be removed in a future release.\nPlease use the \"k6 cloud login\" command instead.\n`,\n\t\tRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\tif err := migrateLegacyConfigFileIfAny(gs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcurrentDiskConf, err := readDiskConfig(gs)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcurrentJSONConfig := cloudapi.Config{}\n\t\t\tcurrentJSONConfigRaw := currentDiskConf.Collectors[\"cloud\"]\n\t\t\tif currentJSONConfigRaw != nil {\n\t\t\t\t// We only want to modify this config, see comment below\n\t\t\t\tif jsonerr := json.Unmarshal(currentJSONConfigRaw, &currentJSONConfig); jsonerr != nil {\n\t\t\t\t\treturn jsonerr\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// We want to use this fully consolidated config for things like\n\t\t\t// host addresses, so users can overwrite them with env vars.\n\t\t\tconsolidatedCurrentConfig, warn, err := cloudapi.GetConsolidatedConfig(\n\t\t\t\tcurrentJSONConfigRaw, gs.Env, \"\", nil, nil)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif warn != \"\" {\n\t\t\t\tgs.Logger.Warn(warn)\n\t\t\t}\n\n\t\t\t// But we don't want to save them back to the JSON file, we only\n\t\t\t// want to save what already existed there and the login details.\n\t\t\tnewCloudConf := currentJSONConfig\n\n\t\t\tshow := getNullBool(cmd.Flags(), \"show\")\n\t\t\treset := getNullBool(cmd.Flags(), \"reset\")\n\t\t\ttoken := getNullString(cmd.Flags(), \"token\")\n\t\t\tswitch {\n\t\t\tcase reset.Valid:\n\t\t\t\tnewCloudConf.Token = null.StringFromPtr(nil)\n\t\t\t\tprintToStdout(gs, \"  token reset\\n\")\n\t\t\tcase show.Bool:\n\t\t\tcase token.Valid:\n\t\t\t\tnewCloudConf.Token = token\n\t\t\tdefault:\n\t\t\t\tform := ui.Form{\n\t\t\t\t\tFields: []ui.Field{\n\t\t\t\t\t\tui.StringField{\n\t\t\t\t\t\t\tKey:   \"Email\",\n\t\t\t\t\t\t\tLabel: \"Email\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tui.PasswordField{\n\t\t\t\t\t\t\tKey:   \"Password\",\n\t\t\t\t\t\t\tLabel: \"Password\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tif !term.IsTerminal(int(syscall.Stdin)) { //nolint:unconvert\n\t\t\t\t\tgs.Logger.Warn(\"Stdin is not a terminal, falling back to plain text input\")\n\t\t\t\t}\n\t\t\t\tvar vals map[string]string\n\t\t\t\tvals, err = form.Run(gs.Stdin, gs.Stdout)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\temail := vals[\"Email\"]\n\t\t\t\tpassword := vals[\"Password\"]\n\n\t\t\t\tclient := cloudapi.NewClient(\n\t\t\t\t\tgs.Logger,\n\t\t\t\t\t\"\",\n\t\t\t\t\tconsolidatedCurrentConfig.Host.String,\n\t\t\t\t\tbuild.Version,\n\t\t\t\t\tconsolidatedCurrentConfig.Timeout.TimeDuration())\n\n\t\t\t\tvar res *cloudapi.LoginResponse\n\t\t\t\tres, err = client.Login(email, password)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif res.Token == \"\" {\n\t\t\t\t\treturn errors.New(`your account has no API token, please generate one at https://app.k6.io/account/api-token`)\n\t\t\t\t}\n\n\t\t\t\tnewCloudConf.Token = null.StringFrom(res.Token)\n\t\t\t}\n\n\t\t\tif currentDiskConf.Collectors == nil {\n\t\t\t\tcurrentDiskConf.Collectors = make(map[string]json.RawMessage)\n\t\t\t}\n\t\t\tcurrentDiskConf.Collectors[\"cloud\"], err = json.Marshal(newCloudConf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif err := writeDiskConfig(gs, currentDiskConf); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif newCloudConf.Token.Valid {\n\t\t\t\tvalueColor := getColor(gs.Flags.NoColor || !gs.Stdout.IsTTY, color.FgCyan)\n\t\t\t\tif !gs.Flags.Quiet {\n\t\t\t\t\tprintToStdout(gs, fmt.Sprintf(\"  token: %s\\n\", valueColor.Sprint(newCloudConf.Token.String)))\n\t\t\t\t}\n\t\t\t\tprintToStdout(gs, fmt.Sprintf(\n\t\t\t\t\t\"Logged in successfully, token saved in %s\\n\", gs.Flags.ConfigFilePath,\n\t\t\t\t))\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\tloginCloudCommand.Flags().StringP(\"token\", \"t\", \"\", \"specify `token` to use\")\n\tloginCloudCommand.Flags().BoolP(\"show\", \"s\", false, \"display saved token and exit\")\n\tloginCloudCommand.Flags().BoolP(\"reset\", \"r\", false, \"reset token\")\n\n\treturn loginCloudCommand\n}\n"
  },
  {
    "path": "internal/cmd/login_influxdb.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/spf13/cobra\"\n\t\"golang.org/x/term\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/output/influxdb\"\n\t\"go.k6.io/k6/internal/ui\"\n)\n\n//nolint:funlen\nfunc getCmdLoginInfluxDB(gs *state.GlobalState) *cobra.Command {\n\t// loginInfluxDBCommand represents the 'login influxdb' command\n\tloginInfluxDBCommand := &cobra.Command{\n\t\tUse:   \"influxdb [uri]\",\n\t\tShort: \"Authenticate with InfluxDB\",\n\t\tLong: `Authenticate with InfluxDB.\n\nThis will set the default server used when just \"-o influxdb\" is passed.`,\n\t\tArgs: cobra.MaximumNArgs(1),\n\t\tRunE: func(_ *cobra.Command, args []string) error {\n\t\t\tif err := migrateLegacyConfigFileIfAny(gs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconfig, err := readDiskConfig(gs)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconf := influxdb.NewConfig()\n\t\t\tjsonConf := config.Collectors[\"influxdb\"]\n\t\t\tif jsonConf != nil {\n\t\t\t\tjsonConfParsed, jsonerr := influxdb.ParseJSON(jsonConf)\n\t\t\t\tif jsonerr != nil {\n\t\t\t\t\treturn jsonerr\n\t\t\t\t}\n\t\t\t\tconf = conf.Apply(jsonConfParsed)\n\t\t\t}\n\t\t\tif len(args) > 0 {\n\t\t\t\turlConf, err := influxdb.ParseURL(args[0])\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tconf = conf.Apply(urlConf)\n\t\t\t}\n\n\t\t\tform := ui.Form{\n\t\t\t\tFields: []ui.Field{\n\t\t\t\t\tui.StringField{\n\t\t\t\t\t\tKey:     \"Addr\",\n\t\t\t\t\t\tLabel:   \"Address\",\n\t\t\t\t\t\tDefault: conf.Addr.String,\n\t\t\t\t\t},\n\t\t\t\t\tui.StringField{\n\t\t\t\t\t\tKey:     \"DB\",\n\t\t\t\t\t\tLabel:   \"Database\",\n\t\t\t\t\t\tDefault: conf.DB.String,\n\t\t\t\t\t},\n\t\t\t\t\tui.StringField{\n\t\t\t\t\t\tKey:     \"Username\",\n\t\t\t\t\t\tLabel:   \"Username\",\n\t\t\t\t\t\tDefault: conf.Username.String,\n\t\t\t\t\t},\n\t\t\t\t\tui.PasswordField{\n\t\t\t\t\t\tKey:   \"Password\",\n\t\t\t\t\t\tLabel: \"Password\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\tif !term.IsTerminal(int(syscall.Stdin)) { //nolint:unconvert\n\t\t\t\tgs.Logger.Warn(\"Stdin is not a terminal, falling back to plain text input\")\n\t\t\t}\n\t\t\tvals, err := form.Run(gs.Stdin, gs.Stdout)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tconf.Addr = null.StringFrom(vals[\"Addr\"])\n\t\t\tconf.DB = null.StringFrom(vals[\"DB\"])\n\t\t\tconf.Username = null.StringFrom(vals[\"Username\"])\n\t\t\tconf.Password = null.StringFrom(vals[\"Password\"])\n\n\t\t\tclient, err := influxdb.MakeClient(conf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif _, _, err = client.Ping(10 * time.Second); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif config.Collectors == nil {\n\t\t\t\tconfig.Collectors = make(map[string]json.RawMessage)\n\t\t\t}\n\t\t\tconfig.Collectors[\"influxdb\"], err = json.Marshal(conf)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn writeDiskConfig(gs, config)\n\t\t},\n\t}\n\treturn loginInfluxDBCommand\n}\n"
  },
  {
    "path": "internal/cmd/new.go",
    "content": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/cmd/templates\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nconst defaultNewScriptName = \"script.js\"\n\ntype newScriptCmd struct {\n\tgs             *state.GlobalState\n\toverwriteFiles bool\n\ttemplateType   string\n\tprojectID      string\n}\n\nfunc (c *newScriptCmd) flagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", pflag.ContinueOnError)\n\tflags.SortFlags = false\n\tflags.BoolVarP(&c.overwriteFiles, \"force\", \"f\", false, \"overwrite existing files\")\n\tflags.StringVar(&c.templateType, \"template\", \"minimal\", \"template type (choices: minimal, protocol, browser) or relative/absolute path to a custom template file\") //nolint:lll\n\tflags.StringVar(&c.projectID, \"project-id\", \"\", \"specify the Grafana Cloud project ID for the test\")\n\treturn flags\n}\n\nfunc (c *newScriptCmd) run(_ *cobra.Command, args []string) (err error) {\n\ttarget := defaultNewScriptName\n\tif len(args) > 0 {\n\t\ttarget = args[0]\n\t}\n\n\tfileExists, err := fsext.Exists(c.gs.FS, target)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif fileExists && !c.overwriteFiles {\n\t\treturn fmt.Errorf(\"%s already exists. Use the `--force` flag to overwrite it\", target)\n\t}\n\n\t// Initialize template manager and validate template before creating any files\n\ttm, err := templates.NewTemplateManager(c.gs.FS)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error initializing template manager: %w\", err)\n\t}\n\n\ttmpl, err := tm.GetTemplate(c.templateType)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error retrieving template: %w\", err)\n\t}\n\n\t// Prepare template arguments\n\targsStruct := templates.TemplateArgs{\n\t\tScriptName: target,\n\t\tProjectID:  c.projectID,\n\t}\n\n\t// First render the template to a buffer to validate it\n\tvar buf strings.Builder\n\tif err := templates.ExecuteTemplate(&buf, tmpl, argsStruct); err != nil {\n\t\treturn fmt.Errorf(\"failed to execute template %s: %w\", c.templateType, err)\n\t}\n\n\t// Only create the file after template rendering succeeds\n\tfd, err := c.gs.FS.Create(target)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tif cerr := fd.Close(); cerr != nil {\n\t\t\tif _, werr := fmt.Fprintf(c.gs.Stderr, \"error closing file: %v\\n\", cerr); werr != nil {\n\t\t\t\terr = fmt.Errorf(\"error writing error message to stderr: %w\", werr)\n\t\t\t} else {\n\t\t\t\terr = cerr\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Write the rendered content to the file\n\tif _, err := io.WriteString(fd, buf.String()); err != nil {\n\t\treturn err\n\t}\n\n\tif _, err := fmt.Fprintf(c.gs.Stdout, \"New script created: %s (%s template).\\n\", target, c.templateType); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc getCmdNewScript(gs *state.GlobalState) *cobra.Command {\n\tc := &newScriptCmd{gs: gs}\n\n\texampleText := getExampleText(c.gs, `\n    # Create a new k6 script with the default template\n    $ {{.}} new\n\n    # Specify a file name when creating a script\n    $ {{.}} new test.js\n\n    # Overwrite an existing file\n    $ {{.}} new -f test.js\n\n    # Create a script using a specific template\n    $ {{.}} new --template protocol\n\n    # Create a cloud-ready script with a specific project ID\n    $ {{.}} new --project-id 12315`[1:])\n\n\tinitCmd := &cobra.Command{\n\t\tUse:   \"new [file]\",\n\t\tShort: \"Create a test\",\n\t\tLong: `Create and initialize a new k6 script using one of the predefined templates.\n\nBy default, the script will be named script.js unless a different name is specified.`,\n\t\tExample: exampleText,\n\t\tArgs:    cobra.MaximumNArgs(1),\n\t\tRunE:    c.run,\n\t}\n\n\tinitCmd.Flags().AddFlagSet(c.flagSet())\n\treturn initCmd\n}\n"
  },
  {
    "path": "internal/cmd/new_test.go",
    "content": "package cmd\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestNewScriptCmd(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname              string\n\t\tscriptNameArg     string\n\t\texpectedCloudName string\n\t\texpectedFilePath  string\n\t}{\n\t\t{\n\t\t\tname:              \"default script name\",\n\t\t\texpectedCloudName: \"script.js\",\n\t\t\texpectedFilePath:  defaultNewScriptName,\n\t\t},\n\t\t{\n\t\t\tname:              \"user-specified script name\",\n\t\t\tscriptNameArg:     \"mytest.js\",\n\t\t\texpectedCloudName: \"mytest.js\",\n\t\t\texpectedFilePath:  \"mytest.js\",\n\t\t},\n\t\t{\n\t\t\tname:              \"script outside of current working directory\",\n\t\t\tscriptNameArg:     \"../mytest.js\",\n\t\t\texpectedCloudName: \"mytest.js\",\n\t\t\texpectedFilePath:  \"../mytest.js\",\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\tts.CmdArgs = []string{\"k6\", \"new\"}\n\t\t\tif testCase.scriptNameArg != \"\" {\n\t\t\t\tts.CmdArgs = append(ts.CmdArgs, testCase.scriptNameArg)\n\t\t\t}\n\n\t\t\tnewRootCommand(ts.GlobalState).execute()\n\n\t\t\tdata, err := fsext.ReadFile(ts.FS, testCase.expectedFilePath)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tjsData := string(data)\n\t\t\tassert.Contains(t, jsData, \"export const options = {\")\n\t\t\tassert.Contains(t, jsData, \"export default function() {\")\n\t\t})\n\t}\n}\n\nfunc TestNewScriptCmd_FileExists_NoOverwrite(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, defaultNewScriptName, []byte(\"untouched\"), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"new\"}\n\tts.ExpectedExitCode = -1\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tdata, err := fsext.ReadFile(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\n\tassert.Contains(t, string(data), \"untouched\")\n}\n\nfunc TestNewScriptCmd_FileExists_Overwrite(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, defaultNewScriptName, []byte(\"untouched\"), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"new\", \"-f\"}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tdata, err := fsext.ReadFile(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\n\tassert.Contains(t, string(data), \"export const options = {\")\n\tassert.Contains(t, string(data), \"export default function() {\")\n}\n\nfunc TestNewScriptCmd_InvalidTemplateType(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"new\", \"--template\", \"invalid-template\"}\n\tts.ExpectedExitCode = -1\n\n\tnewRootCommand(ts.GlobalState).execute()\n\tassert.Contains(t, ts.Stderr.String(), \"invalid template type\")\n\n\t// Verify that no script file was created\n\texists, err := fsext.Exists(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\tassert.False(t, exists, \"script file should not exist\")\n}\n\nfunc TestNewScriptCmd_ProjectID(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"new\", \"--project-id\", \"1422\"}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tdata, err := fsext.ReadFile(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\n\tassert.Contains(t, string(data), \"projectID: 1422\")\n}\n\nfunc TestNewScriptCmd_LocalTemplate(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\n\t// Create template file in test temp directory\n\ttemplatePath := filepath.Join(t.TempDir(), \"template.js\")\n\ttemplateContent := `export default function() {\n  console.log(\"Hello, world!\");\n}`\n\trequire.NoError(t, fsext.WriteFile(ts.FS, templatePath, []byte(templateContent), 0o600))\n\n\tts.CmdArgs = []string{\"k6\", \"new\", \"--template\", templatePath}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tdata, err := fsext.ReadFile(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, templateContent, string(data), \"generated file should match the template content\")\n}\n\nfunc TestNewScriptCmd_LocalTemplateWith_ProjectID(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\n\t// Create template file in test temp directory\n\ttemplatePath := filepath.Join(t.TempDir(), \"template.js\")\n\ttemplateContent := `export default function() {\n  // Template with {{ .ProjectID }} project ID\n  console.log(\"Hello from project {{ .ProjectID }}\");\n}`\n\trequire.NoError(t, fsext.WriteFile(ts.FS, templatePath, []byte(templateContent), 0o600))\n\n\tts.CmdArgs = []string{\"k6\", \"new\", \"--template\", templatePath, \"--project-id\", \"9876\"}\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tdata, err := fsext.ReadFile(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\n\texpectedContent := `export default function() {\n  // Template with 9876 project ID\n  console.log(\"Hello from project 9876\");\n}`\n\tassert.Equal(t, expectedContent, string(data), \"generated file should have project ID interpolated\")\n}\n\nfunc TestNewScriptCmd_LocalTemplate_NonExistentFile(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\tts.ExpectedExitCode = -1\n\n\t// Use a path that we know doesn't exist in the temp directory\n\tnonExistentPath := filepath.Join(t.TempDir(), \"nonexistent.js\")\n\n\tts.CmdArgs = []string{\"k6\", \"new\", \"--template\", nonExistentPath}\n\tts.ExpectedExitCode = -1\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tassert.Contains(t, ts.Stderr.String(), \"failed to read template file\")\n\n\t// Verify that no script file was created\n\texists, err := fsext.Exists(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\tassert.False(t, exists, \"script file should not exist\")\n}\n\nfunc TestNewScriptCmd_LocalTemplate_SyntaxError(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\tts.ExpectedExitCode = -1\n\n\t// Create template file with invalid content in test temp directory\n\ttemplatePath := filepath.Join(t.TempDir(), \"template.js\")\n\tinvalidTemplateContent := `export default function() {\n  // Invalid template with {{ .InvalidField }} field\n  console.log(\"This will cause an error\");\n}`\n\trequire.NoError(t, fsext.WriteFile(ts.FS, templatePath, []byte(invalidTemplateContent), 0o600))\n\n\tts.CmdArgs = []string{\"k6\", \"new\", \"--template\", templatePath, \"--project-id\", \"9876\"}\n\tts.ExpectedExitCode = -1\n\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tassert.Contains(t, ts.Stderr.String(), \"failed to execute template\")\n\n\t// Verify that no script file was created\n\texists, err := fsext.Exists(ts.FS, defaultNewScriptName)\n\trequire.NoError(t, err)\n\tassert.False(t, exists, \"script file should not exist\")\n}\n"
  },
  {
    "path": "internal/cmd/options.go",
    "content": "package cmd\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/spf13/pflag\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nvar (\n\terrTagEmptyName   = errors.New(\"invalid tag, empty name\")\n\terrTagEmptyValue  = errors.New(\"invalid tag, empty value\")\n\terrTagEmptyString = errors.New(\"invalid tag, empty string\")\n)\n\nfunc optionFlagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", 0)\n\tflags.SortFlags = false\n\n\tflags.Int64P(\"vus\", \"u\", 1, \"number of virtual users\")\n\tflags.DurationP(\"duration\", \"d\", 0, \"test duration limit\")\n\tflags.Int64P(\"iterations\", \"i\", 0, \"script total iteration limit (among all VUs)\")\n\tflags.StringSliceP(\"stage\", \"s\", nil, \"add a `stage`, as `[duration]:[target]`\")\n\tflags.String(\"execution-segment\", \"\", \"limit execution to the specified segment, e.g. 10%, 1/3, 0.2:2/3\")\n\tflags.String(\"execution-segment-sequence\", \"\", \"the execution segment sequence\") // TODO better description\n\tflags.BoolP(\"paused\", \"p\", false, \"start the test in a paused state\")\n\tflags.Bool(\"no-setup\", false, \"don't run setup()\")\n\tflags.Bool(\"no-teardown\", false, \"don't run teardown()\")\n\tflags.Int64(\"max-redirects\", 10, \"follow at most n redirects\")\n\tflags.Int64(\"batch\", 20, \"max parallel batch reqs\")\n\tflags.Int64(\"batch-per-host\", 6, \"max parallel batch reqs per host\")\n\tflags.Int64(\"rps\", 0, \"limit requests per second\")\n\tflags.String(\"user-agent\", fmt.Sprintf(\"Grafana k6/%s\", build.Version), \"user agent for http requests\")\n\tflags.String(\"http-debug\", \"\", \"log all HTTP requests and responses. Excludes body by default. To include body use '--http-debug=full'\") //nolint:lll\n\tflags.Lookup(\"http-debug\").NoOptDefVal = \"headers\"\n\tflags.Bool(\"insecure-skip-tls-verify\", false, \"skip verification of TLS certificates\")\n\tflags.Bool(\"no-connection-reuse\", false, \"disable keep-alive connections\")\n\tflags.Bool(\"no-vu-connection-reuse\", false, \"don't reuse connections between iterations\")\n\tflags.Duration(\"min-iteration-duration\", 0, \"minimum amount of time k6 will take executing a single iteration\")\n\tflags.BoolP(\"throw\", \"w\", false, \"throw warnings (like failed http requests) as errors\")\n\tflags.StringSlice(\"blacklist-ip\", nil, \"blacklist an `ip range` from being called\")\n\tflags.StringSlice(\"block-hostnames\", nil, \"block a case-insensitive hostname `pattern`,\"+\n\t\t\" with optional leading wildcard, from being called\")\n\n\t// The comment about system-tags also applies for summary-trend-stats. The default values\n\t// are set in applyDefault().\n\tsumTrendStatsHelp := fmt.Sprintf(\n\t\t\"define `stats` for trend metrics (response times), one or more as 'avg,p(95),...' (default '%s')\",\n\t\tstrings.Join(lib.DefaultSummaryTrendStats, \", \"),\n\t)\n\tflags.StringSlice(\"summary-trend-stats\", nil, sumTrendStatsHelp)\n\tflags.String(\"summary-time-unit\", \"\", \"define the time unit used to display the trend stats. Possible units are: 's', 'ms' and 'us'\") //nolint:lll\n\t// system-tags must have a default value, but we can't specify it here, otherwiese, it will always override others.\n\t// set it to nil here, and add the default in applyDefault() instead.\n\tsystemTagsCliHelpText := fmt.Sprintf(\n\t\t\"only include these system tags in metrics (default %q)\",\n\t\tstrings.ReplaceAll(metrics.DefaultSystemTagSet.SetString(), \",\", \", \"),\n\t)\n\tflags.StringSlice(\"system-tags\", nil, systemTagsCliHelpText)\n\tflags.StringArray(\"tag\", nil, \"add a `tag` to be applied to all samples, as `[name]=[value]`\")\n\tflags.String(\"console-output\", \"\", \"redirects the console logging to the provided output file\")\n\tflags.Bool(\"discard-response-bodies\", false, \"Read but don't process or save HTTP response bodies\")\n\tflags.String(\"local-ips\", \"\", \"Client IP Ranges and/or CIDRs from which each VU will be making requests, \"+\n\t\t\"e.g. '192.168.220.1,192.168.0.10-192.168.0.25', 'fd:1::0/120', etc.\")\n\tflags.String(\"dns\", types.DefaultDNSConfig().String(), \"DNS resolver configuration. Possible ttl values are: 'inf' \"+\n\t\t\"for a persistent cache, '0' to disable the cache, or a positive duration, e.g. '1s', '1m', etc. \"+\n\t\t\"Milliseconds are assumed if no unit is provided. \"+\n\t\t\"Possible select values to return a single IP are: 'first', 'random' or 'roundRobin'. \"+\n\t\t\"Possible policy values are: 'preferIPv4', 'preferIPv6', 'onlyIPv4', 'onlyIPv6' or 'any'.\")\n\treturn flags\n}\n\n//nolint:funlen,gocognit,cyclop // this needs breaking up but probably should wait for croconf\nfunc getOptions(flags *pflag.FlagSet) (lib.Options, error) {\n\topts := lib.Options{\n\t\tVUs:                     getNullInt64(flags, \"vus\"),\n\t\tDuration:                getNullDuration(flags, \"duration\"),\n\t\tIterations:              getNullInt64(flags, \"iterations\"),\n\t\tPaused:                  getNullBool(flags, \"paused\"),\n\t\tNoSetup:                 getNullBool(flags, \"no-setup\"),\n\t\tNoTeardown:              getNullBool(flags, \"no-teardown\"),\n\t\tMaxRedirects:            getNullInt64(flags, \"max-redirects\"),\n\t\tBatch:                   getNullInt64(flags, \"batch\"),\n\t\tBatchPerHost:            getNullInt64(flags, \"batch-per-host\"),\n\t\tRPS:                     getNullInt64(flags, \"rps\"),\n\t\tUserAgent:               getNullString(flags, \"user-agent\"),\n\t\tHTTPDebug:               getNullString(flags, \"http-debug\"),\n\t\tInsecureSkipTLSVerify:   getNullBool(flags, \"insecure-skip-tls-verify\"),\n\t\tNoConnectionReuse:       getNullBool(flags, \"no-connection-reuse\"),\n\t\tNoVUConnectionReuse:     getNullBool(flags, \"no-vu-connection-reuse\"),\n\t\tMinIterationDuration:    getNullDuration(flags, \"min-iteration-duration\"),\n\t\tThrow:                   getNullBool(flags, \"throw\"),\n\t\tDiscardResponseBodies:   getNullBool(flags, \"discard-response-bodies\"),\n\t\tMetricSamplesBufferSize: null.NewInt(1000, false),\n\t}\n\n\t// Using Changed() because GetStringSlice() doesn't differentiate between empty and no value\n\tif flags.Changed(\"stage\") {\n\t\tstageStrings, err := flags.GetStringSlice(\"stage\")\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t\topts.Stages = []lib.Stage{}\n\t\tfor i, s := range stageStrings {\n\t\t\tvar stage lib.Stage\n\t\t\tif err := stage.UnmarshalText([]byte(s)); err != nil {\n\t\t\t\treturn opts, fmt.Errorf(\"error for stage %d: %w\", i, err)\n\t\t\t}\n\t\t\tif !stage.Duration.Valid {\n\t\t\t\treturn opts, fmt.Errorf(\"stage %d doesn't have a specified duration\", i)\n\t\t\t}\n\t\t\topts.Stages = append(opts.Stages, stage)\n\t\t}\n\t}\n\n\tif flags.Changed(\"execution-segment\") {\n\t\texecutionSegmentStr, err := flags.GetString(\"execution-segment\")\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t\tsegment := new(lib.ExecutionSegment)\n\t\terr = segment.UnmarshalText([]byte(executionSegmentStr))\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t\topts.ExecutionSegment = segment\n\t}\n\n\tif flags.Changed(\"execution-segment-sequence\") {\n\t\texecutionSegmentSequenceStr, err := flags.GetString(\"execution-segment-sequence\")\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t\tsegmentSequence := new(lib.ExecutionSegmentSequence)\n\t\terr = segmentSequence.UnmarshalText([]byte(executionSegmentSequenceStr))\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t\topts.ExecutionSegmentSequence = segmentSequence\n\t}\n\n\tif flags.Changed(\"system-tags\") {\n\t\tsystemTagList, err := flags.GetStringSlice(\"system-tags\")\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t\topts.SystemTags = metrics.ToSystemTagSet(systemTagList)\n\t}\n\n\tblacklistIPStrings, err := flags.GetStringSlice(\"blacklist-ip\")\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\tfor _, s := range blacklistIPStrings {\n\t\tnet, parseErr := lib.ParseCIDR(s)\n\t\tif parseErr != nil {\n\t\t\treturn opts, fmt.Errorf(\"error parsing blacklist-ip '%s': %w\", s, parseErr)\n\t\t}\n\t\topts.BlacklistIPs = append(opts.BlacklistIPs, net)\n\t}\n\n\tblockedHostnameStrings, err := flags.GetStringSlice(\"block-hostnames\")\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\tif flags.Changed(\"block-hostnames\") {\n\t\topts.BlockedHostnames, err = types.NewNullHostnameTrie(blockedHostnameStrings)\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t}\n\n\tlocalIpsString, err := flags.GetString(\"local-ips\")\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\tif flags.Changed(\"local-ips\") {\n\t\terr = opts.LocalIPs.UnmarshalText([]byte(localIpsString))\n\t\tif err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t}\n\n\tif flags.Changed(\"summary-trend-stats\") {\n\t\ttrendStats, errSts := flags.GetStringSlice(\"summary-trend-stats\")\n\t\tif errSts != nil {\n\t\t\treturn opts, errSts\n\t\t}\n\t\tif _, errSts = metrics.GetResolversForTrendColumns(trendStats); errSts != nil {\n\t\t\treturn opts, errSts\n\t\t}\n\t\topts.SummaryTrendStats = trendStats\n\t}\n\n\tsummaryTimeUnit, err := flags.GetString(\"summary-time-unit\")\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\tif summaryTimeUnit != \"\" {\n\t\tif summaryTimeUnit != \"s\" && summaryTimeUnit != \"ms\" && summaryTimeUnit != \"us\" {\n\t\t\treturn opts, fmt.Errorf(\"invalid summary time unit '%s', use 's', 'ms' or 'us'\", summaryTimeUnit)\n\t\t}\n\t\topts.SummaryTimeUnit = null.StringFrom(summaryTimeUnit)\n\t}\n\n\trunTags, err := flags.GetStringArray(\"tag\")\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\n\tif len(runTags) > 0 {\n\t\tparsedRunTags := make(map[string]string, len(runTags))\n\t\tfor _, s := range runTags {\n\t\t\tvar name, value string\n\t\t\tname, value, err = parseTagNameValue(s)\n\t\t\tif err != nil {\n\t\t\t\treturn opts, fmt.Errorf(\"error parsing tag '%s': %w\", s, err)\n\t\t\t}\n\t\t\tparsedRunTags[name] = value\n\t\t}\n\t\topts.RunTags = parsedRunTags\n\t}\n\n\tredirectConFile, err := flags.GetString(\"console-output\")\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\n\tif redirectConFile != \"\" {\n\t\topts.ConsoleOutput = null.StringFrom(redirectConFile)\n\t}\n\n\tif dns, err := flags.GetString(\"dns\"); err != nil {\n\t\treturn opts, err\n\t} else if dns != \"\" {\n\t\tif err := opts.DNS.UnmarshalText([]byte(dns)); err != nil {\n\t\t\treturn opts, err\n\t\t}\n\t}\n\n\treturn opts, nil\n}\n\nfunc parseTagNameValue(nv string) (string, string, error) {\n\tif nv == \"\" {\n\t\treturn \"\", \"\", errTagEmptyString\n\t}\n\n\tidx := strings.IndexRune(nv, '=')\n\n\tswitch idx {\n\tcase 0:\n\t\treturn \"\", \"\", errTagEmptyName\n\tcase -1, len(nv) - 1:\n\t\treturn \"\", \"\", errTagEmptyValue\n\tdefault:\n\t\treturn nv[:idx], nv[idx+1:], nil\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/options_test.go",
    "content": "package cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestParseTagKeyValue(t *testing.T) {\n\tt.Parallel()\n\ttestData := []struct {\n\t\tinput string\n\t\tname  string\n\t\tvalue string\n\t\terr   error\n\t}{\n\t\t{\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\terrTagEmptyString,\n\t\t},\n\t\t{\n\t\t\t\"=\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\terrTagEmptyName,\n\t\t},\n\t\t{\n\t\t\t\"=test\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\terrTagEmptyName,\n\t\t},\n\t\t{\n\t\t\t\"test\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\terrTagEmptyValue,\n\t\t},\n\t\t{\n\t\t\t\"test=\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\terrTagEmptyValue,\n\t\t},\n\t\t{\n\t\t\t\"myTag=foo\",\n\t\t\t\"myTag\",\n\t\t\t\"foo\",\n\t\t\tnil,\n\t\t},\n\t}\n\n\tfor _, data := range testData {\n\t\tt.Run(data.input, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tname, value, err := parseTagNameValue(data.input)\n\t\t\tassert.Equal(t, name, data.name)\n\t\t\tassert.Equal(t, value, data.value)\n\t\t\tassert.Equal(t, err, data.err)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/outputs.go",
    "content": "package cmd\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/output/cloud\"\n\t\"go.k6.io/k6/internal/output/csv\"\n\t\"go.k6.io/k6/internal/output/influxdb\"\n\t\"go.k6.io/k6/internal/output/json\"\n\t\"go.k6.io/k6/internal/output/opentelemetry\"\n\t\"go.k6.io/k6/internal/output/prometheusrw/remotewrite\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/output\"\n\n\t\"github.com/grafana/xk6-dashboard/dashboard\"\n)\n\n// builtinOutput marks the available builtin outputs.\n//\n// NOTE: that the enumer is the github.com/dmarkham/enumer\n//\n//go:generate go run github.com/dmarkham/enumer@v1.5.11 -type=builtinOutput -trimprefix builtinOutput -transform=kebab -output builtin_output_gen.go\ntype builtinOutput uint32\n\nconst (\n\tbuiltinOutputCloud builtinOutput = iota\n\tbuiltinOutputCSV\n\tbuiltinOutputDatadog\n\tbuiltinOutputExperimentalPrometheusRW\n\tbuiltinOutputInfluxdb\n\tbuiltinOutputJSON\n\tbuiltinOutputKafka\n\tbuiltinOutputStatsd\n\tbuiltinOutputExperimentalOpentelemetry\n\tbuiltinOutputOpentelemetry\n\tbuiltinOutputSummary\n)\n\n// TODO: move this to an output sub-module after we get rid of the old collectors?\nfunc getAllOutputConstructors() (map[string]output.Constructor, error) {\n\t// Start with the built-in outputs\n\tresult := map[string]output.Constructor{\n\t\tbuiltinOutputJSON.String():     json.New,\n\t\tbuiltinOutputCloud.String():    cloud.New,\n\t\tbuiltinOutputCSV.String():      csv.New,\n\t\tbuiltinOutputInfluxdb.String(): influxdb.New,\n\t\tbuiltinOutputKafka.String(): func(_ output.Params) (output.Output, error) {\n\t\t\treturn nil, errors.New(\"the kafka output was deprecated in k6 v0.32.0 and removed in k6 v0.34.0, \" +\n\t\t\t\t\"please use the new xk6 kafka output extension instead - https://github.com/k6io/xk6-output-kafka\")\n\t\t},\n\t\tbuiltinOutputStatsd.String(): func(_ output.Params) (output.Output, error) {\n\t\t\treturn nil, errors.New(\"the statsd output was deprecated in k6 v0.47.0 and removed in k6 v0.55.0, \" +\n\t\t\t\t\"please use the new xk6 statsd output extension instead. \" +\n\t\t\t\t\"It can be found at https://github.com/LeonAdato/xk6-output-statsd and \" +\n\t\t\t\t\"more info at https://github.com/grafana/k6/issues/2982\")\n\t\t},\n\t\tbuiltinOutputDatadog.String(): func(_ output.Params) (output.Output, error) {\n\t\t\treturn nil, errors.New(\"the datadog output was deprecated in k6 v0.32.0 and removed in k6 v0.34.0, \" +\n\t\t\t\t\"please use the statsd output extension https://github.com/LeonAdato/xk6-output-statsd with environment \" +\n\t\t\t\t\"variable K6_STATSD_ENABLE_TAGS=true or an experimental opentelemetry output instead\",\n\t\t\t)\n\t\t},\n\t\tbuiltinOutputExperimentalPrometheusRW.String(): func(params output.Params) (output.Output, error) {\n\t\t\treturn remotewrite.New(params)\n\t\t},\n\t\t\"web-dashboard\": dashboard.New,\n\t\tbuiltinOutputExperimentalOpentelemetry.String(): func(params output.Params) (output.Output, error) {\n\t\t\tparams.Logger.Warnf(\"OpenTelemetry output has been graduated as a stable output.\"+\n\t\t\t\t\"You can now use just %q instead of %q. The experimental version will be removed in future versions.\",\n\n\t\t\t\t\"opentelemetry\", \"experimental-opentelemetry\")\n\t\t\treturn opentelemetry.New(params)\n\t\t},\n\t\tbuiltinOutputOpentelemetry.String(): func(params output.Params) (output.Output, error) {\n\t\t\treturn opentelemetry.New(params)\n\t\t},\n\t}\n\n\texts := ext.Get(ext.OutputExtension)\n\tfor _, e := range exts {\n\t\tif _, ok := result[e.Name]; ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid output extension %s, built-in output with the same type already exists\", e.Name)\n\t\t}\n\t\tm, ok := e.Module.(output.Constructor)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected output extension type %T\", e.Module)\n\t\t}\n\t\tresult[e.Name] = m\n\t}\n\n\treturn result, nil\n}\n\nfunc getPossibleIDList(constrs map[string]output.Constructor) string {\n\tres := make([]string, 0, len(constrs))\n\tfor k := range constrs {\n\t\tif k == \"kafka\" || k == \"datadog\" {\n\t\t\tcontinue\n\t\t}\n\t\tres = append(res, k)\n\t}\n\tsort.Strings(res)\n\treturn strings.Join(res, \", \")\n}\n\nfunc createOutputs(\n\tgs *state.GlobalState, test *loadedAndConfiguredTest, executionPlan []lib.ExecutionStep,\n) ([]output.Output, error) {\n\toutputConstructors, err := getAllOutputConstructors()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbaseParams := output.Params{\n\t\tScriptPath:     test.source.URL,\n\t\tLogger:         gs.Logger,\n\t\tEnvironment:    gs.Env,\n\t\tStdOut:         gs.Stdout,\n\t\tStdErr:         gs.Stderr,\n\t\tFS:             gs.FS,\n\t\tScriptOptions:  test.derivedConfig.Options,\n\t\tRuntimeOptions: test.preInitState.RuntimeOptions,\n\t\tExecutionPlan:  executionPlan,\n\t\tUsage:          test.preInitState.Usage,\n\t}\n\n\toutputs := test.derivedConfig.Out\n\tif test.derivedConfig.WebDashboard.Bool {\n\t\toutputs = append(outputs, dashboard.OutputName)\n\t}\n\n\tresult := make([]output.Output, 0, len(outputs))\n\n\tfor _, outputFullArg := range outputs {\n\t\toutputType, outputArg, _ := strings.Cut(outputFullArg, \"=\")\n\t\toutputConstructor, ok := outputConstructors[outputType]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"invalid output type '%s', available types are: %s\",\n\t\t\t\toutputType, getPossibleIDList(outputConstructors),\n\t\t\t)\n\t\t}\n\t\tif _, builtinErr := builtinOutputString(outputType); builtinErr == nil {\n\t\t\terr := test.preInitState.Usage.Strings(\"outputs\", outputType)\n\t\t\tif err != nil {\n\t\t\t\tgs.Logger.WithError(err).Warnf(\"Couldn't report usage for output %q\", outputType)\n\t\t\t}\n\t\t}\n\n\t\tparams := baseParams\n\t\tparams.OutputType = outputType\n\t\tparams.ConfigArgument = outputArg\n\t\tparams.JSONConfig = test.derivedConfig.Collectors[outputType]\n\n\t\tout, err := outputConstructor(params)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"could not create the '%s' output: %w\", outputType, err)\n\t\t}\n\n\t\tif thresholdOut, ok := out.(output.WithThresholds); ok {\n\t\t\tthresholdOut.SetThresholds(test.derivedConfig.Thresholds)\n\t\t}\n\n\t\tif builtinMetricOut, ok := out.(output.WithBuiltinMetrics); ok {\n\t\t\tbuiltinMetricOut.SetBuiltinMetrics(test.preInitState.BuiltinMetrics)\n\t\t}\n\n\t\t// If the output is configured to support the archive, and supports it, we proceed\n\t\t// with building an archive and setting it on the output instance.\n\t\tif !test.derivedConfig.NoArchiveUpload.Bool {\n\t\t\tif archiveOut, ok := out.(output.WithArchive); ok {\n\t\t\t\tarchiveOut.SetArchive(test.initRunner.MakeArchive())\n\t\t\t}\n\t\t}\n\n\t\tresult = append(result, out)\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/cmd/outputs_cloud.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst (\n\tdefaultTestName = \"k6 test\"\n\ttestRunIDKey    = \"K6_CLOUDRUN_TEST_RUN_ID\"\n)\n\n// createCloudTest performs some test and Cloud configuration validations and if everything\n// looks good, then it creates a test run in the k6 Cloud, using the Cloud API, meant to be used\n// for streaming test results.\n//\n// This method is also responsible for filling the test run id on the test environment, so it can be used later,\n// and to populate the Cloud configuration back in case the Cloud API returned some overrides,\n// as expected by the Cloud output.\n//\n//nolint:funlen,gocognit,cyclop\nfunc createCloudTest(gs *state.GlobalState, test *loadedAndConfiguredTest) error {\n\t// Otherwise, we continue normally with the creation of the test run in the k6 Cloud backend services.\n\tconf, warn, err := cloudapi.GetConsolidatedConfig(\n\t\ttest.derivedConfig.Collectors[builtinOutputCloud.String()],\n\t\tgs.Env,\n\t\t\"\", // Historically used for -o cloud=..., no longer used (deprecated).\n\t\ttest.derivedConfig.Cloud,\n\t\ttest.derivedConfig.External,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif warn != \"\" {\n\t\tgs.Logger.Warn(warn)\n\t}\n\n\tif conf.Token.String == \"\" {\n\t\treturn errUserUnauthenticated\n\t}\n\n\tif !conf.StackID.Valid || conf.StackID.Int64 == 0 {\n\t\tfallBackMsg := \"\"\n\t\tif !conf.ProjectID.Valid || conf.ProjectID.Int64 == 0 {\n\t\t\tfallBackMsg = \"Falling back to the first available stack. \"\n\t\t}\n\t\tgs.Logger.Warn(\"DEPRECATED: No stack specified. \" + fallBackMsg +\n\t\t\t\"Consider setting a default stack via the `k6 cloud login` command or the `K6_CLOUD_STACK_ID` \" +\n\t\t\t\"environment variable as this will become mandatory in the next major release.\")\n\t}\n\n\t// If not, we continue with some validations and the creation of the test run.\n\tif err := validateRequiredSystemTags(test.derivedConfig.SystemTags); err != nil {\n\t\treturn err\n\t}\n\n\tif !conf.Name.Valid || conf.Name.String == \"\" {\n\t\tscriptPath := test.source.URL.String()\n\t\tif scriptPath == \"\" {\n\t\t\t// Script from stdin without a name, likely from stdin\n\t\t\treturn errors.New(\"script name not set, please specify K6_CLOUD_NAME or options.cloud.name\")\n\t\t}\n\n\t\tconf.Name = null.StringFrom(filepath.Base(scriptPath))\n\t}\n\tif conf.Name.String == \"-\" {\n\t\tconf.Name = null.StringFrom(defaultTestName)\n\t}\n\n\tthresholds := make(map[string][]string)\n\tfor name, t := range test.derivedConfig.Thresholds {\n\t\tfor _, threshold := range t.Thresholds {\n\t\t\tthresholds[name] = append(thresholds[name], threshold.Source)\n\t\t}\n\t}\n\n\tet, err := lib.NewExecutionTuple(\n\t\ttest.derivedConfig.ExecutionSegment,\n\t\ttest.derivedConfig.ExecutionSegmentSequence,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\texecutionPlan := test.derivedConfig.Scenarios.GetFullExecutionRequirements(et)\n\n\tduration, testEnds := lib.GetEndOffset(executionPlan)\n\tif !testEnds {\n\t\treturn errors.New(\"tests with unspecified duration are not allowed when outputting data to k6 cloud\")\n\t}\n\n\tif conf.MetricPushConcurrency.Int64 < 1 {\n\t\treturn fmt.Errorf(\"metrics push concurrency must be a positive number but is %d\",\n\t\t\tconf.MetricPushConcurrency.Int64)\n\t}\n\n\tif conf.MaxTimeSeriesInBatch.Int64 < 1 {\n\t\treturn fmt.Errorf(\"max allowed number of time series in a single batch must be a positive number but is %d\",\n\t\t\tconf.MaxTimeSeriesInBatch.Int64)\n\t}\n\n\tvar testArchive *lib.Archive\n\tif !test.derivedConfig.NoArchiveUpload.Bool {\n\t\ttestArchive = test.initRunner.MakeArchive()\n\t}\n\n\ttestRun := &cloudapi.TestRun{\n\t\tName:       conf.Name.String,\n\t\tProjectID:  conf.ProjectID.Int64,\n\t\tVUsMax:     int64(lib.GetMaxPossibleVUs(executionPlan)), //nolint:gosec\n\t\tThresholds: thresholds,\n\t\tDuration:   int64(duration / time.Second),\n\t\tArchive:    testArchive,\n\t}\n\n\tlogger := gs.Logger.WithFields(logrus.Fields{\"output\": builtinOutputCloud.String()})\n\n\tapiClient := cloudapi.NewClient(\n\t\tlogger, conf.Token.String, conf.Host.String, build.Version, conf.Timeout.TimeDuration())\n\tif conf.StackID.Valid {\n\t\tapiClient.SetStackID(conf.StackID.Int64)\n\t}\n\n\tif testRun.ProjectID == 0 {\n\t\tprojectID, err := resolveDefaultProjectID(gs, &conf)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif projectID > 0 {\n\t\t\ttestRun.ProjectID = projectID\n\t\t}\n\t}\n\n\tresponse, err := apiClient.CreateTestRun(testRun)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// We store the test run id in the environment, so it can be used later.\n\ttest.preInitState.RuntimeOptions.Env[testRunIDKey] = response.ReferenceID\n\n\t// If the Cloud API returned configuration overrides, we apply them to the current configuration.\n\t// Then, we serialize the overridden configuration back, so it can be used by the Cloud output.\n\tif response.ConfigOverride != nil {\n\t\tlogger.WithFields(logrus.Fields{\"override\": response.ConfigOverride}).Debug(\"overriding config options\")\n\n\t\traw, err := cloudConfToRawMessage(conf.Apply(*response.ConfigOverride))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not serialize overridden cloud configuration: %w\", err)\n\t\t}\n\n\t\tif test.derivedConfig.Collectors == nil {\n\t\t\ttest.derivedConfig.Collectors = make(map[string]json.RawMessage)\n\t\t}\n\t\ttest.derivedConfig.Collectors[builtinOutputCloud.String()] = raw\n\t}\n\n\treturn nil\n}\n\n// validateRequiredSystemTags checks if all required tags are present.\nfunc validateRequiredSystemTags(scriptTags *metrics.SystemTagSet) error {\n\tvar missingRequiredTags []string\n\trequiredTags := metrics.SystemTagSet(metrics.TagName |\n\t\tmetrics.TagMethod |\n\t\tmetrics.TagStatus |\n\t\tmetrics.TagError |\n\t\tmetrics.TagCheck |\n\t\tmetrics.TagGroup)\n\tfor _, tag := range metrics.SystemTagValues() {\n\t\tif requiredTags.Has(tag) && !scriptTags.Has(tag) {\n\t\t\tmissingRequiredTags = append(missingRequiredTags, tag.String())\n\t\t}\n\t}\n\tif len(missingRequiredTags) > 0 {\n\t\treturn fmt.Errorf(\n\t\t\t\"the cloud output needs the following system tags enabled: %s\",\n\t\t\tstrings.Join(missingRequiredTags, \", \"),\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc cloudConfToRawMessage(conf cloudapi.Config) (json.RawMessage, error) {\n\tvar buff bytes.Buffer\n\tenc := json.NewEncoder(&buff)\n\tif err := enc.Encode(conf); err != nil {\n\t\treturn nil, err\n\t}\n\treturn buff.Bytes(), nil\n}\n"
  },
  {
    "path": "internal/cmd/outputs_test.go",
    "content": "package cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBuiltinOutputString(t *testing.T) {\n\tt.Parallel()\n\texp := []string{\n\t\t\"cloud\", \"csv\", \"datadog\", \"experimental-prometheus-rw\",\n\t\t\"influxdb\", \"json\", \"kafka\", \"statsd\",\n\t\t\"experimental-opentelemetry\", \"opentelemetry\",\n\t\t\"summary\",\n\t}\n\tassert.Equal(t, exp, builtinOutputStrings())\n}\n"
  },
  {
    "path": "internal/cmd/pause.go",
    "content": "package cmd\n\nimport (\n\t\"github.com/spf13/cobra\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\tv1 \"go.k6.io/k6/api/v1\"\n\t\"go.k6.io/k6/api/v1/client\"\n\t\"go.k6.io/k6/cmd/state\"\n)\n\nfunc getCmdPause(gs *state.GlobalState) *cobra.Command {\n\t// pauseCmd represents the pause command\n\tpauseCmd := &cobra.Command{\n\t\tUse:    \"pause\",\n\t\tShort:  \"Pause a running test\",\n\t\tHidden: true,\n\t\tLong: `Pause a running test.\n\n  Use the global --address flag to specify the URL to the API server.`,\n\t\tRunE: func(_ *cobra.Command, _ []string) error {\n\t\t\tc, err := client.New(gs.Flags.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tstatus, err := c.SetStatus(gs.Ctx, v1.Status{\n\t\t\t\tPaused: null.BoolFrom(true),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn yamlPrint(gs.Stdout, status)\n\t\t},\n\t}\n\treturn pauseCmd\n}\n"
  },
  {
    "path": "internal/cmd/report.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"strconv\"\n\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/usage\"\n)\n\nfunc createReport(u *usage.Usage, execScheduler *execution.Scheduler) map[string]any {\n\texecState := execScheduler.GetState()\n\tm := u.Map()\n\n\tm[\"k6_version\"] = build.Version\n\tm[\"duration\"] = execState.GetCurrentTestRunDuration().String()\n\tm[\"goos\"] = runtime.GOOS\n\tm[\"goarch\"] = runtime.GOARCH\n\tm[\"vus_max\"] = uint64(execState.GetInitializedVUsCount()) //nolint:gosec\n\tm[\"iterations\"] = execState.GetFullIterationCount()\n\texecutors := make(map[string]int)\n\tfor _, ec := range execScheduler.GetExecutorConfigs() {\n\t\texecutors[ec.GetType()]++\n\t}\n\tm[\"executors\"] = executors\n\tm[\"is_ci\"] = isCI(execState.Test.LookupEnv)\n\n\treturn m\n}\n\nfunc reportUsage(ctx context.Context, execScheduler *execution.Scheduler, test *loadedAndConfiguredTest) error {\n\tm := createReport(test.preInitState.Usage, execScheduler)\n\tbody, err := json.Marshal(m)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tconst usageStatsURL = \"https://stats.grafana.org/k6-usage-report\"\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, usageStatsURL, bytes.NewBuffer(body))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\tres, err := http.DefaultClient.Do(req) //nolint:gosec\n\tif err == nil {\n\t\t_ = res.Body.Close()\n\t}\n\n\treturn err\n}\n\n// isCI is a helper that follows a naive approach to determine if k6 is being\n// executed within a CI system. This naive approach consists of checking if\n// the \"CI\" environment variable (among others) is set.\n//\n// We treat the \"CI\" environment variable carefully, because it's the one\n// used more often, and because we know sometimes it's explicitly set to\n// \"false\" to signal that k6 is not running in a CI environment.\n//\n// It is not a foolproof method, but it should work for most cases.\nfunc isCI(lookupEnv func(key string) (val string, ok bool)) bool {\n\tif ci, ok := lookupEnv(\"CI\"); ok {\n\t\tciBool, err := strconv.ParseBool(ci)\n\t\tif err == nil {\n\t\t\treturn ciBool\n\t\t}\n\t\t// If we can't parse the \"CI\" value as a bool, we assume return true\n\t\t// because we know that at least it's not set to any variant of \"false\",\n\t\t// which is the most common use case, and the reasoning we apply below.\n\t\treturn true\n\t}\n\n\t// List of common environment variables used by different CI systems.\n\tciEnvVars := []string{\n\t\t\"BUILD_ID\",               // Jenkins, Cloudbees\n\t\t\"BUILD_NUMBER\",           // Jenkins, TeamCity\n\t\t\"CI\",                     // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari\n\t\t\"CI_APP_ID\",              // Appflow\n\t\t\"CI_BUILD_ID\",            // Appflow\n\t\t\"CI_BUILD_NUMBER\",        // Appflow\n\t\t\"CI_NAME\",                // Codeship and others\n\t\t\"CONTINUOUS_INTEGRATION\", // Travis CI, Cirrus CI\n\t\t\"RUN_ID\",                 // TaskCluster, dsari\n\t}\n\n\t// Check if any of these variables are set\n\tfor _, key := range ciEnvVars {\n\t\tif _, ok := lookupEnv(key); ok {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "internal/cmd/report_test.go",
    "content": "package cmd\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/executor\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestCreateReport(t *testing.T) {\n\tt.Parallel()\n\n\tlogger := testutils.NewLogger(t)\n\topts, err := executor.DeriveScenariosFromShortcuts(lib.Options{\n\t\tVUs:        null.IntFrom(10),\n\t\tIterations: null.IntFrom(170),\n\t}, logger)\n\trequire.NoError(t, err)\n\n\tinitSchedulerWithEnv := func(lookupEnv func(string) (string, bool)) (*execution.Scheduler, error) {\n\t\treturn execution.NewScheduler(&lib.TestRunState{\n\t\t\tTestPreInitState: &lib.TestPreInitState{\n\t\t\t\tLogger:    logger,\n\t\t\t\tLookupEnv: lookupEnv,\n\t\t\t},\n\t\t\tOptions: opts,\n\t\t}, local.NewController())\n\t}\n\n\tt.Run(\"default (no env)\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ts, err := initSchedulerWithEnv(func(_ string) (val string, ok bool) {\n\t\t\treturn \"\", false\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\ts.GetState().ModInitializedVUsCount(6)\n\t\ts.GetState().AddFullIterations(uint64(opts.Iterations.Int64))\n\t\ts.GetState().MarkStarted()\n\t\ttime.Sleep(10 * time.Millisecond)\n\t\ts.GetState().MarkEnded()\n\n\t\tm := createReport(usage.New(), s)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, build.Version, m[\"k6_version\"])\n\t\tassert.EqualValues(t, map[string]int{\"shared-iterations\": 1}, m[\"executors\"])\n\t\tassert.EqualValues(t, 6, m[\"vus_max\"])\n\t\tassert.EqualValues(t, 170, m[\"iterations\"])\n\t\tassert.NotEqual(t, \"0s\", m[\"duration\"])\n\t\tassert.EqualValues(t, false, m[\"is_ci\"])\n\t})\n\n\tt.Run(\"CI=false\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ts, err := initSchedulerWithEnv(func(envVar string) (val string, ok bool) {\n\t\t\tif envVar == \"CI\" {\n\t\t\t\treturn \"false\", true\n\t\t\t}\n\t\t\treturn \"\", false\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\tm := createReport(usage.New(), s)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, build.Version, m[\"k6_version\"])\n\t\tassert.EqualValues(t, map[string]int{\"shared-iterations\": 1}, m[\"executors\"])\n\t\tassert.EqualValues(t, 0, m[\"vus_max\"])\n\t\tassert.EqualValues(t, 0, m[\"iterations\"])\n\t\tassert.Equal(t, \"0s\", m[\"duration\"])\n\t\tassert.EqualValues(t, false, m[\"is_ci\"])\n\t})\n\n\tt.Run(\"CI=true\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ts, err := initSchedulerWithEnv(func(envVar string) (val string, ok bool) {\n\t\t\tif envVar == \"CI\" {\n\t\t\t\treturn \"true\", true\n\t\t\t}\n\t\t\treturn \"\", false\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\tm := createReport(usage.New(), s)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, build.Version, m[\"k6_version\"])\n\t\tassert.EqualValues(t, map[string]int{\"shared-iterations\": 1}, m[\"executors\"])\n\t\tassert.EqualValues(t, 0, m[\"vus_max\"])\n\t\tassert.EqualValues(t, 0, m[\"iterations\"])\n\t\tassert.Equal(t, \"0s\", m[\"duration\"])\n\t\tassert.EqualValues(t, true, m[\"is_ci\"])\n\t})\n}\n"
  },
  {
    "path": "internal/cmd/resume.go",
    "content": "package cmd\n\nimport (\n\t\"github.com/spf13/cobra\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\tv1 \"go.k6.io/k6/api/v1\"\n\t\"go.k6.io/k6/api/v1/client\"\n\t\"go.k6.io/k6/cmd/state\"\n)\n\nfunc getCmdResume(gs *state.GlobalState) *cobra.Command {\n\t// resumeCmd represents the resume command\n\tresumeCmd := &cobra.Command{\n\t\tUse:    \"resume\",\n\t\tShort:  \"Resume a paused test\",\n\t\tHidden: true,\n\t\tLong: `Resume a paused test.\n\n  Use the global --address flag to specify the URL to the API server.`,\n\t\tRunE: func(_ *cobra.Command, _ []string) error {\n\t\t\tc, err := client.New(gs.Flags.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tstatus, err := c.SetStatus(gs.Ctx, v1.Status{\n\t\t\t\tPaused: null.BoolFrom(false),\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn yamlPrint(gs.Stdout, status)\n\t\t},\n\t}\n\treturn resumeCmd\n}\n"
  },
  {
    "path": "internal/cmd/root.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\tstdlog \"log\"\n\t\"runtime/debug\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/log\"\n\t\"go.k6.io/k6/secretsource\"\n\n\t_ \"go.k6.io/k6/internal/secretsource\" // import it to register internal secret sources\n)\n\nconst waitLoggerCloseTimeout = time.Second * 5\n\nfunc getDocsURL() string {\n\tversion := build.Version\n\tversion = strings.TrimPrefix(version, \"v\")\n\tparts := strings.SplitN(version, \".\", 3)\n\tif len(parts) >= 2 {\n\t\treturn fmt.Sprintf(\"https://grafana.com/docs/k6/v%s.%s.x/\", parts[0], parts[1])\n\t}\n\treturn \"https://grafana.com/docs/k6/latest/\"\n}\n\nfunc getRootUsageTemplate() string {\n\treturn fmt.Sprintf(`{{.Short}}\n\nUsage:{{if .Runnable}}\n  {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}\n  {{.CommandPath}} [command]{{end}}{{if .HasAvailableSubCommands}}\n\nCore Commands:{{range .Commands}}{{if eq .Name \"new\"}}\n  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{range .Commands}}{{if eq .Name \"run\"}}\n  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{range .Commands}}{{if eq .Name \"cloud\"}}\n  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}\n\nAdditional Commands:{{range .Commands}}{{if and .IsAvailableCommand (ne .Name \"new\") (ne .Name \"run\") `+\n\t\t`(ne .Name \"cloud\") (ne .Name \"help\")}}\n  {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}\n\nFlags:\n  -h, --help      Show help\n      --version   Show version information\n\nExamples:\n  # Create a test\n  $ {{.CommandPath}} new test.js\n\n  # Run a test\n  $ {{.CommandPath}} run test.js\n\n  # Run a test in Grafana Cloud\n  $ {{.CommandPath}} cloud run test.js\n\n  # Run locally, stream results to Grafana Cloud\n  $ {{.CommandPath}} cloud run --local-execution test.js\n{{if .HasAvailableSubCommands}}\nUse \"{{.CommandPath}} [command] --help\" for more information about a command.\nFull CLI documentation: %s{{end}}\n`, getDocsURL())\n}\n\n// ExecuteWithGlobalState runs the root command with an existing GlobalState.\n// It adds all child commands to the root command and it sets flags appropriately.\n// It is called by main.main(). It only needs to happen once to the rootCmd.\nfunc ExecuteWithGlobalState(gs *state.GlobalState) {\n\tnewRootCommand(gs).execute()\n}\n\n// This is to keep all fields needed for the main/root k6 command\ntype rootCommand struct {\n\tglobalState *state.GlobalState\n\n\tcmd            *cobra.Command\n\tstopLoggersCh  chan struct{}\n\tloggersWg      sync.WaitGroup\n\tloggerIsRemote bool\n}\n\n// newRootCommand creates a root command with a default launcher\nfunc newRootCommand(gs *state.GlobalState) *rootCommand {\n\tc := &rootCommand{\n\t\tglobalState:   gs,\n\t\tstopLoggersCh: make(chan struct{}),\n\t}\n\t// the base command when called without any subcommands.\n\trootCmd := &cobra.Command{\n\t\tUse:               gs.BinaryName,\n\t\tShort:             \"Grafana k6 is an easy-to-use, open-source load and performance testing tool\",\n\t\tLong:              \"\\n\" + getBanner(gs.Flags.NoColor || !gs.Stdout.IsTTY, isTrueColor(gs.Env)),\n\t\tSilenceUsage:      true,\n\t\tSilenceErrors:     true,\n\t\tPersistentPreRunE: c.persistentPreRunE,\n\t\tVersion:           versionString(),\n\t}\n\n\trootCmd.SetVersionTemplate(\n\t\t`{{with .Name}}{{printf \"%s \" .}}{{end}}{{printf \"v%s\\n\" .Version}}`,\n\t)\n\n\trootCmd.PersistentFlags().AddFlagSet(rootCmdPersistentFlagSet(gs))\n\trootCmd.SetArgs(gs.CmdArgs[1:])\n\trootCmd.SetOut(gs.Stdout)\n\trootCmd.SetErr(gs.Stderr) // TODO: use gs.logger.WriterLevel(logrus.ErrorLevel)?\n\trootCmd.SetIn(gs.Stdin)\n\n\tsubCommands := []func(*state.GlobalState) *cobra.Command{\n\t\tgetCmdArchive, getCmdCloud, getCmdNewScript, getCmdInspect, getCmdDeps,\n\t\tgetCmdLogin, getCmdPause, getCmdResume, getCmdScale, getCmdRun,\n\t\tgetCmdStats, getCmdStatus, getCmdVersion, getX,\n\t}\n\n\tdefaultUsageTemplate := (&cobra.Command{}).UsageTemplate()\n\tdefaultUsageTemplate = strings.ReplaceAll(defaultUsageTemplate, \"FlagUsages\", \"FlagUsagesWrapped 120\")\n\n\tfor _, sc := range subCommands {\n\t\tcmd := sc(gs)\n\t\tcmd.SetUsageTemplate(defaultUsageTemplate)\n\t\trootCmd.AddCommand(cmd)\n\t}\n\n\trootCmd.SetUsageTemplate(getRootUsageTemplate())\n\n\tc.cmd = rootCmd\n\treturn c\n}\n\nfunc (c *rootCommand) persistentPreRunE(_ *cobra.Command, _ []string) error {\n\terr := c.setupLoggers(c.stopLoggersCh)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc.globalState.Logger.Debugf(\"k6 version: v%s\", fullVersion())\n\n\treturn nil\n}\n\nfunc (c *rootCommand) execute() {\n\tctx, cancel := context.WithCancel(c.globalState.Ctx)\n\tc.globalState.Ctx = ctx\n\n\texitCode := -1\n\tdefer func() {\n\t\tcancel()\n\t\tc.stopLoggers()\n\t\tc.globalState.OSExit(exitCode)\n\t}()\n\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\texitCode = int(exitcodes.GoPanic)\n\t\t\terr := fmt.Errorf(\"unexpected k6 panic: %s\\n%s\", r, debug.Stack())\n\t\t\tif c.loggerIsRemote {\n\t\t\t\tc.globalState.FallbackLogger.Error(err)\n\t\t\t}\n\t\t\tc.globalState.Logger.Error(err)\n\t\t}\n\t}()\n\n\terr := c.cmd.Execute()\n\tif err == nil {\n\t\texitCode = 0\n\t\treturn\n\t}\n\n\tnewExitCode, err := handleUnsatisfiedDependencies(err, c)\n\n\tif err == nil {\n\t\texitCode = int(newExitCode)\n\t\treturn\n\t}\n\n\tvar ecerr errext.HasExitCode\n\tif errors.As(err, &ecerr) {\n\t\texitCode = int(ecerr.ExitCode())\n\t}\n\n\tif errors.Is(err, errAlreadyReported) {\n\t\treturn\n\t}\n\n\terrText, fields := errext.Format(err)\n\tc.globalState.Logger.WithFields(fields).Error(errText)\n\tif c.loggerIsRemote {\n\t\tc.globalState.FallbackLogger.WithFields(fields).Error(errText)\n\t}\n}\n\nfunc handleUnsatisfiedDependencies(err error, c *rootCommand) (exitcodes.ExitCode, error) {\n\tvar unsatisfiedDependenciesErr binaryIsNotSatisfyingDependenciesError\n\n\tif !errors.As(err, &unsatisfiedDependenciesErr) {\n\t\treturn 0, err\n\t}\n\tdeps := unsatisfiedDependenciesErr.deps\n\tc.globalState.Logger.\n\t\tWithField(\"deps\", deps).\n\t\tInfo(\"Automatic extension resolution is enabled. The current k6 binary doesn't satisfy all dependencies,\" +\n\t\t\t\" it's required to provision a custom binary.\")\n\tprovisioner := newK6BuildProvisioner(c.globalState)\n\tvar customBinary commandExecutor\n\tcustomBinary, err = provisioner.provision(constraintsMapToProvisionDependency(deps))\n\tif err != nil {\n\t\terr = errext.WithExitCodeIfNone(err, exitcodes.ScriptException)\n\t\tc.globalState.Logger.\n\t\t\tWithError(err).\n\t\t\tError(\"Failed to provision a k6 binary with required dependencies.\" +\n\t\t\t\t\" Please, make sure to report this issue by opening a bug report.\")\n\t\treturn 0, err\n\t}\n\n\terr = customBinary.run(c.globalState)\n\t// this only happens if we actually ran the binary and it exited afterwads, in which case we propagate the exit code\n\tvar ecerr errext.HasExitCode\n\tif errors.As(err, &ecerr) {\n\t\treturn ecerr.ExitCode(), err\n\t}\n\n\treturn 0, err\n}\n\nfunc (c *rootCommand) stopLoggers() {\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tc.loggersWg.Wait()\n\t\tclose(done)\n\t}()\n\tclose(c.stopLoggersCh)\n\tselect {\n\tcase <-done:\n\tcase <-time.After(waitLoggerCloseTimeout):\n\t\tc.globalState.FallbackLogger.Errorf(\"The logger didn't stop in %s\", waitLoggerCloseTimeout)\n\t}\n}\n\nfunc rootCmdPersistentFlagSet(gs *state.GlobalState) *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", pflag.ContinueOnError)\n\t// TODO: refactor this config, the default value management with pflag is\n\t// simply terrible... :/\n\t//\n\t// We need to use `gs.Flags.<value>` both as the destination and as\n\t// the value here, since the config values could have already been set by\n\t// their respective environment variables. However, we then also have to\n\t// explicitly set the DefValue to the respective default value from\n\t// `gs.DefaultFlags.<value>`, so that the `k6 --help` message is\n\t// not messed up...\n\n\t// TODO(@mstoykov): likely needs work - no env variables and such. No config.json.\n\tflags.StringArrayVar(&gs.Flags.SecretSource, \"secret-source\", gs.Flags.SecretSource,\n\t\t\"setting secret sources for k6 file[=./path.fileformat],\")\n\n\tflags.StringVar(&gs.Flags.LogOutput, \"log-output\", gs.Flags.LogOutput,\n\t\t\"change the output for k6 logs, possible values are: \"+\n\t\t\t\"'stderr', 'stdout', 'none', 'loki[=host:port]', 'file[=./path.fileformat]'\")\n\tflags.Lookup(\"log-output\").DefValue = gs.DefaultFlags.LogOutput\n\n\tflags.StringVar(&gs.Flags.LogFormat, \"log-format\", gs.Flags.LogFormat, \"log output format\")\n\tflags.Lookup(\"log-format\").DefValue = gs.DefaultFlags.LogFormat\n\n\tflags.StringVarP(&gs.Flags.ConfigFilePath, \"config\", \"c\", gs.Flags.ConfigFilePath, \"JSON config file\")\n\t// And we also need to explicitly set the default value for the usage message here, so things\n\t// like `K6_CONFIG=\"blah\" k6 run -h` don't produce a weird usage message\n\tflags.Lookup(\"config\").DefValue = gs.DefaultFlags.ConfigFilePath\n\tmust(cobra.MarkFlagFilename(flags, \"config\"))\n\n\tflags.BoolVar(&gs.Flags.NoColor, \"no-color\", gs.Flags.NoColor, \"disable colored output\")\n\tflags.Lookup(\"no-color\").DefValue = strconv.FormatBool(gs.DefaultFlags.NoColor)\n\n\t// TODO: support configuring these through environment variables as well?\n\t// either with croconf or through the hack above...\n\tflags.BoolVarP(&gs.Flags.Verbose, \"verbose\", \"v\", gs.DefaultFlags.Verbose, \"enable verbose logging\")\n\tflags.BoolVarP(&gs.Flags.Quiet, \"quiet\", \"q\", gs.DefaultFlags.Quiet, \"disable progress updates\")\n\tflags.StringVarP(&gs.Flags.Address, \"address\", \"a\", gs.DefaultFlags.Address, \"address for the REST API server\")\n\tflags.BoolVar(\n\t\t&gs.Flags.ProfilingEnabled,\n\t\t\"profiling-enabled\",\n\t\tgs.DefaultFlags.ProfilingEnabled,\n\t\t\"enable profiling (pprof) endpoints, k6's REST API should be enabled as well\",\n\t)\n\n\treturn flags\n}\n\n// RawFormatter it does nothing with the message just prints it\ntype RawFormatter struct{}\n\n// Format renders a single log entry\nfunc (f RawFormatter) Format(entry *logrus.Entry) ([]byte, error) {\n\treturn append([]byte(entry.Message), '\\n'), nil\n}\n\n// The returned channel will be closed when the logger has finished flushing and pushing logs after\n// the provided context is closed. It is closed if the logger isn't buffering and sending messages\n// Asynchronously\nfunc (c *rootCommand) setupLoggers(stop <-chan struct{}) error {\n\tif c.globalState.Flags.Verbose {\n\t\tc.globalState.Logger.SetLevel(logrus.DebugLevel)\n\t}\n\n\tvar (\n\t\thook log.AsyncHook\n\t\terr  error\n\t)\n\n\tloggerForceColors := false // disable color by default\n\tswitch line := c.globalState.Flags.LogOutput; {\n\tcase line == \"stderr\":\n\t\tloggerForceColors = !c.globalState.Flags.NoColor && c.globalState.Stderr.IsTTY\n\t\tc.globalState.Logger.SetOutput(c.globalState.Stderr)\n\tcase line == \"stdout\":\n\t\tloggerForceColors = !c.globalState.Flags.NoColor && c.globalState.Stdout.IsTTY\n\t\tc.globalState.Logger.SetOutput(c.globalState.Stdout)\n\tcase line == \"none\":\n\t\tc.globalState.Logger.SetOutput(io.Discard)\n\tcase strings.HasPrefix(line, \"loki\"):\n\t\tc.loggerIsRemote = true\n\t\thook, err = log.LokiFromConfigLine(c.globalState.FallbackLogger, line)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tc.globalState.Flags.LogFormat = \"raw\"\n\tcase strings.HasPrefix(line, \"file\"):\n\t\thook, err = log.FileHookFromConfigLine(\n\t\t\tc.globalState.FS, c.globalState.Getwd,\n\t\t\tc.globalState.FallbackLogger, line,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported log output '%s'\", line)\n\t}\n\n\tswitch c.globalState.Flags.LogFormat {\n\tcase \"raw\":\n\t\tc.globalState.Logger.SetFormatter(&RawFormatter{})\n\t\tc.globalState.Logger.Debug(\"Logger format: RAW\")\n\tcase \"json\":\n\t\tc.globalState.Logger.SetFormatter(&logrus.JSONFormatter{})\n\t\tc.globalState.Logger.Debug(\"Logger format: JSON\")\n\tdefault:\n\t\tc.globalState.Logger.SetFormatter(&logrus.TextFormatter{\n\t\t\tForceColors: loggerForceColors, DisableColors: c.globalState.Flags.NoColor,\n\t\t})\n\t\tc.globalState.Logger.Debug(\"Logger format: TEXT\")\n\t}\n\n\tsecretsources, err := createSecretSources(c.globalState)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// it is important that we add this hook first as hooks are executed in order of addition\n\t// and this means no other hook will get secrets\n\tvar secretsHook logrus.Hook\n\tc.globalState.SecretsManager, secretsHook, err = secretsource.NewManager(secretsources)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(secretsources) != 0 {\n\t\t// don't actually filter anything if there will be no secrets\n\t\tc.globalState.Logger.AddHook(secretsHook)\n\t}\n\n\tcancel := func() {} // noop as default\n\tif hook != nil {\n\t\tctx := context.Background()\n\t\tctx, cancel = context.WithCancel(ctx)\n\t\tc.setLoggerHook(ctx, hook)\n\t}\n\n\t// Sometimes the Go runtime uses the standard log output to\n\t// log some messages directly.\n\t// It does when an invalid char is found in a Cookie.\n\t// Check for details https://github.com/grafana/k6/issues/711#issue-341414887\n\tw := c.globalState.Logger.Writer()\n\tstdlog.SetOutput(w)\n\tc.loggersWg.Go(func() {\n\t\t<-stop\n\t\tcancel()\n\t\t_ = w.Close()\n\t})\n\treturn nil\n}\n\nfunc (c *rootCommand) setLoggerHook(ctx context.Context, h log.AsyncHook) {\n\tc.loggersWg.Go(func() {\n\t\th.Listen(ctx)\n\t})\n\tc.globalState.Logger.AddHook(h)\n\tc.globalState.Logger.SetOutput(io.Discard) // don't output to anywhere else\n}\n\nfunc createSecretSources(gs *state.GlobalState) (map[string]secretsource.Source, error) {\n\tbaseParams := secretsource.Params{\n\t\tLogger:      gs.Logger,\n\t\tEnvironment: gs.Env,\n\t\tFS:          gs.FS,\n\t\tUsage:       gs.Usage,\n\t}\n\n\tresult := make(map[string]secretsource.Source)\n\tfor _, line := range gs.Flags.SecretSource {\n\t\tt, config, ok := strings.Cut(line, \"=\")\n\t\tif !ok {\n\t\t\t// Special case: allow --secret-source=url without explicit config\n\t\t\t// (it will use environment variables + defaults)\n\t\t\tif line == \"url\" {\n\t\t\t\tt = line\n\t\t\t\tconfig = \"\"\n\t\t\t} else {\n\t\t\t\treturn nil, fmt.Errorf(\"couldn't parse secret source configuration %q\", line)\n\t\t\t}\n\t\t}\n\t\tsecretSources := ext.Get(ext.SecretSourceExtension)\n\t\tfound, ok := secretSources[t]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"no secret source for type %q for configuration %q\", t, line)\n\t\t}\n\t\tc := found.Module.(secretsource.Constructor) //nolint:forcetypeassert\n\t\tparams := baseParams\n\t\tname, isDefault, config := extractNameAndDefault(config)\n\t\tparams.ConfigArgument = config\n\n\t\tsecretSource, err := c(params)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t_, alreadRegistered := result[name]\n\t\tif alreadRegistered {\n\t\t\treturn nil, fmt.Errorf(\"secret source for name %q already registered before configuration %q\", t, line)\n\t\t}\n\t\tresult[name] = secretSource\n\t\tif isDefault {\n\t\t\tif _, ok := result[\"default\"]; ok {\n\t\t\t\treturn nil, fmt.Errorf(\"can't have two secret sources that are default ones, second one was %q\", config)\n\t\t\t}\n\t\t\tresult[\"default\"] = secretSource\n\t\t}\n\t}\n\n\tif len(result) == 1 {\n\t\tfor _, l := range result {\n\t\t\tresult[\"default\"] = l\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc extractNameAndDefault(config string) (name string, isDefault bool, remaining string) {\n\tlist := strings.Split(config, \",\")\n\tremainingArray := make([]string, 0, len(list))\n\tfor _, kv := range list {\n\t\tif kv == \"default\" {\n\t\t\tisDefault = true\n\t\t\tcontinue\n\t\t}\n\t\tk, v, _ := strings.Cut(kv, \"=\")\n\t\tif k == \"name\" {\n\t\t\tname = v\n\t\t\tcontinue\n\t\t}\n\t\tremainingArray = append(remainingArray, kv)\n\t}\n\treturn name, isDefault, strings.Join(remainingArray, \",\")\n}\n"
  },
  {
    "path": "internal/cmd/root_test.go",
    "content": "package cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n)\n\nfunc TestRootCommandHelpDisplayCommands(t *testing.T) {\n\tt.Parallel()\n\n\tregisterTestSubcommandExtensions(t)\n\n\ttestCases := []struct {\n\t\tname                  string\n\t\textraArgs             []string\n\t\twantExitCode          exitcodes.ExitCode\n\t\twantStdoutContains    string\n\t\twantStdoutNotContains string\n\t}{\n\t\t{\n\t\t\tname:               \"should have archive command\",\n\t\t\twantStdoutContains: \"  archive     Create an archive\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have cloud command\",\n\t\t\twantStdoutContains: \"  cloud       Run and manage Grafana Cloud tests\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have completion command\",\n\t\t\twantStdoutContains: \"  completion  Generate the autocompletion script for the specified shell\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have inspect command\",\n\t\t\twantStdoutContains: \"  inspect     Inspect a script or archive\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have new command\",\n\t\t\twantStdoutContains: \"  new         Create a test\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have run command\",\n\t\t\twantStdoutContains: \"  run         Run a test\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have x command\",\n\t\t\twantStdoutContains: \"  x           Extension subcommands\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\tts.CmdArgs = []string{\"k6\", \"help\"}\n\t\t\tnewRootCommand(ts.GlobalState).execute()\n\n\t\t\tif tc.wantStdoutContains != \"\" {\n\t\t\t\tassert.Contains(t, ts.Stdout.String(), tc.wantStdoutContains)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/run.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/api\"\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/internal/lib/trace\"\n\t\"go.k6.io/k6/internal/metrics/engine\"\n\t\"go.k6.io/k6/internal/output/cloud\"\n\tsummaryoutput \"go.k6.io/k6/internal/output/summary\"\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\n// cmdRun handles the `k6 run` sub-command\ntype cmdRun struct {\n\tgs *state.GlobalState\n\n\t// TODO: figure out something more elegant?\n\tloadConfiguredTest func(cmd *cobra.Command, args []string) (*loadedAndConfiguredTest, execution.Controller, error)\n}\n\nconst (\n\t// We use an excessively high timeout to wait for event processing to complete,\n\t// since prematurely proceeding before it is done could create bigger problems.\n\t// In practice, this effectively acts as no timeout, and the user will have to\n\t// kill k6 if a hang happens, which is the behavior without events anyway.\n\twaitEventDoneTimeout = 30 * time.Minute\n\n\t// This timeout should be long enough to flush all remaining traces, but still\n\t// provides a safeguard to not block indefinitely.\n\twaitForTracerProviderStopTimeout = 3 * time.Minute\n)\n\n// TODO: split apart some more\n//\n//nolint:funlen,gocognit,gocyclo,cyclop\nfunc (c *cmdRun) run(cmd *cobra.Command, args []string) (err error) {\n\tvar logger logrus.FieldLogger = c.gs.Logger\n\tdefer func() {\n\t\tif err == nil {\n\t\t\tlogger.Debug(\"Everything has finished, exiting k6 normally!\")\n\t\t} else {\n\t\t\tlogger.WithError(err).Debug(\"Everything has finished, exiting k6 with an error!\")\n\t\t}\n\t}()\n\n\tglobalCtx, globalCancel := context.WithCancel(c.gs.Ctx)\n\tdefer globalCancel()\n\n\t// lingerCtx is cancelled by Ctrl+C, and is used to wait for that event when\n\t// k6 was started with the --linger option.\n\tlingerCtx, lingerCancel := context.WithCancel(globalCtx)\n\tdefer lingerCancel()\n\n\t// runCtx is used for the test run execution and is created with the special\n\t// execution.NewTestRunContext() function so that it can be aborted even\n\t// from sub-contexts while also attaching a reason for the abort.\n\trunCtx, runAbort := execution.NewTestRunContext(lingerCtx, logger)\n\n\temitEvent := func(evt *event.Event) func() {\n\t\twaitDone := c.gs.Events.Emit(evt)\n\t\treturn func() {\n\t\t\twaitCtx, waitCancel := context.WithTimeout(globalCtx, waitEventDoneTimeout)\n\t\t\tdefer waitCancel()\n\t\t\tif werr := waitDone(waitCtx); werr != nil {\n\t\t\t\tlogger.WithError(werr).Warn()\n\t\t\t}\n\t\t}\n\t}\n\n\tdefer func() {\n\t\twaitExitDone := emitEvent(&event.Event{\n\t\t\tType: event.Exit,\n\t\t\tData: &event.ExitData{Error: err},\n\t\t})\n\t\twaitExitDone()\n\t\tc.gs.Events.UnsubscribeAll()\n\t}()\n\n\ttest, controller, err := c.loadConfiguredTest(cmd, args)\n\tif err != nil {\n\t\treturn err\n\t}\n\tprintBanner(c.gs)\n\tif test.keyLogger != nil {\n\t\tdefer func() {\n\t\t\tif klErr := test.keyLogger.Close(); klErr != nil {\n\t\t\t\tlogger.WithError(klErr).Warn(\"Error while closing the SSLKEYLOGFILE\")\n\t\t\t}\n\t\t}()\n\t}\n\n\tif err = c.setupTracerProvider(globalCtx, test); err != nil {\n\t\treturn err\n\t}\n\twaitTracesFlushed := func() {\n\t\tctx, cancel := context.WithTimeout(globalCtx, waitForTracerProviderStopTimeout)\n\t\tdefer cancel()\n\t\tif tpErr := test.preInitState.TracerProvider.Shutdown(ctx); tpErr != nil {\n\t\t\tlogger.Errorf(\"The tracer provider didn't stop gracefully: %v\", tpErr)\n\t\t}\n\t}\n\n\t// Write the full consolidated *and derived* options back to the Runner.\n\tconf := test.derivedConfig\n\ttestRunState, err := test.buildTestRunState(conf.Options)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Create a local execution scheduler wrapping the runner.\n\tlogger.Debug(\"Initializing the execution scheduler...\")\n\texecScheduler, err := execution.NewScheduler(testRunState, controller)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tbackgroundProcesses := &sync.WaitGroup{}\n\tdefer backgroundProcesses.Wait()\n\n\t// This is manually triggered after the Engine's Run() has completed,\n\t// and things like a single Ctrl+C don't affect it. We use it to make\n\t// sure that the progressbars finish updating with the latest execution\n\t// state one last time, after the test run has finished.\n\tprogressCtx, progressCancel := context.WithCancel(globalCtx)\n\tdefer progressCancel()\n\n\tinitBar := execScheduler.GetInitProgressBar()\n\tbackgroundProcesses.Go(func() {\n\t\texecutors := execScheduler.GetExecutors()\n\t\tpbs := make([]*pb.ProgressBar, 0, 1+len(executors))\n\t\tpbs = append(pbs, initBar)\n\t\tfor _, s := range executors {\n\t\t\tpbs = append(pbs, s.GetProgress())\n\t\t}\n\t\tshowProgress(progressCtx, c.gs, pbs, logger)\n\t})\n\n\t// Create all outputs.\n\texecutionPlan := execScheduler.GetExecutionPlan()\n\toutputs, err := createOutputs(c.gs, test, executionPlan)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toutputs = append(outputs, testRunState.GroupSummary)\n\n\tmetricsEngine, err := engine.NewMetricsEngine(testRunState.Registry, logger)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsummaryMode, summaryEnabled, err := getSummaryMode(testRunState.RuntimeOptions)\n\tif err != nil {\n\t\t// Theoretically, this should never happen, as we already verify whether the summary\n\t\t// mode is valid while parsing the runtime options, but just in case it happens, we\n\t\t// want to abort the execution anyway.\n\t\treturn err\n\t}\n\n\tthresholdsEnabled := !testRunState.RuntimeOptions.NoThresholds.Bool\n\n\t// We'll need to pipe metrics to the MetricsEngine and process them if any\n\t// of these are enabled: thresholds, end-of-test summary\n\tshouldProcessMetrics := summaryEnabled || thresholdsEnabled\n\tvar metricsIngester *engine.OutputIngester\n\tif shouldProcessMetrics {\n\t\terr = metricsEngine.InitSubMetricsAndThresholds(conf.Options, !thresholdsEnabled)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// We'll need to pipe metrics to the MetricsEngine if either the\n\t\t// thresholds or the end-of-test summary are enabled.\n\t\tmetricsIngester = metricsEngine.CreateIngester()\n\t\toutputs = append(outputs, metricsIngester)\n\t}\n\n\texecutionState := execScheduler.GetState()\n\tif summaryEnabled { //nolint:nestif\n\t\t// Despite having the revamped [summary.Summary], we still keep the use of the\n\t\t// [lib.LegacySummary] for multiple backwards compatibility options,\n\t\t// to be deprecated by v1.0 and likely removed or replaced by v2.0:\n\t\t// - the `legacy` summary mode (which keeps the old summary format/display).\n\t\t// - the data structure for custom `handleSummary()` implementations.\n\t\t// - the data structure for the JSON (--summary-export) output.\n\t\tlegacySummary := func() *lib.LegacySummary {\n\t\t\treturn &lib.LegacySummary{\n\t\t\t\tMetrics:         metricsEngine.ObservedMetrics,\n\t\t\t\tRootGroup:       testRunState.GroupSummary.Group(),\n\t\t\t\tTestRunDuration: executionState.GetCurrentTestRunDuration(),\n\t\t\t\tNoColor:         c.gs.Flags.NoColor,\n\t\t\t\tUIState: lib.UIState{\n\t\t\t\t\tIsStdOutTTY: c.gs.Stdout.IsTTY,\n\t\t\t\t\tIsStdErrTTY: c.gs.Stderr.IsTTY,\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\tsummaryMeta := summary.Meta{\n\t\t\tScript: string(test.source.Data),\n\t\t\tIsCloud: slices.ContainsFunc(outputs, func(o output.Output) bool {\n\t\t\t\t_, isCloud := o.(*cloud.Output)\n\t\t\t\treturn isCloud\n\t\t\t}),\n\t\t}\n\n\t\tswitch summaryMode {\n\t\t// TODO(@joanlopez): remove by k6 v2.0, once we completely drop the support for --summary-mode=legacy.\n\t\tcase summary.ModeLegacy:\n\t\t\tlogger.Warn(`The \"legacy\" summary mode has been deprecated, and will be removed by k6 v2.0. ` +\n\t\t\t\t`Please, migrate to either \"compact\" or \"full\" as soon as possible.`)\n\t\t\t// At the end of the test run\n\t\t\tdefer func() {\n\t\t\t\tlogger.Debug(\"Generating the end-of-test summary...\")\n\n\t\t\t\tsummaryResult, hsErr := test.initRunner.HandleSummary(globalCtx, legacySummary(), nil, summaryMeta)\n\t\t\t\tif hsErr == nil {\n\t\t\t\t\thsErr = handleSummaryResult(c.gs.FS, c.gs.Stdout, c.gs.Stderr, summaryResult)\n\t\t\t\t}\n\t\t\t\tif hsErr != nil {\n\t\t\t\t\tlogger.WithError(hsErr).Error(\"failed to handle the end-of-test summary\")\n\t\t\t\t}\n\t\t\t}()\n\t\tdefault:\n\t\t\t// Instantiates the summary output\n\t\t\tsummaryOutput, err := summaryoutput.New(output.Params{\n\t\t\t\tRuntimeOptions: testRunState.RuntimeOptions,\n\t\t\t\tLogger:         c.gs.Logger,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tlogger.WithError(err).Error(\"failed to initialize the end-of-test summary output\")\n\t\t\t}\n\t\t\toutputs = append(outputs, summaryOutput)\n\n\t\t\t// At the end of the test run\n\t\t\tdefer func() {\n\t\t\t\tlogger.Debug(\"Generating the end-of-test summary...\")\n\n\t\t\t\tsummary := summaryOutput.Summary(\n\t\t\t\t\texecutionState.GetCurrentTestRunDuration(),\n\t\t\t\t\tmetricsEngine.ObservedMetrics,\n\t\t\t\t\ttest.initRunner.GetOptions(),\n\t\t\t\t)\n\n\t\t\t\t// TODO: We should probably try to move these out of the summary,\n\t\t\t\t// likely as an additional argument like options.\n\t\t\t\tsummary.NoColor = c.gs.Flags.NoColor\n\t\t\t\tsummary.EnableColors = !summary.NoColor && c.gs.Stdout.IsTTY\n\t\t\t\tsummary.NewMachineReadableSummary = testRunState.RuntimeOptions.NewMachineReadableSummary.Valid &&\n\t\t\t\t\ttestRunState.RuntimeOptions.NewMachineReadableSummary.Bool\n\n\t\t\t\tsummaryResult, hsErr := test.initRunner.HandleSummary(globalCtx, legacySummary(), summary, summaryMeta)\n\t\t\t\tif hsErr == nil {\n\t\t\t\t\thsErr = handleSummaryResult(c.gs.FS, c.gs.Stdout, c.gs.Stderr, summaryResult)\n\t\t\t\t}\n\t\t\t\tif hsErr != nil {\n\t\t\t\t\tlogger.WithError(hsErr).Error(\"failed to handle the end-of-test summary\")\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\n\twaitInitDone := emitEvent(&event.Event{Type: event.Init})\n\n\t// Create and start the outputs. We do it quite early to get any output URLs\n\t// or other details below. It also allows us to ensure when they have\n\t// flushed their samples and when they have stopped in the defer statements.\n\tinitBar.Modify(pb.WithConstProgress(0, \"Starting outputs\"))\n\toutputManager := output.NewManager(outputs, logger, func(err error) {\n\t\tif err != nil {\n\t\t\tlogger.WithError(err).Error(\"Received error to stop from output\")\n\t\t}\n\t\t// TODO: attach run status and exit code?\n\t\trunAbort(err)\n\t})\n\tsamples := make(chan metrics.SampleContainer, test.derivedConfig.MetricSamplesBufferSize.Int64)\n\t// Spin up the REST API server, if not disabled.\n\tif c.gs.Flags.Address != \"\" { //nolint:nestif\n\t\tinitBar.Modify(pb.WithConstProgress(0, \"Init API server\"))\n\n\t\t// We cannot use backgroundProcesses here, since we need the REST API to\n\t\t// be down before we can close the samples channel above and finish the\n\t\t// processing the metrics pipeline.\n\t\tapiWG := &sync.WaitGroup{}\n\t\tapiWG.Add(2)\n\t\tdefer apiWG.Wait()\n\n\t\tsrvCtx, srvCancel := context.WithCancel(globalCtx)\n\t\tdefer srvCancel()\n\n\t\tsrv := api.GetServer(\n\t\t\trunCtx,\n\t\t\tc.gs.Flags.Address, c.gs.Flags.ProfilingEnabled,\n\t\t\ttestRunState,\n\t\t\tsamples,\n\t\t\tmetricsEngine,\n\t\t\texecScheduler,\n\t\t)\n\t\tgo func() {\n\t\t\tdefer apiWG.Done()\n\t\t\tlogger.Debugf(\"Starting the REST API server on %s\", c.gs.Flags.Address)\n\t\t\tif c.gs.Flags.ProfilingEnabled {\n\t\t\t\tlogger.Debugf(\"Profiling exposed on http://%s/debug/pprof/\", c.gs.Flags.Address)\n\t\t\t}\n\t\t\tif aerr := srv.ListenAndServe(); aerr != nil && !errors.Is(aerr, http.ErrServerClosed) {\n\t\t\t\t// Only exit k6 if the user has explicitly set the REST API address\n\t\t\t\tif cmd.Flags().Lookup(\"address\").Changed {\n\t\t\t\t\tlogger.WithError(aerr).Error(\"Error from API server\")\n\t\t\t\t\tc.gs.OSExit(int(exitcodes.CannotStartRESTAPI))\n\t\t\t\t} else {\n\t\t\t\t\tlogger.WithError(aerr).Warn(\"Error from API server\")\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tgo func() {\n\t\t\tdefer apiWG.Done()\n\t\t\t<-srvCtx.Done()\n\t\t\tshutdCtx, shutdCancel := context.WithTimeout(globalCtx, 1*time.Second)\n\t\t\tdefer shutdCancel()\n\t\t\tif aerr := srv.Shutdown(shutdCtx); aerr != nil {\n\t\t\t\tlogger.WithError(aerr).Debug(\"REST API server did not shut down correctly\")\n\t\t\t}\n\t\t}()\n\t}\n\n\twaitOutputsFlushed, stopOutputs, err := outputManager.Start(samples)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tlogger.Debug(\"Stopping outputs...\")\n\t\t// We call waitOutputsFlushed() below because the threshold calculations\n\t\t// need all of the metrics to be sent to the MetricsEngine before we can\n\t\t// calculate them one last time. We need the threshold calculated here,\n\t\t// since they may change the run status for the outputs.\n\t\tstopOutputs(err)\n\t}()\n\n\tif thresholdsEnabled {\n\t\tfinalizeThresholds := metricsEngine.StartThresholdCalculations(\n\t\t\tmetricsIngester, runAbort, executionState.GetCurrentTestRunDuration,\n\t\t)\n\t\thandleFinalThresholdCalculation := func() {\n\t\t\t// This gets called after the Samples channel has been closed and\n\t\t\t// the OutputManager has flushed all of the cached samples to\n\t\t\t// outputs (including MetricsEngine's ingester). So we are sure\n\t\t\t// there won't be any more metrics being sent.\n\t\t\tlogger.Debug(\"Finalizing thresholds...\")\n\t\t\tbreachedThresholds := finalizeThresholds()\n\t\t\tif len(breachedThresholds) == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttErr := errext.WithAbortReasonIfNone(\n\t\t\t\terrext.WithExitCodeIfNone(\n\t\t\t\t\tfmt.Errorf(\"thresholds on metrics '%s' have been crossed\", strings.Join(breachedThresholds, \", \")),\n\t\t\t\t\texitcodes.ThresholdsHaveFailed,\n\t\t\t\t), errext.AbortedByThresholdsAfterTestEnd)\n\n\t\t\tif err == nil {\n\t\t\t\terr = tErr\n\t\t\t} else {\n\t\t\t\tlogger.WithError(tErr).Debug(\"Crossed thresholds, but test already exited with another error\")\n\t\t\t}\n\t\t}\n\t\tif finalizeThresholds != nil {\n\t\t\tdefer handleFinalThresholdCalculation()\n\t\t}\n\t}\n\n\tdefer func() {\n\t\tlogger.Debug(\"Waiting for metrics and traces processing to finish...\")\n\t\tclose(samples)\n\n\t\tww := [...]func(){\n\t\t\twaitOutputsFlushed,\n\t\t\twaitTracesFlushed,\n\t\t}\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(len(ww))\n\t\tfor _, w := range ww {\n\t\t\tgo func() {\n\t\t\t\tw()\n\t\t\t\twg.Done()\n\t\t\t}()\n\t\t}\n\t\twg.Wait()\n\n\t\tlogger.Debug(\"Metrics and traces processing finished!\")\n\t}()\n\n\tprintExecutionDescription(\n\t\tc.gs, \"local\", args[0], \"\", conf, executionState.ExecutionTuple, executionPlan, outputs,\n\t)\n\n\t// Trap Interrupts, SIGINTs and SIGTERMs.\n\t// TODO: move upwards, right after runCtx is created\n\tgracefulStop := func(sig os.Signal) {\n\t\tlogger.WithField(\"sig\", sig).Debug(\"Stopping k6 in response to signal...\")\n\t\t// first abort the test run this way, to propagate the error\n\t\trunAbort(errext.WithAbortReasonIfNone(\n\t\t\terrext.WithExitCodeIfNone(\n\t\t\t\tfmt.Errorf(\"test run was aborted because k6 received a '%s' signal\", sig), exitcodes.ExternalAbort,\n\t\t\t), errext.AbortedByUser,\n\t\t))\n\t\tlingerCancel() // cancel this context as well, since the user did Ctrl+C\n\t}\n\tonHardStop := func(sig os.Signal) {\n\t\tlogger.WithField(\"sig\", sig).Error(\"Aborting k6 in response to signal\")\n\t\tglobalCancel() // not that it matters, given that os.Exit() will be called right after\n\t}\n\tstopSignalHandling := handleTestAbortSignals(c.gs, gracefulStop, onHardStop)\n\tdefer stopSignalHandling()\n\n\t// Initialize the VUs and executors\n\tstopVUEmission, err := execScheduler.Init(runCtx, samples)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer stopVUEmission()\n\n\tif conf.Linger.Bool {\n\t\tdefer func() {\n\t\t\tmsg := \"The test is done, but --linger was enabled, so k6 is waiting for Ctrl+C to continue...\"\n\t\t\tselect {\n\t\t\tcase <-lingerCtx.Done():\n\t\t\t\t// do nothing, we were interrupted by Ctrl+C already\n\t\t\tdefault:\n\t\t\t\tlogger.Debug(msg)\n\t\t\t\tif !c.gs.Flags.Quiet {\n\t\t\t\t\tprintToStdout(c.gs, msg)\n\t\t\t\t}\n\t\t\t\t<-lingerCtx.Done()\n\t\t\t\tlogger.Debug(\"Ctrl+C received, exiting...\")\n\t\t\t}\n\t\t}()\n\t}\n\n\twaitInitDone()\n\n\twaitTestStartDone := emitEvent(&event.Event{Type: event.TestStart})\n\twaitTestStartDone()\n\n\t// Start the test! However, we won't immediately return if there was an\n\t// error, we still have things to do.\n\terr = execScheduler.Run(globalCtx, runCtx, samples)\n\n\twaitTestEndDone := emitEvent(&event.Event{Type: event.TestEnd})\n\tdefer waitTestEndDone()\n\n\t// Init has passed successfully, so unless disabled, make sure we send a\n\t// usage report after the context is done.\n\tif !conf.NoUsageReport.Bool {\n\t\tbackgroundProcesses.Go(func() {\n\t\t\treportCtx, reportCancel := context.WithTimeout(globalCtx, 3*time.Second)\n\t\t\tdefer reportCancel()\n\t\t\tlogger.Debug(\"Sending usage report...\")\n\n\t\t\tif rerr := reportUsage(reportCtx, execScheduler, test); rerr != nil {\n\t\t\t\tlogger.WithError(rerr).Debug(\"Error sending usage report\")\n\t\t\t} else {\n\t\t\t\tlogger.Debug(\"Usage report sent successfully\")\n\t\t\t}\n\t\t})\n\t}\n\n\t// Check what the execScheduler.Run() error is.\n\tif err != nil {\n\t\terr = common.UnwrapSobekInterruptedError(err)\n\t\tlogger.WithError(err).Debug(\"Test finished with an error\")\n\t\treturn err\n\t}\n\n\t// Warn if no iterations could be completed.\n\tif executionState.GetFullIterationCount() == 0 {\n\t\tlogger.Warn(\"No script iterations fully finished, consider making the test duration longer\")\n\t}\n\n\t// The execution module enables users to mark a test as failed, while letting the test\n\t// execution complete. As such, we check the test status here, after the test run has finished, and\n\t// ensure we return an error indicating that the test run was marked as failed, and the proper\n\t// exit code is used.\n\tif testRunState.TestStatus.Failed() {\n\t\treturn errext.WithExitCodeIfNone(\n\t\t\tfmt.Errorf(\"test run was marked as failed\"),\n\t\t\texitcodes.MarkedAsFailed,\n\t\t)\n\t}\n\n\tlogger.Debug(\"Test finished cleanly\")\n\n\treturn nil\n}\n\nfunc getSummaryMode(runtimeOptions lib.RuntimeOptions) (summary.Mode, bool, error) {\n\tif runtimeOptions.NoSummary.Bool {\n\t\treturn summary.ModeDisabled, false, nil\n\t}\n\n\tsm, err := summary.ValidateMode(runtimeOptions.SummaryMode.String)\n\tif err != nil {\n\t\treturn summary.ModeDisabled, false, err\n\t}\n\n\treturn sm, sm != summary.ModeDisabled, nil\n}\n\nfunc (c *cmdRun) flagSet() *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", pflag.ContinueOnError)\n\tflags.SortFlags = false\n\tflags.AddFlagSet(optionFlagSet())\n\tflags.AddFlagSet(runtimeOptionFlagSet(true))\n\tflags.AddFlagSet(configFlagSet())\n\treturn flags\n}\n\nfunc (c *cmdRun) setupTracerProvider(ctx context.Context, test *loadedAndConfiguredTest) error {\n\tro := test.preInitState.RuntimeOptions\n\tif ro.TracesOutput.String == \"none\" {\n\t\ttest.preInitState.TracerProvider = trace.NewNoopTracerProvider()\n\t\treturn nil\n\t}\n\n\ttp, err := trace.TracerProviderFromConfigLine(ctx, ro.TracesOutput.String)\n\tif err != nil {\n\t\treturn err\n\t}\n\ttest.preInitState.TracerProvider = tp\n\n\treturn nil\n}\n\nfunc getCmdRun(gs *state.GlobalState) *cobra.Command {\n\tc := &cmdRun{\n\t\tgs: gs,\n\t\tloadConfiguredTest: func(cmd *cobra.Command, args []string) (*loadedAndConfiguredTest, execution.Controller, error) {\n\t\t\ttest, err := loadAndConfigureLocalTest(gs, cmd, args, getConfig)\n\t\t\treturn test, local.NewController(), err\n\t\t},\n\t}\n\n\texampleText := getExampleText(gs, `\n  # Run a single VU, once.\n  {{.}} run script.js\n\n  # Run a single VU, 10 times.\n  {{.}} run -i 10 script.js\n\n  # Run 5 VUs, splitting 10 iterations between them.\n  {{.}} run -u 5 -i 10 script.js\n\n  # Run 5 VUs for 10s.\n  {{.}} run -u 5 -d 10s script.js\n\n  # Ramp VUs from 0 to 100 over 10s, stay there for 60s, then 10s down to 0.\n  {{.}} run -u 0 -s 10s:100 -s 60s:100 -s 10s:0\n\n  # Send metrics to a remote storage using the OpenTelemetry output.\n  {{.}} run -o opentelemetry`[1:])\n\n\trunCmd := &cobra.Command{\n\t\tUse:   \"run\",\n\t\tShort: \"Run a test\",\n\t\tLong: `Start a test. This also exposes a REST API to interact with it. Various k6 subcommands offer\na commandline interface for interacting with it.`,\n\t\tExample: exampleText,\n\t\tArgs:    exactArgsWithMsg(1, \"arg should either be \\\"-\\\", if reading script from stdin, or a path to a script file\"),\n\t\tRunE:    c.run,\n\t}\n\n\trunCmd.Flags().SortFlags = false\n\trunCmd.Flags().AddFlagSet(c.flagSet())\n\n\treturn runCmd\n}\n\nfunc handleSummaryResult(fs fsext.Fs, stdOut, stdErr io.Writer, result map[string]io.Reader) error {\n\tvar errs []error\n\n\tgetWriter := func(path string) (io.Writer, error) {\n\t\tswitch path {\n\t\tcase \"stdout\":\n\t\t\treturn stdOut, nil\n\t\tcase \"stderr\":\n\t\t\treturn stdErr, nil\n\t\tdefault:\n\t\t\treturn fs.OpenFile(path, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_TRUNC, 0o666)\n\t\t}\n\t}\n\n\tfor path, value := range result {\n\t\tif writer, err := getWriter(path); err != nil {\n\t\t\terrs = append(errs, fmt.Errorf(\"could not open '%s': %w\", path, err))\n\t\t} else if n, err := io.Copy(writer, value); err != nil {\n\t\t\terrs = append(errs, fmt.Errorf(\"error saving summary to '%s' after %d bytes: %w\", path, n, err))\n\t\t}\n\t}\n\n\treturn consolidateErrorMessage(errs, \"Could not save some summary information:\")\n}\n"
  },
  {
    "path": "internal/cmd/run_test.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/errext\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\ntype mockWriter struct {\n\terr      error\n\terrAfter int\n}\n\nfunc (fw mockWriter) Write(p []byte) (n int, err error) {\n\tif fw.err != nil {\n\t\treturn fw.errAfter, fw.err\n\t}\n\treturn len(p), nil\n}\n\nvar _ io.Writer = mockWriter{}\n\nfunc getFiles(t *testing.T, fileSystem fsext.Fs) map[string]*bytes.Buffer {\n\tresult := map[string]*bytes.Buffer{}\n\twalkFn := func(filePath string, _ fs.FileInfo, err error) error {\n\t\tif filePath == \"/\" || filePath == \"\\\\\" {\n\t\t\treturn nil\n\t\t}\n\t\trequire.NoError(t, err)\n\t\tcontents, err := fsext.ReadFile(fileSystem, filePath)\n\t\trequire.NoError(t, err)\n\t\tresult[filePath] = bytes.NewBuffer(contents)\n\t\treturn nil\n\t}\n\n\terr := fsext.Walk(fileSystem, fsext.FilePathSeparator, filepath.WalkFunc(walkFn))\n\trequire.NoError(t, err)\n\n\treturn result\n}\n\nfunc assertEqual(t *testing.T, exp string, actual io.Reader) {\n\tact, err := io.ReadAll(actual)\n\trequire.NoError(t, err)\n\tassert.Equal(t, []byte(exp), act)\n}\n\nfunc initVars() (\n\tcontent map[string]io.Reader, stdout *bytes.Buffer, stderr *bytes.Buffer, fs fsext.Fs,\n) {\n\treturn map[string]io.Reader{}, bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{}), fsext.NewMemMapFs()\n}\n\nfunc TestHandleSummaryResultSimple(t *testing.T) {\n\tt.Parallel()\n\tcontent, stdout, stderr, fs := initVars()\n\n\t// Test noop\n\tassert.NoError(t, handleSummaryResult(fs, stdout, stderr, content))\n\trequire.Empty(t, getFiles(t, fs))\n\trequire.Empty(t, stdout.Bytes())\n\trequire.Empty(t, stderr.Bytes())\n\n\t// Test stdout only\n\tcontent[\"stdout\"] = bytes.NewBufferString(\"some stdout summary\")\n\tassert.NoError(t, handleSummaryResult(fs, stdout, stderr, content))\n\trequire.Empty(t, getFiles(t, fs))\n\tassertEqual(t, \"some stdout summary\", stdout)\n\trequire.Empty(t, stderr.Bytes())\n}\n\nfunc TestHandleSummaryResultError(t *testing.T) {\n\tt.Parallel()\n\tcontent, _, stderr, fs := initVars()\n\n\texpErr := errors.New(\"test error\")\n\tstdout := mockWriter{err: expErr, errAfter: 10}\n\n\tfilePath1 := \"/path/file1\"\n\tfilePath2 := \"/path/file2\"\n\tif runtime.GOOS == \"windows\" {\n\t\tfilePath1 = \"\\\\path\\\\file1\"\n\t\tfilePath2 = \"\\\\path\\\\file2\"\n\t}\n\n\tcontent[\"stdout\"] = bytes.NewBufferString(\"some stdout summary\")\n\tcontent[\"stderr\"] = bytes.NewBufferString(\"some stderr summary\")\n\tcontent[filePath1] = bytes.NewBufferString(\"file summary 1\")\n\tcontent[filePath2] = bytes.NewBufferString(\"file summary 2\")\n\terr := handleSummaryResult(fs, stdout, stderr, content)\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), expErr.Error())\n\tfiles := getFiles(t, fs)\n\tassertEqual(t, \"file summary 1\", files[filePath1])\n\tassertEqual(t, \"file summary 2\", files[filePath2])\n}\n\nfunc TestRunScriptErrorsAndAbort(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\ttestFilename, name   string\n\t\texpErr, expLogOutput string\n\t\texpExitCode          exitcodes.ExitCode\n\t\tconfigFilename       string\n\t\textraArgs            []string\n\t\tenvVars              map[string]string\n\t}{\n\t\t{\n\t\t\ttestFilename: \"abort.js\",\n\t\t\texpErr:       errext.AbortTest,\n\t\t\texpExitCode:  exitcodes.ScriptAborted,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"abort_initerr.js\",\n\t\t\texpErr:       errext.AbortTest,\n\t\t\texpExitCode:  exitcodes.ScriptAborted,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"abort_initvu.js\",\n\t\t\texpErr:       errext.AbortTest,\n\t\t\texpExitCode:  exitcodes.ScriptAborted,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"abort_teardown.js\",\n\t\t\texpErr:       errext.AbortTest,\n\t\t\texpExitCode:  exitcodes.ScriptAborted,\n\t\t\texpLogOutput: \"Calling teardown function after test.abort()\",\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"initerr.js\",\n\t\t\texpErr:       \"ReferenceError: someUndefinedVar is not defined\",\n\t\t\texpExitCode:  exitcodes.ScriptException,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"invalidconfig/invalid_option.js\",\n\t\t\tname:         \"run should fail with exit status 104 if an invalid option value exists\",\n\t\t\texpErr:       \"this is an invalid type\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"invalidconfig/option_env.js\",\n\t\t\tname:         \"run should fail with exit status 104 if an invalid option is set through env variable\",\n\t\t\texpErr:       \"envconfig.Process\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t\tenvVars: map[string]string{\n\t\t\t\t\"K6_DURATION\": \"fails\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"invalidconfig/option_env.js\",\n\t\t\tname:         \"run should fail with exit status 104 if an invalid option is set through k6 variable\",\n\t\t\texpErr:       \"invalid duration\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t\textraArgs:    []string{\"--env\", \"DURATION=fails\"},\n\t\t},\n\t\t{\n\t\t\ttestFilename:   \"invalidconfig/option_env.js\",\n\t\t\tname:           \"run should fail with exit status 104 if an invalid option is set in a config file\",\n\t\t\texpErr:         \"invalid duration\",\n\t\t\texpExitCode:    exitcodes.InvalidConfig,\n\t\t\tconfigFilename: \"invalidconfig/invalid.json\",\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"invalidconfig/invalid_scenario.js\",\n\t\t\tname:         \"run should fail with exit status 104 if an invalid scenario exists\",\n\t\t\texpErr:       \"specified executor type\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"thresholds/non_existing_metric.js\",\n\t\t\tname:         \"run should fail with exit status 104 on a threshold applied to a non existing metric\",\n\t\t\texpErr:       \"invalid threshold\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"thresholds/non_existing_metric.js\",\n\t\t\tname:         \"run should succeed on a threshold applied to a non existing metric with the --no-thresholds flag set\",\n\t\t\textraArgs:    []string{\"--no-thresholds\"},\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"thresholds/non_existing_metric.js\",\n\t\t\tname:         \"run should succeed on a threshold applied to a non existing submetric with the --no-thresholds flag set\",\n\t\t\textraArgs:    []string{\"--no-thresholds\"},\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"thresholds/malformed_expression.js\",\n\t\t\tname:         \"run should fail with exit status 104 on a malformed threshold expression\",\n\t\t\texpErr:       \"malformed threshold expression\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"thresholds/malformed_expression.js\",\n\t\t\tname:         \"run should on a malformed threshold expression but --no-thresholds flag set\",\n\t\t\textraArgs:    []string{\"--no-thresholds\"},\n\t\t\t// we don't expect an error\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"thresholds/unsupported_aggregation_method.js\",\n\t\t\tname:         \"run should fail with exit status 104 on a threshold applying an unsupported aggregation method to a metric\",\n\t\t\texpErr:       \"invalid threshold\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"thresholds/unsupported_aggregation_method.js\",\n\t\t\tname:         \"run should succeed on a threshold applying an unsupported aggregation method to a metric with the --no-thresholds flag set\",\n\t\t\textraArgs:    []string{\"--no-thresholds\"},\n\t\t},\n\t\t{\n\t\t\ttestFilename: \"fail.js\",\n\t\t\texpExitCode:  exitcodes.MarkedAsFailed,\n\t\t\texpErr:       errext.MarkedAsFailedTest,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tname := tc.testFilename\n\t\tif tc.name != \"\" {\n\t\t\tname = fmt.Sprintf(\"%s (%s)\", tc.testFilename, tc.name)\n\t\t}\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestScript, err := os.ReadFile(path.Join(\"testdata\", tc.testFilename)) //nolint:forbidigo\n\t\t\trequire.NoError(t, err)\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, tc.testFilename), testScript, 0o644))\n\t\t\tts.CmdArgs = append([]string{\"k6\", \"run\", tc.testFilename}, tc.extraArgs...)\n\n\t\t\tif tc.configFilename != \"\" {\n\t\t\t\tconfigFile, err := os.ReadFile(path.Join(\"testdata\", tc.configFilename)) //nolint:forbidigo\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, tc.configFilename), configFile, 0o644))\n\t\t\t\tts.Flags.ConfigFilePath = path.Join(ts.Cwd, tc.configFilename)\n\t\t\t}\n\t\t\tif tc.envVars != nil {\n\t\t\t\tts.Env = tc.envVars\n\t\t\t}\n\n\t\t\tts.ExpectedExitCode = int(tc.expExitCode)\n\t\t\tnewRootCommand(ts.GlobalState).execute()\n\n\t\t\tlogs := ts.LoggerHook.Drain()\n\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\tassert.True(t, testutils.LogContains(logs, logrus.ErrorLevel, tc.expErr))\n\t\t\t}\n\n\t\t\tif tc.expLogOutput != \"\" {\n\t\t\t\tassert.True(t, testutils.LogContains(logs, logrus.InfoLevel, tc.expLogOutput))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInvalidOptionsThresholdErrExitCode(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname         string\n\t\ttestFilename string\n\t\texpExitCode  exitcodes.ExitCode\n\t\textraArgs    []string\n\t}{\n\t\t{\n\t\t\tname:         \"run should fail with exit status 104 on a malformed threshold expression\",\n\t\t\ttestFilename: \"thresholds/malformed_expression.js\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t\t{\n\t\t\tname:         \"run should fail with exit status 104 on a threshold applied to a non existing metric\",\n\t\t\ttestFilename: \"thresholds/non_existing_metric.js\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t\t{\n\t\t\tname:         \"run should fail with exit status 104 on a threshold method being unsupported by the metric\",\n\t\t\ttestFilename: \"thresholds/unsupported_aggregation_method.js\",\n\t\t\texpExitCode:  exitcodes.InvalidConfig,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestScript, err := os.ReadFile(path.Join(\"testdata\", tc.testFilename)) //nolint:forbidigo\n\t\t\trequire.NoError(t, err)\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, tc.testFilename), testScript, 0o644))\n\t\t\tts.CmdArgs = append([]string{\"k6\", \"run\", tc.testFilename}, tc.extraArgs...)\n\n\t\t\tts.ExpectedExitCode = int(tc.expExitCode)\n\t\t\tnewRootCommand(ts.GlobalState).execute()\n\t\t})\n\t}\n}\n\nfunc TestThresholdsRuntimeBehavior(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname                 string\n\t\ttestFilename         string\n\t\texpExitCode          exitcodes.ExitCode\n\t\texpStdoutContains    string\n\t\texpStdoutNotContains string\n\t\textraArgs            []string\n\t}{\n\t\t{\n\t\t\tname:              \"#2518: submetrics without values should be rendered under their parent metric #2518\",\n\t\t\ttestFilename:      \"thresholds/thresholds_on_submetric_without_samples.js\",\n\t\t\texpExitCode:       0,\n\t\t\texpStdoutContains: \"    one..................: 0   0/s\\n      { tag:xyz }........: 0   0/s\\n\",\n\t\t},\n\t\t{\n\t\t\tname:         \"#2512: parsing threshold names containing parsable tokens should be valid\",\n\t\t\ttestFilename: \"thresholds/name_contains_tokens.js\",\n\t\t\texpExitCode:  0,\n\t\t},\n\t\t{\n\t\t\tname:                 \"#2520: thresholds over metrics without values should avoid division by zero and displaying NaN values\",\n\t\t\ttestFilename:         \"thresholds/empty_sink_no_nan.js\",\n\t\t\texpExitCode:          0,\n\t\t\texpStdoutContains:    \"rate.................: 0.00%\",\n\t\t\texpStdoutNotContains: \"NaN\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestScript, err := os.ReadFile(path.Join(\"testdata\", tc.testFilename)) //nolint:forbidigo\n\t\t\trequire.NoError(t, err)\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, tc.testFilename), testScript, 0o644))\n\n\t\t\tts.CmdArgs = []string{\"k6\", \"run\", tc.testFilename}\n\t\t\tts.ExpectedExitCode = int(tc.expExitCode)\n\t\t\tnewRootCommand(ts.GlobalState).execute()\n\n\t\t\tif tc.expStdoutContains != \"\" {\n\t\t\t\tassert.Contains(t, ts.Stdout.String(), tc.expStdoutContains)\n\t\t\t}\n\n\t\t\tif tc.expStdoutNotContains != \"\" {\n\t\t\t\tt.Log(ts.Stdout.String())\n\t\t\t\tassert.NotContains(t, ts.Stdout.String(), tc.expStdoutNotContains)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/runtime_options.go",
    "content": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\n\t\"github.com/spf13/pflag\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/lib\"\n)\n\n// TODO: move this whole file out of the cmd package? maybe when fixing\n// https://github.com/k6io/k6/issues/883, since this code is fairly\n// self-contained and easily testable now, without any global dependencies...\n\nvar userEnvVarName = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)\n\nfunc runtimeOptionFlagSet(includeSysEnv bool) *pflag.FlagSet {\n\tflags := pflag.NewFlagSet(\"\", 0)\n\tflags.SortFlags = false\n\tflags.Bool(\"include-system-env-vars\", includeSysEnv, \"pass the real system environment variables to the runtime\")\n\tflags.String(\"compatibility-mode\", \"extended\",\n\t\t`JavaScript compiler compatibility mode, \"extended\" or \"base\"\nbase: pure Sobek - Golang JS VM supporting ES6+\nextended: base + sets \"global\" as alias for \"globalThis\"\n`)\n\tflags.StringP(\"type\", \"t\", \"\", \"override test type, \\\"js\\\" or \\\"archive\\\"\")\n\tflags.StringArrayP(\"env\", \"e\", nil, \"add/override environment variable with `VAR=value`\")\n\tflags.Bool(\"no-thresholds\", false, \"don't run thresholds\")\n\t// TODO(@joanlopez): remove by k6 v2.0, once we completely drop the support of the deprecated --no-summary flag.\n\tflags.Bool(\"no-summary\", false, \"don't show the summary at the end of the test\")\n\tif err := flags.MarkDeprecated(\"no-summary\", \"use --summary-mode=disabled instead\"); err != nil {\n\t\tpanic(err) // Should never happen\n\t}\n\tflags.String(\"summary-mode\", summary.ModeCompact.String(), \"determine the summary mode,\"+\n\t\t\" \\\"compact\\\", \\\"full\\\" or \\\"disabled\\\"\")\n\tflags.String(\n\t\t\"summary-export\",\n\t\t\"\",\n\t\t\"output the end-of-test summary report to JSON file\",\n\t)\n\t// TODO(@joanlopez): remove by k6 v2.0, once the new summary model is the default and the only one.\n\tflags.Bool(\"new-machine-readable-summary\", false, \"enables the new machine-readable summary, \"+\n\t\t\"which is used for summary exports and as handleSummary() argument\")\n\tflags.String(\"traces-output\", \"none\",\n\t\t\"set the output for k6 traces, possible values are none,otel[=host:port]\")\n\treturn flags\n}\n\nfunc getRuntimeOptions(\n\tflags *pflag.FlagSet,\n\tenvironment map[string]string,\n) (lib.RuntimeOptions, error) {\n\t// TODO: refactor with composable helpers as a part of #883, to reduce copy-paste\n\t// TODO: get these options out of the JSON config file as well?\n\topts, err := populateRuntimeOptionsFromEnv(runtimeOptionsFromFlags(flags), environment)\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\n\t// Set/overwrite environment variables with custom user-supplied values\n\tenvVars, err := flags.GetStringArray(\"env\")\n\tif err != nil {\n\t\treturn opts, err\n\t}\n\tfor _, kv := range envVars {\n\t\tk, v := state.ParseEnvKeyValue(kv)\n\t\t// Allow only alphanumeric ASCII variable names for now\n\t\tif !userEnvVarName.MatchString(k) {\n\t\t\treturn opts, fmt.Errorf(\"invalid environment variable name '%s'\", k)\n\t\t}\n\t\topts.Env[k] = v\n\t}\n\n\treturn opts, nil\n}\n\nfunc runtimeOptionsFromFlags(flags *pflag.FlagSet) lib.RuntimeOptions {\n\topts := lib.RuntimeOptions{\n\t\tTestType:                  getNullString(flags, \"type\"),\n\t\tIncludeSystemEnvVars:      getNullBool(flags, \"include-system-env-vars\"),\n\t\tCompatibilityMode:         getNullString(flags, \"compatibility-mode\"),\n\t\tNoThresholds:              getNullBool(flags, \"no-thresholds\"),\n\t\tNoSummary:                 getNullBool(flags, \"no-summary\"),\n\t\tSummaryMode:               getNullString(flags, \"summary-mode\"),\n\t\tSummaryExport:             getNullString(flags, \"summary-export\"),\n\t\tNewMachineReadableSummary: getNullBool(flags, \"new-machine-readable-summary\"),\n\t\tTracesOutput:              getNullString(flags, \"traces-output\"),\n\t\tEnv:                       make(map[string]string),\n\t}\n\treturn opts\n}\n\nfunc populateRuntimeOptionsFromEnv(opts lib.RuntimeOptions, environment map[string]string) (lib.RuntimeOptions, error) {\n\t// Only override if not explicitly set via the CLI flag\n\n\tif envVar, ok := environment[\"K6_TYPE\"]; !opts.TestType.Valid && ok {\n\t\topts.TestType = null.StringFrom(envVar)\n\t}\n\n\tif envVar, ok := environment[\"K6_COMPATIBILITY_MODE\"]; !opts.CompatibilityMode.Valid && ok {\n\t\topts.CompatibilityMode = null.StringFrom(envVar)\n\t}\n\n\tif _, err := lib.ValidateCompatibilityMode(opts.CompatibilityMode.String); err != nil {\n\t\t// some early validation\n\t\treturn opts, err\n\t}\n\n\tif err := saveBoolFromEnv(environment, \"K6_INCLUDE_SYSTEM_ENV_VARS\", &opts.IncludeSystemEnvVars); err != nil {\n\t\treturn opts, err\n\t}\n\n\tif err := saveBoolFromEnv(environment, \"K6_NO_THRESHOLDS\", &opts.NoThresholds); err != nil {\n\t\treturn opts, err\n\t}\n\n\tif err := saveBoolFromEnv(environment, \"K6_NO_SUMMARY\", &opts.NoSummary); err != nil {\n\t\treturn opts, err\n\t}\n\n\tif envVar, ok := environment[\"K6_SUMMARY_MODE\"]; !opts.SummaryMode.Valid && ok {\n\t\topts.SummaryMode = null.StringFrom(envVar)\n\t}\n\n\tif _, err := summary.ValidateMode(opts.SummaryMode.String); err != nil {\n\t\t// In the case of an invalid summary mode, we early stop\n\t\t// the execution and return the error to the user.\n\t\treturn opts, err\n\t}\n\n\tif envVar, ok := environment[\"K6_SUMMARY_EXPORT\"]; !opts.SummaryExport.Valid && ok {\n\t\topts.SummaryExport = null.StringFrom(envVar)\n\t}\n\n\tif err := saveBoolFromEnv(\n\t\tenvironment, \"K6_NEW_MACHINE_READABLE_SUMMARY\", &opts.NewMachineReadableSummary,\n\t); err != nil {\n\t\treturn opts, err\n\t}\n\n\tif envVar, ok := environment[\"SSLKEYLOGFILE\"]; !opts.KeyWriter.Valid && ok {\n\t\topts.KeyWriter = null.StringFrom(envVar)\n\t}\n\n\tif envVar, ok := environment[\"K6_TRACES_OUTPUT\"]; !opts.TracesOutput.Valid && ok {\n\t\topts.TracesOutput = null.StringFrom(envVar)\n\t}\n\n\t// If enabled, gather the actual system environment variables\n\tif opts.IncludeSystemEnvVars.Bool {\n\t\topts.Env = environment\n\t}\n\n\treturn opts, nil\n}\n\nfunc saveBoolFromEnv(env map[string]string, varName string, placeholder *null.Bool) error {\n\tstrValue, ok := env[varName]\n\tif !ok {\n\t\treturn nil\n\t}\n\tval, err := strconv.ParseBool(strValue)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"env var '%s' is not a valid boolean value: %w\", varName, err)\n\t}\n\t// Only override if not explicitly set via the CLI flag\n\tif !placeholder.Valid {\n\t\t*placeholder = null.BoolFrom(val)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/cmd/runtime_options_test.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype runtimeOptionsTestCase struct {\n\tuseSysEnv bool // Whether to include the system env vars by default (run) or not (cloud/archive/inspect)\n\texpErr    bool\n\tcliFlags  []string\n\tsystemEnv map[string]string\n\texpRTOpts lib.RuntimeOptions\n}\n\nfunc testRuntimeOptionsCase(t *testing.T, tc runtimeOptionsTestCase) {\n\tt.Helper()\n\tflags := runtimeOptionFlagSet(tc.useSysEnv)\n\trequire.NoError(t, flags.Parse(tc.cliFlags))\n\n\trtOpts, err := getRuntimeOptions(flags, tc.systemEnv)\n\tif tc.expErr {\n\t\trequire.Error(t, err)\n\t\treturn\n\t}\n\trequire.NoError(t, err)\n\trequire.Equal(t, tc.expRTOpts, rtOpts)\n\n\tcompatMode, err := lib.ValidateCompatibilityMode(rtOpts.CompatibilityMode.String)\n\trequire.NoError(t, err)\n\n\tjsCode := new(bytes.Buffer)\n\tif compatMode == lib.CompatibilityModeExtended {\n\t\tfmt.Fprint(jsCode, \"export default function() {\")\n\t} else {\n\t\tfmt.Fprint(jsCode, \"module.exports.default = function() {\")\n\t}\n\n\tfor key, val := range tc.expRTOpts.Env {\n\t\tfmt.Fprintf(jsCode,\n\t\t\t\"if (__ENV.%s !== `%s`) { throw new Error('Invalid %s: ' + __ENV.%s); }\",\n\t\t\tkey, val, key, key,\n\t\t)\n\t}\n\tfmt.Fprint(jsCode, \"}\")\n\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/script.js\", jsCode.Bytes(), 0o644))\n\n\tts := tests.NewGlobalTestState(t) // TODO: move upwards, make this into an almost full integration test\n\tregistry := metrics.NewRegistry()\n\ttest := &loadedTest{\n\t\tsourceRootPath: \"script.js\",\n\t\tsource:         &loader.SourceData{Data: jsCode.Bytes(), URL: &url.URL{Path: \"/script.js\", Scheme: \"file\"}},\n\t\tfileSystems:    map[string]fsext.Fs{\"file\": fs},\n\t\tpreInitState: &lib.TestPreInitState{\n\t\t\tLogger:         ts.Logger,\n\t\t\tRuntimeOptions: rtOpts,\n\t\t\tRegistry:       registry,\n\t\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\t\tUsage:          usage.New(),\n\t\t},\n\t}\n\n\trequire.NoError(t, test.prepareFirstRunner(ts.GlobalState))\n\trequire.NoError(t, test.continueInitialization(ts.GlobalState))\n\n\tarchive := test.initRunner.MakeArchive()\n\tarchiveBuf := &bytes.Buffer{}\n\trequire.NoError(t, archive.Write(archiveBuf))\n\n\tgetRunnerErr := func(rtOpts lib.RuntimeOptions) *loadedTest {\n\t\treturn &loadedTest{\n\t\t\tsourceRootPath: \"script.tar\",\n\t\t\tsource:         &loader.SourceData{Data: archiveBuf.Bytes(), URL: &url.URL{Path: \"/script.tar\", Scheme: \"file\"}},\n\t\t\tfileSystems:    map[string]fsext.Fs{\"file\": fs},\n\t\t\tpreInitState: &lib.TestPreInitState{\n\t\t\t\tLogger:         ts.Logger,\n\t\t\t\tRuntimeOptions: rtOpts,\n\t\t\t\tRegistry:       registry,\n\t\t\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\t\t\tUsage:          usage.New(),\n\t\t\t},\n\t\t}\n\t}\n\n\tarchTest := getRunnerErr(lib.RuntimeOptions{})\n\trequire.NoError(t, archTest.prepareFirstRunner(ts.GlobalState))\n\trequire.NoError(t, archTest.continueInitialization(ts.GlobalState))\n\n\tfor key, val := range tc.expRTOpts.Env {\n\t\tarchTest = getRunnerErr(lib.RuntimeOptions{Env: map[string]string{key: \"almost \" + val}})\n\t\trequire.NoError(t, archTest.prepareFirstRunner(ts.GlobalState))\n\t\trequire.NoError(t, archTest.continueInitialization(ts.GlobalState))\n\t\tassert.Equal(t, \"almost \"+val, archTest.initRunner.MakeArchive().Env[key])\n\t}\n}\n\nfunc TestRuntimeOptions(t *testing.T) {\n\tt.Parallel()\n\tvar (\n\t\tdefaultCompatMode                = null.NewString(\"extended\", false)\n\t\tbaseCompatMode                   = null.NewString(\"base\", true)\n\t\textendedCompatMode               = null.NewString(\"extended\", true)\n\t\tenhancedCompatMode               = null.NewString(\"experimental_enhanced\", true)\n\t\tdefaultTracesOutput              = null.NewString(\"none\", false)\n\t\tdefaultSummaryMode               = null.NewString(\"compact\", false)\n\t\tdefaultNewMachineReadableSummary = null.NewBool(false, false)\n\t)\n\n\truntimeOptionsTestCases := map[string]runtimeOptionsTestCase{\n\t\t\"empty env\": {\n\t\t\tuseSysEnv: true,\n\t\t\t// everything else is empty\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       nil,\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"disabled sys env by default\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"disabled sys env by default with ext compat mode\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\", \"K6_COMPATIBILITY_MODE\": \"extended\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         extendedCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"disabled sys env by default with experimental_enhanced compat mode\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\", \"K6_COMPATIBILITY_MODE\": \"experimental_enhanced\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         enhancedCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"disabled sys env by cli 1\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\", \"K6_COMPATIBILITY_MODE\": \"base\"},\n\t\t\tcliFlags:  []string{\"--include-system-env-vars=false\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, true),\n\t\t\t\tCompatibilityMode:         baseCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"disabled sys env by cli 2\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"K6_INCLUDE_SYSTEM_ENV_VARS\": \"true\", \"K6_COMPATIBILITY_MODE\": \"extended\"},\n\t\t\tcliFlags:  []string{\"--include-system-env-vars=0\", \"--compatibility-mode=base\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, true),\n\t\t\t\tCompatibilityMode:         baseCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"disabled sys env by env\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"K6_INCLUDE_SYSTEM_ENV_VARS\": \"false\", \"K6_COMPATIBILITY_MODE\": \"extended\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, true),\n\t\t\t\tCompatibilityMode:         extendedCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"enabled sys env by env\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_INCLUDE_SYSTEM_ENV_VARS\": \"true\", \"K6_COMPATIBILITY_MODE\": \"extended\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, true),\n\t\t\t\tCompatibilityMode:         extendedCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"K6_INCLUDE_SYSTEM_ENV_VARS\": \"true\", \"K6_COMPATIBILITY_MODE\": \"extended\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"enabled sys env by default\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\"},\n\t\t\tcliFlags:  []string{},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"val1\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"enabled sys env by cli 1\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\"},\n\t\t\tcliFlags:  []string{\"--include-system-env-vars\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, true),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"val1\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"enabled sys env by cli 2\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\"},\n\t\t\tcliFlags:  []string{\"--include-system-env-vars=true\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, true),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"val1\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"run only system env\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\"},\n\t\t\tcliFlags:  []string{},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"val1\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"mixed system and cli env\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\", \"test2\": \"\"},\n\t\t\tcliFlags:  []string{\"--env\", \"test3=val3\", \"-e\", \"test4\", \"-e\", \"test5=\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"val1\", \"test2\": \"\", \"test3\": \"val3\", \"test4\": \"\", \"test5\": \"\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"mixed system and cli env 2\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\", \"test2\": \"\"},\n\t\t\tcliFlags:  []string{\"--env\", \"test3=val3\", \"-e\", \"test4\", \"-e\", \"test5=\", \"--include-system-env-vars=1\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, true),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"val1\", \"test2\": \"\", \"test3\": \"val3\", \"test4\": \"\", \"test5\": \"\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"disabled system env with cli params\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1\"},\n\t\t\tcliFlags:  []string{\"-e\", \"test2=overwriten\", \"-e\", \"test2=val2\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test2\": \"val2\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"overwriting system env with cli param\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"val1sys\"},\n\t\t\tcliFlags:  []string{\"--env\", \"test1=val1cli\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"val1cli\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"error wrong compat mode env var value\": {\n\t\t\tsystemEnv: map[string]string{\"K6_COMPATIBILITY_MODE\": \"asdf\"},\n\t\t\texpErr:    true,\n\t\t},\n\t\t\"error wrong compat mode env var value even with CLI flag\": {\n\t\t\tsystemEnv: map[string]string{\"K6_COMPATIBILITY_MODE\": \"asdf\"},\n\t\t\tcliFlags:  []string{\"--compatibility-mode\", \"true\"},\n\t\t\texpErr:    true,\n\t\t},\n\t\t\"error wrong compat mode cli flag value\": {\n\t\t\tcliFlags: []string{\"--compatibility-mode\", \"whatever\"},\n\t\t\texpErr:   true,\n\t\t},\n\t\t\"error invalid cli var name 1\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{},\n\t\t\tcliFlags:  []string{\"--env\", \"test a=error\"},\n\t\t\texpErr:    true,\n\t\t},\n\t\t\"error invalid cli var name 2\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{},\n\t\t\tcliFlags:  []string{\"--env\", \"1var=error\"},\n\t\t\texpErr:    true,\n\t\t},\n\t\t\"error invalid cli var name 3\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{},\n\t\t\tcliFlags:  []string{\"--env\", \"уникод=unicode-disabled\"},\n\t\t\texpErr:    true,\n\t\t},\n\t\t\"valid env vars with spaces\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"value 1\"},\n\t\t\tcliFlags:  []string{\"--env\", \"test2=value 2\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"value 1\", \"test2\": \"value 2\"},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"valid env vars with special chars\": {\n\t\t\tuseSysEnv: true,\n\t\t\tsystemEnv: map[string]string{\"test1\": \"value 1\"},\n\t\t\tcliFlags:  []string{\"--env\", \"test2=value,2\", \"-e\", `test3= ,  ,,, value, ,, 2!'@#,\"`},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(true, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{\"test1\": \"value 1\", \"test2\": \"value,2\", \"test3\": ` ,  ,,, value, ,, 2!'@#,\"`},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"summary and thresholds from env\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_NO_THRESHOLDS\": \"false\", \"K6_NO_SUMMARY\": \"0\", \"K6_SUMMARY_EXPORT\": \"foo\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tNoThresholds:              null.NewBool(false, true),\n\t\t\t\tNoSummary:                 null.NewBool(false, true),\n\t\t\t\tSummaryExport:             null.NewString(\"foo\", true),\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"summary and thresholds from env overwritten by CLI\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_NO_THRESHOLDS\": \"FALSE\", \"K6_NO_SUMMARY\": \"0\", \"K6_SUMMARY_EXPORT\": \"foo\"},\n\t\t\tcliFlags:  []string{\"--no-thresholds\", \"true\", \"--no-summary\", \"true\", \"--summary-export\", \"bar\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tNoThresholds:              null.NewBool(true, true),\n\t\t\t\tNoSummary:                 null.NewBool(true, true),\n\t\t\t\tSummaryExport:             null.NewString(\"bar\", true),\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"env var error detected even when CLI flags overwrite 1\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_NO_THRESHOLDS\": \"boo\"},\n\t\t\tcliFlags:  []string{\"--no-thresholds\", \"true\"},\n\t\t\texpErr:    true,\n\t\t},\n\t\t\"env var error detected even when CLI flags overwrite 2\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_NO_SUMMARY\": \"hoo\"},\n\t\t\tcliFlags:  []string{\"--no-summary\", \"true\"},\n\t\t\texpErr:    true,\n\t\t},\n\t\t\"traces output default\": {\n\t\t\tuseSysEnv: false,\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              null.NewString(\"none\", false),\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"traces output from env\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_TRACES_OUTPUT\": \"foo\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              null.NewString(\"foo\", true),\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"traces output from env overwritten by CLI\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_TRACES_OUTPUT\": \"foo\"},\n\t\t\tcliFlags:  []string{\"--traces-output\", \"bar\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              null.NewString(\"bar\", true),\n\t\t\t\tSummaryMode:               defaultSummaryMode,\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"summary mode from env\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_SUMMARY_MODE\": \"full\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               null.NewString(\"full\", true),\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t\t\"summary mode from env overwritten by CLI\": {\n\t\t\tuseSysEnv: false,\n\t\t\tsystemEnv: map[string]string{\"K6_SUMMARY_MODE\": \"full\"},\n\t\t\tcliFlags:  []string{\"--summary-mode\", \"legacy\"},\n\t\t\texpRTOpts: lib.RuntimeOptions{\n\t\t\t\tIncludeSystemEnvVars:      null.NewBool(false, false),\n\t\t\t\tCompatibilityMode:         defaultCompatMode,\n\t\t\t\tEnv:                       map[string]string{},\n\t\t\t\tTracesOutput:              defaultTracesOutput,\n\t\t\t\tSummaryMode:               null.NewString(\"legacy\", true),\n\t\t\t\tNewMachineReadableSummary: defaultNewMachineReadableSummary,\n\t\t\t},\n\t\t},\n\t}\n\tfor name, tc := range runtimeOptionsTestCases {\n\t\tt.Run(fmt.Sprintf(\"RuntimeOptions test '%s'\", name), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttestRuntimeOptionsCase(t, tc)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/scale.go",
    "content": "package cmd\n\nimport (\n\t\"errors\"\n\n\t\"github.com/spf13/cobra\"\n\n\tv1 \"go.k6.io/k6/api/v1\"\n\t\"go.k6.io/k6/api/v1/client\"\n\t\"go.k6.io/k6/cmd/state\"\n)\n\nfunc getCmdScale(gs *state.GlobalState) *cobra.Command {\n\t// scaleCmd represents the scale command\n\tscaleCmd := &cobra.Command{\n\t\tUse:    \"scale\",\n\t\tShort:  \"Scale a running test\",\n\t\tHidden: true,\n\t\tLong: `Scale a running test.\n\n  Use the global --address flag to specify the URL to the API server.`,\n\t\tRunE: func(cmd *cobra.Command, _ []string) error {\n\t\t\tvus := getNullInt64(cmd.Flags(), \"vus\")\n\t\t\tmaxVUs := getNullInt64(cmd.Flags(), \"max\")\n\t\t\tif !vus.Valid && !maxVUs.Valid {\n\t\t\t\treturn errors.New(\"Specify either -u/--vus or -m/--max\") //nolint:staticcheck\n\t\t\t}\n\n\t\t\tc, err := client.New(gs.Flags.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tstatus, err := c.SetStatus(gs.Ctx, v1.Status{VUs: vus, VUsMax: maxVUs})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn yamlPrint(gs.Stdout, status)\n\t\t},\n\t}\n\n\tscaleCmd.Flags().Int64P(\"vus\", \"u\", 1, \"number of virtual users\")\n\tscaleCmd.Flags().Int64P(\"max\", \"m\", 0, \"max available virtual users\")\n\n\treturn scaleCmd\n}\n"
  },
  {
    "path": "internal/cmd/stats.go",
    "content": "package cmd\n\nimport (\n\t\"github.com/spf13/cobra\"\n\n\t\"go.k6.io/k6/api/v1/client\"\n\t\"go.k6.io/k6/cmd/state\"\n)\n\nfunc getCmdStats(gs *state.GlobalState) *cobra.Command {\n\t// statsCmd represents the stats command\n\tstatsCmd := &cobra.Command{\n\t\tUse:    \"stats\",\n\t\tShort:  \"Show test metrics\",\n\t\tHidden: true,\n\t\tLong: `Show test metrics.\n\n  Use the global --address flag to specify the URL to the API server.`,\n\t\tRunE: func(_ *cobra.Command, _ []string) error {\n\t\t\tc, err := client.New(gs.Flags.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tmetrics, err := c.Metrics(gs.Ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn yamlPrint(gs.Stdout, metrics)\n\t\t},\n\t}\n\treturn statsCmd\n}\n"
  },
  {
    "path": "internal/cmd/status.go",
    "content": "package cmd\n\nimport (\n\t\"github.com/spf13/cobra\"\n\n\t\"go.k6.io/k6/api/v1/client\"\n\t\"go.k6.io/k6/cmd/state\"\n)\n\nfunc getCmdStatus(gs *state.GlobalState) *cobra.Command {\n\t// statusCmd represents the status command\n\tstatusCmd := &cobra.Command{\n\t\tUse:    \"status\",\n\t\tShort:  \"Show test status\",\n\t\tHidden: true,\n\t\tLong: `Show test status.\n\n  Use the global --address flag to specify the URL to the API server.`,\n\t\tRunE: func(_ *cobra.Command, _ []string) error {\n\t\t\tc, err := client.New(gs.Flags.Address)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tstatus, err := c.Status(gs.Ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn yamlPrint(gs.Stdout, status)\n\t\t},\n\t}\n\treturn statusCmd\n}\n"
  },
  {
    "path": "internal/cmd/stdlog_integration_test.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n)\n\n// SetOutput sets the global log so it is racy with other tests\n//\n//nolint:paralleltest\nfunc TestStdLogOutputIsSet(t *testing.T) {\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tts := tests.NewGlobalTestState(t)\n\t// Sometimes the Go runtime uses the standard log output to\n\t// log some messages directly.\n\t// It does when an invalid char is found in a Cookie.\n\t// Check for details https://github.com/grafana/k6/issues/711#issue-341414887\n\tts.Stdin = bytes.NewReader([]byte(tb.Replacer.Replace(`\nimport http from 'k6/http';\nexport const options = {\n  hosts: {\n    \"HTTPSBIN_DOMAIN\": \"HTTPSBIN_IP\",\n  },\n  insecureSkipTLSVerify: true,\n}\nexport default function() {\n  http.get(\"HTTPSBIN_URL/get\", {\n    \"cookies\": {\n      \"test\": \"\\\"\"\n    },\n  })\n}`)))\n\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-i\", \"1\", \"-\"}\n\tnewRootCommand(ts.GlobalState).execute()\n\n\tentries := ts.LoggerHook.Drain()\n\trequire.Len(t, entries, 1)\n\tassert.Contains(t, entries[0].Message, \"Cookie.Value; dropping invalid bytes\")\n}\n"
  },
  {
    "path": "internal/cmd/subcommand.go",
    "content": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/subcommand\"\n)\n\n// getX creates the \"x\" command that serves as a namespace for extension-provided subcommands.\n//\n// Provisioning Workflow:\n//\n// The \"x\" command implements automatic binary provisioning for extension subcommands. When a user\n// runs a subcommand that isn't available in the current k6 binary, the system automatically builds\n// a custom k6 binary with the required extension.\n//\n// Execution Flow:\n//\n//  1. User runs: k6 x <subcommand> [args...]\n//  2. Cobra attempts to match <subcommand> with registered subcommands:\n//     a. If <subcommand> is registered (exists), Cobra executes it normally\n//     b. If <subcommand> is NOT registered (missing), Cobra falls through to the \"x\" command's RunE\n//  3. The RunE function (catch-all handler):\n//     a. Checks if help is requested (no args, \"help\", or flag starting with \"-\")\n//     b. If help requested, displays the \"x\" command help showing available subcommands\n//     c. Otherwise, extracts the subcommand name from args[0]\n//     d. Calls dependenciesFromSubcommand to construct dependencies with \"subcommand:<name>\" format\n//     e. Returns binaryIsNotSatisfyingDependenciesError with the dependencies\n//  4. Error handling in root.go:\n//     a. handleUnsatisfiedDependencies catches the error\n//     b. Triggers k6build provisioner to build a custom binary with the extension\n//     c. Executes the custom binary with the original arguments (including --help if present)\n//\n// Note: DisableFlagParsing is enabled to pass all arguments (including --help) to the provisioned\n// binary unchanged. This ensures that \"k6 x httpbin --help\" will show httpbin's help after provisioning.\n//\n// The \"x\" command itself (without subcommand) displays help showing all available extension subcommands.\nfunc getX(gs *state.GlobalState) *cobra.Command {\n\tcmd := &cobra.Command{\n\t\tUse:   \"x\",\n\t\tShort: \"Extension subcommands\",\n\t\tLong: `Namespace for extension-provided subcommands.\n\nThis command serves as a parent for subcommands registered by k6 extensions,\nallowing them to extend k6's functionality with custom commands.\n`,\n\t\t// Disable flag parsing to pass all arguments unchanged to the provisioned binary.\n\t\t// This ensures flags like --help reach the extension subcommand after provisioning.\n\t\tDisableFlagParsing: true,\n\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\t// Show help if: no args, explicit \"help\", or starts with a flag\n\t\t\tif len(args) == 0 || args[0] == \"help\" || strings.HasPrefix(args[0], \"-\") {\n\t\t\t\treturn cmd.Help()\n\t\t\t}\n\n\t\t\tif !gs.Flags.AutoExtensionResolution {\n\t\t\t\treturn cobra.NoArgs(cmd, args)\n\t\t\t}\n\n\t\t\t// Subcommand not found - trigger provisioning\n\t\t\tdeps, err := dependenciesFromSubcommand(gs, args[0])\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn binaryIsNotSatisfyingDependenciesError{\n\t\t\t\tdeps: deps,\n\t\t\t}\n\t\t},\n\t}\n\n\tcmd.AddCommand(extensionSubcommands(gs)...)\n\n\treturn cmd\n}\n\n// extensionSubcommands retrieves all subcommands provided by extensions.\nfunc extensionSubcommands(gs *state.GlobalState) []*cobra.Command {\n\textensions := ext.Get(ext.SubcommandExtension)\n\tcommands := make([]*cobra.Command, 0, len(extensions))\n\n\tfor _, extension := range extensions {\n\t\tcommands = append(commands, getCmdForExtension(extension, gs))\n\t}\n\n\treturn commands\n}\n\n// getCmdForExtension gets a *cobra.Command for the given subcommand extension.\nfunc getCmdForExtension(extension *ext.Extension, gs *state.GlobalState) *cobra.Command {\n\tctor, ok := extension.Module.(subcommand.Constructor)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"invalid subcommand constructor: name: %s path: %s\", extension.Name, extension.Path))\n\t}\n\n\tcmd := ctor(gs)\n\n\t// Validate that the command's name matches the extension name.\n\tif cmd.Name() != extension.Name {\n\t\tpanic(fmt.Sprintf(\"subcommand name mismatch: command name: %s extension name: %s\", cmd.Name(), extension.Name))\n\t}\n\n\treturn cmd\n}\n\n// dependenciesFromSubcommand constructs a dependencies object for the given subcommand,\n// potentially using the manifest file specified in the global state.\n//\n// Without a manifest, it returns a dependencies object with a single entry for the subcommand\n// with nil version (indicating any version is acceptable).\n//\n// Dependency name is in the format \"subcommand:<subcommand name>\" to distinguish from\n// other types of dependencies. The builder service can use this information to determine\n// which subcommand is being run and provision the appropriate binary.\nfunc dependenciesFromSubcommand(gs *state.GlobalState, subcommand string) (dependencies, error) {\n\tdeps := dependencies{\n\t\t\"subcommand:\" + subcommand: nil,\n\t}\n\n\tm, err := parseManifest(gs.Flags.DependenciesManifest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = deps.applyManifest(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn deps, nil\n}\n"
  },
  {
    "path": "internal/cmd/subcommand_test.go",
    "content": "package cmd\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/spf13/cobra\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/subcommand\"\n)\n\nfunc TestExtensionSubcommands(t *testing.T) {\n\tt.Parallel()\n\n\tregisterTestSubcommandExtensions(t)\n\n\tt.Run(\"returns all extension subcommands\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := tests.NewGlobalTestState(t)\n\t\tcommands := extensionSubcommands(ts.GlobalState)\n\n\t\t// Should have at least the 3 test extensions we registered\n\t\trequire.GreaterOrEqual(t, len(commands), 2)\n\n\t\t// Check that our test commands are present\n\t\tcommandNames := make(map[string]bool)\n\t\tfor _, cmd := range commands {\n\t\t\tcommandNames[cmd.Name()] = true\n\t\t}\n\n\t\trequire.True(t, commandNames[\"test-cmd-1\"], \"test-cmd-1 should be present\")\n\t\trequire.True(t, commandNames[\"test-cmd-2\"], \"test-cmd-2 should be present\")\n\t\trequire.True(t, commandNames[\"test-cmd-3\"], \"test-cmd-3 should be present\")\n\t})\n\n\tt.Run(\"returns commands with correct properties\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := tests.NewGlobalTestState(t)\n\t\tcommands := extensionSubcommands(ts.GlobalState)\n\n\t\tfor _, cmd := range commands {\n\t\t\trequire.NotEmpty(t, cmd.Use, \"command should have a Use field\")\n\n\t\t\tswitch cmd.Use {\n\t\t\tcase \"test-cmd-1\":\n\t\t\t\trequire.Equal(t, \"Test command 1\", cmd.Short)\n\t\t\tcase \"test-cmd-2\":\n\t\t\t\trequire.Equal(t, \"Test command 2\", cmd.Short)\n\t\t\tcase \"test-cmd-3\":\n\t\t\t\trequire.Equal(t, \"Test command 3\", cmd.Short)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc TestXCommandHelpDisplayCommands(t *testing.T) {\n\tt.Parallel()\n\n\tregisterTestSubcommandExtensions(t)\n\n\ttestCases := []struct {\n\t\tname               string\n\t\twantStdoutContains string\n\t}{\n\t\t{\n\t\t\tname:               \"should have test-cmd-1 command\",\n\t\t\twantStdoutContains: \"  test-cmd-1  Test command 1\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have test-cmd-2 command\",\n\t\t\twantStdoutContains: \"  test-cmd-2  Test command 2\",\n\t\t},\n\t\t{\n\t\t\tname:               \"should have test-cmd-3 command\",\n\t\t\twantStdoutContains: \"  test-cmd-3  Test command 3\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := tests.NewGlobalTestState(t)\n\t\t\tts.CmdArgs = []string{\"k6\", \"x\", \"help\"}\n\t\t\tnewRootCommand(ts.GlobalState).execute()\n\n\t\t\trequire.Contains(t, ts.Stdout.String(), tc.wantStdoutContains)\n\t\t})\n\t}\n}\n\nfunc Test_dependenciesFromSubcommand(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"without manifest\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := tests.NewGlobalTestState(t)\n\t\tdeps, err := dependenciesFromSubcommand(ts.GlobalState, \"test-cmd\")\n\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, deps, \"subcommand:test-cmd\")\n\t\trequire.Nil(t, deps[\"subcommand:test-cmd\"])\n\t})\n\n\tt.Run(\"with manifest\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := tests.NewGlobalTestState(t)\n\n\t\tts.Flags.DependenciesManifest = `{\"subcommand:test-cmd\": \"1.2.3\"}`\n\n\t\tdeps, err := dependenciesFromSubcommand(ts.GlobalState, \"test-cmd\")\n\n\t\trequire.NoError(t, err)\n\t\trequire.Contains(t, deps, \"subcommand:test-cmd\")\n\t\trequire.Equal(t, \"1.2.3\", deps[\"subcommand:test-cmd\"].String())\n\t})\n\n\tt.Run(\"with malformed manifest\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := tests.NewGlobalTestState(t)\n\n\t\tts.Flags.DependenciesManifest = `{subcommand:test-cmd\": \"1.2.3\"}`\n\n\t\tdeps, err := dependenciesFromSubcommand(ts.GlobalState, \"test-cmd\")\n\n\t\trequire.Error(t, err)\n\t\trequire.Nil(t, deps)\n\t})\n}\n\nvar registerTestSubcommandExtensionsOnce sync.Once //nolint:gochecknoglobals\n\nfunc registerTestSubcommandExtensions(t *testing.T) {\n\tt.Helper()\n\n\tregisterTestSubcommandExtensionsOnce.Do(func() {\n\t\tsubcommand.RegisterExtension(\"test-cmd-1\", func(_ *state.GlobalState) *cobra.Command {\n\t\t\treturn &cobra.Command{\n\t\t\t\tUse:   \"test-cmd-1\",\n\t\t\t\tShort: \"Test command 1\",\n\t\t\t\tRun:   func(_ *cobra.Command, _ []string) {},\n\t\t\t}\n\t\t})\n\n\t\tsubcommand.RegisterExtension(\"test-cmd-2\", func(_ *state.GlobalState) *cobra.Command {\n\t\t\treturn &cobra.Command{\n\t\t\t\tUse:   \"test-cmd-2\",\n\t\t\t\tShort: \"Test command 2\",\n\t\t\t\tRun:   func(_ *cobra.Command, _ []string) {},\n\t\t\t}\n\t\t})\n\n\t\tsubcommand.RegisterExtension(\"test-cmd-3\", func(_ *state.GlobalState) *cobra.Command {\n\t\t\treturn &cobra.Command{\n\t\t\t\tUse:   \"test-cmd-3\",\n\t\t\t\tShort: \"Test command 3\",\n\t\t\t\tRun:   func(_ *cobra.Command, _ []string) {},\n\t\t\t}\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "internal/cmd/templates/browser.js",
    "content": "import http from \"k6/http\";\nimport exec from 'k6/execution';\nimport { browser } from \"k6/browser\";\nimport { sleep, check, fail } from 'k6';\n\nconst BASE_URL = __ENV.BASE_URL || \"https://quickpizza.grafana.com\";\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: \"shared-iterations\",\n      vus: 1,\n      iterations: 1,\n      options: {\n        browser: {\n          type: \"chromium\",\n        },\n      },\n    },\n  },{{ if .ProjectID }}\n  cloud: {\n    projectID: {{ .ProjectID }},\n    name: \"{{ .ScriptName }}\",\n  },{{ end }}\n};\n\nexport function setup() {\n  let res = http.get(BASE_URL);\n  if (res.status !== 200) {\n    exec.test.abort(`Got unexpected status code ${res.status} when trying to setup. Exiting.`);\n  }\n}\n\nexport default async function() {\n  let checkData;\n  const page = await browser.newPage();\n\n  try {\n    await page.goto(BASE_URL);\n\n    checkData = await page.locator(\"h1\").textContent();\n    check(page, {\n      header: checkData === \"Looking to break out of your pizza routine?\",\n    });\n\n    await page.locator('//button[. = \"Pizza, Please!\"]').click();\n    await page.waitForTimeout(500);\n\n    await page.screenshot({ path: \"screenshot.png\" });\n\n    checkData = await page.locator(\"div#recommendations\").textContent();\n    check(page, {\n      recommendation: checkData !== \"\",\n    });\n  } catch (error) {\n    fail(`Browser iteration failed: ${error.message}`);\n  } finally {\n    await page.close();\n  }\n\n  sleep(1);\n}\n\n"
  },
  {
    "path": "internal/cmd/templates/minimal.js",
    "content": "import http from 'k6/http';\nimport { sleep, check } from 'k6';\n\nexport const options = {\n  vus: 10,\n  duration: '30s',{{ if .ProjectID }}\n  cloud: {\n    projectID: {{ .ProjectID }},\n    name: \"{{ .ScriptName }}\",\n  },{{ end }}\n};\n\nexport default function() {\n  let res = http.get('https://quickpizza.grafana.com');\n  check(res, { \"status is 200\": (res) => res.status === 200 });\n  sleep(1);\n}\n"
  },
  {
    "path": "internal/cmd/templates/protocol.js",
    "content": "import http from \"k6/http\";\nimport exec from 'k6/execution';\nimport { check, sleep } from \"k6\";\n\nconst BASE_URL = __ENV.BASE_URL || 'https://quickpizza.grafana.com';\n\nexport const options = {\n  stages: [\n    { duration: \"10s\", target: 5 },\n    { duration: \"20s\", target: 10 },\n    { duration: \"1s\", target: 0 },\n  ], \n  thresholds: {\n    http_req_failed: [\"rate<0.01\"],\n    http_req_duration: [\"p(95)<500\", \"p(99)<1000\"],\n  },{{ if .ProjectID }}\n  cloud: {\n    projectID: {{ .ProjectID }},\n    name: \"{{ .ScriptName }}\",\n  },{{ end }}\n};\n\nexport function setup() {\n  let res = http.get(BASE_URL);\n  if (res.status !== 200) {\n    exec.test.abort(`Got unexpected status code ${res.status} when trying to setup. Exiting.`);\n  }\n}\n\nexport default function() {\n  let restrictions = {\n    maxCaloriesPerSlice: 500,\n    mustBeVegetarian: false,\n    excludedIngredients: [\"pepperoni\"],\n    excludedTools: [\"knife\"],\n    maxNumberOfToppings: 6,\n    minNumberOfToppings: 2\n  };\n\n  let res = http.post(BASE_URL + \"/api/pizza\", JSON.stringify(restrictions), {\n    headers: {\n      'Content-Type': 'application/json',\n      'Authorization': 'token abcdef0123456789',\n    },\n  });\n\n  check(res, { \"status is 200\": (res) => res.status === 200 });\n  console.log(res.json().pizza.name + \" (\" + res.json().pizza.ingredients.length + \" ingredients)\");\n  sleep(1);\n}\n"
  },
  {
    "path": "internal/cmd/templates/templates.go",
    "content": "// Package templates provides the templates used by the `k6 new` command\npackage templates\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n//go:embed minimal.js\nvar minimalTemplateContent string\n\n//go:embed protocol.js\nvar protocolTemplateContent string\n\n//go:embed browser.js\nvar browserTemplateContent string\n\n// Constants for template types\n// Template names should not contain path separators to not to be confused with file paths\nconst (\n\tMinimalTemplate  = \"minimal\"\n\tProtocolTemplate = \"protocol\"\n\tBrowserTemplate  = \"browser\"\n)\n\n// TemplateManager manages the pre-parsed templates\ntype TemplateManager struct {\n\tminimalTemplate  *template.Template\n\tprotocolTemplate *template.Template\n\tbrowserTemplate  *template.Template\n\tfs               fsext.Fs\n}\n\n// NewTemplateManager initializes a new TemplateManager with parsed templates\nfunc NewTemplateManager(fs fsext.Fs) (*TemplateManager, error) {\n\tminimalTmpl, err := template.New(MinimalTemplate).Parse(minimalTemplateContent)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse minimal template: %w\", err)\n\t}\n\n\tprotocolTmpl, err := template.New(ProtocolTemplate).Parse(protocolTemplateContent)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse protocol template: %w\", err)\n\t}\n\n\tbrowserTmpl, err := template.New(BrowserTemplate).Parse(browserTemplateContent)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse browser template: %w\", err)\n\t}\n\n\treturn &TemplateManager{\n\t\tminimalTemplate:  minimalTmpl,\n\t\tprotocolTemplate: protocolTmpl,\n\t\tbrowserTemplate:  browserTmpl,\n\t\tfs:               fs,\n\t}, nil\n}\n\n// GetTemplate selects the appropriate template based on the type\nfunc (tm *TemplateManager) GetTemplate(tpl string) (*template.Template, error) {\n\t// First check built-in templates\n\tswitch tpl {\n\tcase MinimalTemplate:\n\t\treturn tm.minimalTemplate, nil\n\tcase ProtocolTemplate:\n\t\treturn tm.protocolTemplate, nil\n\tcase BrowserTemplate:\n\t\treturn tm.browserTemplate, nil\n\t}\n\n\t// Then check if it's a file path\n\tif isFilePath(tpl) {\n\t\ttplPath, err := filepath.Abs(tpl)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get absolute path for template %s: %w\", tpl, err)\n\t\t}\n\n\t\t// Read the template content using the provided filesystem\n\t\tcontent, err := fsext.ReadFile(tm.fs, tplPath)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read template file %s: %w\", tpl, err)\n\t\t}\n\n\t\ttmpl, err := template.New(filepath.Base(tplPath)).Parse(string(content))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse template file %s: %w\", tpl, err)\n\t\t}\n\n\t\treturn tmpl, nil\n\t}\n\n\t// Check if there's a file with this name in current directory\n\texists, err := fsext.Exists(tm.fs, fsext.JoinFilePath(\".\", tpl))\n\tif err == nil && exists {\n\t\treturn nil, fmt.Errorf(\"invalid template type %q, did you mean ./%s?\", tpl, tpl)\n\t}\n\n\treturn nil, fmt.Errorf(\"invalid template type %q\", tpl)\n}\n\n// isFilePath checks if the given string looks like a file path by detecting path separators\n// We assume that built-in template names don't contain path separators\nfunc isFilePath(path string) bool {\n\treturn strings.ContainsRune(path, filepath.Separator) || strings.ContainsRune(path, '/')\n}\n\n// TemplateArgs represents arguments passed to templates\ntype TemplateArgs struct {\n\tScriptName string\n\tProjectID  string\n}\n\n// ExecuteTemplate applies the template with provided arguments and writes to the provided writer\nfunc ExecuteTemplate(w io.Writer, tmpl *template.Template, args TemplateArgs) error {\n\treturn tmpl.Execute(w, args)\n}\n"
  },
  {
    "path": "internal/cmd/test_load.go",
    "content": "package cmd\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"maps\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\n\t\"github.com/Masterminds/semver/v3\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/js\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst (\n\ttestTypeJS      = \"js\"\n\ttestTypeArchive = \"archive\"\n)\n\n// loadedTest contains all of data, details and dependencies of a loaded\n// k6 test, but without any config consolidation.\ntype loadedTest struct {\n\tsourceRootPath string // contains the raw string the user supplied\n\tpwd            string\n\tsource         *loader.SourceData\n\tfs             fsext.Fs\n\tfileSystems    map[string]fsext.Fs\n\tpreInitState   *lib.TestPreInitState\n\tinitRunner     lib.Runner // TODO: rename to something more appropriate\n\tkeyLogger      io.Closer\n\n\tdependencies       dependencies\n\timports            []string\n\trunnerContinuation func() (lib.Runner, error)\n\tdependencyErr      error\n}\n\nfunc loadLocalTestWithoutRunner(gs *state.GlobalState, cmd *cobra.Command, args []string) (*loadedTest, error) {\n\tif len(args) < 1 {\n\t\treturn nil, fmt.Errorf(\"k6 needs at least one argument to load the test\")\n\t}\n\n\tsourceRootPath := args[0]\n\tgs.Logger.Debugf(\"Resolving and reading test '%s'...\", sourceRootPath)\n\tsrc, fileSystems, pwd, err := readSource(gs, sourceRootPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresolvedPath := src.URL.String()\n\tgs.Logger.Debugf(\n\t\t\"'%s' resolved to '%s' and successfully loaded %d bytes!\",\n\t\tsourceRootPath, resolvedPath, len(src.Data),\n\t)\n\n\tgs.Logger.Debugf(\"Gathering k6 runtime options...\")\n\truntimeOptions, err := getRuntimeOptions(cmd.Flags(), gs.Env)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif runtimeOptions.CompatibilityMode.String == lib.CompatibilityModeExperimentalEnhanced.String() {\n\t\tgs.Logger.Warnf(\"CompatibilityMode %[1]q is deprecated. Types are stripped by default for `.ts` files. \"+\n\t\t\t\"Please move to using %[2]q instead as %[1]q will be removed in the future\",\n\t\t\tlib.CompatibilityModeExperimentalEnhanced.String(), lib.CompatibilityModeBase.String())\n\t}\n\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.TestPreInitState{\n\t\tLogger:         gs.Logger,\n\t\tRuntimeOptions: runtimeOptions,\n\t\tRegistry:       registry,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tEvents:         gs.Events,\n\t\tLookupEnv: func(key string) (string, bool) {\n\t\t\tval, ok := gs.Env[key]\n\t\t\treturn val, ok\n\t\t},\n\t\tUsage:          gs.Usage,\n\t\tSecretsManager: gs.SecretsManager,\n\t\tTestStatus:     gs.TestStatus,\n\t}\n\n\ttest := &loadedTest{\n\t\tpwd:            pwd,\n\t\tsourceRootPath: sourceRootPath,\n\t\tsource:         src,\n\t\tfs:             gs.FS,\n\t\tfileSystems:    fileSystems,\n\t\tpreInitState:   state,\n\t}\n\n\tif err := test.prepareFirstRunner(gs); err != nil {\n\t\treturn test, fmt.Errorf(\"could not initialize '%s': %w\", sourceRootPath, err)\n\t}\n\n\treturn test, nil\n}\n\nfunc loadLocalTest(gs *state.GlobalState, cmd *cobra.Command, args []string) (*loadedTest, error) {\n\ttest, err := loadLocalTestWithoutRunner(gs, cmd, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := test.continueInitialization(gs); err != nil {\n\t\treturn nil, fmt.Errorf(\"could not initialize '%s': %w\", test.sourceRootPath, err)\n\t}\n\n\treturn test, nil\n}\n\n//nolint:funlen\nfunc (lt *loadedTest) prepareFirstRunner(gs *state.GlobalState) error {\n\tif lt.initRunner != nil || lt.runnerContinuation != nil {\n\t\treturn nil\n\t}\n\n\ttestPath := lt.source.URL.String()\n\tlogger := gs.Logger.WithField(\"test_path\", testPath)\n\n\ttestType := lt.preInitState.RuntimeOptions.TestType.String\n\tif testType == \"\" {\n\t\tlogger.Debug(\"Detecting test type for...\")\n\t\ttestType = detectTestType(lt.source.Data)\n\t}\n\n\tif lt.preInitState.RuntimeOptions.KeyWriter.Valid {\n\t\tlogger.Warnf(\"SSLKEYLOGFILE was specified, logging TLS connection keys to '%s'...\",\n\t\t\tlt.preInitState.RuntimeOptions.KeyWriter.String)\n\t\tkeylogFilename := lt.preInitState.RuntimeOptions.KeyWriter.String\n\t\t// if path is absolute - no point doing anything\n\t\tif !filepath.IsAbs(keylogFilename) {\n\t\t\t// filepath.Abs could be used but it will get the pwd from `os` package instead of what is in lt.pwd\n\t\t\t// this is against our general approach of not using `os` directly and makes testing harder\n\t\t\tkeylogFilename = filepath.Join(lt.pwd, keylogFilename)\n\t\t}\n\t\tf, err := lt.fs.OpenFile(keylogFilename, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_APPEND, 0o600)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"couldn't get absolute path for keylog file: %w\", err)\n\t\t}\n\t\tlt.keyLogger = f\n\t\tlt.preInitState.KeyLogger = &syncWriter{w: f}\n\t}\n\tswitch testType {\n\tcase testTypeJS:\n\t\tspecifier := lt.source.URL.String()\n\t\tpwd := lt.source.URL.JoinPath(\"../\")\n\t\tlogger.Debug(\"Trying to load as a JS test...\")\n\t\tmoduleResolver := js.NewModuleResolver(pwd, lt.preInitState, lt.fileSystems)\n\t\terr := errext.WithExitCodeIfNone(\n\t\t\tmoduleResolver.LoadMainModule(pwd, specifier, lt.source.Data),\n\t\t\texitcodes.ScriptException)\n\t\tlt.imports = moduleResolver.Imported()\n\t\tdeps, depErr := resolveModulesDependencies(err, lt.imports, logger, lt.fileSystems, lt.source, gs)\n\t\tlt.dependencies = deps\n\t\tif depErr != nil {\n\t\t\treturn fmt.Errorf(\"could not load JS test '%s': %w\", testPath, depErr)\n\t\t}\n\t\tlt.runnerContinuation = func() (lib.Runner, error) {\n\t\t\trunner, err := js.New(lt.preInitState, lt.source, lt.fileSystems, moduleResolver)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"could not load JS test '%s': %w\", testPath, err)\n\t\t\t}\n\t\t\treturn runner, nil\n\t\t}\n\t\treturn nil\n\n\tcase testTypeArchive:\n\t\tlogger.Debug(\"Trying to load test as an archive bundle...\")\n\n\t\tarc, err := lib.ReadArchive(bytes.NewReader(lt.source.Data))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"could not load test archive bundle '%s': %w\", testPath, err)\n\t\t}\n\t\tlogger.Debugf(\"Loaded test as an archive bundle with type '%s'!\", arc.Type)\n\n\t\tswitch arc.Type {\n\t\tcase testTypeJS:\n\t\t\tlogger.Debug(\"Evaluating JS from archive bundle...\")\n\t\t\tspecifier := arc.Filename\n\t\t\tpwd := arc.PwdURL\n\t\t\tmoduleResolver := js.NewModuleResolver(pwd, lt.preInitState, arc.Filesystems)\n\t\t\tloadErr := errext.WithExitCodeIfNone(\n\t\t\t\tmoduleResolver.LoadMainModule(pwd, specifier, arc.Data),\n\t\t\t\texitcodes.ScriptException)\n\t\t\tlt.imports = moduleResolver.Imported()\n\t\t\tdeps, depErr := resolveModulesDependencies(loadErr, lt.imports, logger, arc.Filesystems, lt.source, gs)\n\t\t\tlt.dependencies = deps\n\t\t\tif depErr != nil {\n\t\t\t\treturn fmt.Errorf(\"could not load JS test '%s': %w\", testPath, depErr)\n\t\t\t}\n\t\t\tlt.runnerContinuation = func() (lib.Runner, error) {\n\t\t\t\trunner, err := js.NewFromArchive(lt.preInitState, arc, moduleResolver)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"could not load JS from test archive bundle '%s': %w\", testPath, err)\n\t\t\t\t}\n\t\t\t\treturn runner, nil\n\t\t\t}\n\t\t\treturn nil\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"archive '%s' has an unsupported test type '%s'\", testPath, arc.Type)\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown or unspecified test type '%s' for '%s'\", testType, testPath)\n\t}\n}\n\nfunc (lt *loadedTest) continueInitialization(gs *state.GlobalState) error {\n\tif lt.dependencyErr != nil {\n\t\treturn lt.dependencyErr\n\t}\n\tif lt.runnerContinuation == nil {\n\t\treturn fmt.Errorf(\"runner initialization was not prepared\")\n\t}\n\n\tresolvedPath := lt.source.URL.String()\n\tgs.Logger.Debugf(\"Initializing k6 runner for '%s' (%s)...\", lt.sourceRootPath, resolvedPath)\n\trunner, err := lt.runnerContinuation()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tlt.initRunner = runner\n\tlt.runnerContinuation = nil\n\tgs.Logger.Debug(\"Runner successfully initialized!\")\n\treturn nil\n}\n\nfunc (lt *loadedTest) Dependencies() dependencies {\n\treturn lt.dependencies\n}\n\nfunc (lt *loadedTest) Imports() []string {\n\treturn append([]string(nil), lt.imports...)\n}\n\nfunc resolveModulesDependencies(\n\toriginalError error, imports []string, logger logrus.FieldLogger,\n\tfileSystems map[string]fsext.Fs, source *loader.SourceData, gs *state.GlobalState,\n) (dependencies, error) {\n\tdeps, err := collectTestDependencies(originalError, imports, fileSystems, gs.Flags.DependenciesManifest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !gs.Flags.AutoExtensionResolution {\n\t\treturn deps, originalError\n\t}\n\n\tif len(deps) == 0 {\n\t\treturn deps, nil\n\t}\n\n\tif !isCustomBuildRequired(deps, build.Version, ext.GetAll()) {\n\t\tlogger.\n\t\t\tDebug(\"The current k6 binary already satisfies all the required dependencies,\" +\n\t\t\t\t\" it isn't required to provision a new binary.\")\n\t\treturn deps, nil\n\t}\n\n\tif source.URL.Path == \"/-\" {\n\t\tgs.Stdin = bytes.NewBuffer(source.Data)\n\t}\n\n\treturn deps, binaryIsNotSatisfyingDependenciesError{\n\t\tdeps: deps,\n\t}\n}\n\nfunc collectTestDependencies(\n\toriginalError error, imports []string, fileSystems map[string]fsext.Fs, manifest string,\n) (dependencies, error) {\n\tdeps, err := extractUnknownModules(originalError)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Ensure k6 is always a dependency with \"*\" constraint by default.\n\t// This can be overridden by \"use k6\" or \"use k6 with k6/x/...\" directives in the script.\n\tif _, ok := deps[\"k6\"]; !ok {\n\t\tdeps[\"k6\"] = nil\n\t}\n\n\tif err := analyseUseContraints(imports, fileSystems, deps); err != nil {\n\t\treturn nil, err\n\t}\n\n\tm, err := parseManifest(manifest)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = deps.applyManifest(m)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn deps, nil\n}\n\nfunc analyseUseContraints(imports []string, fileSystems map[string]fsext.Fs, deps dependencies) error {\n\tfor _, imported := range imports {\n\t\tif strings.HasPrefix(imported, \"k6\") {\n\t\t\tcontinue\n\t\t}\n\t\tu, err := url.Parse(imported)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// We always have URLs here with scheme and everything\n\t\t_, path, _ := strings.Cut(imported, \"://\")\n\t\tif u.Scheme == \"https\" {\n\t\t\tpath = \"/\" + path\n\t\t}\n\t\tpath, err = url.PathUnescape(filepath.FromSlash(path))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tdata, err := fsext.ReadFile(fileSystems[u.Scheme], path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\terr = processUseDirectives(imported, data, deps)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\ntype dependencies map[string]*semver.Constraints\n\nfunc (d dependencies) update(dep string, constraint *semver.Constraints) error {\n\t// TODO: We could actually do constraint comparison here and get the more specific one\n\toldConstraint, ok := d[dep]\n\tif !ok || oldConstraint == nil || oldConstraint.String() == \"*\" { // either nothing or it didn't have constraint\n\t\td[dep] = constraint\n\t\treturn nil\n\t}\n\tif constraint == oldConstraint || constraint == nil {\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"already have constraint for %q, when parsing %q\", dep, constraint)\n}\n\nfunc (d dependencies) applyManifest(manifest dependencies) error {\n\tfor m, k := range d {\n\t\tif k != nil && k.String() != \"*\" { // if there is constraint skip it\n\t\t\tcontinue\n\t\t}\n\t\tc, ok := manifest[m]\n\t\tif !ok { // skip anything not in the manifest\n\t\t\tcontinue\n\t\t}\n\t\terr := d.update(m, c)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (d dependencies) String() string {\n\tvar buf bytes.Buffer\n\n\tfor idx, depName := range slices.Sorted(maps.Keys(d)) {\n\t\tif idx > 0 {\n\t\t\t_ = buf.WriteByte(';')\n\t\t}\n\n\t\tbuf.WriteString(depName)\n\t\tconstraint := d[depName]\n\t\tif constraint != nil {\n\t\t\tbuf.WriteString(constraint.String())\n\t\t}\n\t}\n\treturn buf.String()\n}\n\nfunc dependenciesFromMap(input map[string]string) (dependencies, error) {\n\tresult := make(dependencies)\n\tfor k, v := range input {\n\t\tif len(v) == 0 {\n\t\t\tresult[k] = nil\n\t\t\tcontinue\n\t\t}\n\t\tcon, err := semver.NewConstraint(v)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult[k] = con\n\t}\n\treturn result, nil\n}\n\nfunc extractUnknownModules(err error) (dependencies, error) {\n\tdeps := make(dependencies)\n\tif err == nil {\n\t\treturn deps, nil\n\t}\n\n\tvar u modules.UnknownModulesError\n\n\tif errors.As(err, &u) {\n\t\tfor _, name := range u.List() {\n\t\t\tdeps[name] = nil\n\t\t}\n\t\treturn deps, nil\n\t}\n\n\treturn nil, err\n}\n\n// TODO(@mstoykov) potentially figure out some less \"exceptionl workflow\" solution\ntype binaryIsNotSatisfyingDependenciesError struct {\n\tdeps dependencies\n}\n\nfunc (r binaryIsNotSatisfyingDependenciesError) Error() string {\n\treturn fmt.Sprintf(\"binary does not satisfy dependencies %q\", r.deps)\n}\n\n// readSource is a small wrapper around loader.ReadSource returning\n// result of the load and filesystems map\nfunc readSource(gs *state.GlobalState, filename string) (*loader.SourceData, map[string]fsext.Fs, string, error) {\n\tpwd, err := gs.Getwd()\n\tif err != nil {\n\t\treturn nil, nil, \"\", err\n\t}\n\n\tfilesystems := loader.CreateFilesystems(gs.FS)\n\tsrc, err := loader.ReadSource(gs.Logger, filename, pwd, filesystems, gs.Stdin)\n\treturn src, filesystems, pwd, err\n}\n\nfunc detectTestType(data []byte) string {\n\tif _, err := tar.NewReader(bytes.NewReader(data)).Next(); err == nil {\n\t\treturn testTypeArchive\n\t}\n\treturn testTypeJS\n}\n\nfunc (lt *loadedTest) consolidateDeriveAndValidateConfig(\n\tgs *state.GlobalState, cmd *cobra.Command,\n\tcliConfGetter func(flags *pflag.FlagSet) (Config, error), // TODO: obviate\n) (*loadedAndConfiguredTest, error) {\n\tvar cliConfig Config\n\tif cliConfGetter != nil {\n\t\tgs.Logger.Debug(\"Parsing CLI flags...\")\n\t\tvar err error\n\t\tcliConfig, err = cliConfGetter(cmd.Flags())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tgs.Logger.Debug(\"Consolidating config layers...\")\n\tconsolidatedConfig, err := getConsolidatedConfig(gs, cliConfig, lt.initRunner.GetOptions())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgs.Logger.Debug(\"Parsing thresholds and validating config...\")\n\t// Parse the thresholds, only if the --no-threshold flag is not set.\n\t// If parsing the threshold expressions failed, consider it as an\n\t// invalid configuration error.\n\tif !lt.preInitState.RuntimeOptions.NoThresholds.Bool {\n\t\tfor metricName, thresholdsDefinition := range consolidatedConfig.Thresholds {\n\t\t\terr = thresholdsDefinition.Parse()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)\n\t\t\t}\n\n\t\t\terr = thresholdsDefinition.Validate(metricName, lt.preInitState.Registry)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)\n\t\t\t}\n\t\t}\n\t}\n\n\tderivedConfig, err := deriveAndValidateConfig(consolidatedConfig, lt.initRunner.IsExecutable, gs.Logger)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &loadedAndConfiguredTest{\n\t\tloadedTest:         lt,\n\t\tconsolidatedConfig: consolidatedConfig,\n\t\tderivedConfig:      derivedConfig,\n\t}, nil\n}\n\n// loadedAndConfiguredTest contains the whole loadedTest, as well as the\n// consolidated test config and the full test run state.\ntype loadedAndConfiguredTest struct {\n\t*loadedTest\n\tconsolidatedConfig Config\n\tderivedConfig      Config\n}\n\nfunc loadAndConfigureLocalTest(\n\tgs *state.GlobalState, cmd *cobra.Command, args []string,\n\tcliConfigGetter func(flags *pflag.FlagSet) (Config, error),\n) (*loadedAndConfiguredTest, error) {\n\ttest, err := loadLocalTest(gs, cmd, args)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn test.consolidateDeriveAndValidateConfig(gs, cmd, cliConfigGetter)\n}\n\n// loadSystemCertPool attempts to load system certificates.\nfunc loadSystemCertPool(logger logrus.FieldLogger) {\n\tif _, err := x509.SystemCertPool(); err != nil {\n\t\tlogger.WithError(err).Warning(\"Unable to load system cert pool\")\n\t}\n}\n\nfunc (lct *loadedAndConfiguredTest) buildTestRunState(\n\tconfigToReinject lib.Options,\n) (*lib.TestRunState, error) {\n\t// This might be the full derived or just the consolidated options\n\tif err := lct.initRunner.SetOptions(configToReinject); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Here, where we get the consolidated options, is where we check if any\n\t// of the deprecated options is being used, and we report it.\n\tif _, isPresent := configToReinject.External[\"loadimpact\"]; isPresent {\n\t\tif err := lct.preInitState.Usage.Uint64(\"deprecations/options.ext.loadimpact\", 1); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// it pre-loads system certificates to avoid doing it on the first TLS request.\n\t// This is done async to avoid blocking the rest of the loading process as it will not stop if it fails.\n\tgo loadSystemCertPool(lct.preInitState.Logger)\n\n\treturn &lib.TestRunState{\n\t\tTestPreInitState: lct.preInitState,\n\t\tRunner:           lct.initRunner,\n\t\tOptions:          lct.derivedConfig.Options, // we will always run with the derived options\n\t\tRunTags:          lct.preInitState.Registry.RootTagSet().WithTagsFromMap(configToReinject.RunTags),\n\t\tGroupSummary:     lib.NewGroupSummary(lct.preInitState.Logger),\n\t}, nil\n}\n\ntype syncWriter struct {\n\tw io.Writer\n\tm sync.Mutex\n}\n\nfunc (cw *syncWriter) Write(b []byte) (int, error) {\n\tcw.m.Lock()\n\tdefer cw.m.Unlock()\n\treturn cw.w.Write(b)\n}\n"
  },
  {
    "path": "internal/cmd/test_load_test.go",
    "content": "package cmd\n\nimport (\n\t\"testing\"\n\n\t\"github.com/Masterminds/semver/v3\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nconst (\n\tfakerJs = `\nimport { Faker } from \"k6/x/faker\";\n\nconst faker = new Faker(11);\n\nexport default function () {\n  console.log(faker.person.firstName());\n}\n`\n\n\tscriptJS = `\n\"use k6 with k6/x/faker > 0.4.0\";\nimport faker from \"./faker.js\";\n\nexport default () => {\n  faker();\n};\n`\n)\n\nfunc TestAnalyseUseConstraints(t *testing.T) {\n\tt.Parallel()\n\n\tfs := testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\"/script.js\": []byte(scriptJS),\n\t\t\"/faker.js\":  []byte(fakerJs),\n\t})\n\tdeps := make(map[string]*semver.Constraints)\n\n\terr := analyseUseContraints([]string{\"file:///script.js\", \"file:///faker.js\"}, map[string]fsext.Fs{\"file\": fs}, deps)\n\n\trequire.NoError(t, err)\n\trequire.Len(t, deps, 1)\n\trequire.Equal(t, deps[\"k6/x/faker\"].String(), \">0.4.0\")\n}\n"
  },
  {
    "path": "internal/cmd/testdata/abort.js",
    "content": "import exec from 'k6/execution';\n\nexport default function () {\n    exec.test.abort();\n}\n"
  },
  {
    "path": "internal/cmd/testdata/abort_initerr.js",
    "content": "import exec from 'k6/execution';\nexec.test.abort();\n"
  },
  {
    "path": "internal/cmd/testdata/abort_initvu.js",
    "content": "import exec from 'k6/execution';\n\n// This won't fail on initial parsing of the script, but on VU initialization.\nif (__VU == 1) {\n  exec.test.abort();\n}\n\nexport default function() {}\n"
  },
  {
    "path": "internal/cmd/testdata/abort_teardown.js",
    "content": "import exec from 'k6/execution';\n\nexport default function () {\n    exec.test.abort();\n}\n\nexport function teardown() {\n    console.log('Calling teardown function after test.abort()');\n}\n"
  },
  {
    "path": "internal/cmd/testdata/example.har",
    "content": "{\n  \"log\": {\n    \"version\": \"1.2\",\n    \"creator\": {\n      \"name\": \"BrowserMob Proxy\",\n      \"version\": \"2.1.6\",\n      \"comment\": \"\"\n    },\n    \"pages\": [{\n      \"id\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:05.981Z\",\n      \"title\": \"Page 0 ţ€$ţɨɲǥ µɲɨȼ๏ď€ ɨɲ Ќ6 \\\" \\u0000\\n\\t♥\\u2028\",\n      \"pageTimings\": {\n        \"onLoad\": 32028,\n        \"comment\": \"\"\n      },\n      \"comment\": \"\"\n    }],\n    \"entries\": [{\n      \"pageref\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:14.325Z\",\n      \"request\": {\n        \"method\": \"POST\",\n        \"url\": \"https://some-host.example.com/checkout/v3/orders\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Authorization\",\n          \"value\": \"Basic stuffz\"\n        }, {\n          \"name\": \"User-Agent\",\n          \"value\": \"SysTest - perf\"\n        }, {\n          \"name\": \"Accept\",\n          \"value\": \"application/json; charset=utf-8\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/json\"\n        }, {\n          \"name\": \"Accept-Encoding\",\n          \"value\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\"\n        }, {\n          \"name\": \"Host\",\n          \"value\": \"some-host.example.com\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"2042\"\n        }],\n        \"queryString\": [],\n        \"postData\": {\n          \"mimeType\": \"application/json\",\n          \"text\": \"{\\\"purchase_currency\\\":\\\"SEK\\\",\\\"purchase_country\\\":\\\"se\\\",\\\"locale\\\":\\\"sv-SE\\\",\\\"merchant_urls\\\":{\\\"terms\\\":\\\"https://some-fourth-host.example.com/v1/redirect/terms\\\",\\\"checkout\\\":\\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\\"confirmation\\\":\\\"https://some-fourth-host.example.com/v1/redirect/confirm\\\",\\\"push\\\":\\\"https://some-fourth-host.example.com/v1/callback/push/{checkout.order.id}?merchant_id=smi-merchant-all-validation\\\\u0026env=perf\\\"},\\\"options\\\":{},\\\"order_lines\\\":[{\\\"reference\\\":\\\"jkwedq9f6t\\\",\\\"name\\\":\\\"Mediokra Betong Lampa. Tangentbord\\\",\\\"type\\\":\\\"physical\\\",\\\"quantity\\\":1,\\\"quantity_unit\\\":\\\"kg\\\",\\\"unit_price\\\":16278,\\\"tax_rate\\\":800,\\\"total_amount\\\":16278,\\\"total_discount_amount\\\":0,\\\"total_tax_amount\\\":1206,\\\"product_url\\\":\\\"http://aufderharluettgen.info/haven\\\",\\\"image_url\\\":\\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"}],\\\"order_amount\\\":16278,\\\"order_tax_amount\\\":1206,\\\"shipping_countries\\\":[\\\"AD\\\",\\\"AE\\\",\\\"AG\\\",\\\"AI\\\",\\\"AL\\\",\\\"AM\\\",\\\"AQ\\\",\\\"AR\\\",\\\"AS\\\",\\\"AT\\\",\\\"AU\\\",\\\"AW\\\",\\\"AX\\\",\\\"AZ\\\",\\\"BB\\\",\\\"BD\\\",\\\"BE\\\",\\\"BF\\\",\\\"BG\\\",\\\"BH\\\",\\\"BJ\\\",\\\"BL\\\",\\\"BM\\\",\\\"BN\\\",\\\"BO\\\",\\\"BQ\\\",\\\"BR\\\",\\\"BS\\\",\\\"BT\\\",\\\"BV\\\",\\\"BW\\\",\\\"BZ\\\",\\\"CA\\\",\\\"CC\\\",\\\"CH\\\",\\\"CK\\\",\\\"CL\\\",\\\"CM\\\",\\\"CO\\\",\\\"CR\\\",\\\"CU\\\",\\\"CV\\\",\\\"CW\\\",\\\"CX\\\",\\\"CY\\\",\\\"CZ\\\",\\\"DE\\\",\\\"DJ\\\",\\\"DK\\\",\\\"DM\\\",\\\"DO\\\",\\\"DZ\\\",\\\"EC\\\",\\\"EE\\\",\\\"EH\\\",\\\"ES\\\",\\\"ET\\\",\\\"FI\\\",\\\"FJ\\\",\\\"FK\\\",\\\"FM\\\",\\\"FO\\\",\\\"FR\\\",\\\"GA\\\",\\\"GB\\\",\\\"GD\\\",\\\"GE\\\",\\\"GF\\\",\\\"GG\\\",\\\"GH\\\",\\\"GI\\\",\\\"GL\\\",\\\"GM\\\",\\\"GP\\\",\\\"GQ\\\",\\\"GR\\\",\\\"GS\\\",\\\"GT\\\",\\\"GU\\\",\\\"HK\\\",\\\"HM\\\",\\\"HN\\\",\\\"HR\\\",\\\"HU\\\",\\\"ID\\\",\\\"IE\\\",\\\"IL\\\",\\\"IM\\\",\\\"IN\\\",\\\"IO\\\",\\\"IS\\\",\\\"IT\\\",\\\"JE\\\",\\\"JM\\\",\\\"JO\\\",\\\"JP\\\",\\\"KE\\\",\\\"KG\\\",\\\"KH\\\",\\\"KI\\\",\\\"KM\\\",\\\"KN\\\",\\\"KR\\\",\\\"KW\\\",\\\"KY\\\",\\\"KZ\\\",\\\"LC\\\",\\\"LI\\\",\\\"LK\\\",\\\"LS\\\",\\\"LT\\\",\\\"LU\\\",\\\"LV\\\",\\\"MA\\\",\\\"MC\\\",\\\"ME\\\",\\\"MF\\\",\\\"MG\\\",\\\"MH\\\",\\\"MK\\\",\\\"ML\\\",\\\"MN\\\",\\\"MO\\\",\\\"MP\\\",\\\"MQ\\\",\\\"MR\\\",\\\"MS\\\",\\\"MT\\\",\\\"MU\\\",\\\"MV\\\",\\\"MW\\\",\\\"MX\\\",\\\"MY\\\",\\\"MZ\\\",\\\"NA\\\",\\\"NC\\\",\\\"NE\\\",\\\"NF\\\",\\\"NG\\\",\\\"NI\\\",\\\"NL\\\",\\\"NO\\\",\\\"NP\\\",\\\"NR\\\",\\\"NU\\\",\\\"NZ\\\",\\\"OM\\\",\\\"PA\\\",\\\"PE\\\",\\\"PF\\\",\\\"PH\\\",\\\"PK\\\",\\\"PL\\\",\\\"PM\\\",\\\"PN\\\",\\\"PR\\\",\\\"PS\\\",\\\"PT\\\",\\\"PW\\\",\\\"PY\\\",\\\"QA\\\",\\\"RE\\\",\\\"RO\\\",\\\"RW\\\",\\\"SA\\\",\\\"SB\\\",\\\"SC\\\",\\\"SE\\\",\\\"SG\\\",\\\"SH\\\",\\\"SI\\\",\\\"SJ\\\",\\\"SK\\\",\\\"SL\\\",\\\"SM\\\",\\\"SN\\\",\\\"SR\\\",\\\"ST\\\",\\\"SV\\\",\\\"SX\\\",\\\"SZ\\\",\\\"TC\\\",\\\"TD\\\",\\\"TF\\\",\\\"TG\\\",\\\"TH\\\",\\\"TJ\\\",\\\"TK\\\",\\\"TL\\\",\\\"TM\\\",\\\"TO\\\",\\\"TR\\\",\\\"TT\\\",\\\"TV\\\",\\\"TW\\\",\\\"TZ\\\",\\\"UM\\\",\\\"US\\\",\\\"UY\\\",\\\"UZ\\\",\\\"VA\\\",\\\"VC\\\",\\\"VE\\\",\\\"VG\\\",\\\"VI\\\",\\\"VN\\\",\\\"WF\\\",\\\"WS\\\",\\\"YT\\\",\\\"ZA\\\",\\\"ZM\\\"]}\",\n          \"comment\": \"\"\n        },\n        \"headersSize\": 365,\n        \"bodySize\": 2042,\n        \"comment\": \"\"\n      },\n      \"response\": {\n        \"status\": 201,\n        \"statusText\": \"Created\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Cache-Control\",\n          \"value\": \"max-age=0, no-cache, no-store\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/json\"\n        }, {\n          \"name\": \"Date\",\n          \"value\": \"Mon, 19 Feb 2018 11:40:07 GMT\"\n        }, {\n          \"name\": \"Correlation-Id\",\n          \"value\": \"ff8b3cca-0477-40cf-9a80-0558f54509f6\"\n        }, {\n          \"name\": \"Location\",\n          \"value\": \"https://some-host.example.com/checkout/v3/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\"\n        }, {\n          \"name\": \"Pragma\",\n          \"value\": \"no-cache\"\n        }, {\n          \"name\": \"Render-Time\",\n          \"value\": \"1310\"\n        }, {\n          \"name\": \"Server\",\n          \"value\": \"openresty\"\n        }, {\n          \"name\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"6840\"\n        }, {\n          \"name\": \"Connection\",\n          \"value\": \"keep-alive\"\n        }],\n        \"content\": {\n          \"size\": 6840,\n          \"mimeType\": \"application/json\",\n          \"text\": \"{\\n  \\\"order_id\\\" : \\\"570714bf-3c2b-452e-90cd-f7c5e552bb25\\\",\\n  \\\"status\\\" : \\\"checkout_incomplete\\\",\\n  \\\"purchase_country\\\" : \\\"se\\\",\\n  \\\"purchase_currency\\\" : \\\"SEK\\\",\\n  \\\"locale\\\" : \\\"sv-SE\\\",\\n  \\\"billing_address\\\" : {\\n    \\\"country\\\" : \\\"se\\\"\\n  },\\n  \\\"customer\\\" : { },\\n  \\\"shipping_address\\\" : {\\n    \\\"country\\\" : \\\"se\\\"\\n  },\\n  \\\"order_amount\\\" : 16278,\\n  \\\"order_tax_amount\\\" : 1206,\\n  \\\"order_lines\\\" : [ {\\n    \\\"type\\\" : \\\"physical\\\",\\n    \\\"reference\\\" : \\\"jkwedq9f6t\\\",\\n    \\\"name\\\" : \\\"Mediokra Betong Lampa. Tangentbord\\\",\\n    \\\"quantity\\\" : 1,\\n    \\\"quantity_unit\\\" : \\\"kg\\\",\\n    \\\"unit_price\\\" : 16278,\\n    \\\"tax_rate\\\" : 800,\\n    \\\"total_amount\\\" : 16278,\\n    \\\"total_discount_amount\\\" : 0,\\n    \\\"total_tax_amount\\\" : 1206,\\n    \\\"product_url\\\" : \\\"http://aufderharluettgen.info/haven\\\",\\n    \\\"image_url\\\" : \\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"\\n  } ],\\n  \\\"merchant_urls\\\" : {\\n    \\\"terms\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/terms\\\",\\n    \\\"checkout\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\n    \\\"confirmation\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/confirm\\\",\\n    \\\"push\\\" : \\\"https://some-fourth-host.example.com/v1/callback/push/{checkout.order.id}?merchant_id=smi-merchant-all-validation&env=perf\\\"\\n  },\\n  \\\"html_snippet\\\" : \\\"<div id=\\\\\\\"container\\\\\\\" style=\\\\\\\"overflow-x: hidden;\\\\\\\">\\\\n  <div id=\\\\\\\"unsupported-page\\\\\\\">\\\\n  <style type=\\\\\\\"text/css\\\\\\\">\\\\n  @-webkit-keyframes FadeIn{from{opacity:0}to{opacity:1}}@-moz-keyframes FadeIn{from{opacity:0}to{opacity:1}}@keyframes FadeIn{from{opacity:0}to{opacity:1}}#unsupported-page{opacity:0;opacity:1\\\\\\\\9;-webkit-animation:FadeIn ease-in 1;-moz-animation:FadeIn ease-in 1;animation:FadeIn ease-in 1;-webkit-animation-fill-mode:forwards;-moz-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-duration:.1s;-moz-animation-duration:.1s;animation-duration:.1s;-webkit-animation-delay:5s;-moz-animation-delay:5s;animation-delay:5s;text-align:center;padding-top:64px}#unsupported-page .heading{font-family:Source Sans Pro,Helvetica,Arial,sans-serif;line-height:48px;font-weight:200;color:#303030;font-size:42px;margin:24px 0}#unsupported-page .subheading{font-family:Source Sans Pro,Helvetica,Arial,sans-serif;line-height:28px;font-weight:400;color:rgba(0,0,0,.7);font-size:19px;max-width:560px;margin:10px auto}#unsupported-page .subheading a{text-decoration:none;background-color:transparent;border:0;color:rgba(0,0,0,.7);font-weight:600}\\\\n  </style>\\\\n  <h1 class=\\\\\\\"heading\\\\\\\">Oops.</h1>\\\\n  <p class=\\\\\\\"subheading\\\\\\\">It seems you might be using an older web browser which is not safe nor compatible with modern web sites. For a smoother checkout experience, please install a <a href=\\\\\\\"http://outdatedbrowser.com/en\\\\\\\" target=\\\\\\\"_blank\\\\\\\">newer browser</a>.</p>\\\\n  <p class=\\\\\\\"subheading\\\\\\\">Sorry for any inconvenience. For any questions, please contact customer service at <a href=\\\\\\\"https://www.example.com\\\\\\\">Example.com</a>.</p>\\\\n  </div>\\\\n  <script type=\\\\\\\"text/javascript\\\\\\\">\\\\n  /* <![CDATA[ */\\\\n  (function(w,k,i,d,n,c,l){\\\\n    w[k]=w[k]||function(){(w[k].q=w[k].q||[]).push(arguments)};\\\\n    l=w[k].config={\\\\n      container:w.document.getElementById(i),\\\\n      ORDER_URL:'https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25',\\\\n      AUTH_HEADER:'Checkout otherStuffz',\\\\n      LAYOUT:'desktop',\\\\n      LOCALE:'sv-SE',\\\\n      ORDER_STATUS:'checkout_incomplete',\\\\n      MERCHANT_TAC_URI:'https://some-fourth-host.example.com/v1/redirect/terms',\\\\n      MERCHANT_TAC_TITLE:'SMI Merchant All Validation',\\\\n      MERCHANT_NAME:'SMI Merchant All Validation',\\\\n      MERCHANT_COLOR:'',\\\\n      GUI_OPTIONS:[],\\\\n      ALLOW_SEPARATE_SHIPPING_ADDRESS:false,\\\\n      PURCHASE_COUNTRY:'swe',\\\\n      PURCHASE_CURRENCY:'SEK',\\\\n      DISALLOW_SKIP_NIN:false,\\\\n      ANALYTICS:'UA-36053137-1',\\\\n      TESTDRIVE:false,\\\\n      CHECKOUT_DOMAIN:'https://some-other-host.example.com',\\\\n      ASSETS_DOMAIN:'https://checkout.cdn.example.com',\\\\n      BOOTSTRAP_SRC:'https://checkout2.cdn.example.com/180218-4e2ae24/checkout.bootstrap.js',\\\\n      PREFILLED:false,\\\\n      DEVICE_RECOGNITION_URL:'https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/device_recognition',\\\\n      CLIENT_EVENT_HOST:'https://really-just-a-fifth-host.example.com',\\\\n      NEW_CONFIRMATION_PAGE: 'false'\\\\n    };\\\\n    n=d.createElement('script');\\\\n    c=d.getElementById(i);\\\\n    n.async=!0;\\\\n    n.src=l.BOOTSTRAP_SRC;\\\\n    c.appendChild(n);\\\\n    try{\\\\n      ((w.Image && (new w.Image))||(d.createElement && d.createElement('img'))||{}).src =\\\\n        l.CLIENT_EVENT_HOST + '/v1/checkout/snippet/load' +\\\\n        '?sid=' + l.ORDER_URL.split('/').slice(-1) +\\\\n        '&order_status=' + w.encodeURIComponent(l.ORDER_STATUS) +\\\\n        '&timestamp=' + (new Date).getTime();\\\\n    }catch(e){}\\\\n  })(this,'_Checkout','container',document);\\\\n  /* ]]> */\\\\n  </script>\\\\n      \\\\n  <noscript>\\\\nPlease <a href=\\\\\\\"http://enable-javascript.com\\\\\\\">enable JavaScript</a>.\\\\n  </noscript>\\\\n</div>\\\",\\n  \\\"started_at\\\" : \\\"2018-02-19T11:40:06Z\\\",\\n  \\\"last_modified_at\\\" : \\\"2018-02-19T11:40:06Z\\\",\\n  \\\"options\\\" : {\\n    \\\"allow_separate_shipping_address\\\" : false,\\n    \\\"date_of_birth_mandatory\\\" : false,\\n    \\\"require_validate_callback_success\\\" : false\\n  },\\n  \\\"external_payment_methods\\\" : [ ],\\n  \\\"external_checkouts\\\" : [ ],\\n  \\\"shipping_countries\\\" : [ \\\"AD\\\", \\\"AE\\\", \\\"AG\\\", \\\"AI\\\", \\\"AL\\\", \\\"AM\\\", \\\"AQ\\\", \\\"AR\\\", \\\"AS\\\", \\\"AT\\\", \\\"AU\\\", \\\"AW\\\", \\\"AX\\\", \\\"AZ\\\", \\\"BB\\\", \\\"BD\\\", \\\"BE\\\", \\\"BF\\\", \\\"BG\\\", \\\"BH\\\", \\\"BJ\\\", \\\"BL\\\", \\\"BM\\\", \\\"BN\\\", \\\"BO\\\", \\\"BQ\\\", \\\"BR\\\", \\\"BS\\\", \\\"BT\\\", \\\"BV\\\", \\\"BW\\\", \\\"BZ\\\", \\\"CA\\\", \\\"CC\\\", \\\"CH\\\", \\\"CK\\\", \\\"CL\\\", \\\"CM\\\", \\\"CO\\\", \\\"CR\\\", \\\"CU\\\", \\\"CV\\\", \\\"CW\\\", \\\"CX\\\", \\\"CY\\\", \\\"CZ\\\", \\\"DE\\\", \\\"DJ\\\", \\\"DK\\\", \\\"DM\\\", \\\"DO\\\", \\\"DZ\\\", \\\"EC\\\", \\\"EE\\\", \\\"EH\\\", \\\"ES\\\", \\\"ET\\\", \\\"FI\\\", \\\"FJ\\\", \\\"FK\\\", \\\"FM\\\", \\\"FO\\\", \\\"FR\\\", \\\"GA\\\", \\\"GB\\\", \\\"GD\\\", \\\"GE\\\", \\\"GF\\\", \\\"GG\\\", \\\"GH\\\", \\\"GI\\\", \\\"GL\\\", \\\"GM\\\", \\\"GP\\\", \\\"GQ\\\", \\\"GR\\\", \\\"GS\\\", \\\"GT\\\", \\\"GU\\\", \\\"HK\\\", \\\"HM\\\", \\\"HN\\\", \\\"HR\\\", \\\"HU\\\", \\\"ID\\\", \\\"IE\\\", \\\"IL\\\", \\\"IM\\\", \\\"IN\\\", \\\"IO\\\", \\\"IS\\\", \\\"IT\\\", \\\"JE\\\", \\\"JM\\\", \\\"JO\\\", \\\"JP\\\", \\\"KE\\\", \\\"KG\\\", \\\"KH\\\", \\\"KI\\\", \\\"KM\\\", \\\"KN\\\", \\\"KR\\\", \\\"KW\\\", \\\"KY\\\", \\\"KZ\\\", \\\"LC\\\", \\\"LI\\\", \\\"LK\\\", \\\"LS\\\", \\\"LT\\\", \\\"LU\\\", \\\"LV\\\", \\\"MA\\\", \\\"MC\\\", \\\"ME\\\", \\\"MF\\\", \\\"MG\\\", \\\"MH\\\", \\\"MK\\\", \\\"ML\\\", \\\"MN\\\", \\\"MO\\\", \\\"MP\\\", \\\"MQ\\\", \\\"MR\\\", \\\"MS\\\", \\\"MT\\\", \\\"MU\\\", \\\"MV\\\", \\\"MW\\\", \\\"MX\\\", \\\"MY\\\", \\\"MZ\\\", \\\"NA\\\", \\\"NC\\\", \\\"NE\\\", \\\"NF\\\", \\\"NG\\\", \\\"NI\\\", \\\"NL\\\", \\\"NO\\\", \\\"NP\\\", \\\"NR\\\", \\\"NU\\\", \\\"NZ\\\", \\\"OM\\\", \\\"PA\\\", \\\"PE\\\", \\\"PF\\\", \\\"PH\\\", \\\"PK\\\", \\\"PL\\\", \\\"PM\\\", \\\"PN\\\", \\\"PR\\\", \\\"PS\\\", \\\"PT\\\", \\\"PW\\\", \\\"PY\\\", \\\"QA\\\", \\\"RE\\\", \\\"RO\\\", \\\"RW\\\", \\\"SA\\\", \\\"SB\\\", \\\"SC\\\", \\\"SE\\\", \\\"SG\\\", \\\"SH\\\", \\\"SI\\\", \\\"SJ\\\", \\\"SK\\\", \\\"SL\\\", \\\"SM\\\", \\\"SN\\\", \\\"SR\\\", \\\"ST\\\", \\\"SV\\\", \\\"SX\\\", \\\"SZ\\\", \\\"TC\\\", \\\"TD\\\", \\\"TF\\\", \\\"TG\\\", \\\"TH\\\", \\\"TJ\\\", \\\"TK\\\", \\\"TL\\\", \\\"TM\\\", \\\"TO\\\", \\\"TR\\\", \\\"TT\\\", \\\"TV\\\", \\\"TW\\\", \\\"TZ\\\", \\\"UM\\\", \\\"US\\\", \\\"UY\\\", \\\"UZ\\\", \\\"VA\\\", \\\"VC\\\", \\\"VE\\\", \\\"VG\\\", \\\"VI\\\", \\\"VN\\\", \\\"WF\\\", \\\"WS\\\", \\\"YT\\\", \\\"ZA\\\", \\\"ZM\\\" ]\\n}\",\n          \"comment\": \"\"\n        },\n        \"redirectURL\": \"\",\n        \"headersSize\": 482,\n        \"bodySize\": 6840,\n        \"comment\": \"\"\n      },\n      \"cache\": {},\n      \"timings\": {\n        \"comment\": \"\",\n        \"dns\": 7,\n        \"connect\": 804,\n        \"send\": 39,\n        \"wait\": 1424,\n        \"receive\": 1,\n        \"blocked\": 0,\n        \"ssl\": 743\n      },\n      \"serverIPAddress\": \"10.225.41.133\",\n      \"comment\": \"\",\n      \"time\": 2276\n    }, {\n      \"pageref\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:15.949Z\",\n      \"request\": {\n        \"method\": \"GET\",\n        \"url\": \"https://some-host.example.com/checkout/v3/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Authorization\",\n          \"value\": \"Basic stuffz\"\n        }, {\n          \"name\": \"User-Agent\",\n          \"value\": \"SysTest - perf\"\n        }, {\n          \"name\": \"Accept\",\n          \"value\": \"application/json; charset=utf-8\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/json\"\n        }, {\n          \"name\": \"Accept-Encoding\",\n          \"value\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\"\n        }, {\n          \"name\": \"Host\",\n          \"value\": \"some-host.example.com\"\n        }],\n        \"queryString\": [],\n        \"headersSize\": 379,\n        \"bodySize\": 0,\n        \"comment\": \"\"\n      },\n      \"response\": {\n        \"status\": 200,\n        \"statusText\": \"OK\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Cache-Control\",\n          \"value\": \"max-age=0, no-cache, no-store\"\n        }, {\n          \"name\": \"Content-Encoding\",\n          \"value\": \"gzip\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/json\"\n        }, {\n          \"name\": \"Date\",\n          \"value\": \"Mon, 19 Feb 2018 11:40:08 GMT\"\n        }, {\n          \"name\": \"Correlation-Id\",\n          \"value\": \"ab776e1a-2ddf-42f1-8ab6-d31987d8f7e6\"\n        }, {\n          \"name\": \"Pragma\",\n          \"value\": \"no-cache\"\n        }, {\n          \"name\": \"Render-Time\",\n          \"value\": \"11\"\n        }, {\n          \"name\": \"Server\",\n          \"value\": \"openresty\"\n        }, {\n          \"name\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains\"\n        }, {\n          \"name\": \"Vary\",\n          \"value\": \"Accept-Encoding\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"2822\"\n        }, {\n          \"name\": \"Connection\",\n          \"value\": \"keep-alive\"\n        }],\n        \"content\": {\n          \"size\": 6840,\n          \"mimeType\": \"application/json\",\n          \"text\": \"{\\n  \\\"order_id\\\" : \\\"570714bf-3c2b-452e-90cd-f7c5e552bb25\\\",\\n  \\\"status\\\" : \\\"checkout_incomplete\\\",\\n  \\\"purchase_country\\\" : \\\"se\\\",\\n  \\\"purchase_currency\\\" : \\\"SEK\\\",\\n  \\\"locale\\\" : \\\"sv-SE\\\",\\n  \\\"billing_address\\\" : {\\n    \\\"country\\\" : \\\"se\\\"\\n  },\\n  \\\"customer\\\" : { },\\n  \\\"shipping_address\\\" : {\\n    \\\"country\\\" : \\\"se\\\"\\n  },\\n  \\\"order_amount\\\" : 16278,\\n  \\\"order_tax_amount\\\" : 1206,\\n  \\\"order_lines\\\" : [ {\\n    \\\"type\\\" : \\\"physical\\\",\\n    \\\"reference\\\" : \\\"jkwedq9f6t\\\",\\n    \\\"name\\\" : \\\"Mediokra Betong Lampa. Tangentbord\\\",\\n    \\\"quantity\\\" : 1,\\n    \\\"quantity_unit\\\" : \\\"kg\\\",\\n    \\\"unit_price\\\" : 16278,\\n    \\\"tax_rate\\\" : 800,\\n    \\\"total_amount\\\" : 16278,\\n    \\\"total_discount_amount\\\" : 0,\\n    \\\"total_tax_amount\\\" : 1206,\\n    \\\"product_url\\\" : \\\"http://aufderharluettgen.info/haven\\\",\\n    \\\"image_url\\\" : \\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"\\n  } ],\\n  \\\"merchant_urls\\\" : {\\n    \\\"terms\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/terms\\\",\\n    \\\"checkout\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\n    \\\"confirmation\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/confirm\\\",\\n    \\\"push\\\" : \\\"https://some-fourth-host.example.com/v1/callback/push/{checkout.order.id}?merchant_id=smi-merchant-all-validation&env=perf\\\"\\n  },\\n  \\\"html_snippet\\\" : \\\"<div id=\\\\\\\"container\\\\\\\" style=\\\\\\\"overflow-x: hidden;\\\\\\\">\\\\n  <div id=\\\\\\\"unsupported-page\\\\\\\">\\\\n  <style type=\\\\\\\"text/css\\\\\\\">\\\\n  @-webkit-keyframes FadeIn{from{opacity:0}to{opacity:1}}@-moz-keyframes FadeIn{from{opacity:0}to{opacity:1}}@keyframes FadeIn{from{opacity:0}to{opacity:1}}#unsupported-page{opacity:0;opacity:1\\\\\\\\9;-webkit-animation:FadeIn ease-in 1;-moz-animation:FadeIn ease-in 1;animation:FadeIn ease-in 1;-webkit-animation-fill-mode:forwards;-moz-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-duration:.1s;-moz-animation-duration:.1s;animation-duration:.1s;-webkit-animation-delay:5s;-moz-animation-delay:5s;animation-delay:5s;text-align:center;padding-top:64px}#unsupported-page .heading{font-family:Source Sans Pro,Helvetica,Arial,sans-serif;line-height:48px;font-weight:200;color:#303030;font-size:42px;margin:24px 0}#unsupported-page .subheading{font-family:Source Sans Pro,Helvetica,Arial,sans-serif;line-height:28px;font-weight:400;color:rgba(0,0,0,.7);font-size:19px;max-width:560px;margin:10px auto}#unsupported-page .subheading a{text-decoration:none;background-color:transparent;border:0;color:rgba(0,0,0,.7);font-weight:600}\\\\n  </style>\\\\n  <h1 class=\\\\\\\"heading\\\\\\\">Oops.</h1>\\\\n  <p class=\\\\\\\"subheading\\\\\\\">It seems you might be using an older web browser which is not safe nor compatible with modern web sites. For a smoother checkout experience, please install a <a href=\\\\\\\"http://outdatedbrowser.com/en\\\\\\\" target=\\\\\\\"_blank\\\\\\\">newer browser</a>.</p>\\\\n  <p class=\\\\\\\"subheading\\\\\\\">Sorry for any inconvenience. For any questions, please contact customer service at <a href=\\\\\\\"https://www.example.com\\\\\\\">Example.com</a>.</p>\\\\n  </div>\\\\n  <script type=\\\\\\\"text/javascript\\\\\\\">\\\\n  /* <![CDATA[ */\\\\n  (function(w,k,i,d,n,c,l){\\\\n    w[k]=w[k]||function(){(w[k].q=w[k].q||[]).push(arguments)};\\\\n    l=w[k].config={\\\\n      container:w.document.getElementById(i),\\\\n      ORDER_URL:'https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25',\\\\n      AUTH_HEADER:'Checkout otherStuffz',\\\\n      LAYOUT:'desktop',\\\\n      LOCALE:'sv-SE',\\\\n      ORDER_STATUS:'checkout_incomplete',\\\\n      MERCHANT_TAC_URI:'https://some-fourth-host.example.com/v1/redirect/terms',\\\\n      MERCHANT_TAC_TITLE:'SMI Merchant All Validation',\\\\n      MERCHANT_NAME:'SMI Merchant All Validation',\\\\n      MERCHANT_COLOR:'',\\\\n      GUI_OPTIONS:[],\\\\n      ALLOW_SEPARATE_SHIPPING_ADDRESS:false,\\\\n      PURCHASE_COUNTRY:'swe',\\\\n      PURCHASE_CURRENCY:'SEK',\\\\n      DISALLOW_SKIP_NIN:false,\\\\n      ANALYTICS:'UA-36053137-1',\\\\n      TESTDRIVE:false,\\\\n      CHECKOUT_DOMAIN:'https://some-other-host.example.com',\\\\n      ASSETS_DOMAIN:'https://checkout.cdn.example.com',\\\\n      BOOTSTRAP_SRC:'https://checkout2.cdn.example.com/180218-4e2ae24/checkout.bootstrap.js',\\\\n      PREFILLED:false,\\\\n      DEVICE_RECOGNITION_URL:'https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/device_recognition',\\\\n      CLIENT_EVENT_HOST:'https://really-just-a-fifth-host.example.com',\\\\n      NEW_CONFIRMATION_PAGE: 'false'\\\\n    };\\\\n    n=d.createElement('script');\\\\n    c=d.getElementById(i);\\\\n    n.async=!0;\\\\n    n.src=l.BOOTSTRAP_SRC;\\\\n    c.appendChild(n);\\\\n    try{\\\\n      ((w.Image && (new w.Image))||(d.createElement && d.createElement('img'))||{}).src =\\\\n        l.CLIENT_EVENT_HOST + '/v1/checkout/snippet/load' +\\\\n        '?sid=' + l.ORDER_URL.split('/').slice(-1) +\\\\n        '&order_status=' + w.encodeURIComponent(l.ORDER_STATUS) +\\\\n        '&timestamp=' + (new Date).getTime();\\\\n    }catch(e){}\\\\n  })(this,'_Checkout','container',document);\\\\n  /* ]]> */\\\\n  </script>\\\\n      \\\\n  <noscript>\\\\nPlease <a href=\\\\\\\"http://enable-javascript.com\\\\\\\">enable JavaScript</a>.\\\\n  </noscript>\\\\n</div>\\\",\\n  \\\"started_at\\\" : \\\"2018-02-19T11:40:06Z\\\",\\n  \\\"last_modified_at\\\" : \\\"2018-02-19T11:40:06Z\\\",\\n  \\\"options\\\" : {\\n    \\\"allow_separate_shipping_address\\\" : false,\\n    \\\"date_of_birth_mandatory\\\" : false,\\n    \\\"require_validate_callback_success\\\" : false\\n  },\\n  \\\"external_payment_methods\\\" : [ ],\\n  \\\"external_checkouts\\\" : [ ],\\n  \\\"shipping_countries\\\" : [ \\\"AD\\\", \\\"AE\\\", \\\"AG\\\", \\\"AI\\\", \\\"AL\\\", \\\"AM\\\", \\\"AQ\\\", \\\"AR\\\", \\\"AS\\\", \\\"AT\\\", \\\"AU\\\", \\\"AW\\\", \\\"AX\\\", \\\"AZ\\\", \\\"BB\\\", \\\"BD\\\", \\\"BE\\\", \\\"BF\\\", \\\"BG\\\", \\\"BH\\\", \\\"BJ\\\", \\\"BL\\\", \\\"BM\\\", \\\"BN\\\", \\\"BO\\\", \\\"BQ\\\", \\\"BR\\\", \\\"BS\\\", \\\"BT\\\", \\\"BV\\\", \\\"BW\\\", \\\"BZ\\\", \\\"CA\\\", \\\"CC\\\", \\\"CH\\\", \\\"CK\\\", \\\"CL\\\", \\\"CM\\\", \\\"CO\\\", \\\"CR\\\", \\\"CU\\\", \\\"CV\\\", \\\"CW\\\", \\\"CX\\\", \\\"CY\\\", \\\"CZ\\\", \\\"DE\\\", \\\"DJ\\\", \\\"DK\\\", \\\"DM\\\", \\\"DO\\\", \\\"DZ\\\", \\\"EC\\\", \\\"EE\\\", \\\"EH\\\", \\\"ES\\\", \\\"ET\\\", \\\"FI\\\", \\\"FJ\\\", \\\"FK\\\", \\\"FM\\\", \\\"FO\\\", \\\"FR\\\", \\\"GA\\\", \\\"GB\\\", \\\"GD\\\", \\\"GE\\\", \\\"GF\\\", \\\"GG\\\", \\\"GH\\\", \\\"GI\\\", \\\"GL\\\", \\\"GM\\\", \\\"GP\\\", \\\"GQ\\\", \\\"GR\\\", \\\"GS\\\", \\\"GT\\\", \\\"GU\\\", \\\"HK\\\", \\\"HM\\\", \\\"HN\\\", \\\"HR\\\", \\\"HU\\\", \\\"ID\\\", \\\"IE\\\", \\\"IL\\\", \\\"IM\\\", \\\"IN\\\", \\\"IO\\\", \\\"IS\\\", \\\"IT\\\", \\\"JE\\\", \\\"JM\\\", \\\"JO\\\", \\\"JP\\\", \\\"KE\\\", \\\"KG\\\", \\\"KH\\\", \\\"KI\\\", \\\"KM\\\", \\\"KN\\\", \\\"KR\\\", \\\"KW\\\", \\\"KY\\\", \\\"KZ\\\", \\\"LC\\\", \\\"LI\\\", \\\"LK\\\", \\\"LS\\\", \\\"LT\\\", \\\"LU\\\", \\\"LV\\\", \\\"MA\\\", \\\"MC\\\", \\\"ME\\\", \\\"MF\\\", \\\"MG\\\", \\\"MH\\\", \\\"MK\\\", \\\"ML\\\", \\\"MN\\\", \\\"MO\\\", \\\"MP\\\", \\\"MQ\\\", \\\"MR\\\", \\\"MS\\\", \\\"MT\\\", \\\"MU\\\", \\\"MV\\\", \\\"MW\\\", \\\"MX\\\", \\\"MY\\\", \\\"MZ\\\", \\\"NA\\\", \\\"NC\\\", \\\"NE\\\", \\\"NF\\\", \\\"NG\\\", \\\"NI\\\", \\\"NL\\\", \\\"NO\\\", \\\"NP\\\", \\\"NR\\\", \\\"NU\\\", \\\"NZ\\\", \\\"OM\\\", \\\"PA\\\", \\\"PE\\\", \\\"PF\\\", \\\"PH\\\", \\\"PK\\\", \\\"PL\\\", \\\"PM\\\", \\\"PN\\\", \\\"PR\\\", \\\"PS\\\", \\\"PT\\\", \\\"PW\\\", \\\"PY\\\", \\\"QA\\\", \\\"RE\\\", \\\"RO\\\", \\\"RW\\\", \\\"SA\\\", \\\"SB\\\", \\\"SC\\\", \\\"SE\\\", \\\"SG\\\", \\\"SH\\\", \\\"SI\\\", \\\"SJ\\\", \\\"SK\\\", \\\"SL\\\", \\\"SM\\\", \\\"SN\\\", \\\"SR\\\", \\\"ST\\\", \\\"SV\\\", \\\"SX\\\", \\\"SZ\\\", \\\"TC\\\", \\\"TD\\\", \\\"TF\\\", \\\"TG\\\", \\\"TH\\\", \\\"TJ\\\", \\\"TK\\\", \\\"TL\\\", \\\"TM\\\", \\\"TO\\\", \\\"TR\\\", \\\"TT\\\", \\\"TV\\\", \\\"TW\\\", \\\"TZ\\\", \\\"UM\\\", \\\"US\\\", \\\"UY\\\", \\\"UZ\\\", \\\"VA\\\", \\\"VC\\\", \\\"VE\\\", \\\"VG\\\", \\\"VI\\\", \\\"VN\\\", \\\"WF\\\", \\\"WS\\\", \\\"YT\\\", \\\"ZA\\\", \\\"ZM\\\" ]\\n}\",\n          \"comment\": \"\"\n        },\n        \"redirectURL\": \"\",\n        \"headersSize\": 408,\n        \"bodySize\": 2822,\n        \"comment\": \"\"\n      },\n      \"cache\": {},\n      \"timings\": {\n        \"comment\": \"\",\n        \"dns\": 0,\n        \"connect\": 126,\n        \"send\": 1,\n        \"wait\": 114,\n        \"receive\": 3,\n        \"blocked\": 0,\n        \"ssl\": 83\n      },\n      \"serverIPAddress\": \"10.225.41.133\",\n      \"comment\": \"\",\n      \"time\": 246\n    }, {\n      \"pageref\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:16.647Z\",\n      \"request\": {\n        \"method\": \"GET\",\n        \"url\": \"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Authorization\",\n          \"value\": \"Checkout otherStuffz\"\n        }, {\n          \"name\": \"User-Agent\",\n          \"value\": \"SysTest - perf\"\n        }, {\n          \"name\": \"Accept\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.client-order-v1+json\"\n        }, {\n          \"name\": \"Accept-Encoding\",\n          \"value\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\"\n        }, {\n          \"name\": \"Host\",\n          \"value\": \"some-other-host.example.com\"\n        }],\n        \"queryString\": [],\n        \"headersSize\": 387,\n        \"bodySize\": 0,\n        \"comment\": \"\"\n      },\n      \"response\": {\n        \"status\": 200,\n        \"statusText\": \"OK\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Cache-Control\",\n          \"value\": \"max-age=0, no-cache, no-store\"\n        }, {\n          \"name\": \"Content-Encoding\",\n          \"value\": \"gzip\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Date\",\n          \"value\": \"Mon, 19 Feb 2018 11:40:09 GMT\"\n        }, {\n          \"name\": \"Correlation-Id\",\n          \"value\": \"a84e5613-526c-4047-be4a-05eed9c6019a\"\n        }, {\n          \"name\": \"Pragma\",\n          \"value\": \"no-cache\"\n        }, {\n          \"name\": \"Render-Time\",\n          \"value\": \"451\"\n        }, {\n          \"name\": \"Server\",\n          \"value\": \"openresty\"\n        }, {\n          \"name\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains\"\n        }, {\n          \"name\": \"Vary\",\n          \"value\": \"Accept-Encoding\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"1478\"\n        }, {\n          \"name\": \"Connection\",\n          \"value\": \"keep-alive\"\n        }],\n        \"content\": {\n          \"size\": 5167,\n          \"mimeType\": \"application/vnd.checkout.server-order-v1+json\",\n          \"text\": \"{\\n  \\\"shared\\\" : {\\n    \\\"challenge\\\" : {\\n      \\\"country\\\" : \\\"swe\\\"\\n    },\\n    \\\"billing_address\\\" : {\\n      \\\"country\\\" : \\\"swe\\\"\\n    },\\n    \\\"customer\\\" : {\\n      \\\"type\\\" : \\\"person\\\"\\n    },\\n    \\\"language\\\" : \\\"sv\\\",\\n    \\\"currency\\\" : \\\"SEK\\\"\\n  },\\n  \\\"cart\\\" : {\\n    \\\"total_tax_amount\\\" : 1206,\\n    \\\"total_price_including_tax\\\" : 16278,\\n    \\\"total_price_excluding_tax\\\" : 15072,\\n    \\\"total_shipping_amount_excluding_tax\\\" : 0,\\n    \\\"total_surcharge_amount_excluding_tax\\\" : 0,\\n    \\\"total_discount_amount_excluding_tax\\\" : 0,\\n    \\\"subtotal\\\" : 15072,\\n    \\\"total_store_credit\\\" : 0,\\n    \\\"items\\\" : [ {\\n      \\\"type\\\" : \\\"physical\\\",\\n      \\\"reference\\\" : \\\"jkwedq9f6t\\\",\\n      \\\"name\\\" : \\\"Mediokra Betong Lampa. Tangentbord\\\",\\n      \\\"quantity\\\" : 1,\\n      \\\"unit_price\\\" : 16278,\\n      \\\"total_tax_amount\\\" : 1206,\\n      \\\"tax_rate\\\" : 800,\\n      \\\"total_price_including_tax\\\" : 16278,\\n      \\\"total_price_excluding_tax\\\" : 15072,\\n      \\\"product_url\\\" : \\\"http://aufderharluettgen.info/haven\\\",\\n      \\\"image_url\\\" : \\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"\\n    } ]\\n  },\\n  \\\"required_fields\\\" : [ \\\"challenge.email\\\", \\\"challenge.postal_code\\\" ],\\n  \\\"options\\\" : {\\n    \\\"allow_separate_shipping_address\\\" : false,\\n    \\\"date_of_birth_mandatory\\\" : false,\\n    \\\"national_identification_number_mandatory\\\" : false,\\n    \\\"allowed_customer_types\\\" : [ \\\"person\\\" ],\\n    \\\"payment_selector_on_load\\\" : false\\n  },\\n  \\\"preview_payment_methods\\\" : [ {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"invoice\\\",\\n    \\\"data\\\" : {\\n      \\\"days\\\" : 14\\n    }\\n  }, {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"credit_card\\\",\\n    \\\"data\\\" : {\\n      \\\"available_cards\\\" : [ \\\"VISA\\\", \\\"MASTER\\\" ],\\n      \\\"allow_saved_card\\\" : false,\\n      \\\"do_save_card\\\" : false\\n    }\\n  } ],\\n  \\\"allowed_billing_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"allowed_shipping_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"status\\\" : {\\n    \\\"prescreened\\\" : false,\\n    \\\"require_terms_consent\\\" : true\\n  },\\n  \\\"merchant_urls\\\" : {\\n    \\\"checkout\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\n    \\\"confirmation\\\" : \\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\n    \\\"terms\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/terms\\\"\\n  }\\n}\",\n          \"comment\": \"\"\n        },\n        \"redirectURL\": \"\",\n        \"headersSize\": 445,\n        \"bodySize\": 1478,\n        \"comment\": \"\"\n      },\n      \"cache\": {},\n      \"timings\": {\n        \"comment\": \"\",\n        \"dns\": 7,\n        \"connect\": 544,\n        \"send\": 1,\n        \"wait\": 698,\n        \"receive\": 1,\n        \"blocked\": 0,\n        \"ssl\": 499\n      },\n      \"serverIPAddress\": \"10.225.41.52\",\n      \"comment\": \"\",\n      \"time\": 1254\n    }, {\n      \"pageref\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:17.478Z\",\n      \"request\": {\n        \"method\": \"POST\",\n        \"url\": \"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Authorization\",\n          \"value\": \"Checkout otherStuffz\"\n        }, {\n          \"name\": \"User-Agent\",\n          \"value\": \"SysTest - perf\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.client-order-v1+json\"\n        }, {\n          \"name\": \"Accept\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Accept-Encoding\",\n          \"value\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\"\n        }, {\n          \"name\": \"Host\",\n          \"value\": \"some-other-host.example.com\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"4351\"\n        }],\n        \"queryString\": [],\n        \"postData\": {\n          \"mimeType\": \"application/vnd.checkout.client-order-v1+json\",\n          \"text\": \"{\\\"shared\\\":{\\\"challenge\\\":{\\\"country\\\":\\\"swe\\\",\\\"email\\\":\\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\\"postal_code\\\":\\\"10066\\\"},\\\"billing_address\\\":{\\\"country\\\":\\\"swe\\\"},\\\"customer\\\":{\\\"type\\\":\\\"person\\\"},\\\"language\\\":\\\"sv\\\",\\\"currency\\\":\\\"SEK\\\"},\\\"cart\\\":{\\\"total_tax_amount\\\":1206,\\\"total_price_including_tax\\\":16278,\\\"total_price_excluding_tax\\\":15072,\\\"total_shipping_amount_excluding_tax\\\":0,\\\"total_surcharge_amount_excluding_tax\\\":0,\\\"total_discount_amount_excluding_tax\\\":0,\\\"subtotal\\\":15072,\\\"total_store_credit\\\":0,\\\"items\\\":[{\\\"type\\\":\\\"physical\\\",\\\"reference\\\":\\\"jkwedq9f6t\\\",\\\"name\\\":\\\"Mediokra Betong Lampa. Tangentbord\\\",\\\"quantity\\\":1,\\\"unit_price\\\":16278,\\\"total_tax_amount\\\":1206,\\\"tax_rate\\\":800,\\\"total_price_including_tax\\\":16278,\\\"total_price_excluding_tax\\\":15072,\\\"product_url\\\":\\\"http://aufderharluettgen.info/haven\\\",\\\"image_url\\\":\\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"}]},\\\"required_fields\\\":[\\\"challenge.email\\\",\\\"challenge.postal_code\\\"],\\\"options\\\":{\\\"allow_separate_shipping_address\\\":false,\\\"date_of_birth_mandatory\\\":false,\\\"national_identification_number_mandatory\\\":false,\\\"allowed_customer_types\\\":[\\\"person\\\"],\\\"payment_selector_on_load\\\":false},\\\"preview_payment_methods\\\":[{\\\"id\\\":\\\"-1\\\",\\\"type\\\":\\\"invoice\\\",\\\"data\\\":{\\\"days\\\":14}},{\\\"id\\\":\\\"-1\\\",\\\"type\\\":\\\"credit_card\\\",\\\"data\\\":{\\\"available_cards\\\":[\\\"VISA\\\",\\\"MASTER\\\"],\\\"allow_saved_card\\\":false,\\\"do_save_card\\\":false}}],\\\"allowed_billing_countries\\\":[\\\"and\\\",\\\"are\\\",\\\"atg\\\",\\\"aia\\\",\\\"alb\\\",\\\"arm\\\",\\\"ata\\\",\\\"arg\\\",\\\"asm\\\",\\\"aut\\\",\\\"aus\\\",\\\"abw\\\",\\\"ala\\\",\\\"aze\\\",\\\"brb\\\",\\\"bgd\\\",\\\"bel\\\",\\\"bfa\\\",\\\"bgr\\\",\\\"bhr\\\",\\\"ben\\\",\\\"blm\\\",\\\"bmu\\\",\\\"brn\\\",\\\"bol\\\",\\\"bes\\\",\\\"bra\\\",\\\"bhs\\\",\\\"btn\\\",\\\"bvt\\\",\\\"bwa\\\",\\\"blz\\\",\\\"can\\\",\\\"cck\\\",\\\"che\\\",\\\"cok\\\",\\\"chl\\\",\\\"cmr\\\",\\\"col\\\",\\\"cri\\\",\\\"cub\\\",\\\"cpv\\\",\\\"cuw\\\",\\\"cxr\\\",\\\"cyp\\\",\\\"cze\\\",\\\"deu\\\",\\\"dji\\\",\\\"dnk\\\",\\\"dma\\\",\\\"dom\\\",\\\"dza\\\",\\\"ecu\\\",\\\"est\\\",\\\"esh\\\",\\\"esp\\\",\\\"eth\\\",\\\"fin\\\",\\\"fji\\\",\\\"flk\\\",\\\"fsm\\\",\\\"fro\\\",\\\"fra\\\",\\\"gab\\\",\\\"gbr\\\",\\\"grd\\\",\\\"geo\\\",\\\"guf\\\",\\\"ggy\\\",\\\"gha\\\",\\\"gib\\\",\\\"grl\\\",\\\"gmb\\\",\\\"glp\\\",\\\"gnq\\\",\\\"grc\\\",\\\"sgs\\\",\\\"gtm\\\",\\\"gum\\\",\\\"hkg\\\",\\\"hmd\\\",\\\"hnd\\\",\\\"hrv\\\",\\\"hun\\\",\\\"idn\\\",\\\"irl\\\",\\\"isr\\\",\\\"imn\\\",\\\"ind\\\",\\\"iot\\\",\\\"isl\\\",\\\"ita\\\",\\\"jey\\\",\\\"jam\\\",\\\"jor\\\",\\\"jpn\\\",\\\"ken\\\",\\\"kgz\\\",\\\"khm\\\",\\\"kir\\\",\\\"com\\\",\\\"kna\\\",\\\"kor\\\",\\\"kwt\\\",\\\"cym\\\",\\\"kaz\\\",\\\"lca\\\",\\\"lie\\\",\\\"lka\\\",\\\"lso\\\",\\\"ltu\\\",\\\"lux\\\",\\\"lva\\\",\\\"mar\\\",\\\"mco\\\",\\\"mne\\\",\\\"maf\\\",\\\"mdg\\\",\\\"mhl\\\",\\\"mkd\\\",\\\"mli\\\",\\\"mng\\\",\\\"mac\\\",\\\"mnp\\\",\\\"mtq\\\",\\\"mrt\\\",\\\"msr\\\",\\\"mlt\\\",\\\"mus\\\",\\\"mdv\\\",\\\"mwi\\\",\\\"mex\\\",\\\"mys\\\",\\\"moz\\\",\\\"nam\\\",\\\"ncl\\\",\\\"ner\\\",\\\"nfk\\\",\\\"nga\\\",\\\"nic\\\",\\\"nld\\\",\\\"nor\\\",\\\"npl\\\",\\\"nru\\\",\\\"niu\\\",\\\"nzl\\\",\\\"omn\\\",\\\"pan\\\",\\\"per\\\",\\\"pyf\\\",\\\"phl\\\",\\\"pak\\\",\\\"pol\\\",\\\"spm\\\",\\\"pcn\\\",\\\"pri\\\",\\\"pse\\\",\\\"prt\\\",\\\"plw\\\",\\\"pry\\\",\\\"qat\\\",\\\"reu\\\",\\\"rou\\\",\\\"rwa\\\",\\\"sau\\\",\\\"slb\\\",\\\"syc\\\",\\\"swe\\\",\\\"sgp\\\",\\\"shn\\\",\\\"svn\\\",\\\"sjm\\\",\\\"svk\\\",\\\"sle\\\",\\\"smr\\\",\\\"sen\\\",\\\"sur\\\",\\\"stp\\\",\\\"slv\\\",\\\"sxm\\\",\\\"swz\\\",\\\"tca\\\",\\\"tcd\\\",\\\"atf\\\",\\\"tgo\\\",\\\"tha\\\",\\\"tjk\\\",\\\"tkl\\\",\\\"tls\\\",\\\"tkm\\\",\\\"ton\\\",\\\"tur\\\",\\\"tto\\\",\\\"tuv\\\",\\\"twn\\\",\\\"tza\\\",\\\"umi\\\",\\\"usa\\\",\\\"ury\\\",\\\"uzb\\\",\\\"vat\\\",\\\"vct\\\",\\\"ven\\\",\\\"vgb\\\",\\\"vir\\\",\\\"vnm\\\",\\\"wlf\\\",\\\"wsm\\\",\\\"myt\\\",\\\"zaf\\\",\\\"zmb\\\"],\\\"allowed_shipping_countries\\\":[\\\"and\\\",\\\"are\\\",\\\"atg\\\",\\\"aia\\\",\\\"alb\\\",\\\"arm\\\",\\\"ata\\\",\\\"arg\\\",\\\"asm\\\",\\\"aut\\\",\\\"aus\\\",\\\"abw\\\",\\\"ala\\\",\\\"aze\\\",\\\"brb\\\",\\\"bgd\\\",\\\"bel\\\",\\\"bfa\\\",\\\"bgr\\\",\\\"bhr\\\",\\\"ben\\\",\\\"blm\\\",\\\"bmu\\\",\\\"brn\\\",\\\"bol\\\",\\\"bes\\\",\\\"bra\\\",\\\"bhs\\\",\\\"btn\\\",\\\"bvt\\\",\\\"bwa\\\",\\\"blz\\\",\\\"can\\\",\\\"cck\\\",\\\"che\\\",\\\"cok\\\",\\\"chl\\\",\\\"cmr\\\",\\\"col\\\",\\\"cri\\\",\\\"cub\\\",\\\"cpv\\\",\\\"cuw\\\",\\\"cxr\\\",\\\"cyp\\\",\\\"cze\\\",\\\"deu\\\",\\\"dji\\\",\\\"dnk\\\",\\\"dma\\\",\\\"dom\\\",\\\"dza\\\",\\\"ecu\\\",\\\"est\\\",\\\"esh\\\",\\\"esp\\\",\\\"eth\\\",\\\"fin\\\",\\\"fji\\\",\\\"flk\\\",\\\"fsm\\\",\\\"fro\\\",\\\"fra\\\",\\\"gab\\\",\\\"gbr\\\",\\\"grd\\\",\\\"geo\\\",\\\"guf\\\",\\\"ggy\\\",\\\"gha\\\",\\\"gib\\\",\\\"grl\\\",\\\"gmb\\\",\\\"glp\\\",\\\"gnq\\\",\\\"grc\\\",\\\"sgs\\\",\\\"gtm\\\",\\\"gum\\\",\\\"hkg\\\",\\\"hmd\\\",\\\"hnd\\\",\\\"hrv\\\",\\\"hun\\\",\\\"idn\\\",\\\"irl\\\",\\\"isr\\\",\\\"imn\\\",\\\"ind\\\",\\\"iot\\\",\\\"isl\\\",\\\"ita\\\",\\\"jey\\\",\\\"jam\\\",\\\"jor\\\",\\\"jpn\\\",\\\"ken\\\",\\\"kgz\\\",\\\"khm\\\",\\\"kir\\\",\\\"com\\\",\\\"kna\\\",\\\"kor\\\",\\\"kwt\\\",\\\"cym\\\",\\\"kaz\\\",\\\"lca\\\",\\\"lie\\\",\\\"lka\\\",\\\"lso\\\",\\\"ltu\\\",\\\"lux\\\",\\\"lva\\\",\\\"mar\\\",\\\"mco\\\",\\\"mne\\\",\\\"maf\\\",\\\"mdg\\\",\\\"mhl\\\",\\\"mkd\\\",\\\"mli\\\",\\\"mng\\\",\\\"mac\\\",\\\"mnp\\\",\\\"mtq\\\",\\\"mrt\\\",\\\"msr\\\",\\\"mlt\\\",\\\"mus\\\",\\\"mdv\\\",\\\"mwi\\\",\\\"mex\\\",\\\"mys\\\",\\\"moz\\\",\\\"nam\\\",\\\"ncl\\\",\\\"ner\\\",\\\"nfk\\\",\\\"nga\\\",\\\"nic\\\",\\\"nld\\\",\\\"nor\\\",\\\"npl\\\",\\\"nru\\\",\\\"niu\\\",\\\"nzl\\\",\\\"omn\\\",\\\"pan\\\",\\\"per\\\",\\\"pyf\\\",\\\"phl\\\",\\\"pak\\\",\\\"pol\\\",\\\"spm\\\",\\\"pcn\\\",\\\"pri\\\",\\\"pse\\\",\\\"prt\\\",\\\"plw\\\",\\\"pry\\\",\\\"qat\\\",\\\"reu\\\",\\\"rou\\\",\\\"rwa\\\",\\\"sau\\\",\\\"slb\\\",\\\"syc\\\",\\\"swe\\\",\\\"sgp\\\",\\\"shn\\\",\\\"svn\\\",\\\"sjm\\\",\\\"svk\\\",\\\"sle\\\",\\\"smr\\\",\\\"sen\\\",\\\"sur\\\",\\\"stp\\\",\\\"slv\\\",\\\"sxm\\\",\\\"swz\\\",\\\"tca\\\",\\\"tcd\\\",\\\"atf\\\",\\\"tgo\\\",\\\"tha\\\",\\\"tjk\\\",\\\"tkl\\\",\\\"tls\\\",\\\"tkm\\\",\\\"ton\\\",\\\"tur\\\",\\\"tto\\\",\\\"tuv\\\",\\\"twn\\\",\\\"tza\\\",\\\"umi\\\",\\\"usa\\\",\\\"ury\\\",\\\"uzb\\\",\\\"vat\\\",\\\"vct\\\",\\\"ven\\\",\\\"vgb\\\",\\\"vir\\\",\\\"vnm\\\",\\\"wlf\\\",\\\"wsm\\\",\\\"myt\\\",\\\"zaf\\\",\\\"zmb\\\"],\\\"status\\\":{\\\"prescreened\\\":false,\\\"require_terms_consent\\\":true},\\\"merchant_urls\\\":{\\\"checkout\\\":\\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\\"confirmation\\\":\\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\\"terms\\\":\\\"https://some-fourth-host.example.com/v1/redirect/terms\\\"}}\",\n          \"comment\": \"\"\n        },\n        \"headersSize\": 410,\n        \"bodySize\": 4351,\n        \"comment\": \"\"\n      },\n      \"response\": {\n        \"status\": 200,\n        \"statusText\": \"OK\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Cache-Control\",\n          \"value\": \"max-age=0, no-cache, no-store\"\n        }, {\n          \"name\": \"Content-Encoding\",\n          \"value\": \"gzip\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Date\",\n          \"value\": \"Mon, 19 Feb 2018 11:40:09 GMT\"\n        }, {\n          \"name\": \"Correlation-Id\",\n          \"value\": \"f6df29e7-f850-4c36-81fc-11def2f44b81\"\n        }, {\n          \"name\": \"Pragma\",\n          \"value\": \"no-cache\"\n        }, {\n          \"name\": \"Render-Time\",\n          \"value\": \"129\"\n        }, {\n          \"name\": \"Server\",\n          \"value\": \"openresty\"\n        }, {\n          \"name\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains\"\n        }, {\n          \"name\": \"Vary\",\n          \"value\": \"Accept-Encoding\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"1636\"\n        }, {\n          \"name\": \"Connection\",\n          \"value\": \"keep-alive\"\n        }],\n        \"content\": {\n          \"size\": 5598,\n          \"mimeType\": \"application/vnd.checkout.server-order-v1+json\",\n          \"text\": \"{\\n  \\\"shared\\\" : {\\n    \\\"challenge\\\" : {\\n      \\\"email\\\" : \\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\n      \\\"postal_code\\\" : \\\"10066\\\",\\n      \\\"country\\\" : \\\"swe\\\"\\n    },\\n    \\\"billing_address\\\" : {\\n      \\\"email\\\" : \\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\n      \\\"postal_code\\\" : \\\"10066\\\",\\n      \\\"country\\\" : \\\"swe\\\"\\n    },\\n    \\\"customer\\\" : {\\n      \\\"type\\\" : \\\"person\\\"\\n    },\\n    \\\"language\\\" : \\\"sv\\\",\\n    \\\"currency\\\" : \\\"SEK\\\"\\n  },\\n  \\\"cart\\\" : {\\n    \\\"total_tax_amount\\\" : 1206,\\n    \\\"total_price_including_tax\\\" : 16278,\\n    \\\"total_price_excluding_tax\\\" : 15072,\\n    \\\"total_shipping_amount_excluding_tax\\\" : 0,\\n    \\\"total_surcharge_amount_excluding_tax\\\" : 0,\\n    \\\"total_discount_amount_excluding_tax\\\" : 0,\\n    \\\"subtotal\\\" : 15072,\\n    \\\"total_store_credit\\\" : 0,\\n    \\\"items\\\" : [ {\\n      \\\"type\\\" : \\\"physical\\\",\\n      \\\"reference\\\" : \\\"jkwedq9f6t\\\",\\n      \\\"name\\\" : \\\"Mediokra Betong Lampa. Tangentbord\\\",\\n      \\\"quantity\\\" : 1,\\n      \\\"unit_price\\\" : 16278,\\n      \\\"total_tax_amount\\\" : 1206,\\n      \\\"tax_rate\\\" : 800,\\n      \\\"total_price_including_tax\\\" : 16278,\\n      \\\"total_price_excluding_tax\\\" : 15072,\\n      \\\"product_url\\\" : \\\"http://aufderharluettgen.info/haven\\\",\\n      \\\"image_url\\\" : \\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"\\n    } ]\\n  },\\n  \\\"required_fields\\\" : [ \\\"billing_address.given_name\\\", \\\"billing_address.family_name\\\", \\\"billing_address.street_address\\\", \\\"billing_address.city\\\", \\\"billing_address.phone\\\", \\\"customer.national_identification_number\\\" ],\\n  \\\"options\\\" : {\\n    \\\"allow_separate_shipping_address\\\" : false,\\n    \\\"date_of_birth_mandatory\\\" : false,\\n    \\\"national_identification_number_mandatory\\\" : false,\\n    \\\"allowed_customer_types\\\" : [ \\\"person\\\" ],\\n    \\\"payment_selector_on_load\\\" : false\\n  },\\n  \\\"preview_payment_methods\\\" : [ {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"invoice\\\",\\n    \\\"data\\\" : {\\n      \\\"days\\\" : 14\\n    }\\n  }, {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"credit_card\\\",\\n    \\\"data\\\" : {\\n      \\\"available_cards\\\" : [ \\\"VISA\\\", \\\"MASTER\\\" ],\\n      \\\"allow_saved_card\\\" : false,\\n      \\\"do_save_card\\\" : false\\n    }\\n  } ],\\n  \\\"allowed_billing_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"allowed_shipping_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"status\\\" : {\\n    \\\"prescreened\\\" : false,\\n    \\\"require_terms_consent\\\" : true\\n  },\\n  \\\"analytics_user_id\\\" : \\\"2EUwzTXiwfzWhYBUkPGxmjTIK9_mDMM7vDQo2wk_C7o=\\\",\\n  \\\"merchant_urls\\\" : {\\n    \\\"checkout\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\n    \\\"confirmation\\\" : \\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\n    \\\"terms\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/terms\\\"\\n  }\\n}\",\n          \"comment\": \"\"\n        },\n        \"redirectURL\": \"\",\n        \"headersSize\": 445,\n        \"bodySize\": 1636,\n        \"comment\": \"\"\n      },\n      \"cache\": {},\n      \"timings\": {\n        \"comment\": \"\",\n        \"dns\": 0,\n        \"connect\": 105,\n        \"send\": 2,\n        \"wait\": 232,\n        \"receive\": 1,\n        \"blocked\": 0,\n        \"ssl\": 63\n      },\n      \"serverIPAddress\": \"10.225.41.52\",\n      \"comment\": \"\",\n      \"time\": 342\n    }, {\n      \"pageref\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:17.845Z\",\n      \"request\": {\n        \"method\": \"POST\",\n        \"url\": \"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Authorization\",\n          \"value\": \"Checkout otherStuffz\"\n        }, {\n          \"name\": \"User-Agent\",\n          \"value\": \"SysTest - perf\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.client-order-v1+json\"\n        }, {\n          \"name\": \"Accept\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Accept-Encoding\",\n          \"value\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\"\n        }, {\n          \"name\": \"Host\",\n          \"value\": \"some-other-host.example.com\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"5003\"\n        }],\n        \"queryString\": [],\n        \"postData\": {\n          \"mimeType\": \"application/vnd.checkout.client-order-v1+json\",\n          \"text\": \"{\\\"shared\\\":{\\\"challenge\\\":{\\\"email\\\":\\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\\"postal_code\\\":\\\"10066\\\",\\\"country\\\":\\\"swe\\\"},\\\"billing_address\\\":{\\\"email\\\":\\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\\"postal_code\\\":\\\"10066\\\",\\\"country\\\":\\\"swe\\\",\\\"given_name\\\":\\\"Eva InvoiceGreenNewSpec\\\",\\\"family_name\\\":\\\"Anglund\\\",\\\"street_address\\\":\\\"Sveavägen 44, 11111 Stockholm, Sweden Eriks Gata gatan\\\",\\\"city\\\":\\\"AlingHelsingstadfors\\\",\\\"phone\\\":\\\"+46700012878\\\",\\\"care_of\\\":\\\"C/O Hakan Ostlund\\\"},\\\"customer\\\":{\\\"type\\\":\\\"person\\\",\\\"national_identification_number\\\":\\\"8910210312\\\"},\\\"language\\\":\\\"sv\\\",\\\"currency\\\":\\\"SEK\\\"},\\\"cart\\\":{\\\"total_tax_amount\\\":1206,\\\"total_price_including_tax\\\":16278,\\\"total_price_excluding_tax\\\":15072,\\\"total_shipping_amount_excluding_tax\\\":0,\\\"total_surcharge_amount_excluding_tax\\\":0,\\\"total_discount_amount_excluding_tax\\\":0,\\\"subtotal\\\":15072,\\\"total_store_credit\\\":0,\\\"items\\\":[{\\\"type\\\":\\\"physical\\\",\\\"reference\\\":\\\"jkwedq9f6t\\\",\\\"name\\\":\\\"Mediokra Betong Lampa. Tangentbord\\\",\\\"quantity\\\":1,\\\"unit_price\\\":16278,\\\"total_tax_amount\\\":1206,\\\"tax_rate\\\":800,\\\"total_price_including_tax\\\":16278,\\\"total_price_excluding_tax\\\":15072,\\\"product_url\\\":\\\"http://aufderharluettgen.info/haven\\\",\\\"image_url\\\":\\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"}]},\\\"required_fields\\\":[\\\"billing_address.given_name\\\",\\\"billing_address.family_name\\\",\\\"billing_address.street_address\\\",\\\"billing_address.city\\\",\\\"billing_address.phone\\\",\\\"customer.national_identification_number\\\",\\\"billing_address.care_of\\\"],\\\"options\\\":{\\\"allow_separate_shipping_address\\\":false,\\\"date_of_birth_mandatory\\\":false,\\\"national_identification_number_mandatory\\\":false,\\\"allowed_customer_types\\\":[\\\"person\\\"],\\\"payment_selector_on_load\\\":false},\\\"preview_payment_methods\\\":[{\\\"id\\\":\\\"-1\\\",\\\"type\\\":\\\"invoice\\\",\\\"data\\\":{\\\"days\\\":14}},{\\\"id\\\":\\\"-1\\\",\\\"type\\\":\\\"credit_card\\\",\\\"data\\\":{\\\"available_cards\\\":[\\\"VISA\\\",\\\"MASTER\\\"],\\\"allow_saved_card\\\":false,\\\"do_save_card\\\":false}}],\\\"allowed_billing_countries\\\":[\\\"and\\\",\\\"are\\\",\\\"atg\\\",\\\"aia\\\",\\\"alb\\\",\\\"arm\\\",\\\"ata\\\",\\\"arg\\\",\\\"asm\\\",\\\"aut\\\",\\\"aus\\\",\\\"abw\\\",\\\"ala\\\",\\\"aze\\\",\\\"brb\\\",\\\"bgd\\\",\\\"bel\\\",\\\"bfa\\\",\\\"bgr\\\",\\\"bhr\\\",\\\"ben\\\",\\\"blm\\\",\\\"bmu\\\",\\\"brn\\\",\\\"bol\\\",\\\"bes\\\",\\\"bra\\\",\\\"bhs\\\",\\\"btn\\\",\\\"bvt\\\",\\\"bwa\\\",\\\"blz\\\",\\\"can\\\",\\\"cck\\\",\\\"che\\\",\\\"cok\\\",\\\"chl\\\",\\\"cmr\\\",\\\"col\\\",\\\"cri\\\",\\\"cub\\\",\\\"cpv\\\",\\\"cuw\\\",\\\"cxr\\\",\\\"cyp\\\",\\\"cze\\\",\\\"deu\\\",\\\"dji\\\",\\\"dnk\\\",\\\"dma\\\",\\\"dom\\\",\\\"dza\\\",\\\"ecu\\\",\\\"est\\\",\\\"esh\\\",\\\"esp\\\",\\\"eth\\\",\\\"fin\\\",\\\"fji\\\",\\\"flk\\\",\\\"fsm\\\",\\\"fro\\\",\\\"fra\\\",\\\"gab\\\",\\\"gbr\\\",\\\"grd\\\",\\\"geo\\\",\\\"guf\\\",\\\"ggy\\\",\\\"gha\\\",\\\"gib\\\",\\\"grl\\\",\\\"gmb\\\",\\\"glp\\\",\\\"gnq\\\",\\\"grc\\\",\\\"sgs\\\",\\\"gtm\\\",\\\"gum\\\",\\\"hkg\\\",\\\"hmd\\\",\\\"hnd\\\",\\\"hrv\\\",\\\"hun\\\",\\\"idn\\\",\\\"irl\\\",\\\"isr\\\",\\\"imn\\\",\\\"ind\\\",\\\"iot\\\",\\\"isl\\\",\\\"ita\\\",\\\"jey\\\",\\\"jam\\\",\\\"jor\\\",\\\"jpn\\\",\\\"ken\\\",\\\"kgz\\\",\\\"khm\\\",\\\"kir\\\",\\\"com\\\",\\\"kna\\\",\\\"kor\\\",\\\"kwt\\\",\\\"cym\\\",\\\"kaz\\\",\\\"lca\\\",\\\"lie\\\",\\\"lka\\\",\\\"lso\\\",\\\"ltu\\\",\\\"lux\\\",\\\"lva\\\",\\\"mar\\\",\\\"mco\\\",\\\"mne\\\",\\\"maf\\\",\\\"mdg\\\",\\\"mhl\\\",\\\"mkd\\\",\\\"mli\\\",\\\"mng\\\",\\\"mac\\\",\\\"mnp\\\",\\\"mtq\\\",\\\"mrt\\\",\\\"msr\\\",\\\"mlt\\\",\\\"mus\\\",\\\"mdv\\\",\\\"mwi\\\",\\\"mex\\\",\\\"mys\\\",\\\"moz\\\",\\\"nam\\\",\\\"ncl\\\",\\\"ner\\\",\\\"nfk\\\",\\\"nga\\\",\\\"nic\\\",\\\"nld\\\",\\\"nor\\\",\\\"npl\\\",\\\"nru\\\",\\\"niu\\\",\\\"nzl\\\",\\\"omn\\\",\\\"pan\\\",\\\"per\\\",\\\"pyf\\\",\\\"phl\\\",\\\"pak\\\",\\\"pol\\\",\\\"spm\\\",\\\"pcn\\\",\\\"pri\\\",\\\"pse\\\",\\\"prt\\\",\\\"plw\\\",\\\"pry\\\",\\\"qat\\\",\\\"reu\\\",\\\"rou\\\",\\\"rwa\\\",\\\"sau\\\",\\\"slb\\\",\\\"syc\\\",\\\"swe\\\",\\\"sgp\\\",\\\"shn\\\",\\\"svn\\\",\\\"sjm\\\",\\\"svk\\\",\\\"sle\\\",\\\"smr\\\",\\\"sen\\\",\\\"sur\\\",\\\"stp\\\",\\\"slv\\\",\\\"sxm\\\",\\\"swz\\\",\\\"tca\\\",\\\"tcd\\\",\\\"atf\\\",\\\"tgo\\\",\\\"tha\\\",\\\"tjk\\\",\\\"tkl\\\",\\\"tls\\\",\\\"tkm\\\",\\\"ton\\\",\\\"tur\\\",\\\"tto\\\",\\\"tuv\\\",\\\"twn\\\",\\\"tza\\\",\\\"umi\\\",\\\"usa\\\",\\\"ury\\\",\\\"uzb\\\",\\\"vat\\\",\\\"vct\\\",\\\"ven\\\",\\\"vgb\\\",\\\"vir\\\",\\\"vnm\\\",\\\"wlf\\\",\\\"wsm\\\",\\\"myt\\\",\\\"zaf\\\",\\\"zmb\\\"],\\\"allowed_shipping_countries\\\":[\\\"and\\\",\\\"are\\\",\\\"atg\\\",\\\"aia\\\",\\\"alb\\\",\\\"arm\\\",\\\"ata\\\",\\\"arg\\\",\\\"asm\\\",\\\"aut\\\",\\\"aus\\\",\\\"abw\\\",\\\"ala\\\",\\\"aze\\\",\\\"brb\\\",\\\"bgd\\\",\\\"bel\\\",\\\"bfa\\\",\\\"bgr\\\",\\\"bhr\\\",\\\"ben\\\",\\\"blm\\\",\\\"bmu\\\",\\\"brn\\\",\\\"bol\\\",\\\"bes\\\",\\\"bra\\\",\\\"bhs\\\",\\\"btn\\\",\\\"bvt\\\",\\\"bwa\\\",\\\"blz\\\",\\\"can\\\",\\\"cck\\\",\\\"che\\\",\\\"cok\\\",\\\"chl\\\",\\\"cmr\\\",\\\"col\\\",\\\"cri\\\",\\\"cub\\\",\\\"cpv\\\",\\\"cuw\\\",\\\"cxr\\\",\\\"cyp\\\",\\\"cze\\\",\\\"deu\\\",\\\"dji\\\",\\\"dnk\\\",\\\"dma\\\",\\\"dom\\\",\\\"dza\\\",\\\"ecu\\\",\\\"est\\\",\\\"esh\\\",\\\"esp\\\",\\\"eth\\\",\\\"fin\\\",\\\"fji\\\",\\\"flk\\\",\\\"fsm\\\",\\\"fro\\\",\\\"fra\\\",\\\"gab\\\",\\\"gbr\\\",\\\"grd\\\",\\\"geo\\\",\\\"guf\\\",\\\"ggy\\\",\\\"gha\\\",\\\"gib\\\",\\\"grl\\\",\\\"gmb\\\",\\\"glp\\\",\\\"gnq\\\",\\\"grc\\\",\\\"sgs\\\",\\\"gtm\\\",\\\"gum\\\",\\\"hkg\\\",\\\"hmd\\\",\\\"hnd\\\",\\\"hrv\\\",\\\"hun\\\",\\\"idn\\\",\\\"irl\\\",\\\"isr\\\",\\\"imn\\\",\\\"ind\\\",\\\"iot\\\",\\\"isl\\\",\\\"ita\\\",\\\"jey\\\",\\\"jam\\\",\\\"jor\\\",\\\"jpn\\\",\\\"ken\\\",\\\"kgz\\\",\\\"khm\\\",\\\"kir\\\",\\\"com\\\",\\\"kna\\\",\\\"kor\\\",\\\"kwt\\\",\\\"cym\\\",\\\"kaz\\\",\\\"lca\\\",\\\"lie\\\",\\\"lka\\\",\\\"lso\\\",\\\"ltu\\\",\\\"lux\\\",\\\"lva\\\",\\\"mar\\\",\\\"mco\\\",\\\"mne\\\",\\\"maf\\\",\\\"mdg\\\",\\\"mhl\\\",\\\"mkd\\\",\\\"mli\\\",\\\"mng\\\",\\\"mac\\\",\\\"mnp\\\",\\\"mtq\\\",\\\"mrt\\\",\\\"msr\\\",\\\"mlt\\\",\\\"mus\\\",\\\"mdv\\\",\\\"mwi\\\",\\\"mex\\\",\\\"mys\\\",\\\"moz\\\",\\\"nam\\\",\\\"ncl\\\",\\\"ner\\\",\\\"nfk\\\",\\\"nga\\\",\\\"nic\\\",\\\"nld\\\",\\\"nor\\\",\\\"npl\\\",\\\"nru\\\",\\\"niu\\\",\\\"nzl\\\",\\\"omn\\\",\\\"pan\\\",\\\"per\\\",\\\"pyf\\\",\\\"phl\\\",\\\"pak\\\",\\\"pol\\\",\\\"spm\\\",\\\"pcn\\\",\\\"pri\\\",\\\"pse\\\",\\\"prt\\\",\\\"plw\\\",\\\"pry\\\",\\\"qat\\\",\\\"reu\\\",\\\"rou\\\",\\\"rwa\\\",\\\"sau\\\",\\\"slb\\\",\\\"syc\\\",\\\"swe\\\",\\\"sgp\\\",\\\"shn\\\",\\\"svn\\\",\\\"sjm\\\",\\\"svk\\\",\\\"sle\\\",\\\"smr\\\",\\\"sen\\\",\\\"sur\\\",\\\"stp\\\",\\\"slv\\\",\\\"sxm\\\",\\\"swz\\\",\\\"tca\\\",\\\"tcd\\\",\\\"atf\\\",\\\"tgo\\\",\\\"tha\\\",\\\"tjk\\\",\\\"tkl\\\",\\\"tls\\\",\\\"tkm\\\",\\\"ton\\\",\\\"tur\\\",\\\"tto\\\",\\\"tuv\\\",\\\"twn\\\",\\\"tza\\\",\\\"umi\\\",\\\"usa\\\",\\\"ury\\\",\\\"uzb\\\",\\\"vat\\\",\\\"vct\\\",\\\"ven\\\",\\\"vgb\\\",\\\"vir\\\",\\\"vnm\\\",\\\"wlf\\\",\\\"wsm\\\",\\\"myt\\\",\\\"zaf\\\",\\\"zmb\\\"],\\\"status\\\":{\\\"prescreened\\\":false,\\\"require_terms_consent\\\":true},\\\"analytics_user_id\\\":\\\"2EUwzTXiwfzWhYBUkPGxmjTIK9_mDMM7vDQo2wk_C7o=\\\",\\\"merchant_urls\\\":{\\\"checkout\\\":\\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\\"confirmation\\\":\\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\\"terms\\\":\\\"https://some-fourth-host.example.com/v1/redirect/terms\\\"},\\\"correlation_id\\\":\\\"f6df29e7-f850-4c36-81fc-11def2f44b81\\\"}\",\n          \"comment\": \"\"\n        },\n        \"headersSize\": 410,\n        \"bodySize\": 5003,\n        \"comment\": \"\"\n      },\n      \"response\": {\n        \"status\": 200,\n        \"statusText\": \"OK\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Cache-Control\",\n          \"value\": \"max-age=0, no-cache, no-store\"\n        }, {\n          \"name\": \"Content-Encoding\",\n          \"value\": \"gzip\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Date\",\n          \"value\": \"Mon, 19 Feb 2018 11:40:10 GMT\"\n        }, {\n          \"name\": \"Correlation-Id\",\n          \"value\": \"a6c51342-b107-4463-a2a0-b530f1bac03e\"\n        }, {\n          \"name\": \"Pragma\",\n          \"value\": \"no-cache\"\n        }, {\n          \"name\": \"Render-Time\",\n          \"value\": \"295\"\n        }, {\n          \"name\": \"Server\",\n          \"value\": \"openresty\"\n        }, {\n          \"name\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains\"\n        }, {\n          \"name\": \"Vary\",\n          \"value\": \"Accept-Encoding\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"1714\"\n        }, {\n          \"name\": \"Connection\",\n          \"value\": \"keep-alive\"\n        }],\n        \"content\": {\n          \"size\": 5588,\n          \"mimeType\": \"application/vnd.checkout.server-order-v1+json\",\n          \"text\": \"{\\n  \\\"shared\\\" : {\\n    \\\"challenge\\\" : {\\n      \\\"email\\\" : \\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\n      \\\"postal_code\\\" : \\\"10066\\\",\\n      \\\"country\\\" : \\\"swe\\\"\\n    },\\n    \\\"billing_address\\\" : {\\n      \\\"given_name\\\" : \\\"Eva InvoiceGreenNewSpec\\\",\\n      \\\"family_name\\\" : \\\"Anglund\\\",\\n      \\\"email\\\" : \\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\n      \\\"street_address\\\" : \\\"Sveavägen 44, 11111 Stockholm, Sweden Eriks Gata gatan\\\",\\n      \\\"street_address2\\\" : \\\"c/o C/O Hakan Ostlund\\\",\\n      \\\"postal_code\\\" : \\\"10066\\\",\\n      \\\"city\\\" : \\\"AlingHelsingstadfors\\\",\\n      \\\"phone\\\" : \\\"070-001 28 78\\\",\\n      \\\"country\\\" : \\\"swe\\\",\\n      \\\"care_of\\\" : \\\"C/O Hakan Ostlund\\\"\\n    },\\n    \\\"customer\\\" : {\\n      \\\"national_identification_number\\\" : \\\"19891021-0312\\\",\\n      \\\"type\\\" : \\\"person\\\"\\n    },\\n    \\\"language\\\" : \\\"sv\\\",\\n    \\\"currency\\\" : \\\"SEK\\\"\\n  },\\n  \\\"cart\\\" : {\\n    \\\"total_tax_amount\\\" : 1206,\\n    \\\"total_price_including_tax\\\" : 16278,\\n    \\\"total_price_excluding_tax\\\" : 15072,\\n    \\\"total_shipping_amount_excluding_tax\\\" : 0,\\n    \\\"total_surcharge_amount_excluding_tax\\\" : 0,\\n    \\\"total_discount_amount_excluding_tax\\\" : 0,\\n    \\\"subtotal\\\" : 15072,\\n    \\\"total_store_credit\\\" : 0,\\n    \\\"items\\\" : [ {\\n      \\\"type\\\" : \\\"physical\\\",\\n      \\\"reference\\\" : \\\"jkwedq9f6t\\\",\\n      \\\"name\\\" : \\\"Mediokra Betong Lampa. Tangentbord\\\",\\n      \\\"quantity\\\" : 1,\\n      \\\"unit_price\\\" : 16278,\\n      \\\"total_tax_amount\\\" : 1206,\\n      \\\"tax_rate\\\" : 800,\\n      \\\"total_price_including_tax\\\" : 16278,\\n      \\\"total_price_excluding_tax\\\" : 15072,\\n      \\\"product_url\\\" : \\\"http://aufderharluettgen.info/haven\\\",\\n      \\\"image_url\\\" : \\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"\\n    } ]\\n  },\\n  \\\"available_payment_methods\\\" : [ {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"invoice\\\",\\n    \\\"data\\\" : {\\n      \\\"days\\\" : 14\\n    }\\n  } ],\\n  \\\"options\\\" : {\\n    \\\"allow_separate_shipping_address\\\" : false,\\n    \\\"date_of_birth_mandatory\\\" : false,\\n    \\\"national_identification_number_mandatory\\\" : false,\\n    \\\"allowed_customer_types\\\" : [ \\\"person\\\" ],\\n    \\\"payment_selector_on_load\\\" : false\\n  },\\n  \\\"allowed_billing_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"allowed_shipping_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"status\\\" : {\\n    \\\"prescreened\\\" : false,\\n    \\\"require_terms_consent\\\" : true\\n  },\\n  \\\"analytics_user_id\\\" : \\\"2EUwzTXiwfzWhYBUkPGxmjTIK9_mDMM7vDQo2wk_C7o=\\\",\\n  \\\"merchant_urls\\\" : {\\n    \\\"checkout\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\n    \\\"confirmation\\\" : \\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\n    \\\"terms\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/terms\\\"\\n  }\\n}\",\n          \"comment\": \"\"\n        },\n        \"redirectURL\": \"\",\n        \"headersSize\": 445,\n        \"bodySize\": 1714,\n        \"comment\": \"\"\n      },\n      \"cache\": {},\n      \"timings\": {\n        \"comment\": \"\",\n        \"dns\": 0,\n        \"connect\": 105,\n        \"send\": 7,\n        \"wait\": 417,\n        \"receive\": 2,\n        \"blocked\": 0,\n        \"ssl\": 62\n      },\n      \"serverIPAddress\": \"10.225.41.52\",\n      \"comment\": \"\",\n      \"time\": 532\n    }, {\n      \"pageref\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:18.394Z\",\n      \"request\": {\n        \"method\": \"POST\",\n        \"url\": \"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Authorization\",\n          \"value\": \"Checkout otherStuffz\"\n        }, {\n          \"name\": \"User-Agent\",\n          \"value\": \"SysTest - perf\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.client-order-v1+json\"\n        }, {\n          \"name\": \"Accept\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Accept-Encoding\",\n          \"value\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\"\n        }, {\n          \"name\": \"Host\",\n          \"value\": \"some-other-host.example.com\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"4774\"\n        }],\n        \"queryString\": [],\n        \"postData\": {\n          \"mimeType\": \"application/vnd.checkout.client-order-v1+json\",\n          \"text\": \"{\\\"shared\\\":{\\\"challenge\\\":{\\\"email\\\":\\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\\"postal_code\\\":\\\"10066\\\",\\\"country\\\":\\\"swe\\\"},\\\"billing_address\\\":{\\\"given_name\\\":\\\"Eva InvoiceGreenNewSpec\\\",\\\"family_name\\\":\\\"Anglund\\\",\\\"email\\\":\\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\\"street_address\\\":\\\"Sveavägen 44, 11111 Stockholm, Sweden Eriks Gata gatan\\\",\\\"street_address2\\\":\\\"c/o C/O Hakan Ostlund\\\",\\\"postal_code\\\":\\\"10066\\\",\\\"city\\\":\\\"AlingHelsingstadfors\\\",\\\"phone\\\":\\\"070-001 28 78\\\",\\\"country\\\":\\\"swe\\\",\\\"care_of\\\":\\\"C/O Hakan Ostlund\\\"},\\\"customer\\\":{\\\"national_identification_number\\\":\\\"19891021-0312\\\",\\\"type\\\":\\\"person\\\"},\\\"language\\\":\\\"sv\\\",\\\"currency\\\":\\\"SEK\\\",\\\"selected_payment_method\\\":{\\\"id\\\":\\\"-1\\\",\\\"type\\\":\\\"invoice\\\",\\\"data\\\":{\\\"days\\\":14}}},\\\"cart\\\":{\\\"total_tax_amount\\\":1206,\\\"total_price_including_tax\\\":16278,\\\"total_price_excluding_tax\\\":15072,\\\"total_shipping_amount_excluding_tax\\\":0,\\\"total_surcharge_amount_excluding_tax\\\":0,\\\"total_discount_amount_excluding_tax\\\":0,\\\"subtotal\\\":15072,\\\"total_store_credit\\\":0,\\\"items\\\":[{\\\"type\\\":\\\"physical\\\",\\\"reference\\\":\\\"jkwedq9f6t\\\",\\\"name\\\":\\\"Mediokra Betong Lampa. Tangentbord\\\",\\\"quantity\\\":1,\\\"unit_price\\\":16278,\\\"total_tax_amount\\\":1206,\\\"tax_rate\\\":800,\\\"total_price_including_tax\\\":16278,\\\"total_price_excluding_tax\\\":15072,\\\"product_url\\\":\\\"http://aufderharluettgen.info/haven\\\",\\\"image_url\\\":\\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"}]},\\\"available_payment_methods\\\":[{\\\"id\\\":\\\"-1\\\",\\\"type\\\":\\\"invoice\\\",\\\"data\\\":{\\\"days\\\":14}}],\\\"options\\\":{\\\"allow_separate_shipping_address\\\":false,\\\"date_of_birth_mandatory\\\":false,\\\"national_identification_number_mandatory\\\":false,\\\"allowed_customer_types\\\":[\\\"person\\\"],\\\"payment_selector_on_load\\\":false},\\\"allowed_billing_countries\\\":[\\\"and\\\",\\\"are\\\",\\\"atg\\\",\\\"aia\\\",\\\"alb\\\",\\\"arm\\\",\\\"ata\\\",\\\"arg\\\",\\\"asm\\\",\\\"aut\\\",\\\"aus\\\",\\\"abw\\\",\\\"ala\\\",\\\"aze\\\",\\\"brb\\\",\\\"bgd\\\",\\\"bel\\\",\\\"bfa\\\",\\\"bgr\\\",\\\"bhr\\\",\\\"ben\\\",\\\"blm\\\",\\\"bmu\\\",\\\"brn\\\",\\\"bol\\\",\\\"bes\\\",\\\"bra\\\",\\\"bhs\\\",\\\"btn\\\",\\\"bvt\\\",\\\"bwa\\\",\\\"blz\\\",\\\"can\\\",\\\"cck\\\",\\\"che\\\",\\\"cok\\\",\\\"chl\\\",\\\"cmr\\\",\\\"col\\\",\\\"cri\\\",\\\"cub\\\",\\\"cpv\\\",\\\"cuw\\\",\\\"cxr\\\",\\\"cyp\\\",\\\"cze\\\",\\\"deu\\\",\\\"dji\\\",\\\"dnk\\\",\\\"dma\\\",\\\"dom\\\",\\\"dza\\\",\\\"ecu\\\",\\\"est\\\",\\\"esh\\\",\\\"esp\\\",\\\"eth\\\",\\\"fin\\\",\\\"fji\\\",\\\"flk\\\",\\\"fsm\\\",\\\"fro\\\",\\\"fra\\\",\\\"gab\\\",\\\"gbr\\\",\\\"grd\\\",\\\"geo\\\",\\\"guf\\\",\\\"ggy\\\",\\\"gha\\\",\\\"gib\\\",\\\"grl\\\",\\\"gmb\\\",\\\"glp\\\",\\\"gnq\\\",\\\"grc\\\",\\\"sgs\\\",\\\"gtm\\\",\\\"gum\\\",\\\"hkg\\\",\\\"hmd\\\",\\\"hnd\\\",\\\"hrv\\\",\\\"hun\\\",\\\"idn\\\",\\\"irl\\\",\\\"isr\\\",\\\"imn\\\",\\\"ind\\\",\\\"iot\\\",\\\"isl\\\",\\\"ita\\\",\\\"jey\\\",\\\"jam\\\",\\\"jor\\\",\\\"jpn\\\",\\\"ken\\\",\\\"kgz\\\",\\\"khm\\\",\\\"kir\\\",\\\"com\\\",\\\"kna\\\",\\\"kor\\\",\\\"kwt\\\",\\\"cym\\\",\\\"kaz\\\",\\\"lca\\\",\\\"lie\\\",\\\"lka\\\",\\\"lso\\\",\\\"ltu\\\",\\\"lux\\\",\\\"lva\\\",\\\"mar\\\",\\\"mco\\\",\\\"mne\\\",\\\"maf\\\",\\\"mdg\\\",\\\"mhl\\\",\\\"mkd\\\",\\\"mli\\\",\\\"mng\\\",\\\"mac\\\",\\\"mnp\\\",\\\"mtq\\\",\\\"mrt\\\",\\\"msr\\\",\\\"mlt\\\",\\\"mus\\\",\\\"mdv\\\",\\\"mwi\\\",\\\"mex\\\",\\\"mys\\\",\\\"moz\\\",\\\"nam\\\",\\\"ncl\\\",\\\"ner\\\",\\\"nfk\\\",\\\"nga\\\",\\\"nic\\\",\\\"nld\\\",\\\"nor\\\",\\\"npl\\\",\\\"nru\\\",\\\"niu\\\",\\\"nzl\\\",\\\"omn\\\",\\\"pan\\\",\\\"per\\\",\\\"pyf\\\",\\\"phl\\\",\\\"pak\\\",\\\"pol\\\",\\\"spm\\\",\\\"pcn\\\",\\\"pri\\\",\\\"pse\\\",\\\"prt\\\",\\\"plw\\\",\\\"pry\\\",\\\"qat\\\",\\\"reu\\\",\\\"rou\\\",\\\"rwa\\\",\\\"sau\\\",\\\"slb\\\",\\\"syc\\\",\\\"swe\\\",\\\"sgp\\\",\\\"shn\\\",\\\"svn\\\",\\\"sjm\\\",\\\"svk\\\",\\\"sle\\\",\\\"smr\\\",\\\"sen\\\",\\\"sur\\\",\\\"stp\\\",\\\"slv\\\",\\\"sxm\\\",\\\"swz\\\",\\\"tca\\\",\\\"tcd\\\",\\\"atf\\\",\\\"tgo\\\",\\\"tha\\\",\\\"tjk\\\",\\\"tkl\\\",\\\"tls\\\",\\\"tkm\\\",\\\"ton\\\",\\\"tur\\\",\\\"tto\\\",\\\"tuv\\\",\\\"twn\\\",\\\"tza\\\",\\\"umi\\\",\\\"usa\\\",\\\"ury\\\",\\\"uzb\\\",\\\"vat\\\",\\\"vct\\\",\\\"ven\\\",\\\"vgb\\\",\\\"vir\\\",\\\"vnm\\\",\\\"wlf\\\",\\\"wsm\\\",\\\"myt\\\",\\\"zaf\\\",\\\"zmb\\\"],\\\"allowed_shipping_countries\\\":[\\\"and\\\",\\\"are\\\",\\\"atg\\\",\\\"aia\\\",\\\"alb\\\",\\\"arm\\\",\\\"ata\\\",\\\"arg\\\",\\\"asm\\\",\\\"aut\\\",\\\"aus\\\",\\\"abw\\\",\\\"ala\\\",\\\"aze\\\",\\\"brb\\\",\\\"bgd\\\",\\\"bel\\\",\\\"bfa\\\",\\\"bgr\\\",\\\"bhr\\\",\\\"ben\\\",\\\"blm\\\",\\\"bmu\\\",\\\"brn\\\",\\\"bol\\\",\\\"bes\\\",\\\"bra\\\",\\\"bhs\\\",\\\"btn\\\",\\\"bvt\\\",\\\"bwa\\\",\\\"blz\\\",\\\"can\\\",\\\"cck\\\",\\\"che\\\",\\\"cok\\\",\\\"chl\\\",\\\"cmr\\\",\\\"col\\\",\\\"cri\\\",\\\"cub\\\",\\\"cpv\\\",\\\"cuw\\\",\\\"cxr\\\",\\\"cyp\\\",\\\"cze\\\",\\\"deu\\\",\\\"dji\\\",\\\"dnk\\\",\\\"dma\\\",\\\"dom\\\",\\\"dza\\\",\\\"ecu\\\",\\\"est\\\",\\\"esh\\\",\\\"esp\\\",\\\"eth\\\",\\\"fin\\\",\\\"fji\\\",\\\"flk\\\",\\\"fsm\\\",\\\"fro\\\",\\\"fra\\\",\\\"gab\\\",\\\"gbr\\\",\\\"grd\\\",\\\"geo\\\",\\\"guf\\\",\\\"ggy\\\",\\\"gha\\\",\\\"gib\\\",\\\"grl\\\",\\\"gmb\\\",\\\"glp\\\",\\\"gnq\\\",\\\"grc\\\",\\\"sgs\\\",\\\"gtm\\\",\\\"gum\\\",\\\"hkg\\\",\\\"hmd\\\",\\\"hnd\\\",\\\"hrv\\\",\\\"hun\\\",\\\"idn\\\",\\\"irl\\\",\\\"isr\\\",\\\"imn\\\",\\\"ind\\\",\\\"iot\\\",\\\"isl\\\",\\\"ita\\\",\\\"jey\\\",\\\"jam\\\",\\\"jor\\\",\\\"jpn\\\",\\\"ken\\\",\\\"kgz\\\",\\\"khm\\\",\\\"kir\\\",\\\"com\\\",\\\"kna\\\",\\\"kor\\\",\\\"kwt\\\",\\\"cym\\\",\\\"kaz\\\",\\\"lca\\\",\\\"lie\\\",\\\"lka\\\",\\\"lso\\\",\\\"ltu\\\",\\\"lux\\\",\\\"lva\\\",\\\"mar\\\",\\\"mco\\\",\\\"mne\\\",\\\"maf\\\",\\\"mdg\\\",\\\"mhl\\\",\\\"mkd\\\",\\\"mli\\\",\\\"mng\\\",\\\"mac\\\",\\\"mnp\\\",\\\"mtq\\\",\\\"mrt\\\",\\\"msr\\\",\\\"mlt\\\",\\\"mus\\\",\\\"mdv\\\",\\\"mwi\\\",\\\"mex\\\",\\\"mys\\\",\\\"moz\\\",\\\"nam\\\",\\\"ncl\\\",\\\"ner\\\",\\\"nfk\\\",\\\"nga\\\",\\\"nic\\\",\\\"nld\\\",\\\"nor\\\",\\\"npl\\\",\\\"nru\\\",\\\"niu\\\",\\\"nzl\\\",\\\"omn\\\",\\\"pan\\\",\\\"per\\\",\\\"pyf\\\",\\\"phl\\\",\\\"pak\\\",\\\"pol\\\",\\\"spm\\\",\\\"pcn\\\",\\\"pri\\\",\\\"pse\\\",\\\"prt\\\",\\\"plw\\\",\\\"pry\\\",\\\"qat\\\",\\\"reu\\\",\\\"rou\\\",\\\"rwa\\\",\\\"sau\\\",\\\"slb\\\",\\\"syc\\\",\\\"swe\\\",\\\"sgp\\\",\\\"shn\\\",\\\"svn\\\",\\\"sjm\\\",\\\"svk\\\",\\\"sle\\\",\\\"smr\\\",\\\"sen\\\",\\\"sur\\\",\\\"stp\\\",\\\"slv\\\",\\\"sxm\\\",\\\"swz\\\",\\\"tca\\\",\\\"tcd\\\",\\\"atf\\\",\\\"tgo\\\",\\\"tha\\\",\\\"tjk\\\",\\\"tkl\\\",\\\"tls\\\",\\\"tkm\\\",\\\"ton\\\",\\\"tur\\\",\\\"tto\\\",\\\"tuv\\\",\\\"twn\\\",\\\"tza\\\",\\\"umi\\\",\\\"usa\\\",\\\"ury\\\",\\\"uzb\\\",\\\"vat\\\",\\\"vct\\\",\\\"ven\\\",\\\"vgb\\\",\\\"vir\\\",\\\"vnm\\\",\\\"wlf\\\",\\\"wsm\\\",\\\"myt\\\",\\\"zaf\\\",\\\"zmb\\\"],\\\"status\\\":{\\\"prescreened\\\":false,\\\"require_terms_consent\\\":true},\\\"analytics_user_id\\\":\\\"2EUwzTXiwfzWhYBUkPGxmjTIK9_mDMM7vDQo2wk_C7o=\\\",\\\"merchant_urls\\\":{\\\"checkout\\\":\\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\\"confirmation\\\":\\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\\"terms\\\":\\\"https://some-fourth-host.example.com/v1/redirect/terms\\\"},\\\"correlation_id\\\":\\\"a6c51342-b107-4463-a2a0-b530f1bac03e\\\"}\",\n          \"comment\": \"\"\n        },\n        \"headersSize\": 410,\n        \"bodySize\": 4774,\n        \"comment\": \"\"\n      },\n      \"response\": {\n        \"status\": 200,\n        \"statusText\": \"OK\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [{\n          \"name\": \"Cache-Control\",\n          \"value\": \"max-age=0, no-cache, no-store\"\n        }, {\n          \"name\": \"Content-Encoding\",\n          \"value\": \"gzip\"\n        }, {\n          \"name\": \"Content-Type\",\n          \"value\": \"application/vnd.checkout.server-order-v1+json\"\n        }, {\n          \"name\": \"Date\",\n          \"value\": \"Mon, 19 Feb 2018 11:40:11 GMT\"\n        }, {\n          \"name\": \"Correlation-Id\",\n          \"value\": \"97fd2531-c0a8-4107-99af-0af60a67176a\"\n        }, {\n          \"name\": \"Pragma\",\n          \"value\": \"no-cache\"\n        }, {\n          \"name\": \"Render-Time\",\n          \"value\": \"1143\"\n        }, {\n          \"name\": \"Server\",\n          \"value\": \"openresty\"\n        }, {\n          \"name\": \"Strict-Transport-Security\",\n          \"value\": \"max-age=31536000; includeSubDomains\"\n        }, {\n          \"name\": \"Vary\",\n          \"value\": \"Accept-Encoding\"\n        }, {\n          \"name\": \"Content-Length\",\n          \"value\": \"1811\"\n        }, {\n          \"name\": \"Connection\",\n          \"value\": \"keep-alive\"\n        }],\n        \"content\": {\n          \"size\": 6184,\n          \"mimeType\": \"application/vnd.checkout.server-order-v1+json\",\n          \"text\": \"{\\n  \\\"shared\\\" : {\\n    \\\"challenge\\\" : {\\n      \\\"email\\\" : \\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\n      \\\"postal_code\\\" : \\\"10066\\\",\\n      \\\"country\\\" : \\\"swe\\\"\\n    },\\n    \\\"billing_address\\\" : {\\n      \\\"given_name\\\" : \\\"Eva InvoiceGreenNewSpec\\\",\\n      \\\"family_name\\\" : \\\"Anglund\\\",\\n      \\\"email\\\" : \\\"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\\\",\\n      \\\"street_address\\\" : \\\"Sveavägen 44, 11111 Stockholm, Sweden Eriks Gata gatan\\\",\\n      \\\"street_address2\\\" : \\\"c/o C/O Hakan Ostlund\\\",\\n      \\\"postal_code\\\" : \\\"10066\\\",\\n      \\\"city\\\" : \\\"AlingHelsingstadfors\\\",\\n      \\\"phone\\\" : \\\"070-001 28 78\\\",\\n      \\\"country\\\" : \\\"swe\\\",\\n      \\\"care_of\\\" : \\\"C/O Hakan Ostlund\\\"\\n    },\\n    \\\"customer\\\" : {\\n      \\\"national_identification_number\\\" : \\\"19891021-0312\\\",\\n      \\\"type\\\" : \\\"person\\\"\\n    },\\n    \\\"selected_payment_method\\\" : {\\n      \\\"id\\\" : \\\"-1\\\",\\n      \\\"type\\\" : \\\"invoice\\\",\\n      \\\"data\\\" : {\\n        \\\"days\\\" : 14\\n      }\\n    },\\n    \\\"language\\\" : \\\"sv\\\",\\n    \\\"currency\\\" : \\\"SEK\\\"\\n  },\\n  \\\"cart\\\" : {\\n    \\\"total_tax_amount\\\" : 1206,\\n    \\\"total_price_including_tax\\\" : 16278,\\n    \\\"total_price_excluding_tax\\\" : 15072,\\n    \\\"total_shipping_amount_excluding_tax\\\" : 0,\\n    \\\"total_surcharge_amount_excluding_tax\\\" : 0,\\n    \\\"total_discount_amount_excluding_tax\\\" : 0,\\n    \\\"subtotal\\\" : 15072,\\n    \\\"total_store_credit\\\" : 0,\\n    \\\"items\\\" : [ {\\n      \\\"type\\\" : \\\"physical\\\",\\n      \\\"reference\\\" : \\\"jkwedq9f6t\\\",\\n      \\\"name\\\" : \\\"Mediokra Betong Lampa. Tangentbord\\\",\\n      \\\"quantity\\\" : 1,\\n      \\\"unit_price\\\" : 16278,\\n      \\\"total_tax_amount\\\" : 1206,\\n      \\\"tax_rate\\\" : 800,\\n      \\\"total_price_including_tax\\\" : 16278,\\n      \\\"total_price_excluding_tax\\\" : 15072,\\n      \\\"product_url\\\" : \\\"http://aufderharluettgen.info/haven\\\",\\n      \\\"image_url\\\" : \\\"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\\\"\\n    } ]\\n  },\\n  \\\"authorized_payment_method\\\" : {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"invoice\\\",\\n    \\\"data\\\" : {\\n      \\\"days\\\" : 14\\n    }\\n  },\\n  \\\"redirect_uri\\\" : \\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\n  \\\"options\\\" : {\\n    \\\"allow_separate_shipping_address\\\" : false,\\n    \\\"date_of_birth_mandatory\\\" : false,\\n    \\\"national_identification_number_mandatory\\\" : false,\\n    \\\"allowed_customer_types\\\" : [ \\\"person\\\" ],\\n    \\\"payment_selector_on_load\\\" : false\\n  },\\n  \\\"preview_payment_methods\\\" : [ {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"invoice\\\",\\n    \\\"data\\\" : {\\n      \\\"days\\\" : 14\\n    }\\n  }, {\\n    \\\"id\\\" : \\\"-1\\\",\\n    \\\"type\\\" : \\\"credit_card\\\",\\n    \\\"data\\\" : {\\n      \\\"available_cards\\\" : [ \\\"VISA\\\", \\\"MASTER\\\" ],\\n      \\\"allow_saved_card\\\" : false,\\n      \\\"do_save_card\\\" : false\\n    }\\n  } ],\\n  \\\"allowed_billing_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"allowed_shipping_countries\\\" : [ \\\"and\\\", \\\"are\\\", \\\"atg\\\", \\\"aia\\\", \\\"alb\\\", \\\"arm\\\", \\\"ata\\\", \\\"arg\\\", \\\"asm\\\", \\\"aut\\\", \\\"aus\\\", \\\"abw\\\", \\\"ala\\\", \\\"aze\\\", \\\"brb\\\", \\\"bgd\\\", \\\"bel\\\", \\\"bfa\\\", \\\"bgr\\\", \\\"bhr\\\", \\\"ben\\\", \\\"blm\\\", \\\"bmu\\\", \\\"brn\\\", \\\"bol\\\", \\\"bes\\\", \\\"bra\\\", \\\"bhs\\\", \\\"btn\\\", \\\"bvt\\\", \\\"bwa\\\", \\\"blz\\\", \\\"can\\\", \\\"cck\\\", \\\"che\\\", \\\"cok\\\", \\\"chl\\\", \\\"cmr\\\", \\\"col\\\", \\\"cri\\\", \\\"cub\\\", \\\"cpv\\\", \\\"cuw\\\", \\\"cxr\\\", \\\"cyp\\\", \\\"cze\\\", \\\"deu\\\", \\\"dji\\\", \\\"dnk\\\", \\\"dma\\\", \\\"dom\\\", \\\"dza\\\", \\\"ecu\\\", \\\"est\\\", \\\"esh\\\", \\\"esp\\\", \\\"eth\\\", \\\"fin\\\", \\\"fji\\\", \\\"flk\\\", \\\"fsm\\\", \\\"fro\\\", \\\"fra\\\", \\\"gab\\\", \\\"gbr\\\", \\\"grd\\\", \\\"geo\\\", \\\"guf\\\", \\\"ggy\\\", \\\"gha\\\", \\\"gib\\\", \\\"grl\\\", \\\"gmb\\\", \\\"glp\\\", \\\"gnq\\\", \\\"grc\\\", \\\"sgs\\\", \\\"gtm\\\", \\\"gum\\\", \\\"hkg\\\", \\\"hmd\\\", \\\"hnd\\\", \\\"hrv\\\", \\\"hun\\\", \\\"idn\\\", \\\"irl\\\", \\\"isr\\\", \\\"imn\\\", \\\"ind\\\", \\\"iot\\\", \\\"isl\\\", \\\"ita\\\", \\\"jey\\\", \\\"jam\\\", \\\"jor\\\", \\\"jpn\\\", \\\"ken\\\", \\\"kgz\\\", \\\"khm\\\", \\\"kir\\\", \\\"com\\\", \\\"kna\\\", \\\"kor\\\", \\\"kwt\\\", \\\"cym\\\", \\\"kaz\\\", \\\"lca\\\", \\\"lie\\\", \\\"lka\\\", \\\"lso\\\", \\\"ltu\\\", \\\"lux\\\", \\\"lva\\\", \\\"mar\\\", \\\"mco\\\", \\\"mne\\\", \\\"maf\\\", \\\"mdg\\\", \\\"mhl\\\", \\\"mkd\\\", \\\"mli\\\", \\\"mng\\\", \\\"mac\\\", \\\"mnp\\\", \\\"mtq\\\", \\\"mrt\\\", \\\"msr\\\", \\\"mlt\\\", \\\"mus\\\", \\\"mdv\\\", \\\"mwi\\\", \\\"mex\\\", \\\"mys\\\", \\\"moz\\\", \\\"nam\\\", \\\"ncl\\\", \\\"ner\\\", \\\"nfk\\\", \\\"nga\\\", \\\"nic\\\", \\\"nld\\\", \\\"nor\\\", \\\"npl\\\", \\\"nru\\\", \\\"niu\\\", \\\"nzl\\\", \\\"omn\\\", \\\"pan\\\", \\\"per\\\", \\\"pyf\\\", \\\"phl\\\", \\\"pak\\\", \\\"pol\\\", \\\"spm\\\", \\\"pcn\\\", \\\"pri\\\", \\\"pse\\\", \\\"prt\\\", \\\"plw\\\", \\\"pry\\\", \\\"qat\\\", \\\"reu\\\", \\\"rou\\\", \\\"rwa\\\", \\\"sau\\\", \\\"slb\\\", \\\"syc\\\", \\\"swe\\\", \\\"sgp\\\", \\\"shn\\\", \\\"svn\\\", \\\"sjm\\\", \\\"svk\\\", \\\"sle\\\", \\\"smr\\\", \\\"sen\\\", \\\"sur\\\", \\\"stp\\\", \\\"slv\\\", \\\"sxm\\\", \\\"swz\\\", \\\"tca\\\", \\\"tcd\\\", \\\"atf\\\", \\\"tgo\\\", \\\"tha\\\", \\\"tjk\\\", \\\"tkl\\\", \\\"tls\\\", \\\"tkm\\\", \\\"ton\\\", \\\"tur\\\", \\\"tto\\\", \\\"tuv\\\", \\\"twn\\\", \\\"tza\\\", \\\"umi\\\", \\\"usa\\\", \\\"ury\\\", \\\"uzb\\\", \\\"vat\\\", \\\"vct\\\", \\\"ven\\\", \\\"vgb\\\", \\\"vir\\\", \\\"vnm\\\", \\\"wlf\\\", \\\"wsm\\\", \\\"myt\\\", \\\"zaf\\\", \\\"zmb\\\" ],\\n  \\\"status\\\" : {\\n    \\\"prescreened\\\" : false,\\n    \\\"require_terms_consent\\\" : true\\n  },\\n  \\\"analytics_user_id\\\" : \\\"2EUwzTXiwfzWhYBUkPGxmjTIK9_mDMM7vDQo2wk_C7o=\\\",\\n  \\\"merchant_urls\\\" : {\\n    \\\"checkout\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/checkout\\\",\\n    \\\"confirmation\\\" : \\\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25/redirect?auth_token=otherStuffz\\\",\\n    \\\"terms\\\" : \\\"https://some-fourth-host.example.com/v1/redirect/terms\\\"\\n  }\\n}\",\n          \"comment\": \"\"\n        },\n        \"redirectURL\": \"\",\n        \"headersSize\": 446,\n        \"bodySize\": 1811,\n        \"comment\": \"\"\n      },\n      \"cache\": {},\n      \"timings\": {\n        \"comment\": \"\",\n        \"dns\": 0,\n        \"connect\": 100,\n        \"send\": 4,\n        \"wait\": 1288,\n        \"receive\": 1,\n        \"blocked\": 0,\n        \"ssl\": 61\n      },\n      \"serverIPAddress\": \"10.225.41.52\",\n      \"comment\": \"\",\n      \"time\": 1395\n    }, {\n      \"pageref\": \"Page 0\",\n      \"startedDateTime\": \"2018-02-19T11:40:19.713Z\",\n      \"request\": {\n        \"method\": \"CONNECT\",\n        \"url\": \"https://a-third-host.example.com:3000\",\n        \"httpVersion\": \"HTTP/1.1\",\n        \"cookies\": [],\n        \"headers\": [],\n        \"queryString\": [],\n        \"headersSize\": 0,\n        \"bodySize\": 0,\n        \"comment\": \"\"\n      },\n      \"response\": {\n        \"status\": 0,\n        \"statusText\": \"\",\n        \"httpVersion\": \"unknown\",\n        \"cookies\": [],\n        \"headers\": [],\n        \"content\": {\n          \"size\": 0,\n          \"mimeType\": \"\",\n          \"comment\": \"\"\n        },\n        \"redirectURL\": \"\",\n        \"headersSize\": -1,\n        \"bodySize\": -1,\n        \"comment\": \"\",\n        \"_error\": \"Unable to connect to host\"\n      },\n      \"cache\": {},\n      \"timings\": {\n        \"comment\": \"\",\n        \"dns\": 32,\n        \"connect\": 105,\n        \"send\": 0,\n        \"wait\": 0,\n        \"receive\": 0,\n        \"blocked\": 0,\n        \"ssl\": -1\n      },\n      \"serverIPAddress\": \"10.225.25.62\",\n      \"comment\": \"\",\n      \"time\": 138\n    }],\n    \"comment\": \"\"\n  }\n}\n"
  },
  {
    "path": "internal/cmd/testdata/example.js",
    "content": "import { group, check, sleep } from 'k6';\nimport http from 'k6/http';\n\n// Version: 1.2\n// Creator: BrowserMob Proxy\n\nexport let options = {\n    maxRedirects: 0,\n};\n\nexport default function() {\n\n\tgroup(\"Page 0 - Page 0 ţ€$ţɨɲǥ µɲɨȼ๏ď€ ɨɲ Ќ6 \\\" \\x00\\n\\t♥\\u2028\", function() {\n\t\tlet res, redirectUrl, json;\n\t\t// Request #0\n\t\tres = http.post(\"https://some-host.example.com/checkout/v3/orders\",\n\t\t\t`{\n\t\t\t\t\"locale\": \"sv-SE\",\n\t\t\t\t\"merchant_urls\": {\n\t\t\t\t\t\"checkout\": \"https://some-fourth-host.example.com/v1/redirect/checkout\",\n\t\t\t\t\t\"confirmation\": \"https://some-fourth-host.example.com/v1/redirect/confirm\",\n\t\t\t\t\t\"push\": \"https://some-fourth-host.example.com/v1/callback/push/{checkout.order.id}?merchant_id=smi-merchant-all-validation\\u0026env=perf\",\n\t\t\t\t\t\"terms\": \"https://some-fourth-host.example.com/v1/redirect/terms\"\n\t\t\t\t},\n\t\t\t\t\"options\": {},\n\t\t\t\t\"order_amount\": 16278,\n\t\t\t\t\"order_lines\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"image_url\": \"https://s3-eu-west-1.amazonaws.com/s3.example.net/my/system-test/images/7.jpg\",\n\t\t\t\t\t\t\"name\": \"Mediokra Betong Lampa. Tangentbord\",\n\t\t\t\t\t\t\"product_url\": \"http://aufderharluettgen.info/haven\",\n\t\t\t\t\t\t\"quantity\": 1,\n\t\t\t\t\t\t\"quantity_unit\": \"kg\",\n\t\t\t\t\t\t\"reference\": \"jkwedq9f6t\",\n\t\t\t\t\t\t\"tax_rate\": 800,\n\t\t\t\t\t\t\"total_amount\": 16278,\n\t\t\t\t\t\t\"total_discount_amount\": 0,\n\t\t\t\t\t\t\"total_tax_amount\": 1206,\n\t\t\t\t\t\t\"type\": \"physical\",\n\t\t\t\t\t\t\"unit_price\": 16278\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"order_tax_amount\": 1206,\n\t\t\t\t\"purchase_country\": \"se\",\n\t\t\t\t\"purchase_currency\": \"SEK\",\n\t\t\t\t\"shipping_countries\": [\"AD\", \"AE\", \"AG\", \"AI\", \"AL\", \"AM\", \"AQ\", \"AR\", \"AS\", \"AT\", \"AU\", \"AW\", \"AX\", \"AZ\", \"BB\", \"BD\", \"BE\", \"BF\", \"BG\", \"BH\", \"BJ\", \"BL\", \"BM\", \"BN\", \"BO\", \"BQ\", \"BR\", \"BS\", \"BT\", \"BV\", \"BW\", \"BZ\", \"CA\", \"CC\", \"CH\", \"CK\", \"CL\", \"CM\", \"CO\", \"CR\", \"CU\", \"CV\", \"CW\", \"CX\", \"CY\", \"CZ\", \"DE\", \"DJ\", \"DK\", \"DM\", \"DO\", \"DZ\", \"EC\", \"EE\", \"EH\", \"ES\", \"ET\", \"FI\", \"FJ\", \"FK\", \"FM\", \"FO\", \"FR\", \"GA\", \"GB\", \"GD\", \"GE\", \"GF\", \"GG\", \"GH\", \"GI\", \"GL\", \"GM\", \"GP\", \"GQ\", \"GR\", \"GS\", \"GT\", \"GU\", \"HK\", \"HM\", \"HN\", \"HR\", \"HU\", \"ID\", \"IE\", \"IL\", \"IM\", \"IN\", \"IO\", \"IS\", \"IT\", \"JE\", \"JM\", \"JO\", \"JP\", \"KE\", \"KG\", \"KH\", \"KI\", \"KM\", \"KN\", \"KR\", \"KW\", \"KY\", \"KZ\", \"LC\", \"LI\", \"LK\", \"LS\", \"LT\", \"LU\", \"LV\", \"MA\", \"MC\", \"ME\", \"MF\", \"MG\", \"MH\", \"MK\", \"ML\", \"MN\", \"MO\", \"MP\", \"MQ\", \"MR\", \"MS\", \"MT\", \"MU\", \"MV\", \"MW\", \"MX\", \"MY\", \"MZ\", \"NA\", \"NC\", \"NE\", \"NF\", \"NG\", \"NI\", \"NL\", \"NO\", \"NP\", \"NR\", \"NU\", \"NZ\", \"OM\", \"PA\", \"PE\", \"PF\", \"PH\", \"PK\", \"PL\", \"PM\", \"PN\", \"PR\", \"PS\", \"PT\", \"PW\", \"PY\", \"QA\", \"RE\", \"RO\", \"RW\", \"SA\", \"SB\", \"SC\", \"SE\", \"SG\", \"SH\", \"SI\", \"SJ\", \"SK\", \"SL\", \"SM\", \"SN\", \"SR\", \"ST\", \"SV\", \"SX\", \"SZ\", \"TC\", \"TD\", \"TF\", \"TG\", \"TH\", \"TJ\", \"TK\", \"TL\", \"TM\", \"TO\", \"TR\", \"TT\", \"TV\", \"TW\", \"TZ\", \"UM\", \"US\", \"UY\", \"UZ\", \"VA\", \"VC\", \"VE\", \"VG\", \"VI\", \"VN\", \"WF\", \"WS\", \"YT\", \"ZA\", \"ZM\"]\n\t\t\t}`,\n\t\t\t{\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"Authorization\": \"Basic stuffz\",\n\t\t\t\t\t\"User-Agent\": \"SysTest - perf\",\n\t\t\t\t\t\"Accept\": \"application/json; charset=utf-8\",\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\",\n\t\t\t\t\t\"Host\": \"some-host.example.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t\tif (!check(res, {\"status is 201\": (r) => r.status === 201 })) { return };\n\t\tredirectUrl = res.headers.Location;\n\t\tjson = JSON.parse(res.body);\n\t\t// Request #1\n\t\tres = http.get(redirectUrl,\n\t\t\t{\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"Authorization\": \"Basic stuffz\",\n\t\t\t\t\t\"User-Agent\": \"SysTest - perf\",\n\t\t\t\t\t\"Accept\": \"application/json; charset=utf-8\",\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\",\n\t\t\t\t\t\"Host\": \"some-host.example.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t\tif (!check(res, {\"status is 200\": (r) => r.status === 200 })) { return };\n\t\tjson = JSON.parse(res.body);\n\t\t// Request #2\n\t\tres = http.get(\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n\t\t\t{\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"Authorization\": \"Checkout otherStuffz\",\n\t\t\t\t\t\"User-Agent\": \"SysTest - perf\",\n\t\t\t\t\t\"Accept\": \"application/vnd.checkout.server-order-v1+json\",\n\t\t\t\t\t\"Content-Type\": \"application/vnd.checkout.client-order-v1+json\",\n\t\t\t\t\t\"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\",\n\t\t\t\t\t\"Host\": \"some-other-host.example.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t\tif (!check(res, {\"status is 200\": (r) => r.status === 200 })) { return };\n\t\tjson = JSON.parse(res.body);\n\t\t// Request #3\n\t\tres = http.post(\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n\t\t\t`{\n\t\t\t\t\"allowed_billing_countries\": [\"${json.allowed_billing_countries[0]}\", \"${json.allowed_billing_countries[1]}\", \"${json.allowed_billing_countries[2]}\", \"${json.allowed_billing_countries[3]}\", \"${json.allowed_billing_countries[4]}\", \"${json.allowed_billing_countries[5]}\", \"${json.allowed_billing_countries[6]}\", \"${json.allowed_billing_countries[7]}\", \"${json.allowed_billing_countries[8]}\", \"${json.allowed_billing_countries[9]}\", \"${json.allowed_billing_countries[10]}\", \"${json.allowed_billing_countries[11]}\", \"${json.allowed_billing_countries[12]}\", \"${json.allowed_billing_countries[13]}\", \"${json.allowed_billing_countries[14]}\", \"${json.allowed_billing_countries[15]}\", \"${json.allowed_billing_countries[16]}\", \"${json.allowed_billing_countries[17]}\", \"${json.allowed_billing_countries[18]}\", \"${json.allowed_billing_countries[19]}\", \"${json.allowed_billing_countries[20]}\", \"${json.allowed_billing_countries[21]}\", \"${json.allowed_billing_countries[22]}\", \"${json.allowed_billing_countries[23]}\", \"${json.allowed_billing_countries[24]}\", \"${json.allowed_billing_countries[25]}\", \"${json.allowed_billing_countries[26]}\", \"${json.allowed_billing_countries[27]}\", \"${json.allowed_billing_countries[28]}\", \"${json.allowed_billing_countries[29]}\", \"${json.allowed_billing_countries[30]}\", \"${json.allowed_billing_countries[31]}\", \"${json.allowed_billing_countries[32]}\", \"${json.allowed_billing_countries[33]}\", \"${json.allowed_billing_countries[34]}\", \"${json.allowed_billing_countries[35]}\", \"${json.allowed_billing_countries[36]}\", \"${json.allowed_billing_countries[37]}\", \"${json.allowed_billing_countries[38]}\", \"${json.allowed_billing_countries[39]}\", \"${json.allowed_billing_countries[40]}\", \"${json.allowed_billing_countries[41]}\", \"${json.allowed_billing_countries[42]}\", \"${json.allowed_billing_countries[43]}\", \"${json.allowed_billing_countries[44]}\", \"${json.allowed_billing_countries[45]}\", \"${json.allowed_billing_countries[46]}\", \"${json.allowed_billing_countries[47]}\", \"${json.allowed_billing_countries[48]}\", \"${json.allowed_billing_countries[49]}\", \"${json.allowed_billing_countries[50]}\", \"${json.allowed_billing_countries[51]}\", \"${json.allowed_billing_countries[52]}\", \"${json.allowed_billing_countries[53]}\", \"${json.allowed_billing_countries[54]}\", \"${json.allowed_billing_countries[55]}\", \"${json.allowed_billing_countries[56]}\", \"${json.allowed_billing_countries[57]}\", \"${json.allowed_billing_countries[58]}\", \"${json.allowed_billing_countries[59]}\", \"${json.allowed_billing_countries[60]}\", \"${json.allowed_billing_countries[61]}\", \"${json.allowed_billing_countries[62]}\", \"${json.allowed_billing_countries[63]}\", \"${json.allowed_billing_countries[64]}\", \"${json.allowed_billing_countries[65]}\", \"${json.allowed_billing_countries[66]}\", \"${json.allowed_billing_countries[67]}\", \"${json.allowed_billing_countries[68]}\", \"${json.allowed_billing_countries[69]}\", \"${json.allowed_billing_countries[70]}\", \"${json.allowed_billing_countries[71]}\", \"${json.allowed_billing_countries[72]}\", \"${json.allowed_billing_countries[73]}\", \"${json.allowed_billing_countries[74]}\", \"${json.allowed_billing_countries[75]}\", \"${json.allowed_billing_countries[76]}\", \"${json.allowed_billing_countries[77]}\", \"${json.allowed_billing_countries[78]}\", \"${json.allowed_billing_countries[79]}\", \"${json.allowed_billing_countries[80]}\", \"${json.allowed_billing_countries[81]}\", \"${json.allowed_billing_countries[82]}\", \"${json.allowed_billing_countries[83]}\", \"${json.allowed_billing_countries[84]}\", \"${json.allowed_billing_countries[85]}\", \"${json.allowed_billing_countries[86]}\", \"${json.allowed_billing_countries[87]}\", \"${json.allowed_billing_countries[88]}\", \"${json.allowed_billing_countries[89]}\", \"${json.allowed_billing_countries[90]}\", \"${json.allowed_billing_countries[91]}\", \"${json.allowed_billing_countries[92]}\", \"${json.allowed_billing_countries[93]}\", \"${json.allowed_billing_countries[94]}\", \"${json.allowed_billing_countries[95]}\", \"${json.allowed_billing_countries[96]}\", \"${json.allowed_billing_countries[97]}\", \"${json.allowed_billing_countries[98]}\", \"${json.allowed_billing_countries[99]}\", \"${json.allowed_billing_countries[100]}\", \"${json.allowed_billing_countries[101]}\", \"${json.allowed_billing_countries[102]}\", \"${json.allowed_billing_countries[103]}\", \"${json.allowed_billing_countries[104]}\", \"${json.allowed_billing_countries[105]}\", \"${json.allowed_billing_countries[106]}\", \"${json.allowed_billing_countries[107]}\", \"${json.allowed_billing_countries[108]}\", \"${json.allowed_billing_countries[109]}\", \"${json.allowed_billing_countries[110]}\", \"${json.allowed_billing_countries[111]}\", \"${json.allowed_billing_countries[112]}\", \"${json.allowed_billing_countries[113]}\", \"${json.allowed_billing_countries[114]}\", \"${json.allowed_billing_countries[115]}\", \"${json.allowed_billing_countries[116]}\", \"${json.allowed_billing_countries[117]}\", \"${json.allowed_billing_countries[118]}\", \"${json.allowed_billing_countries[119]}\", \"${json.allowed_billing_countries[120]}\", \"${json.allowed_billing_countries[121]}\", \"${json.allowed_billing_countries[122]}\", \"${json.allowed_billing_countries[123]}\", \"${json.allowed_billing_countries[124]}\", \"${json.allowed_billing_countries[125]}\", \"${json.allowed_billing_countries[126]}\", \"${json.allowed_billing_countries[127]}\", \"${json.allowed_billing_countries[128]}\", \"${json.allowed_billing_countries[129]}\", \"${json.allowed_billing_countries[130]}\", \"${json.allowed_billing_countries[131]}\", \"${json.allowed_billing_countries[132]}\", \"${json.allowed_billing_countries[133]}\", \"${json.allowed_billing_countries[134]}\", \"${json.allowed_billing_countries[135]}\", \"${json.allowed_billing_countries[136]}\", \"${json.allowed_billing_countries[137]}\", \"${json.allowed_billing_countries[138]}\", \"${json.allowed_billing_countries[139]}\", \"${json.allowed_billing_countries[140]}\", \"${json.allowed_billing_countries[141]}\", \"${json.allowed_billing_countries[142]}\", \"${json.allowed_billing_countries[143]}\", \"${json.allowed_billing_countries[144]}\", \"${json.allowed_billing_countries[145]}\", \"${json.allowed_billing_countries[146]}\", \"${json.allowed_billing_countries[147]}\", \"${json.allowed_billing_countries[148]}\", \"${json.allowed_billing_countries[149]}\", \"${json.allowed_billing_countries[150]}\", \"${json.allowed_billing_countries[151]}\", \"${json.allowed_billing_countries[152]}\", \"${json.allowed_billing_countries[153]}\", \"${json.allowed_billing_countries[154]}\", \"${json.allowed_billing_countries[155]}\", \"${json.allowed_billing_countries[156]}\", \"${json.allowed_billing_countries[157]}\", \"${json.allowed_billing_countries[158]}\", \"${json.allowed_billing_countries[159]}\", \"${json.allowed_billing_countries[160]}\", \"${json.allowed_billing_countries[161]}\", \"${json.allowed_billing_countries[162]}\", \"${json.allowed_billing_countries[163]}\", \"${json.allowed_billing_countries[164]}\", \"${json.allowed_billing_countries[165]}\", \"${json.allowed_billing_countries[166]}\", \"${json.allowed_billing_countries[167]}\", \"${json.allowed_billing_countries[168]}\", \"${json.allowed_billing_countries[169]}\", \"${json.allowed_billing_countries[170]}\", \"${json.allowed_billing_countries[171]}\", \"${json.allowed_billing_countries[172]}\", \"${json.allowed_billing_countries[173]}\", \"${json.allowed_billing_countries[174]}\", \"${json.allowed_billing_countries[175]}\", \"${json.allowed_billing_countries[176]}\", \"${json.allowed_billing_countries[177]}\", \"${json.allowed_billing_countries[178]}\", \"${json.allowed_billing_countries[179]}\", \"${json.allowed_billing_countries[180]}\", \"${json.allowed_billing_countries[181]}\", \"${json.allowed_billing_countries[182]}\", \"${json.allowed_billing_countries[183]}\", \"${json.allowed_billing_countries[184]}\", \"${json.allowed_billing_countries[185]}\", \"${json.allowed_billing_countries[186]}\", \"${json.allowed_billing_countries[187]}\", \"${json.allowed_billing_countries[188]}\", \"${json.allowed_billing_countries[189]}\", \"${json.allowed_billing_countries[190]}\", \"${json.allowed_billing_countries[191]}\", \"${json.allowed_billing_countries[192]}\", \"${json.allowed_billing_countries[193]}\", \"${json.allowed_billing_countries[194]}\", \"${json.allowed_billing_countries[195]}\", \"${json.allowed_billing_countries[196]}\", \"${json.allowed_billing_countries[197]}\", \"${json.allowed_billing_countries[198]}\", \"${json.allowed_billing_countries[199]}\", \"${json.allowed_billing_countries[200]}\", \"${json.allowed_billing_countries[201]}\", \"${json.allowed_billing_countries[202]}\", \"${json.allowed_billing_countries[203]}\", \"${json.allowed_billing_countries[204]}\", \"${json.allowed_billing_countries[205]}\", \"${json.allowed_billing_countries[206]}\", \"${json.allowed_billing_countries[207]}\", \"${json.allowed_billing_countries[208]}\", \"${json.allowed_billing_countries[209]}\", \"${json.allowed_billing_countries[210]}\"],\n\t\t\t\t\"allowed_shipping_countries\": [\"${json.allowed_shipping_countries[0]}\", \"${json.allowed_shipping_countries[1]}\", \"${json.allowed_shipping_countries[2]}\", \"${json.allowed_shipping_countries[3]}\", \"${json.allowed_shipping_countries[4]}\", \"${json.allowed_shipping_countries[5]}\", \"${json.allowed_shipping_countries[6]}\", \"${json.allowed_shipping_countries[7]}\", \"${json.allowed_shipping_countries[8]}\", \"${json.allowed_shipping_countries[9]}\", \"${json.allowed_shipping_countries[10]}\", \"${json.allowed_shipping_countries[11]}\", \"${json.allowed_shipping_countries[12]}\", \"${json.allowed_shipping_countries[13]}\", \"${json.allowed_shipping_countries[14]}\", \"${json.allowed_shipping_countries[15]}\", \"${json.allowed_shipping_countries[16]}\", \"${json.allowed_shipping_countries[17]}\", \"${json.allowed_shipping_countries[18]}\", \"${json.allowed_shipping_countries[19]}\", \"${json.allowed_shipping_countries[20]}\", \"${json.allowed_shipping_countries[21]}\", \"${json.allowed_shipping_countries[22]}\", \"${json.allowed_shipping_countries[23]}\", \"${json.allowed_shipping_countries[24]}\", \"${json.allowed_shipping_countries[25]}\", \"${json.allowed_shipping_countries[26]}\", \"${json.allowed_shipping_countries[27]}\", \"${json.allowed_shipping_countries[28]}\", \"${json.allowed_shipping_countries[29]}\", \"${json.allowed_shipping_countries[30]}\", \"${json.allowed_shipping_countries[31]}\", \"${json.allowed_shipping_countries[32]}\", \"${json.allowed_shipping_countries[33]}\", \"${json.allowed_shipping_countries[34]}\", \"${json.allowed_shipping_countries[35]}\", \"${json.allowed_shipping_countries[36]}\", \"${json.allowed_shipping_countries[37]}\", \"${json.allowed_shipping_countries[38]}\", \"${json.allowed_shipping_countries[39]}\", \"${json.allowed_shipping_countries[40]}\", \"${json.allowed_shipping_countries[41]}\", \"${json.allowed_shipping_countries[42]}\", \"${json.allowed_shipping_countries[43]}\", \"${json.allowed_shipping_countries[44]}\", \"${json.allowed_shipping_countries[45]}\", \"${json.allowed_shipping_countries[46]}\", \"${json.allowed_shipping_countries[47]}\", \"${json.allowed_shipping_countries[48]}\", \"${json.allowed_shipping_countries[49]}\", \"${json.allowed_shipping_countries[50]}\", \"${json.allowed_shipping_countries[51]}\", \"${json.allowed_shipping_countries[52]}\", \"${json.allowed_shipping_countries[53]}\", \"${json.allowed_shipping_countries[54]}\", \"${json.allowed_shipping_countries[55]}\", \"${json.allowed_shipping_countries[56]}\", \"${json.allowed_shipping_countries[57]}\", \"${json.allowed_shipping_countries[58]}\", \"${json.allowed_shipping_countries[59]}\", \"${json.allowed_shipping_countries[60]}\", \"${json.allowed_shipping_countries[61]}\", \"${json.allowed_shipping_countries[62]}\", \"${json.allowed_shipping_countries[63]}\", \"${json.allowed_shipping_countries[64]}\", \"${json.allowed_shipping_countries[65]}\", \"${json.allowed_shipping_countries[66]}\", \"${json.allowed_shipping_countries[67]}\", \"${json.allowed_shipping_countries[68]}\", \"${json.allowed_shipping_countries[69]}\", \"${json.allowed_shipping_countries[70]}\", \"${json.allowed_shipping_countries[71]}\", \"${json.allowed_shipping_countries[72]}\", \"${json.allowed_shipping_countries[73]}\", \"${json.allowed_shipping_countries[74]}\", \"${json.allowed_shipping_countries[75]}\", \"${json.allowed_shipping_countries[76]}\", \"${json.allowed_shipping_countries[77]}\", \"${json.allowed_shipping_countries[78]}\", \"${json.allowed_shipping_countries[79]}\", \"${json.allowed_shipping_countries[80]}\", \"${json.allowed_shipping_countries[81]}\", \"${json.allowed_shipping_countries[82]}\", \"${json.allowed_shipping_countries[83]}\", \"${json.allowed_shipping_countries[84]}\", \"${json.allowed_shipping_countries[85]}\", \"${json.allowed_shipping_countries[86]}\", \"${json.allowed_shipping_countries[87]}\", \"${json.allowed_shipping_countries[88]}\", \"${json.allowed_shipping_countries[89]}\", \"${json.allowed_shipping_countries[90]}\", \"${json.allowed_shipping_countries[91]}\", \"${json.allowed_shipping_countries[92]}\", \"${json.allowed_shipping_countries[93]}\", \"${json.allowed_shipping_countries[94]}\", \"${json.allowed_shipping_countries[95]}\", \"${json.allowed_shipping_countries[96]}\", \"${json.allowed_shipping_countries[97]}\", \"${json.allowed_shipping_countries[98]}\", \"${json.allowed_shipping_countries[99]}\", \"${json.allowed_shipping_countries[100]}\", \"${json.allowed_shipping_countries[101]}\", \"${json.allowed_shipping_countries[102]}\", \"${json.allowed_shipping_countries[103]}\", \"${json.allowed_shipping_countries[104]}\", \"${json.allowed_shipping_countries[105]}\", \"${json.allowed_shipping_countries[106]}\", \"${json.allowed_shipping_countries[107]}\", \"${json.allowed_shipping_countries[108]}\", \"${json.allowed_shipping_countries[109]}\", \"${json.allowed_shipping_countries[110]}\", \"${json.allowed_shipping_countries[111]}\", \"${json.allowed_shipping_countries[112]}\", \"${json.allowed_shipping_countries[113]}\", \"${json.allowed_shipping_countries[114]}\", \"${json.allowed_shipping_countries[115]}\", \"${json.allowed_shipping_countries[116]}\", \"${json.allowed_shipping_countries[117]}\", \"${json.allowed_shipping_countries[118]}\", \"${json.allowed_shipping_countries[119]}\", \"${json.allowed_shipping_countries[120]}\", \"${json.allowed_shipping_countries[121]}\", \"${json.allowed_shipping_countries[122]}\", \"${json.allowed_shipping_countries[123]}\", \"${json.allowed_shipping_countries[124]}\", \"${json.allowed_shipping_countries[125]}\", \"${json.allowed_shipping_countries[126]}\", \"${json.allowed_shipping_countries[127]}\", \"${json.allowed_shipping_countries[128]}\", \"${json.allowed_shipping_countries[129]}\", \"${json.allowed_shipping_countries[130]}\", \"${json.allowed_shipping_countries[131]}\", \"${json.allowed_shipping_countries[132]}\", \"${json.allowed_shipping_countries[133]}\", \"${json.allowed_shipping_countries[134]}\", \"${json.allowed_shipping_countries[135]}\", \"${json.allowed_shipping_countries[136]}\", \"${json.allowed_shipping_countries[137]}\", \"${json.allowed_shipping_countries[138]}\", \"${json.allowed_shipping_countries[139]}\", \"${json.allowed_shipping_countries[140]}\", \"${json.allowed_shipping_countries[141]}\", \"${json.allowed_shipping_countries[142]}\", \"${json.allowed_shipping_countries[143]}\", \"${json.allowed_shipping_countries[144]}\", \"${json.allowed_shipping_countries[145]}\", \"${json.allowed_shipping_countries[146]}\", \"${json.allowed_shipping_countries[147]}\", \"${json.allowed_shipping_countries[148]}\", \"${json.allowed_shipping_countries[149]}\", \"${json.allowed_shipping_countries[150]}\", \"${json.allowed_shipping_countries[151]}\", \"${json.allowed_shipping_countries[152]}\", \"${json.allowed_shipping_countries[153]}\", \"${json.allowed_shipping_countries[154]}\", \"${json.allowed_shipping_countries[155]}\", \"${json.allowed_shipping_countries[156]}\", \"${json.allowed_shipping_countries[157]}\", \"${json.allowed_shipping_countries[158]}\", \"${json.allowed_shipping_countries[159]}\", \"${json.allowed_shipping_countries[160]}\", \"${json.allowed_shipping_countries[161]}\", \"${json.allowed_shipping_countries[162]}\", \"${json.allowed_shipping_countries[163]}\", \"${json.allowed_shipping_countries[164]}\", \"${json.allowed_shipping_countries[165]}\", \"${json.allowed_shipping_countries[166]}\", \"${json.allowed_shipping_countries[167]}\", \"${json.allowed_shipping_countries[168]}\", \"${json.allowed_shipping_countries[169]}\", \"${json.allowed_shipping_countries[170]}\", \"${json.allowed_shipping_countries[171]}\", \"${json.allowed_shipping_countries[172]}\", \"${json.allowed_shipping_countries[173]}\", \"${json.allowed_shipping_countries[174]}\", \"${json.allowed_shipping_countries[175]}\", \"${json.allowed_shipping_countries[176]}\", \"${json.allowed_shipping_countries[177]}\", \"${json.allowed_shipping_countries[178]}\", \"${json.allowed_shipping_countries[179]}\", \"${json.allowed_shipping_countries[180]}\", \"${json.allowed_shipping_countries[181]}\", \"${json.allowed_shipping_countries[182]}\", \"${json.allowed_shipping_countries[183]}\", \"${json.allowed_shipping_countries[184]}\", \"${json.allowed_shipping_countries[185]}\", \"${json.allowed_shipping_countries[186]}\", \"${json.allowed_shipping_countries[187]}\", \"${json.allowed_shipping_countries[188]}\", \"${json.allowed_shipping_countries[189]}\", \"${json.allowed_shipping_countries[190]}\", \"${json.allowed_shipping_countries[191]}\", \"${json.allowed_shipping_countries[192]}\", \"${json.allowed_shipping_countries[193]}\", \"${json.allowed_shipping_countries[194]}\", \"${json.allowed_shipping_countries[195]}\", \"${json.allowed_shipping_countries[196]}\", \"${json.allowed_shipping_countries[197]}\", \"${json.allowed_shipping_countries[198]}\", \"${json.allowed_shipping_countries[199]}\", \"${json.allowed_shipping_countries[200]}\", \"${json.allowed_shipping_countries[201]}\", \"${json.allowed_shipping_countries[202]}\", \"${json.allowed_shipping_countries[203]}\", \"${json.allowed_shipping_countries[204]}\", \"${json.allowed_shipping_countries[205]}\", \"${json.allowed_shipping_countries[206]}\", \"${json.allowed_shipping_countries[207]}\", \"${json.allowed_shipping_countries[208]}\", \"${json.allowed_shipping_countries[209]}\", \"${json.allowed_shipping_countries[210]}\"],\n\t\t\t\t\"cart\": {\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"image_url\": \"${json.cart.items[0].image_url}\",\n\t\t\t\t\t\t\t\"name\": \"${json.cart.items[0].name}\",\n\t\t\t\t\t\t\t\"product_url\": \"${json.cart.items[0].product_url}\",\n\t\t\t\t\t\t\t\"quantity\": \"${json.cart.items[0].quantity}\",\n\t\t\t\t\t\t\t\"reference\": \"${json.cart.items[0].reference}\",\n\t\t\t\t\t\t\t\"tax_rate\": \"${json.cart.items[0].tax_rate}\",\n\t\t\t\t\t\t\t\"total_price_excluding_tax\": \"${json.cart.items[0].total_price_excluding_tax}\",\n\t\t\t\t\t\t\t\"total_price_including_tax\": \"${json.cart.items[0].total_price_including_tax}\",\n\t\t\t\t\t\t\t\"total_tax_amount\": \"${json.cart.items[0].total_tax_amount}\",\n\t\t\t\t\t\t\t\"type\": \"${json.cart.items[0].type}\",\n\t\t\t\t\t\t\t\"unit_price\": \"${json.cart.items[0].unit_price}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"subtotal\": \"${json.cart.subtotal}\",\n\t\t\t\t\t\"total_discount_amount_excluding_tax\": \"${json.cart.total_discount_amount_excluding_tax}\",\n\t\t\t\t\t\"total_price_excluding_tax\": \"${json.cart.total_price_excluding_tax}\",\n\t\t\t\t\t\"total_price_including_tax\": \"${json.cart.total_price_including_tax}\",\n\t\t\t\t\t\"total_shipping_amount_excluding_tax\": \"${json.cart.total_shipping_amount_excluding_tax}\",\n\t\t\t\t\t\"total_store_credit\": \"${json.cart.total_store_credit}\",\n\t\t\t\t\t\"total_surcharge_amount_excluding_tax\": \"${json.cart.total_surcharge_amount_excluding_tax}\",\n\t\t\t\t\t\"total_tax_amount\": \"${json.cart.total_tax_amount}\"\n\t\t\t\t},\n\t\t\t\t\"merchant_urls\": {\n\t\t\t\t\t\"checkout\": \"${json.merchant_urls.checkout}\",\n\t\t\t\t\t\"confirmation\": \"${json.merchant_urls.confirmation}\",\n\t\t\t\t\t\"terms\": \"${json.merchant_urls.terms}\"\n\t\t\t\t},\n\t\t\t\t\"options\": {\n\t\t\t\t\t\"allow_separate_shipping_address\": \"${json.options.allow_separate_shipping_address}\",\n\t\t\t\t\t\"allowed_customer_types\": [\"${json.options.allowed_customer_types[0]}\"],\n\t\t\t\t\t\"date_of_birth_mandatory\": \"${json.options.date_of_birth_mandatory}\",\n\t\t\t\t\t\"national_identification_number_mandatory\": \"${json.options.national_identification_number_mandatory}\",\n\t\t\t\t\t\"payment_selector_on_load\": \"${json.options.payment_selector_on_load}\"\n\t\t\t\t},\n\t\t\t\t\"preview_payment_methods\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"days\": \"${json.preview_payment_methods[0].data.days}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"id\": \"${json.preview_payment_methods[0].id}\",\n\t\t\t\t\t\t\"type\": \"${json.preview_payment_methods[0].type}\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"allow_saved_card\": \"${json.preview_payment_methods[1].data.allow_saved_card}\",\n\t\t\t\t\t\t\t\"available_cards\": [\"${json.preview_payment_methods[1].data.available_cards[0]}\", \"${json.preview_payment_methods[1].data.available_cards[1]}\"],\n\t\t\t\t\t\t\t\"do_save_card\": \"${json.preview_payment_methods[1].data.do_save_card}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"id\": \"${json.preview_payment_methods[1].id}\",\n\t\t\t\t\t\t\"type\": \"${json.preview_payment_methods[1].type}\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"required_fields\": [\"${json.required_fields[0]}\", \"${json.required_fields[1]}\"],\n\t\t\t\t\"shared\": {\n\t\t\t\t\t\"billing_address\": {\n\t\t\t\t\t\t\"country\": \"${json.shared.billing_address.country}\"\n\t\t\t\t\t},\n\t\t\t\t\t\"challenge\": {\n\t\t\t\t\t\t\"country\": \"${json.shared.challenge.country}\",\n\t\t\t\t\t\t\"email\": \"drop+b28643c0e7c74da6b6ff2f4131aa3d64+d0+gr@example.com\",\n\t\t\t\t\t\t\"postal_code\": \"10066\"\n\t\t\t\t\t},\n\t\t\t\t\t\"currency\": \"${json.shared.currency}\",\n\t\t\t\t\t\"customer\": {\n\t\t\t\t\t\t\"type\": \"${json.shared.customer.type}\"\n\t\t\t\t\t},\n\t\t\t\t\t\"language\": \"${json.shared.language}\"\n\t\t\t\t},\n\t\t\t\t\"status\": {\n\t\t\t\t\t\"prescreened\": \"${json.status.prescreened}\",\n\t\t\t\t\t\"require_terms_consent\": \"${json.status.require_terms_consent}\"\n\t\t\t\t}\n\t\t\t}`,\n\t\t\t{\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"Authorization\": \"Checkout otherStuffz\",\n\t\t\t\t\t\"User-Agent\": \"SysTest - perf\",\n\t\t\t\t\t\"Content-Type\": \"application/vnd.checkout.client-order-v1+json\",\n\t\t\t\t\t\"Accept\": \"application/vnd.checkout.server-order-v1+json\",\n\t\t\t\t\t\"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\",\n\t\t\t\t\t\"Host\": \"some-other-host.example.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t\tif (!check(res, {\"status is 200\": (r) => r.status === 200 })) { return };\n\t\tjson = JSON.parse(res.body);\n\t\t// Request #4\n\t\tres = http.post(\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n\t\t\t`{\n\t\t\t\t\"allowed_billing_countries\": [\"${json.allowed_billing_countries[0]}\", \"${json.allowed_billing_countries[1]}\", \"${json.allowed_billing_countries[2]}\", \"${json.allowed_billing_countries[3]}\", \"${json.allowed_billing_countries[4]}\", \"${json.allowed_billing_countries[5]}\", \"${json.allowed_billing_countries[6]}\", \"${json.allowed_billing_countries[7]}\", \"${json.allowed_billing_countries[8]}\", \"${json.allowed_billing_countries[9]}\", \"${json.allowed_billing_countries[10]}\", \"${json.allowed_billing_countries[11]}\", \"${json.allowed_billing_countries[12]}\", \"${json.allowed_billing_countries[13]}\", \"${json.allowed_billing_countries[14]}\", \"${json.allowed_billing_countries[15]}\", \"${json.allowed_billing_countries[16]}\", \"${json.allowed_billing_countries[17]}\", \"${json.allowed_billing_countries[18]}\", \"${json.allowed_billing_countries[19]}\", \"${json.allowed_billing_countries[20]}\", \"${json.allowed_billing_countries[21]}\", \"${json.allowed_billing_countries[22]}\", \"${json.allowed_billing_countries[23]}\", \"${json.allowed_billing_countries[24]}\", \"${json.allowed_billing_countries[25]}\", \"${json.allowed_billing_countries[26]}\", \"${json.allowed_billing_countries[27]}\", \"${json.allowed_billing_countries[28]}\", \"${json.allowed_billing_countries[29]}\", \"${json.allowed_billing_countries[30]}\", \"${json.allowed_billing_countries[31]}\", \"${json.allowed_billing_countries[32]}\", \"${json.allowed_billing_countries[33]}\", \"${json.allowed_billing_countries[34]}\", \"${json.allowed_billing_countries[35]}\", \"${json.allowed_billing_countries[36]}\", \"${json.allowed_billing_countries[37]}\", \"${json.allowed_billing_countries[38]}\", \"${json.allowed_billing_countries[39]}\", \"${json.allowed_billing_countries[40]}\", \"${json.allowed_billing_countries[41]}\", \"${json.allowed_billing_countries[42]}\", \"${json.allowed_billing_countries[43]}\", \"${json.allowed_billing_countries[44]}\", \"${json.allowed_billing_countries[45]}\", \"${json.allowed_billing_countries[46]}\", \"${json.allowed_billing_countries[47]}\", \"${json.allowed_billing_countries[48]}\", \"${json.allowed_billing_countries[49]}\", \"${json.allowed_billing_countries[50]}\", \"${json.allowed_billing_countries[51]}\", \"${json.allowed_billing_countries[52]}\", \"${json.allowed_billing_countries[53]}\", \"${json.allowed_billing_countries[54]}\", \"${json.allowed_billing_countries[55]}\", \"${json.allowed_billing_countries[56]}\", \"${json.allowed_billing_countries[57]}\", \"${json.allowed_billing_countries[58]}\", \"${json.allowed_billing_countries[59]}\", \"${json.allowed_billing_countries[60]}\", \"${json.allowed_billing_countries[61]}\", \"${json.allowed_billing_countries[62]}\", \"${json.allowed_billing_countries[63]}\", \"${json.allowed_billing_countries[64]}\", \"${json.allowed_billing_countries[65]}\", \"${json.allowed_billing_countries[66]}\", \"${json.allowed_billing_countries[67]}\", \"${json.allowed_billing_countries[68]}\", \"${json.allowed_billing_countries[69]}\", \"${json.allowed_billing_countries[70]}\", \"${json.allowed_billing_countries[71]}\", \"${json.allowed_billing_countries[72]}\", \"${json.allowed_billing_countries[73]}\", \"${json.allowed_billing_countries[74]}\", \"${json.allowed_billing_countries[75]}\", \"${json.allowed_billing_countries[76]}\", \"${json.allowed_billing_countries[77]}\", \"${json.allowed_billing_countries[78]}\", \"${json.allowed_billing_countries[79]}\", \"${json.allowed_billing_countries[80]}\", \"${json.allowed_billing_countries[81]}\", \"${json.allowed_billing_countries[82]}\", \"${json.allowed_billing_countries[83]}\", \"${json.allowed_billing_countries[84]}\", \"${json.allowed_billing_countries[85]}\", \"${json.allowed_billing_countries[86]}\", \"${json.allowed_billing_countries[87]}\", \"${json.allowed_billing_countries[88]}\", \"${json.allowed_billing_countries[89]}\", \"${json.allowed_billing_countries[90]}\", \"${json.allowed_billing_countries[91]}\", \"${json.allowed_billing_countries[92]}\", \"${json.allowed_billing_countries[93]}\", \"${json.allowed_billing_countries[94]}\", \"${json.allowed_billing_countries[95]}\", \"${json.allowed_billing_countries[96]}\", \"${json.allowed_billing_countries[97]}\", \"${json.allowed_billing_countries[98]}\", \"${json.allowed_billing_countries[99]}\", \"${json.allowed_billing_countries[100]}\", \"${json.allowed_billing_countries[101]}\", \"${json.allowed_billing_countries[102]}\", \"${json.allowed_billing_countries[103]}\", \"${json.allowed_billing_countries[104]}\", \"${json.allowed_billing_countries[105]}\", \"${json.allowed_billing_countries[106]}\", \"${json.allowed_billing_countries[107]}\", \"${json.allowed_billing_countries[108]}\", \"${json.allowed_billing_countries[109]}\", \"${json.allowed_billing_countries[110]}\", \"${json.allowed_billing_countries[111]}\", \"${json.allowed_billing_countries[112]}\", \"${json.allowed_billing_countries[113]}\", \"${json.allowed_billing_countries[114]}\", \"${json.allowed_billing_countries[115]}\", \"${json.allowed_billing_countries[116]}\", \"${json.allowed_billing_countries[117]}\", \"${json.allowed_billing_countries[118]}\", \"${json.allowed_billing_countries[119]}\", \"${json.allowed_billing_countries[120]}\", \"${json.allowed_billing_countries[121]}\", \"${json.allowed_billing_countries[122]}\", \"${json.allowed_billing_countries[123]}\", \"${json.allowed_billing_countries[124]}\", \"${json.allowed_billing_countries[125]}\", \"${json.allowed_billing_countries[126]}\", \"${json.allowed_billing_countries[127]}\", \"${json.allowed_billing_countries[128]}\", \"${json.allowed_billing_countries[129]}\", \"${json.allowed_billing_countries[130]}\", \"${json.allowed_billing_countries[131]}\", \"${json.allowed_billing_countries[132]}\", \"${json.allowed_billing_countries[133]}\", \"${json.allowed_billing_countries[134]}\", \"${json.allowed_billing_countries[135]}\", \"${json.allowed_billing_countries[136]}\", \"${json.allowed_billing_countries[137]}\", \"${json.allowed_billing_countries[138]}\", \"${json.allowed_billing_countries[139]}\", \"${json.allowed_billing_countries[140]}\", \"${json.allowed_billing_countries[141]}\", \"${json.allowed_billing_countries[142]}\", \"${json.allowed_billing_countries[143]}\", \"${json.allowed_billing_countries[144]}\", \"${json.allowed_billing_countries[145]}\", \"${json.allowed_billing_countries[146]}\", \"${json.allowed_billing_countries[147]}\", \"${json.allowed_billing_countries[148]}\", \"${json.allowed_billing_countries[149]}\", \"${json.allowed_billing_countries[150]}\", \"${json.allowed_billing_countries[151]}\", \"${json.allowed_billing_countries[152]}\", \"${json.allowed_billing_countries[153]}\", \"${json.allowed_billing_countries[154]}\", \"${json.allowed_billing_countries[155]}\", \"${json.allowed_billing_countries[156]}\", \"${json.allowed_billing_countries[157]}\", \"${json.allowed_billing_countries[158]}\", \"${json.allowed_billing_countries[159]}\", \"${json.allowed_billing_countries[160]}\", \"${json.allowed_billing_countries[161]}\", \"${json.allowed_billing_countries[162]}\", \"${json.allowed_billing_countries[163]}\", \"${json.allowed_billing_countries[164]}\", \"${json.allowed_billing_countries[165]}\", \"${json.allowed_billing_countries[166]}\", \"${json.allowed_billing_countries[167]}\", \"${json.allowed_billing_countries[168]}\", \"${json.allowed_billing_countries[169]}\", \"${json.allowed_billing_countries[170]}\", \"${json.allowed_billing_countries[171]}\", \"${json.allowed_billing_countries[172]}\", \"${json.allowed_billing_countries[173]}\", \"${json.allowed_billing_countries[174]}\", \"${json.allowed_billing_countries[175]}\", \"${json.allowed_billing_countries[176]}\", \"${json.allowed_billing_countries[177]}\", \"${json.allowed_billing_countries[178]}\", \"${json.allowed_billing_countries[179]}\", \"${json.allowed_billing_countries[180]}\", \"${json.allowed_billing_countries[181]}\", \"${json.allowed_billing_countries[182]}\", \"${json.allowed_billing_countries[183]}\", \"${json.allowed_billing_countries[184]}\", \"${json.allowed_billing_countries[185]}\", \"${json.allowed_billing_countries[186]}\", \"${json.allowed_billing_countries[187]}\", \"${json.allowed_billing_countries[188]}\", \"${json.allowed_billing_countries[189]}\", \"${json.allowed_billing_countries[190]}\", \"${json.allowed_billing_countries[191]}\", \"${json.allowed_billing_countries[192]}\", \"${json.allowed_billing_countries[193]}\", \"${json.allowed_billing_countries[194]}\", \"${json.allowed_billing_countries[195]}\", \"${json.allowed_billing_countries[196]}\", \"${json.allowed_billing_countries[197]}\", \"${json.allowed_billing_countries[198]}\", \"${json.allowed_billing_countries[199]}\", \"${json.allowed_billing_countries[200]}\", \"${json.allowed_billing_countries[201]}\", \"${json.allowed_billing_countries[202]}\", \"${json.allowed_billing_countries[203]}\", \"${json.allowed_billing_countries[204]}\", \"${json.allowed_billing_countries[205]}\", \"${json.allowed_billing_countries[206]}\", \"${json.allowed_billing_countries[207]}\", \"${json.allowed_billing_countries[208]}\", \"${json.allowed_billing_countries[209]}\", \"${json.allowed_billing_countries[210]}\"],\n\t\t\t\t\"allowed_shipping_countries\": [\"${json.allowed_shipping_countries[0]}\", \"${json.allowed_shipping_countries[1]}\", \"${json.allowed_shipping_countries[2]}\", \"${json.allowed_shipping_countries[3]}\", \"${json.allowed_shipping_countries[4]}\", \"${json.allowed_shipping_countries[5]}\", \"${json.allowed_shipping_countries[6]}\", \"${json.allowed_shipping_countries[7]}\", \"${json.allowed_shipping_countries[8]}\", \"${json.allowed_shipping_countries[9]}\", \"${json.allowed_shipping_countries[10]}\", \"${json.allowed_shipping_countries[11]}\", \"${json.allowed_shipping_countries[12]}\", \"${json.allowed_shipping_countries[13]}\", \"${json.allowed_shipping_countries[14]}\", \"${json.allowed_shipping_countries[15]}\", \"${json.allowed_shipping_countries[16]}\", \"${json.allowed_shipping_countries[17]}\", \"${json.allowed_shipping_countries[18]}\", \"${json.allowed_shipping_countries[19]}\", \"${json.allowed_shipping_countries[20]}\", \"${json.allowed_shipping_countries[21]}\", \"${json.allowed_shipping_countries[22]}\", \"${json.allowed_shipping_countries[23]}\", \"${json.allowed_shipping_countries[24]}\", \"${json.allowed_shipping_countries[25]}\", \"${json.allowed_shipping_countries[26]}\", \"${json.allowed_shipping_countries[27]}\", \"${json.allowed_shipping_countries[28]}\", \"${json.allowed_shipping_countries[29]}\", \"${json.allowed_shipping_countries[30]}\", \"${json.allowed_shipping_countries[31]}\", \"${json.allowed_shipping_countries[32]}\", \"${json.allowed_shipping_countries[33]}\", \"${json.allowed_shipping_countries[34]}\", \"${json.allowed_shipping_countries[35]}\", \"${json.allowed_shipping_countries[36]}\", \"${json.allowed_shipping_countries[37]}\", \"${json.allowed_shipping_countries[38]}\", \"${json.allowed_shipping_countries[39]}\", \"${json.allowed_shipping_countries[40]}\", \"${json.allowed_shipping_countries[41]}\", \"${json.allowed_shipping_countries[42]}\", \"${json.allowed_shipping_countries[43]}\", \"${json.allowed_shipping_countries[44]}\", \"${json.allowed_shipping_countries[45]}\", \"${json.allowed_shipping_countries[46]}\", \"${json.allowed_shipping_countries[47]}\", \"${json.allowed_shipping_countries[48]}\", \"${json.allowed_shipping_countries[49]}\", \"${json.allowed_shipping_countries[50]}\", \"${json.allowed_shipping_countries[51]}\", \"${json.allowed_shipping_countries[52]}\", \"${json.allowed_shipping_countries[53]}\", \"${json.allowed_shipping_countries[54]}\", \"${json.allowed_shipping_countries[55]}\", \"${json.allowed_shipping_countries[56]}\", \"${json.allowed_shipping_countries[57]}\", \"${json.allowed_shipping_countries[58]}\", \"${json.allowed_shipping_countries[59]}\", \"${json.allowed_shipping_countries[60]}\", \"${json.allowed_shipping_countries[61]}\", \"${json.allowed_shipping_countries[62]}\", \"${json.allowed_shipping_countries[63]}\", \"${json.allowed_shipping_countries[64]}\", \"${json.allowed_shipping_countries[65]}\", \"${json.allowed_shipping_countries[66]}\", \"${json.allowed_shipping_countries[67]}\", \"${json.allowed_shipping_countries[68]}\", \"${json.allowed_shipping_countries[69]}\", \"${json.allowed_shipping_countries[70]}\", \"${json.allowed_shipping_countries[71]}\", \"${json.allowed_shipping_countries[72]}\", \"${json.allowed_shipping_countries[73]}\", \"${json.allowed_shipping_countries[74]}\", \"${json.allowed_shipping_countries[75]}\", \"${json.allowed_shipping_countries[76]}\", \"${json.allowed_shipping_countries[77]}\", \"${json.allowed_shipping_countries[78]}\", \"${json.allowed_shipping_countries[79]}\", \"${json.allowed_shipping_countries[80]}\", \"${json.allowed_shipping_countries[81]}\", \"${json.allowed_shipping_countries[82]}\", \"${json.allowed_shipping_countries[83]}\", \"${json.allowed_shipping_countries[84]}\", \"${json.allowed_shipping_countries[85]}\", \"${json.allowed_shipping_countries[86]}\", \"${json.allowed_shipping_countries[87]}\", \"${json.allowed_shipping_countries[88]}\", \"${json.allowed_shipping_countries[89]}\", \"${json.allowed_shipping_countries[90]}\", \"${json.allowed_shipping_countries[91]}\", \"${json.allowed_shipping_countries[92]}\", \"${json.allowed_shipping_countries[93]}\", \"${json.allowed_shipping_countries[94]}\", \"${json.allowed_shipping_countries[95]}\", \"${json.allowed_shipping_countries[96]}\", \"${json.allowed_shipping_countries[97]}\", \"${json.allowed_shipping_countries[98]}\", \"${json.allowed_shipping_countries[99]}\", \"${json.allowed_shipping_countries[100]}\", \"${json.allowed_shipping_countries[101]}\", \"${json.allowed_shipping_countries[102]}\", \"${json.allowed_shipping_countries[103]}\", \"${json.allowed_shipping_countries[104]}\", \"${json.allowed_shipping_countries[105]}\", \"${json.allowed_shipping_countries[106]}\", \"${json.allowed_shipping_countries[107]}\", \"${json.allowed_shipping_countries[108]}\", \"${json.allowed_shipping_countries[109]}\", \"${json.allowed_shipping_countries[110]}\", \"${json.allowed_shipping_countries[111]}\", \"${json.allowed_shipping_countries[112]}\", \"${json.allowed_shipping_countries[113]}\", \"${json.allowed_shipping_countries[114]}\", \"${json.allowed_shipping_countries[115]}\", \"${json.allowed_shipping_countries[116]}\", \"${json.allowed_shipping_countries[117]}\", \"${json.allowed_shipping_countries[118]}\", \"${json.allowed_shipping_countries[119]}\", \"${json.allowed_shipping_countries[120]}\", \"${json.allowed_shipping_countries[121]}\", \"${json.allowed_shipping_countries[122]}\", \"${json.allowed_shipping_countries[123]}\", \"${json.allowed_shipping_countries[124]}\", \"${json.allowed_shipping_countries[125]}\", \"${json.allowed_shipping_countries[126]}\", \"${json.allowed_shipping_countries[127]}\", \"${json.allowed_shipping_countries[128]}\", \"${json.allowed_shipping_countries[129]}\", \"${json.allowed_shipping_countries[130]}\", \"${json.allowed_shipping_countries[131]}\", \"${json.allowed_shipping_countries[132]}\", \"${json.allowed_shipping_countries[133]}\", \"${json.allowed_shipping_countries[134]}\", \"${json.allowed_shipping_countries[135]}\", \"${json.allowed_shipping_countries[136]}\", \"${json.allowed_shipping_countries[137]}\", \"${json.allowed_shipping_countries[138]}\", \"${json.allowed_shipping_countries[139]}\", \"${json.allowed_shipping_countries[140]}\", \"${json.allowed_shipping_countries[141]}\", \"${json.allowed_shipping_countries[142]}\", \"${json.allowed_shipping_countries[143]}\", \"${json.allowed_shipping_countries[144]}\", \"${json.allowed_shipping_countries[145]}\", \"${json.allowed_shipping_countries[146]}\", \"${json.allowed_shipping_countries[147]}\", \"${json.allowed_shipping_countries[148]}\", \"${json.allowed_shipping_countries[149]}\", \"${json.allowed_shipping_countries[150]}\", \"${json.allowed_shipping_countries[151]}\", \"${json.allowed_shipping_countries[152]}\", \"${json.allowed_shipping_countries[153]}\", \"${json.allowed_shipping_countries[154]}\", \"${json.allowed_shipping_countries[155]}\", \"${json.allowed_shipping_countries[156]}\", \"${json.allowed_shipping_countries[157]}\", \"${json.allowed_shipping_countries[158]}\", \"${json.allowed_shipping_countries[159]}\", \"${json.allowed_shipping_countries[160]}\", \"${json.allowed_shipping_countries[161]}\", \"${json.allowed_shipping_countries[162]}\", \"${json.allowed_shipping_countries[163]}\", \"${json.allowed_shipping_countries[164]}\", \"${json.allowed_shipping_countries[165]}\", \"${json.allowed_shipping_countries[166]}\", \"${json.allowed_shipping_countries[167]}\", \"${json.allowed_shipping_countries[168]}\", \"${json.allowed_shipping_countries[169]}\", \"${json.allowed_shipping_countries[170]}\", \"${json.allowed_shipping_countries[171]}\", \"${json.allowed_shipping_countries[172]}\", \"${json.allowed_shipping_countries[173]}\", \"${json.allowed_shipping_countries[174]}\", \"${json.allowed_shipping_countries[175]}\", \"${json.allowed_shipping_countries[176]}\", \"${json.allowed_shipping_countries[177]}\", \"${json.allowed_shipping_countries[178]}\", \"${json.allowed_shipping_countries[179]}\", \"${json.allowed_shipping_countries[180]}\", \"${json.allowed_shipping_countries[181]}\", \"${json.allowed_shipping_countries[182]}\", \"${json.allowed_shipping_countries[183]}\", \"${json.allowed_shipping_countries[184]}\", \"${json.allowed_shipping_countries[185]}\", \"${json.allowed_shipping_countries[186]}\", \"${json.allowed_shipping_countries[187]}\", \"${json.allowed_shipping_countries[188]}\", \"${json.allowed_shipping_countries[189]}\", \"${json.allowed_shipping_countries[190]}\", \"${json.allowed_shipping_countries[191]}\", \"${json.allowed_shipping_countries[192]}\", \"${json.allowed_shipping_countries[193]}\", \"${json.allowed_shipping_countries[194]}\", \"${json.allowed_shipping_countries[195]}\", \"${json.allowed_shipping_countries[196]}\", \"${json.allowed_shipping_countries[197]}\", \"${json.allowed_shipping_countries[198]}\", \"${json.allowed_shipping_countries[199]}\", \"${json.allowed_shipping_countries[200]}\", \"${json.allowed_shipping_countries[201]}\", \"${json.allowed_shipping_countries[202]}\", \"${json.allowed_shipping_countries[203]}\", \"${json.allowed_shipping_countries[204]}\", \"${json.allowed_shipping_countries[205]}\", \"${json.allowed_shipping_countries[206]}\", \"${json.allowed_shipping_countries[207]}\", \"${json.allowed_shipping_countries[208]}\", \"${json.allowed_shipping_countries[209]}\", \"${json.allowed_shipping_countries[210]}\"],\n\t\t\t\t\"analytics_user_id\": \"${json.analytics_user_id}\",\n\t\t\t\t\"cart\": {\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"image_url\": \"${json.cart.items[0].image_url}\",\n\t\t\t\t\t\t\t\"name\": \"${json.cart.items[0].name}\",\n\t\t\t\t\t\t\t\"product_url\": \"${json.cart.items[0].product_url}\",\n\t\t\t\t\t\t\t\"quantity\": \"${json.cart.items[0].quantity}\",\n\t\t\t\t\t\t\t\"reference\": \"${json.cart.items[0].reference}\",\n\t\t\t\t\t\t\t\"tax_rate\": \"${json.cart.items[0].tax_rate}\",\n\t\t\t\t\t\t\t\"total_price_excluding_tax\": \"${json.cart.items[0].total_price_excluding_tax}\",\n\t\t\t\t\t\t\t\"total_price_including_tax\": \"${json.cart.items[0].total_price_including_tax}\",\n\t\t\t\t\t\t\t\"total_tax_amount\": \"${json.cart.items[0].total_tax_amount}\",\n\t\t\t\t\t\t\t\"type\": \"${json.cart.items[0].type}\",\n\t\t\t\t\t\t\t\"unit_price\": \"${json.cart.items[0].unit_price}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"subtotal\": \"${json.cart.subtotal}\",\n\t\t\t\t\t\"total_discount_amount_excluding_tax\": \"${json.cart.total_discount_amount_excluding_tax}\",\n\t\t\t\t\t\"total_price_excluding_tax\": \"${json.cart.total_price_excluding_tax}\",\n\t\t\t\t\t\"total_price_including_tax\": \"${json.cart.total_price_including_tax}\",\n\t\t\t\t\t\"total_shipping_amount_excluding_tax\": \"${json.cart.total_shipping_amount_excluding_tax}\",\n\t\t\t\t\t\"total_store_credit\": \"${json.cart.total_store_credit}\",\n\t\t\t\t\t\"total_surcharge_amount_excluding_tax\": \"${json.cart.total_surcharge_amount_excluding_tax}\",\n\t\t\t\t\t\"total_tax_amount\": \"${json.cart.total_tax_amount}\"\n\t\t\t\t},\n\t\t\t\t\"correlation_id\": \"f6df29e7-f850-4c36-81fc-11def2f44b81\",\n\t\t\t\t\"merchant_urls\": {\n\t\t\t\t\t\"checkout\": \"${json.merchant_urls.checkout}\",\n\t\t\t\t\t\"confirmation\": \"${json.merchant_urls.confirmation}\",\n\t\t\t\t\t\"terms\": \"${json.merchant_urls.terms}\"\n\t\t\t\t},\n\t\t\t\t\"options\": {\n\t\t\t\t\t\"allow_separate_shipping_address\": \"${json.options.allow_separate_shipping_address}\",\n\t\t\t\t\t\"allowed_customer_types\": [\"${json.options.allowed_customer_types[0]}\"],\n\t\t\t\t\t\"date_of_birth_mandatory\": \"${json.options.date_of_birth_mandatory}\",\n\t\t\t\t\t\"national_identification_number_mandatory\": \"${json.options.national_identification_number_mandatory}\",\n\t\t\t\t\t\"payment_selector_on_load\": \"${json.options.payment_selector_on_load}\"\n\t\t\t\t},\n\t\t\t\t\"preview_payment_methods\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"days\": \"${json.preview_payment_methods[0].data.days}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"id\": \"${json.preview_payment_methods[0].id}\",\n\t\t\t\t\t\t\"type\": \"${json.preview_payment_methods[0].type}\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"allow_saved_card\": \"${json.preview_payment_methods[1].data.allow_saved_card}\",\n\t\t\t\t\t\t\t\"available_cards\": [\"${json.preview_payment_methods[1].data.available_cards[0]}\", \"${json.preview_payment_methods[1].data.available_cards[1]}\"],\n\t\t\t\t\t\t\t\"do_save_card\": \"${json.preview_payment_methods[1].data.do_save_card}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"id\": \"${json.preview_payment_methods[1].id}\",\n\t\t\t\t\t\t\"type\": \"${json.preview_payment_methods[1].type}\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"required_fields\": [\"${json.required_fields[0]}\", \"${json.required_fields[1]}\", \"${json.required_fields[2]}\", \"${json.required_fields[3]}\", \"${json.required_fields[4]}\", \"${json.required_fields[5]}\", \"billing_address.care_of\"],\n\t\t\t\t\"shared\": {\n\t\t\t\t\t\"billing_address\": {\n\t\t\t\t\t\t\"care_of\": \"C/O Hakan Ostlund\",\n\t\t\t\t\t\t\"city\": \"AlingHelsingstadfors\",\n\t\t\t\t\t\t\"country\": \"${json.shared.billing_address.country}\",\n\t\t\t\t\t\t\"email\": \"${json.shared.billing_address.email}\",\n\t\t\t\t\t\t\"family_name\": \"Anglund\",\n\t\t\t\t\t\t\"given_name\": \"Eva InvoiceGreenNewSpec\",\n\t\t\t\t\t\t\"phone\": \"+46700012878\",\n\t\t\t\t\t\t\"postal_code\": \"${json.shared.billing_address.postal_code}\",\n\t\t\t\t\t\t\"street_address\": \"Sveavägen 44, 11111 Stockholm, Sweden Eriks Gata gatan\"\n\t\t\t\t\t},\n\t\t\t\t\t\"challenge\": {\n\t\t\t\t\t\t\"country\": \"${json.shared.challenge.country}\",\n\t\t\t\t\t\t\"email\": \"${json.shared.challenge.email}\",\n\t\t\t\t\t\t\"postal_code\": \"${json.shared.challenge.postal_code}\"\n\t\t\t\t\t},\n\t\t\t\t\t\"currency\": \"${json.shared.currency}\",\n\t\t\t\t\t\"customer\": {\n\t\t\t\t\t\t\"national_identification_number\": \"8910210312\",\n\t\t\t\t\t\t\"type\": \"${json.shared.customer.type}\"\n\t\t\t\t\t},\n\t\t\t\t\t\"language\": \"${json.shared.language}\"\n\t\t\t\t},\n\t\t\t\t\"status\": {\n\t\t\t\t\t\"prescreened\": \"${json.status.prescreened}\",\n\t\t\t\t\t\"require_terms_consent\": \"${json.status.require_terms_consent}\"\n\t\t\t\t}\n\t\t\t}`,\n\t\t\t{\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"Authorization\": \"Checkout otherStuffz\",\n\t\t\t\t\t\"User-Agent\": \"SysTest - perf\",\n\t\t\t\t\t\"Content-Type\": \"application/vnd.checkout.client-order-v1+json\",\n\t\t\t\t\t\"Accept\": \"application/vnd.checkout.server-order-v1+json\",\n\t\t\t\t\t\"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\",\n\t\t\t\t\t\"Host\": \"some-other-host.example.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t\tif (!check(res, {\"status is 200\": (r) => r.status === 200 })) { return };\n\t\tjson = JSON.parse(res.body);\n\t\t// Request #5\n\t\tres = http.post(\"https://some-other-host.example.com/yaco/orders/570714bf-3c2b-452e-90cd-f7c5e552bb25\",\n\t\t\t`{\n\t\t\t\t\"allowed_billing_countries\": [\"${json.allowed_billing_countries[0]}\", \"${json.allowed_billing_countries[1]}\", \"${json.allowed_billing_countries[2]}\", \"${json.allowed_billing_countries[3]}\", \"${json.allowed_billing_countries[4]}\", \"${json.allowed_billing_countries[5]}\", \"${json.allowed_billing_countries[6]}\", \"${json.allowed_billing_countries[7]}\", \"${json.allowed_billing_countries[8]}\", \"${json.allowed_billing_countries[9]}\", \"${json.allowed_billing_countries[10]}\", \"${json.allowed_billing_countries[11]}\", \"${json.allowed_billing_countries[12]}\", \"${json.allowed_billing_countries[13]}\", \"${json.allowed_billing_countries[14]}\", \"${json.allowed_billing_countries[15]}\", \"${json.allowed_billing_countries[16]}\", \"${json.allowed_billing_countries[17]}\", \"${json.allowed_billing_countries[18]}\", \"${json.allowed_billing_countries[19]}\", \"${json.allowed_billing_countries[20]}\", \"${json.allowed_billing_countries[21]}\", \"${json.allowed_billing_countries[22]}\", \"${json.allowed_billing_countries[23]}\", \"${json.allowed_billing_countries[24]}\", \"${json.allowed_billing_countries[25]}\", \"${json.allowed_billing_countries[26]}\", \"${json.allowed_billing_countries[27]}\", \"${json.allowed_billing_countries[28]}\", \"${json.allowed_billing_countries[29]}\", \"${json.allowed_billing_countries[30]}\", \"${json.allowed_billing_countries[31]}\", \"${json.allowed_billing_countries[32]}\", \"${json.allowed_billing_countries[33]}\", \"${json.allowed_billing_countries[34]}\", \"${json.allowed_billing_countries[35]}\", \"${json.allowed_billing_countries[36]}\", \"${json.allowed_billing_countries[37]}\", \"${json.allowed_billing_countries[38]}\", \"${json.allowed_billing_countries[39]}\", \"${json.allowed_billing_countries[40]}\", \"${json.allowed_billing_countries[41]}\", \"${json.allowed_billing_countries[42]}\", \"${json.allowed_billing_countries[43]}\", \"${json.allowed_billing_countries[44]}\", \"${json.allowed_billing_countries[45]}\", \"${json.allowed_billing_countries[46]}\", \"${json.allowed_billing_countries[47]}\", \"${json.allowed_billing_countries[48]}\", \"${json.allowed_billing_countries[49]}\", \"${json.allowed_billing_countries[50]}\", \"${json.allowed_billing_countries[51]}\", \"${json.allowed_billing_countries[52]}\", \"${json.allowed_billing_countries[53]}\", \"${json.allowed_billing_countries[54]}\", \"${json.allowed_billing_countries[55]}\", \"${json.allowed_billing_countries[56]}\", \"${json.allowed_billing_countries[57]}\", \"${json.allowed_billing_countries[58]}\", \"${json.allowed_billing_countries[59]}\", \"${json.allowed_billing_countries[60]}\", \"${json.allowed_billing_countries[61]}\", \"${json.allowed_billing_countries[62]}\", \"${json.allowed_billing_countries[63]}\", \"${json.allowed_billing_countries[64]}\", \"${json.allowed_billing_countries[65]}\", \"${json.allowed_billing_countries[66]}\", \"${json.allowed_billing_countries[67]}\", \"${json.allowed_billing_countries[68]}\", \"${json.allowed_billing_countries[69]}\", \"${json.allowed_billing_countries[70]}\", \"${json.allowed_billing_countries[71]}\", \"${json.allowed_billing_countries[72]}\", \"${json.allowed_billing_countries[73]}\", \"${json.allowed_billing_countries[74]}\", \"${json.allowed_billing_countries[75]}\", \"${json.allowed_billing_countries[76]}\", \"${json.allowed_billing_countries[77]}\", \"${json.allowed_billing_countries[78]}\", \"${json.allowed_billing_countries[79]}\", \"${json.allowed_billing_countries[80]}\", \"${json.allowed_billing_countries[81]}\", \"${json.allowed_billing_countries[82]}\", \"${json.allowed_billing_countries[83]}\", \"${json.allowed_billing_countries[84]}\", \"${json.allowed_billing_countries[85]}\", \"${json.allowed_billing_countries[86]}\", \"${json.allowed_billing_countries[87]}\", \"${json.allowed_billing_countries[88]}\", \"${json.allowed_billing_countries[89]}\", \"${json.allowed_billing_countries[90]}\", \"${json.allowed_billing_countries[91]}\", \"${json.allowed_billing_countries[92]}\", \"${json.allowed_billing_countries[93]}\", \"${json.allowed_billing_countries[94]}\", \"${json.allowed_billing_countries[95]}\", \"${json.allowed_billing_countries[96]}\", \"${json.allowed_billing_countries[97]}\", \"${json.allowed_billing_countries[98]}\", \"${json.allowed_billing_countries[99]}\", \"${json.allowed_billing_countries[100]}\", \"${json.allowed_billing_countries[101]}\", \"${json.allowed_billing_countries[102]}\", \"${json.allowed_billing_countries[103]}\", \"${json.allowed_billing_countries[104]}\", \"${json.allowed_billing_countries[105]}\", \"${json.allowed_billing_countries[106]}\", \"${json.allowed_billing_countries[107]}\", \"${json.allowed_billing_countries[108]}\", \"${json.allowed_billing_countries[109]}\", \"${json.allowed_billing_countries[110]}\", \"${json.allowed_billing_countries[111]}\", \"${json.allowed_billing_countries[112]}\", \"${json.allowed_billing_countries[113]}\", \"${json.allowed_billing_countries[114]}\", \"${json.allowed_billing_countries[115]}\", \"${json.allowed_billing_countries[116]}\", \"${json.allowed_billing_countries[117]}\", \"${json.allowed_billing_countries[118]}\", \"${json.allowed_billing_countries[119]}\", \"${json.allowed_billing_countries[120]}\", \"${json.allowed_billing_countries[121]}\", \"${json.allowed_billing_countries[122]}\", \"${json.allowed_billing_countries[123]}\", \"${json.allowed_billing_countries[124]}\", \"${json.allowed_billing_countries[125]}\", \"${json.allowed_billing_countries[126]}\", \"${json.allowed_billing_countries[127]}\", \"${json.allowed_billing_countries[128]}\", \"${json.allowed_billing_countries[129]}\", \"${json.allowed_billing_countries[130]}\", \"${json.allowed_billing_countries[131]}\", \"${json.allowed_billing_countries[132]}\", \"${json.allowed_billing_countries[133]}\", \"${json.allowed_billing_countries[134]}\", \"${json.allowed_billing_countries[135]}\", \"${json.allowed_billing_countries[136]}\", \"${json.allowed_billing_countries[137]}\", \"${json.allowed_billing_countries[138]}\", \"${json.allowed_billing_countries[139]}\", \"${json.allowed_billing_countries[140]}\", \"${json.allowed_billing_countries[141]}\", \"${json.allowed_billing_countries[142]}\", \"${json.allowed_billing_countries[143]}\", \"${json.allowed_billing_countries[144]}\", \"${json.allowed_billing_countries[145]}\", \"${json.allowed_billing_countries[146]}\", \"${json.allowed_billing_countries[147]}\", \"${json.allowed_billing_countries[148]}\", \"${json.allowed_billing_countries[149]}\", \"${json.allowed_billing_countries[150]}\", \"${json.allowed_billing_countries[151]}\", \"${json.allowed_billing_countries[152]}\", \"${json.allowed_billing_countries[153]}\", \"${json.allowed_billing_countries[154]}\", \"${json.allowed_billing_countries[155]}\", \"${json.allowed_billing_countries[156]}\", \"${json.allowed_billing_countries[157]}\", \"${json.allowed_billing_countries[158]}\", \"${json.allowed_billing_countries[159]}\", \"${json.allowed_billing_countries[160]}\", \"${json.allowed_billing_countries[161]}\", \"${json.allowed_billing_countries[162]}\", \"${json.allowed_billing_countries[163]}\", \"${json.allowed_billing_countries[164]}\", \"${json.allowed_billing_countries[165]}\", \"${json.allowed_billing_countries[166]}\", \"${json.allowed_billing_countries[167]}\", \"${json.allowed_billing_countries[168]}\", \"${json.allowed_billing_countries[169]}\", \"${json.allowed_billing_countries[170]}\", \"${json.allowed_billing_countries[171]}\", \"${json.allowed_billing_countries[172]}\", \"${json.allowed_billing_countries[173]}\", \"${json.allowed_billing_countries[174]}\", \"${json.allowed_billing_countries[175]}\", \"${json.allowed_billing_countries[176]}\", \"${json.allowed_billing_countries[177]}\", \"${json.allowed_billing_countries[178]}\", \"${json.allowed_billing_countries[179]}\", \"${json.allowed_billing_countries[180]}\", \"${json.allowed_billing_countries[181]}\", \"${json.allowed_billing_countries[182]}\", \"${json.allowed_billing_countries[183]}\", \"${json.allowed_billing_countries[184]}\", \"${json.allowed_billing_countries[185]}\", \"${json.allowed_billing_countries[186]}\", \"${json.allowed_billing_countries[187]}\", \"${json.allowed_billing_countries[188]}\", \"${json.allowed_billing_countries[189]}\", \"${json.allowed_billing_countries[190]}\", \"${json.allowed_billing_countries[191]}\", \"${json.allowed_billing_countries[192]}\", \"${json.allowed_billing_countries[193]}\", \"${json.allowed_billing_countries[194]}\", \"${json.allowed_billing_countries[195]}\", \"${json.allowed_billing_countries[196]}\", \"${json.allowed_billing_countries[197]}\", \"${json.allowed_billing_countries[198]}\", \"${json.allowed_billing_countries[199]}\", \"${json.allowed_billing_countries[200]}\", \"${json.allowed_billing_countries[201]}\", \"${json.allowed_billing_countries[202]}\", \"${json.allowed_billing_countries[203]}\", \"${json.allowed_billing_countries[204]}\", \"${json.allowed_billing_countries[205]}\", \"${json.allowed_billing_countries[206]}\", \"${json.allowed_billing_countries[207]}\", \"${json.allowed_billing_countries[208]}\", \"${json.allowed_billing_countries[209]}\", \"${json.allowed_billing_countries[210]}\"],\n\t\t\t\t\"allowed_shipping_countries\": [\"${json.allowed_shipping_countries[0]}\", \"${json.allowed_shipping_countries[1]}\", \"${json.allowed_shipping_countries[2]}\", \"${json.allowed_shipping_countries[3]}\", \"${json.allowed_shipping_countries[4]}\", \"${json.allowed_shipping_countries[5]}\", \"${json.allowed_shipping_countries[6]}\", \"${json.allowed_shipping_countries[7]}\", \"${json.allowed_shipping_countries[8]}\", \"${json.allowed_shipping_countries[9]}\", \"${json.allowed_shipping_countries[10]}\", \"${json.allowed_shipping_countries[11]}\", \"${json.allowed_shipping_countries[12]}\", \"${json.allowed_shipping_countries[13]}\", \"${json.allowed_shipping_countries[14]}\", \"${json.allowed_shipping_countries[15]}\", \"${json.allowed_shipping_countries[16]}\", \"${json.allowed_shipping_countries[17]}\", \"${json.allowed_shipping_countries[18]}\", \"${json.allowed_shipping_countries[19]}\", \"${json.allowed_shipping_countries[20]}\", \"${json.allowed_shipping_countries[21]}\", \"${json.allowed_shipping_countries[22]}\", \"${json.allowed_shipping_countries[23]}\", \"${json.allowed_shipping_countries[24]}\", \"${json.allowed_shipping_countries[25]}\", \"${json.allowed_shipping_countries[26]}\", \"${json.allowed_shipping_countries[27]}\", \"${json.allowed_shipping_countries[28]}\", \"${json.allowed_shipping_countries[29]}\", \"${json.allowed_shipping_countries[30]}\", \"${json.allowed_shipping_countries[31]}\", \"${json.allowed_shipping_countries[32]}\", \"${json.allowed_shipping_countries[33]}\", \"${json.allowed_shipping_countries[34]}\", \"${json.allowed_shipping_countries[35]}\", \"${json.allowed_shipping_countries[36]}\", \"${json.allowed_shipping_countries[37]}\", \"${json.allowed_shipping_countries[38]}\", \"${json.allowed_shipping_countries[39]}\", \"${json.allowed_shipping_countries[40]}\", \"${json.allowed_shipping_countries[41]}\", \"${json.allowed_shipping_countries[42]}\", \"${json.allowed_shipping_countries[43]}\", \"${json.allowed_shipping_countries[44]}\", \"${json.allowed_shipping_countries[45]}\", \"${json.allowed_shipping_countries[46]}\", \"${json.allowed_shipping_countries[47]}\", \"${json.allowed_shipping_countries[48]}\", \"${json.allowed_shipping_countries[49]}\", \"${json.allowed_shipping_countries[50]}\", \"${json.allowed_shipping_countries[51]}\", \"${json.allowed_shipping_countries[52]}\", \"${json.allowed_shipping_countries[53]}\", \"${json.allowed_shipping_countries[54]}\", \"${json.allowed_shipping_countries[55]}\", \"${json.allowed_shipping_countries[56]}\", \"${json.allowed_shipping_countries[57]}\", \"${json.allowed_shipping_countries[58]}\", \"${json.allowed_shipping_countries[59]}\", \"${json.allowed_shipping_countries[60]}\", \"${json.allowed_shipping_countries[61]}\", \"${json.allowed_shipping_countries[62]}\", \"${json.allowed_shipping_countries[63]}\", \"${json.allowed_shipping_countries[64]}\", \"${json.allowed_shipping_countries[65]}\", \"${json.allowed_shipping_countries[66]}\", \"${json.allowed_shipping_countries[67]}\", \"${json.allowed_shipping_countries[68]}\", \"${json.allowed_shipping_countries[69]}\", \"${json.allowed_shipping_countries[70]}\", \"${json.allowed_shipping_countries[71]}\", \"${json.allowed_shipping_countries[72]}\", \"${json.allowed_shipping_countries[73]}\", \"${json.allowed_shipping_countries[74]}\", \"${json.allowed_shipping_countries[75]}\", \"${json.allowed_shipping_countries[76]}\", \"${json.allowed_shipping_countries[77]}\", \"${json.allowed_shipping_countries[78]}\", \"${json.allowed_shipping_countries[79]}\", \"${json.allowed_shipping_countries[80]}\", \"${json.allowed_shipping_countries[81]}\", \"${json.allowed_shipping_countries[82]}\", \"${json.allowed_shipping_countries[83]}\", \"${json.allowed_shipping_countries[84]}\", \"${json.allowed_shipping_countries[85]}\", \"${json.allowed_shipping_countries[86]}\", \"${json.allowed_shipping_countries[87]}\", \"${json.allowed_shipping_countries[88]}\", \"${json.allowed_shipping_countries[89]}\", \"${json.allowed_shipping_countries[90]}\", \"${json.allowed_shipping_countries[91]}\", \"${json.allowed_shipping_countries[92]}\", \"${json.allowed_shipping_countries[93]}\", \"${json.allowed_shipping_countries[94]}\", \"${json.allowed_shipping_countries[95]}\", \"${json.allowed_shipping_countries[96]}\", \"${json.allowed_shipping_countries[97]}\", \"${json.allowed_shipping_countries[98]}\", \"${json.allowed_shipping_countries[99]}\", \"${json.allowed_shipping_countries[100]}\", \"${json.allowed_shipping_countries[101]}\", \"${json.allowed_shipping_countries[102]}\", \"${json.allowed_shipping_countries[103]}\", \"${json.allowed_shipping_countries[104]}\", \"${json.allowed_shipping_countries[105]}\", \"${json.allowed_shipping_countries[106]}\", \"${json.allowed_shipping_countries[107]}\", \"${json.allowed_shipping_countries[108]}\", \"${json.allowed_shipping_countries[109]}\", \"${json.allowed_shipping_countries[110]}\", \"${json.allowed_shipping_countries[111]}\", \"${json.allowed_shipping_countries[112]}\", \"${json.allowed_shipping_countries[113]}\", \"${json.allowed_shipping_countries[114]}\", \"${json.allowed_shipping_countries[115]}\", \"${json.allowed_shipping_countries[116]}\", \"${json.allowed_shipping_countries[117]}\", \"${json.allowed_shipping_countries[118]}\", \"${json.allowed_shipping_countries[119]}\", \"${json.allowed_shipping_countries[120]}\", \"${json.allowed_shipping_countries[121]}\", \"${json.allowed_shipping_countries[122]}\", \"${json.allowed_shipping_countries[123]}\", \"${json.allowed_shipping_countries[124]}\", \"${json.allowed_shipping_countries[125]}\", \"${json.allowed_shipping_countries[126]}\", \"${json.allowed_shipping_countries[127]}\", \"${json.allowed_shipping_countries[128]}\", \"${json.allowed_shipping_countries[129]}\", \"${json.allowed_shipping_countries[130]}\", \"${json.allowed_shipping_countries[131]}\", \"${json.allowed_shipping_countries[132]}\", \"${json.allowed_shipping_countries[133]}\", \"${json.allowed_shipping_countries[134]}\", \"${json.allowed_shipping_countries[135]}\", \"${json.allowed_shipping_countries[136]}\", \"${json.allowed_shipping_countries[137]}\", \"${json.allowed_shipping_countries[138]}\", \"${json.allowed_shipping_countries[139]}\", \"${json.allowed_shipping_countries[140]}\", \"${json.allowed_shipping_countries[141]}\", \"${json.allowed_shipping_countries[142]}\", \"${json.allowed_shipping_countries[143]}\", \"${json.allowed_shipping_countries[144]}\", \"${json.allowed_shipping_countries[145]}\", \"${json.allowed_shipping_countries[146]}\", \"${json.allowed_shipping_countries[147]}\", \"${json.allowed_shipping_countries[148]}\", \"${json.allowed_shipping_countries[149]}\", \"${json.allowed_shipping_countries[150]}\", \"${json.allowed_shipping_countries[151]}\", \"${json.allowed_shipping_countries[152]}\", \"${json.allowed_shipping_countries[153]}\", \"${json.allowed_shipping_countries[154]}\", \"${json.allowed_shipping_countries[155]}\", \"${json.allowed_shipping_countries[156]}\", \"${json.allowed_shipping_countries[157]}\", \"${json.allowed_shipping_countries[158]}\", \"${json.allowed_shipping_countries[159]}\", \"${json.allowed_shipping_countries[160]}\", \"${json.allowed_shipping_countries[161]}\", \"${json.allowed_shipping_countries[162]}\", \"${json.allowed_shipping_countries[163]}\", \"${json.allowed_shipping_countries[164]}\", \"${json.allowed_shipping_countries[165]}\", \"${json.allowed_shipping_countries[166]}\", \"${json.allowed_shipping_countries[167]}\", \"${json.allowed_shipping_countries[168]}\", \"${json.allowed_shipping_countries[169]}\", \"${json.allowed_shipping_countries[170]}\", \"${json.allowed_shipping_countries[171]}\", \"${json.allowed_shipping_countries[172]}\", \"${json.allowed_shipping_countries[173]}\", \"${json.allowed_shipping_countries[174]}\", \"${json.allowed_shipping_countries[175]}\", \"${json.allowed_shipping_countries[176]}\", \"${json.allowed_shipping_countries[177]}\", \"${json.allowed_shipping_countries[178]}\", \"${json.allowed_shipping_countries[179]}\", \"${json.allowed_shipping_countries[180]}\", \"${json.allowed_shipping_countries[181]}\", \"${json.allowed_shipping_countries[182]}\", \"${json.allowed_shipping_countries[183]}\", \"${json.allowed_shipping_countries[184]}\", \"${json.allowed_shipping_countries[185]}\", \"${json.allowed_shipping_countries[186]}\", \"${json.allowed_shipping_countries[187]}\", \"${json.allowed_shipping_countries[188]}\", \"${json.allowed_shipping_countries[189]}\", \"${json.allowed_shipping_countries[190]}\", \"${json.allowed_shipping_countries[191]}\", \"${json.allowed_shipping_countries[192]}\", \"${json.allowed_shipping_countries[193]}\", \"${json.allowed_shipping_countries[194]}\", \"${json.allowed_shipping_countries[195]}\", \"${json.allowed_shipping_countries[196]}\", \"${json.allowed_shipping_countries[197]}\", \"${json.allowed_shipping_countries[198]}\", \"${json.allowed_shipping_countries[199]}\", \"${json.allowed_shipping_countries[200]}\", \"${json.allowed_shipping_countries[201]}\", \"${json.allowed_shipping_countries[202]}\", \"${json.allowed_shipping_countries[203]}\", \"${json.allowed_shipping_countries[204]}\", \"${json.allowed_shipping_countries[205]}\", \"${json.allowed_shipping_countries[206]}\", \"${json.allowed_shipping_countries[207]}\", \"${json.allowed_shipping_countries[208]}\", \"${json.allowed_shipping_countries[209]}\", \"${json.allowed_shipping_countries[210]}\"],\n\t\t\t\t\"analytics_user_id\": \"${json.analytics_user_id}\",\n\t\t\t\t\"available_payment_methods\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"days\": \"${json.available_payment_methods[0].data.days}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"id\": \"${json.available_payment_methods[0].id}\",\n\t\t\t\t\t\t\"type\": \"${json.available_payment_methods[0].type}\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"cart\": {\n\t\t\t\t\t\"items\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"image_url\": \"${json.cart.items[0].image_url}\",\n\t\t\t\t\t\t\t\"name\": \"${json.cart.items[0].name}\",\n\t\t\t\t\t\t\t\"product_url\": \"${json.cart.items[0].product_url}\",\n\t\t\t\t\t\t\t\"quantity\": \"${json.cart.items[0].quantity}\",\n\t\t\t\t\t\t\t\"reference\": \"${json.cart.items[0].reference}\",\n\t\t\t\t\t\t\t\"tax_rate\": \"${json.cart.items[0].tax_rate}\",\n\t\t\t\t\t\t\t\"total_price_excluding_tax\": \"${json.cart.items[0].total_price_excluding_tax}\",\n\t\t\t\t\t\t\t\"total_price_including_tax\": \"${json.cart.items[0].total_price_including_tax}\",\n\t\t\t\t\t\t\t\"total_tax_amount\": \"${json.cart.items[0].total_tax_amount}\",\n\t\t\t\t\t\t\t\"type\": \"${json.cart.items[0].type}\",\n\t\t\t\t\t\t\t\"unit_price\": \"${json.cart.items[0].unit_price}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\t\"subtotal\": \"${json.cart.subtotal}\",\n\t\t\t\t\t\"total_discount_amount_excluding_tax\": \"${json.cart.total_discount_amount_excluding_tax}\",\n\t\t\t\t\t\"total_price_excluding_tax\": \"${json.cart.total_price_excluding_tax}\",\n\t\t\t\t\t\"total_price_including_tax\": \"${json.cart.total_price_including_tax}\",\n\t\t\t\t\t\"total_shipping_amount_excluding_tax\": \"${json.cart.total_shipping_amount_excluding_tax}\",\n\t\t\t\t\t\"total_store_credit\": \"${json.cart.total_store_credit}\",\n\t\t\t\t\t\"total_surcharge_amount_excluding_tax\": \"${json.cart.total_surcharge_amount_excluding_tax}\",\n\t\t\t\t\t\"total_tax_amount\": \"${json.cart.total_tax_amount}\"\n\t\t\t\t},\n\t\t\t\t\"correlation_id\": \"a6c51342-b107-4463-a2a0-b530f1bac03e\",\n\t\t\t\t\"merchant_urls\": {\n\t\t\t\t\t\"checkout\": \"${json.merchant_urls.checkout}\",\n\t\t\t\t\t\"confirmation\": \"${json.merchant_urls.confirmation}\",\n\t\t\t\t\t\"terms\": \"${json.merchant_urls.terms}\"\n\t\t\t\t},\n\t\t\t\t\"options\": {\n\t\t\t\t\t\"allow_separate_shipping_address\": \"${json.options.allow_separate_shipping_address}\",\n\t\t\t\t\t\"allowed_customer_types\": [\"${json.options.allowed_customer_types[0]}\"],\n\t\t\t\t\t\"date_of_birth_mandatory\": \"${json.options.date_of_birth_mandatory}\",\n\t\t\t\t\t\"national_identification_number_mandatory\": \"${json.options.national_identification_number_mandatory}\",\n\t\t\t\t\t\"payment_selector_on_load\": \"${json.options.payment_selector_on_load}\"\n\t\t\t\t},\n\t\t\t\t\"shared\": {\n\t\t\t\t\t\"billing_address\": {\n\t\t\t\t\t\t\"care_of\": \"${json.shared.billing_address.care_of}\",\n\t\t\t\t\t\t\"city\": \"${json.shared.billing_address.city}\",\n\t\t\t\t\t\t\"country\": \"${json.shared.billing_address.country}\",\n\t\t\t\t\t\t\"email\": \"${json.shared.billing_address.email}\",\n\t\t\t\t\t\t\"family_name\": \"${json.shared.billing_address.family_name}\",\n\t\t\t\t\t\t\"given_name\": \"${json.shared.billing_address.given_name}\",\n\t\t\t\t\t\t\"phone\": \"${json.shared.billing_address.phone}\",\n\t\t\t\t\t\t\"postal_code\": \"${json.shared.billing_address.postal_code}\",\n\t\t\t\t\t\t\"street_address\": \"${json.shared.billing_address.street_address}\",\n\t\t\t\t\t\t\"street_address2\": \"${json.shared.billing_address.street_address2}\"\n\t\t\t\t\t},\n\t\t\t\t\t\"challenge\": {\n\t\t\t\t\t\t\"country\": \"${json.shared.challenge.country}\",\n\t\t\t\t\t\t\"email\": \"${json.shared.challenge.email}\",\n\t\t\t\t\t\t\"postal_code\": \"${json.shared.challenge.postal_code}\"\n\t\t\t\t\t},\n\t\t\t\t\t\"currency\": \"${json.shared.currency}\",\n\t\t\t\t\t\"customer\": {\n\t\t\t\t\t\t\"national_identification_number\": \"${json.shared.customer.national_identification_number}\",\n\t\t\t\t\t\t\"type\": \"${json.shared.customer.type}\"\n\t\t\t\t\t},\n\t\t\t\t\t\"language\": \"${json.shared.language}\",\n\t\t\t\t\t\"selected_payment_method\": {\n\t\t\t\t\t\t\"data\": {\n\t\t\t\t\t\t\t\"days\": 14\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"id\": \"-1\",\n\t\t\t\t\t\t\"type\": \"invoice\"\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"status\": {\n\t\t\t\t\t\"prescreened\": \"${json.status.prescreened}\",\n\t\t\t\t\t\"require_terms_consent\": \"${json.status.require_terms_consent}\"\n\t\t\t\t}\n\t\t\t}`,\n\t\t\t{\n\t\t\t\t\"headers\": {\n\t\t\t\t\t\"Authorization\": \"Checkout otherStuffz\",\n\t\t\t\t\t\"User-Agent\": \"SysTest - perf\",\n\t\t\t\t\t\"Content-Type\": \"application/vnd.checkout.client-order-v1+json\",\n\t\t\t\t\t\"Accept\": \"application/vnd.checkout.server-order-v1+json\",\n\t\t\t\t\t\"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\",\n\t\t\t\t\t\"Host\": \"some-other-host.example.com\"\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t\tif (!check(res, {\"status is 200\": (r) => r.status === 200 })) { return };\n\t\tjson = JSON.parse(res.body);\n\t\t// Request #6\n\t\tres = http.connect(\"https://a-third-host.example.com:3000\",\n\t\t\"\"\n\t\t)\n\t});\n\n}\n"
  },
  {
    "path": "internal/cmd/testdata/fail.js",
    "content": "import exec from \"k6/execution\";\n\nexport default function () {\n\texec.test.fail();\n}\n"
  },
  {
    "path": "internal/cmd/testdata/initerr.js",
    "content": "someUndefinedVar\n"
  },
  {
    "path": "internal/cmd/testdata/invalidconfig/invalid.json",
    "content": "{\n    \"duration\": \"fails\"\n}\n"
  },
  {
    "path": "internal/cmd/testdata/invalidconfig/invalid_option.js",
    "content": "export const options = {\n    vus: 'this is an invalid type',\n}\n\nexport default function () {}\n"
  },
  {
    "path": "internal/cmd/testdata/invalidconfig/invalid_scenario.js",
    "content": "export const options = {\n    scenarios: {\n      example_scenario: {\n        // name of the executor to use\n        executor: 'shared-iterations',\n        // common scenario configuration\n        startTime: '10s',\n        gracefulStop: '5s',\n        env: { EXAMPLEVAR: 'testing' },\n        tags: { example_tag: 'testing' },\n  \n        // executor-specific configuration\n        vus: 10,\n        iterations: 200,\n        maxDuration: '10s',\n      },\n      another_scenario: {\n        /*...*/\n      },\n    },\n  };\n  "
  },
  {
    "path": "internal/cmd/testdata/invalidconfig/option_env.js",
    "content": "import http from 'k6/http';\n\nexport const options = {\n\titerations: 1,\n    duration: __ENV.DURATION,\n};\n\nexport default function () {\n  const res = http.get('https://test.k6.io');\n}\n"
  },
  {
    "path": "internal/cmd/testdata/summary/api.js",
    "content": "import http from 'k6/http'\nimport {check, group} from 'k6'\nimport {Trend} from 'k6/metrics';\n\nconst myTrend = new Trend('waiting_time');\n\nexport function apiTest() {\n\tconst res = http.get('https://httpbin.org/get')\n\tmyTrend.add(res.timings.waiting);\n\tcheck(res, {\n\t\t'httpbin.org is up': (r) => r.status === 200,\n\t\t'httpbin.org is down': (r) => r.status === 500,\n\t})\n\n\tgroup('auth', () => {\n\t\tconst res = http.post(\n\t\t\t'https://httpbin.org/auth',\n\t\t\tJSON.stringify({\n\t\t\t\tusername: 'sakai',\n\t\t\t\tfirst_name: 'jin',\n\t\t\t\tlast_name: 'sakai',\n\t\t\t\temail: 'jin.sakai@suckerpunch.com',\n\t\t\t\tpassword: 'onegaishimasu',\n\t\t\t})\n\t\t)\n\t\tmyTrend.add(res.timings.waiting);\n\t\tcheck(res, {\n\t\t\t'status is 201 CREATED': (r) => r.status === 201,\n\t\t})\n\n\t\tgroup('authorized crocodiles', () => {\n\t\t\tconst res = http.get('https://httpbin.org/get')\n\t\t\tmyTrend.add(res.timings.waiting);\n\t\t\tcheck(res, {\n\t\t\t\t'authorized crocodiles are 200 OK': (r) => r.status === 200,\n\t\t\t})\n\t\t})\n\t})\n\n\tgroup('my crocodiles', () => {\n\t\tconst res = http.get('https://httpbin.org/get')\n\t\tmyTrend.add(res.timings.waiting);\n\t\tcheck(res, {\n\t\t\t'my crocodiles are 200 OK': (r) => r.status === 200,\n\t\t})\n\t})\n}"
  },
  {
    "path": "internal/cmd/testdata/summary/browser.js",
    "content": "import {browser} from 'k6/browser'\n\nexport async function browserTest() {\n\tconst page = await browser.newPage()\n\n\ttry {\n\t\tawait page.goto('https://quickpizza.grafana.com')\n\t\tawait page.screenshot({path: 'screenshots/screenshot.png'})\n\t} finally {\n\t\tawait page.close()\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/testdata/summary/grpc.js",
    "content": "import grpc from 'k6/net/grpc';\nimport {check} from 'k6'\n\nconst GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';\nconst GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../../lib/testutils/grpcservice/route_guide.proto';\n\nlet client = new grpc.Client();\n\nclient.load([], GRPC_PROTO_PATH);\n\nexport function grpcTest() {\n\tclient.connect(GRPC_ADDR, {plaintext: true});\n\n\tconst response = client.invoke(\"main.FeatureExplorer/GetFeature\", {\n\t\tlatitude: 410248224,\n\t\tlongitude: -747127767\n\t})\n\n\tcheck(response, {\"gRPCC status is OK\": (r) => r && r.status === grpc.StatusOK});\n\tconsole.log(JSON.stringify(response.message))\n\n\tclient.close()\n}"
  },
  {
    "path": "internal/cmd/testdata/summary/main.js",
    "content": "export {apiTest} from './api.js';\nexport {browserTest} from './browser.js';\nexport {grpcTest} from './grpc.js';\nexport {wsTest} from './ws.js';\n\nexport const options = {\n\tthresholds: {\n\t\t'http_reqs': ['count<10', 'rate>2'],\n\t\t'http_reqs{group: ::auth}': ['count>1'],\n\t\t'http_reqs{scenario: api}': ['count>1'],\n\t\t'http_reqs{scenario: api, group: ::auth}': ['count<5'],\n\t\t'http_req_duration{group: ::auth}': ['p(95)<200', 'avg<100'],\n\t},\n\tscenarios: {\n\t\tapi: {\n\t\t\texecutor: 'per-vu-iterations',\n\t\t\tvus: 1,\n\t\t\titerations: 1,\n\t\t\texec: 'apiTest',\n\t\t},\n\t\tbrowser: {\n\t\t\texecutor: 'shared-iterations',\n\t\t\toptions: {\n\t\t\t\tbrowser: {\n\t\t\t\t\ttype: 'chromium',\n\t\t\t\t},\n\t\t\t},\n\t\t\texec: 'browserTest',\n\t\t},\n\t\tgrpc: {\n\t\t\texecutor: 'shared-iterations',\n\t\t\texec: 'grpcTest',\n\t\t},\n\t\tws: {\n\t\t\texecutor: 'shared-iterations',\n\t\t\texec: 'wsTest',\n\t\t},\n\t},\n}\n"
  },
  {
    "path": "internal/cmd/testdata/summary/ws.js",
    "content": "import {\n\trandomString,\n\trandomIntBetween,\n} from \"https://jslib.k6.io/k6-utils/1.1.0/index.js\";\nimport {WebSocket} from \"k6/websockets\";\nimport {\n\tsetTimeout,\n\tclearTimeout,\n\tsetInterval,\n\tclearInterval,\n} from \"k6/timers\";\n\nlet chatRoomName = \"publicRoom\"; // choose your chat room name\nlet sessionDuration = randomIntBetween(1000, 5000); // user session between 5s and 1m\n\nexport function wsTest() {\n\tfor (let i = 0; i < 4; i++) {\n\t\tstartWSWorker(i);\n\t}\n}\n\nfunction startWSWorker(id) {\n\tlet url = `wss://test-api.k6.io/ws/crocochat/${chatRoomName}/`;\n\tlet ws = new WebSocket(url);\n\tws.binaryType = \"arraybuffer\";\n\tws.addEventListener(\"open\", () => {\n\t\tws.send(\n\t\t\tJSON.stringify({\n\t\t\t\tevent: \"SET_NAME\",\n\t\t\t\tnew_name: `Croc ${__VU}:${id}`,\n\t\t\t})\n\t\t);\n\n\t\tws.addEventListener(\"message\", (e) => {\n\t\t\tlet msg = JSON.parse(e.data);\n\t\t\tif (msg.event === \"CHAT_MSG\") {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`VU ${__VU}:${id} received: ${msg.user} says: ${msg.message}`\n\t\t\t\t);\n\t\t\t} else if (msg.event === \"ERROR\") {\n\t\t\t\tconsole.error(`VU ${__VU}:${id} received:: ${msg.message}`);\n\t\t\t} else {\n\t\t\t\tconsole.log(\n\t\t\t\t\t`VU ${__VU}:${id} received unhandled message: ${msg.message}`\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\tlet intervalId = setInterval(() => {\n\t\t\tws.send(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tevent: \"SAY\",\n\t\t\t\t\tmessage: `I'm saying ${randomString(5)}`,\n\t\t\t\t})\n\t\t\t);\n\t\t}, randomIntBetween(2000, 8000)); // say something every 2-8seconds\n\n\t\tlet timeout1id = setTimeout(function () {\n\t\t\tclearInterval(intervalId);\n\t\t\tconsole.log(\n\t\t\t\t`VU ${__VU}:${id}: ${sessionDuration}ms passed, leaving the chat`\n\t\t\t);\n\t\t\tws.send(JSON.stringify({event: \"LEAVE\"}));\n\t\t}, sessionDuration);\n\n\t\tlet timeout2id = setTimeout(function () {\n\t\t\tconsole.log(\n\t\t\t\t`Closing the socket forcefully 3s after graceful LEAVE`\n\t\t\t);\n\t\t\tws.close();\n\t\t}, sessionDuration + 3000);\n\n\t\tws.addEventListener(\"close\", () => {\n\t\t\tclearTimeout(timeout1id);\n\t\t\tclearTimeout(timeout2id);\n\t\t\tconsole.log(`VU ${__VU}:${id}: disconnected`);\n\t\t});\n\t});\n}"
  },
  {
    "path": "internal/cmd/testdata/thresholds/empty_sink_no_nan.js",
    "content": "// In scenarios where a threshold would apply to a rate metric\n// that would not receive any samples (settting abortToFail emphasis the issue),\n// division by zero could occur and lead to NaN values being returned.\n//\n// Protects from #2520 regressions.\nimport { Rate } from \"k6/metrics\";\n\nconst rate = new Rate(\"rate\");\n\nexport const options = {\n\tthresholds: {\n\t\t\"rate{type:read}\": [{ threshold: \"rate>0.9\", abortOnFail: true }],\n\t},\n};\n\nexport default function () {\n\tconsole.log(\"not interacting with rate metric\");\n}\n"
  },
  {
    "path": "internal/cmd/testdata/thresholds/malformed_expression.js",
    "content": "export const options = {\n\tthresholds: {\n\t\thttp_reqs: [\"foo&0\"], // Counter\n\t},\n};\n\nexport default function () {\n\tconsole.log(\n\t\t\"asserting that a malformed threshold fails with exit code 104 (Invalid config)\"\n\t);\n}\n"
  },
  {
    "path": "internal/cmd/testdata/thresholds/name_contains_tokens.js",
    "content": "//  The threshold name contains the '{' and '}' characters, which\n// are used as tokens when parsing the submetric part of a threshold's\n// name. This pattern occurs when following the URL grouping pattern, and\n// should not error.\");\n//\n// Protects from #2512 regressions.\nexport const options = {\n\tthresholds: {\n\t\t\"http_req_duration{name:http://${}.com}\": [\"max < 1000\"],\n\t},\n};\n\nexport default function () {\n\tconsole.log(\n\t\t\"asserting a threshold's name containing parsable tokens is valid\"\n\t);\n}\n"
  },
  {
    "path": "internal/cmd/testdata/thresholds/non_existing_metric.js",
    "content": "export const options = {\n\tthresholds: {\n\t\t// non existing is neither registered, nor a builtin metric.\n\t\t// k6 should catch that.\n\t\t\"non existing\": [\"rate>0\"],\n\t},\n};\n\nexport default function () {\n\tconsole.log(\n\t\t\"asserting that a threshold over a non-existing metric fails with exit code 104 (Invalid config)\"\n\t);\n}\n"
  },
  {
    "path": "internal/cmd/testdata/thresholds/thresholds_on_submetric_without_samples.js",
    "content": "// Thresholds over submetrics without any values should still\n// be displayed under their proper parent metrics in the summary.\n//\n// Protects from #2518 regressions.\nimport { Counter } from \"k6/metrics\";\n\nconst counter1 = new Counter(\"one\");\nconst counter2 = new Counter(\"two\");\n\nexport const options = {\n\tthresholds: {\n\t\t\"one{tag:xyz}\": [],\n\t},\n};\n\nexport default function () {\n\tconsole.log(\"not submitting metric1\");\n\tcounter2.add(42);\n}\n"
  },
  {
    "path": "internal/cmd/testdata/thresholds/unsupported_aggregation_method.js",
    "content": "export const options = {\n\tthresholds: {\n\t\t// http_reqs is a Counter metric. As such, it supports\n\t\t// only the 'count' and 'rate' operations. Thus, 'value'\n\t\t// being a Gauge's metric aggregation method, the threshold\n\t\t// configuration evaluation should fail.\n\t\thttp_reqs: [\"value>0\"],\n\t},\n};\n\nexport default function () {\n\tconsole.log(\n\t\t\"asserting that a threshold applying a method over a metric not supporting it fails with exit code 104 (Invalid config)\"\n\t);\n}\n"
  },
  {
    "path": "internal/cmd/tests/cmd_cloud_login_test.go",
    "content": "package tests\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/cmd\"\n)\n\nconst (\n\tvalidToken       = \"valid-token\"\n\tvalidStackID     = 1234\n\tvalidStack       = \"valid-stack\"\n\tvalidStackURL    = \"https://valid-stack.grafana.net\"\n\tdefaultProjectID = 5678\n)\n\nfunc TestCloudLoginWithArgs(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname               string\n\t\ttoken              string\n\t\tstack              string\n\t\twantErr            bool\n\t\twantStdoutContains []string\n\t}{\n\t\t{\n\t\t\tname:    \"valid token\",\n\t\t\ttoken:   validToken,\n\t\t\twantErr: false,\n\t\t\twantStdoutContains: []string{\n\t\t\t\t\"Logged in successfully\",\n\t\t\t\tfmt.Sprintf(\"token: %s\", validToken),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"valid token and valid stack\",\n\t\t\ttoken:   validToken,\n\t\t\tstack:   validStack,\n\t\t\twantErr: false,\n\t\t\twantStdoutContains: []string{\n\t\t\t\t\"Logged in successfully\",\n\t\t\t\tfmt.Sprintf(\"token: %s\", validToken),\n\t\t\t\tfmt.Sprintf(\"stack-id: %d\", validStackID),\n\t\t\t\tfmt.Sprintf(\"stack-url: %s\", validStackURL),\n\t\t\t\tfmt.Sprintf(\"default-project-id: %d\", defaultProjectID),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"valid token and 'None' stack\",\n\t\t\ttoken:   validToken,\n\t\t\tstack:   \"None\",\n\t\t\twantErr: false,\n\t\t\twantStdoutContains: []string{\n\t\t\t\t\"Logged in successfully\",\n\t\t\t\tfmt.Sprintf(\"token: %s\", validToken),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:               \"invalid token\",\n\t\t\ttoken:              \"invalid-token\",\n\t\t\twantErr:            true,\n\t\t\twantStdoutContains: []string{\"your API token is invalid\"},\n\t\t},\n\t\t{\n\t\t\tname:               \"valid token and invalid stack\",\n\t\t\ttoken:              validToken,\n\t\t\tstack:              \"invalid-stack\",\n\t\t\twantErr:            true,\n\t\t\twantStdoutContains: []string{\"your stack is invalid\"},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsrv := mockValidateTokenServer(t)\n\t\t\tdefer srv.Close()\n\n\t\t\tts := NewGlobalTestState(t)\n\n\t\t\tts.CmdArgs = []string{\"k6\", \"cloud\", \"login\"}\n\t\t\tif tc.token != \"\" {\n\t\t\t\tts.CmdArgs = append(ts.CmdArgs, \"--token\", tc.token)\n\t\t\t}\n\t\t\tif tc.stack != \"\" {\n\t\t\t\tts.CmdArgs = append(ts.CmdArgs, \"--stack\", tc.stack)\n\t\t\t}\n\t\t\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\t\t\tts.Env[\"K6_CLOUD_HOST_V6\"] = srv.URL\n\n\t\t\tif tc.wantErr {\n\t\t\t\tts.ExpectedExitCode = -1\n\t\t\t} else {\n\t\t\t\tts.ExpectedExitCode = 0\n\t\t\t}\n\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tstdout := ts.Stdout.String()\n\t\t\tstderr := ts.Stderr.String()\n\n\t\t\tfor _, substr := range tc.wantStdoutContains {\n\t\t\t\tif tc.wantErr {\n\t\t\t\t\tassert.Contains(t, stderr, substr)\n\t\t\t\t} else {\n\t\t\t\t\tassert.Contains(t, stdout, substr)\n\t\t\t\t\tassert.Contains(t, stderr, \"\")\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc mockValidateTokenServer(t *testing.T) *httptest.Server {\n\tt.Helper()\n\n\treturn httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tswitch req.URL.Path {\n\t\t// v1 path to validate token only\n\t\tcase \"/v1/validate-token\":\n\t\t\tbody, err := io.ReadAll(req.Body)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar payload map[string]any\n\t\t\terr = json.Unmarshal(body, &payload)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Contains(t, payload, \"token\")\n\t\t\tif payload[\"token\"] == validToken {\n\t\t\t\t_, err = fmt.Fprintf(w, `{\"is_valid\": true, \"message\": \"Token is valid\"}`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\t_, err = fmt.Fprintf(w, `{\"is_valid\": false, \"message\": \"Token is invalid\"}`)\n\t\t\trequire.NoError(t, err)\n\n\t\t// v6 path to validate token and stack\n\t\tcase \"/cloud/v6/auth\":\n\t\t\tauthHeader := req.Header.Get(\"Authorization\")\n\t\t\tstackHeader := req.Header.Get(\"X-Stack-Url\")\n\t\t\tif authHeader == fmt.Sprintf(\"Bearer %s\", validToken) && stackHeader == validStackURL {\n\t\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t\t_, err := fmt.Fprintf(w, `{\"stack_id\": %d, \"default_project_id\": %d}`, validStackID, defaultProjectID)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}\n\t}))\n}\n"
  },
  {
    "path": "internal/cmd/tests/cmd_cloud_run_test.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/cmd\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestK6CloudRun(t *testing.T) {\n\tt.Parallel()\n\trunCloudTests(t, setupK6CloudRunCmd)\n}\n\nfunc setupK6CloudRunCmd(cliFlags []string) []string {\n\treturn append([]string{\"k6\", \"cloud\", \"run\"}, append(cliFlags, \"test.js\")...)\n}\n\nfunc TestCloudRunCommandIncompatibleFlags(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname               string\n\t\tcliArgs            []string\n\t\twantStderrContains string\n\t}{\n\t\t{\n\t\t\tname:               \"using --linger should be incompatible with k6 cloud run\",\n\t\t\tcliArgs:            []string{\"--linger\"},\n\t\t\twantStderrContains: \"the --linger flag can only be used in conjunction with the --local-execution flag\",\n\t\t},\n\t\t{\n\t\t\tname:               \"using --exit-on-running should be incompatible with k6 cloud run --local-execution\",\n\t\t\tcliArgs:            []string{\"--local-execution\", \"--exit-on-running\"},\n\t\t\twantStderrContains: \"the --local-execution flag is not compatible with the --exit-on-running flag\",\n\t\t},\n\t\t{\n\t\t\tname:               \"using --show-logs should be incompatible with k6 cloud run --local-execution\",\n\t\t\tcliArgs:            []string{\"--local-execution\", \"--show-logs\"},\n\t\t\twantStderrContains: \"the --local-execution flag is not compatible with the --show-logs flag\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := getSimpleCloudTestState(t, nil, setupK6CloudRunCmd, tc.cliArgs, nil, nil)\n\t\t\tts.ExpectedExitCode = int(exitcodes.InvalidConfig)\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tstderr := ts.Stderr.String()\n\t\t\tassert.Contains(t, stderr, tc.wantStderrContains)\n\t\t})\n\t}\n}\n\nfunc TestCloudRunLocalExecution(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"should upload the test archive with a multipart request as a default\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tscript := `\nexport const options = {\n  cloud: {\n      name: 'Hello k6 Cloud!',\n      projectID: 123456,\n  },\n};\n\nexport default function() {};`\n\n\t\tts := makeTestState(t, script, []string{\"--local-execution\"}, 0)\n\n\t\ttestServerHandlerFunc := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\t\t// When using the local execution mode, the test archive should be uploaded to the cloud\n\t\t\t// as a multipart request.\n\t\t\tformData, err := parseMultipartRequest(req)\n\t\t\trequire.NoError(t, err, \"expected a correctly formed multipart request\")\n\t\t\tassert.Contains(t, formData, \"name\")\n\t\t\tassert.Equal(t, \"Hello k6 Cloud!\", formData[\"name\"])\n\t\t\tassert.Contains(t, formData, \"project_id\")\n\t\t\tassert.Equal(t, \"123456\", formData[\"project_id\"])\n\t\t\tassert.Contains(t, formData, \"file\")\n\t\t\tassert.NotEmpty(t, formData[\"file\"])\n\n\t\t\tresp.WriteHeader(http.StatusOK)\n\t\t\t_, err = fmt.Fprint(resp, `{\n\t\t\t\"reference_id\": \"1337\",\n\t\t\t\"config\": {\n\t\t\t\t\"testRunDetails\": \"https://some.other.url/foo/tests/org/1337?bar=baz\"\n\t\t\t}\n\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tsrv := getCloudTestEndChecker(t, 1337, testServerHandlerFunc, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed)\n\t\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, \"execution: local\")\n\t\tassert.Contains(t, stdout, \"output: cloud (https://some.other.url/foo/tests/org/1337?bar=baz)\")\n\t})\n\n\tt.Run(\"does not upload the archive when --no-archive-upload is provided\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tscript := `\nexport const options = {\n  cloud: {\n      name: 'Hello k6 Cloud!',\n      projectID: 123456,\n  },\n};\n\nexport default function() {};`\n\n\t\tts := makeTestState(t, script, []string{\"--local-execution\", \"--no-archive-upload\"}, 0)\n\n\t\ttestServerHandlerFunc := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\t\tbody, err := io.ReadAll(req.Body)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar payload map[string]any\n\t\t\terr = json.Unmarshal(body, &payload)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Contains(t, payload, \"name\")\n\t\t\tassert.Equal(t, \"Hello k6 Cloud!\", payload[\"name\"])\n\t\t\tassert.Contains(t, payload, \"project_id\")\n\t\t\tassert.Equal(t, float64(123456), payload[\"project_id\"])\n\t\t\tassert.NotContains(t, payload, \"file\")\n\n\t\t\tresp.WriteHeader(http.StatusOK)\n\t\t\t_, err = fmt.Fprint(resp, `{\n\t\t\t\"reference_id\": \"1337\",\n\t\t\t\"config\": {\n\t\t\t\t\"testRunDetails\": \"https://some.other.url/foo/tests/org/1337?bar=baz\"\n\t\t\t}\n\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tsrv := getCloudTestEndChecker(t, 1337, testServerHandlerFunc, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed)\n\t\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, \"execution: local\")\n\t\tassert.Contains(t, stdout, \"output: cloud (https://some.other.url/foo/tests/org/1337?bar=baz)\")\n\t})\n\n\tt.Run(\"the script can read the test run id to the environment\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tscript := `\nexport const options = {\n  cloud: {\n      name: 'Hello k6 Cloud!',\n      projectID: 123456,\n  },\n};\n\nexport default function() {\n\t` + \"console.log(`The test run id is ${__ENV.K6_CLOUDRUN_TEST_RUN_ID}`);\" + `\n};`\n\n\t\tts := makeTestState(t, script, []string{\"--local-execution\", \"--log-output=stdout\"}, 0)\n\n\t\tconst testRunID = 1337\n\t\tsrv := getCloudTestEndChecker(t, testRunID, nil, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed)\n\t\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, \"execution: local\")\n\t\tassert.Contains(t, stdout, \"output: cloud (https://app.k6.io/runs/1337)\")\n\t\tassert.Contains(t, stdout, \"The test run id is \"+strconv.Itoa(testRunID))\n\t})\n}\n\nfunc makeTestState(tb testing.TB, script string, cliFlags []string, expExitCode exitcodes.ExitCode) *GlobalTestState {\n\tif cliFlags == nil {\n\t\tcliFlags = []string{\"-v\", \"--log-output=stdout\"}\n\t}\n\n\tts := NewGlobalTestState(tb)\n\trequire.NoError(tb, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.js\"), []byte(script), 0o644))\n\tts.CmdArgs = append(append([]string{\"k6\", \"cloud\", \"run\"}, cliFlags...), \"test.js\")\n\tts.ExpectedExitCode = int(expExitCode)\n\tts.Env[\"K6_CLOUD_TOKEN\"] = \"foo\" // doesn't matter, we mock the cloud\n\n\treturn ts\n}\n\nfunc parseMultipartRequest(r *http.Request) (map[string]string, error) {\n\t// Parse the multipart form data\n\treader, err := r.MultipartReader()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Initialize a map to store the parsed form data\n\tformData := make(map[string]string)\n\n\t// Iterate through the parts\n\tfor {\n\t\tpart, nextErr := reader.NextPart()\n\t\tif nextErr == io.EOF {\n\t\t\tbreak\n\t\t}\n\t\tif nextErr != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Read the part content\n\t\tbuf := new(bytes.Buffer)\n\t\t_, err = io.Copy(buf, part)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Store the part content in the map\n\t\tformData[part.FormName()] = buf.String()\n\t}\n\n\treturn formData, nil\n}\n"
  },
  {
    "path": "internal/cmd/tests/cmd_cloud_test.go",
    "content": "package tests\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/cmd\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestK6Cloud(t *testing.T) {\n\tt.Parallel()\n\trunCloudTests(t, setupK6CloudCmd)\n}\n\nfunc setupK6CloudCmd(cliFlags []string) []string {\n\treturn append([]string{\"k6\", \"cloud\"}, append(cliFlags, \"test.js\")...)\n}\n\ntype setupCommandFunc func(cliFlags []string) []string\n\nfunc runCloudTests(t *testing.T, setupCmd setupCommandFunc) {\n\tt.Run(\"TestCloudUserNotAuthenticated\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := getSimpleCloudTestState(t, nil, setupCmd, nil, nil, nil)\n\t\tdelete(ts.Env, \"K6_CLOUD_TOKEN\")\n\t\tts.ExpectedExitCode = -1 // TODO: use a more specific exit code?\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, `must first authenticate`)\n\t})\n\n\tt.Run(\"TestCloudLoggedInWithScriptToken\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tscript := `\n\t\texport let options = {\n\t\t\text: {\n\t\t\t\tloadimpact: {\n\t\t\t\t\ttoken: \"asdf\",\n\t\t\t\t\tname: \"my load test\",\n\t\t\t\t\tprojectID: 124,\n\t\t\t\t\tnote: 124,\n\t\t\t\t},\n\t\t\t}\n\t\t};\n\t\texport default function() {};\n\t`\n\n\t\tts := getSimpleCloudTestState(t, []byte(script), setupCmd, nil, nil, nil)\n\t\tdelete(ts.Env, \"K6_CLOUD_TOKEN\")\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.NotContains(t, stdout, `not logged in`)\n\t\tassert.Contains(t, stdout, `execution: cloud`)\n\t\tassert.Contains(t, stdout, `output: https://app.k6.io/runs/123`)\n\t\tassert.Contains(t, stdout, `test status: Finished`)\n\t})\n\n\tt.Run(\"TestCloudExitOnRunning\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcs := func() cloudapi.TestProgressResponse {\n\t\t\treturn cloudapi.TestProgressResponse{\n\t\t\t\tRunStatusText: \"Running\",\n\t\t\t\tRunStatus:     cloudapi.RunStatusRunning,\n\t\t\t}\n\t\t}\n\n\t\tts := getSimpleCloudTestState(t, nil, setupCmd, []string{\"--exit-on-running\", \"--log-output=stdout\"}, nil, cs)\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, `execution: cloud`)\n\t\tassert.Contains(t, stdout, `output: https://app.k6.io/runs/123`)\n\t\tassert.Contains(t, stdout, `test status: Running`)\n\t})\n\n\tt.Run(\"TestCloudUploadOnly\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcs := func() cloudapi.TestProgressResponse {\n\t\t\treturn cloudapi.TestProgressResponse{\n\t\t\t\tRunStatusText: \"Archived\",\n\t\t\t\tRunStatus:     cloudapi.RunStatusArchived,\n\t\t\t}\n\t\t}\n\n\t\tts := getSimpleCloudTestState(t, nil, setupCmd, []string{\"--upload-only\", \"--log-output=stdout\"}, nil, cs)\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, `execution: cloud`)\n\t\tassert.Contains(t, stdout, `output: https://app.k6.io/runs/123`)\n\t\tassert.Contains(t, stdout, `test status: Archived`)\n\t})\n\n\tt.Run(\"TestCloudWithConfigOverride\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconfigOverride := http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) {\n\t\t\tresp.WriteHeader(http.StatusOK)\n\t\t\t_, err := fmt.Fprint(resp, `{\n\t\t\t\"reference_id\": \"123\",\n\t\t\t\"config\": {\n\t\t\t\t\"webAppURL\": \"https://bogus.url\",\n\t\t\t\t\"testRunDetails\": \"something from the cloud\"\n\t\t\t},\n\t\t\t\"logs\": [\n\t\t\t\t{\"level\": \"invalid\", \"message\": \"test debug message\"},\n\t\t\t\t{\"level\": \"warning\", \"message\": \"test warning\"},\n\t\t\t\t{\"level\": \"error\", \"message\": \"test error\"}\n\t\t\t]\n\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tts := getSimpleCloudTestState(t, nil, setupCmd, nil, configOverride, nil)\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, \"execution: cloud\")\n\t\tassert.Contains(t, stdout, \"output: something from the cloud\")\n\t\tassert.Contains(t, stdout, `level=debug msg=\"invalid message level 'invalid' for message 'test debug message'`)\n\t\tassert.Contains(t, stdout, `level=error msg=\"test debug message\" source=grafana-k6-cloud`)\n\t\tassert.Contains(t, stdout, `level=warning msg=\"test warning\" source=grafana-k6-cloud`)\n\t\tassert.Contains(t, stdout, `level=error msg=\"test error\" source=grafana-k6-cloud`)\n\t})\n\n\t// TestCloudWithArchive tests that if k6 uses a static archive with the script inside that has cloud options like:\n\t//\n\t//\texport let options = {\n\t//\t\text: {\n\t//\t\t\tloadimpact: {\n\t//\t\t\t\tname: \"my load test\",\n\t//\t\t\t\tprojectID: 124,\n\t//\t\t\t\tnote: \"lorem ipsum\",\n\t//\t\t\t},\n\t//\t\t}\n\t//\t};\n\t//\n\t// actually sends to the cloud the archive with the correct metadata (metadata.json), like:\n\t//\n\t//\t\"ext\": {\n\t//\t\t\"loadimpact\": {\n\t//\t        \"name\": \"my load test\",\n\t//\t        \"note\": \"lorem ipsum\",\n\t//\t        \"projectID\": 124\n\t//\t      }\n\t//\t}\n\tt.Run(\"TestCloudWithArchive\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestRunID := 123\n\t\tts := NewGlobalTestState(t)\n\n\t\tarchiveUpload := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\t\t// check the archive\n\t\t\tfile, _, err := req.FormFile(\"file\")\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.NotNil(t, file)\n\n\t\t\t// temporary write the archive for file system\n\t\t\tdata, err := io.ReadAll(file)\n\t\t\tassert.NoError(t, err)\n\n\t\t\ttmpPath := filepath.Join(ts.Cwd, \"archive_to_cloud.tar\")\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, tmpPath, data, 0o644))\n\n\t\t\t// check what inside\n\t\t\trequire.NoError(t, testutils.Untar(t, ts.FS, tmpPath, \"tmp/\"))\n\n\t\t\tmetadataRaw, err := fsext.ReadFile(ts.FS, \"tmp/metadata.json\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmetadata := struct {\n\t\t\t\tOptions struct {\n\t\t\t\t\tCloud struct {\n\t\t\t\t\t\tName      string `json:\"name\"`\n\t\t\t\t\t\tNote      string `json:\"note\"`\n\t\t\t\t\t\tProjectID int    `json:\"projectID\"`\n\t\t\t\t\t} `json:\"cloud\"`\n\t\t\t\t} `json:\"options\"`\n\t\t\t}{}\n\n\t\t\t// then unpacked metadata should not contain any environment variables passed at the moment of archive creation\n\t\t\trequire.NoError(t, json.Unmarshal(metadataRaw, &metadata))\n\t\t\trequire.Equal(t, \"my load test\", metadata.Options.Cloud.Name)\n\t\t\trequire.Equal(t, \"lorem ipsum\", metadata.Options.Cloud.Note)\n\t\t\trequire.Equal(t, 124, metadata.Options.Cloud.ProjectID)\n\n\t\t\t// respond with the test run ID\n\t\t\tresp.WriteHeader(http.StatusOK)\n\t\t\t_, err = fmt.Fprintf(resp, `{\"reference_id\": \"%d\"}`, testRunID)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tsrv := getMockCloud(t, testRunID, archiveUpload, nil)\n\n\t\tdata, err := os.ReadFile(filepath.Join(\"testdata/archives\", \"archive_v0.46.0_with_loadimpact_option.tar\")) //nolint:forbidigo // it's a test\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"archive.tar\"), data, 0o644))\n\n\t\tts.CmdArgs = []string{\"k6\", \"cloud\", \"--verbose\", \"--log-output=stdout\", \"archive.tar\"}\n\t\tts.Env[\"K6_SHOW_CLOUD_LOGS\"] = \"false\" // no mock for the logs yet\n\t\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\t\tts.Env[\"K6_CLOUD_TOKEN\"] = \"foo\" // doesn't matter, we mock the cloud\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.NotContains(t, stdout, `not logged in`)\n\t\tassert.Contains(t, stdout, `execution: cloud`)\n\t\tassert.Contains(t, stdout, `hello world from archive`)\n\t\tassert.Contains(t, stdout, `output: https://app.k6.io/runs/123`)\n\t\tassert.Contains(t, stdout, `test status: Finished`)\n\t})\n\n\tt.Run(\"TestCloudThresholdsHaveFailed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tprogressCallback := func() cloudapi.TestProgressResponse {\n\t\t\treturn cloudapi.TestProgressResponse{\n\t\t\t\tRunStatusText: \"Finished\",\n\t\t\t\tRunStatus:     cloudapi.RunStatusFinished,\n\t\t\t\tResultStatus:  cloudapi.ResultStatusFailed,\n\t\t\t\tProgress:      1.0,\n\t\t\t}\n\t\t}\n\t\tts := getSimpleCloudTestState(t, nil, setupCmd, nil, nil, progressCallback)\n\t\tts.ExpectedExitCode = int(exitcodes.ThresholdsHaveFailed)\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, `Thresholds have been crossed`)\n\t})\n\n\tt.Run(\"TestCloudAbortedThreshold\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tprogressCallback := func() cloudapi.TestProgressResponse {\n\t\t\treturn cloudapi.TestProgressResponse{\n\t\t\t\tRunStatusText: \"Finished\",\n\t\t\t\tRunStatus:     cloudapi.RunStatusAbortedThreshold,\n\t\t\t\tResultStatus:  cloudapi.ResultStatusFailed,\n\t\t\t\tProgress:      1.0,\n\t\t\t}\n\t\t}\n\t\tts := getSimpleCloudTestState(t, nil, setupCmd, nil, nil, progressCallback)\n\t\tts.ExpectedExitCode = int(exitcodes.ThresholdsHaveFailed)\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, `Thresholds have been crossed`)\n\t})\n}\n\nfunc cloudTestStartSimple(tb testing.TB, testRunID int) http.Handler {\n\treturn http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) {\n\t\tresp.WriteHeader(http.StatusOK)\n\t\t_, err := fmt.Fprintf(resp, `{\"reference_id\": \"%d\"}`, testRunID)\n\t\tassert.NoError(tb, err)\n\t})\n}\n\nfunc getMockCloud(\n\tt *testing.T, testRunID int,\n\tarchiveUpload http.Handler, progressCallback func() cloudapi.TestProgressResponse,\n) *httptest.Server {\n\tif archiveUpload == nil {\n\t\tarchiveUpload = cloudTestStartSimple(t, testRunID)\n\t}\n\ttestProgressURL := fmt.Sprintf(\"GET ^/v1/test-progress/%d$\", testRunID)\n\tdefaultProgress := cloudapi.TestProgressResponse{\n\t\tRunStatusText: \"Finished\",\n\t\tRunStatus:     cloudapi.RunStatusFinished,\n\t\tResultStatus:  cloudapi.ResultStatusPassed,\n\t\tProgress:      1,\n\t}\n\n\tsrv := getTestServer(t, map[string]http.Handler{\n\t\t\"POST ^/v1/archive-upload$\": archiveUpload,\n\t\ttestProgressURL: http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) {\n\t\t\ttestProgress := defaultProgress\n\t\t\tif progressCallback != nil {\n\t\t\t\ttestProgress = progressCallback()\n\t\t\t}\n\t\t\trespBody, err := json.Marshal(testProgress)\n\t\t\tassert.NoError(t, err)\n\t\t\t_, err = fmt.Fprint(resp, string(respBody))\n\t\t\tassert.NoError(t, err)\n\t\t}),\n\t})\n\n\tt.Cleanup(srv.Close)\n\n\treturn srv\n}\n\nfunc getSimpleCloudTestState(t *testing.T, script []byte, setupCmd setupCommandFunc, cliFlags []string, archiveUpload http.Handler, progressCallback func() cloudapi.TestProgressResponse) *GlobalTestState {\n\tif script == nil {\n\t\tscript = []byte(`export default function() {}`)\n\t}\n\n\tif cliFlags == nil {\n\t\tcliFlags = []string{\"--verbose\", \"--log-output=stdout\"}\n\t}\n\n\tsrv := getMockCloud(t, 123, archiveUpload, progressCallback)\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.js\"), script, 0o644))\n\tts.CmdArgs = setupCmd(cliFlags)\n\tts.Env[\"K6_SHOW_CLOUD_LOGS\"] = \"false\" // no mock for the logs yet\n\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\tts.Env[\"K6_CLOUD_TOKEN\"] = \"foo\" // doesn't matter, we mock the cloud\n\n\treturn ts\n}\n"
  },
  {
    "path": "internal/cmd/tests/cmd_cloud_upload_test.go",
    "content": "package tests\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/internal/cmd\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestK6CloudUpload(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"TestCloudUploadUserNotAuthenticated\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := getSimpleCloudTestState(t, nil, setupK6CloudUploadCmd, nil, nil, nil)\n\t\tdelete(ts.Env, \"K6_CLOUD_TOKEN\")\n\t\tts.ExpectedExitCode = -1\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, `must first authenticate`)\n\t})\n\n\tt.Run(\"TestCloudUploadWithScript\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcs := func() cloudapi.TestProgressResponse {\n\t\t\treturn cloudapi.TestProgressResponse{\n\t\t\t\tRunStatusText: \"Archived\",\n\t\t\t\tRunStatus:     cloudapi.RunStatusArchived,\n\t\t\t}\n\t\t}\n\n\t\tts := getSimpleCloudTestState(t, nil, setupK6CloudUploadCmd, nil, nil, cs)\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.Contains(t, stdout, `execution: cloud`)\n\t\tassert.Contains(t, stdout, `output: https://app.k6.io/runs/123`)\n\t\tassert.Contains(t, stdout, `test status: Archived`)\n\t})\n\n\t// TestCloudUploadWithArchive tests that if k6 uses a static archive with the script inside that has cloud options like:\n\t//\n\t//\texport let options = {\n\t//\t\text: {\n\t//\t\t\tloadimpact: {\n\t//\t\t\t\tname: \"my load test\",\n\t//\t\t\t\tprojectID: 124,\n\t//\t\t\t\tnote: \"lorem ipsum\",\n\t//\t\t\t},\n\t//\t\t}\n\t//\t};\n\t//\n\t// actually sends to the cloud the archive with the correct metadata (metadata.json), like:\n\t//\n\t//\t\"ext\": {\n\t//\t\t\"loadimpact\": {\n\t//\t        \"name\": \"my load test\",\n\t//\t        \"note\": \"lorem ipsum\",\n\t//\t        \"projectID\": 124\n\t//\t      }\n\t//\t}\n\tt.Run(\"TestCloudUploadWithArchive\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestRunID := 123\n\t\tts := NewGlobalTestState(t)\n\n\t\tarchiveUpload := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\t\t// check the archive\n\t\t\tfile, _, err := req.FormFile(\"file\")\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.NotNil(t, file)\n\n\t\t\t// temporary write the archive for file system\n\t\t\tdata, err := io.ReadAll(file)\n\t\t\tassert.NoError(t, err)\n\n\t\t\ttmpPath := filepath.Join(ts.Cwd, \"archive_to_cloud.tar\")\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, tmpPath, data, 0o644))\n\n\t\t\t// check what inside\n\t\t\trequire.NoError(t, testutils.Untar(t, ts.FS, tmpPath, \"tmp/\"))\n\n\t\t\tmetadataRaw, err := fsext.ReadFile(ts.FS, \"tmp/metadata.json\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmetadata := struct {\n\t\t\t\tOptions struct {\n\t\t\t\t\tCloud struct {\n\t\t\t\t\t\tName      string `json:\"name\"`\n\t\t\t\t\t\tNote      string `json:\"note\"`\n\t\t\t\t\t\tProjectID int    `json:\"projectID\"`\n\t\t\t\t\t} `json:\"cloud\"`\n\t\t\t\t} `json:\"options\"`\n\t\t\t}{}\n\n\t\t\t// then unpacked metadata should not contain any environment variables passed at the moment of archive creation\n\t\t\trequire.NoError(t, json.Unmarshal(metadataRaw, &metadata))\n\t\t\trequire.Equal(t, \"my load test\", metadata.Options.Cloud.Name)\n\t\t\trequire.Equal(t, \"lorem ipsum\", metadata.Options.Cloud.Note)\n\t\t\trequire.Equal(t, 124, metadata.Options.Cloud.ProjectID)\n\n\t\t\t// respond with the test run ID\n\t\t\tresp.WriteHeader(http.StatusOK)\n\t\t\t_, err = fmt.Fprintf(resp, `{\"reference_id\": \"%d\"}`, testRunID)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tcs := func() cloudapi.TestProgressResponse {\n\t\t\treturn cloudapi.TestProgressResponse{\n\t\t\t\tRunStatusText: \"Archived\",\n\t\t\t\tRunStatus:     cloudapi.RunStatusArchived,\n\t\t\t}\n\t\t}\n\n\t\tsrv := getMockCloud(t, testRunID, archiveUpload, cs)\n\n\t\tdata, err := os.ReadFile(filepath.Join(\"testdata/archives\", \"archive_v0.46.0_with_loadimpact_option.tar\")) //nolint:forbidigo // it's a test\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"archive.tar\"), data, 0o644))\n\n\t\tts.CmdArgs = []string{\"k6\", \"cloud\", \"upload\", \"archive.tar\"}\n\t\tts.Env[\"K6_SHOW_CLOUD_LOGS\"] = \"false\" // no mock for the logs yet\n\t\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\t\tts.Env[\"K6_CLOUD_TOKEN\"] = \"foo\" // doesn't matter, we mock the cloud\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\t\tassert.NotContains(t, stdout, `not logged in`)\n\t\tassert.Contains(t, stdout, `execution: cloud`)\n\t\tassert.Contains(t, stdout, `output: https://app.k6.io/runs/123`)\n\t\tassert.Contains(t, stdout, `test status: Archived`)\n\t})\n}\n\nfunc setupK6CloudUploadCmd(cliFlags []string) []string {\n\treturn append([]string{\"k6\", \"cloud\", \"upload\"}, append(cliFlags, \"test.js\")...)\n}\n"
  },
  {
    "path": "internal/cmd/tests/cmd_run_grpc_test.go",
    "content": "package tests\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/cmd\"\n\t\"go.k6.io/k6/lib/fsext\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst projectRootPath = \"../../../\"\n\n// TestGRPCInputOutput runs same k6's scripts that we have in example folder\n// it checks that output contains/not contains cetane things\nfunc TestGRPCInputOutput(t *testing.T) {\n\tt.Parallel()\n\n\ttc := map[string]struct {\n\t\tscript                 string\n\t\toutputShouldContain    []string\n\t\toutputShouldNotContain []string\n\t}{\n\t\t\"Server streaming\": {\n\t\t\tscript: projectRootPath + \"examples/grpc_server_streaming.js\",\n\t\t\toutputShouldContain: []string{\n\t\t\t\t\"output: -\",\n\t\t\t\t\"default: 1 iterations for each of 1 VUs\",\n\t\t\t\t\"1 complete and 0 interrupted iterations\",\n\t\t\t\t\"Found feature called\",\n\t\t\t\t\"grpc_streams\",\n\t\t\t\t\"grpc_streams_msgs_received\",\n\t\t\t\t\"grpc_streams_msgs_sent\",\n\t\t\t\t\"All done\",\n\t\t\t},\n\t\t\toutputShouldNotContain: []string{\n\t\t\t\t\"Stream Error:\",\n\t\t\t},\n\t\t},\n\t\t\"Client Streaming\": {\n\t\t\tscript: projectRootPath + \"examples/grpc_client_streaming.js\",\n\t\t\toutputShouldContain: []string{\n\t\t\t\t\"output: -\",\n\t\t\t\t\"default: 1 iterations for each of 1 VUs\",\n\t\t\t\t\"1 complete and 0 interrupted iterations\",\n\t\t\t\t\"Visiting point\",\n\t\t\t\t\"Finished trip with 5 points\",\n\t\t\t\t\"Passed 5 feature\",\n\t\t\t\t\"grpc_streams\",\n\t\t\t\t\"grpc_streams_msgs_received\",\n\t\t\t\t\"grpc_streams_msgs_sent\",\n\t\t\t\t\"All done\",\n\t\t\t},\n\t\t\toutputShouldNotContain: []string{\n\t\t\t\t\"Stream Error:\",\n\t\t\t},\n\t\t},\n\t\t\"Invoke\": {\n\t\t\tscript: projectRootPath + \"examples/grpc_invoke.js\",\n\t\t\toutputShouldContain: []string{\n\t\t\t\t\"output: -\",\n\t\t\t\t\"default: 1 iterations for each of 1 VUs\",\n\t\t\t\t\"1 complete and 0 interrupted iterations\",\n\t\t\t\t\"3 Hasta Way, Newton, NJ 07860, USA\",\n\t\t\t},\n\t\t\toutputShouldNotContain: []string{\n\t\t\t\t\"grpc_streams\",\n\t\t\t\t\"grpc_streams_msgs_received\",\n\t\t\t\t\"grpc_streams_msgs_sent\",\n\t\t\t},\n\t\t},\n\t\t\"Reflection\": {\n\t\t\tscript: projectRootPath + \"examples/grpc_reflection.js\",\n\t\t\toutputShouldContain: []string{\n\t\t\t\t\"output: -\",\n\t\t\t\t\"default: 1 iterations for each of 1 VUs\",\n\t\t\t\t\"1 complete and 0 interrupted iterations\",\n\t\t\t\t\"3 Hasta Way, Newton, NJ 07860, USA\",\n\t\t\t},\n\t\t\toutputShouldNotContain: []string{\n\t\t\t\t\"grpc_streams\",\n\t\t\t\t\"grpc_streams_msgs_received\",\n\t\t\t\t\"grpc_streams_msgs_sent\",\n\t\t\t},\n\t\t},\n\t}\n\n\t// Read the proto file from the testutils package\n\t// it's same that we use in the examples\n\tproto, err := os.ReadFile(projectRootPath + \"internal/lib/testutils/grpcservice/route_guide.proto\") //nolint:forbidigo\n\trequire.NoError(t, err)\n\n\tfor name, test := range tc {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := NewGRPC(t)\n\n\t\t\tscript, err := os.ReadFile(test.script) //nolint:forbidigo\n\t\t\trequire.NoError(t, err)\n\n\t\t\tts := getSingleFileTestState(t, string(script), []string{\"-v\", \"--log-output=stdout\", \"--no-usage-report\"}, 0)\n\t\t\tts.Env = map[string]string{\n\t\t\t\t\"GRPC_ADDR\":       tb.Addr,\n\t\t\t\t\"GRPC_PROTO_PATH\": \"./proto.proto\",\n\t\t\t}\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"proto.proto\"), proto, 0o644))\n\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tstdout := ts.Stdout.String()\n\n\t\t\tfor _, s := range test.outputShouldContain {\n\t\t\t\tassert.Contains(t, stdout, s)\n\t\t\t}\n\t\t\tfor _, s := range test.outputShouldNotContain {\n\t\t\t\tassert.NotContains(t, stdout, s)\n\t\t\t}\n\n\t\t\tassert.Empty(t, ts.Stderr.String())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/tests/cmd_run_test.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"github.com/tidwall/gjson\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/cmd\"\n\t\"go.k6.io/k6/internal/cmd/tests/events\"\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestVersion(t *testing.T) {\n\tt.Parallel()\n\n\ttests := map[string]struct {\n\t\targs string\n\t}{\n\t\t\"flag\":       {\"--version\"},\n\t\t\"subcommand\": {\"version\"},\n\t}\n\n\tts := NewGlobalTestState(t)\n\n\tfor _, tc := range tests {\n\t\tts.CmdArgs = []string{\"k6\", tc.args}\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tassert.Contains(t, stdout, \"k6 v\"+build.Version)\n\t\tassert.Contains(t, stdout, runtime.Version())\n\t\tassert.Contains(t, stdout, runtime.GOOS)\n\t\tassert.Contains(t, stdout, runtime.GOARCH)\n\t}\n\n\tassert.Empty(t, ts.Stderr.Bytes())\n\tassert.Empty(t, ts.LoggerHook.Drain())\n}\n\nfunc TestSimpleTestStdin(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-\"}\n\tts.Stdin = bytes.NewBufferString(`export default function() {};`)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tassert.Contains(t, stdout, \"output: -\")\n\tassert.Contains(t, stdout, \"default: 1 iterations for each of 1 VUs\")\n\tassert.Contains(t, stdout, \"1 complete and 0 interrupted iterations\")\n\tassert.Empty(t, ts.Stderr.Bytes())\n\tassert.Empty(t, ts.LoggerHook.Drain())\n}\n\nfunc TestBinaryNameStdout(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.BinaryName = \"customBinaryName\"\n\tts.CmdArgs = []string{ts.BinaryName}\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tassert.Contains(t, stdout, fmt.Sprintf(\"%s [command]\", ts.BinaryName))\n\tassert.Empty(t, ts.Stderr.Bytes())\n\tassert.Empty(t, ts.LoggerHook.Drain())\n}\n\nfunc TestBinaryNameHelpStdout(t *testing.T) {\n\tt.Parallel()\n\tts := NewGlobalTestState(t)\n\tts.BinaryName = \"customBinaryName\"\n\n\ttests := []struct {\n\t\tcmdName        string\n\t\textraCmd       string // For the `login cloud` cmd\n\t\tcontainsOutput string\n\t}{\n\t\t{\n\t\t\tcmdName:        \"archive\",\n\t\t\tcontainsOutput: fmt.Sprintf(\"%s archive -u 10 -d 10s -O myarchive.tar script.js\", ts.BinaryName),\n\t\t},\n\t\t{\n\t\t\tcmdName:        \"cloud\",\n\t\t\tcontainsOutput: fmt.Sprintf(\"%s cloud script.js\", ts.BinaryName),\n\t\t},\n\t\t{\n\t\t\tcmdName:        \"login\",\n\t\t\textraCmd:       \"cloud\",\n\t\t\tcontainsOutput: fmt.Sprintf(\"%s login cloud -t YOUR_TOKEN\", ts.BinaryName),\n\t\t},\n\t\t{\n\t\t\tcmdName:        \"run\",\n\t\t\tcontainsOutput: fmt.Sprintf(\"%s run -i 10 script.js\", ts.BinaryName),\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tts.CmdArgs = []string{ts.BinaryName, \"help\", tt.cmdName, tt.extraCmd}\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\t\tstdout := ts.Stdout.String()\n\t\tassert.Contains(t, stdout, tt.containsOutput)\n\t\tassert.Empty(t, ts.Stderr.Bytes())\n\t\tassert.Empty(t, ts.LoggerHook.Drain())\n\t}\n}\n\n// TODO: Remove this? It doesn't test anything AFAICT...\nfunc TestStdoutAndStderrAreEmptyWithQuietAndHandleSummary(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"--quiet\", \"run\", \"-\"}\n\tts.Stdin = bytes.NewBufferString(`\n\t\texport default function() {};\n\t\texport function handleSummary(data) {\n\t\t\treturn {}; // silence the end of test summary\n\t\t};\n\t`)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tassert.Empty(t, ts.Stderr.Bytes())\n\tassert.Empty(t, ts.Stdout.Bytes())\n\tassert.Empty(t, ts.LoggerHook.Drain())\n}\n\nfunc TestStdoutAndStderrAreEmptyWithQuietAndLogsForwarded(t *testing.T) {\n\tt.Parallel()\n\n\t// TODO(@joanlopez): remove by k6 v2.0, once we completely drop the support of the deprecated --no-summary flag.\n\tt.Run(\"--no-summary\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := NewGlobalTestState(t)\n\n\t\t// TODO: add a test with relative path\n\t\tlogFilePath := filepath.Join(ts.Cwd, \"test.log\")\n\n\t\tts.CmdArgs = []string{\n\t\t\t\"k6\", \"--quiet\", \"--log-output\", \"file=\" + logFilePath,\n\t\t\t\"--log-format\", \"raw\", \"run\", \"--no-summary\", \"-\",\n\t\t}\n\t\tts.Stdin = bytes.NewBufferString(`\n\t\tconsole.log('init');\n\t\texport default function() { console.log('foo'); };\n\t`)\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t// The test state hook still catches this message\n\t\tassert.True(t, testutils.LogContains(ts.LoggerHook.Drain(), logrus.InfoLevel, `foo`))\n\n\t\t// But it's not shown on stderr or stdout\n\t\tassert.Empty(t, ts.Stderr.Bytes())\n\t\tassert.Equal(t,\n\t\t\t\"Flag --no-summary has been deprecated, use --summary-mode=disabled instead\\n\",\n\t\t\tts.Stdout.String(),\n\t\t) // We don't expect it to be completely empty, but to contain the deprecation message for --no-summary.\n\n\t\t// Instead, it should be in the log file\n\t\tlogContents, err := fsext.ReadFile(ts.FS, logFilePath)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"init\\ninit\\nfoo\\n\", string(logContents)) //nolint:dupword\n\t})\n\n\tt.Run(\"--summary-mode=disabled\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := NewGlobalTestState(t)\n\n\t\t// TODO: add a test with relative path\n\t\tlogFilePath := filepath.Join(ts.Cwd, \"test.log\")\n\n\t\tts.CmdArgs = []string{\n\t\t\t\"k6\", \"--quiet\", \"--log-output\", \"file=\" + logFilePath,\n\t\t\t\"--log-format\", \"raw\", \"run\", \"--summary-mode=disabled\", \"-\",\n\t\t}\n\t\tts.Stdin = bytes.NewBufferString(`\n\t\tconsole.log('init');\n\t\texport default function() { console.log('foo'); };\n\t`)\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t// The test state hook still catches this message\n\t\tassert.True(t, testutils.LogContains(ts.LoggerHook.Drain(), logrus.InfoLevel, `foo`))\n\n\t\t// But it's not shown on stderr or stdout\n\t\tassert.Empty(t, ts.Stderr.Bytes())\n\t\tassert.Empty(t, ts.Stdout.Bytes())\n\n\t\t// Instead, it should be in the log file\n\t\tlogContents, err := fsext.ReadFile(ts.FS, logFilePath)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"init\\ninit\\nfoo\\n\", string(logContents)) //nolint:dupword\n\t})\n}\n\nfunc TestRelativeLogPathWithSetupAndTeardown(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\n\tts.CmdArgs = []string{\"k6\", \"--log-output\", \"file=test.log\", \"--log-format\", \"raw\", \"run\", \"-i\", \"2\", \"-\"}\n\tts.Stdin = bytes.NewBufferString(`\n\t\tconsole.log('init');\n\t\texport default function() { console.log('foo'); };\n\t\texport function setup() { console.log('bar'); };\n\t\texport function teardown() { console.log('baz'); };\n\t`)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t// The test state hook still catches these messages\n\tlogEntries := ts.LoggerHook.Drain()\n\tassert.True(t, testutils.LogContains(logEntries, logrus.InfoLevel, `foo`))\n\tassert.True(t, testutils.LogContains(logEntries, logrus.InfoLevel, `bar`))\n\tassert.True(t, testutils.LogContains(logEntries, logrus.InfoLevel, `baz`))\n\n\t// And check that the log file also contains everything\n\tlogContents, err := fsext.ReadFile(ts.FS, filepath.Join(ts.Cwd, \"test.log\"))\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"init\\ninit\\ninit\\nbar\\nfoo\\nfoo\\ninit\\nbaz\\ninit\\n\", string(logContents)) //nolint:dupword\n}\n\nfunc TestWrongCliFlagIterations(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--iterations\", \"foo\", \"-\"}\n\tts.Stdin = bytes.NewBufferString(`export default function() {};`)\n\t// TODO: check for exitcodes.InvalidConfig after https://github.com/loadimpact/k6/issues/883 is done...\n\tts.ExpectedExitCode = -1\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\tassert.True(t, testutils.LogContains(ts.LoggerHook.Drain(), logrus.ErrorLevel, `invalid argument \"foo\"`))\n}\n\nfunc TestWrongEnvVarIterations(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--vus\", \"2\", \"-\"}\n\tts.Env[\"K6_ITERATIONS\"] = \"4\"\n\tts.Stdin = bytes.NewBufferString(`export default function() {};`)\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"4 iterations shared among 2 VUs\")\n\tassert.Contains(t, stdout, \"4 complete and 0 interrupted iterations\")\n\tassert.Empty(t, ts.Stderr.Bytes())\n\tassert.Empty(t, ts.LoggerHook.Drain())\n}\n\nfunc getSingleFileTestState(tb testing.TB, script string, cliFlags []string, expExitCode exitcodes.ExitCode) *GlobalTestState {\n\tif cliFlags == nil {\n\t\tcliFlags = []string{\"-v\", \"--log-output=stdout\"}\n\t}\n\n\tts := NewGlobalTestState(tb)\n\trequire.NoError(tb, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.js\"), []byte(script), 0o644))\n\tts.CmdArgs = append(append([]string{\"k6\", \"run\"}, cliFlags...), \"test.js\")\n\tts.ExpectedExitCode = int(expExitCode)\n\n\treturn ts\n}\n\nfunc TestMetricsAndThresholds(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport { Counter } from 'k6/metrics';\n\n\t\tvar setupCounter = new Counter('setup_counter');\n\t\tvar teardownCounter = new Counter('teardown_counter');\n\t\tvar defaultCounter = new Counter('default_counter');\n\t\tlet unusedCounter = new Counter('unused_counter');\n\n\t\texport const options = {\n\t\t\tscenarios: {\n\t\t\t\tsc1: {\n\t\t\t\t\texecutor: 'per-vu-iterations',\n\t\t\t\t\tvus: 1,\n\t\t\t\t\titerations: 1,\n\t\t\t\t},\n\t\t\t\tsc2: {\n\t\t\t\t\texecutor: 'shared-iterations',\n\t\t\t\t\tvus: 1,\n\t\t\t\t\titerations: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t\tthresholds: {\n\t\t\t\t'setup_counter': ['count == 1'],\n\t\t\t\t'teardown_counter': ['count == 1'],\n\t\t\t\t'default_counter': ['count == 2'],\n\t\t\t\t'default_counter{scenario:sc1}': ['count == 1'],\n\t\t\t\t'default_counter{scenario:sc2}': ['count == 1'],\n\t\t\t\t'iterations': ['count == 2'],\n\t\t\t\t'iterations{scenario:sc1}': ['count == 1'],\n\t\t\t\t'iterations{scenario:sc2}': ['count == 1'],\n\t\t\t\t'default_counter{nonexistent:tag}': ['count == 0'],\n\t\t\t\t'unused_counter': ['count == 0'],\n\t\t\t\t'http_req_duration{status:200}': [' max == 0'], // no HTTP requests\n\t\t\t},\n\t\t};\n\n\t\texport function setup() {\n\t\t\tconsole.log('setup() start');\n\t\t\tsetupCounter.add(1);\n\t\t\tconsole.log('setup() end');\n\t\t\treturn { foo: 'bar' }\n\t\t}\n\n\t\texport default function (data) {\n\t\t\tconsole.log('default(' + JSON.stringify(data) + ')');\n\t\t\tdefaultCounter.add(1);\n\t\t}\n\n\t\texport function teardown(data) {\n\t\t\tconsole.log('teardown(' + JSON.stringify(data) + ')');\n\t\t\tteardownCounter.add(1);\n\t\t}\n\n\t\texport function handleSummary(data) {\n\t\t\tconsole.log('handleSummary()');\n\t\t\treturn { stdout: JSON.stringify(data, null, 4) }\n\t\t}\n\t`\n\tts := getSingleFileTestState(t, script, []string{\"--quiet\", \"--log-format=raw\"}, 0)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\texpLogLines := []string{\n\t\t`setup() start`, `setup() end`, `default({\"foo\":\"bar\"})`,\n\t\t`default({\"foo\":\"bar\"})`, `teardown({\"foo\":\"bar\"})`, `handleSummary()`,\n\t}\n\n\tlogHookEntries := ts.LoggerHook.Drain()\n\trequire.Len(t, logHookEntries, len(expLogLines))\n\tfor i, expLogLine := range expLogLines {\n\t\tassert.Equal(t, expLogLine, logHookEntries[i].Message)\n\t}\n\n\tassert.Equal(t, strings.Join(expLogLines, \"\\n\")+\"\\n\", ts.Stderr.String())\n\n\tvar summary map[string]any\n\trequire.NoError(t, json.Unmarshal(ts.Stdout.Bytes(), &summary))\n\n\tmetrics, ok := summary[\"metrics\"].(map[string]any)\n\trequire.True(t, ok)\n\n\tteardownCounter, ok := metrics[\"teardown_counter\"].(map[string]any)\n\trequire.True(t, ok)\n\n\tteardownThresholds, ok := teardownCounter[\"thresholds\"].(map[string]any)\n\trequire.True(t, ok)\n\n\texpected := map[string]any{\"count == 1\": map[string]any{\"ok\": true}}\n\trequire.Equal(t, expected, teardownThresholds)\n}\n\nfunc TestThresholdsWithCustomPercentile(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\texport const options = {\n\t\t\tscenarios: {\n\t\t\t\tsc1: {\n\t\t\t\t\texecutor: 'per-vu-iterations',\n\t\t\t\t\tvus: 1,\n\t\t\t\t\titerations: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t\tthresholds: {\n\t\t\t\t'iteration_duration': ['p(0)<50', 'p(90)<100', 'p(99.5)<150', 'p(99.99)<200'],\n\t\t\t},\n\t\t};\n\n\t\texport default function () {}\n\t`\n\tts := getSingleFileTestState(t, script, nil, 0)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\n\t// We want to make sure that all the thresholds expressions are accompanied\n\t// by their values, despite those being present in `options.summaryTrendStats` or not.\n\tassert.Regexp(t, `✓ 'p\\(0\\)<50' p\\(0\\)=\\d+(\\.\\d+)?(µs|ms|ns|s)`, stdout)\n\tassert.Regexp(t, `✓ 'p\\(90\\)<100' p\\(90\\)=\\d+(\\.\\d+)?(µs|ms|ns|s)`, stdout)\n\tassert.Regexp(t, `✓ 'p\\(99.5\\)<150' p\\(99.5\\)=\\d+(\\.\\d+)?(µs|ms|ns|s)`, stdout)\n\tassert.Regexp(t, `✓ 'p\\(99.99\\)<200' p\\(99.99\\)=\\d+(\\.\\d+)?(µs|ms|ns|s)`, stdout)\n}\n\nfunc TestSSLKEYLOGFILEAbsolute(t *testing.T) {\n\tt.Parallel()\n\tts := NewGlobalTestState(t)\n\ttestSSLKEYLOGFILE(t, ts, filepath.Join(ts.Cwd, \"ssl.log\"))\n}\n\nfunc TestSSLKEYLOGFILEARelative(t *testing.T) {\n\tt.Parallel()\n\tts := NewGlobalTestState(t)\n\ttestSSLKEYLOGFILE(t, ts, \"./ssl.log\")\n}\n\nfunc testSSLKEYLOGFILE(t *testing.T, ts *GlobalTestState, filePath string) {\n\tt.Helper()\n\n\t// TODO don't use insecureSkipTLSVerify when/if tlsConfig is given to the runner from outside\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-\"}\n\tts.Env[\"SSLKEYLOGFILE\"] = filePath\n\tts.Stdin = bytes.NewReader([]byte(tb.Replacer.Replace(`\n    import http from \"k6/http\"\n    export const options = {\n      hosts: {\n        \"HTTPSBIN_DOMAIN\": \"HTTPSBIN_IP\",\n      },\n      insecureSkipTLSVerify: true,\n    }\n\n    export default () => {\n      http.get(\"HTTPSBIN_URL/get\");\n    }\n  `)))\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tassert.True(t,\n\t\ttestutils.LogContains(ts.LoggerHook.Drain(), logrus.WarnLevel, \"SSLKEYLOGFILE was specified\"))\n\tsslloglines, err := fsext.ReadFile(ts.FS, filepath.Join(ts.Cwd, \"ssl.log\"))\n\trequire.NoError(t, err)\n\t// TODO maybe have multiple depending on the ciphers used as that seems to change it\n\tassert.Regexp(t, \"^CLIENT_[A-Z_]+ [0-9a-f]+ [0-9a-f]+\\n\", string(sslloglines))\n}\n\nfunc TestThresholdDeprecationWarnings(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--system-tags\", \"url,error,vu,iter,scenario\", \"-\"}\n\tts.Stdin = bytes.NewReader([]byte(`\n\t\texport const options = {\n\t\t\tthresholds: {\n\t\t\t\t'http_req_duration{url:https://test.k6.io}': ['p(95)<500', 'p(99)<1000'],\n\t\t\t\t'http_req_duration{error:foo}': ['p(99)<1000'],\n\t\t\t\t'iterations{scenario:default}': ['count == 1'],\n\t\t\t\t'iterations{vu:1,iter:0}': ['count == 0'], // iter and vu are now unindexable\n\t\t\t},\n\t\t};\n\n\t\texport default function () { }`,\n\t))\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tlogs := ts.LoggerHook.Drain()\n\n\t// We no longer warn about this\n\tassert.False(t, testutils.LogContains(logs, logrus.WarnLevel, \"http_req_duration{url:https://test.k6.io}\"))\n\tassert.False(t, testutils.LogContains(logs, logrus.WarnLevel, \"http_req_duration{error:foo}\"))\n\tassert.True(t, testutils.LogContains(logs, logrus.WarnLevel,\n\t\t\"The high-cardinality 'vu' metric tag was made non-indexable in k6 v0.41.0, so thresholds like 'iterations{vu:1,iter:0}'\",\n\t))\n\tassert.True(t, testutils.LogContains(logs, logrus.WarnLevel,\n\t\t\"The high-cardinality 'iter' metric tag was made non-indexable in k6 v0.41.0, so thresholds like 'iterations{vu:1,iter:0}'\",\n\t))\n}\n\n// TODO: add a hell of a lot more integration tests, including some that spin up\n// a test HTTP server and actually check if k6 hits it\n\n// TODO: also add a test that starts multiple k6 \"instances\", for example:\n//  - one with `k6 run --paused` and another with `k6 resume`\n//  - one with `k6 run` and another with `k6 stats` or `k6 status`\n\nfunc TestExecutionTestOptionsDefaultValues(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n\n\t\texport default function () {\n\t\t\tconsole.log(JSON.stringify(exec.test.options))\n\t\t}\n\t`\n\n\tts := getSingleFileTestState(t, script, []string{\"--iterations\", \"1\"}, 0)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tloglines := ts.LoggerHook.Drain()\n\trequire.Len(t, loglines, 1)\n\n\texpected := `{\"paused\":null,\"executionSegment\":null,\"executionSegmentSequence\":null,\"noSetup\":null,\"setupTimeout\":null,\"noTeardown\":null,\"teardownTimeout\":null,\"rps\":null,\"dns\":{\"ttl\":null,\"select\":null,\"policy\":null},\"maxRedirects\":null,\"userAgent\":null,\"batch\":null,\"batchPerHost\":null,\"httpDebug\":null,\"insecureSkipTLSVerify\":null,\"tlsCipherSuites\":null,\"tlsVersion\":null,\"tlsAuth\":null,\"throw\":null,\"thresholds\":null,\"blacklistIPs\":null,\"blockHostnames\":null,\"hosts\":null,\"noConnectionReuse\":null,\"noVUConnectionReuse\":null,\"minIterationDuration\":null,\"ext\":null,\"summaryTrendStats\":[\"avg\", \"min\", \"med\", \"max\", \"p(90)\", \"p(95)\"],\"summaryTimeUnit\":null,\"systemTags\":[\"check\",\"error\",\"error_code\",\"expected_response\",\"group\",\"method\",\"name\",\"proto\",\"scenario\",\"service\",\"status\",\"subproto\",\"tls_version\",\"url\"],\"tags\":null,\"metricSamplesBufferSize\":null,\"noCookiesReset\":null,\"discardResponseBodies\":null,\"consoleOutput\":null,\"scenarios\":{\"default\":{\"vus\":null,\"iterations\":1,\"executor\":\"shared-iterations\",\"maxDuration\":null,\"startTime\":null,\"env\":null,\"tags\":null,\"gracefulStop\":null,\"exec\":null}},\"localIPs\":null}`\n\tassert.JSONEq(t, expected, loglines[0].Message)\n}\n\nfunc TestSubMetricThresholdNoData(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport { Counter } from 'k6/metrics';\n\n\t\tconst counter1 = new Counter(\"one\");\n\t\tconst counter2 = new Counter(\"two\");\n\n\t\texport const options = {\n\t\t\tthresholds: {\n\t\t\t\t'one{tag:xyz}': [],\n\t\t\t},\n\t\t};\n\n\t\texport default function () {\n\t\t\tcounter2.add(42);\n\t\t}\n\t`\n\tts := getSingleFileTestState(t, script, []string{\"--quiet\"}, 0)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tassert.Len(t, ts.LoggerHook.Drain(), 0)\n\tassert.Contains(t, ts.Stdout.String(), `\n    one..................: 0   0/s\n      { tag:xyz }........: 0   0/s\n    two..................: 42`)\n}\n\nfunc getTestServer(tb testing.TB, routes map[string]http.Handler) *httptest.Server {\n\tmux := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\tfor methodAndRoute, handler := range routes {\n\t\t\tmethod, route, _ := strings.Cut(methodAndRoute, \" \")\n\t\t\trouteRegexp, err := regexp.Compile(route)\n\t\t\trequire.NoError(tb, err)\n\n\t\t\tif req.Method == method && routeRegexp.Match([]byte(req.URL.String())) {\n\t\t\t\thandler.ServeHTTP(resp, req)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// By default, respond with 200 OK to all unmatched requests\n\t\tresp.WriteHeader(http.StatusOK)\n\t})\n\treturn httptest.NewServer(mux)\n}\n\nfunc getCloudTestEndChecker(\n\ttb testing.TB, testRunID int,\n\ttestStart http.Handler, expRunStatus cloudapi.RunStatus, expResultStatus cloudapi.ResultStatus,\n) *httptest.Server {\n\ttestFinished := false\n\n\tif testStart == nil {\n\t\ttestStart = cloudTestStartSimple(tb, testRunID)\n\t}\n\n\tsrv := getTestServer(tb, map[string]http.Handler{\n\t\t\"POST ^/v1/tests$\": testStart,\n\t\tfmt.Sprintf(\"POST ^/v1/tests/%d$\", testRunID): http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {\n\t\t\trequire.NotNil(tb, req.Body)\n\t\t\tbuf := &bytes.Buffer{}\n\t\t\t_, err := io.Copy(buf, req.Body)\n\t\t\trequire.NoError(tb, err)\n\t\t\trequire.NoError(tb, req.Body.Close())\n\n\t\t\tbody := buf.Bytes()\n\t\t\trequire.True(tb, gjson.ValidBytes(body))\n\n\t\t\trunStatus := gjson.GetBytes(body, \"run_status\")\n\t\t\trequire.True(tb, runStatus.Exists()) // important to check, since run_status can be 0\n\t\t\tassert.Equalf(\n\t\t\t\ttb, expRunStatus, cloudapi.RunStatus(runStatus.Int()),\n\t\t\t\t\"received wrong run_status value\",\n\t\t\t)\n\n\t\t\tresultStatus := gjson.GetBytes(body, \"result_status\")\n\t\t\trequire.True(tb, resultStatus.Exists())\n\t\t\tassert.Equalf(\n\t\t\t\ttb, expResultStatus, cloudapi.ResultStatus(resultStatus.Int()),\n\t\t\t\t\"received wrong result_status value\",\n\t\t\t)\n\t\t\ttestFinished = true\n\t\t}),\n\t})\n\n\ttb.Cleanup(func() {\n\t\tassert.Truef(tb, testFinished, \"expected test to have called the cloud API endpoint to finish the test\")\n\t\tsrv.Close()\n\t})\n\n\treturn srv\n}\n\nfunc getSimpleCloudOutputTestState(\n\ttb testing.TB, script string, cliFlags []string,\n\texpRunStatus cloudapi.RunStatus, expResultStatus cloudapi.ResultStatus, expExitCode exitcodes.ExitCode,\n) *GlobalTestState {\n\tif cliFlags == nil {\n\t\tcliFlags = []string{\"-v\", \"--log-output=stdout\"}\n\t}\n\tcliFlags = append(cliFlags, \"--out\", \"cloud\")\n\n\tsrv := getCloudTestEndChecker(tb, 111, nil, expRunStatus, expResultStatus)\n\tts := getSingleFileTestState(tb, script, cliFlags, expExitCode)\n\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\treturn ts\n}\n\nfunc TestSetupTeardownThresholds(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tscript := tb.Replacer.Replace(`\n\t\timport http from \"k6/http\";\n\t\timport { check } from \"k6\";\n\t\timport { Counter } from \"k6/metrics\";\n\n\t\tlet statusCheck = { \"status is 200\": (r) => r.status === 200 }\n\t\tlet myCounter = new Counter(\"setup_teardown\");\n\n\t\texport let options = {\n\t\t\titerations: 5,\n\t\t\tthresholds: {\n\t\t\t\t\"setup_teardown\": [\"count == 3\"],\n\t\t\t\t\"iterations\": [\"count == 5\"],\n\t\t\t\t\"http_reqs\": [\"count == 8\"],\n\t\t\t\t\"checks\": [\"rate == 1\"]\n\t\t\t},\n\t\t};\n\n\t\texport function setup() {\n\t\t\tcheck(http.get(\"HTTPBIN_IP_URL\"), statusCheck) && myCounter.add(1);\n\t\t};\n\n\t\texport default function () {\n\t\t\tcheck(http.get(\"HTTPBIN_IP_URL\"), statusCheck);\n\t\t};\n\n\t\texport function teardown() {\n\t\t\tcheck(http.get(\"HTTPBIN_IP_URL\"), statusCheck) && myCounter.add(1);\n\t\t};\n\t`)\n\n\tcliFlags := []string{\"-v\", \"--log-output=stdout\", \"--linger\"}\n\tts := getSimpleCloudOutputTestState(t, script, cliFlags, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed, 0)\n\n\tsendSignal := injectMockSignalNotifier(ts)\n\tasyncWaitForStdoutAndRun(t, ts, 20, 500*time.Millisecond, \"waiting for Ctrl+C to continue\", func() {\n\t\tdefer func() {\n\t\t\tsendSignal <- syscall.SIGINT\n\t\t\t<-sendSignal\n\t\t}()\n\t\tt.Logf(\"Linger reached, running teardown again and stopping the test...\")\n\t\treq, err := http.NewRequestWithContext(\n\t\t\tts.Ctx, http.MethodPost, fmt.Sprintf(\"http://%s/v1/teardown\", ts.Flags.Address), nil,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tresp, err := http.DefaultClient.Do(req)\n\t\trequire.NoError(t, err)\n\t\tbody, err := io.ReadAll(resp.Body)\n\t\tassert.NoError(t, err)\n\t\tt.Logf(\"Response body: %s\", body)\n\t\tassert.NoError(t, resp.Body.Close())\n\t\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n\t})\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdOut := ts.Stdout.String()\n\tt.Log(stdOut)\n\tassert.Contains(t, stdOut, \"checks\\n    ✓ 'rate == 1' rate=100.00%\")\n\tassert.Contains(t, stdOut, \"http_reqs\\n    ✓ 'count == 8' count=8\")\n\tassert.Contains(t, stdOut, \"iterations\\n    ✓ 'count == 5' count=5\")\n\tassert.Contains(t, stdOut, \"setup_teardown\\n    ✓ 'count == 3' count=3\")\n\n\tlogMsgs := ts.LoggerHook.Drain()\n\tfor _, msg := range logMsgs {\n\t\tif msg.Level != logrus.DebugLevel {\n\t\t\tassert.Failf(t, \"unexpected log message\", \"level %s, msg '%s'\", msg.Level, msg.Message)\n\t\t}\n\t}\n\tassert.True(t, testutils.LogContains(logMsgs, logrus.DebugLevel, \"Running thresholds on 4 metrics...\"))\n\tassert.True(t, testutils.LogContains(logMsgs, logrus.DebugLevel, \"Finalizing thresholds...\"))\n\tassert.True(t, testutils.LogContains(logMsgs, logrus.DebugLevel, \"Metrics emission of VUs and VUsMax metrics stopped\"))\n\tassert.True(t, testutils.LogContains(logMsgs, logrus.DebugLevel, \"Metrics and traces processing finished!\"))\n}\n\nfunc TestThresholdsFailed(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\texport let options = {\n\t\t\tscenarios: {\n\t\t\t\tsc1: {\n\t\t\t\t\texecutor: 'per-vu-iterations',\n\t\t\t\t\tvus: 1, iterations: 1,\n\t\t\t\t},\n\t\t\t\tsc2: {\n\t\t\t\t\texecutor: 'shared-iterations',\n\t\t\t\t\tvus: 1, iterations: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\tthresholds: {\n\t\t\t\t'iterations': ['count == 3'],\n\t\t\t\t'iterations{scenario:sc1}': ['count == 2'],\n\t\t\t\t'iterations{scenario:sc2}': ['count == 1'],\n\t\t\t\t'iterations{scenario:sc3}': ['count == 0'],\n\t\t\t},\n\t\t};\n\n\t\texport default function () {};\n\t`\n\n\t// Since these thresholds don't have an abortOnFail property, the run_status\n\t// in the cloud will still be Finished, even if the test itself failed.\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, nil, cloudapi.RunStatusFinished, cloudapi.ResultStatusFailed, exitcodes.ThresholdsHaveFailed,\n\t)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\texpErr := \"thresholds on metrics 'iterations{scenario:sc1}, iterations{scenario:sc2}' have been crossed\"\n\tassert.True(t, testutils.LogContains(ts.LoggerHook.Drain(), logrus.ErrorLevel, expErr))\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"    iterations\\n    ✓ 'count == 3' count=3\")\n\tassert.Contains(t, stdout, \"      {scenario:sc1}\\n      ✗ 'count == 2' count=1\")\n\tassert.Contains(t, stdout, \"      ✗ 'count == 2' count=1\")\n\tassert.Contains(t, stdout, \"      {scenario:sc2}\\n      ✗ 'count == 1' count=2\")\n}\n\nfunc TestAbortedByThreshold(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\texport const options = {\n\t\t\tscenarios: {\n\t\t\t\tsc1: {\n\t\t\t\t\texecutor: 'constant-arrival-rate',\n\t\t\t\t\tduration: '30s',\n\t\t\t\t\trate: 1,\n\t\t\t\t\tpreAllocatedVUs: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\tthresholds: {\n\t\t\t\t'iterations': [{\n\t\t\t\t\tthreshold: 'count == 1',\n\t\t\t\t\tabortOnFail: true,\n\t\t\t\t}],\n\t\t\t},\n\t\t};\n\n\t\texport default function () {};\n\n\t\texport function teardown() {\n\t\t\tconsole.log('teardown() called');\n\t\t}\n\t`\n\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, nil, cloudapi.RunStatusAbortedThreshold, cloudapi.ResultStatusFailed, exitcodes.ThresholdsHaveFailed,\n\t)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\texpErr := \"thresholds on metrics 'iterations' were crossed; at least one has abortOnFail enabled, stopping test prematurely\"\n\tassert.True(t, testutils.LogContains(ts.LoggerHook.Drain(), logrus.ErrorLevel, expErr))\n\tstdOut := ts.Stdout.String()\n\tt.Log(stdOut)\n\tassert.Contains(t, stdOut, \"iterations\\n    ✗ 'count == 1'\")\n\tassert.Contains(t, stdOut, `teardown() called`)\n\tassert.Contains(t, stdOut, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdOut, `level=debug msg=\"Metrics and traces processing finished!\"`)\n\tassert.Contains(t, stdOut, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=8 tainted=true`)\n}\n\nfunc TestAbortedByUserWithGoodThresholds(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport { Counter } from 'k6/metrics';\n\t\timport exec from 'k6/execution';\n\n\t\texport const options = {\n\t\t\tscenarios: {\n\t\t\t\tsc1: {\n\t\t\t\t\texecutor: 'constant-arrival-rate',\n\t\t\t\t\tduration: '30s',\n\t\t\t\t\trate: 1,\n\t\t\t\t\tpreAllocatedVUs: 2,\n\t\t\t\t},\n\t\t\t},\n\t\t\tthresholds: {\n\t\t\t\t'iterations': ['count >= 1'],\n\t\t\t\t'tc': ['count == 1'],\n\t\t\t\t'tc{group:::setup}': ['count == 0'],\n\t\t\t\t'tc{group:::teardown}': ['count == 1'],\n\t\t\t},\n\t\t};\n\n\t\tlet tc = new Counter('tc');\n\t\texport function teardown() {\n\t\t\ttc.add(1);\n\t\t}\n\n\t\texport default function () {\n\t\t\tconsole.log('simple iter ' + exec.scenario.iterationInTest);\n\t\t};\n\t`\n\n\tts := getSimpleCloudOutputTestState(t, script, nil, cloudapi.RunStatusAbortedUser, cloudapi.ResultStatusPassed, exitcodes.ExternalAbort)\n\n\tasyncWaitForStdoutAndStopTestWithInterruptSignal(t, ts, 30, 300*time.Millisecond, \"simple iter 2\")\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tlogs := ts.LoggerHook.Drain()\n\tassert.False(t, testutils.LogContains(logs, logrus.ErrorLevel, `thresholds on metrics`))\n\tassert.True(t, testutils.LogContains(logs, logrus.ErrorLevel, `test run was aborted because k6 received a 'interrupt' signal`))\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, `\n    iterations\n    ✓ 'count >= 1' count=3\n\n    tc\n    ✓ 'count == 1' count=1\n\n      {group:::setup}\n      ✓ 'count == 0' count=0\n\n      {group:::teardown}\n      ✓ 'count == 1' count=1`)\n\tassert.Contains(t, stdout, `Stopping k6 in response to signal`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics and traces processing finished!\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=5 tainted=false`)\n}\n\nfunc asyncWaitForStdoutAndRun(\n\tt *testing.T, ts *GlobalTestState, attempts int, interval time.Duration, expText string, callback func(),\n) {\n\twg := &sync.WaitGroup{}\n\twg.Go(func() {\n\t\treachedCondition := false\n\t\tfor i := range attempts {\n\t\t\tts.OutMutex.Lock()\n\t\t\tstdOut := ts.Stdout.String()\n\t\t\tts.OutMutex.Unlock()\n\n\t\t\tif strings.Contains(stdOut, expText) {\n\t\t\t\tt.Logf(\"found '%s' in the process stdout on try %d at t=%s\", expText, i, time.Now())\n\t\t\t\treachedCondition = true\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tt.Logf(\"did not find the text '%s' in the process stdout on try %d at t=%s\", expText, i, time.Now())\n\t\t\ttime.Sleep(interval)\n\t\t}\n\t\tif reachedCondition {\n\t\t\tcallback()\n\t\t\treturn // everything is fine\n\t\t}\n\n\t\tts.OutMutex.Lock()\n\t\tstdOut := ts.Stdout.String()\n\t\tts.OutMutex.Unlock()\n\t\tt.Log(stdOut)\n\t\trequire.FailNow(\n\t\t\tt, \"expected output not found\", \"did not find the text '%s' in the process stdout after %d attempts (%s)\",\n\t\t\texpText, attempts, time.Duration(attempts)*interval,\n\t\t)\n\t})\n\n\tt.Cleanup(wg.Wait) // ensure the test waits for the goroutine to finish\n}\n\nfunc injectMockSignalNotifier(ts *GlobalTestState) (sendSignal chan os.Signal) {\n\tsendSignal = make(chan os.Signal)\n\tts.SignalNotify = func(c chan<- os.Signal, signals ...os.Signal) {\n\t\tisAbortNotify := slices.Contains(signals, os.Interrupt)\n\t\tif !isAbortNotify {\n\t\t\treturn\n\t\t}\n\t\tgo func() {\n\t\t\tsig := <-sendSignal\n\t\t\tc <- sig\n\t\t\tclose(sendSignal)\n\t\t}()\n\t}\n\tts.SignalStop = func(_ chan<- os.Signal) { /* noop */ }\n\treturn sendSignal\n}\n\nfunc asyncWaitForStdoutAndStopTestWithInterruptSignal(\n\tt *testing.T, ts *GlobalTestState, attempts int, interval time.Duration, expText string,\n) {\n\tsendSignal := injectMockSignalNotifier(ts)\n\tasyncWaitForStdoutAndRun(t, ts, attempts, interval, expText, func() {\n\t\tt.Log(\"expected stdout text was found, sending interrupt signal...\")\n\t\tsendSignal <- syscall.SIGINT\n\t\t<-sendSignal\n\t})\n}\n\nfunc asyncWaitForStdoutAndStopTestFromRESTAPI(\n\tt *testing.T, ts *GlobalTestState, attempts int, interval time.Duration, expText string,\n) {\n\tasyncWaitForStdoutAndRun(t, ts, attempts, interval, expText, func() {\n\t\treq, err := http.NewRequestWithContext(\n\t\t\tts.Ctx, http.MethodPatch, fmt.Sprintf(\"http://%s/v1/status\", ts.Flags.Address),\n\t\t\tbytes.NewBufferString(`{\"data\":{\"type\":\"status\",\"id\":\"default\",\"attributes\":{\"stopped\":true}}}`),\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tresp, err := http.DefaultClient.Do(req)\n\t\trequire.NoError(t, err)\n\t\tbody, err := io.ReadAll(resp.Body)\n\t\tassert.NoError(t, err)\n\t\tt.Logf(\"Response body: %s\", body)\n\t\tassert.NoError(t, resp.Body.Close())\n\t\tassert.Equal(t, http.StatusOK, resp.StatusCode)\n\t})\n}\n\n// TODO: add more abort scenario tests, see\n// https://github.com/grafana/k6/issues/2804\n\nfunc TestAbortedByUserWithRestAPI(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport { sleep } from 'k6';\n\t\texport default function () {\n\t\t\tconsole.log('a simple iteration')\n\t\t\tsleep(1);\n\t\t};\n\n\t\texport function teardown() {\n\t\t\tconsole.log('teardown() called');\n\t\t}\n\t`\n\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, []string{\"-v\", \"--log-output=stdout\", \"--iterations\", \"20\"},\n\t\tcloudapi.RunStatusAbortedUser, cloudapi.ResultStatusPassed, exitcodes.ScriptStoppedFromRESTAPI,\n\t)\n\n\tasyncWaitForStdoutAndStopTestFromRESTAPI(t, ts, 15, time.Second, \"a simple iteration\")\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, `a simple iteration`)\n\tassert.Contains(t, stdout, `teardown() called`)\n\tassert.Contains(t, stdout, `PATCH /v1/status`)\n\tassert.Contains(t, stdout, `level=error msg=\"test run stopped from REST API`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics and traces processing finished!\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=5 tainted=false`)\n\tassert.NotContains(t, stdout, `Running thresholds`)\n\tassert.NotContains(t, stdout, `Finalizing thresholds`)\n}\n\nfunc TestAbortedByScriptSetupErrorWithDependency(t *testing.T) {\n\tt.Parallel()\n\tdepScript := `\n\t\texport default function () {\n\t\t\tbaz();\n\t\t}\n\t\tfunction baz() {\n\t\t\tthrow new Error(\"baz\");\n\t\t}\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\tmainScript := `\n\t\timport bar from \"./bar.js\";\n\t\texport function setup() {\n\t\t\tconsole.log('wonky setup');\n\t\t\tbar();\n\t\t};\n\t\texport default function() {};\n\n\t\texport { handleSummary } from \"./bar.js\";\n\t`\n\n\tsrv := getCloudTestEndChecker(t, 123, nil, cloudapi.RunStatusAbortedScriptError, cloudapi.ResultStatusPassed)\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.js\"), []byte(mainScript), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"bar.js\"), []byte(depScript), 0o644))\n\n\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-v\", \"--out\", \"cloud\", \"--log-output=stdout\", \"test.js\"}\n\tts.ExpectedExitCode = int(exitcodes.ScriptException)\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, `wonky setup`)\n\n\trootPath := \"file:///\"\n\tif runtime.GOOS == \"windows\" {\n\t\trootPath += \"c:/\"\n\t}\n\tassert.Contains(t, stdout, `level=error msg=\"Error: baz\\n\\tat baz (`+rootPath+`test/bar.js:6:10(3))\\n\\tat default (`+\n\t\trootPath+`test/bar.js:3:7(3))\\n\\tat setup (`+rootPath+`test/test.js:5:7(8))\\n\" hint=\"script exception\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Sending test finished\" output=cloud ref=123 run_status=7 tainted=false`)\n\tassert.Contains(t, stdout, \"bogus summary\")\n}\n\nfunc TestAbortedByUnknownModules(t *testing.T) {\n\tt.Parallel()\n\tdepScript := `\n\t\timport { something } from \"k6/x/somethinghere\"\n\t\timport { another } from \"k6/x/anotherone\"\n\t`\n\tmainScript := `\n\t\timport { something } from \"k6/x/somethinghere\"\n\t\timport \"./a.js\"\n\t\texport default function () { }\n\t`\n\n\tts := NewGlobalTestState(t)\n\tts.Flags.AutoExtensionResolution = false\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.js\"), []byte(mainScript), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"a.js\"), []byte(depScript), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-v\", \"--log-output=stdout\", \"test.js\"}\n\tts.ExpectedExitCode = int(exitcodes.ScriptException)\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\n\tassert.Contains(t, stdout, `unknown modules [\\\"k6/x/anotherone\\\", \\\"k6/x/somethinghere\\\"] were tried to be loaded,`)\n}\n\nfunc TestRunFromNotBaseDirectory(t *testing.T) {\n\tt.Parallel()\n\tdepScript := `\n\t\texport const p = 5;\n\t`\n\tmainScript := `\n\t\timport { p } from \"../../../b/dep.js\";\n\t\texport default function() {\n\t\t\tconsole.log(\"p = \" + p);\n\t\t};\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"a/b/c/test.js\"), []byte(mainScript), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"b/dep.js\"), []byte(depScript), 0o644))\n\n\tts.Cwd = filepath.Join(ts.Cwd, \"./a/\")\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-v\", \"--log-output=stdout\", \"b/c/test.js\"}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\trequire.Contains(t, stdout, `p = 5`)\n}\n\nfunc TestRunCSVParseConcurrentFromMultipleModules(t *testing.T) {\n\tt.Parallel()\n\n\tcsvData := `col1,col2\na,b\nc,d\n`\n\tmodule1Script := `\n\t\timport csv from \"k6/experimental/csv\";\n\t\timport fs from \"k6/experimental/fs\";\n\n\t\tconst file = await fs.open(\"data.csv\");\n\t\texport const data = await csv.parse(file);\n\t`\n\tmodule2Script := `\n\t\timport csv from \"k6/experimental/csv\";\n\t\timport fs from \"k6/experimental/fs\";\n\n\t\tconst file = await fs.open(\"data.csv\");\n\t\texport const data = await csv.parse(file);\n\t`\n\tmodule3Script := `\n\t\timport csv from \"k6/experimental/csv\";\n\t\timport fs from \"k6/experimental/fs\";\n\n\t\tconst file = await fs.open(\"data.csv\");\n\t\texport const data = await csv.parse(file);\n\t`\n\t// Main: imports all 3 modules - each has await csv.parse at top level\n\tmainScript := `\n\t\timport { data as data1 } from \"./modules/module1.js\";\n\t\timport { data as data2 } from \"./modules/module2.js\";\n\t\timport { data as data3 } from \"./modules/module3.js\";\n\n\t\tif (data1.length !== 3 || data2.length !== 3 || data3.length !== 3) {\n\t\t\tthrow new Error(\"Expected 3 records from each parse\");\n\t\t}\n\n\t\tif (data1[0][0] !== \"col1\" || data2[0][0] !== \"col1\" || data3[0][0] !== \"col1\") {\n\t\t\tthrow new Error(\"Unexpected CSV data\");\n\t\t}\n\t\texport default function() { } // just to not error out\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"data.csv\"), []byte(csvData), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"modules/module1.js\"), []byte(module1Script), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"modules/module2.js\"), []byte(module2Script), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"modules/module3.js\"), []byte(module3Script), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"main.js\"), []byte(mainScript), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--vus\", \"1\", \"--iterations\", \"1\", \"main.js\"}\n\tts.ExpectedExitCode = 0\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n}\n\nfunc TestRunFromSeparateDriveWindows(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS != \"windows\" {\n\t\tt.Skip(\"test only for windows\")\n\t}\n\tdepScript := `\n\t\texport const p = 5;\n\t`\n\tmainScript := `\n\t\timport { p } from \"../../../b/dep.js\";\n\t\texport default function() {\n\t\t\tconsole.log(\"p = \" + p);\n\t\t};\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"a/b/c/test.js\"), []byte(mainScript), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"b/dep.js\"), []byte(depScript), 0o644))\n\n\tts.Cwd = \"f:\\\\something somewhere\\\\and another\\\\\"\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-v\", \"--log-output=stdout\", \"c:\\\\test\\\\a\\\\b\\\\c\\\\test.js\"}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\trequire.Contains(t, stdout, `p = 5`)\n}\n\nfunc runTestWithNoLinger(_ *testing.T, ts *GlobalTestState) {\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n}\n\nfunc runTestWithLinger(t *testing.T, ts *GlobalTestState) {\n\tts.CmdArgs = append(ts.CmdArgs, \"--linger\")\n\tasyncWaitForStdoutAndStopTestWithInterruptSignal(t, ts, 15, time.Second, \"waiting for Ctrl+C to continue\")\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n}\n\nfunc TestAbortedByScriptSetupError(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\texport function setup() {\n\t\t\tconsole.log('wonky setup');\n\t\t\tthrow new Error('foo');\n\t\t}\n\n\t\texport function teardown() {\n\t\t\tconsole.log('nice teardown');\n\t\t}\n\n\t\texport default function () {};\n\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\tdoChecks := func(t *testing.T, ts *GlobalTestState) {\n\t\tstdout := ts.Stdout.String()\n\t\tassert.Contains(t, stdout, \"Error: foo\")\n\t\tassert.Contains(t, stdout, \"wonky setup\")\n\t\tassert.NotContains(t, stdout, \"nice teardown\") // do not execute teardown if setup failed\n\t\tassert.Contains(t, stdout, \"bogus summary\")\n\t}\n\n\tt.Run(\"noLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := testAbortedByScriptError(t, script, runTestWithNoLinger)\n\t\tdoChecks(t, ts)\n\t})\n\n\tt.Run(\"withLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := testAbortedByScriptError(t, script, runTestWithLinger)\n\t\tdoChecks(t, ts)\n\t})\n}\n\nfunc TestAbortedByScriptTeardownError(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `\n\t\texport function setup() {\n\t\t\tconsole.log('nice setup');\n\t\t}\n\n\t\texport function teardown() {\n\t\t\tconsole.log('wonky teardown');\n\t\t\tthrow new Error('foo');\n\t\t}\n\n\t\texport default function () {};\n\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\tdoChecks := func(t *testing.T, ts *GlobalTestState) {\n\t\tstdout := ts.Stdout.String()\n\t\tassert.Contains(t, stdout, \"Error: foo\")\n\t\tassert.Contains(t, stdout, \"nice setup\")\n\t\tassert.Contains(t, stdout, \"wonky teardown\")\n\t\tassert.Contains(t, stdout, \"bogus summary\")\n\t}\n\n\tt.Run(\"noLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := testAbortedByScriptError(t, script, runTestWithNoLinger)\n\t\tdoChecks(t, ts)\n\t})\n\n\tt.Run(\"withLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := testAbortedByScriptError(t, script, runTestWithLinger)\n\t\tdoChecks(t, ts)\n\t})\n}\n\nfunc testAbortedByScriptError(t *testing.T, script string, runTest func(*testing.T, *GlobalTestState)) *GlobalTestState {\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, nil, cloudapi.RunStatusAbortedScriptError, cloudapi.ResultStatusPassed, exitcodes.ScriptException,\n\t)\n\trunTest(t, ts)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics and traces processing finished!\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Everything has finished, exiting k6 with an error!\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=7 tainted=false`)\n\treturn ts\n}\n\nfunc TestAbortedByTestAbortFirstInitCode(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n\t\texec.test.abort('foo');\n\t\texport default function () {};\n\n\t\t// Should not be called, since error is in the init context\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\tts := getSingleFileTestState(t, script, nil, exitcodes.ScriptAborted)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"test aborted: foo\")\n\tassert.NotContains(t, stdout, \"bogus summary\")\n}\n\nfunc TestAbortedByTestAbortInNonFirstInitCode(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n\n\t\texport const options = {vus: 3, duration: '5s'};\n\n\t\tif (__VU > 1) {\n\t\t\texec.test.abort('foo');\n\t\t}\n\n\t\texport default function () {};\n\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\ttestAbortedByScriptTestAbort(t, script, runTestWithNoLinger)\n}\n\nfunc TestAbortedByScriptAbortInVUCode(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n\t\texport default function () {\n\t\t\texec.test.abort('foo');\n\t\t};\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\tt.Run(\"noLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithNoLinger)\n\t})\n\n\tt.Run(\"withLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithLinger)\n\t})\n}\n\nfunc TestAbortedByScriptAbortInVUCodeInGroup(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n        import { group } from 'k6';\n\t\texport default function () {\n            group(\"here\", () => {\n                exec.test.abort('foo');\n            });\n\t\t};\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\tt.Run(\"noLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithNoLinger)\n\t})\n\n\tt.Run(\"withLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithLinger)\n\t})\n}\n\nfunc TestAbortedByScriptAbortInSetup(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n\t\texport function setup() {\n\t\t\texec.test.abort('foo');\n\t\t}\n\t\texport default function () {};\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\tt.Run(\"noLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithNoLinger)\n\t})\n\tt.Run(\"withLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithLinger)\n\t})\n}\n\nfunc TestAbortedByScriptAbortInTeardown(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n\t\texport function teardown() {\n\t\t\texec.test.abort('foo');\n\t\t}\n\t\texport default function () {};\n\t\texport function handleSummary() { return {stdout: '\\n\\n\\nbogus summary\\n\\n\\n'};}\n\t`\n\n\tt.Run(\"noLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithNoLinger)\n\t})\n\n\tt.Run(\"withLinger\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestAbortedByScriptTestAbort(t, script, runTestWithLinger)\n\t})\n}\n\nfunc testAbortedByScriptTestAbort(t *testing.T, script string, runTest func(*testing.T, *GlobalTestState)) {\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, nil, cloudapi.RunStatusAbortedUser, cloudapi.ResultStatusPassed, exitcodes.ScriptAborted,\n\t)\n\trunTest(t, ts)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"execution: local\")\n\tassert.Contains(t, stdout, \"output: cloud (https://app.k6.io/runs/111)\")\n\tassert.Contains(t, stdout, \"test aborted: foo\")\n\tassert.Contains(t, stdout, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=5 tainted=false`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics and traces processing finished!\"`)\n\tassert.Contains(t, stdout, \"bogus summary\")\n}\n\nfunc TestAbortedByInterruptDuringVUInit(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport { sleep } from 'k6';\n\t\texport const options = {\n\t\t\tvus: 5,\n\t\t\tduration: '10s',\n\t\t};\n\n\t\tif (__VU > 1) {\n\t\t\tconsole.log('VU init sleeping for a while');\n\t\t\tsleep(100);\n\t\t}\n\n\t\texport default function () {};\n\t`\n\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, nil, cloudapi.RunStatusAbortedUser, cloudapi.ResultStatusPassed, exitcodes.ExternalAbort,\n\t)\n\tasyncWaitForStdoutAndStopTestWithInterruptSignal(t, ts, 15, time.Second, \"VU init sleeping for a while\")\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdOut := ts.Stdout.String()\n\tt.Log(stdOut)\n\n\tassert.Contains(t, stdOut, `level=debug msg=\"Stopping k6 in response to signal...\" sig=interrupt`)\n\tassert.Contains(t, stdOut, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdOut, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=5 tainted=false`)\n\tassert.Contains(t, stdOut, `level=error msg=\"test run was aborted because k6 received a 'interrupt' signal\"`)\n}\n\nfunc TestAbortedByInterruptWhenPaused(t *testing.T) {\n\tt.Parallel()\n\tscript := `export default function () {};`\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, []string{\"-v\", \"--log-output=stdout\", \"--paused\"},\n\t\tcloudapi.RunStatusAbortedUser, cloudapi.ResultStatusPassed, exitcodes.ExternalAbort,\n\t)\n\tasyncWaitForStdoutAndStopTestWithInterruptSignal(\n\t\tt, ts, 10, time.Second, \"Execution is paused, waiting for resume or interrupt...\",\n\t)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdOut := ts.Stdout.String()\n\tt.Log(stdOut)\n\n\tassert.Contains(t, stdOut, `level=debug msg=\"Stopping k6 in response to signal...\" sig=interrupt`)\n\tassert.Contains(t, stdOut, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdOut, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=5 tainted=false`)\n\tassert.Contains(t, stdOut, `level=error msg=\"test run was aborted because k6 received a 'interrupt' signal\"`)\n}\n\nfunc TestAbortedByScriptInitError(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\texport const options = {\n\t\t\tvus: 5,\n\t\t\titerations: 10,\n\t\t};\n\n\t\tif (__VU == 2) {\n\t\t\tthrow new Error('oops in ' + __VU);\n\t\t}\n\n\t\texport default function () {};\n\t`\n\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, nil, cloudapi.RunStatusAbortedScriptError, cloudapi.ResultStatusPassed, exitcodes.ScriptException,\n\t)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"execution: local\")\n\tassert.Contains(t, stdout, \"output: cloud (https://app.k6.io/runs/111)\")\n\tassert.Contains(t, stdout, `level=error msg=\"Error: oops in 2\\n\\tat file:///`)\n\tassert.Contains(t, stdout, `hint=\"error while initializing VU #2 (script exception)\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Metrics emission of VUs and VUsMax metrics stopped\"`)\n\tassert.Contains(t, stdout, `level=debug msg=\"Sending test finished\" output=cloud ref=111 run_status=7 tainted=false`)\n}\n\nfunc TestMetricTagAndSetupDataIsolation(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport exec from 'k6/execution';\n\t\timport { Counter } from 'k6/metrics';\n\t\timport { sleep } from 'k6';\n\n\t\texport const options = {\n\t\t\tscenarios: {\n\t\t\t\tsc1: {\n\t\t\t\t\texecutor: 'shared-iterations',\n\t\t\t\t\tvus: 2,\n\t\t\t\t\titerations: 20,\n\t\t\t\t\tmaxDuration: '7s',\n\t\t\t\t\tgracefulStop: 0,\n\t\t\t\t\texec: 'sc1',\n\t\t\t\t},\n\t\t\t\tsc2: {\n\t\t\t\t\texecutor: 'per-vu-iterations',\n\t\t\t\t\tvus: 1,\n\t\t\t\t\titerations: 1,\n\t\t\t\t\tstartTime: '7s',\n\t\t\t\t\texec: 'sc2',\n\t\t\t\t},\n\t\t\t},\n\t\t\tthresholds: {\n\t\t\t\t'iterations': ['count == 21'],\n\t\t\t\t'iterations{scenario:sc1}': ['count == 20'],\n\t\t\t\t'iterations{sc:1}': ['count == 20'],\n\t\t\t\t'iterations{scenario:sc2}': ['count == 1'],\n\t\t\t\t'mycounter': ['count == 23'],\n\t\t\t\t'mycounter{sc:1}': ['count == 20'],\n\t\t\t\t'mycounter{setup:true}': ['count == 1'],\n\t\t\t\t'mycounter{myiter:1}': ['count >= 1', 'count <= 2'],\n\t\t\t\t'mycounter{myiter:2}': ['count >= 1', 'count <= 2'],\n\t\t\t\t'mycounter{scenario:sc2}': ['count == 1'],\n\t\t\t\t'mycounter{scenario:sc2,sc:1}': ['count == 0'],\n\t\t\t\t'vus_max': ['value == 2'],\n\t\t\t},\n\t\t};\n\t\tlet myCounter = new Counter('mycounter');\n\n\t\texport function setup() {\n\t\t\texec.vu.tags.setup = 'true';\n\t\t\tmyCounter.add(1);\n\t\t\treturn { v: 0 };\n\t\t}\n\n\t\texport function sc1(data) {\n\t\t\tif (data.v !== __ITER) {\n\t\t\t\tthrow new Error('sc1: wrong data for iter ' + __ITER + ': ' + JSON.stringify(data));\n\t\t\t}\n\t\t\tif (__ITER != 0 && data.v != exec.vu.tags.myiter) {\n\t\t\t\tthrow new Error('sc1: wrong vu tags for iter ' + __ITER + ': ' + JSON.stringify(exec.vu.tags));\n\t\t\t}\n\t\t\tdata.v += 1;\n\t\t\texec.vu.tags.myiter = data.v;\n\t\t\texec.vu.tags.sc = 1;\n\t\t\tmyCounter.add(1);\n\t\t\tsleep(0.02); // encourage using both of the VUs\n\t\t}\n\n\t\texport function sc2(data) {\n\t\t\tif (data.v === 0) {\n\t\t\t\tthrow new Error('sc2: wrong data, expected VU to have modified setup data locally: ' + data.v);\n\t\t\t}\n\n\t\t\tif (typeof exec.vu.tags.myiter !== 'undefined') {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'sc2: wrong tags, expected VU to have new tags in new scenario: ' + JSON.stringify(exec.vu.tags),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tmyCounter.add(1);\n\t\t}\n\n\t\texport function teardown(data) {\n\t\t\tif (data.v !== 0) {\n\t\t\t\tthrow new Error('teardown: wrong data: ' + data.v);\n\t\t\t}\n\t\t\tmyCounter.add(1);\n\t\t}\n\t`\n\n\tts := getSimpleCloudOutputTestState(\n\t\tt, script, []string{\"--quiet\", \"--log-output\", \"stdout\"},\n\t\tcloudapi.RunStatusFinished, cloudapi.ResultStatusPassed, 0,\n\t)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.NotContains(t, stdout, \"execution: local\") // because of --quiet\n\tassert.NotContains(t, stdout, \"output: cloud\")    // because of --quiet\n\tassert.Equal(t, 14, strings.Count(stdout, \"✓\"))\n}\n\nfunc getSampleValues(t *testing.T, jsonOutput []byte, metric string, tags map[string]string) []float64 {\n\tjsonLines := bytes.Split(jsonOutput, []byte(\"\\n\"))\n\tresult := []float64{}\n\n\ttagsMatch := func(rawTags any) bool {\n\t\tsampleTags, ok := rawTags.(map[string]any)\n\t\trequire.True(t, ok)\n\t\tfor k, v := range tags {\n\t\t\trv, sok := sampleTags[k]\n\t\t\tif !sok {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\trvs, sok := rv.(string)\n\t\t\trequire.True(t, sok)\n\t\t\tif v != rvs {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\n\tfor _, jsonLine := range jsonLines {\n\t\tif len(jsonLine) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tvar line map[string]any\n\t\trequire.NoError(t, json.Unmarshal(jsonLine, &line))\n\t\tsampleType, ok := line[\"type\"].(string)\n\t\trequire.True(t, ok)\n\t\tif sampleType != \"Point\" {\n\t\t\tcontinue\n\t\t}\n\t\tsampleMetric, ok := line[\"metric\"].(string)\n\t\trequire.True(t, ok)\n\t\tif sampleMetric != metric {\n\t\t\tcontinue\n\t\t}\n\t\tsampleData, ok := line[\"data\"].(map[string]any)\n\t\trequire.True(t, ok)\n\n\t\tif !tagsMatch(sampleData[\"tags\"]) {\n\t\t\tcontinue\n\t\t}\n\n\t\tsamplValue, ok := sampleData[\"value\"].(float64)\n\t\trequire.True(t, ok)\n\t\tresult = append(result, samplValue)\n\t}\n\n\treturn result\n}\n\nfunc sum(vals []float64) (sum float64) {\n\tfor _, val := range vals {\n\t\tsum += val\n\t}\n\treturn sum\n}\n\nfunc TestActiveVUsCount(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `\n\t\tvar sleep = require('k6').sleep;\n\n\t\texports.options = {\n\t\t\tscenarios: {\n\t\t\t\tcarr1: {\n\t\t\t\t\texecutor: 'constant-arrival-rate',\n\t\t\t\t\trate: 10,\n\t\t\t\t\tpreAllocatedVUs: 1,\n\t\t\t\t\tmaxVUs: 10,\n\t\t\t\t\tstartTime: '0s',\n\t\t\t\t\tduration: '3s',\n\t\t\t\t\tgracefulStop: '0s',\n\t\t\t\t},\n\t\t\t\tcarr2: {\n\t\t\t\t\texecutor: 'constant-arrival-rate',\n\t\t\t\t\trate: 10,\n\t\t\t\t\tpreAllocatedVUs: 1,\n\t\t\t\t\tmaxVUs: 10,\n\t\t\t\t\tduration: '3s',\n\t\t\t\t\tstartTime: '3s',\n\t\t\t\t\tgracefulStop: '0s',\n\t\t\t\t},\n\t\t\t\trarr: {\n\t\t\t\t\texecutor: 'ramping-arrival-rate',\n\t\t\t\t\tstartRate: 5,\n\t\t\t\t\tstages: [\n\t\t\t\t\t\t{ target: 10, duration: '2s' },\n\t\t\t\t\t\t{ target: 0, duration: '2s' },\n\t\t\t\t\t],\n\t\t\t\t\tpreAllocatedVUs: 1,\n\t\t\t\t\tmaxVUs: 10,\n\t\t\t\t\tstartTime: '6s',\n\t\t\t\t\tgracefulStop: '0s',\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\n\t\texports.default = function () {\n\t\t\tsleep(5);\n\t\t}\n\t`\n\n\tts := getSingleFileTestState(t, script, []string{\"--compatibility-mode\", \"base\", \"--out\", \"json=results.json\"}, 0)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\n\tjsonResults, err := fsext.ReadFile(ts.FS, \"results.json\")\n\trequire.NoError(t, err)\n\t// t.Log(string(jsonResults))\n\tassert.Equal(t, float64(10), slices.Max(getSampleValues(t, jsonResults, \"vus_max\", nil)))\n\tassert.Equal(t, float64(10), slices.Max(getSampleValues(t, jsonResults, \"vus\", nil)))\n\tassert.Equal(t, float64(0), sum(getSampleValues(t, jsonResults, \"iterations\", nil)))\n\n\tlogEntries := ts.LoggerHook.Drain()\n\tassert.Len(t, logEntries, 4)\n\tfor i, logEntry := range logEntries {\n\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\tif i < 3 {\n\t\t\tassert.Equal(t, \"Insufficient VUs, reached 10 active VUs and cannot initialize more\", logEntry.Message)\n\t\t} else {\n\t\t\tassert.Equal(t, \"No script iterations fully finished, consider making the test duration longer\", logEntry.Message)\n\t\t}\n\t}\n}\n\nfunc TestMinIterationDuration(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport { Counter } from 'k6/metrics';\n\n\t\texport let options = {\n\t\t\tminIterationDuration: '7s',\n\t\t\tsetupTimeout: '2s',\n\t\t\tteardownTimeout: '2s',\n\t\t\tthresholds: {\n\t\t\t\t'test_counter': ['count == 3'],\n\t\t\t},\n\t\t};\n\n\t\tvar c = new Counter('test_counter');\n\n\t\texport function setup() { c.add(1); };\n\t\texport default function () { c.add(1); };\n\t\texport function teardown() { c.add(1); };\n\t`\n\n\tts := getSimpleCloudOutputTestState(t, script, nil, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed, 0)\n\n\tstart := time.Now()\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\telapsed := time.Since(start)\n\tassert.Greater(t, elapsed, 7*time.Second, \"expected more time to have passed because of minIterationDuration\")\n\tassert.Less(\n\t\tt, elapsed, 15*time.Second,\n\t\t\"expected less time to have passed because minIterationDuration should not affect setup() and teardown() \",\n\t)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"test_counter\\n    ✓ 'count == 3\")\n}\n\nfunc TestMetricNameError(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\t\timport { Counter } from 'k6/metrics';\n\n\t\texport let options = {\n\t\t\tvus: 2,\n\t\t\titerations: 2,\n\t\t\tthresholds: {\n\t\t\t\t'test counter': ['count == 4'],\n\t\t\t},\n\t\t};\n\n\t\tvar c = new Counter('test counter');\n\t\tnew Counter('test_counter_#'); // this is also bad but we error on the one above\n\n\t\texport function setup() { c.add(1); };\n\t\texport default function () { c.add(1); };\n\t\texport function teardown() { c.add(1); };\n\t`\n\n\tts := getSingleFileTestState(t, script, nil, exitcodes.ScriptException)\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\n\tlogEntries := ts.LoggerHook.Drain()\n\texpectedMsg := `Metric names must only include up to 128 ASCII letters, numbers, or underscores`\n\tfilteredEntries := testutils.FilterEntries(logEntries, logrus.ErrorLevel, expectedMsg)\n\trequire.Len(t, filteredEntries, 1)\n\trequire.Contains(t, filteredEntries[0].Message, \"'test counter'\")\n}\n\nfunc TestRunTags(t *testing.T) {\n\tt.Parallel()\n\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tscript := tb.Replacer.Replace(`\n\t\timport http from 'k6/http';\n\t\timport ws from 'k6/ws';\n\t\timport { Counter } from 'k6/metrics';\n\t\timport { group, check, fail } from 'k6';\n\n\t\tlet customTags =  { 'over': 'the rainbow' };\n\t\tlet params = { 'tags': customTags};\n\t\tlet statusCheck = { 'status is 200': (r) => r.status === 200 }\n\n\t\tlet myCounter = new Counter('mycounter');\n\n\t\texport const options = {\n\t\t\thosts: {\n\t\t\t\t\"HTTPBIN_DOMAIN\": \"HTTPBIN_IP\",\n\t\t\t\t\"HTTPSBIN_DOMAIN\": \"HTTPSBIN_IP\",\n\t\t\t}\n\t\t}\n\n\t\texport default function() {\n\t\t\tgroup('http', function() {\n\t\t\t\tcheck(http.get('HTTPSBIN_URL', params), statusCheck, customTags);\n\t\t\t\tcheck(http.get('HTTPBIN_URL/status/418', params), statusCheck, customTags);\n\t\t\t})\n\n\t\t\tgroup('websockets', function() {\n\t\t\t\tvar response = ws.connect('WSBIN_URL/ws-echo', params, function (socket) {\n\t\t\t\t\tsocket.on('open', function open() {\n\t\t\t\t\t\tconsole.log('ws open and say hello');\n\t\t\t\t\t\tsocket.send('hello');\n\t\t\t\t\t});\n\n\t\t\t\t\tsocket.on('message', function (message) {\n\t\t\t\t\t\tconsole.log('ws got message ' + message);\n\t\t\t\t\t\tif (message != 'hello') {\n\t\t\t\t\t\t\tfail('Expected to receive \"hello\" but got \"' + message + '\" instead !');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconsole.log('ws closing socket...');\n\t\t\t\t\t\tsocket.close();\n\t\t\t\t\t});\n\n\t\t\t\t\tsocket.on('close', function () {\n\t\t\t\t\t\tconsole.log('ws close');\n\t\t\t\t\t});\n\n\t\t\t\t\tsocket.on('error', function (e) {\n\t\t\t\t\t\tconsole.log('ws error: ' + e.error());\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\tconsole.log('connect returned');\n\t\t\t\tcheck(response, { 'status is 101': (r) => r && r.status === 101 }, customTags);\n\t\t\t})\n\n\t\t\tmyCounter.add(1, customTags);\n\t\t}\n\t`)\n\n\tts := getSingleFileTestState(t, script, []string{\n\t\t\"-u\", \"2\", \"--log-output=stdout\", \"--out\", \"json=results.json\",\n\t\t\"--tag\", \"foo=bar\", \"--tag\", \"test=mest\", \"--tag\", \"over=written, something\",\n\t}, 0)\n\tts.Env[\"K6_ITERATIONS\"] = \"3\"\n\tts.Env[\"K6_INSECURE_SKIP_TLS_VERIFY\"] = \"true\"\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\n\tjsonResults, err := fsext.ReadFile(ts.FS, \"results.json\")\n\trequire.NoError(t, err)\n\n\texpTags := map[string]string{\"foo\": \"bar\", \"test\": \"mest\", \"over\": \"written, something\", \"scenario\": \"default\"}\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"iterations\", expTags)))\n\tassert.Equal(t, 3, len(getSampleValues(t, jsonResults, \"iteration_duration\", expTags)))\n\tassert.Less(t, float64(0), sum(getSampleValues(t, jsonResults, \"data_received\", expTags)))\n\tassert.Less(t, float64(0), sum(getSampleValues(t, jsonResults, \"data_sent\", expTags)))\n\n\texpTags[\"over\"] = \"the rainbow\" // we overwrite this in most with custom tags in the script\n\tassert.Equal(t, float64(6), sum(getSampleValues(t, jsonResults, \"checks\", expTags)))\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"mycounter\", expTags)))\n\n\texpTags[\"group\"] = \"::http\"\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"checks\", expTags)))\n\tassert.Equal(t, float64(6), sum(getSampleValues(t, jsonResults, \"http_reqs\", expTags)))\n\tassert.Equal(t, 6, len(getSampleValues(t, jsonResults, \"http_req_duration\", expTags)))\n\texpTags[\"expected_response\"] = \"true\"\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"http_reqs\", expTags)))\n\tassert.Equal(t, 3, len(getSampleValues(t, jsonResults, \"http_req_duration\", expTags)))\n\texpTags[\"expected_response\"] = \"false\"\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"http_reqs\", expTags)))\n\tassert.Equal(t, 3, len(getSampleValues(t, jsonResults, \"http_req_duration\", expTags)))\n\tdelete(expTags, \"expected_response\")\n\n\texpTags[\"group\"] = \"::websockets\"\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"checks\", expTags)))\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"ws_sessions\", expTags)))\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"ws_msgs_sent\", expTags)))\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"ws_msgs_received\", expTags)))\n\tassert.Equal(t, 3, len(getSampleValues(t, jsonResults, \"ws_session_duration\", expTags)))\n\tassert.Equal(t, 0, len(getSampleValues(t, jsonResults, \"http_req_duration\", expTags)))\n\texpTags[\"check\"] = \"status is 101\"\n\tassert.Equal(t, float64(3), sum(getSampleValues(t, jsonResults, \"checks\", expTags)))\n}\n\nfunc TestRunWithCloudOutputOverrides(t *testing.T) {\n\tt.Parallel()\n\n\tts := getSingleFileTestState(\n\t\tt, \"export default function () {};\",\n\t\t[]string{\"-v\", \"--log-output=stdout\", \"--out=cloud\", \"--out\", \"json=results.json\"}, 0,\n\t)\n\n\tconfigOverride := http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) {\n\t\tresp.WriteHeader(http.StatusOK)\n\t\t_, err := fmt.Fprint(resp, `{\"reference_id\": \"132\", \"config\": {\"webAppURL\": \"https://bogus.url\"}}`)\n\t\tassert.NoError(t, err)\n\t})\n\tsrv := getCloudTestEndChecker(t, 132, configOverride, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed)\n\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"execution: local\")\n\tassert.Contains(t, stdout, \"output: cloud (https://bogus.url/runs/132), json (results.json)\")\n\tassert.Contains(t, stdout, \"iterations...........: 1\")\n}\n\nfunc TestRunWithCloudOutputCustomConfigAndOverridesLegacyCloudOption(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `\nexport const options = {\n  ext: {\n    loadimpact: {\n      name: 'Hello k6 Cloud!',\n      projectID: 123456,\n    },\n  },\n};\n\nexport default function() {};`\n\n\tts := getSingleFileTestState(t, script, []string{\"-v\", \"--log-output=stdout\", \"--out=cloud\"}, 0)\n\n\tconfigOverride := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\tb, err := io.ReadAll(req.Body)\n\t\trequire.NoError(t, err)\n\n\t\tbjs := string(b)\n\t\tassert.Contains(t, bjs, `\"name\":\"Hello k6 Cloud!\"`)\n\t\tassert.Contains(t, bjs, `\"project_id\":123456`)\n\n\t\tresp.WriteHeader(http.StatusOK)\n\t\t_, err = fmt.Fprint(resp, `{\n\t\t\t\"reference_id\": \"1337\",\n\t\t\t\"config\": {\n\t\t\t\t\"webAppURL\": \"https://bogus.url\",\n\t\t\t\t\"testRunDetails\": \"https://some.other.url/foo/tests/org/1337?bar=baz\"\n\t\t\t},\n\t\t\t\"logs\": [\n\t\t\t\t{\"level\": \"debug\", \"message\": \"test debug message\"},\n\t\t\t\t{\"level\": \"info\", \"message\": \"test message\"}\n\t\t\t]\n\t\t}`)\n\t\tassert.NoError(t, err)\n\t})\n\tsrv := getCloudTestEndChecker(t, 1337, configOverride, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed)\n\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"execution: local\")\n\tassert.Contains(t, stdout, \"output: cloud (https://some.other.url/foo/tests/org/1337?bar=baz)\")\n\tassert.Contains(t, stdout, `level=debug msg=\"test debug message\" output=cloud source=grafana-k6-cloud`)\n\tassert.Contains(t, stdout, `level=info msg=\"test message\" output=cloud source=grafana-k6-cloud`)\n}\n\nfunc TestRunWithCloudOutputCustomConfigAndOverrides(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `\nexport const options = {\n  cloud: {\n    name: 'Hello k6 Cloud!',\n    projectID: 123456,\n  },\n};\n\nexport default function() {};`\n\n\tts := getSingleFileTestState(t, script, []string{\"-v\", \"--log-output=stdout\", \"--out=cloud\"}, 0)\n\n\tconfigOverride := http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\tb, err := io.ReadAll(req.Body)\n\t\trequire.NoError(t, err)\n\n\t\tbjs := string(b)\n\t\tassert.Contains(t, bjs, `\"name\":\"Hello k6 Cloud!\"`)\n\t\tassert.Contains(t, bjs, `\"project_id\":123456`)\n\n\t\tresp.WriteHeader(http.StatusOK)\n\t\t_, err = fmt.Fprint(resp, `{\n\t\t\t\"reference_id\": \"1337\",\n\t\t\t\"config\": {\n\t\t\t\t\"webAppURL\": \"https://bogus.url\",\n\t\t\t\t\"testRunDetails\": \"https://some.other.url/foo/tests/org/1337?bar=baz\"\n\t\t\t},\n\t\t\t\"logs\": [\n\t\t\t\t{\"level\": \"debug\", \"message\": \"test debug message\"},\n\t\t\t\t{\"level\": \"info\", \"message\": \"test message\"}\n\t\t\t]\n\t\t}`)\n\t\tassert.NoError(t, err)\n\t})\n\tsrv := getCloudTestEndChecker(t, 1337, configOverride, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed)\n\tts.Env[\"K6_CLOUD_HOST\"] = srv.URL\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.Contains(t, stdout, \"execution: local\")\n\tassert.Contains(t, stdout, \"output: cloud (https://some.other.url/foo/tests/org/1337?bar=baz)\")\n\tassert.Contains(t, stdout, `level=debug msg=\"test debug message\" output=cloud source=grafana-k6-cloud`)\n\tassert.Contains(t, stdout, `level=info msg=\"test message\" output=cloud source=grafana-k6-cloud`)\n}\n\nfunc TestPrometheusRemoteWriteOutput(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.Env[\"K6_PROMETHEUS_RW_SERVER_URL\"] = \"http://a-fake-url-for-fail\"\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--out\", \"experimental-prometheus-rw\", \"-\"}\n\tts.Stdin = bytes.NewBufferString(`export default function () {};`)\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\tts.OutMutex.Lock()\n\tstdout := ts.Stdout.String()\n\tts.OutMutex.Unlock()\n\n\tassert.Contains(t, stdout, \"output: Prometheus remote write\")\n}\n\nfunc BenchmarkReadResponseBody(b *testing.B) {\n\thttpSrv := httpmultibin.NewHTTPMultiBin(b)\n\n\tscript := httpSrv.Replacer.Replace(`\n\t\timport http from \"k6/http\";\n\t\timport { check, sleep } from \"k6\";\n\n\t\tlet statusCheck = { \"status is 200\": (r) => r.status === 200 }\n\n\t\texport let options = {\n\t\t\tduration: '10s',\n\t\t\tvus: 10\n\t\t};\n\n\t\texport default function () {\n\t\t\tlet bytes = randomIntBetween(100 * 1024, 5 * 1024 * 1024)\n\n\t\t\tlet response = http.get(http.url` + \"`HTTPBIN_IP_URL/bytes/${bytes}`\" + `)\n\t\t\tcheck(response, statusCheck)\n\n\t\t\tlet responses = http.batch([\n\t\t\t\t\t\t\t\t\t\t[\"GET\", http.url` + \"`HTTPBIN_IP_URL/stream-bytes/${bytes}`\" + `],\n\t\t\t\t\t\t\t\t\t\t[\"GET\", http.url` + \"`HTTPBIN_IP_URL/stream-bytes/${bytes}`\" + `],\n\t\t\t\t\t\t\t\t\t\t[\"GET\", http.url` + \"`HTTPBIN_IP_URL/bytes/${bytes}`\" + `],\n\t\t\t\t\t\t\t\t\t\t[\"GET\", http.url` + \"`HTTPBIN_IP_URL/bytes/${bytes}`\" + `],\n\t\t\t\t\t\t\t\t\t\t[\"GET\", http.url` + \"`HTTPBIN_IP_URL/gzip`\" + `],\n\t\t\t\t\t\t\t\t\t\t[\"GET\", http.url` + \"`HTTPBIN_IP_URL/deflate`\" + `],\n\t\t\t\t\t\t\t\t\t\t[\"GET\", http.url` + \"`HTTPBIN_IP_URL/image/jpeg`\" + `],\n\t\t\t\t\t\t\t\t\t]);\n\t\t\tresponses.forEach(res => check(res, statusCheck))\n\t\t\tsleep(0.1)\n\t\t};\n\n\t\tfunction randomIntBetween(min, max) {\n\t\t\treturn Math.floor(Math.random() * (max - min + 1) + min);\n\t\t}\n\t`)\n\n\tts := getSimpleCloudOutputTestState(b, script, nil, cloudapi.RunStatusFinished, cloudapi.ResultStatusPassed, 0)\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n}\n\nfunc TestUIRenderOutput(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\toutputs   []string\n\t\texpRender string\n\t}{\n\t\t{outputs: []string{}, expRender: \"output: -\\n\"},\n\t\t{outputs: []string{\"json\"}, expRender: \"output: json(stdout)\\n\\n\"},\n\t\t{outputs: []string{\"json\", \"csv\"}, expRender: \"output: json(stdout), csv (file.csv)\\n\\n\"},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.expRender, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := NewGlobalTestState(t)\n\t\t\tts.CmdArgs = []string{\"k6\", \"run\"}\n\t\t\tfor _, o := range tc.outputs {\n\t\t\t\tts.CmdArgs = append(ts.CmdArgs, \"-o\")\n\t\t\t\tts.CmdArgs = append(ts.CmdArgs, o)\n\t\t\t}\n\t\t\tts.CmdArgs = append(ts.CmdArgs, \"-\")\n\t\t\tts.Stdin = bytes.NewBufferString(`export default function() {};`)\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tstdout := ts.Stdout.String()\n\t\t\tassert.Contains(t, stdout, tc.expRender)\n\t\t})\n\t}\n}\n\nfunc TestUIRenderWebDashboard(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tenv       string\n\t\tactive    bool\n\t\texpRender string\n\t}{\n\t\t{expRender: \"web dashboard:\"},\n\t\t{env: \"false\", expRender: \"web dashboard:\"},\n\t\t{env: \"true\", active: true, expRender: \"web dashboard: http://127.0.0.1:\"},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.expRender, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := NewGlobalTestState(t)\n\t\t\tif tc.env != \"\" {\n\t\t\t\tts.Env[\"K6_WEB_DASHBOARD\"] = tc.env\n\t\t\t}\n\t\t\tts.Env[\"K6_WEB_DASHBOARD_PORT\"] = \"0\"\n\t\t\tts.CmdArgs = []string{\"k6\", \"run\", \"--log-output=stdout\"}\n\t\t\tts.CmdArgs = append(ts.CmdArgs, \"-\")\n\t\t\tts.Stdin = bytes.NewBufferString(`export default function() {};`)\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tif tc.active {\n\t\t\t\tassert.Contains(t, ts.Stdout.String(), tc.expRender)\n\t\t\t} else {\n\t\t\t\tassert.NotContains(t, ts.Stdout.String(), tc.expRender)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TestRunStaticArchives tests that the static archives are working as expected.\n// each archive contains the following files/catalogs:\n// ├── a.js\n// ├── foo\n// │   └── bar.js\n// ├── sample\n// │   └── data.json\n// └── script.js\n// archive was made using binary & platform from the test name\nfunc TestRunStaticArchives(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tarchive string\n\t}{\n\t\t{archive: \"archive_v0.42.0_linux.tar\"},\n\t\t{archive: \"archive_v0.42.0_windows.tar\"},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(\"Using \"+tc.archive, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := NewGlobalTestState(t)\n\n\t\t\tdata, err := os.ReadFile(filepath.Join(\"testdata/archives\", tc.archive)) //nolint:forbidigo // it's a test\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"archive.tar\"), data, 0o644))\n\n\t\t\tts.CmdArgs = []string{\"k6\", \"run\", \"--log-output=stdout\", \"archive.tar\"}\n\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\t\t\tstdout := ts.Stdout.String()\n\t\t\tassert.Contains(t, stdout, \"called default() from script.js\")\n\t\t\tassert.Contains(t, stdout, \"called Bar() from foo/bar.js\")\n\t\t\tassert.Contains(t, stdout, \"called A() from a.js\")\n\t\t\tassert.Contains(t, stdout, \"extracted john doe from sample/data.json\")\n\t\t})\n\t}\n}\n\nfunc TestBadLogOutput(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]string{\n\t\t\"NotExist\":      \"badout\",\n\t\t\"FileBadConfig\": \"file=,levels=bad\",\n\t\t\"LokiBadConfig\": \"loki=,levels=bad\",\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := NewGlobalTestState(t)\n\t\t\tts.CmdArgs = []string{\"k6\", \"run\", \"--log-output\", tc, \"-\"}\n\t\t\tts.Stdin = bytes.NewBufferString(`export default function () {};`)\n\t\t\tts.ExpectedExitCode = -1\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\t\t})\n\t}\n}\n\n// HACK: We need this so multiple tests can register differently named modules.\nvar uniqueModuleNumber uint64 //nolint:gochecknoglobals\n\n// Tests that the appropriate events are emitted in the correct order.\nfunc TestEventSystemOK(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\n\tmoduleName := fmt.Sprintf(\"k6/x/testevents-%d\", atomic.AddUint64(&uniqueModuleNumber, 1))\n\tmod := events.New(event.GlobalEvents, event.VUEvents)\n\tmodules.Register(moduleName, mod)\n\n\tts.CmdArgs = []string{\"k6\", \"--quiet\", \"run\", \"-\"}\n\tts.Stdin = bytes.NewBuffer(fmt.Appendf(nil, `\n\t\timport events from '%s';\n\t\timport { sleep } from 'k6';\n\n\t\texport let options = {\n\t\t\tvus: 1,\n\t\t\titerations: 5,\n\t\t}\n\n\t\texport default function () { sleep(1); }\n\t`, moduleName))\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tdoneCh := make(chan struct{})\n\tgo func() {\n\t\tmod.WG.Wait()\n\t\tclose(doneCh)\n\t}()\n\n\tselect {\n\tcase <-doneCh:\n\tcase <-time.After(time.Second):\n\t\tt.Fatal(\"timed out\")\n\t}\n\n\texpLog := []string{\n\t\t`got event Init with data '<nil>'`,\n\t\t`got event TestStart with data '<nil>'`,\n\t\t`got event IterStart with data '{Iteration:0 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterEnd with data '{Iteration:0 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterStart with data '{Iteration:1 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterEnd with data '{Iteration:1 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterStart with data '{Iteration:2 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterEnd with data '{Iteration:2 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterStart with data '{Iteration:3 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterEnd with data '{Iteration:3 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterStart with data '{Iteration:4 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event IterEnd with data '{Iteration:4 VUID:1 ScenarioName:default Error:<nil>}'`,\n\t\t`got event TestEnd with data '<nil>'`,\n\t\t`got event Exit with data '&{Error:<nil>}'`,\n\t}\n\tlog := ts.LoggerHook.Lines()\n\tassert.Equal(t, expLog, log)\n}\n\n// Check emitted events in the case of a script error.\nfunc TestEventSystemError(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname, script string\n\t\texpLog       []string\n\t\texpExitCode  exitcodes.ExitCode\n\t}{\n\t\t{\n\t\t\tname: \"abort\",\n\t\t\tscript: `\n\t\t\t\timport { test } from 'k6/execution';\n\n\t\t\t\texport let options = {\n\t\t\t\t\tvus: 1,\n\t\t\t\t\titerations: 5,\n\t\t\t\t}\n\n\t\t\t\texport default function () {\n\t\t\t\t\ttest.abort('oops!');\n\t\t\t\t}\n\t\t`, expLog: []string{\n\t\t\t\t\"got event Init with data '<nil>'\",\n\t\t\t\t\"got event TestStart with data '<nil>'\",\n\t\t\t\t\"got event IterStart with data '{Iteration:0 VUID:1 ScenarioName:default Error:<nil>}'\",\n\t\t\t\t\"got event IterEnd with data '{Iteration:0 VUID:1 ScenarioName:default Error:test aborted: oops! at default (file:///-:11:16(5))}'\",\n\t\t\t\t\"got event TestEnd with data '<nil>'\",\n\t\t\t\t\"got event Exit with data '&{Error:test aborted: oops! at default (file:///-:11:16(5))}'\",\n\t\t\t\t\"test aborted: oops! at default (file:///-:11:16(5))\",\n\t\t\t},\n\t\t\texpExitCode: exitcodes.ScriptAborted,\n\t\t},\n\t\t{\n\t\t\tname:   \"init\",\n\t\t\tscript: \"undefinedVar\",\n\t\t\texpLog: []string{\n\t\t\t\t\"got event Exit with data '&{Error:could not initialize '-': could not load JS test \" +\n\t\t\t\t\t\"'file:///-': ReferenceError: undefinedVar is not defined\\n\\tat file:///-:2:1(8)\\n}'\",\n\t\t\t\t\"ReferenceError: undefinedVar is not defined\\n\\tat file:///-:2:1(8)\\n\",\n\t\t\t},\n\t\t\texpExitCode: exitcodes.ScriptException,\n\t\t},\n\t\t{\n\t\t\tname: \"throw\",\n\t\t\tscript: `\n\t\t\t\texport let options = {\n\t\t\t\t\tvus: 1,\n\t\t\t\t\titerations: 2,\n\t\t\t\t}\n\n\t\t\t\texport default function () {\n\t\t\t\t\tthrow new Error('oops!');\n\t\t\t\t}\n\t\t`, expLog: []string{\n\t\t\t\t\"got event Init with data '<nil>'\",\n\t\t\t\t\"got event TestStart with data '<nil>'\",\n\t\t\t\t\"got event IterStart with data '{Iteration:0 VUID:1 ScenarioName:default Error:<nil>}'\",\n\t\t\t\t\"got event IterEnd with data '{Iteration:0 VUID:1 ScenarioName:default Error:Error: oops!\\n\\tat default (file:///-:9:12(3))\\n}'\",\n\t\t\t\t\"Error: oops!\\n\\tat default (file:///-:9:12(3))\\n\",\n\t\t\t\t\"got event IterStart with data '{Iteration:1 VUID:1 ScenarioName:default Error:<nil>}'\",\n\t\t\t\t\"got event IterEnd with data '{Iteration:1 VUID:1 ScenarioName:default Error:Error: oops!\\n\\tat default (file:///-:9:12(3))\\n}'\",\n\t\t\t\t\"Error: oops!\\n\\tat default (file:///-:9:12(3))\\n\",\n\t\t\t\t\"got event TestEnd with data '<nil>'\",\n\t\t\t\t\"got event Exit with data '&{Error:<nil>}'\",\n\t\t\t},\n\t\t\texpExitCode: 0,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := NewGlobalTestState(t)\n\n\t\t\tmoduleName := fmt.Sprintf(\"k6/x/testevents-%d\", atomic.AddUint64(&uniqueModuleNumber, 1))\n\t\t\tmod := events.New(event.GlobalEvents, event.VUEvents)\n\t\t\tmodules.Register(moduleName, mod)\n\n\t\t\tts.CmdArgs = []string{\"k6\", \"--quiet\", \"run\", \"-\"}\n\t\t\tts.ExpectedExitCode = int(tc.expExitCode)\n\t\t\tts.Stdin = bytes.NewBuffer(fmt.Appendf(nil, \"import events from '%s';\\n%s\", moduleName, tc.script))\n\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tdoneCh := make(chan struct{})\n\t\t\tgo func() {\n\t\t\t\tmod.WG.Wait()\n\t\t\t\tclose(doneCh)\n\t\t\t}()\n\n\t\t\tselect {\n\t\t\tcase <-doneCh:\n\t\t\tcase <-time.After(time.Second):\n\t\t\t\tt.Fatal(\"timed out\")\n\t\t\t}\n\n\t\t\tlog := ts.LoggerHook.Lines()\n\t\t\tassert.Equal(t, tc.expLog, log)\n\t\t})\n\t}\n}\n\nfunc BenchmarkRun(b *testing.B) {\n\tb.StopTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tts := NewGlobalTestState(b)\n\n\t\tts.CmdArgs = []string{\"k6\", \"--quiet\", \"run\", \"-\"}\n\t\tts.Stdin = bytes.NewBuffer([]byte(`\n\t\texport let options = {\n\t\t\tvus: 10,\n\t\t\titerations: 100,\n\t\t}\n\n\t\texport default function () {}\n\t\t`))\n\t\tts.ExpectedExitCode = 0\n\n\t\tb.StartTimer()\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\t\tb.StopTimer()\n\t}\n}\n\nfunc BenchmarkRunEvents(b *testing.B) {\n\tb.StopTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tts := NewGlobalTestState(b)\n\n\t\tmoduleName := fmt.Sprintf(\"k6/x/testevents-%d\", atomic.AddUint64(&uniqueModuleNumber, 1))\n\t\tmod := events.New(event.GlobalEvents, event.VUEvents)\n\t\tmodules.Register(moduleName, mod)\n\n\t\tts.CmdArgs = []string{\"k6\", \"--quiet\", \"run\", \"-\"}\n\t\tts.Stdin = bytes.NewBuffer(fmt.Appendf(nil, `\n\t\timport events from '%s';\n\t\texport let options = {\n\t\t\tvus: 10,\n\t\t\titerations: 100,\n\t\t}\n\n\t\texport default function () {}\n\t\t`, moduleName))\n\t\tts.ExpectedExitCode = 0\n\n\t\tb.StartTimer()\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\t\tb.StopTimer()\n\n\t\tdoneCh := make(chan struct{})\n\t\tgo func() {\n\t\t\tmod.WG.Wait()\n\t\t\tclose(doneCh)\n\t\t}()\n\n\t\tselect {\n\t\tcase <-doneCh:\n\t\tcase <-time.After(time.Second):\n\t\t\tb.Fatal(\"timed out\")\n\t\t}\n\t}\n}\n\nfunc TestBrowserPermissions(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname             string\n\t\toptions          string\n\t\texpectedExitCode exitcodes.ExitCode\n\t\texpectedError    string\n\t}{\n\t\t// When we do not supply the correct browser options,\n\t\t// we expect that the test iteration will stop and not\n\t\t// attempt to start a chrome instance.\n\t\t{\n\t\t\tname:             \"browser option not set\",\n\t\t\toptions:          \"\",\n\t\t\texpectedExitCode: 0,\n\t\t\texpectedError:    \"browser not found in registry. make sure to set browser type option in scenario definition in order to use the browser module\",\n\t\t},\n\t\t// When we do supply the correct browser options,\n\t\t// we expect that the browser module will start\n\t\t// the a chrome instance and work with the browser\n\t\t// APIs defined in the test script.\n\t\t//\n\t\t// We do not actually want to rely on having chrome\n\t\t// installed on dev/ci machines, and all we need to\n\t\t// verify is that the browser module does try to exec\n\t\t// a command when the correct browser options are supplied.\n\t\t// This test will try to run a \"fake\" command and we\n\t\t// expect that the test will fail when attempting to\n\t\t// run that command.\n\t\t{\n\t\t\tname: \"browser option set\",\n\t\t\toptions: `export const options = {\n\t\t\t\tscenarios: {\n\t\t\t\t\t\tbrowser: {\n\t\t\t\t\t\texecutor: 'shared-iterations',\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tbrowser: {\n\t\t\t\t\t\t\t\ttype: 'chromium',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}`,\n\t\t\texpectedExitCode: 108,\n\t\t\texpectedError:    \"k6-browser-fake-cmd\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tscript := fmt.Sprintf(`\n\t\t\timport { browser } from 'k6/browser';\n\n\t\t\t%s\n\n\t\t\texport default function() {\n\t\t\t  browser.isConnected()\n\t\t\t};\n\t\t\t`, tt.options)\n\n\t\t\tts := getSingleFileTestState(t, script, []string{}, tt.expectedExitCode)\n\t\t\tts.Env[\"K6_BROWSER_EXECUTABLE_PATH\"] = \"k6-browser-fake-cmd\"\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\t\t\tloglines := ts.LoggerHook.Drain()\n\n\t\t\tassert.Contains(t, loglines[0].Message, tt.expectedError)\n\t\t})\n\t}\n}\n\nfunc TestBrowserExperimentalImport(t *testing.T) {\n\tt.Parallel()\n\n\tconst script = `\n\t\timport { browser } from 'k6/experimental/browser';\n\n\t\texport const options = {\n\t\t\tscenarios: {\n\t\t\t\t\tbrowser: {\n\t\t\t\t\texecutor: 'shared-iterations',\n\t\t\t\t\toptions: {\n\t\t\t\t\t\tbrowser: {\n\t\t\t\t\t\t\ttype: 'chromium',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\texport default function() {\n\t\t};\n\t`\n\n\tconst wantExitCode = 107\n\tts := getSingleFileTestState(t, script, []string{}, wantExitCode)\n\tts.Env[\"K6_BROWSER_EXECUTABLE_PATH\"] = \"k6-browser-fake-cmd\"\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\tloglines := ts.LoggerHook.Drain()\n\n\tassert.Contains(t, loglines[0].Message, \"use k6/browser instead of k6/experimental/browser\")\n}\n\nfunc TestSetupTimeout(t *testing.T) {\n\tt.Parallel()\n\tts := NewGlobalTestState(t)\n\tts.ExpectedExitCode = int(exitcodes.SetupTimeout)\n\tts.CmdArgs = []string{\"k6\", \"run\", \"-\"}\n\tts.Stdin = bytes.NewBufferString(`\n\t\timport { sleep } from 'k6';\n\n\t\texport const options = {\n\t\t\tsetupTimeout: '1s',\n\t\t};\n\n\t\texport function setup() { sleep(100000); };\n\t\texport default function() {}\n\t`)\n\n\tstart := time.Now()\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\telapsed := time.Since(start)\n\tassert.Greater(t, elapsed, 1*time.Second, \"expected more time to have passed because of setupTimeout\")\n\tassert.Less(\n\t\tt, elapsed, 5*time.Second,\n\t\t\"expected less time to have passed because setupTimeout \",\n\t)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tstderr := ts.Stderr.String()\n\tt.Log(stderr)\n\tassert.Contains(t, stderr, \"setup() execution timed out after 1 seconds\")\n}\n\nfunc TestTypeScriptSupport(t *testing.T) {\n\tt.Parallel()\n\tdepScript := `\n\t\texport default function(): number {\n\t\t\tlet p: number = 42;\n\t\t\treturn p;\n\t\t}\n\t`\n\tmainScript := `\n\t\timport bar from \"./bar.ts\";\n\t\tlet s: string = \"something\";\n\t\texport default function() {\n\t\t\tconsole.log(s, bar());\n\t\t};\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.ts\"), []byte(mainScript), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"bar.ts\"), []byte(depScript), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--quiet\", \"test.ts\"}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstderr := ts.Stderr.String()\n\tt.Log(stderr)\n\tassert.Contains(t, stderr, `something 42`)\n}\n\nfunc TestTypeScriptSupportWithoutAutomaticExtensionResolution(t *testing.T) {\n\tt.Parallel()\n\tdepScript := `\n\t\texport default function(): number {\n\t\t\tlet p: number = 42;\n\t\t\treturn p;\n\t\t}\n\t`\n\tmainScript := `\n\t\timport bar from \"./bar.ts\";\n\t\tlet s: string = \"something\";\n\t\texport default function() {\n\t\t\tconsole.log(s, bar());\n\t\t};\n\t`\n\n\tts := NewGlobalTestState(t)\n\tts.Flags.AutoExtensionResolution = false\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.ts\"), []byte(mainScript), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"bar.ts\"), []byte(depScript), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--quiet\", \"test.ts\"}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstderr := ts.Stderr.String()\n\tt.Log(stderr)\n\tassert.Contains(t, stderr, `something 42`)\n}\n\nfunc TestBasicSecrets(t *testing.T) {\n\t// This is the example it will be nice if we can just run it ,but in this case it needs extra arguments so ... maybe not such a great idea\n\tt.Parallel()\n\tmainScript := `\n\t\timport secrets from \"k6/secrets\";\n\n\t\texport default async () => {\n\t\t\tconst my_secret = await secrets.get(\"cool\"); // get secret from a source with the provided identifier\n\t\t\tconsole.log(my_secret);\n\t\t\tawait secrets.get(\"else\"); // get secret from a source with the provided identifier\n\t\t\tconsole.log(my_secret);\n\t\t}\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"secrets.js\"), []byte(mainScript), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--secret-source=mock=cool=something,else=source\", \"secrets.js\"}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstderr := ts.Stderr.String()\n\tt.Log(stderr)\n\n\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" source=console`)\n\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" ***SECRET_REDACTED***=console`)\n}\n\nfunc TestMultipleSecretSources(t *testing.T) {\n\t// This is the example it will be nice if we can just run it ,but in this case it needs extra arguments so ... maybe not such a great idea\n\tt.Parallel()\n\tmainScript := `\n\t\timport secrets from \"k6/secrets\";\n\n\t\texport default async () => {\n\t\t\tconst my_secret = await secrets.source(\"first\").get(\"cool\");\n\t\t\tconsole.log(my_secret);\n\t\t\tawait secrets.source(\"second\").get(\"else\");\n\t\t\tconsole.log(my_secret);\n\t\t\ttry {\n\t\t\t\tawait secrets.source(\"second\").get(\"unkwown\");\n\t\t\t} catch {\n\t\t\t\tconsole.log(\"trigger exception on wrong key\")\n\t\t\t}\n\t\t\tawait secrets.get(\"else\"); // testing default setting\n\t\t}\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"secrets.js\"), []byte(mainScript), 0o644))\n\n\tts.CmdArgs = []string{\n\t\t\"k6\", \"run\",\n\t\t\"--secret-source=mock=name=first,cool=something\",\n\t\t\"--secret-source=mock=name=second,else=source,default\", \"secrets.js\",\n\t}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstderr := ts.Stderr.String()\n\tt.Log(stderr)\n\n\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" source=console`)\n\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" ***SECRET_REDACTED***=console`)\n\tassert.Contains(t, stderr, `level=info msg=\"trigger exception on wrong key\" ***SECRET_REDACTED***=console`)\n}\n\n// TestK6SecretSourceEnvVar covers the K6_SECRET_SOURCE environment variable, which is\n// treated as a single complete source spec equivalent to one --secret-source flag value.\nfunc TestK6SecretSourceEnvVar(t *testing.T) {\n\tt.Parallel()\n\n\t// Script that reads two keys from the default secret source.\n\tscript := `\n\t\timport secrets from \"k6/secrets\";\n\t\texport default async () => {\n\t\t\tconst a = await secrets.get(\"cool\");\n\t\t\tconst b = await secrets.get(\"else\");\n\t\t\tconsole.log(a);\n\t\t\tconsole.log(b);\n\t\t}\n\t`\n\n\ttests := []struct {\n\t\tname             string\n\t\tenvVar           string\n\t\texpectedExitCode int\n\t\tcontains         []string\n\t\tnotContains      []string\n\t}{\n\t\t{\n\t\t\tname:        \"basic mock source via env var\",\n\t\t\tenvVar:      \"mock=cool=something,else=other\",\n\t\t\tcontains:    []string{`level=info msg=\"***SECRET_REDACTED***\" source=console`},\n\t\t\tnotContains: []string{\"level=error\", \"something\", \"other\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"empty env var is error\",\n\t\t\tenvVar:           \"\",\n\t\t\texpectedExitCode: -1,\n\t\t\tcontains:         []string{\"couldn't parse secret source configuration \\\\\\\"\\\\\\\"\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"whitespace-only env var is error\",\n\t\t\tenvVar:           \"   \",\n\t\t\texpectedExitCode: -1,\n\t\t\tcontains:         []string{\"couldn't parse secret source configuration \\\\\\\"   \\\\\\\"\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"invalid source type gives clear error\",\n\t\t\tenvVar:           \"nonexistent=config\",\n\t\t\texpectedExitCode: -1,\n\t\t\tcontains:         []string{\"no secret source for type\", \"nonexistent\"},\n\t\t},\n\t}\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := NewGlobalTestState(t)\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(script), 0o644))\n\t\t\tif tc.expectedExitCode != 0 {\n\t\t\t\tts.ExpectedExitCode = tc.expectedExitCode\n\t\t\t}\n\t\t\tts.Env[\"K6_SECRET_SOURCE\"] = tc.envVar\n\t\t\tts.CmdArgs = []string{\"k6\", \"run\", \"script.js\"}\n\n\t\t\tts.ReparseFlags()\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tstderr := ts.Stderr.String()\n\t\t\tt.Log(stderr)\n\t\t\tfor _, s := range tc.contains {\n\t\t\t\tassert.Contains(t, stderr, s)\n\t\t\t}\n\t\t\tfor _, s := range tc.notContains {\n\t\t\t\tassert.NotContains(t, stderr, s)\n\t\t\t}\n\t\t})\n\t}\n\n\tt.Run(\"file source via env var\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(script), 0o644))\n\t\tsecretFile := filepath.Join(ts.Cwd, \"secrets.env\")\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, secretFile, []byte(\"cool=val1\\nelse=val2\\n\"), 0o644))\n\n\t\tts.Env[\"K6_SECRET_SOURCE\"] = \"file=\" + secretFile\n\t\tts.CmdArgs = []string{\"k6\", \"run\", \"script.js\"}\n\n\t\tts.ReparseFlags()\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstderr := ts.Stderr.String()\n\t\tt.Log(stderr)\n\t\tassert.NotContains(t, stderr, \"level=error\")\n\t\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" source=console`)\n\t\tassert.NotContains(t, stderr, \"val1\")\n\t\tassert.NotContains(t, stderr, \"val2\")\n\t})\n\n\tt.Run(\"url source via env var\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Spin up a local HTTP server that returns a plain-text secret.\n\t\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t// The key is the last path segment: /secrets/{key}\n\t\t\t_, _ = w.Write([]byte(\"url-secret-value\"))\n\t\t}))\n\t\tt.Cleanup(srv.Close)\n\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(script), 0o644))\n\n\t\tts.Env[\"K6_SECRET_SOURCE\"] = fmt.Sprintf(\"url=urlTemplate=%s/secrets/{key},maxRetries=0\", srv.URL)\n\t\tts.CmdArgs = []string{\"k6\", \"run\", \"script.js\"}\n\t\tts.ReparseFlags()\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstderr := ts.Stderr.String()\n\t\tt.Log(stderr)\n\t\tassert.NotContains(t, stderr, \"level=error\")\n\t\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" source=console`)\n\t\tassert.NotContains(t, stderr, \"url-secret-value\")\n\t})\n\n\tt.Run(\"entire env var value is one spec, commas within it are source arguments not separators\", func(t *testing.T) {\n\t\t// K6_SECRET_SOURCE is equivalent to a single --secret-source flag value —\n\t\t// the whole string is one spec. Commas within it belong to the source's\n\t\t// own argument syntax (e.g. mock=name=mysource,cool=val uses commas to\n\t\t// separate name= and key=val arguments), not source-to-source separators.\n\t\tt.Parallel()\n\t\tnamedScript := `\n\t\t\timport secrets from \"k6/secrets\";\n\t\t\texport default async () => {\n\t\t\t\tconst v = await secrets.source(\"mysource\").get(\"cool\");\n\t\t\t\tconsole.log(v);\n\t\t\t}\n\t\t`\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(namedScript), 0o644))\n\n\t\tts.Env[\"K6_SECRET_SOURCE\"] = \"mock=name=mysource,cool=secretval\"\n\t\tts.CmdArgs = []string{\"k6\", \"run\", \"script.js\"}\n\n\t\tts.ReparseFlags()\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstderr := ts.Stderr.String()\n\t\tt.Log(stderr)\n\t\tassert.NotContains(t, stderr, \"level=error\")\n\t\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" source=console`)\n\t})\n\n\tt.Run(\"name= and default suffixes work via env var\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tnamedScript := `\n\t\t\timport secrets from \"k6/secrets\";\n\t\t\texport default async () => {\n\t\t\t\t// access by explicit name\n\t\t\t\tconst a = await secrets.source(\"named\").get(\"cool\");\n\t\t\t\t// access via default\n\t\t\t\tconst b = await secrets.get(\"cool\");\n\t\t\t\tconsole.log(a);\n\t\t\t\tconsole.log(b);\n\t\t\t}\n\t\t`\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(namedScript), 0o644))\n\n\t\tts.Env[\"K6_SECRET_SOURCE\"] = \"mock=name=named,cool=secretval,default\"\n\t\tts.CmdArgs = []string{\"k6\", \"run\", \"script.js\"}\n\n\t\tts.ReparseFlags()\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstderr := ts.Stderr.String()\n\t\tt.Log(stderr)\n\t\tassert.NotContains(t, stderr, \"level=error\")\n\t\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" source=console`)\n\t})\n\n\tt.Run(\"cli flags overrides env variable\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tmultiScript := `\n\t\t\timport secrets from \"k6/secrets\";\n\t\t\texport default async () => {\n\t\t\t\tlet secondMissing = false;\n\t\t\t\ttry {\n\t\t\t\t\tconst a = await secrets.source(\"second\").get(\"cool\");\n\t\t\t\t} catch (e) {\n\t\t\t\t\tsecondMissing = true\n\t\t\t\t}\n\t\t\t\tconst b = await secrets.source(\"first\").get(\"cool\");\n\t\t\t\tconsole.log(b);\n\t\t\t\tconsole.log(secondMissing);\n\t\t\t}\n\t\t`\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(multiScript), 0o644))\n\n\t\tts.Env[\"K6_SECRET_SOURCE\"] = \"mock=name=second,cool=second-secret\"\n\t\tts.CmdArgs = []string{\"k6\", \"run\", \"--secret-source=mock=name=first,cool=first-secret\", \"script.js\"}\n\n\t\tts.ReparseFlags()\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstderr := ts.Stderr.String()\n\t\tt.Log(stderr)\n\t\tassert.NotContains(t, stderr, \"level=error\")\n\t\t// Both secrets are redacted in the output.\n\t\tassert.Contains(t, stderr, `level=info msg=\"***SECRET_REDACTED***\" source=console`)\n\t\t// The boolean false is not a secret — it is logged as-is.\n\t\tassert.Contains(t, stderr, `level=info msg=true source=console`)\n\t})\n}\n\nfunc TestSummaryExport(t *testing.T) {\n\tt.Parallel()\n\n\tmainScript := `\n\t\timport { check } from \"k6\";\n\t\timport { Counter } from 'k6/metrics';\n\n\t\tconst customIter = new Counter(\"custom_iterations\");\n\n\t\texport default function () {\n\t\t\tcustomIter.add(1);\n\t\t\tcheck(true, { \"TRUE is TRUE\": (r) => r });\n\t\t};\n\t`\n\n\tassertSummaryExport := func(t *testing.T, fs fsext.Fs) {\n\t\tt.Helper()\n\n\t\trawSummaryExport, err := fsext.ReadFile(fs, \"results.json\")\n\t\trequire.NoError(t, err)\n\n\t\tvar summaryExport map[string]any\n\t\trequire.NoError(t, json.Unmarshal(rawSummaryExport, &summaryExport))\n\n\t\tassert.Equal(t, map[string]any{\n\t\t\t\"groups\": map[string]any{},\n\t\t\t\"checks\": map[string]any{\n\t\t\t\t\"TRUE is TRUE\": map[string]any{\n\t\t\t\t\t\"fails\":  float64(0),\n\t\t\t\t\t\"id\":     \"1bed1cc5e442054df516f1ca1076ac6a\",\n\t\t\t\t\t\"name\":   \"TRUE is TRUE\",\n\t\t\t\t\t\"passes\": float64(1),\n\t\t\t\t\t\"path\":   \"::TRUE is TRUE\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"name\": \"\",\n\t\t\t\"path\": \"\",\n\t\t\t\"id\":   \"d41d8cd98f00b204e9800998ecf8427e\",\n\t\t}, summaryExport[\"root_group\"])\n\n\t\tmetrics := summaryExport[\"metrics\"].(map[string]any)\n\n\t\tassert.Equal(t, 1.0, metrics[\"custom_iterations\"].(map[string]any)[\"count\"])\n\t\tassert.Equal(t, 1.0, metrics[\"iterations\"].(map[string]any)[\"count\"])\n\n\t\tchecks := metrics[\"checks\"].(map[string]any)\n\t\tassert.Equal(t, 1.0, checks[\"passes\"])\n\t\tassert.Equal(t, 0.0, checks[\"fails\"])\n\t\tassert.Equal(t, 1.0, checks[\"value\"])\n\n\t\t// These metrics are created adhoc for visual end-of-test summary only,\n\t\t// thus they shouldn't be present on the exported summary.\n\t\tassert.NotContains(t, \"checks_total\", metrics)\n\t\tassert.NotContains(t, \"checks_succeeded\", metrics)\n\t\tassert.NotContains(t, \"checks_failed\", metrics)\n\t}\n\n\tfor _, summaryMode := range []string{\"compact\", \"full\"} {\n\t\tt.Run(summaryMode, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := NewGlobalTestState(t)\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(mainScript), 0o644))\n\n\t\t\tts.CmdArgs = []string{\n\t\t\t\t\"k6\", \"run\",\n\t\t\t\t\"--summary-export=results.json\",\n\t\t\t\t\"--summary-mode=\" + summaryMode,\n\t\t\t\t\"script.js\",\n\t\t\t}\n\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tstdout := ts.Stdout.String()\n\t\t\tt.Log(stdout)\n\n\t\t\tassert.Contains(t, stdout, \"checks_total.......: 1\")\n\t\t\tassert.Contains(t, stdout, \"checks_succeeded...: 100.00% 1 out of 1\")\n\t\t\tassert.Contains(t, stdout, \"checks_failed......: 0.00%   0 out of 1\")\n\n\t\t\tassert.Contains(t, stdout, `CUSTOM\n    custom_iterations....: 1`)\n\t\t\tassert.Contains(t, stdout, \"iterations...........: 1\")\n\n\t\t\tassertSummaryExport(t, ts.FS)\n\t\t})\n\t}\n\n\t// TODO(@joanlopez): remove by k6 v2.0, once we completely drop the support for --summary-mode=legacy.\n\tt.Run(\"legacy\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(mainScript), 0o644))\n\n\t\tts.CmdArgs = []string{\n\t\t\t\"k6\", \"run\",\n\t\t\t\"--summary-export=results.json\",\n\t\t\t\"--summary-mode=legacy\",\n\t\t\t\"script.js\",\n\t\t}\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\n\t\tassert.Contains(t, stdout, \"✓ TRUE is TRUE\")\n\t\tassert.Contains(t, stdout, \"checks...............: 100.00% 1 out of 1\")\n\t\tassert.Contains(t, stdout, \"custom_iterations....: 1\")\n\t\tassert.Contains(t, stdout, \"iterations...........: 1\")\n\n\t\t// As of now, \"legacy\" has been deprecated.\n\t\tassert.Contains(t, ts.Stderr.String(), `The \\\"legacy\\\" summary mode has been deprecated, and will be removed by k6 v2.0.`)\n\n\t\tassertSummaryExport(t, ts.FS)\n\t})\n}\n\nfunc TestHandleSummary(t *testing.T) {\n\tt.Parallel()\n\tmainScript := `\n\t\timport { check } from \"k6\";\n\t\timport { Counter } from 'k6/metrics';\n\n\t\tconst customIter = new Counter(\"custom_iterations\");\n\n\t\texport default function () {\n\t\t\tcustomIter.add(1);\n\t\t\tcheck(true, { \"TRUE is TRUE\": (r) => r });\n\t\t};\n\n\t\texport function handleSummary(data) {\n\t    return {\n\t\t  'summary.json': JSON.stringify(data), //the default data object\n\t    };\n\t}\n\t`\n\n\t// TODO(@joanlopez): remove \"summary\" by k6 v2.0, once we completely drop the support for --summary-mode=legacy.\n\tfor _, summaryMode := range []string{\"compact\", \"full\", \"legacy\"} {\n\t\tt.Run(summaryMode, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := NewGlobalTestState(t)\n\t\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(mainScript), 0o644))\n\n\t\t\tts.CmdArgs = []string{\"k6\", \"run\", \"script.js\"}\n\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\tstdout := ts.Stdout.String()\n\t\t\tt.Log(stdout)\n\n\t\t\trawSummaryExport, err := fsext.ReadFile(ts.FS, \"summary.json\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar summaryExport map[string]any\n\t\t\trequire.NoError(t, json.Unmarshal(rawSummaryExport, &summaryExport))\n\n\t\t\tassert.Equal(t, map[string]any{\n\t\t\t\t\"groups\": []any{},\n\t\t\t\t\"checks\": []any{\n\t\t\t\t\tmap[string]any{\n\t\t\t\t\t\t\"fails\":  float64(0),\n\t\t\t\t\t\t\"id\":     \"1bed1cc5e442054df516f1ca1076ac6a\",\n\t\t\t\t\t\t\"name\":   \"TRUE is TRUE\",\n\t\t\t\t\t\t\"passes\": float64(1),\n\t\t\t\t\t\t\"path\":   \"::TRUE is TRUE\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t\"name\": \"\",\n\t\t\t\t\"path\": \"\",\n\t\t\t\t\"id\":   \"d41d8cd98f00b204e9800998ecf8427e\",\n\t\t\t}, summaryExport[\"root_group\"])\n\n\t\t\tmetrics := summaryExport[\"metrics\"].(map[string]any)\n\n\t\t\tassert.Equal(t, 1.0,\n\t\t\t\tmetrics[\"custom_iterations\"].(map[string]any)[\"values\"].(map[string]any)[\"count\"],\n\t\t\t)\n\t\t\tassert.Equal(t, 1.0,\n\t\t\t\tmetrics[\"iterations\"].(map[string]any)[\"values\"].(map[string]any)[\"count\"],\n\t\t\t)\n\n\t\t\tchecks := metrics[\"checks\"].(map[string]any)[\"values\"].(map[string]any)\n\t\t\tassert.Equal(t, 1.0, checks[\"rate\"])\n\t\t\tassert.Equal(t, 1.0, checks[\"passes\"])\n\t\t\tassert.Equal(t, 0.0, checks[\"fails\"])\n\n\t\t\t// These metrics are created adhoc for visual end-of-test summary only,\n\t\t\t// thus they shouldn't be present on the custom `handleSummary()` data structure.\n\t\t\tassert.NotContains(t, \"checks_total\", metrics)\n\t\t\tassert.NotContains(t, \"checks_succeeded\", metrics)\n\t\t\tassert.NotContains(t, \"checks_failed\", metrics)\n\t\t})\n\t}\n}\n\nfunc TestGroupsOrderInFullSummary(t *testing.T) {\n\tt.Parallel()\n\n\tmainScript := `\n\t\timport { group } from 'k6';\n\n\t\texport default function () {\n\t\t\tgroup('E', function () {});\n\t\t\tgroup('D', function () {});\n\t\t\tgroup('C', function () {\n\t\t\t\tgroup('B', function () {\n\t\t\t\t\tgroup('A', function () {\n\t\t\t\t\t\tgroup('too much nesting', function () {\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(mainScript), 0o644))\n\n\tts.CmdArgs = []string{\n\t\t\"k6\", \"run\",\n\t\t\"--summary-mode=full\",\n\t\t\"script.js\",\n\t}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\n\texpectedGroupsRegex := `(?m)^  █ GROUP: E\\s*^\n  █ GROUP: D\\s*^\n  █ GROUP: C\\s*^\n    ↳ GROUP: B\\s*^\n      ↳ GROUP: A\\s*^\n        ↳ GROUP: too much nesting\\s*`\n\n\tassert.Regexp(t, regexp.MustCompile(expectedGroupsRegex), stdout)\n}\n\nfunc TestGroupsOrderInFullSummaryWithScenario(t *testing.T) {\n\tt.Parallel()\n\n\tmainScript := `\n\t\timport { group } from 'k6';\n\n\t\texport const options = {\n\t\t  scenarios: {\n\t\t\tlocal: {\n\t\t\t  executor: \"shared-iterations\",\n\t\t\t},\n\t\t  },\n\t\t};\n\n\t\texport default function () {\n\t\t\tgroup('E', function () {});\n\t\t\tgroup('D', function () {});\n\t\t\tgroup('C', function () {\n\t\t\t\tgroup('B', function () {\n\t\t\t\t\tgroup('A', function () {\n\t\t\t\t\t\tgroup('too much nesting', function () {\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(mainScript), 0o644))\n\n\tts.CmdArgs = []string{\n\t\t\"k6\", \"run\",\n\t\t\"--summary-mode=full\",\n\t\t\"script.js\",\n\t}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\n\texpectedGroupsRegex := `↳ GROUP: E\\s*\n    ↳ GROUP: D\\s*\n    ↳ GROUP: C\\s*\n      ↳ GROUP: B\\s*\n        ↳ GROUP: A\\s*\n          ↳ GROUP: too much nesting\\s*`\n\n\tassert.Regexp(t, regexp.MustCompile(expectedGroupsRegex), stdout)\n}\n\nfunc TestInvalidSummaryModeAbortsTheExecution(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\n\t\t\"k6\", \"run\", \"--summary-mode=unknown\", \"-\",\n\t}\n\tts.Stdin = bytes.NewBufferString(`export default function() {};`)\n\n\t// We expect the execution to be aborted by the invalid summary\n\t// mode and the exit code to be non-zero.\n\tts.ExpectedExitCode = -1\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t// And the error to be shown on stderr.\n\tassert.Contains(t,\n\t\tts.Stderr.String(),\n\t\t`level=error msg=\"invalid summary mode\"`,\n\t)\n}\n\nfunc TestMachineReadableSummary(t *testing.T) {\n\tt.Parallel()\n\n\tmainScript := `\n\t\timport { check } from \"k6\";\n\t\timport { Counter } from 'k6/metrics';\n\n\t\tconst customIter = new Counter(\"custom_iterations\");\n\n\t\texport default function () {\n\t\t\tcustomIter.add(1);\n\t\t\tcheck(true, { \"TRUE is TRUE\": (r) => r });\n\t\t};\n\t`\n\n\tassertSummaryExport := func(t *testing.T, out string) {\n\t\tt.Helper()\n\n\t\t// Configuration block: duration is dynamic.\n\t\tconfigPattern := `\"config\": \\{\n        \"duration\": [\\d.]+,\n        \"execution\": \"local\",\n        \"script\": \"(?:[^\"\\\\]|\\\\.)*\"\n    \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(configPattern), out)\n\n\t\t// Metadata block: generated_at is dynamic.\n\t\tmetadataPattern := `\"metadata\": \\{\n        \"generated_at\": \"\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d+(Z|[+-]\\d{2}:\\d{2})\",\n        \"k6_version\": \"` + regexp.QuoteMeta(build.Version) + `\"\n    \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(metadataPattern), out)\n\n\t\t// Checks block: checks.metrics preserve the order.\n\t\tchecksPattern := `\"checks\": \\{\n            \"metrics\": \\[\n                \\{\n                    \"contains\": \"default\",\n                    \"name\": \"checks_total\",\n                    \"type\": \"counter\",\n                    \"values\": \\{\n                        \"count\": 1\n                    \\}\n                \\},\n                \\{\n                    \"contains\": \"default\",\n                    \"name\": \"checks_failed\",\n                    \"type\": \"rate\",\n                    \"values\": \\{\n                        \"matches\": 0,\n                        \"rate\": 0,\n                        \"total\": 1\n                    \\}\n                \\},\n                \\{\n                    \"contains\": \"default\",\n                    \"name\": \"checks_succeeded\",\n                    \"type\": \"rate\",\n                    \"values\": \\{\n                        \"matches\": 1,\n                        \"rate\": 1,\n                        \"total\": 1\n                    \\}\n                \\}\n            \\],\n            \"results\": \\[\n                \\{\n                    \"fails\": 0,\n                    \"name\": \"TRUE is TRUE\",\n                    \"passes\": 1\n                \\}\n            \\]\n        \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(checksPattern), out)\n\n\t\t// Metrics block: asserted individual because order may vary between executions.\n\t\titerationDurationPattern := `\\{\n                \"contains\": \"time\",\n                \"name\": \"iteration_duration\",\n                \"type\": \"trend\",\n                \"values\": \\{\n                    \"avg\": [\\d.]+,\n                    \"max\": [\\d.]+,\n                    \"med\": [\\d.]+,\n                    \"min\": [\\d.]+,\n                    \"p90\": [\\d.]+,\n                    \"p95\": [\\d.]+\n                \\}\n            \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(iterationDurationPattern), out)\n\n\t\titerationsPattern := `\\{\n                \"contains\": \"default\",\n                \"name\": \"iterations\",\n                \"type\": \"counter\",\n                \"values\": \\{\n                    \"count\": 1\n                \\}\n            \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(iterationsPattern), out)\n\n\t\tdataSentPattern := `\\{\n                \"contains\": \"data\",\n                \"name\": \"data_sent\",\n                \"type\": \"counter\",\n                \"values\": \\{\n                    \"count\": 0\n                \\}\n            \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(dataSentPattern), out)\n\n\t\tdataReceivedPattern := `\\{\n                \"contains\": \"data\",\n                \"name\": \"data_received\",\n                \"type\": \"counter\",\n                \"values\": \\{\n                    \"count\": 0\n                \\}\n            \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(dataReceivedPattern), out)\n\n\t\tcustomIterationsPattern := `\\{\n                \"contains\": \"default\",\n                \"name\": \"custom_iterations\",\n                \"type\": \"counter\",\n                \"values\": \\{\n                    \"count\": 1\n                \\}\n            \\}`\n\t\tassert.Regexp(t, regexp.MustCompile(customIterationsPattern), out)\n\n\t\t// Schema version: statically defined, as changes in the schema will likely require changes in code.\n\t\tversionPattern := `\"version\": \"1\\.0\\.0\"`\n\t\tassert.Regexp(t, regexp.MustCompile(versionPattern), out)\n\t}\n\n\tt.Run(\"--summary-export\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(mainScript), 0o644))\n\n\t\tts.CmdArgs = []string{\n\t\t\t\"k6\", \"run\",\n\t\t\t\"--summary-export=summary.json\",\n\t\t\t\"--new-machine-readable-summary=true\",\n\t\t\t\"script.js\",\n\t\t}\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\n\t\tassert.Contains(t, stdout, \"checks_total.......: 1\")\n\t\tassert.Contains(t, stdout, \"checks_succeeded...: 100.00% 1 out of 1\")\n\t\tassert.Contains(t, stdout, \"checks_failed......: 0.00%   0 out of 1\")\n\n\t\tassert.Contains(t, stdout, `CUSTOM\n    custom_iterations....: 1`)\n\t\tassert.Contains(t, stdout, \"iterations...........: 1\")\n\n\t\tsummaryExport, err := fsext.ReadFile(ts.FS, \"summary.json\")\n\t\trequire.NoError(t, err)\n\n\t\tassertSummaryExport(t, string(summaryExport))\n\t})\n\n\tt.Run(\"handleSummary()\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tmainScript := mainScript + `\n\n\t\texport function handleSummary(data) {\n\t\t\treturn {\n\t\t\t  'summary.json': JSON.stringify(data, null, 4),\n\t\t\t};\n\t\t}\n`\n\n\t\tts := NewGlobalTestState(t)\n\t\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"script.js\"), []byte(mainScript), 0o644))\n\n\t\tts.CmdArgs = []string{\n\t\t\t\"k6\", \"run\",\n\t\t\t\"--new-machine-readable-summary=true\",\n\t\t\t\"script.js\",\n\t\t}\n\n\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\tstdout := ts.Stdout.String()\n\t\tt.Log(stdout)\n\n\t\tsummaryExport, err := fsext.ReadFile(ts.FS, \"summary.json\")\n\t\trequire.NoError(t, err)\n\n\t\tassertSummaryExport(t, string(summaryExport))\n\t})\n}\n\nfunc TestSpaceInPath(t *testing.T) {\n\tt.Parallel()\n\tdepScript := `\n\t\texport default function() {\n\t\t\tlet p = 42;\n\t\t\treturn p;\n\t\t}\n\t`\n\tmainScript := `\n\t\timport bar from \"./foo bar.js\";\n\t\tlet s = \"something\";\n\t\texport default function() {\n\t\t\tconsole.log(s, bar());\n\t\t};\n\t`\n\n\tts := NewGlobalTestState(t)\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test me.js\"), []byte(mainScript), 0o644))\n\trequire.NoError(t, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"foo bar.js\"), []byte(depScript), 0o644))\n\n\tts.CmdArgs = []string{\"k6\", \"run\", \"--quiet\", \"test me.js\"}\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\tstderr := ts.Stderr.String()\n\tt.Log(stderr)\n\tassert.Contains(t, stderr, `something 42`)\n}\n"
  },
  {
    "path": "internal/cmd/tests/doc.go",
    "content": "// Package tests contains integration tests that run k6 commands, and interact\n// with standard I/O streams. They're the highest level tests we have, just\n// below E2E tests that execute the k6 binary. Since they initialize all\n// internal k6 components similarly to how a user would, they're very useful,\n// but also very expensive to run.\npackage tests\n"
  },
  {
    "path": "internal/cmd/tests/eventloop_test.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/cmd\"\n)\n\nfunc TestEventLoop(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\t\tsetTimeout(()=> {console.log(\"initcontext setTimeout\")}, 200)\n\t\tconsole.log(\"initcontext\");\n\t\texport default function() {\n\t\t\tsetTimeout(()=> {console.log(\"default setTimeout\")}, 200)\n\t\t\tconsole.log(\"default\");\n\t\t};\n\t\texport function setup() {\n\t\t\tsetTimeout(()=> {console.log(\"setup setTimeout\")}, 200)\n\t\t\tconsole.log(\"setup\");\n\t\t};\n\t\texport function teardown() {\n\t\t\tsetTimeout(()=> {console.log(\"teardown setTimeout\")}, 200)\n\t\t\tconsole.log(\"teardown\");\n\t\t};\n\t\texport function handleSummary() {\n\t\t\tsetTimeout(()=> {console.log(\"handleSummary setTimeout\")}, 200)\n\t\t\tconsole.log(\"handleSummary\");\n\t\t};\n`)\n\teventLoopTest(t, script, func(logLines []string) {\n\t\trequire.Equal(t, []string{\n\t\t\t\"initcontext\", // first initialization\n\t\t\t\"initcontext setTimeout\",\n\t\t\t\"initcontext\", // for vu\n\t\t\t\"initcontext setTimeout\",\n\t\t\t\"initcontext\", // for setup\n\t\t\t\"initcontext setTimeout\",\n\t\t\t\"setup\", // setup\n\t\t\t\"setup setTimeout\",\n\t\t\t\"default\", // one iteration\n\t\t\t\"default setTimeout\",\n\t\t\t\"initcontext\", // for teardown\n\t\t\t\"initcontext setTimeout\",\n\t\t\t\"teardown\", // teardown\n\t\t\t\"teardown setTimeout\",\n\t\t\t\"initcontext\", // for handleSummary\n\t\t\t\"initcontext setTimeout\",\n\t\t\t\"handleSummary\", // handleSummary\n\t\t\t\"handleSummary setTimeout\",\n\t\t}, logLines)\n\t})\n}\n\nfunc TestEventLoopCrossScenario(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\t\timport exec from \"k6/execution\"\n\t\texport const options = {\n\t\t\tscenarios: {\n\t\t\t\t\"first\":{\n\t\t\t\t\texecutor: \"shared-iterations\",\n\t\t\t\t\tmaxDuration: \"1s\",\n\t\t\t\t\titerations: 1,\n\t\t\t\t\tvus: 1,\n\t\t\t\t\tgracefulStop:\"1s\",\n\t\t\t\t},\n\t\t\t\t\"second\": {\n\t\t\t\t\texecutor: \"shared-iterations\",\n\t\t\t\t\tmaxDuration: \"1s\",\n\t\t\t\t\titerations: 1,\n\t\t\t\t\tvus: 1,\n\t\t\t\t\tstartTime: \"3s\",\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\texport default function() {\n\t\t\tlet i = exec.scenario.name\n\t\t\tsetTimeout(()=> {console.log(i)}, 3000)\n\t\t}\n`)\n\n\teventLoopTest(t, script, func(logLines []string) {\n\t\trequire.Equal(t, []string{\n\t\t\t\"setTimeout 1 was stopped because the VU iteration was interrupted\",\n\t\t\t\"second\",\n\t\t}, logLines)\n\t})\n}\n\nfunc TestEventLoopDoesntCrossIterations(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\t\timport { sleep } from \"k6\"\n\t\texport const options = {\n\t\t\titerations: 2,\n\t\t\tvus: 1,\n\t\t}\n\n\t\texport default function() {\n\t\t\tlet i = __ITER;\n\t\t\tsetTimeout(()=> { console.log(i) }, 1000)\n\t\t\tif (__ITER == 0) {\n\t\t\t\tthrow \"just error\"\n\t\t\t} else {\n\t\t\t\tsleep(1)\n\t\t\t}\n\t\t}\n`)\n\n\teventLoopTest(t, script, func(logLines []string) {\n\t\trequire.Equal(t, []string{\n\t\t\t\"setTimeout 1 was stopped because the VU iteration was interrupted\",\n\t\t\t\"just error\\n\\tat default (file:///-:13:5(14))\\n\", \"1\",\n\t\t}, logLines)\n\t})\n}\n\nfunc eventLoopTest(t *testing.T, script []byte, testHandle func(logLines []string)) {\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"--quiet\", \"run\", \"-\"}\n\tts.Stdin = bytes.NewBuffer(\n\t\tappend([]byte(\"import { setTimeout } from 'k6/timers';\\n\"), script...),\n\t)\n\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\ttestHandle(ts.LoggerHook.Lines())\n}\n"
  },
  {
    "path": "internal/cmd/tests/events/events.go",
    "content": "// Package events is used for testing the event functionality.\npackage events\n\nimport (\n\t\"sync\"\n\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// RootModule is the global module instance that will create module\n// instances for each VU.\ntype RootModule struct {\n\tinitOnce               sync.Once\n\tglobalEvents, vuEvents []event.Type\n\t// Used by the test function to wait for all event handler goroutines to exit,\n\t// to avoid dangling goroutines.\n\tWG sync.WaitGroup\n\t// Closed by the global event handler once the Exit event is received, and\n\t// used as a signal for VU event handlers to also exit.\n\texit chan struct{}\n}\n\n// Events represents an instance of the events module.\ntype Events struct{}\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &Events{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New(globalEvents, vuEvents []event.Type) *RootModule {\n\treturn &RootModule{\n\t\tinitOnce:     sync.Once{},\n\t\texit:         make(chan struct{}),\n\t\tglobalEvents: globalEvents,\n\t\tvuEvents:     vuEvents,\n\t}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (rm *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\trm.initOnce.Do(func() {\n\t\tsid, evtCh := vu.Events().Global.Subscribe(rm.globalEvents...)\n\t\tlogger := vu.InitEnv().Logger\n\t\trm.WG.Add(1)\n\t\tgo func() {\n\t\t\tdefer func() {\n\t\t\t\tclose(rm.exit)\n\t\t\t\trm.WG.Done()\n\t\t\t}()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase evt, ok := <-evtCh:\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tlogger.Infof(\"got event %s with data '%+v'\", evt.Type, evt.Data)\n\t\t\t\t\tevt.Done()\n\t\t\t\t\tif evt.Type == event.Exit {\n\t\t\t\t\t\tvu.Events().Global.Unsubscribe(sid)\n\t\t\t\t\t}\n\t\t\t\tcase <-vu.Context().Done():\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t})\n\n\tif len(rm.vuEvents) > 0 {\n\t\t// NOTE: It would be an improvement to only subscribe to events in VUs\n\t\t// that will actually run the VU function (VU IDs > 0), and not in the\n\t\t// throwaway VUs used for setup/teardown. But since there's no direct\n\t\t// access to the VU ID at this point (it would involve getting it from\n\t\t// vu.Runtime()), we subscribe in all VUs, and all event handler\n\t\t// goroutines would exit normally once rm.exit is closed.\n\t\tsid, evtCh := vu.Events().Local.Subscribe(rm.vuEvents...)\n\t\tlogger := vu.InitEnv().Logger\n\t\trm.WG.Go(func() {\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase evt, ok := <-evtCh:\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tlogger.Infof(\"got event %s with data '%+v'\", evt.Type, evt.Data)\n\t\t\t\t\tevt.Done()\n\t\t\t\tcase <-rm.exit:\n\t\t\t\t\tvu.Events().Local.Unsubscribe(sid)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\treturn &Events{}\n}\n\n// Exports returns the exports of the k6 module.\nfunc (e *Events) Exports() modules.Exports {\n\treturn modules.Exports{Default: e}\n}\n"
  },
  {
    "path": "internal/cmd/tests/grpc.go",
    "content": "package tests\n\nimport (\n\t\"net\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/grpcservice\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/reflection\"\n)\n\n// GRPC .\ntype GRPC struct {\n\tAddr       string\n\tServerGRPC *grpc.Server\n\tReplacer   *strings.Replacer\n}\n\n// NewGRPC .\nfunc NewGRPC(t testing.TB) *GRPC {\n\tgrpcServer := grpc.NewServer()\n\n\taddr := getFreeBindAddr(t)\n\n\tlis, err := (&net.ListenConfig{}).Listen(t.Context(), \"tcp\", addr)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to listen: %v\", err)\n\t}\n\n\tfeatures := grpcservice.LoadFeatures(\"\")\n\tgrpcservice.RegisterRouteGuideServer(grpcServer, grpcservice.NewRouteGuideServer(features...))\n\tgrpcservice.RegisterFeatureExplorerServer(grpcServer, grpcservice.NewFeatureExplorerServer(features...))\n\treflection.Register(grpcServer)\n\n\tgo func() {\n\t\t_ = grpcServer.Serve(lis)\n\t}()\n\n\tt.Cleanup(func() {\n\t\tgrpcServer.Stop()\n\t})\n\n\treturn &GRPC{\n\t\tAddr:       addr,\n\t\tServerGRPC: grpcServer,\n\t\tReplacer: strings.NewReplacer(\n\t\t\t\"GRPCBIN_ADDR\", addr,\n\t\t),\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/tests/test_state.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"net\"\n\t\"os/signal\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t_ \"unsafe\" //nolint:revive,nolintlint // needed for the go:linkname and nolintlint is buggy\n\n\t\"go.k6.io/k6/lib\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/ui/console\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// GlobalTestState is a wrapper around GlobalState for use in tests.\ntype GlobalTestState struct {\n\t*state.GlobalState\n\tCancel func()\n\n\tStdout, Stderr *bytes.Buffer\n\tLoggerHook     *testutils.SimpleLogrusHook\n\n\tCwd string\n\n\tExpectedExitCode int\n}\n\n// NewGlobalTestState returns an initialized GlobalTestState, mocking all\n// GlobalState fields for use in tests.\nfunc NewGlobalTestState(tb testing.TB) *GlobalTestState {\n\ttb.Helper()\n\tctx, cancel := context.WithCancel(context.Background())\n\ttb.Cleanup(cancel)\n\n\tfs := fsext.NewMemMapFs()\n\tcwd := \"/test/\" // TODO: Make this relative to the test?\n\tif runtime.GOOS == \"windows\" {\n\t\tcwd = \"c:\\\\test\\\\\"\n\t}\n\trequire.NoError(tb, fs.MkdirAll(cwd, 0o755))\n\n\tlogger := logrus.New()\n\tlogger.SetLevel(logrus.InfoLevel)\n\tlogger.Out = testutils.NewTestOutput(tb)\n\thook := testutils.NewLogHook()\n\tlogger.AddHook(hook)\n\n\tts := &GlobalTestState{\n\t\tCwd:        cwd,\n\t\tCancel:     cancel,\n\t\tLoggerHook: hook,\n\t\tStdout:     new(bytes.Buffer),\n\t\tStderr:     new(bytes.Buffer),\n\t}\n\n\tosExitCalled := false\n\tdefaultOsExitHandle := func(exitCode int) {\n\t\tcancel()\n\t\tosExitCalled = true\n\t\tassert.Equal(tb, ts.ExpectedExitCode, exitCode)\n\t}\n\n\ttb.Cleanup(func() {\n\t\tif ts.ExpectedExitCode > 0 {\n\t\t\t// Ensure that, if we expected to receive an error, our `os.Exit()` mock\n\t\t\t// function was actually called.\n\t\t\tassert.Truef(tb,\n\t\t\t\tosExitCalled,\n\t\t\t\t\"expected exit code %d, but the os.Exit() mock was not called\",\n\t\t\t\tts.ExpectedExitCode,\n\t\t\t)\n\t\t}\n\t})\n\n\toutMutex := &sync.Mutex{}\n\tdefaultFlags := state.GetDefaultFlags(\".config\", \".cache\")\n\tdefaultFlags.Address = getFreeBindAddr(tb)\n\n\tts.GlobalState = &state.GlobalState{\n\t\tCtx:          ctx,\n\t\tFS:           fs,\n\t\tGetwd:        func() (string, error) { return ts.Cwd, nil },\n\t\tBinaryName:   \"k6\",\n\t\tCmdArgs:      []string{},\n\t\tEnv:          map[string]string{\"K6_NO_USAGE_REPORT\": \"true\"},\n\t\tEvents:       event.NewEventSystem(100, logger),\n\t\tDefaultFlags: defaultFlags,\n\t\tFlags:        defaultFlags,\n\t\tOutMutex:     outMutex,\n\t\tStdout: &console.Writer{\n\t\t\tMutex:  outMutex,\n\t\t\tWriter: ts.Stdout,\n\t\t\tIsTTY:  false,\n\t\t},\n\t\tStderr: &console.Writer{\n\t\t\tMutex:  outMutex,\n\t\t\tWriter: ts.Stderr,\n\t\t\tIsTTY:  false,\n\t\t},\n\t\tStdin:          new(bytes.Buffer),\n\t\tOSExit:         defaultOsExitHandle,\n\t\tSignalNotify:   signal.Notify,\n\t\tSignalStop:     signal.Stop,\n\t\tLogger:         logger,\n\t\tFallbackLogger: testutils.NewLogger(tb).WithField(\"fallback\", true),\n\t\tUsage:          usage.New(),\n\t\tTestStatus:     lib.NewTestStatus(),\n\t}\n\n\treturn ts\n}\n\n// ReparseFlags reparses flags so it can take into account changes to env variables and arguments\nfunc (ts *GlobalTestState) ReparseFlags() {\n\tdefaultFlags := getFlags(ts.DefaultFlags, ts.Env, ts.CmdArgs)\n\tts.DefaultFlags = defaultFlags\n\tts.Flags = defaultFlags\n}\n\n// TODO(@mstoykov): Figure out how to not do it this way and not have more public APIs\n// Also use this for testing more of the GlobalState.Flags\n//\n//go:linkname getFlags go.k6.io/k6/cmd/state.getFlags\nfunc getFlags(defaultFlags state.GlobalFlags, env map[string]string, args []string) state.GlobalFlags\n\nvar portRangeStart uint64 = 6565 //nolint:gochecknoglobals\n\nfunc getFreeBindAddr(tb testing.TB) string {\n\tfor range 100 {\n\t\tport := atomic.AddUint64(&portRangeStart, 1)\n\t\taddr := net.JoinHostPort(\"localhost\", strconv.FormatUint(port, 10))\n\n\t\tlistener, err := (&net.ListenConfig{}).Listen(tb.Context(), \"tcp\", addr)\n\t\tif err != nil {\n\t\t\tcontinue // port was busy for some reason\n\t\t}\n\t\tdefer func() {\n\t\t\tassert.NoError(tb, listener.Close())\n\t\t}()\n\t\treturn addr\n\t}\n\n\ttb.Fatal(\"could not get a free port\")\n\treturn \"\"\n}\n"
  },
  {
    "path": "internal/cmd/tests/tests.go",
    "content": "package tests\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"go.uber.org/goleak\"\n)\n\ntype blockingTransport struct {\n\tfallback       http.RoundTripper\n\tforbiddenHosts map[string]bool\n\tcounter        uint32\n}\n\nfunc (bt *blockingTransport) RoundTrip(req *http.Request) (*http.Response, error) {\n\thost := req.URL.Hostname()\n\tif bt.forbiddenHosts[host] {\n\t\tatomic.AddUint32(&bt.counter, 1)\n\t\tpanic(fmt.Errorf(\"trying to make forbidden request to %s during test\", host))\n\t}\n\treturn bt.fallback.RoundTrip(req)\n}\n\n// Main is a TestMain function that can be imported by other test packages that\n// want to use the blocking transport and other features useful for integration\n// tests.\n//\n//nolint:forbidigo\nfunc Main(m *testing.M) {\n\texitCode := 1 // error out by default\n\tdefer func() {\n\t\tos.Exit(exitCode)\n\t}()\n\n\tbt := &blockingTransport{\n\t\tfallback: http.DefaultTransport,\n\t\tforbiddenHosts: map[string]bool{\n\t\t\t\"ingest.k6.io\":      true,\n\t\t\t\"cloudlogs.k6.io\":   true,\n\t\t\t\"app.k6.io\":         true,\n\t\t\t\"stats.grafana.org\": true,\n\t\t},\n\t}\n\thttp.DefaultTransport = bt\n\tdefer func() {\n\t\tif bt.counter > 0 {\n\t\t\tfmt.Printf(\"Expected blocking transport count to be 0 but was %d\\n\", bt.counter)\n\t\t\texitCode = 2\n\t\t}\n\t}()\n\n\tdefer func() {\n\t\tif err := goleak.Find(); err != nil {\n\t\t\tfmt.Println(err)\n\t\t\texitCode = 3\n\t\t}\n\t}()\n\n\texitCode = m.Run()\n}\n"
  },
  {
    "path": "internal/cmd/tests/tests_test.go",
    "content": "// Package tests contains integration tests for multiple packages.\npackage tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"go.k6.io/k6/internal/cmd\"\n)\n\nfunc TestMain(m *testing.M) {\n\tMain(m)\n}\n\nfunc TestRootCommand(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string][]string{\n\t\t\"Just root\": {\"k6\"},\n\t\t\"Help flag\": {\"k6\", \"--help\"},\n\t}\n\n\thelptxt := \"Usage:\\n  k6 [command]\\n\\nCore Commands\"\n\tfor name, args := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := NewGlobalTestState(t)\n\t\t\tts.CmdArgs = args\n\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\t\t\tassert.Len(t, ts.LoggerHook.Drain(), 0)\n\t\t\tassert.Contains(t, ts.Stdout.String(), helptxt)\n\t\t})\n\t}\n}\n\nfunc TestLoginCloudNotPanicking(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewGlobalTestState(t)\n\tts.CmdArgs = []string{\"k6\", \"login\", \"cloud\"}\n\tts.ExpectedExitCode = -1\n\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\tassert.Contains(t, ts.Stderr.String(), \"Stdin is not a terminal, falling back to plain text input\")\n}\n"
  },
  {
    "path": "internal/cmd/ui.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\t\"unicode/utf8\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/grafana/xk6-dashboard/dashboard\"\n\t\"github.com/sirupsen/logrus\"\n\t\"golang.org/x/term\"\n\n\t\"gopkg.in/yaml.v3\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/internal/metrics/engine\"\n\t\"go.k6.io/k6/internal/output/summary\"\n\t\"go.k6.io/k6/internal/ui\"\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/output\"\n)\n\nconst (\n\t// Max length of left-side progress bar text before trimming is forced\n\tmaxLeftLength = 30\n\t// Amount of padding in chars between rendered progress\n\t// bar text and right-side terminal window edge.\n\ttermPadding      = 1\n\tdefaultTermWidth = 80\n)\n\nfunc setColor(noColor bool, c *color.Color) *color.Color {\n\tif noColor {\n\t\tc.DisableColor()\n\t} else {\n\t\tc.EnableColor()\n\t}\n\treturn c\n}\n\n// getColor returns the requested color, or an uncolored object, depending on\n// the value of noColor. The explicit EnableColor() and DisableColor() are\n// needed because the library checks os.Stdout itself otherwise...\nfunc getColor(noColor bool, attributes ...color.Attribute) *color.Color {\n\treturn setColor(noColor, color.New(attributes...))\n}\n\nfunc getBanner(noColor bool, isTrueColor bool) string {\n\tc := color.New(color.FgYellow)\n\tif isTrueColor {\n\t\tc = color.RGB(0xFF, 0x67, 0x1d).Add(color.Bold)\n\t}\n\tc = setColor(noColor, c)\n\treturn c.Sprint(ui.Banner())\n}\n\n// isTrueColor returns true if the terminal supports true color (24-bit color).\nfunc isTrueColor(env map[string]string) bool {\n\tif v := env[\"COLORTERM\"]; v == \"truecolor\" || v == \"24bit\" { // for most terminals\n\t\treturn true\n\t}\n\tif v := env[\"ConEmuANSI\"]; v == \"ON\" { // for Windows\n\t\treturn true\n\t}\n\t// TODO: Improve this detection.\n\treturn false\n}\n\nfunc printBanner(gs *state.GlobalState) {\n\tif gs.Flags.Quiet {\n\t\treturn // do not print banner when --quiet is enabled\n\t}\n\n\tbanner := getBanner(gs.Flags.NoColor || !gs.Stdout.IsTTY, isTrueColor(gs.Env))\n\t_, err := fmt.Fprintf(gs.Stdout, \"\\n%s\\n\\n\", banner)\n\tif err != nil {\n\t\tgs.Logger.Warnf(\"could not print k6 banner message to stdout: %s\", err.Error())\n\t}\n}\n\nfunc printBar(gs *state.GlobalState, bar *pb.ProgressBar) {\n\tif gs.Flags.Quiet {\n\t\treturn\n\t}\n\tend := \"\\n\"\n\t// TODO: refactor widthDelta away? make the progressbar rendering a bit more\n\t// stateless... basically first render the left and right parts, so we know\n\t// how long the longest line is, and how much space we have for the progress\n\twidthDelta := -defaultTermWidth\n\tif gs.Stdout.IsTTY {\n\t\t// If we're in a TTY, instead of printing the bar and going to the next\n\t\t// line, erase everything till the end of the line and return to the\n\t\t// start, so that the next print will overwrite the same line.\n\t\t//\n\t\t// TODO: check for cross platform support\n\t\tend = \"\\x1b[0K\\r\"\n\t\twidthDelta = 0\n\t}\n\trendered := bar.Render(0, widthDelta)\n\t// Only output the left and middle part of the progress bar\n\tprintToStdout(gs, rendered.String()+end)\n}\n\nfunc modifyAndPrintBar(gs *state.GlobalState, bar *pb.ProgressBar, options ...pb.ProgressBarOption) {\n\tbar.Modify(options...)\n\tprintBar(gs, bar)\n}\n\n// Print execution description for both cloud and local execution.\n// TODO: Clean this up as part of #1499 or #1427\nfunc printExecutionDescription(\n\tgs *state.GlobalState, execution, filename, outputOverride string, conf Config,\n\tet *lib.ExecutionTuple, execPlan []lib.ExecutionStep, outputs []output.Output,\n) {\n\tnoColor := gs.Flags.NoColor || !gs.Stdout.IsTTY\n\tvalueColor := getColor(noColor, color.FgCyan)\n\n\tbuf := &strings.Builder{}\n\tfmt.Fprintln(buf)\n\tfmt.Fprintf(buf, \"     execution: %s\\n\", valueColor.Sprint(execution))\n\tfmt.Fprintf(buf, \"        script: %s\\n\", valueColor.Sprint(filename))\n\n\tvar outputDescriptions []string\n\tswitch {\n\tcase outputOverride != \"\":\n\t\toutputDescriptions = []string{outputOverride}\n\tdefault:\n\t\tfor _, out := range outputs {\n\t\t\tdesc := out.Description()\n\t\t\tswitch desc {\n\t\t\tcase engine.IngesterDescription, lib.GroupSummaryDescription, summary.OutputName:\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif after, ok := strings.CutPrefix(desc, dashboard.OutputName); ok {\n\t\t\t\tfmt.Fprintf(buf, \" web dashboard:%s\\n\", valueColor.Sprint(after))\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\toutputDescriptions = append(outputDescriptions, desc)\n\t\t}\n\t\tif len(outputDescriptions) == 0 {\n\t\t\toutputDescriptions = append(outputDescriptions, \"-\")\n\t\t}\n\t}\n\n\tfmt.Fprintf(buf, \"        output: %s\\n\", valueColor.Sprint(strings.Join(outputDescriptions, \", \")))\n\tif gs.Flags.ProfilingEnabled && gs.Flags.Address != \"\" {\n\t\tfmt.Fprintf(buf, \"     profiling: %s\\n\", valueColor.Sprintf(\"http://%s/debug/pprof/\", gs.Flags.Address))\n\t}\n\n\tfmt.Fprintf(buf, \"\\n\")\n\n\tmaxDuration, _ := lib.GetEndOffset(execPlan)\n\texecutorConfigs := conf.Scenarios.GetSortedConfigs()\n\n\tscenarioDesc := \"1 scenario\"\n\tif len(executorConfigs) > 1 {\n\t\tscenarioDesc = fmt.Sprintf(\"%d scenarios\", len(executorConfigs))\n\t}\n\n\tfmt.Fprintf(buf, \"     scenarios: %s\\n\", valueColor.Sprintf(\n\t\t\"(%.2f%%) %s, %d max VUs, %s max duration (incl. graceful stop):\",\n\t\tconf.ExecutionSegment.FloatLength()*100, scenarioDesc,\n\t\tlib.GetMaxPossibleVUs(execPlan), maxDuration.Round(100*time.Millisecond)),\n\t)\n\tfor _, ec := range executorConfigs {\n\t\tfmt.Fprintf(buf, \"              * %s: %s\\n\",\n\t\t\tec.GetName(), ec.GetDescription(et))\n\t}\n\tfmt.Fprintf(buf, \"\\n\")\n\n\tif gs.Flags.Quiet {\n\t\tgs.Logger.Debug(buf.String())\n\t} else {\n\t\tprintToStdout(gs, buf.String())\n\t}\n}\n\nfunc renderMultipleBars(\n\tnocolor, isTTY, goBack bool, maxLeft, termWidth, widthDelta int, pbs []*pb.ProgressBar,\n) (string, int) {\n\tlineEnd := \"\\n\"\n\tif isTTY {\n\t\t// TODO: check for cross platform support\n\t\tlineEnd = \"\\x1b[K\\n\" // erase till end of line\n\t}\n\n\tvar (\n\t\t// Amount of times line lengths exceed termWidth.\n\t\t// Needed to factor into the amount of lines to jump\n\t\t// back with [A and avoid scrollback issues.\n\t\tlineBreaks  int\n\t\tlongestLine int\n\t\t// Maximum length of each right side column except last,\n\t\t// used to calculate the padding between columns.\n\t\tmaxRColumnLen = make([]int, 2)\n\t\tpbsCount      = len(pbs)\n\t\trendered      = make([]pb.ProgressBarRender, pbsCount)\n\t\tresult        = make([]string, pbsCount+2)\n\t)\n\n\tresult[0] = lineEnd // start with an empty line\n\n\t// First pass to render all progressbars and get the maximum\n\t// lengths of right-side columns.\n\tfor i, pb := range pbs {\n\t\trend := pb.Render(maxLeft, widthDelta)\n\t\tfor i := range rend.Right {\n\t\t\t// Skip last column, since there's nothing to align after it (yet?).\n\t\t\tif i == len(rend.Right)-1 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif len(rend.Right[i]) > maxRColumnLen[i] {\n\t\t\t\tmaxRColumnLen[i] = len(rend.Right[i])\n\t\t\t}\n\t\t}\n\t\trendered[i] = rend\n\t}\n\n\t// Second pass to render final output, applying padding where needed\n\tfor i := range rendered {\n\t\trend := rendered[i]\n\t\tif rend.Hijack != \"\" {\n\t\t\tresult[i+1] = rend.Hijack + lineEnd\n\t\t\truneCount := utf8.RuneCountInString(rend.Hijack)\n\t\t\tlineBreaks += (runeCount - termPadding) / termWidth\n\t\t\tcontinue\n\t\t}\n\t\tvar leftText, rightText string\n\t\tleftPadFmt := fmt.Sprintf(\"%%-%ds\", maxLeft)\n\t\tleftText = fmt.Sprintf(leftPadFmt, rend.Left)\n\t\tfor i := range rend.Right {\n\t\t\trpad := 0\n\t\t\tif len(maxRColumnLen) > i {\n\t\t\t\trpad = maxRColumnLen[i]\n\t\t\t}\n\t\t\trightPadFmt := fmt.Sprintf(\" %%-%ds\", rpad+1)\n\t\t\trightText += fmt.Sprintf(rightPadFmt, rend.Right[i])\n\t\t}\n\t\t// Get visible line length, without ANSI escape sequences (color)\n\t\tstatus := fmt.Sprintf(\" %s \", rend.Status())\n\t\tline := leftText + status + rend.Progress() + rightText\n\t\tlineRuneCount := utf8.RuneCountInString(line)\n\t\tif lineRuneCount > longestLine {\n\t\t\tlongestLine = lineRuneCount\n\t\t}\n\t\tlineBreaks += (lineRuneCount - termPadding) / termWidth\n\t\tif !nocolor {\n\t\t\trend.Color = true\n\t\t\tstatus = fmt.Sprintf(\" %s \", rend.Status())\n\t\t\tline = fmt.Sprintf(leftPadFmt+\"%s%s%s\",\n\t\t\t\trend.Left, status, rend.Progress(), rightText)\n\t\t}\n\t\tresult[i+1] = line + lineEnd\n\t}\n\n\tif isTTY && goBack {\n\t\t// Clear screen and go back to the beginning\n\t\t// TODO: check for cross platform support\n\t\tresult[pbsCount+1] = fmt.Sprintf(\"\\r\\x1b[J\\x1b[%dA\", pbsCount+lineBreaks+1)\n\t} else {\n\t\tresult[pbsCount+1] = \"\"\n\t}\n\n\treturn strings.Join(result, \"\"), longestLine\n}\n\n// TODO: show other information here?\n// TODO: add a no-progress option that will disable these\n// TODO: don't use global variables...\n//\n//nolint:funlen,gocognit\nfunc showProgress(ctx context.Context, gs *state.GlobalState, pbs []*pb.ProgressBar, logger logrus.FieldLogger) {\n\tif gs.Flags.Quiet {\n\t\treturn\n\t}\n\n\tvar terminalSizeUnknown bool\n\ttermWidth := defaultTermWidth\n\tif gs.Stdout.IsTTY {\n\t\ttw, _, err := term.GetSize(gs.Stdout.RawOutFd)\n\t\tif (tw <= 0) || err != nil {\n\t\t\tterminalSizeUnknown = true\n\t\t\tlogger.WithError(err).Debug(\"can't get terminal size\")\n\t\t} else {\n\t\t\ttermWidth = tw\n\t\t}\n\t}\n\n\t// Get the longest left side string length, to align progress bars\n\t// horizontally and trim excess text.\n\tvar leftLen int64\n\tfor _, pb := range pbs {\n\t\tl := pb.Left()\n\t\tleftLen = max(int64(len(l)), leftLen)\n\t}\n\t// Limit to maximum left text length\n\tmaxLeft := int(min(leftLen, maxLeftLength))\n\n\tvar progressBarsLastRenderLock sync.Mutex\n\tvar progressBarsLastRender []byte\n\n\tprintProgressBars := func() {\n\t\tprogressBarsLastRenderLock.Lock()\n\t\t_, _ = gs.Stdout.Writer.Write(progressBarsLastRender)\n\t\tprogressBarsLastRenderLock.Unlock()\n\t}\n\n\tvar widthDelta int\n\t// Default to responsive progress bars when in an interactive terminal\n\trenderProgressBars := func(goBack bool) {\n\t\tbarText, longestLine := renderMultipleBars(\n\t\t\tgs.Flags.NoColor, gs.Stdout.IsTTY, goBack, maxLeft, termWidth, widthDelta, pbs,\n\t\t)\n\t\twidthDelta = termWidth - longestLine - termPadding\n\t\tprogressBarsLastRenderLock.Lock()\n\t\tprogressBarsLastRender = []byte(barText)\n\t\tprogressBarsLastRenderLock.Unlock()\n\t}\n\n\t// Otherwise fallback to fixed compact progress bars\n\tif !gs.Stdout.IsTTY {\n\t\twidthDelta = -pb.DefaultWidth\n\t\trenderProgressBars = func(goBack bool) {\n\t\t\tbarText, _ := renderMultipleBars(gs.Flags.NoColor, gs.Stdout.IsTTY, goBack, maxLeft, termWidth, widthDelta, pbs)\n\t\t\tprogressBarsLastRenderLock.Lock()\n\t\t\tprogressBarsLastRender = []byte(barText)\n\t\t\tprogressBarsLastRenderLock.Unlock()\n\t\t}\n\t}\n\n\t// TODO: make configurable?\n\tupdateFreq := 1 * time.Second\n\tvar stdoutFD int\n\tif gs.Stdout.IsTTY {\n\t\tstdoutFD = gs.Stdout.RawOutFd\n\t\tupdateFreq = 100 * time.Millisecond\n\t\tgs.OutMutex.Lock()\n\t\tgs.Stdout.PersistentText = printProgressBars\n\t\tgs.Stderr.PersistentText = printProgressBars\n\t\tgs.OutMutex.Unlock()\n\t\tdefer func() {\n\t\t\tgs.OutMutex.Lock()\n\t\t\tgs.Stdout.PersistentText = nil\n\t\t\tgs.Stderr.PersistentText = nil\n\t\t\tgs.OutMutex.Unlock()\n\t\t}()\n\t}\n\n\tvar winch chan os.Signal\n\tif sig := getWinchSignal(); sig != nil {\n\t\twinch = make(chan os.Signal, 10)\n\t\tgs.SignalNotify(winch, sig)\n\t\tdefer gs.SignalStop(winch)\n\t}\n\n\tticker := time.NewTicker(updateFreq)\n\tctxDone := ctx.Done()\n\tfor {\n\t\tselect {\n\t\tcase <-ctxDone:\n\t\t\trenderProgressBars(false)\n\t\t\tgs.OutMutex.Lock()\n\t\t\tprintProgressBars()\n\t\t\tgs.OutMutex.Unlock()\n\t\t\treturn\n\t\tcase <-winch:\n\t\t\tif gs.Stdout.IsTTY && !terminalSizeUnknown {\n\t\t\t\t// More responsive progress bar resizing on platforms with SIGWINCH (*nix)\n\t\t\t\ttw, _, err := term.GetSize(stdoutFD)\n\t\t\t\tif tw > 0 && err == nil {\n\t\t\t\t\ttermWidth = tw\n\t\t\t\t}\n\t\t\t}\n\t\tcase <-ticker.C:\n\t\t\t// Default ticker-based progress bar resizing\n\t\t\tif gs.Stdout.IsTTY && !terminalSizeUnknown && winch == nil {\n\t\t\t\ttw, _, err := term.GetSize(stdoutFD)\n\t\t\t\tif tw > 0 && err == nil {\n\t\t\t\t\ttermWidth = tw\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trenderProgressBars(true)\n\t\tgs.OutMutex.Lock()\n\t\tprintProgressBars()\n\t\tgs.OutMutex.Unlock()\n\t}\n}\n\nfunc yamlPrint(w io.Writer, v any) error {\n\tdata, err := yaml.Marshal(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not marshal YAML: %w\", err)\n\t}\n\t_, err = fmt.Fprint(w, string(data))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could flush the data to the output: %w\", err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/cmd/ui_test.go",
    "content": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n)\n\n// Return progressbars with different content lengths, to test for\n// padding.\nfunc createTestProgressBars(num, padding, colIdx int) []*pb.ProgressBar {\n\tpbs := make([]*pb.ProgressBar, num)\n\tfor i := range num {\n\t\tleft := fmt.Sprintf(\"left %d\", i)\n\t\trightCol1 := fmt.Sprintf(\"right %d\", i)\n\t\tprogress := 0.0\n\t\tstatus := pb.Running\n\t\tif i == colIdx {\n\t\t\tpad := strings.Repeat(\"+\", padding)\n\t\t\tleft += pad\n\t\t\trightCol1 += pad\n\t\t\tprogress = 1.0\n\t\t\tstatus = pb.Done\n\t\t}\n\t\tpbs[i] = pb.New(\n\t\t\tpb.WithLeft(func() string { return left }),\n\t\t\tpb.WithStatus(status),\n\t\t\tpb.WithProgress(func() (float64, []string) {\n\t\t\t\treturn progress, []string{rightCol1, \"000\"}\n\t\t\t}),\n\t\t)\n\t}\n\treturn pbs\n}\n\nfunc TestRenderMultipleBars(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname        string\n\t\tpadding     int\n\t\twidthDelta  int\n\t\texpOut      string\n\t\texpLongLine int\n\t}{\n\t\t{\"pad0\", 0, 0, `\nleft 0   [--------------------------------------] right 0  000\nleft 1 ✓ [======================================] right 1  000\nleft 2   [--------------------------------------] right 2  000\n`, 62},\n\t\t{\"pad2\", 2, 0, `\nleft 0     [--------------------------------------] right 0    000\nleft 1++ ✓ [======================================] right 1++  000\nleft 2     [--------------------------------------] right 2    000\n`, 66},\n\t\t{\"pad0compact\", 0, -50, `\nleft 0   [   0% ] right 0  000\nleft 1 ✓ [ 100% ] right 1  000\nleft 2   [   0% ] right 2  000\n`, 30},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpbs := createTestProgressBars(3, tc.padding, 1)\n\t\t\tout, longestLine := renderMultipleBars(true, false, false, 6+tc.padding, 80, tc.widthDelta, pbs)\n\t\t\tassert.Equal(t, tc.expOut, out)\n\t\t\tassert.Equal(t, tc.expLongLine, longestLine)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/cmd/ui_unix.go",
    "content": "//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos\n\npackage cmd\n\nimport (\n\t\"os\"\n\t\"syscall\"\n)\n\nfunc getWinchSignal() os.Signal {\n\treturn syscall.SIGWINCH\n}\n"
  },
  {
    "path": "internal/cmd/ui_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage cmd\n\nimport (\n\t\"os\"\n)\n\nfunc getWinchSignal() os.Signal {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/cmd/version.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/build\"\n)\n\nconst (\n\tcommitKey      = \"commit\"\n\tcommitDirtyKey = \"commit_dirty\"\n\tmainK6Path     = \"go.k6.io/k6\"\n)\n\n// fullVersion returns the maximally full version and build information for\n// the currently running k6 executable.\nfunc fullVersion() string {\n\tdetails := versionDetails()\n\n\tgoVersionArch := fmt.Sprintf(\"%s, %s/%s\", details[\"go_version\"], details[\"go_os\"], details[\"go_arch\"])\n\n\tk6version := fmt.Sprintf(\"%s\", details[\"version\"])\n\t// for the fallback case when the version is not in the expected format\n\t// cobra adds a \"v\" prefix to the version\n\tk6version = strings.TrimLeft(k6version, \"v\")\n\n\tcommit, ok := details[commitKey].(string)\n\tif !ok || commit == \"\" {\n\t\treturn fmt.Sprintf(\"%s (%s)\", k6version, goVersionArch)\n\t}\n\n\tisDirty, ok := details[commitDirtyKey].(bool)\n\tif ok && isDirty {\n\t\tcommit += \"-dirty\"\n\t}\n\n\treturn fmt.Sprintf(\"%s (commit/%s, %s)\", k6version, commit, goVersionArch)\n}\n\n// versionDetails returns the structured details about version\nfunc versionDetails() map[string]any {\n\tv := build.Version\n\tif !strings.HasPrefix(v, \"v\") {\n\t\tv = \"v\" + v\n\t}\n\n\tdetails := map[string]any{\n\t\t\"version\":    v,\n\t\t\"go_version\": runtime.Version(),\n\t\t\"go_os\":      runtime.GOOS,\n\t\t\"go_arch\":    runtime.GOARCH,\n\t}\n\n\tbuildInfo, ok := debug.ReadBuildInfo()\n\tif !ok {\n\t\treturn details\n\t}\n\n\tif buildInfo.Main.Path == mainK6Path {\n\t\tdetails[\"version\"] = buildInfo.Main.Version\n\t\tif buildInfo.Main.Version == \"(devel)\" {\n\t\t\tdetails[\"version\"] = v\n\t\t\tdetails[commitKey] = \"devel\"\n\t\t}\n\t\tfor _, s := range buildInfo.Settings {\n\t\t\tswitch s.Key {\n\t\t\tcase \"vcs.revision\":\n\t\t\t\tcommitLen := min(len(s.Value), 10)\n\t\t\t\tdetails[commitKey] = s.Value[:commitLen]\n\t\t\tcase \"vcs.modified\":\n\t\t\t\tif s.Value == \"true\" {\n\t\t\t\t\tdetails[commitDirtyKey] = true\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor _, dep := range buildInfo.Deps {\n\t\t\tif dep.Path == mainK6Path {\n\t\t\t\tdetails[\"version\"] = dep.Version\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn details\n}\n\nfunc versionString() string {\n\tv := fullVersion()\n\n\tif exts := ext.GetAll(); len(exts) > 0 {\n\t\textsDesc := make([]string, 0, len(exts))\n\t\tfor _, e := range exts {\n\t\t\textsDesc = append(extsDesc, fmt.Sprintf(\"  %s\", e.String()))\n\t\t}\n\t\tv += fmt.Sprintf(\"\\nExtensions:\\n%s\\n\",\n\t\t\tstrings.Join(extsDesc, \"\\n\"))\n\t}\n\treturn v\n}\n\n// versionDetailsWithExtensions returns the structured details about version including extensions\n// returns error if there are unhandled extension types\nfunc versionDetailsWithExtensions(exts []*ext.Extension) (map[string]any, error) {\n\tdetails := versionDetails()\n\n\tif len(exts) == 0 {\n\t\treturn details, nil\n\t}\n\n\t// extInfo represents the JSON structure for an extension in the version details\n\t// modeled after k6 extension registry structure\n\ttype extInfo struct {\n\t\tModule  string   `json:\"module\"`\n\t\tVersion string   `json:\"version\"`\n\t\tImports []string `json:\"imports,omitempty\"`\n\t\tOutputs []string `json:\"outputs,omitempty\"`\n\t}\n\n\tinfoList := make([]*extInfo, 0, len(exts))\n\tinfoMap := make(map[string]*extInfo)\n\n\tfor _, e := range exts {\n\t\tkey := e.Path + \"@\" + e.Version\n\n\t\tinfo, found := infoMap[key]\n\t\tif !found {\n\t\t\tinfo = &extInfo{\n\t\t\t\tModule:  e.Path,\n\t\t\t\tVersion: e.Version,\n\t\t\t}\n\n\t\t\tinfoMap[key] = info\n\t\t\tinfoList = append(infoList, info)\n\t\t}\n\n\t\tswitch e.Type {\n\t\tcase ext.OutputExtension:\n\t\t\tinfo.Outputs = append(info.Outputs, e.Name)\n\t\tcase ext.JSExtension:\n\t\t\tinfo.Imports = append(info.Imports, e.Name)\n\t\tcase ext.SecretSourceExtension:\n\t\t\t// currently, no special handling is needed for secret source extensions\n\t\tcase ext.SubcommandExtension:\n\t\t\t// currently, no special handling is needed for subcommand extensions\n\t\tdefault:\n\t\t\t// report unhandled extension type for future proofing\n\t\t\treturn details, fmt.Errorf(\"unhandled extension type: %s\", e.Type)\n\t\t}\n\t}\n\n\tdetails[\"extensions\"] = infoList\n\n\treturn details, nil\n}\n\ntype versionCmd struct {\n\tgs     *state.GlobalState\n\tisJSON bool\n}\n\nfunc (c *versionCmd) run(cmd *cobra.Command, _ []string) error {\n\tif !c.isJSON {\n\t\troot := cmd.Root()\n\t\troot.SetArgs([]string{\"--version\"})\n\t\t_ = root.Execute()\n\t\treturn nil\n\t}\n\n\tdetails, err := versionDetailsWithExtensions(ext.GetAll())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get version details with extensions: %w\", err)\n\t}\n\n\tif err := json.NewEncoder(c.gs.Stdout).Encode(details); err != nil {\n\t\treturn fmt.Errorf(\"failed to encode/output version details: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc getCmdVersion(gs *state.GlobalState) *cobra.Command {\n\tversionCmd := &versionCmd{gs: gs}\n\n\tcmd := &cobra.Command{\n\t\tUse:    \"version\",\n\t\tShort:  \"Show application version\",\n\t\tLong:   `Show the application version and exit.`,\n\t\tHidden: true,\n\t\tRunE:   versionCmd.run,\n\t}\n\n\tcmd.Flags().BoolVar(&versionCmd.isJSON, \"json\", false, \"if set, output version information will be in JSON format\")\n\n\treturn cmd\n}\n"
  },
  {
    "path": "internal/cmd/version_test.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/cmd/tests\"\n)\n\nfunc TestVersionFlag(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\tts.ExpectedExitCode = 0\n\tts.CmdArgs = []string{\"k6\", \"--version\"}\n\n\tExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.NotEmpty(t, stdout)\n\n\t// Check that the version/format string is correct\n\tassert.Contains(t, stdout, \"k6 v\")\n\tassert.Contains(t, stdout, build.Version)\n\tassert.Contains(t, stdout, runtime.Version())\n\tassert.Contains(t, stdout, runtime.GOOS)\n\tassert.Contains(t, stdout, runtime.GOARCH)\n}\n\nfunc TestVersionSubCommand(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\tts.ExpectedExitCode = 0\n\tts.CmdArgs = []string{\"k6\", \"version\"}\n\n\tExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.NotEmpty(t, stdout)\n\n\t// Check that the version/format string is correct\n\tassert.Contains(t, stdout, \"k6 v\")\n\tassert.Contains(t, stdout, build.Version)\n\tassert.Contains(t, stdout, runtime.Version())\n\tassert.Contains(t, stdout, runtime.GOOS)\n\tassert.Contains(t, stdout, runtime.GOARCH)\n}\n\nfunc TestVersionJSONSubCommand(t *testing.T) {\n\tt.Parallel()\n\n\tts := tests.NewGlobalTestState(t)\n\tts.ExpectedExitCode = 0\n\tts.CmdArgs = []string{\"k6\", \"version\", \"--json\"}\n\n\tExecuteWithGlobalState(ts.GlobalState)\n\n\tstdout := ts.Stdout.String()\n\tt.Log(stdout)\n\tassert.NotEmpty(t, stdout)\n\n\t// try to unmarshal the JSON output\n\tvar details map[string]any\n\terr := json.Unmarshal([]byte(stdout), &details)\n\tassert.NoError(t, err)\n\n\t// Check that details are correct\n\tassert.Contains(t, details, \"version\")\n\tassert.Contains(t, details, \"go_version\")\n\tassert.Contains(t, details, \"go_os\")\n\tassert.Contains(t, details, \"go_arch\")\n\tassert.Equal(t, \"v\"+build.Version, details[\"version\"])\n\tassert.Equal(t, runtime.Version(), details[\"go_version\"])\n\tassert.Equal(t, runtime.GOOS, details[\"go_os\"])\n\tassert.Equal(t, runtime.GOARCH, details[\"go_arch\"])\n\tassert.Equal(t, \"devel\", details[commitKey])\n}\n\nfunc TestVersionDetailsWithExtensions(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname        string\n\t\texts        []*ext.Extension\n\t\texpected    func(t *testing.T, details map[string]any)\n\t\texpectError bool\n\t}{\n\t\t{\n\t\t\tname: \"no extensions\",\n\t\t\texts: []*ext.Extension{},\n\t\t\texpected: func(t *testing.T, details map[string]any) {\n\t\t\t\trequire.NotContains(t, details, \"extensions\")\n\t\t\t\trequire.Contains(t, details, \"version\")\n\t\t\t\trequire.Contains(t, details, \"go_version\")\n\t\t\t\trequire.Contains(t, details, \"go_os\")\n\t\t\t\trequire.Contains(t, details, \"go_arch\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single js extension\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/test\",\n\t\t\t\t\tPath:    \"github.com/grafana/xk6-test\",\n\t\t\t\t\tVersion: \"v0.1.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(t *testing.T, details map[string]any) {\n\t\t\t\trequire.Contains(t, details, \"extensions\")\n\t\t\t\textListRaw, ok := details[\"extensions\"].([]any)\n\t\t\t\trequire.True(t, ok, \"extensions should be a slice\")\n\t\t\t\trequire.Len(t, extListRaw, 1)\n\n\t\t\t\textMap := extListRaw[0].(map[string]any)\n\t\t\t\trequire.Equal(t, \"github.com/grafana/xk6-test\", extMap[\"module\"])\n\t\t\t\trequire.Equal(t, \"v0.1.0\", extMap[\"version\"])\n\t\t\t\trequire.Equal(t, []any{\"k6/x/test\"}, extMap[\"imports\"])\n\t\t\t\trequire.Nil(t, extMap[\"outputs\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"single output extension\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"prometheus\",\n\t\t\t\t\tPath:    \"github.com/grafana/xk6-output-prometheus\",\n\t\t\t\t\tVersion: \"v0.2.0\",\n\t\t\t\t\tType:    ext.OutputExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(t *testing.T, details map[string]any) {\n\t\t\t\trequire.Contains(t, details, \"extensions\")\n\t\t\t\textListRaw, ok := details[\"extensions\"].([]any)\n\t\t\t\trequire.True(t, ok, \"extensions should be a slice\")\n\t\t\t\trequire.Len(t, extListRaw, 1)\n\n\t\t\t\textMap := extListRaw[0].(map[string]any)\n\t\t\t\trequire.Equal(t, \"github.com/grafana/xk6-output-prometheus\", extMap[\"module\"])\n\t\t\t\trequire.Equal(t, \"v0.2.0\", extMap[\"version\"])\n\t\t\t\trequire.Equal(t, []any{\"prometheus\"}, extMap[\"outputs\"])\n\t\t\t\trequire.Nil(t, extMap[\"imports\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"multiple extensions from same module\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/sql\",\n\t\t\t\t\tPath:    \"github.com/grafana/xk6-sql\",\n\t\t\t\t\tVersion: \"v0.3.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/sql/driver/mysql\",\n\t\t\t\t\tPath:    \"github.com/grafana/xk6-sql\",\n\t\t\t\t\tVersion: \"v0.3.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(t *testing.T, details map[string]any) {\n\t\t\t\trequire.Contains(t, details, \"extensions\")\n\t\t\t\textListRaw, ok := details[\"extensions\"].([]any)\n\t\t\t\trequire.True(t, ok, \"extensions should be a slice\")\n\t\t\t\trequire.Len(t, extListRaw, 1, \"should consolidate extensions from same module@version\")\n\n\t\t\t\textMap := extListRaw[0].(map[string]any)\n\t\t\t\trequire.Equal(t, \"github.com/grafana/xk6-sql\", extMap[\"module\"])\n\t\t\t\trequire.Equal(t, \"v0.3.0\", extMap[\"version\"])\n\t\t\t\timports := extMap[\"imports\"].([]any)\n\t\t\t\trequire.Len(t, imports, 2)\n\t\t\t\trequire.Contains(t, imports, \"k6/x/sql\")\n\t\t\t\trequire.Contains(t, imports, \"k6/x/sql/driver/mysql\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"mixed extension types from same module\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/dashboard\",\n\t\t\t\t\tPath:    \"github.com/grafana/xk6-dashboard\",\n\t\t\t\t\tVersion: \"v0.4.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"dashboard\",\n\t\t\t\t\tPath:    \"github.com/grafana/xk6-dashboard\",\n\t\t\t\t\tVersion: \"v0.4.0\",\n\t\t\t\t\tType:    ext.OutputExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(t *testing.T, details map[string]any) {\n\t\t\t\trequire.Contains(t, details, \"extensions\")\n\t\t\t\textListRaw, ok := details[\"extensions\"].([]any)\n\t\t\t\trequire.True(t, ok, \"extensions should be a slice\")\n\t\t\t\trequire.Len(t, extListRaw, 1, \"should consolidate extensions from same module@version\")\n\n\t\t\t\textMap := extListRaw[0].(map[string]any)\n\t\t\t\trequire.Equal(t, \"github.com/grafana/xk6-dashboard\", extMap[\"module\"])\n\t\t\t\trequire.Equal(t, \"v0.4.0\", extMap[\"version\"])\n\t\t\t\trequire.Equal(t, []any{\"k6/x/dashboard\"}, extMap[\"imports\"])\n\t\t\t\trequire.Equal(t, []any{\"dashboard\"}, extMap[\"outputs\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"multiple different extensions\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/test1\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-test1\",\n\t\t\t\t\tVersion: \"v1.0.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"output1\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-output1\",\n\t\t\t\t\tVersion: \"v2.0.0\",\n\t\t\t\t\tType:    ext.OutputExtension,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/test2\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-test2\",\n\t\t\t\t\tVersion: \"v3.0.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(t *testing.T, details map[string]any) {\n\t\t\t\trequire.Contains(t, details, \"extensions\")\n\t\t\t\textListRaw, ok := details[\"extensions\"].([]any)\n\t\t\t\trequire.True(t, ok, \"extensions should be a slice\")\n\t\t\t\trequire.Len(t, extListRaw, 3)\n\n\t\t\t\t// Verify all extensions are present\n\t\t\t\tmodules := make(map[string]bool)\n\t\t\t\tfor _, extRaw := range extListRaw {\n\t\t\t\t\textMap := extRaw.(map[string]any)\n\t\t\t\t\tmodules[extMap[\"module\"].(string)] = true\n\t\t\t\t}\n\t\t\t\trequire.True(t, modules[\"github.com/example/xk6-test1\"])\n\t\t\t\trequire.True(t, modules[\"github.com/example/xk6-output1\"])\n\t\t\t\trequire.True(t, modules[\"github.com/example/xk6-test2\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"same module different versions\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/test\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-test\",\n\t\t\t\t\tVersion: \"v1.0.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/test/v2\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-test\",\n\t\t\t\t\tVersion: \"v2.0.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(t *testing.T, details map[string]any) {\n\t\t\t\trequire.Contains(t, details, \"extensions\")\n\t\t\t\textListRaw, ok := details[\"extensions\"].([]any)\n\t\t\t\trequire.True(t, ok, \"extensions should be a slice\")\n\t\t\t\trequire.Len(t, extListRaw, 2, \"different versions should create separate entries\")\n\n\t\t\t\t// Verify both versions are present\n\t\t\t\tversions := make(map[string]bool)\n\t\t\t\tfor _, extRaw := range extListRaw {\n\t\t\t\t\textMap := extRaw.(map[string]any)\n\t\t\t\t\trequire.Equal(t, \"github.com/example/xk6-test\", extMap[\"module\"])\n\t\t\t\t\tversions[extMap[\"version\"].(string)] = true\n\t\t\t\t}\n\t\t\t\trequire.True(t, versions[\"v1.0.0\"])\n\t\t\t\trequire.True(t, versions[\"v2.0.0\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"unhandled extension type\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"unknown\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-unknown\",\n\t\t\t\t\tVersion: \"v1.0.0\",\n\t\t\t\t\tType:    100, // Unknown/unhandled type\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(_ *testing.T, _ map[string]any) {\n\t\t\t\t// Should not be called when expectError is true\n\t\t\t},\n\t\t\texpectError: true,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed handled and unhandled extensions\",\n\t\t\texts: []*ext.Extension{\n\t\t\t\t{\n\t\t\t\t\tName:    \"k6/x/test\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-test\",\n\t\t\t\t\tVersion: \"v1.0.0\",\n\t\t\t\t\tType:    ext.JSExtension,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"unknown\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-unknown\",\n\t\t\t\t\tVersion: \"v1.0.0\",\n\t\t\t\t\tType:    100, // Unknown/unhandled type\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"output1\",\n\t\t\t\t\tPath:    \"github.com/example/xk6-output1\",\n\t\t\t\t\tVersion: \"v2.0.0\",\n\t\t\t\t\tType:    ext.OutputExtension,\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: func(_ *testing.T, _ map[string]any) {\n\t\t\t\t// Should not be called when expectError is true\n\t\t\t},\n\t\t\texpectError: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tdetails, err := versionDetailsWithExtensions(tt.exts)\n\n\t\t\tif tt.expectError {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), \"unhandled extension type\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// Convert to map[string]any for easier testing\n\t\t\t// (the actual function returns this type but nested structures need conversion)\n\t\t\tjsonBytes, jsonErr := json.Marshal(details)\n\t\t\trequire.NoError(t, jsonErr)\n\n\t\t\tvar result map[string]any\n\t\t\tjsonErr = json.Unmarshal(jsonBytes, &result)\n\t\t\trequire.NoError(t, jsonErr)\n\n\t\t\ttt.expected(t, result)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/ds/histogram/doc.go",
    "content": "// Package histogram provides histogram implementations that are used to track the distribution of metrics.\npackage histogram\n"
  },
  {
    "path": "internal/ds/histogram/hdr.go",
    "content": "package histogram\n\nimport (\n\t\"math\"\n\t\"math/bits\"\n)\n\nconst (\n\t// defaultMinimumResolution is the default resolution used by Hdr.\n\t// It allows to have a higher granularity compared to the basic 1.0 value,\n\t// supporting floating points up to 3 digits.\n\tdefaultMinimumResolution = .001\n\n\t// lowestTrackable represents the minimum value that the Hdr tracks.\n\t// Essentially, it excludes negative numbers.\n\t// Most of the metrics tracked by histograms are durations\n\t// where we don't expect negative numbers.\n\tlowestTrackable = 0\n)\n\n// Hdr represents a distribution of metrics samples' values as histogram.\n//\n// A Hdr is the representation of base-2 exponential histogram with two layers.\n// The first layer has primary buckets in the form of a power of two, and a second layer of buckets\n// for each primary bucket with an equally distributed amount of buckets inside.\n//\n// Hdr has a series of (N * 2^m) buckets, where:\n// N = a power of 2 that defines the number of primary buckets\n// m = a power of 2 that defines the number of the secondary buckets\n// The current version is: f(N = 25, m = 7) = 3200.\ntype Hdr struct {\n\t// Buckets stores the counters for each bin of the histogram.\n\t// It does not include counters for the untrackable values,\n\t// because they contain exception cases and require to be tracked in a dedicated way.\n\tBuckets map[uint32]uint32\n\n\t// ExtraLowBucket counts occurrences of observed values smaller\n\t// than the minimum trackable value.\n\tExtraLowBucket uint32\n\n\t// ExtraHighBucket counts occurrences of observed values bigger\n\t// than the maximum trackable value.\n\tExtraHighBucket uint32\n\n\t// Max is the absolute observed maximum value.\n\tMax float64\n\n\t// Min is the absolute observed minimum value.\n\tMin float64\n\n\t// Sum is the sum of all observed values.\n\tSum float64\n\n\t// Count is counts the amount of observed values.\n\tCount uint32\n\n\t// MinimumResolution represents resolution used by Hdr.\n\t// In principle, it is a multiplier factor for the tracked values.\n\tMinimumResolution float64\n}\n\n// NewHdr creates a new Hdr histogram with default settings.\nfunc NewHdr() *Hdr {\n\treturn &Hdr{\n\t\tMinimumResolution: defaultMinimumResolution,\n\t\tBuckets:           make(map[uint32]uint32),\n\t\tMax:               -math.MaxFloat64,\n\t\tMin:               math.MaxFloat64,\n\t}\n}\n\n// Add adds a value to the Hdr histogram.\nfunc (h *Hdr) Add(v float64) {\n\th.addToBucket(v)\n}\n\n// addToBucket increments the counter of the bucket of the provided value.\n// If the value is lower or higher than the trackable limits\n// then it is counted into specific buckets. All the stats are also updated accordingly.\nfunc (h *Hdr) addToBucket(v float64) {\n\tif v > h.Max {\n\t\th.Max = v\n\t}\n\tif v < h.Min {\n\t\th.Min = v\n\t}\n\n\th.Count++\n\th.Sum += v\n\n\tv /= h.MinimumResolution\n\n\tif v < lowestTrackable {\n\t\th.ExtraLowBucket++\n\t\treturn\n\t}\n\tif v > math.MaxInt64 {\n\t\th.ExtraHighBucket++\n\t\treturn\n\t}\n\n\th.Buckets[resolveBucketIndex(v)]++\n}\n\n// resolveBucketIndex returns the index\n// of the bucket in the histogram for the provided value.\nfunc resolveBucketIndex(val float64) uint32 {\n\tif val < lowestTrackable {\n\t\treturn 0\n\t}\n\n\t// We upscale to the next integer to ensure that each sample falls\n\t// within a specific bucket, even when the value is fractional.\n\t// This avoids under-representing the distribution in the Hdr histogram.\n\tupscaled := uint64(math.Ceil(val))\n\n\t// In Hdr histograms, bucket boundaries are usually defined as multiples of powers of 2,\n\t// allowing for efficient computation of bucket indexes.\n\t//\n\t// We define k=7 in our case, because it allows for sufficient granularity in the\n\t// distribution (2^7=128 primary buckets of which each can be further\n\t// subdivided if needed).\n\t//\n\t// k is the constant balancing factor between granularity and\n\t// computational efficiency.\n\t//\n\t// In our case:\n\t// i.e 2^7  = 128  ~  100 = 10^2\n\t//     2^10 = 1024 ~ 1000 = 10^3\n\t// f(x) = 3*x + 1 - empiric formula that works for us\n\t// since f(2)=7 and f(3)=10\n\tconst k = uint64(7)\n\n\t// 256 = 1 << (k+1)\n\tif upscaled < 256 {\n\t\treturn uint32(upscaled)\n\t}\n\n\t// `nkdiff` helps us find the right bucket for `upscaled`. It does so by determining the\n\t// index for the \"major\" bucket (a set of values within a power of two range) and then\n\t// the \"sub\" bucket within that major bucket. This system provides us with a fine level\n\t// of granularity within a computationally efficient bucketing system. The result is a\n\t// histogram that provides a detailed representation of the distribution of values.\n\t//\n\t// Here we use some math to get simple formula\n\t// derivation:\n\t// let u = upscaled\n\t// let n = msb(u) - most significant digit position\n\t// i.e. n = floor(log(u, 2))\n\t//   major_bucket_index = n - k + 1\n\t//   sub_bucket_index = u>>(n - k) - (1<<k)\n\t//   bucket = major_bucket_index << k + sub_bucket_index =\n\t//          = (n-k+1)<<k + u>>(n-k) - (1<<k) =\n\t//          = (n-k)<<k + u>>(n-k)\n\t//\n\tnkdiff := uint64(bits.Len64(upscaled>>k)) - 1 //nolint:gosec // msb index\n\n\t// We cast safely downscaling because we don't expect we may hit the uint32 limit\n\t// with the bucket index. The bucket represented from the index as MaxUint32\n\t// would be a very huge number bigger than the trackable limits.\n\treturn uint32((nkdiff << k) + (upscaled >> nkdiff)) //nolint:gosec\n}\n"
  },
  {
    "path": "internal/ds/histogram/hdr_test.go",
    "content": "package histogram\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestResolveBucketIndex(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tin  float64\n\t\texp uint32\n\t}{\n\t\t{in: -1029, exp: 0},\n\t\t{in: -12, exp: 0},\n\t\t{in: -0.82673, exp: 0},\n\t\t{in: 0, exp: 0},\n\t\t{in: 0.12, exp: 1},\n\t\t{in: 1.91, exp: 2},\n\t\t{in: 10, exp: 10},\n\t\t{in: 12, exp: 12},\n\t\t{in: 12.5, exp: 13},\n\t\t{in: 20, exp: 20},\n\t\t{in: 255, exp: 255},\n\t\t{in: 256, exp: 256},\n\t\t{in: 282.29, exp: 269},\n\t\t{in: 1029, exp: 512},\n\t\t{in: 39751, exp: 1179},\n\t\t{in: 100000, exp: 1347},\n\t\t{in: 182272, exp: 1458},\n\t\t{in: 183000, exp: 1458},\n\t\t{in: 184000, exp: 1459},\n\t\t{in: 200000, exp: 1475},\n\n\t\t{in: 1 << 20, exp: 1792},\n\t\t{in: (1 << 30) - 1, exp: 3071},\n\t\t{in: 1 << 30, exp: 3072},\n\t\t{in: 1 << 40, exp: 4352},\n\t\t{in: 1 << 62, exp: 7168},\n\n\t\t{in: math.MaxInt32, exp: 3199},        // 2B\n\t\t{in: math.MaxUint32, exp: 3327},       // 4B\n\t\t{in: math.MaxInt64, exp: 7296},        // Huge number // 9.22...e+18\n\t\t{in: math.MaxInt64 + 2000, exp: 7296}, // Assert that it does not overflow\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, int(tc.exp), int(resolveBucketIndex(tc.in)), tc.in)\n\t}\n}\n\nfunc TestHistogramAddWithSimpleValues(t *testing.T) {\n\tt.Parallel()\n\n\tcases := []struct {\n\t\tvals []float64\n\t\texp  *Hdr\n\t}{\n\t\t{\n\t\t\tvals: []float64{0},\n\t\t\texp: &Hdr{\n\t\t\t\tBuckets:         map[uint32]uint32{0: 1},\n\t\t\t\tExtraLowBucket:  0,\n\t\t\t\tExtraHighBucket: 0,\n\t\t\t\tMax:             0,\n\t\t\t\tMin:             0,\n\t\t\t\tSum:             0,\n\t\t\t\tCount:           1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tvals: []float64{8, 5},\n\t\t\texp: &Hdr{\n\t\t\t\tBuckets:         map[uint32]uint32{5: 1, 8: 1},\n\t\t\t\tExtraLowBucket:  0,\n\t\t\t\tExtraHighBucket: 0,\n\t\t\t\tMax:             8,\n\t\t\t\tMin:             5,\n\t\t\t\tSum:             13,\n\t\t\t\tCount:           2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tvals: []float64{8, 9, 10, 5},\n\t\t\texp: &Hdr{\n\t\t\t\tBuckets:         map[uint32]uint32{8: 1, 9: 1, 10: 1, 5: 1},\n\t\t\t\tExtraLowBucket:  0,\n\t\t\t\tExtraHighBucket: 0,\n\t\t\t\tMax:             10,\n\t\t\t\tMin:             5,\n\t\t\t\tSum:             32,\n\t\t\t\tCount:           4,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tvals: []float64{100, 101},\n\t\t\texp: &Hdr{\n\t\t\t\tBuckets:         map[uint32]uint32{100: 1, 101: 1},\n\t\t\t\tExtraLowBucket:  0,\n\t\t\t\tExtraHighBucket: 0,\n\t\t\t\tMax:             101,\n\t\t\t\tMin:             100,\n\t\t\t\tSum:             201,\n\t\t\t\tCount:           2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tvals: []float64{101, 100},\n\t\t\texp: &Hdr{\n\t\t\t\tBuckets:         map[uint32]uint32{100: 1, 101: 1},\n\t\t\t\tExtraLowBucket:  0,\n\t\t\t\tExtraHighBucket: 0,\n\t\t\t\tMax:             101,\n\t\t\t\tMin:             100,\n\t\t\t\tSum:             201,\n\t\t\t\tCount:           2,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor i, tc := range cases {\n\t\tt.Run(strconv.Itoa(i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\th := NewHdr()\n\t\t\t// We use a lower resolution instead of the default\n\t\t\t// so we can keep smaller numbers in this test\n\t\t\th.MinimumResolution = 1.0\n\t\t\tfor _, v := range tc.vals {\n\t\t\t\th.Add(v)\n\t\t\t}\n\t\t\ttc.exp.MinimumResolution = 1.0\n\t\t\tassert.Equal(t, tc.exp, h)\n\t\t})\n\t}\n}\n\nfunc TestHistogramAddWithUntrackables(t *testing.T) {\n\tt.Parallel()\n\n\th := NewHdr()\n\th.MinimumResolution = 1.0\n\tfor _, v := range []float64{5, -3.14, math.MaxInt64 + 3239, 1} {\n\t\th.Add(v)\n\t}\n\n\texp := &Hdr{\n\t\tBuckets:           map[uint32]uint32{1: 1, 5: 1},\n\t\tExtraLowBucket:    1,\n\t\tExtraHighBucket:   1,\n\t\tMax:               9223372036854779046,\n\t\tMin:               -3.14,\n\t\tSum:               math.MaxInt64 + 3239 + 5 + 1 - 3.14,\n\t\tCount:             4,\n\t\tMinimumResolution: 1.0,\n\t}\n\tassert.Equal(t, exp, h)\n}\n\nfunc TestHistogramAddWithMultipleOccurances(t *testing.T) {\n\tt.Parallel()\n\n\th := NewHdr()\n\th.MinimumResolution = 1.0\n\tfor _, v := range []float64{51.8, 103.6, 103.6, 103.6, 103.6} {\n\t\th.Add(v)\n\t}\n\n\texp := &Hdr{\n\t\tBuckets:         map[uint32]uint32{52: 1, 104: 4},\n\t\tMax:             103.6,\n\t\tMin:             51.8,\n\t\tExtraLowBucket:  0,\n\t\tExtraHighBucket: 0,\n\t\tSum:             466.20000000000005,\n\t\tCount:           5,\n\t}\n\texp.MinimumResolution = 1.0\n\tassert.Equal(t, exp, h)\n}\n\nfunc TestHistogramAddWithNegativeNum(t *testing.T) {\n\tt.Parallel()\n\n\th := NewHdr()\n\th.Add(-2.42314)\n\n\texp := &Hdr{\n\t\tMax:               -2.42314,\n\t\tMin:               -2.42314,\n\t\tBuckets:           map[uint32]uint32{},\n\t\tExtraLowBucket:    1,\n\t\tExtraHighBucket:   0,\n\t\tSum:               -2.42314,\n\t\tCount:             1,\n\t\tMinimumResolution: .001,\n\t}\n\tassert.Equal(t, exp, h)\n}\n\nfunc TestHistogramAddWithMultipleNegativeNums(t *testing.T) {\n\tt.Parallel()\n\th := NewHdr()\n\tfor _, v := range []float64{-0.001, -0.001, -0.001} {\n\t\th.Add(v)\n\t}\n\n\texp := &Hdr{\n\t\tBuckets:           map[uint32]uint32{},\n\t\tExtraLowBucket:    3,\n\t\tExtraHighBucket:   0,\n\t\tMax:               -0.001,\n\t\tMin:               -0.001,\n\t\tSum:               -0.003,\n\t\tCount:             3,\n\t\tMinimumResolution: .001,\n\t}\n\tassert.Equal(t, exp, h)\n}\n\nfunc TestHistogramAddWithZeroToOneValues(t *testing.T) {\n\tt.Parallel()\n\th := NewHdr()\n\tfor _, v := range []float64{0.000052, 0.002115, 0.012013, 0.05017, 0.250, 0.54, 0.541, 0.803} {\n\t\th.Add(v)\n\t}\n\n\texp := &Hdr{\n\t\tBuckets:           map[uint32]uint32{1: 1, 3: 1, 13: 1, 51: 1, 250: 1, 391: 2, 456: 1},\n\t\tExtraLowBucket:    0,\n\t\tExtraHighBucket:   0,\n\t\tMax:               .803,\n\t\tMin:               .000052,\n\t\tSum:               2.19835,\n\t\tCount:             8,\n\t\tMinimumResolution: .001,\n\t}\n\tassert.Equal(t, exp, h)\n}\n\nfunc TestNewHistogram(t *testing.T) {\n\tt.Parallel()\n\n\th := NewHdr()\n\texp := &Hdr{\n\t\tBuckets:           map[uint32]uint32{},\n\t\tExtraLowBucket:    0,\n\t\tExtraHighBucket:   0,\n\t\tMax:               -math.MaxFloat64,\n\t\tMin:               math.MaxFloat64,\n\t\tSum:               0,\n\t\tMinimumResolution: .001,\n\t}\n\tassert.Equal(t, exp, h)\n}\n"
  },
  {
    "path": "internal/event/doc.go",
    "content": "// Package event contains the event system used to notify external components of\n// various internal events during test execution.\npackage event\n"
  },
  {
    "path": "internal/event/event.go",
    "content": "package event\n\n// Event is the emitted object sent to all subscribers of its type.\n// The subscriber should call its Done method when finished processing\n// to notify the emitter, though this is not required for all events.\ntype Event struct {\n\tType Type\n\tData any\n\tDone func()\n}\n"
  },
  {
    "path": "internal/event/system.go",
    "content": "package event\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// Subscriber is a limited interface of System that only allows subscribing and\n// unsubscribing.\ntype Subscriber interface {\n\tSubscribe(events ...Type) (subID uint64, eventsCh <-chan *Event)\n\tUnsubscribe(subID uint64)\n}\n\n// System keeps track of subscribers, and allows subscribing to and emitting\n// events.\ntype System struct {\n\tsubMx       sync.RWMutex\n\tsubIDCount  uint64\n\tsubscribers map[Type]map[uint64]chan *Event\n\teventBuffer int\n\tlogger      logrus.FieldLogger\n}\n\n// NewEventSystem returns a new System.\n// eventBuffer determines the size of the Event channel buffer. Events might be\n// dropped if this buffer is full and there are no event listeners, or if events\n// are emitted very quickly and the event handler goroutine is busy. It is\n// recommended to handle events in a separate goroutine to not block the\n// listener goroutine.\nfunc NewEventSystem(eventBuffer int, logger logrus.FieldLogger) *System {\n\treturn &System{\n\t\tsubscribers: make(map[Type]map[uint64]chan *Event),\n\t\teventBuffer: eventBuffer,\n\t\tlogger:      logger,\n\t}\n}\n\n// Subscribe to one or more events. It returns a subscriber ID that can be\n// used to unsubscribe, and an Event channel to receive events.\n// It panics if events is empty.\nfunc (s *System) Subscribe(events ...Type) (subID uint64, eventsCh <-chan *Event) {\n\tif len(events) == 0 {\n\t\tpanic(\"must subscribe to at least 1 event type\")\n\t}\n\n\ts.subMx.Lock()\n\tdefer s.subMx.Unlock()\n\ts.subIDCount++\n\tsubID = s.subIDCount\n\n\tevtCh := make(chan *Event, s.eventBuffer)\n\tfor _, evt := range events {\n\t\tif s.subscribers[evt] == nil {\n\t\t\ts.subscribers[evt] = make(map[uint64]chan *Event)\n\t\t}\n\t\ts.subscribers[evt][subID] = evtCh\n\t}\n\n\ts.logger.WithFields(logrus.Fields{\n\t\t\"subscriptionID\": subID,\n\t\t\"events\":         events,\n\t}).Debug(\"Created event subscription\")\n\n\treturn subID, evtCh\n}\n\n// Emit the event to all subscribers of its type.\n// It returns a function that can be optionally used to wait for all subscribers\n// to process the event (by signalling via the Done method).\nfunc (s *System) Emit(event *Event) (wait func(context.Context) error) {\n\ts.subMx.RLock()\n\tdefer s.subMx.RUnlock()\n\ttotalSubs := len(s.subscribers[event.Type])\n\tif totalSubs == 0 {\n\t\treturn func(context.Context) error { return nil }\n\t}\n\n\tif event.Done == nil {\n\t\tevent.Done = func() {}\n\t}\n\torigDoneFn := event.Done\n\tdoneCh := make(chan struct{}, s.eventBuffer)\n\tdoneFn := func() {\n\t\torigDoneFn()\n\t\t// The done must be read by the reading side to prevent\n\t\t// a goroutine that waits indefinitely.\n\t\tdoneCh <- struct{}{}\n\t}\n\tevent.Done = doneFn\n\n\tfor _, evtCh := range s.subscribers[event.Type] {\n\t\t// The event channel must read off the channel otherwise we would\n\t\t// be dropping events.\n\t\tevtCh <- event\n\t}\n\n\ts.logger.WithFields(logrus.Fields{\n\t\t\"subscribers\": totalSubs,\n\t\t\"event\":       event.Type,\n\t}).Trace(\"Emitted event\")\n\n\treturn func(ctx context.Context) error {\n\t\tvar doneCount int\n\t\tfor {\n\t\t\tif doneCount == totalSubs {\n\t\t\t\tclose(doneCh)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase <-doneCh:\n\t\t\t\tdoneCount++\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn fmt.Errorf(\"context is done before all '%s' events were processed\", event.Type)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Unsubscribe closes the Event channel and removes the subscription with ID\n// subID.\nfunc (s *System) Unsubscribe(subID uint64) {\n\ts.subMx.Lock()\n\tdefer s.subMx.Unlock()\n\tvar seen bool\n\tfor _, sub := range s.subscribers {\n\t\tif evtCh, ok := sub[subID]; ok {\n\t\t\tif !seen {\n\t\t\t\tclose(evtCh)\n\t\t\t}\n\t\t\tdelete(sub, subID)\n\t\t\tseen = true\n\t\t}\n\t}\n\n\tif seen {\n\t\ts.logger.WithFields(logrus.Fields{\n\t\t\t\"subscriptionID\": subID,\n\t\t}).Debug(\"Removed event subscription\")\n\t}\n}\n\n// UnsubscribeAll closes all event channels and removes all subscriptions.\nfunc (s *System) UnsubscribeAll() {\n\ts.subMx.Lock()\n\tdefer s.subMx.Unlock()\n\n\tseenSubs := make(map[uint64]struct{})\n\tfor _, sub := range s.subscribers {\n\t\tfor subID, evtCh := range sub {\n\t\t\tif _, ok := seenSubs[subID]; !ok {\n\t\t\t\tclose(evtCh)\n\t\t\t\tseenSubs[subID] = struct{}{}\n\t\t\t}\n\t\t}\n\t}\n\n\tif len(seenSubs) > 0 {\n\t\ts.logger.WithFields(logrus.Fields{\n\t\t\t\"subscriptions\": len(seenSubs),\n\t\t}).Debug(\"Removed all event subscriptions\")\n\t}\n\n\ts.subscribers = make(map[Type]map[uint64]chan *Event)\n}\n"
  },
  {
    "path": "internal/event/system_test.go",
    "content": "package event\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEventSystem(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"subscribe\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tlogger := logrus.New()\n\t\tlogger.SetOutput(io.Discard)\n\t\tes := NewEventSystem(10, logger)\n\n\t\trequire.Len(t, es.subscribers, 0)\n\n\t\ts1id, s1ch := es.Subscribe(Init)\n\n\t\tassert.Equal(t, uint64(1), s1id)\n\t\tassert.NotNil(t, s1ch)\n\t\tassert.Len(t, es.subscribers, 1)\n\t\tassert.Len(t, es.subscribers[Init], 1)\n\t\tassert.Equal(t, (<-chan *Event)(es.subscribers[Init][s1id]), s1ch)\n\n\t\ts2id, s2ch := es.Subscribe(Init, TestStart)\n\n\t\tassert.Equal(t, uint64(2), s2id)\n\t\tassert.NotNil(t, s2ch)\n\t\tassert.Len(t, es.subscribers, 2)\n\t\tassert.Len(t, es.subscribers[Init], 2)\n\t\tassert.Len(t, es.subscribers[TestStart], 1)\n\t\tassert.Equal(t, (<-chan *Event)(es.subscribers[Init][s2id]), s2ch)\n\t\tassert.Equal(t, (<-chan *Event)(es.subscribers[TestStart][s2id]), s2ch)\n\t})\n\n\tt.Run(\"subscribe/panic\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tlogger := logrus.New()\n\t\tlogger.SetOutput(io.Discard)\n\t\tes := NewEventSystem(10, logger)\n\t\tassert.PanicsWithValue(t, \"must subscribe to at least 1 event type\", func() {\n\t\t\tes.Subscribe()\n\t\t})\n\t})\n\n\tt.Run(\"emit_and_process\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestTimeout := 5 * time.Second\n\t\tctx, cancel := context.WithTimeout(context.Background(), testTimeout)\n\t\tdefer cancel()\n\t\tlogger := logrus.New()\n\t\tlogger.SetOutput(io.Discard)\n\t\tes := NewEventSystem(10, logger)\n\n\t\ts1id, s1ch := es.Subscribe(Init, Exit)\n\t\ts2id, s2ch := es.Subscribe(Init, TestStart, TestEnd, Exit)\n\n\t\ttype result struct {\n\t\t\tsid    uint64\n\t\t\tevents []*Event\n\t\t\terr    error\n\t\t}\n\t\tresultCh := make(chan result, 2)\n\t\tgo func() {\n\t\t\ts1result, err := processEvents(ctx, es, s1id, s1ch)\n\t\t\tresultCh <- result{s1id, s1result, err}\n\t\t}()\n\n\t\tgo func() {\n\t\t\ts2result, err := processEvents(ctx, es, s2id, s2ch)\n\t\t\tresultCh <- result{s2id, s2result, err}\n\t\t}()\n\n\t\tvar (\n\t\t\tdoneMx     sync.RWMutex\n\t\t\tprocessed  = make(map[Type]int)\n\t\t\temitEvents = []Type{Init, TestStart, IterStart, IterEnd, TestEnd, Exit}\n\t\t\tdata       int\n\t\t)\n\t\tfor _, et := range emitEvents {\n\t\t\tevt := &Event{Type: et, Data: data, Done: func() {\n\t\t\t\tdoneMx.Lock()\n\t\t\t\tprocessed[et]++\n\t\t\t\tdoneMx.Unlock()\n\t\t\t}}\n\t\t\tes.Emit(evt)\n\t\t\tdata++\n\t\t}\n\n\t\tfor range 2 {\n\t\t\tselect {\n\t\t\tcase result := <-resultCh:\n\t\t\t\trequire.NoError(t, result.err)\n\t\t\t\tswitch result.sid {\n\t\t\t\tcase s1id:\n\t\t\t\t\trequire.Len(t, result.events, 2)\n\t\t\t\t\tassert.Equal(t, Init, result.events[0].Type)\n\t\t\t\t\tassert.Equal(t, 0, result.events[0].Data)\n\t\t\t\t\tassert.Equal(t, Exit, result.events[1].Type)\n\t\t\t\t\tassert.Equal(t, 5, result.events[1].Data)\n\t\t\t\tcase s2id:\n\t\t\t\t\trequire.Len(t, result.events, 4)\n\t\t\t\t\tassert.Equal(t, Init, result.events[0].Type)\n\t\t\t\t\tassert.Equal(t, 0, result.events[0].Data)\n\t\t\t\t\tassert.Equal(t, TestStart, result.events[1].Type)\n\t\t\t\t\tassert.Equal(t, 1, result.events[1].Data)\n\t\t\t\t\tassert.Equal(t, TestEnd, result.events[2].Type)\n\t\t\t\t\tassert.Equal(t, 4, result.events[2].Data)\n\t\t\t\t\tassert.Equal(t, Exit, result.events[3].Type)\n\t\t\t\t\tassert.Equal(t, 5, result.events[3].Data)\n\t\t\t\t}\n\t\t\tcase <-ctx.Done():\n\t\t\t\tt.Fatalf(\"test timed out after %s\", testTimeout)\n\t\t\t}\n\t\t}\n\n\t\texpProcessed := map[Type]int{\n\t\t\tInit:      2,\n\t\t\tTestStart: 1,\n\t\t\tTestEnd:   1,\n\t\t\tExit:      2,\n\t\t}\n\t\tassert.Equal(t, expProcessed, processed)\n\t})\n\n\tt.Run(\"emit_and_wait/ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\t\tlogger := logrus.New()\n\t\tlogger.SetOutput(io.Discard)\n\t\tes := NewEventSystem(100, logger)\n\n\t\tvar (\n\t\t\twg      sync.WaitGroup\n\t\t\tnumSubs = 100\n\t\t)\n\t\tfor range numSubs {\n\t\t\tsid, evtCh := es.Subscribe(Exit)\n\t\t\twg.Go(func() {\n\t\t\t\t_, err := processEvents(ctx, es, sid, evtCh)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t}\n\n\t\tvar done uint32\n\t\twait := es.Emit(&Event{Type: Exit, Done: func() {\n\t\t\tatomic.AddUint32(&done, 1)\n\t\t}})\n\t\twaitCtx, waitCancel := context.WithTimeout(ctx, time.Second)\n\t\tdefer waitCancel()\n\t\terr := wait(waitCtx)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, uint32(numSubs), done)\n\n\t\twg.Wait()\n\t})\n\n\t// This ensures that the system still works even when the buffer size of\n\t// the event system is smaller than the numSubs. We had an issue where\n\t// when all the sub were trying to call done it would fail since the buffer\n\t// was full and the event would never fully complete and wait indefinitely.\n\tt.Run(\"emit_and_wait/buffer\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\t\tlogger := logrus.New()\n\t\tlogger.SetOutput(io.Discard)\n\t\t// Not buffered\n\t\tes := NewEventSystem(0, logger)\n\n\t\tvar (\n\t\t\twg      sync.WaitGroup\n\t\t\tnumSubs = 100\n\t\t)\n\t\tfor range numSubs {\n\t\t\tsid, evtCh := es.Subscribe(Exit)\n\t\t\twg.Go(func() {\n\t\t\t\t_, err := processEvents(ctx, es, sid, evtCh)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t}\n\n\t\tvar done uint32\n\t\twait := es.Emit(&Event{Type: Exit, Done: func() {\n\t\t\tatomic.AddUint32(&done, 1)\n\t\t}})\n\t\twaitCtx, waitCancel := context.WithTimeout(ctx, time.Second)\n\t\tdefer waitCancel()\n\t\terr := wait(waitCtx)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, uint32(numSubs), done)\n\n\t\twg.Wait()\n\t})\n\n\tt.Run(\"emit_and_wait/error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\t\tdefer cancel()\n\t\tlogger := logrus.New()\n\t\tlogger.SetOutput(io.Discard)\n\t\tes := NewEventSystem(10, logger)\n\n\t\tsid, evtCh := es.Subscribe(Exit)\n\t\tvar wg sync.WaitGroup\n\t\twg.Go(func() {\n\t\t\t_, err := processEvents(ctx, es, sid, evtCh)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\twait := es.Emit(&Event{Type: Exit, Done: func() {\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t}})\n\t\twaitCtx, waitCancel := context.WithTimeout(ctx, 100*time.Millisecond)\n\t\tdefer waitCancel()\n\t\terr := wait(waitCtx)\n\t\tassert.EqualError(t, err, \"context is done before all 'Exit' events were processed\")\n\n\t\twg.Wait()\n\t})\n\n\tt.Run(\"unsubscribe\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tlogger := logrus.New()\n\t\tlogger.SetOutput(io.Discard)\n\t\tes := NewEventSystem(10, logger)\n\n\t\trequire.Len(t, es.subscribers, 0)\n\n\t\tvar (\n\t\t\tnumSubs = 5\n\t\t\tsubs    = make([]uint64, numSubs)\n\t\t)\n\t\tfor i := range numSubs {\n\t\t\tsid, _ := es.Subscribe(Init)\n\t\t\tsubs[i] = sid\n\t\t}\n\n\t\trequire.Len(t, es.subscribers[Init], numSubs)\n\n\t\tes.Unsubscribe(subs[0])\n\t\tassert.Len(t, es.subscribers[Init], numSubs-1)\n\t\tes.Unsubscribe(subs[0]) // second unsubscribe does nothing\n\t\tassert.Len(t, es.subscribers[Init], numSubs-1)\n\n\t\tes.UnsubscribeAll()\n\t\tassert.Len(t, es.subscribers[Init], 0)\n\t})\n}\n\nfunc processEvents(ctx context.Context, es *System, sid uint64, evtCh <-chan *Event) ([]*Event, error) {\n\tresult := make([]*Event, 0)\n\n\tfor {\n\t\tselect {\n\t\tcase evt, ok := <-evtCh:\n\t\t\tif !ok {\n\t\t\t\treturn result, nil\n\t\t\t}\n\t\t\tresult = append(result, evt)\n\t\t\tevt.Done()\n\t\t\tif evt.Type == Exit {\n\t\t\t\tes.Unsubscribe(sid)\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, errors.New(\"test timed out\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/event/type.go",
    "content": "package event\n\n// Type represents the different event types emitted by k6.\n//\n//go:generate enumer -type=Type -trimprefix Type -output type_gen.go\ntype Type uint8\n\nconst (\n\t// Init is emitted when k6 starts initializing outputs, VUs and executors.\n\tInit Type = iota + 1\n\t// TestStart is emitted when the execution scheduler starts running the test.\n\tTestStart\n\t// TestEnd is emitted when the test execution ends.\n\tTestEnd\n\t// IterStart is emitted when a VU starts an iteration.\n\tIterStart\n\t// IterEnd is emitted when a VU ends an iteration.\n\tIterEnd\n\t// Exit is emitted when the k6 process is about to exit.\n\tExit\n)\n\n//nolint:gochecknoglobals\nvar (\n\t// GlobalEvents are emitted once per test run.\n\tGlobalEvents = []Type{Init, TestStart, TestEnd, Exit}\n\t// VUEvents are emitted multiple times per each VU.\n\tVUEvents = []Type{IterStart, IterEnd}\n)\n\n// ExitData is the data sent in the Exit event. Error is the error returned by\n// the run command.\ntype ExitData struct {\n\tError error\n}\n\n// IterData is the data sent in the IterStart and IterEnd events.\ntype IterData struct {\n\tIteration    int64\n\tVUID         uint64\n\tScenarioName string\n\tError        error\n}\n"
  },
  {
    "path": "internal/event/type_gen.go",
    "content": "// Code generated by \"enumer -type=Type -trimprefix Type -output type_gen.go\"; DO NOT EDIT.\n\npackage event\n\nimport (\n\t\"fmt\"\n)\n\nconst _TypeName = \"InitTestStartTestEndIterStartIterEndExit\"\n\nvar _TypeIndex = [...]uint8{0, 4, 13, 20, 29, 36, 40}\n\nfunc (i Type) String() string {\n\ti -= 1\n\tif i >= Type(len(_TypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"Type(%d)\", i+1)\n\t}\n\treturn _TypeName[_TypeIndex[i]:_TypeIndex[i+1]]\n}\n\nvar _TypeValues = []Type{1, 2, 3, 4, 5, 6}\n\nvar _TypeNameToValueMap = map[string]Type{\n\t_TypeName[0:4]:   1,\n\t_TypeName[4:13]:  2,\n\t_TypeName[13:20]: 3,\n\t_TypeName[20:29]: 4,\n\t_TypeName[29:36]: 5,\n\t_TypeName[36:40]: 6,\n}\n\n// TypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc TypeString(s string) (Type, error) {\n\tif val, ok := _TypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to Type values\", s)\n}\n\n// TypeValues returns all values of the enum\nfunc TypeValues() []Type {\n\treturn _TypeValues\n}\n\n// IsAType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i Type) IsAType() bool {\n\tfor _, v := range _TypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/execution/abort.go",
    "content": "package execution\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// testAbortKey is the key used to store the abort function for the context of\n// an executor. This allows any users of that context or its sub-contexts to\n// cancel the whole execution tree, while at the same time providing all of the\n// details for why they cancelled it via the attached error.\ntype testAbortKey struct{}\n\ntype testAbortController struct {\n\tcancel context.CancelFunc\n\n\tlogger logrus.FieldLogger\n\tlock   sync.Mutex // only the first reason will be kept, other will be logged\n\treason error      // see errext package, you can wrap errors to attach exit status, run status, etc.\n}\n\nfunc (tac *testAbortController) abort(err error) {\n\ttac.lock.Lock()\n\tdefer tac.lock.Unlock()\n\tif tac.reason != nil {\n\t\ttac.logger.Debugf(\n\t\t\t\"test abort with reason '%s' was attempted when the test was already aborted due to '%s'\",\n\t\t\terr.Error(), tac.reason.Error(),\n\t\t)\n\t\treturn\n\t}\n\ttac.reason = err\n\ttac.cancel()\n}\n\nfunc (tac *testAbortController) getReason() error {\n\ttac.lock.Lock()\n\tdefer tac.lock.Unlock()\n\treturn tac.reason\n}\n\n// NewTestRunContext returns context.Context that can be aborted by calling the\n// returned TestAbortFunc or by calling CancelTestRunContext() on the returned\n// context or a sub-context of it. Use this to initialize the context that will\n// be passed to the ExecutionScheduler, so `execution.test.abort()` and the REST\n// API test stopping both work.\nfunc NewTestRunContext(\n\tctx context.Context, logger logrus.FieldLogger,\n) (newCtx context.Context, abortTest func(reason error)) {\n\tctx, cancel := context.WithCancel(ctx)\n\n\tcontroller := &testAbortController{\n\t\tcancel: cancel,\n\t\tlogger: logger,\n\t}\n\n\treturn context.WithValue(ctx, testAbortKey{}, controller), controller.abort\n}\n\n// AbortTestRun will cancel the test run context with the given reason if the\n// provided context is actually a TestRuncontext or a child of one.\nfunc AbortTestRun(ctx context.Context, err error) bool {\n\tif x := ctx.Value(testAbortKey{}); x != nil {\n\t\tif v, ok := x.(*testAbortController); ok {\n\t\t\tv.abort(err)\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// GetCancelReasonIfTestAborted returns a reason the Context was cancelled, if it was\n// aborted with these functions. It will return nil if ctx is not an\n// TestRunContext (or its children) or if it was never aborted.\nfunc GetCancelReasonIfTestAborted(ctx context.Context) error {\n\tif x := ctx.Value(testAbortKey{}); x != nil {\n\t\tif v, ok := x.(*testAbortController); ok {\n\t\t\treturn v.getReason()\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/execution/controller.go",
    "content": "package execution\n\n// Controller implementations are used to control the k6 execution of a test or\n// test suite, either locally or in a distributed environment.\ntype Controller interface {\n\t// GetOrCreateData requests the data chunk with the given ID, if it already\n\t// exists. If it doesn't (i.e. this was the first time this function was\n\t// called with that ID), the given callback is called and its result and\n\t// error are saved for the ID and returned for all other calls with it.\n\t//\n\t// This is an atomic and single-flight function, so any calls to it while the callback is\n\t// being executed the same ID will wait for the first call to finish\n\t// and receive its result.\n\t//\n\t// TODO: split apart into `Once()`, `SetData(), `GetData()` and implement\n\t// the GetOrCreateData() behavior in a helper like the ones below?\n\tGetOrCreateData(ID string, callback func() ([]byte, error)) ([]byte, error)\n\n\t// Signal is used to notify that the current instance has reached the given\n\t// event ID, or that it has had an error.\n\tSignal(eventID string, err error) error\n\n\t// Subscribe creates a listener for the specified event ID and returns a\n\t// callback that can wait until all other instances have reached it.\n\tSubscribe(eventID string) (wait func() error)\n}\n\n// SignalAndWait implements a rendezvous point / barrier, a way for all\n// instances to reach the same execution point and wait for each other, before\n// they all ~simultaneously continue with the execution.\n//\n// It subscribes for the given event ID, signals that the current instance has\n// reached it without an error, and then waits until all other instances have\n// reached it or until there is an error in one of them.\nfunc SignalAndWait(c Controller, eventID string) error {\n\twait := c.Subscribe(eventID)\n\n\tif err := c.Signal(eventID, nil); err != nil {\n\t\treturn err\n\t}\n\treturn wait()\n}\n\n// SignalErrorOrWait is a helper method that either immediately signals the\n// given error and returns it, or it signals nominal completion and waits for\n// all other instances to do the same (or signal an error themselves).\nfunc SignalErrorOrWait(c Controller, eventID string, err error) error {\n\tif err != nil {\n\t\t_ = c.Signal(eventID, err)\n\t\treturn err // return the same error we got\n\t}\n\treturn SignalAndWait(c, eventID)\n}\n"
  },
  {
    "path": "internal/execution/local/controller.go",
    "content": "// Package local implements the execution.Controller interface for local\n// (single-machine) k6 execution.\npackage local\n\n// Controller \"controls\" local tests. It doesn't actually do anything, it just\n// implements the execution.Controller interface with no-op operations. The\n// methods don't do anything because local tests have only a single instance.\n//\n// However, for test suites (https://github.com/grafana/k6/issues/1342) in the\n// future, we will probably need to actually implement some of these methods and\n// introduce simple synchronization primitives even for a single machine...\ntype Controller struct{}\n\n// NewController creates a new local execution Controller.\nfunc NewController() *Controller {\n\treturn &Controller{}\n}\n\n// GetOrCreateData immediately calls the given callback and returns its results.\nfunc (c *Controller) GetOrCreateData(_ string, callback func() ([]byte, error)) ([]byte, error) {\n\treturn callback()\n}\n\n// Subscribe is a no-op, it doesn't actually wait for anything, because there is\n// nothing to wait on - we only have one instance in local tests.\n//\n// TODO: actually use waitgroups, since this may actually matter for test\n// suites, even for local test runs. That's because multiple tests might be\n// executed even by a single instance, and if we have complicated flows (e.g.\n// \"test C is executed only after test A and test B finish\"), the easiest way\n// would be for different tests in the suite to reuse this Controller API *both*\n// local and distributed runs.\nfunc (c *Controller) Subscribe(_ string) func() error {\n\treturn func() error {\n\t\treturn nil\n\t}\n}\n\n// Signal is a no-op, it doesn't actually do anything for local test runs.\n//\n// TODO: similar to Wait() above, this might actually be required for\n// complex/branching test suites, even during local non-distributed execution.\nfunc (c *Controller) Signal(_ string, _ error) error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/execution/pkg.go",
    "content": "// Package execution contains most of the components that schedule, execute and\n// control individual k6 tests.\npackage execution\n\n// TODO: move ExecutionSegment and ESS here\n\n// TODO: move execotors interfaces here and implementations in a sub-folder\n// TODO: move the execution state here\n"
  },
  {
    "path": "internal/execution/scheduler.go",
    "content": "package execution\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// A Scheduler is in charge of most of the test execution - initializing VUs and\n// executors, running setup() and teardown(), and actually starting the\n// executors for the different scenarios at the appropriate times.\ntype Scheduler struct {\n\tcontroller Controller\n\n\tinitProgress    *pb.ProgressBar\n\texecutorConfigs []lib.ExecutorConfig // sorted by (startTime, ID)\n\texecutors       []lib.Executor       // sorted by (startTime, ID), excludes executors with no work\n\texecutionPlan   []lib.ExecutionStep\n\tmaxDuration     time.Duration // cached value derived from the execution plan\n\tmaxPossibleVUs  uint64        // cached value derived from the execution plan\n\tstate           *lib.ExecutionState\n}\n\n// NewScheduler creates and returns a new Scheduler instance, without\n// initializing it beyond the bare minimum. Specifically, it creates the needed\n// executor instances and a lot of state placeholders, but it doesn't initialize\n// the executors and it doesn't initialize or run VUs.\nfunc NewScheduler(trs *lib.TestRunState, controller Controller) (*Scheduler, error) {\n\toptions := trs.Options\n\tet, err := lib.NewExecutionTuple(options.ExecutionSegment, options.ExecutionSegmentSequence)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\texecutionPlan := options.Scenarios.GetFullExecutionRequirements(et)\n\tmaxPlannedVUs := lib.GetMaxPlannedVUs(executionPlan)\n\tmaxPossibleVUs := lib.GetMaxPossibleVUs(executionPlan)\n\n\texecutionState := lib.NewExecutionState(trs, et, maxPlannedVUs, maxPossibleVUs)\n\tmaxDuration, _ := lib.GetEndOffset(executionPlan) // we don't care if the end offset is final\n\n\texecutorConfigs := options.Scenarios.GetSortedConfigs()\n\texecutors := make([]lib.Executor, 0, len(executorConfigs))\n\t// Only take executors which have work.\n\tfor _, sc := range executorConfigs {\n\t\tif !sc.HasWork(et) {\n\t\t\ttrs.Logger.Debugf(\n\t\t\t\t\"Executor '%s' is disabled for segment %s due to lack of work!\",\n\t\t\t\tsc.GetName(), options.ExecutionSegment,\n\t\t\t)\n\t\t\tcontinue\n\t\t}\n\t\ts, err := sc.NewExecutor(executionState, trs.Logger.WithFields(logrus.Fields{\n\t\t\t\"scenario\": sc.GetName(),\n\t\t\t\"executor\": sc.GetType(),\n\t\t}))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\texecutors = append(executors, s)\n\t}\n\n\tif options.Paused.Bool {\n\t\tif err := executionState.Pause(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &Scheduler{\n\t\tinitProgress:    pb.New(pb.WithConstLeft(\"Init\")),\n\t\texecutors:       executors,\n\t\texecutorConfigs: executorConfigs,\n\t\texecutionPlan:   executionPlan,\n\t\tmaxDuration:     maxDuration,\n\t\tmaxPossibleVUs:  maxPossibleVUs,\n\t\tstate:           executionState,\n\t\tcontroller:      controller,\n\t}, nil\n}\n\n// GetState returns a pointer to the execution state struct for the execution\n// scheduler. It's guaranteed to be initialized and present, though see the\n// documentation in lib/execution.go for caveats about its usage. The most\n// important one is that none of the methods beyond the pause-related ones\n// should be used for synchronization.\nfunc (e *Scheduler) GetState() *lib.ExecutionState {\n\treturn e.state\n}\n\n// GetExecutors returns the slice of configured executor instances which\n// have work, sorted by their (startTime, name) in an ascending order.\nfunc (e *Scheduler) GetExecutors() []lib.Executor {\n\treturn e.executors\n}\n\n// GetExecutorConfigs returns the slice of all executor configs, sorted by\n// their (startTime, name) in an ascending order.\nfunc (e *Scheduler) GetExecutorConfigs() []lib.ExecutorConfig {\n\treturn e.executorConfigs\n}\n\n// GetInitProgressBar returns the progress bar associated with the Init\n// function. After the Init is done, it is \"hijacked\" to display real-time\n// execution statistics as a text bar.\nfunc (e *Scheduler) GetInitProgressBar() *pb.ProgressBar {\n\treturn e.initProgress\n}\n\n// GetExecutionPlan is a helper method so users of the local execution scheduler\n// don't have to calculate the execution plan again.\nfunc (e *Scheduler) GetExecutionPlan() []lib.ExecutionStep {\n\treturn e.executionPlan\n}\n\n// initVU is a helper method that's used to both initialize the planned VUs\n// in the Init() method, and also passed to executors so they can initialize\n// any unplanned VUs themselves.\nfunc (e *Scheduler) initVU(\n\tctx context.Context, samplesOut chan<- metrics.SampleContainer, logger logrus.FieldLogger,\n) (lib.InitializedVU, error) {\n\t// Get the VU IDs here, so that the VUs are (mostly) ordered by their\n\t// number in the channel buffer\n\tvuIDLocal, vuIDGlobal := e.state.GetUniqueVUIdentifiers()\n\tvu, err := e.state.Test.Runner.NewVU(ctx, vuIDLocal, vuIDGlobal, samplesOut)\n\tif err != nil {\n\t\treturn nil, errext.WithHint(err, fmt.Sprintf(\"error while initializing VU #%d\", vuIDGlobal))\n\t}\n\n\tlogger.Debugf(\"Initialized VU #%d\", vuIDGlobal)\n\treturn vu, nil\n}\n\n// getRunStats is a helper function that can be used as the execution\n// scheduler's progressbar substitute (i.e. hijack).\nfunc (e *Scheduler) getRunStats() string {\n\tstatus := \"running\"\n\tif e.state.IsPaused() {\n\t\tstatus = \"paused\"\n\t}\n\tif e.state.HasStarted() {\n\t\tdur := e.state.GetCurrentTestRunDuration()\n\t\tstatus = fmt.Sprintf(\"%s (%s)\", status, pb.GetFixedLengthDuration(dur, e.maxDuration))\n\t}\n\n\tvusFmt := pb.GetFixedLengthIntFormat(int64(e.maxPossibleVUs)) //nolint:gosec\n\treturn fmt.Sprintf(\n\t\t\"%s, \"+vusFmt+\"/\"+vusFmt+\" VUs, %d complete and %d interrupted iterations\",\n\t\tstatus, e.state.GetCurrentlyActiveVUsCount(), e.state.GetInitializedVUsCount(),\n\t\te.state.GetFullIterationCount(), e.state.GetPartialIterationCount(),\n\t)\n}\n\nfunc (e *Scheduler) initVUsConcurrently(\n\tctx context.Context, samplesOut chan<- metrics.SampleContainer, count uint64,\n\tconcurrency int, logger logrus.FieldLogger,\n) chan error {\n\tdoneInits := make(chan error, count) // poor man's waitgroup with results\n\tlimiter := make(chan struct{})\n\n\tfor range concurrency {\n\t\tgo func() {\n\t\t\tfor range limiter {\n\t\t\t\tnewVU, err := e.initVU(ctx, samplesOut, logger)\n\t\t\t\tif err == nil {\n\t\t\t\t\te.state.AddInitializedVU(newVU)\n\t\t\t\t}\n\t\t\t\tdoneInits <- err\n\t\t\t}\n\t\t}()\n\t}\n\n\tgo func() {\n\t\tdefer close(limiter)\n\t\tfor vuNum := range count {\n\t\t\tselect {\n\t\t\tcase limiter <- struct{}{}:\n\t\t\tcase <-ctx.Done():\n\t\t\t\tfor skipVu := vuNum; skipVu < count; skipVu++ {\n\t\t\t\t\t// do not even start initializing the remaining VUs\n\t\t\t\t\tdoneInits <- ctx.Err()\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn doneInits\n}\n\nfunc (e *Scheduler) emitVUsAndVUsMax(ctx context.Context, out chan<- metrics.SampleContainer) func() {\n\te.state.Test.Logger.Debug(\"Starting emission of VUs and VUsMax metrics...\")\n\ttags := e.state.Test.RunTags\n\twg := &sync.WaitGroup{}\n\twg.Add(1)\n\n\temitMetrics := func() {\n\t\tt := time.Now()\n\t\tsamples := metrics.ConnectedSamples{\n\t\t\tSamples: []metrics.Sample{\n\t\t\t\t{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: e.state.Test.BuiltinMetrics.VUs,\n\t\t\t\t\t\tTags:   tags,\n\t\t\t\t\t},\n\t\t\t\t\tTime:  t,\n\t\t\t\t\tValue: float64(e.state.GetCurrentlyActiveVUsCount()),\n\t\t\t\t}, {\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: e.state.Test.BuiltinMetrics.VUsMax,\n\t\t\t\t\t\tTags:   tags,\n\t\t\t\t\t},\n\t\t\t\t\tTime:  t,\n\t\t\t\t\tValue: float64(e.state.GetInitializedVUsCount()),\n\t\t\t\t},\n\t\t\t},\n\t\t\tTags: tags,\n\t\t\tTime: t,\n\t\t}\n\t\tmetrics.PushIfNotDone(ctx, out, samples)\n\t}\n\n\tticker := time.NewTicker(1 * time.Second)\n\tgo func() {\n\t\tdefer func() {\n\t\t\tticker.Stop()\n\t\t\te.state.Test.Logger.Debug(\"Metrics emission of VUs and VUsMax metrics stopped\")\n\t\t\twg.Done()\n\t\t}()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ticker.C:\n\t\t\t\temitMetrics()\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn wg.Wait\n}\n\n// initVUsAndExecutors concurrently initializes all of the planned VUs and then\n// sequentially initializes all of the configured executors.\nfunc (e *Scheduler) initVUsAndExecutors(ctx context.Context, samplesOut chan<- metrics.SampleContainer) (err error) {\n\te.initProgress.Modify(pb.WithConstProgress(0, \"Init VUs...\"))\n\n\tlogger := e.state.Test.Logger.WithField(\"phase\", \"execution-scheduler-init\")\n\tvusToInitialize := lib.GetMaxPlannedVUs(e.executionPlan)\n\tlogger.WithFields(logrus.Fields{\n\t\t\"neededVUs\":      vusToInitialize,\n\t\t\"executorsCount\": len(e.executors),\n\t}).Debugf(\"Start of initialization\")\n\n\tsubctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\te.state.SetExecutionStatus(lib.ExecutionStatusInitVUs)\n\tdoneInits := e.initVUsConcurrently(subctx, samplesOut, vusToInitialize, runtime.GOMAXPROCS(0), logger)\n\n\tinitializedVUs := new(uint64)\n\tvusFmt := pb.GetFixedLengthIntFormat(int64(vusToInitialize)) //nolint:gosec\n\te.initProgress.Modify(\n\t\tpb.WithProgress(func() (float64, []string) {\n\t\t\tdoneVUs := atomic.LoadUint64(initializedVUs)\n\t\t\tright := fmt.Sprintf(vusFmt+\"/%d VUs initialized\", doneVUs, vusToInitialize)\n\t\t\treturn float64(doneVUs) / float64(vusToInitialize), []string{right}\n\t\t}),\n\t)\n\n\tvar initErr error\n\tfor range vusToInitialize {\n\t\tvar err error\n\t\tselect {\n\t\tcase err = <-doneInits:\n\t\t\tif err == nil {\n\t\t\t\tatomic.AddUint64(initializedVUs, 1)\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\terr = ctx.Err()\n\t\t}\n\n\t\tif err == nil || initErr != nil {\n\t\t\t// No error or a previous init error was already saved and we are\n\t\t\t// just waiting for VUs to finish aborting\n\t\t\tcontinue\n\t\t}\n\n\t\tlogger.WithError(err).Debug(\"VU initialization returned with an error, aborting...\")\n\t\tinitErr = err\n\t\tcancel()\n\t}\n\n\tif initErr != nil {\n\t\treturn initErr\n\t}\n\n\te.state.SetInitVUFunc(func(ctx context.Context, logger *logrus.Entry) (lib.InitializedVU, error) {\n\t\treturn e.initVU(ctx, samplesOut, logger)\n\t})\n\n\te.state.SetExecutionStatus(lib.ExecutionStatusInitExecutors)\n\tlogger.Debugf(\"Finished initializing needed VUs, start initializing executors...\")\n\tfor _, exec := range e.executors {\n\t\texecutorConfig := exec.GetConfig()\n\n\t\tif err := exec.Init(ctx); err != nil {\n\t\t\treturn fmt.Errorf(\"error while initializing executor %s: %w\", executorConfig.GetName(), err)\n\t\t}\n\t\tlogger.Debugf(\"Initialized executor %s\", executorConfig.GetName())\n\t}\n\n\te.state.SetExecutionStatus(lib.ExecutionStatusInitDone)\n\tlogger.Debugf(\"Initialization completed\")\n\treturn nil\n}\n\n// runExecutor gets called by the public Run() method once per configured\n// executor, each time in a new goroutine. It is responsible for waiting out the\n// configured startTime for the specific executor and then running its Run()\n// method.\nfunc (e *Scheduler) runExecutor(\n\trunCtx context.Context, runResults chan<- error, engineOut chan<- metrics.SampleContainer, executor lib.Executor,\n) {\n\texecutorConfig := executor.GetConfig()\n\texecutorStartTime := executorConfig.GetStartTime()\n\texecutorLogger := e.state.Test.Logger.WithFields(logrus.Fields{\n\t\t\"executor\":  executorConfig.GetName(),\n\t\t\"type\":      executorConfig.GetType(),\n\t\t\"startTime\": executorStartTime,\n\t})\n\texecutorProgress := executor.GetProgress()\n\n\t// Check if we have to wait before starting the actual executor execution\n\tif executorStartTime > 0 {\n\t\tstartTime := time.Now()\n\t\texecutorProgress.Modify(\n\t\t\tpb.WithStatus(pb.Waiting),\n\t\t\tpb.WithProgress(func() (float64, []string) {\n\t\t\t\tremWait := (executorStartTime - time.Since(startTime))\n\t\t\t\treturn 0, []string{\"waiting\", pb.GetFixedLengthDuration(remWait, executorStartTime)}\n\t\t\t}),\n\t\t)\n\n\t\texecutorLogger.Debugf(\"Waiting for executor start time...\")\n\t\tselect {\n\t\tcase <-runCtx.Done():\n\t\t\trunResults <- nil // no error since executor hasn't started yet\n\t\t\treturn\n\t\tcase <-time.After(executorStartTime):\n\t\t\t// continue\n\t\t}\n\t}\n\n\texecutorProgress.Modify(\n\t\tpb.WithStatus(pb.Running),\n\t\tpb.WithConstProgress(0, \"started\"),\n\t)\n\texecutorLogger.Debugf(\"Starting executor\")\n\terr := executor.Run(runCtx, engineOut) // executor should handle context cancel itself\n\tif err == nil {\n\t\texecutorLogger.Debugf(\"Executor finished successfully\")\n\t} else {\n\t\texecutorLogger.WithField(\"error\", err).Errorf(\"Executor error\")\n\t}\n\trunResults <- err\n}\n\n// Init concurrently initializes all of the planned VUs and then sequentially\n// initializes all of the configured executors. It also starts the measurement\n// and emission of the `vus` and `vus_max` metrics.\nfunc (e *Scheduler) Init(\n\trunCtx context.Context, samplesOut chan<- metrics.SampleContainer,\n) (stopVUEmission func(), initErr error) {\n\tlogger := e.state.Test.Logger.WithField(\"phase\", \"execution-scheduler-init\")\n\n\tif err := SignalAndWait(e.controller, \"scheduler-init-start\"); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\tinitErr = SignalErrorOrWait(e.controller, \"scheduler-init-done\", initErr)\n\t}()\n\n\texecSchedRunCtx, execSchedRunCancel := context.WithCancel(runCtx)\n\twaitForVUsMetricPush := e.emitVUsAndVUsMax(execSchedRunCtx, samplesOut)\n\tstopVUEmission = func() {\n\t\tlogger.Debugf(\"Stopping vus and vux_max metrics emission...\")\n\t\texecSchedRunCancel()\n\t\twaitForVUsMetricPush()\n\t}\n\n\tdefer func() {\n\t\tif interruptErr := GetCancelReasonIfTestAborted(runCtx); interruptErr != nil {\n\t\t\tlogger.Debugf(\"The test run was interrupted, returning '%s' instead of '%s'\", interruptErr, initErr)\n\t\t\te.state.SetExecutionStatus(lib.ExecutionStatusInterrupted)\n\t\t\tinitErr = interruptErr\n\t\t}\n\t\tif initErr != nil {\n\t\t\tstopVUEmission()\n\t\t}\n\t}()\n\n\treturn stopVUEmission, e.initVUsAndExecutors(execSchedRunCtx, samplesOut)\n}\n\n// Run the Scheduler, funneling all generated metric samples through the supplied\n// out channel.\n//\n//nolint:funlen, gocognit\nfunc (e *Scheduler) Run(globalCtx, runCtx context.Context, samplesOut chan<- metrics.SampleContainer) (runErr error) {\n\tlogger := e.state.Test.Logger.WithField(\"phase\", \"execution-scheduler-run\")\n\n\tif err := SignalAndWait(e.controller, \"scheduler-run-start\"); err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif interruptErr := GetCancelReasonIfTestAborted(runCtx); interruptErr != nil {\n\t\t\tlogger.Debugf(\"The test run was interrupted, returning '%s' instead of '%s'\", interruptErr, runErr)\n\t\t\te.state.SetExecutionStatus(lib.ExecutionStatusInterrupted)\n\t\t\trunErr = interruptErr\n\t\t}\n\t\trunErr = SignalErrorOrWait(e.controller, \"scheduler-run-done\", runErr)\n\t}()\n\n\te.initProgress.Modify(pb.WithConstLeft(\"Run\"))\n\tif e.state.IsPaused() {\n\t\tlogger.Debug(\"Execution is paused, waiting for resume or interrupt...\")\n\t\te.state.SetExecutionStatus(lib.ExecutionStatusPausedBeforeRun)\n\t\te.initProgress.Modify(pb.WithConstProgress(1, \"paused\"))\n\t\tselect {\n\t\tcase <-e.state.ResumeNotify():\n\t\t\t// continue\n\t\tcase <-runCtx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif err := SignalAndWait(e.controller, \"test-ready-to-run-setup\"); err != nil {\n\t\treturn err\n\t}\n\n\te.initProgress.Modify(pb.WithConstProgress(1, \"Starting test...\"))\n\te.state.MarkStarted()\n\tdefer func() {\n\t\tif e.state.Test.TestStatus != nil && e.state.Test.TestStatus.Failed() {\n\t\t\te.state.SetExecutionStatus(lib.ExecutionStatusMarkedAsFailed)\n\t\t\treturn\n\t\t}\n\n\t\tisAborted := GetCancelReasonIfTestAborted(runCtx) != nil\n\t\tif !isAborted {\n\t\t\te.state.MarkEnded()\n\t\t}\n\t}()\n\te.initProgress.Modify(pb.WithConstProgress(1, \"running\"))\n\n\texecutorsCount := len(e.executors)\n\tlogger.WithFields(logrus.Fields{\"executorsCount\": executorsCount}).Debugf(\"Start of test run\")\n\n\trunResults := make(chan error, executorsCount) // nil values are successful runs\n\n\t// TODO: get rid of this context, pass the e.state directly to VUs when they\n\t// are initialized by e.initVUsAndExecutors(). This will also give access to\n\t// its properties in their init context executions.\n\twithExecStateCtx := lib.WithExecutionState(runCtx, e.state)\n\n\t// Run setup() before any executors, if it's not disabled\n\tif !e.state.Test.Options.NoSetup.Bool {\n\t\te.state.SetExecutionStatus(lib.ExecutionStatusSetup)\n\t\te.initProgress.Modify(pb.WithConstProgress(1, \"setup()\"))\n\t\tactuallyRanSetup := false\n\t\tdata, err := e.controller.GetOrCreateData(\"setup\", func() ([]byte, error) {\n\t\t\tactuallyRanSetup = true\n\t\t\tif err := e.state.Test.Runner.Setup(withExecStateCtx, samplesOut); err != nil {\n\t\t\t\tlogger.WithField(\"error\", err).Debug(\"setup() aborted by error\")\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn e.state.Test.Runner.GetSetupData(), nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !actuallyRanSetup {\n\t\t\te.state.Test.Runner.SetSetupData(data)\n\t\t}\n\t}\n\n\tif err := SignalAndWait(e.controller, \"setup-done\"); err != nil {\n\t\treturn err\n\t}\n\n\te.initProgress.Modify(pb.WithHijack(e.getRunStats))\n\n\t// Start all executors at their particular startTime in a separate goroutine...\n\tlogger.Debug(\"Start all executors...\")\n\te.state.SetExecutionStatus(lib.ExecutionStatusRunning)\n\n\texecutorsRunCtx, executorsRunCancel := context.WithCancel(withExecStateCtx)\n\tdefer executorsRunCancel()\n\tfor _, exec := range e.executors {\n\t\tgo e.runExecutor(executorsRunCtx, runResults, samplesOut, exec)\n\t}\n\n\t// Wait for all executors to finish\n\tvar firstErr error\n\tfor range e.executors {\n\t\t// TODO: add logic to abort the test early if there was an error from\n\t\t// the controller (e.g. some other instance for this test died)\n\t\terr := <-runResults\n\t\tif err != nil && firstErr == nil {\n\t\t\tlogger.WithError(err).Debug(\"Executor returned with an error, cancelling test run...\")\n\t\t\tfirstErr = err\n\t\t\texecutorsRunCancel()\n\t\t}\n\t}\n\n\tif err := SignalAndWait(e.controller, \"execution-done\"); err != nil {\n\t\treturn err\n\t}\n\n\t// Run teardown() after all executors are done, if it's not disabled\n\tif !e.state.Test.Options.NoTeardown.Bool {\n\t\te.state.SetExecutionStatus(lib.ExecutionStatusTeardown)\n\t\te.initProgress.Modify(pb.WithConstProgress(1, \"teardown()\"))\n\n\t\t// We run teardown() with the global context, so it isn't interrupted by\n\t\t// thresholds or test.abort() or even Ctrl+C (unless used twice).\n\t\t// TODO: add a `sync.Once` equivalent?\n\t\t_, err := e.controller.GetOrCreateData(\"teardown\", func() ([]byte, error) {\n\t\t\tif err := e.state.Test.Runner.Teardown(globalCtx, samplesOut); err != nil {\n\t\t\t\tlogger.WithField(\"error\", err).Debug(\"teardown() aborted by error\")\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn nil, nil\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := SignalAndWait(e.controller, \"teardown-done\"); err != nil {\n\t\treturn err\n\t}\n\n\treturn firstErr\n}\n\n// SetPaused pauses the test, or start/resumes it. To check if a test is paused,\n// use GetState().IsPaused().\n//\n// Currently, any executor, so any test, can be started in a paused state. This\n// will cause k6 to initialize all needed VUs, but it won't actually start the\n// test. Later, the test can be started for real by resuming/unpausing it from\n// the REST API.\n//\n// After a test is actually started, it may become impossible to pause it again.\n// That is signaled by having SetPaused(true) return an error. The likely cause\n// is that some of the executors for the test don't support pausing after the\n// test has been started.\n//\n// IMPORTANT: Currently only the externally controlled executor can be paused\n// and resumed multiple times in the middle of the test execution! Even then,\n// \"pausing\" is a bit misleading, since k6 won't pause in the middle of the\n// currently executing iterations. It will allow the currently in-progress\n// iterations to finish, and it just won't start any new ones nor will it\n// increment the value returned by GetCurrentTestRunDuration().\nfunc (e *Scheduler) SetPaused(pause bool) error {\n\tif !e.state.HasStarted() && e.state.IsPaused() {\n\t\tif pause {\n\t\t\treturn fmt.Errorf(\"execution is already paused\")\n\t\t}\n\t\te.state.Test.Logger.Debug(\"Starting execution\")\n\t\treturn e.state.Resume()\n\t}\n\n\tfor _, exec := range e.executors {\n\t\tpausableExecutor, ok := exec.(lib.PausableExecutor)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"%s executor '%s' doesn't support pause and resume operations after its start\",\n\t\t\t\texec.GetConfig().GetType(), exec.GetConfig().GetName(),\n\t\t\t)\n\t\t}\n\t\tif err := pausableExecutor.SetPaused(pause); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif pause {\n\t\treturn e.state.Pause()\n\t}\n\treturn e.state.Resume()\n}\n"
  },
  {
    "path": "internal/execution/scheduler_ext_exec_test.go",
    "content": "package execution_test\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/js\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO: rewrite and/or move these as integration tests to reduce boilerplate\n// and improve reliability?\nfunc TestExecutionInfoVUSharing(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\t\timport exec from 'k6/execution';\n\t\timport { sleep } from 'k6';\n\n\t\t// The cvus scenario should reuse the two VUs created for the carr scenario.\n\t\texport let options = {\n\t\t\tscenarios: {\n\t\t\t\tcarr: {\n\t\t\t\t\texecutor: 'constant-arrival-rate',\n\t\t\t\t\texec: 'carr',\n\t\t\t\t\trate: 9,\n\t\t\t\t\ttimeUnit: '0.95s',\n\t\t\t\t\tduration: '1s',\n\t\t\t\t\tpreAllocatedVUs: 2,\n\t\t\t\t\tmaxVUs: 10,\n\t\t\t\t\tgracefulStop: '100ms',\n\t\t\t\t},\n\t\t\t    cvus: {\n\t\t\t\t\texecutor: 'constant-vus',\n\t\t\t\t\texec: 'cvus',\n\t\t\t\t\tvus: 2,\n\t\t\t\t\tduration: '1s',\n\t\t\t\t\tstartTime: '2s',\n\t\t\t\t\tgracefulStop: '0s',\n\t\t\t    },\n\t\t    },\n\t\t};\n\n\t\texport function cvus() {\n\t\t\tconst info = Object.assign({scenario: 'cvus'}, exec.vu);\n\t\t\tconsole.log(JSON.stringify(info));\n\t\t\tsleep(0.2);\n\t\t};\n\n\t\texport function carr() {\n\t\t\tconst info = Object.assign({scenario: 'carr'}, exec.vu);\n\t\t\tconsole.log(JSON.stringify(info));\n\t\t};\n`)\n\n\tlogger := logrus.New()\n\tlogger.SetOutput(io.Discard)\n\tlogHook := testutils.NewLogHook(logrus.InfoLevel)\n\tlogger.AddHook(logHook)\n\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tpiState := &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tRegistry:       registry,\n\t\tUsage:          usage.New(),\n\t}\n\tsourceData := &loader.SourceData{\n\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\tData: script,\n\t}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\trequire.NoError(t, err)\n\n\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, logger, lib.Options{})\n\tdefer cancel()\n\n\ttype vuStat struct {\n\t\titeration uint64\n\t\tscIter    map[string]uint64\n\t}\n\tvuStats := map[uint64]*vuStat{}\n\n\ttype logEntry struct {\n\t\tIDInInstance        uint64\n\t\tScenario            string\n\t\tIterationInInstance uint64\n\t\tIterationInScenario uint64\n\t}\n\n\terrCh := make(chan error, 1)\n\tgo func() { errCh <- execScheduler.Run(ctx, ctx, samples) }()\n\n\tselect {\n\tcase err := <-errCh:\n\t\trequire.NoError(t, err)\n\t\tentries := logHook.Drain()\n\t\tassert.InDelta(t, 20, len(entries), 2)\n\t\tle := &logEntry{}\n\t\tfor _, entry := range entries {\n\t\t\terr = json.Unmarshal([]byte(entry.Message), le)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Contains(t, []uint64{1, 2}, le.IDInInstance)\n\t\t\tif _, ok := vuStats[le.IDInInstance]; !ok {\n\t\t\t\tvuStats[le.IDInInstance] = &vuStat{0, make(map[string]uint64)}\n\t\t\t}\n\t\t\tif le.IterationInInstance > vuStats[le.IDInInstance].iteration {\n\t\t\t\tvuStats[le.IDInInstance].iteration = le.IterationInInstance\n\t\t\t}\n\t\t\tif le.IterationInScenario > vuStats[le.IDInInstance].scIter[le.Scenario] {\n\t\t\t\tvuStats[le.IDInInstance].scIter[le.Scenario] = le.IterationInScenario\n\t\t\t}\n\t\t}\n\t\trequire.Len(t, vuStats, 2)\n\t\t// Both VUs should complete 10 iterations each globally, but 5\n\t\t// iterations each per scenario (iterations are 0-based)\n\t\tfor _, v := range vuStats {\n\t\t\tassert.Equal(t, uint64(9), v.iteration)\n\t\t\tassert.Equal(t, uint64(4), v.scIter[\"cvus\"])\n\t\t\tassert.Equal(t, uint64(4), v.scIter[\"carr\"])\n\t\t}\n\tcase <-time.After(10 * time.Second):\n\t\tt.Fatal(\"timed out\")\n\t}\n}\n\nfunc TestExecutionInfoScenarioIter(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\t\timport exec from 'k6/execution';\n\n\t\t// The pvu scenario should reuse the two VUs created for the carr scenario.\n\t\texport let options = {\n\t\t\tscenarios: {\n\t\t\t\tcarr: {\n\t\t\t\t\texecutor: 'constant-arrival-rate',\n\t\t\t\t\texec: 'carr',\n\t\t\t\t\trate: 9,\n\t\t\t\t\ttimeUnit: '0.95s',\n\t\t\t\t\tduration: '1s',\n\t\t\t\t\tpreAllocatedVUs: 2,\n\t\t\t\t\tmaxVUs: 10,\n\t\t\t\t\tgracefulStop: '100ms',\n\t\t\t\t},\n\t\t\t\tpvu: {\n\t\t\t\t\texecutor: 'per-vu-iterations',\n\t\t\t\t\texec: 'pvu',\n\t\t\t\t\tvus: 2,\n\t\t\t\t\titerations: 5,\n\t\t\t\t\tstartTime: '2s',\n\t\t\t\t\tgracefulStop: '100ms',\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\n\t\texport function pvu() {\n\t\t\tconst info = Object.assign({VUID: __VU}, exec.scenario);\n\t\t\tconsole.log(JSON.stringify(info));\n\t\t}\n\n\t\texport function carr() {\n\t\t\tconst info = Object.assign({VUID: __VU}, exec.scenario);\n\t\t\tconsole.log(JSON.stringify(info));\n\t\t};\n`)\n\n\tlogger := logrus.New()\n\tlogger.SetOutput(io.Discard)\n\tlogHook := testutils.NewLogHook(logrus.InfoLevel)\n\tlogger.AddHook(logHook)\n\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tpiState := &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tRegistry:       registry,\n\t\tUsage:          usage.New(),\n\t}\n\tsourceData := &loader.SourceData{\n\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\tData: script,\n\t}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\trequire.NoError(t, err)\n\n\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, logger, lib.Options{})\n\tdefer cancel()\n\n\terrCh := make(chan error, 1)\n\tgo func() { errCh <- execScheduler.Run(ctx, ctx, samples) }()\n\n\tscStats := map[string]uint64{}\n\n\ttype logEntry struct {\n\t\tName                      string\n\t\tIterationInInstance, VUID uint64\n\t}\n\n\tselect {\n\tcase err := <-errCh:\n\t\trequire.NoError(t, err)\n\t\tentries := logHook.Drain()\n\t\trequire.Len(t, entries, 20)\n\t\tle := &logEntry{}\n\t\tfor _, entry := range entries {\n\t\t\terr = json.Unmarshal([]byte(entry.Message), le)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Contains(t, []uint64{1, 2}, le.VUID)\n\t\t\tif le.IterationInInstance > scStats[le.Name] {\n\t\t\t\tscStats[le.Name] = le.IterationInInstance\n\t\t\t}\n\t\t}\n\t\trequire.Len(t, scStats, 2)\n\t\t// The global per scenario iteration count should be 9 (iterations\n\t\t// start at 0), despite VUs being shared or more than 1 being used.\n\t\tfor _, v := range scStats {\n\t\t\tassert.Equal(t, uint64(9), v)\n\t\t}\n\tcase <-time.After(10 * time.Second):\n\t\tt.Fatal(\"timed out\")\n\t}\n}\n\n// Ensure that scenario iterations returned from k6/execution are\n// stable during the execution of an iteration.\nfunc TestSharedIterationsStable(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\t\timport { sleep } from 'k6';\n\t\timport exec from 'k6/execution';\n\n\t\texport let options = {\n\t\t\tscenarios: {\n\t\t\t\ttest: {\n\t\t\t\t\texecutor: 'shared-iterations',\n\t\t\t\t\tvus: 50,\n\t\t\t\t\titerations: 50,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\texport default function () {\n\t\t\tsleep(1);\n\t\t\tconsole.log(JSON.stringify(Object.assign({VUID: __VU}, exec.scenario)));\n\t\t}\n`)\n\n\tlogger := logrus.New()\n\tlogger.SetOutput(io.Discard)\n\tlogHook := testutils.NewLogHook(logrus.InfoLevel)\n\tlogger.AddHook(logHook)\n\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tpiState := &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tRegistry:       registry,\n\t\tUsage:          usage.New(),\n\t}\n\tsourceData := &loader.SourceData{\n\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\tData: script,\n\t}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\trequire.NoError(t, err)\n\n\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, logger, lib.Options{})\n\tdefer cancel()\n\n\terrCh := make(chan error, 1)\n\tgo func() { errCh <- execScheduler.Run(ctx, ctx, samples) }()\n\n\texpIters := [50]int64{}\n\tfor i := range 50 {\n\t\texpIters[i] = int64(i)\n\t}\n\tgotLocalIters, gotGlobalIters := []int64{}, []int64{}\n\n\ttype logEntry struct{ IterationInInstance, IterationInTest int64 }\n\n\tselect {\n\tcase err := <-errCh:\n\t\trequire.NoError(t, err)\n\t\tentries := logHook.Drain()\n\t\trequire.Len(t, entries, 50)\n\t\tle := &logEntry{}\n\t\tfor _, entry := range entries {\n\t\t\terr = json.Unmarshal([]byte(entry.Message), le)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, le.IterationInInstance, le.IterationInTest)\n\t\t\tgotLocalIters = append(gotLocalIters, le.IterationInInstance)\n\t\t\tgotGlobalIters = append(gotGlobalIters, le.IterationInTest)\n\t\t}\n\n\t\tassert.ElementsMatch(t, expIters, gotLocalIters)\n\t\tassert.ElementsMatch(t, expIters, gotGlobalIters)\n\tcase <-time.After(5 * time.Second):\n\t\tt.Fatal(\"timed out\")\n\t}\n}\n\nfunc TestExecutionInfoAll(t *testing.T) {\n\tt.Parallel()\n\n\tscriptTemplate := `\n\timport { sleep } from 'k6';\n\timport exec from \"k6/execution\";\n\n\texport let options = {\n\t\tscenarios: {\n\t\t\texecutor: {\n\t\t\t\texecutor: \"%[1]s\",\n\t\t\t\t%[2]s\n\t\t\t}\n\t\t}\n\t}\n\n\texport default function () {\n\t\tsleep(0.2);\n\t\tconsole.log(JSON.stringify(exec));\n\t}`\n\n\texecutorConfigs := map[string]string{\n\t\t\"constant-arrival-rate\": `\n\t\t\trate: 1,\n\t\t\ttimeUnit: \"1s\",\n\t\t\tduration: \"1s\",\n\t\t\tpreAllocatedVUs: 1,\n\t\t\tmaxVUs: 2,\n\t\t\tgracefulStop: \"0s\",`,\n\t\t\"constant-vus\": `\n\t\t\tvus: 1,\n\t\t\tduration: \"1s\",\n\t\t\tgracefulStop: \"0s\",`,\n\t\t\"externally-controlled\": `\n\t\t\tvus: 1,\n\t\t\tduration: \"1s\",`,\n\t\t\"per-vu-iterations\": `\n\t\t\tvus: 1,\n\t\t\titerations: 1,\n\t\t\tgracefulStop: \"0s\",`,\n\t\t\"shared-iterations\": `\n\t\t\tvus: 1,\n\t\t\titerations: 1,\n\t\t\tgracefulStop: \"0s\",`,\n\t\t\"ramping-arrival-rate\": `\n\t\t\tstartRate: 1,\n\t\t\ttimeUnit: \"0.5s\",\n\t\t\tpreAllocatedVUs: 1,\n\t\t\tmaxVUs: 2,\n\t\t\tstages: [ { target: 1, duration: \"1s\" } ],\n\t\t\tgracefulStop: \"0s\",`,\n\t\t\"ramping-vus\": `\n\t\t\tstartVUs: 1,\n\t\t\tstages: [ { target: 1, duration: \"1s\" } ],\n\t\t\tgracefulStop: \"0s\",`,\n\t}\n\n\ttestCases := make([]struct{ name, script string }, 0, len(executorConfigs))\n\n\tfor ename, econf := range executorConfigs {\n\t\ttestCases = append(testCases, struct{ name, script string }{\n\t\t\tename, fmt.Sprintf(scriptTemplate, ename, econf),\n\t\t})\n\t}\n\n\t// We're only checking a small subset of all properties, to ensure\n\t// there were no errors with accessing any of the top-level ones.\n\t// Most of the others are time-based, and would be difficult/flaky to check.\n\ttype logEntry struct {\n\t\tScenario struct{ Executor string }\n\t\tInstance struct{ VUsActive int }\n\t\tVU       struct{ IDInTest int }\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tlogger := logrus.New()\n\t\t\tlogger.SetOutput(io.Discard)\n\t\t\tlogHook := testutils.NewLogHook(logrus.InfoLevel)\n\t\t\tlogger.AddHook(logHook)\n\n\t\t\tregistry := metrics.NewRegistry()\n\t\t\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\t\t\tpiState := &lib.TestPreInitState{\n\t\t\t\tLogger:         logger,\n\t\t\t\tBuiltinMetrics: builtinMetrics,\n\t\t\t\tRegistry:       registry,\n\t\t\t\tUsage:          usage.New(),\n\t\t\t}\n\t\t\tsourceData := &loader.SourceData{\n\t\t\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\t\t\tData: []byte(tc.script),\n\t\t\t}\n\t\t\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\t\t\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, logger, lib.Options{})\n\t\t\tdefer cancel()\n\n\t\t\terrCh := make(chan error, 1)\n\t\t\tgo func() { errCh <- execScheduler.Run(ctx, ctx, samples) }()\n\n\t\t\tselect {\n\t\t\tcase err := <-errCh:\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tentries := logHook.Drain()\n\t\t\t\trequire.GreaterOrEqual(t, len(entries), 1)\n\n\t\t\t\tle := &logEntry{}\n\t\t\t\terr = json.Unmarshal([]byte(entries[0].Message), le)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, tc.name, le.Scenario.Executor)\n\t\t\t\tassert.Equal(t, 1, le.Instance.VUsActive)\n\t\t\t\tassert.Equal(t, 1, le.VU.IDInTest)\n\t\t\tcase <-time.After(5 * time.Second):\n\t\t\t\tt.Fatal(\"timed out\")\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/execution/scheduler_ext_test.go",
    "content": "package execution_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\tlogtest \"github.com/sirupsen/logrus/hooks/test\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/js\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/internal/lib/testutils/mockresolver\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/executor\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/lib/netext/httpext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc getTestPreInitState(tb testing.TB) *lib.TestPreInitState {\n\treg := metrics.NewRegistry()\n\treturn &lib.TestPreInitState{\n\t\tLogger:         testutils.NewLogger(tb),\n\t\tRuntimeOptions: lib.RuntimeOptions{},\n\t\tRegistry:       reg,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(reg),\n\t\tUsage:          usage.New(),\n\t}\n}\n\nfunc getTestRunState(\n\ttb testing.TB, piState *lib.TestPreInitState, options lib.Options, runner lib.Runner,\n) *lib.TestRunState {\n\trequire.Empty(tb, options.Validate())\n\trequire.NoError(tb, runner.SetOptions(options))\n\treturn &lib.TestRunState{\n\t\tTestPreInitState: piState,\n\t\tOptions:          options,\n\t\tRunner:           runner,\n\t\tRunTags:          piState.Registry.RootTagSet().WithTagsFromMap(options.RunTags),\n\t}\n}\n\nfunc newTestScheduler(\n\tt *testing.T, runner lib.Runner, logger logrus.FieldLogger, opts lib.Options,\n) (ctx context.Context, cancel func(), execScheduler *execution.Scheduler, samples chan metrics.SampleContainer) {\n\tif runner == nil {\n\t\trunner = &minirunner.MiniRunner{}\n\t}\n\tctx, cancel = context.WithCancel(context.Background())\n\tnewOpts, err := executor.DeriveScenariosFromShortcuts(lib.Options{\n\t\tMetricSamplesBufferSize: null.NewInt(200, false),\n\t}.Apply(runner.GetOptions()).Apply(opts), nil)\n\trequire.NoError(t, err)\n\n\ttestRunState := getTestRunState(t, getTestPreInitState(t), newOpts, runner)\n\tif logger != nil {\n\t\ttestRunState.Logger = logger\n\t}\n\n\texecScheduler, err = execution.NewScheduler(testRunState, local.NewController())\n\trequire.NoError(t, err)\n\n\tsamples = make(chan metrics.SampleContainer, newOpts.MetricSamplesBufferSize.Int64)\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-samples:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tstopEmission, err := execScheduler.Init(ctx, samples)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\tstopEmission()\n\t\tclose(samples)\n\t})\n\n\treturn ctx, cancel, execScheduler, samples\n}\n\nfunc TestSchedulerRun(t *testing.T) {\n\tt.Parallel()\n\tctx, cancel, execScheduler, samples := newTestScheduler(t, nil, nil, lib.Options{})\n\tdefer cancel()\n\n\terr := make(chan error, 1)\n\tgo func() { err <- execScheduler.Run(ctx, ctx, samples) }()\n\tassert.NoError(t, <-err)\n}\n\nfunc TestSchedulerRunNonDefault(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname, script string\n\t}{\n\t\t{\"defaultOK\", `export default function () {}`},\n\t\t{\"nonDefaultOK\", `\n\texport let options = {\n\t\tscenarios: {\n\t\t\tper_vu_iters: {\n\t\t\t\texecutor: \"per-vu-iterations\",\n\t\t\t\tvus: 1,\n\t\t\t\titerations: 1,\n\t\t\t\texec: \"nonDefault\",\n\t\t\t},\n\t\t}\n\t}\n\texport function nonDefault() {}`},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpiState := getTestPreInitState(t)\n\t\t\tsourceData := &loader.SourceData{\n\t\t\t\tURL: &url.URL{Path: \"/script.js\"}, Data: []byte(tc.script),\n\t\t\t}\n\t\t\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\t\t\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestRunState := getTestRunState(t, piState, runner.GetOptions(), runner)\n\n\t\t\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tctx := t.Context()\n\n\t\t\tdone := make(chan struct{})\n\t\t\tsamples := make(chan metrics.SampleContainer)\n\t\t\tdefer close(samples)\n\n\t\t\tstopEmission, err := execScheduler.Init(ctx, samples)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgo func() {\n\t\t\t\tdefer close(done)\n\t\t\t\tdefer stopEmission()\n\t\t\t\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t\t\t}()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-samples:\n\t\t\t\tcase <-done:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestSchedulerRunEnv(t *testing.T) {\n\tt.Parallel()\n\n\tscriptTemplate := `\n\timport { Counter } from \"k6/metrics\";\n\n\tlet errors = new Counter(\"errors\");\n\n\texport let options = {\n\t\tscenarios: {\n\t\t\texecutor: {\n\t\t\t\texecutor: \"%[1]s\",\n\t\t\t\t%[2]s\n\t\t\t}\n\t\t}\n\t}\n\n\texport default function () {\n\t\tif (__ENV.TESTVAR !== \"%[3]s\") {\n\t\t    console.error('Wrong env var value. Expected: %[3]s, actual: ', __ENV.TESTVAR);\n\t\t\terrors.add(1);\n\t\t}\n\t}`\n\n\texecutorConfigs := map[string]string{\n\t\t\"constant-arrival-rate\": `\n\t\t\trate: 1,\n\t\t\ttimeUnit: \"1s\",\n\t\t\tduration: \"1s\",\n\t\t\tpreAllocatedVUs: 1,\n\t\t\tmaxVUs: 2,\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"constant-vus\": `\n\t\t\tvus: 1,\n\t\t\tduration: \"1s\",\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"externally-controlled\": `\n\t\t\tvus: 1,\n\t\t\tduration: \"1s\",`,\n\t\t\"per-vu-iterations\": `\n\t\t\tvus: 1,\n\t\t\titerations: 1,\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"shared-iterations\": `\n\t\t\tvus: 1,\n\t\t\titerations: 1,\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"ramping-arrival-rate\": `\n\t\t\tstartRate: 1,\n\t\t\ttimeUnit: \"0.5s\",\n\t\t\tpreAllocatedVUs: 1,\n\t\t\tmaxVUs: 2,\n\t\t\tstages: [ { target: 1, duration: \"1s\" } ],\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"ramping-vus\": `\n\t\t\tstartVUs: 1,\n\t\t\tstages: [ { target: 1, duration: \"1s\" } ],\n\t\t\tgracefulStop: \"0.5s\",`,\n\t}\n\n\ttestCases := make([]struct{ name, script string }, 0, 2*len(executorConfigs))\n\n\t// Generate tests using global env and with env override\n\tfor ename, econf := range executorConfigs {\n\t\ttestCases = append(testCases, struct{ name, script string }{\n\t\t\t\"global/\" + ename, fmt.Sprintf(scriptTemplate, ename, econf, \"global\"),\n\t\t})\n\t\tconfigWithEnvOverride := econf + \"env: { TESTVAR: 'overridden' }\"\n\t\ttestCases = append(testCases, struct{ name, script string }{\n\t\t\t\"override/\" + ename, fmt.Sprintf(scriptTemplate, ename, configWithEnvOverride, \"overridden\"),\n\t\t})\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpiState := getTestPreInitState(t)\n\t\t\tpiState.RuntimeOptions = lib.RuntimeOptions{Env: map[string]string{\"TESTVAR\": \"global\"}}\n\t\t\tsourceData := &loader.SourceData{\n\t\t\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\t\t\tData: []byte(tc.script),\n\t\t\t}\n\t\t\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\t\t\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestRunState := getTestRunState(t, piState, runner.GetOptions(), runner)\n\t\t\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tctx := t.Context()\n\n\t\t\tdone := make(chan struct{})\n\t\t\tsamples := make(chan metrics.SampleContainer)\n\t\t\tdefer close(samples)\n\n\t\t\tstopEmission, err := execScheduler.Init(ctx, samples)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgo func() {\n\t\t\t\tdefer close(done)\n\t\t\t\tdefer stopEmission()\n\t\t\t\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t\t\t}()\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase sample := <-samples:\n\t\t\t\t\tif s, ok := sample.(metrics.Sample); ok && s.Metric.Name == \"errors\" {\n\t\t\t\t\t\tassert.FailNow(t, \"received error sample from test\")\n\t\t\t\t\t}\n\t\t\t\tcase <-done:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestSchedulerSystemTags(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\tscript := sr(`\n\timport http from \"k6/http\";\n\n\texport let options = {\n\t\tscenarios: {\n\t\t\tper_vu_test: {\n\t\t\t\texecutor: \"per-vu-iterations\",\n\t\t\t\tgracefulStop: \"0s\",\n\t\t\t\tvus: 1,\n\t\t\t\titerations: 1,\n\t\t\t},\n\t\t\tshared_test: {\n\t\t\t\texecutor: \"shared-iterations\",\n\t\t\t\tgracefulStop: \"0s\",\n\t\t\t\tvus: 1,\n\t\t\t\titerations: 1,\n\t\t\t}\n\t\t}\n\t}\n\n\texport default function () {\n\t\thttp.get(\"HTTPBIN_IP_URL/\");\n\t}`)\n\n\tpiState := getTestPreInitState(t)\n\tsourceData := &loader.SourceData{\n\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\tData: []byte(script),\n\t}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, runner.SetOptions(runner.GetOptions().Apply(lib.Options{\n\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t})))\n\n\ttestRunState := getTestRunState(t, piState, runner.GetOptions(), runner)\n\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n\tdefer cancel()\n\n\tsamples := make(chan metrics.SampleContainer)\n\tdefer close(samples)\n\n\tstopEmission, err := execScheduler.Init(ctx, samples)\n\trequire.NoError(t, err)\n\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tdefer close(done)\n\t\tdefer stopEmission()\n\t\trequire.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t}()\n\n\texpCommonTrailTags := testRunState.RunTags.\n\t\tWith(\"group\", \"\").\n\t\tWith(\"method\", \"GET\").\n\t\tWith(\"name\", sr(\"HTTPBIN_IP_URL/\")).\n\t\tWith(\"url\", sr(\"HTTPBIN_IP_URL/\")).\n\t\tWith(\"proto\", \"HTTP/1.1\").\n\t\tWith(\"status\", \"200\").\n\t\tWith(\"expected_response\", \"true\")\n\n\texpTrailPVUTags := expCommonTrailTags.With(\"scenario\", \"per_vu_test\")\n\texpTrailSITags := expCommonTrailTags.With(\"scenario\", \"shared_test\")\n\texpDataSentPVUTags := testRunState.RunTags.With(\"group\", \"\").With(\"scenario\", \"per_vu_test\")\n\texpDataSentSITags := testRunState.RunTags.With(\"group\", \"\").With(\"scenario\", \"shared_test\")\n\n\tvar gotCorrectTags int\n\tfor {\n\t\tselect {\n\t\tcase sample := <-samples:\n\t\t\tswitch s := sample.(type) {\n\t\t\tcase *httpext.Trail:\n\t\t\t\tif s.Tags == expTrailPVUTags || s.Tags == expTrailSITags {\n\t\t\t\t\tgotCorrectTags++\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tfor _, sample := range s.GetSamples() {\n\t\t\t\t\tif sample.Metric.Name == metrics.DataSentName {\n\t\t\t\t\t\tif sample.Tags == expDataSentPVUTags || sample.Tags == expDataSentSITags {\n\t\t\t\t\t\t\tgotCorrectTags++\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase <-done:\n\t\t\tassert.Equal(t, 4, gotCorrectTags, \"received wrong amount of samples with expected tags\")\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestSchedulerRunCustomTags(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\tscriptTemplate := sr(`\n\timport http from \"k6/http\";\n\n\texport let options = {\n\t\tscenarios: {\n\t\t\texecutor: {\n\t\t\t\texecutor: \"%s\",\n\t\t\t\t%s\n\t\t\t}\n\t\t}\n\t}\n\n\texport default function () {\n\t\thttp.get(\"HTTPBIN_IP_URL/\");\n\t}`)\n\n\texecutorConfigs := map[string]string{\n\t\t\"constant-arrival-rate\": `\n\t\t\trate: 1,\n\t\t\ttimeUnit: \"1s\",\n\t\t\tduration: \"1s\",\n\t\t\tpreAllocatedVUs: 1,\n\t\t\tmaxVUs: 2,\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"constant-vus\": `\n\t\t\tvus: 1,\n\t\t\tduration: \"1s\",\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"externally-controlled\": `\n\t\t\tvus: 1,\n\t\t\tduration: \"1s\",`,\n\t\t\"per-vu-iterations\": `\n\t\t\tvus: 1,\n\t\t\titerations: 1,\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"shared-iterations\": `\n\t\t\tvus: 1,\n\t\t\titerations: 1,\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"ramping-arrival-rate\": `\n\t\t\tstartRate: 5,\n\t\t\ttimeUnit: \"0.5s\",\n\t\t\tpreAllocatedVUs: 1,\n\t\t\tmaxVUs: 2,\n\t\t\tstages: [ { target: 10, duration: \"1s\" } ],\n\t\t\tgracefulStop: \"0.5s\",`,\n\t\t\"ramping-vus\": `\n\t\t\tstartVUs: 1,\n\t\t\tstages: [ { target: 1, duration: \"0.5s\" } ],\n\t\t\tgracefulStop: \"0.5s\",`,\n\t}\n\n\ttestCases := make([]struct{ name, script string }, 0, len(executorConfigs))\n\n\t// Generate tests using custom tags\n\tfor ename, econf := range executorConfigs {\n\t\tconfigWithCustomTag := econf + \"tags: { customTag: 'value' }\"\n\t\ttestCases = append(testCases, struct{ name, script string }{\n\t\t\tename, fmt.Sprintf(scriptTemplate, ename, configWithCustomTag),\n\t\t})\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpiState := getTestPreInitState(t)\n\t\t\tsourceData := &loader.SourceData{\n\t\t\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\t\t\tData: []byte(tc.script),\n\t\t\t}\n\t\t\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\t\t\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestRunState := getTestRunState(t, piState, runner.GetOptions(), runner)\n\t\t\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tdone := make(chan struct{})\n\t\t\tsamples := make(chan metrics.SampleContainer)\n\t\t\tdefer close(samples)\n\n\t\t\tstopEmission, err := execScheduler.Init(ctx, samples)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgo func() {\n\t\t\t\tdefer close(done)\n\t\t\t\tdefer stopEmission()\n\t\t\t\trequire.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t\t\t}()\n\t\t\tvar gotTrailTag, gotDataSentTag bool\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase sample := <-samples:\n\t\t\t\t\tif trail, ok := sample.(*httpext.Trail); ok && !gotTrailTag {\n\t\t\t\t\t\ttags := trail.Tags.Map()\n\t\t\t\t\t\tif v, ok := tags[\"customTag\"]; ok && v == \"value\" {\n\t\t\t\t\t\t\tgotTrailTag = true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor _, s := range sample.GetSamples() {\n\t\t\t\t\t\tif s.Metric.Name == metrics.DataSentName && !gotDataSentTag {\n\t\t\t\t\t\t\ttags := s.Tags.Map()\n\t\t\t\t\t\t\tif v, ok := tags[\"customTag\"]; ok && v == \"value\" {\n\t\t\t\t\t\t\t\tgotDataSentTag = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tcase <-done:\n\t\t\t\t\tif !gotTrailTag || !gotDataSentTag {\n\t\t\t\t\t\tassert.FailNow(t, \"a sample with expected tag wasn't received\")\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\n// Ensure that custom executor settings are unique per executor and\n// that there's no \"crossover\"/\"pollution\" between executors.\n// Also test that custom tags are properly set on checks and groups metrics.\nfunc TestSchedulerRunCustomConfigNoCrossover(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tscript := tb.Replacer.Replace(`\n\timport http from \"k6/http\";\n\timport ws from 'k6/ws';\n\timport { Counter } from 'k6/metrics';\n\timport { check, group } from 'k6';\n\n\tlet errors = new Counter('errors');\n\n\texport let options = {\n\t\t// Required for WS tests\n\t\thosts: { 'httpbin.local': '127.0.0.1' },\n\t\tscenarios: {\n\t\t\tscenario1: {\n\t\t\t\texecutor: 'per-vu-iterations',\n\t\t\t\tvus: 1,\n\t\t\t\titerations: 1,\n\t\t\t\tgracefulStop: '0s',\n\t\t\t\tmaxDuration: '1s',\n\t\t\t\texec: 's1func',\n\t\t\t\tenv: { TESTVAR1: 'scenario1' },\n\t\t\t\ttags: { testtag1: 'scenario1' },\n\t\t\t},\n\t\t\tscenario2: {\n\t\t\t\texecutor: 'shared-iterations',\n\t\t\t\tvus: 1,\n\t\t\t\titerations: 1,\n\t\t\t\tgracefulStop: '1s',\n\t\t\t\tstartTime: '0.5s',\n\t\t\t\tmaxDuration: '2s',\n\t\t\t\texec: 's2func',\n\t\t\t\tenv: { TESTVAR2: 'scenario2' },\n\t\t\t\ttags: { testtag2: 'scenario2' },\n\t\t\t},\n\t\t\tscenario3: {\n\t\t\t\texecutor: 'per-vu-iterations',\n\t\t\t\tvus: 1,\n\t\t\t\titerations: 1,\n\t\t\t\tgracefulStop: '1s',\n\t\t\t\texec: 's3funcWS',\n\t\t\t\tenv: { TESTVAR3: 'scenario3' },\n\t\t\t\ttags: { testtag3: 'scenario3' },\n\t\t\t},\n\t\t}\n\t}\n\n\tfunction checkVar(name, expected) {\n\t\tif (__ENV[name] !== expected) {\n\t\t    console.error('Wrong ' + name + \" env var value. Expected: '\"\n\t\t\t\t\t\t+ expected + \"', actual: '\" + __ENV[name] + \"'\");\n\t\t\terrors.add(1);\n\t\t}\n\t}\n\n\texport function s1func() {\n\t\tcheckVar('TESTVAR1', 'scenario1');\n\t\tcheckVar('TESTVAR2', undefined);\n\t\tcheckVar('TESTVAR3', undefined);\n\t\tcheckVar('TESTGLOBALVAR', 'global');\n\n\t\t// Intentionally try to pollute the env\n\t\t__ENV.TESTVAR2 = 'overridden';\n\n\t\thttp.get('HTTPBIN_IP_URL/', { tags: { reqtag: 'scenario1' }});\n\t}\n\n\texport function s2func() {\n\t\tcheckVar('TESTVAR1', undefined);\n\t\tcheckVar('TESTVAR2', 'scenario2');\n\t\tcheckVar('TESTVAR3', undefined);\n\t\tcheckVar('TESTGLOBALVAR', 'global');\n\n\t\thttp.get('HTTPBIN_IP_URL/', { tags: { reqtag: 'scenario2' }});\n\t}\n\n\texport function s3funcWS() {\n\t\tcheckVar('TESTVAR1', undefined);\n\t\tcheckVar('TESTVAR2', undefined);\n\t\tcheckVar('TESTVAR3', 'scenario3');\n\t\tcheckVar('TESTGLOBALVAR', 'global');\n\n\t\tconst customTags = { wstag: 'scenario3' };\n\t\tgroup('wsgroup', function() {\n\t\t\tconst response = ws.connect('WSBIN_URL/ws-echo', { tags: customTags },\n\t\t\t\tfunction (socket) {\n\t\t\t\t\tsocket.on('open', function() {\n\t\t\t\t\t\tsocket.send('hello');\n\t\t\t\t\t});\n\t\t\t\t\tsocket.on('message', function(msg) {\n\t\t\t\t\t\tif (msg != 'hello') {\n\t\t\t\t\t\t    console.error(\"Expected to receive 'hello' but got '\" + msg + \"' instead!\");\n\t\t\t\t\t\t\terrors.add(1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsocket.close()\n\t\t\t\t\t});\n\t\t\t\t\tsocket.on('error', function (e) {\n\t\t\t\t\t\tconsole.log('ws error: ' + e.error());\n\t\t\t\t\t\terrors.add(1);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t);\n\t\t\tcheck(response, { 'status is 101': (r) => r && r.status === 101 }, customTags);\n\t\t});\n\t}\n`)\n\n\tpiState := getTestPreInitState(t)\n\tpiState.RuntimeOptions.Env = map[string]string{\"TESTGLOBALVAR\": \"global\"}\n\tsourceData := &loader.SourceData{\n\t\tURL:  &url.URL{Path: \"/script.js\"},\n\t\tData: []byte(script),\n\t}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\trequire.NoError(t, err)\n\n\ttestRunState := getTestRunState(t, piState, runner.GetOptions(), runner)\n\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n\tdefer cancel()\n\n\tsamples := make(chan metrics.SampleContainer)\n\n\tstopEmission, err := execScheduler.Init(ctx, samples)\n\trequire.NoError(t, err)\n\n\tgo func() {\n\t\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t\tstopEmission()\n\t\tclose(samples)\n\t}()\n\n\texpectedTrailTags := []map[string]string{\n\t\t{\"testtag1\": \"scenario1\", \"reqtag\": \"scenario1\"},\n\t\t{\"testtag2\": \"scenario2\", \"reqtag\": \"scenario2\"},\n\t}\n\texpectedNetTrailTags := []map[string]string{\n\t\t{\"testtag1\": \"scenario1\"},\n\t\t{\"testtag2\": \"scenario2\"},\n\t}\n\texpectedConnSampleTags := map[string]string{\n\t\t\"testtag3\": \"scenario3\", \"wstag\": \"scenario3\",\n\t}\n\texpectedPlainSampleTags := []map[string]string{\n\t\t{\"testtag3\": \"scenario3\"},\n\t\t{\"testtag3\": \"scenario3\", \"wstag\": \"scenario3\"},\n\t}\n\tvar gotSampleTags int\n\tfor sample := range samples {\n\t\tswitch s := sample.(type) {\n\t\tcase metrics.Sample:\n\t\t\tif s.Metric.Name == \"errors\" {\n\t\t\t\tassert.FailNow(t, \"received error sample from test\")\n\t\t\t}\n\t\t\tif s.Metric.Name == \"checks\" || s.Metric.Name == \"group_duration\" {\n\t\t\t\ttags := s.Tags.Map()\n\t\t\t\tfor _, expTags := range expectedPlainSampleTags {\n\t\t\t\t\tif reflect.DeepEqual(expTags, tags) {\n\t\t\t\t\t\tgotSampleTags++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase *httpext.Trail:\n\t\t\ttags := s.Tags.Map()\n\t\t\tfor _, expTags := range expectedTrailTags {\n\t\t\t\tif reflect.DeepEqual(expTags, tags) {\n\t\t\t\t\tgotSampleTags++\n\t\t\t\t}\n\t\t\t}\n\t\tcase metrics.Samples:\n\t\t\tfor _, sample := range s.GetSamples() {\n\t\t\t\tif sample.Metric.Name == metrics.DataSentName {\n\t\t\t\t\ttags := sample.Tags.Map()\n\t\t\t\t\tfor _, expTags := range expectedNetTrailTags {\n\t\t\t\t\t\tif reflect.DeepEqual(expTags, tags) {\n\t\t\t\t\t\t\tgotSampleTags++\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\tcase metrics.ConnectedSamples:\n\t\t\tfor _, sm := range s.Samples {\n\t\t\t\ttags := sm.Tags.Map()\n\t\t\t\tif reflect.DeepEqual(expectedConnSampleTags, tags) {\n\t\t\t\t\tgotSampleTags++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\trequire.Equal(t, 8, gotSampleTags, \"received wrong amount of samples with expected tags\")\n}\n\nfunc TestSchedulerSetupTeardownRun(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Normal\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tsetupC := make(chan struct{})\n\t\tteardownC := make(chan struct{})\n\t\trunner := &minirunner.MiniRunner{\n\t\t\tSetupFn: func(_ context.Context, _ chan<- metrics.SampleContainer) ([]byte, error) {\n\t\t\t\tclose(setupC)\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t\tTeardownFn: func(_ context.Context, _ chan<- metrics.SampleContainer) error {\n\t\t\t\tclose(teardownC)\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, nil, lib.Options{})\n\n\t\terr := make(chan error, 1)\n\t\tgo func() { err <- execScheduler.Run(ctx, ctx, samples) }()\n\t\tdefer cancel()\n\t\t<-setupC\n\t\t<-teardownC\n\t\tassert.NoError(t, <-err)\n\t})\n\tt.Run(\"Setup Error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trunner := &minirunner.MiniRunner{\n\t\t\tSetupFn: func(_ context.Context, _ chan<- metrics.SampleContainer) ([]byte, error) {\n\t\t\t\treturn nil, errors.New(\"setup error\")\n\t\t\t},\n\t\t}\n\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, nil, lib.Options{})\n\t\tdefer cancel()\n\t\tassert.EqualError(t, execScheduler.Run(ctx, ctx, samples), \"setup error\")\n\t})\n\tt.Run(\"Don't Run Setup\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trunner := &minirunner.MiniRunner{\n\t\t\tSetupFn: func(_ context.Context, _ chan<- metrics.SampleContainer) ([]byte, error) {\n\t\t\t\treturn nil, errors.New(\"setup _\")\n\t\t\t},\n\t\t\tTeardownFn: func(_ context.Context, _ chan<- metrics.SampleContainer) error {\n\t\t\t\treturn errors.New(\"teardown error\")\n\t\t\t},\n\t\t}\n\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, nil, lib.Options{\n\t\t\tNoSetup:    null.BoolFrom(true),\n\t\t\tVUs:        null.IntFrom(1),\n\t\t\tIterations: null.IntFrom(1),\n\t\t})\n\t\tdefer cancel()\n\t\tassert.EqualError(t, execScheduler.Run(ctx, ctx, samples), \"teardown error\")\n\t})\n\n\tt.Run(\"Teardown Error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trunner := &minirunner.MiniRunner{\n\t\t\tSetupFn: func(_ context.Context, _ chan<- metrics.SampleContainer) ([]byte, error) {\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t\tTeardownFn: func(_ context.Context, _ chan<- metrics.SampleContainer) error {\n\t\t\t\treturn errors.New(\"teardown error\")\n\t\t\t},\n\t\t}\n\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, nil, lib.Options{\n\t\t\tVUs:        null.IntFrom(1),\n\t\t\tIterations: null.IntFrom(1),\n\t\t})\n\t\tdefer cancel()\n\n\t\tassert.EqualError(t, execScheduler.Run(ctx, ctx, samples), \"teardown error\")\n\t})\n\tt.Run(\"Don't Run Teardown\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trunner := &minirunner.MiniRunner{\n\t\t\tSetupFn: func(_ context.Context, _ chan<- metrics.SampleContainer) ([]byte, error) {\n\t\t\t\treturn nil, nil\n\t\t\t},\n\t\t\tTeardownFn: func(_ context.Context, _ chan<- metrics.SampleContainer) error {\n\t\t\t\treturn errors.New(\"teardown error\")\n\t\t\t},\n\t\t}\n\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, nil, lib.Options{\n\t\t\tNoTeardown: null.BoolFrom(true),\n\t\t\tVUs:        null.IntFrom(1),\n\t\t\tIterations: null.IntFrom(1),\n\t\t})\n\t\tdefer cancel()\n\t\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t})\n}\n\nfunc TestSchedulerStages(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]struct {\n\t\tDuration time.Duration\n\t\tStages   []lib.Stage\n\t}{\n\t\t\"one\": {\n\t\t\t1 * time.Second,\n\t\t\t[]lib.Stage{{Duration: types.NullDurationFrom(1 * time.Second), Target: null.IntFrom(1)}},\n\t\t},\n\t\t\"two\": {\n\t\t\t2 * time.Second,\n\t\t\t[]lib.Stage{\n\t\t\t\t{Duration: types.NullDurationFrom(1 * time.Second), Target: null.IntFrom(1)},\n\t\t\t\t{Duration: types.NullDurationFrom(1 * time.Second), Target: null.IntFrom(2)},\n\t\t\t},\n\t\t},\n\t\t\"four\": {\n\t\t\t4 * time.Second,\n\t\t\t[]lib.Stage{\n\t\t\t\t{Duration: types.NullDurationFrom(1 * time.Second), Target: null.IntFrom(5)},\n\t\t\t\t{Duration: types.NullDurationFrom(3 * time.Second), Target: null.IntFrom(10)},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trunner := &minirunner.MiniRunner{\n\t\t\t\tFn: func(_ context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t}\n\t\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, nil, lib.Options{\n\t\t\t\tVUs:    null.IntFrom(1),\n\t\t\t\tStages: data.Stages,\n\t\t\t})\n\t\t\tdefer cancel()\n\t\t\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t\t\tassert.True(t, execScheduler.GetState().GetCurrentTestRunDuration() >= data.Duration)\n\t\t})\n\t}\n}\n\nfunc TestSchedulerEndTime(t *testing.T) {\n\tt.Parallel()\n\trunner := &minirunner.MiniRunner{\n\t\tFn: func(_ context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\treturn nil\n\t\t},\n\t}\n\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, nil, lib.Options{\n\t\tVUs:      null.IntFrom(10),\n\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t})\n\tdefer cancel()\n\n\tendTime, isFinal := lib.GetEndOffset(execScheduler.GetExecutionPlan())\n\tassert.Equal(t, 31*time.Second, endTime) // because of the default 30s gracefulStop\n\tassert.True(t, isFinal)\n\n\tstartTime := time.Now()\n\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\trunTime := time.Since(startTime)\n\tassert.True(t, runTime > 1*time.Second, \"test did not take 1s\")\n\tassert.True(t, runTime < 10*time.Second, \"took more than 10 seconds\")\n}\n\nfunc TestSchedulerRuntimeErrors(t *testing.T) {\n\tt.Parallel()\n\trunner := &minirunner.MiniRunner{\n\t\tFn: func(_ context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\treturn errors.New(\"hi\")\n\t\t},\n\t\tOptions: lib.Options{\n\t\t\tVUs:      null.IntFrom(10),\n\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t},\n\t}\n\tlogger, hook := logtest.NewNullLogger()\n\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, logger, lib.Options{})\n\tdefer cancel()\n\n\tendTime, isFinal := lib.GetEndOffset(execScheduler.GetExecutionPlan())\n\tassert.Equal(t, 31*time.Second, endTime) // because of the default 30s gracefulStop\n\tassert.True(t, isFinal)\n\n\tstartTime := time.Now()\n\trequire.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\trunTime := time.Since(startTime)\n\tassert.True(t, runTime > 1*time.Second, \"test did not take 1s\")\n\tassert.True(t, runTime < 10*time.Second, \"took more than 10 seconds\")\n\n\tassert.NotEmpty(t, hook.Entries)\n\tfor _, e := range hook.Entries {\n\t\tassert.Equal(t, \"hi\", e.Message)\n\t}\n}\n\nfunc TestSchedulerEndErrors(t *testing.T) {\n\tt.Parallel()\n\n\texec := executor.NewConstantVUsConfig(\"we_need_hard_stop\")\n\texec.VUs = null.IntFrom(10)\n\texec.Duration = types.NullDurationFrom(1 * time.Second)\n\texec.GracefulStop = types.NullDurationFrom(0 * time.Second)\n\n\trunner := &minirunner.MiniRunner{\n\t\tFn: func(ctx context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\t\t<-ctx.Done()\n\t\t\treturn errors.New(\"hi\")\n\t\t},\n\t\tOptions: lib.Options{\n\t\t\tScenarios: lib.ScenarioConfigs{exec.GetName(): exec},\n\t\t},\n\t}\n\tlogger, hook := logtest.NewNullLogger()\n\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, logger, lib.Options{})\n\tdefer cancel()\n\n\tendTime, isFinal := lib.GetEndOffset(execScheduler.GetExecutionPlan())\n\tassert.Equal(t, 1*time.Second, endTime) // because of the 0s gracefulStop\n\tassert.True(t, isFinal)\n\n\tstartTime := time.Now()\n\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\trunTime := time.Since(startTime)\n\tassert.True(t, runTime > 1*time.Second, \"test did not take 1s\")\n\tassert.True(t, runTime < 10*time.Second, \"took more than 10 seconds\")\n\n\tassert.Empty(t, hook.Entries)\n}\n\nfunc TestSchedulerEndIterations(t *testing.T) {\n\tt.Parallel()\n\tregistry := metrics.NewRegistry()\n\tmetric := registry.MustNewMetric(\"test_metric\", metrics.Counter)\n\tts := metrics.TimeSeries{\n\t\tMetric: metric,\n\t\tTags:   registry.RootTagSet(),\n\t}\n\n\toptions, err := executor.DeriveScenariosFromShortcuts(lib.Options{\n\t\tVUs:        null.IntFrom(1),\n\t\tIterations: null.IntFrom(100),\n\t}, nil)\n\trequire.NoError(t, err)\n\trequire.Empty(t, options.Validate())\n\n\tvar i int64\n\trunner := &minirunner.MiniRunner{\n\t\tFn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error {\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\tdefault:\n\t\t\t\tatomic.AddInt64(&i, 1)\n\t\t\t}\n\t\t\tout <- metrics.Sample{\n\t\t\t\tTimeSeries: ts,\n\t\t\t\tValue:      1.0,\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t\tOptions: options,\n\t}\n\n\tctx := t.Context()\n\n\ttestRunState := getTestRunState(t, getTestPreInitState(t), runner.GetOptions(), runner)\n\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\trequire.NoError(t, err)\n\n\tsamples := make(chan metrics.SampleContainer, 300)\n\tdefer close(samples)\n\n\tstopEmission, err := execScheduler.Init(ctx, samples)\n\trequire.NoError(t, err)\n\tdefer stopEmission()\n\n\trequire.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\n\tassert.Equal(t, uint64(100), execScheduler.GetState().GetFullIterationCount())\n\tassert.Equal(t, uint64(0), execScheduler.GetState().GetPartialIterationCount())\n\tassert.Equal(t, int64(100), i)\n\trequire.Equal(t, 100, len(samples)) // TODO: change to 200 https://github.com/k6io/k6/issues/1250\n\tfor range 100 {\n\t\tmySample, ok := <-samples\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, metrics.Sample{TimeSeries: ts, Value: 1.0}, mySample)\n\t}\n}\n\nfunc TestSchedulerIsRunning(t *testing.T) {\n\tt.Parallel()\n\trunner := &minirunner.MiniRunner{\n\t\tFn: func(ctx context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\t\t<-ctx.Done()\n\t\t\treturn nil\n\t\t},\n\t}\n\tctx, cancel, execScheduler, _ := newTestScheduler(t, runner, nil, lib.Options{})\n\tstate := execScheduler.GetState()\n\n\terr := make(chan error)\n\tgo func() { err <- execScheduler.Run(ctx, ctx, nil) }()\n\tfor !state.HasStarted() {\n\t\ttime.Sleep(10 * time.Microsecond)\n\t}\n\tcancel()\n\tfor !state.HasEnded() {\n\t\ttime.Sleep(10 * time.Microsecond)\n\t}\n\tassert.NoError(t, <-err)\n}\n\n// TestDNSResolverCache checks the DNS resolution behavior at the Scheduler level.\nfunc TestDNSResolverCache(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\tscript := sr(`\n\t\timport http from \"k6/http\";\n\t\timport { sleep } from \"k6\";\n\n\t\texport let options = {\n\t\t\tvus: 1,\n\t\t\titerations: 8,\n\t\t\tnoConnectionReuse: true,\n\t\t}\n\n\t\texport default function () {\n\t\t\tconst res = http.get(\"http://myhost:HTTPBIN_PORT/\", { timeout: 50 });\n\t\t\tsleep(0.7);  // somewhat uneven multiple of 0.5 to minimize races with asserts\n\t\t}`)\n\n\ttestCases := map[string]struct {\n\t\topts lib.Options\n\t\t// Amount of expected resolutions after the IP change.\n\t\t// This will demonstrate how the cache is being used, depending on the\n\t\t// configured TTL.\n\t\texpNewResolutions uint32\n\t}{\n\t\t\"default\": {\n\t\t\t// IPs are cached for 5m, so no new resolution attempts will be made.\n\t\t\topts:              lib.Options{DNS: types.DefaultDNSConfig()},\n\t\t\texpNewResolutions: 0,\n\t\t},\n\t\t\"0ok\": {\n\t\t\t// The cache is disabled, so every request does a DNS lookup.\n\t\t\topts: lib.Options{DNS: types.DNSConfig{\n\t\t\t\tTTL:    null.StringFrom(\"0\"),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSfirst, Valid: true},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv4, Valid: false},\n\t\t\t}},\n\t\t\texpNewResolutions: 7,\n\t\t},\n\t\t\"1700\": {\n\t\t\t// IPs are cached for 1.7s.\n\t\t\t// This also checks that unitless values are interpreted as ms.\n\t\t\topts: lib.Options{DNS: types.DNSConfig{\n\t\t\t\tTTL:    null.StringFrom(\"1700\"),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSfirst, Valid: true},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv4, Valid: false},\n\t\t\t}},\n\t\t\texpNewResolutions: 2,\n\t\t},\n\t\t\"3s\": {\n\t\t\topts: lib.Options{DNS: types.DNSConfig{\n\t\t\t\tTTL:    null.StringFrom(\"3s\"),\n\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSfirst, Valid: true},\n\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSpreferIPv4, Valid: false},\n\t\t\t}},\n\t\t\texpNewResolutions: 1,\n\t\t},\n\t}\n\n\tfor name, tc := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tlogger := logrus.New()\n\t\t\tlogger.SetOutput(io.Discard)\n\t\t\tlogHook := testutils.NewLogHook(logrus.WarnLevel)\n\t\t\tlogger.AddHook(logHook)\n\n\t\t\tregistry := metrics.NewRegistry()\n\t\t\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\t\t\tpiState := &lib.TestPreInitState{\n\t\t\t\tLogger:         logger,\n\t\t\t\tBuiltinMetrics: builtinMetrics,\n\t\t\t\tRegistry:       registry,\n\t\t\t\tUsage:          usage.New(),\n\t\t\t}\n\t\t\tsourceData := &loader.SourceData{\n\t\t\t\tURL: &url.URL{Path: \"/script.js\"}, Data: []byte(script),\n\t\t\t}\n\t\t\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\t\t\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmr := mockresolver.New(map[string][]net.IP{\"myhost\": {net.ParseIP(sr(\"HTTPBIN_IP\"))}})\n\t\t\tvar newResolutions uint32\n\t\t\tresolveHook := func(_ string, result []net.IP) {\n\t\t\t\trequire.Len(t, result, 1)\n\t\t\t\tif result[0].String() == \"127.0.0.1\" {\n\t\t\t\t\tmr.Set(\"myhost\", \"127.0.0.254\")\n\t\t\t\t} else {\n\t\t\t\t\tatomic.AddUint32(&newResolutions, 1)\n\t\t\t\t}\n\t\t\t}\n\t\t\tmr.ResolveHook = resolveHook\n\t\t\trunner.ActualResolver = mr.LookupIPAll\n\n\t\t\tctx, cancel, execScheduler, samples := newTestScheduler(t, runner, logger, tc.opts)\n\t\t\tdefer cancel()\n\n\t\t\terrCh := make(chan error, 1)\n\t\t\tgo func() { errCh <- execScheduler.Run(ctx, ctx, samples) }()\n\n\t\t\tselect {\n\t\t\tcase err := <-errCh:\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expNewResolutions, atomic.LoadUint32(&newResolutions))\n\t\t\tcase <-time.After(10 * time.Second):\n\t\t\t\tt.Fatal(\"timed out\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestRealTimeAndSetupTeardownMetrics(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\timport { Counter } from \"k6/metrics\";\n\timport { sleep } from \"k6\";\n\n\tvar counter = new Counter(\"test_counter\");\n\n\texport function setup() {\n\t\tconsole.log(\"setup(), sleeping for 1 second\");\n\t\tcounter.add(1, { place: \"setupBeforeSleep\" });\n\t\tsleep(1);\n\t\tconsole.log(\"setup sleep is done\");\n\t\tcounter.add(2, { place: \"setupAfterSleep\" });\n\t\treturn { \"some\": [\"data\"], \"v\": 1 };\n\t}\n\n\texport function teardown(data) {\n\t\tconsole.log(\"teardown(\" + JSON.stringify(data) + \"), sleeping for 1 second\");\n\t\tcounter.add(3, { place: \"teardownBeforeSleep\" });\n\t\tsleep(1);\n\t\tif (!data || data.v != 1) {\n\t\t\tthrow new Error(\"incorrect data: \" + JSON.stringify(data));\n\t\t}\n\t\tconsole.log(\"teardown sleep is done\");\n\t\tcounter.add(4, { place: \"teardownAfterSleep\" });\n\t}\n\n\texport default function (data) {\n\t\tconsole.log(\"default(\" + JSON.stringify(data) + \") with ENV=\" + JSON.stringify(__ENV) + \" for in ITER \" + __ITER + \" and VU \" + __VU);\n\t\tcounter.add(5, { place: \"defaultBeforeSleep\" });\n\t\tif (!data || data.v != 1) {\n\t\t\tthrow new Error(\"incorrect data: \" + JSON.stringify(data));\n\t\t}\n\t\tsleep(1);\n\t\tconsole.log(\"default() for in ITER \" + __ITER + \" and VU \" + __VU + \" done!\");\n\t\tcounter.add(6, { place: \"defaultAfterSleep\" });\n\t}`)\n\n\tpiState := getTestPreInitState(t)\n\tsourceData := &loader.SourceData{URL: &url.URL{Path: \"/script.js\"}, Data: script}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\trequire.NoError(t, err)\n\n\toptions, err := executor.DeriveScenariosFromShortcuts(runner.GetOptions().Apply(lib.Options{\n\t\tIterations:      null.IntFrom(2),\n\t\tVUs:             null.IntFrom(1),\n\t\tSystemTags:      &metrics.DefaultSystemTagSet,\n\t\tSetupTimeout:    types.NullDurationFrom(4 * time.Second),\n\t\tTeardownTimeout: types.NullDurationFrom(4 * time.Second),\n\t}), nil)\n\trequire.NoError(t, err)\n\n\ttestRunState := getTestRunState(t, piState, options, runner)\n\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\trequire.NoError(t, err)\n\n\tctx := t.Context()\n\n\tdone := make(chan struct{})\n\tsamples := make(chan metrics.SampleContainer)\n\tdefer close(samples)\n\n\tstopEmission, err := execScheduler.Init(ctx, samples)\n\trequire.NoError(t, err)\n\n\tgo func() {\n\t\tdefer close(done)\n\t\tdefer stopEmission()\n\t\tassert.NoError(t, execScheduler.Run(ctx, ctx, samples))\n\t}()\n\n\texpectIn := func(fromMs, toMs int64, expected metrics.SampleContainer) {\n\t\tstart := time.Now()\n\t\tfrom := time.Duration(fromMs) * time.Millisecond\n\t\tto := time.Duration(toMs) * time.Millisecond\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase sampleContainer := <-samples:\n\t\t\t\tgotVus := false\n\t\t\t\tfor _, s := range sampleContainer.GetSamples() {\n\t\t\t\t\tif s.Metric == piState.BuiltinMetrics.VUs || s.Metric == piState.BuiltinMetrics.VUsMax {\n\t\t\t\t\t\tgotVus = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif gotVus {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tnow := time.Now()\n\t\t\t\telapsed := now.Sub(start)\n\t\t\t\tif elapsed < from {\n\t\t\t\t\tt.Errorf(\"Received sample earlier (%s) than expected (%s)\", elapsed, from)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tassert.IsType(t, expected, sampleContainer)\n\t\t\t\texpSamples := expected.GetSamples()\n\t\t\t\tgotSamples := sampleContainer.GetSamples()\n\t\t\t\tif assert.Len(t, gotSamples, len(expSamples)) {\n\t\t\t\t\tfor i, s := range gotSamples {\n\t\t\t\t\t\texpS := expSamples[i]\n\t\t\t\t\t\tif s.Metric.Name != metrics.IterationDurationName {\n\t\t\t\t\t\t\tassert.Equal(t, expS.Value, s.Value)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tassert.Equal(t, expS.Metric.Name, s.Metric.Name)\n\t\t\t\t\t\tassert.Equal(t, expS.Tags.Map(), s.Tags.Map())\n\t\t\t\t\t\tassert.InDelta(t, 0, now.Sub(s.Time), float64(50*time.Millisecond))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\tcase <-time.After(to):\n\t\t\t\tt.Errorf(\"Did not receive sample in the maximum allotted time (%s)\", to)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tgetTags := func(r *metrics.Registry, args ...string) *metrics.TagSet {\n\t\ttags := r.RootTagSet()\n\t\tfor i := 0; i < len(args)-1; i += 2 {\n\t\t\ttags = tags.With(args[i], args[i+1])\n\t\t}\n\t\treturn tags\n\t}\n\ttestCounter, err := piState.Registry.NewMetric(\"test_counter\", metrics.Counter)\n\trequire.NoError(t, err)\n\tgetSample := func(expValue float64, expMetric *metrics.Metric, expTags ...string) metrics.SampleContainer {\n\t\treturn metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: expMetric,\n\t\t\t\tTags:   getTags(piState.Registry, expTags...),\n\t\t\t},\n\t\t\tTime:  time.Now(),\n\t\t\tValue: expValue,\n\t\t}\n\t}\n\tgetNetworkSamples := func(group string, addExpTags ...string) metrics.SampleContainer {\n\t\texpTags := make([]string, 0, 2+len(addExpTags))\n\t\texpTags = append(expTags, \"group\", group)\n\t\texpTags = append(expTags, addExpTags...)\n\t\tdialer := netext.NewDialer(\n\t\t\tnet.Dialer{},\n\t\t\tnetext.NewResolver(net.LookupIP, 0, types.DNSfirst, types.DNSpreferIPv4),\n\t\t)\n\n\t\tctm := metrics.TagsAndMeta{Tags: getTags(piState.Registry, expTags...)}\n\t\treturn dialer.IOSamples(time.Now(), ctm, piState.BuiltinMetrics)\n\t}\n\n\tgetIterationsSamples := func(group string, addExpTags ...string) metrics.SampleContainer {\n\t\texpTags := make([]string, 0, 2+len(addExpTags))\n\t\texpTags = append(expTags, \"group\", group)\n\t\texpTags = append(expTags, addExpTags...)\n\t\tctm := metrics.TagsAndMeta{Tags: getTags(piState.Registry, expTags...)}\n\t\tstartTime := time.Now()\n\t\tendTime := time.Now()\n\n\t\treturn metrics.Samples([]metrics.Sample{\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: piState.BuiltinMetrics.IterationDuration,\n\t\t\t\t\tTags:   ctm.Tags,\n\t\t\t\t},\n\t\t\t\tTime:     endTime,\n\t\t\t\tMetadata: ctm.Metadata,\n\t\t\t\tValue:    metrics.D(endTime.Sub(startTime)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: piState.BuiltinMetrics.Iterations,\n\t\t\t\t\tTags:   ctm.Tags,\n\t\t\t\t},\n\t\t\t\tTime:     endTime,\n\t\t\t\tMetadata: ctm.Metadata,\n\t\t\t\tValue:    1,\n\t\t\t},\n\t\t})\n\t}\n\n\t// Initially give a long time (5s) for the execScheduler to start\n\texpectIn(0, 5000, getSample(1, testCounter, \"group\", \"::setup\", \"place\", \"setupBeforeSleep\"))\n\texpectIn(900, 1100, getSample(2, testCounter, \"group\", \"::setup\", \"place\", \"setupAfterSleep\"))\n\texpectIn(0, 100, getNetworkSamples(\"::setup\"))\n\n\texpectIn(0, 100, getSample(5, testCounter, \"group\", \"\", \"place\", \"defaultBeforeSleep\", \"scenario\", \"default\"))\n\texpectIn(900, 1100, getSample(6, testCounter, \"group\", \"\", \"place\", \"defaultAfterSleep\", \"scenario\", \"default\"))\n\texpectIn(0, 100, getNetworkSamples(\"\", \"scenario\", \"default\"))\n\texpectIn(0, 100, getIterationsSamples(\"\", \"scenario\", \"default\"))\n\n\texpectIn(0, 100, getSample(5, testCounter, \"group\", \"\", \"place\", \"defaultBeforeSleep\", \"scenario\", \"default\"))\n\texpectIn(900, 1100, getSample(6, testCounter, \"group\", \"\", \"place\", \"defaultAfterSleep\", \"scenario\", \"default\"))\n\texpectIn(0, 100, getNetworkSamples(\"\", \"scenario\", \"default\"))\n\texpectIn(0, 100, getIterationsSamples(\"\", \"scenario\", \"default\"))\n\n\texpectIn(0, 1000, getSample(3, testCounter, \"group\", \"::teardown\", \"place\", \"teardownBeforeSleep\"))\n\texpectIn(900, 1100, getSample(4, testCounter, \"group\", \"::teardown\", \"place\", \"teardownAfterSleep\"))\n\texpectIn(0, 100, getNetworkSamples(\"::teardown\"))\n\n\tfor {\n\t\tselect {\n\t\tcase s := <-samples:\n\t\t\tt.Fatalf(\"Did not expect anything in the sample channel bug got %#v\", s)\n\t\tcase <-time.After(3 * time.Second):\n\t\t\tt.Fatalf(\"Local execScheduler took way to long to finish\")\n\t\tcase <-done:\n\t\t\treturn // Exit normally\n\t\t}\n\t}\n}\n\nfunc TestNewSchedulerHasWork(t *testing.T) {\n\tt.Parallel()\n\tscript := []byte(`\n\t\timport http from 'k6/http';\n\n\t\texport let options = {\n\t\t\texecutionSegment: \"3/4:1\",\n\t\t\texecutionSegmentSequence: \"0,1/4,2/4,3/4,1\",\n\t\t\tscenarios: {\n\t\t\t\tshared_iters1: {\n\t\t\t\t\texecutor: \"shared-iterations\",\n\t\t\t\t\tvus: 3,\n\t\t\t\t\titerations: 3,\n\t\t\t\t},\n\t\t\t\tshared_iters2: {\n\t\t\t\t\texecutor: \"shared-iterations\",\n\t\t\t\t\tvus: 4,\n\t\t\t\t\titerations: 4,\n\t\t\t\t},\n\t\t\t\tconstant_arr_rate: {\n\t\t\t\t\texecutor: \"constant-arrival-rate\",\n\t\t\t\t\trate: 3,\n\t\t\t\t\ttimeUnit: \"1s\",\n\t\t\t\t\tduration: \"20s\",\n\t\t\t\t\tpreAllocatedVUs: 4,\n\t\t\t\t\tmaxVUs: 4,\n\t\t\t\t},\n\t\t    },\n\t\t};\n\n\t\texport default function() {\n\t\t\tconst response = http.get(\"http://test.loadimpact.com\");\n\t\t};\n`)\n\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tregistry := metrics.NewRegistry()\n\tpiState := &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tRegistry:       registry,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tUsage:          usage.New(),\n\t}\n\tsourceData := &loader.SourceData{URL: &url.URL{Path: \"/script.js\"}, Data: script}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\trequire.NoError(t, err)\n\n\ttestRunState := getTestRunState(t, piState, runner.GetOptions(), runner)\n\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\trequire.NoError(t, err)\n\n\tassert.Len(t, execScheduler.GetExecutors(), 2)\n\tassert.Len(t, execScheduler.GetExecutorConfigs(), 3)\n\n\terr = execScheduler.SetPaused(true)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"doesn't support pause and resume operations after its start\")\n}\n"
  },
  {
    "path": "internal/execution/scheduler_int_test.go",
    "content": "package execution\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc getBogusTestRunState(tb testing.TB) *lib.TestRunState {\n\treg := metrics.NewRegistry()\n\tpiState := &lib.TestPreInitState{\n\t\tLogger:         testutils.NewLogger(tb),\n\t\tRuntimeOptions: lib.RuntimeOptions{},\n\t\tRegistry:       reg,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(reg),\n\t}\n\n\treturn &lib.TestRunState{\n\t\tTestPreInitState: piState,\n\t\tOptions:          lib.Options{},\n\t\tRunner:           &minirunner.MiniRunner{},\n\t\tRunTags:          piState.Registry.RootTagSet(),\n\t}\n}\n\n// Just a lib.PausableExecutor implementation that can return an error\ntype pausableExecutor struct {\n\tlib.Executor\n\terr error\n}\n\nfunc (p pausableExecutor) SetPaused(bool) error {\n\treturn p.err\n}\n\nfunc TestSetPaused(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"second pause is an error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestRunState := getBogusTestRunState(t)\n\t\tsched, err := NewScheduler(testRunState, local.NewController())\n\t\trequire.NoError(t, err)\n\t\tsched.executors = []lib.Executor{pausableExecutor{err: nil}}\n\n\t\trequire.NoError(t, sched.SetPaused(true))\n\t\terr = sched.SetPaused(true)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"execution is already paused\")\n\t})\n\n\tt.Run(\"unpause at the start is an error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestRunState := getBogusTestRunState(t)\n\t\tsched, err := NewScheduler(testRunState, local.NewController())\n\t\trequire.NoError(t, err)\n\t\tsched.executors = []lib.Executor{pausableExecutor{err: nil}}\n\t\terr = sched.SetPaused(false)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"execution wasn't paused\")\n\t})\n\n\tt.Run(\"second unpause is an error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestRunState := getBogusTestRunState(t)\n\t\tsched, err := NewScheduler(testRunState, local.NewController())\n\t\trequire.NoError(t, err)\n\t\tsched.executors = []lib.Executor{pausableExecutor{err: nil}}\n\t\trequire.NoError(t, sched.SetPaused(true))\n\t\trequire.NoError(t, sched.SetPaused(false))\n\t\terr = sched.SetPaused(false)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"execution wasn't paused\")\n\t})\n\n\tt.Run(\"an error on pausing is propagated\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestRunState := getBogusTestRunState(t)\n\t\tsched, err := NewScheduler(testRunState, local.NewController())\n\t\trequire.NoError(t, err)\n\t\texpectedErr := errors.New(\"testing pausable executor error\")\n\t\tsched.executors = []lib.Executor{pausableExecutor{err: expectedErr}}\n\t\terr = sched.SetPaused(true)\n\t\trequire.Error(t, err)\n\t\trequire.Equal(t, expectedErr, err)\n\t})\n}\n"
  },
  {
    "path": "internal/js/bundle.go",
    "content": "package js\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/js/compiler\"\n\t\"go.k6.io/k6/internal/js/eventloop\"\n\t\"go.k6.io/k6/internal/js/modules/k6/webcrypto\"\n\t\"go.k6.io/k6/internal/js/tc55/timers\"\n\t\"go.k6.io/k6/internal/lib/consts\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// A Bundle is a self-contained bundle of scripts and resources.\n// You can use this to produce identical BundleInstance objects.\ntype Bundle struct {\n\tsourceData *loader.SourceData\n\tOptions    lib.Options\n\n\tCompatibilityMode lib.CompatibilityMode // parsed value\n\tpreInitState      *lib.TestPreInitState\n\n\tfilesystems map[string]fsext.Fs\n\tpwd         *url.URL\n\n\tcallableExports map[string]struct{}\n\tModuleResolver  *modules.ModuleResolver\n}\n\n// A BundleInstance is a self-contained instance of a Bundle.\ntype BundleInstance struct {\n\tRuntime *sobek.Runtime\n\n\t// TODO: maybe just have a reference to the Bundle? or save and pass rtOpts?\n\tenv map[string]string\n\n\tmainModule   sobek.ModuleRecord\n\tmoduleVUImpl *moduleVUImpl\n}\n\nfunc (bi *BundleInstance) getCallableExport(name string) sobek.Callable {\n\tfn, ok := sobek.AssertFunction(bi.getExported(name))\n\t_ = ok // TODO maybe return it\n\treturn fn\n}\n\nfunc (bi *BundleInstance) getExported(name string) sobek.Value {\n\tre, ambigiuous := bi.mainModule.ResolveExport(name)\n\tif ambigiuous || re == nil {\n\t\treturn nil\n\t}\n\tmoduleInstance := bi.Runtime.GetModuleInstance(re.Module)\n\tif moduleInstance == nil {\n\t\tpanic(fmt.Sprintf(\"couldn't load module instance while resolving identifier %q - this is a k6 bug \"+\n\t\t\t\", please report it (https://github.com/grafana/k6/issues)\", re.BindingName))\n\t}\n\n\treturn moduleInstance.GetBindingValue(re.BindingName)\n}\n\n// NewBundle creates a new bundle from a source file and a filesystem.\nfunc NewBundle(\n\tpiState *lib.TestPreInitState, src *loader.SourceData, filesystems map[string]fsext.Fs, mr *modules.ModuleResolver,\n) (*Bundle, error) {\n\treturn newBundle(piState, src, filesystems, lib.Options{}, true, mr)\n}\n\nfunc newBundle(\n\tpiState *lib.TestPreInitState, src *loader.SourceData, filesystems map[string]fsext.Fs,\n\toptions lib.Options, updateOptions bool, // TODO: try to figure out a way to not need both\n\tmoduleResolver *modules.ModuleResolver,\n) (*Bundle, error) {\n\tcompatMode, err := lib.ValidateCompatibilityMode(piState.RuntimeOptions.CompatibilityMode.String)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Make a bundle, instantiate it into a throwaway VM to populate caches.\n\tbundle := &Bundle{\n\t\tsourceData:        src,\n\t\tOptions:           options,\n\t\tCompatibilityMode: compatMode,\n\t\tcallableExports:   make(map[string]struct{}),\n\t\tfilesystems:       filesystems,\n\t\tpwd:               src.PWD,\n\t\tpreInitState:      piState,\n\t\tModuleResolver:    moduleResolver,\n\t}\n\n\tif bundle.pwd == nil {\n\t\tbundle.pwd = loader.Dir(src.URL)\n\t}\n\n\t// Instantiate the bundle into a new VM using a bound init context. This uses a context with a\n\t// runtime, but no state, to allow module-provided types to function within the init context.\n\t// TODO use a real context\n\tvuImpl := &moduleVUImpl{\n\t\tctx:     context.Background(),\n\t\truntime: sobek.New(),\n\t\tevents: events{\n\t\t\tglobal: piState.Events,\n\t\t\tlocal:  event.NewEventSystem(100, piState.Logger),\n\t\t},\n\t}\n\tvuImpl.eventLoop = eventloop.New(vuImpl)\n\tbi, err := bundle.instantiate(vuImpl, 0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbundle.ModuleResolver.Lock()\n\n\terr = bundle.populateExports(updateOptions, bi)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bundle, nil\n}\n\n// NewBundleFromArchive creates a new bundle from an lib.Archive.\nfunc NewBundleFromArchive(\n\tpiState *lib.TestPreInitState, arc *lib.Archive, mr *modules.ModuleResolver,\n) (*Bundle, error) {\n\tif arc.Type != \"js\" {\n\t\treturn nil, fmt.Errorf(\"expected bundle type 'js', got '%s'\", arc.Type)\n\t}\n\n\tenv := arc.Env\n\tif env == nil {\n\t\t// Older archives (<=0.20.0) don't have an \"env\" property\n\t\tenv = make(map[string]string)\n\t}\n\tmaps.Copy(env, piState.RuntimeOptions.Env)\n\tpiState.RuntimeOptions.Env = env\n\n\treturn newBundle(piState, &loader.SourceData{\n\t\tData: arc.Data,\n\t\tURL:  arc.FilenameURL,\n\t}, arc.Filesystems, arc.Options, false, mr)\n}\n\nfunc (b *Bundle) makeArchive() *lib.Archive {\n\tclonedSourceDataURL, _ := url.Parse(b.sourceData.URL.String())\n\tclonedPwdURL, _ := url.Parse(b.pwd.String())\n\n\tarc := &lib.Archive{\n\t\tType:              \"js\",\n\t\tFilesystems:       b.filesystems,\n\t\tOptions:           b.Options,\n\t\tFilenameURL:       clonedSourceDataURL,\n\t\tData:              b.sourceData.Data,\n\t\tPwdURL:            clonedPwdURL,\n\t\tEnv:               make(map[string]string, len(b.preInitState.RuntimeOptions.Env)),\n\t\tCompatibilityMode: b.CompatibilityMode.String(),\n\t\tK6Version:         build.Version,\n\t\tGoos:              runtime.GOOS,\n\t}\n\t// Copy env so changes in the archive are not reflected in the source Bundle\n\tmaps.Copy(arc.Env, b.preInitState.RuntimeOptions.Env)\n\n\treturn arc\n}\n\n// populateExports validates and extracts exported objects\nfunc (b *Bundle) populateExports(updateOptions bool, bi *BundleInstance) error {\n\tvar err error\n\tch := make(chan struct{})\n\tbi.mainModule.GetExportedNames(func(names []string) {\n\t\tdefer close(ch)\n\t\tfor _, k := range names {\n\t\t\tv := bi.getExported(k)\n\t\t\tif _, ok := sobek.AssertFunction(v); ok && k != consts.Options {\n\t\t\t\tb.callableExports[k] = struct{}{}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tswitch k {\n\t\t\tcase consts.Options:\n\t\t\t\tif !updateOptions || v == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvar data []byte\n\t\t\t\tdata, err = json.MarshalIndent(v.Export(), \"\", \"  \")\n\t\t\t\tif err != nil {\n\t\t\t\t\terr = fmt.Errorf(\"error parsing script options: %w\", err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdec := json.NewDecoder(bytes.NewReader(data))\n\t\t\t\tdec.DisallowUnknownFields()\n\t\t\t\tif err = dec.Decode(&b.Options); err != nil {\n\t\t\t\t\tif uerr := json.Unmarshal(data, &b.Options); uerr != nil {\n\t\t\t\t\t\t// Beautify the error so we can try to show the user the key and potential value that is failing to parse\n\t\t\t\t\t\tuerr = beautifyOptionsJSONUnmarshalError(data, uerr)\n\t\t\t\t\t\terr = errext.WithAbortReasonIfNone(\n\t\t\t\t\t\t\terrext.WithExitCodeIfNone(uerr, exitcodes.InvalidConfig),\n\t\t\t\t\t\t\terrext.AbortedByScriptError,\n\t\t\t\t\t\t)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tb.preInitState.Logger.WithError(err).Warn(\"There were unknown fields in the options exported in the script\")\n\t\t\t\t\terr = nil\n\t\t\t\t}\n\t\t\tcase consts.SetupFn:\n\t\t\t\terr = errors.New(\"exported 'setup' must be a function\")\n\t\t\t\treturn\n\t\t\tcase consts.TeardownFn:\n\t\t\t\terr = errors.New(\"exported 'teardown' must be a function\")\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\t<-ch\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(b.callableExports) == 0 {\n\t\treturn errors.New(\"no exported functions in script\")\n\t}\n\n\treturn nil\n}\n\nfunc beautifyOptionsJSONUnmarshalError(data []byte, err error) error {\n\tunmarshalTypError := new(json.UnmarshalTypeError)\n\tif errors.As(err, &unmarshalTypError) {\n\t\te := unmarshalTypError\n\t\tpreviousNewLineIndex := max(bytes.LastIndexByte(data[:e.Offset], '\\n'), 0)\n\t\tnextNewLineIndex := max(min(bytes.IndexByte(data[e.Offset:], '\\n'), len(data)-1), (int)(e.Offset))\n\n\t\tinfo := strings.TrimSpace(string(data[previousNewLineIndex:nextNewLineIndex]))\n\t\terr = fmt.Errorf(\"parsing options from script got error while parsing %q: %w\", info, e)\n\t}\n\treturn err\n}\n\n// Instantiate creates a new runtime from this bundle.\nfunc (b *Bundle) Instantiate(ctx context.Context, vuID uint64) (*BundleInstance, error) {\n\t// Instantiate the bundle into a new VM using a bound init context. This uses a context with a\n\t// runtime, but no state, to allow module-provided types to function within the init context.\n\tvuImpl := &moduleVUImpl{\n\t\tctx:     ctx,\n\t\truntime: sobek.New(),\n\t\tevents: events{\n\t\t\tglobal: b.preInitState.Events,\n\t\t\tlocal:  event.NewEventSystem(100, b.preInitState.Logger),\n\t\t},\n\t}\n\tvuImpl.eventLoop = eventloop.New(vuImpl)\n\tbi, err := b.instantiate(vuImpl, vuID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err = bi.manipulateOptions(b.Options); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bi, nil\n}\n\nfunc (bi *BundleInstance) manipulateOptions(options lib.Options) error {\n\t// Grab any exported functions that could be executed. These were\n\t// already pre-validated in cmd.validateScenarioConfig(), just get them here.\n\tjsOptions := bi.getExported(consts.Options)\n\tvar jsOptionsObj *sobek.Object\n\tif common.IsNullish(jsOptions) {\n\t\treturn nil\n\t}\n\n\tjsOptionsObj = jsOptions.ToObject(bi.Runtime)\n\tvar instErr error\n\toptions.ForEachSpecified(\"json\", func(key string, val any) {\n\t\tif err := jsOptionsObj.Set(key, val); err != nil {\n\t\t\tinstErr = err\n\t\t}\n\t})\n\treturn instErr\n}\n\nfunc newCompiler(preInitState *lib.TestPreInitState, filesystems map[string]fsext.Fs) *compiler.Compiler {\n\tc := compiler.New(preInitState.Logger)\n\tc.WithUsage(preInitState.Usage)\n\tc.Options = compiler.Options{\n\t\tSourceMapLoader: generateSourceMapLoader(preInitState.Logger, filesystems),\n\t}\n\treturn c\n}\n\nfunc (b *Bundle) instantiate(vuImpl *moduleVUImpl, vuID uint64) (*BundleInstance, error) {\n\trt := vuImpl.runtime\n\terr := b.setupJSRuntime(rt, vuID, b.preInitState.Logger)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tinitenv := &common.InitEnvironment{\n\t\tTestPreInitState: b.preInitState,\n\t\tFileSystems:      b.filesystems,\n\t\tCWD:              b.pwd,\n\t}\n\n\tmodSys := modules.NewModuleSystem(b.ModuleResolver, vuImpl)\n\tb.setInitGlobals(rt, vuImpl, modSys)\n\n\terr = registerGlobals(vuImpl)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvuImpl.initEnv = initenv\n\tdefer func() {\n\t\tvuImpl.initEnv = nil\n\t}()\n\n\t// TODO: make something cleaner for interrupting scripts, and more unified\n\t// (e.g. as a part of the event loop?\n\tinitDone := make(chan struct{})\n\tgo func() {\n\t\tselect {\n\t\tcase <-vuImpl.ctx.Done():\n\t\t\trt.Interrupt(vuImpl.ctx.Err())\n\t\tcase initDone <- struct{}{}: // do nothing\n\t\t}\n\t\tclose(initDone)\n\t}()\n\n\tbi := &BundleInstance{\n\t\tRuntime:      vuImpl.runtime,\n\t\tenv:          b.preInitState.RuntimeOptions.Env,\n\t\tmoduleVUImpl: vuImpl,\n\t}\n\tvar result *modules.RunSourceDataResult\n\tcallback := func() error { // this exists so that Sobek catches uncatchable panics such as Interrupt\n\t\tvar err error\n\t\tresult, err = modSys.RunSourceData(b.sourceData)\n\t\treturn err\n\t}\n\n\tcall, _ := sobek.AssertFunction(vuImpl.runtime.ToValue(callback))\n\n\terr = vuImpl.eventLoop.Start(func() error {\n\t\t_, err := call(nil)\n\t\treturn err\n\t})\n\n\t<-initDone\n\n\tif err == nil {\n\t\tvar finished bool\n\t\tbi.mainModule, finished, err = result.Result()\n\t\tif !finished {\n\t\t\treturn nil, errors.New(\"initializing the main module hasn't finished, this is a bug in k6 please report it\")\n\t\t}\n\t}\n\n\tif err != nil {\n\t\tvar exception *sobek.Exception\n\t\tif errors.As(err, &exception) {\n\t\t\terr = &scriptExceptionError{inner: exception}\n\t\t}\n\t\treturn nil, err\n\t}\n\n\t// If we've already initialized the original VU init context, forbid\n\t// any subsequent VUs to open new files\n\tif vuID == 0 {\n\t\tallowOnlyOpenedFiles(b.filesystems[\"file\"])\n\t}\n\n\trt.SetRandSource(common.NewRandSource())\n\n\treturn bi, nil\n}\n\n// registerGlobals registers the globals for the runtime.\n// e.g. timers and webcrypto.\nfunc registerGlobals(vuImpl *moduleVUImpl) error {\n\terr := timers.SetupGlobally(vuImpl)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn webcrypto.SetupGlobally(vuImpl)\n}\n\nfunc (b *Bundle) setupJSRuntime(rt *sobek.Runtime, vuID uint64, logger logrus.FieldLogger) error {\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\trt.SetRandSource(common.NewRandSource())\n\n\tenv := make(map[string]string, len(b.preInitState.RuntimeOptions.Env))\n\tmaps.Copy(env, b.preInitState.RuntimeOptions.Env)\n\terr := rt.Set(\"__ENV\", env)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = rt.Set(\"__VU\", vuID)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = rt.Set(\"console\", newConsole(logger))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif b.CompatibilityMode == lib.CompatibilityModeExtended {\n\t\tglobalThis := rt.GlobalObject()\n\t\terr = globalThis.DefineAccessorProperty(\"global\",\n\t\t\trt.ToValue(func() sobek.Value {\n\t\t\t\tif err := b.preInitState.Usage.Uint64(\"usage/global\", 1); err != nil {\n\t\t\t\t\tb.preInitState.Logger.WithError(err).Warn(\"couldn't report usage\")\n\t\t\t\t}\n\t\t\t\treturn globalThis\n\t\t\t}), rt.ToValue(func(newGlobal *sobek.Object) { // probably not a thing that will happen but still\n\t\t\t\tglobalThis = newGlobal\n\t\t\t}),\n\t\t\tsobek.FLAG_TRUE, sobek.FLAG_TRUE)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// this exists only to make the check in the init context.\ntype requireImpl struct {\n\tinInitContext func() bool\n\tmodSys        *modules.ModuleSystem\n}\n\nfunc (r *requireImpl) require(specifier string) (*sobek.Object, error) {\n\tif !r.inInitContext() {\n\t\treturn nil, fmt.Errorf(cantBeUsedOutsideInitContextMsg, \"require\")\n\t}\n\treturn r.modSys.Require(specifier)\n}\n\nfunc (b *Bundle) setInitGlobals(rt *sobek.Runtime, vu *moduleVUImpl, modSys *modules.ModuleSystem) {\n\tmustSet := func(k string, v any) {\n\t\tif err := rt.Set(k, v); err != nil {\n\t\t\tpanic(fmt.Errorf(\"failed to set '%s' global object: %w\", k, err))\n\t\t}\n\t}\n\n\timpl := requireImpl{\n\t\tinInitContext: func() bool { return vu.state == nil },\n\t\tmodSys:        modSys,\n\t}\n\n\tmustSet(\"require\", impl.require)\n\n\tmustSet(\"open\", func(filename string, args ...string) (sobek.Value, error) {\n\t\t// TODO fix in stack traces\n\t\tif vu.state != nil {\n\t\t\treturn nil, fmt.Errorf(cantBeUsedOutsideInitContextMsg, \"open\")\n\t\t}\n\n\t\tif filename == \"\" {\n\t\t\treturn nil, errors.New(\"open() can't be used with an empty filename\")\n\t\t}\n\t\t// This uses the pwd from the requireImpl\n\t\tpwd, err := modSys.CurrentlyRequiredModule()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !strings.HasPrefix(filename, \"file://\") && !filepath.IsAbs(filename) {\n\t\t\totherPath, shouldWarn := modSys.ShouldWarnOnParentDirNotMatchingCurrentModuleParentDir(vu, pwd)\n\t\t\tlogger := b.preInitState.Logger\n\t\t\tif shouldWarn {\n\t\t\t\tlogger.Warningf(\"open() was used and is currently relative to '%s', but in the future \"+\n\t\t\t\t\t\"it will be aligned with how `require` and imports work and will be relative to '%s'. This means \"+\n\t\t\t\t\t\"that in the future open will open relative path relative to the module/file it is written in. \"+\n\t\t\t\t\t\"You can future proof this by using `import.meta.resolve()` to get relative paths to the file it \"+\n\t\t\t\t\t\"is written in the current k6 version.\", pwd, otherPath)\n\t\t\t\terr = b.preInitState.Usage.Uint64(\"deprecations/openRelativity\", 1)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlogger.WithError(err).Warn(\"failed reporting usage of deprecated relativity of open()\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn openImpl(rt, b.filesystems[\"file\"], pwd, filename, args...)\n\t})\n\twarnAboutModuleMixing := func(name string) {\n\t\twarnFunc := rt.ToValue(func() error {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"you are trying to access identifier %q, this likely is due to mixing \"+\n\t\t\t\t\t\"ECMAScript Modules (ESM) and CommonJS syntax. \"+\n\t\t\t\t\t\"This isn't supported in the JavaScript standard, please use only one or the other\",\n\t\t\t\tname)\n\t\t})\n\t\terr := rt.GlobalObject().DefineAccessorProperty(name, warnFunc, warnFunc, sobek.FLAG_FALSE, sobek.FLAG_FALSE)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Errorf(\"failed to set '%s' global object: %w\", name, err))\n\t\t}\n\t}\n\twarnAboutModuleMixing(\"module\")\n\twarnAboutModuleMixing(\"exports\")\n\n\trt.SetFinalImportMeta(func(o *sobek.Object, mr sobek.ModuleRecord) {\n\t\terr := o.Set(\"resolve\", func(specifier string) (string, error) {\n\t\t\tu, err := modSys.Resolve(mr, specifier)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\treturn u.String(), nil\n\t\t})\n\t\tif err != nil {\n\t\t\tpanic(\"error while creating `import.meta.resolve`: \" + err.Error())\n\t\t}\n\t})\n}\n\nfunc generateFileLoad(logger logrus.FieldLogger, filesystems map[string]fsext.Fs) modules.FileLoader {\n\treturn func(specifier *url.URL, name string) ([]byte, error) {\n\t\tif filepath.IsAbs(name) && runtime.GOOS == \"windows\" {\n\t\t\tlogger.Warnf(\"'%s' was imported with an absolute path - this won't be cross-platform and \"+\n\t\t\t\t\"won't work if you move the script between machines or run it with `k6 cloud`; if absolute paths are \"+\n\t\t\t\t\"required, import them with the `file://` schema for slightly better compatibility\",\n\t\t\t\tname)\n\t\t}\n\t\td, err := loader.Load(logger, filesystems, specifier, name)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn d.Data, nil\n\t}\n}\n\n// NewModuleResolver is used to create a Runner appropriate module resolver\nfunc NewModuleResolver(pwd *url.URL, preInitState *lib.TestPreInitState, filesystems map[string]fsext.Fs,\n) *modules.ModuleResolver {\n\tc := newCompiler(preInitState, filesystems)\n\treturn modules.NewModuleResolver(\n\t\tgetJSModules(), generateFileLoad(preInitState.Logger, filesystems), c, pwd, preInitState.Usage, preInitState.Logger)\n}\n"
  },
  {
    "path": "internal/js/bundle_test.go",
    "content": "package js\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/lib/consts\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst isWindows = runtime.GOOS == \"windows\"\n\nfunc getTestPreInitState(tb testing.TB, logger logrus.FieldLogger, rtOpts *lib.RuntimeOptions) *lib.TestPreInitState {\n\ttb.Helper()\n\tif logger == nil {\n\t\tlogger = testutils.NewLogger(tb)\n\t}\n\tif rtOpts == nil {\n\t\trtOpts = &lib.RuntimeOptions{}\n\t}\n\treg := metrics.NewRegistry()\n\treturn &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tRuntimeOptions: *rtOpts,\n\t\tRegistry:       reg,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(reg),\n\t\tUsage:          usage.New(),\n\t}\n}\n\nfunc getSimpleBundle(tb testing.TB, filename, data string, opts ...any) (*Bundle, error) {\n\ttb.Helper()\n\tfs := fsext.NewMemMapFs()\n\tvar rtOpts *lib.RuntimeOptions\n\tvar logger logrus.FieldLogger\n\tfor _, o := range opts {\n\t\tswitch opt := o.(type) {\n\t\tcase fsext.Fs:\n\t\t\tfs = opt\n\t\tcase lib.RuntimeOptions:\n\t\t\trtOpts = &opt\n\t\tcase logrus.FieldLogger:\n\t\t\tlogger = opt\n\t\tdefault:\n\t\t\ttb.Fatalf(\"unknown test option %q\", opt)\n\t\t}\n\t}\n\tpreInitState := getTestPreInitState(tb, logger, rtOpts)\n\n\tfilenameURL := &url.URL{Path: filename, Scheme: \"file\"}\n\n\tfss := map[string]fsext.Fs{\"file\": fs, \"https\": fsext.NewMemMapFs()}\n\tmoduleResolver := NewModuleResolver(loader.Dir(filenameURL), preInitState, fss)\n\treturn NewBundle(\n\t\tpreInitState,\n\t\t&loader.SourceData{\n\t\t\tURL:  filenameURL,\n\t\t\tData: []byte(data),\n\t\t},\n\t\tfss,\n\t\tmoduleResolver,\n\t)\n}\n\nfunc getSimpleBundleFromArchive(tb testing.TB, arc *lib.Archive, opts ...any) (*Bundle, error) {\n\ttb.Helper()\n\tvar rtOpts *lib.RuntimeOptions\n\tvar logger logrus.FieldLogger\n\tfor _, o := range opts {\n\t\tswitch opt := o.(type) {\n\t\tcase lib.RuntimeOptions:\n\t\t\trtOpts = &opt\n\t\tcase logrus.FieldLogger:\n\t\t\tlogger = opt\n\t\tdefault:\n\t\t\ttb.Fatalf(\"unknown test option %q\", opt)\n\t\t}\n\t}\n\tpreInitState := getTestPreInitState(tb, logger, rtOpts)\n\n\tfss := arc.Filesystems\n\tmoduleResolver := NewModuleResolver(arc.PwdURL, preInitState, fss)\n\treturn NewBundleFromArchive(preInitState, arc, moduleResolver)\n}\n\nfunc getSimpleBundleStdin(tb testing.TB, pwd *url.URL, data string, opts ...any) (*Bundle, error) {\n\ttb.Helper()\n\tfs := fsext.NewMemMapFs()\n\tvar rtOpts *lib.RuntimeOptions\n\tvar logger logrus.FieldLogger\n\tfor _, o := range opts {\n\t\tswitch opt := o.(type) {\n\t\tcase fsext.Fs:\n\t\t\tfs = opt\n\t\tcase lib.RuntimeOptions:\n\t\t\trtOpts = &opt\n\t\tcase logrus.FieldLogger:\n\t\t\tlogger = opt\n\t\tdefault:\n\t\t\ttb.Fatalf(\"unknown test option %q\", opt)\n\t\t}\n\t}\n\n\tpreInitState := getTestPreInitState(tb, logger, rtOpts)\n\n\tfilenameURL := &url.URL{Path: \"/-\", Scheme: \"file\"}\n\n\tfss := map[string]fsext.Fs{\"file\": fs, \"https\": fsext.NewMemMapFs()}\n\tmoduleResolver := NewModuleResolver(pwd, preInitState, fss)\n\treturn NewBundle(\n\t\tpreInitState,\n\t\t&loader.SourceData{\n\t\t\tURL:  filenameURL,\n\t\t\tData: []byte(data),\n\t\t\tPWD:  pwd,\n\t\t},\n\t\tfss,\n\t\tmoduleResolver,\n\t)\n}\n\nfunc TestNewBundle(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Blank\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", \"\")\n\t\trequire.EqualError(t, err, \"no exported functions in script\")\n\t})\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", \"\\x00\")\n\t\trequire.NotNil(t, err)\n\t\trequire.Contains(t, err.Error(), \"file:///script.js: Line 1:1 Unexpected token ILLEGAL (and 1 more errors)\")\n\t})\n\tt.Run(\"Error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `throw new Error(\"aaaa\");`)\n\t\texception := new(scriptExceptionError)\n\t\trequire.ErrorAs(t, err, &exception)\n\t\trequire.EqualError(t, err, \"Error: aaaa\\n\\tat file:///script.js:1:34(3)\\n\")\n\t})\n\tt.Run(\"InvalidExports\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `module.exports = null`)\n\t\trequire.EqualError(t, err, \"CommonJS's exports must not be null\")\n\t})\n\tt.Run(\"DefaultUndefined\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `export default undefined;`)\n\t\trequire.EqualError(t, err, \"no exported functions in script\")\n\t})\n\tt.Run(\"DefaultNull\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `export default null;`)\n\t\trequire.EqualError(t, err, \"no exported functions in script\")\n\t})\n\tt.Run(\"DefaultWrongType\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `export default 12345;`)\n\t\trequire.EqualError(t, err, \"no exported functions in script\")\n\t})\n\tt.Run(\"Minimal\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `export default function() {};`)\n\t\trequire.NoError(t, err)\n\t})\n\tt.Run(\"stdin\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tb, err := getSimpleBundle(t, \"-\", `export default function() {};`)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"file://-\", b.sourceData.URL.String())\n\t\tassert.Equal(t, \"file:///\", b.pwd.String())\n\t})\n\tt.Run(\"CompatibilityMode\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"Extended/ok/global\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trtOpts := lib.RuntimeOptions{\n\t\t\t\tCompatibilityMode: null.StringFrom(lib.CompatibilityModeExtended.String()),\n\t\t\t}\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\",\n\t\t\t\t`module.exports.default = function() {}\n\t\t\t\tif (global.Math != Math) {\n\t\t\t\t\tthrow new Error(\"global is not defined\");\n\t\t\t\t}`, rtOpts)\n\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\tt.Run(\"Base/ok/Minimal\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trtOpts := lib.RuntimeOptions{\n\t\t\t\tCompatibilityMode: null.StringFrom(lib.CompatibilityModeBase.String()),\n\t\t\t}\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\",\n\t\t\t\t`module.exports.default = function() {};`, rtOpts)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\tt.Run(\"Base/err\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttestCases := []struct {\n\t\t\t\tname       string\n\t\t\t\tcompatMode string\n\t\t\t\tcode       string\n\t\t\t\texpErr     string\n\t\t\t}{\n\t\t\t\t{\n\t\t\t\t\t\"InvalidCompat\", \"es1\", `export default function() {};`,\n\t\t\t\t\t`invalid compatibility mode \"es1\". Use: \"extended\", \"base\", \"experimental_enhanced\"`,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tfor _, tc := range testCases {\n\t\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\trtOpts := lib.RuntimeOptions{CompatibilityMode: null.StringFrom(tc.compatMode)}\n\t\t\t\t\t_, err := getSimpleBundle(t, \"/script.js\", tc.code, rtOpts)\n\t\t\t\t\trequire.EqualError(t, err, tc.expErr)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Options\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"Empty\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\tt.Run(\"Null\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\trequire.NoError(t, fsext.WriteFile(fs, \"/options.js\", []byte(\"module.exports={}\"), 0o644))\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport {options} from \"./options.js\";\n\t\t\t\texport default function() {};\n\t\t\t`, fs)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tinvalidOptions := map[string]struct {\n\t\t\t\tExpr, Error string\n\t\t\t}{\n\t\t\t\t\"Array\": {\n\t\t\t\t\t`[]`,\n\t\t\t\t\t`parsing options from script got error while parsing \"[\": ` +\n\t\t\t\t\t\t`json: cannot unmarshal array into Go value of type lib.Options`,\n\t\t\t\t},\n\t\t\t\t\"Bad value\": {\n\t\t\t\t\t`{\n\t\t\t\t\t\t\"duration\": \"5m\",\n\t\t\t\t\t\t\"tags\":[\"something\"],\n\t\t\t\t\t\t\"vus\": 5\n\t\t\t\t\t}`,\n\t\t\t\t\t`parsing options from script got error while parsing \"\\\"tags\\\": [\": ` +\n\t\t\t\t\t\t`json: cannot unmarshal array into Go struct field Options.tags of type map[string]string`,\n\t\t\t\t},\n\t\t\t\t\"Function\": {\n\t\t\t\t\t`function(){}`,\n\t\t\t\t\t\"error parsing script options: json: unsupported type: func(sobek.FunctionCall) sobek.Value\",\n\t\t\t\t},\n\t\t\t}\n\t\t\tfor name, data := range invalidOptions {\n\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\t_, err := getSimpleBundle(t, \"/script.js\", fmt.Sprintf(`\n\t\t\t\t\t\texport let options = %s;\n\t\t\t\t\t\texport default function() {};\n\t\t\t\t\t`, data.Expr))\n\t\t\t\t\trequire.EqualError(t, err, data.Error)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\n\t\tt.Run(\"Paused\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tpaused: true,\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, null.BoolFrom(true), b.Options.Paused)\n\t\t})\n\t\tt.Run(\"VUs\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tvus: 100,\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, null.IntFrom(100), b.Options.VUs)\n\t\t})\n\t\tt.Run(\"Duration\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tduration: \"10s\",\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, types.NullDurationFrom(10*time.Second), b.Options.Duration)\n\t\t})\n\t\tt.Run(\"Iterations\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\titerations: 100,\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, null.IntFrom(100), b.Options.Iterations)\n\t\t})\n\t\tt.Run(\"Stages\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tstages: [],\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, b.Options.Stages, 0)\n\n\t\t\tt.Run(\"Empty\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\tstages: [\n\t\t\t\t\t\t\t{},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, b.Options.Stages, 1)\n\t\t\t\trequire.Equal(t, lib.Stage{}, b.Options.Stages[0])\n\t\t\t})\n\t\t\tt.Run(\"Target\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\tstages: [\n\t\t\t\t\t\t\t{target: 10},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, b.Options.Stages, 1)\n\t\t\t\trequire.Equal(t, lib.Stage{Target: null.IntFrom(10)}, b.Options.Stages[0])\n\t\t\t})\n\t\t\tt.Run(\"Duration\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\tstages: [\n\t\t\t\t\t\t\t{duration: \"10s\"},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, b.Options.Stages, 1)\n\t\t\t\trequire.Equal(t, lib.Stage{Duration: types.NullDurationFrom(10 * time.Second)}, b.Options.Stages[0])\n\t\t\t})\n\t\t\tt.Run(\"DurationAndTarget\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\tstages: [\n\t\t\t\t\t\t\t{duration: \"10s\", target: 10},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, b.Options.Stages, 1)\n\t\t\t\trequire.Equal(t, lib.Stage{Duration: types.NullDurationFrom(10 * time.Second), Target: null.IntFrom(10)}, b.Options.Stages[0])\n\t\t\t})\n\t\t\tt.Run(\"RampUpAndPlateau\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\tstages: [\n\t\t\t\t\t\t\t{duration: \"10s\", target: 10},\n\t\t\t\t\t\t\t{duration: \"5s\"},\n\t\t\t\t\t\t],\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, b.Options.Stages, 2)\n\t\t\t\tassert.Equal(t, lib.Stage{Duration: types.NullDurationFrom(10 * time.Second), Target: null.IntFrom(10)}, b.Options.Stages[0])\n\t\t\t\tassert.Equal(t, lib.Stage{Duration: types.NullDurationFrom(5 * time.Second)}, b.Options.Stages[1])\n\t\t\t})\n\t\t})\n\t\tt.Run(\"MaxRedirects\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tmaxRedirects: 10,\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, null.IntFrom(10), b.Options.MaxRedirects)\n\t\t})\n\t\tt.Run(\"InsecureSkipTLSVerify\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tinsecureSkipTLSVerify: true,\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, null.BoolFrom(true), b.Options.InsecureSkipTLSVerify)\n\t\t})\n\t\tt.Run(\"TLSCipherSuites\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor suiteName, suiteID := range lib.SupportedTLSCipherSuites {\n\t\t\t\tt.Run(suiteName, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tscript := `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\ttlsCipherSuites: [\"%s\"]\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t\t`\n\t\t\t\t\tscript = fmt.Sprintf(script, suiteName)\n\n\t\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", script)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Len(t, *b.Options.TLSCipherSuites, 1)\n\t\t\t\t\trequire.Equal(t, (*b.Options.TLSCipherSuites)[0], suiteID)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t\tt.Run(\"TLSVersion\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Run(\"Object\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\ttlsVersion: {\n\t\t\t\t\t\t\tmin: \"tls1.0\",\n\t\t\t\t\t\t\tmax: \"tls1.2\"\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, lib.TLSVersion(tls.VersionTLS10), b.Options.TLSVersion.Min)\n\t\t\t\tassert.Equal(t, lib.TLSVersion(tls.VersionTLS12), b.Options.TLSVersion.Max)\n\t\t\t})\n\t\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\texport let options = {\n\t\t\t\t\t\ttlsVersion: \"tls1.0\"\n\t\t\t\t\t};\n\t\t\t\t\texport default function() {};\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, lib.TLSVersion(tls.VersionTLS10), b.Options.TLSVersion.Min)\n\t\t\t\tassert.Equal(t, lib.TLSVersion(tls.VersionTLS10), b.Options.TLSVersion.Max)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"Thresholds\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tthresholds: {\n\t\t\t\t\t\thttp_req_duration: [\"avg<100\"],\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, b.Options.Thresholds[\"http_req_duration\"].Thresholds, 1)\n\t\t\trequire.Equal(t, \"avg<100\", b.Options.Thresholds[\"http_req_duration\"].Thresholds[0].Source)\n\t\t})\n\n\t\tt.Run(\"Unknown field\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tlogger := logrus.New()\n\t\t\tlogger.SetLevel(logrus.InfoLevel)\n\t\t\tlogger.Out = io.Discard\n\t\t\thook := testutils.NewLogHook(\n\t\t\t\tlogrus.WarnLevel, logrus.InfoLevel, logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel,\n\t\t\t)\n\t\t\tlogger.AddHook(hook)\n\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\texport let options = {\n\t\t\t\t\tsomething: {\n\t\t\t\t\t\thttp_req_duration: [\"avg<100\"],\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\texport default function() {};\n\t\t\t`, logger)\n\t\t\trequire.NoError(t, err)\n\t\t\tentries := hook.Drain()\n\t\t\trequire.Len(t, entries, 1)\n\t\t\tassert.Equal(t, logrus.WarnLevel, entries[0].Level)\n\t\t\tassert.Contains(t, entries[0].Message, \"There were unknown fields\")\n\t\t\tassert.Contains(t, entries[0].Data[\"error\"].(error).Error(), \"unknown field \\\"something\\\"\")\n\t\t})\n\t})\n}\n\nfunc getArchive(tb testing.TB, data string, rtOpts lib.RuntimeOptions) (*lib.Archive, error) {\n\tb, err := getSimpleBundle(tb, \"script.js\", data, rtOpts)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn b.makeArchive(), nil\n}\n\nfunc TestNewBundleFromArchive(t *testing.T) {\n\tt.Parallel()\n\n\tes5Code := `module.exports.options = { vus: 12345 }; module.exports.default = function() { return \"hi!\" };`\n\tes6Code := `export let options = { vus: 12345 }; export default function() { return \"hi!\"; };`\n\tbaseCompatModeRtOpts := lib.RuntimeOptions{CompatibilityMode: null.StringFrom(lib.CompatibilityModeBase.String())}\n\textCompatModeRtOpts := lib.RuntimeOptions{CompatibilityMode: null.StringFrom(lib.CompatibilityModeExtended.String())}\n\n\tlogger := testutils.NewLogger(t)\n\tcheckBundle := func(t *testing.T, b *Bundle) {\n\t\trequire.Equal(t, lib.Options{VUs: null.IntFrom(12345)}, b.Options)\n\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\trequire.NoError(t, err)\n\t\tval, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"hi!\", val.Export())\n\t}\n\n\tcheckArchive := func(t *testing.T, arc *lib.Archive, rtOpts lib.RuntimeOptions, expError string) {\n\t\tb, err := getSimpleBundleFromArchive(t, arc, rtOpts, logger)\n\t\tif expError != \"\" {\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), expError)\n\t\t} else {\n\t\t\trequire.NoError(t, err)\n\t\t\tcheckBundle(t, b)\n\t\t}\n\t}\n\n\tt.Run(\"es6_script_default\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tarc, err := getArchive(t, es6Code, lib.RuntimeOptions{}) // default options\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, lib.CompatibilityModeExtended.String(), arc.CompatibilityMode)\n\n\t\tcheckArchive(t, arc, lib.RuntimeOptions{}, \"\") // default options\n\t\tcheckArchive(t, arc, extCompatModeRtOpts, \"\")\n\t\tcheckArchive(t, arc, baseCompatModeRtOpts, \"\")\n\t})\n\n\tt.Run(\"es6_script_explicit\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tarc, err := getArchive(t, es6Code, extCompatModeRtOpts)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, lib.CompatibilityModeExtended.String(), arc.CompatibilityMode)\n\n\t\tcheckArchive(t, arc, lib.RuntimeOptions{}, \"\")\n\t\tcheckArchive(t, arc, extCompatModeRtOpts, \"\")\n\t\tcheckArchive(t, arc, baseCompatModeRtOpts, \"\")\n\t})\n\n\tt.Run(\"es5_script_with_extended\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tarc, err := getArchive(t, es5Code, lib.RuntimeOptions{})\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, lib.CompatibilityModeExtended.String(), arc.CompatibilityMode)\n\n\t\tcheckArchive(t, arc, lib.RuntimeOptions{}, \"\")\n\t\tcheckArchive(t, arc, extCompatModeRtOpts, \"\")\n\t\tcheckArchive(t, arc, baseCompatModeRtOpts, \"\")\n\t})\n\n\tt.Run(\"es5_script\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tarc, err := getArchive(t, es5Code, baseCompatModeRtOpts)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, lib.CompatibilityModeBase.String(), arc.CompatibilityMode)\n\n\t\tcheckArchive(t, arc, lib.RuntimeOptions{}, \"\")\n\t\tcheckArchive(t, arc, extCompatModeRtOpts, \"\")\n\t\tcheckArchive(t, arc, baseCompatModeRtOpts, \"\")\n\t})\n\n\tt.Run(\"messed_up_archive\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tarc, err := getArchive(t, es6Code, extCompatModeRtOpts)\n\t\trequire.NoError(t, err)\n\t\tcheckArchive(t, arc, extCompatModeRtOpts, \"\")  // works when I force the compat mode\n\t\tcheckArchive(t, arc, baseCompatModeRtOpts, \"\") // still works as even base compatibility supports ESM\n\t})\n\n\tt.Run(\"script_options_dont_overwrite_metadata\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tcode := `export let options = { vus: 12345 }; export default function() { return options.vus; };`\n\t\tarc := &lib.Archive{\n\t\t\tType:        \"js\",\n\t\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/script\"},\n\t\t\tK6Version:   build.Version,\n\t\t\tData:        []byte(code),\n\t\t\tOptions:     lib.Options{VUs: null.IntFrom(999)},\n\t\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/\"},\n\t\t\tFilesystems: nil,\n\t\t}\n\t\tb, err := getSimpleBundleFromArchive(t, arc, logger)\n\t\trequire.NoError(t, err)\n\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\trequire.NoError(t, err)\n\t\tval, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, int64(999), val.Export())\n\t})\n}\n\nfunc TestOpen(t *testing.T) {\n\tt.Parallel()\n\ttestCases := [...]struct {\n\t\tname           string\n\t\topenPath       string\n\t\tpwd            string\n\t\tisError        bool\n\t\tisArchiveError bool\n\t}{\n\t\t{\n\t\t\tname:     \"notOpeningUrls\",\n\t\t\topenPath: \"github.com\",\n\t\t\tisError:  true,\n\t\t\tpwd:      \"/path/to\",\n\t\t},\n\t\t{\n\t\t\tname:     \"simple\",\n\t\t\topenPath: \"file.txt\",\n\t\t\tpwd:      \"/path/to\",\n\t\t},\n\t\t{\n\t\t\tname:     \"simple with dot\",\n\t\t\topenPath: \"./file.txt\",\n\t\t\tpwd:      \"/path/to\",\n\t\t},\n\t\t{\n\t\t\tname:     \"simple with two dots\",\n\t\t\topenPath: \"../to/file.txt\",\n\t\t\tpwd:      \"/path/not\",\n\t\t},\n\t\t{\n\t\t\tname:     \"fullpath\",\n\t\t\topenPath: \"/path/to/file.txt\",\n\t\t\tpwd:      \"/path/to\",\n\t\t},\n\t\t{\n\t\t\tname:     \"fullpath2\",\n\t\t\topenPath: \"/path/to/file.txt\",\n\t\t\tpwd:      \"/path\",\n\t\t},\n\t\t{\n\t\t\tname:     \"file scheme\",\n\t\t\topenPath: \"file:///path/to/file.txt\",\n\t\t\tpwd:      \"/path\",\n\t\t},\n\t\t{\n\t\t\tname:     \"file is dir\",\n\t\t\topenPath: \"/path/to/\",\n\t\t\tpwd:      \"/path/to\",\n\t\t\tisError:  true,\n\t\t},\n\t\t{\n\t\t\tname:     \"file is missing\",\n\t\t\topenPath: \"/path/to/missing.txt\",\n\t\t\tisError:  true,\n\t\t},\n\t\t{\n\t\t\tname:     \"relative1\",\n\t\t\topenPath: \"to/file.txt\",\n\t\t\tpwd:      \"/path\",\n\t\t},\n\t\t{\n\t\t\tname:     \"relative2\",\n\t\t\topenPath: \"./path/to/file.txt\",\n\t\t\tpwd:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:     \"relative wonky\",\n\t\t\topenPath: \"../path/to/file.txt\",\n\t\t\tpwd:      \"/path\",\n\t\t},\n\t\t{\n\t\t\tname:     \"empty open doesn't panic\",\n\t\t\topenPath: \"\",\n\t\t\tpwd:      \"/path\",\n\t\t\tisError:  true,\n\t\t},\n\t}\n\tfss := map[string]func() (fsext.Fs, string, func()){\n\t\t\"MemMapFS\": func() (fsext.Fs, string, func()) {\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\trequire.NoError(t, fs.MkdirAll(\"/path/to\", 0o755))\n\t\t\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/file.txt\", []byte(`hi`), 0o644))\n\t\t\treturn fs, \"\", func() {}\n\t\t},\n\t\t\"OsFS\": func() (fsext.Fs, string, func()) {\n\t\t\tprefix := t.TempDir()\n\t\t\tfs := fsext.NewOsFs()\n\t\t\tfilePath := filepath.Join(prefix, \"/path/to/file.txt\")\n\t\t\trequire.NoError(t, fs.MkdirAll(filepath.Join(prefix, \"/path/to\"), 0o755))\n\t\t\trequire.NoError(t, fsext.WriteFile(fs, filePath, []byte(`hi`), 0o644))\n\t\t\tfs = fsext.NewChangePathFs(fs, func(name string) (string, error) {\n\t\t\t\t// Drop the prefix effectively building something like https://pkg.go.dev/os#DirFS\n\t\t\t\treturn filepath.Join(prefix, name), nil\n\t\t\t})\n\t\t\tif isWindows {\n\t\t\t\tfs = fsext.NewTrimFilePathSeparatorFs(fs)\n\t\t\t}\n\t\t\treturn fs, prefix, func() { require.NoError(t, os.RemoveAll(prefix)) } //nolint:forbidigo\n\t\t},\n\t}\n\n\tlogger := testutils.NewLogger(t)\n\n\tfor name, fsInit := range fss {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor _, tCase := range testCases {\n\t\t\t\ttestFunc := func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tfs, _, cleanUp := fsInit()\n\t\t\t\t\tdefer cleanUp()\n\t\t\t\t\tfs = fsext.NewReadOnlyFs(fs)\n\t\t\t\t\topenPath := tCase.openPath\n\t\t\t\t\t// if fullpath prepend prefix\n\t\t\t\t\tif isWindows {\n\t\t\t\t\t\topenPath = strings.ReplaceAll(openPath, `\\`, `\\\\`)\n\t\t\t\t\t}\n\t\t\t\t\tpwd := tCase.pwd\n\t\t\t\t\tif pwd == \"\" {\n\t\t\t\t\t\tpwd = \"/path/to/\"\n\t\t\t\t\t}\n\t\t\t\t\tdata := `\n\t\t\t\t\t\texport let file = open(\"` + openPath + `\");\n\t\t\t\t\t\texport default function() { return file };`\n\n\t\t\t\t\tsourceBundle, err := getSimpleBundle(t, filepath.ToSlash(filepath.Join(pwd, \"script.js\")), data, fs)\n\t\t\t\t\tif tCase.isError {\n\t\t\t\t\t\trequire.Error(t, err)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tarcBundle, err := getSimpleBundleFromArchive(t, sourceBundle.makeArchive(), logger)\n\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tfor source, b := range map[string]*Bundle{\"source\": sourceBundle, \"archive\": arcBundle} {\n\t\t\t\t\t\tt.Run(source, func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\t\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\tv, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\trequire.Equal(t, \"hi\", v.Export())\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tt.Run(tCase.name, testFunc) //nolint:paralleltest\n\t\t\t\tif isWindows {\n\t\t\t\t\ttCase := tCase // copy test case before making modifications\n\t\t\t\t\t// windowsify the testcase\n\t\t\t\t\ttCase.openPath = strings.ReplaceAll(tCase.openPath, `/`, `\\`)\n\t\t\t\t\ttCase.pwd = strings.ReplaceAll(tCase.pwd, `/`, `\\`)\n\t\t\t\t\tt.Run(tCase.name+\" with windows slash\", testFunc) //nolint:paralleltest\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestBundleInstantiate(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Run\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\texport let options = {\n\t\t\tvus: 5,\n\t\t\tteardownTimeout: '1s',\n\t\t};\n\t\tlet val = true;\n\t\texport default function() { return val; }\n\t`)\n\t\trequire.NoError(t, err)\n\n\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\trequire.NoError(t, err)\n\t\tv, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, true, v.Export())\n\t})\n\n\tt.Run(\"Options\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\texport let options = {\n\t\t\t\tvus: 5,\n\t\t\t\tteardownTimeout: '1s',\n\t\t\t};\n\t\t\tlet val = true;\n\t\t\texport default function() { return val; }\n\t\t`)\n\t\trequire.NoError(t, err)\n\n\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\trequire.NoError(t, err)\n\t\t// Ensure `options` properties are correctly marshalled\n\t\tjsOptions := bi.getExported(\"options\").ToObject(bi.Runtime)\n\t\tvus := jsOptions.Get(\"vus\").Export()\n\t\trequire.Equal(t, int64(5), vus)\n\t\ttdt := jsOptions.Get(\"teardownTimeout\").Export()\n\t\trequire.Equal(t, \"1s\", tdt)\n\n\t\t// Ensure options propagate correctly from outside to the script\n\t\toptOrig := b.Options.VUs\n\t\tb.Options.VUs = null.IntFrom(10)\n\t\tbi2, err := b.Instantiate(context.Background(), 0)\n\t\trequire.NoError(t, err)\n\t\tjsOptions = bi2.getExported(\"options\").ToObject(bi2.Runtime)\n\t\tvus = jsOptions.Get(\"vus\").Export()\n\t\trequire.Equal(t, int64(10), vus)\n\t\tb.Options.VUs = optOrig\n\t})\n}\n\nfunc TestBundleEnv(t *testing.T) {\n\tt.Parallel()\n\trtOpts := lib.RuntimeOptions{Env: map[string]string{\n\t\t\"TEST_A\": \"1\",\n\t\t\"TEST_B\": \"\",\n\t}}\n\tdata := `\n\t\texport default function() {\n\t\t\tif (__ENV.TEST_A !== \"1\") { throw new Error(\"Invalid TEST_A: \" + __ENV.TEST_A); }\n\t\t\tif (__ENV.TEST_B !== \"\") { throw new Error(\"Invalid TEST_B: \" + __ENV.TEST_B); }\n\t\t}\n\t`\n\tb1, err := getSimpleBundle(t, \"/script.js\", data, rtOpts)\n\trequire.NoError(t, err)\n\n\tlogger := testutils.NewLogger(t)\n\tb2, err := getSimpleBundleFromArchive(t, b1.makeArchive(), logger)\n\trequire.NoError(t, err)\n\n\tbundles := map[string]*Bundle{\"Source\": b1, \"Archive\": b2}\n\tfor name, b := range bundles {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trequire.Equal(t, \"1\", b.preInitState.RuntimeOptions.Env[\"TEST_A\"])\n\t\t\trequire.Equal(t, \"\", b.preInitState.RuntimeOptions.Env[\"TEST_B\"])\n\n\t\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\t_, err = bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestBundleNotSharable(t *testing.T) {\n\tt.Parallel()\n\tdata := `\n\t\texport default function() {\n\t\t\tif (__ITER == 0) {\n\t\t\t\tif (typeof __ENV.something !== \"undefined\") {\n\t\t\t\t\tthrow new Error(\"invalid something: \" + __ENV.something + \" should be undefined\");\n\t\t\t\t}\n\t\t\t\t__ENV.something = __VU;\n\t\t\t} else if (__ENV.something != __VU) {\n\t\t\t\tthrow new Error(\"invalid something: \" + __ENV.something+ \" should be \"+ __VU);\n\t\t\t}\n\t\t}\n\t`\n\tb1, err := getSimpleBundle(t, \"/script.js\", data)\n\trequire.NoError(t, err)\n\tlogger := testutils.NewLogger(t)\n\n\tb2, err := getSimpleBundleFromArchive(t, b1.makeArchive(), logger)\n\trequire.NoError(t, err)\n\n\tbundles := map[string]*Bundle{\"Source\": b1, \"Archive\": b2}\n\tvar vus, iters uint64 = 10, 1000\n\tfor name, b := range bundles {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor i := range vus {\n\t\t\t\tbi, err := b.Instantiate(context.Background(), i)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tfor j := range iters {\n\t\t\t\t\trequire.NoError(t, bi.Runtime.Set(\"__ITER\", j))\n\t\t\t\t\t_, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestBundleMakeArchive(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tcm      lib.CompatibilityMode\n\t\tscript  string\n\t\texclaim string\n\t}{\n\t\t{\n\t\t\tlib.CompatibilityModeExtended, `\n\t\t\t\timport exclaim from \"./exclaim.js\";\n\t\t\t\texport let options = { vus: 12345 };\n\t\t\t\texport let file = open(\"./file.txt\");\n\t\t\t\texport default function() { return exclaim(file); };`,\n\t\t\t`export default function(s) { return s + \"!\" };`,\n\t\t},\n\t\t{\n\t\t\tlib.CompatibilityModeBase, `\n\t\t\t\tvar exclaim = require(\"./exclaim.js\");\n\t\t\t\tmodule.exports.options = { vus: 12345 };\n\t\t\t\tmodule.exports.file = open(\"./file.txt\");\n\t\t\t\tmodule.exports.default = function() { return exclaim(module.exports.file); };`,\n\t\t\t`module.exports.default = function(s) { return s + \"!\" };`,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.cm.String(), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\t_ = fs.MkdirAll(\"/path/to\", 0o755)\n\t\t\t_ = fsext.WriteFile(fs, \"/path/to/file.txt\", []byte(`hi`), 0o644)\n\t\t\t_ = fsext.WriteFile(fs, \"/path/to/exclaim.js\", []byte(tc.exclaim), 0o644)\n\n\t\t\trtOpts := lib.RuntimeOptions{CompatibilityMode: null.StringFrom(tc.cm.String())}\n\t\t\tb, err := getSimpleBundle(t, \"/path/to/script.js\", tc.script, fs, rtOpts)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tarc := b.makeArchive()\n\n\t\t\tassert.Equal(t, \"js\", arc.Type)\n\t\t\tassert.Equal(t, lib.Options{VUs: null.IntFrom(12345)}, arc.Options)\n\t\t\tassert.Equal(t, \"file:///path/to/script.js\", arc.FilenameURL.String())\n\t\t\tassert.Equal(t, tc.script, string(arc.Data))\n\t\t\tassert.Equal(t, \"file:///path/to/\", arc.PwdURL.String())\n\n\t\t\texclaimData, err := fsext.ReadFile(arc.Filesystems[\"file\"], \"/path/to/exclaim.js\")\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.exclaim, string(exclaimData))\n\n\t\t\tfileData, err := fsext.ReadFile(arc.Filesystems[\"file\"], \"/path/to/file.txt\")\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, `hi`, string(fileData))\n\t\t\tassert.Equal(t, build.Version, arc.K6Version)\n\t\t\tassert.Equal(t, tc.cm.String(), arc.CompatibilityMode)\n\t\t})\n\t}\n}\n\nfunc TestGlobalTimers(t *testing.T) {\n\tt.Parallel()\n\tdata := `\n\t\t\timport timers from \"k6/timers\";\n\t\t\tif (setTimeout != timers.setTimeout) {\n\t\t\t\tthrow \"setTimeout doesn't match\";\n\t\t\t}\n\t\t\tif (clearTimeout != timers.clearTimeout) {\n\t\t\t\tthrow \"clearTimeout doesn't match\";\n\t\t\t}\n\t\t\tif (setInterval != timers.setInterval) {\n\t\t\t\tthrow \"setInterval doesn't match\";\n\t\t\t}\n\t\t\tif (clearInterval != timers.clearInterval) {\n\t\t\t\tthrow \"clearInterval doesn't match\";\n\t\t\t}\n\t\t\texport default function() {}\n\t`\n\n\tb1, err := getSimpleBundle(t, \"/script.js\", data)\n\trequire.NoError(t, err)\n\tlogger := testutils.NewLogger(t)\n\n\tb2, err := getSimpleBundleFromArchive(t, b1.makeArchive(), logger)\n\trequire.NoError(t, err)\n\n\tbundles := map[string]*Bundle{\"Source\": b1, \"Archive\": b2}\n\tfor name, b := range bundles {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := b.Instantiate(context.Background(), 1)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestTopLevelAwaitErrors(t *testing.T) {\n\tt.Parallel()\n\tdata := `\n\t\tconst delay = (delayInms) => {\n\t\t\treturn new Promise(resolve => setTimeout(resolve, delayInms));\n\t\t}\n\n\t\tawait delay(10).then(() => {something});\n\t\texport default () => {}\n\t`\n\n\t_, err := getSimpleBundle(t, \"/script.js\", data)\n\trequire.ErrorContains(t, err, \"ReferenceError: something is not defined\")\n}\n"
  },
  {
    "path": "internal/js/compiler/compiler.go",
    "content": "// Package compiler implements additional functionality for k6 to compile js code.\n// more specifically wrapping code in CommonJS wrapper or transforming it through esbuild for typescript support.\n// TODO this package name makes little sense now that it only parses and tranforms javascript.\n// Although people do call such transformation - compilation, so maybe it is still fine\npackage compiler\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/go-sourcemap/sourcemap\"\n\t\"github.com/grafana/sobek/ast\"\n\t\"github.com/grafana/sobek/parser\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/usage\"\n)\n\n// A Compiler compiles JavaScript or TypeScript source code into a sobek.Program\ntype Compiler struct {\n\tlogger  logrus.FieldLogger\n\tOptions Options\n\tusage   *usage.Usage\n}\n\n// New returns a new Compiler\nfunc New(logger logrus.FieldLogger) *Compiler {\n\treturn &Compiler{\n\t\tlogger: logger,\n\t\t// TODO(@mstoykov): unfortunately otherwise we need to do much bigger rewrite around experimental extensions\n\t\t// and likely more extensions tests. This way tests don't need to care about this and the compiler code\n\t\t// doesn't need to check if it has usage set or not.\n\t\tusage: usage.New(),\n\t}\n}\n\n// WithUsage allows the compiler to be given [usage.Usage] to use\nfunc (c *Compiler) WithUsage(u *usage.Usage) {\n\tc.usage = u\n}\n\n// Options are options to the compiler\ntype Options struct {\n\tSourceMapLoader func(string) ([]byte, error)\n}\n\n// parsingState is helper struct to keep the state of a parsing\ntype parsingState struct {\n\t// set when we couldn't load external source map so we can try parsing without loading it\n\tcouldntLoadSourceMap bool\n\t// srcMap is the current full sourceMap that has been generated read so far\n\tsrcMap          []byte\n\tsrcMapError     error\n\tcommonJSWrapped bool // whether the original source is wrapped in a function to make it a CommonJS module\n\tcompiler        *Compiler\n\tesm             bool\n\n\tloader func(string) ([]byte, error)\n}\n\n// Parse parses the provided source. It wraps as the same as CommonJS support.\n// The returned program can be compiled directly by Sobek.\n// Additionally, it returns the end code that has been parsed including any required transformations.\nfunc (c *Compiler) Parse(\n\tsrc, filename string, commonJSWrap bool, esm bool,\n) (prg *ast.Program, finalCode string, err error) {\n\tstate := &parsingState{\n\t\tloader:          c.Options.SourceMapLoader,\n\t\tcommonJSWrapped: commonJSWrap,\n\t\tcompiler:        c,\n\t\tesm:             esm,\n\t}\n\treturn state.parseImpl(src, filename, commonJSWrap)\n}\n\nconst (\n\tusageParsedFilesKey   = \"usage/parsedFiles\"\n\tusageParsedTSFilesKey = \"usage/parsedTSFiles\"\n)\n\nfunc (ps *parsingState) parseImpl(src, filename string, commonJSWrap bool) (*ast.Program, string, error) {\n\tif err := ps.compiler.usage.Uint64(usageParsedFilesKey, 1); err != nil {\n\t\tps.compiler.logger.WithError(err).Warn(\"couldn't report usage for \" + usageParsedFilesKey)\n\t}\n\tcode := src\n\tif commonJSWrap { // the lines in the sourcemap (if available) will be fixed by increaseMappingsByOne\n\t\tcode = ps.wrap(code, filename)\n\t\tps.commonJSWrapped = true\n\t}\n\tvar opts []parser.Option\n\tif ps.loader != nil {\n\t\topts = append(opts, parser.WithSourceMapLoader(ps.sourceMapLoader))\n\t} else {\n\t\topts = append(opts, parser.WithDisableSourceMaps)\n\t}\n\n\tif ps.esm {\n\t\topts = append(opts, parser.IsModule)\n\t}\n\n\tprg, err := parser.ParseFile(nil, filename, code, 0, opts...)\n\n\tif ps.couldntLoadSourceMap {\n\t\tps.couldntLoadSourceMap = false // reset\n\t\t// we probably don't want to abort scripts which have source maps but they can't be found,\n\t\t// this also will be a breaking change, so if we couldn't we retry with it disabled\n\t\tps.compiler.logger.WithError(ps.srcMapError).Warnf(\"Couldn't load source map for %s\", filename)\n\t\tps.loader = nil\n\t\treturn ps.parseImpl(src, filename, commonJSWrap)\n\t}\n\n\tif err == nil {\n\t\treturn prg, code, nil\n\t}\n\n\tisTsExtensionFile := strings.HasSuffix(filename, \".ts\")\n\tisStdin := filename == \"file:///-\"\n\tif !isTsExtensionFile && !isStdin {\n\t\treturn nil, \"\", err\n\t}\n\n\tcode, ps.srcMap, err = StripTypes(src, filename)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// At this point we have stripped types successfully, no matter whether it was a .ts file\n\t// or a script from stdin, and so we can report that a TS file been parsed successfully.\n\tif err := ps.compiler.usage.Uint64(usageParsedTSFilesKey, 1); err != nil {\n\t\tps.compiler.logger.WithError(err).Warn(\"couldn't report usage for \" + usageParsedTSFilesKey)\n\t}\n\n\tif ps.loader != nil {\n\t\t// This hack is required for the source map to work\n\t\tcode += \"\\n//# sourceMappingURL=\" + internalSourceMapURL\n\t}\n\tps.commonJSWrapped = false\n\treturn ps.parseImpl(code, filename, commonJSWrap)\n}\n\nfunc (ps *parsingState) wrap(code, filename string) string {\n\tconditionalNewLine := \"\"\n\tif index := strings.LastIndex(code, \"//# sourceMappingURL=\"); index != -1 {\n\t\t// the lines in the sourcemap (if available) will be fixed by increaseMappingsByOne\n\t\tconditionalNewLine = \"\\n\"\n\t\tnewCode, err := ps.updateInlineSourceMap(code, index)\n\t\tif err != nil {\n\t\t\tps.compiler.logger.Warnf(\"while parsing %q, couldn't update its inline sourcemap which might lead \"+\n\t\t\t\t\"to some line numbers being off: %s\", filename, err)\n\t\t} else {\n\t\t\tcode = newCode\n\t\t}\n\n\t\t// if there is no sourcemap - bork only the first line of code, but leave the remaining ones.\n\t}\n\treturn \"(function(module, exports){\" + conditionalNewLine + code + \"\\n})\\n\"\n}\n\nconst internalSourceMapURL = \"k6://internal-should-not-leak/file.map\"\n\n// sourceMapLoader is to be used with Sobek's WithSourceMapLoader to add more than just loading files from disk.\n// It additionally:\n// - Loads a source-map if the it was generated from internal process.\n// - It additioanlly fixes off-by-one error for CommonJS dependencies due to having to wrap them in a functions.\nfunc (ps *parsingState) sourceMapLoader(path string) ([]byte, error) {\n\tif path == internalSourceMapURL {\n\t\tif ps.commonJSWrapped {\n\t\t\treturn ps.increaseMappingsByOne(ps.srcMap)\n\t\t}\n\t\treturn ps.srcMap, nil\n\t}\n\tps.srcMap, ps.srcMapError = ps.loader(path)\n\tif ps.srcMapError != nil {\n\t\tps.couldntLoadSourceMap = true\n\t\treturn nil, ps.srcMapError\n\t}\n\t_, ps.srcMapError = sourcemap.Parse(path, ps.srcMap)\n\tif ps.srcMapError != nil {\n\t\tps.couldntLoadSourceMap = true\n\t\tps.srcMap = nil\n\t\treturn nil, ps.srcMapError\n\t}\n\tif ps.commonJSWrapped {\n\t\treturn ps.increaseMappingsByOne(ps.srcMap)\n\t}\n\treturn ps.srcMap, nil\n}\n\nfunc (ps *parsingState) updateInlineSourceMap(code string, index int) (string, error) {\n\tnextnewline := strings.Index(code[index:], \"\\n\")\n\tif nextnewline == -1 {\n\t\tnextnewline = len(code[index:])\n\t}\n\tmapurl := code[index : index+nextnewline]\n\tconst base64EncodePrefix = \"application/json;base64,\"\n\tif startOfBase64EncodedSourceMap := strings.Index(mapurl, base64EncodePrefix); startOfBase64EncodedSourceMap != -1 {\n\t\tstartOfBase64EncodedSourceMap += len(base64EncodePrefix)\n\t\tb, err := base64.StdEncoding.DecodeString(mapurl[startOfBase64EncodedSourceMap:])\n\t\tif err != nil {\n\t\t\treturn code, err\n\t\t}\n\t\tb, err = ps.increaseMappingsByOne(b)\n\t\tif err != nil {\n\t\t\treturn code, err\n\t\t}\n\t\tencoded := base64.StdEncoding.EncodeToString(b)\n\t\tcode = code[:index] + \"//# sourceMappingURL=data:application/json;base64,\" + encoded + code[index+nextnewline:]\n\t}\n\treturn code, nil\n}\n\n// increaseMappingsByOne increases the lines in the sourcemap by line so that it fixes the case where we need to wrap a\n// required file in a function to support/emulate commonjs\nfunc (ps *parsingState) increaseMappingsByOne(sourceMap []byte) ([]byte, error) {\n\tvar err error\n\tm := make(map[string]any)\n\tif err = json.Unmarshal(sourceMap, &m); err != nil {\n\t\treturn nil, err\n\t}\n\tmappings, ok := m[\"mappings\"]\n\tif !ok {\n\t\t// no mappings, no idea what this will do, but just return it as technically we can have sourcemap with sections\n\t\t// TODO implement incrementing of `offset` in the sections? to support that case as well\n\t\t// see https://sourcemaps.info/spec.html#h.n05z8dfyl3yh\n\t\t//\n\t\t// TODO (kind of alternatively) drop the newline in the \"commonjs\" wrapping and have only the first line wrong\n\t\t// and drop this whole function\n\t\treturn sourceMap, nil\n\t}\n\tif str, ok := mappings.(string); ok {\n\t\t// ';' is the separator between lines so just adding 1 will make all mappings be for the line after which they were\n\t\t// originally\n\t\tm[\"mappings\"] = \";\" + str\n\t} else {\n\t\t// we have mappings but it's not a string - this is some kind of error\n\t\t// we still won't abort the test but just not load the sourcemap\n\t\tps.couldntLoadSourceMap = true\n\t\treturn nil, errors.New(`missing \"mappings\" in sourcemap`)\n\t}\n\n\treturn json.Marshal(m)\n}\n"
  },
  {
    "path": "internal/js/compiler/compiler_test.go",
    "content": "package compiler\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/grafana/sobek/parser\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n)\n\nfunc TestCompile(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"ES5\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tsrc := `1+(function() { return 2; })()`\n\t\tprg, code, err := c.Parse(src, \"script.js\", false, false)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, src, code)\n\t\tpgm, err := sobek.CompileAST(prg, true)\n\t\trequire.NoError(t, err)\n\t\tv, err := sobek.New().RunProgram(pgm)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, int64(3), v.Export())\n\t})\n\n\tt.Run(\"ES5 Wrap\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tsrc := `exports.d=1+(function() { return 2; })()`\n\t\tprg, code, err := c.Parse(src, \"script.js\", true, false)\n\t\trequire.NoError(t, err)\n\t\tpgm, err := sobek.CompileAST(prg, true)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"(function(module, exports){exports.d=1+(function() { return 2; })()\\n})\\n\", code)\n\t\trt := sobek.New()\n\t\tv, err := rt.RunProgram(pgm)\n\t\tif assert.NoError(t, err) {\n\t\t\tfn, ok := sobek.AssertFunction(v)\n\t\t\tif assert.True(t, ok, \"not a function\") {\n\t\t\t\texp := make(map[string]sobek.Value)\n\t\t\t\t_, err := fn(sobek.Undefined(), sobek.Undefined(), rt.ToValue(exp))\n\t\t\t\tif assert.NoError(t, err) {\n\t\t\t\t\tassert.Equal(t, int64(3), exp[\"d\"].Export())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n\n\tt.Run(\"ES6\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tprg, code, err := c.Parse(`import \"something\"`, \"script.js\", false, true)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, `import \"something\"`, code)\n\t\trequire.NoError(t, err)\n\t\t_, err = sobek.CompileAST(prg, true)\n\t\trequire.NoError(t, err)\n\t\t// TODO running this is a bit more involved :(\n\t})\n\n\tt.Run(\"Wrap\", func(t *testing.T) {\n\t\t// This only works with `require` as wrapping means the import/export won't be top level and that is forbidden\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tprg, code, err := c.Parse(`require(\"something\");`, \"script.js\", true, false)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, `(function(module, exports){require(\"something\");\n})\n`, code)\n\t\tvar requireCalled bool\n\t\trt := sobek.New()\n\t\trequire.NoError(t, rt.Set(\"require\", func(s string) {\n\t\t\tassert.Equal(t, \"something\", s)\n\t\t\trequireCalled = true\n\t\t}))\n\n\t\tpgm, err := sobek.CompileAST(prg, true)\n\t\trequire.NoError(t, err)\n\t\tv, err := rt.RunProgram(pgm)\n\t\trequire.NoError(t, err)\n\t\tfn, ok := sobek.AssertFunction(v)\n\t\trequire.True(t, ok, \"not a function\")\n\t\t_, err = fn(sobek.Undefined())\n\t\tassert.NoError(t, err)\n\t\trequire.True(t, requireCalled)\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\t_, _, err := c.Parse(`1+(=>2)()`, \"script.js\", false, false)\n\t\tassert.IsType(t, parser.ErrorList{}, err)\n\t\tassert.Contains(t, err.Error(), `Line 1:4 Unexpected token =>`)\n\t})\n\n\tt.Run(\"Stdin TS\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tsrc := `1 + (((): number => 2)());`\n\t\tprg, _, err := c.Parse(src, \"file:///-\", false, false)\n\t\trequire.NoError(t, err)\n\t\tpgm, err := sobek.CompileAST(prg, true)\n\t\trequire.NoError(t, err)\n\t\tv, err := sobek.New().RunProgram(pgm)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, int64(3), v.Export())\n\t})\n}\n\nfunc TestCorruptSourceMap(t *testing.T) {\n\tt.Parallel()\n\tcorruptSourceMap := []byte(`{\"mappings\": 12}`) // 12 is a number not a string\n\n\tlogger := logrus.New()\n\tlogger.SetLevel(logrus.DebugLevel)\n\tlogger.Out = io.Discard\n\thook := testutils.SimpleLogrusHook{\n\t\tHookedLevels: []logrus.Level{logrus.InfoLevel, logrus.WarnLevel},\n\t}\n\tlogger.AddHook(&hook)\n\n\tcompiler := New(logger)\n\tcompiler.Options = Options{\n\t\tSourceMapLoader: func(string) ([]byte, error) {\n\t\t\treturn corruptSourceMap, nil\n\t\t},\n\t}\n\t_, _, err := compiler.Parse(\"var s = 5;\\n//# sourceMappingURL=somefile\", \"somefile\", false, false)\n\trequire.NoError(t, err)\n\tentries := hook.Drain()\n\trequire.Len(t, entries, 1)\n\tmsg, err := entries[0].String() // we need this in order to get the field error\n\trequire.NoError(t, err)\n\n\trequire.Contains(t, msg, `Couldn't load source map for somefile`)\n\t// @mstoykov: this is split as message changed in go1.24\n\trequire.Contains(t, msg, `json: cannot unmarshal number into Go struct field`)\n\trequire.Contains(t, msg, `mappings of type string`)\n}\n\nfunc TestMinimalSourceMap(t *testing.T) {\n\tt.Parallel()\n\tcorruptSourceMap := []byte(`{\"version\":3,\"mappings\":\";\",\"sources\":[]}`)\n\n\tlogger := logrus.New()\n\tlogger.SetLevel(logrus.DebugLevel)\n\tlogger.Out = io.Discard\n\thook := testutils.SimpleLogrusHook{\n\t\tHookedLevels: []logrus.Level{logrus.InfoLevel, logrus.WarnLevel},\n\t}\n\tlogger.AddHook(&hook)\n\n\tcompiler := New(logger)\n\tcompiler.Options = Options{\n\t\tSourceMapLoader: func(string) ([]byte, error) {\n\t\t\treturn corruptSourceMap, nil\n\t\t},\n\t}\n\t_, _, err := compiler.Parse(\"class s {};\\n//# sourceMappingURL=somefile\", \"somefile\", false, false)\n\trequire.NoError(t, err)\n\trequire.Empty(t, hook.Drain())\n}\n"
  },
  {
    "path": "internal/js/compiler/enhanced.go",
    "content": "package compiler\n\nimport (\n\t\"github.com/evanw/esbuild/pkg/api\"\n\t\"github.com/grafana/sobek/file\"\n\t\"github.com/grafana/sobek/parser\"\n)\n\n// StripTypes transpiles the input source string and strip types from it.\n// this is done using esbuild\nfunc StripTypes(src, filename string) (code string, srcMap []byte, err error) {\n\topts := api.TransformOptions{\n\t\tLoader:         api.LoaderTS,\n\t\tSourcefile:     filename,\n\t\tTarget:         api.ESNext,\n\t\tFormat:         api.FormatDefault,\n\t\tSourcemap:      api.SourceMapExternal,\n\t\tSourcesContent: api.SourcesContentInclude,\n\t\tLegalComments:  api.LegalCommentsNone,\n\t\tPlatform:       api.PlatformNeutral,\n\t\tLogLevel:       api.LogLevelSilent,\n\t\tCharset:        api.CharsetUTF8,\n\t}\n\n\tresult := api.Transform(src, opts)\n\n\tif hasError, err := esbuildCheckError(&result); hasError {\n\t\treturn \"\", nil, err\n\t}\n\n\treturn string(result.Code), result.Map, nil\n}\n\nfunc esbuildCheckError(result *api.TransformResult) (bool, error) {\n\tif len(result.Errors) == 0 {\n\t\treturn false, nil\n\t}\n\n\tmsg := result.Errors[0]\n\terr := &parser.Error{Message: msg.Text}\n\n\tif msg.Location != nil {\n\t\terr.Position = file.Position{\n\t\t\tFilename: msg.Location.File,\n\t\t\tLine:     msg.Location.Line,\n\t\t\tColumn:   msg.Location.Column,\n\t\t}\n\t}\n\n\treturn true, err\n}\n"
  },
  {
    "path": "internal/js/compiler/enhanced_test.go",
    "content": "package compiler\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/grafana/sobek/parser\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n)\n\nfunc Test_esbuildTransform_js(t *testing.T) {\n\tt.Parallel()\n\n\tcode, srcMap, err := StripTypes(`export default function(name) { return \"Hello, \" + name }`, \"script.js\")\n\n\trequire.NoError(t, err)\n\trequire.NotNil(t, srcMap)\n\trequire.NotEmpty(t, code)\n}\n\nfunc Test_esbuildTransform_ts(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `export function hello(name:string) : string { return \"Hello, \" + name}`\n\n\tcode, srcMap, err := StripTypes(script, \"script.ts\")\n\n\trequire.NoError(t, err)\n\trequire.NotNil(t, srcMap)\n\trequire.NotEmpty(t, code)\n}\n\nfunc TestCompile_experimental_enhanced(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"experimental_enhanced Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tsrc := `1+(function() { return 2; )()`\n\t\t_, _, err := c.Parse(src, \"script.ts\", false, false)\n\t\tassert.IsType(t, &parser.Error{}, err)\n\t\tassert.Contains(t, err.Error(), `script.ts: Line 1:26 Unexpected \")\"`)\n\t})\n\tt.Run(\"experimental_enhanced\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tprg, code, err := c.Parse(`let t :string = \"something\"; require(t);`, \"script.ts\", false, false)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, `let t = \"something\";\nrequire(t);\n`, code)\n\t\tpgm, err := sobek.CompileAST(prg, true)\n\t\trequire.NoError(t, err)\n\t\trt := sobek.New()\n\t\tvar requireCalled bool\n\t\trequire.NoError(t, rt.Set(\"require\", func(s string) {\n\t\t\tassert.Equal(t, \"something\", s)\n\t\t\trequireCalled = true\n\t\t}))\n\t\t_, err = rt.RunProgram(pgm)\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, requireCalled)\n\t})\n\tt.Run(\"experimental_enhanced sourcemap\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := New(testutils.NewLogger(t))\n\t\tc.Options.SourceMapLoader = func(_ string) ([]byte, error) { return nil, nil }\n\t\t_, code, err := c.Parse(`let t :string = \"something\"; require(t);`, \"script.ts\", false, false)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, `let t = \"something\";\nrequire(t);\n\n//# sourceMappingURL=k6://internal-should-not-leak/file.map`, code)\n\t})\n}\n"
  },
  {
    "path": "internal/js/console.go",
    "content": "package js\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/js/common\"\n)\n\n// console represents a JS console implemented as a logrus.FieldLogger.\ntype console struct {\n\tlogger logrus.FieldLogger\n}\n\n// Creates a console with the standard logrus logger.\nfunc newConsole(logger logrus.FieldLogger) *console {\n\treturn &console{logger.WithField(\"source\", \"console\")}\n}\n\n// Creates a console logger with its output set to the file at the provided `filepath`.\nfunc newFileConsole(filepath string, formatter logrus.Formatter, level logrus.Level) (*console, error) {\n\t//nolint:gosec,forbidigo // see https://github.com/grafana/k6/issues/2565\n\tf, err := os.OpenFile(filepath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tl := logrus.New()\n\tl.SetLevel(level)\n\tl.SetOutput(f)\n\tl.SetFormatter(formatter)\n\n\treturn &console{l}, nil\n}\n\nfunc (c console) log(level logrus.Level, args ...sobek.Value) {\n\tvar strs strings.Builder\n\tfor i := range args {\n\t\tif i > 0 {\n\t\t\tstrs.WriteString(\" \")\n\t\t}\n\t\tstrs.WriteString(c.valueString(args[i]))\n\t}\n\tmsg := strs.String()\n\n\tswitch level {\n\tcase logrus.DebugLevel:\n\t\tc.logger.Debug(msg)\n\tcase logrus.InfoLevel:\n\t\tc.logger.Info(msg)\n\tcase logrus.WarnLevel:\n\t\tc.logger.Warn(msg)\n\tcase logrus.ErrorLevel:\n\t\tc.logger.Error(msg)\n\tdefault:\n\t\tpanic(\"unsupported log level: \" + level.String())\n\t}\n}\n\nfunc (c console) Log(args ...sobek.Value) {\n\tc.Info(args...)\n}\n\nfunc (c console) Debug(args ...sobek.Value) {\n\tc.log(logrus.DebugLevel, args...)\n}\n\nfunc (c console) Info(args ...sobek.Value) {\n\tc.log(logrus.InfoLevel, args...)\n}\n\nfunc (c console) Warn(args ...sobek.Value) {\n\tc.log(logrus.WarnLevel, args...)\n}\n\nfunc (c console) Error(args ...sobek.Value) {\n\tc.log(logrus.ErrorLevel, args...)\n}\n\nconst (\n\tfunctionLog = \"[object Function]\"\n\tcircularLog = \"[Circular]\"\n)\n\n// errorType is used to check if a [sobek.Value] implements the [error] interface.\n//\n//nolint:gochecknoglobals\nvar errorType = reflect.TypeFor[error]()\n\nfunc (c console) valueString(v sobek.Value) string {\n\tif _, isFunction := sobek.AssertFunction(v); isFunction {\n\t\treturn functionLog\n\t}\n\n\tif exportType := v.ExportType(); exportType != nil && exportType.Implements(errorType) {\n\t\tif exported := v.Export(); exported != nil {\n\t\t\tif err, isError := exported.(error); isError {\n\t\t\t\treturn err.Error()\n\t\t\t}\n\t\t}\n\t}\n\n\tobj, isObj := v.(*sobek.Object)\n\tif !isObj {\n\t\treturn v.String()\n\t}\n\tif obj.ClassName() == \"Error\" {\n\t\treturn v.String()\n\t}\n\n\tvar sb strings.Builder\n\tc.traverseValue(&sb, obj, make(map[*sobek.Object]bool))\n\treturn sb.String()\n}\n\n// traverseValue recursively traverses a [sobek.Value] and writes a formatted\n// string representation to the provided strings.Builder. For functions, it writes\n// [functionLog], and for circular references, it writes [circularLog].\n//\n// It prevents circular references by keeping track of seen objects.\nfunc (c console) traverseValue(sb *strings.Builder, v sobek.Value, seen map[*sobek.Object]bool) {\n\t// Handles null and sparse values in arrays.\n\tif common.IsNullish(v) {\n\t\tsb.WriteString(\"null\")\n\t\treturn\n\t}\n\n\t// Represent functions as a fixed string.\n\tif _, isFunc := sobek.AssertFunction(v); isFunc {\n\t\tsb.WriteString(functionLog)\n\t\treturn\n\t}\n\n\t// Handle non-object values.\n\tobj, ok := v.(*sobek.Object)\n\tif !ok {\n\t\tformatPrimitive(sb, v)\n\t\treturn\n\t}\n\n\t// Prevent circular references.\n\tif seen[obj] {\n\t\tsb.WriteString(circularLog)\n\t\treturn\n\t}\n\tseen[obj] = true\n\tdefer delete(seen, obj)\n\n\tif obj.ClassName() == \"Error\" {\n\t\tsb.WriteString(v.String())\n\t\treturn\n\t}\n\n\t// Check for TypedArray and ArrayBuffer.\n\tif isBinaryData(obj) {\n\t\tformatBinaryData(sb, obj)\n\t\treturn\n\t}\n\n\t// Handle arrays element-by-element, recursively.\n\tif obj.ClassName() == \"Array\" {\n\t\tlength := obj.Get(\"length\").ToInteger()\n\t\tif length == 0 {\n\t\t\tsb.WriteString(\"[]\")\n\t\t\treturn\n\t\t}\n\t\tsb.WriteString(\"[ \")\n\t\tfor i := range length {\n\t\t\tif i > 0 {\n\t\t\t\tsb.WriteString(\", \")\n\t\t\t}\n\t\t\tc.traverseValue(sb, obj.Get(strconv.FormatInt(i, 10)), seen)\n\t\t}\n\t\tsb.WriteString(\" ]\")\n\t\treturn\n\t}\n\n\tkeys := obj.Keys()\n\t// for empty objects and other JS types with no enumerable properties.\n\tif len(keys) == 0 {\n\t\t// Date objects have no enumerable keys but should display as ISO string.\n\t\tif obj.ClassName() == \"Date\" {\n\t\t\tformatDate(sb, obj)\n\t\t\treturn\n\t\t}\n\t\tsb.WriteString(\"{}\")\n\t\treturn\n\t}\n\n\t// Handle objects key-by-key, recursively.\n\tsb.WriteString(\"{ \")\n\tfor i, key := range keys {\n\t\tif i > 0 {\n\t\t\tsb.WriteString(\", \")\n\t\t}\n\t\tsb.WriteString(key)\n\t\tsb.WriteString(\": \")\n\t\tc.traverseValue(sb, obj.Get(key), seen)\n\t}\n\tsb.WriteString(\" }\")\n}\n\n// formatDate writes a Date object as a quoted ISO string to the builder.\nfunc formatDate(sb *strings.Builder, obj *sobek.Object) {\n\tif toISOString, ok := sobek.AssertFunction(obj.Get(\"toISOString\")); ok {\n\t\tif result, err := toISOString(obj); err == nil {\n\t\t\tsb.WriteByte('\"')\n\t\t\tsb.WriteString(result.String())\n\t\t\tsb.WriteByte('\"')\n\t\t\treturn\n\t\t}\n\t}\n\tsb.WriteString(\"{}\")\n}\n\n// formatPrimitive writes a primitive JS value to the builder.\nfunc formatPrimitive(sb *strings.Builder, v sobek.Value) {\n\tswitch v.ExportType().Kind() {\n\tcase reflect.String:\n\t\tsb.WriteByte('\"')\n\t\tsb.WriteString(v.String())\n\t\tsb.WriteByte('\"')\n\tdefault:\n\t\tsb.WriteString(v.String())\n\t}\n}\n\n// isBinaryData checks for TypedArray and ArrayBuffer.\nfunc isBinaryData(obj *sobek.Object) bool {\n\texportType := obj.ExportType()\n\tif exportType == nil {\n\t\treturn false\n\t}\n\n\tif _, ok := obj.Export().(sobek.ArrayBuffer); ok {\n\t\treturn true\n\t}\n\n\tif exportType.Kind() != reflect.Slice {\n\t\treturn false\n\t}\n\tswitch exportType.Elem().Kind() {\n\tcase reflect.Int8, reflect.Uint8,\n\t\treflect.Int16, reflect.Uint16,\n\t\treflect.Int32, reflect.Uint32,\n\t\treflect.Float32, reflect.Float64,\n\t\treflect.Int64, reflect.Uint64:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// formatBinaryData writes the formatted representation of TypedArray or ArrayBuffer to the builder.\nfunc formatBinaryData(sb *strings.Builder, obj *sobek.Object) {\n\t// ArrayBuffer\n\tif ab, ok := obj.Export().(sobek.ArrayBuffer); ok {\n\t\tbytes := ab.Bytes()\n\t\tsb.WriteString(\"ArrayBuffer { [Uint8Contents]: <\")\n\t\tfor i, b := range bytes {\n\t\t\tif i > 0 {\n\t\t\t\tsb.WriteByte(' ')\n\t\t\t}\n\t\t\tfmt.Fprintf(sb, \"%02x\", b)\n\t\t}\n\t\tsb.WriteString(\">, byteLength: \")\n\t\tsb.WriteString(strconv.Itoa(len(bytes)))\n\t\tsb.WriteString(\" }\")\n\t\treturn\n\t}\n\n\t// TypedArray\n\texportType := obj.ExportType()\n\tif exportType != nil && exportType.Kind() == reflect.Slice {\n\t\ttypeName := typedArrayName(exportType)\n\t\tlength := obj.Get(\"length\").ToInteger()\n\n\t\tsb.WriteString(typeName)\n\t\tsb.WriteByte('(')\n\t\tsb.WriteString(strconv.FormatInt(length, 10))\n\t\tsb.WriteByte(')')\n\n\t\tif length == 0 {\n\t\t\tsb.WriteString(\" []\")\n\t\t\treturn\n\t\t}\n\n\t\tsb.WriteString(\" [ \")\n\t\tfor i := range length {\n\t\t\tif i > 0 {\n\t\t\t\tsb.WriteString(\", \")\n\t\t\t}\n\t\t\tsb.WriteString(obj.Get(strconv.FormatInt(i, 10)).String())\n\t\t}\n\t\tsb.WriteString(\" ]\")\n\t\treturn\n\t}\n\n\tsb.WriteString(obj.String())\n}\n\n// typedArrayName maps Go reflect.Kind -> TypedArray name.\nfunc typedArrayName(exportType reflect.Type) string {\n\t// Note: Can't distinguish Uint8ClampedArray this way\n\tswitch exportType.Elem().Kind() {\n\tcase reflect.Int8:\n\t\treturn \"Int8Array\"\n\tcase reflect.Uint8:\n\t\treturn \"Uint8Array\"\n\tcase reflect.Int16:\n\t\treturn \"Int16Array\"\n\tcase reflect.Uint16:\n\t\treturn \"Uint16Array\"\n\tcase reflect.Int32:\n\t\treturn \"Int32Array\"\n\tcase reflect.Uint32:\n\t\treturn \"Uint32Array\"\n\tcase reflect.Float32:\n\t\treturn \"Float32Array\"\n\tcase reflect.Float64:\n\t\treturn \"Float64Array\"\n\tcase reflect.Int64:\n\t\treturn \"BigInt64Array\"\n\tcase reflect.Uint64:\n\t\treturn \"BigUint64Array\"\n\tdefault:\n\t\treturn \"TypedArray\"\n\t}\n}\n"
  },
  {
    "path": "internal/js/console_test.go",
    "content": "package js\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\tlogtest \"github.com/sirupsen/logrus/hooks/test\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestConsoleContext(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\tlogger, hook := logtest.NewNullLogger()\n\t_ = rt.Set(\"console\", &console{logger})\n\n\t_, err := rt.RunString(`console.log(\"a\")`)\n\trequire.NoError(t, err)\n\tentry := hook.LastEntry()\n\trequire.NotNil(t, entry)\n\tassert.Equal(t, \"a\", entry.Message)\n\n\t_, err = rt.RunString(`console.log(\"b\")`)\n\trequire.NoError(t, err)\n\tentry = hook.LastEntry()\n\trequire.NotNil(t, entry)\n\trequire.Equal(t, \"b\", entry.Message)\n}\n\nfunc getSimpleRunner(tb testing.TB, filename, data string, opts ...any) (*Runner, error) {\n\tvar (\n\t\trtOpts      = lib.RuntimeOptions{CompatibilityMode: null.NewString(\"base\", true)}\n\t\tlogger      = testutils.NewLogger(tb)\n\t\tfsResolvers = map[string]fsext.Fs{\"file\": fsext.NewMemMapFs(), \"https\": fsext.NewMemMapFs()}\n\t)\n\tfor _, o := range opts {\n\t\tswitch opt := o.(type) {\n\t\tcase fsext.Fs:\n\t\t\tfsResolvers[\"file\"] = opt\n\t\tcase map[string]fsext.Fs:\n\t\t\tfsResolvers = opt\n\t\tcase lib.RuntimeOptions:\n\t\t\trtOpts = opt\n\t\tcase logrus.FieldLogger:\n\t\t\tlogger = opt\n\t\tdefault:\n\t\t\ttb.Fatalf(\"unknown test option %q\", opt)\n\t\t}\n\t}\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tfilenameURL := &url.URL{Path: filename, Scheme: \"file\"}\n\n\tpreInitState := &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tRuntimeOptions: rtOpts,\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tRegistry:       registry,\n\t\tLookupEnv:      func(_ string) (val string, ok bool) { return \"\", false },\n\t\tUsage:          usage.New(),\n\t}\n\tmoduleResolver := NewModuleResolver(loader.Dir(filenameURL), preInitState, fsResolvers)\n\treturn New(\n\t\tpreInitState,\n\t\t&loader.SourceData{\n\t\t\tURL:  filenameURL,\n\t\t\tData: []byte(data),\n\t\t},\n\t\tfsResolvers,\n\t\tmoduleResolver,\n\t)\n}\n\nfunc getSimpleArchiveRunner(tb testing.TB, arc *lib.Archive, opts ...any) (*Runner, error) {\n\tvar (\n\t\trtOpts      = lib.RuntimeOptions{CompatibilityMode: null.NewString(\"base\", true)}\n\t\tlogger      = testutils.NewLogger(tb)\n\t\tfsResolvers = map[string]fsext.Fs{\"file\": fsext.NewMemMapFs(), \"https\": fsext.NewMemMapFs()}\n\t)\n\tfor _, o := range opts {\n\t\tswitch opt := o.(type) {\n\t\tcase fsext.Fs:\n\t\t\tfsResolvers[\"file\"] = opt\n\t\tcase map[string]fsext.Fs:\n\t\t\tfsResolvers = opt\n\t\tcase lib.RuntimeOptions:\n\t\t\trtOpts = opt\n\t\tcase logrus.FieldLogger:\n\t\t\tlogger = opt\n\t\tdefault:\n\t\t\ttb.Fatalf(\"unknown test option %q\", opt)\n\t\t}\n\t}\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tpreInitState := &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tRuntimeOptions: rtOpts,\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tRegistry:       registry,\n\t\tUsage:          usage.New(),\n\t}\n\tmoduleResolver := NewModuleResolver(arc.PwdURL, preInitState, arc.Filesystems)\n\treturn NewFromArchive(preInitState, arc, moduleResolver)\n}\n\n// TODO: remove the need for this function, see https://github.com/grafana/k6/issues/2968\n//\n//nolint:forbidigo\nfunc extractLogger(vu lib.ActiveVU) *logrus.Logger {\n\tvuSpecific, ok := vu.(*ActiveVU)\n\tif !ok {\n\t\tpanic(\"lib.ActiveVU can't be caset to *ActiveVU\")\n\t}\n\tfl := vuSpecific.Console.logger\n\tswitch e := fl.(type) {\n\tcase *logrus.Entry:\n\t\treturn e.Logger\n\tcase *logrus.Logger:\n\t\treturn e\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown logrus.FieldLogger option %q\", fl))\n\t}\n}\n\nfunc TestConsoleLogWithSobekNativeObject(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\tobj := rt.NewObject()\n\terr := obj.Set(\"text\", \"nativeObject\")\n\trequire.NoError(t, err)\n\n\tlogger, hook := testutils.NewLoggerWithHook(t)\n\n\tc := newConsole(logger)\n\tc.Log(obj)\n\n\tentry := hook.LastEntry()\n\trequire.NotNil(t, entry, \"nothing logged\")\n\trequire.Equal(t, `{ text: \"nativeObject\" }`, entry.Message)\n}\n\nfunc TestConsoleLogObjectsWithGoTypes(t *testing.T) {\n\tt.Parallel()\n\n\ttype value struct {\n\t\tText string\n\t}\n\n\ttests := []struct {\n\t\tname string\n\t\tin   any\n\t\texp  string\n\t}{\n\t\t{\n\t\t\tname: \"StructLiteral\",\n\t\t\tin: value{\n\t\t\t\tText: \"test1\",\n\t\t\t},\n\t\t\texp: `{ text: \"test1\" }`,\n\t\t},\n\t\t{\n\t\t\tname: \"StructPointer\",\n\t\t\tin: &value{\n\t\t\t\tText: \"test2\",\n\t\t\t},\n\t\t\texp: `{ text: \"test2\" }`,\n\t\t},\n\t\t{\n\t\t\tname: \"Map\",\n\t\t\tin: map[string]any{\n\t\t\t\t\"text\": \"test3\",\n\t\t\t},\n\t\t\texp: `{ text: \"test3\" }`,\n\t\t},\n\t}\n\n\texpFields := logrus.Fields{\"source\": \"console\"}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := sobek.New()\n\t\t\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\t\t\tobj := rt.ToValue(tt.in)\n\n\t\t\tlogger, hook := testutils.NewLoggerWithHook(t)\n\n\t\t\tc := newConsole(logger)\n\t\t\tc.Log(obj)\n\n\t\t\tentry := hook.LastEntry()\n\t\t\trequire.NotNil(t, entry, \"nothing logged\")\n\t\t\tassert.Equal(t, tt.exp, entry.Message)\n\t\t\tassert.Equal(t, expFields, entry.Data)\n\t\t})\n\t}\n}\n\nfunc TestConsoleLog(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tin       string\n\t\texpected string\n\t}{\n\t\t{``, ``},\n\t\t{`\"\"`, ``},\n\t\t{`undefined`, `undefined`},\n\t\t{`null`, `null`},\n\n\t\t{in: `\"string\"`, expected: \"string\"},\n\t\t{in: `\"string\",\"a\",\"b\"`, expected: \"string a b\"},\n\t\t{in: `\"string\",1,2`, expected: \"string 1 2\"},\n\n\t\t{in: `true`, expected: \"true\"},\n\n\t\t{in: `Infinity`, expected: \"Infinity\"},\n\t\t{in: `1e5`, expected: \"100000\"},\n\t\t{in: `1.23e-4`, expected: \"0.000123\"},\n\n\t\t{in: `function() {}`, expected: \"[object Function]\"},\n\t\t{in: `() => {}`, expected: \"[object Function]\"},\n\n\t\t{in: `new Date(0)`, expected: `\"1970-01-01T00:00:00.000Z\"`},\n\t\t{in: `new Error(\"test error\")`, expected: \"Error: test error\"},\n\n\t\t{in: `[\"bar\", 1, 2]`, expected: `[ \"bar\", 1, 2 ]`},\n\t\t{in: `\"bar\", [\"bar\", 0x01, 2], 1, 2`, expected: `bar [ \"bar\", 1, 2 ] 1 2`},\n\n\t\t{in: `{}`, expected: \"{}\"},\n\t\t{in: `{foo:\"bar\"}`, expected: `{ foo: \"bar\" }`},\n\t\t{in: `[\"test1\", 2]`, expected: `[ \"test1\", 2 ]`},\n\n\t\t{in: `{fn: function(){}}`, expected: `{ fn: [object Function] }`},\n\t\t{in: `{fn: function(){}, dt: new Date(0)}`, expected: `{ fn: [object Function], dt: \"1970-01-01T00:00:00.000Z\" }`},\n\t\t{in: `{fn: () => {}}`, expected: `{ fn: [object Function] }`},\n\t\t{in: `{a: 1, fn: function(){}, b: \"two\"}`, expected: `{ a: 1, fn: [object Function], b: \"two\" }`},\n\t\t{in: `{nested: {fn: function(){}}}`, expected: `{ nested: { fn: [object Function] } }`},\n\t\t{in: `[function(){}, 1, \"two\"]`, expected: `[ [object Function], 1, \"two\" ]`},\n\t\t{\n\t\t\tin: `{\n\t\t\t\tarr: [1, 2],\n\t\t\t\tobj: {\n\t\t\t\t\t'a': 'foo', 'b': {\n\t\t\t\t\t\t'c': { 'd': 123 }\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tstr: 'hi'\n\t\t\t}`,\n\t\t\texpected: `{ arr: [ 1, 2 ], obj: { a: \"foo\", b: { c: { d: 123 } } }, str: \"hi\" }`,\n\t\t},\n\n\t\t{in: `[null, undefined, 1]`, expected: `[ null, null, 1 ]`},\n\t\t{in: `[1, , 3]`, expected: `[ 1, null, 3 ]`}, // sparse arrays (holes in arrays)\n\t\t{in: `[[function(){}], [1, 2]]`, expected: `[ [ [object Function] ], [ 1, 2 ] ]`},\n\t\t{in: `new RegExp(\"test\")`, expected: `{}`}, // JSON.stringify of RegExp is {}\n\t\t{in: `{[Symbol(\"test\")]: \"value\", a: 1}`, expected: `{ a: 1 }`},\n\t\t{in: `Object.defineProperty({}, 'x', {get: function() { throw new Error(); }})`, expected: `{}`},\n\t\t{in: `Object.create({inherited: 1}, {own: {value: 2, enumerable: true}})`, expected: `{ own: 2 }`},\n\n\t\t// circular reference AND function (both code paths)\n\t\t{\n\t\t\tin:       `function() {var a = {fn: function(){}, foo: {}}; a.foo = a; return a}()`,\n\t\t\texpected: `{ fn: [object Function], foo: [Circular] }`,\n\t\t},\n\n\t\t// TypedArray and ArrayBuffer formatting\n\t\t{in: `new Int8Array([1, -2, 127, -128])`, expected: `Int8Array(4) [ 1, -2, 127, -128 ]`},\n\t\t{in: `new Uint8Array([0, 128, 255])`, expected: `Uint8Array(3) [ 0, 128, 255 ]`},\n\t\t{in: `new Uint8ClampedArray([0, 128, 255])`, expected: `Uint8Array(3) [ 0, 128, 255 ]`}, // shows as Uint8Array\n\t\t{in: `new Int16Array([100, -100, 32767])`, expected: `Int16Array(3) [ 100, -100, 32767 ]`},\n\t\t{in: `new Uint16Array([0, 32768, 65535])`, expected: `Uint16Array(3) [ 0, 32768, 65535 ]`},\n\t\t{in: `new Int32Array([4, 2, -2147483648])`, expected: `Int32Array(3) [ 4, 2, -2147483648 ]`},\n\t\t{in: `new Uint32Array([0, 2147483648, 4294967295])`, expected: `Uint32Array(3) [ 0, 2147483648, 4294967295 ]`},\n\t\t{in: `new Float32Array([1.5, -2.5])`, expected: `Float32Array(2) [ 1.5, -2.5 ]`},\n\t\t{in: `new Float64Array([3.141592653589793, 2.718281828459045])`, expected: `Float64Array(2) [ 3.141592653589793, 2.718281828459045 ]`},\n\t\t{in: `new BigInt64Array([BigInt(1), BigInt(-1)])`, expected: `BigInt64Array(2) [ 1, -1 ]`},\n\t\t{in: `new BigUint64Array([BigInt(0), BigInt(1)])`, expected: `BigUint64Array(2) [ 0, 1 ]`},\n\n\t\t{in: `new Int8Array(0)`, expected: `Int8Array(0) []`},\n\t\t{in: `new Uint8Array(0)`, expected: `Uint8Array(0) []`},\n\t\t{in: `new Float64Array([])`, expected: `Float64Array(0) []`},\n\t\t{in: `new Int32Array([0])`, expected: `Int32Array(1) [ 0 ]`},\n\n\t\t{in: `new ArrayBuffer(0)`, expected: `ArrayBuffer { [Uint8Contents]: <>, byteLength: 0 }`},\n\t\t{in: `new ArrayBuffer(4)`, expected: `ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }`},\n\t\t{in: `new ArrayBuffer(8)`, expected: `ArrayBuffer { [Uint8Contents]: <00 00 00 00 00 00 00 00>, byteLength: 8 }`},\n\t\t{\n\t\t\tin: `function() {\n\t\t\t\tvar buf = new ArrayBuffer(8);\n\t\t\t\tvar view = new Int32Array(buf);\n\t\t\t\tview[0] = 4;\n\t\t\t\tview[1] = 2;\n\t\t\t\treturn buf;\n\t\t\t}()`,\n\t\t\texpected: `ArrayBuffer { [Uint8Contents]: <04 00 00 00 02 00 00 00>, byteLength: 8 }`,\n\t\t},\n\n\t\t{in: `{v: new Int32Array([4, 2])}`, expected: `{ v: Int32Array(2) [ 4, 2 ] }`},\n\t\t{in: `{b: new ArrayBuffer(4)}`, expected: `{ b: ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 } }`},\n\t\t{in: `{arr: new Int8Array([1, 2]), buf: new ArrayBuffer(2)}`, expected: `{ arr: Int8Array(2) [ 1, 2 ], buf: ArrayBuffer { [Uint8Contents]: <00 00>, byteLength: 2 } }`},\n\n\t\t{in: `[new Int8Array([1, 2])]`, expected: `[ Int8Array(2) [ 1, 2 ] ]`},\n\t\t{in: `[new ArrayBuffer(2), new ArrayBuffer(4)]`, expected: `[ ArrayBuffer { [Uint8Contents]: <00 00>, byteLength: 2 }, ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 } ]`},\n\n\t\t{in: `{count: 2, name: \"test\", data: new Int8Array([1, 2])}`, expected: `{ count: 2, name: \"test\", data: Int8Array(2) [ 1, 2 ] }`},\n\t\t{in: `{fn: function(){}, arr: new Uint8Array([255])}`, expected: `{ fn: [object Function], arr: Uint8Array(1) [ 255 ] }`},\n\t\t{in: `{buf: new ArrayBuffer(4), items: [1, 2, 3]}`, expected: `{ buf: ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }, items: [ 1, 2, 3 ] }`},\n\t\t{in: `{err: new Error(\"test\"), data: new Int8Array([1])}`, expected: `{ err: Error: test, data: Int8Array(1) [ 1 ] }`},\n\n\t\t{in: `{outer: {inner: new Int32Array([100])}}`, expected: `{ outer: { inner: Int32Array(1) [ 100 ] } }`},\n\t\t{in: `{a: {b: {c: new ArrayBuffer(2)}}}`, expected: `{ a: { b: { c: ArrayBuffer { [Uint8Contents]: <00 00>, byteLength: 2 } } } }`},\n\t\t{in: `{level1: {level2: {level3: {data: new Float32Array([1.5])}}}}`, expected: `{ level1: { level2: { level3: { data: Float32Array(1) [ 1.5 ] } } } }`},\n\n\t\t{in: `[1, new Int8Array([2]), \"three\"]`, expected: `[ 1, Int8Array(1) [ 2 ], \"three\" ]`},\n\t\t{in: `[new ArrayBuffer(2), null, new Int16Array([100])]`, expected: `[ ArrayBuffer { [Uint8Contents]: <00 00>, byteLength: 2 }, null, Int16Array(1) [ 100 ] ]`},\n\n\t\t{in: `{users: [{name: \"a\", scores: new Int32Array([10, 20])}]}`, expected: `{ users: [ { name: \"a\", scores: Int32Array(2) [ 10, 20 ] } ] }`},\n\t\t{in: `[[new Int8Array([1])], [new Int8Array([2])]]`, expected: `[ [ Int8Array(1) [ 1 ] ], [ Int8Array(1) [ 2 ] ] ]`},\n\t\t{in: `{matrix: [[new Int8Array([1, 2])], [new Int8Array([3, 4])]]}`, expected: `{ matrix: [ [ Int8Array(2) [ 1, 2 ] ], [ Int8Array(2) [ 3, 4 ] ] ] }`},\n\t\t{in: `{buffers: {a: new ArrayBuffer(2), b: new ArrayBuffer(4)}}`, expected: `{ buffers: { a: ArrayBuffer { [Uint8Contents]: <00 00>, byteLength: 2 }, b: ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 } } }`},\n\t\t{in: `[{arr: new Int8Array([1])}, {arr: new Int8Array([2])}]`, expected: `[ { arr: Int8Array(1) [ 1 ] }, { arr: Int8Array(1) [ 2 ] } ]`},\n\t\t{in: `{data: {nums: [1, 2], typed: new Float64Array([3.14])}}`, expected: `{ data: { nums: [ 1, 2 ], typed: Float64Array(1) [ 3.14 ] } }`},\n\t\t{in: `{config: {enabled: true, buffer: new ArrayBuffer(4), name: \"test\"}}`, expected: `{ config: { enabled: true, buffer: ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }, name: \"test\" } }`},\n\t\t{in: `{items: [{id: 1, data: new Uint8Array([255])}, {id: 2, data: new Uint8Array([128])}]}`, expected: `{ items: [ { id: 1, data: Uint8Array(1) [ 255 ] }, { id: 2, data: Uint8Array(1) [ 128 ] } ] }`},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.in, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr, err := getSimpleRunner(t, \"/script.js\", fmt.Sprintf(\n\t\t\t\t`exports.default = function() { console.log(%s); }`, tt.in))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tctx := t.Context()\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\tinitVU, err := r.newVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\n\t\t\tlogger := extractLogger(vu)\n\n\t\t\tlogger.Out = io.Discard\n\t\t\tlogger.Level = logrus.DebugLevel\n\t\t\thook := logtest.NewLocal(logger)\n\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tentry := hook.LastEntry()\n\n\t\t\trequire.NotNil(t, entry, \"nothing logged\")\n\t\t\tassert.Equal(t, tt.expected, entry.Message)\n\t\t\tassert.Equal(t, logrus.Fields{\"source\": \"console\"}, entry.Data)\n\t\t})\n\t}\n}\n\nfunc TestConsoleLogWithGoValues(t *testing.T) { //nolint:tparallel // actually faster with parallel and also we need the rt to create some of the testdata\n\tt.Parallel()\n\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\ttests := []struct {\n\t\tin       any\n\t\texpected string\n\t}{\n\t\t{in: \"string\", expected: \"string\"},\n\n\t\t{in: []any{}, expected: `[]`},\n\t\t{in: []string{\"a\", \"b\", \"c\"}, expected: `[ \"a\", \"b\", \"c\" ]`},\n\t\t{in: []int{1, 2, 3}, expected: `[ 1, 2, 3 ]`},\n\t\t{in: []any{\"hello\", 42, true, nil}, expected: `[ \"hello\", 42, true, null ]`},\n\t\t{in: []any{[]int{1, 2}, []string{\"a\", \"b\"}}, expected: `[ [ 1, 2 ], [ \"a\", \"b\" ] ]`},\n\n\t\t{in: map[string]any{}, expected: \"{}\"},\n\t\t{in: map[string]any{\"outer\": map[string]any{\"inner\": \"value\"}}, expected: `{ outer: { inner: \"value\" } }`},\n\n\t\t{in: struct {\n\t\t\tName string\n\t\t\tAge  int\n\t\t}{\"John\", 30}, expected: `{ name: \"John\", age: 30 }`},\n\n\t\t{in: errors.New(\"this is an error\"), expected: `this is an error`},\n\t\t{in: fmt.Errorf(\"this is a wrap of: %w\", errors.New(\"error\")), expected: `this is a wrap of: error`},\n\n\t\t{in: rt.NewGoError(errors.New(\"this is a go error\")), expected: `GoError: this is a go error`},\n\t\t{in: rt.NewTypeError(\"type error\"), expected: `TypeError: type error`},\n\t}\n\n\tfor _, tt := range tests { //nolint:paralleltest\n\t\tt.Run(fmt.Sprintf(\"%v\", tt.in), func(t *testing.T) {\n\t\t\tlogger, hook := testutils.NewLoggerWithHook(t)\n\t\t\tc := newConsole(logger)\n\n\t\t\t// Convert Go in to JavaScript in\n\t\t\tjsValue := rt.ToValue(tt.in)\n\n\t\t\t// Call console.log with the converted in\n\t\t\tc.Log(jsValue)\n\n\t\t\tentry := hook.LastEntry()\n\t\t\trequire.NotNil(t, entry, \"nothing logged\")\n\t\t\tassert.Equal(t, tt.expected, entry.Message)\n\t\t\tassert.Equal(t, logrus.Fields{\"source\": \"console\"}, entry.Data)\n\t\t})\n\t}\n}\n\nfunc TestConsoleLevels(t *testing.T) {\n\tt.Parallel()\n\tlevels := map[string]logrus.Level{\n\t\t\"log\":   logrus.InfoLevel,\n\t\t\"debug\": logrus.DebugLevel,\n\t\t\"info\":  logrus.InfoLevel,\n\t\t\"warn\":  logrus.WarnLevel,\n\t\t\"error\": logrus.ErrorLevel,\n\t}\n\targsets := []struct {\n\t\tin  string\n\t\texp string\n\t}{\n\t\t{in: `\"string\"`, exp: \"string\"},\n\t\t{in: `{}`, exp: \"{}\"},\n\t\t{in: `{foo:\"bar\"}`, exp: `{ foo: \"bar\" }`},\n\t}\n\tfor name, level := range levels {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor _, tt := range argsets {\n\t\t\t\targs, result := tt.in, tt.exp\n\t\t\t\tt.Run(args, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tr, err := getSimpleRunner(t, \"/script.js\", fmt.Sprintf(\n\t\t\t\t\t\t`exports.default = function() { console.%s(%s); }`,\n\t\t\t\t\t\tname, args,\n\t\t\t\t\t))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tctx := t.Context()\n\n\t\t\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\t\t\tinitVU, err := r.newVU(ctx, 1, 1, samples)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\n\t\t\t\t\tlogger := extractLogger(vu)\n\n\t\t\t\t\tlogger.Out = io.Discard\n\t\t\t\t\tlogger.Level = logrus.DebugLevel\n\t\t\t\t\thook := logtest.NewLocal(logger)\n\n\t\t\t\t\terr = vu.RunOnce()\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tentry := hook.LastEntry()\n\t\t\t\t\trequire.NotNil(t, entry, \"nothing logged\")\n\n\t\t\t\t\tassert.Equal(t, level, entry.Level)\n\t\t\t\t\tassert.Equal(t, result, entry.Message)\n\t\t\t\t\tassert.Equal(t, logrus.Fields{\"source\": \"console\"}, entry.Data)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestFileConsole(t *testing.T) {\n\tt.Parallel()\n\tvar (\n\t\tlevels = map[string]logrus.Level{\n\t\t\t\"log\":   logrus.InfoLevel,\n\t\t\t\"debug\": logrus.DebugLevel,\n\t\t\t\"info\":  logrus.InfoLevel,\n\t\t\t\"warn\":  logrus.WarnLevel,\n\t\t\t\"error\": logrus.ErrorLevel,\n\t\t}\n\t\targsets = map[string]struct {\n\t\t\tMessage string\n\t\t\tData    logrus.Fields\n\t\t}{\n\t\t\t`\"string\"`:           {Message: \"string\", Data: logrus.Fields{}},\n\t\t\t`\"string\", \"a\", \"b\"`: {Message: \"string a b\", Data: logrus.Fields{}},\n\t\t\t`\"string\", 1, 2`:     {Message: \"string 1 2\", Data: logrus.Fields{}},\n\t\t\t`{}`:                 {Message: \"{}\", Data: logrus.Fields{}},\n\t\t}\n\t\tpreExisting = map[string]bool{\n\t\t\t\"log exists\":        false,\n\t\t\t\"log doesn't exist\": true,\n\t\t}\n\t\tpreExistingText = \"Prexisting file\\n\"\n\t)\n\tfor name, level := range levels {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor args, result := range argsets {\n\t\t\t\tt.Run(args, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\t// whether the file is existed before logging\n\t\t\t\t\tfor msg, deleteFile := range preExisting {\n\t\t\t\t\t\tt.Run(msg, func(t *testing.T) {\n\t\t\t\t\t\t\tt.Parallel()\n\t\t\t\t\t\t\tf, err := os.CreateTemp(t.TempDir(), \"\") //nolint:forbidigo // fix with https://github.com/grafana/k6/issues/2565\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\tlogFilename := f.Name()\n\t\t\t\t\t\t\t// close it as we will want to reopen it and maybe remove it\n\t\t\t\t\t\t\tif deleteFile {\n\t\t\t\t\t\t\t\trequire.NoError(t, f.Close())\n\t\t\t\t\t\t\t\trequire.NoError(t, os.Remove(logFilename)) //nolint:forbidigo // fix with https://github.com/grafana/k6/issues/2565\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// TODO: handle case where the string was no written in full ?\n\t\t\t\t\t\t\t\t_, err = f.WriteString(preExistingText)\n\t\t\t\t\t\t\t\tassert.NoError(t, f.Close())\n\t\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tr, err := getSimpleRunner(t, \"/script\",\n\t\t\t\t\t\t\t\tfmt.Sprintf(\n\t\t\t\t\t\t\t\t\t`exports.default = function() { console.%s(%s); }`,\n\t\t\t\t\t\t\t\t\tname, args,\n\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\terr = r.SetOptions(lib.Options{\n\t\t\t\t\t\t\t\tConsoleOutput: null.StringFrom(logFilename),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\tctx := t.Context()\n\n\t\t\t\t\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\t\t\t\t\tinitVU, err := r.newVU(ctx, 1, 1, samples)\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\t\t\t\t\tlogger := extractLogger(vu)\n\t\t\t\t\t\t\tt.Cleanup(func() {\n\t\t\t\t\t\t\t\tif loggerOut, canBeClosed := logger.Out.(io.Closer); canBeClosed {\n\t\t\t\t\t\t\t\t\trequire.NoError(t, loggerOut.Close())\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t})\n\n\t\t\t\t\t\t\tlogger.Level = logrus.DebugLevel\n\t\t\t\t\t\t\thook := logtest.NewLocal(logger)\n\n\t\t\t\t\t\t\terr = vu.RunOnce()\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\t// Test if the file was created.\n\t\t\t\t\t\t\t_, err = os.Stat(logFilename) //nolint:forbidigo // fix with https://github.com/grafana/k6/issues/2565\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\tentry := hook.LastEntry()\n\t\t\t\t\t\t\trequire.NotNil(t, entry, \"nothing logged\")\n\t\t\t\t\t\t\tassert.Equal(t, level, entry.Level)\n\t\t\t\t\t\t\tassert.Equal(t, result.Message, entry.Message)\n\n\t\t\t\t\t\t\tdata := result.Data\n\t\t\t\t\t\t\tif data == nil {\n\t\t\t\t\t\t\t\tdata = make(logrus.Fields)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\trequire.Equal(t, data, entry.Data)\n\n\t\t\t\t\t\t\t// Test if what we logged to the hook is the same as what we logged\n\t\t\t\t\t\t\t// to the file.\n\t\t\t\t\t\t\tentryStr, err := entry.String()\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\tf, err = os.Open(logFilename) //nolint:forbidigo // fix with https://github.com/grafana/k6/issues/2565\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t\tfileContent, err := io.ReadAll(f)\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\trequire.NoError(t, f.Close())\n\n\t\t\t\t\t\t\texpectedStr := entryStr\n\t\t\t\t\t\t\tif !deleteFile {\n\t\t\t\t\t\t\t\texpectedStr = preExistingText + expectedStr\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\trequire.Equal(t, expectedStr, string(fileContent))\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/doc.go",
    "content": "// Package js is the JavaScript implementation of the lib.Runner and relative concepts for\n// executing concurrent-safe JavaScript code.\npackage js\n"
  },
  {
    "path": "internal/js/empty_iterations_bench_test.go",
    "content": "package js\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\nfunc BenchmarkEmptyIteration(b *testing.B) {\n\tb.StopTimer()\n\n\tr, err := getSimpleRunner(b, \"/script.js\", `exports.default = function() { }`)\n\trequire.NoError(b, err)\n\n\tch := newDevNullSampleChannel()\n\tdefer close(ch)\n\n\tinitVU, err := r.NewVU(context.Background(), 1, 1, ch)\n\trequire.NoError(b, err)\n\tctx := b.Context()\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\tb.StartTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\terr = vu.RunOnce()\n\t\trequire.NoError(b, err)\n\t}\n}\n"
  },
  {
    "path": "internal/js/esm_vs_commonjs_test.go",
    "content": "package js\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\n// The file is mostly around test that have different behaviour in ESM and commonJS\n\nfunc TestReturnInCommonJSModule(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\tif (false) {\n\t\treturn // this works as this gets wrapped in a function\n\t}\n\texports.default = () => {}\n\t`\n\t_, err := getSimpleRunner(t, \"/script.js\", script)\n\trequire.NoError(t, err)\n}\n\nfunc TestReturnInESMModule(t *testing.T) {\n\tt.Parallel()\n\tscript := `\n\tif (false) {\n\t\treturn // this is syntax error\n\t}\n\texport default = () => {}\n\t`\n\t_, err := getSimpleRunner(t, \"/script.js\", script)\n\trequire.ErrorContains(t, err, \"Illegal return statement\")\n}\n"
  },
  {
    "path": "internal/js/eventloop/eventloop.go",
    "content": "// Package eventloop implements an event loop to be used thought js and it's subpackages\npackage eventloop\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// EventLoop implements an event with\n// handling of unhandled rejected promises.\n//\n// A specific thing about this event loop is that it will wait to return\n// not only until the queue is empty but until nothing is registered that it will run in the future.\n// This is in contrast with more common behaviours where it only returns on\n// a specific event/action or when the loop is empty.\n// This is required as in k6 iterations (for which event loop will be primary used)\n// are supposed to be independent and any work started in them needs to finish,\n// but also they need to end when all the instructions are done.\n// Additionally because of this on any error while the event loop will exit it's\n// required to wait on the event loop to be empty before the execution can continue.\ntype EventLoop struct {\n\tlock                sync.Mutex\n\tqueue               []func() error\n\twakeupCh            chan struct{} // TODO: maybe use sync.Cond ?\n\tregisteredCallbacks int\n\tvu                  modules.VU\n\n\t// pendingPromiseRejections are rejected promises with no handler,\n\t// if there is something in this map at an end of an event loop then it will exit with an error.\n\t// It's similar to what Deno and Node do.\n\tpendingPromiseRejections map[*sobek.Promise]struct{}\n}\n\n// New returns a new event loop with a few helpers attached to it:\n// - adding setTimeout javascript implementation\n// - reporting (and aborting on) unhandled promise rejections\nfunc New(vu modules.VU) *EventLoop {\n\te := &EventLoop{\n\t\twakeupCh:                 make(chan struct{}, 1),\n\t\tpendingPromiseRejections: make(map[*sobek.Promise]struct{}),\n\t\tvu:                       vu,\n\t}\n\tvu.Runtime().SetPromiseRejectionTracker(e.promiseRejectionTracker)\n\n\treturn e\n}\n\nfunc (e *EventLoop) wakeup() {\n\tselect {\n\tcase e.wakeupCh <- struct{}{}:\n\tdefault:\n\t}\n}\n\n// RegisterCallback signals to the event loop that you are going to do some\n// asynchronous work off the main thread and that you may need to execute some\n// code back on the main thread when you are done. So, once you call this\n// method, the event loop will wait for you to finish and give it the callback\n// it needs to run back on the main thread before it can end the whole current\n// script iteration.\n//\n// RegisterCallback() *must* be called from the main runtime thread, but its\n// result enqueueCallback() is thread-safe and can be called from any goroutine.\n// enqueueCallback() ensures that its callback parameter is added to the VU\n// runtime's tasks queue, to be executed on the main runtime thread eventually,\n// when the VU is done with the other tasks before it. Unless the whole event\n// loop has been stopped, invoking enqueueCallback() will queue its argument and\n// \"wake up\" the loop (if it was idle, but not stopped).\n//\n// Keep in mind that once you call RegisterCallback(), you *must* also call\n// enqueueCallback() exactly once, even if don't actually need to run any code\n// on the main thread. If that's the case, you can pass an empty no-op callback\n// to it, but you must call it! The event loop will wait for the\n// enqueueCallback() invocation and the k6 iteration won't finish and will be\n// stuck until the VU itself has been stopped (e.g. because the whole test or\n// scenario has ended). Any error returned by any callback on the main thread\n// will abort the current iteration and no further event loop callbacks will be\n// executed in the same iteration.\n//\n// A common pattern for async work is something like this:\n//\n//\tfunc doAsyncWork(vu modules.VU) *sobek.Promise {\n//\t    enqueueCallback := vu.RegisterCallback()\n//\t    p, resolve, reject := vu.Runtime().NewPromise()\n//\n//\t    // Do the actual async work in a new independent goroutine, but make\n//\t    // sure that the Promise resolution is done on the main thread:\n//\t    go func() {\n//\t        // Also make sure to abort early if the context is cancelled, so\n//\t        // the VU is not stuck when the scenario ends or Ctrl+C is used:\n//\t        result, err := doTheActualAsyncWork(vu.Context())\n//\t        enqueueCallback(func() error {\n//\t            if err != nil {\n//\t                reject(err)\n//\t            } else {\n//\t                resolve(result)\n//\t            }\n//\t            return nil  // do not abort the iteration\n//\t        })\n//\t    }()\n//\n//\t    return p\n//\t}\n//\n// This ensures that the actual work happens asynchronously, while the Promise\n// is immediately returned and the main thread resumes execution. It also\n// ensures that the Promise resolution happens safely back on the main thread\n// once the async work is done, as required by Sobek and all other JS runtimes.\n//\n// TODO: rename to ReservePendingCallback or something more appropriate?\nfunc (e *EventLoop) RegisterCallback() (enqueueCallback func(func() error)) {\n\te.lock.Lock()\n\tvar callbackCalled bool\n\te.registeredCallbacks++\n\te.lock.Unlock()\n\n\treturn func(f func() error) {\n\t\te.lock.Lock()\n\t\tif callbackCalled { // this is protected by the lock on the event loop\n\t\t\te.lock.Unlock() // let not lock up the whole event loop, somebody could recover from the panic\n\t\t\tpanic(\"RegisterCallback called twice\")\n\t\t}\n\t\tcallbackCalled = true\n\t\te.queue = append(e.queue, f)\n\t\te.registeredCallbacks--\n\t\te.lock.Unlock()\n\t\te.wakeup()\n\t}\n}\n\nfunc (e *EventLoop) promiseRejectionTracker(p *sobek.Promise, op sobek.PromiseRejectionOperation) {\n\t// No locking necessary here as the Sobek runtime will call this synchronously\n\t// Read Notes on https://tc39.es/ecma262/#sec-host-promise-rejection-tracker\n\tif op == sobek.PromiseRejectionReject {\n\t\te.pendingPromiseRejections[p] = struct{}{}\n\t} else { // sobek.PromiseRejectionHandle so a promise that was previously rejected without handler now got one\n\t\tdelete(e.pendingPromiseRejections, p)\n\t}\n}\n\nfunc (e *EventLoop) popAll() (queue []func() error, awaiting bool) {\n\te.lock.Lock()\n\tqueue = e.queue\n\te.queue = make([]func() error, 0, len(queue))\n\tawaiting = e.registeredCallbacks != 0\n\te.lock.Unlock()\n\treturn queue, awaiting\n}\n\nfunc (e *EventLoop) putInfront(queue []func() error) {\n\te.lock.Lock()\n\te.queue = append(queue, e.queue...)\n\te.lock.Unlock()\n}\n\n// Start will run the event loop until it's empty and there are no uninvoked registered callbacks\n// or a queued function returns an error. The provided firstCallback will be the first thing executed.\n// After Start returns the event loop can be reused as long as waitOnRegistered is called.\nfunc (e *EventLoop) Start(firstCallback func() error) error {\n\te.pendingPromiseRejections = make(map[*sobek.Promise]struct{})\n\te.queue = []func() error{firstCallback}\n\tfor {\n\t\tqueue, awaiting := e.popAll()\n\n\t\tif len(queue) == 0 {\n\t\t\tif !awaiting {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\t<-e.wakeupCh\n\t\t\tcontinue\n\t\t}\n\n\t\tfor i, f := range queue {\n\t\t\tif err := f(); err != nil {\n\t\t\t\te.putInfront(queue[i+1:])\n\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// This will get a random unhandled rejection instead of the first one, for example.\n\t\t// But that seems to be the case in other tools as well so it seems to not be that big of a problem.\n\t\tfor promise := range e.pendingPromiseRejections {\n\t\t\tvalue := promise.Result()\n\t\t\tif !common.IsNullish(value) {\n\t\t\t\tif o := value.ToObject(e.vu.Runtime()); o != nil {\n\t\t\t\t\tif stack := o.Get(\"stack\"); stack != nil {\n\t\t\t\t\t\tvalue = stack\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// this is the de facto wording in both firefox and deno at least\n\t\t\treturn fmt.Errorf(\"Uncaught (in promise) %s\", value) //nolint:staticcheck\n\t\t}\n\t}\n}\n\n// WaitOnRegistered waits on all registered callbacks so we know nothing is still doing work.\n// This does call back the callbacks and more can be queued over time.\n// A different mechanism needs to be used to tell the users that the event loop has errored out or winding down for a\n// different reason.\nfunc (e *EventLoop) WaitOnRegistered() {\n\tfor {\n\t\tqueue, awaiting := e.popAll()\n\t\tif len(queue) == 0 {\n\t\t\tif !awaiting {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t<-e.wakeupCh\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, f := range queue {\n\t\t\tif err := f(); err != nil {\n\t\t\t\t// TODO figure out if we should buffer all errors happening or send them on a channel\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/js/eventloop/eventloop_test.go",
    "content": "package eventloop_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/js/eventloop\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nfunc TestBasicEventLoop(t *testing.T) {\n\tt.Parallel()\n\tloop := eventloop.New(&modulestest.VU{RuntimeField: sobek.New()})\n\tvar ran int\n\tf := func() error { //nolint:unparam\n\t\tran++\n\t\treturn nil\n\t}\n\trequire.NoError(t, loop.Start(f))\n\trequire.Equal(t, 1, ran)\n\trequire.NoError(t, loop.Start(f))\n\trequire.Equal(t, 2, ran)\n\trequire.Error(t, loop.Start(func() error {\n\t\t_ = f()\n\t\tloop.RegisterCallback()(f)\n\t\treturn errors.New(\"something\")\n\t}))\n\trequire.Equal(t, 3, ran)\n}\n\nfunc TestEventLoopRegistered(t *testing.T) {\n\tt.Parallel()\n\tloop := eventloop.New(&modulestest.VU{RuntimeField: sobek.New()})\n\tvar ran int\n\tf := func() error {\n\t\tran++\n\t\tr := loop.RegisterCallback()\n\t\tgo func() {\n\t\t\ttime.Sleep(time.Second)\n\t\t\tr(func() error {\n\t\t\t\tran++\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}()\n\t\treturn nil\n\t}\n\tstart := time.Now()\n\trequire.NoError(t, loop.Start(f))\n\ttook := time.Since(start)\n\trequire.Equal(t, 2, ran)\n\trequire.Less(t, time.Second, took)\n\trequire.Greater(t, time.Second+time.Millisecond*100, took)\n}\n\nfunc TestEventLoopWaitOnRegistered(t *testing.T) {\n\tt.Parallel()\n\tvar ran int\n\tloop := eventloop.New(&modulestest.VU{RuntimeField: sobek.New()})\n\tf := func() error {\n\t\tran++\n\t\tr := loop.RegisterCallback()\n\t\tgo func() {\n\t\t\ttime.Sleep(time.Second)\n\t\t\tr(func() error {\n\t\t\t\tran++\n\t\t\t\treturn nil\n\t\t\t})\n\t\t}()\n\t\treturn fmt.Errorf(\"expected\")\n\t}\n\tstart := time.Now()\n\trequire.Error(t, loop.Start(f))\n\ttook := time.Since(start)\n\tloop.WaitOnRegistered()\n\ttook2 := time.Since(start)\n\trequire.Equal(t, 2, ran)\n\trequire.Greater(t, time.Millisecond*50, took)\n\trequire.Less(t, time.Second, took2)\n\trequire.Greater(t, time.Second+time.Millisecond*100, took2)\n}\n\nfunc TestEventLoopAllCallbacksGetCalled(t *testing.T) {\n\tt.Parallel()\n\tsleepTime := time.Millisecond * 500\n\tloop := eventloop.New(&modulestest.VU{RuntimeField: sobek.New()})\n\tvar called int64\n\tf := func() error {\n\t\tfor i := range 100 {\n\t\t\tbad := i == 99\n\t\t\tr := loop.RegisterCallback()\n\n\t\t\tgo func() {\n\t\t\t\tif !bad {\n\t\t\t\t\ttime.Sleep(sleepTime)\n\t\t\t\t}\n\t\t\t\tr(func() error {\n\t\t\t\t\tif bad {\n\t\t\t\t\t\treturn errors.New(\"something\")\n\t\t\t\t\t}\n\t\t\t\t\tatomic.AddInt64(&called, 1)\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\t\t\t}()\n\t\t}\n\t\treturn fmt.Errorf(\"expected\")\n\t}\n\tfor range 3 {\n\t\tcalled = 0\n\t\tstart := time.Now()\n\t\trequire.Error(t, loop.Start(f))\n\t\ttook := time.Since(start)\n\t\tloop.WaitOnRegistered()\n\t\ttook2 := time.Since(start)\n\t\trequire.Greater(t, time.Millisecond*50, took)\n\t\trequire.Less(t, sleepTime, took2)\n\t\trequire.Greater(t, sleepTime+time.Millisecond*100, took2)\n\t\trequire.EqualValues(t, 99, called)\n\t}\n}\n\nfunc TestEventLoopPanicOnDoubleCallback(t *testing.T) {\n\tt.Parallel()\n\tloop := eventloop.New(&modulestest.VU{RuntimeField: sobek.New()})\n\tvar ran int\n\tf := func() error {\n\t\tran++\n\t\tr := loop.RegisterCallback()\n\t\tgo func() {\n\t\t\ttime.Sleep(time.Second)\n\t\t\tr(func() error {\n\t\t\t\tran++\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\trequire.Panics(t, func() { r(func() error { return nil }) })\n\t\t}()\n\t\treturn nil\n\t}\n\tstart := time.Now()\n\trequire.NoError(t, loop.Start(f))\n\ttook := time.Since(start)\n\trequire.Equal(t, 2, ran)\n\trequire.Less(t, time.Second, took)\n\trequire.Greater(t, time.Second+time.Millisecond*100, took)\n}\n\nfunc TestEventLoopRejectUndefined(t *testing.T) {\n\tt.Parallel()\n\tvu := &modulestest.VU{RuntimeField: sobek.New()}\n\tloop := eventloop.New(vu)\n\terr := loop.Start(func() error {\n\t\t_, err := vu.Runtime().RunString(\"Promise.reject()\")\n\t\treturn err\n\t})\n\tloop.WaitOnRegistered()\n\trequire.EqualError(t, err, \"Uncaught (in promise) undefined\")\n}\n\nfunc TestEventLoopRejectString(t *testing.T) {\n\tt.Parallel()\n\tvu := &modulestest.VU{RuntimeField: sobek.New()}\n\tloop := eventloop.New(vu)\n\terr := loop.Start(func() error {\n\t\t_, err := vu.Runtime().RunString(\"Promise.reject('some string')\")\n\t\treturn err\n\t})\n\tloop.WaitOnRegistered()\n\trequire.EqualError(t, err, \"Uncaught (in promise) some string\")\n}\n\nfunc TestEventLoopRejectSyntaxError(t *testing.T) {\n\tt.Parallel()\n\tvu := &modulestest.VU{RuntimeField: sobek.New()}\n\tloop := eventloop.New(vu)\n\terr := loop.Start(func() error {\n\t\t_, err := vu.Runtime().RunString(\"Promise.resolve().then(()=> {some.syntax.error})\")\n\t\treturn err\n\t})\n\tloop.WaitOnRegistered()\n\trequire.EqualError(t, err, \"Uncaught (in promise) ReferenceError: some is not defined\\n\\tat <eval>:1:30(1)\\n\")\n}\n\nfunc TestEventLoopRejectGoError(t *testing.T) {\n\tt.Parallel()\n\tvu := &modulestest.VU{RuntimeField: sobek.New()}\n\tloop := eventloop.New(vu)\n\trt := vu.Runtime()\n\trequire.NoError(t, rt.Set(\"f\", rt.ToValue(func() error {\n\t\treturn errors.New(\"some error\")\n\t})))\n\terr := loop.Start(func() error {\n\t\t_, err := vu.Runtime().RunString(\"Promise.resolve().then(()=> {f()})\")\n\t\treturn err\n\t})\n\tloop.WaitOnRegistered()\n\trequire.EqualError(t, err, \"Uncaught (in promise) GoError: some error\\n\\tat go.k6.io/k6/internal/js/eventloop_test.TestEventLoopRejectGoError.func1 (native)\\n\\tat <eval>:1:31(2)\\n\")\n}\n\nfunc TestEventLoopRejectThrow(t *testing.T) {\n\tt.Parallel()\n\tvu := &modulestest.VU{RuntimeField: sobek.New()}\n\tloop := eventloop.New(vu)\n\trt := vu.Runtime()\n\trequire.NoError(t, rt.Set(\"f\", rt.ToValue(func() error {\n\t\tcommon.Throw(rt, errors.New(\"throw error\"))\n\t\treturn nil\n\t})))\n\terr := loop.Start(func() error {\n\t\t_, err := vu.Runtime().RunString(\"Promise.resolve().then(()=> {f()})\")\n\t\treturn err\n\t})\n\tloop.WaitOnRegistered()\n\trequire.EqualError(t, err, \"Uncaught (in promise) GoError: throw error\\n\\tat go.k6.io/k6/internal/js/eventloop_test.TestEventLoopRejectThrow.func1 (native)\\n\\tat <eval>:1:31(2)\\n\")\n}\n\nfunc TestEventLoopAsyncAwait(t *testing.T) {\n\tt.Parallel()\n\tvu := &modulestest.VU{RuntimeField: sobek.New()}\n\tloop := eventloop.New(vu)\n\terr := loop.Start(func() error {\n\t\t_, err := vu.Runtime().RunString(`\n        async function a() {\n            some.error.here\n        }\n        Promise.resolve().then(async () => {\n            await a();\n        })\n        `)\n\t\treturn err\n\t})\n\tloop.WaitOnRegistered()\n\trequire.EqualError(t, err, \"Uncaught (in promise) ReferenceError: some is not defined\\n\\tat a (<eval>:3:13(1))\\n\\tat <eval>:6:20(2)\\n\")\n}\n"
  },
  {
    "path": "internal/js/http_bench_test.go",
    "content": "package js\n\nimport (\n\t\"testing\"\n\n\t\"go.k6.io/k6/lib/types\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc BenchmarkHTTPRequests(b *testing.B) {\n\tb.StopTimer()\n\ttb := httpmultibin.NewHTTPMultiBin(b)\n\n\tr, err := getSimpleRunner(b, \"/script.js\", tb.Replacer.Replace(`\n\t\t\timport http from \"k6/http\";\n\t\t\texport default function() {\n\t\t\t\tlet url = \"HTTPBIN_URL\";\n\t\t\t\tlet res = http.get(url + \"/cookies/set?k2=v2&k1=v1\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\t}\n\t\t`), lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(b, err)\n\n\terr = r.SetOptions(lib.Options{\n\t\tThrow:          null.BoolFrom(true),\n\t\tMaxRedirects:   null.IntFrom(10),\n\t\tHosts:          types.NullHosts{Trie: tb.Dialer.Hosts},\n\t\tNoCookiesReset: null.BoolFrom(true),\n\t\tSystemTags:     &metrics.DefaultSystemTagSet,\n\t\tRunTags:        map[string]string{\"myapp\": \"myhttpbench\"},\n\t})\n\trequire.NoError(b, err)\n\n\tch := newDevNullSampleChannel()\n\tdefer close(ch)\n\tctx := b.Context()\n\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\trequire.NoError(b, err)\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\tb.StartTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tassert.NoError(b, vu.RunOnce())\n\t}\n}\n\nfunc BenchmarkHTTPRequestsBase(b *testing.B) {\n\tb.StopTimer()\n\ttb := httpmultibin.NewHTTPMultiBin(b)\n\n\tr, err := getSimpleRunner(b, \"/script.js\", tb.Replacer.Replace(`\n\t\t\tvar http = require(\"k6/http\");\n\t\t\texports.default = function() {\n\t\t\t\tvar url = \"HTTPBIN_URL\";\n\t\t\t\tvar res = http.get(url + \"/cookies/set?k2=v2&k1=v1\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\t}\n\t\t`))\n\trequire.NoError(b, err)\n\terr = r.SetOptions(lib.Options{\n\t\tThrow:          null.BoolFrom(true),\n\t\tMaxRedirects:   null.IntFrom(10),\n\t\tHosts:          types.NullHosts{Trie: tb.Dialer.Hosts},\n\t\tNoCookiesReset: null.BoolFrom(true),\n\t})\n\trequire.NoError(b, err)\n\n\tch := newDevNullSampleChannel()\n\tdefer close(ch)\n\tctx := b.Context()\n\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\trequire.NoError(b, err)\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\tb.StartTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tassert.NoError(b, vu.RunOnce())\n\t}\n}\n"
  },
  {
    "path": "internal/js/init_and_modules_test.go",
    "content": "package js_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/js\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype CheckModule struct {\n\tt             testing.TB\n\tinitCtxCalled int\n\tvuCtxCalled   int\n}\n\nfunc (cm *CheckModule) InitCtx(_ context.Context) {\n\tcm.initCtxCalled++\n}\n\nfunc (cm *CheckModule) VuCtx(_ context.Context) {\n\tcm.vuCtxCalled++\n}\n\nvar uniqueModuleNumber int64 //nolint:gochecknoglobals // we need this so multiple test can register differently named modules\n\nfunc TestNewJSRunnerWithCustomModule(t *testing.T) {\n\tt.Parallel()\n\n\tcheckModule := &CheckModule{t: t}\n\tmoduleName := fmt.Sprintf(\"k6/x/check-%d\", atomic.AddInt64(&uniqueModuleNumber, 1))\n\tmodules.Register(moduleName, checkModule)\n\n\tscript := fmt.Sprintf(`\n\t\tvar check = require(\"%s\");\n\t\tcheck.initCtx();\n\n\t\tmodule.exports.options = { vus: 1, iterations: 1 };\n\t\tmodule.exports.default = function() {\n\t\t\tcheck.vuCtx();\n\t\t};\n\t`, moduleName)\n\n\tlogger := testutils.NewLogger(t)\n\trtOptions := lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"base\")}\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tpreInitState := &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tRegistry:       registry,\n\t\tRuntimeOptions: rtOptions,\n\t\tUsage:          usage.New(),\n\t}\n\tmoduleResolver := js.NewModuleResolver(&url.URL{}, preInitState, nil)\n\trunner, err := js.New(\n\t\tpreInitState,\n\t\t&loader.SourceData{\n\t\t\tURL:  &url.URL{Path: \"blah\", Scheme: \"file\"},\n\t\t\tData: []byte(script),\n\t\t},\n\t\tmap[string]fsext.Fs{\"file\": fsext.NewMemMapFs(), \"https\": fsext.NewMemMapFs()},\n\t\tmoduleResolver,\n\t)\n\trequire.NoError(t, err)\n\tassert.Equal(t, 1, checkModule.initCtxCalled)\n\tassert.Equal(t, 0, checkModule.vuCtxCalled)\n\n\tvu, err := runner.NewVU(context.Background(), 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n\tassert.Equal(t, 2, checkModule.initCtxCalled)\n\tassert.Equal(t, 0, checkModule.vuCtxCalled)\n\n\tvuCtx, vuCancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer vuCancel()\n\n\tactiveVU := vu.Activate(&lib.VUActivationParams{RunContext: vuCtx})\n\trequire.NoError(t, activeVU.RunOnce())\n\tassert.Equal(t, 2, checkModule.initCtxCalled)\n\tassert.Equal(t, 1, checkModule.vuCtxCalled)\n\trequire.NoError(t, activeVU.RunOnce())\n\tassert.Equal(t, 2, checkModule.initCtxCalled)\n\tassert.Equal(t, 2, checkModule.vuCtxCalled)\n\n\tarc := runner.MakeArchive()\n\tassert.Equal(t, 2, checkModule.initCtxCalled) // shouldn't change, we're not executing the init context again\n\tassert.Equal(t, 2, checkModule.vuCtxCalled)\n\n\trunnerFromArc, err := js.NewFromArchive(\n\t\t&lib.TestPreInitState{\n\t\t\tLogger:         logger,\n\t\t\tBuiltinMetrics: builtinMetrics,\n\t\t\tRegistry:       registry,\n\t\t\tRuntimeOptions: rtOptions,\n\t\t\tUsage:          usage.New(),\n\t\t}, arc,\n\t\tmoduleResolver) // fix\n\trequire.NoError(t, err)\n\tassert.Equal(t, 3, checkModule.initCtxCalled) // changes because we need to get the exported functions\n\tassert.Equal(t, 2, checkModule.vuCtxCalled)\n\tvuFromArc, err := runnerFromArc.NewVU(context.Background(), 2, 2, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n\tassert.Equal(t, 4, checkModule.initCtxCalled)\n\tassert.Equal(t, 2, checkModule.vuCtxCalled)\n\tactiveVUFromArc := vuFromArc.Activate(&lib.VUActivationParams{RunContext: vuCtx})\n\trequire.NoError(t, activeVUFromArc.RunOnce())\n\tassert.Equal(t, 4, checkModule.initCtxCalled)\n\tassert.Equal(t, 3, checkModule.vuCtxCalled)\n\trequire.NoError(t, activeVUFromArc.RunOnce())\n\tassert.Equal(t, 4, checkModule.initCtxCalled)\n\tassert.Equal(t, 4, checkModule.vuCtxCalled)\n}\n"
  },
  {
    "path": "internal/js/initcontext.go",
    "content": "package js\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nconst cantBeUsedOutsideInitContextMsg = `the \"%s\" function is only available in the init stage ` +\n\t`(i.e. the global scope), see https://grafana.com/docs/k6/latest/using-k6/test-lifecycle/ for more information`\n\n// openImpl implements openImpl() in the init context and will read and return the\n// contents of a file. If the second argument is \"b\" it returns an ArrayBuffer\n// instance, otherwise a string representation.\nfunc openImpl(rt *sobek.Runtime, fs fsext.Fs, basePWD *url.URL, filename string, args ...string) (sobek.Value, error) {\n\t// Strip file scheme if available as we should support only this scheme\n\tfilename = strings.TrimPrefix(filename, \"file://\")\n\tdata, err := readFile(fs, fsext.Abs(basePWD.Path, filename))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(args) > 0 && args[0] == \"b\" {\n\t\tab := rt.NewArrayBuffer(data)\n\t\treturn rt.ToValue(&ab), nil\n\t}\n\treturn rt.ToValue(string(data)), nil\n}\n\nfunc readFile(fileSystem fsext.Fs, filename string) (data []byte, err error) {\n\tdefer func() {\n\t\tif errors.Is(err, fsext.ErrPathNeverRequestedBefore) {\n\t\t\t// loading different files per VU is not supported, so all files should are going\n\t\t\t// to be used inside the scenario should be opened during the init step (without any conditions)\n\t\t\terr = fmt.Errorf(\n\t\t\t\t\"open() can't be used with files that weren't previously opened during initialization (__VU==0), path: %q\",\n\t\t\t\tfilename,\n\t\t\t)\n\t\t}\n\t}()\n\n\t// Workaround for https://github.com/spf13/fsext/issues/201\n\tif isDir, err := fsext.IsDir(fileSystem, filename); err != nil {\n\t\treturn nil, err\n\t} else if isDir {\n\t\treturn nil, fmt.Errorf(\"open() can't be used with directories, path: %q\", filename)\n\t}\n\n\treturn fsext.ReadFile(fileSystem, filename)\n}\n\n// allowOnlyOpenedFiles enables seen only files\nfunc allowOnlyOpenedFiles(fs fsext.Fs) {\n\talreadyOpenedFS, ok := fs.(fsext.OnlyCachedEnabler)\n\tif !ok {\n\t\treturn\n\t}\n\n\talreadyOpenedFS.AllowOnlyCached()\n}\n\nfunc generateSourceMapLoader(logger logrus.FieldLogger, filesystems map[string]fsext.Fs,\n) func(path string) ([]byte, error) {\n\treturn func(path string) ([]byte, error) {\n\t\tu, err := url.Parse(path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdata, err := loader.Load(logger, filesystems, u, path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn data.Data, nil\n\t}\n}\n"
  },
  {
    "path": "internal/js/initcontext_test.go",
    "content": "package js\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/consts\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestRequire(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Modules\", func(t *testing.T) {\n\t\tt.Run(\"Nonexistent\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\", `import \"k6/NONEXISTENT\";`)\n\t\t\trequire.ErrorContains(t, err, \"GoError: unknown modules [\\\"k6/NONEXISTENT\\\"]\")\n\t\t})\n\n\t\tt.Run(\"k6\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\timport k6 from \"k6\";\n\t\t\t\t\texport let _k6 = k6;\n\t\t\t\t\texport let dummy = \"abc123\";\n\t\t\t\t\texport default function() {}\n\t\t\t`)\n\t\t\trequire.NoError(t, err, \"bundle error\")\n\n\t\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\t\tassert.NoError(t, err, \"instance error\")\n\n\t\t\t_, defaultOk := sobek.AssertFunction(bi.getExported(\"default\"))\n\t\t\tassert.True(t, defaultOk, \"default export is not a function\")\n\t\t\tassert.Equal(t, \"abc123\", bi.getExported(\"dummy\").String())\n\n\t\t\tk6 := bi.getExported(\"_k6\").ToObject(bi.Runtime)\n\t\t\trequire.NotNil(t, k6)\n\t\t\t_, groupOk := sobek.AssertFunction(k6.Get(\"group\"))\n\t\t\tassert.True(t, groupOk, \"k6.group is not a function\")\n\t\t})\n\n\t\tt.Run(\"group\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\t\t\t\t\timport { group } from \"k6\";\n\t\t\t\t\t\texport let _group = group;\n\t\t\t\t\t\texport let dummy = \"abc123\";\n\t\t\t\t\t\texport default function() {}\n\t\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, defaultOk := sobek.AssertFunction(bi.getExported(\"default\"))\n\t\t\tassert.True(t, defaultOk, \"default export is not a function\")\n\t\t\tassert.Equal(t, \"abc123\", bi.getExported(\"dummy\").String())\n\n\t\t\t_, groupOk := sobek.AssertFunction(bi.getExported(\"_group\"))\n\t\t\tassert.True(t, groupOk, \"{ group } is not a function\")\n\t\t})\n\t})\n\n\tt.Run(\"Files\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"Nonexistent\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpath := filepath.FromSlash(\"/nonexistent.js\")\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\", `import \"/nonexistent.js\"; export default function() {}`)\n\t\t\trequire.NotNil(t, err)\n\t\t\tassert.Contains(t, err.Error(), fmt.Sprintf(`\"%s\" couldn't be found on local disk`, filepath.ToSlash(path)))\n\t\t})\n\t\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\trequire.NoError(t, fsext.WriteFile(fs, \"/file.js\", []byte{0x00}, 0o755))\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\", `import \"/file.js\"; export default function() {}`, fs)\n\t\t\tassert.ErrorContains(t, err, \"file:///file.js: Line 1:1 Unexpected token ILLEGAL (and 1 more errors)\")\n\t\t})\n\t\tt.Run(\"Error\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\trequire.NoError(t, fsext.WriteFile(fs, \"/file.js\", []byte(`throw new Error(\"aaaa\")`), 0o755))\n\t\t\t_, err := getSimpleBundle(t, \"/script.js\", `import \"/file.js\"; export default function() {}`, fs)\n\t\t\tassert.EqualError(t, err,\n\t\t\t\t\"Error: aaaa\\n\\tat file:///file.js:1:34(3)\\n\")\n\t\t})\n\n\t\timports := map[string]struct {\n\t\t\tLibPath    string\n\t\t\tConstPaths map[string]string\n\t\t}{\n\t\t\t\"./lib.js\": {\"/path/to/lib.js\", map[string]string{\n\t\t\t\t\"\":               \"\",\n\t\t\t\t\"./const.js\":     \"/path/to/const.js\",\n\t\t\t\t\"../const.js\":    \"/path/const.js\",\n\t\t\t\t\"./sub/const.js\": \"/path/to/sub/const.js\",\n\t\t\t}},\n\t\t\t\"../lib.js\": {\"/path/lib.js\", map[string]string{\n\t\t\t\t\"\":               \"\",\n\t\t\t\t\"./const.js\":     \"/path/const.js\",\n\t\t\t\t\"../const.js\":    \"/const.js\",\n\t\t\t\t\"./sub/const.js\": \"/path/sub/const.js\",\n\t\t\t}},\n\t\t\t\"./dir/lib.js\": {\"/path/to/dir/lib.js\", map[string]string{\n\t\t\t\t\"\":               \"\",\n\t\t\t\t\"./const.js\":     \"/path/to/dir/const.js\",\n\t\t\t\t\"../const.js\":    \"/path/to/const.js\",\n\t\t\t\t\"./sub/const.js\": \"/path/to/dir/sub/const.js\",\n\t\t\t}},\n\t\t\t\"/path/to/lib.js\": {\"/path/to/lib.js\", map[string]string{\n\t\t\t\t\"\":               \"\",\n\t\t\t\t\"./const.js\":     \"/path/to/const.js\",\n\t\t\t\t\"../const.js\":    \"/path/const.js\",\n\t\t\t\t\"./sub/const.js\": \"/path/to/sub/const.js\",\n\t\t\t}},\n\t\t}\n\t\tfor libName, data := range imports {\n\t\t\tt.Run(\"lib=\\\"\"+libName+\"\\\"\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tfor constName, constPath := range data.ConstPaths {\n\t\t\t\t\tname := \"inline\"\n\t\t\t\t\tif constName != \"\" {\n\t\t\t\t\t\tname = \"const=\\\"\" + constName + \"\\\"\"\n\t\t\t\t\t}\n\t\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\t\tt.Parallel()\n\t\t\t\t\t\tfs := fsext.NewMemMapFs()\n\n\t\t\t\t\t\tjsLib := `export default function() { return 12345; }`\n\t\t\t\t\t\tif constName != \"\" {\n\t\t\t\t\t\t\tjsLib = fmt.Sprintf(\n\t\t\t\t\t\t\t\t`import { c } from \"%s\"; export default function() { return c; }`,\n\t\t\t\t\t\t\t\tconstName,\n\t\t\t\t\t\t\t)\n\n\t\t\t\t\t\t\tconstsrc := `export let c = 12345;`\n\t\t\t\t\t\t\trequire.NoError(t, fs.MkdirAll(filepath.Dir(constPath), 0o755))\n\t\t\t\t\t\t\trequire.NoError(t, fsext.WriteFile(fs, constPath, []byte(constsrc), 0o644))\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trequire.NoError(t, fs.MkdirAll(filepath.Dir(data.LibPath), 0o755))\n\t\t\t\t\t\trequire.NoError(t, fsext.WriteFile(fs, data.LibPath, []byte(jsLib), 0o644))\n\n\t\t\t\t\t\tdata := fmt.Sprintf(`\n\t\t\t\t\t\t\t\timport fn from \"%s\";\n\t\t\t\t\t\t\t\tlet v = fn();\n\t\t\t\t\t\t\t\texport default function() {};`,\n\t\t\t\t\t\t\tlibName)\n\t\t\t\t\t\tb, err := getSimpleBundle(t, \"/path/to/script.js\", data, fs)\n\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\t_, err = b.Instantiate(context.Background(), 0)\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tt.Run(\"Isolation\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\trequire.NoError(t, fsext.WriteFile(fs, \"/a.js\", []byte(`const myvar = \"a\";`), 0o644))\n\t\t\trequire.NoError(t, fsext.WriteFile(fs, \"/b.js\", []byte(`const myvar = \"b\";`), 0o644))\n\t\t\tdata := `\n\t\t\t\timport \"./a.js\";\n\t\t\t\timport \"./b.js\";\n\t\t\t\texport default function() {\n\t\t\t\t\tif (typeof myvar != \"undefined\") {\n\t\t\t\t\t\tthrow new Error(\"myvar is set in global scope\");\n\t\t\t\t\t}\n\t\t\t\t};`\n\t\t\tb, err := getSimpleBundle(t, \"/script.js\", data, fs)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tbi, err := b.Instantiate(context.Background(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\t_, err = bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n}\n\nfunc createAndReadFile(t *testing.T, file string, content []byte, expectedLength int, binary string) (*BundleInstance, error) {\n\tt.Helper()\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fs.MkdirAll(\"/path/to\", 0o755))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/\"+file, content, 0o644))\n\n\tdata := fmt.Sprintf(`\n\t\tlet binArg = \"%s\";\n\t\texport let data = open(\"/path/to/%s\", binArg);\n\t\tvar expectedLength = %d;\n\t\tvar len = binArg === \"b\" ? \"byteLength\" : \"length\";\n\t\tif (data[len] != expectedLength) {\n\t\t\tthrow new Error(\"Length not equal, expected: \" + expectedLength + \", actual: \" + data[len]);\n\t\t}\n\t\texport default function() {}\n\t`, binary, file, expectedLength)\n\tb, err := getSimpleBundle(t, \"/path/to/script.js\", data, fs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbi, err := b.Instantiate(context.Background(), 0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn bi, nil\n}\n\nfunc TestInitContextOpen(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tcontent []byte\n\t\tfile    string\n\t\tlength  int\n\t}{\n\t\t{[]byte(\"hello world!\"), \"ascii\", 12},\n\t\t{[]byte(\"?((¯°·._.• ţ€$ţɨɲǥ µɲɨȼ๏ď€ΣSЫ ɨɲ Ќ6 •._.·°¯))؟•\"), \"utf\", 47},\n\t\t{[]byte{0o44, 226, 130, 172}, \"utf-8\", 2}, // $€\n\t\t// {[]byte{00, 36, 32, 127}, \"utf-16\", 2},   // $€\n\t}\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.file, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tbi, err := createAndReadFile(t, tc.file, tc.content, tc.length, \"\")\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, string(tc.content), bi.getExported(\"data\").Export())\n\t\t})\n\t}\n\n\tt.Run(\"Binary\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tbi, err := createAndReadFile(t, \"/path/to/file.bin\", []byte(\"hi!\\x0f\\xff\\x01\"), 6, \"b\")\n\t\trequire.NoError(t, err)\n\t\tbuf := bi.Runtime.NewArrayBuffer([]byte{104, 105, 33, 15, 255, 1})\n\t\tassert.Equal(t, buf, bi.getExported(\"data\").Export())\n\t})\n\n\ttestdata := map[string]string{\n\t\t\"Absolute\": \"/path/to/file\",\n\t\t\"Relative\": \"./file\",\n\t}\n\n\tfor name, loadPath := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := createAndReadFile(t, loadPath, []byte(\"content\"), 7, \"\")\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n\n\tt.Run(\"Nonexistent\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tpath := filepath.FromSlash(\"/nonexistent.txt\")\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `open(\"/nonexistent.txt\"); export default function() {}`)\n\t\trequire.Error(t, err)\n\t\tassert.Contains(t, err.Error(), fmt.Sprintf(\"open %s: file does not exist\", path))\n\t})\n\n\tt.Run(\"Directory\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tpath := filepath.FromSlash(\"/some/dir\")\n\t\tfs := fsext.NewMemMapFs()\n\t\trequire.NoError(t, fs.MkdirAll(path, 0o755))\n\t\t_, err := getSimpleBundle(t, \"/script.js\", `open(\"/some/dir\"); export default function() {}`, fs)\n\t\trequire.Error(t, err)\n\t\tassert.Contains(t, err.Error(), fmt.Sprintf(\"open() can't be used with directories, path: %q\", path))\n\t})\n}\n\nfunc TestRequestWithBinaryFile(t *testing.T) {\n\tt.Parallel()\n\n\tch := make(chan bool, 1)\n\n\th := func(_ http.ResponseWriter, r *http.Request) {\n\t\tdefer func() {\n\t\t\tch <- true\n\t\t}()\n\n\t\trequire.NoError(t, r.ParseMultipartForm(32<<20))\n\t\tfile, _, err := r.FormFile(\"file\")\n\t\trequire.NoError(t, err)\n\t\tdefer func() {\n\t\t\trequire.NoError(t, file.Close())\n\t\t}()\n\t\tbytes := make([]byte, 3)\n\t\t_, err = file.Read(bytes)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, []byte(\"hi!\"), bytes)\n\t\tassert.Equal(t, \"this is a standard form field\", r.FormValue(\"field\"))\n\t}\n\n\tsrv := httptest.NewServer(http.HandlerFunc(h))\n\tdefer srv.Close()\n\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fs.MkdirAll(\"/path/to\", 0o755))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/file.bin\", []byte(\"hi!\"), 0o644))\n\n\tb, err := getSimpleBundle(t, \"/path/to/script.js\",\n\t\tfmt.Sprintf(`\n\t\t\timport http from \"k6/http\";\n\t\t\tlet binFile = open(\"/path/to/file.bin\", \"b\");\n\t\t\texport default function() {\n\t\t\t\tvar data = {\n\t\t\t\t\tfield: \"this is a standard form field\",\n\t\t\t\t\tfile: http.file(binFile, \"test.bin\")\n\t\t\t\t};\n\t\t\t\tvar res = http.post(\"%s\", data);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t`, srv.URL), fs)\n\trequire.NoError(t, err)\n\n\tbi, err := b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\tlogger.Out = io.Discard\n\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tbi.moduleVUImpl.state = &lib.State{\n\t\tOptions: lib.Options{},\n\t\tLogger:  logger,\n\t\tTransport: &http.Transport{\n\t\t\tDialContext: (netext.NewDialer(\n\t\t\t\tnet.Dialer{\n\t\t\t\t\tTimeout:   10 * time.Second,\n\t\t\t\t\tKeepAlive: 60 * time.Second,\n\t\t\t\t},\n\t\t\t\tnetext.NewResolver(net.LookupIP, 0, types.DNSfirst, types.DNSpreferIPv4),\n\t\t\t)).DialContext,\n\t\t},\n\t\tBufferPool:     lib.NewBufferPool(),\n\t\tSamples:        make(chan metrics.SampleContainer, 500),\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\n\tctx := t.Context()\n\tbi.moduleVUImpl.ctx = ctx\n\n\tv, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\trequire.NoError(t, err)\n\trequire.NotNil(t, v)\n\tassert.Equal(t, true, v.Export())\n\n\t<-ch\n}\n\nfunc TestRequestWithMultipleBinaryFiles(t *testing.T) {\n\tt.Parallel()\n\n\tch := make(chan bool, 1)\n\n\th := func(_ http.ResponseWriter, r *http.Request) {\n\t\tdefer func() {\n\t\t\tch <- true\n\t\t}()\n\n\t\trequire.NoError(t, r.ParseMultipartForm(32<<20))\n\t\trequire.Len(t, r.MultipartForm.File[\"files\"], 2)\n\t\tfor i, fh := range r.MultipartForm.File[\"files\"] {\n\t\t\tf, _ := fh.Open()\n\t\t\tdefer func() { require.NoError(t, f.Close()) }()\n\t\t\tbytes := make([]byte, 5)\n\t\t\t_, err := f.Read(bytes)\n\t\t\trequire.NoError(t, err)\n\t\t\tswitch i {\n\t\t\tcase 0:\n\t\t\t\tassert.Equal(t, []byte(\"file1\"), bytes)\n\t\t\tcase 1:\n\t\t\t\tassert.Equal(t, []byte(\"file2\"), bytes)\n\t\t\t}\n\t\t}\n\t}\n\n\tsrv := httptest.NewServer(http.HandlerFunc(h))\n\tdefer srv.Close()\n\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fs.MkdirAll(\"/path/to\", 0o755))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/file1.bin\", []byte(\"file1\"), 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/file2.bin\", []byte(\"file2\"), 0o644))\n\n\tb, err := getSimpleBundle(t, \"/path/to/script.js\",\n\t\tfmt.Sprintf(`\n\timport http from 'k6/http';\n\n\tfunction toByteArray(obj) {\n\t\tlet arr = [];\n\t\tif (typeof obj === 'string') {\n\t\t\tfor (let i=0; i < obj.length; i++) {\n\t\t\t  arr.push(obj.charCodeAt(i) & 0xff);\n\t\t\t}\n\t\t} else {\n\t\t\tobj = new Uint8Array(obj);\n\t\t\tfor (let i=0; i < obj.byteLength; i++) {\n\t\t\t  arr.push(obj[i] & 0xff);\n\t\t\t}\n\t\t}\n\t\treturn arr;\n\t}\n\n\t// A more robust version of this polyfill is available here:\n\t// https://jslib.k6.io/formdata/0.0.1/index.js\n\tfunction FormData() {\n\t\tthis.boundary = '----boundary';\n\t\tthis.files = [];\n\t}\n\n\tFormData.prototype.append = function(name, value, filename) {\n\t\tthis.files.push({\n\t\t\tname: name,\n\t\t\tvalue: value,\n\t\t\tfilename: filename,\n\t\t});\n\t}\n\n\tFormData.prototype.body = function(name, value, filename) {\n\t\tlet body = [];\n\t\tlet barr = toByteArray('--' + this.boundary + '\\r\\n');\n\t\tfor (let i=0; i < this.files.length; i++) {\n\t\t\tbody.push(...barr);\n\t\t\tlet cdarr = toByteArray('Content-Disposition: form-data; name=\"'\n\t\t\t\t\t\t\t+ this.files[i].name + '\"; filename=\"'\n\t\t\t\t\t\t\t+ this.files[i].filename\n\t\t\t\t\t\t\t+ '\"\\r\\nContent-Type: application/octet-stream\\r\\n\\r\\n');\n\t\t\tbody.push(...cdarr);\n\t\t\tbody.push(...toByteArray(this.files[i].value));\n\t\t\tbody.push(...toByteArray('\\r\\n'));\n\t\t}\n\t\tbody.push(...toByteArray('--' + this.boundary + '--\\r\\n'));\n\t\treturn new Uint8Array(body).buffer;\n\t}\n\n\tconst file1 = open('/path/to/file1.bin', 'b');\n\tconst file2 = open('/path/to/file2.bin', 'b');\n\n\texport default function () {\n\t\tconst fd = new FormData();\n\t\tfd.append('files', file1, 'file1.bin');\n\t\tfd.append('files', file2, 'file2.bin');\n\t\tlet res = http.post('%s', fd.body(),\n\t\t\t\t{ headers: { 'Content-Type': 'multipart/form-data; boundary=' + fd.boundary }});\n\t\tif (res.status !== 200) {\n\t\t\tthrow new Error('Expected HTTP 200 response, received: ' + res.status);\n\t\t}\n\t\treturn true;\n\t}\n\t\t\t`, srv.URL), fs)\n\trequire.NoError(t, err)\n\n\tbi, err := b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\tlogger.Out = io.Discard\n\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tbi.moduleVUImpl.state = &lib.State{\n\t\tOptions: lib.Options{},\n\t\tLogger:  logger,\n\t\tTransport: &http.Transport{\n\t\t\tDialContext: (netext.NewDialer(\n\t\t\t\tnet.Dialer{\n\t\t\t\t\tTimeout:   10 * time.Second,\n\t\t\t\t\tKeepAlive: 60 * time.Second,\n\t\t\t\t},\n\t\t\t\tnetext.NewResolver(net.LookupIP, 0, types.DNSfirst, types.DNSpreferIPv4),\n\t\t\t)).DialContext,\n\t\t},\n\t\tBufferPool:     lib.NewBufferPool(),\n\t\tSamples:        make(chan metrics.SampleContainer, 500),\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\n\tctx := t.Context()\n\tbi.moduleVUImpl.ctx = ctx\n\n\tv, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\trequire.NoError(t, err)\n\trequire.NotNil(t, v)\n\tassert.Equal(t, true, v.Export())\n\n\t<-ch\n}\n\nfunc Test__VU(t *testing.T) {\n\tt.Parallel()\n\tb, err := getSimpleBundle(t, \"/script.js\", `\n\t\tlet vu = __VU;\n\t\texport default function() { return vu; }\n\t`)\n\trequire.NoError(t, err)\n\tbi, err := b.Instantiate(context.Background(), 5)\n\trequire.NoError(t, err)\n\tv, err := bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\trequire.NoError(t, err)\n\tassert.Equal(t, int64(5), v.Export())\n}\n\nfunc TestSourceMaps(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/module1.js\", []byte(`\nexport function f2(){\n    throw \"exception in line 2\"\n    console.log(\"in f2\")\n}\nexport function f1(){\n    throw \"exception in line 6\"\n    console.log(\"in f1\")\n}\n`[1:]), 0o644))\n\tdata := `\nimport * as module1 from \"./module1.js\"\n\nexport default function(){\n//    throw \"exception in line 4\"\n    module1.f2()\n    console.log(\"in default\")\n}\n`[1:]\n\tb, err := getSimpleBundle(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\tbi, err := b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n\t_, err = bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\trequire.Error(t, err)\n\texception := new(sobek.Exception)\n\trequire.ErrorAs(t, err, &exception)\n\trequire.Equal(t, \"exception in line 2\\n\\tat f2 (file:///module1.js:2:5(2))\\n\\tat default (file:///script.js:5:15(3))\\n\", exception.String())\n}\n\nfunc TestSourceMapsCJS(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/module1.js\", []byte(`\nexports.f2 = function(){\n    throw \"exception in line 2\"\n    console.log(\"in f2\")\n}\nexports.f1 = function(){\n    throw \"exception in line 6\"\n    console.log(\"in f1\")\n}\n`[1:]), 0o644))\n\tdata := `\nimport * as module1 from \"./module1.js\"\n\nexport default function(){\n//    throw \"exception in line 4\"\n    module1.f2()\n    console.log(\"in default\")\n}\n`[1:]\n\tb, err := getSimpleBundle(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\tbi, err := b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n\t_, err = bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\trequire.Error(t, err)\n\texception := new(sobek.Exception)\n\trequire.ErrorAs(t, err, &exception)\n\trequire.Equal(t, \"exception in line 2\\n\\tat file:///module1.js:2:5(2)\\n\\tat default (file:///script.js:5:15(3))\\n\", exception.String())\n}\n\nfunc TestSourceMapsExternal(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\t// This example is created through the template-typescript\n\trequire.NoError(t, fsext.WriteFile(fs, \"/test1.js\", []byte(`\n(()=>{\"use strict\";var e={};(()=>{var o=e;Object.defineProperty(o,\"__esModule\",{value:!0}),o.default=function(){!function(e){throw\"cool is cool\"}()}})();var o=exports;for(var r in e)o[r]=e[r];e.__esModule&&Object.defineProperty(o,\"__esModule\",{value:!0})})();\n//# sourceMappingURL=test1.js.map\n`[1:]), 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/test1.js.map\", []byte(`\n{\"version\":3,\"sources\":[\"webpack:///./test1.ts\"],\"names\":[\"s\",\"coolThrow\"],\"mappings\":\"2FAGA,sBAHA,SAAmBA,GACf,KAAM,eAGNC,K\",\"file\":\"test1.js\",\"sourcesContent\":[\"function coolThrow(s: string) {\\n    throw \\\"cool \\\"+ s\\n}\\nexport default () => {\\n    coolThrow(\\\"is cool\\\")\\n};\\n\"],\"sourceRoot\":\"\"}\n`[1:]), 0o644))\n\tdata := `\nimport l from \"./test1.js\"\n\nexport default function () {\n\t\tl()\n};\n`[1:]\n\tb, err := getSimpleBundle(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\tbi, err := b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n\t_, err = bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\trequire.Error(t, err)\n\texception := new(sobek.Exception)\n\trequire.ErrorAs(t, err, &exception)\n\trequire.Equal(t, \"cool is cool\\n\\tat webpack:///./test1.ts:2:4(2)\\n\\tat webpack:///./test1.ts:5:4(3)\\n\\tat default (file:///script.js:4:4(3))\\n\", exception.String())\n}\n\nfunc TestSourceMapsInlinedCJS(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\t// this example is from https://github.com/grafana/k6/issues/3689 generated with k6pack\n\tdata := `\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __export = (target, all) => {\n  for (var name in all)\n    __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n  if (from && typeof from === \"object\" || typeof from === \"function\") {\n    for (let key of __getOwnPropNames(from))\n      if (!__hasOwnProp.call(to, key) && key !== except)\n        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n  }\n  return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\nvar __publicField = (obj, key, value) => {\n  __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\n  return value;\n};\n\n// script.ts\nvar script_exports = {};\n__export(script_exports, {\n  default: () => script_default\n});\nmodule.exports = __toCommonJS(script_exports);\n\n// user.ts\nvar UserAccount = class {\n  constructor(name) {\n    __publicField(this, \"name\");\n    __publicField(this, \"id\");\n    this.name = name;\n    this.id = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);\n    throw \"ooops\";\n  }\n};\nfunction newUser(name) {\n  return new UserAccount(name);\n}\n\n// script.ts\nvar script_default = () => {\n  const user = newUser(\"John\");\n  console.log(user);\n};\n//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic2NyaXB0LnRzIiwgInVzZXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCB7IFVzZXIsIG5ld1VzZXIgfSBmcm9tIFwiLi91c2VyXCI7XG5cbmV4cG9ydCBkZWZhdWx0ICgpID0+IHtcbiAgY29uc3QgdXNlcjogVXNlciA9IG5ld1VzZXIoXCJKb2huXCIpO1xuICBjb25zb2xlLmxvZyh1c2VyKTtcbn07XG4iLCAiaW50ZXJmYWNlIFVzZXIge1xuICBuYW1lOiBzdHJpbmc7XG4gIGlkOiBudW1iZXI7XG59XG5cbmNsYXNzIFVzZXJBY2NvdW50IGltcGxlbWVudHMgVXNlciB7XG4gIG5hbWU6IHN0cmluZztcbiAgaWQ6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcpIHtcbiAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgIHRoaXMuaWQgPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUik7XG4gICAgdGhyb3cgXCJvb29wc1wiO1xuICB9XG59XG5cbmZ1bmN0aW9uIG5ld1VzZXIobmFtZTogc3RyaW5nKTogVXNlciB7XG4gIHJldHVybiBuZXcgVXNlckFjY291bnQobmFtZSk7XG59XG5cbmV4cG9ydCB7IFVzZXIsIG5ld1VzZXIgfTtcbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7OztBQ0tBLElBQU0sY0FBTixNQUFrQztBQUFBLEVBSWhDLFlBQVksTUFBYztBQUgxQjtBQUNBO0FBR0UsU0FBSyxPQUFPO0FBQ1osU0FBSyxLQUFLLEtBQUssTUFBTSxLQUFLLE9BQU8sSUFBSSxPQUFPLGdCQUFnQjtBQUM1RCxVQUFNO0FBQUEsRUFDUjtBQUNGO0FBRUEsU0FBUyxRQUFRLE1BQW9CO0FBQ25DLFNBQU8sSUFBSSxZQUFZLElBQUk7QUFDN0I7OztBRGhCQSxJQUFPLGlCQUFRLE1BQU07QUFDbkIsUUFBTSxPQUFhLFFBQVEsTUFBTTtBQUNqQyxVQUFRLElBQUksSUFBSTtBQUNsQjsiLAogICJuYW1lcyI6IFtdCn0K\n`[1:]\n\tb, err := getSimpleBundle(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\tbi, err := b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n\t_, err = bi.getCallableExport(consts.DefaultFn)(sobek.Undefined())\n\trequire.Error(t, err)\n\texception := new(sobek.Exception)\n\trequire.ErrorAs(t, err, &exception)\n\t// TODO figure out why those are not the same as the one in the previous test TestSourceMapsExternal\n\t// likely settings in the transpilers\n\trequire.Equal(t, \"ooops\\n\\tat file:///user.ts:13:4(28)\\n\\tat newUser (file:///user.ts:18:9(3))\\n\\tat script_default (file:///script.ts:4:29(4))\\n\", exception.String())\n}\n\nfunc TestImportModificationsAreConsistentBetweenFiles(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/notk6.js\", []byte(`export default {group}; function group() {}`), 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/instrument.js\", []byte(`\n    import k6 from \"k6\";\n    k6.newKey = 5;\n    k6.group = 3;\n\n    import notk6 from \"./notk6.js\";\n    notk6.group = 3;\n    notk6.newKey = 5;\n    `), 0o644))\n\n\tb, err := getSimpleBundle(t, \"/script.js\", `\n    import k6 from \"k6\";\n    import notk6 from \"./notk6.js\";\n    import \"./instrument.js\";\n    if (k6.newKey != 5) { throw \"k6.newKey is wrong \"+ k6.newKey}\n    if (k6.group != 3) { throw \"k6.group is wrong \"+ k6.group}\n    if (notk6.newKey != 5) { throw \"notk6.newKey is wrong \"+ notk6.newKey}\n    if (notk6.group != 3) { throw \"notk6.group is wrong \"+ notk6.group}\n    export default () => { throw \"this shouldn't be ran\" }\n`, fs)\n\trequire.NoError(t, err, \"bundle error\")\n\n\t_, err = b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n}\n\nfunc TestCacheAbsolutePathsNotRelative(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/a/interesting.js\", []byte(`export default \"a.interesting\"`), 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/a/import.js\", []byte(`export { default as default} from \"./interesting.js\"`), 0o644))\n\n\trequire.NoError(t, fsext.WriteFile(fs, \"/b/interesting.js\", []byte(`export default \"b.interesting\"`), 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/b/import.js\", []byte(`export { default as default} from \"./interesting.js\"`), 0o644))\n\n\tb, err := getSimpleBundle(t, \"/script.js\", `\n    import a from \"/a/import.js\"\n    import b from \"/b/import.js\"\n    if (a != \"a.interesting\") { throw `+\"`\"+`'a' has wrong value \"${a}\" should be \"a.interesting\"`+\"`\"+`}\n\n    if (b != \"b.interesting\") { throw `+\"`\"+`'b' has wrong value \"${b}\" should be \"b.interesting\"`+\"`\"+`}\n    export default () => { throw \"this shouldn't be ran\" }\n`, fs)\n\trequire.NoError(t, err, \"bundle error\")\n\n\t_, err = b.Instantiate(context.Background(), 0)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/js/jsmodules.go",
    "content": "package js\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/browser\"\n\t\"go.k6.io/k6/internal/js/modules/k6/crypto\"\n\t\"go.k6.io/k6/internal/js/modules/k6/crypto/x509\"\n\t\"go.k6.io/k6/internal/js/modules/k6/data\"\n\t\"go.k6.io/k6/internal/js/modules/k6/encoding\"\n\t\"go.k6.io/k6/internal/js/modules/k6/execution\"\n\t\"go.k6.io/k6/internal/js/modules/k6/experimental/csv\"\n\t\"go.k6.io/k6/internal/js/modules/k6/experimental/fs\"\n\t\"go.k6.io/k6/internal/js/modules/k6/experimental/streams\"\n\t\"go.k6.io/k6/internal/js/modules/k6/grpc\"\n\t\"go.k6.io/k6/internal/js/modules/k6/metrics\"\n\t\"go.k6.io/k6/internal/js/modules/k6/secrets\"\n\t\"go.k6.io/k6/internal/js/modules/k6/timers\"\n\t\"go.k6.io/k6/internal/js/modules/k6/websockets\"\n\t\"go.k6.io/k6/internal/js/modules/k6/ws\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/js/modules/k6/html\"\n\t\"go.k6.io/k6/js/modules/k6/http\"\n\n\t\"github.com/grafana/xk6-redis/redis\"\n)\n\nfunc getInternalJSModules() map[string]any {\n\treturn map[string]any{\n\t\t// Stable modules\n\t\t\"k6\":             k6.New(),\n\t\t\"k6/browser\":     browser.New(),\n\t\t\"k6/crypto\":      crypto.New(),\n\t\t\"k6/crypto/x509\": x509.New(),\n\t\t\"k6/data\":        data.New(),\n\t\t\"k6/encoding\":    encoding.New(),\n\t\t\"k6/execution\":   execution.New(),\n\t\t\"k6/html\":        html.New(),\n\t\t\"k6/http\":        http.New(),\n\t\t\"k6/net/grpc\":    grpc.New(),\n\t\t\"k6/metrics\":     metrics.New(),\n\t\t\"k6/secrets\":     secrets.New(),\n\t\t\"k6/timers\":      timers.New(),\n\t\t\"k6/websockets\":  websockets.New(),\n\t\t\"k6/ws\":          ws.New(),\n\n\t\t// Experimental modules\n\t\t\"k6/experimental/csv\":     csv.New(),\n\t\t\"k6/experimental/fs\":      fs.New(),\n\t\t\"k6/experimental/streams\": streams.New(),\n\n\t\t// Deprecated modules\n\t\t\"k6/experimental/websockets\": newWarnExperimentalModule(websockets.New(),\n\t\t\t\"k6/experimental/websockets is deprecated and will be removed in a future release.\"+\n\t\t\t\t\" Please use k6/websockets instead.\"),\n\t\t\"k6/experimental/redis\": newWarnExperimentalModule(redis.New(),\n\t\t\t\"k6/experimental/redis has been deprecated and will be removed in future versions.\"+\n\t\t\t\t\" Please migrate to the new version by changing your import to 'k6/x/redis'.\"+\n\t\t\t\t\" Read more here: https://grafana.com/docs/k6/latest/javascript-api/k6-x-redis\"),\n\n\t\t// Removed modules\n\t\t\"k6/experimental/browser\": newRemovedModule(\n\t\t\t\"k6/experimental/browser has been graduated, please use k6/browser instead.\" +\n\t\t\t\t\"Please update your imports to use k6/browser instead of k6/experimental/browser,\" +\n\t\t\t\t\" For more information, see the migration guide at the link:\" +\n\t\t\t\t\" https://grafana.com/docs/k6/latest/using-k6-browser/migrating-to-k6-v0-52/\"),\n\t\t\"k6/experimental/grpc\": newRemovedModule(\n\t\t\t\"k6/experimental/grpc has been graduated, please use k6/net/grpc instead.\" +\n\t\t\t\t\" See https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/ for more information.\",\n\t\t),\n\t\t\"k6/experimental/timers\": newRemovedModule(\n\t\t\t\"k6/experimental/timers has been graduated, and it's now globally available as defined by standard WebAPIs.\" +\n\t\t\t\t\" You just need to remove the import.\"),\n\t\t\"k6/experimental/tracing\": newRemovedModule(\n\t\t\t\"k6/experimental/tracing has been removed. All of it functionality is available as pure JavaScript module.\" +\n\t\t\t\t\" More info available at the docs:\" +\n\t\t\t\t\" https://grafana.com/docs/k6/latest/javascript-api/jslib/http-instrumentation-tempo\"),\n\t\t\"k6/experimental/webcrypto\": newRemovedModule(\n\t\t\t\"k6/experimental/webcrypto has been graduated and it's now globally available as defined by standard WebAPIs.\" +\n\t\t\t\t\" You just need to remove the import.\"),\n\t}\n}\n\nfunc getJSModules() map[string]any {\n\tresult := getInternalJSModules()\n\texternal := ext.Get(ext.JSExtension)\n\n\t// external is always prefixed with `k6/x`\n\tfor _, e := range external {\n\t\tresult[e.Name] = e.Module\n\t}\n\n\treturn result\n}\n\ntype removedModule struct {\n\terrMsg string\n}\n\nfunc newRemovedModule(errMsg string) modules.Module {\n\treturn &removedModule{errMsg: errMsg}\n}\n\nfunc (rm *removedModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\tcommon.Throw(vu.Runtime(), errors.New(rm.errMsg))\n\n\treturn nil\n}\n\ntype warnExperimentalModule struct {\n\tonce sync.Once\n\tmsg  string\n\tbase modules.Module\n}\n\nfunc newWarnExperimentalModule(base modules.Module, msg string) modules.Module {\n\treturn &warnExperimentalModule{\n\t\tmsg:  msg,\n\t\tbase: base,\n\t}\n}\n\nfunc (w *warnExperimentalModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\tw.once.Do(func() { vu.InitEnv().Logger.Warn(w.msg) })\n\treturn w.base.NewModuleInstance(vu)\n}\n"
  },
  {
    "path": "internal/js/module_loading_test.go",
    "content": "package js\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io/fs\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc newDevNullSampleChannel() chan metrics.SampleContainer {\n\tch := make(chan metrics.SampleContainer, 100)\n\tgo func() {\n\t\tfor range ch { //nolint:revive\n\t\t}\n\t}()\n\treturn ch\n}\n\nfunc TestLoadOnceGlobalVars(t *testing.T) {\n\tt.Parallel()\n\ttestCases := map[string]string{\n\t\t\"module.exports\": `\n\t\t\tvar globalVar;\n\t\t\tif (!globalVar) {\n\t\t\t\tglobalVar = Math.random();\n\t\t\t}\n\t\t\tfunction C() {\n\t\t\t\treturn globalVar;\n\t\t\t}\n\t\t\tmodule.exports = {\n\t\t\t\tC: C,\n\t\t\t}\n\t\t`,\n\t\t\"direct export\": `\n\n\t\t\tvar globalVar;\n\t\t\tif (!globalVar) {\n\t\t\t\tglobalVar = Math.random();\n\t\t\t}\n\t\t\texport function C() {\n\t\t\t\treturn globalVar;\n\t\t\t}\n\t\t`,\n\t}\n\tfor name, data := range testCases {\n\t\tcData := data\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfileSystem := fsext.NewMemMapFs()\n\t\t\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/C.js\", []byte(cData), fs.ModePerm))\n\n\t\t\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/A.js\", []byte(`\n\t\timport { C } from \"./C.js\";\n\t\texport function A() {\n\t\t\treturn C();\n\t\t}\n\t`), fs.ModePerm))\n\t\t\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/B.js\", []byte(`\n\t\tvar  c = require(\"./C.js\");\n\t\texport function B() {\n\t\t\treturn c.C();\n\t\t}\n\t`), fs.ModePerm))\n\t\t\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\timport { A } from \"./A.js\";\n\t\t\timport { B } from \"./B.js\";\n\n\t\t\texport default function(data) {\n\t\t\t\tif (A() === undefined) {\n\t\t\t\t\tthrow new Error(\"A() is undefined\");\n\t\t\t\t}\n\t\t\t\tif (A() != B()) {\n\t\t\t\t\tthrow new Error(\"A() != B()    (\" + A() + \") != (\" + B() + \")\");\n\t\t\t\t}\n\t\t\t}\n\t\t`, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\t\t\trequire.NoError(t, err)\n\n\t\t\tarc := r1.MakeArchive()\n\t\t\tr2, err := getSimpleArchiveRunner(t, arc)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\t\t\tfor name, r := range runners {\n\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tch := newDevNullSampleChannel()\n\t\t\t\t\tdefer close(ch)\n\n\t\t\t\t\tctx := t.Context()\n\n\t\t\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestLoadExportsIsntUsableInModule(t *testing.T) {\n\tt.Parallel()\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/A.js\", []byte(`\n\t\texport function A() {\n\t\t\treturn \"A\";\n\t\t}\n\t\texport function B() {\n\t\t\treturn exports.A() + \"B\";\n\t\t}\n\t`), fs.ModePerm))\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\timport { A, B } from \"./A.js\";\n\n\t\t\texport default function(data) {\n\t\t\t\tif (A() != \"A\") {\n\t\t\t\t\tthrow new Error(\"wrong value of A() \" + A());\n\t\t\t\t}\n\n\t\t\t\tif (B() != \"AB\") {\n\t\t\t\t\tthrow new Error(\"wrong value of B() \" + B());\n\t\t\t\t}\n\t\t\t}\n\t\t`, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.ErrorContains(t, vu.RunOnce(), `you are trying to access identifier \"exports\"`)\n\t\t})\n\t}\n}\n\nfunc TestLoadDoesntBreakHTTPGet(t *testing.T) {\n\tt.Parallel()\n\t// This test that functions such as http.get which require context still work if they are called\n\t// inside script that is imported\n\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/A.js\", []byte(tb.Replacer.Replace(`\n\t\timport http from \"k6/http\";\n\t\texport function A() {\n\t\t\treturn http.get(\"HTTPBIN_URL/get\");\n\t\t}\n\t`)), fs.ModePerm))\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\timport { A } from \"./A.js\";\n\n\t\t\texport default function(data) {\n\t\t\t\tlet resp = A();\n\t\t\t\tif (resp.status != 200) {\n\t\t\t\t\tthrow new Error(\"wrong status \"+ resp.status);\n\t\t\t\t}\n\t\t\t}\n\t\t`, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, r1.SetOptions(lib.Options{Hosts: types.NullHosts{Trie: tb.Dialer.Hosts}}))\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestLoadGlobalVarsAreNotSharedBetweenVUs(t *testing.T) {\n\tt.Parallel()\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/A.js\", []byte(`\n\t\tvar globalVar = 0;\n\t\texport function A() {\n\t\t\tglobalVar += 1\n\t\t\treturn globalVar;\n\t\t}\n\t`), fs.ModePerm))\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\timport { A } from \"./A.js\";\n\n\t\t\texport default function(data) {\n\t\t\t\tvar a = A();\n\t\t\t\tif (a == 1) {\n\t\t\t\t\ta = 2;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"wrong value of a \" + a);\n\t\t\t\t}\n\t\t\t}\n\t\t`, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx, cancel := context.WithCancel(context.Background())\n\t\t\tdefer cancel()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\n\t\t\t// run a second VU\n\t\t\tctx, cancel = context.WithCancel(context.Background())\n\t\t\tdefer cancel()\n\t\t\tinitVU, err = r.NewVU(ctx, 2, 2, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu = initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestLoadCycle(t *testing.T) {\n\tt.Parallel()\n\t// This is mostly the example from https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/counter.js\", []byte(`\n\t\t\tlet main = require(\"./main.js\");\n\t\t\texports.count = 5;\n\t\t\texports.a = function() {\n\t\t\t\treturn main.message;\n\t\t\t}\n\t`), fs.ModePerm))\n\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/main.js\", []byte(`\n\t\t\tlet counter = require(\"./counter.js\");\n\t\t\tlet count = counter.count;\n\t\t\tlet a = counter.a;\n\t\t\texports.message = \"Eval complete\";\n\n\t\t\texports.default = function() {\n\t\t\t\tif (count != 5) {\n\t\t\t\t\tthrow new Error(\"Wrong value of count \"+ count);\n\t\t\t\t}\n\t\t\t\tlet aMessage = a();\n\t\t\t\tif (aMessage != exports.message) {\n\t\t\t\t\tthrow new Error(\"Wrong value of a() \"+ aMessage);\n\t\t\t\t}\n\t\t\t}\n\t`), fs.ModePerm))\n\tdata, err := fsext.ReadFile(fileSystem, \"/main.js\")\n\trequire.NoError(t, err)\n\tr1, err := getSimpleRunner(t, \"/main.js\", string(data), fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestLoadCycleBinding(t *testing.T) {\n\tt.Parallel()\n\t// This is mostly the example from\n\t// http://2ality.com/2015/07/es6-module-exports.html#why-export-bindings\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/a.js\", []byte(`\n\t\timport {bar} from './b.js';\n\t\texport function foo(a) {\n\t\t\t\tif (a !== undefined) {\n\t\t\t\t\treturn \"foo\" + a;\n\t\t\t\t}\n\t\t\t\treturn \"foo\" + bar(3);\n\t\t}\n\t`), fs.ModePerm))\n\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/b.js\", []byte(`\n\t\timport {foo} from './a.js';\n\t\texport function bar(a) {\n\t\t\t\tif (a !== undefined) {\n\t\t\t\t\treturn \"bar\" + a;\n\t\t\t\t}\n\t\t\t\treturn \"bar\" + foo(5);\n\t\t\t}\n\t`), fs.ModePerm))\n\n\tr1, err := getSimpleRunner(t, \"/main.js\", `\n\t\t\timport {foo} from './a.js';\n\t\t\timport {bar} from './b.js';\n\t\t\texport default function() {\n\t\t\t\tlet fooMessage = foo();\n\t\t\t\tif (fooMessage != \"foobar3\") {\n\t\t\t\t\tthrow new Error(\"Wrong value of foo() \"+ fooMessage);\n\t\t\t\t}\n\t\t\t\tlet barMessage = bar();\n\t\t\t\tif (barMessage != \"barfoo5\") {\n\t\t\t\t\tthrow new Error(\"Wrong value of bar() \"+ barMessage);\n\t\t\t\t}\n\t\t\t}\n\t\t`, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestBrowserified(t *testing.T) {\n\tt.Parallel()\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/browserified.js\", []byte(`\n\t\t(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.npmlibs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\n\t\tmodule.exports.A = function () {\n\t\t\treturn \"a\";\n\t\t}\n\n\t\t},{}],2:[function(require,module,exports){\n\t\texports.B = function() {\n\t\treturn \"b\";\n\t\t}\n\n\t\t},{}],3:[function(require,module,exports){\n\t\texports.alpha = require('./a.js');\n\t\texports.bravo = require('./b.js');\n\n\t\t},{\"./a.js\":1,\"./b.js\":2}]},{},[3])(3)\n\t\t});\n\t`), fs.ModePerm))\n\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\timport {alpha, bravo } from \"./browserified.js\";\n\n\t\t\texport default function(data) {\n\t\t\t\tif (alpha.A === undefined) {\n\t\t\t\t\tthrow new Error(\"alpha.A is undefined\");\n\t\t\t\t}\n\t\t\t\tif (alpha.A() != \"a\") {\n\t\t\t\t\tthrow new Error(\"alpha.A() != 'a'    (\" + alpha.A() + \") != 'a'\");\n\t\t\t\t}\n\n\t\t\t\tif (bravo.B === undefined) {\n\t\t\t\t\tthrow new Error(\"bravo.B is undefined\");\n\t\t\t\t}\n\t\t\t\tif (bravo.B() != \"b\") {\n\t\t\t\t\tthrow new Error(\"bravo.B() != 'b'    (\" + bravo.B() + \") != 'b'\");\n\t\t\t\t}\n\t\t\t}\n\t\t`, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := make(chan metrics.SampleContainer, 100)\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestLoadingUnexistingModuleDoesntPanic(t *testing.T) {\n\tt.Parallel()\n\tfileSystem := fsext.NewMemMapFs()\n\tdata := `var b;\n\t\t\ttry {\n\t\t\t\tb = eval(\"require('buffer')\");\n\t\t\t} catch (err) {\n\t\t\t\tb = \"correct\";\n\t\t\t}\n\t\t\texports.default = function() {\n\t\t\t\tif (b != \"correct\") {\n\t\t\t\t\tthrow new Error(\"wrong b \"+ JSON.stringify(b));\n\t\t\t\t}\n\t\t\t}`\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/script.js\", []byte(data), 0o644))\n\tr1, err := getSimpleRunner(t, \"/script.js\", data, fileSystem)\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tbuf := &bytes.Buffer{}\n\trequire.NoError(t, arc.Write(buf))\n\tarc, err = lib.ReadArchive(buf)\n\trequire.NoError(t, err)\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestLoadingSourceMapsDoesntErrorOut(t *testing.T) {\n\tt.Parallel()\n\n\tfileSystem := fsext.NewMemMapFs()\n\tdata := `exports.default = function() {}\n//# sourceMappingURL=test.min.js.map`\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/script.js\", []byte(data), 0o644))\n\tr1, err := getSimpleRunner(t, \"/script.js\", data, fileSystem)\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tbuf := &bytes.Buffer{}\n\trequire.NoError(t, arc.Write(buf))\n\tarc, err = lib.ReadArchive(buf)\n\trequire.NoError(t, err)\n\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestOptionsAreGloballyReadable(t *testing.T) {\n\tt.Parallel()\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/A.js\", []byte(`\n        export function A() {\n        // we can technically get a field set from outside of js this way\n            return options.someField;\n        }`), fs.ModePerm))\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n     import { A } from \"./A.js\";\n     export let options = {\n       someField: \"here is an option\",\n     }\n\n        export default function(data) {\n            var caught = false;\n            try{\n                if (A() == \"here is an option\") {\n                  throw \"oops\"\n                }\n            } catch(e) {\n                if (e.message != \"options is not defined\") {\n                    throw e;\n                }\n                caught = true;\n            }\n            if (!caught) {\n                throw \"expected exception\"\n            }\n        } `, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := newDevNullSampleChannel()\n\t\t\tdefer close(ch)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestOptionsAreNotGloballyWritable(t *testing.T) {\n\tt.Parallel()\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/A.js\", []byte(`\n    export function A() {\n        // this requires that this is defined\n        options.minIterationDuration = \"1h\"\n    }`), fs.ModePerm))\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n    import {A} from \"/A.js\"\n    export let options = {minIterationDuration: \"5m\"}\n\n    export default () =>{}\n    var caught = false;\n    try{\n        A()\n    } catch(e) {\n        if (e.message != \"options is not defined\") {\n            throw e;\n        }\n        caught = true;\n    }\n\n    if (!caught) {\n        throw \"expected exception\"\n    }`, fileSystem, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n\n\t// here it exists\n\trequire.EqualValues(t, time.Minute*5, r1.GetOptions().MinIterationDuration.Duration)\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trequire.EqualValues(t, time.Minute*5, r2.GetOptions().MinIterationDuration.Duration)\n}\n\nfunc TestDefaultNamedExports(t *testing.T) {\n\tt.Parallel()\n\t_, err := getSimpleRunner(t, \"/main.js\", `export default function main() {}`,\n\t\tlib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\trequire.NoError(t, err)\n}\n\nfunc TestStarImport(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"esm_spec\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\t\terr := writeToFs(fs, map[string]any{\n\t\t\t\"/commonjs_file.js\": `exports.something = 5;`,\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\timport * as cjs from \"./commonjs_file.js\"; // commonjs\n\t\t\timport * as k6 from \"k6\"; // \"new\" go module\n\t\t\t// TODO: test with basic go module maybe\n\t\n\t\t\tif (cjs.something != 5) {\n\t\t\t\tthrow \"cjs.something has wrong value\" + cjs.something;\n\t\t\t}\n\t\t\tif (typeof k6.sleep != \"function\") {\n\t\t\t\tthrow \"k6.sleep has wrong type\" + typeof k6.sleep;\n\t\t\t}\n\t\t\texport default () => {}\n\t\t`, fs, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\t\trequire.NoError(t, err)\n\n\t\tarc := r1.MakeArchive()\n\t\t_, err = getSimpleArchiveRunner(t, arc)\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"default_to_namespaced_object\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\timport http from \"k6/http\";\n\t\t\timport * as httpNO from \"k6/http\";\n\n\t\t\tconst httpKeys = Object.keys(http);\n\t\t\tconst httpNOKeys = Object.keys(httpNO);\n\n\t\t\t// 1. Check if both have the same number of properties\n\t\t\tif (httpKeys.length !== httpNOKeys.length) {\n\t\t\t\tthrow \"Objects have a different number of properties.\";\n\t\t\t}\n\n\t\t\t// 2. Check if all properties match\n\t\t\tfor (const key of httpKeys) {\n\t\t\t\tif (!Object.prototype.hasOwnProperty.call(httpNO, key)) {\n\t\t\t\t\tthrow `+\"`Property ${key} is missing in the second object.`\"+`;\n\t\t\t\t}\n\n\t\t\t\tif (http[key] !== httpNO[key]) {\n\t\t\t\t\tthrow `+\"`Property ${key} does not match between the objects.`\"+`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\texport default () => {}\n\t\t`, lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")})\n\t\trequire.NoError(t, err)\n\n\t\tarc := r1.MakeArchive()\n\t\t_, err = getSimpleArchiveRunner(t, arc)\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestIndirectExportDefault(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\terr := writeToFs(fs, map[string]any{\n\t\t\"/other.js\": `export function some() {};`,\n\t})\n\trequire.NoError(t, err)\n\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\timport { some as default } from \"./other.js\";\n\t\texport { default };\n\t`, fs)\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\t_, err = getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/browser_context_mapping.go",
    "content": "package browser\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6error\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// mapBrowserContext to the JS module.\nfunc mapBrowserContext(vu moduleVU, bc *common.BrowserContext) mapping { //nolint:funlen,gocognit\n\tif bc == nil {\n\t\treturn nil\n\t}\n\n\trt := vu.Runtime()\n\treturn mapping{\n\t\t\"addCookies\": func(cookies []*common.Cookie) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.AddCookies(cookies) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"addInitScript\": func(script sobek.Value) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tif k6common.IsNullish(script) {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\n\t\t\t\tsource := \"\"\n\t\t\t\tswitch script.ExportType() {\n\t\t\t\tcase reflect.TypeFor[string]():\n\t\t\t\t\tsource = script.String()\n\t\t\t\tcase reflect.TypeFor[sobek.Object]():\n\t\t\t\t\topts := script.ToObject(rt)\n\t\t\t\t\tfor _, k := range opts.Keys() {\n\t\t\t\t\t\tif k == \"content\" {\n\t\t\t\t\t\t\tsource = opts.Get(k).String()\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\t_, isCallable := sobek.AssertFunction(script)\n\t\t\t\t\tif !isCallable {\n\t\t\t\t\t\tsource = fmt.Sprintf(\"(%s);\", script.ToString().String())\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsource = fmt.Sprintf(\"(%s)(...args);\", script.ToString().String())\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn nil, bc.AddInitScript(source) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"browser\": func() mapping {\n\t\t\t// the browser is grabbed from VU.\n\t\t\treturn mapBrowser(vu)\n\t\t},\n\t\t\"clearCookies\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.ClearCookies() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"clearPermissions\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.ClearPermissions() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"close\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.Close() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"cookies\": func(urls ...string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn bc.Cookies(urls...) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"grantPermissions\": func(permissions []string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := exportTo[common.GrantPermissionsOptions](vu.Runtime(), opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing grant permission options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.GrantPermissions(permissions, popts)\n\t\t\t}), nil\n\t\t},\n\t\t\"setDefaultNavigationTimeout\": bc.SetDefaultNavigationTimeout,\n\t\t\"setDefaultTimeout\":           bc.SetDefaultTimeout,\n\t\t\"setGeolocation\": func(geolocation sobek.Value) (*sobek.Promise, error) {\n\t\t\tgl, err := exportTo[common.Geolocation](vu.Runtime(), geolocation)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing geo location: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.SetGeolocation(&gl)\n\t\t\t}), nil\n\t\t},\n\t\t\"setHTTPCredentials\": func(httpCredentials sobek.Value) (*sobek.Promise, error) {\n\t\t\tcreds, err := exportTo[common.Credentials](rt, httpCredentials)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing HTTP credentials: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.SetHTTPCredentials(creds) //nolint:staticcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setOffline\": func(offline bool) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.SetOffline(offline) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"waitForEvent\": func(event string, optsOrPredicate sobek.Value) (*sobek.Promise, error) {\n\t\t\trt := vu.Runtime()\n\t\t\tctx := vu.Context()\n\n\t\t\tpopts, err := parseWaitForEventOptions(rt, optsOrPredicate, bc.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing wait for event options: %w\", err)\n\t\t\t}\n\n\t\t\t// Waits until the first event if no predicate is specified.\n\t\t\tvar pred func(p *common.Page) (bool, error)\n\n\t\t\t// Waits until the event that satisfies the predicate.\n\t\t\tif popts.PredicateFn != nil {\n\t\t\t\tpred = func(p *common.Page) (bool, error) {\n\t\t\t\t\treturn queueTask(ctx, vu.get(ctx, p.TargetID()), func() (bool, error) {\n\t\t\t\t\t\tv, err := popts.PredicateFn(rt.ToValue(p))\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn false, err\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn v.ToBoolean(), nil\n\t\t\t\t\t})()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (result any, reason error) {\n\t\t\t\tv, err := bc.WaitForEvent(event, pred, popts.Timeout)\n\t\t\t\tif err != nil {\n\t\t\t\t\tpanicIfFatalError(ctx, err)\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tp, ok := v.(*common.Page)\n\t\t\t\tif !ok {\n\t\t\t\t\tpanicIfFatalError(ctx, fmt.Errorf(\"response object is not a page: %w\", k6error.ErrFatal))\n\t\t\t\t}\n\t\t\t\treturn mapPage(vu, p), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"pages\": func() *sobek.Object {\n\t\t\tvar (\n\t\t\t\tmpages []mapping\n\t\t\t\tpages  = bc.Pages()\n\t\t\t)\n\t\t\tfor _, page := range pages {\n\t\t\t\tif page == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tm := mapPage(vu, page)\n\t\t\t\tmpages = append(mpages, m)\n\t\t\t}\n\n\t\t\treturn rt.ToValue(mpages).ToObject(rt)\n\t\t},\n\t\t\"newPage\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tpage, err := bc.NewPage()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapPage(vu, page), nil\n\t\t\t})\n\t\t},\n\t}\n}\n\n// waitForEventOptions are the options used by the browserContext.waitForEvent API.\ntype waitForEventOptions struct {\n\tTimeout     time.Duration\n\tPredicateFn sobek.Callable\n}\n\n// parseWaitForEventOptions parses optsOrPredicate into a WaitForEventOptions.\n// It returns a WaitForEventOptions with the default timeout if optsOrPredicate is nil,\n// or not a callable predicate function.\n// It can parse only a callable predicate function or an object which contains a\n// callable predicate function and a timeout.\nfunc parseWaitForEventOptions(\n\trt *sobek.Runtime, optsOrPredicate sobek.Value, defaultTime time.Duration,\n) (*waitForEventOptions, error) {\n\tw := &waitForEventOptions{\n\t\tTimeout: defaultTime,\n\t}\n\n\tif k6common.IsNullish(optsOrPredicate) {\n\t\treturn w, nil\n\t}\n\tvar isCallable bool\n\tw.PredicateFn, isCallable = sobek.AssertFunction(optsOrPredicate)\n\tif isCallable {\n\t\treturn w, nil\n\t}\n\n\topts := optsOrPredicate.ToObject(rt)\n\tfor _, k := range opts.Keys() {\n\t\tswitch k {\n\t\tcase \"predicate\":\n\t\t\tw.PredicateFn, isCallable = sobek.AssertFunction(opts.Get(k))\n\t\t\tif !isCallable {\n\t\t\t\treturn nil, errors.New(\"predicate function is not callable\")\n\t\t\t}\n\t\tcase \"timeout\":\n\t\t\tw.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown option: %s\", k)\n\t\t}\n\t}\n\n\treturn w, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/browser_context_options_test.go",
    "content": "package browser\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n)\n\nfunc TestBrowserContextOptionsPermissions(t *testing.T) {\n\tt.Parallel()\n\tvu := k6test.NewVU(t)\n\n\topts, err := parseBrowserContextOptions(vu.Runtime(), vu.ToSobekValue((struct {\n\t\tPermissions []any `js:\"permissions\"`\n\t}{\n\t\tPermissions: []any{\"camera\", \"microphone\"},\n\t})))\n\tassert.NoError(t, err)\n\tassert.Len(t, opts.Permissions, 2)\n\tassert.Equal(t, []string{\"camera\", \"microphone\"}, opts.Permissions)\n}\n\nfunc TestBrowserContextSetGeolocation(t *testing.T) {\n\tt.Parallel()\n\tvu := k6test.NewVU(t)\n\n\topts, err := parseBrowserContextOptions(vu.Runtime(), vu.ToSobekValue((struct {\n\t\tGeoLocation *common.Geolocation `js:\"geolocation\"`\n\t}{\n\t\tGeoLocation: &common.Geolocation{\n\t\t\tLatitude:  1.0,\n\t\t\tLongitude: 2.0,\n\t\t\tAccuracy:  3.0,\n\t\t},\n\t})))\n\tassert.NoError(t, err)\n\tassert.NotNil(t, opts)\n\tassert.Equal(t, 1.0, opts.Geolocation.Latitude)\n\tassert.Equal(t, 2.0, opts.Geolocation.Longitude)\n\tassert.Equal(t, 3.0, opts.Geolocation.Accuracy)\n}\n\nfunc TestBrowserContextDefaultOptions(t *testing.T) {\n\tt.Parallel()\n\tvu := k6test.NewVU(t)\n\n\tdefaults := common.DefaultBrowserContextOptions()\n\n\t// gets the default options by default\n\topts, err := parseBrowserContextOptions(vu.Runtime(), nil)\n\trequire.NoError(t, err)\n\tassert.Equal(t, defaults, opts)\n\n\t// merges with the default options\n\topts, err = parseBrowserContextOptions(vu.Runtime(), vu.ToSobekValue((struct {\n\t\tDeviceScaleFactor float64 `js:\"deviceScaleFactor\"` // just to test a different field\n\t}{\n\t\tDeviceScaleFactor: defaults.DeviceScaleFactor + 1,\n\t})))\n\trequire.NoError(t, err)\n\tassert.NotEqual(t, defaults.DeviceScaleFactor, opts.DeviceScaleFactor)\n\tassert.Equal(t, defaults.Locale, opts.Locale) // should remain as default\n}\n\nfunc TestBrowserContextAllOptions(t *testing.T) {\n\tt.Parallel()\n\tvu := k6test.NewVU(t)\n\topts, err := vu.Runtime().RunString(`const opts = {\n\t\t\tacceptDownloads: true,\n\t\t\tdownloadsPath: '/tmp',\n\t\t\tbypassCSP: true,\n\t\t\tcolorScheme: 'dark',\n\t\t\tdeviceScaleFactor: 1,\n\t\t\textraHTTPHeaders: {\n\t\t\t\t'X-Header': 'value',\n\t\t\t},\n\t\t\tgeolocation: { latitude: 51.509865, longitude: -0.118092, accuracy: 1 },\n\t\t\thasTouch: true,\n\t\t\thttpCredentials: { username: 'admin', password: 'password' },\n\t\t\tignoreHTTPSErrors: true,\n\t\t\tisMobile: true,\n\t\t\tjavaScriptEnabled: true,\n\t\t\tlocale: 'fr-FR',\n\t\t\toffline: true,\n\t\t\tpermissions: ['camera', 'microphone'],\n\t\t\treducedMotion: 'no-preference',\n\t\t\tscreen: { width: 800, height: 600 },\n\t\t\ttimezoneID: 'Europe/Paris',\n\t\t\tuserAgent: 'my agent',\n\t\t\tviewport: { width: 800, height: 600 },\n\t\t};\n\t\topts;\n\t`)\n\trequire.NoError(t, err)\n\n\tparsedOpts, err := parseBrowserContextOptions(vu.Runtime(), opts)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, &common.BrowserContextOptions{\n\t\tAcceptDownloads:   true,\n\t\tDownloadsPath:     \"/tmp\",\n\t\tBypassCSP:         true,\n\t\tColorScheme:       common.ColorSchemeDark,\n\t\tDeviceScaleFactor: 1,\n\t\tExtraHTTPHeaders: map[string]string{\n\t\t\t\"X-Header\": \"value\",\n\t\t},\n\t\tGeolocation: &common.Geolocation{\n\t\t\tLatitude:  51.509865,\n\t\t\tLongitude: -0.118092,\n\t\t\tAccuracy:  1,\n\t\t},\n\t\tHasTouch: true,\n\t\tHTTPCredentials: common.Credentials{\n\t\t\tUsername: \"admin\",\n\t\t\tPassword: \"password\",\n\t\t},\n\t\tIgnoreHTTPSErrors: true,\n\t\tIsMobile:          true,\n\t\tJavaScriptEnabled: true,\n\t\tLocale:            \"fr-FR\",\n\t\tOffline:           true,\n\t\tPermissions:       []string{\"camera\", \"microphone\"},\n\t\tReducedMotion:     common.ReducedMotionNoPreference,\n\t\tScreen: common.Screen{\n\t\t\tWidth:  800,\n\t\t\tHeight: 600,\n\t\t},\n\t\tTimezoneID: \"Europe/Paris\",\n\t\tUserAgent:  \"my agent\",\n\t\tViewport: common.Viewport{\n\t\t\tWidth:  800,\n\t\t\tHeight: 600,\n\t\t},\n\t}, parsedOpts)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/browser_mapping.go",
    "content": "package browser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// mapBrowser to the JS module.\n//\n//nolint:gocognit\nfunc mapBrowser(vu moduleVU) mapping {\n\treturn mapping{\n\t\t\"context\": func() (mapping, error) {\n\t\t\tb, err := vu.browser()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\treturn mapBrowserContext(vu, b.Context()), nil\n\t\t},\n\t\t\"closeContext\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tb, err := vu.browser()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn nil, b.CloseContext() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isConnected\": func() (bool, error) {\n\t\t\tb, err := vu.browser()\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\treturn b.IsConnected(), nil\n\t\t},\n\t\t\"newContext\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseBrowserContextOptions(vu.Runtime(), opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing browser.newContext options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tb, err := vu.browser()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tbctx, err := b.NewContext(popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif err := initBrowserContext(bctx, vu.testRunID); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\treturn mapBrowserContext(vu, bctx), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"userAgent\": func() (string, error) {\n\t\t\tb, err := vu.browser()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\treturn b.UserAgent(), nil\n\t\t},\n\t\t\"version\": func() (string, error) {\n\t\t\tb, err := vu.browser()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\treturn b.Version(), nil\n\t\t},\n\t\t\"newPage\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseBrowserContextOptions(vu.Runtime(), opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing browser.newPage options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tb, err := vu.browser()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tpage, err := b.NewPage(popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif err := initBrowserContext(b.Context(), vu.testRunID); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\treturn mapPage(vu, page), nil\n\t\t\t}), nil\n\t\t},\n\t}\n}\n\nfunc initBrowserContext(bctx *common.BrowserContext, testRunID string) error {\n\t// Setting a k6 object which will contain k6 specific metadata\n\t// on the current test run. This allows external applications\n\t// (such as Grafana Faro) to identify that the session is a k6\n\t// automated one and not one driven by a real person.\n\tif err := bctx.AddInitScript(\n\t\tfmt.Sprintf(`window.k6 = { testRunId: %q }`, testRunID),\n\t); err != nil {\n\t\treturn fmt.Errorf(\"adding k6 object to new browser context: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// parseBrowserContextOptions parses the [common.BrowserContext] options from a Sobek value.\nfunc parseBrowserContextOptions(rt *sobek.Runtime, opts sobek.Value) (*common.BrowserContextOptions, error) {\n\tb := common.DefaultBrowserContextOptions()\n\tif err := mergeWith(rt, b, opts); err != nil {\n\t\treturn nil, err\n\t}\n\treturn b, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/console_message_mapping.go",
    "content": "package browser\n\nimport (\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// mapConsoleMessage to the JS module.\nfunc mapConsoleMessage(vu moduleVU, event common.PageEvent) mapping {\n\tcm := event.ConsoleMessage\n\n\treturn mapping{\n\t\t\"args\": func() []mapping {\n\t\t\targs := cm.Args\n\t\t\tmargs := make([]mapping, 0, len(args))\n\t\t\tfor _, arg := range args {\n\t\t\t\ta := mapJSHandle(vu, arg)\n\t\t\t\tmargs = append(margs, a)\n\t\t\t}\n\n\t\t\treturn margs\n\t\t},\n\t\t// page(), text() and type() are defined as\n\t\t// functions in order to match Playwright's API\n\t\t\"page\": func() mapping {\n\t\t\treturn mapPage(vu, cm.Page)\n\t\t},\n\t\t\"text\": func() string {\n\t\t\treturn cm.Text\n\t\t},\n\t\t\"type\": func() string {\n\t\t\treturn cm.Type\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/element_handle_mapping.go",
    "content": "package browser\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\tmaps0 \"maps\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// mapElementHandle to the JS module.\nfunc mapElementHandle(vu moduleVU, eh *common.ElementHandle) mapping { //nolint:gocognit,funlen,cyclop\n\trt := vu.Runtime()\n\tmaps := mapping{\n\t\t\"boundingBox\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tbox, err := eh.BoundingBox()\n\t\t\t\t// We want to avoid errors when an element is not visible and instead\n\t\t\t\t// opt to return a nil rectangle -- this matches Playwright's behaviour.\n\t\t\t\tif errors.Is(err, common.ErrElementNotVisible) {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn box, err\n\t\t\t})\n\t\t},\n\t\t\"check\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleSetCheckedOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing check options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Check(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"click\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleClickOptions(eh.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element click options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\terr := eh.Click(popts)\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"contentFrame\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tf, err := eh.ContentFrame()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapFrame(vu, f), nil\n\t\t\t})\n\t\t},\n\t\t\"dblclick\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleDblclickOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element double click options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Dblclick(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"dispatchEvent\": func(typ string, eventInit sobek.Value) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.DispatchEvent(typ, exportArg(eventInit)) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"fill\": func(value string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleBaseOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element fill options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Fill(value, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"focus\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Focus() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"getAttribute\": func(name string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := eh.GetAttribute(name)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t})\n\t\t},\n\t\t\"hover\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleHoverOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element hover options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Hover(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"innerHTML\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.InnerHTML() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"innerText\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.InnerText() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"inputValue\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleBaseOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element input value options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.InputValue(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isChecked\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.IsChecked() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isDisabled\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.IsDisabled() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isEditable\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.IsEditable() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isEnabled\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.IsEnabled() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isHidden\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.IsHidden() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isVisible\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.IsVisible() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"ownerFrame\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tf, err := eh.OwnerFrame()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapFrame(vu, f), nil\n\t\t\t})\n\t\t},\n\t\t\"press\": func(key string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandlePressOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing press %q options: %w\", key, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Press(key, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"screenshot\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleScreenshotOptions(eh.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element handle screenshot options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tbb, err := eh.Screenshot(popts, vu.filePersister)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\n\t\t\t\tab := rt.NewArrayBuffer(bb)\n\n\t\t\t\treturn &ab, nil\n\t\t\t}), nil\n\t\t},\n\t\t\"scrollIntoViewIfNeeded\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleBaseOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing scrollIntoViewIfNeeded options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.ScrollIntoViewIfNeeded(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"selectOption\": func(values sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tconvValues, err := ConvertSelectOptionValues(vu.Runtime(), values)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing select options values: %w\", err)\n\t\t\t}\n\t\t\tpopts := common.NewElementHandleBaseOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing selectOption options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn eh.SelectOption(convValues, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"selectText\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleBaseOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing selectText options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.SelectText(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setChecked\": func(checked bool, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleSetCheckedOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setChecked options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.SetChecked(checked, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setInputFiles\": func(files sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleSetInputFilesOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles options: %w\", err)\n\t\t\t}\n\t\t\tvar pfiles common.Files\n\t\t\tif err := pfiles.Parse(vu.Context(), files); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles parameter: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.SetInputFiles(&pfiles, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"tap\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleTapOptions(eh.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element tap options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Tap(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"textContent\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := eh.TextContent()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t})\n\t\t},\n\t\t\"type\": func(text string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleTypeOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing type options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Type(text, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"uncheck\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleSetCheckedOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing uncheck options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.Uncheck(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForElementState\": func(state string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewElementHandleWaitForElementStateOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForElementState options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, eh.WaitForElementState(state, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForSelector\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameWaitForSelectorOptions(eh.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForSelector %q options: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\teh, err := eh.WaitForSelector(selector, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapElementHandle(vu, eh), nil\n\t\t\t}), nil\n\t\t},\n\t}\n\tmaps[\"$\"] = func(selector string) *sobek.Promise {\n\t\treturn promise(vu, func() (any, error) {\n\t\t\teh, err := eh.Query(selector, common.StrictModeOff)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t\t// ElementHandle can be null when the selector does not match any elements.\n\t\t\t// We do not want to map nil elementHandles since the expectation is a\n\t\t\t// null result in the test script for this case.\n\t\t\tif eh == nil {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\tehm := mapElementHandle(vu, eh)\n\n\t\t\treturn ehm, nil\n\t\t})\n\t}\n\tmaps[\"$$\"] = func(selector string) *sobek.Promise {\n\t\treturn promise(vu, func() (any, error) {\n\t\t\tehs, err := eh.QueryAll(selector)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t\tvar mehs []mapping\n\t\t\tfor _, eh := range ehs {\n\t\t\t\tehm := mapElementHandle(vu, eh)\n\t\t\t\tmehs = append(mehs, ehm)\n\t\t\t}\n\t\t\treturn mehs, nil\n\t\t})\n\t}\n\n\tjsHandleMap := mapJSHandle(vu, eh)\n\tmaps0.Copy(maps, jsHandleMap)\n\n\treturn maps\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/file_persister.go",
    "content": "package browser\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/storage\"\n)\n\ntype presignedURLConfig struct {\n\tgetterURL string\n\theaders   map[string]string\n\tbasePath  string\n}\n\n// newScreenshotPersister will return either a persister that persists file to the local\n// disk or uploads the files to a remote location. This decision depends on whether\n// the K6_BROWSER_SCREENSHOTS_OUTPUT env var is setup with the correct configs.\nfunc newScreenshotPersister(envLookup env.LookupFunc) (filePersister, error) {\n\tenvVar, ok := envLookup(env.ScreenshotsOutput)\n\tif !ok || envVar == \"\" {\n\t\treturn &storage.LocalFilePersister{}, nil\n\t}\n\n\tpopts, err := parsePresignedURLEnvVar(envVar)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing %s: %w\", env.ScreenshotsOutput, err)\n\t}\n\n\treturn storage.NewRemoteFilePersister(popts.getterURL, popts.headers, popts.basePath), nil\n}\n\n// parsePresignedURLEnvVar will parse a value such as:\n// url=https://127.0.0.1/,basePath=/screenshots,header.1=a,header.2=b\n// and return them.\n//\n\nfunc parsePresignedURLEnvVar(envVarValue string) (presignedURLConfig, error) {\n\tss := strings.Split(envVarValue, \",\")\n\n\tpresignedURL := presignedURLConfig{\n\t\theaders: make(map[string]string),\n\t}\n\tfor _, s := range ss {\n\t\t// The key value pair should be of the form key=value, so split\n\t\t// on '=' to retrieve the key and value separately.\n\t\tkv := strings.Split(s, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"format of value must be k=v, received %q\", s)\n\t\t}\n\n\t\tk := kv[0]\n\t\tv := kv[1]\n\n\t\t// A key with \"header.\" means that the header name is encoded in the\n\t\t// key, separated by a \".\". Split the header on \".\" to retrieve the\n\t\t// header name. The header value should be present in v from the previous\n\t\t// split.\n\t\tvar hv, hk string\n\t\tif strings.Contains(k, \"header.\") {\n\t\t\thv = v\n\n\t\t\thh := strings.Split(k, \".\")\n\t\t\tif len(hh) != 2 {\n\t\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"format of header must be header.k=v, received %q\", s)\n\t\t\t}\n\n\t\t\tk = hh[0]\n\t\t\thk = hh[1]\n\n\t\t\tif hk == \"\" {\n\t\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"empty header key, received %q\", s)\n\t\t\t}\n\t\t}\n\n\t\tswitch k {\n\t\tcase \"url\":\n\t\t\tu, err := url.ParseRequestURI(v)\n\t\t\tif err != nil && u.Scheme != \"\" && u.Host != \"\" {\n\t\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"invalid url %q\", s)\n\t\t\t}\n\t\t\tpresignedURL.getterURL = v\n\t\tcase \"basePath\":\n\t\t\tpresignedURL.basePath = v\n\t\tcase \"header\":\n\t\t\tpresignedURL.headers[hk] = hv\n\t\tdefault:\n\t\t\treturn presignedURLConfig{}, fmt.Errorf(\"invalid option %q\", k)\n\t\t}\n\t}\n\n\tif presignedURL.getterURL == \"\" {\n\t\treturn presignedURLConfig{}, errors.New(\"missing required url\")\n\t}\n\n\treturn presignedURL, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/file_persister_test.go",
    "content": "package browser\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/storage\"\n)\n\nfunc Test_newScreenshotPersister(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname      string\n\t\tenvLookup env.LookupFunc\n\t\twantType  filePersister\n\t\twantErr   bool\n\t}{\n\t\t{\n\t\t\tname:      \"local_no_env_var\",\n\t\t\tenvLookup: env.EmptyLookup,\n\t\t\twantType:  &storage.LocalFilePersister{},\n\t\t},\n\t\t{\n\t\t\tname: \"local_empty_env_var\",\n\t\t\tenvLookup: env.ConstLookup(\n\t\t\t\tenv.ScreenshotsOutput,\n\t\t\t\t\"\",\n\t\t\t),\n\t\t\twantType: &storage.LocalFilePersister{},\n\t\t},\n\t\t{\n\t\t\tname: \"remote\",\n\t\t\tenvLookup: env.ConstLookup(\n\t\t\t\tenv.ScreenshotsOutput,\n\t\t\t\t\"url=https://127.0.0.1/,basePath=/screenshots,header.1=a\",\n\t\t\t),\n\t\t\twantType: &storage.RemoteFilePersister{},\n\t\t},\n\t\t{\n\t\t\tname: \"remote_parse_failed\",\n\t\t\tenvLookup: env.ConstLookup(\n\t\t\t\tenv.ScreenshotsOutput,\n\t\t\t\t\"basePath=/screenshots,header.1=a\",\n\t\t\t),\n\t\t\twantErr: true,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotType, err := newScreenshotPersister(tt.envLookup)\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.IsType(t, tt.wantType, gotType)\n\t\t})\n\t}\n}\n\nfunc Test_parsePresignedURLEnvVar(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname        string\n\t\tenvVarValue string\n\t\twant        presignedURLConfig\n\t\twantErr     string\n\t}{\n\t\t{\n\t\t\tname:        \"url_headers_basePath\",\n\t\t\tenvVarValue: \"url=https://127.0.0.1/,basePath=/screenshots,header.1=a,header.2=b\",\n\t\t\twant: presignedURLConfig{\n\t\t\t\tgetterURL: \"https://127.0.0.1/\",\n\t\t\t\tbasePath:  \"/screenshots\",\n\t\t\t\theaders: map[string]string{\n\t\t\t\t\t\"1\": \"a\",\n\t\t\t\t\t\"2\": \"b\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"url_headers\",\n\t\t\tenvVarValue: \"url=https://127.0.0.1/,header.1=a,header.2=b\",\n\t\t\twant: presignedURLConfig{\n\t\t\t\tgetterURL: \"https://127.0.0.1/\",\n\t\t\t\theaders: map[string]string{\n\t\t\t\t\t\"1\": \"a\",\n\t\t\t\t\t\"2\": \"b\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"url\",\n\t\t\tenvVarValue: \"url=https://127.0.0.1/\",\n\t\t\twant: presignedURLConfig{\n\t\t\t\tgetterURL: \"https://127.0.0.1/\",\n\t\t\t\theaders:   map[string]string{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"url_basePath\",\n\t\t\tenvVarValue: \"url=https://127.0.0.1/,basePath=/screenshots\",\n\t\t\twant: presignedURLConfig{\n\t\t\t\tgetterURL: \"https://127.0.0.1/\",\n\t\t\t\tbasePath:  \"/screenshots\",\n\t\t\t\theaders:   map[string]string{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"empty_basePath\",\n\t\t\tenvVarValue: \"url=https://127.0.0.1/,basePath=\",\n\t\t\twant: presignedURLConfig{\n\t\t\t\tgetterURL: \"https://127.0.0.1/\",\n\t\t\t\tbasePath:  \"\",\n\t\t\t\theaders:   map[string]string{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"empty\",\n\t\t\tenvVarValue: \"\",\n\t\t\twantErr:     `format of value must be k=v, received \"\"`,\n\t\t},\n\t\t{\n\t\t\tname:        \"missing_url\",\n\t\t\tenvVarValue: \"basePath=/screenshots,header.1=a,header.2=b\",\n\t\t\twantErr:     \"missing required url\",\n\t\t},\n\t\t{\n\t\t\tname:        \"invalid_option\",\n\t\t\tenvVarValue: \"ulr=https://127.0.0.1/\",\n\t\t\twantErr:     \"invalid option\",\n\t\t},\n\t\t{\n\t\t\tname:        \"empty_header_key\",\n\t\t\tenvVarValue: \"url=https://127.0.0.1/,header.=a\",\n\t\t\twantErr:     \"empty header key\",\n\t\t},\n\t\t{\n\t\t\tname:        \"invalid_format\",\n\t\t\tenvVarValue: \"url==https://127.0.0.1/\",\n\t\t\twantErr:     \"format of value must be k=v\",\n\t\t},\n\t\t{\n\t\t\tname:        \"invalid_header_format\",\n\t\t\tenvVarValue: \"url=https://127.0.0.1/,header..asd=a\",\n\t\t\twantErr:     \"format of header must be header.k=v\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot, err := parsePresignedURLEnvVar(tt.envVarValue)\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, got)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/frame_locator_mapping.go",
    "content": "package browser\n\nimport (\n\t\"errors\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// mapFrameLocator API to the JS module.\nfunc mapFrameLocator(vu moduleVU, fl *common.FrameLocator) mapping {\n\trt := vu.Runtime()\n\treturn mapping{\n\t\t\"getByAltText\": func(alt sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(alt) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'altText'\")\n\t\t\t}\n\t\t\tpalt, popts := parseGetByBaseOptions(vu.Context(), alt, false, opts)\n\n\t\t\tml := mapLocator(vu, fl.GetByAltText(palt, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByLabel\": func(label sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(label) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'label'\")\n\t\t\t}\n\t\t\tplabel, popts := parseGetByBaseOptions(vu.Context(), label, true, opts)\n\n\t\t\tml := mapLocator(vu, fl.GetByLabel(plabel, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByPlaceholder\": func(placeholder sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(placeholder) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'placeholder'\")\n\t\t\t}\n\t\t\tpplaceholder, popts := parseGetByBaseOptions(vu.Context(), placeholder, false, opts)\n\n\t\t\tml := mapLocator(vu, fl.GetByPlaceholder(pplaceholder, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByRole\": func(role sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(role) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'role'\")\n\t\t\t}\n\t\t\tpopts := parseGetByRoleOptions(vu.Context(), opts)\n\n\t\t\tml := mapLocator(vu, fl.GetByRole(role.String(), popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTestId\": func(testID sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(testID) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'testId'\")\n\t\t\t}\n\t\t\tptestID := parseStringOrRegex(testID, false)\n\n\t\t\tml := mapLocator(vu, fl.GetByTestID(ptestID))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByText\": func(text sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(text) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'text'\")\n\t\t\t}\n\t\t\tptext, popts := parseGetByBaseOptions(vu.Context(), text, true, opts)\n\n\t\t\tml := mapLocator(vu, fl.GetByText(ptext, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTitle\": func(title sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(title) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'title'\")\n\t\t\t}\n\t\t\tptitle, popts := parseGetByBaseOptions(vu.Context(), title, false, opts)\n\n\t\t\tml := mapLocator(vu, fl.GetByTitle(ptitle, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"locator\": func(selector string, opts sobek.Value) mapping {\n\t\t\treturn mapLocator(vu, fl.Locator(selector, parseLocatorOptions(rt, opts)))\n\t\t},\n\t\t\"frameLocator\": func(selector string) *sobek.Object {\n\t\t\tmfl := mapFrameLocator(vu, fl.FrameLocator(selector))\n\t\t\treturn rt.ToValue(mfl).ToObject(rt)\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/frame_mapping.go",
    "content": "package browser\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// mapFrame to the JS module.\n//\n//nolint:funlen,gocognit,cyclop\nfunc mapFrame(vu moduleVU, f *common.Frame) mapping {\n\trt := vu.Runtime()\n\tmaps := mapping{\n\t\t\"check\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameCheckOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing new frame check options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Check(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"childFrames\": func() []mapping {\n\t\t\tcfs := f.ChildFrames()\n\t\t\tmcfs := make([]mapping, 0, len(cfs))\n\t\t\tfor _, fr := range cfs {\n\t\t\t\tmcfs = append(mcfs, mapFrame(vu, fr))\n\t\t\t}\n\t\t\treturn mcfs\n\t\t},\n\t\t\"click\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseFrameClickOptions(vu.Context(), opts, f.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\terr := f.Click(selector, popts)\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"content\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.Content() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"dblclick\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameDblClickOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing double click options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Dblclick(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"dispatchEvent\": func(selector, typ string, eventInit, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameDispatchEventOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing frame dispatch event options: %w\", err)\n\t\t\t}\n\t\t\tearg := exportArg(eventInit)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.DispatchEvent(selector, typ, earg, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"evaluate\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluate requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.Evaluate(funcString, gopts...)\n\t\t\t}), nil\n\t\t},\n\t\t\"evaluateHandle\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluateHandle requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tjsh, err := f.EvaluateHandle(funcString, gopts...)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapJSHandle(vu, jsh), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"fill\": func(selector, value string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameFillOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing fill options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Fill(selector, value, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"focus\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameBaseOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing focus options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Focus(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"frameElement\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tfe, err := f.FrameElement()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapElementHandle(vu, fe), nil\n\t\t\t})\n\t\t},\n\t\t\"getAttribute\": func(selector, name string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameBaseOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing getAttribute options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := f.GetAttribute(selector, name, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t}), nil\n\t\t},\n\t\t\"getByAltText\": func(alt sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(alt) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'altText'\")\n\t\t\t}\n\t\t\tpalt, popts := parseGetByBaseOptions(vu.Context(), alt, false, opts)\n\n\t\t\tml := mapLocator(vu, f.GetByAltText(palt, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByLabel\": func(label sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(label) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'label'\")\n\t\t\t}\n\t\t\tplabel, popts := parseGetByBaseOptions(vu.Context(), label, true, opts)\n\n\t\t\tml := mapLocator(vu, f.GetByLabel(plabel, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByPlaceholder\": func(placeholder sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(placeholder) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'placeholder'\")\n\t\t\t}\n\t\t\tpplaceholder, popts := parseGetByBaseOptions(vu.Context(), placeholder, false, opts)\n\n\t\t\tml := mapLocator(vu, f.GetByPlaceholder(pplaceholder, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByRole\": func(role sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(role) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'role'\")\n\t\t\t}\n\t\t\tpopts := parseGetByRoleOptions(vu.Context(), opts)\n\n\t\t\tml := mapLocator(vu, f.GetByRole(role.String(), popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTestId\": func(testID sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(testID) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'testId'\")\n\t\t\t}\n\t\t\tptestID := parseStringOrRegex(testID, false)\n\n\t\t\tml := mapLocator(vu, f.GetByTestID(ptestID))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByText\": func(text sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(text) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'text'\")\n\t\t\t}\n\t\t\tptext, popts := parseGetByBaseOptions(vu.Context(), text, true, opts)\n\n\t\t\tml := mapLocator(vu, f.GetByText(ptext, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTitle\": func(title sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(title) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'title'\")\n\t\t\t}\n\t\t\tptitle, popts := parseGetByBaseOptions(vu.Context(), title, false, opts)\n\n\t\t\tml := mapLocator(vu, f.GetByTitle(ptitle, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"goto\": func(url string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tgopts := common.NewFrameGotoOptions(\n\t\t\t\tf.Referrer(),\n\t\t\t\tf.NavigationTimeout(),\n\t\t\t)\n\t\t\tif err := gopts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing frame navigation options to %q: %w\", url, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tresp, err := f.Goto(url, gopts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\n\t\t\t\treturn mapResponse(vu, resp), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"hover\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameHoverOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing hover options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Hover(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"innerHTML\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameInnerHTMLOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing inner HTML options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.InnerHTML(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"innerText\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameInnerTextOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing inner text options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.InnerText(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"inputValue\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameInputValueOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing input value options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.InputValue(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isChecked\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsCheckedOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing isChecked options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.IsChecked(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isDetached\": f.IsDetached,\n\t\t\"isDisabled\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsDisabledOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing isDisabled options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.IsDisabled(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isEditable\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsEditableOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isEditable options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.IsEditable(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isEnabled\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsEnabledOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isEnabled options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.IsEnabled(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isHidden\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsHiddenOptions()\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isHidden options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.IsHidden(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isVisible\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsVisibleOptions()\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isVisible options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.IsVisible(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"locator\": func(selector string, opts sobek.Value) mapping {\n\t\t\treturn mapLocator(vu, f.Locator(selector, parseLocatorOptions(rt, opts)))\n\t\t},\n\t\t\"frameLocator\": func(selector string) *sobek.Object {\n\t\t\tmfl := mapFrameLocator(vu, f.FrameLocator(selector))\n\t\t\treturn rt.ToValue(mfl).ToObject(rt)\n\t\t},\n\t\t\"name\": f.Name,\n\t\t\"page\": func() mapping {\n\t\t\treturn mapPage(vu, f.Page())\n\t\t},\n\t\t\"parentFrame\": func() mapping {\n\t\t\treturn mapFrame(vu, f.ParentFrame())\n\t\t},\n\t\t\"press\": func(selector, key string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFramePressOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse press options of selector %q on key %q: %w\", selector, key, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Press(selector, key, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"selectOption\": func(selector string, values sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameSelectOptionOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing select option options: %w\", err)\n\t\t\t}\n\n\t\t\tconvValues, err := ConvertSelectOptionValues(rt, values)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing select options values: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.SelectOption(selector, convValues, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setChecked\": func(selector string, checked bool, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameCheckOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing frame set check options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.SetChecked(selector, checked, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setContent\": func(html string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameSetContentOptions(f.Page().NavigationTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setContent options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.SetContent(html, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setInputFiles\": func(selector string, files sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameSetInputFilesOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles options: %w\", err)\n\t\t\t}\n\n\t\t\tpfiles := new(common.Files)\n\t\t\tif err := pfiles.Parse(vu.Context(), files); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles parameter: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.SetInputFiles(selector, pfiles, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"tap\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameTapOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing frame tap options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Tap(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"textContent\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameTextContentOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing text content options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := f.TextContent(selector, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t}), nil\n\t\t},\n\t\t\"title\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn f.Title()\n\t\t\t})\n\t\t},\n\t\t\"type\": func(selector, text string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameTypeOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing type options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Type(selector, text, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"uncheck\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameUncheckOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing frame uncheck options %q: %w\", selector, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.Uncheck(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"url\": f.URL,\n\t\t\"waitForFunction\": func(pageFunc, opts sobek.Value, args ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tjs, popts, pargs, err := parseWaitForFunctionArgs(\n\t\t\t\tvu.Context(), f.Timeout(), pageFunc, opts, args...,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"frame waitForFunction: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (result any, reason error) {\n\t\t\t\treturn f.WaitForFunction(js, popts, pargs...) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForLoadState\": func(state string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameWaitForLoadStateOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForLoadState %q options: %w\", state, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, f.WaitForLoadState(state, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForNavigation\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\treturn mapWaitForNavigation(vu, f, opts)\n\t\t},\n\t\t\"waitForSelector\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameWaitForSelectorOptions(f.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing wait for selector %q options: %w\", selector, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\teh, err := f.WaitForSelector(selector, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapElementHandle(vu, eh), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForTimeout\": func(timeout int64) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tf.WaitForTimeout(timeout)\n\t\t\t\treturn nil, nil\n\t\t\t})\n\t\t},\n\t\t\"waitForURL\": func(url sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\treturn mapWaitForURL(vu, f, url, opts)\n\t\t},\n\t}\n\tmaps[\"$\"] = func(selector string) *sobek.Promise {\n\t\treturn promise(vu, func() (any, error) {\n\t\t\teh, err := f.Query(selector, common.StrictModeOff)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t\t// ElementHandle can be null when the selector does not match any elements.\n\t\t\t// We do not want to map nil elementHandles since the expectation is a\n\t\t\t// null result in the test script for this case.\n\t\t\tif eh == nil {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\tehm := mapElementHandle(vu, eh)\n\n\t\t\treturn ehm, nil\n\t\t})\n\t}\n\tmaps[\"$$\"] = func(selector string) *sobek.Promise {\n\t\treturn promise(vu, func() (any, error) {\n\t\t\tehs, err := f.QueryAll(selector)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t\tvar mehs []mapping\n\t\t\tfor _, eh := range ehs {\n\t\t\t\tehm := mapElementHandle(vu, eh)\n\t\t\t\tmehs = append(mehs, ehm)\n\t\t\t}\n\t\t\treturn mehs, nil\n\t\t})\n\t}\n\n\treturn maps\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/helpers.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/mstoykov/k6-taskqueue-lib/taskqueue\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6error\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\tk6common \"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/promises\"\n)\n\nfunc panicIfFatalError(ctx context.Context, err error) {\n\tif errors.Is(err, k6error.ErrFatal) {\n\t\tk6ext.Abortf(ctx, err.Error())\n\t}\n}\n\n// mergeWith merges the Sobek value with the existing Go value.\nfunc mergeWith[T any](rt *sobek.Runtime, src T, v sobek.Value) error {\n\tif k6common.IsNullish(v) {\n\t\treturn nil\n\t}\n\treturn rt.ExportTo(v, &src) //nolint:wrapcheck\n}\n\n// exportTo exports the Sobek value to a Go value.\n// It returns the zero value of T if obj does not exist in the Sobek runtime.\n// It's caller's responsibility to check for nilness.\nfunc exportTo[T any](rt *sobek.Runtime, obj sobek.Value) (T, error) {\n\tvar t T\n\tif k6common.IsNullish(obj) {\n\t\treturn t, nil\n\t}\n\terr := rt.ExportTo(obj, &t)\n\treturn t, err //nolint:wrapcheck\n}\n\n// exportArg exports the value and returns it.\n// It returns nil if the value is undefined or null.\nfunc exportArg(gv sobek.Value) any {\n\tif k6common.IsNullish(gv) {\n\t\treturn nil\n\t}\n\treturn gv.Export()\n}\n\n// exportArgs returns a slice of exported sobek values.\nfunc exportArgs(gargs []sobek.Value) []any {\n\targs := make([]any, 0, len(gargs))\n\tfor _, garg := range gargs {\n\t\t// leaves a nil garg in the array since users might want to\n\t\t// pass undefined or null as an argument to a function\n\t\targs = append(args, exportArg(garg))\n\t}\n\treturn args\n}\n\n// sobekEmptyString returns true if a given value is not nil or an empty string.\nfunc sobekEmptyString(v sobek.Value) bool {\n\treturn k6common.IsNullish(v) || strings.TrimSpace(v.String()) == \"\"\n}\n\n// newRegExMatcher returns a function that runs in the JS runtime's event loop\n// for pattern matching. It uses ECMAScript RegEx engine for consistency.\n//\n// It's safe to call this function off of the event loop since the returned\n// function gets run in the task queue, ensuring it runs on the event loop.\nfunc newRegExMatcher(ctx context.Context, vu moduleVU, tq *taskqueue.TaskQueue) common.RegExMatcher {\n\treturn func(pattern, str string) (bool, error) {\n\t\treturn queueTask(ctx, tq, func() (bool, error) {\n\t\t\tv, err := vu.Runtime().RunString(pattern + `.test('` + str + `')`)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"evaluating pattern: %w\", err)\n\t\t\t}\n\t\t\treturn v.ToBoolean(), nil\n\t\t})()\n\t}\n}\n\n// promise runs fn in a goroutine and returns a new sobek.Promise.\n//   - If fn returns a nil error, resolves the promise with the\n//     first result value fn returns.\n//   - Otherwise, rejects the promise with the error fn returns.\nfunc promise(vu moduleVU, fn func() (result any, reason error)) *sobek.Promise {\n\tp, resolve, reject := promises.New(vu)\n\tgo func() {\n\t\tv, err := fn()\n\t\tif err != nil {\n\t\t\treject(err)\n\t\t\treturn\n\t\t}\n\t\tresolve(v)\n\t}()\n\treturn p\n}\n\n// queueTask queues the given function fn to run on the given task queue tq.\n// The returned future blocks until the task is done and returns the result\n// of fn or an error if the context is done before fn completes. It's safe\n// not to call the future if you're not interested in the result of fn.\nfunc queueTask[T any](\n\tctx context.Context,\n\ttq *taskqueue.TaskQueue,\n\tfn func() (T, error),\n) (future func() (T, error)) {\n\tvar (\n\t\tresult T\n\t\terr    error\n\t\tdone   = make(chan struct{})\n\t)\n\ttq.Queue(func() error {\n\t\tdefer close(done)\n\t\tresult, err = fn()\n\t\treturn err\n\t})\n\treturn func() (T, error) {\n\t\tselect {\n\t\tcase <-done:\n\t\t\treturn result, err\n\t\tcase <-ctx.Done():\n\t\t\tvar zero T\n\t\t\treturn zero, fmt.Errorf(\"running on task queue: %w\", common.ContextErr(ctx))\n\t\t}\n\t}\n}\n\n// newTaskQueue returns a new [taskqueue.TaskQueue] that is closed after\n// the returned cancel function is called or when the VU's context is done.\n//\n// Do not call this function off of the event loop.\nfunc newTaskQueue(vu moduleVU) (*taskqueue.TaskQueue, context.Context, context.CancelFunc) {\n\tctx, cancel := context.WithCancel(vu.Context())\n\ttq := taskqueue.New(vu.RegisterCallback)\n\tgo func() {\n\t\t<-ctx.Done()\n\t\ttq.Close()\n\t}()\n\treturn tq, ctx, cancel\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/helpers_test.go",
    "content": "package browser\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSobekEmptyString(t *testing.T) {\n\tt.Parallel()\n\t// SobekEmpty string should return true if the argument\n\t// is an empty string or not defined in the Sobek runtime.\n\trt := sobek.New()\n\trequire.NoError(t, rt.Set(\"sobekEmptyString\", sobekEmptyString))\n\tfor _, s := range []string{\"() => true\", \"'() => false'\"} { // not empty\n\t\tv, err := rt.RunString(`sobekEmptyString(` + s + `)`)\n\t\trequire.NoError(t, err)\n\t\trequire.Falsef(t, v.ToBoolean(), \"got: true, want: false for %q\", s)\n\t}\n\tfor _, s := range []string{\"\", \"  \", \"null\", \"undefined\"} { // empty\n\t\tv, err := rt.RunString(`sobekEmptyString(` + s + `)`)\n\t\trequire.NoError(t, err)\n\t\trequire.Truef(t, v.ToBoolean(), \"got: false, want: true for %q\", s)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/js_handle_mapping.go",
    "content": "package browser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// mapJSHandle to the JS module.\nfunc mapJSHandle(vu moduleVU, jsh common.JSHandleAPI) mapping {\n\treturn mapping{\n\t\t\"asElement\": func() mapping {\n\t\t\treturn mapElementHandle(vu, jsh.AsElement())\n\t\t},\n\t\t\"dispose\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, jsh.Dispose()\n\t\t\t})\n\t\t},\n\t\t\"evaluate\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluate requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn jsh.Evaluate(funcString, gopts...)\n\t\t\t}), nil\n\t\t},\n\t\t\"evaluateHandle\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluateHandle requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\th, err := jsh.EvaluateHandle(funcString, gopts...)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapJSHandle(vu, h), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"getProperties\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tprops, err := jsh.GetProperties()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\n\t\t\t\tdst := make(map[string]any)\n\t\t\t\tfor k, v := range props {\n\t\t\t\t\tdst[k] = mapJSHandle(vu, v)\n\t\t\t\t}\n\t\t\t\treturn dst, nil\n\t\t\t})\n\t\t},\n\t\t\"jsonValue\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn jsh.JSONValue() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/keyboard_mapping.go",
    "content": "package browser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc mapKeyboard(vu moduleVU, kb *common.Keyboard) mapping {\n\treturn mapping{\n\t\t\"down\": func(key string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, kb.Down(key) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"up\": func(key string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, kb.Up(key) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"press\": func(key string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tkbopts, err := exportTo[common.KeyboardOptions](vu.Runtime(), opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing keyboard options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, kb.Press(key, kbopts)\n\t\t\t}), nil\n\t\t},\n\t\t\"type\": func(text string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tkbopts, err := exportTo[common.KeyboardOptions](vu.Runtime(), opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing keyboard options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, kb.Type(text, kbopts)\n\t\t\t}), nil\n\t\t},\n\t\t\"insertText\": func(text string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, kb.InsertText(text) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/locator_mapping.go",
    "content": "package browser\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// mapLocator API to the JS module.\n//\n//nolint:gocognit,funlen,cyclop\nfunc mapLocator(vu moduleVU, lo *common.Locator) mapping {\n\trt := vu.Runtime()\n\treturn mapping{\n\t\t\"all\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tall, err := lo.All()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tres := make([]mapping, len(all))\n\t\t\t\tfor i, el := range all {\n\t\t\t\t\tres[i] = mapLocator(vu, el)\n\t\t\t\t}\n\t\t\t\treturn res, nil\n\t\t\t})\n\t\t},\n\t\t\"boundingBox\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameBaseOptions(lo.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing locator bounding box options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tbox, err := lo.BoundingBox(popts)\n\t\t\t\t// We want to avoid errors when an element is not visible and instead\n\t\t\t\t// opt to return a nil rectangle -- this matches Playwright's behaviour.\n\t\t\t\tif errors.Is(err, common.ErrElementNotVisible) {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn box, err\n\t\t\t}), nil\n\t\t},\n\t\t\"clear\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameFillOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing clear options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Clear(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"click\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseFrameClickOptions(vu.Context(), opts, lo.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Click(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"contentFrame\": func() *sobek.Object {\n\t\t\tml := mapFrameLocator(vu, lo.ContentFrame())\n\t\t\treturn rt.ToValue(ml).ToObject(rt)\n\t\t},\n\t\t\"count\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.Count() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"dblclick\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameDblClickOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing double click options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Dblclick(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"evaluate\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluate requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.Evaluate(funcString, gopts...)\n\t\t\t}), nil\n\t\t},\n\t\t\"evaluateHandle\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluateHandle requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tjsh, err := lo.EvaluateHandle(funcString, gopts...)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapJSHandle(vu, jsh), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"setChecked\": func(checked bool, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameCheckOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing set checked options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.SetChecked(checked, copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"check\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameCheckOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing check options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Check(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"uncheck\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameUncheckOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing uncheck options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Uncheck(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isChecked\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameIsCheckedOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing is checked options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.IsChecked(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isEditable\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameIsEditableOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing is editable options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.IsEditable(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isEnabled\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameIsEnabledOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing is enabled options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.IsEnabled(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isDisabled\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameIsDisabledOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing is disabled options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.IsDisabled(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isVisible\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.IsVisible() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isHidden\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.IsHidden() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"fill\": func(value string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameFillOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing fill options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Fill(value, copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"filter\": func(opts sobek.Value) mapping {\n\t\t\treturn mapLocator(vu, lo.Filter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: parseLocatorOptions(rt, opts),\n\t\t\t}))\n\t\t},\n\t\t\"first\": func() *sobek.Object {\n\t\t\tml := mapLocator(vu, lo.First())\n\t\t\treturn rt.ToValue(ml).ToObject(rt)\n\t\t},\n\t\t\"focus\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameBaseOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing focus options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Focus(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"getAttribute\": func(name string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameBaseOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing get attribute options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := lo.GetAttribute(name, copts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t}), nil\n\t\t},\n\t\t\"getByAltText\": func(alt sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(alt) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'altText'\")\n\t\t\t}\n\t\t\tpalt, popts := parseGetByBaseOptions(vu.Context(), alt, false, opts)\n\n\t\t\tml := mapLocator(vu, lo.GetByAltText(palt, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByLabel\": func(label sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(label) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'label'\")\n\t\t\t}\n\t\t\tplabel, popts := parseGetByBaseOptions(vu.Context(), label, true, opts)\n\n\t\t\tml := mapLocator(vu, lo.GetByLabel(plabel, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByPlaceholder\": func(placeholder sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(placeholder) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'placeholder'\")\n\t\t\t}\n\t\t\tpplaceholder, popts := parseGetByBaseOptions(vu.Context(), placeholder, false, opts)\n\n\t\t\tml := mapLocator(vu, lo.GetByPlaceholder(pplaceholder, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByRole\": func(role sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(role) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'role'\")\n\t\t\t}\n\t\t\tpopts := parseGetByRoleOptions(vu.Context(), opts)\n\n\t\t\tml := mapLocator(vu, lo.GetByRole(role.String(), popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTestId\": func(testID sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(testID) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'testId'\")\n\t\t\t}\n\t\t\tptestID := parseStringOrRegex(testID, false)\n\n\t\t\tml := mapLocator(vu, lo.GetByTestID(ptestID))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByText\": func(text sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(text) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'text'\")\n\t\t\t}\n\t\t\tptext, popts := parseGetByBaseOptions(vu.Context(), text, true, opts)\n\n\t\t\tml := mapLocator(vu, lo.GetByText(ptext, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTitle\": func(title sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(title) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'title'\")\n\t\t\t}\n\t\t\tptitle, popts := parseGetByBaseOptions(vu.Context(), title, false, opts)\n\n\t\t\tml := mapLocator(vu, lo.GetByTitle(ptitle, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"locator\": func(selector string, opts sobek.Value) mapping {\n\t\t\treturn mapLocator(vu, lo.Locator(selector, parseLocatorOptions(rt, opts)))\n\t\t},\n\t\t\"frameLocator\": func(selector string) *sobek.Object {\n\t\t\tmfl := mapFrameLocator(vu, lo.FrameLocator(selector))\n\t\t\treturn rt.ToValue(mfl).ToObject(rt)\n\t\t},\n\t\t\"innerHTML\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameInnerHTMLOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing inner HTML options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.InnerHTML(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"innerText\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameInnerTextOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing inner text options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.InnerText(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"last\": func() *sobek.Object {\n\t\t\tml := mapLocator(vu, lo.Last())\n\t\t\treturn rt.ToValue(ml).ToObject(rt)\n\t\t},\n\t\t\"nth\": func(nth int) *sobek.Object {\n\t\t\tml := mapLocator(vu, lo.Nth(nth))\n\t\t\treturn rt.ToValue(ml).ToObject(rt)\n\t\t},\n\t\t\"textContent\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameTextContentOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing text content options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := lo.TextContent(copts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t}), nil\n\t\t},\n\t\t\"inputValue\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameInputValueOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing input value options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.InputValue(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"selectOption\": func(values sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameSelectOptionOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing select option options: %w\", err)\n\t\t\t}\n\t\t\tconvValues, err := ConvertSelectOptionValues(vu.Runtime(), values)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing select option values: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn lo.SelectOption(convValues, copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"press\": func(key string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFramePressOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing press options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Press(key, copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\n\t\t\"pressSequentially\": func(text string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameTypeOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing locator press sequentially options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.PressSequentially(text, copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\n\t\t\"type\": func(text string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameTypeOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing type options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Type(text, copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"hover\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameHoverOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing hover options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Hover(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"tap\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameTapOptions(lo.DefaultTimeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing locator tap options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.Tap(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"dispatchEvent\": func(typ string, eventInit, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameDispatchEventOptions(lo.DefaultTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing locator dispatch event options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.DispatchEvent(typ, exportArg(eventInit), popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitFor\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tcopts := common.NewFrameWaitForSelectorOptions(lo.Timeout())\n\t\t\tif err := copts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing wait for options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, lo.WaitFor(copts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t}\n}\n\nfunc parseLocatorOptions(rt *sobek.Runtime, opts sobek.Value) *common.LocatorOptions {\n\tif k6common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\tvar popts common.LocatorOptions\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"hasText\":\n\t\t\tpopts.HasText = obj.Get(k).String()\n\t\tcase \"hasNotText\":\n\t\t\tpopts.HasNotText = obj.Get(k).String()\n\t\t}\n\t}\n\n\treturn &popts\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/mapping.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// mapping is a type for mapping our module API to sobek.\n// It acts like a bridge and allows adding wildcard methods\n// and customization over our API.\ntype mapping = map[string]any\n\n// mapBrowserToSobek maps the browser API to the JS module.\n// The motivation of this mapping was to support $ and $$ wildcard\n// methods.\n// See issue #661 for more details.\nfunc mapBrowserToSobek(vu moduleVU) *sobek.Object {\n\tvar (\n\t\trt  = vu.Runtime()\n\t\tobj = rt.NewObject()\n\t)\n\tfor k, v := range mapBrowser(vu) {\n\t\terr := obj.Set(k, rt.ToValue(v))\n\t\tif err != nil {\n\t\t\tk6common.Throw(rt, fmt.Errorf(\"mapping: %w\", err))\n\t\t}\n\t}\n\n\treturn obj\n}\n\nfunc parseFrameClickOptions(\n\tctx context.Context, opts sobek.Value, defaultTimeout time.Duration,\n) (*common.FrameClickOptions, error) {\n\tcopts := common.NewFrameClickOptions(defaultTimeout)\n\tif err := copts.Parse(ctx, opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing click options: %w\", err)\n\t}\n\treturn copts, nil\n}\n\nfunc ConvertSelectOptionValues(rt *sobek.Runtime, values sobek.Value) ([]any, error) {\n\tif k6common.IsNullish(values) {\n\t\treturn nil, nil\n\t}\n\n\tvar (\n\t\topts []any\n\t\tt    = values.Export()\n\t)\n\tswitch values.ExportType().Kind() {\n\tcase reflect.Slice:\n\t\tvar sl []any\n\t\tif err := rt.ExportTo(values, &sl); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"options: expected array, got %T\", values)\n\t\t}\n\n\t\tfor _, item := range sl {\n\t\t\tswitch item := item.(type) {\n\t\t\tcase string:\n\t\t\t\t// Strings will match values or labels\n\t\t\t\tvalOpt := common.SelectOption{Value: new(string)}\n\t\t\t\t*valOpt.Value = item\n\t\t\t\tlabelOpt := common.SelectOption{Label: new(string)}\n\t\t\t\t*labelOpt.Label = item\n\t\t\t\topts = append(opts, &valOpt, &labelOpt)\n\t\t\tcase map[string]any:\n\t\t\t\topt, err := extractSelectOptionFromMap(item)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\topts = append(opts, opt)\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"options: expected string or object, got %T\", item)\n\t\t\t}\n\t\t}\n\tcase reflect.Map:\n\t\tvar raw map[string]any\n\t\tif err := rt.ExportTo(values, &raw); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"options: expected object, got %T\", values)\n\t\t}\n\n\t\topt, err := extractSelectOptionFromMap(raw)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\topts = append(opts, opt)\n\tcase reflect.TypeFor[*common.ElementHandle]().Kind():\n\t\topts = append(opts, t.(*common.ElementHandle)) //nolint:forcetypeassert\n\tcase reflect.TypeFor[sobek.Object]().Kind():\n\t\tobj := values.ToObject(rt)\n\t\topt := common.SelectOption{}\n\t\tfor _, k := range obj.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"value\":\n\t\t\t\topt.Value = new(string)\n\t\t\t\t*opt.Value = obj.Get(k).String()\n\t\t\tcase \"label\":\n\t\t\t\topt.Label = new(string)\n\t\t\t\t*opt.Label = obj.Get(k).String()\n\t\t\tcase \"index\":\n\t\t\t\topt.Index = new(int64)\n\t\t\t\t*opt.Index = obj.Get(k).ToInteger()\n\t\t\t}\n\t\t}\n\t\topts = append(opts, &opt)\n\tcase reflect.String:\n\t\t// Strings will match values or labels\n\t\tvalOpt := common.SelectOption{Value: new(string)}\n\t\t*valOpt.Value = t.(string) //nolint:forcetypeassert\n\t\tlabelOpt := common.SelectOption{Label: new(string)}\n\t\t*labelOpt.Label = t.(string) //nolint:forcetypeassert\n\t\topts = append(opts, &valOpt, &labelOpt)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"options: unsupported type %T\", values)\n\t}\n\n\treturn opts, nil\n}\n\nfunc extractSelectOptionFromMap(v map[string]any) (*common.SelectOption, error) {\n\topt := &common.SelectOption{}\n\tfor k, raw := range v {\n\t\tswitch k {\n\t\tcase \"value\":\n\t\t\topt.Value = new(string)\n\n\t\t\tv, ok := raw.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"options[%v]: expected string, got %T\", k, raw)\n\t\t\t}\n\n\t\t\t*opt.Value = v\n\t\tcase \"label\":\n\t\t\topt.Label = new(string)\n\n\t\t\tv, ok := raw.(string)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"options[%v]: expected string, got %T\", k, raw)\n\t\t\t}\n\t\t\t*opt.Label = v\n\t\tcase \"index\":\n\t\t\topt.Index = new(int64)\n\n\t\t\tswitch raw := raw.(type) {\n\t\t\tcase int:\n\t\t\t\t*opt.Index = int64(raw)\n\t\t\tcase int64:\n\t\t\t\t*opt.Index = raw\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"options[%v]: expected int, got %T\", k, raw)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn opt, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/mapping_test.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\n\tk6common \"go.k6.io/k6/js/common\"\n\tk6modulestest \"go.k6.io/k6/js/modulestest\"\n\tk6lib \"go.k6.io/k6/lib\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n)\n\n// customMappings is a list of custom mappings for our module API.\n// Some of them are wildcards, such as query to $ mapping; and\n// others are for publicly accessible fields, such as mapping\n// of page.keyboard to Page.getKeyboard.\nfunc customMappings() map[string]string {\n\treturn map[string]string{\n\t\t// wildcards\n\t\t\"pageAPI.query\":             \"$\",\n\t\t\"pageAPI.queryAll\":          \"$$\",\n\t\t\"frameAPI.query\":            \"$\",\n\t\t\"frameAPI.queryAll\":         \"$$\",\n\t\t\"elementHandleAPI.query\":    \"$\",\n\t\t\"elementHandleAPI.queryAll\": \"$$\",\n\t\t// getters\n\t\t\"pageAPI.getKeyboard\":    \"keyboard\",\n\t\t\"pageAPI.getMouse\":       \"mouse\",\n\t\t\"pageAPI.getTouchscreen\": \"touchscreen\",\n\t\t// internal methods\n\t\t\"elementHandleAPI.objectID\":    \"\",\n\t\t\"frameAPI.id\":                  \"\",\n\t\t\"frameAPI.loaderID\":            \"\",\n\t\t\"JSHandleAPI.objectID\":         \"\",\n\t\t\"browserAPI.close\":             \"\",\n\t\t\"frameAPI.evaluateWithContext\": \"\",\n\t\t// TODO: browser.on method is unexposed until more event\n\t\t// types other than 'disconnect' are supported.\n\t\t// See: https://go.k6.io/k6/js/modules/k6/browser/issues/913\n\t\t\"browserAPI.on\": \"\",\n\t}\n}\n\n// TestMappings tests that all the methods of the API (api/) are\n// to the module. This is to ensure that we don't forget to map\n// a new method to the module.\nfunc TestMappings(t *testing.T) {\n\tt.Parallel()\n\n\ttype test struct {\n\t\tapiInterface any\n\t\tmapp         func() mapping\n\t}\n\n\tvar (\n\t\tvu = &k6modulestest.VU{\n\t\t\tRuntimeField: sobek.New(),\n\t\t\tInitEnvField: &k6common.InitEnvironment{\n\t\t\t\tTestPreInitState: &k6lib.TestPreInitState{\n\t\t\t\t\tRegistry: k6metrics.NewRegistry(),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tcustomMappings = customMappings()\n\t)\n\n\t// testMapping tests that all the methods of an API are mapped\n\t// to the module. And wildcards are mapped correctly and their\n\t// methods are not mapped.\n\ttestMapping := func(t *testing.T, tt test) {\n\t\tt.Helper()\n\n\t\tvar (\n\t\t\ttyp    = reflect.TypeOf(tt.apiInterface).Elem()\n\t\t\tmapped = tt.mapp()\n\t\t\ttested = make(map[string]bool)\n\t\t)\n\t\tfor i := 0; i < typ.NumMethod(); i++ {\n\t\t\tmethod := typ.Method(i)\n\t\t\trequire.NotNil(t, method)\n\n\t\t\t// sobek uses methods that starts with lowercase.\n\t\t\t// so we need to convert the first letter to lowercase.\n\t\t\tm := toFirstLetterLower(method.Name)\n\n\t\t\tcm, cmok := isCustomMapping(customMappings, typ.Name(), m)\n\t\t\t// if the method is a custom mapping, it should not be\n\t\t\t// mapped to the module. so we should not find it in\n\t\t\t// the mapped methods.\n\t\t\tif _, ok := mapped[m]; cmok && ok {\n\t\t\t\tt.Errorf(\"method %q should not be mapped\", m)\n\t\t\t}\n\t\t\t// a custom mapping with an empty string means that\n\t\t\t// the method should not exist on the API.\n\t\t\tif cmok && cm == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// change the method name if it is mapped to a custom\n\t\t\t// method. these custom methods are not exist on our\n\t\t\t// API. so we need to use the mapped method instead.\n\t\t\tif cmok {\n\t\t\t\tm = cm\n\t\t\t}\n\t\t\tif _, ok := mapped[m]; !ok {\n\t\t\t\tt.Errorf(\"method %q not found\", m)\n\t\t\t}\n\t\t\t// to detect if a method is redundantly mapped.\n\t\t\ttested[m] = true\n\t\t}\n\t\t// detect redundant mappings.\n\t\tfor m := range mapped {\n\t\t\tif !tested[m] {\n\t\t\t\tt.Errorf(\"method %q is redundant\", m)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor name, tt := range map[string]test{\n\t\t\"browser\": {\n\t\t\tapiInterface: (*browserAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapBrowser(moduleVU{VU: vu})\n\t\t\t},\n\t\t},\n\t\t\"browserContext\": {\n\t\t\tapiInterface: (*browserContextAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapBrowserContext(moduleVU{VU: vu}, &common.BrowserContext{})\n\t\t\t},\n\t\t},\n\t\t\"page\": {\n\t\t\tapiInterface: (*pageAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapPage(moduleVU{VU: vu}, &common.Page{\n\t\t\t\t\tKeyboard:    &common.Keyboard{},\n\t\t\t\t\tMouse:       &common.Mouse{},\n\t\t\t\t\tTouchscreen: &common.Touchscreen{},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t\"elementHandle\": {\n\t\t\tapiInterface: (*elementHandleAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapElementHandle(moduleVU{VU: vu}, &common.ElementHandle{})\n\t\t\t},\n\t\t},\n\t\t\"frameLocator\": {\n\t\t\tapiInterface: (*frameLocatorAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapFrameLocator(moduleVU{VU: vu}, &common.FrameLocator{})\n\t\t\t},\n\t\t},\n\t\t\"jsHandle\": {\n\t\t\tapiInterface: (*common.JSHandleAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapJSHandle(moduleVU{VU: vu}, &common.BaseJSHandle{})\n\t\t\t},\n\t\t},\n\t\t\"frame\": {\n\t\t\tapiInterface: (*frameAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapFrame(moduleVU{VU: vu}, &common.Frame{})\n\t\t\t},\n\t\t},\n\t\t\"mapRequest\": {\n\t\t\tapiInterface: (*requestAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapRequest(moduleVU{VU: vu}, &common.Request{})\n\t\t\t},\n\t\t},\n\t\t\"mapResponse\": {\n\t\t\tapiInterface: (*responseAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapResponse(moduleVU{VU: vu}, &common.Response{})\n\t\t\t},\n\t\t},\n\t\t\"mapWorker\": {\n\t\t\tapiInterface: (*workerAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapWorker(moduleVU{VU: vu}, &common.Worker{})\n\t\t\t},\n\t\t},\n\t\t\"mapLocator\": {\n\t\t\tapiInterface: (*locatorAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapLocator(moduleVU{VU: vu}, &common.Locator{})\n\t\t\t},\n\t\t},\n\t\t\"mapConsoleMessage\": {\n\t\t\tapiInterface: (*consoleMessageAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapConsoleMessage(moduleVU{VU: vu}, common.PageEvent{\n\t\t\t\t\tConsoleMessage: &common.ConsoleMessage{},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t\"mapMetricEvent\": {\n\t\t\tapiInterface: (*metricEventAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapMetricEvent(moduleVU{VU: vu}, common.PageEvent{\n\t\t\t\t\tMetric: &common.MetricEvent{},\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t\"mapTouchscreen\": {\n\t\t\tapiInterface: (*touchscreenAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapTouchscreen(moduleVU{VU: vu}, &common.Touchscreen{})\n\t\t\t},\n\t\t},\n\t\t\"mapKeyboard\": {\n\t\t\tapiInterface: (*keyboardAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapKeyboard(moduleVU{VU: vu}, &common.Keyboard{})\n\t\t\t},\n\t\t},\n\t\t\"mapMouse\": {\n\t\t\tapiInterface: (*mouseAPI)(nil),\n\t\t\tmapp: func() mapping {\n\t\t\t\treturn mapMouse(moduleVU{VU: vu}, &common.Mouse{})\n\t\t\t},\n\t\t},\n\t} {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttestMapping(t, tt)\n\t\t})\n\t}\n}\n\n// toFirstLetterLower converts the first letter of the string to lower case.\nfunc toFirstLetterLower(s string) string {\n\t// Special cases.\n\t// Instead of loading up an acronyms list, just do this.\n\t// Good enough for our purposes.\n\tspecial := map[string]string{\n\t\t\"ID\":        \"id\",\n\t\t\"JSON\":      \"json\",\n\t\t\"JSONValue\": \"jsonValue\",\n\t\t\"URL\":       \"url\",\n\t}\n\tif v, ok := special[s]; ok {\n\t\treturn v\n\t}\n\tif s == \"\" {\n\t\treturn \"\"\n\t}\n\n\treturn strings.ToLower(s[:1]) + s[1:]\n}\n\n// isCustomMapping returns true if the method is a custom mapping\n// and returns the name of the method to be called instead of the\n// original one.\nfunc isCustomMapping(customMappings map[string]string, typ, method string) (string, bool) {\n\tname := typ + \".\" + method\n\n\tif s, ok := customMappings[name]; ok {\n\t\treturn s, ok\n\t}\n\n\treturn \"\", false\n}\n\n// ----------------------------------------------------------------------------\n// JavaScript API definitions.\n// ----------------------------------------------------------------------------\n\n// browserAPI is the public interface of a CDP browser.\ntype browserAPI interface {\n\tClose()\n\tContext() *common.BrowserContext\n\tCloseContext()\n\tIsConnected() bool\n\tNewContext(opts *common.BrowserContextOptions) (*common.BrowserContext, error)\n\tNewPage(opts *common.BrowserContextOptions) (*common.Page, error)\n\tOn(string) (bool, error)\n\tUserAgent() string\n\tVersion() string\n}\n\n// browserContextAPI is the public interface of a CDP browser context.\ntype browserContextAPI interface { //nolint:interfacebloat\n\tAddCookies(cookies []*common.Cookie) error\n\tAddInitScript(script sobek.Value, arg sobek.Value) error\n\tBrowser() *common.Browser\n\tClearCookies() error\n\tClearPermissions() error\n\tClose() error\n\tCookies(urls ...string) ([]*common.Cookie, error)\n\tGrantPermissions(permissions []string, opts sobek.Value) error\n\tNewPage() (*common.Page, error)\n\tPages() []*common.Page\n\tSetDefaultNavigationTimeout(timeout int64)\n\tSetDefaultTimeout(timeout int64)\n\tSetGeolocation(geolocation *common.Geolocation) error\n\tSetHTTPCredentials(httpCredentials common.Credentials) error\n\tSetOffline(offline bool) error\n\tWaitForEvent(event common.PageEventName, optsOrPredicate sobek.Value) (any, error)\n}\n\n// pageAPI is the interface of a single browser tab.\ntype pageAPI interface { //nolint:interfacebloat\n\tBringToFront() error\n\tCheck(selector string, opts sobek.Value) error\n\tClick(selector string, opts sobek.Value) error\n\tClose(opts sobek.Value) error\n\tContent() (string, error)\n\tContext() *common.BrowserContext\n\tDblclick(selector string, opts sobek.Value) error\n\tDispatchEvent(selector string, typ string, eventInit sobek.Value, opts sobek.Value)\n\tEmulateMedia(opts sobek.Value) error\n\tEmulateVisionDeficiency(typ string) error\n\tEvaluate(pageFunc sobek.Value, arg ...sobek.Value) (any, error)\n\tEvaluateHandle(pageFunc sobek.Value, arg ...sobek.Value) (common.JSHandleAPI, error)\n\tFill(selector string, value string, opts sobek.Value) error\n\tFocus(selector string, opts sobek.Value) error\n\tFrames() []*common.Frame\n\tGetAttribute(selector string, name string, opts sobek.Value) (string, bool, error)\n\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\tGetByAltText(alt string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByLabel(label string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByPlaceholder(placeholder string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByTitle(title string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByTestId(testID string) *common.Locator\n\tGetByText(text string, opts *common.GetByBaseOptions) *common.Locator\n\tGetKeyboard() *common.Keyboard\n\tGetMouse() *common.Mouse\n\tGetTouchscreen() *common.Touchscreen\n\tGoto(url string, opts sobek.Value) (*common.Response, error)\n\tGoBack(opts sobek.Value) (*common.Response, error)\n\tGoForward(opts sobek.Value) (*common.Response, error)\n\tHover(selector string, opts sobek.Value) error\n\tInnerHTML(selector string, opts sobek.Value) (string, error)\n\tInnerText(selector string, opts sobek.Value) (string, error)\n\tInputValue(selector string, opts sobek.Value) (string, error)\n\tIsChecked(selector string, opts sobek.Value) (bool, error)\n\tIsClosed() bool\n\tIsDisabled(selector string, opts sobek.Value) (bool, error)\n\tIsEditable(selector string, opts sobek.Value) (bool, error)\n\tIsEnabled(selector string, opts sobek.Value) (bool, error)\n\tIsHidden(selector string, opts sobek.Value) (bool, error)\n\tIsVisible(selector string, opts sobek.Value) (bool, error)\n\tLocator(selector string, opts sobek.Value) *common.Locator\n\tFrameLocator(selector string) *common.FrameLocator\n\tMainFrame() *common.Frame\n\tOn(event common.PageEventName, handler func(common.PageEvent) error) error\n\tOpener() pageAPI\n\tPress(selector string, key string, opts sobek.Value) error\n\tQuery(selector string) (*common.ElementHandle, error)\n\tQueryAll(selector string) ([]*common.ElementHandle, error)\n\tReload(opts sobek.Value) *common.Response\n\tRoute(path string, handler sobek.Callable)\n\tScreenshot(opts sobek.Value) ([]byte, error)\n\tSelectOption(selector string, values sobek.Value, opts sobek.Value) ([]string, error)\n\tSetChecked(selector string, checked bool, opts sobek.Value) error\n\tSetContent(html string, opts sobek.Value) error\n\tSetDefaultNavigationTimeout(timeout int64)\n\tSetDefaultTimeout(timeout int64)\n\tSetExtraHTTPHeaders(headers map[string]string) error\n\tSetInputFiles(selector string, files sobek.Value, opts sobek.Value) error\n\tSetViewportSize(viewportSize sobek.Value) error\n\tTap(selector string, opts sobek.Value) error\n\tTextContent(selector string, opts sobek.Value) (string, bool, error)\n\tThrottleCPU(common.CPUProfile) error\n\tThrottleNetwork(common.NetworkProfile) error\n\tTitle() (string, error)\n\tType(selector string, text string, opts sobek.Value) error\n\tUncheck(selector string, opts sobek.Value) error\n\tUnroute(url string) error\n\tUnrouteAll() error\n\tURL() (string, error)\n\tViewportSize() map[string]float64\n\tWaitForFunction(fn, opts sobek.Value, args ...sobek.Value) (any, error)\n\tWaitForLoadState(state string, opts sobek.Value) error\n\tWaitForNavigation(opts sobek.Value) (*common.Response, error)\n\tWaitForSelector(selector string, opts sobek.Value) (*common.ElementHandle, error)\n\tWaitForTimeout(timeout int64)\n\tWaitForURL(url string, opts sobek.Value) (*sobek.Promise, error)\n\tWaitForEvent(event common.PageEventName, opts sobek.Value) (*sobek.Promise, error)\n\tWaitForResponse(url string, opts sobek.Value) (*sobek.Promise, error)\n\tWaitForRequest(url string, opts sobek.Value) (*sobek.Promise, error)\n\tWorkers() []*common.Worker\n}\n\n// consoleMessageAPI is the interface of a console message.\ntype consoleMessageAPI interface {\n\tArgs() []common.JSHandleAPI\n\tPage() *common.Page\n\tText() string\n\tType() string\n}\n\n// metricEventAPI is the interface of a metric event.\ntype metricEventAPI interface {\n\tTag(rm common.RegExMatcher, patterns common.TagMatches) error\n}\n\n// frameAPI is the interface of a CDP target frame.\ntype frameAPI interface { //nolint:interfacebloat\n\tCheck(selector string, opts sobek.Value) error\n\tChildFrames() []*common.Frame\n\tClick(selector string, opts sobek.Value) error\n\tContent() (string, error)\n\tDblclick(selector string, opts sobek.Value) error\n\tDispatchEvent(selector string, typ string, eventInit sobek.Value, opts sobek.Value) error\n\t// EvaluateWithContext for internal use only\n\tEvaluateWithContext(ctx context.Context, pageFunc sobek.Value, args ...sobek.Value) (any, error)\n\tEvaluate(pageFunc sobek.Value, args ...sobek.Value) (any, error)\n\tEvaluateHandle(pageFunc sobek.Value, args ...sobek.Value) (common.JSHandleAPI, error)\n\tFill(selector string, value string, opts sobek.Value) error\n\tFocus(selector string, opts sobek.Value) error\n\tFrameElement() (*common.ElementHandle, error)\n\tGetAttribute(selector string, name string, opts sobek.Value) (string, bool, error)\n\tGetByAltText(alt string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByLabel(label string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByPlaceholder(placeholder string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\tGetByTestId(testID string) *common.Locator\n\tGetByText(text string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByTitle(title string, opts *common.GetByBaseOptions) *common.Locator\n\tGoto(url string, opts sobek.Value) (*common.Response, error)\n\tHover(selector string, opts sobek.Value) error\n\tInnerHTML(selector string, opts sobek.Value) (string, error)\n\tInnerText(selector string, opts sobek.Value) (string, error)\n\tInputValue(selector string, opts sobek.Value) (string, error)\n\tIsChecked(selector string, opts sobek.Value) (bool, error)\n\tIsDetached() bool\n\tIsDisabled(selector string, opts sobek.Value) (bool, error)\n\tIsEditable(selector string, opts sobek.Value) (bool, error)\n\tIsEnabled(selector string, opts sobek.Value) (bool, error)\n\tIsHidden(selector string, opts sobek.Value) (bool, error)\n\tIsVisible(selector string, opts sobek.Value) (bool, error)\n\tID() string\n\tLoaderID() string\n\tLocator(selector string, opts sobek.Value) *common.Locator\n\tFrameLocator(selector string) *common.FrameLocator\n\tName() string\n\tQuery(selector string) (*common.ElementHandle, error)\n\tQueryAll(selector string) ([]*common.ElementHandle, error)\n\tPage() *common.Page\n\tParentFrame() *common.Frame\n\tPress(selector string, key string, opts sobek.Value) error\n\tSelectOption(selector string, values sobek.Value, opts sobek.Value) ([]string, error)\n\tSetChecked(selector string, checked bool, opts sobek.Value) error\n\tSetContent(html string, opts sobek.Value) error\n\tSetInputFiles(selector string, files sobek.Value, opts sobek.Value)\n\tTap(selector string, opts sobek.Value) error\n\tTextContent(selector string, opts sobek.Value) (string, bool, error)\n\tTitle() string\n\tType(selector string, text string, opts sobek.Value) error\n\tUncheck(selector string, opts sobek.Value) error\n\tURL() string\n\tWaitForFunction(pageFunc, opts sobek.Value, args ...sobek.Value) (any, error)\n\tWaitForLoadState(state string, opts sobek.Value) error\n\tWaitForNavigation(opts sobek.Value) (*common.Response, error)\n\tWaitForSelector(selector string, opts sobek.Value) (*common.ElementHandle, error)\n\tWaitForTimeout(timeout int64)\n\tWaitForURL(url string, opts sobek.Value) (*sobek.Promise, error)\n}\n\n// elementHandleAPI is the interface of an in-page DOM element.\ntype elementHandleAPI interface { //nolint:interfacebloat\n\tcommon.JSHandleAPI\n\n\tBoundingBox() (*common.Rect, error)\n\tCheck(opts sobek.Value) error\n\tClick(opts sobek.Value) error\n\tContentFrame() (*common.Frame, error)\n\tDblclick(opts sobek.Value) error\n\tDispatchEvent(typ string, props sobek.Value) error\n\tFill(value string, opts sobek.Value) error\n\tFocus() error\n\tGetAttribute(name string) (string, bool, error)\n\tHover(opts sobek.Value) error\n\tInnerHTML() (string, error)\n\tInnerText() (string, error)\n\tInputValue(opts sobek.Value) (string, error)\n\tIsChecked() (bool, error)\n\tIsDisabled() (bool, error)\n\tIsEditable() (bool, error)\n\tIsEnabled() (bool, error)\n\tIsHidden() (bool, error)\n\tIsVisible() (bool, error)\n\tOwnerFrame() (*common.Frame, error)\n\tPress(key string, opts sobek.Value) error\n\tQuery(selector string) (*common.ElementHandle, error)\n\tQueryAll(selector string) ([]*common.ElementHandle, error)\n\tScreenshot(opts sobek.Value) (sobek.ArrayBuffer, error)\n\tScrollIntoViewIfNeeded(opts sobek.Value) error\n\tSelectOption(values sobek.Value, opts sobek.Value) ([]string, error)\n\tSelectText(opts sobek.Value) error\n\tSetChecked(checked bool, opts sobek.Value) error\n\tSetInputFiles(files sobek.Value, opts sobek.Value) error\n\tTap(opts sobek.Value) error\n\tTextContent() (string, bool, error)\n\tType(text string, opts sobek.Value) error\n\tUncheck(opts sobek.Value) error\n\tWaitForElementState(state string, opts sobek.Value) error\n\tWaitForSelector(selector string, opts sobek.Value) (*common.ElementHandle, error)\n}\n\ntype frameLocatorAPI interface {\n\tGetByAltText(alt string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByLabel(label string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByPlaceholder(placeholder string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\tGetByTestId(testID string) *common.Locator\n\tGetByText(text string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByTitle(title string, opts *common.GetByBaseOptions) *common.Locator\n\tLocator(selector string) *common.Locator\n\tFrameLocator(selector string) *common.FrameLocator\n}\n\n// requestAPI is the interface of an HTTP request.\ntype requestAPI interface { //nolint:interfacebloat\n\tAllHeaders() map[string]string\n\tFailure() *common.RequestFailure\n\tFrame() *common.Frame\n\tHeaderValue(string) sobek.Value\n\tHeaders() map[string]string\n\tHeadersArray() []common.HTTPHeader\n\tIsNavigationRequest() bool\n\tMethod() string\n\tPostData() string\n\tPostDataBuffer() sobek.ArrayBuffer\n\tResourceType() string\n\tResponse() *common.Response\n\tSize() common.HTTPMessageSize\n\tTiming() sobek.Value\n\tURL() string\n}\n\n// responseAPI is the interface of an HTTP response.\ntype responseAPI interface { //nolint:interfacebloat\n\tAllHeaders() map[string]string\n\tBody() ([]byte, error)\n\tFrame() *common.Frame\n\tHeaderValue(string) (string, bool)\n\tHeaderValues(string) []string\n\tHeaders() map[string]string\n\tHeadersArray() []common.HTTPHeader\n\tJSON() (any, error)\n\tOk() bool\n\tRequest() *common.Request\n\tSecurityDetails() *common.SecurityDetails\n\tServerAddr() *common.RemoteAddress\n\tSize() common.HTTPMessageSize\n\tStatus() int64\n\tStatusText() string\n\tURL() string\n\tText() (string, error)\n}\n\n// locatorAPI represents a way to find element(s) on a page at any moment.\ntype locatorAPI interface { //nolint:interfacebloat\n\tAll() ([]*common.Locator, error)\n\tBoundingBox(opts *common.FrameBaseOptions) (*common.Rect, error)\n\tClear(opts *common.FrameFillOptions) error\n\tClick(opts sobek.Value) error\n\tContentFrame() *common.FrameLocator\n\tCount() (int, error)\n\tDblclick(opts sobek.Value) error\n\tEvaluate(pageFunc sobek.Value, arg ...sobek.Value) (any, error)\n\tEvaluateHandle(pageFunc sobek.Value, arg ...sobek.Value) (common.JSHandleAPI, error)\n\tSetChecked(checked bool, opts sobek.Value) error\n\tCheck(opts sobek.Value) error\n\tUncheck(opts sobek.Value) error\n\tIsChecked(opts sobek.Value) (bool, error)\n\tIsEditable(opts sobek.Value) (bool, error)\n\tIsEnabled(opts sobek.Value) (bool, error)\n\tIsDisabled(opts sobek.Value) (bool, error)\n\tIsVisible(opts sobek.Value) (bool, error)\n\tIsHidden(opts sobek.Value) (bool, error)\n\tFill(value string, opts sobek.Value) error\n\tFilter(opts *common.LocatorFilterOptions) *common.Locator\n\tFirst() *common.Locator\n\tFocus(opts sobek.Value) error\n\tGetAttribute(name string, opts sobek.Value) (string, bool, error)\n\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\tGetByAltText(alt string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByLabel(label string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByPlaceholder(placeholder string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByTitle(title string, opts *common.GetByBaseOptions) *common.Locator\n\tGetByTestId(testID string) *common.Locator\n\tGetByText(text string, opts *common.GetByBaseOptions) *common.Locator\n\tInnerHTML(opts sobek.Value) (string, error)\n\tInnerText(opts sobek.Value) (string, error)\n\tTextContent(opts sobek.Value) (string, bool, error)\n\tInputValue(opts sobek.Value) (string, error)\n\tLocator(selector string) *common.Locator\n\tFrameLocator(selector string) *common.FrameLocator\n\tLast() *common.Locator\n\tNth(nth int) *common.Locator\n\tSelectOption(values sobek.Value, opts sobek.Value) ([]string, error)\n\tPress(key string, opts sobek.Value) error\n\tPressSequentially(text string, opts sobek.Value) error\n\tType(text string, opts sobek.Value) error\n\tHover(opts sobek.Value) error\n\tTap(opts sobek.Value) error\n\tDispatchEvent(typ string, eventInit, opts sobek.Value)\n\tWaitFor(opts sobek.Value) error\n}\n\n// keyboardAPI is the interface of a keyboard input device.\ntype keyboardAPI interface {\n\tDown(key string) error\n\tUp(key string) error\n\tInsertText(char string) error\n\tPress(key string, opts sobek.Value) error\n\tType(text string, opts sobek.Value) error\n}\n\n// touchscreenAPI is the interface of a touchscreen.\ntype touchscreenAPI interface {\n\tTap(x float64, y float64) error\n}\n\n// mouseAPI is the interface of a mouse input device.\ntype mouseAPI interface {\n\tClick(x float64, y float64, opts sobek.Value) error\n\tDblClick(x float64, y float64, opts sobek.Value) error\n\tDown(opts sobek.Value) error\n\tUp(opts sobek.Value) error\n\tMove(x float64, y float64, opts sobek.Value) error\n}\n\n// workerAPI is the interface of a web worker.\ntype workerAPI interface {\n\tURL() string\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/metric_event_mapping.go",
    "content": "package browser\n\nimport (\n\t\"fmt\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// mapMetricEvent to the JS module.\nfunc mapMetricEvent(vu moduleVU, event common.PageEvent) mapping {\n\trt := vu.Runtime()\n\tem := event.Metric\n\n\treturn mapping{\n\t\t\"tag\": func(urls common.TagMatches) error {\n\t\t\tcallback := func(pattern, url string) (bool, error) {\n\t\t\t\tmatched, err := rt.RunString(pattern + `.test('` + url + `')`)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false, fmt.Errorf(\"matching url with regex: %w\", err)\n\t\t\t\t}\n\t\t\t\treturn matched.ToBoolean(), nil\n\t\t\t}\n\n\t\t\treturn em.Tag(callback, urls) //nolint:wrapcheck\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/module.go",
    "content": "// Package browser is the browser module's entry point, and\n// initializer of various global types, and a translation layer\n// between sobek and the internal business logic.\n//\n// It initializes and drives the downstream components by passing\n// the necessary concrete dependencies.\npackage browser\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\n\tk6modules \"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// filePersister is the type that all file persisters must implement. It's job is\n\t// to persist a file somewhere, hiding the details of where and how from the caller.\n\tfilePersister interface {\n\t\tPersist(ctx context.Context, path string, data io.Reader) (err error)\n\t}\n\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct {\n\t\tPidRegistry    *pidRegistry\n\t\tremoteRegistry *remoteRegistry\n\t\tinitOnce       *sync.Once\n\t\ttracesMetadata map[string]string\n\t\tfilePersister  filePersister\n\t\ttestRunID      string\n\t}\n\n\t// JSModule exposes the properties available to the JS script.\n\tJSModule struct {\n\t\tBrowser         *sobek.Object\n\t\tDevices         map[string]common.Device\n\t\tNetworkProfiles map[string]common.NetworkProfile `js:\"networkProfiles\"`\n\t}\n\n\t// ModuleInstance represents an instance of the JS module.\n\tModuleInstance struct {\n\t\tmod *JSModule\n\t}\n)\n\nvar (\n\t_ k6modules.Module   = &RootModule{}\n\t_ k6modules.Instance = &ModuleInstance{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{\n\t\tPidRegistry: &pidRegistry{},\n\t\tinitOnce:    &sync.Once{},\n\t}\n}\n\n// NewModuleInstance implements the k6modules.Module interface to return\n// a new instance for each VU.\nfunc (m *RootModule) NewModuleInstance(vu k6modules.VU) k6modules.Instance {\n\t// initialization should be done once per module as it initializes\n\t// globally used values across the whole test run and not just the\n\t// current VU. Since initialization can fail with an error,\n\t// we've had to place it here so that if an error occurs a\n\t// panic can be initiated and safely handled by k6.\n\tm.initOnce.Do(func() {\n\t\tm.initialize(vu)\n\t})\n\n\treturn &ModuleInstance{\n\t\tmod: &JSModule{\n\t\t\tBrowser: mapBrowserToSobek(moduleVU{\n\t\t\t\tVU:          vu,\n\t\t\t\tpidRegistry: m.PidRegistry,\n\t\t\t\tbrowserRegistry: newBrowserRegistry(\n\t\t\t\t\tcontext.Background(),\n\t\t\t\t\tvu,\n\t\t\t\t\tm.remoteRegistry,\n\t\t\t\t\tm.PidRegistry,\n\t\t\t\t\tm.tracesMetadata,\n\t\t\t\t),\n\t\t\t\ttaskQueueRegistry: newTaskQueueRegistry(vu),\n\t\t\t\tfilePersister:     m.filePersister,\n\t\t\t\ttestRunID:         m.testRunID,\n\t\t\t}),\n\t\t\tDevices:         common.GetDevices(),\n\t\t\tNetworkProfiles: common.GetNetworkProfiles(),\n\t\t},\n\t}\n}\n\n// Exports returns the exports of the JS module so that it can be used in test\n// scripts.\nfunc (mi *ModuleInstance) Exports() k6modules.Exports {\n\treturn k6modules.Exports{Default: mi.mod}\n}\n\n// initialize initializes the module instance with a new remote registry\n// and debug server, etc.\nfunc (m *RootModule) initialize(vu k6modules.VU) {\n\tvar (\n\t\terr     error\n\t\tinitEnv = vu.InitEnv()\n\t)\n\tm.remoteRegistry, err = newRemoteRegistry(initEnv.LookupEnv)\n\tif err != nil {\n\t\tk6ext.Abortf(vu.Context(), \"failed to create remote registry: %v\", err)\n\t}\n\tm.tracesMetadata, err = parseTracesMetadata(initEnv.LookupEnv)\n\tif err != nil {\n\t\tk6ext.Abortf(vu.Context(), \"parsing browser traces metadata: %v\", err)\n\t}\n\tm.filePersister, err = newScreenshotPersister(initEnv.LookupEnv)\n\tif err != nil {\n\t\tk6ext.Abortf(vu.Context(), \"failed to create file persister: %v\", err)\n\t}\n\tif e, ok := initEnv.LookupEnv(env.K6TestRunID); ok && e != \"\" {\n\t\tm.testRunID = e\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/module_test.go",
    "content": "package browser\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n)\n\n// TestModuleNew tests registering the module.\n// It doesn't test the module's remaining functionality as it is\n// already tested in the tests/ integration tests.\nfunc TestModuleNew(t *testing.T) {\n\tt.Parallel()\n\n\tvu := k6test.NewVU(t)\n\tm, ok := New().NewModuleInstance(vu).(*ModuleInstance)\n\trequire.True(t, ok, \"NewModuleInstance should return a ModuleInstance\")\n\trequire.NotNil(t, m.mod, \"Module should be set\")\n\trequire.NotNil(t, m.mod.Browser, \"Browser should be set\")\n\trequire.NotNil(t, m.mod.Devices, \"Devices should be set\")\n\trequire.NotNil(t, m.mod.NetworkProfiles, \"Profiles should be set\")\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/modulevu.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\n\tk6modules \"go.k6.io/k6/js/modules\"\n)\n\n// moduleVU carries module specific VU information.\n//\n// Currently, it is used to carry the VU object to the inner objects and\n// promises.\ntype moduleVU struct {\n\tk6modules.VU\n\n\t*pidRegistry\n\t*browserRegistry\n\n\t*taskQueueRegistry\n\n\tfilePersister\n\n\ttestRunID string\n}\n\n// browser returns the VU browser instance for the current iteration.\nfunc (vu moduleVU) browser() (*common.Browser, error) {\n\treturn vu.getBrowser(vu.State().Iteration)\n}\n\nfunc (vu moduleVU) Context() context.Context {\n\t// promises and inner objects need the VU object to be\n\t// able to use k6-core specific functionality.\n\t//\n\t// We should not cache the context (especially the init\n\t// context from the vu that is received from k6 in\n\t// NewModuleInstance).\n\treturn k6ext.WithVU(vu.VU.Context(), vu)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/mouse_mapping.go",
    "content": "package browser\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\nfunc mapMouse(vu moduleVU, m *common.Mouse) mapping {\n\trt := vu.Runtime()\n\treturn mapping{\n\t\t\"click\": func(x float64, y float64, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseMouseClickOptions(rt, opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing mouse click options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, m.Click(x, y, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"dblClick\": func(x float64, y float64, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseMouseDblClickOptions(rt, opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing mouse double click options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, m.DblClick(x, y, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"down\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseMouseDownUpOptions(rt, opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing mouse down options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, m.Down(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"up\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseMouseDownUpOptions(rt, opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing mouse up options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, m.Up(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"move\": func(x float64, y float64, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseMouseMoveOptions(rt, opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing mouse move options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, m.Move(x, y, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t}\n}\n\n// parseMouseClickOptions parses the mouse click options from a Sobek value.\nfunc parseMouseClickOptions(rt *sobek.Runtime, opts sobek.Value) (*common.MouseClickOptions, error) {\n\tpopts := common.NewMouseClickOptions()\n\tif k6common.IsNullish(opts) {\n\t\treturn popts, nil\n\t}\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tv := obj.Get(k)\n\t\tswitch k {\n\t\tcase \"button\":\n\t\t\tpopts.Button = v.String()\n\t\tcase \"clickCount\":\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64:\n\t\t\t\tpopts.ClickCount = v.ToInteger()\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"clickCount must be an integer, got %s\", v.ExportType().Kind())\n\t\t\t}\n\t\tcase \"delay\":\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64:\n\t\t\t\tpopts.Delay = v.ToInteger()\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"delay must be an integer, got %s\", v.ExportType().Kind())\n\t\t\t}\n\t\t}\n\t}\n\n\treturn popts, nil\n}\n\n// parseMouseDblClickOptions parses the mouse double click options from a Sobek value.\nfunc parseMouseDblClickOptions(rt *sobek.Runtime, opts sobek.Value) (*common.MouseDblClickOptions, error) {\n\tpopts := common.NewMouseDblClickOptions()\n\tif k6common.IsNullish(opts) {\n\t\treturn popts, nil\n\t}\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tv := obj.Get(k)\n\t\tswitch k {\n\t\tcase \"button\":\n\t\t\tpopts.Button = v.String()\n\t\tcase \"delay\":\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64:\n\t\t\t\tpopts.Delay = v.ToInteger()\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"delay must be an integer, got %s\", v.ExportType().Kind())\n\t\t\t}\n\t\t}\n\t}\n\n\treturn popts, nil\n}\n\n// parseMouseDownUpOptions parses the mouse down/up options from a Sobek value.\nfunc parseMouseDownUpOptions(rt *sobek.Runtime, opts sobek.Value) (*common.MouseDownUpOptions, error) {\n\tpopts := common.NewMouseDownUpOptions()\n\tif k6common.IsNullish(opts) {\n\t\treturn popts, nil\n\t}\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tv := obj.Get(k)\n\t\tswitch k {\n\t\tcase \"button\":\n\t\t\tpopts.Button = v.String()\n\t\tcase \"clickCount\":\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64:\n\t\t\t\tpopts.ClickCount = v.ToInteger()\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"clickCount must be an integer, got %s\", v.ExportType().Kind())\n\t\t\t}\n\t\t}\n\t}\n\n\treturn popts, nil\n}\n\n// parseMouseMoveOptions parses the mouse move options from a Sobek value.\nfunc parseMouseMoveOptions(rt *sobek.Runtime, opts sobek.Value) (*common.MouseMoveOptions, error) {\n\tpopts := common.NewMouseMoveOptions()\n\tif k6common.IsNullish(opts) {\n\t\treturn popts, nil\n\t}\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tif k == \"steps\" {\n\t\t\tv := obj.Get(k)\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64:\n\t\t\t\tpopts.Steps = v.ToInteger()\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"steps must be an integer, got %s\", v.ExportType().Kind())\n\t\t\t}\n\t\t}\n\t}\n\n\treturn popts, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/mouse_mapping_test.go",
    "content": "package browser\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n)\n\nfunc TestParseMouseClickOptions(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twant    *common.MouseClickOptions\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:  \"defaults_on_null\",\n\t\t\tinput: `null`,\n\t\t\twant:  &common.MouseClickOptions{Button: \"left\", ClickCount: 1, Delay: 0},\n\t\t},\n\t\t{\n\t\t\tname:  \"all_options\",\n\t\t\tinput: `({button: \"right\", clickCount: 3, delay: 100})`,\n\t\t\twant:  &common.MouseClickOptions{Button: \"right\", ClickCount: 3, Delay: 100},\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_clickCount\",\n\t\t\tinput:   `({clickCount: \"invalid\"})`,\n\t\t\twantErr: \"clickCount must be an integer\",\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_delay\",\n\t\t\tinput:   `({delay: true})`,\n\t\t\twantErr: \"delay must be an integer\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\tv, err := vu.Runtime().RunString(tt.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts, err := parseMouseClickOptions(vu.Runtime(), v)\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, opts)\n\t\t})\n\t}\n}\n\nfunc TestParseMouseDblClickOptions(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twant    *common.MouseDblClickOptions\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:  \"defaults_on_null\",\n\t\t\tinput: `null`,\n\t\t\twant:  &common.MouseDblClickOptions{Button: \"left\", Delay: 0},\n\t\t},\n\t\t{\n\t\t\tname:  \"all_options\",\n\t\t\tinput: `({button: \"right\", delay: 50})`,\n\t\t\twant:  &common.MouseDblClickOptions{Button: \"right\", Delay: 50},\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_delay\",\n\t\t\tinput:   `({delay: \"slow\"})`,\n\t\t\twantErr: \"delay must be an integer\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\tv, err := vu.Runtime().RunString(tt.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts, err := parseMouseDblClickOptions(vu.Runtime(), v)\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, opts)\n\t\t})\n\t}\n}\n\nfunc TestParseMouseDownUpOptions(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twant    *common.MouseDownUpOptions\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:  \"defaults_on_null\",\n\t\t\tinput: `null`,\n\t\t\twant:  &common.MouseDownUpOptions{Button: \"left\", ClickCount: 1},\n\t\t},\n\t\t{\n\t\t\tname:  \"all_options\",\n\t\t\tinput: `({button: \"middle\", clickCount: 2})`,\n\t\t\twant:  &common.MouseDownUpOptions{Button: \"middle\", ClickCount: 2},\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_clickCount\",\n\t\t\tinput:   `({clickCount: []})`,\n\t\t\twantErr: \"clickCount must be an integer\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\tv, err := vu.Runtime().RunString(tt.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts, err := parseMouseDownUpOptions(vu.Runtime(), v)\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, opts)\n\t\t})\n\t}\n}\n\nfunc TestParseMouseMoveOptions(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twant    *common.MouseMoveOptions\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:  \"defaults_on_null\",\n\t\t\tinput: `null`,\n\t\t\twant:  &common.MouseMoveOptions{Steps: 1},\n\t\t},\n\t\t{\n\t\t\tname:  \"custom_steps\",\n\t\t\tinput: `({steps: 10})`,\n\t\t\twant:  &common.MouseMoveOptions{Steps: 10},\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_steps\",\n\t\t\tinput:   `({steps: {}})`,\n\t\t\twantErr: \"steps must be an integer\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\tv, err := vu.Runtime().RunString(tt.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts, err := parseMouseMoveOptions(vu.Runtime(), v)\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, opts)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/page_mapping.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// mapPage to the JS module.\n//\n//nolint:funlen\nfunc mapPage(vu moduleVU, p *common.Page) mapping { //nolint:gocognit,cyclop\n\trt := vu.Runtime()\n\tmaps := mapping{\n\t\t\"bringToFront\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.BringToFront() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"check\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameCheckOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing new frame check options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Check(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"click\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseFrameClickOptions(vu.Context(), opts, p.MainFrame().Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\terr := p.Click(selector, popts)\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"close\": func(opts sobek.Value) *sobek.Promise {\n\t\t\t// TODO when opts are implemented for this function, parse them here before calling promise()\n\t\t\t// in a goroutine off the event loop. As that will race with anything running on the event loop.\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\t// Close the page first so its goroutines (FrameSession, NetworkManager)\n\t\t\t\t// can finish processing events through the task queue before it's shut down.\n\t\t\t\terr := p.Close()\n\n\t\t\t\t// Now it's safe to close the taskqueue for this targetID.\n\t\t\t\tvu.close(p.TargetID())\n\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"content\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.Content() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"context\": func() mapping {\n\t\t\treturn mapBrowserContext(vu, p.Context())\n\t\t},\n\t\t\"dblclick\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameDblClickOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing double click options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Dblclick(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"dispatchEvent\": func(selector, typ string, eventInit, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameDispatchEventOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing page dispatch event options: %w\", err)\n\t\t\t}\n\t\t\tearg := exportArg(eventInit)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.DispatchEvent(selector, typ, earg, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"emulateMedia\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parsePageEmulateMediaOptions(rt, opts, common.NewPageEmulateMediaOptions(p))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing emulateMedia options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.EmulateMedia(popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"emulateVisionDeficiency\": func(typ string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.EmulateVisionDeficiency(typ) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"evaluate\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluate requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.Evaluate(funcString, gopts...)\n\t\t\t}), nil\n\t\t},\n\t\t\"evaluateHandle\": func(pageFunc sobek.Value, gargs ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tif sobekEmptyString(pageFunc) {\n\t\t\t\treturn nil, fmt.Errorf(\"evaluateHandle requires a page function\")\n\t\t\t}\n\t\t\tfuncString := pageFunc.String()\n\t\t\tgopts := exportArgs(gargs)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tjsh, err := p.EvaluateHandle(funcString, gopts...)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapJSHandle(vu, jsh), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"fill\": func(selector string, value string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameFillOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing fill options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Fill(selector, value, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"focus\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameBaseOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing focus options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Focus(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"frames\": func() *sobek.Object {\n\t\t\tfrs := p.Frames()\n\t\t\tmfrs := make([]mapping, 0, len(frs))\n\t\t\tfor _, fr := range frs {\n\t\t\t\tmfrs = append(mfrs, mapFrame(vu, fr))\n\t\t\t}\n\t\t\treturn rt.ToValue(mfrs).ToObject(rt)\n\t\t},\n\t\t\"getAttribute\": func(selector string, name string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameBaseOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing getAttribute options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := p.GetAttribute(selector, name, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t}), nil\n\t\t},\n\t\t\"getByRole\": func(role sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(role) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'role'\")\n\t\t\t}\n\t\t\tpopts := parseGetByRoleOptions(vu.Context(), opts)\n\n\t\t\tml := mapLocator(vu, p.GetByRole(role.String(), popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByAltText\": func(alt sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(alt) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'altText'\")\n\t\t\t}\n\t\t\tpalt, popts := parseGetByBaseOptions(vu.Context(), alt, false, opts)\n\n\t\t\tml := mapLocator(vu, p.GetByAltText(palt, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByLabel\": func(label sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(label) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'label'\")\n\t\t\t}\n\t\t\tplabel, popts := parseGetByBaseOptions(vu.Context(), label, true, opts)\n\n\t\t\tml := mapLocator(vu, p.GetByLabel(plabel, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByPlaceholder\": func(placeholder sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(placeholder) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'placeholder'\")\n\t\t\t}\n\t\t\tpplaceholder, popts := parseGetByBaseOptions(vu.Context(), placeholder, false, opts)\n\n\t\t\tml := mapLocator(vu, p.GetByPlaceholder(pplaceholder, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTitle\": func(title sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(title) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'title'\")\n\t\t\t}\n\t\t\tptitle, popts := parseGetByBaseOptions(vu.Context(), title, false, opts)\n\n\t\t\tml := mapLocator(vu, p.GetByTitle(ptitle, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByTestId\": func(testID sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(testID) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'testId'\")\n\t\t\t}\n\t\t\tptestID := parseStringOrRegex(testID, false)\n\n\t\t\tml := mapLocator(vu, p.GetByTestID(ptestID))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"getByText\": func(text sobek.Value, opts sobek.Value) (*sobek.Object, error) {\n\t\t\tif k6common.IsNullish(text) {\n\t\t\t\treturn nil, errors.New(\"missing required argument 'text'\")\n\t\t\t}\n\t\t\tptext, popts := parseGetByBaseOptions(vu.Context(), text, true, opts)\n\n\t\t\tml := mapLocator(vu, p.GetByText(ptext, popts))\n\t\t\treturn rt.ToValue(ml).ToObject(rt), nil\n\t\t},\n\t\t\"goto\": func(url string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tgopts := common.NewFrameGotoOptions(\n\t\t\t\tp.Referrer(),\n\t\t\t\tp.NavigationTimeout(),\n\t\t\t)\n\t\t\tif err := gopts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing page navigation options to %q: %w\", url, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tresp, err := p.Goto(url, gopts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\n\t\t\t\treturn mapResponse(vu, resp), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"hover\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameHoverOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing hover options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Hover(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"innerHTML\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameInnerHTMLOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing inner HTML options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.InnerHTML(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"innerText\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameInnerTextOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing inner text options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.InnerText(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"inputValue\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameInputValueOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing input value options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.InputValue(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isChecked\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsCheckedOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isChecked options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.IsChecked(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isClosed\": p.IsClosed,\n\t\t\"isDisabled\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsDisabledOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isDisabled options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.IsDisabled(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isEditable\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsEditableOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isEditabled options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.IsEditable(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isEnabled\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsEnabledOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isEnabled options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.IsEnabled(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isHidden\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsHiddenOptions()\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parse isHidden options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.IsHidden(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"isVisible\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameIsVisibleOptions()\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing isVisible options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.IsVisible(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"keyboard\": mapKeyboard(vu, p.GetKeyboard()),\n\t\t\"locator\": func(selector string, opts sobek.Value) *sobek.Object {\n\t\t\tml := mapLocator(vu, p.Locator(selector, parseLocatorOptions(rt, opts)))\n\t\t\treturn rt.ToValue(ml).ToObject(rt)\n\t\t},\n\t\t\"frameLocator\": func(selector string) *sobek.Object {\n\t\t\tmfl := mapFrameLocator(vu, p.FrameLocator(selector))\n\t\t\treturn rt.ToValue(mfl).ToObject(rt)\n\t\t},\n\t\t\"mainFrame\": func() *sobek.Object {\n\t\t\tmf := mapFrame(vu, p.MainFrame())\n\t\t\treturn rt.ToValue(mf).ToObject(rt)\n\t\t},\n\t\t\"mouse\": mapMouse(vu, p.GetMouse()),\n\t\t\"on\":    mapPageOn(vu, p),\n\t\t\"opener\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.Opener(), nil\n\t\t\t})\n\t\t},\n\t\t\"press\": func(selector string, key string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFramePressOptions(p.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing press options of selector %q: %w\", selector, err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Press(selector, key, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"reload\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewPageReloadOptions(common.LifecycleEventLoad, p.NavigationTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing reload options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tresp, err := p.Reload(popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t\t}\n\t\t\t\treturn mapResponse(vu, resp), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"goBack\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewPageGoBackForwardOptions(common.LifecycleEventLoad, p.NavigationTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing page go back options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tresp, err := p.GoBackForward(-1, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t\t}\n\t\t\t\treturn mapResponse(vu, resp), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"goForward\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewPageGoBackForwardOptions(common.LifecycleEventLoad, p.NavigationTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing page go forward options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tresp, err := p.GoBackForward(+1, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t\t}\n\t\t\t\treturn mapResponse(vu, resp), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"route\": mapPageRoute(vu, p),\n\t\t\"screenshot\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewPageScreenshotOptions()\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing page screenshot options: %w\", err)\n\t\t\t}\n\n\t\t\trt := vu.Runtime()\n\t\t\tpromise, res, rej := rt.NewPromise()\n\t\t\tcallback := vu.RegisterCallback()\n\t\t\tgo func() {\n\t\t\t\tbb, err := p.Screenshot(popts, vu.filePersister)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcallback(func() error {\n\t\t\t\t\t\treturn rej(err)\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tcallback(func() error {\n\t\t\t\t\treturn res(rt.NewArrayBuffer(bb))\n\t\t\t\t})\n\t\t\t}()\n\n\t\t\treturn promise, nil\n\t\t},\n\t\t\"selectOption\": func(selector string, values sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameSelectOptionOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing select option options: %w\", err)\n\t\t\t}\n\n\t\t\tconvValues, err := ConvertSelectOptionValues(vu.Runtime(), values)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing select options values: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.SelectOption(selector, convValues, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setChecked\": func(selector string, checked bool, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameCheckOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing frame set check options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.SetChecked(selector, checked, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setContent\": func(html string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameSetContentOptions(p.MainFrame().NavigationTimeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setContent options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.SetContent(html, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setDefaultNavigationTimeout\": p.SetDefaultNavigationTimeout,\n\t\t\"setDefaultTimeout\":           p.SetDefaultTimeout,\n\t\t\"setExtraHTTPHeaders\": func(headers map[string]string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.SetExtraHTTPHeaders(headers) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"setInputFiles\": func(selector string, files sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameSetInputFilesOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles options: %w\", err)\n\t\t\t}\n\n\t\t\tpfiles := new(common.Files)\n\t\t\tif err := pfiles.Parse(vu.Context(), files); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing setInputFiles parameter: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.SetInputFiles(selector, pfiles, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setViewportSize\": func(viewportSize sobek.Value) (*sobek.Promise, error) {\n\t\t\ts, err := parseSize(rt, viewportSize)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing viewport size: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.SetViewportSize(s) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"tap\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameTapOptions(p.Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing page tap options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Tap(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"textContent\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameTextContentOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing text content options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\ts, ok, err := p.TextContent(selector, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t\t}\n\t\t\t\treturn s, nil\n\t\t\t}), nil\n\t\t},\n\t\t\"throttleCPU\": func(cpuProfile common.CPUProfile) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.ThrottleCPU(cpuProfile) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"throttleNetwork\": func(networkProfile common.NetworkProfile) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.ThrottleNetwork(networkProfile) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"title\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn p.Title() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"touchscreen\": mapTouchscreen(vu, p.GetTouchscreen()),\n\t\t\"type\": func(selector string, text string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameTypeOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing type options: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Type(selector, text, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"uncheck\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameUncheckOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing frame uncheck options %q: %w\", selector, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Uncheck(selector, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"unroute\": func(url string) (*sobek.Promise, error) {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.Unroute(url)\n\t\t\t}), nil\n\t\t},\n\t\t\"unrouteAll\": func() (*sobek.Promise, error) {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.UnrouteAll()\n\t\t\t}), nil\n\t\t},\n\t\t\"url\":          p.URL,\n\t\t\"viewportSize\": p.ViewportSize,\n\t\t\"waitForFunction\": func(pageFunc, opts sobek.Value, args ...sobek.Value) (*sobek.Promise, error) {\n\t\t\tjs, popts, pargs, err := parseWaitForFunctionArgs(\n\t\t\t\tvu.Context(), p.Timeout(), pageFunc, opts, args...,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"page waitForFunction: %w\", err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (result any, reason error) {\n\t\t\t\treturn p.WaitForFunction(js, popts, pargs...) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForLoadState\": func(state string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameWaitForLoadStateOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForLoadState %q options: %w\", state, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, p.WaitForLoadState(state, popts) //nolint:wrapcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForNavigation\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\treturn mapWaitForNavigation(vu, p, opts)\n\t\t},\n\t\t\"waitForSelector\": func(selector string, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts := common.NewFrameWaitForSelectorOptions(p.MainFrame().Timeout())\n\t\t\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing wait for selector %q options: %w\", selector, err)\n\t\t\t}\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\teh, err := p.WaitForSelector(selector, popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\treturn mapElementHandle(vu, eh), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForTimeout\": func(timeout int64) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tp.WaitForTimeout(timeout)\n\t\t\t\treturn nil, nil\n\t\t\t})\n\t\t},\n\t\t\"waitForURL\": func(url sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\treturn mapWaitForURL(vu, p, url, opts)\n\t\t},\n\t\t\"waitForResponse\": func(url sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parsePageWaitForResponseOptions(vu.Context(), opts, p.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForResponse options: %w\", err)\n\t\t\t}\n\n\t\t\tvar val string\n\t\t\tswitch url.ExportType() {\n\t\t\tcase reflect.TypeFor[string]():\n\t\t\t\tval = \"'\" + url.String() + \"'\" // Strings require quotes\n\t\t\tdefault: // JS Regex, CSS, numbers or booleans\n\t\t\t\tval = url.String() // No quotes\n\t\t\t}\n\n\t\t\ttq, ctx, stop := newTaskQueue(vu)\n\n\t\t\treturn promise(vu, func() (result any, reason error) {\n\t\t\t\tdefer stop()\n\t\t\t\treturn p.WaitForResponse(val, popts, newRegExMatcher(ctx, vu, tq))\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForRequest\": func(url sobek.Value, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parsePageWaitForRequestOptions(vu.Context(), opts, p.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForRequest options: %w\", err)\n\t\t\t}\n\n\t\t\tvar val string\n\t\t\tswitch url.ExportType() {\n\t\t\tcase reflect.TypeFor[string]():\n\t\t\t\tval = \"'\" + url.String() + \"'\" // Strings require quotes\n\t\t\tdefault: // JS Regex, CSS, numbers or booleans\n\t\t\t\tval = url.String() // No quotes\n\t\t\t}\n\n\t\t\ttq, ctx, stop := newTaskQueue(vu)\n\n\t\t\treturn promise(vu, func() (result any, reason error) {\n\t\t\t\tdefer stop()\n\t\t\t\treturn p.WaitForRequest(val, popts, newRegExMatcher(ctx, vu, tq))\n\t\t\t}), nil\n\t\t},\n\t\t\"waitForEvent\": func(event common.PageEventName, opts sobek.Value) (*sobek.Promise, error) {\n\t\t\t// AVOID using a default case to force handling new event types explicitly\n\t\t\t// so that the linter can catch unhandled event types as non-exhaustive switch.\n\t\t\t// Otherwise, we might miss mapping new [PageEvent] types added in the future.\n\t\t\t// This is for keeping events in sync between waitForEvent and page.on.\n\t\t\tmapPageEvent := func(vu moduleVU, pe common.PageEvent) (mapping, error) {\n\t\t\t\tswitch event {\n\t\t\t\tcase common.PageEventConsole:\n\t\t\t\t\treturn mapConsoleMessage(vu, pe), nil\n\t\t\t\tcase common.PageEventRequest:\n\t\t\t\t\treturn mapRequestEvent(vu, pe), nil\n\t\t\t\tcase common.PageEventResponse:\n\t\t\t\t\treturn mapResponseEvent(vu, pe), nil\n\t\t\t\tcase common.PageEventRequestFinished:\n\t\t\t\t\treturn mapRequestEvent(vu, pe), nil\n\t\t\t\tcase common.PageEventRequestFailed:\n\t\t\t\t\treturn mapRequestEvent(vu, pe), nil\n\t\t\t\tcase common.PageEventMetric:\n\t\t\t\t\t// intentionally left blank\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"waitForEvent does not support mapping for event: %q\", event)\n\t\t\t}\n\n\t\t\tpopts, fn, err := parsePageWaitForEventOptions(vu.Context(), opts, p.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing waitForEvent options: %w\", err)\n\t\t\t}\n\n\t\t\tctx := vu.Context()\n\t\t\ttq := vu.get(ctx, p.TargetID())\n\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\trpe, err := p.WaitForEvent(event, popts, func(pe common.PageEvent) (bool, error) {\n\t\t\t\t\tif fn == nil {\n\t\t\t\t\t\treturn true, nil\n\t\t\t\t\t}\n\t\t\t\t\treturn queueTask(ctx, tq, func() (bool, error) {\n\t\t\t\t\t\tm, err := mapPageEvent(vu, pe)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn false, err\n\t\t\t\t\t\t}\n\t\t\t\t\t\tv, err := fn(sobek.Undefined(), vu.Runtime().ToValue(m))\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn false, fmt.Errorf(\"executing waitForEvent predicate: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn v.ToBoolean(), nil\n\t\t\t\t\t})()\n\t\t\t\t})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"waiting for page event %q: %w\", event, err)\n\t\t\t\t}\n\t\t\t\treturn mapPageEvent(vu, rpe)\n\t\t\t}), nil\n\t\t},\n\t\t\"workers\": func() *sobek.Object {\n\t\t\tworkers := p.Workers()\n\t\t\tmws := make([]mapping, 0, len(workers))\n\t\t\tfor _, w := range workers {\n\t\t\t\tmw := mapWorker(vu, w)\n\t\t\t\tmws = append(mws, mw)\n\t\t\t}\n\t\t\treturn rt.ToValue(mws).ToObject(rt)\n\t\t},\n\t}\n\tmaps[\"$\"] = func(selector string) *sobek.Promise {\n\t\treturn promise(vu, func() (any, error) {\n\t\t\teh, err := p.Query(selector)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t\t// ElementHandle can be null when the selector does not match any elements.\n\t\t\t// We do not want to map nil elementHandles since the expectation is a\n\t\t\t// null result in the test script for this case.\n\t\t\tif eh == nil {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\tehm := mapElementHandle(vu, eh)\n\n\t\t\treturn ehm, nil\n\t\t})\n\t}\n\tmaps[\"$$\"] = func(selector string) *sobek.Promise {\n\t\treturn promise(vu, func() (any, error) {\n\t\t\tehs, err := p.QueryAll(selector)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t\tvar mehs []mapping\n\t\t\tfor _, eh := range ehs {\n\t\t\t\tehm := mapElementHandle(vu, eh)\n\t\t\t\tmehs = append(mehs, ehm)\n\t\t\t}\n\t\t\treturn mehs, nil\n\t\t})\n\t}\n\n\treturn maps\n}\n\n// mapPageOn enables using various page.on event handlers with the page.on method.\n// It provides a generic way to map different event types to their respective handler functions.\nfunc mapPageOn(vu moduleVU, p *common.Page) func(common.PageEventName, sobek.Callable) error {\n\treturn func(eventName common.PageEventName, handle sobek.Callable) error {\n\t\tif handle == nil {\n\t\t\tpanic(vu.Runtime().NewTypeError(`The \"listener\" argument must be a function`))\n\t\t}\n\n\t\tpageEvents := map[common.PageEventName]struct {\n\t\t\tmapp func(vu moduleVU, event common.PageEvent) mapping\n\t\t\twait bool // Whether to wait for the handler to complete.\n\t\t}{\n\t\t\tcommon.PageEventConsole:         {mapp: mapConsoleMessage},\n\t\t\tcommon.PageEventMetric:          {mapp: mapMetricEvent, wait: true},\n\t\t\tcommon.PageEventRequest:         {mapp: mapRequestEvent},\n\t\t\tcommon.PageEventResponse:        {mapp: mapResponseEvent},\n\t\t\tcommon.PageEventRequestFinished: {mapp: mapRequestEvent},\n\t\t\tcommon.PageEventRequestFailed:   {mapp: mapRequestEvent},\n\t\t}\n\t\tpageEvent, ok := pageEvents[eventName]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unknown page on event: %q\", eventName)\n\t\t}\n\n\t\tctx := vu.Context()\n\t\ttq := vu.get(ctx, p.TargetID())\n\n\t\treturn p.On(eventName, func(event common.PageEvent) error {\n\t\t\twait := queueTask(ctx, tq, func() (sobek.Value, error) {\n\t\t\t\t_, err := handle(sobek.Undefined(), vu.Runtime().ToValue(pageEvent.mapp(vu, event)))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"executing page.on('%s') handler: %w\", eventName, err)\n\t\t\t\t}\n\t\t\t\treturn nil, nil\n\t\t\t})\n\t\t\tif pageEvent.wait {\n\t\t\t\tif _, err := wait(); errors.Is(err, context.Canceled) {\n\t\t\t\t\treturn errors.New(\"iteration ended before page.on handler completed executing\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n\t}\n}\n\nfunc parseWaitForFunctionArgs(\n\tctx context.Context, timeout time.Duration, pageFunc, opts sobek.Value, gargs ...sobek.Value,\n) (string, *common.FrameWaitForFunctionOptions, []any, error) {\n\tpopts := common.NewFrameWaitForFunctionOptions(timeout)\n\terr := popts.Parse(ctx, opts)\n\tif err != nil {\n\t\treturn \"\", nil, nil, fmt.Errorf(\"parsing waitForFunction options: %w\", err)\n\t}\n\n\tjs := pageFunc.ToString().String()\n\t_, isCallable := sobek.AssertFunction(pageFunc)\n\tif !isCallable {\n\t\tjs = fmt.Sprintf(\"() => (%s)\", js)\n\t}\n\n\treturn js, popts, exportArgs(gargs), nil\n}\n\n// parseStringOrRegex parses a sobek.Value to return either a quoted string if it was a string,\n// or a raw string if it was a JS RegExp object or another type.\n//\n// Some getBy* APIs work with single quotes and some work with double quotes.\n// This inconsistency seems to stem from the injected code copied from\n// Playwright itself.\n//\n// I would prefer not to change the copied injected script code from Playwright\n// so that it is easier to copy over updates/fixes from Playwright when we need\n// to.\nfunc parseStringOrRegex(v sobek.Value, doubleQuote bool) string {\n\tvar a string\n\tswitch v.ExportType() {\n\tcase reflect.TypeFor[string](): // text values require quotes\n\t\tif doubleQuote {\n\t\t\ta = `\"` + strings.ReplaceAll(v.String(), `\"`, `\\\"`) + `\"`\n\t\t} else {\n\t\t\ta = `'` + strings.ReplaceAll(v.String(), `'`, `\\'`) + `'`\n\t\t}\n\tcase reflect.TypeFor[map[string]any](): // JS RegExp\n\t\ta = v.String() // No quotes\n\tdefault: // CSS, numbers or booleans\n\t\ta = v.String() // No quotes\n\t}\n\treturn a\n}\n\n// parseGetByRoleOptions parses the GetByRole options from the Sobek.Value.\nfunc parseGetByRoleOptions(ctx context.Context, opts sobek.Value) *common.GetByRoleOptions {\n\tif k6common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\to := &common.GetByRoleOptions{}\n\n\trt := k6ext.Runtime(ctx)\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"checked\":\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.Checked = &val\n\t\tcase \"disabled\":\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.Disabled = &val\n\t\tcase \"exact\":\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.Exact = &val\n\t\tcase \"expanded\":\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.Expanded = &val\n\t\tcase \"includeHidden\":\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.IncludeHidden = &val\n\t\tcase \"level\":\n\t\t\tval := obj.Get(k).ToInteger()\n\t\t\to.Level = &val\n\t\tcase \"name\":\n\t\t\tval := parseStringOrRegex(obj.Get(k), false)\n\t\t\to.Name = &val\n\t\tcase \"pressed\":\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.Pressed = &val\n\t\tcase \"selected\":\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.Selected = &val\n\t\t}\n\t}\n\n\treturn o\n}\n\n// parseGetByBaseOptions parses the options for the GetBy* APIs and the input\n// text/regex.\nfunc parseGetByBaseOptions(\n\tctx context.Context,\n\tinput sobek.Value,\n\tdoubleQuote bool,\n\topts sobek.Value,\n) (string, *common.GetByBaseOptions) {\n\ta := parseStringOrRegex(input, doubleQuote)\n\n\tif k6common.IsNullish(opts) {\n\t\treturn a, nil\n\t}\n\n\to := &common.GetByBaseOptions{}\n\n\trt := k6ext.Runtime(ctx)\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tif k == \"exact\" {\n\t\t\tval := obj.Get(k).ToBoolean()\n\t\t\to.Exact = &val\n\t\t}\n\t}\n\n\treturn a, o\n}\n\n// mapPageRoute maps the requested page.route event to the Sobek runtime.\nfunc mapPageRoute(vu moduleVU, p *common.Page) func(sobek.Value, sobek.Callable) (*sobek.Promise, error) {\n\treturn func(path sobek.Value, cb sobek.Callable) (*sobek.Promise, error) {\n\t\tctx := vu.Context()\n\n\t\tppath := parseStringOrRegex(path, false)\n\t\ttq := vu.get(ctx, p.TargetID())\n\n\t\troute := func(r *common.Route) error {\n\t\t\t_, err := queueTask(ctx, tq, func() (any, error) {\n\t\t\t\treturn cb(sobek.Undefined(), vu.Runtime().ToValue(mapRoute(vu, r)))\n\t\t\t})()\n\t\t\tif errors.Is(err, context.Canceled) {\n\t\t\t\treturn fmt.Errorf(\"page.route('%s'): iteration ended before route completed\", path)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"page.route('%s'): %w\", path, err)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\treturn promise(vu, func() (any, error) {\n\t\t\treturn nil, p.Route(ppath, route, newRegExMatcher(ctx, vu, tq))\n\t\t}), nil\n\t}\n}\n\nfunc mapWaitForURL(vu moduleVU, target interface {\n\tTimeout() time.Duration\n\tWaitForURL(urlPattern string, opts *common.FrameWaitForURLOptions, rm common.RegExMatcher) error\n}, url sobek.Value, opts sobek.Value,\n) (*sobek.Promise, error) {\n\tif k6common.IsNullish(url) {\n\t\treturn nil, errors.New(\"missing required argument 'url'\")\n\t}\n\tpopts := common.NewFrameWaitForURLOptions(target.Timeout())\n\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing waitForURL options: %w\", err)\n\t}\n\n\tpurl := parseStringOrRegex(url, false)\n\ttq, ctx, stop := newTaskQueue(vu)\n\n\treturn promise(vu, func() (result any, reason error) {\n\t\tdefer stop()\n\t\treturn nil, target.WaitForURL(purl, popts, newRegExMatcher(ctx, vu, tq))\n\t}), nil\n}\n\nfunc mapWaitForNavigation(vu moduleVU, target interface {\n\tTimeout() time.Duration\n\tWaitForNavigation(*common.FrameWaitForNavigationOptions, common.RegExMatcher) (*common.Response, error)\n}, opts sobek.Value,\n) (*sobek.Promise, error) {\n\tpopts := common.NewFrameWaitForNavigationOptions(target.Timeout())\n\tif err := popts.Parse(vu.Context(), opts); err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing frame wait for navigation options: %w\", err)\n\t}\n\n\t// Only use task queue and RegExMatcher if a URL is specified.\n\trm, stop := func() (common.RegExMatcher, func()) {\n\t\tif popts.URL == \"\" {\n\t\t\treturn nil, func() {}\n\t\t}\n\t\ttq, ctx, stop := newTaskQueue(vu)\n\t\treturn newRegExMatcher(ctx, vu, tq), stop\n\t}()\n\n\treturn promise(vu, func() (any, error) {\n\t\tdefer stop()\n\n\t\tresp, err := target.WaitForNavigation(popts, rm)\n\t\tif err != nil {\n\t\t\treturn nil, err //nolint:wrapcheck\n\t\t}\n\t\treturn mapResponse(vu, resp), nil\n\t}), nil\n}\n\nfunc parsePageWaitForResponseOptions(\n\tctx context.Context, opts sobek.Value, defaultTimeout time.Duration,\n) (*common.PageWaitForResponseOptions, error) {\n\tropts := common.NewPageWaitForResponseOptions(defaultTimeout)\n\tif k6common.IsNullish(opts) {\n\t\treturn ropts, nil\n\t}\n\n\trt := k6ext.Runtime(ctx)\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"timeout\":\n\t\t\tropts.Timeout = time.Duration(obj.Get(k).ToInteger()) * time.Millisecond\n\t\tdefault:\n\t\t\treturn ropts, fmt.Errorf(\"unsupported waitForResponse option: '%s'\", k)\n\t\t}\n\t}\n\n\treturn ropts, nil\n}\n\nfunc parsePageWaitForRequestOptions(\n\tctx context.Context, opts sobek.Value, defaultTimeout time.Duration,\n) (*common.PageWaitForRequestOptions, error) {\n\tropts := common.PageWaitForRequestOptions{\n\t\tTimeout: defaultTimeout,\n\t}\n\n\tif k6common.IsNullish(opts) {\n\t\treturn &ropts, nil\n\t}\n\n\tobj := opts.ToObject(k6ext.Runtime(ctx))\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"timeout\":\n\t\t\tropts.Timeout = time.Duration(obj.Get(k).ToInteger()) * time.Millisecond\n\t\tdefault:\n\t\t\treturn &ropts, fmt.Errorf(\"unsupported waitForRequest option: '%s'\", k)\n\t\t}\n\t}\n\n\treturn &ropts, nil\n}\n\nfunc parsePageWaitForEventOptions(\n\tctx context.Context, opts sobek.Value, defaultTimeout time.Duration,\n) (*common.PageWaitForEventOptions, sobek.Callable, error) {\n\tropts := &common.PageWaitForEventOptions{\n\t\tTimeout: defaultTimeout,\n\t}\n\n\tif k6common.IsNullish(opts) {\n\t\treturn ropts, nil, nil\n\t}\n\n\tif fn, ok := sobek.AssertFunction(opts); ok {\n\t\treturn ropts, fn, nil\n\t}\n\n\tobj := opts.ToObject(k6ext.Runtime(ctx))\n\n\tvar pred sobek.Callable\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"timeout\":\n\t\t\tropts.Timeout = time.Duration(obj.Get(k).ToInteger()) * time.Millisecond\n\t\tcase \"predicate\":\n\t\t\tfn, ok := sobek.AssertFunction(obj.Get(k))\n\t\t\tif !ok {\n\t\t\t\treturn nil, nil, fmt.Errorf(\"predicate must be a function\")\n\t\t\t}\n\t\t\tpred = fn\n\t\tdefault:\n\t\t\treturn nil, nil, fmt.Errorf(\"waitForEvent does not support option: '%s'\", k)\n\t\t}\n\t}\n\n\treturn ropts, pred, nil\n}\n\n// parseSize parses the size options from a Sobek value.\nfunc parseSize(rt *sobek.Runtime, opts sobek.Value) (*common.Size, error) {\n\tsize := &common.Size{}\n\tif k6common.IsNullish(opts) {\n\t\treturn size, nil\n\t}\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tv := obj.Get(k)\n\t\tif k6common.IsNullish(v) {\n\t\t\tcontinue\n\t\t}\n\t\tswitch k {\n\t\tcase \"width\":\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64, reflect.Float64:\n\t\t\t\tsize.Width = v.ToFloat()\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"width must be a number, got %s\", v.ExportType().Kind())\n\t\t\t}\n\t\tcase \"height\":\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64, reflect.Float64:\n\t\t\t\tsize.Height = v.ToFloat()\n\t\t\tdefault:\n\t\t\t\treturn nil, fmt.Errorf(\"height must be a number, got %s\", v.ExportType().Kind())\n\t\t\t}\n\t\t}\n\t}\n\n\treturn size, nil\n}\n\n// parsePageEmulateMediaOptions parses the page emulate media options from a Sobek value.\n//\n//nolint:unparam\nfunc parsePageEmulateMediaOptions(\n\trt *sobek.Runtime, opts sobek.Value, defaults *common.PageEmulateMediaOptions,\n) (*common.PageEmulateMediaOptions, error) {\n\tif k6common.IsNullish(opts) {\n\t\treturn defaults, nil\n\t}\n\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"colorScheme\":\n\t\t\tdefaults.ColorScheme = common.ColorScheme(obj.Get(k).String())\n\t\tcase \"media\":\n\t\t\tdefaults.Media = common.MediaType(obj.Get(k).String())\n\t\tcase \"reducedMotion\":\n\t\t\tdefaults.ReducedMotion = common.ReducedMotion(obj.Get(k).String())\n\t\t}\n\t}\n\n\treturn defaults, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/page_mapping_test.go",
    "content": "package browser\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n)\n\nfunc TestParseStringOrRegex(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\tmk := func(code string) sobek.Value {\n\t\tv, err := rt.RunString(code)\n\t\trequire.NoError(t, err)\n\t\treturn v\n\t}\n\n\ttests := []struct {\n\t\tname        string\n\t\tinput       sobek.Value\n\t\tdoubleQuote bool\n\t\twant        string\n\t}{\n\t\t{name: \"string_single_quote\", input: mk(`'abc'`), doubleQuote: false, want: `'abc'`},\n\t\t{name: \"string_single_quote\", input: mk(`'abc'`), doubleQuote: true, want: `\"abc\"`},\n\t\t{name: \"string_double_quote\", input: mk(`\"abc\"`), doubleQuote: true, want: `\"abc\"`},\n\t\t{name: \"string_double_quote\", input: mk(`\"abc\"`), doubleQuote: false, want: `'abc'`},\n\t\t{name: \"regex_literal\", input: mk(`/ab+c/i`), doubleQuote: false, want: `/ab+c/i`},\n\t\t{name: \"number\", input: mk(`123`), doubleQuote: true, want: `123`},\n\t\t{name: \"boolean\", input: mk(`true`), doubleQuote: false, want: `true`},\n\t\t{name: \"object\", input: mk(`({a:1})`), doubleQuote: false, want: `[object Object]`},\n\t\t{name: \"null\", input: mk(`null`), doubleQuote: false, want: `null`},\n\t\t{name: \"undefined\", input: mk(`undefined`), doubleQuote: false, want: `undefined`},\n\t\t{name: \"undefined\", input: mk(``), doubleQuote: false, want: `undefined`},\n\t\t{name: \"string_with_single_quote\", input: mk(`'abc\\''`), doubleQuote: false, want: `'abc\\''`},\n\t\t{name: \"string_with_single_quote\", input: mk(`'abc\\''`), doubleQuote: true, want: `\"abc'\"`},\n\t\t{name: \"string_with_double_quote\", input: mk(`'abc\"'`), doubleQuote: false, want: `'abc\"'`},\n\t\t{name: \"string_with_double_quote\", input: mk(`'abc\"'`), doubleQuote: true, want: `\"abc\\\"\"`},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tgot := parseStringOrRegex(tc.input, tc.doubleQuote)\n\t\t\trequire.Equal(t, tc.want, got)\n\t\t})\n\t}\n}\n\nfunc TestParseSize(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname    string\n\t\tinput   string\n\t\twant    *common.Size\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:  \"defaults_on_null\",\n\t\t\tinput: `null`,\n\t\t\twant:  &common.Size{Width: 0, Height: 0},\n\t\t},\n\t\t{\n\t\t\tname:  \"all_options\",\n\t\t\tinput: `({width: 1920, height: 1080})`,\n\t\t\twant:  &common.Size{Width: 1920, Height: 1080},\n\t\t},\n\t\t{\n\t\t\tname:  \"partial_width_only\",\n\t\t\tinput: `({width: 1920})`,\n\t\t\twant:  &common.Size{Width: 1920, Height: 0},\n\t\t},\n\t\t{\n\t\t\tname:  \"float_width\",\n\t\t\tinput: `({width: 1920.5, height: 1080})`,\n\t\t\twant:  &common.Size{Width: 1920.5, Height: 1080},\n\t\t},\n\t\t{\n\t\t\tname:  \"float_height\",\n\t\t\tinput: `({width: 1920, height: 1080.5})`,\n\t\t\twant:  &common.Size{Width: 1920, Height: 1080.5},\n\t\t},\n\t\t{\n\t\t\tname:  \"null_width\",\n\t\t\tinput: `({width: null, height: 1080})`,\n\t\t\twant:  &common.Size{Width: 0, Height: 1080},\n\t\t},\n\t\t{\n\t\t\tname:  \"undefined_width\",\n\t\t\tinput: `({width: undefined, height: 1080})`,\n\t\t\twant:  &common.Size{Width: 0, Height: 1080},\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_width_string\",\n\t\t\tinput:   `({width: \"1920\", height: 1080})`,\n\t\t\twantErr: \"width must be a number\",\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_height_string\",\n\t\t\tinput:   `({width: 1920, height: \"1080\"})`,\n\t\t\twantErr: \"height must be a number\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\tv, err := vu.Runtime().RunString(tt.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts, err := parseSize(vu.Runtime(), v)\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, opts)\n\t\t})\n\t}\n}\n\nfunc TestParsePageEmulateMediaOptions(t *testing.T) {\n\tt.Parallel()\n\n\tnewDefaults := func() *common.PageEmulateMediaOptions {\n\t\treturn &common.PageEmulateMediaOptions{\n\t\t\tColorScheme:   common.ColorSchemeLight,\n\t\t\tMedia:         common.MediaTypeScreen,\n\t\t\tReducedMotion: common.ReducedMotionNoPreference,\n\t\t}\n\t}\n\n\ttests := []struct {\n\t\tname  string\n\t\tinput string\n\t\twant  *common.PageEmulateMediaOptions\n\t}{\n\t\t{\n\t\t\tname:  \"defaults_on_null\",\n\t\t\tinput: `null`,\n\t\t\twant:  newDefaults(),\n\t\t},\n\t\t{\n\t\t\tname:  \"all_options\",\n\t\t\tinput: `({colorScheme: \"dark\", media: \"print\", reducedMotion: \"reduce\"})`,\n\t\t\twant: &common.PageEmulateMediaOptions{\n\t\t\t\tColorScheme:   \"dark\",\n\t\t\t\tMedia:         \"print\",\n\t\t\t\tReducedMotion: \"reduce\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:  \"partial_option\",\n\t\t\tinput: `({media: \"print\"})`,\n\t\t\twant: &common.PageEmulateMediaOptions{\n\t\t\t\tColorScheme:   common.ColorSchemeLight,\n\t\t\t\tMedia:         \"print\",\n\t\t\t\tReducedMotion: common.ReducedMotionNoPreference,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\tv, err := vu.Runtime().RunString(tt.input)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts, err := parsePageEmulateMediaOptions(vu.Runtime(), v, newDefaults())\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, opts)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/registry.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\t\"crypto/rand\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/mstoykov/k6-taskqueue-lib/taskqueue\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\toteltrace \"go.opentelemetry.io/otel/trace\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/chromium\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\tbrowsertrace \"go.k6.io/k6/internal/js/modules/k6/browser/trace\"\n\n\tk6event \"go.k6.io/k6/internal/event\"\n\tk6modules \"go.k6.io/k6/js/modules\"\n)\n\n// errBrowserNotFoundInRegistry indicates that the browser instance\n// for the iteration, which should have been initialized as a result\n// of the IterStart event, has not been found in the registry. This\n// might happen if browser type option is not set in scenario definition.\nvar errBrowserNotFoundInRegistry = errors.New(\"browser not found in registry. \" +\n\t\"make sure to set browser type option in scenario definition in order to use the browser module\")\n\n// pidRegistry keeps track of the launched browser process IDs.\ntype pidRegistry struct {\n\tmu  sync.RWMutex\n\tids []int\n}\n\n// registerPid registers the launched browser process ID.\nfunc (r *pidRegistry) registerPid(pid int) {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\tr.ids = append(r.ids, pid)\n}\n\n// Pids returns the launched browser process IDs.\nfunc (r *pidRegistry) Pids() []int {\n\tr.mu.RLock()\n\tdefer r.mu.RUnlock()\n\n\tpids := make([]int, len(r.ids))\n\tcopy(pids, r.ids)\n\n\treturn pids\n}\n\n// remoteRegistry contains the details of the remote web browsers.\n// At the moment it's the WS URLs.\ntype remoteRegistry struct {\n\tisRemote bool\n\twsURLs   []string\n}\n\n// newRemoteRegistry will create a new RemoteRegistry. This will\n// parse the K6_BROWSER_WS_URL env var to retrieve the defined\n// list of WS URLs.\n//\n// K6_BROWSER_WS_URL can be defined as a single WS URL or a\n// comma separated list of URLs.\nfunc newRemoteRegistry(envLookup env.LookupFunc) (*remoteRegistry, error) {\n\tr := &remoteRegistry{}\n\n\tisRemote, wsURLs, err := checkForScenarios(envLookup)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif isRemote {\n\t\tr.isRemote = isRemote\n\t\tr.wsURLs = wsURLs\n\t\treturn r, nil\n\t}\n\n\tr.isRemote, r.wsURLs = checkForBrowserWSURLs(envLookup)\n\n\treturn r, nil\n}\n\nfunc checkForBrowserWSURLs(envLookup env.LookupFunc) (bool, []string) {\n\twsURL, isRemote := envLookup(env.WebSocketURLs)\n\tif !isRemote {\n\t\treturn false, nil\n\t}\n\n\tif !strings.ContainsRune(wsURL, ',') {\n\t\treturn true, []string{wsURL}\n\t}\n\n\t// If last parts element is a void string,\n\t// because WS URL contained an ending comma,\n\t// remove it\n\tparts := strings.Split(wsURL, \",\")\n\tif parts[len(parts)-1] == \"\" {\n\t\tparts = parts[:len(parts)-1]\n\t}\n\n\treturn true, parts\n}\n\n// checkForScenarios will parse the K6_INSTANCE_SCENARIOS env var if\n// it has been defined.\nfunc checkForScenarios(envLookup env.LookupFunc) (bool, []string, error) {\n\tscenariosJSON, isRemote := envLookup(env.InstanceScenarios)\n\tif !isRemote {\n\t\treturn false, nil, nil\n\t}\n\t// prevent failing in unquoting empty string.\n\tif scenariosJSON == \"\" {\n\t\treturn false, nil, nil\n\t}\n\tscenariosJSON, err := strconv.Unquote(scenariosJSON)\n\tif err != nil {\n\t\treturn false, nil, fmt.Errorf(\"unqouting K6_INSTANCE_SCENARIOS: %w\", err)\n\t}\n\n\tvar scenarios []struct {\n\t\tID       string `json:\"id\"`\n\t\tBrowsers []struct {\n\t\t\tHandle string `json:\"handle\"`\n\t\t} `json:\"browsers\"`\n\t}\n\tif err := json.Unmarshal([]byte(scenariosJSON), &scenarios); err != nil {\n\t\treturn false, nil, fmt.Errorf(\"parsing K6_INSTANCE_SCENARIOS: %w\", err)\n\t}\n\n\tvar wsURLs []string\n\tfor _, s := range scenarios {\n\t\tfor _, b := range s.Browsers {\n\t\t\tif strings.TrimSpace(b.Handle) == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\twsURLs = append(wsURLs, b.Handle)\n\t\t}\n\t}\n\tif len(wsURLs) == 0 {\n\t\treturn false, wsURLs, nil\n\t}\n\n\treturn true, wsURLs, nil\n}\n\n// isRemoteBrowser returns a WS URL and true when a WS URL is defined,\n// otherwise it returns an empty string and false. If more than one\n// WS URL was registered in newRemoteRegistry, a randomly chosen URL from\n// the list in a round-robin fashion is selected and returned.\nfunc (r *remoteRegistry) isRemoteBrowser() (string, bool) {\n\tif !r.isRemote {\n\t\treturn \"\", false\n\t}\n\n\t// Choose a random WS URL from the provided list\n\ti, _ := rand.Int(rand.Reader, big.NewInt(int64(len(r.wsURLs))))\n\twsURL := r.wsURLs[i.Int64()]\n\n\treturn wsURL, true\n}\n\n// browserRegistry stores a single VU browser instances\n// indexed per iteration.\ntype browserRegistry struct {\n\tvu k6modules.VU\n\n\ttr             *tracesRegistry\n\ttrInit         sync.Once\n\ttracesMetadata map[string]string\n\n\tmu sync.RWMutex\n\tm  map[int64]*common.Browser\n\n\tbuildFn browserBuildFunc\n}\n\ntype browserBuildFunc func(ctx, vuCtx context.Context) (*common.Browser, error)\n\n// newBrowserRegistry should only take a background context, not a context from\n// k6 (i.e. vu). The reason for this is that we want to control the chromium\n// lifecycle with the k6 event system.\n//\n// The k6 event system gives this extension time to properly cleanup any running\n// chromium subprocesses or connections to a remote chromium instance.\n//\n// A vu context (a context on an iteration) doesn't allow us to do this. Once k6\n// closes a vu context, it basically pulls the rug from under the extensions feet.\nfunc newBrowserRegistry(\n\tctx context.Context,\n\tvu k6modules.VU,\n\tremote *remoteRegistry,\n\tpids *pidRegistry,\n\ttracesMetadata map[string]string,\n) *browserRegistry {\n\tbt := chromium.NewBrowserType(vu)\n\tbuilder := func(ctx, vuCtx context.Context) (*common.Browser, error) {\n\t\tvar (\n\t\t\terr                    error\n\t\t\tb                      *common.Browser\n\t\t\twsURL, isRemoteBrowser = remote.isRemoteBrowser()\n\t\t)\n\n\t\tif isRemoteBrowser {\n\t\t\tb, err = bt.Connect(ctx, vuCtx, wsURL)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t} else {\n\t\t\tvar pid int\n\t\t\tb, pid, err = bt.Launch(ctx, vuCtx)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t}\n\t\t\tpids.registerPid(pid)\n\t\t}\n\n\t\treturn b, nil\n\t}\n\n\tr := &browserRegistry{\n\t\tvu:             vu,\n\t\ttracesMetadata: tracesMetadata,\n\t\tm:              make(map[int64]*common.Browser),\n\t\tbuildFn:        builder,\n\t}\n\n\texitSubID, exitCh := vu.Events().Global.Subscribe(\n\t\tk6event.Exit,\n\t)\n\titerSubID, eventsCh := vu.Events().Local.Subscribe(\n\t\tk6event.IterStart,\n\t\tk6event.IterEnd,\n\t)\n\tunsubscribe := func() {\n\t\tvu.Events().Local.Unsubscribe(iterSubID)\n\t\tvu.Events().Global.Unsubscribe(exitSubID)\n\t}\n\n\tgo r.handleExitEvent(exitCh, unsubscribe)\n\tgo r.handleIterEvents(ctx, eventsCh)\n\n\treturn r\n}\n\nfunc (r *browserRegistry) handleIterEvents(\n\tctx context.Context, eventsCh <-chan *k6event.Event,\n) {\n\tvar (\n\t\tok   bool\n\t\tdata k6event.IterData\n\t)\n\n\tfor e := range eventsCh {\n\t\t// If browser module is imported in the test, NewModuleInstance will be called for\n\t\t// every VU. Because on VU init stage we can not distinguish to which scenario it\n\t\t// belongs or access its options (because state is nil), we have to always subscribe\n\t\t// to each VU iter events, including VUs that do not make use of the browser in their\n\t\t// iterations.\n\t\t// Therefore, if we get an event that does not correspond to a browser iteration, then\n\t\t// skip this iteration. We can't just unsubscribe as the VU might be reused in a later\n\t\t// scenario that does have browser setup.\n\t\t// TODO try to maybe do this only once per scenario\n\t\tif !isBrowserIter(r.vu) {\n\t\t\te.Done()\n\t\t\tcontinue\n\t\t}\n\n\t\t// The context in the VU is not thread safe. It can\n\t\t// be safely accessed during an iteration but not\n\t\t// before one is started. This is why it is being\n\t\t// accessed and used here.\n\t\tvuCtx := k6ext.WithVU(r.vu.Context(), r.vu)\n\n\t\tif data, ok = e.Data.(k6event.IterData); !ok {\n\t\t\te.Done()\n\t\t\tk6ext.Abortf(vuCtx, \"unexpected iteration event data format: %v\", e.Data)\n\t\t\t// Continue so we don't block the k6 event system producer.\n\t\t\t// Test will be aborted by k6, which will previously send the\n\t\t\t// 'Exit' event so browser resources cleanup can be guaranteed.\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch e.Type {\n\t\tcase k6event.IterStart:\n\t\t\t// Because VU.State is nil when browser registry is initialized,\n\t\t\t// we have to initialize traces registry on the first VU iteration\n\t\t\t// so we can get access to the k6 TracerProvider.\n\t\t\tr.initTracesRegistry()\n\n\t\t\t// Wrap the tracer into the VU context to make it accessible for the\n\t\t\t// other components during the iteration that inherit the VU context.\n\t\t\t//\n\t\t\t// All browser APIs should work with the vu context, and allow the\n\t\t\t// k6 iteration control its lifecycle.\n\t\t\ttracerCtx := common.WithTracer(r.vu.Context(), r.tr.tracer)\n\t\t\ttracedCtx := r.tr.startIterationTrace(tracerCtx, data)\n\n\t\t\tb, err := r.buildFn(ctx, tracedCtx)\n\t\t\tif err != nil {\n\t\t\t\te.Done()\n\t\t\t\tk6ext.Abortf(vuCtx, \"error building browser on IterStart: %v\", err)\n\t\t\t\t// Continue so we don't block the k6 event system producer.\n\t\t\t\t// Test will be aborted by k6, which will previously send the\n\t\t\t\t// 'Exit' event so browser resources cleanup can be guaranteed.\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tr.setBrowser(data.Iteration, b)\n\t\tcase k6event.IterEnd:\n\t\t\tr.deleteBrowser(data.Iteration)\n\t\t\tr.tr.endIterationTrace(data.Iteration)\n\t\tdefault:\n\t\t\tr.vu.State().Logger.Warnf(\"received unexpected event type: %v\", e.Type)\n\t\t}\n\n\t\te.Done()\n\t}\n}\n\nfunc (r *browserRegistry) handleExitEvent(exitCh <-chan *k6event.Event, unsubscribeFn func()) {\n\tdefer unsubscribeFn()\n\n\te, ok := <-exitCh\n\tif !ok {\n\t\treturn\n\t}\n\tdefer e.Done()\n\tr.clear()\n\n\t// Stop traces registry before calling e.Done()\n\t// so we avoid a race condition between active spans\n\t// being flushed and test exiting\n\tr.stopTracesRegistry()\n}\n\nfunc (r *browserRegistry) setBrowser(id int64, b *common.Browser) {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\tr.m[id] = b\n}\n\nfunc (r *browserRegistry) getBrowser(id int64) (*common.Browser, error) {\n\tr.mu.RLock()\n\tdefer r.mu.RUnlock()\n\n\tif b, ok := r.m[id]; ok {\n\t\treturn b, nil\n\t}\n\n\treturn nil, errBrowserNotFoundInRegistry\n}\n\nfunc (r *browserRegistry) deleteBrowser(id int64) {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\tif b, ok := r.m[id]; ok {\n\t\tb.Close()\n\t\tdelete(r.m, id)\n\t}\n}\n\n// This is only used in a test. Avoids having to manipulate the mutex in the\n// test itself.\nfunc (r *browserRegistry) browserCount() int {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\treturn len(r.m)\n}\n\nfunc (r *browserRegistry) clear() {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\tfor id, b := range r.m {\n\t\tb.Close()\n\t\tdelete(r.m, id)\n\t}\n}\n\n// initTracesRegistry must only be called within an iteration execution,\n// as it requires access to the k6 TracerProvider which is only accessible\n// through the VU.State during the iteration execution time span.\nfunc (r *browserRegistry) initTracesRegistry() {\n\t// Use a sync.Once so the traces registry is only initialized once\n\t// per VU, as that is the scope for both browser and traces registry.\n\tr.trInit.Do(func() {\n\t\tr.tr = newTracesRegistry(\n\t\t\tbrowsertrace.NewTracer(r.vu.State().TracerProvider, r.tracesMetadata),\n\t\t)\n\t})\n}\n\nfunc (r *browserRegistry) stopTracesRegistry() {\n\t// Because traces registry is initialized on iterStart event, it is not\n\t// initialized for the initial NewModuleInstance call, whose VU does not\n\t// execute any iteration.\n\tif r.tr != nil {\n\t\tr.tr.stop()\n\t}\n}\n\nfunc isBrowserIter(vu k6modules.VU) bool {\n\topts := k6ext.GetScenarioOpts(vu.Context(), vu)\n\t_, ok := opts[\"type\"] // Check if browser type option is set\n\treturn ok\n}\n\n// trace represents a traces registry entry which holds the\n// root span for the trace and a context that wraps that span.\ntype trace struct {\n\tctx      context.Context\n\trootSpan oteltrace.Span\n}\n\n// tracesRegistry holds the traces for all iterations of a single VU.\ntype tracesRegistry struct {\n\ttracer *browsertrace.Tracer\n\n\tmu sync.Mutex\n\tm  map[int64]*trace\n}\n\nfunc newTracesRegistry(tracer *browsertrace.Tracer) *tracesRegistry {\n\treturn &tracesRegistry{\n\t\ttracer: tracer,\n\t\tm:      make(map[int64]*trace),\n\t}\n}\n\nfunc (r *tracesRegistry) startIterationTrace(ctx context.Context, data k6event.IterData) context.Context {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\tif t, ok := r.m[data.Iteration]; ok {\n\t\treturn t.ctx\n\t}\n\n\tspanCtx, span := r.tracer.Start(ctx, \"iteration\", oteltrace.WithAttributes(\n\t\tattribute.Int64(\"test.iteration.number\", data.Iteration),\n\t\tattribute.Int64(\"test.vu\", int64(data.VUID)), //nolint:gosec\n\t\tattribute.String(\"test.scenario\", data.ScenarioName),\n\t))\n\n\tr.m[data.Iteration] = &trace{\n\t\tctx:      spanCtx,\n\t\trootSpan: span,\n\t}\n\n\treturn spanCtx\n}\n\nfunc (r *tracesRegistry) endIterationTrace(iter int64) {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\tif t, ok := r.m[iter]; ok {\n\t\tt.rootSpan.End()\n\t\tdelete(r.m, iter)\n\t}\n}\n\nfunc (r *tracesRegistry) stop() {\n\t// End all iteration traces\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\tfor k, v := range r.m {\n\t\tv.rootSpan.End()\n\t\tdelete(r.m, k)\n\t}\n}\n\n// This is only used in a test. Avoids having to manipulate the mutex in the\n// test itself.\nfunc (r *tracesRegistry) iterationTracesCount() int {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\n\treturn len(r.m)\n}\n\nfunc parseTracesMetadata(envLookup env.LookupFunc) (map[string]string, error) {\n\tvar (\n\t\tok bool\n\t\tv  string\n\t\tm  = make(map[string]string)\n\t)\n\tif v, ok = envLookup(env.TracesMetadata); !ok {\n\t\treturn m, nil\n\t}\n\n\tfor elem := range strings.SplitSeq(v, \",\") {\n\t\tkv := strings.Split(elem, \"=\")\n\t\tif len(kv) != 2 {\n\t\t\treturn nil, fmt.Errorf(\"%q is not a valid key=value metadata\", elem)\n\t\t}\n\t\tm[kv[0]] = kv[1]\n\t}\n\n\treturn m, nil\n}\n\ntype taskQueueRegistry struct {\n\tvu k6modules.VU\n\n\ttqMu sync.Mutex\n\ttq   map[string]*taskqueue.TaskQueue\n}\n\nfunc newTaskQueueRegistry(vu k6modules.VU) *taskQueueRegistry {\n\treturn &taskQueueRegistry{\n\t\tvu:   vu,\n\t\ttqMu: sync.Mutex{},\n\t\ttq:   make(map[string]*taskqueue.TaskQueue),\n\t}\n}\n\n// get will retrieve the taskqueue associated with the given targetID. If one\n// doesn't exist then a new taskqueue will be created.\n//\n// ctx must be the context from the VU, so that we can automatically close the\n// taskqueue when the iteration ends.\nfunc (t *taskQueueRegistry) get(ctx context.Context, targetID string) *taskqueue.TaskQueue {\n\tt.tqMu.Lock()\n\tdefer t.tqMu.Unlock()\n\n\ttq := t.tq[targetID]\n\tif tq == nil {\n\t\ttq = taskqueue.New(t.vu.RegisterCallback)\n\t\tt.tq[targetID] = tq\n\n\t\t// We want to ensure that the taskqueue is closed when the context is\n\t\t// closed.\n\t\tgo func(ctx context.Context) {\n\t\t\t<-ctx.Done()\n\n\t\t\ttq.Close()\n\t\t}(ctx)\n\t}\n\n\treturn tq\n}\n\nfunc (t *taskQueueRegistry) close(targetID string) {\n\tt.tqMu.Lock()\n\tdefer t.tqMu.Unlock()\n\n\ttq := t.tq[targetID]\n\tif tq != nil {\n\t\ttq.Close()\n\t\tdelete(t.tq, targetID)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/registry_test.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strconv\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\n\tk6event \"go.k6.io/k6/internal/event\"\n)\n\nfunc TestPidRegistry(t *testing.T) {\n\tt.Parallel()\n\n\tp := &pidRegistry{}\n\n\tvar wg sync.WaitGroup\n\titeration := 100\n\texpected := make([]int, 0, iteration)\n\twg.Add(iteration)\n\tfor i := range iteration {\n\t\tgo func(i int) {\n\t\t\tp.registerPid(i)\n\t\t\twg.Done()\n\t\t}(i)\n\t\texpected = append(expected, i)\n\t}\n\n\twg.Wait()\n\n\tgot := p.Pids()\n\n\tassert.ElementsMatch(t, expected, got)\n}\n\nfunc TestIsRemoteBrowser(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname                    string\n\t\tenvVarName, envVarValue string\n\t\texpIsRemote             bool\n\t\texpValidWSURLs          []string\n\t\texpErr                  error\n\t}{\n\t\t{\n\t\t\tname:        \"browser is not remote\",\n\t\t\tenvVarName:  \"FOO\",\n\t\t\tenvVarValue: \"BAR\",\n\t\t\texpIsRemote: false,\n\t\t},\n\t\t{\n\t\t\tname:           \"single WS URL\",\n\t\t\tenvVarName:     env.WebSocketURLs,\n\t\t\tenvVarValue:    \"WS_URL\",\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"WS_URL\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"multiple WS URL\",\n\t\t\tenvVarName:     env.WebSocketURLs,\n\t\t\tenvVarValue:    \"WS_URL_1,WS_URL_2,WS_URL_3\",\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"WS_URL_1\", \"WS_URL_2\", \"WS_URL_3\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"ending comma is handled\",\n\t\t\tenvVarName:     env.WebSocketURLs,\n\t\t\tenvVarValue:    \"WS_URL_1,WS_URL_2,\",\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"WS_URL_1\", \"WS_URL_2\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"void string does not panic\",\n\t\t\tenvVarName:     env.WebSocketURLs,\n\t\t\tenvVarValue:    \"\",\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"comma does not panic\",\n\t\t\tenvVarName:     env.WebSocketURLs,\n\t\t\tenvVarValue:    \",\",\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"read a single scenario with a single ws url\",\n\t\t\tenvVarName:     env.InstanceScenarios,\n\t\t\tenvVarValue:    `[{\"id\": \"one\",\"browsers\": [{ \"handle\": \"WS_URL_1\" }]}]`,\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"WS_URL_1\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"read a single scenario with a two ws urls\",\n\t\t\tenvVarName:     env.InstanceScenarios,\n\t\t\tenvVarValue:    `[{\"id\": \"one\",\"browsers\": [{\"handle\": \"WS_URL_1\"}, {\"handle\": \"WS_URL_2\"}]}]`,\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"WS_URL_1\", \"WS_URL_2\"},\n\t\t},\n\t\t{\n\t\t\tname:       \"read two scenarios with multiple ws urls\",\n\t\t\tenvVarName: env.InstanceScenarios,\n\t\t\tenvVarValue: `[\n\t\t\t\t{\"id\": \"one\",\"browsers\": [{\"handle\": \"WS_URL_1\"}, {\"handle\": \"WS_URL_2\"}]},\n\t\t\t\t{\"id\": \"two\",\"browsers\": [{\"handle\": \"WS_URL_3\"}, {\"handle\": \"WS_URL_4\"}]}\n\t\t\t]`,\n\t\t\texpIsRemote:    true,\n\t\t\texpValidWSURLs: []string{\"WS_URL_1\", \"WS_URL_2\", \"WS_URL_3\", \"WS_URL_4\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"read scenarios without any ws urls\",\n\t\t\tenvVarName:     env.InstanceScenarios,\n\t\t\tenvVarValue:    `[{\"id\": \"one\",\"browsers\": [{}]}]`,\n\t\t\texpIsRemote:    false,\n\t\t\texpValidWSURLs: []string{\"\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"read scenarios without any browser objects\",\n\t\t\tenvVarName:     env.InstanceScenarios,\n\t\t\tenvVarValue:    `[{\"id\": \"one\"}]`,\n\t\t\texpIsRemote:    false,\n\t\t\texpValidWSURLs: []string{\"\"},\n\t\t},\n\t\t{\n\t\t\tname:        \"read empty scenarios\",\n\t\t\tenvVarName:  env.InstanceScenarios,\n\t\t\tenvVarValue: ``,\n\t\t\texpErr:      errors.New(\"parsing K6_INSTANCE_SCENARIOS: unexpected end of JSON input\"),\n\t\t},\n\t}\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tlookup := func(key string) (string, bool) {\n\t\t\t\tv := tc.envVarValue\n\t\t\t\tif tc.envVarName == \"K6_INSTANCE_SCENARIOS\" {\n\t\t\t\t\tv = strconv.Quote(v)\n\t\t\t\t}\n\t\t\t\tif key == tc.envVarName {\n\t\t\t\t\treturn v, true\n\t\t\t\t}\n\t\t\t\treturn \"\", false\n\t\t\t}\n\n\t\t\trr, err := newRemoteRegistry(lookup)\n\t\t\tif tc.expErr != nil {\n\t\t\t\tassert.Error(t, tc.expErr, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.NoError(t, err)\n\n\t\t\twsURL, isRemote := rr.isRemoteBrowser()\n\t\t\trequire.Equal(t, tc.expIsRemote, isRemote)\n\t\t\tif isRemote {\n\t\t\t\trequire.Contains(t, tc.expValidWSURLs, wsURL)\n\t\t\t}\n\t\t})\n\t}\n\n\tt.Run(\"K6_INSTANCE_SCENARIOS should override K6_BROWSER_WS_URL\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tlookup := func(key string) (string, bool) {\n\t\t\tswitch key {\n\t\t\tcase env.WebSocketURLs:\n\t\t\t\treturn \"WS_URL_1\", true\n\t\t\tcase env.InstanceScenarios:\n\t\t\t\treturn strconv.Quote(`[{\"id\": \"one\",\"browsers\": [{ \"handle\": \"WS_URL_2\" }]}]`), true\n\t\t\tdefault:\n\t\t\t\treturn \"\", false\n\t\t\t}\n\t\t}\n\n\t\trr, err := newRemoteRegistry(lookup)\n\t\tassert.NoError(t, err)\n\n\t\twsURL, isRemote := rr.isRemoteBrowser()\n\n\t\trequire.Equal(t, true, isRemote)\n\t\trequire.Equal(t, \"WS_URL_2\", wsURL)\n\t})\n}\n\nfunc TestBrowserRegistry(t *testing.T) {\n\tt.Parallel()\n\n\tremoteRegistry, err := newRemoteRegistry(func(key string) (string, bool) {\n\t\t// No env vars\n\t\treturn \"\", false\n\t})\n\trequire.NoError(t, err)\n\n\tt.Run(\"init_and_close_browsers_on_iter_events\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar (\n\t\t\tvu              = k6test.NewVU(t)\n\t\t\tbrowserRegistry = newBrowserRegistry(context.Background(), vu, remoteRegistry, &pidRegistry{}, nil)\n\t\t)\n\n\t\tvu.ActivateVU()\n\n\t\t// Send a few IterStart events\n\t\tvu.StartIteration(t, k6test.WithIteration(0))\n\t\tvu.StartIteration(t, k6test.WithIteration(1))\n\t\tvu.StartIteration(t, k6test.WithIteration(2))\n\n\t\t// Verify browsers are initialized\n\t\tassert.Equal(t, 3, browserRegistry.browserCount())\n\n\t\t// Verify iteration traces are started\n\t\tassert.Equal(t, 3, browserRegistry.tr.iterationTracesCount())\n\n\t\t// Send IterEnd events\n\t\tvu.EndIteration(t, k6test.WithIteration(0))\n\t\tvu.EndIteration(t, k6test.WithIteration(1))\n\t\tvu.EndIteration(t, k6test.WithIteration(2))\n\n\t\t// Verify there are no browsers left\n\t\tassert.Equal(t, 0, browserRegistry.browserCount())\n\n\t\t// Verify iteration traces have been ended\n\t\tassert.Equal(t, 0, browserRegistry.tr.iterationTracesCount())\n\t})\n\n\tt.Run(\"close_browsers_on_exit_event\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar (\n\t\t\tvu              = k6test.NewVU(t)\n\t\t\tbrowserRegistry = newBrowserRegistry(context.Background(), vu, remoteRegistry, &pidRegistry{}, nil)\n\t\t)\n\n\t\tvu.ActivateVU()\n\n\t\t// Send a few IterStart events\n\t\tvu.StartIteration(t, k6test.WithIteration(0))\n\t\tvu.StartIteration(t, k6test.WithIteration(1))\n\t\tvu.StartIteration(t, k6test.WithIteration(2))\n\n\t\t// Verify browsers are initialized\n\t\tassert.Equal(t, 3, browserRegistry.browserCount())\n\n\t\t// Send Exit event\n\t\tevents, ok := vu.EventsField.Global.(*k6event.System)\n\t\trequire.True(t, ok, \"want *k6event.System; got %T\", events)\n\t\twaitDone := events.Emit(&k6event.Event{\n\t\t\tType: k6event.Exit,\n\t\t})\n\t\trequire.NoError(t, waitDone(context.Background()), \"error waiting on Exit done\")\n\n\t\t// Verify there are no browsers left\n\t\tassert.Equal(t, 0, browserRegistry.browserCount())\n\t})\n\n\tt.Run(\"skip_on_non_browser_vu\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar (\n\t\t\tvu              = k6test.NewVU(t)\n\t\t\tbrowserRegistry = newBrowserRegistry(context.Background(), vu, remoteRegistry, &pidRegistry{}, nil)\n\t\t)\n\n\t\tvu.ActivateVU()\n\n\t\t// Unset browser type option in scenario options in order to represent that VU is not\n\t\t// a browser test VU\n\t\tdelete(vu.StateField.Options.Scenarios[\"default\"].GetScenarioOptions().Browser, \"type\")\n\n\t\tvu.StartIteration(t, k6test.WithIteration(0))\n\n\t\t// Verify there are no browsers\n\t\tassert.Equal(t, 0, browserRegistry.browserCount())\n\t})\n\n\t// This test ensures that the chromium browser's lifecycle is not controlled\n\t// by the vu context.\n\tt.Run(\"dont_close_browser_on_vu_context_close\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\tvar cancel context.CancelFunc\n\t\tvu.CtxField, cancel = context.WithCancel(vu.CtxField)\n\t\tbrowserRegistry := newBrowserRegistry(context.Background(), vu, remoteRegistry, &pidRegistry{}, nil)\n\n\t\tvu.ActivateVU()\n\n\t\t// Send a few IterStart events\n\t\tvu.StartIteration(t, k6test.WithIteration(0))\n\n\t\t// Verify browsers are initialized\n\t\tassert.Equal(t, 1, browserRegistry.browserCount())\n\n\t\t// Cancel the \"iteration\" by closing the context.\n\t\tcancel()\n\n\t\t// Verify browsers are still alive\n\t\tassert.Equal(t, 1, browserRegistry.browserCount())\n\n\t\t// Do cleanup by sending the Exit event\n\t\tevents, ok := vu.EventsField.Global.(*k6event.System)\n\t\trequire.True(t, ok, \"want *k6event.System; got %T\", events)\n\t\twaitDone := events.Emit(&k6event.Event{\n\t\t\tType: k6event.Exit,\n\t\t})\n\t\trequire.NoError(t, waitDone(context.Background()), \"error waiting on Exit done\")\n\n\t\t// Verify there are no browsers left\n\t\tassert.Equal(t, 0, browserRegistry.browserCount())\n\t})\n}\n\nfunc TestParseTracesMetadata(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tname        string\n\t\tenv         map[string]string\n\t\texpMetadata map[string]string\n\t\texpErrMssg  string\n\t}{\n\t\t{\n\t\t\tname:        \"no metadata\",\n\t\t\tenv:         make(map[string]string),\n\t\t\texpMetadata: make(map[string]string),\n\t\t},\n\t\t{\n\t\t\tname: \"one metadata field\",\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_BROWSER_TRACES_METADATA\": \"meta=value\",\n\t\t\t},\n\t\t\texpMetadata: map[string]string{\n\t\t\t\t\"meta\": \"value\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"one metadata field finishing in comma\",\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_BROWSER_TRACES_METADATA\": \"meta=value,\",\n\t\t\t},\n\t\t\texpMetadata: map[string]string{\n\t\t\t\t\"meta\": \"value\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"multiple metadata fields\",\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_BROWSER_TRACES_METADATA\": \"meta1=value1,meta2=value2\",\n\t\t\t},\n\t\t\texpMetadata: map[string]string{\n\t\t\t\t\"meta1\": \"value1\",\n\t\t\t\t\"meta2\": \"value2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"multiple metadata fields finishing in comma\",\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_BROWSER_TRACES_METADATA\": \"meta1=value1,meta2=value2,\",\n\t\t\t},\n\t\t\texpMetadata: map[string]string{\n\t\t\t\t\"meta1\": \"value1\",\n\t\t\t\t\"meta2\": \"value2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid metadata\",\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_BROWSER_TRACES_METADATA\": \"thisIsInvalid\",\n\t\t\t},\n\t\t\texpErrMssg: \"is not a valid key=value metadata\",\n\t\t},\n\t\t{\n\t\t\tname: \"invalid metadata void\",\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_BROWSER_TRACES_METADATA\": \"\",\n\t\t\t},\n\t\t\texpErrMssg: \"is not a valid key=value metadata\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tlookup := func(key string) (string, bool) {\n\t\t\t\tv, ok := tc.env[key]\n\t\t\t\treturn v, ok\n\t\t\t}\n\t\t\tmetadata, err := parseTracesMetadata(lookup)\n\t\t\tif err != nil {\n\t\t\t\tassert.ErrorContains(t, err, tc.expErrMssg)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.Equal(t, tc.expMetadata, metadata)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/request_mapping.go",
    "content": "package browser\n\nimport (\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc mapRequestEvent(vu moduleVU, event common.PageEvent) mapping {\n\tr := event.Request\n\n\treturn mapRequest(vu, r)\n}\n\n// mapRequest to the JS module.\nfunc mapRequest(vu moduleVU, r *common.Request) mapping {\n\trt := vu.Runtime()\n\tmaps := mapping{\n\t\t\"allHeaders\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.AllHeaders(), nil\n\t\t\t})\n\t\t},\n\t\t\"frame\": func() *sobek.Object {\n\t\t\tmf := mapFrame(vu, r.Frame())\n\t\t\treturn rt.ToValue(mf).ToObject(rt)\n\t\t},\n\t\t\"headerValue\": func(name string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tv, ok := r.HeaderValue(name)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\n\t\t\t\treturn v, nil\n\t\t\t})\n\t\t},\n\t\t\"headers\": r.Headers,\n\t\t\"headersArray\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.HeadersArray(), nil\n\t\t\t})\n\t\t},\n\t\t\"isNavigationRequest\": r.IsNavigationRequest,\n\t\t\"method\":              r.Method,\n\t\t\"postData\": func() any {\n\t\t\tp := r.PostData()\n\t\t\tif p == \"\" {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn p\n\t\t},\n\t\t\"postDataBuffer\": func() any {\n\t\t\tp := r.PostDataBuffer()\n\t\t\tif len(p) == 0 {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn rt.NewArrayBuffer(p)\n\t\t},\n\t\t\"resourceType\": r.ResourceType,\n\t\t\"response\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tresp := r.Response()\n\t\t\t\tif resp == nil {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn mapResponse(vu, resp), nil\n\t\t\t})\n\t\t},\n\t\t\"size\":    r.Size,\n\t\t\"timing\":  r.Timing,\n\t\t\"url\":     r.URL,\n\t\t\"failure\": r.Failure,\n\t}\n\n\treturn maps\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/response_mapping.go",
    "content": "package browser\n\nimport (\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc mapResponseEvent(vu moduleVU, event common.PageEvent) mapping {\n\treturn mapResponse(vu, event.Response)\n}\n\n// mapResponse to the JS module.\n//\n//nolint:funlen\nfunc mapResponse(vu moduleVU, r *common.Response) mapping {\n\tif r == nil {\n\t\treturn nil\n\t}\n\tmaps := mapping{\n\t\t\"allHeaders\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.AllHeaders(), nil\n\t\t\t})\n\t\t},\n\t\t\"body\": func() *sobek.Promise {\n\t\t\trt := vu.Runtime()\n\t\t\tpromise, res, rej := rt.NewPromise()\n\t\t\tcallback := vu.RegisterCallback()\n\t\t\tgo func() {\n\t\t\t\tbody, err := r.Body()\n\t\t\t\tif err != nil {\n\t\t\t\t\tcallback(func() error {\n\t\t\t\t\t\treturn rej(err)\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tcallback(func() error {\n\t\t\t\t\tbuf := vu.Runtime().NewArrayBuffer(body)\n\t\t\t\t\treturn res(&buf)\n\t\t\t\t})\n\t\t\t}()\n\t\t\treturn promise\n\t\t},\n\t\t\"frame\": func() mapping {\n\t\t\treturn mapFrame(vu, r.Frame())\n\t\t},\n\t\t\"headerValue\": func(name string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tv, ok := r.HeaderValue(name)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn nil, nil\n\t\t\t\t}\n\t\t\t\treturn v, nil\n\t\t\t})\n\t\t},\n\t\t\"headerValues\": func(name string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.HeaderValues(name), nil\n\t\t\t})\n\t\t},\n\t\t\"headers\": r.Headers,\n\t\t\"headersArray\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.HeadersArray(), nil\n\t\t\t})\n\t\t},\n\t\t\"json\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.JSON() //nolint: wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"ok\": r.Ok,\n\t\t\"request\": func() mapping {\n\t\t\treturn mapRequest(vu, r.Request())\n\t\t},\n\t\t\"securityDetails\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.SecurityDetails(), nil\n\t\t\t})\n\t\t},\n\t\t\"serverAddr\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.ServerAddr(), nil\n\t\t\t})\n\t\t},\n\t\t\"size\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.Size(), nil\n\t\t\t})\n\t\t},\n\t\t\"status\":     r.Status,\n\t\t\"statusText\": r.StatusText,\n\t\t\"url\":        r.URL,\n\t\t\"text\": func() *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn r.Text() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t}\n\n\treturn maps\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/route_mapping.go",
    "content": "package browser\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// mapRoute to the JS module.\nfunc mapRoute(vu moduleVU, route *common.Route) mapping {\n\treturn mapping{\n\t\t\"abort\": func(reason string) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, route.Abort(reason)\n\t\t\t})\n\t\t},\n\t\t\"continue\": func(opts sobek.Value) *sobek.Promise {\n\t\t\tcopts, err := parseContinueOptions(vu.Context(), opts)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn nil, route.Continue(copts)\n\t\t\t})\n\t\t},\n\t\t\"fulfill\": func(opts sobek.Value) *sobek.Promise {\n\t\t\tfopts, err := parseFulfillOptions(vu.Context(), opts)\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn nil, route.Fulfill(fopts)\n\t\t\t})\n\t\t},\n\t\t\"request\": func() mapping {\n\t\t\treturn mapRequest(vu, route.Request())\n\t\t},\n\t}\n}\n\nfunc parseContinueOptions(ctx context.Context, opts sobek.Value) (common.ContinueOptions, error) {\n\tcopts := common.ContinueOptions{}\n\tif k6common.IsNullish(opts) {\n\t\treturn copts, nil\n\t}\n\n\trt := k6ext.Runtime(ctx)\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"headers\":\n\t\t\tcopts.Headers = parseHeaders(obj.Get(k).ToObject(rt))\n\t\tcase \"method\":\n\t\t\tcopts.Method = obj.Get(k).String()\n\t\tcase \"postData\":\n\t\t\tbytesData, err := k6common.ToBytes(obj.Get(k).Export())\n\t\t\tif err != nil {\n\t\t\t\treturn copts, err\n\t\t\t}\n\t\t\tcopts.PostData = bytesData\n\t\tcase \"url\":\n\t\t\tcopts.URL = obj.Get(k).String()\n\t\t}\n\t}\n\n\treturn copts, nil\n}\n\nfunc parseFulfillOptions(ctx context.Context, opts sobek.Value) (common.FulfillOptions, error) {\n\tfopts := common.FulfillOptions{}\n\tif k6common.IsNullish(opts) {\n\t\treturn fopts, nil\n\t}\n\n\trt := k6ext.Runtime(ctx)\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"body\":\n\t\t\tbytesBody, err := k6common.ToBytes(obj.Get(k).Export())\n\t\t\tif err != nil {\n\t\t\t\treturn fopts, err\n\t\t\t}\n\t\t\tfopts.Body = bytesBody\n\t\tcase \"contentType\":\n\t\t\tfopts.ContentType = obj.Get(k).String()\n\t\tcase \"headers\":\n\t\t\tfopts.Headers = parseHeaders(obj.Get(k).ToObject(rt))\n\t\tcase \"status\":\n\t\t\tfopts.Status = obj.Get(k).ToInteger()\n\t\t// As we don't support all fields that PW supports, we return an error to inform the user\n\t\tdefault:\n\t\t\treturn fopts, fmt.Errorf(\"unsupported fulfill option: '%s'\", k)\n\t\t}\n\t}\n\n\treturn fopts, nil\n}\n\nfunc parseHeaders(headers *sobek.Object) []common.HTTPHeader {\n\theadersKeys := headers.Keys()\n\tresult := make([]common.HTTPHeader, 0, len(headersKeys))\n\tfor _, hk := range headersKeys {\n\t\tvalue := headers.Get(hk)\n\t\t// Skip undefined headers\n\t\tif k6common.IsNullish(value) {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, common.HTTPHeader{\n\t\t\tName:  hk,\n\t\t\tValue: value.String(),\n\t\t})\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/route_options_test.go",
    "content": "package browser\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n)\n\nfunc TestParseContinueOptions(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tname         string\n\t\tjsOpts       string\n\t\texpectedOpts common.ContinueOptions\n\t\texpectedErr  bool\n\t}{\n\t\t{\n\t\t\tname: \"valid_options\",\n\t\t\tjsOpts: `{\n\t\t\t\tpostData: \"test data\",\n\t\t\t\tmethod: \"POST\",\n\t\t\t\turl: \"https://example.com\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedOpts: common.ContinueOptions{\n\t\t\t\tPostData: []byte(\"test data\"),\n\t\t\t\tHeaders: []common.HTTPHeader{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"Content-Type\",\n\t\t\t\t\t\tValue: \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMethod: \"POST\",\n\t\t\t\tURL:    \"https://example.com\",\n\t\t\t},\n\t\t\texpectedErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"buffer_postData\",\n\t\t\tjsOpts: `{\n\t\t\t\tpostData: new Uint8Array([116, 101, 115, 116, 32, 100, 97, 116, 97]),\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedOpts: common.ContinueOptions{\n\t\t\t\tPostData: []byte(\"test data\"),\n\t\t\t\tHeaders: []common.HTTPHeader{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"Content-Type\",\n\t\t\t\t\t\tValue: \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"remove_undefined_headers\",\n\t\t\tjsOpts: `{\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": undefined,\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedOpts: common.ContinueOptions{\n\t\t\t\tHeaders: []common.HTTPHeader{},\n\t\t\t},\n\t\t\texpectedErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid postData\",\n\t\t\tjsOpts: `{\n\t\t\t\tpostData: 12345,\n\t\t\t\tmethod: \"POST\"\n\t\t\t}`,\n\t\t\texpectedOpts: common.ContinueOptions{},\n\t\t\texpectedErr:  true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\topts, err := vu.Runtime().RunString(\n\t\t\t\tfmt.Sprintf(`const opts = %s;\n\t\t\t\t\topts;\n\t\t\t\t`, tt.jsOpts))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tparsedOpts, err := parseContinueOptions(vu.Context(), opts)\n\t\t\tif tt.expectedErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tt.expectedOpts, parsedOpts)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseFulfillOptions(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tname         string\n\t\tjsOpts       string\n\t\texpectedOpts common.FulfillOptions\n\t\texpectedErr  bool\n\t}{\n\t\t{\n\t\t\tname: \"valid_options\",\n\t\t\tjsOpts: `{\n\t\t\t\tbody: \"test data\",\n\t\t\t\tcontentType: \"application/json\",\n\t\t\t\tstatus: 200,\n\t\t\t}`,\n\t\t\texpectedOpts: common.FulfillOptions{\n\t\t\t\tBody:        []byte(\"test data\"),\n\t\t\t\tContentType: \"application/json\",\n\t\t\t\tStatus:      200,\n\t\t\t},\n\t\t\texpectedErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"buffer_body\",\n\t\t\tjsOpts: `{\n\t\t\t\tbody: new Uint8Array([116, 101, 115, 116, 32, 100, 97, 116, 97]),\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedOpts: common.FulfillOptions{\n\t\t\t\tBody: []byte(\"test data\"),\n\t\t\t\tHeaders: []common.HTTPHeader{\n\t\t\t\t\t{\n\t\t\t\t\t\tName:  \"Content-Type\",\n\t\t\t\t\t\tValue: \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpectedErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"remove_undefined_headers\",\n\t\t\tjsOpts: `{\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": undefined,\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedOpts: common.FulfillOptions{\n\t\t\t\tHeaders: []common.HTTPHeader{},\n\t\t\t},\n\t\t\texpectedErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"unsupported_option\",\n\t\t\tjsOpts: `{\n\t\t\t\tunsupportedOption: \"value\"\n\t\t\t}`,\n\t\t\texpectedOpts: common.FulfillOptions{},\n\t\t\texpectedErr:  true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvu := k6test.NewVU(t)\n\t\t\topts, err := vu.Runtime().RunString(\n\t\t\t\tfmt.Sprintf(`const opts = %s;\n\t\t\t\t\topts;\n\t\t\t\t`, tt.jsOpts))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tparsedOpts, err := parseFulfillOptions(vu.Context(), opts)\n\t\t\tif tt.expectedErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tt.expectedOpts, parsedOpts)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/touchscreen_mapping.go",
    "content": "package browser\n\nimport (\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// mapTouchscreen to the JS module.\nfunc mapTouchscreen(vu moduleVU, ts *common.Touchscreen) mapping {\n\treturn mapping{\n\t\t\"tap\": func(x float64, y float64) *sobek.Promise {\n\t\t\treturn promise(vu, func() (result any, reason error) {\n\t\t\t\treturn nil, ts.Tap(x, y) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/browser/worker_mapping.go",
    "content": "package browser\n\nimport (\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// mapWorker to the JS module.\nfunc mapWorker(_ moduleVU, w *common.Worker) mapping {\n\treturn mapping{\n\t\t\"url\": w.URL(),\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/chromium/browser.go",
    "content": "// Package chromium is responsible for launching a Chrome browser process and managing its lifetime.\npackage chromium\n\nimport (\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// Browser is the public interface of a CDP browser.\ntype Browser struct {\n\tcommon.Browser\n\n\t// TODO:\n\t// - add support for service workers\n\t// - add support for background pages\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/chromium/browser_type.go",
    "content": "package chromium\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\" // nosemgrep: math-random-used // This is used to generate id for easier debugging\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/storage\"\n\n\tk6modules \"go.k6.io/k6/js/modules\"\n\tk6lib \"go.k6.io/k6/lib\"\n)\n\n// BrowserType provides methods to launch a Chrome browser instance or connect to an existing one.\n// It's the entry point for interacting with the browser.\ntype BrowserType struct {\n\t// FIXME: This is only exported because testBrowser needs it. Contexts\n\t// shouldn't be stored on structs if we can avoid it.\n\tCtx          context.Context\n\tvu           k6modules.VU\n\thooks        *common.Hooks\n\tk6Metrics    *k6ext.CustomMetrics\n\trandSrc      *rand.Rand\n\tenvLookupper env.LookupFunc\n}\n\n// NewBrowserType registers our custom k6 metrics, creates method mappings on\n// the sobek runtime, and returns a new Chrome browser type.\nfunc NewBrowserType(vu k6modules.VU) *BrowserType {\n\t// NOTE: vu.InitEnv() *must* be called from the script init scope,\n\t// otherwise it will return nil.\n\tenv := vu.InitEnv()\n\n\treturn &BrowserType{\n\t\tvu:           vu,\n\t\thooks:        common.NewHooks(),\n\t\tk6Metrics:    k6ext.RegisterCustomMetrics(env.Registry),\n\t\trandSrc:      rand.New(rand.NewSource(time.Now().UnixNano())), //nolint: gosec\n\t\tenvLookupper: env.LookupEnv,\n\t}\n}\n\nfunc (b *BrowserType) init(\n\tctx context.Context, isRemoteBrowser bool,\n) (context.Context, *common.BrowserOptions, *log.Logger, error) {\n\tctx = b.initContext(ctx)\n\n\tlogger, err := makeLogger(ctx, b.envLookupper)\n\tif err != nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"error setting up logger: %w\", err)\n\t}\n\n\tvar browserOpts *common.BrowserOptions\n\tif isRemoteBrowser {\n\t\tbrowserOpts = common.NewRemoteBrowserOptions()\n\t} else {\n\t\tbrowserOpts = common.NewLocalBrowserOptions()\n\t}\n\n\topts := k6ext.GetScenarioOpts(b.vu.Context(), b.vu)\n\tif err = browserOpts.Parse(ctx, logger, opts, b.envLookupper); err != nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"error parsing browser options: %w\", err)\n\t}\n\tctx = common.WithBrowserOptions(ctx, browserOpts)\n\n\tif err := logger.SetCategoryFilter(browserOpts.LogCategoryFilter); err != nil {\n\t\treturn nil, nil, nil, fmt.Errorf(\"error setting category filter: %w\", err)\n\t}\n\tif browserOpts.Debug {\n\t\t_ = logger.SetLevel(\"debug\")\n\t}\n\n\treturn ctx, browserOpts, logger, nil\n}\n\nfunc (b *BrowserType) initContext(ctx context.Context) context.Context {\n\tctx = k6ext.WithVU(ctx, b.vu)\n\tctx = k6ext.WithCustomMetrics(ctx, b.k6Metrics)\n\tctx = common.WithHooks(ctx, b.hooks)\n\tctx = common.WithIterationID(ctx, fmt.Sprintf(\"%x\", b.randSrc.Uint64()))\n\treturn ctx\n}\n\n// Connect attaches k6 browser to an existing browser instance.\n//\n// vuCtx is the context coming from the VU itself. The k6 vu/iteration controls\n// its lifecycle.\n//\n// context.background() is used when connecting to an instance of chromium. The\n// connection lifecycle should be handled by the k6 event system.\n//\n// The separation is important to allow for the iteration to end when k6 requires\n// the iteration to end (e.g. during a SIGTERM) and unblocks k6 to then fire off\n// the events which allows the connection to close.\nfunc (b *BrowserType) Connect(ctx, vuCtx context.Context, wsEndpoint string) (*common.Browser, error) {\n\tvuCtx, browserOpts, logger, err := b.init(vuCtx, true)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"initializing browser type: %w\", err)\n\t}\n\n\tbp, err := b.connect(ctx, vuCtx, wsEndpoint, browserOpts, logger)\n\tif err != nil {\n\t\terr = &k6ext.UserFriendlyError{\n\t\t\tErr:     err,\n\t\t\tTimeout: browserOpts.Timeout,\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%w\", err)\n\t}\n\n\treturn bp, nil\n}\n\nfunc (b *BrowserType) connect(\n\tctx, vuCtx context.Context, wsURL string, opts *common.BrowserOptions, logger *log.Logger,\n) (*common.Browser, error) {\n\tbrowserProc, err := b.link(ctx, wsURL, logger)\n\tif browserProc == nil {\n\t\treturn nil, fmt.Errorf(\"connecting to browser: %w\", err)\n\t}\n\n\t// If this context is cancelled we'll initiate an extension wide\n\t// cancellation and shutdown.\n\tbrowserCtx, browserCtxCancel := context.WithCancel(vuCtx)\n\tb.Ctx = browserCtx\n\tbrowser, err := common.NewBrowser(\n\t\tctx, browserCtx, browserCtxCancel, browserProc, opts, logger,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"connecting to browser: %w\", err)\n\t}\n\n\treturn browser, nil\n}\n\nfunc (b *BrowserType) link(\n\tctx context.Context,\n\twsURL string, logger *log.Logger,\n) (*common.BrowserProcess, error) {\n\tbProcCtx, bProcCtxCancel := context.WithCancelCause(ctx)\n\tp, err := common.NewRemoteBrowserProcess(bProcCtx, wsURL, bProcCtxCancel, logger)\n\tif err != nil {\n\t\tbProcCtxCancel(fmt.Errorf(\"failed to connect to remote browser process: %w\", err))\n\t\treturn nil, err //nolint:wrapcheck\n\t}\n\n\treturn p, nil\n}\n\n// Launch allocates a new Chrome browser process and returns a new Browser value,\n// which can be used for controlling the Chrome browser.\n//\n// vuCtx is the context coming from the VU itself. The k6 vu/iteration controls\n// its lifecycle.\n//\n// context.background() is used when launching an instance of chromium. The\n// chromium lifecycle should be handled by the k6 event system.\n//\n// The separation is important to allow for the iteration to end when k6 requires\n// the iteration to end (e.g. during a SIGTERM) and unblocks k6 to then fire off\n// the events which allows the chromium subprocess to shutdown.\nfunc (b *BrowserType) Launch(ctx, vuCtx context.Context) (_ *common.Browser, browserProcessID int, _ error) {\n\tvuCtx, browserOpts, logger, err := b.init(vuCtx, false)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"initializing browser type: %w\", err)\n\t}\n\n\tbp, pid, err := b.launch(ctx, vuCtx, browserOpts, logger)\n\tif err != nil {\n\t\terr = &k6ext.UserFriendlyError{\n\t\t\tErr:     err,\n\t\t\tTimeout: browserOpts.Timeout,\n\t\t}\n\t\treturn nil, 0, fmt.Errorf(\"%w\", err)\n\t}\n\n\treturn bp, pid, nil\n}\n\nfunc (b *BrowserType) launch(\n\tctx, vuCtx context.Context, opts *common.BrowserOptions, logger *log.Logger,\n) (_ *common.Browser, pid int, _ error) {\n\tflags, err := prepareFlags(opts, &(b.vu.State()).Options)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"%w\", err)\n\t}\n\n\tdataDir := &storage.Dir{}\n\tif err := dataDir.Make(b.tmpdir(), flags[\"user-data-dir\"]); err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"%w\", err)\n\t}\n\tflags[\"user-data-dir\"] = dataDir.Dir\n\n\tpath, err := executablePath(opts.ExecutablePath, b.envLookupper, exec.LookPath)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"finding browser executable: %w\", err)\n\t}\n\n\tbrowserProc, err := b.allocate(ctx, path, flags, dataDir, logger)\n\tif browserProc == nil {\n\t\treturn nil, 0, fmt.Errorf(\"launching browser: %w\", err)\n\t}\n\n\t// If this context is cancelled we'll initiate an extension wide\n\t// cancellation and shutdown.\n\tbrowserCtx, browserCtxCancel := context.WithCancel(vuCtx)\n\tb.Ctx = browserCtx\n\tbrowser, err := common.NewBrowser(ctx, browserCtx, browserCtxCancel,\n\t\tbrowserProc, opts, logger)\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"launching browser: %w\", err)\n\t}\n\n\treturn browser, browserProc.Pid(), nil\n}\n\n// tmpdir returns the temporary directory to use for the browser.\n// It returns the value of the TMPDIR environment variable if set,\n// otherwise it returns an empty string.\nfunc (b *BrowserType) tmpdir() string {\n\tdir, _ := b.envLookupper(\"TMPDIR\")\n\treturn dir\n}\n\n// Name returns the name of this browser type.\nfunc (b *BrowserType) Name() string {\n\treturn \"chromium\"\n}\n\n// allocate starts a new Chromium browser process and returns it.\nfunc (b *BrowserType) allocate(\n\tctx context.Context,\n\tpath string,\n\tflags map[string]any, dataDir *storage.Dir,\n\tlogger *log.Logger,\n) (_ *common.BrowserProcess, rerr error) {\n\tbProcCtx, bProcCtxCancel := context.WithCancelCause(ctx)\n\tdefer func() {\n\t\tif rerr != nil {\n\t\t\tbProcCtxCancel(errors.New(\"local browser process init failed\"))\n\t\t}\n\t}()\n\n\targs, err := parseArgs(flags)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn common.NewLocalBrowserProcess(bProcCtx, path, args, dataDir, bProcCtxCancel, logger) //nolint: wrapcheck\n}\n\nvar (\n\t// ErrChromeNotInstalled is returned when the Chrome executable is not found.\n\tErrChromeNotInstalled = errors.New(\n\t\t\"k6 couldn't detect google chrome or a chromium-supported browser on this system\",\n\t)\n\n\t// ErrChromeNotFoundAtPath is returned when the Chrome executable is not found at the given path.\n\tErrChromeNotFoundAtPath = errors.New(\n\t\t\"k6 couldn't detect google chrome or a chromium-supported browser on the given path\",\n\t)\n)\n\n// executablePath returns the path where the extension expects to find the browser executable.\nfunc executablePath(\n\tpath string,\n\tenv env.LookupFunc,\n\tlookPath func(file string) (string, error), // os.LookPath\n) (string, error) {\n\t// find the browser executable in the user provided path\n\tif path := strings.TrimSpace(path); path != \"\" {\n\t\tif _, err := lookPath(path); err == nil {\n\t\t\treturn path, nil\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"%w: %s\", ErrChromeNotFoundAtPath, path)\n\t}\n\n\t// find the browser executable in the default paths below\n\tpaths := []string{\n\t\t// Unix-like\n\t\t\"headless_shell\",\n\t\t\"headless-shell\",\n\t\t\"chromium\",\n\t\t\"chromium-browser\",\n\t\t\"google-chrome\",\n\t\t\"google-chrome-stable\",\n\t\t\"google-chrome-beta\",\n\t\t\"google-chrome-unstable\",\n\t\t\"/usr/bin/google-chrome\",\n\t\t// Windows\n\t\t\"chrome\",\n\t\t\"chrome.exe\", // in case PATHEXT is misconfigured\n\t\t`C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe`,\n\t\t`C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe`,\n\t\t// Mac (from https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Mac/857950/)\n\t\t\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\",\n\t\t\"/Applications/Chromium.app/Contents/MacOS/Chromium\",\n\t}\n\t// find the browser executable in the user profile\n\tif userProfile, ok := env(\"USERPROFILE\"); ok {\n\t\tpaths = append(paths, filepath.Join(userProfile, `AppData\\Local\\Google\\Chrome\\Application\\chrome.exe`))\n\t}\n\tfor _, path := range paths {\n\t\tif _, err := lookPath(path); err == nil {\n\t\t\treturn path, nil\n\t\t}\n\t}\n\n\treturn \"\", ErrChromeNotInstalled\n}\n\n// parseArgs parses command-line arguments and returns them.\nfunc parseArgs(flags map[string]any) ([]string, error) {\n\t// Build command line args list\n\tvar args []string\n\tfor name, value := range flags {\n\t\tswitch value := value.(type) {\n\t\tcase string:\n\t\t\targs = append(args, parseStringArg(name, value))\n\t\tcase bool:\n\t\t\tif value {\n\t\t\t\targs = append(args, fmt.Sprintf(\"--%s\", name))\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(`invalid browser command line flag: \"%s=%v\"`, name, value)\n\t\t}\n\t}\n\tif _, ok := flags[\"remote-debugging-port\"]; !ok {\n\t\targs = append(args, \"--remote-debugging-port=0\")\n\t}\n\n\t// Force the first page to be blank, instead of the welcome page;\n\t// --no-first-run doesn't enforce that.\n\t// args = append(args, common.BlankPage)\n\t// args = append(args, \"--no-startup-window\")\n\treturn args, nil\n}\n\nfunc parseStringArg(flag string, value string) string {\n\tif strings.TrimSpace(value) == \"\" {\n\t\t// If the value is empty, we don't include it in the args list.\n\t\t// Otherwise, it will produce \"--name=\" which is invalid.\n\t\treturn fmt.Sprintf(\"--%s\", flag)\n\t}\n\treturn fmt.Sprintf(\"--%s=%s\", flag, value)\n}\n\nfunc prepareFlags(lopts *common.BrowserOptions, k6opts *k6lib.Options) (map[string]any, error) {\n\t// After Puppeteer's and Playwright's default behavior.\n\tf := map[string]any{\n\t\t\"disable-background-networking\":                      true,\n\t\t\"enable-features\":                                    \"NetworkService,NetworkServiceInProcess\",\n\t\t\"disable-background-timer-throttling\":                true,\n\t\t\"disable-backgrounding-occluded-windows\":             true,\n\t\t\"disable-breakpad\":                                   true,\n\t\t\"disable-component-extensions-with-background-pages\": true,\n\t\t\"disable-default-apps\":                               true,\n\t\t\"disable-dev-shm-usage\":                              true,\n\t\t\"disable-extensions\":                                 true,\n\t\t//nolint:lll\n\t\t\"disable-features\":                \"ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,AcceptCHFrame\",\n\t\t\"disable-hang-monitor\":            true,\n\t\t\"disable-ipc-flooding-protection\": true,\n\t\t\"disable-popup-blocking\":          true,\n\t\t\"disable-prompt-on-repost\":        true,\n\t\t\"disable-renderer-backgrounding\":  true,\n\t\t\"force-color-profile\":             \"srgb\",\n\t\t\"metrics-recording-only\":          true,\n\t\t\"no-first-run\":                    true,\n\t\t\"enable-automation\":               true,\n\t\t\"password-store\":                  \"basic\",\n\t\t\"use-mock-keychain\":               true,\n\t\t\"no-service-autorun\":              true,\n\n\t\t\"no-startup-window\":        true,\n\t\t\"no-default-browser-check\": true,\n\t\t\"headless\":                 lopts.Headless,\n\t\t\"window-size\":              fmt.Sprintf(\"%d,%d\", 800, 600),\n\t}\n\tif lopts.Headless {\n\t\tf[\"hide-scrollbars\"] = true\n\t\tf[\"mute-audio\"] = true\n\t\tf[\"blink-settings\"] = \"primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4\"\n\t}\n\tignoreDefaultArgsFlags(f, lopts.IgnoreDefaultArgs)\n\n\tsetFlagsFromArgs(f, lopts.Args)\n\tif err := setFlagsFromK6Options(f, k6opts); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn f, nil\n}\n\n// ignoreDefaultArgsFlags ignores any flags in the provided slice.\nfunc ignoreDefaultArgsFlags(flags map[string]any, toIgnore []string) {\n\tfor _, name := range toIgnore {\n\t\tdelete(flags, strings.TrimPrefix(name, \"--\"))\n\t}\n}\n\n// setFlagsFromArgs fills flags by parsing the args slice.\n// This is used for passing the \"arg=value\" arguments along with other launch options\n// when launching a new Chrome browser.\nfunc setFlagsFromArgs(flags map[string]any, args []string) {\n\tvar argname, argval string\n\tfor _, arg := range args {\n\t\tpair := strings.SplitN(arg, \"=\", 2)\n\t\targname, argval = strings.TrimSpace(pair[0]), \"\"\n\t\tif len(pair) > 1 {\n\t\t\targval = common.TrimQuotes(strings.TrimSpace(pair[1]))\n\t\t}\n\t\tflags[argname] = argval\n\t}\n}\n\n// setFlagsFromK6Options adds additional data to flags considering the k6 options.\n// Such as: \"host-resolver-rules\" for blocking requests.\nfunc setFlagsFromK6Options(flags map[string]any, k6opts *k6lib.Options) error {\n\tif k6opts == nil {\n\t\treturn nil\n\t}\n\n\thostResolver := []string{}\n\tif currHostResolver, ok := flags[\"host-resolver-rules\"]; ok {\n\t\thostResolver = append(hostResolver, fmt.Sprintf(\"%s\", currHostResolver))\n\t}\n\n\t// Add the host resolver rules.\n\t//\n\t// This is done by marshaling the k6 hosts option to JSON and then\n\t// unmarshaling it to a map[string]string. This is done because the\n\t// k6 v0.42 changed Hosts from a map to types.NullHosts and doesn't\n\t// expose the map anymore.\n\t//\n\t// TODO: A better way to do this would be to handle the resolver\n\t// rules by communicating with Chromium (and then using Hosts's\n\t// Match method) instead of passing the rules via the command line\n\t// to Chromium.\n\tvar rules map[string]string\n\tb, err := json.Marshal(k6opts.Hosts)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshaling hosts option: %w\", err)\n\t}\n\tif err := json.Unmarshal(b, &rules); err != nil {\n\t\treturn fmt.Errorf(\"unmarshaling hosts option: %w\", err)\n\t}\n\tfor k, v := range rules {\n\t\thostResolver = append(hostResolver, fmt.Sprintf(\"MAP %s %s\", k, v))\n\t}\n\tif len(hostResolver) > 0 {\n\t\tsort.Strings(hostResolver)\n\t\tflags[\"host-resolver-rules\"] = strings.Join(hostResolver, \",\")\n\t}\n\n\treturn nil\n}\n\n// makeLogger makes and returns an extension wide logger.\nfunc makeLogger(ctx context.Context, envLookup env.LookupFunc) (*log.Logger, error) {\n\tvar (\n\t\tk6Logger = k6ext.GetVU(ctx).State().Logger\n\t\tlogger   = log.New(k6Logger, common.GetIterationID(ctx))\n\t)\n\tif el, ok := envLookup(env.LogLevel); ok {\n\t\tif logger.SetLevel(el) != nil {\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"invalid log level %q, should be one of: panic, fatal, error, warn, warning, info, debug, trace\",\n\t\t\t\tel,\n\t\t\t)\n\t\t}\n\t}\n\tif _, ok := envLookup(env.LogCaller); ok {\n\t\tlogger.ReportCaller()\n\t}\n\n\treturn logger, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/chromium/browser_type_test.go",
    "content": "package chromium\n\nimport (\n\t\"io/fs\"\n\t\"net\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\n\tk6lib \"go.k6.io/k6/lib\"\n\tk6types \"go.k6.io/k6/lib/types\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBrowserTypePrepareFlags(t *testing.T) {\n\tt.Parallel()\n\n\t// to be used by the tests below\n\thost, err := k6types.NewHost(net.ParseIP(\"127.0.0.1\"), \"8000\")\n\trequire.NoError(t, err, \"failed to set up test host\")\n\thosts, err := k6types.NewHosts(map[string]k6types.Host{\n\t\t\"test.k6.io\":         *host,\n\t\t\"httpbin.test.k6.io\": *host,\n\t})\n\trequire.NoError(t, err, \"failed to set up test hosts\")\n\n\ttestCases := []struct {\n\t\tflag                      string\n\t\tchangeOpts                *common.BrowserOptions\n\t\tchangeK6Opts              *k6lib.Options\n\t\texpInitVal, expChangedVal any\n\t\tpost                      func(t *testing.T, flags map[string]any)\n\t}{\n\t\t{\n\t\t\tflag:       \"hide-scrollbars\",\n\t\t\tchangeOpts: &common.BrowserOptions{IgnoreDefaultArgs: []string{\"hide-scrollbars\"}, Headless: true},\n\t\t},\n\t\t{\n\t\t\tflag:          \"hide-scrollbars\",\n\t\t\tchangeOpts:    &common.BrowserOptions{Headless: true},\n\t\t\texpChangedVal: true,\n\t\t},\n\t\t{\n\t\t\tflag:          \"browser-arg\",\n\t\t\texpInitVal:    nil,\n\t\t\tchangeOpts:    &common.BrowserOptions{Args: []string{\"browser-arg=value\"}},\n\t\t\texpChangedVal: \"value\",\n\t\t},\n\t\t{\n\t\t\tflag:          \"browser-arg-flag\",\n\t\t\texpInitVal:    nil,\n\t\t\tchangeOpts:    &common.BrowserOptions{Args: []string{\"browser-arg-flag\"}},\n\t\t\texpChangedVal: \"\",\n\t\t},\n\t\t{\n\t\t\tflag:       \"browser-arg-trim-double-quote\",\n\t\t\texpInitVal: nil,\n\t\t\tchangeOpts: &common.BrowserOptions{Args: []string{\n\t\t\t\t`   browser-arg-trim-double-quote =  \"value  \"  `,\n\t\t\t}},\n\t\t\texpChangedVal: \"value  \",\n\t\t},\n\t\t{\n\t\t\tflag:       \"browser-arg-trim-single-quote\",\n\t\t\texpInitVal: nil,\n\t\t\tchangeOpts: &common.BrowserOptions{Args: []string{\n\t\t\t\t`   browser-arg-trim-single-quote=' value '`,\n\t\t\t}},\n\t\t\texpChangedVal: \" value \",\n\t\t},\n\t\t{\n\t\t\tflag:       \"browser-args\",\n\t\t\texpInitVal: nil,\n\t\t\tchangeOpts: &common.BrowserOptions{Args: []string{\n\t\t\t\t\"browser-arg1='value1\", \"browser-arg2=''value2''\", \"browser-flag\",\n\t\t\t}},\n\t\t\tpost: func(t *testing.T, flags map[string]any) {\n\t\t\t\tt.Helper()\n\n\t\t\t\tassert.Equal(t, \"'value1\", flags[\"browser-arg1\"])\n\t\t\t\tassert.Equal(t, \"'value2'\", flags[\"browser-arg2\"])\n\t\t\t\tassert.Equal(t, \"\", flags[\"browser-flag\"])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tflag:       \"host-resolver-rules\",\n\t\t\texpInitVal: nil,\n\t\t\tchangeOpts: &common.BrowserOptions{Args: []string{\n\t\t\t\t`host-resolver-rules=\"MAP * www.example.com, EXCLUDE *.youtube.*\"`,\n\t\t\t}},\n\t\t\tchangeK6Opts: &k6lib.Options{\n\t\t\t\tHosts: k6types.NullHosts{Trie: hosts, Valid: true},\n\t\t\t},\n\t\t\texpChangedVal: \"MAP * www.example.com, EXCLUDE *.youtube.*,\" +\n\t\t\t\t\"MAP httpbin.test.k6.io 127.0.0.1:8000,MAP test.k6.io 127.0.0.1:8000\",\n\t\t},\n\t\t{\n\t\t\tflag:          \"host-resolver-rules\",\n\t\t\texpInitVal:    nil,\n\t\t\tchangeOpts:    &common.BrowserOptions{},\n\t\t\tchangeK6Opts:  &k6lib.Options{},\n\t\t\texpChangedVal: nil,\n\t\t},\n\t\t{\n\t\t\tflag:          \"headless\",\n\t\t\texpInitVal:    false,\n\t\t\tchangeOpts:    &common.BrowserOptions{Headless: true},\n\t\t\texpChangedVal: true,\n\t\t\tpost: func(t *testing.T, flags map[string]any) {\n\t\t\t\tt.Helper()\n\n\t\t\t\textraFlags := []string{\"hide-scrollbars\", \"mute-audio\", \"blink-settings\"}\n\t\t\t\tfor _, f := range extraFlags {\n\t\t\t\t\tassert.Contains(t, flags, f)\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.flag, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tflags, err := prepareFlags(&common.BrowserOptions{}, nil)\n\t\t\trequire.NoError(t, err, \"failed to prepare flags\")\n\n\t\t\tif tc.expInitVal != nil {\n\t\t\t\trequire.Contains(t, flags, tc.flag)\n\t\t\t\tassert.Equal(t, tc.expInitVal, flags[tc.flag])\n\t\t\t} else {\n\t\t\t\trequire.NotContains(t, flags, tc.flag)\n\t\t\t}\n\n\t\t\tif tc.changeOpts != nil || tc.changeK6Opts != nil {\n\t\t\t\tflags, err = prepareFlags(tc.changeOpts, tc.changeK6Opts)\n\t\t\t\trequire.NoError(t, err, \"failed to prepare flags\")\n\t\t\t\tif tc.expChangedVal != nil {\n\t\t\t\t\tassert.Equal(t, tc.expChangedVal, flags[tc.flag])\n\t\t\t\t} else {\n\t\t\t\t\tassert.NotContains(t, flags, tc.flag)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif tc.post != nil {\n\t\t\t\ttc.post(t, flags)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestExecutablePath(t *testing.T) {\n\tt.Parallel()\n\n\t// we pick a random file name to look for in our tests\n\t// this doesn't matter as long as it's in the paths we look for\n\t// in ExecutablePath function.\n\tconst chromiumExecutable = \"google-chrome\"\n\n\tuserProvidedPath := filepath.Join(\"path\", \"to\", \"chromium\")\n\n\tfileNotExists := func(file string) (string, error) {\n\t\treturn \"\", fs.ErrNotExist\n\t}\n\n\ttests := map[string]struct {\n\t\tuserProvidedPath string                            // user provided path\n\t\tlookPath         func(file string) (string, error) // determines if a file exists\n\t\tuserProfile      env.LookupFunc                    // user profile folder lookup\n\n\t\twantPath string\n\t\twantErr  error\n\t}{\n\t\t\"without_chromium\": {\n\t\t\tuserProvidedPath: \"\",\n\t\t\tlookPath:         fileNotExists,\n\t\t\tuserProfile:      env.EmptyLookup,\n\t\t\twantPath:         \"\",\n\t\t\twantErr:          ErrChromeNotInstalled,\n\t\t},\n\t\t\"with_chromium\": {\n\t\t\tuserProvidedPath: \"\",\n\t\t\tlookPath: func(file string) (string, error) {\n\t\t\t\tif file == chromiumExecutable {\n\t\t\t\t\treturn \"\", nil\n\t\t\t\t}\n\t\t\t\treturn \"\", fs.ErrNotExist\n\t\t\t},\n\t\t\tuserProfile: env.EmptyLookup,\n\t\t\twantPath:    chromiumExecutable,\n\t\t\twantErr:     nil,\n\t\t},\n\t\t\"without_chromium_in_user_path\": {\n\t\t\tuserProvidedPath: userProvidedPath,\n\t\t\tlookPath:         fileNotExists,\n\t\t\tuserProfile:      env.EmptyLookup,\n\t\t\twantPath:         \"\",\n\t\t\twantErr:          ErrChromeNotFoundAtPath,\n\t\t},\n\t\t\"with_chromium_in_user_path\": {\n\t\t\tuserProvidedPath: userProvidedPath,\n\t\t\tlookPath: func(file string) (string, error) {\n\t\t\t\tif file == userProvidedPath {\n\t\t\t\t\treturn \"\", nil\n\t\t\t\t}\n\t\t\t\treturn \"\", fs.ErrNotExist\n\t\t\t},\n\t\t\tuserProfile: env.EmptyLookup,\n\t\t\twantPath:    userProvidedPath,\n\t\t\twantErr:     nil,\n\t\t},\n\t\t\"without_chromium_in_user_profile\": {\n\t\t\tuserProvidedPath: \"\",\n\t\t\tlookPath:         fileNotExists,\n\t\t\tuserProfile:      env.ConstLookup(\"USERPROFILE\", `home`),\n\t\t\twantPath:         \"\",\n\t\t\twantErr:          ErrChromeNotInstalled,\n\t\t},\n\t\t\"with_chromium_in_user_profile\": {\n\t\t\tuserProvidedPath: \"\",\n\t\t\tlookPath: func(file string) (string, error) { // we look chrome.exe in the user profile\n\t\t\t\tif file == filepath.Join(\"home\", `AppData\\Local\\Google\\Chrome\\Application\\chrome.exe`) {\n\t\t\t\t\treturn \"\", nil\n\t\t\t\t}\n\t\t\t\treturn \"\", fs.ErrNotExist\n\t\t\t},\n\t\t\tuserProfile: env.ConstLookup(\"USERPROFILE\", `home`),\n\t\t\twantPath:    filepath.Join(\"home\", `AppData\\Local\\Google\\Chrome\\Application\\chrome.exe`),\n\t\t\twantErr:     nil,\n\t\t},\n\t}\n\tfor name, tt := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tpath, err := executablePath(tt.userProvidedPath, tt.userProfile, tt.lookPath)\n\n\t\t\tassert.Equal(t, tt.wantPath, path)\n\n\t\t\tif tt.wantErr != nil {\n\t\t\t\tassert.ErrorIs(t, err, tt.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestParseArgs(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname  string\n\t\tflags map[string]any\n\t\twant  []string\n\t}{\n\t\t{\n\t\t\tname: \"string_flag_with_value\",\n\t\t\tflags: map[string]any{\n\t\t\t\t\"flag1\": \"value1\",\n\t\t\t\t\"flag2\": \"value2\",\n\t\t\t},\n\t\t\twant: []string{\n\t\t\t\t\"--flag1=value1\",\n\t\t\t\t\"--flag2=value2\",\n\t\t\t\t\"--remote-debugging-port=0\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"string_flag_with_empty_value\",\n\t\t\tflags: map[string]any{\n\t\t\t\t\"flag1\": \"\",\n\t\t\t\t\"flag2\": \"value2\",\n\t\t\t},\n\t\t\twant: []string{\n\t\t\t\t\"--flag1\",\n\t\t\t\t\"--flag2=value2\",\n\t\t\t\t\"--remote-debugging-port=0\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"bool_flag_true\",\n\t\t\tflags: map[string]any{\n\t\t\t\t\"flag1\": true,\n\t\t\t\t\"flag2\": true,\n\t\t\t},\n\t\t\twant: []string{\n\t\t\t\t\"--flag1\",\n\t\t\t\t\"--flag2\",\n\t\t\t\t\"--remote-debugging-port=0\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"bool_flag_false\",\n\t\t\tflags: map[string]any{\n\t\t\t\t\"flag1\": false,\n\t\t\t\t\"flag2\": true,\n\t\t\t},\n\t\t\twant: []string{\n\t\t\t\t\"--flag2\",\n\t\t\t\t\"--remote-debugging-port=0\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"invalid_flag_type\",\n\t\t\tflags: map[string]any{\n\t\t\t\t\"flag1\": 123,\n\t\t\t},\n\t\t\twant: nil,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot, err := parseArgs(tt.flags)\n\n\t\t\tif tt.want == nil {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tsort.StringSlice(tt.want).Sort()\n\t\t\tsort.StringSlice(got).Sort()\n\t\t\tassert.Equal(t, tt.want, got)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/barrier.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\ntype Barrier struct {\n\tcount int64\n\tch    chan bool\n\terrCh chan error\n}\n\nfunc NewBarrier() *Barrier {\n\treturn &Barrier{\n\t\tcount: 1,\n\t\tch:    make(chan bool, 1),\n\t\terrCh: make(chan error, 1),\n\t}\n}\n\nfunc (b *Barrier) AddFrameNavigation(frame *Frame) {\n\tif frame.parentFrame != nil {\n\t\treturn // We only care about top-frame navigation\n\t}\n\tch, evCancelFn := createWaitForEventHandler(frame.ctx, frame, []string{EventFrameNavigation}, func(data any) bool {\n\t\treturn true\n\t})\n\tgo func() {\n\t\tdefer evCancelFn() // Remove event handler\n\t\tatomic.AddInt64(&b.count, 1)\n\t\tselect {\n\t\tcase <-frame.ctx.Done():\n\t\tcase <-time.After(frame.manager.timeoutSettings.navigationTimeout()):\n\t\t\tb.errCh <- ErrTimedOut\n\t\tcase <-ch:\n\t\t\tb.ch <- true\n\t\t}\n\t\tatomic.AddInt64(&b.count, -1)\n\t}()\n}\n\nfunc (b *Barrier) Wait(ctx context.Context) error {\n\tif atomic.AddInt64(&b.count, -1) == 0 {\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\tcase <-b.ch:\n\t\treturn nil\n\tcase err := <-b.errCh:\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/barrier_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\nfunc TestBarrier(t *testing.T) {\n\tt.Parallel()\n\n\tctx := context.Background()\n\n\tlog := log.NewNullLogger()\n\n\ttimeoutSettings := NewTimeoutSettings(nil)\n\tframeManager := NewFrameManager(ctx, nil, nil, timeoutSettings, log)\n\tframe := NewFrame(ctx, frameManager, nil, cdp.FrameID(\"frame_id_0123456789\"), log)\n\n\tbarrier := NewBarrier()\n\tbarrier.AddFrameNavigation(frame)\n\tframe.emit(EventFrameNavigation, \"some data\")\n\n\terr := barrier.Wait(ctx)\n\trequire.Nil(t, err)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto\"\n\tcdpbrowser \"github.com/chromedp/cdproto/browser\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/target\"\n\t\"github.com/gorilla/websocket\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\nconst (\n\tBrowserStateOpen int64 = iota\n\tBrowserStateClosed\n)\n\n// Browser stores a Browser context.\ntype Browser struct {\n\t// These are internal contexts which control the lifecycle of the connection\n\t// and eventLoop. It is shutdown when browser.close() is called.\n\tbrowserCtx      context.Context\n\tbrowserCancelFn context.CancelCauseFunc\n\n\tvuCtx         context.Context\n\tvuCtxCancelFn context.CancelFunc\n\n\tstate int64\n\n\tbrowserProc *BrowserProcess\n\tbrowserOpts *BrowserOptions\n\n\t// Connection to the browser to talk CDP protocol.\n\t// A *Connection is saved to this field, see: connect().\n\tconn connection\n\n\t// This mutex is only needed in an edge case where we have multiple\n\t// instances of k6 connecting to the same chrome instance. In this\n\t// case when a page is created by the first k6 instance, the second\n\t// instance of k6 will also receive an onAttachedToTarget event. When\n\t// this occurs there's a small chance that at the same time a new\n\t// context is being created by the second k6 instance. So the read\n\t// occurs in getDefaultBrowserContextOrMatchedID which is called by\n\t// onAttachedToTarget, and the write in NewContext. This mutex protects\n\t// the read/write race condition for this one case.\n\tcontextMu      sync.RWMutex\n\tcontext        *BrowserContext\n\tdefaultContext *BrowserContext\n\n\t// Needed as the targets map will be accessed from multiple Go routines,\n\t// the main VU/JS go routine and the Go routine listening for CDP messages.\n\tpagesMu sync.RWMutex\n\tpages   map[target.ID]*Page\n\n\tsessionIDtoTargetIDMu sync.RWMutex\n\tsessionIDtoTargetID   map[target.SessionID]target.ID\n\n\t// closing guards against new pages being attached while we're closing\n\t// the browser. It also protects against multiple calls to Close().\n\tclosing atomic.Bool\n\n\t// version caches the browser version information.\n\tversion browserVersion\n\n\t// runOnClose is a list of functions to run when the browser is closed.\n\trunOnClose []func() error\n\n\tlogger *log.Logger\n}\n\n// browserVersion is a struct to hold the browser version information.\ntype browserVersion struct {\n\tprotocolVersion string\n\tproduct         string\n\trevision        string\n\tuserAgent       string\n\tjsVersion       string\n}\n\n// NewBrowser creates a new browser, connects to it, then returns it.\nfunc NewBrowser(\n\tctx context.Context,\n\tvuCtx context.Context,\n\tvuCtxCancelFn context.CancelFunc,\n\tbrowserProc *BrowserProcess,\n\tbrowserOpts *BrowserOptions,\n\tlogger *log.Logger,\n) (*Browser, error) {\n\tb := newBrowser(ctx, vuCtx, vuCtxCancelFn, browserProc, browserOpts, logger)\n\tif err := b.connect(); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// cache the browser version information.\n\tvar err error\n\tif b.version, err = b.fetchVersion(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn b, nil\n}\n\n// newBrowser returns a ready to use Browser without connecting to an actual browser.\nfunc newBrowser(\n\tctx context.Context,\n\tvuCtx context.Context,\n\tvuCtxCancelFn context.CancelFunc,\n\tbrowserProc *BrowserProcess,\n\tbrowserOpts *BrowserOptions,\n\tlogger *log.Logger,\n) *Browser {\n\t// The browser needs its own context to correctly close dependencies such\n\t// as the connection. It cannot rely on the vuCtx since that would close\n\t// the connection too early. The connection and subprocess need to be\n\t// shutdown at around the same time to allow for any last minute CDP\n\t// cleanup messages to be sent to chromium.\n\tctx, cancelFn := context.WithCancelCause(ctx)\n\n\treturn &Browser{\n\t\tbrowserCtx:          ctx,\n\t\tbrowserCancelFn:     cancelFn,\n\t\tvuCtx:               vuCtx,\n\t\tvuCtxCancelFn:       vuCtxCancelFn,\n\t\tstate:               BrowserStateOpen,\n\t\tbrowserProc:         browserProc,\n\t\tbrowserOpts:         browserOpts,\n\t\tpages:               make(map[target.ID]*Page),\n\t\tsessionIDtoTargetID: make(map[target.SessionID]target.ID),\n\t\tlogger:              logger,\n\t}\n}\n\nfunc (b *Browser) connect() error {\n\tb.logger.Debugf(\"Browser:connect\", \"wsURL:%q\", b.browserProc.WsURL())\n\n\t// connectionOnAttachedToTarget hooks into the connection to listen\n\t// for target attachment events. this way, browser can manage the\n\t// decision of target attachments. so that we can stop connection\n\t// from doing unnecessary work.\n\t//\n\t// We need the connection to shutdown when browser.Close is called.\n\t// This is why we're using the internal context.\n\tvar err error\n\tb.conn, err = NewConnection(\n\t\tb.browserCtx,\n\t\tb.browserProc.WsURL(),\n\t\tb.logger,\n\t\tb.connectionOnAttachedToTarget,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"connecting to browser DevTools URL: %w\", err)\n\t}\n\n\t// We don't need to lock this because `connect()` is called only in NewBrowser\n\tb.defaultContext, err = NewBrowserContext(b.vuCtx, b, \"\", DefaultBrowserContextOptions(), b.logger)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"browser connect: %w\", err)\n\t}\n\tb.runOnClose = append(b.runOnClose, b.defaultContext.cleanup)\n\n\treturn b.initEvents()\n}\n\nfunc (b *Browser) disposeContext(id cdp.BrowserContextID) error {\n\tb.logger.Debugf(\"Browser:disposeContext\", \"bctxid:%v\", id)\n\n\taction := target.DisposeBrowserContext(id)\n\tif err := action.Do(cdp.WithExecutor(b.vuCtx, b.conn)); err != nil {\n\t\treturn fmt.Errorf(\"disposing browser context ID %s: %w\", id, err)\n\t}\n\tb.context = nil\n\n\treturn nil\n}\n\n// getDefaultBrowserContextOrMatchedID returns the BrowserContext for the given browser context ID.\n// If the browser context is not found, the default BrowserContext is returned.\nfunc (b *Browser) getDefaultBrowserContextOrMatchedID(id cdp.BrowserContextID) *BrowserContext {\n\tb.contextMu.RLock()\n\tdefer b.contextMu.RUnlock()\n\n\tif b.context == nil || b.context.id != id {\n\t\treturn b.defaultContext\n\t}\n\n\treturn b.context\n}\n\nfunc (b *Browser) getPages() []*Page {\n\tb.pagesMu.RLock()\n\tdefer b.pagesMu.RUnlock()\n\tpages := make([]*Page, 0, len(b.pages))\n\tfor _, p := range b.pages {\n\t\tpages = append(pages, p)\n\t}\n\treturn pages\n}\n\nfunc (b *Browser) initEvents() error {\n\tchHandler := make(chan Event)\n\n\t// Using the internal context here. Using vuCtx would close the connection/subprocess\n\t// and therefore shutdown chromium when the iteration ends which isn't what we\n\t// want to happen. Chromium should only be closed by the k6 event system.\n\tb.conn.on(b.browserCtx, []string{\n\t\tcdproto.EventTargetAttachedToTarget,\n\t\tcdproto.EventTargetDetachedFromTarget,\n\t\tEventConnectionClose,\n\t}, chHandler)\n\n\tgo func() {\n\t\tdefer func() {\n\t\t\tb.browserProc.didLoseConnection()\n\t\t\t// Closing the vuCtx incase it hasn't already been closed. Very likely\n\t\t\t// already closed since the vuCtx is controlled by the k6 iteration,\n\t\t\t// whereas the initContext is controlled by the k6 event system when\n\t\t\t// browser.close() is called. k6 iteration ends before the event system.\n\t\t\tif b.vuCtxCancelFn != nil {\n\t\t\t\tb.vuCtxCancelFn()\n\t\t\t}\n\t\t}()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-b.browserCtx.Done():\n\t\t\t\treturn\n\t\t\tcase event := <-chHandler:\n\t\t\t\tif ev, ok := event.data.(*target.EventAttachedToTarget); ok {\n\t\t\t\t\tb.logger.Debugf(\"Browser:initEvents:onAttachedToTarget\", \"sid:%v tid:%v\", ev.SessionID, ev.TargetInfo.TargetID)\n\t\t\t\t\tif err := b.onAttachedToTarget(ev); err != nil {\n\t\t\t\t\t\tk6ext.Panicf(b.vuCtx, \"browser is attaching to target: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t} else if ev, ok := event.data.(*target.EventDetachedFromTarget); ok {\n\t\t\t\t\tb.logger.Debugf(\"Browser:initEvents:onDetachedFromTarget\", \"sid:%v\", ev.SessionID)\n\t\t\t\t\tb.onDetachedFromTarget(ev)\n\t\t\t\t} else if event.typ == EventConnectionClose {\n\t\t\t\t\tb.logger.Debugf(\"Browser:initEvents:EventConnectionClose\", \"\")\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\taction := target.SetAutoAttach(true, true).WithFlatten(true)\n\tif err := action.Do(cdp.WithExecutor(b.vuCtx, b.conn)); err != nil {\n\t\treturn fmt.Errorf(\"internal error while auto-attaching to browser pages: %w\", err)\n\t}\n\n\t// Target.setAutoAttach has a bug where it does not wait for new Targets being attached.\n\t// However making a dummy call afterwards fixes this.\n\t// This can be removed after https://chromium-review.googlesource.com/c/chromium/src/+/2885888 lands in stable.\n\taction2 := target.GetTargetInfo()\n\tif _, err := action2.Do(cdp.WithExecutor(b.vuCtx, b.conn)); err != nil {\n\t\treturn fmt.Errorf(\"internal error while getting browser target info: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// connectionOnAttachedToTarget is called when Connection receives an attachedToTarget\n// event. Returning false will stop the event from being processed by the connection.\nfunc (b *Browser) connectionOnAttachedToTarget(eva *target.EventAttachedToTarget) bool {\n\t// This allows to attach targets to the same browser context as the current\n\t// one, and to the default browser context.\n\t//\n\t// We don't want to hold the lock for the entire function\n\t// (connectionOnAttachedToTarget) run duration, because we want to avoid\n\t// possible lock contention issues with the browser context being closed while\n\t// we're waiting for it. So, we do the lock management in a function with its\n\t// own defer.\n\tisAllowedBrowserContext := func() bool {\n\t\tb.contextMu.RLock()\n\t\tdefer b.contextMu.RUnlock()\n\t\treturn b.context == nil || b.context.id == eva.TargetInfo.BrowserContextID\n\t}\n\n\treturn isAllowedBrowserContext()\n}\n\n// onAttachedToTarget is called when a new page is attached to the browser.\nfunc (b *Browser) onAttachedToTarget(ev *target.EventAttachedToTarget) error {\n\tb.logger.Debugf(\"Browser:onAttachedToTarget\", \"sid:%v tid:%v bctxid:%v\",\n\t\tev.SessionID, ev.TargetInfo.TargetID, ev.TargetInfo.BrowserContextID)\n\n\tvar (\n\t\ttargetPage = ev.TargetInfo\n\t\tbrowserCtx = b.getDefaultBrowserContextOrMatchedID(targetPage.BrowserContextID)\n\t)\n\n\tif !b.isAttachedPageValid(ev, browserCtx) {\n\t\treturn nil // Ignore this page.\n\t}\n\tsession := b.conn.getSession(ev.SessionID)\n\tif session == nil {\n\t\tb.logger.Debugf(\"Browser:onAttachedToTarget\",\n\t\t\t\"session closed before attachToTarget is handled. sid:%v tid:%v\",\n\t\t\tev.SessionID, targetPage.TargetID)\n\t\treturn nil // ignore\n\t}\n\n\tvar (\n\t\tisPage = targetPage.Type == \"page\"\n\t\topener *Page\n\t)\n\t// Opener is nil for the initial page.\n\tif isPage {\n\t\tb.pagesMu.RLock()\n\t\tif t, ok := b.pages[targetPage.OpenerID]; ok {\n\t\t\topener = t\n\t\t}\n\t\tb.pagesMu.RUnlock()\n\t}\n\tp, err := NewPage(b.vuCtx, session, browserCtx, targetPage.TargetID, opener, isPage, b.logger)\n\tif err != nil && b.isPageAttachmentErrorIgnorable(ev, session, err) {\n\t\tif b.closing.Load() {\n\t\t\tb.logger.Debugf(\"Browser:onAttachedToTarget\", \"new page failed; browser is closing: sid:%v\", ev.SessionID)\n\t\t\tdetachSession(b.browserCtx, session)\n\t\t}\n\t\treturn nil // Ignore this page.\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating a new %s: %w\", targetPage.Type, err)\n\t}\n\n\t// This prevents a race where Close() sets closing and snapshots\n\t// pages, but a new page is inserted outside that snapshot.\n\tif err := b.attachNewPage(p, ev); err != nil {\n\t\tif !errors.Is(err, errBrowserClosing) {\n\t\t\treturn fmt.Errorf(\"attaching new page: %w\", err)\n\t\t}\n\n\t\tb.logger.Debugf(\n\t\t\t\"Browser:onAttachedToTarget\",\n\t\t\t\"rejected page attachment; browser is closing: sid:%v tid:%v\",\n\t\t\tev.SessionID, ev.TargetInfo.TargetID,\n\t\t)\n\t\tif closeErr := p.Close(); closeErr != nil {\n\t\t\tb.logger.Debugf(\n\t\t\t\t\"Browser:onAttachedToTarget\",\n\t\t\t\t\"closing rejected page: %v\", closeErr,\n\t\t\t)\n\t\t}\n\n\t\tdetachSession(b.browserCtx, session)\n\n\t\treturn nil\n\t}\n\n\t// Emit the page event only for pages, not for background pages.\n\t// Background pages are created by extensions.\n\tif isPage {\n\t\tbrowserCtx.emit(EventBrowserContextPage, p)\n\t}\n\n\treturn nil\n}\n\n// errBrowserClosing is returned when a page attachment\n// is rejected because the browser has started closing.\nvar errBrowserClosing = errors.New(\"browser is closing\")\n\n// attachNewPage checks whether the browser is closing and, if not, attaches\n// the page. Returns errBrowserClosing if the browser is shutting down.\nfunc (b *Browser) attachNewPage(p *Page, ev *target.EventAttachedToTarget) error {\n\ttargetPage := ev.TargetInfo\n\n\tattachPage := func() error {\n\t\tb.pagesMu.Lock()\n\t\tdefer b.pagesMu.Unlock()\n\n\t\tif b.closing.Load() {\n\t\t\treturn errBrowserClosing\n\t\t}\n\n\t\tb.logger.Debugf(\n\t\t\t\"Browser:attachNewPage:addTarget\",\n\t\t\t\"sid:%v tid:%v pageType:%s\",\n\t\t\tev.SessionID, targetPage.TargetID, targetPage.Type,\n\t\t)\n\t\tb.pages[targetPage.TargetID] = p\n\n\t\treturn nil\n\t}\n\n\tif err := attachPage(); err != nil {\n\t\treturn err\n\t}\n\n\tb.sessionIDtoTargetIDMu.Lock()\n\tb.sessionIDtoTargetID[ev.SessionID] = targetPage.TargetID\n\tb.sessionIDtoTargetIDMu.Unlock()\n\n\treturn nil\n}\n\n// isAttachedPageValid returns true if the attached page is valid and should be\n// added to the browser's pages. It returns false if the attached page is not\n// valid and should be ignored.\nfunc (b *Browser) isAttachedPageValid(ev *target.EventAttachedToTarget, browserCtx *BrowserContext) bool {\n\ttargetPage := ev.TargetInfo\n\n\t// We're not interested in the top-level browser target, other targets or DevTools targets right now.\n\tisDevTools := strings.HasPrefix(targetPage.URL, \"devtools://devtools\")\n\tif targetPage.Type == \"browser\" || targetPage.Type == \"other\" || isDevTools {\n\t\tb.logger.Debugf(\"Browser:isAttachedPageValid:return\", \"sid:%v tid:%v (devtools)\", ev.SessionID, targetPage.TargetID)\n\t\treturn false\n\t}\n\tpageType := targetPage.Type\n\tif pageType != \"page\" && pageType != \"background_page\" {\n\t\tb.logger.Debugf(\n\t\t\t\"Browser:isAttachedPageValid\", \"sid:%v tid:%v bctxid:%v bctx nil:%t, unknown target type: %q\",\n\t\t\tev.SessionID, targetPage.TargetID, targetPage.BrowserContextID, browserCtx == nil, targetPage.Type)\n\t\treturn false\n\t}\n\t// If the target is not in the same browser context as the current one, ignore it.\n\tif browserCtx.id != targetPage.BrowserContextID {\n\t\tb.logger.Debugf(\n\t\t\t\"Browser:isAttachedPageValid\", \"incorrect browser context sid:%v tid:%v bctxid:%v target bctxid:%v\",\n\t\t\tev.SessionID, targetPage.TargetID, targetPage.BrowserContextID, browserCtx.id,\n\t\t)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// isPageAttachmentErrorIgnorable returns true if the error is ignorable.\nfunc (b *Browser) isPageAttachmentErrorIgnorable(ev *target.EventAttachedToTarget, session *Session, err error) bool {\n\ttargetPage := ev.TargetInfo\n\n\t// If we're no longer connected to browser, then ignore WebSocket errors.\n\t// This can happen when the browser is closed while the page is being attached.\n\tvar (\n\t\tisRunning = atomic.LoadInt64(&b.state) == BrowserStateOpen && b.IsConnected() // b.conn.isConnected()\n\t\twsErr     *websocket.CloseError\n\t)\n\tif !errors.As(err, &wsErr) && !isRunning {\n\t\t// If we're no longer connected to browser, then ignore WebSocket errors\n\t\tb.logger.Debugf(\"Browser:isPageAttachmentErrorIgnorable:return\",\n\t\t\t\"sid:%v tid:%v pageType:%s websocket err:%v\",\n\t\t\tev.SessionID, targetPage.TargetID, targetPage.Type, err)\n\t\treturn true\n\t}\n\n\t// No need to register the page if the test run is over.\n\tselect {\n\tcase <-b.vuCtx.Done():\n\t\tb.logger.Debugf(\"Browser:isPageAttachmentErrorIgnorable:return:<-ctx.Done\",\n\t\t\t\"sid:%v tid:%v pageType:%s err:%v\",\n\t\t\tev.SessionID, targetPage.TargetID, targetPage.Type, b.vuCtx.Err())\n\t\treturn true\n\tdefault:\n\t}\n\t// No need to register the page if the context is already done.\n\tif errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {\n\t\tb.logger.Debugf(\"Browser:isPageAttachmentErrorIgnorable:return:context.Done\",\n\t\t\t\"sid:%v tid:%v pageType:%s err:%v\", ev.SessionID, targetPage.TargetID, targetPage.Type, err)\n\t\treturn true\n\t}\n\t// Another VU or instance closed the page, and the session is closed.\n\t// This can happen if the page is closed before the attachedToTarget\n\t// event is handled.\n\tif session.Closed() {\n\t\tb.logger.Debugf(\"Browser:isPageAttachmentErrorIgnorable:return:session.Done\",\n\t\t\t\"session closed: sid:%v tid:%v pageType:%s err:%v\",\n\t\t\tev.SessionID, targetPage.TargetID, targetPage.Type, err)\n\t\treturn true\n\t}\n\n\treturn false // cannot ignore\n}\n\n// onDetachedFromTarget event can be issued multiple times per target if multiple\n// sessions have been attached to it. So we'll remove the page only once.\nfunc (b *Browser) onDetachedFromTarget(ev *target.EventDetachedFromTarget) {\n\tb.sessionIDtoTargetIDMu.RLock()\n\ttargetID, ok := b.sessionIDtoTargetID[ev.SessionID]\n\n\tb.logger.Debugf(\"Browser:onDetachedFromTarget\", \"sid:%v tid:%v\", ev.SessionID, targetID)\n\tdefer b.logger.Debugf(\"Browser:onDetachedFromTarget:return\", \"sid:%v tid:%v\", ev.SessionID, targetID)\n\n\tb.sessionIDtoTargetIDMu.RUnlock()\n\tif !ok {\n\t\t// We don't track targets of type \"browser\", \"other\" and \"devtools\",\n\t\t// so ignore if we don't recognize target.\n\t\treturn\n\t}\n\n\tb.pagesMu.Lock()\n\tdefer b.pagesMu.Unlock()\n\tif t, ok := b.pages[targetID]; ok {\n\t\tb.logger.Debugf(\"Browser:onDetachedFromTarget:deletePage\", \"sid:%v tid:%v\", ev.SessionID, targetID)\n\n\t\tdelete(b.pages, targetID)\n\t\tt.didClose()\n\t}\n}\n\nfunc (b *Browser) newPageInContext(id cdp.BrowserContextID) (*Page, error) {\n\tbc := b.getDefaultBrowserContextOrMatchedID(id)\n\tif bc.id != id {\n\t\treturn nil, fmt.Errorf(\"missing browser context %s, current context is %s\", id, bc.id)\n\t}\n\n\tctx, cancel := context.WithTimeout(b.vuCtx, b.browserOpts.Timeout)\n\tdefer cancel()\n\n\t// buffer of one is for sending the target ID whether an event handler\n\t// exists or not.\n\ttargetID := make(chan target.ID, 1)\n\n\twaitForPage, removeEventHandler := createWaitForEventHandler(\n\t\tctx,\n\t\tbc, // browser context will emit the following event:\n\t\t[]string{EventBrowserContextPage},\n\t\tfunc(e any) bool {\n\t\t\ttid := <-targetID\n\n\t\t\tb.logger.Debugf(\"Browser:newPageInContext:createWaitForEventHandler\",\n\t\t\t\t\"tid:%v ptid:%v bctxid:%v\", tid, e.(*Page).targetID, id) //nolint:forcetypeassert\n\n\t\t\t// we are only interested in the new page.\n\t\t\treturn e.(*Page).targetID == tid //nolint:forcetypeassert\n\t\t},\n\t)\n\tdefer removeEventHandler()\n\n\t// create a new page.\n\taction := target.CreateTarget(BlankPage).WithNewWindow(true).WithBrowserContextID(id)\n\ttid, err := action.Do(cdp.WithExecutor(ctx, b.conn))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating a new blank page: %w\", err)\n\t}\n\t// let the event handler know about the new page.\n\ttargetID <- tid\n\tvar page *Page\n\tselect {\n\tcase <-waitForPage:\n\t\tb.logger.Debugf(\"Browser:newPageInContext:<-waitForPage\", \"tid:%v bctxid:%v\", tid, id)\n\t\tb.pagesMu.RLock()\n\t\tpage = b.pages[tid]\n\t\tb.pagesMu.RUnlock()\n\tcase <-ctx.Done():\n\t\tb.logger.Debugf(\"Browser:newPageInContext:<-ctx.Done\", \"tid:%v bctxid:%v err:%v\", tid, id, ctx.Err())\n\t}\n\n\tif err = ContextErr(ctx); err != nil {\n\t\terr = &k6ext.UserFriendlyError{\n\t\t\tErr:     err,\n\t\t\tTimeout: b.browserOpts.Timeout,\n\t\t}\n\t}\n\n\tif err == nil && page == nil {\n\t\terr = &k6ext.UserFriendlyError{\n\t\t\tErr: errors.New(\"can't fetch the page for unknown reason\"),\n\t\t}\n\t}\n\n\treturn page, err\n}\n\n// Close shuts down the browser.\nfunc (b *Browser) Close() {\n\tif !b.closing.CompareAndSwap(false, true) {\n\t\tb.logger.Warnf(\n\t\t\t\"Browser:Close\",\n\t\t\t\"Please call browser.close only once, and do not use the browser after calling close.\",\n\t\t)\n\t\treturn\n\t}\n\t// This will help with some cleanup in the connection and event loop above in\n\t// initEvents().\n\tdefer b.browserCancelFn(errors.New(\"browser closed\"))\n\tdefer func() {\n\t\tif err := b.browserProc.Cleanup(); err != nil {\n\t\t\tb.logger.Errorf(\"Browser:Close\", \"cleaning up the user data directory: %v\", err)\n\t\t}\n\t}()\n\tdefer func() {\n\t\tfor _, fn := range b.runOnClose {\n\t\t\tif err := fn(); err != nil {\n\t\t\t\tb.logger.Errorf(\"Browser:Close\", \"running cleanup function: %v\", err)\n\t\t\t}\n\t\t}\n\t}()\n\t// Close and drain all open pages to ensure their goroutines\n\t// (frame sessions, network managers) are properly waited on\n\t// before the browser process is terminated.\n\tfor _, p := range b.getPages() {\n\t\tif err := p.Close(); err != nil {\n\t\t\tb.logger.Debugf(\"Browser:Close\", \"closing page: %v\", err)\n\t\t}\n\t}\n\n\tatomic.CompareAndSwapInt64(&b.state, b.state, BrowserStateClosed)\n\t// Signal to the connection and the process that we're gracefully closing.\n\t// We ignore any IO errors reading from the WS connection, because the below\n\t// CDP Browser.close command ends the connection unexpectedly, which causes\n\t// `websocket.ReadMessage()` to return `close 1006 (abnormal closure):\n\t// unexpected EOF`.\n\tb.conn.IgnoreIOErrors()\n\tb.browserProc.GracefulClose()\n\t// If the browser is not being executed remotely, send the Browser.close CDP\n\t// command, which triggers the browser process to exit.\n\tif !b.browserOpts.isRemoteBrowser {\n\t\tvar closeErr *websocket.CloseError\n\t\t// Using the internal context with a timeout of 10 seconds here since\n\t\t// 1. vu context will very likely be closed;\n\t\t// 2. there's a chance that the process has died but the connection still\n\t\t//    thinks it's open.\n\t\ttoCtx, toCancelCtx := context.WithTimeout(b.browserCtx, time.Second*10)\n\t\tdefer toCancelCtx()\n\t\terr := cdpbrowser.Close().Do(cdp.WithExecutor(toCtx, b.conn))\n\t\tif err != nil && !errors.As(err, &closeErr) {\n\t\t\tb.logger.Errorf(\"Browser:Close\", \"closing the browser: %v\", err)\n\t\t}\n\t}\n\t// Wait for all outstanding events (e.g. Target.detachedFromTarget) to be\n\t// processed, and for the process to exit gracefully. Otherwise kill it\n\t// forcefully after the timeout.\n\ttimeout := time.Second\n\tselect {\n\tcase <-b.browserProc.processDone:\n\tcase <-time.After(timeout):\n\t\tb.logger.Debugf(\"Browser:Close\", \"killing browser process with PID %d after %s\", b.browserProc.Pid(), timeout)\n\t\tb.browserProc.Terminate()\n\t}\n\t// This is unintuitive, since the process exited, so the connection would've\n\t// been closed as well. The reason we still call conn.Close() here is to\n\t// close all sessions and emit the EventConnectionClose event, which will\n\t// trigger the cancellation of the main browser context. We don't call it\n\t// before the process is done to avoid disconnecting too early, since we\n\t// expect some CDP events to arrive after Browser.close, and we can't know\n\t// for sure when that has finished. This will error writing to the socket,\n\t// but we ignore it.\n\tb.conn.Close()\n}\n\n// CloseContext is a short-cut function to close the current browser's context.\n// If there is no active browser context, it returns an error.\nfunc (b *Browser) CloseContext() error {\n\tif b.context == nil {\n\t\treturn errors.New(\"cannot close context as none is active in browser\")\n\t}\n\treturn b.context.Close()\n}\n\n// Context returns the current browser context or nil.\nfunc (b *Browser) Context() *BrowserContext {\n\treturn b.context\n}\n\n// IsConnected returns whether the WebSocket connection to the browser process\n// is active or not.\nfunc (b *Browser) IsConnected() bool {\n\treturn b.browserProc.isConnected()\n}\n\n// NewContext creates a new incognito-like browser context.\nfunc (b *Browser) NewContext(opts *BrowserContextOptions) (*BrowserContext, error) {\n\t_, span := TraceAPICall(b.vuCtx, \"\", \"browser.newContext\")\n\tdefer span.End()\n\n\tif b.context != nil {\n\t\treturn nil, spanRecordErrorf(span, \"existing browser context must be closed before creating a new one\")\n\t}\n\n\taction := target.CreateBrowserContext().WithDisposeOnDetach(true)\n\tbrowserContextID, err := action.Do(cdp.WithExecutor(b.vuCtx, b.conn))\n\tb.logger.Debugf(\"Browser:NewContext\", \"bctxid:%v\", browserContextID)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"creating browser context ID %s: %w\", browserContextID, err)\n\t}\n\n\tbrowserCtx, err := NewBrowserContext(b.vuCtx, b, browserContextID, opts, b.logger)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"new browser context: %w\", err)\n\t}\n\tb.runOnClose = append(b.runOnClose, browserCtx.cleanup)\n\n\tb.contextMu.Lock()\n\tdefer b.contextMu.Unlock()\n\tb.context = browserCtx\n\n\treturn browserCtx, nil\n}\n\n// NewPage creates a new tab in the browser window.\nfunc (b *Browser) NewPage(opts *BrowserContextOptions) (*Page, error) {\n\t_, span := TraceAPICall(b.vuCtx, \"\", \"browser.newPage\")\n\tdefer span.End()\n\n\tbrowserCtx, err := b.NewContext(opts)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"new page: %w\", err)\n\t}\n\n\tpage, err := browserCtx.NewPage()\n\tif err != nil {\n\t\treturn nil, spanRecordError(span, err)\n\t}\n\n\treturn page, nil\n}\n\n// On returns a Promise that is resolved when the browser process is disconnected.\n// The only accepted event value is \"disconnected\".\nfunc (b *Browser) On(event string) (bool, error) {\n\tif event != EventBrowserDisconnected {\n\t\treturn false, fmt.Errorf(\"unknown browser event: %q, must be %q\", event, EventBrowserDisconnected)\n\t}\n\n\tselect {\n\tcase <-b.browserProc.lostConnection:\n\t\treturn true, nil\n\tcase <-b.vuCtx.Done():\n\t\treturn false, fmt.Errorf(\"browser.on promise rejected: %w\", ContextErr(b.vuCtx))\n\t}\n}\n\n// UserAgent returns the controlled browser's user agent string.\nfunc (b *Browser) UserAgent() string {\n\treturn b.version.userAgent\n}\n\n// Version returns the controlled browser's version.\nfunc (b *Browser) Version() string {\n\tproduct := b.version.product\n\t_, after, ok := strings.Cut(product, \"/\")\n\tif !ok {\n\t\treturn product\n\t}\n\treturn after\n}\n\n// fetchVersion returns the browser version information.\nfunc (b *Browser) fetchVersion() (browserVersion, error) {\n\tvar (\n\t\tbv  browserVersion\n\t\terr error\n\t)\n\tbv.protocolVersion, bv.product, bv.revision, bv.userAgent, bv.jsVersion, err = cdpbrowser.\n\t\tGetVersion().\n\t\tDo(cdp.WithExecutor(b.vuCtx, b.conn))\n\tif err != nil {\n\t\treturn browserVersion{}, fmt.Errorf(\"getting browser version information: %w\", err)\n\t}\n\n\t// Adjust the user agent to remove the headless part.\n\t//\n\t// Including Headless might cause issues with some websites that treat headless\n\t// browsers differently. Later on, [BrowserContext] will set the user agent to\n\t// this user agent if not set by the user. This will force [FrameSession] to\n\t// set the user agent to the browser's user agent.\n\t//\n\t// Doing this here provides a consistent user agent across all browser contexts.\n\t// Also, it makes it consistent to query the user agent from the browser.\n\tif b.browserOpts.Headless {\n\t\tbv.userAgent = strings.ReplaceAll(bv.userAgent, \"Headless\", \"\")\n\t}\n\n\treturn bv, nil\n}\n\n// WsURL returns the Websocket URL that the browser is listening on for CDP clients.\nfunc (b *Browser) WsURL() string {\n\treturn b.browserProc.WsURL()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_context.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tcdpbrowser \"github.com/chromedp/cdproto/browser\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/storage\"\n\t\"github.com/chromedp/cdproto/target\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common/js\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6error\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\n// waitForEventType represents the event types that can be used when working\n// with the browserContext.waitForEvent API.\ntype waitForEventType string\n\n// Cookie represents a browser cookie.\n//\n// https://datatracker.ietf.org/doc/html/rfc6265.\ntype Cookie struct {\n\tName     string         `js:\"name\" json:\"name\"`         // Cookie name.\n\tValue    string         `js:\"value\" json:\"value\"`       // Cookie value.\n\tDomain   string         `js:\"domain\" json:\"domain\"`     // Cookie domain.\n\tPath     string         `js:\"path\" json:\"path\"`         // Cookie path.\n\tHTTPOnly bool           `js:\"httpOnly\" json:\"httpOnly\"` // True if cookie is http-only.\n\tSecure   bool           `js:\"secure\" json:\"secure\"`     // True if cookie is secure.\n\tSameSite CookieSameSite `js:\"sameSite\" json:\"sameSite\"` // Cookie SameSite type.\n\tURL      string         `js:\"url\" json:\"url,omitempty\"` // Cookie URL.\n\t// Cookie expiration date as the number of seconds since the UNIX epoch.\n\tExpires int64 `js:\"expires\" json:\"expires\"`\n}\n\n// CookieSameSite represents the cookie's 'SameSite' status.\n//\n// https://tools.ietf.org/html/draft-west-first-party-cookies.\ntype CookieSameSite string\n\nconst (\n\t// CookieSameSiteStrict sets the cookie to be sent only in a first-party\n\t// context and not be sent along with requests initiated by third party\n\t// websites.\n\tCookieSameSiteStrict CookieSameSite = \"Strict\"\n\n\t// CookieSameSiteLax sets the cookie to be sent along with \"same-site\"\n\t// requests, and with \"cross-site\" top-level navigations.\n\tCookieSameSiteLax CookieSameSite = \"Lax\"\n\n\t// CookieSameSiteNone sets the cookie to be sent in all contexts, i.e\n\t// potentially insecure third-party requests.\n\tCookieSameSiteNone CookieSameSite = \"None\"\n)\n\nconst (\n\t// waitForEventTypePage represents the page event which fires when a new\n\t// page is created.\n\twaitForEventTypePage = \"page\"\n)\n\n// BrowserContext stores context information for a single independent browser session.\n// A newly launched browser instance contains a default browser context.\n// Any browser context created aside from the default will be considered an \"incognito\"\n// browser context and will not store any data on disk.\ntype BrowserContext struct {\n\tBaseEventEmitter\n\n\tctx             context.Context\n\tbrowser         *Browser\n\tid              cdp.BrowserContextID\n\topts            *BrowserContextOptions\n\ttimeoutSettings *TimeoutSettings\n\tlogger          *log.Logger\n\n\tevaluateOnNewDocumentSources []string\n\n\t// DownloadsPath is the path where downloads will be stored.\n\tDownloadsPath string\n}\n\n// artifactsDirectory is the prefix for the temporary directory created for downloads.\nconst artifactsDirectory = \"k6browser-artifacts-\"\n\n// setDownloadsPath sets the downloads path.\n// If the provided path is empty, a temporary directory with\n// an artifactsDirectory prefix will be created.\nfunc (b *BrowserContext) setDownloadsPath(path string) error {\n\tpath = strings.TrimSpace(path)\n\tif path != \"\" {\n\t\tb.DownloadsPath = path\n\t\treturn nil\n\t}\n\tdir, err := os.MkdirTemp(os.TempDir(), artifactsDirectory+\"*\") //nolint:forbidigo\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating temporary directory for downloads: %w\", err)\n\t}\n\tb.DownloadsPath = dir\n\n\treturn nil\n}\n\n// cleanup cleans up the resources associated with the browser context.\nfunc (b *BrowserContext) cleanup() error {\n\tif err := os.RemoveAll(b.DownloadsPath); err != nil { //nolint:forbidigo\n\t\treturn fmt.Errorf(\"removing downloads path: %w\", err)\n\t}\n\tb.DownloadsPath = \"\"\n\n\treturn nil\n}\n\n// NewBrowserContext creates a new browser context.\nfunc NewBrowserContext(\n\tctx context.Context, browser *Browser, id cdp.BrowserContextID, opts *BrowserContextOptions, logger *log.Logger,\n) (*BrowserContext, error) {\n\t// set the default options if none provided.\n\tif opts == nil {\n\t\topts = DefaultBrowserContextOptions()\n\t}\n\t// Always use the [Browser]'s user agent if it's not set by the user.\n\t// Setting this forces [FrameSession] to set Chromium's user agent.\n\tif strings.TrimSpace(opts.UserAgent) == \"\" {\n\t\topts.UserAgent = browser.UserAgent()\n\t}\n\n\tb := BrowserContext{\n\t\tBaseEventEmitter: NewBaseEventEmitter(ctx),\n\t\tctx:              ctx,\n\t\tbrowser:          browser,\n\t\tid:               id,\n\t\topts:             opts,\n\t\tlogger:           logger,\n\t\ttimeoutSettings:  NewTimeoutSettings(nil),\n\t}\n\n\tif len(opts.Permissions) > 0 {\n\t\terr := b.GrantPermissions(opts.Permissions, GrantPermissionsOptions{})\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif err := b.AddInitScript(js.WebVitalIIFEScript); err != nil {\n\t\treturn nil, fmt.Errorf(\"adding web vital script to new browser context: %w\", err)\n\t}\n\tif err := b.AddInitScript(js.WebVitalInitScript); err != nil {\n\t\treturn nil, fmt.Errorf(\"adding web vital init script to new browser context: %w\", err)\n\t}\n\tif err := b.setDownloadsPath(opts.DownloadsPath); err != nil {\n\t\treturn nil, fmt.Errorf(\"setting downloads path: %w\", err)\n\t}\n\n\treturn &b, nil\n}\n\n// AddInitScript adds a script that will be initialized on all new pages.\nfunc (b *BrowserContext) AddInitScript(script string) error {\n\tb.logger.Debugf(\"BrowserContext:AddInitScript\", \"bctxid:%v\", b.id)\n\n\tb.evaluateOnNewDocumentSources = append(b.evaluateOnNewDocumentSources, script)\n\n\tfor _, p := range b.browser.getPages() {\n\t\tif err := p.evaluateOnNewDocument(script); err != nil {\n\t\t\treturn fmt.Errorf(\"adding init script to browser context: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (b *BrowserContext) applyAllInitScripts(p *Page) error {\n\tfor _, source := range b.evaluateOnNewDocumentSources {\n\t\tif err := p.evaluateOnNewDocument(source); err != nil {\n\t\t\treturn fmt.Errorf(\"adding init script to browser context: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Browser returns the browser instance that this browser context belongs to.\nfunc (b *BrowserContext) Browser() *Browser {\n\treturn b.browser\n}\n\n// ClearPermissions clears any permission overrides.\nfunc (b *BrowserContext) ClearPermissions() error {\n\tb.logger.Debugf(\"BrowserContext:ClearPermissions\", \"bctxid:%v\", b.id)\n\n\taction := cdpbrowser.ResetPermissions().WithBrowserContextID(b.id)\n\tif err := action.Do(cdp.WithExecutor(b.ctx, b.browser.conn)); err != nil {\n\t\treturn fmt.Errorf(\"clearing permissions: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Close shuts down the browser context.\nfunc (b *BrowserContext) Close() error {\n\tb.logger.Debugf(\"BrowserContext:Close\", \"bctxid:%v\", b.id)\n\n\tif b.id == \"\" {\n\t\treturn fmt.Errorf(\"default browser context can't be closed\")\n\t}\n\tif err := b.browser.disposeContext(b.id); err != nil {\n\t\treturn fmt.Errorf(\"disposing browser context: %w\", err)\n\t}\n\treturn nil\n}\n\n// GrantPermissions enables the specified permissions, all others will be disabled.\nfunc (b *BrowserContext) GrantPermissions(permissions []string, opts GrantPermissionsOptions) error {\n\tb.logger.Debugf(\"BrowserContext:GrantPermissions\", \"bctxid:%v\", b.id)\n\n\tpermsToProtocol := map[string]cdpbrowser.PermissionType{\n\t\t\"geolocation\":          cdpbrowser.PermissionTypeGeolocation,\n\t\t\"midi\":                 cdpbrowser.PermissionTypeMidi,\n\t\t\"midi-sysex\":           cdpbrowser.PermissionTypeMidiSysex,\n\t\t\"notifications\":        cdpbrowser.PermissionTypeNotifications,\n\t\t\"camera\":               cdpbrowser.PermissionTypeVideoCapture,\n\t\t\"microphone\":           cdpbrowser.PermissionTypeAudioCapture,\n\t\t\"background-sync\":      cdpbrowser.PermissionTypeBackgroundSync,\n\t\t\"ambient-light-sensor\": cdpbrowser.PermissionTypeSensors,\n\t\t\"accelerometer\":        cdpbrowser.PermissionTypeSensors,\n\t\t\"gyroscope\":            cdpbrowser.PermissionTypeSensors,\n\t\t\"magnetometer\":         cdpbrowser.PermissionTypeSensors,\n\t\t\"clipboard-read\":       cdpbrowser.PermissionTypeClipboardReadWrite,\n\t\t\"clipboard-write\":      cdpbrowser.PermissionTypeClipboardSanitizedWrite,\n\t\t\"payment-handler\":      cdpbrowser.PermissionTypePaymentHandler,\n\t}\n\n\tperms := make([]cdpbrowser.PermissionType, 0, len(permissions))\n\tfor _, p := range permissions {\n\t\tproto, ok := permsToProtocol[p]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"%q is an invalid permission\", p)\n\t\t}\n\t\tperms = append(perms, proto)\n\t}\n\n\taction := cdpbrowser.GrantPermissions(perms).WithOrigin(opts.Origin).WithBrowserContextID(b.id)\n\tif err := action.Do(cdp.WithExecutor(b.ctx, b.browser.conn)); err != nil {\n\t\treturn fmt.Errorf(\"granting browser permissions: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// NewPage creates a new page inside this browser context.\nfunc (b *BrowserContext) NewPage() (*Page, error) {\n\tb.logger.Debugf(\"BrowserContext:NewPage\", \"bctxid:%v\", b.id)\n\t_, span := TraceAPICall(b.ctx, \"\", \"browserContext.newPage\")\n\tdefer span.End()\n\n\tp, err := b.browser.newPageInContext(b.id)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"creating new page in browser context: %w\", err)\n\t}\n\n\tb.logger.Debugf(\"BrowserContext:NewPage:return\", \"bctxid:%v ptid:%s\", b.id, p.targetID)\n\treturn p, nil\n}\n\n// Pages returns a list of pages inside this browser context.\nfunc (b *BrowserContext) Pages() []*Page {\n\treturn append([]*Page{}, b.browser.getPages()...)\n}\n\n// SetDefaultNavigationTimeout sets the default navigation timeout in milliseconds.\nfunc (b *BrowserContext) SetDefaultNavigationTimeout(timeout int64) {\n\tb.logger.Debugf(\"BrowserContext:SetDefaultNavigationTimeout\", \"bctxid:%v timeout:%d\", b.id, timeout)\n\n\tb.timeoutSettings.setDefaultNavigationTimeout(time.Duration(timeout) * time.Millisecond)\n}\n\n// SetDefaultTimeout sets the default maximum timeout in milliseconds.\nfunc (b *BrowserContext) SetDefaultTimeout(timeout int64) {\n\tb.logger.Debugf(\"BrowserContext:SetDefaultTimeout\", \"bctxid:%v timeout:%d\", b.id, timeout)\n\n\tb.timeoutSettings.setDefaultTimeout(time.Duration(timeout) * time.Millisecond)\n}\n\n// SetGeolocation overrides the geo location of the user.\nfunc (b *BrowserContext) SetGeolocation(g *Geolocation) error {\n\tb.logger.Debugf(\"BrowserContext:SetGeolocation\", \"bctxid:%v\", b.id)\n\n\tif err := g.Validate(); err != nil {\n\t\treturn fmt.Errorf(\"validating geo location: %w\", err)\n\t}\n\n\tb.opts.Geolocation = g\n\tfor _, p := range b.browser.getPages() {\n\t\tif err := p.updateGeolocation(); err != nil {\n\t\t\treturn fmt.Errorf(\"updating geo location in target ID %s: %w\", p.targetID, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// SetHTTPCredentials sets username/password credentials to use for HTTP authentication.\n//\n// Deprecated: Create a new BrowserContext with httpCredentials instead.\n// See for details:\n// - https://github.com/microsoft/playwright/issues/2196#issuecomment-627134837\n// - https://github.com/microsoft/playwright/pull/2763\nfunc (b *BrowserContext) SetHTTPCredentials(hc Credentials) error {\n\tb.logger.Warnf(\"setHTTPCredentials\", \"setHTTPCredentials is deprecated.\"+\n\t\t\" Create a new BrowserContext with httpCredentials instead.\")\n\tb.logger.Debugf(\"BrowserContext:SetHTTPCredentials\", \"bctxid:%v\", b.id)\n\n\tb.opts.HTTPCredentials = hc\n\tfor _, p := range b.browser.getPages() {\n\t\tif err := p.updateHTTPCredentials(); err != nil {\n\t\t\treturn fmt.Errorf(\"setting HTTP credentials in target ID %s: %w\", p.targetID, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// SetOffline toggles the browser's connectivity on/off.\nfunc (b *BrowserContext) SetOffline(offline bool) error {\n\tb.logger.Debugf(\"BrowserContext:SetOffline\", \"bctxid:%v offline:%t\", b.id, offline)\n\n\tb.opts.Offline = offline\n\tfor _, p := range b.browser.getPages() {\n\t\tif err := p.updateOffline(); err != nil {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"setting offline status to %t for the browser context ID %s: %w\",\n\t\t\t\toffline, b.id, err,\n\t\t\t)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Timeout will return the default timeout or the one set by the user.\nfunc (b *BrowserContext) Timeout() time.Duration {\n\treturn b.timeoutSettings.timeout()\n}\n\n// WaitForEvent waits for event.\nfunc (b *BrowserContext) WaitForEvent(event string, f func(p *Page) (bool, error), timeout time.Duration) (any, error) {\n\tb.logger.Debugf(\"BrowserContext:WaitForEvent\", \"bctxid:%v event:%q\", b.id, event)\n\n\treturn b.waitForEvent(waitForEventType(event), f, timeout)\n}\n\nfunc (b *BrowserContext) waitForEvent(\n\tevent waitForEventType,\n\tpredicateFn func(p *Page) (bool, error),\n\ttimeout time.Duration,\n) (any, error) {\n\tif event != waitForEventTypePage {\n\t\treturn nil, fmt.Errorf(\"incorrect event %q, %q is the only event supported\", event, waitForEventTypePage)\n\t}\n\n\tevCancelCtx, evCancelFn := context.WithCancel(b.ctx)\n\tdefer evCancelFn() // This will remove the event handler once we return from here.\n\n\tchEvHandler := make(chan Event)\n\tch := make(chan any)\n\terrCh := make(chan error)\n\n\tgo b.runWaitForEventHandler(evCancelCtx, chEvHandler, predicateFn, ch, errCh)\n\n\tb.on(evCancelCtx, []string{EventBrowserContextPage}, chEvHandler)\n\n\tselect {\n\tcase <-b.ctx.Done():\n\t\treturn nil, ContextErr(b.ctx) //nolint:wrapcheck\n\tcase <-time.After(timeout):\n\t\tb.logger.Debugf(\"BrowserContext:WaitForEvent:timeout\", \"bctxid:%v event:%q\", b.id, event)\n\t\treturn nil, fmt.Errorf(\"waitForEvent timed out after %v\", timeout)\n\tcase evData := <-ch:\n\t\tb.logger.Debugf(\"BrowserContext:WaitForEvent:evData\", \"bctxid:%v event:%q\", b.id, event)\n\t\treturn evData, nil\n\tcase err := <-errCh:\n\t\tb.logger.Debugf(\"BrowserContext:WaitForEvent:err\", \"bctxid:%v event:%q, err:%v\", b.id, event, err)\n\t\treturn nil, err\n\t}\n}\n\n// runWaitForEventHandler can work with a nil predicateFn. If predicateFn is\n// nil it will return the response straight away.\nfunc (b *BrowserContext) runWaitForEventHandler(\n\tctx context.Context,\n\tchEvHandler chan Event, predicateFn func(p *Page) (bool, error),\n\tout chan<- any, errOut chan<- error,\n) {\n\tb.logger.Debugf(\"BrowserContext:runWaitForEventHandler:go():starts\", \"bctxid:%v\", b.id)\n\tdefer b.logger.Debugf(\"BrowserContext:runWaitForEventHandler:go():returns\", \"bctxid:%v\", b.id)\n\n\tdefer func() {\n\t\tclose(out)\n\t\tclose(errOut)\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tb.logger.Debugf(\"BrowserContext:runWaitForEventHandler:go():ctx:done\", \"bctxid:%v\", b.id)\n\t\t\treturn\n\t\tcase ev := <-chEvHandler:\n\t\t\tif ev.typ != EventBrowserContextPage {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tb.logger.Debugf(\"BrowserContext:runWaitForEventHandler:go():EventBrowserContextPage\", \"bctxid:%v\", b.id)\n\t\t\tp, ok := ev.data.(*Page)\n\t\t\tif !ok {\n\t\t\t\terrOut <- fmt.Errorf(\"on create page event failed to return a page: %w\", k6error.ErrFatal)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif predicateFn == nil {\n\t\t\t\tb.logger.Debugf(\"BrowserContext:runWaitForEventHandler:go():EventBrowserContextPage:return\", \"bctxid:%v\", b.id)\n\t\t\t\tout <- p\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tretVal, err := predicateFn(p)\n\t\t\tif err != nil {\n\t\t\t\terrOut <- fmt.Errorf(\"predicate function failed: %w\", err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif retVal {\n\t\t\t\tb.logger.Debugf(\n\t\t\t\t\t\"BrowserContext:runWaitForEventHandler:go():EventBrowserContextPage:predicateFn:return\",\n\t\t\t\t\t\"bctxid:%v\", b.id,\n\t\t\t\t)\n\t\t\t\tout <- p\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (b *BrowserContext) getSession(id target.SessionID) *Session {\n\treturn b.browser.conn.getSession(id)\n}\n\n// AddCookies adds cookies into this browser context.\n// All pages within this context will have these cookies installed.\nfunc (b *BrowserContext) AddCookies(cookies []*Cookie) error {\n\tb.logger.Debugf(\"BrowserContext:AddCookies\", \"bctxid:%v\", b.id)\n\n\t// skip work if no cookies provided.\n\tif len(cookies) == 0 {\n\t\treturn fmt.Errorf(\"no cookies provided\")\n\t}\n\n\tcookiesToSet := make([]*network.CookieParam, 0, len(cookies))\n\tfor _, c := range cookies {\n\t\tif c.Name == \"\" {\n\t\t\treturn fmt.Errorf(\"cookie name must be set: %#v\", c)\n\t\t}\n\t\tif c.Value == \"\" {\n\t\t\treturn fmt.Errorf(\"cookie value must be set: %#v\", c)\n\t\t}\n\t\t// if URL is not set, both Domain and Path must be provided\n\t\tif c.URL == \"\" && (c.Domain == \"\" || c.Path == \"\") {\n\t\t\tconst msg = \"if cookie URL is not provided, both domain and path must be specified: %#v\"\n\t\t\treturn fmt.Errorf(msg, c)\n\t\t}\n\t\t// calculate the cookie expiration date, session cookie if not set.\n\t\tvar ts *cdp.TimeSinceEpoch\n\t\tif c.Expires > 0 {\n\t\t\tt := cdp.TimeSinceEpoch(time.Unix(c.Expires, 0))\n\t\t\tts = &t\n\t\t}\n\t\tcookiesToSet = append(cookiesToSet, &network.CookieParam{\n\t\t\tName:     c.Name,\n\t\t\tValue:    c.Value,\n\t\t\tDomain:   c.Domain,\n\t\t\tPath:     c.Path,\n\t\t\tURL:      c.URL,\n\t\t\tExpires:  ts,\n\t\t\tHTTPOnly: c.HTTPOnly,\n\t\t\tSecure:   c.Secure,\n\t\t\tSameSite: network.CookieSameSite(c.SameSite),\n\t\t})\n\t}\n\n\tsetCookies := storage.\n\t\tSetCookies(cookiesToSet).\n\t\tWithBrowserContextID(b.id)\n\tif err := setCookies.Do(cdp.WithExecutor(b.ctx, b.browser.conn)); err != nil {\n\t\treturn fmt.Errorf(\"cannot set cookies: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// ClearCookies clears cookies.\nfunc (b *BrowserContext) ClearCookies() error {\n\tb.logger.Debugf(\"BrowserContext:ClearCookies\", \"bctxid:%v\", b.id)\n\n\tclearCookies := storage.\n\t\tClearCookies().\n\t\tWithBrowserContextID(b.id)\n\tif err := clearCookies.Do(cdp.WithExecutor(b.ctx, b.browser.conn)); err != nil {\n\t\treturn fmt.Errorf(\"clearing cookies: %w\", err)\n\t}\n\treturn nil\n}\n\n// Cookies returns all cookies.\n// Some of them can be added with the AddCookies method and some of them are\n// automatically taken from the browser context when it is created. And some of\n// them are set by the page, i.e., using the Set-Cookie HTTP header or via\n// JavaScript like document.cookie.\nfunc (b *BrowserContext) Cookies(urls ...string) ([]*Cookie, error) {\n\tb.logger.Debugf(\"BrowserContext:Cookies\", \"bctxid:%v\", b.id)\n\n\t// get cookies from this browser context.\n\tgetCookies := storage.\n\t\tGetCookies().\n\t\tWithBrowserContextID(b.id)\n\tnetworkCookies, err := getCookies.Do(\n\t\tcdp.WithExecutor(b.ctx, b.browser.conn),\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"retrieving cookies: %w\", err)\n\t}\n\t// return if no cookies found so we don't have to needlessly convert them.\n\t// users can still work with cookies using the empty slice.\n\t// like this: cookies.length === 0.\n\tif len(networkCookies) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// convert the received CDP cookies to the browser API format.\n\tcookies := make([]*Cookie, len(networkCookies))\n\tfor i, c := range networkCookies {\n\t\tcookies[i] = &Cookie{\n\t\t\tName:     c.Name,\n\t\t\tValue:    c.Value,\n\t\t\tDomain:   c.Domain,\n\t\t\tPath:     c.Path,\n\t\t\tExpires:  int64(c.Expires),\n\t\t\tHTTPOnly: c.HTTPOnly,\n\t\t\tSecure:   c.Secure,\n\t\t\tSameSite: CookieSameSite(c.SameSite),\n\t\t}\n\t}\n\t// filter cookies by the provided URLs.\n\tcookies, err = filterCookies(cookies, urls...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"filtering cookies: %w\", err)\n\t}\n\tif len(cookies) == 0 {\n\t\treturn nil, nil\n\t}\n\n\treturn cookies, nil\n}\n\n// filterCookies filters the given cookies based on URLs.\n// If an error occurs while parsing the cookie URLs, the error is returned.\nfunc filterCookies(cookies []*Cookie, urls ...string) ([]*Cookie, error) {\n\tif len(urls) == 0 || len(cookies) == 0 {\n\t\treturn cookies, nil\n\t}\n\n\tpurls, err := parseURLs(urls...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing urls: %w\", err)\n\t}\n\n\t// the following algorithm is like a sorting algorithm,\n\t// but instead of sorting, it filters the cookies slice\n\t// in place, without allocating a new slice. this is\n\t// done to avoid unnecessary allocations and copying\n\t// of data.\n\t//\n\t// n is used to remember the last cookie that should be\n\t// kept in the cookies slice. all cookies before n should\n\t// be kept, all cookies after n should be removed. it\n\t// constantly shifts cookies to be kept to the left in the\n\t// slice, overwriting cookies that should be removed.\n\t//\n\t// if a cookie should not be kept, it will be overwritten\n\t// by the next cookie that should be kept. if no cookies\n\t// should be kept, a nil slice is returned. otherwise,\n\t// the slice is truncated to the last cookie that should\n\t// be kept.\n\n\tvar n int\n\n\tfor _, c := range cookies {\n\t\tvar keep bool\n\n\t\tfor _, uri := range purls {\n\t\t\tif shouldKeepCookie(c, uri) {\n\t\t\t\tkeep = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !keep {\n\t\t\tcontinue\n\t\t}\n\t\tcookies[n] = c\n\t\tn++\n\t}\n\t// if no cookies should be kept, return nil instead of\n\t// an empty slice to conform with the API error behavior.\n\t// also makes tests concise.\n\tif n == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// remove all cookies after the last cookie that should be kept.\n\treturn cookies[:n], nil\n}\n\n// shouldKeepCookie determines whether a cookie should be kept,\n// based on its compatibility with a specific URL.\n// Returns true if the cookie should be kept, false otherwise.\nfunc shouldKeepCookie(c *Cookie, uri *url.URL) bool {\n\t// Ensure consistent domain formatting for easier comparison.\n\t// A leading dot means the cookie is valid across subdomains.\n\t// For example, if the domain is example.com, then adding a\n\t// dot turns it into .example.com, making the cookie valid\n\t// for sub.example.com, another.example.com, etc.\n\tdomain := c.Domain\n\tif !strings.HasPrefix(domain, \".\") {\n\t\tdomain = \".\" + domain\n\t}\n\t// Confirm that the cookie's domain is a suffix of the URL's\n\t// hostname, emulating how a browser would scope cookies to\n\t// specific domains.\n\tif !strings.HasSuffix(domain, \".\"+uri.Hostname()) {\n\t\treturn false\n\t}\n\t// Follow RFC 6265 for cookies: an empty or missing path should\n\t// be treated as \"/\".\n\t//\n\t// See: https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4\n\tpath := c.Path\n\tif path == \"\" {\n\t\tpath = \"/\"\n\t}\n\t// Ensure that the cookie applies to the specific path of the\n\t// URL, emulating how a browser would scope cookies to specific\n\t// paths within a domain.\n\tif !strings.HasPrefix(path, uri.Path) {\n\t\treturn false\n\t}\n\t// Emulate browser behavior: Don't include secure cookies when\n\t// the scheme is not HTTPS, unless it's localhost.\n\tif uri.Scheme != \"https\" && uri.Hostname() != \"localhost\" && c.Secure {\n\t\treturn false\n\t}\n\n\t// Keep the cookie.\n\treturn true\n}\n\n// parseURLs parses the given URLs.\n// If an error occurs while parsing a URL, the error is returned.\nfunc parseURLs(urls ...string) ([]*url.URL, error) {\n\tpurls := make([]*url.URL, len(urls))\n\tfor i, u := range urls {\n\t\turi, err := url.ParseRequestURI(\n\t\t\tstrings.TrimSpace(u),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%q: %w\", u, err)\n\t\t}\n\t\tpurls[i] = uri\n\t}\n\n\treturn purls, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_context_options.go",
    "content": "package common\n\nimport \"fmt\"\n\n// BrowserContextOptions stores browser context options.\ntype BrowserContextOptions struct {\n\tAcceptDownloads   bool              `js:\"acceptDownloads\"`\n\tDownloadsPath     string            `js:\"downloadsPath\"`\n\tBypassCSP         bool              `js:\"bypassCSP\"`\n\tColorScheme       ColorScheme       `js:\"colorScheme\"`\n\tDeviceScaleFactor float64           `js:\"deviceScaleFactor\"`\n\tExtraHTTPHeaders  map[string]string `js:\"extraHTTPHeaders\"`\n\tGeolocation       *Geolocation      `js:\"geolocation\"`\n\tHasTouch          bool              `js:\"hasTouch\"`\n\tHTTPCredentials   Credentials       `js:\"httpCredentials\"`\n\tIgnoreHTTPSErrors bool              `js:\"ignoreHTTPSErrors\"`\n\tIsMobile          bool              `js:\"isMobile\"`\n\tJavaScriptEnabled bool              `js:\"javaScriptEnabled\"`\n\tLocale            string            `js:\"locale\"`\n\tOffline           bool              `js:\"offline\"`\n\tPermissions       []string          `js:\"permissions\"`\n\tReducedMotion     ReducedMotion     `js:\"reducedMotion\"`\n\tScreen            Screen            `js:\"screen\"`\n\tTimezoneID        string            `js:\"timezoneID\"`\n\tUserAgent         string            `js:\"userAgent\"`\n\tVideosPath        string            `js:\"videosPath\"`\n\tViewport          Viewport          `js:\"viewport\"`\n}\n\n// DefaultBrowserContextOptions returns the default browser context options.\nfunc DefaultBrowserContextOptions() *BrowserContextOptions {\n\treturn &BrowserContextOptions{\n\t\tColorScheme:       ColorSchemeLight,\n\t\tDeviceScaleFactor: 1.0,\n\t\tExtraHTTPHeaders:  make(map[string]string),\n\t\tJavaScriptEnabled: true,\n\t\tLocale:            DefaultLocale,\n\t\tPermissions:       []string{},\n\t\tReducedMotion:     ReducedMotionNoPreference,\n\t\tScreen:            Screen{Width: DefaultScreenWidth, Height: DefaultScreenHeight},\n\t\tViewport:          Viewport{Width: DefaultScreenWidth, Height: DefaultScreenHeight},\n\t}\n}\n\n// Geolocation represents a geolocation.\ntype Geolocation struct {\n\tLatitude  float64 `js:\"latitude\"`\n\tLongitude float64 `js:\"longitude\"`\n\tAccuracy  float64 `js:\"accuracy\"`\n}\n\n// Validate validates the [Geolocation].\nfunc (g *Geolocation) Validate() error {\n\tif g.Longitude < -180 || g.Longitude > 180 {\n\t\treturn fmt.Errorf(`invalid longitude \"%.2f\": precondition -180 <= LONGITUDE <= 180 failed`, g.Longitude)\n\t}\n\tif g.Latitude < -90 || g.Latitude > 90 {\n\t\treturn fmt.Errorf(`invalid latitude \"%.2f\": precondition -90 <= LATITUDE <= 90 failed`, g.Latitude)\n\t}\n\tif g.Accuracy < 0 {\n\t\treturn fmt.Errorf(`invalid accuracy \"%.2f\": precondition 0 <= ACCURACY failed`, g.Accuracy)\n\t}\n\treturn nil\n}\n\n// GrantPermissionsOptions is used by BrowserContext.GrantPermissions.\ntype GrantPermissionsOptions struct {\n\tOrigin string\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_context_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common/js\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\nfunc TestNewBrowserContext(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"add_web_vital_js_scripts_to_context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tlogger := log.NewNullLogger()\n\t\tb := newBrowser(context.Background(), ctx, cancel, nil, NewLocalBrowserOptions(), logger)\n\n\t\tvu := k6test.NewVU(t)\n\t\tctx = k6ext.WithVU(ctx, vu)\n\n\t\tbc, err := NewBrowserContext(ctx, b, \"some-id\", nil, nil)\n\t\trequire.NoError(t, err)\n\n\t\twebVitalIIFEScriptFound := false\n\t\twebVitalInitScriptFound := false\n\t\tfor _, script := range bc.evaluateOnNewDocumentSources {\n\t\t\tswitch script {\n\t\t\tcase js.WebVitalIIFEScript:\n\t\t\t\twebVitalIIFEScriptFound = true\n\t\t\tcase js.WebVitalInitScript:\n\t\t\t\twebVitalInitScriptFound = true\n\t\t\tdefault:\n\t\t\t\tassert.Fail(t, \"script is neither WebVitalIIFEScript, nor WebVitalInitScript\")\n\t\t\t}\n\t\t}\n\n\t\tassert.True(t, webVitalIIFEScriptFound, \"WebVitalIIFEScript was not initialized in the context\")\n\t\tassert.True(t, webVitalInitScriptFound, \"WebVitalInitScript was not initialized in the context\")\n\t})\n}\n\nfunc TestSetDownloadsPath(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"empty_path\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar bc BrowserContext\n\t\trequire.NoError(t, bc.setDownloadsPath(\"\"))\n\t\tassert.NotEmpty(t, bc.DownloadsPath)\n\t\tassert.Contains(t, bc.DownloadsPath, artifactsDirectory)\n\t\tassert.DirExists(t, bc.DownloadsPath)\n\t})\n\tt.Run(\"non_empty_path\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar bc BrowserContext\n\t\tpath := \"/my/directory\"\n\t\trequire.NoError(t, bc.setDownloadsPath(path))\n\t\tassert.Equal(t, path, bc.DownloadsPath)\n\t})\n\tt.Run(\"cleanup\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar bc BrowserContext\n\t\trequire.NoError(t, bc.setDownloadsPath(\"\"))\n\t\tassert.DirExists(t, bc.DownloadsPath)\n\t\trequire.NoError(t, bc.cleanup())\n\t\tassert.NoDirExists(t, bc.DownloadsPath)\n\t})\n}\n\nfunc TestFilterCookies(t *testing.T) {\n\tt.Parallel()\n\n\ttests := map[string]struct {\n\t\tfilterByURLs []string\n\t\tcookies      []*Cookie\n\t\twantCookies  []*Cookie\n\t\twantErr      bool\n\t}{\n\t\t\"no_cookies\": {\n\t\t\tfilterByURLs: []string{\"https://example.com\"},\n\t\t\tcookies:      nil,\n\t\t\twantCookies:  nil,\n\t\t},\n\t\t\"filter_none\": {\n\t\t\tfilterByURLs: nil,\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"bar.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"bar.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_by_url\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://foo.com\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"bar.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"baz.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_by_urls\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://foo.com\",\n\t\t\t\t\"https://baz.com\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"bar.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"baz.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"baz.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_by_subdomain\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://sub.foo.com\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"sub.foo.com\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \".foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"sub.foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_dot_prefixed_domains\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://foo.com\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \".foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \".foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_by_secure_cookies\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://foo.com\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t\tSecure: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t\tSecure: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_by_http_only_cookies\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://foo.com\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain:   \"foo.com\",\n\t\t\t\t\tHTTPOnly: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain:   \"foo.com\",\n\t\t\t\t\tHTTPOnly: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_by_path\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://foo.com/bar\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t\tPath:   \"/bar\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t\tPath:   \"/baz\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t\tPath:   \"/bar\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"allow_secure_cookie_on_localhost\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"http://localhost\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"localhost\",\n\t\t\t\t\tSecure: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"localhost\",\n\t\t\t\t\tSecure: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"disallow_secure_cookie_on_http\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"http://foo.com\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t\tSecure: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: nil,\n\t\t},\n\t\t\"invalid_filter\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"HELLO WORLD!\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: nil,\n\t\t\twantErr:     true,\n\t\t},\n\t\t\"invalid_filter_empty\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: nil,\n\t\t\twantErr:     true,\n\t\t},\n\t\t\"invalid_filter_multi\": {\n\t\t\tfilterByURLs: []string{\n\t\t\t\t\"https://foo.com\", \"\", \"HELLO WORLD\",\n\t\t\t},\n\t\t\tcookies: []*Cookie{\n\t\t\t\t{\n\t\t\t\t\tDomain: \"foo.com\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookies: nil,\n\t\t\twantErr:     true,\n\t\t},\n\t}\n\tfor name, tt := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tcookies, err := filterCookies(\n\t\t\t\ttt.cookies,\n\t\t\t\ttt.filterByURLs...,\n\t\t\t)\n\t\t\tif tt.wantErr {\n\t\t\t\tassert.Nilf(t, cookies, \"want no cookies after an error, but got %#v\", cookies)\n\t\t\t\trequire.Errorf(t, err, \"want an error, but got none\")\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equalf(t,\n\t\t\t\ttt.wantCookies, cookies,\n\t\t\t\t\"incorrect cookies filtered by the filter %#v\", tt.filterByURLs,\n\t\t\t)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_options.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// Script variables.\nconst optType = \"type\"\n\n// BrowserOptions stores browser options.\ntype BrowserOptions struct {\n\tArgs              []string\n\tDebug             bool\n\tExecutablePath    string\n\tHeadless          bool\n\tIgnoreDefaultArgs []string\n\tLogCategoryFilter string\n\t// TODO: Do not expose slowMo option by now.\n\t// See https://go.k6.io/k6/js/modules/k6/browser/issues/857.\n\tSlowMo  time.Duration\n\tTimeout time.Duration\n\n\tisRemoteBrowser bool // some options will be ignored if browser is in a remote machine\n}\n\n// NewLocalBrowserOptions returns a new BrowserOptions\n// for a browser launched in the local machine.\nfunc NewLocalBrowserOptions() *BrowserOptions {\n\treturn &BrowserOptions{\n\t\tHeadless:          true,\n\t\tLogCategoryFilter: \".*\",\n\t\tTimeout:           DefaultTimeout,\n\t}\n}\n\n// NewRemoteBrowserOptions returns a new BrowserOptions\n// for a browser running in a remote machine.\nfunc NewRemoteBrowserOptions() *BrowserOptions {\n\treturn &BrowserOptions{\n\t\tHeadless:          true,\n\t\tLogCategoryFilter: \".*\",\n\t\tTimeout:           DefaultTimeout,\n\t\tisRemoteBrowser:   true,\n\t}\n}\n\n// Parse parses browser options from a JS object.\nfunc (bo *BrowserOptions) Parse(\n\tctx context.Context, logger *log.Logger, opts map[string]any, envLookup env.LookupFunc,\n) error {\n\t// Parse opts\n\tbt, ok := opts[optType]\n\t// Only 'chromium' is supported by now, so return error\n\t// if type option is not set, or if it's set and its value\n\t// is different than 'chromium'\n\tif !ok {\n\t\treturn errors.New(\"browser type option must be set\")\n\t}\n\tif bt != \"chromium\" {\n\t\treturn fmt.Errorf(\"unsupported browser type: %s\", bt)\n\t}\n\n\t// Parse env\n\tenvOpts := [...]string{\n\t\tenv.BrowserArguments,\n\t\tenv.BrowserEnableDebugging,\n\t\tenv.BrowserExecutablePath,\n\t\tenv.BrowserHeadless,\n\t\tenv.BrowserIgnoreDefaultArgs,\n\t\tenv.LogCategoryFilter,\n\t\tenv.BrowserGlobalTimeout,\n\t}\n\n\tfor _, e := range envOpts {\n\t\tev, ok := envLookup(e)\n\t\tif !ok || ev == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif bo.shouldIgnoreIfBrowserIsRemote(e) {\n\t\t\tlogger.Warnf(\"BrowserOptions\", \"setting %s option is disallowed when browser is remote\", e)\n\t\t\tcontinue\n\t\t}\n\t\tvar err error\n\t\tswitch e {\n\t\tcase env.BrowserArguments:\n\t\t\tbo.Args = parseListOpt(ev)\n\t\tcase env.BrowserEnableDebugging:\n\t\t\tbo.Debug, err = parseBoolOpt(e, ev)\n\t\tcase env.BrowserExecutablePath:\n\t\t\tbo.ExecutablePath = ev\n\t\tcase env.BrowserHeadless:\n\t\t\tbo.Headless, err = parseBoolOpt(e, ev)\n\t\tcase env.BrowserIgnoreDefaultArgs:\n\t\t\tbo.IgnoreDefaultArgs = parseListOpt(ev)\n\t\tcase env.LogCategoryFilter:\n\t\t\tbo.LogCategoryFilter = ev\n\t\tcase env.BrowserGlobalTimeout:\n\t\t\tbo.Timeout, err = parseTimeOpt(e, ev)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (bo *BrowserOptions) shouldIgnoreIfBrowserIsRemote(opt string) bool {\n\tif !bo.isRemoteBrowser {\n\t\treturn false\n\t}\n\n\tshouldIgnoreIfBrowserIsRemote := map[string]struct{}{\n\t\tenv.BrowserArguments:         {},\n\t\tenv.BrowserExecutablePath:    {},\n\t\tenv.BrowserHeadless:          {},\n\t\tenv.BrowserIgnoreDefaultArgs: {},\n\t}\n\t_, ignore := shouldIgnoreIfBrowserIsRemote[opt]\n\n\treturn ignore\n}\n\nfunc parseBoolOpt(k, v string) (bool, error) {\n\tb, err := strconv.ParseBool(v)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"%s should be a boolean\", k)\n\t}\n\n\treturn b, nil\n}\n\nfunc parseTimeOpt(k, v string) (time.Duration, error) {\n\tt, err := types.GetDurationValue(v)\n\tif err != nil {\n\t\treturn time.Duration(0), fmt.Errorf(\"%s should be a time duration value: %w\", k, err)\n\t}\n\n\treturn t, nil\n}\n\nfunc parseListOpt(v string) []string {\n\telems := strings.Split(v, \",\")\n\t// If last element is a void string,\n\t// because value contained an ending comma,\n\t// remove it\n\tif elems[len(elems)-1] == \"\" {\n\t\telems = elems[:len(elems)-1]\n\t}\n\n\treturn elems\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_options_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\nfunc TestBrowserOptionsParse(t *testing.T) {\n\tt.Parallel()\n\n\tdefaultOptions := &BrowserOptions{\n\t\tHeadless:          true,\n\t\tLogCategoryFilter: \".*\",\n\t\tTimeout:           DefaultTimeout,\n\t}\n\n\tfor name, tt := range map[string]struct {\n\t\topts            map[string]any\n\t\tenvLookupper    env.LookupFunc\n\t\tassert          func(testing.TB, *BrowserOptions)\n\t\terr             string\n\t\tisRemoteBrowser bool\n\t}{\n\t\t\"defaults\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.EmptyLookup,\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Equal(t, defaultOptions, lo)\n\t\t\t},\n\t\t},\n\t\t\"defaults_nil\": { // providing nil option returns default options\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.EmptyLookup,\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Equal(t, defaultOptions, lo)\n\t\t\t},\n\t\t},\n\t\t\"defaults_remote_browser\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tisRemoteBrowser: true,\n\t\t\tenvLookupper: func(k string) (string, bool) {\n\t\t\t\tswitch k {\n\t\t\t\t// disallow changing the following opts\n\t\t\t\tcase env.BrowserArguments:\n\t\t\t\t\treturn \"any\", true\n\t\t\t\tcase env.BrowserExecutablePath:\n\t\t\t\t\treturn \"something else\", true\n\t\t\t\tcase env.BrowserHeadless:\n\t\t\t\t\treturn \"false\", true\n\t\t\t\tcase env.BrowserIgnoreDefaultArgs:\n\t\t\t\t\treturn \"any\", true\n\t\t\t\t// allow changing the following opts\n\t\t\t\tcase env.BrowserEnableDebugging:\n\t\t\t\t\treturn \"true\", true\n\t\t\t\tcase env.LogCategoryFilter:\n\t\t\t\t\treturn \"...\", true\n\t\t\t\tcase env.BrowserGlobalTimeout:\n\t\t\t\t\treturn \"1s\", true\n\t\t\t\tdefault:\n\t\t\t\t\treturn \"\", false\n\t\t\t\t}\n\t\t\t},\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Equal(t, &BrowserOptions{\n\t\t\t\t\t// disallowed:\n\t\t\t\t\tHeadless: true,\n\t\t\t\t\t// allowed:\n\t\t\t\t\tDebug:             true,\n\t\t\t\t\tLogCategoryFilter: \"...\",\n\t\t\t\t\tTimeout:           time.Second,\n\n\t\t\t\t\tisRemoteBrowser: true,\n\t\t\t\t}, lo)\n\t\t\t},\n\t\t},\n\t\t\"nulls\": { // don't override the defaults on `null`\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: func(k string) (string, bool) {\n\t\t\t\treturn \"\", true\n\t\t\t},\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Equal(tb, &BrowserOptions{\n\t\t\t\t\tHeadless:          true,\n\t\t\t\t\tLogCategoryFilter: \".*\",\n\t\t\t\t\tTimeout:           DefaultTimeout,\n\t\t\t\t}, lo)\n\t\t\t},\n\t\t},\n\t\t\"args\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserArguments, \"browser-arg1='value1,browser-arg2=value2,browser-flag\"),\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\trequire.Len(tb, lo.Args, 3)\n\t\t\t\tassert.Equal(tb, \"browser-arg1='value1\", lo.Args[0])\n\t\t\t\tassert.Equal(tb, \"browser-arg2=value2\", lo.Args[1])\n\t\t\t\tassert.Equal(tb, \"browser-flag\", lo.Args[2])\n\t\t\t},\n\t\t},\n\t\t\"debug\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserEnableDebugging, \"true\"),\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.True(t, lo.Debug)\n\t\t\t},\n\t\t},\n\t\t\"debug_err\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserEnableDebugging, \"non-boolean\"),\n\t\t\terr:          \"K6_BROWSER_DEBUG should be a boolean\",\n\t\t},\n\t\t\"executablePath\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserExecutablePath, \"cmd/somewhere\"),\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Equal(t, \"cmd/somewhere\", lo.ExecutablePath)\n\t\t\t},\n\t\t},\n\t\t\"headless\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserHeadless, \"false\"),\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.False(t, lo.Headless)\n\t\t\t},\n\t\t},\n\t\t\"headless_err\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserHeadless, \"non-boolean\"),\n\t\t\terr:          \"K6_BROWSER_HEADLESS should be a boolean\",\n\t\t},\n\t\t\"ignoreDefaultArgs\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserIgnoreDefaultArgs, \"--hide-scrollbars,--hide-something\"),\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Len(t, lo.IgnoreDefaultArgs, 2)\n\t\t\t\tassert.Equal(t, \"--hide-scrollbars\", lo.IgnoreDefaultArgs[0])\n\t\t\t\tassert.Equal(t, \"--hide-something\", lo.IgnoreDefaultArgs[1])\n\t\t\t},\n\t\t},\n\t\t\"logCategoryFilter\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.LogCategoryFilter, \"**\"),\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Equal(t, \"**\", lo.LogCategoryFilter)\n\t\t\t},\n\t\t},\n\t\t\"timeout\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserGlobalTimeout, \"10s\"),\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\tassert.Equal(t, 10*time.Second, lo.Timeout)\n\t\t\t},\n\t\t},\n\t\t\"timeout_err\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.ConstLookup(env.BrowserGlobalTimeout, \"ABC\"),\n\t\t\terr:          \"K6_BROWSER_TIMEOUT should be a time duration value\",\n\t\t},\n\t\t\"browser_type\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"chromium\",\n\t\t\t},\n\t\t\tenvLookupper: env.EmptyLookup,\n\t\t\tassert: func(tb testing.TB, lo *BrowserOptions) {\n\t\t\t\ttb.Helper()\n\t\t\t\t// Noop, just expect no error\n\t\t\t},\n\t\t},\n\t\t\"browser_type_err\": {\n\t\t\topts: map[string]any{\n\t\t\t\t\"type\": \"mybrowsertype\",\n\t\t\t},\n\t\t\tenvLookupper: env.EmptyLookup,\n\t\t\terr:          \"unsupported browser type: mybrowsertype\",\n\t\t},\n\t\t\"browser_type_unset_err\": {\n\t\t\tenvLookupper: env.EmptyLookup,\n\t\t\terr:          \"browser type option must be set\",\n\t\t},\n\t} {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar (\n\t\t\t\tvu = k6test.NewVU(t)\n\t\t\t\tlo *BrowserOptions\n\t\t\t)\n\n\t\t\tif tt.isRemoteBrowser {\n\t\t\t\tlo = NewRemoteBrowserOptions()\n\t\t\t} else {\n\t\t\t\tlo = NewLocalBrowserOptions()\n\t\t\t}\n\n\t\t\terr := lo.Parse(vu.Context(), log.NewNullLogger(), tt.opts, tt.envLookupper)\n\t\t\tif tt.err != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, tt.err)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ttt.assert(t, lo)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_process.go",
    "content": "package common\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/storage\"\n)\n\ntype BrowserProcess struct {\n\tctx    context.Context\n\tcancel context.CancelCauseFunc\n\n\tmeta browserProcessMeta\n\n\t// Channels for managing termination.\n\tlostConnection             chan struct{}\n\tprocessIsGracefullyClosing chan struct{}\n\tprocessDone                chan struct{}\n\n\t// Browser's WebSocket URL to speak CDP\n\twsURL string\n\n\tlogger *log.Logger\n}\n\n// NewLocalBrowserProcess starts a local browser process and\n// returns a new BrowserProcess instance to interact with it.\nfunc NewLocalBrowserProcess(\n\tctx context.Context,\n\tpath string,\n\targs []string,\n\tdataDir *storage.Dir,\n\tctxCancel context.CancelCauseFunc,\n\tlogger *log.Logger,\n) (*BrowserProcess, error) {\n\tcmd, err := execute(ctx, path, args, dataDir, logger)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\twsURL, err := parseDevToolsURL(ctx, cmd)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmeta := newLocalBrowserProcessMeta(cmd.Process, dataDir)\n\n\tp := BrowserProcess{\n\t\tctx:                        ctx,\n\t\tcancel:                     ctxCancel,\n\t\tmeta:                       meta,\n\t\tlostConnection:             make(chan struct{}),\n\t\tprocessIsGracefullyClosing: make(chan struct{}),\n\t\tprocessDone:                cmd.done,\n\t\twsURL:                      wsURL,\n\t\tlogger:                     logger,\n\t}\n\n\tgo p.handleClose(ctx)\n\n\treturn &p, nil\n}\n\n// NewRemoteBrowserProcess returns a new BrowserProcess instance\n// which references a remote browser process.\nfunc NewRemoteBrowserProcess(\n\tctx context.Context, wsURL string, ctxCancel context.CancelCauseFunc, logger *log.Logger,\n) (*BrowserProcess, error) {\n\tp := BrowserProcess{\n\t\tctx:                        ctx,\n\t\tcancel:                     ctxCancel,\n\t\tmeta:                       newRemoteBrowserProcessMeta(),\n\t\tlostConnection:             make(chan struct{}),\n\t\tprocessIsGracefullyClosing: make(chan struct{}),\n\t\tprocessDone:                make(chan struct{}),\n\t\twsURL:                      wsURL,\n\t\tlogger:                     logger,\n\t}\n\n\tgo p.handleClose(ctx)\n\n\treturn &p, nil\n}\n\nfunc (p *BrowserProcess) handleClose(ctx context.Context) {\n\t// If we lose connection to the browser and we're not in-progress with clean\n\t// browser-initiated termination then cancel the context to clean up.\n\tselect {\n\tcase <-p.lostConnection:\n\tcase <-ctx.Done():\n\t}\n\n\tselect {\n\tcase <-p.processIsGracefullyClosing:\n\tdefault:\n\t\tp.cancel(fmt.Errorf(\"lost connection while closing the browser (websocket url: %s)\", p.wsURL))\n\t}\n}\n\nfunc (p *BrowserProcess) didLoseConnection() {\n\tclose(p.lostConnection)\n}\n\nfunc (p *BrowserProcess) isConnected() bool {\n\tvar ok bool\n\tselect {\n\tcase _, ok = <-p.lostConnection:\n\tdefault:\n\t\tok = true\n\t}\n\treturn ok\n}\n\n// GracefulClose triggers a graceful closing of the browser process.\nfunc (p *BrowserProcess) GracefulClose() {\n\tp.logger.Debugf(\"Browser:GracefulClose\", \"\")\n\tclose(p.processIsGracefullyClosing)\n}\n\n// Terminate triggers the termination of the browser process.\nfunc (p *BrowserProcess) Terminate() {\n\tp.logger.Debugf(\"Browser:Close\", \"browserProc terminate\")\n\tp.cancel(errors.New(\"browser process terminated\"))\n}\n\n// WsURL returns the Websocket URL that the browser is listening on for CDP clients.\nfunc (p *BrowserProcess) WsURL() string {\n\treturn p.wsURL\n}\n\n// Pid returns the browser process ID, or -1 if this is unknown.\nfunc (p *BrowserProcess) Pid() int {\n\treturn p.meta.Pid()\n}\n\n// Cleanup cleans up the metadata associated with the browser\n// process, mainly the browser data directory.\nfunc (p *BrowserProcess) Cleanup() error {\n\treturn p.meta.Cleanup() //nolint:wrapcheck\n}\n\ntype command struct {\n\t*exec.Cmd\n\tdone           chan struct{}\n\tstdout, stderr io.Reader\n}\n\nfunc execute(\n\tctx context.Context, path string, args []string,\n\tdataDir *storage.Dir, logger *log.Logger,\n) (command, error) {\n\tcmd := exec.CommandContext(ctx, path, args...) //nolint:gosec\n\tkillAfterParent(cmd)\n\n\tstdout, err := cmd.StdoutPipe()\n\tif err != nil {\n\t\treturn command{}, fmt.Errorf(\"%w\", err)\n\t}\n\tstderr, err := cmd.StderrPipe()\n\tif err != nil {\n\t\treturn command{}, fmt.Errorf(\"%w\", err)\n\t}\n\n\t// We must start the cmd before calling cmd.Wait, as otherwise the two\n\t// can run into a data race.\n\terr = cmd.Start()\n\tif os.IsNotExist(err) { //nolint:forbidigo\n\t\treturn command{}, fmt.Errorf(\"file does not exist: %s\", path)\n\t}\n\tif err != nil {\n\t\treturn command{}, fmt.Errorf(\"%w\", err)\n\t}\n\tif ctx.Err() != nil {\n\t\treturn command{}, ContextErr(ctx)\n\t}\n\n\tdone := make(chan struct{})\n\tgo func() {\n\t\t// TODO: How to handle these errors?\n\t\tdefer func() {\n\t\t\tif err := dataDir.Cleanup(); err != nil {\n\t\t\t\tlogger.Errorf(\"browser\", \"cleaning up the user data directory: %v\", err)\n\t\t\t}\n\t\t\tclose(done)\n\t\t}()\n\n\t\tif err := cmd.Wait(); err != nil {\n\t\t\tlogger.Errorf(\"browser\",\n\t\t\t\t\"process with PID %d unexpectedly ended: %v\",\n\t\t\t\tcmd.Process.Pid, err)\n\t\t}\n\t}()\n\n\treturn command{cmd, done, stdout, stderr}, nil\n}\n\n// parseDevToolsURL grabs the WebSocket address from Chrome's output and returns\n// it. If the process ends abruptly, it will return the first error from stderr.\nfunc parseDevToolsURL(ctx context.Context, cmd command) (_ string, err error) {\n\tparser := &devToolsURLParser{\n\t\tsc: bufio.NewScanner(cmd.stderr),\n\t}\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tfor parser.scan() {\n\t\t}\n\t\tclose(done)\n\t}()\n\tfor err == nil {\n\t\tselect {\n\t\tcase <-done:\n\t\t\terr = parser.err()\n\t\tcase <-ctx.Done():\n\t\t\terr = ContextErr(ctx)\n\t\tcase <-cmd.done:\n\t\t\terr = errors.New(\"browser process ended unexpectedly\")\n\t\t}\n\t}\n\tif parser.url != \"\" {\n\t\terr = nil\n\t}\n\n\treturn parser.url, err\n}\n\ntype devToolsURLParser struct {\n\tsc *bufio.Scanner\n\n\terrs []error\n\turl  string\n}\n\nfunc (p *devToolsURLParser) scan() bool {\n\tif !p.sc.Scan() {\n\t\treturn false\n\t}\n\n\tconst urlPrefix = \"DevTools listening on \"\n\n\tline := p.sc.Text()\n\tif strings.HasPrefix(line, urlPrefix) {\n\t\tp.url = strings.TrimPrefix(strings.TrimSpace(line), urlPrefix)\n\t}\n\tif strings.Contains(line, \":ERROR:\") {\n\t\tif i := strings.Index(line, \"] \"); i > 0 {\n\t\t\tp.errs = append(p.errs, errors.New(line[i+2:]))\n\t\t}\n\t}\n\n\treturn p.url == \"\"\n}\n\nfunc (p *devToolsURLParser) err() error {\n\tif p.url != \"\" {\n\t\treturn io.EOF\n\t}\n\tif len(p.errs) > 0 {\n\t\treturn p.errs[0]\n\t}\n\n\terr := p.sc.Err()\n\tif errors.Is(err, fs.ErrClosed) {\n\t\treturn fmt.Errorf(\"browser process shutdown unexpectedly before establishing a connection: %w\", err)\n\t}\n\tif err != nil {\n\t\treturn err //nolint:wrapcheck\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_process_meta.go",
    "content": "package common\n\nimport (\n\t\"os\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/storage\"\n)\n\nconst (\n\tunknownProcessPid = -1\n)\n\n// browserProcessMeta handles the metadata associated with\n// a browser process, especifically, the OS process handle\n// and the associated browser data directory.\ntype browserProcessMeta interface {\n\tPid() int\n\tCleanup() error\n}\n\n// localBrowserProcessMeta holds the metadata for local\n// browser process.\ntype localBrowserProcessMeta struct {\n\tprocess     *os.Process //nolint:forbidigo\n\tuserDataDir *storage.Dir\n}\n\n// newLocalBrowserProcessMeta returns a new BrowserProcessMeta\n// for the given OS process and storage directory.\nfunc newLocalBrowserProcessMeta(\n\tprocess *os.Process, userDataDir *storage.Dir, //nolint:forbidigo\n) *localBrowserProcessMeta {\n\treturn &localBrowserProcessMeta{\n\t\tprocess,\n\t\tuserDataDir,\n\t}\n}\n\n// Pid returns the Pid for the local browser process.\nfunc (l *localBrowserProcessMeta) Pid() int {\n\treturn l.process.Pid\n}\n\n// Cleanup cleans the local user data directory associated\n// with the local browser process.\nfunc (l *localBrowserProcessMeta) Cleanup() error {\n\treturn l.userDataDir.Cleanup() //nolint:wrapcheck\n}\n\n// remoteBrowserProcessMeta is a placeholder for a\n// remote browser process metadata.\ntype remoteBrowserProcessMeta struct{}\n\n// newRemoteBrowserProcessMeta returns a new BrowserProcessMeta\n// which acts as a placeholder for a remote browser process data.\nfunc newRemoteBrowserProcessMeta() *remoteBrowserProcessMeta {\n\treturn &remoteBrowserProcessMeta{}\n}\n\n// Pid returns -1 as the remote browser process is unknown.\nfunc (r *remoteBrowserProcessMeta) Pid() int {\n\treturn unknownProcessPid\n}\n\n// Cleanup does nothing and returns nil, as there is no\n// access to the remote browser's user data directory.\nfunc (r *remoteBrowserProcessMeta) Cleanup() error {\n\t// Nothing to do.\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_process_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype mockCommand struct {\n\t*command\n\tcancelFn context.CancelFunc\n}\n\ntype mockReader struct {\n\tlines []string\n\thook  func()\n\terr   error\n}\n\nfunc (r *mockReader) Read(p []byte) (n int, err error) {\n\tif r.hook != nil {\n\t\t// Allow some time for the read to be processed\n\t\ttime.AfterFunc(100*time.Millisecond, r.hook)\n\t\tr.hook = nil // Ensure the hook only runs once\n\t}\n\tif len(r.lines) == 0 {\n\t\treturn 0, io.EOF\n\t}\n\tn = copy(p, []byte(r.lines[0]+\"\\n\"))\n\tr.lines = r.lines[1:]\n\n\treturn n, r.err\n}\n\nfunc TestParseDevToolsURL(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tstderr   []string\n\t\treadErr  error\n\t\treadHook func(c *mockCommand)\n\t\tassert   func(t *testing.T, wsURL string, err error)\n\t}{\n\t\t{\n\t\t\tname: \"ok/no_error\",\n\t\t\tstderr: []string{\n\t\t\t\t`DevTools listening on ws://127.0.0.1:41315/devtools/browser/d1d3f8eb-b362-4f12-9370-bd25778d0da7`,\n\t\t\t},\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"ws://127.0.0.1:41315/devtools/browser/d1d3f8eb-b362-4f12-9370-bd25778d0da7\", wsURL)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ok/non-fatal_error\",\n\t\t\tstderr: []string{\n\t\t\t\t`[23400:23418:1028/115455.877614:ERROR:bus.cc(399)] Failed to ` +\n\t\t\t\t\t`connect to the bus: Could not parse server address: ` +\n\t\t\t\t\t`Unknown address type (examples of valid types are \"tcp\" ` +\n\t\t\t\t\t`and on UNIX \"unix\")`,\n\t\t\t\t\"\",\n\t\t\t\t`DevTools listening on ws://127.0.0.1:41315/devtools/browser/d1d3f8eb-b362-4f12-9370-bd25778d0da7`,\n\t\t\t},\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"ws://127.0.0.1:41315/devtools/browser/d1d3f8eb-b362-4f12-9370-bd25778d0da7\", wsURL)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"err/fatal-eof\",\n\t\t\tstderr: []string{\n\t\t\t\t`[6497:6497:1013/103521.932979:ERROR:ozone_platform_x11` +\n\t\t\t\t\t`.cc(247)] Missing X server or $DISPLAY` + \"\\n\",\n\t\t\t},\n\t\t\treadErr: io.ErrUnexpectedEOF,\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.Empty(t, wsURL)\n\t\t\t\tassert.EqualError(t, err, \"Missing X server or $DISPLAY\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:    \"err/fatal-eof-no_stderr\",\n\t\t\tstderr:  []string{\"\"},\n\t\t\treadErr: io.ErrUnexpectedEOF,\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.Empty(t, wsURL)\n\t\t\t\tassert.EqualError(t, err, \"unexpected EOF\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// Ensure any error found on stderr is returned first.\n\t\t\tname: \"err/fatal-premature_cmd_done-stderr\",\n\t\t\tstderr: []string{\n\t\t\t\t`[6497:6497:1013/103521.932979:ERROR:ozone_platform_x11` +\n\t\t\t\t\t`.cc(247)] Missing X server or $DISPLAY` + \"\\n\",\n\t\t\t},\n\t\t\treadHook: func(c *mockCommand) { close(c.done) },\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.Empty(t, wsURL)\n\t\t\t\tassert.EqualError(t, err, \"Missing X server or $DISPLAY\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// If there's no error on stderr, return a generic error.\n\t\t\tname:     \"err/fatal-premature_cmd_done-no_stderr\",\n\t\t\tstderr:   []string{\"\"},\n\t\t\treadHook: func(c *mockCommand) { close(c.done) },\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.Empty(t, wsURL)\n\t\t\t\tassert.EqualError(t, err, \"browser process ended unexpectedly\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"err/fatal-premature_ctx_cancel-stderr\",\n\t\t\tstderr: []string{\n\t\t\t\t`[6497:6497:1013/103521.932979:ERROR:ozone_platform_x11` +\n\t\t\t\t\t`.cc(247)] Missing X server or $DISPLAY` + \"\\n\",\n\t\t\t},\n\t\t\treadHook: func(c *mockCommand) { c.cancelFn() },\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.Empty(t, wsURL)\n\t\t\t\tassert.EqualError(t, err, \"Missing X server or $DISPLAY\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"err/fatal-premature_ctx_cancel-no_stderr\",\n\t\t\tstderr:   []string{\"\"},\n\t\t\treadHook: func(c *mockCommand) { c.cancelFn() },\n\t\t\tassert: func(t *testing.T, wsURL string, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\trequire.Empty(t, wsURL)\n\t\t\t\tassert.EqualError(t, err, \"context canceled\")\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx, cancel := context.WithCancel(context.Background())\n\t\t\tt.Cleanup(cancel)\n\n\t\t\tvar cmd *mockCommand\n\t\t\tmr := mockReader{lines: tc.stderr, err: tc.readErr}\n\t\t\tif tc.readHook != nil {\n\t\t\t\tmr.hook = func() { tc.readHook(cmd) }\n\t\t\t}\n\t\t\tcmd = &mockCommand{&command{done: make(chan struct{}), stderr: &mr}, cancel}\n\n\t\t\ttimeout := time.Second\n\t\t\ttimer := time.NewTimer(timeout)\n\t\t\tt.Cleanup(func() { _ = timer.Stop() })\n\n\t\t\tvar (\n\t\t\t\tdone  = make(chan struct{})\n\t\t\t\twsURL string\n\t\t\t\terr   error\n\t\t\t)\n\n\t\t\tgo func() {\n\t\t\t\twsURL, err = parseDevToolsURL(ctx, *cmd.command)\n\t\t\t\tclose(done)\n\t\t\t}()\n\n\t\t\tselect {\n\t\t\tcase <-done:\n\t\t\t\ttc.assert(t, wsURL, err)\n\t\t\tcase <-timer.C:\n\t\t\t\tt.Errorf(\"test timed out after %s\", timeout)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/browser_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/target\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\nfunc TestBrowserNewPageInContext(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\t// default IDs to be used in tests.\n\t\tbrowserContextID cdp.BrowserContextID = \"42\"\n\t\ttargetID         target.ID            = \"84\"\n\t)\n\n\ttype testCase struct {\n\t\tb  *Browser\n\t\tbc *BrowserContext\n\t}\n\n\tnewTestCase := func(id cdp.BrowserContextID) *testCase {\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tb := newBrowser(context.Background(), ctx, cancel, nil, NewLocalBrowserOptions(), log.NewNullLogger())\n\n\t\t// set a new browser context in the browser with `id`, so that newPageInContext can find it.\n\t\tvar err error\n\t\tb.context, err = NewBrowserContext(k6ext.WithVU(ctx, k6test.NewVU(t)), b, id, nil, nil)\n\t\tb.defaultContext = b.context // always happens when a new browser is connected\n\t\trequire.NoError(t, err)\n\n\t\ttc := &testCase{b: b, bc: b.context}\n\n\t\t// newPageInContext will return this page by searching it by its targetID in the wait event handler.\n\t\ttc.b.pages[targetID] = &Page{targetID: targetID}\n\t\ttc.b.conn = fakeConn{\n\t\t\texecute: func(ctx context.Context, method string, params, res any) error {\n\t\t\t\trequire.Equal(t, target.CommandCreateTarget, method)\n\t\t\t\trequire.IsType(t, params, &target.CreateTargetParams{})\n\t\t\t\ttp, _ := params.(*target.CreateTargetParams)\n\t\t\t\trequire.Equal(t, BlankPage, tp.URL)\n\t\t\t\trequire.Equal(t, browserContextID, tp.BrowserContextID)\n\n\t\t\t\t// newPageInContext event handler will catch this target ID, and compare it to\n\t\t\t\t// the new page's target ID to detect whether the page\n\t\t\t\t// is loaded.\n\t\t\t\trequire.IsType(t, res, &target.CreateTargetReturns{})\n\t\t\t\tv, _ := res.(*target.CreateTargetReturns)\n\t\t\t\tv.TargetID = targetID\n\n\t\t\t\t// for the event handler to work, there needs to be an event called\n\t\t\t\t// EventBrowserContextPage to be fired. this normally happens when the browser's\n\t\t\t\t// onAttachedToTarget event is fired. here, we imitate as if the browser created a target for\n\t\t\t\t// the page.\n\t\t\t\ttc.bc.emit(EventBrowserContextPage, &Page{targetID: targetID})\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t\treturn tc\n\t}\n\n\tt.Run(\"happy_path\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// newPageInContext will look for this browser context.\n\t\ttc := newTestCase(browserContextID)\n\n\t\tpage, err := tc.b.newPageInContext(browserContextID)\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, page)\n\t\trequire.Equal(t, targetID, page.targetID)\n\t})\n\n\t// should return an error if it cannot find a browser context.\n\tt.Run(\"missing_browser_context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst missingBrowserContextID = \"911\"\n\n\t\t// set an existing browser context,\n\t\t_, err := newTestCase(browserContextID).\n\t\t\t// but look for a different one.\n\t\t\tb.newPageInContext(missingBrowserContextID)\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), missingBrowserContextID,\n\t\t\t\"should have returned the missing browser context ID in the error message\")\n\t})\n\n\tt.Run(\"uses_default_browser_context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttc := newTestCase(browserContextID)\n\t\ttc.b.context = nil // should use default context if there is no current context\n\n\t\trequire.NotPanics(t, func() {\n\t\t\t_, err := tc.b.newPageInContext(browserContextID)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t})\n\n\t// should return the error returned from the executor.\n\tt.Run(\"error_in_create_target_action\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst wantErr = \"anything\"\n\n\t\ttc := newTestCase(browserContextID)\n\t\ttc.b.conn = fakeConn{\n\t\t\texecute: func(context.Context, string, any, any) error {\n\t\t\t\treturn errors.New(wantErr)\n\t\t\t},\n\t\t}\n\t\tpage, err := tc.b.newPageInContext(browserContextID)\n\n\t\trequire.NotNil(t, err)\n\t\trequire.Contains(t, err.Error(), wantErr)\n\t\trequire.Nil(t, page)\n\t})\n\n\tt.Run(\"timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttc := newTestCase(browserContextID)\n\n\t\t// set a lower timeout for catching the timeout error.\n\t\tconst timeout = 100 * time.Millisecond\n\t\t// set the timeout for the browser value.\n\t\ttc.b.browserOpts.Timeout = timeout\n\t\ttc.b.conn = fakeConn{\n\t\t\texecute: func(context.Context, string, any, any) error {\n\t\t\t\t// executor takes more time than the timeout.\n\t\t\t\ttime.Sleep(2 * timeout)\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\n\t\tvar (\n\t\t\tpage *Page\n\t\t\terr  error\n\n\t\t\tdone = make(chan struct{})\n\t\t)\n\t\tgo func() {\n\t\t\t// it should timeout in 100ms because the executor will sleep double of the timeout time.\n\t\t\tpage, err = tc.b.newPageInContext(browserContextID)\n\t\t\tdone <- struct{}{}\n\t\t}()\n\t\tselect {\n\t\tcase <-done:\n\t\t\trequire.Error(t, err)\n\t\t\trequire.ErrorIs(t, err, context.DeadlineExceeded)\n\t\t\trequire.Nil(t, page)\n\t\tcase <-time.After(5 * timeout):\n\t\t\trequire.FailNow(t, \"test timed out: expected newPageInContext to time out instead\")\n\t\t}\n\t})\n\n\tt.Run(\"context_done\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttc := newTestCase(browserContextID)\n\n\t\ttc.b.conn = fakeConn{\n\t\t\texecute: func(context.Context, string, any, any) error {\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\n\t\tvar cancel func()\n\t\ttc.b.vuCtx, cancel = context.WithCancel(tc.b.vuCtx)\n\t\t// let newPageInContext return a context cancelation error by canceling the context before\n\t\t// running the method.\n\t\tcancel()\n\t\tpage, err := tc.b.newPageInContext(browserContextID)\n\t\trequire.Error(t, err)\n\t\trequire.ErrorIs(t, err, context.Canceled)\n\t\trequire.Nil(t, page)\n\t})\n}\n\ntype fakeConn struct {\n\tconnection\n\texecute func(context.Context, string, any, any) error\n}\n\nfunc (c fakeConn) Execute(\n\tctx context.Context, method string, params, res any,\n) error {\n\treturn c.execute(ctx, method, params, res)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/connection.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\tcdpruntime \"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/chromedp/cdproto/target\"\n\tjsonv2 \"github.com/go-json-experiment/json\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n\t\"github.com/gorilla/websocket\"\n)\n\nconst wsWriteBufferSize = 1 << 20\n\n// Each connection needs its own msgID. A msgID will be used by the\n// connection and associated sessions. When a CDP request is made to\n// chrome, it's best to work with unique ids to avoid the Execute\n// handlers working with the wrong response, or handlers deadlocking\n// when their response is rerouted to the wrong handler.\n//\n// Use the msgIDGenerator interface to abstract `id` away.\ntype msgID struct {\n\tid int64\n}\n\n//nolint:gochecknoglobals\nvar defaultJSONV2Options = jsonv2.JoinOptions(\n\tjsonv2.DefaultOptionsV2(),\n\tjsontext.AllowInvalidUTF8(true), // this is needed as chromium sometimes returns invalid utf-8\n)\n\nfunc (m *msgID) newID() int64 {\n\treturn atomic.AddInt64(&m.id, 1)\n}\n\ntype msgIDGenerator interface {\n\tnewID() int64\n}\n\ntype executorEmitter interface {\n\tcdp.Executor\n\tEventEmitter\n}\n\ntype connection interface {\n\texecutorEmitter\n\tClose()\n\tIgnoreIOErrors()\n\tgetSession(target.SessionID) *Session\n}\n\ntype session interface {\n\tcdp.Executor\n\texecutorEmitter\n\tExecuteWithoutExpectationOnReply(context.Context, string, any, any) error\n\tID() target.SessionID\n\tTargetID() target.ID\n\tDone() <-chan struct{}\n}\n\n// Action is the general interface of an CDP action.\ntype Action interface {\n\tDo(context.Context) error\n}\n\n// ActionFunc is an adapter to allow regular functions to be used as an Action.\ntype ActionFunc func(context.Context) error\n\n// Do executes the func f using the provided context.\nfunc (f ActionFunc) Do(ctx context.Context) error {\n\treturn f(ctx)\n}\n\n// Connection represents a WebSocket connection and the root \"Browser Session\".\n//\n//\t                                          ┌───────────────────────────────────────────────────────────────────┐\n//\t                                          │                                                                   │\n//\t                                          │                          Browser Process                          │\n//\t                                          │                                                                   │\n//\t                                          └───────────────────────────────────────────────────────────────────┘\n//\t┌───────────────────────────┐                                           │      ▲\n//\t│Reads JSON-RPC CDP messages│                                           │      │\n//\t│from WS connection and puts│                                           ▼      │\n//\t│ them on incoming queue of │             ┌───────────────────────────────────────────────────────────────────┐\n//\t│    target session, as     ├─────────────■                                                                   │\n//\t│   identified by message   │             │                       WebSocket Connection                        │\n//\t│   session ID. Messages    │             │                                                                   │\n//\t│ without a session ID are  │             └───────────────────────────────────────────────────────────────────┘\n//\t│considered to belong to the│                    │      ▲                                       │      ▲\n//\t│  root \"Browser Session\".  │                    │      │                                       │      │\n//\t└───────────────────────────┘                    ▼      │                                       ▼      │\n//\t┌───────────────────────────┐             ┌────────────────────┐                         ┌────────────────────┐\n//\t│  Handles CDP messages on  ├─────────────■                    │                         │                    │\n//\t│incoming queue and puts CDP│             │      Session       │      *  *  *  *  *      │      Session       │\n//\t│   messages on outgoing    │             │                    │                         │                    │\n//\t│ channel of WS connection. │             └────────────────────┘                         └────────────────────┘\n//\t└───────────────────────────┘                    │      ▲                                       │      ▲\n//\t  │      │                                       │      │                                       │      │\n//\t  ▼      │                                       ▼      │                                       ▼      │\n//\n//\t┌───────────────────────────┐             ┌────────────────────┐                         ┌────────────────────┐\n//\t│Registers with session as a├─────────────■                    │                         │                    │\n//\t│handler for a specific CDP │             │   Event Listener   │      *  *  *  *  *      │   Event Listener   │\n//\t│       Domain event.       │             │                    │                         │                    │\n//\t└───────────────────────────┘             └────────────────────┘                         └────────────────────┘\ntype Connection struct {\n\tBaseEventEmitter\n\n\tctx          context.Context\n\tcancelCtx    context.CancelCauseFunc\n\twsURL        string\n\tlogger       *log.Logger\n\tconn         *websocket.Conn\n\tsendCh       chan *cdproto.Message\n\trecvCh       chan *cdproto.Message\n\tcloseCh      chan int\n\terrorCh      chan error\n\tdone         chan struct{}\n\tclosing      chan struct{}\n\tshutdownOnce sync.Once\n\tmsgIDGen     msgIDGenerator\n\n\tsessionsMu sync.RWMutex\n\tsessions   map[target.SessionID]*Session\n\n\t// onTargetAttachedToTarget is called when a new target is attached to the browser.\n\t// Returning false will prevent the session from being created.\n\t// If onTargetAttachedToTarget is nil, the session will be created.\n\tonTargetAttachedToTarget func(*target.EventAttachedToTarget) bool\n}\n\n// NewConnection creates a new browser.\nfunc NewConnection(\n\tctx context.Context,\n\twsURL string,\n\tlogger *log.Logger,\n\tonTargetAttachedToTarget func(*target.EventAttachedToTarget) bool,\n) (*Connection, error) {\n\tvar header http.Header\n\tvar tlsConfig *tls.Config\n\twsd := websocket.Dialer{\n\t\tHandshakeTimeout: time.Second * 60,\n\t\tProxy:            http.ProxyFromEnvironment, // TODO(fix): use proxy settings from launch options\n\t\tTLSClientConfig:  tlsConfig,\n\t\tWriteBufferSize:  wsWriteBufferSize,\n\t\tReadBufferSize:   wsWriteBufferSize,\n\t}\n\n\tctx, cancelCtx := context.WithCancelCause(ctx)\n\n\tconn, response, connErr := wsd.DialContext(ctx, wsURL, header)\n\tif response != nil {\n\t\tdefer func() {\n\t\t\t_ = response.Body.Close()\n\t\t}()\n\t}\n\tif connErr != nil {\n\t\tcancelCtx(fmt.Errorf(\"failed to dial websocket at %s: %w\", wsURL, connErr))\n\t\treturn nil, connErr\n\t}\n\n\tc := Connection{\n\t\tBaseEventEmitter:         NewBaseEventEmitter(ctx),\n\t\tctx:                      ctx,\n\t\tcancelCtx:                cancelCtx,\n\t\twsURL:                    wsURL,\n\t\tlogger:                   logger,\n\t\tconn:                     conn,\n\t\tsendCh:                   make(chan *cdproto.Message, 32), // Avoid blocking in Execute\n\t\trecvCh:                   make(chan *cdproto.Message),\n\t\tcloseCh:                  make(chan int),\n\t\terrorCh:                  make(chan error),\n\t\tdone:                     make(chan struct{}),\n\t\tclosing:                  make(chan struct{}),\n\t\tmsgIDGen:                 &msgID{},\n\t\tsessions:                 make(map[target.SessionID]*Session),\n\t\tonTargetAttachedToTarget: onTargetAttachedToTarget,\n\t}\n\n\tgo c.recvLoop()\n\tgo c.sendLoop()\n\n\treturn &c, nil\n}\n\nfunc (c *Connection) close(code int) error {\n\tc.logger.Debugf(\"Connection:close\", \"code:%d\", code)\n\n\tdefer func() {\n\t\tc.cancelCtx(fmt.Errorf(\"connection closed with websocket code: %d\", code))\n\t}()\n\n\tvar err error\n\tc.shutdownOnce.Do(func() {\n\t\tdefer func() {\n\t\t\t// Stop the main control loop\n\t\t\tclose(c.done)\n\t\t\t_ = c.conn.Close()\n\t\t}()\n\n\t\tc.closeAllSessions()\n\n\t\terr = c.conn.WriteControl(websocket.CloseMessage,\n\t\t\twebsocket.FormatCloseMessage(code, \"\"),\n\t\t\ttime.Now().Add(time.Second),\n\t\t)\n\n\t\t// According to the WS RFC[1], we might want to wait for a response\n\t\t// Control frame back from the browser here (possibly for the above\n\t\t// timeout duration), but Chrom{e,ium} never sends one, even when\n\t\t// the browser process exits normally after the Browser.close CDP\n\t\t// command. So we don't bother waiting, since it would just needlessly\n\t\t// delay the k6 iteration.\n\t\t// [1]: https://www.rfc-editor.org/rfc/rfc6455#section-1.4\n\n\t\tc.emit(EventConnectionClose, nil)\n\t})\n\n\treturn err\n}\n\n// closeSession closes the session with the given session ID.\n// It returns true if the session was found and closed, false otherwise.\nfunc (c *Connection) closeSession(sid target.SessionID, tid target.ID) bool {\n\tc.logger.Debugf(\"Connection:closeSession\", \"sid:%v tid:%v wsURL:%v\", sid, tid, c.wsURL)\n\n\tc.sessionsMu.Lock()\n\tdefer c.sessionsMu.Unlock()\n\n\tsession, ok := c.sessions[sid]\n\tif !ok {\n\t\treturn false\n\t}\n\tsession.close()\n\tdelete(c.sessions, sid)\n\n\treturn true\n}\n\nfunc (c *Connection) closeAllSessions() {\n\tc.logger.Debugf(\"Connection:closeAllSessions\", \"wsURL:%v\", c.wsURL)\n\n\tc.sessionsMu.Lock()\n\tfor _, s := range c.sessions {\n\t\ts.close()\n\t\tdelete(c.sessions, s.id)\n\t}\n\tc.sessionsMu.Unlock()\n}\n\nfunc (c *Connection) createSession(info *target.Info) (*Session, error) {\n\tc.logger.Debugf(\"Connection:createSession\", \"tid:%v bctxid:%v type:%s\",\n\t\tinfo.TargetID, info.BrowserContextID, info.Type)\n\n\tvar sessionID target.SessionID\n\tvar err error\n\taction := target.AttachToTarget(info.TargetID).WithFlatten(true)\n\tif sessionID, err = action.Do(cdp.WithExecutor(c.ctx, c)); err != nil {\n\t\tc.logger.Debugf(\"Connection:createSession\", \"tid:%v bctxid:%v type:%s err:%v\",\n\t\t\tinfo.TargetID, info.BrowserContextID, info.Type, err)\n\t\treturn nil, err\n\t}\n\tsess := c.getSession(sessionID)\n\tif sess == nil {\n\t\tc.logger.Warnf(\"Connection:createSession\", \"tid:%v bctxid:%v type:%s sid:%v, session is nil\",\n\t\t\tinfo.TargetID, info.BrowserContextID, info.Type, sessionID)\n\t}\n\treturn sess, nil\n}\n\nfunc (c *Connection) handleIOError(err error) {\n\tif closing := c.isClosing(); websocket.IsCloseError(\n\t\terr, websocket.CloseNormalClosure, websocket.CloseGoingAway,\n\t) || closing {\n\t\tc.logger.Debugf(\"cdp\", \"received IO error: %v, connection is closing: %v\", err, closing)\n\t\treturn\n\t}\n\n\t// Report an unexpected closure\n\tc.logger.Errorf(\"cdp\", \"communicating with browser: %v\", err)\n\tselect {\n\tcase c.errorCh <- err:\n\tcase <-c.done:\n\t\treturn\n\t}\n\tvar (\n\t\tcerr *websocket.CloseError\n\t\tcode = websocket.CloseGoingAway\n\t)\n\tif errors.As(err, &cerr) {\n\t\tcode = cerr.Code\n\t}\n\tselect {\n\tcase c.closeCh <- code:\n\t\tc.logger.Debugf(\"cdp\", \"ending browser communication with code %d\", code)\n\tcase <-c.done:\n\t\tc.logger.Debugf(\"cdp\", \"ending browser communication\")\n\t}\n}\n\nfunc (c *Connection) getSession(id target.SessionID) *Session {\n\tc.sessionsMu.RLock()\n\tdefer c.sessionsMu.RUnlock()\n\n\treturn c.sessions[id]\n}\n\n// findTragetIDForLog should only be used for logging purposes.\n// It will return an empty string if logger.DebugMode is false.\nfunc (c *Connection) findTargetIDForLog(id target.SessionID) target.ID {\n\tif !c.logger.DebugMode() {\n\t\treturn \"\"\n\t}\n\ts := c.getSession(id)\n\tif s == nil {\n\t\treturn \"\"\n\t}\n\treturn s.targetID\n}\n\n//nolint:funlen,gocognit,cyclop\nfunc (c *Connection) recvLoop() {\n\tc.logger.Debugf(\"Connection:recvLoop\", \"wsURL:%q\", c.wsURL)\n\tfor {\n\t\t_, reader, err := c.conn.NextReader()\n\t\tif err != nil {\n\t\t\tc.handleIOError(err)\n\t\t\treturn\n\t\t}\n\n\t\tvar msg cdproto.Message\n\t\terr = jsonv2.UnmarshalRead(reader, &msg, defaultJSONV2Options)\n\t\tif err != nil {\n\t\t\tselect {\n\t\t\tcase c.errorCh <- err:\n\t\t\t\tc.logger.Debugf(\"Connection:recvLoop:<-err\", \"wsURL:%q err:%v\", c.wsURL, err)\n\t\t\tcase <-c.done:\n\t\t\t\tc.logger.Debugf(\"Connection:recvLoop:<-c.done\", \"wsURL:%q\", c.wsURL)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// Handle attachment and detachment from targets,\n\t\t// creating and deleting sessions as necessary.\n\t\t//nolint:nestif\n\t\tif msg.Method == cdproto.EventTargetAttachedToTarget {\n\t\t\tev, err := cdproto.UnmarshalMessage(&msg)\n\t\t\tif err != nil {\n\t\t\t\tc.logger.Errorf(\"cdp\", \"%s\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\teva := ev.(*target.EventAttachedToTarget) //nolint:forcetypeassert\n\t\t\tsid, tid := eva.SessionID, eva.TargetInfo.TargetID\n\n\t\t\tif c.onTargetAttachedToTarget != nil {\n\t\t\t\t// If onTargetAttachedToTarget is set, it will be called to determine\n\t\t\t\t// if a session should be created for the target.\n\t\t\t\tok := c.onTargetAttachedToTarget(eva)\n\t\t\t\tif !ok {\n\t\t\t\t\tc.stopWaitingForDebugger(sid)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tc.sessionsMu.Lock()\n\t\t\tsession := NewSession(c.ctx, c, sid, tid, c.logger, c.msgIDGen)\n\t\t\tc.logger.Debugf(\"Connection:recvLoop:EventAttachedToTarget\", \"sid:%v tid:%v wsURL:%q\", sid, tid, c.wsURL)\n\t\t\tc.sessions[sid] = session\n\t\t\tc.sessionsMu.Unlock()\n\t\t} else if msg.Method == cdproto.EventTargetDetachedFromTarget {\n\t\t\tev, err := cdproto.UnmarshalMessage(&msg)\n\t\t\tif err != nil {\n\t\t\t\tc.logger.Errorf(\"cdp\", \"%s\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tevt := ev.(*target.EventDetachedFromTarget) //nolint:forcetypeassert\n\t\t\tsid := evt.SessionID\n\t\t\ttid := c.findTargetIDForLog(sid)\n\t\t\tok := c.closeSession(sid, tid)\n\t\t\tif !ok {\n\t\t\t\tc.logger.Debugf(\n\t\t\t\t\t\"Connection:recvLoop:EventDetachedFromTarget\",\n\t\t\t\t\t\"sid:%v tid:%v wsURL:%q, session not found\",\n\t\t\t\t\tsid, tid, c.wsURL,\n\t\t\t\t)\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tswitch {\n\t\tcase msg.SessionID != \"\" && (msg.Method != \"\" || msg.ID != 0):\n\t\t\t// TODO: possible data race - session can get removed after getting it here\n\t\t\tsession := c.getSession(msg.SessionID)\n\t\t\tif session == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif msg.Error != nil && msg.Error.Message == \"No session with given id\" {\n\t\t\t\tc.logger.Debugf(\"Connection:recvLoop\", \"sid:%v tid:%v wsURL:%q, closeSession #2\",\n\t\t\t\t\tsession.id, session.targetID, c.wsURL)\n\t\t\t\tc.closeSession(session.id, session.targetID)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase session.readCh <- &msg:\n\t\t\tcase code := <-c.closeCh:\n\t\t\t\tc.logger.Debugf(\"Connection:recvLoop:<-c.closeCh\", \"sid:%v tid:%v wsURL:%v crashed:%t\",\n\t\t\t\t\tsession.id, session.targetID, c.wsURL, session.crashed)\n\t\t\t\t_ = c.close(code)\n\t\t\tcase <-c.done:\n\t\t\t\tc.logger.Debugf(\"Connection:recvLoop:<-c.done\", \"sid:%v tid:%v wsURL:%v crashed:%t\",\n\t\t\t\t\tsession.id, session.targetID, c.wsURL, session.crashed)\n\t\t\t\treturn\n\t\t\t}\n\n\t\tcase msg.Method != \"\":\n\t\t\tc.logger.Debugf(\"Connection:recvLoop:msg.Method:emit\", \"sid:%v method:%q\", msg.SessionID, msg.Method)\n\t\t\tev, err := cdproto.UnmarshalMessage(&msg)\n\t\t\tif err != nil {\n\t\t\t\tc.logger.Errorf(\"cdp\", \"%s\", err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tc.emit(string(msg.Method), ev)\n\n\t\tcase msg.ID != 0:\n\t\t\tc.logger.Debugf(\"Connection:recvLoop:msg.ID:emit\", \"sid:%v method:%q\", msg.SessionID, msg.Method)\n\t\t\tc.emit(\"\", &msg)\n\n\t\tdefault:\n\t\t\tc.logger.Errorf(\"cdp\", \"ignoring malformed incoming message (missing id or method): %#v (message: %s)\",\n\t\t\t\tmsg, msg.Error.Message)\n\t\t}\n\t}\n}\n\n// stopWaitingForDebugger tells the browser to stop waiting for the\n// debugger to attach to the page's session.\n//\n// Whether we're not sharing pages among browser contexts, Chromium\n// still does so (since we're auto-attaching all browser targets).\n// This means that if we don't stop waiting for the debugger, the\n// browser will wait for the debugger to attach to the new page\n// indefinitely, even if the page is not part of the browser context\n// we're using.\n//\n// We don't return an error because the browser might have already\n// closed the connection. In that case, handling the error would\n// be redundant. This operation is best-effort.\nfunc (c *Connection) stopWaitingForDebugger(sid target.SessionID) {\n\tmsg := &cdproto.Message{\n\t\tID:        c.msgIDGen.newID(),\n\t\tSessionID: sid,\n\t\tMethod:    cdproto.MethodType(cdpruntime.CommandRunIfWaitingForDebugger),\n\t}\n\terr := c.send(c.ctx, msg, nil, nil)\n\tif err != nil {\n\t\tc.logger.Errorf(\"Connection:stopWaitingForDebugger\", \"sid:%v wsURL:%q, err:%v\", sid, c.wsURL, err)\n\t}\n}\n\nfunc (c *Connection) send(\n\tctx context.Context, msg *cdproto.Message, recvCh chan *cdproto.Message, res any,\n) error {\n\tselect {\n\tcase c.sendCh <- msg:\n\tcase err := <-c.errorCh:\n\t\tc.logger.Debugf(\"Connection:send:<-c.errorCh\", \"wsURL:%q sid:%v, err:%v\", c.wsURL, msg.SessionID, err)\n\t\treturn fmt.Errorf(\"sending a message to browser: %w\", err)\n\tcase code := <-c.closeCh:\n\t\tc.logger.Debugf(\"Connection:send:<-c.closeCh\", \"wsURL:%q sid:%v, websocket code:%v\", c.wsURL, msg.SessionID, code)\n\t\t_ = c.close(code)\n\t\treturn fmt.Errorf(\"closing communication with browser: %w\", &websocket.CloseError{Code: code})\n\tcase <-ctx.Done():\n\t\tc.logger.Debugf(\"Connection:send:<-ctx.Done\", \"wsURL:%q sid:%v err:%v\", c.wsURL, msg.SessionID, c.ctx.Err())\n\t\treturn nil\n\tcase <-c.done:\n\t\tc.logger.Debugf(\"Connection:send:<-c.done\", \"wsURL:%q sid:%v\", c.wsURL, msg.SessionID)\n\t\treturn nil\n\t}\n\n\t// Block waiting for response.\n\tif recvCh == nil {\n\t\treturn nil\n\t}\n\ttid := c.findTargetIDForLog(msg.SessionID)\n\tselect {\n\tcase msg := <-recvCh:\n\t\tvar sid target.SessionID\n\t\ttid = \"\"\n\t\tif msg != nil {\n\t\t\tsid = msg.SessionID\n\t\t\ttid = c.findTargetIDForLog(sid)\n\t\t}\n\t\tswitch {\n\t\tcase msg == nil:\n\t\t\tc.logger.Debugf(\"Connection:send\", \"wsURL:%q, err:ErrChannelClosed\", c.wsURL)\n\t\t\treturn ErrChannelClosed\n\t\tcase msg.Error != nil:\n\t\t\tc.logger.Debugf(\"Connection:send\", \"sid:%v tid:%v wsURL:%q, msg err:%v\", sid, tid, c.wsURL, msg.Error)\n\t\t\treturn msg.Error\n\t\tcase res != nil:\n\t\t\treturn jsonv2.Unmarshal(msg.Result, res, defaultJSONV2Options)\n\t\t}\n\t\treturn nil\n\tcase err := <-c.errorCh:\n\t\tc.logger.Debugf(\"Connection:send:<-c.errorCh #2\", \"sid:%v tid:%v wsURL:%q, err:%v\", msg.SessionID, tid, c.wsURL, err)\n\t\treturn err\n\tcase code := <-c.closeCh:\n\t\tc.logger.Debugf(\"Connection:send:<-c.closeCh #2\", \"sid:%v tid:%v wsURL:%q, websocket code:%v\",\n\t\t\tmsg.SessionID, tid, c.wsURL, code)\n\t\t_ = c.close(code)\n\t\treturn &websocket.CloseError{Code: code}\n\tcase <-c.done:\n\t\tc.logger.Debugf(\"Connection:send:<-c.done #2\", \"sid:%v tid:%v wsURL:%q\", msg.SessionID, tid, c.wsURL)\n\tcase <-ctx.Done():\n\t\tc.logger.Debugf(\"Connection:send:<-ctx.Done()\", \"sid:%v tid:%v wsURL:%q err:%v\",\n\t\t\tmsg.SessionID, tid, c.wsURL, ContextErr(c.ctx))\n\t\treturn ContextErr(ctx)\n\tcase <-c.ctx.Done():\n\t\tc.logger.Debugf(\"Connection:send:<-c.ctx.Done()\", \"sid:%v tid:%v wsURL:%q err:%v\",\n\t\t\tmsg.SessionID, tid, c.wsURL, ContextErr(c.ctx))\n\t\treturn ContextErr(c.ctx)\n\t}\n\treturn nil\n}\n\nfunc (c *Connection) sendLoop() {\n\tc.logger.Debugf(\"Connection:sendLoop\", \"wsURL:%q, starts\", c.wsURL)\n\tfor {\n\t\tselect {\n\t\tcase msg := <-c.sendCh:\n\t\t\twriter, err := c.conn.NextWriter(websocket.TextMessage)\n\t\t\tif err != nil {\n\t\t\t\tc.handleIOError(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\terr = jsonv2.MarshalWrite(writer, msg, defaultJSONV2Options)\n\t\t\tif err != nil {\n\t\t\t\tc.handleIOError(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif err := writer.Close(); err != nil {\n\t\t\t\tc.handleIOError(err)\n\t\t\t\treturn\n\t\t\t}\n\t\tcase code := <-c.closeCh:\n\t\t\tc.logger.Debugf(\"Connection:sendLoop:<-c.closeCh\", \"wsURL:%q code:%d\", c.wsURL, code)\n\t\t\t_ = c.close(code)\n\t\t\treturn\n\t\tcase <-c.done:\n\t\t\tc.logger.Debugf(\"Connection:sendLoop:<-c.done#2\", \"wsURL:%q\", c.wsURL)\n\t\t\treturn\n\t\tcase <-c.ctx.Done():\n\t\t\tc.logger.Debugf(\"connection:sendLoop\", \"returning, ctx.Err: %q\", c.ctx.Err())\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Close cleanly closes the WebSocket connection.\n// It returns an error if sending the Close control frame fails.\n//\n// Optional code to override default websocket.CloseGoingAway (1001).\nfunc (c *Connection) Close() {\n\tcode := websocket.CloseNormalClosure\n\tc.logger.Debugf(\"connection:Close\", \"wsURL:%q code:%d\", c.wsURL, code)\n\t_ = c.close(code)\n}\n\n// Execute implements cdproto.Executor and performs a synchronous send and receive.\nfunc (c *Connection) Execute(\n\tctx context.Context, method string, params, res any,\n) error {\n\tc.logger.Debugf(\"connection:Execute\", \"wsURL:%q method:%q\", c.wsURL, method)\n\tid := c.msgIDGen.newID()\n\n\t// Setup event handler used to block for response to message being sent.\n\tch := make(chan *cdproto.Message, 1)\n\tevCancelCtx, evCancelFn := context.WithCancel(ctx)\n\tchEvHandler := make(chan Event)\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\tc.logger.Debugf(\"connection:Execute:<-evCancelCtx.Done()\", \"wsURL:%q err:%v\", c.wsURL, evCancelCtx.Err())\n\t\t\t\treturn\n\t\t\tcase ev := <-chEvHandler:\n\t\t\t\tmsg, ok := ev.data.(*cdproto.Message)\n\t\t\t\tif ok && msg.ID == id {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\t\t\tc.logger.Debugf(\"connection:Execute:<-evCancelCtx.Done()#2\", \"wsURL:%q err:%v\", c.wsURL, evCancelCtx.Err())\n\t\t\t\t\tcase ch <- msg:\n\t\t\t\t\t\t// Stopping goroutine as we expect only one response with the matching message ID\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\tc.onAll(evCancelCtx, chEvHandler)\n\tdefer evCancelFn() // Remove event handler\n\n\t// Send the message\n\tvar buf []byte\n\tif params != nil {\n\t\tvar err error\n\t\tbuf, err = jsonv2.Marshal(params, defaultJSONV2Options)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tmsg := &cdproto.Message{\n\t\tID:     id,\n\t\tMethod: cdproto.MethodType(method),\n\t\tParams: buf,\n\t}\n\n\treturn c.send(evCancelCtx, msg, ch, res)\n}\n\n// IgnoreIOErrors signals that the connection will soon be closed, so that any\n// received IO errors can be disregarded.\nfunc (c *Connection) IgnoreIOErrors() {\n\tclose(c.closing)\n}\n\nfunc (c *Connection) isClosing() (s bool) {\n\tselect {\n\tcase <-c.closing:\n\t\ts = true\n\tdefault:\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/connection_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/tests/ws\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/target\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestConnection(t *testing.T) {\n\tt.Parallel()\n\n\tserver := ws.NewServer(t, ws.WithEchoHandler(\"/echo\"))\n\n\tt.Run(\"connect\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\turl, _ := url.Parse(server.ServerHTTP.URL)\n\t\twsURL := fmt.Sprintf(\"ws://%s/echo\", url.Host)\n\t\tconn, err := NewConnection(ctx, wsURL, log.NewNullLogger(), nil)\n\t\tconn.Close()\n\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestConnectionClosureAbnormal(t *testing.T) {\n\tt.Parallel()\n\n\tserver := ws.NewServer(t, ws.WithClosureAbnormalHandler(\"/closure-abnormal\"))\n\n\tt.Run(\"closure abnormal\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\turl, _ := url.Parse(server.ServerHTTP.URL)\n\t\twsURL := fmt.Sprintf(\"ws://%s/closure-abnormal\", url.Host)\n\t\tconn, err := NewConnection(ctx, wsURL, log.NewNullLogger(), nil)\n\n\t\tif assert.NoError(t, err) {\n\t\t\taction := target.SetDiscoverTargets(true)\n\t\t\terr := action.Do(cdp.WithExecutor(ctx, conn))\n\t\t\trequire.ErrorContains(t, err, \"websocket: close 1006 (abnormal closure): unexpected EOF\")\n\t\t}\n\t})\n}\n\nfunc TestConnectionSendRecv(t *testing.T) {\n\tt.Parallel()\n\n\tserver := ws.NewServer(t, ws.WithCDPHandler(\"/cdp\", ws.CDPDefaultHandler, nil))\n\n\tt.Run(\"send command with empty reply\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\turl, _ := url.Parse(server.ServerHTTP.URL)\n\t\twsURL := fmt.Sprintf(\"ws://%s/cdp\", url.Host)\n\t\tconn, err := NewConnection(ctx, wsURL, log.NewNullLogger(), nil)\n\n\t\tif assert.NoError(t, err) {\n\t\t\taction := target.SetDiscoverTargets(true)\n\t\t\terr := action.Do(cdp.WithExecutor(ctx, conn))\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t})\n}\n\nfunc TestConnectionCreateSession(t *testing.T) {\n\tt.Parallel()\n\n\tcmdsReceived := make([]cdproto.MethodType, 0)\n\thandler := func(conn *websocket.Conn, msg *cdproto.Message, writeCh chan cdproto.Message, done chan struct{}) {\n\t\tif msg.SessionID == \"\" && msg.Method != \"\" {\n\t\t\tswitch msg.Method {\n\t\t\tcase cdproto.MethodType(cdproto.CommandTargetSetDiscoverTargets):\n\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\tID:        msg.ID,\n\t\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\t\tResult:    jsontext.Value([]byte(\"{}\")),\n\t\t\t\t}\n\t\t\tcase cdproto.MethodType(cdproto.CommandTargetAttachToTarget):\n\t\t\t\tswitch msg.Method {\n\t\t\t\tcase cdproto.MethodType(cdproto.CommandTargetSetDiscoverTargets):\n\t\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\t\tID:        msg.ID,\n\t\t\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\t\t\tResult:    jsontext.Value([]byte(\"{}\")),\n\t\t\t\t\t}\n\t\t\t\tcase cdproto.MethodType(cdproto.CommandTargetAttachToTarget):\n\t\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\t\tMethod: cdproto.EventTargetAttachedToTarget,\n\t\t\t\t\t\tParams: jsontext.Value([]byte(`\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"sessionId\": \"0123456789\",\n\t\t\t\t\t\t\t\"targetInfo\": {\n\t\t\t\t\t\t\t\t\"targetId\": \"abcdef0123456789\",\n\t\t\t\t\t\t\t\t\"type\": \"page\",\n\t\t\t\t\t\t\t\t\"title\": \"\",\n\t\t\t\t\t\t\t\t\"url\": \"about:blank\",\n\t\t\t\t\t\t\t\t\"attached\": true,\n\t\t\t\t\t\t\t\t\"browserContextId\": \"0123456789876543210\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"waitingForDebugger\": false\n\t\t\t\t\t\t}\n\t\t\t\t\t\t`)),\n\t\t\t\t\t}\n\t\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\t\tID:        msg.ID,\n\t\t\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\t\t\tResult:    jsontext.Value([]byte(`{\"sessionId\":\"0123456789\"}`)),\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tserver := ws.NewServer(t, ws.WithCDPHandler(\"/cdp\", handler, &cmdsReceived))\n\n\tt.Run(\"create session for target\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\turl, _ := url.Parse(server.ServerHTTP.URL)\n\t\twsURL := fmt.Sprintf(\"ws://%s/cdp\", url.Host)\n\t\tconn, err := NewConnection(ctx, wsURL, log.NewNullLogger(), nil)\n\n\t\tif assert.NoError(t, err) {\n\t\t\tsession, err := conn.createSession(&target.Info{\n\t\t\t\tTargetID:         \"abcdef0123456789\",\n\t\t\t\tType:             \"page\",\n\t\t\t\tBrowserContextID: \"0123456789876543210\",\n\t\t\t})\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, session)\n\t\t\trequire.NotEmpty(t, session.id)\n\t\t\trequire.NotEmpty(t, conn.sessions)\n\t\t\trequire.Len(t, conn.sessions, 1)\n\t\t\trequire.Equal(t, conn.sessions[session.id], session)\n\t\t\trequire.Equal(t, []cdproto.MethodType{\n\t\t\t\tcdproto.CommandTargetAttachToTarget,\n\t\t\t}, cmdsReceived)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/consts.go",
    "content": "package common\n\nimport \"time\"\n\nconst (\n\t// Defaults\n\n\tDefaultLocale       string        = \"en-US\"\n\tDefaultScreenWidth  int64         = 1280\n\tDefaultScreenHeight int64         = 720\n\tDefaultTimeout      time.Duration = 30 * time.Second\n\n\t// Life-cycle consts\n\n\tLifeCycleNetworkIdleTimeout time.Duration = 500 * time.Millisecond\n\n\t// API default consts.\n\n\tStrictModeOff = false\n)\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/context.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n)\n\ntype ctxKey int\n\nconst (\n\tctxKeyBrowserOptions ctxKey = iota\n\tctxKeyHooks\n\tctxKeyIterationID\n\tctxKeyTracer\n)\n\nfunc WithHooks(ctx context.Context, hooks *Hooks) context.Context {\n\treturn context.WithValue(ctx, ctxKeyHooks, hooks)\n}\n\nfunc GetHooks(ctx context.Context) *Hooks {\n\tv := ctx.Value(ctxKeyHooks)\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn v.(*Hooks) //nolint:forcetypeassert\n}\n\n// WithIterationID adds an identifier for the current iteration to the context.\nfunc WithIterationID(ctx context.Context, iterID string) context.Context {\n\treturn context.WithValue(ctx, ctxKeyIterationID, iterID)\n}\n\n// GetIterationID returns the iteration identifier attached to the context.\nfunc GetIterationID(ctx context.Context) string {\n\ts, _ := ctx.Value(ctxKeyIterationID).(string)\n\treturn s\n}\n\n// WithBrowserOptions adds the browser options to the context.\nfunc WithBrowserOptions(ctx context.Context, opts *BrowserOptions) context.Context {\n\treturn context.WithValue(ctx, ctxKeyBrowserOptions, opts)\n}\n\n// GetBrowserOptions returns the browser options attached to the context.\nfunc GetBrowserOptions(ctx context.Context) *BrowserOptions {\n\tv := ctx.Value(ctxKeyBrowserOptions)\n\tif v == nil {\n\t\treturn nil\n\t}\n\tif bo, ok := v.(*BrowserOptions); ok {\n\t\treturn bo\n\t}\n\treturn nil\n}\n\n// WithTracer adds the given tracer to the context.\nfunc WithTracer(ctx context.Context, tracer Tracer) context.Context {\n\treturn context.WithValue(ctx, ctxKeyTracer, tracer)\n}\n\n// GetTracer returns the tracer attached to the context, or nil if not found.\nfunc GetTracer(ctx context.Context) Tracer {\n\tv := ctx.Value(ctxKeyTracer)\n\tif v == nil {\n\t\treturn nil\n\t}\n\tif tracer, ok := v.(Tracer); ok {\n\t\treturn tracer\n\t}\n\treturn nil\n}\n\n// contextWithDoneChan returns a new context that is canceled either\n// when the done channel is closed or ctx is canceled.\nfunc contextWithDoneChan(ctx context.Context, done chan struct{}) context.Context {\n\tctx, cancel := context.WithCancel(ctx)\n\tgo func() {\n\t\tdefer cancel()\n\t\tselect {\n\t\tcase <-done:\n\t\tcase <-ctx.Done():\n\t\t}\n\t}()\n\treturn ctx\n}\n\n// ContextErr returns ctx.Err() and, if present, appends the cancel cause.\nfunc ContextErr(ctx context.Context) error {\n\terr := ctx.Err()\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tcause := context.Cause(ctx)\n\tif cause == nil || errors.Is(cause, err) {\n\t\treturn err\n\t}\n\n\treturn fmt.Errorf(\"%w: %w\", err, cause)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/context_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestContextWithDoneChan(t *testing.T) {\n\tt.Parallel()\n\n\tdone := make(chan struct{})\n\tctx := contextWithDoneChan(context.Background(), done)\n\tclose(done)\n\tselect {\n\tcase <-ctx.Done():\n\tcase <-time.After(time.Millisecond * 100):\n\t\trequire.FailNow(t, \"should cancel the context after closing the done chan\")\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/device.go",
    "content": "package common\n\n// Device represents an end-user device (computer, tablet, phone etc.)\ntype Device struct {\n\tName              string   `js:\"name\"`\n\tUserAgent         string   `js:\"userAgent\"`\n\tViewport          Viewport `js:\"viewport\"`\n\tDeviceScaleFactor float64  `js:\"deviceScaleFactor\"`\n\tIsMobile          bool     `js:\"isMobile\"`\n\tHasTouch          bool     `js:\"hasTouch\"`\n}\n\n// GetDevices returns predefined emulation settings for many end-user devices.\n//\n//nolint:lll,funlen\nfunc GetDevices() map[string]Device {\n\treturn map[string]Device{\n\t\t\"Blackberry PlayBook\": {\n\t\t\tName:      \"Blackberry PlayBook\",\n\t\t\tUserAgent: \"Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  600,\n\t\t\t\tHeight: 1024,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Blackberry PlayBook landscape\": {\n\t\t\tName:      \"Blackberry PlayBook landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  1024,\n\t\t\t\tHeight: 600,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"BlackBerry Z30\": {\n\t\t\tName:      \"BlackBerry Z30\",\n\t\t\tUserAgent: \"Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  360,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"BlackBerry Z30 landscape\": {\n\t\t\tName:      \"BlackBerry Z30 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy Note 3\": {\n\t\t\tName:      \"Galaxy Note 3\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  360,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy Note 3 landscape\": {\n\t\t\tName:      \"Galaxy Note 3 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy Note II\": {\n\t\t\tName:      \"Galaxy Note II\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  360,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy Note II landscape\": {\n\t\t\tName:      \"Galaxy Note II landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy S III\": {\n\t\t\tName:      \"Galaxy S III\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  360,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy S III landscape\": {\n\t\t\tName:      \"Galaxy S III landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy S5\": {\n\t\t\tName:      \"Galaxy S5\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  360,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Galaxy S5 landscape\": {\n\t\t\tName:      \"Galaxy S5 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPad\": {\n\t\t\tName:      \"iPad\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  768,\n\t\t\t\tHeight: 1024,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPad landscape\": {\n\t\t\tName:      \"iPad landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  1024,\n\t\t\t\tHeight: 768,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPad Mini\": {\n\t\t\tName:      \"iPad Mini\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  768,\n\t\t\t\tHeight: 1024,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPad Mini landscape\": {\n\t\t\tName:      \"iPad Mini landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  1024,\n\t\t\t\tHeight: 768,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPad Pro\": {\n\t\t\tName:      \"iPad Pro\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  1024,\n\t\t\t\tHeight: 1366,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPad Pro landscape\": {\n\t\t\tName:      \"iPad Pro landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  1366,\n\t\t\t\tHeight: 1024,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 4\": {\n\t\t\tName:      \"iPhone 4\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  320,\n\t\t\t\tHeight: 480,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 4 landscape\": {\n\t\t\tName:      \"iPhone 4 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  480,\n\t\t\t\tHeight: 320,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 5\": {\n\t\t\tName:      \"iPhone 5\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  320,\n\t\t\t\tHeight: 568,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 5 landscape\": {\n\t\t\tName:      \"iPhone 5 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  568,\n\t\t\t\tHeight: 320,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 6\": {\n\t\t\tName:      \"iPhone 6\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  375,\n\t\t\t\tHeight: 667,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 6 landscape\": {\n\t\t\tName:      \"iPhone 6 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  667,\n\t\t\t\tHeight: 375,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 6 Plus\": {\n\t\t\tName:      \"iPhone 6 Plus\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  414,\n\t\t\t\tHeight: 736,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 6 Plus landscape\": {\n\t\t\tName:      \"iPhone 6 Plus landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  736,\n\t\t\t\tHeight: 414,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 7\": {\n\t\t\tName:      \"iPhone 7\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  375,\n\t\t\t\tHeight: 667,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 7 landscape\": {\n\t\t\tName:      \"iPhone 7 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  667,\n\t\t\t\tHeight: 375,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 7 Plus\": {\n\t\t\tName:      \"iPhone 7 Plus\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  414,\n\t\t\t\tHeight: 736,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 7 Plus landscape\": {\n\t\t\tName:      \"iPhone 7 Plus landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  736,\n\t\t\t\tHeight: 414,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 8\": {\n\t\t\tName:      \"iPhone 8\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  375,\n\t\t\t\tHeight: 667,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 8 landscape\": {\n\t\t\tName:      \"iPhone 8 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  667,\n\t\t\t\tHeight: 375,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 8 Plus\": {\n\t\t\tName:      \"iPhone 8 Plus\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  414,\n\t\t\t\tHeight: 736,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone 8 Plus landscape\": {\n\t\t\tName:      \"iPhone 8 Plus landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  736,\n\t\t\t\tHeight: 414,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone SE\": {\n\t\t\tName:      \"iPhone SE\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  320,\n\t\t\t\tHeight: 568,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone SE landscape\": {\n\t\t\tName:      \"iPhone SE landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  568,\n\t\t\t\tHeight: 320,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone X\": {\n\t\t\tName:      \"iPhone X\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  375,\n\t\t\t\tHeight: 812,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone X landscape\": {\n\t\t\tName:      \"iPhone X landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  812,\n\t\t\t\tHeight: 375,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone XR\": {\n\t\t\tName:      \"iPhone XR\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  414,\n\t\t\t\tHeight: 896,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"iPhone XR landscape\": {\n\t\t\tName:      \"iPhone XR landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  896,\n\t\t\t\tHeight: 414,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"JioPhone 2\": {\n\t\t\tName:      \"JioPhone 2\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Mobile; LYF/F300B/LYF-F300B-001-01-15-130718-i;Android; rv:48.0) Gecko/48.0 Firefox/48.0 KAIOS/2.5\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  240,\n\t\t\t\tHeight: 320,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"JioPhone 2 landscape\": {\n\t\t\tName:      \"JioPhone 2 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Mobile; LYF/F300B/LYF-F300B-001-01-15-130718-i;Android; rv:48.0) Gecko/48.0 Firefox/48.0 KAIOS/2.5\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  320,\n\t\t\t\tHeight: 240,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Kindle Fire HDX\": {\n\t\t\tName:      \"Kindle Fire HDX\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  800,\n\t\t\t\tHeight: 1280,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Kindle Fire HDX landscape\": {\n\t\t\tName:      \"Kindle Fire HDX landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  1280,\n\t\t\t\tHeight: 800,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"LG Optimus L70\": {\n\t\t\tName:      \"LG Optimus L70\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  384,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1.25,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"LG Optimus L70 landscape\": {\n\t\t\tName:      \"LG Optimus L70 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 384,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1.25,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Microsoft Lumia 550\": {\n\t\t\tName:      \"Microsoft Lumia 550\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Microsoft Lumia 950\": {\n\t\t\tName:      \"Microsoft Lumia 950\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  360,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 4,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Microsoft Lumia 950 landscape\": {\n\t\t\tName:      \"Microsoft Lumia 950 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 4,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 10\": {\n\t\t\tName:      \"Nexus 10\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  800,\n\t\t\t\tHeight: 1280,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 10 landscape\": {\n\t\t\tName:      \"Nexus 10 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  1280,\n\t\t\t\tHeight: 800,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 4\": {\n\t\t\tName:      \"Nexus 4\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  384,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 4 landscape\": {\n\t\t\tName:      \"Nexus 4 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 384,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 5\": {\n\t\t\tName:      \"Nexus 5\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  360,\n\t\t\t\tHeight: 640,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 5 landscape\": {\n\t\t\tName:      \"Nexus 5 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  640,\n\t\t\t\tHeight: 360,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 5X\": {\n\t\t\tName:      \"Nexus 5X\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  412,\n\t\t\t\tHeight: 732,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2.625,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 5X landscape\": {\n\t\t\tName:      \"Nexus 5X landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  732,\n\t\t\t\tHeight: 412,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2.625,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 6\": {\n\t\t\tName:      \"Nexus 6\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  412,\n\t\t\t\tHeight: 732,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 6 landscape\": {\n\t\t\tName:      \"Nexus 6 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  732,\n\t\t\t\tHeight: 412,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 6P\": {\n\t\t\tName:      \"Nexus 6P\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  412,\n\t\t\t\tHeight: 732,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 6P landscape\": {\n\t\t\tName:      \"Nexus 6P landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  732,\n\t\t\t\tHeight: 412,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 7\": {\n\t\t\tName:      \"Nexus 7\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  600,\n\t\t\t\tHeight: 960,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nexus 7 landscape\": {\n\t\t\tName:      \"Nexus 7 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  960,\n\t\t\t\tHeight: 600,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nokia Lumia 520\": {\n\t\t\tName:      \"Nokia Lumia 520\",\n\t\t\tUserAgent: \"Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  320,\n\t\t\t\tHeight: 533,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nokia Lumia 520 landscape\": {\n\t\t\tName:      \"Nokia Lumia 520 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  533,\n\t\t\t\tHeight: 320,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nokia N9\": {\n\t\t\tName:      \"Nokia N9\",\n\t\t\tUserAgent: \"Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  480,\n\t\t\t\tHeight: 854,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Nokia N9 landscape\": {\n\t\t\tName:      \"Nokia N9 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  854,\n\t\t\t\tHeight: 480,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 1,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Pixel 2\": {\n\t\t\tName:      \"Pixel 2\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  411,\n\t\t\t\tHeight: 731,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2.625,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Pixel 2 landscape\": {\n\t\t\tName:      \"Pixel 2 landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  731,\n\t\t\t\tHeight: 411,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 2.625,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Pixel 2 XL\": {\n\t\t\tName:      \"Pixel 2 XL\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  411,\n\t\t\t\tHeight: 823,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t\t\"Pixel 2 XL landscape\": {\n\t\t\tName:      \"Pixel 2 XL landscape\",\n\t\t\tUserAgent: \"Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3765.0 Mobile Safari/537.36\",\n\t\t\tViewport: Viewport{\n\t\t\t\tWidth:  823,\n\t\t\t\tHeight: 411,\n\t\t\t},\n\t\t\tDeviceScaleFactor: 3.5,\n\t\t\tIsMobile:          true,\n\t\t\tHasTouch:          true,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/doc.go",
    "content": "// Package common provides the main logic of the browser module.\n// This package will be split into multiple packages in the future.\npackage common\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/element_handle.go",
    "content": "package common\n\nimport (\n\t\"cmp\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common/js\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n)\n\n// Common error types for element visibility.\nvar (\n\t// ErrElementNotVisible is returned when an element is not visible for an operation.\n\tErrElementNotVisible = errors.New(\"element is not visible\")\n\t// ErrElementNotAttachedToDOM is returned when an element is not attached to the DOM.\n\tErrElementNotAttachedToDOM = errors.New(\"element is not attached to the DOM\")\n)\n\nconst (\n\tresultDone       = \"done\"\n\tresultNeedsInput = \"needsinput\"\n)\n\ntype (\n\telementHandleActionFunc        func(context.Context, *ElementHandle) (any, error)\n\telementHandlePointerActionFunc func(context.Context, *ElementHandle, *Position) (any, error)\n\tretryablePointerActionFunc     func(context.Context, *ScrollIntoViewOptions) (any, error)\n\n\t// evalFunc is a common interface for both evalWithScript and eval.\n\t// It helps abstracting these methods to aid with testing.\n\tevalFunc func(ctx context.Context, opts evalOptions, js string, args ...any) (any, error)\n)\n\n// ElementHandle represents a HTML element JS object inside an execution context.\ntype ElementHandle struct {\n\tBaseJSHandle\n\n\tframe *Frame\n}\n\n// String returns a string repesentation of ElementHandle.\n// It exists mostly for debugging where we don't want fmt.Sprintf to just\n// go through a complex object and try to stringify it.\nfunc (h *ElementHandle) String() string {\n\treturn \"ElementHandle{\" +\n\t\t\" BaseJSHandle:  \" + h.BaseJSHandle.String() +\n\t\t\" frame: \" + h.frame.String() +\n\t\t\"}\"\n}\n\nfunc (h *ElementHandle) boundingBox() (*Rect, error) {\n\tvar box *dom.BoxModel\n\tvar err error\n\taction := dom.GetBoxModel().WithObjectID(h.remoteObject.ObjectID)\n\tif box, err = action.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting bounding box model of DOM node: %w\", err)\n\t}\n\n\tif box == nil || box.Border == nil {\n\t\treturn nil, ErrElementNotAttachedToDOM\n\t}\n\n\tquad := box.Border\n\tx := math.Min(quad[0], math.Min(quad[2], math.Min(quad[4], quad[6])))\n\ty := math.Min(quad[1], math.Min(quad[3], math.Min(quad[5], quad[7])))\n\twidth := math.Max(quad[0], math.Max(quad[2], math.Max(quad[4], quad[6]))) - x\n\theight := math.Max(quad[1], math.Max(quad[3], math.Max(quad[5], quad[7]))) - y\n\n\tposition, err := h.frame.position()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting position of parent frame: %w\", err)\n\t}\n\n\treturn &Rect{X: x + position.X, Y: y + position.Y, Width: width, Height: height}, nil\n}\n\n// translatePointToPage translates the point to the page's coordinates if the\n// point is relative to the parent frame.\nfunc (h *ElementHandle) translatePointToPage(apiCtx context.Context, point Position) (Position, error) {\n\th.logger.Debugf(\"ElementHandle:translatePointToPage\", \"point before translation: %v\", point)\n\n\tframe, err := h.ownerFrame(apiCtx)\n\tif err != nil {\n\t\treturn Position{}, fmt.Errorf(\"checking hit target at %v: %w\", point, err)\n\t}\n\n\tif frame == nil || frame.parentFrame == nil {\n\t\th.logger.Debugf(\"ElementHandle:translatePointToPage\", \"no parent frame\")\n\t\treturn point, nil\n\t}\n\n\tel, err := frame.FrameElement()\n\tif err != nil {\n\t\treturn Position{}, err\n\t}\n\n\tbox, err := el.BoundingBox()\n\tif err != nil {\n\t\treturn Position{}, fmt.Errorf(\"getting bounding box of parent frame: %w\", err)\n\t}\n\n\tif box.contains(point) {\n\t\th.logger.Debugf(\"ElementHandle:translatePointToPage\", \"point is already in the page\")\n\t\treturn point, nil\n\t}\n\n\t// Translate from frame coordinates to page coordinates.\n\tpoint.X += box.X\n\tpoint.Y += box.Y\n\n\th.logger.Debugf(\"ElementHandle:translatePointToPage\", \"point after translation: %v\", point)\n\n\treturn point, nil\n}\n\n// checkHitTargetAt checks if the element is hit by the pointer at the given point.\n//\n// It will recurse through frames and iframes to check if the point hits a target\n// when an error:intercept occurs.\n//\n// It will eventually return error:intercept if the point doesn't hit any target. At\n// this point the caller should retry the action after scrolling.\nfunc (h *ElementHandle) checkHitTargetAt(apiCtx context.Context, point Position) (bool, error) {\n\th.logger.Debugf(\"ElementHandle:checkHitTargetAt\", \"checking hit target at %v\", point)\n\n\tfn := `\n\t\t(node, injected, point) => {\n\t\t\treturn injected.checkHitTargetAt(node, point);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(h.ctx, opts, fn, point)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t// Either we're done or an error happened (returned as \"error:...\" from JS)\n\tconst done = resultDone\n\tif v, ok := result.(string); !ok {\n\t\tframe, err := h.ownerFrame(apiCtx)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"checking hit target at %v: %w\", point, err)\n\t\t}\n\n\t\tif frame == nil {\n\t\t\t// We got a { hitTargetDescription: ... } result\n\t\t\t// Meaning: Another element is preventing pointer events.\n\t\t\t//\n\t\t\t// It's safe to count an object return as an interception.\n\t\t\t// We just don't interpret what is intercepting with the target element\n\t\t\t// because we don't need any more functionality from this JS function\n\t\t\t// right now.\n\t\t\treturn false, errorFromDOMError(\"error:intercept\")\n\t\t}\n\n\t\tel, err := frame.FrameElement()\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\treturn el.checkHitTargetAt(apiCtx, point)\n\t} else if v != done {\n\t\treturn false, errorFromDOMError(v)\n\t}\n\n\treturn true, nil\n}\n\nfunc (h *ElementHandle) checkElementState(_ context.Context, state string) (*bool, error) {\n\tfn := `\n\t\t(node, injected, state) => {\n\t\t\treturn injected.checkElementState(node, state);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(h.ctx, opts, fn, state)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch v := result.(type) {\n\tcase string: // An error happened (returned as \"error:...\" from JS)\n\t\treturn nil, errorFromDOMError(v)\n\tcase bool:\n\t\treturn &v, nil\n\t}\n\n\treturn nil, fmt.Errorf(\n\t\t\"checking state %q of element %q\", state, reflect.TypeOf(result))\n}\n\nfunc (h *ElementHandle) click(p *Position, opts *MouseClickOptions) error {\n\treturn h.frame.page.Mouse.click(p.X, p.Y, opts)\n}\n\n// This will get the clickable point of the element relative to the page even\n// when the element is in an iframe. In some cases this isn't the case and we\n// need to translate the point to the page.\nfunc (h *ElementHandle) clickablePoint() (*Position, error) {\n\tr, err := h.BoundingBox()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"finding clickable point: %w\", err)\n\t}\n\treturn &Position{X: r.X + r.Width/2, Y: r.Y + r.Height/2}, nil\n}\n\nfunc (h *ElementHandle) dblclick(p *Position, opts *MouseClickOptions) error {\n\treturn h.frame.page.Mouse.click(p.X, p.Y, opts)\n}\n\n// DefaultTimeout returns the default timeout for this element handle.\nfunc (h *ElementHandle) DefaultTimeout() time.Duration {\n\treturn h.frame.manager.timeoutSettings.timeout()\n}\n\nfunc (h *ElementHandle) dispatchEvent(_ context.Context, typ string, eventInit any) (any, error) {\n\tfn := `\n\t\t(node, injected, type, eventInit) => {\n\t\t\tinjected.dispatchEvent(node, type, eventInit);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\t_, err := h.evalWithScript(h.ctx, opts, fn, typ, eventInit)\n\n\treturn nil, err\n}\n\nfunc (h *ElementHandle) fill(_ context.Context, value string) error {\n\tfn := `\n\t\t(node, injected, value) => {\n\t\t\treturn injected.fill(node, value);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(h.ctx, opts, fn, value)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts, ok := result.(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type %T\", result)\n\t}\n\n\tif s == resultNeedsInput {\n\t\tif err := h.frame.page.Keyboard.InsertText(value); err != nil {\n\t\t\treturn fmt.Errorf(\"fill: %w\", err)\n\t\t}\n\t} else if s != resultDone {\n\t\t// Either we're done or an error happened (returned as \"error:...\" from JS)\n\t\treturn errorFromDOMError(s)\n\t}\n\n\treturn nil\n}\n\nfunc (h *ElementHandle) focus(apiCtx context.Context, resetSelectionIfNotFocused bool) error {\n\tfn := `\n\t\t(node, injected, resetSelectionIfNotFocused) => {\n\t\t\treturn injected.focusNode(node, resetSelectionIfNotFocused);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(apiCtx, opts, fn, resetSelectionIfNotFocused)\n\tif err != nil {\n\t\treturn err\n\t}\n\ts, ok := result.(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type %T\", result)\n\t}\n\tif s != resultDone {\n\t\t// Either we're done or an error happened (returned as \"error:...\" from JS)\n\t\treturn errorFromDOMError(s)\n\t}\n\n\treturn nil\n}\n\nfunc (h *ElementHandle) getAttribute(apiCtx context.Context, name string) (any, error) {\n\tjs := `\n\t\t(element) => {\n\t\t\treturn element.getAttribute('` + name + `');\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\treturn h.eval(apiCtx, opts, js)\n}\n\nfunc (h *ElementHandle) hover(_ context.Context, p *Position) error {\n\treturn h.frame.page.Mouse.move(p.X, p.Y, NewMouseMoveOptions())\n}\n\nfunc (h *ElementHandle) innerHTML(apiCtx context.Context) (any, error) {\n\tjs := `\n\t\t(element) => {\n\t\t\treturn element.innerHTML;\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\treturn h.eval(apiCtx, opts, js)\n}\n\nfunc (h *ElementHandle) innerText(apiCtx context.Context) (any, error) {\n\tjs := `\n\t\t(element) => {\n\t\t\treturn element.innerText;\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\n\treturn h.eval(apiCtx, opts, js)\n}\n\nfunc (h *ElementHandle) inputValue(apiCtx context.Context) (any, error) {\n\t//nolint:lll\n\tjs := `\n\t\t(element) => {\n\t\t\tif (element.nodeType !== Node.ELEMENT_NODE || (element.nodeName !== 'INPUT' && element.nodeName !== 'TEXTAREA' && element.nodeName !== 'SELECT')) {\n        \t\t\tthrow Error('Node is not an <input>, <textarea> or <select> element');\n\t\t\t}\n\t\t\treturn element.value;\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\treturn h.eval(apiCtx, opts, js)\n}\n\nfunc (h *ElementHandle) isChecked(apiCtx context.Context, timeout time.Duration) (bool, error) {\n\treturn h.waitForElementState(apiCtx, []string{\"checked\"}, timeout)\n}\n\nfunc (h *ElementHandle) isDisabled(apiCtx context.Context, timeout time.Duration) (bool, error) {\n\treturn h.waitForElementState(apiCtx, []string{\"disabled\"}, timeout)\n}\n\nfunc (h *ElementHandle) isEditable(apiCtx context.Context, timeout time.Duration) (bool, error) {\n\treturn h.waitForElementState(apiCtx, []string{\"editable\"}, timeout)\n}\n\nfunc (h *ElementHandle) isEnabled(apiCtx context.Context, timeout time.Duration) (bool, error) {\n\treturn h.waitForElementState(apiCtx, []string{\"enabled\"}, timeout)\n}\n\nfunc (h *ElementHandle) isHidden(apiCtx context.Context) (bool, error) {\n\treturn h.waitForElementState(apiCtx, []string{\"hidden\"}, 0)\n}\n\nfunc (h *ElementHandle) isVisible(apiCtx context.Context) (bool, error) {\n\treturn h.waitForElementState(apiCtx, []string{\"visible\"}, 0)\n}\n\nfunc (h *ElementHandle) offsetPosition(apiCtx context.Context, offset *Position) (*Position, error) {\n\tfn := `\n\t\t(node, injected) => {\n\t\t\treturn injected.getElementBorderWidth(node);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(apiCtx, opts, fn)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar border struct{ Top, Left float64 }\n\tif err := convert(result, &border); err != nil {\n\t\treturn nil, fmt.Errorf(\"converting result (%v of type %t) to border: %w\", result, result, err)\n\t}\n\n\tbox, err := h.BoundingBox()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"finding offset position: %w\", err)\n\t}\n\n\tif box == nil || (border.Left == 0 && border.Top == 0) {\n\t\treturn nil, ErrElementNotVisible\n\t}\n\n\t// Make point relative to the padding box to align with offsetX/offsetY.\n\treturn &Position{\n\t\tX: box.X + border.Left + offset.X,\n\t\tY: box.Y + border.Top + offset.Y,\n\t}, nil\n}\n\nfunc (h *ElementHandle) ownerFrame(apiCtx context.Context) (*Frame, error) {\n\tframeID, err := h.frame.page.getOwnerFrame(apiCtx, h)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif frameID == \"\" {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\tframe, ok := h.frame.page.frameManager.getFrameByID(frameID)\n\tif ok {\n\t\treturn frame, nil\n\t}\n\tfor _, page := range h.frame.page.browserCtx.browser.pages {\n\t\tframe, ok = page.frameManager.getFrameByID(frameID)\n\t\tif ok {\n\t\t\treturn frame, nil\n\t\t}\n\t}\n\n\treturn nil, nil //nolint:nilnil\n}\n\nfunc (h *ElementHandle) scrollRectIntoViewIfNeeded(apiCtx context.Context, rect *dom.Rect) error {\n\taction := dom.ScrollIntoViewIfNeeded().WithObjectID(h.remoteObject.ObjectID).WithRect(rect)\n\terr := action.Do(cdp.WithExecutor(apiCtx, h.session))\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"Node does not have a layout object\") {\n\t\t\treturn ErrElementNotVisible\n\t\t}\n\t\tif strings.Contains(err.Error(), \"Node is detached from document\") {\n\t\t\treturn ErrElementNotAttachedToDOM\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (h *ElementHandle) press(apiCtx context.Context, key string, opts KeyboardOptions) error {\n\terr := h.focus(apiCtx, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = h.frame.page.Keyboard.comboPress(key, opts)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (h *ElementHandle) selectOption(apiCtx context.Context, values []any) (any, error) {\n\tfn := `\n\t\t(node, injected, values) => {\n\t\t\treturn injected.selectOptions(node, values);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: false,\n\t}\n\tresult, err := h.evalWithScript(apiCtx, opts, fn, values)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif result, ok := result.(string); ok {\n\t\t// An error happened (returned as \"error:...\" from JS)\n\t\tif result != resultDone {\n\t\t\treturn nil, errorFromDOMError(result)\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc (h *ElementHandle) selectText(apiCtx context.Context) error {\n\tfn := `\n\t\t(node, injected) => {\n\t\t\treturn injected.selectText(node);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(apiCtx, opts, fn)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif result, ok := result.(string); ok {\n\t\tif result != resultDone {\n\t\t\treturn errorFromDOMError(result)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (h *ElementHandle) textContent(apiCtx context.Context) (any, error) {\n\tjs := `\n\t\t(element) => {\n\t\t\treturn element.textContent;\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\treturn h.eval(apiCtx, opts, js)\n}\n\nfunc (h *ElementHandle) typ(apiCtx context.Context, text string, opts KeyboardOptions) error {\n\terr := h.focus(apiCtx, true)\n\tif err != nil {\n\t\treturn err\n\t}\n\terr = h.frame.page.Keyboard.typ(text, opts)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (h *ElementHandle) waitAndScrollIntoViewIfNeeded(\n\t_ context.Context, force, noWaitAfter bool, timeout time.Duration,\n) error {\n\tfn := func(apiCtx context.Context, _ *ElementHandle) (any, error) {\n\t\tfn := `\n\t\t\t(element) => {\n\t\t\t\telement.scrollIntoViewIfNeeded(true);\n\t\t\t\treturn [window.scrollX, window.scrollY];\n\t\t\t}\n\t\t`\n\t\topts := evalOptions{\n\t\t\tforceCallable: true,\n\t\t\treturnByValue: true,\n\t\t}\n\n\t\treturn h.eval(apiCtx, opts, fn)\n\t}\n\tactFn := h.newAction([]string{\"visible\", \"stable\"}, fn, force, noWaitAfter, timeout)\n\t_, err := call(h.ctx, actFn, timeout)\n\n\treturn err\n}\n\nfunc (h *ElementHandle) waitForElementState(\n\tapiCtx context.Context, states []string, timeout time.Duration,\n) (bool, error) {\n\tfn := `\n\t\t(node, injected, states, timeout) => {\n\t\t\treturn injected.waitForElementStates(node, states, timeout);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(apiCtx, opts, fn, states, timeout.Milliseconds())\n\tif err != nil {\n\t\treturn false, errorFromDOMError(err)\n\t}\n\tswitch v := result.(type) {\n\tcase string: // Either we're done or an error happened (returned as \"error:...\" from JS)\n\t\tif v == resultDone {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, errorFromDOMError(v)\n\tcase bool:\n\t\treturn v, nil\n\t}\n\n\treturn false, fmt.Errorf(\n\t\t\"waiting for states %v of element %q\", states, reflect.TypeOf(result))\n}\n\n// stepIntoFrame steps into an iframe/frame. Due to CORS, we need to perform this\n// step outside of the browser (chromium). It returns the frame that it has stepped\n// into and the selector to use within that frame.\nfunc (h *ElementHandle) stepIntoFrame(\n\tapiCtx context.Context, parsedSelector *Selector, frameNavIndex int, opts *FrameWaitForSelectorOptions,\n) (*Frame, string, error) {\n\t// Split selector at frame navigation boundary\n\tbeforeFrame, afterFrame := h.splitSelectorAtFrame(parsedSelector, frameNavIndex)\n\n\t// Find the iframe element using the \"before frame\" selector\n\tiframeSelector := h.reconstructSelector(beforeFrame)\n\n\tiframeHandle, err := h.waitForSelector(apiCtx, iframeSelector, opts)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"finding iframe with selector %q: %w\", iframeSelector, err)\n\t}\n\n\t// This is a valid response from waitForSelector. It means that the element\n\t// was either hidden or detached.\n\tif iframeHandle == nil {\n\t\treturn nil, \"\", ErrElementNotVisible\n\t}\n\n\tframe, err := iframeHandle.ContentFrame()\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"getting iframe frame: %w\", err)\n\t}\n\n\t// Wait for selector in the iframe using the \"after frame\" selector\n\tafterFrameSelector := h.reconstructSelector(afterFrame)\n\n\treturn frame, afterFrameSelector, nil\n}\n\nfunc (h *ElementHandle) waitForSelector(\n\tapiCtx context.Context, selector string, opts *FrameWaitForSelectorOptions,\n) (*ElementHandle, error) {\n\tparsedSelector, err := NewSelector(selector)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Check for frame navigation in the selector\n\tframeNavIndex := h.findFrameNavigationIndex(parsedSelector)\n\tif frameNavIndex != -1 {\n\t\t// Strict is true because we assume the user is interested in the element\n\t\t// in the frame and not the frame it is in.\n\t\topts := &FrameWaitForSelectorOptions{\n\t\t\tState:   DOMElementStateAttached,\n\t\t\tTimeout: opts.Timeout,\n\t\t\tStrict:  true,\n\t\t}\n\n\t\tframe, afterFrameSelector, err := h.stepIntoFrame(apiCtx, parsedSelector, frameNavIndex, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn frame.waitForSelector(afterFrameSelector, opts)\n\t}\n\n\t// No frame navigation - proceed with normal waitForSelector logic\n\tfn := `\n\t\t(node, injected, selector, strict, state, timeout, ...args) => {\n\t\t\treturn injected.waitForSelector(selector, node, strict, state, 'raf', timeout, ...args);\n\t\t}\n\t`\n\teopts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: false,\n\t}\n\tresult, err := h.evalWithScript(\n\t\tapiCtx,\n\t\teopts, fn, parsedSelector,\n\t\topts.Strict, opts.State.String(), opts.Timeout.Milliseconds(),\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch r := result.(type) {\n\tcase *ElementHandle:\n\t\treturn r, nil\n\tdefault:\n\t\t// This is a valid response, which means that the element was either\n\t\t// hidden or detached.\n\t\treturn nil, nil //nolint:nilnil\n\t}\n}\n\nfunc (h *ElementHandle) count(apiCtx context.Context, selector string) (int, error) {\n\tparsedSelector, err := NewSelector(selector)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\t// Check for frame navigation in the selector\n\tframeNavIndex := h.findFrameNavigationIndex(parsedSelector)\n\tif frameNavIndex != -1 {\n\t\t// Strict is true because we assume the user is interested in the element\n\t\t// in the frame and not the frame it is in.\n\t\topts := &FrameWaitForSelectorOptions{\n\t\t\tState:   DOMElementStateAttached,\n\t\t\tTimeout: h.frame.defaultTimeout(),\n\t\t\tStrict:  true,\n\t\t}\n\n\t\tframe, afterFrameSelector, err := h.stepIntoFrame(apiCtx, parsedSelector, frameNavIndex, opts)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\treturn frame.count(afterFrameSelector)\n\t}\n\n\t// No frame navigation - proceed with normal count logic\n\tfn := `\n\t\t\t(node, injected, selector) => {\n\t\t\t\treturn injected.count(selector, node);\n\t\t\t}\n\t\t`\n\teopts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(\n\t\tapiCtx,\n\t\teopts, fn, parsedSelector,\n\t)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tswitch r := result.(type) {\n\tcase float64:\n\t\tif r < float64(math.MinInt32) || r > float64(math.MaxInt32) {\n\t\t\treturn 0, fmt.Errorf(\"value %v out of range for int32 type\", r)\n\t\t}\n\t\treturn int(r), nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"unexpected value %v of type %T\", r, r)\n\t}\n}\n\n// findFrameNavigationIndex finds the index of the first internal:control=enter-frame directive\nfunc (h *ElementHandle) findFrameNavigationIndex(selector *Selector) int {\n\tfor i, part := range selector.Parts {\n\t\tif part.Name == \"internal:control\" && part.Body == \"enter-frame\" {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\n// splitSelectorAtFrame splits a selector at the frame navigation boundary\nfunc (h *ElementHandle) splitSelectorAtFrame(selector *Selector, frameIndex int) (*Selector, *Selector) {\n\tbeforeFrame := &Selector{\n\t\tSelector: selector.Selector, // Keep original for reference\n\t\tParts:    selector.Parts[:frameIndex],\n\t\tCapture:  selector.Capture,\n\t}\n\n\tafterFrame := &Selector{\n\t\tSelector: selector.Selector, // Keep original for reference\n\t\tParts:    selector.Parts[frameIndex+1:],\n\t\tCapture:  selector.Capture,\n\t}\n\n\treturn beforeFrame, afterFrame\n}\n\n// reconstructSelector rebuilds a selector string from selector parts\nfunc (h *ElementHandle) reconstructSelector(selector *Selector) string {\n\tif len(selector.Parts) == 0 {\n\t\treturn \"\"\n\t}\n\n\tparts := make([]string, len(selector.Parts))\n\tfor i, part := range selector.Parts {\n\t\tif part.Name == \"css\" {\n\t\t\tparts[i] = part.Body\n\t\t} else {\n\t\t\tparts[i] = part.Name + \"=\" + part.Body\n\t\t}\n\t}\n\n\treturn strings.Join(parts, \" >> \")\n}\n\n// AsElement returns this element handle.\nfunc (h *ElementHandle) AsElement() *ElementHandle {\n\treturn h\n}\n\n// BoundingBox returns this element's bounding box.\nfunc (h *ElementHandle) BoundingBox() (*Rect, error) {\n\tbbox, err := h.boundingBox()\n\tif err != nil && strings.Contains(err.Error(), \"Could not compute box model\") {\n\t\treturn nil, fmt.Errorf(\"%w: %w\", ErrElementNotVisible, err)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting bounding box: %w\", err)\n\t}\n\treturn bbox, nil\n}\n\n// Click scrolls element into view and clicks in the center of the element\n// TODO: look into making more robust using retries\n// (see: https://github.com/microsoft/playwright/blob/master/src/server/dom.ts#L298)\nfunc (h *ElementHandle) Click(opts *ElementHandleClickOptions) error {\n\tclick := h.newPointerAction(\n\t\tfunc(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\t\treturn nil, handle.click(p, opts.ToMouseClickOptions())\n\t\t},\n\t\t&opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(h.ctx, click, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"clicking on element: %w\", err)\n\t}\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// ContentFrame returns the frame that contains this element.\nfunc (h *ElementHandle) ContentFrame() (*Frame, error) {\n\tvar (\n\t\tnode *cdp.Node\n\t\terr  error\n\t)\n\taction := dom.DescribeNode().WithObjectID(h.remoteObject.ObjectID)\n\tif node, err = action.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting remote node %q: %w\", h.remoteObject.ObjectID, err)\n\t}\n\tif node == nil || node.FrameID == \"\" {\n\t\treturn nil, fmt.Errorf(\"element is not an iframe\")\n\t}\n\n\tframe, ok := h.frame.manager.getFrameByID(node.FrameID)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"frame not found for id %s\", node.FrameID)\n\t}\n\n\treturn frame, nil\n}\n\n// Dblclick scrolls element into view and double clicks on the element.\nfunc (h *ElementHandle) Dblclick(opts *ElementHandleDblclickOptions) error {\n\tdblclick := func(_ context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.dblclick(p, opts.ToMouseClickOptions())\n\t}\n\tdblclickAction := h.newPointerAction(dblclick, &opts.ElementHandleBasePointerOptions)\n\tif _, err := call(h.ctx, dblclickAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"double clicking on element: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// DispatchEvent dispatches a DOM event to the element.\nfunc (h *ElementHandle) DispatchEvent(typ string, eventInit any) error {\n\tdispatchEvent := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.dispatchEvent(apiCtx, typ, eventInit)\n\t}\n\topts := NewElementHandleBaseOptions(h.DefaultTimeout())\n\tdispatchEventAction := h.newAction(\n\t\t[]string{}, dispatchEvent, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, dispatchEventAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"dispatching element event %q: %w\", typ, err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// Fill types the given value into the element.\nfunc (h *ElementHandle) Fill(value string, opts *ElementHandleBaseOptions) error {\n\tfill := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.fill(apiCtx, value)\n\t}\n\tfillAction := h.newAction(\n\t\t[]string{\"visible\", \"enabled\", \"editable\"},\n\t\tfill, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, fillAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"filling element: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// Focus scrolls element into view and focuses the element.\nfunc (h *ElementHandle) Focus() error {\n\tfocus := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.focus(apiCtx, false)\n\t}\n\topts := NewElementHandleBaseOptions(h.DefaultTimeout())\n\tfocusAction := h.newAction(\n\t\t[]string{}, focus, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, focusAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"focusing on element: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// GetAttribute retrieves the value of specified element attribute.\n// The second return value is true if the attribute exists, and false otherwise.\nfunc (h *ElementHandle) GetAttribute(name string) (string, bool, error) {\n\tgetAttribute := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.getAttribute(apiCtx, name)\n\t}\n\topts := NewElementHandleBaseOptions(h.DefaultTimeout())\n\tgetAttributeAction := h.newAction(\n\t\t[]string{}, getAttribute, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\n\tv, err := call(h.ctx, getAttributeAction, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"getting attribute %q of element: %w\", name, err)\n\t}\n\tif v == nil {\n\t\treturn \"\", false, nil\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", false, fmt.Errorf(\n\t\t\t\"getting attribute %q of element: unexpected type %T (expecting string)\",\n\t\t\tname, v,\n\t\t)\n\t}\n\n\treturn s, true, nil\n}\n\n// Hover scrolls element into view and hovers over its center point.\nfunc (h *ElementHandle) Hover(opts *ElementHandleHoverOptions) error {\n\thover := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.hover(apiCtx, p)\n\t}\n\thoverAction := h.newPointerAction(hover, &opts.ElementHandleBasePointerOptions)\n\tif _, err := call(h.ctx, hoverAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"hovering on element: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// InnerHTML returns the inner HTML of the element.\nfunc (h *ElementHandle) InnerHTML() (string, error) {\n\tinnerHTML := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.innerHTML(apiCtx)\n\t}\n\topts := NewElementHandleBaseOptions(h.DefaultTimeout())\n\tinnerHTMLAction := h.newAction(\n\t\t[]string{}, innerHTML, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tv, err := call(h.ctx, innerHTMLAction, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting element's inner HTML: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unexpected type %T (expecting string)\", v)\n\t}\n\n\treturn s, nil\n}\n\n// InnerText returns the inner text of the element.\nfunc (h *ElementHandle) InnerText() (string, error) {\n\tinnerText := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.innerText(apiCtx)\n\t}\n\topts := NewElementHandleBaseOptions(h.DefaultTimeout())\n\tinnerTextAction := h.newAction(\n\t\t[]string{}, innerText, opts.Force, opts.NoWaitAfter, opts.Timeout.Abs(),\n\t)\n\tv, err := call(h.ctx, innerTextAction, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting element's inner text: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unexpected type %T (expecting string)\", v)\n\t}\n\n\treturn s, nil\n}\n\n// InputValue returns the value of the input element.\nfunc (h *ElementHandle) InputValue(opts *ElementHandleBaseOptions) (string, error) {\n\tinputValue := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.inputValue(apiCtx)\n\t}\n\tinputValueAction := h.newAction([]string{}, inputValue, opts.Force, opts.NoWaitAfter, opts.Timeout)\n\tv, err := call(h.ctx, inputValueAction, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting element's input value: %w\", err)\n\t}\n\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unexpected type %T (expecting string)\", v)\n\t}\n\n\treturn s, nil\n}\n\n// IsChecked checks if a checkbox or radio is checked.\nfunc (h *ElementHandle) IsChecked() (bool, error) {\n\tok, err := h.isChecked(h.ctx, 0)\n\t// We don't care about timeout errors here!\n\tif err != nil && !errors.Is(err, ErrTimedOut) {\n\t\treturn false, fmt.Errorf(\"checking element is checked: %w\", err)\n\t}\n\n\treturn ok, nil\n}\n\n// IsDisabled checks if the element is disabled.\nfunc (h *ElementHandle) IsDisabled() (bool, error) {\n\tok, err := h.isDisabled(h.ctx, 0)\n\t// We don't care anout timeout errors here!\n\tif err != nil && !errors.Is(err, ErrTimedOut) {\n\t\treturn false, fmt.Errorf(\"checking element is disabled: %w\", err)\n\t}\n\n\treturn ok, nil\n}\n\n// IsEditable checks if the element is editable.\nfunc (h *ElementHandle) IsEditable() (bool, error) {\n\tok, err := h.isEditable(h.ctx, 0)\n\t// We don't care anout timeout errors here!\n\tif err != nil && !errors.Is(err, ErrTimedOut) {\n\t\treturn false, fmt.Errorf(\"checking element is editable: %w\", err)\n\t}\n\n\treturn ok, nil\n}\n\n// IsEnabled checks if the element is enabled.\nfunc (h *ElementHandle) IsEnabled() (bool, error) {\n\tok, err := h.isEnabled(h.ctx, 0)\n\t// We don't care anout timeout errors here!\n\tif err != nil && !errors.Is(err, ErrTimedOut) {\n\t\treturn false, fmt.Errorf(\"checking element is enabled: %w\", err)\n\t}\n\n\treturn ok, nil\n}\n\n// IsHidden checks if the element is hidden.\nfunc (h *ElementHandle) IsHidden() (bool, error) {\n\tok, err := h.isHidden(h.ctx)\n\t// We don't care anout timeout errors here!\n\tif err != nil && !errors.Is(err, ErrTimedOut) {\n\t\treturn false, fmt.Errorf(\"checking element is hidden: %w\", err)\n\t}\n\n\treturn ok, nil\n}\n\n// IsVisible checks if the element is visible.\nfunc (h *ElementHandle) IsVisible() (bool, error) {\n\tok, err := h.isVisible(h.ctx)\n\t// We don't care anout timeout errors here!\n\tif err != nil && !errors.Is(err, ErrTimedOut) {\n\t\treturn false, fmt.Errorf(\"checking element is visible: %w\", err)\n\t}\n\n\treturn ok, nil\n}\n\n// OwnerFrame returns the frame containing this element.\nfunc (h *ElementHandle) OwnerFrame() (_ *Frame, rerr error) {\n\tfn := `\n\t\t(node, injected) => {\n\t\t\treturn injected.getDocumentElement(node);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: false,\n\t}\n\tres, err := h.evalWithScript(h.ctx, opts, fn)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting document element: %w\", err)\n\t}\n\tif res == nil {\n\t\treturn nil, errors.New(\"getting document element: nil document\")\n\t}\n\n\tdocumentHandle, ok := res.(*ElementHandle)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected result type while getting document element: %T\", res)\n\t}\n\tdefer func() {\n\t\tif err := documentHandle.Dispose(); err != nil {\n\t\t\terr = fmt.Errorf(\"disposing document element: %w\", err)\n\t\t\trerr = errors.Join(err, rerr)\n\t\t}\n\t}()\n\n\tif documentHandle.remoteObject.ObjectID == \"\" {\n\t\treturn nil, err\n\t}\n\n\tvar node *cdp.Node\n\taction := dom.DescribeNode().WithObjectID(documentHandle.remoteObject.ObjectID)\n\tif node, err = action.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting node in frame: %w\", err)\n\t}\n\tif node == nil || node.FrameID == \"\" {\n\t\treturn nil, fmt.Errorf(\"no frame found for node: %w\", err)\n\t}\n\n\tframe, ok := h.frame.manager.getFrameByID(node.FrameID)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"no frame found for id %s\", node.FrameID)\n\t}\n\n\treturn frame, nil\n}\n\n// Press scrolls element into view and presses the given keys.\nfunc (h *ElementHandle) Press(key string, opts *ElementHandlePressOptions) error {\n\tpress := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.press(apiCtx, key, KeyboardOptions{})\n\t}\n\tpressAction := h.newAction(\n\t\t[]string{}, press, false, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, pressAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"pressing %q on element: %w\", key, err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// Query runs \"element.querySelector\" within the page. If no element matches the selector,\n// the return value resolves to \"null\".\nfunc (h *ElementHandle) Query(selector string, strict bool) (_ *ElementHandle, rerr error) {\n\tparsedSelector, err := NewSelector(selector)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing selector %q: %w\", selector, err)\n\t}\n\n\t// Check for frame navigation in the selector\n\tframeNavIndex := h.findFrameNavigationIndex(parsedSelector)\n\tif frameNavIndex != -1 {\n\t\t// Strict is true because we assume the user is interested in the element\n\t\t// in the frame and not the frame it is in.\n\t\topts := &FrameWaitForSelectorOptions{\n\t\t\tState:   DOMElementStateAttached,\n\t\t\tTimeout: h.frame.defaultTimeout(),\n\t\t\tStrict:  true,\n\t\t}\n\n\t\tframe, afterFrameSelector, err := h.stepIntoFrame(h.ctx, parsedSelector, frameNavIndex, opts)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn frame.Query(afterFrameSelector, strict)\n\t}\n\n\t// No frame navigation - proceed with normal Query logic\n\tquerySelector := `\n\t\t(node, injected, selector, strict) => {\n\t\t\treturn injected.querySelector(selector, strict, node || document);\n\t\t}\n\t`\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: false,\n\t}\n\tresult, err := h.evalWithScript(h.ctx, opts, querySelector, parsedSelector, strict)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"querying selector %q: %w\", selector, err)\n\t}\n\tif result == nil {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\thandle, ok := result.(JSHandleAPI)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"querying selector %q, wrong type %T\", selector, result)\n\t}\n\telement := handle.AsElement()\n\tif element == nil {\n\t\tdefer func() {\n\t\t\tif err := handle.Dispose(); err != nil {\n\t\t\t\terr = fmt.Errorf(\"disposing element handle: %w\", err)\n\t\t\t\trerr = errors.Join(err, rerr)\n\t\t\t}\n\t\t}()\n\t\treturn nil, fmt.Errorf(\"querying selector %q\", selector)\n\t}\n\n\treturn element, nil\n}\n\n// QueryAll queries element subtree for matching elements.\n// If no element matches the selector, the return value resolves to \"null\".\nfunc (h *ElementHandle) QueryAll(selector string) ([]*ElementHandle, error) {\n\thandles, err := h.queryAll(selector, h.evalWithScript)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"querying all selector %q: %w\", selector, err)\n\t}\n\n\treturn handles, nil\n}\n\nfunc (h *ElementHandle) queryAll(selector string, eval evalFunc) (_ []*ElementHandle, rerr error) {\n\tparsedSelector, err := NewSelector(selector)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing selector %q: %w\", selector, err)\n\t}\n\tresult, err := eval(\n\t\th.ctx,\n\t\tevalOptions{forceCallable: true, returnByValue: false},\n\t\tjs.QueryAll,\n\t\tparsedSelector,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"querying all selectors %q: %w\", selector, err)\n\t}\n\tif result == nil {\n\t\t// it is ok to return a nil slice because it means we didn't find any elements.\n\t\treturn nil, nil\n\t}\n\n\thandles, ok := result.(JSHandleAPI)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"getting element handle for selector %q: %w\", selector, ErrJSHandleInvalid)\n\t}\n\tdefer func() {\n\t\tif err := handles.Dispose(); err != nil {\n\t\t\terr = fmt.Errorf(\"disposing element handles: %w\", err)\n\t\t\trerr = errors.Join(err, rerr)\n\t\t}\n\t}()\n\n\tprops, err := handles.GetProperties()\n\tif err != nil {\n\t\t// GetProperties has a rich error already, so we don't need to wrap it.\n\t\treturn nil, err //nolint:wrapcheck\n\t}\n\n\ttype indexedElem struct {\n\t\tindex int\n\t\telem  *ElementHandle\n\t}\n\n\tindexedElems := make([]indexedElem, 0, len(props))\n\tfor key, prop := range props {\n\t\tif el := prop.AsElement(); el != nil {\n\t\t\t// DOM elements are stored with numeric indices (\"0\", \"1\", \"2\", ...)\n\t\t\t// per JavaScript's array-like object specification.\n\t\t\tidx, err := strconv.Atoi(key)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing element index %q for selector %q: %w\", key, selector, err)\n\t\t\t}\n\t\t\tindexedElems = append(indexedElems, indexedElem{index: idx, elem: el})\n\t\t} else if err := prop.Dispose(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"disposing property while querying all selectors %q: %w\", selector, err)\n\t\t}\n\t}\n\n\tslices.SortFunc(indexedElems, func(a, b indexedElem) int {\n\t\treturn cmp.Compare(a.index, b.index)\n\t})\n\n\tels := make([]*ElementHandle, 0, len(indexedElems))\n\tfor _, ie := range indexedElems {\n\t\tels = append(els, ie.elem)\n\t}\n\n\treturn els, nil\n}\n\n// SetChecked checks or unchecks an element.\nfunc (h *ElementHandle) SetChecked(checked bool, opts *ElementHandleSetCheckedOptions) error {\n\tsetChecked := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.setChecked(apiCtx, checked, p)\n\t}\n\tsetCheckedAction := h.newPointerAction(setChecked, &opts.ElementHandleBasePointerOptions)\n\tif _, err := call(h.ctx, setCheckedAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"checking element: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// Uncheck scrolls element into view, and if it's an input element of type\n// checkbox that is already checked, clicks on it to mark it as unchecked.\nfunc (h *ElementHandle) Uncheck(opts *ElementHandleSetCheckedOptions) error {\n\treturn h.SetChecked(false, opts)\n}\n\n// Check scrolls element into view, and if it's an input element of type\n// checkbox that is unchecked, clicks on it to mark it as checked.\nfunc (h *ElementHandle) Check(opts *ElementHandleSetCheckedOptions) error {\n\treturn h.SetChecked(true, opts)\n}\n\nfunc (h *ElementHandle) setChecked(apiCtx context.Context, checked bool, p *Position) error {\n\tstate, err := h.checkElementState(apiCtx, \"checked\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tif checked == *state {\n\t\treturn nil\n\t}\n\n\terr = h.click(p, NewMouseClickOptions())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tstate, err = h.checkElementState(apiCtx, \"checked\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tif checked != *state {\n\t\treturn errors.New(\"clicking the checkbox did not change its state\")\n\t}\n\n\treturn nil\n}\n\n// Screenshot will instruct Chrome to save a screenshot of the current element and save it to specified file.\nfunc (h *ElementHandle) Screenshot(\n\topts *ElementHandleScreenshotOptions,\n\tsp ScreenshotPersister,\n) ([]byte, error) {\n\tspanCtx, span := TraceAPICall(\n\t\th.ctx,\n\t\th.frame.page.targetID.String(),\n\t\t\"elementHandle.screenshot\",\n\t)\n\tdefer span.End()\n\n\tspan.SetAttributes(attribute.String(\"screenshot.path\", opts.Path))\n\n\ts := newScreenshotter(spanCtx, sp, h.logger)\n\tbuf, err := s.screenshotElement(h, opts)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"taking screenshot of elementHandle: %w\", err)\n\t}\n\n\treturn buf, err\n}\n\n// ScrollIntoViewIfNeeded scrolls element into view if needed.\nfunc (h *ElementHandle) ScrollIntoViewIfNeeded(opts *ElementHandleBaseOptions) error {\n\terr := h.waitAndScrollIntoViewIfNeeded(h.ctx, opts.Force, opts.NoWaitAfter, opts.Timeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"scrolling element into view: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// SelectOption selects the options matching the given values.\nfunc (h *ElementHandle) SelectOption(values []any, opts *ElementHandleBaseOptions) ([]string, error) {\n\tselectOption := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.selectOption(apiCtx, values)\n\t}\n\tselectOptionAction := h.newAction(\n\t\t[]string{}, selectOption, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tselectedOptions, err := call(h.ctx, selectOptionAction, opts.Timeout)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selecting options: %w\", err)\n\t}\n\tvar returnVal []string\n\tif err := convert(selectedOptions, &returnVal); err != nil {\n\t\treturn nil, fmt.Errorf(\"unpacking selected options: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn returnVal, nil\n}\n\n// SelectText selects the text of the element.\nfunc (h *ElementHandle) SelectText(opts *ElementHandleBaseOptions) error {\n\tselectText := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.selectText(apiCtx)\n\t}\n\tselectTextAction := h.newAction(\n\t\t[]string{}, selectText, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, selectTextAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"selecting text: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// SetInputFiles sets the given files into the input file element.\nfunc (h *ElementHandle) SetInputFiles(files *Files, opts *ElementHandleSetInputFilesOptions) error {\n\tsetInputFiles := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.setInputFiles(apiCtx, files)\n\t}\n\tsetInputFilesAction := h.newAction([]string{}, setInputFiles, opts.Force, opts.NoWaitAfter, opts.Timeout)\n\tif _, err := call(h.ctx, setInputFilesAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"setting input files: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (h *ElementHandle) setInputFiles(apiCtx context.Context, files *Files) error {\n\t// allow clearing the input by passing an empty array\n\tvar payload []*File\n\tif files != nil {\n\t\tpayload = files.Payload\n\t}\n\tfn := `\n\t\t(node, injected, payload) => {\n\t\t\treturn injected.setInputFiles(node, payload);\n\t\t}\n\t`\n\tevalOpts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := h.evalWithScript(apiCtx, evalOpts, fn, payload)\n\tif err != nil {\n\t\treturn err\n\t}\n\tv, ok := result.(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type %T\", result)\n\t}\n\tif v != \"done\" {\n\t\treturn errorFromDOMError(v)\n\t}\n\n\treturn nil\n}\n\n// Tap scrolls element into view and taps in the center of the element.\nfunc (h *ElementHandle) Tap(opts *ElementHandleTapOptions) error {\n\ttap := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.tap(apiCtx, p)\n\t}\n\ttapAction := h.newPointerAction(tap, &opts.ElementHandleBasePointerOptions)\n\n\tif _, err := call(h.ctx, tapAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"tapping element: %w\", err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\nfunc (h *ElementHandle) tap(_ context.Context, p *Position) error {\n\treturn h.frame.page.Touchscreen.tap(p.X, p.Y)\n}\n\n// TextContent returns the text content of the element.\n// The second return value is true if the text content exists, and false otherwise.\nfunc (h *ElementHandle) TextContent() (string, bool, error) {\n\ttextContent := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.textContent(apiCtx)\n\t}\n\topts := NewElementHandleBaseOptions(h.DefaultTimeout())\n\ttextContentAction := h.newAction(\n\t\t[]string{}, textContent, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tv, err := call(h.ctx, textContentAction, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"getting text content of element: %w\", err)\n\t}\n\tif v == nil {\n\t\treturn \"\", false, nil\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", false, fmt.Errorf(\n\t\t\t\"getting text content of element: unexpected type %T (expecting string)\",\n\t\t\tv,\n\t\t)\n\t}\n\n\treturn s, true, nil\n}\n\n// Timeout will return the default timeout or the one set by the user.\n// It's an internal method not to be exposed as a JS API.\nfunc (h *ElementHandle) Timeout() time.Duration {\n\treturn h.DefaultTimeout()\n}\n\n// Type scrolls element into view, focuses element and types text.\nfunc (h *ElementHandle) Type(text string, opts *ElementHandleTypeOptions) error {\n\ttyp := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.typ(apiCtx, text, KeyboardOptions{})\n\t}\n\ttypeAction := h.newAction(\n\t\t[]string{}, typ, false, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(h.ctx, typeAction, opts.Timeout); err != nil {\n\t\treturn fmt.Errorf(\"typing text %q: %w\", text, err)\n\t}\n\n\tapplySlowMo(h.ctx)\n\n\treturn nil\n}\n\n// WaitForElementState waits for the element to reach the given state.\nfunc (h *ElementHandle) WaitForElementState(state string, opts *ElementHandleWaitForElementStateOptions) error {\n\t_, err := h.waitForElementState(h.ctx, []string{state}, opts.Timeout)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"waiting for element state %q: %w\", state, err)\n\t}\n\n\treturn nil\n}\n\n// WaitForSelector waits for the selector to appear in the DOM.\nfunc (h *ElementHandle) WaitForSelector(selector string, opts *FrameWaitForSelectorOptions) (*ElementHandle, error) {\n\thandle, err := h.waitForSelector(h.ctx, selector, opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"waiting for selector %q: %w\", selector, err)\n\t}\n\n\treturn handle, nil\n}\n\n// evalWithScript evaluates the given js code in the scope of this ElementHandle and returns the result.\n// The js code can call helper functions from injected_script.js.\nfunc (h *ElementHandle) evalWithScript(\n\tctx context.Context,\n\topts evalOptions, js string, args ...any,\n) (any, error) {\n\tscript, err := h.execCtx.getInjectedScript(h.ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting injected script: %w\", err)\n\t}\n\treturn h.eval(ctx, opts, js, append([]any{script}, args...)...)\n}\n\n// eval evaluates the given js code in the scope of this ElementHandle and returns the result.\nfunc (h *ElementHandle) eval(\n\tctx context.Context,\n\topts evalOptions, js string, args ...any,\n) (any, error) {\n\t// passing `h` makes it evaluate js code in the element handle's scope.\n\treturn h.execCtx.eval(ctx, opts, js, append([]any{h}, args...)...)\n}\n\nfunc (h *ElementHandle) newAction(\n\tstates []string, fn elementHandleActionFunc, force, noWaitAfter bool, timeout time.Duration,\n) func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t// All or a subset of the following actionability checks are made before performing the actual action:\n\t// 1. Attached to DOM\n\t// 2. Visible\n\t// 3. Stable\n\t// 4. Enabled\n\tactionFn := func(apiCtx context.Context) (any, error) {\n\t\t// Check if we should run actionability checks\n\t\tif !force {\n\t\t\tif _, err := h.waitForElementState(apiCtx, states, timeout); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\tb := NewBarrier()\n\t\th.frame.manager.addBarrier(b)\n\t\tdefer h.frame.manager.removeBarrier(b)\n\n\t\tres, err := fn(apiCtx, h)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// Do we need to wait for navigation to happen\n\t\tif !noWaitAfter {\n\t\t\tif err := b.Wait(apiCtx); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\n\t\treturn res, nil\n\t}\n\n\treturn func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t\tif res, err := actionFn(apiCtx); err != nil {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase errCh <- err:\n\t\t\t}\n\t\t} else {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase resultCh <- res:\n\t\t\t}\n\t\t}\n\t}\n}\n\n//nolint:gocognit,funlen\nfunc (h *ElementHandle) newPointerAction(\n\tfn elementHandlePointerActionFunc, opts *ElementHandleBasePointerOptions,\n) func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t// All or a subset of the following actionability checks are made before performing the actual action:\n\t// 1. Attached to DOM\n\t// 2. Visible\n\t// 3. Stable\n\t// 4. Enabled\n\t// 5. Receives events\n\tpointerFn := func(apiCtx context.Context, sopts *ScrollIntoViewOptions) (res any, err error) {\n\t\t// We need to scroll the element into view first, otherwise we can\n\t\t// end up in a situation where the element is not in the correct state\n\t\t// (visible and stable, but could be enabled).\n\t\terr = h.scrollRectIntoViewIfNeeded(apiCtx, nil)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"scrolling element into view: %w\", err)\n\t\t}\n\n\t\t// Check if we should run actionability checks\n\t\tif !opts.Force {\n\t\t\t// As mentioned above, if we didn't scroll first, we could end\n\t\t\t// up stuck waiting indefinitely for the element to be in the\n\t\t\t// correct state.\n\t\t\tstates := []string{\"visible\", \"stable\", \"enabled\"}\n\t\t\tif _, err = h.waitForElementState(apiCtx, states, opts.Timeout); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"waiting for element state: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// Decide position where a mouse down should happen if needed by action\n\t\tp := opts.Position\n\n\t\t// Change scrolling action depending on the scrolling options\n\t\tif sopts == nil {\n\t\t\tvar rect *dom.Rect\n\t\t\tif p != nil {\n\t\t\t\trect = &dom.Rect{X: p.X, Y: p.Y}\n\t\t\t}\n\t\t\terr = h.scrollRectIntoViewIfNeeded(apiCtx, rect)\n\t\t} else {\n\t\t\t_, err = h.eval(\n\t\t\t\tapiCtx,\n\t\t\t\tevalOptions{forceCallable: true, returnByValue: false},\n\t\t\t\tjs.ScrollIntoView,\n\t\t\t\tsopts,\n\t\t\t)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"scrolling element into view: %w\", err)\n\t\t}\n\n\t\t// Get the clickable point\n\t\tif p != nil {\n\t\t\tp, err = h.offsetPosition(apiCtx, opts.Position)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"getting element position: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tp, err = h.clickablePoint()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"pointer action: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\t// Further translation of the point might be necessary if the point\n\t\t// is still relative to the parent frame it is in and not the page.\n\t\t*p, err = h.translatePointToPage(apiCtx, *p)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"translating point to page: %w\", err)\n\t\t}\n\n\t\t// Do a final actionability check to see if element can receive events\n\t\t// at mouse position in question\n\t\tif !opts.Force {\n\t\t\tif ok, err := h.checkHitTargetAt(apiCtx, *p); !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"checking hit target: %w\", err)\n\t\t\t}\n\t\t}\n\t\t// Are we only \"trialing\" the action but not actually performing\n\t\t// it (ie. running the actionability checks).\n\t\tif opts.Trial {\n\t\t\treturn nil, nil //nolint:nilnil\n\t\t}\n\n\t\tb := NewBarrier()\n\t\th.frame.manager.addBarrier(b)\n\t\tdefer h.frame.manager.removeBarrier(b)\n\t\tif res, err = fn(apiCtx, h, p); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"evaluating pointer action: %w\", err)\n\t\t}\n\t\t// Do we need to wait for navigation to happen\n\t\tif !opts.NoWaitAfter {\n\t\t\tif err = b.Wait(apiCtx); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"waiting for navigation: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\treturn res, nil\n\t}\n\n\treturn func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t\tif res, err := retryPointerAction(apiCtx, pointerFn, opts); err != nil {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase errCh <- err:\n\t\t\t}\n\t\t} else {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase resultCh <- res:\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc retryPointerAction(\n\tapiCtx context.Context, fn retryablePointerActionFunc, opts *ElementHandleBasePointerOptions,\n) (res any, err error) {\n\tfor {\n\t\tres, err = fn(apiCtx, nil)\n\t\tif opts.Force || err == nil {\n\t\t\treturn res, err\n\t\t}\n\n\t\t// try with different scrolling options\n\t\tfor _, p := range []ScrollPosition{\n\t\t\tScrollPositionStart,\n\t\t\tScrollPositionCenter,\n\t\t\tScrollPositionEnd,\n\t\t\tScrollPositionNearest,\n\t\t} {\n\t\t\ts := ScrollIntoViewOptions{Block: p, Inline: p}\n\t\t\tif res, err = fn(apiCtx, &s); err == nil {\n\t\t\t\treturn res, nil\n\t\t\t}\n\t\t}\n\n\t\t// Only locator based APIs should retry.\n\t\tif !opts.retry {\n\t\t\treturn res, err\n\t\t}\n\n\t\tif !errors.Is(err, ErrElementNotVisible) &&\n\t\t\t!errors.Is(err, ErrElementNotAttachedToDOM) &&\n\t\t\t!strings.Contains(err.Error(), \"frame has been detached\") {\n\t\t\treturn res, err\n\t\t}\n\n\t\t// Wait with timeout or context cancellation\n\t\tselect {\n\t\tcase <-apiCtx.Done():\n\t\t\treturn nil, ContextErr(apiCtx)\n\t\tcase <-time.After(20 * time.Millisecond):\n\t\t\t// Continue retrying after delay\n\t\t}\n\t}\n}\n\nfunc errorFromDOMError(v any) error {\n\tvar (\n\t\terr  error\n\t\tserr string\n\t)\n\tswitch e := v.(type) {\n\tcase string:\n\t\tserr = e\n\tcase error:\n\t\tif e == nil {\n\t\t\treturn errors.New(\"DOM error is nil\")\n\t\t}\n\t\terr, serr = e, e.Error()\n\tdefault:\n\t\treturn fmt.Errorf(\"unexpected DOM error type %T\", v)\n\t}\n\tvar uerr *k6ext.UserFriendlyError\n\tif errors.As(err, &uerr) {\n\t\treturn err\n\t}\n\tif strings.Contains(serr, \"timed out\") {\n\t\treturn &k6ext.UserFriendlyError{\n\t\t\tErr: ErrTimedOut,\n\t\t}\n\t}\n\tif s := \"error:expectednode:\"; strings.HasPrefix(serr, s) {\n\t\treturn fmt.Errorf(\"expected node but got %s\", strings.TrimPrefix(serr, s))\n\t}\n\n\tif serr == \"error:notconnected\" {\n\t\treturn ErrElementNotAttachedToDOM\n\t}\n\n\terrs := map[string]string{\n\t\t\"error:notelement\":             \"node is not an element\",\n\t\t\"error:nothtmlelement\":         \"not an HTMLElement\",\n\t\t\"error:notfillableelement\":     \"element is not an <input>, <textarea> or [contenteditable] element\",\n\t\t\"error:notfillableinputtype\":   \"input of this type cannot be filled\",\n\t\t\"error:notfillablenumberinput\": \"cannot type text into input[type=number]\",\n\t\t\"error:notvaliddate\":           \"malformed value\",\n\t\t\"error:notinput\":               \"node is not an HTMLInputElement\",\n\t\t\"error:notfile\":                \"node is not an input[type=file] element\",\n\t\t\"error:hasnovalue\":             \"node is not an HTMLInputElement or HTMLTextAreaElement or HTMLSelectElement\",\n\t\t\"error:notselect\":              \"element is not a <select> element\",\n\t\t\"error:notcheckbox\":            \"not a checkbox or radio button\",\n\t\t\"error:notmultiplefileinput\":   \"non-multiple file input can only accept single file\",\n\t\t\"error:strictmodeviolation\":    \"strict mode violation, multiple elements returned for selector query\",\n\t\t\"error:notqueryablenode\":       \"node is not queryable\",\n\t\t\"error:nthnocapture\":           \"can't query n-th element in a chained selector with capture\",\n\t\t\"error:intercept\":              \"another element is intercepting with pointer action\",\n\t}\n\tif err, ok := errs[serr]; ok {\n\t\treturn errors.New(err)\n\t}\n\n\treturn errors.New(serr)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/element_handle_options.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/js/common\"\n)\n\ntype ElementHandleBaseOptions struct {\n\tForce       bool          `json:\"force\"`\n\tNoWaitAfter bool          `json:\"noWaitAfter\"`\n\tTimeout     time.Duration `json:\"timeout\"`\n}\n\ntype ElementHandleBasePointerOptions struct {\n\tElementHandleBaseOptions\n\tPosition *Position `json:\"position\"`\n\tTrial    bool      `json:\"trial\"`\n\n\t// We don't want to export this field. Internal use only to determine if we\n\t// should retry when using locator based APIs.\n\tretry bool\n}\n\n// ScrollPosition is a parameter for scrolling an element.\ntype ScrollPosition string\n\nconst (\n\t// ScrollPositionStart scrolls an element at the top of its parent.\n\tScrollPositionStart ScrollPosition = \"start\"\n\t// ScrollPositionCenter scrolls an element at the center of its parent.\n\tScrollPositionCenter ScrollPosition = \"center\"\n\t// ScrollPositionEnd scrolls an element at the end of its parent.\n\tScrollPositionEnd ScrollPosition = \"end\"\n\t// ScrollPositionNearest scrolls an element at the nearest position of its parent.\n\tScrollPositionNearest ScrollPosition = \"nearest\"\n)\n\nconst (\n\toptionButton     = \"button\"\n\toptionDelay      = \"delay\"\n\toptionClickCount = \"clickCount\"\n\toptionModifiers  = \"modifiers\"\n)\n\n// ScrollIntoViewOptions change the behavior of ScrollIntoView.\n// See: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView\ntype ScrollIntoViewOptions struct {\n\t// Block defines vertical alignment.\n\t// One of start, center, end, or nearest.\n\t// Defaults to start.\n\tBlock ScrollPosition `json:\"block\"`\n\n\t// Inline defines horizontal alignment.\n\t// One of start, center, end, or nearest.\n\t// Defaults to nearest.\n\tInline ScrollPosition `json:\"inline\"`\n}\n\ntype ElementHandleCheckOptions struct {\n\tElementHandleBasePointerOptions\n}\n\ntype ElementHandleClickOptions struct {\n\tElementHandleBasePointerOptions\n\tButton     string   `json:\"button\"`\n\tClickCount int64    `json:\"clickCount\"`\n\tDelay      int64    `json:\"delay\"`\n\tModifiers  []string `json:\"modifiers\"`\n}\n\ntype ElementHandleDblclickOptions struct {\n\tElementHandleBasePointerOptions\n\tButton    string   `json:\"button\"`\n\tDelay     int64    `json:\"delay\"`\n\tModifiers []string `json:\"modifiers\"`\n}\n\ntype ElementHandleHoverOptions struct {\n\tElementHandleBasePointerOptions\n\tModifiers []string `json:\"modifiers\"`\n}\n\n// File is the descriptor of a single file.\ntype File struct {\n\tName     string `json:\"name\"`\n\tMimetype string `json:\"mimeType\"`\n\tBuffer   string `json:\"buffer\"`\n}\n\n// Files is the input parameter for ElementHandle.SetInputFiles.\ntype Files struct {\n\tPayload []*File `json:\"payload\"`\n}\n\n// ElementHandleSetInputFilesOptions are options for ElementHandle.SetInputFiles.\ntype ElementHandleSetInputFilesOptions struct {\n\tElementHandleBaseOptions\n}\n\ntype ElementHandlePressOptions struct {\n\tDelay       int64         `json:\"delay\"`\n\tNoWaitAfter bool          `json:\"noWaitAfter\"`\n\tTimeout     time.Duration `json:\"timeout\"`\n}\n\ntype ElementHandleScreenshotOptions struct {\n\tPath           string        `json:\"path\"`\n\tFormat         ImageFormat   `json:\"format\"`\n\tOmitBackground bool          `json:\"omitBackground\"`\n\tQuality        int64         `json:\"quality\"`\n\tTimeout        time.Duration `json:\"timeout\"`\n}\n\ntype ElementHandleSetCheckedOptions struct {\n\tElementHandleBasePointerOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype ElementHandleTapOptions struct {\n\tElementHandleBasePointerOptions\n\tModifiers []string `json:\"modifiers\"`\n}\n\ntype ElementHandleTypeOptions struct {\n\tDelay       int64         `json:\"delay\"`\n\tNoWaitAfter bool          `json:\"noWaitAfter\"`\n\tTimeout     time.Duration `json:\"timeout\"`\n}\n\ntype ElementHandleWaitForElementStateOptions struct {\n\tTimeout time.Duration `json:\"timeout\"`\n}\n\nfunc NewElementHandleBaseOptions(defaultTimeout time.Duration) *ElementHandleBaseOptions {\n\treturn &ElementHandleBaseOptions{\n\t\tForce:       false,\n\t\tNoWaitAfter: false,\n\t\tTimeout:     defaultTimeout,\n\t}\n}\n\n// Parse parses the ElementHandleBaseOptions from the given opts.\nfunc (o *ElementHandleBaseOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\tgopts := opts.ToObject(k6ext.Runtime(ctx))\n\tfor _, k := range gopts.Keys() {\n\t\tswitch k {\n\t\tcase \"force\":\n\t\t\to.Force = gopts.Get(k).ToBoolean()\n\t\tcase \"noWaitAfter\":\n\t\t\to.NoWaitAfter = gopts.Get(k).ToBoolean()\n\t\tcase \"timeout\":\n\t\t\to.Timeout = time.Duration(gopts.Get(k).ToInteger()) * time.Millisecond\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc NewElementHandleBasePointerOptions(defaultTimeout time.Duration) *ElementHandleBasePointerOptions {\n\treturn &ElementHandleBasePointerOptions{\n\t\tElementHandleBaseOptions: *NewElementHandleBaseOptions(defaultTimeout),\n\t\tPosition:                 nil,\n\t\tTrial:                    false,\n\t}\n}\n\n// Parse parses the ElementHandleBasePointerOptions from the given opts.\nfunc (o *ElementHandleBasePointerOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif err := o.ElementHandleBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"position\":\n\t\t\t\tvar p map[string]float64\n\t\t\t\to.Position = &Position{}\n\t\t\t\tif rt.ExportTo(opts.Get(k), &p) != nil {\n\t\t\t\t\to.Position.X = p[\"x\"]\n\t\t\t\t\to.Position.Y = p[\"y\"]\n\t\t\t\t}\n\t\t\tcase \"trial\":\n\t\t\t\to.Trial = opts.Get(k).ToBoolean()\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewElementHandleCheckOptions(defaultTimeout time.Duration) *ElementHandleCheckOptions {\n\treturn &ElementHandleCheckOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the ElementHandleCheckOptions from the given opts.\nfunc (o *ElementHandleCheckOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\treturn o.ElementHandleBasePointerOptions.Parse(ctx, opts)\n}\n\n// NewElementHandleSetInputFilesOptions creates a new ElementHandleSetInputFilesOption.\nfunc NewElementHandleSetInputFilesOptions(defaultTimeout time.Duration) *ElementHandleSetInputFilesOptions {\n\treturn &ElementHandleSetInputFilesOptions{\n\t\tElementHandleBaseOptions: *NewElementHandleBaseOptions(defaultTimeout),\n\t}\n}\n\n// addFile to the struct. Input value can only be a file descriptor object.\nfunc (f *Files) addFile(ctx context.Context, file sobek.Value) error {\n\tif common.IsNullish(file) {\n\t\treturn nil\n\t}\n\trt := k6ext.Runtime(ctx)\n\tfileType := file.ExportType()\n\tswitch fileType.Kind() {\n\tcase reflect.Map: // file descriptor object\n\t\tvar parsedFile File\n\t\tif err := rt.ExportTo(file, &parsedFile); err != nil {\n\t\t\treturn fmt.Errorf(\"parsing file descriptor: %w\", err)\n\t\t}\n\t\tf.Payload = append(f.Payload, &parsedFile)\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid parameter type : %s\", fileType.Kind().String())\n\t}\n\n\treturn nil\n}\n\n// Parse parses the Files struct from the given sobek.Value.\nfunc (f *Files) Parse(ctx context.Context, files sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif common.IsNullish(files) {\n\t\treturn nil\n\t}\n\n\toptsType := files.ExportType()\n\tswitch optsType.Kind() {\n\tcase reflect.Slice: // array of filePaths or array of file descriptor objects\n\t\tgopts := files.ToObject(rt)\n\t\tfor _, k := range gopts.Keys() {\n\t\t\terr := f.addFile(ctx, gopts.Get(k))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tdefault: // filePath or file descriptor object\n\t\treturn f.addFile(ctx, files)\n\t}\n\n\treturn nil\n}\n\n// Parse parses the ElementHandleSetInputFilesOption from the given opts.\nfunc (o *ElementHandleSetInputFilesOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc NewElementHandleClickOptions(defaultTimeout time.Duration) *ElementHandleClickOptions {\n\treturn &ElementHandleClickOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tButton:                          \"left\",\n\t\tClickCount:                      1,\n\t\tDelay:                           0,\n\t\tModifiers:                       []string{},\n\t}\n}\n\n// Parse parses the ElementHandleClickOptions from the given opts.\nfunc (o *ElementHandleClickOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\n\tif common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\trt := k6ext.Runtime(ctx)\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase optionButton:\n\t\t\to.Button = obj.Get(k).String()\n\t\tcase optionClickCount:\n\t\t\to.ClickCount = obj.Get(k).ToInteger()\n\t\tcase optionDelay:\n\t\t\to.Delay = obj.Get(k).ToInteger()\n\t\tcase optionModifiers:\n\t\t\tvar m []string\n\t\t\tif err := rt.ExportTo(obj.Get(k), &m); err != nil {\n\t\t\t\treturn fmt.Errorf(\"parsing element handle click option modifiers: %w\", err)\n\t\t\t}\n\t\t\to.Modifiers = m\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *ElementHandleClickOptions) ToMouseClickOptions() *MouseClickOptions {\n\to2 := NewMouseClickOptions()\n\to2.Button = o.Button\n\to2.ClickCount = o.ClickCount\n\to2.Delay = o.Delay\n\treturn o2\n}\n\nfunc NewElementHandleDblclickOptions(defaultTimeout time.Duration) *ElementHandleDblclickOptions {\n\treturn &ElementHandleDblclickOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tButton:                          \"left\",\n\t\tDelay:                           0,\n\t\tModifiers:                       []string{},\n\t}\n}\n\n// Parse parses the ElementHandleDblclickOptions from the given opts.\nfunc (o *ElementHandleDblclickOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"button\":\n\t\t\t\to.Button = opts.Get(k).String()\n\t\t\tcase \"delay\":\n\t\t\t\to.Delay = opts.Get(k).ToInteger()\n\t\t\tcase \"modifiers\":\n\t\t\t\tvar m []string\n\t\t\t\tif err := rt.ExportTo(opts.Get(k), &m); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\to.Modifiers = m\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (o *ElementHandleDblclickOptions) ToMouseClickOptions() *MouseClickOptions {\n\to2 := NewMouseClickOptions()\n\to2.Button = o.Button\n\to2.ClickCount = 2\n\to2.Delay = o.Delay\n\treturn o2\n}\n\nfunc NewElementHandleHoverOptions(defaultTimeout time.Duration) *ElementHandleHoverOptions {\n\treturn &ElementHandleHoverOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tModifiers:                       []string{},\n\t}\n}\n\n// Parse parses the ElementHandleHoverOptions from the given opts.\nfunc (o *ElementHandleHoverOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tif k == \"modifiers\" {\n\t\t\t\tvar m []string\n\t\t\t\tif err := rt.ExportTo(opts.Get(k), &m); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\to.Modifiers = m\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewElementHandlePressOptions(defaultTimeout time.Duration) *ElementHandlePressOptions {\n\treturn &ElementHandlePressOptions{\n\t\tDelay:       0,\n\t\tNoWaitAfter: false,\n\t\tTimeout:     defaultTimeout,\n\t}\n}\n\n// Parse parses the ElementHandlePressOptions from the given opts.\nfunc (o *ElementHandlePressOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"delay\":\n\t\t\t\to.Delay = opts.Get(k).ToInteger()\n\t\t\tcase \"noWaitAfter\":\n\t\t\t\to.NoWaitAfter = opts.Get(k).ToBoolean()\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (o *ElementHandlePressOptions) ToBaseOptions() *ElementHandleBaseOptions {\n\to2 := ElementHandleBaseOptions{}\n\to2.Force = false\n\to2.NoWaitAfter = o.NoWaitAfter\n\to2.Timeout = o.Timeout\n\treturn &o2\n}\n\nfunc NewElementHandleScreenshotOptions(defaultTimeout time.Duration) *ElementHandleScreenshotOptions {\n\treturn &ElementHandleScreenshotOptions{\n\t\tPath:           \"\",\n\t\tFormat:         ImageFormatPNG,\n\t\tOmitBackground: false,\n\t\tQuality:        100,\n\t\tTimeout:        defaultTimeout,\n\t}\n}\n\n// Parse parses the ElementHandleScreenshotOptions from the given opts.\nfunc (o *ElementHandleScreenshotOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\trt := k6ext.Runtime(ctx)\n\tformatSpecified := false\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"omitBackground\":\n\t\t\to.OmitBackground = obj.Get(k).ToBoolean()\n\t\tcase \"path\":\n\t\t\to.Path = obj.Get(k).String()\n\t\tcase \"quality\":\n\t\t\to.Quality = obj.Get(k).ToInteger()\n\t\tcase \"type\":\n\t\t\tif f, ok := imageFormatToID[obj.Get(k).String()]; ok {\n\t\t\t\to.Format = f\n\t\t\t\tformatSpecified = true\n\t\t\t}\n\t\tcase \"timeout\":\n\t\t\to.Timeout = time.Duration(obj.Get(k).ToInteger()) * time.Millisecond\n\t\t}\n\t}\n\n\t// Infer file format by path if format not explicitly specified (default is PNG)\n\tif o.Path != \"\" && !formatSpecified {\n\t\tif strings.HasSuffix(o.Path, \".jpg\") || strings.HasSuffix(o.Path, \".jpeg\") {\n\t\t\to.Format = ImageFormatJPEG\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc NewElementHandleSetCheckedOptions(defaultTimeout time.Duration) *ElementHandleSetCheckedOptions {\n\treturn &ElementHandleSetCheckedOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tStrict:                          false,\n\t}\n}\n\n// Parse parses the ElementHandleSetCheckedOptions from the given opts.\nfunc (o *ElementHandleSetCheckedOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tif k == \"strict\" {\n\t\t\t\to.Strict = opts.Get(k).ToBoolean()\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewElementHandleTapOptions(defaultTimeout time.Duration) *ElementHandleTapOptions {\n\treturn &ElementHandleTapOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tModifiers:                       []string{},\n\t}\n}\n\n// Parse parses the ElementHandleTapOptions from the given opts.\nfunc (o *ElementHandleTapOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tif k == \"modifiers\" {\n\t\t\t\tvar m []string\n\t\t\t\tif err := rt.ExportTo(opts.Get(k), &m); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\to.Modifiers = m\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewElementHandleTypeOptions(defaultTimeout time.Duration) *ElementHandleTypeOptions {\n\treturn &ElementHandleTypeOptions{\n\t\tDelay:       0,\n\t\tNoWaitAfter: false,\n\t\tTimeout:     defaultTimeout,\n\t}\n}\n\n// Parse parses the ElementHandleTypeOptions from the given opts.\nfunc (o *ElementHandleTypeOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"delay\":\n\t\t\t\to.Delay = opts.Get(k).ToInteger()\n\t\t\tcase \"noWaitAfter\":\n\t\t\t\to.NoWaitAfter = opts.Get(k).ToBoolean()\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (o *ElementHandleTypeOptions) ToBaseOptions() *ElementHandleBaseOptions {\n\to2 := ElementHandleBaseOptions{}\n\to2.Force = false\n\to2.NoWaitAfter = o.NoWaitAfter\n\to2.Timeout = o.Timeout\n\treturn &o2\n}\n\nfunc NewElementHandleWaitForElementStateOptions(defaultTimeout time.Duration) *ElementHandleWaitForElementStateOptions {\n\treturn &ElementHandleWaitForElementStateOptions{\n\t\tTimeout: defaultTimeout,\n\t}\n}\n\n// Parse parses the ElementHandleWaitForElementStateOptions from the given opts.\nfunc (o *ElementHandleWaitForElementStateOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tif k == \"timeout\" {\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// ElementHandleDispatchEventOptions are options for ElementHandle.dispatchEvent.\ntype ElementHandleDispatchEventOptions struct {\n\t*ElementHandleBaseOptions\n}\n\n// NewElementHandleDispatchEventOptions returns a new ElementHandleDispatchEventOptions.\nfunc NewElementHandleDispatchEventOptions(defaultTimeout time.Duration) *ElementHandleDispatchEventOptions {\n\treturn &ElementHandleDispatchEventOptions{\n\t\tElementHandleBaseOptions: NewElementHandleBaseOptions(defaultTimeout),\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/element_handle_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common/js\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestErrorFromDOMError(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []struct {\n\t\tin       string\n\t\tsentinel bool // if it returns the same error value\n\t\twant     error\n\t}{\n\t\t{in: \"timed out\", want: ErrTimedOut, sentinel: true},\n\t\t{in: \"error:notconnected\", want: ErrElementNotAttachedToDOM},\n\t\t{in: \"error:expectednode:anything\", want: errors.New(\"expected node but got anything\")},\n\t\t{in: \"nonexistent error\", want: errors.New(\"nonexistent error\")},\n\t} {\n\t\tgot := errorFromDOMError(tc.in)\n\t\tif tc.sentinel && !errors.Is(got, tc.want) {\n\t\t\tassert.Failf(t, \"not sentinel\", \"error value of %q should be sentinel\", tc.in)\n\t\t} else {\n\t\t\trequire.Error(t, got)\n\t\t\tassert.EqualError(t, tc.want, got.Error())\n\t\t}\n\t}\n}\n\nfunc TestQueryAll(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\tnilHandle    = func() *ElementHandle { return nil }\n\t\tnonNilHandle = func() *ElementHandle { return &ElementHandle{} }\n\t)\n\n\tfor name, tt := range map[string]struct {\n\t\tselector                      string\n\t\treturnHandle                  func() any\n\t\treturnErr                     error\n\t\twantErr                       bool\n\t\twantHandles, wantDisposeCalls int\n\t}{\n\t\t\"invalid_selector\": {\n\t\t\tselector:     \"*=*>>*=*\",\n\t\t\treturnHandle: func() any { return nil },\n\t\t\treturnErr:    errors.New(\"any\"),\n\t\t\twantErr:      true,\n\t\t},\n\t\t\"cannot_evaluate\": {\n\t\t\tselector:     \"*\",\n\t\t\treturnHandle: func() any { return nil },\n\t\t\treturnErr:    errors.New(\"any\"),\n\t\t\twantErr:      true,\n\t\t},\n\t\t\"nil_handles_no_err\": {\n\t\t\tselector:     \"*\",\n\t\t\treturnHandle: func() any { return nil },\n\t\t\treturnErr:    nil,\n\t\t\twantErr:      false,\n\t\t},\n\t\t\"invalid_js_handle\": {\n\t\t\tselector:     \"*\",\n\t\t\treturnHandle: func() any { return \"an invalid handle\" },\n\t\t\twantErr:      true,\n\t\t},\n\t\t\"disposes_main_handle\": {\n\t\t\tselector:         \"*\",\n\t\t\treturnHandle:     func() any { return &jsHandleStub{} },\n\t\t\twantDisposeCalls: 1,\n\t\t},\n\t\t// disposes the main handle and all its nil children\n\t\t\"disposes_handles\": {\n\t\t\tselector: \"*\",\n\t\t\treturnHandle: func() any {\n\t\t\t\thandles := &jsHandleStub{\n\t\t\t\t\tasElementFn: nilHandle,\n\t\t\t\t}\n\t\t\t\thandles.getPropertiesFn = func() (map[string]JSHandleAPI, error) {\n\t\t\t\t\treturn map[string]JSHandleAPI{\n\t\t\t\t\t\t\"1\": handles,\n\t\t\t\t\t\t\"2\": handles,\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\n\t\t\t\treturn handles\n\t\t\t},\n\t\t\twantDisposeCalls: 3,\n\t\t},\n\t\t// only returns non-nil handles\n\t\t\"returns_elems\": {\n\t\t\tselector: \"*\",\n\t\t\treturnHandle: func() any {\n\t\t\t\tchildHandles := map[string]JSHandleAPI{\n\t\t\t\t\t\"1\": &jsHandleStub{asElementFn: nonNilHandle},\n\t\t\t\t\t\"2\": &jsHandleStub{asElementFn: nonNilHandle},\n\t\t\t\t\t\"3\": &jsHandleStub{asElementFn: nilHandle},\n\t\t\t\t}\n\t\t\t\treturn &jsHandleStub{\n\t\t\t\t\tgetPropertiesFn: func() (map[string]JSHandleAPI, error) {\n\t\t\t\t\t\treturn childHandles, nil\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantHandles: 2,\n\t\t},\n\t\t\"returns_err\": {\n\t\t\tselector: \"*\",\n\t\t\treturnHandle: func() any {\n\t\t\t\treturn &jsHandleStub{\n\t\t\t\t\tgetPropertiesFn: func() (map[string]JSHandleAPI, error) {\n\t\t\t\t\t\treturn nil, errors.New(\"any error\")\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t\twantHandles: 0,\n\t\t\twantErr:     true,\n\t\t},\n\t} {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar (\n\t\t\t\treturnHandle = tt.returnHandle()\n\t\t\t\tevalFunc     = func(_ context.Context, _ evalOptions, _ string, _ ...any) (any, error) {\n\t\t\t\t\treturn returnHandle, tt.returnErr\n\t\t\t\t}\n\t\t\t)\n\n\t\t\thandles, err := (&ElementHandle{}).queryAll(tt.selector, evalFunc)\n\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Nil(t, handles)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t\tassert.Len(t, handles, tt.wantHandles)\n\n\t\t\tif want := tt.wantDisposeCalls; want > 0 {\n\t\t\t\tstub, ok := returnHandle.(*jsHandleStub)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\tassert.Equal(t, want, stub.disposeCalls)\n\t\t\t}\n\t\t})\n\t}\n\n\tt.Run(\"return_in_document_order\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst numElements = 11\n\t\telems := make([]*ElementHandle, numElements)\n\t\tfor i := range numElements {\n\t\t\telems[i] = &ElementHandle{}\n\t\t}\n\t\tjsHandleAPI := func(elem *ElementHandle) JSHandleAPI {\n\t\t\treturn &jsHandleStub{asElementFn: func() *ElementHandle { return elem }}\n\t\t}\n\n\t\thandles := map[string]JSHandleAPI{\n\t\t\t// numeric keys\n\t\t\t\"0\":  jsHandleAPI(elems[0]),\n\t\t\t\"1\":  jsHandleAPI(elems[1]),\n\t\t\t\"2\":  jsHandleAPI(elems[2]),\n\t\t\t\"3\":  jsHandleAPI(elems[3]),\n\t\t\t\"4\":  jsHandleAPI(elems[4]),\n\t\t\t\"5\":  jsHandleAPI(elems[5]),\n\t\t\t\"6\":  jsHandleAPI(elems[6]),\n\t\t\t\"7\":  jsHandleAPI(elems[7]),\n\t\t\t\"8\":  jsHandleAPI(elems[8]),\n\t\t\t\"9\":  jsHandleAPI(elems[9]),\n\t\t\t\"10\": jsHandleAPI(elems[10]),\n\t\t\t// non-numeric keys that should be filtered out\n\t\t\t\"length\":  &jsHandleStub{asElementFn: nilHandle},\n\t\t\t\"forEach\": &jsHandleStub{asElementFn: nilHandle},\n\t\t\t\"item\":    &jsHandleStub{asElementFn: nilHandle},\n\t\t}\n\n\t\tevalFunc := func(_ context.Context, _ evalOptions, _ string, _ ...any) (any, error) {\n\t\t\treturn &jsHandleStub{\n\t\t\t\tgetPropertiesFn: func() (map[string]JSHandleAPI, error) {\n\t\t\t\t\treturn handles, nil\n\t\t\t\t},\n\t\t\t}, nil\n\t\t}\n\n\t\tresults, err := (&ElementHandle{}).queryAll(\"*\", evalFunc)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, results, numElements)\n\t\tassert.True(t, slices.Equal(elems, results), \"elements must be sorted in document order\")\n\t})\n\n\tt.Run(\"eval_call\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst selector = \"body\"\n\n\t\t_, _ = (&ElementHandle{}).queryAll(\n\t\t\tselector,\n\t\t\tfunc(_ context.Context, opts evalOptions, jsFunc string, args ...any) (any, error) {\n\t\t\t\tassert.Equal(t, js.QueryAll, jsFunc)\n\n\t\t\t\tassert.Equal(t, true, opts.forceCallable)\n\t\t\t\tassert.Equal(t, false, opts.returnByValue)\n\n\t\t\t\tassert.NotEmpty(t, args)\n\t\t\t\tassert.IsType(t, args[0], &Selector{})\n\t\t\t\tsel, ok := args[0].(*Selector)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\tassert.Equal(t, selector, sel.Selector)\n\n\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t},\n\t\t)\n\t})\n}\n\ntype jsHandleStub struct {\n\tJSHandleAPI\n\n\tdisposeCalls int\n\n\tasElementFn     func() *ElementHandle\n\tgetPropertiesFn func() (map[string]JSHandleAPI, error)\n}\n\nfunc (s *jsHandleStub) AsElement() *ElementHandle {\n\tif s.asElementFn == nil {\n\t\treturn nil\n\t}\n\treturn s.asElementFn()\n}\n\nfunc (s *jsHandleStub) Dispose() error {\n\ts.disposeCalls++\n\treturn nil\n}\n\nfunc (s *jsHandleStub) GetProperties() (map[string]JSHandleAPI, error) {\n\tif s.getPropertiesFn == nil {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\treturn s.getPropertiesFn()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/errors.go",
    "content": "package common\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// Error is a common package error.\ntype Error string\n\n// Error satisfies the builtin error interface.\nfunc (e Error) Error() string {\n\treturn string(e)\n}\n\n// Error types.\nconst (\n\tErrUnexpectedRemoteObjectWithID Error = \"cannot extract value when remote object ID is given\"\n\tErrChannelClosed                Error = \"channel closed\"\n\tErrFrameDetached                Error = \"frame detached\"\n\tErrJSHandleDisposed             Error = \"JS handle is disposed\"\n\tErrJSHandleInvalid              Error = \"JS handle is invalid\"\n\tErrTargetCrashed                Error = \"Target has crashed\"\n\tErrTimedOut                     Error = \"timed out\"\n\tErrWrongExecutionContext        Error = \"JS handles can be evaluated only in the context they were created\"\n)\n\ntype BigIntParseError struct {\n\terr error\n}\n\n// Error satisfies the builtin error interface.\nfunc (e BigIntParseError) Error() string {\n\treturn fmt.Sprintf(\"parsing bigint: %v\", e.err)\n}\n\n// Is satisfies the builtin error Is interface.\nfunc (e BigIntParseError) Is(target error) bool {\n\t_, ok := target.(BigIntParseError)\n\treturn ok\n}\n\n// Unwrap satisfies the builtin error Unwrap interface.\nfunc (e BigIntParseError) Unwrap() error {\n\treturn e.err\n}\n\ntype UnserializableValueError struct {\n\tUnserializableValue runtime.UnserializableValue\n}\n\n// Error satisfies the builtin error interface.\nfunc (e UnserializableValueError) Error() string {\n\treturn fmt.Sprintf(\"unsupported unserializable value: %s\", e.UnserializableValue)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/event_emitter.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"sync\"\n)\n\nconst (\n\t// Browser\n\n\tEventBrowserDisconnected string = \"disconnected\"\n\n\t// BrowserContext\n\n\tEventBrowserContextPage string = \"page\"\n\n\t// Connection\n\n\tEventConnectionClose string = \"close\"\n\n\t// Frame\n\n\tEventFrameNavigation   string = \"navigation\"\n\tEventFrameAddLifecycle string = \"addlifecycle\"\n)\n\n// Event as emitted by an EventEmiter.\ntype Event struct {\n\ttyp  string\n\tdata any\n}\n\n// NavigationEvent is emitted when we receive a Page.frameNavigated or\n// Page.navigatedWithinDocument CDP event.\n// See:\n// - https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-frameNavigated\n// - https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-navigatedWithinDocument\ntype NavigationEvent struct {\n\tnewDocument *DocumentInfo\n\turl         string\n\tname        string\n\terr         error\n}\n\ntype queue struct {\n\twriteMutex sync.Mutex\n\twrite      []Event\n\treadMutex  sync.Mutex\n\tread       []Event\n}\n\ntype eventHandler struct {\n\tctx   context.Context\n\tch    chan Event\n\tqueue *queue\n}\n\n// EventEmitter that all event emitters need to implement.\ntype EventEmitter interface {\n\temit(event string, data any)\n\ton(ctx context.Context, events []string, ch chan Event)\n\tonAll(ctx context.Context, ch chan Event)\n}\n\n// syncFunc functions are passed through the syncCh for synchronously handling\n// eventHandler requests.\ntype syncFunc func() (done chan struct{})\n\n// BaseEventEmitter emits events to registered handlers.\ntype BaseEventEmitter struct {\n\thandlers    map[string][]*eventHandler\n\thandlersAll []*eventHandler\n\n\tqueues map[chan Event]*queue\n\n\tsyncCh chan syncFunc\n\tctx    context.Context\n}\n\n// NewBaseEventEmitter creates a new instance of a base event emitter.\nfunc NewBaseEventEmitter(ctx context.Context) BaseEventEmitter {\n\tbem := BaseEventEmitter{\n\t\thandlers: make(map[string][]*eventHandler),\n\t\tsyncCh:   make(chan syncFunc),\n\t\tctx:      ctx,\n\t\tqueues:   make(map[chan Event]*queue),\n\t}\n\tgo bem.syncAll(ctx)\n\treturn bem\n}\n\n// syncAll receives work requests from BaseEventEmitter methods\n// and processes them one at a time for synchronization.\n//\n// It returns when the BaseEventEmitter context is done.\nfunc (e *BaseEventEmitter) syncAll(ctx context.Context) {\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\tcase fn := <-e.syncCh:\n\t\t\t// run the function and signal when it's done\n\t\t\tdone := fn()\n\t\t\tdone <- struct{}{}\n\t\t}\n\t}\n}\n\n// sync is a helper for sychronized access to the BaseEventEmitter.\nfunc (e *BaseEventEmitter) sync(fn func()) {\n\tdone := make(chan struct{})\n\tselect {\n\tcase <-e.ctx.Done():\n\t\treturn\n\tcase e.syncCh <- func() chan struct{} {\n\t\tfn()\n\t\treturn done\n\t}:\n\t}\n\t// wait for the function to return\n\t<-done\n}\n\nfunc (e *BaseEventEmitter) emit(event string, data any) {\n\temitEvent := func(eh *eventHandler) {\n\t\teh.queue.readMutex.Lock()\n\t\tdefer eh.queue.readMutex.Unlock()\n\n\t\t// We try to read from the read queue (queue.read).\n\t\t// If there isn't anything on the read queue, then there must\n\t\t// be something being populated by the synched emitTo\n\t\t// func below.\n\t\t// Swap around the read queue with the write queue.\n\t\t// Queue is now being populated again by emitTo, and all\n\t\t// emitEvent goroutines can continue to consume from\n\t\t// the read queue until that is again depleted.\n\t\tif len(eh.queue.read) == 0 {\n\t\t\teh.queue.writeMutex.Lock()\n\t\t\t// Clear the read slice before swapping to prevent keeping references\n\t\t\teh.queue.read = make([]Event, 0)\n\t\t\teh.queue.read, eh.queue.write = eh.queue.write, eh.queue.read\n\t\t\teh.queue.writeMutex.Unlock()\n\t\t}\n\n\t\tselect {\n\t\tcase eh.ch <- eh.queue.read[0]:\n\t\t\teh.queue.read[0] = Event{}\n\t\t\teh.queue.read = eh.queue.read[1:]\n\t\tcase <-eh.ctx.Done():\n\t\t\t// TODO: handle the error\n\t\t}\n\t}\n\temitTo := func(handlers []*eventHandler) (updated []*eventHandler) {\n\t\tfor i := 0; i < len(handlers); {\n\t\t\thandler := handlers[i]\n\t\t\tselect {\n\t\t\tcase <-handler.ctx.Done():\n\t\t\t\thandlers = append(handlers[:i], handlers[i+1:]...)\n\t\t\t\tcontinue\n\t\t\tdefault:\n\t\t\t\thandler.queue.writeMutex.Lock()\n\t\t\t\thandler.queue.write = append(handler.queue.write, Event{typ: event, data: data})\n\t\t\t\thandler.queue.writeMutex.Unlock()\n\n\t\t\t\tgo emitEvent(handler)\n\t\t\t\ti++\n\t\t\t}\n\t\t}\n\t\treturn handlers\n\t}\n\te.sync(func() {\n\t\te.handlers[event] = emitTo(e.handlers[event])\n\t\te.handlersAll = emitTo(e.handlersAll)\n\t})\n}\n\n// On registers a handler for a specific event.\nfunc (e *BaseEventEmitter) on(ctx context.Context, events []string, ch chan Event) {\n\te.sync(func() {\n\t\tq, ok := e.queues[ch]\n\t\tif !ok {\n\t\t\tq = &queue{}\n\t\t\te.queues[ch] = q\n\t\t}\n\n\t\tfor _, event := range events {\n\t\t\te.handlers[event] = append(e.handlers[event], &eventHandler{ctx: ctx, ch: ch, queue: q})\n\t\t}\n\t})\n}\n\n// OnAll registers a handler for all events.\nfunc (e *BaseEventEmitter) onAll(ctx context.Context, ch chan Event) {\n\te.sync(func() {\n\t\tq, ok := e.queues[ch]\n\t\tif !ok {\n\t\t\tq = &queue{}\n\t\t\te.queues[ch] = q\n\t\t}\n\n\t\te.handlersAll = append(e.handlersAll, &eventHandler{ctx: ctx, ch: ch, queue: q})\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/event_emitter_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEventEmitterSpecificEvent(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"add event handler\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tch := make(chan Event)\n\n\t\temitter.on(ctx, []string{cdproto.EventTargetTargetCreated}, ch)\n\t\temitter.sync(func() {\n\t\t\trequire.Len(t, emitter.handlers, 1)\n\t\t\trequire.Contains(t, emitter.handlers, cdproto.EventTargetTargetCreated)\n\t\t\trequire.Len(t, emitter.handlers[cdproto.EventTargetTargetCreated], 1)\n\t\t\trequire.Equal(t, ch, emitter.handlers[cdproto.EventTargetTargetCreated][0].ch)\n\t\t\trequire.Empty(t, emitter.handlersAll)\n\t\t})\n\t})\n\n\tt.Run(\"remove event handler\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\tcancelCtx, cancelFn := context.WithCancel(ctx)\n\t\temitter := NewBaseEventEmitter(cancelCtx)\n\t\tch := make(chan Event)\n\n\t\temitter.on(cancelCtx, []string{cdproto.EventTargetTargetCreated}, ch)\n\t\tcancelFn()\n\t\temitter.emit(cdproto.EventTargetTargetCreated, nil) // Event handlers are removed as part of event emission\n\n\t\temitter.sync(func() {\n\t\t\trequire.Contains(t, emitter.handlers, cdproto.EventTargetTargetCreated)\n\t\t\trequire.Len(t, emitter.handlers[cdproto.EventTargetTargetCreated], 0)\n\t\t})\n\t})\n\n\tt.Run(\"emit event\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tch := make(chan Event, 1)\n\n\t\temitter.on(ctx, []string{cdproto.EventTargetTargetCreated}, ch)\n\t\temitter.emit(cdproto.EventTargetTargetCreated, \"hello world\")\n\t\tmsg := <-ch\n\n\t\temitter.sync(func() {\n\t\t\trequire.Equal(t, cdproto.EventTargetTargetCreated, msg.typ)\n\t\t\trequire.Equal(t, \"hello world\", msg.data)\n\t\t})\n\t})\n}\n\nfunc TestEventEmitterAllEvents(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"add catch-all event handler\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tch := make(chan Event)\n\n\t\temitter.onAll(ctx, ch)\n\n\t\temitter.sync(func() {\n\t\t\trequire.Len(t, emitter.handlersAll, 1)\n\t\t\trequire.Equal(t, ch, emitter.handlersAll[0].ch)\n\t\t\trequire.Empty(t, emitter.handlers)\n\t\t})\n\t})\n\n\tt.Run(\"remove catch-all event handler\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tcancelCtx, cancelFn := context.WithCancel(ctx)\n\t\tch := make(chan Event)\n\n\t\temitter.onAll(cancelCtx, ch)\n\t\tcancelFn()\n\t\temitter.emit(cdproto.EventTargetTargetCreated, nil) // Event handlers are removed as part of event emission\n\n\t\temitter.sync(func() {\n\t\t\trequire.Len(t, emitter.handlersAll, 0)\n\t\t})\n\t})\n\n\tt.Run(\"emit event\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tch := make(chan Event, 1)\n\n\t\temitter.onAll(ctx, ch)\n\t\temitter.emit(cdproto.EventTargetTargetCreated, \"hello world\")\n\t\tmsg := <-ch\n\n\t\temitter.sync(func() {\n\t\t\trequire.Equal(t, cdproto.EventTargetTargetCreated, msg.typ)\n\t\t\trequire.Equal(t, \"hello world\", msg.data)\n\t\t})\n\t})\n}\n\nfunc TestBaseEventEmitter(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"order of emitted events kept\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Test description\n\t\t//\n\t\t// 1. Emit many events from the emitWorker.\n\t\t// 2. Handler receives the emitted events.\n\t\t//\n\t\t// Success criteria: Ensure that the ordering of events is\n\t\t//                   received in the order they're emitted.\n\n\t\teventName := \"AtomicIntEvent\"\n\t\tmaxInt := 100\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tch := make(chan Event)\n\t\temitter.on(ctx, []string{eventName}, ch)\n\n\t\tvar expectedI int\n\t\thandler := func() {\n\t\t\tdefer cancel()\n\n\t\t\tfor expectedI != maxInt {\n\t\t\t\te := <-ch\n\n\t\t\t\ti, ok := e.data.(int)\n\t\t\t\tif !ok {\n\t\t\t\t\tassert.FailNow(t, \"unexpected type read from channel\", e.data)\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(t, eventName, e.typ)\n\t\t\t\tassert.Equal(t, expectedI, i)\n\n\t\t\t\texpectedI++\n\t\t\t}\n\n\t\t\tclose(ch)\n\t\t}\n\t\tgo handler()\n\n\t\temitWorker := func() {\n\t\t\tfor i := range maxInt {\n\t\t\t\temitter.emit(eventName, i)\n\t\t\t}\n\t\t}\n\t\tgo emitWorker()\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\tcase <-time.After(time.Second * 2):\n\t\t\tassert.FailNow(t, \"test timed out, deadlock?\")\n\t\t}\n\t})\n\n\tt.Run(\"order of emitted different event types kept\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Test description\n\t\t//\n\t\t// 1. Emit many different event types from the emitWorker.\n\t\t// 2. Handler receives the emitted events.\n\t\t//\n\t\t// Success criteria: Ensure that the ordering of events is\n\t\t//                   received in the order they're emitted.\n\n\t\teventName1 := \"AtomicIntEvent1\"\n\t\teventName2 := \"AtomicIntEvent2\"\n\t\teventName3 := \"AtomicIntEvent3\"\n\t\teventName4 := \"AtomicIntEvent4\"\n\t\tmaxInt := 100\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tch := make(chan Event)\n\t\t// Calling on twice to ensure that the same queue is used\n\t\t// internally for the same channel and handler.\n\t\temitter.on(ctx, []string{eventName1, eventName2}, ch)\n\t\temitter.on(ctx, []string{eventName3, eventName4}, ch)\n\n\t\tvar expectedI int\n\t\thandler := func() {\n\t\t\tdefer cancel()\n\n\t\t\tfor expectedI != maxInt {\n\t\t\t\te := <-ch\n\n\t\t\t\ti, ok := e.data.(int)\n\t\t\t\tif !ok {\n\t\t\t\t\tassert.FailNow(t, \"unexpected type read from channel\", e.data)\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(t, expectedI, i)\n\n\t\t\t\texpectedI++\n\t\t\t}\n\n\t\t\tclose(ch)\n\t\t}\n\t\tgo handler()\n\n\t\temitWorker := func() {\n\t\t\tfor i := 0; i < maxInt; i += 4 {\n\t\t\t\temitter.emit(eventName1, i)\n\t\t\t\temitter.emit(eventName2, i+1)\n\t\t\t\temitter.emit(eventName3, i+2)\n\t\t\t\temitter.emit(eventName4, i+3)\n\t\t\t}\n\t\t}\n\t\tgo emitWorker()\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\tcase <-time.After(time.Second * 2):\n\t\t\tassert.FailNow(t, \"test timed out, deadlock?\")\n\t\t}\n\t})\n\n\tt.Run(\"handler can emit without deadlocking\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Test description\n\t\t//\n\t\t// 1. Emit many events from the emitWorker.\n\t\t// 2. Handler receives emitted events (AtomicIntEvent1).\n\t\t// 3. Handler emits event as AtomicIntEvent2.\n\t\t// 4. Handler received emitted events again (AtomicIntEvent2).\n\t\t//\n\t\t// Success criteria: No deadlock should occur between receiving,\n\t\t//                   emitting, and receiving of events.\n\n\t\teventName1 := \"AtomicIntEvent1\"\n\t\teventName2 := \"AtomicIntEvent2\"\n\t\tmaxInt := 100\n\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\temitter := NewBaseEventEmitter(ctx)\n\t\tch := make(chan Event)\n\t\temitter.on(ctx, []string{eventName1, eventName2}, ch)\n\n\t\tvar expectedI2 int\n\t\thandler := func() {\n\t\t\tdefer cancel()\n\n\t\t\tfor expectedI2 != maxInt {\n\t\t\t\te := <-ch\n\n\t\t\t\tswitch e.typ {\n\t\t\t\tcase eventName1:\n\t\t\t\t\ti, ok := e.data.(int)\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tassert.FailNow(t, \"unexpected type read from channel\", e.data)\n\t\t\t\t\t}\n\t\t\t\t\temitter.emit(eventName2, i)\n\t\t\t\tcase eventName2:\n\t\t\t\t\texpectedI2++\n\t\t\t\tdefault:\n\t\t\t\t\tassert.FailNow(t, \"unexpected event type received\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tclose(ch)\n\t\t}\n\t\tgo handler()\n\n\t\temitWorker := func() {\n\t\t\tfor i := range maxInt {\n\t\t\t\temitter.emit(eventName1, i)\n\t\t\t}\n\t\t}\n\t\tgo emitWorker()\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\tcase <-time.After(time.Second * 2):\n\t\t\tassert.FailNow(t, \"test timed out, deadlock?\")\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/execution_context.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/chromedp/cdproto/target\"\n)\n\nconst evaluationScriptURL = \"__xk6_browser_evaluation_script__\"\n\n// This error code originates from chromium.\nconst devToolsServerErrorCode = -32000\n\ntype executionWorld string\n\nconst (\n\tmainWorld    executionWorld = \"main\"\n\tutilityWorld executionWorld = \"utility\"\n)\n\nfunc (ew executionWorld) valid() bool {\n\treturn ew == mainWorld || ew == utilityWorld\n}\n\ntype evalOptions struct {\n\tforceCallable, returnByValue bool\n}\n\nfunc (ea evalOptions) String() string {\n\treturn fmt.Sprintf(\"forceCallable:%t returnByValue:%t\", ea.forceCallable, ea.returnByValue)\n}\n\n// ExecutionContext represents a JS execution context.\ntype ExecutionContext struct {\n\tctx            context.Context\n\tlogger         *log.Logger\n\tsession        session\n\tframe          *Frame\n\tid             runtime.ExecutionContextID\n\tisMutex        sync.RWMutex\n\tinjectedScript JSHandleAPI\n\n\t// Used for logging\n\tsid  target.SessionID // Session ID\n\tstid cdp.FrameID      // Session TargetID\n\tfid  cdp.FrameID      // Frame ID\n\tfurl string           // Frame URL\n}\n\n// NewExecutionContext creates a new JS execution context.\nfunc NewExecutionContext(\n\tctx context.Context, s session, f *Frame, id runtime.ExecutionContextID, l *log.Logger,\n) *ExecutionContext {\n\te := &ExecutionContext{\n\t\tctx:            ctx,\n\t\tsession:        s,\n\t\tframe:          f,\n\t\tid:             id,\n\t\tinjectedScript: nil,\n\t\tlogger:         l,\n\t}\n\tif s != nil {\n\t\te.sid = s.ID()\n\t\te.stid = cdp.FrameID(s.TargetID())\n\t}\n\tif f != nil {\n\t\te.fid = cdp.FrameID(f.ID())\n\t\te.furl = f.URL()\n\t}\n\tl.Debugf(\n\t\t\"NewExecutionContext\",\n\t\t\"sid:%s stid:%s fid:%s ectxid:%d furl:%q\",\n\t\te.sid, e.stid, e.fid, id, e.furl)\n\n\treturn e\n}\n\n// Adopts specified backend node into this execution context from another execution context.\nfunc (e *ExecutionContext) adoptBackendNodeID(backendNodeID cdp.BackendNodeID) (*ElementHandle, error) {\n\te.logger.Debugf(\n\t\t\"ExecutionContext:adoptBackendNodeID\",\n\t\t\"sid:%s stid:%s fid:%s ectxid:%d furl:%q bnid:%d\",\n\t\te.sid, e.stid, e.fid, e.id, e.furl, backendNodeID)\n\n\tvar (\n\t\tremoteObj *runtime.RemoteObject\n\t\terr       error\n\t)\n\n\taction := dom.ResolveNode().\n\t\tWithBackendNodeID(backendNodeID).\n\t\tWithExecutionContextID(e.id)\n\n\tif remoteObj, err = action.Do(cdp.WithExecutor(e.ctx, e.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"resolving DOM node: %w\", err)\n\t}\n\n\t// This can occur due to race conditions between trying to click on an element\n\t// and chrome moving on (e.g. navigating).\n\tif remoteObj == nil {\n\t\treturn nil, fmt.Errorf(`the page may have navigated away or the element is\n\t\t\tnow missing. It might happen when k6 and/or Chrome are overloaded. You\n\t\t\tmight need to increase the compute resources`)\n\t}\n\n\treturn NewJSHandle(e.ctx, e.session, e, e.frame, remoteObj, e.logger).AsElement(), nil\n}\n\n// Adopts the specified element handle into this execution context from another execution context.\nfunc (e *ExecutionContext) adoptElementHandle(eh *ElementHandle) (*ElementHandle, error) {\n\tvar (\n\t\tefid cdp.FrameID\n\t\tesid target.SessionID\n\t)\n\tif eh.frame != nil {\n\t\tefid = cdp.FrameID(eh.frame.ID())\n\t}\n\tif eh.session != nil {\n\t\tesid = eh.session.ID()\n\t}\n\te.logger.Debugf(\n\t\t\"ExecutionContext:adoptElementHandle\",\n\t\t\"sid:%s stid:%s fid:%s ectxid:%d furl:%q ehtid:%s ehsid:%s\",\n\t\te.sid, e.stid, e.fid, e.id, e.furl,\n\t\tefid, esid)\n\n\tif eh.execCtx == e {\n\t\treturn nil, errors.New(\"already belongs to the same execution context\")\n\t}\n\tif e.frame == nil {\n\t\treturn nil, errors.New(\"does not have a frame owner\")\n\t}\n\n\tvar node *cdp.Node\n\tvar err error\n\n\taction := dom.DescribeNode().WithObjectID(eh.remoteObject.ObjectID)\n\tif node, err = action.Do(cdp.WithExecutor(e.ctx, e.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"describing DOM node: %w\", err)\n\t}\n\n\treturn e.adoptBackendNodeID(node.BackendNodeID)\n}\n\n// eval evaluates the provided JavaScript within this execution context and\n// returns a value or handle.\n//\n//nolint:funlen\nfunc (e *ExecutionContext) eval(\n\tapiCtx context.Context, opts evalOptions, js string, args ...any,\n) (any, error) {\n\tif escapesSobekValues(args...) {\n\t\treturn nil, errors.New(\"sobek.Value escaped\")\n\t}\n\te.logger.Debugf(\n\t\t\"ExecutionContext:eval\",\n\t\t\"sid:%s stid:%s fid:%s ectxid:%d furl:%q %s\",\n\t\te.sid, e.stid, e.fid, e.id, e.furl, opts)\n\n\tsuffix := `//# sourceURL=` + evaluationScriptURL\n\n\tvar action interface {\n\t\tDo(context.Context) (*runtime.RemoteObject, *runtime.ExceptionDetails, error)\n\t}\n\n\tif !opts.forceCallable {\n\t\tif !hasSourceURL(js) {\n\t\t\tjs += \"\\n\" + suffix\n\t\t}\n\n\t\taction = runtime.Evaluate(js).\n\t\t\tWithContextID(e.id).\n\t\t\tWithReturnByValue(opts.returnByValue).\n\t\t\tWithAwaitPromise(true).\n\t\t\tWithUserGesture(true)\n\t} else {\n\t\tvar arguments []*runtime.CallArgument\n\t\tfor _, arg := range args {\n\t\t\tresult, err := convertArgument(apiCtx, e, arg)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"converting argument %q \"+\n\t\t\t\t\t\"in execution context ID %d and frame ID %v: %w\",\n\t\t\t\t\targ, e.id, e.Frame().ID(), err)\n\t\t\t}\n\t\t\targuments = append(arguments, result)\n\t\t}\n\n\t\tjs += \"\\n\" + suffix + \"\\n\"\n\t\taction = runtime.CallFunctionOn(js).\n\t\t\tWithArguments(arguments).\n\t\t\tWithExecutionContextID(e.id).\n\t\t\tWithReturnByValue(opts.returnByValue).\n\t\t\tWithAwaitPromise(true).\n\t\t\tWithUserGesture(true)\n\t}\n\n\tvar (\n\t\tremoteObject     *runtime.RemoteObject\n\t\texceptionDetails *runtime.ExceptionDetails\n\t\terr              error\n\t)\n\tif remoteObject, exceptionDetails, err = action.Do(cdp.WithExecutor(apiCtx, e.session)); err != nil {\n\t\tvar cdpe *cdproto.Error\n\t\tif errors.As(err, &cdpe) && cdpe.Code == devToolsServerErrorCode {\n\t\t\t// By creating a new error instead of reusing it, we're removing the\n\t\t\t// chromium specific error code.\n\t\t\treturn nil, errors.New(cdpe.Message)\n\t\t}\n\n\t\te.logger.Debugf(\"ExecutionContext:eval\", \"Unexpected DevTools server error: %v\", err)\n\t\treturn nil, err\n\t}\n\tif exceptionDetails != nil {\n\t\treturn nil, fmt.Errorf(\"%s\", parseExceptionDetails(exceptionDetails))\n\t}\n\tvar res any\n\tif remoteObject == nil {\n\t\te.logger.Debugf(\n\t\t\t\"ExecutionContext:eval\",\n\t\t\t\"sid:%s stid:%s fid:%s ectxid:%d furl:%q remoteObject is nil\",\n\t\t\te.sid, e.stid, e.fid, e.id, e.furl)\n\t\treturn res, nil\n\t}\n\n\tif opts.returnByValue {\n\t\tres, err = valueFromRemoteObject(apiCtx, remoteObject)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"extracting value from remote object with ID %s: %w\",\n\t\t\t\tremoteObject.ObjectID, err)\n\t\t}\n\t} else if remoteObject.ObjectID != \"\" {\n\t\t// Note: we don't use the passed in apiCtx here as it could be tied to a timeout\n\t\tres = NewJSHandle(e.ctx, e.session, e, e.frame, remoteObject, e.logger)\n\t}\n\n\treturn res, nil\n}\n\n// Based on: https://github.com/microsoft/playwright/blob/master/src/server/injected/injectedScript.ts\n//\n//go:embed js/injected_script.js\nvar injectedScriptSource string\n\n//nolint:gochecknoglobals\nvar injectedScriptSourceWithSourceURL = `(() => {` + injectedScriptSource + `; return new InjectedScript();})()` +\n\t\"\\n//# sourceURL=\" + evaluationScriptURL\n\n// getInjectedScript returns a JS handle to the injected script of helper functions.\nfunc (e *ExecutionContext) getInjectedScript(apiCtx context.Context) (JSHandleAPI, error) {\n\te.logger.Debugf(\n\t\t\"ExecutionContext:getInjectedScript\",\n\t\t\"sid:%s stid:%s fid:%s ectxid:%d efurl:%s\",\n\t\te.sid, e.stid, e.fid, e.id, e.furl)\n\n\te.isMutex.RLock()\n\tif e.injectedScript != nil {\n\t\tinjectedScript := e.injectedScript\n\t\te.isMutex.RUnlock()\n\t\treturn injectedScript, nil\n\t}\n\te.isMutex.RUnlock()\n\n\thandle, err := e.eval(\n\t\tapiCtx,\n\t\tevalOptions{forceCallable: false, returnByValue: false},\n\t\tinjectedScriptSourceWithSourceURL,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif handle == nil {\n\t\treturn nil, errors.New(\"handle is nil\")\n\t}\n\tinjectedScript, ok := handle.(JSHandleAPI)\n\tif !ok {\n\t\treturn nil, ErrJSHandleInvalid\n\t}\n\te.isMutex.Lock()\n\te.injectedScript = injectedScript\n\te.isMutex.Unlock()\n\n\treturn injectedScript, nil\n}\n\n// Eval evaluates the provided JavaScript within this execution context and\n// returns a value or handle.\nfunc (e *ExecutionContext) Eval(apiCtx context.Context, js string, args ...any) (any, error) {\n\tif escapesSobekValues(args...) {\n\t\treturn nil, errors.New(\"sobek.Value escaped\")\n\t}\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tevalArgs := make([]any, 0, len(args))\n\tevalArgs = append(evalArgs, args...)\n\n\treturn e.eval(apiCtx, opts, js, evalArgs...)\n}\n\n// EvalHandle evaluates the provided JavaScript within this execution context\n// and returns a JSHandle.\nfunc (e *ExecutionContext) EvalHandle(apiCtx context.Context, js string, args ...any) (JSHandleAPI, error) {\n\tif escapesSobekValues(args...) {\n\t\treturn nil, errors.New(\"sobek.Value escaped\")\n\t}\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: false,\n\t}\n\tevalArgs := make([]any, 0, len(args))\n\tevalArgs = append(evalArgs, args...)\n\tres, err := e.eval(apiCtx, opts, js, evalArgs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif res == nil {\n\t\treturn nil, errors.New(\"nil result\")\n\t}\n\n\tr, ok := res.(JSHandleAPI)\n\tif !ok {\n\t\treturn nil, ErrJSHandleInvalid\n\t}\n\n\treturn r, nil\n}\n\n// Frame returns the frame that this execution context belongs to.\nfunc (e *ExecutionContext) Frame() *Frame {\n\treturn e.frame\n}\n\n// ID returns the CDP runtime ID of this execution context.\nfunc (e *ExecutionContext) ID() runtime.ExecutionContextID {\n\treturn e.id\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/frame.go",
    "content": "package common\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\n// maxRetry controls how many times to retry if an action fails.\nconst maxRetry = 1\n\ntype DocumentInfo struct {\n\tdocumentID string\n\trequest    *Request\n}\n\n// DOMElementState represents a DOM element state.\ntype DOMElementState int\n\n// Valid DOM element states.\nconst (\n\tDOMElementStateAttached DOMElementState = iota\n\tDOMElementStateDetached\n\tDOMElementStateVisible\n\tDOMElementStateHidden\n)\n\nfunc (s DOMElementState) String() string {\n\treturn domElementStateToString[s]\n}\n\nvar domElementStateToString = map[DOMElementState]string{ //nolint:gochecknoglobals\n\tDOMElementStateAttached: \"attached\",\n\tDOMElementStateDetached: \"detached\",\n\tDOMElementStateVisible:  \"visible\",\n\tDOMElementStateHidden:   \"hidden\",\n}\n\nvar domElementStateToID = map[string]DOMElementState{ //nolint:gochecknoglobals\n\t\"attached\": DOMElementStateAttached,\n\t\"detached\": DOMElementStateDetached,\n\t\"visible\":  DOMElementStateVisible,\n\t\"hidden\":   DOMElementStateHidden,\n}\n\n// MarshalJSON marshals the enum as a quoted JSON string.\nfunc (s DOMElementState) MarshalJSON() ([]byte, error) {\n\tbuffer := bytes.NewBufferString(`\"`)\n\tbuffer.WriteString(domElementStateToString[s])\n\tbuffer.WriteString(`\"`)\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON unmarshals a quoted JSON string to the enum value.\nfunc (s *DOMElementState) UnmarshalJSON(b []byte) error {\n\tvar j string\n\terr := json.Unmarshal(b, &j)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshaling DOM element state: %w\", err)\n\t}\n\t// Note that if the string cannot be found then it will be set to the zero value.\n\t*s = domElementStateToID[j]\n\treturn nil\n}\n\n// Frame represents a frame in an HTML document.\ntype Frame struct {\n\tBaseEventEmitter\n\n\tctx         context.Context\n\tpage        *Page\n\tmanager     *FrameManager\n\tparentFrame *Frame\n\n\tchildFramesMu sync.RWMutex\n\tchildFrames   map[*Frame]bool\n\n\tpropertiesMu sync.RWMutex\n\tid           cdp.FrameID\n\tloaderID     string\n\tname         string\n\turl          string\n\tdetached     bool\n\n\t// A life cycle event is only considered triggered for a frame if the entire\n\t// frame subtree has also had the life cycle event triggered.\n\tlifecycleEventsMu sync.RWMutex\n\tlifecycleEvents   map[LifecycleEvent]bool\n\n\tdocumentHandle *ElementHandle\n\n\texecutionContextMu sync.RWMutex\n\texecutionContexts  map[executionWorld]frameExecutionContext\n\n\tloadingStartedTime time.Time\n\n\tinflightRequestsMu sync.RWMutex\n\tinflightRequests   map[network.RequestID]bool\n\n\tcurrentDocument   *DocumentInfo\n\tpendingDocumentMu sync.RWMutex\n\tpendingDocument   *DocumentInfo\n\n\tlog *log.Logger\n}\n\n// String returns a string repesentation of Frame.\n// It exists mostly for debugging where we don't want fmt.Sprintf to just\n// go through a complex object and try to stringify it.\nfunc (f *Frame) String() string {\n\treturn \"Frame: {\" +\n\t\t\" id: \" + f.id.String() +\n\t\t\" name: \" + f.name +\n\t\t\" url: \" + f.url +\n\t\t\"}\"\n}\n\n// NewFrame creates a new HTML document frame.\nfunc NewFrame(\n\tctx context.Context, m *FrameManager, parentFrame *Frame, frameID cdp.FrameID, log *log.Logger,\n) *Frame {\n\tif log.DebugMode() {\n\t\tvar pfid string\n\t\tif parentFrame != nil {\n\t\t\tpfid = parentFrame.ID()\n\t\t}\n\t\tvar sid string\n\t\tif m != nil && m.session != nil {\n\t\t\tsid = string(m.session.ID())\n\t\t}\n\t\tlog.Debugf(\"NewFrame\", \"sid:%s fid:%s pfid:%s\", sid, frameID, pfid)\n\t}\n\n\treturn &Frame{\n\t\tBaseEventEmitter:  NewBaseEventEmitter(ctx),\n\t\tctx:               ctx,\n\t\tpage:              m.page,\n\t\tmanager:           m,\n\t\tparentFrame:       parentFrame,\n\t\tchildFrames:       make(map[*Frame]bool),\n\t\tid:                frameID,\n\t\tlifecycleEvents:   make(map[LifecycleEvent]bool),\n\t\tinflightRequests:  make(map[network.RequestID]bool),\n\t\texecutionContexts: make(map[executionWorld]frameExecutionContext),\n\t\tcurrentDocument:   &DocumentInfo{},\n\t\tlog:               log,\n\t}\n}\n\nfunc (f *Frame) addChildFrame(child *Frame) {\n\tf.log.Debugf(\"Frame:addChildFrame\",\n\t\t\"fid:%s cfid:%s furl:%q cfurl:%q\",\n\t\tf.ID(), child.ID(), f.URL(), child.URL())\n\n\tf.childFramesMu.Lock()\n\tdefer f.childFramesMu.Unlock()\n\n\tf.childFrames[child] = true\n}\n\nfunc (f *Frame) addRequest(id network.RequestID) {\n\tf.log.Debugf(\"Frame:addRequest\", \"fid:%s furl:%q rid:%s\", f.ID(), f.URL(), id)\n\n\tf.inflightRequestsMu.Lock()\n\tdefer f.inflightRequestsMu.Unlock()\n\n\tf.inflightRequests[id] = true\n}\n\nfunc (f *Frame) deleteRequest(id network.RequestID) {\n\tf.log.Debugf(\"Frame:deleteRequest\", \"fid:%s furl:%q rid:%s\", f.ID(), f.URL(), id)\n\n\tf.inflightRequestsMu.Lock()\n\tdefer f.inflightRequestsMu.Unlock()\n\n\tdelete(f.inflightRequests, id)\n}\n\nfunc (f *Frame) clearLifecycle() {\n\tf.log.Debugf(\"Frame:clearLifecycle\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\t// clear lifecycle events\n\tf.lifecycleEventsMu.Lock()\n\tf.lifecycleEvents = make(map[LifecycleEvent]bool)\n\tf.lifecycleEventsMu.Unlock()\n\n\t// keep the request related to the document if present\n\t// in f.inflightRequests\n\tf.inflightRequestsMu.Lock()\n\t{\n\t\t// currentDocument may not always have a request\n\t\t// associated with it. see: frame_manager.go\n\t\tcdr := f.currentDocument.request\n\n\t\tinflightRequests := make(map[network.RequestID]bool)\n\t\tfor req := range f.inflightRequests {\n\t\t\tif cdr != nil && req != cdr.requestID {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tinflightRequests[req] = true\n\t\t}\n\t\tf.inflightRequests = inflightRequests\n\t}\n\tf.inflightRequestsMu.Unlock()\n}\n\nfunc (f *Frame) detach() error {\n\tf.log.Debugf(\"Frame:detach\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tf.setDetached(true)\n\tif f.parentFrame != nil {\n\t\tf.parentFrame.removeChildFrame(f)\n\t}\n\tf.parentFrame = nil\n\n\t// detach() is called by the same frame Goroutine that manages execution\n\t// context switches. so this should be safe.\n\t// we don't need to protect the following with executionContextMu.\n\tif f.documentHandle == nil {\n\t\treturn nil\n\t}\n\tif err := f.documentHandle.Dispose(); err != nil {\n\t\treturn fmt.Errorf(\"disposing document handle while detaching frame: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (f *Frame) defaultTimeout() time.Duration {\n\treturn f.manager.timeoutSettings.timeout()\n}\n\nfunc (f *Frame) document() (*ElementHandle, error) {\n\tf.log.Debugf(\"Frame:document\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tif cdh, ok := f.cachedDocumentHandle(); ok {\n\t\treturn cdh, nil\n\t}\n\n\tf.waitForExecutionContext(mainWorld)\n\n\tdh, err := f.newDocumentHandle()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting new document handle: %w\", err)\n\t}\n\n\t// each execution context switch modifies documentHandle.\n\t// see: nullContext().\n\tf.executionContextMu.Lock()\n\tdefer f.executionContextMu.Unlock()\n\tf.documentHandle = dh\n\n\treturn dh, nil\n}\n\nfunc (f *Frame) cachedDocumentHandle() (*ElementHandle, bool) {\n\t// each execution context switch modifies documentHandle.\n\t// see: nullContext().\n\tf.executionContextMu.RLock()\n\tdefer f.executionContextMu.RUnlock()\n\n\treturn f.documentHandle, f.documentHandle != nil\n}\n\nfunc (f *Frame) newDocumentHandle() (*ElementHandle, error) {\n\tresult, err := f.evaluate(\n\t\tf.ctx,\n\t\tmainWorld,\n\t\tevalOptions{\n\t\t\tforceCallable: false,\n\t\t\treturnByValue: false,\n\t\t},\n\t\t\"document\",\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting document element handle: %w\", err)\n\t}\n\tif result == nil {\n\t\treturn nil, fmt.Errorf(\"document element handle is nil\")\n\t}\n\tdh, ok := result.(*ElementHandle)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected document handle type: %T\", result)\n\t}\n\n\treturn dh, nil\n}\n\nfunc (f *Frame) hasContext(world executionWorld) bool {\n\tf.executionContextMu.RLock()\n\tdefer f.executionContextMu.RUnlock()\n\n\treturn f.executionContexts[world] != nil\n}\n\nfunc (f *Frame) hasLifecycleEventFired(event LifecycleEvent) bool {\n\tf.lifecycleEventsMu.RLock()\n\tdefer f.lifecycleEventsMu.RUnlock()\n\n\treturn f.lifecycleEvents[event]\n}\n\nfunc (f *Frame) navigated(name string, url string, loaderID string) {\n\tf.log.Debugf(\"Frame:navigated\", \"fid:%s furl:%q lid:%s name:%q url:%q\", f.ID(), f.URL(), loaderID, name, url)\n\n\tf.propertiesMu.Lock()\n\tdefer f.propertiesMu.Unlock()\n\tf.name = name\n\tf.url = url\n\tf.loaderID = loaderID\n}\n\nfunc (f *Frame) nullContext(execCtxID runtime.ExecutionContextID) {\n\tf.log.Debugf(\"Frame:nullContext\", \"fid:%s furl:%q ectxid:%d \", f.ID(), f.URL(), execCtxID)\n\n\tf.executionContextMu.Lock()\n\tdefer f.executionContextMu.Unlock()\n\n\tif ec := f.executionContexts[mainWorld]; ec != nil && ec.ID() == execCtxID {\n\t\tf.executionContexts[mainWorld] = nil\n\t\tf.documentHandle = nil\n\t\treturn\n\t}\n\tif ec := f.executionContexts[utilityWorld]; ec != nil && ec.ID() == execCtxID {\n\t\tf.executionContexts[utilityWorld] = nil\n\t}\n}\n\nfunc (f *Frame) onLifecycleEvent(event LifecycleEvent) {\n\tf.log.Debugf(\"Frame:onLifecycleEvent\", \"fid:%s furl:%q event:%s\", f.ID(), f.URL(), event)\n\n\tf.lifecycleEventsMu.Lock()\n\tf.lifecycleEvents[event] = true\n\tf.lifecycleEventsMu.Unlock()\n\n\tf.emit(EventFrameAddLifecycle, FrameLifecycleEvent{\n\t\tURL:   f.URL(),\n\t\tEvent: event,\n\t})\n}\n\nfunc (f *Frame) onLoadingStarted() {\n\tf.log.Debugf(\"Frame:onLoadingStarted\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tf.loadingStartedTime = time.Now()\n}\n\nfunc (f *Frame) onLoadingStopped() {\n\tf.log.Debugf(\"Frame:onLoadingStopped\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\t// TODO: We should start a timer here and allow the user\n\t//       to set how long to wait until after onLoadingStopped\n\t//       has occurred. The reason we may want a timeout here\n\t//       are for websites where they perform many network\n\t//       requests so it may take a long time for us to see\n\t//       a networkIdle event or we may never see one if the\n\t//       website never stops performing network requests.\n}\n\nfunc (f *Frame) position() (*Position, error) {\n\tframe, ok := f.manager.getFrameByID(cdp.FrameID(f.page.targetID))\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"could not find frame with id %s\", f.page.targetID)\n\t}\n\tif frame == f.page.frameManager.MainFrame() {\n\t\treturn &Position{X: 0, Y: 0}, nil\n\t}\n\telement, err := frame.FrameElement()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbox, err := element.BoundingBox()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"finding position in frame: %w\", err)\n\t}\n\n\treturn &Position{X: box.X, Y: box.Y}, nil\n}\n\nfunc (f *Frame) removeChildFrame(child *Frame) {\n\tf.log.Debugf(\"Frame:removeChildFrame\", \"fid:%s furl:%q cfid:%s curl:%q\",\n\t\tf.ID(), f.URL(), child.ID(), child.URL())\n\n\tf.childFramesMu.Lock()\n\tdefer f.childFramesMu.Unlock()\n\n\tdelete(f.childFrames, child)\n}\n\nfunc (f *Frame) setContext(world executionWorld, execCtx frameExecutionContext) {\n\tf.executionContextMu.Lock()\n\tdefer f.executionContextMu.Unlock()\n\n\tf.log.Debugf(\"Frame:setContext\", \"fid:%s furl:%q ectxid:%d world:%s\",\n\t\tf.ID(), f.URL(), execCtx.ID(), world)\n\n\tif !world.valid() {\n\t\terr := fmt.Errorf(\"unknown world: %q, it should be either main or utility\", world)\n\t\tpanic(err)\n\t}\n\n\t// There is a race condition when it comes to attaching iframes and the\n\t// execution context that apply to these frames. What usually occurs is:\n\t//\n\t// 1. An exec context for about:blank is first set;\n\t// 2. A new set event is received for exec context for the url pointing\n\t//    to the actual destination for the iframe;\n\t// 3. Finally the execution context for about:blank is destroyed, not\n\t//    for the second execution context.\n\t//\n\t// This is the order of events when iframes are in use on a site, and\n\t// so it is safe to nil the original execution context and overwrite it\n\t// with the second one.\n\t//\n\t// The exec context destroyed event will not remove the new exec context\n\t// since the ids do not match.\n\t//\n\t// If we didn't overwrite the first execCtx with the new one, then\n\t// waitForExecutionContext could end up waiting indefinitely since all\n\t// execCtx were destroyed.\n\tif f.executionContexts[world] != nil {\n\t\tf.log.Debugf(\"Frame:setContext\", \"fid:%s furl:%q ectxid:%d world:%s, overriding existing world\",\n\t\t\tf.ID(), f.URL(), execCtx.ID(), world)\n\n\t\tf.executionContexts[world] = nil\n\t\tf.documentHandle = nil\n\t}\n\n\tf.executionContexts[world] = execCtx\n\tf.log.Debugf(\"Frame:setContext\", \"fid:%s furl:%q ectxid:%d world:%s, world set\",\n\t\tf.ID(), f.URL(), execCtx.ID(), world)\n}\n\nfunc (f *Frame) setID(id cdp.FrameID) {\n\tf.propertiesMu.Lock()\n\tdefer f.propertiesMu.Unlock()\n\n\tf.id = id\n}\n\nfunc (f *Frame) waitForExecutionContext(world executionWorld) {\n\tf.log.Debugf(\"Frame:waitForExecutionContext\", \"fid:%s furl:%q world:%s\",\n\t\tf.ID(), f.URL(), world)\n\n\tt := time.NewTicker(50 * time.Millisecond)\n\tdefer t.Stop()\n\tfor {\n\t\tselect {\n\t\tcase <-t.C:\n\t\t\tif f.hasContext(world) {\n\t\t\t\treturn\n\t\t\t}\n\t\tcase <-f.ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (f *Frame) waitForSelectorRetry(\n\tselector string, opts *FrameWaitForSelectorOptions, retry int,\n) (h *ElementHandle, err error) {\n\tfor ; retry >= 0; retry-- {\n\t\tif h, err = f.waitForSelector(selector, opts); err == nil {\n\t\t\treturn h, nil\n\t\t}\n\t}\n\n\treturn nil, err\n}\n\n// waitForSelector will wait for the given selector to reach a defined state in\n// opts.\n//\n// It will auto retry on certain errors until the retryCount is below 0. The\n// retry workaround is needed since the underlying DOM can change when the\n// wait action is performed during a navigation.\nfunc (f *Frame) waitForSelector(selector string, opts *FrameWaitForSelectorOptions) (*ElementHandle, error) {\n\tf.log.Debugf(\"Frame:waitForSelector\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\thandle, err := f.waitFor(selector, opts, 20)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif handle == nil {\n\t\treturn nil, fmt.Errorf(\"waiting for selector %q did not result in any nodes\", selector)\n\t}\n\n\t// We always return ElementHandles in the main execution context (aka \"DOM world\")\n\tf.executionContextMu.RLock()\n\tdefer f.executionContextMu.RUnlock()\n\n\tuec := f.executionContexts[utilityWorld]\n\n\t// An element should belong to the current main world execution context, and\n\t// not to the utility world context, otherwise, we should adopt it to the\n\t// current world's execution context. This is only valid when the handle\n\t// is from the current frame and not part of a nested frame.\n\tadopted := handle\n\tif uec != nil && uec == handle.execCtx {\n\t\twec := f.executionContexts[mainWorld]\n\t\tif wec == nil {\n\t\t\treturn nil, fmt.Errorf(\"waiting for selector %q: execution context %q not found\", selector, mainWorld)\n\t\t}\n\n\t\tif adopted, err = wec.adoptElementHandle(handle); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"waiting for selector %q: adopting element handle: %w\", selector, err)\n\t\t}\n\n\t\tif err = handle.Dispose(); err != nil {\n\t\t\tf.log.Warnf(\n\t\t\t\t\"Frame:waitForSelector\",\n\t\t\t\t\"fid:%s furl:%q sel:%q disposing element handle: %v\",\n\t\t\t\tf.ID(), f.URL(), selector, err,\n\t\t\t)\n\t\t}\n\t}\n\n\treturn adopted, nil\n}\n\nfunc (f *Frame) waitFor(\n\tselector string, opts *FrameWaitForSelectorOptions, retryCount int,\n) (_ *ElementHandle, rerr error) {\n\tf.log.Debugf(\"Frame:waitFor\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tretryCount--\n\tif retryCount < 0 {\n\t\treturn nil, errors.New(\"waitFor retry threshold reached\")\n\t}\n\n\tdocument, err := f.document()\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"Cannot find context with specified id\") {\n\t\t\treturn f.waitFor(selector, opts, retryCount)\n\t\t}\n\t\treturn nil, err\n\t}\n\n\thandle, err := document.waitForSelector(f.ctx, selector, opts)\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"Inspected target navigated or closed\") {\n\t\t\treturn f.waitFor(selector, opts, retryCount)\n\t\t}\n\t\tif strings.Contains(err.Error(), \"Cannot find context with specified id\") {\n\t\t\treturn f.waitFor(selector, opts, retryCount)\n\t\t}\n\t\tif strings.Contains(err.Error(), \"Execution context was destroyed\") {\n\t\t\treturn f.waitFor(selector, opts, retryCount)\n\t\t}\n\t\tif strings.Contains(err.Error(), \"visible\") {\n\t\t\treturn f.waitFor(selector, opts, retryCount)\n\t\t}\n\t}\n\n\treturn handle, err\n}\n\nfunc (f *Frame) boundingBox(selector string, opts *FrameBaseOptions) (*Rect, error) {\n\tgetBoundingBox := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.boundingBox()\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, getBoundingBox, []string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn nil, errorFromDOMError(err)\n\t}\n\n\tbv, ok := v.(*Rect)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"getting bounding box of %q: unexpected type %T\", selector, v)\n\t}\n\n\treturn bv, nil\n}\n\n// ChildFrames returns a list of child frames.\nfunc (f *Frame) ChildFrames() []*Frame {\n\tf.childFramesMu.RLock()\n\tdefer f.childFramesMu.RUnlock()\n\n\tl := make([]*Frame, 0, len(f.childFrames))\n\tfor child := range f.childFrames {\n\t\tl = append(l, child)\n\t}\n\treturn l\n}\n\n// Click clicks the first element found that matches selector.\nfunc (f *Frame) Click(selector string, opts *FrameClickOptions) error {\n\tf.log.Debugf(\"Frame:Click\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.click(selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"clicking on %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) click(selector string, opts *FrameClickOptions) error {\n\tclick := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.click(p, opts.ToMouseClickOptions())\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, click, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\nfunc (f *Frame) count(selector string) (int, error) {\n\tf.log.Debugf(\"Frame:count\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tdocument, err := f.document()\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"getting document: %w\", err)\n\t}\n\n\tc, err := document.count(f.ctx, selector)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"counting elements: %w\", err)\n\t}\n\n\treturn c, nil\n}\n\n// Check clicks the first element found that matches selector.\nfunc (f *Frame) Check(selector string, popts *FrameCheckOptions) error {\n\tf.log.Debugf(\"Frame:Check\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.check(selector, popts); err != nil {\n\t\treturn fmt.Errorf(\"checking %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) check(selector string, opts *FrameCheckOptions) error {\n\tcheck := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.setChecked(apiCtx, true, p)\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, check, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\nfunc (f *Frame) setChecked(selector string, checked bool, opts *FrameCheckOptions) error {\n\tsetChecked := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.setChecked(apiCtx, checked, p)\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, setChecked, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// SetChecked sets the checked state of the first element found that matches the selector.\nfunc (f *Frame) SetChecked(selector string, checked bool, popts *FrameCheckOptions) error {\n\tf.log.Debugf(\"Frame:SetChecked\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.setChecked(selector, checked, popts); err != nil {\n\t\treturn fmt.Errorf(\"setting checked %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\n// Uncheck the first found element that matches the selector.\nfunc (f *Frame) Uncheck(selector string, popts *FrameUncheckOptions) error {\n\tf.log.Debugf(\"Frame:Uncheck\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.uncheck(selector, popts); err != nil {\n\t\treturn fmt.Errorf(\"unchecking %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) uncheck(selector string, opts *FrameUncheckOptions) error {\n\tuncheck := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.setChecked(apiCtx, false, p)\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, uncheck, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// IsChecked returns true if the first element that matches the selector\n// is checked. Otherwise, returns false.\nfunc (f *Frame) IsChecked(selector string, opts *FrameIsCheckedOptions) (bool, error) {\n\tf.log.Debugf(\"Frame:IsChecked\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tchecked, err := f.isChecked(selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking element is checked %q: %w\", selector, err)\n\t}\n\n\treturn checked, nil\n}\n\nfunc (f *Frame) isChecked(selector string, opts *FrameIsCheckedOptions) (bool, error) {\n\tisChecked := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\tv, err := handle.isChecked(apiCtx, 0) // Zero timeout when checking state\n\t\tif errors.Is(err, ErrTimedOut) {      // We don't care about timeout errors here!\n\t\t\treturn v, nil\n\t\t}\n\t\treturn v, err\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, isChecked, []string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn false, errorFromDOMError(err)\n\t}\n\n\tbv, ok := v.(bool)\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"checking is %q checked: unexpected type %T\", selector, v)\n\t}\n\n\treturn bv, nil\n}\n\n// Content returns the HTML content of the frame.\nfunc (f *Frame) Content() (string, error) {\n\tf.log.Debugf(\"Frame:Content\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tjs := `() => {\n\t\tlet content = '';\n\t\tif (document.doctype) {\n\t\t\tcontent = new XMLSerializer().serializeToString(document.doctype);\n\t\t}\n\t\tif (document.documentElement) {\n\t\t\tcontent += document.documentElement.outerHTML;\n\t\t}\n\t\treturn content;\n\t}`\n\n\tv, err := f.Evaluate(js)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting frame content: %w\", err)\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"getting frame content: expected string, got %T\", v)\n\t}\n\n\treturn s, nil\n}\n\n// Dblclick double clicks an element matching provided selector.\nfunc (f *Frame) Dblclick(selector string, popts *FrameDblclickOptions) error {\n\tf.log.Debugf(\"Frame:DblClick\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.dblclick(selector, popts); err != nil {\n\t\treturn fmt.Errorf(\"double clicking on %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\n// dblclick is like Dblclick but takes parsed options and neither throws\n// an error, or applies slow motion.\nfunc (f *Frame) dblclick(selector string, opts *FrameDblclickOptions) error {\n\tdblclick := func(_ context.Context, eh *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, eh.dblclick(p, opts.ToMouseClickOptions())\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, dblclick, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// DispatchEvent dispatches an event for the first element matching the selector.\nfunc (f *Frame) DispatchEvent(selector, typ string, eventInit any, opts *FrameDispatchEventOptions) error {\n\tf.log.Debugf(\"Frame:DispatchEvent\", \"fid:%s furl:%q sel:%q typ:%q\", f.ID(), f.URL(), selector, typ)\n\n\tif err := f.dispatchEvent(selector, typ, eventInit, opts); err != nil {\n\t\treturn fmt.Errorf(\"dispatching frame event %q to %q: %w\", typ, selector, err)\n\t}\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\n// dispatchEvent is like DispatchEvent but takes parsed options and neither throws\n// an error, or applies slow motion.\nfunc (f *Frame) dispatchEvent(selector, typ string, eventInit any, opts *FrameDispatchEventOptions) error {\n\tdispatchEvent := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.dispatchEvent(apiCtx, typ, eventInit)\n\t}\n\tconst (\n\t\tforce       = false\n\t\tnoWaitAfter = false\n\t)\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, dispatchEvent, []string{},\n\t\tforce, noWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// EvaluateWithContext will evaluate provided page function within an execution context.\n// The passed in context will be used instead of the frame's context. The context must\n// be a derivative of one that contains the sobek runtime.\nfunc (f *Frame) EvaluateWithContext(ctx context.Context, pageFunc string, args ...any) (any, error) {\n\tf.log.Debugf(\"Frame:EvaluateWithContext\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tf.waitForExecutionContext(mainWorld)\n\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := f.evaluate(ctx, mainWorld, opts, pageFunc, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating JS: %w\", err)\n\t}\n\n\tapplySlowMo(ctx)\n\n\treturn result, nil\n}\n\n// Evaluate will evaluate provided page function within an execution context.\nfunc (f *Frame) Evaluate(pageFunc string, args ...any) (any, error) {\n\tf.log.Debugf(\"Frame:Evaluate\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\treturn f.EvaluateWithContext(f.ctx, pageFunc, args...)\n}\n\n// EvaluateGlobal will evaluate the given JS code in the global object.\nfunc (f *Frame) EvaluateGlobal(ctx context.Context, js string) error {\n\taction := runtime.Evaluate(js).WithAwaitPromise(true)\n\n\tvar (\n\t\texceptionDetails *runtime.ExceptionDetails\n\t\terr              error\n\t)\n\tif _, exceptionDetails, err = action.Do(cdp.WithExecutor(ctx, f.manager.session)); err != nil {\n\t\treturn fmt.Errorf(\"evaluating JS in global context: %w\", err)\n\t}\n\tif exceptionDetails != nil {\n\t\treturn fmt.Errorf(\"%s\", parseExceptionDetails(exceptionDetails))\n\t}\n\n\treturn nil\n}\n\n// EvaluateHandle will evaluate provided page function within an execution context.\nfunc (f *Frame) EvaluateHandle(pageFunc string, args ...any) (handle JSHandleAPI, _ error) {\n\tf.log.Debugf(\"Frame:EvaluateHandle\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tevalHandle := func() (JSHandleAPI, error) {\n\t\tf.executionContextMu.RLock()\n\t\tdefer f.executionContextMu.RUnlock()\n\n\t\tec := f.executionContexts[mainWorld]\n\t\tif ec == nil {\n\t\t\treturn nil, fmt.Errorf(\"evaluating handle for frame: execution context %q not found\", mainWorld)\n\t\t}\n\t\treturn ec.EvalHandle(f.ctx, pageFunc, args...) //nolint:wrapcheck\n\t}\n\n\tf.waitForExecutionContext(mainWorld)\n\thandle, err := evalHandle()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating handle for frame: %w\", err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn handle, nil\n}\n\n// Fill fills out the first element found that matches the selector.\nfunc (f *Frame) Fill(selector, value string, popts *FrameFillOptions) error {\n\tf.log.Debugf(\"Frame:Fill\", \"fid:%s furl:%q sel:%q val:%q\", f.ID(), f.URL(), selector, value)\n\n\tif err := f.fill(selector, value, popts); err != nil {\n\t\treturn fmt.Errorf(\"filling %q with %q: %w\", selector, value, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) fill(selector, value string, opts *FrameFillOptions) error {\n\tfill := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.fill(apiCtx, value)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict,\n\t\tfill, []string{\"visible\", \"enabled\", \"editable\"},\n\t\topts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// Focus focuses on the first element that matches the selector.\nfunc (f *Frame) Focus(selector string, popts *FrameBaseOptions) error {\n\tf.log.Debugf(\"Frame:Focus\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.focus(selector, popts); err != nil {\n\t\treturn fmt.Errorf(\"focusing %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) focus(selector string, opts *FrameBaseOptions) error {\n\tfocus := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.focus(apiCtx, true)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, focus,\n\t\t[]string{}, false, true, opts.Timeout,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// FrameElement returns the element handle for the frame.\nfunc (f *Frame) FrameElement() (*ElementHandle, error) {\n\tf.log.Debugf(\"Frame:FrameElement\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\telement, err := f.page.getFrameElement(f)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting frame element: %w\", err)\n\t}\n\treturn element, nil\n}\n\n// GetAttribute of the first element found that matches the selector.\n// The second return value is true if the attribute exists, and false otherwise.\nfunc (f *Frame) GetAttribute(selector, name string, popts *FrameBaseOptions) (string, bool, error) {\n\tf.log.Debugf(\"Frame:GetAttribute\", \"fid:%s furl:%q sel:%q name:%s\", f.ID(), f.URL(), selector, name)\n\n\ts, ok, err := f.getAttribute(selector, name, popts)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"getting attribute %q of %q: %w\", name, selector, err)\n\t}\n\n\treturn s, ok, nil\n}\n\nfunc (f *Frame) getAttribute(selector, name string, opts *FrameBaseOptions) (string, bool, error) {\n\tgetAttribute := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.getAttribute(apiCtx, name)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, getAttribute,\n\t\t[]string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", false, errorFromDOMError(err)\n\t}\n\tif v == nil {\n\t\treturn \"\", false, nil\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", false, fmt.Errorf(\"unexpected type %T (expecting string)\", v)\n\t}\n\n\treturn s, true, nil\n}\n\n// GetByRole creates and returns a new locator for this frame using the ARIA role\n// and any additional options.\nfunc (f *Frame) GetByRole(role string, opts *GetByRoleOptions) *Locator {\n\tf.log.Debugf(\"Frame:GetByRole\", \"fid:%s furl:%q role:%q opts:%+v\", f.ID(), f.URL(), role, opts)\n\n\treturn f.Locator(f.buildRoleSelector(role, opts), nil)\n}\n\n// isQuotedText returns true if the string is a quoted string.\n// This is used to determine if the string will be used to match\n// a string instead of as a regex in the getBy* APIs. It handles\n// both single and double quotes.\nfunc isQuotedText(s string) bool {\n\ts = strings.TrimSpace(s)\n\tif len(s) <= 1 {\n\t\treturn false\n\t}\n\n\tswitch {\n\tcase s[0] == '\\'' && s[len(s)-1] == '\\'':\n\t\treturn true\n\tcase s[0] == '\"' && s[len(s)-1] == '\"':\n\t\treturn true\n\t}\n\treturn false\n}\n\n// buildAttributeSelector is a helper method that builds an attribute selector\n// prefixed with internal:attr. It handles quoted strings and\n// applies the appropriate suffix for exact or case-insensitive matching.\nfunc (f *Frame) buildAttributeSelector(attrName, attrValue string, opts *GetByBaseOptions) string {\n\tvar b strings.Builder\n\tb.WriteString(\"internal:attr=\")\n\tb.WriteByte('[')\n\tb.WriteString(attrName)\n\tb.WriteByte('=')\n\tb.WriteString(attrValue)\n\tif isQuotedText(attrValue) {\n\t\tif opts != nil && opts.Exact != nil && *opts.Exact {\n\t\t\tb.WriteByte('s')\n\t\t} else {\n\t\t\tb.WriteByte('i')\n\t\t}\n\t}\n\tb.WriteByte(']')\n\treturn b.String()\n}\n\n// buildRoleSelector is a helper method that builds a role selector prefixed with internal:role.\n// It handles quoted strings and applies the appropriate suffix for exact or case-insensitive matching,\n// among the other role-specific options.\nfunc (f *Frame) buildRoleSelector(role string, opts *GetByRoleOptions) string {\n\tvar b strings.Builder\n\tb.WriteString(\"internal:role=\")\n\tb.WriteString(role)\n\n\tif opts == nil {\n\t\treturn b.String()\n\t}\n\n\tproperties := f.mapGetByRoleOptions(opts)\n\tfor key, value := range properties {\n\t\tb.WriteString(\"[\" + key + \"=\" + value + \"]\")\n\t}\n\treturn b.String()\n}\n\nfunc (f *Frame) mapGetByRoleOptions(opts *GetByRoleOptions) map[string]string {\n\tproperties := make(map[string]string)\n\n\tif opts.Checked != nil {\n\t\tproperties[\"checked\"] = strconv.FormatBool(*opts.Checked)\n\t}\n\n\tif opts.Disabled != nil {\n\t\tproperties[\"disabled\"] = strconv.FormatBool(*opts.Disabled)\n\t}\n\n\tif opts.Selected != nil {\n\t\tproperties[\"selected\"] = strconv.FormatBool(*opts.Selected)\n\t}\n\n\tif opts.Expanded != nil {\n\t\tproperties[\"expanded\"] = strconv.FormatBool(*opts.Expanded)\n\t}\n\n\tif opts.IncludeHidden != nil {\n\t\tproperties[\"include-hidden\"] = strconv.FormatBool(*opts.IncludeHidden)\n\t}\n\n\tif opts.Level != nil {\n\t\tproperties[\"level\"] = strconv.FormatInt(*opts.Level, 10)\n\t}\n\n\tif opts.Name != nil && *opts.Name != \"\" {\n\t\t// Exact option can only be applied to quoted strings.\n\t\tif isQuotedText(*opts.Name) {\n\t\t\tif opts.Exact != nil && *opts.Exact {\n\t\t\t\t*opts.Name = (*opts.Name) + \"s\"\n\t\t\t} else {\n\t\t\t\t*opts.Name = (*opts.Name) + \"i\"\n\t\t\t}\n\t\t}\n\t\tproperties[\"name\"] = *opts.Name\n\t}\n\n\tif opts.Pressed != nil {\n\t\tproperties[\"pressed\"] = strconv.FormatBool(*opts.Pressed)\n\t}\n\n\treturn properties\n}\n\n// buildLabelSelector is a helper method that builds a label selector prefixed with internal:label.\n// It handles quoted strings and applies the appropriate suffix for exact or case-insensitive matching.\nfunc (f *Frame) buildLabelSelector(label string, opts *GetByBaseOptions) string {\n\tvar b strings.Builder\n\tb.WriteString(\"internal:label=\")\n\tb.WriteString(label)\n\tif isQuotedText(label) {\n\t\tif opts != nil && opts.Exact != nil && *opts.Exact {\n\t\t\tb.WriteByte('s')\n\t\t} else {\n\t\t\tb.WriteByte('i')\n\t\t}\n\t}\n\treturn b.String()\n}\n\n// buildTestIDSelector is a helper method that builds a data-testid selector.\n// Similar to buildAttributeSelector but without special case-sensitiveness handling.\nfunc (f *Frame) buildTestIDSelector(testID string) string {\n\tvar b strings.Builder\n\tb.WriteString(\"internal:attr=[data-testid=\")\n\tb.WriteString(testID)\n\tb.WriteByte(']')\n\treturn b.String()\n}\n\n// buildTextSelector is a helper method that builds a text selector prefixed with internal:text.\n// It handles quoted strings and applies the appropriate suffix for exact or case-insensitive matching.\nfunc (f *Frame) buildTextSelector(text string, opts *GetByBaseOptions) string {\n\tvar b strings.Builder\n\tb.WriteString(\"internal:text=\")\n\tb.WriteString(text)\n\tif isQuotedText(text) {\n\t\tif opts != nil && opts.Exact != nil && *opts.Exact {\n\t\t\tb.WriteByte('s')\n\t\t} else {\n\t\t\tb.WriteByte('i')\n\t\t}\n\t}\n\treturn b.String()\n}\n\n// GetByAltText creates and returns a new locator for this frame that allows locating elements by their alt text.\nfunc (f *Frame) GetByAltText(alt string, opts *GetByBaseOptions) *Locator {\n\tf.log.Debugf(\"Frame:GetByAltText\", \"fid:%s furl:%q alt:%q opts:%+v\", f.ID(), f.URL(), alt, opts)\n\n\treturn f.Locator(f.buildAttributeSelector(\"alt\", alt, opts), nil)\n}\n\n// GetByLabel creates and returns a new locator for this frame that allows locating input elements by the text\n// of the associated `<label>` or `aria-labelledby` element, or by the `aria-label` attribute.\nfunc (f *Frame) GetByLabel(label string, opts *GetByBaseOptions) *Locator {\n\tf.log.Debugf(\"Frame:GetByLabel\", \"fid:%s furl:%q label:%q opts:%+v\", f.ID(), f.URL(), label, opts)\n\n\treturn f.Locator(f.buildLabelSelector(label, opts), nil)\n}\n\n// GetByPlaceholder creates and returns a new locator for this frame based on the placeholder attribute.\nfunc (f *Frame) GetByPlaceholder(placeholder string, opts *GetByBaseOptions) *Locator {\n\tf.log.Debugf(\"Frame:GetByPlaceholder\", \"fid:%s furl:%q placeholder:%q opts:%+v\", f.ID(), f.URL(), placeholder, opts)\n\n\treturn f.Locator(f.buildAttributeSelector(\"placeholder\", placeholder, opts), nil)\n}\n\n// GetByTitle creates and returns a new locator for this frame based on the title attribute.\nfunc (f *Frame) GetByTitle(title string, opts *GetByBaseOptions) *Locator {\n\tf.log.Debugf(\"Frame:GetByTitle\", \"fid:%s furl:%q title:%q opts:%+v\", f.ID(), f.URL(), title, opts)\n\n\treturn f.Locator(f.buildAttributeSelector(\"title\", title, opts), nil)\n}\n\n// GetByTestID creates and returns a new locator for this frame based on the data-testid attribute.\nfunc (f *Frame) GetByTestID(testID string) *Locator {\n\tf.log.Debugf(\"Frame:GetByTestID\", \"fid:%s furl:%q testID:%q\", f.ID(), f.URL(), testID)\n\n\treturn f.Locator(f.buildTestIDSelector(testID), nil)\n}\n\n// GetByText creates and returns a new locator for this frame based on text content.\nfunc (f *Frame) GetByText(text string, opts *GetByBaseOptions) *Locator {\n\tf.log.Debugf(\"Frame:GetByText\", \"fid:%s furl:%q text:%q opts:%+v\", f.ID(), f.URL(), text, opts)\n\n\treturn f.Locator(f.buildTextSelector(text, opts), nil)\n}\n\n// Referrer returns the referrer of the frame from the network manager\n// of the frame's session.\n// It's an internal method not to be exposed as a JS API.\nfunc (f *Frame) Referrer() string {\n\tnm := f.manager.page.mainFrameSession.getNetworkManager()\n\treturn nm.extraHTTPHeaders[\"referer\"]\n}\n\n// NavigationTimeout returns the navigation timeout of the frame.\n// It's an internal method not to be exposed as a JS API.\nfunc (f *Frame) NavigationTimeout() time.Duration {\n\treturn f.manager.timeoutSettings.navigationTimeout()\n}\n\n// Goto will navigate the frame to the specified URL and return a HTTP response object.\nfunc (f *Frame) Goto(url string, opts *FrameGotoOptions) (*Response, error) {\n\tresp, err := f.manager.NavigateFrame(f, url, opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"navigating frame to %q: %w\", url, err)\n\t}\n\tapplySlowMo(f.ctx)\n\n\t// Since the response will be in an interface, it will never be nil,\n\t// so we need to return nil explicitly.\n\tif resp == nil {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\treturn resp, nil\n}\n\n// Hover moves the pointer over the first element that matches the selector.\nfunc (f *Frame) Hover(selector string, popts *FrameHoverOptions) error {\n\tf.log.Debugf(\"Frame:Hover\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.hover(selector, popts); err != nil {\n\t\treturn fmt.Errorf(\"hovering %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) hover(selector string, opts *FrameHoverOptions) error {\n\thover := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.hover(apiCtx, p)\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, hover, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// InnerHTML returns the innerHTML attribute of the first element found\n// that matches the selector.\nfunc (f *Frame) InnerHTML(selector string, popts *FrameInnerHTMLOptions) (string, error) {\n\tf.log.Debugf(\"Frame:InnerHTML\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tv, err := f.innerHTML(selector, popts)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting inner HTML of %q: %w\", selector, err)\n\t}\n\n\treturn v, nil\n}\n\nfunc (f *Frame) innerHTML(selector string, opts *FrameInnerHTMLOptions) (string, error) {\n\tinnerHTML := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.innerHTML(apiCtx)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, innerHTML,\n\t\t[]string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", errorFromDOMError(err)\n\t}\n\tif v == nil {\n\t\treturn \"\", nil\n\t}\n\tgv, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unexpected type %T\", v)\n\t}\n\n\treturn gv, nil\n}\n\n// InnerText returns the inner text of the first element found\n// that matches the selector.\nfunc (f *Frame) InnerText(selector string, popts *FrameInnerTextOptions) (string, error) {\n\tf.log.Debugf(\"Frame:InnerText\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tv, err := f.innerText(selector, popts)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting inner text of %q: %w\", selector, err)\n\t}\n\n\treturn v, nil\n}\n\nfunc (f *Frame) innerText(selector string, opts *FrameInnerTextOptions) (string, error) {\n\tinnerText := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.innerText(apiCtx)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, innerText,\n\t\t[]string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", errorFromDOMError(err)\n\t}\n\tif v == nil {\n\t\treturn \"\", nil\n\t}\n\tgv, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unexpected type %T\", v)\n\t}\n\n\treturn gv, nil\n}\n\n// InputValue returns the input value of the first element found that matches the selector.\nfunc (f *Frame) InputValue(selector string, popts *FrameInputValueOptions) (string, error) {\n\tf.log.Debugf(\"Frame:InputValue\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tv, err := f.inputValue(selector, popts)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting input value of %q: %w\", selector, err)\n\t}\n\n\treturn v, nil\n}\n\nfunc (f *Frame) inputValue(selector string, opts *FrameInputValueOptions) (string, error) {\n\tinputValue := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.inputValue(apiCtx)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, inputValue,\n\t\t[]string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", errorFromDOMError(err)\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"unexpected type %T\", v)\n\t}\n\n\treturn s, nil\n}\n\n// IsDetached returns whether the frame is detached or not.\nfunc (f *Frame) IsDetached() bool {\n\tf.propertiesMu.RLock()\n\tdefer f.propertiesMu.RUnlock()\n\n\treturn f.detached\n}\n\n// setDetached sets the frame detachment.\nfunc (f *Frame) setDetached(detached bool) {\n\tf.propertiesMu.Lock()\n\tdefer f.propertiesMu.Unlock()\n\n\tf.detached = detached\n}\n\n// IsEditable returns true if the first element that matches the selector\n// is editable. Otherwise, returns false.\nfunc (f *Frame) IsEditable(selector string, opts *FrameIsEditableOptions) (bool, error) {\n\tf.log.Debugf(\"Frame:IsEditable\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\teditable, err := f.isEditable(selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q editable: %w\", selector, err)\n\t}\n\n\treturn editable, nil\n}\n\nfunc (f *Frame) isEditable(selector string, opts *FrameIsEditableOptions) (bool, error) {\n\tisEditable := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\tv, err := handle.isEditable(apiCtx, 0) // Zero timeout when checking state\n\t\tif errors.Is(err, ErrTimedOut) {       // We don't care about timeout errors here!\n\t\t\treturn v, nil\n\t\t}\n\t\treturn v, err\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, isEditable, []string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn false, errorFromDOMError(err)\n\t}\n\n\tbv, ok := v.(bool)\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"checking is %q editable: unexpected type %T\", selector, v)\n\t}\n\n\treturn bv, nil\n}\n\n// IsEnabled returns true if the first element that matches the selector\n// is enabled. Otherwise, returns false.\nfunc (f *Frame) IsEnabled(selector string, opts *FrameIsEnabledOptions) (bool, error) {\n\tf.log.Debugf(\"Frame:IsEnabled\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tenabled, err := f.isEnabled(selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q enabled: %w\", selector, err)\n\t}\n\n\treturn enabled, nil\n}\n\nfunc (f *Frame) isEnabled(selector string, opts *FrameIsEnabledOptions) (bool, error) {\n\tisEnabled := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\tv, err := handle.isEnabled(apiCtx, 0) // Zero timeout when checking state\n\t\tif errors.Is(err, ErrTimedOut) {      // We don't care about timeout errors here!\n\t\t\treturn v, nil\n\t\t}\n\t\treturn v, err\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, isEnabled, []string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn false, errorFromDOMError(err)\n\t}\n\n\tbv, ok := v.(bool)\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"checking is %q enabled: unexpected type %T\", selector, v)\n\t}\n\n\treturn bv, nil\n}\n\n// IsDisabled returns true if the first element that matches the selector\n// is disabled. Otherwise, returns false.\nfunc (f *Frame) IsDisabled(selector string, opts *FrameIsDisabledOptions) (bool, error) {\n\tf.log.Debugf(\"Frame:IsDisabled\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tdisabled, err := f.isDisabled(selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q disabled: %w\", selector, err)\n\t}\n\n\treturn disabled, nil\n}\n\nfunc (f *Frame) isDisabled(selector string, opts *FrameIsDisabledOptions) (bool, error) {\n\tisDisabled := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\tv, err := handle.isDisabled(apiCtx, 0) // Zero timeout when checking state\n\t\tif errors.Is(err, ErrTimedOut) {       // We don't care about timeout errors here!\n\t\t\treturn v, nil\n\t\t}\n\t\treturn v, err\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, isDisabled, []string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn false, errorFromDOMError(err)\n\t}\n\n\tbv, ok := v.(bool)\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"checking is %q disabled: unexpected type %T\", selector, v)\n\t}\n\n\treturn bv, nil\n}\n\n// IsHidden returns true if the first element that matches the selector\n// is hidden. Otherwise, returns false.\nfunc (f *Frame) IsHidden(selector string, opts *FrameIsHiddenOptions) (bool, error) {\n\tf.log.Debugf(\"Frame:IsHidden\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\thidden, err := f.isHidden(selector, opts)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn hidden, nil\n}\n\nfunc (f *Frame) isHidden(selector string, opts *FrameIsHiddenOptions) (bool, error) {\n\tisHidden := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\tv, err := handle.isHidden(apiCtx) // Zero timeout when checking state\n\t\tif errors.Is(err, ErrTimedOut) {  // We don't care about timeout errors here!\n\t\t\treturn v, nil\n\t\t}\n\t\treturn v, err\n\t}\n\tv, err := f.runActionOnSelector(f.ctx, selector, opts.Strict, isHidden, func() bool { return true })\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q hidden: %w\", selector, err)\n\t}\n\n\treturn v, nil\n}\n\n// IsVisible returns true if the first element that matches the selector\n// is visible. Otherwise, returns false.\nfunc (f *Frame) IsVisible(selector string, opts *FrameIsVisibleOptions) (bool, error) {\n\tf.log.Debugf(\"Frame:IsVisible\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tvisible, err := f.isVisible(selector, opts)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn visible, nil\n}\n\nfunc (f *Frame) isVisible(selector string, opts *FrameIsVisibleOptions) (bool, error) {\n\tisVisible := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\tv, err := handle.isVisible(apiCtx) // Zero timeout when checking state\n\t\tif errors.Is(err, ErrTimedOut) {   // We don't care about timeout errors here!\n\t\t\treturn v, nil\n\t\t}\n\t\treturn v, err\n\t}\n\tv, err := f.runActionOnSelector(f.ctx, selector, opts.Strict, isVisible, func() bool { return false })\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q visible: %w\", selector, err)\n\t}\n\n\treturn v, nil\n}\n\n// ID returns the frame id.\nfunc (f *Frame) ID() string {\n\tf.propertiesMu.RLock()\n\tdefer f.propertiesMu.RUnlock()\n\n\treturn f.id.String()\n}\n\n// Locator creates and returns a new locator for this frame.\nfunc (f *Frame) Locator(selector string, opts *LocatorOptions) *Locator {\n\tf.log.Debugf(\"Frame:Locator\", \"fid:%s furl:%q selector:%q opts:%+v\", f.ID(), f.URL(), selector, opts)\n\n\treturn NewLocator(f.ctx, opts, selector, f, f.log)\n}\n\n// FrameLocator is a convenience method equivalent to frame.locator(selector).contentFrame().\nfunc (f *Frame) FrameLocator(selector string) *FrameLocator {\n\tf.log.Debugf(\"Frame:FrameLocator\", \"fid:%s furl:%q selector:%q\", f.ID(), f.URL(), selector)\n\n\treturn f.Locator(selector, nil).ContentFrame()\n}\n\n// LoaderID returns the ID of the frame that loaded this frame.\nfunc (f *Frame) LoaderID() string {\n\tf.propertiesMu.RLock()\n\tdefer f.propertiesMu.RUnlock()\n\n\treturn f.loaderID\n}\n\n// Name returns the frame name.\nfunc (f *Frame) Name() string {\n\tf.propertiesMu.RLock()\n\tdefer f.propertiesMu.RUnlock()\n\n\treturn f.name\n}\n\n// Query runs a selector query against the document tree, returning the first matching element or\n// \"null\" if no match is found.\nfunc (f *Frame) Query(selector string, strict bool) (*ElementHandle, error) {\n\tf.log.Debugf(\"Frame:Query\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tdocument, err := f.document()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting document: %w\", err)\n\t}\n\treturn document.Query(selector, strict)\n}\n\n// QueryAll runs a selector query against the document tree, returning all matching elements.\nfunc (f *Frame) QueryAll(selector string) ([]*ElementHandle, error) {\n\tf.log.Debugf(\"Frame:QueryAll\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tdocument, err := f.document()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting document: %w\", err)\n\t}\n\treturn document.QueryAll(selector)\n}\n\n// Page returns page that owns frame.\nfunc (f *Frame) Page() *Page {\n\treturn f.manager.page\n}\n\n// ParentFrame returns the parent frame, if one exists.\nfunc (f *Frame) ParentFrame() *Frame {\n\treturn f.parentFrame\n}\n\n// Press presses the given key for the first element found that matches the selector.\nfunc (f *Frame) Press(selector, key string, opts *FramePressOptions) error {\n\tf.log.Debugf(\"Frame:Press\", \"fid:%s furl:%q sel:%q key:%q\", f.ID(), f.URL(), selector, key)\n\n\tif err := f.press(selector, key, opts); err != nil {\n\t\treturn fmt.Errorf(\"pressing %q on %q: %w\", key, selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) press(selector, key string, opts *FramePressOptions) error {\n\tpress := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.press(apiCtx, key, opts.ToKeyboardOptions())\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, press,\n\t\t[]string{}, false, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// SelectOption selects the given options and returns the array of\n// option values of the first element found that matches the selector.\nfunc (f *Frame) SelectOption(selector string, values []any, popts *FrameSelectOptionOptions) ([]string, error) {\n\tf.log.Debugf(\"Frame:SelectOption\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tv, err := f.selectOption(selector, values, popts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selecting option on %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn v, nil\n}\n\nfunc (f *Frame) selectOption(selector string, values []any, opts *FrameSelectOptionOptions) ([]string, error) {\n\tselectOption := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.selectOption(apiCtx, values)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, selectOption,\n\t\t[]string{}, opts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn nil, errorFromDOMError(err)\n\t}\n\tselectHandle, ok := v.(jsHandle)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected select element type %T\", v)\n\t}\n\n\t// pack the selected <option> values inside <select> into a slice\n\toptHandles, err := selectHandle.getProperties()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getProperties: %w\", err)\n\t}\n\tvals := make([]string, 0, len(optHandles))\n\tfor _, oh := range optHandles {\n\t\tval, err := oh.JSONValue()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"reading value: %w\", err)\n\t\t}\n\t\tvals = append(vals, val)\n\t\tif err := oh.dispose(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"optionHandle.dispose: %w\", err)\n\t\t}\n\t}\n\tif err := selectHandle.dispose(); err != nil {\n\t\treturn nil, fmt.Errorf(\"selectHandle.dispose: %w\", err)\n\t}\n\n\treturn vals, nil\n}\n\n// SetContent replaces the entire HTML document content.\nfunc (f *Frame) SetContent(html string, _ *FrameSetContentOptions) error {\n\tf.log.Debugf(\"Frame:SetContent\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\t// TODO(@inancgumus): Respect the FrameSetContentOptions before executing the action.\n\t// A solution is similar to the logic in `WaitForLoadState`.\n\n\tjs := `(html) => {\n\t\twindow.stop();\n\t\tdocument.open();\n\t\tdocument.write(html);\n\t\tdocument.close();\n\t}`\n\n\tf.waitForExecutionContext(utilityWorld)\n\n\teopts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tif _, err := f.evaluate(f.ctx, utilityWorld, eopts, js, html); err != nil {\n\t\treturn fmt.Errorf(\"setting content: %w\", err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\n// SetInputFiles sets input files for the selected element.\nfunc (f *Frame) SetInputFiles(selector string, pfiles *Files, popts *FrameSetInputFilesOptions) error {\n\tf.log.Debugf(\"Frame:SetInputFiles\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.setInputFiles(selector, pfiles, popts); err != nil {\n\t\treturn fmt.Errorf(\"setting input files on %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\n// Tap the first element that matches the selector.\nfunc (f *Frame) Tap(selector string, opts *FrameTapOptions) error {\n\tf.log.Debugf(\"Frame:Tap\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tif err := f.tap(selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"tapping on %q: %w\", selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) tap(selector string, opts *FrameTapOptions) error {\n\ttap := func(apiCtx context.Context, handle *ElementHandle, p *Position) (any, error) {\n\t\treturn nil, handle.tap(apiCtx, p)\n\t}\n\tact := f.newPointerAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, tap, &opts.ElementHandleBasePointerOptions,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\nfunc (f *Frame) setInputFiles(selector string, files *Files, opts *FrameSetInputFilesOptions) error {\n\tsetInputFiles := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.setInputFiles(apiCtx, files)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict,\n\t\tsetInputFiles, []string{},\n\t\topts.Force, opts.NoWaitAfter, opts.Timeout,\n\t)\n\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// TextContent returns the textContent attribute of the first element found\n// that matches the selector. The second return value is true if the returned\n// text content is not null or empty, and false otherwise.\nfunc (f *Frame) TextContent(selector string, popts *FrameTextContentOptions) (string, bool, error) {\n\tf.log.Debugf(\"Frame:TextContent\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tv, ok, err := f.textContent(selector, popts)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"getting text content of %q: %w\", selector, err)\n\t}\n\n\treturn v, ok, nil\n}\n\nfunc (f *Frame) textContent(selector string, opts *FrameTextContentOptions) (string, bool, error) {\n\tTextContent := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.textContent(apiCtx)\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, TextContent,\n\t\t[]string{}, false, true, opts.Timeout,\n\t)\n\tv, err := call(f.ctx, act, opts.Timeout)\n\tif err != nil {\n\t\treturn \"\", false, errorFromDOMError(err)\n\t}\n\tif v == nil {\n\t\treturn \"\", false, nil\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", false, fmt.Errorf(\"unexpected type %T (expecting string)\", v)\n\t}\n\n\treturn s, true, nil\n}\n\n// Timeout will return the default timeout or the one set by the user.\n// It's an internal method not to be exposed as a JS API.\nfunc (f *Frame) Timeout() time.Duration {\n\treturn f.defaultTimeout()\n}\n\n// Title returns the title of the frame.\nfunc (f *Frame) Title() (string, error) {\n\tf.log.Debugf(\"Frame:Title\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tjs := `() => document.title`\n\tv, err := f.Evaluate(js)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting frame title: %w\", err)\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"getting frame title: expected string, got %T\", v)\n\t}\n\n\treturn s, nil\n}\n\n// Type text on the first element found matches the selector.\nfunc (f *Frame) Type(selector, text string, popts *FrameTypeOptions) error {\n\tf.log.Debugf(\"Frame:Type\", \"fid:%s furl:%q sel:%q text:%q\", f.ID(), f.URL(), selector, text)\n\n\tif err := f.typ(selector, text, popts); err != nil {\n\t\treturn fmt.Errorf(\"typing %q in %q: %w\", text, selector, err)\n\t}\n\n\tapplySlowMo(f.ctx)\n\n\treturn nil\n}\n\nfunc (f *Frame) typ(selector, text string, opts *FrameTypeOptions) error {\n\ttypeText := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn nil, handle.typ(apiCtx, text, opts.ToKeyboardOptions())\n\t}\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, opts.Strict, typeText,\n\t\t[]string{}, false, opts.NoWaitAfter, opts.Timeout,\n\t)\n\tif _, err := call(f.ctx, act, opts.Timeout); err != nil {\n\t\treturn errorFromDOMError(err)\n\t}\n\n\treturn nil\n}\n\n// URL returns the frame URL.\nfunc (f *Frame) URL() string {\n\tif f == nil {\n\t\treturn \"\"\n\t}\n\n\tf.propertiesMu.RLock()\n\tdefer f.propertiesMu.RUnlock()\n\n\treturn f.url\n}\n\n// URL set the frame URL.\nfunc (f *Frame) setURL(url string) {\n\tdefer f.propertiesMu.Unlock()\n\tf.propertiesMu.Lock()\n\n\tf.url = url\n}\n\n// WaitForFunction waits for the given predicate to return a truthy value.\nfunc (f *Frame) WaitForFunction(js string, opts *FrameWaitForFunctionOptions, jsArgs ...any) (any, error) {\n\tf.log.Debugf(\"Frame:WaitForFunction\", \"fid:%s furl:%q\", f.ID(), f.URL())\n\n\tvar polling any = opts.Polling\n\tif opts.Polling == PollingInterval {\n\t\tpolling = opts.Interval\n\t}\n\n\tresult, err := f.waitForFunction(f.ctx, mainWorld, js,\n\t\tpolling, opts.Timeout, jsArgs...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// prevent passing a non-nil interface to the upper layers.\n\tif result == nil {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\treturn result, err\n}\n\nfunc (f *Frame) waitForFunction(\n\tapiCtx context.Context, world executionWorld, js string,\n\tpolling any, timeout time.Duration, args ...any,\n) (any, error) {\n\tf.log.Debugf(\n\t\t\"Frame:waitForFunction\",\n\t\t\"fid:%s furl:%q world:%s poll:%s timeout:%s\",\n\t\tf.ID(), f.URL(), world, polling, timeout)\n\n\tf.waitForExecutionContext(world)\n\n\tf.executionContextMu.RLock()\n\tdefer f.executionContextMu.RUnlock()\n\n\texecCtx := f.executionContexts[world]\n\tif execCtx == nil {\n\t\treturn nil, fmt.Errorf(\"waiting for function: execution context %q not found\", world)\n\t}\n\tinjected, err := execCtx.getInjectedScript(apiCtx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting injected script: %w\", err)\n\t}\n\n\tpageFn := `\n\t\t(injected, predicate, polling, timeout, ...args) => {\n\t\t\treturn injected.waitForPredicateFunction(predicate, polling, timeout, ...args);\n\t\t}\n\t`\n\n\t// First evaluate the predicate function itself to get its handle.\n\topts := evalOptions{forceCallable: false, returnByValue: false}\n\thandle, err := execCtx.eval(apiCtx, opts, js)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"waiting for function, getting handle: %w\", err)\n\t}\n\n\t// Then evaluate the injected function call, passing it the predicate\n\t// function handle and the rest of the arguments.\n\topts = evalOptions{forceCallable: true, returnByValue: false}\n\tresult, err := execCtx.eval(\n\t\tapiCtx, opts, pageFn, append([]any{\n\t\t\tinjected,\n\t\t\thandle,\n\t\t\tpolling,\n\t\t\ttimeout.Milliseconds(), // The JS value is in ms integers\n\t\t}, args...)...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"waiting for function, polling: %w\", err)\n\t}\n\t// prevent passing a non-nil interface to the upper layers.\n\tif result == nil {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\treturn result, nil\n}\n\n// WaitForLoadState waits for the given load state to be reached.\n// This will unblock if that lifecycle event has already been received.\nfunc (f *Frame) WaitForLoadState(state string, popts *FrameWaitForLoadStateOptions) error {\n\tf.log.Debugf(\"Frame:WaitForLoadState\", \"fid:%s furl:%q state:%s\", f.ID(), f.URL(), state)\n\tdefer f.log.Debugf(\"Frame:WaitForLoadState:return\", \"fid:%s furl:%q state:%s\", f.ID(), f.URL(), state)\n\n\ttimeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, popts.Timeout)\n\tdefer timeoutCancel()\n\n\twaitUntil := LifecycleEventLoad\n\tif state != \"\" {\n\t\tif err := waitUntil.UnmarshalText([]byte(state)); err != nil {\n\t\t\treturn fmt.Errorf(\"unmarshaling wait for load state %q: %w\", state, err)\n\t\t}\n\t}\n\n\tlifecycleEvent, lifecycleEventCancel := createWaitForEventPredicateHandler(\n\t\ttimeoutCtx,\n\t\tf,\n\t\t[]string{EventFrameAddLifecycle},\n\t\tfunc(data any) bool {\n\t\t\tif le, ok := data.(FrameLifecycleEvent); ok {\n\t\t\t\treturn le.Event == waitUntil\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\tdefer lifecycleEventCancel()\n\n\tif f.hasLifecycleEventFired(waitUntil) {\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase <-lifecycleEvent:\n\tcase <-timeoutCtx.Done():\n\t\treturn fmt.Errorf(\"waiting for load state %q: %w\", state, ContextErr(timeoutCtx))\n\t}\n\n\treturn nil\n}\n\n// WaitForNavigation waits for the given navigation lifecycle event to happen.\n// RegExMatcher should be non-nil to be able to test against a URL pattern in the options.\n//\n//nolint:funlen\nfunc (f *Frame) WaitForNavigation(opts *FrameWaitForNavigationOptions, rm RegExMatcher) (*Response, error) {\n\tf.log.Debugf(\"Frame:WaitForNavigation\",\n\t\t\"fid:%s furl:%s url:%s\", f.ID(), f.URL(), opts.URL)\n\tdefer f.log.Debugf(\"Frame:WaitForNavigation:return\",\n\t\t\"fid:%s furl:%s\", f.ID(), f.URL())\n\n\ttimeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, opts.Timeout)\n\n\t// Create URL matcher based on the pattern\n\tmatcher, err := newPatternMatcher(opts.URL, rm)\n\tif err != nil {\n\t\ttimeoutCancel()\n\t\treturn nil, fmt.Errorf(\"parsing URL pattern: %w\", err)\n\t}\n\n\tvar matcherErr error\n\tnavEvtCh, navEvtCancel := createWaitForEventPredicateHandler(timeoutCtx, f, []string{EventFrameNavigation},\n\t\tfunc(data any) bool {\n\t\t\tif navEvt, ok := data.(*NavigationEvent); ok {\n\t\t\t\t// Check if the navigation URL matches the pattern\n\t\t\t\tmatched, err := matcher(navEvt.url)\n\t\t\t\tif err != nil {\n\t\t\t\t\tmatcherErr = err\n\t\t\t\t\t// Return true here even though it's not correct and no match\n\t\t\t\t\t// was found. We need this to exit asap so that the error can be\n\t\t\t\t\t// propagated to the caller.\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t\treturn matched\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\n\tlifecycleEvtCh, lifecycleEvtCancel := createWaitForEventPredicateHandler(\n\t\ttimeoutCtx, f, []string{EventFrameAddLifecycle},\n\t\tfunc(data any) bool {\n\t\t\t// Wait for the lifecycle event to happen.\n\t\t\tif le, ok := data.(FrameLifecycleEvent); ok {\n\t\t\t\treturn le.Event == opts.WaitUntil\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\n\thandleTimeoutError := f.handleWaitForNavigationTimeoutErrorFn(opts)\n\n\tdefer func() {\n\t\ttimeoutCancel()\n\t\tnavEvtCancel()\n\t\tlifecycleEvtCancel()\n\t}()\n\n\tvar (\n\t\tresp       *Response\n\t\tsameDocNav bool\n\t)\n\tselect {\n\tcase evt := <-navEvtCh:\n\t\tif matcherErr != nil {\n\t\t\treturn nil, matcherErr\n\t\t}\n\t\tif e, ok := evt.(*NavigationEvent); ok {\n\t\t\tif e.err != nil {\n\t\t\t\treturn nil, e.err\n\t\t\t}\n\n\t\t\tif e.newDocument == nil {\n\t\t\t\tsameDocNav = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// request could be nil if navigating to e.g. BlankPage.\n\t\t\treq := e.newDocument.request\n\t\t\tif req != nil {\n\t\t\t\treq.responseMu.RLock()\n\t\t\t\tresp = req.response\n\t\t\t\treq.responseMu.RUnlock()\n\t\t\t}\n\t\t}\n\tcase <-timeoutCtx.Done():\n\t\treturn nil, handleTimeoutError(ContextErr(timeoutCtx))\n\t}\n\n\t// A lifecycle event won't be received when navigating within the same\n\t// document, so don't wait for it. The event might've also already been\n\t// fired once we're here, so also skip waiting in that case.\n\tif !sameDocNav && !f.hasLifecycleEventFired(opts.WaitUntil) {\n\t\tselect {\n\t\tcase <-lifecycleEvtCh:\n\t\tcase <-timeoutCtx.Done():\n\t\t\treturn nil, handleTimeoutError(ContextErr(timeoutCtx))\n\t\t}\n\t}\n\n\t// Since the response will be in an interface, it will never be nil,\n\t// so we need to return nil explicitly.\n\tif resp == nil {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\treturn resp, nil\n}\n\nfunc (f *Frame) handleWaitForNavigationTimeoutErrorFn(opts *FrameWaitForNavigationOptions) func(err error) error {\n\treturn func(err error) error {\n\t\tf.log.Debugf(\"Frame:WaitForNavigation\",\n\t\t\t\"fid:%v furl:%s timeoutCtx done: %v\", f.ID(), f.URL(), err)\n\t\tif err != nil {\n\t\t\te := &k6ext.UserFriendlyError{\n\t\t\t\tErr:     err,\n\t\t\t\tTimeout: opts.Timeout,\n\t\t\t}\n\t\t\tif opts.URL != \"\" {\n\t\t\t\treturn fmt.Errorf(\"waiting for navigation to URL matching %q: %w\", opts.URL, e)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"waiting for navigation: %w\", e)\n\t\t}\n\n\t\treturn nil\n\t}\n}\n\n// WaitForSelector waits for the given selector to match the waiting criteria.\nfunc (f *Frame) WaitForSelector(selector string, popts *FrameWaitForSelectorOptions) (*ElementHandle, error) {\n\thandle, err := f.waitForSelectorRetry(selector, popts, maxRetry)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"waiting for selector %q: %w\", selector, err)\n\t}\n\n\treturn handle, nil\n}\n\n// WaitForTimeout waits the specified amount of milliseconds.\nfunc (f *Frame) WaitForTimeout(timeout int64) {\n\tto := time.Duration(timeout) * time.Millisecond\n\n\tf.log.Debugf(\"Frame:WaitForTimeout\", \"fid:%s furl:%q timeout:%s\", f.ID(), f.URL(), to)\n\tdefer f.log.Debugf(\"Frame:WaitForTimeout:return\", \"fid:%s furl:%q timeout:%s\", f.ID(), f.URL(), to)\n\n\tselect {\n\tcase <-f.ctx.Done():\n\tcase <-time.After(to):\n\t}\n}\n\n// WaitForURL waits for the frame to navigate to a URL matching the given pattern.\n// RegExMatcher should be non-nil to be able to test against a URL pattern.\nfunc (f *Frame) WaitForURL(urlPattern string, opts *FrameWaitForURLOptions, rm RegExMatcher) error {\n\tf.log.Debugf(\"Frame:WaitForURL\", \"fid:%s furl:%q pattern:%s\", f.ID(), f.URL(), urlPattern)\n\tdefer f.log.Debugf(\"Frame:WaitForURL:return\", \"fid:%s furl:%q pattern:%s\", f.ID(), f.URL(), urlPattern)\n\n\tmatched, err := rm.Match(urlPattern, f.URL())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"waiting for URL %q: %w\", urlPattern, err)\n\t}\n\tif matched {\n\t\t// Already at target URL, just wait for load state\n\t\treturn f.WaitForLoadState(opts.WaitUntil.String(), &FrameWaitForLoadStateOptions{\n\t\t\tTimeout: opts.Timeout,\n\t\t})\n\t}\n\n\t// Wait for navigation to matching URL\n\tnavOpts := &FrameWaitForNavigationOptions{\n\t\tURL:       urlPattern,\n\t\tTimeout:   opts.Timeout,\n\t\tWaitUntil: opts.WaitUntil,\n\t}\n\t_, err = f.WaitForNavigation(navOpts, rm)\n\n\treturn err\n}\n\nfunc (f *Frame) adoptBackendNodeID(world executionWorld, id cdp.BackendNodeID) (*ElementHandle, error) {\n\tf.log.Debugf(\"Frame:adoptBackendNodeID\", \"fid:%s furl:%q world:%s id:%d\", f.ID(), f.URL(), world, id)\n\n\tf.executionContextMu.RLock()\n\tdefer f.executionContextMu.RUnlock()\n\n\tec := f.executionContexts[world]\n\tif ec == nil {\n\t\treturn nil, fmt.Errorf(\"execution context %q not found\", world)\n\t}\n\treturn ec.adoptBackendNodeID(id)\n}\n\nfunc (f *Frame) evaluate(\n\tapiCtx context.Context,\n\tworld executionWorld,\n\topts evalOptions, pageFunc string, args ...any,\n) (any, error) {\n\tf.log.Debugf(\"Frame:evaluate\", \"fid:%s furl:%q world:%s opts:%s\", f.ID(), f.URL(), world, opts)\n\n\tf.executionContextMu.RLock()\n\tdefer f.executionContextMu.RUnlock()\n\n\tec := f.executionContexts[world]\n\tif ec == nil {\n\t\treturn nil, fmt.Errorf(\"execution context %q not found\", world)\n\t}\n\n\teh, err := ec.eval(apiCtx, opts, pageFunc, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w\", err)\n\t}\n\n\treturn eh, nil\n}\n\nfunc (f *Frame) evaluateWithSelector(selector string, pageFunc string, args ...any) (any, error) {\n\tf.log.Debugf(\"Frame:evaluateWithSelector\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tevaluate := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.Evaluate(pageFunc, args...)\n\t}\n\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, true, evaluate, []string{}, false, true, f.defaultTimeout(),\n\t)\n\tv, err := call(f.ctx, act, f.defaultTimeout())\n\tif err != nil {\n\t\treturn nil, errorFromDOMError(err)\n\t}\n\treturn v, nil\n}\n\nfunc (f *Frame) evaluateHandleWithSelector(selector string, pageFunc string, args ...any) (JSHandleAPI, error) {\n\tf.log.Debugf(\"Frame:evaluateHandleWithSelector\", \"fid:%s furl:%q sel:%q\", f.ID(), f.URL(), selector)\n\n\tevaluateHandle := func(apiCtx context.Context, handle *ElementHandle) (any, error) {\n\t\treturn handle.EvaluateHandle(pageFunc, args...)\n\t}\n\n\tact := f.newAction(\n\t\tselector, DOMElementStateAttached, true, evaluateHandle, []string{}, false, true, f.defaultTimeout(),\n\t)\n\tv, err := call(f.ctx, act, f.defaultTimeout())\n\tif err != nil {\n\t\treturn nil, errorFromDOMError(err)\n\t}\n\n\thandle, ok := v.(JSHandleAPI)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"evaluating handle of %q: unexpected type %T\", selector, v)\n\t}\n\n\treturn handle, nil\n}\n\n// frameExecutionContext represents a JS execution context that belongs to Frame.\ntype frameExecutionContext interface {\n\t// adoptBackendNodeID adopts specified backend node into this execution\n\t// context from another execution context.\n\tadoptBackendNodeID(backendNodeID cdp.BackendNodeID) (*ElementHandle, error)\n\n\t// adoptElementHandle adopts the specified element handle into this\n\t// execution context from another execution context.\n\tadoptElementHandle(elementHandle *ElementHandle) (*ElementHandle, error)\n\n\t// eval evaluates the provided JavaScript within this execution context and\n\t// returns a value or handle.\n\teval(\n\t\tapiCtx context.Context, opts evalOptions, js string, args ...any,\n\t) (res any, err error)\n\n\t// getInjectedScript returns a JS handle to the injected script of helper\n\t// functions.\n\tgetInjectedScript(apiCtx context.Context) (JSHandleAPI, error)\n\n\t// Eval evaluates the provided JavaScript within this execution context and\n\t// returns a value or handle.\n\tEval(apiCtx context.Context, js string, args ...any) (any, error)\n\n\t// EvalHandle evaluates the provided JavaScript within this execution\n\t// context and returns a JSHandle.\n\tEvalHandle(apiCtx context.Context, js string, args ...any) (JSHandleAPI, error)\n\n\t// Frame returns the frame that this execution context belongs to.\n\tFrame() *Frame\n\n\t// id returns the CDP runtime ID of this execution context.\n\tID() runtime.ExecutionContextID\n}\n\nfunc (f *Frame) runActionOnSelector(\n\tctx context.Context, selector string, strict bool, fn elementHandleActionFunc, nullResponder func() bool,\n) (bool, error) {\n\thandle, err := f.Query(selector, strict)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"query: %w\", err)\n\t}\n\tif handle == nil {\n\t\tf.log.Debugf(\"Frame:runActionOnSelector:nilHandler\", \"fid:%s furl:%q selector:%s\", f.ID(), f.URL(), selector)\n\t\treturn nullResponder(), err\n\t}\n\n\tv, err := fn(ctx, handle)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"calling function: %w\", err)\n\t}\n\n\tbv, ok := v.(bool)\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"unexpected type %T\", v)\n\t}\n\n\treturn bv, nil\n}\n\n//nolint:unparam\nfunc (f *Frame) newAction(\n\tselector string, state DOMElementState, strict bool, fn elementHandleActionFunc, states []string,\n\tforce, noWaitAfter bool, timeout time.Duration,\n) func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t// We execute a frame action in the following steps:\n\t// 1. Find element matching specified selector\n\t// 2. Wait for it to reach specified DOM state\n\t// 3. Run element handle action (incl. actionability checks)\n\treturn func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t\twaitOpts := NewFrameWaitForSelectorOptions(f.defaultTimeout())\n\t\twaitOpts.State = state\n\t\twaitOpts.Strict = strict\n\t\thandle, err := f.waitForSelector(selector, waitOpts)\n\t\tif err != nil {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase errCh <- err:\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif handle == nil {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase resultCh <- nil:\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tf := handle.newAction(states, fn, force, noWaitAfter, timeout)\n\t\tf(apiCtx, resultCh, errCh)\n\t}\n}\n\n//nolint:unparam\nfunc (f *Frame) newPointerAction(\n\tselector string, state DOMElementState, strict bool, fn elementHandlePointerActionFunc,\n\topts *ElementHandleBasePointerOptions,\n) func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t// We execute a frame pointer action in the following steps:\n\t// 1. Find element matching specified selector\n\t// 2. Wait for it to reach specified DOM state\n\t// 3. Run element handle action (incl. actionability checks)\n\treturn func(apiCtx context.Context, resultCh chan any, errCh chan error) {\n\t\twaitOpts := NewFrameWaitForSelectorOptions(f.defaultTimeout())\n\t\twaitOpts.State = state\n\t\twaitOpts.Strict = strict\n\t\thandle, err := f.waitForSelector(selector, waitOpts)\n\t\tif err != nil {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase errCh <- err:\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif handle == nil {\n\t\t\tselect {\n\t\t\tcase <-apiCtx.Done():\n\t\t\tcase resultCh <- nil:\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tf := handle.newPointerAction(fn, opts)\n\t\tf(apiCtx, resultCh, errCh)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/frame_manager.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\tcdppage \"github.com/chromedp/cdproto/page\"\n)\n\n// FrameManager manages all frames in a page and their life-cycles, it's a purely internal component.\ntype FrameManager struct {\n\tctx             context.Context\n\tsession         session\n\tpage            *Page\n\ttimeoutSettings *TimeoutSettings\n\n\t// protects from the data race between:\n\t// - Frame.startNetworkIdleTimer.frameLifecycleEvent.recalculateLifecycle\n\t// - *FrameSession.initEvents.onFrameNavigated->FrameManager.frameNavigated\n\tmainFrameMu sync.RWMutex\n\tmainFrame   *Frame\n\n\t// Needed as the frames map will be accessed from multiple Go routines,\n\t// the main VU/JS go routine and the Go routine listening for CDP messages.\n\tframesMu sync.RWMutex\n\tframes   map[cdp.FrameID]*Frame\n\n\tbarriersMu sync.RWMutex\n\tbarriers   []*Barrier\n\n\tlogger *log.Logger\n\tid     int64\n}\n\n// frameManagerID is used for giving a unique ID to a frame manager.\nvar frameManagerID int64 //nolint:gochecknoglobals // TODO(@mstoykov): move it to the module instance\n\n// NewFrameManager creates a new HTML document frame manager.\nfunc NewFrameManager(\n\tctx context.Context,\n\ts session,\n\tp *Page,\n\tts *TimeoutSettings,\n\tl *log.Logger,\n) *FrameManager {\n\tm := &FrameManager{\n\t\tctx:             ctx,\n\t\tsession:         s,\n\t\tpage:            p,\n\t\ttimeoutSettings: ts,\n\t\tframes:          make(map[cdp.FrameID]*Frame),\n\t\tbarriers:        make([]*Barrier, 0),\n\t\tlogger:          l,\n\t\tid:              atomic.AddInt64(&frameManagerID, 1),\n\t}\n\n\tm.logger.Debugf(\"FrameManager:New\", \"fmid:%d\", m.ID())\n\n\treturn m\n}\n\nfunc (m *FrameManager) addBarrier(b *Barrier) {\n\tm.logger.Debugf(\"FrameManager:addBarrier\", \"fmid:%d\", m.ID())\n\n\tm.barriersMu.Lock()\n\tdefer m.barriersMu.Unlock()\n\tm.barriers = append(m.barriers, b)\n}\n\nfunc (m *FrameManager) removeBarrier(b *Barrier) {\n\tm.logger.Debugf(\"FrameManager:removeBarrier\", \"fmid:%d\", m.ID())\n\n\tm.barriersMu.Lock()\n\tdefer m.barriersMu.Unlock()\n\tindex := -1\n\tfor i, b2 := range m.barriers {\n\t\tif b == b2 {\n\t\t\tindex = i\n\t\t\tbreak\n\t\t}\n\t}\n\tm.barriers = append(m.barriers[:index], m.barriers[index+1:]...)\n}\n\nfunc (m *FrameManager) frameAbortedNavigation(frameID cdp.FrameID, errorText, documentID string) {\n\tm.logger.Debugf(\"FrameManager:frameAbortedNavigation\",\n\t\t\"fmid:%d fid:%v err:%s docid:%s\",\n\t\tm.ID(), frameID, errorText, documentID)\n\n\tm.framesMu.Lock()\n\tdefer m.framesMu.Unlock()\n\n\tframe := m.frames[frameID]\n\tif frame == nil {\n\t\treturn\n\t}\n\n\tframe.pendingDocumentMu.Lock()\n\n\tif frame.pendingDocument == nil {\n\t\tframe.pendingDocumentMu.Unlock()\n\t\treturn\n\t}\n\tif documentID != \"\" && frame.pendingDocument.documentID != documentID {\n\t\tframe.pendingDocumentMu.Unlock()\n\t\treturn\n\t}\n\n\tm.logger.Debugf(\"FrameManager:frameAbortedNavigation:emit:EventFrameNavigation\",\n\t\t\"fmid:%d fid:%v err:%s docid:%s fname:%s furl:%s\",\n\t\tm.ID(), frameID, errorText, documentID, frame.Name(), frame.URL())\n\n\tne := &NavigationEvent{\n\t\turl:         frame.URL(),\n\t\tname:        frame.Name(),\n\t\tnewDocument: frame.pendingDocument,\n\t\terr:         errors.New(errorText),\n\t}\n\tframe.pendingDocument = nil\n\n\tframe.pendingDocumentMu.Unlock()\n\n\tframe.emit(EventFrameNavigation, ne)\n}\n\nfunc (m *FrameManager) frameAttached(frameID cdp.FrameID, parentFrameID cdp.FrameID) {\n\tm.logger.Debugf(\"FrameManager:frameAttached\", \"fmid:%d fid:%v pfid:%v\",\n\t\tm.ID(), frameID, parentFrameID)\n\n\tm.framesMu.Lock()\n\tdefer m.framesMu.Unlock()\n\n\tif _, ok := m.frames[frameID]; ok {\n\t\tm.logger.Debugf(\"FrameManager:frameAttached:return\",\n\t\t\t\"fmid:%d fid:%v pfid:%v cannot find frame\",\n\t\t\tm.ID(), frameID, parentFrameID)\n\n\t\treturn\n\t}\n\tif parentFrame, ok := m.frames[parentFrameID]; ok {\n\t\tframe := NewFrame(m.ctx, m, parentFrame, frameID, m.logger)\n\t\t// TODO: create a addFrame func\n\t\tm.frames[frameID] = frame\n\t\tparentFrame.addChildFrame(frame)\n\n\t\tm.logger.Debugf(\"FrameManager:frameAttached:emit:EventPageFrameAttached\",\n\t\t\t\"fmid:%d fid:%v pfid:%v\", m.ID(), frameID, parentFrameID)\n\t}\n}\n\nfunc (m *FrameManager) frameDetached(frameID cdp.FrameID, reason cdppage.FrameDetachedReason) error {\n\tm.logger.Debugf(\"FrameManager:frameDetached\", \"fmid:%d fid:%v\", m.ID(), frameID)\n\n\tframe, ok := m.getFrameByID(frameID)\n\tif !ok {\n\t\tm.logger.Debugf(\"FrameManager:frameDetached:return\",\n\t\t\t\"fmid:%d fid:%v cannot find frame\",\n\t\t\tm.ID(), frameID)\n\t\treturn nil\n\t}\n\n\t// This helps prevent an iframe and its child frames from being removed\n\t// when the type of detach is a swap. After this detach event usually\n\t// the iframe navigates, which requires the frames to be present for the\n\t// navigate to work.\n\tfs, ok := m.page.getFrameSession(frameID)\n\tif ok {\n\t\tm.logger.Debugf(\"FrameManager:frameDetached:sessionFound\",\n\t\t\t\"fmid:%d fid:%v fsID1:%v fsID2:%v found session for frame\",\n\t\t\tm.ID(), frameID, fs.session.ID(), m.session.ID())\n\n\t\tif fs.session.ID() != m.session.ID() {\n\t\t\tm.logger.Debugf(\"FrameManager:frameDetached:notSameSession:return\",\n\t\t\t\t\"fmid:%d fid:%v event session and frame session do not match\",\n\t\t\t\tm.ID(), frameID)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tif reason == cdppage.FrameDetachedReasonSwap {\n\t\t// When a local frame is swapped out for a remote\n\t\t// frame, we want to keep the current frame which is\n\t\t// still referenced by the (incoming) remote frame, but\n\t\t// remove all its child frames.\n\t\treturn m.removeChildFramesRecursively(frame)\n\t}\n\n\treturn m.removeFramesRecursively(frame)\n}\n\nfunc (m *FrameManager) frameLifecycleEvent(frameID cdp.FrameID, event LifecycleEvent) {\n\tm.logger.Debugf(\"FrameManager:frameLifecycleEvent\",\n\t\t\"fmid:%d fid:%v event:%s\",\n\t\tm.ID(), frameID, lifecycleEventToString[event])\n\n\tframe, ok := m.getFrameByID(frameID)\n\tif ok {\n\t\tframe.onLifecycleEvent(event)\n\t}\n}\n\nfunc (m *FrameManager) frameLoadingStarted(frameID cdp.FrameID) {\n\tm.logger.Debugf(\"FrameManager:frameLoadingStarted\",\n\t\t\"fmid:%d fid:%v\", m.ID(), frameID)\n\n\tframe, ok := m.getFrameByID(frameID)\n\tif ok {\n\t\tframe.onLoadingStarted()\n\t}\n}\n\nfunc (m *FrameManager) frameLoadingStopped(frameID cdp.FrameID) {\n\tm.logger.Debugf(\"FrameManager:frameLoadingStopped\",\n\t\t\"fmid:%d fid:%v\", m.ID(), frameID)\n\n\tframe, ok := m.getFrameByID(frameID)\n\tif ok {\n\t\tframe.onLoadingStopped()\n\t}\n}\n\n//nolint:funlen\nfunc (m *FrameManager) frameNavigated(\n\tframeID cdp.FrameID, parentFrameID cdp.FrameID, documentID string, name string, url string, initial bool,\n) error {\n\tm.logger.Debugf(\"FrameManager:frameNavigated\",\n\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t\",\n\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial)\n\n\t// TODO: add test to make sure the navigated frame has correct ID, parent ID, loader ID, name and URL\n\tm.framesMu.Lock()\n\tdefer m.framesMu.Unlock()\n\n\tisMainFrame := parentFrameID == \"\"\n\tframe := m.frames[frameID]\n\n\tif !isMainFrame && frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:frameNavigated:nil frame\",\n\t\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t\",\n\t\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial)\n\n\t\t// If the frame is nil at this point, then the cause of this is likely\n\t\t// due to chrome not sending a frameAttached event ahead of time. This\n\t\t// isn't a bug in chrome, and seems to be intended behavior. Instead\n\t\t// of worrying about the nil frame and causing the test to fail when\n\t\t// the frame is nil, we can instead return early. The frame will\n\t\t// be initialized when getFrameTree CDP request is made, which will\n\t\t// call onFrameAttached and onFrameNavigated.\n\n\t\treturn nil\n\t}\n\n\tm.logger.Debugf(\"FrameManager:frameNavigated:removeFrames\",\n\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t\",\n\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial)\n\n\tif frame != nil {\n\t\tm.framesMu.Unlock()\n\t\tfor _, child := range frame.ChildFrames() {\n\t\t\tif err := m.removeFramesRecursively(child); err != nil {\n\t\t\t\tm.framesMu.Lock()\n\t\t\t\treturn fmt.Errorf(\"removing child frames recursively: %w\", err)\n\t\t\t}\n\t\t}\n\t\tm.framesMu.Lock()\n\t}\n\n\tvar mainFrame *Frame\n\tif isMainFrame && frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:frameNavigated:MainFrame:initialMainFrameNavigation\",\n\t\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t\",\n\t\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial)\n\n\t\t// Initial main frame navigation.\n\t\tframe = NewFrame(m.ctx, m, nil, frameID, m.logger)\n\t\tmainFrame = frame\n\t} else if isMainFrame && frame.ID() != string(frameID) {\n\t\tm.logger.Debugf(\"FrameManager:frameNavigated:MainFrame:delete\",\n\t\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t oldfid:%v\",\n\t\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial, frame.ID())\n\n\t\t// Update frame ID to retain frame identity on cross-process navigation.\n\t\tdelete(m.frames, cdp.FrameID(frame.ID()))\n\t\tframe.setID(frameID)\n\t\tmainFrame = frame\n\t}\n\tif mainFrame != nil {\n\t\tm.frames[frameID] = frame\n\t\tm.setMainFrame(frame)\n\t}\n\n\tframe.navigated(name, url, documentID)\n\n\tframe.pendingDocumentMu.Lock()\n\tdefer frame.pendingDocumentMu.Unlock()\n\n\tvar (\n\t\tkeepPending     *DocumentInfo\n\t\tpendingDocument = frame.pendingDocument\n\t)\n\tif pendingDocument != nil {\n\t\tif pendingDocument.documentID == \"\" {\n\t\t\tpendingDocument.documentID = documentID\n\t\t}\n\t\tif pendingDocument.documentID == documentID {\n\t\t\t// Committing a pending document.\n\t\t\tframe.currentDocument = pendingDocument\n\t\t} else {\n\t\t\t// Sometimes, we already have a new pending when the old one commits.\n\t\t\t// An example would be Chromium error page followed by a new navigation request,\n\t\t\t// where the error page commit arrives after Network.requestWillBeSent for the\n\t\t\t// new navigation.\n\t\t\t// We commit, but keep the pending request since it's not done yet.\n\t\t\tkeepPending = pendingDocument\n\t\t\tframe.currentDocument = &DocumentInfo{\n\t\t\t\tdocumentID: documentID,\n\t\t\t\trequest:    nil,\n\t\t\t}\n\t\t}\n\t\tframe.pendingDocument = nil\n\t} else {\n\t\t// No pending, just commit a new document.\n\t\tframe.currentDocument = &DocumentInfo{\n\t\t\tdocumentID: documentID,\n\t\t\trequest:    nil,\n\t\t}\n\t}\n\n\tm.logger.Debugf(\"FrameManager:frameNavigated\",\n\t\t\"fmid:%d fid:%v pfid:%v docid:%s fname:%s furl:%s initial:%t pdoc:nil - fcurdoc:%v\",\n\t\tm.ID(), frameID, parentFrameID, documentID, name, url, initial, documentID)\n\n\tframe.clearLifecycle()\n\tframe.emit(EventFrameNavigation, &NavigationEvent{url: url, name: name, newDocument: frame.currentDocument})\n\n\t// TODO: when we add API support for storage we need to track origins\n\t// if !initial {\n\t// \t//f.page.frameNavigatedToNewDocument(f)\n\t// }\n\n\t// Restore pending if any (see comments above about keepPending).\n\tframe.pendingDocument = keepPending\n\n\treturn nil\n}\n\nfunc (m *FrameManager) frameNavigatedWithinDocument(frameID cdp.FrameID, url string) {\n\tm.logger.Debugf(\"FrameManager:frameNavigatedWithinDocument\",\n\t\t\"fmid:%d fid:%v url:%s\", m.ID(), frameID, url)\n\n\tm.framesMu.Lock()\n\tdefer m.framesMu.Unlock()\n\n\tframe := m.frames[frameID]\n\tif frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:frameNavigatedWithinDocument:nilFrame:return\",\n\t\t\t\"fmid:%d fid:%v url:%s\", m.ID(), frameID, url)\n\n\t\treturn\n\t}\n\n\tm.logger.Debugf(\"FrameManager:frameNavigatedWithinDocument\",\n\t\t\"fmid:%d fid:%v furl:%s url:%s\", m.ID(), frameID, frame.URL(), url)\n\n\tframe.setURL(url)\n\tframe.emit(EventFrameNavigation, &NavigationEvent{url: url, name: frame.Name()})\n}\n\nfunc (m *FrameManager) frameRequestedNavigation(frameID cdp.FrameID, url string, documentID string) error {\n\tm.logger.Debugf(\"FrameManager:frameRequestedNavigation\",\n\t\t\"fmid:%d fid:%v url:%s docid:%s\", m.ID(), frameID, url, documentID)\n\n\tm.framesMu.Lock()\n\tdefer m.framesMu.Unlock()\n\n\tframe := m.frames[frameID]\n\tif frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:frameRequestedNavigation:nilFrame:return\",\n\t\t\t\"fmid:%d fid:%v url:%s docid:%s\", m.ID(), frameID, url, documentID)\n\n\t\t// If a frame doesn't exist then the call to this method (which\n\t\t// originates from a EventFrameRequestedNavigation CDP event) is on a\n\t\t// stale frame that no longer exists in memory.\n\t\treturn nil\n\t}\n\n\tm.barriersMu.RLock()\n\tdefer m.barriersMu.RUnlock()\n\tfor _, b := range m.barriers {\n\t\tm.logger.Debugf(\"FrameManager:frameRequestedNavigation:AddFrameNavigation\",\n\t\t\t\"fmid:%d fid:%v furl:%s url:%s docid:%s\", m.ID(), frameID, frame.URL(), url, documentID)\n\n\t\tb.AddFrameNavigation(frame)\n\t}\n\n\tframe.pendingDocumentMu.Lock()\n\tdefer frame.pendingDocumentMu.Unlock()\n\n\tif frame.pendingDocument != nil && frame.pendingDocument.documentID == documentID {\n\t\tm.logger.Debugf(\"FrameManager:frameRequestedNavigation:return\",\n\t\t\t\"fmid:%d fid:%v furl:%s url:%s docid:%s pdocid:%s pdoc:dontSet\",\n\t\t\tm.ID(), frameID, frame.URL(), url, documentID,\n\t\t\tframe.pendingDocument.documentID)\n\n\t\t// Do not override request with nil\n\t\treturn nil\n\t}\n\n\tm.logger.Debugf(\"FrameManager:frameRequestedNavigation:return\",\n\t\t\"fmid:%d fid:%v furl:%s url:%s docid:%s pdoc:set\",\n\t\tm.ID(), frameID, frame.URL(), url, documentID)\n\n\tframe.pendingDocument = &DocumentInfo{documentID: documentID}\n\treturn nil\n}\n\n// getFrameByID finds a frame with id. If found, it returns the frame and true,\n// otherwise, it returns nil and false.\nfunc (m *FrameManager) getFrameByID(id cdp.FrameID) (*Frame, bool) {\n\tm.framesMu.RLock()\n\tdefer m.framesMu.RUnlock()\n\n\tframe, ok := m.frames[id]\n\n\treturn frame, ok\n}\n\nfunc (m *FrameManager) removeChildFramesRecursively(frame *Frame) error {\n\tfor _, child := range frame.ChildFrames() {\n\t\tif err := m.removeFramesRecursively(child); err != nil {\n\t\t\treturn fmt.Errorf(\"removing child frames recursively: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *FrameManager) removeFramesRecursively(frame *Frame) error {\n\tfor _, child := range frame.ChildFrames() {\n\t\tm.logger.Debugf(\"FrameManager:removeFramesRecursively\",\n\t\t\t\"fmid:%d cfid:%v pfid:%v cfname:%s cfurl:%s\",\n\t\t\tm.ID(), child.ID(), frame.ID(), child.Name(), child.URL())\n\n\t\tif err := m.removeFramesRecursively(child); err != nil {\n\t\t\treturn fmt.Errorf(\"removing frames recursively: %w\", err)\n\t\t}\n\t}\n\n\tif err := frame.detach(); err != nil {\n\t\treturn fmt.Errorf(\"removing frames recursively: detaching frame: %w\", err)\n\t}\n\n\tm.framesMu.Lock()\n\tm.logger.Debugf(\"FrameManager:removeFramesRecursively:delParentFrame\",\n\t\t\"fmid:%d fid:%v fname:%s furl:%s\",\n\t\tm.ID(), frame.ID(), frame.Name(), frame.URL())\n\n\tdelete(m.frames, cdp.FrameID(frame.ID()))\n\tm.framesMu.Unlock()\n\n\treturn nil\n}\n\nfunc (m *FrameManager) requestFailed(req *Request, canceled bool) {\n\tm.logger.Debugf(\"FrameManager:requestFailed\", \"fmid:%d rurl:%s\", m.ID(), req.URL())\n\n\tframe := req.getFrame()\n\tif frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:requestFailed\", \"frame is nil\")\n\t\treturn\n\t}\n\tframe.deleteRequest(req.getID())\n\n\tframe.pendingDocumentMu.RLock()\n\tif frame.pendingDocument == nil || frame.pendingDocument.request != req {\n\t\tm.logger.Debugf(\"FrameManager:requestFailed:return\", \"fmid:%d pdoc:nil\", m.ID())\n\t\tframe.pendingDocumentMu.RUnlock()\n\t\treturn\n\t}\n\n\terrorText := req.errorText\n\tif canceled {\n\t\terrorText += \"; maybe frame was detached?\"\n\t}\n\n\tdocID := frame.pendingDocument.documentID\n\tframe.pendingDocumentMu.RUnlock()\n\n\tm.frameAbortedNavigation(cdp.FrameID(frame.ID()), errorText, docID)\n}\n\nfunc (m *FrameManager) requestFinished(req *Request) {\n\tm.logger.Debugf(\"FrameManager:requestFinished\", \"fmid:%d rurl:%s\",\n\t\tm.ID(), req.URL())\n\n\tframe := req.getFrame()\n\tif frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:requestFinished:return\",\n\t\t\t\"fmid:%d rurl:%s frame:nil\", m.ID(), req.URL())\n\t\treturn\n\t}\n\tframe.deleteRequest(req.getID())\n\t/*\n\t\telse if frame.inflightRequestsLen() <= 10 {\n\t\t\tfor reqID, _ := range frame.inflightRequests {\n\t\t\t\treq := frame.requestByID(reqID)\n\t\t\t}\n\t\t}\n\t*/\n}\n\nfunc (m *FrameManager) requestStarted(req *Request) {\n\tm.logger.Debugf(\"FrameManager:requestStarted\", \"fmid:%d rurl:%s\", m.ID(), req.URL())\n\n\tm.framesMu.Lock()\n\tdefer m.framesMu.Unlock()\n\n\tframe := req.getFrame()\n\tif frame == nil {\n\t\tm.logger.Debugf(\"FrameManager:requestStarted:return\",\n\t\t\t\"fmid:%d rurl:%s frame:nil\", m.ID(), req.URL())\n\t\treturn\n\t}\n\n\tframe.addRequest(req.getID())\n\tif req.documentID != \"\" {\n\t\tframe.pendingDocumentMu.Lock()\n\t\tframe.pendingDocument = &DocumentInfo{documentID: req.documentID, request: req}\n\t\tframe.pendingDocumentMu.Unlock()\n\t}\n\n\tif !m.page.hasRoutes() {\n\t\treturn\n\t}\n\n\troute := NewRoute(m.logger, m.page.mainFrameSession.networkManager, req)\n\tm.page.routesMu.RLock()\n\tdefer m.page.routesMu.RUnlock()\n\tfor _, r := range m.page.routes {\n\t\tmatched, err := r.urlMatcher(req.URL())\n\t\tif err != nil {\n\t\t\tm.logger.Errorf(\"FrameManager:requestStarted\",\n\t\t\t\t\"fmid:%d rurl:%s error matching url: %v\", m.ID(), req.URL(), err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif !matched {\n\t\t\tcontinue\n\t\t}\n\n\t\tfunc() {\n\t\t\t// In case routes are updated in the handler\n\t\t\tm.page.routesMu.RUnlock()\n\t\t\tdefer m.page.routesMu.RLock()\n\n\t\t\terr := r.handler(route)\n\t\t\tif err != nil {\n\t\t\t\tm.logger.Errorf(\"FrameManager:requestStarted\",\n\t\t\t\t\t\"fmid:%d rurl:%s error handling request with route: %v\", m.ID(), req.URL(), err)\n\t\t\t}\n\t\t}()\n\n\t\treturn\n\t}\n\n\tif err := route.Continue(ContinueOptions{}); err != nil {\n\t\tm.logger.Errorf(\"FrameManager:requestStarted\",\n\t\t\t\"fmid:%d rurl:%s error continuing request: %v\", m.ID(), req.URL(), err)\n\t}\n}\n\n// Frames returns a list of frames on the page.\nfunc (m *FrameManager) Frames() []*Frame {\n\tm.framesMu.RLock()\n\tdefer m.framesMu.RUnlock()\n\tframes := make([]*Frame, 0, len(m.frames))\n\tfor _, frame := range m.frames {\n\t\tframes = append(frames, frame)\n\t}\n\treturn frames\n}\n\n// MainFrame returns the main frame of the page.\nfunc (m *FrameManager) MainFrame() *Frame {\n\tm.mainFrameMu.RLock()\n\tdefer m.mainFrameMu.RUnlock()\n\n\treturn m.mainFrame\n}\n\n// setMainFrame sets the main frame of the page.\nfunc (m *FrameManager) setMainFrame(f *Frame) {\n\tm.mainFrameMu.Lock()\n\tdefer m.mainFrameMu.Unlock()\n\n\tm.logger.Debugf(\"FrameManager:setMainFrame\",\n\t\t\"fmid:%d fid:%v furl:%s\",\n\t\tm.ID(), f.ID(), f.URL())\n\n\tm.mainFrame = f\n}\n\n// MainFrameURL returns the main frame's url.\nfunc (m *FrameManager) MainFrameURL() string {\n\tm.mainFrameMu.RLock()\n\tdefer m.mainFrameMu.RUnlock()\n\n\treturn m.mainFrame.URL()\n}\n\n// NavigateFrame will navigate a specified frame to specified URL.\n//\n//nolint:funlen\nfunc (m *FrameManager) NavigateFrame(frame *Frame, url string, parsedOpts *FrameGotoOptions) (*Response, error) {\n\tvar (\n\t\tfmid = m.ID()\n\t\tfid  = frame.ID()\n\t\tfurl = frame.URL()\n\t)\n\tm.logger.Debugf(\"FrameManager:NavigateFrame\",\n\t\t\"fmid:%d fid:%v furl:%s url:%s\", fmid, fid, furl, url)\n\tdefer m.logger.Debugf(\"FrameManager:NavigateFrame:return\",\n\t\t\"fmid:%d fid:%v furl:%s url:%s\", fmid, fid, furl, url)\n\n\ttimeoutCtx, timeoutCancelFn := context.WithTimeout(m.ctx, parsedOpts.Timeout)\n\tdefer timeoutCancelFn()\n\n\tvar newDocumentID string\n\tnewDocIDIsReadyCh := make(chan struct{})\n\n\tnavEvtCh, navEvtCancel := createWaitForEventPredicateHandler(\n\t\ttimeoutCtx, frame, []string{EventFrameNavigation},\n\t\tfunc(data any) bool {\n\t\t\tselect {\n\t\t\tcase <-newDocIDIsReadyCh:\n\t\t\tcase <-timeoutCtx.Done():\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif evt, ok := data.(*NavigationEvent); ok {\n\t\t\t\tif evt.newDocument != nil {\n\t\t\t\t\treturn evt.newDocument.documentID == newDocumentID\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\tdefer navEvtCancel()\n\n\tlifecycleEvtCh, lifecycleEvtCancel := createWaitForEventPredicateHandler(\n\t\ttimeoutCtx, frame, []string{EventFrameAddLifecycle},\n\t\tfunc(data any) bool {\n\t\t\tle, ok := data.(FrameLifecycleEvent)\n\t\t\tif !ok {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\t// skip the initial blank page if we are navigating to a non-blank page.\n\t\t\t// otherwise, we will get a lifecycle event for the initial blank page\n\t\t\t// and return prematurely before waiting for the navigation to complete.\n\t\t\tif url != BlankPage && le.URL == BlankPage {\n\t\t\t\tm.logger.Debugf(\n\t\t\t\t\t\"FrameManager:NavigateFrame:createWaitForEventPredicateHandler\",\n\t\t\t\t\t\"fmid:%d fid:%v furl:%s url:%s waitUntil:%s event.lifecycle:%q event.url:%q skipping %s\",\n\t\t\t\t\tfmid, fid, furl, url, parsedOpts.WaitUntil, le.Event, le.URL, BlankPage,\n\t\t\t\t)\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\treturn le.Event == parsedOpts.WaitUntil\n\t\t})\n\tdefer lifecycleEvtCancel()\n\n\tfs, ok := frame.page.getFrameSession(cdp.FrameID(frame.ID()))\n\tif !ok {\n\t\tm.logger.Debugf(\"FrameManager:NavigateFrame\",\n\t\t\t\"fmid:%d fid:%v furl:%s url:%s fs:nil\",\n\t\t\tfmid, fid, furl, url)\n\n\t\t// Attaching an iframe to an existing page doesn't seem to trigger a \"Target.attachedToTarget\" event\n\t\t// from the browser even when \"Target.setAutoAttach\" is true. If this is the case fallback to the\n\n\t\t// main frame's session.\n\t\tfs = frame.page.mainFrameSession\n\t}\n\n\tvar err error\n\tnewDocumentID, err = fs.navigateFrame(frame, url, parsedOpts.Referer)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"navigating to %q: %w\", url, err)\n\t}\n\n\tif newDocumentID == \"\" {\n\t\t// It's a navigation within the same document (e.g., via anchor links or\n\t\t// the History API), so don't wait for a response nor any lifecycle\n\t\t// events.\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\t// unblock the waiter goroutine\n\tclose(newDocIDIsReadyCh)\n\n\twrapTimeoutError := func(err error) error {\n\t\tif errors.Is(err, context.DeadlineExceeded) {\n\t\t\terr = &k6ext.UserFriendlyError{\n\t\t\t\tErr:     err,\n\t\t\t\tTimeout: parsedOpts.Timeout,\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"navigating to %q: %w\", url, err)\n\t\t}\n\t\tm.logger.Debugf(\"FrameManager:NavigateFrame\",\n\t\t\t\"fmid:%d fid:%v furl:%s url:%s timeoutCtx done: %v\",\n\t\t\tfmid, fid, furl, url, err)\n\n\t\treturn err // TODO maybe wrap this as well?\n\t}\n\n\tvar resp *Response\n\tselect {\n\tcase evt := <-navEvtCh:\n\t\tif e, ok := evt.(*NavigationEvent); ok {\n\t\t\tif e.err != nil {\n\t\t\t\treturn nil, e.err\n\t\t\t}\n\n\t\t\treq := e.newDocument.request\n\t\t\t// Request could be nil in case of navigation to e.g. BlankPage.\n\t\t\tif req != nil {\n\t\t\t\treq.responseMu.RLock()\n\t\t\t\tresp = req.response\n\t\t\t\treq.responseMu.RUnlock()\n\t\t\t}\n\t\t}\n\tcase <-timeoutCtx.Done():\n\t\treturn nil, wrapTimeoutError(ContextErr(timeoutCtx))\n\t}\n\n\tselect {\n\tcase <-lifecycleEvtCh:\n\tcase <-timeoutCtx.Done():\n\t\treturn nil, wrapTimeoutError(ContextErr(timeoutCtx))\n\t}\n\n\treturn resp, nil\n}\n\n// Page returns the page that this frame manager belongs to.\nfunc (m *FrameManager) Page() *Page {\n\tif m.page != nil {\n\t\treturn m.page\n\t}\n\treturn nil\n}\n\n// ID returns the unique ID of a FrameManager value.\nfunc (m *FrameManager) ID() int64 {\n\treturn atomic.LoadInt64(&m.id)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/frame_options.go",
    "content": "package common\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/js/common\"\n)\n\ntype FrameBaseOptions struct {\n\tTimeout time.Duration `json:\"timeout\"`\n\tStrict  bool          `json:\"strict\"`\n}\n\ntype FrameCheckOptions struct {\n\tElementHandleBasePointerOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameClickOptions struct {\n\tElementHandleClickOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameDblclickOptions struct {\n\tElementHandleDblclickOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameFillOptions struct {\n\tElementHandleBaseOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameGotoOptions struct {\n\tReferer   string         `json:\"referer\"`\n\tTimeout   time.Duration  `json:\"timeout\"`\n\tWaitUntil LifecycleEvent `json:\"waitUntil\" js:\"waitUntil\"`\n}\n\ntype FrameHoverOptions struct {\n\tElementHandleHoverOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameInnerHTMLOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameInnerTextOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameInputValueOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameIsCheckedOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameIsDisabledOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameIsEditableOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameIsEnabledOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameIsHiddenOptions struct {\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameIsVisibleOptions struct {\n\tStrict bool `json:\"strict\"`\n}\n\ntype FramePressOptions struct {\n\tElementHandlePressOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameSelectOptionOptions struct {\n\tElementHandleBaseOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameSetContentOptions struct {\n\tTimeout   time.Duration  `json:\"timeout\"`\n\tWaitUntil LifecycleEvent `json:\"waitUntil\" js:\"waitUntil\"`\n}\n\n// FrameSetInputFilesOptions are options for Frame.setInputFiles.\ntype FrameSetInputFilesOptions struct {\n\tElementHandleSetInputFilesOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameTapOptions struct {\n\tElementHandleBasePointerOptions\n\tModifiers []string `json:\"modifiers\"`\n\tStrict    bool     `json:\"strict\"`\n}\n\ntype FrameTextContentOptions struct {\n\tFrameBaseOptions\n}\n\ntype FrameTypeOptions struct {\n\tElementHandleTypeOptions\n\tStrict bool `json:\"strict\"`\n}\n\ntype FrameUncheckOptions struct {\n\tElementHandleBasePointerOptions\n\tStrict bool `json:\"strict\"`\n}\n\n// PollingType is the type of polling to use.\ntype PollingType int\n\nconst (\n\t// PollingRaf is the requestAnimationFrame polling type.\n\tPollingRaf PollingType = iota\n\n\t// PollingMutation is the mutation polling type.\n\tPollingMutation\n\n\t// PollingInterval is the interval polling type.\n\tPollingInterval\n)\n\nfunc (p PollingType) String() string {\n\treturn pollingTypeToString[p]\n}\n\nvar pollingTypeToString = map[PollingType]string{ //nolint:gochecknoglobals\n\tPollingRaf:      \"raf\",\n\tPollingMutation: \"mutation\",\n\tPollingInterval: \"interval\",\n}\n\nvar pollingTypeToID = map[string]PollingType{ //nolint:gochecknoglobals\n\t\"raf\":      PollingRaf,\n\t\"mutation\": PollingMutation,\n\t\"interval\": PollingInterval,\n}\n\n// MarshalJSON marshals the enum as a quoted JSON string.\nfunc (p PollingType) MarshalJSON() ([]byte, error) {\n\tbuffer := bytes.NewBufferString(`\"`)\n\tbuffer.WriteString(pollingTypeToString[p])\n\tbuffer.WriteString(`\"`)\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON unmarshals a quoted JSON string to the enum value.\nfunc (p *PollingType) UnmarshalJSON(b []byte) error {\n\tvar j string\n\terr := json.Unmarshal(b, &j)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshaling polling type: %w\", err)\n\t}\n\t// Note that if the string cannot be found then it will be set to the zero value.\n\t*p = pollingTypeToID[j]\n\treturn nil\n}\n\ntype FrameWaitForFunctionOptions struct {\n\tPolling  PollingType   `json:\"polling\"`\n\tInterval int64         `json:\"interval\"`\n\tTimeout  time.Duration `json:\"timeout\"`\n}\n\ntype FrameWaitForLoadStateOptions struct {\n\tTimeout time.Duration `json:\"timeout\"`\n}\n\ntype FrameWaitForNavigationOptions struct {\n\tURL       string         `json:\"url\"`\n\tWaitUntil LifecycleEvent `json:\"waitUntil\" js:\"waitUntil\"`\n\tTimeout   time.Duration  `json:\"timeout\"`\n}\n\ntype FrameWaitForSelectorOptions struct {\n\tState   DOMElementState `json:\"state\"`\n\tStrict  bool            `json:\"strict\"`\n\tTimeout time.Duration   `json:\"timeout\"`\n}\n\nfunc NewFrameBaseOptions(defaultTimeout time.Duration) *FrameBaseOptions {\n\treturn &FrameBaseOptions{\n\t\tTimeout: defaultTimeout,\n\t\tStrict:  false,\n\t}\n}\n\n// Parse parses the frame base options.\nfunc (o *FrameBaseOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"strict\":\n\t\t\t\to.Strict = opts.Get(k).ToBoolean()\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewFrameCheckOptions(defaultTimeout time.Duration) *FrameCheckOptions {\n\treturn &FrameCheckOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tStrict:                          false,\n\t}\n}\n\n// Parse parses the frame check options.\nfunc (o *FrameCheckOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFrameClickOptions(defaultTimeout time.Duration) *FrameClickOptions {\n\treturn &FrameClickOptions{\n\t\tElementHandleClickOptions: *NewElementHandleClickOptions(defaultTimeout),\n\t\tStrict:                    false,\n\t}\n}\n\n// Parse parses the frame click options.\nfunc (o *FrameClickOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleClickOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFrameDblClickOptions(defaultTimeout time.Duration) *FrameDblclickOptions {\n\treturn &FrameDblclickOptions{\n\t\tElementHandleDblclickOptions: *NewElementHandleDblclickOptions(defaultTimeout),\n\t\tStrict:                       false,\n\t}\n}\n\n// Parse parses the frame dblclick options.\nfunc (o *FrameDblclickOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleDblclickOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFrameFillOptions(defaultTimeout time.Duration) *FrameFillOptions {\n\treturn &FrameFillOptions{\n\t\tElementHandleBaseOptions: *NewElementHandleBaseOptions(defaultTimeout),\n\t\tStrict:                   false,\n\t}\n}\n\n// Parse parses the frame fill options.\nfunc (o *FrameFillOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFrameGotoOptions(defaultReferer string, defaultTimeout time.Duration) *FrameGotoOptions {\n\treturn &FrameGotoOptions{\n\t\tReferer:   defaultReferer,\n\t\tTimeout:   defaultTimeout,\n\t\tWaitUntil: LifecycleEventLoad,\n\t}\n}\n\n// Parse parses the frame goto options.\nfunc (o *FrameGotoOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"referer\":\n\t\t\t\to.Referer = opts.Get(k).String()\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\tcase \"waitUntil\":\n\t\t\t\tlifeCycle := opts.Get(k).String()\n\t\t\t\tif err := o.WaitUntil.UnmarshalText([]byte(lifeCycle)); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"parsing goto options: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewFrameHoverOptions(defaultTimeout time.Duration) *FrameHoverOptions {\n\treturn &FrameHoverOptions{\n\t\tElementHandleHoverOptions: *NewElementHandleHoverOptions(defaultTimeout),\n\t\tStrict:                    false,\n\t}\n}\n\n// Parse parses the frame hover options.\nfunc (o *FrameHoverOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleHoverOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFrameInnerHTMLOptions(defaultTimeout time.Duration) *FrameInnerHTMLOptions {\n\treturn &FrameInnerHTMLOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame innerHTML options.\nfunc (o *FrameInnerHTMLOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameInnerTextOptions(defaultTimeout time.Duration) *FrameInnerTextOptions {\n\treturn &FrameInnerTextOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame innerText options.\nfunc (o *FrameInnerTextOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameInputValueOptions(defaultTimeout time.Duration) *FrameInputValueOptions {\n\treturn &FrameInputValueOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame inputValue options.\nfunc (o *FrameInputValueOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameIsCheckedOptions(defaultTimeout time.Duration) *FrameIsCheckedOptions {\n\treturn &FrameIsCheckedOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame isChecked options.\nfunc (o *FrameIsCheckedOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameIsDisabledOptions(defaultTimeout time.Duration) *FrameIsDisabledOptions {\n\treturn &FrameIsDisabledOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame isDisabled options.\nfunc (o *FrameIsDisabledOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameIsEditableOptions(defaultTimeout time.Duration) *FrameIsEditableOptions {\n\treturn &FrameIsEditableOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame isEditable options.\nfunc (o *FrameIsEditableOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameIsEnabledOptions(defaultTimeout time.Duration) *FrameIsEnabledOptions {\n\treturn &FrameIsEnabledOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame isEnabled options.\nfunc (o *FrameIsEnabledOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// NewFrameIsHiddenOptions creates and returns a new instance of FrameIsHiddenOptions.\nfunc NewFrameIsHiddenOptions() *FrameIsHiddenOptions {\n\treturn &FrameIsHiddenOptions{}\n}\n\n// Parse parses FrameIsHiddenOptions from sobek.Value.\nfunc (o *FrameIsHiddenOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\n// NewFrameIsVisibleOptions creates and returns a new instance of FrameIsVisibleOptions.\nfunc NewFrameIsVisibleOptions() *FrameIsVisibleOptions {\n\treturn &FrameIsVisibleOptions{}\n}\n\n// Parse parses FrameIsVisibleOptions from sobek.Value.\nfunc (o *FrameIsVisibleOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFramePressOptions(defaultTimeout time.Duration) *FramePressOptions {\n\treturn &FramePressOptions{\n\t\tElementHandlePressOptions: *NewElementHandlePressOptions(defaultTimeout),\n\t\tStrict:                    false,\n\t}\n}\n\n// ToKeyboardOptions converts FramePressOptions to KeyboardOptions.\nfunc (o *FramePressOptions) ToKeyboardOptions() KeyboardOptions {\n\tvar o2 KeyboardOptions\n\to2.Delay = o.Delay\n\treturn o2\n}\n\n// NewFrameSelectOptionOptions creates and returns a new instance of FrameSelectOptionOptions.\nfunc NewFrameSelectOptionOptions(defaultTimeout time.Duration) *FrameSelectOptionOptions {\n\treturn &FrameSelectOptionOptions{\n\t\tElementHandleBaseOptions: *NewElementHandleBaseOptions(defaultTimeout),\n\t\tStrict:                   false,\n\t}\n}\n\n// Parse parses the frame selectOption options.\nfunc (o *FrameSelectOptionOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFrameSetContentOptions(defaultTimeout time.Duration) *FrameSetContentOptions {\n\treturn &FrameSetContentOptions{\n\t\tTimeout:   defaultTimeout,\n\t\tWaitUntil: LifecycleEventLoad,\n\t}\n}\n\n// Parse parses the frame setContent options.\nfunc (o *FrameSetContentOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\tcase \"waitUntil\":\n\t\t\t\tlifeCycle := opts.Get(k).String()\n\t\t\t\tif err := o.WaitUntil.UnmarshalText([]byte(lifeCycle)); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"parsing setContent options: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// NewFrameSetInputFilesOptions creates a new FrameSetInputFilesOptions.\nfunc NewFrameSetInputFilesOptions(defaultTimeout time.Duration) *FrameSetInputFilesOptions {\n\treturn &FrameSetInputFilesOptions{\n\t\tElementHandleSetInputFilesOptions: *NewElementHandleSetInputFilesOptions(defaultTimeout),\n\t\tStrict:                            false,\n\t}\n}\n\n// Parse parses FrameSetInputFilesOptions from sobek.Value.\nfunc (o *FrameSetInputFilesOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleSetInputFilesOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameTapOptions(defaultTimeout time.Duration) *FrameTapOptions {\n\treturn &FrameTapOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tModifiers:                       []string{},\n\t\tStrict:                          false,\n\t}\n}\n\n// Parse parses the frame tap options.\nfunc (o *FrameTapOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"modifiers\":\n\t\t\t\tvar m []string\n\t\t\t\tif err := rt.ExportTo(opts.Get(k), &m); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\to.Modifiers = m\n\t\t\tcase \"strict\":\n\t\t\t\to.Strict = opts.Get(k).ToBoolean()\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewFrameTextContentOptions(defaultTimeout time.Duration) *FrameTextContentOptions {\n\treturn &FrameTextContentOptions{\n\t\tFrameBaseOptions: *NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\n// Parse parses the frame textContent options.\nfunc (o *FrameTextContentOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.FrameBaseOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc NewFrameTypeOptions(defaultTimeout time.Duration) *FrameTypeOptions {\n\treturn &FrameTypeOptions{\n\t\tElementHandleTypeOptions: *NewElementHandleTypeOptions(defaultTimeout),\n\t\tStrict:                   false,\n\t}\n}\n\n// ToKeyboardOptions converts FrameTypeOptions to KeyboardOptions.\nfunc (o *FrameTypeOptions) ToKeyboardOptions() KeyboardOptions {\n\tvar o2 KeyboardOptions\n\to2.Delay = o.Delay\n\treturn o2\n}\n\nfunc NewFrameUncheckOptions(defaultTimeout time.Duration) *FrameUncheckOptions {\n\treturn &FrameUncheckOptions{\n\t\tElementHandleBasePointerOptions: *NewElementHandleBasePointerOptions(defaultTimeout),\n\t\tStrict:                          false,\n\t}\n}\n\n// Parse parses the frame uncheck options.\nfunc (o *FrameUncheckOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif err := o.ElementHandleBasePointerOptions.Parse(ctx, opts); err != nil {\n\t\treturn err\n\t}\n\to.Strict = parseStrict(ctx, opts)\n\treturn nil\n}\n\nfunc NewFrameWaitForFunctionOptions(defaultTimeout time.Duration) *FrameWaitForFunctionOptions {\n\treturn &FrameWaitForFunctionOptions{\n\t\tPolling:  PollingRaf,\n\t\tInterval: 0,\n\t\tTimeout:  defaultTimeout,\n\t}\n}\n\n// Parse JavaScript waitForFunction options.\nfunc (o *FrameWaitForFunctionOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\trt := k6ext.Runtime(ctx)\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tv := obj.Get(k)\n\t\tswitch k {\n\t\tcase \"timeout\":\n\t\t\to.Timeout = time.Duration(v.ToInteger()) * time.Millisecond\n\t\tcase \"polling\":\n\t\t\tswitch v.ExportType().Kind() {\n\t\t\tcase reflect.Int64:\n\t\t\t\to.Polling = PollingInterval\n\t\t\t\to.Interval = v.ToInteger()\n\t\t\tcase reflect.String:\n\t\t\t\tif p, ok := pollingTypeToID[v.ToString().String()]; ok {\n\t\t\t\t\to.Polling = p\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tfallthrough\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"wrong polling option value: %q; \"+\n\t\t\t\t\t`possible values: \"raf\", \"mutation\" or number`, v)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc NewFrameWaitForLoadStateOptions(defaultTimeout time.Duration) *FrameWaitForLoadStateOptions {\n\treturn &FrameWaitForLoadStateOptions{\n\t\tTimeout: defaultTimeout,\n\t}\n}\n\n// Parse parses the frame waitForLoadState options.\nfunc (o *FrameWaitForLoadStateOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tif k == \"timeout\" {\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewFrameWaitForNavigationOptions(defaultTimeout time.Duration) *FrameWaitForNavigationOptions {\n\treturn &FrameWaitForNavigationOptions{\n\t\tURL:       \"\",\n\t\tTimeout:   defaultTimeout,\n\t\tWaitUntil: LifecycleEventLoad,\n\t}\n}\n\n// Parse parses the frame waitForNavigation options.\nfunc (o *FrameWaitForNavigationOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"url\":\n\t\t\t\tvar val string\n\t\t\t\tswitch opts.Get(k).ExportType() {\n\t\t\t\tcase reflect.TypeFor[string]():\n\t\t\t\t\tval = fmt.Sprintf(\"'%s'\", opts.Get(k).String()) // Strings require quotes\n\t\t\t\tdefault: // JS Regex, CSS, numbers or booleans\n\t\t\t\t\tval = opts.Get(k).String() // No quotes\n\t\t\t\t}\n\n\t\t\t\to.URL = val\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\tcase \"waitUntil\":\n\t\t\t\tlifeCycle := opts.Get(k).String()\n\t\t\t\tif err := o.WaitUntil.UnmarshalText([]byte(lifeCycle)); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"parsing waitForNavigation options: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewFrameWaitForSelectorOptions(defaultTimeout time.Duration) *FrameWaitForSelectorOptions {\n\treturn &FrameWaitForSelectorOptions{\n\t\tState:   DOMElementStateVisible,\n\t\tStrict:  false,\n\t\tTimeout: defaultTimeout,\n\t}\n}\n\n// Parse parses the frame waitForSelector options.\nfunc (o *FrameWaitForSelectorOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"state\":\n\t\t\t\tstate := opts.Get(k).String()\n\t\t\t\tif s, ok := domElementStateToID[state]; ok {\n\t\t\t\t\to.State = s\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"%q is not a valid DOM state\", state)\n\t\t\t\t}\n\t\t\tcase \"strict\":\n\t\t\t\to.Strict = opts.Get(k).ToBoolean()\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// FrameDispatchEventOptions are options for Frame.dispatchEvent.\ntype FrameDispatchEventOptions struct {\n\t*FrameBaseOptions\n}\n\n// NewFrameDispatchEventOptions returns a new FrameDispatchEventOptions.\nfunc NewFrameDispatchEventOptions(defaultTimeout time.Duration) *FrameDispatchEventOptions {\n\treturn &FrameDispatchEventOptions{\n\t\tFrameBaseOptions: NewFrameBaseOptions(defaultTimeout),\n\t}\n}\n\nfunc parseStrict(ctx context.Context, opts sobek.Value) bool {\n\tvar strict bool\n\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tif k == \"strict\" {\n\t\t\t\tstrict = opts.Get(k).ToBoolean()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn strict\n}\n\n// FrameWaitForURLOptions are options for Frame.waitForURL and Page.waitForURL.\ntype FrameWaitForURLOptions struct {\n\tTimeout   time.Duration\n\tWaitUntil LifecycleEvent\n}\n\n// NewFrameWaitForURLOptions returns a new FrameWaitForURLOptions.\nfunc NewFrameWaitForURLOptions(defaultTimeout time.Duration) *FrameWaitForURLOptions {\n\treturn &FrameWaitForURLOptions{\n\t\tTimeout:   defaultTimeout,\n\t\tWaitUntil: LifecycleEventLoad,\n\t}\n}\n\n// Parse parses the frame waitForURL options.\nfunc (o *FrameWaitForURLOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\tcase \"waitUntil\":\n\t\t\t\tlifeCycle := opts.Get(k).String()\n\t\t\t\tif err := o.WaitUntil.UnmarshalText([]byte(lifeCycle)); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"parsing waitForURL options: %w\", err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/frame_options_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFrameGotoOptionsParse(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\topts := vu.ToSobekValue(map[string]any{\n\t\t\t\"timeout\":   \"1000\",\n\t\t\t\"waitUntil\": \"networkidle\",\n\t\t})\n\t\tgotoOpts := NewFrameGotoOptions(\"https://example.com/\", 0)\n\t\terr := gotoOpts.Parse(vu.Context(), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, \"https://example.com/\", gotoOpts.Referer)\n\t\tassert.Equal(t, time.Second, gotoOpts.Timeout)\n\t\tassert.Equal(t, LifecycleEventNetworkIdle, gotoOpts.WaitUntil)\n\t})\n\n\tt.Run(\"err/invalid_waitUntil\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\topts := vu.ToSobekValue(map[string]any{\n\t\t\t\"waitUntil\": \"none\",\n\t\t})\n\t\tnavOpts := NewFrameGotoOptions(\"\", 0)\n\t\terr := navOpts.Parse(vu.Context(), opts)\n\n\t\tassert.EqualError(t, err,\n\t\t\t`parsing goto options: `+\n\t\t\t\t`invalid lifecycle event: \"none\"; must be one of: `+\n\t\t\t\t`load, domcontentloaded, networkidle`)\n\t})\n}\n\nfunc TestFrameSetContentOptionsParse(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\topts := vu.ToSobekValue(map[string]any{\n\t\t\t\"waitUntil\": \"networkidle\",\n\t\t})\n\t\tscOpts := NewFrameSetContentOptions(30 * time.Second)\n\t\terr := scOpts.Parse(vu.Context(), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, 30*time.Second, scOpts.Timeout)\n\t\tassert.Equal(t, LifecycleEventNetworkIdle, scOpts.WaitUntil)\n\t})\n\n\tt.Run(\"err/invalid_waitUntil\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\topts := vu.ToSobekValue(map[string]any{\n\t\t\t\"waitUntil\": \"none\",\n\t\t})\n\t\tnavOpts := NewFrameSetContentOptions(0)\n\t\terr := navOpts.Parse(vu.Context(), opts)\n\n\t\tassert.EqualError(t, err,\n\t\t\t`parsing setContent options: `+\n\t\t\t\t`invalid lifecycle event: \"none\"; must be one of: `+\n\t\t\t\t`load, domcontentloaded, networkidle`)\n\t})\n}\n\nfunc TestFrameWaitForNavigationOptionsParse(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\topts := vu.ToSobekValue(map[string]any{\n\t\t\t\"url\":       \"https://example.com/\",\n\t\t\t\"timeout\":   \"1000\",\n\t\t\t\"waitUntil\": \"networkidle\",\n\t\t})\n\t\tnavOpts := NewFrameWaitForNavigationOptions(0)\n\t\terr := navOpts.Parse(vu.Context(), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, \"'https://example.com/'\", navOpts.URL)\n\t\tassert.Equal(t, time.Second, navOpts.Timeout)\n\t\tassert.Equal(t, LifecycleEventNetworkIdle, navOpts.WaitUntil)\n\t})\n\n\tt.Run(\"err/invalid_waitUntil\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\topts := vu.ToSobekValue(map[string]any{\n\t\t\t\"waitUntil\": \"none\",\n\t\t})\n\t\tnavOpts := NewFrameWaitForNavigationOptions(0)\n\t\terr := navOpts.Parse(vu.Context(), opts)\n\n\t\tassert.EqualError(t, err,\n\t\t\t`parsing waitForNavigation options: `+\n\t\t\t\t`invalid lifecycle event: \"none\"; must be one of: `+\n\t\t\t\t`load, domcontentloaded, networkidle`)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/frame_session.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\tk6modules \"go.k6.io/k6/js/modules\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/browser\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/chromedp/cdproto/emulation\"\n\t\"github.com/chromedp/cdproto/inspector\"\n\tcdplog \"github.com/chromedp/cdproto/log\"\n\t\"github.com/chromedp/cdproto/network\"\n\tcdppage \"github.com/chromedp/cdproto/page\"\n\tcdpruntime \"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/chromedp/cdproto/security\"\n\t\"github.com/chromedp/cdproto/target\"\n)\n\nconst utilityWorldName = \"__k6_browser_utility_world__\"\n\n// CPUProfile is used in throttleCPU.\ntype CPUProfile struct {\n\t// rate as a slowdown factor (1 is no throttle, 2 is 2x slowdown, etc).\n\tRate float64\n}\n\n/*\nFrameSession is used for managing a frame's life-cycle, or in other words its full session.\nIt manages all the event listening while deferring the state storage to the Frame and FrameManager\nstructs.\n*/\ntype FrameSession struct {\n\tctx            context.Context\n\tteardownCtx    context.Context\n\tsession        session\n\tpage           *Page\n\tparent         *FrameSession\n\tmanager        *FrameManager\n\tnetworkManager *NetworkManager\n\n\tk6Metrics *k6ext.CustomMetrics\n\n\ttargetID target.ID\n\t// windowID can be 0 when it is associated to an iframe or frame with no UI.\n\twindowID    browser.WindowID\n\thasUIWindow bool\n\n\t// To understand the concepts of Isolated Worlds, Contexts and Frames and\n\t// the relationship betwween them have a look at the following doc:\n\t//nolint:lll\n\t// https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/core/v8/V8BindingDesign.md\n\tcontextIDToContextMu sync.Mutex\n\tcontextIDToContext   map[cdpruntime.ExecutionContextID]*ExecutionContext\n\tisolatedWorlds       map[string]bool\n\n\teventCh chan Event\n\twg      sync.WaitGroup\n\n\tchildSessions map[cdp.FrameID]*FrameSession\n\tvu            k6modules.VU\n\n\tlogger *log.Logger\n\n\t// Keep a reference to the main frame span so we can end it\n\t// when FrameSession.ctx is Done\n\tmainFrameSpan trace.Span\n\t// The initial navigation when a new page is created navigates to about:blank.\n\t// We want to make sure that the the navigation span is created for this in\n\t// onFrameNavigated, but subsequent calls to onFrameNavigated in the same\n\t// mainframe never again create a navigation span.\n\tinitialNavDone bool\n}\n\n// NewFrameSession initializes and returns a new FrameSession.\n//\n//nolint:funlen\nfunc NewFrameSession(\n\tctx context.Context,\n\tteardownCtx context.Context,\n\ts session,\n\tp *Page,\n\tparent *FrameSession,\n\ttid target.ID,\n\tl *log.Logger,\n\thasUIWindow bool,\n) (_ *FrameSession, err error) {\n\tl.Debugf(\"NewFrameSession\", \"sid:%v tid:%v\", s.ID(), tid)\n\n\tk6Metrics := k6ext.GetCustomMetrics(ctx)\n\n\tfs := FrameSession{\n\t\tctx:                  ctx,\n\t\tteardownCtx:          teardownCtx,\n\t\tsession:              s,\n\t\tpage:                 p,\n\t\tparent:               parent,\n\t\tmanager:              p.frameManager,\n\t\ttargetID:             tid,\n\t\tcontextIDToContextMu: sync.Mutex{},\n\t\tcontextIDToContext:   make(map[cdpruntime.ExecutionContextID]*ExecutionContext),\n\t\tisolatedWorlds:       make(map[string]bool),\n\t\teventCh:              make(chan Event),\n\t\tchildSessions:        make(map[cdp.FrameID]*FrameSession),\n\t\tvu:                   k6ext.GetVU(ctx),\n\t\tk6Metrics:            k6Metrics,\n\t\tlogger:               l,\n\t\thasUIWindow:          hasUIWindow,\n\t}\n\n\tif err := cdpruntime.RunIfWaitingForDebugger().Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"run if waiting for debugger to attach: %w\", err)\n\t}\n\n\tvar parentNM *NetworkManager\n\tif fs.parent != nil {\n\t\tparentNM = fs.parent.networkManager\n\t}\n\tfs.networkManager, err = NewNetworkManager(ctx, k6Metrics, s, fs.manager, parentNM, fs.manager.page)\n\tif err != nil {\n\t\tl.Debugf(\"NewFrameSession:NewNetworkManager\", \"sid:%v tid:%v err:%v\",\n\t\t\ts.ID(), tid, err)\n\t\treturn nil, err\n\t}\n\n\t// When a frame creates a new FrameSession without UI (e.g. some iframes) we cannot\n\t// retrieve the windowID. Doing so would lead to an error from chromium. For now all\n\t// iframes that are attached are setup with hasUIWindow as false which seems to work\n\t// as expected for iframes with and without UI elements.\n\tif fs.hasUIWindow {\n\t\taction := browser.GetWindowForTarget().WithTargetID(fs.targetID)\n\t\tif fs.windowID, _, err = action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\t\tl.Debugf(\n\t\t\t\t\"NewFrameSession:GetWindowForTarget\",\n\t\t\t\t\"sid:%v tid:%v err:%v\",\n\t\t\t\ts.ID(), tid, err)\n\n\t\t\treturn nil, fmt.Errorf(\"getting browser window ID: %w\", err)\n\t\t}\n\t}\n\n\tfs.initEvents()\n\tif err = fs.initFrameTree(); err != nil {\n\t\tl.Debugf(\n\t\t\t\"NewFrameSession:initFrameTree\",\n\t\t\t\"sid:%v tid:%v err:%v\",\n\t\t\ts.ID(), tid, err)\n\n\t\treturn nil, err\n\t}\n\tif err = fs.initIsolatedWorld(utilityWorldName); err != nil {\n\t\tl.Debugf(\n\t\t\t\"NewFrameSession:initIsolatedWorld\",\n\t\t\t\"sid:%v tid:%v err:%v\",\n\t\t\ts.ID(), tid, err)\n\n\t\treturn nil, err\n\t}\n\tif err = fs.initOptions(); err != nil {\n\t\tl.Debugf(\n\t\t\t\"NewFrameSession:initOptions\",\n\t\t\t\"sid:%v tid:%v err:%v\",\n\t\t\ts.ID(), tid, err)\n\n\t\treturn nil, err\n\t}\n\tif err = fs.initDomains(); err != nil {\n\t\tl.Debugf(\n\t\t\t\"NewFrameSession:initDomains\",\n\t\t\t\"sid:%v tid:%v err:%v\",\n\t\t\ts.ID(), tid, err)\n\n\t\treturn nil, err\n\t}\n\n\treturn &fs, nil\n}\n\nfunc (fs *FrameSession) emulateLocale() error {\n\taction := emulation.SetLocaleOverride().WithLocale(fs.page.browserCtx.opts.Locale)\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\tif strings.Contains(err.Error(), \"Another locale override is already in effect\") {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"emulating locale %q: %w\", fs.page.browserCtx.opts.Locale, err)\n\t}\n\treturn nil\n}\n\nfunc (fs *FrameSession) emulateTimezone() error {\n\taction := emulation.SetTimezoneOverride(fs.page.browserCtx.opts.TimezoneID)\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\tif strings.Contains(err.Error(), \"Timezone override is already in effect\") {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"emulating timezone %q: %w\", fs.page.browserCtx.opts.TimezoneID, err)\n\t}\n\treturn nil\n}\n\nfunc (fs *FrameSession) getNetworkManager() *NetworkManager {\n\treturn fs.networkManager\n}\n\nfunc (fs *FrameSession) initDomains() error {\n\tactions := []Action{\n\t\t// TODO: can we get rid of the following by doing DOM related stuff in JS instead?\n\t\tdom.Enable(),\n\t\tcdplog.Enable(),\n\t\tcdpruntime.Enable(),\n\t\ttarget.SetAutoAttach(true, true).WithFlatten(true),\n\t}\n\tfor _, action := range actions {\n\t\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"internal error while enabling %T: %w\", action, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n//nolint:cyclop\nfunc (fs *FrameSession) initEvents() {\n\tfs.logger.Debugf(\"NewFrameSession:initEvents\",\n\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\tevents := []string{\n\t\tcdproto.EventInspectorTargetCrashed,\n\t}\n\tfs.session.on(fs.ctx, events, fs.eventCh)\n\tif !fs.isMainFrame() {\n\t\tfs.initRendererEvents()\n\t}\n\n\tfs.wg.Go(func() {\n\t\tfs.logger.Debugf(\"NewFrameSession:initEvents:go\",\n\t\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\t\tdefer func() {\n\t\t\t// If there is an active span for main frame,\n\t\t\t// end it before exiting so it can be flushed\n\t\t\tif fs.mainFrameSpan != nil {\n\t\t\t\t// The url needs to be added here instead of at the start of the span\n\t\t\t\t// because at the start of the span we don't know the correct url for\n\t\t\t\t// the page we're navigating to. At the end of the span we do have this\n\t\t\t\t// information.\n\t\t\t\tfs.mainFrameSpan.SetAttributes(attribute.String(\"navigation.url\", fs.manager.MainFrameURL()))\n\t\t\t\tfs.mainFrameSpan.End()\n\t\t\t\tfs.mainFrameSpan = nil\n\t\t\t}\n\t\t\tfs.logger.Debugf(\"NewFrameSession:initEvents:go:return\",\n\t\t\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\t\t}()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-fs.session.Done():\n\t\t\t\tfs.logger.Debugf(\"FrameSession:initEvents:go:session.done\",\n\t\t\t\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\t\t\t\treturn\n\t\t\tcase <-fs.ctx.Done():\n\t\t\t\tfs.logger.Debugf(\"FrameSession:initEvents:go:ctx.Done\",\n\t\t\t\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\t\t\t\treturn\n\t\t\tcase event := <-fs.eventCh:\n\t\t\t\tswitch ev := event.data.(type) {\n\t\t\t\tcase *inspector.EventTargetCrashed:\n\t\t\t\t\tfs.onTargetCrashed()\n\t\t\t\tcase *cdplog.EventEntryAdded:\n\t\t\t\t\tfs.onLogEntryAdded(ev)\n\t\t\t\tcase *cdppage.EventFrameAttached:\n\t\t\t\t\tfs.onFrameAttached(ev.FrameID, ev.ParentFrameID)\n\t\t\t\tcase *cdppage.EventFrameDetached:\n\t\t\t\t\tfs.onFrameDetached(ev.FrameID, ev.Reason)\n\t\t\t\tcase *cdppage.EventFrameNavigated:\n\t\t\t\t\tconst initial = false\n\t\t\t\t\tfs.onFrameNavigated(ev.Frame, initial)\n\t\t\t\tcase *cdppage.EventFrameRequestedNavigation:\n\t\t\t\t\tfs.onFrameRequestedNavigation(ev)\n\t\t\t\tcase *cdppage.EventFrameStartedLoading:\n\t\t\t\t\tfs.onFrameStartedLoading(ev.FrameID)\n\t\t\t\tcase *cdppage.EventFrameStoppedLoading:\n\t\t\t\t\tfs.onFrameStoppedLoading(ev.FrameID)\n\t\t\t\tcase *cdppage.EventLifecycleEvent:\n\t\t\t\t\tfs.onPageLifecycle(ev)\n\t\t\t\tcase *cdppage.EventNavigatedWithinDocument:\n\t\t\t\t\tfs.onPageNavigatedWithinDocument(ev)\n\t\t\t\tcase *cdpruntime.EventConsoleAPICalled:\n\t\t\t\t\tfs.onConsoleAPICalled(ev)\n\t\t\t\tcase *cdpruntime.EventExceptionThrown:\n\t\t\t\t\tfs.onExceptionThrown(ev)\n\t\t\t\tcase *cdpruntime.EventExecutionContextCreated:\n\t\t\t\t\tfs.onExecutionContextCreated(ev)\n\t\t\t\tcase *cdpruntime.EventExecutionContextDestroyed:\n\t\t\t\t\tfs.onExecutionContextDestroyed(ev.ExecutionContextID)\n\t\t\t\tcase *cdpruntime.EventExecutionContextsCleared:\n\t\t\t\t\tfs.onExecutionContextsCleared()\n\t\t\t\tcase *target.EventAttachedToTarget:\n\t\t\t\t\tfs.onAttachedToTarget(ev)\n\t\t\t\tcase *target.EventDetachedFromTarget:\n\t\t\t\t\tfs.onDetachedFromTarget(ev)\n\t\t\t\tcase *cdppage.EventJavascriptDialogOpening:\n\t\t\t\t\tfs.onEventJavascriptDialogOpening(ev)\n\t\t\t\tcase *cdpruntime.EventBindingCalled:\n\t\t\t\t\tfs.onEventBindingCalled(ev)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc (fs *FrameSession) onEventBindingCalled(event *cdpruntime.EventBindingCalled) {\n\tfs.logger.Debugf(\"FrameSessions:onEventBindingCalled\",\n\t\t\"sid:%v tid:%v name:%s payload:%s\",\n\t\tfs.session.ID(), fs.targetID, event.Name, event.Payload)\n\n\terr := fs.parseAndEmitWebVitalMetric(event.Payload)\n\tif err != nil {\n\t\tfs.logger.Errorf(\"FrameSession:onEventBindingCalled\", \"failed to emit web vital metric: %v\", err)\n\t}\n}\n\nfunc (fs *FrameSession) parseAndEmitWebVitalMetric(object string) error {\n\tfs.logger.Debugf(\"FrameSession:parseAndEmitWebVitalMetric\", \"object:%s\", object)\n\n\twv := struct {\n\t\tID             string\n\t\tName           string\n\t\tValue          json.Number\n\t\tRating         string\n\t\tDelta          json.Number\n\t\tNumEntries     json.Number\n\t\tNavigationType string\n\t\tURL            string\n\t\tSpanID         string\n\t}{}\n\n\tif err := json.Unmarshal([]byte(object), &wv); err != nil {\n\t\treturn fmt.Errorf(\"json couldn't be parsed: %w\", err)\n\t}\n\n\tmetric, ok := fs.k6Metrics.WebVitals[wv.Name]\n\tif !ok {\n\t\treturn fmt.Errorf(\"metric not registered %q\", wv.Name)\n\t}\n\n\tvalue, err := wv.Value.Float64()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"value couldn't be parsed %q\", wv.Value)\n\t}\n\n\tstate := fs.vu.State()\n\ttags := state.Tags.GetCurrentValues().Tags\n\tif state.Options.SystemTags.Has(k6metrics.TagURL) {\n\t\ttags = handleURLTag(fs.page, wv.URL, http.MethodGet, tags)\n\t}\n\n\ttags = tags.With(\"rating\", wv.Rating)\n\n\tnow := time.Now()\n\tpushIfNotDone(fs.vu.Context(), fs.logger, state.Samples, k6metrics.ConnectedSamples{\n\t\tSamples: []k6metrics.Sample{\n\t\t\t{\n\t\t\t\tTimeSeries: k6metrics.TimeSeries{Metric: metric, Tags: tags},\n\t\t\t\tValue:      value,\n\t\t\t\tTime:       now,\n\t\t\t},\n\t\t},\n\t})\n\n\t_, span := TraceEvent(\n\t\tfs.ctx, fs.targetID.String(), \"web_vital\", wv.SpanID, trace.WithAttributes(\n\t\t\tattribute.String(\"web_vital.name\", wv.Name),\n\t\t\tattribute.Float64(\"web_vital.value\", value),\n\t\t\tattribute.String(\"web_vital.rating\", wv.Rating),\n\t\t))\n\tdefer span.End()\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) onEventJavascriptDialogOpening(event *cdppage.EventJavascriptDialogOpening) {\n\tfs.logger.Debugf(\"FrameSession:onEventJavascriptDialogOpening\",\n\t\t\"sid:%v tid:%v url:%v dialogType:%s\",\n\t\tfs.session.ID(), fs.targetID, event.URL, event.Type)\n\n\t// Dialog type of beforeunload needs to accept the\n\t// dialog, instead of dismissing it. We're unable to\n\t// dismiss beforeunload dialog boxes at the moment as\n\t// it seems to pause the exec of any other action on\n\t// the page. I believe this is an issue in Chromium.\n\taction := cdppage.HandleJavaScriptDialog(false)\n\tif event.Type == cdppage.DialogTypeBeforeunload {\n\t\taction = cdppage.HandleJavaScriptDialog(true)\n\t}\n\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\tfs.logger.Errorf(\"FrameSession:onEventJavascriptDialogOpening\", \"failed to dismiss dialog box: %v\", err)\n\t}\n}\n\nfunc (fs *FrameSession) initFrameTree() error {\n\tfs.logger.Debugf(\"NewFrameSession:initFrameTree\",\n\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\taction := cdppage.Enable()\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn fmt.Errorf(\"enabling page domain: %w\", err)\n\t}\n\n\tvar frameTree *cdppage.FrameTree\n\tvar err error\n\n\t// Recursively enumerate all existing frames in page to create initial in-memory structures\n\t// used for access and manipulation from JS.\n\taction2 := cdppage.GetFrameTree()\n\tif frameTree, err = action2.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn fmt.Errorf(\"getting page frame tree: %w\", err)\n\t} else if frameTree == nil {\n\t\t// This can happen with very short scripts when we might not have enough\n\t\t// time to initialize properly.\n\t\treturn fmt.Errorf(\"got a nil page frame tree\")\n\t}\n\n\t// Any new frame may have a child frame, not just mainframes.\n\tfs.handleFrameTree(frameTree, fs.isMainFrame())\n\n\tif fs.isMainFrame() {\n\t\tfs.initRendererEvents()\n\t}\n\treturn nil\n}\n\nfunc (fs *FrameSession) initIsolatedWorld(name string) error {\n\tfs.logger.Debugf(\"NewFrameSession:initIsolatedWorld\",\n\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\taction := cdppage.SetLifecycleEventsEnabled(true)\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn fmt.Errorf(\"enabling page lifecycle events: %w\", err)\n\t}\n\n\tif _, ok := fs.isolatedWorlds[name]; ok {\n\t\tfs.logger.Debugf(\"NewFrameSession:initIsolatedWorld\",\n\t\t\t\"sid:%v tid:%v, not found: %q\",\n\t\t\tfs.session.ID(), fs.targetID, name)\n\n\t\treturn nil\n\t}\n\tfs.isolatedWorlds[name] = true\n\n\tvar frames []*Frame\n\tif fs.isMainFrame() {\n\t\tframes = fs.manager.Frames()\n\t} else {\n\t\tframe, ok := fs.manager.getFrameByID(cdp.FrameID(fs.targetID))\n\t\tif ok {\n\t\t\tframes = []*Frame{frame}\n\t\t}\n\t}\n\tfor _, frame := range frames {\n\t\t// A frame could have been removed before we execute this, so don't wait around for a reply.\n\t\t_ = fs.session.ExecuteWithoutExpectationOnReply(\n\t\t\tfs.ctx,\n\t\t\tcdppage.CommandCreateIsolatedWorld,\n\t\t\t&cdppage.CreateIsolatedWorldParams{\n\t\t\t\tFrameID:             cdp.FrameID(frame.ID()),\n\t\t\t\tWorldName:           name,\n\t\t\t\tGrantUniveralAccess: true,\n\t\t\t},\n\t\t\tnil)\n\t}\n\n\tfs.logger.Debugf(\"NewFrameSession:initIsolatedWorld:AddScriptToEvaluateOnNewDocument\",\n\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\taction2 := cdppage.AddScriptToEvaluateOnNewDocument(`//# sourceURL=` + evaluationScriptURL).\n\t\tWithWorldName(name)\n\tif _, err := action2.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn fmt.Errorf(\"adding script to evaluate on new document: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (fs *FrameSession) initOptions() error {\n\tfs.logger.Debugf(\"NewFrameSession:initOptions\",\n\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\tvar (\n\t\topts       = fs.manager.page.browserCtx.opts\n\t\toptActions = []Action{}\n\t\tstate      = fs.vu.State()\n\t)\n\n\tif fs.isMainFrame() {\n\t\toptActions = append(optActions, emulation.SetFocusEmulationEnabled(true))\n\t\tif err := fs.updateViewport(); err != nil {\n\t\t\tfs.logger.Debugf(\"NewFrameSession:initOptions:updateViewport\",\n\t\t\t\t\"sid:%v tid:%v, err:%v\",\n\t\t\t\tfs.session.ID(), fs.targetID, err)\n\t\t\treturn err\n\t\t}\n\t}\n\tif opts.BypassCSP {\n\t\toptActions = append(optActions, cdppage.SetBypassCSP(true))\n\t}\n\tif opts.IgnoreHTTPSErrors {\n\t\toptActions = append(optActions, security.SetIgnoreCertificateErrors(true))\n\t}\n\tif opts.HasTouch {\n\t\toptActions = append(optActions, emulation.SetTouchEmulationEnabled(true))\n\t}\n\tif !opts.JavaScriptEnabled {\n\t\toptActions = append(optActions, emulation.SetScriptExecutionDisabled(true))\n\t}\n\tif opts.UserAgent != \"\" || opts.Locale != \"\" {\n\t\toptActions = append(optActions, emulation.SetUserAgentOverride(opts.UserAgent).WithAcceptLanguage(opts.Locale))\n\t}\n\tif opts.Locale != \"\" {\n\t\tif err := fs.emulateLocale(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif opts.TimezoneID != \"\" {\n\t\tif err := fs.emulateTimezone(); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := fs.updateGeolocation(true); err != nil {\n\t\treturn err\n\t}\n\tif err := fs.updateExtraHTTPHeaders(true); err != nil {\n\t\treturn err\n\t}\n\n\tvar reqIntercept bool\n\tif state.Options.BlockedHostnames.Trie != nil ||\n\t\tlen(state.Options.BlacklistIPs) > 0 {\n\t\treqIntercept = true\n\t}\n\tif err := fs.updateRequestInterception(reqIntercept); err != nil {\n\t\treturn err\n\t}\n\n\tif err := fs.updateOffline(true); err != nil {\n\t\treturn err\n\t}\n\tif err := fs.updateHTTPCredentials(true); err != nil {\n\t\treturn err\n\t}\n\tif err := fs.updateEmulateMedia(); err != nil {\n\t\treturn err\n\t}\n\n\tfor _, action := range optActions {\n\t\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"internal error while initializing frame %T: %w\", action, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) initRendererEvents() {\n\tfs.logger.Debugf(\"NewFrameSession:initEvents:initRendererEvents\",\n\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\tevents := []string{\n\t\tcdproto.EventLogEntryAdded,\n\t\tcdproto.EventPageFileChooserOpened,\n\t\tcdproto.EventPageFrameAttached,\n\t\tcdproto.EventPageFrameDetached,\n\t\tcdproto.EventPageFrameNavigated,\n\t\tcdproto.EventPageFrameRequestedNavigation,\n\t\tcdproto.EventPageFrameStartedLoading,\n\t\tcdproto.EventPageFrameStoppedLoading,\n\t\tcdproto.EventPageJavascriptDialogOpening,\n\t\tcdproto.EventPageLifecycleEvent,\n\t\tcdproto.EventPageNavigatedWithinDocument,\n\t\tcdproto.EventRuntimeConsoleAPICalled,\n\t\tcdproto.EventRuntimeExceptionThrown,\n\t\tcdproto.EventRuntimeExecutionContextCreated,\n\t\tcdproto.EventRuntimeExecutionContextDestroyed,\n\t\tcdproto.EventRuntimeExecutionContextsCleared,\n\t\tcdproto.EventTargetAttachedToTarget,\n\t\tcdproto.EventTargetDetachedFromTarget,\n\t\tcdproto.EventRuntimeBindingCalled,\n\t}\n\tfs.session.on(fs.ctx, events, fs.eventCh)\n}\n\nfunc (fs *FrameSession) isMainFrame() bool {\n\treturn fs.targetID == fs.page.targetID\n}\n\nfunc (fs *FrameSession) wait() {\n\tfs.wg.Wait()\n\tfs.networkManager.wait()\n}\n\nfunc (fs *FrameSession) handleFrameTree(frameTree *cdppage.FrameTree, initialFrame bool) {\n\tfs.logger.Debugf(\"FrameSession:handleFrameTree\",\n\t\t\"fid:%v sid:%v tid:%v\", frameTree.Frame.ID, fs.session.ID(), fs.targetID)\n\n\tif frameTree.Frame.ParentID != \"\" {\n\t\tfs.onFrameAttached(frameTree.Frame.ID, frameTree.Frame.ParentID)\n\t}\n\tfs.onFrameNavigated(frameTree.Frame, initialFrame)\n\tif frameTree.ChildFrames == nil {\n\t\treturn\n\t}\n\tfor _, child := range frameTree.ChildFrames {\n\t\tfs.handleFrameTree(child, initialFrame)\n\t}\n}\n\nfunc (fs *FrameSession) navigateFrame(frame *Frame, url, referrer string) (string, error) {\n\tfs.logger.Debugf(\"FrameSession:navigateFrame\",\n\t\t\"sid:%v fid:%s tid:%v url:%q referrer:%q\",\n\t\tfs.session.ID(), frame.ID(), fs.targetID, url, referrer)\n\n\taction := cdppage.Navigate(url).WithReferrer(referrer).WithFrameID(cdp.FrameID(frame.ID()))\n\t_, documentID, errorText, _, err := action.Do(cdp.WithExecutor(fs.ctx, fs.session))\n\tif err != nil {\n\t\tif errorText == \"\" {\n\t\t\terr = fmt.Errorf(\"%w\", err)\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"%q: %w\", errorText, err)\n\t\t}\n\t}\n\treturn documentID.String(), err\n}\n\nfunc (fs *FrameSession) onConsoleAPICalled(event *cdpruntime.EventConsoleAPICalled) {\n\tl := fs.logger.\n\t\tWithTime(event.Timestamp.Time()).\n\t\tWithField(\"source\", \"browser\").\n\t\tWithField(\"browser_source\", \"console-api\")\n\n\t/* accessing the state Group while not on the eventloop is racy\n\tif s := fs.vu.State(); s.Group.Path != \"\" {\n\t\tl = l.WithField(\"group\", s.Group.Path)\n\t}\n\t*/\n\n\tparsedObjects := make([]string, 0, len(event.Args))\n\tfor _, robj := range event.Args {\n\t\ts, err := parseConsoleRemoteObject(fs.logger, robj)\n\t\tif err != nil {\n\t\t\tfs.logger.Errorf(\"onConsoleAPICalled\", \"failed to parse console message %v\", err)\n\t\t}\n\t\tparsedObjects = append(parsedObjects, s)\n\t}\n\n\tmsg := strings.Join(parsedObjects, \" \")\n\n\t// this is where debug & other console.* apis will default to (such as\n\t// console.table).\n\tl.Debug(msg)\n}\n\n// We should consider building an API around this as it could be useful\n// information about the user's website not handling exceptions.\nfunc (fs *FrameSession) onExceptionThrown(event *cdpruntime.EventExceptionThrown) {\n\tfs.logger.Debugf(\"FrameSession:onExceptionThrown\",\n\t\t\"sid:%v tid:%v url:%s line:%d col:%d text:%s\",\n\t\tfs.session.ID(), fs.targetID, event.ExceptionDetails.URL,\n\t\tevent.ExceptionDetails.LineNumber, event.ExceptionDetails.ColumnNumber,\n\t\tevent.ExceptionDetails.Text)\n}\n\nfunc (fs *FrameSession) onExecutionContextCreated(event *cdpruntime.EventExecutionContextCreated) {\n\tfs.logger.Debugf(\"FrameSession:onExecutionContextCreated\",\n\t\t\"sid:%v tid:%v ectxid:%d\",\n\t\tfs.session.ID(), fs.targetID, event.Context.ID)\n\n\tauxData := event.Context.AuxData\n\tvar i struct {\n\t\tFrameID   cdp.FrameID `json:\"frameId\"`\n\t\tIsDefault bool        `json:\"isDefault\"`\n\t\tType      string      `json:\"type\"`\n\t}\n\tif err := json.Unmarshal(auxData, &i); err != nil {\n\t\tk6ext.Panicf(fs.ctx, \"unmarshaling executionContextCreated event JSON: %w\", err)\n\t}\n\n\tframe, ok := fs.manager.getFrameByID(i.FrameID)\n\tif !ok {\n\t\tfs.logger.Debugf(\"FrameSession:onExecutionContextCreated:return\",\n\t\t\t\"sid:%v tid:%v ectxid:%d missing frame\",\n\t\t\tfs.session.ID(), fs.targetID, event.Context.ID)\n\t\treturn\n\t}\n\n\tvar world executionWorld\n\tif i.IsDefault {\n\t\tworld = mainWorld\n\t} else if event.Context.Name == utilityWorldName && !frame.hasContext(utilityWorld) {\n\t\t// In case of multiple sessions to the same target, there's a race between\n\t\t// connections so we might end up creating multiple isolated worlds.\n\t\t// We can use either.\n\t\tworld = utilityWorld\n\t}\n\n\tif i.Type == \"isolated\" {\n\t\tfs.isolatedWorlds[event.Context.Name] = true\n\t}\n\tcontext := NewExecutionContext(fs.ctx, fs.session, frame, event.Context.ID, fs.logger)\n\tif world != \"\" {\n\t\tfs.logger.Debugf(\"FrameSession:setContext\",\n\t\t\t\"sid:%v fid:%v ectxid:%d\",\n\t\t\tfs.session.ID(), frame.ID(), event.Context.ID)\n\t\tframe.setContext(world, context)\n\t}\n\tfs.contextIDToContextMu.Lock()\n\tfs.contextIDToContext[event.Context.ID] = context\n\tfs.contextIDToContextMu.Unlock()\n}\n\nfunc (fs *FrameSession) onExecutionContextDestroyed(execCtxID cdpruntime.ExecutionContextID) {\n\tfs.logger.Debugf(\"FrameSession:onExecutionContextDestroyed\",\n\t\t\"sid:%v tid:%v ectxid:%d\",\n\t\tfs.session.ID(), fs.targetID, execCtxID)\n\n\tfs.contextIDToContextMu.Lock()\n\tdefer fs.contextIDToContextMu.Unlock()\n\tcontext, ok := fs.contextIDToContext[execCtxID]\n\tif !ok {\n\t\treturn\n\t}\n\tif context.Frame() != nil {\n\t\tcontext.Frame().nullContext(execCtxID)\n\t}\n\tdelete(fs.contextIDToContext, execCtxID)\n}\n\nfunc (fs *FrameSession) onExecutionContextsCleared() {\n\tfs.logger.Debugf(\"FrameSession:onExecutionContextsCleared\",\n\t\t\"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\tfs.contextIDToContextMu.Lock()\n\tdefer fs.contextIDToContextMu.Unlock()\n\n\tfor _, context := range fs.contextIDToContext {\n\t\tif context.Frame() != nil {\n\t\t\tcontext.Frame().nullContext(context.id)\n\t\t}\n\t}\n\tfor k := range fs.contextIDToContext {\n\t\tdelete(fs.contextIDToContext, k)\n\t}\n}\n\nfunc (fs *FrameSession) onFrameAttached(frameID cdp.FrameID, parentFrameID cdp.FrameID) {\n\tfs.logger.Debugf(\"FrameSession:onFrameAttached\",\n\t\t\"sid:%v tid:%v fid:%v pfid:%v\",\n\t\tfs.session.ID(), fs.targetID, frameID, parentFrameID)\n\n\t// TODO: add handling for cross-process frame transitioning\n\tfs.manager.frameAttached(frameID, parentFrameID)\n}\n\nfunc (fs *FrameSession) onFrameDetached(frameID cdp.FrameID, reason cdppage.FrameDetachedReason) {\n\tfs.logger.Debugf(\"FrameSession:onFrameDetached\",\n\t\t\"sid:%v tid:%v fid:%v reason:%s\",\n\t\tfs.session.ID(), fs.targetID, frameID, reason)\n\n\tif err := fs.manager.frameDetached(frameID, reason); err != nil {\n\t\tk6ext.Panicf(fs.ctx, \"handling frameDetached event: %w\", err)\n\t}\n}\n\nfunc (fs *FrameSession) onFrameNavigated(frame *cdp.Frame, initial bool) {\n\tfs.logger.Debugf(\"FrameSession:onFrameNavigated\",\n\t\t\"sid:%v tid:%v fid:%v\",\n\t\tfs.session.ID(), fs.targetID, frame.ID)\n\n\terr := fs.manager.frameNavigated(\n\t\tframe.ID, frame.ParentID, frame.LoaderID.String(),\n\t\tframe.Name, frame.URL+frame.URLFragment, initial)\n\tif err != nil {\n\t\tk6ext.Panicf(fs.ctx, \"handling frameNavigated event to %q: %w\",\n\t\t\tframe.URL+frame.URLFragment, err)\n\t}\n\n\t// Only create a navigation span once from here, since a new page navigating\n\t// to about:blank doesn't call onFrameStartedLoading. All subsequent\n\t// navigations call onFrameStartedLoading.\n\tif fs.initialNavDone {\n\t\treturn\n\t}\n\n\tfs.initialNavDone = true\n\tfs.processNavigationSpan(frame.ID)\n}\n\nfunc (fs *FrameSession) processNavigationSpan(id cdp.FrameID) {\n\tnewFrame, ok := fs.manager.getFrameByID(id)\n\tif !ok {\n\t\treturn\n\t}\n\n\t// Trace navigation only for the main frame.\n\t// TODO: How will this affect sub frames such as iframes?\n\tif newFrame.page.frameManager.MainFrame() != newFrame {\n\t\treturn\n\t}\n\n\t// End the navigation span if it is non-nil\n\tif fs.mainFrameSpan != nil {\n\t\t// The url needs to be added here instead of at the start of the span\n\t\t// because at the start of the span we don't know the correct url for\n\t\t// the page we're navigating to. At the end of the span we do have this\n\t\t// information.\n\t\tfs.mainFrameSpan.SetAttributes(attribute.String(\"navigation.url\", fs.manager.MainFrameURL()))\n\t\tfs.mainFrameSpan.End()\n\t}\n\n\t_, fs.mainFrameSpan = TraceNavigation(\n\t\tfs.ctx, fs.targetID.String(),\n\t)\n\n\tspanID := fs.mainFrameSpan.SpanContext().SpanID().String()\n\n\t// Set k6SpanId property in the page so it can be retrieved when pushing\n\t// the Web Vitals events from the page execution context and used to\n\t// correlate them with the navigation span to which they belong to.\n\tsetSpanIDProp := func() {\n\t\tjs := fmt.Sprintf(\"window.k6SpanId = '%s';\", spanID)\n\t\terr := newFrame.EvaluateGlobal(fs.ctx, js)\n\t\tif err != nil {\n\t\t\tfs.logger.Debugf(\n\t\t\t\t\"FrameSession:onFrameNavigated\", \"error on evaluating window.k6SpanId: %v\", err,\n\t\t\t)\n\t\t}\n\t}\n\n\t// Executing a CDP command in the event parsing goroutine might deadlock in some cases.\n\t// For example a deadlock happens if the content loaded in the frame that has navigated\n\t// includes a JavaScript initiated dialog which we have to explicitly accept or dismiss\n\t// (see onEventJavascriptDialogOpening). In that case our EvaluateGlobal call can't be\n\t// executed, as the browser is waiting for us to accept/dismiss the JS dialog, but we\n\t// can't act on that because the event parsing goroutine is stuck in onFrameNavigated.\n\t// Because in this case the action is to set an attribute to the global object (window)\n\t// it should be safe to just execute this in a separate goroutine.\n\tgo setSpanIDProp()\n}\n\nfunc (fs *FrameSession) onFrameRequestedNavigation(event *cdppage.EventFrameRequestedNavigation) {\n\tfs.logger.Debugf(\"FrameSession:onFrameRequestedNavigation\",\n\t\t\"sid:%v tid:%v fid:%v url:%q\",\n\t\tfs.session.ID(), fs.targetID, event.FrameID, event.URL)\n\n\tif event.Disposition == \"currentTab\" {\n\t\terr := fs.manager.frameRequestedNavigation(event.FrameID, event.URL, \"\")\n\t\tif err != nil {\n\t\t\tk6ext.Panicf(fs.ctx, \"handling frameRequestedNavigation event to %q: %w\", event.URL, err)\n\t\t}\n\t}\n}\n\nfunc (fs *FrameSession) onFrameStartedLoading(frameID cdp.FrameID) {\n\tfs.logger.Debugf(\"FrameSession:onFrameStartedLoading\",\n\t\t\"sid:%v tid:%v fid:%v\",\n\t\tfs.session.ID(), fs.targetID, frameID)\n\n\tfs.processNavigationSpan(frameID)\n\n\tfs.manager.frameLoadingStarted(frameID)\n}\n\nfunc (fs *FrameSession) onFrameStoppedLoading(frameID cdp.FrameID) {\n\tfs.logger.Debugf(\"FrameSession:onFrameStoppedLoading\",\n\t\t\"sid:%v tid:%v fid:%v\",\n\t\tfs.session.ID(), fs.targetID, frameID)\n\n\tfs.manager.frameLoadingStopped(frameID)\n}\n\nfunc (fs *FrameSession) onLogEntryAdded(event *cdplog.EventEntryAdded) {\n\tl := fs.logger.\n\t\tWithTime(event.Entry.Timestamp.Time()).\n\t\tWithField(\"source\", \"browser\").\n\t\tWithField(\"url\", event.Entry.URL).\n\t\tWithField(\"browser_source\", event.Entry.Source.String()).\n\t\tWithField(\"line_number\", event.Entry.LineNumber)\n\n\t/* accessing the state Group while not on the eventloop is racy\n\tif s := fs.vu.State(); s.Group.Path != \"\" {\n\t\tl = l.WithField(\"group\", s.Group.Path)\n\t}\n\t*/\n\n\tl.Debug(event.Entry.Text)\n}\n\nfunc (fs *FrameSession) onPageLifecycle(event *cdppage.EventLifecycleEvent) {\n\tfs.logger.Debugf(\"FrameSession:onPageLifecycle\",\n\t\t\"sid:%v tid:%v fid:%v event:%s eventTime:%q\",\n\t\tfs.session.ID(), fs.targetID, event.FrameID, event.Name, event.Timestamp.Time())\n\n\t_, ok := fs.manager.getFrameByID(event.FrameID)\n\tif !ok {\n\t\treturn\n\t}\n\n\tswitch event.Name {\n\tcase \"load\":\n\t\tfs.manager.frameLifecycleEvent(event.FrameID, LifecycleEventLoad)\n\tcase \"DOMContentLoaded\":\n\t\tfs.manager.frameLifecycleEvent(event.FrameID, LifecycleEventDOMContentLoad)\n\tcase \"networkIdle\":\n\t\tfs.manager.frameLifecycleEvent(event.FrameID, LifecycleEventNetworkIdle)\n\t}\n}\n\nfunc (fs *FrameSession) onPageNavigatedWithinDocument(event *cdppage.EventNavigatedWithinDocument) {\n\tfs.logger.Debugf(\"FrameSession:onPageNavigatedWithinDocument\",\n\t\t\"sid:%v tid:%v fid:%v\",\n\t\tfs.session.ID(), fs.targetID, event.FrameID)\n\n\tfs.manager.frameNavigatedWithinDocument(event.FrameID, event.URL)\n}\n\nfunc (fs *FrameSession) onAttachedToTarget(event *target.EventAttachedToTarget) {\n\tvar (\n\t\tti  = event.TargetInfo\n\t\tsid = event.SessionID\n\t\terr error\n\t)\n\n\tfs.logger.Debugf(\"FrameSession:onAttachedToTarget\",\n\t\t\"sid:%v tid:%v esid:%v etid:%v ebctxid:%v type:%q\",\n\t\tfs.session.ID(), fs.targetID, event.SessionID,\n\t\tevent.TargetInfo.TargetID, event.TargetInfo.BrowserContextID,\n\t\tevent.TargetInfo.Type)\n\n\tsession := fs.page.browserCtx.getSession(event.SessionID)\n\tif session == nil {\n\t\tfs.logger.Debugf(\"FrameSession:onAttachedToTarget:NewFrameSession\",\n\t\t\t\"sid:%v tid:%v esid:%v etid:%v ebctxid:%v type:%q err:nil session\",\n\t\t\tfs.session.ID(), fs.targetID, event.SessionID,\n\t\t\tevent.TargetInfo.TargetID, event.TargetInfo.BrowserContextID,\n\t\t\tevent.TargetInfo.Type)\n\t\treturn\n\t}\n\n\tswitch ti.Type {\n\tcase \"iframe\":\n\t\terr = fs.attachIFrameToTarget(ti, session)\n\tcase \"worker\":\n\t\terr = fs.attachWorkerToTarget(ti, session)\n\tdefault:\n\t\tfs.logger.Debugf(\"FrameSession:onAttachedToTarget\",\n\t\t\t\"unsupported target type %q sid:%v\", ti.Type, session.ID())\n\t\tdetachSession(fs.teardownCtx, session)\n\t}\n\tif err == nil {\n\t\treturn\n\t}\n\t// Handle or ignore errors.\n\tvar reason string\n\tdefer func() {\n\t\tfs.logger.Debugf(\"FrameSession:onAttachedToTarget:return\",\n\t\t\t\"sid:%v tid:%v esid:%v etid:%v ebctxid:%v type:%q reason:%s\",\n\t\t\tfs.session.ID(), fs.targetID, sid,\n\t\t\tti.TargetID, ti.BrowserContextID,\n\t\t\tti.Type, reason)\n\t}()\n\t// Ignore errors if we're no longer connected to browser.\n\t// This happens when there is no browser but we still want to\n\t// attach a frame/worker to it.\n\tif !fs.page.browserCtx.browser.IsConnected() {\n\t\treason = \"browser disconnected\"\n\t\treturn // ignore\n\t}\n\t// Final chance:\n\t// Ignore the error if the context was canceled, otherwise,\n\t// throw a k6 error.\n\tselect {\n\tcase <-fs.ctx.Done():\n\t\treason = \"frame session context canceled\"\n\t\treturn\n\tcase <-session.done:\n\t\treason = \"session closed\"\n\t\treturn\n\tdefault:\n\t\t// Ignore context canceled error to gracefully handle shutting down\n\t\t// of the extension. This may happen because of generated events\n\t\t// while a frame session is being created.\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\treason = \"context canceled\"\n\t\t\treturn // ignore\n\t\t}\n\t\treason = \"fatal\"\n\t\tk6ext.Panicf(fs.ctx, \"attaching %v: %w\", ti.Type, err)\n\t}\n}\n\n// attachIFrameToTarget attaches an IFrame target to a given session.\nfunc (fs *FrameSession) attachIFrameToTarget(ti *target.Info, session *Session) error {\n\t// If the page is closing, don't create a new FrameSession.\n\t// Unblocks the target so the browser doesn't hang.\n\tif fs.page.isClosing() {\n\t\tfs.logger.Debugf(\"FrameSession:attachIFrameToTarget\",\n\t\t\t\"rejected frame; page is closing: tid=%v\", ti.TargetID)\n\t\tdetachSession(fs.teardownCtx, session)\n\t\treturn nil\n\t}\n\n\tsid := session.ID()\n\tfr, ok := fs.manager.getFrameByID(cdp.FrameID(ti.TargetID))\n\tif !ok {\n\t\t// IFrame should be attached to fs.page with EventFrameAttached\n\t\t// event before.\n\t\tfs.logger.Debugf(\"FrameSession:attachIFrameToTarget:return\",\n\t\t\t\"sid:%v tid:%v esid:%v etid:%v ebctxid:%v type:%q, nil frame\",\n\t\t\tfs.session.ID(), fs.targetID,\n\t\t\tsid, ti.TargetID, ti.BrowserContextID, ti.Type)\n\t\treturn nil\n\t}\n\t// Remove all children of the previously attached frame.\n\terr := fs.manager.removeChildFramesRecursively(fr)\n\tif err != nil {\n\t\tfs.logger.Debugf(\"FrameSession:attachIFrameToTarget:return\",\n\t\t\t\"sid:%v tid:%v esid:%v etid:%v ebctxid:%v type:%q, can't remove child frames recursively: %q\",\n\t\t\tfs.session.ID(), fs.targetID, sid, ti.TargetID, ti.BrowserContextID, ti.Type, err)\n\t}\n\n\tnfs, err := NewFrameSession(\n\t\tfs.ctx,\n\t\tfs.teardownCtx,\n\t\tsession,\n\t\tfs.page, fs, ti.TargetID,\n\t\tfs.logger,\n\t\tfalse)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"attaching iframe target ID %v to session ID %v: %w\",\n\t\t\tti.TargetID, sid, err)\n\t}\n\n\tif err := fs.page.attachFrameSession(cdp.FrameID(ti.TargetID), nfs); err != nil {\n\t\tif errors.Is(err, errPageClosing) {\n\t\t\tfs.logger.Debugf(\"FrameSession:attachIFrameToTarget\",\n\t\t\t\t\"rejected frame; page is closing: tid=%v\", ti.TargetID)\n\t\t\tdetachSession(fs.teardownCtx, session)\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// attachWorkerToTarget attaches a Worker target to a given session.\nfunc (fs *FrameSession) attachWorkerToTarget(ti *target.Info, session *Session) error {\n\tif fs.page.isClosing() {\n\t\tfs.logger.Debugf(\"FrameSession:attachWorkerToTarget\",\n\t\t\t\"rejected worker; page is closing: tid=%v\", ti.TargetID)\n\t\tdetachSession(fs.teardownCtx, session)\n\t\treturn nil\n\t}\n\n\tw, err := NewWorker(fs.ctx, session, ti.TargetID, ti.URL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"attaching worker target ID %v to session ID %v: %w\",\n\t\t\tti.TargetID, session.ID(), err)\n\t}\n\tfs.page.addWorker(session.ID(), w)\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) onDetachedFromTarget(event *target.EventDetachedFromTarget) {\n\tfs.logger.Debugf(\"FrameSession:onDetachedFromTarget\",\n\t\t\"sid:%v tid:%v esid:%v\",\n\t\tfs.session.ID(), fs.targetID, event.SessionID)\n\n\tfs.page.removeWorker(event.SessionID)\n}\n\nfunc (fs *FrameSession) onTargetCrashed() {\n\tfs.logger.Debugf(\"FrameSession:onTargetCrashed\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\t// TODO:?\n\ts, ok := fs.session.(*Session)\n\tif !ok {\n\t\tk6ext.Panicf(fs.ctx, \"unexpected type %T\", fs.session)\n\t}\n\ts.markAsCrashed()\n}\n\nfunc (fs *FrameSession) updateEmulateMedia() error {\n\tfs.logger.Debugf(\"NewFrameSession:updateEmulateMedia\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\tfeatures := make([]*emulation.MediaFeature, 0)\n\n\tswitch fs.page.colorScheme {\n\tcase ColorSchemeLight:\n\t\tfeatures = append(features, &emulation.MediaFeature{Name: \"prefers-color-scheme\", Value: \"light\"})\n\tcase ColorSchemeDark:\n\t\tfeatures = append(features, &emulation.MediaFeature{Name: \"prefers-color-scheme\", Value: \"dark\"})\n\tdefault:\n\t\tfeatures = append(features, &emulation.MediaFeature{Name: \"prefers-color-scheme\", Value: \"\"})\n\t}\n\n\tswitch fs.page.reducedMotion {\n\tcase ReducedMotionReduce:\n\t\tfeatures = append(features, &emulation.MediaFeature{Name: \"prefers-reduced-motion\", Value: \"reduce\"})\n\tdefault:\n\t\tfeatures = append(features, &emulation.MediaFeature{Name: \"prefers-reduced-motion\", Value: \"\"})\n\t}\n\n\taction := emulation.SetEmulatedMedia().\n\t\tWithMedia(string(fs.page.mediaType)).\n\t\tWithFeatures(features)\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn fmt.Errorf(\"internal error while updating emulated media: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (fs *FrameSession) updateExtraHTTPHeaders(initial bool) error {\n\tfs.logger.Debugf(\"NewFrameSession:updateExtraHTTPHeaders\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\t// Merge extra headers from browser context and page, where page specific headers ake precedence.\n\tmergedHeaders := make(network.Headers)\n\tfor k, v := range fs.page.browserCtx.opts.ExtraHTTPHeaders {\n\t\tmergedHeaders[k] = v\n\t}\n\tfor k, v := range fs.page.extraHTTPHeaders {\n\t\tmergedHeaders[k] = v\n\t}\n\tif !initial || len(mergedHeaders) > 0 {\n\t\tif err := fs.networkManager.SetExtraHTTPHeaders(mergedHeaders); err != nil {\n\t\t\treturn fmt.Errorf(\"updating extra HTTP headers: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) updateGeolocation(initial bool) error {\n\tfs.logger.Debugf(\"NewFrameSession:updateGeolocation\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\tgeolocation := fs.page.browserCtx.opts.Geolocation\n\tif !initial || geolocation != nil {\n\t\taction := emulation.SetGeolocationOverride().\n\t\t\tWithLatitude(geolocation.Latitude).\n\t\t\tWithLongitude(geolocation.Longitude).\n\t\t\tWithAccuracy(geolocation.Accuracy)\n\t\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"%w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) updateHTTPCredentials(initial bool) error {\n\tfs.logger.Debugf(\"NewFrameSession:updateHttpCredentials\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\tcredentials := fs.page.browserCtx.opts.HTTPCredentials\n\tif !initial || !credentials.IsEmpty() {\n\t\treturn fs.networkManager.Authenticate(credentials)\n\t}\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) updateOffline(initial bool) error {\n\tfs.logger.Debugf(\"NewFrameSession:updateOffline\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\toffline := fs.page.browserCtx.opts.Offline\n\tif !initial || offline {\n\t\tif err := fs.networkManager.SetOfflineMode(offline); err != nil {\n\t\t\treturn fmt.Errorf(\"updating offline mode for frame %v: %w\", fs.targetID, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) throttleNetwork(networkProfile NetworkProfile) error {\n\tfs.logger.Debugf(\"NewFrameSession:throttleNetwork\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\treturn fs.networkManager.ThrottleNetwork(networkProfile)\n}\n\nfunc (fs *FrameSession) throttleCPU(cpuProfile CPUProfile) error {\n\taction := emulation.SetCPUThrottlingRate(cpuProfile.Rate)\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn fmt.Errorf(\"throttling CPU: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) updateRequestInterception(enable bool) error {\n\tfs.logger.Debugf(\"NewFrameSession:updateRequestInterception\",\n\t\t\"sid:%v tid:%v on:%v\",\n\t\tfs.session.ID(),\n\t\tfs.targetID, enable)\n\n\treturn fs.networkManager.setRequestInterception(enable)\n}\n\nfunc (fs *FrameSession) updateViewport() error {\n\tfs.logger.Debugf(\"NewFrameSession:updateViewport\", \"sid:%v tid:%v\", fs.session.ID(), fs.targetID)\n\n\t// other frames don't have viewports and,\n\t// this method shouldn't be called for them.\n\t// this is just a sanity check.\n\tif !fs.isMainFrame() {\n\t\terr := fmt.Errorf(\"updateViewport should be called only in the main frame.\"+\n\t\t\t\" (sid:%v tid:%v)\", fs.session.ID(), fs.targetID)\n\t\tpanic(err)\n\t}\n\n\topts := fs.page.browserCtx.opts\n\temulatedSize := fs.page.emulatedSize\n\tif emulatedSize == nil {\n\t\treturn nil\n\t}\n\tviewport := emulatedSize.Viewport\n\tscreen := emulatedSize.Screen\n\n\torientation := emulation.ScreenOrientation{\n\t\tAngle: 0.0,\n\t\tType:  emulation.OrientationTypePortraitPrimary,\n\t}\n\tif viewport.Width > viewport.Height {\n\t\torientation.Angle = 90.0\n\t\torientation.Type = emulation.OrientationTypeLandscapePrimary\n\t}\n\taction := emulation.SetDeviceMetricsOverride(viewport.Width, viewport.Height, opts.DeviceScaleFactor, opts.IsMobile).\n\t\tWithScreenOrientation(&orientation).\n\t\tWithScreenWidth(screen.Width).\n\t\tWithScreenHeight(screen.Height)\n\tif err := action.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\treturn fmt.Errorf(\"emulating viewport: %w\", err)\n\t}\n\n\tif fs.hasUIWindow {\n\t\t// add an inset to viewport depending on the operating system.\n\t\t// this won't add an inset if we're running in headless mode.\n\t\tviewport = viewport.recalculateInset(\n\t\t\tfs.page.browserCtx.browser.browserOpts.Headless,\n\t\t\truntime.GOOS,\n\t\t)\n\t\taction2 := browser.SetWindowBounds(fs.windowID, &browser.Bounds{\n\t\t\tWidth:  viewport.Width,\n\t\t\tHeight: viewport.Height,\n\t\t})\n\t\tif err := action2.Do(cdp.WithExecutor(fs.ctx, fs.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"setting window bounds: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (fs *FrameSession) executionContextForID(\n\texecutionContextID cdpruntime.ExecutionContextID,\n) (*ExecutionContext, error) {\n\tfs.contextIDToContextMu.Lock()\n\tdefer fs.contextIDToContextMu.Unlock()\n\n\tif exc, ok := fs.contextIDToContext[executionContextID]; ok {\n\t\treturn exc, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"no execution context found for id: %v\", executionContextID)\n}\n\n// detachSession unblocks a target waiting for debugger and detaches from it.\n// Prevents the browser from hanging on rejected targets during close\nfunc detachSession(ctx context.Context, session *Session) {\n\t_ = session.ExecuteWithoutExpectationOnReply(ctx, cdpruntime.CommandRunIfWaitingForDebugger, nil, nil)\n\t_ = session.ExecuteWithoutExpectationOnReply(ctx, target.CommandDetachFromTarget,\n\t\t&target.DetachFromTargetParams{SessionID: session.id}, nil)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/frame_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// Test calling Frame.document does not panic with a nil document.\n// See: Issue #53 for details.\nfunc TestFrameNilDocument(t *testing.T) {\n\tt.Parallel()\n\n\tvu := k6test.NewVU(t)\n\tlog := log.NewNullLogger()\n\n\tfm := NewFrameManager(vu.Context(), nil, nil, nil, log)\n\tframe := NewFrame(vu.Context(), fm, nil, cdp.FrameID(\"42\"), log)\n\n\t// frame should not panic with a nil document\n\tstub := &executionContextTestStub{\n\t\tevalFn: func(apiCtx context.Context, opts evalOptions, js string, args ...any) (res any, err error) {\n\t\t\t// return nil to test for panic\n\t\t\treturn nil, nil //nolint:nilnil\n\t\t},\n\t}\n\n\t// document() waits for the main execution context\n\tok := make(chan struct{}, 1)\n\tgo func() {\n\t\tframe.setContext(mainWorld, stub)\n\t\tok <- struct{}{}\n\t}()\n\tselect {\n\tcase <-ok:\n\tcase <-time.After(time.Second):\n\t\trequire.FailNow(t, \"cannot set the main execution context, frame.setContext timed out\")\n\t}\n\n\trequire.NotPanics(t, func() {\n\t\t_, err := frame.document()\n\t\trequire.Error(t, err)\n\t})\n\n\t// frame gets the document from the evaluate call\n\twant := &ElementHandle{}\n\tstub.evalFn = func(\n\t\tapiCtx context.Context, opts evalOptions, js string, args ...any,\n\t) (res any, err error) {\n\t\treturn want, nil\n\t}\n\tgot, err := frame.document()\n\trequire.NoError(t, err)\n\trequire.Equal(t, want, got)\n\n\t// frame sets documentHandle in the document method\n\tgot = frame.documentHandle\n\trequire.Equal(t, want, got)\n}\n\n// See: Issue #177 for details.\nfunc TestFrameManagerFrameAbortedNavigationShouldEmitANonNilPendingDocument(t *testing.T) {\n\tt.Parallel()\n\n\tctx, log := context.Background(), log.NewNullLogger()\n\n\t// add the frame to frame manager\n\tfm := NewFrameManager(ctx, nil, nil, NewTimeoutSettings(nil), log)\n\tframe := NewFrame(ctx, fm, nil, cdp.FrameID(\"42\"), log)\n\tfm.frames[frame.id] = frame\n\n\t// listen for frame navigation events\n\trecv := make(chan Event)\n\tframe.on(ctx, []string{EventFrameNavigation}, recv)\n\n\t// emit the navigation event\n\tframe.pendingDocument = &DocumentInfo{\n\t\tdocumentID: \"42\",\n\t}\n\tfm.frameAbortedNavigation(frame.id, \"any error\", frame.pendingDocument.documentID)\n\n\t// receive the emitted event and verify that emitted document\n\t// is not nil.\n\te := <-recv\n\trequire.IsType(t, &NavigationEvent{}, e.data, \"event should be a navigation event\")\n\tne := e.data.(*NavigationEvent)\n\trequire.NotNil(t, ne, \"event should not be nil\")\n\trequire.NotNil(t, ne.newDocument, \"emitted document should not be nil\")\n\n\t// since the navigation is aborted, the aborting frame should have\n\t// a nil pending document.\n\trequire.Nil(t, frame.pendingDocument)\n}\n\ntype executionContextTestStub struct {\n\tExecutionContext\n\tevalFn func(\n\t\tapiCtx context.Context, opts evalOptions, js string, args ...any,\n\t) (res any, err error)\n}\n\nfunc (e *executionContextTestStub) eval( // this needs to be a pointer as otherwise it will copy the mutex inside of it\n\tapiCtx context.Context, opts evalOptions, js string, args ...any,\n) (res any, err error) {\n\treturn e.evalFn(apiCtx, opts, js, args...)\n}\n\n// toPtr is a helper function to convert a value to a pointer.\nfunc toPtr[T any](v T) *T {\n\treturn &v\n}\n\nfunc TestBuildAttributeSelector(t *testing.T) {\n\tt.Parallel()\n\n\tf := &Frame{}\n\n\ttests := []struct {\n\t\tname      string\n\t\tattrName  string\n\t\tattrValue string\n\t\topts      *GetByBaseOptions\n\t\twant      string\n\t}{\n\t\t{\n\t\t\tname:      \"empty\",\n\t\t\tattrName:  \"\",\n\t\t\tattrValue: \"\",\n\t\t\topts:      nil,\n\t\t\twant:      \"internal:attr=[=]\",\n\t\t},\n\t\t{\n\t\t\tname:      \"unquoted_no_opts\",\n\t\t\tattrName:  \"data-test\",\n\t\t\tattrValue: \"foo\",\n\t\t\topts:      nil,\n\t\t\twant:      \"internal:attr=[data-test=foo]\",\n\t\t},\n\t\t{\n\t\t\tname:      \"quoted_single_nil_opts\",\n\t\t\tattrName:  \"data-test\",\n\t\t\tattrValue: \"'Foo Bar'\",\n\t\t\topts:      nil,\n\t\t\twant:      \"internal:attr=[data-test='Foo Bar'i]\",\n\t\t},\n\t\t{\n\t\t\tname:      \"quoted_single_exact_false\",\n\t\t\tattrName:  \"data-test\",\n\t\t\tattrValue: \"'Foo Bar'\",\n\t\t\topts:      &GetByBaseOptions{Exact: toPtr(false)},\n\t\t\twant:      \"internal:attr=[data-test='Foo Bar'i]\",\n\t\t},\n\t\t{\n\t\t\tname:      \"quoted_single_exact_true\",\n\t\t\tattrName:  \"data-test\",\n\t\t\tattrValue: \"'Foo Bar'\",\n\t\t\topts:      &GetByBaseOptions{Exact: toPtr(true)},\n\t\t\twant:      \"internal:attr=[data-test='Foo Bar's]\",\n\t\t},\n\t\t{\n\t\t\tname:      \"quoted_double_exact_true\",\n\t\t\tattrName:  \"data-test\",\n\t\t\tattrValue: \"\\\"Foo Bar\\\"\",\n\t\t\topts:      &GetByBaseOptions{Exact: toPtr(true)},\n\t\t\twant:      \"internal:attr=[data-test=\\\"Foo Bar\\\"s]\",\n\t\t},\n\t\t{\n\t\t\tname:      \"quoted_double_exact_false\",\n\t\t\tattrName:  \"data-test\",\n\t\t\tattrValue: \"\\\"Foo Bar\\\"\",\n\t\t\topts:      &GetByBaseOptions{Exact: toPtr(false)},\n\t\t\twant:      \"internal:attr=[data-test=\\\"Foo Bar\\\"i]\",\n\t\t},\n\t\t{\n\t\t\tname:      \"quoted_single_exact_nil\",\n\t\t\tattrName:  \"data-test\",\n\t\t\tattrValue: \"'Foo Bar'\",\n\t\t\topts:      &GetByBaseOptions{Exact: nil},\n\t\t\twant:      \"internal:attr=[data-test='Foo Bar'i]\",\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot := f.buildAttributeSelector(tc.attrName, tc.attrValue, tc.opts)\n\t\t\trequire.Equal(t, tc.want, got)\n\t\t})\n\t}\n}\n\nfunc TestIsQuotedText(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname string\n\t\tin   string\n\t\twant bool\n\t}{\n\t\t{name: \"empty\", in: \"\", want: false},\n\t\t{name: \"unquoted\", in: \"foo\", want: false},\n\t\t{name: \"single_quoted\", in: \"'foo'\", want: true},\n\t\t{name: \"double_quoted\", in: \"\\\"foo\\\"\", want: true},\n\t\t{name: \"mismatched_quotes_1\", in: \"'foo\\\"\", want: false},\n\t\t{name: \"mismatched_quotes_2\", in: \"\\\"foo'\", want: false},\n\t\t{name: \"just_single_quote\", in: \"'\", want: false},\n\t\t{name: \"just_double_quote\", in: \"\\\"\", want: false},\n\t\t{name: \"two_single_quotes\", in: \"''\", want: true},\n\t\t{name: \"two_double_quotes\", in: \"\\\"\\\"\", want: true},\n\t\t{name: \"leading_space_then_quoted\", in: \" 'foo'\", want: true},\n\t\t{name: \"trailing_space_after_quoted\", in: \"'foo' \", want: true},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot := isQuotedText(tc.in)\n\t\t\tif got != tc.want {\n\t\t\t\tt.Fatalf(\"isQuotedText(%q) = %v, want %v\", tc.in, got, tc.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/helpers.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"regexp\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\tcdpruntime \"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n)\n\nfunc convertBaseJSHandleTypes(\n\t_ context.Context, execCtx *ExecutionContext, objHandle *BaseJSHandle,\n) (*cdpruntime.CallArgument, error) {\n\tif objHandle.execCtx != execCtx {\n\t\treturn nil, ErrWrongExecutionContext\n\t}\n\tif objHandle.disposed {\n\t\treturn nil, ErrJSHandleDisposed\n\t}\n\tif objHandle.remoteObject.UnserializableValue.String() != \"\" {\n\t\treturn &cdpruntime.CallArgument{\n\t\t\tUnserializableValue: objHandle.remoteObject.UnserializableValue,\n\t\t}, nil\n\t}\n\tif objHandle.remoteObject.ObjectID.String() == \"\" {\n\t\treturn &cdpruntime.CallArgument{Value: objHandle.remoteObject.Value}, nil\n\t}\n\treturn &cdpruntime.CallArgument{ObjectID: objHandle.remoteObject.ObjectID}, nil\n}\n\nfunc convertArgument(\n\tctx context.Context, execCtx *ExecutionContext, arg any,\n) (*cdpruntime.CallArgument, error) {\n\tif escapesSobekValues(arg) {\n\t\treturn nil, errors.New(\"sobek.Value escaped\")\n\t}\n\tswitch a := arg.(type) {\n\tcase int64:\n\t\tif a > math.MaxInt32 {\n\t\t\treturn &cdpruntime.CallArgument{\n\t\t\t\tUnserializableValue: cdpruntime.UnserializableValue(fmt.Sprintf(\"%dn\", a)),\n\t\t\t}, nil\n\t\t}\n\t\tb, err := json.Marshal(a)\n\t\treturn &cdpruntime.CallArgument{Value: b}, err\n\tcase float64:\n\t\tvar unserVal string\n\t\tswitch a {\n\t\tcase math.Float64frombits(0 | (1 << 63)):\n\t\t\tunserVal = \"-0\"\n\t\tcase math.Inf(0):\n\t\t\tunserVal = \"Infinity\"\n\t\tcase math.Inf(-1):\n\t\t\tunserVal = \"-Infinity\"\n\t\tdefault:\n\t\t\tif math.IsNaN(a) {\n\t\t\t\tunserVal = \"NaN\"\n\t\t\t}\n\t\t}\n\n\t\tif unserVal != \"\" {\n\t\t\treturn &cdpruntime.CallArgument{\n\t\t\t\tUnserializableValue: cdpruntime.UnserializableValue(unserVal),\n\t\t\t}, nil\n\t\t}\n\n\t\tb, err := json.Marshal(a)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"converting argument '%v': %w\", arg, err)\n\t\t}\n\n\t\treturn &cdpruntime.CallArgument{Value: b}, err\n\tcase *ElementHandle:\n\t\treturn convertBaseJSHandleTypes(ctx, execCtx, &a.BaseJSHandle)\n\tcase *BaseJSHandle:\n\t\treturn convertBaseJSHandleTypes(ctx, execCtx, a)\n\tdefault:\n\t\tb, err := json.Marshal(a)\n\t\treturn &cdpruntime.CallArgument{Value: b}, err //nolint:wrapcheck\n\t}\n}\n\nfunc call(\n\tctx context.Context, fn func(context.Context, chan any, chan error), timeout time.Duration,\n) (any, error) {\n\tvar (\n\t\tresult   any\n\t\terr      error\n\t\tcancelFn context.CancelFunc\n\t\tresultCh = make(chan any)\n\t\terrCh    = make(chan error)\n\t)\n\tif timeout > 0 {\n\t\tctx, cancelFn = context.WithTimeout(ctx, timeout)\n\t\tdefer cancelFn()\n\t}\n\n\tgo fn(ctx, resultCh, errCh)\n\n\tselect {\n\tcase <-ctx.Done():\n\t\terr = &k6ext.UserFriendlyError{\n\t\t\tErr:     ContextErr(ctx),\n\t\t\tTimeout: timeout,\n\t\t}\n\tcase result = <-resultCh:\n\tcase err = <-errCh:\n\t}\n\n\treturn result, err\n}\n\n//nolint:gocognit\nfunc createWaitForEventHandler(\n\tctx context.Context,\n\temitter EventEmitter, events []string,\n\tpredicateFn func(data any) bool,\n) (\n\tchan any, context.CancelFunc,\n) {\n\tevCancelCtx, evCancelFn := context.WithCancel(ctx)\n\tchEvHandler := make(chan Event)\n\tch := make(chan any)\n\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\treturn\n\t\t\tcase ev := <-chEvHandler:\n\t\t\t\tif slices.Contains(events, ev.typ) {\n\t\t\t\t\tif predicateFn != nil {\n\t\t\t\t\t\tif predicateFn(ev.data) {\n\t\t\t\t\t\t\tselect {\n\t\t\t\t\t\t\tcase ch <- ev.data:\n\t\t\t\t\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tselect {\n\t\t\t\t\t\tcase ch <- nil:\n\t\t\t\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tclose(ch)\n\n\t\t\t\t\t// We wait for one matching event only,\n\t\t\t\t\t// then remove the event handler by cancelling context and stopping goroutine.\n\t\t\t\t\tevCancelFn()\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\temitter.on(evCancelCtx, events, chEvHandler)\n\treturn ch, evCancelFn\n}\n\n// Returns a channel that will block until the predicateFn returns true.\n// This is similar to createWaitForEventHandler, except that it doesn't\n// stop waiting after the first received matching event.\nfunc createWaitForEventPredicateHandler(\n\tctx context.Context, emitter EventEmitter, events []string,\n\tpredicateFn func(data any) bool,\n) (\n\tchan any, context.CancelFunc,\n) {\n\tevCancelCtx, evCancelFn := context.WithCancel(ctx)\n\tchEvHandler := make(chan Event)\n\tch := make(chan any)\n\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\treturn\n\t\t\tcase ev := <-chEvHandler:\n\t\t\t\tif slices.Contains(events, ev.typ) &&\n\t\t\t\t\tpredicateFn != nil && predicateFn(ev.data) {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase ch <- ev.data:\n\t\t\t\t\t\tclose(ch)\n\t\t\t\t\t\tevCancelFn()\n\t\t\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\n\temitter.on(evCancelCtx, events, chEvHandler)\n\n\treturn ch, evCancelFn\n}\n\n// TrimQuotes removes surrounding single or double quotes from s.\n// We're not using strings.Trim() to avoid trimming unbalanced values,\n// e.g. `\"'arg` shouldn't change.\n// Source: https://stackoverflow.com/a/48451906\nfunc TrimQuotes(s string) string {\n\tif len(s) >= 2 {\n\t\tif c := s[len(s)-1]; s[0] == c && (c == '\"' || c == '\\'') {\n\t\t\treturn s[1 : len(s)-1]\n\t\t}\n\t}\n\treturn s\n}\n\n// convert is a helper function to convert any value to a given type.\n// underneath, it uses json.Marshal and json.Unmarshal to do the conversion.\nfunc convert[T any](from any, to *T) error {\n\tbuf, err := json.Marshal(from)\n\tif err != nil {\n\t\treturn err //nolint:wrapcheck\n\t}\n\treturn json.Unmarshal(buf, to) //nolint:wrapcheck\n}\n\n// TODO:\n// remove this temporary helper after ensuring the sobek-free\n// business logic works.\nfunc escapesSobekValues(args ...any) bool {\n\tfor _, arg := range args {\n\t\tif _, ok := arg.(sobek.Value); ok {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// patternMatcherFunc is a function that matches a string against a pattern.\ntype patternMatcherFunc func(string) (bool, error)\n\n// RegExMatcher is a function that matches a pattern against\n// a string and returns true if they match, false otherwise.\ntype RegExMatcher func(pattern, str string) (bool, error)\n\n// newPatternMatcher returns a [patternMatcherFunc] that uses string matching for\n// quoted strings, and ECMAScript (Sobek) regex matching for others. If the pattern\n// is empty or a single quote, it matches any string.\nfunc newPatternMatcher(pattern string, rm RegExMatcher) (patternMatcherFunc, error) {\n\tif pattern == \"\" || pattern == \"''\" {\n\t\treturn func(s string) (bool, error) { return true, nil }, nil\n\t}\n\tif isQuotedText(pattern) {\n\t\treturn func(s string) (bool, error) { return \"'\"+s+\"'\" == pattern, nil }, nil\n\t}\n\tif rm == nil {\n\t\treturn nil, fmt.Errorf(\"regex matcher must be provided\")\n\t}\n\treturn func(s string) (bool, error) {\n\t\tok, err := rm(pattern, s)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"matching %q against pattern %q: %w\", s, pattern, err)\n\t\t}\n\t\treturn ok, nil\n\t}, nil\n}\n\n// Match evaluates the supplied string against the given pattern using the provided\n// [RegExMatcher] for regex patterns. The matcher behavior is determined by [newPatternMatcher].\nfunc (rm RegExMatcher) Match(pattern, s string) (bool, error) {\n\tm, err := newPatternMatcher(pattern, rm)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"matching %q against pattern %q: %w\", s, pattern, err)\n\t}\n\treturn m(s)\n}\n\nvar sourceURLRegex = regexp.MustCompile(`(?s)[\\040\\t]*//[@#] sourceURL=\\s*(\\S*?)\\s*$`)\n\nfunc hasSourceURL(js string) bool {\n\tlastNotEmptyIndex := strings.LastIndexFunc(js, func(r rune) bool {\n\t\tswitch r {\n\t\tcase '\\n', '\\r', ' ', '\\t':\n\t\t\treturn false\n\t\tdefault:\n\t\t\treturn true\n\t\t}\n\t})\n\tlastNewLineBeforeLastLineIndex := 0 // default to going through the whole string\n\tif lastNotEmptyIndex != -1 {        // if there are no new lines - go through the whole string\n\t\tlastNewLineBeforeLastLineIndex = strings.LastIndex(js[:lastNotEmptyIndex], \"\\n\")\n\t\tif lastNewLineBeforeLastLineIndex == -1 { // reset to zero again\n\t\t\tlastNewLineBeforeLastLineIndex = 0\n\t\t}\n\t}\n\n\treturn sourceURLRegex.MatchString(js[lastNewLineBeforeLastLineIndex:])\n}\n\n// pushIfNotDone preserves PushIfNotDone semantics and logs when\n// a metric drop is observed because the provided context is done.\nfunc pushIfNotDone(\n\tctx context.Context,\n\tlogger *log.Logger,\n\toutput chan<- k6metrics.SampleContainer,\n\tsample k6metrics.SampleContainer,\n) {\n\tif k6metrics.PushIfNotDone(ctx, output, sample) {\n\t\treturn\n\t}\n\t// Should no longer happen under normal circumstances,\n\t// but if it does, log it for better observability.\n\tlogger.Warnf(\"pushIfNotDone\", \"dropping metric sample: %v\", ContextErr(ctx))\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/helpers_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\nfunc newExecCtx() (*ExecutionContext, context.Context) {\n\tctx := context.Background()\n\tlogger := log.NewNullLogger()\n\texecCtx := NewExecutionContext(ctx, nil, nil, runtime.ExecutionContextID(123456789), logger)\n\n\treturn execCtx, ctx\n}\n\nfunc TestConvertArgument(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"int64\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\t\tvar value int64 = 777\n\t\targ, _ := convertArgument(ctx, execCtx, value)\n\n\t\trequire.NotNil(t, arg)\n\t\tresult, _ := json.Marshal(value)\n\t\trequire.Equal(t, result, []byte(arg.Value))\n\t\trequire.Empty(t, arg.UnserializableValue)\n\t\trequire.Empty(t, arg.ObjectID)\n\t})\n\n\tt.Run(\"int64 maxint\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\n\t\tvar value int64 = math.MaxInt32 + 1\n\t\targ, _ := convertArgument(ctx, execCtx, value)\n\n\t\trequire.NotNil(t, arg)\n\t\trequire.Equal(t, fmt.Sprintf(\"%dn\", value), string(arg.UnserializableValue))\n\t\trequire.Empty(t, arg.Value)\n\t\trequire.Empty(t, arg.ObjectID)\n\t})\n\n\tt.Run(\"float64\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\n\t\tvalue := 777.0\n\t\targ, _ := convertArgument(ctx, execCtx, value)\n\n\t\trequire.NotNil(t, arg)\n\t\tresult, _ := json.Marshal(value)\n\t\trequire.Equal(t, result, []byte(arg.Value))\n\t\trequire.Empty(t, arg.UnserializableValue)\n\t\trequire.Empty(t, arg.ObjectID)\n\t})\n\n\tt.Run(\"float64 unserializable values\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\n\t\tunserializableValues := []struct {\n\t\t\tvalue    float64\n\t\t\texpected string\n\t\t}{\n\t\t\t{\n\t\t\t\tvalue:    math.Float64frombits(0 | (1 << 63)),\n\t\t\t\texpected: \"-0\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue:    math.Inf(0),\n\t\t\t\texpected: \"Infinity\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue:    math.Inf(-1),\n\t\t\t\texpected: \"-Infinity\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue:    math.NaN(),\n\t\t\t\texpected: \"NaN\",\n\t\t\t},\n\t\t}\n\n\t\tfor _, v := range unserializableValues {\n\t\t\targ, _ := convertArgument(ctx, execCtx, v.value)\n\t\t\trequire.NotNil(t, arg)\n\t\t\trequire.Equal(t, v.expected, string(arg.UnserializableValue))\n\t\t\trequire.Empty(t, arg.Value)\n\t\t\trequire.Empty(t, arg.ObjectID)\n\t\t}\n\t})\n\n\tt.Run(\"bool\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\n\t\tvalue := true\n\t\targ, _ := convertArgument(ctx, execCtx, value)\n\n\t\trequire.NotNil(t, arg)\n\t\tresult, _ := json.Marshal(value)\n\t\trequire.Equal(t, result, []byte(arg.Value))\n\t\trequire.Empty(t, arg.UnserializableValue)\n\t\trequire.Empty(t, arg.ObjectID)\n\t})\n\n\tt.Run(\"string\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\t\tvalue := \"hello world\"\n\t\targ, _ := convertArgument(ctx, execCtx, value)\n\n\t\trequire.NotNil(t, arg)\n\t\tresult, _ := json.Marshal(value)\n\t\trequire.Equal(t, result, []byte(arg.Value))\n\t\trequire.Empty(t, arg.UnserializableValue)\n\t\trequire.Empty(t, arg.ObjectID)\n\t})\n\n\tt.Run(\"*BaseJSHandle\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\t\tlog := log.NewNullLogger()\n\n\t\ttimeoutSettings := NewTimeoutSettings(nil)\n\t\tframeManager := NewFrameManager(ctx, nil, nil, timeoutSettings, log)\n\t\tframe := NewFrame(ctx, frameManager, nil, cdp.FrameID(\"frame_id_0123456789\"), log)\n\t\tremoteObjValue := \"hellow world\"\n\t\tresult, _ := json.Marshal(remoteObjValue)\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:  \"string\",\n\t\t\tValue: result,\n\t\t}\n\n\t\tvalue := NewJSHandle(ctx, nil, execCtx, frame, remoteObject, execCtx.logger)\n\t\targ, _ := convertArgument(ctx, execCtx, value)\n\n\t\trequire.NotNil(t, arg)\n\t\trequire.Equal(t, result, []byte(arg.Value))\n\t\trequire.Empty(t, arg.UnserializableValue)\n\t\trequire.Empty(t, arg.ObjectID)\n\t})\n\n\tt.Run(\"*BaseJSHandle wrong context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\t\tlog := log.NewNullLogger()\n\n\t\ttimeoutSettings := NewTimeoutSettings(nil)\n\t\tframeManager := NewFrameManager(ctx, nil, nil, timeoutSettings, log)\n\t\tframe := NewFrame(ctx, frameManager, nil, cdp.FrameID(\"frame_id_0123456789\"), log)\n\t\tremoteObjectID := runtime.RemoteObjectID(\"object_id_0123456789\")\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:     \"object\",\n\t\t\tSubtype:  \"node\",\n\t\t\tObjectID: remoteObjectID,\n\t\t}\n\t\texecCtx2 := NewExecutionContext(ctx, nil, nil, runtime.ExecutionContextID(123456789), execCtx.logger)\n\n\t\tvalue := NewJSHandle(ctx, nil, execCtx2, frame, remoteObject, execCtx.logger)\n\t\targ, err := convertArgument(ctx, execCtx, value)\n\n\t\trequire.Nil(t, arg)\n\t\trequire.ErrorIs(t, ErrWrongExecutionContext, err)\n\t})\n\n\tt.Run(\"*BaseJSHandle is disposed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\t\tlog := log.NewNullLogger()\n\n\t\ttimeoutSettings := NewTimeoutSettings(nil)\n\t\tframeManager := NewFrameManager(ctx, nil, nil, timeoutSettings, log)\n\t\tframe := NewFrame(ctx, frameManager, nil, cdp.FrameID(\"frame_id_0123456789\"), log)\n\t\tremoteObjectID := runtime.RemoteObjectID(\"object_id_0123456789\")\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:     \"object\",\n\t\t\tSubtype:  \"node\",\n\t\t\tObjectID: remoteObjectID,\n\t\t}\n\n\t\tvalue := NewJSHandle(ctx, nil, execCtx, frame, remoteObject, execCtx.logger)\n\t\tvalue.(*BaseJSHandle).disposed = true\n\t\targ, err := convertArgument(ctx, execCtx, value)\n\n\t\trequire.Nil(t, arg)\n\t\trequire.ErrorIs(t, ErrJSHandleDisposed, err)\n\t})\n\n\tt.Run(\"*BaseJSHandle as *ElementHandle\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texecCtx, ctx := newExecCtx()\n\t\tlog := log.NewNullLogger()\n\n\t\ttimeoutSettings := NewTimeoutSettings(nil)\n\t\tframeManager := NewFrameManager(ctx, nil, nil, timeoutSettings, log)\n\t\tframe := NewFrame(ctx, frameManager, nil, cdp.FrameID(\"frame_id_0123456789\"), log)\n\t\tremoteObjectID := runtime.RemoteObjectID(\"object_id_0123456789\")\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:     \"object\",\n\t\t\tSubtype:  \"node\",\n\t\t\tObjectID: remoteObjectID,\n\t\t}\n\n\t\tvalue := NewJSHandle(ctx, nil, execCtx, frame, remoteObject, execCtx.logger)\n\t\targ, _ := convertArgument(ctx, execCtx, value)\n\n\t\trequire.NotNil(t, arg)\n\t\trequire.Equal(t, remoteObjectID, arg.ObjectID)\n\t\trequire.Empty(t, arg.Value)\n\t\trequire.Empty(t, arg.UnserializableValue)\n\t})\n}\n\nfunc TestHasSourceURL(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\tjs     string\n\t\tresult bool\n\t}{\n\t\t\"empty\": {\n\t\t\tjs:     \"\",\n\t\t\tresult: false,\n\t\t},\n\t\t\"simple\": {\n\t\t\tjs:     \"something;\\n//# sourceURL=somethingher\",\n\t\t\tresult: true,\n\t\t},\n\t\t\"simple without\": {\n\t\t\tjs:     \"something\",\n\t\t\tresult: false,\n\t\t},\n\t\t\"only sourceURL\": {\n\t\t\tjs:     \"//# sourceURL=somethinghere\",\n\t\t\tresult: true,\n\t\t},\n\t}\n\n\tfor name, c := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trequire.Equal(t, c.result, hasSourceURL(c.js))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/hooks.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n)\n\ntype HookID int\n\nconst (\n\tHookApplySlowMo HookID = iota\n)\n\ntype Hook func(context.Context)\n\ntype Hooks struct {\n\tmu    sync.RWMutex\n\thooks map[HookID]Hook\n}\n\nfunc applySlowMo(ctx context.Context) {\n\thooks := GetHooks(ctx)\n\tif hooks == nil {\n\t\treturn\n\t}\n\tif hook := hooks.Get(HookApplySlowMo); hook != nil {\n\t\thook(ctx)\n\t}\n}\n\nfunc defaultSlowMo(ctx context.Context) {\n\tsm := GetBrowserOptions(ctx).SlowMo\n\tif sm <= 0 {\n\t\treturn\n\t}\n\tselect {\n\tcase <-ctx.Done():\n\tcase <-time.After(sm):\n\t}\n}\n\nfunc NewHooks() *Hooks {\n\th := Hooks{\n\t\thooks: make(map[HookID]Hook),\n\t}\n\th.registerDefaultHooks()\n\treturn &h\n}\n\nfunc (h *Hooks) registerDefaultHooks() {\n\th.Register(HookApplySlowMo, defaultSlowMo)\n}\n\nfunc (h *Hooks) Get(id HookID) Hook {\n\th.mu.RLock()\n\tdefer h.mu.RUnlock()\n\treturn h.hooks[id]\n}\n\nfunc (h *Hooks) Register(id HookID, hook Hook) {\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\th.hooks[id] = hook\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/http.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/fetch\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\tk6modules \"go.k6.io/k6/js/modules\"\n)\n\n// These ResourceTypes are duplicates of CDP's network.ResourceType. We want to work\n// with our version of ResourceType to catch any breaking changes early.\nconst (\n\tResourceTypeDocument           string = \"Document\"\n\tResourceTypeStylesheet         string = \"Stylesheet\"\n\tResourceTypeImage              string = \"Image\"\n\tResourceTypeMedia              string = \"Media\"\n\tResourceTypeFont               string = \"Font\"\n\tResourceTypeScript             string = \"Script\"\n\tResourceTypeTextTrack          string = \"TextTrack\"\n\tResourceTypeXHR                string = \"XHR\"\n\tResourceTypeFetch              string = \"Fetch\"\n\tResourceTypePrefetch           string = \"Prefetch\"\n\tResourceTypeEventSource        string = \"EventSource\"\n\tResourceTypeWebSocket          string = \"WebSocket\"\n\tResourceTypeManifest           string = \"Manifest\"\n\tResourceTypeSignedExchange     string = \"SignedExchange\"\n\tResourceTypePing               string = \"Ping\"\n\tResourceTypeCSPViolationReport string = \"CSPViolationReport\"\n\tResourceTypePreflight          string = \"Preflight\"\n\tResourceTypeOther              string = \"Other\"\n\tResourceTypeUnknown            string = \"Unknown\"\n)\n\n// HTTPHeader is a single HTTP header.\ntype HTTPHeader struct {\n\tName  string `json:\"name\"`\n\tValue string `json:\"value\"`\n}\n\n// HTTPMessageSize are the sizes in bytes of the HTTP message header and body.\ntype HTTPMessageSize struct {\n\tHeaders int64 `json:\"headers\"`\n\tBody    int64 `json:\"body\"`\n}\n\n// Total returns the total size in bytes of the HTTP message.\nfunc (s HTTPMessageSize) Total() int64 {\n\treturn s.Headers + s.Body\n}\n\n// RequestFailure contains information about a failed request.\ntype RequestFailure struct {\n\tErrorText string `js:\"errorText\"`\n}\n\n// Request represents a browser HTTP request.\ntype Request struct {\n\tctx           context.Context\n\tframe         *Frame\n\tresponseMu    sync.RWMutex\n\tresponse      *Response\n\tredirectChain []*Request\n\trequestID     network.RequestID\n\tdocumentID    string\n\turl           *url.URL\n\tmethod        string\n\theaders       map[string][]string\n\t// For now we're only going to work with the 0th entry of postDataEntries.\n\t// We've not been able to reproduce a situation where more than one entry\n\t// occupies the slice. Once we have a better idea of when more than one\n\t// entry is in postDataEntries, we should look to export a new API.\n\tpostDataEntries     []string\n\tresourceType        string\n\tisNavigationRequest bool\n\tallowInterception   bool\n\tinterceptionID      fetch.RequestID\n\tfromMemoryCache     bool\n\terrorText           string\n\t// offset is the difference between the timestamp and wallTime fields.\n\t//\n\t// The cdp package (and the CDP protocol) uses the monotonic time\n\t// when calculating timestamps. And the cdp package does so by\n\t// getting it from the local machine's last boot time. This causes\n\t// a time skew between the timestamp and the machine's walltime.\n\t//\n\t// Since the cdp package uses monotonic time in timestamp fields, we\n\t// need to calculate the timestamp with the monotonic difference.\n\t//\n\t// See issue #533 for more details.\n\toffset            time.Duration\n\ttimestamp         time.Time\n\twallTime          time.Time\n\tresponseEndTiming float64\n}\n\n// NewRequestParams are input parameters for NewRequest.\ntype NewRequestParams struct {\n\tevent             *network.EventRequestWillBeSent\n\tframe             *Frame\n\tredirectChain     []*Request\n\tinterceptionID    fetch.RequestID\n\tallowInterception bool\n}\n\n// NewRequest creates a new HTTP request.\nfunc NewRequest(ctx context.Context, logger *log.Logger, rp NewRequestParams) (*Request, error) {\n\tev := rp.event\n\n\tdocumentID := cdp.LoaderID(\"\")\n\tif ev.RequestID == network.RequestID(ev.LoaderID) && ev.Type == \"Document\" {\n\t\tdocumentID = ev.LoaderID\n\t}\n\n\tu, err := url.Parse(ev.Request.URL)\n\tif err != nil {\n\t\tvar uerr *url.Error\n\t\tif errors.As(err, &uerr) {\n\t\t\terr = uerr.Err\n\t\t}\n\t\treturn nil, fmt.Errorf(\"parsing URL %q: %w\", ev.Request.URL, err)\n\t}\n\n\tisNavigationRequest := string(ev.RequestID) == string(ev.LoaderID) &&\n\t\tev.Type == network.ResourceTypeDocument\n\n\tpd := make([]string, 0, len(ev.Request.PostDataEntries))\n\tfor _, i := range ev.Request.PostDataEntries {\n\t\tif i == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tdecodedBytes, err := base64.StdEncoding.DecodeString(i.Bytes)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decoding postData %q: %w\", i.Bytes, err)\n\t\t}\n\n\t\tpd = append(pd, string(decodedBytes))\n\t}\n\n\tr := Request{\n\t\turl:                 u,\n\t\tframe:               rp.frame,\n\t\tredirectChain:       rp.redirectChain,\n\t\trequestID:           ev.RequestID,\n\t\tmethod:              ev.Request.Method,\n\t\tpostDataEntries:     pd,\n\t\tresourceType:        validateResourceType(logger, ev.Type.String()),\n\t\tisNavigationRequest: isNavigationRequest,\n\t\tallowInterception:   rp.allowInterception,\n\t\tinterceptionID:      rp.interceptionID,\n\t\ttimestamp:           ev.Timestamp.Time(),\n\t\twallTime:            ev.WallTime.Time(),\n\t\toffset:              ev.WallTime.Time().Sub(ev.Timestamp.Time()),\n\t\tdocumentID:          documentID.String(),\n\t\theaders:             make(map[string][]string, len(ev.Request.Headers)),\n\t\tctx:                 ctx,\n\t}\n\tfor n, v := range ev.Request.Headers {\n\t\tif s, ok := v.(string); ok {\n\t\t\tr.headers[n] = []string{s}\n\t\t}\n\t}\n\n\treturn &r, nil\n}\n\n// validateResourceType will validate network.ResourceType string values against our own\n// ResourceType string values.\n//   - If a new network.ResourceType is added, this will log a warn and return\n//     ResourceTypeUnknown.\n//   - If an existing network.ResourceType is amended, this will log a warn and return\n//     ResourceTypeUnknown.\n//   - If a network.ResourceType is deleted then we will get a compilation error.\nfunc validateResourceType(logger *log.Logger, t string) string {\n\tswitch t {\n\tcase ResourceTypeDocument:\n\tcase ResourceTypeStylesheet:\n\tcase ResourceTypeImage:\n\tcase ResourceTypeMedia:\n\tcase ResourceTypeFont:\n\tcase ResourceTypeScript:\n\tcase ResourceTypeTextTrack:\n\tcase ResourceTypeXHR:\n\tcase ResourceTypeFetch:\n\tcase ResourceTypePrefetch:\n\tcase ResourceTypeEventSource:\n\tcase ResourceTypeWebSocket:\n\tcase ResourceTypeManifest:\n\tcase ResourceTypeSignedExchange:\n\tcase ResourceTypePing:\n\tcase ResourceTypeCSPViolationReport:\n\tcase ResourceTypePreflight:\n\tcase ResourceTypeOther:\n\tdefault:\n\t\tt = ResourceTypeUnknown\n\t\tlogger.Warnf(\"http:resourceType\", \"unknown network.ResourceType %q detected\", t)\n\t}\n\n\treturn t\n}\n\nfunc (r *Request) getFrame() *Frame {\n\treturn r.frame\n}\n\nfunc (r *Request) getID() network.RequestID {\n\treturn r.requestID\n}\n\nfunc (r *Request) getDocumentID() string {\n\treturn r.documentID\n}\n\nfunc (r *Request) headersSize() int64 {\n\tsize := 4 // 4 = 2 spaces + 2 line breaks (GET /path \\r\\n)\n\tsize += len(r.method)\n\tsize += len(r.url.Path)\n\tsize += 8 // httpVersion\n\tfor n, v := range r.headers {\n\t\tsize += len(n) + len(strings.Join(v, \"\")) + 4 // 4 = ': ' + '\\r\\n'\n\t}\n\treturn int64(size)\n}\n\nfunc (r *Request) setErrorText(errorText string) {\n\tr.errorText = errorText\n}\n\n// Failure returns the error text if the request failed, otherwise nil.\nfunc (r *Request) Failure() *RequestFailure {\n\tif r.errorText == \"\" {\n\t\treturn nil\n\t}\n\treturn &RequestFailure{ErrorText: r.errorText}\n}\n\nfunc (r *Request) setLoadedFromCache(fromMemoryCache bool) {\n\tr.fromMemoryCache = fromMemoryCache\n}\n\n// AllHeaders returns all the request headers.\nfunc (r *Request) AllHeaders() map[string]string {\n\t// TODO: fix this data to include \"ExtraInfo\" header data\n\theaders := make(map[string]string)\n\tfor n, v := range r.headers {\n\t\theaders[strings.ToLower(n)] = strings.Join(v, \",\")\n\t}\n\treturn headers\n}\n\n// Frame returns the frame within which the request was made.\nfunc (r *Request) Frame() *Frame {\n\treturn r.frame\n}\n\n// HeaderValue returns the value of the given header.\nfunc (r *Request) HeaderValue(name string) (string, bool) {\n\theaders := r.AllHeaders()\n\tval, ok := headers[strings.ToLower(name)]\n\treturn val, ok\n}\n\n// Headers returns the request headers.\nfunc (r *Request) Headers() map[string]string {\n\theaders := make(map[string]string)\n\tfor n, v := range r.headers {\n\t\theaders[n] = strings.Join(v, \",\")\n\t}\n\treturn headers\n}\n\n// HeadersArray returns the request headers as an array of objects.\nfunc (r *Request) HeadersArray() []HTTPHeader {\n\theaders := make([]HTTPHeader, 0)\n\tfor n, vals := range r.headers {\n\t\tfor _, v := range vals {\n\t\t\theaders = append(headers, HTTPHeader{Name: n, Value: v})\n\t\t}\n\t}\n\treturn headers\n}\n\n// IsNavigationRequest returns whether this was a navigation request or not.\nfunc (r *Request) IsNavigationRequest() bool {\n\treturn r.isNavigationRequest\n}\n\n// Method returns the request method.\nfunc (r *Request) Method() string {\n\treturn r.method\n}\n\n// PostData returns the request post data, if any.\n//\n// If will not attempt to fetch the data if it should have some but nothing is\n// cached locally: https://go.k6.io/k6/js/modules/k6/browser/issues/1470\n//\n// This relies on PostDataEntries. It will only ever return the 0th entry.\n// TODO: Create a PostDataEntries API when we have a better idea of when that\n// is needed.\nfunc (r *Request) PostData() string {\n\tif len(r.postDataEntries) > 0 {\n\t\treturn r.postDataEntries[0]\n\t}\n\n\treturn \"\"\n}\n\n// PostDataBuffer returns the request post data as an ArrayBuffer.\n//\n// If will not attempt to fetch the data if it should have some but nothing is\n// cached locally: https://go.k6.io/k6/js/modules/k6/browser/issues/1470\n//\n// This relies on PostDataEntries. It will only ever return the 0th entry.\n// TODO: Create a PostDataEntries API when we have a better idea of when that\n// is needed.\nfunc (r *Request) PostDataBuffer() []byte {\n\tif len(r.postDataEntries) > 0 {\n\t\treturn []byte(r.postDataEntries[0])\n\t}\n\n\treturn nil\n}\n\n// ResourceType returns the request resource type.\nfunc (r *Request) ResourceType() string {\n\treturn r.resourceType\n}\n\n// Response returns the response for the request, if received.\nfunc (r *Request) Response() *Response {\n\treturn r.response\n}\n\n// Size returns the size of the request.\nfunc (r *Request) Size() HTTPMessageSize {\n\tvar b int64\n\tfor _, p := range r.postDataEntries {\n\t\tb += int64(len(p))\n\t}\n\treturn HTTPMessageSize{\n\t\tBody:    b,\n\t\tHeaders: r.headersSize(),\n\t}\n}\n\n// resourceTiming is the type returned from request.timing.\ntype resourceTiming struct {\n\tStartTime             float64 `js:\"startTime\"`\n\tDomainLookupStart     float64 `js:\"domainLookupStart\"`\n\tDomainLookupEnd       float64 `js:\"domainLookupEnd\"`\n\tConnectStart          float64 `js:\"connectStart\"`\n\tSecureConnectionStart float64 `js:\"secureConnectionStart\"`\n\tConnectEnd            float64 `js:\"connectEnd\"`\n\tRequestStart          float64 `js:\"requestStart\"`\n\tResponseStart         float64 `js:\"responseStart\"`\n\tResponseEnd           float64 `js:\"responseEnd\"`\n}\n\n// Timing returns the request timing information.\nfunc (r *Request) Timing() *resourceTiming {\n\tif r.response == nil {\n\t\treturn nil\n\t}\n\n\ttiming := r.response.timing\n\n\treturn &resourceTiming{\n\t\tStartTime:             (timing.RequestTime - float64(r.timestamp.Unix()) + float64(r.wallTime.Unix())) * 1000,\n\t\tDomainLookupStart:     timing.DNSStart,\n\t\tDomainLookupEnd:       timing.DNSEnd,\n\t\tConnectStart:          timing.ConnectStart,\n\t\tSecureConnectionStart: timing.SslStart,\n\t\tConnectEnd:            timing.ConnectEnd,\n\t\tRequestStart:          timing.SendStart,\n\t\tResponseStart:         timing.ReceiveHeadersEnd,\n\t\tResponseEnd:           r.responseEndTiming,\n\t}\n}\n\n// URL returns the request URL.\nfunc (r *Request) URL() string {\n\treturn r.url.String()\n}\n\n// RemoteAddress contains informationa about a remote target.\ntype RemoteAddress struct {\n\tIPAddress string `json:\"ipAddress\" js:\"ipAddress\"`\n\tPort      int64  `json:\"port\" js:\"port\"`\n}\n\n// SecurityDetails contains informationa about the security details of a TLS connection.\ntype SecurityDetails struct {\n\tSubjectName string   `json:\"subjectName\" js:\"subjectName\"`\n\tIssuer      string   `json:\"issuer\" js:\"issuer\"`\n\tValidFrom   int64    `json:\"validFrom\" js:\"validFrom\"`\n\tValidTo     int64    `json:\"validTo\" js:\"validTo\"`\n\tProtocol    string   `json:\"protocol\" js:\"protocol\"`\n\tSANList     []string `json:\"sanList\" js:\"sanList\"`\n}\n\n// Response represents a browser HTTP response.\ntype Response struct {\n\tctx               context.Context\n\tlogger            *log.Logger\n\trequest           *Request\n\tremoteAddress     *RemoteAddress\n\tsecurityDetails   *SecurityDetails\n\tprotocol          string\n\turl               string\n\tstatus            int64\n\tstatusText        string\n\tbodyMu            sync.RWMutex\n\tbody              []byte\n\theaders           map[string][]string\n\tfromDiskCache     bool\n\tfromServiceWorker bool\n\tfromPrefetchCache bool\n\ttimestamp         time.Time\n\twallTime          time.Time\n\ttiming            *network.ResourceTiming\n\tvu                k6modules.VU\n\n\tcachedJSON any\n}\n\n// NewHTTPResponse creates a new HTTP response.\nfunc NewHTTPResponse(\n\tctx context.Context, req *Request, resp *network.Response, timestamp *cdp.MonotonicTime,\n) *Response {\n\tvu := k6ext.GetVU(ctx)\n\tstate := vu.State()\n\tr := Response{\n\t\tctx: ctx,\n\t\t// TODO: Pass an internal logger instead of basing it on k6's logger?\n\t\t// See https://go.k6.io/k6/js/modules/k6/browser/issues/54\n\t\tlogger:            log.New(state.Logger, GetIterationID(ctx)),\n\t\trequest:           req,\n\t\tremoteAddress:     &RemoteAddress{IPAddress: resp.RemoteIPAddress, Port: resp.RemotePort},\n\t\tsecurityDetails:   nil,\n\t\tprotocol:          resp.Protocol,\n\t\turl:               resp.URL,\n\t\tstatus:            resp.Status,\n\t\tstatusText:        resp.StatusText,\n\t\tbody:              nil,\n\t\theaders:           make(map[string][]string, len(resp.Headers)),\n\t\tfromDiskCache:     resp.FromDiskCache,\n\t\tfromServiceWorker: resp.FromServiceWorker,\n\t\tfromPrefetchCache: resp.FromPrefetchCache,\n\t\ttimestamp:         timestamp.Time(),\n\t\twallTime:          timestamp.Time().Add(req.offset),\n\t\ttiming:            resp.Timing,\n\t\tvu:                vu,\n\t}\n\n\tfor n, v := range resp.Headers {\n\t\ts, ok := v.(string)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tr.headers[n] = []string{s}\n\t}\n\n\tif resp.SecurityDetails != nil {\n\t\tr.securityDetails = &SecurityDetails{\n\t\t\tSubjectName: resp.SecurityDetails.SubjectName,\n\t\t\tIssuer:      resp.SecurityDetails.Issuer,\n\t\t\tValidFrom:   resp.SecurityDetails.ValidFrom.Time().Unix(),\n\t\t\tValidTo:     resp.SecurityDetails.ValidTo.Time().Unix(),\n\t\t\tProtocol:    resp.SecurityDetails.Protocol,\n\t\t\tSANList:     resp.SecurityDetails.SanList,\n\t\t}\n\t}\n\n\treturn &r\n}\n\nfunc (r *Response) fetchBody() error {\n\tcached := func() bool {\n\t\tr.bodyMu.RLock()\n\t\tdefer r.bodyMu.RUnlock()\n\n\t\treturn r.body != nil || r.request.frame == nil\n\t}\n\tif cached() {\n\t\treturn nil\n\t}\n\taction := network.GetResponseBody(r.request.requestID)\n\n\t// Try to fetch the response body. If the request to retrieve the response\n\t// body is too \"quick\" then the response body is not available. After\n\t// retrying we have a better chance of getting the response body.\n\tvar body []byte\n\tvar err error\n\tmaxRetries := 5\n\tfor i := 0; i <= maxRetries; i++ {\n\t\tbody, err = action.Do(cdp.WithExecutor(r.ctx, r.request.frame.manager.session))\n\t\tif err == nil {\n\t\t\tbreak\n\t\t}\n\t\tif strings.Contains(err.Error(), \"No data found for resource with given identifier\") {\n\t\t\tif i == maxRetries {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tcontinue\n\t\t}\n\t\tbreak\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"fetching response body: %w\", err)\n\t}\n\tr.bodyMu.Lock()\n\tr.body = body\n\tr.bodyMu.Unlock()\n\n\treturn nil\n}\n\nfunc (r *Response) headersSize() int64 {\n\tsize := 4 // 4 = 2 spaces + 2 line breaks (HTTP/1.1 200 OK\\r\\n)\n\tsize += 8 // httpVersion\n\tsize += 3 // statusCode\n\tsize += len(r.statusText)\n\tfor n, v := range r.headers {\n\t\tsize += len(n) + len(strings.Join(v, \"\")) + 4 // 4 = ': ' + '\\r\\n'\n\t}\n\tsize += 2 // '\\r\\n'\n\treturn int64(size)\n}\n\n// AllHeaders returns all the response headers.\nfunc (r *Response) AllHeaders() map[string]string {\n\t// TODO: fix this data to include \"ExtraInfo\" header data\n\theaders := make(map[string]string)\n\tfor n, v := range r.headers {\n\t\theaders[strings.ToLower(n)] = strings.Join(v, \",\")\n\t}\n\treturn headers\n}\n\n// Body returns the response body as a bytes buffer.\nfunc (r *Response) Body() ([]byte, error) {\n\tif r.status >= 300 && r.status <= 399 {\n\t\treturn nil, fmt.Errorf(\"response body is unavailable for redirect responses\")\n\t}\n\tif err := r.fetchBody(); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting response body: %w\", err)\n\t}\n\n\tr.bodyMu.RLock()\n\tdefer r.bodyMu.RUnlock()\n\n\treturn r.body, nil\n}\n\n// bodySize returns the size in bytes of the response body.\nfunc (r *Response) bodySize() int64 {\n\t// Skip redirect responses\n\tif r.status >= 300 && r.status <= 399 {\n\t\treturn 0\n\t}\n\n\tif err := r.fetchBody(); err != nil {\n\t\tr.logger.Debugf(\"Response:bodySize:fetchBody\",\n\t\t\t\"url:%s method:%s err:%s\", r.url, r.request.method, err)\n\t}\n\n\tr.bodyMu.RLock()\n\tdefer r.bodyMu.RUnlock()\n\n\treturn int64(len(r.body))\n}\n\n// Frame returns the frame within which the response was received.\nfunc (r *Response) Frame() *Frame {\n\treturn r.request.frame\n}\n\n// HeaderValue returns the value of the given header.\n// Returns true if the header is present, false otherwise.\nfunc (r *Response) HeaderValue(name string) (string, bool) {\n\theaders := r.AllHeaders()\n\tv, ok := headers[strings.ToLower(name)]\n\treturn v, ok\n}\n\n// HeaderValues returns the values of the given header.\nfunc (r *Response) HeaderValues(name string) []string {\n\theaders := r.AllHeaders()\n\treturn strings.Split(headers[name], \",\")\n}\n\n// FromCache returns whether this response was served from disk cache.\nfunc (r *Response) FromCache() bool {\n\treturn r.fromDiskCache\n}\n\n// FromPrefetchCache returns whether this response was served from prefetch cache.\nfunc (r *Response) FromPrefetchCache() bool {\n\treturn r.fromPrefetchCache\n}\n\n// FromServiceWorker returns whether this response was served by a service worker.\nfunc (r *Response) FromServiceWorker() bool {\n\treturn r.fromServiceWorker\n}\n\n// Headers returns the response headers.\nfunc (r *Response) Headers() map[string]string {\n\theaders := make(map[string]string)\n\tfor n, v := range r.headers {\n\t\theaders[n] = strings.Join(v, \",\")\n\t}\n\treturn headers\n}\n\n// HeadersArray returns the response headers as an array of objects.\nfunc (r *Response) HeadersArray() []HTTPHeader {\n\theaders := make([]HTTPHeader, 0)\n\tfor n, vals := range r.headers {\n\t\tfor _, v := range vals {\n\t\t\theaders = append(headers, HTTPHeader{Name: n, Value: v})\n\t\t}\n\t}\n\treturn headers\n}\n\n// JSON returns the response body as JSON data.\nfunc (r *Response) JSON() (any, error) {\n\tif r.cachedJSON != nil {\n\t\treturn r.cachedJSON, nil\n\t}\n\tif err := r.fetchBody(); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting response body: %w\", err)\n\t}\n\n\tr.bodyMu.RLock()\n\tdefer r.bodyMu.RUnlock()\n\n\tvar v any\n\tif err := json.Unmarshal(r.body, &v); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshalling response body to JSON: %w\", err)\n\t}\n\tr.cachedJSON = v\n\n\treturn v, nil\n}\n\n// Ok returns true if status code of response if considered ok, otherwise returns false.\nfunc (r *Response) Ok() bool {\n\tif r.status == 0 || (r.status >= 200 && r.status <= 299) {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Request returns the request that led to this response.\nfunc (r *Response) Request() *Request {\n\treturn r.request\n}\n\n// SecurityDetails returns the security details of the response.\nfunc (r *Response) SecurityDetails() *SecurityDetails {\n\treturn r.securityDetails\n}\n\n// ServerAddr returns the remote address of the server.\nfunc (r *Response) ServerAddr() *RemoteAddress {\n\treturn r.remoteAddress\n}\n\n// Size returns the size in bytes of the response.\nfunc (r *Response) Size() HTTPMessageSize {\n\treturn HTTPMessageSize{\n\t\tBody:    r.bodySize(),\n\t\tHeaders: r.headersSize(),\n\t}\n}\n\n// Status returns the response status code.\nfunc (r *Response) Status() int64 {\n\treturn r.status\n}\n\n// StatusText returns the response status text.\nfunc (r *Response) StatusText() string {\n\treturn r.statusText\n}\n\n// Text returns the response body as a string.\nfunc (r *Response) Text() (string, error) {\n\tif err := r.fetchBody(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting response body as text: %w\", err)\n\t}\n\n\tr.bodyMu.RLock()\n\tdefer r.bodyMu.RUnlock()\n\n\treturn string(r.body), nil\n}\n\n// URL returns the request URL.\nfunc (r *Response) URL() string {\n\treturn r.url\n}\n\n// Route allows to handle a request.\ntype Route struct {\n\tlogger         *log.Logger\n\tnetworkManager *NetworkManager\n\n\trequest *Request\n\thandled bool\n}\n\n// ContinueOptions are request fields that can be overridden when continuing a request.\ntype ContinueOptions struct {\n\tHeaders  []HTTPHeader\n\tMethod   string\n\tPostData []byte\n\tURL      string\n}\n\n// FulfillOptions are response fields that can be set when fulfilling a request.\ntype FulfillOptions struct {\n\tBody        []byte\n\tContentType string\n\tHeaders     []HTTPHeader\n\tStatus      int64\n}\n\n// NewRoute creates a new Route that allows to modify a request's behavior.\nfunc NewRoute(logger *log.Logger, networkManager *NetworkManager, request *Request) *Route {\n\treturn &Route{\n\t\tlogger:         logger,\n\t\tnetworkManager: networkManager,\n\t\trequest:        request,\n\t\thandled:        false,\n\t}\n}\n\n// Request returns the request associated with the route.\nfunc (r *Route) Request() *Request { return r.request }\n\n// Abort aborts the request with the given error code.\nfunc (r *Route) Abort(errorCode string) error {\n\terr := r.startHandling()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif errorCode == \"\" {\n\t\terrorCode = \"failed\"\n\t}\n\n\treturn r.networkManager.AbortRequest(r.request.interceptionID, errorCode)\n}\n\n// Continue continues the request.\nfunc (r *Route) Continue(opts ContinueOptions) error {\n\terr := r.startHandling()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn r.networkManager.ContinueRequest(r.request.interceptionID, opts, r.request.HeadersArray())\n}\n\n// Fulfill fulfills the request with the given options for the response.\nfunc (r *Route) Fulfill(opts FulfillOptions) error {\n\terr := r.startHandling()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn r.networkManager.FulfillRequest(r.request, opts)\n}\n\nfunc (r *Route) startHandling() error {\n\tif r.handled {\n\t\treturn fmt.Errorf(\"route is already handled\")\n\t}\n\tr.handled = true\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/http_test.go",
    "content": "package common\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\nfunc TestRequest(t *testing.T) {\n\tt.Parallel()\n\n\tts := cdp.MonotonicTime(time.Now())\n\twt := cdp.TimeSinceEpoch(time.Now())\n\theaders := map[string]any{\"key\": \"value\"}\n\tevt := &network.EventRequestWillBeSent{\n\t\tRequestID: network.RequestID(\"1234\"),\n\t\tRequest: &network.Request{\n\t\t\tURL:             \"https://test/post\",\n\t\t\tMethod:          \"POST\",\n\t\t\tHeaders:         network.Headers(headers),\n\t\t\tPostDataEntries: []*network.PostDataEntry{{Bytes: \"aGVsbG8=\"}}, // base64 encoded \"hello\"\n\t\t},\n\t\tTimestamp: &ts,\n\t\tWallTime:  &wt,\n\t}\n\tvu := k6test.NewVU(t)\n\treq, err := NewRequest(vu.Context(), log.NewNullLogger(), NewRequestParams{\n\t\tevent:          evt,\n\t\tinterceptionID: \"intercept\",\n\t})\n\trequire.NoError(t, err)\n\n\tt.Run(\"error_parse_url\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tevt := &network.EventRequestWillBeSent{\n\t\t\tRequestID: network.RequestID(\"1234\"),\n\t\t\tRequest: &network.Request{\n\t\t\t\tURL:             \":\",\n\t\t\t\tMethod:          \"POST\",\n\t\t\t\tHeaders:         network.Headers(headers),\n\t\t\t\tPostDataEntries: []*network.PostDataEntry{{Bytes: \"aGVsbG8=\"}}, // base64 encoded \"hello\"\n\t\t\t},\n\t\t\tTimestamp: &ts,\n\t\t\tWallTime:  &wt,\n\t\t}\n\t\tvu := k6test.NewVU(t)\n\t\treq, err := NewRequest(vu.Context(), log.NewNullLogger(), NewRequestParams{\n\t\t\tevent:          evt,\n\t\t\tinterceptionID: \"intercept\",\n\t\t})\n\t\trequire.EqualError(t, err, `parsing URL \":\": missing protocol scheme`)\n\t\trequire.Nil(t, req)\n\t})\n\n\tt.Run(\"Headers()\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tassert.Equal(t, map[string]string{\"key\": \"value\"}, req.Headers())\n\t})\n\n\tt.Run(\"HeadersArray()\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tassert.Equal(t, []HTTPHeader{\n\t\t\t{Name: \"key\", Value: \"value\"},\n\t\t}, req.HeadersArray())\n\t})\n\n\tt.Run(\"HeaderValue()_key\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tgot, ok := req.HeaderValue(\"key\")\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, \"value\", got)\n\t})\n\n\tt.Run(\"HeaderValue()_KEY\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tgot, ok := req.HeaderValue(\"KEY\")\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, \"value\", got)\n\t})\n\n\tt.Run(\"Size()\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tassert.Equal(t,\n\t\t\tHTTPMessageSize{Headers: int64(33), Body: int64(5)},\n\t\t\treq.Size())\n\t})\n}\n\nfunc TestResponse(t *testing.T) {\n\tt.Parallel()\n\n\tts := cdp.MonotonicTime(time.Now())\n\theaders := map[string]any{\"key\": \"value\"}\n\tvu := k6test.NewVU(t)\n\tvu.ActivateVU()\n\treq := &Request{\n\t\toffset: 0,\n\t}\n\tres := NewHTTPResponse(vu.Context(), req, &network.Response{\n\t\tURL:     \"https://test/post\",\n\t\tHeaders: network.Headers(headers),\n\t}, &ts)\n\n\tt.Run(\"HeaderValue()_key\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tgot, ok := res.HeaderValue(\"key\")\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, \"value\", got)\n\t})\n\n\tt.Run(\"HeaderValue()_KEY\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tgot, ok := res.HeaderValue(\"KEY\")\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, \"value\", got)\n\t})\n}\n\nfunc TestValidateResourceType(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname  string\n\t\tinput string\n\t\twant  string\n\t}{\n\t\t{name: ResourceTypeDocument, input: network.ResourceTypeDocument.String(), want: ResourceTypeDocument},\n\t\t{name: ResourceTypeStylesheet, input: network.ResourceTypeStylesheet.String(), want: ResourceTypeStylesheet},\n\t\t{name: ResourceTypeImage, input: network.ResourceTypeImage.String(), want: ResourceTypeImage},\n\t\t{name: ResourceTypeMedia, input: network.ResourceTypeMedia.String(), want: ResourceTypeMedia},\n\t\t{name: ResourceTypeFont, input: network.ResourceTypeFont.String(), want: ResourceTypeFont},\n\t\t{name: ResourceTypeScript, input: network.ResourceTypeScript.String(), want: ResourceTypeScript},\n\t\t{name: ResourceTypeTextTrack, input: network.ResourceTypeTextTrack.String(), want: ResourceTypeTextTrack},\n\t\t{name: ResourceTypeXHR, input: network.ResourceTypeXHR.String(), want: ResourceTypeXHR},\n\t\t{name: ResourceTypeFetch, input: network.ResourceTypeFetch.String(), want: ResourceTypeFetch},\n\t\t{name: ResourceTypePrefetch, input: network.ResourceTypePrefetch.String(), want: ResourceTypePrefetch},\n\t\t{name: ResourceTypeEventSource, input: network.ResourceTypeEventSource.String(), want: ResourceTypeEventSource},\n\t\t{name: ResourceTypeWebSocket, input: network.ResourceTypeWebSocket.String(), want: ResourceTypeWebSocket},\n\t\t{name: ResourceTypeManifest, input: network.ResourceTypeManifest.String(), want: ResourceTypeManifest},\n\t\t{name: ResourceTypeSignedExchange, input: network.ResourceTypeSignedExchange.String(), want: ResourceTypeSignedExchange},\n\t\t{name: ResourceTypePing, input: network.ResourceTypePing.String(), want: ResourceTypePing},\n\t\t{name: ResourceTypeCSPViolationReport, input: network.ResourceTypeCSPViolationReport.String(), want: ResourceTypeCSPViolationReport},\n\t\t{name: ResourceTypePreflight, input: network.ResourceTypePreflight.String(), want: ResourceTypePreflight},\n\t\t{name: ResourceTypeOther, input: network.ResourceTypeOther.String(), want: ResourceTypeOther},\n\t\t{name: \"fake\", input: \"fake\", want: ResourceTypeUnknown},\n\t\t{name: \"amended_existing\", input: strings.ToLower(network.ResourceTypeOther.String()), want: ResourceTypeUnknown},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot := validateResourceType(log.NewNullLogger(), tt.input)\n\t\t\tassert.Equal(t, tt.want, got)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/actions.go",
    "content": "package js\n\nimport (\n\t_ \"embed\"\n)\n\n// ScrollIntoView scrolls an element into view.\n//\n//go:embed scroll_into_view.js\nvar ScrollIntoView string\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/doc.go",
    "content": "// Package js provides JavaScript code that the browser module evaluates on the browser.\n// The common package uses this package.\n// `injected_script.js` is injected into each execution context.\npackage js\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/embedded_scripts.go",
    "content": "package js\n\nimport (\n\t_ \"embed\"\n)\n\n// WebVitalIIFEScript was downloaded from\n// https://unpkg.com/web-vitals@3/dist/web-vitals.iife.js.\n// Repo: https://github.com/GoogleChrome/web-vitals\n//\n//go:embed web_vital_iife.js\nvar WebVitalIIFEScript string\n\n// WebVitalInitScript uses WebVitalIIFEScript\n// and applies it to the current website that\n// this init script is used against.\n//\n//go:embed web_vital_init.js\nvar WebVitalInitScript string\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/injected_script.js",
    "content": "/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// k6BrowserNative allows accessing native browser objects\n// even if the page under test has overridden them.\nconst k6BrowserNative = (() => {\n  const iframe = document.createElement('iframe');\n  // hide it offscreen with zero size\n  iframe.style.position = 'absolute';\n  iframe.style.width = '0';\n  iframe.style.height = '0';\n  iframe.style.border = '0';\n  iframe.style.top = '-9999px';\n  iframe.style.left = '-9999px';\n  iframe.style.display = 'none';\n\n  // grab the native browser object\n  document.documentElement.appendChild(iframe);\n  const win = iframe.contentWindow;\n  document.documentElement.removeChild(iframe);\n\n  return {\n    Set: win.Set,\n    Map: win.Map,\n    // Add other native browser objects as needed.\n  }\n})();\n\n// packages/playwright-core/src/utils/isomorphic/stringUtils.ts\nvar normalizedWhitespaceCache;\nfunction normalizeWhiteSpace(text) {\n  normalizedWhitespaceCache = normalizedWhitespaceCache || new k6BrowserNative.Map();\n  let result = normalizedWhitespaceCache == null ? void 0 : normalizedWhitespaceCache.get(text);\n  if (result === void 0) {\n    result = text.replace(/[\\u200b\\u00ad]/g, \"\").trim().replace(/\\s+/g, \" \");\n    normalizedWhitespaceCache == null ? void 0 : normalizedWhitespaceCache.set(text, result);\n  }\n  return result;\n}\n\n// packages/injected/src/domUtils.ts\nvar globalOptions = {};\nfunction getGlobalOptions() {\n  return globalOptions;\n}\nfunction parentElementOrShadowHost(element) {\n  if (element.parentElement)\n    return element.parentElement;\n  if (!element.parentNode)\n    return;\n  if (element.parentNode.nodeType === 11 && element.parentNode.host)\n    return element.parentNode.host;\n}\nfunction enclosingShadowRootOrDocument(element) {\n  let node = element;\n  while (node.parentNode)\n    node = node.parentNode;\n  if (node.nodeType === 11 || node.nodeType === 9)\n    return node;\n}\nfunction enclosingShadowHost(element) {\n  while (element.parentElement)\n    element = element.parentElement;\n  return parentElementOrShadowHost(element);\n}\nfunction closestCrossShadow(element, css, scope) {\n  while (element) {\n    const closest = element.closest(css);\n    if (scope && closest !== scope && (closest == null ? void 0 : closest.contains(scope)))\n      return;\n    if (closest)\n      return closest;\n    element = enclosingShadowHost(element);\n  }\n}\nfunction getElementComputedStyle(element, pseudo) {\n  return element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element, pseudo) : void 0;\n}\nfunction isElementStyleVisibilityVisible(element, style) {\n  style = style != null ? style : getElementComputedStyle(element);\n  if (!style)\n    return true;\n  if (Element.prototype.checkVisibility && globalOptions.browserNameForWorkarounds !== \"webkit\") {\n    if (!element.checkVisibility())\n      return false;\n  } else {\n    const detailsOrSummary = element.closest(\"details,summary\");\n    if (detailsOrSummary !== element && (detailsOrSummary == null ? void 0 : detailsOrSummary.nodeName) === \"DETAILS\" && !detailsOrSummary.open)\n      return false;\n  }\n  if (style.visibility !== \"visible\")\n    return false;\n  return true;\n}\nfunction isVisibleTextNode(node) {\n  const range = node.ownerDocument.createRange();\n  range.selectNode(node);\n  const rect = range.getBoundingClientRect();\n  return rect.width > 0 && rect.height > 0;\n}\nfunction elementSafeTagName(element) {\n  if (element instanceof HTMLFormElement)\n    return \"FORM\";\n  return element.tagName.toUpperCase();\n}\n\n// packages/injected/src/roleUtils.ts\nfunction hasExplicitAccessibleName(e) {\n  return e.hasAttribute(\"aria-label\") || e.hasAttribute(\"aria-labelledby\");\n}\nvar kAncestorPreventingLandmark = \"article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]\";\nvar kGlobalAriaAttributes = [\n  [\"aria-atomic\", void 0],\n  [\"aria-busy\", void 0],\n  [\"aria-controls\", void 0],\n  [\"aria-current\", void 0],\n  [\"aria-describedby\", void 0],\n  [\"aria-details\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-disabled', undefined],\n  [\"aria-dropeffect\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-errormessage', undefined],\n  [\"aria-flowto\", void 0],\n  [\"aria-grabbed\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-haspopup', undefined],\n  [\"aria-hidden\", void 0],\n  // Global use deprecated in ARIA 1.2\n  // ['aria-invalid', undefined],\n  [\"aria-keyshortcuts\", void 0],\n  [\"aria-label\", [\"caption\", \"code\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"superscript\"]],\n  [\"aria-labelledby\", [\"caption\", \"code\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"superscript\"]],\n  [\"aria-live\", void 0],\n  [\"aria-owns\", void 0],\n  [\"aria-relevant\", void 0],\n  [\"aria-roledescription\", [\"generic\"]]\n];\nfunction hasGlobalAriaAttribute(element, forRole) {\n  return kGlobalAriaAttributes.some(([attr, prohibited]) => {\n    return !(prohibited == null ? void 0 : prohibited.includes(forRole || \"\")) && element.hasAttribute(attr);\n  });\n}\nfunction hasTabIndex(element) {\n  return !Number.isNaN(Number(String(element.getAttribute(\"tabindex\"))));\n}\nfunction isFocusable(element) {\n  return !isNativelyDisabled(element) && (isNativelyFocusable(element) || hasTabIndex(element));\n}\nfunction isNativelyFocusable(element) {\n  const tagName = elementSafeTagName(element);\n  if ([\"BUTTON\", \"DETAILS\", \"SELECT\", \"TEXTAREA\"].includes(tagName))\n    return true;\n  if (tagName === \"A\" || tagName === \"AREA\")\n    return element.hasAttribute(\"href\");\n  if (tagName === \"INPUT\")\n    return !element.hidden;\n  return false;\n}\nvar kImplicitRoleByTagName = {\n  \"A\": (e) => {\n    return e.hasAttribute(\"href\") ? \"link\" : null;\n  },\n  \"AREA\": (e) => {\n    return e.hasAttribute(\"href\") ? \"link\" : null;\n  },\n  \"ARTICLE\": () => \"article\",\n  \"ASIDE\": () => \"complementary\",\n  \"BLOCKQUOTE\": () => \"blockquote\",\n  \"BUTTON\": () => \"button\",\n  \"CAPTION\": () => \"caption\",\n  \"CODE\": () => \"code\",\n  \"DATALIST\": () => \"listbox\",\n  \"DD\": () => \"definition\",\n  \"DEL\": () => \"deletion\",\n  \"DETAILS\": () => \"group\",\n  \"DFN\": () => \"term\",\n  \"DIALOG\": () => \"dialog\",\n  \"DT\": () => \"term\",\n  \"EM\": () => \"emphasis\",\n  \"FIELDSET\": () => \"group\",\n  \"FIGURE\": () => \"figure\",\n  \"FOOTER\": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : \"contentinfo\",\n  \"FORM\": (e) => hasExplicitAccessibleName(e) ? \"form\" : null,\n  \"H1\": () => \"heading\",\n  \"H2\": () => \"heading\",\n  \"H3\": () => \"heading\",\n  \"H4\": () => \"heading\",\n  \"H5\": () => \"heading\",\n  \"H6\": () => \"heading\",\n  \"HEADER\": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : \"banner\",\n  \"HR\": () => \"separator\",\n  \"HTML\": () => \"document\",\n  \"IMG\": (e) => e.getAttribute(\"alt\") === \"\" && !e.getAttribute(\"title\") && !hasGlobalAriaAttribute(e) && !hasTabIndex(e) ? \"presentation\" : \"img\",\n  \"INPUT\": (e) => {\n    const type = e.type.toLowerCase();\n    if (type === \"search\")\n      return e.hasAttribute(\"list\") ? \"combobox\" : \"searchbox\";\n    if ([\"email\", \"tel\", \"text\", \"url\", \"\"].includes(type)) {\n      const list = getIdRefs(e, e.getAttribute(\"list\"))[0];\n      return list && elementSafeTagName(list) === \"DATALIST\" ? \"combobox\" : \"textbox\";\n    }\n    if (type === \"hidden\")\n      return null;\n    if (type === \"file\" && !getGlobalOptions().inputFileRoleTextbox)\n      return \"button\";\n    return inputTypeToRole[type] || \"textbox\";\n  },\n  \"INS\": () => \"insertion\",\n  \"LI\": () => \"listitem\",\n  \"MAIN\": () => \"main\",\n  \"MARK\": () => \"mark\",\n  \"MATH\": () => \"math\",\n  \"MENU\": () => \"list\",\n  \"METER\": () => \"meter\",\n  \"NAV\": () => \"navigation\",\n  \"OL\": () => \"list\",\n  \"OPTGROUP\": () => \"group\",\n  \"OPTION\": () => \"option\",\n  \"OUTPUT\": () => \"status\",\n  \"P\": () => \"paragraph\",\n  \"PROGRESS\": () => \"progressbar\",\n  \"SECTION\": (e) => hasExplicitAccessibleName(e) ? \"region\" : null,\n  \"SELECT\": (e) => e.hasAttribute(\"multiple\") || e.size > 1 ? \"listbox\" : \"combobox\",\n  \"STRONG\": () => \"strong\",\n  \"SUB\": () => \"subscript\",\n  \"SUP\": () => \"superscript\",\n  // For <svg> we default to Chrome behavior:\n  // - Chrome reports 'img'.\n  // - Firefox reports 'diagram' that is not in official ARIA spec yet.\n  // - Safari reports 'no role', but still computes accessible name.\n  \"SVG\": () => \"img\",\n  \"TABLE\": () => \"table\",\n  \"TBODY\": () => \"rowgroup\",\n  \"TD\": (e) => {\n    const table = closestCrossShadow(e, \"table\");\n    const role = table ? getExplicitAriaRole(table) : \"\";\n    return role === \"grid\" || role === \"treegrid\" ? \"gridcell\" : \"cell\";\n  },\n  \"TEXTAREA\": () => \"textbox\",\n  \"TFOOT\": () => \"rowgroup\",\n  \"TH\": (e) => {\n    if (e.getAttribute(\"scope\") === \"col\")\n      return \"columnheader\";\n    if (e.getAttribute(\"scope\") === \"row\")\n      return \"rowheader\";\n    const table = closestCrossShadow(e, \"table\");\n    const role = table ? getExplicitAriaRole(table) : \"\";\n    return role === \"grid\" || role === \"treegrid\" ? \"gridcell\" : \"cell\";\n  },\n  \"THEAD\": () => \"rowgroup\",\n  \"TIME\": () => \"time\",\n  \"TR\": () => \"row\",\n  \"UL\": () => \"list\"\n};\nvar kPresentationInheritanceParents = {\n  \"DD\": [\"DL\", \"DIV\"],\n  \"DIV\": [\"DL\"],\n  \"DT\": [\"DL\", \"DIV\"],\n  \"LI\": [\"OL\", \"UL\"],\n  \"TBODY\": [\"TABLE\"],\n  \"TD\": [\"TR\"],\n  \"TFOOT\": [\"TABLE\"],\n  \"TH\": [\"TR\"],\n  \"THEAD\": [\"TABLE\"],\n  \"TR\": [\"THEAD\", \"TBODY\", \"TFOOT\", \"TABLE\"]\n};\nfunction getImplicitAriaRole(element) {\n  var _a;\n  const implicitRole = ((_a = kImplicitRoleByTagName[elementSafeTagName(element)]) == null ? void 0 : _a.call(kImplicitRoleByTagName, element)) || \"\";\n  if (!implicitRole)\n    return null;\n  let ancestor = element;\n  while (ancestor) {\n    const parent = parentElementOrShadowHost(ancestor);\n    const parents = kPresentationInheritanceParents[elementSafeTagName(ancestor)];\n    if (!parents || !parent || !parents.includes(elementSafeTagName(parent)))\n      break;\n    const parentExplicitRole = getExplicitAriaRole(parent);\n    if ((parentExplicitRole === \"none\" || parentExplicitRole === \"presentation\") && !hasPresentationConflictResolution(parent, parentExplicitRole))\n      return parentExplicitRole;\n    ancestor = parent;\n  }\n  return implicitRole;\n}\nvar validRoles = [\n  \"alert\",\n  \"alertdialog\",\n  \"application\",\n  \"article\",\n  \"banner\",\n  \"blockquote\",\n  \"button\",\n  \"caption\",\n  \"cell\",\n  \"checkbox\",\n  \"code\",\n  \"columnheader\",\n  \"combobox\",\n  \"complementary\",\n  \"contentinfo\",\n  \"definition\",\n  \"deletion\",\n  \"dialog\",\n  \"directory\",\n  \"document\",\n  \"emphasis\",\n  \"feed\",\n  \"figure\",\n  \"form\",\n  \"generic\",\n  \"grid\",\n  \"gridcell\",\n  \"group\",\n  \"heading\",\n  \"img\",\n  \"insertion\",\n  \"link\",\n  \"list\",\n  \"listbox\",\n  \"listitem\",\n  \"log\",\n  \"main\",\n  \"mark\",\n  \"marquee\",\n  \"math\",\n  \"meter\",\n  \"menu\",\n  \"menubar\",\n  \"menuitem\",\n  \"menuitemcheckbox\",\n  \"menuitemradio\",\n  \"navigation\",\n  \"none\",\n  \"note\",\n  \"option\",\n  \"paragraph\",\n  \"presentation\",\n  \"progressbar\",\n  \"radio\",\n  \"radiogroup\",\n  \"region\",\n  \"row\",\n  \"rowgroup\",\n  \"rowheader\",\n  \"scrollbar\",\n  \"search\",\n  \"searchbox\",\n  \"separator\",\n  \"slider\",\n  \"spinbutton\",\n  \"status\",\n  \"strong\",\n  \"subscript\",\n  \"superscript\",\n  \"switch\",\n  \"tab\",\n  \"table\",\n  \"tablist\",\n  \"tabpanel\",\n  \"term\",\n  \"textbox\",\n  \"time\",\n  \"timer\",\n  \"toolbar\",\n  \"tooltip\",\n  \"tree\",\n  \"treegrid\",\n  \"treeitem\"\n];\nfunction getExplicitAriaRole(element) {\n  const roles = (element.getAttribute(\"role\") || \"\").split(\" \").map((role) => role.trim());\n  return roles.find((role) => validRoles.includes(role)) || null;\n}\nfunction hasPresentationConflictResolution(element, role) {\n  return hasGlobalAriaAttribute(element, role) || isFocusable(element);\n}\nfunction getAriaRole(element) {\n  const explicitRole = getExplicitAriaRole(element);\n  if (!explicitRole)\n    return getImplicitAriaRole(element);\n  if (explicitRole === \"none\" || explicitRole === \"presentation\") {\n    const implicitRole = getImplicitAriaRole(element);\n    if (hasPresentationConflictResolution(element, implicitRole))\n      return implicitRole;\n  }\n  return explicitRole;\n}\nfunction getAriaBoolean(attr) {\n  return attr === null ? void 0 : attr.toLowerCase() === \"true\";\n}\nfunction isElementIgnoredForAria(element) {\n  return [\"STYLE\", \"SCRIPT\", \"NOSCRIPT\", \"TEMPLATE\"].includes(elementSafeTagName(element));\n}\nfunction isElementHiddenForAria(element) {\n  if (isElementIgnoredForAria(element))\n    return true;\n  const style = getElementComputedStyle(element);\n  const isSlot = element.nodeName === \"SLOT\";\n  if ((style == null ? void 0 : style.display) === \"contents\" && !isSlot) {\n    for (let child = element.firstChild; child; child = child.nextSibling) {\n      if (child.nodeType === 1 && !isElementHiddenForAria(child))\n        return false;\n      if (child.nodeType === 3 && isVisibleTextNode(child))\n        return false;\n    }\n    return true;\n  }\n  const isOptionInsideSelect = element.nodeName === \"OPTION\" && !!element.closest(\"select\");\n  if (!isOptionInsideSelect && !isSlot && !isElementStyleVisibilityVisible(element, style))\n    return true;\n  return belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element);\n}\nfunction belongsToDisplayNoneOrAriaHiddenOrNonSlotted(element) {\n  let hidden = cacheIsHidden == null ? void 0 : cacheIsHidden.get(element);\n  if (hidden === void 0) {\n    hidden = false;\n    if (element.parentElement && element.parentElement.shadowRoot && !element.assignedSlot)\n      hidden = true;\n    if (!hidden) {\n      const style = getElementComputedStyle(element);\n      hidden = !style || style.display === \"none\" || getAriaBoolean(element.getAttribute(\"aria-hidden\")) === true;\n    }\n    if (!hidden) {\n      const parent = parentElementOrShadowHost(element);\n      if (parent)\n        hidden = belongsToDisplayNoneOrAriaHiddenOrNonSlotted(parent);\n    }\n    cacheIsHidden == null ? void 0 : cacheIsHidden.set(element, hidden);\n  }\n  return hidden;\n}\nfunction getIdRefs(element, ref) {\n  if (!ref)\n    return [];\n  const root = enclosingShadowRootOrDocument(element);\n  if (!root)\n    return [];\n  try {\n    const ids = ref.split(\" \").filter((id) => !!id);\n    const result = [];\n    for (const id of ids) {\n      const firstElement = root.querySelector(\"#\" + CSS.escape(id));\n      if (firstElement && !result.includes(firstElement))\n        result.push(firstElement);\n    }\n    return result;\n  } catch (e) {\n    return [];\n  }\n}\nfunction trimFlatString(s) {\n  return s.trim();\n}\nfunction asFlatString(s) {\n  return s.split(\"\\xA0\").map((chunk) => chunk.replace(/\\r\\n/g, \"\\\n\").replace(/[\\u200b\\u00ad]/g, \"\").replace(/\\s\\s*/g, \" \")).join(\"\\xA0\").trim();\n}\nfunction queryInAriaOwned(element, selector) {\n  const result = [...element.querySelectorAll(selector)];\n  for (const owned of getIdRefs(element, element.getAttribute(\"aria-owns\"))) {\n    if (owned.matches(selector))\n      result.push(owned);\n    result.push(...owned.querySelectorAll(selector));\n  }\n  return result;\n}\nfunction getPseudoContent(element, pseudo) {\n  const cache = pseudo === \"::before\" ? cachePseudoContentBefore : cachePseudoContentAfter;\n  if (cache == null ? void 0 : cache.has(element))\n    return (cache == null ? void 0 : cache.get(element)) || \"\";\n  const pseudoStyle = getElementComputedStyle(element, pseudo);\n  const content = getPseudoContentImpl(element, pseudoStyle);\n  if (cache)\n    cache.set(element, content);\n  return content;\n}\nfunction getPseudoContentImpl(element, pseudoStyle) {\n  if (!pseudoStyle || pseudoStyle.display === \"none\" || pseudoStyle.visibility === \"hidden\")\n    return \"\";\n  const content = pseudoStyle.content;\n  let resolvedContent;\n  if (content[0] === \"'\" && content[content.length - 1] === \"'\" || content[0] === '\"' && content[content.length - 1] === '\"') {\n    resolvedContent = content.substring(1, content.length - 1);\n  } else if (content.startsWith(\"attr(\") && content.endsWith(\")\")) {\n    const attrName = content.substring(\"attr(\".length, content.length - 1).trim();\n    resolvedContent = element.getAttribute(attrName) || \"\";\n  }\n  if (resolvedContent !== void 0) {\n    const display = pseudoStyle.display || \"inline\";\n    if (display !== \"inline\")\n      return \" \" + resolvedContent + \" \";\n    return resolvedContent;\n  }\n  return \"\";\n}\nfunction getAriaLabelledByElements(element) {\n  const ref = element.getAttribute(\"aria-labelledby\");\n  if (ref === null)\n    return null;\n  const refs = getIdRefs(element, ref);\n  return refs.length ? refs : null;\n}\nfunction allowsNameFromContent(role, targetDescendant) {\n  const alwaysAllowsNameFromContent = [\"button\", \"cell\", \"checkbox\", \"columnheader\", \"gridcell\", \"heading\", \"link\", \"menuitem\", \"menuitemcheckbox\", \"menuitemradio\", \"option\", \"radio\", \"row\", \"rowheader\", \"switch\", \"tab\", \"tooltip\", \"treeitem\"].includes(role);\n  const descendantAllowsNameFromContent = targetDescendant && [\"\", \"caption\", \"code\", \"contentinfo\", \"definition\", \"deletion\", \"emphasis\", \"insertion\", \"list\", \"listitem\", \"mark\", \"none\", \"paragraph\", \"presentation\", \"region\", \"row\", \"rowgroup\", \"section\", \"strong\", \"subscript\", \"superscript\", \"table\", \"term\", \"time\"].includes(role);\n  return alwaysAllowsNameFromContent || descendantAllowsNameFromContent;\n}\nfunction getElementAccessibleName(element, includeHidden) {\n  const cache = includeHidden ? cacheAccessibleNameHidden : cacheAccessibleName;\n  let accessibleName = cache == null ? void 0 : cache.get(element);\n  if (accessibleName === void 0) {\n    accessibleName = \"\";\n    const elementProhibitsNaming = [\"caption\", \"code\", \"definition\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"mark\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"suggestion\", \"superscript\", \"term\", \"time\"].includes(getAriaRole(element) || \"\");\n    if (!elementProhibitsNaming) {\n      accessibleName = asFlatString(getTextAlternativeInternal(element, {\n        includeHidden,\n        visitedElements: new k6BrowserNative.Set(),\n        embeddedInTargetElement: \"self\"\n      }));\n    }\n    cache == null ? void 0 : cache.set(element, accessibleName);\n  }\n  return accessibleName;\n}\nfunction getTextAlternativeInternal(element, options) {\n  var _a, _b, _c, _d;\n  if (options.visitedElements.has(element))\n    return \"\";\n  const childOptions = {\n    ...options,\n    embeddedInTargetElement: options.embeddedInTargetElement === \"self\" ? \"descendant\" : options.embeddedInTargetElement\n  };\n  if (!options.includeHidden) {\n    const isEmbeddedInHiddenReferenceTraversal = !!((_a = options.embeddedInLabelledBy) == null ? void 0 : _a.hidden) || !!((_b = options.embeddedInDescribedBy) == null ? void 0 : _b.hidden) || !!((_c = options.embeddedInNativeTextAlternative) == null ? void 0 : _c.hidden) || !!((_d = options.embeddedInLabel) == null ? void 0 : _d.hidden);\n    if (isElementIgnoredForAria(element) || !isEmbeddedInHiddenReferenceTraversal && isElementHiddenForAria(element)) {\n      options.visitedElements.add(element);\n      return \"\";\n    }\n  }\n  const labelledBy = getAriaLabelledByElements(element);\n  if (!options.embeddedInLabelledBy) {\n    const accessibleName = (labelledBy || []).map((ref) => getTextAlternativeInternal(ref, {\n      ...options,\n      embeddedInLabelledBy: { element: ref, hidden: isElementHiddenForAria(ref) },\n      embeddedInDescribedBy: void 0,\n      embeddedInTargetElement: void 0,\n      embeddedInLabel: void 0,\n      embeddedInNativeTextAlternative: void 0\n    })).join(\" \");\n    if (accessibleName)\n      return accessibleName;\n  }\n  const role = getAriaRole(element) || \"\";\n  const tagName = elementSafeTagName(element);\n  if (!!options.embeddedInLabel || !!options.embeddedInLabelledBy || options.embeddedInTargetElement === \"descendant\") {\n    const isOwnLabel = [...element.labels || []].includes(element);\n    const isOwnLabelledBy = (labelledBy || []).includes(element);\n    if (!isOwnLabel && !isOwnLabelledBy) {\n      if (role === \"textbox\") {\n        options.visitedElements.add(element);\n        if (tagName === \"INPUT\" || tagName === \"TEXTAREA\")\n          return element.value;\n        return element.textContent || \"\";\n      }\n      if ([\"combobox\", \"listbox\"].includes(role)) {\n        options.visitedElements.add(element);\n        let selectedOptions;\n        if (tagName === \"SELECT\") {\n          selectedOptions = [...element.selectedOptions];\n          if (!selectedOptions.length && element.options.length)\n            selectedOptions.push(element.options[0]);\n        } else {\n          const listbox = role === \"combobox\" ? queryInAriaOwned(element, \"*\").find((e) => getAriaRole(e) === \"listbox\") : element;\n          selectedOptions = listbox ? queryInAriaOwned(listbox, '[aria-selected=\"true\"]').filter((e) => getAriaRole(e) === \"option\") : [];\n        }\n        if (!selectedOptions.length && tagName === \"INPUT\") {\n          return element.value;\n        }\n        return selectedOptions.map((option) => getTextAlternativeInternal(option, childOptions)).join(\" \");\n      }\n      if ([\"progressbar\", \"scrollbar\", \"slider\", \"spinbutton\", \"meter\"].includes(role)) {\n        options.visitedElements.add(element);\n        if (element.hasAttribute(\"aria-valuetext\"))\n          return element.getAttribute(\"aria-valuetext\") || \"\";\n        if (element.hasAttribute(\"aria-valuenow\"))\n          return element.getAttribute(\"aria-valuenow\") || \"\";\n        return element.getAttribute(\"value\") || \"\";\n      }\n      if ([\"menu\"].includes(role)) {\n        options.visitedElements.add(element);\n        return \"\";\n      }\n    }\n  }\n  const ariaLabel = element.getAttribute(\"aria-label\") || \"\";\n  if (trimFlatString(ariaLabel)) {\n    options.visitedElements.add(element);\n    return ariaLabel;\n  }\n  if (![\"presentation\", \"none\"].includes(role)) {\n    if (tagName === \"INPUT\" && [\"button\", \"submit\", \"reset\"].includes(element.type)) {\n      options.visitedElements.add(element);\n      const value = element.value || \"\";\n      if (trimFlatString(value))\n        return value;\n      if (element.type === \"submit\")\n        return \"Submit\";\n      if (element.type === \"reset\")\n        return \"Reset\";\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (!getGlobalOptions().inputFileRoleTextbox && tagName === \"INPUT\" && element.type === \"file\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length && !options.embeddedInLabelledBy)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      return \"Choose File\";\n    }\n    if (tagName === \"INPUT\" && element.type === \"image\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length && !options.embeddedInLabelledBy)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      if (trimFlatString(title))\n        return title;\n      return \"Submit\";\n    }\n    if (!labelledBy && tagName === \"BUTTON\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n    }\n    if (!labelledBy && tagName === \"OUTPUT\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      return element.getAttribute(\"title\") || \"\";\n    }\n    if (!labelledBy && (tagName === \"TEXTAREA\" || tagName === \"SELECT\" || tagName === \"INPUT\")) {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length)\n        return getAccessibleNameFromAssociatedLabels(labels, options);\n      const usePlaceholder = tagName === \"INPUT\" && [\"text\", \"password\", \"search\", \"tel\", \"email\", \"url\"].includes(element.type) || tagName === \"TEXTAREA\";\n      const placeholder = element.getAttribute(\"placeholder\") || \"\";\n      const title = element.getAttribute(\"title\") || \"\";\n      if (!usePlaceholder || title)\n        return title;\n      return placeholder;\n    }\n    if (!labelledBy && tagName === \"FIELDSET\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"LEGEND\") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (!labelledBy && tagName === \"FIGURE\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"FIGCAPTION\") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (tagName === \"IMG\") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (tagName === \"TABLE\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"CAPTION\") {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInNativeTextAlternative: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n      const summary = element.getAttribute(\"summary\") || \"\";\n      if (summary)\n        return summary;\n    }\n    if (tagName === \"AREA\") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (trimFlatString(alt))\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (tagName === \"SVG\" || element.ownerSVGElement) {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (elementSafeTagName(child) === \"TITLE\" && child.ownerSVGElement) {\n          return getTextAlternativeInternal(child, {\n            ...childOptions,\n            embeddedInLabelledBy: { element: child, hidden: isElementHiddenForAria(child) }\n          });\n        }\n      }\n    }\n    if (element.ownerSVGElement && tagName === \"A\") {\n      const title = element.getAttribute(\"xlink:title\") || \"\";\n      if (trimFlatString(title)) {\n        options.visitedElements.add(element);\n        return title;\n      }\n    }\n  }\n  const shouldNameFromContentForSummary = tagName === \"SUMMARY\" && ![\"presentation\", \"none\"].includes(role);\n  if (allowsNameFromContent(role, options.embeddedInTargetElement === \"descendant\") || shouldNameFromContentForSummary || !!options.embeddedInLabelledBy || !!options.embeddedInDescribedBy || !!options.embeddedInLabel || !!options.embeddedInNativeTextAlternative) {\n    options.visitedElements.add(element);\n    const accessibleName = innerAccumulatedElementText(element, childOptions);\n    const maybeTrimmedAccessibleName = options.embeddedInTargetElement === \"self\" ? trimFlatString(accessibleName) : accessibleName;\n    if (maybeTrimmedAccessibleName)\n      return accessibleName;\n  }\n  if (![\"presentation\", \"none\"].includes(role) || tagName === \"IFRAME\") {\n    options.visitedElements.add(element);\n    const title = element.getAttribute(\"title\") || \"\";\n    if (trimFlatString(title))\n      return title;\n  }\n  options.visitedElements.add(element);\n  return \"\";\n}\nfunction innerAccumulatedElementText(element, options) {\n  const tokens = [];\n  const visit = (node, skipSlotted) => {\n    var _a;\n    if (skipSlotted && node.assignedSlot)\n      return;\n    if (node.nodeType === 1) {\n      const display = ((_a = getElementComputedStyle(node)) == null ? void 0 : _a.display) || \"inline\";\n      let token = getTextAlternativeInternal(node, options);\n      if (display !== \"inline\" || node.nodeName === \"BR\")\n        token = \" \" + token + \" \";\n      tokens.push(token);\n    } else if (node.nodeType === 3) {\n      tokens.push(node.textContent || \"\");\n    }\n  };\n  tokens.push(getPseudoContent(element, \"::before\"));\n  const assignedNodes = element.nodeName === \"SLOT\" ? element.assignedNodes() : [];\n  if (assignedNodes.length) {\n    for (const child of assignedNodes)\n      visit(child, false);\n  } else {\n    for (let child = element.firstChild; child; child = child.nextSibling)\n      visit(child, true);\n    if (element.shadowRoot) {\n      for (let child = element.shadowRoot.firstChild; child; child = child.nextSibling)\n        visit(child, true);\n    }\n    for (const owned of getIdRefs(element, element.getAttribute(\"aria-owns\")))\n      visit(owned, true);\n  }\n  tokens.push(getPseudoContent(element, \"::after\"));\n  return tokens.join(\"\");\n}\nvar kAriaSelectedRoles = [\"gridcell\", \"option\", \"row\", \"tab\", \"rowheader\", \"columnheader\", \"treeitem\"];\nfunction getAriaSelected(element) {\n  if (elementSafeTagName(element) === \"OPTION\")\n    return element.selected;\n  if (kAriaSelectedRoles.includes(getAriaRole(element) || \"\"))\n    return getAriaBoolean(element.getAttribute(\"aria-selected\")) === true;\n  return false;\n}\nvar kAriaCheckedRoles = [\"checkbox\", \"menuitemcheckbox\", \"option\", \"radio\", \"switch\", \"menuitemradio\", \"treeitem\"];\nfunction getAriaChecked(element) {\n  const result = getChecked(element, true);\n  return result === \"error\" ? false : result;\n}\nfunction getChecked(element, allowMixed) {\n  const tagName = elementSafeTagName(element);\n  if (allowMixed && tagName === \"INPUT\" && element.indeterminate)\n    return \"mixed\";\n  if (tagName === \"INPUT\" && [\"checkbox\", \"radio\"].includes(element.type))\n    return element.checked;\n  if (kAriaCheckedRoles.includes(getAriaRole(element) || \"\")) {\n    const checked = element.getAttribute(\"aria-checked\");\n    if (checked === \"true\")\n      return true;\n    if (allowMixed && checked === \"mixed\")\n      return \"mixed\";\n    return false;\n  }\n  return \"error\";\n}\nvar kAriaPressedRoles = [\"button\"];\nfunction getAriaPressed(element) {\n  if (kAriaPressedRoles.includes(getAriaRole(element) || \"\")) {\n    const pressed = element.getAttribute(\"aria-pressed\");\n    if (pressed === \"true\")\n      return true;\n    if (pressed === \"mixed\")\n      return \"mixed\";\n  }\n  return false;\n}\nvar kAriaExpandedRoles = [\"application\", \"button\", \"checkbox\", \"combobox\", \"gridcell\", \"link\", \"listbox\", \"menuitem\", \"row\", \"tab\", \"treeitem\", \"columnheader\", \"menuitemcheckbox\", \"menuitemradio\", \"rowheader\", \"switch\"];\nfunction getAriaExpanded(element) {\n  if (elementSafeTagName(element) === \"DETAILS\")\n    return element.open;\n  if (kAriaExpandedRoles.includes(getAriaRole(element) || \"\")) {\n    const expanded = element.getAttribute(\"aria-expanded\");\n    if (expanded === null)\n      return void 0;\n    if (expanded === \"true\")\n      return true;\n    return false;\n  }\n  return void 0;\n}\nvar kAriaLevelRoles = [\"heading\", \"listitem\", \"row\", \"treeitem\"];\nfunction getAriaLevel(element) {\n  const native = { \"H1\": 1, \"H2\": 2, \"H3\": 3, \"H4\": 4, \"H5\": 5, \"H6\": 6 }[elementSafeTagName(element)];\n  if (native)\n    return native;\n  if (kAriaLevelRoles.includes(getAriaRole(element) || \"\")) {\n    const attr = element.getAttribute(\"aria-level\");\n    const value = attr === null ? Number.NaN : Number(attr);\n    if (Number.isInteger(value) && value >= 1)\n      return value;\n  }\n  return 0;\n}\nvar kAriaDisabledRoles = [\"application\", \"button\", \"composite\", \"gridcell\", \"group\", \"input\", \"link\", \"menuitem\", \"scrollbar\", \"separator\", \"tab\", \"checkbox\", \"columnheader\", \"combobox\", \"grid\", \"listbox\", \"menu\", \"menubar\", \"menuitemcheckbox\", \"menuitemradio\", \"option\", \"radio\", \"radiogroup\", \"row\", \"rowheader\", \"searchbox\", \"select\", \"slider\", \"spinbutton\", \"switch\", \"tablist\", \"textbox\", \"toolbar\", \"tree\", \"treegrid\", \"treeitem\"];\nfunction getAriaDisabled(element) {\n  return isNativelyDisabled(element) || hasExplicitAriaDisabled(element);\n}\nfunction isNativelyDisabled(element) {\n  const isNativeFormControl = [\"BUTTON\", \"INPUT\", \"SELECT\", \"TEXTAREA\", \"OPTION\", \"OPTGROUP\"].includes(element.tagName);\n  return isNativeFormControl && (element.hasAttribute(\"disabled\") || belongsToDisabledFieldSet(element));\n}\nfunction belongsToDisabledFieldSet(element) {\n  const fieldSetElement = element == null ? void 0 : element.closest(\"FIELDSET[DISABLED]\");\n  if (!fieldSetElement)\n    return false;\n  const legendElement = fieldSetElement.querySelector(\":scope > LEGEND\");\n  return !legendElement || !legendElement.contains(element);\n}\nfunction hasExplicitAriaDisabled(element, isAncestor = false) {\n  if (!element)\n    return false;\n  if (isAncestor || kAriaDisabledRoles.includes(getAriaRole(element) || \"\")) {\n    const attribute = (element.getAttribute(\"aria-disabled\") || \"\").toLowerCase();\n    if (attribute === \"true\")\n      return true;\n    if (attribute === \"false\")\n      return false;\n    return hasExplicitAriaDisabled(parentElementOrShadowHost(element), true);\n  }\n  return false;\n}\nfunction getAccessibleNameFromAssociatedLabels(labels, options) {\n  return [...labels].map((label) => getTextAlternativeInternal(label, {\n    ...options,\n    embeddedInLabel: { element: label, hidden: isElementHiddenForAria(label) },\n    embeddedInNativeTextAlternative: void 0,\n    embeddedInLabelledBy: void 0,\n    embeddedInDescribedBy: void 0,\n    embeddedInTargetElement: void 0\n  })).filter((accessibleName) => !!accessibleName).join(\" \");\n}\nvar cacheAccessibleName;\nvar cacheAccessibleNameHidden;\nvar cacheAccessibleDescription;\nvar cacheAccessibleDescriptionHidden;\nvar cacheAccessibleErrorMessage;\nvar cacheIsHidden;\nvar cachePseudoContentBefore;\nvar cachePseudoContentAfter;\nvar cachesCounter = 0;\nfunction beginAriaCaches() {\n  ++cachesCounter;\n  cacheAccessibleName != null ? cacheAccessibleName : cacheAccessibleName = new k6BrowserNative.Map();\n  cacheAccessibleNameHidden != null ? cacheAccessibleNameHidden : cacheAccessibleNameHidden = new k6BrowserNative.Map();\n  cacheAccessibleDescription != null ? cacheAccessibleDescription : cacheAccessibleDescription = new k6BrowserNative.Map();\n  cacheAccessibleDescriptionHidden != null ? cacheAccessibleDescriptionHidden : cacheAccessibleDescriptionHidden = new k6BrowserNative.Map();\n  cacheAccessibleErrorMessage != null ? cacheAccessibleErrorMessage : cacheAccessibleErrorMessage = new k6BrowserNative.Map();\n  cacheIsHidden != null ? cacheIsHidden : cacheIsHidden = new k6BrowserNative.Map();\n  cachePseudoContentBefore != null ? cachePseudoContentBefore : cachePseudoContentBefore = new k6BrowserNative.Map();\n  cachePseudoContentAfter != null ? cachePseudoContentAfter : cachePseudoContentAfter = new k6BrowserNative.Map();\n}\nfunction endAriaCaches() {\n  if (!--cachesCounter) {\n    cacheAccessibleName = void 0;\n    cacheAccessibleNameHidden = void 0;\n    cacheAccessibleDescription = void 0;\n    cacheAccessibleDescriptionHidden = void 0;\n    cacheAccessibleErrorMessage = void 0;\n    cacheIsHidden = void 0;\n    cachePseudoContentBefore = void 0;\n    cachePseudoContentAfter = void 0;\n  }\n}\nvar inputTypeToRole = {\n  \"button\": \"button\",\n  \"checkbox\": \"checkbox\",\n  \"image\": \"button\",\n  \"number\": \"spinbutton\",\n  \"radio\": \"radio\",\n  \"range\": \"slider\",\n  \"reset\": \"button\",\n  \"submit\": \"button\"\n};\n\n// packages/injected/src/selectorUtils.ts\nfunction matchesAttributePart(value, attr) {\n  const objValue = typeof value === \"string\" && !attr.caseSensitive ? value.toUpperCase() : value;\n  const attrValue = typeof attr.value === \"string\" && !attr.caseSensitive ? attr.value.toUpperCase() : attr.value;\n  if (attr.op === \"<truthy>\")\n    return !!objValue;\n  if (attr.op === \"=\") {\n    if (attrValue instanceof RegExp)\n      return typeof objValue === \"string\" && !!objValue.match(attrValue);\n    return objValue === attrValue;\n  }\n  if (typeof objValue !== \"string\" || typeof attrValue !== \"string\")\n    return false;\n  if (attr.op === \"*=\")\n    return objValue.includes(attrValue);\n  if (attr.op === \"^=\")\n    return objValue.startsWith(attrValue);\n  if (attr.op === \"$=\")\n    return objValue.endsWith(attrValue);\n  if (attr.op === \"|=\")\n    return objValue === attrValue || objValue.startsWith(attrValue + \"-\");\n  if (attr.op === \"~=\")\n    return objValue.split(\" \").includes(attrValue);\n  return false;\n}\n\n// packages/playwright-core/src/utils/isomorphic/cssParser.ts\nvar InvalidSelectorError = class extends Error {\n};\n\n// packages/playwright-core/src/utils/isomorphic/selectorParser.ts\nfunction parseAttributeSelector(selector, allowUnquotedStrings) {\n  let wp = 0;\n  let EOL = selector.length === 0;\n  const next = () => selector[wp] || \"\";\n  const eat1 = () => {\n    const result2 = next();\n    ++wp;\n    EOL = wp >= selector.length;\n    return result2;\n  };\n  const syntaxError = (stage) => {\n    if (EOL)\n      throw new InvalidSelectorError(`Unexpected end of selector while parsing selector \\`${selector}\\``);\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - unexpected symbol \"${next()}\" at position ${wp}` + (stage ? \" during \" + stage : \"\"));\n  };\n  function skipSpaces() {\n    while (!EOL && /\\s/.test(next()))\n      eat1();\n  }\n  function isCSSNameChar(char) {\n    return char >= \"\\x80\" || char >= \"0\" && char <= \"9\" || char >= \"A\" && char <= \"Z\" || char >= \"a\" && char <= \"z\" || char >= \"0\" && char <= \"9\" || char === \"_\" || char === \"-\";\n  }\n  function readIdentifier() {\n    let result2 = \"\";\n    skipSpaces();\n    while (!EOL && isCSSNameChar(next()))\n      result2 += eat1();\n    return result2;\n  }\n  function readQuotedString(quote) {\n    let result2 = eat1();\n    if (result2 !== quote)\n      syntaxError(\"parsing quoted string\");\n    while (!EOL && next() !== quote) {\n      if (next() === \"\\\\\")\n        eat1();\n      result2 += eat1();\n    }\n    if (next() !== quote)\n      syntaxError(\"parsing quoted string\");\n    result2 += eat1();\n    return result2;\n  }\n  function readRegularExpression() {\n    if (eat1() !== \"/\")\n      syntaxError(\"parsing regular expression\");\n    let source = \"\";\n    let inClass = false;\n    while (!EOL) {\n      if (next() === \"\\\\\") {\n        source += eat1();\n        if (EOL)\n          syntaxError(\"parsing regular expression\");\n      } else if (inClass && next() === \"]\") {\n        inClass = false;\n      } else if (!inClass && next() === \"[\") {\n        inClass = true;\n      } else if (!inClass && next() === \"/\") {\n        break;\n      }\n      source += eat1();\n    }\n    if (eat1() !== \"/\")\n      syntaxError(\"parsing regular expression\");\n    let flags = \"\";\n    while (!EOL && next().match(/[dgimsuy]/))\n      flags += eat1();\n    try {\n      return new RegExp(source, flags);\n    } catch (e) {\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\`: ${e.message}`);\n    }\n  }\n  function readAttributeToken() {\n    let token = \"\";\n    skipSpaces();\n    if (next() === `'` || next() === `\"`)\n      token = readQuotedString(next()).slice(1, -1);\n    else\n      token = readIdentifier();\n    if (!token)\n      syntaxError(\"parsing property path\");\n    return token;\n  }\n  function readOperator() {\n    skipSpaces();\n    let op = \"\";\n    if (!EOL)\n      op += eat1();\n    if (!EOL && op !== \"=\")\n      op += eat1();\n    if (![\"=\", \"*=\", \"^=\", \"$=\", \"|=\", \"~=\"].includes(op))\n      syntaxError(\"parsing operator\");\n    return op;\n  }\n  function readAttribute() {\n    eat1();\n    const jsonPath = [];\n    jsonPath.push(readAttributeToken());\n    skipSpaces();\n    while (next() === \".\") {\n      eat1();\n      jsonPath.push(readAttributeToken());\n      skipSpaces();\n    }\n    if (next() === \"]\") {\n      eat1();\n      return { name: jsonPath.join(\".\"), jsonPath, op: \"<truthy>\", value: null, caseSensitive: false };\n    }\n    const operator = readOperator();\n    let value = void 0;\n    let caseSensitive = true;\n    skipSpaces();\n    if (next() === \"/\") {\n      if (operator !== \"=\")\n        throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with regular expression`);\n      value = readRegularExpression();\n    } else if (next() === `'` || next() === `\"`) {\n      value = readQuotedString(next()).slice(1, -1);\n      skipSpaces();\n      if (next() === \"i\" || next() === \"I\") {\n        caseSensitive = false;\n        eat1();\n      } else if (next() === \"s\" || next() === \"S\") {\n        caseSensitive = true;\n        eat1();\n      }\n    } else {\n      value = \"\";\n      while (!EOL && (isCSSNameChar(next()) || next() === \"+\" || next() === \".\"))\n        value += eat1();\n      if (value === \"true\") {\n        value = true;\n      } else if (value === \"false\") {\n        value = false;\n      } else {\n        if (!allowUnquotedStrings) {\n          value = +value;\n          if (Number.isNaN(value))\n            syntaxError(\"parsing attribute value\");\n        }\n      }\n    }\n    skipSpaces();\n    if (next() !== \"]\")\n      syntaxError(\"parsing attribute value\");\n    eat1();\n    if (operator !== \"=\" && typeof value !== \"string\")\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with non-string matching value - ${value}`);\n    return { name: jsonPath.join(\".\"), jsonPath, op: operator, value, caseSensitive };\n  }\n  const result = {\n    name: \"\",\n    attributes: []\n  };\n  result.name = readIdentifier();\n  skipSpaces();\n  while (next() === \"[\") {\n    result.attributes.push(readAttribute());\n    skipSpaces();\n  }\n  if (!EOL)\n    syntaxError(void 0);\n  if (!result.name && !result.attributes.length)\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - selector cannot be empty`);\n  return result;\n}\n\n// packages/injected/src/roleSelectorEngine.ts\nvar kSupportedAttributes = [\"selected\", \"checked\", \"pressed\", \"expanded\", \"level\", \"disabled\", \"name\", \"include-hidden\"];\nkSupportedAttributes.sort();\nfunction validateSupportedRole(attr, roles, role) {\n  if (!roles.includes(role))\n    throw new Error(`\"${attr}\" attribute is only supported for roles: ${roles.slice().sort().map((role2) => `\"${role2}\"`).join(\", \")}`);\n}\nfunction validateSupportedValues(attr, values) {\n  if (attr.op !== \"<truthy>\" && !values.includes(attr.value))\n    throw new Error(`\"${attr.name}\" must be one of ${values.map((v) => JSON.stringify(v)).join(\", \")}`);\n}\nfunction validateSupportedOp(attr, ops) {\n  if (!ops.includes(attr.op))\n    throw new Error(`\"${attr.name}\" does not support \"${attr.op}\" matcher`);\n}\nfunction validateAttributes(attrs, role) {\n  const options = { role };\n  for (const attr of attrs) {\n    switch (attr.name) {\n      case \"checked\": {\n        validateSupportedRole(attr.name, kAriaCheckedRoles, role);\n        validateSupportedValues(attr, [true, false, \"mixed\"]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.checked = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"pressed\": {\n        validateSupportedRole(attr.name, kAriaPressedRoles, role);\n        validateSupportedValues(attr, [true, false, \"mixed\"]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.pressed = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"selected\": {\n        validateSupportedRole(attr.name, kAriaSelectedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.selected = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"expanded\": {\n        validateSupportedRole(attr.name, kAriaExpandedRoles, role);\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.expanded = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"level\": {\n        validateSupportedRole(attr.name, kAriaLevelRoles, role);\n        if (typeof attr.value === \"string\")\n          attr.value = +attr.value;\n        if (attr.op !== \"=\" || typeof attr.value !== \"number\" || Number.isNaN(attr.value))\n          throw new Error(`\"level\" attribute must be compared to a number`);\n        options.level = attr.value;\n        break;\n      }\n      case \"disabled\": {\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.disabled = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      case \"name\": {\n        if (attr.op === \"<truthy>\")\n          throw new Error(`\"name\" attribute must have a value`);\n        if (typeof attr.value !== \"string\" && !(attr.value instanceof RegExp))\n          throw new Error(`\"name\" attribute must be a string or a regular expression`);\n        options.name = attr.value;\n        options.nameOp = attr.op;\n        options.exact = attr.caseSensitive;\n        break;\n      }\n      case \"include-hidden\": {\n        validateSupportedValues(attr, [true, false]);\n        validateSupportedOp(attr, [\"<truthy>\", \"=\"]);\n        options.includeHidden = attr.op === \"<truthy>\" ? true : attr.value;\n        break;\n      }\n      default: {\n        throw new Error(`Unknown attribute \"${attr.name}\", must be one of ${kSupportedAttributes.map((a) => `\"${a}\"`).join(\", \")}.`);\n      }\n    }\n  }\n  return options;\n}\nfunction queryRole(scope, options, internal) {\n  const result = [];\n  const match = (element) => {\n    if (getAriaRole(element) !== options.role)\n      return;\n    if (options.selected !== void 0 && getAriaSelected(element) !== options.selected)\n      return;\n    if (options.checked !== void 0 && getAriaChecked(element) !== options.checked)\n      return;\n    if (options.pressed !== void 0 && getAriaPressed(element) !== options.pressed)\n      return;\n    if (options.expanded !== void 0 && getAriaExpanded(element) !== options.expanded)\n      return;\n    if (options.level !== void 0 && getAriaLevel(element) !== options.level)\n      return;\n    if (options.disabled !== void 0 && getAriaDisabled(element) !== options.disabled)\n      return;\n    if (!options.includeHidden) {\n      const isHidden = isElementHiddenForAria(element);\n      if (isHidden)\n        return;\n    }\n    if (options.name !== void 0) {\n      const accessibleName = normalizeWhiteSpace(getElementAccessibleName(element, !!options.includeHidden));\n      if (typeof options.name === \"string\")\n        options.name = normalizeWhiteSpace(options.name);\n      if (internal && !options.exact && options.nameOp === \"=\")\n        options.nameOp = \"*=\";\n      if (!matchesAttributePart(accessibleName, { name: \"\", jsonPath: [], op: options.nameOp || \"=\", value: options.name, caseSensitive: !!options.exact }))\n        return;\n    }\n    result.push(element);\n  };\n  const query = (root) => {\n    const shadows = [];\n    if (root.shadowRoot)\n      shadows.push(root.shadowRoot);\n    for (const element of root.querySelectorAll(\"*\")) {\n      match(element);\n      if (element.shadowRoot)\n        shadows.push(element.shadowRoot);\n    }\n    shadows.forEach(query);\n  };\n  query(scope);\n  return result;\n}\n\nfunction createRoleEngine(internal) {\n  return {\n    queryAll: (scope, selector) => {\n      const parsed = parseAttributeSelector(selector, true);\n      const role = parsed.name.toLowerCase();\n      if (!role)\n        throw new Error(`Role must not be empty`);\n      const options = validateAttributes(parsed.attributes, role);\n      beginAriaCaches();\n      try {\n        return queryRole(scope, options, internal);\n      } finally {\n        endAriaCaches();\n      }\n    }\n  };\n}\n\n// packages/injected/src/selectorEvaluator.ts\nvar SelectorEvaluatorImpl = class {\n  constructor() {\n    this._retainCacheCounter = 0;\n    this._cacheText = new k6BrowserNative.Map();\n    this._cacheQueryCSS = new k6BrowserNative.Map();\n  }\n  begin() {\n    ++this._retainCacheCounter;\n  }\n  end() {\n    --this._retainCacheCounter;\n    if (!this._retainCacheCounter) {\n      this._cacheQueryCSS.clear();\n      this._cacheText.clear();\n    }\n  }\n  _cached(cache, main, rest, cb) {\n    if (!cache.has(main))\n      cache.set(main, []);\n    const entries = cache.get(main);\n    const entry = entries.find((e) => rest.every((value, index) => e.rest[index] === value));\n    if (entry)\n      return entry.result;\n    const result = cb();\n    entries.push({ rest, result });\n    return result;\n  }\n  _queryCSS(context, css) {\n    return this._cached(this._cacheQueryCSS, css, [context.scope, context.pierceShadow, context.originalScope], () => {\n      let result = [];\n      function query(root) {\n        result = result.concat([...root.querySelectorAll(css)]);\n        if (!context.pierceShadow)\n          return;\n        if (root.shadowRoot)\n          query(root.shadowRoot);\n        for (const element of root.querySelectorAll(\"*\")) {\n          if (element.shadowRoot)\n            query(element.shadowRoot);\n        }\n      }\n      query(context.scope);\n      return result;\n    });\n  }\n};\n\n// packages/injected/src/selectorUtils.ts\nfunction shouldSkipForTextMatching(element) {\n  const document = element.ownerDocument;\n  return element.nodeName === \"SCRIPT\" || element.nodeName === \"NOSCRIPT\" || element.nodeName === \"STYLE\" || document.head && document.head.contains(element);\n}\nfunction elementText(cache, root) {\n  let value = cache.get(root);\n  if (value === void 0) {\n    value = { full: \"\", normalized: \"\", immediate: [] };\n    if (!shouldSkipForTextMatching(root)) {\n      let currentImmediate = \"\";\n      if (root instanceof HTMLInputElement && (root.type === \"submit\" || root.type === \"button\")) {\n        value = { full: root.value, normalized: normalizeWhiteSpace(root.value), immediate: [root.value] };\n      } else {\n        for (let child = root.firstChild; child; child = child.nextSibling) {\n          if (child.nodeType === Node.TEXT_NODE) {\n            value.full += child.nodeValue || \"\";\n            currentImmediate += child.nodeValue || \"\";\n          } else if (child.nodeType === Node.COMMENT_NODE) {\n            continue;\n          } else {\n            if (currentImmediate)\n              value.immediate.push(currentImmediate);\n            currentImmediate = \"\";\n            if (child.nodeType === Node.ELEMENT_NODE)\n              value.full += elementText(cache, child).full;\n          }\n        }\n        if (currentImmediate)\n          value.immediate.push(currentImmediate);\n        if (root.shadowRoot)\n          value.full += elementText(cache, root.shadowRoot).full;\n        if (value.full)\n          value.normalized = normalizeWhiteSpace(value.full);\n      }\n    }\n    cache.set(root, value);\n  }\n  return value;\n}\nfunction getElementLabels(textCache, element) {\n  const labels = getAriaLabelledByElements(element);\n  if (labels)\n    return labels.map((label) => elementText(textCache, label));\n  const ariaLabel = element.getAttribute(\"aria-label\");\n  if (ariaLabel !== null && !!ariaLabel.trim())\n    return [{ full: ariaLabel, normalized: normalizeWhiteSpace(ariaLabel), immediate: [ariaLabel] }];\n  const isNonHiddenInput = element.nodeName === \"INPUT\" && element.type !== \"hidden\";\n  if ([\"BUTTON\", \"METER\", \"OUTPUT\", \"PROGRESS\", \"SELECT\", \"TEXTAREA\"].includes(element.nodeName) || isNonHiddenInput) {\n    const labels2 = element.labels;\n    if (labels2)\n      return [...labels2].map((label) => elementText(textCache, label));\n  }\n  return [];\n}\nfunction elementMatchesText(cache, element, matcher) {\n  if (shouldSkipForTextMatching(element))\n    return \"none\";\n  if (!matcher(elementText(cache, element)))\n    return \"none\";\n  for (let child = element.firstChild; child; child = child.nextSibling) {\n    if (child.nodeType === Node.ELEMENT_NODE && matcher(elementText(cache, child)))\n      return \"selfAndChildren\";\n  }\n  if (element.shadowRoot && matcher(elementText(cache, element.shadowRoot)))\n    return \"selfAndChildren\";\n  return \"self\";\n}\n\n// packages/injected/src/injectedScript.ts\nfunction cssUnquote(s) {\n  s = s.substring(1, s.length - 1);\n  if (!s.includes(\"\\\\\"))\n    return s;\n  const r = [];\n  let i = 0;\n  while (i < s.length) {\n    if (s[i] === \"\\\\\" && i + 1 < s.length)\n      i++;\n    r.push(s[i++]);\n  }\n  return r.join(\"\");\n}\nfunction createTextMatcher(selector, internal) {\n  if (selector[0] === \"/\" && selector.lastIndexOf(\"/\") > 0) {\n    const lastSlash = selector.lastIndexOf(\"/\");\n    const re = new RegExp(selector.substring(1, lastSlash), selector.substring(lastSlash + 1));\n    return { matcher: (elementText2) => re.test(elementText2.full), kind: \"regex\" };\n  }\n  const unquote = internal ? JSON.parse.bind(JSON) : cssUnquote;\n  let strict = false;\n  if (selector.length > 1 && selector[0] === '\"' && selector[selector.length - 1] === '\"') {\n    selector = unquote(selector);\n    strict = true;\n  } else if (internal && selector.length > 1 && selector[0] === '\"' && selector[selector.length - 2] === '\"' && selector[selector.length - 1] === \"i\") {\n    selector = unquote(selector.substring(0, selector.length - 1));\n    strict = false;\n  } else if (internal && selector.length > 1 && selector[0] === '\"' && selector[selector.length - 2] === '\"' && selector[selector.length - 1] === \"s\") {\n    selector = unquote(selector.substring(0, selector.length - 1));\n    strict = true;\n  } else if (selector.length > 1 && selector[0] === \"'\" && selector[selector.length - 1] === \"'\") {\n    selector = unquote(selector);\n    strict = true;\n  }\n  selector = normalizeWhiteSpace(selector);\n  if (strict) {\n    if (internal)\n      return { kind: \"strict\", matcher: (elementText2) => elementText2.normalized === selector };\n    const strictTextNodeMatcher = (elementText2) => {\n      if (!selector && !elementText2.immediate.length)\n        return true;\n      return elementText2.immediate.some((s) => normalizeWhiteSpace(s) === selector);\n    };\n    return { matcher: strictTextNodeMatcher, kind: \"strict\" };\n  }\n  selector = selector.toLowerCase();\n  return { kind: \"lax\", matcher: (elementText2) => elementText2.normalized.toLowerCase().includes(selector) };\n}\n\n\nconst autoClosingTags = new k6BrowserNative.Set([\n  \"AREA\",\n  \"BASE\",\n  \"BR\",\n  \"COL\",\n  \"COMMAND\",\n  \"EMBED\",\n  \"HR\",\n  \"IMG\",\n  \"INPUT\",\n  \"KEYGEN\",\n  \"LINK\",\n  \"MENUITEM\",\n  \"META\",\n  \"PARAM\",\n  \"SOURCE\",\n  \"TRACK\",\n  \"WBR\",\n]);\nconst booleanAttributes = new k6BrowserNative.Set([\n  \"checked\",\n  \"selected\",\n  \"disabled\",\n  \"readonly\",\n  \"multiple\",\n]);\nconst eventType = new k6BrowserNative.Map([\n  [\"auxclick\", \"mouse\"],\n  [\"click\", \"mouse\"],\n  [\"dblclick\", \"mouse\"],\n  [\"mousedown\", \"mouse\"],\n  [\"mouseenter\", \"mouse\"],\n  [\"mouseleave\", \"mouse\"],\n  [\"mousemove\", \"mouse\"],\n  [\"mouseout\", \"mouse\"],\n  [\"mouseover\", \"mouse\"],\n  [\"mouseup\", \"mouse\"],\n  [\"mousewheel\", \"mouse\"],\n\n  [\"keydown\", \"keyboard\"],\n  [\"keyup\", \"keyboard\"],\n  [\"keypress\", \"keyboard\"],\n  [\"textInput\", \"keyboard\"],\n\n  [\"touchstart\", \"touch\"],\n  [\"touchmove\", \"touch\"],\n  [\"touchend\", \"touch\"],\n  [\"touchcancel\", \"touch\"],\n\n  [\"pointerover\", \"pointer\"],\n  [\"pointerout\", \"pointer\"],\n  [\"pointerenter\", \"pointer\"],\n  [\"pointerleave\", \"pointer\"],\n  [\"pointerdown\", \"pointer\"],\n  [\"pointerup\", \"pointer\"],\n  [\"pointermove\", \"pointer\"],\n  [\"pointercancel\", \"pointer\"],\n  [\"gotpointercapture\", \"pointer\"],\n  [\"lostpointercapture\", \"pointer\"],\n\n  [\"focus\", \"focus\"],\n  [\"blur\", \"focus\"],\n\n  [\"drag\", \"drag\"],\n  [\"dragstart\", \"drag\"],\n  [\"dragend\", \"drag\"],\n  [\"dragover\", \"drag\"],\n  [\"dragenter\", \"drag\"],\n  [\"dragleave\", \"drag\"],\n  [\"dragexit\", \"drag\"],\n  [\"drop\", \"drag\"],\n]);\n\nconst continuePolling = Symbol(\"continuePolling\");\n\nfunction isVisible(element) {\n  if (!element.ownerDocument || !element.ownerDocument.defaultView) {\n    return true;\n  }\n  const style = element.ownerDocument.defaultView.getComputedStyle(element);\n  if (!style || style.visibility === \"hidden\") {\n    return false;\n  }\n  const rect = element.getBoundingClientRect();\n  return rect.width > 0 && rect.height > 0;\n}\n\nfunction oneLine(s) {\n  return s.replace(/\\n/g, \"↵\").replace(/\\t/g, \"⇆\");\n}\n\nclass CSSQueryEngine {\n  queryAll(root, selector) {\n    return root.querySelectorAll(selector);\n  }\n}\n\nclass TextQueryEngine {\n  queryAll(root, selector) {\n    return root.queryAll(selector);\n  }\n}\n\nclass XPathQueryEngine {\n  queryAll(root, selector) {\n    if (selector.startsWith(\"/\")) {\n      selector = \".\" + selector;\n    }\n    const result = [];\n\n    // DocumentFragments cannot be queried with XPath and they do not implement\n    // evaluate. It first needs to be converted to a Document before being able\n    // to run the evaluate against it.\n    //\n    // This avoids the following error:\n    // - Failed to execute 'evaluate' on 'Document': The node provided is\n    //   '#document-fragment', which is not a valid context node type.\n    if (root instanceof DocumentFragment) {\n      root = convertToDocument(root);\n    }\n\n    const document = root instanceof Document ? root : root.ownerDocument;\n    if (!document) {\n      return result;\n    }\n    const it = document.evaluate(\n      selector,\n      root,\n      null,\n      XPathResult.ORDERED_NODE_ITERATOR_TYPE\n    );\n    for (let node = it.iterateNext(); node; node = it.iterateNext()) {\n      if (node.nodeType === 1 /*Node.ELEMENT_NODE*/) {\n        result.push(node);\n      }\n    }\n    return result;\n  }\n}\n\nclass AttributeEngine {\n  constructor() {\n    this._evaluator = new SelectorEvaluatorImpl();\n  }\n  queryAll(root, selector) {\n    try {\n      this._evaluator.begin();\n\n      const parsed = parseAttributeSelector(selector, true);\n      if (parsed.name || parsed.attributes.length !== 1)\n        throw new Error(\"Malformed attribute selector: \" + selector);\n      const { name, value, caseSensitive } = parsed.attributes[0];\n      const lowerCaseValue = caseSensitive ? null : value.toLowerCase();\n      let matcher;\n      if (value instanceof RegExp)\n        matcher = (s) => !!s.match(value);\n      else if (caseSensitive)\n        matcher = (s) => s === value;\n      else\n        matcher = (s) => s.toLowerCase().includes(lowerCaseValue);\n      const elements = this._evaluator._queryCSS({ scope: root, pierceShadow: true }, `[${name}]`);\n      return elements.filter((e) => matcher(e.getAttribute(name)));\n    } finally {\n      this._evaluator.end();\n    }\n  };\n}\n\nclass LabelEngine {\n  constructor() {\n    this._evaluator = new SelectorEvaluatorImpl();\n  }\n  queryAll(root, selector) {\n    try {\n      this._evaluator.begin();\n\n      const { matcher } = createTextMatcher(selector, true);\n      const allElements = this._evaluator._queryCSS({ scope: root, pierceShadow: true }, \"*\");\n      return allElements.filter((element) => {\n        return getElementLabels(this._evaluator._cacheText, element).some((label) => matcher(label));\n      });\n    } finally {\n      this._evaluator.end();\n    }\n  }\n}\n\nclass TextEngine {\n  constructor(shadow, internal) {\n    this._evaluator = new SelectorEvaluatorImpl();\n    this._shadow = shadow;\n    this._internal = internal;\n  }\n  queryAll(root, selector) {\n    try {\n      this._evaluator.begin();\n\n      const { matcher, kind } = createTextMatcher(selector, this._internal);\n      const result = [];\n      let lastDidNotMatchSelf = null;\n      const appendElement = (element) => {\n        if (kind === \"lax\" && lastDidNotMatchSelf && lastDidNotMatchSelf.contains(element))\n          return false;\n        const matches = elementMatchesText(this._evaluator._cacheText, element, matcher);\n        if (matches === \"none\")\n          lastDidNotMatchSelf = element;\n        if (matches === \"self\" || matches === \"selfAndChildren\" && kind === \"strict\" && !this._internal)\n          result.push(element);\n      };\n      if (root.nodeType === Node.ELEMENT_NODE)\n        appendElement(root);\n      const elements = this._evaluator._queryCSS({ scope: root, pierceShadow: this._shadow }, \"*\");\n      for (const element of elements)\n        appendElement(element);\n      return result;\n    } finally {\n      this._evaluator.end();\n    }\n  }\n}\n\n// convertToDocument will convert a DocumentFragment into a Document. It does\n// this by creating a new Document and copying the elements from the\n// DocumentFragment to the Document.\nfunction convertToDocument(fragment) {\n  var newDoc = document.implementation.createHTMLDocument(\"Temporary Document\");\n\n  copyNodesToDocument(fragment, newDoc.body);\n\n  return newDoc;\n}\n\n// copyNodesToDocument manually copies nodes to a new document, excluding\n// ShadowRoot nodes -- ShadowRoot are not cloneable so we need to manually\n// clone them one element at a time.\nfunction copyNodesToDocument(sourceNode, targetNode) {\n  sourceNode.childNodes.forEach((child) => {\n      if (child.nodeType === Node.ELEMENT_NODE) {\n          // Clone the child node without its descendants\n          let clonedChild = child.cloneNode(false);\n          targetNode.appendChild(clonedChild);\n\n          // If the child has a shadow root, recursively copy its children\n          // instead of the shadow root itself.\n          if (child.shadowRoot) {\n              copyNodesToDocument(child.shadowRoot, clonedChild);\n          } else {\n              // Recursively copy normal child nodes\n              copyNodesToDocument(child, clonedChild);\n          }\n      } else {\n          // For non-element nodes (like text nodes), clone them directly.\n          let clonedChild = child.cloneNode(true);\n          targetNode.appendChild(clonedChild);\n      }\n  });\n}\n\nclass InjectedScript {\n  constructor() {\n    this._replaceRafWithTimeout = false;\n    this._stableRafCount = 10;\n    this._evaluator = new SelectorEvaluatorImpl();\n    this._queryEngines = {\n      css: new CSSQueryEngine(),\n      text: new TextQueryEngine(),\n      xpath: new XPathQueryEngine(),\n      'internal:role': createRoleEngine(true),\n      'internal:attr': new AttributeEngine(),\n      'internal:label': new LabelEngine(),\n      'internal:text': new TextEngine(true, true),\n      'internal:has-text': this._createInternalHasTextEngine(),\n      'internal:has-not-text': this._createInternalHasNotTextEngine(),\n    };\n  }\n\n  _queryEngineAll(part, root) {\n    return this._queryEngines[part.name].queryAll(root, part.body);\n  }\n\n  _createInternalHasTextEngine() {\n    return {\n      queryAll: (root, selector) => {\n        if (root.nodeType !== 1 /* Node.ELEMENT_NODE */)\n          return [];\n        const element = root;\n        const text = elementText(this._evaluator._cacheText, element);\n        const { matcher } = createTextMatcher(selector, true);\n        return matcher(text) ? [element] : [];\n      }\n    };\n  }\n\n  _createInternalHasNotTextEngine() {\n    return {\n      queryAll: (root, selector) => {\n        if (root.nodeType !== 1 /* Node.ELEMENT_NODE */)\n          return [];\n        const element = root;\n        const text = elementText(this._evaluator._cacheText, element);\n        const { matcher } = createTextMatcher(selector, true);\n        return matcher(text) ? [] : [element];\n      }\n    };\n  }\n\n  _querySelectorRecursively(roots, selector, index, queryCache) {\n    if (index === selector.parts.length) {\n      return roots;\n    }\n\n    const part = selector.parts[index];\n    if (part.name === \"nth\") {\n      let filtered = [];\n      if (part.body === \"0\") {\n        filtered = roots.slice(0, 1);\n      } else if (part.body === \"-1\") {\n        if (roots.length) {\n          filtered = roots.slice(roots.length - 1);\n        }\n      } else {\n        if (typeof selector.capture === \"number\") {\n          return \"error:nthnocapture\";\n        }\n        const nth = parseInt(part.body, 10);\n        const set = new k6BrowserNative.Set();\n        for (const root of roots) {\n          set.add(root.element);\n          if (nth + 1 === set.size) {\n            filtered = [root];\n          }\n        }\n      }\n      return this._querySelectorRecursively(\n        filtered,\n        selector,\n        index + 1,\n        queryCache\n      );\n    }\n\n    if (part.name === \"visible\") {\n      const visible = Boolean(part.body);\n      return roots.filter((match) => visible === isVisible(match.element));\n    }\n\n    const result = [];\n    for (const root of roots) {\n      const capture =\n        index - 1 === selector.capture ? root.element : root.capture;\n\n      // Do not query engine twice for the same element.\n      let queryResults = queryCache.get(root.element);\n      if (!queryResults) {\n        queryResults = [];\n        queryCache.set(root.element, queryResults);\n      }\n      let all = queryResults[index];\n      if (!all) {\n        all = this._queryEngineAll(selector.parts[index], root.element);\n        queryResults[index] = all;\n      }\n\n      for (const element of all) {\n        if (!(\"nodeName\" in element)) {\n          return `error:expectednode:${Object.prototype.toString.call(\n            element\n          )}`;\n        }\n        result.push({ element, capture });\n      }\n\n      // Explore the Shadow DOM recursively.\n      const shadowResults = this._exploreShadowDOM(root.element, selector, index, queryCache, capture);\n      result.push(...shadowResults);\n    }\n\n    return this._querySelectorRecursively(\n      result,\n      selector,\n      index + 1,\n      queryCache\n    );\n  }\n\n  _exploreShadowDOM(root, selector, index, queryCache, capture) {\n    let result = [];\n    if (root.shadowRoot) {\n      const shadowRootResults = this._querySelectorRecursively(\n        [{ element: root.shadowRoot, capture }],\n        selector,\n        index,\n        queryCache\n      );\n      result = result.concat(shadowRootResults);\n    }\n\n    if (!root.hasChildNodes()) return result;\n    \n    for (let i = 0; i < root.children.length; i++) {\n      const childElement = root.children[i];\n      result = result.concat(this._exploreShadowDOM(childElement, selector, index, queryCache, capture));\n    }\n    \n    return result;\n  }\n\n  // Make sure we target an appropriate node in the DOM before performing an action.\n  _retarget(node, behavior) {\n    let element =\n      node.nodeType === 1 /*Node.ELEMENT_NODE*/ ? node : node.parentElement;\n    if (!element) {\n      return null;\n    }\n    if (!element.matches(\"input, textarea, select\")) {\n      element =\n        element.closest(\n          \"button, [role=button], [role=checkbox], [role=radio]\"\n        ) || element;\n    }\n    if (behavior === \"follow-label\") {\n      if (\n        !element.matches(\n          \"input, textarea, button, select, [role=button], [role=checkbox], [role=radio]\"\n        ) &&\n        !element.isContentEditable\n      ) {\n        // Go up to the label that might be connected to the input/textarea.\n        element = element.closest(\"label\") || element;\n      }\n      if (element.nodeName === \"LABEL\") {\n        element = element.control || element;\n      }\n    }\n    return element;\n  }\n\n  checkElementState(node, state) {\n    const element = this._retarget(\n      node,\n      [\"stable\", \"visible\", \"hidden\"].includes(state)\n        ? \"no-follow-label\"\n        : \"follow-label\"\n    );\n    if (!element || !element.isConnected) {\n      if (state === \"hidden\") {\n        return true;\n      }\n      return \"error:notconnected\";\n    }\n\n    if (state === \"visible\") {\n      return this.isVisible(element);\n    }\n    if (state === \"hidden\") {\n      return !this.isVisible(element);\n    }\n\n    const disabled =\n      [\"BUTTON\", \"INPUT\", \"SELECT\", \"TEXTAREA\"].includes(element.nodeName) &&\n      element.hasAttribute(\"disabled\");\n    if (state === \"disabled\") {\n      return disabled;\n    }\n    if (state === \"enabled\") {\n      return !disabled;\n    }\n\n    const editable = !(\n      [\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(element.nodeName) &&\n      element.hasAttribute(\"readonly\")\n    );\n    if (state === \"editable\") {\n      return !disabled && editable;\n    }\n\n    if (state === \"checked\") {\n      if (element.getAttribute(\"role\") === \"checkbox\") {\n        return element.getAttribute(\"aria-checked\") === \"true\";\n      }\n      if (element.nodeName !== \"INPUT\") {\n        return \"error:notcheckbox\";\n      }\n      if (![\"radio\", \"checkbox\"].includes(element.type.toLowerCase())) {\n        return \"error:notcheckbox\";\n      }\n      return element.checked;\n    }\n    return 'error:unexpected element state \"' + state + '\"';\n  }\n\n  checkHitTargetAt(node, point) {\n    let element =\n      node.nodeType === 1 /*Node.ELEMENT_NODE*/ ? node : node.parentElement;\n    if (!element || !element.isConnected) {\n      return \"error:notconnected\";\n    }\n    element = element.closest(\"button, [role=button]\") || element;\n    let hitElement = this.deepElementFromPoint(document, point.x, point.y);\n    const hitParents = [];\n    while (hitElement && hitElement !== element) {\n      hitParents.push(hitElement);\n      hitElement = this.parentElementOrShadowHost(hitElement);\n    }\n    if (hitElement === element) {\n      return \"done\";\n    }\n    const hitTargetDescription = this.previewNode(hitParents[0] || document.documentElement);\n    // Root is the topmost element in the hitTarget's chain that is not in the\n    // element's chain. For example, it might be a dialog element that overlays\n    // the target.\n    let rootHitTargetDescription;\n    while (element) {\n      const index = hitParents.indexOf(element);\n      if (index !== -1) {\n        if (index > 1) {\n          rootHitTargetDescription = this.previewNode(hitParents[index - 1]);\n        }\n        break;\n      }\n      element = this.parentElementOrShadowHost(element);\n    }\n    if (rootHitTargetDescription)\n      return {\n        hitTargetDescription: `${hitTargetDescription} from ${rootHitTargetDescription} subtree`,\n      };\n    return { hitTargetDescription };\n  }\n\n  deepElementFromPoint(document, x, y) {\n    let container = document;\n    let element;\n    while (container) {\n      // elementFromPoint works incorrectly in Chromium (http://crbug.com/1188919),\n      // so we use elementsFromPoint instead.\n      const elements = container.elementsFromPoint(x, y);\n      const innerElement = elements[0];\n      if (!innerElement || element === innerElement) {\n        break;\n      }\n      element = innerElement;\n      container = element.shadowRoot;\n    }\n    return element;\n  }\n\n  dispatchEvent(node, type, eventInit) {\n    let event;\n    eventInit = {\n      bubbles: true,\n      cancelable: true,\n      composed: true,\n      ...eventInit,\n    };\n    switch (eventType.get(type)) {\n      case \"mouse\":\n        event = new MouseEvent(type, eventInit);\n        break;\n      case \"keyboard\":\n        event = new KeyboardEvent(type, eventInit);\n        break;\n      case \"touch\":\n        event = new TouchEvent(type, eventInit);\n        break;\n      case \"pointer\":\n        event = new PointerEvent(type, eventInit);\n        break;\n      case \"focus\":\n        event = new FocusEvent(type, eventInit);\n        break;\n      case \"drag\":\n        event = new DragEvent(type, eventInit);\n        break;\n      default:\n        event = new Event(type, eventInit);\n        break;\n    }\n    node.dispatchEvent(event);\n  }\n\n  setInputFiles(node, payloads) {\n    if (node.nodeType !== Node.ELEMENT_NODE)\n      return \"error:notelement\";\n    if (node.nodeName.toLowerCase() !== \"input\")\n      return 'error:notinput';\n    const type = (node.getAttribute('type') || '').toLowerCase();\n    if (type !== 'file')\n      return 'error:notfile';\n\n    const dt = new DataTransfer();\n    if (payloads) {\n      const files = payloads.map(file => {\n        const bytes = Uint8Array.from(atob(file.buffer), c => c.charCodeAt(0));\n        return new File([bytes], file.name, { type: file.mimeType, lastModified: file.lastModifiedMs });\n      });\n      for (const file of files)\n        dt.items.add(file);\n    }\n    node.files = dt.files;\n    node.dispatchEvent(new Event('input', { 'bubbles': true }));\n    node.dispatchEvent(new Event('change', { 'bubbles': true }));\n    return \"done\";\n  }\n\n  getElementBorderWidth(node) {\n    if (\n      node.nodeType !== 1 /*Node.ELEMENT_NODE*/ ||\n      !node.ownerDocument ||\n      !node.ownerDocument.defaultView\n    ) {\n      return { left: 0, top: 0 };\n    }\n    const style = node.ownerDocument.defaultView.getComputedStyle(node);\n    return {\n      left: parseInt(style.borderLeftWidth || \"\", 10),\n      top: parseInt(style.borderTopWidth || \"\", 10),\n    };\n  }\n\n  fill(node, value=\"\") {\n    const element = this._retarget(node, \"follow-label\");\n    if (!element) {\n      return \"error:notconnected\";\n    }\n    if (element.nodeName.toLowerCase() === \"input\") {\n      const input = element;\n      const type = input.type.toLowerCase();\n      const kDateTypes = new k6BrowserNative.Set([\n        \"date\",\n        \"time\",\n        \"datetime\",\n        \"datetime-local\",\n        \"month\",\n        \"week\",\n      ]);\n      const kTextInputTypes = new k6BrowserNative.Set([\n        \"\",\n        \"email\",\n        \"number\",\n        \"password\",\n        \"search\",\n        \"tel\",\n        \"text\",\n        \"url\",\n      ]);\n      if (!kTextInputTypes.has(type) && !kDateTypes.has(type)) {\n        return \"error:notfillableinputtype\";\n      }\n      value = value.trim();\n      if (type === \"number\" && isNaN(Number(value))) {\n        return \"error:notfillablenumberinput\";\n      }\n      if (kDateTypes.has(type)) {\n        input.focus();\n        input.value = value;\n        if (input.value !== value) {\n          return \"error:notvaliddate\";\n        }\n        element.dispatchEvent(new Event(\"input\", { bubbles: true }));\n        element.dispatchEvent(new Event(\"change\", { bubbles: true }));\n        return \"done\"; // We have already changed the value, no need to input it.\n      }\n    } else if (element.nodeName.toLowerCase() === \"textarea\") {\n      // Nothing to check here.\n    } else if (!element.isContentEditable) {\n      return \"error:notfillableelement\";\n    }\n    this.selectText(element);\n    return \"needsinput\"; // Still need to input the value.\n  }\n\n  focusNode(node, resetSelectionIfNotFocused) {\n    if (!node.isConnected) {\n      return \"error:notconnected\";\n    }\n    if (node.nodeType !== 1 /*Node.ELEMENT_NODE*/) {\n      return \"error:notelement\";\n    }\n    const wasFocused =\n      node.getRootNode().activeElement === node &&\n      node.ownerDocument &&\n      node.ownerDocument.hasFocus();\n    node.focus();\n    if (\n      resetSelectionIfNotFocused &&\n      !wasFocused &&\n      node.nodeName.toLowerCase() === \"input\"\n    ) {\n      try {\n        node.setSelectionRange(0, 0);\n      } catch (e) {\n        // Some inputs do not allow selection.\n      }\n    }\n    return \"done\";\n  }\n\n  getDocumentElement(node) {\n    const doc = node;\n    if (doc.documentElement && doc.documentElement.ownerDocument === doc) {\n      return doc.documentElement;\n    }\n    return node.ownerDocument ? node.ownerDocument.documentElement : null;\n  }\n\n  isVisible(element) {\n    return isVisible(element);\n  }\n\n  parentElementOrShadowHost(element) {\n    if (element.parentElement) {\n      return element.parentElement;\n    }\n    if (!element.parentNode) {\n      return;\n    }\n    if (\n      element.parentNode.nodeType === 11 /*Node.DOCUMENT_FRAGMENT_NODE*/ &&\n      element.parentNode.host\n    ) {\n      return element.parentNode.host;\n    }\n  }\n\n  previewNode(node) {\n    if (node.nodeType === 3 /*Node.TEXT_NODE*/) {\n      return oneLine(`#text=${node.nodeValue || \"\"}`);\n    }\n    if (node.nodeType !== 1 /*Node.ELEMENT_NODE*/) {\n      return oneLine(`<${node.nodeName.toLowerCase()} />`);\n    }\n    const element = node;\n\n    const attrs = [];\n    for (let i = 0; i < element.attributes.length; i++) {\n      const { name, value } = element.attributes[i];\n      if (name === \"style\") {\n        continue;\n      }\n      if (!value && booleanAttributes.has(name)) {\n        attrs.push(` ${name}`);\n      } else {\n        attrs.push(` ${name}=\"${value}\"`);\n      }\n    }\n    attrs.sort((a, b) => a.length - b.length);\n    let attrText = attrs.join(\"\");\n    if (attrText.length > 50) {\n      attrText = attrText.substring(0, 49) + \"\\u2026\";\n    }\n    if (autoClosingTags.has(element.nodeName)) {\n      return oneLine(`<${element.nodeName.toLowerCase()}${attrText}/>`);\n    }\n\n    const children = element.childNodes;\n    let onlyText = false;\n    if (children.length <= 5) {\n      onlyText = true;\n      for (let i = 0; i < children.length; i++) {\n        onlyText = onlyText && children[i].nodeType === 3 /*Node.TEXT_NODE*/;\n      }\n    }\n    let text = onlyText\n      ? element.textContent || \"\"\n      : children.length\n      ? \"\\u2026\"\n      : \"\";\n    if (text.length > 50) {\n      text = text.substring(0, 49) + \"\\u2026\";\n    }\n    return oneLine(\n      `<${element.nodeName.toLowerCase()}${attrText}>${text}</${element.nodeName.toLowerCase()}>`\n    );\n  }\n\n  querySelector(selector, strict, root) {\n    if (!root[\"querySelector\"]) {\n      return \"error:notqueryablenode\";\n    }\n    const result = this._querySelectorRecursively(\n      [{ element: root, capture: undefined }],\n      selector,\n      0,\n      new k6BrowserNative.Map()\n    );\n    if (strict && result.length > 1) {\n      throw \"error:strictmodeviolation\";\n    }\n    if (result.length == 0) {\n      return null;\n    }\n    return result[0].capture || result[0].element;\n  }\n\n  querySelectorAll(selector, root) {\n    if (!root[\"querySelectorAll\"]) {\n      return \"error:notqueryablenode\";\n    }\n    const result = this._querySelectorRecursively(\n      [{ element: root, capture: undefined }],\n      selector,\n      0,\n      new k6BrowserNative.Map()\n    );\n    const set = new k6BrowserNative.Set();\n    for (const r of result) {\n      set.add(r.capture || r.element);\n    }\n    return [...set];\n  }\n\n  selectOptions(node, optionsToSelect) {\n    const element = this._retarget(node, \"follow-label\");\n    if (!element) {\n      return \"error:notconnected\";\n    }\n    if (element.nodeName.toLowerCase() !== \"select\") {\n      return \"error:notselect\";\n    }\n    const select = element;\n    const options = Array.from(select.options);\n    const selectedOptions = [];\n    let remainingOptionsToSelect = optionsToSelect.slice();\n    for (let index = 0; index < options.length; index++) {\n      const option = options[index];\n      const filter = (optionToSelect) => {\n        if (optionToSelect instanceof Node) {\n          return option === optionToSelect;\n        }\n        let matches = true;\n        if (\n          optionToSelect.value !== undefined &&\n          optionToSelect.value !== null\n        ) {\n          matches = matches && optionToSelect.value === option.value;\n        }\n        if (\n          optionToSelect.label !== undefined &&\n          optionToSelect.label !== null\n        ) {\n          matches = matches && optionToSelect.label === option.label;\n        }\n        if (\n          optionToSelect.index !== undefined &&\n          optionToSelect.index !== null\n        ) {\n          matches = matches && optionToSelect.index === index;\n        }\n        return matches;\n      };\n      if (!remainingOptionsToSelect.some(filter)) {\n        continue;\n      }\n      selectedOptions.push(option);\n      if (select.multiple) {\n        remainingOptionsToSelect = remainingOptionsToSelect.filter(\n          (o) => !filter(o)\n        );\n      } else {\n        remainingOptionsToSelect = [];\n        break;\n      }\n    }\n    /*if (remainingOptionsToSelect.length) {\n            return continuePolling;\n        }*/\n    select.value = undefined;\n    selectedOptions.forEach((option) => (option.selected = true));\n    select.dispatchEvent(new Event(\"input\", { bubbles: true }));\n    select.dispatchEvent(new Event(\"change\", { bubbles: true }));\n    return selectedOptions.map((option) => option.value);\n  }\n\n  selectText(node) {\n    const element = this._retarget(node, \"follow-label\");\n    if (!element) {\n      return \"error:notconnected\";\n    }\n    if (element.nodeName.toLowerCase() === \"input\") {\n      const input = element;\n      input.select();\n      input.focus();\n      return \"done\";\n    }\n    if (element.nodeName.toLowerCase() === \"textarea\") {\n      const textarea = element;\n      textarea.selectionStart = 0;\n      textarea.selectionEnd = textarea.value.length;\n      textarea.focus();\n      return \"done\";\n    }\n    const range = element.ownerDocument.createRange();\n    range.selectNodeContents(element);\n    const selection = element.ownerDocument.defaultView.getSelection();\n    if (selection) {\n      selection.removeAllRanges();\n      selection.addRange(range);\n    }\n    element.focus();\n    return \"done\";\n  }\n\n  async waitForPredicateFunction(predicateFn, polling, timeout, ...args) {\n    let timedOut = false;\n    let timeoutPoll = null;\n    const predicate = () => {\n      return predicateFn(...args) || continuePolling;\n    };\n    if (timeout !== undefined || timeout !== null) {\n      setTimeout(() => {\n        timedOut = true;\n        if (timeoutPoll) timeoutPoll();\n      }, timeout);\n    }\n    if (polling === \"raf\") return await pollRaf();\n    if (polling === \"mutation\") return await pollMutation();\n    if (typeof polling === \"number\") return await pollInterval(polling);\n\n    async function pollMutation() {\n      const success = predicate();\n      if (success !== continuePolling) return Promise.resolve(success);\n\n      let resolve, reject;\n      const result = new Promise((res, rej) => {\n        resolve = res;\n        reject = rej;\n      });\n      try {\n        const observer = new MutationObserver(async () => {\n          if (timedOut) {\n            observer.disconnect();\n            reject(`timed out after ${timeout}ms`);\n          }\n          const success = predicate();\n          if (success !== continuePolling) {\n            observer.disconnect();\n            resolve(success);\n          }\n        });\n        timeoutPoll = () => {\n          observer.disconnect();\n          reject(`timed out after ${timeout}ms`);\n        };\n        observer.observe(document, {\n          childList: true,\n          subtree: true,\n          attributes: true,\n        });\n      } catch(error) {\n        reject(error);\n        return;\n      }\n      return result;\n    }\n\n    async function pollRaf() {\n      let resolve, reject;\n      const result = new Promise((res, rej) => {\n        resolve = res;\n        reject = rej;\n      });\n      await onRaf();\n      return result;\n\n      async function onRaf() {\n        try {\n          if (timedOut) {\n            reject(`timed out after ${timeout}ms`);\n            return;\n          }\n          const success = predicate();\n          if (success !== continuePolling) {\n            resolve(success);\n            return\n          } else {\n            requestAnimationFrame(onRaf);\n          }\n        } catch (error) {\n          reject(error);\n          return;\n        }\n      }\n    }\n\n    async function pollInterval(pollInterval) {\n      let resolve, reject;\n      const result = new Promise((res, rej) => {\n        resolve = res;\n        reject = rej;\n      });\n      await onTimeout();\n      return result;\n\n      async function onTimeout() {\n        try{\n          if (timedOut) {\n            reject(`timed out after ${timeout}ms`);\n            return;\n          }\n          const success = predicate();\n          if (success !== continuePolling) resolve(success);\n          else setTimeout(onTimeout, pollInterval);\n        } catch(error) {\n          reject(error);\n          return;\n        }\n      }\n    }\n  }\n\n  waitForElementStates(node, states=[], timeout, ...args) {\n    let lastRect = undefined;\n    let counter = 0;\n    let samePositionCounter = 0;\n\n    const predicate = () => {\n      if (states.includes(\"stable\")) {\n        const element = this._retarget(node, \"no-follow-label\");\n        if (!element) {\n          return \"error:notconnected\";\n        }\n\n        // First raf happens in the same animation frame as evaluation, so it does not produce\n        // any client rect difference compared to synchronous call. We skip the synchronous call\n        // and only force layout during actual rafs as a small optimisation.\n        if (++counter === 1) {\n          return continuePolling;\n        }\n\n        const clientRect = element.getBoundingClientRect();\n        const rect = {\n          x: clientRect.top,\n          y: clientRect.left,\n          width: clientRect.width,\n          height: clientRect.height,\n        };\n        const samePosition =\n          lastRect &&\n          rect.x === lastRect.x &&\n          rect.y === lastRect.y &&\n          rect.width === lastRect.width &&\n          rect.height === lastRect.height;\n        if (samePosition) {\n          ++samePositionCounter;\n        } else {\n          samePositionCounter = 0;\n        }\n        const isStable = samePositionCounter >= this._stableRafCount;\n        const isStableForLogs = isStable || !lastRect;\n        lastRect = rect;\n        if (!isStable) {\n          return continuePolling;\n        }\n      }\n\n      for (const state of states) {\n        if (state !== \"stable\") {\n          const result = this.checkElementState(node, state);\n          if (typeof result !== \"boolean\") {\n            return result;\n          }\n          if (!result) {\n            return continuePolling;\n          }\n          continue;\n        }\n      }\n\n      return true; // All states are good!\n    };\n\n    if (this._replaceRafWithTimeout) {\n      return this.waitForPredicateFunction(predicate, 16, timeout, ...args);\n    } else {\n      return this.waitForPredicateFunction(predicate, \"raf\", timeout, ...args);\n    }\n  }\n\n  waitForSelector(selector, root, strict, state, polling, timeout, ...args) {\n    let lastElement;\n    const predicate = () => {\n      const elements = this.querySelectorAll(selector, root || document);\n      const element = elements[0];\n      const visible = element ? isVisible(element) : false;\n\n      if (lastElement !== element) {\n        lastElement = element;\n        if (!element) {\n          // assume that the element is not attached.\n          console.debug(`'${selector.selector}' did not match any elements with state '${state}'`);\n        } else {\n          if (elements.length > 1) {\n            if (strict) {\n              throw \"error:strictmodeviolation\";\n            }\n          }\n        }\n      }\n\n      switch (state) {\n        case \"attached\":\n          return element ? element : continuePolling;\n        case \"detached\":\n          return !element ? true : continuePolling;\n        case \"visible\":\n          return visible ? element : continuePolling;\n        case \"hidden\":\n          return !visible ? element : continuePolling;\n      }\n    };\n\n    return this.waitForPredicateFunction(predicate, polling, timeout, ...args);\n  }\n\n  count(selector, root) {\n    const elements = this.querySelectorAll(selector, root || document);\n    return elements.length;\n  }\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/query_all.js",
    "content": "/**\n * Finds all elements in a given scope.\n * @param {Node} scope - The scope of searching. It can be a node.\n *                       By default, it is document.\n * @param {InjectedScript} injected - Injected script.\n * @param {string} selector - XPath or CSS selector string.\n * @returns {Set<Node>|string} - A set of nodes found or an error string.\n */\nfunction QueryAll(scope = document, injected, selector) {\n  return injected.querySelectorAll(selector, scope);\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/scroll_into_view.js",
    "content": "/**\n * Scrolls an element into view.\n * @param {Node} node - The element to scroll into.\n * @param {ScrollIntoViewOptions} options.\n * @returns {void}\n */\nfunction scrollIntoView(node, options) {\n  // we can only scroll to element nodes\n  if (node.nodeType !== Node.ELEMENT_NODE) {\n    return;\n  }\n  node.scrollIntoView(options);\n}"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/selectors.go",
    "content": "package js\n\nimport (\n\t_ \"embed\"\n)\n\n// QueryAll queries all the elements in a given scope (document by default).\n//\n//go:embed query_all.js\nvar QueryAll string\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/web_vital_iife.js",
    "content": "var webVitals=function(e){\"use strict\";var n,t,r,i,o,a=-1,c=function(e){addEventListener(\"pageshow\",(function(n){n.persisted&&(a=n.timeStamp,e(n))}),!0)},u=function(){return window.performance&&performance.getEntriesByType&&performance.getEntriesByType(\"navigation\")[0]},s=function(){var e=u();return e&&e.activationStart||0},f=function(e,n){var t=u(),r=\"navigate\";return a>=0?r=\"back-forward-cache\":t&&(r=document.prerendering||s()>0?\"prerender\":document.wasDiscarded?\"restore\":t.type.replace(/_/g,\"-\")),{name:e,value:void 0===n?-1:n,rating:\"good\",delta:0,entries:[],id:\"v3-\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:r}},d=function(e,n,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){var r=new PerformanceObserver((function(e){Promise.resolve().then((function(){n(e.getEntries())}))}));return r.observe(Object.assign({type:e,buffered:!0},t||{})),r}}catch(e){}},l=function(e,n,t,r){var i,o;return function(a){n.value>=0&&(a||r)&&((o=n.value-(i||0))||void 0===i)&&(i=n.value,n.delta=o,n.rating=function(e,n){return e>n[1]?\"poor\":e>n[0]?\"needs-improvement\":\"good\"}(n.value,t),e(n))}},v=function(e){requestAnimationFrame((function(){return requestAnimationFrame((function(){return e()}))}))},p=function(e){var n=function(n){\"pagehide\"!==n.type&&\"hidden\"!==document.visibilityState||e(n)};addEventListener(\"visibilitychange\",n,!0),addEventListener(\"pagehide\",n,!0)},m=function(e){var n=!1;return function(t){n||(e(t),n=!0)}},h=-1,g=function(){return\"hidden\"!==document.visibilityState||document.prerendering?1/0:0},T=function(e){\"hidden\"===document.visibilityState&&h>-1&&(h=\"visibilitychange\"===e.type?e.timeStamp:0,C())},y=function(){addEventListener(\"visibilitychange\",T,!0),addEventListener(\"prerenderingchange\",T,!0)},C=function(){removeEventListener(\"visibilitychange\",T,!0),removeEventListener(\"prerenderingchange\",T,!0)},E=function(){return h<0&&(h=g(),y(),c((function(){setTimeout((function(){h=g(),y()}),0)}))),{get firstHiddenTime(){return h}}},L=function(e){document.prerendering?addEventListener(\"prerenderingchange\",(function(){return e()}),!0):e()},b=[1800,3e3],S=function(e,n){n=n||{},L((function(){var t,r=E(),i=f(\"FCP\"),o=d(\"paint\",(function(e){e.forEach((function(e){\"first-contentful-paint\"===e.name&&(o.disconnect(),e.startTime<r.firstHiddenTime&&(i.value=Math.max(e.startTime-s(),0),i.entries.push(e),t(!0)))}))}));o&&(t=l(e,i,b,n.reportAllChanges),c((function(r){i=f(\"FCP\"),t=l(e,i,b,n.reportAllChanges),v((function(){i.value=performance.now()-r.timeStamp,t(!0)}))})))}))},w=[.1,.25],P=function(e,n){n=n||{},S(m((function(){var t,r=f(\"CLS\",0),i=0,o=[],a=function(e){e.forEach((function(e){if(!e.hadRecentInput){var n=o[0],t=o[o.length-1];i&&e.startTime-t.startTime<1e3&&e.startTime-n.startTime<5e3?(i+=e.value,o.push(e)):(i=e.value,o=[e])}})),i>r.value&&(r.value=i,r.entries=o,t())},u=d(\"layout-shift\",a);u&&(t=l(e,r,w,n.reportAllChanges),p((function(){a(u.takeRecords()),t(!0)})),c((function(){i=0,r=f(\"CLS\",0),t=l(e,r,w,n.reportAllChanges),v((function(){return t()}))})),setTimeout(t,0))})))},F={passive:!0,capture:!0},I=new Date,A=function(e,i){n||(n=i,t=e,r=new Date,k(removeEventListener),M())},M=function(){if(t>=0&&t<r-I){var e={entryType:\"first-input\",name:n.type,target:n.target,cancelable:n.cancelable,startTime:n.timeStamp,processingStart:n.timeStamp+t};i.forEach((function(n){n(e)})),i=[]}},D=function(e){if(e.cancelable){var n=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;\"pointerdown\"==e.type?function(e,n){var t=function(){A(e,n),i()},r=function(){i()},i=function(){removeEventListener(\"pointerup\",t,F),removeEventListener(\"pointercancel\",r,F)};addEventListener(\"pointerup\",t,F),addEventListener(\"pointercancel\",r,F)}(n,e):A(n,e)}},k=function(e){[\"mousedown\",\"keydown\",\"touchstart\",\"pointerdown\"].forEach((function(n){return e(n,D,F)}))},B=[100,300],x=function(e,r){r=r||{},L((function(){var o,a=E(),u=f(\"FID\"),s=function(e){e.startTime<a.firstHiddenTime&&(u.value=e.processingStart-e.startTime,u.entries.push(e),o(!0))},v=function(e){e.forEach(s)},h=d(\"first-input\",v);o=l(e,u,B,r.reportAllChanges),h&&p(m((function(){v(h.takeRecords()),h.disconnect()}))),h&&c((function(){var a;u=f(\"FID\"),o=l(e,u,B,r.reportAllChanges),i=[],t=-1,n=null,k(addEventListener),a=s,i.push(a),M()}))}))},N=0,R=1/0,H=0,O=function(e){e.forEach((function(e){e.interactionId&&(R=Math.min(R,e.interactionId),H=Math.max(H,e.interactionId),N=H?(H-R)/7+1:0)}))},_=function(){return o?N:performance.interactionCount||0},j=function(){\"interactionCount\"in performance||o||(o=d(\"event\",O,{type:\"event\",buffered:!0,durationThreshold:0}))},q=[200,500],V=0,z=function(){return _()-V},G=[],J={},K=function(e){var n=G[G.length-1],t=J[e.interactionId];if(t||G.length<10||e.duration>n.latency){if(t)t.entries.push(e),t.latency=Math.max(t.latency,e.duration);else{var r={id:e.interactionId,latency:e.duration,entries:[e]};J[r.id]=r,G.push(r)}G.sort((function(e,n){return n.latency-e.latency})),G.splice(10).forEach((function(e){delete J[e.id]}))}},Q=function(e,n){n=n||{},L((function(){j();var t,r=f(\"INP\"),i=function(e){e.forEach((function(e){(e.interactionId&&K(e),\"first-input\"===e.entryType)&&(!G.some((function(n){return n.entries.some((function(n){return e.duration===n.duration&&e.startTime===n.startTime}))}))&&K(e))}));var n,i=(n=Math.min(G.length-1,Math.floor(z()/50)),G[n]);i&&i.latency!==r.value&&(r.value=i.latency,r.entries=i.entries,t())},o=d(\"event\",i,{durationThreshold:n.durationThreshold||40});t=l(e,r,q,n.reportAllChanges),o&&(o.observe({type:\"first-input\",buffered:!0}),p((function(){i(o.takeRecords()),r.value<0&&z()>0&&(r.value=0,r.entries=[]),t(!0)})),c((function(){G=[],V=_(),r=f(\"INP\"),t=l(e,r,q,n.reportAllChanges)})))}))},U=[2500,4e3],W={},X=function(e,n){n=n||{},L((function(){var t,r=E(),i=f(\"LCP\"),o=function(e){var n=e[e.length-1];n&&n.startTime<r.firstHiddenTime&&(i.value=Math.max(n.startTime-s(),0),i.entries=[n],t())},a=d(\"largest-contentful-paint\",o);if(a){t=l(e,i,U,n.reportAllChanges);var u=m((function(){W[i.id]||(o(a.takeRecords()),a.disconnect(),W[i.id]=!0,t(!0))}));[\"keydown\",\"click\"].forEach((function(e){addEventListener(e,u,!0)})),p(u),c((function(r){i=f(\"LCP\"),t=l(e,i,U,n.reportAllChanges),v((function(){i.value=performance.now()-r.timeStamp,W[i.id]=!0,t(!0)}))}))}}))},Y=[800,1800],Z=function e(n){document.prerendering?L((function(){return e(n)})):\"complete\"!==document.readyState?addEventListener(\"load\",(function(){return e(n)}),!0):setTimeout(n,0)},$=function(e,n){n=n||{};var t=f(\"TTFB\"),r=l(e,t,Y,n.reportAllChanges);Z((function(){var i=u();if(i){var o=i.responseStart;if(o<=0||o>performance.now())return;t.value=Math.max(o-s(),0),t.entries=[i],r(!0),c((function(){t=f(\"TTFB\",0),(r=l(e,t,Y,n.reportAllChanges))(!0)}))}}))};return e.CLSThresholds=w,e.FCPThresholds=b,e.FIDThresholds=B,e.INPThresholds=q,e.LCPThresholds=U,e.TTFBThresholds=Y,e.getCLS=P,e.getFCP=S,e.getFID=x,e.getINP=Q,e.getLCP=X,e.getTTFB=$,e.onCLS=P,e.onFCP=S,e.onFID=x,e.onINP=Q,e.onLCP=X,e.onTTFB=$,Object.defineProperty(e,\"__esModule\",{value:!0}),e}({});"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js/web_vital_init.js",
    "content": "function print(metric) {\n  const m = {\n    id: metric.id,\n    name: metric.name,\n    value: metric.value,\n    rating: metric.rating,\n    delta: metric.delta,\n    numEntries: metric.entries.length,\n    navigationType: metric.navigationType,\n    url: window.location.href,\n    // To be able to associate a Web Vital measurement to the PageNavigation\n    // span, we need to collect the span ID that was previously set in the\n    // page after the navigation, and pass it back to k6 browser included in\n    // the WV event so the measurement can be correctly linked to the page\n    // navigation span\n    spanID: window.k6SpanId,\n  }\n  window.k6browserSendWebVitalMetric(JSON.stringify(m))\n}\n\nfunction load() {\n  webVitals.onCLS(print);\n  webVitals.onFID(print);\n  webVitals.onLCP(print);\n\n  webVitals.onFCP(print);\n  webVitals.onINP(print);\n  webVitals.onTTFB(print);\n}\n\nload();\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/js_handle.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// JSHandleAPI is the interface of an in-page JS object.\n//\n// TODO: Find a way to move this to a concrete type. It's too difficult to\n// do that right now because of the tests and the way we're using the\n// JSHandleAPI interface.\ntype JSHandleAPI interface {\n\tAsElement() *ElementHandle\n\tDispose() error\n\tEvaluate(pageFunc string, args ...any) (any, error)\n\tEvaluateHandle(pageFunc string, args ...any) (JSHandleAPI, error)\n\tGetProperties() (map[string]JSHandleAPI, error)\n\tJSONValue() (string, error)\n\tObjectID() runtime.RemoteObjectID\n}\n\ntype jsHandle interface {\n\tJSHandleAPI\n\tdispose() error\n\tgetProperties() (map[string]jsHandle, error)\n}\n\n// BaseJSHandle represents a JS object in an execution context.\ntype BaseJSHandle struct {\n\tctx          context.Context\n\tlogger       *log.Logger\n\tsession      session\n\texecCtx      *ExecutionContext\n\tremoteObject *runtime.RemoteObject\n\tdisposed     bool\n}\n\n// String returns a string repesentation of BaseJSHandle.\n// It exists mostly for debugging where we don't want fmt.Sprintf to just\n// go through a complex object and try to stringify it.\nfunc (h *BaseJSHandle) String() string {\n\treturn \"BaseJSHandle{ \" +\n\t\t\"SessionID: \" + h.session.ID().String() + \", \" +\n\t\t\"dispose: \" + strconv.FormatBool(h.disposed) +\n\t\t\"}\"\n}\n\n// NewJSHandle creates a new JS handle referencing a remote object.\nfunc NewJSHandle(\n\tctx context.Context,\n\ts session,\n\tectx *ExecutionContext,\n\tf *Frame,\n\tro *runtime.RemoteObject,\n\tl *log.Logger,\n) jsHandle {\n\teh := &BaseJSHandle{\n\t\tctx:          ctx,\n\t\tsession:      s,\n\t\texecCtx:      ectx,\n\t\tremoteObject: ro,\n\t\tdisposed:     false,\n\t\tlogger:       l,\n\t}\n\n\tif ro.Subtype == \"node\" && ectx.Frame() != nil {\n\t\treturn &ElementHandle{\n\t\t\tBaseJSHandle: *eh,\n\t\t\tframe:        f,\n\t\t}\n\t}\n\n\treturn eh\n}\n\n// AsElement returns an element handle if this JSHandle is a reference to a JS HTML element.\nfunc (h *BaseJSHandle) AsElement() *ElementHandle {\n\treturn nil\n}\n\n// Dispose releases the remote object.\nfunc (h *BaseJSHandle) Dispose() error {\n\terr := h.dispose()\n\tif err == nil { // no error\n\t\treturn nil\n\t}\n\n\t// We do not want to return an error when the error is a closed\n\t// context. The reason the context would be closed is due to the\n\t// iteration ending and therefore the associated browser and its assets\n\t// will be automatically deleted.\n\tif errors.Is(err, context.Canceled) {\n\t\th.logger.Debugf(\"BaseJSHandle:Dispose\", \"%v\", err)\n\t\treturn nil\n\t}\n\t// The following error indicates that the object we're trying to release\n\t// cannot be found, which would mean that the object has already been\n\t// removed/deleted. This can occur when a navigation occurs, usually when\n\t// a page contains an iframe.\n\tif strings.Contains(err.Error(), \"Cannot find context with specified id\") {\n\t\th.logger.Debugf(\"BaseJSHandle:Dispose\", \"%v\", err)\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"disposing element with ID %s: %w\", h.remoteObject.ObjectID, err)\n}\n\n// dispose sends a command to the browser to release the remote object.\nfunc (h *BaseJSHandle) dispose() error {\n\tif h.disposed {\n\t\treturn nil\n\t}\n\th.disposed = true\n\tif h.remoteObject.ObjectID == \"\" {\n\t\treturn nil\n\t}\n\tact := runtime.ReleaseObject(h.remoteObject.ObjectID)\n\tif err := act.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {\n\t\treturn fmt.Errorf(\"disposing element with ID %s: %w\",\n\t\t\th.remoteObject.ObjectID, err)\n\t}\n\n\treturn nil\n}\n\n// Evaluate will evaluate provided page function within an execution context.\nfunc (h *BaseJSHandle) Evaluate(pageFunc string, args ...any) (any, error) {\n\targs = append([]any{h}, args...)\n\tres, err := h.execCtx.Eval(h.ctx, pageFunc, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating element: %w\", err)\n\t}\n\n\treturn res, nil\n}\n\n// EvaluateHandle will evaluate provided page function within an execution context.\nfunc (h *BaseJSHandle) EvaluateHandle(pageFunc string, args ...any) (JSHandleAPI, error) {\n\targs = append([]any{h}, args...)\n\teh, err := h.execCtx.EvalHandle(h.ctx, pageFunc, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating handle for element: %w\", err)\n\t}\n\n\treturn eh, nil\n}\n\n// GetProperties retreives the JS handle's properties.\nfunc (h *BaseJSHandle) GetProperties() (map[string]JSHandleAPI, error) {\n\thandles, err := h.getProperties()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tjsHandles := make(map[string]JSHandleAPI, len(handles))\n\tfor k, v := range handles {\n\t\tjsHandles[k] = v\n\t}\n\n\treturn jsHandles, nil\n}\n\n// getProperties is like GetProperties, but does not panic.\nfunc (h *BaseJSHandle) getProperties() (map[string]jsHandle, error) {\n\tact := runtime.GetProperties(h.remoteObject.ObjectID).WithOwnProperties(true)\n\tresult, _, _, _, err := act.Do(cdp.WithExecutor(h.ctx, h.session)) //nolint:dogsled\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting properties for element with ID %s: %w\",\n\t\t\th.remoteObject.ObjectID, err)\n\t}\n\n\tprops := make(map[string]jsHandle, len(result))\n\tfor _, r := range result {\n\t\tif !r.Enumerable {\n\t\t\tcontinue\n\t\t}\n\t\tprops[r.Name] = NewJSHandle(h.ctx, h.session, h.execCtx, h.execCtx.Frame(), r.Value, h.logger)\n\t}\n\n\treturn props, nil\n}\n\n// JSONValue returns a JSON version of this JS handle.\nfunc (h *BaseJSHandle) JSONValue() (string, error) {\n\tremoteObject := h.remoteObject\n\tif remoteObject.ObjectID != \"\" {\n\t\tvar err error\n\t\taction := runtime.CallFunctionOn(\"function() { return this; }\").\n\t\t\tWithReturnByValue(true).\n\t\t\tWithAwaitPromise(true).\n\t\t\tWithObjectID(h.remoteObject.ObjectID)\n\t\tif remoteObject, _, err = action.Do(cdp.WithExecutor(h.ctx, h.session)); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"retrieving json value: %w\", err)\n\t\t}\n\t}\n\n\tres, err := parseConsoleRemoteObject(h.logger, remoteObject)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"extracting json value (remote object id: %v): %w\", remoteObject.ObjectID, err)\n\t}\n\n\treturn res, nil\n}\n\n// ObjectID returns the remote object ID.\nfunc (h *BaseJSHandle) ObjectID() runtime.RemoteObjectID {\n\treturn h.remoteObject.ObjectID\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/keyboard.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/input\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/keyboardlayout\"\n)\n\nconst (\n\tModifierKeyAlt int64 = 1 << iota\n\tModifierKeyControl\n\tModifierKeyMeta\n\tModifierKeyShift\n)\n\n// KeyboardOptions represents the options for the keyboard.\ntype KeyboardOptions struct {\n\tDelay int64 `json:\"delay\"`\n}\n\n// Keyboard represents a keyboard input device.\n// Each Page has a publicly accessible Keyboard.\ntype Keyboard struct {\n\tctx     context.Context\n\tsession session\n\n\tmodifiers     int64              // like shift, alt, ctrl, ...\n\tpressedKeys   map[int64]struct{} // tracks keys through down() and up()\n\tpressedKeysMu sync.Mutex\n\tlayoutName    string // us by default\n\tlayout        keyboardlayout.KeyboardLayout\n}\n\n// NewKeyboard returns a new keyboard with a \"us\" layout.\nfunc NewKeyboard(ctx context.Context, s session) *Keyboard {\n\treturn &Keyboard{\n\t\tctx:         ctx,\n\t\tsession:     s,\n\t\tpressedKeys: make(map[int64]struct{}),\n\t\tlayoutName:  \"us\",\n\t\tlayout:      keyboardlayout.GetKeyboardLayout(\"us\"),\n\t}\n}\n\n// Down sends a key down message to a session target.\nfunc (k *Keyboard) Down(key string) error {\n\tif err := k.down(key); err != nil {\n\t\treturn fmt.Errorf(\"sending key down: %w\", err)\n\t}\n\treturn nil\n}\n\n// Up sends a key up message to a session target.\nfunc (k *Keyboard) Up(key string) error {\n\tif err := k.up(key); err != nil {\n\t\treturn fmt.Errorf(\"sending key up: %w\", err)\n\t}\n\treturn nil\n}\n\n// Press sends a key press message to a session target.\n// It delays the action if `Delay` option is specified.\n// A press message consists of successive key down and up messages.\nfunc (k *Keyboard) Press(key string, kbdOpts KeyboardOptions) error {\n\tif err := k.comboPress(key, kbdOpts); err != nil {\n\t\treturn fmt.Errorf(\"pressing key: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// InsertText inserts a text without dispatching key events.\nfunc (k *Keyboard) InsertText(text string) error {\n\tif err := k.insertText(text); err != nil {\n\t\treturn fmt.Errorf(\"inserting text: %w\", err)\n\t}\n\treturn nil\n}\n\n// Type sends a press message to a session target for each character in text.\n// It delays the action if `Delay` option is specified.\n//\n// It sends an insertText message if a character is not among\n// valid characters in the keyboard's layout.\nfunc (k *Keyboard) Type(text string, kbdOpts KeyboardOptions) error {\n\tif err := k.typ(text, kbdOpts); err != nil {\n\t\treturn fmt.Errorf(\"typing text: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (k *Keyboard) down(key string) error {\n\tkey = k.platformSpecificResolution(key)\n\n\tkeyInput := keyboardlayout.KeyInput(key)\n\tif _, ok := k.layout.ValidKeys[keyInput]; !ok {\n\t\treturn fmt.Errorf(\"%q is not a valid key for layout %q\", key, k.layoutName)\n\t}\n\n\tkeyDef := k.keyDefinitionFromKey(keyInput)\n\tk.modifiers |= k.modifierBitFromKeyName(keyDef.Key)\n\ttext := keyDef.Text\n\n\tk.pressedKeysMu.Lock()\n\t_, autoRepeat := k.pressedKeys[keyDef.KeyCode]\n\tk.pressedKeys[keyDef.KeyCode] = struct{}{}\n\tk.pressedKeysMu.Unlock()\n\n\tkeyType := input.KeyDown\n\tif text == \"\" {\n\t\tkeyType = input.KeyRawDown\n\t}\n\n\taction := input.DispatchKeyEvent(keyType).\n\t\tWithModifiers(input.Modifier(k.modifiers)).\n\t\tWithKey(keyDef.Key).\n\t\tWithWindowsVirtualKeyCode(keyDef.KeyCode).\n\t\tWithCode(keyDef.Code).\n\t\tWithLocation(keyDef.Location).\n\t\tWithIsKeypad(keyDef.Location == 3).\n\t\tWithText(text).\n\t\tWithUnmodifiedText(text).\n\t\tWithAutoRepeat(autoRepeat)\n\tif err := action.Do(cdp.WithExecutor(k.ctx, k.session)); err != nil {\n\t\treturn fmt.Errorf(\"dispatching key event down: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *Keyboard) up(key string) error {\n\tkey = k.platformSpecificResolution(key)\n\n\tkeyInput := keyboardlayout.KeyInput(key)\n\tif _, ok := k.layout.ValidKeys[keyInput]; !ok {\n\t\treturn fmt.Errorf(\"'%s' is not a valid key for layout '%s'\", key, k.layoutName)\n\t}\n\n\tkeyDef := k.keyDefinitionFromKey(keyInput)\n\tk.modifiers &= ^k.modifierBitFromKeyName(keyDef.Key)\n\tk.pressedKeysMu.Lock()\n\tdelete(k.pressedKeys, keyDef.KeyCode)\n\tk.pressedKeysMu.Unlock()\n\n\taction := input.DispatchKeyEvent(input.KeyUp).\n\t\tWithModifiers(input.Modifier(k.modifiers)).\n\t\tWithKey(keyDef.Key).\n\t\tWithWindowsVirtualKeyCode(keyDef.KeyCode).\n\t\tWithCode(keyDef.Code).\n\t\tWithLocation(keyDef.Location)\n\tif err := action.Do(cdp.WithExecutor(k.ctx, k.session)); err != nil {\n\t\treturn fmt.Errorf(\"dispatching key event up: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (k *Keyboard) insertText(text string) error {\n\taction := input.InsertText(text)\n\tif err := action.Do(cdp.WithExecutor(k.ctx, k.session)); err != nil {\n\t\treturn fmt.Errorf(\"inserting text: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (k *Keyboard) keyDefinitionFromKey(key keyboardlayout.KeyInput) keyboardlayout.KeyDefinition {\n\tshift := k.modifiers & ModifierKeyShift\n\n\t// Find directly from the keyboard layout\n\tsrcKeyDef, ok := k.layout.Keys[key]\n\t// Try to find based on key value instead of code\n\tif !ok {\n\t\tsrcKeyDef, ok = k.layout.KeyDefinition(key)\n\t}\n\t// Try to find with the shift key value\n\t// e.g. for `@`, the shift modifier needs to\n\t// be used.\n\tvar foundInShift bool\n\tif !ok {\n\t\tsrcKeyDef = k.layout.ShiftKeyDefinition(key)\n\t\tshift = k.modifiers | ModifierKeyShift\n\t\tfoundInShift = true\n\t}\n\n\tvar keyDef keyboardlayout.KeyDefinition\n\tkeyDef.Code = srcKeyDef.Code\n\tif srcKeyDef.Key != \"\" {\n\t\tkeyDef.Key = srcKeyDef.Key\n\t}\n\tif len(srcKeyDef.Key) == 1 {\n\t\tkeyDef.Text = srcKeyDef.Key\n\t}\n\tif shift != 0 && srcKeyDef.ShiftKeyCode != 0 {\n\t\tkeyDef.KeyCode = srcKeyDef.ShiftKeyCode\n\t}\n\tif srcKeyDef.KeyCode != 0 {\n\t\tkeyDef.KeyCode = srcKeyDef.KeyCode\n\t}\n\tif srcKeyDef.Location != 0 {\n\t\tkeyDef.Location = srcKeyDef.Location\n\t}\n\tif srcKeyDef.Text != \"\" {\n\t\tkeyDef.Text = srcKeyDef.Text\n\t}\n\t// Shift is only used on keys which are `KeyX`` (where X is\n\t// A-Z), or on keys which require shift to be pressed e.g.\n\t// `@`, and shift must be pressed as well as a shiftKey\n\t// text value present for the key.\n\t// Not all keys have a text value when shift is pressed\n\t// e.g. `Control`.\n\t// When a key such as `2` is pressed, we must ignore shift\n\t// otherwise we would type `@`.\n\tisKeyXOrOnShiftLayerAndShiftUsed := (strings.HasPrefix(string(key), \"Key\") || foundInShift) &&\n\t\tshift != 0 &&\n\t\tsrcKeyDef.ShiftKey != \"\"\n\tif isKeyXOrOnShiftLayerAndShiftUsed {\n\t\tkeyDef.Key = srcKeyDef.ShiftKey\n\t\tkeyDef.Text = srcKeyDef.ShiftKey\n\t}\n\t// If any modifiers besides shift are pressed, no text should be sent\n\tif k.modifiers & ^ModifierKeyShift != 0 {\n\t\tkeyDef.Text = \"\"\n\t}\n\treturn keyDef\n}\n\nfunc (k *Keyboard) modifierBitFromKeyName(key string) int64 {\n\tswitch key {\n\tcase \"Alt\":\n\t\treturn ModifierKeyAlt\n\tcase \"Control\":\n\t\treturn ModifierKeyControl\n\tcase \"Meta\":\n\t\treturn ModifierKeyMeta\n\tcase \"Shift\":\n\t\treturn ModifierKeyShift\n\t}\n\treturn 0\n}\n\nfunc (k *Keyboard) platformSpecificResolution(key string) string {\n\tif key == \"ControlOrMeta\" {\n\t\tif runtime.GOOS == \"darwin\" {\n\t\t\tkey = \"Meta\"\n\t\t} else {\n\t\t\tkey = \"Control\"\n\t\t}\n\t}\n\treturn key\n}\n\nfunc (k *Keyboard) comboPress(keys string, opts KeyboardOptions) error {\n\tif opts.Delay > 0 {\n\t\tif err := wait(k.ctx, opts.Delay); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tkk := split(keys)\n\tfor _, key := range kk {\n\t\tif err := k.down(key); err != nil {\n\t\t\treturn fmt.Errorf(\"cannot do key down: %w\", err)\n\t\t}\n\t}\n\n\tfor i := range kk {\n\t\tkey := kk[len(kk)-i-1]\n\t\tif err := k.up(key); err != nil {\n\t\t\treturn fmt.Errorf(\"cannot do key up: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// This splits the string on `+`.\n// If `+` on it's own is passed, it will return [\"+\"].\n// If `++` is passed in, it will return [\"+\", \"\"].\n// If `+++` is passed in, it will return [\"+\", \"+\"].\nfunc split(keys string) []string {\n\tvar (\n\t\tkk = make([]string, 0)\n\t\ts  strings.Builder\n\t)\n\tfor _, r := range keys {\n\t\tif r == '+' && s.Len() > 0 {\n\t\t\tkk = append(kk, s.String())\n\t\t\ts.Reset()\n\t\t} else {\n\t\t\ts.WriteRune(r)\n\t\t}\n\t}\n\tkk = append(kk, s.String())\n\n\treturn kk\n}\n\nfunc (k *Keyboard) press(key string, opts KeyboardOptions) error {\n\tif opts.Delay > 0 {\n\t\tif err := wait(k.ctx, opts.Delay); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := k.down(key); err != nil {\n\t\treturn fmt.Errorf(\"key down: %w\", err)\n\t}\n\treturn k.up(key)\n}\n\nfunc (k *Keyboard) typ(text string, opts KeyboardOptions) error {\n\tlayout := keyboardlayout.GetKeyboardLayout(k.layoutName)\n\tfor _, c := range text {\n\t\tif opts.Delay > 0 {\n\t\t\tif err := wait(k.ctx, opts.Delay); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tkeyInput := keyboardlayout.KeyInput(c)\n\t\tif _, ok := layout.ValidKeys[keyInput]; ok {\n\t\t\tif err := k.press(string(c), opts); err != nil {\n\t\t\t\treturn fmt.Errorf(\"pressing key: %w\", err)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif err := k.insertText(string(c)); err != nil {\n\t\t\treturn fmt.Errorf(\"inserting text: %w\", err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc wait(ctx context.Context, delay int64) error {\n\tt := time.NewTimer(time.Duration(delay) * time.Millisecond)\n\tselect {\n\tcase <-ctx.Done():\n\t\tif !t.Stop() {\n\t\t\t<-t.C\n\t\t}\n\t\treturn fmt.Errorf(\"%w\", ContextErr(ctx))\n\tcase <-t.C:\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/keyboard_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/keyboardlayout\"\n)\n\nfunc TestSplit(t *testing.T) {\n\tt.Parallel()\n\n\ttype args struct {\n\t\tkeys string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant []string\n\t}{\n\t\t{\n\t\t\tname: \"empty slice on empty string\",\n\t\t\targs: args{\n\t\t\t\tkeys: \"\",\n\t\t\t},\n\t\t\twant: []string{\"\"},\n\t\t},\n\t\t{\n\t\t\tname: \"empty slice on string without separator\",\n\t\t\targs: args{\n\t\t\t\tkeys: \"HelloWorld!\",\n\t\t\t},\n\t\t\twant: []string{\"HelloWorld!\"},\n\t\t},\n\t\t{\n\t\t\tname: \"string split with separator\",\n\t\t\targs: args{\n\t\t\t\tkeys: \"Hello+World+!\",\n\t\t\t},\n\t\t\twant: []string{\"Hello\", \"World\", \"!\"},\n\t\t},\n\t\t{\n\t\t\tname: \"do not split on single +\",\n\t\t\targs: args{\n\t\t\t\tkeys: \"+\",\n\t\t\t},\n\t\t\twant: []string{\"+\"},\n\t\t},\n\t\t{\n\t\t\tname: \"split ++ to + and ''\",\n\t\t\targs: args{\n\t\t\t\tkeys: \"++\",\n\t\t\t},\n\t\t\twant: []string{\"+\", \"\"},\n\t\t},\n\t\t{\n\t\t\tname: \"split +++ to + and +\",\n\t\t\targs: args{\n\t\t\t\tkeys: \"+++\",\n\t\t\t},\n\t\t\twant: []string{\"+\", \"+\"},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgot := split(tt.args.keys)\n\t\t\tassert.Equal(t, tt.want, got)\n\t\t})\n\t}\n}\n\nfunc TestKeyboardPress(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"panics when '' empty key passed in\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\tk := NewKeyboard(vu.Context(), nil)\n\t\trequire.Error(t, k.Press(\"\", KeyboardOptions{}))\n\t})\n}\n\nfunc TestKeyDefinitionCode(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\tvu = k6test.NewVU(t)\n\t\tk  = NewKeyboard(vu.Context(), nil)\n\t)\n\n\ttests := []struct {\n\t\tkey           keyboardlayout.KeyInput\n\t\texpectedCodes []string\n\t}{\n\t\t{key: \"Escape\", expectedCodes: []string{\"Escape\"}},\n\t\t{key: \"F1\", expectedCodes: []string{\"F1\"}},\n\t\t{key: \"F2\", expectedCodes: []string{\"F2\"}},\n\t\t{key: \"F3\", expectedCodes: []string{\"F3\"}},\n\t\t{key: \"F4\", expectedCodes: []string{\"F4\"}},\n\t\t{key: \"F5\", expectedCodes: []string{\"F5\"}},\n\t\t{key: \"F6\", expectedCodes: []string{\"F6\"}},\n\t\t{key: \"F7\", expectedCodes: []string{\"F7\"}},\n\t\t{key: \"F8\", expectedCodes: []string{\"F8\"}},\n\t\t{key: \"F9\", expectedCodes: []string{\"F9\"}},\n\t\t{key: \"F10\", expectedCodes: []string{\"F10\"}},\n\t\t{key: \"F11\", expectedCodes: []string{\"F11\"}},\n\t\t{key: \"F12\", expectedCodes: []string{\"F12\"}},\n\t\t{key: \"`\", expectedCodes: []string{\"Backquote\"}},\n\t\t{key: \"-\", expectedCodes: []string{\"Minus\", \"NumpadSubtract\"}},\n\t\t{key: \"=\", expectedCodes: []string{\"Equal\"}},\n\t\t{key: \"\\\\\", expectedCodes: []string{\"Backslash\"}},\n\t\t{key: \"Backspace\", expectedCodes: []string{\"Backspace\"}},\n\t\t{key: \"Tab\", expectedCodes: []string{\"Tab\"}},\n\t\t{key: \"q\", expectedCodes: []string{\"KeyQ\"}},\n\t\t{key: \"w\", expectedCodes: []string{\"KeyW\"}},\n\t\t{key: \"e\", expectedCodes: []string{\"KeyE\"}},\n\t\t{key: \"r\", expectedCodes: []string{\"KeyR\"}},\n\t\t{key: \"t\", expectedCodes: []string{\"KeyT\"}},\n\t\t{key: \"y\", expectedCodes: []string{\"KeyY\"}},\n\t\t{key: \"u\", expectedCodes: []string{\"KeyU\"}},\n\t\t{key: \"i\", expectedCodes: []string{\"KeyI\"}},\n\t\t{key: \"o\", expectedCodes: []string{\"KeyO\"}},\n\t\t{key: \"p\", expectedCodes: []string{\"KeyP\"}},\n\t\t{key: \"[\", expectedCodes: []string{\"BracketLeft\"}},\n\t\t{key: \"]\", expectedCodes: []string{\"BracketRight\"}},\n\t\t{key: \"CapsLock\", expectedCodes: []string{\"CapsLock\"}},\n\t\t{key: \"a\", expectedCodes: []string{\"KeyA\"}},\n\t\t{key: \"s\", expectedCodes: []string{\"KeyS\"}},\n\t\t{key: \"d\", expectedCodes: []string{\"KeyD\"}},\n\t\t{key: \"f\", expectedCodes: []string{\"KeyF\"}},\n\t\t{key: \"g\", expectedCodes: []string{\"KeyG\"}},\n\t\t{key: \"h\", expectedCodes: []string{\"KeyH\"}},\n\t\t{key: \"j\", expectedCodes: []string{\"KeyJ\"}},\n\t\t{key: \"k\", expectedCodes: []string{\"KeyK\"}},\n\t\t{key: \"l\", expectedCodes: []string{\"KeyL\"}},\n\t\t{key: \";\", expectedCodes: []string{\"Semicolon\"}},\n\t\t{key: \"'\", expectedCodes: []string{\"Quote\"}},\n\t\t{key: \"Shift\", expectedCodes: []string{\"ShiftLeft\", \"ShiftRight\"}},\n\t\t{key: \"z\", expectedCodes: []string{\"KeyZ\"}},\n\t\t{key: \"x\", expectedCodes: []string{\"KeyX\"}},\n\t\t{key: \"c\", expectedCodes: []string{\"KeyC\"}},\n\t\t{key: \"v\", expectedCodes: []string{\"KeyV\"}},\n\t\t{key: \"b\", expectedCodes: []string{\"KeyB\"}},\n\t\t{key: \"n\", expectedCodes: []string{\"KeyN\"}},\n\t\t{key: \"m\", expectedCodes: []string{\"KeyM\"}},\n\t\t{key: \",\", expectedCodes: []string{\"Comma\"}},\n\t\t{key: \"/\", expectedCodes: []string{\"Slash\", \"NumpadDivide\"}},\n\t\t{key: \"Control\", expectedCodes: []string{\"ControlLeft\", \"ControlRight\"}},\n\t\t{key: \"Meta\", expectedCodes: []string{\"MetaLeft\", \"MetaRight\"}},\n\t\t{key: \"Alt\", expectedCodes: []string{\"AltLeft\", \"AltRight\"}},\n\t\t{key: \" \", expectedCodes: []string{\"Space\"}},\n\t\t{key: \"AltGraph\", expectedCodes: []string{\"AltGraph\"}},\n\t\t{key: \"ConTextMenu\", expectedCodes: []string{\"ConTextMenu\"}},\n\t\t{key: \"PrintScreen\", expectedCodes: []string{\"PrintScreen\"}},\n\t\t{key: \"ScrollLock\", expectedCodes: []string{\"ScrollLock\"}},\n\t\t{key: \"Pause\", expectedCodes: []string{\"Pause\"}},\n\t\t{key: \"PageUp\", expectedCodes: []string{\"PageUp\"}},\n\t\t{key: \"PageDown\", expectedCodes: []string{\"PageDown\"}},\n\t\t{key: \"Insert\", expectedCodes: []string{\"Insert\"}},\n\t\t{key: \"Delete\", expectedCodes: []string{\"Delete\"}},\n\t\t{key: \"Home\", expectedCodes: []string{\"Home\"}},\n\t\t{key: \"End\", expectedCodes: []string{\"End\"}},\n\t\t{key: \"ArrowLeft\", expectedCodes: []string{\"ArrowLeft\"}},\n\t\t{key: \"ArrowUp\", expectedCodes: []string{\"ArrowUp\"}},\n\t\t{key: \"ArrowRight\", expectedCodes: []string{\"ArrowRight\"}},\n\t\t{key: \"ArrowDown\", expectedCodes: []string{\"ArrowDown\"}},\n\t\t{key: \"NumLock\", expectedCodes: []string{\"NumLock\"}},\n\t\t{key: \"*\", expectedCodes: []string{\"NumpadMultiply\"}},\n\t\t{key: \"7\", expectedCodes: []string{\"Numpad7\", \"Digit7\"}},\n\t\t{key: \"8\", expectedCodes: []string{\"Numpad8\", \"Digit8\"}},\n\t\t{key: \"9\", expectedCodes: []string{\"Numpad9\", \"Digit9\"}},\n\t\t{key: \"4\", expectedCodes: []string{\"Numpad4\", \"Digit4\"}},\n\t\t{key: \"5\", expectedCodes: []string{\"Numpad5\", \"Digit5\"}},\n\t\t{key: \"6\", expectedCodes: []string{\"Numpad6\", \"Digit6\"}},\n\t\t{key: \"+\", expectedCodes: []string{\"NumpadAdd\"}},\n\t\t{key: \"1\", expectedCodes: []string{\"Numpad1\", \"Digit1\"}},\n\t\t{key: \"2\", expectedCodes: []string{\"Numpad2\", \"Digit2\"}},\n\t\t{key: \"3\", expectedCodes: []string{\"Numpad3\", \"Digit3\"}},\n\t\t{key: \"0\", expectedCodes: []string{\"Numpad0\", \"Digit0\"}},\n\t\t{key: \".\", expectedCodes: []string{\"NumpadDecimal\", \"Period\"}},\n\t\t{key: \"Enter\", expectedCodes: []string{\"NumpadEnter\", \"Enter\"}},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(string(tt.key), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tkd := k.keyDefinitionFromKey(tt.key)\n\t\t\tassert.Contains(t, tt.expectedCodes, kd.Code)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/kill_linux.go",
    "content": "//go:build linux\n\npackage common\n\nimport (\n\t\"os/exec\"\n\t\"syscall\"\n)\n\n// killAfterParent kills the child process when the parent process dies.\nfunc killAfterParent(cmd *exec.Cmd) {\n\tif cmd.SysProcAttr == nil {\n\t\tcmd.SysProcAttr = new(syscall.SysProcAttr)\n\t}\n\tcmd.SysProcAttr.Pdeathsig = syscall.SIGKILL\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/kill_other.go",
    "content": "//go:build !linux\n// +build !linux\n\npackage common\n\nimport \"os/exec\"\n\n// killAfterParent kills the child process when the parent process dies.\nfunc killAfterParent(cmd *exec.Cmd) {\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/layout.go",
    "content": "package common\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\n// Position represents a position.\ntype Position struct {\n\tX float64 `json:\"x\"`\n\tY float64 `json:\"y\"`\n}\n\n// Rect represents a rectangle.\ntype Rect struct {\n\tX      float64 `js:\"x\"`\n\tY      float64 `js:\"y\"`\n\tWidth  float64 `js:\"width\"`\n\tHeight float64 `js:\"height\"`\n}\n\nfunc (r *Rect) enclosingIntRect() *Rect {\n\tx := math.Floor(r.X + 1e-3)\n\ty := math.Floor(r.Y + 1e-3)\n\tx2 := math.Ceil(r.X + r.Width - 1e-3)\n\ty2 := math.Ceil(r.Y + r.Height - 1e-3)\n\treturn &Rect{X: x, Y: y, Width: x2 - x, Height: y2 - y}\n}\n\nfunc (r Rect) contains(p Position) bool {\n\treturn p.X >= r.X && p.X <= r.X+r.Width &&\n\t\tp.Y >= r.Y && p.Y <= r.Y+r.Height\n}\n\n// SelectOption represents a select option.\ntype SelectOption struct {\n\tValue *string `json:\"value\"`\n\tLabel *string `json:\"label\"`\n\tIndex *int64  `json:\"index\"`\n}\n\n// Size represents a size.\ntype Size struct {\n\tWidth  float64 `js:\"width\"`\n\tHeight float64 `js:\"height\"`\n}\n\nfunc (s Size) enclosingIntSize() *Size {\n\treturn &Size{\n\t\tWidth:  math.Floor(s.Width + 1e-3),\n\t\tHeight: math.Floor(s.Height + 1e-3),\n\t}\n}\n\nfunc (s Size) String() string {\n\treturn fmt.Sprintf(\"%fx%f\", s.Width, s.Height)\n}\n\n// Viewport represents a page viewport.\ntype Viewport struct {\n\tWidth  int64 `js:\"width\"`\n\tHeight int64 `js:\"height\"`\n}\n\n// IsEmpty returns true if the viewport is empty.\nfunc (v Viewport) IsEmpty() bool {\n\treturn v.Width == 0 && v.Height == 0\n}\n\nfunc (v Viewport) String() string {\n\treturn fmt.Sprintf(\"%dx%d\", v.Width, v.Height)\n}\n\n// recalculateInset is used to calculate the inset width and height\n// depending on the operating system and add it to the given v, and\n// return a new Viewport. It returns the same Viewport if headless is true.\nfunc (v Viewport) recalculateInset(headless bool, os string) Viewport {\n\tif headless {\n\t\treturn v\n\t}\n\t// TODO: popup windows have their own insets.\n\tvar inset Viewport\n\tswitch os {\n\tdefault:\n\t\tinset = Viewport{Width: 24, Height: 88}\n\tcase \"windows\":\n\t\tinset = Viewport{Width: 16, Height: 88}\n\tcase \"linux\":\n\t\tinset = Viewport{Width: 8, Height: 85}\n\tcase \"darwin\":\n\t\t// Playwright is using w:2 h:80 here but I checked it\n\t\t// on my Mac and w:0 h:79 works best.\n\t\tinset = Viewport{Width: 0, Height: 79}\n\t}\n\n\treturn Viewport{\n\t\tWidth:  v.Width + inset.Width,\n\t\tHeight: v.Height + inset.Height,\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/layout_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// See: Issue #183 for details.\nfunc TestViewportCalculateInset(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"headless\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\theadless, vp := true, Viewport{}\n\t\tvp = vp.recalculateInset(headless, \"any os\")\n\t\tassert.Equal(t, Viewport{}, vp,\n\t\t\t\"should not change the viewport if headless is true\")\n\t})\n\n\tt.Run(\"headful\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar (\n\t\t\theadless bool\n\t\t\tvp       Viewport\n\t\t)\n\t\tvp = vp.recalculateInset(headless, \"any os\")\n\t\tassert.NotEqual(t, Viewport{}, vp,\n\t\t\t\"should add the default inset to the viewport if the\"+\n\t\t\t\t\" operating system is unrecognized by the addInset.\")\n\t})\n\n\t// should add a different inset to viewport than the default one\n\t// if a recognized os is given.\n\tfor _, os := range []string{\"windows\", \"linux\", \"darwin\"} {\n\t\tt.Run(os, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar (\n\t\t\t\theadless bool\n\t\t\t\tvp       Viewport\n\t\t\t)\n\t\t\t// add the default inset to the viewport\n\t\t\tvp = vp.recalculateInset(headless, \"any os\")\n\t\t\tdefaultVp := vp\n\t\t\t// add an os specific inset to the viewport\n\t\t\tvp = vp.recalculateInset(headless, os)\n\n\t\t\tassert.NotEqual(t, defaultVp, vp, \"inset for %q should exist\", os)\n\t\t\t// we multiply the default viewport by two to detect\n\t\t\t// whether an os specific inset is adding the default\n\t\t\t// viewport, instead of its own.\n\t\t\tassert.NotEqual(t, Viewport{\n\t\t\t\tWidth:  defaultVp.Width * 2,\n\t\t\t\tHeight: defaultVp.Height * 2,\n\t\t\t}, vp, \"inset for %q should not be the same as the default one\", os)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/lifecycle.go",
    "content": "package common\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// FrameLifecycleEvent is emitted when a frame lifecycle event occurs.\ntype FrameLifecycleEvent struct {\n\t// URL is the URL of the frame that emitted the event.\n\tURL string\n\n\t// Event is the lifecycle event that occurred.\n\tEvent LifecycleEvent\n}\n\n// LifecycleEvent is a lifecycle event.\ntype LifecycleEvent int\n\nconst (\n\t// LifecycleEventLoad is emitted when the page load event is fired.\n\tLifecycleEventLoad LifecycleEvent = iota\n\n\t// LifecycleEventDOMContentLoad is emitted when the DOMContentLoaded event is fired.\n\tLifecycleEventDOMContentLoad\n\n\t// LifecycleEventNetworkIdle is emitted when there are no more than 2 network connections for at least 500 ms.\n\tLifecycleEventNetworkIdle\n)\n\nfunc (l LifecycleEvent) String() string {\n\treturn lifecycleEventToString[l]\n}\n\nvar lifecycleEventToString = map[LifecycleEvent]string{ //nolint:gochecknoglobals\n\tLifecycleEventLoad:           \"load\",\n\tLifecycleEventDOMContentLoad: \"domcontentloaded\",\n\tLifecycleEventNetworkIdle:    \"networkidle\",\n}\n\nvar lifecycleEventToID = map[string]LifecycleEvent{ //nolint:gochecknoglobals\n\t\"load\":             LifecycleEventLoad,\n\t\"domcontentloaded\": LifecycleEventDOMContentLoad,\n\t\"networkidle\":      LifecycleEventNetworkIdle,\n}\n\n// MarshalJSON marshals the enum as a quoted JSON string.\nfunc (l LifecycleEvent) MarshalJSON() ([]byte, error) {\n\tbuffer := bytes.NewBufferString(`\"`)\n\tbuffer.WriteString(lifecycleEventToString[l])\n\tbuffer.WriteString(`\"`)\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON unmarshals a quoted JSON string to the enum value.\nfunc (l *LifecycleEvent) UnmarshalJSON(b []byte) error {\n\tvar j string\n\terr := json.Unmarshal(b, &j)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshaling %q to lifecycle event: %w\", b, err)\n\t}\n\t// Note that if the string cannot be found then it will be set to the zero value.\n\t*l = lifecycleEventToID[j]\n\treturn nil\n}\n\n// MarshalText returns the string representation of the enum value.\n// It returns an error if the enum value is invalid.\nfunc (l *LifecycleEvent) MarshalText() ([]byte, error) {\n\tif l == nil {\n\t\treturn []byte(\"\"), nil\n\t}\n\tvar (\n\t\tok bool\n\t\ts  string\n\t)\n\tif s, ok = lifecycleEventToString[*l]; !ok {\n\t\treturn nil, fmt.Errorf(\"invalid lifecycle event: %v\", int(*l))\n\t}\n\n\treturn []byte(s), nil\n}\n\n// UnmarshalText unmarshals a text representation to the enum value.\n// It returns an error if given a wrong value.\nfunc (l *LifecycleEvent) UnmarshalText(text []byte) error {\n\tvar (\n\t\tok  bool\n\t\tval = string(text)\n\t)\n\n\tif *l, ok = lifecycleEventToID[val]; !ok {\n\t\tvalid := make([]string, 0, len(lifecycleEventToID))\n\t\tfor k := range lifecycleEventToID {\n\t\t\tvalid = append(valid, k)\n\t\t}\n\t\tsort.Slice(valid, func(i, j int) bool {\n\t\t\treturn lifecycleEventToID[valid[j]] > lifecycleEventToID[valid[i]]\n\t\t})\n\t\treturn fmt.Errorf(\n\t\t\t\"invalid lifecycle event: %q; must be one of: %s\",\n\t\t\tval, strings.Join(valid, \", \"))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/lifecycle_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLifecycleEventMarshalText(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok/nil\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar evt *LifecycleEvent\n\t\tm, err := evt.MarshalText()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, []byte(\"\"), m)\n\t})\n\n\tt.Run(\"err/invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tevt := LifecycleEvent(-1)\n\t\t_, err := evt.MarshalText()\n\t\trequire.EqualError(t, err, \"invalid lifecycle event: -1\")\n\t})\n}\n\nfunc TestLifecycleEventMarshalTextRound(t *testing.T) {\n\tt.Parallel()\n\n\tevt := LifecycleEventLoad\n\tm, err := evt.MarshalText()\n\trequire.NoError(t, err)\n\tassert.Equal(t, []byte(\"load\"), m)\n\n\tvar evt2 LifecycleEvent\n\terr = evt2.UnmarshalText(m)\n\trequire.NoError(t, err)\n\tassert.Equal(t, evt, evt2)\n}\n\nfunc TestLifecycleEventUnmarshalText(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar evt LifecycleEvent\n\t\terr := evt.UnmarshalText([]byte(\"load\"))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, LifecycleEventLoad, evt)\n\t})\n\n\tt.Run(\"err/invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar evt LifecycleEvent\n\t\terr := evt.UnmarshalText([]byte(\"none\"))\n\t\trequire.EqualError(t, err,\n\t\t\t`invalid lifecycle event: \"none\"; `+\n\t\t\t\t`must be one of: load, domcontentloaded, networkidle`)\n\t})\n\n\tt.Run(\"err/invalid_empty\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar evt LifecycleEvent\n\t\terr := evt.UnmarshalText([]byte(\"\"))\n\t\trequire.EqualError(t, err,\n\t\t\t`invalid lifecycle event: \"\"; `+\n\t\t\t\t`must be one of: load, domcontentloaded, networkidle`)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/locator.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\n// Strict mode:\n// All operations on locators throw an exception if more\n// than one element matches the locator's selector.\n//\n// See Issue #100 for more details.\n\n// Locator represents a way to find element(s) on the page at any moment.\ntype Locator struct {\n\tselector string\n\topts     *LocatorOptions\n\n\tframe *Frame\n\n\tctx context.Context\n\tlog *log.Logger\n}\n\n// LocatorOptions allows modifying the [Locator] behavior.\ntype LocatorOptions struct {\n\t// Matches only elements that contain the specified text.\n\t// String or RegExp. Optional.\n\tHasText string\n\t// Matches only elements that do not contain the specified text.\n\t// String or RegExp. Optional.\n\tHasNotText string\n}\n\n// NewLocator creates and returns a new locator.\nfunc NewLocator(ctx context.Context, opts *LocatorOptions, selector string, f *Frame, l *log.Logger) *Locator {\n\tif opts == nil {\n\t\topts = new(LocatorOptions)\n\t}\n\tif opts.HasText != \"\" {\n\t\tselector += \" >> internal:has-text=\" + opts.HasText\n\t}\n\tif opts.HasNotText != \"\" {\n\t\tselector += \" >> internal:has-not-text=\" + opts.HasNotText\n\t}\n\treturn &Locator{\n\t\tselector: selector,\n\t\topts:     opts,\n\t\tframe:    f,\n\t\tctx:      ctx,\n\t\tlog:      l,\n\t}\n}\n\n// BoundingBox will return the bounding box of the element.\nfunc (l *Locator) BoundingBox(opts *FrameBaseOptions) (*Rect, error) {\n\topts.Strict = true\n\treturn l.frame.boundingBox(l.selector, opts)\n}\n\n// Clear will clear the input field.\n// This works with the Fill API and fills the input field with an empty string.\nfunc (l *Locator) Clear(opts *FrameFillOptions) error {\n\tl.log.Debugf(\n\t\t\"Locator:Clear\", \"fid:%s furl:%q sel:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, opts,\n\t)\n\n\topts.Strict = true\n\tif err := l.frame.fill(l.selector, \"\", opts); err != nil {\n\t\treturn fmt.Errorf(\"clearing %q: %w\", l.selector, err)\n\t}\n\n\treturn nil\n}\n\n// Timeout will return the default timeout or the one set by the user.\nfunc (l *Locator) Timeout() time.Duration {\n\treturn l.frame.defaultTimeout()\n}\n\n// Click on an element using locator's selector with strict mode on.\nfunc (l *Locator) Click(opts *FrameClickOptions) error {\n\tl.log.Debugf(\"Locator:Click\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\t_, span := TraceAPICall(l.ctx, l.frame.page.targetID.String(), \"locator.click\")\n\tdefer span.End()\n\n\topts.Strict = true\n\topts.retry = true\n\tif err := l.frame.click(l.selector, opts); err != nil {\n\t\treturn spanRecordErrorf(span, \"clicking on %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\nfunc (l *Locator) All() ([]*Locator, error) {\n\tl.log.Debugf(\"Locator:All\", \"fid:%s furl:%q sel:%q\", l.frame.ID(), l.frame.URL(), l.selector)\n\n\tcount, err := l.Count()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlocators := make([]*Locator, count)\n\tfor i := range count {\n\t\tlocators[i] = l.Nth(i)\n\t}\n\n\treturn locators, nil\n}\n\n// ContentFrame creates and returns a new FrameLocator, which is useful when\n// needing to interact with elements in an iframe and the current locator already\n// points to the iframe.\nfunc (l *Locator) ContentFrame() *FrameLocator {\n\treturn NewFrameLocator(l.ctx, l.selector, l.frame, l.log)\n}\n\n// Count APIs do not wait for the element to be present. It also does not set\n// strict to true, allowing it to return the total number of elements matching\n// the selector.\nfunc (l *Locator) Count() (int, error) {\n\treturn l.frame.count(l.selector)\n}\n\n// Dblclick double clicks on an element using locator's selector with strict mode on.\nfunc (l *Locator) Dblclick(opts *FrameDblclickOptions) error {\n\tl.log.Debugf(\"Locator:Dblclick\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\topts.retry = true\n\tif err := l.frame.dblclick(l.selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"double clicking on %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\nfunc (l *Locator) Evaluate(pageFunc string, args ...any) (any, error) {\n\treturn l.frame.evaluateWithSelector(l.selector, pageFunc, args...)\n}\n\nfunc (l *Locator) EvaluateHandle(pageFunc string, args ...any) (JSHandleAPI, error) {\n\treturn l.frame.evaluateHandleWithSelector(l.selector, pageFunc, args...)\n}\n\n// SetChecked sets the checked state of the element using locator's selector\n// with strict mode on.\nfunc (l *Locator) SetChecked(checked bool, opts *FrameCheckOptions) error {\n\tl.log.Debugf(\n\t\t\"Locator:SetChecked\", \"fid:%s furl:%q sel:%q checked:%v opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, checked, opts,\n\t)\n\n\topts.Strict = true\n\topts.retry = true\n\tif err := l.frame.setChecked(l.selector, checked, opts); err != nil {\n\t\treturn fmt.Errorf(\"setting %q checked to %v: %w\", l.selector, checked, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// Check on an element using locator's selector with strict mode on.\nfunc (l *Locator) Check(opts *FrameCheckOptions) error {\n\tl.log.Debugf(\"Locator:Check\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\topts.retry = true\n\tif err := l.frame.check(l.selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"checking %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// Uncheck on an element using locator's selector with strict mode on.\nfunc (l *Locator) Uncheck(opts *FrameUncheckOptions) error {\n\tl.log.Debugf(\"Locator:Uncheck\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\topts.retry = true\n\tif err := l.frame.uncheck(l.selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"unchecking %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// IsChecked returns true if the element matches the locator's\n// selector and is checked. Otherwise, returns false.\nfunc (l *Locator) IsChecked(opts *FrameIsCheckedOptions) (bool, error) {\n\tl.log.Debugf(\"Locator:IsChecked\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\tchecked, err := l.frame.isChecked(l.selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q checked: %w\", l.selector, err)\n\t}\n\n\treturn checked, nil\n}\n\n// IsEditable returns true if the element matches the locator's\n// selector and is Editable. Otherwise, returns false.\nfunc (l *Locator) IsEditable(opts *FrameIsEditableOptions) (bool, error) {\n\tl.log.Debugf(\"Locator:IsEditable\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\teditable, err := l.frame.isEditable(l.selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q editable: %w\", l.selector, err)\n\t}\n\n\treturn editable, nil\n}\n\n// IsEnabled returns true if the element matches the locator's\n// selector and is Enabled. Otherwise, returns false.\nfunc (l *Locator) IsEnabled(opts *FrameIsEnabledOptions) (bool, error) {\n\tl.log.Debugf(\"Locator:IsEnabled\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\tenabled, err := l.frame.isEnabled(l.selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q enabled: %w\", l.selector, err)\n\t}\n\n\treturn enabled, nil\n}\n\n// IsDisabled returns true if the element matches the locator's\n// selector and is disabled. Otherwise, returns false.\nfunc (l *Locator) IsDisabled(opts *FrameIsDisabledOptions) (bool, error) {\n\tl.log.Debugf(\"Locator:IsDisabled\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\tdisabled, err := l.frame.isDisabled(l.selector, opts)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q disabled: %w\", l.selector, err)\n\t}\n\n\treturn disabled, nil\n}\n\n// IsVisible returns true if the element matches the locator's\n// selector and is visible. Otherwise, returns false.\nfunc (l *Locator) IsVisible() (bool, error) {\n\tl.log.Debugf(\"Locator:IsVisible\", \"fid:%s furl:%q sel:%q\", l.frame.ID(), l.frame.URL(), l.selector)\n\n\tvisible, err := l.frame.isVisible(l.selector, &FrameIsVisibleOptions{Strict: true})\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q visible: %w\", l.selector, err)\n\t}\n\n\treturn visible, nil\n}\n\n// IsHidden returns true if the element matches the locator's\n// selector and is hidden. Otherwise, returns false.\nfunc (l *Locator) IsHidden() (bool, error) {\n\tl.log.Debugf(\"Locator:IsHidden\", \"fid:%s furl:%q sel:%q\", l.frame.ID(), l.frame.URL(), l.selector)\n\n\thidden, err := l.frame.isHidden(l.selector, &FrameIsHiddenOptions{Strict: true})\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"checking is %q hidden: %w\", l.selector, err)\n\t}\n\n\treturn hidden, nil\n}\n\n// Fill out the element using locator's selector with strict mode on.\nfunc (l *Locator) Fill(value string, opts *FrameFillOptions) error {\n\tl.log.Debugf(\n\t\t\"Locator:Fill\", \"fid:%s furl:%q sel:%q val:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, value, opts,\n\t)\n\n\topts.Strict = true\n\tif err := l.frame.fill(l.selector, value, opts); err != nil {\n\t\treturn fmt.Errorf(\"filling %q with %q: %w\", l.selector, value, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// LocatorFilterOptions allows filtering a [Locator] by various criteria.\n// It's similar to [LocatorOptions] but used for filtering existing locators.\ntype LocatorFilterOptions struct {\n\t*LocatorOptions\n}\n\n// Filter returns a new [Locator] after applying the options to the current one.\nfunc (l *Locator) Filter(opts *LocatorFilterOptions) *Locator {\n\treturn NewLocator(l.ctx, opts.LocatorOptions, l.selector, l.frame, l.log)\n}\n\n// First will return the first child of the element matching the locator's\n// selector.\nfunc (l *Locator) First() *Locator {\n\treturn NewLocator(l.ctx, nil, l.selector+\" >> nth=0\", l.frame, l.log)\n}\n\n// Focus on the element using locator's selector with strict mode on.\nfunc (l *Locator) Focus(opts *FrameBaseOptions) error {\n\tl.log.Debugf(\"Locator:Focus\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\tif err := l.frame.focus(l.selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"focusing on %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// GetAttribute of the element using locator's selector with strict mode on.\n// The second return value is true if the attribute exists, and false otherwise.\nfunc (l *Locator) GetAttribute(name string, opts *FrameBaseOptions) (string, bool, error) {\n\tl.log.Debugf(\n\t\t\"Locator:GetAttribute\", \"fid:%s furl:%q sel:%q name:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, name, opts,\n\t)\n\n\topts.Strict = true\n\ts, ok, err := l.frame.getAttribute(l.selector, name, opts)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"getting attribute %q of %q: %w\", name, l.selector, err)\n\t}\n\n\treturn s, ok, nil\n}\n\n// GetByAltText creates and returns a new relative locator that allows locating elements by their alt text.\nfunc (l *Locator) GetByAltText(alt string, opts *GetByBaseOptions) *Locator {\n\tl.log.Debugf(\n\t\t\"Locator:GetByAltText\", \"fid:%s furl:%q selector:%s alt:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, alt, opts,\n\t)\n\n\treturn l.Locator(l.frame.buildAttributeSelector(\"alt\", alt, opts), nil)\n}\n\n// GetByLabel creates and returns a new relative locator that allows locating input elements by the text\n// of the associated `<label>` or `aria-labelledby` element, or by the `aria-label` attribute.\nfunc (l *Locator) GetByLabel(label string, opts *GetByBaseOptions) *Locator {\n\tl.log.Debugf(\n\t\t\"Locator:GetByLabel\", \"fid:%s furl:%q selector:%s label:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, label, opts,\n\t)\n\n\treturn l.Locator(l.frame.buildLabelSelector(label, opts), nil)\n}\n\n// GetByPlaceholder creates and returns a new relative locator for this based on the placeholder attribute.\nfunc (l *Locator) GetByPlaceholder(placeholder string, opts *GetByBaseOptions) *Locator {\n\tl.log.Debugf(\n\t\t\"Locator:GetByPlaceholder\", \"fid:%s furl:%q selector:%s placeholder:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, placeholder, opts,\n\t)\n\n\treturn l.Locator(l.frame.buildAttributeSelector(\"placeholder\", placeholder, opts), nil)\n}\n\n// GetByRole creates and returns a new relative locator using the ARIA role and any additional options.\nfunc (l *Locator) GetByRole(role string, opts *GetByRoleOptions) *Locator {\n\tl.log.Debugf(\n\t\t\"Locator:GetByRole\", \"fid:%s furl:%q selector:%s role:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, role, opts,\n\t)\n\n\treturn l.Locator(l.frame.buildRoleSelector(role, opts), nil)\n}\n\n// GetByTestID creates and returns a new relative locator based on the data-testid attribute.\nfunc (l *Locator) GetByTestID(testID string) *Locator {\n\tl.log.Debugf(\n\t\t\"Locator:GetByTestID\", \"fid:%s furl:%q selector:%s testID:%q\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, testID,\n\t)\n\n\treturn l.Locator(l.frame.buildTestIDSelector(testID), nil)\n}\n\n// GetByText creates and returns a new relative locator based on text content.\nfunc (l *Locator) GetByText(text string, opts *GetByBaseOptions) *Locator {\n\tl.log.Debugf(\n\t\t\"Locator:GetByText\", \"fid:%s furl:%q selector:%s text:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, text, opts,\n\t)\n\n\treturn l.Locator(l.frame.buildTextSelector(text, opts), nil)\n}\n\n// GetByTitle creates and returns a new relative locator based on the title attribute.\nfunc (l *Locator) GetByTitle(title string, opts *GetByBaseOptions) *Locator {\n\tl.log.Debugf(\n\t\t\"Locator:GetByTitle\", \"fid:%s furl:%q selector:%s title:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, title, opts,\n\t)\n\n\treturn l.Locator(l.frame.buildAttributeSelector(\"title\", title, opts), nil)\n}\n\n// Locator creates and returns a new locator chained/relative to the current locator.\nfunc (l *Locator) Locator(selector string, opts *LocatorOptions) *Locator {\n\treturn NewLocator(l.ctx, opts, l.selector+\" >> \"+selector, l.frame, l.log)\n}\n\n// FrameLocator creates a frame locator for an iframe matching the given selector\n// within the current locator's scope.\nfunc (l *Locator) FrameLocator(selector string) *FrameLocator {\n\tl.log.Debugf(\"Locator:FrameLocator\", \"selector:%q childSelector:%q\", l.selector, selector)\n\n\treturn l.Locator(selector, nil).ContentFrame()\n}\n\n// InnerHTML returns the element's inner HTML that matches\n// the locator's selector with strict mode on.\nfunc (l *Locator) InnerHTML(opts *FrameInnerHTMLOptions) (string, error) {\n\tl.log.Debugf(\"Locator:InnerHTML\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\ts, err := l.frame.innerHTML(l.selector, opts)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting inner HTML of %q: %w\", l.selector, err)\n\t}\n\n\treturn s, nil\n}\n\n// InnerText returns the element's inner text that matches\n// the locator's selector with strict mode on.\nfunc (l *Locator) InnerText(opts *FrameInnerTextOptions) (string, error) {\n\tl.log.Debugf(\"Locator:InnerText\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\ts, err := l.frame.innerText(l.selector, opts)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting inner text of %q: %w\", l.selector, err)\n\t}\n\n\treturn s, nil\n}\n\n// Last will return the last child of the element matching the locator's\n// selector.\nfunc (l *Locator) Last() *Locator {\n\treturn NewLocator(l.ctx, nil, l.selector+\" >> nth=-1\", l.frame, l.log)\n}\n\n// Nth will return the nth child of the element matching the locator's\n// selector.\nfunc (l *Locator) Nth(nth int) *Locator {\n\treturn NewLocator(l.ctx, nil, l.selector+\" >> nth=\"+strconv.Itoa(nth), l.frame, l.log)\n}\n\n// TextContent returns the element's text content that matches\n// the locator's selector with strict mode on. The second return\n// value is true if the returned text content is not null or empty,\n// and false otherwise.\nfunc (l *Locator) TextContent(opts *FrameTextContentOptions) (string, bool, error) {\n\tl.log.Debugf(\"Locator:TextContent\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\ts, ok, err := l.frame.textContent(l.selector, opts)\n\tif err != nil {\n\t\treturn \"\", false, fmt.Errorf(\"getting text content of %q: %w\", l.selector, err)\n\t}\n\n\treturn s, ok, nil\n}\n\n// InputValue returns the element's input value that matches\n// the locator's selector with strict mode on.\nfunc (l *Locator) InputValue(opts *FrameInputValueOptions) (string, error) {\n\tl.log.Debugf(\"Locator:InputValue\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\tv, err := l.frame.inputValue(l.selector, opts)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting input value of %q: %w\", l.selector, err)\n\t}\n\n\treturn v, nil\n}\n\n// SelectOption filters option values of the first element that matches\n// the locator's selector (with strict mode on), selects the options,\n// and returns the filtered options.\nfunc (l *Locator) SelectOption(values []any, opts *FrameSelectOptionOptions) ([]string, error) {\n\tl.log.Debugf(\"Locator:SelectOption\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\tv, err := l.frame.selectOption(l.selector, values, opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"selecting option on %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn v, nil\n}\n\n// Press the given key on the element found that matches the locator's\n// selector with strict mode on.\nfunc (l *Locator) Press(key string, opts *FramePressOptions) error {\n\tl.log.Debugf(\n\t\t\"Locator:Press\", \"fid:%s furl:%q sel:%q key:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, key, opts,\n\t)\n\n\topts.Strict = true\n\tif err := l.frame.press(l.selector, key, opts); err != nil {\n\t\treturn fmt.Errorf(\"pressing %q on %q: %w\", key, l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// PressSequentially focuses on the element and sequentially sends a keydown,\n// keypress, and keyup events for each character in the provided string.\n// For handling special keys, use the [Locator.Press] method.\nfunc (l *Locator) PressSequentially(text string, opts *FrameTypeOptions) error {\n\tl.log.Debugf(\n\t\t\"Locator:PressSequentially\", \"fid:%s furl:%q sel:%q text:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, text, opts,\n\t)\n\t_, span := TraceAPICall(l.ctx, l.frame.page.targetID.String(), \"locator.pressSequentially\")\n\tdefer span.End()\n\n\topts.Strict = true\n\tif err := l.frame.typ(l.selector, text, opts); err != nil {\n\t\treturn spanRecordErrorf(span, \"pressing sequentially %q on %q: %w\", text, l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// Type text on the element found that matches the locator's\n// selector with strict mode on.\nfunc (l *Locator) Type(text string, opts *FrameTypeOptions) error {\n\tl.log.Debugf(\n\t\t\"Locator:Type\", \"fid:%s furl:%q sel:%q text:%q opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, text, opts,\n\t)\n\t_, span := TraceAPICall(l.ctx, l.frame.page.targetID.String(), \"locator.type\")\n\tdefer span.End()\n\n\topts.Strict = true\n\tif err := l.frame.typ(l.selector, text, opts); err != nil {\n\t\treturn spanRecordErrorf(span, \"typing %q in %q: %w\", text, l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// Hover moves the pointer over the element that matches the locator's\n// selector with strict mode on.\nfunc (l *Locator) Hover(opts *FrameHoverOptions) error {\n\tl.log.Debugf(\"Locator:Hover\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\topts.retry = true\n\tif err := l.frame.hover(l.selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"hovering on %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// Tap the element found that matches the locator's selector with strict mode on.\nfunc (l *Locator) Tap(opts *FrameTapOptions) error {\n\tl.log.Debugf(\"Locator:Tap\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\topts.retry = true\n\tif err := l.frame.tap(l.selector, opts); err != nil {\n\t\treturn fmt.Errorf(\"tapping on %q: %w\", l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// DispatchEvent dispatches an event for the element matching the\n// locator's selector with strict mode on.\nfunc (l *Locator) DispatchEvent(typ string, eventInit any, opts *FrameDispatchEventOptions) error {\n\tl.log.Debugf(\n\t\t\"Locator:DispatchEvent\", \"fid:%s furl:%q sel:%q typ:%q eventInit:%+v opts:%+v\",\n\t\tl.frame.ID(), l.frame.URL(), l.selector, typ, eventInit, opts,\n\t)\n\n\topts.Strict = true\n\tif err := l.frame.dispatchEvent(l.selector, typ, eventInit, opts); err != nil {\n\t\treturn fmt.Errorf(\"dispatching locator event %q to %q: %w\", typ, l.selector, err)\n\t}\n\n\tapplySlowMo(l.ctx)\n\n\treturn nil\n}\n\n// WaitFor waits for the element matching the locator's selector with strict mode on.\nfunc (l *Locator) WaitFor(opts *FrameWaitForSelectorOptions) error {\n\tl.log.Debugf(\"Locator:WaitFor\", \"fid:%s furl:%q sel:%q opts:%+v\", l.frame.ID(), l.frame.URL(), l.selector, opts)\n\n\topts.Strict = true\n\t_, err := l.frame.waitFor(l.selector, opts, 20)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"waiting for %q: %w\", l.selector, err)\n\t}\n\n\treturn nil\n}\n\n// DefaultTimeout returns the default timeout for the locator.\n// This is an internal API and should not be used by users.\nfunc (l *Locator) DefaultTimeout() time.Duration {\n\treturn l.frame.defaultTimeout()\n}\n\n// FrameLocator represent a way to find element(s) in an iframe.\ntype FrameLocator struct {\n\tselector string\n\n\tframe *Frame\n\n\tctx context.Context\n\tlog *log.Logger\n}\n\n// NewFrameLocator creates and returns a new frame locator.\nfunc NewFrameLocator(ctx context.Context, selector string, f *Frame, l *log.Logger) *FrameLocator {\n\treturn &FrameLocator{\n\t\tselector: selector,\n\t\tframe:    f,\n\t\tctx:      ctx,\n\t\tlog:      l,\n\t}\n}\n\n// GetByAltText creates and returns a new locator for this frame locator\n// based on the alt attribute text.\nfunc (fl *FrameLocator) GetByAltText(alt string, opts *GetByBaseOptions) *Locator {\n\tfl.log.Debugf(\"FrameLocator:GetByAltText\", \"selector: %q alt: %q opts:%+v\", fl.selector, alt, opts)\n\n\treturn fl.Locator(fl.frame.buildAttributeSelector(\"alt\", alt, opts), nil)\n}\n\n// GetByLabel creates and returns a new locator for this frame locator based on the label text.\nfunc (fl *FrameLocator) GetByLabel(label string, opts *GetByBaseOptions) *Locator {\n\tfl.log.Debugf(\"FrameLocator:GetByLabel\", \"selector: %q label: %q opts:%+v\", fl.selector, label, opts)\n\n\treturn fl.Locator(fl.frame.buildLabelSelector(label, opts), nil)\n}\n\n// GetByPlaceholder creates and returns a new locator for this frame locator based on the placeholder attribute.\nfunc (fl *FrameLocator) GetByPlaceholder(placeholder string, opts *GetByBaseOptions) *Locator {\n\tfl.log.Debugf(\"FrameLocator:GetByPlaceholder\", \"selector: %q placeholder: %q opts:%+v\", fl.selector, placeholder, opts)\n\n\treturn fl.Locator(fl.frame.buildAttributeSelector(\"placeholder\", placeholder, opts), nil)\n}\n\n// GetByRole creates and returns a new locator for this frame locator based on their ARIA role.\nfunc (fl *FrameLocator) GetByRole(role string, opts *GetByRoleOptions) *Locator {\n\tfl.log.Debugf(\"FrameLocator:GetByRole\", \"selector: %q role: %q opts:%+v\", fl.selector, role, opts)\n\n\treturn fl.Locator(fl.frame.buildRoleSelector(role, opts), nil)\n}\n\n// GetByTestID creates and returns a new locator for this frame locator based on the data-testid attribute.\nfunc (fl *FrameLocator) GetByTestID(testID string) *Locator {\n\tfl.log.Debugf(\"FrameLocator:GetByTestID\", \"selector: %q testID: %q\", fl.selector, testID)\n\n\treturn fl.Locator(fl.frame.buildTestIDSelector(testID), nil)\n}\n\n// GetByText creates and returns a new locator for this frame locator based on text content.\nfunc (fl *FrameLocator) GetByText(text string, opts *GetByBaseOptions) *Locator {\n\tfl.log.Debugf(\"FrameLocator:GetByText\", \"selector: %q text: %q opts:%+v\", fl.selector, text, opts)\n\n\treturn fl.Locator(fl.frame.buildTextSelector(text, opts), nil)\n}\n\n// GetByTitle creates and returns a new locator for this frame locator based on the title attribute.\nfunc (fl *FrameLocator) GetByTitle(title string, opts *GetByBaseOptions) *Locator {\n\tfl.log.Debugf(\"FrameLocator:GetByTitle\", \"selector: %q title: %q opts:%+v\", fl.selector, title, opts)\n\n\treturn fl.Locator(fl.frame.buildAttributeSelector(\"title\", title, opts), nil)\n}\n\n// Locator creates and returns a new locator chained/relative to the current FrameLocator.\nfunc (fl *FrameLocator) Locator(selector string, opts *LocatorOptions) *Locator {\n\t// Add frame navigation marker to indicate we need to enter the frame's contentDocument\n\tframeNavSelector := fl.selector + \" >> internal:control=enter-frame >> \" + selector\n\treturn NewLocator(fl.ctx, opts, frameNavSelector, fl.frame, fl.log)\n}\n\n// FrameLocator creates a nested frame locator for an iframe matching the given\nfunc (fl *FrameLocator) FrameLocator(selector string) *FrameLocator {\n\tfl.log.Debugf(\"FrameLocator:FrameLocator\", \"selector:%q childSelector:%q\", fl.selector, selector)\n\n\treturn fl.Locator(selector, nil).ContentFrame()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/locator_options.go",
    "content": "package common\n\n// GetByRoleOptions are the optional options fow when working with the\n// GetByRole API.\ntype GetByRoleOptions struct {\n\tChecked       *bool   `json:\"checked\"`\n\tDisabled      *bool   `json:\"disabled\"`\n\tExact         *bool   `json:\"exact\"`\n\tExpanded      *bool   `json:\"expanded\"`\n\tIncludeHidden *bool   `json:\"includeHidden\"`\n\tLevel         *int64  `json:\"level\"`\n\tName          *string `json:\"name\"`\n\tPressed       *bool   `json:\"pressed\"`\n\tSelected      *bool   `json:\"selected\"`\n}\n\n// GetByBaseOptions are the optional options for when working with the\n// several GetBy* APIs.\ntype GetByBaseOptions struct {\n\tExact *bool `json:\"exact\"`\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/mouse.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/input\"\n)\n\n// Mouse represents a mouse input device.\ntype Mouse struct {\n\tctx             context.Context\n\tsession         session\n\tframe           *Frame\n\ttimeoutSettings *TimeoutSettings\n\tkeyboard        *Keyboard\n\tx               float64\n\ty               float64\n\tbutton          input.MouseButton\n}\n\n// NewMouse creates a new mouse.\nfunc NewMouse(ctx context.Context, s session, f *Frame, ts *TimeoutSettings, k *Keyboard) *Mouse {\n\treturn &Mouse{\n\t\tctx:             ctx,\n\t\tsession:         s,\n\t\tframe:           f,\n\t\ttimeoutSettings: ts,\n\t\tkeyboard:        k,\n\t\tbutton:          input.None,\n\t}\n}\n\n// Click will trigger a series of MouseMove, MouseDown and MouseUp events in the browser.\nfunc (m *Mouse) Click(x float64, y float64, opts *MouseClickOptions) error {\n\tif err := m.click(x, y, opts); err != nil {\n\t\treturn fmt.Errorf(\"clicking on x:%f y:%f: %w\", x, y, err)\n\t}\n\treturn nil\n}\n\nfunc (m *Mouse) click(x float64, y float64, opts *MouseClickOptions) error {\n\tmouseDownUpOpts := opts.ToMouseDownUpOptions()\n\tif err := m.move(x, y, NewMouseMoveOptions()); err != nil {\n\t\treturn err\n\t}\n\tfor i := 0; i < int(mouseDownUpOpts.ClickCount); i++ {\n\t\tif err := m.down(mouseDownUpOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif opts.Delay != 0 {\n\t\t\tt := time.NewTimer(time.Duration(opts.Delay) * time.Millisecond)\n\t\t\tselect {\n\t\t\tcase <-m.ctx.Done():\n\t\t\t\tt.Stop()\n\t\t\tcase <-t.C:\n\t\t\t}\n\t\t}\n\t\tif err := m.up(mouseDownUpOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// DblClick will trigger Click twice in quick succession.\nfunc (m *Mouse) DblClick(x float64, y float64, opts *MouseDblClickOptions) error {\n\tif err := m.click(x, y, opts.ToMouseClickOptions()); err != nil {\n\t\treturn fmt.Errorf(\"double clicking on x:%f y:%f: %w\", x, y, err)\n\t}\n\treturn nil\n}\n\n// Down will trigger a MouseDown event in the browser.\nfunc (m *Mouse) Down(opts *MouseDownUpOptions) error {\n\tif err := m.down(opts); err != nil {\n\t\treturn fmt.Errorf(\"pressing the mouse button on x:%f y:%f: %w\", m.x, m.y, err)\n\t}\n\treturn nil\n}\n\nfunc (m *Mouse) down(opts *MouseDownUpOptions) error {\n\tm.button = input.MouseButton(opts.Button)\n\taction := input.DispatchMouseEvent(input.MousePressed, m.x, m.y).\n\t\tWithButton(input.MouseButton(opts.Button)).\n\t\tWithModifiers(input.Modifier(m.keyboard.modifiers)).\n\t\tWithClickCount(opts.ClickCount)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\treturn fmt.Errorf(\"mouse down: %w\", err)\n\t}\n\treturn nil\n}\n\n// Up will trigger a MouseUp event in the browser.\nfunc (m *Mouse) Up(opts *MouseDownUpOptions) error {\n\tif err := m.up(opts); err != nil {\n\t\treturn fmt.Errorf(\"releasing the mouse button on x:%f y:%f: %w\", m.x, m.y, err)\n\t}\n\treturn nil\n}\n\nfunc (m *Mouse) up(opts *MouseDownUpOptions) error {\n\tm.button = input.None\n\taction := input.DispatchMouseEvent(input.MouseReleased, m.x, m.y).\n\t\tWithButton(input.MouseButton(opts.Button)).\n\t\tWithModifiers(input.Modifier(m.keyboard.modifiers)).\n\t\tWithClickCount(opts.ClickCount)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\treturn fmt.Errorf(\"mouse up: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Move will trigger a MouseMoved event in the browser.\nfunc (m *Mouse) Move(x float64, y float64, opts *MouseMoveOptions) error {\n\tif err := m.move(x, y, opts); err != nil {\n\t\treturn fmt.Errorf(\"moving the mouse pointer to x:%f y:%f: %w\", x, y, err)\n\t}\n\treturn nil\n}\n\nfunc (m *Mouse) move(x float64, y float64, opts *MouseMoveOptions) error {\n\tfromX := m.x\n\tfromY := m.y\n\tm.x = x\n\tm.y = y\n\tfor i := int64(1); i <= opts.Steps; i++ {\n\t\tx := fromX + (m.x-fromX)*float64(i/opts.Steps)\n\t\ty := fromY + (m.y-fromY)*float64(i/opts.Steps)\n\t\taction := input.DispatchMouseEvent(input.MouseMoved, x, y).\n\t\t\tWithButton(m.button).\n\t\t\tWithModifiers(input.Modifier(m.keyboard.modifiers))\n\t\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"mouse move: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/mouse_options.go",
    "content": "package common\n\ntype MouseClickOptions struct {\n\tButton     string `json:\"button\"`\n\tClickCount int64  `json:\"clickCount\"`\n\tDelay      int64  `json:\"delay\"`\n}\n\ntype MouseDblClickOptions struct {\n\tButton string `json:\"button\"`\n\tDelay  int64  `json:\"delay\"`\n}\n\ntype MouseDownUpOptions struct {\n\tButton     string `json:\"button\"`\n\tClickCount int64  `json:\"clickCount\"`\n}\n\ntype MouseMoveOptions struct {\n\tSteps int64 `json:\"steps\"`\n}\n\nfunc NewMouseClickOptions() *MouseClickOptions {\n\treturn &MouseClickOptions{\n\t\tButton:     \"left\",\n\t\tClickCount: 1,\n\t\tDelay:      0,\n\t}\n}\n\nfunc (o *MouseClickOptions) ToMouseDownUpOptions() *MouseDownUpOptions {\n\to2 := NewMouseDownUpOptions()\n\to2.Button = o.Button\n\to2.ClickCount = o.ClickCount\n\treturn o2\n}\n\nfunc NewMouseDblClickOptions() *MouseDblClickOptions {\n\treturn &MouseDblClickOptions{\n\t\tButton: \"left\",\n\t\tDelay:  0,\n\t}\n}\n\n// ToMouseClickOptions converts MouseDblClickOptions to a MouseClickOptions.\nfunc (o *MouseDblClickOptions) ToMouseClickOptions() *MouseClickOptions {\n\to2 := NewMouseClickOptions()\n\to2.Button = o.Button\n\to2.ClickCount = 2\n\to2.Delay = o.Delay\n\treturn o2\n}\n\nfunc NewMouseDownUpOptions() *MouseDownUpOptions {\n\treturn &MouseDownUpOptions{\n\t\tButton:     \"left\",\n\t\tClickCount: 1,\n\t}\n}\n\nfunc NewMouseMoveOptions() *MouseMoveOptions {\n\treturn &MouseMoveOptions{\n\t\tSteps: 1,\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/network_manager.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\n\tk6modules \"go.k6.io/k6/js/modules\"\n\tk6lib \"go.k6.io/k6/lib\"\n\tk6netext \"go.k6.io/k6/lib/netext\"\n\tk6types \"go.k6.io/k6/lib/types\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/emulation\"\n\t\"github.com/chromedp/cdproto/fetch\"\n\t\"github.com/chromedp/cdproto/network\"\n)\n\n// Credentials holds HTTP authentication credentials.\ntype Credentials struct {\n\tUsername string `js:\"username\"`\n\tPassword string `js:\"password\"` //nolint:gosec\n}\n\n// IsEmpty returns true if the credentials are empty.\nfunc (c Credentials) IsEmpty() bool {\n\tc = Credentials{\n\t\tUsername: strings.TrimSpace(c.Username),\n\t\tPassword: strings.TrimSpace(c.Password),\n\t}\n\treturn c == (Credentials{})\n}\n\ntype eventInterceptor interface {\n\turlTagName(urlTag string, method string) (string, bool)\n\tonRequest(request *Request)\n\tonResponse(response *Response)\n\tonRequestFinished(request *Request)\n\tonRequestFailed(request *Request)\n}\n\n// NetworkManager manages all frames in HTML document.\ntype NetworkManager struct {\n\tBaseEventEmitter\n\n\tctx              context.Context\n\tlogger           *log.Logger\n\tsession          session\n\tparent           *NetworkManager\n\tframeManager     *FrameManager\n\tcredentials      Credentials\n\tresolver         k6netext.Resolver\n\tvu               k6modules.VU\n\tcustomMetrics    *k6ext.CustomMetrics\n\teventInterceptor eventInterceptor\n\terrorReasons     map[string]network.ErrorReason\n\n\t// TODO: manage inflight requests separately (move them between the two maps\n\t// as they transition from inflight -> completed)\n\treqIDToRequest map[network.RequestID]*Request\n\treqsMu         sync.RWMutex\n\n\t// These two maps are used to store the events so we can call onRequest with both of them,\n\t// regardless of the order of the events\n\treqIDToRequestWillBeSentEvent map[network.RequestID]*network.EventRequestWillBeSent\n\teventsWillBeSentMu            sync.RWMutex\n\treqIDToRequestPausedEvent     map[network.RequestID]*fetch.EventRequestPaused\n\teventsPausedMu                sync.RWMutex\n\n\tattemptedAuth map[fetch.RequestID]bool\n\n\textraHTTPHeaders               map[string]string\n\toffline                        bool\n\tnetworkProfile                 NetworkProfile\n\tuserCacheDisabled              bool\n\tuserReqInterceptionEnabled     bool\n\tprotocolReqInterceptionEnabled bool\n\n\twg sync.WaitGroup\n}\n\n// NewNetworkManager creates a new network manager.\nfunc NewNetworkManager(\n\tctx context.Context,\n\tcustomMetrics *k6ext.CustomMetrics,\n\ts session,\n\tfm *FrameManager,\n\tparent *NetworkManager,\n\tei eventInterceptor,\n) (*NetworkManager, error) {\n\tvu := k6ext.GetVU(ctx)\n\tstate := vu.State()\n\n\tresolver, err := newResolver(state.Options.DNS)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"newResolver(%+v): %w\", state.Options.DNS, err)\n\t}\n\n\tm := NetworkManager{\n\t\tBaseEventEmitter: NewBaseEventEmitter(ctx),\n\t\tctx:              ctx,\n\t\t// TODO: Pass an internal logger instead of basing it on k6's logger?\n\t\t// See https://go.k6.io/k6/js/modules/k6/browser/issues/54\n\t\tlogger:                        log.New(state.Logger, GetIterationID(ctx)),\n\t\tsession:                       s,\n\t\tparent:                        parent,\n\t\tframeManager:                  fm,\n\t\tresolver:                      resolver,\n\t\tvu:                            vu,\n\t\tcustomMetrics:                 customMetrics,\n\t\treqIDToRequest:                make(map[network.RequestID]*Request),\n\t\treqIDToRequestWillBeSentEvent: make(map[network.RequestID]*network.EventRequestWillBeSent),\n\t\treqIDToRequestPausedEvent:     make(map[network.RequestID]*fetch.EventRequestPaused),\n\t\tattemptedAuth:                 make(map[fetch.RequestID]bool),\n\t\textraHTTPHeaders:              make(map[string]string),\n\t\tnetworkProfile:                NewNetworkProfile(),\n\t\teventInterceptor:              ei,\n\t\terrorReasons:                  errorReasons(),\n\t}\n\tm.initEvents()\n\tif err := m.initDomains(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &m, nil\n}\n\nfunc errorReasons() map[string]network.ErrorReason {\n\treturn map[string]network.ErrorReason{\n\t\t\"aborted\":              network.ErrorReasonAborted,\n\t\t\"accessdenied\":         network.ErrorReasonAccessDenied,\n\t\t\"addressunreachable\":   network.ErrorReasonAddressUnreachable,\n\t\t\"blockedbyclient\":      network.ErrorReasonBlockedByClient,\n\t\t\"blockedbyresponse\":    network.ErrorReasonBlockedByResponse,\n\t\t\"connectionaborted\":    network.ErrorReasonConnectionAborted,\n\t\t\"connectionclosed\":     network.ErrorReasonConnectionClosed,\n\t\t\"connectionfailed\":     network.ErrorReasonConnectionFailed,\n\t\t\"connectionrefused\":    network.ErrorReasonConnectionRefused,\n\t\t\"connectionreset\":      network.ErrorReasonConnectionReset,\n\t\t\"internetdisconnected\": network.ErrorReasonInternetDisconnected,\n\t\t\"namenotresolved\":      network.ErrorReasonNameNotResolved,\n\t\t\"timedout\":             network.ErrorReasonTimedOut,\n\t\t\"failed\":               network.ErrorReasonFailed,\n\t}\n}\n\n// Returns a new Resolver.\n// Copied with minor changes from\n// https://github.com/grafana/k6/blob/fb70bc6f3d3f22a40e65f32deea3cea1b6d70a76/js/runner.go#L459\nfunc newResolver(conf k6types.DNSConfig) (k6netext.Resolver, error) {\n\tttl, err := parseTTL(conf.TTL.String)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing TTL: %w\", err)\n\t}\n\n\tdnsSel := conf.Select\n\tif !dnsSel.Valid {\n\t\tdnsSel = k6types.DefaultDNSConfig().Select\n\t}\n\tdnsPol := conf.Policy\n\tif !dnsPol.Valid {\n\t\tdnsPol = k6types.DefaultDNSConfig().Policy\n\t}\n\treturn k6netext.NewResolver(\n\t\tnet.LookupIP, ttl, dnsSel.DNSSelect, dnsPol.DNSPolicy), nil\n}\n\n// Parse a string representation of TTL to time.Duration.\n// Copied from https://github.com/grafana/k6/blob/fb70bc6f3d3f22a40e65f32deea3cea1b6d70a76/js/runner.go#L479\nfunc parseTTL(ttlS string) (time.Duration, error) {\n\tttl := time.Duration(0)\n\tswitch ttlS {\n\tcase \"inf\":\n\t\t// cache \"infinitely\"\n\t\tttl = time.Hour * 24 * 365\n\tcase \"0\":\n\t\t// disable cache\n\tcase \"\":\n\t\tttlS = k6types.DefaultDNSConfig().TTL.String\n\t\tfallthrough\n\tdefault:\n\t\tvar err error\n\t\tttl, err = k6types.ParseExtendedDuration(ttlS)\n\t\tif ttl < 0 || err != nil {\n\t\t\treturn ttl, fmt.Errorf(\"invalid DNS TTL: %s\", ttlS)\n\t\t}\n\t}\n\treturn ttl, nil\n}\n\nfunc (m *NetworkManager) deleteRequestByID(reqID network.RequestID) {\n\tm.reqsMu.Lock()\n\tdefer m.reqsMu.Unlock()\n\tdelete(m.reqIDToRequest, reqID)\n}\n\nfunc (m *NetworkManager) emitRequestMetrics(req *Request) {\n\tstate := m.vu.State()\n\n\ttags := state.Tags.GetCurrentValues().Tags\n\tif state.Options.SystemTags.Has(k6metrics.TagMethod) {\n\t\ttags = tags.With(\"method\", req.method)\n\t}\n\tif state.Options.SystemTags.Has(k6metrics.TagURL) {\n\t\ttags = handleURLTag(m.eventInterceptor, req.URL(), req.method, tags)\n\t}\n\ttags = tags.With(\"resource_type\", req.ResourceType())\n\n\tpushIfNotDone(m.vu.Context(), m.logger, state.Samples, k6metrics.ConnectedSamples{\n\t\tSamples: []k6metrics.Sample{\n\t\t\t{\n\t\t\t\tTimeSeries: k6metrics.TimeSeries{Metric: m.customMetrics.BrowserDataSent, Tags: tags},\n\t\t\t\tValue:      float64(req.Size().Total()),\n\t\t\t\tTime:       req.wallTime,\n\t\t\t},\n\t\t},\n\t})\n}\n\nfunc (m *NetworkManager) emitResponseMetrics(resp *Response, req *Request) {\n\tstate := m.vu.State()\n\n\t// In some scenarios we might not receive a ResponseReceived CDP event, in\n\t// which case the response won't be created. So to emit as much metric data\n\t// as possible we set some sensible defaults instead.\n\tvar (\n\t\tstatus, bodySize                    int64\n\t\tipAddress, protocol                 string\n\t\tfromCache, fromPreCache, fromSvcWrk bool\n\t\turl                                 = req.url.String()\n\t\twallTime                            = time.Now()\n\t\tfailed                              float64\n\t)\n\tif resp != nil {\n\t\tstatus = resp.status\n\t\tbodySize = resp.Size().Total()\n\t\tipAddress = resp.remoteAddress.IPAddress\n\t\tprotocol = resp.protocol\n\t\tfromCache = resp.fromDiskCache\n\t\tfromPreCache = resp.fromPrefetchCache\n\t\tfromSvcWrk = resp.fromServiceWorker\n\t\twallTime = resp.wallTime\n\t\turl = resp.url\n\t\t// Assuming that a failure is when status\n\t\t// is not between 200 and 399 (inclusive).\n\t\tif status < 200 || status > 399 {\n\t\t\tfailed = 1\n\t\t}\n\t} else {\n\t\tm.logger.Debugf(\"NetworkManager:emitResponseMetrics\",\n\t\t\t\"response is nil url:%s method:%s\", req.url, req.method)\n\t}\n\n\ttags := state.Tags.GetCurrentValues().Tags\n\tif state.Options.SystemTags.Has(k6metrics.TagMethod) {\n\t\ttags = tags.With(\"method\", req.method)\n\t}\n\tif state.Options.SystemTags.Has(k6metrics.TagURL) {\n\t\ttags = handleURLTag(m.eventInterceptor, url, req.method, tags)\n\t}\n\tif state.Options.SystemTags.Has(k6metrics.TagIP) {\n\t\ttags = tags.With(\"ip\", ipAddress)\n\t}\n\tif state.Options.SystemTags.Has(k6metrics.TagStatus) {\n\t\ttags = tags.With(\"status\", strconv.Itoa(int(status)))\n\t}\n\tif state.Options.SystemTags.Has(k6metrics.TagProto) {\n\t\ttags = tags.With(\"proto\", protocol)\n\t}\n\n\ttags = tags.With(\"from_cache\", strconv.FormatBool(fromCache))\n\ttags = tags.With(\"from_prefetch_cache\", strconv.FormatBool(fromPreCache))\n\ttags = tags.With(\"from_service_worker\", strconv.FormatBool(fromSvcWrk))\n\ttags = tags.With(\"resource_type\", req.ResourceType())\n\n\tpushIfNotDone(m.vu.Context(), m.logger, state.Samples, k6metrics.ConnectedSamples{\n\t\tSamples: []k6metrics.Sample{\n\t\t\t{\n\t\t\t\tTimeSeries: k6metrics.TimeSeries{Metric: m.customMetrics.BrowserHTTPReqDuration, Tags: tags},\n\t\t\t\tValue:      k6metrics.D(wallTime.Sub(req.wallTime)),\n\t\t\t\tTime:       wallTime,\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: k6metrics.TimeSeries{Metric: m.customMetrics.BrowserDataReceived, Tags: tags},\n\t\t\t\tValue:      float64(bodySize),\n\t\t\t\tTime:       wallTime,\n\t\t\t},\n\t\t},\n\t})\n\n\tif resp != nil && resp.timing != nil {\n\t\tpushIfNotDone(m.vu.Context(), m.logger, state.Samples, k6metrics.ConnectedSamples{\n\t\t\tSamples: []k6metrics.Sample{\n\t\t\t\t{\n\t\t\t\t\tTimeSeries: k6metrics.TimeSeries{Metric: m.customMetrics.BrowserHTTPReqFailed, Tags: tags},\n\t\t\t\t\tValue:      failed,\n\t\t\t\t\tTime:       wallTime,\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n}\n\n// handleURLTag will check if the url tag needs to be grouped by testing\n// against user supplied regex. If there's a match a user supplied name will\n// be used instead of the url for the url tag, otherwise the url will be used.\nfunc handleURLTag(mi eventInterceptor, url string, method string, tags *k6metrics.TagSet) *k6metrics.TagSet {\n\tif newTagName, urlMatched := mi.urlTagName(url, method); urlMatched {\n\t\ttags = tags.With(\"url\", newTagName)\n\t\ttags = tags.With(\"name\", newTagName)\n\t\treturn tags\n\t}\n\n\ttags = tags.With(\"url\", url)\n\ttags = tags.With(\"name\", url)\n\n\treturn tags\n}\n\nfunc (m *NetworkManager) handleRequestRedirect(\n\treq *Request, redirectResponse *network.Response, timestamp *cdp.MonotonicTime,\n) {\n\tresp := NewHTTPResponse(m.ctx, req, redirectResponse, timestamp)\n\treq.responseMu.Lock()\n\treq.response = resp\n\treq.responseMu.Unlock()\n\treq.redirectChain = append(req.redirectChain, req)\n\n\tm.emitResponseMetrics(resp, req)\n\tm.deleteRequestByID(req.requestID)\n\n\t/*\n\t\tdelete(m.attemptedAuth, req.interceptionID);\n\t*/\n\n\tm.eventInterceptor.onResponse(resp)\n\tm.eventInterceptor.onRequestFinished(req)\n\tm.emit(cdproto.EventNetworkResponseReceived, resp)\n\tm.emit(cdproto.EventNetworkLoadingFinished, req)\n}\n\nfunc (m *NetworkManager) initDomains() error {\n\tactions := []Action{network.Enable()}\n\n\t// Only enable the Fetch domain if necessary, as it has a performance overhead.\n\tif m.userReqInterceptionEnabled {\n\t\tactions = append(actions,\n\t\t\tnetwork.SetCacheDisabled(true),\n\t\t\tfetch.Enable().WithPatterns([]*fetch.RequestPattern{{URLPattern: \"*\"}}))\n\t}\n\tfor _, action := range actions {\n\t\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"initializing networking %T: %w\", action, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *NetworkManager) initEvents() {\n\tchHandler := make(chan Event)\n\tm.session.on(m.ctx, []string{\n\t\tcdproto.EventNetworkLoadingFailed,\n\t\tcdproto.EventNetworkLoadingFinished,\n\t\tcdproto.EventNetworkRequestWillBeSent,\n\t\tcdproto.EventNetworkRequestServedFromCache,\n\t\tcdproto.EventNetworkResponseReceived,\n\t\tcdproto.EventFetchRequestPaused,\n\t\tcdproto.EventFetchAuthRequired,\n\t}, chHandler)\n\n\tm.wg.Go(func() {\n\t\tfor m.handleEvents(chHandler) {\n\t\t}\n\t})\n}\n\nfunc (m *NetworkManager) handleEvents(in <-chan Event) bool {\n\tselect {\n\tcase <-m.ctx.Done():\n\t\treturn false\n\tcase <-m.session.Done():\n\t\treturn false\n\tcase event := <-in:\n\t\tselect {\n\t\tcase <-m.ctx.Done():\n\t\t\treturn false\n\t\tcase <-m.session.Done():\n\t\t\treturn false\n\t\tdefault:\n\t\t}\n\t\tswitch ev := event.data.(type) {\n\t\tcase *network.EventLoadingFailed:\n\t\t\tm.onLoadingFailed(ev)\n\t\tcase *network.EventLoadingFinished:\n\t\t\tm.onLoadingFinished(ev)\n\t\tcase *network.EventRequestWillBeSent:\n\t\t\tm.onRequestWillBeSent(ev)\n\t\tcase *network.EventRequestServedFromCache:\n\t\t\tm.onRequestServedFromCache(ev)\n\t\tcase *network.EventResponseReceived:\n\t\t\tm.onResponseReceived(ev)\n\t\tcase *fetch.EventRequestPaused:\n\t\t\tm.onRequestPaused(ev)\n\t\tcase *fetch.EventAuthRequired:\n\t\t\tm.onAuthRequired(ev)\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (m *NetworkManager) onLoadingFailed(event *network.EventLoadingFailed) {\n\treq, ok := m.requestFromID(event.RequestID)\n\tif !ok {\n\t\t// TODO: add handling of iframe document requests starting in one session and ending up in another\n\t\treturn\n\t}\n\n\treq.setErrorText(event.ErrorText)\n\treq.responseEndTiming = float64(event.Timestamp.Time().Unix()-req.timestamp.Unix()) * 1000\n\tm.eventInterceptor.onRequestFailed(req)\n\tm.deleteRequestByID(event.RequestID)\n\tm.frameManager.requestFailed(req, event.Canceled)\n}\n\nfunc (m *NetworkManager) onLoadingFinished(event *network.EventLoadingFinished) {\n\treq := m.requestForOnLoadingFinished(event.RequestID)\n\t// the request was not created yet.\n\tif req == nil {\n\t\treturn\n\t}\n\n\treq.responseEndTiming = float64(event.Timestamp.Time().Unix()-req.timestamp.Unix()) * 1000\n\tm.deleteRequestByID(event.RequestID)\n\tm.frameManager.requestFinished(req)\n\tm.eventInterceptor.onRequestFinished(req)\n\n\t// Skip data and blob URLs when emitting metrics, since they're internal to the browser.\n\tif isInternalURL(req.url) {\n\t\treturn\n\t}\n\temitResponseMetrics := func() {\n\t\treq.responseMu.RLock()\n\t\tm.emitResponseMetrics(req.response, req)\n\t\treq.responseMu.RUnlock()\n\t}\n\tif !req.allowInterception {\n\t\temitResponseMetrics()\n\t\treturn\n\t}\n\t// When request interception is enabled, we need to process requestPaused messages\n\t// from CDP in order to get the response for the request. However, we can't process\n\t// them until the request is unblocked. Since we're blocking the NetworkManager\n\t// goroutine here, we need to spawn a new goroutine to allow the requestPaused\n\t// messages to be processed by the NetworkManager.\n\t//\n\t// This happens when the main page request redirects before it finishes loading.\n\t// So the new redirect request will be blocked until the main page finishes loading.\n\t// The main page will wait forever since its subrequest is blocked.\n\tm.wg.Go(func() {\n\t\temitResponseMetrics()\n\t})\n}\n\n// requestForOnLoadingFinished returns the request for the given request ID.\nfunc (m *NetworkManager) requestForOnLoadingFinished(rid network.RequestID) *Request {\n\tr, ok := m.requestFromID(rid)\n\n\t// Immediately return if the request is found.\n\tif ok {\n\t\treturn r\n\t}\n\n\t// Handle IFrame document requests starting in one session and ending up in another.\n\tif m.parent == nil {\n\t\treturn nil\n\t}\n\n\tpr, ok := m.parent.requestFromID(rid)\n\tif !ok {\n\t\treturn nil\n\t}\n\t// Requests eminating from the parent have matching requestIDs.\n\tif pr.getDocumentID() != rid.String() {\n\t\treturn nil\n\t}\n\n\t// Switch the request to the parent request.\n\tm.reqsMu.Lock()\n\tm.reqIDToRequest[rid] = pr\n\tm.reqsMu.Unlock()\n\tm.parent.deleteRequestByID(rid)\n\n\treturn pr\n}\n\nfunc isInternalURL(u *url.URL) bool {\n\treturn u.Scheme == \"data\" || u.Scheme == \"blob\"\n}\n\nfunc (m *NetworkManager) onRequest(event *network.EventRequestWillBeSent,\n\trequestPausedEvent *fetch.EventRequestPaused,\n) {\n\tm.logger.Debugf(\"NetworkManager:onRequest\", \"url:%s method:%s type:%s fid:%s Starting onRequest\",\n\t\tevent.Request.URL, event.Request.Method, event.Initiator.Type, event.FrameID)\n\tvar redirectChain []*Request = nil\n\tif event.RedirectResponse != nil {\n\t\treq, ok := m.requestFromID(event.RequestID)\n\t\tif ok {\n\t\t\tm.handleRequestRedirect(req, event.RedirectResponse, event.Timestamp)\n\t\t\tredirectChain = req.redirectChain\n\t\t}\n\t} else {\n\t\tredirectChain = make([]*Request, 0)\n\t}\n\n\tfor _, r := range redirectChain {\n\t\tm.emitRequestMetrics(r)\n\t}\n\n\tvar frame *Frame = nil\n\tvar ok bool\n\tif event.FrameID != \"\" {\n\t\tframe, ok = m.frameManager.getFrameByID(event.FrameID)\n\t}\n\tif !ok && requestPausedEvent != nil && requestPausedEvent.FrameID != \"\" {\n\t\tframe, ok = m.frameManager.getFrameByID(requestPausedEvent.FrameID)\n\t}\n\n\t// Check if it's main resource request interception (targetID === main frame id).\n\tif !ok && m.frameManager.page != nil && event.FrameID != \"\" &&\n\t\tevent.FrameID == cdp.FrameID(m.frameManager.page.targetID) {\n\t\t// Main resource request for the page is being intercepted so the Frame is not created\n\t\t// yet. Precreate it here for the purposes of request interception. It will be updated\n\t\t// later as soon as the request continues and we receive frame tree from the page.\n\t\tm.frameManager.frameAttached(event.FrameID, \"\")\n\t\tframe, ok = m.frameManager.getFrameByID(event.FrameID)\n\t}\n\n\tif !ok {\n\t\tm.logger.Debugf(\"NetworkManager:onRequest\", \"url:%s method:%s type:%s fid:%s frame is nil\",\n\t\t\tevent.Request.URL, event.Request.Method, event.Initiator.Type, event.FrameID)\n\t}\n\n\tvar interceptionID fetch.RequestID\n\tif requestPausedEvent != nil {\n\t\tinterceptionID = requestPausedEvent.RequestID\n\t}\n\n\treq, err := NewRequest(m.ctx, m.logger, NewRequestParams{\n\t\tevent:             event,\n\t\tframe:             frame,\n\t\tredirectChain:     redirectChain,\n\t\tinterceptionID:    interceptionID,\n\t\tallowInterception: m.userReqInterceptionEnabled,\n\t})\n\tif err != nil {\n\t\tm.logger.Errorf(\"NetworkManager\", \"creating request: %s\", err)\n\t\treturn\n\t}\n\t// Skip data and blob URLs, since they're internal to the browser.\n\tif isInternalURL(req.url) {\n\t\tm.logger.Debugf(\"NetworkManager\", \"skipping request handling of %s URL\", req.url.Scheme)\n\t\treturn\n\t}\n\tm.reqsMu.Lock()\n\tm.reqIDToRequest[event.RequestID] = req\n\tm.reqsMu.Unlock()\n\tm.emitRequestMetrics(req)\n\tm.frameManager.requestStarted(req)\n\n\tm.eventInterceptor.onRequest(req)\n}\n\n// onRequestWillBeSent calls the onRequest method:\n// - right away, if request interception is disabled\n// - only if we first received the onRequestPaused event, if request interception is enabled;\n// otherwise, it stores the event in a map to be processed when the onRequestPaused event arrives\nfunc (m *NetworkManager) onRequestWillBeSent(event *network.EventRequestWillBeSent) {\n\tm.logger.Debugf(\"NetworkManager:onRequestWillBeSent\", \"url:%s method:%s type:%s fid:%s Starting onRequestWillBeSent\",\n\t\tevent.Request.URL, event.Request.Method, event.Initiator.Type, event.FrameID)\n\n\tif m.protocolReqInterceptionEnabled {\n\t\trequestID := event.RequestID\n\t\tif requestPausedEvent, ok := m.pausedEventFromReqID(requestID); ok {\n\t\t\tm.onRequest(event, requestPausedEvent)\n\t\t\tm.eventsPausedMu.Lock()\n\t\t\tdelete(m.reqIDToRequestPausedEvent, requestID)\n\t\t\tm.eventsPausedMu.Unlock()\n\t\t} else {\n\t\t\tm.eventsWillBeSentMu.Lock()\n\t\t\tm.reqIDToRequestWillBeSentEvent[requestID] = event\n\t\t\tm.eventsWillBeSentMu.Unlock()\n\t\t}\n\t} else {\n\t\tm.onRequest(event, nil)\n\t}\n}\n\n// onRequestPaused can send one of these two CDP events:\n// - Fetch.failRequest if the URL is part of the blocked hosts or IPs\n// - Fetch.continueRequest if the request is not blocked and no route is configured\n// In both case, if we first received the onRequestWillBeSent event, we call onRequest\n// otherwise, it stores the event in a map to be processed when the onRequestWillBeSent event arrives\nfunc (m *NetworkManager) onRequestPaused(event *fetch.EventRequestPaused) {\n\tm.logger.Debugf(\"NetworkManager:onRequestPaused\",\n\t\t\"url:%v sid:%s\", event.Request.URL, m.session.ID())\n\tdefer m.logger.Debugf(\"NetworkManager:onRequestPaused:return\",\n\t\t\"url:%v sid:%s\", event.Request.URL, m.session.ID())\n\n\tvar failErr error\n\n\tdefer func() {\n\t\trequestID := event.NetworkID\n\t\tif requestWillBeSentEvent, ok := m.willBeSentEventFromReqID(requestID); ok {\n\t\t\tm.onRequest(requestWillBeSentEvent, event)\n\t\t\tm.eventsWillBeSentMu.Lock()\n\t\t\tdelete(m.reqIDToRequestWillBeSentEvent, requestID)\n\t\t\tm.eventsWillBeSentMu.Unlock()\n\t\t} else {\n\t\t\tm.eventsPausedMu.Lock()\n\t\t\tm.reqIDToRequestPausedEvent[requestID] = event\n\t\t\tm.eventsPausedMu.Unlock()\n\t\t}\n\n\t\tif failErr != nil {\n\t\t\taction := fetch.FailRequest(event.RequestID, network.ErrorReasonBlockedByClient)\n\t\t\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\t\t\t// Avoid logging as error when context is canceled.\n\t\t\t\t// Most probably this happens when trying to fail a site's background request\n\t\t\t\t// while the iteration is ending and therefore the browser context is being closed.\n\t\t\t\tif errors.Is(err, context.Canceled) {\n\t\t\t\t\tm.logger.Debug(\"NetworkManager:onRequestPaused\", \"context canceled interrupting request\")\n\t\t\t\t} else {\n\t\t\t\t\tm.logger.Errorf(\"NetworkManager:onRequestPaused\", \"interrupting request: %s\", err)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tm.logger.Warnf(\"NetworkManager:onRequestPaused\",\n\t\t\t\t\"request %s %s was aborted: %s\", event.Request.Method, event.Request.URL, failErr)\n\n\t\t\treturn\n\t\t}\n\n\t\t// If no route was added, continue all requests\n\t\tif m.frameManager.page == nil || !m.frameManager.page.hasRoutes() {\n\t\t\terr := m.ContinueRequest(event.RequestID, ContinueOptions{}, nil)\n\t\t\tif err != nil {\n\t\t\t\tm.logger.Errorf(\"NetworkManager:onRequestPaused\",\n\t\t\t\t\t\"continuing request %s %s: %s\", event.Request.Method, event.Request.URL, err)\n\t\t\t}\n\t\t}\n\t}()\n\n\tpurl, err := url.Parse(event.Request.URL)\n\tif err != nil {\n\t\tm.logger.Errorf(\"NetworkManager:onRequestPaused\",\n\t\t\t\"parsing URL %q: %s\", event.Request.URL, err)\n\t\treturn\n\t}\n\n\tvar (\n\t\thost  = purl.Hostname()\n\t\tip    = net.ParseIP(host)\n\t\tstate = m.vu.State()\n\t)\n\tif ip != nil {\n\t\tfailErr = checkBlockedIPs(ip, state.Options.BlacklistIPs)\n\t\treturn\n\t}\n\tfailErr = checkBlockedHosts(host, state.Options.BlockedHostnames.Trie)\n\tif failErr != nil {\n\t\treturn\n\t}\n\n\t// Do one last check of the resolved IP\n\tip, err = m.resolver.LookupIP(host)\n\tif err != nil {\n\t\tm.logger.Debugf(\"NetworkManager:onRequestPaused\",\n\t\t\t\"resolving %q: %s\", host, err)\n\t\treturn\n\t}\n\tfailErr = checkBlockedIPs(ip, state.Options.BlacklistIPs)\n}\n\nfunc checkBlockedHosts(host string, blockedHosts *k6types.HostnameTrie) error {\n\tif blockedHosts == nil {\n\t\treturn nil\n\t}\n\tif match, blocked := blockedHosts.Contains(host); blocked {\n\t\treturn fmt.Errorf(\"hostname %s matches a blocked pattern %q\", host, match)\n\t}\n\treturn nil\n}\n\nfunc checkBlockedIPs(ip net.IP, blockedIPs []*k6lib.IPNet) error {\n\tfor _, ipnet := range blockedIPs {\n\t\tif ipnet.Contains(ip) {\n\t\t\t// TODO: Return netext.BlackListedIPError here once its private\n\t\t\t// fields are exported, or there's a constructor for it.\n\t\t\treturn fmt.Errorf(\"IP %s is in a blacklisted range %q\", ip, ipnet)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (m *NetworkManager) onAuthRequired(event *fetch.EventAuthRequired) {\n\tvar (\n\t\tres = fetch.AuthChallengeResponseResponseDefault\n\t\trid = event.RequestID\n\n\t\tusername, password string\n\t)\n\n\tswitch {\n\tcase m.attemptedAuth[rid]:\n\t\tdelete(m.attemptedAuth, rid)\n\t\tres = fetch.AuthChallengeResponseResponseCancelAuth\n\tcase !m.credentials.IsEmpty():\n\t\t// TODO: remove requests from attemptedAuth when:\n\t\t//       - request is redirected\n\t\t//       - loading finished\n\t\tm.attemptedAuth[rid] = true\n\t\tres = fetch.AuthChallengeResponseResponseProvideCredentials\n\t\t// The Fetch.AuthChallengeResponse docs mention username and password should only be set\n\t\t// if the response is ProvideCredentials.\n\t\t// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#type-AuthChallengeResponse\n\t\tusername, password = m.credentials.Username, m.credentials.Password\n\t}\n\terr := fetch.ContinueWithAuth(\n\t\trid,\n\t\t&fetch.AuthChallengeResponse{\n\t\t\tResponse: res,\n\t\t\tUsername: username,\n\t\t\tPassword: password,\n\t\t},\n\t).Do(cdp.WithExecutor(m.ctx, m.session))\n\tif err != nil {\n\t\tm.logger.Debugf(\"NetworkManager:onAuthRequired\", \"continueWithAuth url:%q err:%v\", event.Request.URL, err)\n\t} else {\n\t\tm.logger.Debugf(\"NetworkManager:onAuthRequired\", \"continueWithAuth url:%q OK\", event.Request.URL)\n\t}\n}\n\nfunc (m *NetworkManager) onRequestServedFromCache(event *network.EventRequestServedFromCache) {\n\treq, ok := m.requestFromID(event.RequestID)\n\tif ok {\n\t\treq.setLoadedFromCache(true)\n\t}\n}\n\nfunc (m *NetworkManager) onResponseReceived(event *network.EventResponseReceived) {\n\treq, ok := m.requestFromID(event.RequestID)\n\n\tif !ok {\n\t\treturn\n\t}\n\tresp := NewHTTPResponse(m.ctx, req, event.Response, event.Timestamp)\n\treq.responseMu.Lock()\n\treq.response = resp\n\treq.responseMu.Unlock()\n\n\tm.logger.Debugf(\"FrameManager:onResponseReceived\", \"rid:%s rurl:%s\", event.RequestID, resp.URL())\n\n\tm.eventInterceptor.onResponse(resp)\n}\n\nfunc (m *NetworkManager) requestFromID(reqID network.RequestID) (*Request, bool) {\n\tm.reqsMu.RLock()\n\tdefer m.reqsMu.RUnlock()\n\n\tr, ok := m.reqIDToRequest[reqID]\n\n\treturn r, ok\n}\n\nfunc (m *NetworkManager) willBeSentEventFromReqID(reqID network.RequestID) (*network.EventRequestWillBeSent, bool) {\n\tm.eventsWillBeSentMu.RLock()\n\tdefer m.eventsWillBeSentMu.RUnlock()\n\n\te, ok := m.reqIDToRequestWillBeSentEvent[reqID]\n\n\treturn e, ok\n}\n\nfunc (m *NetworkManager) pausedEventFromReqID(reqID network.RequestID) (*fetch.EventRequestPaused, bool) {\n\tm.eventsPausedMu.RLock()\n\tdefer m.eventsPausedMu.RUnlock()\n\n\te, ok := m.reqIDToRequestPausedEvent[reqID]\n\n\treturn e, ok\n}\n\nfunc (m *NetworkManager) setRequestInterception(value bool) error {\n\tm.userReqInterceptionEnabled = value\n\treturn m.updateProtocolRequestInterception()\n}\n\nfunc (m *NetworkManager) updateProtocolCacheDisabled() error {\n\taction := network.SetCacheDisabled(m.userCacheDisabled)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\terrAction := \"enabling\"\n\t\tif m.userCacheDisabled {\n\t\t\terrAction = \"disabling\"\n\t\t}\n\t\treturn fmt.Errorf(\"%s network cache: %w\", errAction, err)\n\t}\n\treturn nil\n}\n\nfunc (m *NetworkManager) updateProtocolRequestInterception() error {\n\tenabled := m.userReqInterceptionEnabled\n\tif enabled == m.protocolReqInterceptionEnabled {\n\t\treturn nil\n\t}\n\n\tm.protocolReqInterceptionEnabled = enabled\n\tm.logger.Debugf(\"NetworkManager:updateProtocolRequestInterception\",\n\t\t\"updating request interception to %t (session: %s)\", enabled, m.session.ID())\n\n\tactions := []Action{\n\t\tnetwork.SetCacheDisabled(true),\n\t\tfetch.Enable().\n\t\t\tWithHandleAuthRequests(true).\n\t\t\tWithPatterns([]*fetch.RequestPattern{\n\t\t\t\t{\n\t\t\t\t\tURLPattern:   \"*\",\n\t\t\t\t\tRequestStage: fetch.RequestStageRequest,\n\t\t\t\t},\n\t\t\t}),\n\t}\n\tif !enabled {\n\t\tactions = []Action{\n\t\t\tnetwork.SetCacheDisabled(false),\n\t\t\tfetch.Disable(),\n\t\t}\n\t}\n\tfor _, action := range actions {\n\t\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"internal error while updating protocol request interception %T: %w\", action, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Authenticate sets HTTP authentication credentials to use.\nfunc (m *NetworkManager) Authenticate(credentials Credentials) error {\n\tm.credentials = credentials\n\tif !credentials.IsEmpty() {\n\t\tm.userReqInterceptionEnabled = true\n\t}\n\tif err := m.updateProtocolRequestInterception(); err != nil {\n\t\treturn fmt.Errorf(\"setting authentication credentials: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (m *NetworkManager) AbortRequest(requestID fetch.RequestID, errorReason string) error {\n\tm.logger.Debugf(\"NetworkManager:AbortRequest\", \"aborting request (id: %s, errorReason: %s)\",\n\t\trequestID, errorReason)\n\tnetErrorReason, ok := m.errorReasons[errorReason]\n\tif !ok {\n\t\treturn fmt.Errorf(\"unknown error code: %s\", errorReason)\n\t}\n\n\taction := fetch.FailRequest(requestID, netErrorReason)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\t// Avoid logging as error when context is canceled.\n\t\t// Most probably this happens when trying to fail a site's background request\n\t\t// while the iteration is ending and therefore the browser context is being closed.\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\tm.logger.Debug(\"NetworkManager:AbortRequest\", \"context canceled interrupting request\")\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"fail to abort request (id: %s): %w\", requestID, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (m *NetworkManager) ContinueRequest(\n\trequestID fetch.RequestID,\n\topts ContinueOptions,\n\toriginalHeaders []HTTPHeader,\n) error {\n\tm.logger.Debugf(\"NetworkManager:ContinueRequest\", \"continuing request (id: %s)\", requestID)\n\taction := fetch.ContinueRequest(requestID)\n\n\tif len(opts.Headers) > 0 {\n\t\taction = action.WithHeaders(toFetchHeaders(opts.Headers))\n\t}\n\tif opts.URL != \"\" {\n\t\taction = action.WithURL(opts.URL)\n\t}\n\tif opts.Method != \"\" {\n\t\taction = action.WithMethod(opts.Method)\n\t}\n\tif len(opts.PostData) > 0 {\n\t\tb64PostData := base64.StdEncoding.EncodeToString(opts.PostData)\n\t\taction = action.WithPostData(b64PostData)\n\t}\n\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\t// Avoid logging as error when context is canceled.\n\t\t// Most probably this happens when trying to fail a site's background request\n\t\t// while the iteration is ending and therefore the browser context is being closed.\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\tm.logger.Debug(\"NetworkManager:ContinueRequest\", \"context canceled continuing request\")\n\t\t\treturn nil\n\t\t}\n\n\t\t// This error message is an internal issue, rather than something that the user can\n\t\t// action on. It's also usually ok to ignore since it means that the page has navigated\n\t\t// away or something has occurred which means that the request is no longer needed and\n\t\t// isn't being tracked by chromium.\n\t\tif strings.Contains(err.Error(), \"Invalid InterceptionId\") {\n\t\t\tm.logger.Debugf(\"NetworkManager:ContinueRequest\", \"invalid interception ID (%s) continuing request: %s\",\n\t\t\t\trequestID, err)\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"fail to continue request (id: %s): %w\", requestID, err)\n\t}\n\n\treturn nil\n}\n\nfunc (m *NetworkManager) FulfillRequest(request *Request, opts FulfillOptions) error {\n\tresponseCode := int64(http.StatusOK)\n\tif opts.Status != 0 {\n\t\tresponseCode = opts.Status\n\t}\n\n\taction := fetch.FulfillRequest(request.interceptionID, responseCode)\n\n\tif opts.ContentType != \"\" {\n\t\topts.Headers = append(opts.Headers, HTTPHeader{\n\t\t\tName:  \"Content-Type\",\n\t\t\tValue: opts.ContentType,\n\t\t})\n\t}\n\n\theaders := toFetchHeaders(opts.Headers)\n\tif len(headers) > 0 {\n\t\taction = action.WithResponseHeaders(headers)\n\t}\n\n\tif len(opts.Body) > 0 {\n\t\tb64Body := base64.StdEncoding.EncodeToString(opts.Body)\n\t\taction = action.WithBody(b64Body)\n\t}\n\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\t// Avoid logging as error when context is canceled.\n\t\t// Most probably this happens when trying to fail a site's background request\n\t\t// while the iteration is ending and therefore the browser context is being closed.\n\t\tif errors.Is(err, context.Canceled) {\n\t\t\tm.logger.Debug(\"NetworkManager:FulfillRequest\", \"context canceled fulfilling request\")\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"fail to fulfill request (id: %s): %w\",\n\t\t\trequest.interceptionID, err)\n\t}\n\n\treturn nil\n}\n\nfunc toFetchHeaders(headers []HTTPHeader) []*fetch.HeaderEntry {\n\tif len(headers) == 0 {\n\t\treturn nil\n\t}\n\n\tfetchHeaders := make([]*fetch.HeaderEntry, len(headers))\n\tfor i, header := range headers {\n\t\tfetchHeaders[i] = &fetch.HeaderEntry{\n\t\t\tName:  header.Name,\n\t\t\tValue: header.Value,\n\t\t}\n\t}\n\treturn fetchHeaders\n}\n\n// SetExtraHTTPHeaders sets extra HTTP request headers to be sent with every request.\nfunc (m *NetworkManager) SetExtraHTTPHeaders(headers network.Headers) error {\n\terr := network.\n\t\tSetExtraHTTPHeaders(headers).\n\t\tDo(cdp.WithExecutor(m.ctx, m.session))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"setting extra HTTP headers: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// SetOfflineMode toggles offline mode on/off.\nfunc (m *NetworkManager) SetOfflineMode(offline bool) error {\n\tif m.offline == offline {\n\t\treturn nil\n\t}\n\tm.offline = offline\n\n\taction := network.EmulateNetworkConditions(\n\t\tm.offline,\n\t\tm.networkProfile.Latency,\n\t\tm.networkProfile.Download,\n\t\tm.networkProfile.Upload,\n\t)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\treturn fmt.Errorf(\"emulating network conditions: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// ThrottleNetwork changes the network attributes in chrome to simulate slower\n// networks e.g. a slow 3G connection.\nfunc (m *NetworkManager) ThrottleNetwork(networkProfile NetworkProfile) error {\n\tif m.networkProfile == networkProfile {\n\t\treturn nil\n\t}\n\tm.networkProfile = networkProfile\n\n\taction := network.EmulateNetworkConditions(\n\t\tm.offline,\n\t\tm.networkProfile.Latency,\n\t\tm.networkProfile.Download,\n\t\tm.networkProfile.Upload,\n\t)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\treturn fmt.Errorf(\"throttling network: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// SetUserAgent overrides the browser user agent string.\nfunc (m *NetworkManager) SetUserAgent(userAgent string) {\n\taction := emulation.SetUserAgentOverride(userAgent)\n\tif err := action.Do(cdp.WithExecutor(m.ctx, m.session)); err != nil {\n\t\tk6ext.Panicf(m.ctx, \"setting user agent: %w\", err)\n\t}\n}\n\n// SetCacheEnabled toggles cache on/off.\nfunc (m *NetworkManager) SetCacheEnabled(enabled bool) {\n\tm.userCacheDisabled = !enabled\n\tif err := m.updateProtocolCacheDisabled(); err != nil {\n\t\tk6ext.Panicf(m.ctx, \"%v\", err)\n\t}\n}\n\nfunc (m *NetworkManager) wait() {\n\tm.wg.Wait()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/network_manager_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\tk6mockresolver \"go.k6.io/k6/internal/lib/testutils/mockresolver\"\n\tk6lib \"go.k6.io/k6/lib\"\n\tk6types \"go.k6.io/k6/lib/types\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/fetch\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst mockHostname = \"host.test\"\n\ntype fakeSession struct {\n\tsession\n\tcdpCalls []string\n}\n\n// Execute implements the cdp.Executor interface to record calls made to it and\n// allow assertions in tests.\nfunc (s *fakeSession) Execute(\n\tctx context.Context, method string, params, res any,\n) error {\n\ts.cdpCalls = append(s.cdpCalls, method)\n\treturn nil\n}\n\nfunc newTestNetworkManager(t *testing.T, k6opts k6lib.Options) (*NetworkManager, *fakeSession) {\n\tt.Helper()\n\n\tsession := &fakeSession{\n\t\tsession: &Session{\n\t\t\tid: \"1234\",\n\t\t},\n\t}\n\n\tmr := k6mockresolver.New(map[string][]net.IP{\n\t\tmockHostname: {\n\t\t\tnet.ParseIP(\"127.0.0.10\"),\n\t\t\tnet.ParseIP(\"127.0.0.11\"),\n\t\t\tnet.ParseIP(\"127.0.0.12\"),\n\t\t\tnet.ParseIP(\"2001:db8::10\"),\n\t\t\tnet.ParseIP(\"2001:db8::11\"),\n\t\t\tnet.ParseIP(\"2001:db8::12\"),\n\t\t},\n\t})\n\n\tvu := k6test.NewVU(t)\n\tvu.ActivateVU()\n\tctx := vu.Context()\n\tst := vu.State()\n\tst.Options = k6opts\n\tlogger := log.New(st.Logger, \"\")\n\ttimeoutSettings := NewTimeoutSettings(nil)\n\tframeManager := NewFrameManager(ctx, nil, nil, timeoutSettings, logger)\n\n\tnm := &NetworkManager{\n\t\tctx:                           ctx,\n\t\tlogger:                        logger,\n\t\tsession:                       session,\n\t\tframeManager:                  frameManager,\n\t\tresolver:                      mr,\n\t\tvu:                            vu,\n\t\treqIDToRequest:                map[network.RequestID]*Request{},\n\t\treqIDToRequestWillBeSentEvent: make(map[network.RequestID]*network.EventRequestWillBeSent),\n\t\treqIDToRequestPausedEvent:     make(map[network.RequestID]*fetch.EventRequestPaused),\n\t}\n\n\treturn nm, session\n}\n\nfunc TestOnRequestPausedBlockedHostnames(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname, reqURL                  string\n\t\tblockedHostnames, expCDPCalls []string\n\t}{\n\t\t{\n\t\t\tname:             \"ok_fail_simple\",\n\t\t\tblockedHostnames: []string{\"*.test\"},\n\t\t\treqURL:           fmt.Sprintf(\"http://%s/\", mockHostname),\n\t\t\texpCDPCalls:      []string{\"Fetch.failRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"ok_continue_simple\",\n\t\t\tblockedHostnames: []string{\"*.test\"},\n\t\t\treqURL:           \"http://host.com/\",\n\t\t\texpCDPCalls:      []string{\"Fetch.continueRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"ok_continue_empty\",\n\t\t\tblockedHostnames: nil,\n\t\t\treqURL:           \"http://host.com/\",\n\t\t\texpCDPCalls:      []string{\"Fetch.continueRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"ok_continue_ip\",\n\t\t\tblockedHostnames: []string{\"*.test\"},\n\t\t\treqURL:           \"http://127.0.0.1:8000/\",\n\t\t\texpCDPCalls:      []string{\"Fetch.continueRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:             \"err_url_continue\",\n\t\t\tblockedHostnames: []string{\"*.test\"},\n\t\t\treqURL:           \":::\",\n\t\t\texpCDPCalls:      []string{\"Fetch.continueRequest\"},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tblocked, err := k6types.NewNullHostnameTrie(tc.blockedHostnames)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tk6opts := k6lib.Options{BlockedHostnames: blocked}\n\t\t\tnm, session := newTestNetworkManager(t, k6opts)\n\t\t\tev := &fetch.EventRequestPaused{\n\t\t\t\tRequestID: \"1234\",\n\t\t\t\tRequest: &network.Request{\n\t\t\t\t\tMethod: \"GET\",\n\t\t\t\t\tURL:    tc.reqURL,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tnm.onRequestPaused(ev)\n\n\t\t\tassert.Equal(t, tc.expCDPCalls, session.cdpCalls)\n\t\t})\n\t}\n}\n\nfunc TestOnRequestPausedBlockedIPs(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname, reqURL            string\n\t\tblockedIPs, expCDPCalls []string\n\t}{\n\t\t{\n\t\t\tname:        \"ok_fail_simple\",\n\t\t\tblockedIPs:  []string{\"10.0.0.0/8\", \"192.168.0.0/16\"},\n\t\t\treqURL:      \"http://10.0.0.1:8000/\",\n\t\t\texpCDPCalls: []string{\"Fetch.failRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:        \"ok_fail_resolved_ip\",\n\t\t\tblockedIPs:  []string{\"127.0.0.10/32\"},\n\t\t\treqURL:      fmt.Sprintf(\"http://%s/\", mockHostname),\n\t\t\texpCDPCalls: []string{\"Fetch.failRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:        \"ok_continue_resolved_ip\",\n\t\t\tblockedIPs:  []string{\"127.0.0.50/32\"},\n\t\t\treqURL:      fmt.Sprintf(\"http://%s/\", mockHostname),\n\t\t\texpCDPCalls: []string{\"Fetch.continueRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:        \"ok_continue_simple\",\n\t\t\tblockedIPs:  []string{\"127.0.0.0/8\"},\n\t\t\treqURL:      \"http://10.0.0.1:8000/\",\n\t\t\texpCDPCalls: []string{\"Fetch.continueRequest\"},\n\t\t},\n\t\t{\n\t\t\tname:        \"ok_continue_empty\",\n\t\t\tblockedIPs:  nil,\n\t\t\treqURL:      \"http://127.0.0.1/\",\n\t\t\texpCDPCalls: []string{\"Fetch.continueRequest\"},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tblockedIPs := make([]*k6lib.IPNet, len(tc.blockedIPs))\n\t\t\tfor i, ipcidr := range tc.blockedIPs {\n\t\t\t\tipnet, err := k6lib.ParseCIDR(ipcidr)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tblockedIPs[i] = ipnet\n\t\t\t}\n\n\t\t\tk6opts := k6lib.Options{BlacklistIPs: blockedIPs}\n\t\t\tnm, session := newTestNetworkManager(t, k6opts)\n\t\t\tev := &fetch.EventRequestPaused{\n\t\t\t\tRequestID: \"1234\",\n\t\t\t\tRequest: &network.Request{\n\t\t\t\t\tMethod: \"GET\",\n\t\t\t\t\tURL:    tc.reqURL,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tnm.onRequestPaused(ev)\n\n\t\t\tassert.Equal(t, tc.expCDPCalls, session.cdpCalls)\n\t\t})\n\t}\n}\n\ntype EventInterceptorMock struct{}\n\nfunc (m *EventInterceptorMock) urlTagName(_ string, _ string) (string, bool) {\n\treturn \"\", false\n}\n\nfunc (m *EventInterceptorMock) onRequest(_ *Request) {}\n\nfunc (m *EventInterceptorMock) onResponse(_ *Response) {}\n\nfunc (m *EventInterceptorMock) onRequestFinished(_ *Request) {}\n\nfunc (m *EventInterceptorMock) onRequestFailed(_ *Request) {}\n\nfunc TestNetworkManagerEmitRequestResponseMetricsTimingSkew(t *testing.T) {\n\tt.Parallel()\n\n\tnow := time.Now()\n\ttype tm struct{ ts, wt time.Time }\n\ttests := []struct {\n\t\tname                       string\n\t\treq, res, wantReq, wantRes tm\n\t}{\n\t\t{\n\t\t\tname:    \"ok\",\n\t\t\treq:     tm{ts: now, wt: now},\n\t\t\tres:     tm{ts: now, wt: now},\n\t\t\twantReq: tm{wt: now},\n\t\t\twantRes: tm{wt: now},\n\t\t},\n\t\t{\n\t\t\tname:    \"ok2\",\n\t\t\treq:     tm{ts: now, wt: now},\n\t\t\tres:     tm{ts: now.Add(time.Minute)},\n\t\t\twantReq: tm{wt: now},\n\t\t\twantRes: tm{wt: now.Add(time.Minute)},\n\t\t},\n\t\t{\n\t\t\tname:    \"ts_past\",\n\t\t\treq:     tm{ts: now.Add(-time.Hour), wt: now},\n\t\t\tres:     tm{ts: now.Add(-time.Hour).Add(time.Minute)},\n\t\t\twantReq: tm{wt: now},\n\t\t\twantRes: tm{wt: now.Add(time.Minute)},\n\t\t},\n\t\t{\n\t\t\tname:    \"ts_future\",\n\t\t\treq:     tm{ts: now.Add(time.Hour), wt: now},\n\t\t\tres:     tm{ts: now.Add(time.Hour).Add(time.Minute)},\n\t\t\twantReq: tm{wt: now},\n\t\t\twantRes: tm{wt: now.Add(time.Minute)},\n\t\t},\n\t\t{\n\t\t\tname:    \"wt_past\",\n\t\t\treq:     tm{ts: now, wt: now.Add(-time.Hour)},\n\t\t\tres:     tm{ts: now.Add(time.Minute)},\n\t\t\twantReq: tm{wt: now.Add(-time.Hour)},\n\t\t\twantRes: tm{wt: now.Add(-time.Hour).Add(time.Minute)},\n\t\t},\n\t\t{\n\t\t\tname:    \"wt_future\",\n\t\t\treq:     tm{ts: now, wt: now.Add(time.Hour)},\n\t\t\tres:     tm{ts: now.Add(time.Minute)},\n\t\t\twantReq: tm{wt: now.Add(time.Hour)},\n\t\t\twantRes: tm{wt: now.Add(time.Hour).Add(time.Minute)},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tregistry := k6metrics.NewRegistry()\n\t\t\tk6m := k6ext.RegisterCustomMetrics(registry)\n\n\t\t\tvar (\n\t\t\t\tvu = k6test.NewVU(t)\n\t\t\t\tnm = &NetworkManager{ctx: vu.Context(), vu: vu, customMetrics: k6m, eventInterceptor: &EventInterceptorMock{}}\n\t\t\t)\n\t\t\tvu.ActivateVU()\n\n\t\t\treq, err := NewRequest(vu.Context(), log.NewNullLogger(), NewRequestParams{\n\t\t\t\tevent: &network.EventRequestWillBeSent{\n\t\t\t\t\tRequest:   &network.Request{},\n\t\t\t\t\tTimestamp: (*cdp.MonotonicTime)(&tt.req.ts),\n\t\t\t\t\tWallTime:  (*cdp.TimeSinceEpoch)(&tt.req.wt),\n\t\t\t\t},\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\tnm.emitRequestMetrics(req)\n\t\t\tn := vu.AssertSamples(func(s k6metrics.Sample) {\n\t\t\t\tassert.Equalf(t, tt.wantReq.wt, s.Time, \"timing skew in %s\", s.Metric.Name)\n\t\t\t})\n\t\t\tassert.Equalf(t, 1, n, \"should emit %d request metric\", 1)\n\t\t\tres := NewHTTPResponse(vu.Context(), req,\n\t\t\t\t&network.Response{Timing: &network.ResourceTiming{}},\n\t\t\t\t(*cdp.MonotonicTime)(&tt.res.ts),\n\t\t\t)\n\t\t\tnm.emitResponseMetrics(res, req)\n\t\t\tn = vu.AssertSamples(func(s k6metrics.Sample) {\n\t\t\t\tassert.Equalf(t, tt.wantRes.wt, s.Time, \"timing skew in %s\", s.Metric.Name)\n\t\t\t})\n\t\t\tassert.Equalf(t, 3, n, \"should emit 8 response metrics\")\n\t\t})\n\t}\n}\n\nfunc TestRequestForOnLoadingFinished(t *testing.T) {\n\tt.Parallel()\n\n\ttests := map[string]struct {\n\t\tID      network.RequestID\n\t\trequest *Request\n\t\tparent  *Request\n\t\twant    *Request\n\t}{\n\t\t\"non_nil_request\": {\n\t\t\tID: \"1234\",\n\t\t\trequest: &Request{\n\t\t\t\trequestID:  \"1234\",\n\t\t\t\tdocumentID: \"1234\",\n\t\t\t},\n\t\t\twant: &Request{\n\t\t\t\trequestID:  \"1234\",\n\t\t\t\tdocumentID: \"1234\",\n\t\t\t},\n\t\t},\n\t\t\"non_nil_request_with_parent\": {\n\t\t\tID: \"1234\",\n\t\t\trequest: &Request{\n\t\t\t\trequestID:  \"1234\",\n\t\t\t\tdocumentID: \"1234\",\n\t\t\t},\n\t\t\tparent: &Request{\n\t\t\t\tdocumentID: \"3421\",\n\t\t\t},\n\t\t\twant: &Request{\n\t\t\t\trequestID:  \"1234\",\n\t\t\t\tdocumentID: \"1234\",\n\t\t\t},\n\t\t},\n\t\t\"nil_request\": {\n\t\t\trequest: nil,\n\t\t\twant:    nil,\n\t\t},\n\t\t\"nil_request_with_non_nil_parent_with_matching_document_id\": {\n\t\t\tID:      \"1234\",\n\t\t\trequest: nil,\n\t\t\tparent: &Request{\n\t\t\t\trequestID:  \"1234\",\n\t\t\t\tdocumentID: \"1234\",\n\t\t\t},\n\t\t\twant: &Request{\n\t\t\t\trequestID:  \"1234\",\n\t\t\t\tdocumentID: \"1234\",\n\t\t\t},\n\t\t},\n\t\t\"nil_request_with_non_nil_parent_with_non_matching_document_id\": {\n\t\t\tID:      \"1234\",\n\t\t\trequest: nil,\n\t\t\tparent: &Request{\n\t\t\t\trequestID:  \"1234\",\n\t\t\t\tdocumentID: \"4321\",\n\t\t\t},\n\t\t\twant: nil,\n\t\t},\n\t}\n\tfor name, tt := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tnm, _ := newTestNetworkManager(t, k6lib.Options{})\n\t\t\tnm.parent, _ = newTestNetworkManager(t, k6lib.Options{})\n\n\t\t\tif tt.request != nil {\n\t\t\t\ttt.request.requestID = tt.ID\n\t\t\t\tnm.reqIDToRequest[tt.ID] = tt.request\n\t\t\t}\n\t\t\tif tt.parent != nil {\n\t\t\t\tnm.parent.reqIDToRequest[tt.parent.requestID] = tt.parent\n\t\t\t}\n\n\t\t\tr := nm.requestForOnLoadingFinished(tt.ID)\n\t\t\tif tt.want == nil {\n\t\t\t\trequire.Nil(t, r)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NotNil(t, r)\n\t\t\tassert.Equal(t, tt.want, r)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/network_profile.go",
    "content": "package common\n\n// NetworkProfile is used in ThrottleNetwork.\ntype NetworkProfile struct {\n\t// Minimum latency from request sent to response headers received (ms).\n\tLatency float64\n\n\t// Maximal aggregated download throughput (bytes/sec). -1 disables download throttling.\n\tDownload float64\n\n\t// Maximal aggregated upload throughput (bytes/sec). -1 disables upload throttling.\n\tUpload float64\n}\n\n// NewNetworkProfile creates a non-throttled network profile.\nfunc NewNetworkProfile() NetworkProfile {\n\treturn NetworkProfile{\n\t\tLatency:  0,\n\t\tDownload: -1,\n\t\tUpload:   -1,\n\t}\n}\n\n// GetNetworkProfiles returns NetworkProfiles which are ready to be used to\n// throttle the network with page.throttleNetwork.\nfunc GetNetworkProfiles() map[string]NetworkProfile {\n\treturn map[string]NetworkProfile{\n\t\t\"No Throttling\": {\n\t\t\tDownload: -1,\n\t\t\tUpload:   -1,\n\t\t\tLatency:  0,\n\t\t},\n\t\t\"Slow 3G\": {\n\t\t\t// (500 (Kb/s) * 1000 (to bits/s)) / 8 (to bytes/s)) * 0.8 (20% bandwidth loss)\n\t\t\tDownload: ((500 * 1000) / 8) * 0.8,\n\t\t\t// (500 (Kb/s) * 1000 (to bits/s)) / 8 (to bytes/s)) * 0.8 (20% bandwidth loss)\n\t\t\tUpload:  ((500 * 1000) / 8) * 0.8,\n\t\t\tLatency: 400 * 5,\n\t\t},\n\t\t\"Fast 3G\": {\n\t\t\t// ((1.6 (Mb/s) * 1000 (to Kb/s) * 1000 (to bits/s)) / 8 (to bytes/s)) * 0.9 (10% bandwidth loss)\n\t\t\tDownload: ((1.6 * 1000 * 1000) / 8) * 0.9,\n\t\t\t// (750 (Kb/s) * 1000 (to bits/s)) / 8 (to bytes/s)) * 0.9 (10% bandwidth loss)\n\t\t\tUpload:  ((750 * 1000) / 8) * 0.9,\n\t\t\tLatency: 150 * 3.75,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/page.go",
    "content": "package common\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"iter\"\n\t\"net/http\"\n\t\"slices\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/chromedp/cdproto/emulation\"\n\t\"github.com/chromedp/cdproto/page\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/chromedp/cdproto/target\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\n// BlankPage represents a blank page.\nconst BlankPage = \"about:blank\"\n\n// PageEventName represents the name of the page event.\ntype PageEventName string\n\nconst webVitalBinding = \"k6browserSendWebVitalMetric\"\n\nconst (\n\t// PageEventConsole represents the page console event.\n\tPageEventConsole PageEventName = \"console\"\n\n\t// PageEventMetric represents the page metric event.\n\tPageEventMetric PageEventName = \"metric\"\n\n\t// PageEventRequest represents the page request event.\n\tPageEventRequest PageEventName = \"request\"\n\n\t// PageEventResponse represents the page response event.\n\tPageEventResponse PageEventName = \"response\"\n\n\t// PageEventRequestFinished represents the page request finished event.\n\tPageEventRequestFinished PageEventName = \"requestfinished\"\n\n\t// PageEventRequestFailed represents the page requestfailed event.\n\tPageEventRequestFailed PageEventName = \"requestfailed\"\n)\n\n// PageEventHandler is a function type that handles a page on event.\ntype PageEventHandler func(PageEvent) error\n\n// pageEventHandlerRecord is a registered event on a page.\n// The id field is used to identify the handler in the eventHandlers map.\ntype pageEventHandlerRecord struct {\n\tid      uint64\n\thandler PageEventHandler\n}\n\n// MediaType represents the type of media to emulate.\ntype MediaType string\n\nconst (\n\t// MediaTypeScreen represents the screen media type.\n\tMediaTypeScreen MediaType = \"screen\"\n\n\t// MediaTypePrint represents the print media type.\n\tMediaTypePrint MediaType = \"print\"\n)\n\n// ReducedMotion represents a browser reduce-motion setting.\ntype ReducedMotion string\n\n// Valid reduce-motion options.\nconst (\n\tReducedMotionReduce       ReducedMotion = \"reduce\"\n\tReducedMotionNoPreference ReducedMotion = \"no-preference\"\n)\n\nfunc (r ReducedMotion) String() string {\n\treturn reducedMotionToString[r]\n}\n\nvar reducedMotionToString = map[ReducedMotion]string{ //nolint:gochecknoglobals\n\tReducedMotionReduce:       \"reduce\",\n\tReducedMotionNoPreference: \"no-preference\",\n}\n\nvar reducedMotionToID = map[string]ReducedMotion{ //nolint:gochecknoglobals\n\t\"reduce\":        ReducedMotionReduce,\n\t\"no-preference\": ReducedMotionNoPreference,\n}\n\n// MarshalJSON marshals the enum as a quoted JSON string.\nfunc (r ReducedMotion) MarshalJSON() ([]byte, error) {\n\tbuffer := bytes.NewBufferString(`\"`)\n\tbuffer.WriteString(reducedMotionToString[r])\n\tbuffer.WriteString(`\"`)\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON unmarshals a quoted JSON string to the enum value.\nfunc (r *ReducedMotion) UnmarshalJSON(b []byte) error {\n\tvar j string\n\terr := json.Unmarshal(b, &j)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshaling %q to ReducedMotion: %w\", b, err)\n\t}\n\t// Note that if the string cannot be found then it will be set to the zero value.\n\t*r = reducedMotionToID[j]\n\treturn nil\n}\n\n// Screen represents a device screen.\ntype Screen struct {\n\tWidth  int64 `js:\"width\"`\n\tHeight int64 `js:\"height\"`\n}\n\n// ColorScheme represents a browser color scheme.\ntype ColorScheme string\n\n// Valid color schemes.\nconst (\n\tColorSchemeLight        ColorScheme = \"light\"\n\tColorSchemeDark         ColorScheme = \"dark\"\n\tColorSchemeNoPreference ColorScheme = \"no-preference\"\n)\n\nfunc (c ColorScheme) String() string {\n\treturn colorSchemeToString[c]\n}\n\nvar colorSchemeToString = map[ColorScheme]string{ //nolint:gochecknoglobals\n\tColorSchemeLight:        \"light\",\n\tColorSchemeDark:         \"dark\",\n\tColorSchemeNoPreference: \"no-preference\",\n}\n\nvar colorSchemeToID = map[string]ColorScheme{ //nolint:gochecknoglobals\n\t\"light\":         ColorSchemeLight,\n\t\"dark\":          ColorSchemeDark,\n\t\"no-preference\": ColorSchemeNoPreference,\n}\n\n// MarshalJSON marshals the enum as a quoted JSON string.\nfunc (c ColorScheme) MarshalJSON() ([]byte, error) {\n\tbuffer := bytes.NewBufferString(`\"`)\n\tbuffer.WriteString(colorSchemeToString[c])\n\tbuffer.WriteString(`\"`)\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON unmarshals a quoted JSON string to the enum value.\nfunc (c *ColorScheme) UnmarshalJSON(b []byte) error {\n\tvar j string\n\terr := json.Unmarshal(b, &j)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshaling %q to ColorScheme: %w\", b, err)\n\t}\n\t// Note that if the string cannot be found then it will be set to the zero value.\n\t*c = colorSchemeToID[j]\n\treturn nil\n}\n\n// EmulatedSize represents the emulated viewport and screen sizes.\ntype EmulatedSize struct {\n\tViewport Viewport\n\tScreen   Screen\n}\n\n// NewEmulatedSize creates and returns a new EmulatedSize.\nfunc NewEmulatedSize(viewport Viewport, screen Screen) *EmulatedSize {\n\treturn &EmulatedSize{\n\t\tViewport: viewport,\n\t\tScreen:   screen,\n\t}\n}\n\n// ConsoleMessage represents a page console message.\ntype ConsoleMessage struct {\n\t// Args represent the list of arguments passed to a console function call.\n\tArgs []JSHandleAPI\n\n\t// Page is the page that produced the console message, if any.\n\tPage *Page\n\n\t// Text represents the text of the console message.\n\tText string\n\n\t// Type is the type of the console message.\n\t// It can be one of 'log', 'debug', 'info', 'error', 'warning', 'dir', 'dirxml',\n\t// 'table', 'trace', 'clear', 'startGroup', 'startGroupCollapsed', 'endGroup',\n\t// 'assert', 'profile', 'profileEnd', 'count', 'timeEnd'.\n\tType string\n}\n\ntype RouteHandler struct {\n\tpath       string\n\thandler    RouteHandlerCallback\n\turlMatcher patternMatcherFunc\n}\n\nfunc NewRouteHandler(\n\tpath string,\n\thandler RouteHandlerCallback,\n\turlMatcher patternMatcherFunc,\n) *RouteHandler {\n\treturn &RouteHandler{\n\t\tpath:       path,\n\t\thandler:    handler,\n\t\turlMatcher: urlMatcher,\n\t}\n}\n\ntype RouteHandlerCallback func(*Route) error\n\n// Page stores Page/tab related context.\ntype Page struct {\n\tKeyboard    *Keyboard\n\tMouse       *Mouse\n\tTouchscreen *Touchscreen\n\n\tctx       context.Context\n\tcancelCtx context.CancelFunc\n\n\tteardownCtx context.Context\n\n\t// what it really needs is an executor with\n\t// SessionID and TargetID\n\tsession session\n\n\tbrowserCtx      *BrowserContext\n\ttargetID        target.ID\n\topener          *Page\n\tframeManager    *FrameManager\n\ttimeoutSettings *TimeoutSettings\n\n\tjsEnabled bool\n\n\t// protects from race between:\n\t// - Browser.initEvents.onDetachedFromTarget->Page.didClose\n\t// - FrameSession.initEvents.onFrameDetached->FrameManager.frameDetached.removeFramesRecursively->Page.IsClosed\n\tclosedMu sync.RWMutex\n\tclosed   bool\n\n\t// closing serializes Page.Close() so that repeated calls return the\n\t// same result without repeating teardown.\n\tclosingOnce sync.Once\n\tcloseErr    error\n\t// closing is closed when the page begins tearing down.  Checked by\n\t// attachment paths (attachFrameSession) to reject late frame sessions.\n\tclosing chan struct{}\n\n\t// TODO: setter change these fields (mutex?)\n\temulatedSize     *EmulatedSize\n\tmediaType        MediaType\n\tcolorScheme      ColorScheme\n\treducedMotion    ReducedMotion\n\textraHTTPHeaders map[string]string\n\n\tbackgroundPage bool\n\n\teventCh            chan Event\n\teventHandlers      map[PageEventName][]pageEventHandlerRecord\n\teventHandlersMu    sync.RWMutex\n\teventHandlerLastID atomic.Uint64\n\n\tmainFrameSession *FrameSession\n\tframeSessions    map[cdp.FrameID]*FrameSession\n\tframeSessionsMu  sync.RWMutex\n\tworkers          map[target.SessionID]*Worker\n\tworkersMu        sync.Mutex\n\troutes           []*RouteHandler\n\troutesMu         sync.RWMutex\n\n\tlogger *log.Logger\n}\n\n// NewPage creates a new browser page context.\nfunc NewPage(\n\tctx context.Context,\n\ts session,\n\tbctx *BrowserContext,\n\ttid target.ID,\n\topener *Page,\n\tbp bool,\n\tlogger *log.Logger,\n) (*Page, error) {\n\tpageCtx, pageCancel := context.WithCancel(ctx)\n\n\tp := Page{\n\t\tctx:              pageCtx,\n\t\tcancelCtx:        pageCancel,\n\t\tteardownCtx:      bctx.browser.browserCtx,\n\t\tsession:          s,\n\t\tbrowserCtx:       bctx,\n\t\ttargetID:         tid,\n\t\topener:           opener,\n\t\tbackgroundPage:   bp,\n\t\tmediaType:        MediaTypeScreen,\n\t\tcolorScheme:      bctx.opts.ColorScheme,\n\t\treducedMotion:    bctx.opts.ReducedMotion,\n\t\textraHTTPHeaders: bctx.opts.ExtraHTTPHeaders,\n\t\ttimeoutSettings:  NewTimeoutSettings(bctx.timeoutSettings),\n\t\tKeyboard:         NewKeyboard(ctx, s),\n\t\tjsEnabled:        true,\n\t\tclosing:          make(chan struct{}),\n\t\teventCh:          make(chan Event),\n\t\teventHandlers:    make(map[PageEventName][]pageEventHandlerRecord),\n\t\tframeSessions:    make(map[cdp.FrameID]*FrameSession),\n\t\tworkers:          make(map[target.SessionID]*Worker),\n\t\tlogger:           logger,\n\t}\n\n\tp.logger.Debugf(\"Page:NewPage\", \"sid:%v tid:%v backgroundPage:%t\",\n\t\tp.sessionID(), tid, bp)\n\n\t// We need to init viewport and screen size before initializing the main frame session,\n\t// as that's where the emulation is activated.\n\tif !bctx.opts.Viewport.IsEmpty() {\n\t\tp.emulatedSize = NewEmulatedSize(bctx.opts.Viewport, bctx.opts.Screen)\n\t}\n\n\tvar err error\n\tp.frameManager = NewFrameManager(ctx, s, &p, p.timeoutSettings, p.logger)\n\tp.mainFrameSession, err = NewFrameSession(p.ctx, p.teardownCtx, s, &p, nil, tid, p.logger, true)\n\tif err != nil {\n\t\tp.logger.Debugf(\"Page:NewPage:NewFrameSession:return\", \"sid:%v tid:%v err:%v\",\n\t\t\tp.sessionID(), tid, err)\n\n\t\treturn nil, err\n\t}\n\tp.frameSessionsMu.Lock()\n\tp.frameSessions[cdp.FrameID(tid)] = p.mainFrameSession\n\tp.frameSessionsMu.Unlock()\n\tp.Mouse = NewMouse(ctx, s, p.frameManager.MainFrame(), bctx.timeoutSettings, p.Keyboard)\n\tp.Touchscreen = NewTouchscreen(ctx, s, p.Keyboard)\n\n\tp.initEvents()\n\n\taction := target.SetAutoAttach(true, true).WithFlatten(true)\n\tif err := action.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"internal error while auto attaching to browser pages: %w\", err)\n\t}\n\n\tadd := runtime.AddBinding(webVitalBinding)\n\tif err := add.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"internal error while adding binding to page: %w\", err)\n\t}\n\n\tif err := bctx.applyAllInitScripts(&p); err != nil {\n\t\treturn nil, fmt.Errorf(\"internal error while applying init scripts to page: %w\", err)\n\t}\n\n\treturn &p, nil\n}\n\nfunc (p *Page) initEvents() {\n\tp.logger.Debugf(\"Page:initEvents\",\n\t\t\"sid:%v tid:%v\", p.session.ID(), p.targetID)\n\n\tevents := []string{\n\t\tcdproto.EventRuntimeConsoleAPICalled,\n\t}\n\tp.session.on(p.ctx, events, p.eventCh)\n\n\tgo func() {\n\t\tp.logger.Debugf(\"Page:initEvents:go\",\n\t\t\t\"sid:%v tid:%v\", p.session.ID(), p.targetID)\n\t\tdefer func() {\n\t\t\tp.logger.Debugf(\"Page:initEvents:go:return\",\n\t\t\t\t\"sid:%v tid:%v\", p.session.ID(), p.targetID)\n\t\t}()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-p.session.Done():\n\t\t\t\tp.logger.Debugf(\"Page:initEvents:go:session.done\",\n\t\t\t\t\t\"sid:%v tid:%v\", p.session.ID(), p.targetID)\n\t\t\t\treturn\n\t\t\tcase <-p.ctx.Done():\n\t\t\t\tp.logger.Debugf(\"Page:initEvents:go:ctx.Done\",\n\t\t\t\t\t\"sid:%v tid:%v\", p.session.ID(), p.targetID)\n\t\t\t\treturn\n\t\t\tcase event := <-p.eventCh:\n\t\t\t\tif ev, ok := event.data.(*runtime.EventConsoleAPICalled); ok {\n\t\t\t\t\tp.onConsoleAPICalled(ev)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n}\n\n// MetricEvent is the type that is exported to JS. It is currently only used to\n// match on the urlTag and return a name when a match is found.\ntype MetricEvent struct {\n\t// The URL value from the metric's url tag. It will be used to match\n\t// against the URL grouping regexs.\n\turl string\n\t// The method of the request made to the URL.\n\tmethod string\n\n\t// When a match is found this userProvidedURLTagName field should be updated.\n\tuserProvidedURLTagName string\n\n\t// When a match is found this is set to true.\n\tisUserURLTagNameExist bool\n}\n\n// TagMatches contains the name tag and matches used to match against existing\n// metric tags that are about to be emitted.\ntype TagMatches struct {\n\t// The name to send back to the caller of the handler.\n\tTagName string `js:\"name\"`\n\t// The patterns to match against.\n\tMatches []Match `js:\"matches\"`\n}\n\n// Match contains the fields that will be used to match against metric tags\n// that are about to be emitted.\ntype Match struct {\n\t// This is a regex that will be compared against the existing url tag.\n\tURLRegEx string `js:\"url\"`\n\t// This is the request method to match on.\n\tMethod string `js:\"method\"`\n}\n\n// Tag will find the first match given the URLTagPatterns and the URL from\n// the metric tag and update the name field.\nfunc (e *MetricEvent) Tag(rm RegExMatcher, matches TagMatches) error {\n\tname := strings.TrimSpace(matches.TagName)\n\tif name == \"\" {\n\t\treturn fmt.Errorf(\"name %q is invalid\", matches.TagName)\n\t}\n\n\tfor _, m := range matches.Matches {\n\t\t// Validate the request method type if it has been assigned in a Match.\n\t\tmethod := strings.TrimSpace(m.Method)\n\t\tif method != \"\" {\n\t\t\tmethod = strings.ToUpper(method)\n\t\t\tswitch method {\n\t\t\tcase http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete, http.MethodPatch,\n\t\t\t\thttp.MethodHead, http.MethodOptions, http.MethodConnect, http.MethodTrace:\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"method %q is invalid\", m.Method)\n\t\t\t}\n\n\t\t\tif method != e.method {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// matchesRegex is a function that will perform the regex test in the Sobek\n\t\t// runtime.\n\t\tmatched, err := rm(m.URLRegEx, e.url)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif matched {\n\t\t\te.isUserURLTagNameExist = true\n\t\t\te.userProvidedURLTagName = name\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// urlTagName is used to match the given url with the matches defined by the\n// user. Currently matches only contains url. When a match is found a user\n// defined name, which is to be used in the urls place in the url metric tag,\n// is returned.\n//\n// The check is done by calling the handlers that were registered with\n// `page.on('metric')`. The user will need to use `Tag` to supply the\n// url regexes and the matching is done from within there. If a match is found,\n// the supplied name is returned back upstream to the caller of urlTagName.\nfunc (p *Page) urlTagName(url string, method string) (string, bool) {\n\tvar (\n\t\ttag         string\n\t\tmatched     bool\n\t\tmetricEvent = &MetricEvent{url: url, method: method}\n\t)\n\n\tfor handle := range p.eventHandlersByName(PageEventMetric) {\n\t\tif err := handle(PageEvent{Metric: metricEvent}); err != nil {\n\t\t\tp.logger.Debugf(\"urlTagName\", \"handler returned an error: %v\", err)\n\t\t\treturn \"\", false\n\t\t}\n\t}\n\n\t// If a match was found then the name field in em will have been updated.\n\tif metricEvent.isUserURLTagNameExist {\n\t\ttag = metricEvent.userProvidedURLTagName\n\t\tmatched = true\n\t}\n\tp.logger.Debugf(\"urlTagName\", \"name: %q nameChanged: %v\", tag, matched)\n\n\treturn tag, matched\n}\n\n// onRequest calls [PageEventRequest] handlers after each request is made.\nfunc (p *Page) onRequest(request *Request) {\n\tfor handle := range p.eventHandlersByName(PageEventRequest) {\n\t\tif err := handle(PageEvent{Request: request}); err != nil {\n\t\t\tp.logger.Warnf(\"onRequest\", \"handler returned an error: %v\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// onResponse will call the handlers for the page.on('response') event.\nfunc (p *Page) onResponse(resp *Response) {\n\tfor handle := range p.eventHandlersByName(PageEventResponse) {\n\t\tif err := handle(PageEvent{Response: resp}); err != nil {\n\t\t\tp.logger.Warnf(\"onResponse\", \"handler returned an error: %v\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// onRequestFinished calls [PageEventRequestFinished] handlers when a request completes successfully.\nfunc (p *Page) onRequestFinished(request *Request) {\n\tfor handle := range p.eventHandlersByName(PageEventRequestFinished) {\n\t\tif err := handle(PageEvent{Request: request}); err != nil {\n\t\t\tp.logger.Warnf(\"onRequestFinished\", \"handler returned an error: %v\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// onRequestFailed will call the handlers for the page.on('requestfailed') event.\nfunc (p *Page) onRequestFailed(request *Request) {\n\tfor handle := range p.eventHandlersByName(PageEventRequestFailed) {\n\t\tif err := handle(PageEvent{Request: request}); err != nil {\n\t\t\tp.logger.Warnf(\"onRequestFailed\", \"handler returned an error: %v\", err)\n\t\t}\n\t}\n}\n\nfunc (p *Page) onConsoleAPICalled(event *runtime.EventConsoleAPICalled) {\n\tif !p.hasEventHandler(PageEventConsole) {\n\t\treturn\n\t}\n\tcm, err := p.consoleMsgFromConsoleEvent(event)\n\tif err != nil {\n\t\tp.logger.Errorf(\"Page:onConsoleAPICalled\", \"building console message: %v\", err)\n\t\treturn\n\t}\n\tfor handle := range p.eventHandlersByName(PageEventConsole) {\n\t\tif err := handle(PageEvent{ConsoleMessage: cm}); err != nil {\n\t\t\tp.logger.Debugf(\"onConsoleAPICalled\", \"handler returned an error: %v\", err)\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (p *Page) consoleMsgFromConsoleEvent(e *runtime.EventConsoleAPICalled) (*ConsoleMessage, error) {\n\texecCtx, err := p.executionContextForID(e.ExecutionContextID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar (\n\t\tobjects       = make([]string, 0, len(e.Args))\n\t\tobjectHandles = make([]JSHandleAPI, 0, len(e.Args))\n\t)\n\n\tfor _, robj := range e.Args {\n\t\ts, err := parseConsoleRemoteObject(p.logger, robj)\n\t\tif err != nil {\n\t\t\tp.logger.Errorf(\"consoleMsgFromConsoleEvent\", \"failed to parse console message %v\", err)\n\t\t}\n\n\t\tobjects = append(objects, s)\n\t\tobjectHandles = append(objectHandles, NewJSHandle(\n\t\t\tp.ctx, p.session, execCtx, execCtx.Frame(), robj, p.logger,\n\t\t))\n\t}\n\n\treturn &ConsoleMessage{\n\t\tArgs: objectHandles,\n\t\tPage: p,\n\t\tText: textForConsoleEvent(e, objects),\n\t\tType: e.Type.String(),\n\t}, nil\n}\n\nfunc (p *Page) addWorker(sessionID target.SessionID, w *Worker) {\n\tp.logger.Debugf(\"Page:addWorker\", \"sid:%v\", sessionID)\n\n\tp.workersMu.Lock()\n\tdefer p.workersMu.Unlock()\n\tp.workers[sessionID] = w\n}\n\nfunc (p *Page) removeWorker(sessionID target.SessionID) {\n\tp.logger.Debugf(\"Page:removeWorker\", \"sid:%v\", sessionID)\n\n\tp.workersMu.Lock()\n\tdefer p.workersMu.Unlock()\n\tdelete(p.workers, sessionID)\n}\n\nfunc (p *Page) defaultTimeout() time.Duration {\n\treturn p.timeoutSettings.timeout()\n}\n\nfunc (p *Page) didClose() {\n\tp.logger.Debugf(\"Page:didClose\", \"sid:%v\", p.sessionID())\n\n\tp.closedMu.Lock()\n\t{\n\t\tp.closed = true\n\t}\n\tp.closedMu.Unlock()\n}\n\nfunc (p *Page) evaluateOnNewDocument(source string) error {\n\tp.logger.Debugf(\"Page:evaluateOnNewDocument\", \"sid:%v\", p.sessionID())\n\n\taction := page.AddScriptToEvaluateOnNewDocument(source)\n\t_, err := action.Do(cdp.WithExecutor(p.ctx, p.session))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"evaluating script on document: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc (p *Page) getFrameElement(f *Frame) (handle *ElementHandle, _ error) {\n\tif f == nil {\n\t\tp.logger.Debugf(\"Page:getFrameElement\", \"sid:%v frame:nil\", p.sessionID())\n\t} else {\n\t\tp.logger.Debugf(\"Page:getFrameElement\", \"sid:%v fid:%s furl:%s\",\n\t\t\tp.sessionID(), f.ID(), f.URL())\n\t}\n\n\tparent := f.parentFrame\n\tif parent == nil {\n\t\treturn nil, errors.New(\"frame has been detached 1\")\n\t}\n\n\trootFrame := f\n\tfor ; rootFrame.parentFrame != nil; rootFrame = rootFrame.parentFrame {\n\t}\n\n\tparentSession, ok := p.getFrameSession(cdp.FrameID(rootFrame.ID()))\n\tif !ok {\n\t\treturn nil, errors.New(\"parent frame has been detached\")\n\t}\n\n\taction := dom.GetFrameOwner(cdp.FrameID(f.ID()))\n\tbackendNodeID, _, err := action.Do(cdp.WithExecutor(p.ctx, parentSession.session))\n\tif err != nil {\n\t\tif strings.Contains(err.Error(), \"frame with the given id was not found\") {\n\t\t\treturn nil, errors.New(\"frame has been detached\")\n\t\t}\n\t\treturn nil, fmt.Errorf(\"getting frame owner: %w\", err)\n\t}\n\n\tparent = f.parentFrame\n\tif parent == nil {\n\t\treturn nil, errors.New(\"frame has been detached 2\")\n\t}\n\treturn parent.adoptBackendNodeID(mainWorld, backendNodeID)\n}\n\nfunc (p *Page) getOwnerFrame(apiCtx context.Context, h *ElementHandle) (cdp.FrameID, error) {\n\tp.logger.Debugf(\"Page:getOwnerFrame\", \"sid:%v\", p.sessionID())\n\n\t// document.documentElement has frameId of the owner frame\n\tpageFn := `\n\t\tnode => {\n\t\t\tconst doc = node;\n      \t\tif (doc.documentElement && doc.documentElement.ownerDocument === doc)\n        \t\treturn doc.documentElement;\n      \t\treturn node.ownerDocument ? node.ownerDocument.documentElement : null;\n\t\t}\n\t`\n\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: false,\n\t}\n\tresult, err := h.execCtx.eval(apiCtx, opts, pageFn, h)\n\tif err != nil {\n\t\tp.logger.Debugf(\"Page:getOwnerFrame:return\", \"sid:%v err:%v\", p.sessionID(), err)\n\t\treturn \"\", nil\n\t}\n\tswitch result.(type) { //nolint:gocritic\n\tcase nil:\n\t\tp.logger.Debugf(\"Page:getOwnerFrame:return\", \"sid:%v result:nil\", p.sessionID())\n\t\treturn \"\", nil\n\t}\n\n\tdocumentElement := result.(*ElementHandle) //nolint:forcetypeassert\n\tif documentElement == nil {\n\t\tp.logger.Debugf(\"Page:getOwnerFrame:return\", \"sid:%v docel:nil\", p.sessionID())\n\t\treturn \"\", nil\n\t}\n\tif documentElement.remoteObject.ObjectID == \"\" {\n\t\tp.logger.Debugf(\"Page:getOwnerFrame:return\", \"sid:%v robjid:%q\", p.sessionID(), \"\")\n\t\treturn \"\", nil\n\t}\n\n\taction := dom.DescribeNode().WithObjectID(documentElement.remoteObject.ObjectID)\n\t// If the element is in an iframe, then using the page's session will not\n\t// contain the element that we're looking for since frames do not\n\t// share context between each other due to CORS.\n\t//\n\t// Instead here we use the element's session to retrieve the description of\n\t// itself, which works even when we're handling elements that are not in\n\t// an iframe.\n\tnode, err := action.Do(cdp.WithExecutor(p.ctx, h.session))\n\tif err != nil {\n\t\tp.logger.Debugf(\"Page:getOwnerFrame:DescribeNode:return\", \"sid:%v err:%v\", p.sessionID(), err)\n\t\treturn \"\", nil\n\t}\n\n\tif node == nil {\n\t\tp.logger.Debugf(\"Page:getOwnerFrame:node:nil:return\", \"sid:%v err:%v\", p.sessionID(), err)\n\t\treturn \"\", nil\n\t}\n\n\tframeID := node.FrameID\n\tif err := documentElement.Dispose(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"disposing document element while getting owner frame: %w\", err)\n\t}\n\n\treturn frameID, nil\n}\n\n// errPageClosing is returned when a frame-session attachment is rejected\n// because the page has started closing.\nvar errPageClosing = errors.New(\"page is closing\")\n\nfunc (p *Page) attachFrameSession(fid cdp.FrameID, fs *FrameSession) error {\n\tp.logger.Debugf(\"Page:attachFrameSession\", \"sid:%v fid=%v\", p.session.ID(), fid)\n\n\tif fs == nil {\n\t\treturn errors.New(\"internal error: FrameSession is nil\")\n\t}\n\n\t// This prevents a TOCTOU race where Close() snapshots owned sessions\n\t// and then a new session is inserted outside that snapshot.\n\tp.frameSessionsMu.Lock()\n\tdefer p.frameSessionsMu.Unlock()\n\n\tif p.isClosing() {\n\t\tp.logger.Debugf(\"Page:attachFrameSession\", \"rejected fid=%v: page is closing\", fid)\n\t\treturn errPageClosing\n\t}\n\n\tp.frameSessions[fid] = fs\n\n\treturn nil\n}\n\n// waitForFrameSessions waits for every FrameSession's event goroutine\n// (and transitively its NetworkManager goroutines) to finish.\nfunc (p *Page) waitForFrameSessions() {\n\tp.frameSessionsMu.RLock()\n\tsessions := make([]*FrameSession, 0, len(p.frameSessions))\n\tfor _, fs := range p.frameSessions {\n\t\tsessions = append(sessions, fs)\n\t}\n\tp.frameSessionsMu.RUnlock()\n\tfor _, fs := range sessions {\n\t\tfs.wait()\n\t}\n}\n\nfunc (p *Page) getFrameSession(frameID cdp.FrameID) (*FrameSession, bool) {\n\tp.logger.Debugf(\"Page:getFrameSession\", \"sid:%v fid:%v\", p.sessionID(), frameID)\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tv, ok := p.frameSessions[frameID]\n\n\treturn v, ok\n}\n\nfunc (p *Page) hasRoutes() bool {\n\tp.routesMu.RLock()\n\tdefer p.routesMu.RUnlock()\n\n\treturn len(p.routes) > 0\n}\n\nfunc (p *Page) resetViewport() error {\n\tp.logger.Debugf(\"Page:resetViewport\", \"sid:%v\", p.sessionID())\n\n\taction := emulation.SetDeviceMetricsOverride(0, 0, 0, false)\n\treturn action.Do(cdp.WithExecutor(p.ctx, p.session))\n}\n\nfunc (p *Page) setEmulatedSize(emulatedSize *EmulatedSize) error {\n\tp.logger.Debugf(\"Page:setEmulatedSize\", \"sid:%v\", p.sessionID())\n\n\tp.emulatedSize = emulatedSize\n\treturn p.mainFrameSession.updateViewport()\n}\n\nfunc (p *Page) setViewportSize(viewportSize *Size) error {\n\tp.logger.Debugf(\"Page:setViewportSize\", \"sid:%v vps:%v\",\n\t\tp.sessionID(), viewportSize)\n\n\tviewport := Viewport{\n\t\tWidth:  int64(viewportSize.Width),\n\t\tHeight: int64(viewportSize.Height),\n\t}\n\tscreen := Screen{\n\t\tWidth:  int64(viewportSize.Width),\n\t\tHeight: int64(viewportSize.Height),\n\t}\n\treturn p.setEmulatedSize(NewEmulatedSize(viewport, screen))\n}\n\nfunc (p *Page) updateExtraHTTPHeaders() error {\n\tp.logger.Debugf(\"Page:updateExtraHTTPHeaders\", \"sid:%v\", p.sessionID())\n\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tfor _, fs := range p.frameSessions {\n\t\tif err := fs.updateExtraHTTPHeaders(false); err != nil {\n\t\t\treturn fmt.Errorf(\"updating extra HTTP headers: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *Page) updateGeolocation() error {\n\tp.logger.Debugf(\"Page:updateGeolocation\", \"sid:%v\", p.sessionID())\n\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tfor _, fs := range p.frameSessions {\n\t\tp.logger.Debugf(\"Page:updateGeolocation:frameSession\",\n\t\t\t\"sid:%v tid:%v wid:%v\",\n\t\t\tp.sessionID(), fs.targetID, fs.windowID)\n\n\t\tif err := fs.updateGeolocation(false); err != nil {\n\t\t\tp.logger.Debugf(\"Page:updateGeolocation:frameSession:return\",\n\t\t\t\t\"sid:%v tid:%v wid:%v err:%v\",\n\t\t\t\tp.sessionID(), fs.targetID, fs.windowID, err)\n\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *Page) updateOffline() error {\n\tp.logger.Debugf(\"Page:updateOffline\", \"sid:%v\", p.sessionID())\n\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tfor _, fs := range p.frameSessions {\n\t\tif err := fs.updateOffline(false); err != nil {\n\t\t\treturn fmt.Errorf(\"updating page frame sessions to offline: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *Page) updateHTTPCredentials() error {\n\tp.logger.Debugf(\"Page:updateHttpCredentials\", \"sid:%v\", p.sessionID())\n\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tfor _, fs := range p.frameSessions {\n\t\tif err := fs.updateHTTPCredentials(false); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *Page) viewportSize() Size {\n\treturn Size{\n\t\tWidth:  float64(p.emulatedSize.Viewport.Width),\n\t\tHeight: float64(p.emulatedSize.Viewport.Height),\n\t}\n}\n\n// BringToFront activates the browser tab for this page.\nfunc (p *Page) BringToFront() error {\n\tp.logger.Debugf(\"Page:BringToFront\", \"sid:%v\", p.sessionID())\n\n\taction := page.BringToFront()\n\tif err := action.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {\n\t\treturn fmt.Errorf(\"bringing page to front: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// SetChecked sets the checked state of the element matching the provided selector.\nfunc (p *Page) SetChecked(selector string, checked bool, popts *FrameCheckOptions) error {\n\tp.logger.Debugf(\"Page:SetChecked\", \"sid:%v selector:%s checked:%t\", p.sessionID(), selector, checked)\n\n\treturn p.MainFrame().SetChecked(selector, checked, popts)\n}\n\n// Check checks an element matching the provided selector.\nfunc (p *Page) Check(selector string, popts *FrameCheckOptions) error {\n\tp.logger.Debugf(\"Page:Check\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Check(selector, popts)\n}\n\n// Uncheck unchecks an element matching the provided selector.\nfunc (p *Page) Uncheck(selector string, popts *FrameUncheckOptions) error {\n\tp.logger.Debugf(\"Page:Uncheck\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Uncheck(selector, popts)\n}\n\n// IsChecked returns true if the first element that matches the selector\n// is checked. Otherwise, returns false.\nfunc (p *Page) IsChecked(selector string, opts *FrameIsCheckedOptions) (bool, error) {\n\tp.logger.Debugf(\"Page:IsChecked\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().IsChecked(selector, opts)\n}\n\n// Click clicks an element matching provided selector.\nfunc (p *Page) Click(selector string, opts *FrameClickOptions) error {\n\tp.logger.Debugf(\"Page:Click\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Click(selector, opts)\n}\n\n// isClosing reports whether the page has started closing.\nfunc (p *Page) isClosing() bool {\n\tselect {\n\tcase <-p.closing:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// Close closes the page. It is safe to call multiple times; only the\n// first call performs the teardown and subsequent calls return the same result.\nfunc (p *Page) Close() error {\n\tp.logger.Debugf(\"Page:Close\", \"sid:%v\", p.sessionID())\n\n\tp.closingOnce.Do(func() {\n\t\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.close\")\n\t\tdefer span.End()\n\n\t\tclose(p.closing)\n\n\t\tteardownTimeoutCtx, closeCancel := context.WithTimeout(p.teardownCtx, p.defaultTimeout())\n\t\tdefer closeCancel()\n\n\t\t// forcing the pagehide event to trigger web vitals metrics.\n\t\tv := `() => window.dispatchEvent(new Event('pagehide'))`\n\t\t_, err := p.MainFrame().EvaluateWithContext(teardownTimeoutCtx, v)\n\t\tif err != nil {\n\t\t\tp.logger.Warnf(\"Page:Close\", \"failed to hide page: %v\", err)\n\t\t}\n\n\t\tvar closeErrs []error\n\n\t\tadd := runtime.RemoveBinding(webVitalBinding)\n\t\tif err := add.Do(cdp.WithExecutor(teardownTimeoutCtx, p.session)); err != nil {\n\t\t\t// continue so that we can shutdown the page even if we fail to remove the binding.\n\t\t\tcloseErrs = append(closeErrs, fmt.Errorf(\"internal error while removing binding from page: %w\", err))\n\t\t}\n\n\t\terr = target.CloseTarget(p.targetID).Do(cdp.WithExecutor(teardownTimeoutCtx, p.session))\n\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t// When a close target command is sent to the browser via CDP,\n\t\t\t// the browser will start to cleanup and the first thing it\n\t\t\t// will do is return a target.EventDetachedFromTarget, which in\n\t\t\t// our implementation will close the session connection (this\n\t\t\t// does not close the CDP websocket, just removes the session\n\t\t\t// so no other CDP calls can be made with the session ID).\n\t\t\t// This can result in the session's context being closed while\n\t\t\t// we're waiting for the response to come back from the browser\n\t\t\t// for this current command (it's racey).\n\t\t\tcloseErrs = append(closeErrs, fmt.Errorf(\"closing a page: %w\", err))\n\t\t}\n\n\t\t// Start the teardown of the page's resources (FrameSessions, NetworkManagers, etc)\n\t\t// and wait for them to finish their teardown. This allows for a graceful cleanup\n\t\t// of resources and ensures that all events are processed before the page is closed.\n\t\tp.cancelCtx()\n\t\tp.waitForFrameSessions()\n\n\t\tif len(closeErrs) > 0 {\n\t\t\tp.closeErr = spanRecordError(span, errors.Join(closeErrs...))\n\t\t}\n\t})\n\n\treturn p.closeErr\n}\n\n// Content returns the HTML content of the page.\nfunc (p *Page) Content() (string, error) {\n\tp.logger.Debugf(\"Page:Content\", \"sid:%v\", p.sessionID())\n\n\treturn p.MainFrame().Content()\n}\n\n// Context closes the page.\nfunc (p *Page) Context() *BrowserContext {\n\treturn p.browserCtx\n}\n\n// Dblclick double clicks an element matching provided selector.\nfunc (p *Page) Dblclick(selector string, popts *FrameDblclickOptions) error {\n\tp.logger.Debugf(\"Page:Dblclick\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Dblclick(selector, popts)\n}\n\n// DispatchEvent dispatches an event on the page to the element that matches the provided selector.\nfunc (p *Page) DispatchEvent(selector string, typ string, eventInit any, opts *FrameDispatchEventOptions) error {\n\tp.logger.Debugf(\"Page:DispatchEvent\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().DispatchEvent(selector, typ, eventInit, opts)\n}\n\n// EmulateMedia emulates the given media type.\nfunc (p *Page) EmulateMedia(popts *PageEmulateMediaOptions) error {\n\tp.logger.Debugf(\"Page:EmulateMedia\", \"sid:%v\", p.sessionID())\n\n\tp.mediaType = popts.Media\n\tp.colorScheme = popts.ColorScheme\n\tp.reducedMotion = popts.ReducedMotion\n\n\tp.frameSessionsMu.RLock()\n\tfor _, fs := range p.frameSessions {\n\t\tif err := fs.updateEmulateMedia(); err != nil {\n\t\t\tp.frameSessionsMu.RUnlock()\n\t\t\treturn fmt.Errorf(\"emulating media: %w\", err)\n\t\t}\n\t}\n\tp.frameSessionsMu.RUnlock()\n\n\tapplySlowMo(p.ctx)\n\n\treturn nil\n}\n\n// EmulateVisionDeficiency activates/deactivates emulation of a vision deficiency.\nfunc (p *Page) EmulateVisionDeficiency(typ string) error {\n\tp.logger.Debugf(\"Page:EmulateVisionDeficiency\", \"sid:%v typ:%s\", p.sessionID(), typ)\n\n\tvalidTypes := map[string]emulation.SetEmulatedVisionDeficiencyType{\n\t\t\"achromatopsia\": emulation.SetEmulatedVisionDeficiencyTypeAchromatopsia,\n\t\t\"blurredVision\": emulation.SetEmulatedVisionDeficiencyTypeBlurredVision,\n\t\t\"deuteranopia\":  emulation.SetEmulatedVisionDeficiencyTypeDeuteranopia,\n\t\t\"none\":          emulation.SetEmulatedVisionDeficiencyTypeNone,\n\t\t\"protanopia\":    emulation.SetEmulatedVisionDeficiencyTypeProtanopia,\n\t\t\"tritanopia\":    emulation.SetEmulatedVisionDeficiencyTypeTritanopia,\n\t}\n\tt, ok := validTypes[typ]\n\tif !ok {\n\t\treturn fmt.Errorf(\"unsupported vision deficiency: %s\", typ)\n\t}\n\n\taction := emulation.SetEmulatedVisionDeficiency(t)\n\tif err := action.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {\n\t\treturn fmt.Errorf(\"setting emulated vision deficiency %q: %w\", typ, err)\n\t}\n\n\tapplySlowMo(p.ctx)\n\n\treturn nil\n}\n\n// Evaluate runs JS code within the execution context of the main frame of the page.\nfunc (p *Page) Evaluate(pageFunc string, args ...any) (any, error) {\n\tp.logger.Debugf(\"Page:Evaluate\", \"sid:%v\", p.sessionID())\n\n\treturn p.MainFrame().Evaluate(pageFunc, args...)\n}\n\n// EvaluateHandle runs JS code within the execution context of the main frame of the page.\nfunc (p *Page) EvaluateHandle(pageFunc string, args ...any) (JSHandleAPI, error) {\n\tp.logger.Debugf(\"Page:EvaluateHandle\", \"sid:%v\", p.sessionID())\n\n\th, err := p.MainFrame().EvaluateHandle(pageFunc, args...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating handle for page: %w\", err)\n\t}\n\treturn h, nil\n}\n\n// Fill fills an input element with the provided value.\nfunc (p *Page) Fill(selector string, value string, popts *FrameFillOptions) error {\n\tp.logger.Debugf(\"Page:Fill\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Fill(selector, value, popts)\n}\n\n// Focus focuses an element matching the provided selector.\nfunc (p *Page) Focus(selector string, popts *FrameBaseOptions) error {\n\tp.logger.Debugf(\"Page:Focus\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Focus(selector, popts)\n}\n\n// Frames returns a list of frames on the page.\nfunc (p *Page) Frames() []*Frame {\n\treturn p.frameManager.Frames()\n}\n\n// GetAttribute returns the attribute value of the element matching the provided selector.\n// The second return value is true if the attribute exists, and false otherwise.\nfunc (p *Page) GetAttribute(selector string, name string, popts *FrameBaseOptions) (string, bool, error) {\n\tp.logger.Debugf(\"Page:GetAttribute\", \"sid:%v selector:%s name:%s\",\n\t\tp.sessionID(), selector, name)\n\n\treturn p.MainFrame().GetAttribute(selector, name, popts)\n}\n\n// GetByRole creates and returns a new locator for this page (main frame) based on their ARIA role.\nfunc (p *Page) GetByRole(role string, opts *GetByRoleOptions) *Locator {\n\tp.logger.Debugf(\"Page:GetByRole\", \"sid:%s role: %q opts:%+v\", p.sessionID(), role, opts)\n\n\treturn p.MainFrame().GetByRole(role, opts)\n}\n\n// GetByAltText creates and returns a new locator for this page (main frame)\n// based on the alt attribute text.\nfunc (p *Page) GetByAltText(alt string, opts *GetByBaseOptions) *Locator {\n\tp.logger.Debugf(\"Page:GetByAltText\", \"sid:%s alt: %q opts:%+v\", p.sessionID(), alt, opts)\n\n\treturn p.MainFrame().GetByAltText(alt, opts)\n}\n\n// GetByLabel creates and returns a new locator for this page (main frame) based on the label text.\nfunc (p *Page) GetByLabel(label string, opts *GetByBaseOptions) *Locator {\n\tp.logger.Debugf(\"Page:GetByLabel\", \"sid:%s label: %q opts:%+v\", p.sessionID(), label, opts)\n\n\treturn p.MainFrame().GetByLabel(label, opts)\n}\n\n// GetByPlaceholder creates and returns a new locator for this page (main frame) based on the placeholder attribute.\nfunc (p *Page) GetByPlaceholder(placeholder string, opts *GetByBaseOptions) *Locator {\n\tp.logger.Debugf(\"Page:GetByPlaceholder\", \"sid:%s placeholder: %q opts:%+v\", p.sessionID(), placeholder, opts)\n\n\treturn p.MainFrame().GetByPlaceholder(placeholder, opts)\n}\n\n// GetByTitle creates and returns a new locator for this page (main frame) based on the title attribute.\nfunc (p *Page) GetByTitle(title string, opts *GetByBaseOptions) *Locator {\n\tp.logger.Debugf(\"Page:GetByTitle\", \"sid:%s title: %q opts:%+v\", p.sessionID(), title, opts)\n\n\treturn p.MainFrame().GetByTitle(title, opts)\n}\n\n// GetByTestID creates and returns a new locator for this page (main frame) based on the data-testid attribute.\nfunc (p *Page) GetByTestID(testID string) *Locator {\n\tp.logger.Debugf(\"Page:GetByTestID\", \"sid:%s testID: %q\", p.sessionID(), testID)\n\n\treturn p.MainFrame().GetByTestID(testID)\n}\n\n// GetByText creates and returns a new locator for this page (main frame) based on text content.\nfunc (p *Page) GetByText(text string, opts *GetByBaseOptions) *Locator {\n\tp.logger.Debugf(\"Page:GetByText\", \"sid:%s text: %q opts:%+v\", p.sessionID(), text, opts)\n\n\treturn p.MainFrame().GetByText(text, opts)\n}\n\n// GetKeyboard returns the keyboard for the page.\nfunc (p *Page) GetKeyboard() *Keyboard {\n\treturn p.Keyboard\n}\n\n// GetMouse returns the mouse for the page.\nfunc (p *Page) GetMouse() *Mouse {\n\treturn p.Mouse\n}\n\n// GetTouchscreen returns the touchscreen for the page.\nfunc (p *Page) GetTouchscreen() *Touchscreen {\n\treturn p.Touchscreen\n}\n\n// Goto will navigate the page to the specified URL and return a HTTP response object.\nfunc (p *Page) Goto(url string, opts *FrameGotoOptions) (*Response, error) {\n\tp.logger.Debugf(\"Page:Goto\", \"sid:%v url:%q\", p.sessionID(), url)\n\t_, span := TraceAPICall(\n\t\tp.ctx,\n\t\tp.targetID.String(),\n\t\t\"page.goto\",\n\t\ttrace.WithAttributes(attribute.String(\"page.goto.url\", url)),\n\t)\n\tdefer span.End()\n\n\tresp, err := p.MainFrame().Goto(url, opts)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"navigating page: %w\", err)\n\t}\n\n\treturn resp, nil\n}\n\n// Hover hovers over an element matching the provided selector.\nfunc (p *Page) Hover(selector string, popts *FrameHoverOptions) error {\n\tp.logger.Debugf(\"Page:Hover\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Hover(selector, popts)\n}\n\n// InnerHTML returns the inner HTML of the element matching the provided selector.\nfunc (p *Page) InnerHTML(selector string, popts *FrameInnerHTMLOptions) (string, error) {\n\tp.logger.Debugf(\"Page:InnerHTML\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().InnerHTML(selector, popts)\n}\n\n// InnerText returns the inner text of the element matching the provided selector.\nfunc (p *Page) InnerText(selector string, popts *FrameInnerTextOptions) (string, error) {\n\tp.logger.Debugf(\"Page:InnerText\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().InnerText(selector, popts)\n}\n\n// InputValue returns the value of the input element matching the provided selector.\nfunc (p *Page) InputValue(selector string, popts *FrameInputValueOptions) (string, error) {\n\tp.logger.Debugf(\"Page:InputValue\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().InputValue(selector, popts)\n}\n\nfunc (p *Page) IsClosed() bool {\n\tp.closedMu.RLock()\n\tdefer p.closedMu.RUnlock()\n\n\treturn p.closed\n}\n\n// IsDisabled returns true if the first element that matches the selector\n// is disabled. Otherwise, returns false.\nfunc (p *Page) IsDisabled(selector string, opts *FrameIsDisabledOptions) (bool, error) {\n\tp.logger.Debugf(\"Page:IsDisabled\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().IsDisabled(selector, opts)\n}\n\n// IsEditable returns true if the first element that matches the selector\n// is editable. Otherwise, returns false.\nfunc (p *Page) IsEditable(selector string, opts *FrameIsEditableOptions) (bool, error) {\n\tp.logger.Debugf(\"Page:IsEditable\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().IsEditable(selector, opts)\n}\n\n// IsEnabled returns true if the first element that matches the selector\n// is enabled. Otherwise, returns false.\nfunc (p *Page) IsEnabled(selector string, opts *FrameIsEnabledOptions) (bool, error) {\n\tp.logger.Debugf(\"Page:IsEnabled\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().IsEnabled(selector, opts)\n}\n\n// IsHidden will look for an element in the dom with given selector and see if\n// the element is hidden. It will not wait for a match to occur. If no elements\n// match `false` will be returned.\nfunc (p *Page) IsHidden(selector string, opts *FrameIsHiddenOptions) (bool, error) {\n\tp.logger.Debugf(\"Page:IsHidden\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().IsHidden(selector, opts)\n}\n\n// IsVisible will look for an element in the dom with given selector. It will\n// not wait for a match to occur. If no elements match `false` will be returned.\nfunc (p *Page) IsVisible(selector string, opts *FrameIsVisibleOptions) (bool, error) {\n\tp.logger.Debugf(\"Page:IsVisible\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().IsVisible(selector, opts)\n}\n\n// Locator creates and returns a new locator for this page (main frame).\nfunc (p *Page) Locator(selector string, opts *LocatorOptions) *Locator {\n\tp.logger.Debugf(\"Page:Locator\", \"sid:%s sel: %q opts:%+v\", p.sessionID(), selector, opts)\n\n\treturn p.MainFrame().Locator(selector, opts)\n}\n\n// FrameLocator creates a frame locator for an iframe matching the given selector.\nfunc (p *Page) FrameLocator(selector string) *FrameLocator {\n\tp.logger.Debugf(\"Page:FrameLocator\", \"sid:%s selector:%q\", p.sessionID(), selector)\n\n\treturn p.Locator(selector, nil).ContentFrame()\n}\n\n// MainFrame returns the main frame on the page.\nfunc (p *Page) MainFrame() *Frame {\n\tmf := p.frameManager.MainFrame()\n\n\tif mf == nil {\n\t\tp.logger.Debugf(\"Page:MainFrame\", \"sid:%v\", p.sessionID())\n\t} else {\n\t\tp.logger.Debugf(\"Page:MainFrame\",\n\t\t\t\"sid:%v mfid:%v mflid:%v mfurl:%v\",\n\t\t\tp.sessionID(), mf.id, mf.loaderID, mf.URL())\n\t}\n\n\treturn mf\n}\n\n// Referrer returns the page's referrer.\n// It's an internal method not to be exposed as a JS API.\nfunc (p *Page) Referrer() string {\n\tnm := p.mainFrameSession.getNetworkManager()\n\treturn nm.extraHTTPHeaders[\"referer\"]\n}\n\n// Route registers a handler to be executed for a given request path\nfunc (p *Page) Route(path string, cb RouteHandlerCallback, rm RegExMatcher) error {\n\tp.logger.Debugf(\"Page:Route\", \"sid:%v path:%s\", p.sessionID(), path)\n\n\tif !p.hasRoutes() {\n\t\terr := p.mainFrameSession.updateRequestInterception(true)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tmatcher, err := newPatternMatcher(path, rm)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating url matcher for path %s: %w\", path, err)\n\t}\n\n\trouteHandler := NewRouteHandler(path, cb, matcher)\n\tp.routesMu.Lock()\n\tdefer p.routesMu.Unlock()\n\t// Append new route at the beginning of the slice as, when several routes match the given pattern,\n\t// they will run in the opposite order to their registration.\n\tp.routes = append([]*RouteHandler{routeHandler}, p.routes...)\n\n\treturn nil\n}\n\n// Unroute removes the route(s) for the specified URL pattern.\n// If multiple routes match the same URL pattern, all of them are removed.\nfunc (p *Page) Unroute(path string) error {\n\tp.logger.Debugf(\"Page:Unroute\", \"sid:%v path:%s\", p.sessionID(), path)\n\n\tp.routesMu.Lock()\n\tdefer p.routesMu.Unlock()\n\n\tp.routes = slices.DeleteFunc(p.routes, func(rh *RouteHandler) bool {\n\t\treturn rh.path == path\n\t})\n\n\t// If no routes remain, disable request interception\n\tif len(p.routes) == 0 {\n\t\treturn p.mainFrameSession.updateRequestInterception(false)\n\t}\n\n\treturn nil\n}\n\n// UnrouteAll removes all registered routes.\nfunc (p *Page) UnrouteAll() error {\n\tp.logger.Debugf(\"Page:UnrouteAll\", \"sid:%v\", p.sessionID())\n\n\tp.routesMu.Lock()\n\tdefer p.routesMu.Unlock()\n\n\tp.routes = []*RouteHandler{}\n\n\t// Disable request interception when no route is registered\n\treturn p.mainFrameSession.updateRequestInterception(false)\n}\n\n// NavigationTimeout returns the page's navigation timeout.\n// It's an internal method not to be exposed as a JS API.\nfunc (p *Page) NavigationTimeout() time.Duration {\n\treturn p.frameManager.timeoutSettings.navigationTimeout()\n}\n\n// PageEvent represents a generic page event.\n// Use one of the fields to get the specific event data.\ntype PageEvent struct {\n\t// ConsoleMessage is the console message event.\n\tConsoleMessage *ConsoleMessage\n\n\t// Metric is the metric event event.\n\tMetric *MetricEvent\n\n\t// Request is the read only request that is about to be sent from the\n\t// browser to the WuT.\n\tRequest *Request\n\n\t// Response is the read only response that was received from the WuT.\n\tResponse *Response\n}\n\n// On subscribes to a page event for which the given handler will be executed\n// passing in the ConsoleMessage associated with the event.\n// The only accepted event value is 'console'.\nfunc (p *Page) On(event PageEventName, handler PageEventHandler) error {\n\tif handler == nil {\n\t\treturn errors.New(`\"handler\" argument cannot be nil`)\n\t}\n\n\t_, err := p.addEventHandler(event, handler)\n\treturn err\n}\n\nfunc (p *Page) addEventHandler(event PageEventName, handler PageEventHandler) (id uint64, err error) {\n\tp.eventHandlersMu.Lock()\n\tdefer p.eventHandlersMu.Unlock()\n\n\tr := pageEventHandlerRecord{\n\t\tid:      p.eventHandlerLastID.Add(1),\n\t\thandler: handler,\n\t}\n\tp.eventHandlers[event] = append(p.eventHandlers[event], r)\n\n\treturn r.id, nil\n}\n\nfunc (p *Page) removeEventHandler(event PageEventName, id uint64) {\n\tp.eventHandlersMu.Lock()\n\tdefer p.eventHandlersMu.Unlock()\n\n\thandlers, ok := p.eventHandlers[event]\n\tif !ok {\n\t\tp.logger.Debugf(\"Page:removeEventHandler\", \"sid:%v event:%s not found\", p.sessionID(), event)\n\t\treturn\n\t}\n\tp.eventHandlers[event] = slices.DeleteFunc(handlers, func(r pageEventHandlerRecord) bool {\n\t\treturn r.id == id\n\t})\n\tif len(p.eventHandlers[event]) == 0 {\n\t\tdelete(p.eventHandlers, event)\n\t}\n}\n\n// hasEventHandler returns true if there is a handler\n// registered for the given page on event name.\nfunc (p *Page) hasEventHandler(event PageEventName) bool {\n\tp.eventHandlersMu.RLock()\n\tdefer p.eventHandlersMu.RUnlock()\n\thandlers, ok := p.eventHandlers[event]\n\treturn ok && len(handlers) > 0\n}\n\n// Opener returns the opener of the target.\nfunc (p *Page) Opener() *Page {\n\treturn p.opener\n}\n\n// Press presses the given key for the first element found that matches the selector.\nfunc (p *Page) Press(selector string, key string, opts *FramePressOptions) error {\n\tp.logger.Debugf(\"Page:Press\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Press(selector, key, opts)\n}\n\n// Query returns the first element matching the specified selector.\nfunc (p *Page) Query(selector string) (*ElementHandle, error) {\n\tp.logger.Debugf(\"Page:Query\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.frameManager.MainFrame().Query(selector, StrictModeOff)\n}\n\n// QueryAll returns all elements matching the specified selector.\nfunc (p *Page) QueryAll(selector string) ([]*ElementHandle, error) {\n\tp.logger.Debugf(\"Page:QueryAll\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.frameManager.MainFrame().QueryAll(selector)\n}\n\n// Reload will reload the current page.\nfunc (p *Page) Reload(opts *PageReloadOptions) (_ *Response, rerr error) { //nolint:funlen\n\tp.logger.Debugf(\"Page:Reload\", \"sid:%v\", p.sessionID())\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.reload\")\n\tdefer span.End()\n\tdefer func() {\n\t\tif rerr != nil {\n\t\t\trerr = spanRecordErrorf(span, \"reloading page: %w\", rerr)\n\t\t}\n\t}()\n\n\ttimeoutCtx, timeoutCancelFn := context.WithTimeout(p.ctx, opts.Timeout)\n\tdefer timeoutCancelFn()\n\n\twaitForFrameNavigation, cancelWaitingForFrameNavigation := createWaitForEventHandler(\n\t\ttimeoutCtx, p.frameManager.MainFrame(),\n\t\t[]string{EventFrameNavigation},\n\t\tfunc(_ any) bool {\n\t\t\treturn true // Both successful and failed navigations are considered\n\t\t},\n\t)\n\tdefer cancelWaitingForFrameNavigation() // Remove event handler\n\n\twaitForLifecycleEvent, cancelWaitingForLifecycleEvent := createWaitForEventPredicateHandler(\n\t\ttimeoutCtx, p.frameManager.MainFrame(),\n\t\t[]string{EventFrameAddLifecycle},\n\t\tfunc(data any) bool {\n\t\t\tif le, ok := data.(FrameLifecycleEvent); ok {\n\t\t\t\treturn le.Event == opts.WaitUntil\n\t\t\t}\n\t\t\treturn false\n\t\t})\n\tdefer cancelWaitingForLifecycleEvent()\n\n\treloadAction := page.Reload()\n\tif err := reloadAction.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {\n\t\treturn nil, err\n\t}\n\n\twrapTimeoutError := func(err error) error {\n\t\tif errors.Is(err, context.DeadlineExceeded) {\n\t\t\terr = &k6ext.UserFriendlyError{\n\t\t\t\tErr:     err,\n\t\t\t\tTimeout: opts.Timeout,\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\tp.logger.Debugf(\"Page:Reload\", \"timeoutCtx done: %v\", err)\n\n\t\treturn err\n\t}\n\n\tvar (\n\t\tnavigationEvent *NavigationEvent\n\t\terr             error\n\t)\n\tselect {\n\tcase <-p.ctx.Done():\n\t\terr = ContextErr(p.ctx)\n\tcase <-timeoutCtx.Done():\n\t\terr = wrapTimeoutError(ContextErr(timeoutCtx))\n\tcase event := <-waitForFrameNavigation:\n\t\tvar ok bool\n\t\tif navigationEvent, ok = event.(*NavigationEvent); !ok {\n\t\t\terr = fmt.Errorf(\"unexpected event data type: %T, expected *NavigationEvent\", event)\n\t\t} else if navigationEvent != nil && navigationEvent.err != nil {\n\t\t\terr = navigationEvent.err\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar resp *Response\n\n\t// Sometimes the new document is not yet available when the navigation event is emitted.\n\tnewDocument := navigationEvent.newDocument\n\tif newDocument != nil && newDocument.request != nil {\n\t\treq := newDocument.request\n\t\treq.responseMu.RLock()\n\t\tresp = req.response\n\t\treq.responseMu.RUnlock()\n\t}\n\n\tselect {\n\tcase <-waitForLifecycleEvent:\n\tcase <-timeoutCtx.Done():\n\t\treturn nil, wrapTimeoutError(ContextErr(timeoutCtx))\n\t}\n\n\tapplySlowMo(p.ctx)\n\n\treturn resp, nil\n}\n\n// GoBackForward navigates through the browser's session history.\n// Use delta = -1 for going back and delta = +1 for going forward.\nfunc (p *Page) GoBackForward(delta int, opts *PageGoBackForwardOptions) (_ *Response, rerr error) {\n\tdirection := \"back\"\n\tspanName := \"page.goBack\"\n\tif delta > 0 {\n\t\tdirection = \"forward\"\n\t\tspanName = \"page.goForward\"\n\t}\n\n\tp.logger.Debugf(\"Page:GoBackForward\", \"sid:%v direction:%s\", p.sessionID(), direction)\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), spanName)\n\tdefer span.End()\n\tdefer func() {\n\t\tif rerr != nil {\n\t\t\trerr = spanRecordErrorf(span, \"page going %s: %w\", direction, rerr)\n\t\t}\n\t}()\n\n\tcurrentIndex, entries, err := page.GetNavigationHistory().Do(cdp.WithExecutor(p.ctx, p.session))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttargetIndex := currentIndex + int64(delta)\n\n\t// Check boundaries\n\tif targetIndex < 0 || targetIndex >= int64(len(entries)) {\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\n\thistoryEntryID := entries[targetIndex].ID\n\ttargetURL := entries[targetIndex].URL\n\n\ttimeoutCtx, timeoutCancelFn := context.WithTimeout(p.ctx, opts.Timeout)\n\tdefer timeoutCancelFn()\n\n\tnavAction := page.NavigateToHistoryEntry(historyEntryID)\n\tif err := navAction.Do(cdp.WithExecutor(p.ctx, p.session)); err != nil {\n\t\treturn nil, fmt.Errorf(\"navigating to history entry %d: %w\", historyEntryID, err)\n\t}\n\n\twrapTimeoutError := func(err error) error {\n\t\tif errors.Is(err, context.DeadlineExceeded) {\n\t\t\terr = &k6ext.UserFriendlyError{\n\t\t\t\tErr:     err,\n\t\t\t\tTimeout: opts.Timeout,\n\t\t\t}\n\t\t}\n\t\tp.logger.Debugf(\"Page:GoBackForward\", \"timeoutCtx done: %v\", err)\n\t\treturn fmt.Errorf(\"navigating %s to history entry %d: %w\", direction, historyEntryID, err)\n\t}\n\n\t// Poll for URL change, don't rely on lifecycle events since bfcache\n\t// restorations don't re-fire them.\n\tticker := time.NewTicker(50 * time.Millisecond)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-p.ctx.Done():\n\t\t\treturn nil, p.ctx.Err()\n\t\tcase <-timeoutCtx.Done():\n\t\t\treturn nil, wrapTimeoutError(timeoutCtx.Err())\n\t\tcase <-ticker.C:\n\t\t\tmainFrame := p.frameManager.MainFrame()\n\t\t\tif mainFrame == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcurrentURL := mainFrame.URL()\n\t\t\tp.logger.Debugf(\"Page:GoBackForward\", \"polling: currentURL=%s targetURL=%s\", currentURL, targetURL)\n\n\t\t\tif currentURL == targetURL {\n\t\t\t\tp.logger.Debugf(\"Page:GoBackForward\", \"navigation complete to %s\", targetURL)\n\t\t\t\tapplySlowMo(p.ctx)\n\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Screenshot will instruct Chrome to save a screenshot of the current page and save it to specified file.\nfunc (p *Page) Screenshot(opts *PageScreenshotOptions, sp ScreenshotPersister) ([]byte, error) {\n\tspanCtx, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.screenshot\")\n\tdefer span.End()\n\n\tspan.SetAttributes(attribute.String(\"screenshot.path\", opts.Path))\n\n\ts := newScreenshotter(spanCtx, sp, p.logger)\n\tbuf, err := s.screenshotPage(p, opts)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"taking screenshot of page: %w\", err)\n\t}\n\n\treturn buf, err\n}\n\n// SelectOption selects the given options and returns the array of\n// option values of the first element found that matches the selector.\nfunc (p *Page) SelectOption(selector string, values []any, popts *FrameSelectOptionOptions) ([]string, error) {\n\tp.logger.Debugf(\"Page:SelectOption\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().SelectOption(selector, values, popts)\n}\n\n// SetContent replaces the entire HTML document content.\nfunc (p *Page) SetContent(html string, opts *FrameSetContentOptions) error {\n\tp.logger.Debugf(\"Page:SetContent\", \"sid:%v\", p.sessionID())\n\n\treturn p.MainFrame().SetContent(html, opts)\n}\n\n// SetDefaultNavigationTimeout sets the default navigation timeout in milliseconds.\nfunc (p *Page) SetDefaultNavigationTimeout(timeout int64) {\n\tp.logger.Debugf(\"Page:SetDefaultNavigationTimeout\", \"sid:%v timeout:%d\", p.sessionID(), timeout)\n\n\tp.timeoutSettings.setDefaultNavigationTimeout(time.Duration(timeout) * time.Millisecond)\n}\n\n// SetDefaultTimeout sets the default maximum timeout in milliseconds.\nfunc (p *Page) SetDefaultTimeout(timeout int64) {\n\tp.logger.Debugf(\"Page:SetDefaultTimeout\", \"sid:%v timeout:%d\", p.sessionID(), timeout)\n\n\tp.timeoutSettings.setDefaultTimeout(time.Duration(timeout) * time.Millisecond)\n}\n\n// SetExtraHTTPHeaders sets default HTTP headers for page and whole frame hierarchy.\nfunc (p *Page) SetExtraHTTPHeaders(headers map[string]string) error {\n\tp.logger.Debugf(\"Page:SetExtraHTTPHeaders\", \"sid:%v\", p.sessionID())\n\n\tp.extraHTTPHeaders = headers\n\treturn p.updateExtraHTTPHeaders()\n}\n\n// SetInputFiles sets input files for the selected element.\nfunc (p *Page) SetInputFiles(selector string, files *Files, opts *FrameSetInputFilesOptions) error {\n\tp.logger.Debugf(\"Page:SetInputFiles\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().SetInputFiles(selector, files, opts)\n}\n\n// SetViewportSize will update the viewport width and height.\nfunc (p *Page) SetViewportSize(viewportSize *Size) error {\n\tp.logger.Debugf(\"Page:SetViewportSize\", \"sid:%v\", p.sessionID())\n\n\tif err := p.setViewportSize(viewportSize); err != nil {\n\t\treturn fmt.Errorf(\"setting viewport size: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// Tap will tap the element matching the provided selector.\nfunc (p *Page) Tap(selector string, opts *FrameTapOptions) error {\n\tp.logger.Debugf(\"Page:SetViewportSize\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().Tap(selector, opts)\n}\n\n// TextContent returns the textContent attribute of the first element found\n// that matches the selector. The second return value is true if the returned\n// text content is not null or empty, and false otherwise.\nfunc (p *Page) TextContent(selector string, popts *FrameTextContentOptions) (string, bool, error) {\n\tp.logger.Debugf(\"Page:TextContent\", \"sid:%v selector:%s\", p.sessionID(), selector)\n\n\treturn p.MainFrame().TextContent(selector, popts)\n}\n\n// Timeout will return the default timeout or the one set by the user.\n// It's an internal method not to be exposed as a JS API.\nfunc (p *Page) Timeout() time.Duration {\n\treturn p.defaultTimeout()\n}\n\n// Title returns the page title.\nfunc (p *Page) Title() (string, error) {\n\tp.logger.Debugf(\"Page:Title\", \"sid:%v\", p.sessionID())\n\n\tjs := `() => document.title`\n\tv, err := p.Evaluate(js)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting page title: %w\", err)\n\t}\n\ts, ok := v.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"getting page title: expected string, got %T\", v)\n\t}\n\n\treturn s, nil\n}\n\n// ThrottleCPU will slow the CPU down from chrome's perspective to simulate\n// a test being run on a slower device.\nfunc (p *Page) ThrottleCPU(cpuProfile CPUProfile) error {\n\tp.logger.Debugf(\"Page:ThrottleCPU\", \"sid:%v\", p.sessionID())\n\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tfor _, fs := range p.frameSessions {\n\t\tif err := fs.throttleCPU(cpuProfile); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ThrottleNetwork will slow the network down to simulate a slow network e.g.\n// simulating a slow 3G connection.\nfunc (p *Page) ThrottleNetwork(networkProfile NetworkProfile) error {\n\tp.logger.Debugf(\"Page:ThrottleNetwork\", \"sid:%v\", p.sessionID())\n\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tfor _, fs := range p.frameSessions {\n\t\tif err := fs.throttleNetwork(networkProfile); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Type text on the first element found matches the selector.\nfunc (p *Page) Type(selector string, text string, popts *FrameTypeOptions) error {\n\tp.logger.Debugf(\"Page:Type\", \"sid:%v selector:%s text:%s\", p.sessionID(), selector, text)\n\n\treturn p.MainFrame().Type(selector, text, popts)\n}\n\n// URL returns the location of the page.\nfunc (p *Page) URL() (string, error) {\n\tp.logger.Debugf(\"Page:URL\", \"sid:%v\", p.sessionID())\n\n\treturn p.MainFrame().url, nil\n}\n\n// ViewportSize will return information on the viewport width and height.\nfunc (p *Page) ViewportSize() map[string]float64 {\n\tp.logger.Debugf(\"Page:ViewportSize\", \"sid:%v\", p.sessionID())\n\n\tvps := p.viewportSize()\n\treturn map[string]float64{\n\t\t\"width\":  vps.Width,\n\t\t\"height\": vps.Height,\n\t}\n}\n\n// WaitForFunction waits for the given predicate to return a truthy value.\nfunc (p *Page) WaitForFunction(js string, opts *FrameWaitForFunctionOptions, jsArgs ...any) (any, error) {\n\tp.logger.Debugf(\"Page:WaitForFunction\", \"sid:%v\", p.sessionID())\n\treturn p.frameManager.MainFrame().WaitForFunction(js, opts, jsArgs...)\n}\n\n// WaitForLoadState waits for the specified page life cycle event.\nfunc (p *Page) WaitForLoadState(state string, popts *FrameWaitForLoadStateOptions) error {\n\tp.logger.Debugf(\"Page:WaitForLoadState\", \"sid:%v state:%q\", p.sessionID(), state)\n\n\treturn p.frameManager.MainFrame().WaitForLoadState(state, popts)\n}\n\n// WaitForNavigation waits for the given navigation lifecycle event to happen.\n// RegExMatcher should be non-nil to be able to test against a URL pattern in the options.\nfunc (p *Page) WaitForNavigation(opts *FrameWaitForNavigationOptions, rm RegExMatcher) (*Response, error) {\n\tp.logger.Debugf(\"Page:WaitForNavigation\", \"sid:%v\", p.sessionID())\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.waitForNavigation\")\n\tdefer span.End()\n\n\tresp, err := p.frameManager.MainFrame().WaitForNavigation(opts, rm)\n\tif err != nil {\n\t\treturn nil, spanRecordError(span, err)\n\t}\n\n\treturn resp, err\n}\n\n// WaitForSelector waits for the given selector to match the waiting criteria.\nfunc (p *Page) WaitForSelector(selector string, popts *FrameWaitForSelectorOptions) (*ElementHandle, error) {\n\tp.logger.Debugf(\"Page:WaitForSelector\",\n\t\t\"sid:%v stid:%v ptid:%v selector:%s\",\n\t\tp.sessionID(), p.session.TargetID(), p.targetID, selector)\n\n\treturn p.frameManager.MainFrame().WaitForSelector(selector, popts)\n}\n\n// WaitForTimeout waits the specified number of milliseconds.\nfunc (p *Page) WaitForTimeout(timeout int64) {\n\tp.logger.Debugf(\"Page:WaitForTimeout\", \"sid:%v timeout:%d\", p.sessionID(), timeout)\n\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.waitForTimeout\")\n\tdefer span.End()\n\n\tp.frameManager.MainFrame().WaitForTimeout(timeout)\n}\n\n// WaitForURL waits for the page to navigate to a URL matching the given pattern.\n// RegExMatcher should be non-nil to be able to test against a URL pattern.\nfunc (p *Page) WaitForURL(urlPattern string, opts *FrameWaitForURLOptions, rm RegExMatcher) error {\n\tp.logger.Debugf(\"Page:WaitForURL\", \"sid:%v pattern:%s\", p.sessionID(), urlPattern)\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.waitForURL\")\n\tdefer span.End()\n\n\terr := p.frameManager.MainFrame().WaitForURL(urlPattern, opts, rm)\n\tif err != nil {\n\t\treturn spanRecordError(span, err)\n\t}\n\n\treturn nil\n}\n\n// eventHandlersByName returns a single-use iterator that yields all event handlers\n// registered for the given event name. If there are no handlers registered, it\n// returns an empty iterator. The iterator is safe for concurrent use.\nfunc (p *Page) eventHandlersByName(evn PageEventName) iter.Seq[PageEventHandler] {\n\treturn func(yield func(PageEventHandler) bool) {\n\t\tif !p.hasEventHandler(evn) {\n\t\t\treturn\n\t\t}\n\n\t\t// Avoid holding locks while running handlers (which might\n\t\t// register/unregister handlers and thus attempt to acquire the\n\t\t// write lock), and prevents concurrent modification issues.\n\t\tp.eventHandlersMu.RLock()\n\t\thandlers := slices.Clone(p.eventHandlers[evn])\n\t\tp.eventHandlersMu.RUnlock()\n\n\t\tfor _, next := range handlers {\n\t\t\tif !yield(next.handler) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// waitForEvent subscribes to the given event and resolves once the predicate\n// determines an event should complete the wait or terminate with an error.\nfunc (p *Page) waitForEvent(\n\tctx context.Context,\n\teventName PageEventName,\n\tpredicate func(PageEvent) (bool, error),\n) (_ PageEvent, rerr error) {\n\tdefer func() {\n\t\tif rerr != nil {\n\t\t\trerr = fmt.Errorf(\"waiting for page %s event: %w\", eventName, rerr)\n\t\t}\n\t}()\n\n\ttype pageEventWaitResult struct {\n\t\tevent PageEvent\n\t\terr   error\n\t}\n\n\tvar (\n\t\tonce   sync.Once\n\t\tresult = make(chan pageEventWaitResult, 1)\n\t)\n\tid, err := p.addEventHandler(eventName, func(event PageEvent) error {\n\t\tok, perr := predicate(event)\n\t\tif perr == nil && !ok {\n\t\t\treturn nil\n\t\t}\n\t\t// We don't want to deadlock if another event frequently happens.\n\t\t// Although the channel is buffered and we remove the handler once we get\n\t\t// the first event, another event could happen before we remove the handler.\n\t\tonce.Do(func() { result <- pageEventWaitResult{event: event, err: perr} })\n\t\treturn perr\n\t})\n\tif err != nil {\n\t\treturn PageEvent{}, err\n\t}\n\t// Avoids dangling event handlers after we're done.\n\tdefer p.removeEventHandler(eventName, id)\n\n\tselect {\n\tcase r := <-result:\n\t\treturn r.event, r.err\n\tcase <-ctx.Done():\n\t\treturn PageEvent{}, ContextErr(ctx)\n\t}\n}\n\n// WaitForResponse waits for a response that matches the given URL pattern.\n// RegExMatcher should be non-nil to be able to test against a URL pattern.\nfunc (p *Page) WaitForResponse(\n\turlPattern string, opts *PageWaitForResponseOptions, rm RegExMatcher,\n) (*Response, error) {\n\tp.logger.Debugf(\"Page:WaitForResponse\", \"sid:%v pattern:%s\", p.sessionID(), urlPattern)\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.waitForResponse\")\n\tdefer span.End()\n\n\tctx, cancel := context.WithTimeout(p.ctx, opts.Timeout)\n\tdefer cancel()\n\n\tev, err := p.waitForEvent(ctx, PageEventResponse, func(e PageEvent) (bool, error) {\n\t\treturn rm.Match(urlPattern, e.Response.URL())\n\t})\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"waiting for response: %w\", &k6ext.UserFriendlyError{\n\t\t\tErr: err, Timeout: opts.Timeout,\n\t\t})\n\t}\n\n\treturn ev.Response, nil\n}\n\n// PageWaitForRequestOptions are options for [Page.WaitForRequest].\ntype PageWaitForRequestOptions struct {\n\t// Timeout is the maximum time to wait for the request.\n\tTimeout time.Duration\n}\n\n// WaitForRequest waits for a request that matches the given URL pattern.\nfunc (p *Page) WaitForRequest(\n\turlPattern string, opts *PageWaitForRequestOptions, rm RegExMatcher,\n) (*Request, error) {\n\tp.logger.Debugf(\"Page:waitForRequest\", \"sid:%v pattern:%s\", p.sessionID(), urlPattern)\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.waitForRequest\")\n\tdefer span.End()\n\n\tctx, cancel := context.WithTimeout(p.ctx, opts.Timeout)\n\tdefer cancel()\n\n\tev, err := p.waitForEvent(ctx, PageEventRequest, func(e PageEvent) (bool, error) {\n\t\treturn rm.Match(urlPattern, e.Request.URL())\n\t})\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"waiting for request: %w\", &k6ext.UserFriendlyError{\n\t\t\tErr: err, Timeout: opts.Timeout,\n\t\t})\n\t}\n\treturn ev.Request, nil\n}\n\n// PageWaitForEventOptions are options for [Page.WaitForEvent].\ntype PageWaitForEventOptions struct {\n\t// Timeout is the maximum time to wait for the event.\n\tTimeout time.Duration\n}\n\n// WaitForEvent waits for the specified event to be emitted.\nfunc (p *Page) WaitForEvent(\n\teventName PageEventName,\n\topts *PageWaitForEventOptions,\n\tfn func(PageEvent) (bool, error),\n) (PageEvent, error) {\n\tp.logger.Debugf(\"Page:WaitForEvent\", \"sid:%v event:%s\", p.sessionID(), eventName)\n\t_, span := TraceAPICall(p.ctx, p.targetID.String(), \"page.waitForEvent\")\n\tdefer span.End()\n\n\tctx, cancel := context.WithTimeout(p.ctx, opts.Timeout)\n\tdefer cancel()\n\n\t// If no predicate is provided, match the first event.\n\tif fn == nil {\n\t\tfn = func(PageEvent) (bool, error) { return true, nil }\n\t}\n\n\tev, err := p.waitForEvent(ctx, eventName, fn)\n\tif err != nil {\n\t\treturn PageEvent{}, spanRecordErrorf(span, \"waiting for page event %q: %w\", eventName, &k6ext.UserFriendlyError{\n\t\t\tErr: err, Timeout: opts.Timeout,\n\t\t})\n\t}\n\treturn ev, nil\n}\n\n// Workers returns all WebWorkers of page.\nfunc (p *Page) Workers() []*Worker {\n\tp.workersMu.Lock()\n\tdefer p.workersMu.Unlock()\n\tworkers := make([]*Worker, 0, len(p.workers))\n\tfor _, w := range p.workers {\n\t\tworkers = append(workers, w)\n\t}\n\treturn workers\n}\n\n// TargetID retrieve the unique id that is associated to this page.\n// For internal use only.\nfunc (p *Page) TargetID() string {\n\treturn p.targetID.String()\n}\n\n// executionContextForID returns the page ExecutionContext for the given ID.\nfunc (p *Page) executionContextForID(\n\texecutionContextID runtime.ExecutionContextID,\n) (*ExecutionContext, error) {\n\tp.frameSessionsMu.RLock()\n\tdefer p.frameSessionsMu.RUnlock()\n\n\tfor _, fs := range p.frameSessions {\n\t\tif exc, err := fs.executionContextForID(executionContextID); err == nil {\n\t\t\treturn exc, nil\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"no execution context found for id: %v\", executionContextID)\n}\n\n// sessionID returns the Page's session ID.\n// It should be used internally in the Page.\nfunc (p *Page) sessionID() (sid target.SessionID) {\n\tif p != nil && p.session != nil {\n\t\tsid = p.session.ID()\n\t}\n\treturn sid\n}\n\n// textForConsoleEvent generates the text representation for a consoleAPICalled event\n// mimicking Playwright's behavior.\nfunc textForConsoleEvent(e *runtime.EventConsoleAPICalled, args []string) string {\n\tif e.Type.String() == \"dir\" || e.Type.String() == \"dirxml\" ||\n\t\te.Type.String() == \"table\" {\n\t\tif len(e.Args) > 0 {\n\t\t\t// These commands accept a single arg\n\t\t\treturn e.Args[0].Description\n\t\t}\n\t\treturn \"\"\n\t}\n\n\treturn strings.Join(args, \" \")\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/page_options.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/chromedp/cdproto/page\"\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/js/common\"\n)\n\ntype PageEmulateMediaOptions struct {\n\tColorScheme   ColorScheme   `json:\"colorScheme\"`\n\tMedia         MediaType     `json:\"media\"`\n\tReducedMotion ReducedMotion `json:\"reducedMotion\"`\n}\n\ntype PageReloadOptions struct {\n\tWaitUntil LifecycleEvent `json:\"waitUntil\" js:\"waitUntil\"`\n\tTimeout   time.Duration  `json:\"timeout\"`\n}\n\ntype PageScreenshotOptions struct {\n\tClip           *page.Viewport `json:\"clip\"`\n\tPath           string         `json:\"path\"`\n\tFormat         ImageFormat    `json:\"format\"`\n\tFullPage       bool           `json:\"fullPage\"`\n\tOmitBackground bool           `json:\"omitBackground\"`\n\tQuality        int64          `json:\"quality\"`\n}\n\n// PageGoBackForwardOptions are options for Page.GoBack and Page.GoForward.\ntype PageGoBackForwardOptions struct {\n\tWaitUntil LifecycleEvent `json:\"waitUntil\"`\n\tTimeout   time.Duration  `json:\"timeout\"`\n}\n\nfunc NewPageEmulateMediaOptions(from *Page) *PageEmulateMediaOptions {\n\treturn &PageEmulateMediaOptions{\n\t\tColorScheme:   from.colorScheme,\n\t\tMedia:         from.mediaType,\n\t\tReducedMotion: from.reducedMotion,\n\t}\n}\n\nfunc NewPageReloadOptions(defaultWaitUntil LifecycleEvent, defaultTimeout time.Duration) *PageReloadOptions {\n\treturn &PageReloadOptions{\n\t\tWaitUntil: defaultWaitUntil,\n\t\tTimeout:   defaultTimeout,\n\t}\n}\n\n// NewPageGoBackForwardOptions returns a new PageGoBackForwardOptions.\nfunc NewPageGoBackForwardOptions(\n\tdefaultWaitUntil LifecycleEvent,\n\tdefaultTimeout time.Duration,\n) *PageGoBackForwardOptions {\n\treturn &PageGoBackForwardOptions{\n\t\tWaitUntil: defaultWaitUntil,\n\t\tTimeout:   defaultTimeout,\n\t}\n}\n\n// Parse parses the page go back/forward options.\nfunc (o *PageGoBackForwardOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\tobj := opts.ToObject(k6ext.Runtime(ctx))\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"waitUntil\":\n\t\t\tlifeCycle := obj.Get(k).String()\n\t\t\tif l, ok := lifecycleEventToID[lifeCycle]; ok {\n\t\t\t\to.WaitUntil = l\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"%q is not a valid lifecycle\", lifeCycle)\n\t\t\t}\n\t\tcase \"timeout\":\n\t\t\to.Timeout = time.Duration(obj.Get(k).ToInteger()) * time.Millisecond\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Parse parses the page reload options.\nfunc (o *PageReloadOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\trt := k6ext.Runtime(ctx)\n\tif !common.IsNullish(opts) {\n\t\topts := opts.ToObject(rt)\n\t\tfor _, k := range opts.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"waitUntil\":\n\t\t\t\tlifeCycle := opts.Get(k).String()\n\t\t\t\tif l, ok := lifecycleEventToID[lifeCycle]; ok {\n\t\t\t\t\to.WaitUntil = l\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"%q is not a valid lifecycle\", lifeCycle)\n\t\t\t\t}\n\t\t\tcase \"timeout\":\n\t\t\t\to.Timeout = time.Duration(opts.Get(k).ToInteger()) * time.Millisecond\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc NewPageScreenshotOptions() *PageScreenshotOptions {\n\treturn &PageScreenshotOptions{\n\t\tClip:           nil,\n\t\tPath:           \"\",\n\t\tFormat:         ImageFormatPNG,\n\t\tFullPage:       false,\n\t\tOmitBackground: false,\n\t\tQuality:        100,\n\t}\n}\n\n// Parse parses the page screenshot options.\nfunc (o *PageScreenshotOptions) Parse(ctx context.Context, opts sobek.Value) error {\n\tif common.IsNullish(opts) {\n\t\treturn nil\n\t}\n\n\trt := k6ext.Runtime(ctx)\n\tformatSpecified := false\n\tobj := opts.ToObject(rt)\n\tfor _, k := range obj.Keys() {\n\t\tswitch k {\n\t\tcase \"clip\":\n\t\t\tvar c map[string]float64\n\t\t\tif rt.ExportTo(obj.Get(k), &c) != nil {\n\t\t\t\to.Clip = &page.Viewport{\n\t\t\t\t\tX:      c[\"x\"],\n\t\t\t\t\tY:      c[\"y\"],\n\t\t\t\t\tWidth:  c[\"width\"],\n\t\t\t\t\tHeight: c[\"height\"],\n\t\t\t\t\tScale:  1,\n\t\t\t\t}\n\t\t\t}\n\t\tcase \"fullPage\":\n\t\t\to.FullPage = obj.Get(k).ToBoolean()\n\t\tcase \"omitBackground\":\n\t\t\to.OmitBackground = obj.Get(k).ToBoolean()\n\t\tcase \"path\":\n\t\t\to.Path = obj.Get(k).String()\n\t\tcase \"quality\":\n\t\t\to.Quality = obj.Get(k).ToInteger()\n\t\tcase \"type\":\n\t\t\tif f, ok := imageFormatToID[obj.Get(k).String()]; ok {\n\t\t\t\to.Format = f\n\t\t\t\tformatSpecified = true\n\t\t\t}\n\t\t}\n\t}\n\n\t// Infer file format by path if format not explicitly specified (default is PNG)\n\tif o.Path != \"\" && !formatSpecified {\n\t\tif strings.HasSuffix(o.Path, \".jpg\") || strings.HasSuffix(o.Path, \".jpeg\") {\n\t\t\to.Format = ImageFormatJPEG\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// PageWaitForResponseOptions are options for Page.waitForResponse.\ntype PageWaitForResponseOptions struct {\n\tTimeout time.Duration\n}\n\n// NewPageWaitForResponseOptions returns a new PageWaitForResponseOptions.\nfunc NewPageWaitForResponseOptions(defaultTimeout time.Duration) *PageWaitForResponseOptions {\n\treturn &PageWaitForResponseOptions{\n\t\tTimeout: defaultTimeout,\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/page_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// TestPageLocator can be removed later on when we add integration\n// tests. Since we don't yet have any of them, it makes sense to keep\n// this test.\nfunc TestPageLocator(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\twantMainFrameID = \"1\"\n\t\twantSelector    = \"span\"\n\t)\n\tctx := context.TODO()\n\tp := &Page{\n\t\tctx: ctx,\n\t\tframeManager: &FrameManager{\n\t\t\tctx:       ctx,\n\t\t\tmainFrame: &Frame{id: wantMainFrameID, ctx: ctx},\n\t\t},\n\t}\n\tl := p.Locator(wantSelector, nil)\n\tassert.Equal(t, wantSelector, l.selector)\n\tassert.Equal(t, wantMainFrameID, string(l.frame.id))\n\n\t// other behavior will be tested via integration tests\n}\n\nfunc TestPageEventHandlersLifecycle(t *testing.T) {\n\tt.Parallel()\n\n\tp := &Page{\n\t\teventHandlers: make(map[PageEventName][]pageEventHandlerRecord),\n\t}\n\n\t// Add some handlers to the page event handling system.\n\thandler := func(PageEvent) error { return nil }\n\tid1, err := p.addEventHandler(PageEventRequest, handler)\n\tassert.NoError(t, err)\n\tid2, err := p.addEventHandler(PageEventRequest, handler)\n\tassert.NoError(t, err)\n\tid3, err := p.addEventHandler(PageEventResponse, handler)\n\tassert.NoError(t, err)\n\n\t// Check if the handlers are registered correctly.\n\tassert.True(t, p.hasEventHandler(PageEventRequest))\n\tassert.True(t, p.hasEventHandler(PageEventResponse))\n\tassert.False(t, p.hasEventHandler(PageEventConsole))\n\n\t// Remove the handlers and check if they are removed correctly.\n\tp.removeEventHandler(PageEventRequest, id1)\n\tp.removeEventHandler(PageEventRequest, id2)\n\tassert.False(t, p.hasEventHandler(PageEventRequest))\n\tp.removeEventHandler(PageEventResponse, id3)\n\tassert.False(t, p.hasEventHandler(PageEventResponse))\n}\n\nfunc TestPageEventHandlerIterator(t *testing.T) {\n\tt.Parallel()\n\n\tnewPage := func() *Page {\n\t\treturn &Page{\n\t\t\teventHandlers: make(map[PageEventName][]pageEventHandlerRecord),\n\t\t}\n\t}\n\n\tt.Run(\"zero\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tn := 0\n\t\tfor range newPage().eventHandlersByName(PageEventConsole) {\n\t\t\tn++\n\t\t}\n\t\tassert.Zero(t, n, \"must not yield any handlers\")\n\t})\n\n\tt.Run(\"single_handler\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar called bool\n\n\t\tpage := newPage()\n\t\t_, err := page.addEventHandler(PageEventConsole, func(event PageEvent) error {\n\t\t\tcalled = true\n\t\t\treturn nil\n\t\t})\n\t\trequire.NoError(t, err)\n\t\tfor handle := range page.eventHandlersByName(PageEventConsole) {\n\t\t\t_ = handle(PageEvent{})\n\t\t}\n\t\tassert.Truef(t, called, \"did not call the registered handler\")\n\t})\n\n\tt.Run(\"multiple_handlers\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar called []int\n\n\t\tp := newPage()\n\t\t_, err := p.addEventHandler(PageEventResponse, func(event PageEvent) error {\n\t\t\tcalled = append(called, 1)\n\t\t\treturn nil\n\t\t})\n\t\trequire.NoError(t, err)\n\t\t_, err = p.addEventHandler(PageEventResponse, func(event PageEvent) error {\n\t\t\tcalled = append(called, 2)\n\t\t\treturn nil\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\tfor handle := range p.eventHandlersByName(PageEventResponse) {\n\t\t\t_ = handle(PageEvent{})\n\t\t}\n\t\tassert.Lenf(t, called, 2, \"must call all registered handlers\")\n\t\tassert.Equal(t, []int{1, 2}, called, \"must call handlers in order of registration\")\n\t})\n\n\tt.Run(\"handler_error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\thandlerError := errors.New(\"handler error\")\n\n\t\tpage := newPage()\n\t\t_, err := page.addEventHandler(PageEventRequest, func(event PageEvent) error {\n\t\t\treturn handlerError\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\tfor handle := range page.eventHandlersByName(PageEventRequest) {\n\t\t\tassert.ErrorIs(t, handle(PageEvent{}), handlerError)\n\t\t}\n\t})\n}\n\nfunc TestPageOn(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"nil handler\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tp := &Page{}\n\n\t\terr := p.On(\"metric\", nil)\n\t\tassert.Error(t, err)\n\t\tassert.ErrorContains(t, err, `\"handler\" argument cannot be nil`)\n\t})\n\n\tt.Run(\"valid handler\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tp := &Page{\n\t\t\teventHandlers: make(map[PageEventName][]pageEventHandlerRecord),\n\t\t}\n\t\thandler := func(PageEvent) error { return nil }\n\n\t\terr := p.On(\"metric\", handler)\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, p.eventHandlers[(\"metric\")], 1)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/remote_object.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\nvar bigIntRegex = regexp.MustCompile(\"^[0-9]*n$\")\n\ntype objectOverflowError struct{}\n\n// Error returns the description of the overflow error.\nfunc (*objectOverflowError) Error() string {\n\treturn \"object is too large and will be parsed partially\"\n}\n\ntype objectPropertyParseError struct {\n\terror\n\tproperty string\n}\n\n// Error returns the reason of the failure, including the wrapper parsing error\n// message.\nfunc (pe *objectPropertyParseError) Error() string {\n\treturn fmt.Sprintf(\"parsing object property %q: %s\", pe.property, pe.error)\n}\n\n// Unwrap returns the wrapped parsing error.\nfunc (pe *objectPropertyParseError) Unwrap() error {\n\treturn pe.error\n}\n\ntype remoteObjectParseError struct {\n\terror\n\ttyp     string\n\tsubType string\n\tval     string\n}\n\n// Error returns a string representation of the error.\nfunc (e *remoteObjectParseError) Error() string {\n\treturn fmt.Sprintf(\"parsing remote object with type: %s subtype: %s val: %s err: %s\",\n\t\te.typ, e.subType, e.val, e.error.Error())\n}\n\n// Unwrap returns the wrapped parsing error.\nfunc (e *remoteObjectParseError) Unwrap() error {\n\treturn e.error\n}\n\nfunc parseRemoteObjectPreview(op *runtime.ObjectPreview) (map[string]any, error) {\n\tobj := make(map[string]any)\n\tvar result []error\n\tif op.Overflow {\n\t\tresult = append(result, &objectOverflowError{})\n\t}\n\n\tfor _, p := range op.Properties {\n\t\tval, err := parseRemoteObjectValue(p.Type, p.Subtype, p.Value, p.ValuePreview)\n\t\tif err != nil {\n\t\t\tresult = append(result, &objectPropertyParseError{err, p.Name})\n\t\t\tcontinue\n\t\t}\n\t\tobj[p.Name] = val\n\t}\n\n\treturn obj, errors.Join(result...)\n}\n\nfunc parseRemoteObjectValue(\n\tt runtime.Type, st runtime.Subtype, val string, op *runtime.ObjectPreview,\n) (any, error) {\n\tswitch t { //nolint:exhaustive\n\tcase runtime.TypeAccessor:\n\t\treturn \"accessor\", nil\n\tcase runtime.TypeBigint:\n\t\tn, err := strconv.ParseInt(strings.ReplaceAll(val, \"n\", \"\"), 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, BigIntParseError{err}\n\t\t}\n\t\treturn n, nil\n\tcase runtime.TypeFunction:\n\t\treturn \"function()\", nil\n\tcase runtime.TypeString:\n\t\tif !strings.HasPrefix(val, `\"`) {\n\t\t\treturn val, nil\n\t\t}\n\tcase runtime.TypeSymbol:\n\t\treturn val, nil\n\tcase runtime.TypeObject:\n\t\tif op != nil {\n\t\t\treturn parseRemoteObjectPreview(op)\n\t\t}\n\t\tif val == \"Object\" {\n\t\t\treturn val, nil\n\t\t}\n\t\tif st == runtime.SubtypeNull {\n\t\t\treturn nil, nil //nolint:nilnil\n\t\t}\n\tcase runtime.TypeUndefined:\n\t\treturn \"undefined\", nil\n\t}\n\n\tvar v any\n\tif err := json.Unmarshal([]byte(val), &v); err != nil {\n\t\treturn nil, &remoteObjectParseError{\n\t\t\terror:   err,\n\t\t\ttyp:     string(t),\n\t\t\tsubType: string(st),\n\t\t\tval:     val,\n\t\t}\n\t}\n\n\treturn v, nil\n}\n\nfunc parseExceptionDetails(exc *runtime.ExceptionDetails) string {\n\tif exc == nil {\n\t\treturn \"\"\n\t}\n\tvar errMsg string\n\tif exc.Exception != nil {\n\t\terrMsg = exc.Exception.Description\n\t\tif errMsg == \"\" {\n\t\t\tif o, _ := parseRemoteObject(exc.Exception); o != nil {\n\t\t\t\terrMsg = fmt.Sprintf(\"%s\", o)\n\t\t\t}\n\t\t}\n\t}\n\treturn errMsg\n}\n\n// parseRemoteObject is to be used by callers that require the string value\n// to be parsed to a Go type.\nfunc parseRemoteObject(obj *runtime.RemoteObject) (any, error) {\n\tuv := obj.UnserializableValue\n\n\tif uv == \"\" {\n\t\treturn parseRemoteObjectValue(obj.Type, obj.Subtype, string(obj.Value), obj.Preview)\n\t}\n\n\tif bigIntRegex.Match([]byte(uv)) {\n\t\tn, err := strconv.ParseInt(strings.ReplaceAll(uv.String(), \"n\", \"\"), 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, BigIntParseError{err}\n\t\t}\n\t\treturn n, nil\n\t}\n\n\tswitch uv.String() {\n\tcase \"-0\": // To handle +0 divided by negative number\n\t\treturn math.Float64frombits(0 | (1 << 63)), nil\n\tcase \"NaN\":\n\t\treturn math.NaN(), nil\n\tcase \"Infinity\":\n\t\treturn math.Inf(0), nil\n\tcase \"-Infinity\":\n\t\treturn math.Inf(-1), nil\n\t}\n\n\t// We should never get here, as previous switch statement should\n\t// be exhaustive and contain all possible unserializable values.\n\t// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-UnserializableValue\n\treturn nil, UnserializableValueError{uv}\n}\n\nfunc valueFromRemoteObject(_ context.Context, robj *runtime.RemoteObject) (any, error) {\n\tval, err := parseRemoteObject(robj)\n\tif val == \"undefined\" {\n\t\treturn nil, err\n\t}\n\treturn val, err\n}\n\nfunc parseConsoleRemoteObjectPreview(logger *log.Logger, op *runtime.ObjectPreview) (string, error) {\n\tobj := make(map[string]string)\n\tif op.Overflow {\n\t\tlogger.Debugf(\"parseConsoleRemoteObjectPreview\", \"object is too large and will be parsed partially\")\n\t}\n\n\tfor _, p := range op.Properties {\n\t\tval, err := parseConsoleRemoteObjectValue(logger, p.Type, p.Subtype, p.Value, p.ValuePreview)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tobj[p.Name] = val\n\t}\n\n\tbb, err := json.Marshal(obj)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"marshaling object %q to string: %w\", obj, err)\n\t}\n\n\treturn string(bb), nil\n}\n\nfunc parseConsoleRemoteArrayPreview(logger *log.Logger, op *runtime.ObjectPreview) (string, error) {\n\tarr := make([]any, 0, len(op.Properties))\n\tif op.Overflow {\n\t\tlogger.Debugf(\"parseConsoleRemoteArrayPreview\", \"array is too large and will be parsed partially\")\n\t}\n\n\tfor _, p := range op.Properties {\n\t\tval, err := parseConsoleRemoteObjectValue(logger, p.Type, p.Subtype, p.Value, p.ValuePreview)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tarr = append(arr, val)\n\t}\n\n\tbb, err := json.Marshal(arr)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"marshaling array %q to string: %w\", arr, err)\n\t}\n\n\treturn string(bb), nil\n}\n\nfunc parseConsoleRemoteObjectValue(\n\tlogger *log.Logger,\n\tt runtime.Type,\n\tst runtime.Subtype,\n\tval string,\n\top *runtime.ObjectPreview,\n) (string, error) {\n\tswitch t {\n\tcase runtime.TypeAccessor:\n\t\treturn \"accessor\", nil\n\tcase runtime.TypeFunction:\n\t\treturn \"function()\", nil\n\tcase runtime.TypeString:\n\t\tif after, ok := strings.CutPrefix(val, `\"`); ok {\n\t\t\tval = after\n\t\t\tval = strings.TrimSuffix(val, `\"`)\n\t\t}\n\tcase runtime.TypeObject:\n\t\tif op != nil {\n\t\t\tif st == \"array\" {\n\t\t\t\treturn parseConsoleRemoteArrayPreview(logger, op)\n\t\t\t}\n\t\t\treturn parseConsoleRemoteObjectPreview(logger, op)\n\t\t}\n\t\tif val == \"Object\" {\n\t\t\treturn val, nil\n\t\t}\n\t\tif st == \"null\" {\n\t\t\treturn \"null\", nil\n\t\t}\n\tcase runtime.TypeUndefined:\n\t\treturn \"undefined\", nil\n\t// The following cases are here to clarify that all cases have been\n\t// considered, but that the result will return val without processing it.\n\tcase runtime.TypeNumber:\n\tcase runtime.TypeBoolean:\n\tcase runtime.TypeSymbol:\n\tcase runtime.TypeBigint:\n\t}\n\n\treturn val, nil\n}\n\n// parseConsoleRemoteObject is to be used by callers that are working with\n// console messages that are written to Chrome's console by the website under\n// test.\nfunc parseConsoleRemoteObject(logger *log.Logger, obj *runtime.RemoteObject) (string, error) {\n\tif obj.UnserializableValue != \"\" {\n\t\treturn obj.UnserializableValue.String(), nil\n\t}\n\n\treturn parseConsoleRemoteObjectValue(logger, obj.Type, obj.Subtype, string(obj.Value), obj.Preview)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/remote_object_test.go",
    "content": "package common\n\nimport (\n\t\"encoding/json\"\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n)\n\nfunc TestValueFromRemoteObject(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"unserializable value error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\tunserializableValue := runtime.UnserializableValue(\"a string instead\")\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:                \"number\",\n\t\t\tUnserializableValue: unserializableValue,\n\t\t}\n\n\t\targ, err := valueFromRemoteObject(vu.Context(), remoteObject)\n\t\trequire.Nil(t, arg)\n\t\trequire.ErrorIs(t, UnserializableValueError{unserializableValue}, err)\n\t})\n\n\tt.Run(\"bigint parsing error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\tunserializableValue := runtime.UnserializableValue(\"a string instead\")\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:                \"bigint\",\n\t\t\tUnserializableValue: unserializableValue,\n\t\t}\n\n\t\targ, err := valueFromRemoteObject(vu.Context(), remoteObject)\n\n\t\trequire.Nil(t, arg)\n\t\tassert.ErrorIs(t, UnserializableValueError{unserializableValue}, err)\n\t})\n\n\tt.Run(\"float64 unserializable values\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\tunserializableValues := []struct {\n\t\t\tvalue    string\n\t\t\texpected float64\n\t\t}{\n\t\t\t{\n\t\t\t\tvalue:    \"-0\",\n\t\t\t\texpected: math.Float64frombits(0 | (1 << 63)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue:    \"Infinity\",\n\t\t\t\texpected: math.Inf(0),\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue:    \"-Infinity\",\n\t\t\t\texpected: math.Inf(-1),\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue:    \"NaN\",\n\t\t\t\texpected: math.NaN(),\n\t\t\t},\n\t\t}\n\n\t\tfor _, v := range unserializableValues {\n\t\t\tremoteObject := &runtime.RemoteObject{\n\t\t\t\tType:                \"number\",\n\t\t\t\tUnserializableValue: runtime.UnserializableValue(v.value),\n\t\t\t}\n\t\t\targ, err := valueFromRemoteObject(vu.Context(), remoteObject)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, arg)\n\t\t\trequire.IsType(t, float64(0), arg)\n\t\t\tif v.value == \"NaN\" {\n\t\t\t\trequire.True(t, math.IsNaN(arg.(float64)))\n\t\t\t} else {\n\t\t\t\trequire.Equal(t, v.expected, arg.(float64))\n\t\t\t}\n\t\t}\n\t})\n\n\tt.Run(\"undefined\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType: runtime.TypeUndefined,\n\t\t}\n\n\t\targ, err := valueFromRemoteObject(vu.Context(), remoteObject)\n\t\trequire.NoError(t, err)\n\t\trequire.Nil(t, arg)\n\t})\n\n\tt.Run(\"null\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvu := k6test.NewVU(t)\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:    runtime.TypeObject,\n\t\t\tSubtype: runtime.SubtypeNull,\n\t\t}\n\n\t\targ, err := valueFromRemoteObject(vu.Context(), remoteObject)\n\t\trequire.NoError(t, err)\n\t\trequire.Nil(t, arg)\n\t})\n\n\tt.Run(\"primitive types\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tprimitiveTypes := []struct {\n\t\t\ttyp   runtime.Type\n\t\t\tvalue any\n\t\t}{\n\t\t\t{\n\t\t\t\ttyp:   \"number\",\n\t\t\t\tvalue: float64(777), // js numbers are float64\n\t\t\t},\n\t\t\t{\n\t\t\t\ttyp:   \"number\",\n\t\t\t\tvalue: float64(777.0),\n\t\t\t},\n\t\t\t{\n\t\t\t\ttyp:   \"string\",\n\t\t\t\tvalue: \"hello world\",\n\t\t\t},\n\t\t\t{\n\t\t\t\ttyp:   \"boolean\",\n\t\t\t\tvalue: true,\n\t\t\t},\n\t\t}\n\n\t\tvu := k6test.NewVU(t)\n\t\tfor _, p := range primitiveTypes {\n\t\t\tmarshalled, _ := json.Marshal(p.value)\n\t\t\tremoteObject := &runtime.RemoteObject{\n\t\t\t\tType:  p.typ,\n\t\t\t\tValue: marshalled,\n\t\t\t}\n\n\t\t\targ, err := valueFromRemoteObject(vu.Context(), remoteObject)\n\n\t\t\trequire.Nil(t, err)\n\t\t\trequire.IsType(t, p.value, arg)\n\t\t}\n\t})\n\n\tt.Run(\"remote object with ID\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tremoteObjectID := runtime.RemoteObjectID(\"object_id_0123456789\")\n\t\tremoteObject := &runtime.RemoteObject{\n\t\t\tType:     \"object\",\n\t\t\tSubtype:  \"node\",\n\t\t\tObjectID: remoteObjectID,\n\t\t\tPreview: &runtime.ObjectPreview{\n\t\t\t\tProperties: []*runtime.PropertyPreview{\n\t\t\t\t\t{Name: \"num\", Type: runtime.TypeNumber, Value: \"1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\tvu := k6test.NewVU(t)\n\t\tval, err := valueFromRemoteObject(vu.Context(), remoteObject)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, map[string]any{\"num\": float64(1)}, val)\n\t})\n}\n\nfunc TestParseRemoteObject(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tsubtype  string\n\t\tpreview  *runtime.ObjectPreview\n\t\tvalue    jsontext.Value\n\t\texpected any\n\t\texpErr   string\n\t}{\n\t\t{\n\t\t\tname: \"most_types\",\n\t\t\tpreview: &runtime.ObjectPreview{\n\t\t\t\tProperties: []*runtime.PropertyPreview{\n\t\t\t\t\t{Name: \"accessor\", Type: runtime.TypeAccessor, Value: \"\"},\n\t\t\t\t\t{Name: \"bigint\", Type: runtime.TypeBigint, Value: \"100n\"},\n\t\t\t\t\t{Name: \"bool\", Type: runtime.TypeBoolean, Value: \"true\"},\n\t\t\t\t\t{Name: \"fn\", Type: runtime.TypeFunction, Value: \"\"},\n\t\t\t\t\t{Name: \"num\", Type: runtime.TypeNumber, Value: \"1\"},\n\t\t\t\t\t{Name: \"str\", Type: runtime.TypeString, Value: \"string\"},\n\t\t\t\t\t{Name: \"strquot\", Type: runtime.TypeString, Value: `\"quoted string\"`},\n\t\t\t\t\t{Name: \"sym\", Type: runtime.TypeSymbol, Value: \"Symbol()\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: map[string]any{\n\t\t\t\t\"accessor\": \"accessor\",\n\t\t\t\t\"bigint\":   int64(100),\n\t\t\t\t\"bool\":     true,\n\t\t\t\t\"fn\":       \"function()\",\n\t\t\t\t\"num\":      float64(1),\n\t\t\t\t\"str\":      \"string\",\n\t\t\t\t\"strquot\":  \"quoted string\",\n\t\t\t\t\"sym\":      \"Symbol()\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"nested\",\n\t\t\tpreview: &runtime.ObjectPreview{\n\t\t\t\tProperties: []*runtime.PropertyPreview{\n\t\t\t\t\t// We don't actually get nested ObjectPreviews from CDP.\n\t\t\t\t\t// I.e. the object `{nested: {one: 1}}` returns value \"Object\"\n\t\t\t\t\t// for the \"nested\" property, with a nil *ValuePreview. :-/\n\t\t\t\t\t{Name: \"nested\", Type: runtime.TypeObject, Value: \"Object\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: map[string]any{\n\t\t\t\t\"nested\": \"Object\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:     \"err_overflow\",\n\t\t\tpreview:  &runtime.ObjectPreview{Overflow: true},\n\t\t\texpected: map[string]any{},\n\t\t\texpErr:   \"object is too large and will be parsed partially\",\n\t\t},\n\t\t{\n\t\t\tname: \"err_parsing_property\",\n\t\t\tpreview: &runtime.ObjectPreview{\n\t\t\t\tProperties: []*runtime.PropertyPreview{\n\t\t\t\t\t{Name: \"failprop\", Type: runtime.TypeObject, Value: \"some\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\texpected: map[string]any{},\n\t\t\texpErr:   \"parsing object property\",\n\t\t},\n\t\t{\n\t\t\tname:     \"null\",\n\t\t\tsubtype:  \"null\",\n\t\t\tvalue:    nil,\n\t\t\texpected: nil,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tremoteObject := &runtime.RemoteObject{\n\t\t\t\tType:     \"object\",\n\t\t\t\tSubtype:  runtime.Subtype(tc.subtype),\n\t\t\t\tObjectID: runtime.RemoteObjectID(\"object_id_0123456789\"),\n\t\t\t\tPreview:  tc.preview,\n\t\t\t\tValue:    tc.value,\n\t\t\t}\n\t\t\tval, err := parseRemoteObject(remoteObject)\n\t\t\tassert.Equal(t, tc.expected, val)\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\tassert.Contains(t, err.Error(), tc.expErr)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/screenshotter.go",
    "content": "package common\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/emulation\"\n\tcdppage \"github.com/chromedp/cdproto/page\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\n// ScreenshotPersister is the type that all file persisters must implement. It's job is\n// to persist a file somewhere, hiding the details of where and how from the caller.\ntype ScreenshotPersister interface {\n\tPersist(ctx context.Context, path string, data io.Reader) (err error)\n}\n\n// ImageFormat represents an image file format.\ntype ImageFormat string\n\n// Valid image format options.\nconst (\n\tImageFormatJPEG ImageFormat = \"jpeg\"\n\tImageFormatPNG  ImageFormat = \"png\"\n)\n\nfunc (f ImageFormat) String() string {\n\treturn imageFormatToString[f]\n}\n\nvar imageFormatToString = map[ImageFormat]string{ //nolint:gochecknoglobals\n\tImageFormatJPEG: \"jpeg\",\n\tImageFormatPNG:  \"png\",\n}\n\nvar imageFormatToID = map[string]ImageFormat{ //nolint:gochecknoglobals\n\t\"jpeg\": ImageFormatJPEG,\n\t\"png\":  ImageFormatPNG,\n}\n\n// MarshalJSON marshals the enum as a quoted JSON string.\nfunc (f ImageFormat) MarshalJSON() ([]byte, error) {\n\tbuffer := bytes.NewBufferString(`\"`)\n\tbuffer.WriteString(imageFormatToString[f])\n\tbuffer.WriteString(`\"`)\n\treturn buffer.Bytes(), nil\n}\n\n// UnmarshalJSON unmarshals a quoted JSON string to the enum value.\nfunc (f *ImageFormat) UnmarshalJSON(b []byte) error {\n\tvar j string\n\terr := json.Unmarshal(b, &j)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshalling image format: %w\", err)\n\t}\n\t// Note that if the string cannot be found then it will be set to the zero value.\n\t*f = imageFormatToID[j]\n\treturn nil\n}\n\ntype screenshotter struct {\n\tctx       context.Context\n\tpersister ScreenshotPersister\n\tlogger    *log.Logger\n}\n\nfunc newScreenshotter(\n\tctx context.Context,\n\tsp ScreenshotPersister,\n\tlogger *log.Logger,\n) *screenshotter {\n\treturn &screenshotter{ctx, sp, logger}\n}\n\nfunc (s *screenshotter) fullPageSize(p *Page) (*Size, error) {\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := p.frameManager.MainFrame().evaluate(s.ctx, mainWorld, opts, `\n        () => {\n            if (!document.body || !document.documentElement) {\n                return null;\n            }\n            return {\n                width: Math.max(\n                    document.body.scrollWidth, document.documentElement.scrollWidth,\n                    document.body.offsetWidth, document.documentElement.offsetWidth,\n                    document.body.clientWidth, document.documentElement.clientWidth\n                ),\n                height: Math.max(\n                    document.body.scrollHeight, document.documentElement.scrollHeight,\n                    document.body.offsetHeight, document.documentElement.offsetHeight,\n                    document.body.clientHeight, document.documentElement.clientHeight\n                ),\n            };\n        }`)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar size Size\n\tif err := convert(result, &size); err != nil {\n\t\treturn nil, fmt.Errorf(\"converting result (%v of type %t) to size: %w\", result, result, err)\n\t}\n\n\treturn &size, nil\n}\n\nfunc (s *screenshotter) originalViewportSize(p *Page) (*Size, *Size, error) {\n\toriginalViewportSize := p.viewportSize()\n\tviewportSize := originalViewportSize\n\tif viewportSize.Width != 0 || viewportSize.Height != 0 {\n\t\treturn &viewportSize, &originalViewportSize, nil\n\t}\n\n\topts := evalOptions{\n\t\tforceCallable: true,\n\t\treturnByValue: true,\n\t}\n\tresult, err := p.frameManager.MainFrame().evaluate(s.ctx, mainWorld, opts, `\n\t() => (\n\t\t{ width: window.innerWidth, height: window.innerHeight }\n\t)`)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"getting viewport dimensions: %w\", err)\n\t}\n\n\tvar returnVal Size\n\tif err := convert(result, &returnVal); err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"unpacking window size: %w\", err)\n\t}\n\n\tviewportSize.Width = returnVal.Width\n\tviewportSize.Height = returnVal.Height\n\n\treturn &viewportSize, &originalViewportSize, nil\n}\n\nfunc (s *screenshotter) restoreViewport(p *Page, originalViewport *Size) error {\n\tif originalViewport != nil {\n\t\treturn p.setViewportSize(originalViewport)\n\t}\n\treturn p.resetViewport()\n}\n\nfunc (s *screenshotter) screenshot(\n\tsess session, doc, viewport *Rect, format ImageFormat, omitBackground bool, quality int64, path string,\n) ([]byte, error) {\n\tvar (\n\t\tbuf  []byte\n\t\tclip *cdppage.Viewport\n\t)\n\tcapture := cdppage.CaptureScreenshot()\n\n\tshouldSetDefaultBackground := omitBackground && format == \"png\"\n\tif shouldSetDefaultBackground {\n\t\taction := emulation.SetDefaultBackgroundColorOverride().\n\t\t\tWithColor(&cdp.RGBA{R: 0, G: 0, B: 0, A: 0})\n\t\tif err := action.Do(cdp.WithExecutor(s.ctx, sess)); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"setting screenshot background transparency: %w\", err)\n\t\t}\n\t}\n\n\t// Add common options\n\tcapture.WithQuality(quality)\n\tswitch format {\n\tcase ImageFormatJPEG:\n\t\tcapture.WithFormat(cdppage.CaptureScreenshotFormatJpeg)\n\tdefault:\n\t\tcapture.WithFormat(cdppage.CaptureScreenshotFormatPng)\n\t}\n\n\tvisualViewportScale, visualViewportPageX, visualViewportPageY, err := getViewPortDimensions(s.ctx, sess, s.logger)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif doc == nil {\n\t\ts := Size{\n\t\t\tWidth:  viewport.Width / visualViewportScale,\n\t\t\tHeight: viewport.Height / visualViewportScale,\n\t\t}.enclosingIntSize()\n\t\tdoc = &Rect{\n\t\t\tX:      visualViewportPageX + viewport.X,\n\t\t\tY:      visualViewportPageY + viewport.Y,\n\t\t\tWidth:  s.Width,\n\t\t\tHeight: s.Height,\n\t\t}\n\t}\n\n\tscale := 1.0\n\tif viewport != nil {\n\t\tscale = visualViewportScale\n\t}\n\tclip = &cdppage.Viewport{\n\t\tX:      doc.X,\n\t\tY:      doc.Y,\n\t\tWidth:  doc.Width,\n\t\tHeight: doc.Height,\n\t\tScale:  scale,\n\t}\n\tif clip.Width > 0 && clip.Height > 0 {\n\t\tcapture = capture.WithClip(clip)\n\t}\n\n\t// Capture screenshot\n\tbuf, err = capture.Do(cdp.WithExecutor(s.ctx, sess))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"capturing screenshot: %w\", err)\n\t}\n\n\tif shouldSetDefaultBackground {\n\t\taction := emulation.SetDefaultBackgroundColorOverride()\n\t\tif err := action.Do(cdp.WithExecutor(s.ctx, sess)); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"resetting screenshot background color: %w\", err)\n\t\t}\n\t}\n\n\t// Save screenshot capture to file\n\tif path != \"\" {\n\t\tif err := s.persister.Persist(s.ctx, path, bytes.NewBuffer(buf)); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"persisting screenshot: %w\", err)\n\t\t}\n\t}\n\n\treturn buf, nil\n}\n\nfunc getViewPortDimensions(ctx context.Context, sess session, logger *log.Logger) (float64, float64, float64, error) {\n\tvisualViewportScale := 1.0\n\tvisualViewportPageX, visualViewportPageY := 0.0, 0.0\n\n\t// Add clip region\n\t//nolint:dogsled\n\t_, _, _, _, cssVisualViewport, _, err := cdppage.GetLayoutMetrics().Do(cdp.WithExecutor(ctx, sess))\n\tif err != nil {\n\t\treturn 0, 0, 0, fmt.Errorf(\"getting layout metrics for screenshot: %w\", err)\n\t}\n\n\t// we had a null pointer panic cases, when visualViewport is nil\n\t// instead of the erroring out, we fallback to defaults and still try to do a screenshot\n\tif cssVisualViewport != nil {\n\t\tvisualViewportScale = cssVisualViewport.Scale\n\t\tvisualViewportPageX = cssVisualViewport.PageX\n\t\tvisualViewportPageY = cssVisualViewport.PageY\n\t} else {\n\t\tlogger.Warnf(\n\t\t\t\"Screenshotter::screenshot\",\n\t\t\t\"chrome browser returned nil on page.getLayoutMetrics, falling back to defaults for cssVisualViewport \"+\n\t\t\t\t\"(scale: %v, pageX: %v, pageY: %v).\"+\n\t\t\t\t\"This is non-standard behavior, if possible please report this issue (with a reproducible script) \"+\n\t\t\t\t\"to the https://github.com/grafana/k6/issues/new.\",\n\t\t\tvisualViewportScale, visualViewportPageX, visualViewportPageY,\n\t\t)\n\t}\n\n\treturn visualViewportScale, visualViewportPageX, visualViewportPageY, nil\n}\n\nfunc (s *screenshotter) screenshotElement(h *ElementHandle, opts *ElementHandleScreenshotOptions) ([]byte, error) {\n\tformat := opts.Format\n\tviewportSize, originalViewportSize, err := s.originalViewportSize(h.frame.page)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting original viewport size: %w\", err)\n\t}\n\n\terr = h.waitAndScrollIntoViewIfNeeded(h.ctx, false, true, opts.Timeout)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"scrolling element into view: %w\", err)\n\t}\n\n\tbbox, err := h.boundingBox()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"node is either not visible or not an HTMLElement: %w\", err)\n\t}\n\tif bbox.Width <= 0 {\n\t\treturn nil, fmt.Errorf(\"node has 0 width\")\n\t}\n\tif bbox.Height <= 0 {\n\t\treturn nil, fmt.Errorf(\"node has 0 height\")\n\t}\n\n\tvar overriddenViewportSize *Size\n\tfitsViewport := bbox.Width <= viewportSize.Width && bbox.Height <= viewportSize.Height\n\tif !fitsViewport { //nolint:nestif\n\t\toverriddenViewportSize = Size{\n\t\t\tWidth:  math.Max(viewportSize.Width, bbox.Width),\n\t\t\tHeight: math.Max(viewportSize.Height, bbox.Height),\n\t\t}.enclosingIntSize()\n\t\tif err := h.frame.page.setViewportSize(overriddenViewportSize); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"setting viewport size to %s: %w\",\n\t\t\t\toverriddenViewportSize, err)\n\t\t}\n\t\terr = h.waitAndScrollIntoViewIfNeeded(h.ctx, false, true, opts.Timeout)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"scrolling element into view: %w\", err)\n\t\t}\n\t\tbbox, err = h.boundingBox()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"node is either not visible or not an HTMLElement: %w\", err)\n\t\t}\n\t\tif bbox.Width <= 0 {\n\t\t\treturn nil, fmt.Errorf(\"node has 0 width\")\n\t\t}\n\t\tif bbox.Height <= 0 {\n\t\t\treturn nil, fmt.Errorf(\"node has 0 height\")\n\t\t}\n\t}\n\n\tscrollOffset, err := h.Evaluate(`() => { return {x: window.scrollX, y: window.scrollY};}`)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating scroll offset: %w\", err)\n\t}\n\n\tvar returnVal Position\n\tif err := convert(scrollOffset, &returnVal); err != nil {\n\t\treturn nil, fmt.Errorf(\"unpacking scroll offset: %w\", err)\n\t}\n\n\tdocumentRect := bbox\n\tdocumentRect.X += returnVal.X\n\tdocumentRect.Y += returnVal.Y\n\n\tbuf, err := s.screenshot(\n\t\th.frame.page.session,\n\t\tdocumentRect.enclosingIntRect(),\n\t\tnil, // viewportRect\n\t\tformat,\n\t\topts.OmitBackground,\n\t\topts.Quality,\n\t\topts.Path,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif overriddenViewportSize != nil {\n\t\tif err := s.restoreViewport(h.frame.page, originalViewportSize); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"restoring viewport: %w\", err)\n\t\t}\n\t}\n\n\treturn buf, nil\n}\n\nfunc (s *screenshotter) screenshotPage(p *Page, opts *PageScreenshotOptions) ([]byte, error) {\n\tformat := opts.Format\n\n\t// Infer file format by path\n\tif opts.Path != \"\" && opts.Format != \"png\" && opts.Format != \"jpeg\" {\n\t\tif strings.HasSuffix(opts.Path, \".jpg\") || strings.HasSuffix(opts.Path, \".jpeg\") {\n\t\t\tformat = \"jpeg\"\n\t\t}\n\t}\n\n\tviewportSize, originalViewportSize, err := s.originalViewportSize(p)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"getting original viewport size: %w\", err)\n\t}\n\n\tif opts.FullPage { //nolint:nestif\n\t\tfullPageSize, err := s.fullPageSize(p)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"getting full page size: %w\", err)\n\t\t}\n\t\tdocumentRect := &Rect{\n\t\t\tX:      0,\n\t\t\tY:      0,\n\t\t\tWidth:  fullPageSize.Width,\n\t\t\tHeight: fullPageSize.Height,\n\t\t}\n\t\tvar overriddenViewportSize *Size\n\t\tfitsViewport := fullPageSize.Width <= viewportSize.Width && fullPageSize.Height <= viewportSize.Height\n\t\tif !fitsViewport {\n\t\t\toverriddenViewportSize = fullPageSize\n\t\t\tif err := p.setViewportSize(overriddenViewportSize); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"setting viewport size to %s: %w\",\n\t\t\t\t\toverriddenViewportSize, err)\n\t\t\t}\n\t\t}\n\t\tif opts.Clip != nil {\n\t\t\tdocumentRect, err = s.trimClipToSize(&Rect{\n\t\t\t\tX:      opts.Clip.X,\n\t\t\t\tY:      opts.Clip.Y,\n\t\t\t\tWidth:  opts.Clip.Width,\n\t\t\t\tHeight: opts.Clip.Height,\n\t\t\t}, &Size{Width: documentRect.Width, Height: documentRect.Height})\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"trimming clip to size: %w\", err)\n\t\t\t}\n\t\t}\n\n\t\tbuf, err := s.screenshot(p.session, documentRect, nil, format, opts.OmitBackground, opts.Quality, opts.Path)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif overriddenViewportSize != nil {\n\t\t\tif err := s.restoreViewport(p, originalViewportSize); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"restoring viewport to %s: %w\",\n\t\t\t\t\toriginalViewportSize, err)\n\t\t\t}\n\t\t}\n\t\treturn buf, nil\n\t}\n\n\tviewportRect := &Rect{\n\t\tX:      0,\n\t\tY:      0,\n\t\tWidth:  viewportSize.Width,\n\t\tHeight: viewportSize.Height,\n\t}\n\tif opts.Clip != nil {\n\t\tviewportRect, err = s.trimClipToSize(&Rect{\n\t\t\tX:      opts.Clip.X,\n\t\t\tY:      opts.Clip.Y,\n\t\t\tWidth:  opts.Clip.Width,\n\t\t\tHeight: opts.Clip.Height,\n\t\t}, viewportSize)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"trimming clip to size: %w\", err)\n\t\t}\n\t}\n\treturn s.screenshot(p.session, nil, viewportRect, format, opts.OmitBackground, opts.Quality, opts.Path)\n}\n\nfunc (s *screenshotter) trimClipToSize(clip *Rect, size *Size) (*Rect, error) {\n\tp1 := Position{\n\t\tX: math.Max(0, math.Min(clip.X, size.Width)),\n\t\tY: math.Max(0, math.Min(clip.Y, size.Height)),\n\t}\n\tp2 := Position{\n\t\tX: math.Max(0, math.Min(clip.X+clip.Width, size.Width)),\n\t\tY: math.Max(0, math.Min(clip.Y+clip.Height, size.Height)),\n\t}\n\tresult := Rect{\n\t\tX:      p1.X,\n\t\tY:      p1.Y,\n\t\tWidth:  p2.X - p1.X,\n\t\tHeight: p2.Y - p1.Y,\n\t}\n\tif result.Width == 0 || result.Height == 0 {\n\t\treturn nil, errors.New(\"clip area is either empty or outside the viewport\")\n\t}\n\treturn &result, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/selectors.go",
    "content": "/**\n * Copyright (c) Microsoft Corporation.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage common\n\nimport (\n\t\"errors\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n// Matches `name:body`, a query engine name and selector for that engine.\nvar reQueryEngine *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z_0-9-+:*]+$`)\n\n// Matches start of XPath query.\nvar reXPathSelector *regexp.Regexp = regexp.MustCompile(`^\\(*//`)\n\n// Matches the text selectors of the form text=<value>\nvar reTextSelector *regexp.Regexp = regexp.MustCompile(`^\\s*text\\s*=\\s*(.*)$`)\n\ntype SelectorPart struct {\n\tName string `json:\"name\"`\n\tBody string `json:\"body\"`\n}\n\ntype Selector struct {\n\tSelector string          `json:\"selector\"`\n\tParts    []*SelectorPart `json:\"parts\"`\n\n\t// By default chained queries resolve to elements matched by the last selector,\n\t// but a selector can be prefixed with `*` to capture elements resolved by\n\t// an intermediate selector.\n\tCapture *int `json:\"capture\"`\n}\n\nfunc NewSelector(selector string) (*Selector, error) {\n\tif selector == \"\" {\n\t\treturn nil, errors.New(\"provided selector is empty\")\n\t}\n\n\ts := Selector{\n\t\tSelector: selector,\n\t\tParts:    make([]*SelectorPart, 0, 1),\n\t\tCapture:  nil,\n\t}\n\terr := s.parse()\n\treturn &s, err\n}\n\nfunc (s *Selector) appendPart(p *SelectorPart, capture bool) error {\n\ts.Parts = append(s.Parts, p)\n\tif capture {\n\t\tif s.Capture != nil {\n\t\t\treturn errors.New(\"only one of the selectors can capture using * modifier\")\n\t\t}\n\t\ts.Capture = new(int)\n\t\t*s.Capture = (len(s.Parts) - 1)\n\t}\n\treturn nil\n}\n\n// parse splits the selector into parts, separated by `>>`, and identifies\n// the query engine for each part.\n//\n//nolint:cyclop,funlen\nfunc (s *Selector) parse() error {\n\tparsePart := func(part string) (*SelectorPart, bool) {\n\t\tpart = strings.TrimSpace(part)\n\t\tif part == \"\" {\n\t\t\treturn nil, false\n\t\t}\n\n\t\tbefore, after, ok := strings.Cut(part, \"=\")\n\t\tvar name, body string\n\n\t\tswitch {\n\t\tcase ok && reQueryEngine.MatchString(strings.TrimSpace(before)):\n\t\t\tname = strings.TrimSpace(before)\n\t\t\tbody = after\n\t\tcase len(part) > 1 && part[0] == '\"' && part[len(part)-1] == '\"':\n\t\t\tname = \"text\"\n\t\t\tbody = part\n\t\tcase len(part) > 1 && part[0] == '\\'' && part[len(part)-1] == '\\'':\n\t\t\tname = \"text\"\n\t\t\tbody = part\n\t\tcase reXPathSelector.MatchString(part) || strings.HasPrefix(part, \"..\"):\n\t\t\tname = \"xpath\"\n\t\t\tbody = part\n\t\tdefault:\n\t\t\tname = \"css\"\n\t\t\tbody = part\n\t\t}\n\n\t\tcapture := false\n\t\tif strings.HasPrefix(name, \"*\") {\n\t\t\tcapture = true\n\t\t\tname = name[1:]\n\t\t}\n\n\t\treturn &SelectorPart{Name: name, Body: body}, capture\n\t}\n\n\tvar (\n\t\tstart, index int\n\t\tquote        rune\n\t)\n\n\tappendPart := func(start, end int) error {\n\t\tp, capture := parsePart(s.Selector[start:end])\n\t\t// Skip empty segments between `>>`, e.g., when there are consecutive `>>` or leading/trailing `>>`.\n\t\tif p == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn s.appendPart(p, capture)\n\t}\n\n\tif !strings.Contains(s.Selector, \">>\") {\n\t\treturn appendPart(0, len(s.Selector))\n\t}\n\n\tshouldIgnoreTextSelectorQuote := func(start, end int) bool {\n\t\tprefix := s.Selector[start:end]\n\t\tif match := reTextSelector.FindStringSubmatch(prefix); match != nil && match[1] != \"\" {\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tfor index < len(s.Selector) {\n\t\tc := rune(s.Selector[index])\n\t\tswitch {\n\t\tcase c == '\\\\' && index+1 < len(s.Selector):\n\t\t\tindex += 2\n\t\tcase c == quote:\n\t\t\tquote = 0\n\t\t\tindex++\n\t\tcase quote == 0 && (c == '\"' || c == '\\'' || c == '`') && !shouldIgnoreTextSelectorQuote(start, index):\n\t\t\tquote = c\n\t\t\tindex++\n\t\tcase quote == 0 && c == '>' && index+1 < len(s.Selector) && s.Selector[index+1] == '>':\n\t\t\tif err := appendPart(start, index); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tindex += 2\n\t\t\tstart = index\n\t\tdefault:\n\t\t\tindex++\n\t\t}\n\t}\n\n\treturn appendPart(start, index)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/selectors_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSelectorParse(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname          string\n\t\tinput         string\n\t\texpectedParts []*SelectorPart\n\t\texpectedCap   *int\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tname:          \"Empty selector\",\n\t\t\tinput:         \"\",\n\t\t\texpectedParts: nil,\n\t\t\texpectedCap:   nil,\n\t\t\texpectedError: \"provided selector is empty\",\n\t\t},\n\t\t{\n\t\t\tname:  \"Escaped quotes in text\",\n\t\t\tinput: `text=\"Click the \\\"Submit\\\" button\"`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"text\", Body: `\"Click the \\\"Submit\\\" button\"`},\n\t\t\t},\n\t\t\texpectedCap: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"Chain with >> and nth\",\n\t\t\tinput: `css=div.container >> text=\"Login\" >> nth=0`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"css\", Body: \"div.container\"},\n\t\t\t\t{Name: \"text\", Body: `\"Login\"`},\n\t\t\t\t{Name: \"nth\", Body: \"0\"},\n\t\t\t},\n\t\t\texpectedCap: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"XPath selector\",\n\t\t\tinput: `(//div[@class=\"item\"])[2] >> text=\"Buy\"`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"xpath\", Body: `(//div[@class=\"item\"])[2]`},\n\t\t\t\t{Name: \"text\", Body: `\"Buy\"`},\n\t\t\t},\n\t\t\texpectedCap: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"Capture selector\",\n\t\t\tinput: `*css=div.list >> text=\"Product 2\"`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"css\", Body: \"div.list\"},\n\t\t\t\t{Name: \"text\", Body: `\"Product 2\"`},\n\t\t\t},\n\t\t\texpectedCap: func() *int { i := 0; return &i }(),\n\t\t},\n\t\t{\n\t\t\tname:  \"Internal has-text\",\n\t\t\tinput: `internal:has-text=\"Some text\"`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"internal:has-text\", Body: `\"Some text\"`},\n\t\t\t},\n\t\t\texpectedCap: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"Capture + escaped quotes\",\n\t\t\tinput: `*text=\"Item \\\"Special\\\" >> Button\"`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"text\", Body: `\"Item \\\"Special\\\" >> Button\"`},\n\t\t\t},\n\t\t\texpectedCap: func() *int { i := 0; return &i }(),\n\t\t},\n\t\t{\n\t\t\tname:  \"Spaces around =\",\n\t\t\tinput: `text = \"Login\"`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"text\", Body: ` \"Login\"`},\n\t\t\t},\n\t\t\texpectedCap: nil,\n\t\t},\n\t\t{\n\t\t\tname:  \"Space between >>\",\n\t\t\tinput: `css=\"div\" >> >> text=\"item\"`,\n\t\t\texpectedParts: []*SelectorPart{\n\t\t\t\t{Name: \"css\", Body: `\"div\"`},\n\t\t\t\t{Name: \"text\", Body: `\"item\"`},\n\t\t\t},\n\t\t\texpectedCap: nil,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsel, err := NewSelector(tc.input)\n\n\t\t\tif tc.expectedError != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.ErrorContains(t, err, tc.expectedError)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.expectedParts, sel.Parts, \"Parts mismatch\")\n\t\t\tassert.EqualValues(t, tc.expectedCap, sel.Capture, \"Capture mismatch\")\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/session.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"errors\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/target\"\n\tjsonv2 \"github.com/go-json-experiment/json\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n)\n\n// Session represents a CDP session to a target.\ntype Session struct {\n\tBaseEventEmitter\n\n\tconn     *Connection\n\tid       target.SessionID\n\ttargetID target.ID\n\tmsgIDGen msgIDGenerator\n\treadCh   chan *cdproto.Message\n\tdone     chan struct{}\n\tclosed   bool\n\tcrashed  bool\n\n\tlogger *log.Logger\n}\n\n// NewSession creates a new session.\nfunc NewSession(\n\tctx context.Context, conn *Connection, id target.SessionID, tid target.ID, logger *log.Logger, msgIDGen msgIDGenerator,\n) *Session {\n\ts := Session{\n\t\tBaseEventEmitter: NewBaseEventEmitter(ctx),\n\t\tconn:             conn,\n\t\tid:               id,\n\t\ttargetID:         tid,\n\t\treadCh:           make(chan *cdproto.Message),\n\t\tdone:             make(chan struct{}),\n\t\tmsgIDGen:         msgIDGen,\n\n\t\tlogger: logger,\n\t}\n\ts.logger.Debugf(\"Session:NewSession\", \"sid:%v tid:%v\", id, tid)\n\tgo s.readLoop()\n\treturn &s\n}\n\n// ID returns session ID.\nfunc (s *Session) ID() target.SessionID {\n\treturn s.id\n}\n\n// TargetID returns session's target ID.\nfunc (s *Session) TargetID() target.ID {\n\treturn s.targetID\n}\n\nfunc (s *Session) close() {\n\ts.logger.Debugf(\"Session:close\", \"sid:%v tid:%v\", s.id, s.targetID)\n\tif s.closed {\n\t\ts.logger.Debugf(\"Session:close\", \"already closed, sid:%v tid:%v\", s.id, s.targetID)\n\t\treturn\n\t}\n\n\t// Stop the read loop\n\tclose(s.done)\n\ts.closed = true\n}\n\nfunc (s *Session) markAsCrashed() {\n\ts.logger.Debugf(\"Session:markAsCrashed\", \"sid:%v tid:%v\", s.id, s.targetID)\n\ts.crashed = true\n}\n\n// Wraps conn.ReadMessage in a channel.\nfunc (s *Session) readLoop() {\n\tfor {\n\t\tselect {\n\t\tcase msg := <-s.readCh:\n\t\t\tev, err := cdproto.UnmarshalMessage(msg)\n\t\t\tif errors.Is(err, cdp.ErrUnknownCommandOrEvent(\"\")) && msg.Method == \"\" {\n\t\t\t\t// Results from commands may not always have methods in them.\n\t\t\t\t// This is the reason of this error. So it's harmless.\n\t\t\t\t//\n\t\t\t\t// Also:\n\t\t\t\t// This is most likely an event received from an older\n\t\t\t\t// Chrome which a newer cdproto doesn't have, as it is\n\t\t\t\t// deprecated. Ignore that error, and emit raw cdproto.Message.\n\t\t\t\ts.emit(\"\", msg)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\ts.logger.Debugf(\"Session:readLoop:<-s.readCh\", \"sid:%v tid:%v cannot unmarshal: %v\", s.id, s.targetID, err)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ts.emit(string(msg.Method), ev)\n\t\tcase <-s.done:\n\t\t\ts.logger.Debugf(\"Session:readLoop:<-s.done\", \"sid:%v tid:%v\", s.id, s.targetID)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Execute implements the cdp.Executor interface.\nfunc (s *Session) Execute(\n\tctx context.Context, method string, params, res any,\n) error {\n\ts.logger.Debugf(\"Session:Execute\", \"sid:%v tid:%v method:%q\", s.id, s.targetID, method)\n\tif s.crashed {\n\t\ts.logger.Debugf(\"Session:Execute:return\", \"sid:%v tid:%v method:%q crashed\", s.id, s.targetID, method)\n\t\treturn ErrTargetCrashed\n\t}\n\n\tid := s.msgIDGen.newID()\n\n\t// Setup event handler used to block for response to message being sent.\n\tch := make(chan *cdproto.Message, 1)\n\tevCancelCtx, evCancelFn := context.WithCancel(ctx)\n\tchEvHandler := make(chan Event)\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\ts.logger.Debugf(\"Session:Execute:<-evCancelCtx.Done():return\", \"sid:%v tid:%v method:%q\",\n\t\t\t\t\ts.id, s.targetID, method)\n\t\t\t\treturn\n\t\t\tcase ev := <-chEvHandler:\n\t\t\t\tif msg, ok := ev.data.(*cdproto.Message); ok && msg.ID == id {\n\t\t\t\t\tselect {\n\t\t\t\t\tcase <-evCancelCtx.Done():\n\t\t\t\t\t\ts.logger.Debugf(\"Session:Execute:<-evCancelCtx.Done():2:return\", \"sid:%v tid:%v method:%q\",\n\t\t\t\t\t\t\ts.id, s.targetID, method)\n\t\t\t\t\tcase ch <- msg:\n\t\t\t\t\t\t// We expect only one response with the matching message ID,\n\t\t\t\t\t\t// then remove event handler by cancelling context and stopping goroutine.\n\t\t\t\t\t\tevCancelFn()\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\ts.onAll(evCancelCtx, chEvHandler)\n\tdefer evCancelFn() // Remove event handler\n\n\ts.logger.Debugf(\"Session:Execute:s.conn.send\", \"sid:%v tid:%v method:%q\", s.id, s.targetID, method)\n\n\tvar buf []byte\n\tif params != nil {\n\t\tvar err error\n\t\tbuf, err = jsonv2.Marshal(params, defaultJSONV2Options)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tmsg := &cdproto.Message{\n\t\tID:        id,\n\t\tSessionID: s.id,\n\t\tMethod:    cdproto.MethodType(method),\n\t\tParams:    buf,\n\t}\n\treturn s.conn.send(contextWithDoneChan(evCancelCtx, s.done), msg, ch, res)\n}\n\nfunc (s *Session) ExecuteWithoutExpectationOnReply(\n\tctx context.Context, method string, params, res any,\n) error {\n\ts.logger.Debugf(\"Session:ExecuteWithoutExpectationOnReply\", \"sid:%v tid:%v method:%q\", s.id, s.targetID, method)\n\tif s.crashed {\n\t\ts.logger.Debugf(\"Session:ExecuteWithoutExpectationOnReply\", \"sid:%v tid:%v method:%q, ErrTargetCrashed\",\n\t\t\ts.id, s.targetID, method)\n\t\treturn ErrTargetCrashed\n\t}\n\n\ts.logger.Debugf(\"Session:Execute:s.conn.send\", \"sid:%v tid:%v method:%q\", s.id, s.targetID, method)\n\n\tvar buf []byte\n\tif params != nil {\n\t\tvar err error\n\t\tbuf, err = jsonv2.Marshal(params, defaultJSONV2Options)\n\t\tif err != nil {\n\t\t\ts.logger.Debugf(\"Session:ExecuteWithoutExpectationOnReply:Marshal\", \"sid:%v tid:%v method:%q err=%v\",\n\t\t\t\ts.id, s.targetID, method, err)\n\t\t\treturn err\n\t\t}\n\t}\n\tmsg := &cdproto.Message{\n\t\tID: s.msgIDGen.newID(),\n\t\t// We use different sessions to send messages to \"targets\"\n\t\t// (browser, page, frame etc.) in CDP.\n\t\t//\n\t\t// If we don't specify a session (a session ID in the JSON message),\n\t\t// it will be a message for the browser target.\n\t\t//\n\t\t// With a session specified (set using cdp.WithExecutor(ctx, session)),\n\t\t// it will properly route the CDP message to the correct target\n\t\t// (page, frame etc.).\n\t\t//\n\t\t// The difference between using Connection and Session to send\n\t\t// and receive CDP messages basically, they both implement\n\t\t// the cdp.Executor interface but one adds a sessionID to\n\t\t// the CPD messages:\n\t\tSessionID: s.id,\n\t\tMethod:    cdproto.MethodType(method),\n\t\tParams:    buf,\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\treturn s.conn.send(contextWithDoneChan(ctx, s.done), msg, nil, res)\n}\n\n// Done returns a channel that is closed when this session is closed.\nfunc (s *Session) Done() <-chan struct{} {\n\treturn s.done\n}\n\n// Closed returns true if this session is closed.\nfunc (s *Session) Closed() bool {\n\tselect {\n\tcase <-s.done:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/session_test.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/log\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/tests/ws\"\n\n\t\"github.com/chromedp/cdproto\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\tcdppage \"github.com/chromedp/cdproto/page\"\n\t\"github.com/chromedp/cdproto/target\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSessionCreateSession(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\tcdpTargetID         = \"target_id_0123456789\"\n\t\tcdpBrowserContextID = \"browser_context_id_0123456789\"\n\n\t\ttargetAttachedToTargetEvent = `\n\t\t{\n\t\t\t\"sessionId\": \"session_id_0123456789\",\n\t\t\t\"targetInfo\": {\n\t\t\t\t\"targetId\": \"target_id_0123456789\",\n\t\t\t\t\"type\": \"page\",\n\t\t\t\t\"title\": \"\",\n\t\t\t\t\"url\": \"about:blank\",\n\t\t\t\t\"attached\": true,\n\t\t\t\t\"browserContextId\": \"browser_context_id_0123456789\"\n\t\t\t},\n\t\t\t\"waitingForDebugger\": false\n\t\t}`\n\n\t\ttargetAttachedToTargetResult = `\n\t\t{\n\t\t\t\"sessionId\":\"session_id_0123456789\"\n\t\t}\n\t\t`\n\t)\n\n\tcmdsReceived := make([]cdproto.MethodType, 0)\n\thandler := func(conn *websocket.Conn, msg *cdproto.Message, writeCh chan cdproto.Message, done chan struct{}) {\n\t\tif msg.SessionID != \"\" && msg.Method != \"\" {\n\t\t\tif msg.Method == cdproto.MethodType(cdproto.CommandPageEnable) {\n\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\tID:        msg.ID,\n\t\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\t}\n\t\t\t\tclose(done) // We're done after receiving the Page.enable command\n\t\t\t}\n\t\t} else if msg.Method != \"\" {\n\t\t\tswitch msg.Method {\n\t\t\tcase cdproto.MethodType(cdproto.CommandTargetSetDiscoverTargets):\n\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\tID:        msg.ID,\n\t\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\t\tResult:    jsontext.Value([]byte(\"{}\")),\n\t\t\t\t}\n\t\t\tcase cdproto.MethodType(cdproto.CommandTargetAttachToTarget):\n\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\tMethod: cdproto.EventTargetAttachedToTarget,\n\t\t\t\t\tParams: jsontext.Value([]byte(targetAttachedToTargetEvent)),\n\t\t\t\t}\n\t\t\t\twriteCh <- cdproto.Message{\n\t\t\t\t\tID:        msg.ID,\n\t\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\t\tResult:    jsontext.Value([]byte(targetAttachedToTargetResult)),\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tserver := ws.NewServer(t, ws.WithCDPHandler(\"/cdp\", handler, &cmdsReceived))\n\n\tt.Run(\"send and recv session commands\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tctx := context.Background()\n\t\turl, _ := url.Parse(server.ServerHTTP.URL)\n\t\twsURL := fmt.Sprintf(\"ws://%s/cdp\", url.Host)\n\t\tconn, err := NewConnection(ctx, wsURL, log.NewNullLogger(), nil)\n\n\t\tif assert.NoError(t, err) {\n\t\t\tsession, err := conn.createSession(&target.Info{\n\t\t\t\tType:             \"page\",\n\t\t\t\tTargetID:         cdpTargetID,\n\t\t\t\tBrowserContextID: cdpBrowserContextID,\n\t\t\t})\n\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\taction := cdppage.Enable()\n\t\t\t\terr := action.Do(cdp.WithExecutor(ctx, session))\n\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, []cdproto.MethodType{\n\t\t\t\t\tcdproto.CommandTargetAttachToTarget,\n\t\t\t\t\tcdproto.CommandPageEnable,\n\t\t\t\t}, cmdsReceived)\n\t\t\t}\n\n\t\t\tconn.Close()\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/timeout.go",
    "content": "package common\n\nimport \"time\"\n\n// TimeoutSettings holds information on timeout settings.\ntype TimeoutSettings struct {\n\tparent                   *TimeoutSettings\n\tdefaultTimeout           *time.Duration\n\tdefaultNavigationTimeout *time.Duration\n}\n\n// NewTimeoutSettings creates a new timeout settings object.\nfunc NewTimeoutSettings(parent *TimeoutSettings) *TimeoutSettings {\n\tt := &TimeoutSettings{\n\t\tparent:                   parent,\n\t\tdefaultTimeout:           nil,\n\t\tdefaultNavigationTimeout: nil,\n\t}\n\treturn t\n}\n\nfunc (t *TimeoutSettings) setDefaultTimeout(timeout time.Duration) {\n\tt.defaultTimeout = &timeout\n}\n\nfunc (t *TimeoutSettings) setDefaultNavigationTimeout(timeout time.Duration) {\n\tt.defaultNavigationTimeout = &timeout\n}\n\nfunc (t *TimeoutSettings) navigationTimeout() time.Duration {\n\tif t.defaultNavigationTimeout != nil {\n\t\treturn *t.defaultNavigationTimeout\n\t}\n\tif t.defaultTimeout != nil {\n\t\treturn *t.defaultTimeout\n\t}\n\tif t.parent != nil {\n\t\treturn t.parent.navigationTimeout()\n\t}\n\treturn DefaultTimeout\n}\n\nfunc (t *TimeoutSettings) timeout() time.Duration {\n\tif t.defaultTimeout != nil {\n\t\treturn *t.defaultTimeout\n\t}\n\tif t.parent != nil {\n\t\treturn t.parent.timeout()\n\t}\n\treturn DefaultTimeout\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/timeout_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTimeoutSettings(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"TimeoutSettings.NewTimeoutSettings\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"should work\", testTimeoutSettingsNewTimeoutSettings)\n\t\tt.Run(\"should work with parent\", testTimeoutSettingsNewTimeoutSettingsWithParent)\n\t})\n\tt.Run(\"TimeoutSettings.setDefaultTimeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"should work\", testTimeoutSettingsSetDefaultTimeout)\n\t})\n\tt.Run(\"TimeoutSettings.setDefaultNavigationTimeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"should work\", testTimeoutSettingsSetDefaultNavigationTimeout)\n\t})\n\tt.Run(\"TimeoutSettings.navigationTimeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"should work\", testTimeoutSettingsNavigationTimeout)\n\t\tt.Run(\"should work with parent\", testTimeoutSettingsNavigationTimeoutWithParent)\n\t})\n\tt.Run(\"TimeoutSettings.timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"should work\", testTimeoutSettingsTimeout)\n\t\tt.Run(\"should work with parent\", testTimeoutSettingsTimeoutWithParent)\n\t})\n}\n\nfunc testTimeoutSettingsNewTimeoutSettings(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\tassert.Nil(t, ts.parent)\n\tassert.Nil(t, ts.defaultTimeout)\n\tassert.Nil(t, ts.defaultNavigationTimeout)\n}\n\nfunc testTimeoutSettingsNewTimeoutSettingsWithParent(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\ttsWithParent := NewTimeoutSettings(ts)\n\tassert.Equal(t, ts, tsWithParent.parent)\n\tassert.Nil(t, tsWithParent.defaultTimeout)\n\tassert.Nil(t, tsWithParent.defaultNavigationTimeout)\n}\n\nfunc testTimeoutSettingsSetDefaultTimeout(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\tts.setDefaultTimeout(time.Duration(100) * time.Millisecond)\n\tassert.Equal(t, int64(100), ts.defaultTimeout.Milliseconds())\n}\n\nfunc testTimeoutSettingsSetDefaultNavigationTimeout(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\tts.setDefaultNavigationTimeout(time.Duration(100) * time.Millisecond)\n\tassert.Equal(t, int64(100), ts.defaultNavigationTimeout.Milliseconds())\n}\n\nfunc testTimeoutSettingsNavigationTimeout(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\n\t// Assert default timeout value is used\n\tassert.Equal(t, DefaultTimeout, ts.navigationTimeout())\n\n\t// Assert custom default timeout is used\n\tts.setDefaultNavigationTimeout(time.Duration(100) * time.Millisecond)\n\tassert.Equal(t, int64(100), ts.navigationTimeout().Milliseconds())\n}\n\nfunc testTimeoutSettingsNavigationTimeoutWithParent(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\ttsWithParent := NewTimeoutSettings(ts)\n\n\t// Assert default timeout value is used\n\tassert.Equal(t, DefaultTimeout, tsWithParent.navigationTimeout())\n\n\t// Assert custom default timeout from parent is used\n\tts.setDefaultNavigationTimeout(time.Duration(1000) * time.Millisecond)\n\tassert.Equal(t, int64(1000), tsWithParent.navigationTimeout().Milliseconds())\n\n\t// Assert custom default timeout is used (over parent)\n\ttsWithParent.setDefaultNavigationTimeout(time.Duration(100) * time.Millisecond)\n\tassert.Equal(t, int64(100), tsWithParent.navigationTimeout().Milliseconds())\n}\n\nfunc testTimeoutSettingsTimeout(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\n\t// Assert default timeout value is used\n\tassert.Equal(t, DefaultTimeout, ts.timeout())\n\n\t// Assert custom default timeout is used\n\tts.setDefaultTimeout(time.Duration(100) * time.Millisecond)\n\tassert.Equal(t, int64(100), ts.timeout().Milliseconds())\n}\n\nfunc testTimeoutSettingsTimeoutWithParent(t *testing.T) {\n\tt.Parallel()\n\n\tts := NewTimeoutSettings(nil)\n\ttsWithParent := NewTimeoutSettings(ts)\n\n\t// Assert default timeout value is used\n\tassert.Equal(t, DefaultTimeout, tsWithParent.timeout())\n\n\t// Assert custom default timeout from parent is used\n\tts.setDefaultTimeout(time.Duration(1000) * time.Millisecond)\n\tassert.Equal(t, int64(1000), tsWithParent.timeout().Milliseconds())\n\n\t// Assert custom default timeout is used (over parent)\n\ttsWithParent.setDefaultTimeout(time.Duration(100) * time.Millisecond)\n\tassert.Equal(t, int64(100), tsWithParent.timeout().Milliseconds())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/touchscreen.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/input\"\n)\n\n// Touchscreen represents a touchscreen.\ntype Touchscreen struct {\n\tctx      context.Context\n\tsession  session\n\tkeyboard *Keyboard\n}\n\n// NewTouchscreen returns a new TouchScreen.\nfunc NewTouchscreen(ctx context.Context, s session, k *Keyboard) *Touchscreen {\n\treturn &Touchscreen{\n\t\tctx:      ctx,\n\t\tsession:  s,\n\t\tkeyboard: k,\n\t}\n}\n\n// Tap dispatches a tap start and tap end event.\nfunc (t *Touchscreen) Tap(x float64, y float64) error {\n\tif err := t.tap(x, y); err != nil {\n\t\treturn fmt.Errorf(\"tapping: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (t *Touchscreen) tap(x float64, y float64) error {\n\ttouchStart := input.DispatchTouchEvent(\n\t\tinput.TouchStart,\n\t\t[]*input.TouchPoint{{X: x, Y: y}},\n\t).WithModifiers(\n\t\tinput.Modifier(t.keyboard.modifiers),\n\t)\n\tif err := touchStart.Do(cdp.WithExecutor(t.ctx, t.session)); err != nil {\n\t\treturn fmt.Errorf(\"touch start: %w\", err)\n\t}\n\n\ttouchEnd := input.DispatchTouchEvent(\n\t\tinput.TouchEnd,\n\t\t[]*input.TouchPoint{},\n\t).WithModifiers(\n\t\tinput.Modifier(t.keyboard.modifiers),\n\t)\n\tif err := touchEnd.Do(cdp.WithExecutor(t.ctx, t.session)); err != nil {\n\t\treturn fmt.Errorf(\"touch end: %w\", err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/trace.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/trace\"\n\n\tbrowsertrace \"go.k6.io/k6/internal/js/modules/k6/browser/trace\"\n)\n\n// Tracer defines the interface with the tracing methods used in the common package.\ntype Tracer interface {\n\tTraceAPICall(\n\t\tctx context.Context, targetID string, spanName string, opts ...trace.SpanStartOption,\n\t) (context.Context, trace.Span)\n\tTraceNavigation(\n\t\tctx context.Context, targetID string, opts ...trace.SpanStartOption,\n\t) (context.Context, trace.Span)\n\tTraceEvent(\n\t\tctx context.Context, targetID string, eventName string, spanID string, opts ...trace.SpanStartOption,\n\t) (context.Context, trace.Span)\n}\n\n// TraceAPICall is a helper method that retrieves the Tracer from the given ctx and\n// calls its TraceAPICall implementation. If the Tracer is not present in the given\n// ctx, it returns a noopSpan and the given context.\nfunc TraceAPICall(\n\tctx context.Context, targetID string, spanName string, opts ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\tif tracer := GetTracer(ctx); tracer != nil {\n\t\treturn tracer.TraceAPICall(ctx, targetID, spanName, opts...)\n\t}\n\treturn ctx, browsertrace.NoopSpan{}\n}\n\n// TraceNavigation is a helper method that retrieves the Tracer from the given ctx and\n// calls its TraceNavigation implementation. If the Tracer is not present in the given\n// ctx, it returns a noopSpan and the given context.\nfunc TraceNavigation(\n\tctx context.Context, targetID string, opts ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\tif tracer := GetTracer(ctx); tracer != nil {\n\t\treturn tracer.TraceNavigation(ctx, targetID, opts...)\n\t}\n\treturn ctx, browsertrace.NoopSpan{}\n}\n\n// TraceEvent is a helper method that retrieves the Tracer from the given ctx and\n// calls its TraceEvent implementation. If the Tracer is not present in the given\n// ctx, it returns a noopSpan and the given context.\nfunc TraceEvent(\n\tctx context.Context, targetID string, eventName string, spanID string, options ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\tif tracer := GetTracer(ctx); tracer != nil {\n\t\treturn tracer.TraceEvent(ctx, targetID, eventName, spanID, options...)\n\t}\n\treturn ctx, browsertrace.NoopSpan{}\n}\n\n// spanRecordErrorf creates a formatted error, sets the status of the span\n// to the error and records the error on the span. It then returns the\n// created error for convenience to avoid boilerplate code.\nfunc spanRecordErrorf(span trace.Span, format string, a ...any) error {\n\treturn spanRecordError(span, fmt.Errorf(format, a...))\n}\n\n// spanRecordError is like [spanRecordErrorf] but takes an error\n// value directly instead of creating a new error value.\nfunc spanRecordError(span trace.Span, err error) error {\n\tspan.SetStatus(codes.Error, err.Error())\n\tspan.RecordError(err)\n\treturn err\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/common/worker.go",
    "content": "package common\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/log\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/chromedp/cdproto/target\"\n)\n\ntype Worker struct {\n\tctx     context.Context\n\tsession session\n\n\ttargetID target.ID\n\turl      string\n}\n\n// NewWorker creates a new page viewport.\nfunc NewWorker(ctx context.Context, s session, id target.ID, url string) (*Worker, error) {\n\tw := Worker{\n\t\tctx:      ctx,\n\t\tsession:  s,\n\t\ttargetID: id,\n\t\turl:      url,\n\t}\n\tif err := w.initEvents(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &w, nil\n}\n\nfunc (w *Worker) initEvents() error {\n\tactions := []Action{\n\t\tlog.Enable(),\n\t\tnetwork.Enable(),\n\t\truntime.RunIfWaitingForDebugger(),\n\t}\n\tfor _, action := range actions {\n\t\tif err := action.Do(cdp.WithExecutor(w.ctx, w.session)); err != nil {\n\t\t\treturn fmt.Errorf(\"protocol error while initializing worker %T: %w\", action, err)\n\t\t}\n\t}\n\treturn nil\n}\n\n// URL returns the URL of the web worker.\nfunc (w *Worker) URL() string {\n\treturn w.url\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/env/env.go",
    "content": "// Package env provides types to interact with environment setup.\npackage env\n\nimport (\n\t\"os\"\n\t\"strconv\"\n)\n\n// Execution specific.\nconst (\n\t// InstanceScenarios is an environment variable that can be used to\n\t// define the extra scenarios details to use when running remotely.\n\tInstanceScenarios = \"K6_INSTANCE_SCENARIOS\"\n\n\t// WebSocketURLs is an environment variable that can be used to\n\t// define the WS URLs to connect to when running remotely.\n\tWebSocketURLs = \"K6_BROWSER_WS_URL\"\n\n\t// BrowserArguments is an environment variable that can be used to\n\t// pass extra arguments to the browser process.\n\tBrowserArguments = \"K6_BROWSER_ARGS\"\n\n\t// BrowserExecutablePath is an environment variable that can be used\n\t// to define the path to the browser to execute.\n\tBrowserExecutablePath = \"K6_BROWSER_EXECUTABLE_PATH\"\n\n\t// BrowserEnableDebugging is an environment variable that can be used to\n\t// define if the browser should be launched with debugging enabled.\n\tBrowserEnableDebugging = \"K6_BROWSER_DEBUG\"\n\n\t// BrowserHeadless is an environment variable that can be used to\n\t// define if the browser should be launched in headless mode.\n\tBrowserHeadless = \"K6_BROWSER_HEADLESS\"\n\n\t// BrowserIgnoreDefaultArgs is an environment variable that can be\n\t// used to define if the browser should ignore default arguments.\n\tBrowserIgnoreDefaultArgs = \"K6_BROWSER_IGNORE_DEFAULT_ARGS\"\n\n\t// BrowserGlobalTimeout is an environment variable that can be used\n\t// to set the global timeout for the browser.\n\tBrowserGlobalTimeout = \"K6_BROWSER_TIMEOUT\"\n)\n\n// Logging and debugging.\nconst (\n\t// LogCaller is an environment variable that can be used to enable\n\t// the caller function information in the browser logs.\n\tLogCaller = \"K6_BROWSER_LOG_CALLER\"\n\n\t// LogLevel is an environment variable that can be used to set the\n\t// log level for the browser logs.\n\tLogLevel = \"K6_BROWSER_LOG\"\n\n\t// LogCategoryFilter is an environment variable that can be used to\n\t// filter the browser logs based on their category. It supports\n\t// regular expressions.\n\tLogCategoryFilter = \"K6_BROWSER_LOG_CATEGORY_FILTER\"\n)\n\n// Tracing.\nconst (\n\t// TracesMetadata is an environment variable that can be used to\n\t// set additional metadata to be included in the generated traces.\n\t// The format must comply with: key1=value1,key2=value2,...\n\tTracesMetadata = \"K6_BROWSER_TRACES_METADATA\"\n)\n\n// Screenshots.\nconst (\n\t// ScreenshotsOutput can be used to configure the browser module\n\t// to upload screenshots to a remote location instead of saving\n\t// to the local disk.\n\tScreenshotsOutput = \"K6_BROWSER_SCREENSHOTS_OUTPUT\"\n)\n\n// Infrastructural.\nconst (\n\t// K6TestRunID represents the test run id. Note: this was taken from\n\t// k6.\n\tK6TestRunID = \"K6_CLOUD_PUSH_REF_ID\"\n)\n\n// LookupFunc defines a function to look up a key from the environment.\ntype LookupFunc func(key string) (string, bool)\n\n// EmptyLookup is a LookupFunc that always returns \"\" and false.\nfunc EmptyLookup(_ string) (string, bool) { return \"\", false }\n\n// Lookup is a LookupFunc that uses os.LookupEnv.\nfunc Lookup(key string) (string, bool) { return os.LookupEnv(key) } //nolint:forbidigo\n\n// ConstLookup is a LookupFunc that always returns the given value and true\n// if the key matches the given key. Otherwise it returns EmptyLookup\n// behaviour. Useful for testing.\nfunc ConstLookup(k, v string) LookupFunc {\n\treturn func(key string) (string, bool) {\n\t\tif key == k {\n\t\t\treturn v, true\n\t\t}\n\t\treturn EmptyLookup(key)\n\t}\n}\n\n// LookupBool returns the result of Lookup as a bool.\n// If the key does not exist or the value is not a valid bool, it returns false.\n// Otherwise it returns the bool value and true.\nfunc LookupBool(key string) (value bool, ok bool) {\n\tv, ok := Lookup(key)\n\tif !ok {\n\t\treturn false, false\n\t}\n\tbv, err := strconv.ParseBool(v)\n\tif err != nil {\n\t\treturn false, true\n\t}\n\treturn bv, true\n}\n\n// IsBrowserHeadless returns true if the BrowserHeadless environment\n// variable is not set or set to true.\n// The default behaviour is to run the browser in headless mode.\nfunc IsBrowserHeadless() bool {\n\tv, ok := LookupBool(BrowserHeadless)\n\treturn !ok || v\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6error/internal.go",
    "content": "// Package k6error contains ErrFatal.\npackage k6error\n\nimport (\n\t\"errors\"\n)\n\n// ErrFatal should be wrapped into an error\n// to signal to the mapping layer that the error\n// is a fatal error and we should abort the whole\n// test run, not just the current iteration. It\n// should be used in cases where if the iteration\n// ran again then there's a 100% chance that it\n// will end up running into the same error.\nvar ErrFatal = errors.New(\"fatal error\")\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6ext/context.go",
    "content": "package k6ext\n\nimport (\n\t\"context\"\n\n\tk6modules \"go.k6.io/k6/js/modules\"\n\tk6lib \"go.k6.io/k6/lib\"\n\n\t\"github.com/grafana/sobek\"\n)\n\ntype ctxKey int\n\nconst (\n\tctxKeyVU ctxKey = iota\n\tctxKeyPid\n\tctxKeyCustomK6Metrics\n)\n\n// WithVU returns a new context based on ctx with the k6 VU instance attached.\nfunc WithVU(ctx context.Context, vu k6modules.VU) context.Context {\n\treturn context.WithValue(ctx, ctxKeyVU, vu)\n}\n\n// GetVU returns the attached k6 VU instance from ctx, which can be used to\n// retrieve the sobek runtime and other k6 objects relevant to the currently\n// executing VU.\n// See https://github.com/grafana/k6/blob/v0.37.0/js/initcontext.go#L168-L186\nfunc GetVU(ctx context.Context) k6modules.VU {\n\tv := ctx.Value(ctxKeyVU)\n\tif vu, ok := v.(k6modules.VU); ok {\n\t\treturn vu\n\t}\n\treturn nil\n}\n\n// WithCustomMetrics attaches the CustomK6Metrics object to the context.\nfunc WithCustomMetrics(ctx context.Context, k6m *CustomMetrics) context.Context {\n\treturn context.WithValue(ctx, ctxKeyCustomK6Metrics, k6m)\n}\n\n// GetCustomMetrics returns the CustomK6Metrics object attached to the context.\nfunc GetCustomMetrics(ctx context.Context) *CustomMetrics {\n\tv := ctx.Value(ctxKeyCustomK6Metrics)\n\tif k6m, ok := v.(*CustomMetrics); ok {\n\t\treturn k6m\n\t}\n\treturn nil\n}\n\n// Runtime is a convenience function for getting a k6 VU runtime.\nfunc Runtime(ctx context.Context) *sobek.Runtime {\n\treturn GetVU(ctx).Runtime()\n}\n\n// GetScenarioName returns the scenario name associated with the given context.\nfunc GetScenarioName(ctx context.Context) string {\n\tss := k6lib.GetScenarioState(ctx)\n\tif ss == nil {\n\t\treturn \"\"\n\t}\n\treturn ss.Name\n}\n\n// GetScenarioOpts returns the browser options and environment variables associated\n// with the given context.\nfunc GetScenarioOpts(ctx context.Context, vu k6modules.VU) map[string]any {\n\tscenario := GetScenarioName(ctx)\n\tif scenario == \"\" {\n\t\treturn nil\n\t}\n\tif so := vu.State().Options.Scenarios[scenario].GetScenarioOptions(); so != nil {\n\t\treturn so.Browser\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6ext/doc.go",
    "content": "// Package k6ext acts as an encapsulation layer between the k6 core and xk6-browser.\npackage k6ext\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6ext/k6test/doc.go",
    "content": "// Package k6test provides mock implementations of k6 elements for testing purposes.\npackage k6test\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6ext/k6test/executor.go",
    "content": "package k6test\n\nimport (\n\t\"github.com/sirupsen/logrus\"\n\n\tk6lib \"go.k6.io/k6/lib\"\n\tk6executor \"go.k6.io/k6/lib/executor\"\n)\n\n// TestExecutor is a k6lib.ExecutorConfig implementation\n// for testing purposes.\ntype TestExecutor struct {\n\tk6executor.BaseConfig\n}\n\n// GetDescription returns a mock Executor description.\nfunc (te *TestExecutor) GetDescription(*k6lib.ExecutionTuple) string {\n\treturn \"TestExecutor\"\n}\n\n// GetExecutionRequirements is a dummy implementation that just returns nil.\nfunc (te *TestExecutor) GetExecutionRequirements(*k6lib.ExecutionTuple) []k6lib.ExecutionStep {\n\treturn nil\n}\n\n// NewExecutor is a dummy implementation that just returns nil.\nfunc (te *TestExecutor) NewExecutor(*k6lib.ExecutionState, *logrus.Entry) (k6lib.Executor, error) {\n\treturn nil, nil //nolint:nilnil\n}\n\n// HasWork is a dummy implementation that returns true.\nfunc (te *TestExecutor) HasWork(*k6lib.ExecutionTuple) bool {\n\treturn true\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6ext/k6test/vu.go",
    "content": "package k6test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/js/eventloop\"\n\tk6testutils \"go.k6.io/k6/internal/lib/testutils\"\n\tk6trace \"go.k6.io/k6/internal/lib/trace\"\n\tk6common \"go.k6.io/k6/js/common\"\n\tk6modulestest \"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\tk6executor \"go.k6.io/k6/lib/executor\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n)\n\n// VU is a k6 VU instance.\n// TODO: Do we still need this VU wrapper?\n// ToSobekValue can be a helper function that takes a sobek.Runtime (although it's\n// not much of a helper from calling ToValue(i) directly...), and we can access\n// EventLoop from modulestest.Runtime.EventLoop.\ntype VU struct {\n\t*k6modulestest.VU\n\tLoop      *eventloop.EventLoop\n\ttoBeState *lib.State\n\tsamples   chan k6metrics.SampleContainer\n\tTestRT    *k6modulestest.Runtime\n}\n\n// ToSobekValue is a convenience method for converting any value to a sobek value.\nfunc (v *VU) ToSobekValue(i any) sobek.Value { return v.Runtime().ToValue(i) }\n\n// ActivateVU mimicks activation of the VU as in k6.\n// It transitions the VU from the init stage to the execution stage by\n// setting the VU's state to the state that was passed to NewVU.\nfunc (v *VU) ActivateVU() {\n\tv.StateField = v.toBeState\n\tv.InitEnvField = nil\n}\n\n// AssertSamples asserts each sample VU received since AssertSamples\n// is last called, then it returns the number of received samples.\nfunc (v *VU) AssertSamples(assertSample func(s k6metrics.Sample)) int {\n\tvar n int\n\tfor _, bs := range k6metrics.GetBufferedSamples(v.samples) {\n\t\tfor _, s := range bs.GetSamples() {\n\t\t\tassertSample(s)\n\t\t\tn++\n\t\t}\n\t}\n\treturn n\n}\n\n// WithScenarioName is used to set the scenario name in the IterData\n// for the 'IterStart' event.\ntype WithScenarioName = string\n\n// WithVUID is used to set the VU id in the IterData for the 'IterStart'\n// event.\ntype WithVUID = uint64\n\n// WithIteration is used to set the iteration in the IterData for the\n// 'IterStart' event.\ntype WithIteration = int64\n\n// StartIteration generates a new IterStart event through the VU event system.\n//\n// opts can be used to parameterize the iteration data such as:\n//   - WithScenarioName: sets the scenario name (default is 'default').\n//   - WithVUID: sets the VUID (default 1).\n//   - WithIteration: sets the iteration (default 0).\nfunc (v *VU) StartIteration(tb testing.TB, opts ...any) {\n\ttb.Helper()\n\ttb.Cleanup(func() { v.EndIteration(tb) }) // this prevents leaks. there are no sideeffects if this is done before.\n\tv.iterEvent(tb, event.IterStart, \"IterStart\", opts...)\n}\n\n// EndIteration generates a new IterEnd event through the VU event system.\n//\n// opts can be used to parameterize the iteration data such as:\n//   - WithScenarioName: sets the scenario name (default is 'default').\n//   - WithVUID: sets the VUID (default 1).\n//   - WithIteration: sets the iteration (default 0).\nfunc (v *VU) EndIteration(tb testing.TB, opts ...any) {\n\ttb.Helper()\n\tv.iterEvent(tb, event.IterEnd, \"IterEnd\", opts...)\n}\n\n// iterEvent generates an iteration event for the VU.\nfunc (v *VU) iterEvent(tb testing.TB, eventType event.Type, eventName string, opts ...any) {\n\ttb.Helper()\n\n\tdata := event.IterData{\n\t\tIteration:    0,\n\t\tVUID:         1,\n\t\tScenarioName: \"default\",\n\t}\n\n\tfor _, opt := range opts {\n\t\tswitch opt := opt.(type) {\n\t\tcase WithScenarioName:\n\t\t\tdata.ScenarioName = opt\n\t\tcase WithVUID:\n\t\t\tdata.VUID = opt\n\t\tcase WithIteration:\n\t\t\tdata.Iteration = opt\n\t\t}\n\t}\n\n\tevents, ok := v.EventsField.Local.(*event.System)\n\trequire.True(tb, ok, \"want *event.System; got %T\", events)\n\twaitDone := events.Emit(&event.Event{\n\t\tType: eventType,\n\t\tData: data,\n\t})\n\trequire.NoError(tb, waitDone(context.Background()), \"error waiting on %s done\", eventName)\n}\n\n// RunOnEventLoop runs the given JavaScript code on the VU's event loop and\n// returns the result as a sobek.Value.\nfunc (v *VU) RunOnEventLoop(tb testing.TB, js string, args ...any) (sobek.Value, error) {\n\ttb.Helper()\n\n\treturn v.TestRT.RunOnEventLoop(fmt.Sprintf(js, args...))\n}\n\n// RunAsync runs the given JavaScript code on the VU's event loop and returns\n// the result as a sobek.Value.\nfunc (v *VU) RunAsync(tb testing.TB, js string, args ...any) (sobek.Value, error) {\n\ttb.Helper()\n\n\tjsWithArgs := fmt.Sprintf(js, args...)\n\n\treturn v.RunOnEventLoop(tb, \"(async function() { %s })();\", jsWithArgs)\n}\n\n// RunPromise runs the given JavaScript code on the VU's event loop and returns\n// the result as a *sobek.Promise.\nfunc (v *VU) RunPromise(tb testing.TB, js string, args ...any) *sobek.Promise {\n\ttb.Helper()\n\n\tgv, err := v.RunAsync(tb, js, args...)\n\trequire.NoError(tb, err, \"running promise on event loop\")\n\treturn ToPromise(tb, gv)\n}\n\n// SetVar sets a variable in the VU's sobek runtime's global scope.\nfunc (v *VU) SetVar(tb testing.TB, name string, value any) {\n\ttb.Helper()\n\n\terr := v.TestRT.VU.Runtime().GlobalObject().Set(name, value)\n\trequire.NoError(tb, err, \"setting variable %q to %v\", name, value)\n}\n\n// ToPromise asserts and returns a sobek.Value as a *sobek.Promise.\nfunc ToPromise(tb testing.TB, gv sobek.Value) *sobek.Promise {\n\ttb.Helper()\n\n\tp, ok := gv.Export().(*sobek.Promise)\n\trequire.True(tb, ok, \"got: %T, want *sobek.Promise\", gv.Export())\n\treturn p\n}\n\n// WithSamples is used to indicate we want to use a bidirectional channel\n// so that the test can read the metrics being emitted to the channel.\ntype WithSamples chan k6metrics.SampleContainer\n\n// WithTracerProvider allows to set the VU TracerProvider.\ntype WithTracerProvider lib.TracerProvider\n\n// NewVU returns a mock k6 VU.\n//\n// opts can be one of the following:\n//   - WithSamples: a bidirectional channel that will be used to emit metrics.\n//   - env.LookupFunc: a lookup function that will be used to lookup environment variables.\n//   - WithTracerProvider: a TracerProvider that will be set as the VU TracerProvider.\nfunc NewVU(tb testing.TB, opts ...any) *VU {\n\ttb.Helper()\n\n\tvar (\n\t\tsamples                           = make(chan k6metrics.SampleContainer, 1000)\n\t\tlookupFunc                        = env.EmptyLookup\n\t\ttracerProvider lib.TracerProvider = k6trace.NewNoopTracerProvider()\n\t)\n\tfor _, opt := range opts {\n\t\tswitch opt := opt.(type) {\n\t\tcase WithSamples:\n\t\t\tsamples = opt\n\t\tcase env.LookupFunc:\n\t\t\tlookupFunc = opt\n\t\tcase WithTracerProvider:\n\t\t\ttracerProvider = opt\n\t\t}\n\t}\n\n\tlogger := k6testutils.NewLogger(tb)\n\n\ttestRT := k6modulestest.NewRuntime(tb)\n\ttestRT.VU.InitEnvField.LookupEnv = lookupFunc\n\tglobalEvents := event.NewEventSystem(100, logger)\n\ttestRT.VU.EventsField = k6common.Events{\n\t\tGlobal: globalEvents,\n\t\tLocal:  event.NewEventSystem(100, logger),\n\t}\n\t// Emit an Exit event on cleanup to ensure browser registry goroutines\n\t// (handleIterEvents and handleExitEvent) are properly terminated.\n\t// Without this, those goroutines block on channel receives forever,\n\t// leaking across tests and eventually causing the test suite to hang.\n\ttb.Cleanup(func() {\n\t\twaitDone := globalEvents.Emit(&event.Event{\n\t\t\tType: event.Exit,\n\t\t})\n\t\t_ = waitDone(context.Background())\n\t})\n\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tMaxRedirects: null.IntFrom(10),\n\t\t\tUserAgent:    null.StringFrom(\"TestUserAgent\"),\n\t\t\tThrow:        null.BoolFrom(true),\n\t\t\tSystemTags:   &k6metrics.DefaultSystemTagSet,\n\t\t\tBatch:        null.IntFrom(20),\n\t\t\tBatchPerHost: null.IntFrom(20),\n\t\t\t// HTTPDebug:    null.StringFrom(\"full\"),\n\t\t\tScenarios: lib.ScenarioConfigs{\n\t\t\t\t\"default\": &TestExecutor{\n\t\t\t\t\tBaseConfig: k6executor.BaseConfig{\n\t\t\t\t\t\tOptions: &lib.ScenarioOptions{\n\t\t\t\t\t\t\tBrowser: map[string]any{\n\t\t\t\t\t\t\t\t\"type\": \"chromium\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tLogger:     logger,\n\t\tBufferPool: lib.NewBufferPool(),\n\t\tSamples:    samples,\n\t\tTags: lib.NewVUStateTags(\n\t\t\ttestRT.VU.InitEnvField.Registry.RootTagSet().With(\"group\", lib.RootGroupPath),\n\t\t),\n\t\tBuiltinMetrics: k6metrics.RegisterBuiltinMetrics(k6metrics.NewRegistry()),\n\t\tTracerProvider: tracerProvider,\n\t}\n\n\tctx := k6ext.WithVU(testRT.VU.CtxField, testRT.VU)\n\tctx = lib.WithScenarioState(ctx, &lib.ScenarioState{Name: \"default\"})\n\ttestRT.VU.CtxField = ctx\n\n\treturn &VU{VU: testRT.VU, Loop: testRT.EventLoop, toBeState: state, samples: samples, TestRT: testRT}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6ext/metrics.go",
    "content": "package k6ext\n\nimport (\n\tk6metrics \"go.k6.io/k6/metrics\"\n)\n\nconst (\n\twebVitalFID  = \"FID\"\n\twebVitalTTFB = \"TTFB\"\n\twebVitalLCP  = \"LCP\"\n\twebVitalCLS  = \"CLS\"\n\twebVitalINP  = \"INP\"\n\twebVitalFCP  = \"FCP\"\n\n\tfidName  = \"browser_web_vital_fid\"\n\tttfbName = \"browser_web_vital_ttfb\"\n\tlcpName  = \"browser_web_vital_lcp\"\n\tclsName  = \"browser_web_vital_cls\"\n\tinpName  = \"browser_web_vital_inp\"\n\tfcpName  = \"browser_web_vital_fcp\"\n\n\tbrowserDataSentName        = \"browser_data_sent\"\n\tbrowserDataReceivedName    = \"browser_data_received\"\n\tbrowserHTTPReqDurationName = \"browser_http_req_duration\"\n\tbrowserHTTPReqFailedName   = \"browser_http_req_failed\"\n)\n\n// CustomMetrics are the custom k6 metrics used by xk6-browser.\ntype CustomMetrics struct {\n\tWebVitals map[string]*k6metrics.Metric\n\n\tBrowserDataSent        *k6metrics.Metric\n\tBrowserDataReceived    *k6metrics.Metric\n\tBrowserHTTPReqDuration *k6metrics.Metric\n\tBrowserHTTPReqFailed   *k6metrics.Metric\n}\n\n// RegisterCustomMetrics creates and registers our custom metrics with the k6\n// VU Registry and returns our internal struct pointer.\nfunc RegisterCustomMetrics(registry *k6metrics.Registry) *CustomMetrics {\n\twvs := map[string]string{\n\t\twebVitalFID:  fidName,  // first input delay\n\t\twebVitalTTFB: ttfbName, // time to first byte\n\t\twebVitalLCP:  lcpName,  // largest content paint\n\t\twebVitalCLS:  clsName,  // cumulative layout shift\n\t\twebVitalINP:  inpName,  // interaction to next paint\n\t\twebVitalFCP:  fcpName,  // first contentful paint\n\t}\n\twebVitals := make(map[string]*k6metrics.Metric)\n\n\tfor k, v := range wvs {\n\t\tt := k6metrics.Time\n\t\t// CLS is not a time based measurement, it is a score,\n\t\t// so use the default metric type for CLS.\n\t\tif k == webVitalCLS {\n\t\t\tt = k6metrics.Default\n\t\t}\n\n\t\twebVitals[k] = registry.MustNewMetric(v, k6metrics.Trend, t)\n\t}\n\n\treturn &CustomMetrics{\n\t\tWebVitals:              webVitals,\n\t\tBrowserDataSent:        registry.MustNewMetric(browserDataSentName, k6metrics.Counter, k6metrics.Data),\n\t\tBrowserDataReceived:    registry.MustNewMetric(browserDataReceivedName, k6metrics.Counter, k6metrics.Data),\n\t\tBrowserHTTPReqDuration: registry.MustNewMetric(browserHTTPReqDurationName, k6metrics.Trend, k6metrics.Time),\n\t\tBrowserHTTPReqFailed:   registry.MustNewMetric(browserHTTPReqFailedName, k6metrics.Rate),\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/k6ext/panic.go",
    "content": "package k6ext\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/errext\"\n\tk6common \"go.k6.io/k6/js/common\"\n)\n\n// Abortf will shutdown the whole test run. This should\n// only be used from the sobek mapping layer. It is only\n// to be used when an error will occur in all iterations,\n// so it's permanent.\nfunc Abortf(ctx context.Context, format string, a ...any) {\n\tfailFunc := func(rt *sobek.Runtime, a ...any) {\n\t\treason := fmt.Errorf(format, a...).Error()\n\t\trt.Interrupt(&errext.InterruptError{Reason: reason})\n\t}\n\tsharedPanic(ctx, failFunc, a...)\n}\n\n// Panicf will cause a panic with the given error which will stop\n// the current iteration. Before panicking, it will find the\n// browser process from the context and kill it if it still exists.\n// TODO: test.\nfunc Panicf(ctx context.Context, format string, a ...any) {\n\tfailFunc := func(rt *sobek.Runtime, a ...any) {\n\t\tk6common.Throw(rt, fmt.Errorf(format, a...))\n\t}\n\tsharedPanic(ctx, failFunc, a...)\n}\n\nfunc sharedPanic(ctx context.Context, failFunc func(rt *sobek.Runtime, a ...any), a ...any) {\n\trt := Runtime(ctx)\n\tif rt == nil {\n\t\t// this should never happen unless a programmer error\n\t\tpanic(\"no k6 JS runtime in context\")\n\t}\n\t// get a user-friendly error if the err is not already so.\n\tif len(a) > 0 {\n\t\tvar (\n\t\t\tuerr    *UserFriendlyError\n\t\t\terr, ok = a[len(a)-1].(error)\n\t\t)\n\t\tif ok && !errors.As(err, &uerr) {\n\t\t\ta[len(a)-1] = &UserFriendlyError{Err: err}\n\t\t}\n\t}\n\tdefer failFunc(rt, a...)\n\n\t// TODO: Remove this after moving k6ext.Panic into the mapping layer.\n\tpidder, ok := GetVU(ctx).(interface {\n\t\tPids() []int\n\t})\n\tif !ok {\n\t\t// we're running in a test, let's skip killing the process.\n\t\treturn\n\t}\n\tfor _, pid := range pidder.Pids() {\n\t\tp, err := os.FindProcess(pid) //nolint:forbidigo\n\t\tif err != nil {\n\t\t\t// optimistically skip and don't kill the process\n\t\t\tcontinue\n\t\t}\n\t\t// no need to check the error for whether we could kill it as\n\t\t// we're already dying.\n\t\t_ = p.Kill()\n\t}\n}\n\n// UserFriendlyError maps an internal error to an error that users\n// can easily understand.\ntype UserFriendlyError struct {\n\tErr     error\n\tTimeout time.Duration // prints \"timed out after Ns\" error\n}\n\nfunc (e *UserFriendlyError) Unwrap() error { return e.Err }\n\nfunc (e *UserFriendlyError) Error() string {\n\tswitch {\n\tdefault:\n\t\treturn e.Err.Error()\n\tcase e.Err == nil:\n\t\treturn \"\"\n\tcase errors.Is(e.Err, context.DeadlineExceeded):\n\t\ts := \"timed out\"\n\t\tif t := e.Timeout; t != 0 {\n\t\t\ts += fmt.Sprintf(\" after %s\", t)\n\t\t}\n\t\treturn strings.ReplaceAll(e.Err.Error(), context.DeadlineExceeded.Error(), s)\n\tcase errors.Is(e.Err, context.Canceled):\n\t\treturn \"canceled\"\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/keyboardlayout/layout.go",
    "content": "// Package keyboardlayout provides keyboard key interpretation and layout validation.\npackage keyboardlayout\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n)\n\ntype KeyInput string\n\ntype KeyDefinition struct {\n\tCode                   string\n\tKey                    string\n\tKeyCode                int64\n\tKeyCodeWithoutLocation int64\n\tShiftKey               string\n\tShiftKeyCode           int64\n\tText                   string\n\tLocation               int64\n}\n\ntype KeyboardLayout struct {\n\tValidKeys map[KeyInput]bool\n\tKeys      map[KeyInput]KeyDefinition\n}\n\n// KeyDefinition returns true with the key definition of a given key input.\n// It returns false and an empty key definition if it cannot find the key.\nfunc (kl KeyboardLayout) KeyDefinition(key KeyInput) (KeyDefinition, bool) {\n\tfor _, d := range kl.Keys {\n\t\tif d.Key == string(key) {\n\t\t\treturn d, true\n\t\t}\n\t}\n\treturn KeyDefinition{}, false\n}\n\n// ShiftKeyDefinition returns shift key definition of a given key input.\n// It returns an empty key definition if it cannot find the key.\nfunc (kl KeyboardLayout) ShiftKeyDefinition(key KeyInput) KeyDefinition {\n\tfor _, d := range kl.Keys {\n\t\tif d.ShiftKey == string(key) {\n\t\t\treturn d\n\t\t}\n\t}\n\treturn KeyDefinition{}\n}\n\n//nolint:gochecknoglobals\nvar (\n\tkbdLayouts = make(map[string]KeyboardLayout)\n\tmx         sync.RWMutex\n)\n\n// GetKeyboardLayout returns the keyboard layout registered with name.\nfunc GetKeyboardLayout(name string) KeyboardLayout {\n\tmx.RLock()\n\tdefer mx.RUnlock()\n\treturn kbdLayouts[name]\n}\n\nfunc init() {\n\tinitUS()\n}\n\n// Register the given keyboard layout.\n// This function panics if a keyboard layout with the same name is already registered.\nfunc register(lang string, validKeys map[KeyInput]bool, keys map[KeyInput]KeyDefinition) {\n\tmx.Lock()\n\tdefer mx.Unlock()\n\n\tif _, ok := kbdLayouts[lang]; ok {\n\t\tpanic(fmt.Sprintf(\"keyboard layout already registered: %s\", lang))\n\t}\n\tkbdLayouts[lang] = KeyboardLayout{ValidKeys: validKeys, Keys: keys}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/keyboardlayout/us.go",
    "content": "package keyboardlayout\n\n//nolint:funlen\nfunc initUS() {\n\tvalidKeys := map[KeyInput]bool{\n\t\t\"0\":                  true,\n\t\t\"1\":                  true,\n\t\t\"2\":                  true,\n\t\t\"3\":                  true,\n\t\t\"4\":                  true,\n\t\t\"5\":                  true,\n\t\t\"6\":                  true,\n\t\t\"7\":                  true,\n\t\t\"8\":                  true,\n\t\t\"9\":                  true,\n\t\t\"Power\":              true,\n\t\t\"Eject\":              true,\n\t\t\"Abort\":              true,\n\t\t\"Help\":               true,\n\t\t\"Backspace\":          true,\n\t\t\"Tab\":                true,\n\t\t\"Numpad5\":            true,\n\t\t\"NumpadEnter\":        true,\n\t\t\"Enter\":              true,\n\t\t\"\\r\":                 true,\n\t\t\"\\n\":                 true,\n\t\t\"ShiftLeft\":          true,\n\t\t\"ShiftRight\":         true,\n\t\t\"ControlLeft\":        true,\n\t\t\"ControlRight\":       true,\n\t\t\"AltLeft\":            true,\n\t\t\"AltRight\":           true,\n\t\t\"Pause\":              true,\n\t\t\"CapsLock\":           true,\n\t\t\"Escape\":             true,\n\t\t\"Convert\":            true,\n\t\t\"NonConvert\":         true,\n\t\t\"Space\":              true,\n\t\t\"Numpad9\":            true,\n\t\t\"PageUp\":             true,\n\t\t\"Numpad3\":            true,\n\t\t\"PageDown\":           true,\n\t\t\"End\":                true,\n\t\t\"Numpad1\":            true,\n\t\t\"Home\":               true,\n\t\t\"Numpad7\":            true,\n\t\t\"ArrowLeft\":          true,\n\t\t\"Numpad4\":            true,\n\t\t\"Numpad8\":            true,\n\t\t\"ArrowUp\":            true,\n\t\t\"ArrowRight\":         true,\n\t\t\"Numpad6\":            true,\n\t\t\"Numpad2\":            true,\n\t\t\"ArrowDown\":          true,\n\t\t\"Select\":             true,\n\t\t\"Open\":               true,\n\t\t\"PrintScreen\":        true,\n\t\t\"Insert\":             true,\n\t\t\"Numpad0\":            true,\n\t\t\"Delete\":             true,\n\t\t\"NumpadDecimal\":      true,\n\t\t\"Digit0\":             true,\n\t\t\"Digit1\":             true,\n\t\t\"Digit2\":             true,\n\t\t\"Digit3\":             true,\n\t\t\"Digit4\":             true,\n\t\t\"Digit5\":             true,\n\t\t\"Digit6\":             true,\n\t\t\"Digit7\":             true,\n\t\t\"Digit8\":             true,\n\t\t\"Digit9\":             true,\n\t\t\"KeyA\":               true,\n\t\t\"KeyB\":               true,\n\t\t\"KeyC\":               true,\n\t\t\"KeyD\":               true,\n\t\t\"KeyE\":               true,\n\t\t\"KeyF\":               true,\n\t\t\"KeyG\":               true,\n\t\t\"KeyH\":               true,\n\t\t\"KeyI\":               true,\n\t\t\"KeyJ\":               true,\n\t\t\"KeyK\":               true,\n\t\t\"KeyL\":               true,\n\t\t\"KeyM\":               true,\n\t\t\"KeyN\":               true,\n\t\t\"KeyO\":               true,\n\t\t\"KeyP\":               true,\n\t\t\"KeyQ\":               true,\n\t\t\"KeyR\":               true,\n\t\t\"KeyS\":               true,\n\t\t\"KeyT\":               true,\n\t\t\"KeyU\":               true,\n\t\t\"KeyV\":               true,\n\t\t\"KeyW\":               true,\n\t\t\"KeyX\":               true,\n\t\t\"KeyY\":               true,\n\t\t\"KeyZ\":               true,\n\t\t\"MetaLeft\":           true,\n\t\t\"MetaRight\":          true,\n\t\t\"ConTextMenu\":        true,\n\t\t\"NumpadMultiply\":     true,\n\t\t\"NumpadAdd\":          true,\n\t\t\"NumpadSubtract\":     true,\n\t\t\"NumpadDivide\":       true,\n\t\t\"F1\":                 true,\n\t\t\"F2\":                 true,\n\t\t\"F3\":                 true,\n\t\t\"F4\":                 true,\n\t\t\"F5\":                 true,\n\t\t\"F6\":                 true,\n\t\t\"F7\":                 true,\n\t\t\"F8\":                 true,\n\t\t\"F9\":                 true,\n\t\t\"F10\":                true,\n\t\t\"F11\":                true,\n\t\t\"F12\":                true,\n\t\t\"F13\":                true,\n\t\t\"F14\":                true,\n\t\t\"F15\":                true,\n\t\t\"F16\":                true,\n\t\t\"F17\":                true,\n\t\t\"F18\":                true,\n\t\t\"F19\":                true,\n\t\t\"F20\":                true,\n\t\t\"F21\":                true,\n\t\t\"F22\":                true,\n\t\t\"F23\":                true,\n\t\t\"F24\":                true,\n\t\t\"NumLock\":            true,\n\t\t\"ScrollLock\":         true,\n\t\t\"AudioVolumeMute\":    true,\n\t\t\"AudioVolumeDown\":    true,\n\t\t\"AudioVolumeUp\":      true,\n\t\t\"MediaTrackNext\":     true,\n\t\t\"MediaTrackPrevious\": true,\n\t\t\"MediaStop\":          true,\n\t\t\"MediaPlayPause\":     true,\n\t\t\"Semicolon\":          true,\n\t\t\"Equal\":              true,\n\t\t\"NumpadEqual\":        true,\n\t\t\"Comma\":              true,\n\t\t\"Minus\":              true,\n\t\t\"Period\":             true,\n\t\t\"Slash\":              true,\n\t\t\"Backquote\":          true,\n\t\t\"BracketLeft\":        true,\n\t\t\"Backslash\":          true,\n\t\t\"BracketRight\":       true,\n\t\t\"Quote\":              true,\n\t\t\"AltGraph\":           true,\n\t\t\"Props\":              true,\n\t\t\"Cancel\":             true,\n\t\t\"Clear\":              true,\n\t\t\"Shift\":              true,\n\t\t\"Control\":            true,\n\t\t\"ControlOrMeta\":      true,\n\t\t\"Alt\":                true,\n\t\t\"Accept\":             true,\n\t\t\"ModeChange\":         true,\n\t\t\" \":                  true,\n\t\t\"Print\":              true,\n\t\t\"Execute\":            true,\n\t\t\"\\u0000\":             true,\n\t\t\"a\":                  true,\n\t\t\"b\":                  true,\n\t\t\"c\":                  true,\n\t\t\"d\":                  true,\n\t\t\"e\":                  true,\n\t\t\"f\":                  true,\n\t\t\"g\":                  true,\n\t\t\"h\":                  true,\n\t\t\"i\":                  true,\n\t\t\"j\":                  true,\n\t\t\"k\":                  true,\n\t\t\"l\":                  true,\n\t\t\"m\":                  true,\n\t\t\"n\":                  true,\n\t\t\"o\":                  true,\n\t\t\"p\":                  true,\n\t\t\"q\":                  true,\n\t\t\"r\":                  true,\n\t\t\"s\":                  true,\n\t\t\"t\":                  true,\n\t\t\"u\":                  true,\n\t\t\"v\":                  true,\n\t\t\"w\":                  true,\n\t\t\"x\":                  true,\n\t\t\"y\":                  true,\n\t\t\"z\":                  true,\n\t\t\"Meta\":               true,\n\t\t\"*\":                  true,\n\t\t\"+\":                  true,\n\t\t\"-\":                  true,\n\t\t\"/\":                  true,\n\t\t\";\":                  true,\n\t\t\"=\":                  true,\n\t\t\",\":                  true,\n\t\t\".\":                  true,\n\t\t\"`\":                  true,\n\t\t\"[\":                  true,\n\t\t\"\\\\\":                 true,\n\t\t\"]\":                  true,\n\t\t\"'\":                  true,\n\t\t\"Attn\":               true,\n\t\t\"CrSel\":              true,\n\t\t\"ExSel\":              true,\n\t\t\"EraseEof\":           true,\n\t\t\"Play\":               true,\n\t\t\"ZoomOut\":            true,\n\t\t\")\":                  true,\n\t\t\"!\":                  true,\n\t\t\"@\":                  true,\n\t\t\"#\":                  true,\n\t\t\"$\":                  true,\n\t\t\"%\":                  true,\n\t\t\"^\":                  true,\n\t\t\"&\":                  true,\n\t\t\"(\":                  true,\n\t\t\"A\":                  true,\n\t\t\"B\":                  true,\n\t\t\"C\":                  true,\n\t\t\"D\":                  true,\n\t\t\"E\":                  true,\n\t\t\"F\":                  true,\n\t\t\"G\":                  true,\n\t\t\"H\":                  true,\n\t\t\"I\":                  true,\n\t\t\"J\":                  true,\n\t\t\"K\":                  true,\n\t\t\"L\":                  true,\n\t\t\"M\":                  true,\n\t\t\"N\":                  true,\n\t\t\"O\":                  true,\n\t\t\"P\":                  true,\n\t\t\"Q\":                  true,\n\t\t\"R\":                  true,\n\t\t\"S\":                  true,\n\t\t\"T\":                  true,\n\t\t\"U\":                  true,\n\t\t\"V\":                  true,\n\t\t\"W\":                  true,\n\t\t\"X\":                  true,\n\t\t\"Y\":                  true,\n\t\t\"Z\":                  true,\n\t\t\":\":                  true,\n\t\t\"<\":                  true,\n\t\t\"_\":                  true,\n\t\t\">\":                  true,\n\t\t\"?\":                  true,\n\t\t\"~\":                  true,\n\t\t\"{\":                  true,\n\t\t\"|\":                  true,\n\t\t\"}\":                  true,\n\t\t\"\\\"\":                 true,\n\t\t\"SoftLeft\":           true,\n\t\t\"SoftRight\":          true,\n\t\t\"Camera\":             true,\n\t\t\"Call\":               true,\n\t\t\"EndCall\":            true,\n\t\t\"VolumeDown\":         true,\n\t\t\"VolumeUp\":           true,\n\t}\n\tKeys := map[KeyInput]KeyDefinition{\n\t\t// Functions row\n\t\t\"Escape\": {Code: \"Escape\", KeyCode: 27, Key: \"Escape\"},\n\t\t\"F1\":     {Code: \"F1\", KeyCode: 112, Key: \"F1\"},\n\t\t\"F2\":     {Code: \"F2\", KeyCode: 113, Key: \"F2\"},\n\t\t\"F3\":     {Code: \"F3\", KeyCode: 114, Key: \"F3\"},\n\t\t\"F4\":     {Code: \"F4\", KeyCode: 115, Key: \"F4\"},\n\t\t\"F5\":     {Code: \"F5\", KeyCode: 116, Key: \"F5\"},\n\t\t\"F6\":     {Code: \"F6\", KeyCode: 117, Key: \"F6\"},\n\t\t\"F7\":     {Code: \"F7\", KeyCode: 118, Key: \"F7\"},\n\t\t\"F8\":     {Code: \"F8\", KeyCode: 119, Key: \"F8\"},\n\t\t\"F9\":     {Code: \"F9\", KeyCode: 120, Key: \"F9\"},\n\t\t\"F10\":    {Code: \"F10\", KeyCode: 121, Key: \"F10\"},\n\t\t\"F11\":    {Code: \"F11\", KeyCode: 122, Key: \"F11\"},\n\t\t\"F12\":    {Code: \"F12\", KeyCode: 123, Key: \"F12\"},\n\n\t\t// Numbers row\n\t\t\"Backquote\": {Code: \"Backquote\", KeyCode: 192, ShiftKey: \"~\", Key: \"`\"},\n\t\t\"Digit1\":    {Code: \"Digit1\", KeyCode: 49, ShiftKey: \"!\", Key: \"1\"},\n\t\t\"Digit2\":    {Code: \"Digit2\", KeyCode: 50, ShiftKey: \"@\", Key: \"2\"},\n\t\t\"Digit3\":    {Code: \"Digit3\", KeyCode: 51, ShiftKey: \"#\", Key: \"3\"},\n\t\t\"Digit4\":    {Code: \"Digit4\", KeyCode: 52, ShiftKey: \"$\", Key: \"4\"},\n\t\t\"Digit5\":    {Code: \"Digit5\", KeyCode: 53, ShiftKey: \"%\", Key: \"5\"},\n\t\t\"Digit6\":    {Code: \"Digit6\", KeyCode: 54, ShiftKey: \"^\", Key: \"6\"},\n\t\t\"Digit7\":    {Code: \"Digit7\", KeyCode: 55, ShiftKey: \"&\", Key: \"7\"},\n\t\t\"Digit8\":    {Code: \"Digit8\", KeyCode: 56, ShiftKey: \"*\", Key: \"8\"},\n\t\t\"Digit9\":    {Code: \"Digit9\", KeyCode: 57, ShiftKey: \"(\", Key: \"9\"},\n\t\t\"Digit0\":    {Code: \"Digit0\", KeyCode: 48, ShiftKey: \")\", Key: \"0\"},\n\t\t\"Minus\":     {Code: \"Minus\", KeyCode: 189, ShiftKey: \"_\", Key: \"-\"},\n\t\t\"Equal\":     {Code: \"Equal\", KeyCode: 187, ShiftKey: \"+\", Key: \"=\"},\n\t\t\"Backslash\": {Code: \"Backslash\", KeyCode: 220, ShiftKey: \"|\", Key: \"\\\\\"},\n\t\t\"Backspace\": {Code: \"Backspace\", KeyCode: 8, Key: \"Backspace\"},\n\n\t\t// First row\n\t\t\"Tab\":          {Code: \"Tab\", KeyCode: 9, Key: \"Tab\"},\n\t\t\"KeyQ\":         {Code: \"KeyQ\", KeyCode: 81, ShiftKey: \"Q\", Key: \"q\"},\n\t\t\"KeyW\":         {Code: \"KeyW\", KeyCode: 87, ShiftKey: \"W\", Key: \"w\"},\n\t\t\"KeyE\":         {Code: \"KeyE\", KeyCode: 69, ShiftKey: \"E\", Key: \"e\"},\n\t\t\"KeyR\":         {Code: \"KeyR\", KeyCode: 82, ShiftKey: \"R\", Key: \"r\"},\n\t\t\"KeyT\":         {Code: \"KeyT\", KeyCode: 84, ShiftKey: \"T\", Key: \"t\"},\n\t\t\"KeyY\":         {Code: \"KeyY\", KeyCode: 89, ShiftKey: \"Y\", Key: \"y\"},\n\t\t\"KeyU\":         {Code: \"KeyU\", KeyCode: 85, ShiftKey: \"U\", Key: \"u\"},\n\t\t\"KeyI\":         {Code: \"KeyI\", KeyCode: 73, ShiftKey: \"I\", Key: \"i\"},\n\t\t\"KeyO\":         {Code: \"KeyO\", KeyCode: 79, ShiftKey: \"O\", Key: \"o\"},\n\t\t\"KeyP\":         {Code: \"KeyP\", KeyCode: 80, ShiftKey: \"P\", Key: \"p\"},\n\t\t\"BracketLeft\":  {Code: \"BracketLeft\", KeyCode: 219, ShiftKey: \"{\", Key: \"[\"},\n\t\t\"BracketRight\": {Code: \"BracketRight\", KeyCode: 221, ShiftKey: \"}\", Key: \"]\"},\n\n\t\t// Second row\n\t\t\"CapsLock\":  {Code: \"CapsLock\", KeyCode: 20, Key: \"CapsLock\"},\n\t\t\"KeyA\":      {Code: \"KeyA\", KeyCode: 65, ShiftKey: \"A\", Key: \"a\"},\n\t\t\"KeyS\":      {Code: \"KeyS\", KeyCode: 83, ShiftKey: \"S\", Key: \"s\"},\n\t\t\"KeyD\":      {Code: \"KeyD\", KeyCode: 68, ShiftKey: \"D\", Key: \"d\"},\n\t\t\"KeyF\":      {Code: \"KeyF\", KeyCode: 70, ShiftKey: \"F\", Key: \"f\"},\n\t\t\"KeyG\":      {Code: \"KeyG\", KeyCode: 71, ShiftKey: \"G\", Key: \"g\"},\n\t\t\"KeyH\":      {Code: \"KeyH\", KeyCode: 72, ShiftKey: \"H\", Key: \"h\"},\n\t\t\"KeyJ\":      {Code: \"KeyJ\", KeyCode: 74, ShiftKey: \"J\", Key: \"j\"},\n\t\t\"KeyK\":      {Code: \"KeyK\", KeyCode: 75, ShiftKey: \"K\", Key: \"k\"},\n\t\t\"KeyL\":      {Code: \"KeyL\", KeyCode: 76, ShiftKey: \"L\", Key: \"l\"},\n\t\t\"Semicolon\": {Code: \"Semicolon\", KeyCode: 186, ShiftKey: \":\", Key: \";\"},\n\t\t\"Quote\":     {Code: \"Quote\", KeyCode: 222, ShiftKey: \"\\\"\", Key: \"'\"},\n\t\t\"Enter\":     {Code: \"Enter\", KeyCode: 13, Key: \"Enter\", Text: \"\\r\"},\n\n\t\t// Third row\n\t\t\"ShiftLeft\":  {Code: \"ShiftLeft\", KeyCode: 160, KeyCodeWithoutLocation: 16, Key: \"Shift\", Location: 1},\n\t\t\"KeyZ\":       {Code: \"KeyZ\", KeyCode: 90, ShiftKey: \"Z\", Key: \"z\"},\n\t\t\"KeyX\":       {Code: \"KeyX\", KeyCode: 88, ShiftKey: \"X\", Key: \"x\"},\n\t\t\"KeyC\":       {Code: \"KeyC\", KeyCode: 67, ShiftKey: \"C\", Key: \"c\"},\n\t\t\"KeyV\":       {Code: \"KeyV\", KeyCode: 86, ShiftKey: \"V\", Key: \"v\"},\n\t\t\"KeyB\":       {Code: \"KeyB\", KeyCode: 66, ShiftKey: \"B\", Key: \"b\"},\n\t\t\"KeyN\":       {Code: \"KeyN\", KeyCode: 78, ShiftKey: \"N\", Key: \"n\"},\n\t\t\"KeyM\":       {Code: \"KeyM\", KeyCode: 77, ShiftKey: \"M\", Key: \"m\"},\n\t\t\"Comma\":      {Code: \"Comma\", KeyCode: 188, ShiftKey: \"<\", Key: \",\"},\n\t\t\"Period\":     {Code: \"Period\", KeyCode: 190, ShiftKey: \">\", Key: \".\"},\n\t\t\"Slash\":      {Code: \"Slash\", KeyCode: 191, ShiftKey: \"?\", Key: \"/\"},\n\t\t\"ShiftRight\": {Code: \"ShiftRight\", KeyCode: 161, KeyCodeWithoutLocation: 16, Key: \"Shift\", Location: 2},\n\n\t\t// Last row\n\t\t\"ControlLeft\":  {Code: \"ControlLeft\", KeyCode: 162, KeyCodeWithoutLocation: 17, Key: \"Control\", Location: 1},\n\t\t\"MetaLeft\":     {Code: \"MetaLeft\", KeyCode: 91, Key: \"Meta\", Location: 1},\n\t\t\"AltLeft\":      {Code: \"AltLeft\", KeyCode: 164, KeyCodeWithoutLocation: 18, Key: \"Alt\", Location: 1},\n\t\t\"Space\":        {Code: \"Space\", KeyCode: 32, Key: \" \"},\n\t\t\"AltRight\":     {Code: \"AltRight\", KeyCode: 165, KeyCodeWithoutLocation: 18, Key: \"Alt\", Location: 2},\n\t\t\"AltGraph\":     {Code: \"AltGraph\", KeyCode: 225, Key: \"AltGraph\"},\n\t\t\"MetaRight\":    {Code: \"MetaRight\", KeyCode: 92, Key: \"Meta\", Location: 2},\n\t\t\"ConTextMenu\":  {Code: \"ConTextMenu\", KeyCode: 93, Key: \"ConTextMenu\"},\n\t\t\"ControlRight\": {Code: \"ControlRight\", KeyCode: 163, KeyCodeWithoutLocation: 17, Key: \"Control\", Location: 2},\n\n\t\t// Center block\n\t\t\"PrintScreen\": {Code: \"PrintScreen\", KeyCode: 44, Key: \"PrintScreen\"},\n\t\t\"ScrollLock\":  {Code: \"ScrollLock\", KeyCode: 145, Key: \"ScrollLock\"},\n\t\t\"Pause\":       {Code: \"Pause\", KeyCode: 19, Key: \"Pause\"},\n\n\t\t\"PageUp\":   {Code: \"PageUp\", KeyCode: 33, Key: \"PageUp\"},\n\t\t\"PageDown\": {Code: \"PageDown\", KeyCode: 34, Key: \"PageDown\"},\n\t\t\"Insert\":   {Code: \"Insert\", KeyCode: 45, Key: \"Insert\"},\n\t\t\"Delete\":   {Code: \"Delete\", KeyCode: 46, Key: \"Delete\"},\n\t\t\"Home\":     {Code: \"Home\", KeyCode: 36, Key: \"Home\"},\n\t\t\"End\":      {Code: \"End\", KeyCode: 35, Key: \"End\"},\n\n\t\t\"ArrowLeft\":  {Code: \"ArrowLeft\", KeyCode: 37, Key: \"ArrowLeft\"},\n\t\t\"ArrowUp\":    {Code: \"ArrowUp\", KeyCode: 38, Key: \"ArrowUp\"},\n\t\t\"ArrowRight\": {Code: \"ArrowRight\", KeyCode: 39, Key: \"ArrowRight\"},\n\t\t\"ArrowDown\":  {Code: \"ArrowDown\", KeyCode: 40, Key: \"ArrowDown\"},\n\n\t\t// Numpad\n\t\t\"NumLock\":        {Code: \"NumLock\", KeyCode: 144, Key: \"NumLock\"},\n\t\t\"NumpadDivide\":   {Code: \"NumpadDivide\", KeyCode: 111, Key: \"/\", Location: 3},\n\t\t\"NumpadMultiply\": {Code: \"NumpadMultiply\", KeyCode: 106, Key: \"*\", Location: 3},\n\t\t\"NumpadSubtract\": {Code: \"NumpadSubtract\", KeyCode: 109, Key: \"-\", Location: 3},\n\t\t\"Numpad7\":        {Code: \"Numpad7\", KeyCode: 36, ShiftKeyCode: 103, Key: \"Home\", ShiftKey: \"7\", Location: 3},\n\t\t\"Numpad8\":        {Code: \"Numpad8\", KeyCode: 38, ShiftKeyCode: 104, Key: \"ArrowUp\", ShiftKey: \"8\", Location: 3},\n\t\t\"Numpad9\":        {Code: \"Numpad9\", KeyCode: 33, ShiftKeyCode: 105, Key: \"PageUp\", ShiftKey: \"9\", Location: 3},\n\t\t\"Numpad4\":        {Code: \"Numpad4\", KeyCode: 37, ShiftKeyCode: 100, Key: \"ArrowLeft\", ShiftKey: \"4\", Location: 3},\n\t\t\"Numpad5\":        {Code: \"Numpad5\", KeyCode: 12, ShiftKeyCode: 101, Key: \"Clear\", ShiftKey: \"5\", Location: 3},\n\t\t\"Numpad6\":        {Code: \"Numpad6\", KeyCode: 39, ShiftKeyCode: 102, Key: \"ArrowRight\", ShiftKey: \"6\", Location: 3},\n\t\t\"NumpadAdd\":      {Code: \"NumpadAdd\", KeyCode: 107, Key: \"+\", Location: 3},\n\t\t\"Numpad1\":        {Code: \"Numpad1\", KeyCode: 35, ShiftKeyCode: 97, Key: \"End\", ShiftKey: \"1\", Location: 3},\n\t\t\"Numpad2\":        {Code: \"Numpad2\", KeyCode: 40, ShiftKeyCode: 98, Key: \"ArrowDown\", ShiftKey: \"2\", Location: 3},\n\t\t\"Numpad3\":        {Code: \"Numpad3\", KeyCode: 34, ShiftKeyCode: 99, Key: \"PageDown\", ShiftKey: \"3\", Location: 3},\n\t\t\"Numpad0\":        {Code: \"Numpad0\", KeyCode: 45, ShiftKeyCode: 96, Key: \"Insert\", ShiftKey: \"0\", Location: 3},\n\t\t\"NumpadDecimal\":  {Code: \"NumpadDecimal\", KeyCode: 46, ShiftKeyCode: 110, Key: \"\\u0000\", ShiftKey: \".\", Location: 3},\n\t\t\"NumpadEnter\":    {Code: \"NumpadEnter\", KeyCode: 13, Key: \"Enter\", Text: \"\\r\", Location: 3},\n\t}\n\n\tregister(\"us\", validKeys, Keys)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/log/logger.go",
    "content": "// Package log provides logging for the browser module.\npackage log\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\ntype Logger struct {\n\t*logrus.Logger //nolint:forbidigo\n\tmu             sync.Mutex\n\tlastLogCall    int64\n\titerID         string\n\tcategoryFilter *regexp.Regexp\n}\n\n// NewNullLogger will create a logger where log lines will\n// be discarded and not logged anywhere.\nfunc NewNullLogger() *Logger {\n\tlog := logrus.New()\n\tlog.SetOutput(io.Discard)\n\treturn New(log, \"\")\n}\n\n// New creates a new logger.\nfunc New(logger logrus.FieldLogger, iterID string) *Logger {\n\tll := &Logger{\n\t\tLogger: logrus.New(),\n\t\titerID: iterID,\n\t}\n\n\tif logger == nil {\n\t\tll.Warnf(\"Logger\", \"no logger supplied, using default\")\n\t} else if l, ok := logger.(*logrus.Logger); !ok { //nolint:forbidigo\n\t\tll.Warnf(\"Logger\", \"invalid logger type %T, using default\", logger)\n\t} else {\n\t\tll.Logger = l\n\t}\n\n\treturn ll\n}\n\n// Tracef logs a trace message.\nfunc (l *Logger) Tracef(category string, msg string, args ...any) {\n\tl.Logf(logrus.TraceLevel, category, msg, args...)\n}\n\n// Debugf logs a debug message.\nfunc (l *Logger) Debugf(category string, msg string, args ...any) {\n\tl.Logf(logrus.DebugLevel, category, msg, args...)\n}\n\n// Errorf logs an error message.\nfunc (l *Logger) Errorf(category string, msg string, args ...any) {\n\tl.Logf(logrus.ErrorLevel, category, msg, args...)\n}\n\n// Infof logs an info message.\nfunc (l *Logger) Infof(category string, msg string, args ...any) {\n\tl.Logf(logrus.InfoLevel, category, msg, args...)\n}\n\n// Warnf logs an warning message.\nfunc (l *Logger) Warnf(category string, msg string, args ...any) {\n\tl.Logf(logrus.WarnLevel, category, msg, args...)\n}\n\n// Logf logs a message.\nfunc (l *Logger) Logf(level logrus.Level, category string, msg string, args ...any) {\n\tif l == nil {\n\t\treturn\n\t}\n\t// don't log if the current log level isn't in the required level.\n\tif l.GetLevel() < level {\n\t\treturn\n\t}\n\tl.mu.Lock()\n\tdefer l.mu.Unlock()\n\n\tnow := time.Now().UnixNano() / 1000000\n\telapsed := now - l.lastLogCall\n\tif now == elapsed {\n\t\telapsed = 0\n\t}\n\tdefer func() {\n\t\tl.lastLogCall = now\n\t}()\n\n\tif l.categoryFilter != nil && !l.categoryFilter.MatchString(category) {\n\t\treturn\n\t}\n\tfields := logrus.Fields{\n\t\t\"source\":   \"browser\",\n\t\t\"category\": category,\n\t\t\"elapsed\":  fmt.Sprintf(\"%d ms\", elapsed),\n\t}\n\tif l.iterID != \"\" && l.GetLevel() > logrus.InfoLevel {\n\t\tfields[\"iteration_id\"] = l.iterID\n\t}\n\tentry := l.WithFields(fields)\n\tif l.GetLevel() < level {\n\t\tentry.Printf(msg, args...)\n\t\treturn\n\t}\n\tentry.Logf(level, msg, args...)\n}\n\n// SetLevel sets the logger level from a level string.\n// Accepted values:\n//   - \"panic\"\n//   - \"fatal\"\n//   - \"error\"\n//   - \"warn\"\n//   - \"warning\"\n//   - \"info\"\n//   - \"debug\"\n//   - \"trace\"\nfunc (l *Logger) SetLevel(level string) error {\n\tpl, err := logrus.ParseLevel(level)\n\tif err != nil {\n\t\treturn err\n\t}\n\tl.Logger.SetLevel(pl)\n\treturn nil\n}\n\n// DebugMode returns true if the logger level is set to Debug or higher.\nfunc (l *Logger) DebugMode() bool {\n\treturn l.GetLevel() >= logrus.DebugLevel\n}\n\n// ReportCaller adds source file and function names to the log entries.\nfunc (l *Logger) ReportCaller() {\n\tcaller := func() func(*runtime.Frame) (string, string) {\n\t\treturn func(f *runtime.Frame) (function string, file string) {\n\t\t\treturn f.Func.Name(), fmt.Sprintf(\"%s:%d\", f.File, f.Line)\n\t\t}\n\t}\n\tl.SetFormatter(&logrus.TextFormatter{\n\t\tCallerPrettyfier: caller(),\n\t\tFieldMap: logrus.FieldMap{\n\t\t\tlogrus.FieldKeyFile: \"caller\",\n\t\t},\n\t})\n\tl.SetReportCaller(true)\n}\n\n// SetCategoryFilter enables filtering logs by the filter regex.\nfunc (l *Logger) SetCategoryFilter(filter string) (err error) {\n\tif filter == \"\" {\n\t\treturn nil\n\t}\n\tif l.categoryFilter, err = regexp.Compile(filter); err != nil {\n\t\treturn fmt.Errorf(\"invalid category filter %q: %w\", filter, err)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/storage/file_persister.go",
    "content": "package storage\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n)\n\n// LocalFilePersister will persist files to the local disk.\ntype LocalFilePersister struct{}\n\n// Persist will write the contents of data to the local disk on the specified path.\n// TODO: we should not write to disk here but put it on some queue for async disk writes.\nfunc (l *LocalFilePersister) Persist(_ context.Context, path string, data io.Reader) (err error) {\n\tcp := filepath.Clean(path)\n\n\tdir := filepath.Dir(cp)\n\tif err = os.MkdirAll(dir, 0o755); err != nil { //nolint:forbidigo,gosec\n\t\treturn fmt.Errorf(\"creating a local directory %q: %w\", dir, err)\n\t}\n\n\tf, err := os.OpenFile(cp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600) //nolint:forbidigo\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating a local file %q: %w\", cp, err)\n\t}\n\tdefer func() {\n\t\tif cerr := f.Close(); cerr != nil && err == nil {\n\t\t\terr = fmt.Errorf(\"closing the local file %q: %w\", cp, cerr)\n\t\t}\n\t}()\n\n\tbf := bufio.NewWriter(f)\n\n\tif _, err := io.Copy(bf, data); err != nil {\n\t\treturn fmt.Errorf(\"copying data to file: %w\", err)\n\t}\n\n\tif err := bf.Flush(); err != nil {\n\t\treturn fmt.Errorf(\"flushing data to disk: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// RemoteFilePersister is to be used when files created by the browser module need\n// to be uploaded to a remote location. This uses a presignedURLRequestURL to\n// retrieve one presigned URL. The presigned url is used to upload the file\n// to the remote location.\ntype RemoteFilePersister struct {\n\tpresignedURLRequestURL string\n\theaders                map[string]string\n\tbasePath               string\n\n\thttpClient *http.Client\n}\n\n// PresignedURLResponse holds the response from a presigned generation request.\ntype PresignedURLResponse struct {\n\tService string `json:\"service\"`\n\tURLs    []struct {\n\t\tName         string            `json:\"name\"`\n\t\tPresignedURL string            `json:\"pre_signed_url\"` //nolint:tagliatelle\n\t\tMethod       string            `json:\"method\"`\n\t\tFormFields   map[string]string `json:\"form_fields\"` //nolint:tagliatelle\n\t} `json:\"urls\"`\n}\n\n// NewRemoteFilePersister creates a new instance of RemoteFilePersister.\nfunc NewRemoteFilePersister(\n\tpresignedURLRequestURL string,\n\theaders map[string]string,\n\tbasePath string,\n) *RemoteFilePersister {\n\treturn &RemoteFilePersister{\n\t\tpresignedURLRequestURL: presignedURLRequestURL,\n\t\theaders:                headers,\n\t\tbasePath:               basePath,\n\t\thttpClient: &http.Client{\n\t\t\tTimeout: time.Second * 10,\n\t\t},\n\t}\n}\n\n// Persist will upload the contents of data to a remote location.\nfunc (r *RemoteFilePersister) Persist(ctx context.Context, path string, data io.Reader) (err error) {\n\tpsResp, err := r.requestPresignedURL(ctx, path)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"requesting presigned url: %w\", err)\n\t}\n\n\treq, err := newFileUploadRequest(ctx, psResp, data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"creating upload request: %w\", err)\n\t}\n\n\tresp, err := r.httpClient.Do(req) //nolint:gosec\n\tif err != nil {\n\t\treturn fmt.Errorf(\"performing upload request: %w\", err)\n\t}\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\tif _, err := io.Copy(io.Discard, resp.Body); err != nil {\n\t\treturn fmt.Errorf(\"draining upload response body: %w\", err)\n\t}\n\n\tif err := checkStatusCode(resp); err != nil {\n\t\treturn fmt.Errorf(\"uploading: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// requestPresignedURL will request a new presigned URL from the remote server\n// and returns a [PresignedURLResponse] that contains the presigned URL details.\nfunc (r *RemoteFilePersister) requestPresignedURL(ctx context.Context, path string) (PresignedURLResponse, error) {\n\tb, err := buildPresignedRequestBody(r.basePath, path)\n\tif err != nil {\n\t\treturn PresignedURLResponse{}, fmt.Errorf(\"building request body: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(\n\t\tctx,\n\t\thttp.MethodPost,\n\t\tr.presignedURLRequestURL,\n\t\tbytes.NewReader(b),\n\t)\n\tif err != nil {\n\t\treturn PresignedURLResponse{}, fmt.Errorf(\"creating request: %w\", err)\n\t}\n\n\tfor k, v := range r.headers {\n\t\treq.Header.Add(k, v)\n\t}\n\n\tresp, err := r.httpClient.Do(req) //nolint:gosec\n\tif err != nil {\n\t\treturn PresignedURLResponse{}, fmt.Errorf(\"performing request: %w\", err)\n\t}\n\tdefer resp.Body.Close() //nolint:errcheck\n\n\tif err := checkStatusCode(resp); err != nil {\n\t\treturn PresignedURLResponse{}, err\n\t}\n\n\treturn readPresignedURLResponse(resp)\n}\n\nfunc buildPresignedRequestBody(basePath, path string) ([]byte, error) {\n\tb := struct {\n\t\tService   string `json:\"service\"`\n\t\tOperation string `json:\"operation\"`\n\t\tFiles     []struct {\n\t\t\tName string `json:\"name\"`\n\t\t} `json:\"files\"`\n\t}{\n\t\tService:   \"aws_s3\",\n\t\tOperation: \"upload_post\",\n\t\tFiles: []struct {\n\t\t\tName string `json:\"name\"`\n\t\t}{\n\t\t\t{\n\t\t\t\tName: filepath.Join(basePath, path),\n\t\t\t},\n\t\t},\n\t}\n\n\tbb, err := json.Marshal(b)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"marshaling request body: %w\", err)\n\t}\n\n\treturn bb, nil\n}\n\nfunc readPresignedURLResponse(resp *http.Response) (PresignedURLResponse, error) {\n\tvar rb PresignedURLResponse\n\n\tdecoder := json.NewDecoder(resp.Body)\n\terr := decoder.Decode(&rb)\n\tif err != nil {\n\t\treturn PresignedURLResponse{}, fmt.Errorf(\"decoding response body: %w\", err)\n\t}\n\n\tif len(rb.URLs) == 0 {\n\t\treturn PresignedURLResponse{}, errors.New(\"missing presigned url in response body\")\n\t}\n\n\treturn rb, nil\n}\n\n// newFileUploadRequest creates a new HTTP request to upload a file as a multipart\n// form to the presigned URL received from the server.\nfunc newFileUploadRequest(\n\tctx context.Context,\n\tresp PresignedURLResponse,\n\tdata io.Reader,\n) (*http.Request, error) {\n\t// we don't support multiple presigned URLs at the moment.\n\tpsu := resp.URLs[0]\n\n\t// copy all form fields received from a presigned URL\n\t// response to the multipart form fields.\n\tvar form bytes.Buffer\n\tfw := multipart.NewWriter(&form)\n\tfor k, v := range psu.FormFields {\n\t\tif err := fw.WriteField(k, v); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"writing form field key %q and value %q: %w\", k, v, err)\n\t\t}\n\t}\n\t// attach the file data to the form.\n\tff, err := fw.CreateFormFile(\"file\", psu.Name)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating multipart form file: %w\", err)\n\t}\n\tif _, err := io.Copy(ff, data); err != nil {\n\t\treturn nil, fmt.Errorf(\"copying file data to multipart form: %w\", err)\n\t}\n\tif err := fw.Close(); err != nil {\n\t\treturn nil, fmt.Errorf(\"closing multipart form writer: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(\n\t\tctx,\n\t\tpsu.Method,\n\t\tpsu.PresignedURL,\n\t\t&form,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating new request: %w\", err)\n\t}\n\treq.Header.Set(\"Content-Type\", fw.FormDataContentType())\n\n\treturn req, nil\n}\n\nfunc checkStatusCode(resp *http.Response) error {\n\tif resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {\n\t\treturn fmt.Errorf(\"server returned %d (%s)\", resp.StatusCode, strings.ToLower(http.StatusText(resp.StatusCode)))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/storage/file_persister_test.go",
    "content": "package storage\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestLocalFilePersister(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname         string\n\t\tpath         string\n\t\texistingData string\n\t\tdata         string\n\t\ttruncates    bool\n\t}{\n\t\t{\n\t\t\tname: \"just_file\",\n\t\t\tpath: \"test.txt\",\n\t\t\tdata: \"some data\",\n\t\t},\n\t\t{\n\t\t\tname: \"with_dir\",\n\t\t\tpath: \"path/test.txt\",\n\t\t\tdata: \"some data\",\n\t\t},\n\t\t{\n\t\t\tname:         \"truncates\",\n\t\t\tpath:         \"test.txt\",\n\t\t\tdata:         \"some data\",\n\t\t\ttruncates:    true,\n\t\t\texistingData: \"existing data\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tdir := t.TempDir()\n\t\t\tp := filepath.Join(dir, tt.path)\n\n\t\t\t// We want to make sure that the persister truncates the existing\n\t\t\t// data and therefore overwrites existing data. This sets up a file\n\t\t\t// with some existing data that should be overwritten.\n\t\t\tif tt.truncates {\n\t\t\t\terr := os.WriteFile(p, []byte(tt.existingData), 0o600) //nolint:forbidigo\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\tvar l LocalFilePersister\n\t\t\terr := l.Persist(context.Background(), p, strings.NewReader(tt.data))\n\t\t\tassert.NoError(t, err)\n\n\t\t\ti, err := os.Stat(p) //nolint:forbidigo\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.False(t, i.IsDir())\n\n\t\t\tbb, err := os.ReadFile(filepath.Clean(p)) //nolint:forbidigo\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif tt.truncates {\n\t\t\t\tassert.NotEqual(t, tt.existingData, string(bb))\n\t\t\t}\n\n\t\t\tassert.Equal(t, tt.data, string(bb))\n\t\t})\n\t}\n}\n\nfunc TestRemoteFilePersister(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"not supported on windows for now\")\n\t\t// actual problem is that the paths used are with reverse slash even when they get to be inside JSON\n\t\t// which leads to them being parsed as escepe codes when they shouldn't\n\t}\n\n\tconst (\n\t\tbasePath          = \"screenshots\"\n\t\tpresignedEndpoint = \"/presigned\"\n\t\tuploadEndpoint    = \"/upload\"\n\t)\n\n\ttests := []struct {\n\t\tname                    string\n\t\tpath                    string\n\t\tdataToUpload            string\n\t\tmultipartFormFields     map[string]string\n\t\twantPresignedURLBody    string\n\t\twantPresignedHeaders    map[string]string\n\t\twantPresignedURLMethod  string\n\t\tuploadResponse          int\n\t\tgetPresignedURLResponse int\n\t\twantError               string\n\t}{\n\t\t{\n\t\t\tname:         \"upload_file\",\n\t\t\tpath:         \"some/path/file.png\",\n\t\t\tdataToUpload: \"here's some data\",\n\t\t\tmultipartFormFields: map[string]string{\n\t\t\t\t\"fooKey\": \"foo\",\n\t\t\t\t\"barKey\": \"bar\",\n\t\t\t},\n\t\t\twantPresignedURLBody: `{\n\t\t\t\t\t\"service\":\"aws_s3\",\n\t\t\t\t\t\"operation\": \"upload_post\",\n\t\t\t\t\t\"files\":[{\"name\":\"%s\"}]\n\t\t\t\t}`,\n\t\t\twantPresignedHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"token asd123\",\n\t\t\t\t\"Run_id\":        \"123456\",\n\t\t\t},\n\t\t\twantPresignedURLMethod:  http.MethodPost,\n\t\t\tuploadResponse:          http.StatusOK,\n\t\t\tgetPresignedURLResponse: http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname:         \"upload_file\",\n\t\t\tpath:         \"some/path/file.png\",\n\t\t\tdataToUpload: \"here's some data\",\n\t\t\tmultipartFormFields: map[string]string{ // provide different form fields then the previous test\n\t\t\t\t\"bazKey\": \"baz\",\n\t\t\t\t\"quxKey\": \"qux\",\n\t\t\t},\n\t\t\twantPresignedURLBody: `{\n\t\t\t\t\t\"service\":\"aws_s3\",\n\t\t\t\t\t\"operation\": \"upload_post\",\n\t\t\t\t\t\"files\":[{\"name\":\"%s\"}]\n\t\t\t\t}`,\n\t\t\twantPresignedHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"token asd123\",\n\t\t\t\t\"Run_id\":        \"123456\",\n\t\t\t},\n\t\t\twantPresignedURLMethod:  http.MethodPut, // accepts dynamic methods\n\t\t\tuploadResponse:          http.StatusOK,\n\t\t\tgetPresignedURLResponse: http.StatusOK,\n\t\t},\n\t\t{\n\t\t\tname:         \"get_presigned_rate_limited\",\n\t\t\tpath:         \"some/path/file.png\",\n\t\t\tdataToUpload: \"here's some data\",\n\t\t\twantPresignedURLBody: `{\n\t\t\t\t\t\"service\":\"aws_s3\",\n\t\t\t\t\t\"operation\": \"upload_post\",\n\t\t\t\t\t\"files\":[{\"name\":\"%s\"}]\n\t\t\t\t}`,\n\t\t\twantPresignedHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"token asd123\",\n\t\t\t\t\"Run_id\":        \"123456\",\n\t\t\t},\n\t\t\twantPresignedURLMethod:  http.MethodPost,\n\t\t\tgetPresignedURLResponse: http.StatusTooManyRequests,\n\t\t\twantError:               \"requesting presigned url: server returned 429 (too many requests)\",\n\t\t},\n\t\t{\n\t\t\tname:         \"get_presigned_fails\",\n\t\t\tpath:         \"some/path/file.png\",\n\t\t\tdataToUpload: \"here's some data\",\n\t\t\twantPresignedURLBody: `{\n\t\t\t\t\t\"service\":\"aws_s3\",\n\t\t\t\t\t\"operation\": \"upload_post\",\n\t\t\t\t\t\"files\":[{\"name\":\"%s\"}]\n\t\t\t\t}`,\n\t\t\twantPresignedHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"token asd123\",\n\t\t\t\t\"Run_id\":        \"123456\",\n\t\t\t},\n\t\t\twantPresignedURLMethod:  http.MethodPost,\n\t\t\tgetPresignedURLResponse: http.StatusInternalServerError,\n\t\t\twantError:               \"requesting presigned url: server returned 500 (internal server error)\",\n\t\t},\n\t\t{\n\t\t\tname:         \"upload_rate_limited\",\n\t\t\tpath:         \"some/path/file.png\",\n\t\t\tdataToUpload: \"here's some data\",\n\t\t\twantPresignedURLBody: `{\n\t\t\t\t\t\"service\":\"aws_s3\",\n\t\t\t\t\t\"operation\": \"upload_post\",\n\t\t\t\t\t\"files\":[{\"name\":\"%s\"}]\n\t\t\t\t}`,\n\t\t\twantPresignedHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"token asd123\",\n\t\t\t\t\"Run_id\":        \"123456\",\n\t\t\t},\n\t\t\twantPresignedURLMethod:  http.MethodPost,\n\t\t\tuploadResponse:          http.StatusTooManyRequests,\n\t\t\tgetPresignedURLResponse: http.StatusOK,\n\t\t\twantError:               \"uploading: server returned 429 (too many requests)\",\n\t\t},\n\t\t{\n\t\t\tname:         \"upload_fails\",\n\t\t\tpath:         \"some/path/file.png\",\n\t\t\tdataToUpload: \"here's some data\",\n\t\t\twantPresignedURLBody: `{\n\t\t\t\t\t\"service\":\"aws_s3\",\n\t\t\t\t\t\"operation\": \"upload_post\",\n\t\t\t\t\t\"files\":[{\"name\":\"%s\"}]\n\t\t\t\t}`,\n\t\t\twantPresignedHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"token asd123\",\n\t\t\t\t\"Run_id\":        \"123456\",\n\t\t\t},\n\t\t\twantPresignedURLMethod:  http.MethodPost,\n\t\t\tuploadResponse:          http.StatusInternalServerError,\n\t\t\tgetPresignedURLResponse: http.StatusOK,\n\t\t\twantError:               \"uploading: server returned 500 (internal server error)\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tmux := http.NewServeMux()\n\t\t\ts := httptest.NewServer(mux)\n\t\t\tdefer s.Close()\n\n\t\t\t// This handles the request to retrieve a presigned url.\n\t\t\tmux.HandleFunc(presignedEndpoint, http.HandlerFunc(\n\t\t\t\tfunc(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t\tdefer r.Body.Close() //nolint:errcheck\n\n\t\t\t\t\tbb, err := io.ReadAll(r.Body)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t// Does the response match the expected format?\n\t\t\t\t\twantPresignedURLBody := fmt.Sprintf(\n\t\t\t\t\t\ttt.wantPresignedURLBody,\n\t\t\t\t\t\tfilepath.Join(basePath, tt.path),\n\t\t\t\t\t)\n\t\t\t\t\tassert.JSONEq(t, wantPresignedURLBody, string(bb))\n\n\t\t\t\t\t// Do the HTTP headers are sent to the server from the browser module?\n\t\t\t\t\tfor k, v := range tt.wantPresignedHeaders {\n\t\t\t\t\t\tassert.Equal(t, v, r.Header[k][0])\n\t\t\t\t\t}\n\n\t\t\t\t\tvar formFields string\n\t\t\t\t\tfor k, v := range tt.multipartFormFields {\n\t\t\t\t\t\tformFields += fmt.Sprintf(`\"%s\":\"%s\",`, k, v)\n\t\t\t\t\t}\n\t\t\t\t\tformFields = strings.TrimRight(formFields, \",\")\n\n\t\t\t\t\tw.WriteHeader(tt.getPresignedURLResponse)\n\t\t\t\t\t_, err = fmt.Fprintf(w, `{\n\t\t\t\t\t\t\t\"service\": \"aws_s3\",\n\t\t\t\t\t\t\t\"urls\": [{\n\t\t\t\t\t\t\t\t\"name\": \"%s\",\n\t\t\t\t\t\t\t\t\"pre_signed_url\": \"%s\",\n\t\t\t\t\t\t\t\t\"method\": \"%s\",\n\t\t\t\t\t\t\t\t\"form_fields\": {%s}\n\t\t\t\t\t\t\t}]\n\t\t\t\t\t\t\t}`,\n\t\t\t\t\t\tbasePath+\"/\"+tt.path,\n\t\t\t\t\t\ts.URL+uploadEndpoint,\n\t\t\t\t\t\ttt.wantPresignedURLMethod,\n\t\t\t\t\t\tformFields,\n\t\t\t\t\t)\n\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t},\n\t\t\t))\n\n\t\t\t// This handles the upload of the files with the presigned url that\n\t\t\t// is retrieved from the handler above.\n\t\t\tmux.HandleFunc(uploadEndpoint, http.HandlerFunc(\n\t\t\t\tfunc(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t\tdefer r.Body.Close() //nolint:errcheck\n\n\t\t\t\t\tassert.Equal(t, tt.wantPresignedURLMethod, r.Method)\n\n\t\t\t\t\t// Does the multipart form data contain the file to upload?\n\t\t\t\t\tfile, header, err := r.FormFile(\"file\")\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tt.Cleanup(func() {\n\t\t\t\t\t\t_ = file.Close()\n\t\t\t\t\t})\n\t\t\t\t\tcd := header.Header.Get(\"Content-Disposition\")\n\t\t\t\t\tassert.Equal(t, `form-data; name=\"file\"; filename=\"`+basePath+`/`+tt.path+`\"`, cd)\n\n\t\t\t\t\t// Does the file content match the expected data?\n\t\t\t\t\tbb, err := io.ReadAll(file)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, tt.dataToUpload, string(bb))\n\n\t\t\t\t\t// Is the content type set correctly to the binary data?\n\t\t\t\t\tassert.Equal(t, \"application/octet-stream\", header.Header.Get(\"Content-Type\"))\n\n\t\t\t\t\tw.WriteHeader(tt.uploadResponse)\n\t\t\t\t}))\n\n\t\t\tr := NewRemoteFilePersister(s.URL+presignedEndpoint, tt.wantPresignedHeaders, basePath)\n\t\t\terr := r.Persist(context.Background(), tt.path, strings.NewReader(tt.dataToUpload))\n\t\t\tif tt.wantError != \"\" {\n\t\t\t\tassert.EqualError(t, err, tt.wantError)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/storage/storage.go",
    "content": "// Package storage provides data storage for the extension and user specific data.\npackage storage\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n)\n\n// K6BrowserDataDirPattern is the pattern used to create the\n// temporary directory for the browser data.\nconst K6BrowserDataDirPattern = \"k6browser-data-*\"\n\n// Dir manages data storage for the extension and user specific data\n// on the local filesystem.\ntype Dir struct {\n\tDir    string // path to the data storage directory\n\tmu     sync.Mutex\n\tremove bool // whether to remove the temporary directory in cleanup\n\n\t// FS abstractions\n\tfsMkdirTemp func(dir, pattern string) (string, error)\n\tfsRemoveAll func(path string) error\n}\n\n// Make creates a new temporary directory in tmpDir, and stores the path to\n// the directory in the Dir field. When the dir argument is not empty, no\n// directory will be created and it will not be deleted if Cleanup is called.\nfunc (d *Dir) Make(tmpDir string, dir any) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\t// use the provided dir.\n\tif ud, ok := dir.(string); ok && ud != \"\" {\n\t\td.Dir = ud\n\t\treturn nil\n\t}\n\n\t// create a temporary dir because the provided dir is empty.\n\tif d.fsMkdirTemp == nil {\n\t\td.fsMkdirTemp = os.MkdirTemp //nolint:forbidigo\n\t}\n\tvar err error\n\tif d.Dir, err = d.fsMkdirTemp(tmpDir, K6BrowserDataDirPattern); err != nil {\n\t\tvar (\n\t\t\tpe   *fs.PathError\n\t\t\tpath = filepath.Join(tmpDir, K6BrowserDataDirPattern)\n\t\t)\n\t\tif errors.As(err, &pe) {\n\t\t\tpath = pe.Path\n\t\t\terr = pe.Err\n\t\t}\n\n\t\treturn fmt.Errorf(\"making browser data directory %q: %w\", path, err)\n\t}\n\td.remove = true\n\n\treturn nil\n}\n\n// Cleanup removes the temporary directory if Make was called with a non\n// empty dir argument.\n// It is named as Cleanup because it can be used for other features in the\n// future.\nfunc (d *Dir) Cleanup() error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\tif !d.remove {\n\t\treturn nil\n\t}\n\n\tif d.fsRemoveAll == nil {\n\t\td.fsRemoveAll = os.RemoveAll //nolint:forbidigo\n\t}\n\n\tif err := d.fsRemoveAll(d.Dir); err != nil {\n\t\t// On Windows, we may need to retry the removal after a delay to ensure all Chromium processes are terminated.\n\t\t// See https://github.com/grafana/k6/issues/4364\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t\treturn d.fsRemoveAll(d.Dir)\n\t\t}\n\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/storage/storage_test.go",
    "content": "package storage\n\nimport (\n\t\"io/fs\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDirMake(t *testing.T) {\n\tt.Parallel()\n\n\ttmpDir := os.TempDir() //nolint:forbidigo\n\n\tt.Run(\"dir_provided\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tdir := t.TempDir()\n\n\t\tvar s Dir\n\t\trequire.NoError(t, s.Make(\"\", dir))\n\t\trequire.Equal(t, dir, s.Dir, \"should return the directory\")\n\t\tassert.NotPanics(t, func() {\n\t\t\tt.Helper()\n\t\t\terr := s.Cleanup()\n\t\t\tassert.NoError(t, err)\n\t\t}) // should be a no-op\n\t\tassert.DirExists(t, dir, \"should not remove directory\")\n\t})\n\n\tt.Run(\"dir_absent\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar s Dir\n\t\trequire.NoError(t, s.Make(\"\", \"\"))\n\t\trequire.True(t, strings.HasPrefix(s.Dir, tmpDir))\n\t\trequire.DirExists(t, s.Dir)\n\n\t\tassert.NotPanics(t, func() {\n\t\t\tt.Helper()\n\t\t\terr := s.Cleanup()\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\trequire.NoDirExists(t, s.Dir)\n\t})\n\n\tt.Run(\"dir_mk_err\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar s Dir\n\t\trequire.ErrorIs(t, s.Make(\"/NOT_EXISTING_DIRECTORY/K6/BROWSER\", \"\"), fs.ErrNotExist)\n\t\tassert.Empty(t, s.Dir)\n\n\t\tassert.NotPanics(t, func() {\n\t\t\tt.Helper()\n\t\t\terr := s.Cleanup()\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/browser_context_options_test.go",
    "content": "package tests\n\nimport (\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc TestBrowserContextOptionsDefaultValues(t *testing.T) {\n\tt.Parallel()\n\n\topts := common.DefaultBrowserContextOptions()\n\tassert.False(t, opts.AcceptDownloads)\n\tassert.Empty(t, opts.DownloadsPath)\n\tassert.False(t, opts.BypassCSP)\n\tassert.Equal(t, common.ColorSchemeLight, opts.ColorScheme)\n\tassert.Equal(t, 1.0, opts.DeviceScaleFactor)\n\tassert.Empty(t, opts.ExtraHTTPHeaders)\n\tassert.Nil(t, opts.Geolocation)\n\tassert.False(t, opts.HasTouch)\n\tassert.True(t, opts.HTTPCredentials.IsEmpty())\n\tassert.False(t, opts.IgnoreHTTPSErrors)\n\tassert.False(t, opts.IsMobile)\n\tassert.True(t, opts.JavaScriptEnabled)\n\tassert.Equal(t, common.DefaultLocale, opts.Locale)\n\tassert.False(t, opts.Offline)\n\tassert.Empty(t, opts.Permissions)\n\tassert.Equal(t, common.ReducedMotionNoPreference, opts.ReducedMotion)\n\tassert.Equal(t, common.Screen{Width: common.DefaultScreenWidth, Height: common.DefaultScreenHeight}, opts.Screen)\n\tassert.Equal(t, \"\", opts.TimezoneID)\n\tassert.Equal(t, \"\", opts.UserAgent)\n\tassert.Equal(t, common.Viewport{Width: common.DefaultScreenWidth, Height: common.DefaultScreenHeight}, opts.Viewport)\n}\n\nfunc TestBrowserContextOptionsDefaultViewport(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\tviewportSize := p.ViewportSize()\n\tassert.Equal(t, float64(common.DefaultScreenWidth), viewportSize[\"width\"])\n\tassert.Equal(t, float64(common.DefaultScreenHeight), viewportSize[\"height\"])\n}\n\nfunc TestBrowserContextOptionsSetViewport(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\topts := common.DefaultBrowserContextOptions()\n\topts.Viewport = common.Viewport{\n\t\tWidth:  800,\n\t\tHeight: 600,\n\t}\n\tbctx, err := tb.NewContext(opts)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\tif err := bctx.Close(); err != nil {\n\t\t\tt.Log(\"closing browser context:\", err)\n\t\t}\n\t})\n\tp, err := bctx.NewPage()\n\trequire.NoError(t, err)\n\n\tviewportSize := p.ViewportSize()\n\tassert.Equal(t, float64(800), viewportSize[\"width\"])\n\tassert.Equal(t, float64(600), viewportSize[\"height\"])\n}\n\nfunc TestBrowserContextOptionsExtraHTTPHeaders(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\n\topts := common.DefaultBrowserContextOptions()\n\topts.ExtraHTTPHeaders = map[string]string{\n\t\t\"Some-Header\": \"Some-Value\",\n\t}\n\tbctx, err := tb.NewContext(opts)\n\trequire.NoError(t, err)\n\tt.Cleanup(func() {\n\t\tif err := bctx.Close(); err != nil {\n\t\t\tt.Log(\"closing browser context:\", err)\n\t\t}\n\t})\n\n\tp, err := bctx.NewPage()\n\trequire.NoError(t, err)\n\n\terr = tb.awaitWithTimeout(time.Second*5, func() error {\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\tresp, err := p.Goto(\n\t\t\ttb.url(\"/get\"),\n\t\t\topts,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trequire.NotNil(t, resp)\n\n\t\tresponseBody, err := resp.Body()\n\t\trequire.NoError(t, err)\n\n\t\tvar body struct{ Headers map[string][]string }\n\t\trequire.NoError(t, json.Unmarshal(responseBody, &body))\n\n\t\th := body.Headers[\"Some-Header\"]\n\t\trequire.NotEmpty(t, h)\n\t\tassert.Equal(t, \"Some-Value\", h[0])\n\n\t\treturn nil\n\t})\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/browser_context_test.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n)\n\nfunc TestBrowserContextAddCookies(t *testing.T) {\n\tt.Parallel()\n\n\tdayAfter := time.Now().\n\t\tAdd(24 * time.Hour).\n\t\tUnix()\n\tdayBefore := time.Now().\n\t\tAdd(-24 * time.Hour).\n\t\tUnix()\n\n\ttests := map[string]struct {\n\t\tname             string\n\t\tcookies          []*common.Cookie\n\t\twantCookiesToSet []*common.Cookie\n\t\twantErr          bool\n\t}{\n\t\t\"cookie\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:  \"test_cookie_name\",\n\t\t\t\t\tValue: \"test_cookie_value\",\n\t\t\t\t\tURL:   \"http://test.go\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookiesToSet: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"test_cookie_name\",\n\t\t\t\t\tValue:    \"test_cookie_value\",\n\t\t\t\t\tDomain:   \"test.go\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t\"cookie_with_url\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:  \"test_cookie_name\",\n\t\t\t\t\tValue: \"test_cookie_value\",\n\t\t\t\t\tURL:   \"http://test.go\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookiesToSet: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"test_cookie_name\",\n\t\t\t\t\tValue:    \"test_cookie_value\",\n\t\t\t\t\tDomain:   \"test.go\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t\"cookie_with_domain_and_path\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:   \"test_cookie_name\",\n\t\t\t\t\tValue:  \"test_cookie_value\",\n\t\t\t\t\tDomain: \"test.go\",\n\t\t\t\t\tPath:   \"/to/page\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookiesToSet: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"test_cookie_name\",\n\t\t\t\t\tValue:    \"test_cookie_value\",\n\t\t\t\t\tDomain:   \"test.go\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/to/page\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t\"cookie_with_expiration\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t// session cookie\n\t\t\t\t{\n\t\t\t\t\tName:  \"session_cookie\",\n\t\t\t\t\tValue: \"session_cookie_value\",\n\t\t\t\t\tURL:   \"http://test.go\",\n\t\t\t\t},\n\t\t\t\t// persistent cookie\n\t\t\t\t{\n\t\t\t\t\tName:    \"persistent_cookie_name\",\n\t\t\t\t\tValue:   \"persistent_cookie_value\",\n\t\t\t\t\tExpires: dayAfter,\n\t\t\t\t\tURL:     \"http://test.go\",\n\t\t\t\t},\n\t\t\t\t// expired cookie\n\t\t\t\t{\n\t\t\t\t\tName:    \"expired_cookie_name\",\n\t\t\t\t\tValue:   \"expired_cookie_value\",\n\t\t\t\t\tExpires: dayBefore,\n\t\t\t\t\tURL:     \"http://test.go\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantCookiesToSet: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:    \"session_cookie\",\n\t\t\t\t\tValue:   \"session_cookie_value\",\n\t\t\t\t\tDomain:  \"test.go\",\n\t\t\t\t\tExpires: -1,\n\t\t\t\t\tPath:    \"/\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:    \"persistent_cookie_name\",\n\t\t\t\t\tValue:   \"persistent_cookie_value\",\n\t\t\t\t\tDomain:  \"test.go\",\n\t\t\t\t\tExpires: dayAfter,\n\t\t\t\t\tPath:    \"/\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: false,\n\t\t},\n\t\t\"nil_cookies\": {\n\t\t\tcookies: nil,\n\t\t\twantErr: true,\n\t\t},\n\t\t\"cookie_missing_name\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tValue: \"test_cookie_value\",\n\t\t\t\t\tURL:   \"http://test.go\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t\"cookie_missing_value\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName: \"test_cookie_name\",\n\t\t\t\t\tURL:  \"http://test.go\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t\"cookie_missing_url\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:  \"test_cookie_name\",\n\t\t\t\t\tValue: \"test_cookie_value\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t\"cookies_missing_path\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:   \"test_cookie_name\",\n\t\t\t\t\tValue:  \"test_cookie_value\",\n\t\t\t\t\tDomain: \"test.go\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t\t\"cookies_missing_domain\": {\n\t\t\tcookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:  \"test_cookie_name\",\n\t\t\t\t\tValue: \"test_cookie_value\",\n\t\t\t\t\tPath:  \"/to/page\",\n\t\t\t\t},\n\t\t\t},\n\t\t\twantErr: true,\n\t\t},\n\t}\n\tfor name, tt := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tbc, err := tb.NewContext(nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = bc.AddCookies(tt.cookies)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// ensure cookies are set.\n\t\t\tcookies, err := bc.Cookies()\n\t\t\trequire.NoErrorf(t,\n\t\t\t\terr, \"failed to get cookies from the browser context\",\n\t\t\t)\n\t\t\tassert.Equalf(t,\n\t\t\t\ttt.wantCookiesToSet, cookies,\n\t\t\t\t\"incorrect cookies received from the browser context\",\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc TestBrowserContextCookies(t *testing.T) {\n\tt.Parallel()\n\n\t// an empty page is required to set cookies. we're just using a\n\t// simple handler that returns 200 OK to have an empty page.\n\tokHandler := func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusOK)\n\t}\n\n\ttests := map[string]struct {\n\t\t// setupHandler is a handler that will be used to setup the\n\t\t// test environment. it acts like a page returning cookies.\n\t\tsetupHandler func(w http.ResponseWriter, r *http.Request)\n\n\t\t// documentCookiesSnippet is a JavaScript snippet that will be\n\t\t// evaluated in the page to set document.cookie.\n\t\tdocumentCookiesSnippet string\n\n\t\t// addCookies is a list of cookies that will be added to the\n\t\t// browser context using the AddCookies method.\n\t\t// if empty, no cookies will be added.\n\t\taddCookies []*common.Cookie\n\n\t\t// filterCookiesByURLs allows to filter cookies by URLs.\n\t\t// if nil, all cookies will be returned.\n\t\tfilterCookiesByURLs []string\n\n\t\t// wantDocumentCookies is a string representation of the\n\t\t// document.cookie value that is expected to be set.\n\t\twantDocumentCookies string\n\n\t\t// wantContextCookies is a list of cookies that are expected\n\t\t// to be set in the browser context.\n\t\twantContextCookies []*common.Cookie\n\n\t\twantErr bool\n\t}{\n\t\t\"no_cookies\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"\",\n\t\t\twantContextCookies:  nil,\n\t\t},\n\t\t\"cookie\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\tdocument.cookie = \"name=value\";\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"name=value\",\n\t\t\twantContextCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"name\",\n\t\t\t\t\tValue:    \"value\",\n\t\t\t\t\tDomain:   \"127.0.0.1\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"cookies\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\tdocument.cookie = \"name=value\";\n\t\t\t\t\tdocument.cookie = \"name2=value2\";\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"name=value; name2=value2\",\n\t\t\twantContextCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"name\",\n\t\t\t\t\tValue:    \"value\",\n\t\t\t\t\tDomain:   \"127.0.0.1\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:     \"name2\",\n\t\t\t\t\tValue:    \"value2\",\n\t\t\t\t\tDomain:   \"127.0.0.1\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"cookie_with_path\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\tdocument.cookie = \"name=value; path=/empty\";\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"name=value\",\n\t\t\twantContextCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"name\",\n\t\t\t\t\tValue:    \"value\",\n\t\t\t\t\tDomain:   \"127.0.0.1\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/empty\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"cookie_with_different_domain\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\tdocument.cookie = \"name=value; domain=k6.io\";\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"\", // some cookies cannot be set (i.e. cookies using different domains)\n\t\t\twantContextCookies:  nil,\n\t\t},\n\t\t\"http_only_cookie\": {\n\t\t\tsetupHandler: func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.Header().Set(\"Set-Cookie\", \"name=value;HttpOnly; Path=/\")\n\t\t\t},\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"\",\n\t\t\twantContextCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tHTTPOnly: true,\n\t\t\t\t\tName:     \"name\",\n\t\t\t\t\tValue:    \"value\",\n\t\t\t\t\tDomain:   \"127.0.0.1\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSameSite: \"\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"same_site_strict_cookie\": {\n\t\t\tsetupHandler: func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.Header().Set(\"Set-Cookie\", \"name=value;SameSite=Strict\")\n\t\t\t},\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"name=value\",\n\t\t\twantContextCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tSameSite: common.CookieSameSiteStrict,\n\t\t\t\t\tName:     \"name\",\n\t\t\t\t\tValue:    \"value\",\n\t\t\t\t\tDomain:   \"127.0.0.1\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"same_site_lax_cookie\": {\n\t\t\tsetupHandler: func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.Header().Set(\"Set-Cookie\", \"name=value;SameSite=Lax\")\n\t\t\t},\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\tfilterCookiesByURLs: nil,\n\t\t\twantDocumentCookies: \"name=value\",\n\t\t\twantContextCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tSameSite: common.CookieSameSiteLax,\n\t\t\t\t\tName:     \"name\",\n\t\t\t\t\tValue:    \"value\",\n\t\t\t\t\tDomain:   \"127.0.0.1\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSecure:   false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_cookies_by_urls\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\taddCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"fooCookie\",\n\t\t\t\t\tValue:    \"fooValue\",\n\t\t\t\t\tURL:      \"https://foo.com\",\n\t\t\t\t\tSameSite: common.CookieSameSiteNone,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:     \"barCookie\",\n\t\t\t\t\tValue:    \"barValue\",\n\t\t\t\t\tURL:      \"https://bar.com\",\n\t\t\t\t\tSameSite: common.CookieSameSiteLax,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:     \"bazCookie\",\n\t\t\t\t\tValue:    \"bazValue\",\n\t\t\t\t\tURL:      \"https://baz.com\",\n\t\t\t\t\tSameSite: common.CookieSameSiteLax,\n\t\t\t\t},\n\t\t\t},\n\t\t\tfilterCookiesByURLs: []string{\n\t\t\t\t\"https://foo.com\",\n\t\t\t\t\"https://baz.com\",\n\t\t\t},\n\t\t\twantDocumentCookies: \"\",\n\t\t\twantContextCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"fooCookie\",\n\t\t\t\t\tValue:    \"fooValue\",\n\t\t\t\t\tDomain:   \"foo.com\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSecure:   true,\n\t\t\t\t\tSameSite: common.CookieSameSiteNone,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:     \"bazCookie\",\n\t\t\t\t\tValue:    \"bazValue\",\n\t\t\t\t\tDomain:   \"baz.com\",\n\t\t\t\t\tExpires:  -1,\n\t\t\t\t\tHTTPOnly: false,\n\t\t\t\t\tPath:     \"/\",\n\t\t\t\t\tSecure:   true,\n\t\t\t\t\tSameSite: common.CookieSameSiteLax,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"filter_no_cookies\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\taddCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"fooCookie\",\n\t\t\t\t\tValue:    \"fooValue\",\n\t\t\t\t\tURL:      \"https://foo.com\",\n\t\t\t\t\tSameSite: common.CookieSameSiteNone,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tName:     \"barCookie\",\n\t\t\t\t\tValue:    \"barValue\",\n\t\t\t\t\tURL:      \"https://bar.com\",\n\t\t\t\t\tSameSite: common.CookieSameSiteLax,\n\t\t\t\t},\n\t\t\t},\n\t\t\tfilterCookiesByURLs: []string{\n\t\t\t\t\"https://baz.com\",\n\t\t\t},\n\t\t\twantDocumentCookies: \"\",\n\t\t\twantContextCookies:  nil,\n\t\t},\n\t\t\"filter_invalid\": {\n\t\t\tsetupHandler: okHandler,\n\t\t\tdocumentCookiesSnippet: `\n\t\t\t\t() => {\n\t\t\t\t\treturn document.cookie;\n\t\t\t\t}\n\t\t\t`,\n\t\t\taddCookies: []*common.Cookie{\n\t\t\t\t{\n\t\t\t\t\tName:     \"fooCookie\",\n\t\t\t\t\tValue:    \"fooValue\",\n\t\t\t\t\tURL:      \"https://foo.com\",\n\t\t\t\t\tSameSite: common.CookieSameSiteNone,\n\t\t\t\t},\n\t\t\t},\n\t\t\tfilterCookiesByURLs: []string{\n\t\t\t\t\"LOREM IPSUM\",\n\t\t\t},\n\t\t\twantDocumentCookies: \"\",\n\t\t\twantContextCookies:  nil,\n\t\t\twantErr:             true,\n\t\t},\n\t}\n\tfor name, tt := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t// an empty page is required to set cookies\n\t\t\t// since we want to run cookie tests in parallel\n\t\t\t// we're creating a new browser context for each test.\n\t\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\t// the setupHandler can set some cookies\n\t\t\t// that will be received by the browser context.\n\t\t\ttb.withHandler(\"/empty\", tt.setupHandler)\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := p.Goto(\n\t\t\t\ttb.url(\"/empty\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoErrorf(t,\n\t\t\t\terr, \"failed to open an empty page\",\n\t\t\t)\n\n\t\t\t// setting document.cookie into the page\n\t\t\tcookie, err := p.Evaluate(tt.documentCookiesSnippet)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equalf(t,\n\t\t\t\ttt.wantDocumentCookies,\n\t\t\t\tcookie,\n\t\t\t\t\"incorrect document.cookie received\",\n\t\t\t)\n\n\t\t\t// adding cookies to the browser context by our API.\n\t\t\tif tt.addCookies != nil {\n\t\t\t\terr := p.Context().AddCookies(tt.addCookies)\n\t\t\t\trequire.NoErrorf(t,\n\t\t\t\t\terr, \"failed to add cookies to the browser context: %#v\", tt.addCookies,\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// getting cookies from the browser context\n\t\t\t// either from the page or from the context\n\t\t\t// some cookies can be set by the response handler\n\t\t\tcookies, err := p.Context().Cookies(tt.filterCookiesByURLs...)\n\t\t\tif tt.wantErr {\n\t\t\t\trequire.Errorf(t,\n\t\t\t\t\terr, \"expected an error, but got none\",\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoErrorf(t,\n\t\t\t\terr, \"failed to get cookies from the browser context\",\n\t\t\t)\n\t\t\tassert.Equalf(t,\n\t\t\t\ttt.wantContextCookies, cookies,\n\t\t\t\t\"incorrect cookies received from the browser context\",\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc TestBrowserContextClearCookies(t *testing.T) {\n\tt.Parallel()\n\n\t// add a cookie and clear it out\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\tp := tb.NewPage(nil)\n\tbctx := p.Context()\n\n\terr := bctx.AddCookies(\n\t\t[]*common.Cookie{\n\t\t\t{\n\t\t\t\tName:  \"test_cookie_name\",\n\t\t\t\tValue: \"test_cookie_value\",\n\t\t\t\tURL:   \"http://test.go\",\n\t\t\t},\n\t\t},\n\t)\n\trequire.NoError(t, err)\n\trequire.NoError(t, bctx.ClearCookies())\n\n\tcookies, err := bctx.Cookies()\n\trequire.NoError(t, err)\n\trequire.Emptyf(t, cookies, \"want no cookies, but got: %#v\", cookies)\n}\n\nfunc TestK6Object(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname      string\n\t\ttestRunID string\n\t\twant      string\n\t}{\n\t\t{\n\t\t\tname: \"empty_testRunId\",\n\t\t\twant: `{\"testRunId\":\"\"}`,\n\t\t},\n\t\t{\n\t\t\tname:      \"with_testRunId\",\n\t\t\ttestRunID: \"123456\",\n\t\t\twant:      `{\"testRunId\":\"123456\"}`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer(), withEnvLookup(env.ConstLookup(env.K6TestRunID, tt.testRunID)))\n\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\t\t\tdefer tb.vu.EndIteration(t)\n\n\t\t\t// First test with browser.newPage\n\t\t\tgot := tb.vu.RunPromise(t, `\n\t\t\t\tconst p = await browser.newPage();\n\t\t\t\tawait p.goto(\"about:blank\");\n\t\t\t\tconst o = await p.evaluate(() => window.k6);\n\t\t\t\treturn JSON.stringify(o);\n\t\t\t`)\n\t\t\tassert.Equal(t, tt.want, got.Result().String())\n\n\t\t\t// Now test with browser.newContext\n\t\t\tgot = tb.vu.RunPromise(t, `\n\t\t\t\tawait browser.closeContext();\n\t\t\t\tconst c = await browser.newContext();\n\t\t\t\tconst p2 = await c.newPage();\n\t\t\t\tawait p2.goto(\"about:blank\");\n\t\t\t\tconst o2 = await p2.evaluate(() => window.k6);\n\t\t\t\treturn JSON.stringify(o2);\n\t\t\t`)\n\t\t\tassert.Equal(t, tt.want, got.Result().String())\n\t\t})\n\t}\n}\n\n// This test ensures that when opening a new tab, this it is possible to navigate\n// to the url. If the mapping layer is not setup correctly we can end up with a\n// NPD.\nfunc TestNewTab(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer(), withEnvLookup(env.ConstLookup(env.K6TestRunID, \"12345\")))\n\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\tdefer tb.vu.EndIteration(t)\n\n\t_, err := tb.vu.RunAsync(t, `\n\t\tconst p = await browser.newPage()\n\t\tawait p.goto(\"%s\")\n\n\t\tconst p2 = await browser.context().newPage()\n\t\tawait p2.goto(\"%s\")\n\t`, tb.staticURL(\"ping.html\"), tb.staticURL(\"ping.html\"))\n\trequire.NoError(t, err)\n}\n\nfunc TestBrowserContextTimeout(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname                     string\n\t\tdefaultTimeout           time.Duration\n\t\tdefaultNavigationTimeout time.Duration\n\t}{\n\t\t{\n\t\t\tname:           \"fail when timeout exceeds default timeout\",\n\t\t\tdefaultTimeout: 1 * time.Millisecond,\n\t\t},\n\t\t{\n\t\t\tname:                     \"fail when timeout exceeds default navigation timeout\",\n\t\t\tdefaultNavigationTimeout: 1 * time.Millisecond,\n\t\t},\n\t\t{\n\t\t\tname:                     \"default navigation timeout supersedes default timeout\",\n\t\t\tdefaultTimeout:           30 * time.Second,\n\t\t\tdefaultNavigationTimeout: 1 * time.Millisecond,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withHTTPServer())\n\n\t\t\ttb.withHandler(\"/slow\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\t_, err := fmt.Fprintf(w, `sorry for being so slow`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\n\t\t\tbc, err := tb.NewContext(nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tp, err := bc.NewPage()\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar timeout time.Duration\n\t\t\tif tc.defaultTimeout != 0 {\n\t\t\t\ttimeout = tc.defaultTimeout\n\t\t\t\tbc.SetDefaultTimeout(tc.defaultTimeout.Milliseconds())\n\t\t\t}\n\t\t\tif tc.defaultNavigationTimeout != 0 {\n\t\t\t\ttimeout = tc.defaultNavigationTimeout\n\t\t\t\tbc.SetDefaultNavigationTimeout(tc.defaultNavigationTimeout.Milliseconds())\n\t\t\t}\n\t\t\tres, err := p.Goto(\n\t\t\t\ttb.url(\"/slow\"),\n\t\t\t\t&common.FrameGotoOptions{\n\t\t\t\t\tTimeout: timeout,\n\t\t\t\t},\n\t\t\t)\n\t\t\trequire.Nil(t, res)\n\t\t\tassert.ErrorContains(t, err, \"timed out after\")\n\t\t})\n\t}\n}\n\nfunc TestBrowserContextWaitForEvent(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname      string\n\t\tevent     string\n\t\tpredicate func(p *common.Page) (bool, error)\n\t\ttimeout   time.Duration\n\t\twantErr   string\n\t}{\n\t\t{\n\t\t\t// No predicate and default timeout.\n\t\t\tname:    \"success\",\n\t\t\tevent:   \"page\",\n\t\t\ttimeout: 30 * time.Second,\n\t\t},\n\t\t{\n\t\t\t// With a predicate function and default timeout.\n\t\t\tname:      \"success_with_predicate\",\n\t\t\tevent:     \"page\",\n\t\t\tpredicate: func(p *common.Page) (bool, error) { return true, nil },\n\t\t\ttimeout:   30 * time.Second,\n\t\t},\n\t\t{\n\t\t\t// Fails when an event other than \"page\" is passed in.\n\t\t\tname:    \"fails_incorrect_event\",\n\t\t\tevent:   \"browser\",\n\t\t\twantErr: `incorrect event \"browser\", \"page\" is the only event supported`,\n\t\t},\n\t\t{\n\t\t\t// Fails when the timeout fires while waiting on waitForEvent.\n\t\t\tname:      \"fails_timeout\",\n\t\t\tevent:     \"page\",\n\t\t\tpredicate: func(p *common.Page) (bool, error) { return false, nil },\n\t\t\ttimeout:   10 * time.Millisecond,\n\t\t\twantErr:   \"waitForEvent timed out after 10ms\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t// Use withSkipClose() opt as we will close it manually to force the\n\t\t\t// page.TaskQueue closing, which seems to be a requirement otherwise\n\t\t\t// it doesn't complete the test.\n\t\t\ttb := newTestBrowser(t)\n\n\t\t\tbc, err := tb.NewContext(nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tctx, cancel := context.WithTimeout(tb.context(), 5*time.Second)\n\t\t\tdefer cancel()\n\n\t\t\tvar (\n\t\t\t\taboutToCallWait = make(chan bool)\n\t\t\t\tp1ID, p2ID      string\n\t\t\t)\n\n\t\t\terr = tb.run(ctx,\n\t\t\t\tfunc() error {\n\t\t\t\t\tvar resp any\n\t\t\t\t\tclose(aboutToCallWait)\n\t\t\t\t\tresp, err := bc.WaitForEvent(tc.event, tc.predicate, tc.timeout)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\tp, ok := resp.(*common.Page)\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\treturn errors.New(\"response from waitForEvent is not a page\")\n\t\t\t\t\t}\n\t\t\t\t\tp1ID = p.MainFrame().ID()\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tfunc() error {\n\t\t\t\t\t<-aboutToCallWait\n\n\t\t\t\t\tif tc.wantErr == \"\" {\n\t\t\t\t\t\tp, err := bc.NewPage()\n\t\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\t\tp2ID = p.MainFrame().ID()\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t)\n\n\t\t\tif tc.wantErr != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, tc.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.NoError(t, err)\n\t\t\t// We want to make sure that the page that was created with\n\t\t\t// newPage matches the return value from waitForEvent.\n\t\t\tassert.Equal(t, p1ID, p2ID)\n\t\t})\n\t}\n}\n\nfunc TestBrowserContextGrantPermissions(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname       string\n\t\tpermission string\n\t\twantErr    string\n\t}{\n\t\t{name: \"geolocation\", permission: \"geolocation\"},\n\t\t{name: \"midi\", permission: \"midi\"},\n\t\t{name: \"midi-sysex\", permission: \"midi-sysex\"},\n\t\t{name: \"notifications\", permission: \"notifications\"},\n\t\t{name: \"camera\", permission: \"camera\"},\n\t\t{name: \"microphone\", permission: \"microphone\"},\n\t\t{name: \"background-sync\", permission: \"background-sync\"},\n\t\t{name: \"ambient-light-sensor\", permission: \"ambient-light-sensor\"},\n\t\t{name: \"accelerometer\", permission: \"accelerometer\"},\n\t\t{name: \"gyroscope\", permission: \"gyroscope\"},\n\t\t{name: \"magnetometer\", permission: \"magnetometer\"},\n\t\t{name: \"clipboard-read\", permission: \"clipboard-read\"},\n\t\t{name: \"clipboard-write\", permission: \"clipboard-write\"},\n\t\t{name: \"payment-handler\", permission: \"payment-handler\"},\n\t\t{name: \"fake-permission\", permission: \"fake-permission\", wantErr: `\"fake-permission\" is an invalid permission`},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\tbCtx, err := tb.NewContext(nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = bCtx.GrantPermissions(\n\t\t\t\t[]string{tc.permission},\n\t\t\t\tcommon.GrantPermissionsOptions{},\n\t\t\t)\n\n\t\t\tif tc.wantErr == \"\" {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.EqualError(t, err, tc.wantErr)\n\t\t})\n\t}\n}\n\nfunc TestBrowserContextClearPermissions(t *testing.T) {\n\tt.Parallel()\n\n\thasPermission := func(_ *testBrowser, p *common.Page, perm string) bool {\n\t\tt.Helper()\n\n\t\tjs := fmt.Sprintf(`\n\t\t\t(perm) => navigator.permissions.query(\n\t\t\t\t{ name: %q }\n\t\t\t).then(result => result.state)\n\t\t`, perm)\n\t\tv, err := p.Evaluate(js)\n\t\trequire.NoError(t, err)\n\t\ts := asString(t, v)\n\t\treturn s == \"granted\"\n\t}\n\n\tt.Run(\"no_permissions_set\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tbCtx, err := tb.NewContext(nil)\n\t\trequire.NoError(t, err)\n\t\tp, err := bCtx.NewPage()\n\t\trequire.NoError(t, err)\n\n\t\trequire.False(t, hasPermission(tb, p, \"geolocation\"))\n\n\t\terr = bCtx.ClearPermissions()\n\t\tassert.NoError(t, err)\n\t\trequire.False(t, hasPermission(tb, p, \"geolocation\"))\n\t})\n\n\tt.Run(\"permissions_set\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tbCtx, err := tb.NewContext(nil)\n\t\trequire.NoError(t, err)\n\t\tp, err := bCtx.NewPage()\n\t\trequire.NoError(t, err)\n\n\t\trequire.False(t, hasPermission(tb, p, \"geolocation\"))\n\n\t\terr = bCtx.GrantPermissions(\n\t\t\t[]string{\"geolocation\"},\n\t\t\tcommon.GrantPermissionsOptions{},\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, hasPermission(tb, p, \"geolocation\"))\n\n\t\terr = bCtx.ClearPermissions()\n\t\tassert.NoError(t, err)\n\t\trequire.False(t, hasPermission(tb, p, \"geolocation\"))\n\t})\n}\n\nfunc TestBrowserContextMappingBehavior(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\n\t// By default, `browser.context()` returns a nullish value,\n\t// so when using optional chaining (i.e., '?.') to call one of the mapping methods,\n\t// it shouldn't panic, as described in https://github.com/grafana/k6/issues/4936.\n\tvalue, err := tb.vu.RunOnEventLoop(t, `browser.context()?.pages() != null`)\n\trequire.NoError(t, err)\n\trequire.False(t, value.ToBoolean())\n\n\t_, err = tb.vu.RunAsync(t, `await browser.newContext();`)\n\trequire.NoError(t, err)\n\n\t// Now, after having called `browser.newContext()` as above, it should return\n\t// a non-null Browser context, so when calling one of the mapping methods, it\n\t// should also return a non-null value.\n\tvalue, err = tb.runtime().RunString(`browser.context()?.pages() != null`)\n\trequire.NoError(t, err)\n\trequire.True(t, value.ToBoolean())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/browser_test.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/browser\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/storage\"\n)\n\nfunc TestBrowserNewPage(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t)\n\tp1 := b.NewPage(nil)\n\tc := b.Context()\n\tassert.NotNil(t, c)\n\n\t_, err := b.Browser.NewPage(nil)\n\tassert.EqualError(t, err, \"new page: existing browser context must be closed before creating a new one\")\n\n\terr = p1.Close()\n\trequire.NoError(t, err)\n\tc = b.Context()\n\tassert.NotNil(t, c)\n\n\t_, err = b.Browser.NewPage(nil)\n\tassert.EqualError(t, err, \"new page: existing browser context must be closed before creating a new one\")\n\n\trequire.NoError(t, b.Context().Close())\n\tc = b.Context()\n\tassert.Nil(t, c)\n\n\t_ = b.NewPage(nil)\n\tc = b.Context()\n\tassert.NotNil(t, c)\n}\n\nfunc TestBrowserNewContext(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t)\n\tbc1, err := b.NewContext(nil)\n\tassert.NoError(t, err)\n\tc := b.Context()\n\tassert.NotNil(t, c)\n\n\t_, err = b.NewContext(nil)\n\tassert.EqualError(t, err, \"existing browser context must be closed before creating a new one\")\n\n\trequire.NoError(t, bc1.Close())\n\tc = b.Context()\n\tassert.Nil(t, c)\n\n\t_, err = b.NewContext(nil)\n\tassert.NoError(t, err)\n\tc = b.Context()\n\tassert.NotNil(t, c)\n}\n\nfunc TestTmpDirCleanup(t *testing.T) {\n\tt.Parallel()\n\n\ttmpDirPath := t.TempDir()\n\n\tb := newTestBrowser(\n\t\tt,\n\t\twithSkipClose(),\n\t\twithEnvLookup(env.ConstLookup(\"TMPDIR\", tmpDirPath)),\n\t)\n\tp := b.NewPage(nil)\n\trequire.NoError(t, p.Close())\n\n\tmatches, err := filepath.Glob(filepath.Join(tmpDirPath, storage.K6BrowserDataDirPattern))\n\tassert.NoError(t, err)\n\tassert.NotEmptyf(t, matches, \"a dir should exist that matches the pattern %q\", storage.K6BrowserDataDirPattern)\n\n\tb.Close()\n\n\t// We need to wait for something (k6 browser, chromium or the os) to\n\t// actually complete the removal of the directory. It's a race condition.\n\t// To try to mitigate the issue, we're adding a retry which waits half a\n\t// second if the dir still exits.\n\tfor range 5 {\n\t\tmatches, err = filepath.Glob(filepath.Join(tmpDirPath, storage.K6BrowserDataDirPattern))\n\t\tassert.NoError(t, err)\n\t\tif len(matches) == 0 {\n\t\t\tbreak\n\t\t}\n\t\ttime.Sleep(time.Millisecond * 500)\n\t}\n\n\tassert.Empty(t, matches, \"a dir shouldn't exist which matches the pattern %q\", storage.K6BrowserDataDirPattern)\n}\n\nfunc TestTmpDirCleanupOnContextClose(t *testing.T) {\n\tt.Parallel()\n\n\ttmpDirPath := t.TempDir()\n\n\tb := newTestBrowser(\n\t\tt,\n\t\twithSkipClose(),\n\t\twithEnvLookup(env.ConstLookup(\"TMPDIR\", tmpDirPath)),\n\t)\n\n\tmatches, err := filepath.Glob(filepath.Join(tmpDirPath, storage.K6BrowserDataDirPattern))\n\tassert.NoError(t, err)\n\tassert.NotEmpty(t, matches, \"a dir should exist that matches the pattern %q\", storage.K6BrowserDataDirPattern)\n\n\tb.cancelContext()\n\t<-b.ctx.Done()\n\n\trequire.NotPanicsf(t, b.Close, \"first call to browser.close should not panic\")\n\n\tmatches, err = filepath.Glob(filepath.Join(tmpDirPath, storage.K6BrowserDataDirPattern))\n\tassert.NoError(t, err)\n\tassert.Empty(t, matches, \"a dir shouldn't exist which matches the pattern %q\", storage.K6BrowserDataDirPattern)\n}\n\nfunc TestBrowserOn(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `\n\tconst result = b.on('%s')\n\tlog(result);`\n\n\tt.Run(\"err_wrong_event\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tb := newTestBrowser(t)\n\t\trequire.NoError(t, b.runtime().Set(\"b\", b.Browser))\n\n\t\t_, err := b.runJavaScript(script, \"wrongevent\")\n\t\trequire.Error(t, err)\n\t\tassert.ErrorContains(t, err, `unknown browser event: \"wrongevent\", must be \"disconnected\"`)\n\t})\n\n\tt.Run(\"ok_promise_resolved\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar (\n\t\t\tb   = newTestBrowser(t, withSkipClose())\n\t\t\trt  = b.runtime()\n\t\t\tlog []string\n\t\t)\n\n\t\trequire.NoError(t, rt.Set(\"b\", b.Browser))\n\t\trequire.NoError(t, rt.Set(\"log\", func(s string) { log = append(log, s) }))\n\n\t\ttime.AfterFunc(100*time.Millisecond, b.Close)\n\t\t_, err := b.runJavaScript(script, \"disconnected\")\n\t\trequire.NoError(t, err)\n\t\tassert.Contains(t, log, \"true\")\n\t})\n\n\tt.Run(\"ok_promise_rejected\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar (\n\t\t\tb   = newTestBrowser(t)\n\t\t\trt  = b.runtime()\n\t\t\tlog []string\n\t\t)\n\n\t\trequire.NoError(t, rt.Set(\"b\", b.Browser))\n\t\trequire.NoError(t, rt.Set(\"log\", func(s string) { log = append(log, s) }))\n\n\t\ttime.AfterFunc(100*time.Millisecond, b.cancelContext)\n\t\t_, err := b.runJavaScript(script, \"disconnected\")\n\t\tassert.ErrorContains(t, err, \"browser.on promise rejected: context canceled\")\n\t})\n}\n\n// This only works for Chrome!\nfunc TestBrowserVersion(t *testing.T) {\n\tt.Parallel()\n\n\tconst re = `^\\d+\\.\\d+\\.\\d+\\.\\d+$`\n\tr, err := regexp.Compile(re) //nolint:gocritic\n\trequire.NoError(t, err)\n\tver := newTestBrowser(t).Version()\n\tassert.Regexp(t, r, ver, \"expected browser version to match regex %q, but found %q\", re, ver)\n}\n\n// This only works for Chrome!\n// TODO: Improve this test, see:\n// https://go.k6.io/k6/js/modules/k6/browser/pull/51#discussion_r742696736\nfunc TestBrowserUserAgent(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t)\n\n\tua := b.UserAgent()\n\tif prefix := \"Mozilla/5.0\"; !strings.HasPrefix(ua, prefix) {\n\t\tt.Errorf(\"UserAgent should start with %q, but got: %q\", prefix, ua)\n\t}\n\t// We default to removing the \"Headless\" part of the user agent string.\n\tassert.NotContains(t, ua, \"Headless\")\n}\n\nfunc TestBrowserCrashErr(t *testing.T) {\n\t// Skip until we get answer from Chromium team in an open issue\n\t// https://issues.chromium.org/issues/364089353.\n\tt.Skip(\"Skipping until we get response from Chromium team\")\n\n\tt.Parallel()\n\n\t// create a new VU in an environment that requires a bad remote-debugging-port.\n\tvu := k6test.NewVU(t, env.ConstLookup(env.BrowserArguments, \"remote-debugging-port=99999\"))\n\n\tmod := browser.New().NewModuleInstance(vu)\n\tjsMod, ok := mod.Exports().Default.(*browser.JSModule)\n\trequire.Truef(t, ok, \"unexpected default mod export type %T\", mod.Exports().Default)\n\n\tvu.ActivateVU()\n\tvu.StartIteration(t)\n\n\tvu.SetVar(t, \"browser\", jsMod.Browser)\n\t_, err := vu.RunAsync(t, `\n\t\tconst p = await browser.newPage();\n\t\tawait p.close();\n\t`)\n\tassert.ErrorContains(t, err, \"launching browser: Invalid devtools server port\")\n}\n\nfunc TestBrowserLogIterationID(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withLogCache())\n\n\tvar (\n\t\titerID     = common.GetIterationID(tb.ctx)\n\t\ttracedEvts int\n\t)\n\n\trequire.NotEmpty(t, iterID)\n\n\ttb.logCache.mu.RLock()\n\tdefer tb.logCache.mu.RUnlock()\n\n\trequire.NotEmpty(t, tb.logCache.entries)\n\n\tfor _, evt := range tb.logCache.entries {\n\t\tfor k, v := range evt.Data {\n\t\t\tif k == \"iteration_id\" {\n\t\t\t\tassert.Equal(t, iterID, v)\n\t\t\t\ttracedEvts++\n\t\t\t}\n\t\t}\n\t}\n\n\tassert.Equal(t, len(tb.logCache.entries), tracedEvts)\n}\n\n//nolint:paralleltest\nfunc TestMultiBrowserPanic(t *testing.T) {\n\t// this test should run sequentially.\n\t// don't use t.Parallel() here.\n\n\tvar b1, b2 *testBrowser\n\n\t// run it in a test to kick in the Cleanup() in testBrowser.\n\tt.Run(\"browsers\", func(t *testing.T) {\n\t\tb1 = newTestBrowser(t)\n\t\tb2 = newTestBrowser(t)\n\n\t\tfunc() {\n\t\t\tdefer func() { _ = recover() }()\n\t\t\tk6ext.Panicf(b1.ctx, \"forcing a panic\")\n\t\t}()\n\t})\n\n\t// FindProcess only returns alive/dead processes on nixes.\n\t// Sending Interrupt on Windows is not implemented.\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"skipping on windows\")\n\t}\n\n\tassertProcess := func(t *testing.T, pid int, n int) {\n\t\tt.Helper()\n\n\t\tp, err := os.FindProcess(pid) //nolint:forbidigo\n\t\tif err != nil {\n\t\t\t// process is already dead.\n\t\t\t// no need to check if it's dead with Signal(0).\n\t\t\treturn\n\t\t}\n\t\tif err = p.Signal(syscall.Signal(0)); !errors.Is(err, os.ErrProcessDone) { //nolint:forbidigo\n\t\t\tassert.Errorf(t, err, \"process #%d should be dead, but exists\", n)\n\t\t}\n\t}\n\tassertProcess(t, b1.pid, 1)\n\tassertProcess(t, b2.pid, 2)\n}\n\nfunc TestBrowserMultiClose(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withSkipClose(), withLogCache())\n\n\trequire.NotPanicsf(t, tb.Close, \"first call to browser.close should not panic\")\n\trequire.NotPanicsf(t, tb.Close, \"second call to browser.close should not panic\")\n\ttb.logCache.assertContains(t, \"browser.close only once\")\n}\n\nfunc TestMultiConnectToSingleBrowser(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withSkipClose())\n\tdefer tb.Close()\n\n\tctx := context.Background()\n\n\tb1, err := tb.browserType.Connect(context.Background(), ctx, tb.wsURL)\n\trequire.NoError(t, err)\n\tt.Cleanup(b1.Close)\n\tbctx1, err := b1.NewContext(nil)\n\trequire.NoError(t, err)\n\tp1, err := bctx1.NewPage()\n\trequire.NoError(t, err, \"failed to create page #1\")\n\n\tb2, err := tb.browserType.Connect(context.Background(), ctx, tb.wsURL)\n\trequire.NoError(t, err)\n\tt.Cleanup(b2.Close)\n\tbctx2, err := b2.NewContext(nil)\n\trequire.NoError(t, err)\n\n\terr = p1.Close()\n\trequire.NoError(t, err, \"failed to close page #1\")\n\trequire.NoError(t, bctx1.Close())\n\n\tp2, err := bctx2.NewPage()\n\trequire.NoError(t, err, \"failed to create page #2\")\n\terr = p2.Close()\n\trequire.NoError(t, err, \"failed to close page #2\")\n}\n\nfunc TestCloseContext(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"close_context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\t_, err := tb.NewContext(nil)\n\t\trequire.NoError(t, err)\n\n\t\tassert.NotNil(t, tb.Context())\n\n\t\terr = tb.CloseContext()\n\t\trequire.NoError(t, err)\n\n\t\tassert.Nil(t, tb.Context())\n\t})\n\n\tt.Run(\"err_no_context\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tassert.Nil(t, tb.Context())\n\t\tassert.Error(t, tb.CloseContext())\n\t})\n}\n\nfunc TestIsolateBrowserContexts(t *testing.T) {\n\tt.Parallel()\n\ttb := newTestBrowser(t)\n\n\tb1 := tb.Browser\n\tb2, err := tb.browserType.Connect(context.Background(), tb.context(), tb.wsURL)\n\trequire.NoError(t, err)\n\tt.Cleanup(b2.Close)\n\n\tbctx1, err := b1.NewContext(nil)\n\trequire.NoError(t, err)\n\tbctx2, err := b2.NewContext(nil)\n\trequire.NoError(t, err)\n\n\t// both browser connections will receive onAttachedToTarget events.\n\t// each Connection value should filter out events that are not related to\n\t// the browser context it wasn't created from.\n\terr = tb.run(tb.context(), func() error {\n\t\t_, err := bctx1.NewPage()\n\t\treturn err\n\t}, func() error {\n\t\t_, err := bctx2.NewPage()\n\t\treturn err\n\t})\n\trequire.NoError(t, err)\n\n\t// assert.Len produces verbose output. so, use our own len.\n\tbctx1PagesLen := len(bctx1.Pages())\n\tbctx2PagesLen := len(bctx2.Pages())\n\tassert.Equalf(t, 1, bctx1PagesLen, \"browser context #1 should be attached to a single page, but got %d\", bctx1PagesLen)\n\tassert.Equalf(t, 1, bctx2PagesLen, \"browser context #2 should be attached to a single page, but got %d\", bctx2PagesLen)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/browser_type_test.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/browser\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/chromium\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n)\n\nfunc TestBrowserTypeConnect(t *testing.T) {\n\tt.Parallel()\n\n\t// Start a test browser so we can get its WS URL\n\t// and use it to connect through BrowserType.Connect.\n\ttb := newTestBrowser(t)\n\tvu := k6test.NewVU(t)\n\tbt := chromium.NewBrowserType(vu)\n\tvu.ActivateVU()\n\n\tb, err := bt.Connect(context.Background(), context.Background(), tb.wsURL)\n\trequire.NoError(t, err)\n\tt.Cleanup(b.Close)\n\t_, err = b.NewPage(nil)\n\trequire.NoError(t, err)\n}\n\nfunc TestBrowserTypeLaunchToConnect(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tbp := newTestBrowserProxy(t, tb)\n\n\t// Export WS URL env var\n\t// pointing to test browser proxy\n\tvu := k6test.NewVU(t, env.ConstLookup(env.WebSocketURLs, bp.wsURL()))\n\n\t// We have to call launch method through JS API in sobek\n\t// to take mapping layer into account, instead of calling\n\t// BrowserType.Launch method directly\n\troot := browser.New()\n\tmod := root.NewModuleInstance(vu)\n\tjsMod, ok := mod.Exports().Default.(*browser.JSModule)\n\trequire.Truef(t, ok, \"unexpected default mod export type %T\", mod.Exports().Default)\n\n\tvu.ActivateVU()\n\tvu.StartIteration(t)\n\n\tvu.SetVar(t, \"browser\", jsMod.Browser)\n\t_, err := vu.RunAsync(t, `\n\t\tconst p = await browser.newPage();\n\t\tawait p.close();\n\t`)\n\trequire.NoError(t, err)\n\n\t// Verify the proxy, which's WS URL was set as\n\t// K6_BROWSER_WS_URL, has received a connection req\n\trequire.True(t, bp.connected)\n\t// Verify that no new process pids have been added\n\t// to pid registry\n\trequire.Len(t, root.PidRegistry.Pids(), 0)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/doc.go",
    "content": "// Package tests provides integration tests.\n// The `testBrowser` type enables us to test the browser module with a real browser.\npackage tests\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/element_handle_test.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"image/png\"\n\t\"io\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n//go:embed static/mouse_helper.js\nvar mouseHelperScriptSource string\n\n//nolint:gochecknoglobals\nvar htmlInputButton = fmt.Sprintf(`\n<!DOCTYPE html>\n<html>\n  <head>\n\t<title>Button test</title>\n  </head>\n  <body>\n\t<script>%s</script>\n\t<button>Click target</button>\n\t<script>\n\t  window.result = 'Was not clicked';\n\t  window.offsetX = undefined;\n\t  window.offsetY = undefined;\n\t  window.pageX = undefined;\n\t  window.pageY = undefined;\n\t  window.shiftKey = undefined;\n\t  window.pageX = undefined;\n\t  window.pageY = undefined;\n\t  window.bubbles = undefined;\n\t  document.querySelector('button').addEventListener('click', e => {\n\t\tresult = 'Clicked';\n\t\toffsetX = e.offsetX;\n\t\toffsetY = e.offsetY;\n\t\tpageX = e.pageX;\n\t\tpageY = e.pageY;\n\t\tshiftKey = e.shiftKey;\n\t\tbubbles = e.bubbles;\n\t\tcancelable = e.cancelable;\n\t\tcomposed = e.composed;\n\t  }, false);\n\t</script>\n  </body>\n</html>\n`, mouseHelperScriptSource)\n\nfunc TestElementHandleBoundingBoxInvisibleElement(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\terr := p.SetContent(`<div style=\"display:none\">hello</div>`, nil)\n\trequire.NoError(t, err)\n\telement, err := p.Query(\"div\")\n\trequire.NoError(t, err)\n\n\t_, err = element.BoundingBox()\n\trequire.ErrorIs(t, err, common.ErrElementNotVisible)\n}\n\n// This test is the same as TestElementHandleBoundingBoxInvisibleElement, but\n// uses the mapper to test the behaviour to ensure we get a null result when\n// an element is not visible.\nfunc TestElementHandleBoundingBoxInvisibleElementWithMapper(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\n\tgot := tb.vu.RunPromise(t, `\n\t\tconst p = await browser.newPage();\n\n\t\tawait p.setContent('<div style=\"display:none\">hello</div>');\n\n\t\tconst element = await p.$(\"div\");\n\n\t\treturn await element.boundingBox();\n\t`,\n\t)\n\tassert.Equal(t, sobek.Null(), got.Result())\n}\n\nfunc TestElementHandleBoundingBoxSVG(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(`\n\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"500\" height=\"500\">\n\t\t\t<rect id=\"theRect\" x=\"30\" y=\"50\" width=\"200\" height=\"300\"></rect>\n\t\t</svg>\n\t`, nil)\n\trequire.NoError(t, err)\n\n\telement, err := p.Query(\"#therect\")\n\trequire.NoError(t, err)\n\n\tbbox, err := element.BoundingBox()\n\trequire.NoError(t, err)\n\n\tpageFn := `e => {\n        const rect = e.getBoundingClientRect();\n        return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };\n    }`\n\tbox, err := p.Evaluate(pageFn, element)\n\trequire.NoError(t, err)\n\trect := convert(t, box, &common.Rect{})\n\trequire.EqualValues(t, bbox, rect)\n}\n\nfunc TestElementHandleClick(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(htmlInputButton, nil)\n\trequire.NoError(t, err)\n\n\tbutton, err := p.Query(\"button\")\n\trequire.NoError(t, err)\n\n\topts := common.NewElementHandleClickOptions(button.Timeout())\n\t// FIX: this is just a workaround because navigation is never triggered\n\t// and we'd be waiting for it to happen otherwise!\n\topts.NoWaitAfter = true\n\terr = button.Click(opts)\n\trequire.NoError(t, err)\n\n\tres, err := p.Evaluate(`() => window['result']`)\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"Clicked\", res)\n}\n\nfunc TestElementHandleClickWithNodeRemoved(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(htmlInputButton, nil)\n\trequire.NoError(t, err)\n\n\t// Remove all nodes\n\t_, err = p.Evaluate(`() => delete window['Node']`)\n\trequire.NoError(t, err)\n\n\tbutton, err := p.Query(\"button\")\n\trequire.NoError(t, err)\n\n\topts := common.NewElementHandleClickOptions(button.Timeout())\n\t// FIX: this is just a workaround because navigation is never triggered\n\t// and we'd be waiting for it to happen otherwise!\n\topts.NoWaitAfter = true\n\terr = button.Click(opts)\n\trequire.NoError(t, err)\n\n\tres, err := p.Evaluate(`() => window['result']`)\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"Clicked\", res)\n}\n\nfunc TestElementHandleClickWithDetachedNode(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(htmlInputButton, nil)\n\trequire.NoError(t, err)\n\tbutton, err := p.Query(\"button\")\n\trequire.NoError(t, err)\n\n\t// Detach node to panic when clicked\n\t_, err = p.Evaluate(`button => button.remove()`, button)\n\trequire.NoError(t, err)\n\n\topts := common.NewElementHandleClickOptions(button.Timeout())\n\t// FIX: this is just a workaround because navigation is never triggered\n\t// and we'd be waiting for it to happen otherwise!\n\topts.NoWaitAfter = true\n\terr = button.Click(opts)\n\tassert.ErrorContains(\n\t\tt, err,\n\t\t\"element is not attached to the DOM\",\n\t\t\"expected click to result in correct error to panic\",\n\t)\n}\n\nfunc TestElementHandleClickConcealedLink(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // wrong result\n\t}\n\n\tconst (\n\t\twantBefore = \"🙈\"\n\t\twantAfter  = \"🐵\"\n\t)\n\n\ttb := newTestBrowser(t, withFileServer())\n\n\tbcopts := common.DefaultBrowserContextOptions()\n\tbcopts.Viewport = common.Viewport{\n\t\tWidth:  500,\n\t\tHeight: 240,\n\t}\n\tbc, err := tb.NewContext(bcopts)\n\trequire.NoError(t, err)\n\n\tp, err := bc.NewPage()\n\trequire.NoError(t, err)\n\n\tclickResult := func() (any, error) {\n\t\tconst cmd = `\n\t\t\t() => window.clickResult\n\t\t`\n\t\treturn p.Evaluate(cmd)\n\t}\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tresp, err := p.Goto(\n\t\ttb.staticURL(\"/concealed_link.html\"),\n\t\topts,\n\t)\n\trequire.NotNil(t, resp)\n\trequire.NoError(t, err)\n\tresult, err := clickResult()\n\trequire.NoError(t, err)\n\trequire.Equal(t, wantBefore, result)\n\n\terr = p.Click(\"#concealed\", common.NewFrameClickOptions(p.Timeout()))\n\trequire.NoError(t, err)\n\tresult, err = clickResult()\n\trequire.NoError(t, err)\n\trequire.Equal(t, wantAfter, result)\n}\n\nfunc TestElementHandleNonClickable(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\n\tbctx, err := tb.NewContext(nil)\n\trequire.NoError(t, err)\n\tp, err := bctx.NewPage()\n\trequire.NoError(t, err)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tresp, err := p.Goto(\n\t\ttb.staticURL(\"/non_clickable.html\"),\n\t\topts,\n\t)\n\trequire.NotNil(t, resp)\n\trequire.NoError(t, err)\n\n\terr = p.Click(\"#non-clickable\", common.NewFrameClickOptions(p.Timeout()))\n\trequire.Errorf(t, err, \"element should not be clickable\")\n}\n\nfunc TestElementHandleGetAttribute(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\" href=\"null\">Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tel, err := p.Query(\"#el\")\n\trequire.NoError(t, err)\n\n\tgot, ok, err := el.GetAttribute(\"href\")\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"null\", got)\n}\n\nfunc TestElementHandleGetAttributeMissing(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\">Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tel, err := p.Query(\"#el\")\n\trequire.NoError(t, err)\n\n\tgot, ok, err := el.GetAttribute(\"missing\")\n\trequire.NoError(t, err)\n\trequire.False(t, ok)\n\tassert.Equal(t, \"\", got)\n}\n\nfunc TestElementHandleGetAttributeEmpty(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\" empty>Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tel, err := p.Query(\"#el\")\n\trequire.NoError(t, err)\n\n\tgot, ok, err := el.GetAttribute(\"empty\")\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"\", got)\n}\n\nfunc TestElementHandleInputValue(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\terr := p.SetContent(`\n\t\t<input value=\"hello1\">\n\t\t<select><option value=\"hello2\" selected></option></select>\n\t\t<textarea>hello3</textarea>\n    `, nil)\n\trequire.NoError(t, err)\n\n\telement, err := p.Query(\"input\")\n\trequire.NoError(t, err)\n\n\tvalue, err := element.InputValue(common.NewElementHandleBaseOptions(element.Timeout()))\n\trequire.NoError(t, err)\n\trequire.NoError(t, element.Dispose())\n\tassert.Equal(t, \"hello1\", value, `expected input value \"hello1\", got %q`, value)\n\n\telement, err = p.Query(\"select\")\n\trequire.NoError(t, err)\n\n\tvalue, err = element.InputValue(common.NewElementHandleBaseOptions(element.Timeout()))\n\trequire.NoError(t, err)\n\trequire.NoError(t, element.Dispose())\n\tassert.Equal(t, \"hello2\", value, `expected input value \"hello2\", got %q`, value)\n\n\telement, err = p.Query(\"textarea\")\n\trequire.NoError(t, err)\n\n\tvalue, err = element.InputValue(common.NewElementHandleBaseOptions(element.Timeout()))\n\trequire.NoError(t, err)\n\trequire.NoError(t, element.Dispose())\n\tassert.Equal(t, \"hello3\", value, `expected input value \"hello3\", got %q`, value)\n}\n\nfunc TestElementHandleIsChecked(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\terr := p.SetContent(`<input type=\"checkbox\" checked>`, nil)\n\trequire.NoError(t, err)\n\telement, err := p.Query(\"input\")\n\trequire.NoError(t, err)\n\n\tchecked, err := element.IsChecked()\n\trequire.NoError(t, err)\n\tassert.True(t, checked, \"expected checkbox to be checked\")\n\trequire.NoError(t, element.Dispose())\n\n\terr = p.SetContent(`<input type=\"checkbox\">`, nil)\n\trequire.NoError(t, err)\n\telement, err = p.Query(\"input\")\n\trequire.NoError(t, err)\n\tchecked, err = element.IsChecked()\n\trequire.NoError(t, err)\n\tassert.False(t, checked, \"expected checkbox to be unchecked\")\n\trequire.NoError(t, element.Dispose())\n}\n\n//nolint:tparallel // it doesn't make sense to run the subtests in parallel with separate browsers\nfunc TestElementHandleQueryAll(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\twantLiLen = 3\n\t\tquery     = \"li.ali\"\n\t)\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`\n\t\t<ul id=\"aul\">\n\t\t\t<li class=\"ali\">1</li>\n\t\t\t<li class=\"ali\">2</li>\n\t\t\t<li class=\"ali\">3</li>\n\t\t</ul>\n  \t`, nil)\n\trequire.NoError(t, err)\n\n\tassertTextContent := func(t *testing.T, e *common.ElementHandle, wantContent string) {\n\t\tt.Helper()\n\t\ttext, ok, err := e.TextContent()\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, wantContent, text)\n\t}\n\n\tt.Run(\"element_handle\", func(t *testing.T) { //nolint:paralleltest\n\t\tel, err := p.Query(\"#aul\")\n\t\trequire.NoError(t, err)\n\n\t\tels, err := el.QueryAll(query)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, els, wantLiLen)\n\t\tassertTextContent(t, els[0], \"1\")\n\t\tassertTextContent(t, els[1], \"2\")\n\t\tassertTextContent(t, els[2], \"3\")\n\t})\n\tt.Run(\"page\", func(t *testing.T) { //nolint:paralleltest\n\t\tels, err := p.QueryAll(query)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, els, wantLiLen)\n\t\tassertTextContent(t, els[0], \"1\")\n\t\tassertTextContent(t, els[1], \"2\")\n\t\tassertTextContent(t, els[2], \"3\")\n\t})\n\tt.Run(\"frame\", func(t *testing.T) { //nolint:paralleltest\n\t\tels, err := p.MainFrame().QueryAll(query)\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, els, wantLiLen)\n\t\tassertTextContent(t, els[0], \"1\")\n\t\tassertTextContent(t, els[1], \"2\")\n\t\tassertTextContent(t, els[2], \"3\")\n\t})\n}\n\ntype mockPersister struct{}\n\nfunc (m *mockPersister) Persist(_ context.Context, _ string, _ io.Reader) (err error) {\n\treturn nil\n}\n\nfunc TestElementHandleScreenshot(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\ts := &common.Size{Width: 800, Height: 600}\n\terr := p.SetViewportSize(s)\n\trequire.NoError(t, err)\n\n\t_, err = p.Evaluate(`\n\t\t() => {\n\t\t\tdocument.body.style.margin = '0';\n\t\t\tdocument.body.style.padding = '0';\n\t\t\tdocument.documentElement.style.margin = '0';\n\t\t\tdocument.documentElement.style.padding = '0';\n\n\t\t\tconst div = document.createElement('div');\n\t\t\tdiv.style.marginTop = '400px';\n\t\t\tdiv.style.marginLeft = '100px';\n\t\t\tdiv.style.width = '100px';\n\t\t\tdiv.style.height = '100px';\n\t\t\tdiv.style.background = 'red';\n\n\t\t\tdocument.body.appendChild(div);\n\t\t}\n\t`)\n\trequire.NoError(t, err)\n\n\telem, err := p.Query(\"div\")\n\trequire.NoError(t, err)\n\n\tbuf, err := elem.Screenshot(\n\t\tcommon.NewElementHandleScreenshotOptions(elem.Timeout()),\n\t\t&mockPersister{},\n\t)\n\trequire.NoError(t, err)\n\n\treader := bytes.NewReader(buf)\n\timg, err := png.Decode(reader)\n\tassert.Nil(t, err)\n\n\tassert.Equal(t, 100, img.Bounds().Max.X, \"screenshot width is not 100px as expected, but %dpx\", img.Bounds().Max.X)\n\tassert.Equal(t, 100, img.Bounds().Max.Y, \"screenshot height is not 100px as expected, but %dpx\", img.Bounds().Max.Y)\n\n\tr, g, b, _ := img.At(0, 0).RGBA()\n\tassert.Equal(t, uint32(255), r>>8) // each color component has been scaled by alpha (<<8)\n\tassert.Equal(t, uint32(0), g)\n\tassert.Equal(t, uint32(0), b)\n\tr, g, b, _ = img.At(99, 99).RGBA()\n\tassert.Equal(t, uint32(255), r>>8) // each color component has been scaled by alpha (<<8)\n\tassert.Equal(t, uint32(0), g)\n\tassert.Equal(t, uint32(0), b)\n}\n\nfunc TestElementHandleWaitForSelector(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\terr := p.SetContent(`<div class=\"root\"></div>`, nil)\n\trequire.NoError(t, err)\n\n\troot, err := p.Query(\".root\")\n\trequire.NoError(t, err)\n\n\t_, err = p.Evaluate(`\n        () => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tconst div = document.createElement('div');\n\t\t\t\tdiv.className = 'element-to-appear';\n\t\t\t\tdiv.appendChild(document.createTextNode(\"Hello World\"));\n\t\t\t\troot = document.querySelector('.root');\n\t\t\t\troot.appendChild(div);\n\t\t\t}, 100);\n\t\t}\n\t`)\n\trequire.NoError(t, err)\n\n\telement, err := root.WaitForSelector(\".element-to-appear\", common.NewFrameWaitForSelectorOptions(time.Second))\n\trequire.NoError(t, err)\n\trequire.NotNil(t, element, \"expected element to have been found after wait\")\n\n\trequire.NoError(t, element.Dispose())\n}\n\nfunc TestElementHandlePress(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(`<input>`, nil)\n\trequire.NoError(t, err)\n\n\tel, err := p.Query(\"input\")\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, el.Press(\"Shift+KeyA\", common.NewElementHandlePressOptions(el.Timeout())))\n\trequire.NoError(t, el.Press(\"KeyB\", common.NewElementHandlePressOptions(el.Timeout())))\n\trequire.NoError(t, el.Press(\"Shift+KeyC\", common.NewElementHandlePressOptions(el.Timeout())))\n\n\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"AbC\", v)\n}\n\nfunc TestElementHandleQuery(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<div id=\"foo\">hello</div>`, nil)\n\trequire.NoError(t, err)\n\n\telement, err := p.Query(\"bar\")\n\n\trequire.NoError(t, err)\n\trequire.Nil(t, element)\n}\n\nfunc TestElementHandleTextContent(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<div id=\"el\">Something</div>`, nil)\n\trequire.NoError(t, err)\n\n\tel, err := p.Query(\"#el\")\n\trequire.NoError(t, err)\n\n\tgot, ok, err := el.TextContent()\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"Something\", got)\n}\n\nfunc TestElementHandleTextContentMissing(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\t// document never has text content.\n\tjs, err := p.EvaluateHandle(`() => document`)\n\trequire.NoError(t, err)\n\t_, ok, err := js.AsElement().TextContent()\n\trequire.NoError(t, err)\n\trequire.False(t, ok)\n}\n\nfunc TestElementHandleTextContentEmpty(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<div id=\"el\"/>`, nil)\n\trequire.NoError(t, err)\n\n\tel, err := p.Query(\"#el\")\n\trequire.NoError(t, err)\n\n\tgot, ok, err := el.TextContent()\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\trequire.Empty(t, got)\n}\n\nfunc TestElementHandleSetChecked(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\terr := p.SetContent(`<input type=\"checkbox\">`, nil)\n\trequire.NoError(t, err)\n\telement, err := p.Query(\"input\")\n\trequire.NoError(t, err)\n\tchecked, err := element.IsChecked()\n\trequire.NoError(t, err)\n\trequire.False(t, checked, \"expected checkbox to be unchecked\")\n\n\terr = element.SetChecked(true, common.NewElementHandleSetCheckedOptions(element.Timeout()))\n\trequire.NoError(t, err)\n\tchecked, err = element.IsChecked()\n\trequire.NoError(t, err)\n\tassert.True(t, checked, \"expected checkbox to be checked\")\n\n\terr = element.SetChecked(false, common.NewElementHandleSetCheckedOptions(element.Timeout()))\n\trequire.NoError(t, err)\n\tchecked, err = element.IsChecked()\n\trequire.NoError(t, err)\n\tassert.False(t, checked, \"expected checkbox to be unchecked\")\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/frame_manager_test.go",
    "content": "// practically none of this work on windows\n//go:build !windows\n\npackage tests\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc TestWaitForFrameNavigationWithinDocument(t *testing.T) {\n\tt.Parallel()\n\n\tconst timeout = 5 * time.Second\n\n\ttestCases := []struct {\n\t\tname, selector string\n\t}{\n\t\t{name: \"history\", selector: \"a#nav-history\"},\n\t\t{name: \"anchor\", selector: \"a#nav-anchor\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\t\tTimeout:   timeout,\n\t\t\t}\n\t\t\tresp, err := p.Goto(tb.staticURL(\"/nav_in_doc.html\"), opts)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, resp)\n\n\t\t\twaitForNav := func() error {\n\t\t\t\topts := &common.FrameWaitForNavigationOptions{Timeout: timeout}\n\t\t\t\t_, err := p.WaitForNavigation(opts, nil)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tclick := func() error {\n\t\t\t\treturn p.Click(tc.selector, common.NewFrameClickOptions(p.Timeout()))\n\t\t\t}\n\t\t\tctx, cancel := context.WithTimeout(tb.ctx, timeout)\n\t\t\tdefer cancel()\n\t\t\terr = tb.run(ctx, waitForNav, click)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestWaitForFrameNavigation(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\tp := tb.NewPage(nil)\n\n\ttb.withHandler(\"/first\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t_, err := fmt.Fprintf(w, `\n\t\t<html>\n\t\t\t<head>\n\t\t\t\t<title>First page</title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<a href=\"/second\">click me</a>\n\t\t\t</body>\n\t\t</html>\n\t\t`)\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/second\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t_, err := fmt.Fprintf(w, `\n\t\t<html>\n\t\t\t<head>\n\t\t\t\t<title>Second page</title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<a href=\"/first\">click me</a>\n\t\t\t</body>\n\t\t</html>\n\t\t`)\n\t\trequire.NoError(t, err)\n\t})\n\n\topts := &common.FrameGotoOptions{\n\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\tTimeout:   common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(tb.url(\"/first\"), opts)\n\trequire.NoError(t, err)\n\n\twaitForNav := func() error {\n\t\topts := &common.FrameWaitForNavigationOptions{\n\t\t\tTimeout: 5000 * time.Millisecond,\n\t\t}\n\t\t_, err := p.WaitForNavigation(opts, nil)\n\t\treturn err\n\t}\n\tclick := func() error {\n\t\treturn p.Click(`a`, common.NewFrameClickOptions(p.Timeout()))\n\t}\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\terr = tb.run(ctx, waitForNav, click)\n\trequire.NoError(t, err)\n\n\ttitle, err := p.Title()\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"Second page\", title)\n}\n\nfunc TestFrameManagerRequestStartedWithRoutes(t *testing.T) {\n\tt.Parallel()\n\n\tfakeRegExMatcher := func(pattern, url string) (bool, error) {\n\t\tmatched, err := regexp.MatchString(fmt.Sprintf(\"http://[^/]*%s\", pattern), url)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error matching regex: %w\", err)\n\t\t}\n\n\t\treturn matched, nil\n\t}\n\n\ttype callsCount struct {\n\t\trouteHandler int\n\t\tfirstApi     int\n\t\tsecondApi    int\n\t}\n\ttests := []struct {\n\t\tname         string\n\t\troutePath    string\n\t\trouteHandler func(*common.Route)\n\t\tcallsCount   callsCount\n\t}{\n\t\t{\n\t\t\tname: \"request_without_routes\",\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 0,\n\t\t\t\tfirstApi:     1,\n\t\t\t\tsecondApi:    1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"continue_request_with_matching_string_route\",\n\t\t\troutePath: \"/data/first\",\n\t\t\trouteHandler: func(route *common.Route) {\n\t\t\t\terr := route.Continue(common.ContinueOptions{})\n\t\t\t\tassert.NoError(t, err)\n\t\t\t},\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 1,\n\t\t\t\tfirstApi:     1,\n\t\t\t\tsecondApi:    1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"continue_request_with_non_matching_string_route\",\n\t\t\troutePath: \"/data/third\",\n\t\t\trouteHandler: func(route *common.Route) {\n\t\t\t\terr := route.Continue(common.ContinueOptions{})\n\t\t\t\tassert.NoError(t, err)\n\t\t\t},\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 0,\n\t\t\t\tfirstApi:     1,\n\t\t\t\tsecondApi:    1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"continue_request_with_multiple_matching_regex_route\",\n\t\t\troutePath: \"/data/.*\",\n\t\t\trouteHandler: func(route *common.Route) {\n\t\t\t\terr := route.Continue(common.ContinueOptions{})\n\t\t\t\tassert.NoError(t, err)\n\t\t\t},\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 2,\n\t\t\t\tfirstApi:     1,\n\t\t\t\tsecondApi:    1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"continue_request_with_opts\",\n\t\t\troutePath: \"/data/first\",\n\t\t\trouteHandler: func(route *common.Route) {\n\t\t\t\tnewURL := strings.Replace(route.Request().URL(), \"/data/first\", \"/data/second\", 1)\n\t\t\t\terr := route.Continue(common.ContinueOptions{\n\t\t\t\t\tURL: newURL,\n\t\t\t\t})\n\t\t\t\tassert.NoError(t, err)\n\t\t\t},\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 1,\n\t\t\t\tfirstApi:     0,\n\t\t\t\tsecondApi:    2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"abort_first_request\",\n\t\t\troutePath: \"/data/first\",\n\t\t\trouteHandler: func(route *common.Route) {\n\t\t\t\terr := route.Abort(\"failed\")\n\t\t\t\tassert.NoError(t, err)\n\t\t\t},\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 1,\n\t\t\t\tfirstApi:     0,\n\t\t\t\tsecondApi:    0, // Second API call is not made because the first throws an error\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"abort_second_request\",\n\t\t\troutePath: \"/data/second\",\n\t\t\trouteHandler: func(route *common.Route) {\n\t\t\t\terr := route.Abort(\"failed\")\n\t\t\t\tassert.NoError(t, err)\n\t\t\t},\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 1,\n\t\t\t\tfirstApi:     1,\n\t\t\t\tsecondApi:    0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"fulfill_request\",\n\t\t\troutePath: \"/data/first\",\n\t\t\trouteHandler: func(route *common.Route) {\n\t\t\t\terr := route.Fulfill(common.FulfillOptions{\n\t\t\t\t\tBody:        []byte(`{\"data\": \"Fulfilled data\"}`),\n\t\t\t\t\tContentType: \"application/json\",\n\t\t\t\t\tHeaders: []common.HTTPHeader{\n\t\t\t\t\t\t{Name: \"Access-Control-Allow-Origin\", Value: \"*\"},\n\t\t\t\t\t},\n\t\t\t\t\tStatus: 200,\n\t\t\t\t})\n\t\t\t\tassert.NoError(t, err)\n\t\t\t},\n\t\t\tcallsCount: callsCount{\n\t\t\t\trouteHandler: 1,\n\t\t\t\tfirstApi:     0,\n\t\t\t\tsecondApi:    1,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\t// Track number of calls in each function\n\t\t\tcalls := callsCount{\n\t\t\t\trouteHandler: 0,\n\t\t\t\tfirstApi:     0,\n\t\t\t\tsecondApi:    0,\n\t\t\t}\n\n\t\t\t// Set up handlers for test resources\n\t\t\ttb.withHandler(\"/test\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\t\t\t_, err := fmt.Fprintf(w, `\n\t\t\t\t<html>\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<title>Test Page</title>\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<h1>Test</h1>\n\t\t\t\t\t\t<script type=\"module\">\n\t\t\t\t\t\t\tawait fetchData();\n\t\t\t\t\t\t\tasync function fetchData() {\n\t\t\t\t\t\t\t\tawait fetch('/data/first');\n\t\t\t\t\t\t\t\tawait fetch('/data/second');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>\n\t\t\t\t`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\n\t\t\ttb.withHandler(\"/data/first\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t\t_, err := fmt.Fprint(w, `{\"data\": \"First data\"}`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tcalls.firstApi++\n\t\t\t})\n\n\t\t\ttb.withHandler(\"/data/second\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t\t_, err := fmt.Fprint(w, `{\"data\": \"Second data\"}`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tcalls.secondApi++\n\t\t\t})\n\n\t\t\t// Set up route if needed\n\t\t\tif tt.routeHandler != nil {\n\t\t\t\trouteHandler := func(route *common.Route) error {\n\t\t\t\t\tcalls.routeHandler++\n\t\t\t\t\ttt.routeHandler(route)\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\terr := p.Route(tt.routePath, routeHandler, fakeRegExMatcher)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\t// Navigate to trigger requests - this will internally call requestStarted\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\t\tTimeout:   common.DefaultTimeout,\n\t\t\t}\n\n\t\t\t_, err := p.Goto(tb.url(\"/test\"), opts)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tt.callsCount.routeHandler, calls.routeHandler)\n\t\t\tassert.Equal(t, tt.callsCount.firstApi, calls.firstApi)\n\t\t\tassert.Equal(t, tt.callsCount.secondApi, calls.secondApi)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/frame_test.go",
    "content": "// practically none of this work on windows\n//go:build !windows\n\npackage tests\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n)\n\nfunc TestFramePress(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(`<input id=\"text1\">`, nil)\n\trequire.NoError(t, err)\n\n\tf := p.Frames()[0]\n\n\topts := common.NewFramePressOptions(f.Timeout())\n\trequire.NoError(t, f.Press(\"#text1\", \"Shift+KeyA\", opts))\n\trequire.NoError(t, f.Press(\"#text1\", \"KeyB\", opts))\n\trequire.NoError(t, f.Press(\"#text1\", \"Shift+KeyC\", opts))\n\n\tinputValue, err := f.InputValue(\"#text1\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"AbC\", inputValue)\n}\n\nfunc TestFrameDismissDialogBox(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tt := range []string{\n\t\t\"alert\",\n\t\t\"confirm\",\n\t\t\"prompt\",\n\t\t\"beforeunload\",\n\t} {\n\t\tt.Run(tt, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar (\n\t\t\t\ttb = newTestBrowser(t, withFileServer())\n\t\t\t\tp  = tb.NewPage(nil)\n\t\t\t)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\t\tTimeout:   common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := p.Goto(tb.staticURL(\"dialog.html?dialogType=\"+tt), opts)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif tt == \"beforeunload\" {\n\t\t\t\terr = p.Click(\"#clickHere\", common.NewFrameClickOptions(p.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\n\t\t\tresult, ok, err := p.TextContent(\"#textField\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.EqualValues(t, tt+\" dismissed\", result)\n\t\t})\n\t}\n}\n\nfunc TestFrameNoPanicWithEmbeddedIFrame(t *testing.T) {\n\tt.Parallel()\n\n\t// We're skipping this when running in headless\n\t// environments since the bug that the test fixes\n\t// only surfaces when in headfull mode.\n\t// Remove this skip once we have headfull mode in\n\t// CI: https://go.k6.io/k6/js/modules/k6/browser/issues/678\n\tif env.IsBrowserHeadless() {\n\t\tt.Skip(\"skipped when in headless mode\")\n\t}\n\n\t// run the browser in headfull mode.\n\ttb := newTestBrowser(\n\t\tt,\n\t\twithFileServer(),\n\t\twithEnvLookup(env.ConstLookup(env.BrowserHeadless, \"0\")),\n\t)\n\n\tp := tb.NewPage(nil)\n\topts := &common.FrameGotoOptions{\n\t\tWaitUntil: common.LifecycleEventDOMContentLoad,\n\t\tTimeout:   common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(tb.staticURL(\"embedded_iframe.html\"), opts)\n\trequire.NoError(t, err)\n\n\tresult, ok, err := p.TextContent(\"#doneDiv\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.EqualValues(t, \"Done!\", result)\n}\n\n// Without the fix in https://go.k6.io/k6/js/modules/k6/browser/pull/942\n// this test would hang on the \"sign in\" link click.\nfunc TestFrameNoPanicNavigateAndClickOnPageWithIFrames(t *testing.T) {\n\tt.Parallel()\n\n\t// We're skipping this when running in headless\n\t// environments since the bug that the test fixes\n\t// only surfaces when in headfull mode.\n\t// Remove this skip once we have headfull mode in\n\t// CI: https://go.k6.io/k6/js/modules/k6/browser/issues/678\n\tif env.IsBrowserHeadless() {\n\t\tt.Skip(\"skipped when in headless mode\")\n\t}\n\n\ttb := newTestBrowser(\n\t\tt,\n\t\twithFileServer(),\n\t\twithEnvLookup(env.ConstLookup(env.BrowserHeadless, \"0\")),\n\t)\n\tp := tb.NewPage(nil)\n\ttb.withHandler(\"/iframeSignIn\", func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, tb.staticURL(\"iframe_signin.html\"), http.StatusMovedPermanently)\n\t})\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(\n\t\ttb.staticURL(\"iframe_home.html\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithTimeout(tb.context(), 5*time.Second)\n\tdefer cancel()\n\n\terr = tb.run(\n\t\tctx,\n\t\tfunc() error { return p.Click(`a[href=\"/iframeSignIn\"]`, common.NewFrameClickOptions(p.Timeout())) },\n\t\tfunc() error {\n\t\t\t_, err := p.WaitForNavigation(\n\t\t\t\tcommon.NewFrameWaitForNavigationOptions(p.Timeout()), nil,\n\t\t\t)\n\t\t\treturn err\n\t\t},\n\t)\n\trequire.NoError(t, err)\n\n\tresult, ok, err := p.TextContent(\"#doneDiv\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.EqualValues(t, \"Sign In Page\", result)\n}\n\nfunc TestFrameTitle(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(\n\t\t`<html><head><title>Some title</title></head></html>`,\n\t\tnil,\n\t)\n\trequire.NoError(t, err)\n\n\ttitle, err := p.MainFrame().Title()\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"Some title\", title)\n}\n\nfunc TestFrameGetAttribute(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\" href=\"null\">Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tgot, ok, err := p.Frames()[0].GetAttribute(\"#el\", \"href\", common.NewFrameBaseOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"null\", got)\n}\n\nfunc TestFrameGetAttributeMissing(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\">Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tgot, ok, err := p.Frames()[0].GetAttribute(\"#el\", \"missing\", common.NewFrameBaseOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.False(t, ok)\n\tassert.Equal(t, \"\", got)\n}\n\nfunc TestFrameGetAttributeEmpty(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\" empty>Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tgot, ok, err := p.Frames()[0].GetAttribute(\"#el\", \"empty\", common.NewFrameBaseOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"\", got)\n}\n\nfunc TestFrameSetChecked(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<input id=\"el\" type=\"checkbox\">`, nil)\n\trequire.NoError(t, err)\n\n\tisopts := common.NewFrameIsCheckedOptions(p.MainFrame().Timeout())\n\tchecked, err := p.Frames()[0].IsChecked(\"#el\", isopts)\n\trequire.NoError(t, err)\n\tassert.False(t, checked)\n\n\terr = p.Frames()[0].SetChecked(\"#el\", true, common.NewFrameCheckOptions(p.Frames()[0].Timeout()))\n\trequire.NoError(t, err)\n\tisopts = common.NewFrameIsCheckedOptions(p.MainFrame().Timeout())\n\tchecked, err = p.Frames()[0].IsChecked(\"#el\", isopts)\n\trequire.NoError(t, err)\n\tassert.True(t, checked)\n\n\terr = p.Frames()[0].SetChecked(\"#el\", false, common.NewFrameCheckOptions(p.Frames()[0].Timeout()))\n\trequire.NoError(t, err)\n\tisopts = common.NewFrameIsCheckedOptions(p.MainFrame().Timeout())\n\tchecked, err = p.Frames()[0].IsChecked(\"#el\", isopts)\n\trequire.NoError(t, err)\n\tassert.False(t, checked)\n}\n\nfunc TestFrameWaitForURLSuccess(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tcode     string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname:     \"when_already_at_matching_url\",\n\t\t\tcode:     `await frame.waitForURL(/.*waitfornavigation_test\\.html$/);`,\n\t\t\texpected: []string{\"waitfornavigation_test.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"exact_url_match\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tframe.waitForURL(page1URL),\n\t\t\t\t\tframe.locator('#page1').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page1.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"regex_pattern_match\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tframe.waitForURL(/.*2\\.html$/),\n\t\t\t\t\tframe.locator('#page2').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page2.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"empty_pattern_match\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tframe.waitForURL(''),\n\t\t\t\t\tframe.locator('#page2').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page2.html\", \"waitfornavigation_test.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"waitUntil_domcontentloaded\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tframe.waitForURL(/.*page1\\.html$/, { waitUntil: 'domcontentloaded' }),\n\t\t\t\t\tframe.locator('#page1').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page1.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"already_at_url_with_regex_pattern\",\n\t\t\tcode: `\n\t\t\t\tawait frame.waitForURL(/.*\\/waitfornavigation_test\\.html$/);\n\t\t\t`,\n\t\t\texpected: []string{\"waitfornavigation_test.html\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\n\t\t\ttb.vu.SetVar(t, \"frame\", &sobek.Object{})\n\t\t\ttb.vu.SetVar(t, \"testURL\", tb.staticURL(\"waitfornavigation_test.html\"))\n\t\t\ttb.vu.SetVar(t, \"page1URL\", tb.staticURL(\"page1.html\"))\n\t\t\t_, err := tb.vu.RunAsync(t, `\n\t\t\t\tconst page = await browser.newPage();\n\t\n\t\t\t\tawait page.setContent('<iframe></iframe>');\n\t\n\t\t\t\tconst iframeElement = await page.$('iframe');\n\t\t\t\tframe = await iframeElement.contentFrame();\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult := tb.vu.RunPromise(t, `\n\t\t\t\tawait frame.goto(testURL);\n\t\t\t\t%s\n\t\t\t\treturn frame.url();\n\t\t\t`, tt.code)\n\t\t\tgot := strings.ReplaceAll(result.Result().String(), tb.staticURL(\"\"), \"\")\n\t\t\tassert.Contains(t, tt.expected, got)\n\t\t})\n\t}\n}\n\nfunc TestFrameWaitForURLFailure(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tcode     string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"timeout_on_mismatched_url\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tframe.waitForURL(/.*nonexistent\\.html$/, { timeout: 500 }),\n\t\t\t\t\tframe.locator('#page1').click()  // This goes to page1.html, not nonexistent.html\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: \"timed out after 500ms\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing_required_argument\",\n\t\t\tcode: `\n\t\t\t\tawait frame.waitForURL();\n\t\t\t`,\n\t\t\texpected: \"missing required argument 'url'\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\n\t\t\ttb.vu.SetVar(t, \"frame\", &sobek.Object{})\n\t\t\ttb.vu.SetVar(t, \"testURL\", tb.staticURL(\"waitfornavigation_test.html\"))\n\t\t\t_, err := tb.vu.RunAsync(t, `\n\t\t\t\tconst page = await browser.newPage();\n\t\n\t\t\t\tawait page.setContent('<iframe></iframe>');\n\t\n\t\t\t\tconst iframeElement = await page.$('iframe');\n\t\t\t\tframe = await iframeElement.contentFrame();\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = tb.vu.RunAsync(t, `\n\t\t\t\tawait frame.goto(testURL);\n\t\t\t\t%s\n\t\t\t`, tt.code)\n\t\t\tassert.ErrorContains(t, err, tt.expected)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/get_by_test.go",
    "content": "// practically none of this work on windows\n//go:build !windows\n\npackage tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nconst (\n\tframeLocatorImpl = \"frameLocator\"\n\tlocatorImpl      = \"locator\"\n\tframeImpl        = \"frame\"\n\tpageImpl         = \"page\"\n\tiframeID         = \"frameB\"\n)\n\nfunc TestGetByRoleSuccess(t *testing.T) {\n\tt.Parallel()\n\n\t// This test all the implicit roles that are valid for the role-based\n\t// selector engine that is in the injected_script.js file. Implicit roles\n\t// are roles that are not explicitly defined in the HTML, but are\n\t// implied by the context of the element.\n\tt.Run(\"implicit\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttests := []struct {\n\t\t\tname         string\n\t\t\trole         string\n\t\t\topts         *common.GetByRoleOptions\n\t\t\texpected     int\n\t\t\texpectedText string\n\t\t}{\n\t\t\t{\n\t\t\t\tname:     \"link\",\n\t\t\t\trole:     \"link\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Link text'`)},\n\t\t\t\texpected: 1, expectedText: \"Link text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"area\",\n\t\t\t\trole:     \"link\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Map area'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"button\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Click'`)},\n\t\t\t\texpected: 1, expectedText: \"Click\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"submit_type\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Submit'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"image_type\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Image Button'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"checkbox_type\",\n\t\t\t\trole:     \"checkbox\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"radio_type\",\n\t\t\t\trole:     \"radio\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"text_type\",\n\t\t\t\trole:     \"textbox\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Text type'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"textarea\",\n\t\t\t\trole:     \"textbox\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Text area'`)},\n\t\t\t\texpected: 1, expectedText: \"Textarea\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"search_type\",\n\t\t\t\trole:     \"searchbox\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"range_type\",\n\t\t\t\trole:     \"slider\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"number_type\",\n\t\t\t\trole:     \"spinbutton\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"progress\",\n\t\t\t\trole:     \"progressbar\",\n\t\t\t\texpected: 1, expectedText: \"Progress\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"output\",\n\t\t\t\trole:     \"status\",\n\t\t\t\texpected: 1, expectedText: \"Output\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"details_summary\",\n\t\t\t\trole:     \"group\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'details'`)},\n\t\t\t\texpected: 1, expectedText: \"SummaryDetails\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"dialog\",\n\t\t\t\trole:     \"dialog\",\n\t\t\t\texpected: 1, expectedText: \"Dialog\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"h1\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Level: toPtr(int64(1))},\n\t\t\t\texpected: 1, expectedText: \"Heading1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"h2\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Level: toPtr(int64(2))},\n\t\t\t\texpected: 1, expectedText: \"Heading2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"h3\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Level: toPtr(int64(3))},\n\t\t\t\texpected: 1, expectedText: \"Heading3\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"h4\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Level: toPtr(int64(4))},\n\t\t\t\texpected: 1, expectedText: \"Heading4\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"h5\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Level: toPtr(int64(5))},\n\t\t\t\texpected: 1, expectedText: \"Heading5\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"h6\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Level: toPtr(int64(6))},\n\t\t\t\texpected: 1, expectedText: \"Heading6\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"hr\",\n\t\t\t\trole:     \"separator\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"img\",\n\t\t\t\trole:     \"img\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Img'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"img_presentation\",\n\t\t\t\trole:     \"presentation\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"ul_list\",\n\t\t\t\trole:     \"list\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'ul'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"ol_list\",\n\t\t\t\trole:     \"list\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'ol'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"ul_li_listitem\",\n\t\t\t\trole:     \"listitem\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'ul-li'`)},\n\t\t\t\texpected: 1, expectedText: \"Item1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"ol_li_listitem\",\n\t\t\t\trole:     \"listitem\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'ol-li'`)},\n\t\t\t\texpected: 1, expectedText: \"Item2\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"dd\",\n\t\t\t\trole:     \"definition\",\n\t\t\t\texpected: 1, expectedText: \"Description\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"dt_dfn\",\n\t\t\t\trole:     \"term\",\n\t\t\t\texpected: 2, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"fieldset_legend\",\n\t\t\t\trole:     \"group\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Legend'`)},\n\t\t\t\texpected: 1, expectedText: \"Legend\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"figure_figcaption\",\n\t\t\t\trole:     \"figure\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Caption'`)},\n\t\t\t\texpected: 1, expectedText: \"Caption\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table\",\n\t\t\t\trole:     \"table\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'table1'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_scope_row\",\n\t\t\t\trole:     \"rowheader\",\n\t\t\t\texpected: 1, expectedText: \"Head Row\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_scope_col\",\n\t\t\t\trole:     \"columnheader\",\n\t\t\t\texpected: 1, expectedText: \"Head Column\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_head_cell\",\n\t\t\t\trole:     \"cell\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'th'`)},\n\t\t\t\texpected: 1, expectedText: \"Head Cell\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_head_gridcell\",\n\t\t\t\trole:     \"gridcell\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'th gridcell'`)},\n\t\t\t\texpected: 1, expectedText: \"Head Gridcell\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_body\",\n\t\t\t\trole:     \"rowgroup\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'tbody'`)},\n\t\t\t\texpected: 1, expectedText: \"Cell\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_foot\",\n\t\t\t\trole:     \"rowgroup\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'tfoot'`)},\n\t\t\t\texpected: 1, expectedText: \"Foot\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_tr\",\n\t\t\t\trole:     \"row\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'tr'`)},\n\t\t\t\texpected: 1, expectedText: \"Row\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_td_cell\",\n\t\t\t\trole:     \"cell\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'td'`)},\n\t\t\t\texpected: 1, expectedText: \"Column Cell\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"table_td_gridcell\",\n\t\t\t\trole:     \"gridcell\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'td gridcell'`)},\n\t\t\t\texpected: 1, expectedText: \"Column Gridcell\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"main\",\n\t\t\t\trole:     \"main\",\n\t\t\t\texpected: 1, expectedText: \"Main\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"nav\",\n\t\t\t\trole:     \"navigation\",\n\t\t\t\texpected: 1, expectedText: \"Nav\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"article\",\n\t\t\t\trole:     \"article\",\n\t\t\t\texpected: 1, expectedText: \"Article\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"aside\",\n\t\t\t\trole:     \"complementary\",\n\t\t\t\texpected: 1, expectedText: \"Aside\",\n\t\t\t},\n\t\t\t// Only works when outside the <section> element.\n\t\t\t{\n\t\t\t\tname:     \"header\",\n\t\t\t\trole:     \"banner\",\n\t\t\t\texpected: 1, expectedText: \"Header\",\n\t\t\t},\n\t\t\t// Only works when outside the <section> element.\n\t\t\t{\n\t\t\t\tname:     \"footer\",\n\t\t\t\trole:     \"contentinfo\",\n\t\t\t\texpected: 1, expectedText: \"Footer\",\n\t\t\t},\n\t\t\t// Only works with aria labels.\n\t\t\t{\n\t\t\t\tname:     \"form\",\n\t\t\t\trole:     \"form\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'form'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t// Only works with aria labels.\n\t\t\t{\n\t\t\t\tname:     \"section\",\n\t\t\t\trole:     \"region\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Region Section'`)},\n\t\t\t\texpected: 1, expectedText: \"Region content\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"blockquote\",\n\t\t\t\trole:     \"blockquote\",\n\t\t\t\texpected: 1, expectedText: \"Blockquote text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"caption\",\n\t\t\t\trole:     \"caption\",\n\t\t\t\texpected: 1, expectedText: \"Table Caption\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"code\",\n\t\t\t\trole:     \"code\",\n\t\t\t\texpected: 1, expectedText: \"Code sample\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"del\",\n\t\t\t\trole:     \"deletion\",\n\t\t\t\texpected: 1, expectedText: \"Deleted text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"em\",\n\t\t\t\trole:     \"emphasis\",\n\t\t\t\texpected: 1, expectedText: \"Emphasized text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"ins\",\n\t\t\t\trole:     \"insertion\",\n\t\t\t\texpected: 1, expectedText: \"Inserted text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"mark\",\n\t\t\t\trole:     \"mark\",\n\t\t\t\texpected: 1, expectedText: \"Marked text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"math\",\n\t\t\t\trole:     \"math\",\n\t\t\t\texpected: 1, expectedText: \"x=1\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"menu\",\n\t\t\t\trole:     \"list\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'menu'`)},\n\t\t\t\texpected: 1, expectedText: \"Menu item\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"meter\",\n\t\t\t\trole:     \"meter\",\n\t\t\t\texpected: 1, expectedText: \"50%\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"p\",\n\t\t\t\trole:     \"paragraph\",\n\t\t\t\texpected: 1, expectedText: \"Paragraph text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"strong\",\n\t\t\t\trole:     \"strong\",\n\t\t\t\texpected: 1, expectedText: \"Strong text\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"sub\",\n\t\t\t\trole:     \"subscript\",\n\t\t\t\texpected: 1, expectedText: \"Subscript\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"sup\",\n\t\t\t\trole:     \"superscript\",\n\t\t\t\texpected: 1, expectedText: \"Superscript\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"svg\",\n\t\t\t\trole:     \"img\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'svg'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"time\",\n\t\t\t\trole:     \"time\",\n\t\t\t\texpected: 1, expectedText: \"June 9, 2025\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"select\",\n\t\t\t\trole:     \"combobox\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'select'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"select_multiple\",\n\t\t\t\trole:     \"listbox\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'select multiple'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"datalist\",\n\t\t\t\trole:     \"listbox\",\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t// TODO: This is not working, not even in Playwright.\n\t\t\t// {\n\t\t\t// \tname:     \"optgroup\",\n\t\t\t// \trole:     \"group\",\n\t\t\t// \topts:     &common.GetByRoleOptions{Name: toPtr(`'optgroup'`)},\n\t\t\t// \texpected: 1, expectedText: \"\",\n\t\t\t// },\n\t\t}\n\t\tfor _, tt := range tests {\n\t\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\t\tstaticURL := tb.staticURL(\"get_by_role_implicit.html\")\n\t\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\t\tp := tb.NewPage(nil)\n\n\t\t\t\tgetByRoleImplementations := getByImplementationsOf[interface {\n\t\t\t\t\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\t\t\t\t}](p)\n\n\t\t\t\tfor implName, impl := range getByRoleImplementations {\n\t\t\t\t\tt.Run(implName, func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tl := impl.GetByRole(tt.role, tt.opts)\n\t\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\n\t\t\t\t\t\tif tt.expectedText != \"\" {\n\t\t\t\t\t\t\ttext, _, err := l.TextContent(common.NewFrameTextContentOptions(l.Timeout()))\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\trequire.Equal(t, tt.expectedText, text)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n\n\t// This test all the explicit roles that are valid for the role-based\n\t// selector engine that is in the injected_script.js file. Explicit roles\n\t// are roles that are explicitly defined in the HTML using the correct\n\t// role attribute.\n\tt.Run(\"explicit\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttests := []struct {\n\t\t\trole         string\n\t\t\texpected     int\n\t\t\texpectedText string\n\t\t}{\n\t\t\t{role: \"alert\", expected: 1, expectedText: \"Alert\"},\n\t\t\t{role: \"alertdialog\", expected: 1, expectedText: \"Alert Dialog\"},\n\t\t\t{role: \"application\", expected: 1, expectedText: \"Application\"},\n\t\t\t{role: \"article\", expected: 1, expectedText: \"Article\"},\n\t\t\t{role: \"banner\", expected: 1, expectedText: \"Banner\"},\n\t\t\t{role: \"blockquote\", expected: 1, expectedText: \"Blockquote\"},\n\t\t\t{role: \"button\", expected: 1, expectedText: \"Button\"},\n\t\t\t{role: \"caption\", expected: 1, expectedText: \"Caption\"},\n\t\t\t{role: \"cell\", expected: 1, expectedText: \"Cell\"},\n\t\t\t{role: \"checkbox\", expected: 1, expectedText: \"Checkbox\"},\n\t\t\t{role: \"code\", expected: 1, expectedText: \"Code\"},\n\t\t\t{role: \"columnheader\", expected: 1, expectedText: \"Column Header\"},\n\t\t\t{role: \"combobox\", expected: 1, expectedText: \"Combobox\"},\n\t\t\t{role: \"complementary\", expected: 1, expectedText: \"Complementary\"},\n\t\t\t{role: \"contentinfo\", expected: 1, expectedText: \"Content Info\"},\n\t\t\t{role: \"definition\", expected: 1, expectedText: \"Definition\"},\n\t\t\t{role: \"deletion\", expected: 1, expectedText: \"Deletion\"},\n\t\t\t{role: \"dialog\", expected: 1, expectedText: \"Dialog\"},\n\t\t\t{role: \"directory\", expected: 1, expectedText: \"Directory\"},\n\t\t\t{role: \"emphasis\", expected: 1, expectedText: \"Emphasis\"},\n\t\t\t{role: \"feed\", expected: 1, expectedText: \"Feed\"},\n\t\t\t{role: \"figure\", expected: 1, expectedText: \"Figure\"},\n\t\t\t{role: \"form\", expected: 1, expectedText: \"Form\"},\n\t\t\t{role: \"generic\", expected: 1, expectedText: \"Generic\"},\n\t\t\t{role: \"grid\", expected: 1, expectedText: \"Grid\"},\n\t\t\t{role: \"gridcell\", expected: 1, expectedText: \"Grid Cell\"},\n\t\t\t{role: \"group\", expected: 1, expectedText: \"Group\"},\n\t\t\t{role: \"heading\", expected: 1, expectedText: \"Heading\"},\n\t\t\t{role: \"img\", expected: 1, expectedText: \"Image\"},\n\t\t\t{role: \"insertion\", expected: 1, expectedText: \"Insertion\"},\n\t\t\t{role: \"link\", expected: 1, expectedText: \"Link\"},\n\t\t\t{role: \"list\", expected: 1, expectedText: \"List\"},\n\t\t\t{role: \"listbox\", expected: 1, expectedText: \"List Box\"},\n\t\t\t{role: \"listitem\", expected: 1, expectedText: \"List Item\"},\n\t\t\t{role: \"log\", expected: 1, expectedText: \"Log\"},\n\t\t\t{role: \"main\", expected: 1, expectedText: \"Main\"},\n\t\t\t{role: \"mark\", expected: 1, expectedText: \"Mark\"},\n\t\t\t{role: \"marquee\", expected: 1, expectedText: \"Marquee\"},\n\t\t\t{role: \"math\", expected: 1, expectedText: \"Math\"},\n\t\t\t{role: \"meter\", expected: 1, expectedText: \"Meter\"},\n\t\t\t{role: \"menu\", expected: 1, expectedText: \"Menu\"},\n\t\t\t{role: \"menubar\", expected: 1, expectedText: \"Menu Bar\"},\n\t\t\t{role: \"menuitem\", expected: 1, expectedText: \"Menu Item\"},\n\t\t\t{role: \"menuitemcheckbox\", expected: 1, expectedText: \"Menu Item Checkbox\"},\n\t\t\t{role: \"menuitemradio\", expected: 1, expectedText: \"Menu Item Radio\"},\n\t\t\t{role: \"navigation\", expected: 1, expectedText: \"Navigation\"},\n\t\t\t{role: \"note\", expected: 1, expectedText: \"Note\"},\n\t\t\t{role: \"none\", expected: 1, expectedText: \"None\"},\n\t\t\t{role: \"option\", expected: 1, expectedText: \"Option\"},\n\t\t\t{role: \"paragraph\", expected: 1, expectedText: \"Paragraph\"},\n\t\t\t{role: \"presentation\", expected: 1, expectedText: \"Presentation\"},\n\t\t\t{role: \"progressbar\", expected: 1, expectedText: \"Progress Bar\"},\n\t\t\t{role: \"radio\", expected: 1, expectedText: \"Radio\"},\n\t\t\t{role: \"radiogroup\", expected: 1, expectedText: \"Radio Group\"},\n\t\t\t{role: \"region\", expected: 1, expectedText: \"Region\"},\n\t\t\t{role: \"row\", expected: 1, expectedText: \"Row\"},\n\t\t\t{role: \"rowgroup\", expected: 1, expectedText: \"Row Group\"},\n\t\t\t{role: \"rowheader\", expected: 1, expectedText: \"Row Header\"},\n\t\t\t{role: \"scrollbar\", expected: 1, expectedText: \"Scroll Bar\"},\n\t\t\t{role: \"search\", expected: 1, expectedText: \"Search\"},\n\t\t\t{role: \"searchbox\", expected: 1, expectedText: \"Search Box\"},\n\t\t\t{role: \"separator\", expected: 1, expectedText: \"Separator\"},\n\t\t\t{role: \"slider\", expected: 1, expectedText: \"Slider\"},\n\t\t\t{role: \"spinbutton\", expected: 1, expectedText: \"Spin Button\"},\n\t\t\t{role: \"strong\", expected: 1, expectedText: \"Strong\"},\n\t\t\t{role: \"subscript\", expected: 1, expectedText: \"Subscript\"},\n\t\t\t{role: \"superscript\", expected: 1, expectedText: \"Superscript\"},\n\t\t\t{role: \"status\", expected: 1, expectedText: \"Status\"},\n\t\t\t{role: \"switch\", expected: 1, expectedText: \"Switch\"},\n\t\t\t{role: \"tab\", expected: 1, expectedText: \"Tab\"},\n\t\t\t{role: \"tablist\", expected: 1, expectedText: \"Tab List\"},\n\t\t\t{role: \"tabpanel\", expected: 1, expectedText: \"Tab Panel\"},\n\t\t\t{role: \"table\", expected: 1, expectedText: \"Table\"},\n\t\t\t{role: \"term\", expected: 1, expectedText: \"Term\"},\n\t\t\t{role: \"textbox\", expected: 1, expectedText: \"Text Box\"},\n\t\t\t{role: \"time\", expected: 1, expectedText: \"Time\"},\n\t\t\t{role: \"timer\", expected: 1, expectedText: \"Timer\"},\n\t\t\t{role: \"toolbar\", expected: 1, expectedText: \"Toolbar\"},\n\t\t\t{role: \"tooltip\", expected: 1, expectedText: \"Tooltip\"},\n\t\t\t{role: \"tree\", expected: 1, expectedText: \"Tree\"},\n\t\t\t{role: \"treegrid\", expected: 1, expectedText: \"Tree Grid\"},\n\t\t\t{role: \"treeitem\", expected: 1, expectedText: \"Tree Item\"},\n\t\t}\n\t\tfor _, tt := range tests {\n\t\t\tt.Run(tt.role, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\t\tstaticURL := tb.staticURL(\"get_by_role_explicit.html\")\n\t\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\t\tp := tb.NewPage(nil)\n\n\t\t\t\tgetByRoleImplementations := getByImplementationsOf[interface {\n\t\t\t\t\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\t\t\t\t}](p)\n\n\t\t\t\tfor implName, impl := range getByRoleImplementations {\n\t\t\t\t\tt.Run(implName, func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tl := impl.GetByRole(tt.role, nil)\n\t\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\n\t\t\t\t\t\tif tt.expectedText != \"\" {\n\t\t\t\t\t\t\ttext, err := l.InnerText(common.NewFrameInnerTextOptions(l.Timeout()))\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\trequire.Equal(t, tt.expectedText, text)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\t// We test the 'document' role independently, because the expectations\n\t\t// for each getByRole implementation (page, frame, locator) are different:\n\t\tt.Run(\"document\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_role_explicit.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByRoleImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\t\t\t}](p)\n\n\t\t\texpectedByImplementation := map[string]int{\n\t\t\t\tpageImpl:         2,\n\t\t\t\tframeImpl:        2,\n\t\t\t\tlocatorImpl:      1,\n\t\t\t\tframeLocatorImpl: 2,\n\t\t\t}\n\n\t\t\tfor implName, impl := range getByRoleImplementations {\n\t\t\t\tt.Run(implName, func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t}\n\n\t\t\t\t\tl := impl.GetByRole(\"document\", nil)\n\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, expectedByImplementation[implName], c)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t})\n\n\t// This tests all the options and different attributes (such as explicit\n\t// aria attributes vs the text value of an element) that can be used in\n\t// the DOM with the same role.\n\tt.Run(\"edge_cases\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttests := []struct {\n\t\t\tname         string\n\t\t\trole         string\n\t\t\topts         *common.GetByRoleOptions\n\t\t\texpected     int\n\t\t\texpectedText string\n\t\t}{\n\t\t\t{\n\t\t\t\tname:     \"text_content_as_name\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Submit Form'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"not_exact\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'submit form'`), Exact: toPtr(false)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"exact_no_match\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'submit form'`), Exact: toPtr(true)},\n\t\t\t\texpected: 0, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"exact_match\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Submit Form'`), Exact: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"aria_label_as_name\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Save Draft'`)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"aria_labelledby_as_name\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Upload'`)},\n\t\t\t\texpected: 1, expectedText: \"labelledby-upload-button\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"hidden_text_nodes_should_be_ignored\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'FooBar'`)},\n\t\t\t\texpected: 0, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"only_visible_node\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Bar'`)},\n\t\t\t\texpected: 1, expectedText: \"Bar\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"regex_matching\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`/^[a-z0-9]+$/`)},\n\t\t\t\texpected: 1, expectedText: \"abc123\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"selected_option\",\n\t\t\t\trole:     \"option\",\n\t\t\t\topts:     &common.GetByRoleOptions{Selected: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"One\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"pressed_option\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Pressed: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"Toggle\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"expanded_option\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Expanded: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"Expanded\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"level_option\",\n\t\t\t\trole:     \"heading\",\n\t\t\t\topts:     &common.GetByRoleOptions{Level: toPtr(int64(6))},\n\t\t\t\texpected: 1, expectedText: \"Section\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"checked_option\",\n\t\t\t\trole:     \"checkbox\",\n\t\t\t\topts:     &common.GetByRoleOptions{Checked: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"radio_checked_option\",\n\t\t\t\trole:     \"radio\",\n\t\t\t\topts:     &common.GetByRoleOptions{Checked: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"disabled_option\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Disabled: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"Go\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"include_css_hidden\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Hidden X Button'`), IncludeHidden: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"X\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"include_aria_hidden\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Name: toPtr(`'Hidden Hi Button'`), IncludeHidden: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"Hi\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"combo_options\",\n\t\t\t\trole:     \"button\",\n\t\t\t\topts:     &common.GetByRoleOptions{Pressed: toPtr(false), Name: toPtr(`'Archive'`), IncludeHidden: toPtr(true)},\n\t\t\t\texpected: 1, expectedText: \"Combo Options Button\",\n\t\t\t},\n\t\t}\n\t\tfor _, tt := range tests {\n\t\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\t\tstaticURL := tb.staticURL(\"get_by_role_edge_cases.html\")\n\t\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\t\tp := tb.NewPage(nil)\n\n\t\t\t\tgetByRoleImplementations := getByImplementationsOf[interface {\n\t\t\t\t\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\t\t\t\t}](p)\n\n\t\t\t\tfor implName, impl := range getByRoleImplementations {\n\t\t\t\t\tt.Run(implName, func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tl := impl.GetByRole(tt.role, tt.opts)\n\t\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\n\t\t\t\t\t\tif tt.expectedText != \"\" {\n\t\t\t\t\t\t\ttext, err := l.InnerText(common.NewFrameInnerTextOptions(l.Timeout()))\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\trequire.Equal(t, tt.expectedText, text)\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestGetByRoleFailure(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname          string\n\t\trole          string\n\t\topts          *common.GetByRoleOptions\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\t\"missing_quotes_on_string\",\n\t\t\t\"button\",\n\t\t\t&common.GetByRoleOptions{Name: toPtr(`Submit Form`)},\n\t\t\t\"Error while parsing selector `button[name=Submit Form]` - unexpected symbol\",\n\t\t},\n\t\t{\n\t\t\t\"missing_role\",\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\t\"Error while parsing selector `` - selector cannot be empty\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_role.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByRoleImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByRole(role string, opts *common.GetByRoleOptions) *common.Locator\n\t\t\t}](p)\n\n\t\t\tfor implName, impl := range getByRoleImplementations {\n\t\t\t\tt.Run(implName, func(t *testing.T) {\n\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t}\n\n\t\t\t\t\tl := impl.GetByRole(tt.role, tt.opts)\n\t\t\t\t\t_, err := l.Count()\n\t\t\t\t\trequire.ErrorContains(t, err, tt.expectedError)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetByAltTextSuccess(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\talt      string\n\t\topts     *common.GetByBaseOptions\n\t\texpected int\n\t}{\n\t\t{\n\t\t\t\"missing_alt\",\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t// matches on all the elements with an alt attribute.\n\t\t\t\"empty_string\",\n\t\t\t\"''\",\n\t\t\tnil,\n\t\t\t2,\n\t\t},\n\t\t{\n\t\t\t\"no_options\",\n\t\t\t\"'World Map'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"exact_match\",\n\t\t\t\"'World Map'\",\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"no_exact_match\",\n\t\t\t\"'world map'\",\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t\"regex_match\",\n\t\t\t`/^[a-z0-9]+$/`,\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_alt_text.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByAltTextImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByAltText(alt string, opts *common.GetByBaseOptions) *common.Locator\n\t\t\t}](p)\n\n\t\t\tfor implName, impl := range getByAltTextImplementations {\n\t\t\t\tt.Run(implName, func(t *testing.T) {\n\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t}\n\n\t\t\t\t\tl := impl.GetByAltText(tt.alt, tt.opts)\n\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetByLabelSuccess(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tlabel    string\n\t\topts     *common.GetByBaseOptions\n\t\texpected int\n\t}{\n\t\t{\n\t\t\t// matches on all the elements with a label.\n\t\t\t\"missing_label\",\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\t4,\n\t\t},\n\t\t{\n\t\t\t// matches on all the elements with a label.\n\t\t\t\"empty_string\",\n\t\t\t`\"\"`,\n\t\t\tnil,\n\t\t\t4,\n\t\t},\n\t\t{\n\t\t\t\"aria_label\",\n\t\t\t`\"username\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"exact_match\",\n\t\t\t`\"Password\"`,\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"no_exact_match\",\n\t\t\t`\"password\"`,\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t\"regex_match\",\n\t\t\t`/^[a-z0-9]+$/`,\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"aria_labelledby\",\n\t\t\t`\"I agree to the Terms and Conditions.\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_label.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByLabelImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByLabel(label string, opts *common.GetByBaseOptions) *common.Locator\n\t\t\t}](p)\n\n\t\t\tfor implName, impl := range getByLabelImplementations {\n\t\t\t\tt.Run(implName, func(t *testing.T) {\n\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t}\n\n\t\t\t\t\tl := impl.GetByLabel(tt.label, tt.opts)\n\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetByPlaceholderSuccess(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname        string\n\t\tplaceholder string\n\t\topts        *common.GetByBaseOptions\n\t\texpected    int\n\t}{\n\t\t{\n\t\t\t\"missing_placeholder\",\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t// matches on all the elements with a placeholder attribute.\n\t\t\t\"empty_string\",\n\t\t\t\"''\",\n\t\t\tnil,\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t\"no_options\",\n\t\t\t\"'Enter your name'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"exact_match\",\n\t\t\t\"'Email address'\",\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"no_exact_match\",\n\t\t\t\"'email address'\",\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t\"case_insensitive_match\",\n\t\t\t\"'email address'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"regex_match\",\n\t\t\t`/^[a-z0-9]+$/`,\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"textarea_placeholder\",\n\t\t\t\"'Enter comments'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"search_placeholder\",\n\t\t\t\"'Search...'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_placeholder.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByPlaceholderImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByPlaceholder(placeholder string, opts *common.GetByBaseOptions) *common.Locator\n\t\t\t}](p)\n\n\t\t\tfor implName, impl := range getByPlaceholderImplementations {\n\t\t\t\tt.Run(implName, func(t *testing.T) {\n\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t}\n\n\t\t\t\t\tl := impl.GetByPlaceholder(tt.placeholder, tt.opts)\n\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetByTitleSuccess(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\ttitle    string\n\t\topts     *common.GetByBaseOptions\n\t\texpected int\n\t}{\n\t\t{\n\t\t\t\"missing_title\",\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t// matches on all the elements with a title attribute.\n\t\t\t\"empty_string\",\n\t\t\t\"''\",\n\t\t\tnil,\n\t\t\t5,\n\t\t},\n\t\t{\n\t\t\t\"no_options\",\n\t\t\t\"'Click me'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"exact_match\",\n\t\t\t\"'Link to somewhere'\",\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"no_exact_match\",\n\t\t\t\"'link to somewhere'\",\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t0,\n\t\t},\n\t\t{\n\t\t\t\"case_insensitive_match\",\n\t\t\t\"'link to somewhere'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"regex_match\",\n\t\t\t`/^[a-z0-9]+$/`,\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"image_title\",\n\t\t\t\"'Placeholder image'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t\t{\n\t\t\t\"div_title\",\n\t\t\t\"'Information box'\",\n\t\t\tnil,\n\t\t\t1,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_title.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByTitleImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByTitle(title string, opts *common.GetByBaseOptions) *common.Locator\n\t\t\t}](p)\n\n\t\t\tfor implName, impl := range getByTitleImplementations {\n\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t} else {\n\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t}\n\n\t\t\t\tt.Run(implName, func(t *testing.T) {\n\t\t\t\t\tl := impl.GetByTitle(tt.title, tt.opts)\n\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetByTestIDSuccess(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname         string\n\t\ttestID       string\n\t\texpected     int\n\t\texpectedText string\n\t}{\n\t\t{\n\t\t\t\"submit_button\",\n\t\t\t\"'submit-button'\",\n\t\t\t1,\n\t\t\t\"Submit\",\n\t\t},\n\t\t{\n\t\t\t\"username_input\",\n\t\t\t\"'username-input'\",\n\t\t\t1,\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"info_box\",\n\t\t\t\"'info-box'\",\n\t\t\t1,\n\t\t\t\"Information\",\n\t\t},\n\t\t{\n\t\t\t\"regex_match\",\n\t\t\t`/^[a-z0-9]+$/`,\n\t\t\t1,\n\t\t\t\"Test span\",\n\t\t},\n\t\t{\n\t\t\t\"link_testid\",\n\t\t\t\"'my-link'\",\n\t\t\t1,\n\t\t\t\"Link\",\n\t\t},\n\t\t{\n\t\t\t\"non_existent_testid\",\n\t\t\t\"'does-not-exist'\",\n\t\t\t0,\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"missing_testid\",\n\t\t\t\"\",\n\t\t\t0,\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"empty_string\",\n\t\t\t\"''\",\n\t\t\t0,\n\t\t\t\"\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_testid.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByTestIDImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByTestID(testID string) *common.Locator\n\t\t\t}](p)\n\n\t\t\tfor implName, impl := range getByTestIDImplementations {\n\t\t\t\tt.Run(implName, func(t *testing.T) {\n\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t}\n\n\t\t\t\t\tl := impl.GetByTestID(tt.testID)\n\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\n\t\t\t\t\tif tt.expected > 0 && tt.expectedText != \"\" {\n\t\t\t\t\t\ttext, err := l.InnerText(common.NewFrameInnerTextOptions(l.Timeout()))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\trequire.Equal(t, tt.expectedText, text)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetByTextSuccess(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname         string\n\t\ttext         string\n\t\topts         *common.GetByBaseOptions\n\t\texpected     int\n\t\texpectedText string\n\t}{\n\t\t{\n\t\t\t\"missing_text\",\n\t\t\t\"\",\n\t\t\tnil,\n\t\t\t7,\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"simple_text\",\n\t\t\t`\"Hello World\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t\t\"Hello World\",\n\t\t},\n\t\t{\n\t\t\t\"button_text\",\n\t\t\t`\"Click me\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t\t\"Click me\",\n\t\t},\n\t\t{\n\t\t\t\"exact_match\",\n\t\t\t`\"Learn more\"`,\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t1,\n\t\t\t\"Learn more\",\n\t\t},\n\t\t{\n\t\t\t\"no_exact_match\",\n\t\t\t`\"learn more\"`,\n\t\t\t&common.GetByBaseOptions{Exact: toPtr(true)},\n\t\t\t0,\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"case_insensitive_match\",\n\t\t\t`\"hello world\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t\t\"Hello World\",\n\t\t},\n\t\t{\n\t\t\t\"regex_match\",\n\t\t\t`/^[a-z0-9]+$/`,\n\t\t\tnil,\n\t\t\t1,\n\t\t\t\"abc123\",\n\t\t},\n\t\t{\n\t\t\t\"partial_text_match\",\n\t\t\t`\"longer text\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t\t\"This is a longer text with multiple words\",\n\t\t},\n\t\t{\n\t\t\t\"normalized_whitespace\",\n\t\t\t`\"Spaced text\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t\t\"Spaced text\",\n\t\t},\n\t\t{\n\t\t\t\"label_text\",\n\t\t\t`\"Email address\"`,\n\t\t\tnil,\n\t\t\t1,\n\t\t\t\"Email address\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tstaticURL := tb.staticURL(\"get_by_text.html\")\n\t\t\ttb.withIFrameURL(staticURL, iframeID)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tgetByTextImplementations := getByImplementationsOf[interface {\n\t\t\t\tGetByText(text string, opts *common.GetByBaseOptions) *common.Locator\n\t\t\t}](p)\n\n\t\t\tfor implName, impl := range getByTextImplementations {\n\t\t\t\tt.Run(implName, func(t *testing.T) {\n\t\t\t\t\tif implName == frameLocatorImpl {\n\t\t\t\t\t\ttb.GotoPage(p, tb.url(\"/iframe\"))\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttb.GotoPage(p, staticURL)\n\t\t\t\t\t}\n\n\t\t\t\t\tl := impl.GetByText(tt.text, tt.opts)\n\t\t\t\t\tc, err := l.Count()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, tt.expected, c)\n\n\t\t\t\t\tif tt.expected > 0 && tt.expectedText != \"\" {\n\t\t\t\t\t\ttext, err := l.InnerText(common.NewFrameInnerTextOptions(l.Timeout()))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\trequire.Equal(t, tt.expectedText, text)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetByNullHandling(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\n\t// Setup\n\ttb.vu.SetVar(t, \"page\", &sobek.Object{})\n\t_, err := tb.vu.RunAsync(t, `\n\t\tpage = await browser.newPage();\n\t\tframe = page.mainFrame();\n\t\tlocator = page.locator(':root');\n\t\tframeLocator = page.locator('#%s').contentFrame();\n\t`, iframeID)\n\trequire.NoError(t, err)\n\n\tfor _, getByImpl := range []string{pageImpl, frameImpl, locatorImpl, frameLocatorImpl} {\n\t\t_, err = tb.vu.RunAsync(t, `\n\t\tawait %s.getByRole().click();\n\t`, getByImpl)\n\t\trequire.ErrorContains(t, err, \"missing required argument 'role'\")\n\n\t\t_, err = tb.vu.RunAsync(t, `\n\t\tawait %s.getByAltText().click();\n\t`, getByImpl)\n\t\trequire.ErrorContains(t, err, \"missing required argument 'altText'\")\n\n\t\t_, err = tb.vu.RunAsync(t, `\n\t\tawait %s.getByLabel().click();\n\t`, getByImpl)\n\t\trequire.ErrorContains(t, err, \"missing required argument 'label'\")\n\n\t\t_, err = tb.vu.RunAsync(t, `\n\t\tawait %s.getByPlaceholder().click();\n\t`, getByImpl)\n\t\trequire.ErrorContains(t, err, \"missing required argument 'placeholder'\")\n\n\t\t_, err = tb.vu.RunAsync(t, `\n\t\tawait %s.getByTitle().click();\n\t`, getByImpl)\n\t\trequire.ErrorContains(t, err, \"missing required argument 'title'\")\n\n\t\t_, err = tb.vu.RunAsync(t, `\n\t\tawait %s.getByTestId().click();\n\t`, getByImpl)\n\t\trequire.ErrorContains(t, err, \"missing required argument 'testId'\")\n\n\t\t_, err = tb.vu.RunAsync(t, `\n\t\tawait %s.getByText().click();\n\t`, getByImpl)\n\t\trequire.ErrorContains(t, err, \"missing required argument 'text'\")\n\t}\n}\n\nfunc getByImplementationsOf[T any](p *common.Page) map[string]T {\n\treturn map[string]T{\n\t\tpageImpl:         any(p).(T),\n\t\tframeImpl:        any(p.MainFrame()).(T),\n\t\tlocatorImpl:      any(p.Locator(\":root\", nil)).(T),\n\t\tframeLocatorImpl: any(p.Locator(\"#\"+iframeID, nil).ContentFrame()).(T),\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/goroutine_leak_test.go",
    "content": "package tests\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// TestGoroutineLeakOnRepeatedClicks tests that repeated button fetch and clicks\n// don't cause goroutine leaks. It fetches and clicks a button 20 times and verifies\n// that goroutine count doesn't increase beyond the threshold (10% locally should be\n// enough, 30% for GitHub Actions).\nfunc TestGoroutineLeakOnRepeatedClicks(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\tbuttonHTML := `\n\t\t<button id=\"test-button\" onclick=\"document.getElementById('counter').innerHTML = parseInt(document.getElementById('counter').innerHTML || 0) + 1;\">\n\t\t\tClick me\n\t\t</button>\n\t\t<div id=\"counter\">0</div>\n\t`\n\terr := p.SetContent(buttonHTML, nil)\n\trequire.NoError(t, err)\n\n\t// Force GC\n\truntime.GC()\n\n\t// Measure baseline\n\tbaselineGoroutines := runtime.NumGoroutine()\n\n\tt.Logf(\"Baseline goroutines: %d\", baselineGoroutines)\n\n\tconst clickCount = 20\n\tfor i := range clickCount {\n\t\tbutton, err := p.Query(\"#test-button\")\n\t\trequire.NoError(t, err)\n\n\t\terr = button.Click(common.NewElementHandleClickOptions(time.Duration(1000) * time.Millisecond))\n\t\trequire.NoError(t, err, \"click %d failed\", i+1)\n\t}\n\n\t// Force GC again to ensure we're measuring actual goroutines leaks\n\truntime.GC()\n\n\t// Get final measurements\n\tfinalGoroutines := runtime.NumGoroutine()\n\n\tt.Logf(\"Final goroutines: %d\", finalGoroutines)\n\n\t// Calculate and assert goroutine increase is within threshold\n\tgoroutineIncrease := finalGoroutines - baselineGoroutines\n\tgoroutineIncreasePercent := float64(goroutineIncrease) / float64(baselineGoroutines) * 100\n\tt.Logf(\"Goroutine increase: %d (%.2f%%)\", goroutineIncrease, goroutineIncreasePercent)\n\n\t// It should be 10%, but it has to be 30% due to the github actions environment.\n\tthresholdPercent := 0.30\n\n\tmaxAllowedGoroutineIncrease := int(float64(baselineGoroutines) * thresholdPercent)\n\tassert.LessOrEqual(t, goroutineIncrease, maxAllowedGoroutineIncrease,\n\t\t\"Goroutine count increased by %d (%.2f%%), which exceeds the %.0f%% threshold (%d). Possible goroutine leak detected.\",\n\t\tgoroutineIncrease, goroutineIncreasePercent, thresholdPercent*100, maxAllowedGoroutineIncrease)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/js_handle_get_properties_test.go",
    "content": "package tests\n\nimport (\n\t_ \"embed\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestJSHandleGetProperties(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\thandle, err := p.EvaluateHandle(`\n\t() => {\n\t\treturn {\n\t\t\tprop1: \"one\",\n\t\t\tprop2: \"two\",\n\t\t\tprop3: \"three\"\n\t\t};\n\t}\n\t`)\n\trequire.NoError(t, err, \"expected no error when evaluating handle\")\n\n\tprops, err := handle.GetProperties()\n\trequire.NoError(t, err, \"expected no error when getting properties\")\n\n\tvalue, err := props[\"prop1\"].JSONValue()\n\tassert.NoError(t, err, \"expected no error when getting JSONValue\")\n\tassert.Equal(t, value, \"one\", `expected property value of \"one\", got %q`, value)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/js_handle_test.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestJSHandleEvaluate(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tpageFunc string\n\t\targs     []any\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"no_args\",\n\t\t\tpageFunc: `handle => handle.innerText`,\n\t\t\targs:     nil,\n\t\t\texpected: \"Some title\",\n\t\t},\n\t\t{\n\t\t\tname: \"with_args\",\n\t\t\tpageFunc: `(handle, a, b) => {\n\t\t\t\tconst c = a + b;\n\t\t\t\treturn handle.innerText + \" \" + c\n\t\t\t}`,\n\t\t\targs:     []any{1, 2},\n\t\t\texpected: \"Some title 3\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\terr := p.SetContent(`<html><head><title>Some title</title></head></html>`, nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult, err := p.EvaluateHandle(`() => document.head`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, result)\n\n\t\t\tgot, err := result.Evaluate(tt.pageFunc, tt.args...)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.expected, got)\n\t\t})\n\t}\n}\n\nfunc TestJSHandleEvaluateHandle(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tpageFunc string\n\t\targs     []any\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"no_args\",\n\t\t\tpageFunc: `handle => {\n\t\t\t\treturn {\"innerText\": handle.innerText};\n\t\t\t}`,\n\t\t\targs:     nil,\n\t\t\texpected: `{\"innerText\":\"Some title\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with_args\",\n\t\t\tpageFunc: `(handle, a, b) => {\n\t\t\t\treturn {\"innerText\": handle.innerText, \"sum\": a + b};\n\t\t\t}`,\n\t\t\targs:     []any{1, 2},\n\t\t\texpected: `{\"innerText\":\"Some title\",\"sum\":3}`,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\terr := p.SetContent(`<html><head><title>Some title</title></head></html>`, nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult, err := p.EvaluateHandle(`() => document.head`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, result)\n\n\t\t\tgot, err := result.EvaluateHandle(tt.pageFunc, tt.args...)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.NotNil(t, got)\n\n\t\t\tj, err := got.JSONValue()\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.expected, j)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/keyboard_test.go",
    "content": "// practically none of this work on windows\n//go:build !windows\n\npackage tests\n\nimport (\n\t\"context\"\n\t_ \"embed\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/keyboardlayout\"\n)\n\nfunc TestKeyboardPress(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"all_keys\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\t\tlayout := keyboardlayout.GetKeyboardLayout(\"us\")\n\n\t\tfor k := range layout.Keys {\n\t\t\tassert.NoError(t, kb.Press(string(k), common.KeyboardOptions{}))\n\t\t}\n\t})\n\n\tt.Run(\"backspace\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<input>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"input\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"input\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Type(\"Hello World!\", common.KeyboardOptions{}))\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"Hello World!\", v)\n\n\t\trequire.NoError(t, kb.Press(\"Backspace\", common.KeyboardOptions{}))\n\t\tv, err = el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"Hello World\", v)\n\t})\n\n\tt.Run(\"combo\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<input>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"input\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"input\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Press(\"Shift++\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+=\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+@\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+6\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+KeyA\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+b\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+C\", common.KeyboardOptions{}))\n\n\t\trequire.NoError(t, kb.Press(\"Control+KeyI\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Control+J\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Control+k\", common.KeyboardOptions{}))\n\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"+=@6AbC\", v)\n\t})\n\n\tt.Run(\"control_or_meta\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\t// Navigate to page1\n\t\turl := tb.staticURL(\"page1.html\")\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(\n\t\t\turl,\n\t\t\topts,\n\t\t)\n\t\tassert.NoError(t, err)\n\n\t\t// Make sure the h1 header is \"Page 1\"\n\t\th1 := p.Locator(\"h1\", nil)\n\t\ttext, err := h1.InnerText(common.NewFrameInnerTextOptions(h1.Timeout()))\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"Page 1\", text)\n\n\t\tctx, cancel := context.WithTimeout(tb.context(), 5*time.Second)\n\t\tdefer cancel()\n\n\t\tbc := tb.Context()\n\t\tvar newTab *common.Page\n\n\t\t// We want to meta/control click the link so that it opens in a new tab.\n\t\t// At the same time we will wait for a new page creation with WaitForEvent.\n\t\terr = tb.run(ctx,\n\t\t\tfunc() error {\n\t\t\t\tvar resp any\n\t\t\t\tresp, err := bc.WaitForEvent(\"page\", nil, 5*time.Second)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tvar ok bool\n\t\t\t\tnewTab, ok = resp.(*common.Page)\n\t\t\t\tassert.True(t, ok)\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\tfunc() error {\n\t\t\t\tkb := p.GetKeyboard()\n\t\t\t\tassert.NoError(t, kb.Down(\"ControlOrMeta\"))\n\t\t\t\terr = p.Locator(`a[href=\"page2.html\"]`, nil).Click(common.NewFrameClickOptions(p.Timeout()))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.NoError(t, kb.Up(\"ControlOrMeta\"))\n\n\t\t\t\treturn nil\n\t\t\t},\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\t// Wait for the new tab to complete loading.\n\t\tassert.NoError(t, newTab.WaitForLoadState(\"load\", common.NewFrameWaitForLoadStateOptions(p.MainFrame().Timeout())))\n\n\t\t// Make sure the newTab has a different h1 heading.\n\t\th1 = newTab.Locator(\"h1\", nil)\n\t\ttext, err = h1.InnerText(common.NewFrameInnerTextOptions(h1.Timeout()))\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"Page 2\", text)\n\n\t\t// Make sure there are two pages open.\n\t\tpp := bc.Pages()\n\t\tassert.Len(t, pp, 2)\n\t})\n\n\tt.Run(\"meta\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Skip(\"FIXME\") // See https://go.k6.io/k6/js/modules/k6/browser/issues/424\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<input>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"input\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"input\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Press(\"Shift+KeyA\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+b\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Shift+C\", common.KeyboardOptions{}))\n\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"AbC\", v)\n\n\t\tmetaKey := \"Control\"\n\t\tif runtime.GOOS == \"darwin\" {\n\t\t\tmetaKey = \"Meta\"\n\t\t}\n\t\trequire.NoError(t, kb.Press(metaKey+\"+A\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Delete\", common.KeyboardOptions{}))\n\t\tv, err = el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"\", v)\n\t})\n\n\tt.Run(\"type does not split on +\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<textarea>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"textarea\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"textarea\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Type(\"L+m+KeyN\", common.KeyboardOptions{}))\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"L+m+KeyN\", v)\n\t})\n\n\tt.Run(\"capitalization\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<textarea>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"textarea\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"textarea\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Press(\"C\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"d\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"KeyE\", common.KeyboardOptions{}))\n\n\t\trequire.NoError(t, kb.Down(\"Shift\"))\n\t\trequire.NoError(t, kb.Down(\"f\"))\n\t\trequire.NoError(t, kb.Up(\"f\"))\n\t\trequire.NoError(t, kb.Down(\"G\"))\n\t\trequire.NoError(t, kb.Up(\"G\"))\n\t\trequire.NoError(t, kb.Down(\"KeyH\"))\n\t\trequire.NoError(t, kb.Up(\"KeyH\"))\n\t\trequire.NoError(t, kb.Up(\"Shift\"))\n\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"CdefGH\", v)\n\t})\n\n\tt.Run(\"type not affected by shift\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<textarea>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"textarea\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"textarea\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Down(\"Shift\"))\n\t\trequire.NoError(t, kb.Type(\"oPqR\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Up(\"Shift\"))\n\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"oPqR\", v)\n\t})\n\n\tt.Run(\"newline\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<textarea>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"textarea\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"textarea\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Type(\"Hello\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Enter\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Press(\"Enter\", common.KeyboardOptions{}))\n\t\trequire.NoError(t, kb.Type(\"World!\", common.KeyboardOptions{}))\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"Hello\\n\\nWorld!\", v)\n\t})\n\n\t// Replicates the test from https://playwright.dev/docs/api/class-keyboard\n\tt.Run(\"selection\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tkb := p.GetKeyboard()\n\n\t\terr := p.SetContent(`<input>`, nil)\n\t\trequire.NoError(t, err)\n\t\tel, err := p.Query(\"input\")\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, p.Focus(\"input\", common.NewFrameBaseOptions(p.MainFrame().Timeout())))\n\n\t\trequire.NoError(t, kb.Type(\"Hello World!\", common.KeyboardOptions{}))\n\t\tv, err := el.InputValue(common.NewElementHandleBaseOptions(el.Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"Hello World!\", v)\n\n\t\trequire.NoError(t, kb.Press(\"ArrowLeft\", common.KeyboardOptions{}))\n\t\t// Should hold the key until Up() is called.\n\t\trequire.NoError(t, kb.Down(\"Shift\"))\n\t\tfor range len(\" World\") {\n\t\t\trequire.NoError(t, kb.Press(\"ArrowLeft\", common.KeyboardOptions{}))\n\t\t}\n\t\t// Should release the key but the selection should remain active.\n\t\trequire.NoError(t, kb.Up(\"Shift\"))\n\t\t// Should delete the selection.\n\t\trequire.NoError(t, kb.Press(\"Backspace\", common.KeyboardOptions{}))\n\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"Hello World!\", v)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/launch_options_slowmo_test.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc TestBrowserOptionsSlowMo(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\tt.Run(\"Page\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"check\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\tassert.NoError(t, p.Check(\".check\", common.NewFrameCheckOptions(p.MainFrame().Timeout())))\n\t\t\t})\n\t\t})\n\t\tt.Run(\"click\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.Click(\"button\", common.NewFrameClickOptions(p.Timeout()))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"dblClick\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.Dblclick(\"button\", common.NewFrameDblClickOptions(p.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"dispatchEvent\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.DispatchEvent(\"button\", \"click\", nil, common.NewFrameDispatchEventOptions(p.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"emulateMedia\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\tpopts := common.NewPageEmulateMediaOptions(p)\n\t\t\t\tpopts.Media = \"print\"\n\t\t\t\terr := p.EmulateMedia(popts)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"evaluate\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\t_, err := p.Evaluate(`() => void 0`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"evaluateHandle\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\t_, err := p.EvaluateHandle(`() => window`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"fill\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.Fill(\".fill\", \"foo\", common.NewFrameFillOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"focus\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.Focus(\"button\", common.NewFrameBaseOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"goto\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t\t}\n\t\t\t\t_, err := p.Goto(\n\t\t\t\t\tcommon.BlankPage,\n\t\t\t\t\topts,\n\t\t\t\t)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"hover\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.Hover(\"button\", common.NewFrameHoverOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"press\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.Press(\"button\", \"Enter\", common.NewFramePressOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"reload\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\topts := common.NewPageReloadOptions(common.LifecycleEventLoad, p.MainFrame().NavigationTimeout())\n\t\t\t\t_, err := p.Reload(opts)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"setContent\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.SetContent(\"hello world\", nil)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\t/*t.Run(\"setInputFiles\", func(t *testing.T) {\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *Browser, p *common.Page) {\n\t\t\t\tp.SetInputFiles(\".file\", nil, nil)\n\t\t\t})\n\t\t})*/\n\t\tt.Run(\"selectOption\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\t_, err := p.SelectOption(\"select\", []any{\"foo\"}, common.NewFrameSelectOptionOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"type\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\terr := p.Type(\".fill\", \"a\", common.NewFrameTypeOptions(p.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"uncheck\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestPageSlowMoImpl(t, tb, func(_ *testBrowser, p *common.Page) {\n\t\t\t\tassert.NoError(t, p.Uncheck(\".uncheck\", common.NewFrameUncheckOptions(p.Timeout())))\n\t\t\t})\n\t\t})\n\t})\n\n\tt.Run(\"Frame\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"check\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\tassert.NoError(t, f.Check(\".check\", common.NewFrameCheckOptions(f.Timeout())))\n\t\t\t})\n\t\t})\n\t\tt.Run(\"click\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.Click(\"button\", common.NewFrameClickOptions(f.Timeout()))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"dblClick\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.Dblclick(\"button\", common.NewFrameDblClickOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"dispatchEvent\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.DispatchEvent(\"button\", \"click\", nil, common.NewFrameDispatchEventOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"evaluate\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\t_, err := f.Evaluate(`() => void 0`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"evaluateHandle\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\t_, err := f.EvaluateHandle(`() => window`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"fill\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.Fill(\".fill\", \"foo\", common.NewFrameFillOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"focus\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.Focus(\"button\", common.NewFrameBaseOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"goto\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t\t}\n\t\t\t\t_, _ = f.Goto(\n\t\t\t\t\tcommon.BlankPage,\n\t\t\t\t\topts,\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"hover\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.Hover(\"button\", common.NewFrameHoverOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"press\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.Press(\"button\", \"Enter\", common.NewFramePressOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"setContent\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.SetContent(\"hello world\", nil)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\t/*t.Run(\"setInputFiles\", func(t *testing.T) {\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *Browser, f common.Frame) {\n\t\t\t\tf.SetInputFiles(\".file\", nil, nil)\n\t\t\t})\n\t\t})*/\n\t\tt.Run(\"selectOption\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\t_, err := f.SelectOption(\"select\", []any{\"foo\"}, common.NewFrameSelectOptionOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"type\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\terr := f.Type(\".fill\", \"a\", common.NewFrameTypeOptions(f.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"uncheck\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttestFrameSlowMoImpl(t, tb, func(_ *testBrowser, f *common.Frame) {\n\t\t\t\tassert.NoError(t, f.Uncheck(\".uncheck\", common.NewFrameUncheckOptions(f.Timeout())))\n\t\t\t})\n\t\t})\n\t})\n}\n\nfunc testSlowMoImpl(t *testing.T, tb *testBrowser, fn func(*testBrowser)) {\n\tt.Helper()\n\n\thooks := common.GetHooks(tb.ctx)\n\tcurrentHook := hooks.Get(common.HookApplySlowMo)\n\tchCalled := make(chan bool, 1)\n\tdefer hooks.Register(common.HookApplySlowMo, currentHook)\n\thooks.Register(common.HookApplySlowMo, func(ctx context.Context) {\n\t\tcurrentHook(ctx)\n\t\tchCalled <- true\n\t})\n\n\tdidSlowMo := false\n\tgo fn(tb)\n\tselect {\n\tcase <-tb.ctx.Done():\n\tcase <-chCalled:\n\t\tdidSlowMo = true\n\t}\n\n\trequire.True(t, didSlowMo, \"expected action to have been slowed down\")\n}\n\nfunc testPageSlowMoImpl(t *testing.T, tb *testBrowser, fn func(*testBrowser, *common.Page)) {\n\tt.Helper()\n\n\tp := tb.NewPage(nil)\n\terr := p.SetContent(`\n\t\t<button>a</button>\n\t\t<input type=\"checkbox\" class=\"check\">\n\t\t<input type=\"checkbox\" checked=true class=\"uncheck\">\n\t\t<input class=\"fill\">\n\t\t<select>\n\t\t<option>foo</option>\n\t\t</select>\n\t\t<input type=\"file\" class=\"file\">\n    \t`, nil,\n\t)\n\trequire.NoError(t, err)\n\ttestSlowMoImpl(t, tb, func(tb *testBrowser) { fn(tb, p) })\n}\n\nfunc testFrameSlowMoImpl(t *testing.T, tb *testBrowser, fn func(bt *testBrowser, f *common.Frame)) {\n\tt.Helper()\n\n\tp := tb.NewPage(nil)\n\n\tpageFn := `\n\tasync (frameId, url) => {\n\t\tconst frame = document.createElement('iframe');\n\t\tframe.src = url;\n\t\tframe.id = frameId;\n\t\tdocument.body.appendChild(frame);\n\t\tawait new Promise(x => frame.onload = x);\n\t\treturn frame;\n\t}\n\t`\n\n\th, err := p.EvaluateHandle(\n\t\tpageFn,\n\t\t\"frame1\",\n\t\ttb.staticURL(\"empty.html\"),\n\t)\n\trequire.NoError(tb.t, err)\n\n\tf, err := h.AsElement().ContentFrame()\n\trequire.NoError(tb.t, err)\n\n\terr = f.SetContent(`\n\t\t<button>a</button>\n\t\t<input type=\"checkbox\" class=\"check\">\n\t\t<input type=\"checkbox\" checked=true class=\"uncheck\">\n\t\t<input class=\"fill\">\n\t\t<select>\n\t\t  <option>foo</option>\n\t\t</select>\n\t\t<input type=\"file\" class=\"file\">\n    \t`, nil)\n\trequire.NoError(tb.t, err)\n\ttestSlowMoImpl(t, tb, func(tb *testBrowser) { fn(tb, f) })\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/lifecycle_wait_test.go",
    "content": "// practically none of this work on windows\n//go:build !windows\n\npackage tests\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// TODO\n// Remove the promises. We don't need them anymore.\n\n// General guidelines on lifecycle events:\n//\n// load\n//\n//   The load event is fired when the initial HTML document has been completely\n//   loaded. It does not wait for the other network requests to complete.\n//\n//   Emitted by the browser once:\n//   1. The HTML is loaded.\n//   2. The async scripts have loaded.\n//\n// domcontentloaded\n//\n//   The DOMContentLoaded event is fired when the initial HTML document has been\n//   completely loaded and parsed. It does not wait for the async scripts or the\n//   other network requests to complete.\n//\n//   Emitted by the browser once:\n//   1. The HTML is loaded.\n//\n// networkidle\n//\n//   The networkidle event is fired when there are no network connections for at\n//   least 500ms.\n//\n//   Emitted by the browser once:\n//   1. The HTML is loaded.\n//   2. The async scripts have loaded.\n//   3. All other network requests have completed.\n\nfunc TestLifecycleWaitForNavigation(t *testing.T) {\n\t// Test description\n\t//\n\t// Steps:\n\t//   1. goto /home and wait for the specified lifecycle event.\n\t//   2. click on a link that navigates to a page, and wait on\n\t//    the specified lifecycle event.\n\t//\n\t// Success criteria:\n\t//   The click will perform a navigation away from the current page,\n\t//   it should wait for the specified lifecycle event and the result\n\t//   of the page should match the original nav.\n\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname                  string\n\t\tpingSlowness          time.Duration\n\t\tpingJSSlow            bool\n\t\twaitUntil             common.LifecycleEvent\n\t\tpingRequestTextAssert func(result string, pingCount int)\n\t\tpingJSTextAssert      func(result string)\n\t\tassertFunc            func(tb *testBrowser, p *common.Page) error\n\t\twantError             string\n\t}{\n\t\t{\n\t\t\tname:         \"load\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventLoad,\n\t\t\tpingRequestTextAssert: func(result string, pingCount int) {\n\t\t\t\tassert.NotEqualValues(t, fmt.Sprintf(\"Waiting... pong %d - for loop complete\", pingCount), result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"domcontentloaded\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   true,\n\t\t\twaitUntil:    common.LifecycleEventDOMContentLoad,\n\t\t\tpingRequestTextAssert: func(result string, pingCount int) {\n\t\t\t\tassert.NotEqualValues(t, fmt.Sprintf(\"Waiting... pong %d - for loop complete\", pingCount), result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"Waiting...\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"networkidle\",\n\t\t\tpingSlowness: 0,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventNetworkIdle,\n\t\t\tpingRequestTextAssert: func(result string, pingCount int) {\n\t\t\t\tassert.EqualValues(t, fmt.Sprintf(\"Waiting... pong %d - for loop complete\", pingCount), result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// Test description\n\t\t\t//\n\t\t\t// Steps:\n\t\t\t//   1. goto /home and wait for the specified lifecycle event.\n\t\t\t//   2. call WaitForNavigation without clicking on the link.\n\t\t\t//    the specified lifecycle event.\n\t\t\t//\n\t\t\t// Success criteria:\n\t\t\t//   We want this test to timeout since the navigation has\n\t\t\t//   completed, a new one hasn't started but we \"accidentally\"\n\t\t\t//   call WaitForNavigation.\n\t\t\tname:         \"timeout\",\n\t\t\tpingSlowness: 0,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventNetworkIdle,\n\t\t\tassertFunc: func(tb *testBrowser, p *common.Page) error {\n\t\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tassert.EqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\n\t\t\t\topts := &common.FrameWaitForNavigationOptions{\n\t\t\t\t\tTimeout:   1000 * time.Millisecond,\n\t\t\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\t\t}\n\t\t\t\t_, err = p.WaitForNavigation(opts, nil)\n\n\t\t\t\treturn err\n\t\t\t},\n\t\t\twantError: \"waiting for navigation: timed out after 1s\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\twithHomeHandler(t, tb, \"lifecycle.html?pingCount=10\")\n\t\t\twithPingHandler(t, tb, tt.pingSlowness, nil)\n\t\t\twithPingJSHandler(t, tb, tt.pingJSSlow, nil, false)\n\n\t\t\tif tt.assertFunc != nil {\n\t\t\t\tassertHome(t, tb, p, tt.waitUntil, func() error {\n\t\t\t\t\treturn tt.assertFunc(tb, p)\n\t\t\t\t}, nil, tt.wantError)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassertHome(t, tb, p, tt.waitUntil, func() error {\n\t\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingRequestTextAssert(result, 10)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingJSTextAssert(result)\n\n\t\t\t\twaitForNav := func() error {\n\t\t\t\t\topts := &common.FrameWaitForNavigationOptions{\n\t\t\t\t\t\tTimeout:   30000 * time.Millisecond,\n\t\t\t\t\t\tWaitUntil: tt.waitUntil,\n\t\t\t\t\t}\n\t\t\t\t\t_, err := p.WaitForNavigation(opts, nil)\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tclick := func() error {\n\t\t\t\t\treturn p.Click(`a`, common.NewFrameClickOptions(p.Timeout()))\n\t\t\t\t}\n\n\t\t\t\tctx, cancel := context.WithTimeout(tb.ctx, 5*time.Second)\n\t\t\t\tdefer cancel()\n\n\t\t\t\treturn tb.run(ctx, waitForNav, click)\n\t\t\t}, func() {\n\t\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ttt.pingRequestTextAssert(result, 20)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ttt.pingJSTextAssert(result)\n\t\t\t}, \"\")\n\t\t})\n\t}\n}\n\nfunc TestLifecycleWaitForLoadState(t *testing.T) {\n\tt.Parallel()\n\n\t// Test description\n\t//\n\t// Steps:\n\t//   1. goto /home and wait for the specified lifecycle event.\n\t//   2. use WaitForLoadState with the same specified lifecycle event.\n\t//\n\t// Success criteria:\n\t//   We want to ensure that the specified event is persisted in\n\t//   memory, and we don't block on WaitForLoadState.\n\n\ttests := []struct {\n\t\tname                  string\n\t\tpingSlowness          time.Duration\n\t\tpingJSSlow            bool\n\t\twaitUntil             common.LifecycleEvent\n\t\tpingRequestTextAssert func(result string)\n\t\tpingJSTextAssert      func(result string)\n\t\tassertFunc            func(p *common.Page)\n\t}{\n\t\t{\n\t\t\tname:         \"load\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventLoad,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.NotEqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"domcontentloaded\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   true,\n\t\t\twaitUntil:    common.LifecycleEventDOMContentLoad,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.NotEqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"Waiting...\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"networkidle\",\n\t\t\tpingSlowness: 0,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventNetworkIdle,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// Test description\n\t\t\t//\n\t\t\t// Steps:\n\t\t\t//   1. goto /home and wait for the domcontentloaded lifecycle event.\n\t\t\t//   2. use WaitForLoadState with networkidle.\n\t\t\t//\n\t\t\t// Success criteria:\n\t\t\t//   We want to quickly move to calling WaitForLoadState\n\t\t\t//   so that we wait until networkidle is received from\n\t\t\t//   the browser -- not relying on the persisted state in memory.\n\t\t\tname:         \"domcontentloaded then networkidle\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventDOMContentLoad,\n\t\t\tassertFunc: func(p *common.Page) {\n\t\t\t\terr := p.WaitForLoadState(common.LifecycleEventNetworkIdle.String(), common.NewFrameWaitForLoadStateOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.EqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\twithHomeHandler(t, tb, \"lifecycle.html?pingCount=10\")\n\t\t\twithPingHandler(t, tb, tt.pingSlowness, nil)\n\t\t\twithPingJSHandler(t, tb, tt.pingJSSlow, nil, false)\n\n\t\t\tif tt.assertFunc != nil {\n\t\t\t\tassertHome(t, tb, p, tt.waitUntil, func() error {\n\t\t\t\t\ttt.assertFunc(p)\n\t\t\t\t\treturn nil\n\t\t\t\t}, nil, \"\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassertHome(t, tb, p, tt.waitUntil, func() error {\n\t\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ttt.pingRequestTextAssert(result)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ttt.pingJSTextAssert(result)\n\n\t\t\t\t// This shouldn't block and return after calling hasLifecycleEventFired.\n\t\t\t\treturn p.WaitForLoadState(tt.waitUntil.String(), common.NewFrameWaitForLoadStateOptions(p.MainFrame().Timeout()))\n\t\t\t}, nil, \"\")\n\t\t})\n\t}\n}\n\nfunc TestLifecycleReload(t *testing.T) {\n\tt.Parallel()\n\n\t// Test description\n\t//\n\t// Steps:\n\t//   1. goto /home and wait for the specified lifecycle event.\n\t//   2. reload the page and wait for the specified lifecycle event.\n\t//\n\t// Success criteria:\n\t//   The resulting page after reload is the same as\n\t//   the initial navigation with goto.\n\n\ttests := []struct {\n\t\tname                  string\n\t\tpingSlowness          time.Duration\n\t\tpingJSSlow            bool\n\t\twaitUntil             common.LifecycleEvent\n\t\tpingRequestTextAssert func(result string, pingCount int)\n\t\tpingJSTextAssert      func(result string)\n\t}{\n\t\t{\n\t\t\tname:         \"load\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventLoad,\n\t\t\tpingRequestTextAssert: func(result string, pingCount int) {\n\t\t\t\tassert.NotEqualValues(t, fmt.Sprintf(\"Waiting... pong %d - for loop complete\", pingCount), result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"domcontentloaded\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   true,\n\t\t\twaitUntil:    common.LifecycleEventDOMContentLoad,\n\t\t\tpingRequestTextAssert: func(result string, pingCount int) {\n\t\t\t\tassert.NotEqualValues(t, fmt.Sprintf(\"Waiting... pong %d - for loop complete\", pingCount), result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"Waiting...\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"networkidle\",\n\t\t\tpingSlowness: 0,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventNetworkIdle,\n\t\t\tpingRequestTextAssert: func(result string, pingCount int) {\n\t\t\t\tassert.EqualValues(t, fmt.Sprintf(\"Waiting... pong %d - for loop complete\", pingCount), result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\twithHomeHandler(t, tb, \"lifecycle.html?pingCount=10\")\n\t\t\twithPingHandler(t, tb, tt.pingSlowness, nil)\n\t\t\twithPingJSHandler(t, tb, tt.pingJSSlow, nil, false)\n\n\t\t\tassertHome(t, tb, p, tt.waitUntil, func() error {\n\t\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingRequestTextAssert(result, 10)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingJSTextAssert(result)\n\n\t\t\t\topts := &common.PageReloadOptions{\n\t\t\t\t\tWaitUntil: tt.waitUntil,\n\t\t\t\t\tTimeout:   30 * time.Second,\n\t\t\t\t}\n\t\t\t\t_, err = p.Reload(opts)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingRequestTextAssert(result, 20)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingJSTextAssert(result)\n\n\t\t\t\treturn nil\n\t\t\t}, nil, \"\")\n\t\t})\n\t}\n}\n\nfunc TestLifecycleGotoWithSubFrame(t *testing.T) {\n\tt.Parallel()\n\n\t// Test description\n\t//\n\t// Steps:\n\t//   1. goto /home (with iframe to /sub) and wait for the specified lifecycle event.\n\t//\n\t// Success criteria:\n\t//   The web page (all frames) is in the expected state\n\t//   once we receive the specified lifecycle event from\n\t//   the browser.\n\n\ttests := []struct {\n\t\tname                  string\n\t\tpingSlowness          time.Duration\n\t\tpingJSSlow            bool\n\t\twaitUntil             common.LifecycleEvent\n\t\tpingRequestTextAssert func(result string)\n\t\tpingJSTextAssert      func(result string)\n\t}{\n\t\t{\n\t\t\tname:         \"load\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventLoad,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.NotEqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"domcontentloaded\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   true,\n\t\t\twaitUntil:    common.LifecycleEventDOMContentLoad,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.NotEqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"Waiting...\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"networkidle\",\n\t\t\tpingSlowness: 0,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventNetworkIdle,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\twithHomeHandler(t, tb, \"lifecycle_main_frame.html\")\n\t\t\twithSubHandler(t, tb, \"lifecycle.html?pingCount=10\")\n\t\t\twithPingHandler(t, tb, tt.pingSlowness, nil)\n\t\t\twithPingJSHandler(t, tb, tt.pingJSSlow, nil, true)\n\n\t\t\tassertHome(t, tb, p, tt.waitUntil, func() error {\n\t\t\t\tresult, _, err := p.TextContent(\"#subFramePingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingRequestTextAssert(result)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#subFramePingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingJSTextAssert(result)\n\n\t\t\t\treturn nil\n\t\t\t}, nil, \"\")\n\t\t})\n\t}\n}\n\nfunc TestLifecycleGoto(t *testing.T) {\n\tt.Parallel()\n\n\t// Test description\n\t//\n\t// Steps:\n\t//   1. goto /home and wait for the specified lifecycle event.\n\t//\n\t// Success criteria:\n\t//   The web page is in the expected state once we receive\n\t//   the specified lifecycle event from the browser.\n\n\ttests := []struct {\n\t\tname                  string\n\t\tpingSlowness          time.Duration\n\t\tpingJSSlow            bool\n\t\twaitUntil             common.LifecycleEvent\n\t\tpingRequestTextAssert func(result string)\n\t\tpingJSTextAssert      func(result string)\n\t}{\n\t\t{\n\t\t\tname:         \"load\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   false,\n\t\t\twaitUntil:    common.LifecycleEventLoad,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.NotEqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:         \"domcontentloaded\",\n\t\t\tpingSlowness: 100 * time.Millisecond,\n\t\t\tpingJSSlow:   true,\n\t\t\twaitUntil:    common.LifecycleEventDOMContentLoad,\n\t\t\tpingRequestTextAssert: func(result string) {\n\t\t\t\tassert.NotEqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\t\t\t},\n\t\t\tpingJSTextAssert: func(result string) {\n\t\t\t\tassert.EqualValues(t, \"Waiting...\", result)\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\twithHomeHandler(t, tb, \"lifecycle.html?pingCount=10\")\n\t\t\twithPingHandler(t, tb, tt.pingSlowness, nil)\n\t\t\twithPingJSHandler(t, tb, tt.pingJSSlow, nil, false)\n\n\t\t\tassertHome(t, tb, p, tt.waitUntil, func() error {\n\t\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingRequestTextAssert(result)\n\n\t\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\ttt.pingJSTextAssert(result)\n\n\t\t\t\treturn nil\n\t\t\t}, nil, \"\")\n\t\t})\n\t}\n}\n\nfunc TestLifecycleGotoNetworkIdle(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"doesn't timeout waiting for networkIdle\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\tp := tb.NewPage(nil)\n\t\ttb.withHandler(\"/home\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t_, err := fmt.Fprintf(w, `\n\t\t\t<html>\n\t\t\t\t<head></head>\n\t\t\t\t<body>\n\t\t\t\t\t<div id=\"pingJSText\">Waiting...</div>\n\t\t\t\t\t<script src=\"/ping.js\" async></script>\n\t\t\t\t</body>\n\t\t\t</html>\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\twithPingJSHandler(t, tb, false, nil, false)\n\n\t\tassertHome(t, tb, p, common.LifecycleEventNetworkIdle, func() error {\n\t\t\tresult, _, err := p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\n\t\t\treturn nil\n\t\t}, nil, \"\")\n\t})\n\n\tt.Run(\"doesn't unblock wait for networkIdle too early\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\twithHomeHandler(t, tb, \"lifecycle.html?pingCount=4\")\n\t\tch := make(chan bool)\n\t\twithPingHandler(t, tb, 50*time.Millisecond, ch)\n\t\twithPingJSHandler(t, tb, false, ch, false)\n\n\t\tassertHome(t, tb, p, common.LifecycleEventNetworkIdle, func() error {\n\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tassert.EqualValues(t, \"Waiting... pong 4 - for loop complete\", result)\n\n\t\t\tresult, _, err = p.TextContent(\"#pingJSText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tassert.EqualValues(t, \"ping.js loaded from server\", result)\n\n\t\t\treturn nil\n\t\t}, nil, \"\")\n\t})\n\n\tt.Run(\"doesn't unblock wait on networkIdle early when load and domcontentloaded complete at once\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\twithHomeHandler(t, tb, \"lifecycle_no_ping_js.html\")\n\t\twithPingHandler(t, tb, 50*time.Millisecond, nil)\n\n\t\tassertHome(t, tb, p, common.LifecycleEventNetworkIdle, func() error {\n\t\t\tresult, _, err := p.TextContent(\"#pingRequestText\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tassert.EqualValues(t, \"Waiting... pong 10 - for loop complete\", result)\n\n\t\t\treturn nil\n\t\t}, nil, \"\")\n\t})\n}\n\nfunc withHomeHandler(t *testing.T, tb *testBrowser, htmlFile string) {\n\tt.Helper()\n\n\ttb.withHandler(\"/home\", func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, tb.staticURL(htmlFile), http.StatusMovedPermanently)\n\t})\n}\n\nfunc withSubHandler(t *testing.T, tb *testBrowser, htmlFile string) {\n\tt.Helper()\n\n\ttb.withHandler(\"/sub\", func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, tb.staticURL(htmlFile), http.StatusMovedPermanently)\n\t})\n}\n\nfunc withPingHandler(t *testing.T, tb *testBrowser, slow time.Duration, ch chan bool) {\n\tt.Helper()\n\n\tvar counter int64\n\tvar counterMu sync.Mutex\n\ttb.withHandler(\"/ping\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tif ch != nil {\n\t\t\t<-ch\n\t\t}\n\n\t\tcounterMu.Lock()\n\t\tdefer counterMu.Unlock()\n\n\t\ttime.Sleep(slow)\n\n\t\tcounter++\n\t\t_, err := fmt.Fprintf(w, \"pong %d\", counter)\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc withPingJSHandler(t *testing.T, tb *testBrowser, slow bool, ch chan bool, withSubFrame bool) {\n\tt.Helper()\n\n\ttb.withHandler(\"/ping.js\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tscript := `\n\t\t\tvar pingJSTextOutput = document.getElementById(\"pingJSText\");\n\t\t\tpingJSTextOutput.innerText = \"ping.js loaded from server\";\n\t\t`\n\t\tif withSubFrame {\n\t\t\tscript += `\n\n\t\t\tvar parentOutputServerMsg = window.parent.document.getElementById('subFramePingJSText');\n\t\t\tparentOutputServerMsg.innerText = pingJSTextOutput.innerText;\n\t\t\t`\n\t\t}\n\t\tif slow {\n\t\t\tscript = `\n\t\t\tawait new Promise(resolve => setTimeout(resolve, 1000));\n\n\t\t\t` + script\n\t\t}\n\t\t_, err := fmt.Fprint(w, script)\n\t\trequire.NoError(t, err)\n\n\t\tif ch != nil {\n\t\t\tclose(ch)\n\t\t}\n\t})\n}\n\nfunc assertHome(\n\tt *testing.T,\n\ttb *testBrowser, p *common.Page,\n\twaitUntil common.LifecycleEvent,\n\tcheck func() error, secondCheck func(), wantError string,\n) {\n\tt.Helper()\n\n\tvar resolved, rejected bool\n\terr := func() error {\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: waitUntil,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(tb.url(\"/home\"), opts)\n\t\tif err == nil {\n\t\t\tresolved = true\n\t\t} else {\n\t\t\trejected = true\n\t\t}\n\n\t\terr = check()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif secondCheck != nil {\n\t\t\tsecondCheck()\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tif wantError != \"\" {\n\t\trequire.EqualError(t, err, wantError)\n\t\treturn\n\t}\n\n\trequire.NoError(t, err)\n\n\tassert.True(t, resolved)\n\tassert.False(t, rejected)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/locator_test.go",
    "content": "// practically none of this work on windows\n//go:build !windows\n\npackage tests\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/browser\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// Strict mode:\n// All operations on locators throw an exception if more\n// than one element matches the locator's selector.\n\n// Note:\n// We skip adding t.Parallel to subtests because sobek or our code might race.\n\nfunc TestLocator(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname string\n\t\tdo   func(*testBrowser, *common.Page)\n\t}{\n\t\t{\n\t\t\t\"All\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlocators, err := p.Locator(\"a\", nil).All()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, locators, 3)\n\n\t\t\t\tfirstText, err := locators[0].InnerText(common.NewFrameInnerTextOptions(locators[0].Timeout()))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, `Click`, firstText)\n\n\t\t\t\tsecondText, err := locators[1].InnerText(common.NewFrameInnerTextOptions(locators[1].Timeout()))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, `Dblclick`, secondText)\n\n\t\t\t\tthirdText, err := locators[2].InnerText(common.NewFrameInnerTextOptions(locators[2].Timeout()))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, `Click`, thirdText)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"BoundingBox\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\trect, err := p.Locator(\"#divHello\", nil).BoundingBox(&common.FrameBaseOptions{\n\t\t\t\t\tTimeout: p.Timeout(),\n\t\t\t\t})\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.GreaterOrEqual(t, rect.X, 0.0)\n\t\t\t\tassert.GreaterOrEqual(t, rect.Y, 0.0)\n\t\t\t\tassert.GreaterOrEqual(t, rect.Width, 0.0)\n\t\t\t\tassert.GreaterOrEqual(t, rect.Height, 0.0)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Check\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tcheck := func() bool {\n\t\t\t\t\tv, err := p.Evaluate(`() => window.check`)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn asBool(t, v)\n\t\t\t\t}\n\t\t\t\tt.Run(\"check\", func(t *testing.T) {\n\t\t\t\t\tl := p.Locator(\"#inputCheckbox\", nil)\n\t\t\t\t\trequire.False(t, check(), \"should be unchecked first\")\n\t\t\t\t\trequire.NoError(t, l.Check(common.NewFrameCheckOptions(l.Timeout())))\n\t\t\t\t\trequire.True(t, check(), \"cannot not check the input box\")\n\t\t\t\t\trequire.NoError(t, l.Uncheck(common.NewFrameUncheckOptions(l.Timeout())))\n\t\t\t\t\trequire.False(t, check(), \"cannot not uncheck the input box\")\n\t\t\t\t})\n\t\t\t\tt.Run(\"setChecked\", func(t *testing.T) {\n\t\t\t\t\tl := p.Locator(\"#inputCheckbox\", nil)\n\t\t\t\t\trequire.False(t, check(), \"should be unchecked first\")\n\t\t\t\t\trequire.NoError(t, l.SetChecked(true, common.NewFrameCheckOptions(l.Timeout())))\n\t\t\t\t\trequire.True(t, check(), \"cannot not check the input box\")\n\t\t\t\t\trequire.NoError(t, l.SetChecked(false, common.NewFrameCheckOptions(l.Timeout())))\n\t\t\t\t\trequire.False(t, check(), \"cannot not uncheck the input box\")\n\t\t\t\t})\n\t\t\t\tt.Run(\"is_checked\", func(t *testing.T) {\n\t\t\t\t\tl := p.Locator(\"#inputCheckbox\", nil)\n\t\t\t\t\trequire.NoError(t, l.Check(common.NewFrameCheckOptions(l.Timeout())))\n\t\t\t\t\tchecked, err := l.IsChecked(common.NewFrameIsCheckedOptions(l.Timeout()))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.True(t, checked)\n\n\t\t\t\t\trequire.NoError(t, l.Uncheck(common.NewFrameUncheckOptions(l.Timeout())))\n\t\t\t\t\tchecked, err = l.IsChecked(common.NewFrameIsCheckedOptions(l.Timeout()))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.False(t, checked)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Clear\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tconst value = \"fill me up\"\n\t\t\t\tl := p.Locator(\"#inputText\", nil)\n\n\t\t\t\trequire.NoError(t, l.Fill(value, common.NewFrameFillOptions(l.Timeout())))\n\t\t\t\tinputValue, err := p.InputValue(\"#inputText\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, value, inputValue)\n\n\t\t\t\terr = l.Clear(common.NewFrameFillOptions(l.Timeout()))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tinputValue, err = p.InputValue(\"#inputText\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"\", inputValue)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Click\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tl := p.Locator(\"#link\", nil)\n\t\t\t\terr := l.Click(common.NewFrameClickOptions(l.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tv, err := p.Evaluate(`() => window.result`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.True(t, asBool(t, v), \"cannot not click the link\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Dblclick\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlo := p.Locator(\"#linkdbl\", nil)\n\t\t\t\trequire.NoError(t, lo.Dblclick(common.NewFrameDblClickOptions(lo.Timeout())))\n\n\t\t\t\tv, err := p.Evaluate(`() => window.dblclick`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.True(t, asBool(t, v), \"cannot double click the link\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"DispatchEvent\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tresult := func() bool {\n\t\t\t\t\tv, err := p.Evaluate(`() => window.result`)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn asBool(t, v)\n\t\t\t\t}\n\t\t\t\trequire.False(t, result(), \"should not be clicked first\")\n\n\t\t\t\tlo := p.Locator(\"#link\", nil)\n\t\t\t\topts := common.NewFrameDispatchEventOptions(0) // no timeout\n\t\t\t\trequire.NoError(t, lo.DispatchEvent(\"click\", \"mouseevent\", opts))\n\t\t\t\trequire.True(t, result(), \"cannot not dispatch event\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Fill\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tconst value = \"fill me up\"\n\t\t\t\tlo := p.Locator(\"#inputText\", nil)\n\t\t\t\trequire.NoError(t, lo.Fill(value, common.NewFrameFillOptions(lo.Timeout())))\n\t\t\t\tinputValue, err := p.InputValue(\"#inputText\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, value, inputValue)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"FillTextarea\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tconst value = \"fill me up\"\n\t\t\t\tlo := p.Locator(\"textarea\", nil)\n\t\t\t\trequire.NoError(t, lo.Fill(value, common.NewFrameFillOptions(lo.Timeout())))\n\t\t\t\tinputValue, err := p.InputValue(\"textarea\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, value, inputValue)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"FillParagraph\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tconst value = \"fill me up\"\n\t\t\t\tlo := p.Locator(\"#firstParagraph\", nil)\n\t\t\t\trequire.NoError(t, lo.Fill(value, common.NewFrameFillOptions(lo.Timeout())))\n\t\t\t\ttextContent, ok, err := p.TextContent(\"#firstParagraph\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\trequire.Equal(t, value, textContent)\n\t\t\t\tlo = p.Locator(\"#secondParagraph\", nil)\n\t\t\t\trequire.Error(t, lo.Fill(value, common.NewFrameFillOptions(lo.Timeout())))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"First\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tfirst := p.Locator(\"a\", nil).First()\n\t\t\t\ttext, err := first.InnerText(common.NewFrameInnerTextOptions(first.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, `Click`, text)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Focus\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tfocused := func() bool {\n\t\t\t\t\tv, err := p.Evaluate(\n\t\t\t\t\t\t`() => document.activeElement == document.getElementById('inputText')`,\n\t\t\t\t\t)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn asBool(t, v)\n\t\t\t\t}\n\t\t\t\tlo := p.Locator(\"#inputText\", nil)\n\t\t\t\trequire.False(t, focused(), \"should not be focused first\")\n\t\t\t\trequire.NoError(t, lo.Focus(common.NewFrameBaseOptions(lo.Timeout())))\n\t\t\t\trequire.True(t, focused(), \"should be focused\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"GetAttribute\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tl := p.Locator(\"#inputText\", nil)\n\t\t\t\tv, ok, err := l.GetAttribute(\"value\", common.NewFrameBaseOptions(l.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotNil(t, v)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\trequire.Equal(t, \"something\", v)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Hover\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tresult := func() bool {\n\t\t\t\t\tv, err := p.Evaluate(`() => window.result`)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn asBool(t, v)\n\t\t\t\t}\n\t\t\t\trequire.False(t, result(), \"should not be hovered first\")\n\t\t\t\tlo := p.Locator(\"#inputText\", nil)\n\t\t\t\trequire.NoError(t, lo.Hover(common.NewFrameHoverOptions(lo.Timeout())))\n\t\t\t\trequire.True(t, result(), \"should be hovered\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"InnerHTML\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tdivHello := p.Locator(\"#divHello\", nil)\n\t\t\t\thtml, err := divHello.InnerHTML(common.NewFrameInnerHTMLOptions(divHello.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, `<span>hello</span>`, html)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"InnerText\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tspan := p.Locator(\"#divHello > span\", nil)\n\t\t\t\ttext, err := span.InnerText(common.NewFrameInnerTextOptions(span.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, `hello`, text)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"InputValue\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tt.Run(\"input\", func(t *testing.T) {\n\t\t\t\t\tinput := p.Locator(\"#inputText\", nil)\n\t\t\t\t\tv, err := input.InputValue(common.NewFrameInputValueOptions(input.Timeout()))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, \"something\", v)\n\t\t\t\t})\n\t\t\t\tt.Run(\"textarea\", func(t *testing.T) {\n\t\t\t\t\ttextarea := p.Locator(\"textarea\", nil)\n\t\t\t\t\tv, err := textarea.InputValue(common.NewFrameInputValueOptions(textarea.Timeout()))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, \"text area\", v)\n\t\t\t\t})\n\t\t\t\tt.Run(\"select\", func(t *testing.T) {\n\t\t\t\t\tselectElement := p.Locator(\"#selectElement\", nil)\n\t\t\t\t\tv, err := selectElement.InputValue(common.NewFrameInputValueOptions(selectElement.Timeout()))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Equal(t, \"option text\", v)\n\t\t\t\t})\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Last\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlast := p.Locator(\"div\", nil).Last()\n\t\t\t\ttext, err := last.InnerText(common.NewFrameInnerTextOptions(last.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, `bye`, text)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Nth\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tnth := p.Locator(\"a\", nil).Nth(0)\n\t\t\t\ttext, err := nth.InnerText(common.NewFrameInnerTextOptions(nth.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, `Click`, text)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Press\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlo := p.Locator(\"#inputText\", nil)\n\t\t\t\trequire.NoError(t, lo.Press(\"x\", common.NewFramePressOptions(lo.Timeout())))\n\t\t\t\tinputValue, err := p.InputValue(\"#inputText\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, \"xsomething\", inputValue)\n\t\t\t},\n\t\t},\n\n\t\t{\n\t\t\t\"PressSequentially\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlo := p.Locator(\"#inputText\", nil)\n\t\t\t\trequire.NoError(t, lo.Clear(common.NewFrameFillOptions(lo.Timeout())))\n\n\t\t\t\trequire.NoError(t, lo.PressSequentially(\"hello\", common.NewFrameTypeOptions(lo.Timeout())))\n\n\t\t\t\tvalue, err := p.InputValue(\"#inputText\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, \"hello\", value)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"PressSequentiallyWithDelayOption\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlo := p.Locator(\"#inputText\", nil)\n\t\t\t\trequire.NoError(t, lo.Clear(common.NewFrameFillOptions(lo.Timeout())))\n\n\t\t\t\topts := common.NewFrameTypeOptions(lo.Timeout())\n\t\t\t\topts.Delay = 100\n\n\t\t\t\trequire.NoError(t, lo.PressSequentially(\"text\", opts))\n\n\t\t\t\tvalue, err := p.InputValue(\"#inputText\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, \"text\", value)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"PressSequentiallyTextarea\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlo := p.Locator(\"textarea\", nil)\n\t\t\t\trequire.NoError(t, lo.Clear(common.NewFrameFillOptions(lo.Timeout())))\n\n\t\t\t\trequire.NoError(t, lo.PressSequentially(\"some text\", common.NewFrameTypeOptions(lo.Timeout())))\n\n\t\t\t\tvalue, err := lo.InputValue(common.NewFrameInputValueOptions(lo.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, \"some text\", value)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"SelectOption\", func(tb *testBrowser, p *common.Page) {\n\t\t\t\tl := p.Locator(\"#selectElement\", nil)\n\t\t\t\ta, err := browser.ConvertSelectOptionValues(tb.vu.Runtime(), tb.toSobekValue(`option text 2`))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trv, err := l.SelectOption(a, common.NewFrameSelectOptionOptions(l.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Len(t, rv, 1)\n\t\t\t\trequire.Equal(t, \"option text 2\", rv[0])\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Tap\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tresult := func() bool {\n\t\t\t\t\tv, err := p.Evaluate(`() => window.result`)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn asBool(t, v)\n\t\t\t\t}\n\t\t\t\trequire.False(t, result(), \"should not be tapped first\")\n\t\t\t\topts := common.NewFrameTapOptions(common.DefaultTimeout)\n\t\t\t\terr := p.Locator(\"#inputText\", nil).Tap(opts)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.True(t, result(), \"should be tapped\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"TextContent\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tdivHello := p.Locator(\"#divHello\", nil)\n\t\t\t\ttext, ok, err := divHello.TextContent(common.NewFrameTextContentOptions(divHello.Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\trequire.Equal(t, `hello`, text)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Type\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tlo := p.Locator(\"#inputText\", nil)\n\t\t\t\trequire.NoError(t, lo.Type(\"real \", common.NewFrameTypeOptions(lo.Timeout())))\n\t\t\t\tinputValue, err := p.InputValue(\"#inputText\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, \"real something\", inputValue)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"WaitFor state:visible\", func(tb *testBrowser, p *common.Page) {\n\t\t\t\topts := common.NewFrameWaitForSelectorOptions(100 * time.Millisecond)\n\t\t\t\tlo := p.Locator(\"#link\", nil)\n\t\t\t\trequire.NoError(t, lo.WaitFor(opts))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"WaitFor state:attached\", func(tb *testBrowser, p *common.Page) {\n\t\t\t\topts := common.NewFrameWaitForSelectorOptions(100 * time.Millisecond)\n\t\t\t\topts.State = common.DOMElementStateAttached\n\t\t\t\tlo := p.Locator(\"#link\", nil)\n\t\t\t\trequire.NoError(t, lo.WaitFor(opts))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"WaitFor state:hidden\", func(tb *testBrowser, p *common.Page) {\n\t\t\t\topts := common.NewFrameWaitForSelectorOptions(100 * time.Millisecond)\n\t\t\t\topts.State = common.DOMElementStateHidden\n\t\t\t\tlo := p.Locator(\"#inputHiddenText\", nil)\n\t\t\t\trequire.NoError(t, lo.WaitFor(opts))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"WaitFor state:detached\", func(tb *testBrowser, p *common.Page) {\n\t\t\t\topts := common.NewFrameWaitForSelectorOptions(100 * time.Millisecond)\n\t\t\t\topts.State = common.DOMElementStateDetached\n\t\t\t\tlo := p.Locator(\"#nonExistingElement\", nil)\n\t\t\t\trequire.NoError(t, lo.WaitFor(opts))\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := p.Goto(\n\t\t\t\ttb.staticURL(\"locators.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\ttt.do(tb, p)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n\n\tsanityTests := []struct {\n\t\tname string\n\t\tdo   func(*common.Locator, *testBrowser) error\n\t}{\n\t\t{\n\t\t\t\"BoundingBox\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.BoundingBox(common.NewFrameBaseOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Check\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Check(common.NewFrameCheckOptions(100 * time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Clear\", func(l *common.Locator, _ *testBrowser) error {\n\t\t\t\topts := common.NewFrameFillOptions(100 * time.Millisecond)\n\t\t\t\treturn l.Clear(opts)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Click\", func(l *common.Locator, _ *testBrowser) error {\n\t\t\t\topts := common.NewFrameClickOptions(100 * time.Millisecond)\n\t\t\t\treturn l.Click(opts)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Dblclick\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Dblclick(common.NewFrameDblClickOptions(100 * time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"DispatchEvent\", func(l *common.Locator, _ *testBrowser) error {\n\t\t\t\topts := common.NewFrameDispatchEventOptions(100 * time.Millisecond)\n\t\t\t\treturn l.DispatchEvent(\"click\", \"mouseevent\", opts)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Focus\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Focus(common.NewFrameBaseOptions(100 * time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Fill\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Fill(\"fill me up\", common.NewFrameFillOptions(100*time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"GetAttribute\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, _, err := l.GetAttribute(\"value\", common.NewFrameBaseOptions(100*time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Hover\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Hover(common.NewFrameHoverOptions(100 * time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"InnerHTML\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.InnerHTML(common.NewFrameInnerHTMLOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"InnerText\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.InnerText(common.NewFrameInnerTextOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"InputValue\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.InputValue(common.NewFrameInputValueOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Press\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Press(\"a\", common.NewFramePressOptions(100*time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"PressSequentially\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.PressSequentially(\"text\", common.NewFrameTypeOptions(100*time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"SetChecked\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.SetChecked(true, common.NewFrameCheckOptions(100*time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"SelectOption\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.SelectOption([]any{\"\"}, common.NewFrameSelectOptionOptions(100*time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Tap\", func(l *common.Locator, _ *testBrowser) error {\n\t\t\t\topts := common.NewFrameTapOptions(100 * time.Millisecond)\n\t\t\t\treturn l.Tap(opts)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Type\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Type(\"a\", common.NewFrameTypeOptions(100*time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"TextContent\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, _, err := l.TextContent(common.NewFrameTextContentOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"Uncheck\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.Uncheck(common.NewFrameUncheckOptions(100 * time.Millisecond))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"WaitFor\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\treturn l.WaitFor(common.NewFrameWaitForSelectorOptions(100 * time.Millisecond))\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range sanityTests {\n\t\tt.Run(\"timeout/\"+tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\tp := tb.NewPage(nil)\n\t\t\terr := p.SetContent(\"<html></html>\", nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Error(t, tt.do(p.Locator(\"NOTEXIST\", nil), tb))\n\t\t})\n\t}\n\n\tfor _, tt := range sanityTests {\n\t\tt.Run(\"strict/\"+tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := p.Goto(\n\t\t\t\ttb.staticURL(\"locators.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Error(t, tt.do(p.Locator(\"a\", nil), tb))\n\t\t})\n\t}\n}\n\nfunc TestLocatorElementState(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tstate, eval string\n\t\tquery       func(*common.Locator) (bool, error)\n\t}{\n\t\t{\n\t\t\t\"disabled\",\n\t\t\t`() => document.getElementById('inputText').disabled = true`,\n\t\t\tfunc(l *common.Locator) (bool, error) {\n\t\t\t\tresp, err := l.IsDisabled(common.NewFrameIsDisabledOptions(l.Timeout()))\n\t\t\t\treturn !resp, err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"enabled\",\n\t\t\t`() => document.getElementById('inputText').disabled = true`,\n\t\t\tfunc(l *common.Locator) (bool, error) {\n\t\t\t\tresp, err := l.IsEnabled(common.NewFrameIsEnabledOptions(l.Timeout()))\n\t\t\t\treturn resp, err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"hidden\",\n\t\t\t`() => document.getElementById('inputText').style.visibility = 'hidden'`,\n\t\t\tfunc(l *common.Locator) (bool, error) {\n\t\t\t\tresp, err := l.IsHidden()\n\t\t\t\treturn !resp, err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"readOnly\",\n\t\t\t`() => document.getElementById('inputText').readOnly = true`,\n\t\t\tfunc(l *common.Locator) (bool, error) {\n\t\t\t\tresp, err := l.IsEditable(common.NewFrameIsEditableOptions(l.Timeout()))\n\t\t\t\treturn resp, err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"visible\",\n\t\t\t`() => document.getElementById('inputText').style.visibility = 'hidden'`,\n\t\t\tfunc(l *common.Locator) (bool, error) {\n\t\t\t\tresp, err := l.IsVisible()\n\t\t\t\treturn resp, err\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.state, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := p.Goto(\n\t\t\t\ttb.staticURL(\"locators.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tl := p.Locator(\"#inputText\", nil)\n\t\t\tresult, err := tt.query(l)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.True(t, result)\n\n\t\t\t_, err = p.Evaluate(tt.eval)\n\t\t\trequire.NoError(t, err)\n\t\t\tresult, err = tt.query(l)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.False(t, result)\n\t\t})\n\t}\n\n\tsanityTests := []struct {\n\t\tname string\n\t\tdo   func(*common.Locator, *testBrowser) error\n\t}{\n\t\t{\n\t\t\t\"IsChecked\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.IsChecked(common.NewFrameIsCheckedOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"IsEditable\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.IsEditable(common.NewFrameIsEditableOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"IsEnabled\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.IsEnabled(common.NewFrameIsEnabledOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t\"IsDisabled\", func(l *common.Locator, tb *testBrowser) error {\n\t\t\t\t_, err := l.IsDisabled(common.NewFrameIsDisabledOptions(100 * time.Millisecond))\n\t\t\t\treturn err\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range sanityTests {\n\t\tt.Run(\"timeout/\"+tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\tp := tb.NewPage(nil)\n\t\t\terr := p.SetContent(\"<html></html>\", nil)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Error(t, tt.do(p.Locator(\"NOTEXIST\", nil), tb))\n\t\t})\n\t}\n\n\tfor _, tt := range sanityTests {\n\t\tt.Run(\"strict/\"+tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := p.Goto(\n\t\t\t\ttb.staticURL(\"locators.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Error(t, tt.do(p.Locator(\"a\", nil), tb))\n\t\t})\n\t}\n}\n\nfunc TestLocatorPress(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(`<input id=\"text1\">`, nil)\n\trequire.NoError(t, err)\n\n\tl := p.Locator(\"#text1\", nil)\n\n\trequire.NoError(t, l.Press(\"Shift+KeyA\", common.NewFramePressOptions(l.Timeout())))\n\trequire.NoError(t, l.Press(\"KeyB\", common.NewFramePressOptions(l.Timeout())))\n\trequire.NoError(t, l.Press(\"Shift+KeyC\", common.NewFramePressOptions(l.Timeout())))\n\n\tv, err := l.InputValue(common.NewFrameInputValueOptions(l.Timeout()))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"AbC\", v)\n}\n\nfunc TestLocatorShadowDOM(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\tp := tb.NewPage(nil)\n\n\tpopts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(\n\t\ttb.staticURL(\"shadow_dom_link.html\"),\n\t\tpopts,\n\t)\n\trequire.NoError(t, err)\n\terr = p.Click(\"#inner-link\", common.NewFrameClickOptions(time.Second))\n\trequire.NoError(t, err)\n}\n\nfunc TestSelectOption(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\n\tgot := tb.vu.RunPromise(t, `\n\t\tconst page = await browser.newPage();\n\n\t\tawait page.goto('%s');\n\n\t\tconst options = page.locator('#numbers-options');\n\n\t\tawait options.selectOption({label:'Five'});\n\t\tlet selectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'five') {\n\t\t\tthrow new Error('Expected \"five\" but got ' + selectedValue);\n\t\t}\n\n\t\tawait options.selectOption({index:5});\n\t\tselectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'five') {\n\t\t\tthrow new Error('Expected \"five\" but got ' + selectedValue);\n\t\t}\n\n\t\tawait options.selectOption({value:'four'});\n\t\tselectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'four') {\n\t\t\tthrow new Error('Expected \"four\" but got ' + selectedValue);\n\t\t}\n\n\t\tawait options.selectOption([{label:'One'}]);\n\t\tselectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'one') {\n\t\t\tthrow new Error('Expected \"one\" but got ' + selectedValue);\n\t\t}\n\n\t\tawait options.selectOption(['two']); // Value\n\t\tselectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'two') {\n\t\t\tthrow new Error('Expected \"two\" but got ' + selectedValue);\n\t\t}\n\n\t\tawait options.selectOption('five'); // Value\n\t\tselectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'five') {\n\t\t\tthrow new Error('Expected \"five\" but got ' + selectedValue);\n\t\t}\n\n\t\tawait options.selectOption(['Three']); // Label\n\t\tselectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'three') {\n\t\t\tthrow new Error('Expected \"three\" but got ' + selectedValue);\n\t\t}\n\n\t\tawait options.selectOption('Five'); // Label\n\t\tselectedValue = await options.inputValue();\n\t\tif (selectedValue !== 'five') {\n\t\t\tthrow new Error('Expected \"five\" but got ' + selectedValue);\n\t\t}\n\n\t\tconst results = await options.selectOption(['One', 'two']); // Both label and value\n\t\tif (results.length !== 2 || !results.includes('one') || !results.includes('two')) {\n\t\t\tthrow new Error('Expected \"one,two\" but got ' + results);\n\t\t}\n\t`, tb.staticURL(\"select_options.html\"))\n\tassert.Equal(t, sobek.Undefined(), got.Result())\n}\n\nfunc TestCount(t *testing.T) {\n\tt.Parallel()\n\n\tiframeID := \"frameB\"\n\n\tsetupNonCORS := func(t *testing.T) (*testBrowser, *common.Page) {\n\t\tt.Helper()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\n\t\tp := tb.NewPage(nil)\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(\n\t\t\ttb.staticURL(\"locators.html\"),\n\t\t\topts,\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\treturn tb, p\n\t}\n\n\tsetupCORS := func(t *testing.T) (*testBrowser, *common.Page) {\n\t\tt.Helper()\n\n\t\tiframeHTML := `<!DOCTYPE html>\n\t\t<html>\n\t\t<head></head>\n\t\t<body>\n\t\t\t<button id=\"incrementB\">Increment Counter B</button>\n\t\t</body>\n\t\t</html>`\n\n\t\ttb := newTestBrowser(t, withIFrameContent(iframeHTML, iframeID))\n\n\t\tp := tb.GotoNewPage(tb.url(\"/iframe\"))\n\n\t\treturn tb, p\n\t}\n\n\ttests := []struct {\n\t\tname          string\n\t\tsetup         func(*testing.T) (*testBrowser, *common.Page)\n\t\tdo            func(*testBrowser, *common.Page) (int, error)\n\t\texpectedCount int\n\t}{\n\t\t{\n\t\t\tname:  \"0\",\n\t\t\tsetup: setupNonCORS,\n\t\t\tdo: func(_ *testBrowser, p *common.Page) (int, error) {\n\t\t\t\tl := p.Locator(\"#NOTEXIST\", nil)\n\t\t\t\treturn l.Count()\n\t\t\t},\n\t\t\texpectedCount: 0,\n\t\t},\n\t\t{\n\t\t\tname:  \"1\",\n\t\t\tsetup: setupNonCORS,\n\t\t\tdo: func(_ *testBrowser, p *common.Page) (int, error) {\n\t\t\t\tl := p.Locator(\"#link\", nil)\n\t\t\t\treturn l.Count()\n\t\t\t},\n\t\t\texpectedCount: 1,\n\t\t},\n\t\t{\n\t\t\tname:  \"3\",\n\t\t\tsetup: setupNonCORS,\n\t\t\tdo: func(_ *testBrowser, p *common.Page) (int, error) {\n\t\t\t\tl := p.Locator(\"a\", nil)\n\t\t\t\treturn l.Count()\n\t\t\t},\n\t\t\texpectedCount: 3,\n\t\t},\n\t\t{\n\t\t\tname:  \"CORS\",\n\t\t\tsetup: setupCORS,\n\t\t\tdo: func(_ *testBrowser, p *common.Page) (int, error) {\n\t\t\t\tframeBContent := p.Locator(\"#\"+iframeID, nil).ContentFrame()\n\t\t\t\treturn frameBContent.Locator(\"#incrementB\", nil).Count()\n\t\t\t},\n\t\t\texpectedCount: 1,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb, p := tt.setup(t)\n\n\t\t\tc, err := tt.do(tb, p)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.expectedCount, c)\n\t\t})\n\t}\n}\n\nfunc TestReactInput(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname string\n\t\tdo   func(*testBrowser, *common.Page)\n\t}{\n\t\t{\n\t\t\t\"Fill\", func(_ *testBrowser, p *common.Page) {\n\t\t\t\tconst value = \"test@example.com\"\n\t\t\t\tlo := p.Locator(\"input[placeholder='Username or email']\", nil)\n\t\t\t\trequire.NoError(t, lo.Fill(value, common.NewFrameFillOptions(lo.Timeout())))\n\t\t\t\tinputValue, err := p.InnerText(\"p[id='react-state']\", common.NewFrameInnerTextOptions(p.MainFrame().Timeout()))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, fmt.Sprintf(\"React state: %q\", value), inputValue)\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := p.Goto(\n\t\t\t\ttb.staticURL(\"react_input.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\ttt.do(tb, p)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestLocatorNesting(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\n\tp := tb.NewPage(nil)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(\n\t\ttb.staticURL(\"locator_nesting.html\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\n\tqtyLocator := p.Locator(`[data-testid=\"inventory\"]`, nil).\n\t\tLocator(`[data-item=\"apples\"]`, nil).\n\t\tLocator(`.qty`, nil)\n\tq, err := qtyLocator.InnerText(common.NewFrameInnerTextOptions(qtyLocator.Timeout()))\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"0\", q)\n\n\terr = p.Locator(`[data-testid=\"inventory\"]`, nil).\n\t\tLocator(`[data-item=\"apples\"]`, nil).\n\t\tLocator(`button.add`, nil).\n\t\tClick(common.NewFrameClickOptions(common.DefaultTimeout))\n\trequire.NoError(t, err)\n\n\tqtyLocator2 := p.Locator(`[data-testid=\"inventory\"]`, nil).\n\t\tLocator(`[data-item=\"apples\"]`, nil).\n\t\tLocator(`.qty`, nil)\n\tq, err = qtyLocator2.InnerText(common.NewFrameInnerTextOptions(qtyLocator2.Timeout()))\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"1\", q)\n}\n\n// This test ensures that the actionability checks are retried if we receive\n// any visible based errors from chrome. This is done by navigating to a page\n// where a button is hidden and unhidden every animation frame (~60 times per\n// second). We should not be able to click on the button, and if chrome returns\n// an error saying the element is not visible, we should retry. The only error\n// we expect is the timeout error.\nfunc TestActionabilityRetry(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\n\tp := tb.NewPage(nil)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(\n\t\ttb.staticURL(\"hide_unhide.html\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\n\tlo := p.Locator(\"#incBtn\", nil)\n\terr = lo.Click(common.NewFrameClickOptions(1 * time.Second))\n\trequire.ErrorContains(t, err, \"timed out after\")\n\n\tvalue := p.Locator(\"#value\", nil)\n\ttext, err := value.InnerText(common.NewFrameInnerTextOptions(value.Timeout()))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"0\", text)\n}\n\nfunc TestLocatorFilter(t *testing.T) {\n\tt.Parallel()\n\n\tsetupPage := func(t *testing.T) *common.Page {\n\t\tt.Helper()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.SetContent(`\n\t\t\t<section>\n\t\t\t\t<div>\n\t\t\t\t\t<span>hello</span>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<span>world</span>\n\t\t\t\t</div>\n\t\t\t</section>`,\n\t\t\tnil,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\treturn p\n\t}\n\n\tt.Run(\"filter_hasText\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcount, err := setupPage(t).\n\t\t\tLocator(\"div\", nil).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasText: \"hello\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, count)\n\t})\n\n\tt.Run(\"filter_hasText_on_locator_with_hasText\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcount, err := setupPage(t).\n\t\t\tLocator(\"div\", &common.LocatorOptions{\n\t\t\t\tHasText: \"hello\",\n\t\t\t}).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasText: \"hello\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, count)\n\t})\n\n\tt.Run(\"filter_hasText_different_on_locator_with_hasText\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcount, err := setupPage(t).\n\t\t\tLocator(\"div\", &common.LocatorOptions{\n\t\t\t\tHasText: \"hello\",\n\t\t\t}).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasText: \"world\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 0, count)\n\t})\n\n\tt.Run(\"filter_hasText_section_with_world\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcount, err := setupPage(t).\n\t\t\tLocator(\"section\", &common.LocatorOptions{\n\t\t\t\tHasText: \"hello\",\n\t\t\t}).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasText: \"world\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, count)\n\t})\n\n\tt.Run(\"filter_hasText_nested_locator\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcount, err := setupPage(t).\n\t\t\tLocator(\"div\", nil).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasText: \"hello\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tLocator(\"span\", nil).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, count)\n\t})\n\n\tt.Run(\"filter_hasNotText_hello\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcount, err := setupPage(t).\n\t\t\tLocator(\"div\", nil).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasNotText: \"hello\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, count)\n\t})\n\n\tt.Run(\"filter_hasNotText_foo\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcount, err := setupPage(t).\n\t\t\tLocator(\"div\", nil).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasNotText: \"foo\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 2, count)\n\t})\n}\n\nfunc TestFrameLocatorLocatorOptions(t *testing.T) {\n\tt.Parallel()\n\n\t// We'll only test nil and non-nil LocatorOptions here, as the actual\n\t// filtering logic is tested in TestLocatorLocatorOptions. This test\n\t// just ensures that FrameLocator.Locator passes the options down correctly.\n\n\tsetup := func(t *testing.T) *common.FrameLocator {\n\t\tt.Helper()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.SetContent(`\n\t\t\t<iframe srcdoc='\n\t\t\t\t<section>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span>hello</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span>world</span>\n\t\t\t\t\t</div>\n\t\t\t\t</section>\n\t\t\t'></iframe>`,\n\t\t\tnil,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\treturn p.Locator(\"iframe\", nil).ContentFrame()\n\t}\n\tt.Run(\"nil_options\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tn, err := setup(t).\n\t\t\tLocator(\"div\", nil).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 2, n)\n\t})\n\tt.Run(\"options\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tn, err := setup(t).\n\t\t\tLocator(\"div\", &common.LocatorOptions{\n\t\t\t\tHasText: \"hello\",\n\t\t\t}).\n\t\t\tCount()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, n)\n\t})\n}\n\nfunc TestLocatorLocatorOptions(t *testing.T) {\n\tt.Parallel()\n\n\tsetupPage := func(t *testing.T) *common.Page {\n\t\tt.Helper()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.SetContent(`\n\t\t\t<section>\n\t\t\t\t<div>\n\t\t\t\t\t<span>hello</span>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<span>world</span>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<span>good bye</span>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span>moon</span>\n\t\t\t\t\t\t<span>land</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</section>`,\n\t\t\tnil,\n\t\t)\n\t\trequire.NoError(t, err)\n\t\treturn p\n\t}\n\n\tt.Run(\"nil_options\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tloc := setupPage(t).\n\t\t\tLocator(\"div\", nil).\n\t\t\tLocator(\"span\", nil)\n\t\tn, err := loc.Count()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 5, n)\n\t})\n\n\tt.Run(\"options\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Selects the \"moon\" and \"land\" spans.\n\t\tloc := setupPage(t).\n\t\t\tLocator(\"div\", &common.LocatorOptions{\n\t\t\t\tHasText: \"good bye\",\n\t\t\t}).\n\t\t\tLocator(\"span\", &common.LocatorOptions{\n\t\t\t\tHasNotText: \"good bye\",\n\t\t\t})\n\t\tlocs, err := loc.All()\n\t\trequire.NoError(t, err)\n\t\trequire.Len(t, locs, 2)\n\n\t\ttext, ok, err := locs[0].TextContent(common.NewFrameTextContentOptions(locs[0].Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\trequire.Equal(t, \"moon\", text)\n\n\t\ttext, ok, err = locs[1].TextContent(common.NewFrameTextContentOptions(locs[1].Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\trequire.Equal(t, \"land\", text)\n\t})\n\n\tt.Run(\"nil_options_with_filter\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Finds the divs, filters to the one with \"good bye\",\n\t\t// then finds its spans and filters to the one with \"moon\".\n\t\tloc := setupPage(t).\n\t\t\tLocator(\"div\", nil).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasText: \"good bye\",\n\t\t\t\t},\n\t\t\t}).\n\t\t\tLocator(\"span\", nil).\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasText: \"moon\",\n\t\t\t\t},\n\t\t\t})\n\t\tn, err := loc.Count()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, n)\n\n\t\ttext, ok, err := loc.TextContent(common.NewFrameTextContentOptions(loc.Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\trequire.Equal(t, \"moon\", text)\n\t})\n\n\tt.Run(\"options_with_filter\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tloc := setupPage(t).\n\t\t\t// Finds the div element with the \"good bye\" text.\n\t\t\tLocator(\"div\", &common.LocatorOptions{\n\t\t\t\tHasText: \"good bye\",\n\t\t\t}).\n\t\t\t// Filters out child spans with the \"good bye\" text.\n\t\t\tLocator(\"span\", &common.LocatorOptions{\n\t\t\t\tHasNotText: \"good bye\",\n\t\t\t}).\n\t\t\t// Filters out childs span with the \"moon\" text.\n\t\t\tFilter(&common.LocatorFilterOptions{\n\t\t\t\tLocatorOptions: &common.LocatorOptions{\n\t\t\t\t\tHasNotText: \"moon\",\n\t\t\t\t},\n\t\t\t})\n\t\tn, err := loc.Count()\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, 1, n)\n\n\t\ttext, ok, err := loc.TextContent(common.NewFrameTextContentOptions(loc.Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\trequire.Equal(t, \"land\", text)\n\t})\n}\n\nfunc TestVisibilityWithCORS(t *testing.T) {\n\tt.Parallel()\n\n\tiframeID := \"frameB\"\n\n\tsetupCORS := func(t *testing.T) (*testBrowser, *common.Page) {\n\t\tt.Helper()\n\n\t\tiframeHTML := `<!DOCTYPE html>\n\t\t<html>\n\t\t<head></head>\n\t\t<body>\n\t\t\t<button id=\"visibleButton\">Hello</button>\n\t\t\t<button id=\"hiddenButton\" hidden>World</button>\n\t\t</body>\n\t\t</html>`\n\n\t\ttb := newTestBrowser(t, withIFrameContent(iframeHTML, iframeID))\n\n\t\tp := tb.GotoNewPage(tb.url(\"/iframe\"))\n\n\t\treturn tb, p\n\t}\n\n\ttests := []struct {\n\t\tname string\n\t\tdo   func(*testBrowser, *common.Page) (bool, error)\n\t\twant bool\n\t}{\n\t\t{\n\t\t\tname: \"hidden\",\n\t\t\tdo: func(_ *testBrowser, p *common.Page) (bool, error) {\n\t\t\t\tframeBContent := p.Locator(\"#\"+iframeID, nil).ContentFrame()\n\t\t\t\treturn frameBContent.Locator(\"#hiddenButton\", nil).IsHidden()\n\t\t\t},\n\t\t\twant: true,\n\t\t},\n\t\t{\n\t\t\tname: \"visible\",\n\t\t\tdo: func(_ *testBrowser, p *common.Page) (bool, error) {\n\t\t\t\tframeBContent := p.Locator(\"#\"+iframeID, nil).ContentFrame()\n\t\t\t\treturn frameBContent.Locator(\"#visibleButton\", nil).IsVisible()\n\t\t\t},\n\t\t\twant: true,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb, p := setupCORS(t)\n\n\t\t\tgot, err := tt.do(tb, p)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.want, got)\n\t\t})\n\t}\n}\n\nfunc TestLocatorEvaluate(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tpageFunc string\n\t\targs     []any\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"no_args\",\n\t\t\tpageFunc: `handle => handle.innerText`,\n\t\t\targs:     nil,\n\t\t\texpected: \"Some title\",\n\t\t},\n\t\t{\n\t\t\tname: \"with_args\",\n\t\t\tpageFunc: `(handle, a, b) => {\n\t\t\t\tconst c = a + b;\n\t\t\t\treturn handle.innerText + \" \" + c\n\t\t\t}`,\n\t\t\targs:     []any{1, 2},\n\t\t\texpected: \"Some title 3\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\terr := p.SetContent(`<html><head><title data-testid=\"title\">Some title</title></head></html>`, nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult := p.GetByTestID(\"'title'\")\n\t\t\trequire.NotNil(t, result)\n\n\t\t\tgot, err := result.Evaluate(tt.pageFunc, tt.args...)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.expected, got)\n\t\t})\n\t}\n}\n\nfunc TestLocatorEvaluateHandle(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tpageFunc string\n\t\targs     []any\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"no_args\",\n\t\t\tpageFunc: `handle => {\n\t\t\t\treturn {\"innerText\": handle.innerText};\n\t\t\t}`,\n\t\t\targs:     nil,\n\t\t\texpected: `{\"innerText\":\"Some title\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"with_args\",\n\t\t\tpageFunc: `(handle, a, b) => {\n\t\t\t\treturn {\"innerText\": handle.innerText, \"sum\": a + b};\n\t\t\t}`,\n\t\t\targs:     []any{1, 2},\n\t\t\texpected: `{\"innerText\":\"Some title\",\"sum\":3}`,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\terr := p.SetContent(`<html><head><title data-testid=\"title\">Some title</title></head></html>`, nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult := p.GetByTestID(\"'title'\")\n\t\t\trequire.NotNil(t, result)\n\n\t\t\tgot, err := result.EvaluateHandle(tt.pageFunc, tt.args...)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.NotNil(t, got)\n\n\t\t\tj, err := got.JSONValue()\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tt.expected, j)\n\t\t})\n\t}\n}\n\nfunc TestFrameLocator(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"page_frameLocator\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(tb.staticURL(\"iframe_test_main.html\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\t// Test the new frameLocator() method on Page\n\t\tfl := p.FrameLocator(\"#iframe1\")\n\t\trequire.NotNil(t, fl)\n\n\t\tnestedFL := fl.FrameLocator(\"#iframe2\")\n\t\trequire.NotNil(t, nestedFL)\n\n\t\tbuttonLocator := nestedFL.Locator(\"#button1\", nil)\n\t\trequire.NotNil(t, buttonLocator)\n\n\t\terr = buttonLocator.Click(common.NewFrameClickOptions(buttonLocator.Timeout()))\n\t\trequire.NoError(t, err)\n\n\t\tclicked, err := buttonLocator.Evaluate(\"el => window.buttonClicked\")\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, clicked.(bool), \"buttonClicked should be true after click\")\n\t})\n\n\tt.Run(\"frame_frameLocator\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(tb.staticURL(\"iframe_test_main.html\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\t// Test the new frameLocator() method on Frame\n\t\tmainFrame := p.MainFrame()\n\t\tfl := mainFrame.FrameLocator(\"#iframe1\")\n\t\trequire.NotNil(t, fl)\n\n\t\tnestedFL := fl.FrameLocator(\"#iframe2\")\n\t\trequire.NotNil(t, nestedFL)\n\n\t\tbuttonLocator := nestedFL.Locator(\"#button1\", nil)\n\t\trequire.NotNil(t, buttonLocator)\n\n\t\terr = buttonLocator.Click(common.NewFrameClickOptions(buttonLocator.Timeout()))\n\t\trequire.NoError(t, err)\n\n\t\tclicked, err := buttonLocator.Evaluate(\"el => window.buttonClicked\")\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, clicked.(bool), \"buttonClicked should be true after click\")\n\t})\n\n\tt.Run(\"locator_frameLocator\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(tb.staticURL(\"iframe_test_main.html\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\tbodyLocator := p.Locator(\"body\", nil)\n\t\tfl := bodyLocator.FrameLocator(\"#iframe1\")\n\t\trequire.NotNil(t, fl)\n\n\t\tnestedFL := fl.FrameLocator(\"#iframe2\")\n\t\trequire.NotNil(t, nestedFL)\n\n\t\tbuttonLocator := nestedFL.Locator(\"#button1\", nil)\n\t\trequire.NotNil(t, buttonLocator)\n\n\t\terr = buttonLocator.Click(common.NewFrameClickOptions(buttonLocator.Timeout()))\n\t\trequire.NoError(t, err)\n\n\t\tclicked, err := buttonLocator.Evaluate(\"el => window.buttonClicked\")\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, clicked.(bool), \"buttonClicked should be true after click\")\n\t})\n\n\tt.Run(\"comparison_with_contentFrame\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(tb.staticURL(\"iframe_test_main.html\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\t// compare old and new\n\t\toldWay := p.Locator(\"#iframe1\", nil).ContentFrame()\n\t\trequire.NotNil(t, oldWay)\n\n\t\tnewWay := p.FrameLocator(\"#iframe1\")\n\t\trequire.NotNil(t, newWay)\n\n\t\toldNested := oldWay.FrameLocator(\"#iframe2\")\n\t\tnewNested := newWay.FrameLocator(\"#iframe2\")\n\n\t\toldButton := oldNested.Locator(\"#button1\", nil)\n\t\tnewButton := newNested.Locator(\"#button1\", nil)\n\n\t\trequire.NotNil(t, oldButton)\n\t\trequire.NotNil(t, newButton)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/logrus_hook.go",
    "content": "package tests\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// logCache implements the logrus.Hook interface and could be used to check\n// if log messages were outputted.\ntype logCache struct {\n\tHookedLevels []logrus.Level\n\n\tmu      sync.RWMutex\n\tentries []logrus.Entry\n}\n\n// Levels just returns whatever was stored in the HookedLevels slice.\nfunc (lc *logCache) Levels() []logrus.Level {\n\treturn lc.HookedLevels\n}\n\n// Fire saves whatever message the logrus library passed in the cache.\nfunc (lc *logCache) Fire(e *logrus.Entry) error {\n\tlc.mu.Lock()\n\tdefer lc.mu.Unlock()\n\tlc.entries = append(lc.entries, *e)\n\treturn nil\n}\n\n// assertContains checks if msg is contained in any of the cached logged events\n// and fails the test if it's not. It also prints the cached log messages to\n// help debugging.\nfunc (lc *logCache) assertContains(tb testing.TB, msg string) {\n\ttb.Helper()\n\n\tif lc.contains(msg) {\n\t\treturn\n\t}\n\ttb.Errorf(\"expected log cache to contain %q, but it didn't.\", msg)\n\tlc.dump(tb)\n}\n\n// dump prints all the cached log messages to the testing.TB.\nfunc (lc *logCache) dump(tb testing.TB) {\n\ttb.Helper()\n\n\tlc.mu.RLock()\n\tdefer lc.mu.RUnlock()\n\n\ttb.Log(strings.Repeat(\"-\", 80))\n\tfor _, e := range lc.entries {\n\t\ttb.Log(e.Message)\n\t}\n}\n\n// contains returns true if msg is contained in any of the cached logged events\n// or false otherwise.\nfunc (lc *logCache) contains(msg string) bool {\n\tlc.mu.RLock()\n\tdefer lc.mu.RUnlock()\n\tfor _, evt := range lc.entries {\n\t\tif strings.Contains(evt.Message, msg) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// attachLogCache sets logger to DebugLevel, attaches a LogCache hook and\n// returns it.\nfunc attachLogCache(tb testing.TB, fl logrus.FieldLogger) *logCache {\n\ttb.Helper()\n\n\tvar ok bool\n\tvar logger *logrus.Logger                  //nolint:forbidigo\n\tif logger, ok = fl.(*logrus.Logger); !ok { //nolint:forbidigo\n\t\t// TODO: Fix this to always work with logrus.FieldLoger.\n\t\t// See: https://go.k6.io/k6/js/modules/k6/browser/issues/818\n\t\ttb.Fatalf(\"logCache: unexpected logger type: %T\", fl)\n\t}\n\n\tlc := &logCache{HookedLevels: []logrus.Level{logrus.DebugLevel, logrus.WarnLevel}}\n\tlogger.SetLevel(logrus.DebugLevel)\n\tlogger.AddHook(lc)\n\tlogger.SetOutput(io.Discard)\n\n\treturn lc\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/mouse_test.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc TestMouseActions(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"click\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tm := p.GetMouse()\n\n\t\t// Set up a page with a button that changes text when clicked\n\t\tbuttonHTML := `\n\t\t\t<button onclick=\"this.innerHTML='Clicked!'\">Click me</button>\n\t\t`\n\t\terr := p.SetContent(buttonHTML, nil)\n\t\trequire.NoError(t, err)\n\t\tbutton, err := p.Query(\"button\")\n\t\trequire.NoError(t, err)\n\n\t\t// Simulate a click at the button coordinates\n\t\tbox, err := button.BoundingBox()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, m.Click(box.X, box.Y, common.NewMouseClickOptions()))\n\n\t\t// Verify the button's text changed\n\t\ttext, ok, err := button.TextContent()\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"Clicked!\", text)\n\t})\n\n\tt.Run(\"double_click\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tm := p.GetMouse()\n\n\t\t// Set up a page with a button that changes text on double click and also counts clicks\n\t\tbuttonHTML := `\n\t\t\t<script>window.clickCount = 0;</script>\n\t\t\t<button\n\t\t\t\tonclick=\"document.getElementById('clicks').innerHTML = ++window.clickCount;\"\n\t\t\t\tondblclick=\"this.innerHTML='Double Clicked!';\">Click me</button>\n\t\t\t<div id=\"clicks\"></div>\n\t\t`\n\t\terr := p.SetContent(buttonHTML, nil)\n\t\trequire.NoError(t, err)\n\t\tbutton, err := p.Query(\"button\")\n\t\trequire.NoError(t, err)\n\n\t\t// Get the button's bounding box for accurate clicking\n\t\tbox, err := button.BoundingBox()\n\t\trequire.NoError(t, err)\n\n\t\t// Simulate a double click at the button coordinates\n\t\trequire.NoError(t, m.DblClick(box.X, box.Y, common.NewMouseDblClickOptions()))\n\n\t\t// Verify the button's text changed\n\t\ttext, ok, err := button.TextContent()\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"Double Clicked!\", text)\n\n\t\t// Also verify that the element was clicked twice\n\t\tclickCountDiv, err := p.Query(\"div#clicks\")\n\t\trequire.NoError(t, err)\n\t\ttext, ok, err = clickCountDiv.TextContent()\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"2\", text)\n\t})\n\n\tt.Run(\"move\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tm := p.GetMouse()\n\n\t\t// Set up a page with an area that detects mouse move\n\t\tareaHTML := `\n\t\t\t<div\n\t\t\t\tonmousemove=\"this.innerHTML='Mouse Moved';\"\n\t\t\t\tstyle=\"width:100px;height:100px;\"\n\t\t\t></div>\n\t\t`\n\t\terr := p.SetContent(areaHTML, nil)\n\t\trequire.NoError(t, err)\n\t\tarea, err := p.Query(\"div\")\n\t\trequire.NoError(t, err)\n\n\t\t// Simulate mouse move within the div\n\t\tbox, err := area.BoundingBox()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, m.Move(box.X+50, box.Y+50, common.NewMouseMoveOptions())) // Move to the center of the div\n\t\ttext, ok, err := area.TextContent()\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"Mouse Moved\", text)\n\t})\n\n\tt.Run(\"move_down_up\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\tm := p.GetMouse()\n\n\t\t// Set up a page with a button that tracks mouse down and up\n\t\tbuttonHTML := `\n\t\t\t<button\n\t\t\t\tonmousedown=\"this.innerHTML='Mouse Down';\"\n\t\t\t\tonmouseup=\"this.innerHTML='Mouse Up';\"\n\t\t\t>Mouse</button>\n\t\t`\n\t\terr := p.SetContent(buttonHTML, nil)\n\t\trequire.NoError(t, err)\n\t\tbutton, err := p.Query(\"button\")\n\t\trequire.NoError(t, err)\n\n\t\tbox, err := button.BoundingBox()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, m.Move(box.X, box.Y, common.NewMouseMoveOptions()))\n\t\trequire.NoError(t, m.Down(common.NewMouseDownUpOptions()))\n\t\ttext, ok, err := button.TextContent()\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"Mouse Down\", text)\n\t\trequire.NoError(t, m.Up(common.NewMouseDownUpOptions()))\n\t\ttext, ok, err = button.TextContent()\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"Mouse Up\", text)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/network_manager_test.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n\n\tk6lib \"go.k6.io/k6/lib\"\n\tk6types \"go.k6.io/k6/lib/types\"\n)\n\n// TestURLSkipRequest checks that, since https://github.com/grafana/k6/commit/f29064ef, k6 doesn't\n// handle navigation requests for local urls, like: blob:... or data:..., and so it doesn't emit errors\n// neither (e.g. in case of a non-existing blob), in contraposition to what Playwright does.\nfunc TestURLSkipRequest(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withLogCache())\n\tp := tb.NewPage(nil)\n\n\t_, err := p.Goto(\n\t\t\"data:text/html,hello\",\n\t\t&common.FrameGotoOptions{Timeout: common.DefaultTimeout},\n\t)\n\trequire.NoError(t, err)\n\ttb.logCache.assertContains(t, \"skipping request handling of data URL\")\n\n\t// In this test, we're checking that the network manager is skipping request handling of certain URLs,\n\t// but Browser navigation still happens.\n\t//\n\t// However, until Chrome 139.x, there was a subtle bug causing no valid NavigationEvent to be emitted.\n\t// An event being considered valid by having a document id that matches the document id of the frame\n\t// that navigated to that url. So, until that, we expected the following [p.Goto] call to timeout.\n\t//\n\t// Since Chrome 140.x, this bug has been fixed, and now the navigation to a non-existing blob behaves\n\t// similarly to what happens in the lines above, no timing out but succeeding with normality.\n\t//\n\t// Note that, in spite of non-existing blob (we cannot define a valid one because k6 lacks general support\n\t// for Blob and URL WebAPIs), this doesn't return any error because as stated in the TestURLSkipRequest docs,\n\t// k6 intentionally skips that request handling, thus not throwing the net::ERR_FILE_NOT_FOUND that Chrome\n\t// throws in such case, as Playwright does.\n\t_, err = p.Goto(\n\t\t\"blob:something\",\n\t\t&common.FrameGotoOptions{Timeout: common.DefaultTimeout},\n\t)\n\trequire.NoError(t, err)\n\ttb.logCache.assertContains(t, \"skipping request handling of blob URL\")\n}\n\nfunc TestBlockHostnames(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer(), withLogCache())\n\n\tblocked, err := k6types.NewNullHostnameTrie([]string{\"*.test\"})\n\trequire.NoError(t, err)\n\ttb.vu.State().Options.BlockedHostnames = blocked\n\n\tp := tb.NewPage(nil)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tres, err := p.Goto(\n\t\t\"http://host.test/\",\n\t\topts,\n\t)\n\trequire.Nil(t, res)\n\trequire.Error(t, err)\n\trequire.ErrorContains(t, err, `navigating frame to \"http://host.test/\": net::ERR_BLOCKED_BY_CLIENT`)\n\ttb.logCache.assertContains(t, \"was aborted: hostname host.test matches a blocked pattern\")\n\n\tres, err = p.Goto(\n\t\ttb.url(\"/get\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\tassert.NotNil(t, res)\n}\n\nfunc TestBlockIPs(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer(), withLogCache())\n\n\tipnet, err := k6lib.ParseCIDR(\"10.0.0.0/8\")\n\trequire.NoError(t, err)\n\ttb.vu.State().Options.BlacklistIPs = []*k6lib.IPNet{ipnet}\n\n\tp := tb.NewPage(nil)\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tres, err := p.Goto(\n\t\t\"http://10.0.0.1:8000/\",\n\t\topts,\n\t)\n\trequire.Nil(t, res)\n\trequire.Error(t, err)\n\trequire.ErrorContains(t, err, `navigating frame to \"http://10.0.0.1:8000/\": net::ERR_BLOCKED_BY_CLIENT`)\n\ttb.logCache.assertContains(t, `was aborted: IP 10.0.0.1 is in a blacklisted range \"10.0.0.0/8\"`)\n\n\t// Ensure other requests go through\n\tres, err = p.Goto(\n\t\ttb.url(\"/get\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\tassert.NotNil(t, res)\n}\n\nfunc TestBasicAuth(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\tvalidUser     = \"validuser\"\n\t\tvalidPassword = \"validpass\"\n\t)\n\n\tauth := func(tb testing.TB, user, pass string) *common.Response {\n\t\ttb.Helper()\n\n\t\tbrowser := newTestBrowser(t, withHTTPServer())\n\n\t\tbcopts := common.DefaultBrowserContextOptions()\n\t\tbcopts.HTTPCredentials = common.Credentials{\n\t\t\tUsername: validUser,\n\t\t\tPassword: validPassword,\n\t\t}\n\t\tbc, err := browser.NewContext(bcopts)\n\t\trequire.NoError(t, err)\n\n\t\tp, err := bc.NewPage()\n\t\trequire.NoError(t, err)\n\n\t\turl := browser.url(\n\t\t\tfmt.Sprintf(\"/basic-auth/%s/%s\", user, pass),\n\t\t)\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: common.LifecycleEventLoad,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\tres, err := p.Goto(url, opts)\n\t\trequire.NoError(t, err)\n\n\t\treturn res\n\t}\n\n\tt.Run(\"valid\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tresp := auth(t, validUser, validPassword)\n\t\trequire.NotNil(t, resp)\n\t\tassert.Equal(t, http.StatusOK, int(resp.Status()))\n\t})\n\tt.Run(\"invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tresp := auth(t, \"invalidUser\", \"invalidPassword\")\n\t\trequire.NotNil(t, resp)\n\t\tassert.Equal(t, http.StatusUnauthorized, int(resp.Status()))\n\t})\n}\n\n// See issue #1072 for more details.\nfunc TestInterceptBeforePageLoad(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\n\t// changing the main frame to another URL will trigger a redirect\n\t// before the page is loaded. this will cause a deadlock because\n\t// the page's response body won't be available yet due to request\n\t// interception.\n\t//\n\t// the reason for this is that the browser will intercept the\n\t// request and pause it, but the response body won't be available\n\t// until the page is loaded, which won't happen because the\n\t// request is paused.\n\ttb.withHandler(\"/neverFinishesLoading\", func(w http.ResponseWriter, r *http.Request) {\n\t\tconst runBeforePageOnLoad = `\n\t\t\t// immediately redirect to another page before the page is\n\t\t\t// loaded. browsers wait for scripts to finish executing\n\t\t\t// before firing the load event, so this will cause the\n\t\t\t// page to never finish loading.\n\t\t\twindow.location.href='/trap';\n\t\t`\n\t\t_, err := fmt.Fprintf(w, `\n\t\t\t<html>\n\t\t\t\t<head>\n\t\t\t\t\t<script>\n\t\t\t\t\t\t%s\n\t\t\t\t\t</script>\n\t\t\t\t</head>\n\t\t\t\t<body />\n\t\t\t</html>\n\t\t`, runBeforePageOnLoad)\n\t\trequire.NoError(t, err)\n\t})\n\n\t// this handler will be called before the main page is loaded\n\ttb.withHandler(\"/trap\", func(w http.ResponseWriter, r *http.Request) {\n\t\t_, err := fmt.Fprint(w, \"ok\")\n\t\trequire.NoError(t, err)\n\t})\n\n\t// go to the main page and wait for the redirect to happen\n\t// before the page is loaded (LifecycleEventDOMContentLoad).\n\tgotoPage := func() error {\n\t\tp := tb.NewPage(nil)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: common.LifecycleEventDOMContentLoad,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\t_, err := p.Goto(\n\t\t\ttb.url(\"/neverFinishesLoading\"),\n\t\t\topts,\n\t\t)\n\n\t\treturn err\n\t}\n\n\t// enable interception to pause the redirect in the main page\n\tblocked, err := k6types.NewNullHostnameTrie([]string{\"foo.com\"})\n\trequire.NoError(t, err)\n\ttb.vu.State().Options.BlockedHostnames = blocked\n\n\t// go to the main page and cut short with a timeout\n\t// if it takes too long. in a buggy case, this will\n\t// deadlock and never return.\n\t//\n\t// a five seconds timeout is plenty for this bug to\n\t// manifest.\n\tctx, cancel := context.WithTimeout(tb.ctx, 5*time.Second)\n\tdefer cancel()\n\terr = tb.run(ctx, gotoPage)\n\trequire.NoError(t, err)\n}\n\n// TestNetworkManagerCloseMetricEmissionRace reproduces the race\n// condition where NetworkManager emits metrics during the engine\n// shutdown. Reproduces the issue 4203 when run with the -race flag.\nfunc TestNetworkManagerCloseMetricEmissionRace(t *testing.T) {\n\tt.Parallel()\n\n\tsamples := make(chan k6metrics.SampleContainer, 5)\n\ttb := newTestBrowser(t, withHTTPServer(), withSamples(samples), withSkipClose())\n\ttb.vu.StartIteration(t)\n\tpage := tb.NewPage(nil)\n\n\ttb.withHandler(\"/foo\", func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = fmt.Fprint(w, `<html><head></head><body>loaded</body></html>`)\n\t})\n\ttb.withHandler(\"/ping\", func(w http.ResponseWriter, r *http.Request) {\n\t\t_, _ = fmt.Fprint(w, \"pong\")\n\t})\n\n\topts := &common.FrameGotoOptions{Timeout: common.DefaultTimeout}\n\t_, err := page.Goto(tb.url(\"/foo\"), opts)\n\trequire.NoError(t, err)\n\n\t// Fire a burst of fetch requests from JS so that many HTTP-metric\n\t// emission goroutines are active or queued when we close the page.\n\t_, err = page.Evaluate(`() => {\n\t\tconst promises = [];\n\t\tfor (let i = 0; i < 5; i++) {\n\t\t\tpromises.push(fetch('/ping?i=' + i));\n\t\t}\n\t\treturn Promise.all(promises).then(() => 'done');\n\t}`)\n\trequire.NoError(t, err)\n\n\t// Close the page in a goroutine. On a correct implementation,\n\t// Close blocks until all metric-emitting goroutines finish.\n\tcloseDone := make(chan error, 1)\n\tgo func() { closeDone <- page.Close() }()\n\n\tdefer close(samples)\n\tgo func() {\n\t\tfor range samples {\n\t\t}\n\t}()\n\n\t// Wait for Close to return.\n\tselect {\n\tcase err := <-closeDone:\n\t\trequire.NoError(t, err)\n\tcase <-time.After(30 * time.Second):\n\t\tt.Fatal(\"page.Close() did not return after draining samples\")\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/page_test.go",
    "content": "package tests\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t_ \"embed\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"image/png\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n)\n\ntype jsFrameBaseOpts struct {\n\tTimeout string\n\tStrict  bool\n}\n\nconst sampleHTML = `<div><b>Test</b><ol><li><i>One</i></li></ol></div>`\n\nfunc TestNestedFrames(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"windows take forever to do this test\")\n\t}\n\n\ttb := newTestBrowser(t,\n\t\twithFileServer(),\n\t)\n\n\tpage := tb.NewPage(nil)\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\t_, err := page.Goto(\n\t\ttb.staticURL(\"iframe_test_main.html\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\n\tframe1Handle, err := page.WaitForSelector(\"iframe[id='iframe1']\", common.NewFrameWaitForSelectorOptions(page.MainFrame().Timeout()))\n\tassert.Nil(t, err)\n\tassert.NotNil(t, frame1Handle)\n\n\tframe1, err := frame1Handle.ContentFrame()\n\tassert.Nil(t, err)\n\tassert.NotNil(t, frame1)\n\n\tframe2Handle, err := frame1.WaitForSelector(\"iframe[id='iframe2']\", common.NewFrameWaitForSelectorOptions(frame1.Timeout()))\n\tassert.Nil(t, err)\n\tassert.NotNil(t, frame2Handle)\n\n\tframe2, err := frame2Handle.ContentFrame()\n\tassert.Nil(t, err)\n\tassert.NotNil(t, frame2)\n\n\tbutton1Handle, err := frame2.WaitForSelector(\"button[id='button1']\", common.NewFrameWaitForSelectorOptions(frame2.Timeout()))\n\tassert.Nil(t, err)\n\tassert.NotNil(t, button1Handle)\n\n\terr = button1Handle.Click(common.NewElementHandleClickOptions(button1Handle.Timeout()))\n\tassert.Nil(t, err)\n\n\tv, err := frame2.Evaluate(`() => window.buttonClicked`)\n\trequire.NoError(t, err)\n\tbv := asBool(t, v)\n\tassert.True(t, bv, \"button hasn't been clicked\")\n}\n\nfunc TestPageEmulateMedia(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\tpopts := &common.PageEmulateMediaOptions{\n\t\tMedia:         \"print\",\n\t\tColorScheme:   \"dark\",\n\t\tReducedMotion: \"reduce\",\n\t}\n\terr := p.EmulateMedia(popts)\n\trequire.NoError(t, err)\n\n\tresult, err := p.Evaluate(`() => matchMedia('print').matches`)\n\trequire.NoError(t, err)\n\tassert.IsTypef(t, true, result, \"expected media 'print'\")\n\n\tresult, err = p.Evaluate(`() => matchMedia('(prefers-color-scheme: dark)').matches`)\n\trequire.NoError(t, err)\n\tassert.IsTypef(t, true, result, \"expected color scheme 'dark'\")\n\n\tresult, err = p.Evaluate(`() => matchMedia('(prefers-reduced-motion: reduce)').matches`)\n\trequire.NoError(t, err)\n\tassert.IsTypef(t, true, result, \"expected reduced motion setting to be 'reduce'\")\n}\n\nfunc TestPageContent(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\tcontent := `<!DOCTYPE html><html><head></head><body><h1>Hello</h1></body></html>`\n\terr := p.SetContent(content, nil)\n\trequire.NoError(t, err)\n\n\tcontent, err = p.Content()\n\trequire.NoError(t, err)\n\tassert.Equal(t, content, content)\n}\n\nfunc TestPageEvaluate(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok/func_arg\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\n\t\tgot, err := p.Evaluate(\n\t\t\t`(v) => { window.v = v; return window.v }`,\n\t\t\t\"test\",\n\t\t)\n\t\trequire.NoError(t, err)\n\t\ts := asString(t, got)\n\t\tassert.Equal(t, \"test\", s)\n\t})\n\n\tt.Run(\"ok/void_func\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\th, err := p.EvaluateHandle(`() => console.log(\"hello\")`)\n\t\tassert.Nil(t, h, \"expected nil handle\")\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"err\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestCases := []struct {\n\t\t\tname, js, errMsg string\n\t\t}{\n\t\t\t{\n\t\t\t\t\"promise\",\n\t\t\t\t`async () => { return await new Promise((res, rej) => { rej('rejected'); }); }`,\n\t\t\t\t\"evaluating JS: rejected\",\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"syntax\", `() => {`,\n\t\t\t\t\"evaluating JS: SyntaxError: Unexpected token ')'\",\n\t\t\t},\n\t\t\t{\"undef\", \"undef\", \"evaluating JS: ReferenceError: undef is not defined\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttb := newTestBrowser(t)\n\t\t\t\tp := tb.NewPage(nil)\n\t\t\t\t_, err := p.Evaluate(tc.js)\n\t\t\t\trequire.ErrorContains(t, err, tc.errMsg)\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestPageEvaluateMapping(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname   string\n\t\tscript string\n\t\twant   any\n\t}{\n\t\t{\n\t\t\tname:   \"arrow\",\n\t\t\tscript: \"() => 0\",\n\t\t\twant:   0,\n\t\t},\n\t\t{\n\t\t\tname:   \"full_func\",\n\t\t\tscript: \"function() {return 1}\",\n\t\t\twant:   1,\n\t\t},\n\t\t{\n\t\t\tname:   \"arrow_func_no_return\",\n\t\t\tscript: \"() => {2}\",\n\t\t\twant:   sobek.Null(),\n\t\t},\n\t\t{\n\t\t\tname:   \"full_func_no_return\",\n\t\t\tscript: \"function() {3}\",\n\t\t\twant:   sobek.Null(),\n\t\t},\n\t\t{\n\t\t\tname:   \"async_func\",\n\t\t\tscript: \"async function() {return 4}\",\n\t\t\twant:   4,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t)\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\t\t\tdefer tb.vu.EndIteration(t)\n\n\t\t\t// Test script as non string input\n\t\t\ttb.vu.SetVar(t, \"p\", &sobek.Object{})\n\t\t\tgot := tb.vu.RunPromise(t, `\n\t\t\t\tp = await browser.newPage()\n\t\t\t\treturn await p.evaluate(%s)\n\t\t\t`, tt.script)\n\t\t\tassert.Equal(t, tb.vu.ToSobekValue(tt.want), got.Result())\n\n\t\t\t// Test script as string input\n\t\t\tgot = tb.vu.RunPromise(t,\n\t\t\t\t`return await p.evaluate(\"%s\")`,\n\t\t\t\ttt.script,\n\t\t\t)\n\t\t\tassert.Equal(t, tb.vu.ToSobekValue(tt.want), got.Result())\n\t\t\t// Test script as string input\n\t\t\t_ = tb.vu.RunPromise(t, `await p.close()`)\n\t\t})\n\t}\n}\n\nfunc TestPageEvaluateMappingError(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\ttests := []struct {\n\t\tname    string\n\t\tscript  string\n\t\twantErr string\n\t}{\n\t\t{\n\t\t\tname:    \"invalid\",\n\t\t\tscript:  \"5\",\n\t\t\twantErr: \"Given expression does not evaluate to a function\",\n\t\t},\n\t\t{\n\t\t\tname:    \"invalid_with_brackets\",\n\t\t\tscript:  \"(6)\",\n\t\t\twantErr: \"Given expression does not evaluate to a function\",\n\t\t},\n\t\t{\n\t\t\tname:    \"void\",\n\t\t\tscript:  \"\",\n\t\t\twantErr: \"evaluate requires a page function\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests { //nolint:paralleltest\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\t\t\tdefer tb.vu.EndIteration(t)\n\t\t\t// Test script as non string input\n\t\t\ttb.vu.SetVar(t, \"p\", &sobek.Object{})\n\t\t\t_, err := tb.vu.RunAsync(t, `\n\t\t\t\tp = await browser.newPage()\n\t\t\t\tawait p.evaluate(%s)\n\t\t\t`, tt.script)\n\t\t\tassert.ErrorContains(t, err, tt.wantErr)\n\n\t\t\t// Test script as string input\n\t\t\t_, err = tb.vu.RunAsync(t, `\n\t\t\t\tawait p.evaluate(\"%s\")\n\t\t\t`, tt.script)\n\t\t\tassert.ErrorContains(t, err, tt.wantErr)\n\t\t})\n\t}\n}\n\nfunc TestPageGoto(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t, withFileServer())\n\tp := b.NewPage(nil)\n\n\turl := b.staticURL(\"empty.html\")\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tr, err := p.Goto(\n\t\turl,\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, r)\n\tassert.Equal(t, url, r.URL(), `expected URL to be %q, result of navigation was %q`, url, r.URL())\n}\n\nfunc TestPageGotoDataURI(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t)\n\tp := b.NewPage(nil)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tr, err := p.Goto(\n\t\t\"data:text/html,hello\",\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\tassert.Nil(t, r, `expected response to be nil`)\n\trequire.NoError(t, err)\n}\n\nfunc TestPageGotoWaitUntilLoad(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // no idea but it doesn't work\n\t}\n\n\tb := newTestBrowser(t, withFileServer())\n\tp := b.NewPage(nil)\n\n\topts := &common.FrameGotoOptions{\n\t\tWaitUntil: common.LifecycleEventLoad,\n\t\tTimeout:   common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(b.staticURL(\"wait_until.html\"), opts)\n\trequire.NoError(t, err)\n\tresults, err := p.Evaluate(`() => window.results`)\n\trequire.NoError(t, err)\n\tassert.EqualValues(t,\n\t\t[]any{\"DOMContentLoaded\", \"load\"}, results,\n\t\t`expected \"load\" event to have fired`,\n\t)\n}\n\nfunc TestPageGotoWaitUntilDOMContentLoaded(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // no idea but it doesn't work\n\t}\n\n\tb := newTestBrowser(t, withFileServer())\n\tp := b.NewPage(nil)\n\n\topts := &common.FrameGotoOptions{\n\t\tWaitUntil: common.LifecycleEventDOMContentLoad,\n\t\tTimeout:   common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(b.staticURL(\"wait_until.html\"), opts)\n\trequire.NoError(t, err)\n\tv, err := p.Evaluate(`() => window.results`)\n\trequire.NoError(t, err)\n\tresults, ok := v.([]any)\n\tif !ok {\n\t\tt.Fatalf(\"expected results to be a slice, got %T\", v)\n\t}\n\trequire.True(t, len(results) >= 1, \"expected at least one result\")\n\tassert.EqualValues(t,\n\t\t\"DOMContentLoaded\", results[0],\n\t\t`expected \"DOMContentLoaded\" event to have fired`,\n\t)\n}\n\nfunc TestPageInnerHTML(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tp := newTestBrowser(t).NewPage(nil)\n\t\terr := p.SetContent(sampleHTML, nil)\n\t\trequire.NoError(t, err)\n\t\tinnerHTML, err := p.InnerHTML(\"div\", common.NewFrameInnerHTMLOptions(p.MainFrame().Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, `<b>Test</b><ol><li><i>One</i></li></ol>`, innerHTML)\n\t})\n\n\tt.Run(\"err_empty_selector\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tdefer func() {\n\t\t}()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\t_, err := p.InnerHTML(\"\", common.NewFrameInnerHTMLOptions(p.Context().Timeout()))\n\t\trequire.ErrorContains(t, err, \"provided selector is empty\")\n\t})\n\n\tt.Run(\"err_wrong_selector\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.SetContent(sampleHTML, nil)\n\t\trequire.NoError(t, err)\n\t\tpopts := common.NewFrameInnerHTMLOptions(p.MainFrame().Timeout())\n\t\trequire.NoError(t, popts.Parse(tb.vu.Context(), tb.toSobekValue(jsFrameBaseOpts{Timeout: \"100\"})))\n\t\t_, err = p.InnerHTML(\"p\", popts)\n\t\trequire.Error(t, err)\n\t})\n}\n\nfunc TestPageInnerText(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tp := newTestBrowser(t).NewPage(nil)\n\t\terr := p.SetContent(sampleHTML, nil)\n\t\trequire.NoError(t, err)\n\t\tinnerText, err := p.InnerText(\"div\", common.NewFrameInnerTextOptions(p.MainFrame().Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"Test\\nOne\", innerText)\n\t})\n\n\tt.Run(\"err_empty_selector\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\t_, err := p.InnerText(\"\", common.NewFrameInnerTextOptions(p.MainFrame().Timeout()))\n\t\trequire.ErrorContains(t, err, \"provided selector is empty\")\n\t})\n\n\tt.Run(\"err_wrong_selector\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.SetContent(sampleHTML, nil)\n\t\trequire.NoError(t, err)\n\n\t\tpopts := common.NewFrameInnerTextOptions(p.MainFrame().Timeout())\n\t\trequire.NoError(t, popts.Parse(tb.vu.Context(), tb.toSobekValue(jsFrameBaseOpts{Timeout: \"100\"})))\n\t\t_, err = p.InnerText(\"p\", popts)\n\t\trequire.Error(t, err)\n\t})\n}\n\nfunc TestPageTextContent(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tp := newTestBrowser(t).NewPage(nil)\n\t\terr := p.SetContent(sampleHTML, nil)\n\t\trequire.NoError(t, err)\n\t\ttextContent, ok, err := p.TextContent(\"div\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"TestOne\", textContent)\n\t})\n\n\tt.Run(\"err_empty_selector\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\t_, _, err := p.TextContent(\"\", common.NewFrameTextContentOptions(p.MainFrame().Timeout()))\n\t\trequire.ErrorContains(t, err, \"provided selector is empty\")\n\t})\n\n\tt.Run(\"err_wrong_selector\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.SetContent(sampleHTML, nil)\n\t\trequire.NoError(t, err)\n\t\t_, _, err = p.TextContent(\"p\", common.NewFrameTextContentOptions(100))\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"err_wrong_selector\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.SetContent(sampleHTML, nil)\n\t\trequire.NoError(t, err)\n\t\t_, _, err = p.TextContent(\"p\", common.NewFrameTextContentOptions(100))\n\t\trequire.Error(t, err)\n\t})\n}\n\nfunc TestPageInputValue(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\terr := p.SetContent(`\n\t\t<input value=\"hello1\">\n\t\t<select><option value=\"hello2\" selected></option></select>\n\t\t<textarea>hello3</textarea>\n     \t`, nil)\n\trequire.NoError(t, err)\n\n\tinputValue, err := p.InputValue(\"input\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\tgot, want := inputValue, \"hello1\"\n\tassert.Equal(t, want, got)\n\n\tinputValue, err = p.InputValue(\"select\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\tgot, want = inputValue, \"hello2\"\n\tassert.Equal(t, want, got)\n\n\tinputValue, err = p.InputValue(\"textarea\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\tgot, want = inputValue, \"hello3\"\n\tassert.Equal(t, want, got)\n}\n\n// test for: https://go.k6.io/k6/js/modules/k6/browser/issues/132\nfunc TestPageInputSpecialCharacters(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\terr := p.SetContent(`<input id=\"special\">`, nil)\n\trequire.NoError(t, err)\n\tel, err := p.Query(\"#special\")\n\trequire.NoError(t, err)\n\n\twants := []string{\n\t\t\"test@k6.io\",\n\t\t\"<hello WoRlD \\\\/>\",\n\t\t\"{(hello world!)}\",\n\t\t\"!#$%^&*()+_|~±\",\n\t\t`¯\\_(ツ)_/¯`,\n\t}\n\tfor _, want := range wants {\n\t\trequire.NoError(t, el.Fill(\"\", common.NewElementHandleBaseOptions(common.DefaultTimeout)))\n\t\trequire.NoError(t, el.Type(want, common.NewElementHandleTypeOptions(common.DefaultTimeout)))\n\n\t\tgot, err := el.InputValue(common.NewElementHandleBaseOptions(common.DefaultTimeout))\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, want, got)\n\t}\n}\n\n//nolint:paralleltest\nfunc TestPageFill(t *testing.T) {\n\t// these tests are not parallel by intention because\n\t// they're testing the same page instance and they're\n\t// faster when run sequentially.\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`\n\t\t<input id=\"text\" type=\"text\" value=\"something\" />\n\t\t<input id=\"date\" type=\"date\" value=\"2012-03-12\"/>\n\t\t<input id=\"number\" type=\"number\" value=\"42\"/>\n\t\t<input id=\"unfillable\" type=\"radio\" />\n\t`, nil)\n\trequire.NoError(t, err)\n\n\thappy := []struct{ name, selector, value string }{\n\t\t{name: \"text\", selector: \"#text\", value: \"fill me up\"},\n\t\t{name: \"date\", selector: \"#date\", value: \"2012-03-13\"},\n\t\t{name: \"number\", selector: \"#number\", value: \"42\"},\n\t}\n\tsad := []struct{ name, selector, value string }{\n\t\t{name: \"date\", selector: \"#date\", value: \"invalid date\"},\n\t\t{name: \"number\", selector: \"#number\", value: \"forty two\"},\n\t\t{name: \"unfillable\", selector: \"#unfillable\", value: \"can't touch this\"},\n\t}\n\tfor _, tt := range happy {\n\t\tt.Run(\"happy/\"+tt.name, func(t *testing.T) {\n\t\t\terr := p.Fill(tt.selector, tt.value, common.NewFrameFillOptions(p.MainFrame().Timeout()))\n\t\t\trequire.NoError(t, err)\n\t\t\tinputValue, err := p.InputValue(tt.selector, common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tt.value, inputValue)\n\t\t})\n\t}\n\tfor _, tt := range sad {\n\t\tt.Run(\"sad/\"+tt.name, func(t *testing.T) {\n\t\t\terr := p.Fill(tt.selector, tt.value, common.NewFrameFillOptions(p.MainFrame().Timeout()))\n\t\t\trequire.Error(t, err)\n\t\t})\n\t}\n}\n\nfunc TestPageIsChecked(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\n\terr := p.SetContent(`<input type=\"checkbox\" checked>`, nil)\n\trequire.NoError(t, err)\n\n\tisopts := common.NewFrameIsCheckedOptions(common.DefaultTimeout)\n\tchecked, err := p.IsChecked(\"input\", isopts)\n\trequire.NoError(t, err)\n\tassert.True(t, checked, \"expected checkbox to be checked\")\n\n\terr = p.SetContent(`<input type=\"checkbox\">`, nil)\n\trequire.NoError(t, err)\n\n\tisopts = common.NewFrameIsCheckedOptions(common.DefaultTimeout)\n\tchecked, err = p.IsChecked(\"input\", isopts)\n\trequire.NoError(t, err)\n\tassert.False(t, checked, \"expected checkbox to be unchecked\")\n}\n\nfunc TestPageSetChecked(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<input id=\"el\" type=\"checkbox\">`, nil)\n\trequire.NoError(t, err)\n\n\tisopts := common.NewFrameIsCheckedOptions(common.DefaultTimeout)\n\tchecked, err := p.IsChecked(\"#el\", isopts)\n\trequire.NoError(t, err)\n\tassert.False(t, checked)\n\n\terr = p.SetChecked(\"#el\", true, common.NewFrameCheckOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\tisopts = common.NewFrameIsCheckedOptions(common.DefaultTimeout)\n\tchecked, err = p.IsChecked(\"#el\", isopts)\n\trequire.NoError(t, err)\n\tassert.True(t, checked)\n\n\terr = p.SetChecked(\"#el\", false, common.NewFrameCheckOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\tisopts = common.NewFrameIsCheckedOptions(common.DefaultTimeout)\n\tchecked, err = p.IsChecked(\"#el\", isopts)\n\trequire.NoError(t, err)\n\tassert.False(t, checked)\n}\n\nfunc TestPageScreenshotFullpage(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\tp := tb.NewPage(nil)\n\n\ts := &common.Size{Width: 1280, Height: 800}\n\terr := p.SetViewportSize(s)\n\trequire.NoError(t, err)\n\n\t_, err = p.Evaluate(`\n\t() => {\n\t\tdocument.body.style.margin = '0';\n\t\tdocument.body.style.padding = '0';\n\t\tdocument.documentElement.style.margin = '0';\n\t\tdocument.documentElement.style.padding = '0';\n\n\t\tconst div = document.createElement('div');\n\t\tdiv.style.width = '1280px';\n\t\tdiv.style.height = '800px';\n\t\tdiv.style.background = 'linear-gradient(to bottom, red, blue)';\n\n\t\tdocument.body.appendChild(div);\n\t}`)\n\trequire.NoError(t, err)\n\n\topts := common.NewPageScreenshotOptions()\n\topts.FullPage = true\n\tbuf, err := p.Screenshot(opts, &mockPersister{})\n\trequire.NoError(t, err)\n\n\treader := bytes.NewReader(buf)\n\timg, err := png.Decode(reader)\n\tassert.Nil(t, err)\n\n\tassert.Equal(t, 1280, img.Bounds().Max.X, \"want: screenshot width is 1280px, got: %dpx\", img.Bounds().Max.X)\n\tassert.Equal(t, 800, img.Bounds().Max.Y, \"want: screenshot height is 800px, got: %dpx\", img.Bounds().Max.Y)\n\n\t// Allow tolerance to account for differences in rendering between\n\t// different platforms and browsers. The goal is to ensure that the\n\t// screenshot is mostly red at the top and mostly blue at the bottom.\n\tr, _, b, _ := img.At(0, 0).RGBA()\n\tassert.Truef(t, r > b*2, \"want: the top pixel to be dominantly red, got R: %d, B: %d\", r, b)\n\tr, _, b, _ = img.At(0, 799).RGBA()\n\tassert.Truef(t, b > r*2, \"want: the bottom pixel to be dominantly blue, got R: %d, B: %d\", r, b)\n}\n\nfunc TestPageTitle(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<html><head><title>Some title</title></head></html>`, nil)\n\trequire.NoError(t, err)\n\ttitle, err := p.Title()\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"Some title\", title)\n}\n\nfunc TestPageSetExtraHTTPHeaders(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t, withHTTPServer())\n\n\tp := b.NewPage(nil)\n\n\theaders := map[string]string{\n\t\t\"Some-Header\": \"Some-Value\",\n\t}\n\terr := p.SetExtraHTTPHeaders(headers)\n\trequire.NoError(t, err)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tresp, err := p.Goto(\n\t\tb.url(\"/get\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, resp)\n\n\tresponseBody, err := resp.Body()\n\trequire.NoError(t, err)\n\n\tvar body struct{ Headers map[string][]string }\n\terr = json.Unmarshal(responseBody, &body)\n\trequire.NoError(t, err)\n\n\th := body.Headers[\"Some-Header\"]\n\trequire.NotEmpty(t, h)\n\tassert.Equal(t, \"Some-Value\", h[0])\n}\n\nfunc TestPageWaitForFunction(t *testing.T) {\n\tt.Parallel()\n\n\t// script is here to test we're not getting an error from the\n\t// waitForFunction call itself and the tests that use it are\n\t// testing the polling functionality—not the response from\n\t// waitForFunction.\n\tscript := `\n\t\tpage = await browser.newPage();\n\t\tlet resp = await page.waitForFunction(%s, %s, %s);\n\t\tlog('ok: '+resp);`\n\n\tsetup := func(t *testing.T) *testBrowser {\n\t\ttb := newTestBrowser(t, withLogCache())\n\t\ttb.vu.ActivateVU()\n\t\ttb.vu.StartIteration(t)\n\t\tt.Cleanup(func() { tb.vu.EndIteration(t) })\n\t\trequire.NoError(t, tb.vu.Runtime().Set(\"log\", func(s string) { tb.vu.State().Logger.Warn(s) }))\n\t\treturn tb\n\t}\n\n\tt.Run(\"ok_func_raf_default\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := setup(t)\n\n\t\ttb.vu.SetVar(t, \"page\", &sobek.Object{})\n\t\t_, err := tb.vu.RunOnEventLoop(t, `fn = () => {\n\t\t\tif (typeof window._cnt == 'undefined') window._cnt = 0;\n\t\t\tif (window._cnt >= 50) return true;\n\t\t\twindow._cnt++;\n\t\t\treturn false;\n\t\t}`)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = tb.vu.RunAsync(t, script, \"fn\", \"{}\", \"null\")\n\t\trequire.NoError(t, err)\n\t\ttb.logCache.assertContains(t, \"ok: null\")\n\t})\n\n\tt.Run(\"ok_func_raf_default_arg\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := setup(t)\n\n\t\t_, err := tb.vu.RunOnEventLoop(t, `fn = arg => {\n\t\t\twindow._arg = arg;\n\t\t\treturn true;\n\t\t}`)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = tb.vu.RunAsync(t, script, \"fn\", \"{}\", `\"raf_arg\"`)\n\t\trequire.NoError(t, err)\n\t\ttb.logCache.contains(\"ok: null\")\n\n\t\tp := tb.vu.RunPromise(t, `return await page.evaluate(() => window._arg);`)\n\t\trequire.Equal(t, sobek.PromiseStateFulfilled, p.State())\n\t\tassert.Equal(t, \"raf_arg\", p.Result().String())\n\t})\n\n\tt.Run(\"ok_func_raf_default_args\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := setup(t)\n\n\t\t_, err := tb.vu.RunOnEventLoop(t, `fn = (...args) => {\n\t\t\twindow._args = args;\n\t\t\treturn true;\n\t\t}`)\n\t\trequire.NoError(t, err)\n\n\t\targs := []int{1, 2, 3}\n\t\targsJS, err := json.Marshal(args)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = tb.vu.RunAsync(t, script, \"fn\", \"{}\", \"...\"+string(argsJS))\n\t\trequire.NoError(t, err)\n\t\ttb.logCache.contains(\"ok: null\")\n\n\t\tp := tb.vu.RunPromise(t, `return await page.evaluate(() => window._args);`)\n\t\trequire.Equal(t, sobek.PromiseStateFulfilled, p.State())\n\t\tvar gotArgs []int\n\t\t_ = tb.vu.Runtime().ExportTo(p.Result(), &gotArgs)\n\t\tassert.Equal(t, args, gotArgs)\n\t})\n\n\tt.Run(\"err_expr_raf_timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := setup(t)\n\n\t\t_, err := tb.vu.RunAsync(t, script, \"false\", \"{ polling: 'raf', timeout: 500 }\", \"null\")\n\t\trequire.ErrorContains(t, err, \"timed out after 500ms\")\n\t})\n\n\tt.Run(\"err_wrong_polling\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := setup(t)\n\n\t\t_, err := tb.vu.RunAsync(t, script, \"false\", \"{ polling: 'blah' }\", \"null\")\n\t\trequire.Error(t, err)\n\t\tassert.Contains(t, err.Error(),\n\t\t\t`parsing waitForFunction options: wrong polling option value:`,\n\t\t\t`\"blah\"; possible values: \"raf\", \"mutation\" or number`)\n\t})\n\n\tt.Run(\"ok_expr_poll_interval\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := setup(t)\n\t\ttb.vu.SetVar(t, \"page\", &sobek.Object{})\n\t\t_, err := tb.vu.RunAsync(t, `\n\t\t\tpage = await browser.newPage();\n\t\t\tawait page.evaluate(() => {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tconst el = document.createElement('h1');\n\t\t\t\t\tel.innerHTML = 'Hello';\n\t\t\t\t\tdocument.body.appendChild(el);\n\t\t\t\t}, 1000);\n\t\t\t});`,\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\tscript := `\n\t\t\tlet resp = await page.waitForFunction(%s, %s, %s);\n\t\t\tif (resp) {\n\t\t\t\tlog('ok: '+resp.innerHTML());\n\t\t\t} else {\n\t\t\t\tlog('err: '+err);\n\t\t\t}`\n\t\t_, err = tb.vu.RunAsync(t, script, `\"document.querySelector('h1')\"`, \"{ polling: 100, timeout: 2000, }\", \"null\")\n\t\trequire.NoError(t, err)\n\t\ttb.logCache.contains(\"ok: Hello\")\n\t})\n\n\tt.Run(\"ok_func_poll_mutation\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := setup(t)\n\n\t\ttb.vu.SetVar(t, \"page\", &sobek.Object{})\n\t\t_, err := tb.vu.RunAsync(t, `\n\t\t\tfn = () => document.querySelector('h1') !== null\n\n\t\t\tpage = await browser.newPage();\n\t\t\tawait page.evaluate(() => {\n\t\t\t\tconsole.log('calling setTimeout...');\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tconsole.log('creating element...');\n\t\t\t\t\tconst el = document.createElement('h1');\n\t\t\t\t\tel.innerHTML = 'Hello';\n\t\t\t\t\tdocument.body.appendChild(el);\n\t\t\t\t}, 1000);\n\t\t\t})`,\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\tscript := `\n\t\t\tlet resp = await page.waitForFunction(%s, %s, %s);\n\t\t\tlog('ok: '+resp);`\n\n\t\t_, err = tb.vu.RunAsync(t, script, \"fn\", \"{ polling: 'mutation', timeout: 2000, }\", \"null\")\n\t\trequire.NoError(t, err)\n\t\ttb.logCache.assertContains(t, \"ok: null\")\n\t})\n}\n\nfunc TestPageWaitForLoadState(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"err_wrong_event\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\terr := p.WaitForLoadState(\"none\", common.NewFrameWaitForLoadStateOptions(p.MainFrame().Timeout()))\n\t\trequire.ErrorContains(t, err, `invalid lifecycle event: \"none\"; must be one of: load, domcontentloaded, networkidle`)\n\t})\n}\n\n// See: The issue #187 for details.\nfunc TestPageWaitForNavigationErrOnCtxDone(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t)\n\tp := b.NewPage(nil)\n\tgo b.cancelContext()\n\t<-b.context().Done()\n\t_, err := p.WaitForNavigation(\n\t\tcommon.NewFrameWaitForNavigationOptions(p.Timeout()), nil)\n\trequire.ErrorContains(t, err, \"canceled\")\n}\n\nfunc TestPagePress(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t)\n\n\tp := tb.NewPage(nil)\n\n\terr := p.SetContent(`<input id=\"text1\">`, nil)\n\trequire.NoError(t, err)\n\n\topts := common.NewFramePressOptions(p.MainFrame().Timeout())\n\trequire.NoError(t, p.Press(\"#text1\", \"Shift+KeyA\", opts))\n\trequire.NoError(t, p.Press(\"#text1\", \"KeyB\", opts))\n\trequire.NoError(t, p.Press(\"#text1\", \"Shift+KeyC\", opts))\n\n\tinputValue, err := p.InputValue(\"#text1\", common.NewFrameInputValueOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"AbC\", inputValue)\n}\n\nfunc TestPageURL(t *testing.T) {\n\tt.Parallel()\n\n\tb := newTestBrowser(t, withHTTPServer())\n\n\tp := b.NewPage(nil)\n\turi, err := p.URL()\n\trequire.NoError(t, err)\n\tassert.Equal(t, common.BlankPage, uri)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tresp, err := p.Goto(\n\t\tb.url(\"/get\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, resp)\n\turi, err = p.URL()\n\trequire.NoError(t, err)\n\tassert.Regexp(t, \"http://.*/get\", uri)\n}\n\nfunc TestPageClose(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"page_from_browser\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tb := newTestBrowser(t, withHTTPServer())\n\n\t\tp := b.NewPage(nil)\n\n\t\terr := p.Close()\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"page_from_browserContext\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tb := newTestBrowser(t, withHTTPServer())\n\n\t\tc, err := b.NewContext(nil)\n\t\trequire.NoError(t, err)\n\t\tp, err := c.NewPage()\n\t\trequire.NoError(t, err)\n\n\t\terr = p.Close()\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestPageOn(t *testing.T) {\n\tt.Parallel()\n\n\ttests := map[string]struct {\n\t\tfun     string\n\t\twantErr string\n\t}{\n\t\t\"nil on('console') handler\": {\n\t\t\tfun:     `page.on('console')`,\n\t\t\twantErr: `TypeError: The \"listener\" argument must be a function`,\n\t\t},\n\t\t\"valid on('console') handler\": {\n\t\t\tfun: `page.on('console', () => {})`,\n\t\t},\n\t\t\"nil on('metric') handler\": {\n\t\t\tfun:     `page.on('metric')`,\n\t\t\twantErr: `TypeError: The \"listener\" argument must be a function`,\n\t\t},\n\t\t\"valid on('metric') handler\": {\n\t\t\tfun: `page.on('metric', () => {})`,\n\t\t},\n\t\t\"nil on('request') handler\": {\n\t\t\tfun:     `page.on('request')`,\n\t\t\twantErr: `TypeError: The \"listener\" argument must be a function`,\n\t\t},\n\t\t\"valid on('request') handler\": {\n\t\t\tfun: `page.on('request', () => {})`,\n\t\t},\n\t\t\"nil on('response') handler\": {\n\t\t\tfun:     `page.on('response')`,\n\t\t\twantErr: `TypeError: The \"listener\" argument must be a function`,\n\t\t},\n\t\t\"valid on('response') handler\": {\n\t\t\tfun: `page.on('response', () => {})`,\n\t\t},\n\t\t\"nil on('requestfailed') handler\": {\n\t\t\tfun:     `page.on('requestfailed')`,\n\t\t\twantErr: `TypeError: The \"listener\" argument must be a function`,\n\t\t},\n\t\t\"valid on('requestfailed') handler\": {\n\t\t\tfun: `page.on('requestfailed', () => {})`,\n\t\t},\n\t}\n\n\tfor name, tt := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\t\t\tdefer tb.vu.EndIteration(t)\n\n\t\t\tgv, err := tb.vu.RunAsync(t, `\n\t\t\t\tconst page = await browser.newPage();\n\t\t\t\ttry {\n\t\t\t\t\t%s        // e.g. page.on('console', handler);\n\t\t\t\t} finally {\n\t\t\t\t\tawait page.close();\n\t\t\t\t}\n \t\t\t`, tt.fun)\n\n\t\t\tgot := k6test.ToPromise(t, gv)\n\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, tt.wantErr)\n\t\t\t\tassert.Equal(t, sobek.PromiseStateRejected, got.State())\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, sobek.PromiseStateFulfilled, got.State())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPageOnConsole(t *testing.T) {\n\tt.Parallel()\n\n\tconst blankPage = \"about:blank\"\n\n\ttestCases := []struct {\n\t\tname      string\n\t\tconsoleFn string\n\t\tassertFn  func(*testing.T, *common.ConsoleMessage)\n\t}{\n\t\t{\n\t\t\tname:      \"on console.log\",\n\t\t\tconsoleFn: \"() => console.log('this is a log message')\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"log\", cm.Type)\n\t\t\t\tassert.Equal(t, \"this is a log message\", cm.Text)\n\t\t\t\tval, err := cm.Args[0].JSONValue()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"this is a log message\", val)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.debug\",\n\t\t\tconsoleFn: \"() => console.debug('this is a debug message')\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"debug\", cm.Type)\n\t\t\t\tassert.Equal(t, \"this is a debug message\", cm.Text)\n\t\t\t\tval, err := cm.Args[0].JSONValue()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"this is a debug message\", val)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.info\",\n\t\t\tconsoleFn: \"() => console.info('this is an info message')\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"info\", cm.Type)\n\t\t\t\tassert.Equal(t, \"this is an info message\", cm.Text)\n\t\t\t\tval, err := cm.Args[0].JSONValue()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"this is an info message\", val)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.error\",\n\t\t\tconsoleFn: \"() => console.error('this is an error message')\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"error\", cm.Type)\n\t\t\t\tassert.Equal(t, \"this is an error message\", cm.Text)\n\t\t\t\tval, err := cm.Args[0].JSONValue()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"this is an error message\", val)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.warn\",\n\t\t\tconsoleFn: \"() => console.warn('this is a warning message')\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"warning\", cm.Type)\n\t\t\t\tassert.Equal(t, \"this is a warning message\", cm.Text)\n\t\t\t\tval, err := cm.Args[0].JSONValue()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"this is a warning message\", val)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.dir\",\n\t\t\tconsoleFn: \"() => console.dir(document.location)\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"dir\", cm.Type)\n\t\t\t\tassert.Equal(t, \"Location\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.dirxml\",\n\t\t\tconsoleFn: \"() => console.dirxml(document.location)\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"dirxml\", cm.Type)\n\t\t\t\tassert.Equal(t, \"Location\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.table\",\n\t\t\tconsoleFn: \"() => console.table([['Grafana', 'k6'], ['Grafana', 'Mimir']])\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"table\", cm.Type)\n\t\t\t\tassert.Equal(t, \"Array(2)\", cm.Text)\n\t\t\t\tval, err := cm.Args[0].JSONValue()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, `[[\"Grafana\",\"k6\"],[\"Grafana\",\"Mimir\"]]`, val)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.trace\",\n\t\t\tconsoleFn: \"() => console.trace('trace example')\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"trace\", cm.Type)\n\t\t\t\tassert.Equal(t, \"trace example\", cm.Text)\n\t\t\t\tval, err := cm.Args[0].JSONValue()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"trace example\", val)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.clear\",\n\t\t\tconsoleFn: \"() => console.clear()\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"clear\", cm.Type)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.group\",\n\t\t\tconsoleFn: \"() => console.group()\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"startGroup\", cm.Type)\n\t\t\t\tassert.Equal(t, \"console.group\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.groupCollapsed\",\n\t\t\tconsoleFn: \"() => console.groupCollapsed()\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"startGroupCollapsed\", cm.Type)\n\t\t\t\tassert.Equal(t, \"console.groupCollapsed\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.groupEnd\",\n\t\t\tconsoleFn: \"() => console.groupEnd()\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"endGroup\", cm.Type)\n\t\t\t\tassert.Equal(t, \"console.groupEnd\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.assert\",\n\t\t\tconsoleFn: \"() => console.assert(2 == 3)\", // Only writes to console if assertion is false\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"assert\", cm.Type)\n\t\t\t\tassert.Equal(t, \"console.assert\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.count (default label)\",\n\t\t\tconsoleFn: \"() => console.count()\", // default label\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"count\", cm.Type)\n\t\t\t\tassert.Equal(t, \"default: 1\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.count\",\n\t\t\tconsoleFn: \"() => console.count('k6')\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"count\", cm.Type)\n\t\t\t\tassert.Equal(t, \"k6: 1\", cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:      \"on console.time\",\n\t\t\tconsoleFn: \"() => { console.time('k6'); console.timeEnd('k6'); }\",\n\t\t\tassertFn: func(t *testing.T, cm *common.ConsoleMessage) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Equal(t, \"timeEnd\", cm.Type)\n\t\t\t\tassert.Regexp(t, `^k6: [0-9]+\\.[0-9]+`, cm.Text, `expected prefix \"k6: <a float>\" but got %q`, cm.Text)\n\t\t\t\turi, err := cm.Page.URL()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.True(t, uri == blankPage, \"url is not %s\", blankPage)\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t// Use withSkipClose() opt as we will close it\n\t\t\t// manually to force the page.TaskQueue closing\n\t\t\ttb := newTestBrowser(t)\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tvar (\n\t\t\t\tdone1 = make(chan bool)\n\t\t\t\tdone2 = make(chan bool)\n\n\t\t\t\ttestTO = 2500 * time.Millisecond\n\t\t\t)\n\n\t\t\t// Console Messages should be multiplexed for every registered handler\n\t\t\teventHandlerOne := func(event common.PageEvent) error {\n\t\t\t\tdefer close(done1)\n\t\t\t\ttc.assertFn(t, event.ConsoleMessage)\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\teventHandlerTwo := func(event common.PageEvent) error {\n\t\t\t\tdefer close(done2)\n\t\t\t\ttc.assertFn(t, event.ConsoleMessage)\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// eventHandlerOne and eventHandlerTwo will be called from a\n\t\t\t// separate goroutine from within the page's async event loop.\n\t\t\t// This is why we need to wait on done1 and done2 to be closed.\n\t\t\terr := p.On(\"console\", eventHandlerOne)\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = p.On(\"console\", eventHandlerTwo)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = p.Evaluate(tc.consoleFn)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tselect {\n\t\t\tcase <-done1:\n\t\t\tcase <-time.After(testTO):\n\t\t\t\tassert.Fail(t, \"test timed out before eventHandlerOne completed\")\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase <-done2:\n\t\t\tcase <-time.After(testTO):\n\t\t\t\tassert.Fail(t, \"test timed out before eventHandlerTwo completed\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestPageTimeout(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname                     string\n\t\tdefaultTimeout           time.Duration\n\t\tdefaultNavigationTimeout time.Duration\n\t}{\n\t\t{\n\t\t\tname:           \"fail when timeout exceeds default timeout\",\n\t\t\tdefaultTimeout: 1 * time.Millisecond,\n\t\t},\n\t\t{\n\t\t\tname:                     \"fail when timeout exceeds default navigation timeout\",\n\t\t\tdefaultNavigationTimeout: 1 * time.Millisecond,\n\t\t},\n\t\t{\n\t\t\tname:                     \"default navigation timeout supersedes default timeout\",\n\t\t\tdefaultTimeout:           30 * time.Second,\n\t\t\tdefaultNavigationTimeout: 1 * time.Millisecond,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withHTTPServer())\n\n\t\t\ttb.withHandler(\"/slow\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\t_, err := fmt.Fprintf(w, `sorry for being so slow`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tvar timeout time.Duration\n\t\t\tif tc.defaultTimeout != 0 {\n\t\t\t\ttimeout = tc.defaultTimeout\n\t\t\t\tp.SetDefaultTimeout(tc.defaultTimeout.Milliseconds())\n\t\t\t}\n\t\t\tif tc.defaultNavigationTimeout != 0 {\n\t\t\t\ttimeout = tc.defaultNavigationTimeout\n\t\t\t\tp.SetDefaultNavigationTimeout(tc.defaultNavigationTimeout.Milliseconds())\n\t\t\t}\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: timeout,\n\t\t\t}\n\t\t\tres, err := p.Goto(\n\t\t\t\ttb.url(\"/slow\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.Nil(t, res)\n\t\t\tassert.ErrorContains(t, err, \"timed out after\")\n\t\t})\n\t}\n}\n\nfunc TestPageWaitForSelector(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // no idea but it doesn't work\n\t}\n\n\ttestCases := []struct {\n\t\tname          string\n\t\turl           string\n\t\topts          map[string]any\n\t\tcustomTimeout time.Duration\n\t\tselector      string\n\t\terrAssert     func(*testing.T, error)\n\t}{\n\t\t{\n\t\t\tname:     \"should wait for selector\",\n\t\t\turl:      \"wait_for.html\",\n\t\t\tselector: \"#my-div\",\n\t\t\terrAssert: func(t *testing.T, e error) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.Nil(t, e)\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"should TO waiting for selector\",\n\t\t\turl:  \"wait_for.html\",\n\t\t\t// set a timeout smaller than the time\n\t\t\t// it takes the element to show up\n\t\t\tcustomTimeout: time.Nanosecond,\n\t\t\tselector:      \"#my-div\",\n\t\t\terrAssert: func(t *testing.T, e error) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.ErrorContains(t, e, \"timed out after\")\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\n\t\t\tpage := tb.NewPage(nil)\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := page.Goto(\n\t\t\t\ttb.staticURL(tc.url),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttimeout := page.MainFrame().Timeout()\n\t\t\tif tc.customTimeout != 0 {\n\t\t\t\ttimeout = tc.customTimeout\n\t\t\t}\n\n\t\t\t_, err = page.WaitForSelector(tc.selector, common.NewFrameWaitForSelectorOptions(timeout))\n\t\t\ttc.errAssert(t, err)\n\t\t})\n\t}\n}\n\nfunc TestPageThrottleNetwork(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // windows timeouts\n\t}\n\n\ttestCases := []struct {\n\t\tname                     string\n\t\tnetworkProfile           common.NetworkProfile\n\t\twantMinRoundTripDuration int64\n\t}{\n\t\t{\n\t\t\tname: \"none\",\n\t\t\tnetworkProfile: common.NetworkProfile{\n\t\t\t\tLatency:  0,\n\t\t\t\tDownload: -1,\n\t\t\t\tUpload:   -1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// In the ping.html file, an async ping request is made. The time it takes\n\t\t\t// to perform the roundtrip of calling ping and getting the response is\n\t\t\t// measured and used to assert that Latency has been correctly used.\n\t\t\tname: \"latency\",\n\t\t\tnetworkProfile: common.NetworkProfile{\n\t\t\t\tLatency:  100,\n\t\t\t\tDownload: -1,\n\t\t\t\tUpload:   -1,\n\t\t\t},\n\t\t\twantMinRoundTripDuration: 100,\n\t\t},\n\t\t{\n\t\t\t// In the ping.html file, an async ping request is made, the ping response\n\t\t\t// returns the request body (around a 1MB). The time it takes to perform the\n\t\t\t// roundtrip of calling ping and getting the response body is measured and\n\t\t\t// used to assert that Download has been correctly used.\n\t\t\tname: \"download\",\n\t\t\tnetworkProfile: common.NetworkProfile{\n\t\t\t\tLatency:  0,\n\t\t\t\tDownload: 1000,\n\t\t\t\tUpload:   -1,\n\t\t\t},\n\t\t\twantMinRoundTripDuration: 1000,\n\t\t},\n\t\t{\n\t\t\t// In the ping.html file, an async ping request is made with around a 1MB body.\n\t\t\t// The time it takes to perform the roundtrip of calling ping is measured\n\t\t\t// and used to assert that Upload has been correctly used.\n\t\t\tname: \"upload\",\n\t\t\tnetworkProfile: common.NetworkProfile{\n\t\t\t\tLatency:  0,\n\t\t\t\tDownload: -1,\n\t\t\t\tUpload:   1000,\n\t\t\t},\n\t\t\twantMinRoundTripDuration: 1000,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\n\t\t\ttb.withHandler(\"/ping\", func(w http.ResponseWriter, req *http.Request) {\n\t\t\t\tdefer func() {\n\t\t\t\t\terr := req.Body.Close()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t}()\n\t\t\t\tbb, err := io.ReadAll(req.Body)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t_, err = fmt.Fprint(w, string(bb))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\n\t\t\tpage := tb.NewPage(nil)\n\n\t\t\terr := page.ThrottleNetwork(tc.networkProfile)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err = page.Goto(\n\t\t\t\ttb.staticURL(\"ping.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tselector := `div[id=\"result\"]`\n\n\t\t\t// result selector only appears once the page gets a response\n\t\t\t// from the async ping request.\n\t\t\t_, err = page.WaitForSelector(selector, common.NewFrameWaitForSelectorOptions(page.MainFrame().Timeout()))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresp, err := page.InnerText(selector, common.NewFrameInnerTextOptions(page.MainFrame().Timeout()))\n\t\t\trequire.NoError(t, err)\n\t\t\tms, err := strconv.ParseInt(resp, 10, 64)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.GreaterOrEqual(t, ms, tc.wantMinRoundTripDuration)\n\t\t})\n\t}\n}\n\n// This test will first navigate to the ping.html site a few times, record the\n// average time it takes to run the test. Next it will repeat the steps but\n// first apply CPU throttling. The average duration with CPU throttling\n// enabled should be longer than without it.\nfunc TestPageThrottleCPU(t *testing.T) {\n\tt.Parallel()\n\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // windows timeouts\n\t}\n\ttb := newTestBrowser(t, withFileServer())\n\n\ttb.withHandler(\"/ping\", func(w http.ResponseWriter, req *http.Request) {\n\t\tdefer func() {\n\t\t\terr := req.Body.Close()\n\t\t\trequire.NoError(t, err)\n\t\t}()\n\t\tbb, err := io.ReadAll(req.Body)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = fmt.Fprint(w, string(bb))\n\t\trequire.NoError(t, err)\n\t})\n\n\tpage := tb.NewPage(nil)\n\tconst iterations = 5\n\n\tnoCPUThrottle := performPingTest(t, tb, page, iterations)\n\n\terr := page.ThrottleCPU(common.CPUProfile{\n\t\tRate: 50,\n\t})\n\trequire.NoError(t, err)\n\n\twithCPUThrottle := performPingTest(t, tb, page, iterations)\n\n\tassert.Greater(t, withCPUThrottle, noCPUThrottle)\n}\n\nfunc performPingTest(t *testing.T, tb *testBrowser, page *common.Page, iterations int) int64 {\n\tt.Helper()\n\n\tvar ms int64\n\tfor range iterations {\n\t\tstart := time.Now()\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := page.Goto(\n\t\t\ttb.staticURL(\"ping.html\"),\n\t\t\topts,\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\tselector := `div[id=\"result\"]`\n\n\t\t// result selector only appears once the page gets a response\n\t\t// from the async ping request.\n\t\t_, err = page.WaitForSelector(selector, common.NewFrameWaitForSelectorOptions(page.MainFrame().Timeout()))\n\t\trequire.NoError(t, err)\n\n\t\tms += time.Since(start).Abs().Milliseconds()\n\t}\n\n\treturn ms / int64(iterations)\n}\n\nfunc TestPageIsVisible(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // timeouts\n\t}\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tselector string\n\t\toptions  common.FrameIsVisibleOptions\n\t\twant     bool\n\t\twantErr  string\n\t}{\n\t\t{\n\t\t\tname:     \"visible\",\n\t\t\tselector: \"div[id=my-div]\",\n\t\t\twant:     true,\n\t\t},\n\t\t{\n\t\t\tname:     \"not_visible\",\n\t\t\tselector: \"div[id=my-div-3]\",\n\t\t\twant:     false,\n\t\t},\n\t\t{\n\t\t\tname:     \"not_found\",\n\t\t\tselector: \"div[id=does-not-exist]\",\n\t\t\twant:     false,\n\t\t},\n\t\t{\n\t\t\tname:     \"first_div\",\n\t\t\tselector: \"div\",\n\t\t\twant:     true,\n\t\t},\n\t\t{\n\t\t\tname:     \"first_div\",\n\t\t\tselector: \"div\",\n\t\t\toptions: common.FrameIsVisibleOptions{\n\t\t\t\tStrict: true,\n\t\t\t},\n\t\t\twantErr: \"error:strictmodeviolation\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\n\t\t\tpage := tb.NewPage(nil)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := page.Goto(\n\t\t\t\ttb.staticURL(\"visible.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgot, err := page.IsVisible(tc.selector, &tc.options)\n\t\t\tif tc.wantErr != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, tc.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, tc.want, got)\n\t\t})\n\t}\n}\n\nfunc TestPageIsHidden(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip() // timeouts\n\t}\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tselector string\n\t\toptions  common.FrameIsHiddenOptions\n\t\twant     bool\n\t\twantErr  string\n\t}{\n\t\t{\n\t\t\tname:     \"hidden\",\n\t\t\tselector: \"div[id=my-div-3]\",\n\t\t\twant:     true,\n\t\t},\n\t\t{\n\t\t\tname:     \"visible\",\n\t\t\tselector: \"div[id=my-div]\",\n\t\t\twant:     false,\n\t\t},\n\t\t{\n\t\t\tname:     \"not_found\",\n\t\t\tselector: \"div[id=does-not-exist]\",\n\t\t\twant:     true,\n\t\t},\n\t\t{\n\t\t\tname:     \"first_div\",\n\t\t\tselector: \"div\",\n\t\t\twant:     false,\n\t\t},\n\t\t{\n\t\t\tname:     \"first_div\",\n\t\t\tselector: \"div\",\n\t\t\toptions: common.FrameIsHiddenOptions{\n\t\t\t\tStrict: true,\n\t\t\t},\n\t\t\twantErr: \"error:strictmodeviolation\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\n\t\t\tpage := tb.NewPage(nil)\n\n\t\t\topts := &common.FrameGotoOptions{\n\t\t\t\tTimeout: common.DefaultTimeout,\n\t\t\t}\n\t\t\t_, err := page.Goto(\n\t\t\t\ttb.staticURL(\"visible.html\"),\n\t\t\t\topts,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tgot, err := page.IsHidden(tc.selector, &tc.options)\n\t\t\tif tc.wantErr != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, tc.wantErr)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, tc.want, got)\n\t\t})\n\t}\n}\n\nfunc TestShadowDOMAndDocumentFragment(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"windows timeouts on these tests\")\n\t}\n\ttests := []struct {\n\t\tname     string\n\t\tselector string\n\t\twant     string\n\t}{\n\t\t{\n\t\t\t// This test waits for an element that is in the DocumentFragment.\n\t\t\tname:     \"waitFor_DocumentFragment\",\n\t\t\tselector: `//p[@id=\"inDocFrag\"]`,\n\t\t\twant:     \"This text is added via a document fragment!\",\n\t\t},\n\t\t{\n\t\t\t// This test waits for an element that is in the DocumentFragment\n\t\t\t// that is within an open shadow root.\n\t\t\tname:     \"waitFor_ShadowRoot_DocumentFragment\",\n\t\t\tselector: `//p[@id=\"inShadowRootDocFrag\"]`,\n\t\t\twant:     \"This is inside Shadow DOM, added via a DocumentFragment!\",\n\t\t},\n\t\t{\n\t\t\t// This test waits for an element that is in the original Document.\n\t\t\tname:     \"waitFor_done\",\n\t\t\tselector: `//div[@id=\"done\"]`,\n\t\t\twant:     \"All additions to page completed (i'm in the original document)\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\t\t\tdefer tb.vu.EndIteration(t)\n\n\t\t\tgot := tb.vu.RunPromise(t, `\n\t\t\t\tconst p = await browser.newPage()\n\t\t\t\tawait p.goto(\"%s\")\n\n\t\t\t\tconst s = p.locator('%s')\n\t\t\t\tawait s.waitFor({\n\t\t\t\t\ttimeout: 1000,\n\t\t\t\t\tstate: 'attached',\n\t\t\t\t});\n\n\t\t\t\tconst text = await s.innerText();\n\t\t\t\tawait p.close()\n\t\t\t\treturn text;\n \t\t\t`, tb.staticURL(\"shadow_and_doc_frag.html\"), tt.selector)\n\t\t\tassert.Equal(t, tt.want, got.Result().String())\n\t\t})\n\t}\n}\n\nfunc TestPageTargetBlank(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\ttb.withHandler(\"/home\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t_, err := w.Write([]byte(\n\t\t\t`<!DOCTYPE html><html><head></head><body>\n\t\t\t\t<a href=\"/link\" target=\"_blank\">click me</a>\n\t\t\t</body></html>`,\n\t\t))\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/link\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t_, err := w.Write(\n\t\t\t[]byte(`<!DOCTYPE html><html><head></head><body><h1>you clicked!</h1></body></html>`),\n\t\t)\n\t\trequire.NoError(t, err)\n\t})\n\n\tp := tb.NewPage(nil)\n\n\t// Navigate to the page with a link that opens a new page.\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tresp, err := p.Goto(tb.url(\"/home\"), opts)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, resp)\n\n\t// Current page count should be 1.\n\tpp := p.Context().Pages()\n\tassert.Equal(t, 1, len(pp))\n\n\t// This link should open the link on a new page.\n\terr = p.Click(\"a[href='/link']\", common.NewFrameClickOptions(p.Timeout()))\n\trequire.NoError(t, err)\n\n\t// Wait for the page to be created and for it to navigate to the link.\n\tobj, err := p.Context().WaitForEvent(\"page\", nil, common.DefaultTimeout)\n\trequire.NoError(t, err)\n\tp2, ok := obj.(*common.Page)\n\trequire.True(t, ok, \"return from WaitForEvent is not a Page\")\n\n\terr = p2.WaitForLoadState(common.LifecycleEventLoad.String(), common.NewFrameWaitForLoadStateOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\n\t// Now there should be 2 pages.\n\tpp = p.Context().Pages()\n\tassert.Equal(t, 2, len(pp))\n\n\t// Make sure the new page contains the correct page.\n\tgot, err := p2.InnerHTML(\"h1\", common.NewFrameInnerHTMLOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"you clicked!\", got)\n}\n\nfunc TestPageGetAttribute(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\" href=\"null\">Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tgot, ok, err := p.GetAttribute(\"#el\", \"href\", common.NewFrameBaseOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"null\", got)\n}\n\nfunc TestPageGetAttributeMissing(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\">Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tgot, ok, err := p.GetAttribute(\"#el\", \"missing\", common.NewFrameBaseOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.False(t, ok)\n\tassert.Equal(t, \"\", got)\n}\n\nfunc TestPageGetAttributeEmpty(t *testing.T) {\n\tt.Parallel()\n\n\tp := newTestBrowser(t).NewPage(nil)\n\terr := p.SetContent(`<a id=\"el\" empty>Something</a>`, nil)\n\trequire.NoError(t, err)\n\n\tgot, ok, err := p.GetAttribute(\"#el\", \"empty\", common.NewFrameBaseOptions(p.MainFrame().Timeout()))\n\trequire.NoError(t, err)\n\trequire.True(t, ok)\n\tassert.Equal(t, \"\", got)\n}\n\nfunc TestPageOnMetric(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname      string\n\t\tfun       string\n\t\twant      string\n\t\twantRegex string\n\t\twantErr   string\n\t}{\n\t\t{\n\t\t\t// Just a single page.on.\n\t\t\tname: \"single_page.on\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t  \tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twant: \"ping-1\",\n\t\t},\n\t\t{\n\t\t\t// A single page.on but with multiple calls to Tag.\n\t\t\tname: \"multi_tag\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-2',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t]\n\t\t\t\t  });\n\t\t\t});`,\n\t\t\twant: \"ping-2\",\n\t\t},\n\t\t{\n\t\t\t// Two page.on and in one of them multiple calls to Tag.\n\t\t\tname: \"multi_tag_page.on\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-2',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t  {url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t  ]\n\t\t\t\t  });\n\t\t\t});\n\t\t\tpage.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-3',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twant: \"ping-3\",\n\t\t},\n\t\t{\n\t\t\t// A single page.on but within it another page.on.\n\t\t\tname: \"multi_page.on_call\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t\tpage.on('metric', (metric) => {\n\t\t\t\t\tmetric.tag({\n\t\t\t\t\t\tname:'ping-4',\n\t\t\t\t\t\tmatches: [\n\t\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/},\n\t\t\t\t\t\t]\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twant: \"ping-4\",\n\t\t},\n\t\t{\n\t\t\t// With method field GET, which is the correct method for the request.\n\t\t\tname: \"with_method\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/, method: 'GET'},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twant: \"ping-1\",\n\t\t},\n\t\t{\n\t\t\t// With method field \" get \", which is to ensure it is internally\n\t\t\t// converted to \"GET\" before comparing.\n\t\t\tname: \"lowercase_needs_trimming\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/, method: ' get '},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twant: \"ping-1\",\n\t\t},\n\t\t{\n\t\t\t// When supplying the wrong request method (POST) when it should be GET.\n\t\t\t// In this case the URLs aren't grouped.\n\t\t\tname: \"wrong_method_should_skip_method_comparison\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/, method: 'POST'},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twantRegex: `http://127\\.0\\.0\\.1:[0-9]+/ping\\?h=[0-9a-z]+`,\n\t\t},\n\t\t{\n\t\t\t// We should get an error back when the name is invalid (empty string)\n\t\t\tname: \"with_invalid_name\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'  ',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/, method: 'GET'},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twantRegex: `http://127\\.0\\.0\\.1:[0-9]+/ping\\?h=[0-9a-z]+`,\n\t\t\twantErr:   `name \"  \" is invalid`,\n\t\t},\n\t\t{\n\t\t\t// We should get an error back when the method is invalid.\n\t\t\tname: \"with_invalid_name\",\n\t\t\tfun: `page.on('metric', (metric) => {\n\t\t\t\tmetric.tag({\n\t\t\t\t\tname:'ping-1',\n\t\t\t\t\tmatches: [\n\t\t\t\t\t\t{url: /^http:\\/\\/127\\.0\\.0\\.1\\:[0-9]+\\/ping\\?h=[0-9a-z]+$/, method: 'foo'},\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t});`,\n\t\t\twantRegex: `http://127\\.0\\.0\\.1:[0-9]+/ping\\?h=[0-9a-z]+`,\n\t\t\twantErr:   `method \"foo\" is invalid`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar foundAmended atomic.Int32\n\t\t\tvar foundUnamended atomic.Int32\n\n\t\t\tdone := make(chan bool)\n\n\t\t\tsamples := make(chan k6metrics.SampleContainer)\n\t\t\t// This page will perform many pings with a changing h query parameter.\n\t\t\t// This URL should be grouped according to how page.on('metric') is used.\n\t\t\ttb := newTestBrowser(t, withHTTPServer(), withSamples(samples))\n\t\t\ttb.withHandler(\"/home\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t_, err := fmt.Fprintf(w, `\n\t\t<html>\n\t\t\t<head></head>\n\t\t\t<body>\n\t\t\t\t<script type=\"module\">\n\t\t\t\t\tawait ping();\n\t\t\t\t\tasync function ping() {\n\t\t\t\t\t\tawait fetch('/ping?h=2kq2lo6n06');\n\t\t\t\t\t\tawait fetch('/ping?h=ej0ypprcjk');\n\t\t\t\t\t}\n\t\t\t\t</script>\n\t\t\t</body>\n\t\t</html>`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t\ttb.withHandler(\"/ping\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t_, err := fmt.Fprintf(w, `pong`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\n\t\t\tignoreURLs := map[string]any{\n\t\t\t\ttb.url(\"/home\"):        nil,\n\t\t\t\ttb.url(\"/favicon.ico\"): nil,\n\t\t\t}\n\t\t\tgo func() {\n\t\t\t\tdefer close(done)\n\t\t\t\tfor e := range samples {\n\t\t\t\t\tss := e.GetSamples()\n\t\t\t\t\tfor _, s := range ss {\n\t\t\t\t\t\t// At the moment all metrics that the browser emits contains\n\t\t\t\t\t\t// both a url and name tag on each metric.\n\t\t\t\t\t\tu, ok := s.Tags.Get(\"url\")\n\t\t\t\t\t\tassert.True(t, ok)\n\t\t\t\t\t\tn, ok := s.Tags.Get(\"name\")\n\t\t\t\t\t\tassert.True(t, ok)\n\n\t\t\t\t\t\t// The name and url tags should have the same value.\n\t\t\t\t\t\tassert.Equal(t, u, n)\n\n\t\t\t\t\t\t// If the url is in the ignoreURLs map then this will\n\t\t\t\t\t\t// not have been matched on by the regex, so continue.\n\t\t\t\t\t\tif _, ok := ignoreURLs[u]; ok {\n\t\t\t\t\t\t\tfoundUnamended.Add(1)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Url shouldn't contain any of the hash values, and should\n\t\t\t\t\t\t// instead take the name that was supplied in the Tag\n\t\t\t\t\t\t// function on metric in page.on.\n\t\t\t\t\t\tif tt.wantRegex != \"\" {\n\t\t\t\t\t\t\tassert.Regexp(t, tt.wantRegex, u)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tassert.Equal(t, tt.want, u)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfoundAmended.Add(1)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\t\t\tdefer tb.vu.EndIteration(t)\n\n\t\t\t// Some of the business logic is in the mapping layer unfortunately.\n\t\t\t// To test everything is wried up correctly, we're required to work\n\t\t\t// with RunPromise.\n\t\t\tgv, err := tb.vu.RunAsync(t, `\n\t\t\t\tconst page = await browser.newPage()\n\n\t\t\t\t%s\n\n\t\t\t\tawait page.goto('%s', {waitUntil: 'networkidle'});\n\n\t\t\t\tawait page.close()\n\t\t\t`, tt.fun, tb.url(\"/home\"))\n\n\t\t\tif tt.wantErr != \"\" {\n\t\t\t\tassert.ErrorContains(t, err, tt.wantErr)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\n\t\t\tgot := k6test.ToPromise(t, gv)\n\n\t\t\tassert.True(t, got.Result().Equals(sobek.Null()))\n\n\t\t\tclose(samples)\n\n\t\t\t<-done\n\n\t\t\t// We want to make sure that we found at least one occurrence\n\t\t\t// of a metric which matches our expectations.\n\t\t\tassert.True(t, foundAmended.Load() > 0)\n\n\t\t\t// We want to make sure that we found at least one occurrence\n\t\t\t// of a metric which didn't match our expectations.\n\t\t\tassert.True(t, foundUnamended.Load() > 0)\n\t\t})\n\t}\n}\n\nfunc TestPageOnRequest(t *testing.T) {\n\tt.Parallel()\n\n\t// Start and setup a webserver to test the page.on('request') handler.\n\ttb := newTestBrowser(t, withHTTPServer())\n\n\ttb.withHandler(\"/home\", func(w http.ResponseWriter, r *http.Request) {\n\t\t_, err := fmt.Fprintf(w, `<!DOCTYPE html>\n<html>\n<head>\n    <link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n    <script>fetch('/api', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify({name: 'tester'})\n    })</script>\n</body>\n</html>`)\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tbody, err := io.ReadAll(r.Body)\n\t\trequire.NoError(t, err)\n\n\t\tvar data struct {\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\terr = json.Unmarshal(body, &data)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = fmt.Fprintf(w, `{\"message\": \"Hello %s!\"}`, data.Name)\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/style.css\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/css\")\n\t\t_, err := fmt.Fprintf(w, `body { background-color: #f0f0f0; }`)\n\t\trequire.NoError(t, err)\n\t})\n\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\tdefer tb.vu.EndIteration(t)\n\n\t// Some of the business logic is in the mapping layer unfortunately.\n\t// To test everything is wried up correctly, we're required to work\n\t// with RunPromise.\n\t//\n\t// The code below is the JavaScript code that is executed in the k6 iteration.\n\t// It will wait for all requests to be captured in returnValue, before returning.\n\tgv, err := tb.vu.RunAsync(t, `\n\t\tconst context = await browser.newContext({locale: 'en-US', userAgent: 'some-user-agent'});\n\t\tconst page = await context.newPage();\n\n\t\tvar returnValue = [];\n\t\tpage.on('request', async (request) => {\n\t\t\treturnValue.push({\n\t\t\t\tallHeaders: await request.allHeaders(),\n\t\t\t\tframeUrl: request.frame().url(),\n\t\t\t\tacceptLanguageHeader: await request.headerValue('Accept-Language'),\n\t\t\t\theaders: request.headers(),\n\t\t\t\theadersArray: await request.headersArray(),\n\t\t\t\tisNavigationRequest: request.isNavigationRequest(),\n\t\t\t\tmethod: request.method(),\n\t\t\t\tpostData: request.postData(),\n\t\t\t\tpostDataBuffer: request.postDataBuffer() ? String.fromCharCode.apply(null, new Uint8Array(request.postDataBuffer())) : null,\n\t\t\t\tresourceType: request.resourceType(),\n\t\t\t\t// Ignoring response for now since it is not reliable as we don't explicitly wait for the request to finish.\n\t\t\t\t// response: await request.response(),\n\t\t\t\tsize: request.size(),\n\t\t\t\t// Ignoring timing for now since it is not reliable as we don't explicitly wait for the request to finish.\n\t\t\t\t// timing: request.timing(),\n\t\t\t\turl: request.url()\n\t\t\t});\n\t\t});\n\n\t\tawait page.goto('%s', {waitUntil: 'networkidle'});\n\n\t\tawait page.close();\n\n\t\treturn JSON.stringify(returnValue, null, 2);\n\t`, tb.url(\"/home\"))\n\tassert.NoError(t, err)\n\n\tgot := k6test.ToPromise(t, gv)\n\n\t// Convert the result to a string and then to a slice of requests.\n\tvar requests []request\n\terr = json.Unmarshal([]byte(got.Result().String()), &requests)\n\trequire.NoError(t, err)\n\n\texpected := []request{\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"accept-language\":           \"en-US\",\n\t\t\t\t\"upgrade-insecure-requests\": \"1\",\n\t\t\t\t\"user-agent\":                \"some-user-agent\",\n\t\t\t},\n\t\t\tFrameURL:             \"about:blank\",\n\t\t\tAcceptLanguageHeader: \"en-US\",\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Accept-Language\":           \"en-US\",\n\t\t\t\t\"Upgrade-Insecure-Requests\": \"1\",\n\t\t\t\t\"User-Agent\":                \"some-user-agent\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"Upgrade-Insecure-Requests\", \"value\": \"1\"},\n\t\t\t\t{\"name\": \"User-Agent\", \"value\": \"some-user-agent\"},\n\t\t\t\t{\"name\": \"Accept-Language\", \"value\": \"en-US\"},\n\t\t\t},\n\t\t\tIsNavigationRequest: true,\n\t\t\tMethod:              \"GET\",\n\t\t\tPostData:            \"\",\n\t\t\tPostDataBuffer:      \"\",\n\t\t\tResourceType:        \"Document\",\n\t\t\tSize: map[string]int{\n\t\t\t\t\"body\":    0,\n\t\t\t\t\"headers\": 103,\n\t\t\t},\n\t\t\tURL: tb.url(\"/home\"),\n\t\t},\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"accept-language\": \"en-US\",\n\t\t\t\t\"referer\":         tb.url(\"/home\"),\n\t\t\t\t\"user-agent\":      \"some-user-agent\",\n\t\t\t},\n\t\t\tFrameURL:             tb.url(\"/home\"),\n\t\t\tAcceptLanguageHeader: \"en-US\",\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Accept-Language\": \"en-US\",\n\t\t\t\t\"Referer\":         tb.url(\"/home\"),\n\t\t\t\t\"User-Agent\":      \"some-user-agent\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"User-Agent\", \"value\": \"some-user-agent\"},\n\t\t\t\t{\"name\": \"Accept-Language\", \"value\": \"en-US\"},\n\t\t\t\t{\"name\": \"Referer\", \"value\": tb.url(\"/home\")},\n\t\t\t},\n\t\t\tIsNavigationRequest: false,\n\t\t\tMethod:              \"GET\",\n\t\t\tPostData:            \"\",\n\t\t\tPostDataBuffer:      \"\",\n\t\t\tResourceType:        \"Stylesheet\",\n\t\t\tSize: map[string]int{\n\t\t\t\t\"body\":    0,\n\t\t\t\t\"headers\": 116,\n\t\t\t},\n\t\t\tURL: tb.url(\"/style.css\"),\n\t\t},\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"accept-language\": \"en-US\",\n\t\t\t\t\"content-type\":    \"application/json\",\n\t\t\t\t\"referer\":         tb.url(\"/home\"),\n\t\t\t\t\"user-agent\":      \"some-user-agent\",\n\t\t\t},\n\t\t\tFrameURL:             tb.url(\"/home\"),\n\t\t\tAcceptLanguageHeader: \"en-US\",\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Accept-Language\": \"en-US\",\n\t\t\t\t\"Content-Type\":    \"application/json\",\n\t\t\t\t\"Referer\":         tb.url(\"/home\"),\n\t\t\t\t\"User-Agent\":      \"some-user-agent\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"Referer\", \"value\": tb.url(\"/home\")},\n\t\t\t\t{\"name\": \"User-Agent\", \"value\": \"some-user-agent\"},\n\t\t\t\t{\"name\": \"Accept-Language\", \"value\": \"en-US\"},\n\t\t\t\t{\"name\": \"Content-Type\", \"value\": \"application/json\"},\n\t\t\t},\n\t\t\tIsNavigationRequest: false,\n\t\t\tMethod:              \"POST\",\n\t\t\tPostData:            `{\"name\":\"tester\"}`,\n\t\t\tPostDataBuffer:      `{\"name\":\"tester\"}`,\n\t\t\tResourceType:        \"Fetch\",\n\t\t\tSize: map[string]int{\n\t\t\t\t\"body\":    17,\n\t\t\t\t\"headers\": 143,\n\t\t\t},\n\t\t\tURL: tb.url(\"/api\"),\n\t\t},\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"accept-language\": \"en-US\",\n\t\t\t\t\"referer\":         tb.url(\"/home\"),\n\t\t\t\t\"user-agent\":      \"some-user-agent\",\n\t\t\t},\n\t\t\tFrameURL:             tb.url(\"/home\"),\n\t\t\tAcceptLanguageHeader: \"en-US\",\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Accept-Language\": \"en-US\",\n\t\t\t\t\"Referer\":         tb.url(\"/home\"),\n\t\t\t\t\"User-Agent\":      \"some-user-agent\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"Accept-Language\", \"value\": \"en-US\"},\n\t\t\t\t{\"name\": \"Referer\", \"value\": tb.url(\"/home\")},\n\t\t\t\t{\"name\": \"User-Agent\", \"value\": \"some-user-agent\"},\n\t\t\t},\n\t\t\tIsNavigationRequest: false,\n\t\t\tMethod:              \"GET\",\n\t\t\tPostData:            \"\",\n\t\t\tPostDataBuffer:      \"\",\n\t\t\tResourceType:        \"Other\",\n\t\t\tSize: map[string]int{\n\t\t\t\t\"body\":    0,\n\t\t\t\t\"headers\": 118,\n\t\t\t},\n\t\t\tURL: tb.url(\"/favicon.ico\"),\n\t\t},\n\t}\n\n\t// Compare each request one by one for better test failure visibility\n\tfor _, req := range requests {\n\t\ti := slices.IndexFunc(expected, func(r request) bool { return req.URL == r.URL })\n\t\tassert.NotEqual(t, -1, i, \"failed to find expected request with URL %s\", req.URL)\n\n\t\tsortByName := func(m1, m2 map[string]string) int {\n\t\t\treturn strings.Compare(m1[\"name\"], m2[\"name\"])\n\t\t}\n\t\tslices.SortFunc(req.HeadersArray, sortByName)\n\t\tslices.SortFunc(expected[i].HeadersArray, sortByName)\n\t\tassert.Equal(t, expected[i], req)\n\t}\n}\n\ntype request struct {\n\tAllHeaders           map[string]string   `json:\"allHeaders\"`\n\tFrameURL             string              `json:\"frameUrl\"`\n\tAcceptLanguageHeader string              `json:\"acceptLanguageHeader\"`\n\tHeaders              map[string]string   `json:\"headers\"`\n\tHeadersArray         []map[string]string `json:\"headersArray\"`\n\tIsNavigationRequest  bool                `json:\"isNavigationRequest\"`\n\tMethod               string              `json:\"method\"`\n\tPostData             string              `json:\"postData\"`\n\tPostDataBuffer       string              `json:\"postDataBuffer\"`\n\tResourceType         string              `json:\"resourceType\"`\n\tSize                 map[string]int      `json:\"size\"`\n\tURL                  string              `json:\"url\"`\n}\n\ntype response struct {\n\tAllHeaders            map[string]string      `json:\"allHeaders\"`\n\tBody                  string                 `json:\"body\"`\n\tFrameURL              string                 `json:\"frameUrl\"`\n\tAcceptLanguageHeader  string                 `json:\"acceptLanguageHeader\"`\n\tAcceptLanguageHeaders []string               `json:\"acceptLanguageHeaders\"`\n\tHeaders               map[string]string      `json:\"headers\"`\n\tHeadersArray          []map[string]string    `json:\"headersArray\"`\n\tJSON                  string                 `json:\"json\"`\n\tOK                    bool                   `json:\"ok\"`\n\tRequestURL            string                 `json:\"requestUrl\"`\n\tSecurityDetails       common.SecurityDetails `json:\"securityDetails\"`\n\tServerAddr            common.RemoteAddress   `json:\"serverAddr\"`\n\tSize                  map[string]int         `json:\"size\"`\n\tStatus                int64                  `json:\"status\"`\n\tStatusText            string                 `json:\"statusText\"`\n\tURL                   string                 `json:\"url\"`\n\tText                  string                 `json:\"text\"`\n}\n\nfunc TestPageOnResponse(t *testing.T) {\n\tt.Parallel()\n\n\t// Start and setup a webserver to test the page.on('request') handler.\n\ttb := newTestBrowser(t, withHTTPServer())\n\n\ttb.withHandler(\"/home\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t_, err := fmt.Fprintf(w, `<!DOCTYPE html>\n<html>\n<head>\n    <link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n    <script>fetch('/api', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify({name: 'tester'})\n    })</script>\n</body>\n</html>`)\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tbody, err := io.ReadAll(r.Body)\n\t\trequire.NoError(t, err)\n\t\tdefer require.NoError(t, r.Body.Close())\n\n\t\tvar data struct {\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\terr = json.Unmarshal(body, &data)\n\t\trequire.NoError(t, err)\n\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t_, err = fmt.Fprintf(w, `{\"message\": \"Hello %s!\"}`, data.Name)\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/style.css\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/css\")\n\t\t_, err := fmt.Fprintf(w, `body { background-color: #f0f0f0; }`)\n\t\trequire.NoError(t, err)\n\t})\n\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\tdefer tb.vu.EndIteration(t)\n\t// Some of the business logic is in the mapping layer unfortunately.\n\t// To test everything is wried up correctly, we're required to work\n\t// with RunPromise.\n\t//\n\t// The code below is the JavaScript code that is executed in the k6 iteration.\n\t// It will wait for all requests to be captured in returnValue, before returning.\n\tgv, err := tb.vu.RunAsync(t, `\n\t\tconst context = await browser.newContext({locale: 'en-US', userAgent: 'some-user-agent'});\n\t\tconst page = await context.newPage();\n\n\t\tvar returnValue = [];\n\t\tpage.on('response', async (response) => {\n\t\t\t// We need to check if the response is JSON before calling json()\n\t\t\tconst allHeaders = await response.allHeaders();\n\t\t\tvar json = null;\n\t\t\tif (allHeaders[\"content-type\"] === \"application/json\") {\n\t\t\t\tjson = await response.json();\n\t\t\t}\n\n\t\t\treturnValue.push({\n\t\t\t\tallHeaders: allHeaders,\n\t\t\t\tbody: await response.body() ? String.fromCharCode.apply(null, new Uint8Array(await response.body())) : null,\n\t\t\t\tframeUrl: response.frame().url(),\n\t\t\t\tacceptLanguageHeader: await response.headerValue('Accept-Language'),\n\t\t\t\tacceptLanguageHeaders: await response.headerValues('Accept-Language'),\n\t\t\t\theaders: response.headers(),\n\t\t\t\theadersArray: await response.headersArray(),\n\t\t\t\tjson: JSON.stringify(json),\n\t\t\t\tok: response.ok(),\n\t\t\t\trequestUrl: response.request().url(),\n\t\t\t\tsecurityDetails: await response.securityDetails(),\n\t\t\t\tserverAddr: await response.serverAddr(),\n\t\t\t\tsize: await response.size(),\n\t\t\t\tstatus: response.status(),\n\t\t\t\tstatusText: response.statusText(),\n\t\t\t\turl: response.url(),\n\t\t\t\ttext: await response.text()\n\t\t\t});\n\t\t})\n\n\t\tawait page.goto('%s', {waitUntil: 'networkidle'});\n\n\t\tawait page.close();\n\n\t\treturn JSON.stringify(returnValue, null, 2);\n\t`, tb.url(\"/home\"))\n\trequire.NoError(t, err)\n\n\tgot := k6test.ToPromise(t, gv)\n\n\t// Convert the result to a string and then to a slice of requests.\n\tvar responses []response\n\terr = json.Unmarshal([]byte(got.Result().String()), &responses)\n\trequire.NoError(t, err)\n\n\t// Normalize the date\n\tfor i := range responses {\n\t\tfor k := range responses[i].AllHeaders {\n\t\t\tif strings.Contains(strings.ToLower(k), \"date\") {\n\t\t\t\tresponses[i].AllHeaders[k] = \"Wed, 29 Jan 2025 09:00:00 GMT\"\n\t\t\t}\n\t\t}\n\t\tfor k := range responses[i].Headers {\n\t\t\tif strings.Contains(strings.ToLower(k), \"date\") {\n\t\t\t\tresponses[i].Headers[k] = \"Wed, 29 Jan 2025 09:00:00 GMT\"\n\t\t\t}\n\t\t}\n\t\tfor k, header := range responses[i].HeadersArray {\n\t\t\tif strings.Contains(strings.ToLower(header[\"name\"]), \"date\") {\n\t\t\t\tresponses[i].HeadersArray[k][\"value\"] = \"Wed, 29 Jan 2025 09:00:00 GMT\"\n\t\t\t}\n\t\t}\n\t}\n\n\tserverURL := tb.http.ServerHTTP.URL\n\thost, p, err := net.SplitHostPort(strings.TrimPrefix(serverURL, \"http://\"))\n\trequire.NoError(t, err)\n\n\tport, err := strconv.ParseInt(p, 10, 64)\n\trequire.NoError(t, err)\n\n\texpected := []response{\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"content-length\": \"286\",\n\t\t\t\t\"content-type\":   \"text/html; charset=utf-8\",\n\t\t\t\t\"date\":           \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t},\n\t\t\tBody:                  \"<!DOCTYPE html>\\n<html>\\n<head>\\n    <link rel=\\\"stylesheet\\\" href=\\\"/style.css\\\">\\n</head>\\n<body>\\n    <script>fetch('/api', {\\n      method: 'POST',\\n      headers: {\\n        'Content-Type': 'application/json'\\n      },\\n      body: JSON.stringify({name: 'tester'})\\n    })</script>\\n</body>\\n</html>\",\n\t\t\tFrameURL:              tb.url(\"/home\"),\n\t\t\tAcceptLanguageHeader:  \"\",\n\t\t\tAcceptLanguageHeaders: []string{\"\"},\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Content-Length\": \"286\",\n\t\t\t\t\"Content-Type\":   \"text/html; charset=utf-8\",\n\t\t\t\t\"Date\":           \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"Content-Length\", \"value\": \"286\"},\n\t\t\t\t{\"name\": \"Content-Type\", \"value\": \"text/html; charset=utf-8\"},\n\t\t\t\t{\"name\": \"Date\", \"value\": \"Wed, 29 Jan 2025 09:00:00 GMT\"},\n\t\t\t},\n\t\t\tJSON:            \"null\",\n\t\t\tOK:              true,\n\t\t\tRequestURL:      tb.url(\"/home\"),\n\t\t\tSecurityDetails: common.SecurityDetails{},\n\t\t\tServerAddr:      common.RemoteAddress{IPAddress: host, Port: port},\n\t\t\tSize:            map[string]int{\"body\": 286, \"headers\": 117},\n\t\t\tStatus:          200,\n\t\t\tStatusText:      \"OK\",\n\t\t\tURL:             tb.url(\"/home\"),\n\t\t\tText:            \"<!DOCTYPE html>\\n<html>\\n<head>\\n    <link rel=\\\"stylesheet\\\" href=\\\"/style.css\\\">\\n</head>\\n<body>\\n    <script>fetch('/api', {\\n      method: 'POST',\\n      headers: {\\n        'Content-Type': 'application/json'\\n      },\\n      body: JSON.stringify({name: 'tester'})\\n    })</script>\\n</body>\\n</html>\",\n\t\t},\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"content-length\": \"35\",\n\t\t\t\t\"content-type\":   \"text/css\",\n\t\t\t\t\"date\":           \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t},\n\t\t\tBody:                  \"body { background-color: #f0f0f0; }\",\n\t\t\tFrameURL:              tb.url(\"/home\"),\n\t\t\tAcceptLanguageHeader:  \"\",\n\t\t\tAcceptLanguageHeaders: []string{\"\"},\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Content-Length\": \"35\",\n\t\t\t\t\"Content-Type\":   \"text/css\",\n\t\t\t\t\"Date\":           \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"Date\", \"value\": \"Wed, 29 Jan 2025 09:00:00 GMT\"},\n\t\t\t\t{\"name\": \"Content-Type\", \"value\": \"text/css\"},\n\t\t\t\t{\"name\": \"Content-Length\", \"value\": \"35\"},\n\t\t\t},\n\t\t\tJSON:            \"null\",\n\t\t\tOK:              true,\n\t\t\tRequestURL:      tb.url(\"/style.css\"),\n\t\t\tSecurityDetails: common.SecurityDetails{},\n\t\t\tServerAddr:      common.RemoteAddress{IPAddress: host, Port: port},\n\t\t\tSize:            map[string]int{\"body\": 35, \"headers\": 100},\n\t\t\tStatus:          200,\n\t\t\tStatusText:      \"OK\",\n\t\t\tURL:             tb.url(\"/style.css\"),\n\t\t\tText:            \"body { background-color: #f0f0f0; }\",\n\t\t},\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"access-control-allow-credentials\": \"true\",\n\t\t\t\t\"access-control-allow-origin\":      \"*\",\n\t\t\t\t\"content-length\":                   \"19\",\n\t\t\t\t\"content-type\":                     \"text/plain; charset=utf-8\",\n\t\t\t\t\"date\":                             \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t\t\"x-content-type-options\":           \"nosniff\",\n\t\t\t},\n\t\t\tBody:                  \"404 page not found\\n\",\n\t\t\tFrameURL:              tb.url(\"/home\"),\n\t\t\tAcceptLanguageHeader:  \"\",\n\t\t\tAcceptLanguageHeaders: []string{\"\"},\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Access-Control-Allow-Credentials\": \"true\",\n\t\t\t\t\"Access-Control-Allow-Origin\":      \"*\",\n\t\t\t\t\"Content-Length\":                   \"19\",\n\t\t\t\t\"Content-Type\":                     \"text/plain; charset=utf-8\",\n\t\t\t\t\"Date\":                             \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t\t\"X-Content-Type-Options\":           \"nosniff\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"Date\", \"value\": \"Wed, 29 Jan 2025 09:00:00 GMT\"},\n\t\t\t\t{\"name\": \"Content-Type\", \"value\": \"text/plain; charset=utf-8\"},\n\t\t\t\t{\"name\": \"Access-Control-Allow-Credentials\", \"value\": \"true\"},\n\t\t\t\t{\"name\": \"X-Content-Type-Options\", \"value\": \"nosniff\"},\n\t\t\t\t{\"name\": \"Access-Control-Allow-Origin\", \"value\": \"*\"},\n\t\t\t\t{\"name\": \"Content-Length\", \"value\": \"19\"},\n\t\t\t},\n\t\t\tJSON:            \"null\",\n\t\t\tOK:              false,\n\t\t\tRequestURL:      tb.url(\"/favicon.ico\"),\n\t\t\tSecurityDetails: common.SecurityDetails{},\n\t\t\tServerAddr:      common.RemoteAddress{IPAddress: host, Port: port},\n\t\t\tSize:            map[string]int{\"body\": 19, \"headers\": 229},\n\t\t\tStatus:          404,\n\t\t\tStatusText:      \"Not Found\",\n\t\t\tURL:             tb.url(\"/favicon.ico\"),\n\t\t\tText:            \"404 page not found\\n\",\n\t\t},\n\t\t{\n\t\t\tAllHeaders: map[string]string{\n\t\t\t\t\"content-length\": \"28\",\n\t\t\t\t\"content-type\":   \"application/json\",\n\t\t\t\t\"date\":           \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t},\n\t\t\tBody:                  \"{\\\"message\\\": \\\"Hello tester!\\\"}\",\n\t\t\tFrameURL:              tb.url(\"/home\"),\n\t\t\tAcceptLanguageHeader:  \"\",\n\t\t\tAcceptLanguageHeaders: []string{\"\"},\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Content-Length\": \"28\",\n\t\t\t\t\"Content-Type\":   \"application/json\",\n\t\t\t\t\"Date\":           \"Wed, 29 Jan 2025 09:00:00 GMT\",\n\t\t\t},\n\t\t\tHeadersArray: []map[string]string{\n\t\t\t\t{\"name\": \"Date\", \"value\": \"Wed, 29 Jan 2025 09:00:00 GMT\"},\n\t\t\t\t{\"name\": \"Content-Type\", \"value\": \"application/json\"},\n\t\t\t\t{\"name\": \"Content-Length\", \"value\": \"28\"},\n\t\t\t},\n\t\t\tJSON:            \"{\\\"message\\\":\\\"Hello tester!\\\"}\",\n\t\t\tOK:              true,\n\t\t\tRequestURL:      tb.url(\"/api\"),\n\t\t\tSecurityDetails: common.SecurityDetails{},\n\t\t\tServerAddr:      common.RemoteAddress{IPAddress: host, Port: port},\n\t\t\tSize:            map[string]int{\"body\": 28, \"headers\": 108},\n\t\t\tStatus:          200,\n\t\t\tStatusText:      \"OK\",\n\t\t\tURL:             tb.url(\"/api\"),\n\t\t\tText:            \"{\\\"message\\\": \\\"Hello tester!\\\"}\",\n\t\t},\n\t}\n\n\t// Compare each response one by one for better test failure visibility\n\tfor _, resp := range responses {\n\t\ti := slices.IndexFunc(expected, func(r response) bool { return resp.URL == r.URL })\n\t\tassert.NotEqual(t, -1, i, \"failed to find expected request with URL %s\", resp.URL)\n\n\t\tsortByName := func(m1, m2 map[string]string) int {\n\t\t\treturn strings.Compare(m1[\"name\"], m2[\"name\"])\n\t\t}\n\t\tslices.SortFunc(resp.HeadersArray, sortByName)\n\t\tslices.SortFunc(expected[i].HeadersArray, sortByName)\n\t\tassert.Equal(t, expected[i], resp)\n\t}\n}\n\n// TestPageOnRequestFinished tests that the requestfinished event fires when requests complete successfully.\nfunc TestPageOnRequestFinished(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\ttb.withHandler(\"/home\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t_, err := fmt.Fprintf(w, `<!DOCTYPE html>\n<html>\n<head>\n    <link rel=\"stylesheet\" href=\"/style.css\">\n</head>\n<body>\n    <script>fetch('/api', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify({name: 'tester'})\n    })</script>\n</body>\n</html>`)\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/api\", func(w http.ResponseWriter, r *http.Request) {\n\t\tbody, err := io.ReadAll(r.Body)\n\t\trequire.NoError(t, err)\n\t\tdefer require.NoError(t, r.Body.Close())\n\n\t\tvar data struct {\n\t\t\tName string `json:\"name\"`\n\t\t}\n\t\terr = json.Unmarshal(body, &data)\n\t\trequire.NoError(t, err)\n\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t_, err = fmt.Fprintf(w, `{\"message\": \"Hello %s!\"}`, data.Name)\n\t\trequire.NoError(t, err)\n\t})\n\ttb.withHandler(\"/style.css\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/css\")\n\t\t_, err := fmt.Fprintf(w, `body { background-color: #f0f0f0; }`)\n\t\trequire.NoError(t, err)\n\t})\n\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\tdefer tb.vu.EndIteration(t)\n\n\tgv, err := tb.vu.RunAsync(t, `\n\t\tconst context = await browser.newContext();\n\t\tconst page = await context.newPage();\n\n\t\tvar finishedRequests = [];\n\t\tpage.on('requestfinished', (request) => {\n\t\t\tfinishedRequests.push({\n\t\t\t\turl: request.url(),\n\t\t\t\tmethod: request.method(),\n\t\t\t\tresourceType: request.resourceType(),\n\t\t\t\tisNavigationRequest: request.isNavigationRequest(),\n\t\t\t});\n\t\t});\n\n\t\tawait page.goto('%s', {waitUntil: 'networkidle'});\n\t\tawait page.close();\n\t\treturn JSON.stringify(finishedRequests, null, 2);\n\t`, tb.url(\"/home\"))\n\trequire.NoError(t, err)\n\n\tgot := k6test.ToPromise(t, gv)\n\trequire.Equal(t, sobek.PromiseStateFulfilled, got.State())\n\n\tvar finishedRequests []struct {\n\t\tURL                 string `json:\"url\"`\n\t\tMethod              string `json:\"method\"`\n\t\tResourceType        string `json:\"resourceType\"`\n\t\tIsNavigationRequest bool   `json:\"isNavigationRequest\"`\n\t}\n\terr = json.Unmarshal([]byte(got.Result().String()), &finishedRequests)\n\trequire.NoError(t, err)\n\n\t// Verify we captured some finished requests\n\trequire.NotEmpty(t, finishedRequests, \"expected to capture at least one finished request\")\n\n\tvar foundHome, foundAPI, foundCSS bool\n\tfor _, req := range finishedRequests {\n\t\tswitch {\n\t\tcase strings.HasSuffix(req.URL, \"/home\"):\n\t\t\tfoundHome = true\n\t\t\tassert.Equal(t, \"GET\", req.Method)\n\t\t\tassert.Equal(t, \"Document\", req.ResourceType)\n\t\t\tassert.True(t, req.IsNavigationRequest)\n\t\tcase strings.HasSuffix(req.URL, \"/api\"):\n\t\t\tfoundAPI = true\n\t\t\tassert.Equal(t, \"POST\", req.Method)\n\t\t\tassert.Equal(t, \"Fetch\", req.ResourceType)\n\t\t\tassert.False(t, req.IsNavigationRequest)\n\t\tcase strings.HasSuffix(req.URL, \"/style.css\"):\n\t\t\tfoundCSS = true\n\t\t\tassert.Equal(t, \"GET\", req.Method)\n\t\t\tassert.Equal(t, \"Stylesheet\", req.ResourceType)\n\t\t\tassert.False(t, req.IsNavigationRequest)\n\t\t}\n\t}\n\n\tassert.True(t, foundHome, \"expected to find /home request in finished requests\")\n\tassert.True(t, foundAPI, \"expected to find /api request in finished requests\")\n\tassert.True(t, foundCSS, \"expected to find /style.css request in finished requests\")\n}\n\n// TestPageOnRequestFinishedRedirect tests that the requestfinished event fires\n// for each request in a redirect chain, not just the final one.\nfunc TestPageOnRequestFinishedRedirect(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\ttb.withHandler(\"/redir-a\", func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, tb.url(\"/redir-b\"), http.StatusFound)\n\t})\n\ttb.withHandler(\"/redir-b\", func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, tb.url(\"/redir-final\"), http.StatusFound)\n\t})\n\ttb.withHandler(\"/redir-final\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\t_, err := fmt.Fprint(w, \"<html><body>done</body></html>\")\n\t\trequire.NoError(t, err)\n\t})\n\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\tdefer tb.vu.EndIteration(t)\n\n\tgv, err := tb.vu.RunAsync(t, `\n\t\tconst context = await browser.newContext();\n\t\tconst page = await context.newPage();\n\n\t\tconst expectedCount = 3; // redir-a, redir-b, redir-final\n\t\tconst finishedRequests = [];\n\t\tlet resolveAll;\n\t\tconst allFinished = new Promise(r => { resolveAll = r; });\n\n\t\tpage.on('requestfinished', (request) => {\n\t\t\tconst url = request.url();\n\t\t\tif (url.includes('/redir-')) {\n\t\t\t\tfinishedRequests.push({ url: url });\n\t\t\t\tif (finishedRequests.length >= expectedCount) {\n\t\t\t\t\tresolveAll();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait page.goto('%s', {waitUntil: 'networkidle'});\n\t\tawait allFinished;\n\t\tawait page.close();\n\t\treturn JSON.stringify(finishedRequests, null, 2);\n\t`, tb.url(\"/redir-a\"))\n\trequire.NoError(t, err)\n\n\tgot := k6test.ToPromise(t, gv)\n\trequire.Equal(t, sobek.PromiseStateFulfilled, got.State())\n\n\tvar finishedRequests []struct {\n\t\tURL string `json:\"url\"`\n\t}\n\terr = json.Unmarshal([]byte(got.Result().String()), &finishedRequests)\n\trequire.NoError(t, err)\n\n\t// Verify that requestfinished fired for the redirect requests,\n\t// not just the final response.\n\tvar foundRedirA, foundRedirB, foundFinal bool\n\tfor _, req := range finishedRequests {\n\t\tswitch {\n\t\tcase strings.HasSuffix(req.URL, \"/redir-a\"):\n\t\t\tfoundRedirA = true\n\t\tcase strings.HasSuffix(req.URL, \"/redir-b\"):\n\t\t\tfoundRedirB = true\n\t\tcase strings.HasSuffix(req.URL, \"/redir-final\"):\n\t\t\tfoundFinal = true\n\t\t}\n\t}\n\n\tassert.True(t, foundRedirA, \"expected requestfinished to fire for /redir-a (first redirect)\")\n\tassert.True(t, foundRedirB, \"expected requestfinished to fire for /redir-b (second redirect)\")\n\tassert.True(t, foundFinal, \"expected requestfinished to fire for /redir-final (final response)\")\n}\n\n// TestPageOnResponseRedirect tests that the response event fires\n// for each response in a redirect chain, not just the final one.\nfunc TestPageOnResponseRedirect(t *testing.T) {\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\ttb.withHandler(\"/redir-a\", func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, tb.url(\"/redir-b\"), http.StatusFound)\n\t})\n\ttb.withHandler(\"/redir-b\", func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, tb.url(\"/redir-final\"), http.StatusFound)\n\t})\n\ttb.withHandler(\"/redir-final\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\t_, err := fmt.Fprint(w, \"<html><body>done</body></html>\")\n\t\trequire.NoError(t, err)\n\t})\n\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\tdefer tb.vu.EndIteration(t)\n\n\tgv, err := tb.vu.RunAsync(t, `\n\t\tconst context = await browser.newContext();\n\t\tconst page = await context.newPage();\n\n\t\tconst expectedCount = 3; // redir-a, redir-b, redir-final\n\t\tconst responses = [];\n\t\tlet resolveAll;\n\t\tconst allReceived = new Promise(r => { resolveAll = r; });\n\n\t\tpage.on('response', (response) => {\n\t\t\tconst url = response.url();\n\t\t\tif (url.includes('/redir-')) {\n\t\t\t\tresponses.push({ url: url, status: response.status() });\n\t\t\t\tif (responses.length >= expectedCount) {\n\t\t\t\t\tresolveAll();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait page.goto('%s', {waitUntil: 'networkidle'});\n\t\tawait allReceived;\n\t\tawait page.close();\n\t\treturn JSON.stringify(responses, null, 2);\n\t`, tb.url(\"/redir-a\"))\n\trequire.NoError(t, err)\n\n\tgot := k6test.ToPromise(t, gv)\n\trequire.Equal(t, sobek.PromiseStateFulfilled, got.State())\n\n\tvar responses []struct {\n\t\tURL    string `json:\"url\"`\n\t\tStatus int    `json:\"status\"`\n\t}\n\terr = json.Unmarshal([]byte(got.Result().String()), &responses)\n\trequire.NoError(t, err)\n\n\t// Verify that response event fired for each redirect response,\n\t// not just the final one.\n\tvar foundRedirA, foundRedirB, foundFinal bool\n\tfor _, resp := range responses {\n\t\tswitch {\n\t\tcase strings.HasSuffix(resp.URL, \"/redir-a\"):\n\t\t\tfoundRedirA = true\n\t\t\tassert.Equal(t, http.StatusFound, resp.Status, \"/redir-a should be a 302\")\n\t\tcase strings.HasSuffix(resp.URL, \"/redir-b\"):\n\t\t\tfoundRedirB = true\n\t\t\tassert.Equal(t, http.StatusFound, resp.Status, \"/redir-b should be a 302\")\n\t\tcase strings.HasSuffix(resp.URL, \"/redir-final\"):\n\t\t\tfoundFinal = true\n\t\t\tassert.Equal(t, http.StatusOK, resp.Status, \"/redir-final should be a 200\")\n\t\t}\n\t}\n\n\tassert.True(t, foundRedirA, \"expected response event to fire for /redir-a (first redirect)\")\n\tassert.True(t, foundRedirB, \"expected response event to fire for /redir-b (second redirect)\")\n\tassert.True(t, foundFinal, \"expected response event to fire for /redir-final (final response)\")\n}\n\n// TestPageOnRequestFailed tests that the requestfailed event fires when requests fail.\nfunc TestPageOnRequestFailed(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"server_aborted_request\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\n\t\ttb.withHandler(\"/home\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t_, err := fmt.Fprintf(w, `<!DOCTYPE html>\n<html>\n<body>\n    <h1>Test Page</h1>\n    <script>\n        fetch('/api/data')\n            .then(() => { window.fetchResult = 'success'; })\n            .catch(() => { window.fetchResult = 'failed'; });\n    </script>\n</body>\n</html>`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\ttb.withHandler(\"/api/data\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tpanic(http.ErrAbortHandler)\n\t\t})\n\n\t\tp := tb.NewPage(nil)\n\n\t\tvar failedRequests []map[string]string\n\t\terr := p.On(common.PageEventRequestFailed, func(ev common.PageEvent) error {\n\t\t\treq := ev.Request\n\t\t\tfailure := req.Failure()\n\t\t\terrorText := \"\"\n\t\t\tif failure != nil {\n\t\t\t\terrorText = failure.ErrorText\n\t\t\t}\n\t\t\tfailedRequests = append(failedRequests, map[string]string{\n\t\t\t\t\"url\":          req.URL(),\n\t\t\t\t\"method\":       req.Method(),\n\t\t\t\t\"resourceType\": req.ResourceType(),\n\t\t\t\t\"errorText\":    errorText,\n\t\t\t})\n\t\t\treturn nil\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\t_, err = p.Goto(tb.url(\"/home\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\trequire.Len(t, failedRequests, 1, \"expected exactly one failed request\")\n\n\t\tfailedReq := failedRequests[0]\n\t\tassert.Contains(t, failedReq[\"url\"], \"/api/data\", \"failed request URL should contain /api/data\")\n\t\tassert.Equal(t, \"GET\", failedReq[\"method\"], \"failed request method should be GET\")\n\t\tassert.Equal(t, \"Fetch\", failedReq[\"resourceType\"], \"failed request resourceType should be Fetch\")\n\t\tassert.NotEmpty(t, failedReq[\"errorText\"], \"failed request should have error text\")\n\t})\n\n\tt.Run(\"server_aborted_multiple_requests\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\n\t\ttb.withHandler(\"/home\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t_, err := fmt.Fprintf(w, `<!DOCTYPE html>\n<html>\n<body>\n    <script>\n        Promise.allSettled([\n            fetch('/api/first'),\n            fetch('/api/second')\n        ]).then(() => { window.allDone = true; });\n    </script>\n</body>\n</html>`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\ttb.withHandler(\"/api/first\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tpanic(http.ErrAbortHandler)\n\t\t})\n\n\t\ttb.withHandler(\"/api/second\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tpanic(http.ErrAbortHandler)\n\t\t})\n\n\t\tp := tb.NewPage(nil)\n\n\t\tvar failedRequests []string\n\t\terr := p.On(common.PageEventRequestFailed, func(ev common.PageEvent) error {\n\t\t\tfailedRequests = append(failedRequests, ev.Request.URL())\n\t\t\treturn nil\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\t_, err = p.Goto(tb.url(\"/home\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\t// Verify that both requests failed\n\t\trequire.Len(t, failedRequests, 2, \"expected two failed requests\")\n\n\t\tvar hasFirst, hasSecond bool\n\t\tfor _, url := range failedRequests {\n\t\t\tif strings.Contains(url, \"/api/first\") {\n\t\t\t\thasFirst = true\n\t\t\t}\n\t\t\tif strings.Contains(url, \"/api/second\") {\n\t\t\t\thasSecond = true\n\t\t\t}\n\t\t}\n\t\tassert.True(t, hasFirst, \"expected /api/first to be in failed requests\")\n\t\tassert.True(t, hasSecond, \"expected /api/second to be in failed requests\")\n\t})\n}\n\nfunc TestPageMustUseNativeJavaScriptObjects(t *testing.T) {\n\tt.Parallel()\n\n\t// Add an element to query for later.\n\ttb := newTestBrowser(t)\n\tpage := tb.NewPage(nil)\n\trequire.NoError(t, page.SetContent(`\n\t\t<!DOCTYPE html>\n\t\t<html>\n\t\t<head></head>\n\t\t<body>\n\t\t\t<div id='textField'>Hello World</div>\n\t\t</div>\n\t\t</body>\n\t\t</html>\n\t`, nil))\n\n\t// Override the native objects using the test page.\n\t//\n\t// WARNING: Keep the function names and the native\n\t// type names in sync for isOverwritten() to work.\n\t// E.g.: Set() and window.overrides.Set are the same.\n\t_, err := page.Evaluate(`() => {\n\t\twindow.overrides = {};\n\t\tSet = () => window.overrides.Set = true;\n\t\tMap = () => window.overrides.Map = true;\n\t\t// Add other native objects here as needed.\n\t}`)\n\trequire.NoError(t, err)\n\n\t// Ensure that our test page has overridden the\n\t// native Set and Map JavaScript objects.\n\tisOverwritten := func(page *common.Page, objectName string) bool {\n\t\tv, err := page.Evaluate(fmt.Sprintf(`\n\t\t\t() => { %s(); return window.overrides.%[1]s; }`,\n\t\t\tobjectName,\n\t\t), nil)\n\t\trequire.NoErrorf(t, err, \"page should not have thrown an error: %s\", err)\n\t\trequire.IsTypef(t, v, true, \"expected %s to be a boolean\", objectName)\n\t\treturn v.(bool)\n\t}\n\trequire.True(t, isOverwritten(page, \"Set\"), \"page should override the native Set\")\n\trequire.True(t, isOverwritten(page, \"Map\"), \"page should override the native Map\")\n\n\t// Ensure that we can still use the native Set and\n\t// Map, even if the page under test has overridden\n\t// them. QueryAll calls injected script, which\n\t// requires Set and Map.\n\t_, err = page.QueryAll(\"#textField\")\n\trequire.NoErrorf(t, err, \"page should not override the native objects, but it did\")\n}\n\nfunc TestWaitForNavigationWithURL(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipped due to https://github.com/grafana/k6/issues/4937\")\n\t}\n\n\tt.Parallel()\n\n\ttb := newTestBrowser(t, withFileServer())\n\ttb.vu.ActivateVU()\n\ttb.vu.StartIteration(t)\n\n\t// Setup\n\ttb.vu.SetVar(t, \"page\", &sobek.Object{})\n\ttb.vu.SetVar(t, \"testURL\", tb.staticURL(\"waitfornavigation_test.html\"))\n\ttb.vu.SetVar(t, \"page1URL\", tb.staticURL(\"page1.html\"))\n\t_, err := tb.vu.RunAsync(t, `\n\t\t\tpage = await browser.newPage();\n\t\t`)\n\trequire.NoError(t, err)\n\n\t// Test exact URL match\n\tgot := tb.vu.RunPromise(t, `\n\t\tawait page.goto(testURL);\n\n\t\tawait Promise.all([\n\t\t\tpage.waitForNavigation({ url: page1URL }),\n\t\t\tpage.locator('#page1').click()\n\t\t]);\n\t\treturn page.url();\n\t`,\n\t)\n\tassert.Equal(t, tb.staticURL(\"page1.html\"), got.Result().String())\n\n\t// Test regex pattern - matches any page with .html extension\n\tgot = tb.vu.RunPromise(t, `\n\t\tawait page.goto(testURL);\n\n\t\tawait Promise.all([\n\t\t\tpage.waitForNavigation({ url: /.*2\\.html$/ }),\n\t\t\tpage.locator('#page2').click()\n\t\t]);\n\t\treturn page.url();\n\t`,\n\t)\n\tassert.Equal(t, tb.staticURL(\"page2.html\"), got.Result().String())\n\n\t// Test timeout when URL doesn't match\n\t_, err = tb.vu.RunAsync(t, `\n\t\tawait page.goto(testURL);\n\n\t\tawait Promise.all([\n\t\t\tpage.waitForNavigation({ url: /.*nonexistent.html$/, timeout: 500 }),\n\t\t\tpage.locator('#page1').click()  // This goes to page1.html, not nonexistent.html\n\t\t]);\n\t`,\n\t)\n\tassert.ErrorContains(t, err, \"timed out after 500ms\")\n\n\t// Test empty pattern (matches any navigation)\n\tgot = tb.vu.RunPromise(t, `\n\t\tawait page.goto(testURL);\n\n\t\tawait Promise.all([\n\t\t\tpage.waitForNavigation({ url: '' }),\n\t\t\tpage.locator('#page2').click()\n\t\t]);\n\t\treturn page.url();\n\t`,\n\t)\n\tassert.Equal(t, tb.staticURL(\"page2.html\"), got.Result().String())\n\n\t// Test regex pattern with invalid regex\n\t_, err = tb.vu.RunAsync(t, `\n\t\tawait page.goto(testURL);\n\n\t\tawait Promise.all([\n\t\t\tpage.waitForNavigation({ url: /^.*/my_messages.*$/ }),\n\t\t\tpage.locator('#page2').click()\n\t\t]);\n\t`,\n\t)\n\tassert.ErrorContains(t, err, \"Unexpected token *\")\n}\n\nfunc TestPageWaitForURLSuccess(t *testing.T) {\n\tt.Parallel()\n\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipped due to https://github.com/grafana/k6/issues/4937\")\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\tcode     string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname:     \"when_already_at_matching_url\",\n\t\t\tcode:     `await page.waitForURL(/.*waitfornavigation_test\\.html$/);`,\n\t\t\texpected: []string{\"waitfornavigation_test.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"exact_url_match\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tpage.waitForURL(page1URL),\n\t\t\t\t\tpage.locator('#page1').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page1.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"regex_pattern_match\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tpage.waitForURL(/.*2\\.html$/),\n\t\t\t\t\tpage.locator('#page2').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page2.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"empty_pattern_match\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tpage.waitForURL(''),\n\t\t\t\t\tpage.locator('#page2').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page2.html\", \"waitfornavigation_test.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"waitUntil_domcontentloaded\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tpage.waitForURL(/.*page1\\.html$/, { waitUntil: 'domcontentloaded' }),\n\t\t\t\t\tpage.locator('#page1').click()\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: []string{\"page1.html\"},\n\t\t},\n\t\t{\n\t\t\tname: \"already_at_url_with_regex_pattern\",\n\t\t\tcode: `\n\t\t\t\tawait page.waitForURL(/.*\\/waitfornavigation_test\\.html$/);\n\t\t\t`,\n\t\t\texpected: []string{\"waitfornavigation_test.html\"},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\n\t\t\ttb.vu.SetVar(t, \"page\", &sobek.Object{})\n\t\t\ttb.vu.SetVar(t, \"testURL\", tb.staticURL(\"waitfornavigation_test.html\"))\n\t\t\ttb.vu.SetVar(t, \"page1URL\", tb.staticURL(\"page1.html\"))\n\t\t\t_, err := tb.vu.RunAsync(t, `\n\t\t\t\tpage = await browser.newPage();\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult := tb.vu.RunPromise(t, `\n\t\t\t\tawait page.goto(testURL);\n\t\t\t\t%s\n\t\t\t\treturn page.url();\n\t\t\t`, tt.code)\n\t\t\tgot := strings.ReplaceAll(result.Result().String(), tb.staticURL(\"\"), \"\")\n\t\t\tassert.Contains(t, tt.expected, got)\n\t\t})\n\t}\n}\n\nfunc TestPageWaitForURLFailure(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipped due to https://github.com/grafana/k6/issues/4937\")\n\t}\n\n\ttests := []struct {\n\t\tname     string\n\t\tcode     string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"timeout_on_mismatched_url\",\n\t\t\tcode: `\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tpage.waitForURL(/.*nonexistent\\.html$/, { timeout: 500 }),\n\t\t\t\t\tpage.locator('#page1').click()  // This goes to page1.html, not nonexistent.html\n\t\t\t\t]);\n\t\t\t`,\n\t\t\texpected: \"timed out after 500ms\",\n\t\t},\n\t\t{\n\t\t\tname: \"missing_required_argument\",\n\t\t\tcode: `\n\t\t\t\tawait page.waitForURL();\n\t\t\t`,\n\t\t\texpected: \"missing required argument 'url'\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\ttb.vu.ActivateVU()\n\t\t\ttb.vu.StartIteration(t)\n\n\t\t\ttb.vu.SetVar(t, \"page\", &sobek.Object{})\n\t\t\ttb.vu.SetVar(t, \"testURL\", tb.staticURL(\"waitfornavigation_test.html\"))\n\t\t\t_, err := tb.vu.RunAsync(t, `\n\t\t\t\tpage = await browser.newPage();\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = tb.vu.RunAsync(t, `\n\t\t\t\tawait page.goto(testURL);\n\t\t\t\t%s\n\t\t\t`, tt.code)\n\t\t\tassert.ErrorContains(t, err, tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestPageWaitForResponse(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok/correct_response_matches\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\ttb.withHandler(\"/api/users\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t_, err := fmt.Fprintf(w, `{\"users\": []}`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\ttb.withHandler(\"/api/posts\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t_, err := fmt.Fprintf(w, `{\"posts\": []}`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t\ttb.withHandler(\"/page\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t_, err := fmt.Fprintf(w, `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html><body><script>\n\t\t\t\t\tsetTimeout(() => fetch('/api/posts'), 50);\n\t\t\t\t\tsetTimeout(() => fetch('/api/users'), 100);\n\t\t\t\t</script></body></html>\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\tp := tb.NewPage(nil)\n\n\t\tgotoPage := func() error {\n\t\t\t_, err := p.Goto(tb.url(\"/page\"), &common.FrameGotoOptions{\n\t\t\t\tWaitUntil: common.LifecycleEventDOMContentLoad,\n\t\t\t\tTimeout:   common.DefaultTimeout,\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\n\t\twaitForUsers := func() error {\n\t\t\topts := common.NewPageWaitForResponseOptions(p.Timeout())\n\t\t\tmockRegexChecker := func(pattern, url string) (bool, error) {\n\t\t\t\treturn strings.Contains(url, \"/users\"), nil\n\t\t\t}\n\t\t\tresp, err := p.WaitForResponse(\".*users.*\", opts, mockRegexChecker)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\trequire.Contains(t, resp.URL(), \"/users\")\n\t\t\treturn nil\n\t\t}\n\n\t\terr := tb.run(tb.context(), gotoPage, waitForUsers)\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"err/canceled\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\t\topts := common.NewPageWaitForResponseOptions(p.Timeout())\n\t\tgo tb.cancelContext()\n\t\t<-tb.context().Done()\n\n\t\tmockRegexChecker := func(pattern, url string) (bool, error) {\n\t\t\treturn strings.Contains(url, \"page\"), nil\n\t\t}\n\n\t\t_, err := p.WaitForResponse(\"/page\", opts, mockRegexChecker)\n\t\trequire.ErrorIs(t, err, context.Canceled)\n\t})\n\n\tt.Run(\"err/timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\n\t\tp := tb.NewPage(nil)\n\n\t\twaitForApi := func() error {\n\t\t\topts := common.NewPageWaitForResponseOptions(500 * time.Millisecond)\n\t\t\tmockRegexChecker := func(pattern, url string) (bool, error) {\n\t\t\t\treturn strings.Contains(url, \"/api\"), nil\n\t\t\t}\n\n\t\t\tresp, err := p.WaitForResponse(\".*api.*\", opts, mockRegexChecker)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\trequire.NotNil(t, resp)\n\t\t\trequire.Contains(t, resp.URL(), \"/api\")\n\t\t\treturn nil\n\t\t}\n\n\t\terr := tb.run(tb.context(), waitForApi)\n\t\trequire.ErrorIs(t, err, context.DeadlineExceeded)\n\t})\n}\n\nfunc TestPageWaitForRequest(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok/waits_for_request\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.GotoNewPage(tb.staticURL(\"/usual.html\"))\n\n\t\tvar req *common.Request\n\t\terr := tb.run(tb.context(),\n\t\t\t// We make three requests for detecting edge cases,\n\t\t\t// such as if WaitForRequest stops at the first match,\n\t\t\t// or misses requests made in quick succession.\n\t\t\tfunc() error {\n\t\t\t\t_, err := p.Evaluate(`() => {\n\t\t\t\t\tfetch('fetch-request-1');\n\t\t\t\t\tfetch('fetch-request-2');\n\t\t\t\t\tfetch('fetch-request-3');\n\t\t\t\t}`, nil)\n\t\t\t\treturn err\n\t\t\t},\n\t\t\t// Waits until the request we're looking for is made.\n\t\t\tfunc() error {\n\t\t\t\tvar werr error\n\t\t\t\treq, werr = p.WaitForRequest(\n\t\t\t\t\t\"fetch-request-2\",\n\t\t\t\t\t&common.PageWaitForRequestOptions{\n\t\t\t\t\t\tTimeout: p.Timeout(),\n\t\t\t\t\t},\n\t\t\t\t\tfunc(pattern, url string) (bool, error) {\n\t\t\t\t\t\treturn strings.Contains(url, pattern), nil\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\treturn werr\n\t\t\t},\n\t\t)\n\t\trequire.NoError(t, err)\n\t\trequire.NotNilf(t, req, \"must have returned the request\")\n\t\trequire.Contains(t, req.URL(), \"fetch-request-2\", \"must return the correct request\")\n\t})\n\n\tt.Run(\"err/pattern-func-error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer(), withLogCache())\n\t\tp := tb.GotoNewPage(tb.staticURL(\"/usual.html\"))\n\n\t\tpatternFuncError := errors.New(\"pattern func error\")\n\t\terr := tb.run(tb.context(), func() error {\n\t\t\t_, werr := p.WaitForRequest(\n\t\t\t\t\"usual.html\",\n\t\t\t\t&common.PageWaitForRequestOptions{\n\t\t\t\t\tTimeout: p.Timeout(),\n\t\t\t\t},\n\t\t\t\tfunc(pattern, url string) (bool, error) {\n\t\t\t\t\treturn false, patternFuncError\n\t\t\t\t},\n\t\t\t)\n\t\t\treturn werr\n\t\t})\n\t\trequire.ErrorIs(t, err, patternFuncError)\n\t\ttb.logCache.assertContains(t, patternFuncError.Error())\n\t})\n\n\tt.Run(\"err/canceled\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\n\t\tgo tb.cancelContext()\n\t\t<-tb.context().Done()\n\n\t\treq, err := p.WaitForRequest(\n\t\t\t\"/does-not-matter\",\n\t\t\t&common.PageWaitForRequestOptions{Timeout: p.Timeout()},\n\t\t\tfunc(pattern, url string) (bool, error) {\n\t\t\t\treturn true, nil\n\t\t\t},\n\t\t)\n\t\trequire.ErrorIs(t, err, context.Canceled)\n\t\trequire.Nil(t, req)\n\t})\n\n\tt.Run(\"err/timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\n\t\tvar req *common.Request\n\t\terr := tb.run(tb.context(), func() error {\n\t\t\tvar werr error\n\t\t\treq, werr = tb.NewPage(nil).WaitForRequest(\n\t\t\t\t\"/does-not-exist\",\n\t\t\t\t&common.PageWaitForRequestOptions{\n\t\t\t\t\tTimeout: 500 * time.Millisecond,\n\t\t\t\t},\n\t\t\t\tfunc(pattern, url string) (bool, error) {\n\t\t\t\t\treturn true, nil\n\t\t\t\t},\n\t\t\t)\n\t\t\treturn werr\n\t\t})\n\t\trequire.ErrorIs(t, err, context.DeadlineExceeded)\n\t\trequire.Nil(t, req)\n\t})\n}\n\n// TestClickInNestedFramesCORS tests clicking on buttons within nested frames\n// which are from different origins. At the end of the test the counter in\n// each frame should be \"1\".\nfunc TestClickInNestedFramesCORS(t *testing.T) {\n\tt.Parallel()\n\n\t// Origin C: innermost frame with counter button and nested same-origin iframe\n\toriginCHTML := `<!DOCTYPE html>\n\t<html>\n\t<head></head>\n\t<body>\n\t  <p>Counter: <span id=\"count\">0</span></p>\n\t  <button id=\"increment\">Increment Counter</button>\n\t  <iframe id=\"frameD\" src=\"/innerC\" width=\"300\" height=\"100\"></iframe>\n\t  <script>\n\t\tlet count = 0;\n\t\tdocument.getElementById('increment').addEventListener('click', () => {\n\t\t  count++;\n\t\t  document.getElementById('count').textContent = count;\n\t\t});\n\t  </script>\n\t</body>\n\t</html>`\n\n\t// Nested same-origin frame content served at /innerC on origin C\n\tinnerCHTML := `<!DOCTYPE html>\n\t<html>\n\t<head></head>\n\t<body>\n\t  <p>Counter D: <span id=\"countD\">0</span></p>\n\t  <button id=\"incrementD\">Increment Counter D</button>\n\t  <script>\n\t\tlet countD = 0;\n\t\tdocument.getElementById('incrementD').addEventListener('click', () => {\n\t\t  countD++;\n\t\t  document.getElementById('countD').textContent = countD;\n\t\t});\n\t  </script>\n\t</body>\n\t</html>`\n\n\t// Nested same-origin frame content served at /innerA on origin A\n\tinnerAHTML := `<!DOCTYPE html>\n\t<html>\n\t<head></head>\n\t<body>\n\t  <p>Counter A2: <span id=\"countA2\">0</span></p>\n\t  <button id=\"incrementA2\">Increment Counter A2</button>\n\t  <script>\n\t\tlet countA2 = 0;\n\t\tdocument.getElementById('incrementA2').addEventListener('click', () => {\n\t\t  countA2++;\n\t\t  document.getElementById('countA2').textContent = countA2;\n\t\t});\n\t  </script>\n\t</body>\n\t</html>`\n\n\t// Server for origin C\n\tmuxC := http.NewServeMux()\n\tmuxC.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t\t_, err := w.Write([]byte(originCHTML))\n\t\trequire.NoError(t, err)\n\t})\n\tmuxC.HandleFunc(\"/innerC\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t\t_, err := w.Write([]byte(innerCHTML))\n\t\trequire.NoError(t, err)\n\t})\n\tsrvC := httptest.NewServer(muxC)\n\tt.Cleanup(func() {\n\t\tsrvC.Close()\n\t})\n\n\t// Origin B: intermediate frame embedding origin C + own counter (with dynamic C URL)\n\toriginBHTML := fmt.Sprintf(`<!DOCTYPE html>\n\t<html>\n\t<head></head>\n\t<body>\n\t  <p>Counter B: <span id=\"countB\">0</span></p>\n\t  <button id=\"incrementB\">Increment Counter B</button>\n\t  <iframe id=\"frameC\" src=\"%s\" width=\"400\" height=\"200\"></iframe>\n\t  <script>\n\t\tlet countB = 0;\n\t\tdocument.getElementById('incrementB').addEventListener('click', () => {\n\t\t  countB++;\n\t\t  document.getElementById('countB').textContent = countB;\n\t\t});\n\t  </script>\n\t</body>\n\t</html>`, srvC.URL)\n\n\t// Server for origin B\n\tmuxB := http.NewServeMux()\n\tmuxB.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t\t_, err := w.Write([]byte(originBHTML))\n\t\trequire.NoError(t, err)\n\t})\n\tsrvB := httptest.NewServer(muxB)\n\tt.Cleanup(func() {\n\t\tsrvB.Close()\n\t})\n\n\t// Origin A: main page embedding origin B and same-origin frame A (with dynamic B URL)\n\toriginAHTML := fmt.Sprintf(`<!DOCTYPE html>\n\t<html>\n\t<head></head>\n\t<body>\n\t  <p>Counter A: <span id=\"countA\">0</span></p>\n\t  <button id=\"incrementA\">Increment Counter A</button>\n\t  <iframe id=\"frameA\" src=\"/innerA\" width=\"300\" height=\"150\" style=\"display: block; margin: 10px auto;\"></iframe>\n\t  <iframe id=\"frameB\" src=\"%s\" width=\"450\" height=\"300\" style=\"display: block; margin: 10px auto;\"></iframe>\n\t  <script>\n\t\tlet countA = 0;\n\t\tdocument.getElementById('incrementA').addEventListener('click', () => {\n\t\t  countA++;\n\t\t  document.getElementById('countA').textContent = countA;\n\t\t});\n\t  </script>\n\t</body>\n\t</html>`, srvB.URL)\n\n\t// Server for origin A\n\tmuxA := http.NewServeMux()\n\tmuxA.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t\t_, err := w.Write([]byte(originAHTML))\n\t\trequire.NoError(t, err)\n\t})\n\tmuxA.HandleFunc(\"/innerA\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t\t_, err := w.Write([]byte(innerAHTML))\n\t\trequire.NoError(t, err)\n\t})\n\tsrvA := httptest.NewServer(muxA)\n\tt.Cleanup(func() {\n\t\tsrvA.Close()\n\t})\n\n\tt.Run(\"ok/click_in_nested_frames\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Use srvA.URL as the entry point in the rest of the test (navigate, click, etc.).\n\t\tpage := newTestBrowser(t).NewPage(nil)\n\n\t\t// Navigate to the page that srvA is serving.\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := page.Goto(srvA.URL, opts)\n\t\trequire.NoError(t, err)\n\n\t\tvar (\n\t\t\tclickOpts     = common.NewFrameClickOptions(page.Timeout())\n\t\t\texpectedCount = \"1\"\n\t\t)\n\n\t\t// First click on the main frame.\n\t\terr = page.Locator(\"#incrementA\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tla := page.Locator(\"#countA\", nil)\n\t\tcountA, ok, err := la.TextContent(common.NewFrameTextContentOptions(la.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countA)\n\n\t\t// Now get the first nested frame.\n\t\tframeA, err := page.Query(\"#frameA\")\n\t\trequire.NoError(t, err)\n\n\t\tframeAContent, err := frameA.ContentFrame()\n\t\trequire.NoError(t, err)\n\n\t\t// Click on the second nested frame.\n\t\terr = frameAContent.Locator(\"#incrementA2\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tla2 := frameAContent.Locator(\"#countA2\", nil)\n\t\tcountA2, ok, err := la2.TextContent(common.NewFrameTextContentOptions(la2.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countA2)\n\n\t\t// Now get the second nested frame.\n\t\tframeB, err := page.Query(\"#frameB\")\n\t\trequire.NoError(t, err)\n\n\t\tframeBContent, err := frameB.ContentFrame()\n\t\trequire.NoError(t, err)\n\n\t\t// Click on the third nested frame.\n\t\terr = frameBContent.Locator(\"#incrementB\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tlb := frameBContent.Locator(\"#countB\", nil)\n\t\tcountB, ok, err := lb.TextContent(common.NewFrameTextContentOptions(lb.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countB)\n\n\t\t// Now get the third nested frame.\n\t\tframeC, err := frameBContent.Query(\"#frameC\", false)\n\t\trequire.NoError(t, err)\n\n\t\tframeCContent, err := frameC.ContentFrame()\n\t\trequire.NoError(t, err)\n\n\t\t// Click on the fourth nested frame.\n\t\terr = frameCContent.Locator(\"#increment\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tlc := frameCContent.Locator(\"#count\", nil)\n\t\tcount, ok, err := lc.TextContent(common.NewFrameTextContentOptions(lc.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, count)\n\n\t\t// Now get the fourth nested frame.\n\t\tframeD, err := frameCContent.Query(\"#frameD\", false)\n\t\trequire.NoError(t, err)\n\n\t\tframeDContent, err := frameD.ContentFrame()\n\t\trequire.NoError(t, err)\n\n\t\t// Click on the fifth nested frame.\n\t\terr = frameDContent.Locator(\"#incrementD\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tld := frameDContent.Locator(\"#countD\", nil)\n\t\tcountD, ok, err := ld.TextContent(common.NewFrameTextContentOptions(ld.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countD)\n\t})\n\n\t// This test is the same as the previous one, but uses the Locator API\n\t// instead of the Frame APIs.\n\tt.Run(\"ok/click_in_nested_frames_with_locator\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Use srvA.URL as the entry point in the rest of the test (navigate, click, etc.).\n\t\tpage := newTestBrowser(t).NewPage(nil)\n\n\t\t// Navigate to the page that srvA is serving.\n\t\topts := &common.FrameGotoOptions{\n\t\t\tTimeout: common.DefaultTimeout,\n\t\t}\n\t\t_, err := page.Goto(srvA.URL, opts)\n\t\trequire.NoError(t, err)\n\n\t\tvar (\n\t\t\tclickOpts     = common.NewFrameClickOptions(page.Timeout())\n\t\t\texpectedCount = \"1\"\n\t\t)\n\n\t\t// First click on the main frame.\n\t\terr = page.Locator(\"#incrementA\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tla := page.Locator(\"#countA\", nil)\n\t\tcountA, ok, err := la.TextContent(common.NewFrameTextContentOptions(la.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countA)\n\n\t\t// Now get the first nested frame.\n\t\tframeAContent := page.Locator(\"#frameA\", nil).ContentFrame()\n\n\t\t// Click on the second nested frame.\n\t\terr = frameAContent.Locator(\"#incrementA2\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tla2 := frameAContent.Locator(\"#countA2\", nil)\n\t\tcountA2, ok, err := la2.TextContent(common.NewFrameTextContentOptions(la2.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countA2)\n\n\t\t// Now get the second nested frame.\n\t\tframeBContent := page.Locator(\"#frameB\", nil).ContentFrame()\n\n\t\t// Click on the third nested frame.\n\t\terr = frameBContent.Locator(\"#incrementB\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tlb := frameBContent.Locator(\"#countB\", nil)\n\t\tcountB, ok, err := lb.TextContent(common.NewFrameTextContentOptions(lb.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countB)\n\n\t\t// Now get the third nested frame.\n\t\tframeCContent := frameBContent.Locator(\"#frameC\", nil).ContentFrame()\n\n\t\t// Click on the fourth nested frame.\n\t\terr = frameCContent.Locator(\"#increment\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tlc := frameCContent.Locator(\"#count\", nil)\n\t\tcount, ok, err := lc.TextContent(common.NewFrameTextContentOptions(lc.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, count)\n\n\t\t// Now get the fourth nested frame.\n\t\tframeDContent := frameCContent.Locator(\"#frameD\", nil).ContentFrame()\n\n\t\t// Click on the fifth nested frame.\n\t\terr = frameDContent.Locator(\"#incrementD\", nil).Click(clickOpts)\n\t\trequire.NoError(t, err)\n\n\t\tld := frameDContent.Locator(\"#countD\", nil)\n\t\tcountD, ok, err := ld.TextContent(common.NewFrameTextContentOptions(ld.Timeout()))\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, expectedCount, countD)\n\t})\n}\n\nfunc TestPageUnroute(t *testing.T) {\n\tt.Parallel()\n\n\tjsRegexCheckerMock := func(pattern, url string) (bool, error) {\n\t\tmatched, err := regexp.MatchString(fmt.Sprintf(\"http://[^/]*%s\", pattern), url)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error matching regex: %w\", err)\n\t\t}\n\t\treturn matched, nil\n\t}\n\n\tt.Run(\"unroute_single_route\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\tp := tb.NewPage(nil)\n\n\t\trouteHandlerCalls := 0\n\t\trouteHandler := func(route *common.Route) error {\n\t\t\trouteHandlerCalls++\n\t\t\treturn route.Continue(common.ContinueOptions{})\n\t\t}\n\n\t\ttb.withHandler(\"/test\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\t\t_, err := fmt.Fprintf(w, `\n\t\t\t<html>\n\t\t\t\t<body>\n\t\t\t\t\t<script>\n\t\t\t\t\t\tfetch('/api/data');\n\t\t\t\t\t</script>\n\t\t\t\t</body>\n\t\t\t</html>\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\ttb.withHandler(\"/api/data\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t_, err := fmt.Fprint(w, `{\"data\": \"test\"}`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\t// Add route\n\t\terr := p.Route(\"/api/data\", routeHandler, jsRegexCheckerMock)\n\t\trequire.NoError(t, err)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, 1, routeHandlerCalls)\n\n\t\t// Remove the route\n\t\trouteHandlerCalls = 0\n\t\terr = p.Unroute(\"/api/data\")\n\t\trequire.NoError(t, err)\n\n\t\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, 0, routeHandlerCalls, \"Route handler should not be called after unroute\")\n\t})\n\n\tt.Run(\"unroute_multiple_matching_routes\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\tp := tb.NewPage(nil)\n\n\t\thandler1Calls := 0\n\t\thandler2Calls := 0\n\n\t\trouteHandler1 := func(route *common.Route) error {\n\t\t\thandler1Calls++\n\t\t\treturn route.Continue(common.ContinueOptions{})\n\t\t}\n\n\t\trouteHandler2 := func(route *common.Route) error {\n\t\t\thandler2Calls++\n\t\t\treturn route.Continue(common.ContinueOptions{})\n\t\t}\n\n\t\ttb.withHandler(\"/test\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\t\t_, err := fmt.Fprintf(w, `\n\t\t\t<html>\n\t\t\t\t<body>\n\t\t\t\t\t<script>\n\t\t\t\t\t\tfetch('/api/data');\n\t\t\t\t\t</script>\n\t\t\t\t</body>\n\t\t\t</html>\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\ttb.withHandler(\"/api/data\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t_, err := fmt.Fprint(w, `{\"data\": \"test\"}`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\t// Add multiple routes for the same path\n\t\terr := p.Route(\"/api/data\", routeHandler1, jsRegexCheckerMock)\n\t\trequire.NoError(t, err)\n\t\terr = p.Route(\"/api/data\", routeHandler2, jsRegexCheckerMock)\n\t\trequire.NoError(t, err)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\t// Only the most recently added handler should be called\n\t\tassert.Equal(t, 0, handler1Calls, \"First handler should not be called when second handler is present\")\n\t\tassert.Equal(t, 1, handler2Calls, \"Second handler should be called\")\n\n\t\t// Remove all routes for this path\n\t\thandler1Calls = 0\n\t\thandler2Calls = 0\n\n\t\terr = p.Unroute(\"/api/data\")\n\t\trequire.NoError(t, err)\n\n\t\t// Second navigation should not trigger any route handlers\n\t\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, 0, handler1Calls, \"First handler should not be called after unroute\")\n\t\tassert.Equal(t, 0, handler2Calls, \"Second handler should not be called after unroute\")\n\t})\n\n\tt.Run(\"unroute_nonexistent_route\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\tp := tb.NewPage(nil)\n\n\t\trouteHandlerCalls := 0\n\t\trouteHandler := func(route *common.Route) error {\n\t\t\trouteHandlerCalls++\n\t\t\treturn route.Continue(common.ContinueOptions{})\n\t\t}\n\n\t\ttb.withHandler(\"/test\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\t\t_, err := fmt.Fprintf(w, `\n\t\t\t<html>\n\t\t\t\t<body>\n\t\t\t\t\t<script>\n\t\t\t\t\t\tfetch('/api/data');\n\t\t\t\t\t</script>\n\t\t\t\t</body>\n\t\t\t</html>\n\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\ttb.withHandler(\"/api/data\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t_, err := fmt.Fprint(w, `{\"data\": \"data\"}`)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\n\t\terr := p.Route(\"/api/data\", routeHandler, jsRegexCheckerMock)\n\t\trequire.NoError(t, err)\n\n\t\topts := &common.FrameGotoOptions{\n\t\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\t\tTimeout:   common.DefaultTimeout,\n\t\t}\n\t\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, 1, routeHandlerCalls)\n\n\t\t// Remove a non-existent route - this should be a no-op and not affect existing route\n\t\trouteHandlerCalls = 0\n\t\terr = p.Unroute(\"/unknown\")\n\t\trequire.NoError(t, err)\n\n\t\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\t\trequire.NoError(t, err)\n\n\t\tassert.Equal(t, 1, routeHandlerCalls, \"Route handler should still be active\")\n\t})\n}\n\nfunc TestPageUnrouteAll(t *testing.T) {\n\tt.Parallel()\n\n\tjsRegexCheckerMock := func(pattern, url string) (bool, error) {\n\t\tmatched, err := regexp.MatchString(fmt.Sprintf(\"http://[^/]*%s\", pattern), url)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error matching regex: %w\", err)\n\t\t}\n\t\treturn matched, nil\n\t}\n\n\ttb := newTestBrowser(t, withHTTPServer())\n\tp := tb.NewPage(nil)\n\n\troute1Calls := 0\n\troute2Calls := 0\n\n\trouteHandler1 := func(route *common.Route) error {\n\t\troute1Calls++\n\t\treturn route.Continue(common.ContinueOptions{})\n\t}\n\n\trouteHandler2 := func(route *common.Route) error {\n\t\troute2Calls++\n\t\treturn route.Continue(common.ContinueOptions{})\n\t}\n\n\ttb.withHandler(\"/test\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\t_, err := fmt.Fprintf(w, `\n\t\t\t<html>\n\t\t\t\t<body>\n\t\t\t\t\t<script>\n\t\t\t\t\t\tfetch('/api/first');\n\t\t\t\t\t\tfetch('/api/second');\n\t\t\t\t\t</script>\n\t\t\t\t</body>\n\t\t\t</html>\n\t\t\t`)\n\t\trequire.NoError(t, err)\n\t})\n\n\ttb.withHandler(\"/api/first\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t_, err := fmt.Fprint(w, `{\"data\": \"first\"}`)\n\t\trequire.NoError(t, err)\n\t})\n\n\ttb.withHandler(\"/api/second\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t_, err := fmt.Fprint(w, `{\"data\": \"second\"}`)\n\t\trequire.NoError(t, err)\n\t})\n\n\t// Add multiple routes\n\terr := p.Route(\"/api/first\", routeHandler1, jsRegexCheckerMock)\n\trequire.NoError(t, err)\n\terr = p.Route(\"/api/second\", routeHandler2, jsRegexCheckerMock)\n\trequire.NoError(t, err)\n\n\topts := &common.FrameGotoOptions{\n\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\tTimeout:   common.DefaultTimeout,\n\t}\n\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, 1, route1Calls)\n\tassert.Equal(t, 1, route2Calls)\n\n\t// Remove all routes - no route handler should be triggered\n\troute1Calls = 0\n\troute2Calls = 0\n\terr = p.UnrouteAll()\n\trequire.NoError(t, err)\n\n\t_, err = p.Goto(tb.url(\"/test\"), opts)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, 0, route1Calls, \"First route should be removed\")\n\tassert.Equal(t, 0, route2Calls, \"Second route should be removed\")\n}\n\nfunc TestPageWaitForEvent(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"ok/waits_for_console_event\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\ttb.withHandler(\"/page\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t_, _ = fmt.Fprintf(w, `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html><body><script>\n\t\t\t\t\tsetTimeout(() => console.log(\"hello world\"), 50);\n\t\t\t\t</script></body></html>\n\t\t\t`)\n\t\t})\n\n\t\tp := tb.NewPage(nil)\n\n\t\tgotoPage := func() error {\n\t\t\t_, err := p.Goto(tb.url(\"/page\"), &common.FrameGotoOptions{\n\t\t\t\tWaitUntil: common.LifecycleEventDOMContentLoad,\n\t\t\t\tTimeout:   common.DefaultTimeout,\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\n\t\tvar ev common.PageEvent\n\t\twaitForConsole := func() error {\n\t\t\tvar err error\n\t\t\tev, err = p.WaitForEvent(\n\t\t\t\tcommon.PageEventConsole,\n\t\t\t\t&common.PageWaitForEventOptions{Timeout: p.Timeout()},\n\t\t\t\tnil,\n\t\t\t)\n\t\t\treturn err\n\t\t}\n\n\t\terr := tb.run(tb.context(), gotoPage, waitForConsole)\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, ev.ConsoleMessage)\n\t\trequire.Equal(t, \"hello world\", ev.ConsoleMessage.Text)\n\t})\n\n\tt.Run(\"ok/waits_for_response_event\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withHTTPServer())\n\t\ttb.withHandler(\"/api/data\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\t_, _ = fmt.Fprintf(w, `{\"data\": \"test\"}`)\n\t\t})\n\t\ttb.withHandler(\"/page\", func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t_, _ = fmt.Fprintf(w, `\n\t\t\t\t<!doctype html>\n\t\t\t\t<html><body><script>\n\t\t\t\t\tsetTimeout(() => fetch('/api/data'), 50);\n\t\t\t\t</script></body></html>\n\t\t\t`)\n\t\t})\n\n\t\tp := tb.NewPage(nil)\n\n\t\tgotoPage := func() error {\n\t\t\t_, err := p.Goto(tb.url(\"/page\"), &common.FrameGotoOptions{\n\t\t\t\tWaitUntil: common.LifecycleEventDOMContentLoad,\n\t\t\t\tTimeout:   common.DefaultTimeout,\n\t\t\t})\n\t\t\treturn err\n\t\t}\n\n\t\tvar ev common.PageEvent\n\t\twaitForResponse := func() error {\n\t\t\tvar err error\n\t\t\tev, err = p.WaitForEvent(\n\t\t\t\tcommon.PageEventResponse,\n\t\t\t\t&common.PageWaitForEventOptions{Timeout: p.Timeout()},\n\t\t\t\tfunc(pe common.PageEvent) (bool, error) {\n\t\t\t\t\treturn strings.Contains(pe.Response.URL(), \"/api/data\"), nil\n\t\t\t\t},\n\t\t\t)\n\t\t\treturn err\n\t\t}\n\n\t\terr := tb.run(tb.context(), gotoPage, waitForResponse)\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, ev.Response)\n\t\trequire.Contains(t, ev.Response.URL(), \"/api/data\")\n\t})\n\n\tt.Run(\"err/canceled\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\n\t\tgo tb.cancelContext()\n\t\t<-tb.context().Done()\n\n\t\t_, err := p.WaitForEvent(\n\t\t\tcommon.PageEventConsole,\n\t\t\t&common.PageWaitForEventOptions{Timeout: p.Timeout()},\n\t\t\tnil,\n\t\t)\n\t\trequire.ErrorIs(t, err, context.Canceled)\n\t})\n\n\tt.Run(\"err/timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t)\n\t\tp := tb.NewPage(nil)\n\n\t\terr := tb.run(tb.context(), func() error {\n\t\t\t_, werr := p.WaitForEvent(\n\t\t\t\tcommon.PageEventConsole,\n\t\t\t\t&common.PageWaitForEventOptions{Timeout: 500 * time.Millisecond},\n\t\t\t\tnil,\n\t\t\t)\n\t\t\treturn werr\n\t\t})\n\t\trequire.ErrorIs(t, err, context.DeadlineExceeded)\n\t})\n}\n\nfunc TestPageGoBackForward(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"go_back_and_forward\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\turl1 := tb.staticURL(\"page1.html\")\n\t\ttb.GotoPageAndAssertURL(p, url1)\n\n\t\turl2 := tb.staticURL(\"page2.html\")\n\t\ttb.GotoPageAndAssertURL(p, url2)\n\n\t\topts := common.NewPageGoBackForwardOptions(common.LifecycleEventLoad, common.DefaultTimeout)\n\t\t_, err := p.GoBackForward(-1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, url1, \"expected to be back on first page\")\n\n\t\t_, err = p.GoBackForward(+1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, url2, \"expected to be forward on second page\")\n\t})\n\n\tt.Run(\"go_back_to_about_blank\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\turl1 := tb.staticURL(\"page1.html\")\n\t\ttb.GotoPage(p, url1)\n\n\t\topts := common.NewPageGoBackForwardOptions(common.LifecycleEventLoad, common.DefaultTimeout)\n\t\t_, err := p.GoBackForward(-1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, common.BlankPage, \"expected to be back on about:blank\")\n\n\t\tresp, err := p.GoBackForward(-1, opts)\n\t\trequire.NoError(t, err)\n\t\tassert.Nil(t, resp, \"expected nil response when can't go back\")\n\t})\n\n\tt.Run(\"go_forward_returns_nil_at_boundary\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\n\t\turl1 := tb.staticURL(\"page1.html\")\n\t\ttb.GotoPage(p, url1)\n\n\t\topts := common.NewPageGoBackForwardOptions(common.LifecycleEventLoad, common.DefaultTimeout)\n\t\tresp, err := p.GoBackForward(+1, opts)\n\t\trequire.NoError(t, err)\n\t\tassert.Nil(t, resp, \"expected nil response when can't go forward\")\n\t\ttb.AssertURL(p, url1, \"URL should not change when can't go forward\")\n\t})\n\n\tt.Run(\"go_back_and_forward_with_iframe_page\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttb := newTestBrowser(t, withFileServer())\n\t\tp := tb.NewPage(nil)\n\t\topts := common.NewPageGoBackForwardOptions(common.LifecycleEventLoad, common.DefaultTimeout)\n\n\t\turl1 := tb.staticURL(\"page1.html\")\n\t\turl2 := tb.staticURL(\"page_with_iframe.html\")\n\t\turl3 := tb.staticURL(\"page2.html\")\n\n\t\ttb.GotoPage(p, url1)\n\t\ttb.GotoPage(p, url2)\n\t\ttb.GotoPage(p, url3)\n\t\ttb.GotoPageAndAssertURL(p, url1)\n\n\t\t_, err := p.GoBackForward(-1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, url3, \"first goBack should land on page2\")\n\n\t\t_, err = p.GoBackForward(-1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, url2, \"second goBack should land on iframe page\")\n\n\t\t_, err = p.GoBackForward(-1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, url1, \"third goBack should land on page1\")\n\n\t\t_, err = p.GoBackForward(+1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, url2, \"first goForward should land on iframe page\")\n\n\t\t_, err = p.GoBackForward(+1, opts)\n\t\trequire.NoError(t, err)\n\t\ttb.AssertURL(p, url3, \"second goForward should land on page2\")\n\n\t\tfor range 3 {\n\t\t\t_, err = p.GoBackForward(-1, opts)\n\t\t\trequire.NoError(t, err)\n\t\t\t_, err = p.GoBackForward(+1, opts)\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t\ttb.AssertURL(p, url3, \"after rapid navigation should still be on page2\")\n\t})\n}\n\n// The race occurs when browser goroutines (FrameSession event loop,\n// NetworkManager fire-and-forget goroutines) call PushIfNotDone on the\n// k6 samples channel while close(samples) runs during engine shutdown.\n// Reproduces the issue 5341 when run with the -race flag.\nfunc TestPageCloseMetricEmissionRaceCondition(t *testing.T) {\n\tt.Parallel()\n\n\tsamples := make(chan k6metrics.SampleContainer, 100)\n\ttb := newTestBrowser(t, withSamples(samples), withSkipClose())\n\ttb.vu.StartIteration(t)\n\n\tpage := tb.NewPage(nil)\n\t_, err := page.Evaluate(`() => {\n\t\twindow.k6browserSendWebVitalMetric(JSON.stringify({\n\t\t\tid: \"v1-5341-1\",\n\t\t\tname: \"CLS\",\n\t\t\tvalue: 0.01,\n\t\t\trating: \"good\",\n\t\t\tdelta: 0.01,\n\t\t\tnumEntries: 1,\n\t\t\tnavigationType: \"navigate\",\n\t\t\turl: window.location.href,\n\t\t\tspanID: \"\"\n\t\t}));\n\t}`)\n\trequire.NoError(t, err)\n\n\t// Dispatches a pagehide event to trigger Web Vital metric emission.\n\t// At the same time, simulate the engine is shutting down.\n\trequire.NoError(t, page.Close())\n\tclose(samples)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/remote_obj_test.go",
    "content": "package tests\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\nfunc TestConsoleLogParse(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname string\n\t\tlog  string\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"number\", log: \"1\", want: \"1\",\n\t\t},\n\t\t{\n\t\t\tname: \"string\", log: `\"some string\"`, want: \"some string\",\n\t\t},\n\t\t{\n\t\t\tname: \"bool\", log: \"true\", want: \"true\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty_array\", log: \"[]\", want: \"[]\",\n\t\t},\n\t\t{\n\t\t\tname: \"empty_object\", log: \"{}\", want: \"{}\",\n\t\t},\n\t\t{\n\t\t\tname: \"filled_object\", log: `{\"foo\":{\"bar1\":\"bar2\"}}`, want: `{\"foo\":\"Object\"}`,\n\t\t},\n\t\t{\n\t\t\tname: \"filled_array\", log: `[\"foo\",\"bar\"]`, want: `[\"foo\",\"bar\"]`,\n\t\t},\n\t\t{\n\t\t\tname: \"filled_array\", log: `() => true`, want: `function()`,\n\t\t},\n\t\t{\n\t\t\tname: \"empty\", log: \"\", want: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"null\", log: \"null\", want: \"null\",\n\t\t},\n\t\t{\n\t\t\tname: \"undefined\", log: \"undefined\", want: \"undefined\",\n\t\t},\n\t\t{\n\t\t\tname: \"bigint\", log: `BigInt(\"2\")`, want: \"2n\",\n\t\t},\n\t\t{\n\t\t\tname: \"unwrapped_bigint\", log: \"3n\", want: \"3n\",\n\t\t},\n\t\t{\n\t\t\tname: \"float\", log: \"3.14\", want: \"3.14\",\n\t\t},\n\t\t{\n\t\t\tname: \"scientific_notation\", log: \"123e-5\", want: \"0.00123\",\n\t\t},\n\t\t{\n\t\t\tname: \"partially_parsed\",\n\t\t\tlog:  \"window\",\n\t\t\twant: `{\"document\":\"#document\",\"location\":\"Location\",\"name\":\"\",\"self\":\"Window\",\"window\":\"Window\"}`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tdone := make(chan bool)\n\n\t\t\teventHandler := func(event common.PageEvent) error {\n\t\t\t\tdefer close(done)\n\t\t\t\tassert.Equal(t, tt.want, event.ConsoleMessage.Text)\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// eventHandler will be called from a separate goroutine from within\n\t\t\t// the page's async event loop. This is why we need to wait on done\n\t\t\t// to close.\n\t\t\terr := p.On(\"console\", eventHandler)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tif tt.log == \"\" {\n\t\t\t\t_, err = p.Evaluate(`() => console.log(\"\")`)\n\t\t\t} else {\n\t\t\t\t_, err = p.Evaluate(fmt.Sprintf(\"() => console.log(%s)\", tt.log))\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\tselect {\n\t\t\tcase <-done:\n\t\t\tcase <-time.After(2500 * time.Millisecond):\n\t\t\t\tassert.Fail(t, \"test timed out before event handler was called\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestEvalRemoteObjectParse(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname string\n\t\teval string\n\t\twant any\n\t}{\n\t\t{\n\t\t\tname: \"number\", eval: \"1\", want: float64(1),\n\t\t},\n\t\t{\n\t\t\tname: \"string\", eval: `\"some string\"`, want: \"some string\",\n\t\t},\n\t\t{\n\t\t\tname: \"bool\", eval: \"true\", want: true,\n\t\t},\n\t\t{\n\t\t\tname: \"empty_array\", eval: \"[]\", want: []any{},\n\t\t},\n\t\t{\n\t\t\tname: \"empty_object\", eval: \"{}\", want: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"filled_object\", eval: `{return {foo:\"bar\"};}`, want: map[string]any{\"foo\": \"bar\"},\n\t\t},\n\t\t{\n\t\t\tname: \"filled_array\", eval: `{return [\"foo\",\"bar\"];}`, want: []any{0: \"foo\", 1: \"bar\"},\n\t\t},\n\t\t{\n\t\t\tname: \"filled_array\", eval: `() => true`, want: `function()`,\n\t\t},\n\t\t{\n\t\t\tname: \"empty\", eval: \"\", want: \"\",\n\t\t},\n\t\t{\n\t\t\tname: \"null\", eval: \"null\", want: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"undefined\", eval: \"undefined\", want: nil,\n\t\t},\n\t\t{\n\t\t\tname: \"bigint\", eval: `BigInt(\"2\")`, want: int64(2),\n\t\t},\n\t\t{\n\t\t\tname: \"unwrapped_bigint\", eval: \"3n\", want: int64(3),\n\t\t},\n\t\t{\n\t\t\tname: \"float\", eval: \"3.14\", want: 3.14,\n\t\t},\n\t\t{\n\t\t\tname: \"scientific_notation\", eval: \"123e-5\", want: 0.00123,\n\t\t},\n\t\t// TODO:\n\t\t// {\n\t\t// \t// This test is ignored until https://go.k6.io/k6/js/modules/k6/browser/issues/1132\n\t\t// \t// has been resolved.\n\t\t// \tname: \"partially_parsed\",\n\t\t// \teval:  \"window\",\n\t\t// \twant: `{\"document\":\"#document\",\"location\":\"Location\",\"name\":\"\",\"self\":\"Window\",\"window\":\"Window\"}`,\n\t\t// },\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttb := newTestBrowser(t, withFileServer())\n\t\t\tp := tb.NewPage(nil)\n\n\t\t\tvar (\n\t\t\t\tgot any\n\t\t\t\terr error\n\t\t\t)\n\t\t\tif tt.eval == \"\" {\n\t\t\t\tgot, err = p.Evaluate(`() => \"\"`)\n\t\t\t} else {\n\t\t\t\tgot, err = p.Evaluate(fmt.Sprintf(\"() => %s\", tt.eval))\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.EqualValues(t, tt.want, got)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/setinputfiles_test.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n)\n\n// TestSetInputFiles tests the SetInputFiles function.\nfunc TestSetInputFiles(t *testing.T) {\n\tt.Parallel()\n\n\ttype indexedFn func(idx int, propName string) any\n\ttype testFn func(page *common.Page, files *common.Files) error\n\ttype setupFn func() *common.Files\n\ttype checkFn func(t *testing.T,\n\t\tgetFileCountFn func() any,\n\t\tgetFilePropFn indexedFn,\n\t\terr error)\n\n\tconst (\n\t\tpropName = \"name\"\n\t\tpropType = \"type\"\n\t\tpropSize = \"size\"\n\t)\n\n\tpageContent := `\n\t  <input type=\"file\" id=\"upload\"/>\n\t  <input type=\"text\" id=\"textinput\"/>\n\t  <button id=\"button1\">Click</button>\n\t`\n\n\tdefaultTestPage := func(page *common.Page, files *common.Files) error {\n\t\treturn page.SetInputFiles(\"#upload\", files, common.NewFrameSetInputFilesOptions(common.DefaultTimeout))\n\t}\n\tdefaultTestElementHandle := func(page *common.Page, files *common.Files) error {\n\t\thandle, err := page.WaitForSelector(\"#upload\", common.NewFrameWaitForSelectorOptions(common.DefaultTimeout))\n\t\tassert.NoError(t, err)\n\t\treturn handle.SetInputFiles(files, common.NewElementHandleSetInputFilesOptions(common.DefaultTimeout))\n\t}\n\n\ttestCases := []struct {\n\t\tname  string\n\t\tsetup setupFn\n\t\ttests []testFn\n\t\tcheck checkFn\n\t}{\n\t\t{\n\t\t\tname: \"set_one_file_with_object\",\n\t\t\tsetup: func() *common.Files {\n\t\t\t\treturn &common.Files{\n\t\t\t\t\tPayload: []*common.File{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:     \"test.json\",\n\t\t\t\t\t\t\tMimetype: \"text/json\",\n\t\t\t\t\t\t\tBuffer:   \"MDEyMzQ1Njc4OQ==\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t\ttests: []testFn{defaultTestPage, defaultTestElementHandle},\n\t\t\tcheck: func(t *testing.T, getFileCountFn func() any, getFilePropFn indexedFn, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\t// check if input has 1 file\n\t\t\t\tassert.Equal(t, float64(1), getFileCountFn())\n\t\t\t\t// check added file is correct\n\t\t\t\tassert.Equal(t, \"test.json\", getFilePropFn(0, propName))\n\t\t\t\tassert.Equal(t, float64(10), getFilePropFn(0, propSize))\n\t\t\t\tassert.Equal(t, \"text/json\", getFilePropFn(0, propType))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"set_two_files_with_array_of_objects\",\n\t\t\tsetup: func() *common.Files {\n\t\t\t\treturn &common.Files{\n\t\t\t\t\tPayload: []*common.File{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:     \"test.json\",\n\t\t\t\t\t\t\tMimetype: \"text/json\",\n\t\t\t\t\t\t\tBuffer:   \"MDEyMzQ1Njc4OQ==\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:     \"test.xml\",\n\t\t\t\t\t\t\tMimetype: \"text/xml\",\n\t\t\t\t\t\t\tBuffer:   \"MDEyMzQ1Njc4OTAxMjM0\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t\ttests: []testFn{defaultTestPage, defaultTestElementHandle},\n\t\t\tcheck: func(t *testing.T, getFileCountFn func() any, getFilePropFn indexedFn, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\t// check if input has 2 files\n\t\t\t\tassert.Equal(t, float64(2), getFileCountFn())\n\t\t\t\t// check added files are correct\n\t\t\t\tassert.Equal(t, \"test.json\", getFilePropFn(0, propName))\n\t\t\t\tassert.Equal(t, float64(10), getFilePropFn(0, propSize))\n\t\t\t\tassert.Equal(t, \"text/json\", getFilePropFn(0, propType))\n\t\t\t\tassert.Equal(t, \"test.xml\", getFilePropFn(1, propName))\n\t\t\t\tassert.Equal(t, float64(15), getFilePropFn(1, propSize))\n\t\t\t\tassert.Equal(t, \"text/xml\", getFilePropFn(1, propType))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"set_nil\",\n\t\t\tsetup: func() *common.Files {\n\t\t\t\treturn nil\n\t\t\t},\n\t\t\ttests: []testFn{defaultTestPage, defaultTestElementHandle},\n\t\t\tcheck: func(t *testing.T, getFileCountFn func() any, _ indexedFn, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\t// check if input has 1 file\n\t\t\t\tassert.Equal(t, float64(0), getFileCountFn())\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"test_injected_script_notinput\",\n\t\t\tsetup: func() *common.Files {\n\t\t\t\treturn &common.Files{\n\t\t\t\t\tPayload: []*common.File{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:     \"test.json\",\n\t\t\t\t\t\t\tMimetype: \"text/json\",\n\t\t\t\t\t\t\tBuffer:   \"MDEyMzQ1Njc4OQ==\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t\ttests: []testFn{\n\t\t\t\tfunc(page *common.Page, files *common.Files) error {\n\t\t\t\t\treturn page.SetInputFiles(\"#button1\", files, common.NewFrameSetInputFilesOptions(common.DefaultTimeout))\n\t\t\t\t},\n\t\t\t\tfunc(page *common.Page, files *common.Files) error {\n\t\t\t\t\thandle, err := page.WaitForSelector(\"#button1\", common.NewFrameWaitForSelectorOptions(common.DefaultTimeout))\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\treturn handle.SetInputFiles(files, common.NewElementHandleSetInputFilesOptions(common.DefaultTimeout))\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, getFileCountFn func() any, _ indexedFn, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.ErrorContains(t, err, \"node is not an HTMLInputElement\")\n\t\t\t\tassert.ErrorContains(t, err, \"setting input files\")\n\t\t\t\t// check if input has 0 file\n\t\t\t\tassert.Equal(t, float64(0), getFileCountFn())\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"test_injected_script_notfile\",\n\t\t\tsetup: func() *common.Files {\n\t\t\t\treturn &common.Files{\n\t\t\t\t\tPayload: []*common.File{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:     \"test.json\",\n\t\t\t\t\t\t\tMimetype: \"text/json\",\n\t\t\t\t\t\t\tBuffer:   \"MDEyMzQ1Njc4OQ==\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t\ttests: []testFn{\n\t\t\t\tfunc(page *common.Page, files *common.Files) error {\n\t\t\t\t\treturn page.SetInputFiles(\"#textinput\", files, common.NewFrameSetInputFilesOptions(common.DefaultTimeout))\n\t\t\t\t},\n\t\t\t\tfunc(page *common.Page, files *common.Files) error {\n\t\t\t\t\thandle, err := page.WaitForSelector(\"#textinput\", common.NewFrameWaitForSelectorOptions(common.DefaultTimeout))\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\treturn handle.SetInputFiles(files, common.NewElementHandleSetInputFilesOptions(common.DefaultTimeout))\n\t\t\t\t},\n\t\t\t},\n\t\t\tcheck: func(t *testing.T, getFileCountFn func() any, _ indexedFn, err error) {\n\t\t\t\tt.Helper()\n\t\t\t\tassert.ErrorContains(t, err, \"node is not an input[type=file] element\")\n\t\t\t\tassert.ErrorContains(t, err, \"setting input files\")\n\t\t\t\t// check if input has 0 file\n\t\t\t\tassert.Equal(t, float64(0), getFileCountFn())\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tfor _, test := range tc.tests {\n\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttb := newTestBrowser(t)\n\t\t\t\tpage := tb.NewPage(nil)\n\n\t\t\t\terr := page.SetContent(pageContent, nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tgetFileCountFn := func() any {\n\t\t\t\t\tv, err := page.Evaluate(`() => document.getElementById(\"upload\").files.length`)\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\treturn v\n\t\t\t\t}\n\n\t\t\t\tgetFilePropertyFn := func(idx int, propName string) any {\n\t\t\t\t\tv, err := page.Evaluate(\n\t\t\t\t\t\t`(idx, propName) => document.getElementById(\"upload\").files[idx][propName]`,\n\t\t\t\t\t\tidx,\n\t\t\t\t\t\tpropName)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn v\n\t\t\t\t}\n\n\t\t\t\terr = test(page, tc.setup())\n\t\t\t\ttc.check(t, getFileCountFn, getFilePropertyFn, err)\n\t\t\t})\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/concealed_link.html",
    "content": "<html>\n<head>\n    <title>Concealed element test</title>\n    <style>\n        * {\n            padding: 0;\n            margin: 0;\n        }\n        ol {\n            padding-top: 160px;\n        }\n        li {\n            height: 80px;\n            border: 1px solid black;\n        }\n        .sticky {\n            z-index: 9999;\n            width: 100%;\n            position: fixed;\n            height: 160px;\n            background: black;\n        }\n    </style>\n</head>\n<body>    \n    <div class=\"sticky\"></div>\n    <ol>\n        <li>item 1</li>\n        <li>item 2</li>\n        <li>item 3</li>\n        <li id=\"concealed\">item 4</li>\n        <li>item 5</li>\n        <li>item 6</li>\n        <li>item 7</li>\n        <li>item 8</li>\n        <li>item 9</li>\n        <li id=\"last\">item 10</li>\n    </ol>\n\n    <script type=\"text/javascript\">\n        window.clickResult = '🙈';\n\n        el = document.querySelector('#concealed');\n        el.addEventListener('click', function (ev) {\n            ev.preventDefault();\n            window.clickResult = \"🐵\";\n        })\n    </script>\n</body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/dialog.html",
    "content": "<html lang=\"en\">\n    <head></head>\n    <body>\n        <div id='textField'>Hello World</div>\n        <br />\n        <button id=\"clickHere\" onclick=\"window.location.reload();\">click here</button>\n\n        <script>\n            const queryString = window.location.search;\n            const urlParams = new URLSearchParams(queryString);\n            const dialogType = urlParams.get('dialogType');\n            const div = document.getElementById('textField');\n\n            switch(dialogType) {\n                case \"alert\":\n                    alert(\"Click accept\");\n                    div.textContent = 'alert dismissed';\n                    break;\n                case \"confirm\":\n                    confirm(\"Click accept\");\n                    div.textContent = 'confirm dismissed';\n                    break;\n                case \"prompt\":\n                    prompt(\"Add text and then click accept\");\n                    div.textContent = 'prompt dismissed';\n                    break;\n                case \"beforeunload\":\n                    window.addEventListener('beforeunload', (event) => {\n                        event.returnValue = \"Are you sure you want to leave?\";\n                    });\n                    div.textContent = 'beforeunload dismissed';\n                    break;\n            }\n        </script>\n    </body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/embedded_iframe.html",
    "content": "<html>\n    <head></head>\n    <body>\n        <div id='doneDiv'></div>\n        <iframe src='https://www.youtube.com/embed/gwO7k5RTE54?wmode=opaque&amp;enablejsapi=1' onload='document.getElementById(\"doneDiv\").innerText = \"Done!\"'></iframe>\n    </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_alt_text.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Alt Text Selector Engine Test Suite</title>\n</head>\n<body>\n  <img src=\"world-map.jpg\" alt=\"World Map\">\n  <img src=\"abc123.jpg\" alt=\"abc123\">\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_label.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Label Selector Engine Test Suite</title>\n</head>\n<body>\n  <input aria-label=\"Username\">\n  <label for=\"password-input\">Password</label>\n  <input id=\"password-input\">\n  <input aria-label=\"abc123\">\n  <span\n    role=\"checkbox\"\n    aria-checked=\"false\"\n    tabindex=\"0\"\n    aria-labelledby=\"tac\"></span>\n  <span id=\"tac\">I agree to the Terms and Conditions.</span>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_placeholder.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Placeholder Selector Engine Test Suite</title>\n</head>\n<body>\n  <input placeholder=\"Enter your name\">\n  <input type=\"email\" placeholder=\"Email address\">\n  <textarea placeholder=\"Enter comments\"></textarea>\n  <input placeholder=\"abc123\">\n  <input type=\"search\" placeholder=\"Search...\">\n</body>\n</html> "
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_role_edge_cases.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Role Selector Engine Test Suite</title>\n</head>\n<body>\n  <!-- 1. Name Matching -->\n  <section>\n    <!-- Text content as name -->\n    <button>Submit Form</button>\n    <!-- aria-label -->\n    <button aria-label=\"Save Draft\"></button>\n    <!-- aria-labelledby -->\n    <span id=\"label-source\">Upload</span>\n    <div role=\"button\" aria-labelledby=\"label-source\">labelledby-upload-button</div>\n    <!-- Hidden text nodes should be ignored -->\n    <button><span style=\"display:none\">Foo</span>Bar</button>\n  </section>\n\n  <!-- 2. Regex matching -->\n  <section>\n    <h3>abc123</h3>\n  </section>\n\n  <!-- 3. State Filters -->\n  <section>\n    <!-- select (listbox) -->\n    <select>\n      <option selected>One</option>\n      <option>Two</option>\n    </select>\n    <!-- pressed (aria-pressed) -->\n    <button aria-pressed=\"true\">Toggle</button>\n    <!-- expanded (aria-expanded) -->\n    <div role=\"button\" aria-expanded=\"true\">Expanded</div>\n    <!-- level (heading) -->\n    <h6>Section</h6>\n    <!-- checked (checkbox/radio) -->\n    <input type=\"checkbox\" checked>\n    <input type=\"radio\" name=\"group1\" checked>\n    <!-- disabled (native) -->\n    <button disabled>Go</button>\n  </section>\n\n  <!-- 4. Hidden Filtering -->\n  <section>\n    <!-- CSS hidden -->\n    <button style=\"display:none\" aria-label=\"Hidden X Button\">X</button>\n    <!-- aria-hidden -->\n    <div aria-hidden=\"true\">\n      <button aria-label=\"Hidden Hi Button\">Hi</button>\n    </div>\n  </section>\n\n  <!-- 5. Combination Tests -->\n  <section>\n    <!-- hidden + state + name -->\n    <div role=\"button\" aria-label=\"Archive\" aria-pressed=\"false\" hidden>Combo Options Button</div>\n  </section>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_role_explicit.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Role Selector Engine Test Suite</title>\n</head>\n<body>\n  <!-- 6. Explicit ARIA roles -->\n  <section>\n    <div role=\"alert\">Alert</div>\n    <div role=\"alertdialog\">Alert Dialog</div>\n    <div role=\"application\">Application</div>\n    <div role=\"article\">Article</div>\n    <div role=\"banner\">Banner</div>\n    <div role=\"blockquote\">Blockquote</div>\n    <div role=\"button\">Button</div>\n    <div role=\"caption\">Caption</div>\n    <div role=\"cell\">Cell</div>\n    <div role=\"checkbox\">Checkbox</div>\n    <div role=\"code\">Code</div>\n    <div role=\"columnheader\">Column Header</div>\n    <div role=\"combobox\">Combobox</div>\n    <div role=\"complementary\">Complementary</div>\n    <div role=\"contentinfo\">Content Info</div>\n    <div role=\"definition\">Definition</div>\n    <div role=\"deletion\">Deletion</div>\n    <div role=\"dialog\">Dialog</div>\n    <div role=\"directory\">Directory</div>\n    <div role=\"document\">Document</div>\n    <div role=\"emphasis\">Emphasis</div>\n    <div role=\"feed\">Feed</div>\n    <div role=\"figure\">Figure</div>\n    <div role=\"form\">Form</div>\n    <div role=\"generic\">Generic</div>\n    <div role=\"grid\">Grid</div>\n    <div role=\"gridcell\">Grid Cell</div>\n    <div role=\"group\">Group</div>\n    <div role=\"heading\">Heading</div>\n    <div role=\"img\">Image</div>\n    <div role=\"insertion\">Insertion</div>\n    <div role=\"link\">Link</div>\n    <div role=\"list\">List</div>\n    <div role=\"listbox\">List Box</div>\n    <div role=\"listitem\">List Item</div>\n    <div role=\"log\">Log</div>\n    <div role=\"main\">Main</div>\n    <div role=\"mark\">Mark</div>\n    <div role=\"marquee\">Marquee</div>\n    <div role=\"math\">Math</div>\n    <div role=\"meter\">Meter</div>\n    <div role=\"menu\">Menu</div>\n    <div role=\"menubar\">Menu Bar</div>\n    <div role=\"menuitem\">Menu Item</div>\n    <div role=\"menuitemcheckbox\">Menu Item Checkbox</div>\n    <div role=\"menuitemradio\">Menu Item Radio</div>\n    <div role=\"navigation\">Navigation</div>\n    <div role=\"note\">Note</div>\n    <div role=\"none\">None</div>\n    <div role=\"option\">Option</div>\n    <div role=\"paragraph\">Paragraph</div>\n    <div role=\"presentation\">Presentation</div>\n    <div role=\"progressbar\">Progress Bar</div>\n    <div role=\"radio\">Radio</div>\n    <div role=\"radiogroup\">Radio Group</div>\n    <div role=\"region\">Region</div>\n    <div role=\"row\">Row</div>\n    <div role=\"rowgroup\">Row Group</div>\n    <div role=\"rowheader\">Row Header</div>\n    <div role=\"scrollbar\">Scroll Bar</div>\n    <div role=\"search\">Search</div>\n    <div role=\"searchbox\">Search Box</div>\n    <div role=\"separator\">Separator</div>\n    <div role=\"slider\">Slider</div>\n    <div role=\"spinbutton\">Spin Button</div>\n    <div role=\"strong\">Strong</div>\n    <div role=\"subscript\">Subscript</div>\n    <div role=\"superscript\">Superscript</div>\n    <div role=\"status\">Status</div>\n    <div role=\"switch\">Switch</div>\n    <div role=\"tab\">Tab</div>\n    <div role=\"tablist\">Tab List</div>\n    <div role=\"tabpanel\">Tab Panel</div>\n    <div role=\"table\">Table</div>\n    <div role=\"term\">Term</div>\n    <div role=\"textbox\">Text Box</div>\n    <div role=\"time\">Time</div>\n    <div role=\"timer\">Timer</div>\n    <div role=\"toolbar\">Toolbar</div>\n    <div role=\"tooltip\">Tooltip</div>\n    <div role=\"tree\">Tree</div>\n    <div role=\"treegrid\">Tree Grid</div>\n    <div role=\"treeitem\">Tree Item</div>\n  </section>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_role_implicit.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Role Selector Engine Test Suite</title>\n</head>\n<body>\n  <!-- header -->\n  <header>Header</header>\n  <!-- 7. Implicit Role Coverage -->\n  <section>\n    <!-- a[href] -->\n    <a href=\"#\">Link text</a>\n    <!-- area[href] -->\n    <map><area href=\"#\" aria-label=\"Map area\"></map>\n    <!-- button -->\n    <button>Click</button>\n    <!-- input type=submit -->\n    <input type=\"submit\" value=\"Submit\">\n    <!-- input type=image -->\n    <input type=\"image\" src=\"#\" alt=\"Image Button\">\n    <!-- input type=checkbox -->\n    <input type=\"checkbox\">\n    <!-- input type=radio -->\n    <input type=\"radio\" name=\"r\">\n    <!-- input type=text -->\n    <input type=\"text\" value=\"Text\" aria-label=\"Text type\">\n    <!-- textarea -->\n    <textarea aria-label=\"Text area\">Textarea</textarea>\n    <!-- input type=search -->\n    <input type=\"search\" value=\"Search\">\n    <!-- input type=range -->\n    <input type=\"range\" min=\"0\" max=\"100\" value=\"50\">\n    <!-- input type=number -->\n    <input type=\"number\" value=\"3\">\n    <!-- progress -->\n    <progress value=\"30\" max=\"100\">Progress</progress>\n    <!-- output -->\n    <output>Output</output>\n    <!-- details/summary -->\n    <details aria-label=\"details\"><summary>Summary</summary><div>Details</div></details>\n    <!-- dialog -->\n    <dialog open>Dialog</dialog>\n    <!-- headings h1-h6 -->\n    <h1>Heading1</h1><h2>Heading2</h2><h3>Heading3</h3><h4>Heading4</h4><h5>Heading5</h5><h6>Heading6</h6>\n    <!-- hr -->\n    <hr>\n    <!-- img -->\n    <img src=\"\" alt=\"Img\" aria-label=\"Img\">\n    <!-- ul/ol and li -->\n    <ul aria-label=\"ul\"><li aria-label=\"ul-li\">Item1</li></ul>\n    <ol aria-label=\"ol\"><li aria-label=\"ol-li\">Item2</li></ol>\n    <!-- dl dt dd -->\n    <dl><dt>Term</dt><dd>Description</dd></dl>\n    <!-- fieldset/legend -->\n    <fieldset><legend>Legend</legend><input></fieldset>\n    <!-- figure/figcaption -->\n    <figure><figcaption>Caption</figcaption><img src=\"\" alt=\"\"></figure>\n    <!-- table, thead, tbody, tfoot, tr, th, td -->\n    <table aria-label=\"table1\">\n      <thead><tr><th aria-label=\"th gridcell\" role=\"gridcell\">Head Gridcell</th></tr></thead>\n      <thead><tr><th aria-label=\"th\">Head Cell</th></tr></thead>\n      <thead><tr><th scope=\"col\">Head Column</th></tr></thead>\n      <thead><tr><th scope=\"row\">Head Row</th></tr></thead>\n      <tbody aria-label=\"tbody\"><tr><td>Cell</td></tr></tbody>\n      <tbody><tr aria-label=\"tr\"><td>Row</td></tr></tbody>\n      <tbody><tr><td aria-label=\"td\">Column Cell</td></tr></tbody>\n      <tbody><tr><td aria-label=\"td gridcell\" role=\"gridcell\">Column Gridcell</td></tr></tbody>\n      <tfoot aria-label=\"tfoot\"><tr><td>Foot</td></tr></tfoot>\n    </table>\n    <!-- main -->\n    <main>Main</main>\n    <!-- nav -->\n    <nav>Nav</nav>\n    <!-- article -->\n    <article>Article</article>\n    <!-- aside -->\n    <aside>Aside</aside>\n    <!-- form -->\n    <form aria-label=\"form\"><input></form>\n    <!-- section (region) -->\n    <section aria-label=\"Region Section\">Region content</section>\n    <blockquote>Blockquote text</blockquote>\n    <!-- caption -->\n    <table><caption>Table Caption</caption><tr><td>Cell</td></tr></table>\n    <!-- code -->\n    <code>Code sample</code>\n    <!-- del -->\n    <del>Deleted text</del>\n    <!-- dfn -->\n    <dfn>Definition term</dfn>\n    <!-- em -->\n    <em>Emphasized text</em>\n    <!-- ins -->\n    <ins>Inserted text</ins>\n    <!-- mark -->\n    <mark>Marked text</mark>\n    <!-- math -->\n    <math><mi>x</mi><mo>=</mo><mn>1</mn></math>\n    <!-- menu -->\n    <menu aria-label=\"menu\"><li>Menu item</li></menu>\n    <!-- meter -->\n    <meter value=\"0.5\">50%</meter>\n    <!-- p -->\n    <p>Paragraph text</p>\n    <!-- strong -->\n    <strong>Strong text</strong>\n    <!-- sub -->\n    <sub>Subscript</sub>\n    <!-- sup -->\n    <sup>Superscript</sup>\n    <!-- svg -->\n    <svg aria-label=\"svg\"><circle cx=\"10\" cy=\"10\" r=\"5\"></circle></svg>\n    <!-- time -->\n    <time datetime=\"2025-06-09\">June 9, 2025</time>\n    <!-- select (combobox) -->\n    <select aria-label=\"select\">\n        <option>A</option>\n    </select>\n    <!-- select (listbox) -->\n    <select aria-label=\"select multiple\" multiple>\n      <option>A</option>\n      <option>B</option>\n    </select>\n    <!-- select (optgroup) -->\n    <select>\n      <optgroup label=\"optgroup\">\n        <option>A</option>\n        <option>B</option>\n      </optgroup>\n    </select>\n    <!-- datalist -->\n    <datalist id=\"dl2\"><option>One</option></datalist><input list=\"dl2\">\n  </section>\n  <!-- footer -->\n  <footer>Footer</footer>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_testid.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Test ID Selector Engine Test Suite</title>\n</head>\n<body>\n  <button data-testid=\"submit-button\">Submit</button>\n  <input type=\"text\" data-testid=\"username-input\" placeholder=\"Username\">\n  <div data-testid=\"info-box\">Information</div>\n  <span data-testid=\"abc123\">Test span</span>\n  <a href=\"#\" data-testid=\"my-link\">Link</a>\n</body>\n</html> "
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_text.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Text Selector Engine Test Suite</title>\n</head>\n<body>\n  <div>Hello World</div>\n  <button>Click me</button>\n  <a href=\"#\">Learn more</a>\n  <span>abc123</span>\n  <p>This is a longer text with multiple words</p>\n  <div>  Spaced  text  </div>\n  <label>Email address</label>\n</body>\n</html> "
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/get_by_title.html",
    "content": "<!DOCTYPE html>\n<head>\n  <title>Title Selector Engine Test Suite</title>\n</head>\n<body>\n  <button title=\"Click me\">Button</button>\n  <a href=\"#\" title=\"Link to somewhere\">Link</a>\n  <img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==\" title=\"Placeholder image\">\n  <div title=\"Information box\">This is some information</div>\n  <span title=\"abc123\">Test span</span>\n</body>\n</html> "
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/hide_unhide.html",
    "content": "<!doctype html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>RAF-Toggling Counter Button</title>\n</head>\n<body>\n  <p>Count: <span id=\"value\">0</span></p>\n\n  <button id=\"incBtn\" type=\"button\">+1</button>\n\n  <script>\n    let count = 0;\n    const valueEl = document.getElementById('value');\n    const incBtn = document.getElementById('incBtn');\n\n    incBtn.addEventListener('click', function () {\n      count += 1;\n      valueEl.textContent = count;\n      console.log('click', count);\n    });\n\n    function loop() {\n      // Flip visibility every animation frame (~60 times per second)\n      incBtn.hidden = !incBtn.hidden;\n      requestAnimationFrame(loop);\n    }\n\n    requestAnimationFrame(loop);\n  </script>\n</body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/iframe_home.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n    <head></head>\n    <body>\n        <a href=\"/iframeSignIn\">Sign In</a>\n        <iframe src=\"about:blank\"></iframe>\n    </body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/iframe_signin.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n    <head></head>\n    <body>\n        <div id=\"doneDiv\">Sign In Page</div>\n        <iframe src=\"about:blank\"></iframe>\n    </body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/iframe_test_main.html",
    "content": "<html>\n  <body>\n    <iframe id=\"iframe1\" src=\"iframe_test_nested1.html\"></iframe>\n  </body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/iframe_test_nested1.html",
    "content": "<html>\n  <body>\n    <iframe id=\"iframe2\" src=\"iframe_test_nested2.html\"></iframe>\n  </body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/iframe_test_nested2.html",
    "content": "<html>\n  <body>\n    <script>\n      buttonClicked=false;\n    </script>\n    <button id=\"button1\" onclick='buttonClicked=true;'></button>\n  </body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/lifecycle.html",
    "content": "<html>\n\n<head></head>\n\n<body>\n    <a href=\"/home\" id=\"homeLink\">Home</a>\n    <div id=\"pingRequestText\">Waiting...</div>\n    <div id=\"pingJSText\">Waiting...</div>\n\n    <script>\n        var pingRequestTextOutput = document.getElementById(\"pingRequestText\");\n        var parentOutput = window.parent.document.getElementById('subFramePingRequestText');\n\n        var p = pingRequestText();\n        p.then(() => {\n            pingRequestTextOutput.innerText += ' - for loop complete';\n            if (parentOutput) {\n                parentOutput.innerText = pingRequestTextOutput.innerText;\n            }\n        })\n\n        async function pingRequestText() {\n            const queryString = window.location.search;\n            const urlParams = new URLSearchParams(queryString);\n            const pingCount = urlParams.get('pingCount')\n\n            for (var i = 0; i < pingCount; i++) {\n                await fetch('/ping')\n                    .then(response => response.text())\n                    .then((data) => {\n                        pingRequestTextOutput.innerText = 'Waiting... ' + data;\n                        if (parentOutput) {\n                            parentOutput.innerText = pingRequestTextOutput.innerText;\n                        }\n                    });\n            }\n        }\n    </script>\n    <script src=\"/ping.js\" async></script>\n</body>\n\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/lifecycle_main_frame.html",
    "content": "<html>\n\n<head></head>\n\n<body>\n    <div id=\"frameType\">main</div>\n    <div id=\"subFramePingRequestText\">Waiting...</div>\n    <div id=\"subFramePingJSText\">Waiting...</div>\n    <iframe src=\"/sub\"></iframe>\n</body>\n\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/lifecycle_no_ping_js.html",
    "content": "<html>\n\n<head></head>\n\n<body>\n    <div id=\"pingRequestText\">Waiting...</div>\n\n    <script>\n        var pingRequestTextOutput = document.getElementById(\"pingRequestText\");\n\n        var p = requestPings();\n        p.then(() => {\n            pingRequestTextOutput.innerText += ' - for loop complete';\n        })\n\n        async function requestPings() {\n            for (var i = 0; i < 10; i++) {\n                await fetch('/ping')\n                    .then(response => response.text())\n                    .then((data) => {\n                        pingRequestTextOutput.innerText = 'Waiting... ' + data;\n                    });\n            }\n        }\n    </script>\n</body>\n\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/locator_nesting.html",
    "content": "<html>\n\n<div id=\"inventory\" data-testid=\"inventory\">\n  <div class=\"item\" data-item=\"bananas\">\n    <span class=\"name\">Bananas</span>\n    <span class=\"qty\" aria-live=\"polite\">0</span>\n    <button class=\"add\" type=\"button\">Add</button>\n  </div>\n  <div class=\"item\" data-item=\"apples\">\n    <span class=\"name\">Apples</span>\n    <span class=\"qty\" aria-live=\"polite\">0</span>\n    <button class=\"add\" type=\"button\">Add</button>\n  </div>\n</div>\n\n<script>\n  // Increment only the clicked row’s qty\n  document.getElementById('inventory').addEventListener('click', e => {\n    const btn = e.target.closest('button.add');\n    if (!btn) return;\n    const row = btn.closest('.item');\n    const qty = row.querySelector('.qty');\n    qty.textContent = String((parseInt(qty.textContent || '0', 10) || 0) + 1);\n  });\n</script>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/locators.html",
    "content": "<!DOCTYPE html>\n<html>\n\n<head>\n    <title>Clickable link test</title>\n</head>\n\n<body>\n    <a id=\"link\" href=\"#\" onclick=\"event.preventDefault()\">Click</a>\n    <a id=\"linkdbl\" href=\"#\" ondblclick=\"event.preventDefault()\">Dblclick</a>\n    <a href=\"#\" onclick=\"event.preventDefault()\">Click</a>\n    <input id=\"inputCheckbox\" type=\"checkbox\" />\n    <input type=\"checkbox\" />\n    <input id=\"inputText\" type=\"text\" value=\"something\" />\n    <input id=\"inputHiddenText\" type=\"text\" hidden=\"true\">\n    <div id=\"divHello\"><span>hello</span></div>\n    <div><span>bye</span></div>\n    <textarea>text area</textarea>\n    <p id=\"firstParagraph\" contenteditable=\"true\">original text</p>\n    <p id=\"secondParagraph\">original text</p>\n    <select id=\"selectElement\"><option value=\"option text\"></option><option value=\"option text 2\"></option></select>\n    <select></select>\n    <script>\n        window.result = false;\n        window.dblclick = false;\n        window.check = false;\n\n        document.querySelector('#link').addEventListener(\n            'click', e => { window.result = true; }, false\n        );\n        document.querySelector('#linkdbl').addEventListener(\n            'dblclick', e => { window.dblclick = true; }, false\n        );\n        document.querySelector('#inputCheckbox').addEventListener(\n            'change', e => { window.check = e.currentTarget.checked; }, false\n        );\n        document.querySelector('#inputText').addEventListener(\n            'mousemove', e => { window.result = true; }, false\n        );\n        document.querySelector('#inputText').addEventListener(\n            'touchstart', e => { window.result = true; }, false\n        );\n    </script>\n</body>\n\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/mouse_helper.js",
    "content": "// This injects a circle into the page that moves with the mouse;\n// Useful for debugging\n(function(){\n    const box = document.createElement('div');\n    box.classList.add('mouse-helper');\n    const styleElement = document.createElement('style');\n    styleElement.innerHTML = `\n        .mouse-helper {\n            pointer-events: none;\n            position: absolute;\n            top: 0;\n            left: 0;\n            width: 20px;\n            height: 20px;\n            background: rgba(0,0,0,.4);\n            border: 1px solid white;\n            border-radius: 10px;\n            margin-left: -10px;\n            margin-top: -10px;\n            transition: background .2s, border-radius .2s, border-color .2s;\n        }\n        .mouse-helper.button-1 {\n            transition: none;\n            background: rgba(0,0,0,0.9);\n        }\n        .mouse-helper.button-2 {\n            transition: none;\n            border-color: rgba(0,0,255,0.9);\n        }\n        .mouse-helper.button-3 {\n            transition: none;\n            border-radius: 4px;\n        }\n        .mouse-helper.button-4 {\n            transition: none;\n            border-color: rgba(255,0,0,0.9);\n        }\n        .mouse-helper.button-5 {\n            transition: none;\n            border-color: rgba(0,255,0,0.9);\n        }\n        `;\n    document.head.appendChild(styleElement);\n    document.body.appendChild(box);\n    document.addEventListener('mousemove', event => {\n        box.style.left = event.pageX + 'px';\n        box.style.top = event.pageY + 'px';\n        updateButtons(event.buttons);\n    }, true);\n    document.addEventListener('mousedown', event => {\n        updateButtons(event.buttons);\n        box.classList.add('button-' + event.which);\n    }, true);\n    document.addEventListener('mouseup', event => {\n        updateButtons(event.buttons);\n        box.classList.remove('button-' + event.which);\n    }, true);\n    function updateButtons(buttons) {\n        for (let i = 0; i < 5; i++) {\n            box.classList.toggle('button-' + i, buttons & (1 << i));\n        }\n    }\n})();"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/nav_in_doc.html",
    "content": "<html>\n  <head>\n    <title>Navigation test within the same document</title>\n  </head>\n  <body>\n    <a id=\"nav-history\" href=\"#\">Navigate with History API</a>\n    <a id=\"nav-anchor\" href=\"#anchor\">Navigate with anchor link</a>\n    <div id=\"anchor\">Some div...</div>\n    <script>\n      const el = document.querySelector('a#nav-history');\n      el.addEventListener('click', function(evt) {\n        evt.preventDefault();\n        history.pushState({}, 'navigated', '/nav2');\n      });\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/non_clickable.html",
    "content": "<html>\n\n<head>\n    <title>Non-clickable test</title>\n    <style>\n        p {\n            z-index: 9998;\n            margin: 0;\n            padding: 0;\n            left: 0px;\n            bottom: 0px;\n            width: 100%;\n            height: 100%;\n            position: fixed;\n            background-color: black;\n        }\n    </style>\n</head>\n<body>\n    <p>I'm preventing clicking on elements</p>\n    <a href=\"#\" id=\"non-clickable\" onclick=\"event.preventDefault()\">I am non clickable</a>\n</body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/page1.html",
    "content": "<html lang=\"en\">\n    <head></head>\n    <body>\n        <h1>Page 1</h1>\n        <a href=\"page2.html\">Click Me</a>\n    </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/page2.html",
    "content": "<html lang=\"en\">\n    <head></head>\n    <body>\n        <h1>Page 2</h1>\n    </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/page_with_iframe.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <title>Page with Iframe</title>\n</head>\n<body>\n    <h1>Page with Iframe</h1>\n    <iframe src=\"page2.html\" id=\"myframe\" width=\"400\" height=\"300\"></iframe>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/ping.html",
    "content": "<html>\n  <head>\n    <title>Ping duration test</title>\n  </head>\n  <body>\n    <div id=\"waiting\">NA</div>\n    <script>\n        asd()\n\n        async function asd() {\n            var sendDate = (new Date()).getTime();\n\n            var receiveDate = 0;\n            await fetch('/ping', {\n                method: 'POST',\n                body: JSON.stringify('0'.repeat(1024))\n            })\n            .then(response => response.json())\n            .then(data => {\n                receiveDate = (new Date()).getTime();\n            })\n            \n            var responseTimeMs = receiveDate - sendDate;\n\n            document.getElementById(\"waiting\").innerHTML = `<div id=\"result\">${responseTimeMs}</div>`;\n        }\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/react-dom.development.js",
    "content": "/**\n * @license React\n * react-dom.development.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :\n  typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :\n  (global = global || self, factory(global.ReactDOM = {}, global.React));\n}(this, (function (exports, React) { 'use strict';\n\n  var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n\n  var suppressWarning = false;\n  function setSuppressWarning(newSuppressWarning) {\n    {\n      suppressWarning = newSuppressWarning;\n    }\n  } // In DEV, calls to console.warn and console.error get replaced\n  // by calls to these methods by a Babel plugin.\n  //\n  // In PROD (or in packages without access to React internals),\n  // they are left as they are instead.\n\n  function warn(format) {\n    {\n      if (!suppressWarning) {\n        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n          args[_key - 1] = arguments[_key];\n        }\n\n        printWarning('warn', format, args);\n      }\n    }\n  }\n  function error(format) {\n    {\n      if (!suppressWarning) {\n        for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n          args[_key2 - 1] = arguments[_key2];\n        }\n\n        printWarning('error', format, args);\n      }\n    }\n  }\n\n  function printWarning(level, format, args) {\n    // When changing this logic, you might want to also\n    // update consoleWithStackDev.www.js as well.\n    {\n      var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;\n      var stack = ReactDebugCurrentFrame.getStackAddendum();\n\n      if (stack !== '') {\n        format += '%s';\n        args = args.concat([stack]);\n      } // eslint-disable-next-line react-internal/safe-string-coercion\n\n\n      var argsWithFormat = args.map(function (item) {\n        return String(item);\n      }); // Careful: RN currently depends on this prefix\n\n      argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it\n      // breaks IE9: https://github.com/facebook/react/issues/13610\n      // eslint-disable-next-line react-internal/no-production-logging\n\n      Function.prototype.apply.call(console[level], console, argsWithFormat);\n    }\n  }\n\n  var FunctionComponent = 0;\n  var ClassComponent = 1;\n  var IndeterminateComponent = 2; // Before we know whether it is function or class\n\n  var HostRoot = 3; // Root of a host tree. Could be nested inside another node.\n\n  var HostPortal = 4; // A subtree. Could be an entry point to a different renderer.\n\n  var HostComponent = 5;\n  var HostText = 6;\n  var Fragment = 7;\n  var Mode = 8;\n  var ContextConsumer = 9;\n  var ContextProvider = 10;\n  var ForwardRef = 11;\n  var Profiler = 12;\n  var SuspenseComponent = 13;\n  var MemoComponent = 14;\n  var SimpleMemoComponent = 15;\n  var LazyComponent = 16;\n  var IncompleteClassComponent = 17;\n  var DehydratedFragment = 18;\n  var SuspenseListComponent = 19;\n  var ScopeComponent = 21;\n  var OffscreenComponent = 22;\n  var LegacyHiddenComponent = 23;\n  var CacheComponent = 24;\n  var TracingMarkerComponent = 25;\n\n  // -----------------------------------------------------------------------------\n\n  var enableClientRenderFallbackOnTextMismatch = true; // TODO: Need to review this code one more time before landing\n  // the react-reconciler package.\n\n  var enableNewReconciler = false; // Support legacy Primer support on internal FB www\n\n  var enableLazyContextPropagation = false; // FB-only usage. The new API has different semantics.\n\n  var enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber\n\n  var enableSuspenseAvoidThisFallback = false; // Enables unstable_avoidThisFallback feature in Fizz\n  // React DOM Chopping Block\n  //\n  // Similar to main Chopping Block but only flags related to React DOM. These are\n  // grouped because we will likely batch all of them into a single major release.\n  // -----------------------------------------------------------------------------\n  // Disable support for comment nodes as React DOM containers. Already disabled\n  // in open source, but www codebase still relies on it. Need to remove.\n\n  var disableCommentsAsDOMContainers = true; // Disable javascript: URL strings in href for XSS protection.\n  // and client rendering, mostly to allow JSX attributes to apply to the custom\n  // element's object properties instead of only HTML attributes.\n  // https://github.com/facebook/react/issues/11347\n\n  var enableCustomElementPropertySupport = false; // Disables children for <textarea> elements\n  var warnAboutStringRefs = true; // -----------------------------------------------------------------------------\n  // Debugging and DevTools\n  // -----------------------------------------------------------------------------\n  // Adds user timing marks for e.g. state updates, suspense, and work loop stuff,\n  // for an experimental timeline tool.\n\n  var enableSchedulingProfiler = true; // Helps identify side effects in render-phase lifecycle hooks and setState\n\n  var enableProfilerTimer = true; // Record durations for commit and passive effects phases.\n\n  var enableProfilerCommitHooks = true; // Phase param passed to onRender callback differentiates between an \"update\" and a \"cascading-update\".\n\n  var allNativeEvents = new Set();\n  /**\n   * Mapping from registration name to event name\n   */\n\n\n  var registrationNameDependencies = {};\n  /**\n   * Mapping from lowercase registration names to the properly cased version,\n   * used to warn in the case of missing event handlers. Available\n   * only in true.\n   * @type {Object}\n   */\n\n  var possibleRegistrationNames =  {} ; // Trust the developer to only use possibleRegistrationNames in true\n\n  function registerTwoPhaseEvent(registrationName, dependencies) {\n    registerDirectEvent(registrationName, dependencies);\n    registerDirectEvent(registrationName + 'Capture', dependencies);\n  }\n  function registerDirectEvent(registrationName, dependencies) {\n    {\n      if (registrationNameDependencies[registrationName]) {\n        error('EventRegistry: More than one plugin attempted to publish the same ' + 'registration name, `%s`.', registrationName);\n      }\n    }\n\n    registrationNameDependencies[registrationName] = dependencies;\n\n    {\n      var lowerCasedName = registrationName.toLowerCase();\n      possibleRegistrationNames[lowerCasedName] = registrationName;\n\n      if (registrationName === 'onDoubleClick') {\n        possibleRegistrationNames.ondblclick = registrationName;\n      }\n    }\n\n    for (var i = 0; i < dependencies.length; i++) {\n      allNativeEvents.add(dependencies[i]);\n    }\n  }\n\n  var canUseDOM = !!(typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined');\n\n  var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n  /*\n   * The `'' + value` pattern (used in in perf-sensitive code) throws for Symbol\n   * and Temporal.* types. See https://github.com/facebook/react/pull/22064.\n   *\n   * The functions in this module will throw an easier-to-understand,\n   * easier-to-debug exception with a clear errors message message explaining the\n   * problem. (Instead of a confusing exception thrown inside the implementation\n   * of the `value` object).\n   */\n  // $FlowFixMe only called in DEV, so void return is not possible.\n  function typeName(value) {\n    {\n      // toStringTag is needed for namespaced types like Temporal.Instant\n      var hasToStringTag = typeof Symbol === 'function' && Symbol.toStringTag;\n      var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || 'Object';\n      return type;\n    }\n  } // $FlowFixMe only called in DEV, so void return is not possible.\n\n\n  function willCoercionThrow(value) {\n    {\n      try {\n        testStringCoercion(value);\n        return false;\n      } catch (e) {\n        return true;\n      }\n    }\n  }\n\n  function testStringCoercion(value) {\n    // If you ended up here by following an exception call stack, here's what's\n    // happened: you supplied an object or symbol value to React (as a prop, key,\n    // DOM attribute, CSS property, string ref, etc.) and when React tried to\n    // coerce it to a string using `'' + value`, an exception was thrown.\n    //\n    // The most common types that will cause this exception are `Symbol` instances\n    // and Temporal objects like `Temporal.Instant`. But any object that has a\n    // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this\n    // exception. (Library authors do this to prevent users from using built-in\n    // numeric operators like `+` or comparison operators like `>=` because custom\n    // methods are needed to perform accurate arithmetic or comparison.)\n    //\n    // To fix the problem, coerce this object or symbol value to a string before\n    // passing it to React. The most reliable way is usually `String(value)`.\n    //\n    // To find which value is throwing, check the browser or debugger console.\n    // Before this exception was thrown, there should be `console.error` output\n    // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the\n    // problem and how that type was used: key, atrribute, input value prop, etc.\n    // In most cases, this console output also shows the component and its\n    // ancestor components where the exception happened.\n    //\n    // eslint-disable-next-line react-internal/safe-string-coercion\n    return '' + value;\n  }\n\n  function checkAttributeStringCoercion(value, attributeName) {\n    {\n      if (willCoercionThrow(value)) {\n        error('The provided `%s` attribute is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', attributeName, typeName(value));\n\n        return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n      }\n    }\n  }\n  function checkKeyStringCoercion(value) {\n    {\n      if (willCoercionThrow(value)) {\n        error('The provided key is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', typeName(value));\n\n        return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n      }\n    }\n  }\n  function checkPropStringCoercion(value, propName) {\n    {\n      if (willCoercionThrow(value)) {\n        error('The provided `%s` prop is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', propName, typeName(value));\n\n        return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n      }\n    }\n  }\n  function checkCSSPropertyStringCoercion(value, propName) {\n    {\n      if (willCoercionThrow(value)) {\n        error('The provided `%s` CSS property is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', propName, typeName(value));\n\n        return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n      }\n    }\n  }\n  function checkHtmlStringCoercion(value) {\n    {\n      if (willCoercionThrow(value)) {\n        error('The provided HTML markup uses a value of unsupported type %s.' + ' This value must be coerced to a string before before using it here.', typeName(value));\n\n        return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n      }\n    }\n  }\n  function checkFormFieldValueStringCoercion(value) {\n    {\n      if (willCoercionThrow(value)) {\n        error('Form field values (value, checked, defaultValue, or defaultChecked props)' + ' must be strings, not %s.' + ' This value must be coerced to a string before before using it here.', typeName(value));\n\n        return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n      }\n    }\n  }\n\n  // A reserved attribute.\n  // It is handled by React separately and shouldn't be written to the DOM.\n  var RESERVED = 0; // A simple string attribute.\n  // Attributes that aren't in the filter are presumed to have this type.\n\n  var STRING = 1; // A string attribute that accepts booleans in React. In HTML, these are called\n  // \"enumerated\" attributes with \"true\" and \"false\" as possible values.\n  // When true, it should be set to a \"true\" string.\n  // When false, it should be set to a \"false\" string.\n\n  var BOOLEANISH_STRING = 2; // A real boolean attribute.\n  // When true, it should be present (set either to an empty string or its name).\n  // When false, it should be omitted.\n\n  var BOOLEAN = 3; // An attribute that can be used as a flag as well as with a value.\n  // When true, it should be present (set either to an empty string or its name).\n  // When false, it should be omitted.\n  // For any other value, should be present with that value.\n\n  var OVERLOADED_BOOLEAN = 4; // An attribute that must be numeric or parse as a numeric.\n  // When falsy, it should be removed.\n\n  var NUMERIC = 5; // An attribute that must be positive numeric or parse as a positive numeric.\n  // When falsy, it should be removed.\n\n  var POSITIVE_NUMERIC = 6;\n\n  /* eslint-disable max-len */\n  var ATTRIBUTE_NAME_START_CHAR = \":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\";\n  /* eslint-enable max-len */\n\n  var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + \"\\\\-.0-9\\\\u00B7\\\\u0300-\\\\u036F\\\\u203F-\\\\u2040\";\n  var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$');\n  var illegalAttributeNameCache = {};\n  var validatedAttributeNameCache = {};\n  function isAttributeNameSafe(attributeName) {\n    if (hasOwnProperty.call(validatedAttributeNameCache, attributeName)) {\n      return true;\n    }\n\n    if (hasOwnProperty.call(illegalAttributeNameCache, attributeName)) {\n      return false;\n    }\n\n    if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) {\n      validatedAttributeNameCache[attributeName] = true;\n      return true;\n    }\n\n    illegalAttributeNameCache[attributeName] = true;\n\n    {\n      error('Invalid attribute name: `%s`', attributeName);\n    }\n\n    return false;\n  }\n  function shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag) {\n    if (propertyInfo !== null) {\n      return propertyInfo.type === RESERVED;\n    }\n\n    if (isCustomComponentTag) {\n      return false;\n    }\n\n    if (name.length > 2 && (name[0] === 'o' || name[0] === 'O') && (name[1] === 'n' || name[1] === 'N')) {\n      return true;\n    }\n\n    return false;\n  }\n  function shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag) {\n    if (propertyInfo !== null && propertyInfo.type === RESERVED) {\n      return false;\n    }\n\n    switch (typeof value) {\n      case 'function': // $FlowIssue symbol is perfectly valid here\n\n      case 'symbol':\n        // eslint-disable-line\n        return true;\n\n      case 'boolean':\n        {\n          if (isCustomComponentTag) {\n            return false;\n          }\n\n          if (propertyInfo !== null) {\n            return !propertyInfo.acceptsBooleans;\n          } else {\n            var prefix = name.toLowerCase().slice(0, 5);\n            return prefix !== 'data-' && prefix !== 'aria-';\n          }\n        }\n\n      default:\n        return false;\n    }\n  }\n  function shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag) {\n    if (value === null || typeof value === 'undefined') {\n      return true;\n    }\n\n    if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, isCustomComponentTag)) {\n      return true;\n    }\n\n    if (isCustomComponentTag) {\n\n      return false;\n    }\n\n    if (propertyInfo !== null) {\n\n      switch (propertyInfo.type) {\n        case BOOLEAN:\n          return !value;\n\n        case OVERLOADED_BOOLEAN:\n          return value === false;\n\n        case NUMERIC:\n          return isNaN(value);\n\n        case POSITIVE_NUMERIC:\n          return isNaN(value) || value < 1;\n      }\n    }\n\n    return false;\n  }\n  function getPropertyInfo(name) {\n    return properties.hasOwnProperty(name) ? properties[name] : null;\n  }\n\n  function PropertyInfoRecord(name, type, mustUseProperty, attributeName, attributeNamespace, sanitizeURL, removeEmptyString) {\n    this.acceptsBooleans = type === BOOLEANISH_STRING || type === BOOLEAN || type === OVERLOADED_BOOLEAN;\n    this.attributeName = attributeName;\n    this.attributeNamespace = attributeNamespace;\n    this.mustUseProperty = mustUseProperty;\n    this.propertyName = name;\n    this.type = type;\n    this.sanitizeURL = sanitizeURL;\n    this.removeEmptyString = removeEmptyString;\n  } // When adding attributes to this list, be sure to also add them to\n  // the `possibleStandardNames` module to ensure casing and incorrect\n  // name warnings.\n\n\n  var properties = {}; // These props are reserved by React. They shouldn't be written to the DOM.\n\n  var reservedProps = ['children', 'dangerouslySetInnerHTML', // TODO: This prevents the assignment of defaultValue to regular\n  // elements (not just inputs). Now that ReactDOMInput assigns to the\n  // defaultValue property -- do we need this?\n  'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style'];\n\n  reservedProps.forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, RESERVED, false, // mustUseProperty\n    name, // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // A few React string attributes have a different name.\n  // This is a mapping from React prop names to the attribute names.\n\n  [['acceptCharset', 'accept-charset'], ['className', 'class'], ['htmlFor', 'for'], ['httpEquiv', 'http-equiv']].forEach(function (_ref) {\n    var name = _ref[0],\n        attributeName = _ref[1];\n    properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty\n    attributeName, // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These are \"enumerated\" HTML attributes that accept \"true\" and \"false\".\n  // In React, we let users pass `true` and `false` even though technically\n  // these aren't boolean attributes (they are coerced to strings).\n\n  ['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty\n    name.toLowerCase(), // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These are \"enumerated\" SVG attributes that accept \"true\" and \"false\".\n  // In React, we let users pass `true` and `false` even though technically\n  // these aren't boolean attributes (they are coerced to strings).\n  // Since these are SVG attributes, their attribute names are case-sensitive.\n\n  ['autoReverse', 'externalResourcesRequired', 'focusable', 'preserveAlpha'].forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, BOOLEANISH_STRING, false, // mustUseProperty\n    name, // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These are HTML boolean attributes.\n\n  ['allowFullScreen', 'async', // Note: there is a special case that prevents it from being written to the DOM\n  // on the client side because the browsers are inconsistent. Instead we call focus().\n  'autoFocus', 'autoPlay', 'controls', 'default', 'defer', 'disabled', 'disablePictureInPicture', 'disableRemotePlayback', 'formNoValidate', 'hidden', 'loop', 'noModule', 'noValidate', 'open', 'playsInline', 'readOnly', 'required', 'reversed', 'scoped', 'seamless', // Microdata\n  'itemScope'].forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, BOOLEAN, false, // mustUseProperty\n    name.toLowerCase(), // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These are the few React props that we set as DOM properties\n  // rather than attributes. These are all booleans.\n\n  ['checked', // Note: `option.selected` is not updated if `select.multiple` is\n  // disabled with `removeAttribute`. We have special logic for handling this.\n  'multiple', 'muted', 'selected' // NOTE: if you add a camelCased prop to this list,\n  // you'll need to set attributeName to name.toLowerCase()\n  // instead in the assignment below.\n  ].forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, BOOLEAN, true, // mustUseProperty\n    name, // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These are HTML attributes that are \"overloaded booleans\": they behave like\n  // booleans, but can also accept a string value.\n\n  ['capture', 'download' // NOTE: if you add a camelCased prop to this list,\n  // you'll need to set attributeName to name.toLowerCase()\n  // instead in the assignment below.\n  ].forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, OVERLOADED_BOOLEAN, false, // mustUseProperty\n    name, // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These are HTML attributes that must be positive numbers.\n\n  ['cols', 'rows', 'size', 'span' // NOTE: if you add a camelCased prop to this list,\n  // you'll need to set attributeName to name.toLowerCase()\n  // instead in the assignment below.\n  ].forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, POSITIVE_NUMERIC, false, // mustUseProperty\n    name, // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These are HTML attributes that must be numbers.\n\n  ['rowSpan', 'start'].forEach(function (name) {\n    properties[name] = new PropertyInfoRecord(name, NUMERIC, false, // mustUseProperty\n    name.toLowerCase(), // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  });\n  var CAMELIZE = /[\\-\\:]([a-z])/g;\n\n  var capitalize = function (token) {\n    return token[1].toUpperCase();\n  }; // This is a list of all SVG attributes that need special casing, namespacing,\n  // or boolean value assignment. Regular attributes that just accept strings\n  // and have the same names are omitted, just like in the HTML attribute filter.\n  // Some of these attributes can be hard to find. This list was created by\n  // scraping the MDN documentation.\n\n\n  ['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' // NOTE: if you add a camelCased prop to this list,\n  // you'll need to set attributeName to name.toLowerCase()\n  // instead in the assignment below.\n  ].forEach(function (attributeName) {\n    var name = attributeName.replace(CAMELIZE, capitalize);\n    properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty\n    attributeName, null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // String SVG attributes with the xlink namespace.\n\n  ['xlink:actuate', 'xlink:arcrole', 'xlink:role', 'xlink:show', 'xlink:title', 'xlink:type' // NOTE: if you add a camelCased prop to this list,\n  // you'll need to set attributeName to name.toLowerCase()\n  // instead in the assignment below.\n  ].forEach(function (attributeName) {\n    var name = attributeName.replace(CAMELIZE, capitalize);\n    properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty\n    attributeName, 'http://www.w3.org/1999/xlink', false, // sanitizeURL\n    false);\n  }); // String SVG attributes with the xml namespace.\n\n  ['xml:base', 'xml:lang', 'xml:space' // NOTE: if you add a camelCased prop to this list,\n  // you'll need to set attributeName to name.toLowerCase()\n  // instead in the assignment below.\n  ].forEach(function (attributeName) {\n    var name = attributeName.replace(CAMELIZE, capitalize);\n    properties[name] = new PropertyInfoRecord(name, STRING, false, // mustUseProperty\n    attributeName, 'http://www.w3.org/XML/1998/namespace', false, // sanitizeURL\n    false);\n  }); // These attribute exists both in HTML and SVG.\n  // The attribute name is case-sensitive in SVG so we can't just use\n  // the React name like we do for attributes that exist only in HTML.\n\n  ['tabIndex', 'crossOrigin'].forEach(function (attributeName) {\n    properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty\n    attributeName.toLowerCase(), // attributeName\n    null, // attributeNamespace\n    false, // sanitizeURL\n    false);\n  }); // These attributes accept URLs. These must not allow javascript: URLS.\n  // These will also need to accept Trusted Types object in the future.\n\n  var xlinkHref = 'xlinkHref';\n  properties[xlinkHref] = new PropertyInfoRecord('xlinkHref', STRING, false, // mustUseProperty\n  'xlink:href', 'http://www.w3.org/1999/xlink', true, // sanitizeURL\n  false);\n  ['src', 'href', 'action', 'formAction'].forEach(function (attributeName) {\n    properties[attributeName] = new PropertyInfoRecord(attributeName, STRING, false, // mustUseProperty\n    attributeName.toLowerCase(), // attributeName\n    null, // attributeNamespace\n    true, // sanitizeURL\n    true);\n  });\n\n  // and any newline or tab are filtered out as if they're not part of the URL.\n  // https://url.spec.whatwg.org/#url-parsing\n  // Tab or newline are defined as \\r\\n\\t:\n  // https://infra.spec.whatwg.org/#ascii-tab-or-newline\n  // A C0 control is a code point in the range \\u0000 NULL to \\u001F\n  // INFORMATION SEPARATOR ONE, inclusive:\n  // https://infra.spec.whatwg.org/#c0-control-or-space\n\n  /* eslint-disable max-len */\n\n  var isJavaScriptProtocol = /^[\\u0000-\\u001F ]*j[\\r\\n\\t]*a[\\r\\n\\t]*v[\\r\\n\\t]*a[\\r\\n\\t]*s[\\r\\n\\t]*c[\\r\\n\\t]*r[\\r\\n\\t]*i[\\r\\n\\t]*p[\\r\\n\\t]*t[\\r\\n\\t]*\\:/i;\n  var didWarn = false;\n\n  function sanitizeURL(url) {\n    {\n      if (!didWarn && isJavaScriptProtocol.test(url)) {\n        didWarn = true;\n\n        error('A future version of React will block javascript: URLs as a security precaution. ' + 'Use event handlers instead if you can. If you need to generate unsafe HTML try ' + 'using dangerouslySetInnerHTML instead. React was passed %s.', JSON.stringify(url));\n      }\n    }\n  }\n\n  /**\n   * Get the value for a property on a node. Only used in DEV for SSR validation.\n   * The \"expected\" argument is used as a hint of what the expected value is.\n   * Some properties have multiple equivalent values.\n   */\n  function getValueForProperty(node, name, expected, propertyInfo) {\n    {\n      if (propertyInfo.mustUseProperty) {\n        var propertyName = propertyInfo.propertyName;\n        return node[propertyName];\n      } else {\n        // This check protects multiple uses of `expected`, which is why the\n        // react-internal/safe-string-coercion rule is disabled in several spots\n        // below.\n        {\n          checkAttributeStringCoercion(expected, name);\n        }\n\n        if ( propertyInfo.sanitizeURL) {\n          // If we haven't fully disabled javascript: URLs, and if\n          // the hydration is successful of a javascript: URL, we\n          // still want to warn on the client.\n          // eslint-disable-next-line react-internal/safe-string-coercion\n          sanitizeURL('' + expected);\n        }\n\n        var attributeName = propertyInfo.attributeName;\n        var stringValue = null;\n\n        if (propertyInfo.type === OVERLOADED_BOOLEAN) {\n          if (node.hasAttribute(attributeName)) {\n            var value = node.getAttribute(attributeName);\n\n            if (value === '') {\n              return true;\n            }\n\n            if (shouldRemoveAttribute(name, expected, propertyInfo, false)) {\n              return value;\n            } // eslint-disable-next-line react-internal/safe-string-coercion\n\n\n            if (value === '' + expected) {\n              return expected;\n            }\n\n            return value;\n          }\n        } else if (node.hasAttribute(attributeName)) {\n          if (shouldRemoveAttribute(name, expected, propertyInfo, false)) {\n            // We had an attribute but shouldn't have had one, so read it\n            // for the error message.\n            return node.getAttribute(attributeName);\n          }\n\n          if (propertyInfo.type === BOOLEAN) {\n            // If this was a boolean, it doesn't matter what the value is\n            // the fact that we have it is the same as the expected.\n            return expected;\n          } // Even if this property uses a namespace we use getAttribute\n          // because we assume its namespaced name is the same as our config.\n          // To use getAttributeNS we need the local name which we don't have\n          // in our config atm.\n\n\n          stringValue = node.getAttribute(attributeName);\n        }\n\n        if (shouldRemoveAttribute(name, expected, propertyInfo, false)) {\n          return stringValue === null ? expected : stringValue; // eslint-disable-next-line react-internal/safe-string-coercion\n        } else if (stringValue === '' + expected) {\n          return expected;\n        } else {\n          return stringValue;\n        }\n      }\n    }\n  }\n  /**\n   * Get the value for a attribute on a node. Only used in DEV for SSR validation.\n   * The third argument is used as a hint of what the expected value is. Some\n   * attributes have multiple equivalent values.\n   */\n\n  function getValueForAttribute(node, name, expected, isCustomComponentTag) {\n    {\n      if (!isAttributeNameSafe(name)) {\n        return;\n      }\n\n      if (!node.hasAttribute(name)) {\n        return expected === undefined ? undefined : null;\n      }\n\n      var value = node.getAttribute(name);\n\n      {\n        checkAttributeStringCoercion(expected, name);\n      }\n\n      if (value === '' + expected) {\n        return expected;\n      }\n\n      return value;\n    }\n  }\n  /**\n   * Sets the value for a property on a node.\n   *\n   * @param {DOMElement} node\n   * @param {string} name\n   * @param {*} value\n   */\n\n  function setValueForProperty(node, name, value, isCustomComponentTag) {\n    var propertyInfo = getPropertyInfo(name);\n\n    if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) {\n      return;\n    }\n\n    if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) {\n      value = null;\n    }\n\n\n    if (isCustomComponentTag || propertyInfo === null) {\n      if (isAttributeNameSafe(name)) {\n        var _attributeName = name;\n\n        if (value === null) {\n          node.removeAttribute(_attributeName);\n        } else {\n          {\n            checkAttributeStringCoercion(value, name);\n          }\n\n          node.setAttribute(_attributeName,  '' + value);\n        }\n      }\n\n      return;\n    }\n\n    var mustUseProperty = propertyInfo.mustUseProperty;\n\n    if (mustUseProperty) {\n      var propertyName = propertyInfo.propertyName;\n\n      if (value === null) {\n        var type = propertyInfo.type;\n        node[propertyName] = type === BOOLEAN ? false : '';\n      } else {\n        // Contrary to `setAttribute`, object properties are properly\n        // `toString`ed by IE8/9.\n        node[propertyName] = value;\n      }\n\n      return;\n    } // The rest are treated as attributes with special cases.\n\n\n    var attributeName = propertyInfo.attributeName,\n        attributeNamespace = propertyInfo.attributeNamespace;\n\n    if (value === null) {\n      node.removeAttribute(attributeName);\n    } else {\n      var _type = propertyInfo.type;\n      var attributeValue;\n\n      if (_type === BOOLEAN || _type === OVERLOADED_BOOLEAN && value === true) {\n        // If attribute type is boolean, we know for sure it won't be an execution sink\n        // and we won't require Trusted Type here.\n        attributeValue = '';\n      } else {\n        // `setAttribute` with objects becomes only `[object]` in IE8/9,\n        // ('' + value) makes it output the correct toString()-value.\n        {\n          {\n            checkAttributeStringCoercion(value, attributeName);\n          }\n\n          attributeValue = '' + value;\n        }\n\n        if (propertyInfo.sanitizeURL) {\n          sanitizeURL(attributeValue.toString());\n        }\n      }\n\n      if (attributeNamespace) {\n        node.setAttributeNS(attributeNamespace, attributeName, attributeValue);\n      } else {\n        node.setAttribute(attributeName, attributeValue);\n      }\n    }\n  }\n\n  // ATTENTION\n  // When adding new symbols to this file,\n  // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'\n  // The Symbol used to tag the ReactElement-like types.\n  var REACT_ELEMENT_TYPE = Symbol.for('react.element');\n  var REACT_PORTAL_TYPE = Symbol.for('react.portal');\n  var REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');\n  var REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');\n  var REACT_PROFILER_TYPE = Symbol.for('react.profiler');\n  var REACT_PROVIDER_TYPE = Symbol.for('react.provider');\n  var REACT_CONTEXT_TYPE = Symbol.for('react.context');\n  var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');\n  var REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');\n  var REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');\n  var REACT_MEMO_TYPE = Symbol.for('react.memo');\n  var REACT_LAZY_TYPE = Symbol.for('react.lazy');\n  var REACT_SCOPE_TYPE = Symbol.for('react.scope');\n  var REACT_DEBUG_TRACING_MODE_TYPE = Symbol.for('react.debug_trace_mode');\n  var REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');\n  var REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden');\n  var REACT_CACHE_TYPE = Symbol.for('react.cache');\n  var REACT_TRACING_MARKER_TYPE = Symbol.for('react.tracing_marker');\n  var MAYBE_ITERATOR_SYMBOL = Symbol.iterator;\n  var FAUX_ITERATOR_SYMBOL = '@@iterator';\n  function getIteratorFn(maybeIterable) {\n    if (maybeIterable === null || typeof maybeIterable !== 'object') {\n      return null;\n    }\n\n    var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];\n\n    if (typeof maybeIterator === 'function') {\n      return maybeIterator;\n    }\n\n    return null;\n  }\n\n  var assign = Object.assign;\n\n  // Helpers to patch console.logs to avoid logging during side-effect free\n  // replaying on render function. This currently only patches the object\n  // lazily which won't cover if the log function was extracted eagerly.\n  // We could also eagerly patch the method.\n  var disabledDepth = 0;\n  var prevLog;\n  var prevInfo;\n  var prevWarn;\n  var prevError;\n  var prevGroup;\n  var prevGroupCollapsed;\n  var prevGroupEnd;\n\n  function disabledLog() {}\n\n  disabledLog.__reactDisabledLog = true;\n  function disableLogs() {\n    {\n      if (disabledDepth === 0) {\n        /* eslint-disable react-internal/no-production-logging */\n        prevLog = console.log;\n        prevInfo = console.info;\n        prevWarn = console.warn;\n        prevError = console.error;\n        prevGroup = console.group;\n        prevGroupCollapsed = console.groupCollapsed;\n        prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099\n\n        var props = {\n          configurable: true,\n          enumerable: true,\n          value: disabledLog,\n          writable: true\n        }; // $FlowFixMe Flow thinks console is immutable.\n\n        Object.defineProperties(console, {\n          info: props,\n          log: props,\n          warn: props,\n          error: props,\n          group: props,\n          groupCollapsed: props,\n          groupEnd: props\n        });\n        /* eslint-enable react-internal/no-production-logging */\n      }\n\n      disabledDepth++;\n    }\n  }\n  function reenableLogs() {\n    {\n      disabledDepth--;\n\n      if (disabledDepth === 0) {\n        /* eslint-disable react-internal/no-production-logging */\n        var props = {\n          configurable: true,\n          enumerable: true,\n          writable: true\n        }; // $FlowFixMe Flow thinks console is immutable.\n\n        Object.defineProperties(console, {\n          log: assign({}, props, {\n            value: prevLog\n          }),\n          info: assign({}, props, {\n            value: prevInfo\n          }),\n          warn: assign({}, props, {\n            value: prevWarn\n          }),\n          error: assign({}, props, {\n            value: prevError\n          }),\n          group: assign({}, props, {\n            value: prevGroup\n          }),\n          groupCollapsed: assign({}, props, {\n            value: prevGroupCollapsed\n          }),\n          groupEnd: assign({}, props, {\n            value: prevGroupEnd\n          })\n        });\n        /* eslint-enable react-internal/no-production-logging */\n      }\n\n      if (disabledDepth < 0) {\n        error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.');\n      }\n    }\n  }\n\n  var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;\n  var prefix;\n  function describeBuiltInComponentFrame(name, source, ownerFn) {\n    {\n      if (prefix === undefined) {\n        // Extract the VM specific prefix used by each line.\n        try {\n          throw Error();\n        } catch (x) {\n          var match = x.stack.trim().match(/\\n( *(at )?)/);\n          prefix = match && match[1] || '';\n        }\n      } // We use the prefix to ensure our stacks line up with native stack frames.\n\n\n      return '\\n' + prefix + name;\n    }\n  }\n  var reentry = false;\n  var componentFrameCache;\n\n  {\n    var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;\n    componentFrameCache = new PossiblyWeakMap();\n  }\n\n  function describeNativeComponentFrame(fn, construct) {\n    // If something asked for a stack inside a fake render, it should get ignored.\n    if ( !fn || reentry) {\n      return '';\n    }\n\n    {\n      var frame = componentFrameCache.get(fn);\n\n      if (frame !== undefined) {\n        return frame;\n      }\n    }\n\n    var control;\n    reentry = true;\n    var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined.\n\n    Error.prepareStackTrace = undefined;\n    var previousDispatcher;\n\n    {\n      previousDispatcher = ReactCurrentDispatcher.current; // Set the dispatcher in DEV because this might be call in the render function\n      // for warnings.\n\n      ReactCurrentDispatcher.current = null;\n      disableLogs();\n    }\n\n    try {\n      // This should throw.\n      if (construct) {\n        // Something should be setting the props in the constructor.\n        var Fake = function () {\n          throw Error();\n        }; // $FlowFixMe\n\n\n        Object.defineProperty(Fake.prototype, 'props', {\n          set: function () {\n            // We use a throwing setter instead of frozen or non-writable props\n            // because that won't throw in a non-strict mode function.\n            throw Error();\n          }\n        });\n\n        if (typeof Reflect === 'object' && Reflect.construct) {\n          // We construct a different control for this case to include any extra\n          // frames added by the construct call.\n          try {\n            Reflect.construct(Fake, []);\n          } catch (x) {\n            control = x;\n          }\n\n          Reflect.construct(fn, [], Fake);\n        } else {\n          try {\n            Fake.call();\n          } catch (x) {\n            control = x;\n          }\n\n          fn.call(Fake.prototype);\n        }\n      } else {\n        try {\n          throw Error();\n        } catch (x) {\n          control = x;\n        }\n\n        fn();\n      }\n    } catch (sample) {\n      // This is inlined manually because closure doesn't do it for us.\n      if (sample && control && typeof sample.stack === 'string') {\n        // This extracts the first frame from the sample that isn't also in the control.\n        // Skipping one frame that we assume is the frame that calls the two.\n        var sampleLines = sample.stack.split('\\n');\n        var controlLines = control.stack.split('\\n');\n        var s = sampleLines.length - 1;\n        var c = controlLines.length - 1;\n\n        while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) {\n          // We expect at least one stack frame to be shared.\n          // Typically this will be the root most one. However, stack frames may be\n          // cut off due to maximum stack limits. In this case, one maybe cut off\n          // earlier than the other. We assume that the sample is longer or the same\n          // and there for cut off earlier. So we should find the root most frame in\n          // the sample somewhere in the control.\n          c--;\n        }\n\n        for (; s >= 1 && c >= 0; s--, c--) {\n          // Next we find the first one that isn't the same which should be the\n          // frame that called our sample function and the control.\n          if (sampleLines[s] !== controlLines[c]) {\n            // In V8, the first line is describing the message but other VMs don't.\n            // If we're about to return the first line, and the control is also on the same\n            // line, that's a pretty good indicator that our sample threw at same line as\n            // the control. I.e. before we entered the sample frame. So we ignore this result.\n            // This can happen if you passed a class to function component, or non-function.\n            if (s !== 1 || c !== 1) {\n              do {\n                s--;\n                c--; // We may still have similar intermediate frames from the construct call.\n                // The next one that isn't the same should be our match though.\n\n                if (c < 0 || sampleLines[s] !== controlLines[c]) {\n                  // V8 adds a \"new\" prefix for native classes. Let's remove it to make it prettier.\n                  var _frame = '\\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled \"<anonymous>\"\n                  // but we have a user-provided \"displayName\"\n                  // splice it in to make the stack more readable.\n\n\n                  if (fn.displayName && _frame.includes('<anonymous>')) {\n                    _frame = _frame.replace('<anonymous>', fn.displayName);\n                  }\n\n                  {\n                    if (typeof fn === 'function') {\n                      componentFrameCache.set(fn, _frame);\n                    }\n                  } // Return the line we found.\n\n\n                  return _frame;\n                }\n              } while (s >= 1 && c >= 0);\n            }\n\n            break;\n          }\n        }\n      }\n    } finally {\n      reentry = false;\n\n      {\n        ReactCurrentDispatcher.current = previousDispatcher;\n        reenableLogs();\n      }\n\n      Error.prepareStackTrace = previousPrepareStackTrace;\n    } // Fallback to just using the name if we couldn't make it throw.\n\n\n    var name = fn ? fn.displayName || fn.name : '';\n    var syntheticFrame = name ? describeBuiltInComponentFrame(name) : '';\n\n    {\n      if (typeof fn === 'function') {\n        componentFrameCache.set(fn, syntheticFrame);\n      }\n    }\n\n    return syntheticFrame;\n  }\n\n  function describeClassComponentFrame(ctor, source, ownerFn) {\n    {\n      return describeNativeComponentFrame(ctor, true);\n    }\n  }\n  function describeFunctionComponentFrame(fn, source, ownerFn) {\n    {\n      return describeNativeComponentFrame(fn, false);\n    }\n  }\n\n  function shouldConstruct(Component) {\n    var prototype = Component.prototype;\n    return !!(prototype && prototype.isReactComponent);\n  }\n\n  function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) {\n\n    if (type == null) {\n      return '';\n    }\n\n    if (typeof type === 'function') {\n      {\n        return describeNativeComponentFrame(type, shouldConstruct(type));\n      }\n    }\n\n    if (typeof type === 'string') {\n      return describeBuiltInComponentFrame(type);\n    }\n\n    switch (type) {\n      case REACT_SUSPENSE_TYPE:\n        return describeBuiltInComponentFrame('Suspense');\n\n      case REACT_SUSPENSE_LIST_TYPE:\n        return describeBuiltInComponentFrame('SuspenseList');\n    }\n\n    if (typeof type === 'object') {\n      switch (type.$$typeof) {\n        case REACT_FORWARD_REF_TYPE:\n          return describeFunctionComponentFrame(type.render);\n\n        case REACT_MEMO_TYPE:\n          // Memo may contain any component type so we recursively resolve it.\n          return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn);\n\n        case REACT_LAZY_TYPE:\n          {\n            var lazyComponent = type;\n            var payload = lazyComponent._payload;\n            var init = lazyComponent._init;\n\n            try {\n              // Lazy may contain any component type so we recursively resolve it.\n              return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn);\n            } catch (x) {}\n          }\n      }\n    }\n\n    return '';\n  }\n\n  function describeFiber(fiber) {\n    var owner =  fiber._debugOwner ? fiber._debugOwner.type : null ;\n    var source =  fiber._debugSource ;\n\n    switch (fiber.tag) {\n      case HostComponent:\n        return describeBuiltInComponentFrame(fiber.type);\n\n      case LazyComponent:\n        return describeBuiltInComponentFrame('Lazy');\n\n      case SuspenseComponent:\n        return describeBuiltInComponentFrame('Suspense');\n\n      case SuspenseListComponent:\n        return describeBuiltInComponentFrame('SuspenseList');\n\n      case FunctionComponent:\n      case IndeterminateComponent:\n      case SimpleMemoComponent:\n        return describeFunctionComponentFrame(fiber.type);\n\n      case ForwardRef:\n        return describeFunctionComponentFrame(fiber.type.render);\n\n      case ClassComponent:\n        return describeClassComponentFrame(fiber.type);\n\n      default:\n        return '';\n    }\n  }\n\n  function getStackByFiberInDevAndProd(workInProgress) {\n    try {\n      var info = '';\n      var node = workInProgress;\n\n      do {\n        info += describeFiber(node);\n        node = node.return;\n      } while (node);\n\n      return info;\n    } catch (x) {\n      return '\\nError generating stack: ' + x.message + '\\n' + x.stack;\n    }\n  }\n\n  function getWrappedName(outerType, innerType, wrapperName) {\n    var displayName = outerType.displayName;\n\n    if (displayName) {\n      return displayName;\n    }\n\n    var functionName = innerType.displayName || innerType.name || '';\n    return functionName !== '' ? wrapperName + \"(\" + functionName + \")\" : wrapperName;\n  } // Keep in sync with react-reconciler/getComponentNameFromFiber\n\n\n  function getContextName(type) {\n    return type.displayName || 'Context';\n  } // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.\n\n\n  function getComponentNameFromType(type) {\n    if (type == null) {\n      // Host root, text node or just invalid type.\n      return null;\n    }\n\n    {\n      if (typeof type.tag === 'number') {\n        error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.');\n      }\n    }\n\n    if (typeof type === 'function') {\n      return type.displayName || type.name || null;\n    }\n\n    if (typeof type === 'string') {\n      return type;\n    }\n\n    switch (type) {\n      case REACT_FRAGMENT_TYPE:\n        return 'Fragment';\n\n      case REACT_PORTAL_TYPE:\n        return 'Portal';\n\n      case REACT_PROFILER_TYPE:\n        return 'Profiler';\n\n      case REACT_STRICT_MODE_TYPE:\n        return 'StrictMode';\n\n      case REACT_SUSPENSE_TYPE:\n        return 'Suspense';\n\n      case REACT_SUSPENSE_LIST_TYPE:\n        return 'SuspenseList';\n\n    }\n\n    if (typeof type === 'object') {\n      switch (type.$$typeof) {\n        case REACT_CONTEXT_TYPE:\n          var context = type;\n          return getContextName(context) + '.Consumer';\n\n        case REACT_PROVIDER_TYPE:\n          var provider = type;\n          return getContextName(provider._context) + '.Provider';\n\n        case REACT_FORWARD_REF_TYPE:\n          return getWrappedName(type, type.render, 'ForwardRef');\n\n        case REACT_MEMO_TYPE:\n          var outerName = type.displayName || null;\n\n          if (outerName !== null) {\n            return outerName;\n          }\n\n          return getComponentNameFromType(type.type) || 'Memo';\n\n        case REACT_LAZY_TYPE:\n          {\n            var lazyComponent = type;\n            var payload = lazyComponent._payload;\n            var init = lazyComponent._init;\n\n            try {\n              return getComponentNameFromType(init(payload));\n            } catch (x) {\n              return null;\n            }\n          }\n\n        // eslint-disable-next-line no-fallthrough\n      }\n    }\n\n    return null;\n  }\n\n  function getWrappedName$1(outerType, innerType, wrapperName) {\n    var functionName = innerType.displayName || innerType.name || '';\n    return outerType.displayName || (functionName !== '' ? wrapperName + \"(\" + functionName + \")\" : wrapperName);\n  } // Keep in sync with shared/getComponentNameFromType\n\n\n  function getContextName$1(type) {\n    return type.displayName || 'Context';\n  }\n\n  function getComponentNameFromFiber(fiber) {\n    var tag = fiber.tag,\n        type = fiber.type;\n\n    switch (tag) {\n      case CacheComponent:\n        return 'Cache';\n\n      case ContextConsumer:\n        var context = type;\n        return getContextName$1(context) + '.Consumer';\n\n      case ContextProvider:\n        var provider = type;\n        return getContextName$1(provider._context) + '.Provider';\n\n      case DehydratedFragment:\n        return 'DehydratedFragment';\n\n      case ForwardRef:\n        return getWrappedName$1(type, type.render, 'ForwardRef');\n\n      case Fragment:\n        return 'Fragment';\n\n      case HostComponent:\n        // Host component type is the display name (e.g. \"div\", \"View\")\n        return type;\n\n      case HostPortal:\n        return 'Portal';\n\n      case HostRoot:\n        return 'Root';\n\n      case HostText:\n        return 'Text';\n\n      case LazyComponent:\n        // Name comes from the type in this case; we don't have a tag.\n        return getComponentNameFromType(type);\n\n      case Mode:\n        if (type === REACT_STRICT_MODE_TYPE) {\n          // Don't be less specific than shared/getComponentNameFromType\n          return 'StrictMode';\n        }\n\n        return 'Mode';\n\n      case OffscreenComponent:\n        return 'Offscreen';\n\n      case Profiler:\n        return 'Profiler';\n\n      case ScopeComponent:\n        return 'Scope';\n\n      case SuspenseComponent:\n        return 'Suspense';\n\n      case SuspenseListComponent:\n        return 'SuspenseList';\n\n      case TracingMarkerComponent:\n        return 'TracingMarker';\n      // The display name for this tags come from the user-provided type:\n\n      case ClassComponent:\n      case FunctionComponent:\n      case IncompleteClassComponent:\n      case IndeterminateComponent:\n      case MemoComponent:\n      case SimpleMemoComponent:\n        if (typeof type === 'function') {\n          return type.displayName || type.name || null;\n        }\n\n        if (typeof type === 'string') {\n          return type;\n        }\n\n        break;\n\n    }\n\n    return null;\n  }\n\n  var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;\n  var current = null;\n  var isRendering = false;\n  function getCurrentFiberOwnerNameInDevOrNull() {\n    {\n      if (current === null) {\n        return null;\n      }\n\n      var owner = current._debugOwner;\n\n      if (owner !== null && typeof owner !== 'undefined') {\n        return getComponentNameFromFiber(owner);\n      }\n    }\n\n    return null;\n  }\n\n  function getCurrentFiberStackInDev() {\n    {\n      if (current === null) {\n        return '';\n      } // Safe because if current fiber exists, we are reconciling,\n      // and it is guaranteed to be the work-in-progress version.\n\n\n      return getStackByFiberInDevAndProd(current);\n    }\n  }\n\n  function resetCurrentFiber() {\n    {\n      ReactDebugCurrentFrame.getCurrentStack = null;\n      current = null;\n      isRendering = false;\n    }\n  }\n  function setCurrentFiber(fiber) {\n    {\n      ReactDebugCurrentFrame.getCurrentStack = fiber === null ? null : getCurrentFiberStackInDev;\n      current = fiber;\n      isRendering = false;\n    }\n  }\n  function getCurrentFiber() {\n    {\n      return current;\n    }\n  }\n  function setIsRendering(rendering) {\n    {\n      isRendering = rendering;\n    }\n  }\n\n  // Flow does not allow string concatenation of most non-string types. To work\n  // around this limitation, we use an opaque type that can only be obtained by\n  // passing the value through getToStringValue first.\n  function toString(value) {\n    // The coercion safety check is performed in getToStringValue().\n    // eslint-disable-next-line react-internal/safe-string-coercion\n    return '' + value;\n  }\n  function getToStringValue(value) {\n    switch (typeof value) {\n      case 'boolean':\n      case 'number':\n      case 'string':\n      case 'undefined':\n        return value;\n\n      case 'object':\n        {\n          checkFormFieldValueStringCoercion(value);\n        }\n\n        return value;\n\n      default:\n        // function, symbol are assigned as empty strings\n        return '';\n    }\n  }\n\n  var hasReadOnlyValue = {\n    button: true,\n    checkbox: true,\n    image: true,\n    hidden: true,\n    radio: true,\n    reset: true,\n    submit: true\n  };\n  function checkControlledValueProps(tagName, props) {\n    {\n      if (!(hasReadOnlyValue[props.type] || props.onChange || props.onInput || props.readOnly || props.disabled || props.value == null)) {\n        error('You provided a `value` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultValue`. Otherwise, ' + 'set either `onChange` or `readOnly`.');\n      }\n\n      if (!(props.onChange || props.readOnly || props.disabled || props.checked == null)) {\n        error('You provided a `checked` prop to a form field without an ' + '`onChange` handler. This will render a read-only field. If ' + 'the field should be mutable use `defaultChecked`. Otherwise, ' + 'set either `onChange` or `readOnly`.');\n      }\n    }\n  }\n\n  function isCheckable(elem) {\n    var type = elem.type;\n    var nodeName = elem.nodeName;\n    return nodeName && nodeName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio');\n  }\n\n  function getTracker(node) {\n    return node._valueTracker;\n  }\n\n  function detachTracker(node) {\n    node._valueTracker = null;\n  }\n\n  function getValueFromNode(node) {\n    var value = '';\n\n    if (!node) {\n      return value;\n    }\n\n    if (isCheckable(node)) {\n      value = node.checked ? 'true' : 'false';\n    } else {\n      value = node.value;\n    }\n\n    return value;\n  }\n\n  function trackValueOnNode(node) {\n    var valueField = isCheckable(node) ? 'checked' : 'value';\n    var descriptor = Object.getOwnPropertyDescriptor(node.constructor.prototype, valueField);\n\n    {\n      checkFormFieldValueStringCoercion(node[valueField]);\n    }\n\n    var currentValue = '' + node[valueField]; // if someone has already defined a value or Safari, then bail\n    // and don't track value will cause over reporting of changes,\n    // but it's better then a hard failure\n    // (needed for certain tests that spyOn input values and Safari)\n\n    if (node.hasOwnProperty(valueField) || typeof descriptor === 'undefined' || typeof descriptor.get !== 'function' || typeof descriptor.set !== 'function') {\n      return;\n    }\n\n    var get = descriptor.get,\n        set = descriptor.set;\n    Object.defineProperty(node, valueField, {\n      configurable: true,\n      get: function () {\n        return get.call(this);\n      },\n      set: function (value) {\n        {\n          checkFormFieldValueStringCoercion(value);\n        }\n\n        currentValue = '' + value;\n        set.call(this, value);\n      }\n    }); // We could've passed this the first time\n    // but it triggers a bug in IE11 and Edge 14/15.\n    // Calling defineProperty() again should be equivalent.\n    // https://github.com/facebook/react/issues/11768\n\n    Object.defineProperty(node, valueField, {\n      enumerable: descriptor.enumerable\n    });\n    var tracker = {\n      getValue: function () {\n        return currentValue;\n      },\n      setValue: function (value) {\n        {\n          checkFormFieldValueStringCoercion(value);\n        }\n\n        currentValue = '' + value;\n      },\n      stopTracking: function () {\n        detachTracker(node);\n        delete node[valueField];\n      }\n    };\n    return tracker;\n  }\n\n  function track(node) {\n    if (getTracker(node)) {\n      return;\n    } // TODO: Once it's just Fiber we can move this to node._wrapperState\n\n\n    node._valueTracker = trackValueOnNode(node);\n  }\n  function updateValueIfChanged(node) {\n    if (!node) {\n      return false;\n    }\n\n    var tracker = getTracker(node); // if there is no tracker at this point it's unlikely\n    // that trying again will succeed\n\n    if (!tracker) {\n      return true;\n    }\n\n    var lastValue = tracker.getValue();\n    var nextValue = getValueFromNode(node);\n\n    if (nextValue !== lastValue) {\n      tracker.setValue(nextValue);\n      return true;\n    }\n\n    return false;\n  }\n\n  function getActiveElement(doc) {\n    doc = doc || (typeof document !== 'undefined' ? document : undefined);\n\n    if (typeof doc === 'undefined') {\n      return null;\n    }\n\n    try {\n      return doc.activeElement || doc.body;\n    } catch (e) {\n      return doc.body;\n    }\n  }\n\n  var didWarnValueDefaultValue = false;\n  var didWarnCheckedDefaultChecked = false;\n  var didWarnControlledToUncontrolled = false;\n  var didWarnUncontrolledToControlled = false;\n\n  function isControlled(props) {\n    var usesChecked = props.type === 'checkbox' || props.type === 'radio';\n    return usesChecked ? props.checked != null : props.value != null;\n  }\n  /**\n   * Implements an <input> host component that allows setting these optional\n   * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.\n   *\n   * If `checked` or `value` are not supplied (or null/undefined), user actions\n   * that affect the checked state or value will trigger updates to the element.\n   *\n   * If they are supplied (and not null/undefined), the rendered element will not\n   * trigger updates to the element. Instead, the props must change in order for\n   * the rendered element to be updated.\n   *\n   * The rendered element will be initialized as unchecked (or `defaultChecked`)\n   * with an empty value (or `defaultValue`).\n   *\n   * See http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html\n   */\n\n\n  function getHostProps(element, props) {\n    var node = element;\n    var checked = props.checked;\n    var hostProps = assign({}, props, {\n      defaultChecked: undefined,\n      defaultValue: undefined,\n      value: undefined,\n      checked: checked != null ? checked : node._wrapperState.initialChecked\n    });\n    return hostProps;\n  }\n  function initWrapperState(element, props) {\n    {\n      checkControlledValueProps('input', props);\n\n      if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) {\n        error('%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type);\n\n        didWarnCheckedDefaultChecked = true;\n      }\n\n      if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) {\n        error('%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component', props.type);\n\n        didWarnValueDefaultValue = true;\n      }\n    }\n\n    var node = element;\n    var defaultValue = props.defaultValue == null ? '' : props.defaultValue;\n    node._wrapperState = {\n      initialChecked: props.checked != null ? props.checked : props.defaultChecked,\n      initialValue: getToStringValue(props.value != null ? props.value : defaultValue),\n      controlled: isControlled(props)\n    };\n  }\n  function updateChecked(element, props) {\n    var node = element;\n    var checked = props.checked;\n\n    if (checked != null) {\n      setValueForProperty(node, 'checked', checked, false);\n    }\n  }\n  function updateWrapper(element, props) {\n    var node = element;\n\n    {\n      var controlled = isControlled(props);\n\n      if (!node._wrapperState.controlled && controlled && !didWarnUncontrolledToControlled) {\n        error('A component is changing an uncontrolled input to be controlled. ' + 'This is likely caused by the value changing from undefined to ' + 'a defined value, which should not happen. ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components');\n\n        didWarnUncontrolledToControlled = true;\n      }\n\n      if (node._wrapperState.controlled && !controlled && !didWarnControlledToUncontrolled) {\n        error('A component is changing a controlled input to be uncontrolled. ' + 'This is likely caused by the value changing from a defined to ' + 'undefined, which should not happen. ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components');\n\n        didWarnControlledToUncontrolled = true;\n      }\n    }\n\n    updateChecked(element, props);\n    var value = getToStringValue(props.value);\n    var type = props.type;\n\n    if (value != null) {\n      if (type === 'number') {\n        if (value === 0 && node.value === '' || // We explicitly want to coerce to number here if possible.\n        // eslint-disable-next-line\n        node.value != value) {\n          node.value = toString(value);\n        }\n      } else if (node.value !== toString(value)) {\n        node.value = toString(value);\n      }\n    } else if (type === 'submit' || type === 'reset') {\n      // Submit/reset inputs need the attribute removed completely to avoid\n      // blank-text buttons.\n      node.removeAttribute('value');\n      return;\n    }\n\n    {\n      // When syncing the value attribute, the value comes from a cascade of\n      // properties:\n      //  1. The value React property\n      //  2. The defaultValue React property\n      //  3. Otherwise there should be no change\n      if (props.hasOwnProperty('value')) {\n        setDefaultValue(node, props.type, value);\n      } else if (props.hasOwnProperty('defaultValue')) {\n        setDefaultValue(node, props.type, getToStringValue(props.defaultValue));\n      }\n    }\n\n    {\n      // When syncing the checked attribute, it only changes when it needs\n      // to be removed, such as transitioning from a checkbox into a text input\n      if (props.checked == null && props.defaultChecked != null) {\n        node.defaultChecked = !!props.defaultChecked;\n      }\n    }\n  }\n  function postMountWrapper(element, props, isHydrating) {\n    var node = element; // Do not assign value if it is already set. This prevents user text input\n    // from being lost during SSR hydration.\n\n    if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) {\n      var type = props.type;\n      var isButton = type === 'submit' || type === 'reset'; // Avoid setting value attribute on submit/reset inputs as it overrides the\n      // default value provided by the browser. See: #12872\n\n      if (isButton && (props.value === undefined || props.value === null)) {\n        return;\n      }\n\n      var initialValue = toString(node._wrapperState.initialValue); // Do not assign value if it is already set. This prevents user text input\n      // from being lost during SSR hydration.\n\n      if (!isHydrating) {\n        {\n          // When syncing the value attribute, the value property should use\n          // the wrapperState._initialValue property. This uses:\n          //\n          //   1. The value React property when present\n          //   2. The defaultValue React property when present\n          //   3. An empty string\n          if (initialValue !== node.value) {\n            node.value = initialValue;\n          }\n        }\n      }\n\n      {\n        // Otherwise, the value attribute is synchronized to the property,\n        // so we assign defaultValue to the same thing as the value property\n        // assignment step above.\n        node.defaultValue = initialValue;\n      }\n    } // Normally, we'd just do `node.checked = node.checked` upon initial mount, less this bug\n    // this is needed to work around a chrome bug where setting defaultChecked\n    // will sometimes influence the value of checked (even after detachment).\n    // Reference: https://bugs.chromium.org/p/chromium/issues/detail?id=608416\n    // We need to temporarily unset name to avoid disrupting radio button groups.\n\n\n    var name = node.name;\n\n    if (name !== '') {\n      node.name = '';\n    }\n\n    {\n      // When syncing the checked attribute, both the checked property and\n      // attribute are assigned at the same time using defaultChecked. This uses:\n      //\n      //   1. The checked React property when present\n      //   2. The defaultChecked React property when present\n      //   3. Otherwise, false\n      node.defaultChecked = !node.defaultChecked;\n      node.defaultChecked = !!node._wrapperState.initialChecked;\n    }\n\n    if (name !== '') {\n      node.name = name;\n    }\n  }\n  function restoreControlledState(element, props) {\n    var node = element;\n    updateWrapper(node, props);\n    updateNamedCousins(node, props);\n  }\n\n  function updateNamedCousins(rootNode, props) {\n    var name = props.name;\n\n    if (props.type === 'radio' && name != null) {\n      var queryRoot = rootNode;\n\n      while (queryRoot.parentNode) {\n        queryRoot = queryRoot.parentNode;\n      } // If `rootNode.form` was non-null, then we could try `form.elements`,\n      // but that sometimes behaves strangely in IE8. We could also try using\n      // `form.getElementsByName`, but that will only return direct children\n      // and won't include inputs that use the HTML5 `form=` attribute. Since\n      // the input might not even be in a form. It might not even be in the\n      // document. Let's just use the local `querySelectorAll` to ensure we don't\n      // miss anything.\n\n\n      {\n        checkAttributeStringCoercion(name, 'name');\n      }\n\n      var group = queryRoot.querySelectorAll('input[name=' + JSON.stringify('' + name) + '][type=\"radio\"]');\n\n      for (var i = 0; i < group.length; i++) {\n        var otherNode = group[i];\n\n        if (otherNode === rootNode || otherNode.form !== rootNode.form) {\n          continue;\n        } // This will throw if radio buttons rendered by different copies of React\n        // and the same name are rendered into the same form (same as #1939).\n        // That's probably okay; we don't support it just as we don't support\n        // mixing React radio buttons with non-React ones.\n\n\n        var otherProps = getFiberCurrentPropsFromNode(otherNode);\n\n        if (!otherProps) {\n          throw new Error('ReactDOMInput: Mixing React and non-React radio inputs with the ' + 'same `name` is not supported.');\n        } // We need update the tracked value on the named cousin since the value\n        // was changed but the input saw no event or value set\n\n\n        updateValueIfChanged(otherNode); // If this is a controlled radio button group, forcing the input that\n        // was previously checked to update will cause it to be come re-checked\n        // as appropriate.\n\n        updateWrapper(otherNode, otherProps);\n      }\n    }\n  } // In Chrome, assigning defaultValue to certain input types triggers input validation.\n  // For number inputs, the display value loses trailing decimal points. For email inputs,\n  // Chrome raises \"The specified value <x> is not a valid email address\".\n  //\n  // Here we check to see if the defaultValue has actually changed, avoiding these problems\n  // when the user is inputting text\n  //\n  // https://github.com/facebook/react/issues/7253\n\n\n  function setDefaultValue(node, type, value) {\n    if ( // Focused number inputs synchronize on blur. See ChangeEventPlugin.js\n    type !== 'number' || getActiveElement(node.ownerDocument) !== node) {\n      if (value == null) {\n        node.defaultValue = toString(node._wrapperState.initialValue);\n      } else if (node.defaultValue !== toString(value)) {\n        node.defaultValue = toString(value);\n      }\n    }\n  }\n\n  var didWarnSelectedSetOnOption = false;\n  var didWarnInvalidChild = false;\n  var didWarnInvalidInnerHTML = false;\n  /**\n   * Implements an <option> host component that warns when `selected` is set.\n   */\n\n  function validateProps(element, props) {\n    {\n      // If a value is not provided, then the children must be simple.\n      if (props.value == null) {\n        if (typeof props.children === 'object' && props.children !== null) {\n          React.Children.forEach(props.children, function (child) {\n            if (child == null) {\n              return;\n            }\n\n            if (typeof child === 'string' || typeof child === 'number') {\n              return;\n            }\n\n            if (!didWarnInvalidChild) {\n              didWarnInvalidChild = true;\n\n              error('Cannot infer the option value of complex children. ' + 'Pass a `value` prop or use a plain string as children to <option>.');\n            }\n          });\n        } else if (props.dangerouslySetInnerHTML != null) {\n          if (!didWarnInvalidInnerHTML) {\n            didWarnInvalidInnerHTML = true;\n\n            error('Pass a `value` prop if you set dangerouslyInnerHTML so React knows ' + 'which value should be selected.');\n          }\n        }\n      } // TODO: Remove support for `selected` in <option>.\n\n\n      if (props.selected != null && !didWarnSelectedSetOnOption) {\n        error('Use the `defaultValue` or `value` props on <select> instead of ' + 'setting `selected` on <option>.');\n\n        didWarnSelectedSetOnOption = true;\n      }\n    }\n  }\n  function postMountWrapper$1(element, props) {\n    // value=\"\" should make a value attribute (#6219)\n    if (props.value != null) {\n      element.setAttribute('value', toString(getToStringValue(props.value)));\n    }\n  }\n\n  var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare\n\n  function isArray(a) {\n    return isArrayImpl(a);\n  }\n\n  var didWarnValueDefaultValue$1;\n\n  {\n    didWarnValueDefaultValue$1 = false;\n  }\n\n  function getDeclarationErrorAddendum() {\n    var ownerName = getCurrentFiberOwnerNameInDevOrNull();\n\n    if (ownerName) {\n      return '\\n\\nCheck the render method of `' + ownerName + '`.';\n    }\n\n    return '';\n  }\n\n  var valuePropNames = ['value', 'defaultValue'];\n  /**\n   * Validation function for `value` and `defaultValue`.\n   */\n\n  function checkSelectPropTypes(props) {\n    {\n      checkControlledValueProps('select', props);\n\n      for (var i = 0; i < valuePropNames.length; i++) {\n        var propName = valuePropNames[i];\n\n        if (props[propName] == null) {\n          continue;\n        }\n\n        var propNameIsArray = isArray(props[propName]);\n\n        if (props.multiple && !propNameIsArray) {\n          error('The `%s` prop supplied to <select> must be an array if ' + '`multiple` is true.%s', propName, getDeclarationErrorAddendum());\n        } else if (!props.multiple && propNameIsArray) {\n          error('The `%s` prop supplied to <select> must be a scalar ' + 'value if `multiple` is false.%s', propName, getDeclarationErrorAddendum());\n        }\n      }\n    }\n  }\n\n  function updateOptions(node, multiple, propValue, setDefaultSelected) {\n    var options = node.options;\n\n    if (multiple) {\n      var selectedValues = propValue;\n      var selectedValue = {};\n\n      for (var i = 0; i < selectedValues.length; i++) {\n        // Prefix to avoid chaos with special keys.\n        selectedValue['$' + selectedValues[i]] = true;\n      }\n\n      for (var _i = 0; _i < options.length; _i++) {\n        var selected = selectedValue.hasOwnProperty('$' + options[_i].value);\n\n        if (options[_i].selected !== selected) {\n          options[_i].selected = selected;\n        }\n\n        if (selected && setDefaultSelected) {\n          options[_i].defaultSelected = true;\n        }\n      }\n    } else {\n      // Do not set `select.value` as exact behavior isn't consistent across all\n      // browsers for all cases.\n      var _selectedValue = toString(getToStringValue(propValue));\n\n      var defaultSelected = null;\n\n      for (var _i2 = 0; _i2 < options.length; _i2++) {\n        if (options[_i2].value === _selectedValue) {\n          options[_i2].selected = true;\n\n          if (setDefaultSelected) {\n            options[_i2].defaultSelected = true;\n          }\n\n          return;\n        }\n\n        if (defaultSelected === null && !options[_i2].disabled) {\n          defaultSelected = options[_i2];\n        }\n      }\n\n      if (defaultSelected !== null) {\n        defaultSelected.selected = true;\n      }\n    }\n  }\n  /**\n   * Implements a <select> host component that allows optionally setting the\n   * props `value` and `defaultValue`. If `multiple` is false, the prop must be a\n   * stringable. If `multiple` is true, the prop must be an array of stringables.\n   *\n   * If `value` is not supplied (or null/undefined), user actions that change the\n   * selected option will trigger updates to the rendered options.\n   *\n   * If it is supplied (and not null/undefined), the rendered options will not\n   * update in response to user actions. Instead, the `value` prop must change in\n   * order for the rendered options to update.\n   *\n   * If `defaultValue` is provided, any options with the supplied values will be\n   * selected.\n   */\n\n\n  function getHostProps$1(element, props) {\n    return assign({}, props, {\n      value: undefined\n    });\n  }\n  function initWrapperState$1(element, props) {\n    var node = element;\n\n    {\n      checkSelectPropTypes(props);\n    }\n\n    node._wrapperState = {\n      wasMultiple: !!props.multiple\n    };\n\n    {\n      if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue$1) {\n        error('Select elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled select ' + 'element and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components');\n\n        didWarnValueDefaultValue$1 = true;\n      }\n    }\n  }\n  function postMountWrapper$2(element, props) {\n    var node = element;\n    node.multiple = !!props.multiple;\n    var value = props.value;\n\n    if (value != null) {\n      updateOptions(node, !!props.multiple, value, false);\n    } else if (props.defaultValue != null) {\n      updateOptions(node, !!props.multiple, props.defaultValue, true);\n    }\n  }\n  function postUpdateWrapper(element, props) {\n    var node = element;\n    var wasMultiple = node._wrapperState.wasMultiple;\n    node._wrapperState.wasMultiple = !!props.multiple;\n    var value = props.value;\n\n    if (value != null) {\n      updateOptions(node, !!props.multiple, value, false);\n    } else if (wasMultiple !== !!props.multiple) {\n      // For simplicity, reapply `defaultValue` if `multiple` is toggled.\n      if (props.defaultValue != null) {\n        updateOptions(node, !!props.multiple, props.defaultValue, true);\n      } else {\n        // Revert the select back to its default unselected state.\n        updateOptions(node, !!props.multiple, props.multiple ? [] : '', false);\n      }\n    }\n  }\n  function restoreControlledState$1(element, props) {\n    var node = element;\n    var value = props.value;\n\n    if (value != null) {\n      updateOptions(node, !!props.multiple, value, false);\n    }\n  }\n\n  var didWarnValDefaultVal = false;\n\n  /**\n   * Implements a <textarea> host component that allows setting `value`, and\n   * `defaultValue`. This differs from the traditional DOM API because value is\n   * usually set as PCDATA children.\n   *\n   * If `value` is not supplied (or null/undefined), user actions that affect the\n   * value will trigger updates to the element.\n   *\n   * If `value` is supplied (and not null/undefined), the rendered element will\n   * not trigger updates to the element. Instead, the `value` prop must change in\n   * order for the rendered element to be updated.\n   *\n   * The rendered element will be initialized with an empty value, the prop\n   * `defaultValue` if specified, or the children content (deprecated).\n   */\n  function getHostProps$2(element, props) {\n    var node = element;\n\n    if (props.dangerouslySetInnerHTML != null) {\n      throw new Error('`dangerouslySetInnerHTML` does not make sense on <textarea>.');\n    } // Always set children to the same thing. In IE9, the selection range will\n    // get reset if `textContent` is mutated.  We could add a check in setTextContent\n    // to only set the value if/when the value differs from the node value (which would\n    // completely solve this IE9 bug), but Sebastian+Sophie seemed to like this\n    // solution. The value can be a boolean or object so that's why it's forced\n    // to be a string.\n\n\n    var hostProps = assign({}, props, {\n      value: undefined,\n      defaultValue: undefined,\n      children: toString(node._wrapperState.initialValue)\n    });\n\n    return hostProps;\n  }\n  function initWrapperState$2(element, props) {\n    var node = element;\n\n    {\n      checkControlledValueProps('textarea', props);\n\n      if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValDefaultVal) {\n        error('%s contains a textarea with both value and defaultValue props. ' + 'Textarea elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled textarea ' + 'and remove one of these props. More info: ' + 'https://reactjs.org/link/controlled-components', getCurrentFiberOwnerNameInDevOrNull() || 'A component');\n\n        didWarnValDefaultVal = true;\n      }\n    }\n\n    var initialValue = props.value; // Only bother fetching default value if we're going to use it\n\n    if (initialValue == null) {\n      var children = props.children,\n          defaultValue = props.defaultValue;\n\n      if (children != null) {\n        {\n          error('Use the `defaultValue` or `value` props instead of setting ' + 'children on <textarea>.');\n        }\n\n        {\n          if (defaultValue != null) {\n            throw new Error('If you supply `defaultValue` on a <textarea>, do not pass children.');\n          }\n\n          if (isArray(children)) {\n            if (children.length > 1) {\n              throw new Error('<textarea> can only have at most one child.');\n            }\n\n            children = children[0];\n          }\n\n          defaultValue = children;\n        }\n      }\n\n      if (defaultValue == null) {\n        defaultValue = '';\n      }\n\n      initialValue = defaultValue;\n    }\n\n    node._wrapperState = {\n      initialValue: getToStringValue(initialValue)\n    };\n  }\n  function updateWrapper$1(element, props) {\n    var node = element;\n    var value = getToStringValue(props.value);\n    var defaultValue = getToStringValue(props.defaultValue);\n\n    if (value != null) {\n      // Cast `value` to a string to ensure the value is set correctly. While\n      // browsers typically do this as necessary, jsdom doesn't.\n      var newValue = toString(value); // To avoid side effects (such as losing text selection), only set value if changed\n\n      if (newValue !== node.value) {\n        node.value = newValue;\n      }\n\n      if (props.defaultValue == null && node.defaultValue !== newValue) {\n        node.defaultValue = newValue;\n      }\n    }\n\n    if (defaultValue != null) {\n      node.defaultValue = toString(defaultValue);\n    }\n  }\n  function postMountWrapper$3(element, props) {\n    var node = element; // This is in postMount because we need access to the DOM node, which is not\n    // available until after the component has mounted.\n\n    var textContent = node.textContent; // Only set node.value if textContent is equal to the expected\n    // initial value. In IE10/IE11 there is a bug where the placeholder attribute\n    // will populate textContent as well.\n    // https://developer.microsoft.com/microsoft-edge/platform/issues/101525/\n\n    if (textContent === node._wrapperState.initialValue) {\n      if (textContent !== '' && textContent !== null) {\n        node.value = textContent;\n      }\n    }\n  }\n  function restoreControlledState$2(element, props) {\n    // DOM component is still mounted; update\n    updateWrapper$1(element, props);\n  }\n\n  var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n  var MATH_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n  var SVG_NAMESPACE = 'http://www.w3.org/2000/svg'; // Assumes there is no parent namespace.\n\n  function getIntrinsicNamespace(type) {\n    switch (type) {\n      case 'svg':\n        return SVG_NAMESPACE;\n\n      case 'math':\n        return MATH_NAMESPACE;\n\n      default:\n        return HTML_NAMESPACE;\n    }\n  }\n  function getChildNamespace(parentNamespace, type) {\n    if (parentNamespace == null || parentNamespace === HTML_NAMESPACE) {\n      // No (or default) parent namespace: potential entry point.\n      return getIntrinsicNamespace(type);\n    }\n\n    if (parentNamespace === SVG_NAMESPACE && type === 'foreignObject') {\n      // We're leaving SVG.\n      return HTML_NAMESPACE;\n    } // By default, pass namespace below.\n\n\n    return parentNamespace;\n  }\n\n  /* globals MSApp */\n\n  /**\n   * Create a function which has 'unsafe' privileges (required by windows8 apps)\n   */\n  var createMicrosoftUnsafeLocalFunction = function (func) {\n    if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {\n      return function (arg0, arg1, arg2, arg3) {\n        MSApp.execUnsafeLocalFunction(function () {\n          return func(arg0, arg1, arg2, arg3);\n        });\n      };\n    } else {\n      return func;\n    }\n  };\n\n  var reusableSVGContainer;\n  /**\n   * Set the innerHTML property of a node\n   *\n   * @param {DOMElement} node\n   * @param {string} html\n   * @internal\n   */\n\n  var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) {\n    if (node.namespaceURI === SVG_NAMESPACE) {\n\n      if (!('innerHTML' in node)) {\n        // IE does not have innerHTML for SVG nodes, so instead we inject the\n        // new markup in a temp node and then move the child nodes across into\n        // the target node\n        reusableSVGContainer = reusableSVGContainer || document.createElement('div');\n        reusableSVGContainer.innerHTML = '<svg>' + html.valueOf().toString() + '</svg>';\n        var svgNode = reusableSVGContainer.firstChild;\n\n        while (node.firstChild) {\n          node.removeChild(node.firstChild);\n        }\n\n        while (svgNode.firstChild) {\n          node.appendChild(svgNode.firstChild);\n        }\n\n        return;\n      }\n    }\n\n    node.innerHTML = html;\n  });\n\n  /**\n   * HTML nodeType values that represent the type of the node\n   */\n  var ELEMENT_NODE = 1;\n  var TEXT_NODE = 3;\n  var COMMENT_NODE = 8;\n  var DOCUMENT_NODE = 9;\n  var DOCUMENT_FRAGMENT_NODE = 11;\n\n  /**\n   * Set the textContent property of a node. For text updates, it's faster\n   * to set the `nodeValue` of the Text node directly instead of using\n   * `.textContent` which will remove the existing node and create a new one.\n   *\n   * @param {DOMElement} node\n   * @param {string} text\n   * @internal\n   */\n\n  var setTextContent = function (node, text) {\n    if (text) {\n      var firstChild = node.firstChild;\n\n      if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE) {\n        firstChild.nodeValue = text;\n        return;\n      }\n    }\n\n    node.textContent = text;\n  };\n\n  // List derived from Gecko source code:\n  // https://github.com/mozilla/gecko-dev/blob/4e638efc71/layout/style/test/property_database.js\n  var shorthandToLonghand = {\n    animation: ['animationDelay', 'animationDirection', 'animationDuration', 'animationFillMode', 'animationIterationCount', 'animationName', 'animationPlayState', 'animationTimingFunction'],\n    background: ['backgroundAttachment', 'backgroundClip', 'backgroundColor', 'backgroundImage', 'backgroundOrigin', 'backgroundPositionX', 'backgroundPositionY', 'backgroundRepeat', 'backgroundSize'],\n    backgroundPosition: ['backgroundPositionX', 'backgroundPositionY'],\n    border: ['borderBottomColor', 'borderBottomStyle', 'borderBottomWidth', 'borderImageOutset', 'borderImageRepeat', 'borderImageSlice', 'borderImageSource', 'borderImageWidth', 'borderLeftColor', 'borderLeftStyle', 'borderLeftWidth', 'borderRightColor', 'borderRightStyle', 'borderRightWidth', 'borderTopColor', 'borderTopStyle', 'borderTopWidth'],\n    borderBlockEnd: ['borderBlockEndColor', 'borderBlockEndStyle', 'borderBlockEndWidth'],\n    borderBlockStart: ['borderBlockStartColor', 'borderBlockStartStyle', 'borderBlockStartWidth'],\n    borderBottom: ['borderBottomColor', 'borderBottomStyle', 'borderBottomWidth'],\n    borderColor: ['borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor'],\n    borderImage: ['borderImageOutset', 'borderImageRepeat', 'borderImageSlice', 'borderImageSource', 'borderImageWidth'],\n    borderInlineEnd: ['borderInlineEndColor', 'borderInlineEndStyle', 'borderInlineEndWidth'],\n    borderInlineStart: ['borderInlineStartColor', 'borderInlineStartStyle', 'borderInlineStartWidth'],\n    borderLeft: ['borderLeftColor', 'borderLeftStyle', 'borderLeftWidth'],\n    borderRadius: ['borderBottomLeftRadius', 'borderBottomRightRadius', 'borderTopLeftRadius', 'borderTopRightRadius'],\n    borderRight: ['borderRightColor', 'borderRightStyle', 'borderRightWidth'],\n    borderStyle: ['borderBottomStyle', 'borderLeftStyle', 'borderRightStyle', 'borderTopStyle'],\n    borderTop: ['borderTopColor', 'borderTopStyle', 'borderTopWidth'],\n    borderWidth: ['borderBottomWidth', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth'],\n    columnRule: ['columnRuleColor', 'columnRuleStyle', 'columnRuleWidth'],\n    columns: ['columnCount', 'columnWidth'],\n    flex: ['flexBasis', 'flexGrow', 'flexShrink'],\n    flexFlow: ['flexDirection', 'flexWrap'],\n    font: ['fontFamily', 'fontFeatureSettings', 'fontKerning', 'fontLanguageOverride', 'fontSize', 'fontSizeAdjust', 'fontStretch', 'fontStyle', 'fontVariant', 'fontVariantAlternates', 'fontVariantCaps', 'fontVariantEastAsian', 'fontVariantLigatures', 'fontVariantNumeric', 'fontVariantPosition', 'fontWeight', 'lineHeight'],\n    fontVariant: ['fontVariantAlternates', 'fontVariantCaps', 'fontVariantEastAsian', 'fontVariantLigatures', 'fontVariantNumeric', 'fontVariantPosition'],\n    gap: ['columnGap', 'rowGap'],\n    grid: ['gridAutoColumns', 'gridAutoFlow', 'gridAutoRows', 'gridTemplateAreas', 'gridTemplateColumns', 'gridTemplateRows'],\n    gridArea: ['gridColumnEnd', 'gridColumnStart', 'gridRowEnd', 'gridRowStart'],\n    gridColumn: ['gridColumnEnd', 'gridColumnStart'],\n    gridColumnGap: ['columnGap'],\n    gridGap: ['columnGap', 'rowGap'],\n    gridRow: ['gridRowEnd', 'gridRowStart'],\n    gridRowGap: ['rowGap'],\n    gridTemplate: ['gridTemplateAreas', 'gridTemplateColumns', 'gridTemplateRows'],\n    listStyle: ['listStyleImage', 'listStylePosition', 'listStyleType'],\n    margin: ['marginBottom', 'marginLeft', 'marginRight', 'marginTop'],\n    marker: ['markerEnd', 'markerMid', 'markerStart'],\n    mask: ['maskClip', 'maskComposite', 'maskImage', 'maskMode', 'maskOrigin', 'maskPositionX', 'maskPositionY', 'maskRepeat', 'maskSize'],\n    maskPosition: ['maskPositionX', 'maskPositionY'],\n    outline: ['outlineColor', 'outlineStyle', 'outlineWidth'],\n    overflow: ['overflowX', 'overflowY'],\n    padding: ['paddingBottom', 'paddingLeft', 'paddingRight', 'paddingTop'],\n    placeContent: ['alignContent', 'justifyContent'],\n    placeItems: ['alignItems', 'justifyItems'],\n    placeSelf: ['alignSelf', 'justifySelf'],\n    textDecoration: ['textDecorationColor', 'textDecorationLine', 'textDecorationStyle'],\n    textEmphasis: ['textEmphasisColor', 'textEmphasisStyle'],\n    transition: ['transitionDelay', 'transitionDuration', 'transitionProperty', 'transitionTimingFunction'],\n    wordWrap: ['overflowWrap']\n  };\n\n  /**\n   * CSS properties which accept numbers but are not in units of \"px\".\n   */\n  var isUnitlessNumber = {\n    animationIterationCount: true,\n    aspectRatio: true,\n    borderImageOutset: true,\n    borderImageSlice: true,\n    borderImageWidth: true,\n    boxFlex: true,\n    boxFlexGroup: true,\n    boxOrdinalGroup: true,\n    columnCount: true,\n    columns: true,\n    flex: true,\n    flexGrow: true,\n    flexPositive: true,\n    flexShrink: true,\n    flexNegative: true,\n    flexOrder: true,\n    gridArea: true,\n    gridRow: true,\n    gridRowEnd: true,\n    gridRowSpan: true,\n    gridRowStart: true,\n    gridColumn: true,\n    gridColumnEnd: true,\n    gridColumnSpan: true,\n    gridColumnStart: true,\n    fontWeight: true,\n    lineClamp: true,\n    lineHeight: true,\n    opacity: true,\n    order: true,\n    orphans: true,\n    tabSize: true,\n    widows: true,\n    zIndex: true,\n    zoom: true,\n    // SVG-related properties\n    fillOpacity: true,\n    floodOpacity: true,\n    stopOpacity: true,\n    strokeDasharray: true,\n    strokeDashoffset: true,\n    strokeMiterlimit: true,\n    strokeOpacity: true,\n    strokeWidth: true\n  };\n  /**\n   * @param {string} prefix vendor-specific prefix, eg: Webkit\n   * @param {string} key style name, eg: transitionDuration\n   * @return {string} style name prefixed with `prefix`, properly camelCased, eg:\n   * WebkitTransitionDuration\n   */\n\n  function prefixKey(prefix, key) {\n    return prefix + key.charAt(0).toUpperCase() + key.substring(1);\n  }\n  /**\n   * Support style names that may come passed in prefixed by adding permutations\n   * of vendor prefixes.\n   */\n\n\n  var prefixes = ['Webkit', 'ms', 'Moz', 'O']; // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an\n  // infinite loop, because it iterates over the newly added props too.\n\n  Object.keys(isUnitlessNumber).forEach(function (prop) {\n    prefixes.forEach(function (prefix) {\n      isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];\n    });\n  });\n\n  /**\n   * Convert a value into the proper css writable value. The style name `name`\n   * should be logical (no hyphens), as specified\n   * in `CSSProperty.isUnitlessNumber`.\n   *\n   * @param {string} name CSS property name such as `topMargin`.\n   * @param {*} value CSS property value such as `10px`.\n   * @return {string} Normalized style value with dimensions applied.\n   */\n\n  function dangerousStyleValue(name, value, isCustomProperty) {\n    // Note that we've removed escapeTextForBrowser() calls here since the\n    // whole string will be escaped when the attribute is injected into\n    // the markup. If you provide unsafe user data here they can inject\n    // arbitrary CSS which may be problematic (I couldn't repro this):\n    // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet\n    // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/\n    // This is not an XSS hole but instead a potential CSS injection issue\n    // which has lead to a greater discussion about how we're going to\n    // trust URLs moving forward. See #2115901\n    var isEmpty = value == null || typeof value === 'boolean' || value === '';\n\n    if (isEmpty) {\n      return '';\n    }\n\n    if (!isCustomProperty && typeof value === 'number' && value !== 0 && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) {\n      return value + 'px'; // Presumes implicit 'px' suffix for unitless numbers\n    }\n\n    {\n      checkCSSPropertyStringCoercion(value, name);\n    }\n\n    return ('' + value).trim();\n  }\n\n  var uppercasePattern = /([A-Z])/g;\n  var msPattern = /^ms-/;\n  /**\n   * Hyphenates a camelcased CSS property name, for example:\n   *\n   *   > hyphenateStyleName('backgroundColor')\n   *   < \"background-color\"\n   *   > hyphenateStyleName('MozTransition')\n   *   < \"-moz-transition\"\n   *   > hyphenateStyleName('msTransition')\n   *   < \"-ms-transition\"\n   *\n   * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix\n   * is converted to `-ms-`.\n   */\n\n  function hyphenateStyleName(name) {\n    return name.replace(uppercasePattern, '-$1').toLowerCase().replace(msPattern, '-ms-');\n  }\n\n  var warnValidStyle = function () {};\n\n  {\n    // 'msTransform' is correct, but the other prefixes should be capitalized\n    var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/;\n    var msPattern$1 = /^-ms-/;\n    var hyphenPattern = /-(.)/g; // style values shouldn't contain a semicolon\n\n    var badStyleValueWithSemicolonPattern = /;\\s*$/;\n    var warnedStyleNames = {};\n    var warnedStyleValues = {};\n    var warnedForNaNValue = false;\n    var warnedForInfinityValue = false;\n\n    var camelize = function (string) {\n      return string.replace(hyphenPattern, function (_, character) {\n        return character.toUpperCase();\n      });\n    };\n\n    var warnHyphenatedStyleName = function (name) {\n      if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {\n        return;\n      }\n\n      warnedStyleNames[name] = true;\n\n      error('Unsupported style property %s. Did you mean %s?', name, // As Andi Smith suggests\n      // (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix\n      // is converted to lowercase `ms`.\n      camelize(name.replace(msPattern$1, 'ms-')));\n    };\n\n    var warnBadVendoredStyleName = function (name) {\n      if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {\n        return;\n      }\n\n      warnedStyleNames[name] = true;\n\n      error('Unsupported vendor-prefixed style property %s. Did you mean %s?', name, name.charAt(0).toUpperCase() + name.slice(1));\n    };\n\n    var warnStyleValueWithSemicolon = function (name, value) {\n      if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {\n        return;\n      }\n\n      warnedStyleValues[value] = true;\n\n      error(\"Style property values shouldn't contain a semicolon. \" + 'Try \"%s: %s\" instead.', name, value.replace(badStyleValueWithSemicolonPattern, ''));\n    };\n\n    var warnStyleValueIsNaN = function (name, value) {\n      if (warnedForNaNValue) {\n        return;\n      }\n\n      warnedForNaNValue = true;\n\n      error('`NaN` is an invalid value for the `%s` css style property.', name);\n    };\n\n    var warnStyleValueIsInfinity = function (name, value) {\n      if (warnedForInfinityValue) {\n        return;\n      }\n\n      warnedForInfinityValue = true;\n\n      error('`Infinity` is an invalid value for the `%s` css style property.', name);\n    };\n\n    warnValidStyle = function (name, value) {\n      if (name.indexOf('-') > -1) {\n        warnHyphenatedStyleName(name);\n      } else if (badVendoredStyleNamePattern.test(name)) {\n        warnBadVendoredStyleName(name);\n      } else if (badStyleValueWithSemicolonPattern.test(value)) {\n        warnStyleValueWithSemicolon(name, value);\n      }\n\n      if (typeof value === 'number') {\n        if (isNaN(value)) {\n          warnStyleValueIsNaN(name, value);\n        } else if (!isFinite(value)) {\n          warnStyleValueIsInfinity(name, value);\n        }\n      }\n    };\n  }\n\n  var warnValidStyle$1 = warnValidStyle;\n\n  /**\n   * Operations for dealing with CSS properties.\n   */\n\n  /**\n   * This creates a string that is expected to be equivalent to the style\n   * attribute generated by server-side rendering. It by-passes warnings and\n   * security checks so it's not safe to use this value for anything other than\n   * comparison. It is only used in DEV for SSR validation.\n   */\n\n  function createDangerousStringForStyles(styles) {\n    {\n      var serialized = '';\n      var delimiter = '';\n\n      for (var styleName in styles) {\n        if (!styles.hasOwnProperty(styleName)) {\n          continue;\n        }\n\n        var styleValue = styles[styleName];\n\n        if (styleValue != null) {\n          var isCustomProperty = styleName.indexOf('--') === 0;\n          serialized += delimiter + (isCustomProperty ? styleName : hyphenateStyleName(styleName)) + ':';\n          serialized += dangerousStyleValue(styleName, styleValue, isCustomProperty);\n          delimiter = ';';\n        }\n      }\n\n      return serialized || null;\n    }\n  }\n  /**\n   * Sets the value for multiple styles on a node.  If a value is specified as\n   * '' (empty string), the corresponding style property will be unset.\n   *\n   * @param {DOMElement} node\n   * @param {object} styles\n   */\n\n  function setValueForStyles(node, styles) {\n    var style = node.style;\n\n    for (var styleName in styles) {\n      if (!styles.hasOwnProperty(styleName)) {\n        continue;\n      }\n\n      var isCustomProperty = styleName.indexOf('--') === 0;\n\n      {\n        if (!isCustomProperty) {\n          warnValidStyle$1(styleName, styles[styleName]);\n        }\n      }\n\n      var styleValue = dangerousStyleValue(styleName, styles[styleName], isCustomProperty);\n\n      if (styleName === 'float') {\n        styleName = 'cssFloat';\n      }\n\n      if (isCustomProperty) {\n        style.setProperty(styleName, styleValue);\n      } else {\n        style[styleName] = styleValue;\n      }\n    }\n  }\n\n  function isValueEmpty(value) {\n    return value == null || typeof value === 'boolean' || value === '';\n  }\n  /**\n   * Given {color: 'red', overflow: 'hidden'} returns {\n   *   color: 'color',\n   *   overflowX: 'overflow',\n   *   overflowY: 'overflow',\n   * }. This can be read as \"the overflowY property was set by the overflow\n   * shorthand\". That is, the values are the property that each was derived from.\n   */\n\n\n  function expandShorthandMap(styles) {\n    var expanded = {};\n\n    for (var key in styles) {\n      var longhands = shorthandToLonghand[key] || [key];\n\n      for (var i = 0; i < longhands.length; i++) {\n        expanded[longhands[i]] = key;\n      }\n    }\n\n    return expanded;\n  }\n  /**\n   * When mixing shorthand and longhand property names, we warn during updates if\n   * we expect an incorrect result to occur. In particular, we warn for:\n   *\n   * Updating a shorthand property (longhand gets overwritten):\n   *   {font: 'foo', fontVariant: 'bar'} -> {font: 'baz', fontVariant: 'bar'}\n   *   becomes .style.font = 'baz'\n   * Removing a shorthand property (longhand gets lost too):\n   *   {font: 'foo', fontVariant: 'bar'} -> {fontVariant: 'bar'}\n   *   becomes .style.font = ''\n   * Removing a longhand property (should revert to shorthand; doesn't):\n   *   {font: 'foo', fontVariant: 'bar'} -> {font: 'foo'}\n   *   becomes .style.fontVariant = ''\n   */\n\n\n  function validateShorthandPropertyCollisionInDev(styleUpdates, nextStyles) {\n    {\n      if (!nextStyles) {\n        return;\n      }\n\n      var expandedUpdates = expandShorthandMap(styleUpdates);\n      var expandedStyles = expandShorthandMap(nextStyles);\n      var warnedAbout = {};\n\n      for (var key in expandedUpdates) {\n        var originalKey = expandedUpdates[key];\n        var correctOriginalKey = expandedStyles[key];\n\n        if (correctOriginalKey && originalKey !== correctOriginalKey) {\n          var warningKey = originalKey + ',' + correctOriginalKey;\n\n          if (warnedAbout[warningKey]) {\n            continue;\n          }\n\n          warnedAbout[warningKey] = true;\n\n          error('%s a style property during rerender (%s) when a ' + 'conflicting property is set (%s) can lead to styling bugs. To ' + \"avoid this, don't mix shorthand and non-shorthand properties \" + 'for the same value; instead, replace the shorthand with ' + 'separate values.', isValueEmpty(styleUpdates[originalKey]) ? 'Removing' : 'Updating', originalKey, correctOriginalKey);\n        }\n      }\n    }\n  }\n\n  // For HTML, certain tags should omit their close tag. We keep a list for\n  // those special-case tags.\n  var omittedCloseTags = {\n    area: true,\n    base: true,\n    br: true,\n    col: true,\n    embed: true,\n    hr: true,\n    img: true,\n    input: true,\n    keygen: true,\n    link: true,\n    meta: true,\n    param: true,\n    source: true,\n    track: true,\n    wbr: true // NOTE: menuitem's close tag should be omitted, but that causes problems.\n\n  };\n\n  // `omittedCloseTags` except that `menuitem` should still have its closing tag.\n\n  var voidElementTags = assign({\n    menuitem: true\n  }, omittedCloseTags);\n\n  var HTML = '__html';\n\n  function assertValidProps(tag, props) {\n    if (!props) {\n      return;\n    } // Note the use of `==` which checks for null or undefined.\n\n\n    if (voidElementTags[tag]) {\n      if (props.children != null || props.dangerouslySetInnerHTML != null) {\n        throw new Error(tag + \" is a void element tag and must neither have `children` nor \" + 'use `dangerouslySetInnerHTML`.');\n      }\n    }\n\n    if (props.dangerouslySetInnerHTML != null) {\n      if (props.children != null) {\n        throw new Error('Can only set one of `children` or `props.dangerouslySetInnerHTML`.');\n      }\n\n      if (typeof props.dangerouslySetInnerHTML !== 'object' || !(HTML in props.dangerouslySetInnerHTML)) {\n        throw new Error('`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + 'Please visit https://reactjs.org/link/dangerously-set-inner-html ' + 'for more information.');\n      }\n    }\n\n    {\n      if (!props.suppressContentEditableWarning && props.contentEditable && props.children != null) {\n        error('A component is `contentEditable` and contains `children` managed by ' + 'React. It is now your responsibility to guarantee that none of ' + 'those nodes are unexpectedly modified or duplicated. This is ' + 'probably not intentional.');\n      }\n    }\n\n    if (props.style != null && typeof props.style !== 'object') {\n      throw new Error('The `style` prop expects a mapping from style properties to values, ' + \"not a string. For example, style={{marginRight: spacing + 'em'}} when \" + 'using JSX.');\n    }\n  }\n\n  function isCustomComponent(tagName, props) {\n    if (tagName.indexOf('-') === -1) {\n      return typeof props.is === 'string';\n    }\n\n    switch (tagName) {\n      // These are reserved SVG and MathML elements.\n      // We don't mind this list too much because we expect it to never grow.\n      // The alternative is to track the namespace in a few places which is convoluted.\n      // https://w3c.github.io/webcomponents/spec/custom/#custom-elements-core-concepts\n      case 'annotation-xml':\n      case 'color-profile':\n      case 'font-face':\n      case 'font-face-src':\n      case 'font-face-uri':\n      case 'font-face-format':\n      case 'font-face-name':\n      case 'missing-glyph':\n        return false;\n\n      default:\n        return true;\n    }\n  }\n\n  // When adding attributes to the HTML or SVG allowed attribute list, be sure to\n  // also add them to this module to ensure casing and incorrect name\n  // warnings.\n  var possibleStandardNames = {\n    // HTML\n    accept: 'accept',\n    acceptcharset: 'acceptCharset',\n    'accept-charset': 'acceptCharset',\n    accesskey: 'accessKey',\n    action: 'action',\n    allowfullscreen: 'allowFullScreen',\n    alt: 'alt',\n    as: 'as',\n    async: 'async',\n    autocapitalize: 'autoCapitalize',\n    autocomplete: 'autoComplete',\n    autocorrect: 'autoCorrect',\n    autofocus: 'autoFocus',\n    autoplay: 'autoPlay',\n    autosave: 'autoSave',\n    capture: 'capture',\n    cellpadding: 'cellPadding',\n    cellspacing: 'cellSpacing',\n    challenge: 'challenge',\n    charset: 'charSet',\n    checked: 'checked',\n    children: 'children',\n    cite: 'cite',\n    class: 'className',\n    classid: 'classID',\n    classname: 'className',\n    cols: 'cols',\n    colspan: 'colSpan',\n    content: 'content',\n    contenteditable: 'contentEditable',\n    contextmenu: 'contextMenu',\n    controls: 'controls',\n    controlslist: 'controlsList',\n    coords: 'coords',\n    crossorigin: 'crossOrigin',\n    dangerouslysetinnerhtml: 'dangerouslySetInnerHTML',\n    data: 'data',\n    datetime: 'dateTime',\n    default: 'default',\n    defaultchecked: 'defaultChecked',\n    defaultvalue: 'defaultValue',\n    defer: 'defer',\n    dir: 'dir',\n    disabled: 'disabled',\n    disablepictureinpicture: 'disablePictureInPicture',\n    disableremoteplayback: 'disableRemotePlayback',\n    download: 'download',\n    draggable: 'draggable',\n    enctype: 'encType',\n    enterkeyhint: 'enterKeyHint',\n    for: 'htmlFor',\n    form: 'form',\n    formmethod: 'formMethod',\n    formaction: 'formAction',\n    formenctype: 'formEncType',\n    formnovalidate: 'formNoValidate',\n    formtarget: 'formTarget',\n    frameborder: 'frameBorder',\n    headers: 'headers',\n    height: 'height',\n    hidden: 'hidden',\n    high: 'high',\n    href: 'href',\n    hreflang: 'hrefLang',\n    htmlfor: 'htmlFor',\n    httpequiv: 'httpEquiv',\n    'http-equiv': 'httpEquiv',\n    icon: 'icon',\n    id: 'id',\n    imagesizes: 'imageSizes',\n    imagesrcset: 'imageSrcSet',\n    innerhtml: 'innerHTML',\n    inputmode: 'inputMode',\n    integrity: 'integrity',\n    is: 'is',\n    itemid: 'itemID',\n    itemprop: 'itemProp',\n    itemref: 'itemRef',\n    itemscope: 'itemScope',\n    itemtype: 'itemType',\n    keyparams: 'keyParams',\n    keytype: 'keyType',\n    kind: 'kind',\n    label: 'label',\n    lang: 'lang',\n    list: 'list',\n    loop: 'loop',\n    low: 'low',\n    manifest: 'manifest',\n    marginwidth: 'marginWidth',\n    marginheight: 'marginHeight',\n    max: 'max',\n    maxlength: 'maxLength',\n    media: 'media',\n    mediagroup: 'mediaGroup',\n    method: 'method',\n    min: 'min',\n    minlength: 'minLength',\n    multiple: 'multiple',\n    muted: 'muted',\n    name: 'name',\n    nomodule: 'noModule',\n    nonce: 'nonce',\n    novalidate: 'noValidate',\n    open: 'open',\n    optimum: 'optimum',\n    pattern: 'pattern',\n    placeholder: 'placeholder',\n    playsinline: 'playsInline',\n    poster: 'poster',\n    preload: 'preload',\n    profile: 'profile',\n    radiogroup: 'radioGroup',\n    readonly: 'readOnly',\n    referrerpolicy: 'referrerPolicy',\n    rel: 'rel',\n    required: 'required',\n    reversed: 'reversed',\n    role: 'role',\n    rows: 'rows',\n    rowspan: 'rowSpan',\n    sandbox: 'sandbox',\n    scope: 'scope',\n    scoped: 'scoped',\n    scrolling: 'scrolling',\n    seamless: 'seamless',\n    selected: 'selected',\n    shape: 'shape',\n    size: 'size',\n    sizes: 'sizes',\n    span: 'span',\n    spellcheck: 'spellCheck',\n    src: 'src',\n    srcdoc: 'srcDoc',\n    srclang: 'srcLang',\n    srcset: 'srcSet',\n    start: 'start',\n    step: 'step',\n    style: 'style',\n    summary: 'summary',\n    tabindex: 'tabIndex',\n    target: 'target',\n    title: 'title',\n    type: 'type',\n    usemap: 'useMap',\n    value: 'value',\n    width: 'width',\n    wmode: 'wmode',\n    wrap: 'wrap',\n    // SVG\n    about: 'about',\n    accentheight: 'accentHeight',\n    'accent-height': 'accentHeight',\n    accumulate: 'accumulate',\n    additive: 'additive',\n    alignmentbaseline: 'alignmentBaseline',\n    'alignment-baseline': 'alignmentBaseline',\n    allowreorder: 'allowReorder',\n    alphabetic: 'alphabetic',\n    amplitude: 'amplitude',\n    arabicform: 'arabicForm',\n    'arabic-form': 'arabicForm',\n    ascent: 'ascent',\n    attributename: 'attributeName',\n    attributetype: 'attributeType',\n    autoreverse: 'autoReverse',\n    azimuth: 'azimuth',\n    basefrequency: 'baseFrequency',\n    baselineshift: 'baselineShift',\n    'baseline-shift': 'baselineShift',\n    baseprofile: 'baseProfile',\n    bbox: 'bbox',\n    begin: 'begin',\n    bias: 'bias',\n    by: 'by',\n    calcmode: 'calcMode',\n    capheight: 'capHeight',\n    'cap-height': 'capHeight',\n    clip: 'clip',\n    clippath: 'clipPath',\n    'clip-path': 'clipPath',\n    clippathunits: 'clipPathUnits',\n    cliprule: 'clipRule',\n    'clip-rule': 'clipRule',\n    color: 'color',\n    colorinterpolation: 'colorInterpolation',\n    'color-interpolation': 'colorInterpolation',\n    colorinterpolationfilters: 'colorInterpolationFilters',\n    'color-interpolation-filters': 'colorInterpolationFilters',\n    colorprofile: 'colorProfile',\n    'color-profile': 'colorProfile',\n    colorrendering: 'colorRendering',\n    'color-rendering': 'colorRendering',\n    contentscripttype: 'contentScriptType',\n    contentstyletype: 'contentStyleType',\n    cursor: 'cursor',\n    cx: 'cx',\n    cy: 'cy',\n    d: 'd',\n    datatype: 'datatype',\n    decelerate: 'decelerate',\n    descent: 'descent',\n    diffuseconstant: 'diffuseConstant',\n    direction: 'direction',\n    display: 'display',\n    divisor: 'divisor',\n    dominantbaseline: 'dominantBaseline',\n    'dominant-baseline': 'dominantBaseline',\n    dur: 'dur',\n    dx: 'dx',\n    dy: 'dy',\n    edgemode: 'edgeMode',\n    elevation: 'elevation',\n    enablebackground: 'enableBackground',\n    'enable-background': 'enableBackground',\n    end: 'end',\n    exponent: 'exponent',\n    externalresourcesrequired: 'externalResourcesRequired',\n    fill: 'fill',\n    fillopacity: 'fillOpacity',\n    'fill-opacity': 'fillOpacity',\n    fillrule: 'fillRule',\n    'fill-rule': 'fillRule',\n    filter: 'filter',\n    filterres: 'filterRes',\n    filterunits: 'filterUnits',\n    floodopacity: 'floodOpacity',\n    'flood-opacity': 'floodOpacity',\n    floodcolor: 'floodColor',\n    'flood-color': 'floodColor',\n    focusable: 'focusable',\n    fontfamily: 'fontFamily',\n    'font-family': 'fontFamily',\n    fontsize: 'fontSize',\n    'font-size': 'fontSize',\n    fontsizeadjust: 'fontSizeAdjust',\n    'font-size-adjust': 'fontSizeAdjust',\n    fontstretch: 'fontStretch',\n    'font-stretch': 'fontStretch',\n    fontstyle: 'fontStyle',\n    'font-style': 'fontStyle',\n    fontvariant: 'fontVariant',\n    'font-variant': 'fontVariant',\n    fontweight: 'fontWeight',\n    'font-weight': 'fontWeight',\n    format: 'format',\n    from: 'from',\n    fx: 'fx',\n    fy: 'fy',\n    g1: 'g1',\n    g2: 'g2',\n    glyphname: 'glyphName',\n    'glyph-name': 'glyphName',\n    glyphorientationhorizontal: 'glyphOrientationHorizontal',\n    'glyph-orientation-horizontal': 'glyphOrientationHorizontal',\n    glyphorientationvertical: 'glyphOrientationVertical',\n    'glyph-orientation-vertical': 'glyphOrientationVertical',\n    glyphref: 'glyphRef',\n    gradienttransform: 'gradientTransform',\n    gradientunits: 'gradientUnits',\n    hanging: 'hanging',\n    horizadvx: 'horizAdvX',\n    'horiz-adv-x': 'horizAdvX',\n    horizoriginx: 'horizOriginX',\n    'horiz-origin-x': 'horizOriginX',\n    ideographic: 'ideographic',\n    imagerendering: 'imageRendering',\n    'image-rendering': 'imageRendering',\n    in2: 'in2',\n    in: 'in',\n    inlist: 'inlist',\n    intercept: 'intercept',\n    k1: 'k1',\n    k2: 'k2',\n    k3: 'k3',\n    k4: 'k4',\n    k: 'k',\n    kernelmatrix: 'kernelMatrix',\n    kernelunitlength: 'kernelUnitLength',\n    kerning: 'kerning',\n    keypoints: 'keyPoints',\n    keysplines: 'keySplines',\n    keytimes: 'keyTimes',\n    lengthadjust: 'lengthAdjust',\n    letterspacing: 'letterSpacing',\n    'letter-spacing': 'letterSpacing',\n    lightingcolor: 'lightingColor',\n    'lighting-color': 'lightingColor',\n    limitingconeangle: 'limitingConeAngle',\n    local: 'local',\n    markerend: 'markerEnd',\n    'marker-end': 'markerEnd',\n    markerheight: 'markerHeight',\n    markermid: 'markerMid',\n    'marker-mid': 'markerMid',\n    markerstart: 'markerStart',\n    'marker-start': 'markerStart',\n    markerunits: 'markerUnits',\n    markerwidth: 'markerWidth',\n    mask: 'mask',\n    maskcontentunits: 'maskContentUnits',\n    maskunits: 'maskUnits',\n    mathematical: 'mathematical',\n    mode: 'mode',\n    numoctaves: 'numOctaves',\n    offset: 'offset',\n    opacity: 'opacity',\n    operator: 'operator',\n    order: 'order',\n    orient: 'orient',\n    orientation: 'orientation',\n    origin: 'origin',\n    overflow: 'overflow',\n    overlineposition: 'overlinePosition',\n    'overline-position': 'overlinePosition',\n    overlinethickness: 'overlineThickness',\n    'overline-thickness': 'overlineThickness',\n    paintorder: 'paintOrder',\n    'paint-order': 'paintOrder',\n    panose1: 'panose1',\n    'panose-1': 'panose1',\n    pathlength: 'pathLength',\n    patterncontentunits: 'patternContentUnits',\n    patterntransform: 'patternTransform',\n    patternunits: 'patternUnits',\n    pointerevents: 'pointerEvents',\n    'pointer-events': 'pointerEvents',\n    points: 'points',\n    pointsatx: 'pointsAtX',\n    pointsaty: 'pointsAtY',\n    pointsatz: 'pointsAtZ',\n    prefix: 'prefix',\n    preservealpha: 'preserveAlpha',\n    preserveaspectratio: 'preserveAspectRatio',\n    primitiveunits: 'primitiveUnits',\n    property: 'property',\n    r: 'r',\n    radius: 'radius',\n    refx: 'refX',\n    refy: 'refY',\n    renderingintent: 'renderingIntent',\n    'rendering-intent': 'renderingIntent',\n    repeatcount: 'repeatCount',\n    repeatdur: 'repeatDur',\n    requiredextensions: 'requiredExtensions',\n    requiredfeatures: 'requiredFeatures',\n    resource: 'resource',\n    restart: 'restart',\n    result: 'result',\n    results: 'results',\n    rotate: 'rotate',\n    rx: 'rx',\n    ry: 'ry',\n    scale: 'scale',\n    security: 'security',\n    seed: 'seed',\n    shaperendering: 'shapeRendering',\n    'shape-rendering': 'shapeRendering',\n    slope: 'slope',\n    spacing: 'spacing',\n    specularconstant: 'specularConstant',\n    specularexponent: 'specularExponent',\n    speed: 'speed',\n    spreadmethod: 'spreadMethod',\n    startoffset: 'startOffset',\n    stddeviation: 'stdDeviation',\n    stemh: 'stemh',\n    stemv: 'stemv',\n    stitchtiles: 'stitchTiles',\n    stopcolor: 'stopColor',\n    'stop-color': 'stopColor',\n    stopopacity: 'stopOpacity',\n    'stop-opacity': 'stopOpacity',\n    strikethroughposition: 'strikethroughPosition',\n    'strikethrough-position': 'strikethroughPosition',\n    strikethroughthickness: 'strikethroughThickness',\n    'strikethrough-thickness': 'strikethroughThickness',\n    string: 'string',\n    stroke: 'stroke',\n    strokedasharray: 'strokeDasharray',\n    'stroke-dasharray': 'strokeDasharray',\n    strokedashoffset: 'strokeDashoffset',\n    'stroke-dashoffset': 'strokeDashoffset',\n    strokelinecap: 'strokeLinecap',\n    'stroke-linecap': 'strokeLinecap',\n    strokelinejoin: 'strokeLinejoin',\n    'stroke-linejoin': 'strokeLinejoin',\n    strokemiterlimit: 'strokeMiterlimit',\n    'stroke-miterlimit': 'strokeMiterlimit',\n    strokewidth: 'strokeWidth',\n    'stroke-width': 'strokeWidth',\n    strokeopacity: 'strokeOpacity',\n    'stroke-opacity': 'strokeOpacity',\n    suppresscontenteditablewarning: 'suppressContentEditableWarning',\n    suppresshydrationwarning: 'suppressHydrationWarning',\n    surfacescale: 'surfaceScale',\n    systemlanguage: 'systemLanguage',\n    tablevalues: 'tableValues',\n    targetx: 'targetX',\n    targety: 'targetY',\n    textanchor: 'textAnchor',\n    'text-anchor': 'textAnchor',\n    textdecoration: 'textDecoration',\n    'text-decoration': 'textDecoration',\n    textlength: 'textLength',\n    textrendering: 'textRendering',\n    'text-rendering': 'textRendering',\n    to: 'to',\n    transform: 'transform',\n    typeof: 'typeof',\n    u1: 'u1',\n    u2: 'u2',\n    underlineposition: 'underlinePosition',\n    'underline-position': 'underlinePosition',\n    underlinethickness: 'underlineThickness',\n    'underline-thickness': 'underlineThickness',\n    unicode: 'unicode',\n    unicodebidi: 'unicodeBidi',\n    'unicode-bidi': 'unicodeBidi',\n    unicoderange: 'unicodeRange',\n    'unicode-range': 'unicodeRange',\n    unitsperem: 'unitsPerEm',\n    'units-per-em': 'unitsPerEm',\n    unselectable: 'unselectable',\n    valphabetic: 'vAlphabetic',\n    'v-alphabetic': 'vAlphabetic',\n    values: 'values',\n    vectoreffect: 'vectorEffect',\n    'vector-effect': 'vectorEffect',\n    version: 'version',\n    vertadvy: 'vertAdvY',\n    'vert-adv-y': 'vertAdvY',\n    vertoriginx: 'vertOriginX',\n    'vert-origin-x': 'vertOriginX',\n    vertoriginy: 'vertOriginY',\n    'vert-origin-y': 'vertOriginY',\n    vhanging: 'vHanging',\n    'v-hanging': 'vHanging',\n    videographic: 'vIdeographic',\n    'v-ideographic': 'vIdeographic',\n    viewbox: 'viewBox',\n    viewtarget: 'viewTarget',\n    visibility: 'visibility',\n    vmathematical: 'vMathematical',\n    'v-mathematical': 'vMathematical',\n    vocab: 'vocab',\n    widths: 'widths',\n    wordspacing: 'wordSpacing',\n    'word-spacing': 'wordSpacing',\n    writingmode: 'writingMode',\n    'writing-mode': 'writingMode',\n    x1: 'x1',\n    x2: 'x2',\n    x: 'x',\n    xchannelselector: 'xChannelSelector',\n    xheight: 'xHeight',\n    'x-height': 'xHeight',\n    xlinkactuate: 'xlinkActuate',\n    'xlink:actuate': 'xlinkActuate',\n    xlinkarcrole: 'xlinkArcrole',\n    'xlink:arcrole': 'xlinkArcrole',\n    xlinkhref: 'xlinkHref',\n    'xlink:href': 'xlinkHref',\n    xlinkrole: 'xlinkRole',\n    'xlink:role': 'xlinkRole',\n    xlinkshow: 'xlinkShow',\n    'xlink:show': 'xlinkShow',\n    xlinktitle: 'xlinkTitle',\n    'xlink:title': 'xlinkTitle',\n    xlinktype: 'xlinkType',\n    'xlink:type': 'xlinkType',\n    xmlbase: 'xmlBase',\n    'xml:base': 'xmlBase',\n    xmllang: 'xmlLang',\n    'xml:lang': 'xmlLang',\n    xmlns: 'xmlns',\n    'xml:space': 'xmlSpace',\n    xmlnsxlink: 'xmlnsXlink',\n    'xmlns:xlink': 'xmlnsXlink',\n    xmlspace: 'xmlSpace',\n    y1: 'y1',\n    y2: 'y2',\n    y: 'y',\n    ychannelselector: 'yChannelSelector',\n    z: 'z',\n    zoomandpan: 'zoomAndPan'\n  };\n\n  var ariaProperties = {\n    'aria-current': 0,\n    // state\n    'aria-description': 0,\n    'aria-details': 0,\n    'aria-disabled': 0,\n    // state\n    'aria-hidden': 0,\n    // state\n    'aria-invalid': 0,\n    // state\n    'aria-keyshortcuts': 0,\n    'aria-label': 0,\n    'aria-roledescription': 0,\n    // Widget Attributes\n    'aria-autocomplete': 0,\n    'aria-checked': 0,\n    'aria-expanded': 0,\n    'aria-haspopup': 0,\n    'aria-level': 0,\n    'aria-modal': 0,\n    'aria-multiline': 0,\n    'aria-multiselectable': 0,\n    'aria-orientation': 0,\n    'aria-placeholder': 0,\n    'aria-pressed': 0,\n    'aria-readonly': 0,\n    'aria-required': 0,\n    'aria-selected': 0,\n    'aria-sort': 0,\n    'aria-valuemax': 0,\n    'aria-valuemin': 0,\n    'aria-valuenow': 0,\n    'aria-valuetext': 0,\n    // Live Region Attributes\n    'aria-atomic': 0,\n    'aria-busy': 0,\n    'aria-live': 0,\n    'aria-relevant': 0,\n    // Drag-and-Drop Attributes\n    'aria-dropeffect': 0,\n    'aria-grabbed': 0,\n    // Relationship Attributes\n    'aria-activedescendant': 0,\n    'aria-colcount': 0,\n    'aria-colindex': 0,\n    'aria-colspan': 0,\n    'aria-controls': 0,\n    'aria-describedby': 0,\n    'aria-errormessage': 0,\n    'aria-flowto': 0,\n    'aria-labelledby': 0,\n    'aria-owns': 0,\n    'aria-posinset': 0,\n    'aria-rowcount': 0,\n    'aria-rowindex': 0,\n    'aria-rowspan': 0,\n    'aria-setsize': 0\n  };\n\n  var warnedProperties = {};\n  var rARIA = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$');\n  var rARIACamel = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$');\n\n  function validateProperty(tagName, name) {\n    {\n      if (hasOwnProperty.call(warnedProperties, name) && warnedProperties[name]) {\n        return true;\n      }\n\n      if (rARIACamel.test(name)) {\n        var ariaName = 'aria-' + name.slice(4).toLowerCase();\n        var correctName = ariaProperties.hasOwnProperty(ariaName) ? ariaName : null; // If this is an aria-* attribute, but is not listed in the known DOM\n        // DOM properties, then it is an invalid aria-* attribute.\n\n        if (correctName == null) {\n          error('Invalid ARIA attribute `%s`. ARIA attributes follow the pattern aria-* and must be lowercase.', name);\n\n          warnedProperties[name] = true;\n          return true;\n        } // aria-* attributes should be lowercase; suggest the lowercase version.\n\n\n        if (name !== correctName) {\n          error('Invalid ARIA attribute `%s`. Did you mean `%s`?', name, correctName);\n\n          warnedProperties[name] = true;\n          return true;\n        }\n      }\n\n      if (rARIA.test(name)) {\n        var lowerCasedName = name.toLowerCase();\n        var standardName = ariaProperties.hasOwnProperty(lowerCasedName) ? lowerCasedName : null; // If this is an aria-* attribute, but is not listed in the known DOM\n        // DOM properties, then it is an invalid aria-* attribute.\n\n        if (standardName == null) {\n          warnedProperties[name] = true;\n          return false;\n        } // aria-* attributes should be lowercase; suggest the lowercase version.\n\n\n        if (name !== standardName) {\n          error('Unknown ARIA attribute `%s`. Did you mean `%s`?', name, standardName);\n\n          warnedProperties[name] = true;\n          return true;\n        }\n      }\n    }\n\n    return true;\n  }\n\n  function warnInvalidARIAProps(type, props) {\n    {\n      var invalidProps = [];\n\n      for (var key in props) {\n        var isValid = validateProperty(type, key);\n\n        if (!isValid) {\n          invalidProps.push(key);\n        }\n      }\n\n      var unknownPropString = invalidProps.map(function (prop) {\n        return '`' + prop + '`';\n      }).join(', ');\n\n      if (invalidProps.length === 1) {\n        error('Invalid aria prop %s on <%s> tag. ' + 'For details, see https://reactjs.org/link/invalid-aria-props', unknownPropString, type);\n      } else if (invalidProps.length > 1) {\n        error('Invalid aria props %s on <%s> tag. ' + 'For details, see https://reactjs.org/link/invalid-aria-props', unknownPropString, type);\n      }\n    }\n  }\n\n  function validateProperties(type, props) {\n    if (isCustomComponent(type, props)) {\n      return;\n    }\n\n    warnInvalidARIAProps(type, props);\n  }\n\n  var didWarnValueNull = false;\n  function validateProperties$1(type, props) {\n    {\n      if (type !== 'input' && type !== 'textarea' && type !== 'select') {\n        return;\n      }\n\n      if (props != null && props.value === null && !didWarnValueNull) {\n        didWarnValueNull = true;\n\n        if (type === 'select' && props.multiple) {\n          error('`value` prop on `%s` should not be null. ' + 'Consider using an empty array when `multiple` is set to `true` ' + 'to clear the component or `undefined` for uncontrolled components.', type);\n        } else {\n          error('`value` prop on `%s` should not be null. ' + 'Consider using an empty string to clear the component or `undefined` ' + 'for uncontrolled components.', type);\n        }\n      }\n    }\n  }\n\n  var validateProperty$1 = function () {};\n\n  {\n    var warnedProperties$1 = {};\n    var EVENT_NAME_REGEX = /^on./;\n    var INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/;\n    var rARIA$1 = new RegExp('^(aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$');\n    var rARIACamel$1 = new RegExp('^(aria)[A-Z][' + ATTRIBUTE_NAME_CHAR + ']*$');\n\n    validateProperty$1 = function (tagName, name, value, eventRegistry) {\n      if (hasOwnProperty.call(warnedProperties$1, name) && warnedProperties$1[name]) {\n        return true;\n      }\n\n      var lowerCasedName = name.toLowerCase();\n\n      if (lowerCasedName === 'onfocusin' || lowerCasedName === 'onfocusout') {\n        error('React uses onFocus and onBlur instead of onFocusIn and onFocusOut. ' + 'All React events are normalized to bubble, so onFocusIn and onFocusOut ' + 'are not needed/supported by React.');\n\n        warnedProperties$1[name] = true;\n        return true;\n      } // We can't rely on the event system being injected on the server.\n\n\n      if (eventRegistry != null) {\n        var registrationNameDependencies = eventRegistry.registrationNameDependencies,\n            possibleRegistrationNames = eventRegistry.possibleRegistrationNames;\n\n        if (registrationNameDependencies.hasOwnProperty(name)) {\n          return true;\n        }\n\n        var registrationName = possibleRegistrationNames.hasOwnProperty(lowerCasedName) ? possibleRegistrationNames[lowerCasedName] : null;\n\n        if (registrationName != null) {\n          error('Invalid event handler property `%s`. Did you mean `%s`?', name, registrationName);\n\n          warnedProperties$1[name] = true;\n          return true;\n        }\n\n        if (EVENT_NAME_REGEX.test(name)) {\n          error('Unknown event handler property `%s`. It will be ignored.', name);\n\n          warnedProperties$1[name] = true;\n          return true;\n        }\n      } else if (EVENT_NAME_REGEX.test(name)) {\n        // If no event plugins have been injected, we are in a server environment.\n        // So we can't tell if the event name is correct for sure, but we can filter\n        // out known bad ones like `onclick`. We can't suggest a specific replacement though.\n        if (INVALID_EVENT_NAME_REGEX.test(name)) {\n          error('Invalid event handler property `%s`. ' + 'React events use the camelCase naming convention, for example `onClick`.', name);\n        }\n\n        warnedProperties$1[name] = true;\n        return true;\n      } // Let the ARIA attribute hook validate ARIA attributes\n\n\n      if (rARIA$1.test(name) || rARIACamel$1.test(name)) {\n        return true;\n      }\n\n      if (lowerCasedName === 'innerhtml') {\n        error('Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.');\n\n        warnedProperties$1[name] = true;\n        return true;\n      }\n\n      if (lowerCasedName === 'aria') {\n        error('The `aria` attribute is reserved for future use in React. ' + 'Pass individual `aria-` attributes instead.');\n\n        warnedProperties$1[name] = true;\n        return true;\n      }\n\n      if (lowerCasedName === 'is' && value !== null && value !== undefined && typeof value !== 'string') {\n        error('Received a `%s` for a string attribute `is`. If this is expected, cast ' + 'the value to a string.', typeof value);\n\n        warnedProperties$1[name] = true;\n        return true;\n      }\n\n      if (typeof value === 'number' && isNaN(value)) {\n        error('Received NaN for the `%s` attribute. If this is expected, cast ' + 'the value to a string.', name);\n\n        warnedProperties$1[name] = true;\n        return true;\n      }\n\n      var propertyInfo = getPropertyInfo(name);\n      var isReserved = propertyInfo !== null && propertyInfo.type === RESERVED; // Known attributes should match the casing specified in the property config.\n\n      if (possibleStandardNames.hasOwnProperty(lowerCasedName)) {\n        var standardName = possibleStandardNames[lowerCasedName];\n\n        if (standardName !== name) {\n          error('Invalid DOM property `%s`. Did you mean `%s`?', name, standardName);\n\n          warnedProperties$1[name] = true;\n          return true;\n        }\n      } else if (!isReserved && name !== lowerCasedName) {\n        // Unknown attributes should have lowercase casing since that's how they\n        // will be cased anyway with server rendering.\n        error('React does not recognize the `%s` prop on a DOM element. If you ' + 'intentionally want it to appear in the DOM as a custom ' + 'attribute, spell it as lowercase `%s` instead. ' + 'If you accidentally passed it from a parent component, remove ' + 'it from the DOM element.', name, lowerCasedName);\n\n        warnedProperties$1[name] = true;\n        return true;\n      }\n\n      if (typeof value === 'boolean' && shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) {\n        if (value) {\n          error('Received `%s` for a non-boolean attribute `%s`.\\n\\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s=\"%s\" or %s={value.toString()}.', value, name, name, value, name);\n        } else {\n          error('Received `%s` for a non-boolean attribute `%s`.\\n\\n' + 'If you want to write it to the DOM, pass a string instead: ' + '%s=\"%s\" or %s={value.toString()}.\\n\\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.', value, name, name, value, name, name, name);\n        }\n\n        warnedProperties$1[name] = true;\n        return true;\n      } // Now that we've validated casing, do not validate\n      // data types for reserved props\n\n\n      if (isReserved) {\n        return true;\n      } // Warn when a known attribute is a bad type\n\n\n      if (shouldRemoveAttributeWithWarning(name, value, propertyInfo, false)) {\n        warnedProperties$1[name] = true;\n        return false;\n      } // Warn when passing the strings 'false' or 'true' into a boolean prop\n\n\n      if ((value === 'false' || value === 'true') && propertyInfo !== null && propertyInfo.type === BOOLEAN) {\n        error('Received the string `%s` for the boolean attribute `%s`. ' + '%s ' + 'Did you mean %s={%s}?', value, name, value === 'false' ? 'The browser will interpret it as a truthy value.' : 'Although this works, it will not work as expected if you pass the string \"false\".', name, value);\n\n        warnedProperties$1[name] = true;\n        return true;\n      }\n\n      return true;\n    };\n  }\n\n  var warnUnknownProperties = function (type, props, eventRegistry) {\n    {\n      var unknownProps = [];\n\n      for (var key in props) {\n        var isValid = validateProperty$1(type, key, props[key], eventRegistry);\n\n        if (!isValid) {\n          unknownProps.push(key);\n        }\n      }\n\n      var unknownPropString = unknownProps.map(function (prop) {\n        return '`' + prop + '`';\n      }).join(', ');\n\n      if (unknownProps.length === 1) {\n        error('Invalid value for prop %s on <%s> tag. Either remove it from the element, ' + 'or pass a string or number value to keep it in the DOM. ' + 'For details, see https://reactjs.org/link/attribute-behavior ', unknownPropString, type);\n      } else if (unknownProps.length > 1) {\n        error('Invalid values for props %s on <%s> tag. Either remove them from the element, ' + 'or pass a string or number value to keep them in the DOM. ' + 'For details, see https://reactjs.org/link/attribute-behavior ', unknownPropString, type);\n      }\n    }\n  };\n\n  function validateProperties$2(type, props, eventRegistry) {\n    if (isCustomComponent(type, props)) {\n      return;\n    }\n\n    warnUnknownProperties(type, props, eventRegistry);\n  }\n\n  var IS_EVENT_HANDLE_NON_MANAGED_NODE = 1;\n  var IS_NON_DELEGATED = 1 << 1;\n  var IS_CAPTURE_PHASE = 1 << 2;\n  // set to LEGACY_FB_SUPPORT. LEGACY_FB_SUPPORT only gets set when\n  // we call willDeferLaterForLegacyFBSupport, thus not bailing out\n  // will result in endless cycles like an infinite loop.\n  // We also don't want to defer during event replaying.\n\n  var SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS = IS_EVENT_HANDLE_NON_MANAGED_NODE | IS_NON_DELEGATED | IS_CAPTURE_PHASE;\n\n  // This exists to avoid circular dependency between ReactDOMEventReplaying\n  // and DOMPluginEventSystem.\n  var currentReplayingEvent = null;\n  function setReplayingEvent(event) {\n    {\n      if (currentReplayingEvent !== null) {\n        error('Expected currently replaying event to be null. This error ' + 'is likely caused by a bug in React. Please file an issue.');\n      }\n    }\n\n    currentReplayingEvent = event;\n  }\n  function resetReplayingEvent() {\n    {\n      if (currentReplayingEvent === null) {\n        error('Expected currently replaying event to not be null. This error ' + 'is likely caused by a bug in React. Please file an issue.');\n      }\n    }\n\n    currentReplayingEvent = null;\n  }\n  function isReplayingEvent(event) {\n    return event === currentReplayingEvent;\n  }\n\n  /**\n   * Gets the target node from a native browser event by accounting for\n   * inconsistencies in browser DOM APIs.\n   *\n   * @param {object} nativeEvent Native browser event.\n   * @return {DOMEventTarget} Target node.\n   */\n\n  function getEventTarget(nativeEvent) {\n    // Fallback to nativeEvent.srcElement for IE9\n    // https://github.com/facebook/react/issues/12506\n    var target = nativeEvent.target || nativeEvent.srcElement || window; // Normalize SVG <use> element events #4963\n\n    if (target.correspondingUseElement) {\n      target = target.correspondingUseElement;\n    } // Safari may fire events on text nodes (Node.TEXT_NODE is 3).\n    // @see http://www.quirksmode.org/js/events_properties.html\n\n\n    return target.nodeType === TEXT_NODE ? target.parentNode : target;\n  }\n\n  var restoreImpl = null;\n  var restoreTarget = null;\n  var restoreQueue = null;\n\n  function restoreStateOfTarget(target) {\n    // We perform this translation at the end of the event loop so that we\n    // always receive the correct fiber here\n    var internalInstance = getInstanceFromNode(target);\n\n    if (!internalInstance) {\n      // Unmounted\n      return;\n    }\n\n    if (typeof restoreImpl !== 'function') {\n      throw new Error('setRestoreImplementation() needs to be called to handle a target for controlled ' + 'events. This error is likely caused by a bug in React. Please file an issue.');\n    }\n\n    var stateNode = internalInstance.stateNode; // Guard against Fiber being unmounted.\n\n    if (stateNode) {\n      var _props = getFiberCurrentPropsFromNode(stateNode);\n\n      restoreImpl(internalInstance.stateNode, internalInstance.type, _props);\n    }\n  }\n\n  function setRestoreImplementation(impl) {\n    restoreImpl = impl;\n  }\n  function enqueueStateRestore(target) {\n    if (restoreTarget) {\n      if (restoreQueue) {\n        restoreQueue.push(target);\n      } else {\n        restoreQueue = [target];\n      }\n    } else {\n      restoreTarget = target;\n    }\n  }\n  function needsStateRestore() {\n    return restoreTarget !== null || restoreQueue !== null;\n  }\n  function restoreStateIfNeeded() {\n    if (!restoreTarget) {\n      return;\n    }\n\n    var target = restoreTarget;\n    var queuedTargets = restoreQueue;\n    restoreTarget = null;\n    restoreQueue = null;\n    restoreStateOfTarget(target);\n\n    if (queuedTargets) {\n      for (var i = 0; i < queuedTargets.length; i++) {\n        restoreStateOfTarget(queuedTargets[i]);\n      }\n    }\n  }\n\n  // the renderer. Such as when we're dispatching events or if third party\n  // libraries need to call batchedUpdates. Eventually, this API will go away when\n  // everything is batched by default. We'll then have a similar API to opt-out of\n  // scheduled work and instead do synchronous work.\n  // Defaults\n\n  var batchedUpdatesImpl = function (fn, bookkeeping) {\n    return fn(bookkeeping);\n  };\n\n  var flushSyncImpl = function () {};\n\n  var isInsideEventHandler = false;\n\n  function finishEventHandler() {\n    // Here we wait until all updates have propagated, which is important\n    // when using controlled components within layers:\n    // https://github.com/facebook/react/issues/1698\n    // Then we restore state of any controlled component.\n    var controlledComponentsHavePendingUpdates = needsStateRestore();\n\n    if (controlledComponentsHavePendingUpdates) {\n      // If a controlled event was fired, we may need to restore the state of\n      // the DOM node back to the controlled value. This is necessary when React\n      // bails out of the update without touching the DOM.\n      // TODO: Restore state in the microtask, after the discrete updates flush,\n      // instead of early flushing them here.\n      flushSyncImpl();\n      restoreStateIfNeeded();\n    }\n  }\n\n  function batchedUpdates(fn, a, b) {\n    if (isInsideEventHandler) {\n      // If we are currently inside another batch, we need to wait until it\n      // fully completes before restoring state.\n      return fn(a, b);\n    }\n\n    isInsideEventHandler = true;\n\n    try {\n      return batchedUpdatesImpl(fn, a, b);\n    } finally {\n      isInsideEventHandler = false;\n      finishEventHandler();\n    }\n  } // TODO: Replace with flushSync\n  function setBatchingImplementation(_batchedUpdatesImpl, _discreteUpdatesImpl, _flushSyncImpl) {\n    batchedUpdatesImpl = _batchedUpdatesImpl;\n    flushSyncImpl = _flushSyncImpl;\n  }\n\n  function isInteractive(tag) {\n    return tag === 'button' || tag === 'input' || tag === 'select' || tag === 'textarea';\n  }\n\n  function shouldPreventMouseEvent(name, type, props) {\n    switch (name) {\n      case 'onClick':\n      case 'onClickCapture':\n      case 'onDoubleClick':\n      case 'onDoubleClickCapture':\n      case 'onMouseDown':\n      case 'onMouseDownCapture':\n      case 'onMouseMove':\n      case 'onMouseMoveCapture':\n      case 'onMouseUp':\n      case 'onMouseUpCapture':\n      case 'onMouseEnter':\n        return !!(props.disabled && isInteractive(type));\n\n      default:\n        return false;\n    }\n  }\n  /**\n   * @param {object} inst The instance, which is the source of events.\n   * @param {string} registrationName Name of listener (e.g. `onClick`).\n   * @return {?function} The stored callback.\n   */\n\n\n  function getListener(inst, registrationName) {\n    var stateNode = inst.stateNode;\n\n    if (stateNode === null) {\n      // Work in progress (ex: onload events in incremental mode).\n      return null;\n    }\n\n    var props = getFiberCurrentPropsFromNode(stateNode);\n\n    if (props === null) {\n      // Work in progress.\n      return null;\n    }\n\n    var listener = props[registrationName];\n\n    if (shouldPreventMouseEvent(registrationName, inst.type, props)) {\n      return null;\n    }\n\n    if (listener && typeof listener !== 'function') {\n      throw new Error(\"Expected `\" + registrationName + \"` listener to be a function, instead got a value of `\" + typeof listener + \"` type.\");\n    }\n\n    return listener;\n  }\n\n  var passiveBrowserEventsSupported = false; // Check if browser support events with passive listeners\n  // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support\n\n  if (canUseDOM) {\n    try {\n      var options = {}; // $FlowFixMe: Ignore Flow complaining about needing a value\n\n      Object.defineProperty(options, 'passive', {\n        get: function () {\n          passiveBrowserEventsSupported = true;\n        }\n      });\n      window.addEventListener('test', options, options);\n      window.removeEventListener('test', options, options);\n    } catch (e) {\n      passiveBrowserEventsSupported = false;\n    }\n  }\n\n  function invokeGuardedCallbackProd(name, func, context, a, b, c, d, e, f) {\n    var funcArgs = Array.prototype.slice.call(arguments, 3);\n\n    try {\n      func.apply(context, funcArgs);\n    } catch (error) {\n      this.onError(error);\n    }\n  }\n\n  var invokeGuardedCallbackImpl = invokeGuardedCallbackProd;\n\n  {\n    // In DEV mode, we swap out invokeGuardedCallback for a special version\n    // that plays more nicely with the browser's DevTools. The idea is to preserve\n    // \"Pause on exceptions\" behavior. Because React wraps all user-provided\n    // functions in invokeGuardedCallback, and the production version of\n    // invokeGuardedCallback uses a try-catch, all user exceptions are treated\n    // like caught exceptions, and the DevTools won't pause unless the developer\n    // takes the extra step of enabling pause on caught exceptions. This is\n    // unintuitive, though, because even though React has caught the error, from\n    // the developer's perspective, the error is uncaught.\n    //\n    // To preserve the expected \"Pause on exceptions\" behavior, we don't use a\n    // try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake\n    // DOM node, and call the user-provided callback from inside an event handler\n    // for that fake event. If the callback throws, the error is \"captured\" using\n    // a global event handler. But because the error happens in a different\n    // event loop context, it does not interrupt the normal program flow.\n    // Effectively, this gives us try-catch behavior without actually using\n    // try-catch. Neat!\n    // Check that the browser supports the APIs we need to implement our special\n    // DEV version of invokeGuardedCallback\n    if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') {\n      var fakeNode = document.createElement('react');\n\n      invokeGuardedCallbackImpl = function invokeGuardedCallbackDev(name, func, context, a, b, c, d, e, f) {\n        // If document doesn't exist we know for sure we will crash in this method\n        // when we call document.createEvent(). However this can cause confusing\n        // errors: https://github.com/facebook/create-react-app/issues/3482\n        // So we preemptively throw with a better message instead.\n        if (typeof document === 'undefined' || document === null) {\n          throw new Error('The `document` global was defined when React was initialized, but is not ' + 'defined anymore. This can happen in a test environment if a component ' + 'schedules an update from an asynchronous callback, but the test has already ' + 'finished running. To solve this, you can either unmount the component at ' + 'the end of your test (and ensure that any asynchronous operations get ' + 'canceled in `componentWillUnmount`), or you can change the test itself ' + 'to be asynchronous.');\n        }\n\n        var evt = document.createEvent('Event');\n        var didCall = false; // Keeps track of whether the user-provided callback threw an error. We\n        // set this to true at the beginning, then set it to false right after\n        // calling the function. If the function errors, `didError` will never be\n        // set to false. This strategy works even if the browser is flaky and\n        // fails to call our global error handler, because it doesn't rely on\n        // the error event at all.\n\n        var didError = true; // Keeps track of the value of window.event so that we can reset it\n        // during the callback to let user code access window.event in the\n        // browsers that support it.\n\n        var windowEvent = window.event; // Keeps track of the descriptor of window.event to restore it after event\n        // dispatching: https://github.com/facebook/react/issues/13688\n\n        var windowEventDescriptor = Object.getOwnPropertyDescriptor(window, 'event');\n\n        function restoreAfterDispatch() {\n          // We immediately remove the callback from event listeners so that\n          // nested `invokeGuardedCallback` calls do not clash. Otherwise, a\n          // nested call would trigger the fake event handlers of any call higher\n          // in the stack.\n          fakeNode.removeEventListener(evtType, callCallback, false); // We check for window.hasOwnProperty('event') to prevent the\n          // window.event assignment in both IE <= 10 as they throw an error\n          // \"Member not found\" in strict mode, and in Firefox which does not\n          // support window.event.\n\n          if (typeof window.event !== 'undefined' && window.hasOwnProperty('event')) {\n            window.event = windowEvent;\n          }\n        } // Create an event handler for our fake event. We will synchronously\n        // dispatch our fake event using `dispatchEvent`. Inside the handler, we\n        // call the user-provided callback.\n\n\n        var funcArgs = Array.prototype.slice.call(arguments, 3);\n\n        function callCallback() {\n          didCall = true;\n          restoreAfterDispatch();\n          func.apply(context, funcArgs);\n          didError = false;\n        } // Create a global error event handler. We use this to capture the value\n        // that was thrown. It's possible that this error handler will fire more\n        // than once; for example, if non-React code also calls `dispatchEvent`\n        // and a handler for that event throws. We should be resilient to most of\n        // those cases. Even if our error event handler fires more than once, the\n        // last error event is always used. If the callback actually does error,\n        // we know that the last error event is the correct one, because it's not\n        // possible for anything else to have happened in between our callback\n        // erroring and the code that follows the `dispatchEvent` call below. If\n        // the callback doesn't error, but the error event was fired, we know to\n        // ignore it because `didError` will be false, as described above.\n\n\n        var error; // Use this to track whether the error event is ever called.\n\n        var didSetError = false;\n        var isCrossOriginError = false;\n\n        function handleWindowError(event) {\n          error = event.error;\n          didSetError = true;\n\n          if (error === null && event.colno === 0 && event.lineno === 0) {\n            isCrossOriginError = true;\n          }\n\n          if (event.defaultPrevented) {\n            // Some other error handler has prevented default.\n            // Browsers silence the error report if this happens.\n            // We'll remember this to later decide whether to log it or not.\n            if (error != null && typeof error === 'object') {\n              try {\n                error._suppressLogging = true;\n              } catch (inner) {// Ignore.\n              }\n            }\n          }\n        } // Create a fake event type.\n\n\n        var evtType = \"react-\" + (name ? name : 'invokeguardedcallback'); // Attach our event handlers\n\n        window.addEventListener('error', handleWindowError);\n        fakeNode.addEventListener(evtType, callCallback, false); // Synchronously dispatch our fake event. If the user-provided function\n        // errors, it will trigger our global error handler.\n\n        evt.initEvent(evtType, false, false);\n        fakeNode.dispatchEvent(evt);\n\n        if (windowEventDescriptor) {\n          Object.defineProperty(window, 'event', windowEventDescriptor);\n        }\n\n        if (didCall && didError) {\n          if (!didSetError) {\n            // The callback errored, but the error event never fired.\n            // eslint-disable-next-line react-internal/prod-error-codes\n            error = new Error('An error was thrown inside one of your components, but React ' + \"doesn't know what it was. This is likely due to browser \" + 'flakiness. React does its best to preserve the \"Pause on ' + 'exceptions\" behavior of the DevTools, which requires some ' + \"DEV-mode only tricks. It's possible that these don't work in \" + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.');\n          } else if (isCrossOriginError) {\n            // eslint-disable-next-line react-internal/prod-error-codes\n            error = new Error(\"A cross-origin error was thrown. React doesn't have access to \" + 'the actual error object in development. ' + 'See https://reactjs.org/link/crossorigin-error for more information.');\n          }\n\n          this.onError(error);\n        } // Remove our event listeners\n\n\n        window.removeEventListener('error', handleWindowError);\n\n        if (!didCall) {\n          // Something went really wrong, and our event was not dispatched.\n          // https://github.com/facebook/react/issues/16734\n          // https://github.com/facebook/react/issues/16585\n          // Fall back to the production implementation.\n          restoreAfterDispatch();\n          return invokeGuardedCallbackProd.apply(this, arguments);\n        }\n      };\n    }\n  }\n\n  var invokeGuardedCallbackImpl$1 = invokeGuardedCallbackImpl;\n\n  var hasError = false;\n  var caughtError = null; // Used by event system to capture/rethrow the first error.\n\n  var hasRethrowError = false;\n  var rethrowError = null;\n  var reporter = {\n    onError: function (error) {\n      hasError = true;\n      caughtError = error;\n    }\n  };\n  /**\n   * Call a function while guarding against errors that happens within it.\n   * Returns an error if it throws, otherwise null.\n   *\n   * In production, this is implemented using a try-catch. The reason we don't\n   * use a try-catch directly is so that we can swap out a different\n   * implementation in DEV mode.\n   *\n   * @param {String} name of the guard to use for logging or debugging\n   * @param {Function} func The function to invoke\n   * @param {*} context The context to use when calling the function\n   * @param {...*} args Arguments for function\n   */\n\n  function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) {\n    hasError = false;\n    caughtError = null;\n    invokeGuardedCallbackImpl$1.apply(reporter, arguments);\n  }\n  /**\n   * Same as invokeGuardedCallback, but instead of returning an error, it stores\n   * it in a global so it can be rethrown by `rethrowCaughtError` later.\n   * TODO: See if caughtError and rethrowError can be unified.\n   *\n   * @param {String} name of the guard to use for logging or debugging\n   * @param {Function} func The function to invoke\n   * @param {*} context The context to use when calling the function\n   * @param {...*} args Arguments for function\n   */\n\n  function invokeGuardedCallbackAndCatchFirstError(name, func, context, a, b, c, d, e, f) {\n    invokeGuardedCallback.apply(this, arguments);\n\n    if (hasError) {\n      var error = clearCaughtError();\n\n      if (!hasRethrowError) {\n        hasRethrowError = true;\n        rethrowError = error;\n      }\n    }\n  }\n  /**\n   * During execution of guarded functions we will capture the first error which\n   * we will rethrow to be handled by the top level error handler.\n   */\n\n  function rethrowCaughtError() {\n    if (hasRethrowError) {\n      var error = rethrowError;\n      hasRethrowError = false;\n      rethrowError = null;\n      throw error;\n    }\n  }\n  function hasCaughtError() {\n    return hasError;\n  }\n  function clearCaughtError() {\n    if (hasError) {\n      var error = caughtError;\n      hasError = false;\n      caughtError = null;\n      return error;\n    } else {\n      throw new Error('clearCaughtError was called but no error was captured. This error ' + 'is likely caused by a bug in React. Please file an issue.');\n    }\n  }\n\n  var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n  var _ReactInternals$Sched = ReactInternals.Scheduler,\n      unstable_cancelCallback = _ReactInternals$Sched.unstable_cancelCallback,\n      unstable_now = _ReactInternals$Sched.unstable_now,\n      unstable_scheduleCallback = _ReactInternals$Sched.unstable_scheduleCallback,\n      unstable_shouldYield = _ReactInternals$Sched.unstable_shouldYield,\n      unstable_requestPaint = _ReactInternals$Sched.unstable_requestPaint,\n      unstable_getFirstCallbackNode = _ReactInternals$Sched.unstable_getFirstCallbackNode,\n      unstable_runWithPriority = _ReactInternals$Sched.unstable_runWithPriority,\n      unstable_next = _ReactInternals$Sched.unstable_next,\n      unstable_continueExecution = _ReactInternals$Sched.unstable_continueExecution,\n      unstable_pauseExecution = _ReactInternals$Sched.unstable_pauseExecution,\n      unstable_getCurrentPriorityLevel = _ReactInternals$Sched.unstable_getCurrentPriorityLevel,\n      unstable_ImmediatePriority = _ReactInternals$Sched.unstable_ImmediatePriority,\n      unstable_UserBlockingPriority = _ReactInternals$Sched.unstable_UserBlockingPriority,\n      unstable_NormalPriority = _ReactInternals$Sched.unstable_NormalPriority,\n      unstable_LowPriority = _ReactInternals$Sched.unstable_LowPriority,\n      unstable_IdlePriority = _ReactInternals$Sched.unstable_IdlePriority,\n      unstable_forceFrameRate = _ReactInternals$Sched.unstable_forceFrameRate,\n      unstable_flushAllWithoutAsserting = _ReactInternals$Sched.unstable_flushAllWithoutAsserting,\n      unstable_yieldValue = _ReactInternals$Sched.unstable_yieldValue,\n      unstable_setDisableYieldValue = _ReactInternals$Sched.unstable_setDisableYieldValue;\n\n  /**\n   * `ReactInstanceMap` maintains a mapping from a public facing stateful\n   * instance (key) and the internal representation (value). This allows public\n   * methods to accept the user facing instance as an argument and map them back\n   * to internal methods.\n   *\n   * Note that this module is currently shared and assumed to be stateless.\n   * If this becomes an actual Map, that will break.\n   */\n  function get(key) {\n    return key._reactInternals;\n  }\n  function has(key) {\n    return key._reactInternals !== undefined;\n  }\n  function set(key, value) {\n    key._reactInternals = value;\n  }\n\n  // Don't change these two values. They're used by React Dev Tools.\n  var NoFlags =\n  /*                      */\n  0;\n  var PerformedWork =\n  /*                */\n  1; // You can change the rest (and add more).\n\n  var Placement =\n  /*                    */\n  2;\n  var Update =\n  /*                       */\n  4;\n  var ChildDeletion =\n  /*                */\n  16;\n  var ContentReset =\n  /*                 */\n  32;\n  var Callback =\n  /*                     */\n  64;\n  var DidCapture =\n  /*                   */\n  128;\n  var ForceClientRender =\n  /*            */\n  256;\n  var Ref =\n  /*                          */\n  512;\n  var Snapshot =\n  /*                     */\n  1024;\n  var Passive =\n  /*                      */\n  2048;\n  var Hydrating =\n  /*                    */\n  4096;\n  var Visibility =\n  /*                   */\n  8192;\n  var StoreConsistency =\n  /*             */\n  16384;\n  var LifecycleEffectMask = Passive | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit)\n\n  var HostEffectMask =\n  /*               */\n  32767; // These are not really side effects, but we still reuse this field.\n\n  var Incomplete =\n  /*                   */\n  32768;\n  var ShouldCapture =\n  /*                */\n  65536;\n  var ForceUpdateForLegacySuspense =\n  /* */\n  131072;\n  var Forked =\n  /*                       */\n  1048576; // Static tags describe aspects of a fiber that are not specific to a render,\n  // e.g. a fiber uses a passive effect (even if there are no updates on this particular render).\n  // This enables us to defer more work in the unmount case,\n  // since we can defer traversing the tree during layout to look for Passive effects,\n  // and instead rely on the static flag as a signal that there may be cleanup work.\n\n  var RefStatic =\n  /*                    */\n  2097152;\n  var LayoutStatic =\n  /*                 */\n  4194304;\n  var PassiveStatic =\n  /*                */\n  8388608; // These flags allow us to traverse to fibers that have effects on mount\n  // without traversing the entire tree after every commit for\n  // double invoking\n\n  var MountLayoutDev =\n  /*               */\n  16777216;\n  var MountPassiveDev =\n  /*              */\n  33554432; // Groups of flags that are used in the commit phase to skip over trees that\n  // don't contain effects, by checking subtreeFlags.\n\n  var BeforeMutationMask = // TODO: Remove Update flag from before mutation phase by re-landing Visibility\n  // flag logic (see #20043)\n  Update | Snapshot | ( 0);\n  var MutationMask = Placement | Update | ChildDeletion | ContentReset | Ref | Hydrating | Visibility;\n  var LayoutMask = Update | Callback | Ref | Visibility; // TODO: Split into PassiveMountMask and PassiveUnmountMask\n\n  var PassiveMask = Passive | ChildDeletion; // Union of tags that don't get reset on clones.\n  // This allows certain concepts to persist without recalculating them,\n  // e.g. whether a subtree contains passive effects or portals.\n\n  var StaticMask = LayoutStatic | PassiveStatic | RefStatic;\n\n  var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;\n  function getNearestMountedFiber(fiber) {\n    var node = fiber;\n    var nearestMounted = fiber;\n\n    if (!fiber.alternate) {\n      // If there is no alternate, this might be a new tree that isn't inserted\n      // yet. If it is, then it will have a pending insertion effect on it.\n      var nextNode = node;\n\n      do {\n        node = nextNode;\n\n        if ((node.flags & (Placement | Hydrating)) !== NoFlags) {\n          // This is an insertion or in-progress hydration. The nearest possible\n          // mounted fiber is the parent but we need to continue to figure out\n          // if that one is still mounted.\n          nearestMounted = node.return;\n        }\n\n        nextNode = node.return;\n      } while (nextNode);\n    } else {\n      while (node.return) {\n        node = node.return;\n      }\n    }\n\n    if (node.tag === HostRoot) {\n      // TODO: Check if this was a nested HostRoot when used with\n      // renderContainerIntoSubtree.\n      return nearestMounted;\n    } // If we didn't hit the root, that means that we're in an disconnected tree\n    // that has been unmounted.\n\n\n    return null;\n  }\n  function getSuspenseInstanceFromFiber(fiber) {\n    if (fiber.tag === SuspenseComponent) {\n      var suspenseState = fiber.memoizedState;\n\n      if (suspenseState === null) {\n        var current = fiber.alternate;\n\n        if (current !== null) {\n          suspenseState = current.memoizedState;\n        }\n      }\n\n      if (suspenseState !== null) {\n        return suspenseState.dehydrated;\n      }\n    }\n\n    return null;\n  }\n  function getContainerFromFiber(fiber) {\n    return fiber.tag === HostRoot ? fiber.stateNode.containerInfo : null;\n  }\n  function isFiberMounted(fiber) {\n    return getNearestMountedFiber(fiber) === fiber;\n  }\n  function isMounted(component) {\n    {\n      var owner = ReactCurrentOwner.current;\n\n      if (owner !== null && owner.tag === ClassComponent) {\n        var ownerFiber = owner;\n        var instance = ownerFiber.stateNode;\n\n        if (!instance._warnedAboutRefsInRender) {\n          error('%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentNameFromFiber(ownerFiber) || 'A component');\n        }\n\n        instance._warnedAboutRefsInRender = true;\n      }\n    }\n\n    var fiber = get(component);\n\n    if (!fiber) {\n      return false;\n    }\n\n    return getNearestMountedFiber(fiber) === fiber;\n  }\n\n  function assertIsMounted(fiber) {\n    if (getNearestMountedFiber(fiber) !== fiber) {\n      throw new Error('Unable to find node on an unmounted component.');\n    }\n  }\n\n  function findCurrentFiberUsingSlowPath(fiber) {\n    var alternate = fiber.alternate;\n\n    if (!alternate) {\n      // If there is no alternate, then we only need to check if it is mounted.\n      var nearestMounted = getNearestMountedFiber(fiber);\n\n      if (nearestMounted === null) {\n        throw new Error('Unable to find node on an unmounted component.');\n      }\n\n      if (nearestMounted !== fiber) {\n        return null;\n      }\n\n      return fiber;\n    } // If we have two possible branches, we'll walk backwards up to the root\n    // to see what path the root points to. On the way we may hit one of the\n    // special cases and we'll deal with them.\n\n\n    var a = fiber;\n    var b = alternate;\n\n    while (true) {\n      var parentA = a.return;\n\n      if (parentA === null) {\n        // We're at the root.\n        break;\n      }\n\n      var parentB = parentA.alternate;\n\n      if (parentB === null) {\n        // There is no alternate. This is an unusual case. Currently, it only\n        // happens when a Suspense component is hidden. An extra fragment fiber\n        // is inserted in between the Suspense fiber and its children. Skip\n        // over this extra fragment fiber and proceed to the next parent.\n        var nextParent = parentA.return;\n\n        if (nextParent !== null) {\n          a = b = nextParent;\n          continue;\n        } // If there's no parent, we're at the root.\n\n\n        break;\n      } // If both copies of the parent fiber point to the same child, we can\n      // assume that the child is current. This happens when we bailout on low\n      // priority: the bailed out fiber's child reuses the current child.\n\n\n      if (parentA.child === parentB.child) {\n        var child = parentA.child;\n\n        while (child) {\n          if (child === a) {\n            // We've determined that A is the current branch.\n            assertIsMounted(parentA);\n            return fiber;\n          }\n\n          if (child === b) {\n            // We've determined that B is the current branch.\n            assertIsMounted(parentA);\n            return alternate;\n          }\n\n          child = child.sibling;\n        } // We should never have an alternate for any mounting node. So the only\n        // way this could possibly happen is if this was unmounted, if at all.\n\n\n        throw new Error('Unable to find node on an unmounted component.');\n      }\n\n      if (a.return !== b.return) {\n        // The return pointer of A and the return pointer of B point to different\n        // fibers. We assume that return pointers never criss-cross, so A must\n        // belong to the child set of A.return, and B must belong to the child\n        // set of B.return.\n        a = parentA;\n        b = parentB;\n      } else {\n        // The return pointers point to the same fiber. We'll have to use the\n        // default, slow path: scan the child sets of each parent alternate to see\n        // which child belongs to which set.\n        //\n        // Search parent A's child set\n        var didFindChild = false;\n        var _child = parentA.child;\n\n        while (_child) {\n          if (_child === a) {\n            didFindChild = true;\n            a = parentA;\n            b = parentB;\n            break;\n          }\n\n          if (_child === b) {\n            didFindChild = true;\n            b = parentA;\n            a = parentB;\n            break;\n          }\n\n          _child = _child.sibling;\n        }\n\n        if (!didFindChild) {\n          // Search parent B's child set\n          _child = parentB.child;\n\n          while (_child) {\n            if (_child === a) {\n              didFindChild = true;\n              a = parentB;\n              b = parentA;\n              break;\n            }\n\n            if (_child === b) {\n              didFindChild = true;\n              b = parentB;\n              a = parentA;\n              break;\n            }\n\n            _child = _child.sibling;\n          }\n\n          if (!didFindChild) {\n            throw new Error('Child was not found in either parent set. This indicates a bug ' + 'in React related to the return pointer. Please file an issue.');\n          }\n        }\n      }\n\n      if (a.alternate !== b) {\n        throw new Error(\"Return fibers should always be each others' alternates. \" + 'This error is likely caused by a bug in React. Please file an issue.');\n      }\n    } // If the root is not a host container, we're in a disconnected tree. I.e.\n    // unmounted.\n\n\n    if (a.tag !== HostRoot) {\n      throw new Error('Unable to find node on an unmounted component.');\n    }\n\n    if (a.stateNode.current === a) {\n      // We've determined that A is the current branch.\n      return fiber;\n    } // Otherwise B has to be current branch.\n\n\n    return alternate;\n  }\n  function findCurrentHostFiber(parent) {\n    var currentParent = findCurrentFiberUsingSlowPath(parent);\n    return currentParent !== null ? findCurrentHostFiberImpl(currentParent) : null;\n  }\n\n  function findCurrentHostFiberImpl(node) {\n    // Next we'll drill down this component to find the first HostComponent/Text.\n    if (node.tag === HostComponent || node.tag === HostText) {\n      return node;\n    }\n\n    var child = node.child;\n\n    while (child !== null) {\n      var match = findCurrentHostFiberImpl(child);\n\n      if (match !== null) {\n        return match;\n      }\n\n      child = child.sibling;\n    }\n\n    return null;\n  }\n\n  function findCurrentHostFiberWithNoPortals(parent) {\n    var currentParent = findCurrentFiberUsingSlowPath(parent);\n    return currentParent !== null ? findCurrentHostFiberWithNoPortalsImpl(currentParent) : null;\n  }\n\n  function findCurrentHostFiberWithNoPortalsImpl(node) {\n    // Next we'll drill down this component to find the first HostComponent/Text.\n    if (node.tag === HostComponent || node.tag === HostText) {\n      return node;\n    }\n\n    var child = node.child;\n\n    while (child !== null) {\n      if (child.tag !== HostPortal) {\n        var match = findCurrentHostFiberWithNoPortalsImpl(child);\n\n        if (match !== null) {\n          return match;\n        }\n      }\n\n      child = child.sibling;\n    }\n\n    return null;\n  }\n\n  // This module only exists as an ESM wrapper around the external CommonJS\n  var scheduleCallback = unstable_scheduleCallback;\n  var cancelCallback = unstable_cancelCallback;\n  var shouldYield = unstable_shouldYield;\n  var requestPaint = unstable_requestPaint;\n  var now = unstable_now;\n  var getCurrentPriorityLevel = unstable_getCurrentPriorityLevel;\n  var ImmediatePriority = unstable_ImmediatePriority;\n  var UserBlockingPriority = unstable_UserBlockingPriority;\n  var NormalPriority = unstable_NormalPriority;\n  var LowPriority = unstable_LowPriority;\n  var IdlePriority = unstable_IdlePriority;\n  // this doesn't actually exist on the scheduler, but it *does*\n  // on scheduler/unstable_mock, which we'll need for internal testing\n  var unstable_yieldValue$1 = unstable_yieldValue;\n  var unstable_setDisableYieldValue$1 = unstable_setDisableYieldValue;\n\n  var rendererID = null;\n  var injectedHook = null;\n  var injectedProfilingHooks = null;\n  var hasLoggedError = false;\n  var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined';\n  function injectInternals(internals) {\n    if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {\n      // No DevTools\n      return false;\n    }\n\n    var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__;\n\n    if (hook.isDisabled) {\n      // This isn't a real property on the hook, but it can be set to opt out\n      // of DevTools integration and associated warnings and logs.\n      // https://github.com/facebook/react/issues/3877\n      return true;\n    }\n\n    if (!hook.supportsFiber) {\n      {\n        error('The installed version of React DevTools is too old and will not work ' + 'with the current version of React. Please update React DevTools. ' + 'https://reactjs.org/link/react-devtools');\n      } // DevTools exists, even though it doesn't support Fiber.\n\n\n      return true;\n    }\n\n    try {\n      if (enableSchedulingProfiler) {\n        // Conditionally inject these hooks only if Timeline profiler is supported by this build.\n        // This gives DevTools a way to feature detect that isn't tied to version number\n        // (since profiling and timeline are controlled by different feature flags).\n        internals = assign({}, internals, {\n          getLaneLabelMap: getLaneLabelMap,\n          injectProfilingHooks: injectProfilingHooks\n        });\n      }\n\n      rendererID = hook.inject(internals); // We have successfully injected, so now it is safe to set up hooks.\n\n      injectedHook = hook;\n    } catch (err) {\n      // Catch all errors because it is unsafe to throw during initialization.\n      {\n        error('React instrumentation encountered an error: %s.', err);\n      }\n    }\n\n    if (hook.checkDCE) {\n      // This is the real DevTools.\n      return true;\n    } else {\n      // This is likely a hook installed by Fast Refresh runtime.\n      return false;\n    }\n  }\n  function onScheduleRoot(root, children) {\n    {\n      if (injectedHook && typeof injectedHook.onScheduleFiberRoot === 'function') {\n        try {\n          injectedHook.onScheduleFiberRoot(rendererID, root, children);\n        } catch (err) {\n          if ( !hasLoggedError) {\n            hasLoggedError = true;\n\n            error('React instrumentation encountered an error: %s', err);\n          }\n        }\n      }\n    }\n  }\n  function onCommitRoot(root, eventPriority) {\n    if (injectedHook && typeof injectedHook.onCommitFiberRoot === 'function') {\n      try {\n        var didError = (root.current.flags & DidCapture) === DidCapture;\n\n        if (enableProfilerTimer) {\n          var schedulerPriority;\n\n          switch (eventPriority) {\n            case DiscreteEventPriority:\n              schedulerPriority = ImmediatePriority;\n              break;\n\n            case ContinuousEventPriority:\n              schedulerPriority = UserBlockingPriority;\n              break;\n\n            case DefaultEventPriority:\n              schedulerPriority = NormalPriority;\n              break;\n\n            case IdleEventPriority:\n              schedulerPriority = IdlePriority;\n              break;\n\n            default:\n              schedulerPriority = NormalPriority;\n              break;\n          }\n\n          injectedHook.onCommitFiberRoot(rendererID, root, schedulerPriority, didError);\n        } else {\n          injectedHook.onCommitFiberRoot(rendererID, root, undefined, didError);\n        }\n      } catch (err) {\n        {\n          if (!hasLoggedError) {\n            hasLoggedError = true;\n\n            error('React instrumentation encountered an error: %s', err);\n          }\n        }\n      }\n    }\n  }\n  function onPostCommitRoot(root) {\n    if (injectedHook && typeof injectedHook.onPostCommitFiberRoot === 'function') {\n      try {\n        injectedHook.onPostCommitFiberRoot(rendererID, root);\n      } catch (err) {\n        {\n          if (!hasLoggedError) {\n            hasLoggedError = true;\n\n            error('React instrumentation encountered an error: %s', err);\n          }\n        }\n      }\n    }\n  }\n  function onCommitUnmount(fiber) {\n    if (injectedHook && typeof injectedHook.onCommitFiberUnmount === 'function') {\n      try {\n        injectedHook.onCommitFiberUnmount(rendererID, fiber);\n      } catch (err) {\n        {\n          if (!hasLoggedError) {\n            hasLoggedError = true;\n\n            error('React instrumentation encountered an error: %s', err);\n          }\n        }\n      }\n    }\n  }\n  function setIsStrictModeForDevtools(newIsStrictMode) {\n    {\n      if (typeof unstable_yieldValue$1 === 'function') {\n        // We're in a test because Scheduler.unstable_yieldValue only exists\n        // in SchedulerMock. To reduce the noise in strict mode tests,\n        // suppress warnings and disable scheduler yielding during the double render\n        unstable_setDisableYieldValue$1(newIsStrictMode);\n        setSuppressWarning(newIsStrictMode);\n      }\n\n      if (injectedHook && typeof injectedHook.setStrictMode === 'function') {\n        try {\n          injectedHook.setStrictMode(rendererID, newIsStrictMode);\n        } catch (err) {\n          {\n            if (!hasLoggedError) {\n              hasLoggedError = true;\n\n              error('React instrumentation encountered an error: %s', err);\n            }\n          }\n        }\n      }\n    }\n  } // Profiler API hooks\n\n  function injectProfilingHooks(profilingHooks) {\n    injectedProfilingHooks = profilingHooks;\n  }\n\n  function getLaneLabelMap() {\n    {\n      var map = new Map();\n      var lane = 1;\n\n      for (var index = 0; index < TotalLanes; index++) {\n        var label = getLabelForLane(lane);\n        map.set(lane, label);\n        lane *= 2;\n      }\n\n      return map;\n    }\n  }\n\n  function markCommitStarted(lanes) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStarted === 'function') {\n        injectedProfilingHooks.markCommitStarted(lanes);\n      }\n    }\n  }\n  function markCommitStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markCommitStopped === 'function') {\n        injectedProfilingHooks.markCommitStopped();\n      }\n    }\n  }\n  function markComponentRenderStarted(fiber) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStarted === 'function') {\n        injectedProfilingHooks.markComponentRenderStarted(fiber);\n      }\n    }\n  }\n  function markComponentRenderStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentRenderStopped === 'function') {\n        injectedProfilingHooks.markComponentRenderStopped();\n      }\n    }\n  }\n  function markComponentPassiveEffectMountStarted(fiber) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStarted === 'function') {\n        injectedProfilingHooks.markComponentPassiveEffectMountStarted(fiber);\n      }\n    }\n  }\n  function markComponentPassiveEffectMountStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectMountStopped === 'function') {\n        injectedProfilingHooks.markComponentPassiveEffectMountStopped();\n      }\n    }\n  }\n  function markComponentPassiveEffectUnmountStarted(fiber) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStarted === 'function') {\n        injectedProfilingHooks.markComponentPassiveEffectUnmountStarted(fiber);\n      }\n    }\n  }\n  function markComponentPassiveEffectUnmountStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentPassiveEffectUnmountStopped === 'function') {\n        injectedProfilingHooks.markComponentPassiveEffectUnmountStopped();\n      }\n    }\n  }\n  function markComponentLayoutEffectMountStarted(fiber) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectMountStarted === 'function') {\n        injectedProfilingHooks.markComponentLayoutEffectMountStarted(fiber);\n      }\n    }\n  }\n  function markComponentLayoutEffectMountStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectMountStopped === 'function') {\n        injectedProfilingHooks.markComponentLayoutEffectMountStopped();\n      }\n    }\n  }\n  function markComponentLayoutEffectUnmountStarted(fiber) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStarted === 'function') {\n        injectedProfilingHooks.markComponentLayoutEffectUnmountStarted(fiber);\n      }\n    }\n  }\n  function markComponentLayoutEffectUnmountStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentLayoutEffectUnmountStopped === 'function') {\n        injectedProfilingHooks.markComponentLayoutEffectUnmountStopped();\n      }\n    }\n  }\n  function markComponentErrored(fiber, thrownValue, lanes) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentErrored === 'function') {\n        injectedProfilingHooks.markComponentErrored(fiber, thrownValue, lanes);\n      }\n    }\n  }\n  function markComponentSuspended(fiber, wakeable, lanes) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markComponentSuspended === 'function') {\n        injectedProfilingHooks.markComponentSuspended(fiber, wakeable, lanes);\n      }\n    }\n  }\n  function markLayoutEffectsStarted(lanes) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markLayoutEffectsStarted === 'function') {\n        injectedProfilingHooks.markLayoutEffectsStarted(lanes);\n      }\n    }\n  }\n  function markLayoutEffectsStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markLayoutEffectsStopped === 'function') {\n        injectedProfilingHooks.markLayoutEffectsStopped();\n      }\n    }\n  }\n  function markPassiveEffectsStarted(lanes) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markPassiveEffectsStarted === 'function') {\n        injectedProfilingHooks.markPassiveEffectsStarted(lanes);\n      }\n    }\n  }\n  function markPassiveEffectsStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markPassiveEffectsStopped === 'function') {\n        injectedProfilingHooks.markPassiveEffectsStopped();\n      }\n    }\n  }\n  function markRenderStarted(lanes) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markRenderStarted === 'function') {\n        injectedProfilingHooks.markRenderStarted(lanes);\n      }\n    }\n  }\n  function markRenderYielded() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markRenderYielded === 'function') {\n        injectedProfilingHooks.markRenderYielded();\n      }\n    }\n  }\n  function markRenderStopped() {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markRenderStopped === 'function') {\n        injectedProfilingHooks.markRenderStopped();\n      }\n    }\n  }\n  function markRenderScheduled(lane) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markRenderScheduled === 'function') {\n        injectedProfilingHooks.markRenderScheduled(lane);\n      }\n    }\n  }\n  function markForceUpdateScheduled(fiber, lane) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markForceUpdateScheduled === 'function') {\n        injectedProfilingHooks.markForceUpdateScheduled(fiber, lane);\n      }\n    }\n  }\n  function markStateUpdateScheduled(fiber, lane) {\n    {\n      if (injectedProfilingHooks !== null && typeof injectedProfilingHooks.markStateUpdateScheduled === 'function') {\n        injectedProfilingHooks.markStateUpdateScheduled(fiber, lane);\n      }\n    }\n  }\n\n  var NoMode =\n  /*                         */\n  0; // TODO: Remove ConcurrentMode by reading from the root tag instead\n\n  var ConcurrentMode =\n  /*                 */\n  1;\n  var ProfileMode =\n  /*                    */\n  2;\n  var StrictLegacyMode =\n  /*               */\n  8;\n  var StrictEffectsMode =\n  /*              */\n  16;\n\n  // TODO: This is pretty well supported by browsers. Maybe we can drop it.\n  var clz32 = Math.clz32 ? Math.clz32 : clz32Fallback; // Count leading zeros.\n  // Based on:\n  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32\n\n  var log = Math.log;\n  var LN2 = Math.LN2;\n\n  function clz32Fallback(x) {\n    var asUint = x >>> 0;\n\n    if (asUint === 0) {\n      return 32;\n    }\n\n    return 31 - (log(asUint) / LN2 | 0) | 0;\n  }\n\n  // If those values are changed that package should be rebuilt and redeployed.\n\n  var TotalLanes = 31;\n  var NoLanes =\n  /*                        */\n  0;\n  var NoLane =\n  /*                          */\n  0;\n  var SyncLane =\n  /*                        */\n  1;\n  var InputContinuousHydrationLane =\n  /*    */\n  2;\n  var InputContinuousLane =\n  /*             */\n  4;\n  var DefaultHydrationLane =\n  /*            */\n  8;\n  var DefaultLane =\n  /*                     */\n  16;\n  var TransitionHydrationLane =\n  /*                */\n  32;\n  var TransitionLanes =\n  /*                       */\n  4194240;\n  var TransitionLane1 =\n  /*                        */\n  64;\n  var TransitionLane2 =\n  /*                        */\n  128;\n  var TransitionLane3 =\n  /*                        */\n  256;\n  var TransitionLane4 =\n  /*                        */\n  512;\n  var TransitionLane5 =\n  /*                        */\n  1024;\n  var TransitionLane6 =\n  /*                        */\n  2048;\n  var TransitionLane7 =\n  /*                        */\n  4096;\n  var TransitionLane8 =\n  /*                        */\n  8192;\n  var TransitionLane9 =\n  /*                        */\n  16384;\n  var TransitionLane10 =\n  /*                       */\n  32768;\n  var TransitionLane11 =\n  /*                       */\n  65536;\n  var TransitionLane12 =\n  /*                       */\n  131072;\n  var TransitionLane13 =\n  /*                       */\n  262144;\n  var TransitionLane14 =\n  /*                       */\n  524288;\n  var TransitionLane15 =\n  /*                       */\n  1048576;\n  var TransitionLane16 =\n  /*                       */\n  2097152;\n  var RetryLanes =\n  /*                            */\n  130023424;\n  var RetryLane1 =\n  /*                             */\n  4194304;\n  var RetryLane2 =\n  /*                             */\n  8388608;\n  var RetryLane3 =\n  /*                             */\n  16777216;\n  var RetryLane4 =\n  /*                             */\n  33554432;\n  var RetryLane5 =\n  /*                             */\n  67108864;\n  var SomeRetryLane = RetryLane1;\n  var SelectiveHydrationLane =\n  /*          */\n  134217728;\n  var NonIdleLanes =\n  /*                          */\n  268435455;\n  var IdleHydrationLane =\n  /*               */\n  268435456;\n  var IdleLane =\n  /*                        */\n  536870912;\n  var OffscreenLane =\n  /*                   */\n  1073741824; // This function is used for the experimental timeline (react-devtools-timeline)\n  // It should be kept in sync with the Lanes values above.\n\n  function getLabelForLane(lane) {\n    {\n      if (lane & SyncLane) {\n        return 'Sync';\n      }\n\n      if (lane & InputContinuousHydrationLane) {\n        return 'InputContinuousHydration';\n      }\n\n      if (lane & InputContinuousLane) {\n        return 'InputContinuous';\n      }\n\n      if (lane & DefaultHydrationLane) {\n        return 'DefaultHydration';\n      }\n\n      if (lane & DefaultLane) {\n        return 'Default';\n      }\n\n      if (lane & TransitionHydrationLane) {\n        return 'TransitionHydration';\n      }\n\n      if (lane & TransitionLanes) {\n        return 'Transition';\n      }\n\n      if (lane & RetryLanes) {\n        return 'Retry';\n      }\n\n      if (lane & SelectiveHydrationLane) {\n        return 'SelectiveHydration';\n      }\n\n      if (lane & IdleHydrationLane) {\n        return 'IdleHydration';\n      }\n\n      if (lane & IdleLane) {\n        return 'Idle';\n      }\n\n      if (lane & OffscreenLane) {\n        return 'Offscreen';\n      }\n    }\n  }\n  var NoTimestamp = -1;\n  var nextTransitionLane = TransitionLane1;\n  var nextRetryLane = RetryLane1;\n\n  function getHighestPriorityLanes(lanes) {\n    switch (getHighestPriorityLane(lanes)) {\n      case SyncLane:\n        return SyncLane;\n\n      case InputContinuousHydrationLane:\n        return InputContinuousHydrationLane;\n\n      case InputContinuousLane:\n        return InputContinuousLane;\n\n      case DefaultHydrationLane:\n        return DefaultHydrationLane;\n\n      case DefaultLane:\n        return DefaultLane;\n\n      case TransitionHydrationLane:\n        return TransitionHydrationLane;\n\n      case TransitionLane1:\n      case TransitionLane2:\n      case TransitionLane3:\n      case TransitionLane4:\n      case TransitionLane5:\n      case TransitionLane6:\n      case TransitionLane7:\n      case TransitionLane8:\n      case TransitionLane9:\n      case TransitionLane10:\n      case TransitionLane11:\n      case TransitionLane12:\n      case TransitionLane13:\n      case TransitionLane14:\n      case TransitionLane15:\n      case TransitionLane16:\n        return lanes & TransitionLanes;\n\n      case RetryLane1:\n      case RetryLane2:\n      case RetryLane3:\n      case RetryLane4:\n      case RetryLane5:\n        return lanes & RetryLanes;\n\n      case SelectiveHydrationLane:\n        return SelectiveHydrationLane;\n\n      case IdleHydrationLane:\n        return IdleHydrationLane;\n\n      case IdleLane:\n        return IdleLane;\n\n      case OffscreenLane:\n        return OffscreenLane;\n\n      default:\n        {\n          error('Should have found matching lanes. This is a bug in React.');\n        } // This shouldn't be reachable, but as a fallback, return the entire bitmask.\n\n\n        return lanes;\n    }\n  }\n\n  function getNextLanes(root, wipLanes) {\n    // Early bailout if there's no pending work left.\n    var pendingLanes = root.pendingLanes;\n\n    if (pendingLanes === NoLanes) {\n      return NoLanes;\n    }\n\n    var nextLanes = NoLanes;\n    var suspendedLanes = root.suspendedLanes;\n    var pingedLanes = root.pingedLanes; // Do not work on any idle work until all the non-idle work has finished,\n    // even if the work is suspended.\n\n    var nonIdlePendingLanes = pendingLanes & NonIdleLanes;\n\n    if (nonIdlePendingLanes !== NoLanes) {\n      var nonIdleUnblockedLanes = nonIdlePendingLanes & ~suspendedLanes;\n\n      if (nonIdleUnblockedLanes !== NoLanes) {\n        nextLanes = getHighestPriorityLanes(nonIdleUnblockedLanes);\n      } else {\n        var nonIdlePingedLanes = nonIdlePendingLanes & pingedLanes;\n\n        if (nonIdlePingedLanes !== NoLanes) {\n          nextLanes = getHighestPriorityLanes(nonIdlePingedLanes);\n        }\n      }\n    } else {\n      // The only remaining work is Idle.\n      var unblockedLanes = pendingLanes & ~suspendedLanes;\n\n      if (unblockedLanes !== NoLanes) {\n        nextLanes = getHighestPriorityLanes(unblockedLanes);\n      } else {\n        if (pingedLanes !== NoLanes) {\n          nextLanes = getHighestPriorityLanes(pingedLanes);\n        }\n      }\n    }\n\n    if (nextLanes === NoLanes) {\n      // This should only be reachable if we're suspended\n      // TODO: Consider warning in this path if a fallback timer is not scheduled.\n      return NoLanes;\n    } // If we're already in the middle of a render, switching lanes will interrupt\n    // it and we'll lose our progress. We should only do this if the new lanes are\n    // higher priority.\n\n\n    if (wipLanes !== NoLanes && wipLanes !== nextLanes && // If we already suspended with a delay, then interrupting is fine. Don't\n    // bother waiting until the root is complete.\n    (wipLanes & suspendedLanes) === NoLanes) {\n      var nextLane = getHighestPriorityLane(nextLanes);\n      var wipLane = getHighestPriorityLane(wipLanes);\n\n      if ( // Tests whether the next lane is equal or lower priority than the wip\n      // one. This works because the bits decrease in priority as you go left.\n      nextLane >= wipLane || // Default priority updates should not interrupt transition updates. The\n      // only difference between default updates and transition updates is that\n      // default updates do not support refresh transitions.\n      nextLane === DefaultLane && (wipLane & TransitionLanes) !== NoLanes) {\n        // Keep working on the existing in-progress tree. Do not interrupt.\n        return wipLanes;\n      }\n    }\n\n    if ((nextLanes & InputContinuousLane) !== NoLanes) {\n      // When updates are sync by default, we entangle continuous priority updates\n      // and default updates, so they render in the same batch. The only reason\n      // they use separate lanes is because continuous updates should interrupt\n      // transitions, but default updates should not.\n      nextLanes |= pendingLanes & DefaultLane;\n    } // Check for entangled lanes and add them to the batch.\n    //\n    // A lane is said to be entangled with another when it's not allowed to render\n    // in a batch that does not also include the other lane. Typically we do this\n    // when multiple updates have the same source, and we only want to respond to\n    // the most recent event from that source.\n    //\n    // Note that we apply entanglements *after* checking for partial work above.\n    // This means that if a lane is entangled during an interleaved event while\n    // it's already rendering, we won't interrupt it. This is intentional, since\n    // entanglement is usually \"best effort\": we'll try our best to render the\n    // lanes in the same batch, but it's not worth throwing out partially\n    // completed work in order to do it.\n    // TODO: Reconsider this. The counter-argument is that the partial work\n    // represents an intermediate state, which we don't want to show to the user.\n    // And by spending extra time finishing it, we're increasing the amount of\n    // time it takes to show the final state, which is what they are actually\n    // waiting for.\n    //\n    // For those exceptions where entanglement is semantically important, like\n    // useMutableSource, we should ensure that there is no partial work at the\n    // time we apply the entanglement.\n\n\n    var entangledLanes = root.entangledLanes;\n\n    if (entangledLanes !== NoLanes) {\n      var entanglements = root.entanglements;\n      var lanes = nextLanes & entangledLanes;\n\n      while (lanes > 0) {\n        var index = pickArbitraryLaneIndex(lanes);\n        var lane = 1 << index;\n        nextLanes |= entanglements[index];\n        lanes &= ~lane;\n      }\n    }\n\n    return nextLanes;\n  }\n  function getMostRecentEventTime(root, lanes) {\n    var eventTimes = root.eventTimes;\n    var mostRecentEventTime = NoTimestamp;\n\n    while (lanes > 0) {\n      var index = pickArbitraryLaneIndex(lanes);\n      var lane = 1 << index;\n      var eventTime = eventTimes[index];\n\n      if (eventTime > mostRecentEventTime) {\n        mostRecentEventTime = eventTime;\n      }\n\n      lanes &= ~lane;\n    }\n\n    return mostRecentEventTime;\n  }\n\n  function computeExpirationTime(lane, currentTime) {\n    switch (lane) {\n      case SyncLane:\n      case InputContinuousHydrationLane:\n      case InputContinuousLane:\n        // User interactions should expire slightly more quickly.\n        //\n        // NOTE: This is set to the corresponding constant as in Scheduler.js.\n        // When we made it larger, a product metric in www regressed, suggesting\n        // there's a user interaction that's being starved by a series of\n        // synchronous updates. If that theory is correct, the proper solution is\n        // to fix the starvation. However, this scenario supports the idea that\n        // expiration times are an important safeguard when starvation\n        // does happen.\n        return currentTime + 250;\n\n      case DefaultHydrationLane:\n      case DefaultLane:\n      case TransitionHydrationLane:\n      case TransitionLane1:\n      case TransitionLane2:\n      case TransitionLane3:\n      case TransitionLane4:\n      case TransitionLane5:\n      case TransitionLane6:\n      case TransitionLane7:\n      case TransitionLane8:\n      case TransitionLane9:\n      case TransitionLane10:\n      case TransitionLane11:\n      case TransitionLane12:\n      case TransitionLane13:\n      case TransitionLane14:\n      case TransitionLane15:\n      case TransitionLane16:\n        return currentTime + 5000;\n\n      case RetryLane1:\n      case RetryLane2:\n      case RetryLane3:\n      case RetryLane4:\n      case RetryLane5:\n        // TODO: Retries should be allowed to expire if they are CPU bound for\n        // too long, but when I made this change it caused a spike in browser\n        // crashes. There must be some other underlying bug; not super urgent but\n        // ideally should figure out why and fix it. Unfortunately we don't have\n        // a repro for the crashes, only detected via production metrics.\n        return NoTimestamp;\n\n      case SelectiveHydrationLane:\n      case IdleHydrationLane:\n      case IdleLane:\n      case OffscreenLane:\n        // Anything idle priority or lower should never expire.\n        return NoTimestamp;\n\n      default:\n        {\n          error('Should have found matching lanes. This is a bug in React.');\n        }\n\n        return NoTimestamp;\n    }\n  }\n\n  function markStarvedLanesAsExpired(root, currentTime) {\n    // TODO: This gets called every time we yield. We can optimize by storing\n    // the earliest expiration time on the root. Then use that to quickly bail out\n    // of this function.\n    var pendingLanes = root.pendingLanes;\n    var suspendedLanes = root.suspendedLanes;\n    var pingedLanes = root.pingedLanes;\n    var expirationTimes = root.expirationTimes; // Iterate through the pending lanes and check if we've reached their\n    // expiration time. If so, we'll assume the update is being starved and mark\n    // it as expired to force it to finish.\n\n    var lanes = pendingLanes;\n\n    while (lanes > 0) {\n      var index = pickArbitraryLaneIndex(lanes);\n      var lane = 1 << index;\n      var expirationTime = expirationTimes[index];\n\n      if (expirationTime === NoTimestamp) {\n        // Found a pending lane with no expiration time. If it's not suspended, or\n        // if it's pinged, assume it's CPU-bound. Compute a new expiration time\n        // using the current time.\n        if ((lane & suspendedLanes) === NoLanes || (lane & pingedLanes) !== NoLanes) {\n          // Assumes timestamps are monotonically increasing.\n          expirationTimes[index] = computeExpirationTime(lane, currentTime);\n        }\n      } else if (expirationTime <= currentTime) {\n        // This lane expired\n        root.expiredLanes |= lane;\n      }\n\n      lanes &= ~lane;\n    }\n  } // This returns the highest priority pending lanes regardless of whether they\n  // are suspended.\n\n  function getHighestPriorityPendingLanes(root) {\n    return getHighestPriorityLanes(root.pendingLanes);\n  }\n  function getLanesToRetrySynchronouslyOnError(root) {\n    var everythingButOffscreen = root.pendingLanes & ~OffscreenLane;\n\n    if (everythingButOffscreen !== NoLanes) {\n      return everythingButOffscreen;\n    }\n\n    if (everythingButOffscreen & OffscreenLane) {\n      return OffscreenLane;\n    }\n\n    return NoLanes;\n  }\n  function includesSyncLane(lanes) {\n    return (lanes & SyncLane) !== NoLanes;\n  }\n  function includesNonIdleWork(lanes) {\n    return (lanes & NonIdleLanes) !== NoLanes;\n  }\n  function includesOnlyRetries(lanes) {\n    return (lanes & RetryLanes) === lanes;\n  }\n  function includesOnlyNonUrgentLanes(lanes) {\n    var UrgentLanes = SyncLane | InputContinuousLane | DefaultLane;\n    return (lanes & UrgentLanes) === NoLanes;\n  }\n  function includesOnlyTransitions(lanes) {\n    return (lanes & TransitionLanes) === lanes;\n  }\n  function includesBlockingLane(root, lanes) {\n\n    var SyncDefaultLanes = InputContinuousHydrationLane | InputContinuousLane | DefaultHydrationLane | DefaultLane;\n    return (lanes & SyncDefaultLanes) !== NoLanes;\n  }\n  function includesExpiredLane(root, lanes) {\n    // This is a separate check from includesBlockingLane because a lane can\n    // expire after a render has already started.\n    return (lanes & root.expiredLanes) !== NoLanes;\n  }\n  function isTransitionLane(lane) {\n    return (lane & TransitionLanes) !== NoLanes;\n  }\n  function claimNextTransitionLane() {\n    // Cycle through the lanes, assigning each new transition to the next lane.\n    // In most cases, this means every transition gets its own lane, until we\n    // run out of lanes and cycle back to the beginning.\n    var lane = nextTransitionLane;\n    nextTransitionLane <<= 1;\n\n    if ((nextTransitionLane & TransitionLanes) === NoLanes) {\n      nextTransitionLane = TransitionLane1;\n    }\n\n    return lane;\n  }\n  function claimNextRetryLane() {\n    var lane = nextRetryLane;\n    nextRetryLane <<= 1;\n\n    if ((nextRetryLane & RetryLanes) === NoLanes) {\n      nextRetryLane = RetryLane1;\n    }\n\n    return lane;\n  }\n  function getHighestPriorityLane(lanes) {\n    return lanes & -lanes;\n  }\n  function pickArbitraryLane(lanes) {\n    // This wrapper function gets inlined. Only exists so to communicate that it\n    // doesn't matter which bit is selected; you can pick any bit without\n    // affecting the algorithms where its used. Here I'm using\n    // getHighestPriorityLane because it requires the fewest operations.\n    return getHighestPriorityLane(lanes);\n  }\n\n  function pickArbitraryLaneIndex(lanes) {\n    return 31 - clz32(lanes);\n  }\n\n  function laneToIndex(lane) {\n    return pickArbitraryLaneIndex(lane);\n  }\n\n  function includesSomeLane(a, b) {\n    return (a & b) !== NoLanes;\n  }\n  function isSubsetOfLanes(set, subset) {\n    return (set & subset) === subset;\n  }\n  function mergeLanes(a, b) {\n    return a | b;\n  }\n  function removeLanes(set, subset) {\n    return set & ~subset;\n  }\n  function intersectLanes(a, b) {\n    return a & b;\n  } // Seems redundant, but it changes the type from a single lane (used for\n  // updates) to a group of lanes (used for flushing work).\n\n  function laneToLanes(lane) {\n    return lane;\n  }\n  function higherPriorityLane(a, b) {\n    // This works because the bit ranges decrease in priority as you go left.\n    return a !== NoLane && a < b ? a : b;\n  }\n  function createLaneMap(initial) {\n    // Intentionally pushing one by one.\n    // https://v8.dev/blog/elements-kinds#avoid-creating-holes\n    var laneMap = [];\n\n    for (var i = 0; i < TotalLanes; i++) {\n      laneMap.push(initial);\n    }\n\n    return laneMap;\n  }\n  function markRootUpdated(root, updateLane, eventTime) {\n    root.pendingLanes |= updateLane; // If there are any suspended transitions, it's possible this new update\n    // could unblock them. Clear the suspended lanes so that we can try rendering\n    // them again.\n    //\n    // TODO: We really only need to unsuspend only lanes that are in the\n    // `subtreeLanes` of the updated fiber, or the update lanes of the return\n    // path. This would exclude suspended updates in an unrelated sibling tree,\n    // since there's no way for this update to unblock it.\n    //\n    // We don't do this if the incoming update is idle, because we never process\n    // idle updates until after all the regular updates have finished; there's no\n    // way it could unblock a transition.\n\n    if (updateLane !== IdleLane) {\n      root.suspendedLanes = NoLanes;\n      root.pingedLanes = NoLanes;\n    }\n\n    var eventTimes = root.eventTimes;\n    var index = laneToIndex(updateLane); // We can always overwrite an existing timestamp because we prefer the most\n    // recent event, and we assume time is monotonically increasing.\n\n    eventTimes[index] = eventTime;\n  }\n  function markRootSuspended(root, suspendedLanes) {\n    root.suspendedLanes |= suspendedLanes;\n    root.pingedLanes &= ~suspendedLanes; // The suspended lanes are no longer CPU-bound. Clear their expiration times.\n\n    var expirationTimes = root.expirationTimes;\n    var lanes = suspendedLanes;\n\n    while (lanes > 0) {\n      var index = pickArbitraryLaneIndex(lanes);\n      var lane = 1 << index;\n      expirationTimes[index] = NoTimestamp;\n      lanes &= ~lane;\n    }\n  }\n  function markRootPinged(root, pingedLanes, eventTime) {\n    root.pingedLanes |= root.suspendedLanes & pingedLanes;\n  }\n  function markRootFinished(root, remainingLanes) {\n    var noLongerPendingLanes = root.pendingLanes & ~remainingLanes;\n    root.pendingLanes = remainingLanes; // Let's try everything again\n\n    root.suspendedLanes = NoLanes;\n    root.pingedLanes = NoLanes;\n    root.expiredLanes &= remainingLanes;\n    root.mutableReadLanes &= remainingLanes;\n    root.entangledLanes &= remainingLanes;\n    var entanglements = root.entanglements;\n    var eventTimes = root.eventTimes;\n    var expirationTimes = root.expirationTimes; // Clear the lanes that no longer have pending work\n\n    var lanes = noLongerPendingLanes;\n\n    while (lanes > 0) {\n      var index = pickArbitraryLaneIndex(lanes);\n      var lane = 1 << index;\n      entanglements[index] = NoLanes;\n      eventTimes[index] = NoTimestamp;\n      expirationTimes[index] = NoTimestamp;\n      lanes &= ~lane;\n    }\n  }\n  function markRootEntangled(root, entangledLanes) {\n    // In addition to entangling each of the given lanes with each other, we also\n    // have to consider _transitive_ entanglements. For each lane that is already\n    // entangled with *any* of the given lanes, that lane is now transitively\n    // entangled with *all* the given lanes.\n    //\n    // Translated: If C is entangled with A, then entangling A with B also\n    // entangles C with B.\n    //\n    // If this is hard to grasp, it might help to intentionally break this\n    // function and look at the tests that fail in ReactTransition-test.js. Try\n    // commenting out one of the conditions below.\n    var rootEntangledLanes = root.entangledLanes |= entangledLanes;\n    var entanglements = root.entanglements;\n    var lanes = rootEntangledLanes;\n\n    while (lanes) {\n      var index = pickArbitraryLaneIndex(lanes);\n      var lane = 1 << index;\n\n      if ( // Is this one of the newly entangled lanes?\n      lane & entangledLanes | // Is this lane transitively entangled with the newly entangled lanes?\n      entanglements[index] & entangledLanes) {\n        entanglements[index] |= entangledLanes;\n      }\n\n      lanes &= ~lane;\n    }\n  }\n  function getBumpedLaneForHydration(root, renderLanes) {\n    var renderLane = getHighestPriorityLane(renderLanes);\n    var lane;\n\n    switch (renderLane) {\n      case InputContinuousLane:\n        lane = InputContinuousHydrationLane;\n        break;\n\n      case DefaultLane:\n        lane = DefaultHydrationLane;\n        break;\n\n      case TransitionLane1:\n      case TransitionLane2:\n      case TransitionLane3:\n      case TransitionLane4:\n      case TransitionLane5:\n      case TransitionLane6:\n      case TransitionLane7:\n      case TransitionLane8:\n      case TransitionLane9:\n      case TransitionLane10:\n      case TransitionLane11:\n      case TransitionLane12:\n      case TransitionLane13:\n      case TransitionLane14:\n      case TransitionLane15:\n      case TransitionLane16:\n      case RetryLane1:\n      case RetryLane2:\n      case RetryLane3:\n      case RetryLane4:\n      case RetryLane5:\n        lane = TransitionHydrationLane;\n        break;\n\n      case IdleLane:\n        lane = IdleHydrationLane;\n        break;\n\n      default:\n        // Everything else is already either a hydration lane, or shouldn't\n        // be retried at a hydration lane.\n        lane = NoLane;\n        break;\n    } // Check if the lane we chose is suspended. If so, that indicates that we\n    // already attempted and failed to hydrate at that level. Also check if we're\n    // already rendering that lane, which is rare but could happen.\n\n\n    if ((lane & (root.suspendedLanes | renderLanes)) !== NoLane) {\n      // Give up trying to hydrate and fall back to client render.\n      return NoLane;\n    }\n\n    return lane;\n  }\n  function addFiberToLanesMap(root, fiber, lanes) {\n\n    if (!isDevToolsPresent) {\n      return;\n    }\n\n    var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap;\n\n    while (lanes > 0) {\n      var index = laneToIndex(lanes);\n      var lane = 1 << index;\n      var updaters = pendingUpdatersLaneMap[index];\n      updaters.add(fiber);\n      lanes &= ~lane;\n    }\n  }\n  function movePendingFibersToMemoized(root, lanes) {\n\n    if (!isDevToolsPresent) {\n      return;\n    }\n\n    var pendingUpdatersLaneMap = root.pendingUpdatersLaneMap;\n    var memoizedUpdaters = root.memoizedUpdaters;\n\n    while (lanes > 0) {\n      var index = laneToIndex(lanes);\n      var lane = 1 << index;\n      var updaters = pendingUpdatersLaneMap[index];\n\n      if (updaters.size > 0) {\n        updaters.forEach(function (fiber) {\n          var alternate = fiber.alternate;\n\n          if (alternate === null || !memoizedUpdaters.has(alternate)) {\n            memoizedUpdaters.add(fiber);\n          }\n        });\n        updaters.clear();\n      }\n\n      lanes &= ~lane;\n    }\n  }\n  function getTransitionsForLanes(root, lanes) {\n    {\n      return null;\n    }\n  }\n\n  var DiscreteEventPriority = SyncLane;\n  var ContinuousEventPriority = InputContinuousLane;\n  var DefaultEventPriority = DefaultLane;\n  var IdleEventPriority = IdleLane;\n  var currentUpdatePriority = NoLane;\n  function getCurrentUpdatePriority() {\n    return currentUpdatePriority;\n  }\n  function setCurrentUpdatePriority(newPriority) {\n    currentUpdatePriority = newPriority;\n  }\n  function runWithPriority(priority, fn) {\n    var previousPriority = currentUpdatePriority;\n\n    try {\n      currentUpdatePriority = priority;\n      return fn();\n    } finally {\n      currentUpdatePriority = previousPriority;\n    }\n  }\n  function higherEventPriority(a, b) {\n    return a !== 0 && a < b ? a : b;\n  }\n  function lowerEventPriority(a, b) {\n    return a === 0 || a > b ? a : b;\n  }\n  function isHigherEventPriority(a, b) {\n    return a !== 0 && a < b;\n  }\n  function lanesToEventPriority(lanes) {\n    var lane = getHighestPriorityLane(lanes);\n\n    if (!isHigherEventPriority(DiscreteEventPriority, lane)) {\n      return DiscreteEventPriority;\n    }\n\n    if (!isHigherEventPriority(ContinuousEventPriority, lane)) {\n      return ContinuousEventPriority;\n    }\n\n    if (includesNonIdleWork(lane)) {\n      return DefaultEventPriority;\n    }\n\n    return IdleEventPriority;\n  }\n\n  // This is imported by the event replaying implementation in React DOM. It's\n  // in a separate file to break a circular dependency between the renderer and\n  // the reconciler.\n  function isRootDehydrated(root) {\n    var currentState = root.current.memoizedState;\n    return currentState.isDehydrated;\n  }\n\n  var _attemptSynchronousHydration;\n\n  function setAttemptSynchronousHydration(fn) {\n    _attemptSynchronousHydration = fn;\n  }\n  function attemptSynchronousHydration(fiber) {\n    _attemptSynchronousHydration(fiber);\n  }\n  var attemptContinuousHydration;\n  function setAttemptContinuousHydration(fn) {\n    attemptContinuousHydration = fn;\n  }\n  var attemptHydrationAtCurrentPriority;\n  function setAttemptHydrationAtCurrentPriority(fn) {\n    attemptHydrationAtCurrentPriority = fn;\n  }\n  var getCurrentUpdatePriority$1;\n  function setGetCurrentUpdatePriority(fn) {\n    getCurrentUpdatePriority$1 = fn;\n  }\n  var attemptHydrationAtPriority;\n  function setAttemptHydrationAtPriority(fn) {\n    attemptHydrationAtPriority = fn;\n  } // TODO: Upgrade this definition once we're on a newer version of Flow that\n  // has this definition built-in.\n\n  var hasScheduledReplayAttempt = false; // The queue of discrete events to be replayed.\n\n  var queuedDiscreteEvents = []; // Indicates if any continuous event targets are non-null for early bailout.\n  // if the last target was dehydrated.\n\n  var queuedFocus = null;\n  var queuedDrag = null;\n  var queuedMouse = null; // For pointer events there can be one latest event per pointerId.\n\n  var queuedPointers = new Map();\n  var queuedPointerCaptures = new Map(); // We could consider replaying selectionchange and touchmoves too.\n\n  var queuedExplicitHydrationTargets = [];\n  var discreteReplayableEvents = ['mousedown', 'mouseup', 'touchcancel', 'touchend', 'touchstart', 'auxclick', 'dblclick', 'pointercancel', 'pointerdown', 'pointerup', 'dragend', 'dragstart', 'drop', 'compositionend', 'compositionstart', 'keydown', 'keypress', 'keyup', 'input', 'textInput', // Intentionally camelCase\n  'copy', 'cut', 'paste', 'click', 'change', 'contextmenu', 'reset', 'submit'];\n  function isDiscreteEventThatRequiresHydration(eventType) {\n    return discreteReplayableEvents.indexOf(eventType) > -1;\n  }\n\n  function createQueuedReplayableEvent(blockedOn, domEventName, eventSystemFlags, targetContainer, nativeEvent) {\n    return {\n      blockedOn: blockedOn,\n      domEventName: domEventName,\n      eventSystemFlags: eventSystemFlags,\n      nativeEvent: nativeEvent,\n      targetContainers: [targetContainer]\n    };\n  }\n\n  function clearIfContinuousEvent(domEventName, nativeEvent) {\n    switch (domEventName) {\n      case 'focusin':\n      case 'focusout':\n        queuedFocus = null;\n        break;\n\n      case 'dragenter':\n      case 'dragleave':\n        queuedDrag = null;\n        break;\n\n      case 'mouseover':\n      case 'mouseout':\n        queuedMouse = null;\n        break;\n\n      case 'pointerover':\n      case 'pointerout':\n        {\n          var pointerId = nativeEvent.pointerId;\n          queuedPointers.delete(pointerId);\n          break;\n        }\n\n      case 'gotpointercapture':\n      case 'lostpointercapture':\n        {\n          var _pointerId = nativeEvent.pointerId;\n          queuedPointerCaptures.delete(_pointerId);\n          break;\n        }\n    }\n  }\n\n  function accumulateOrCreateContinuousQueuedReplayableEvent(existingQueuedEvent, blockedOn, domEventName, eventSystemFlags, targetContainer, nativeEvent) {\n    if (existingQueuedEvent === null || existingQueuedEvent.nativeEvent !== nativeEvent) {\n      var queuedEvent = createQueuedReplayableEvent(blockedOn, domEventName, eventSystemFlags, targetContainer, nativeEvent);\n\n      if (blockedOn !== null) {\n        var _fiber2 = getInstanceFromNode(blockedOn);\n\n        if (_fiber2 !== null) {\n          // Attempt to increase the priority of this target.\n          attemptContinuousHydration(_fiber2);\n        }\n      }\n\n      return queuedEvent;\n    } // If we have already queued this exact event, then it's because\n    // the different event systems have different DOM event listeners.\n    // We can accumulate the flags, and the targetContainers, and\n    // store a single event to be replayed.\n\n\n    existingQueuedEvent.eventSystemFlags |= eventSystemFlags;\n    var targetContainers = existingQueuedEvent.targetContainers;\n\n    if (targetContainer !== null && targetContainers.indexOf(targetContainer) === -1) {\n      targetContainers.push(targetContainer);\n    }\n\n    return existingQueuedEvent;\n  }\n\n  function queueIfContinuousEvent(blockedOn, domEventName, eventSystemFlags, targetContainer, nativeEvent) {\n    // These set relatedTarget to null because the replayed event will be treated as if we\n    // moved from outside the window (no target) onto the target once it hydrates.\n    // Instead of mutating we could clone the event.\n    switch (domEventName) {\n      case 'focusin':\n        {\n          var focusEvent = nativeEvent;\n          queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent(queuedFocus, blockedOn, domEventName, eventSystemFlags, targetContainer, focusEvent);\n          return true;\n        }\n\n      case 'dragenter':\n        {\n          var dragEvent = nativeEvent;\n          queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent(queuedDrag, blockedOn, domEventName, eventSystemFlags, targetContainer, dragEvent);\n          return true;\n        }\n\n      case 'mouseover':\n        {\n          var mouseEvent = nativeEvent;\n          queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent(queuedMouse, blockedOn, domEventName, eventSystemFlags, targetContainer, mouseEvent);\n          return true;\n        }\n\n      case 'pointerover':\n        {\n          var pointerEvent = nativeEvent;\n          var pointerId = pointerEvent.pointerId;\n          queuedPointers.set(pointerId, accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointers.get(pointerId) || null, blockedOn, domEventName, eventSystemFlags, targetContainer, pointerEvent));\n          return true;\n        }\n\n      case 'gotpointercapture':\n        {\n          var _pointerEvent = nativeEvent;\n          var _pointerId2 = _pointerEvent.pointerId;\n          queuedPointerCaptures.set(_pointerId2, accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointerCaptures.get(_pointerId2) || null, blockedOn, domEventName, eventSystemFlags, targetContainer, _pointerEvent));\n          return true;\n        }\n    }\n\n    return false;\n  } // Check if this target is unblocked. Returns true if it's unblocked.\n\n  function attemptExplicitHydrationTarget(queuedTarget) {\n    // TODO: This function shares a lot of logic with findInstanceBlockingEvent.\n    // Try to unify them. It's a bit tricky since it would require two return\n    // values.\n    var targetInst = getClosestInstanceFromNode(queuedTarget.target);\n\n    if (targetInst !== null) {\n      var nearestMounted = getNearestMountedFiber(targetInst);\n\n      if (nearestMounted !== null) {\n        var tag = nearestMounted.tag;\n\n        if (tag === SuspenseComponent) {\n          var instance = getSuspenseInstanceFromFiber(nearestMounted);\n\n          if (instance !== null) {\n            // We're blocked on hydrating this boundary.\n            // Increase its priority.\n            queuedTarget.blockedOn = instance;\n            attemptHydrationAtPriority(queuedTarget.priority, function () {\n              attemptHydrationAtCurrentPriority(nearestMounted);\n            });\n            return;\n          }\n        } else if (tag === HostRoot) {\n          var root = nearestMounted.stateNode;\n\n          if (isRootDehydrated(root)) {\n            queuedTarget.blockedOn = getContainerFromFiber(nearestMounted); // We don't currently have a way to increase the priority of\n            // a root other than sync.\n\n            return;\n          }\n        }\n      }\n    }\n\n    queuedTarget.blockedOn = null;\n  }\n\n  function queueExplicitHydrationTarget(target) {\n    // TODO: This will read the priority if it's dispatched by the React\n    // event system but not native events. Should read window.event.type, like\n    // we do for updates (getCurrentEventPriority).\n    var updatePriority = getCurrentUpdatePriority$1();\n    var queuedTarget = {\n      blockedOn: null,\n      target: target,\n      priority: updatePriority\n    };\n    var i = 0;\n\n    for (; i < queuedExplicitHydrationTargets.length; i++) {\n      // Stop once we hit the first target with lower priority than\n      if (!isHigherEventPriority(updatePriority, queuedExplicitHydrationTargets[i].priority)) {\n        break;\n      }\n    }\n\n    queuedExplicitHydrationTargets.splice(i, 0, queuedTarget);\n\n    if (i === 0) {\n      attemptExplicitHydrationTarget(queuedTarget);\n    }\n  }\n\n  function attemptReplayContinuousQueuedEvent(queuedEvent) {\n    if (queuedEvent.blockedOn !== null) {\n      return false;\n    }\n\n    var targetContainers = queuedEvent.targetContainers;\n\n    while (targetContainers.length > 0) {\n      var targetContainer = targetContainers[0];\n      var nextBlockedOn = findInstanceBlockingEvent(queuedEvent.domEventName, queuedEvent.eventSystemFlags, targetContainer, queuedEvent.nativeEvent);\n\n      if (nextBlockedOn === null) {\n        {\n          var nativeEvent = queuedEvent.nativeEvent;\n          var nativeEventClone = new nativeEvent.constructor(nativeEvent.type, nativeEvent);\n          setReplayingEvent(nativeEventClone);\n          nativeEvent.target.dispatchEvent(nativeEventClone);\n          resetReplayingEvent();\n        }\n      } else {\n        // We're still blocked. Try again later.\n        var _fiber3 = getInstanceFromNode(nextBlockedOn);\n\n        if (_fiber3 !== null) {\n          attemptContinuousHydration(_fiber3);\n        }\n\n        queuedEvent.blockedOn = nextBlockedOn;\n        return false;\n      } // This target container was successfully dispatched. Try the next.\n\n\n      targetContainers.shift();\n    }\n\n    return true;\n  }\n\n  function attemptReplayContinuousQueuedEventInMap(queuedEvent, key, map) {\n    if (attemptReplayContinuousQueuedEvent(queuedEvent)) {\n      map.delete(key);\n    }\n  }\n\n  function replayUnblockedEvents() {\n    hasScheduledReplayAttempt = false;\n\n\n    if (queuedFocus !== null && attemptReplayContinuousQueuedEvent(queuedFocus)) {\n      queuedFocus = null;\n    }\n\n    if (queuedDrag !== null && attemptReplayContinuousQueuedEvent(queuedDrag)) {\n      queuedDrag = null;\n    }\n\n    if (queuedMouse !== null && attemptReplayContinuousQueuedEvent(queuedMouse)) {\n      queuedMouse = null;\n    }\n\n    queuedPointers.forEach(attemptReplayContinuousQueuedEventInMap);\n    queuedPointerCaptures.forEach(attemptReplayContinuousQueuedEventInMap);\n  }\n\n  function scheduleCallbackIfUnblocked(queuedEvent, unblocked) {\n    if (queuedEvent.blockedOn === unblocked) {\n      queuedEvent.blockedOn = null;\n\n      if (!hasScheduledReplayAttempt) {\n        hasScheduledReplayAttempt = true; // Schedule a callback to attempt replaying as many events as are\n        // now unblocked. This first might not actually be unblocked yet.\n        // We could check it early to avoid scheduling an unnecessary callback.\n\n        unstable_scheduleCallback(unstable_NormalPriority, replayUnblockedEvents);\n      }\n    }\n  }\n\n  function retryIfBlockedOn(unblocked) {\n    // Mark anything that was blocked on this as no longer blocked\n    // and eligible for a replay.\n    if (queuedDiscreteEvents.length > 0) {\n      scheduleCallbackIfUnblocked(queuedDiscreteEvents[0], unblocked); // This is a exponential search for each boundary that commits. I think it's\n      // worth it because we expect very few discrete events to queue up and once\n      // we are actually fully unblocked it will be fast to replay them.\n\n      for (var i = 1; i < queuedDiscreteEvents.length; i++) {\n        var queuedEvent = queuedDiscreteEvents[i];\n\n        if (queuedEvent.blockedOn === unblocked) {\n          queuedEvent.blockedOn = null;\n        }\n      }\n    }\n\n    if (queuedFocus !== null) {\n      scheduleCallbackIfUnblocked(queuedFocus, unblocked);\n    }\n\n    if (queuedDrag !== null) {\n      scheduleCallbackIfUnblocked(queuedDrag, unblocked);\n    }\n\n    if (queuedMouse !== null) {\n      scheduleCallbackIfUnblocked(queuedMouse, unblocked);\n    }\n\n    var unblock = function (queuedEvent) {\n      return scheduleCallbackIfUnblocked(queuedEvent, unblocked);\n    };\n\n    queuedPointers.forEach(unblock);\n    queuedPointerCaptures.forEach(unblock);\n\n    for (var _i = 0; _i < queuedExplicitHydrationTargets.length; _i++) {\n      var queuedTarget = queuedExplicitHydrationTargets[_i];\n\n      if (queuedTarget.blockedOn === unblocked) {\n        queuedTarget.blockedOn = null;\n      }\n    }\n\n    while (queuedExplicitHydrationTargets.length > 0) {\n      var nextExplicitTarget = queuedExplicitHydrationTargets[0];\n\n      if (nextExplicitTarget.blockedOn !== null) {\n        // We're still blocked.\n        break;\n      } else {\n        attemptExplicitHydrationTarget(nextExplicitTarget);\n\n        if (nextExplicitTarget.blockedOn === null) {\n          // We're unblocked.\n          queuedExplicitHydrationTargets.shift();\n        }\n      }\n    }\n  }\n\n  var ReactCurrentBatchConfig = ReactSharedInternals.ReactCurrentBatchConfig; // TODO: can we stop exporting these?\n\n  var _enabled = true; // This is exported in FB builds for use by legacy FB layer infra.\n  // We'd like to remove this but it's not clear if this is safe.\n\n  function setEnabled(enabled) {\n    _enabled = !!enabled;\n  }\n  function isEnabled() {\n    return _enabled;\n  }\n  function createEventListenerWrapperWithPriority(targetContainer, domEventName, eventSystemFlags) {\n    var eventPriority = getEventPriority(domEventName);\n    var listenerWrapper;\n\n    switch (eventPriority) {\n      case DiscreteEventPriority:\n        listenerWrapper = dispatchDiscreteEvent;\n        break;\n\n      case ContinuousEventPriority:\n        listenerWrapper = dispatchContinuousEvent;\n        break;\n\n      case DefaultEventPriority:\n      default:\n        listenerWrapper = dispatchEvent;\n        break;\n    }\n\n    return listenerWrapper.bind(null, domEventName, eventSystemFlags, targetContainer);\n  }\n\n  function dispatchDiscreteEvent(domEventName, eventSystemFlags, container, nativeEvent) {\n    var previousPriority = getCurrentUpdatePriority();\n    var prevTransition = ReactCurrentBatchConfig.transition;\n    ReactCurrentBatchConfig.transition = null;\n\n    try {\n      setCurrentUpdatePriority(DiscreteEventPriority);\n      dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent);\n    } finally {\n      setCurrentUpdatePriority(previousPriority);\n      ReactCurrentBatchConfig.transition = prevTransition;\n    }\n  }\n\n  function dispatchContinuousEvent(domEventName, eventSystemFlags, container, nativeEvent) {\n    var previousPriority = getCurrentUpdatePriority();\n    var prevTransition = ReactCurrentBatchConfig.transition;\n    ReactCurrentBatchConfig.transition = null;\n\n    try {\n      setCurrentUpdatePriority(ContinuousEventPriority);\n      dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent);\n    } finally {\n      setCurrentUpdatePriority(previousPriority);\n      ReactCurrentBatchConfig.transition = prevTransition;\n    }\n  }\n\n  function dispatchEvent(domEventName, eventSystemFlags, targetContainer, nativeEvent) {\n    if (!_enabled) {\n      return;\n    }\n\n    {\n      dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay(domEventName, eventSystemFlags, targetContainer, nativeEvent);\n    }\n  }\n\n  function dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay(domEventName, eventSystemFlags, targetContainer, nativeEvent) {\n    var blockedOn = findInstanceBlockingEvent(domEventName, eventSystemFlags, targetContainer, nativeEvent);\n\n    if (blockedOn === null) {\n      dispatchEventForPluginEventSystem(domEventName, eventSystemFlags, nativeEvent, return_targetInst, targetContainer);\n      clearIfContinuousEvent(domEventName, nativeEvent);\n      return;\n    }\n\n    if (queueIfContinuousEvent(blockedOn, domEventName, eventSystemFlags, targetContainer, nativeEvent)) {\n      nativeEvent.stopPropagation();\n      return;\n    } // We need to clear only if we didn't queue because\n    // queueing is accumulative.\n\n\n    clearIfContinuousEvent(domEventName, nativeEvent);\n\n    if (eventSystemFlags & IS_CAPTURE_PHASE && isDiscreteEventThatRequiresHydration(domEventName)) {\n      while (blockedOn !== null) {\n        var fiber = getInstanceFromNode(blockedOn);\n\n        if (fiber !== null) {\n          attemptSynchronousHydration(fiber);\n        }\n\n        var nextBlockedOn = findInstanceBlockingEvent(domEventName, eventSystemFlags, targetContainer, nativeEvent);\n\n        if (nextBlockedOn === null) {\n          dispatchEventForPluginEventSystem(domEventName, eventSystemFlags, nativeEvent, return_targetInst, targetContainer);\n        }\n\n        if (nextBlockedOn === blockedOn) {\n          break;\n        }\n\n        blockedOn = nextBlockedOn;\n      }\n\n      if (blockedOn !== null) {\n        nativeEvent.stopPropagation();\n      }\n\n      return;\n    } // This is not replayable so we'll invoke it but without a target,\n    // in case the event system needs to trace it.\n\n\n    dispatchEventForPluginEventSystem(domEventName, eventSystemFlags, nativeEvent, null, targetContainer);\n  }\n\n  var return_targetInst = null; // Returns a SuspenseInstance or Container if it's blocked.\n  // The return_targetInst field above is conceptually part of the return value.\n\n  function findInstanceBlockingEvent(domEventName, eventSystemFlags, targetContainer, nativeEvent) {\n    // TODO: Warn if _enabled is false.\n    return_targetInst = null;\n    var nativeEventTarget = getEventTarget(nativeEvent);\n    var targetInst = getClosestInstanceFromNode(nativeEventTarget);\n\n    if (targetInst !== null) {\n      var nearestMounted = getNearestMountedFiber(targetInst);\n\n      if (nearestMounted === null) {\n        // This tree has been unmounted already. Dispatch without a target.\n        targetInst = null;\n      } else {\n        var tag = nearestMounted.tag;\n\n        if (tag === SuspenseComponent) {\n          var instance = getSuspenseInstanceFromFiber(nearestMounted);\n\n          if (instance !== null) {\n            // Queue the event to be replayed later. Abort dispatching since we\n            // don't want this event dispatched twice through the event system.\n            // TODO: If this is the first discrete event in the queue. Schedule an increased\n            // priority for this boundary.\n            return instance;\n          } // This shouldn't happen, something went wrong but to avoid blocking\n          // the whole system, dispatch the event without a target.\n          // TODO: Warn.\n\n\n          targetInst = null;\n        } else if (tag === HostRoot) {\n          var root = nearestMounted.stateNode;\n\n          if (isRootDehydrated(root)) {\n            // If this happens during a replay something went wrong and it might block\n            // the whole system.\n            return getContainerFromFiber(nearestMounted);\n          }\n\n          targetInst = null;\n        } else if (nearestMounted !== targetInst) {\n          // If we get an event (ex: img onload) before committing that\n          // component's mount, ignore it for now (that is, treat it as if it was an\n          // event on a non-React tree). We might also consider queueing events and\n          // dispatching them after the mount.\n          targetInst = null;\n        }\n      }\n    }\n\n    return_targetInst = targetInst; // We're not blocked on anything.\n\n    return null;\n  }\n  function getEventPriority(domEventName) {\n    switch (domEventName) {\n      // Used by SimpleEventPlugin:\n      case 'cancel':\n      case 'click':\n      case 'close':\n      case 'contextmenu':\n      case 'copy':\n      case 'cut':\n      case 'auxclick':\n      case 'dblclick':\n      case 'dragend':\n      case 'dragstart':\n      case 'drop':\n      case 'focusin':\n      case 'focusout':\n      case 'input':\n      case 'invalid':\n      case 'keydown':\n      case 'keypress':\n      case 'keyup':\n      case 'mousedown':\n      case 'mouseup':\n      case 'paste':\n      case 'pause':\n      case 'play':\n      case 'pointercancel':\n      case 'pointerdown':\n      case 'pointerup':\n      case 'ratechange':\n      case 'reset':\n      case 'resize':\n      case 'seeked':\n      case 'submit':\n      case 'touchcancel':\n      case 'touchend':\n      case 'touchstart':\n      case 'volumechange': // Used by polyfills:\n      // eslint-disable-next-line no-fallthrough\n\n      case 'change':\n      case 'selectionchange':\n      case 'textInput':\n      case 'compositionstart':\n      case 'compositionend':\n      case 'compositionupdate': // Only enableCreateEventHandleAPI:\n      // eslint-disable-next-line no-fallthrough\n\n      case 'beforeblur':\n      case 'afterblur': // Not used by React but could be by user code:\n      // eslint-disable-next-line no-fallthrough\n\n      case 'beforeinput':\n      case 'blur':\n      case 'fullscreenchange':\n      case 'focus':\n      case 'hashchange':\n      case 'popstate':\n      case 'select':\n      case 'selectstart':\n        return DiscreteEventPriority;\n\n      case 'drag':\n      case 'dragenter':\n      case 'dragexit':\n      case 'dragleave':\n      case 'dragover':\n      case 'mousemove':\n      case 'mouseout':\n      case 'mouseover':\n      case 'pointermove':\n      case 'pointerout':\n      case 'pointerover':\n      case 'scroll':\n      case 'toggle':\n      case 'touchmove':\n      case 'wheel': // Not used by React but could be by user code:\n      // eslint-disable-next-line no-fallthrough\n\n      case 'mouseenter':\n      case 'mouseleave':\n      case 'pointerenter':\n      case 'pointerleave':\n        return ContinuousEventPriority;\n\n      case 'message':\n        {\n          // We might be in the Scheduler callback.\n          // Eventually this mechanism will be replaced by a check\n          // of the current priority on the native scheduler.\n          var schedulerPriority = getCurrentPriorityLevel();\n\n          switch (schedulerPriority) {\n            case ImmediatePriority:\n              return DiscreteEventPriority;\n\n            case UserBlockingPriority:\n              return ContinuousEventPriority;\n\n            case NormalPriority:\n            case LowPriority:\n              // TODO: Handle LowSchedulerPriority, somehow. Maybe the same lane as hydration.\n              return DefaultEventPriority;\n\n            case IdlePriority:\n              return IdleEventPriority;\n\n            default:\n              return DefaultEventPriority;\n          }\n        }\n\n      default:\n        return DefaultEventPriority;\n    }\n  }\n\n  function addEventBubbleListener(target, eventType, listener) {\n    target.addEventListener(eventType, listener, false);\n    return listener;\n  }\n  function addEventCaptureListener(target, eventType, listener) {\n    target.addEventListener(eventType, listener, true);\n    return listener;\n  }\n  function addEventCaptureListenerWithPassiveFlag(target, eventType, listener, passive) {\n    target.addEventListener(eventType, listener, {\n      capture: true,\n      passive: passive\n    });\n    return listener;\n  }\n  function addEventBubbleListenerWithPassiveFlag(target, eventType, listener, passive) {\n    target.addEventListener(eventType, listener, {\n      passive: passive\n    });\n    return listener;\n  }\n\n  /**\n   * These variables store information about text content of a target node,\n   * allowing comparison of content before and after a given event.\n   *\n   * Identify the node where selection currently begins, then observe\n   * both its text content and its current position in the DOM. Since the\n   * browser may natively replace the target node during composition, we can\n   * use its position to find its replacement.\n   *\n   *\n   */\n  var root = null;\n  var startText = null;\n  var fallbackText = null;\n  function initialize(nativeEventTarget) {\n    root = nativeEventTarget;\n    startText = getText();\n    return true;\n  }\n  function reset() {\n    root = null;\n    startText = null;\n    fallbackText = null;\n  }\n  function getData() {\n    if (fallbackText) {\n      return fallbackText;\n    }\n\n    var start;\n    var startValue = startText;\n    var startLength = startValue.length;\n    var end;\n    var endValue = getText();\n    var endLength = endValue.length;\n\n    for (start = 0; start < startLength; start++) {\n      if (startValue[start] !== endValue[start]) {\n        break;\n      }\n    }\n\n    var minEnd = startLength - start;\n\n    for (end = 1; end <= minEnd; end++) {\n      if (startValue[startLength - end] !== endValue[endLength - end]) {\n        break;\n      }\n    }\n\n    var sliceTail = end > 1 ? 1 - end : undefined;\n    fallbackText = endValue.slice(start, sliceTail);\n    return fallbackText;\n  }\n  function getText() {\n    if ('value' in root) {\n      return root.value;\n    }\n\n    return root.textContent;\n  }\n\n  /**\n   * `charCode` represents the actual \"character code\" and is safe to use with\n   * `String.fromCharCode`. As such, only keys that correspond to printable\n   * characters produce a valid `charCode`, the only exception to this is Enter.\n   * The Tab-key is considered non-printable and does not have a `charCode`,\n   * presumably because it does not produce a tab-character in browsers.\n   *\n   * @param {object} nativeEvent Native browser event.\n   * @return {number} Normalized `charCode` property.\n   */\n  function getEventCharCode(nativeEvent) {\n    var charCode;\n    var keyCode = nativeEvent.keyCode;\n\n    if ('charCode' in nativeEvent) {\n      charCode = nativeEvent.charCode; // FF does not set `charCode` for the Enter-key, check against `keyCode`.\n\n      if (charCode === 0 && keyCode === 13) {\n        charCode = 13;\n      }\n    } else {\n      // IE8 does not implement `charCode`, but `keyCode` has the correct value.\n      charCode = keyCode;\n    } // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux)\n    // report Enter as charCode 10 when ctrl is pressed.\n\n\n    if (charCode === 10) {\n      charCode = 13;\n    } // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.\n    // Must not discard the (non-)printable Enter-key.\n\n\n    if (charCode >= 32 || charCode === 13) {\n      return charCode;\n    }\n\n    return 0;\n  }\n\n  function functionThatReturnsTrue() {\n    return true;\n  }\n\n  function functionThatReturnsFalse() {\n    return false;\n  } // This is intentionally a factory so that we have different returned constructors.\n  // If we had a single constructor, it would be megamorphic and engines would deopt.\n\n\n  function createSyntheticEvent(Interface) {\n    /**\n     * Synthetic events are dispatched by event plugins, typically in response to a\n     * top-level event delegation handler.\n     *\n     * These systems should generally use pooling to reduce the frequency of garbage\n     * collection. The system should check `isPersistent` to determine whether the\n     * event should be released into the pool after being dispatched. Users that\n     * need a persisted event should invoke `persist`.\n     *\n     * Synthetic events (and subclasses) implement the DOM Level 3 Events API by\n     * normalizing browser quirks. Subclasses do not necessarily have to implement a\n     * DOM interface; custom application-specific events can also subclass this.\n     */\n    function SyntheticBaseEvent(reactName, reactEventType, targetInst, nativeEvent, nativeEventTarget) {\n      this._reactName = reactName;\n      this._targetInst = targetInst;\n      this.type = reactEventType;\n      this.nativeEvent = nativeEvent;\n      this.target = nativeEventTarget;\n      this.currentTarget = null;\n\n      for (var _propName in Interface) {\n        if (!Interface.hasOwnProperty(_propName)) {\n          continue;\n        }\n\n        var normalize = Interface[_propName];\n\n        if (normalize) {\n          this[_propName] = normalize(nativeEvent);\n        } else {\n          this[_propName] = nativeEvent[_propName];\n        }\n      }\n\n      var defaultPrevented = nativeEvent.defaultPrevented != null ? nativeEvent.defaultPrevented : nativeEvent.returnValue === false;\n\n      if (defaultPrevented) {\n        this.isDefaultPrevented = functionThatReturnsTrue;\n      } else {\n        this.isDefaultPrevented = functionThatReturnsFalse;\n      }\n\n      this.isPropagationStopped = functionThatReturnsFalse;\n      return this;\n    }\n\n    assign(SyntheticBaseEvent.prototype, {\n      preventDefault: function () {\n        this.defaultPrevented = true;\n        var event = this.nativeEvent;\n\n        if (!event) {\n          return;\n        }\n\n        if (event.preventDefault) {\n          event.preventDefault(); // $FlowFixMe - flow is not aware of `unknown` in IE\n        } else if (typeof event.returnValue !== 'unknown') {\n          event.returnValue = false;\n        }\n\n        this.isDefaultPrevented = functionThatReturnsTrue;\n      },\n      stopPropagation: function () {\n        var event = this.nativeEvent;\n\n        if (!event) {\n          return;\n        }\n\n        if (event.stopPropagation) {\n          event.stopPropagation(); // $FlowFixMe - flow is not aware of `unknown` in IE\n        } else if (typeof event.cancelBubble !== 'unknown') {\n          // The ChangeEventPlugin registers a \"propertychange\" event for\n          // IE. This event does not support bubbling or cancelling, and\n          // any references to cancelBubble throw \"Member not found\".  A\n          // typeof check of \"unknown\" circumvents this issue (and is also\n          // IE specific).\n          event.cancelBubble = true;\n        }\n\n        this.isPropagationStopped = functionThatReturnsTrue;\n      },\n\n      /**\n       * We release all dispatched `SyntheticEvent`s after each event loop, adding\n       * them back into the pool. This allows a way to hold onto a reference that\n       * won't be added back into the pool.\n       */\n      persist: function () {// Modern event system doesn't use pooling.\n      },\n\n      /**\n       * Checks if this event should be released back into the pool.\n       *\n       * @return {boolean} True if this should not be released, false otherwise.\n       */\n      isPersistent: functionThatReturnsTrue\n    });\n    return SyntheticBaseEvent;\n  }\n  /**\n   * @interface Event\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/\n   */\n\n\n  var EventInterface = {\n    eventPhase: 0,\n    bubbles: 0,\n    cancelable: 0,\n    timeStamp: function (event) {\n      return event.timeStamp || Date.now();\n    },\n    defaultPrevented: 0,\n    isTrusted: 0\n  };\n  var SyntheticEvent = createSyntheticEvent(EventInterface);\n\n  var UIEventInterface = assign({}, EventInterface, {\n    view: 0,\n    detail: 0\n  });\n\n  var SyntheticUIEvent = createSyntheticEvent(UIEventInterface);\n  var lastMovementX;\n  var lastMovementY;\n  var lastMouseEvent;\n\n  function updateMouseMovementPolyfillState(event) {\n    if (event !== lastMouseEvent) {\n      if (lastMouseEvent && event.type === 'mousemove') {\n        lastMovementX = event.screenX - lastMouseEvent.screenX;\n        lastMovementY = event.screenY - lastMouseEvent.screenY;\n      } else {\n        lastMovementX = 0;\n        lastMovementY = 0;\n      }\n\n      lastMouseEvent = event;\n    }\n  }\n  /**\n   * @interface MouseEvent\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/\n   */\n\n\n  var MouseEventInterface = assign({}, UIEventInterface, {\n    screenX: 0,\n    screenY: 0,\n    clientX: 0,\n    clientY: 0,\n    pageX: 0,\n    pageY: 0,\n    ctrlKey: 0,\n    shiftKey: 0,\n    altKey: 0,\n    metaKey: 0,\n    getModifierState: getEventModifierState,\n    button: 0,\n    buttons: 0,\n    relatedTarget: function (event) {\n      if (event.relatedTarget === undefined) return event.fromElement === event.srcElement ? event.toElement : event.fromElement;\n      return event.relatedTarget;\n    },\n    movementX: function (event) {\n      if ('movementX' in event) {\n        return event.movementX;\n      }\n\n      updateMouseMovementPolyfillState(event);\n      return lastMovementX;\n    },\n    movementY: function (event) {\n      if ('movementY' in event) {\n        return event.movementY;\n      } // Don't need to call updateMouseMovementPolyfillState() here\n      // because it's guaranteed to have already run when movementX\n      // was copied.\n\n\n      return lastMovementY;\n    }\n  });\n\n  var SyntheticMouseEvent = createSyntheticEvent(MouseEventInterface);\n  /**\n   * @interface DragEvent\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/\n   */\n\n  var DragEventInterface = assign({}, MouseEventInterface, {\n    dataTransfer: 0\n  });\n\n  var SyntheticDragEvent = createSyntheticEvent(DragEventInterface);\n  /**\n   * @interface FocusEvent\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/\n   */\n\n  var FocusEventInterface = assign({}, UIEventInterface, {\n    relatedTarget: 0\n  });\n\n  var SyntheticFocusEvent = createSyntheticEvent(FocusEventInterface);\n  /**\n   * @interface Event\n   * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent\n   */\n\n  var AnimationEventInterface = assign({}, EventInterface, {\n    animationName: 0,\n    elapsedTime: 0,\n    pseudoElement: 0\n  });\n\n  var SyntheticAnimationEvent = createSyntheticEvent(AnimationEventInterface);\n  /**\n   * @interface Event\n   * @see http://www.w3.org/TR/clipboard-apis/\n   */\n\n  var ClipboardEventInterface = assign({}, EventInterface, {\n    clipboardData: function (event) {\n      return 'clipboardData' in event ? event.clipboardData : window.clipboardData;\n    }\n  });\n\n  var SyntheticClipboardEvent = createSyntheticEvent(ClipboardEventInterface);\n  /**\n   * @interface Event\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents\n   */\n\n  var CompositionEventInterface = assign({}, EventInterface, {\n    data: 0\n  });\n\n  var SyntheticCompositionEvent = createSyntheticEvent(CompositionEventInterface);\n  /**\n   * @interface Event\n   * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105\n   *      /#events-inputevents\n   */\n  // Happens to share the same list for now.\n\n  var SyntheticInputEvent = SyntheticCompositionEvent;\n  /**\n   * Normalization of deprecated HTML5 `key` values\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names\n   */\n\n  var normalizeKey = {\n    Esc: 'Escape',\n    Spacebar: ' ',\n    Left: 'ArrowLeft',\n    Up: 'ArrowUp',\n    Right: 'ArrowRight',\n    Down: 'ArrowDown',\n    Del: 'Delete',\n    Win: 'OS',\n    Menu: 'ContextMenu',\n    Apps: 'ContextMenu',\n    Scroll: 'ScrollLock',\n    MozPrintableKey: 'Unidentified'\n  };\n  /**\n   * Translation from legacy `keyCode` to HTML5 `key`\n   * Only special keys supported, all others depend on keyboard layout or browser\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names\n   */\n\n  var translateToKey = {\n    '8': 'Backspace',\n    '9': 'Tab',\n    '12': 'Clear',\n    '13': 'Enter',\n    '16': 'Shift',\n    '17': 'Control',\n    '18': 'Alt',\n    '19': 'Pause',\n    '20': 'CapsLock',\n    '27': 'Escape',\n    '32': ' ',\n    '33': 'PageUp',\n    '34': 'PageDown',\n    '35': 'End',\n    '36': 'Home',\n    '37': 'ArrowLeft',\n    '38': 'ArrowUp',\n    '39': 'ArrowRight',\n    '40': 'ArrowDown',\n    '45': 'Insert',\n    '46': 'Delete',\n    '112': 'F1',\n    '113': 'F2',\n    '114': 'F3',\n    '115': 'F4',\n    '116': 'F5',\n    '117': 'F6',\n    '118': 'F7',\n    '119': 'F8',\n    '120': 'F9',\n    '121': 'F10',\n    '122': 'F11',\n    '123': 'F12',\n    '144': 'NumLock',\n    '145': 'ScrollLock',\n    '224': 'Meta'\n  };\n  /**\n   * @param {object} nativeEvent Native browser event.\n   * @return {string} Normalized `key` property.\n   */\n\n  function getEventKey(nativeEvent) {\n    if (nativeEvent.key) {\n      // Normalize inconsistent values reported by browsers due to\n      // implementations of a working draft specification.\n      // FireFox implements `key` but returns `MozPrintableKey` for all\n      // printable characters (normalized to `Unidentified`), ignore it.\n      var key = normalizeKey[nativeEvent.key] || nativeEvent.key;\n\n      if (key !== 'Unidentified') {\n        return key;\n      }\n    } // Browser does not implement `key`, polyfill as much of it as we can.\n\n\n    if (nativeEvent.type === 'keypress') {\n      var charCode = getEventCharCode(nativeEvent); // The enter-key is technically both printable and non-printable and can\n      // thus be captured by `keypress`, no other non-printable key should.\n\n      return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);\n    }\n\n    if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {\n      // While user keyboard layout determines the actual meaning of each\n      // `keyCode` value, almost all function keys have a universal value.\n      return translateToKey[nativeEvent.keyCode] || 'Unidentified';\n    }\n\n    return '';\n  }\n  /**\n   * Translation from modifier key to the associated property in the event.\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers\n   */\n\n\n  var modifierKeyToProp = {\n    Alt: 'altKey',\n    Control: 'ctrlKey',\n    Meta: 'metaKey',\n    Shift: 'shiftKey'\n  }; // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support\n  // getModifierState. If getModifierState is not supported, we map it to a set of\n  // modifier keys exposed by the event. In this case, Lock-keys are not supported.\n\n  function modifierStateGetter(keyArg) {\n    var syntheticEvent = this;\n    var nativeEvent = syntheticEvent.nativeEvent;\n\n    if (nativeEvent.getModifierState) {\n      return nativeEvent.getModifierState(keyArg);\n    }\n\n    var keyProp = modifierKeyToProp[keyArg];\n    return keyProp ? !!nativeEvent[keyProp] : false;\n  }\n\n  function getEventModifierState(nativeEvent) {\n    return modifierStateGetter;\n  }\n  /**\n   * @interface KeyboardEvent\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/\n   */\n\n\n  var KeyboardEventInterface = assign({}, UIEventInterface, {\n    key: getEventKey,\n    code: 0,\n    location: 0,\n    ctrlKey: 0,\n    shiftKey: 0,\n    altKey: 0,\n    metaKey: 0,\n    repeat: 0,\n    locale: 0,\n    getModifierState: getEventModifierState,\n    // Legacy Interface\n    charCode: function (event) {\n      // `charCode` is the result of a KeyPress event and represents the value of\n      // the actual printable character.\n      // KeyPress is deprecated, but its replacement is not yet final and not\n      // implemented in any major browser. Only KeyPress has charCode.\n      if (event.type === 'keypress') {\n        return getEventCharCode(event);\n      }\n\n      return 0;\n    },\n    keyCode: function (event) {\n      // `keyCode` is the result of a KeyDown/Up event and represents the value of\n      // physical keyboard key.\n      // The actual meaning of the value depends on the users' keyboard layout\n      // which cannot be detected. Assuming that it is a US keyboard layout\n      // provides a surprisingly accurate mapping for US and European users.\n      // Due to this, it is left to the user to implement at this time.\n      if (event.type === 'keydown' || event.type === 'keyup') {\n        return event.keyCode;\n      }\n\n      return 0;\n    },\n    which: function (event) {\n      // `which` is an alias for either `keyCode` or `charCode` depending on the\n      // type of the event.\n      if (event.type === 'keypress') {\n        return getEventCharCode(event);\n      }\n\n      if (event.type === 'keydown' || event.type === 'keyup') {\n        return event.keyCode;\n      }\n\n      return 0;\n    }\n  });\n\n  var SyntheticKeyboardEvent = createSyntheticEvent(KeyboardEventInterface);\n  /**\n   * @interface PointerEvent\n   * @see http://www.w3.org/TR/pointerevents/\n   */\n\n  var PointerEventInterface = assign({}, MouseEventInterface, {\n    pointerId: 0,\n    width: 0,\n    height: 0,\n    pressure: 0,\n    tangentialPressure: 0,\n    tiltX: 0,\n    tiltY: 0,\n    twist: 0,\n    pointerType: 0,\n    isPrimary: 0\n  });\n\n  var SyntheticPointerEvent = createSyntheticEvent(PointerEventInterface);\n  /**\n   * @interface TouchEvent\n   * @see http://www.w3.org/TR/touch-events/\n   */\n\n  var TouchEventInterface = assign({}, UIEventInterface, {\n    touches: 0,\n    targetTouches: 0,\n    changedTouches: 0,\n    altKey: 0,\n    metaKey: 0,\n    ctrlKey: 0,\n    shiftKey: 0,\n    getModifierState: getEventModifierState\n  });\n\n  var SyntheticTouchEvent = createSyntheticEvent(TouchEventInterface);\n  /**\n   * @interface Event\n   * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-\n   * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent\n   */\n\n  var TransitionEventInterface = assign({}, EventInterface, {\n    propertyName: 0,\n    elapsedTime: 0,\n    pseudoElement: 0\n  });\n\n  var SyntheticTransitionEvent = createSyntheticEvent(TransitionEventInterface);\n  /**\n   * @interface WheelEvent\n   * @see http://www.w3.org/TR/DOM-Level-3-Events/\n   */\n\n  var WheelEventInterface = assign({}, MouseEventInterface, {\n    deltaX: function (event) {\n      return 'deltaX' in event ? event.deltaX : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).\n      'wheelDeltaX' in event ? -event.wheelDeltaX : 0;\n    },\n    deltaY: function (event) {\n      return 'deltaY' in event ? event.deltaY : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).\n      'wheelDeltaY' in event ? -event.wheelDeltaY : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).\n      'wheelDelta' in event ? -event.wheelDelta : 0;\n    },\n    deltaZ: 0,\n    // Browsers without \"deltaMode\" is reporting in raw wheel delta where one\n    // notch on the scroll is always +/- 120, roughly equivalent to pixels.\n    // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or\n    // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.\n    deltaMode: 0\n  });\n\n  var SyntheticWheelEvent = createSyntheticEvent(WheelEventInterface);\n\n  var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space\n\n  var START_KEYCODE = 229;\n  var canUseCompositionEvent = canUseDOM && 'CompositionEvent' in window;\n  var documentMode = null;\n\n  if (canUseDOM && 'documentMode' in document) {\n    documentMode = document.documentMode;\n  } // Webkit offers a very useful `textInput` event that can be used to\n  // directly represent `beforeInput`. The IE `textinput` event is not as\n  // useful, so we don't use it.\n\n\n  var canUseTextInputEvent = canUseDOM && 'TextEvent' in window && !documentMode; // In IE9+, we have access to composition events, but the data supplied\n  // by the native compositionend event may be incorrect. Japanese ideographic\n  // spaces, for instance (\\u3000) are not recorded correctly.\n\n  var useFallbackCompositionData = canUseDOM && (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11);\n  var SPACEBAR_CODE = 32;\n  var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);\n\n  function registerEvents() {\n    registerTwoPhaseEvent('onBeforeInput', ['compositionend', 'keypress', 'textInput', 'paste']);\n    registerTwoPhaseEvent('onCompositionEnd', ['compositionend', 'focusout', 'keydown', 'keypress', 'keyup', 'mousedown']);\n    registerTwoPhaseEvent('onCompositionStart', ['compositionstart', 'focusout', 'keydown', 'keypress', 'keyup', 'mousedown']);\n    registerTwoPhaseEvent('onCompositionUpdate', ['compositionupdate', 'focusout', 'keydown', 'keypress', 'keyup', 'mousedown']);\n  } // Track whether we've ever handled a keypress on the space key.\n\n\n  var hasSpaceKeypress = false;\n  /**\n   * Return whether a native keypress event is assumed to be a command.\n   * This is required because Firefox fires `keypress` events for key commands\n   * (cut, copy, select-all, etc.) even though no character is inserted.\n   */\n\n  function isKeypressCommand(nativeEvent) {\n    return (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) && // ctrlKey && altKey is equivalent to AltGr, and is not a command.\n    !(nativeEvent.ctrlKey && nativeEvent.altKey);\n  }\n  /**\n   * Translate native top level events into event types.\n   */\n\n\n  function getCompositionEventType(domEventName) {\n    switch (domEventName) {\n      case 'compositionstart':\n        return 'onCompositionStart';\n\n      case 'compositionend':\n        return 'onCompositionEnd';\n\n      case 'compositionupdate':\n        return 'onCompositionUpdate';\n    }\n  }\n  /**\n   * Does our fallback best-guess model think this event signifies that\n   * composition has begun?\n   */\n\n\n  function isFallbackCompositionStart(domEventName, nativeEvent) {\n    return domEventName === 'keydown' && nativeEvent.keyCode === START_KEYCODE;\n  }\n  /**\n   * Does our fallback mode think that this event is the end of composition?\n   */\n\n\n  function isFallbackCompositionEnd(domEventName, nativeEvent) {\n    switch (domEventName) {\n      case 'keyup':\n        // Command keys insert or clear IME input.\n        return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;\n\n      case 'keydown':\n        // Expect IME keyCode on each keydown. If we get any other\n        // code we must have exited earlier.\n        return nativeEvent.keyCode !== START_KEYCODE;\n\n      case 'keypress':\n      case 'mousedown':\n      case 'focusout':\n        // Events are not possible without cancelling IME.\n        return true;\n\n      default:\n        return false;\n    }\n  }\n  /**\n   * Google Input Tools provides composition data via a CustomEvent,\n   * with the `data` property populated in the `detail` object. If this\n   * is available on the event object, use it. If not, this is a plain\n   * composition event and we have nothing special to extract.\n   *\n   * @param {object} nativeEvent\n   * @return {?string}\n   */\n\n\n  function getDataFromCustomEvent(nativeEvent) {\n    var detail = nativeEvent.detail;\n\n    if (typeof detail === 'object' && 'data' in detail) {\n      return detail.data;\n    }\n\n    return null;\n  }\n  /**\n   * Check if a composition event was triggered by Korean IME.\n   * Our fallback mode does not work well with IE's Korean IME,\n   * so just use native composition events when Korean IME is used.\n   * Although CompositionEvent.locale property is deprecated,\n   * it is available in IE, where our fallback mode is enabled.\n   *\n   * @param {object} nativeEvent\n   * @return {boolean}\n   */\n\n\n  function isUsingKoreanIME(nativeEvent) {\n    return nativeEvent.locale === 'ko';\n  } // Track the current IME composition status, if any.\n\n\n  var isComposing = false;\n  /**\n   * @return {?object} A SyntheticCompositionEvent.\n   */\n\n  function extractCompositionEvent(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget) {\n    var eventType;\n    var fallbackData;\n\n    if (canUseCompositionEvent) {\n      eventType = getCompositionEventType(domEventName);\n    } else if (!isComposing) {\n      if (isFallbackCompositionStart(domEventName, nativeEvent)) {\n        eventType = 'onCompositionStart';\n      }\n    } else if (isFallbackCompositionEnd(domEventName, nativeEvent)) {\n      eventType = 'onCompositionEnd';\n    }\n\n    if (!eventType) {\n      return null;\n    }\n\n    if (useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)) {\n      // The current composition is stored statically and must not be\n      // overwritten while composition continues.\n      if (!isComposing && eventType === 'onCompositionStart') {\n        isComposing = initialize(nativeEventTarget);\n      } else if (eventType === 'onCompositionEnd') {\n        if (isComposing) {\n          fallbackData = getData();\n        }\n      }\n    }\n\n    var listeners = accumulateTwoPhaseListeners(targetInst, eventType);\n\n    if (listeners.length > 0) {\n      var event = new SyntheticCompositionEvent(eventType, domEventName, null, nativeEvent, nativeEventTarget);\n      dispatchQueue.push({\n        event: event,\n        listeners: listeners\n      });\n\n      if (fallbackData) {\n        // Inject data generated from fallback path into the synthetic event.\n        // This matches the property of native CompositionEventInterface.\n        event.data = fallbackData;\n      } else {\n        var customData = getDataFromCustomEvent(nativeEvent);\n\n        if (customData !== null) {\n          event.data = customData;\n        }\n      }\n    }\n  }\n\n  function getNativeBeforeInputChars(domEventName, nativeEvent) {\n    switch (domEventName) {\n      case 'compositionend':\n        return getDataFromCustomEvent(nativeEvent);\n\n      case 'keypress':\n        /**\n         * If native `textInput` events are available, our goal is to make\n         * use of them. However, there is a special case: the spacebar key.\n         * In Webkit, preventing default on a spacebar `textInput` event\n         * cancels character insertion, but it *also* causes the browser\n         * to fall back to its default spacebar behavior of scrolling the\n         * page.\n         *\n         * Tracking at:\n         * https://code.google.com/p/chromium/issues/detail?id=355103\n         *\n         * To avoid this issue, use the keypress event as if no `textInput`\n         * event is available.\n         */\n        var which = nativeEvent.which;\n\n        if (which !== SPACEBAR_CODE) {\n          return null;\n        }\n\n        hasSpaceKeypress = true;\n        return SPACEBAR_CHAR;\n\n      case 'textInput':\n        // Record the characters to be added to the DOM.\n        var chars = nativeEvent.data; // If it's a spacebar character, assume that we have already handled\n        // it at the keypress level and bail immediately. Android Chrome\n        // doesn't give us keycodes, so we need to ignore it.\n\n        if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {\n          return null;\n        }\n\n        return chars;\n\n      default:\n        // For other native event types, do nothing.\n        return null;\n    }\n  }\n  /**\n   * For browsers that do not provide the `textInput` event, extract the\n   * appropriate string to use for SyntheticInputEvent.\n   */\n\n\n  function getFallbackBeforeInputChars(domEventName, nativeEvent) {\n    // If we are currently composing (IME) and using a fallback to do so,\n    // try to extract the composed characters from the fallback object.\n    // If composition event is available, we extract a string only at\n    // compositionevent, otherwise extract it at fallback events.\n    if (isComposing) {\n      if (domEventName === 'compositionend' || !canUseCompositionEvent && isFallbackCompositionEnd(domEventName, nativeEvent)) {\n        var chars = getData();\n        reset();\n        isComposing = false;\n        return chars;\n      }\n\n      return null;\n    }\n\n    switch (domEventName) {\n      case 'paste':\n        // If a paste event occurs after a keypress, throw out the input\n        // chars. Paste events should not lead to BeforeInput events.\n        return null;\n\n      case 'keypress':\n        /**\n         * As of v27, Firefox may fire keypress events even when no character\n         * will be inserted. A few possibilities:\n         *\n         * - `which` is `0`. Arrow keys, Esc key, etc.\n         *\n         * - `which` is the pressed key code, but no char is available.\n         *   Ex: 'AltGr + d` in Polish. There is no modified character for\n         *   this key combination and no character is inserted into the\n         *   document, but FF fires the keypress for char code `100` anyway.\n         *   No `input` event will occur.\n         *\n         * - `which` is the pressed key code, but a command combination is\n         *   being used. Ex: `Cmd+C`. No character is inserted, and no\n         *   `input` event will occur.\n         */\n        if (!isKeypressCommand(nativeEvent)) {\n          // IE fires the `keypress` event when a user types an emoji via\n          // Touch keyboard of Windows.  In such a case, the `char` property\n          // holds an emoji character like `\\uD83D\\uDE0A`.  Because its length\n          // is 2, the property `which` does not represent an emoji correctly.\n          // In such a case, we directly return the `char` property instead of\n          // using `which`.\n          if (nativeEvent.char && nativeEvent.char.length > 1) {\n            return nativeEvent.char;\n          } else if (nativeEvent.which) {\n            return String.fromCharCode(nativeEvent.which);\n          }\n        }\n\n        return null;\n\n      case 'compositionend':\n        return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent) ? null : nativeEvent.data;\n\n      default:\n        return null;\n    }\n  }\n  /**\n   * Extract a SyntheticInputEvent for `beforeInput`, based on either native\n   * `textInput` or fallback behavior.\n   *\n   * @return {?object} A SyntheticInputEvent.\n   */\n\n\n  function extractBeforeInputEvent(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget) {\n    var chars;\n\n    if (canUseTextInputEvent) {\n      chars = getNativeBeforeInputChars(domEventName, nativeEvent);\n    } else {\n      chars = getFallbackBeforeInputChars(domEventName, nativeEvent);\n    } // If no characters are being inserted, no BeforeInput event should\n    // be fired.\n\n\n    if (!chars) {\n      return null;\n    }\n\n    var listeners = accumulateTwoPhaseListeners(targetInst, 'onBeforeInput');\n\n    if (listeners.length > 0) {\n      var event = new SyntheticInputEvent('onBeforeInput', 'beforeinput', null, nativeEvent, nativeEventTarget);\n      dispatchQueue.push({\n        event: event,\n        listeners: listeners\n      });\n      event.data = chars;\n    }\n  }\n  /**\n   * Create an `onBeforeInput` event to match\n   * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.\n   *\n   * This event plugin is based on the native `textInput` event\n   * available in Chrome, Safari, Opera, and IE. This event fires after\n   * `onKeyPress` and `onCompositionEnd`, but before `onInput`.\n   *\n   * `beforeInput` is spec'd but not implemented in any browsers, and\n   * the `input` event does not provide any useful information about what has\n   * actually been added, contrary to the spec. Thus, `textInput` is the best\n   * available event to identify the characters that have actually been inserted\n   * into the target node.\n   *\n   * This plugin is also responsible for emitting `composition` events, thus\n   * allowing us to share composition fallback code for both `beforeInput` and\n   * `composition` event types.\n   */\n\n\n  function extractEvents(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer) {\n    extractCompositionEvent(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget);\n    extractBeforeInputEvent(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget);\n  }\n\n  /**\n   * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary\n   */\n  var supportedInputTypes = {\n    color: true,\n    date: true,\n    datetime: true,\n    'datetime-local': true,\n    email: true,\n    month: true,\n    number: true,\n    password: true,\n    range: true,\n    search: true,\n    tel: true,\n    text: true,\n    time: true,\n    url: true,\n    week: true\n  };\n\n  function isTextInputElement(elem) {\n    var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();\n\n    if (nodeName === 'input') {\n      return !!supportedInputTypes[elem.type];\n    }\n\n    if (nodeName === 'textarea') {\n      return true;\n    }\n\n    return false;\n  }\n\n  /**\n   * Checks if an event is supported in the current execution environment.\n   *\n   * NOTE: This will not work correctly for non-generic events such as `change`,\n   * `reset`, `load`, `error`, and `select`.\n   *\n   * Borrows from Modernizr.\n   *\n   * @param {string} eventNameSuffix Event name, e.g. \"click\".\n   * @return {boolean} True if the event is supported.\n   * @internal\n   * @license Modernizr 3.0.0pre (Custom Build) | MIT\n   */\n\n  function isEventSupported(eventNameSuffix) {\n    if (!canUseDOM) {\n      return false;\n    }\n\n    var eventName = 'on' + eventNameSuffix;\n    var isSupported = (eventName in document);\n\n    if (!isSupported) {\n      var element = document.createElement('div');\n      element.setAttribute(eventName, 'return;');\n      isSupported = typeof element[eventName] === 'function';\n    }\n\n    return isSupported;\n  }\n\n  function registerEvents$1() {\n    registerTwoPhaseEvent('onChange', ['change', 'click', 'focusin', 'focusout', 'input', 'keydown', 'keyup', 'selectionchange']);\n  }\n\n  function createAndAccumulateChangeEvent(dispatchQueue, inst, nativeEvent, target) {\n    // Flag this event loop as needing state restore.\n    enqueueStateRestore(target);\n    var listeners = accumulateTwoPhaseListeners(inst, 'onChange');\n\n    if (listeners.length > 0) {\n      var event = new SyntheticEvent('onChange', 'change', null, nativeEvent, target);\n      dispatchQueue.push({\n        event: event,\n        listeners: listeners\n      });\n    }\n  }\n  /**\n   * For IE shims\n   */\n\n\n  var activeElement = null;\n  var activeElementInst = null;\n  /**\n   * SECTION: handle `change` event\n   */\n\n  function shouldUseChangeEvent(elem) {\n    var nodeName = elem.nodeName && elem.nodeName.toLowerCase();\n    return nodeName === 'select' || nodeName === 'input' && elem.type === 'file';\n  }\n\n  function manualDispatchChangeEvent(nativeEvent) {\n    var dispatchQueue = [];\n    createAndAccumulateChangeEvent(dispatchQueue, activeElementInst, nativeEvent, getEventTarget(nativeEvent)); // If change and propertychange bubbled, we'd just bind to it like all the\n    // other events and have it go through ReactBrowserEventEmitter. Since it\n    // doesn't, we manually listen for the events and so we have to enqueue and\n    // process the abstract event manually.\n    //\n    // Batching is necessary here in order to ensure that all event handlers run\n    // before the next rerender (including event handlers attached to ancestor\n    // elements instead of directly on the input). Without this, controlled\n    // components don't work properly in conjunction with event bubbling because\n    // the component is rerendered and the value reverted before all the event\n    // handlers can run. See https://github.com/facebook/react/issues/708.\n\n    batchedUpdates(runEventInBatch, dispatchQueue);\n  }\n\n  function runEventInBatch(dispatchQueue) {\n    processDispatchQueue(dispatchQueue, 0);\n  }\n\n  function getInstIfValueChanged(targetInst) {\n    var targetNode = getNodeFromInstance(targetInst);\n\n    if (updateValueIfChanged(targetNode)) {\n      return targetInst;\n    }\n  }\n\n  function getTargetInstForChangeEvent(domEventName, targetInst) {\n    if (domEventName === 'change') {\n      return targetInst;\n    }\n  }\n  /**\n   * SECTION: handle `input` event\n   */\n\n\n  var isInputEventSupported = false;\n\n  if (canUseDOM) {\n    // IE9 claims to support the input event but fails to trigger it when\n    // deleting text, so we ignore its input events.\n    isInputEventSupported = isEventSupported('input') && (!document.documentMode || document.documentMode > 9);\n  }\n  /**\n   * (For IE <=9) Starts tracking propertychange events on the passed-in element\n   * and override the value property so that we can distinguish user events from\n   * value changes in JS.\n   */\n\n\n  function startWatchingForValueChange(target, targetInst) {\n    activeElement = target;\n    activeElementInst = targetInst;\n    activeElement.attachEvent('onpropertychange', handlePropertyChange);\n  }\n  /**\n   * (For IE <=9) Removes the event listeners from the currently-tracked element,\n   * if any exists.\n   */\n\n\n  function stopWatchingForValueChange() {\n    if (!activeElement) {\n      return;\n    }\n\n    activeElement.detachEvent('onpropertychange', handlePropertyChange);\n    activeElement = null;\n    activeElementInst = null;\n  }\n  /**\n   * (For IE <=9) Handles a propertychange event, sending a `change` event if\n   * the value of the active element has changed.\n   */\n\n\n  function handlePropertyChange(nativeEvent) {\n    if (nativeEvent.propertyName !== 'value') {\n      return;\n    }\n\n    if (getInstIfValueChanged(activeElementInst)) {\n      manualDispatchChangeEvent(nativeEvent);\n    }\n  }\n\n  function handleEventsForInputEventPolyfill(domEventName, target, targetInst) {\n    if (domEventName === 'focusin') {\n      // In IE9, propertychange fires for most input events but is buggy and\n      // doesn't fire when text is deleted, but conveniently, selectionchange\n      // appears to fire in all of the remaining cases so we catch those and\n      // forward the event if the value has changed\n      // In either case, we don't want to call the event handler if the value\n      // is changed from JS so we redefine a setter for `.value` that updates\n      // our activeElementValue variable, allowing us to ignore those changes\n      //\n      // stopWatching() should be a noop here but we call it just in case we\n      // missed a blur event somehow.\n      stopWatchingForValueChange();\n      startWatchingForValueChange(target, targetInst);\n    } else if (domEventName === 'focusout') {\n      stopWatchingForValueChange();\n    }\n  } // For IE8 and IE9.\n\n\n  function getTargetInstForInputEventPolyfill(domEventName, targetInst) {\n    if (domEventName === 'selectionchange' || domEventName === 'keyup' || domEventName === 'keydown') {\n      // On the selectionchange event, the target is just document which isn't\n      // helpful for us so just check activeElement instead.\n      //\n      // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire\n      // propertychange on the first input event after setting `value` from a\n      // script and fires only keydown, keypress, keyup. Catching keyup usually\n      // gets it and catching keydown lets us fire an event for the first\n      // keystroke if user does a key repeat (it'll be a little delayed: right\n      // before the second keystroke). Other input methods (e.g., paste) seem to\n      // fire selectionchange normally.\n      return getInstIfValueChanged(activeElementInst);\n    }\n  }\n  /**\n   * SECTION: handle `click` event\n   */\n\n\n  function shouldUseClickEvent(elem) {\n    // Use the `click` event to detect changes to checkbox and radio inputs.\n    // This approach works across all browsers, whereas `change` does not fire\n    // until `blur` in IE8.\n    var nodeName = elem.nodeName;\n    return nodeName && nodeName.toLowerCase() === 'input' && (elem.type === 'checkbox' || elem.type === 'radio');\n  }\n\n  function getTargetInstForClickEvent(domEventName, targetInst) {\n    if (domEventName === 'click') {\n      return getInstIfValueChanged(targetInst);\n    }\n  }\n\n  function getTargetInstForInputOrChangeEvent(domEventName, targetInst) {\n    if (domEventName === 'input' || domEventName === 'change') {\n      return getInstIfValueChanged(targetInst);\n    }\n  }\n\n  function handleControlledInputBlur(node) {\n    var state = node._wrapperState;\n\n    if (!state || !state.controlled || node.type !== 'number') {\n      return;\n    }\n\n    {\n      // If controlled, assign the value attribute to the current value on blur\n      setDefaultValue(node, 'number', node.value);\n    }\n  }\n  /**\n   * This plugin creates an `onChange` event that normalizes change events\n   * across form elements. This event fires at a time when it's possible to\n   * change the element's value without seeing a flicker.\n   *\n   * Supported elements are:\n   * - input (see `isTextInputElement`)\n   * - textarea\n   * - select\n   */\n\n\n  function extractEvents$1(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer) {\n    var targetNode = targetInst ? getNodeFromInstance(targetInst) : window;\n    var getTargetInstFunc, handleEventFunc;\n\n    if (shouldUseChangeEvent(targetNode)) {\n      getTargetInstFunc = getTargetInstForChangeEvent;\n    } else if (isTextInputElement(targetNode)) {\n      if (isInputEventSupported) {\n        getTargetInstFunc = getTargetInstForInputOrChangeEvent;\n      } else {\n        getTargetInstFunc = getTargetInstForInputEventPolyfill;\n        handleEventFunc = handleEventsForInputEventPolyfill;\n      }\n    } else if (shouldUseClickEvent(targetNode)) {\n      getTargetInstFunc = getTargetInstForClickEvent;\n    }\n\n    if (getTargetInstFunc) {\n      var inst = getTargetInstFunc(domEventName, targetInst);\n\n      if (inst) {\n        createAndAccumulateChangeEvent(dispatchQueue, inst, nativeEvent, nativeEventTarget);\n        return;\n      }\n    }\n\n    if (handleEventFunc) {\n      handleEventFunc(domEventName, targetNode, targetInst);\n    } // When blurring, set the value attribute for number inputs\n\n\n    if (domEventName === 'focusout') {\n      handleControlledInputBlur(targetNode);\n    }\n  }\n\n  function registerEvents$2() {\n    registerDirectEvent('onMouseEnter', ['mouseout', 'mouseover']);\n    registerDirectEvent('onMouseLeave', ['mouseout', 'mouseover']);\n    registerDirectEvent('onPointerEnter', ['pointerout', 'pointerover']);\n    registerDirectEvent('onPointerLeave', ['pointerout', 'pointerover']);\n  }\n  /**\n   * For almost every interaction we care about, there will be both a top-level\n   * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that\n   * we do not extract duplicate events. However, moving the mouse into the\n   * browser from outside will not fire a `mouseout` event. In this case, we use\n   * the `mouseover` top-level event.\n   */\n\n\n  function extractEvents$2(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer) {\n    var isOverEvent = domEventName === 'mouseover' || domEventName === 'pointerover';\n    var isOutEvent = domEventName === 'mouseout' || domEventName === 'pointerout';\n\n    if (isOverEvent && !isReplayingEvent(nativeEvent)) {\n      // If this is an over event with a target, we might have already dispatched\n      // the event in the out event of the other target. If this is replayed,\n      // then it's because we couldn't dispatch against this target previously\n      // so we have to do it now instead.\n      var related = nativeEvent.relatedTarget || nativeEvent.fromElement;\n\n      if (related) {\n        // If the related node is managed by React, we can assume that we have\n        // already dispatched the corresponding events during its mouseout.\n        if (getClosestInstanceFromNode(related) || isContainerMarkedAsRoot(related)) {\n          return;\n        }\n      }\n    }\n\n    if (!isOutEvent && !isOverEvent) {\n      // Must not be a mouse or pointer in or out - ignoring.\n      return;\n    }\n\n    var win; // TODO: why is this nullable in the types but we read from it?\n\n    if (nativeEventTarget.window === nativeEventTarget) {\n      // `nativeEventTarget` is probably a window object.\n      win = nativeEventTarget;\n    } else {\n      // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.\n      var doc = nativeEventTarget.ownerDocument;\n\n      if (doc) {\n        win = doc.defaultView || doc.parentWindow;\n      } else {\n        win = window;\n      }\n    }\n\n    var from;\n    var to;\n\n    if (isOutEvent) {\n      var _related = nativeEvent.relatedTarget || nativeEvent.toElement;\n\n      from = targetInst;\n      to = _related ? getClosestInstanceFromNode(_related) : null;\n\n      if (to !== null) {\n        var nearestMounted = getNearestMountedFiber(to);\n\n        if (to !== nearestMounted || to.tag !== HostComponent && to.tag !== HostText) {\n          to = null;\n        }\n      }\n    } else {\n      // Moving to a node from outside the window.\n      from = null;\n      to = targetInst;\n    }\n\n    if (from === to) {\n      // Nothing pertains to our managed components.\n      return;\n    }\n\n    var SyntheticEventCtor = SyntheticMouseEvent;\n    var leaveEventType = 'onMouseLeave';\n    var enterEventType = 'onMouseEnter';\n    var eventTypePrefix = 'mouse';\n\n    if (domEventName === 'pointerout' || domEventName === 'pointerover') {\n      SyntheticEventCtor = SyntheticPointerEvent;\n      leaveEventType = 'onPointerLeave';\n      enterEventType = 'onPointerEnter';\n      eventTypePrefix = 'pointer';\n    }\n\n    var fromNode = from == null ? win : getNodeFromInstance(from);\n    var toNode = to == null ? win : getNodeFromInstance(to);\n    var leave = new SyntheticEventCtor(leaveEventType, eventTypePrefix + 'leave', from, nativeEvent, nativeEventTarget);\n    leave.target = fromNode;\n    leave.relatedTarget = toNode;\n    var enter = null; // We should only process this nativeEvent if we are processing\n    // the first ancestor. Next time, we will ignore the event.\n\n    var nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget);\n\n    if (nativeTargetInst === targetInst) {\n      var enterEvent = new SyntheticEventCtor(enterEventType, eventTypePrefix + 'enter', to, nativeEvent, nativeEventTarget);\n      enterEvent.target = toNode;\n      enterEvent.relatedTarget = fromNode;\n      enter = enterEvent;\n    }\n\n    accumulateEnterLeaveTwoPhaseListeners(dispatchQueue, leave, enter, from, to);\n  }\n\n  /**\n   * inlined Object.is polyfill to avoid requiring consumers ship their own\n   * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is\n   */\n  function is(x, y) {\n    return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare\n    ;\n  }\n\n  var objectIs = typeof Object.is === 'function' ? Object.is : is;\n\n  /**\n   * Performs equality by iterating through keys on an object and returning false\n   * when any key has values which are not strictly equal between the arguments.\n   * Returns true when the values of all keys are strictly equal.\n   */\n\n  function shallowEqual(objA, objB) {\n    if (objectIs(objA, objB)) {\n      return true;\n    }\n\n    if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {\n      return false;\n    }\n\n    var keysA = Object.keys(objA);\n    var keysB = Object.keys(objB);\n\n    if (keysA.length !== keysB.length) {\n      return false;\n    } // Test for A's keys different from B.\n\n\n    for (var i = 0; i < keysA.length; i++) {\n      var currentKey = keysA[i];\n\n      if (!hasOwnProperty.call(objB, currentKey) || !objectIs(objA[currentKey], objB[currentKey])) {\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  /**\n   * Given any node return the first leaf node without children.\n   *\n   * @param {DOMElement|DOMTextNode} node\n   * @return {DOMElement|DOMTextNode}\n   */\n\n  function getLeafNode(node) {\n    while (node && node.firstChild) {\n      node = node.firstChild;\n    }\n\n    return node;\n  }\n  /**\n   * Get the next sibling within a container. This will walk up the\n   * DOM if a node's siblings have been exhausted.\n   *\n   * @param {DOMElement|DOMTextNode} node\n   * @return {?DOMElement|DOMTextNode}\n   */\n\n\n  function getSiblingNode(node) {\n    while (node) {\n      if (node.nextSibling) {\n        return node.nextSibling;\n      }\n\n      node = node.parentNode;\n    }\n  }\n  /**\n   * Get object describing the nodes which contain characters at offset.\n   *\n   * @param {DOMElement|DOMTextNode} root\n   * @param {number} offset\n   * @return {?object}\n   */\n\n\n  function getNodeForCharacterOffset(root, offset) {\n    var node = getLeafNode(root);\n    var nodeStart = 0;\n    var nodeEnd = 0;\n\n    while (node) {\n      if (node.nodeType === TEXT_NODE) {\n        nodeEnd = nodeStart + node.textContent.length;\n\n        if (nodeStart <= offset && nodeEnd >= offset) {\n          return {\n            node: node,\n            offset: offset - nodeStart\n          };\n        }\n\n        nodeStart = nodeEnd;\n      }\n\n      node = getLeafNode(getSiblingNode(node));\n    }\n  }\n\n  /**\n   * @param {DOMElement} outerNode\n   * @return {?object}\n   */\n\n  function getOffsets(outerNode) {\n    var ownerDocument = outerNode.ownerDocument;\n    var win = ownerDocument && ownerDocument.defaultView || window;\n    var selection = win.getSelection && win.getSelection();\n\n    if (!selection || selection.rangeCount === 0) {\n      return null;\n    }\n\n    var anchorNode = selection.anchorNode,\n        anchorOffset = selection.anchorOffset,\n        focusNode = selection.focusNode,\n        focusOffset = selection.focusOffset; // In Firefox, anchorNode and focusNode can be \"anonymous divs\", e.g. the\n    // up/down buttons on an <input type=\"number\">. Anonymous divs do not seem to\n    // expose properties, triggering a \"Permission denied error\" if any of its\n    // properties are accessed. The only seemingly possible way to avoid erroring\n    // is to access a property that typically works for non-anonymous divs and\n    // catch any error that may otherwise arise. See\n    // https://bugzilla.mozilla.org/show_bug.cgi?id=208427\n\n    try {\n      /* eslint-disable no-unused-expressions */\n      anchorNode.nodeType;\n      focusNode.nodeType;\n      /* eslint-enable no-unused-expressions */\n    } catch (e) {\n      return null;\n    }\n\n    return getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset);\n  }\n  /**\n   * Returns {start, end} where `start` is the character/codepoint index of\n   * (anchorNode, anchorOffset) within the textContent of `outerNode`, and\n   * `end` is the index of (focusNode, focusOffset).\n   *\n   * Returns null if you pass in garbage input but we should probably just crash.\n   *\n   * Exported only for testing.\n   */\n\n  function getModernOffsetsFromPoints(outerNode, anchorNode, anchorOffset, focusNode, focusOffset) {\n    var length = 0;\n    var start = -1;\n    var end = -1;\n    var indexWithinAnchor = 0;\n    var indexWithinFocus = 0;\n    var node = outerNode;\n    var parentNode = null;\n\n    outer: while (true) {\n      var next = null;\n\n      while (true) {\n        if (node === anchorNode && (anchorOffset === 0 || node.nodeType === TEXT_NODE)) {\n          start = length + anchorOffset;\n        }\n\n        if (node === focusNode && (focusOffset === 0 || node.nodeType === TEXT_NODE)) {\n          end = length + focusOffset;\n        }\n\n        if (node.nodeType === TEXT_NODE) {\n          length += node.nodeValue.length;\n        }\n\n        if ((next = node.firstChild) === null) {\n          break;\n        } // Moving from `node` to its first child `next`.\n\n\n        parentNode = node;\n        node = next;\n      }\n\n      while (true) {\n        if (node === outerNode) {\n          // If `outerNode` has children, this is always the second time visiting\n          // it. If it has no children, this is still the first loop, and the only\n          // valid selection is anchorNode and focusNode both equal to this node\n          // and both offsets 0, in which case we will have handled above.\n          break outer;\n        }\n\n        if (parentNode === anchorNode && ++indexWithinAnchor === anchorOffset) {\n          start = length;\n        }\n\n        if (parentNode === focusNode && ++indexWithinFocus === focusOffset) {\n          end = length;\n        }\n\n        if ((next = node.nextSibling) !== null) {\n          break;\n        }\n\n        node = parentNode;\n        parentNode = node.parentNode;\n      } // Moving from `node` to its next sibling `next`.\n\n\n      node = next;\n    }\n\n    if (start === -1 || end === -1) {\n      // This should never happen. (Would happen if the anchor/focus nodes aren't\n      // actually inside the passed-in node.)\n      return null;\n    }\n\n    return {\n      start: start,\n      end: end\n    };\n  }\n  /**\n   * In modern non-IE browsers, we can support both forward and backward\n   * selections.\n   *\n   * Note: IE10+ supports the Selection object, but it does not support\n   * the `extend` method, which means that even in modern IE, it's not possible\n   * to programmatically create a backward selection. Thus, for all IE\n   * versions, we use the old IE API to create our selections.\n   *\n   * @param {DOMElement|DOMTextNode} node\n   * @param {object} offsets\n   */\n\n  function setOffsets(node, offsets) {\n    var doc = node.ownerDocument || document;\n    var win = doc && doc.defaultView || window; // Edge fails with \"Object expected\" in some scenarios.\n    // (For instance: TinyMCE editor used in a list component that supports pasting to add more,\n    // fails when pasting 100+ items)\n\n    if (!win.getSelection) {\n      return;\n    }\n\n    var selection = win.getSelection();\n    var length = node.textContent.length;\n    var start = Math.min(offsets.start, length);\n    var end = offsets.end === undefined ? start : Math.min(offsets.end, length); // IE 11 uses modern selection, but doesn't support the extend method.\n    // Flip backward selections, so we can set with a single range.\n\n    if (!selection.extend && start > end) {\n      var temp = end;\n      end = start;\n      start = temp;\n    }\n\n    var startMarker = getNodeForCharacterOffset(node, start);\n    var endMarker = getNodeForCharacterOffset(node, end);\n\n    if (startMarker && endMarker) {\n      if (selection.rangeCount === 1 && selection.anchorNode === startMarker.node && selection.anchorOffset === startMarker.offset && selection.focusNode === endMarker.node && selection.focusOffset === endMarker.offset) {\n        return;\n      }\n\n      var range = doc.createRange();\n      range.setStart(startMarker.node, startMarker.offset);\n      selection.removeAllRanges();\n\n      if (start > end) {\n        selection.addRange(range);\n        selection.extend(endMarker.node, endMarker.offset);\n      } else {\n        range.setEnd(endMarker.node, endMarker.offset);\n        selection.addRange(range);\n      }\n    }\n  }\n\n  function isTextNode(node) {\n    return node && node.nodeType === TEXT_NODE;\n  }\n\n  function containsNode(outerNode, innerNode) {\n    if (!outerNode || !innerNode) {\n      return false;\n    } else if (outerNode === innerNode) {\n      return true;\n    } else if (isTextNode(outerNode)) {\n      return false;\n    } else if (isTextNode(innerNode)) {\n      return containsNode(outerNode, innerNode.parentNode);\n    } else if ('contains' in outerNode) {\n      return outerNode.contains(innerNode);\n    } else if (outerNode.compareDocumentPosition) {\n      return !!(outerNode.compareDocumentPosition(innerNode) & 16);\n    } else {\n      return false;\n    }\n  }\n\n  function isInDocument(node) {\n    return node && node.ownerDocument && containsNode(node.ownerDocument.documentElement, node);\n  }\n\n  function isSameOriginFrame(iframe) {\n    try {\n      // Accessing the contentDocument of a HTMLIframeElement can cause the browser\n      // to throw, e.g. if it has a cross-origin src attribute.\n      // Safari will show an error in the console when the access results in \"Blocked a frame with origin\". e.g:\n      // iframe.contentDocument.defaultView;\n      // A safety way is to access one of the cross origin properties: Window or Location\n      // Which might result in \"SecurityError\" DOM Exception and it is compatible to Safari.\n      // https://html.spec.whatwg.org/multipage/browsers.html#integration-with-idl\n      return typeof iframe.contentWindow.location.href === 'string';\n    } catch (err) {\n      return false;\n    }\n  }\n\n  function getActiveElementDeep() {\n    var win = window;\n    var element = getActiveElement();\n\n    while (element instanceof win.HTMLIFrameElement) {\n      if (isSameOriginFrame(element)) {\n        win = element.contentWindow;\n      } else {\n        return element;\n      }\n\n      element = getActiveElement(win.document);\n    }\n\n    return element;\n  }\n  /**\n   * @ReactInputSelection: React input selection module. Based on Selection.js,\n   * but modified to be suitable for react and has a couple of bug fixes (doesn't\n   * assume buttons have range selections allowed).\n   * Input selection module for React.\n   */\n\n  /**\n   * @hasSelectionCapabilities: we get the element types that support selection\n   * from https://html.spec.whatwg.org/#do-not-apply, looking at `selectionStart`\n   * and `selectionEnd` rows.\n   */\n\n\n  function hasSelectionCapabilities(elem) {\n    var nodeName = elem && elem.nodeName && elem.nodeName.toLowerCase();\n    return nodeName && (nodeName === 'input' && (elem.type === 'text' || elem.type === 'search' || elem.type === 'tel' || elem.type === 'url' || elem.type === 'password') || nodeName === 'textarea' || elem.contentEditable === 'true');\n  }\n  function getSelectionInformation() {\n    var focusedElem = getActiveElementDeep();\n    return {\n      focusedElem: focusedElem,\n      selectionRange: hasSelectionCapabilities(focusedElem) ? getSelection(focusedElem) : null\n    };\n  }\n  /**\n   * @restoreSelection: If any selection information was potentially lost,\n   * restore it. This is useful when performing operations that could remove dom\n   * nodes and place them back in, resulting in focus being lost.\n   */\n\n  function restoreSelection(priorSelectionInformation) {\n    var curFocusedElem = getActiveElementDeep();\n    var priorFocusedElem = priorSelectionInformation.focusedElem;\n    var priorSelectionRange = priorSelectionInformation.selectionRange;\n\n    if (curFocusedElem !== priorFocusedElem && isInDocument(priorFocusedElem)) {\n      if (priorSelectionRange !== null && hasSelectionCapabilities(priorFocusedElem)) {\n        setSelection(priorFocusedElem, priorSelectionRange);\n      } // Focusing a node can change the scroll position, which is undesirable\n\n\n      var ancestors = [];\n      var ancestor = priorFocusedElem;\n\n      while (ancestor = ancestor.parentNode) {\n        if (ancestor.nodeType === ELEMENT_NODE) {\n          ancestors.push({\n            element: ancestor,\n            left: ancestor.scrollLeft,\n            top: ancestor.scrollTop\n          });\n        }\n      }\n\n      if (typeof priorFocusedElem.focus === 'function') {\n        priorFocusedElem.focus();\n      }\n\n      for (var i = 0; i < ancestors.length; i++) {\n        var info = ancestors[i];\n        info.element.scrollLeft = info.left;\n        info.element.scrollTop = info.top;\n      }\n    }\n  }\n  /**\n   * @getSelection: Gets the selection bounds of a focused textarea, input or\n   * contentEditable node.\n   * -@input: Look up selection bounds of this input\n   * -@return {start: selectionStart, end: selectionEnd}\n   */\n\n  function getSelection(input) {\n    var selection;\n\n    if ('selectionStart' in input) {\n      // Modern browser with input or textarea.\n      selection = {\n        start: input.selectionStart,\n        end: input.selectionEnd\n      };\n    } else {\n      // Content editable or old IE textarea.\n      selection = getOffsets(input);\n    }\n\n    return selection || {\n      start: 0,\n      end: 0\n    };\n  }\n  /**\n   * @setSelection: Sets the selection bounds of a textarea or input and focuses\n   * the input.\n   * -@input     Set selection bounds of this input or textarea\n   * -@offsets   Object of same form that is returned from get*\n   */\n\n  function setSelection(input, offsets) {\n    var start = offsets.start;\n    var end = offsets.end;\n\n    if (end === undefined) {\n      end = start;\n    }\n\n    if ('selectionStart' in input) {\n      input.selectionStart = start;\n      input.selectionEnd = Math.min(end, input.value.length);\n    } else {\n      setOffsets(input, offsets);\n    }\n  }\n\n  var skipSelectionChangeEvent = canUseDOM && 'documentMode' in document && document.documentMode <= 11;\n\n  function registerEvents$3() {\n    registerTwoPhaseEvent('onSelect', ['focusout', 'contextmenu', 'dragend', 'focusin', 'keydown', 'keyup', 'mousedown', 'mouseup', 'selectionchange']);\n  }\n\n  var activeElement$1 = null;\n  var activeElementInst$1 = null;\n  var lastSelection = null;\n  var mouseDown = false;\n  /**\n   * Get an object which is a unique representation of the current selection.\n   *\n   * The return value will not be consistent across nodes or browsers, but\n   * two identical selections on the same node will return identical objects.\n   */\n\n  function getSelection$1(node) {\n    if ('selectionStart' in node && hasSelectionCapabilities(node)) {\n      return {\n        start: node.selectionStart,\n        end: node.selectionEnd\n      };\n    } else {\n      var win = node.ownerDocument && node.ownerDocument.defaultView || window;\n      var selection = win.getSelection();\n      return {\n        anchorNode: selection.anchorNode,\n        anchorOffset: selection.anchorOffset,\n        focusNode: selection.focusNode,\n        focusOffset: selection.focusOffset\n      };\n    }\n  }\n  /**\n   * Get document associated with the event target.\n   */\n\n\n  function getEventTargetDocument(eventTarget) {\n    return eventTarget.window === eventTarget ? eventTarget.document : eventTarget.nodeType === DOCUMENT_NODE ? eventTarget : eventTarget.ownerDocument;\n  }\n  /**\n   * Poll selection to see whether it's changed.\n   *\n   * @param {object} nativeEvent\n   * @param {object} nativeEventTarget\n   * @return {?SyntheticEvent}\n   */\n\n\n  function constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) {\n    // Ensure we have the right element, and that the user is not dragging a\n    // selection (this matches native `select` event behavior). In HTML5, select\n    // fires only on input and textarea thus if there's no focused element we\n    // won't dispatch.\n    var doc = getEventTargetDocument(nativeEventTarget);\n\n    if (mouseDown || activeElement$1 == null || activeElement$1 !== getActiveElement(doc)) {\n      return;\n    } // Only fire when selection has actually changed.\n\n\n    var currentSelection = getSelection$1(activeElement$1);\n\n    if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {\n      lastSelection = currentSelection;\n      var listeners = accumulateTwoPhaseListeners(activeElementInst$1, 'onSelect');\n\n      if (listeners.length > 0) {\n        var event = new SyntheticEvent('onSelect', 'select', null, nativeEvent, nativeEventTarget);\n        dispatchQueue.push({\n          event: event,\n          listeners: listeners\n        });\n        event.target = activeElement$1;\n      }\n    }\n  }\n  /**\n   * This plugin creates an `onSelect` event that normalizes select events\n   * across form elements.\n   *\n   * Supported elements are:\n   * - input (see `isTextInputElement`)\n   * - textarea\n   * - contentEditable\n   *\n   * This differs from native browser implementations in the following ways:\n   * - Fires on contentEditable fields as well as inputs.\n   * - Fires for collapsed selection.\n   * - Fires after user input.\n   */\n\n\n  function extractEvents$3(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer) {\n    var targetNode = targetInst ? getNodeFromInstance(targetInst) : window;\n\n    switch (domEventName) {\n      // Track the input node that has focus.\n      case 'focusin':\n        if (isTextInputElement(targetNode) || targetNode.contentEditable === 'true') {\n          activeElement$1 = targetNode;\n          activeElementInst$1 = targetInst;\n          lastSelection = null;\n        }\n\n        break;\n\n      case 'focusout':\n        activeElement$1 = null;\n        activeElementInst$1 = null;\n        lastSelection = null;\n        break;\n      // Don't fire the event while the user is dragging. This matches the\n      // semantics of the native select event.\n\n      case 'mousedown':\n        mouseDown = true;\n        break;\n\n      case 'contextmenu':\n      case 'mouseup':\n      case 'dragend':\n        mouseDown = false;\n        constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);\n        break;\n      // Chrome and IE fire non-standard event when selection is changed (and\n      // sometimes when it hasn't). IE's event fires out of order with respect\n      // to key and input events on deletion, so we discard it.\n      //\n      // Firefox doesn't support selectionchange, so check selection status\n      // after each key entry. The selection changes after keydown and before\n      // keyup, but we check on keydown as well in the case of holding down a\n      // key, when multiple keydown events are fired but only one keyup is.\n      // This is also our approach for IE handling, for the reason above.\n\n      case 'selectionchange':\n        if (skipSelectionChangeEvent) {\n          break;\n        }\n\n      // falls through\n\n      case 'keydown':\n      case 'keyup':\n        constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);\n    }\n  }\n\n  /**\n   * Generate a mapping of standard vendor prefixes using the defined style property and event name.\n   *\n   * @param {string} styleProp\n   * @param {string} eventName\n   * @returns {object}\n   */\n\n  function makePrefixMap(styleProp, eventName) {\n    var prefixes = {};\n    prefixes[styleProp.toLowerCase()] = eventName.toLowerCase();\n    prefixes['Webkit' + styleProp] = 'webkit' + eventName;\n    prefixes['Moz' + styleProp] = 'moz' + eventName;\n    return prefixes;\n  }\n  /**\n   * A list of event names to a configurable list of vendor prefixes.\n   */\n\n\n  var vendorPrefixes = {\n    animationend: makePrefixMap('Animation', 'AnimationEnd'),\n    animationiteration: makePrefixMap('Animation', 'AnimationIteration'),\n    animationstart: makePrefixMap('Animation', 'AnimationStart'),\n    transitionend: makePrefixMap('Transition', 'TransitionEnd')\n  };\n  /**\n   * Event names that have already been detected and prefixed (if applicable).\n   */\n\n  var prefixedEventNames = {};\n  /**\n   * Element to check for prefixes on.\n   */\n\n  var style = {};\n  /**\n   * Bootstrap if a DOM exists.\n   */\n\n  if (canUseDOM) {\n    style = document.createElement('div').style; // On some platforms, in particular some releases of Android 4.x,\n    // the un-prefixed \"animation\" and \"transition\" properties are defined on the\n    // style object but the events that fire will still be prefixed, so we need\n    // to check if the un-prefixed events are usable, and if not remove them from the map.\n\n    if (!('AnimationEvent' in window)) {\n      delete vendorPrefixes.animationend.animation;\n      delete vendorPrefixes.animationiteration.animation;\n      delete vendorPrefixes.animationstart.animation;\n    } // Same as above\n\n\n    if (!('TransitionEvent' in window)) {\n      delete vendorPrefixes.transitionend.transition;\n    }\n  }\n  /**\n   * Attempts to determine the correct vendor prefixed event name.\n   *\n   * @param {string} eventName\n   * @returns {string}\n   */\n\n\n  function getVendorPrefixedEventName(eventName) {\n    if (prefixedEventNames[eventName]) {\n      return prefixedEventNames[eventName];\n    } else if (!vendorPrefixes[eventName]) {\n      return eventName;\n    }\n\n    var prefixMap = vendorPrefixes[eventName];\n\n    for (var styleProp in prefixMap) {\n      if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) {\n        return prefixedEventNames[eventName] = prefixMap[styleProp];\n      }\n    }\n\n    return eventName;\n  }\n\n  var ANIMATION_END = getVendorPrefixedEventName('animationend');\n  var ANIMATION_ITERATION = getVendorPrefixedEventName('animationiteration');\n  var ANIMATION_START = getVendorPrefixedEventName('animationstart');\n  var TRANSITION_END = getVendorPrefixedEventName('transitionend');\n\n  var topLevelEventsToReactNames = new Map(); // NOTE: Capitalization is important in this list!\n  //\n  // E.g. it needs \"pointerDown\", not \"pointerdown\".\n  // This is because we derive both React name (\"onPointerDown\")\n  // and DOM name (\"pointerdown\") from the same list.\n  //\n  // Exceptions that don't match this convention are listed separately.\n  //\n  // prettier-ignore\n\n  var simpleEventPluginEvents = ['abort', 'auxClick', 'cancel', 'canPlay', 'canPlayThrough', 'click', 'close', 'contextMenu', 'copy', 'cut', 'drag', 'dragEnd', 'dragEnter', 'dragExit', 'dragLeave', 'dragOver', 'dragStart', 'drop', 'durationChange', 'emptied', 'encrypted', 'ended', 'error', 'gotPointerCapture', 'input', 'invalid', 'keyDown', 'keyPress', 'keyUp', 'load', 'loadedData', 'loadedMetadata', 'loadStart', 'lostPointerCapture', 'mouseDown', 'mouseMove', 'mouseOut', 'mouseOver', 'mouseUp', 'paste', 'pause', 'play', 'playing', 'pointerCancel', 'pointerDown', 'pointerMove', 'pointerOut', 'pointerOver', 'pointerUp', 'progress', 'rateChange', 'reset', 'resize', 'seeked', 'seeking', 'stalled', 'submit', 'suspend', 'timeUpdate', 'touchCancel', 'touchEnd', 'touchStart', 'volumeChange', 'scroll', 'toggle', 'touchMove', 'waiting', 'wheel'];\n\n  function registerSimpleEvent(domEventName, reactName) {\n    topLevelEventsToReactNames.set(domEventName, reactName);\n    registerTwoPhaseEvent(reactName, [domEventName]);\n  }\n\n  function registerSimpleEvents() {\n    for (var i = 0; i < simpleEventPluginEvents.length; i++) {\n      var eventName = simpleEventPluginEvents[i];\n      var domEventName = eventName.toLowerCase();\n      var capitalizedEvent = eventName[0].toUpperCase() + eventName.slice(1);\n      registerSimpleEvent(domEventName, 'on' + capitalizedEvent);\n    } // Special cases where event names don't match.\n\n\n    registerSimpleEvent(ANIMATION_END, 'onAnimationEnd');\n    registerSimpleEvent(ANIMATION_ITERATION, 'onAnimationIteration');\n    registerSimpleEvent(ANIMATION_START, 'onAnimationStart');\n    registerSimpleEvent('dblclick', 'onDoubleClick');\n    registerSimpleEvent('focusin', 'onFocus');\n    registerSimpleEvent('focusout', 'onBlur');\n    registerSimpleEvent(TRANSITION_END, 'onTransitionEnd');\n  }\n\n  function extractEvents$4(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer) {\n    var reactName = topLevelEventsToReactNames.get(domEventName);\n\n    if (reactName === undefined) {\n      return;\n    }\n\n    var SyntheticEventCtor = SyntheticEvent;\n    var reactEventType = domEventName;\n\n    switch (domEventName) {\n      case 'keypress':\n        // Firefox creates a keypress event for function keys too. This removes\n        // the unwanted keypress events. Enter is however both printable and\n        // non-printable. One would expect Tab to be as well (but it isn't).\n        if (getEventCharCode(nativeEvent) === 0) {\n          return;\n        }\n\n      /* falls through */\n\n      case 'keydown':\n      case 'keyup':\n        SyntheticEventCtor = SyntheticKeyboardEvent;\n        break;\n\n      case 'focusin':\n        reactEventType = 'focus';\n        SyntheticEventCtor = SyntheticFocusEvent;\n        break;\n\n      case 'focusout':\n        reactEventType = 'blur';\n        SyntheticEventCtor = SyntheticFocusEvent;\n        break;\n\n      case 'beforeblur':\n      case 'afterblur':\n        SyntheticEventCtor = SyntheticFocusEvent;\n        break;\n\n      case 'click':\n        // Firefox creates a click event on right mouse clicks. This removes the\n        // unwanted click events.\n        if (nativeEvent.button === 2) {\n          return;\n        }\n\n      /* falls through */\n\n      case 'auxclick':\n      case 'dblclick':\n      case 'mousedown':\n      case 'mousemove':\n      case 'mouseup': // TODO: Disabled elements should not respond to mouse events\n\n      /* falls through */\n\n      case 'mouseout':\n      case 'mouseover':\n      case 'contextmenu':\n        SyntheticEventCtor = SyntheticMouseEvent;\n        break;\n\n      case 'drag':\n      case 'dragend':\n      case 'dragenter':\n      case 'dragexit':\n      case 'dragleave':\n      case 'dragover':\n      case 'dragstart':\n      case 'drop':\n        SyntheticEventCtor = SyntheticDragEvent;\n        break;\n\n      case 'touchcancel':\n      case 'touchend':\n      case 'touchmove':\n      case 'touchstart':\n        SyntheticEventCtor = SyntheticTouchEvent;\n        break;\n\n      case ANIMATION_END:\n      case ANIMATION_ITERATION:\n      case ANIMATION_START:\n        SyntheticEventCtor = SyntheticAnimationEvent;\n        break;\n\n      case TRANSITION_END:\n        SyntheticEventCtor = SyntheticTransitionEvent;\n        break;\n\n      case 'scroll':\n        SyntheticEventCtor = SyntheticUIEvent;\n        break;\n\n      case 'wheel':\n        SyntheticEventCtor = SyntheticWheelEvent;\n        break;\n\n      case 'copy':\n      case 'cut':\n      case 'paste':\n        SyntheticEventCtor = SyntheticClipboardEvent;\n        break;\n\n      case 'gotpointercapture':\n      case 'lostpointercapture':\n      case 'pointercancel':\n      case 'pointerdown':\n      case 'pointermove':\n      case 'pointerout':\n      case 'pointerover':\n      case 'pointerup':\n        SyntheticEventCtor = SyntheticPointerEvent;\n        break;\n    }\n\n    var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;\n\n    {\n      // Some events don't bubble in the browser.\n      // In the past, React has always bubbled them, but this can be surprising.\n      // We're going to try aligning closer to the browser behavior by not bubbling\n      // them in React either. We'll start by not bubbling onScroll, and then expand.\n      var accumulateTargetOnly = !inCapturePhase && // TODO: ideally, we'd eventually add all events from\n      // nonDelegatedEvents list in DOMPluginEventSystem.\n      // Then we can remove this special list.\n      // This is a breaking change that can wait until React 18.\n      domEventName === 'scroll';\n\n      var _listeners = accumulateSinglePhaseListeners(targetInst, reactName, nativeEvent.type, inCapturePhase, accumulateTargetOnly);\n\n      if (_listeners.length > 0) {\n        // Intentionally create event lazily.\n        var _event = new SyntheticEventCtor(reactName, reactEventType, null, nativeEvent, nativeEventTarget);\n\n        dispatchQueue.push({\n          event: _event,\n          listeners: _listeners\n        });\n      }\n    }\n  }\n\n  // TODO: remove top-level side effect.\n  registerSimpleEvents();\n  registerEvents$2();\n  registerEvents$1();\n  registerEvents$3();\n  registerEvents();\n\n  function extractEvents$5(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer) {\n    // TODO: we should remove the concept of a \"SimpleEventPlugin\".\n    // This is the basic functionality of the event system. All\n    // the other plugins are essentially polyfills. So the plugin\n    // should probably be inlined somewhere and have its logic\n    // be core the to event system. This would potentially allow\n    // us to ship builds of React without the polyfilled plugins below.\n    extractEvents$4(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags);\n    var shouldProcessPolyfillPlugins = (eventSystemFlags & SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS) === 0; // We don't process these events unless we are in the\n    // event's native \"bubble\" phase, which means that we're\n    // not in the capture phase. That's because we emulate\n    // the capture phase here still. This is a trade-off,\n    // because in an ideal world we would not emulate and use\n    // the phases properly, like we do with the SimpleEvent\n    // plugin. However, the plugins below either expect\n    // emulation (EnterLeave) or use state localized to that\n    // plugin (BeforeInput, Change, Select). The state in\n    // these modules complicates things, as you'll essentially\n    // get the case where the capture phase event might change\n    // state, only for the following bubble event to come in\n    // later and not trigger anything as the state now\n    // invalidates the heuristics of the event plugin. We\n    // could alter all these plugins to work in such ways, but\n    // that might cause other unknown side-effects that we\n    // can't foresee right now.\n\n    if (shouldProcessPolyfillPlugins) {\n      extractEvents$2(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget);\n      extractEvents$1(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget);\n      extractEvents$3(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget);\n      extractEvents(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget);\n    }\n  } // List of events that need to be individually attached to media elements.\n\n\n  var mediaEventTypes = ['abort', 'canplay', 'canplaythrough', 'durationchange', 'emptied', 'encrypted', 'ended', 'error', 'loadeddata', 'loadedmetadata', 'loadstart', 'pause', 'play', 'playing', 'progress', 'ratechange', 'resize', 'seeked', 'seeking', 'stalled', 'suspend', 'timeupdate', 'volumechange', 'waiting']; // We should not delegate these events to the container, but rather\n  // set them on the actual target element itself. This is primarily\n  // because these events do not consistently bubble in the DOM.\n\n  var nonDelegatedEvents = new Set(['cancel', 'close', 'invalid', 'load', 'scroll', 'toggle'].concat(mediaEventTypes));\n\n  function executeDispatch(event, listener, currentTarget) {\n    var type = event.type || 'unknown-event';\n    event.currentTarget = currentTarget;\n    invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event);\n    event.currentTarget = null;\n  }\n\n  function processDispatchQueueItemsInOrder(event, dispatchListeners, inCapturePhase) {\n    var previousInstance;\n\n    if (inCapturePhase) {\n      for (var i = dispatchListeners.length - 1; i >= 0; i--) {\n        var _dispatchListeners$i = dispatchListeners[i],\n            instance = _dispatchListeners$i.instance,\n            currentTarget = _dispatchListeners$i.currentTarget,\n            listener = _dispatchListeners$i.listener;\n\n        if (instance !== previousInstance && event.isPropagationStopped()) {\n          return;\n        }\n\n        executeDispatch(event, listener, currentTarget);\n        previousInstance = instance;\n      }\n    } else {\n      for (var _i = 0; _i < dispatchListeners.length; _i++) {\n        var _dispatchListeners$_i = dispatchListeners[_i],\n            _instance = _dispatchListeners$_i.instance,\n            _currentTarget = _dispatchListeners$_i.currentTarget,\n            _listener = _dispatchListeners$_i.listener;\n\n        if (_instance !== previousInstance && event.isPropagationStopped()) {\n          return;\n        }\n\n        executeDispatch(event, _listener, _currentTarget);\n        previousInstance = _instance;\n      }\n    }\n  }\n\n  function processDispatchQueue(dispatchQueue, eventSystemFlags) {\n    var inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;\n\n    for (var i = 0; i < dispatchQueue.length; i++) {\n      var _dispatchQueue$i = dispatchQueue[i],\n          event = _dispatchQueue$i.event,\n          listeners = _dispatchQueue$i.listeners;\n      processDispatchQueueItemsInOrder(event, listeners, inCapturePhase); //  event system doesn't use pooling.\n    } // This would be a good time to rethrow if any of the event handlers threw.\n\n\n    rethrowCaughtError();\n  }\n\n  function dispatchEventsForPlugins(domEventName, eventSystemFlags, nativeEvent, targetInst, targetContainer) {\n    var nativeEventTarget = getEventTarget(nativeEvent);\n    var dispatchQueue = [];\n    extractEvents$5(dispatchQueue, domEventName, targetInst, nativeEvent, nativeEventTarget, eventSystemFlags);\n    processDispatchQueue(dispatchQueue, eventSystemFlags);\n  }\n\n  function listenToNonDelegatedEvent(domEventName, targetElement) {\n    {\n      if (!nonDelegatedEvents.has(domEventName)) {\n        error('Did not expect a listenToNonDelegatedEvent() call for \"%s\". ' + 'This is a bug in React. Please file an issue.', domEventName);\n      }\n    }\n\n    var isCapturePhaseListener = false;\n    var listenerSet = getEventListenerSet(targetElement);\n    var listenerSetKey = getListenerSetKey(domEventName, isCapturePhaseListener);\n\n    if (!listenerSet.has(listenerSetKey)) {\n      addTrappedEventListener(targetElement, domEventName, IS_NON_DELEGATED, isCapturePhaseListener);\n      listenerSet.add(listenerSetKey);\n    }\n  }\n  function listenToNativeEvent(domEventName, isCapturePhaseListener, target) {\n    {\n      if (nonDelegatedEvents.has(domEventName) && !isCapturePhaseListener) {\n        error('Did not expect a listenToNativeEvent() call for \"%s\" in the bubble phase. ' + 'This is a bug in React. Please file an issue.', domEventName);\n      }\n    }\n\n    var eventSystemFlags = 0;\n\n    if (isCapturePhaseListener) {\n      eventSystemFlags |= IS_CAPTURE_PHASE;\n    }\n\n    addTrappedEventListener(target, domEventName, eventSystemFlags, isCapturePhaseListener);\n  } // This is only used by createEventHandle when the\n  var listeningMarker = '_reactListening' + Math.random().toString(36).slice(2);\n  function listenToAllSupportedEvents(rootContainerElement) {\n    if (!rootContainerElement[listeningMarker]) {\n      rootContainerElement[listeningMarker] = true;\n      allNativeEvents.forEach(function (domEventName) {\n        // We handle selectionchange separately because it\n        // doesn't bubble and needs to be on the document.\n        if (domEventName !== 'selectionchange') {\n          if (!nonDelegatedEvents.has(domEventName)) {\n            listenToNativeEvent(domEventName, false, rootContainerElement);\n          }\n\n          listenToNativeEvent(domEventName, true, rootContainerElement);\n        }\n      });\n      var ownerDocument = rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument;\n\n      if (ownerDocument !== null) {\n        // The selectionchange event also needs deduplication\n        // but it is attached to the document.\n        if (!ownerDocument[listeningMarker]) {\n          ownerDocument[listeningMarker] = true;\n          listenToNativeEvent('selectionchange', false, ownerDocument);\n        }\n      }\n    }\n  }\n\n  function addTrappedEventListener(targetContainer, domEventName, eventSystemFlags, isCapturePhaseListener, isDeferredListenerForLegacyFBSupport) {\n    var listener = createEventListenerWrapperWithPriority(targetContainer, domEventName, eventSystemFlags); // If passive option is not supported, then the event will be\n    // active and not passive.\n\n    var isPassiveListener = undefined;\n\n    if (passiveBrowserEventsSupported) {\n      // Browsers introduced an intervention, making these events\n      // passive by default on document. React doesn't bind them\n      // to document anymore, but changing this now would undo\n      // the performance wins from the change. So we emulate\n      // the existing behavior manually on the roots now.\n      // https://github.com/facebook/react/issues/19651\n      if (domEventName === 'touchstart' || domEventName === 'touchmove' || domEventName === 'wheel') {\n        isPassiveListener = true;\n      }\n    }\n\n    targetContainer =  targetContainer;\n    var unsubscribeListener; // When legacyFBSupport is enabled, it's for when we\n\n\n    if (isCapturePhaseListener) {\n      if (isPassiveListener !== undefined) {\n        unsubscribeListener = addEventCaptureListenerWithPassiveFlag(targetContainer, domEventName, listener, isPassiveListener);\n      } else {\n        unsubscribeListener = addEventCaptureListener(targetContainer, domEventName, listener);\n      }\n    } else {\n      if (isPassiveListener !== undefined) {\n        unsubscribeListener = addEventBubbleListenerWithPassiveFlag(targetContainer, domEventName, listener, isPassiveListener);\n      } else {\n        unsubscribeListener = addEventBubbleListener(targetContainer, domEventName, listener);\n      }\n    }\n  }\n\n  function isMatchingRootContainer(grandContainer, targetContainer) {\n    return grandContainer === targetContainer || grandContainer.nodeType === COMMENT_NODE && grandContainer.parentNode === targetContainer;\n  }\n\n  function dispatchEventForPluginEventSystem(domEventName, eventSystemFlags, nativeEvent, targetInst, targetContainer) {\n    var ancestorInst = targetInst;\n\n    if ((eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) === 0 && (eventSystemFlags & IS_NON_DELEGATED) === 0) {\n      var targetContainerNode = targetContainer; // If we are using the legacy FB support flag, we\n\n      if (targetInst !== null) {\n        // The below logic attempts to work out if we need to change\n        // the target fiber to a different ancestor. We had similar logic\n        // in the legacy event system, except the big difference between\n        // systems is that the modern event system now has an event listener\n        // attached to each React Root and React Portal Root. Together,\n        // the DOM nodes representing these roots are the \"rootContainer\".\n        // To figure out which ancestor instance we should use, we traverse\n        // up the fiber tree from the target instance and attempt to find\n        // root boundaries that match that of our current \"rootContainer\".\n        // If we find that \"rootContainer\", we find the parent fiber\n        // sub-tree for that root and make that our ancestor instance.\n        var node = targetInst;\n\n        mainLoop: while (true) {\n          if (node === null) {\n            return;\n          }\n\n          var nodeTag = node.tag;\n\n          if (nodeTag === HostRoot || nodeTag === HostPortal) {\n            var container = node.stateNode.containerInfo;\n\n            if (isMatchingRootContainer(container, targetContainerNode)) {\n              break;\n            }\n\n            if (nodeTag === HostPortal) {\n              // The target is a portal, but it's not the rootContainer we're looking for.\n              // Normally portals handle their own events all the way down to the root.\n              // So we should be able to stop now. However, we don't know if this portal\n              // was part of *our* root.\n              var grandNode = node.return;\n\n              while (grandNode !== null) {\n                var grandTag = grandNode.tag;\n\n                if (grandTag === HostRoot || grandTag === HostPortal) {\n                  var grandContainer = grandNode.stateNode.containerInfo;\n\n                  if (isMatchingRootContainer(grandContainer, targetContainerNode)) {\n                    // This is the rootContainer we're looking for and we found it as\n                    // a parent of the Portal. That means we can ignore it because the\n                    // Portal will bubble through to us.\n                    return;\n                  }\n                }\n\n                grandNode = grandNode.return;\n              }\n            } // Now we need to find it's corresponding host fiber in the other\n            // tree. To do this we can use getClosestInstanceFromNode, but we\n            // need to validate that the fiber is a host instance, otherwise\n            // we need to traverse up through the DOM till we find the correct\n            // node that is from the other tree.\n\n\n            while (container !== null) {\n              var parentNode = getClosestInstanceFromNode(container);\n\n              if (parentNode === null) {\n                return;\n              }\n\n              var parentTag = parentNode.tag;\n\n              if (parentTag === HostComponent || parentTag === HostText) {\n                node = ancestorInst = parentNode;\n                continue mainLoop;\n              }\n\n              container = container.parentNode;\n            }\n          }\n\n          node = node.return;\n        }\n      }\n    }\n\n    batchedUpdates(function () {\n      return dispatchEventsForPlugins(domEventName, eventSystemFlags, nativeEvent, ancestorInst);\n    });\n  }\n\n  function createDispatchListener(instance, listener, currentTarget) {\n    return {\n      instance: instance,\n      listener: listener,\n      currentTarget: currentTarget\n    };\n  }\n\n  function accumulateSinglePhaseListeners(targetFiber, reactName, nativeEventType, inCapturePhase, accumulateTargetOnly, nativeEvent) {\n    var captureName = reactName !== null ? reactName + 'Capture' : null;\n    var reactEventName = inCapturePhase ? captureName : reactName;\n    var listeners = [];\n    var instance = targetFiber;\n    var lastHostComponent = null; // Accumulate all instances and listeners via the target -> root path.\n\n    while (instance !== null) {\n      var _instance2 = instance,\n          stateNode = _instance2.stateNode,\n          tag = _instance2.tag; // Handle listeners that are on HostComponents (i.e. <div>)\n\n      if (tag === HostComponent && stateNode !== null) {\n        lastHostComponent = stateNode; // createEventHandle listeners\n\n\n        if (reactEventName !== null) {\n          var listener = getListener(instance, reactEventName);\n\n          if (listener != null) {\n            listeners.push(createDispatchListener(instance, listener, lastHostComponent));\n          }\n        }\n      } // If we are only accumulating events for the target, then we don't\n      // continue to propagate through the React fiber tree to find other\n      // listeners.\n\n\n      if (accumulateTargetOnly) {\n        break;\n      } // If we are processing the onBeforeBlur event, then we need to take\n\n      instance = instance.return;\n    }\n\n    return listeners;\n  } // We should only use this function for:\n  // - BeforeInputEventPlugin\n  // - ChangeEventPlugin\n  // - SelectEventPlugin\n  // This is because we only process these plugins\n  // in the bubble phase, so we need to accumulate two\n  // phase event listeners (via emulation).\n\n  function accumulateTwoPhaseListeners(targetFiber, reactName) {\n    var captureName = reactName + 'Capture';\n    var listeners = [];\n    var instance = targetFiber; // Accumulate all instances and listeners via the target -> root path.\n\n    while (instance !== null) {\n      var _instance3 = instance,\n          stateNode = _instance3.stateNode,\n          tag = _instance3.tag; // Handle listeners that are on HostComponents (i.e. <div>)\n\n      if (tag === HostComponent && stateNode !== null) {\n        var currentTarget = stateNode;\n        var captureListener = getListener(instance, captureName);\n\n        if (captureListener != null) {\n          listeners.unshift(createDispatchListener(instance, captureListener, currentTarget));\n        }\n\n        var bubbleListener = getListener(instance, reactName);\n\n        if (bubbleListener != null) {\n          listeners.push(createDispatchListener(instance, bubbleListener, currentTarget));\n        }\n      }\n\n      instance = instance.return;\n    }\n\n    return listeners;\n  }\n\n  function getParent(inst) {\n    if (inst === null) {\n      return null;\n    }\n\n    do {\n      inst = inst.return; // TODO: If this is a HostRoot we might want to bail out.\n      // That is depending on if we want nested subtrees (layers) to bubble\n      // events to their parent. We could also go through parentNode on the\n      // host node but that wouldn't work for React Native and doesn't let us\n      // do the portal feature.\n    } while (inst && inst.tag !== HostComponent);\n\n    if (inst) {\n      return inst;\n    }\n\n    return null;\n  }\n  /**\n   * Return the lowest common ancestor of A and B, or null if they are in\n   * different trees.\n   */\n\n\n  function getLowestCommonAncestor(instA, instB) {\n    var nodeA = instA;\n    var nodeB = instB;\n    var depthA = 0;\n\n    for (var tempA = nodeA; tempA; tempA = getParent(tempA)) {\n      depthA++;\n    }\n\n    var depthB = 0;\n\n    for (var tempB = nodeB; tempB; tempB = getParent(tempB)) {\n      depthB++;\n    } // If A is deeper, crawl up.\n\n\n    while (depthA - depthB > 0) {\n      nodeA = getParent(nodeA);\n      depthA--;\n    } // If B is deeper, crawl up.\n\n\n    while (depthB - depthA > 0) {\n      nodeB = getParent(nodeB);\n      depthB--;\n    } // Walk in lockstep until we find a match.\n\n\n    var depth = depthA;\n\n    while (depth--) {\n      if (nodeA === nodeB || nodeB !== null && nodeA === nodeB.alternate) {\n        return nodeA;\n      }\n\n      nodeA = getParent(nodeA);\n      nodeB = getParent(nodeB);\n    }\n\n    return null;\n  }\n\n  function accumulateEnterLeaveListenersForEvent(dispatchQueue, event, target, common, inCapturePhase) {\n    var registrationName = event._reactName;\n    var listeners = [];\n    var instance = target;\n\n    while (instance !== null) {\n      if (instance === common) {\n        break;\n      }\n\n      var _instance4 = instance,\n          alternate = _instance4.alternate,\n          stateNode = _instance4.stateNode,\n          tag = _instance4.tag;\n\n      if (alternate !== null && alternate === common) {\n        break;\n      }\n\n      if (tag === HostComponent && stateNode !== null) {\n        var currentTarget = stateNode;\n\n        if (inCapturePhase) {\n          var captureListener = getListener(instance, registrationName);\n\n          if (captureListener != null) {\n            listeners.unshift(createDispatchListener(instance, captureListener, currentTarget));\n          }\n        } else if (!inCapturePhase) {\n          var bubbleListener = getListener(instance, registrationName);\n\n          if (bubbleListener != null) {\n            listeners.push(createDispatchListener(instance, bubbleListener, currentTarget));\n          }\n        }\n      }\n\n      instance = instance.return;\n    }\n\n    if (listeners.length !== 0) {\n      dispatchQueue.push({\n        event: event,\n        listeners: listeners\n      });\n    }\n  } // We should only use this function for:\n  // - EnterLeaveEventPlugin\n  // This is because we only process this plugin\n  // in the bubble phase, so we need to accumulate two\n  // phase event listeners.\n\n\n  function accumulateEnterLeaveTwoPhaseListeners(dispatchQueue, leaveEvent, enterEvent, from, to) {\n    var common = from && to ? getLowestCommonAncestor(from, to) : null;\n\n    if (from !== null) {\n      accumulateEnterLeaveListenersForEvent(dispatchQueue, leaveEvent, from, common, false);\n    }\n\n    if (to !== null && enterEvent !== null) {\n      accumulateEnterLeaveListenersForEvent(dispatchQueue, enterEvent, to, common, true);\n    }\n  }\n  function getListenerSetKey(domEventName, capture) {\n    return domEventName + \"__\" + (capture ? 'capture' : 'bubble');\n  }\n\n  var didWarnInvalidHydration = false;\n  var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML';\n  var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning';\n  var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';\n  var AUTOFOCUS = 'autoFocus';\n  var CHILDREN = 'children';\n  var STYLE = 'style';\n  var HTML$1 = '__html';\n  var warnedUnknownTags;\n  var validatePropertiesInDevelopment;\n  var warnForPropDifference;\n  var warnForExtraAttributes;\n  var warnForInvalidEventListener;\n  var canDiffStyleForHydrationWarning;\n  var normalizeHTML;\n\n  {\n    warnedUnknownTags = {\n      // There are working polyfills for <dialog>. Let people use it.\n      dialog: true,\n      // Electron ships a custom <webview> tag to display external web content in\n      // an isolated frame and process.\n      // This tag is not present in non Electron environments such as JSDom which\n      // is often used for testing purposes.\n      // @see https://electronjs.org/docs/api/webview-tag\n      webview: true\n    };\n\n    validatePropertiesInDevelopment = function (type, props) {\n      validateProperties(type, props);\n      validateProperties$1(type, props);\n      validateProperties$2(type, props, {\n        registrationNameDependencies: registrationNameDependencies,\n        possibleRegistrationNames: possibleRegistrationNames\n      });\n    }; // IE 11 parses & normalizes the style attribute as opposed to other\n    // browsers. It adds spaces and sorts the properties in some\n    // non-alphabetical order. Handling that would require sorting CSS\n    // properties in the client & server versions or applying\n    // `expectedStyle` to a temporary DOM node to read its `style` attribute\n    // normalized. Since it only affects IE, we're skipping style warnings\n    // in that browser completely in favor of doing all that work.\n    // See https://github.com/facebook/react/issues/11807\n\n\n    canDiffStyleForHydrationWarning = canUseDOM && !document.documentMode;\n\n    warnForPropDifference = function (propName, serverValue, clientValue) {\n      if (didWarnInvalidHydration) {\n        return;\n      }\n\n      var normalizedClientValue = normalizeMarkupForTextOrAttribute(clientValue);\n      var normalizedServerValue = normalizeMarkupForTextOrAttribute(serverValue);\n\n      if (normalizedServerValue === normalizedClientValue) {\n        return;\n      }\n\n      didWarnInvalidHydration = true;\n\n      error('Prop `%s` did not match. Server: %s Client: %s', propName, JSON.stringify(normalizedServerValue), JSON.stringify(normalizedClientValue));\n    };\n\n    warnForExtraAttributes = function (attributeNames) {\n      if (didWarnInvalidHydration) {\n        return;\n      }\n\n      didWarnInvalidHydration = true;\n      var names = [];\n      attributeNames.forEach(function (name) {\n        names.push(name);\n      });\n\n      error('Extra attributes from the server: %s', names);\n    };\n\n    warnForInvalidEventListener = function (registrationName, listener) {\n      if (listener === false) {\n        error('Expected `%s` listener to be a function, instead got `false`.\\n\\n' + 'If you used to conditionally omit it with %s={condition && value}, ' + 'pass %s={condition ? value : undefined} instead.', registrationName, registrationName, registrationName);\n      } else {\n        error('Expected `%s` listener to be a function, instead got a value of `%s` type.', registrationName, typeof listener);\n      }\n    }; // Parse the HTML and read it back to normalize the HTML string so that it\n    // can be used for comparison.\n\n\n    normalizeHTML = function (parent, html) {\n      // We could have created a separate document here to avoid\n      // re-initializing custom elements if they exist. But this breaks\n      // how <noscript> is being handled. So we use the same document.\n      // See the discussion in https://github.com/facebook/react/pull/11157.\n      var testElement = parent.namespaceURI === HTML_NAMESPACE ? parent.ownerDocument.createElement(parent.tagName) : parent.ownerDocument.createElementNS(parent.namespaceURI, parent.tagName);\n      testElement.innerHTML = html;\n      return testElement.innerHTML;\n    };\n  } // HTML parsing normalizes CR and CRLF to LF.\n  // It also can turn \\u0000 into \\uFFFD inside attributes.\n  // https://www.w3.org/TR/html5/single-page.html#preprocessing-the-input-stream\n  // If we have a mismatch, it might be caused by that.\n  // We will still patch up in this case but not fire the warning.\n\n\n  var NORMALIZE_NEWLINES_REGEX = /\\r\\n?/g;\n  var NORMALIZE_NULL_AND_REPLACEMENT_REGEX = /\\u0000|\\uFFFD/g;\n\n  function normalizeMarkupForTextOrAttribute(markup) {\n    {\n      checkHtmlStringCoercion(markup);\n    }\n\n    var markupString = typeof markup === 'string' ? markup : '' + markup;\n    return markupString.replace(NORMALIZE_NEWLINES_REGEX, '\\n').replace(NORMALIZE_NULL_AND_REPLACEMENT_REGEX, '');\n  }\n\n  function checkForUnmatchedText(serverText, clientText, isConcurrentMode, shouldWarnDev) {\n    var normalizedClientText = normalizeMarkupForTextOrAttribute(clientText);\n    var normalizedServerText = normalizeMarkupForTextOrAttribute(serverText);\n\n    if (normalizedServerText === normalizedClientText) {\n      return;\n    }\n\n    if (shouldWarnDev) {\n      {\n        if (!didWarnInvalidHydration) {\n          didWarnInvalidHydration = true;\n\n          error('Text content did not match. Server: \"%s\" Client: \"%s\"', normalizedServerText, normalizedClientText);\n        }\n      }\n    }\n\n    if (isConcurrentMode && enableClientRenderFallbackOnTextMismatch) {\n      // In concurrent roots, we throw when there's a text mismatch and revert to\n      // client rendering, up to the nearest Suspense boundary.\n      throw new Error('Text content does not match server-rendered HTML.');\n    }\n  }\n\n  function getOwnerDocumentFromRootContainer(rootContainerElement) {\n    return rootContainerElement.nodeType === DOCUMENT_NODE ? rootContainerElement : rootContainerElement.ownerDocument;\n  }\n\n  function noop() {}\n\n  function trapClickOnNonInteractiveElement(node) {\n    // Mobile Safari does not fire properly bubble click events on\n    // non-interactive elements, which means delegated click listeners do not\n    // fire. The workaround for this bug involves attaching an empty click\n    // listener on the target node.\n    // https://www.quirksmode.org/blog/archives/2010/09/click_event_del.html\n    // Just set it using the onclick property so that we don't have to manage any\n    // bookkeeping for it. Not sure if we need to clear it when the listener is\n    // removed.\n    // TODO: Only do this for the relevant Safaris maybe?\n    node.onclick = noop;\n  }\n\n  function setInitialDOMProperties(tag, domElement, rootContainerElement, nextProps, isCustomComponentTag) {\n    for (var propKey in nextProps) {\n      if (!nextProps.hasOwnProperty(propKey)) {\n        continue;\n      }\n\n      var nextProp = nextProps[propKey];\n\n      if (propKey === STYLE) {\n        {\n          if (nextProp) {\n            // Freeze the next style object so that we can assume it won't be\n            // mutated. We have already warned for this in the past.\n            Object.freeze(nextProp);\n          }\n        } // Relies on `updateStylesByID` not mutating `styleUpdates`.\n\n\n        setValueForStyles(domElement, nextProp);\n      } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {\n        var nextHtml = nextProp ? nextProp[HTML$1] : undefined;\n\n        if (nextHtml != null) {\n          setInnerHTML(domElement, nextHtml);\n        }\n      } else if (propKey === CHILDREN) {\n        if (typeof nextProp === 'string') {\n          // Avoid setting initial textContent when the text is empty. In IE11 setting\n          // textContent on a <textarea> will cause the placeholder to not\n          // show within the <textarea> until it has been focused and blurred again.\n          // https://github.com/facebook/react/issues/6731#issuecomment-254874553\n          var canSetTextContent = tag !== 'textarea' || nextProp !== '';\n\n          if (canSetTextContent) {\n            setTextContent(domElement, nextProp);\n          }\n        } else if (typeof nextProp === 'number') {\n          setTextContent(domElement, '' + nextProp);\n        }\n      } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (propKey === AUTOFOCUS) ; else if (registrationNameDependencies.hasOwnProperty(propKey)) {\n        if (nextProp != null) {\n          if ( typeof nextProp !== 'function') {\n            warnForInvalidEventListener(propKey, nextProp);\n          }\n\n          if (propKey === 'onScroll') {\n            listenToNonDelegatedEvent('scroll', domElement);\n          }\n        }\n      } else if (nextProp != null) {\n        setValueForProperty(domElement, propKey, nextProp, isCustomComponentTag);\n      }\n    }\n  }\n\n  function updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag) {\n    // TODO: Handle wasCustomComponentTag\n    for (var i = 0; i < updatePayload.length; i += 2) {\n      var propKey = updatePayload[i];\n      var propValue = updatePayload[i + 1];\n\n      if (propKey === STYLE) {\n        setValueForStyles(domElement, propValue);\n      } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {\n        setInnerHTML(domElement, propValue);\n      } else if (propKey === CHILDREN) {\n        setTextContent(domElement, propValue);\n      } else {\n        setValueForProperty(domElement, propKey, propValue, isCustomComponentTag);\n      }\n    }\n  }\n\n  function createElement(type, props, rootContainerElement, parentNamespace) {\n    var isCustomComponentTag; // We create tags in the namespace of their parent container, except HTML\n    // tags get no namespace.\n\n    var ownerDocument = getOwnerDocumentFromRootContainer(rootContainerElement);\n    var domElement;\n    var namespaceURI = parentNamespace;\n\n    if (namespaceURI === HTML_NAMESPACE) {\n      namespaceURI = getIntrinsicNamespace(type);\n    }\n\n    if (namespaceURI === HTML_NAMESPACE) {\n      {\n        isCustomComponentTag = isCustomComponent(type, props); // Should this check be gated by parent namespace? Not sure we want to\n        // allow <SVG> or <mATH>.\n\n        if (!isCustomComponentTag && type !== type.toLowerCase()) {\n          error('<%s /> is using incorrect casing. ' + 'Use PascalCase for React components, ' + 'or lowercase for HTML elements.', type);\n        }\n      }\n\n      if (type === 'script') {\n        // Create the script via .innerHTML so its \"parser-inserted\" flag is\n        // set to true and it does not execute\n        var div = ownerDocument.createElement('div');\n\n        div.innerHTML = '<script><' + '/script>'; // eslint-disable-line\n        // This is guaranteed to yield a script element.\n\n        var firstChild = div.firstChild;\n        domElement = div.removeChild(firstChild);\n      } else if (typeof props.is === 'string') {\n        // $FlowIssue `createElement` should be updated for Web Components\n        domElement = ownerDocument.createElement(type, {\n          is: props.is\n        });\n      } else {\n        // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug.\n        // See discussion in https://github.com/facebook/react/pull/6896\n        // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240\n        domElement = ownerDocument.createElement(type); // Normally attributes are assigned in `setInitialDOMProperties`, however the `multiple` and `size`\n        // attributes on `select`s needs to be added before `option`s are inserted.\n        // This prevents:\n        // - a bug where the `select` does not scroll to the correct option because singular\n        //  `select` elements automatically pick the first item #13222\n        // - a bug where the `select` set the first item as selected despite the `size` attribute #14239\n        // See https://github.com/facebook/react/issues/13222\n        // and https://github.com/facebook/react/issues/14239\n\n        if (type === 'select') {\n          var node = domElement;\n\n          if (props.multiple) {\n            node.multiple = true;\n          } else if (props.size) {\n            // Setting a size greater than 1 causes a select to behave like `multiple=true`, where\n            // it is possible that no option is selected.\n            //\n            // This is only necessary when a select in \"single selection mode\".\n            node.size = props.size;\n          }\n        }\n      }\n    } else {\n      domElement = ownerDocument.createElementNS(namespaceURI, type);\n    }\n\n    {\n      if (namespaceURI === HTML_NAMESPACE) {\n        if (!isCustomComponentTag && Object.prototype.toString.call(domElement) === '[object HTMLUnknownElement]' && !hasOwnProperty.call(warnedUnknownTags, type)) {\n          warnedUnknownTags[type] = true;\n\n          error('The tag <%s> is unrecognized in this browser. ' + 'If you meant to render a React component, start its name with ' + 'an uppercase letter.', type);\n        }\n      }\n    }\n\n    return domElement;\n  }\n  function createTextNode(text, rootContainerElement) {\n    return getOwnerDocumentFromRootContainer(rootContainerElement).createTextNode(text);\n  }\n  function setInitialProperties(domElement, tag, rawProps, rootContainerElement) {\n    var isCustomComponentTag = isCustomComponent(tag, rawProps);\n\n    {\n      validatePropertiesInDevelopment(tag, rawProps);\n    } // TODO: Make sure that we check isMounted before firing any of these events.\n\n\n    var props;\n\n    switch (tag) {\n      case 'dialog':\n        listenToNonDelegatedEvent('cancel', domElement);\n        listenToNonDelegatedEvent('close', domElement);\n        props = rawProps;\n        break;\n\n      case 'iframe':\n      case 'object':\n      case 'embed':\n        // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the load event.\n        listenToNonDelegatedEvent('load', domElement);\n        props = rawProps;\n        break;\n\n      case 'video':\n      case 'audio':\n        // We listen to these events in case to ensure emulated bubble\n        // listeners still fire for all the media events.\n        for (var i = 0; i < mediaEventTypes.length; i++) {\n          listenToNonDelegatedEvent(mediaEventTypes[i], domElement);\n        }\n\n        props = rawProps;\n        break;\n\n      case 'source':\n        // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the error event.\n        listenToNonDelegatedEvent('error', domElement);\n        props = rawProps;\n        break;\n\n      case 'img':\n      case 'image':\n      case 'link':\n        // We listen to these events in case to ensure emulated bubble\n        // listeners still fire for error and load events.\n        listenToNonDelegatedEvent('error', domElement);\n        listenToNonDelegatedEvent('load', domElement);\n        props = rawProps;\n        break;\n\n      case 'details':\n        // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the toggle event.\n        listenToNonDelegatedEvent('toggle', domElement);\n        props = rawProps;\n        break;\n\n      case 'input':\n        initWrapperState(domElement, rawProps);\n        props = getHostProps(domElement, rawProps); // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the invalid event.\n\n        listenToNonDelegatedEvent('invalid', domElement);\n        break;\n\n      case 'option':\n        validateProps(domElement, rawProps);\n        props = rawProps;\n        break;\n\n      case 'select':\n        initWrapperState$1(domElement, rawProps);\n        props = getHostProps$1(domElement, rawProps); // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the invalid event.\n\n        listenToNonDelegatedEvent('invalid', domElement);\n        break;\n\n      case 'textarea':\n        initWrapperState$2(domElement, rawProps);\n        props = getHostProps$2(domElement, rawProps); // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the invalid event.\n\n        listenToNonDelegatedEvent('invalid', domElement);\n        break;\n\n      default:\n        props = rawProps;\n    }\n\n    assertValidProps(tag, props);\n    setInitialDOMProperties(tag, domElement, rootContainerElement, props, isCustomComponentTag);\n\n    switch (tag) {\n      case 'input':\n        // TODO: Make sure we check if this is still unmounted or do any clean\n        // up necessary since we never stop tracking anymore.\n        track(domElement);\n        postMountWrapper(domElement, rawProps, false);\n        break;\n\n      case 'textarea':\n        // TODO: Make sure we check if this is still unmounted or do any clean\n        // up necessary since we never stop tracking anymore.\n        track(domElement);\n        postMountWrapper$3(domElement);\n        break;\n\n      case 'option':\n        postMountWrapper$1(domElement, rawProps);\n        break;\n\n      case 'select':\n        postMountWrapper$2(domElement, rawProps);\n        break;\n\n      default:\n        if (typeof props.onClick === 'function') {\n          // TODO: This cast may not be sound for SVG, MathML or custom elements.\n          trapClickOnNonInteractiveElement(domElement);\n        }\n\n        break;\n    }\n  } // Calculate the diff between the two objects.\n\n  function diffProperties(domElement, tag, lastRawProps, nextRawProps, rootContainerElement) {\n    {\n      validatePropertiesInDevelopment(tag, nextRawProps);\n    }\n\n    var updatePayload = null;\n    var lastProps;\n    var nextProps;\n\n    switch (tag) {\n      case 'input':\n        lastProps = getHostProps(domElement, lastRawProps);\n        nextProps = getHostProps(domElement, nextRawProps);\n        updatePayload = [];\n        break;\n\n      case 'select':\n        lastProps = getHostProps$1(domElement, lastRawProps);\n        nextProps = getHostProps$1(domElement, nextRawProps);\n        updatePayload = [];\n        break;\n\n      case 'textarea':\n        lastProps = getHostProps$2(domElement, lastRawProps);\n        nextProps = getHostProps$2(domElement, nextRawProps);\n        updatePayload = [];\n        break;\n\n      default:\n        lastProps = lastRawProps;\n        nextProps = nextRawProps;\n\n        if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') {\n          // TODO: This cast may not be sound for SVG, MathML or custom elements.\n          trapClickOnNonInteractiveElement(domElement);\n        }\n\n        break;\n    }\n\n    assertValidProps(tag, nextProps);\n    var propKey;\n    var styleName;\n    var styleUpdates = null;\n\n    for (propKey in lastProps) {\n      if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) {\n        continue;\n      }\n\n      if (propKey === STYLE) {\n        var lastStyle = lastProps[propKey];\n\n        for (styleName in lastStyle) {\n          if (lastStyle.hasOwnProperty(styleName)) {\n            if (!styleUpdates) {\n              styleUpdates = {};\n            }\n\n            styleUpdates[styleName] = '';\n          }\n        }\n      } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) ; else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (propKey === AUTOFOCUS) ; else if (registrationNameDependencies.hasOwnProperty(propKey)) {\n        // This is a special case. If any listener updates we need to ensure\n        // that the \"current\" fiber pointer gets updated so we need a commit\n        // to update this element.\n        if (!updatePayload) {\n          updatePayload = [];\n        }\n      } else {\n        // For all other deleted properties we add it to the queue. We use\n        // the allowed property list in the commit phase instead.\n        (updatePayload = updatePayload || []).push(propKey, null);\n      }\n    }\n\n    for (propKey in nextProps) {\n      var nextProp = nextProps[propKey];\n      var lastProp = lastProps != null ? lastProps[propKey] : undefined;\n\n      if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) {\n        continue;\n      }\n\n      if (propKey === STYLE) {\n        {\n          if (nextProp) {\n            // Freeze the next style object so that we can assume it won't be\n            // mutated. We have already warned for this in the past.\n            Object.freeze(nextProp);\n          }\n        }\n\n        if (lastProp) {\n          // Unset styles on `lastProp` but not on `nextProp`.\n          for (styleName in lastProp) {\n            if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) {\n              if (!styleUpdates) {\n                styleUpdates = {};\n              }\n\n              styleUpdates[styleName] = '';\n            }\n          } // Update styles that changed since `lastProp`.\n\n\n          for (styleName in nextProp) {\n            if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) {\n              if (!styleUpdates) {\n                styleUpdates = {};\n              }\n\n              styleUpdates[styleName] = nextProp[styleName];\n            }\n          }\n        } else {\n          // Relies on `updateStylesByID` not mutating `styleUpdates`.\n          if (!styleUpdates) {\n            if (!updatePayload) {\n              updatePayload = [];\n            }\n\n            updatePayload.push(propKey, styleUpdates);\n          }\n\n          styleUpdates = nextProp;\n        }\n      } else if (propKey === DANGEROUSLY_SET_INNER_HTML) {\n        var nextHtml = nextProp ? nextProp[HTML$1] : undefined;\n        var lastHtml = lastProp ? lastProp[HTML$1] : undefined;\n\n        if (nextHtml != null) {\n          if (lastHtml !== nextHtml) {\n            (updatePayload = updatePayload || []).push(propKey, nextHtml);\n          }\n        }\n      } else if (propKey === CHILDREN) {\n        if (typeof nextProp === 'string' || typeof nextProp === 'number') {\n          (updatePayload = updatePayload || []).push(propKey, '' + nextProp);\n        }\n      } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING) ; else if (registrationNameDependencies.hasOwnProperty(propKey)) {\n        if (nextProp != null) {\n          // We eagerly listen to this even though we haven't committed yet.\n          if ( typeof nextProp !== 'function') {\n            warnForInvalidEventListener(propKey, nextProp);\n          }\n\n          if (propKey === 'onScroll') {\n            listenToNonDelegatedEvent('scroll', domElement);\n          }\n        }\n\n        if (!updatePayload && lastProp !== nextProp) {\n          // This is a special case. If any listener updates we need to ensure\n          // that the \"current\" props pointer gets updated so we need a commit\n          // to update this element.\n          updatePayload = [];\n        }\n      } else {\n        // For any other property we always add it to the queue and then we\n        // filter it out using the allowed property list during the commit.\n        (updatePayload = updatePayload || []).push(propKey, nextProp);\n      }\n    }\n\n    if (styleUpdates) {\n      {\n        validateShorthandPropertyCollisionInDev(styleUpdates, nextProps[STYLE]);\n      }\n\n      (updatePayload = updatePayload || []).push(STYLE, styleUpdates);\n    }\n\n    return updatePayload;\n  } // Apply the diff.\n\n  function updateProperties(domElement, updatePayload, tag, lastRawProps, nextRawProps) {\n    // Update checked *before* name.\n    // In the middle of an update, it is possible to have multiple checked.\n    // When a checked radio tries to change name, browser makes another radio's checked false.\n    if (tag === 'input' && nextRawProps.type === 'radio' && nextRawProps.name != null) {\n      updateChecked(domElement, nextRawProps);\n    }\n\n    var wasCustomComponentTag = isCustomComponent(tag, lastRawProps);\n    var isCustomComponentTag = isCustomComponent(tag, nextRawProps); // Apply the diff.\n\n    updateDOMProperties(domElement, updatePayload, wasCustomComponentTag, isCustomComponentTag); // TODO: Ensure that an update gets scheduled if any of the special props\n    // changed.\n\n    switch (tag) {\n      case 'input':\n        // Update the wrapper around inputs *after* updating props. This has to\n        // happen after `updateDOMProperties`. Otherwise HTML5 input validations\n        // raise warnings and prevent the new value from being assigned.\n        updateWrapper(domElement, nextRawProps);\n        break;\n\n      case 'textarea':\n        updateWrapper$1(domElement, nextRawProps);\n        break;\n\n      case 'select':\n        // <select> value update needs to occur after <option> children\n        // reconciliation\n        postUpdateWrapper(domElement, nextRawProps);\n        break;\n    }\n  }\n\n  function getPossibleStandardName(propName) {\n    {\n      var lowerCasedName = propName.toLowerCase();\n\n      if (!possibleStandardNames.hasOwnProperty(lowerCasedName)) {\n        return null;\n      }\n\n      return possibleStandardNames[lowerCasedName] || null;\n    }\n  }\n\n  function diffHydratedProperties(domElement, tag, rawProps, parentNamespace, rootContainerElement, isConcurrentMode, shouldWarnDev) {\n    var isCustomComponentTag;\n    var extraAttributeNames;\n\n    {\n      isCustomComponentTag = isCustomComponent(tag, rawProps);\n      validatePropertiesInDevelopment(tag, rawProps);\n    } // TODO: Make sure that we check isMounted before firing any of these events.\n\n\n    switch (tag) {\n      case 'dialog':\n        listenToNonDelegatedEvent('cancel', domElement);\n        listenToNonDelegatedEvent('close', domElement);\n        break;\n\n      case 'iframe':\n      case 'object':\n      case 'embed':\n        // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the load event.\n        listenToNonDelegatedEvent('load', domElement);\n        break;\n\n      case 'video':\n      case 'audio':\n        // We listen to these events in case to ensure emulated bubble\n        // listeners still fire for all the media events.\n        for (var i = 0; i < mediaEventTypes.length; i++) {\n          listenToNonDelegatedEvent(mediaEventTypes[i], domElement);\n        }\n\n        break;\n\n      case 'source':\n        // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the error event.\n        listenToNonDelegatedEvent('error', domElement);\n        break;\n\n      case 'img':\n      case 'image':\n      case 'link':\n        // We listen to these events in case to ensure emulated bubble\n        // listeners still fire for error and load events.\n        listenToNonDelegatedEvent('error', domElement);\n        listenToNonDelegatedEvent('load', domElement);\n        break;\n\n      case 'details':\n        // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the toggle event.\n        listenToNonDelegatedEvent('toggle', domElement);\n        break;\n\n      case 'input':\n        initWrapperState(domElement, rawProps); // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the invalid event.\n\n        listenToNonDelegatedEvent('invalid', domElement);\n        break;\n\n      case 'option':\n        validateProps(domElement, rawProps);\n        break;\n\n      case 'select':\n        initWrapperState$1(domElement, rawProps); // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the invalid event.\n\n        listenToNonDelegatedEvent('invalid', domElement);\n        break;\n\n      case 'textarea':\n        initWrapperState$2(domElement, rawProps); // We listen to this event in case to ensure emulated bubble\n        // listeners still fire for the invalid event.\n\n        listenToNonDelegatedEvent('invalid', domElement);\n        break;\n    }\n\n    assertValidProps(tag, rawProps);\n\n    {\n      extraAttributeNames = new Set();\n      var attributes = domElement.attributes;\n\n      for (var _i = 0; _i < attributes.length; _i++) {\n        var name = attributes[_i].name.toLowerCase();\n\n        switch (name) {\n          // Controlled attributes are not validated\n          // TODO: Only ignore them on controlled tags.\n          case 'value':\n            break;\n\n          case 'checked':\n            break;\n\n          case 'selected':\n            break;\n\n          default:\n            // Intentionally use the original name.\n            // See discussion in https://github.com/facebook/react/pull/10676.\n            extraAttributeNames.add(attributes[_i].name);\n        }\n      }\n    }\n\n    var updatePayload = null;\n\n    for (var propKey in rawProps) {\n      if (!rawProps.hasOwnProperty(propKey)) {\n        continue;\n      }\n\n      var nextProp = rawProps[propKey];\n\n      if (propKey === CHILDREN) {\n        // For text content children we compare against textContent. This\n        // might match additional HTML that is hidden when we read it using\n        // textContent. E.g. \"foo\" will match \"f<span>oo</span>\" but that still\n        // satisfies our requirement. Our requirement is not to produce perfect\n        // HTML and attributes. Ideally we should preserve structure but it's\n        // ok not to if the visible content is still enough to indicate what\n        // even listeners these nodes might be wired up to.\n        // TODO: Warn if there is more than a single textNode as a child.\n        // TODO: Should we use domElement.firstChild.nodeValue to compare?\n        if (typeof nextProp === 'string') {\n          if (domElement.textContent !== nextProp) {\n            if (rawProps[SUPPRESS_HYDRATION_WARNING] !== true) {\n              checkForUnmatchedText(domElement.textContent, nextProp, isConcurrentMode, shouldWarnDev);\n            }\n\n            updatePayload = [CHILDREN, nextProp];\n          }\n        } else if (typeof nextProp === 'number') {\n          if (domElement.textContent !== '' + nextProp) {\n            if (rawProps[SUPPRESS_HYDRATION_WARNING] !== true) {\n              checkForUnmatchedText(domElement.textContent, nextProp, isConcurrentMode, shouldWarnDev);\n            }\n\n            updatePayload = [CHILDREN, '' + nextProp];\n          }\n        }\n      } else if (registrationNameDependencies.hasOwnProperty(propKey)) {\n        if (nextProp != null) {\n          if ( typeof nextProp !== 'function') {\n            warnForInvalidEventListener(propKey, nextProp);\n          }\n\n          if (propKey === 'onScroll') {\n            listenToNonDelegatedEvent('scroll', domElement);\n          }\n        }\n      } else if (shouldWarnDev && true && // Convince Flow we've calculated it (it's DEV-only in this method.)\n      typeof isCustomComponentTag === 'boolean') {\n        // Validate that the properties correspond to their expected values.\n        var serverValue = void 0;\n        var propertyInfo = isCustomComponentTag && enableCustomElementPropertySupport ? null : getPropertyInfo(propKey);\n\n        if (rawProps[SUPPRESS_HYDRATION_WARNING] === true) ; else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING || // Controlled attributes are not validated\n        // TODO: Only ignore them on controlled tags.\n        propKey === 'value' || propKey === 'checked' || propKey === 'selected') ; else if (propKey === DANGEROUSLY_SET_INNER_HTML) {\n          var serverHTML = domElement.innerHTML;\n          var nextHtml = nextProp ? nextProp[HTML$1] : undefined;\n\n          if (nextHtml != null) {\n            var expectedHTML = normalizeHTML(domElement, nextHtml);\n\n            if (expectedHTML !== serverHTML) {\n              warnForPropDifference(propKey, serverHTML, expectedHTML);\n            }\n          }\n        } else if (propKey === STYLE) {\n          // $FlowFixMe - Should be inferred as not undefined.\n          extraAttributeNames.delete(propKey);\n\n          if (canDiffStyleForHydrationWarning) {\n            var expectedStyle = createDangerousStringForStyles(nextProp);\n            serverValue = domElement.getAttribute('style');\n\n            if (expectedStyle !== serverValue) {\n              warnForPropDifference(propKey, serverValue, expectedStyle);\n            }\n          }\n        } else if (isCustomComponentTag && !enableCustomElementPropertySupport) {\n          // $FlowFixMe - Should be inferred as not undefined.\n          extraAttributeNames.delete(propKey.toLowerCase());\n          serverValue = getValueForAttribute(domElement, propKey, nextProp);\n\n          if (nextProp !== serverValue) {\n            warnForPropDifference(propKey, serverValue, nextProp);\n          }\n        } else if (!shouldIgnoreAttribute(propKey, propertyInfo, isCustomComponentTag) && !shouldRemoveAttribute(propKey, nextProp, propertyInfo, isCustomComponentTag)) {\n          var isMismatchDueToBadCasing = false;\n\n          if (propertyInfo !== null) {\n            // $FlowFixMe - Should be inferred as not undefined.\n            extraAttributeNames.delete(propertyInfo.attributeName);\n            serverValue = getValueForProperty(domElement, propKey, nextProp, propertyInfo);\n          } else {\n            var ownNamespace = parentNamespace;\n\n            if (ownNamespace === HTML_NAMESPACE) {\n              ownNamespace = getIntrinsicNamespace(tag);\n            }\n\n            if (ownNamespace === HTML_NAMESPACE) {\n              // $FlowFixMe - Should be inferred as not undefined.\n              extraAttributeNames.delete(propKey.toLowerCase());\n            } else {\n              var standardName = getPossibleStandardName(propKey);\n\n              if (standardName !== null && standardName !== propKey) {\n                // If an SVG prop is supplied with bad casing, it will\n                // be successfully parsed from HTML, but will produce a mismatch\n                // (and would be incorrectly rendered on the client).\n                // However, we already warn about bad casing elsewhere.\n                // So we'll skip the misleading extra mismatch warning in this case.\n                isMismatchDueToBadCasing = true; // $FlowFixMe - Should be inferred as not undefined.\n\n                extraAttributeNames.delete(standardName);\n              } // $FlowFixMe - Should be inferred as not undefined.\n\n\n              extraAttributeNames.delete(propKey);\n            }\n\n            serverValue = getValueForAttribute(domElement, propKey, nextProp);\n          }\n\n          var dontWarnCustomElement = enableCustomElementPropertySupport  ;\n\n          if (!dontWarnCustomElement && nextProp !== serverValue && !isMismatchDueToBadCasing) {\n            warnForPropDifference(propKey, serverValue, nextProp);\n          }\n        }\n      }\n    }\n\n    {\n      if (shouldWarnDev) {\n        if ( // $FlowFixMe - Should be inferred as not undefined.\n        extraAttributeNames.size > 0 && rawProps[SUPPRESS_HYDRATION_WARNING] !== true) {\n          // $FlowFixMe - Should be inferred as not undefined.\n          warnForExtraAttributes(extraAttributeNames);\n        }\n      }\n    }\n\n    switch (tag) {\n      case 'input':\n        // TODO: Make sure we check if this is still unmounted or do any clean\n        // up necessary since we never stop tracking anymore.\n        track(domElement);\n        postMountWrapper(domElement, rawProps, true);\n        break;\n\n      case 'textarea':\n        // TODO: Make sure we check if this is still unmounted or do any clean\n        // up necessary since we never stop tracking anymore.\n        track(domElement);\n        postMountWrapper$3(domElement);\n        break;\n\n      case 'select':\n      case 'option':\n        // For input and textarea we current always set the value property at\n        // post mount to force it to diverge from attributes. However, for\n        // option and select we don't quite do the same thing and select\n        // is not resilient to the DOM state changing so we don't do that here.\n        // TODO: Consider not doing this for input and textarea.\n        break;\n\n      default:\n        if (typeof rawProps.onClick === 'function') {\n          // TODO: This cast may not be sound for SVG, MathML or custom elements.\n          trapClickOnNonInteractiveElement(domElement);\n        }\n\n        break;\n    }\n\n    return updatePayload;\n  }\n  function diffHydratedText(textNode, text, isConcurrentMode) {\n    var isDifferent = textNode.nodeValue !== text;\n    return isDifferent;\n  }\n  function warnForDeletedHydratableElement(parentNode, child) {\n    {\n      if (didWarnInvalidHydration) {\n        return;\n      }\n\n      didWarnInvalidHydration = true;\n\n      error('Did not expect server HTML to contain a <%s> in <%s>.', child.nodeName.toLowerCase(), parentNode.nodeName.toLowerCase());\n    }\n  }\n  function warnForDeletedHydratableText(parentNode, child) {\n    {\n      if (didWarnInvalidHydration) {\n        return;\n      }\n\n      didWarnInvalidHydration = true;\n\n      error('Did not expect server HTML to contain the text node \"%s\" in <%s>.', child.nodeValue, parentNode.nodeName.toLowerCase());\n    }\n  }\n  function warnForInsertedHydratedElement(parentNode, tag, props) {\n    {\n      if (didWarnInvalidHydration) {\n        return;\n      }\n\n      didWarnInvalidHydration = true;\n\n      error('Expected server HTML to contain a matching <%s> in <%s>.', tag, parentNode.nodeName.toLowerCase());\n    }\n  }\n  function warnForInsertedHydratedText(parentNode, text) {\n    {\n      if (text === '') {\n        // We expect to insert empty text nodes since they're not represented in\n        // the HTML.\n        // TODO: Remove this special case if we can just avoid inserting empty\n        // text nodes.\n        return;\n      }\n\n      if (didWarnInvalidHydration) {\n        return;\n      }\n\n      didWarnInvalidHydration = true;\n\n      error('Expected server HTML to contain a matching text node for \"%s\" in <%s>.', text, parentNode.nodeName.toLowerCase());\n    }\n  }\n  function restoreControlledState$3(domElement, tag, props) {\n    switch (tag) {\n      case 'input':\n        restoreControlledState(domElement, props);\n        return;\n\n      case 'textarea':\n        restoreControlledState$2(domElement, props);\n        return;\n\n      case 'select':\n        restoreControlledState$1(domElement, props);\n        return;\n    }\n  }\n\n  var validateDOMNesting = function () {};\n\n  var updatedAncestorInfo = function () {};\n\n  {\n    // This validation code was written based on the HTML5 parsing spec:\n    // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope\n    //\n    // Note: this does not catch all invalid nesting, nor does it try to (as it's\n    // not clear what practical benefit doing so provides); instead, we warn only\n    // for cases where the parser will give a parse tree differing from what React\n    // intended. For example, <b><div></div></b> is invalid but we don't warn\n    // because it still parses correctly; we do warn for other cases like nested\n    // <p> tags where the beginning of the second element implicitly closes the\n    // first, causing a confusing mess.\n    // https://html.spec.whatwg.org/multipage/syntax.html#special\n    var specialTags = ['address', 'applet', 'area', 'article', 'aside', 'base', 'basefont', 'bgsound', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dir', 'div', 'dl', 'dt', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'iframe', 'img', 'input', 'isindex', 'li', 'link', 'listing', 'main', 'marquee', 'menu', 'menuitem', 'meta', 'nav', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'p', 'param', 'plaintext', 'pre', 'script', 'section', 'select', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'wbr', 'xmp']; // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-scope\n\n    var inScopeTags = ['applet', 'caption', 'html', 'table', 'td', 'th', 'marquee', 'object', 'template', // https://html.spec.whatwg.org/multipage/syntax.html#html-integration-point\n    // TODO: Distinguish by namespace here -- for <title>, including it here\n    // errs on the side of fewer warnings\n    'foreignObject', 'desc', 'title']; // https://html.spec.whatwg.org/multipage/syntax.html#has-an-element-in-button-scope\n\n    var buttonScopeTags = inScopeTags.concat(['button']); // https://html.spec.whatwg.org/multipage/syntax.html#generate-implied-end-tags\n\n    var impliedEndTags = ['dd', 'dt', 'li', 'option', 'optgroup', 'p', 'rp', 'rt'];\n    var emptyAncestorInfo = {\n      current: null,\n      formTag: null,\n      aTagInScope: null,\n      buttonTagInScope: null,\n      nobrTagInScope: null,\n      pTagInButtonScope: null,\n      listItemTagAutoclosing: null,\n      dlItemTagAutoclosing: null\n    };\n\n    updatedAncestorInfo = function (oldInfo, tag) {\n      var ancestorInfo = assign({}, oldInfo || emptyAncestorInfo);\n\n      var info = {\n        tag: tag\n      };\n\n      if (inScopeTags.indexOf(tag) !== -1) {\n        ancestorInfo.aTagInScope = null;\n        ancestorInfo.buttonTagInScope = null;\n        ancestorInfo.nobrTagInScope = null;\n      }\n\n      if (buttonScopeTags.indexOf(tag) !== -1) {\n        ancestorInfo.pTagInButtonScope = null;\n      } // See rules for 'li', 'dd', 'dt' start tags in\n      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody\n\n\n      if (specialTags.indexOf(tag) !== -1 && tag !== 'address' && tag !== 'div' && tag !== 'p') {\n        ancestorInfo.listItemTagAutoclosing = null;\n        ancestorInfo.dlItemTagAutoclosing = null;\n      }\n\n      ancestorInfo.current = info;\n\n      if (tag === 'form') {\n        ancestorInfo.formTag = info;\n      }\n\n      if (tag === 'a') {\n        ancestorInfo.aTagInScope = info;\n      }\n\n      if (tag === 'button') {\n        ancestorInfo.buttonTagInScope = info;\n      }\n\n      if (tag === 'nobr') {\n        ancestorInfo.nobrTagInScope = info;\n      }\n\n      if (tag === 'p') {\n        ancestorInfo.pTagInButtonScope = info;\n      }\n\n      if (tag === 'li') {\n        ancestorInfo.listItemTagAutoclosing = info;\n      }\n\n      if (tag === 'dd' || tag === 'dt') {\n        ancestorInfo.dlItemTagAutoclosing = info;\n      }\n\n      return ancestorInfo;\n    };\n    /**\n     * Returns whether\n     */\n\n\n    var isTagValidWithParent = function (tag, parentTag) {\n      // First, let's check if we're in an unusual parsing mode...\n      switch (parentTag) {\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inselect\n        case 'select':\n          return tag === 'option' || tag === 'optgroup' || tag === '#text';\n\n        case 'optgroup':\n          return tag === 'option' || tag === '#text';\n        // Strictly speaking, seeing an <option> doesn't mean we're in a <select>\n        // but\n\n        case 'option':\n          return tag === '#text';\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intd\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incaption\n        // No special behavior since these rules fall back to \"in body\" mode for\n        // all except special table nodes which cause bad parsing behavior anyway.\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intr\n\n        case 'tr':\n          return tag === 'th' || tag === 'td' || tag === 'style' || tag === 'script' || tag === 'template';\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intbody\n\n        case 'tbody':\n        case 'thead':\n        case 'tfoot':\n          return tag === 'tr' || tag === 'style' || tag === 'script' || tag === 'template';\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-incolgroup\n\n        case 'colgroup':\n          return tag === 'col' || tag === 'template';\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-intable\n\n        case 'table':\n          return tag === 'caption' || tag === 'colgroup' || tag === 'tbody' || tag === 'tfoot' || tag === 'thead' || tag === 'style' || tag === 'script' || tag === 'template';\n        // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inhead\n\n        case 'head':\n          return tag === 'base' || tag === 'basefont' || tag === 'bgsound' || tag === 'link' || tag === 'meta' || tag === 'title' || tag === 'noscript' || tag === 'noframes' || tag === 'style' || tag === 'script' || tag === 'template';\n        // https://html.spec.whatwg.org/multipage/semantics.html#the-html-element\n\n        case 'html':\n          return tag === 'head' || tag === 'body' || tag === 'frameset';\n\n        case 'frameset':\n          return tag === 'frame';\n\n        case '#document':\n          return tag === 'html';\n      } // Probably in the \"in body\" parsing mode, so we outlaw only tag combos\n      // where the parsing rules cause implicit opens or closes to be added.\n      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody\n\n\n      switch (tag) {\n        case 'h1':\n        case 'h2':\n        case 'h3':\n        case 'h4':\n        case 'h5':\n        case 'h6':\n          return parentTag !== 'h1' && parentTag !== 'h2' && parentTag !== 'h3' && parentTag !== 'h4' && parentTag !== 'h5' && parentTag !== 'h6';\n\n        case 'rp':\n        case 'rt':\n          return impliedEndTags.indexOf(parentTag) === -1;\n\n        case 'body':\n        case 'caption':\n        case 'col':\n        case 'colgroup':\n        case 'frameset':\n        case 'frame':\n        case 'head':\n        case 'html':\n        case 'tbody':\n        case 'td':\n        case 'tfoot':\n        case 'th':\n        case 'thead':\n        case 'tr':\n          // These tags are only valid with a few parents that have special child\n          // parsing rules -- if we're down here, then none of those matched and\n          // so we allow it only if we don't know what the parent is, as all other\n          // cases are invalid.\n          return parentTag == null;\n      }\n\n      return true;\n    };\n    /**\n     * Returns whether\n     */\n\n\n    var findInvalidAncestorForTag = function (tag, ancestorInfo) {\n      switch (tag) {\n        case 'address':\n        case 'article':\n        case 'aside':\n        case 'blockquote':\n        case 'center':\n        case 'details':\n        case 'dialog':\n        case 'dir':\n        case 'div':\n        case 'dl':\n        case 'fieldset':\n        case 'figcaption':\n        case 'figure':\n        case 'footer':\n        case 'header':\n        case 'hgroup':\n        case 'main':\n        case 'menu':\n        case 'nav':\n        case 'ol':\n        case 'p':\n        case 'section':\n        case 'summary':\n        case 'ul':\n        case 'pre':\n        case 'listing':\n        case 'table':\n        case 'hr':\n        case 'xmp':\n        case 'h1':\n        case 'h2':\n        case 'h3':\n        case 'h4':\n        case 'h5':\n        case 'h6':\n          return ancestorInfo.pTagInButtonScope;\n\n        case 'form':\n          return ancestorInfo.formTag || ancestorInfo.pTagInButtonScope;\n\n        case 'li':\n          return ancestorInfo.listItemTagAutoclosing;\n\n        case 'dd':\n        case 'dt':\n          return ancestorInfo.dlItemTagAutoclosing;\n\n        case 'button':\n          return ancestorInfo.buttonTagInScope;\n\n        case 'a':\n          // Spec says something about storing a list of markers, but it sounds\n          // equivalent to this check.\n          return ancestorInfo.aTagInScope;\n\n        case 'nobr':\n          return ancestorInfo.nobrTagInScope;\n      }\n\n      return null;\n    };\n\n    var didWarn$1 = {};\n\n    validateDOMNesting = function (childTag, childText, ancestorInfo) {\n      ancestorInfo = ancestorInfo || emptyAncestorInfo;\n      var parentInfo = ancestorInfo.current;\n      var parentTag = parentInfo && parentInfo.tag;\n\n      if (childText != null) {\n        if (childTag != null) {\n          error('validateDOMNesting: when childText is passed, childTag should be null');\n        }\n\n        childTag = '#text';\n      }\n\n      var invalidParent = isTagValidWithParent(childTag, parentTag) ? null : parentInfo;\n      var invalidAncestor = invalidParent ? null : findInvalidAncestorForTag(childTag, ancestorInfo);\n      var invalidParentOrAncestor = invalidParent || invalidAncestor;\n\n      if (!invalidParentOrAncestor) {\n        return;\n      }\n\n      var ancestorTag = invalidParentOrAncestor.tag;\n      var warnKey = !!invalidParent + '|' + childTag + '|' + ancestorTag;\n\n      if (didWarn$1[warnKey]) {\n        return;\n      }\n\n      didWarn$1[warnKey] = true;\n      var tagDisplayName = childTag;\n      var whitespaceInfo = '';\n\n      if (childTag === '#text') {\n        if (/\\S/.test(childText)) {\n          tagDisplayName = 'Text nodes';\n        } else {\n          tagDisplayName = 'Whitespace text nodes';\n          whitespaceInfo = \" Make sure you don't have any extra whitespace between tags on \" + 'each line of your source code.';\n        }\n      } else {\n        tagDisplayName = '<' + childTag + '>';\n      }\n\n      if (invalidParent) {\n        var info = '';\n\n        if (ancestorTag === 'table' && childTag === 'tr') {\n          info += ' Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by ' + 'the browser.';\n        }\n\n        error('validateDOMNesting(...): %s cannot appear as a child of <%s>.%s%s', tagDisplayName, ancestorTag, whitespaceInfo, info);\n      } else {\n        error('validateDOMNesting(...): %s cannot appear as a descendant of ' + '<%s>.', tagDisplayName, ancestorTag);\n      }\n    };\n  }\n\n  var SUPPRESS_HYDRATION_WARNING$1 = 'suppressHydrationWarning';\n  var SUSPENSE_START_DATA = '$';\n  var SUSPENSE_END_DATA = '/$';\n  var SUSPENSE_PENDING_START_DATA = '$?';\n  var SUSPENSE_FALLBACK_START_DATA = '$!';\n  var STYLE$1 = 'style';\n  var eventsEnabled = null;\n  var selectionInformation = null;\n  function getRootHostContext(rootContainerInstance) {\n    var type;\n    var namespace;\n    var nodeType = rootContainerInstance.nodeType;\n\n    switch (nodeType) {\n      case DOCUMENT_NODE:\n      case DOCUMENT_FRAGMENT_NODE:\n        {\n          type = nodeType === DOCUMENT_NODE ? '#document' : '#fragment';\n          var root = rootContainerInstance.documentElement;\n          namespace = root ? root.namespaceURI : getChildNamespace(null, '');\n          break;\n        }\n\n      default:\n        {\n          var container = nodeType === COMMENT_NODE ? rootContainerInstance.parentNode : rootContainerInstance;\n          var ownNamespace = container.namespaceURI || null;\n          type = container.tagName;\n          namespace = getChildNamespace(ownNamespace, type);\n          break;\n        }\n    }\n\n    {\n      var validatedTag = type.toLowerCase();\n      var ancestorInfo = updatedAncestorInfo(null, validatedTag);\n      return {\n        namespace: namespace,\n        ancestorInfo: ancestorInfo\n      };\n    }\n  }\n  function getChildHostContext(parentHostContext, type, rootContainerInstance) {\n    {\n      var parentHostContextDev = parentHostContext;\n      var namespace = getChildNamespace(parentHostContextDev.namespace, type);\n      var ancestorInfo = updatedAncestorInfo(parentHostContextDev.ancestorInfo, type);\n      return {\n        namespace: namespace,\n        ancestorInfo: ancestorInfo\n      };\n    }\n  }\n  function getPublicInstance(instance) {\n    return instance;\n  }\n  function prepareForCommit(containerInfo) {\n    eventsEnabled = isEnabled();\n    selectionInformation = getSelectionInformation();\n    var activeInstance = null;\n\n    setEnabled(false);\n    return activeInstance;\n  }\n  function resetAfterCommit(containerInfo) {\n    restoreSelection(selectionInformation);\n    setEnabled(eventsEnabled);\n    eventsEnabled = null;\n    selectionInformation = null;\n  }\n  function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) {\n    var parentNamespace;\n\n    {\n      // TODO: take namespace into account when validating.\n      var hostContextDev = hostContext;\n      validateDOMNesting(type, null, hostContextDev.ancestorInfo);\n\n      if (typeof props.children === 'string' || typeof props.children === 'number') {\n        var string = '' + props.children;\n        var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type);\n        validateDOMNesting(null, string, ownAncestorInfo);\n      }\n\n      parentNamespace = hostContextDev.namespace;\n    }\n\n    var domElement = createElement(type, props, rootContainerInstance, parentNamespace);\n    precacheFiberNode(internalInstanceHandle, domElement);\n    updateFiberProps(domElement, props);\n    return domElement;\n  }\n  function appendInitialChild(parentInstance, child) {\n    parentInstance.appendChild(child);\n  }\n  function finalizeInitialChildren(domElement, type, props, rootContainerInstance, hostContext) {\n    setInitialProperties(domElement, type, props, rootContainerInstance);\n\n    switch (type) {\n      case 'button':\n      case 'input':\n      case 'select':\n      case 'textarea':\n        return !!props.autoFocus;\n\n      case 'img':\n        return true;\n\n      default:\n        return false;\n    }\n  }\n  function prepareUpdate(domElement, type, oldProps, newProps, rootContainerInstance, hostContext) {\n    {\n      var hostContextDev = hostContext;\n\n      if (typeof newProps.children !== typeof oldProps.children && (typeof newProps.children === 'string' || typeof newProps.children === 'number')) {\n        var string = '' + newProps.children;\n        var ownAncestorInfo = updatedAncestorInfo(hostContextDev.ancestorInfo, type);\n        validateDOMNesting(null, string, ownAncestorInfo);\n      }\n    }\n\n    return diffProperties(domElement, type, oldProps, newProps);\n  }\n  function shouldSetTextContent(type, props) {\n    return type === 'textarea' || type === 'noscript' || typeof props.children === 'string' || typeof props.children === 'number' || typeof props.dangerouslySetInnerHTML === 'object' && props.dangerouslySetInnerHTML !== null && props.dangerouslySetInnerHTML.__html != null;\n  }\n  function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) {\n    {\n      var hostContextDev = hostContext;\n      validateDOMNesting(null, text, hostContextDev.ancestorInfo);\n    }\n\n    var textNode = createTextNode(text, rootContainerInstance);\n    precacheFiberNode(internalInstanceHandle, textNode);\n    return textNode;\n  }\n  function getCurrentEventPriority() {\n    var currentEvent = window.event;\n\n    if (currentEvent === undefined) {\n      return DefaultEventPriority;\n    }\n\n    return getEventPriority(currentEvent.type);\n  }\n  // if a component just imports ReactDOM (e.g. for findDOMNode).\n  // Some environments might not have setTimeout or clearTimeout.\n\n  var scheduleTimeout = typeof setTimeout === 'function' ? setTimeout : undefined;\n  var cancelTimeout = typeof clearTimeout === 'function' ? clearTimeout : undefined;\n  var noTimeout = -1;\n  var localPromise = typeof Promise === 'function' ? Promise : undefined; // -------------------\n  var scheduleMicrotask = typeof queueMicrotask === 'function' ? queueMicrotask : typeof localPromise !== 'undefined' ? function (callback) {\n    return localPromise.resolve(null).then(callback).catch(handleErrorInNextTick);\n  } : scheduleTimeout; // TODO: Determine the best fallback here.\n\n  function handleErrorInNextTick(error) {\n    setTimeout(function () {\n      throw error;\n    });\n  } // -------------------\n  function commitMount(domElement, type, newProps, internalInstanceHandle) {\n    // Despite the naming that might imply otherwise, this method only\n    // fires if there is an `Update` effect scheduled during mounting.\n    // This happens if `finalizeInitialChildren` returns `true` (which it\n    // does to implement the `autoFocus` attribute on the client). But\n    // there are also other cases when this might happen (such as patching\n    // up text content during hydration mismatch). So we'll check this again.\n    switch (type) {\n      case 'button':\n      case 'input':\n      case 'select':\n      case 'textarea':\n        if (newProps.autoFocus) {\n          domElement.focus();\n        }\n\n        return;\n\n      case 'img':\n        {\n          if (newProps.src) {\n            domElement.src = newProps.src;\n          }\n\n          return;\n        }\n    }\n  }\n  function commitUpdate(domElement, updatePayload, type, oldProps, newProps, internalInstanceHandle) {\n    // Apply the diff to the DOM node.\n    updateProperties(domElement, updatePayload, type, oldProps, newProps); // Update the props handle so that we know which props are the ones with\n    // with current event handlers.\n\n    updateFiberProps(domElement, newProps);\n  }\n  function resetTextContent(domElement) {\n    setTextContent(domElement, '');\n  }\n  function commitTextUpdate(textInstance, oldText, newText) {\n    textInstance.nodeValue = newText;\n  }\n  function appendChild(parentInstance, child) {\n    parentInstance.appendChild(child);\n  }\n  function appendChildToContainer(container, child) {\n    var parentNode;\n\n    if (container.nodeType === COMMENT_NODE) {\n      parentNode = container.parentNode;\n      parentNode.insertBefore(child, container);\n    } else {\n      parentNode = container;\n      parentNode.appendChild(child);\n    } // This container might be used for a portal.\n    // If something inside a portal is clicked, that click should bubble\n    // through the React tree. However, on Mobile Safari the click would\n    // never bubble through the *DOM* tree unless an ancestor with onclick\n    // event exists. So we wouldn't see it and dispatch it.\n    // This is why we ensure that non React root containers have inline onclick\n    // defined.\n    // https://github.com/facebook/react/issues/11918\n\n\n    var reactRootContainer = container._reactRootContainer;\n\n    if ((reactRootContainer === null || reactRootContainer === undefined) && parentNode.onclick === null) {\n      // TODO: This cast may not be sound for SVG, MathML or custom elements.\n      trapClickOnNonInteractiveElement(parentNode);\n    }\n  }\n  function insertBefore(parentInstance, child, beforeChild) {\n    parentInstance.insertBefore(child, beforeChild);\n  }\n  function insertInContainerBefore(container, child, beforeChild) {\n    if (container.nodeType === COMMENT_NODE) {\n      container.parentNode.insertBefore(child, beforeChild);\n    } else {\n      container.insertBefore(child, beforeChild);\n    }\n  }\n\n  function removeChild(parentInstance, child) {\n    parentInstance.removeChild(child);\n  }\n  function removeChildFromContainer(container, child) {\n    if (container.nodeType === COMMENT_NODE) {\n      container.parentNode.removeChild(child);\n    } else {\n      container.removeChild(child);\n    }\n  }\n  function clearSuspenseBoundary(parentInstance, suspenseInstance) {\n    var node = suspenseInstance; // Delete all nodes within this suspense boundary.\n    // There might be nested nodes so we need to keep track of how\n    // deep we are and only break out when we're back on top.\n\n    var depth = 0;\n\n    do {\n      var nextNode = node.nextSibling;\n      parentInstance.removeChild(node);\n\n      if (nextNode && nextNode.nodeType === COMMENT_NODE) {\n        var data = nextNode.data;\n\n        if (data === SUSPENSE_END_DATA) {\n          if (depth === 0) {\n            parentInstance.removeChild(nextNode); // Retry if any event replaying was blocked on this.\n\n            retryIfBlockedOn(suspenseInstance);\n            return;\n          } else {\n            depth--;\n          }\n        } else if (data === SUSPENSE_START_DATA || data === SUSPENSE_PENDING_START_DATA || data === SUSPENSE_FALLBACK_START_DATA) {\n          depth++;\n        }\n      }\n\n      node = nextNode;\n    } while (node); // TODO: Warn, we didn't find the end comment boundary.\n    // Retry if any event replaying was blocked on this.\n\n\n    retryIfBlockedOn(suspenseInstance);\n  }\n  function clearSuspenseBoundaryFromContainer(container, suspenseInstance) {\n    if (container.nodeType === COMMENT_NODE) {\n      clearSuspenseBoundary(container.parentNode, suspenseInstance);\n    } else if (container.nodeType === ELEMENT_NODE) {\n      clearSuspenseBoundary(container, suspenseInstance);\n    } // Retry if any event replaying was blocked on this.\n\n\n    retryIfBlockedOn(container);\n  }\n  function hideInstance(instance) {\n    // TODO: Does this work for all element types? What about MathML? Should we\n    // pass host context to this method?\n    instance = instance;\n    var style = instance.style;\n\n    if (typeof style.setProperty === 'function') {\n      style.setProperty('display', 'none', 'important');\n    } else {\n      style.display = 'none';\n    }\n  }\n  function hideTextInstance(textInstance) {\n    textInstance.nodeValue = '';\n  }\n  function unhideInstance(instance, props) {\n    instance = instance;\n    var styleProp = props[STYLE$1];\n    var display = styleProp !== undefined && styleProp !== null && styleProp.hasOwnProperty('display') ? styleProp.display : null;\n    instance.style.display = dangerousStyleValue('display', display);\n  }\n  function unhideTextInstance(textInstance, text) {\n    textInstance.nodeValue = text;\n  }\n  function clearContainer(container) {\n    if (container.nodeType === ELEMENT_NODE) {\n      container.textContent = '';\n    } else if (container.nodeType === DOCUMENT_NODE) {\n      if (container.documentElement) {\n        container.removeChild(container.documentElement);\n      }\n    }\n  } // -------------------\n  function canHydrateInstance(instance, type, props) {\n    if (instance.nodeType !== ELEMENT_NODE || type.toLowerCase() !== instance.nodeName.toLowerCase()) {\n      return null;\n    } // This has now been refined to an element node.\n\n\n    return instance;\n  }\n  function canHydrateTextInstance(instance, text) {\n    if (text === '' || instance.nodeType !== TEXT_NODE) {\n      // Empty strings are not parsed by HTML so there won't be a correct match here.\n      return null;\n    } // This has now been refined to a text node.\n\n\n    return instance;\n  }\n  function canHydrateSuspenseInstance(instance) {\n    if (instance.nodeType !== COMMENT_NODE) {\n      // Empty strings are not parsed by HTML so there won't be a correct match here.\n      return null;\n    } // This has now been refined to a suspense node.\n\n\n    return instance;\n  }\n  function isSuspenseInstancePending(instance) {\n    return instance.data === SUSPENSE_PENDING_START_DATA;\n  }\n  function isSuspenseInstanceFallback(instance) {\n    return instance.data === SUSPENSE_FALLBACK_START_DATA;\n  }\n  function getSuspenseInstanceFallbackErrorDetails(instance) {\n    var dataset = instance.nextSibling && instance.nextSibling.dataset;\n    var digest, message, stack;\n\n    if (dataset) {\n      digest = dataset.dgst;\n\n      {\n        message = dataset.msg;\n        stack = dataset.stck;\n      }\n    }\n\n    {\n      return {\n        message: message,\n        digest: digest,\n        stack: stack\n      };\n    } // let value = {message: undefined, hash: undefined};\n    // const nextSibling = instance.nextSibling;\n    // if (nextSibling) {\n    //   const dataset = ((nextSibling: any): HTMLTemplateElement).dataset;\n    //   value.message = dataset.msg;\n    //   value.hash = dataset.hash;\n    //   if (true) {\n    //     value.stack = dataset.stack;\n    //   }\n    // }\n    // return value;\n\n  }\n  function registerSuspenseInstanceRetry(instance, callback) {\n    instance._reactRetry = callback;\n  }\n\n  function getNextHydratable(node) {\n    // Skip non-hydratable nodes.\n    for (; node != null; node = node.nextSibling) {\n      var nodeType = node.nodeType;\n\n      if (nodeType === ELEMENT_NODE || nodeType === TEXT_NODE) {\n        break;\n      }\n\n      if (nodeType === COMMENT_NODE) {\n        var nodeData = node.data;\n\n        if (nodeData === SUSPENSE_START_DATA || nodeData === SUSPENSE_FALLBACK_START_DATA || nodeData === SUSPENSE_PENDING_START_DATA) {\n          break;\n        }\n\n        if (nodeData === SUSPENSE_END_DATA) {\n          return null;\n        }\n      }\n    }\n\n    return node;\n  }\n\n  function getNextHydratableSibling(instance) {\n    return getNextHydratable(instance.nextSibling);\n  }\n  function getFirstHydratableChild(parentInstance) {\n    return getNextHydratable(parentInstance.firstChild);\n  }\n  function getFirstHydratableChildWithinContainer(parentContainer) {\n    return getNextHydratable(parentContainer.firstChild);\n  }\n  function getFirstHydratableChildWithinSuspenseInstance(parentInstance) {\n    return getNextHydratable(parentInstance.nextSibling);\n  }\n  function hydrateInstance(instance, type, props, rootContainerInstance, hostContext, internalInstanceHandle, shouldWarnDev) {\n    precacheFiberNode(internalInstanceHandle, instance); // TODO: Possibly defer this until the commit phase where all the events\n    // get attached.\n\n    updateFiberProps(instance, props);\n    var parentNamespace;\n\n    {\n      var hostContextDev = hostContext;\n      parentNamespace = hostContextDev.namespace;\n    } // TODO: Temporary hack to check if we're in a concurrent root. We can delete\n    // when the legacy root API is removed.\n\n\n    var isConcurrentMode = (internalInstanceHandle.mode & ConcurrentMode) !== NoMode;\n    return diffHydratedProperties(instance, type, props, parentNamespace, rootContainerInstance, isConcurrentMode, shouldWarnDev);\n  }\n  function hydrateTextInstance(textInstance, text, internalInstanceHandle, shouldWarnDev) {\n    precacheFiberNode(internalInstanceHandle, textInstance); // TODO: Temporary hack to check if we're in a concurrent root. We can delete\n    // when the legacy root API is removed.\n\n    var isConcurrentMode = (internalInstanceHandle.mode & ConcurrentMode) !== NoMode;\n    return diffHydratedText(textInstance, text);\n  }\n  function hydrateSuspenseInstance(suspenseInstance, internalInstanceHandle) {\n    precacheFiberNode(internalInstanceHandle, suspenseInstance);\n  }\n  function getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance) {\n    var node = suspenseInstance.nextSibling; // Skip past all nodes within this suspense boundary.\n    // There might be nested nodes so we need to keep track of how\n    // deep we are and only break out when we're back on top.\n\n    var depth = 0;\n\n    while (node) {\n      if (node.nodeType === COMMENT_NODE) {\n        var data = node.data;\n\n        if (data === SUSPENSE_END_DATA) {\n          if (depth === 0) {\n            return getNextHydratableSibling(node);\n          } else {\n            depth--;\n          }\n        } else if (data === SUSPENSE_START_DATA || data === SUSPENSE_FALLBACK_START_DATA || data === SUSPENSE_PENDING_START_DATA) {\n          depth++;\n        }\n      }\n\n      node = node.nextSibling;\n    } // TODO: Warn, we didn't find the end comment boundary.\n\n\n    return null;\n  } // Returns the SuspenseInstance if this node is a direct child of a\n  // SuspenseInstance. I.e. if its previous sibling is a Comment with\n  // SUSPENSE_x_START_DATA. Otherwise, null.\n\n  function getParentSuspenseInstance(targetInstance) {\n    var node = targetInstance.previousSibling; // Skip past all nodes within this suspense boundary.\n    // There might be nested nodes so we need to keep track of how\n    // deep we are and only break out when we're back on top.\n\n    var depth = 0;\n\n    while (node) {\n      if (node.nodeType === COMMENT_NODE) {\n        var data = node.data;\n\n        if (data === SUSPENSE_START_DATA || data === SUSPENSE_FALLBACK_START_DATA || data === SUSPENSE_PENDING_START_DATA) {\n          if (depth === 0) {\n            return node;\n          } else {\n            depth--;\n          }\n        } else if (data === SUSPENSE_END_DATA) {\n          depth++;\n        }\n      }\n\n      node = node.previousSibling;\n    }\n\n    return null;\n  }\n  function commitHydratedContainer(container) {\n    // Retry if any event replaying was blocked on this.\n    retryIfBlockedOn(container);\n  }\n  function commitHydratedSuspenseInstance(suspenseInstance) {\n    // Retry if any event replaying was blocked on this.\n    retryIfBlockedOn(suspenseInstance);\n  }\n  function shouldDeleteUnhydratedTailInstances(parentType) {\n    return parentType !== 'head' && parentType !== 'body';\n  }\n  function didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, text, isConcurrentMode) {\n    var shouldWarnDev = true;\n    checkForUnmatchedText(textInstance.nodeValue, text, isConcurrentMode, shouldWarnDev);\n  }\n  function didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, text, isConcurrentMode) {\n    if (parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) {\n      var shouldWarnDev = true;\n      checkForUnmatchedText(textInstance.nodeValue, text, isConcurrentMode, shouldWarnDev);\n    }\n  }\n  function didNotHydrateInstanceWithinContainer(parentContainer, instance) {\n    {\n      if (instance.nodeType === ELEMENT_NODE) {\n        warnForDeletedHydratableElement(parentContainer, instance);\n      } else if (instance.nodeType === COMMENT_NODE) ; else {\n        warnForDeletedHydratableText(parentContainer, instance);\n      }\n    }\n  }\n  function didNotHydrateInstanceWithinSuspenseInstance(parentInstance, instance) {\n    {\n      // $FlowFixMe: Only Element or Document can be parent nodes.\n      var parentNode = parentInstance.parentNode;\n\n      if (parentNode !== null) {\n        if (instance.nodeType === ELEMENT_NODE) {\n          warnForDeletedHydratableElement(parentNode, instance);\n        } else if (instance.nodeType === COMMENT_NODE) ; else {\n          warnForDeletedHydratableText(parentNode, instance);\n        }\n      }\n    }\n  }\n  function didNotHydrateInstance(parentType, parentProps, parentInstance, instance, isConcurrentMode) {\n    {\n      if (isConcurrentMode || parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) {\n        if (instance.nodeType === ELEMENT_NODE) {\n          warnForDeletedHydratableElement(parentInstance, instance);\n        } else if (instance.nodeType === COMMENT_NODE) ; else {\n          warnForDeletedHydratableText(parentInstance, instance);\n        }\n      }\n    }\n  }\n  function didNotFindHydratableInstanceWithinContainer(parentContainer, type, props) {\n    {\n      warnForInsertedHydratedElement(parentContainer, type);\n    }\n  }\n  function didNotFindHydratableTextInstanceWithinContainer(parentContainer, text) {\n    {\n      warnForInsertedHydratedText(parentContainer, text);\n    }\n  }\n  function didNotFindHydratableInstanceWithinSuspenseInstance(parentInstance, type, props) {\n    {\n      // $FlowFixMe: Only Element or Document can be parent nodes.\n      var parentNode = parentInstance.parentNode;\n      if (parentNode !== null) warnForInsertedHydratedElement(parentNode, type);\n    }\n  }\n  function didNotFindHydratableTextInstanceWithinSuspenseInstance(parentInstance, text) {\n    {\n      // $FlowFixMe: Only Element or Document can be parent nodes.\n      var parentNode = parentInstance.parentNode;\n      if (parentNode !== null) warnForInsertedHydratedText(parentNode, text);\n    }\n  }\n  function didNotFindHydratableInstance(parentType, parentProps, parentInstance, type, props, isConcurrentMode) {\n    {\n      if (isConcurrentMode || parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) {\n        warnForInsertedHydratedElement(parentInstance, type);\n      }\n    }\n  }\n  function didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, text, isConcurrentMode) {\n    {\n      if (isConcurrentMode || parentProps[SUPPRESS_HYDRATION_WARNING$1] !== true) {\n        warnForInsertedHydratedText(parentInstance, text);\n      }\n    }\n  }\n  function errorHydratingContainer(parentContainer) {\n    {\n      // TODO: This gets logged by onRecoverableError, too, so we should be\n      // able to remove it.\n      error('An error occurred during hydration. The server HTML was replaced with client content in <%s>.', parentContainer.nodeName.toLowerCase());\n    }\n  }\n  function preparePortalMount(portalInstance) {\n    listenToAllSupportedEvents(portalInstance);\n  }\n\n  var randomKey = Math.random().toString(36).slice(2);\n  var internalInstanceKey = '__reactFiber$' + randomKey;\n  var internalPropsKey = '__reactProps$' + randomKey;\n  var internalContainerInstanceKey = '__reactContainer$' + randomKey;\n  var internalEventHandlersKey = '__reactEvents$' + randomKey;\n  var internalEventHandlerListenersKey = '__reactListeners$' + randomKey;\n  var internalEventHandlesSetKey = '__reactHandles$' + randomKey;\n  function detachDeletedInstance(node) {\n    // TODO: This function is only called on host components. I don't think all of\n    // these fields are relevant.\n    delete node[internalInstanceKey];\n    delete node[internalPropsKey];\n    delete node[internalEventHandlersKey];\n    delete node[internalEventHandlerListenersKey];\n    delete node[internalEventHandlesSetKey];\n  }\n  function precacheFiberNode(hostInst, node) {\n    node[internalInstanceKey] = hostInst;\n  }\n  function markContainerAsRoot(hostRoot, node) {\n    node[internalContainerInstanceKey] = hostRoot;\n  }\n  function unmarkContainerAsRoot(node) {\n    node[internalContainerInstanceKey] = null;\n  }\n  function isContainerMarkedAsRoot(node) {\n    return !!node[internalContainerInstanceKey];\n  } // Given a DOM node, return the closest HostComponent or HostText fiber ancestor.\n  // If the target node is part of a hydrated or not yet rendered subtree, then\n  // this may also return a SuspenseComponent or HostRoot to indicate that.\n  // Conceptually the HostRoot fiber is a child of the Container node. So if you\n  // pass the Container node as the targetNode, you will not actually get the\n  // HostRoot back. To get to the HostRoot, you need to pass a child of it.\n  // The same thing applies to Suspense boundaries.\n\n  function getClosestInstanceFromNode(targetNode) {\n    var targetInst = targetNode[internalInstanceKey];\n\n    if (targetInst) {\n      // Don't return HostRoot or SuspenseComponent here.\n      return targetInst;\n    } // If the direct event target isn't a React owned DOM node, we need to look\n    // to see if one of its parents is a React owned DOM node.\n\n\n    var parentNode = targetNode.parentNode;\n\n    while (parentNode) {\n      // We'll check if this is a container root that could include\n      // React nodes in the future. We need to check this first because\n      // if we're a child of a dehydrated container, we need to first\n      // find that inner container before moving on to finding the parent\n      // instance. Note that we don't check this field on  the targetNode\n      // itself because the fibers are conceptually between the container\n      // node and the first child. It isn't surrounding the container node.\n      // If it's not a container, we check if it's an instance.\n      targetInst = parentNode[internalContainerInstanceKey] || parentNode[internalInstanceKey];\n\n      if (targetInst) {\n        // Since this wasn't the direct target of the event, we might have\n        // stepped past dehydrated DOM nodes to get here. However they could\n        // also have been non-React nodes. We need to answer which one.\n        // If we the instance doesn't have any children, then there can't be\n        // a nested suspense boundary within it. So we can use this as a fast\n        // bailout. Most of the time, when people add non-React children to\n        // the tree, it is using a ref to a child-less DOM node.\n        // Normally we'd only need to check one of the fibers because if it\n        // has ever gone from having children to deleting them or vice versa\n        // it would have deleted the dehydrated boundary nested inside already.\n        // However, since the HostRoot starts out with an alternate it might\n        // have one on the alternate so we need to check in case this was a\n        // root.\n        var alternate = targetInst.alternate;\n\n        if (targetInst.child !== null || alternate !== null && alternate.child !== null) {\n          // Next we need to figure out if the node that skipped past is\n          // nested within a dehydrated boundary and if so, which one.\n          var suspenseInstance = getParentSuspenseInstance(targetNode);\n\n          while (suspenseInstance !== null) {\n            // We found a suspense instance. That means that we haven't\n            // hydrated it yet. Even though we leave the comments in the\n            // DOM after hydrating, and there are boundaries in the DOM\n            // that could already be hydrated, we wouldn't have found them\n            // through this pass since if the target is hydrated it would\n            // have had an internalInstanceKey on it.\n            // Let's get the fiber associated with the SuspenseComponent\n            // as the deepest instance.\n            var targetSuspenseInst = suspenseInstance[internalInstanceKey];\n\n            if (targetSuspenseInst) {\n              return targetSuspenseInst;\n            } // If we don't find a Fiber on the comment, it might be because\n            // we haven't gotten to hydrate it yet. There might still be a\n            // parent boundary that hasn't above this one so we need to find\n            // the outer most that is known.\n\n\n            suspenseInstance = getParentSuspenseInstance(suspenseInstance); // If we don't find one, then that should mean that the parent\n            // host component also hasn't hydrated yet. We can return it\n            // below since it will bail out on the isMounted check later.\n          }\n        }\n\n        return targetInst;\n      }\n\n      targetNode = parentNode;\n      parentNode = targetNode.parentNode;\n    }\n\n    return null;\n  }\n  /**\n   * Given a DOM node, return the ReactDOMComponent or ReactDOMTextComponent\n   * instance, or null if the node was not rendered by this React.\n   */\n\n  function getInstanceFromNode(node) {\n    var inst = node[internalInstanceKey] || node[internalContainerInstanceKey];\n\n    if (inst) {\n      if (inst.tag === HostComponent || inst.tag === HostText || inst.tag === SuspenseComponent || inst.tag === HostRoot) {\n        return inst;\n      } else {\n        return null;\n      }\n    }\n\n    return null;\n  }\n  /**\n   * Given a ReactDOMComponent or ReactDOMTextComponent, return the corresponding\n   * DOM node.\n   */\n\n  function getNodeFromInstance(inst) {\n    if (inst.tag === HostComponent || inst.tag === HostText) {\n      // In Fiber this, is just the state node right now. We assume it will be\n      // a host component or host text.\n      return inst.stateNode;\n    } // Without this first invariant, passing a non-DOM-component triggers the next\n    // invariant for a missing parent, which is super confusing.\n\n\n    throw new Error('getNodeFromInstance: Invalid argument.');\n  }\n  function getFiberCurrentPropsFromNode(node) {\n    return node[internalPropsKey] || null;\n  }\n  function updateFiberProps(node, props) {\n    node[internalPropsKey] = props;\n  }\n  function getEventListenerSet(node) {\n    var elementListenerSet = node[internalEventHandlersKey];\n\n    if (elementListenerSet === undefined) {\n      elementListenerSet = node[internalEventHandlersKey] = new Set();\n    }\n\n    return elementListenerSet;\n  }\n\n  var loggedTypeFailures = {};\n  var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame;\n\n  function setCurrentlyValidatingElement(element) {\n    {\n      if (element) {\n        var owner = element._owner;\n        var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);\n        ReactDebugCurrentFrame$1.setExtraStackFrame(stack);\n      } else {\n        ReactDebugCurrentFrame$1.setExtraStackFrame(null);\n      }\n    }\n  }\n\n  function checkPropTypes(typeSpecs, values, location, componentName, element) {\n    {\n      // $FlowFixMe This is okay but Flow doesn't know it.\n      var has = Function.call.bind(hasOwnProperty);\n\n      for (var typeSpecName in typeSpecs) {\n        if (has(typeSpecs, typeSpecName)) {\n          var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to\n          // fail the render phase where it didn't fail before. So we log it.\n          // After these have been cleaned up, we'll let them throw.\n\n          try {\n            // This is intentionally an invariant that gets caught. It's the same\n            // behavior as without this statement except with a better message.\n            if (typeof typeSpecs[typeSpecName] !== 'function') {\n              // eslint-disable-next-line react-internal/prod-error-codes\n              var err = Error((componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.');\n              err.name = 'Invariant Violation';\n              throw err;\n            }\n\n            error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED');\n          } catch (ex) {\n            error$1 = ex;\n          }\n\n          if (error$1 && !(error$1 instanceof Error)) {\n            setCurrentlyValidatingElement(element);\n\n            error('%s: type specification of %s' + ' `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error$1);\n\n            setCurrentlyValidatingElement(null);\n          }\n\n          if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) {\n            // Only monitor this failure once because there tends to be a lot of the\n            // same error.\n            loggedTypeFailures[error$1.message] = true;\n            setCurrentlyValidatingElement(element);\n\n            error('Failed %s type: %s', location, error$1.message);\n\n            setCurrentlyValidatingElement(null);\n          }\n        }\n      }\n    }\n  }\n\n  var valueStack = [];\n  var fiberStack;\n\n  {\n    fiberStack = [];\n  }\n\n  var index = -1;\n\n  function createCursor(defaultValue) {\n    return {\n      current: defaultValue\n    };\n  }\n\n  function pop(cursor, fiber) {\n    if (index < 0) {\n      {\n        error('Unexpected pop.');\n      }\n\n      return;\n    }\n\n    {\n      if (fiber !== fiberStack[index]) {\n        error('Unexpected Fiber popped.');\n      }\n    }\n\n    cursor.current = valueStack[index];\n    valueStack[index] = null;\n\n    {\n      fiberStack[index] = null;\n    }\n\n    index--;\n  }\n\n  function push(cursor, value, fiber) {\n    index++;\n    valueStack[index] = cursor.current;\n\n    {\n      fiberStack[index] = fiber;\n    }\n\n    cursor.current = value;\n  }\n\n  var warnedAboutMissingGetChildContext;\n\n  {\n    warnedAboutMissingGetChildContext = {};\n  }\n\n  var emptyContextObject = {};\n\n  {\n    Object.freeze(emptyContextObject);\n  } // A cursor to the current merged context object on the stack.\n\n\n  var contextStackCursor = createCursor(emptyContextObject); // A cursor to a boolean indicating whether the context has changed.\n\n  var didPerformWorkStackCursor = createCursor(false); // Keep track of the previous context object that was on the stack.\n  // We use this to get access to the parent context after we have already\n  // pushed the next context provider, and now need to merge their contexts.\n\n  var previousContext = emptyContextObject;\n\n  function getUnmaskedContext(workInProgress, Component, didPushOwnContextIfProvider) {\n    {\n      if (didPushOwnContextIfProvider && isContextProvider(Component)) {\n        // If the fiber is a context provider itself, when we read its context\n        // we may have already pushed its own child context on the stack. A context\n        // provider should not \"see\" its own child context. Therefore we read the\n        // previous (parent) context instead for a context provider.\n        return previousContext;\n      }\n\n      return contextStackCursor.current;\n    }\n  }\n\n  function cacheContext(workInProgress, unmaskedContext, maskedContext) {\n    {\n      var instance = workInProgress.stateNode;\n      instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext;\n      instance.__reactInternalMemoizedMaskedChildContext = maskedContext;\n    }\n  }\n\n  function getMaskedContext(workInProgress, unmaskedContext) {\n    {\n      var type = workInProgress.type;\n      var contextTypes = type.contextTypes;\n\n      if (!contextTypes) {\n        return emptyContextObject;\n      } // Avoid recreating masked context unless unmasked context has changed.\n      // Failing to do this will result in unnecessary calls to componentWillReceiveProps.\n      // This may trigger infinite loops if componentWillReceiveProps calls setState.\n\n\n      var instance = workInProgress.stateNode;\n\n      if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) {\n        return instance.__reactInternalMemoizedMaskedChildContext;\n      }\n\n      var context = {};\n\n      for (var key in contextTypes) {\n        context[key] = unmaskedContext[key];\n      }\n\n      {\n        var name = getComponentNameFromFiber(workInProgress) || 'Unknown';\n        checkPropTypes(contextTypes, context, 'context', name);\n      } // Cache unmasked context so we can avoid recreating masked context unless necessary.\n      // Context is created before the class component is instantiated so check for instance.\n\n\n      if (instance) {\n        cacheContext(workInProgress, unmaskedContext, context);\n      }\n\n      return context;\n    }\n  }\n\n  function hasContextChanged() {\n    {\n      return didPerformWorkStackCursor.current;\n    }\n  }\n\n  function isContextProvider(type) {\n    {\n      var childContextTypes = type.childContextTypes;\n      return childContextTypes !== null && childContextTypes !== undefined;\n    }\n  }\n\n  function popContext(fiber) {\n    {\n      pop(didPerformWorkStackCursor, fiber);\n      pop(contextStackCursor, fiber);\n    }\n  }\n\n  function popTopLevelContextObject(fiber) {\n    {\n      pop(didPerformWorkStackCursor, fiber);\n      pop(contextStackCursor, fiber);\n    }\n  }\n\n  function pushTopLevelContextObject(fiber, context, didChange) {\n    {\n      if (contextStackCursor.current !== emptyContextObject) {\n        throw new Error('Unexpected context found on stack. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n      }\n\n      push(contextStackCursor, context, fiber);\n      push(didPerformWorkStackCursor, didChange, fiber);\n    }\n  }\n\n  function processChildContext(fiber, type, parentContext) {\n    {\n      var instance = fiber.stateNode;\n      var childContextTypes = type.childContextTypes; // TODO (bvaughn) Replace this behavior with an invariant() in the future.\n      // It has only been added in Fiber to match the (unintentional) behavior in Stack.\n\n      if (typeof instance.getChildContext !== 'function') {\n        {\n          var componentName = getComponentNameFromFiber(fiber) || 'Unknown';\n\n          if (!warnedAboutMissingGetChildContext[componentName]) {\n            warnedAboutMissingGetChildContext[componentName] = true;\n\n            error('%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName);\n          }\n        }\n\n        return parentContext;\n      }\n\n      var childContext = instance.getChildContext();\n\n      for (var contextKey in childContext) {\n        if (!(contextKey in childContextTypes)) {\n          throw new Error((getComponentNameFromFiber(fiber) || 'Unknown') + \".getChildContext(): key \\\"\" + contextKey + \"\\\" is not defined in childContextTypes.\");\n        }\n      }\n\n      {\n        var name = getComponentNameFromFiber(fiber) || 'Unknown';\n        checkPropTypes(childContextTypes, childContext, 'child context', name);\n      }\n\n      return assign({}, parentContext, childContext);\n    }\n  }\n\n  function pushContextProvider(workInProgress) {\n    {\n      var instance = workInProgress.stateNode; // We push the context as early as possible to ensure stack integrity.\n      // If the instance does not exist yet, we will push null at first,\n      // and replace it on the stack later when invalidating the context.\n\n      var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyContextObject; // Remember the parent context so we can merge with it later.\n      // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates.\n\n      previousContext = contextStackCursor.current;\n      push(contextStackCursor, memoizedMergedChildContext, workInProgress);\n      push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress);\n      return true;\n    }\n  }\n\n  function invalidateContextProvider(workInProgress, type, didChange) {\n    {\n      var instance = workInProgress.stateNode;\n\n      if (!instance) {\n        throw new Error('Expected to have an instance by this point. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n      }\n\n      if (didChange) {\n        // Merge parent and own context.\n        // Skip this if we're not updating due to sCU.\n        // This avoids unnecessarily recomputing memoized values.\n        var mergedContext = processChildContext(workInProgress, type, previousContext);\n        instance.__reactInternalMemoizedMergedChildContext = mergedContext; // Replace the old (or empty) context with the new one.\n        // It is important to unwind the context in the reverse order.\n\n        pop(didPerformWorkStackCursor, workInProgress);\n        pop(contextStackCursor, workInProgress); // Now push the new context and mark that it has changed.\n\n        push(contextStackCursor, mergedContext, workInProgress);\n        push(didPerformWorkStackCursor, didChange, workInProgress);\n      } else {\n        pop(didPerformWorkStackCursor, workInProgress);\n        push(didPerformWorkStackCursor, didChange, workInProgress);\n      }\n    }\n  }\n\n  function findCurrentUnmaskedContext(fiber) {\n    {\n      // Currently this is only used with renderSubtreeIntoContainer; not sure if it\n      // makes sense elsewhere\n      if (!isFiberMounted(fiber) || fiber.tag !== ClassComponent) {\n        throw new Error('Expected subtree parent to be a mounted class component. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n      }\n\n      var node = fiber;\n\n      do {\n        switch (node.tag) {\n          case HostRoot:\n            return node.stateNode.context;\n\n          case ClassComponent:\n            {\n              var Component = node.type;\n\n              if (isContextProvider(Component)) {\n                return node.stateNode.__reactInternalMemoizedMergedChildContext;\n              }\n\n              break;\n            }\n        }\n\n        node = node.return;\n      } while (node !== null);\n\n      throw new Error('Found unexpected detached subtree parent. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n    }\n  }\n\n  var LegacyRoot = 0;\n  var ConcurrentRoot = 1;\n\n  var syncQueue = null;\n  var includesLegacySyncCallbacks = false;\n  var isFlushingSyncQueue = false;\n  function scheduleSyncCallback(callback) {\n    // Push this callback into an internal queue. We'll flush these either in\n    // the next tick, or earlier if something calls `flushSyncCallbackQueue`.\n    if (syncQueue === null) {\n      syncQueue = [callback];\n    } else {\n      // Push onto existing queue. Don't need to schedule a callback because\n      // we already scheduled one when we created the queue.\n      syncQueue.push(callback);\n    }\n  }\n  function scheduleLegacySyncCallback(callback) {\n    includesLegacySyncCallbacks = true;\n    scheduleSyncCallback(callback);\n  }\n  function flushSyncCallbacksOnlyInLegacyMode() {\n    // Only flushes the queue if there's a legacy sync callback scheduled.\n    // TODO: There's only a single type of callback: performSyncOnWorkOnRoot. So\n    // it might make more sense for the queue to be a list of roots instead of a\n    // list of generic callbacks. Then we can have two: one for legacy roots, one\n    // for concurrent roots. And this method would only flush the legacy ones.\n    if (includesLegacySyncCallbacks) {\n      flushSyncCallbacks();\n    }\n  }\n  function flushSyncCallbacks() {\n    if (!isFlushingSyncQueue && syncQueue !== null) {\n      // Prevent re-entrance.\n      isFlushingSyncQueue = true;\n      var i = 0;\n      var previousUpdatePriority = getCurrentUpdatePriority();\n\n      try {\n        var isSync = true;\n        var queue = syncQueue; // TODO: Is this necessary anymore? The only user code that runs in this\n        // queue is in the render or commit phases.\n\n        setCurrentUpdatePriority(DiscreteEventPriority);\n\n        for (; i < queue.length; i++) {\n          var callback = queue[i];\n\n          do {\n            callback = callback(isSync);\n          } while (callback !== null);\n        }\n\n        syncQueue = null;\n        includesLegacySyncCallbacks = false;\n      } catch (error) {\n        // If something throws, leave the remaining callbacks on the queue.\n        if (syncQueue !== null) {\n          syncQueue = syncQueue.slice(i + 1);\n        } // Resume flushing in the next tick\n\n\n        scheduleCallback(ImmediatePriority, flushSyncCallbacks);\n        throw error;\n      } finally {\n        setCurrentUpdatePriority(previousUpdatePriority);\n        isFlushingSyncQueue = false;\n      }\n    }\n\n    return null;\n  }\n\n  // TODO: Use the unified fiber stack module instead of this local one?\n  // Intentionally not using it yet to derisk the initial implementation, because\n  // the way we push/pop these values is a bit unusual. If there's a mistake, I'd\n  // rather the ids be wrong than crash the whole reconciler.\n  var forkStack = [];\n  var forkStackIndex = 0;\n  var treeForkProvider = null;\n  var treeForkCount = 0;\n  var idStack = [];\n  var idStackIndex = 0;\n  var treeContextProvider = null;\n  var treeContextId = 1;\n  var treeContextOverflow = '';\n  function isForkedChild(workInProgress) {\n    warnIfNotHydrating();\n    return (workInProgress.flags & Forked) !== NoFlags;\n  }\n  function getForksAtLevel(workInProgress) {\n    warnIfNotHydrating();\n    return treeForkCount;\n  }\n  function getTreeId() {\n    var overflow = treeContextOverflow;\n    var idWithLeadingBit = treeContextId;\n    var id = idWithLeadingBit & ~getLeadingBit(idWithLeadingBit);\n    return id.toString(32) + overflow;\n  }\n  function pushTreeFork(workInProgress, totalChildren) {\n    // This is called right after we reconcile an array (or iterator) of child\n    // fibers, because that's the only place where we know how many children in\n    // the whole set without doing extra work later, or storing addtional\n    // information on the fiber.\n    //\n    // That's why this function is separate from pushTreeId — it's called during\n    // the render phase of the fork parent, not the child, which is where we push\n    // the other context values.\n    //\n    // In the Fizz implementation this is much simpler because the child is\n    // rendered in the same callstack as the parent.\n    //\n    // It might be better to just add a `forks` field to the Fiber type. It would\n    // make this module simpler.\n    warnIfNotHydrating();\n    forkStack[forkStackIndex++] = treeForkCount;\n    forkStack[forkStackIndex++] = treeForkProvider;\n    treeForkProvider = workInProgress;\n    treeForkCount = totalChildren;\n  }\n  function pushTreeId(workInProgress, totalChildren, index) {\n    warnIfNotHydrating();\n    idStack[idStackIndex++] = treeContextId;\n    idStack[idStackIndex++] = treeContextOverflow;\n    idStack[idStackIndex++] = treeContextProvider;\n    treeContextProvider = workInProgress;\n    var baseIdWithLeadingBit = treeContextId;\n    var baseOverflow = treeContextOverflow; // The leftmost 1 marks the end of the sequence, non-inclusive. It's not part\n    // of the id; we use it to account for leading 0s.\n\n    var baseLength = getBitLength(baseIdWithLeadingBit) - 1;\n    var baseId = baseIdWithLeadingBit & ~(1 << baseLength);\n    var slot = index + 1;\n    var length = getBitLength(totalChildren) + baseLength; // 30 is the max length we can store without overflowing, taking into\n    // consideration the leading 1 we use to mark the end of the sequence.\n\n    if (length > 30) {\n      // We overflowed the bitwise-safe range. Fall back to slower algorithm.\n      // This branch assumes the length of the base id is greater than 5; it won't\n      // work for smaller ids, because you need 5 bits per character.\n      //\n      // We encode the id in multiple steps: first the base id, then the\n      // remaining digits.\n      //\n      // Each 5 bit sequence corresponds to a single base 32 character. So for\n      // example, if the current id is 23 bits long, we can convert 20 of those\n      // bits into a string of 4 characters, with 3 bits left over.\n      //\n      // First calculate how many bits in the base id represent a complete\n      // sequence of characters.\n      var numberOfOverflowBits = baseLength - baseLength % 5; // Then create a bitmask that selects only those bits.\n\n      var newOverflowBits = (1 << numberOfOverflowBits) - 1; // Select the bits, and convert them to a base 32 string.\n\n      var newOverflow = (baseId & newOverflowBits).toString(32); // Now we can remove those bits from the base id.\n\n      var restOfBaseId = baseId >> numberOfOverflowBits;\n      var restOfBaseLength = baseLength - numberOfOverflowBits; // Finally, encode the rest of the bits using the normal algorithm. Because\n      // we made more room, this time it won't overflow.\n\n      var restOfLength = getBitLength(totalChildren) + restOfBaseLength;\n      var restOfNewBits = slot << restOfBaseLength;\n      var id = restOfNewBits | restOfBaseId;\n      var overflow = newOverflow + baseOverflow;\n      treeContextId = 1 << restOfLength | id;\n      treeContextOverflow = overflow;\n    } else {\n      // Normal path\n      var newBits = slot << baseLength;\n\n      var _id = newBits | baseId;\n\n      var _overflow = baseOverflow;\n      treeContextId = 1 << length | _id;\n      treeContextOverflow = _overflow;\n    }\n  }\n  function pushMaterializedTreeId(workInProgress) {\n    warnIfNotHydrating(); // This component materialized an id. This will affect any ids that appear\n    // in its children.\n\n    var returnFiber = workInProgress.return;\n\n    if (returnFiber !== null) {\n      var numberOfForks = 1;\n      var slotIndex = 0;\n      pushTreeFork(workInProgress, numberOfForks);\n      pushTreeId(workInProgress, numberOfForks, slotIndex);\n    }\n  }\n\n  function getBitLength(number) {\n    return 32 - clz32(number);\n  }\n\n  function getLeadingBit(id) {\n    return 1 << getBitLength(id) - 1;\n  }\n\n  function popTreeContext(workInProgress) {\n    // Restore the previous values.\n    // This is a bit more complicated than other context-like modules in Fiber\n    // because the same Fiber may appear on the stack multiple times and for\n    // different reasons. We have to keep popping until the work-in-progress is\n    // no longer at the top of the stack.\n    while (workInProgress === treeForkProvider) {\n      treeForkProvider = forkStack[--forkStackIndex];\n      forkStack[forkStackIndex] = null;\n      treeForkCount = forkStack[--forkStackIndex];\n      forkStack[forkStackIndex] = null;\n    }\n\n    while (workInProgress === treeContextProvider) {\n      treeContextProvider = idStack[--idStackIndex];\n      idStack[idStackIndex] = null;\n      treeContextOverflow = idStack[--idStackIndex];\n      idStack[idStackIndex] = null;\n      treeContextId = idStack[--idStackIndex];\n      idStack[idStackIndex] = null;\n    }\n  }\n  function getSuspendedTreeContext() {\n    warnIfNotHydrating();\n\n    if (treeContextProvider !== null) {\n      return {\n        id: treeContextId,\n        overflow: treeContextOverflow\n      };\n    } else {\n      return null;\n    }\n  }\n  function restoreSuspendedTreeContext(workInProgress, suspendedContext) {\n    warnIfNotHydrating();\n    idStack[idStackIndex++] = treeContextId;\n    idStack[idStackIndex++] = treeContextOverflow;\n    idStack[idStackIndex++] = treeContextProvider;\n    treeContextId = suspendedContext.id;\n    treeContextOverflow = suspendedContext.overflow;\n    treeContextProvider = workInProgress;\n  }\n\n  function warnIfNotHydrating() {\n    {\n      if (!getIsHydrating()) {\n        error('Expected to be hydrating. This is a bug in React. Please file ' + 'an issue.');\n      }\n    }\n  }\n\n  // This may have been an insertion or a hydration.\n\n  var hydrationParentFiber = null;\n  var nextHydratableInstance = null;\n  var isHydrating = false; // This flag allows for warning supression when we expect there to be mismatches\n  // due to earlier mismatches or a suspended fiber.\n\n  var didSuspendOrErrorDEV = false; // Hydration errors that were thrown inside this boundary\n\n  var hydrationErrors = null;\n\n  function warnIfHydrating() {\n    {\n      if (isHydrating) {\n        error('We should not be hydrating here. This is a bug in React. Please file a bug.');\n      }\n    }\n  }\n\n  function markDidThrowWhileHydratingDEV() {\n    {\n      didSuspendOrErrorDEV = true;\n    }\n  }\n  function didSuspendOrErrorWhileHydratingDEV() {\n    {\n      return didSuspendOrErrorDEV;\n    }\n  }\n\n  function enterHydrationState(fiber) {\n\n    var parentInstance = fiber.stateNode.containerInfo;\n    nextHydratableInstance = getFirstHydratableChildWithinContainer(parentInstance);\n    hydrationParentFiber = fiber;\n    isHydrating = true;\n    hydrationErrors = null;\n    didSuspendOrErrorDEV = false;\n    return true;\n  }\n\n  function reenterHydrationStateFromDehydratedSuspenseInstance(fiber, suspenseInstance, treeContext) {\n\n    nextHydratableInstance = getFirstHydratableChildWithinSuspenseInstance(suspenseInstance);\n    hydrationParentFiber = fiber;\n    isHydrating = true;\n    hydrationErrors = null;\n    didSuspendOrErrorDEV = false;\n\n    if (treeContext !== null) {\n      restoreSuspendedTreeContext(fiber, treeContext);\n    }\n\n    return true;\n  }\n\n  function warnUnhydratedInstance(returnFiber, instance) {\n    {\n      switch (returnFiber.tag) {\n        case HostRoot:\n          {\n            didNotHydrateInstanceWithinContainer(returnFiber.stateNode.containerInfo, instance);\n            break;\n          }\n\n        case HostComponent:\n          {\n            var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;\n            didNotHydrateInstance(returnFiber.type, returnFiber.memoizedProps, returnFiber.stateNode, instance, // TODO: Delete this argument when we remove the legacy root API.\n            isConcurrentMode);\n            break;\n          }\n\n        case SuspenseComponent:\n          {\n            var suspenseState = returnFiber.memoizedState;\n            if (suspenseState.dehydrated !== null) didNotHydrateInstanceWithinSuspenseInstance(suspenseState.dehydrated, instance);\n            break;\n          }\n      }\n    }\n  }\n\n  function deleteHydratableInstance(returnFiber, instance) {\n    warnUnhydratedInstance(returnFiber, instance);\n    var childToDelete = createFiberFromHostInstanceForDeletion();\n    childToDelete.stateNode = instance;\n    childToDelete.return = returnFiber;\n    var deletions = returnFiber.deletions;\n\n    if (deletions === null) {\n      returnFiber.deletions = [childToDelete];\n      returnFiber.flags |= ChildDeletion;\n    } else {\n      deletions.push(childToDelete);\n    }\n  }\n\n  function warnNonhydratedInstance(returnFiber, fiber) {\n    {\n      if (didSuspendOrErrorDEV) {\n        // Inside a boundary that already suspended. We're currently rendering the\n        // siblings of a suspended node. The mismatch may be due to the missing\n        // data, so it's probably a false positive.\n        return;\n      }\n\n      switch (returnFiber.tag) {\n        case HostRoot:\n          {\n            var parentContainer = returnFiber.stateNode.containerInfo;\n\n            switch (fiber.tag) {\n              case HostComponent:\n                var type = fiber.type;\n                var props = fiber.pendingProps;\n                didNotFindHydratableInstanceWithinContainer(parentContainer, type);\n                break;\n\n              case HostText:\n                var text = fiber.pendingProps;\n                didNotFindHydratableTextInstanceWithinContainer(parentContainer, text);\n                break;\n            }\n\n            break;\n          }\n\n        case HostComponent:\n          {\n            var parentType = returnFiber.type;\n            var parentProps = returnFiber.memoizedProps;\n            var parentInstance = returnFiber.stateNode;\n\n            switch (fiber.tag) {\n              case HostComponent:\n                {\n                  var _type = fiber.type;\n                  var _props = fiber.pendingProps;\n                  var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;\n                  didNotFindHydratableInstance(parentType, parentProps, parentInstance, _type, _props, // TODO: Delete this argument when we remove the legacy root API.\n                  isConcurrentMode);\n                  break;\n                }\n\n              case HostText:\n                {\n                  var _text = fiber.pendingProps;\n\n                  var _isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;\n\n                  didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, _text, // TODO: Delete this argument when we remove the legacy root API.\n                  _isConcurrentMode);\n                  break;\n                }\n            }\n\n            break;\n          }\n\n        case SuspenseComponent:\n          {\n            var suspenseState = returnFiber.memoizedState;\n            var _parentInstance = suspenseState.dehydrated;\n            if (_parentInstance !== null) switch (fiber.tag) {\n              case HostComponent:\n                var _type2 = fiber.type;\n                var _props2 = fiber.pendingProps;\n                didNotFindHydratableInstanceWithinSuspenseInstance(_parentInstance, _type2);\n                break;\n\n              case HostText:\n                var _text2 = fiber.pendingProps;\n                didNotFindHydratableTextInstanceWithinSuspenseInstance(_parentInstance, _text2);\n                break;\n            }\n            break;\n          }\n\n        default:\n          return;\n      }\n    }\n  }\n\n  function insertNonHydratedInstance(returnFiber, fiber) {\n    fiber.flags = fiber.flags & ~Hydrating | Placement;\n    warnNonhydratedInstance(returnFiber, fiber);\n  }\n\n  function tryHydrate(fiber, nextInstance) {\n    switch (fiber.tag) {\n      case HostComponent:\n        {\n          var type = fiber.type;\n          var props = fiber.pendingProps;\n          var instance = canHydrateInstance(nextInstance, type);\n\n          if (instance !== null) {\n            fiber.stateNode = instance;\n            hydrationParentFiber = fiber;\n            nextHydratableInstance = getFirstHydratableChild(instance);\n            return true;\n          }\n\n          return false;\n        }\n\n      case HostText:\n        {\n          var text = fiber.pendingProps;\n          var textInstance = canHydrateTextInstance(nextInstance, text);\n\n          if (textInstance !== null) {\n            fiber.stateNode = textInstance;\n            hydrationParentFiber = fiber; // Text Instances don't have children so there's nothing to hydrate.\n\n            nextHydratableInstance = null;\n            return true;\n          }\n\n          return false;\n        }\n\n      case SuspenseComponent:\n        {\n          var suspenseInstance = canHydrateSuspenseInstance(nextInstance);\n\n          if (suspenseInstance !== null) {\n            var suspenseState = {\n              dehydrated: suspenseInstance,\n              treeContext: getSuspendedTreeContext(),\n              retryLane: OffscreenLane\n            };\n            fiber.memoizedState = suspenseState; // Store the dehydrated fragment as a child fiber.\n            // This simplifies the code for getHostSibling and deleting nodes,\n            // since it doesn't have to consider all Suspense boundaries and\n            // check if they're dehydrated ones or not.\n\n            var dehydratedFragment = createFiberFromDehydratedFragment(suspenseInstance);\n            dehydratedFragment.return = fiber;\n            fiber.child = dehydratedFragment;\n            hydrationParentFiber = fiber; // While a Suspense Instance does have children, we won't step into\n            // it during the first pass. Instead, we'll reenter it later.\n\n            nextHydratableInstance = null;\n            return true;\n          }\n\n          return false;\n        }\n\n      default:\n        return false;\n    }\n  }\n\n  function shouldClientRenderOnMismatch(fiber) {\n    return (fiber.mode & ConcurrentMode) !== NoMode && (fiber.flags & DidCapture) === NoFlags;\n  }\n\n  function throwOnHydrationMismatch(fiber) {\n    throw new Error('Hydration failed because the initial UI does not match what was ' + 'rendered on the server.');\n  }\n\n  function tryToClaimNextHydratableInstance(fiber) {\n    if (!isHydrating) {\n      return;\n    }\n\n    var nextInstance = nextHydratableInstance;\n\n    if (!nextInstance) {\n      if (shouldClientRenderOnMismatch(fiber)) {\n        warnNonhydratedInstance(hydrationParentFiber, fiber);\n        throwOnHydrationMismatch();\n      } // Nothing to hydrate. Make it an insertion.\n\n\n      insertNonHydratedInstance(hydrationParentFiber, fiber);\n      isHydrating = false;\n      hydrationParentFiber = fiber;\n      return;\n    }\n\n    var firstAttemptedInstance = nextInstance;\n\n    if (!tryHydrate(fiber, nextInstance)) {\n      if (shouldClientRenderOnMismatch(fiber)) {\n        warnNonhydratedInstance(hydrationParentFiber, fiber);\n        throwOnHydrationMismatch();\n      } // If we can't hydrate this instance let's try the next one.\n      // We use this as a heuristic. It's based on intuition and not data so it\n      // might be flawed or unnecessary.\n\n\n      nextInstance = getNextHydratableSibling(firstAttemptedInstance);\n      var prevHydrationParentFiber = hydrationParentFiber;\n\n      if (!nextInstance || !tryHydrate(fiber, nextInstance)) {\n        // Nothing to hydrate. Make it an insertion.\n        insertNonHydratedInstance(hydrationParentFiber, fiber);\n        isHydrating = false;\n        hydrationParentFiber = fiber;\n        return;\n      } // We matched the next one, we'll now assume that the first one was\n      // superfluous and we'll delete it. Since we can't eagerly delete it\n      // we'll have to schedule a deletion. To do that, this node needs a dummy\n      // fiber associated with it.\n\n\n      deleteHydratableInstance(prevHydrationParentFiber, firstAttemptedInstance);\n    }\n  }\n\n  function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) {\n\n    var instance = fiber.stateNode;\n    var shouldWarnIfMismatchDev = !didSuspendOrErrorDEV;\n    var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber, shouldWarnIfMismatchDev); // TODO: Type this specific to this type of component.\n\n    fiber.updateQueue = updatePayload; // If the update payload indicates that there is a change or if there\n    // is a new ref we mark this as an update.\n\n    if (updatePayload !== null) {\n      return true;\n    }\n\n    return false;\n  }\n\n  function prepareToHydrateHostTextInstance(fiber) {\n\n    var textInstance = fiber.stateNode;\n    var textContent = fiber.memoizedProps;\n    var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber);\n\n    if (shouldUpdate) {\n      // We assume that prepareToHydrateHostTextInstance is called in a context where the\n      // hydration parent is the parent host component of this host text.\n      var returnFiber = hydrationParentFiber;\n\n      if (returnFiber !== null) {\n        switch (returnFiber.tag) {\n          case HostRoot:\n            {\n              var parentContainer = returnFiber.stateNode.containerInfo;\n              var isConcurrentMode = (returnFiber.mode & ConcurrentMode) !== NoMode;\n              didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, textContent, // TODO: Delete this argument when we remove the legacy root API.\n              isConcurrentMode);\n              break;\n            }\n\n          case HostComponent:\n            {\n              var parentType = returnFiber.type;\n              var parentProps = returnFiber.memoizedProps;\n              var parentInstance = returnFiber.stateNode;\n\n              var _isConcurrentMode2 = (returnFiber.mode & ConcurrentMode) !== NoMode;\n\n              didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, textContent, // TODO: Delete this argument when we remove the legacy root API.\n              _isConcurrentMode2);\n              break;\n            }\n        }\n      }\n    }\n\n    return shouldUpdate;\n  }\n\n  function prepareToHydrateHostSuspenseInstance(fiber) {\n\n    var suspenseState = fiber.memoizedState;\n    var suspenseInstance = suspenseState !== null ? suspenseState.dehydrated : null;\n\n    if (!suspenseInstance) {\n      throw new Error('Expected to have a hydrated suspense instance. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n    }\n\n    hydrateSuspenseInstance(suspenseInstance, fiber);\n  }\n\n  function skipPastDehydratedSuspenseInstance(fiber) {\n\n    var suspenseState = fiber.memoizedState;\n    var suspenseInstance = suspenseState !== null ? suspenseState.dehydrated : null;\n\n    if (!suspenseInstance) {\n      throw new Error('Expected to have a hydrated suspense instance. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n    }\n\n    return getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance);\n  }\n\n  function popToNextHostParent(fiber) {\n    var parent = fiber.return;\n\n    while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot && parent.tag !== SuspenseComponent) {\n      parent = parent.return;\n    }\n\n    hydrationParentFiber = parent;\n  }\n\n  function popHydrationState(fiber) {\n\n    if (fiber !== hydrationParentFiber) {\n      // We're deeper than the current hydration context, inside an inserted\n      // tree.\n      return false;\n    }\n\n    if (!isHydrating) {\n      // If we're not currently hydrating but we're in a hydration context, then\n      // we were an insertion and now need to pop up reenter hydration of our\n      // siblings.\n      popToNextHostParent(fiber);\n      isHydrating = true;\n      return false;\n    } // If we have any remaining hydratable nodes, we need to delete them now.\n    // We only do this deeper than head and body since they tend to have random\n    // other nodes in them. We also ignore components with pure text content in\n    // side of them. We also don't delete anything inside the root container.\n\n\n    if (fiber.tag !== HostRoot && (fiber.tag !== HostComponent || shouldDeleteUnhydratedTailInstances(fiber.type) && !shouldSetTextContent(fiber.type, fiber.memoizedProps))) {\n      var nextInstance = nextHydratableInstance;\n\n      if (nextInstance) {\n        if (shouldClientRenderOnMismatch(fiber)) {\n          warnIfUnhydratedTailNodes(fiber);\n          throwOnHydrationMismatch();\n        } else {\n          while (nextInstance) {\n            deleteHydratableInstance(fiber, nextInstance);\n            nextInstance = getNextHydratableSibling(nextInstance);\n          }\n        }\n      }\n    }\n\n    popToNextHostParent(fiber);\n\n    if (fiber.tag === SuspenseComponent) {\n      nextHydratableInstance = skipPastDehydratedSuspenseInstance(fiber);\n    } else {\n      nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null;\n    }\n\n    return true;\n  }\n\n  function hasUnhydratedTailNodes() {\n    return isHydrating && nextHydratableInstance !== null;\n  }\n\n  function warnIfUnhydratedTailNodes(fiber) {\n    var nextInstance = nextHydratableInstance;\n\n    while (nextInstance) {\n      warnUnhydratedInstance(fiber, nextInstance);\n      nextInstance = getNextHydratableSibling(nextInstance);\n    }\n  }\n\n  function resetHydrationState() {\n\n    hydrationParentFiber = null;\n    nextHydratableInstance = null;\n    isHydrating = false;\n    didSuspendOrErrorDEV = false;\n  }\n\n  function upgradeHydrationErrorsToRecoverable() {\n    if (hydrationErrors !== null) {\n      // Successfully completed a forced client render. The errors that occurred\n      // during the hydration attempt are now recovered. We will log them in\n      // commit phase, once the entire tree has finished.\n      queueRecoverableErrors(hydrationErrors);\n      hydrationErrors = null;\n    }\n  }\n\n  function getIsHydrating() {\n    return isHydrating;\n  }\n\n  function queueHydrationError(error) {\n    if (hydrationErrors === null) {\n      hydrationErrors = [error];\n    } else {\n      hydrationErrors.push(error);\n    }\n  }\n\n  var ReactCurrentBatchConfig$1 = ReactSharedInternals.ReactCurrentBatchConfig;\n  var NoTransition = null;\n  function requestCurrentTransition() {\n    return ReactCurrentBatchConfig$1.transition;\n  }\n\n  var ReactStrictModeWarnings = {\n    recordUnsafeLifecycleWarnings: function (fiber, instance) {},\n    flushPendingUnsafeLifecycleWarnings: function () {},\n    recordLegacyContextWarning: function (fiber, instance) {},\n    flushLegacyContextWarning: function () {},\n    discardPendingWarnings: function () {}\n  };\n\n  {\n    var findStrictRoot = function (fiber) {\n      var maybeStrictRoot = null;\n      var node = fiber;\n\n      while (node !== null) {\n        if (node.mode & StrictLegacyMode) {\n          maybeStrictRoot = node;\n        }\n\n        node = node.return;\n      }\n\n      return maybeStrictRoot;\n    };\n\n    var setToSortedString = function (set) {\n      var array = [];\n      set.forEach(function (value) {\n        array.push(value);\n      });\n      return array.sort().join(', ');\n    };\n\n    var pendingComponentWillMountWarnings = [];\n    var pendingUNSAFE_ComponentWillMountWarnings = [];\n    var pendingComponentWillReceivePropsWarnings = [];\n    var pendingUNSAFE_ComponentWillReceivePropsWarnings = [];\n    var pendingComponentWillUpdateWarnings = [];\n    var pendingUNSAFE_ComponentWillUpdateWarnings = []; // Tracks components we have already warned about.\n\n    var didWarnAboutUnsafeLifecycles = new Set();\n\n    ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = function (fiber, instance) {\n      // Dedupe strategy: Warn once per component.\n      if (didWarnAboutUnsafeLifecycles.has(fiber.type)) {\n        return;\n      }\n\n      if (typeof instance.componentWillMount === 'function' && // Don't warn about react-lifecycles-compat polyfilled components.\n      instance.componentWillMount.__suppressDeprecationWarning !== true) {\n        pendingComponentWillMountWarnings.push(fiber);\n      }\n\n      if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillMount === 'function') {\n        pendingUNSAFE_ComponentWillMountWarnings.push(fiber);\n      }\n\n      if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) {\n        pendingComponentWillReceivePropsWarnings.push(fiber);\n      }\n\n      if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillReceiveProps === 'function') {\n        pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber);\n      }\n\n      if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) {\n        pendingComponentWillUpdateWarnings.push(fiber);\n      }\n\n      if (fiber.mode & StrictLegacyMode && typeof instance.UNSAFE_componentWillUpdate === 'function') {\n        pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber);\n      }\n    };\n\n    ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = function () {\n      // We do an initial pass to gather component names\n      var componentWillMountUniqueNames = new Set();\n\n      if (pendingComponentWillMountWarnings.length > 0) {\n        pendingComponentWillMountWarnings.forEach(function (fiber) {\n          componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');\n          didWarnAboutUnsafeLifecycles.add(fiber.type);\n        });\n        pendingComponentWillMountWarnings = [];\n      }\n\n      var UNSAFE_componentWillMountUniqueNames = new Set();\n\n      if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) {\n        pendingUNSAFE_ComponentWillMountWarnings.forEach(function (fiber) {\n          UNSAFE_componentWillMountUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');\n          didWarnAboutUnsafeLifecycles.add(fiber.type);\n        });\n        pendingUNSAFE_ComponentWillMountWarnings = [];\n      }\n\n      var componentWillReceivePropsUniqueNames = new Set();\n\n      if (pendingComponentWillReceivePropsWarnings.length > 0) {\n        pendingComponentWillReceivePropsWarnings.forEach(function (fiber) {\n          componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');\n          didWarnAboutUnsafeLifecycles.add(fiber.type);\n        });\n        pendingComponentWillReceivePropsWarnings = [];\n      }\n\n      var UNSAFE_componentWillReceivePropsUniqueNames = new Set();\n\n      if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) {\n        pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(function (fiber) {\n          UNSAFE_componentWillReceivePropsUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');\n          didWarnAboutUnsafeLifecycles.add(fiber.type);\n        });\n        pendingUNSAFE_ComponentWillReceivePropsWarnings = [];\n      }\n\n      var componentWillUpdateUniqueNames = new Set();\n\n      if (pendingComponentWillUpdateWarnings.length > 0) {\n        pendingComponentWillUpdateWarnings.forEach(function (fiber) {\n          componentWillUpdateUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');\n          didWarnAboutUnsafeLifecycles.add(fiber.type);\n        });\n        pendingComponentWillUpdateWarnings = [];\n      }\n\n      var UNSAFE_componentWillUpdateUniqueNames = new Set();\n\n      if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) {\n        pendingUNSAFE_ComponentWillUpdateWarnings.forEach(function (fiber) {\n          UNSAFE_componentWillUpdateUniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');\n          didWarnAboutUnsafeLifecycles.add(fiber.type);\n        });\n        pendingUNSAFE_ComponentWillUpdateWarnings = [];\n      } // Finally, we flush all the warnings\n      // UNSAFE_ ones before the deprecated ones, since they'll be 'louder'\n\n\n      if (UNSAFE_componentWillMountUniqueNames.size > 0) {\n        var sortedNames = setToSortedString(UNSAFE_componentWillMountUniqueNames);\n\n        error('Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\\n\\n' + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\\n' + '\\nPlease update the following components: %s', sortedNames);\n      }\n\n      if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) {\n        var _sortedNames = setToSortedString(UNSAFE_componentWillReceivePropsUniqueNames);\n\n        error('Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\\n\\n' + '* Move data fetching code or side effects to componentDidUpdate.\\n' + \"* If you're updating state whenever props change, \" + 'refactor your code to use memoization techniques or move it to ' + 'static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\\n' + '\\nPlease update the following components: %s', _sortedNames);\n      }\n\n      if (UNSAFE_componentWillUpdateUniqueNames.size > 0) {\n        var _sortedNames2 = setToSortedString(UNSAFE_componentWillUpdateUniqueNames);\n\n        error('Using UNSAFE_componentWillUpdate in strict mode is not recommended ' + 'and may indicate bugs in your code. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\\n\\n' + '* Move data fetching code or side effects to componentDidUpdate.\\n' + '\\nPlease update the following components: %s', _sortedNames2);\n      }\n\n      if (componentWillMountUniqueNames.size > 0) {\n        var _sortedNames3 = setToSortedString(componentWillMountUniqueNames);\n\n        warn('componentWillMount has been renamed, and is not recommended for use. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\\n\\n' + '* Move code with side effects to componentDidMount, and set initial state in the constructor.\\n' + '* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' + 'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' + 'To rename all deprecated lifecycles to their new names, you can run ' + '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\\n' + '\\nPlease update the following components: %s', _sortedNames3);\n      }\n\n      if (componentWillReceivePropsUniqueNames.size > 0) {\n        var _sortedNames4 = setToSortedString(componentWillReceivePropsUniqueNames);\n\n        warn('componentWillReceiveProps has been renamed, and is not recommended for use. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\\n\\n' + '* Move data fetching code or side effects to componentDidUpdate.\\n' + \"* If you're updating state whenever props change, refactor your \" + 'code to use memoization techniques or move it to ' + 'static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\\n' + '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' + 'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' + 'To rename all deprecated lifecycles to their new names, you can run ' + '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\\n' + '\\nPlease update the following components: %s', _sortedNames4);\n      }\n\n      if (componentWillUpdateUniqueNames.size > 0) {\n        var _sortedNames5 = setToSortedString(componentWillUpdateUniqueNames);\n\n        warn('componentWillUpdate has been renamed, and is not recommended for use. ' + 'See https://reactjs.org/link/unsafe-component-lifecycles for details.\\n\\n' + '* Move data fetching code or side effects to componentDidUpdate.\\n' + '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' + 'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' + 'To rename all deprecated lifecycles to their new names, you can run ' + '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\\n' + '\\nPlease update the following components: %s', _sortedNames5);\n      }\n    };\n\n    var pendingLegacyContextWarning = new Map(); // Tracks components we have already warned about.\n\n    var didWarnAboutLegacyContext = new Set();\n\n    ReactStrictModeWarnings.recordLegacyContextWarning = function (fiber, instance) {\n      var strictRoot = findStrictRoot(fiber);\n\n      if (strictRoot === null) {\n        error('Expected to find a StrictMode component in a strict mode tree. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n\n        return;\n      } // Dedup strategy: Warn once per component.\n\n\n      if (didWarnAboutLegacyContext.has(fiber.type)) {\n        return;\n      }\n\n      var warningsForRoot = pendingLegacyContextWarning.get(strictRoot);\n\n      if (fiber.type.contextTypes != null || fiber.type.childContextTypes != null || instance !== null && typeof instance.getChildContext === 'function') {\n        if (warningsForRoot === undefined) {\n          warningsForRoot = [];\n          pendingLegacyContextWarning.set(strictRoot, warningsForRoot);\n        }\n\n        warningsForRoot.push(fiber);\n      }\n    };\n\n    ReactStrictModeWarnings.flushLegacyContextWarning = function () {\n      pendingLegacyContextWarning.forEach(function (fiberArray, strictRoot) {\n        if (fiberArray.length === 0) {\n          return;\n        }\n\n        var firstFiber = fiberArray[0];\n        var uniqueNames = new Set();\n        fiberArray.forEach(function (fiber) {\n          uniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');\n          didWarnAboutLegacyContext.add(fiber.type);\n        });\n        var sortedNames = setToSortedString(uniqueNames);\n\n        try {\n          setCurrentFiber(firstFiber);\n\n          error('Legacy context API has been detected within a strict-mode tree.' + '\\n\\nThe old API will be supported in all 16.x releases, but applications ' + 'using it should migrate to the new version.' + '\\n\\nPlease update the following components: %s' + '\\n\\nLearn more about this warning here: https://reactjs.org/link/legacy-context', sortedNames);\n        } finally {\n          resetCurrentFiber();\n        }\n      });\n    };\n\n    ReactStrictModeWarnings.discardPendingWarnings = function () {\n      pendingComponentWillMountWarnings = [];\n      pendingUNSAFE_ComponentWillMountWarnings = [];\n      pendingComponentWillReceivePropsWarnings = [];\n      pendingUNSAFE_ComponentWillReceivePropsWarnings = [];\n      pendingComponentWillUpdateWarnings = [];\n      pendingUNSAFE_ComponentWillUpdateWarnings = [];\n      pendingLegacyContextWarning = new Map();\n    };\n  }\n\n  var didWarnAboutMaps;\n  var didWarnAboutGenerators;\n  var didWarnAboutStringRefs;\n  var ownerHasKeyUseWarning;\n  var ownerHasFunctionTypeWarning;\n\n  var warnForMissingKey = function (child, returnFiber) {};\n\n  {\n    didWarnAboutMaps = false;\n    didWarnAboutGenerators = false;\n    didWarnAboutStringRefs = {};\n    /**\n     * Warn if there's no key explicitly set on dynamic arrays of children or\n     * object keys are not valid. This allows us to keep track of children between\n     * updates.\n     */\n\n    ownerHasKeyUseWarning = {};\n    ownerHasFunctionTypeWarning = {};\n\n    warnForMissingKey = function (child, returnFiber) {\n      if (child === null || typeof child !== 'object') {\n        return;\n      }\n\n      if (!child._store || child._store.validated || child.key != null) {\n        return;\n      }\n\n      if (typeof child._store !== 'object') {\n        throw new Error('React Component in warnForMissingKey should have a _store. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n      }\n\n      child._store.validated = true;\n      var componentName = getComponentNameFromFiber(returnFiber) || 'Component';\n\n      if (ownerHasKeyUseWarning[componentName]) {\n        return;\n      }\n\n      ownerHasKeyUseWarning[componentName] = true;\n\n      error('Each child in a list should have a unique ' + '\"key\" prop. See https://reactjs.org/link/warning-keys for ' + 'more information.');\n    };\n  }\n\n  function isReactClass(type) {\n    return type.prototype && type.prototype.isReactComponent;\n  }\n\n  function coerceRef(returnFiber, current, element) {\n    var mixedRef = element.ref;\n\n    if (mixedRef !== null && typeof mixedRef !== 'function' && typeof mixedRef !== 'object') {\n      {\n        // TODO: Clean this up once we turn on the string ref warning for\n        // everyone, because the strict mode case will no longer be relevant\n        if ((returnFiber.mode & StrictLegacyMode || warnAboutStringRefs) && // We warn in ReactElement.js if owner and self are equal for string refs\n        // because these cannot be automatically converted to an arrow function\n        // using a codemod. Therefore, we don't have to warn about string refs again.\n        !(element._owner && element._self && element._owner.stateNode !== element._self) && // Will already throw with \"Function components cannot have string refs\"\n        !(element._owner && element._owner.tag !== ClassComponent) && // Will already warn with \"Function components cannot be given refs\"\n        !(typeof element.type === 'function' && !isReactClass(element.type)) && // Will already throw with \"Element ref was specified as a string (someStringRef) but no owner was set\"\n        element._owner) {\n          var componentName = getComponentNameFromFiber(returnFiber) || 'Component';\n\n          if (!didWarnAboutStringRefs[componentName]) {\n            {\n              error('Component \"%s\" contains the string ref \"%s\". Support for string refs ' + 'will be removed in a future major release. We recommend using ' + 'useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-string-ref', componentName, mixedRef);\n            }\n\n            didWarnAboutStringRefs[componentName] = true;\n          }\n        }\n      }\n\n      if (element._owner) {\n        var owner = element._owner;\n        var inst;\n\n        if (owner) {\n          var ownerFiber = owner;\n\n          if (ownerFiber.tag !== ClassComponent) {\n            throw new Error('Function components cannot have string refs. ' + 'We recommend using useRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-string-ref');\n          }\n\n          inst = ownerFiber.stateNode;\n        }\n\n        if (!inst) {\n          throw new Error(\"Missing owner for string ref \" + mixedRef + \". This error is likely caused by a \" + 'bug in React. Please file an issue.');\n        } // Assigning this to a const so Flow knows it won't change in the closure\n\n\n        var resolvedInst = inst;\n\n        {\n          checkPropStringCoercion(mixedRef, 'ref');\n        }\n\n        var stringRef = '' + mixedRef; // Check if previous string ref matches new string ref\n\n        if (current !== null && current.ref !== null && typeof current.ref === 'function' && current.ref._stringRef === stringRef) {\n          return current.ref;\n        }\n\n        var ref = function (value) {\n          var refs = resolvedInst.refs;\n\n          if (value === null) {\n            delete refs[stringRef];\n          } else {\n            refs[stringRef] = value;\n          }\n        };\n\n        ref._stringRef = stringRef;\n        return ref;\n      } else {\n        if (typeof mixedRef !== 'string') {\n          throw new Error('Expected ref to be a function, a string, an object returned by React.createRef(), or null.');\n        }\n\n        if (!element._owner) {\n          throw new Error(\"Element ref was specified as a string (\" + mixedRef + \") but no owner was set. This could happen for one of\" + ' the following reasons:\\n' + '1. You may be adding a ref to a function component\\n' + \"2. You may be adding a ref to a component that was not created inside a component's render method\\n\" + '3. You have multiple copies of React loaded\\n' + 'See https://reactjs.org/link/refs-must-have-owner for more information.');\n        }\n      }\n    }\n\n    return mixedRef;\n  }\n\n  function throwOnInvalidObjectType(returnFiber, newChild) {\n    var childString = Object.prototype.toString.call(newChild);\n    throw new Error(\"Objects are not valid as a React child (found: \" + (childString === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : childString) + \"). \" + 'If you meant to render a collection of children, use an array ' + 'instead.');\n  }\n\n  function warnOnFunctionType(returnFiber) {\n    {\n      var componentName = getComponentNameFromFiber(returnFiber) || 'Component';\n\n      if (ownerHasFunctionTypeWarning[componentName]) {\n        return;\n      }\n\n      ownerHasFunctionTypeWarning[componentName] = true;\n\n      error('Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of <Component /> from render. ' + 'Or maybe you meant to call this function rather than return it.');\n    }\n  }\n\n  function resolveLazy(lazyType) {\n    var payload = lazyType._payload;\n    var init = lazyType._init;\n    return init(payload);\n  } // This wrapper function exists because I expect to clone the code in each path\n  // to be able to optimize each path individually by branching early. This needs\n  // a compiler or we can do it manually. Helpers that don't need this branching\n  // live outside of this function.\n\n\n  function ChildReconciler(shouldTrackSideEffects) {\n    function deleteChild(returnFiber, childToDelete) {\n      if (!shouldTrackSideEffects) {\n        // Noop.\n        return;\n      }\n\n      var deletions = returnFiber.deletions;\n\n      if (deletions === null) {\n        returnFiber.deletions = [childToDelete];\n        returnFiber.flags |= ChildDeletion;\n      } else {\n        deletions.push(childToDelete);\n      }\n    }\n\n    function deleteRemainingChildren(returnFiber, currentFirstChild) {\n      if (!shouldTrackSideEffects) {\n        // Noop.\n        return null;\n      } // TODO: For the shouldClone case, this could be micro-optimized a bit by\n      // assuming that after the first child we've already added everything.\n\n\n      var childToDelete = currentFirstChild;\n\n      while (childToDelete !== null) {\n        deleteChild(returnFiber, childToDelete);\n        childToDelete = childToDelete.sibling;\n      }\n\n      return null;\n    }\n\n    function mapRemainingChildren(returnFiber, currentFirstChild) {\n      // Add the remaining children to a temporary map so that we can find them by\n      // keys quickly. Implicit (null) keys get added to this set with their index\n      // instead.\n      var existingChildren = new Map();\n      var existingChild = currentFirstChild;\n\n      while (existingChild !== null) {\n        if (existingChild.key !== null) {\n          existingChildren.set(existingChild.key, existingChild);\n        } else {\n          existingChildren.set(existingChild.index, existingChild);\n        }\n\n        existingChild = existingChild.sibling;\n      }\n\n      return existingChildren;\n    }\n\n    function useFiber(fiber, pendingProps) {\n      // We currently set sibling to null and index to 0 here because it is easy\n      // to forget to do before returning it. E.g. for the single child case.\n      var clone = createWorkInProgress(fiber, pendingProps);\n      clone.index = 0;\n      clone.sibling = null;\n      return clone;\n    }\n\n    function placeChild(newFiber, lastPlacedIndex, newIndex) {\n      newFiber.index = newIndex;\n\n      if (!shouldTrackSideEffects) {\n        // During hydration, the useId algorithm needs to know which fibers are\n        // part of a list of children (arrays, iterators).\n        newFiber.flags |= Forked;\n        return lastPlacedIndex;\n      }\n\n      var current = newFiber.alternate;\n\n      if (current !== null) {\n        var oldIndex = current.index;\n\n        if (oldIndex < lastPlacedIndex) {\n          // This is a move.\n          newFiber.flags |= Placement;\n          return lastPlacedIndex;\n        } else {\n          // This item can stay in place.\n          return oldIndex;\n        }\n      } else {\n        // This is an insertion.\n        newFiber.flags |= Placement;\n        return lastPlacedIndex;\n      }\n    }\n\n    function placeSingleChild(newFiber) {\n      // This is simpler for the single child case. We only need to do a\n      // placement for inserting new children.\n      if (shouldTrackSideEffects && newFiber.alternate === null) {\n        newFiber.flags |= Placement;\n      }\n\n      return newFiber;\n    }\n\n    function updateTextNode(returnFiber, current, textContent, lanes) {\n      if (current === null || current.tag !== HostText) {\n        // Insert\n        var created = createFiberFromText(textContent, returnFiber.mode, lanes);\n        created.return = returnFiber;\n        return created;\n      } else {\n        // Update\n        var existing = useFiber(current, textContent);\n        existing.return = returnFiber;\n        return existing;\n      }\n    }\n\n    function updateElement(returnFiber, current, element, lanes) {\n      var elementType = element.type;\n\n      if (elementType === REACT_FRAGMENT_TYPE) {\n        return updateFragment(returnFiber, current, element.props.children, lanes, element.key);\n      }\n\n      if (current !== null) {\n        if (current.elementType === elementType || ( // Keep this check inline so it only runs on the false path:\n         isCompatibleFamilyForHotReloading(current, element) ) || // Lazy types should reconcile their resolved type.\n        // We need to do this after the Hot Reloading check above,\n        // because hot reloading has different semantics than prod because\n        // it doesn't resuspend. So we can't let the call below suspend.\n        typeof elementType === 'object' && elementType !== null && elementType.$$typeof === REACT_LAZY_TYPE && resolveLazy(elementType) === current.type) {\n          // Move based on index\n          var existing = useFiber(current, element.props);\n          existing.ref = coerceRef(returnFiber, current, element);\n          existing.return = returnFiber;\n\n          {\n            existing._debugSource = element._source;\n            existing._debugOwner = element._owner;\n          }\n\n          return existing;\n        }\n      } // Insert\n\n\n      var created = createFiberFromElement(element, returnFiber.mode, lanes);\n      created.ref = coerceRef(returnFiber, current, element);\n      created.return = returnFiber;\n      return created;\n    }\n\n    function updatePortal(returnFiber, current, portal, lanes) {\n      if (current === null || current.tag !== HostPortal || current.stateNode.containerInfo !== portal.containerInfo || current.stateNode.implementation !== portal.implementation) {\n        // Insert\n        var created = createFiberFromPortal(portal, returnFiber.mode, lanes);\n        created.return = returnFiber;\n        return created;\n      } else {\n        // Update\n        var existing = useFiber(current, portal.children || []);\n        existing.return = returnFiber;\n        return existing;\n      }\n    }\n\n    function updateFragment(returnFiber, current, fragment, lanes, key) {\n      if (current === null || current.tag !== Fragment) {\n        // Insert\n        var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key);\n        created.return = returnFiber;\n        return created;\n      } else {\n        // Update\n        var existing = useFiber(current, fragment);\n        existing.return = returnFiber;\n        return existing;\n      }\n    }\n\n    function createChild(returnFiber, newChild, lanes) {\n      if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number') {\n        // Text nodes don't have keys. If the previous node is implicitly keyed\n        // we can continue to replace it without aborting even if it is not a text\n        // node.\n        var created = createFiberFromText('' + newChild, returnFiber.mode, lanes);\n        created.return = returnFiber;\n        return created;\n      }\n\n      if (typeof newChild === 'object' && newChild !== null) {\n        switch (newChild.$$typeof) {\n          case REACT_ELEMENT_TYPE:\n            {\n              var _created = createFiberFromElement(newChild, returnFiber.mode, lanes);\n\n              _created.ref = coerceRef(returnFiber, null, newChild);\n              _created.return = returnFiber;\n              return _created;\n            }\n\n          case REACT_PORTAL_TYPE:\n            {\n              var _created2 = createFiberFromPortal(newChild, returnFiber.mode, lanes);\n\n              _created2.return = returnFiber;\n              return _created2;\n            }\n\n          case REACT_LAZY_TYPE:\n            {\n              var payload = newChild._payload;\n              var init = newChild._init;\n              return createChild(returnFiber, init(payload), lanes);\n            }\n        }\n\n        if (isArray(newChild) || getIteratorFn(newChild)) {\n          var _created3 = createFiberFromFragment(newChild, returnFiber.mode, lanes, null);\n\n          _created3.return = returnFiber;\n          return _created3;\n        }\n\n        throwOnInvalidObjectType(returnFiber, newChild);\n      }\n\n      {\n        if (typeof newChild === 'function') {\n          warnOnFunctionType(returnFiber);\n        }\n      }\n\n      return null;\n    }\n\n    function updateSlot(returnFiber, oldFiber, newChild, lanes) {\n      // Update the fiber if the keys match, otherwise return null.\n      var key = oldFiber !== null ? oldFiber.key : null;\n\n      if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number') {\n        // Text nodes don't have keys. If the previous node is implicitly keyed\n        // we can continue to replace it without aborting even if it is not a text\n        // node.\n        if (key !== null) {\n          return null;\n        }\n\n        return updateTextNode(returnFiber, oldFiber, '' + newChild, lanes);\n      }\n\n      if (typeof newChild === 'object' && newChild !== null) {\n        switch (newChild.$$typeof) {\n          case REACT_ELEMENT_TYPE:\n            {\n              if (newChild.key === key) {\n                return updateElement(returnFiber, oldFiber, newChild, lanes);\n              } else {\n                return null;\n              }\n            }\n\n          case REACT_PORTAL_TYPE:\n            {\n              if (newChild.key === key) {\n                return updatePortal(returnFiber, oldFiber, newChild, lanes);\n              } else {\n                return null;\n              }\n            }\n\n          case REACT_LAZY_TYPE:\n            {\n              var payload = newChild._payload;\n              var init = newChild._init;\n              return updateSlot(returnFiber, oldFiber, init(payload), lanes);\n            }\n        }\n\n        if (isArray(newChild) || getIteratorFn(newChild)) {\n          if (key !== null) {\n            return null;\n          }\n\n          return updateFragment(returnFiber, oldFiber, newChild, lanes, null);\n        }\n\n        throwOnInvalidObjectType(returnFiber, newChild);\n      }\n\n      {\n        if (typeof newChild === 'function') {\n          warnOnFunctionType(returnFiber);\n        }\n      }\n\n      return null;\n    }\n\n    function updateFromMap(existingChildren, returnFiber, newIdx, newChild, lanes) {\n      if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number') {\n        // Text nodes don't have keys, so we neither have to check the old nor\n        // new node for the key. If both are text nodes, they match.\n        var matchedFiber = existingChildren.get(newIdx) || null;\n        return updateTextNode(returnFiber, matchedFiber, '' + newChild, lanes);\n      }\n\n      if (typeof newChild === 'object' && newChild !== null) {\n        switch (newChild.$$typeof) {\n          case REACT_ELEMENT_TYPE:\n            {\n              var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null;\n\n              return updateElement(returnFiber, _matchedFiber, newChild, lanes);\n            }\n\n          case REACT_PORTAL_TYPE:\n            {\n              var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null;\n\n              return updatePortal(returnFiber, _matchedFiber2, newChild, lanes);\n            }\n\n          case REACT_LAZY_TYPE:\n            var payload = newChild._payload;\n            var init = newChild._init;\n            return updateFromMap(existingChildren, returnFiber, newIdx, init(payload), lanes);\n        }\n\n        if (isArray(newChild) || getIteratorFn(newChild)) {\n          var _matchedFiber3 = existingChildren.get(newIdx) || null;\n\n          return updateFragment(returnFiber, _matchedFiber3, newChild, lanes, null);\n        }\n\n        throwOnInvalidObjectType(returnFiber, newChild);\n      }\n\n      {\n        if (typeof newChild === 'function') {\n          warnOnFunctionType(returnFiber);\n        }\n      }\n\n      return null;\n    }\n    /**\n     * Warns if there is a duplicate or missing key\n     */\n\n\n    function warnOnInvalidKey(child, knownKeys, returnFiber) {\n      {\n        if (typeof child !== 'object' || child === null) {\n          return knownKeys;\n        }\n\n        switch (child.$$typeof) {\n          case REACT_ELEMENT_TYPE:\n          case REACT_PORTAL_TYPE:\n            warnForMissingKey(child, returnFiber);\n            var key = child.key;\n\n            if (typeof key !== 'string') {\n              break;\n            }\n\n            if (knownKeys === null) {\n              knownKeys = new Set();\n              knownKeys.add(key);\n              break;\n            }\n\n            if (!knownKeys.has(key)) {\n              knownKeys.add(key);\n              break;\n            }\n\n            error('Encountered two children with the same key, `%s`. ' + 'Keys should be unique so that components maintain their identity ' + 'across updates. Non-unique keys may cause children to be ' + 'duplicated and/or omitted — the behavior is unsupported and ' + 'could change in a future version.', key);\n\n            break;\n\n          case REACT_LAZY_TYPE:\n            var payload = child._payload;\n            var init = child._init;\n            warnOnInvalidKey(init(payload), knownKeys, returnFiber);\n            break;\n        }\n      }\n\n      return knownKeys;\n    }\n\n    function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, lanes) {\n      // This algorithm can't optimize by searching from both ends since we\n      // don't have backpointers on fibers. I'm trying to see how far we can get\n      // with that model. If it ends up not being worth the tradeoffs, we can\n      // add it later.\n      // Even with a two ended optimization, we'd want to optimize for the case\n      // where there are few changes and brute force the comparison instead of\n      // going for the Map. It'd like to explore hitting that path first in\n      // forward-only mode and only go for the Map once we notice that we need\n      // lots of look ahead. This doesn't handle reversal as well as two ended\n      // search but that's unusual. Besides, for the two ended optimization to\n      // work on Iterables, we'd need to copy the whole set.\n      // In this first iteration, we'll just live with hitting the bad case\n      // (adding everything to a Map) in for every insert/move.\n      // If you change this code, also update reconcileChildrenIterator() which\n      // uses the same algorithm.\n      {\n        // First, validate keys.\n        var knownKeys = null;\n\n        for (var i = 0; i < newChildren.length; i++) {\n          var child = newChildren[i];\n          knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber);\n        }\n      }\n\n      var resultingFirstChild = null;\n      var previousNewFiber = null;\n      var oldFiber = currentFirstChild;\n      var lastPlacedIndex = 0;\n      var newIdx = 0;\n      var nextOldFiber = null;\n\n      for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {\n        if (oldFiber.index > newIdx) {\n          nextOldFiber = oldFiber;\n          oldFiber = null;\n        } else {\n          nextOldFiber = oldFiber.sibling;\n        }\n\n        var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], lanes);\n\n        if (newFiber === null) {\n          // TODO: This breaks on empty slots like null children. That's\n          // unfortunate because it triggers the slow path all the time. We need\n          // a better way to communicate whether this was a miss or null,\n          // boolean, undefined, etc.\n          if (oldFiber === null) {\n            oldFiber = nextOldFiber;\n          }\n\n          break;\n        }\n\n        if (shouldTrackSideEffects) {\n          if (oldFiber && newFiber.alternate === null) {\n            // We matched the slot, but we didn't reuse the existing fiber, so we\n            // need to delete the existing child.\n            deleteChild(returnFiber, oldFiber);\n          }\n        }\n\n        lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);\n\n        if (previousNewFiber === null) {\n          // TODO: Move out of the loop. This only happens for the first run.\n          resultingFirstChild = newFiber;\n        } else {\n          // TODO: Defer siblings if we're not at the right index for this slot.\n          // I.e. if we had null values before, then we want to defer this\n          // for each null value. However, we also don't want to call updateSlot\n          // with the previous one.\n          previousNewFiber.sibling = newFiber;\n        }\n\n        previousNewFiber = newFiber;\n        oldFiber = nextOldFiber;\n      }\n\n      if (newIdx === newChildren.length) {\n        // We've reached the end of the new children. We can delete the rest.\n        deleteRemainingChildren(returnFiber, oldFiber);\n\n        if (getIsHydrating()) {\n          var numberOfForks = newIdx;\n          pushTreeFork(returnFiber, numberOfForks);\n        }\n\n        return resultingFirstChild;\n      }\n\n      if (oldFiber === null) {\n        // If we don't have any more existing children we can choose a fast path\n        // since the rest will all be insertions.\n        for (; newIdx < newChildren.length; newIdx++) {\n          var _newFiber = createChild(returnFiber, newChildren[newIdx], lanes);\n\n          if (_newFiber === null) {\n            continue;\n          }\n\n          lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx);\n\n          if (previousNewFiber === null) {\n            // TODO: Move out of the loop. This only happens for the first run.\n            resultingFirstChild = _newFiber;\n          } else {\n            previousNewFiber.sibling = _newFiber;\n          }\n\n          previousNewFiber = _newFiber;\n        }\n\n        if (getIsHydrating()) {\n          var _numberOfForks = newIdx;\n          pushTreeFork(returnFiber, _numberOfForks);\n        }\n\n        return resultingFirstChild;\n      } // Add all children to a key map for quick lookups.\n\n\n      var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves.\n\n      for (; newIdx < newChildren.length; newIdx++) {\n        var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], lanes);\n\n        if (_newFiber2 !== null) {\n          if (shouldTrackSideEffects) {\n            if (_newFiber2.alternate !== null) {\n              // The new fiber is a work in progress, but if there exists a\n              // current, that means that we reused the fiber. We need to delete\n              // it from the child list so that we don't add it to the deletion\n              // list.\n              existingChildren.delete(_newFiber2.key === null ? newIdx : _newFiber2.key);\n            }\n          }\n\n          lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx);\n\n          if (previousNewFiber === null) {\n            resultingFirstChild = _newFiber2;\n          } else {\n            previousNewFiber.sibling = _newFiber2;\n          }\n\n          previousNewFiber = _newFiber2;\n        }\n      }\n\n      if (shouldTrackSideEffects) {\n        // Any existing children that weren't consumed above were deleted. We need\n        // to add them to the deletion list.\n        existingChildren.forEach(function (child) {\n          return deleteChild(returnFiber, child);\n        });\n      }\n\n      if (getIsHydrating()) {\n        var _numberOfForks2 = newIdx;\n        pushTreeFork(returnFiber, _numberOfForks2);\n      }\n\n      return resultingFirstChild;\n    }\n\n    function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, lanes) {\n      // This is the same implementation as reconcileChildrenArray(),\n      // but using the iterator instead.\n      var iteratorFn = getIteratorFn(newChildrenIterable);\n\n      if (typeof iteratorFn !== 'function') {\n        throw new Error('An object is not an iterable. This error is likely caused by a bug in ' + 'React. Please file an issue.');\n      }\n\n      {\n        // We don't support rendering Generators because it's a mutation.\n        // See https://github.com/facebook/react/issues/12995\n        if (typeof Symbol === 'function' && // $FlowFixMe Flow doesn't know about toStringTag\n        newChildrenIterable[Symbol.toStringTag] === 'Generator') {\n          if (!didWarnAboutGenerators) {\n            error('Using Generators as children is unsupported and will likely yield ' + 'unexpected results because enumerating a generator mutates it. ' + 'You may convert it to an array with `Array.from()` or the ' + '`[...spread]` operator before rendering. Keep in mind ' + 'you might need to polyfill these features for older browsers.');\n          }\n\n          didWarnAboutGenerators = true;\n        } // Warn about using Maps as children\n\n\n        if (newChildrenIterable.entries === iteratorFn) {\n          if (!didWarnAboutMaps) {\n            error('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.');\n          }\n\n          didWarnAboutMaps = true;\n        } // First, validate keys.\n        // We'll get a different iterator later for the main pass.\n\n\n        var _newChildren = iteratorFn.call(newChildrenIterable);\n\n        if (_newChildren) {\n          var knownKeys = null;\n\n          var _step = _newChildren.next();\n\n          for (; !_step.done; _step = _newChildren.next()) {\n            var child = _step.value;\n            knownKeys = warnOnInvalidKey(child, knownKeys, returnFiber);\n          }\n        }\n      }\n\n      var newChildren = iteratorFn.call(newChildrenIterable);\n\n      if (newChildren == null) {\n        throw new Error('An iterable object provided no iterator.');\n      }\n\n      var resultingFirstChild = null;\n      var previousNewFiber = null;\n      var oldFiber = currentFirstChild;\n      var lastPlacedIndex = 0;\n      var newIdx = 0;\n      var nextOldFiber = null;\n      var step = newChildren.next();\n\n      for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) {\n        if (oldFiber.index > newIdx) {\n          nextOldFiber = oldFiber;\n          oldFiber = null;\n        } else {\n          nextOldFiber = oldFiber.sibling;\n        }\n\n        var newFiber = updateSlot(returnFiber, oldFiber, step.value, lanes);\n\n        if (newFiber === null) {\n          // TODO: This breaks on empty slots like null children. That's\n          // unfortunate because it triggers the slow path all the time. We need\n          // a better way to communicate whether this was a miss or null,\n          // boolean, undefined, etc.\n          if (oldFiber === null) {\n            oldFiber = nextOldFiber;\n          }\n\n          break;\n        }\n\n        if (shouldTrackSideEffects) {\n          if (oldFiber && newFiber.alternate === null) {\n            // We matched the slot, but we didn't reuse the existing fiber, so we\n            // need to delete the existing child.\n            deleteChild(returnFiber, oldFiber);\n          }\n        }\n\n        lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);\n\n        if (previousNewFiber === null) {\n          // TODO: Move out of the loop. This only happens for the first run.\n          resultingFirstChild = newFiber;\n        } else {\n          // TODO: Defer siblings if we're not at the right index for this slot.\n          // I.e. if we had null values before, then we want to defer this\n          // for each null value. However, we also don't want to call updateSlot\n          // with the previous one.\n          previousNewFiber.sibling = newFiber;\n        }\n\n        previousNewFiber = newFiber;\n        oldFiber = nextOldFiber;\n      }\n\n      if (step.done) {\n        // We've reached the end of the new children. We can delete the rest.\n        deleteRemainingChildren(returnFiber, oldFiber);\n\n        if (getIsHydrating()) {\n          var numberOfForks = newIdx;\n          pushTreeFork(returnFiber, numberOfForks);\n        }\n\n        return resultingFirstChild;\n      }\n\n      if (oldFiber === null) {\n        // If we don't have any more existing children we can choose a fast path\n        // since the rest will all be insertions.\n        for (; !step.done; newIdx++, step = newChildren.next()) {\n          var _newFiber3 = createChild(returnFiber, step.value, lanes);\n\n          if (_newFiber3 === null) {\n            continue;\n          }\n\n          lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx);\n\n          if (previousNewFiber === null) {\n            // TODO: Move out of the loop. This only happens for the first run.\n            resultingFirstChild = _newFiber3;\n          } else {\n            previousNewFiber.sibling = _newFiber3;\n          }\n\n          previousNewFiber = _newFiber3;\n        }\n\n        if (getIsHydrating()) {\n          var _numberOfForks3 = newIdx;\n          pushTreeFork(returnFiber, _numberOfForks3);\n        }\n\n        return resultingFirstChild;\n      } // Add all children to a key map for quick lookups.\n\n\n      var existingChildren = mapRemainingChildren(returnFiber, oldFiber); // Keep scanning and use the map to restore deleted items as moves.\n\n      for (; !step.done; newIdx++, step = newChildren.next()) {\n        var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, lanes);\n\n        if (_newFiber4 !== null) {\n          if (shouldTrackSideEffects) {\n            if (_newFiber4.alternate !== null) {\n              // The new fiber is a work in progress, but if there exists a\n              // current, that means that we reused the fiber. We need to delete\n              // it from the child list so that we don't add it to the deletion\n              // list.\n              existingChildren.delete(_newFiber4.key === null ? newIdx : _newFiber4.key);\n            }\n          }\n\n          lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx);\n\n          if (previousNewFiber === null) {\n            resultingFirstChild = _newFiber4;\n          } else {\n            previousNewFiber.sibling = _newFiber4;\n          }\n\n          previousNewFiber = _newFiber4;\n        }\n      }\n\n      if (shouldTrackSideEffects) {\n        // Any existing children that weren't consumed above were deleted. We need\n        // to add them to the deletion list.\n        existingChildren.forEach(function (child) {\n          return deleteChild(returnFiber, child);\n        });\n      }\n\n      if (getIsHydrating()) {\n        var _numberOfForks4 = newIdx;\n        pushTreeFork(returnFiber, _numberOfForks4);\n      }\n\n      return resultingFirstChild;\n    }\n\n    function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, lanes) {\n      // There's no need to check for keys on text nodes since we don't have a\n      // way to define them.\n      if (currentFirstChild !== null && currentFirstChild.tag === HostText) {\n        // We already have an existing node so let's just update it and delete\n        // the rest.\n        deleteRemainingChildren(returnFiber, currentFirstChild.sibling);\n        var existing = useFiber(currentFirstChild, textContent);\n        existing.return = returnFiber;\n        return existing;\n      } // The existing first child is not a text node so we need to create one\n      // and delete the existing ones.\n\n\n      deleteRemainingChildren(returnFiber, currentFirstChild);\n      var created = createFiberFromText(textContent, returnFiber.mode, lanes);\n      created.return = returnFiber;\n      return created;\n    }\n\n    function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes) {\n      var key = element.key;\n      var child = currentFirstChild;\n\n      while (child !== null) {\n        // TODO: If key === null and child.key === null, then this only applies to\n        // the first item in the list.\n        if (child.key === key) {\n          var elementType = element.type;\n\n          if (elementType === REACT_FRAGMENT_TYPE) {\n            if (child.tag === Fragment) {\n              deleteRemainingChildren(returnFiber, child.sibling);\n              var existing = useFiber(child, element.props.children);\n              existing.return = returnFiber;\n\n              {\n                existing._debugSource = element._source;\n                existing._debugOwner = element._owner;\n              }\n\n              return existing;\n            }\n          } else {\n            if (child.elementType === elementType || ( // Keep this check inline so it only runs on the false path:\n             isCompatibleFamilyForHotReloading(child, element) ) || // Lazy types should reconcile their resolved type.\n            // We need to do this after the Hot Reloading check above,\n            // because hot reloading has different semantics than prod because\n            // it doesn't resuspend. So we can't let the call below suspend.\n            typeof elementType === 'object' && elementType !== null && elementType.$$typeof === REACT_LAZY_TYPE && resolveLazy(elementType) === child.type) {\n              deleteRemainingChildren(returnFiber, child.sibling);\n\n              var _existing = useFiber(child, element.props);\n\n              _existing.ref = coerceRef(returnFiber, child, element);\n              _existing.return = returnFiber;\n\n              {\n                _existing._debugSource = element._source;\n                _existing._debugOwner = element._owner;\n              }\n\n              return _existing;\n            }\n          } // Didn't match.\n\n\n          deleteRemainingChildren(returnFiber, child);\n          break;\n        } else {\n          deleteChild(returnFiber, child);\n        }\n\n        child = child.sibling;\n      }\n\n      if (element.type === REACT_FRAGMENT_TYPE) {\n        var created = createFiberFromFragment(element.props.children, returnFiber.mode, lanes, element.key);\n        created.return = returnFiber;\n        return created;\n      } else {\n        var _created4 = createFiberFromElement(element, returnFiber.mode, lanes);\n\n        _created4.ref = coerceRef(returnFiber, currentFirstChild, element);\n        _created4.return = returnFiber;\n        return _created4;\n      }\n    }\n\n    function reconcileSinglePortal(returnFiber, currentFirstChild, portal, lanes) {\n      var key = portal.key;\n      var child = currentFirstChild;\n\n      while (child !== null) {\n        // TODO: If key === null and child.key === null, then this only applies to\n        // the first item in the list.\n        if (child.key === key) {\n          if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) {\n            deleteRemainingChildren(returnFiber, child.sibling);\n            var existing = useFiber(child, portal.children || []);\n            existing.return = returnFiber;\n            return existing;\n          } else {\n            deleteRemainingChildren(returnFiber, child);\n            break;\n          }\n        } else {\n          deleteChild(returnFiber, child);\n        }\n\n        child = child.sibling;\n      }\n\n      var created = createFiberFromPortal(portal, returnFiber.mode, lanes);\n      created.return = returnFiber;\n      return created;\n    } // This API will tag the children with the side-effect of the reconciliation\n    // itself. They will be added to the side-effect list as we pass through the\n    // children and the parent.\n\n\n    function reconcileChildFibers(returnFiber, currentFirstChild, newChild, lanes) {\n      // This function is not recursive.\n      // If the top level item is an array, we treat it as a set of children,\n      // not as a fragment. Nested arrays on the other hand will be treated as\n      // fragment nodes. Recursion happens at the normal flow.\n      // Handle top level unkeyed fragments as if they were arrays.\n      // This leads to an ambiguity between <>{[...]}</> and <>...</>.\n      // We treat the ambiguous cases above the same.\n      var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null;\n\n      if (isUnkeyedTopLevelFragment) {\n        newChild = newChild.props.children;\n      } // Handle object types\n\n\n      if (typeof newChild === 'object' && newChild !== null) {\n        switch (newChild.$$typeof) {\n          case REACT_ELEMENT_TYPE:\n            return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, lanes));\n\n          case REACT_PORTAL_TYPE:\n            return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, lanes));\n\n          case REACT_LAZY_TYPE:\n            var payload = newChild._payload;\n            var init = newChild._init; // TODO: This function is supposed to be non-recursive.\n\n            return reconcileChildFibers(returnFiber, currentFirstChild, init(payload), lanes);\n        }\n\n        if (isArray(newChild)) {\n          return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, lanes);\n        }\n\n        if (getIteratorFn(newChild)) {\n          return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, lanes);\n        }\n\n        throwOnInvalidObjectType(returnFiber, newChild);\n      }\n\n      if (typeof newChild === 'string' && newChild !== '' || typeof newChild === 'number') {\n        return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, lanes));\n      }\n\n      {\n        if (typeof newChild === 'function') {\n          warnOnFunctionType(returnFiber);\n        }\n      } // Remaining cases are all treated as empty.\n\n\n      return deleteRemainingChildren(returnFiber, currentFirstChild);\n    }\n\n    return reconcileChildFibers;\n  }\n\n  var reconcileChildFibers = ChildReconciler(true);\n  var mountChildFibers = ChildReconciler(false);\n  function cloneChildFibers(current, workInProgress) {\n    if (current !== null && workInProgress.child !== current.child) {\n      throw new Error('Resuming work not yet implemented.');\n    }\n\n    if (workInProgress.child === null) {\n      return;\n    }\n\n    var currentChild = workInProgress.child;\n    var newChild = createWorkInProgress(currentChild, currentChild.pendingProps);\n    workInProgress.child = newChild;\n    newChild.return = workInProgress;\n\n    while (currentChild.sibling !== null) {\n      currentChild = currentChild.sibling;\n      newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps);\n      newChild.return = workInProgress;\n    }\n\n    newChild.sibling = null;\n  } // Reset a workInProgress child set to prepare it for a second pass.\n\n  function resetChildFibers(workInProgress, lanes) {\n    var child = workInProgress.child;\n\n    while (child !== null) {\n      resetWorkInProgress(child, lanes);\n      child = child.sibling;\n    }\n  }\n\n  var valueCursor = createCursor(null);\n  var rendererSigil;\n\n  {\n    // Use this to detect multiple renderers using the same context\n    rendererSigil = {};\n  }\n\n  var currentlyRenderingFiber = null;\n  var lastContextDependency = null;\n  var lastFullyObservedContext = null;\n  var isDisallowedContextReadInDEV = false;\n  function resetContextDependencies() {\n    // This is called right before React yields execution, to ensure `readContext`\n    // cannot be called outside the render phase.\n    currentlyRenderingFiber = null;\n    lastContextDependency = null;\n    lastFullyObservedContext = null;\n\n    {\n      isDisallowedContextReadInDEV = false;\n    }\n  }\n  function enterDisallowedContextReadInDEV() {\n    {\n      isDisallowedContextReadInDEV = true;\n    }\n  }\n  function exitDisallowedContextReadInDEV() {\n    {\n      isDisallowedContextReadInDEV = false;\n    }\n  }\n  function pushProvider(providerFiber, context, nextValue) {\n    {\n      push(valueCursor, context._currentValue, providerFiber);\n      context._currentValue = nextValue;\n\n      {\n        if (context._currentRenderer !== undefined && context._currentRenderer !== null && context._currentRenderer !== rendererSigil) {\n          error('Detected multiple renderers concurrently rendering the ' + 'same context provider. This is currently unsupported.');\n        }\n\n        context._currentRenderer = rendererSigil;\n      }\n    }\n  }\n  function popProvider(context, providerFiber) {\n    var currentValue = valueCursor.current;\n    pop(valueCursor, providerFiber);\n\n    {\n      {\n        context._currentValue = currentValue;\n      }\n    }\n  }\n  function scheduleContextWorkOnParentPath(parent, renderLanes, propagationRoot) {\n    // Update the child lanes of all the ancestors, including the alternates.\n    var node = parent;\n\n    while (node !== null) {\n      var alternate = node.alternate;\n\n      if (!isSubsetOfLanes(node.childLanes, renderLanes)) {\n        node.childLanes = mergeLanes(node.childLanes, renderLanes);\n\n        if (alternate !== null) {\n          alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);\n        }\n      } else if (alternate !== null && !isSubsetOfLanes(alternate.childLanes, renderLanes)) {\n        alternate.childLanes = mergeLanes(alternate.childLanes, renderLanes);\n      }\n\n      if (node === propagationRoot) {\n        break;\n      }\n\n      node = node.return;\n    }\n\n    {\n      if (node !== propagationRoot) {\n        error('Expected to find the propagation root when scheduling context work. ' + 'This error is likely caused by a bug in React. Please file an issue.');\n      }\n    }\n  }\n  function propagateContextChange(workInProgress, context, renderLanes) {\n    {\n      propagateContextChange_eager(workInProgress, context, renderLanes);\n    }\n  }\n\n  function propagateContextChange_eager(workInProgress, context, renderLanes) {\n\n    var fiber = workInProgress.child;\n\n    if (fiber !== null) {\n      // Set the return pointer of the child to the work-in-progress fiber.\n      fiber.return = workInProgress;\n    }\n\n    while (fiber !== null) {\n      var nextFiber = void 0; // Visit this fiber.\n\n      var list = fiber.dependencies;\n\n      if (list !== null) {\n        nextFiber = fiber.child;\n        var dependency = list.firstContext;\n\n        while (dependency !== null) {\n          // Check if the context matches.\n          if (dependency.context === context) {\n            // Match! Schedule an update on this fiber.\n            if (fiber.tag === ClassComponent) {\n              // Schedule a force update on the work-in-progress.\n              var lane = pickArbitraryLane(renderLanes);\n              var update = createUpdate(NoTimestamp, lane);\n              update.tag = ForceUpdate; // TODO: Because we don't have a work-in-progress, this will add the\n              // update to the current fiber, too, which means it will persist even if\n              // this render is thrown away. Since it's a race condition, not sure it's\n              // worth fixing.\n              // Inlined `enqueueUpdate` to remove interleaved update check\n\n              var updateQueue = fiber.updateQueue;\n\n              if (updateQueue === null) ; else {\n                var sharedQueue = updateQueue.shared;\n                var pending = sharedQueue.pending;\n\n                if (pending === null) {\n                  // This is the first update. Create a circular list.\n                  update.next = update;\n                } else {\n                  update.next = pending.next;\n                  pending.next = update;\n                }\n\n                sharedQueue.pending = update;\n              }\n            }\n\n            fiber.lanes = mergeLanes(fiber.lanes, renderLanes);\n            var alternate = fiber.alternate;\n\n            if (alternate !== null) {\n              alternate.lanes = mergeLanes(alternate.lanes, renderLanes);\n            }\n\n            scheduleContextWorkOnParentPath(fiber.return, renderLanes, workInProgress); // Mark the updated lanes on the list, too.\n\n            list.lanes = mergeLanes(list.lanes, renderLanes); // Since we already found a match, we can stop traversing the\n            // dependency list.\n\n            break;\n          }\n\n          dependency = dependency.next;\n        }\n      } else if (fiber.tag === ContextProvider) {\n        // Don't scan deeper if this is a matching provider\n        nextFiber = fiber.type === workInProgress.type ? null : fiber.child;\n      } else if (fiber.tag === DehydratedFragment) {\n        // If a dehydrated suspense boundary is in this subtree, we don't know\n        // if it will have any context consumers in it. The best we can do is\n        // mark it as having updates.\n        var parentSuspense = fiber.return;\n\n        if (parentSuspense === null) {\n          throw new Error('We just came from a parent so we must have had a parent. This is a bug in React.');\n        }\n\n        parentSuspense.lanes = mergeLanes(parentSuspense.lanes, renderLanes);\n        var _alternate = parentSuspense.alternate;\n\n        if (_alternate !== null) {\n          _alternate.lanes = mergeLanes(_alternate.lanes, renderLanes);\n        } // This is intentionally passing this fiber as the parent\n        // because we want to schedule this fiber as having work\n        // on its children. We'll use the childLanes on\n        // this fiber to indicate that a context has changed.\n\n\n        scheduleContextWorkOnParentPath(parentSuspense, renderLanes, workInProgress);\n        nextFiber = fiber.sibling;\n      } else {\n        // Traverse down.\n        nextFiber = fiber.child;\n      }\n\n      if (nextFiber !== null) {\n        // Set the return pointer of the child to the work-in-progress fiber.\n        nextFiber.return = fiber;\n      } else {\n        // No child. Traverse to next sibling.\n        nextFiber = fiber;\n\n        while (nextFiber !== null) {\n          if (nextFiber === workInProgress) {\n            // We're back to the root of this subtree. Exit.\n            nextFiber = null;\n            break;\n          }\n\n          var sibling = nextFiber.sibling;\n\n          if (sibling !== null) {\n            // Set the return pointer of the sibling to the work-in-progress fiber.\n            sibling.return = nextFiber.return;\n            nextFiber = sibling;\n            break;\n          } // No more siblings. Traverse up.\n\n\n          nextFiber = nextFiber.return;\n        }\n      }\n\n      fiber = nextFiber;\n    }\n  }\n  function prepareToReadContext(workInProgress, renderLanes) {\n    currentlyRenderingFiber = workInProgress;\n    lastContextDependency = null;\n    lastFullyObservedContext = null;\n    var dependencies = workInProgress.dependencies;\n\n    if (dependencies !== null) {\n      {\n        var firstContext = dependencies.firstContext;\n\n        if (firstContext !== null) {\n          if (includesSomeLane(dependencies.lanes, renderLanes)) {\n            // Context list has a pending update. Mark that this fiber performed work.\n            markWorkInProgressReceivedUpdate();\n          } // Reset the work-in-progress list\n\n\n          dependencies.firstContext = null;\n        }\n      }\n    }\n  }\n  function readContext(context) {\n    {\n      // This warning would fire if you read context inside a Hook like useMemo.\n      // Unlike the class check below, it's not enforced in production for perf.\n      if (isDisallowedContextReadInDEV) {\n        error('Context can only be read while React is rendering. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In function components, you can read it directly in the function body, but not ' + 'inside Hooks like useReducer() or useMemo().');\n      }\n    }\n\n    var value =  context._currentValue ;\n\n    if (lastFullyObservedContext === context) ; else {\n      var contextItem = {\n        context: context,\n        memoizedValue: value,\n        next: null\n      };\n\n      if (lastContextDependency === null) {\n        if (currentlyRenderingFiber === null) {\n          throw new Error('Context can only be read while React is rendering. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In function components, you can read it directly in the function body, but not ' + 'inside Hooks like useReducer() or useMemo().');\n        } // This is the first dependency for this component. Create a new list.\n\n\n        lastContextDependency = contextItem;\n        currentlyRenderingFiber.dependencies = {\n          lanes: NoLanes,\n          firstContext: contextItem\n        };\n      } else {\n        // Append a new context item.\n        lastContextDependency = lastContextDependency.next = contextItem;\n      }\n    }\n\n    return value;\n  }\n\n  // render. When this render exits, either because it finishes or because it is\n  // interrupted, the interleaved updates will be transferred onto the main part\n  // of the queue.\n\n  var concurrentQueues = null;\n  function pushConcurrentUpdateQueue(queue) {\n    if (concurrentQueues === null) {\n      concurrentQueues = [queue];\n    } else {\n      concurrentQueues.push(queue);\n    }\n  }\n  function finishQueueingConcurrentUpdates() {\n    // Transfer the interleaved updates onto the main queue. Each queue has a\n    // `pending` field and an `interleaved` field. When they are not null, they\n    // point to the last node in a circular linked list. We need to append the\n    // interleaved list to the end of the pending list by joining them into a\n    // single, circular list.\n    if (concurrentQueues !== null) {\n      for (var i = 0; i < concurrentQueues.length; i++) {\n        var queue = concurrentQueues[i];\n        var lastInterleavedUpdate = queue.interleaved;\n\n        if (lastInterleavedUpdate !== null) {\n          queue.interleaved = null;\n          var firstInterleavedUpdate = lastInterleavedUpdate.next;\n          var lastPendingUpdate = queue.pending;\n\n          if (lastPendingUpdate !== null) {\n            var firstPendingUpdate = lastPendingUpdate.next;\n            lastPendingUpdate.next = firstInterleavedUpdate;\n            lastInterleavedUpdate.next = firstPendingUpdate;\n          }\n\n          queue.pending = lastInterleavedUpdate;\n        }\n      }\n\n      concurrentQueues = null;\n    }\n  }\n  function enqueueConcurrentHookUpdate(fiber, queue, update, lane) {\n    var interleaved = queue.interleaved;\n\n    if (interleaved === null) {\n      // This is the first update. Create a circular list.\n      update.next = update; // At the end of the current render, this queue's interleaved updates will\n      // be transferred to the pending queue.\n\n      pushConcurrentUpdateQueue(queue);\n    } else {\n      update.next = interleaved.next;\n      interleaved.next = update;\n    }\n\n    queue.interleaved = update;\n    return markUpdateLaneFromFiberToRoot(fiber, lane);\n  }\n  function enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update, lane) {\n    var interleaved = queue.interleaved;\n\n    if (interleaved === null) {\n      // This is the first update. Create a circular list.\n      update.next = update; // At the end of the current render, this queue's interleaved updates will\n      // be transferred to the pending queue.\n\n      pushConcurrentUpdateQueue(queue);\n    } else {\n      update.next = interleaved.next;\n      interleaved.next = update;\n    }\n\n    queue.interleaved = update;\n  }\n  function enqueueConcurrentClassUpdate(fiber, queue, update, lane) {\n    var interleaved = queue.interleaved;\n\n    if (interleaved === null) {\n      // This is the first update. Create a circular list.\n      update.next = update; // At the end of the current render, this queue's interleaved updates will\n      // be transferred to the pending queue.\n\n      pushConcurrentUpdateQueue(queue);\n    } else {\n      update.next = interleaved.next;\n      interleaved.next = update;\n    }\n\n    queue.interleaved = update;\n    return markUpdateLaneFromFiberToRoot(fiber, lane);\n  }\n  function enqueueConcurrentRenderForLane(fiber, lane) {\n    return markUpdateLaneFromFiberToRoot(fiber, lane);\n  } // Calling this function outside this module should only be done for backwards\n  // compatibility and should always be accompanied by a warning.\n\n  var unsafe_markUpdateLaneFromFiberToRoot = markUpdateLaneFromFiberToRoot;\n\n  function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {\n    // Update the source fiber's lanes\n    sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);\n    var alternate = sourceFiber.alternate;\n\n    if (alternate !== null) {\n      alternate.lanes = mergeLanes(alternate.lanes, lane);\n    }\n\n    {\n      if (alternate === null && (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags) {\n        warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);\n      }\n    } // Walk the parent path to the root and update the child lanes.\n\n\n    var node = sourceFiber;\n    var parent = sourceFiber.return;\n\n    while (parent !== null) {\n      parent.childLanes = mergeLanes(parent.childLanes, lane);\n      alternate = parent.alternate;\n\n      if (alternate !== null) {\n        alternate.childLanes = mergeLanes(alternate.childLanes, lane);\n      } else {\n        {\n          if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {\n            warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);\n          }\n        }\n      }\n\n      node = parent;\n      parent = parent.return;\n    }\n\n    if (node.tag === HostRoot) {\n      var root = node.stateNode;\n      return root;\n    } else {\n      return null;\n    }\n  }\n\n  var UpdateState = 0;\n  var ReplaceState = 1;\n  var ForceUpdate = 2;\n  var CaptureUpdate = 3; // Global state that is reset at the beginning of calling `processUpdateQueue`.\n  // It should only be read right after calling `processUpdateQueue`, via\n  // `checkHasForceUpdateAfterProcessing`.\n\n  var hasForceUpdate = false;\n  var didWarnUpdateInsideUpdate;\n  var currentlyProcessingQueue;\n\n  {\n    didWarnUpdateInsideUpdate = false;\n    currentlyProcessingQueue = null;\n  }\n\n  function initializeUpdateQueue(fiber) {\n    var queue = {\n      baseState: fiber.memoizedState,\n      firstBaseUpdate: null,\n      lastBaseUpdate: null,\n      shared: {\n        pending: null,\n        interleaved: null,\n        lanes: NoLanes\n      },\n      effects: null\n    };\n    fiber.updateQueue = queue;\n  }\n  function cloneUpdateQueue(current, workInProgress) {\n    // Clone the update queue from current. Unless it's already a clone.\n    var queue = workInProgress.updateQueue;\n    var currentQueue = current.updateQueue;\n\n    if (queue === currentQueue) {\n      var clone = {\n        baseState: currentQueue.baseState,\n        firstBaseUpdate: currentQueue.firstBaseUpdate,\n        lastBaseUpdate: currentQueue.lastBaseUpdate,\n        shared: currentQueue.shared,\n        effects: currentQueue.effects\n      };\n      workInProgress.updateQueue = clone;\n    }\n  }\n  function createUpdate(eventTime, lane) {\n    var update = {\n      eventTime: eventTime,\n      lane: lane,\n      tag: UpdateState,\n      payload: null,\n      callback: null,\n      next: null\n    };\n    return update;\n  }\n  function enqueueUpdate(fiber, update, lane) {\n    var updateQueue = fiber.updateQueue;\n\n    if (updateQueue === null) {\n      // Only occurs if the fiber has been unmounted.\n      return null;\n    }\n\n    var sharedQueue = updateQueue.shared;\n\n    {\n      if (currentlyProcessingQueue === sharedQueue && !didWarnUpdateInsideUpdate) {\n        error('An update (setState, replaceState, or forceUpdate) was scheduled ' + 'from inside an update function. Update functions should be pure, ' + 'with zero side-effects. Consider using componentDidUpdate or a ' + 'callback.');\n\n        didWarnUpdateInsideUpdate = true;\n      }\n    }\n\n    if (isUnsafeClassRenderPhaseUpdate()) {\n      // This is an unsafe render phase update. Add directly to the update\n      // queue so we can process it immediately during the current render.\n      var pending = sharedQueue.pending;\n\n      if (pending === null) {\n        // This is the first update. Create a circular list.\n        update.next = update;\n      } else {\n        update.next = pending.next;\n        pending.next = update;\n      }\n\n      sharedQueue.pending = update; // Update the childLanes even though we're most likely already rendering\n      // this fiber. This is for backwards compatibility in the case where you\n      // update a different component during render phase than the one that is\n      // currently renderings (a pattern that is accompanied by a warning).\n\n      return unsafe_markUpdateLaneFromFiberToRoot(fiber, lane);\n    } else {\n      return enqueueConcurrentClassUpdate(fiber, sharedQueue, update, lane);\n    }\n  }\n  function entangleTransitions(root, fiber, lane) {\n    var updateQueue = fiber.updateQueue;\n\n    if (updateQueue === null) {\n      // Only occurs if the fiber has been unmounted.\n      return;\n    }\n\n    var sharedQueue = updateQueue.shared;\n\n    if (isTransitionLane(lane)) {\n      var queueLanes = sharedQueue.lanes; // If any entangled lanes are no longer pending on the root, then they must\n      // have finished. We can remove them from the shared queue, which represents\n      // a superset of the actually pending lanes. In some cases we may entangle\n      // more than we need to, but that's OK. In fact it's worse if we *don't*\n      // entangle when we should.\n\n      queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes.\n\n      var newQueueLanes = mergeLanes(queueLanes, lane);\n      sharedQueue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if\n      // the lane finished since the last time we entangled it. So we need to\n      // entangle it again, just to be sure.\n\n      markRootEntangled(root, newQueueLanes);\n    }\n  }\n  function enqueueCapturedUpdate(workInProgress, capturedUpdate) {\n    // Captured updates are updates that are thrown by a child during the render\n    // phase. They should be discarded if the render is aborted. Therefore,\n    // we should only put them on the work-in-progress queue, not the current one.\n    var queue = workInProgress.updateQueue; // Check if the work-in-progress queue is a clone.\n\n    var current = workInProgress.alternate;\n\n    if (current !== null) {\n      var currentQueue = current.updateQueue;\n\n      if (queue === currentQueue) {\n        // The work-in-progress queue is the same as current. This happens when\n        // we bail out on a parent fiber that then captures an error thrown by\n        // a child. Since we want to append the update only to the work-in\n        // -progress queue, we need to clone the updates. We usually clone during\n        // processUpdateQueue, but that didn't happen in this case because we\n        // skipped over the parent when we bailed out.\n        var newFirst = null;\n        var newLast = null;\n        var firstBaseUpdate = queue.firstBaseUpdate;\n\n        if (firstBaseUpdate !== null) {\n          // Loop through the updates and clone them.\n          var update = firstBaseUpdate;\n\n          do {\n            var clone = {\n              eventTime: update.eventTime,\n              lane: update.lane,\n              tag: update.tag,\n              payload: update.payload,\n              callback: update.callback,\n              next: null\n            };\n\n            if (newLast === null) {\n              newFirst = newLast = clone;\n            } else {\n              newLast.next = clone;\n              newLast = clone;\n            }\n\n            update = update.next;\n          } while (update !== null); // Append the captured update the end of the cloned list.\n\n\n          if (newLast === null) {\n            newFirst = newLast = capturedUpdate;\n          } else {\n            newLast.next = capturedUpdate;\n            newLast = capturedUpdate;\n          }\n        } else {\n          // There are no base updates.\n          newFirst = newLast = capturedUpdate;\n        }\n\n        queue = {\n          baseState: currentQueue.baseState,\n          firstBaseUpdate: newFirst,\n          lastBaseUpdate: newLast,\n          shared: currentQueue.shared,\n          effects: currentQueue.effects\n        };\n        workInProgress.updateQueue = queue;\n        return;\n      }\n    } // Append the update to the end of the list.\n\n\n    var lastBaseUpdate = queue.lastBaseUpdate;\n\n    if (lastBaseUpdate === null) {\n      queue.firstBaseUpdate = capturedUpdate;\n    } else {\n      lastBaseUpdate.next = capturedUpdate;\n    }\n\n    queue.lastBaseUpdate = capturedUpdate;\n  }\n\n  function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) {\n    switch (update.tag) {\n      case ReplaceState:\n        {\n          var payload = update.payload;\n\n          if (typeof payload === 'function') {\n            // Updater function\n            {\n              enterDisallowedContextReadInDEV();\n            }\n\n            var nextState = payload.call(instance, prevState, nextProps);\n\n            {\n              if ( workInProgress.mode & StrictLegacyMode) {\n                setIsStrictModeForDevtools(true);\n\n                try {\n                  payload.call(instance, prevState, nextProps);\n                } finally {\n                  setIsStrictModeForDevtools(false);\n                }\n              }\n\n              exitDisallowedContextReadInDEV();\n            }\n\n            return nextState;\n          } // State object\n\n\n          return payload;\n        }\n\n      case CaptureUpdate:\n        {\n          workInProgress.flags = workInProgress.flags & ~ShouldCapture | DidCapture;\n        }\n      // Intentional fallthrough\n\n      case UpdateState:\n        {\n          var _payload = update.payload;\n          var partialState;\n\n          if (typeof _payload === 'function') {\n            // Updater function\n            {\n              enterDisallowedContextReadInDEV();\n            }\n\n            partialState = _payload.call(instance, prevState, nextProps);\n\n            {\n              if ( workInProgress.mode & StrictLegacyMode) {\n                setIsStrictModeForDevtools(true);\n\n                try {\n                  _payload.call(instance, prevState, nextProps);\n                } finally {\n                  setIsStrictModeForDevtools(false);\n                }\n              }\n\n              exitDisallowedContextReadInDEV();\n            }\n          } else {\n            // Partial state object\n            partialState = _payload;\n          }\n\n          if (partialState === null || partialState === undefined) {\n            // Null and undefined are treated as no-ops.\n            return prevState;\n          } // Merge the partial state and the previous state.\n\n\n          return assign({}, prevState, partialState);\n        }\n\n      case ForceUpdate:\n        {\n          hasForceUpdate = true;\n          return prevState;\n        }\n    }\n\n    return prevState;\n  }\n\n  function processUpdateQueue(workInProgress, props, instance, renderLanes) {\n    // This is always non-null on a ClassComponent or HostRoot\n    var queue = workInProgress.updateQueue;\n    hasForceUpdate = false;\n\n    {\n      currentlyProcessingQueue = queue.shared;\n    }\n\n    var firstBaseUpdate = queue.firstBaseUpdate;\n    var lastBaseUpdate = queue.lastBaseUpdate; // Check if there are pending updates. If so, transfer them to the base queue.\n\n    var pendingQueue = queue.shared.pending;\n\n    if (pendingQueue !== null) {\n      queue.shared.pending = null; // The pending queue is circular. Disconnect the pointer between first\n      // and last so that it's non-circular.\n\n      var lastPendingUpdate = pendingQueue;\n      var firstPendingUpdate = lastPendingUpdate.next;\n      lastPendingUpdate.next = null; // Append pending updates to base queue\n\n      if (lastBaseUpdate === null) {\n        firstBaseUpdate = firstPendingUpdate;\n      } else {\n        lastBaseUpdate.next = firstPendingUpdate;\n      }\n\n      lastBaseUpdate = lastPendingUpdate; // If there's a current queue, and it's different from the base queue, then\n      // we need to transfer the updates to that queue, too. Because the base\n      // queue is a singly-linked list with no cycles, we can append to both\n      // lists and take advantage of structural sharing.\n      // TODO: Pass `current` as argument\n\n      var current = workInProgress.alternate;\n\n      if (current !== null) {\n        // This is always non-null on a ClassComponent or HostRoot\n        var currentQueue = current.updateQueue;\n        var currentLastBaseUpdate = currentQueue.lastBaseUpdate;\n\n        if (currentLastBaseUpdate !== lastBaseUpdate) {\n          if (currentLastBaseUpdate === null) {\n            currentQueue.firstBaseUpdate = firstPendingUpdate;\n          } else {\n            currentLastBaseUpdate.next = firstPendingUpdate;\n          }\n\n          currentQueue.lastBaseUpdate = lastPendingUpdate;\n        }\n      }\n    } // These values may change as we process the queue.\n\n\n    if (firstBaseUpdate !== null) {\n      // Iterate through the list of updates to compute the result.\n      var newState = queue.baseState; // TODO: Don't need to accumulate this. Instead, we can remove renderLanes\n      // from the original lanes.\n\n      var newLanes = NoLanes;\n      var newBaseState = null;\n      var newFirstBaseUpdate = null;\n      var newLastBaseUpdate = null;\n      var update = firstBaseUpdate;\n\n      do {\n        var updateLane = update.lane;\n        var updateEventTime = update.eventTime;\n\n        if (!isSubsetOfLanes(renderLanes, updateLane)) {\n          // Priority is insufficient. Skip this update. If this is the first\n          // skipped update, the previous update/state is the new base\n          // update/state.\n          var clone = {\n            eventTime: updateEventTime,\n            lane: updateLane,\n            tag: update.tag,\n            payload: update.payload,\n            callback: update.callback,\n            next: null\n          };\n\n          if (newLastBaseUpdate === null) {\n            newFirstBaseUpdate = newLastBaseUpdate = clone;\n            newBaseState = newState;\n          } else {\n            newLastBaseUpdate = newLastBaseUpdate.next = clone;\n          } // Update the remaining priority in the queue.\n\n\n          newLanes = mergeLanes(newLanes, updateLane);\n        } else {\n          // This update does have sufficient priority.\n          if (newLastBaseUpdate !== null) {\n            var _clone = {\n              eventTime: updateEventTime,\n              // This update is going to be committed so we never want uncommit\n              // it. Using NoLane works because 0 is a subset of all bitmasks, so\n              // this will never be skipped by the check above.\n              lane: NoLane,\n              tag: update.tag,\n              payload: update.payload,\n              callback: update.callback,\n              next: null\n            };\n            newLastBaseUpdate = newLastBaseUpdate.next = _clone;\n          } // Process this update.\n\n\n          newState = getStateFromUpdate(workInProgress, queue, update, newState, props, instance);\n          var callback = update.callback;\n\n          if (callback !== null && // If the update was already committed, we should not queue its\n          // callback again.\n          update.lane !== NoLane) {\n            workInProgress.flags |= Callback;\n            var effects = queue.effects;\n\n            if (effects === null) {\n              queue.effects = [update];\n            } else {\n              effects.push(update);\n            }\n          }\n        }\n\n        update = update.next;\n\n        if (update === null) {\n          pendingQueue = queue.shared.pending;\n\n          if (pendingQueue === null) {\n            break;\n          } else {\n            // An update was scheduled from inside a reducer. Add the new\n            // pending updates to the end of the list and keep processing.\n            var _lastPendingUpdate = pendingQueue; // Intentionally unsound. Pending updates form a circular list, but we\n            // unravel them when transferring them to the base queue.\n\n            var _firstPendingUpdate = _lastPendingUpdate.next;\n            _lastPendingUpdate.next = null;\n            update = _firstPendingUpdate;\n            queue.lastBaseUpdate = _lastPendingUpdate;\n            queue.shared.pending = null;\n          }\n        }\n      } while (true);\n\n      if (newLastBaseUpdate === null) {\n        newBaseState = newState;\n      }\n\n      queue.baseState = newBaseState;\n      queue.firstBaseUpdate = newFirstBaseUpdate;\n      queue.lastBaseUpdate = newLastBaseUpdate; // Interleaved updates are stored on a separate queue. We aren't going to\n      // process them during this render, but we do need to track which lanes\n      // are remaining.\n\n      var lastInterleaved = queue.shared.interleaved;\n\n      if (lastInterleaved !== null) {\n        var interleaved = lastInterleaved;\n\n        do {\n          newLanes = mergeLanes(newLanes, interleaved.lane);\n          interleaved = interleaved.next;\n        } while (interleaved !== lastInterleaved);\n      } else if (firstBaseUpdate === null) {\n        // `queue.lanes` is used for entangling transitions. We can set it back to\n        // zero once the queue is empty.\n        queue.shared.lanes = NoLanes;\n      } // Set the remaining expiration time to be whatever is remaining in the queue.\n      // This should be fine because the only two other things that contribute to\n      // expiration time are props and context. We're already in the middle of the\n      // begin phase by the time we start processing the queue, so we've already\n      // dealt with the props. Context in components that specify\n      // shouldComponentUpdate is tricky; but we'll have to account for\n      // that regardless.\n\n\n      markSkippedUpdateLanes(newLanes);\n      workInProgress.lanes = newLanes;\n      workInProgress.memoizedState = newState;\n    }\n\n    {\n      currentlyProcessingQueue = null;\n    }\n  }\n\n  function callCallback(callback, context) {\n    if (typeof callback !== 'function') {\n      throw new Error('Invalid argument passed as callback. Expected a function. Instead ' + (\"received: \" + callback));\n    }\n\n    callback.call(context);\n  }\n\n  function resetHasForceUpdateBeforeProcessing() {\n    hasForceUpdate = false;\n  }\n  function checkHasForceUpdateAfterProcessing() {\n    return hasForceUpdate;\n  }\n  function commitUpdateQueue(finishedWork, finishedQueue, instance) {\n    // Commit the effects\n    var effects = finishedQueue.effects;\n    finishedQueue.effects = null;\n\n    if (effects !== null) {\n      for (var i = 0; i < effects.length; i++) {\n        var effect = effects[i];\n        var callback = effect.callback;\n\n        if (callback !== null) {\n          effect.callback = null;\n          callCallback(callback, instance);\n        }\n      }\n    }\n  }\n\n  var NO_CONTEXT = {};\n  var contextStackCursor$1 = createCursor(NO_CONTEXT);\n  var contextFiberStackCursor = createCursor(NO_CONTEXT);\n  var rootInstanceStackCursor = createCursor(NO_CONTEXT);\n\n  function requiredContext(c) {\n    if (c === NO_CONTEXT) {\n      throw new Error('Expected host context to exist. This error is likely caused by a bug ' + 'in React. Please file an issue.');\n    }\n\n    return c;\n  }\n\n  function getRootHostContainer() {\n    var rootInstance = requiredContext(rootInstanceStackCursor.current);\n    return rootInstance;\n  }\n\n  function pushHostContainer(fiber, nextRootInstance) {\n    // Push current root instance onto the stack;\n    // This allows us to reset root when portals are popped.\n    push(rootInstanceStackCursor, nextRootInstance, fiber); // Track the context and the Fiber that provided it.\n    // This enables us to pop only Fibers that provide unique contexts.\n\n    push(contextFiberStackCursor, fiber, fiber); // Finally, we need to push the host context to the stack.\n    // However, we can't just call getRootHostContext() and push it because\n    // we'd have a different number of entries on the stack depending on\n    // whether getRootHostContext() throws somewhere in renderer code or not.\n    // So we push an empty value first. This lets us safely unwind on errors.\n\n    push(contextStackCursor$1, NO_CONTEXT, fiber);\n    var nextRootContext = getRootHostContext(nextRootInstance); // Now that we know this function doesn't throw, replace it.\n\n    pop(contextStackCursor$1, fiber);\n    push(contextStackCursor$1, nextRootContext, fiber);\n  }\n\n  function popHostContainer(fiber) {\n    pop(contextStackCursor$1, fiber);\n    pop(contextFiberStackCursor, fiber);\n    pop(rootInstanceStackCursor, fiber);\n  }\n\n  function getHostContext() {\n    var context = requiredContext(contextStackCursor$1.current);\n    return context;\n  }\n\n  function pushHostContext(fiber) {\n    var rootInstance = requiredContext(rootInstanceStackCursor.current);\n    var context = requiredContext(contextStackCursor$1.current);\n    var nextContext = getChildHostContext(context, fiber.type); // Don't push this Fiber's context unless it's unique.\n\n    if (context === nextContext) {\n      return;\n    } // Track the context and the Fiber that provided it.\n    // This enables us to pop only Fibers that provide unique contexts.\n\n\n    push(contextFiberStackCursor, fiber, fiber);\n    push(contextStackCursor$1, nextContext, fiber);\n  }\n\n  function popHostContext(fiber) {\n    // Do not pop unless this Fiber provided the current context.\n    // pushHostContext() only pushes Fibers that provide unique contexts.\n    if (contextFiberStackCursor.current !== fiber) {\n      return;\n    }\n\n    pop(contextStackCursor$1, fiber);\n    pop(contextFiberStackCursor, fiber);\n  }\n\n  var DefaultSuspenseContext = 0; // The Suspense Context is split into two parts. The lower bits is\n  // inherited deeply down the subtree. The upper bits only affect\n  // this immediate suspense boundary and gets reset each new\n  // boundary or suspense list.\n\n  var SubtreeSuspenseContextMask = 1; // Subtree Flags:\n  // InvisibleParentSuspenseContext indicates that one of our parent Suspense\n  // boundaries is not currently showing visible main content.\n  // Either because it is already showing a fallback or is not mounted at all.\n  // We can use this to determine if it is desirable to trigger a fallback at\n  // the parent. If not, then we might need to trigger undesirable boundaries\n  // and/or suspend the commit to avoid hiding the parent content.\n\n  var InvisibleParentSuspenseContext = 1; // Shallow Flags:\n  // ForceSuspenseFallback can be used by SuspenseList to force newly added\n  // items into their fallback state during one of the render passes.\n\n  var ForceSuspenseFallback = 2;\n  var suspenseStackCursor = createCursor(DefaultSuspenseContext);\n  function hasSuspenseContext(parentContext, flag) {\n    return (parentContext & flag) !== 0;\n  }\n  function setDefaultShallowSuspenseContext(parentContext) {\n    return parentContext & SubtreeSuspenseContextMask;\n  }\n  function setShallowSuspenseContext(parentContext, shallowContext) {\n    return parentContext & SubtreeSuspenseContextMask | shallowContext;\n  }\n  function addSubtreeSuspenseContext(parentContext, subtreeContext) {\n    return parentContext | subtreeContext;\n  }\n  function pushSuspenseContext(fiber, newContext) {\n    push(suspenseStackCursor, newContext, fiber);\n  }\n  function popSuspenseContext(fiber) {\n    pop(suspenseStackCursor, fiber);\n  }\n\n  function shouldCaptureSuspense(workInProgress, hasInvisibleParent) {\n    // If it was the primary children that just suspended, capture and render the\n    // fallback. Otherwise, don't capture and bubble to the next boundary.\n    var nextState = workInProgress.memoizedState;\n\n    if (nextState !== null) {\n      if (nextState.dehydrated !== null) {\n        // A dehydrated boundary always captures.\n        return true;\n      }\n\n      return false;\n    }\n\n    var props = workInProgress.memoizedProps; // Regular boundaries always capture.\n\n    {\n      return true;\n    } // If it's a boundary we should avoid, then we prefer to bubble up to the\n  }\n  function findFirstSuspended(row) {\n    var node = row;\n\n    while (node !== null) {\n      if (node.tag === SuspenseComponent) {\n        var state = node.memoizedState;\n\n        if (state !== null) {\n          var dehydrated = state.dehydrated;\n\n          if (dehydrated === null || isSuspenseInstancePending(dehydrated) || isSuspenseInstanceFallback(dehydrated)) {\n            return node;\n          }\n        }\n      } else if (node.tag === SuspenseListComponent && // revealOrder undefined can't be trusted because it don't\n      // keep track of whether it suspended or not.\n      node.memoizedProps.revealOrder !== undefined) {\n        var didSuspend = (node.flags & DidCapture) !== NoFlags;\n\n        if (didSuspend) {\n          return node;\n        }\n      } else if (node.child !== null) {\n        node.child.return = node;\n        node = node.child;\n        continue;\n      }\n\n      if (node === row) {\n        return null;\n      }\n\n      while (node.sibling === null) {\n        if (node.return === null || node.return === row) {\n          return null;\n        }\n\n        node = node.return;\n      }\n\n      node.sibling.return = node.return;\n      node = node.sibling;\n    }\n\n    return null;\n  }\n\n  var NoFlags$1 =\n  /*   */\n  0; // Represents whether effect should fire.\n\n  var HasEffect =\n  /* */\n  1; // Represents the phase in which the effect (not the clean-up) fires.\n\n  var Insertion =\n  /*  */\n  2;\n  var Layout =\n  /*    */\n  4;\n  var Passive$1 =\n  /*   */\n  8;\n\n  // and should be reset before starting a new render.\n  // This tracks which mutable sources need to be reset after a render.\n\n  var workInProgressSources = [];\n  function resetWorkInProgressVersions() {\n    for (var i = 0; i < workInProgressSources.length; i++) {\n      var mutableSource = workInProgressSources[i];\n\n      {\n        mutableSource._workInProgressVersionPrimary = null;\n      }\n    }\n\n    workInProgressSources.length = 0;\n  }\n  // This ensures that the version used for server rendering matches the one\n  // that is eventually read during hydration.\n  // If they don't match there's a potential tear and a full deopt render is required.\n\n  function registerMutableSourceForHydration(root, mutableSource) {\n    var getVersion = mutableSource._getVersion;\n    var version = getVersion(mutableSource._source); // TODO Clear this data once all pending hydration work is finished.\n    // Retaining it forever may interfere with GC.\n\n    if (root.mutableSourceEagerHydrationData == null) {\n      root.mutableSourceEagerHydrationData = [mutableSource, version];\n    } else {\n      root.mutableSourceEagerHydrationData.push(mutableSource, version);\n    }\n  }\n\n  var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher,\n      ReactCurrentBatchConfig$2 = ReactSharedInternals.ReactCurrentBatchConfig;\n  var didWarnAboutMismatchedHooksForComponent;\n  var didWarnUncachedGetSnapshot;\n\n  {\n    didWarnAboutMismatchedHooksForComponent = new Set();\n  }\n\n  // These are set right before calling the component.\n  var renderLanes = NoLanes; // The work-in-progress fiber. I've named it differently to distinguish it from\n  // the work-in-progress hook.\n\n  var currentlyRenderingFiber$1 = null; // Hooks are stored as a linked list on the fiber's memoizedState field. The\n  // current hook list is the list that belongs to the current fiber. The\n  // work-in-progress hook list is a new list that will be added to the\n  // work-in-progress fiber.\n\n  var currentHook = null;\n  var workInProgressHook = null; // Whether an update was scheduled at any point during the render phase. This\n  // does not get reset if we do another render pass; only when we're completely\n  // finished evaluating this component. This is an optimization so we know\n  // whether we need to clear render phase updates after a throw.\n\n  var didScheduleRenderPhaseUpdate = false; // Where an update was scheduled only during the current render pass. This\n  // gets reset after each attempt.\n  // TODO: Maybe there's some way to consolidate this with\n  // `didScheduleRenderPhaseUpdate`. Or with `numberOfReRenders`.\n\n  var didScheduleRenderPhaseUpdateDuringThisPass = false; // Counts the number of useId hooks in this component.\n\n  var localIdCounter = 0; // Used for ids that are generated completely client-side (i.e. not during\n  // hydration). This counter is global, so client ids are not stable across\n  // render attempts.\n\n  var globalClientIdCounter = 0;\n  var RE_RENDER_LIMIT = 25; // In DEV, this is the name of the currently executing primitive hook\n\n  var currentHookNameInDev = null; // In DEV, this list ensures that hooks are called in the same order between renders.\n  // The list stores the order of hooks used during the initial render (mount).\n  // Subsequent renders (updates) reference this list.\n\n  var hookTypesDev = null;\n  var hookTypesUpdateIndexDev = -1; // In DEV, this tracks whether currently rendering component needs to ignore\n  // the dependencies for Hooks that need them (e.g. useEffect or useMemo).\n  // When true, such Hooks will always be \"remounted\". Only used during hot reload.\n\n  var ignorePreviousDependencies = false;\n\n  function mountHookTypesDev() {\n    {\n      var hookName = currentHookNameInDev;\n\n      if (hookTypesDev === null) {\n        hookTypesDev = [hookName];\n      } else {\n        hookTypesDev.push(hookName);\n      }\n    }\n  }\n\n  function updateHookTypesDev() {\n    {\n      var hookName = currentHookNameInDev;\n\n      if (hookTypesDev !== null) {\n        hookTypesUpdateIndexDev++;\n\n        if (hookTypesDev[hookTypesUpdateIndexDev] !== hookName) {\n          warnOnHookMismatchInDev(hookName);\n        }\n      }\n    }\n  }\n\n  function checkDepsAreArrayDev(deps) {\n    {\n      if (deps !== undefined && deps !== null && !isArray(deps)) {\n        // Verify deps, but only on mount to avoid extra checks.\n        // It's unlikely their type would change as usually you define them inline.\n        error('%s received a final argument that is not an array (instead, received `%s`). When ' + 'specified, the final argument must be an array.', currentHookNameInDev, typeof deps);\n      }\n    }\n  }\n\n  function warnOnHookMismatchInDev(currentHookName) {\n    {\n      var componentName = getComponentNameFromFiber(currentlyRenderingFiber$1);\n\n      if (!didWarnAboutMismatchedHooksForComponent.has(componentName)) {\n        didWarnAboutMismatchedHooksForComponent.add(componentName);\n\n        if (hookTypesDev !== null) {\n          var table = '';\n          var secondColumnStart = 30;\n\n          for (var i = 0; i <= hookTypesUpdateIndexDev; i++) {\n            var oldHookName = hookTypesDev[i];\n            var newHookName = i === hookTypesUpdateIndexDev ? currentHookName : oldHookName;\n            var row = i + 1 + \". \" + oldHookName; // Extra space so second column lines up\n            // lol @ IE not supporting String#repeat\n\n            while (row.length < secondColumnStart) {\n              row += ' ';\n            }\n\n            row += newHookName + '\\n';\n            table += row;\n          }\n\n          error('React has detected a change in the order of Hooks called by %s. ' + 'This will lead to bugs and errors if not fixed. ' + 'For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks\\n\\n' + '   Previous render            Next render\\n' + '   ------------------------------------------------------\\n' + '%s' + '   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n', componentName, table);\n        }\n      }\n    }\n  }\n\n  function throwInvalidHookError() {\n    throw new Error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\\n' + '2. You might be breaking the Rules of Hooks\\n' + '3. You might have more than one copy of React in the same app\\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');\n  }\n\n  function areHookInputsEqual(nextDeps, prevDeps) {\n    {\n      if (ignorePreviousDependencies) {\n        // Only true when this component is being hot reloaded.\n        return false;\n      }\n    }\n\n    if (prevDeps === null) {\n      {\n        error('%s received a final argument during this render, but not during ' + 'the previous render. Even though the final argument is optional, ' + 'its type cannot change between renders.', currentHookNameInDev);\n      }\n\n      return false;\n    }\n\n    {\n      // Don't bother comparing lengths in prod because these arrays should be\n      // passed inline.\n      if (nextDeps.length !== prevDeps.length) {\n        error('The final argument passed to %s changed size between renders. The ' + 'order and size of this array must remain constant.\\n\\n' + 'Previous: %s\\n' + 'Incoming: %s', currentHookNameInDev, \"[\" + prevDeps.join(', ') + \"]\", \"[\" + nextDeps.join(', ') + \"]\");\n      }\n    }\n\n    for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) {\n      if (objectIs(nextDeps[i], prevDeps[i])) {\n        continue;\n      }\n\n      return false;\n    }\n\n    return true;\n  }\n\n  function renderWithHooks(current, workInProgress, Component, props, secondArg, nextRenderLanes) {\n    renderLanes = nextRenderLanes;\n    currentlyRenderingFiber$1 = workInProgress;\n\n    {\n      hookTypesDev = current !== null ? current._debugHookTypes : null;\n      hookTypesUpdateIndexDev = -1; // Used for hot reloading:\n\n      ignorePreviousDependencies = current !== null && current.type !== workInProgress.type;\n    }\n\n    workInProgress.memoizedState = null;\n    workInProgress.updateQueue = null;\n    workInProgress.lanes = NoLanes; // The following should have already been reset\n    // currentHook = null;\n    // workInProgressHook = null;\n    // didScheduleRenderPhaseUpdate = false;\n    // localIdCounter = 0;\n    // TODO Warn if no hooks are used at all during mount, then some are used during update.\n    // Currently we will identify the update render as a mount because memoizedState === null.\n    // This is tricky because it's valid for certain types of components (e.g. React.lazy)\n    // Using memoizedState to differentiate between mount/update only works if at least one stateful hook is used.\n    // Non-stateful hooks (e.g. context) don't get added to memoizedState,\n    // so memoizedState would be null during updates and mounts.\n\n    {\n      if (current !== null && current.memoizedState !== null) {\n        ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdateInDEV;\n      } else if (hookTypesDev !== null) {\n        // This dispatcher handles an edge case where a component is updating,\n        // but no stateful hooks have been used.\n        // We want to match the production code behavior (which will use HooksDispatcherOnMount),\n        // but with the extra DEV validation to ensure hooks ordering hasn't changed.\n        // This dispatcher does that.\n        ReactCurrentDispatcher$1.current = HooksDispatcherOnMountWithHookTypesInDEV;\n      } else {\n        ReactCurrentDispatcher$1.current = HooksDispatcherOnMountInDEV;\n      }\n    }\n\n    var children = Component(props, secondArg); // Check if there was a render phase update\n\n    if (didScheduleRenderPhaseUpdateDuringThisPass) {\n      // Keep rendering in a loop for as long as render phase updates continue to\n      // be scheduled. Use a counter to prevent infinite loops.\n      var numberOfReRenders = 0;\n\n      do {\n        didScheduleRenderPhaseUpdateDuringThisPass = false;\n        localIdCounter = 0;\n\n        if (numberOfReRenders >= RE_RENDER_LIMIT) {\n          throw new Error('Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.');\n        }\n\n        numberOfReRenders += 1;\n\n        {\n          // Even when hot reloading, allow dependencies to stabilize\n          // after first render to prevent infinite render phase updates.\n          ignorePreviousDependencies = false;\n        } // Start over from the beginning of the list\n\n\n        currentHook = null;\n        workInProgressHook = null;\n        workInProgress.updateQueue = null;\n\n        {\n          // Also validate hook order for cascading updates.\n          hookTypesUpdateIndexDev = -1;\n        }\n\n        ReactCurrentDispatcher$1.current =  HooksDispatcherOnRerenderInDEV ;\n        children = Component(props, secondArg);\n      } while (didScheduleRenderPhaseUpdateDuringThisPass);\n    } // We can assume the previous dispatcher is always this one, since we set it\n    // at the beginning of the render phase and there's no re-entrance.\n\n\n    ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;\n\n    {\n      workInProgress._debugHookTypes = hookTypesDev;\n    } // This check uses currentHook so that it works the same in DEV and prod bundles.\n    // hookTypesDev could catch more cases (e.g. context) but only in DEV bundles.\n\n\n    var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;\n    renderLanes = NoLanes;\n    currentlyRenderingFiber$1 = null;\n    currentHook = null;\n    workInProgressHook = null;\n\n    {\n      currentHookNameInDev = null;\n      hookTypesDev = null;\n      hookTypesUpdateIndexDev = -1; // Confirm that a static flag was not added or removed since the last\n      // render. If this fires, it suggests that we incorrectly reset the static\n      // flags in some other part of the codebase. This has happened before, for\n      // example, in the SuspenseList implementation.\n\n      if (current !== null && (current.flags & StaticMask) !== (workInProgress.flags & StaticMask) && // Disable this warning in legacy mode, because legacy Suspense is weird\n      // and creates false positives. To make this work in legacy mode, we'd\n      // need to mark fibers that commit in an incomplete state, somehow. For\n      // now I'll disable the warning that most of the bugs that would trigger\n      // it are either exclusive to concurrent mode or exist in both.\n      (current.mode & ConcurrentMode) !== NoMode) {\n        error('Internal React error: Expected static flag was missing. Please ' + 'notify the React team.');\n      }\n    }\n\n    didScheduleRenderPhaseUpdate = false; // This is reset by checkDidRenderIdHook\n    // localIdCounter = 0;\n\n    if (didRenderTooFewHooks) {\n      throw new Error('Rendered fewer hooks than expected. This may be caused by an accidental ' + 'early return statement.');\n    }\n\n    return children;\n  }\n  function checkDidRenderIdHook() {\n    // This should be called immediately after every renderWithHooks call.\n    // Conceptually, it's part of the return value of renderWithHooks; it's only a\n    // separate function to avoid using an array tuple.\n    var didRenderIdHook = localIdCounter !== 0;\n    localIdCounter = 0;\n    return didRenderIdHook;\n  }\n  function bailoutHooks(current, workInProgress, lanes) {\n    workInProgress.updateQueue = current.updateQueue; // TODO: Don't need to reset the flags here, because they're reset in the\n    // complete phase (bubbleProperties).\n\n    if ( (workInProgress.mode & StrictEffectsMode) !== NoMode) {\n      workInProgress.flags &= ~(MountPassiveDev | MountLayoutDev | Passive | Update);\n    } else {\n      workInProgress.flags &= ~(Passive | Update);\n    }\n\n    current.lanes = removeLanes(current.lanes, lanes);\n  }\n  function resetHooksAfterThrow() {\n    // We can assume the previous dispatcher is always this one, since we set it\n    // at the beginning of the render phase and there's no re-entrance.\n    ReactCurrentDispatcher$1.current = ContextOnlyDispatcher;\n\n    if (didScheduleRenderPhaseUpdate) {\n      // There were render phase updates. These are only valid for this render\n      // phase, which we are now aborting. Remove the updates from the queues so\n      // they do not persist to the next render. Do not remove updates from hooks\n      // that weren't processed.\n      //\n      // Only reset the updates from the queue if it has a clone. If it does\n      // not have a clone, that means it wasn't processed, and the updates were\n      // scheduled before we entered the render phase.\n      var hook = currentlyRenderingFiber$1.memoizedState;\n\n      while (hook !== null) {\n        var queue = hook.queue;\n\n        if (queue !== null) {\n          queue.pending = null;\n        }\n\n        hook = hook.next;\n      }\n\n      didScheduleRenderPhaseUpdate = false;\n    }\n\n    renderLanes = NoLanes;\n    currentlyRenderingFiber$1 = null;\n    currentHook = null;\n    workInProgressHook = null;\n\n    {\n      hookTypesDev = null;\n      hookTypesUpdateIndexDev = -1;\n      currentHookNameInDev = null;\n      isUpdatingOpaqueValueInRenderPhase = false;\n    }\n\n    didScheduleRenderPhaseUpdateDuringThisPass = false;\n    localIdCounter = 0;\n  }\n\n  function mountWorkInProgressHook() {\n    var hook = {\n      memoizedState: null,\n      baseState: null,\n      baseQueue: null,\n      queue: null,\n      next: null\n    };\n\n    if (workInProgressHook === null) {\n      // This is the first hook in the list\n      currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook;\n    } else {\n      // Append to the end of the list\n      workInProgressHook = workInProgressHook.next = hook;\n    }\n\n    return workInProgressHook;\n  }\n\n  function updateWorkInProgressHook() {\n    // This function is used both for updates and for re-renders triggered by a\n    // render phase update. It assumes there is either a current hook we can\n    // clone, or a work-in-progress hook from a previous render pass that we can\n    // use as a base. When we reach the end of the base list, we must switch to\n    // the dispatcher used for mounts.\n    var nextCurrentHook;\n\n    if (currentHook === null) {\n      var current = currentlyRenderingFiber$1.alternate;\n\n      if (current !== null) {\n        nextCurrentHook = current.memoizedState;\n      } else {\n        nextCurrentHook = null;\n      }\n    } else {\n      nextCurrentHook = currentHook.next;\n    }\n\n    var nextWorkInProgressHook;\n\n    if (workInProgressHook === null) {\n      nextWorkInProgressHook = currentlyRenderingFiber$1.memoizedState;\n    } else {\n      nextWorkInProgressHook = workInProgressHook.next;\n    }\n\n    if (nextWorkInProgressHook !== null) {\n      // There's already a work-in-progress. Reuse it.\n      workInProgressHook = nextWorkInProgressHook;\n      nextWorkInProgressHook = workInProgressHook.next;\n      currentHook = nextCurrentHook;\n    } else {\n      // Clone from the current hook.\n      if (nextCurrentHook === null) {\n        throw new Error('Rendered more hooks than during the previous render.');\n      }\n\n      currentHook = nextCurrentHook;\n      var newHook = {\n        memoizedState: currentHook.memoizedState,\n        baseState: currentHook.baseState,\n        baseQueue: currentHook.baseQueue,\n        queue: currentHook.queue,\n        next: null\n      };\n\n      if (workInProgressHook === null) {\n        // This is the first hook in the list.\n        currentlyRenderingFiber$1.memoizedState = workInProgressHook = newHook;\n      } else {\n        // Append to the end of the list.\n        workInProgressHook = workInProgressHook.next = newHook;\n      }\n    }\n\n    return workInProgressHook;\n  }\n\n  function createFunctionComponentUpdateQueue() {\n    return {\n      lastEffect: null,\n      stores: null\n    };\n  }\n\n  function basicStateReducer(state, action) {\n    // $FlowFixMe: Flow doesn't like mixed types\n    return typeof action === 'function' ? action(state) : action;\n  }\n\n  function mountReducer(reducer, initialArg, init) {\n    var hook = mountWorkInProgressHook();\n    var initialState;\n\n    if (init !== undefined) {\n      initialState = init(initialArg);\n    } else {\n      initialState = initialArg;\n    }\n\n    hook.memoizedState = hook.baseState = initialState;\n    var queue = {\n      pending: null,\n      interleaved: null,\n      lanes: NoLanes,\n      dispatch: null,\n      lastRenderedReducer: reducer,\n      lastRenderedState: initialState\n    };\n    hook.queue = queue;\n    var dispatch = queue.dispatch = dispatchReducerAction.bind(null, currentlyRenderingFiber$1, queue);\n    return [hook.memoizedState, dispatch];\n  }\n\n  function updateReducer(reducer, initialArg, init) {\n    var hook = updateWorkInProgressHook();\n    var queue = hook.queue;\n\n    if (queue === null) {\n      throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.');\n    }\n\n    queue.lastRenderedReducer = reducer;\n    var current = currentHook; // The last rebase update that is NOT part of the base state.\n\n    var baseQueue = current.baseQueue; // The last pending update that hasn't been processed yet.\n\n    var pendingQueue = queue.pending;\n\n    if (pendingQueue !== null) {\n      // We have new updates that haven't been processed yet.\n      // We'll add them to the base queue.\n      if (baseQueue !== null) {\n        // Merge the pending queue and the base queue.\n        var baseFirst = baseQueue.next;\n        var pendingFirst = pendingQueue.next;\n        baseQueue.next = pendingFirst;\n        pendingQueue.next = baseFirst;\n      }\n\n      {\n        if (current.baseQueue !== baseQueue) {\n          // Internal invariant that should never happen, but feasibly could in\n          // the future if we implement resuming, or some form of that.\n          error('Internal error: Expected work-in-progress queue to be a clone. ' + 'This is a bug in React.');\n        }\n      }\n\n      current.baseQueue = baseQueue = pendingQueue;\n      queue.pending = null;\n    }\n\n    if (baseQueue !== null) {\n      // We have a queue to process.\n      var first = baseQueue.next;\n      var newState = current.baseState;\n      var newBaseState = null;\n      var newBaseQueueFirst = null;\n      var newBaseQueueLast = null;\n      var update = first;\n\n      do {\n        var updateLane = update.lane;\n\n        if (!isSubsetOfLanes(renderLanes, updateLane)) {\n          // Priority is insufficient. Skip this update. If this is the first\n          // skipped update, the previous update/state is the new base\n          // update/state.\n          var clone = {\n            lane: updateLane,\n            action: update.action,\n            hasEagerState: update.hasEagerState,\n            eagerState: update.eagerState,\n            next: null\n          };\n\n          if (newBaseQueueLast === null) {\n            newBaseQueueFirst = newBaseQueueLast = clone;\n            newBaseState = newState;\n          } else {\n            newBaseQueueLast = newBaseQueueLast.next = clone;\n          } // Update the remaining priority in the queue.\n          // TODO: Don't need to accumulate this. Instead, we can remove\n          // renderLanes from the original lanes.\n\n\n          currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, updateLane);\n          markSkippedUpdateLanes(updateLane);\n        } else {\n          // This update does have sufficient priority.\n          if (newBaseQueueLast !== null) {\n            var _clone = {\n              // This update is going to be committed so we never want uncommit\n              // it. Using NoLane works because 0 is a subset of all bitmasks, so\n              // this will never be skipped by the check above.\n              lane: NoLane,\n              action: update.action,\n              hasEagerState: update.hasEagerState,\n              eagerState: update.eagerState,\n              next: null\n            };\n            newBaseQueueLast = newBaseQueueLast.next = _clone;\n          } // Process this update.\n\n\n          if (update.hasEagerState) {\n            // If this update is a state update (not a reducer) and was processed eagerly,\n            // we can use the eagerly computed state\n            newState = update.eagerState;\n          } else {\n            var action = update.action;\n            newState = reducer(newState, action);\n          }\n        }\n\n        update = update.next;\n      } while (update !== null && update !== first);\n\n      if (newBaseQueueLast === null) {\n        newBaseState = newState;\n      } else {\n        newBaseQueueLast.next = newBaseQueueFirst;\n      } // Mark that the fiber performed work, but only if the new state is\n      // different from the current state.\n\n\n      if (!objectIs(newState, hook.memoizedState)) {\n        markWorkInProgressReceivedUpdate();\n      }\n\n      hook.memoizedState = newState;\n      hook.baseState = newBaseState;\n      hook.baseQueue = newBaseQueueLast;\n      queue.lastRenderedState = newState;\n    } // Interleaved updates are stored on a separate queue. We aren't going to\n    // process them during this render, but we do need to track which lanes\n    // are remaining.\n\n\n    var lastInterleaved = queue.interleaved;\n\n    if (lastInterleaved !== null) {\n      var interleaved = lastInterleaved;\n\n      do {\n        var interleavedLane = interleaved.lane;\n        currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, interleavedLane);\n        markSkippedUpdateLanes(interleavedLane);\n        interleaved = interleaved.next;\n      } while (interleaved !== lastInterleaved);\n    } else if (baseQueue === null) {\n      // `queue.lanes` is used for entangling transitions. We can set it back to\n      // zero once the queue is empty.\n      queue.lanes = NoLanes;\n    }\n\n    var dispatch = queue.dispatch;\n    return [hook.memoizedState, dispatch];\n  }\n\n  function rerenderReducer(reducer, initialArg, init) {\n    var hook = updateWorkInProgressHook();\n    var queue = hook.queue;\n\n    if (queue === null) {\n      throw new Error('Should have a queue. This is likely a bug in React. Please file an issue.');\n    }\n\n    queue.lastRenderedReducer = reducer; // This is a re-render. Apply the new render phase updates to the previous\n    // work-in-progress hook.\n\n    var dispatch = queue.dispatch;\n    var lastRenderPhaseUpdate = queue.pending;\n    var newState = hook.memoizedState;\n\n    if (lastRenderPhaseUpdate !== null) {\n      // The queue doesn't persist past this render pass.\n      queue.pending = null;\n      var firstRenderPhaseUpdate = lastRenderPhaseUpdate.next;\n      var update = firstRenderPhaseUpdate;\n\n      do {\n        // Process this render phase update. We don't have to check the\n        // priority because it will always be the same as the current\n        // render's.\n        var action = update.action;\n        newState = reducer(newState, action);\n        update = update.next;\n      } while (update !== firstRenderPhaseUpdate); // Mark that the fiber performed work, but only if the new state is\n      // different from the current state.\n\n\n      if (!objectIs(newState, hook.memoizedState)) {\n        markWorkInProgressReceivedUpdate();\n      }\n\n      hook.memoizedState = newState; // Don't persist the state accumulated from the render phase updates to\n      // the base state unless the queue is empty.\n      // TODO: Not sure if this is the desired semantics, but it's what we\n      // do for gDSFP. I can't remember why.\n\n      if (hook.baseQueue === null) {\n        hook.baseState = newState;\n      }\n\n      queue.lastRenderedState = newState;\n    }\n\n    return [newState, dispatch];\n  }\n\n  function mountMutableSource(source, getSnapshot, subscribe) {\n    {\n      return undefined;\n    }\n  }\n\n  function updateMutableSource(source, getSnapshot, subscribe) {\n    {\n      return undefined;\n    }\n  }\n\n  function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {\n    var fiber = currentlyRenderingFiber$1;\n    var hook = mountWorkInProgressHook();\n    var nextSnapshot;\n    var isHydrating = getIsHydrating();\n\n    if (isHydrating) {\n      if (getServerSnapshot === undefined) {\n        throw new Error('Missing getServerSnapshot, which is required for ' + 'server-rendered content. Will revert to client rendering.');\n      }\n\n      nextSnapshot = getServerSnapshot();\n\n      {\n        if (!didWarnUncachedGetSnapshot) {\n          if (nextSnapshot !== getServerSnapshot()) {\n            error('The result of getServerSnapshot should be cached to avoid an infinite loop');\n\n            didWarnUncachedGetSnapshot = true;\n          }\n        }\n      }\n    } else {\n      nextSnapshot = getSnapshot();\n\n      {\n        if (!didWarnUncachedGetSnapshot) {\n          var cachedSnapshot = getSnapshot();\n\n          if (!objectIs(nextSnapshot, cachedSnapshot)) {\n            error('The result of getSnapshot should be cached to avoid an infinite loop');\n\n            didWarnUncachedGetSnapshot = true;\n          }\n        }\n      } // Unless we're rendering a blocking lane, schedule a consistency check.\n      // Right before committing, we will walk the tree and check if any of the\n      // stores were mutated.\n      //\n      // We won't do this if we're hydrating server-rendered content, because if\n      // the content is stale, it's already visible anyway. Instead we'll patch\n      // it up in a passive effect.\n\n\n      var root = getWorkInProgressRoot();\n\n      if (root === null) {\n        throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.');\n      }\n\n      if (!includesBlockingLane(root, renderLanes)) {\n        pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot);\n      }\n    } // Read the current snapshot from the store on every render. This breaks the\n    // normal rules of React, and only works because store updates are\n    // always synchronous.\n\n\n    hook.memoizedState = nextSnapshot;\n    var inst = {\n      value: nextSnapshot,\n      getSnapshot: getSnapshot\n    };\n    hook.queue = inst; // Schedule an effect to subscribe to the store.\n\n    mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [subscribe]); // Schedule an effect to update the mutable instance fields. We will update\n    // this whenever subscribe, getSnapshot, or value changes. Because there's no\n    // clean-up function, and we track the deps correctly, we can call pushEffect\n    // directly, without storing any additional state. For the same reason, we\n    // don't need to set a static flag, either.\n    // TODO: We can move this to the passive phase once we add a pre-commit\n    // consistency check. See the next comment.\n\n    fiber.flags |= Passive;\n    pushEffect(HasEffect | Passive$1, updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), undefined, null);\n    return nextSnapshot;\n  }\n\n  function updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {\n    var fiber = currentlyRenderingFiber$1;\n    var hook = updateWorkInProgressHook(); // Read the current snapshot from the store on every render. This breaks the\n    // normal rules of React, and only works because store updates are\n    // always synchronous.\n\n    var nextSnapshot = getSnapshot();\n\n    {\n      if (!didWarnUncachedGetSnapshot) {\n        var cachedSnapshot = getSnapshot();\n\n        if (!objectIs(nextSnapshot, cachedSnapshot)) {\n          error('The result of getSnapshot should be cached to avoid an infinite loop');\n\n          didWarnUncachedGetSnapshot = true;\n        }\n      }\n    }\n\n    var prevSnapshot = hook.memoizedState;\n    var snapshotChanged = !objectIs(prevSnapshot, nextSnapshot);\n\n    if (snapshotChanged) {\n      hook.memoizedState = nextSnapshot;\n      markWorkInProgressReceivedUpdate();\n    }\n\n    var inst = hook.queue;\n    updateEffect(subscribeToStore.bind(null, fiber, inst, subscribe), [subscribe]); // Whenever getSnapshot or subscribe changes, we need to check in the\n    // commit phase if there was an interleaved mutation. In concurrent mode\n    // this can happen all the time, but even in synchronous mode, an earlier\n    // effect may have mutated the store.\n\n    if (inst.getSnapshot !== getSnapshot || snapshotChanged || // Check if the susbcribe function changed. We can save some memory by\n    // checking whether we scheduled a subscription effect above.\n    workInProgressHook !== null && workInProgressHook.memoizedState.tag & HasEffect) {\n      fiber.flags |= Passive;\n      pushEffect(HasEffect | Passive$1, updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), undefined, null); // Unless we're rendering a blocking lane, schedule a consistency check.\n      // Right before committing, we will walk the tree and check if any of the\n      // stores were mutated.\n\n      var root = getWorkInProgressRoot();\n\n      if (root === null) {\n        throw new Error('Expected a work-in-progress root. This is a bug in React. Please file an issue.');\n      }\n\n      if (!includesBlockingLane(root, renderLanes)) {\n        pushStoreConsistencyCheck(fiber, getSnapshot, nextSnapshot);\n      }\n    }\n\n    return nextSnapshot;\n  }\n\n  function pushStoreConsistencyCheck(fiber, getSnapshot, renderedSnapshot) {\n    fiber.flags |= StoreConsistency;\n    var check = {\n      getSnapshot: getSnapshot,\n      value: renderedSnapshot\n    };\n    var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue;\n\n    if (componentUpdateQueue === null) {\n      componentUpdateQueue = createFunctionComponentUpdateQueue();\n      currentlyRenderingFiber$1.updateQueue = componentUpdateQueue;\n      componentUpdateQueue.stores = [check];\n    } else {\n      var stores = componentUpdateQueue.stores;\n\n      if (stores === null) {\n        componentUpdateQueue.stores = [check];\n      } else {\n        stores.push(check);\n      }\n    }\n  }\n\n  function updateStoreInstance(fiber, inst, nextSnapshot, getSnapshot) {\n    // These are updated in the passive phase\n    inst.value = nextSnapshot;\n    inst.getSnapshot = getSnapshot; // Something may have been mutated in between render and commit. This could\n    // have been in an event that fired before the passive effects, or it could\n    // have been in a layout effect. In that case, we would have used the old\n    // snapsho and getSnapshot values to bail out. We need to check one more time.\n\n    if (checkIfSnapshotChanged(inst)) {\n      // Force a re-render.\n      forceStoreRerender(fiber);\n    }\n  }\n\n  function subscribeToStore(fiber, inst, subscribe) {\n    var handleStoreChange = function () {\n      // The store changed. Check if the snapshot changed since the last time we\n      // read from the store.\n      if (checkIfSnapshotChanged(inst)) {\n        // Force a re-render.\n        forceStoreRerender(fiber);\n      }\n    }; // Subscribe to the store and return a clean-up function.\n\n\n    return subscribe(handleStoreChange);\n  }\n\n  function checkIfSnapshotChanged(inst) {\n    var latestGetSnapshot = inst.getSnapshot;\n    var prevValue = inst.value;\n\n    try {\n      var nextValue = latestGetSnapshot();\n      return !objectIs(prevValue, nextValue);\n    } catch (error) {\n      return true;\n    }\n  }\n\n  function forceStoreRerender(fiber) {\n    var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n    if (root !== null) {\n      scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n    }\n  }\n\n  function mountState(initialState) {\n    var hook = mountWorkInProgressHook();\n\n    if (typeof initialState === 'function') {\n      // $FlowFixMe: Flow doesn't like mixed types\n      initialState = initialState();\n    }\n\n    hook.memoizedState = hook.baseState = initialState;\n    var queue = {\n      pending: null,\n      interleaved: null,\n      lanes: NoLanes,\n      dispatch: null,\n      lastRenderedReducer: basicStateReducer,\n      lastRenderedState: initialState\n    };\n    hook.queue = queue;\n    var dispatch = queue.dispatch = dispatchSetState.bind(null, currentlyRenderingFiber$1, queue);\n    return [hook.memoizedState, dispatch];\n  }\n\n  function updateState(initialState) {\n    return updateReducer(basicStateReducer);\n  }\n\n  function rerenderState(initialState) {\n    return rerenderReducer(basicStateReducer);\n  }\n\n  function pushEffect(tag, create, destroy, deps) {\n    var effect = {\n      tag: tag,\n      create: create,\n      destroy: destroy,\n      deps: deps,\n      // Circular\n      next: null\n    };\n    var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue;\n\n    if (componentUpdateQueue === null) {\n      componentUpdateQueue = createFunctionComponentUpdateQueue();\n      currentlyRenderingFiber$1.updateQueue = componentUpdateQueue;\n      componentUpdateQueue.lastEffect = effect.next = effect;\n    } else {\n      var lastEffect = componentUpdateQueue.lastEffect;\n\n      if (lastEffect === null) {\n        componentUpdateQueue.lastEffect = effect.next = effect;\n      } else {\n        var firstEffect = lastEffect.next;\n        lastEffect.next = effect;\n        effect.next = firstEffect;\n        componentUpdateQueue.lastEffect = effect;\n      }\n    }\n\n    return effect;\n  }\n\n  function mountRef(initialValue) {\n    var hook = mountWorkInProgressHook();\n\n    {\n      var _ref2 = {\n        current: initialValue\n      };\n      hook.memoizedState = _ref2;\n      return _ref2;\n    }\n  }\n\n  function updateRef(initialValue) {\n    var hook = updateWorkInProgressHook();\n    return hook.memoizedState;\n  }\n\n  function mountEffectImpl(fiberFlags, hookFlags, create, deps) {\n    var hook = mountWorkInProgressHook();\n    var nextDeps = deps === undefined ? null : deps;\n    currentlyRenderingFiber$1.flags |= fiberFlags;\n    hook.memoizedState = pushEffect(HasEffect | hookFlags, create, undefined, nextDeps);\n  }\n\n  function updateEffectImpl(fiberFlags, hookFlags, create, deps) {\n    var hook = updateWorkInProgressHook();\n    var nextDeps = deps === undefined ? null : deps;\n    var destroy = undefined;\n\n    if (currentHook !== null) {\n      var prevEffect = currentHook.memoizedState;\n      destroy = prevEffect.destroy;\n\n      if (nextDeps !== null) {\n        var prevDeps = prevEffect.deps;\n\n        if (areHookInputsEqual(nextDeps, prevDeps)) {\n          hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps);\n          return;\n        }\n      }\n    }\n\n    currentlyRenderingFiber$1.flags |= fiberFlags;\n    hook.memoizedState = pushEffect(HasEffect | hookFlags, create, destroy, nextDeps);\n  }\n\n  function mountEffect(create, deps) {\n    if ( (currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) {\n      return mountEffectImpl(MountPassiveDev | Passive | PassiveStatic, Passive$1, create, deps);\n    } else {\n      return mountEffectImpl(Passive | PassiveStatic, Passive$1, create, deps);\n    }\n  }\n\n  function updateEffect(create, deps) {\n    return updateEffectImpl(Passive, Passive$1, create, deps);\n  }\n\n  function mountInsertionEffect(create, deps) {\n    return mountEffectImpl(Update, Insertion, create, deps);\n  }\n\n  function updateInsertionEffect(create, deps) {\n    return updateEffectImpl(Update, Insertion, create, deps);\n  }\n\n  function mountLayoutEffect(create, deps) {\n    var fiberFlags = Update;\n\n    {\n      fiberFlags |= LayoutStatic;\n    }\n\n    if ( (currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) {\n      fiberFlags |= MountLayoutDev;\n    }\n\n    return mountEffectImpl(fiberFlags, Layout, create, deps);\n  }\n\n  function updateLayoutEffect(create, deps) {\n    return updateEffectImpl(Update, Layout, create, deps);\n  }\n\n  function imperativeHandleEffect(create, ref) {\n    if (typeof ref === 'function') {\n      var refCallback = ref;\n\n      var _inst = create();\n\n      refCallback(_inst);\n      return function () {\n        refCallback(null);\n      };\n    } else if (ref !== null && ref !== undefined) {\n      var refObject = ref;\n\n      {\n        if (!refObject.hasOwnProperty('current')) {\n          error('Expected useImperativeHandle() first argument to either be a ' + 'ref callback or React.createRef() object. Instead received: %s.', 'an object with keys {' + Object.keys(refObject).join(', ') + '}');\n        }\n      }\n\n      var _inst2 = create();\n\n      refObject.current = _inst2;\n      return function () {\n        refObject.current = null;\n      };\n    }\n  }\n\n  function mountImperativeHandle(ref, create, deps) {\n    {\n      if (typeof create !== 'function') {\n        error('Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: %s.', create !== null ? typeof create : 'null');\n      }\n    } // TODO: If deps are provided, should we skip comparing the ref itself?\n\n\n    var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null;\n    var fiberFlags = Update;\n\n    {\n      fiberFlags |= LayoutStatic;\n    }\n\n    if ( (currentlyRenderingFiber$1.mode & StrictEffectsMode) !== NoMode) {\n      fiberFlags |= MountLayoutDev;\n    }\n\n    return mountEffectImpl(fiberFlags, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps);\n  }\n\n  function updateImperativeHandle(ref, create, deps) {\n    {\n      if (typeof create !== 'function') {\n        error('Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: %s.', create !== null ? typeof create : 'null');\n      }\n    } // TODO: If deps are provided, should we skip comparing the ref itself?\n\n\n    var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null;\n    return updateEffectImpl(Update, Layout, imperativeHandleEffect.bind(null, create, ref), effectDeps);\n  }\n\n  function mountDebugValue(value, formatterFn) {// This hook is normally a no-op.\n    // The react-debug-hooks package injects its own implementation\n    // so that e.g. DevTools can display custom hook values.\n  }\n\n  var updateDebugValue = mountDebugValue;\n\n  function mountCallback(callback, deps) {\n    var hook = mountWorkInProgressHook();\n    var nextDeps = deps === undefined ? null : deps;\n    hook.memoizedState = [callback, nextDeps];\n    return callback;\n  }\n\n  function updateCallback(callback, deps) {\n    var hook = updateWorkInProgressHook();\n    var nextDeps = deps === undefined ? null : deps;\n    var prevState = hook.memoizedState;\n\n    if (prevState !== null) {\n      if (nextDeps !== null) {\n        var prevDeps = prevState[1];\n\n        if (areHookInputsEqual(nextDeps, prevDeps)) {\n          return prevState[0];\n        }\n      }\n    }\n\n    hook.memoizedState = [callback, nextDeps];\n    return callback;\n  }\n\n  function mountMemo(nextCreate, deps) {\n    var hook = mountWorkInProgressHook();\n    var nextDeps = deps === undefined ? null : deps;\n    var nextValue = nextCreate();\n    hook.memoizedState = [nextValue, nextDeps];\n    return nextValue;\n  }\n\n  function updateMemo(nextCreate, deps) {\n    var hook = updateWorkInProgressHook();\n    var nextDeps = deps === undefined ? null : deps;\n    var prevState = hook.memoizedState;\n\n    if (prevState !== null) {\n      // Assume these are defined. If they're not, areHookInputsEqual will warn.\n      if (nextDeps !== null) {\n        var prevDeps = prevState[1];\n\n        if (areHookInputsEqual(nextDeps, prevDeps)) {\n          return prevState[0];\n        }\n      }\n    }\n\n    var nextValue = nextCreate();\n    hook.memoizedState = [nextValue, nextDeps];\n    return nextValue;\n  }\n\n  function mountDeferredValue(value) {\n    var hook = mountWorkInProgressHook();\n    hook.memoizedState = value;\n    return value;\n  }\n\n  function updateDeferredValue(value) {\n    var hook = updateWorkInProgressHook();\n    var resolvedCurrentHook = currentHook;\n    var prevValue = resolvedCurrentHook.memoizedState;\n    return updateDeferredValueImpl(hook, prevValue, value);\n  }\n\n  function rerenderDeferredValue(value) {\n    var hook = updateWorkInProgressHook();\n\n    if (currentHook === null) {\n      // This is a rerender during a mount.\n      hook.memoizedState = value;\n      return value;\n    } else {\n      // This is a rerender during an update.\n      var prevValue = currentHook.memoizedState;\n      return updateDeferredValueImpl(hook, prevValue, value);\n    }\n  }\n\n  function updateDeferredValueImpl(hook, prevValue, value) {\n    var shouldDeferValue = !includesOnlyNonUrgentLanes(renderLanes);\n\n    if (shouldDeferValue) {\n      // This is an urgent update. If the value has changed, keep using the\n      // previous value and spawn a deferred render to update it later.\n      if (!objectIs(value, prevValue)) {\n        // Schedule a deferred render\n        var deferredLane = claimNextTransitionLane();\n        currentlyRenderingFiber$1.lanes = mergeLanes(currentlyRenderingFiber$1.lanes, deferredLane);\n        markSkippedUpdateLanes(deferredLane); // Set this to true to indicate that the rendered value is inconsistent\n        // from the latest value. The name \"baseState\" doesn't really match how we\n        // use it because we're reusing a state hook field instead of creating a\n        // new one.\n\n        hook.baseState = true;\n      } // Reuse the previous value\n\n\n      return prevValue;\n    } else {\n      // This is not an urgent update, so we can use the latest value regardless\n      // of what it is. No need to defer it.\n      // However, if we're currently inside a spawned render, then we need to mark\n      // this as an update to prevent the fiber from bailing out.\n      //\n      // `baseState` is true when the current value is different from the rendered\n      // value. The name doesn't really match how we use it because we're reusing\n      // a state hook field instead of creating a new one.\n      if (hook.baseState) {\n        // Flip this back to false.\n        hook.baseState = false;\n        markWorkInProgressReceivedUpdate();\n      }\n\n      hook.memoizedState = value;\n      return value;\n    }\n  }\n\n  function startTransition(setPending, callback, options) {\n    var previousPriority = getCurrentUpdatePriority();\n    setCurrentUpdatePriority(higherEventPriority(previousPriority, ContinuousEventPriority));\n    setPending(true);\n    var prevTransition = ReactCurrentBatchConfig$2.transition;\n    ReactCurrentBatchConfig$2.transition = {};\n    var currentTransition = ReactCurrentBatchConfig$2.transition;\n\n    {\n      ReactCurrentBatchConfig$2.transition._updatedFibers = new Set();\n    }\n\n    try {\n      setPending(false);\n      callback();\n    } finally {\n      setCurrentUpdatePriority(previousPriority);\n      ReactCurrentBatchConfig$2.transition = prevTransition;\n\n      {\n        if (prevTransition === null && currentTransition._updatedFibers) {\n          var updatedFibersCount = currentTransition._updatedFibers.size;\n\n          if (updatedFibersCount > 10) {\n            warn('Detected a large number of updates inside startTransition. ' + 'If this is due to a subscription please re-write it to use React provided hooks. ' + 'Otherwise concurrent mode guarantees are off the table.');\n          }\n\n          currentTransition._updatedFibers.clear();\n        }\n      }\n    }\n  }\n\n  function mountTransition() {\n    var _mountState = mountState(false),\n        isPending = _mountState[0],\n        setPending = _mountState[1]; // The `start` method never changes.\n\n\n    var start = startTransition.bind(null, setPending);\n    var hook = mountWorkInProgressHook();\n    hook.memoizedState = start;\n    return [isPending, start];\n  }\n\n  function updateTransition() {\n    var _updateState = updateState(),\n        isPending = _updateState[0];\n\n    var hook = updateWorkInProgressHook();\n    var start = hook.memoizedState;\n    return [isPending, start];\n  }\n\n  function rerenderTransition() {\n    var _rerenderState = rerenderState(),\n        isPending = _rerenderState[0];\n\n    var hook = updateWorkInProgressHook();\n    var start = hook.memoizedState;\n    return [isPending, start];\n  }\n\n  var isUpdatingOpaqueValueInRenderPhase = false;\n  function getIsUpdatingOpaqueValueInRenderPhaseInDEV() {\n    {\n      return isUpdatingOpaqueValueInRenderPhase;\n    }\n  }\n\n  function mountId() {\n    var hook = mountWorkInProgressHook();\n    var root = getWorkInProgressRoot(); // TODO: In Fizz, id generation is specific to each server config. Maybe we\n    // should do this in Fiber, too? Deferring this decision for now because\n    // there's no other place to store the prefix except for an internal field on\n    // the public createRoot object, which the fiber tree does not currently have\n    // a reference to.\n\n    var identifierPrefix = root.identifierPrefix;\n    var id;\n\n    if (getIsHydrating()) {\n      var treeId = getTreeId(); // Use a captial R prefix for server-generated ids.\n\n      id = ':' + identifierPrefix + 'R' + treeId; // Unless this is the first id at this level, append a number at the end\n      // that represents the position of this useId hook among all the useId\n      // hooks for this fiber.\n\n      var localId = localIdCounter++;\n\n      if (localId > 0) {\n        id += 'H' + localId.toString(32);\n      }\n\n      id += ':';\n    } else {\n      // Use a lowercase r prefix for client-generated ids.\n      var globalClientId = globalClientIdCounter++;\n      id = ':' + identifierPrefix + 'r' + globalClientId.toString(32) + ':';\n    }\n\n    hook.memoizedState = id;\n    return id;\n  }\n\n  function updateId() {\n    var hook = updateWorkInProgressHook();\n    var id = hook.memoizedState;\n    return id;\n  }\n\n  function dispatchReducerAction(fiber, queue, action) {\n    {\n      if (typeof arguments[3] === 'function') {\n        error(\"State updates from the useState() and useReducer() Hooks don't support the \" + 'second callback argument. To execute a side effect after ' + 'rendering, declare it in the component body with useEffect().');\n      }\n    }\n\n    var lane = requestUpdateLane(fiber);\n    var update = {\n      lane: lane,\n      action: action,\n      hasEagerState: false,\n      eagerState: null,\n      next: null\n    };\n\n    if (isRenderPhaseUpdate(fiber)) {\n      enqueueRenderPhaseUpdate(queue, update);\n    } else {\n      var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);\n\n      if (root !== null) {\n        var eventTime = requestEventTime();\n        scheduleUpdateOnFiber(root, fiber, lane, eventTime);\n        entangleTransitionUpdate(root, queue, lane);\n      }\n    }\n\n    markUpdateInDevTools(fiber, lane);\n  }\n\n  function dispatchSetState(fiber, queue, action) {\n    {\n      if (typeof arguments[3] === 'function') {\n        error(\"State updates from the useState() and useReducer() Hooks don't support the \" + 'second callback argument. To execute a side effect after ' + 'rendering, declare it in the component body with useEffect().');\n      }\n    }\n\n    var lane = requestUpdateLane(fiber);\n    var update = {\n      lane: lane,\n      action: action,\n      hasEagerState: false,\n      eagerState: null,\n      next: null\n    };\n\n    if (isRenderPhaseUpdate(fiber)) {\n      enqueueRenderPhaseUpdate(queue, update);\n    } else {\n      var alternate = fiber.alternate;\n\n      if (fiber.lanes === NoLanes && (alternate === null || alternate.lanes === NoLanes)) {\n        // The queue is currently empty, which means we can eagerly compute the\n        // next state before entering the render phase. If the new state is the\n        // same as the current state, we may be able to bail out entirely.\n        var lastRenderedReducer = queue.lastRenderedReducer;\n\n        if (lastRenderedReducer !== null) {\n          var prevDispatcher;\n\n          {\n            prevDispatcher = ReactCurrentDispatcher$1.current;\n            ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n          }\n\n          try {\n            var currentState = queue.lastRenderedState;\n            var eagerState = lastRenderedReducer(currentState, action); // Stash the eagerly computed state, and the reducer used to compute\n            // it, on the update object. If the reducer hasn't changed by the\n            // time we enter the render phase, then the eager state can be used\n            // without calling the reducer again.\n\n            update.hasEagerState = true;\n            update.eagerState = eagerState;\n\n            if (objectIs(eagerState, currentState)) {\n              // Fast path. We can bail out without scheduling React to re-render.\n              // It's still possible that we'll need to rebase this update later,\n              // if the component re-renders for a different reason and by that\n              // time the reducer has changed.\n              // TODO: Do we still need to entangle transitions in this case?\n              enqueueConcurrentHookUpdateAndEagerlyBailout(fiber, queue, update, lane);\n              return;\n            }\n          } catch (error) {// Suppress the error. It will throw again in the render phase.\n          } finally {\n            {\n              ReactCurrentDispatcher$1.current = prevDispatcher;\n            }\n          }\n        }\n      }\n\n      var root = enqueueConcurrentHookUpdate(fiber, queue, update, lane);\n\n      if (root !== null) {\n        var eventTime = requestEventTime();\n        scheduleUpdateOnFiber(root, fiber, lane, eventTime);\n        entangleTransitionUpdate(root, queue, lane);\n      }\n    }\n\n    markUpdateInDevTools(fiber, lane);\n  }\n\n  function isRenderPhaseUpdate(fiber) {\n    var alternate = fiber.alternate;\n    return fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1;\n  }\n\n  function enqueueRenderPhaseUpdate(queue, update) {\n    // This is a render phase update. Stash it in a lazily-created map of\n    // queue -> linked list of updates. After this render pass, we'll restart\n    // and apply the stashed updates on top of the work-in-progress hook.\n    didScheduleRenderPhaseUpdateDuringThisPass = didScheduleRenderPhaseUpdate = true;\n    var pending = queue.pending;\n\n    if (pending === null) {\n      // This is the first update. Create a circular list.\n      update.next = update;\n    } else {\n      update.next = pending.next;\n      pending.next = update;\n    }\n\n    queue.pending = update;\n  } // TODO: Move to ReactFiberConcurrentUpdates?\n\n\n  function entangleTransitionUpdate(root, queue, lane) {\n    if (isTransitionLane(lane)) {\n      var queueLanes = queue.lanes; // If any entangled lanes are no longer pending on the root, then they\n      // must have finished. We can remove them from the shared queue, which\n      // represents a superset of the actually pending lanes. In some cases we\n      // may entangle more than we need to, but that's OK. In fact it's worse if\n      // we *don't* entangle when we should.\n\n      queueLanes = intersectLanes(queueLanes, root.pendingLanes); // Entangle the new transition lane with the other transition lanes.\n\n      var newQueueLanes = mergeLanes(queueLanes, lane);\n      queue.lanes = newQueueLanes; // Even if queue.lanes already include lane, we don't know for certain if\n      // the lane finished since the last time we entangled it. So we need to\n      // entangle it again, just to be sure.\n\n      markRootEntangled(root, newQueueLanes);\n    }\n  }\n\n  function markUpdateInDevTools(fiber, lane, action) {\n\n    {\n      markStateUpdateScheduled(fiber, lane);\n    }\n  }\n\n  var ContextOnlyDispatcher = {\n    readContext: readContext,\n    useCallback: throwInvalidHookError,\n    useContext: throwInvalidHookError,\n    useEffect: throwInvalidHookError,\n    useImperativeHandle: throwInvalidHookError,\n    useInsertionEffect: throwInvalidHookError,\n    useLayoutEffect: throwInvalidHookError,\n    useMemo: throwInvalidHookError,\n    useReducer: throwInvalidHookError,\n    useRef: throwInvalidHookError,\n    useState: throwInvalidHookError,\n    useDebugValue: throwInvalidHookError,\n    useDeferredValue: throwInvalidHookError,\n    useTransition: throwInvalidHookError,\n    useMutableSource: throwInvalidHookError,\n    useSyncExternalStore: throwInvalidHookError,\n    useId: throwInvalidHookError,\n    unstable_isNewReconciler: enableNewReconciler\n  };\n\n  var HooksDispatcherOnMountInDEV = null;\n  var HooksDispatcherOnMountWithHookTypesInDEV = null;\n  var HooksDispatcherOnUpdateInDEV = null;\n  var HooksDispatcherOnRerenderInDEV = null;\n  var InvalidNestedHooksDispatcherOnMountInDEV = null;\n  var InvalidNestedHooksDispatcherOnUpdateInDEV = null;\n  var InvalidNestedHooksDispatcherOnRerenderInDEV = null;\n\n  {\n    var warnInvalidContextAccess = function () {\n      error('Context can only be read while React is rendering. ' + 'In classes, you can read it in the render method or getDerivedStateFromProps. ' + 'In function components, you can read it directly in the function body, but not ' + 'inside Hooks like useReducer() or useMemo().');\n    };\n\n    var warnInvalidHookAccess = function () {\n      error('Do not call Hooks inside useEffect(...), useMemo(...), or other built-in Hooks. ' + 'You can only call Hooks at the top level of your React function. ' + 'For more information, see ' + 'https://reactjs.org/link/rules-of-hooks');\n    };\n\n    HooksDispatcherOnMountInDEV = {\n      readContext: function (context) {\n        return readContext(context);\n      },\n      useCallback: function (callback, deps) {\n        currentHookNameInDev = 'useCallback';\n        mountHookTypesDev();\n        checkDepsAreArrayDev(deps);\n        return mountCallback(callback, deps);\n      },\n      useContext: function (context) {\n        currentHookNameInDev = 'useContext';\n        mountHookTypesDev();\n        return readContext(context);\n      },\n      useEffect: function (create, deps) {\n        currentHookNameInDev = 'useEffect';\n        mountHookTypesDev();\n        checkDepsAreArrayDev(deps);\n        return mountEffect(create, deps);\n      },\n      useImperativeHandle: function (ref, create, deps) {\n        currentHookNameInDev = 'useImperativeHandle';\n        mountHookTypesDev();\n        checkDepsAreArrayDev(deps);\n        return mountImperativeHandle(ref, create, deps);\n      },\n      useInsertionEffect: function (create, deps) {\n        currentHookNameInDev = 'useInsertionEffect';\n        mountHookTypesDev();\n        checkDepsAreArrayDev(deps);\n        return mountInsertionEffect(create, deps);\n      },\n      useLayoutEffect: function (create, deps) {\n        currentHookNameInDev = 'useLayoutEffect';\n        mountHookTypesDev();\n        checkDepsAreArrayDev(deps);\n        return mountLayoutEffect(create, deps);\n      },\n      useMemo: function (create, deps) {\n        currentHookNameInDev = 'useMemo';\n        mountHookTypesDev();\n        checkDepsAreArrayDev(deps);\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountMemo(create, deps);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useReducer: function (reducer, initialArg, init) {\n        currentHookNameInDev = 'useReducer';\n        mountHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountReducer(reducer, initialArg, init);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useRef: function (initialValue) {\n        currentHookNameInDev = 'useRef';\n        mountHookTypesDev();\n        return mountRef(initialValue);\n      },\n      useState: function (initialState) {\n        currentHookNameInDev = 'useState';\n        mountHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountState(initialState);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useDebugValue: function (value, formatterFn) {\n        currentHookNameInDev = 'useDebugValue';\n        mountHookTypesDev();\n        return mountDebugValue();\n      },\n      useDeferredValue: function (value) {\n        currentHookNameInDev = 'useDeferredValue';\n        mountHookTypesDev();\n        return mountDeferredValue(value);\n      },\n      useTransition: function () {\n        currentHookNameInDev = 'useTransition';\n        mountHookTypesDev();\n        return mountTransition();\n      },\n      useMutableSource: function (source, getSnapshot, subscribe) {\n        currentHookNameInDev = 'useMutableSource';\n        mountHookTypesDev();\n        return mountMutableSource();\n      },\n      useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n        currentHookNameInDev = 'useSyncExternalStore';\n        mountHookTypesDev();\n        return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n      },\n      useId: function () {\n        currentHookNameInDev = 'useId';\n        mountHookTypesDev();\n        return mountId();\n      },\n      unstable_isNewReconciler: enableNewReconciler\n    };\n\n    HooksDispatcherOnMountWithHookTypesInDEV = {\n      readContext: function (context) {\n        return readContext(context);\n      },\n      useCallback: function (callback, deps) {\n        currentHookNameInDev = 'useCallback';\n        updateHookTypesDev();\n        return mountCallback(callback, deps);\n      },\n      useContext: function (context) {\n        currentHookNameInDev = 'useContext';\n        updateHookTypesDev();\n        return readContext(context);\n      },\n      useEffect: function (create, deps) {\n        currentHookNameInDev = 'useEffect';\n        updateHookTypesDev();\n        return mountEffect(create, deps);\n      },\n      useImperativeHandle: function (ref, create, deps) {\n        currentHookNameInDev = 'useImperativeHandle';\n        updateHookTypesDev();\n        return mountImperativeHandle(ref, create, deps);\n      },\n      useInsertionEffect: function (create, deps) {\n        currentHookNameInDev = 'useInsertionEffect';\n        updateHookTypesDev();\n        return mountInsertionEffect(create, deps);\n      },\n      useLayoutEffect: function (create, deps) {\n        currentHookNameInDev = 'useLayoutEffect';\n        updateHookTypesDev();\n        return mountLayoutEffect(create, deps);\n      },\n      useMemo: function (create, deps) {\n        currentHookNameInDev = 'useMemo';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountMemo(create, deps);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useReducer: function (reducer, initialArg, init) {\n        currentHookNameInDev = 'useReducer';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountReducer(reducer, initialArg, init);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useRef: function (initialValue) {\n        currentHookNameInDev = 'useRef';\n        updateHookTypesDev();\n        return mountRef(initialValue);\n      },\n      useState: function (initialState) {\n        currentHookNameInDev = 'useState';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountState(initialState);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useDebugValue: function (value, formatterFn) {\n        currentHookNameInDev = 'useDebugValue';\n        updateHookTypesDev();\n        return mountDebugValue();\n      },\n      useDeferredValue: function (value) {\n        currentHookNameInDev = 'useDeferredValue';\n        updateHookTypesDev();\n        return mountDeferredValue(value);\n      },\n      useTransition: function () {\n        currentHookNameInDev = 'useTransition';\n        updateHookTypesDev();\n        return mountTransition();\n      },\n      useMutableSource: function (source, getSnapshot, subscribe) {\n        currentHookNameInDev = 'useMutableSource';\n        updateHookTypesDev();\n        return mountMutableSource();\n      },\n      useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n        currentHookNameInDev = 'useSyncExternalStore';\n        updateHookTypesDev();\n        return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n      },\n      useId: function () {\n        currentHookNameInDev = 'useId';\n        updateHookTypesDev();\n        return mountId();\n      },\n      unstable_isNewReconciler: enableNewReconciler\n    };\n\n    HooksDispatcherOnUpdateInDEV = {\n      readContext: function (context) {\n        return readContext(context);\n      },\n      useCallback: function (callback, deps) {\n        currentHookNameInDev = 'useCallback';\n        updateHookTypesDev();\n        return updateCallback(callback, deps);\n      },\n      useContext: function (context) {\n        currentHookNameInDev = 'useContext';\n        updateHookTypesDev();\n        return readContext(context);\n      },\n      useEffect: function (create, deps) {\n        currentHookNameInDev = 'useEffect';\n        updateHookTypesDev();\n        return updateEffect(create, deps);\n      },\n      useImperativeHandle: function (ref, create, deps) {\n        currentHookNameInDev = 'useImperativeHandle';\n        updateHookTypesDev();\n        return updateImperativeHandle(ref, create, deps);\n      },\n      useInsertionEffect: function (create, deps) {\n        currentHookNameInDev = 'useInsertionEffect';\n        updateHookTypesDev();\n        return updateInsertionEffect(create, deps);\n      },\n      useLayoutEffect: function (create, deps) {\n        currentHookNameInDev = 'useLayoutEffect';\n        updateHookTypesDev();\n        return updateLayoutEffect(create, deps);\n      },\n      useMemo: function (create, deps) {\n        currentHookNameInDev = 'useMemo';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return updateMemo(create, deps);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useReducer: function (reducer, initialArg, init) {\n        currentHookNameInDev = 'useReducer';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return updateReducer(reducer, initialArg, init);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useRef: function (initialValue) {\n        currentHookNameInDev = 'useRef';\n        updateHookTypesDev();\n        return updateRef();\n      },\n      useState: function (initialState) {\n        currentHookNameInDev = 'useState';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return updateState(initialState);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useDebugValue: function (value, formatterFn) {\n        currentHookNameInDev = 'useDebugValue';\n        updateHookTypesDev();\n        return updateDebugValue();\n      },\n      useDeferredValue: function (value) {\n        currentHookNameInDev = 'useDeferredValue';\n        updateHookTypesDev();\n        return updateDeferredValue(value);\n      },\n      useTransition: function () {\n        currentHookNameInDev = 'useTransition';\n        updateHookTypesDev();\n        return updateTransition();\n      },\n      useMutableSource: function (source, getSnapshot, subscribe) {\n        currentHookNameInDev = 'useMutableSource';\n        updateHookTypesDev();\n        return updateMutableSource();\n      },\n      useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n        currentHookNameInDev = 'useSyncExternalStore';\n        updateHookTypesDev();\n        return updateSyncExternalStore(subscribe, getSnapshot);\n      },\n      useId: function () {\n        currentHookNameInDev = 'useId';\n        updateHookTypesDev();\n        return updateId();\n      },\n      unstable_isNewReconciler: enableNewReconciler\n    };\n\n    HooksDispatcherOnRerenderInDEV = {\n      readContext: function (context) {\n        return readContext(context);\n      },\n      useCallback: function (callback, deps) {\n        currentHookNameInDev = 'useCallback';\n        updateHookTypesDev();\n        return updateCallback(callback, deps);\n      },\n      useContext: function (context) {\n        currentHookNameInDev = 'useContext';\n        updateHookTypesDev();\n        return readContext(context);\n      },\n      useEffect: function (create, deps) {\n        currentHookNameInDev = 'useEffect';\n        updateHookTypesDev();\n        return updateEffect(create, deps);\n      },\n      useImperativeHandle: function (ref, create, deps) {\n        currentHookNameInDev = 'useImperativeHandle';\n        updateHookTypesDev();\n        return updateImperativeHandle(ref, create, deps);\n      },\n      useInsertionEffect: function (create, deps) {\n        currentHookNameInDev = 'useInsertionEffect';\n        updateHookTypesDev();\n        return updateInsertionEffect(create, deps);\n      },\n      useLayoutEffect: function (create, deps) {\n        currentHookNameInDev = 'useLayoutEffect';\n        updateHookTypesDev();\n        return updateLayoutEffect(create, deps);\n      },\n      useMemo: function (create, deps) {\n        currentHookNameInDev = 'useMemo';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnRerenderInDEV;\n\n        try {\n          return updateMemo(create, deps);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useReducer: function (reducer, initialArg, init) {\n        currentHookNameInDev = 'useReducer';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnRerenderInDEV;\n\n        try {\n          return rerenderReducer(reducer, initialArg, init);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useRef: function (initialValue) {\n        currentHookNameInDev = 'useRef';\n        updateHookTypesDev();\n        return updateRef();\n      },\n      useState: function (initialState) {\n        currentHookNameInDev = 'useState';\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnRerenderInDEV;\n\n        try {\n          return rerenderState(initialState);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useDebugValue: function (value, formatterFn) {\n        currentHookNameInDev = 'useDebugValue';\n        updateHookTypesDev();\n        return updateDebugValue();\n      },\n      useDeferredValue: function (value) {\n        currentHookNameInDev = 'useDeferredValue';\n        updateHookTypesDev();\n        return rerenderDeferredValue(value);\n      },\n      useTransition: function () {\n        currentHookNameInDev = 'useTransition';\n        updateHookTypesDev();\n        return rerenderTransition();\n      },\n      useMutableSource: function (source, getSnapshot, subscribe) {\n        currentHookNameInDev = 'useMutableSource';\n        updateHookTypesDev();\n        return updateMutableSource();\n      },\n      useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n        currentHookNameInDev = 'useSyncExternalStore';\n        updateHookTypesDev();\n        return updateSyncExternalStore(subscribe, getSnapshot);\n      },\n      useId: function () {\n        currentHookNameInDev = 'useId';\n        updateHookTypesDev();\n        return updateId();\n      },\n      unstable_isNewReconciler: enableNewReconciler\n    };\n\n    InvalidNestedHooksDispatcherOnMountInDEV = {\n      readContext: function (context) {\n        warnInvalidContextAccess();\n        return readContext(context);\n      },\n      useCallback: function (callback, deps) {\n        currentHookNameInDev = 'useCallback';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountCallback(callback, deps);\n      },\n      useContext: function (context) {\n        currentHookNameInDev = 'useContext';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return readContext(context);\n      },\n      useEffect: function (create, deps) {\n        currentHookNameInDev = 'useEffect';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountEffect(create, deps);\n      },\n      useImperativeHandle: function (ref, create, deps) {\n        currentHookNameInDev = 'useImperativeHandle';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountImperativeHandle(ref, create, deps);\n      },\n      useInsertionEffect: function (create, deps) {\n        currentHookNameInDev = 'useInsertionEffect';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountInsertionEffect(create, deps);\n      },\n      useLayoutEffect: function (create, deps) {\n        currentHookNameInDev = 'useLayoutEffect';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountLayoutEffect(create, deps);\n      },\n      useMemo: function (create, deps) {\n        currentHookNameInDev = 'useMemo';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountMemo(create, deps);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useReducer: function (reducer, initialArg, init) {\n        currentHookNameInDev = 'useReducer';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountReducer(reducer, initialArg, init);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useRef: function (initialValue) {\n        currentHookNameInDev = 'useRef';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountRef(initialValue);\n      },\n      useState: function (initialState) {\n        currentHookNameInDev = 'useState';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;\n\n        try {\n          return mountState(initialState);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useDebugValue: function (value, formatterFn) {\n        currentHookNameInDev = 'useDebugValue';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountDebugValue();\n      },\n      useDeferredValue: function (value) {\n        currentHookNameInDev = 'useDeferredValue';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountDeferredValue(value);\n      },\n      useTransition: function () {\n        currentHookNameInDev = 'useTransition';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountTransition();\n      },\n      useMutableSource: function (source, getSnapshot, subscribe) {\n        currentHookNameInDev = 'useMutableSource';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountMutableSource();\n      },\n      useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n        currentHookNameInDev = 'useSyncExternalStore';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n      },\n      useId: function () {\n        currentHookNameInDev = 'useId';\n        warnInvalidHookAccess();\n        mountHookTypesDev();\n        return mountId();\n      },\n      unstable_isNewReconciler: enableNewReconciler\n    };\n\n    InvalidNestedHooksDispatcherOnUpdateInDEV = {\n      readContext: function (context) {\n        warnInvalidContextAccess();\n        return readContext(context);\n      },\n      useCallback: function (callback, deps) {\n        currentHookNameInDev = 'useCallback';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateCallback(callback, deps);\n      },\n      useContext: function (context) {\n        currentHookNameInDev = 'useContext';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return readContext(context);\n      },\n      useEffect: function (create, deps) {\n        currentHookNameInDev = 'useEffect';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateEffect(create, deps);\n      },\n      useImperativeHandle: function (ref, create, deps) {\n        currentHookNameInDev = 'useImperativeHandle';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateImperativeHandle(ref, create, deps);\n      },\n      useInsertionEffect: function (create, deps) {\n        currentHookNameInDev = 'useInsertionEffect';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateInsertionEffect(create, deps);\n      },\n      useLayoutEffect: function (create, deps) {\n        currentHookNameInDev = 'useLayoutEffect';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateLayoutEffect(create, deps);\n      },\n      useMemo: function (create, deps) {\n        currentHookNameInDev = 'useMemo';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return updateMemo(create, deps);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useReducer: function (reducer, initialArg, init) {\n        currentHookNameInDev = 'useReducer';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return updateReducer(reducer, initialArg, init);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useRef: function (initialValue) {\n        currentHookNameInDev = 'useRef';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateRef();\n      },\n      useState: function (initialState) {\n        currentHookNameInDev = 'useState';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return updateState(initialState);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useDebugValue: function (value, formatterFn) {\n        currentHookNameInDev = 'useDebugValue';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateDebugValue();\n      },\n      useDeferredValue: function (value) {\n        currentHookNameInDev = 'useDeferredValue';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateDeferredValue(value);\n      },\n      useTransition: function () {\n        currentHookNameInDev = 'useTransition';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateTransition();\n      },\n      useMutableSource: function (source, getSnapshot, subscribe) {\n        currentHookNameInDev = 'useMutableSource';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateMutableSource();\n      },\n      useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n        currentHookNameInDev = 'useSyncExternalStore';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateSyncExternalStore(subscribe, getSnapshot);\n      },\n      useId: function () {\n        currentHookNameInDev = 'useId';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateId();\n      },\n      unstable_isNewReconciler: enableNewReconciler\n    };\n\n    InvalidNestedHooksDispatcherOnRerenderInDEV = {\n      readContext: function (context) {\n        warnInvalidContextAccess();\n        return readContext(context);\n      },\n      useCallback: function (callback, deps) {\n        currentHookNameInDev = 'useCallback';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateCallback(callback, deps);\n      },\n      useContext: function (context) {\n        currentHookNameInDev = 'useContext';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return readContext(context);\n      },\n      useEffect: function (create, deps) {\n        currentHookNameInDev = 'useEffect';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateEffect(create, deps);\n      },\n      useImperativeHandle: function (ref, create, deps) {\n        currentHookNameInDev = 'useImperativeHandle';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateImperativeHandle(ref, create, deps);\n      },\n      useInsertionEffect: function (create, deps) {\n        currentHookNameInDev = 'useInsertionEffect';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateInsertionEffect(create, deps);\n      },\n      useLayoutEffect: function (create, deps) {\n        currentHookNameInDev = 'useLayoutEffect';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateLayoutEffect(create, deps);\n      },\n      useMemo: function (create, deps) {\n        currentHookNameInDev = 'useMemo';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return updateMemo(create, deps);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useReducer: function (reducer, initialArg, init) {\n        currentHookNameInDev = 'useReducer';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return rerenderReducer(reducer, initialArg, init);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useRef: function (initialValue) {\n        currentHookNameInDev = 'useRef';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateRef();\n      },\n      useState: function (initialState) {\n        currentHookNameInDev = 'useState';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        var prevDispatcher = ReactCurrentDispatcher$1.current;\n        ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;\n\n        try {\n          return rerenderState(initialState);\n        } finally {\n          ReactCurrentDispatcher$1.current = prevDispatcher;\n        }\n      },\n      useDebugValue: function (value, formatterFn) {\n        currentHookNameInDev = 'useDebugValue';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateDebugValue();\n      },\n      useDeferredValue: function (value) {\n        currentHookNameInDev = 'useDeferredValue';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return rerenderDeferredValue(value);\n      },\n      useTransition: function () {\n        currentHookNameInDev = 'useTransition';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return rerenderTransition();\n      },\n      useMutableSource: function (source, getSnapshot, subscribe) {\n        currentHookNameInDev = 'useMutableSource';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateMutableSource();\n      },\n      useSyncExternalStore: function (subscribe, getSnapshot, getServerSnapshot) {\n        currentHookNameInDev = 'useSyncExternalStore';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateSyncExternalStore(subscribe, getSnapshot);\n      },\n      useId: function () {\n        currentHookNameInDev = 'useId';\n        warnInvalidHookAccess();\n        updateHookTypesDev();\n        return updateId();\n      },\n      unstable_isNewReconciler: enableNewReconciler\n    };\n  }\n\n  var now$1 = unstable_now;\n  var commitTime = 0;\n  var layoutEffectStartTime = -1;\n  var profilerStartTime = -1;\n  var passiveEffectStartTime = -1;\n  /**\n   * Tracks whether the current update was a nested/cascading update (scheduled from a layout effect).\n   *\n   * The overall sequence is:\n   *   1. render\n   *   2. commit (and call `onRender`, `onCommit`)\n   *   3. check for nested updates\n   *   4. flush passive effects (and call `onPostCommit`)\n   *\n   * Nested updates are identified in step 3 above,\n   * but step 4 still applies to the work that was just committed.\n   * We use two flags to track nested updates then:\n   * one tracks whether the upcoming update is a nested update,\n   * and the other tracks whether the current update was a nested update.\n   * The first value gets synced to the second at the start of the render phase.\n   */\n\n  var currentUpdateIsNested = false;\n  var nestedUpdateScheduled = false;\n\n  function isCurrentUpdateNested() {\n    return currentUpdateIsNested;\n  }\n\n  function markNestedUpdateScheduled() {\n    {\n      nestedUpdateScheduled = true;\n    }\n  }\n\n  function resetNestedUpdateFlag() {\n    {\n      currentUpdateIsNested = false;\n      nestedUpdateScheduled = false;\n    }\n  }\n\n  function syncNestedUpdateFlag() {\n    {\n      currentUpdateIsNested = nestedUpdateScheduled;\n      nestedUpdateScheduled = false;\n    }\n  }\n\n  function getCommitTime() {\n    return commitTime;\n  }\n\n  function recordCommitTime() {\n\n    commitTime = now$1();\n  }\n\n  function startProfilerTimer(fiber) {\n\n    profilerStartTime = now$1();\n\n    if (fiber.actualStartTime < 0) {\n      fiber.actualStartTime = now$1();\n    }\n  }\n\n  function stopProfilerTimerIfRunning(fiber) {\n\n    profilerStartTime = -1;\n  }\n\n  function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) {\n\n    if (profilerStartTime >= 0) {\n      var elapsedTime = now$1() - profilerStartTime;\n      fiber.actualDuration += elapsedTime;\n\n      if (overrideBaseTime) {\n        fiber.selfBaseDuration = elapsedTime;\n      }\n\n      profilerStartTime = -1;\n    }\n  }\n\n  function recordLayoutEffectDuration(fiber) {\n\n    if (layoutEffectStartTime >= 0) {\n      var elapsedTime = now$1() - layoutEffectStartTime;\n      layoutEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor\n      // Or the root (for the DevTools Profiler to read)\n\n      var parentFiber = fiber.return;\n\n      while (parentFiber !== null) {\n        switch (parentFiber.tag) {\n          case HostRoot:\n            var root = parentFiber.stateNode;\n            root.effectDuration += elapsedTime;\n            return;\n\n          case Profiler:\n            var parentStateNode = parentFiber.stateNode;\n            parentStateNode.effectDuration += elapsedTime;\n            return;\n        }\n\n        parentFiber = parentFiber.return;\n      }\n    }\n  }\n\n  function recordPassiveEffectDuration(fiber) {\n\n    if (passiveEffectStartTime >= 0) {\n      var elapsedTime = now$1() - passiveEffectStartTime;\n      passiveEffectStartTime = -1; // Store duration on the next nearest Profiler ancestor\n      // Or the root (for the DevTools Profiler to read)\n\n      var parentFiber = fiber.return;\n\n      while (parentFiber !== null) {\n        switch (parentFiber.tag) {\n          case HostRoot:\n            var root = parentFiber.stateNode;\n\n            if (root !== null) {\n              root.passiveEffectDuration += elapsedTime;\n            }\n\n            return;\n\n          case Profiler:\n            var parentStateNode = parentFiber.stateNode;\n\n            if (parentStateNode !== null) {\n              // Detached fibers have their state node cleared out.\n              // In this case, the return pointer is also cleared out,\n              // so we won't be able to report the time spent in this Profiler's subtree.\n              parentStateNode.passiveEffectDuration += elapsedTime;\n            }\n\n            return;\n        }\n\n        parentFiber = parentFiber.return;\n      }\n    }\n  }\n\n  function startLayoutEffectTimer() {\n\n    layoutEffectStartTime = now$1();\n  }\n\n  function startPassiveEffectTimer() {\n\n    passiveEffectStartTime = now$1();\n  }\n\n  function transferActualDuration(fiber) {\n    // Transfer time spent rendering these children so we don't lose it\n    // after we rerender. This is used as a helper in special cases\n    // where we should count the work of multiple passes.\n    var child = fiber.child;\n\n    while (child) {\n      fiber.actualDuration += child.actualDuration;\n      child = child.sibling;\n    }\n  }\n\n  function resolveDefaultProps(Component, baseProps) {\n    if (Component && Component.defaultProps) {\n      // Resolve default props. Taken from ReactElement\n      var props = assign({}, baseProps);\n      var defaultProps = Component.defaultProps;\n\n      for (var propName in defaultProps) {\n        if (props[propName] === undefined) {\n          props[propName] = defaultProps[propName];\n        }\n      }\n\n      return props;\n    }\n\n    return baseProps;\n  }\n\n  var fakeInternalInstance = {};\n  var didWarnAboutStateAssignmentForComponent;\n  var didWarnAboutUninitializedState;\n  var didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate;\n  var didWarnAboutLegacyLifecyclesAndDerivedState;\n  var didWarnAboutUndefinedDerivedState;\n  var warnOnUndefinedDerivedState;\n  var warnOnInvalidCallback;\n  var didWarnAboutDirectlyAssigningPropsToState;\n  var didWarnAboutContextTypeAndContextTypes;\n  var didWarnAboutInvalidateContextType;\n  var didWarnAboutLegacyContext$1;\n\n  {\n    didWarnAboutStateAssignmentForComponent = new Set();\n    didWarnAboutUninitializedState = new Set();\n    didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate = new Set();\n    didWarnAboutLegacyLifecyclesAndDerivedState = new Set();\n    didWarnAboutDirectlyAssigningPropsToState = new Set();\n    didWarnAboutUndefinedDerivedState = new Set();\n    didWarnAboutContextTypeAndContextTypes = new Set();\n    didWarnAboutInvalidateContextType = new Set();\n    didWarnAboutLegacyContext$1 = new Set();\n    var didWarnOnInvalidCallback = new Set();\n\n    warnOnInvalidCallback = function (callback, callerName) {\n      if (callback === null || typeof callback === 'function') {\n        return;\n      }\n\n      var key = callerName + '_' + callback;\n\n      if (!didWarnOnInvalidCallback.has(key)) {\n        didWarnOnInvalidCallback.add(key);\n\n        error('%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback);\n      }\n    };\n\n    warnOnUndefinedDerivedState = function (type, partialState) {\n      if (partialState === undefined) {\n        var componentName = getComponentNameFromType(type) || 'Component';\n\n        if (!didWarnAboutUndefinedDerivedState.has(componentName)) {\n          didWarnAboutUndefinedDerivedState.add(componentName);\n\n          error('%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName);\n        }\n      }\n    }; // This is so gross but it's at least non-critical and can be removed if\n    // it causes problems. This is meant to give a nicer error message for\n    // ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component,\n    // ...)) which otherwise throws a \"_processChildContext is not a function\"\n    // exception.\n\n\n    Object.defineProperty(fakeInternalInstance, '_processChildContext', {\n      enumerable: false,\n      value: function () {\n        throw new Error('_processChildContext is not available in React 16+. This likely ' + 'means you have multiple copies of React and are attempting to nest ' + 'a React 15 tree inside a React 16 tree using ' + \"unstable_renderSubtreeIntoContainer, which isn't supported. Try \" + 'to make sure you have only one copy of React (and ideally, switch ' + 'to ReactDOM.createPortal).');\n      }\n    });\n    Object.freeze(fakeInternalInstance);\n  }\n\n  function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) {\n    var prevState = workInProgress.memoizedState;\n    var partialState = getDerivedStateFromProps(nextProps, prevState);\n\n    {\n      if ( workInProgress.mode & StrictLegacyMode) {\n        setIsStrictModeForDevtools(true);\n\n        try {\n          // Invoke the function an extra time to help detect side-effects.\n          partialState = getDerivedStateFromProps(nextProps, prevState);\n        } finally {\n          setIsStrictModeForDevtools(false);\n        }\n      }\n\n      warnOnUndefinedDerivedState(ctor, partialState);\n    } // Merge the partial state and the previous state.\n\n\n    var memoizedState = partialState === null || partialState === undefined ? prevState : assign({}, prevState, partialState);\n    workInProgress.memoizedState = memoizedState; // Once the update queue is empty, persist the derived state onto the\n    // base state.\n\n    if (workInProgress.lanes === NoLanes) {\n      // Queue is always non-null for classes\n      var updateQueue = workInProgress.updateQueue;\n      updateQueue.baseState = memoizedState;\n    }\n  }\n\n  var classComponentUpdater = {\n    isMounted: isMounted,\n    enqueueSetState: function (inst, payload, callback) {\n      var fiber = get(inst);\n      var eventTime = requestEventTime();\n      var lane = requestUpdateLane(fiber);\n      var update = createUpdate(eventTime, lane);\n      update.payload = payload;\n\n      if (callback !== undefined && callback !== null) {\n        {\n          warnOnInvalidCallback(callback, 'setState');\n        }\n\n        update.callback = callback;\n      }\n\n      var root = enqueueUpdate(fiber, update, lane);\n\n      if (root !== null) {\n        scheduleUpdateOnFiber(root, fiber, lane, eventTime);\n        entangleTransitions(root, fiber, lane);\n      }\n\n      {\n        markStateUpdateScheduled(fiber, lane);\n      }\n    },\n    enqueueReplaceState: function (inst, payload, callback) {\n      var fiber = get(inst);\n      var eventTime = requestEventTime();\n      var lane = requestUpdateLane(fiber);\n      var update = createUpdate(eventTime, lane);\n      update.tag = ReplaceState;\n      update.payload = payload;\n\n      if (callback !== undefined && callback !== null) {\n        {\n          warnOnInvalidCallback(callback, 'replaceState');\n        }\n\n        update.callback = callback;\n      }\n\n      var root = enqueueUpdate(fiber, update, lane);\n\n      if (root !== null) {\n        scheduleUpdateOnFiber(root, fiber, lane, eventTime);\n        entangleTransitions(root, fiber, lane);\n      }\n\n      {\n        markStateUpdateScheduled(fiber, lane);\n      }\n    },\n    enqueueForceUpdate: function (inst, callback) {\n      var fiber = get(inst);\n      var eventTime = requestEventTime();\n      var lane = requestUpdateLane(fiber);\n      var update = createUpdate(eventTime, lane);\n      update.tag = ForceUpdate;\n\n      if (callback !== undefined && callback !== null) {\n        {\n          warnOnInvalidCallback(callback, 'forceUpdate');\n        }\n\n        update.callback = callback;\n      }\n\n      var root = enqueueUpdate(fiber, update, lane);\n\n      if (root !== null) {\n        scheduleUpdateOnFiber(root, fiber, lane, eventTime);\n        entangleTransitions(root, fiber, lane);\n      }\n\n      {\n        markForceUpdateScheduled(fiber, lane);\n      }\n    }\n  };\n\n  function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) {\n    var instance = workInProgress.stateNode;\n\n    if (typeof instance.shouldComponentUpdate === 'function') {\n      var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext);\n\n      {\n        if ( workInProgress.mode & StrictLegacyMode) {\n          setIsStrictModeForDevtools(true);\n\n          try {\n            // Invoke the function an extra time to help detect side-effects.\n            shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext);\n          } finally {\n            setIsStrictModeForDevtools(false);\n          }\n        }\n\n        if (shouldUpdate === undefined) {\n          error('%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentNameFromType(ctor) || 'Component');\n        }\n      }\n\n      return shouldUpdate;\n    }\n\n    if (ctor.prototype && ctor.prototype.isPureReactComponent) {\n      return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState);\n    }\n\n    return true;\n  }\n\n  function checkClassInstance(workInProgress, ctor, newProps) {\n    var instance = workInProgress.stateNode;\n\n    {\n      var name = getComponentNameFromType(ctor) || 'Component';\n      var renderPresent = instance.render;\n\n      if (!renderPresent) {\n        if (ctor.prototype && typeof ctor.prototype.render === 'function') {\n          error('%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name);\n        } else {\n          error('%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name);\n        }\n      }\n\n      if (instance.getInitialState && !instance.getInitialState.isReactClassApproved && !instance.state) {\n        error('getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', name);\n      }\n\n      if (instance.getDefaultProps && !instance.getDefaultProps.isReactClassApproved) {\n        error('getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', name);\n      }\n\n      if (instance.propTypes) {\n        error('propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name);\n      }\n\n      if (instance.contextType) {\n        error('contextType was defined as an instance property on %s. Use a static ' + 'property to define contextType instead.', name);\n      }\n\n      {\n        if (ctor.childContextTypes && !didWarnAboutLegacyContext$1.has(ctor) && // Strict Mode has its own warning for legacy context, so we can skip\n        // this one.\n        (workInProgress.mode & StrictLegacyMode) === NoMode) {\n          didWarnAboutLegacyContext$1.add(ctor);\n\n          error('%s uses the legacy childContextTypes API which is no longer ' + 'supported and will be removed in the next major release. Use ' + 'React.createContext() instead\\n\\n.' + 'Learn more about this warning here: https://reactjs.org/link/legacy-context', name);\n        }\n\n        if (ctor.contextTypes && !didWarnAboutLegacyContext$1.has(ctor) && // Strict Mode has its own warning for legacy context, so we can skip\n        // this one.\n        (workInProgress.mode & StrictLegacyMode) === NoMode) {\n          didWarnAboutLegacyContext$1.add(ctor);\n\n          error('%s uses the legacy contextTypes API which is no longer supported ' + 'and will be removed in the next major release. Use ' + 'React.createContext() with static contextType instead.\\n\\n' + 'Learn more about this warning here: https://reactjs.org/link/legacy-context', name);\n        }\n\n        if (instance.contextTypes) {\n          error('contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name);\n        }\n\n        if (ctor.contextType && ctor.contextTypes && !didWarnAboutContextTypeAndContextTypes.has(ctor)) {\n          didWarnAboutContextTypeAndContextTypes.add(ctor);\n\n          error('%s declares both contextTypes and contextType static properties. ' + 'The legacy contextTypes property will be ignored.', name);\n        }\n      }\n\n      if (typeof instance.componentShouldUpdate === 'function') {\n        error('%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', name);\n      }\n\n      if (ctor.prototype && ctor.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined') {\n        error('%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentNameFromType(ctor) || 'A pure component');\n      }\n\n      if (typeof instance.componentDidUnmount === 'function') {\n        error('%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name);\n      }\n\n      if (typeof instance.componentDidReceiveProps === 'function') {\n        error('%s has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', name);\n      }\n\n      if (typeof instance.componentWillRecieveProps === 'function') {\n        error('%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name);\n      }\n\n      if (typeof instance.UNSAFE_componentWillRecieveProps === 'function') {\n        error('%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name);\n      }\n\n      var hasMutatedProps = instance.props !== newProps;\n\n      if (instance.props !== undefined && hasMutatedProps) {\n        error('%s(...): When calling super() in `%s`, make sure to pass ' + \"up the same props that your component's constructor was passed.\", name, name);\n      }\n\n      if (instance.defaultProps) {\n        error('Setting defaultProps as an instance property on %s is not supported and will be ignored.' + ' Instead, define defaultProps as a static property on %s.', name, name);\n      }\n\n      if (typeof instance.getSnapshotBeforeUpdate === 'function' && typeof instance.componentDidUpdate !== 'function' && !didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.has(ctor)) {\n        didWarnAboutGetSnapshotBeforeUpdateWithoutDidUpdate.add(ctor);\n\n        error('%s: getSnapshotBeforeUpdate() should be used with componentDidUpdate(). ' + 'This component defines getSnapshotBeforeUpdate() only.', getComponentNameFromType(ctor));\n      }\n\n      if (typeof instance.getDerivedStateFromProps === 'function') {\n        error('%s: getDerivedStateFromProps() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name);\n      }\n\n      if (typeof instance.getDerivedStateFromError === 'function') {\n        error('%s: getDerivedStateFromError() is defined as an instance method ' + 'and will be ignored. Instead, declare it as a static method.', name);\n      }\n\n      if (typeof ctor.getSnapshotBeforeUpdate === 'function') {\n        error('%s: getSnapshotBeforeUpdate() is defined as a static method ' + 'and will be ignored. Instead, declare it as an instance method.', name);\n      }\n\n      var _state = instance.state;\n\n      if (_state && (typeof _state !== 'object' || isArray(_state))) {\n        error('%s.state: must be set to an object or null', name);\n      }\n\n      if (typeof instance.getChildContext === 'function' && typeof ctor.childContextTypes !== 'object') {\n        error('%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', name);\n      }\n    }\n  }\n\n  function adoptClassInstance(workInProgress, instance) {\n    instance.updater = classComponentUpdater;\n    workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates\n\n    set(instance, workInProgress);\n\n    {\n      instance._reactInternalInstance = fakeInternalInstance;\n    }\n  }\n\n  function constructClassInstance(workInProgress, ctor, props) {\n    var isLegacyContextConsumer = false;\n    var unmaskedContext = emptyContextObject;\n    var context = emptyContextObject;\n    var contextType = ctor.contextType;\n\n    {\n      if ('contextType' in ctor) {\n        var isValid = // Allow null for conditional declaration\n        contextType === null || contextType !== undefined && contextType.$$typeof === REACT_CONTEXT_TYPE && contextType._context === undefined; // Not a <Context.Consumer>\n\n        if (!isValid && !didWarnAboutInvalidateContextType.has(ctor)) {\n          didWarnAboutInvalidateContextType.add(ctor);\n          var addendum = '';\n\n          if (contextType === undefined) {\n            addendum = ' However, it is set to undefined. ' + 'This can be caused by a typo or by mixing up named and default imports. ' + 'This can also happen due to a circular dependency, so ' + 'try moving the createContext() call to a separate file.';\n          } else if (typeof contextType !== 'object') {\n            addendum = ' However, it is set to a ' + typeof contextType + '.';\n          } else if (contextType.$$typeof === REACT_PROVIDER_TYPE) {\n            addendum = ' Did you accidentally pass the Context.Provider instead?';\n          } else if (contextType._context !== undefined) {\n            // <Context.Consumer>\n            addendum = ' Did you accidentally pass the Context.Consumer instead?';\n          } else {\n            addendum = ' However, it is set to an object with keys {' + Object.keys(contextType).join(', ') + '}.';\n          }\n\n          error('%s defines an invalid contextType. ' + 'contextType should point to the Context object returned by React.createContext().%s', getComponentNameFromType(ctor) || 'Component', addendum);\n        }\n      }\n    }\n\n    if (typeof contextType === 'object' && contextType !== null) {\n      context = readContext(contextType);\n    } else {\n      unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);\n      var contextTypes = ctor.contextTypes;\n      isLegacyContextConsumer = contextTypes !== null && contextTypes !== undefined;\n      context = isLegacyContextConsumer ? getMaskedContext(workInProgress, unmaskedContext) : emptyContextObject;\n    }\n\n    var instance = new ctor(props, context); // Instantiate twice to help detect side-effects.\n\n    {\n      if ( workInProgress.mode & StrictLegacyMode) {\n        setIsStrictModeForDevtools(true);\n\n        try {\n          instance = new ctor(props, context); // eslint-disable-line no-new\n        } finally {\n          setIsStrictModeForDevtools(false);\n        }\n      }\n    }\n\n    var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null;\n    adoptClassInstance(workInProgress, instance);\n\n    {\n      if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) {\n        var componentName = getComponentNameFromType(ctor) || 'Component';\n\n        if (!didWarnAboutUninitializedState.has(componentName)) {\n          didWarnAboutUninitializedState.add(componentName);\n\n          error('`%s` uses `getDerivedStateFromProps` but its initial state is ' + '%s. This is not recommended. Instead, define the initial state by ' + 'assigning an object to `this.state` in the constructor of `%s`. ' + 'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.', componentName, instance.state === null ? 'null' : 'undefined', componentName);\n        }\n      } // If new component APIs are defined, \"unsafe\" lifecycles won't be called.\n      // Warn about these lifecycles if they are present.\n      // Don't warn about react-lifecycles-compat polyfilled methods though.\n\n\n      if (typeof ctor.getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function') {\n        var foundWillMountName = null;\n        var foundWillReceivePropsName = null;\n        var foundWillUpdateName = null;\n\n        if (typeof instance.componentWillMount === 'function' && instance.componentWillMount.__suppressDeprecationWarning !== true) {\n          foundWillMountName = 'componentWillMount';\n        } else if (typeof instance.UNSAFE_componentWillMount === 'function') {\n          foundWillMountName = 'UNSAFE_componentWillMount';\n        }\n\n        if (typeof instance.componentWillReceiveProps === 'function' && instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) {\n          foundWillReceivePropsName = 'componentWillReceiveProps';\n        } else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') {\n          foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps';\n        }\n\n        if (typeof instance.componentWillUpdate === 'function' && instance.componentWillUpdate.__suppressDeprecationWarning !== true) {\n          foundWillUpdateName = 'componentWillUpdate';\n        } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') {\n          foundWillUpdateName = 'UNSAFE_componentWillUpdate';\n        }\n\n        if (foundWillMountName !== null || foundWillReceivePropsName !== null || foundWillUpdateName !== null) {\n          var _componentName = getComponentNameFromType(ctor) || 'Component';\n\n          var newApiName = typeof ctor.getDerivedStateFromProps === 'function' ? 'getDerivedStateFromProps()' : 'getSnapshotBeforeUpdate()';\n\n          if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(_componentName)) {\n            didWarnAboutLegacyLifecyclesAndDerivedState.add(_componentName);\n\n            error('Unsafe legacy lifecycles will not be called for components using new component APIs.\\n\\n' + '%s uses %s but also contains the following legacy lifecycles:%s%s%s\\n\\n' + 'The above lifecycles should be removed. Learn more about this warning here:\\n' + 'https://reactjs.org/link/unsafe-component-lifecycles', _componentName, newApiName, foundWillMountName !== null ? \"\\n  \" + foundWillMountName : '', foundWillReceivePropsName !== null ? \"\\n  \" + foundWillReceivePropsName : '', foundWillUpdateName !== null ? \"\\n  \" + foundWillUpdateName : '');\n          }\n        }\n      }\n    } // Cache unmasked context so we can avoid recreating masked context unless necessary.\n    // ReactFiberContext usually updates this cache but can't for newly-created instances.\n\n\n    if (isLegacyContextConsumer) {\n      cacheContext(workInProgress, unmaskedContext, context);\n    }\n\n    return instance;\n  }\n\n  function callComponentWillMount(workInProgress, instance) {\n    var oldState = instance.state;\n\n    if (typeof instance.componentWillMount === 'function') {\n      instance.componentWillMount();\n    }\n\n    if (typeof instance.UNSAFE_componentWillMount === 'function') {\n      instance.UNSAFE_componentWillMount();\n    }\n\n    if (oldState !== instance.state) {\n      {\n        error('%s.componentWillMount(): Assigning directly to this.state is ' + \"deprecated (except inside a component's \" + 'constructor). Use setState instead.', getComponentNameFromFiber(workInProgress) || 'Component');\n      }\n\n      classComponentUpdater.enqueueReplaceState(instance, instance.state, null);\n    }\n  }\n\n  function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) {\n    var oldState = instance.state;\n\n    if (typeof instance.componentWillReceiveProps === 'function') {\n      instance.componentWillReceiveProps(newProps, nextContext);\n    }\n\n    if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') {\n      instance.UNSAFE_componentWillReceiveProps(newProps, nextContext);\n    }\n\n    if (instance.state !== oldState) {\n      {\n        var componentName = getComponentNameFromFiber(workInProgress) || 'Component';\n\n        if (!didWarnAboutStateAssignmentForComponent.has(componentName)) {\n          didWarnAboutStateAssignmentForComponent.add(componentName);\n\n          error('%s.componentWillReceiveProps(): Assigning directly to ' + \"this.state is deprecated (except inside a component's \" + 'constructor). Use setState instead.', componentName);\n        }\n      }\n\n      classComponentUpdater.enqueueReplaceState(instance, instance.state, null);\n    }\n  } // Invokes the mount life-cycles on a previously never rendered instance.\n\n\n  function mountClassInstance(workInProgress, ctor, newProps, renderLanes) {\n    {\n      checkClassInstance(workInProgress, ctor, newProps);\n    }\n\n    var instance = workInProgress.stateNode;\n    instance.props = newProps;\n    instance.state = workInProgress.memoizedState;\n    instance.refs = {};\n    initializeUpdateQueue(workInProgress);\n    var contextType = ctor.contextType;\n\n    if (typeof contextType === 'object' && contextType !== null) {\n      instance.context = readContext(contextType);\n    } else {\n      var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);\n      instance.context = getMaskedContext(workInProgress, unmaskedContext);\n    }\n\n    {\n      if (instance.state === newProps) {\n        var componentName = getComponentNameFromType(ctor) || 'Component';\n\n        if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) {\n          didWarnAboutDirectlyAssigningPropsToState.add(componentName);\n\n          error('%s: It is not recommended to assign props directly to state ' + \"because updates to props won't be reflected in state. \" + 'In most cases, it is better to use props directly.', componentName);\n        }\n      }\n\n      if (workInProgress.mode & StrictLegacyMode) {\n        ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, instance);\n      }\n\n      {\n        ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(workInProgress, instance);\n      }\n    }\n\n    instance.state = workInProgress.memoizedState;\n    var getDerivedStateFromProps = ctor.getDerivedStateFromProps;\n\n    if (typeof getDerivedStateFromProps === 'function') {\n      applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps);\n      instance.state = workInProgress.memoizedState;\n    } // In order to support react-lifecycles-compat polyfilled components,\n    // Unsafe lifecycles should not be invoked for components using the new APIs.\n\n\n    if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {\n      callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's\n      // process them now.\n\n      processUpdateQueue(workInProgress, newProps, instance, renderLanes);\n      instance.state = workInProgress.memoizedState;\n    }\n\n    if (typeof instance.componentDidMount === 'function') {\n      var fiberFlags = Update;\n\n      {\n        fiberFlags |= LayoutStatic;\n      }\n\n      if ( (workInProgress.mode & StrictEffectsMode) !== NoMode) {\n        fiberFlags |= MountLayoutDev;\n      }\n\n      workInProgress.flags |= fiberFlags;\n    }\n  }\n\n  function resumeMountClassInstance(workInProgress, ctor, newProps, renderLanes) {\n    var instance = workInProgress.stateNode;\n    var oldProps = workInProgress.memoizedProps;\n    instance.props = oldProps;\n    var oldContext = instance.context;\n    var contextType = ctor.contextType;\n    var nextContext = emptyContextObject;\n\n    if (typeof contextType === 'object' && contextType !== null) {\n      nextContext = readContext(contextType);\n    } else {\n      var nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);\n      nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext);\n    }\n\n    var getDerivedStateFromProps = ctor.getDerivedStateFromProps;\n    var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // Note: During these life-cycles, instance.props/instance.state are what\n    // ever the previously attempted to render - not the \"current\". However,\n    // during componentDidUpdate we pass the \"current\" props.\n    // In order to support react-lifecycles-compat polyfilled components,\n    // Unsafe lifecycles should not be invoked for components using the new APIs.\n\n    if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) {\n      if (oldProps !== newProps || oldContext !== nextContext) {\n        callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext);\n      }\n    }\n\n    resetHasForceUpdateBeforeProcessing();\n    var oldState = workInProgress.memoizedState;\n    var newState = instance.state = oldState;\n    processUpdateQueue(workInProgress, newProps, instance, renderLanes);\n    newState = workInProgress.memoizedState;\n\n    if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) {\n      // If an update was already in progress, we should schedule an Update\n      // effect even though we're bailing out, so that cWU/cDU are called.\n      if (typeof instance.componentDidMount === 'function') {\n        var fiberFlags = Update;\n\n        {\n          fiberFlags |= LayoutStatic;\n        }\n\n        if ( (workInProgress.mode & StrictEffectsMode) !== NoMode) {\n          fiberFlags |= MountLayoutDev;\n        }\n\n        workInProgress.flags |= fiberFlags;\n      }\n\n      return false;\n    }\n\n    if (typeof getDerivedStateFromProps === 'function') {\n      applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps);\n      newState = workInProgress.memoizedState;\n    }\n\n    var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext);\n\n    if (shouldUpdate) {\n      // In order to support react-lifecycles-compat polyfilled components,\n      // Unsafe lifecycles should not be invoked for components using the new APIs.\n      if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) {\n        if (typeof instance.componentWillMount === 'function') {\n          instance.componentWillMount();\n        }\n\n        if (typeof instance.UNSAFE_componentWillMount === 'function') {\n          instance.UNSAFE_componentWillMount();\n        }\n      }\n\n      if (typeof instance.componentDidMount === 'function') {\n        var _fiberFlags = Update;\n\n        {\n          _fiberFlags |= LayoutStatic;\n        }\n\n        if ( (workInProgress.mode & StrictEffectsMode) !== NoMode) {\n          _fiberFlags |= MountLayoutDev;\n        }\n\n        workInProgress.flags |= _fiberFlags;\n      }\n    } else {\n      // If an update was already in progress, we should schedule an Update\n      // effect even though we're bailing out, so that cWU/cDU are called.\n      if (typeof instance.componentDidMount === 'function') {\n        var _fiberFlags2 = Update;\n\n        {\n          _fiberFlags2 |= LayoutStatic;\n        }\n\n        if ( (workInProgress.mode & StrictEffectsMode) !== NoMode) {\n          _fiberFlags2 |= MountLayoutDev;\n        }\n\n        workInProgress.flags |= _fiberFlags2;\n      } // If shouldComponentUpdate returned false, we should still update the\n      // memoized state to indicate that this work can be reused.\n\n\n      workInProgress.memoizedProps = newProps;\n      workInProgress.memoizedState = newState;\n    } // Update the existing instance's state, props, and context pointers even\n    // if shouldComponentUpdate returns false.\n\n\n    instance.props = newProps;\n    instance.state = newState;\n    instance.context = nextContext;\n    return shouldUpdate;\n  } // Invokes the update life-cycles and returns false if it shouldn't rerender.\n\n\n  function updateClassInstance(current, workInProgress, ctor, newProps, renderLanes) {\n    var instance = workInProgress.stateNode;\n    cloneUpdateQueue(current, workInProgress);\n    var unresolvedOldProps = workInProgress.memoizedProps;\n    var oldProps = workInProgress.type === workInProgress.elementType ? unresolvedOldProps : resolveDefaultProps(workInProgress.type, unresolvedOldProps);\n    instance.props = oldProps;\n    var unresolvedNewProps = workInProgress.pendingProps;\n    var oldContext = instance.context;\n    var contextType = ctor.contextType;\n    var nextContext = emptyContextObject;\n\n    if (typeof contextType === 'object' && contextType !== null) {\n      nextContext = readContext(contextType);\n    } else {\n      var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true);\n      nextContext = getMaskedContext(workInProgress, nextUnmaskedContext);\n    }\n\n    var getDerivedStateFromProps = ctor.getDerivedStateFromProps;\n    var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // Note: During these life-cycles, instance.props/instance.state are what\n    // ever the previously attempted to render - not the \"current\". However,\n    // during componentDidUpdate we pass the \"current\" props.\n    // In order to support react-lifecycles-compat polyfilled components,\n    // Unsafe lifecycles should not be invoked for components using the new APIs.\n\n    if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) {\n      if (unresolvedOldProps !== unresolvedNewProps || oldContext !== nextContext) {\n        callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext);\n      }\n    }\n\n    resetHasForceUpdateBeforeProcessing();\n    var oldState = workInProgress.memoizedState;\n    var newState = instance.state = oldState;\n    processUpdateQueue(workInProgress, newProps, instance, renderLanes);\n    newState = workInProgress.memoizedState;\n\n    if (unresolvedOldProps === unresolvedNewProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing() && !(enableLazyContextPropagation   )) {\n      // If an update was already in progress, we should schedule an Update\n      // effect even though we're bailing out, so that cWU/cDU are called.\n      if (typeof instance.componentDidUpdate === 'function') {\n        if (unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState) {\n          workInProgress.flags |= Update;\n        }\n      }\n\n      if (typeof instance.getSnapshotBeforeUpdate === 'function') {\n        if (unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState) {\n          workInProgress.flags |= Snapshot;\n        }\n      }\n\n      return false;\n    }\n\n    if (typeof getDerivedStateFromProps === 'function') {\n      applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps);\n      newState = workInProgress.memoizedState;\n    }\n\n    var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) || // TODO: In some cases, we'll end up checking if context has changed twice,\n    // both before and after `shouldComponentUpdate` has been called. Not ideal,\n    // but I'm loath to refactor this function. This only happens for memoized\n    // components so it's not that common.\n    enableLazyContextPropagation   ;\n\n    if (shouldUpdate) {\n      // In order to support react-lifecycles-compat polyfilled components,\n      // Unsafe lifecycles should not be invoked for components using the new APIs.\n      if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function')) {\n        if (typeof instance.componentWillUpdate === 'function') {\n          instance.componentWillUpdate(newProps, newState, nextContext);\n        }\n\n        if (typeof instance.UNSAFE_componentWillUpdate === 'function') {\n          instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext);\n        }\n      }\n\n      if (typeof instance.componentDidUpdate === 'function') {\n        workInProgress.flags |= Update;\n      }\n\n      if (typeof instance.getSnapshotBeforeUpdate === 'function') {\n        workInProgress.flags |= Snapshot;\n      }\n    } else {\n      // If an update was already in progress, we should schedule an Update\n      // effect even though we're bailing out, so that cWU/cDU are called.\n      if (typeof instance.componentDidUpdate === 'function') {\n        if (unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState) {\n          workInProgress.flags |= Update;\n        }\n      }\n\n      if (typeof instance.getSnapshotBeforeUpdate === 'function') {\n        if (unresolvedOldProps !== current.memoizedProps || oldState !== current.memoizedState) {\n          workInProgress.flags |= Snapshot;\n        }\n      } // If shouldComponentUpdate returned false, we should still update the\n      // memoized props/state to indicate that this work can be reused.\n\n\n      workInProgress.memoizedProps = newProps;\n      workInProgress.memoizedState = newState;\n    } // Update the existing instance's state, props, and context pointers even\n    // if shouldComponentUpdate returns false.\n\n\n    instance.props = newProps;\n    instance.state = newState;\n    instance.context = nextContext;\n    return shouldUpdate;\n  }\n\n  function createCapturedValueAtFiber(value, source) {\n    // If the value is an error, call this function immediately after it is thrown\n    // so the stack is accurate.\n    return {\n      value: value,\n      source: source,\n      stack: getStackByFiberInDevAndProd(source),\n      digest: null\n    };\n  }\n  function createCapturedValue(value, digest, stack) {\n    return {\n      value: value,\n      source: null,\n      stack: stack != null ? stack : null,\n      digest: digest != null ? digest : null\n    };\n  }\n\n  // This module is forked in different environments.\n  // By default, return `true` to log errors to the console.\n  // Forks can return `false` if this isn't desirable.\n  function showErrorDialog(boundary, errorInfo) {\n    return true;\n  }\n\n  function logCapturedError(boundary, errorInfo) {\n    try {\n      var logError = showErrorDialog(boundary, errorInfo); // Allow injected showErrorDialog() to prevent default console.error logging.\n      // This enables renderers like ReactNative to better manage redbox behavior.\n\n      if (logError === false) {\n        return;\n      }\n\n      var error = errorInfo.value;\n\n      if (true) {\n        var source = errorInfo.source;\n        var stack = errorInfo.stack;\n        var componentStack = stack !== null ? stack : ''; // Browsers support silencing uncaught errors by calling\n        // `preventDefault()` in window `error` handler.\n        // We record this information as an expando on the error.\n\n        if (error != null && error._suppressLogging) {\n          if (boundary.tag === ClassComponent) {\n            // The error is recoverable and was silenced.\n            // Ignore it and don't print the stack addendum.\n            // This is handy for testing error boundaries without noise.\n            return;\n          } // The error is fatal. Since the silencing might have\n          // been accidental, we'll surface it anyway.\n          // However, the browser would have silenced the original error\n          // so we'll print it first, and then print the stack addendum.\n\n\n          console['error'](error); // Don't transform to our wrapper\n          // For a more detailed description of this block, see:\n          // https://github.com/facebook/react/pull/13384\n        }\n\n        var componentName = source ? getComponentNameFromFiber(source) : null;\n        var componentNameMessage = componentName ? \"The above error occurred in the <\" + componentName + \"> component:\" : 'The above error occurred in one of your React components:';\n        var errorBoundaryMessage;\n\n        if (boundary.tag === HostRoot) {\n          errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\\n' + 'Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.';\n        } else {\n          var errorBoundaryName = getComponentNameFromFiber(boundary) || 'Anonymous';\n          errorBoundaryMessage = \"React will try to recreate this component tree from scratch \" + (\"using the error boundary you provided, \" + errorBoundaryName + \".\");\n        }\n\n        var combinedMessage = componentNameMessage + \"\\n\" + componentStack + \"\\n\\n\" + (\"\" + errorBoundaryMessage); // In development, we provide our own message with just the component stack.\n        // We don't include the original error message and JS stack because the browser\n        // has already printed it. Even if the application swallows the error, it is still\n        // displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils.\n\n        console['error'](combinedMessage); // Don't transform to our wrapper\n      } else {\n        // In production, we print the error directly.\n        // This will include the message, the JS stack, and anything the browser wants to show.\n        // We pass the error object instead of custom message so that the browser displays the error natively.\n        console['error'](error); // Don't transform to our wrapper\n      }\n    } catch (e) {\n      // This method must not throw, or React internal state will get messed up.\n      // If console.error is overridden, or logCapturedError() shows a dialog that throws,\n      // we want to report this error outside of the normal stack as a last resort.\n      // https://github.com/facebook/react/issues/13188\n      setTimeout(function () {\n        throw e;\n      });\n    }\n  }\n\n  var PossiblyWeakMap$1 = typeof WeakMap === 'function' ? WeakMap : Map;\n\n  function createRootErrorUpdate(fiber, errorInfo, lane) {\n    var update = createUpdate(NoTimestamp, lane); // Unmount the root by rendering null.\n\n    update.tag = CaptureUpdate; // Caution: React DevTools currently depends on this property\n    // being called \"element\".\n\n    update.payload = {\n      element: null\n    };\n    var error = errorInfo.value;\n\n    update.callback = function () {\n      onUncaughtError(error);\n      logCapturedError(fiber, errorInfo);\n    };\n\n    return update;\n  }\n\n  function createClassErrorUpdate(fiber, errorInfo, lane) {\n    var update = createUpdate(NoTimestamp, lane);\n    update.tag = CaptureUpdate;\n    var getDerivedStateFromError = fiber.type.getDerivedStateFromError;\n\n    if (typeof getDerivedStateFromError === 'function') {\n      var error$1 = errorInfo.value;\n\n      update.payload = function () {\n        return getDerivedStateFromError(error$1);\n      };\n\n      update.callback = function () {\n        {\n          markFailedErrorBoundaryForHotReloading(fiber);\n        }\n\n        logCapturedError(fiber, errorInfo);\n      };\n    }\n\n    var inst = fiber.stateNode;\n\n    if (inst !== null && typeof inst.componentDidCatch === 'function') {\n      update.callback = function callback() {\n        {\n          markFailedErrorBoundaryForHotReloading(fiber);\n        }\n\n        logCapturedError(fiber, errorInfo);\n\n        if (typeof getDerivedStateFromError !== 'function') {\n          // To preserve the preexisting retry behavior of error boundaries,\n          // we keep track of which ones already failed during this batch.\n          // This gets reset before we yield back to the browser.\n          // TODO: Warn in strict mode if getDerivedStateFromError is\n          // not defined.\n          markLegacyErrorBoundaryAsFailed(this);\n        }\n\n        var error$1 = errorInfo.value;\n        var stack = errorInfo.stack;\n        this.componentDidCatch(error$1, {\n          componentStack: stack !== null ? stack : ''\n        });\n\n        {\n          if (typeof getDerivedStateFromError !== 'function') {\n            // If componentDidCatch is the only error boundary method defined,\n            // then it needs to call setState to recover from errors.\n            // If no state update is scheduled then the boundary will swallow the error.\n            if (!includesSomeLane(fiber.lanes, SyncLane)) {\n              error('%s: Error boundaries should implement getDerivedStateFromError(). ' + 'In that method, return a state update to display an error message or fallback UI.', getComponentNameFromFiber(fiber) || 'Unknown');\n            }\n          }\n        }\n      };\n    }\n\n    return update;\n  }\n\n  function attachPingListener(root, wakeable, lanes) {\n    // Attach a ping listener\n    //\n    // The data might resolve before we have a chance to commit the fallback. Or,\n    // in the case of a refresh, we'll never commit a fallback. So we need to\n    // attach a listener now. When it resolves (\"pings\"), we can decide whether to\n    // try rendering the tree again.\n    //\n    // Only attach a listener if one does not already exist for the lanes\n    // we're currently rendering (which acts like a \"thread ID\" here).\n    //\n    // We only need to do this in concurrent mode. Legacy Suspense always\n    // commits fallbacks synchronously, so there are no pings.\n    var pingCache = root.pingCache;\n    var threadIDs;\n\n    if (pingCache === null) {\n      pingCache = root.pingCache = new PossiblyWeakMap$1();\n      threadIDs = new Set();\n      pingCache.set(wakeable, threadIDs);\n    } else {\n      threadIDs = pingCache.get(wakeable);\n\n      if (threadIDs === undefined) {\n        threadIDs = new Set();\n        pingCache.set(wakeable, threadIDs);\n      }\n    }\n\n    if (!threadIDs.has(lanes)) {\n      // Memoize using the thread ID to prevent redundant listeners.\n      threadIDs.add(lanes);\n      var ping = pingSuspendedRoot.bind(null, root, wakeable, lanes);\n\n      {\n        if (isDevToolsPresent) {\n          // If we have pending work still, restore the original updaters\n          restorePendingUpdaters(root, lanes);\n        }\n      }\n\n      wakeable.then(ping, ping);\n    }\n  }\n\n  function attachRetryListener(suspenseBoundary, root, wakeable, lanes) {\n    // Retry listener\n    //\n    // If the fallback does commit, we need to attach a different type of\n    // listener. This one schedules an update on the Suspense boundary to turn\n    // the fallback state off.\n    //\n    // Stash the wakeable on the boundary fiber so we can access it in the\n    // commit phase.\n    //\n    // When the wakeable resolves, we'll attempt to render the boundary\n    // again (\"retry\").\n    var wakeables = suspenseBoundary.updateQueue;\n\n    if (wakeables === null) {\n      var updateQueue = new Set();\n      updateQueue.add(wakeable);\n      suspenseBoundary.updateQueue = updateQueue;\n    } else {\n      wakeables.add(wakeable);\n    }\n  }\n\n  function resetSuspendedComponent(sourceFiber, rootRenderLanes) {\n    // A legacy mode Suspense quirk, only relevant to hook components.\n\n\n    var tag = sourceFiber.tag;\n\n    if ((sourceFiber.mode & ConcurrentMode) === NoMode && (tag === FunctionComponent || tag === ForwardRef || tag === SimpleMemoComponent)) {\n      var currentSource = sourceFiber.alternate;\n\n      if (currentSource) {\n        sourceFiber.updateQueue = currentSource.updateQueue;\n        sourceFiber.memoizedState = currentSource.memoizedState;\n        sourceFiber.lanes = currentSource.lanes;\n      } else {\n        sourceFiber.updateQueue = null;\n        sourceFiber.memoizedState = null;\n      }\n    }\n  }\n\n  function getNearestSuspenseBoundaryToCapture(returnFiber) {\n    var node = returnFiber;\n\n    do {\n      if (node.tag === SuspenseComponent && shouldCaptureSuspense(node)) {\n        return node;\n      } // This boundary already captured during this render. Continue to the next\n      // boundary.\n\n\n      node = node.return;\n    } while (node !== null);\n\n    return null;\n  }\n\n  function markSuspenseBoundaryShouldCapture(suspenseBoundary, returnFiber, sourceFiber, root, rootRenderLanes) {\n    // This marks a Suspense boundary so that when we're unwinding the stack,\n    // it captures the suspended \"exception\" and does a second (fallback) pass.\n    if ((suspenseBoundary.mode & ConcurrentMode) === NoMode) {\n      // Legacy Mode Suspense\n      //\n      // If the boundary is in legacy mode, we should *not*\n      // suspend the commit. Pretend as if the suspended component rendered\n      // null and keep rendering. When the Suspense boundary completes,\n      // we'll do a second pass to render the fallback.\n      if (suspenseBoundary === returnFiber) {\n        // Special case where we suspended while reconciling the children of\n        // a Suspense boundary's inner Offscreen wrapper fiber. This happens\n        // when a React.lazy component is a direct child of a\n        // Suspense boundary.\n        //\n        // Suspense boundaries are implemented as multiple fibers, but they\n        // are a single conceptual unit. The legacy mode behavior where we\n        // pretend the suspended fiber committed as `null` won't work,\n        // because in this case the \"suspended\" fiber is the inner\n        // Offscreen wrapper.\n        //\n        // Because the contents of the boundary haven't started rendering\n        // yet (i.e. nothing in the tree has partially rendered) we can\n        // switch to the regular, concurrent mode behavior: mark the\n        // boundary with ShouldCapture and enter the unwind phase.\n        suspenseBoundary.flags |= ShouldCapture;\n      } else {\n        suspenseBoundary.flags |= DidCapture;\n        sourceFiber.flags |= ForceUpdateForLegacySuspense; // We're going to commit this fiber even though it didn't complete.\n        // But we shouldn't call any lifecycle methods or callbacks. Remove\n        // all lifecycle effect tags.\n\n        sourceFiber.flags &= ~(LifecycleEffectMask | Incomplete);\n\n        if (sourceFiber.tag === ClassComponent) {\n          var currentSourceFiber = sourceFiber.alternate;\n\n          if (currentSourceFiber === null) {\n            // This is a new mount. Change the tag so it's not mistaken for a\n            // completed class component. For example, we should not call\n            // componentWillUnmount if it is deleted.\n            sourceFiber.tag = IncompleteClassComponent;\n          } else {\n            // When we try rendering again, we should not reuse the current fiber,\n            // since it's known to be in an inconsistent state. Use a force update to\n            // prevent a bail out.\n            var update = createUpdate(NoTimestamp, SyncLane);\n            update.tag = ForceUpdate;\n            enqueueUpdate(sourceFiber, update, SyncLane);\n          }\n        } // The source fiber did not complete. Mark it with Sync priority to\n        // indicate that it still has pending work.\n\n\n        sourceFiber.lanes = mergeLanes(sourceFiber.lanes, SyncLane);\n      }\n\n      return suspenseBoundary;\n    } // Confirmed that the boundary is in a concurrent mode tree. Continue\n    // with the normal suspend path.\n    //\n    // After this we'll use a set of heuristics to determine whether this\n    // render pass will run to completion or restart or \"suspend\" the commit.\n    // The actual logic for this is spread out in different places.\n    //\n    // This first principle is that if we're going to suspend when we complete\n    // a root, then we should also restart if we get an update or ping that\n    // might unsuspend it, and vice versa. The only reason to suspend is\n    // because you think you might want to restart before committing. However,\n    // it doesn't make sense to restart only while in the period we're suspended.\n    //\n    // Restarting too aggressively is also not good because it starves out any\n    // intermediate loading state. So we use heuristics to determine when.\n    // Suspense Heuristics\n    //\n    // If nothing threw a Promise or all the same fallbacks are already showing,\n    // then don't suspend/restart.\n    //\n    // If this is an initial render of a new tree of Suspense boundaries and\n    // those trigger a fallback, then don't suspend/restart. We want to ensure\n    // that we can show the initial loading state as quickly as possible.\n    //\n    // If we hit a \"Delayed\" case, such as when we'd switch from content back into\n    // a fallback, then we should always suspend/restart. Transitions apply\n    // to this case. If none is defined, JND is used instead.\n    //\n    // If we're already showing a fallback and it gets \"retried\", allowing us to show\n    // another level, but there's still an inner boundary that would show a fallback,\n    // then we suspend/restart for 500ms since the last time we showed a fallback\n    // anywhere in the tree. This effectively throttles progressive loading into a\n    // consistent train of commits. This also gives us an opportunity to restart to\n    // get to the completed state slightly earlier.\n    //\n    // If there's ambiguity due to batching it's resolved in preference of:\n    // 1) \"delayed\", 2) \"initial render\", 3) \"retry\".\n    //\n    // We want to ensure that a \"busy\" state doesn't get force committed. We want to\n    // ensure that new initial loading states can commit as soon as possible.\n\n\n    suspenseBoundary.flags |= ShouldCapture; // TODO: I think we can remove this, since we now use `DidCapture` in\n    // the begin phase to prevent an early bailout.\n\n    suspenseBoundary.lanes = rootRenderLanes;\n    return suspenseBoundary;\n  }\n\n  function throwException(root, returnFiber, sourceFiber, value, rootRenderLanes) {\n    // The source fiber did not complete.\n    sourceFiber.flags |= Incomplete;\n\n    {\n      if (isDevToolsPresent) {\n        // If we have pending work still, restore the original updaters\n        restorePendingUpdaters(root, rootRenderLanes);\n      }\n    }\n\n    if (value !== null && typeof value === 'object' && typeof value.then === 'function') {\n      // This is a wakeable. The component suspended.\n      var wakeable = value;\n      resetSuspendedComponent(sourceFiber);\n\n      {\n        if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) {\n          markDidThrowWhileHydratingDEV();\n        }\n      }\n\n\n      var suspenseBoundary = getNearestSuspenseBoundaryToCapture(returnFiber);\n\n      if (suspenseBoundary !== null) {\n        suspenseBoundary.flags &= ~ForceClientRender;\n        markSuspenseBoundaryShouldCapture(suspenseBoundary, returnFiber, sourceFiber, root, rootRenderLanes); // We only attach ping listeners in concurrent mode. Legacy Suspense always\n        // commits fallbacks synchronously, so there are no pings.\n\n        if (suspenseBoundary.mode & ConcurrentMode) {\n          attachPingListener(root, wakeable, rootRenderLanes);\n        }\n\n        attachRetryListener(suspenseBoundary, root, wakeable);\n        return;\n      } else {\n        // No boundary was found. Unless this is a sync update, this is OK.\n        // We can suspend and wait for more data to arrive.\n        if (!includesSyncLane(rootRenderLanes)) {\n          // This is not a sync update. Suspend. Since we're not activating a\n          // Suspense boundary, this will unwind all the way to the root without\n          // performing a second pass to render a fallback. (This is arguably how\n          // refresh transitions should work, too, since we're not going to commit\n          // the fallbacks anyway.)\n          //\n          // This case also applies to initial hydration.\n          attachPingListener(root, wakeable, rootRenderLanes);\n          renderDidSuspendDelayIfPossible();\n          return;\n        } // This is a sync/discrete update. We treat this case like an error\n        // because discrete renders are expected to produce a complete tree\n        // synchronously to maintain consistency with external state.\n\n\n        var uncaughtSuspenseError = new Error('A component suspended while responding to synchronous input. This ' + 'will cause the UI to be replaced with a loading indicator. To ' + 'fix, updates that suspend should be wrapped ' + 'with startTransition.'); // If we're outside a transition, fall through to the regular error path.\n        // The error will be caught by the nearest suspense boundary.\n\n        value = uncaughtSuspenseError;\n      }\n    } else {\n      // This is a regular error, not a Suspense wakeable.\n      if (getIsHydrating() && sourceFiber.mode & ConcurrentMode) {\n        markDidThrowWhileHydratingDEV();\n\n        var _suspenseBoundary = getNearestSuspenseBoundaryToCapture(returnFiber); // If the error was thrown during hydration, we may be able to recover by\n        // discarding the dehydrated content and switching to a client render.\n        // Instead of surfacing the error, find the nearest Suspense boundary\n        // and render it again without hydration.\n\n\n        if (_suspenseBoundary !== null) {\n          if ((_suspenseBoundary.flags & ShouldCapture) === NoFlags) {\n            // Set a flag to indicate that we should try rendering the normal\n            // children again, not the fallback.\n            _suspenseBoundary.flags |= ForceClientRender;\n          }\n\n          markSuspenseBoundaryShouldCapture(_suspenseBoundary, returnFiber, sourceFiber, root, rootRenderLanes); // Even though the user may not be affected by this error, we should\n          // still log it so it can be fixed.\n\n          queueHydrationError(createCapturedValueAtFiber(value, sourceFiber));\n          return;\n        }\n      }\n    }\n\n    value = createCapturedValueAtFiber(value, sourceFiber);\n    renderDidError(value); // We didn't find a boundary that could handle this type of exception. Start\n    // over and traverse parent path again, this time treating the exception\n    // as an error.\n\n    var workInProgress = returnFiber;\n\n    do {\n      switch (workInProgress.tag) {\n        case HostRoot:\n          {\n            var _errorInfo = value;\n            workInProgress.flags |= ShouldCapture;\n            var lane = pickArbitraryLane(rootRenderLanes);\n            workInProgress.lanes = mergeLanes(workInProgress.lanes, lane);\n            var update = createRootErrorUpdate(workInProgress, _errorInfo, lane);\n            enqueueCapturedUpdate(workInProgress, update);\n            return;\n          }\n\n        case ClassComponent:\n          // Capture and retry\n          var errorInfo = value;\n          var ctor = workInProgress.type;\n          var instance = workInProgress.stateNode;\n\n          if ((workInProgress.flags & DidCapture) === NoFlags && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) {\n            workInProgress.flags |= ShouldCapture;\n\n            var _lane = pickArbitraryLane(rootRenderLanes);\n\n            workInProgress.lanes = mergeLanes(workInProgress.lanes, _lane); // Schedule the error boundary to re-render using updated state\n\n            var _update = createClassErrorUpdate(workInProgress, errorInfo, _lane);\n\n            enqueueCapturedUpdate(workInProgress, _update);\n            return;\n          }\n\n          break;\n      }\n\n      workInProgress = workInProgress.return;\n    } while (workInProgress !== null);\n  }\n\n  function getSuspendedCache() {\n    {\n      return null;\n    } // This function is called when a Suspense boundary suspends. It returns the\n  }\n\n  var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner;\n  var didReceiveUpdate = false;\n  var didWarnAboutBadClass;\n  var didWarnAboutModulePatternComponent;\n  var didWarnAboutContextTypeOnFunctionComponent;\n  var didWarnAboutGetDerivedStateOnFunctionComponent;\n  var didWarnAboutFunctionRefs;\n  var didWarnAboutReassigningProps;\n  var didWarnAboutRevealOrder;\n  var didWarnAboutTailOptions;\n  var didWarnAboutDefaultPropsOnFunctionComponent;\n\n  {\n    didWarnAboutBadClass = {};\n    didWarnAboutModulePatternComponent = {};\n    didWarnAboutContextTypeOnFunctionComponent = {};\n    didWarnAboutGetDerivedStateOnFunctionComponent = {};\n    didWarnAboutFunctionRefs = {};\n    didWarnAboutReassigningProps = false;\n    didWarnAboutRevealOrder = {};\n    didWarnAboutTailOptions = {};\n    didWarnAboutDefaultPropsOnFunctionComponent = {};\n  }\n\n  function reconcileChildren(current, workInProgress, nextChildren, renderLanes) {\n    if (current === null) {\n      // If this is a fresh new component that hasn't been rendered yet, we\n      // won't update its child set by applying minimal side-effects. Instead,\n      // we will add them all to the child before it gets rendered. That means\n      // we can optimize this reconciliation pass by not tracking side-effects.\n      workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderLanes);\n    } else {\n      // If the current child is the same as the work in progress, it means that\n      // we haven't yet started any work on these children. Therefore, we use\n      // the clone algorithm to create a copy of all the current children.\n      // If we had any progressed work already, that is invalid at this point so\n      // let's throw it out.\n      workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderLanes);\n    }\n  }\n\n  function forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderLanes) {\n    // This function is fork of reconcileChildren. It's used in cases where we\n    // want to reconcile without matching against the existing set. This has the\n    // effect of all current children being unmounted; even if the type and key\n    // are the same, the old child is unmounted and a new child is created.\n    //\n    // To do this, we're going to go through the reconcile algorithm twice. In\n    // the first pass, we schedule a deletion for all the current children by\n    // passing null.\n    workInProgress.child = reconcileChildFibers(workInProgress, current.child, null, renderLanes); // In the second pass, we mount the new children. The trick here is that we\n    // pass null in place of where we usually pass the current child set. This has\n    // the effect of remounting all children regardless of whether their\n    // identities match.\n\n    workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderLanes);\n  }\n\n  function updateForwardRef(current, workInProgress, Component, nextProps, renderLanes) {\n    // TODO: current can be non-null here even if the component\n    // hasn't yet mounted. This happens after the first render suspends.\n    // We'll need to figure out if this is fine or can cause issues.\n    {\n      if (workInProgress.type !== workInProgress.elementType) {\n        // Lazy component props can't be validated in createElement\n        // because they're only guaranteed to be resolved here.\n        var innerPropTypes = Component.propTypes;\n\n        if (innerPropTypes) {\n          checkPropTypes(innerPropTypes, nextProps, // Resolved props\n          'prop', getComponentNameFromType(Component));\n        }\n      }\n    }\n\n    var render = Component.render;\n    var ref = workInProgress.ref; // The rest is a fork of updateFunctionComponent\n\n    var nextChildren;\n    var hasId;\n    prepareToReadContext(workInProgress, renderLanes);\n\n    {\n      markComponentRenderStarted(workInProgress);\n    }\n\n    {\n      ReactCurrentOwner$1.current = workInProgress;\n      setIsRendering(true);\n      nextChildren = renderWithHooks(current, workInProgress, render, nextProps, ref, renderLanes);\n      hasId = checkDidRenderIdHook();\n\n      if ( workInProgress.mode & StrictLegacyMode) {\n        setIsStrictModeForDevtools(true);\n\n        try {\n          nextChildren = renderWithHooks(current, workInProgress, render, nextProps, ref, renderLanes);\n          hasId = checkDidRenderIdHook();\n        } finally {\n          setIsStrictModeForDevtools(false);\n        }\n      }\n\n      setIsRendering(false);\n    }\n\n    {\n      markComponentRenderStopped();\n    }\n\n    if (current !== null && !didReceiveUpdate) {\n      bailoutHooks(current, workInProgress, renderLanes);\n      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n    }\n\n    if (getIsHydrating() && hasId) {\n      pushMaterializedTreeId(workInProgress);\n    } // React DevTools reads this flag.\n\n\n    workInProgress.flags |= PerformedWork;\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function updateMemoComponent(current, workInProgress, Component, nextProps, renderLanes) {\n    if (current === null) {\n      var type = Component.type;\n\n      if (isSimpleFunctionComponent(type) && Component.compare === null && // SimpleMemoComponent codepath doesn't resolve outer props either.\n      Component.defaultProps === undefined) {\n        var resolvedType = type;\n\n        {\n          resolvedType = resolveFunctionForHotReloading(type);\n        } // If this is a plain function component without default props,\n        // and with only the default shallow comparison, we upgrade it\n        // to a SimpleMemoComponent to allow fast path updates.\n\n\n        workInProgress.tag = SimpleMemoComponent;\n        workInProgress.type = resolvedType;\n\n        {\n          validateFunctionComponentInDev(workInProgress, type);\n        }\n\n        return updateSimpleMemoComponent(current, workInProgress, resolvedType, nextProps, renderLanes);\n      }\n\n      {\n        var innerPropTypes = type.propTypes;\n\n        if (innerPropTypes) {\n          // Inner memo component props aren't currently validated in createElement.\n          // We could move it there, but we'd still need this for lazy code path.\n          checkPropTypes(innerPropTypes, nextProps, // Resolved props\n          'prop', getComponentNameFromType(type));\n        }\n\n        if ( Component.defaultProps !== undefined) {\n          var componentName = getComponentNameFromType(type) || 'Unknown';\n\n          if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {\n            error('%s: Support for defaultProps will be removed from memo components ' + 'in a future major release. Use JavaScript default parameters instead.', componentName);\n\n            didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;\n          }\n        }\n      }\n\n      var child = createFiberFromTypeAndProps(Component.type, null, nextProps, workInProgress, workInProgress.mode, renderLanes);\n      child.ref = workInProgress.ref;\n      child.return = workInProgress;\n      workInProgress.child = child;\n      return child;\n    }\n\n    {\n      var _type = Component.type;\n      var _innerPropTypes = _type.propTypes;\n\n      if (_innerPropTypes) {\n        // Inner memo component props aren't currently validated in createElement.\n        // We could move it there, but we'd still need this for lazy code path.\n        checkPropTypes(_innerPropTypes, nextProps, // Resolved props\n        'prop', getComponentNameFromType(_type));\n      }\n    }\n\n    var currentChild = current.child; // This is always exactly one child\n\n    var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(current, renderLanes);\n\n    if (!hasScheduledUpdateOrContext) {\n      // This will be the props with resolved defaultProps,\n      // unlike current.memoizedProps which will be the unresolved ones.\n      var prevProps = currentChild.memoizedProps; // Default to shallow comparison\n\n      var compare = Component.compare;\n      compare = compare !== null ? compare : shallowEqual;\n\n      if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {\n        return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n      }\n    } // React DevTools reads this flag.\n\n\n    workInProgress.flags |= PerformedWork;\n    var newChild = createWorkInProgress(currentChild, nextProps);\n    newChild.ref = workInProgress.ref;\n    newChild.return = workInProgress;\n    workInProgress.child = newChild;\n    return newChild;\n  }\n\n  function updateSimpleMemoComponent(current, workInProgress, Component, nextProps, renderLanes) {\n    // TODO: current can be non-null here even if the component\n    // hasn't yet mounted. This happens when the inner render suspends.\n    // We'll need to figure out if this is fine or can cause issues.\n    {\n      if (workInProgress.type !== workInProgress.elementType) {\n        // Lazy component props can't be validated in createElement\n        // because they're only guaranteed to be resolved here.\n        var outerMemoType = workInProgress.elementType;\n\n        if (outerMemoType.$$typeof === REACT_LAZY_TYPE) {\n          // We warn when you define propTypes on lazy()\n          // so let's just skip over it to find memo() outer wrapper.\n          // Inner props for memo are validated later.\n          var lazyComponent = outerMemoType;\n          var payload = lazyComponent._payload;\n          var init = lazyComponent._init;\n\n          try {\n            outerMemoType = init(payload);\n          } catch (x) {\n            outerMemoType = null;\n          } // Inner propTypes will be validated in the function component path.\n\n\n          var outerPropTypes = outerMemoType && outerMemoType.propTypes;\n\n          if (outerPropTypes) {\n            checkPropTypes(outerPropTypes, nextProps, // Resolved (SimpleMemoComponent has no defaultProps)\n            'prop', getComponentNameFromType(outerMemoType));\n          }\n        }\n      }\n    }\n\n    if (current !== null) {\n      var prevProps = current.memoizedProps;\n\n      if (shallowEqual(prevProps, nextProps) && current.ref === workInProgress.ref && ( // Prevent bailout if the implementation changed due to hot reload.\n       workInProgress.type === current.type )) {\n        didReceiveUpdate = false; // The props are shallowly equal. Reuse the previous props object, like we\n        // would during a normal fiber bailout.\n        //\n        // We don't have strong guarantees that the props object is referentially\n        // equal during updates where we can't bail out anyway — like if the props\n        // are shallowly equal, but there's a local state or context update in the\n        // same batch.\n        //\n        // However, as a principle, we should aim to make the behavior consistent\n        // across different ways of memoizing a component. For example, React.memo\n        // has a different internal Fiber layout if you pass a normal function\n        // component (SimpleMemoComponent) versus if you pass a different type\n        // like forwardRef (MemoComponent). But this is an implementation detail.\n        // Wrapping a component in forwardRef (or React.lazy, etc) shouldn't\n        // affect whether the props object is reused during a bailout.\n\n        workInProgress.pendingProps = nextProps = prevProps;\n\n        if (!checkScheduledUpdateOrContext(current, renderLanes)) {\n          // The pending lanes were cleared at the beginning of beginWork. We're\n          // about to bail out, but there might be other lanes that weren't\n          // included in the current render. Usually, the priority level of the\n          // remaining updates is accumulated during the evaluation of the\n          // component (i.e. when processing the update queue). But since since\n          // we're bailing out early *without* evaluating the component, we need\n          // to account for it here, too. Reset to the value of the current fiber.\n          // NOTE: This only applies to SimpleMemoComponent, not MemoComponent,\n          // because a MemoComponent fiber does not have hooks or an update queue;\n          // rather, it wraps around an inner component, which may or may not\n          // contains hooks.\n          // TODO: Move the reset at in beginWork out of the common path so that\n          // this is no longer necessary.\n          workInProgress.lanes = current.lanes;\n          return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n        } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {\n          // This is a special case that only exists for legacy mode.\n          // See https://github.com/facebook/react/pull/19216.\n          didReceiveUpdate = true;\n        }\n      }\n    }\n\n    return updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes);\n  }\n\n  function updateOffscreenComponent(current, workInProgress, renderLanes) {\n    var nextProps = workInProgress.pendingProps;\n    var nextChildren = nextProps.children;\n    var prevState = current !== null ? current.memoizedState : null;\n\n    if (nextProps.mode === 'hidden' || enableLegacyHidden ) {\n      // Rendering a hidden tree.\n      if ((workInProgress.mode & ConcurrentMode) === NoMode) {\n        // In legacy sync mode, don't defer the subtree. Render it now.\n        // TODO: Consider how Offscreen should work with transitions in the future\n        var nextState = {\n          baseLanes: NoLanes,\n          cachePool: null,\n          transitions: null\n        };\n        workInProgress.memoizedState = nextState;\n\n        pushRenderLanes(workInProgress, renderLanes);\n      } else if (!includesSomeLane(renderLanes, OffscreenLane)) {\n        var spawnedCachePool = null; // We're hidden, and we're not rendering at Offscreen. We will bail out\n        // and resume this tree later.\n\n        var nextBaseLanes;\n\n        if (prevState !== null) {\n          var prevBaseLanes = prevState.baseLanes;\n          nextBaseLanes = mergeLanes(prevBaseLanes, renderLanes);\n        } else {\n          nextBaseLanes = renderLanes;\n        } // Schedule this fiber to re-render at offscreen priority. Then bailout.\n\n\n        workInProgress.lanes = workInProgress.childLanes = laneToLanes(OffscreenLane);\n        var _nextState = {\n          baseLanes: nextBaseLanes,\n          cachePool: spawnedCachePool,\n          transitions: null\n        };\n        workInProgress.memoizedState = _nextState;\n        workInProgress.updateQueue = null;\n        // to avoid a push/pop misalignment.\n\n\n        pushRenderLanes(workInProgress, nextBaseLanes);\n\n        return null;\n      } else {\n        // This is the second render. The surrounding visible content has already\n        // committed. Now we resume rendering the hidden tree.\n        // Rendering at offscreen, so we can clear the base lanes.\n        var _nextState2 = {\n          baseLanes: NoLanes,\n          cachePool: null,\n          transitions: null\n        };\n        workInProgress.memoizedState = _nextState2; // Push the lanes that were skipped when we bailed out.\n\n        var subtreeRenderLanes = prevState !== null ? prevState.baseLanes : renderLanes;\n\n        pushRenderLanes(workInProgress, subtreeRenderLanes);\n      }\n    } else {\n      // Rendering a visible tree.\n      var _subtreeRenderLanes;\n\n      if (prevState !== null) {\n        // We're going from hidden -> visible.\n        _subtreeRenderLanes = mergeLanes(prevState.baseLanes, renderLanes);\n\n        workInProgress.memoizedState = null;\n      } else {\n        // We weren't previously hidden, and we still aren't, so there's nothing\n        // special to do. Need to push to the stack regardless, though, to avoid\n        // a push/pop misalignment.\n        _subtreeRenderLanes = renderLanes;\n      }\n\n      pushRenderLanes(workInProgress, _subtreeRenderLanes);\n    }\n\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  } // Note: These happen to have identical begin phases, for now. We shouldn't hold\n\n  function updateFragment(current, workInProgress, renderLanes) {\n    var nextChildren = workInProgress.pendingProps;\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function updateMode(current, workInProgress, renderLanes) {\n    var nextChildren = workInProgress.pendingProps.children;\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function updateProfiler(current, workInProgress, renderLanes) {\n    {\n      workInProgress.flags |= Update;\n\n      {\n        // Reset effect durations for the next eventual effect phase.\n        // These are reset during render to allow the DevTools commit hook a chance to read them,\n        var stateNode = workInProgress.stateNode;\n        stateNode.effectDuration = 0;\n        stateNode.passiveEffectDuration = 0;\n      }\n    }\n\n    var nextProps = workInProgress.pendingProps;\n    var nextChildren = nextProps.children;\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function markRef(current, workInProgress) {\n    var ref = workInProgress.ref;\n\n    if (current === null && ref !== null || current !== null && current.ref !== ref) {\n      // Schedule a Ref effect\n      workInProgress.flags |= Ref;\n\n      {\n        workInProgress.flags |= RefStatic;\n      }\n    }\n  }\n\n  function updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes) {\n    {\n      if (workInProgress.type !== workInProgress.elementType) {\n        // Lazy component props can't be validated in createElement\n        // because they're only guaranteed to be resolved here.\n        var innerPropTypes = Component.propTypes;\n\n        if (innerPropTypes) {\n          checkPropTypes(innerPropTypes, nextProps, // Resolved props\n          'prop', getComponentNameFromType(Component));\n        }\n      }\n    }\n\n    var context;\n\n    {\n      var unmaskedContext = getUnmaskedContext(workInProgress, Component, true);\n      context = getMaskedContext(workInProgress, unmaskedContext);\n    }\n\n    var nextChildren;\n    var hasId;\n    prepareToReadContext(workInProgress, renderLanes);\n\n    {\n      markComponentRenderStarted(workInProgress);\n    }\n\n    {\n      ReactCurrentOwner$1.current = workInProgress;\n      setIsRendering(true);\n      nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderLanes);\n      hasId = checkDidRenderIdHook();\n\n      if ( workInProgress.mode & StrictLegacyMode) {\n        setIsStrictModeForDevtools(true);\n\n        try {\n          nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderLanes);\n          hasId = checkDidRenderIdHook();\n        } finally {\n          setIsStrictModeForDevtools(false);\n        }\n      }\n\n      setIsRendering(false);\n    }\n\n    {\n      markComponentRenderStopped();\n    }\n\n    if (current !== null && !didReceiveUpdate) {\n      bailoutHooks(current, workInProgress, renderLanes);\n      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n    }\n\n    if (getIsHydrating() && hasId) {\n      pushMaterializedTreeId(workInProgress);\n    } // React DevTools reads this flag.\n\n\n    workInProgress.flags |= PerformedWork;\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function updateClassComponent(current, workInProgress, Component, nextProps, renderLanes) {\n    {\n      // This is used by DevTools to force a boundary to error.\n      switch (shouldError(workInProgress)) {\n        case false:\n          {\n            var _instance = workInProgress.stateNode;\n            var ctor = workInProgress.type; // TODO This way of resetting the error boundary state is a hack.\n            // Is there a better way to do this?\n\n            var tempInstance = new ctor(workInProgress.memoizedProps, _instance.context);\n            var state = tempInstance.state;\n\n            _instance.updater.enqueueSetState(_instance, state, null);\n\n            break;\n          }\n\n        case true:\n          {\n            workInProgress.flags |= DidCapture;\n            workInProgress.flags |= ShouldCapture; // eslint-disable-next-line react-internal/prod-error-codes\n\n            var error$1 = new Error('Simulated error coming from DevTools');\n            var lane = pickArbitraryLane(renderLanes);\n            workInProgress.lanes = mergeLanes(workInProgress.lanes, lane); // Schedule the error boundary to re-render using updated state\n\n            var update = createClassErrorUpdate(workInProgress, createCapturedValueAtFiber(error$1, workInProgress), lane);\n            enqueueCapturedUpdate(workInProgress, update);\n            break;\n          }\n      }\n\n      if (workInProgress.type !== workInProgress.elementType) {\n        // Lazy component props can't be validated in createElement\n        // because they're only guaranteed to be resolved here.\n        var innerPropTypes = Component.propTypes;\n\n        if (innerPropTypes) {\n          checkPropTypes(innerPropTypes, nextProps, // Resolved props\n          'prop', getComponentNameFromType(Component));\n        }\n      }\n    } // Push context providers early to prevent context stack mismatches.\n    // During mounting we don't know the child context yet as the instance doesn't exist.\n    // We will invalidate the child context in finishClassComponent() right after rendering.\n\n\n    var hasContext;\n\n    if (isContextProvider(Component)) {\n      hasContext = true;\n      pushContextProvider(workInProgress);\n    } else {\n      hasContext = false;\n    }\n\n    prepareToReadContext(workInProgress, renderLanes);\n    var instance = workInProgress.stateNode;\n    var shouldUpdate;\n\n    if (instance === null) {\n      resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress); // In the initial pass we might need to construct the instance.\n\n      constructClassInstance(workInProgress, Component, nextProps);\n      mountClassInstance(workInProgress, Component, nextProps, renderLanes);\n      shouldUpdate = true;\n    } else if (current === null) {\n      // In a resume, we'll already have an instance we can reuse.\n      shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderLanes);\n    } else {\n      shouldUpdate = updateClassInstance(current, workInProgress, Component, nextProps, renderLanes);\n    }\n\n    var nextUnitOfWork = finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes);\n\n    {\n      var inst = workInProgress.stateNode;\n\n      if (shouldUpdate && inst.props !== nextProps) {\n        if (!didWarnAboutReassigningProps) {\n          error('It looks like %s is reassigning its own `this.props` while rendering. ' + 'This is not supported and can lead to confusing bugs.', getComponentNameFromFiber(workInProgress) || 'a component');\n        }\n\n        didWarnAboutReassigningProps = true;\n      }\n    }\n\n    return nextUnitOfWork;\n  }\n\n  function finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes) {\n    // Refs should update even if shouldComponentUpdate returns false\n    markRef(current, workInProgress);\n    var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags;\n\n    if (!shouldUpdate && !didCaptureError) {\n      // Context providers should defer to sCU for rendering\n      if (hasContext) {\n        invalidateContextProvider(workInProgress, Component, false);\n      }\n\n      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n    }\n\n    var instance = workInProgress.stateNode; // Rerender\n\n    ReactCurrentOwner$1.current = workInProgress;\n    var nextChildren;\n\n    if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') {\n      // If we captured an error, but getDerivedStateFromError is not defined,\n      // unmount all the children. componentDidCatch will schedule an update to\n      // re-render a fallback. This is temporary until we migrate everyone to\n      // the new API.\n      // TODO: Warn in a future release.\n      nextChildren = null;\n\n      {\n        stopProfilerTimerIfRunning();\n      }\n    } else {\n      {\n        markComponentRenderStarted(workInProgress);\n      }\n\n      {\n        setIsRendering(true);\n        nextChildren = instance.render();\n\n        if ( workInProgress.mode & StrictLegacyMode) {\n          setIsStrictModeForDevtools(true);\n\n          try {\n            instance.render();\n          } finally {\n            setIsStrictModeForDevtools(false);\n          }\n        }\n\n        setIsRendering(false);\n      }\n\n      {\n        markComponentRenderStopped();\n      }\n    } // React DevTools reads this flag.\n\n\n    workInProgress.flags |= PerformedWork;\n\n    if (current !== null && didCaptureError) {\n      // If we're recovering from an error, reconcile without reusing any of\n      // the existing children. Conceptually, the normal children and the children\n      // that are shown on error are two different sets, so we shouldn't reuse\n      // normal children even if their identities match.\n      forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderLanes);\n    } else {\n      reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    } // Memoize state using the values we just used to render.\n    // TODO: Restructure so we never read values from the instance.\n\n\n    workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it.\n\n    if (hasContext) {\n      invalidateContextProvider(workInProgress, Component, true);\n    }\n\n    return workInProgress.child;\n  }\n\n  function pushHostRootContext(workInProgress) {\n    var root = workInProgress.stateNode;\n\n    if (root.pendingContext) {\n      pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context);\n    } else if (root.context) {\n      // Should always be set\n      pushTopLevelContextObject(workInProgress, root.context, false);\n    }\n\n    pushHostContainer(workInProgress, root.containerInfo);\n  }\n\n  function updateHostRoot(current, workInProgress, renderLanes) {\n    pushHostRootContext(workInProgress);\n\n    if (current === null) {\n      throw new Error('Should have a current fiber. This is a bug in React.');\n    }\n\n    var nextProps = workInProgress.pendingProps;\n    var prevState = workInProgress.memoizedState;\n    var prevChildren = prevState.element;\n    cloneUpdateQueue(current, workInProgress);\n    processUpdateQueue(workInProgress, nextProps, null, renderLanes);\n    var nextState = workInProgress.memoizedState;\n    var root = workInProgress.stateNode;\n    // being called \"element\".\n\n\n    var nextChildren = nextState.element;\n\n    if ( prevState.isDehydrated) {\n      // This is a hydration root whose shell has not yet hydrated. We should\n      // attempt to hydrate.\n      // Flip isDehydrated to false to indicate that when this render\n      // finishes, the root will no longer be dehydrated.\n      var overrideState = {\n        element: nextChildren,\n        isDehydrated: false,\n        cache: nextState.cache,\n        pendingSuspenseBoundaries: nextState.pendingSuspenseBoundaries,\n        transitions: nextState.transitions\n      };\n      var updateQueue = workInProgress.updateQueue; // `baseState` can always be the last state because the root doesn't\n      // have reducer functions so it doesn't need rebasing.\n\n      updateQueue.baseState = overrideState;\n      workInProgress.memoizedState = overrideState;\n\n      if (workInProgress.flags & ForceClientRender) {\n        // Something errored during a previous attempt to hydrate the shell, so we\n        // forced a client render.\n        var recoverableError = createCapturedValueAtFiber(new Error('There was an error while hydrating. Because the error happened outside ' + 'of a Suspense boundary, the entire root will switch to ' + 'client rendering.'), workInProgress);\n        return mountHostRootWithoutHydrating(current, workInProgress, nextChildren, renderLanes, recoverableError);\n      } else if (nextChildren !== prevChildren) {\n        var _recoverableError = createCapturedValueAtFiber(new Error('This root received an early update, before anything was able ' + 'hydrate. Switched the entire root to client rendering.'), workInProgress);\n\n        return mountHostRootWithoutHydrating(current, workInProgress, nextChildren, renderLanes, _recoverableError);\n      } else {\n        // The outermost shell has not hydrated yet. Start hydrating.\n        enterHydrationState(workInProgress);\n\n        var child = mountChildFibers(workInProgress, null, nextChildren, renderLanes);\n        workInProgress.child = child;\n        var node = child;\n\n        while (node) {\n          // Mark each child as hydrating. This is a fast path to know whether this\n          // tree is part of a hydrating tree. This is used to determine if a child\n          // node has fully mounted yet, and for scheduling event replaying.\n          // Conceptually this is similar to Placement in that a new subtree is\n          // inserted into the React tree here. It just happens to not need DOM\n          // mutations because it already exists.\n          node.flags = node.flags & ~Placement | Hydrating;\n          node = node.sibling;\n        }\n      }\n    } else {\n      // Root is not dehydrated. Either this is a client-only root, or it\n      // already hydrated.\n      resetHydrationState();\n\n      if (nextChildren === prevChildren) {\n        return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n      }\n\n      reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    }\n\n    return workInProgress.child;\n  }\n\n  function mountHostRootWithoutHydrating(current, workInProgress, nextChildren, renderLanes, recoverableError) {\n    // Revert to client rendering.\n    resetHydrationState();\n    queueHydrationError(recoverableError);\n    workInProgress.flags |= ForceClientRender;\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function updateHostComponent(current, workInProgress, renderLanes) {\n    pushHostContext(workInProgress);\n\n    if (current === null) {\n      tryToClaimNextHydratableInstance(workInProgress);\n    }\n\n    var type = workInProgress.type;\n    var nextProps = workInProgress.pendingProps;\n    var prevProps = current !== null ? current.memoizedProps : null;\n    var nextChildren = nextProps.children;\n    var isDirectTextChild = shouldSetTextContent(type, nextProps);\n\n    if (isDirectTextChild) {\n      // We special case a direct text child of a host node. This is a common\n      // case. We won't handle it as a reified child. We will instead handle\n      // this in the host environment that also has access to this prop. That\n      // avoids allocating another HostText fiber and traversing it.\n      nextChildren = null;\n    } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {\n      // If we're switching from a direct text child to a normal child, or to\n      // empty, we need to schedule the text content to be reset.\n      workInProgress.flags |= ContentReset;\n    }\n\n    markRef(current, workInProgress);\n    reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function updateHostText(current, workInProgress) {\n    if (current === null) {\n      tryToClaimNextHydratableInstance(workInProgress);\n    } // Nothing to do here. This is terminal. We'll do the completion step\n    // immediately after.\n\n\n    return null;\n  }\n\n  function mountLazyComponent(_current, workInProgress, elementType, renderLanes) {\n    resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress);\n    var props = workInProgress.pendingProps;\n    var lazyComponent = elementType;\n    var payload = lazyComponent._payload;\n    var init = lazyComponent._init;\n    var Component = init(payload); // Store the unwrapped component in the type.\n\n    workInProgress.type = Component;\n    var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component);\n    var resolvedProps = resolveDefaultProps(Component, props);\n    var child;\n\n    switch (resolvedTag) {\n      case FunctionComponent:\n        {\n          {\n            validateFunctionComponentInDev(workInProgress, Component);\n            workInProgress.type = Component = resolveFunctionForHotReloading(Component);\n          }\n\n          child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderLanes);\n          return child;\n        }\n\n      case ClassComponent:\n        {\n          {\n            workInProgress.type = Component = resolveClassForHotReloading(Component);\n          }\n\n          child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderLanes);\n          return child;\n        }\n\n      case ForwardRef:\n        {\n          {\n            workInProgress.type = Component = resolveForwardRefForHotReloading(Component);\n          }\n\n          child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderLanes);\n          return child;\n        }\n\n      case MemoComponent:\n        {\n          {\n            if (workInProgress.type !== workInProgress.elementType) {\n              var outerPropTypes = Component.propTypes;\n\n              if (outerPropTypes) {\n                checkPropTypes(outerPropTypes, resolvedProps, // Resolved for outer only\n                'prop', getComponentNameFromType(Component));\n              }\n            }\n          }\n\n          child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too\n          renderLanes);\n          return child;\n        }\n    }\n\n    var hint = '';\n\n    {\n      if (Component !== null && typeof Component === 'object' && Component.$$typeof === REACT_LAZY_TYPE) {\n        hint = ' Did you wrap a component in React.lazy() more than once?';\n      }\n    } // This message intentionally doesn't mention ForwardRef or MemoComponent\n    // because the fact that it's a separate type of work is an\n    // implementation detail.\n\n\n    throw new Error(\"Element type is invalid. Received a promise that resolves to: \" + Component + \". \" + (\"Lazy element type must resolve to a class or function.\" + hint));\n  }\n\n  function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderLanes) {\n    resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress); // Promote the fiber to a class and try rendering again.\n\n    workInProgress.tag = ClassComponent; // The rest of this function is a fork of `updateClassComponent`\n    // Push context providers early to prevent context stack mismatches.\n    // During mounting we don't know the child context yet as the instance doesn't exist.\n    // We will invalidate the child context in finishClassComponent() right after rendering.\n\n    var hasContext;\n\n    if (isContextProvider(Component)) {\n      hasContext = true;\n      pushContextProvider(workInProgress);\n    } else {\n      hasContext = false;\n    }\n\n    prepareToReadContext(workInProgress, renderLanes);\n    constructClassInstance(workInProgress, Component, nextProps);\n    mountClassInstance(workInProgress, Component, nextProps, renderLanes);\n    return finishClassComponent(null, workInProgress, Component, true, hasContext, renderLanes);\n  }\n\n  function mountIndeterminateComponent(_current, workInProgress, Component, renderLanes) {\n    resetSuspendedCurrentOnMountInLegacyMode(_current, workInProgress);\n    var props = workInProgress.pendingProps;\n    var context;\n\n    {\n      var unmaskedContext = getUnmaskedContext(workInProgress, Component, false);\n      context = getMaskedContext(workInProgress, unmaskedContext);\n    }\n\n    prepareToReadContext(workInProgress, renderLanes);\n    var value;\n    var hasId;\n\n    {\n      markComponentRenderStarted(workInProgress);\n    }\n\n    {\n      if (Component.prototype && typeof Component.prototype.render === 'function') {\n        var componentName = getComponentNameFromType(Component) || 'Unknown';\n\n        if (!didWarnAboutBadClass[componentName]) {\n          error(\"The <%s /> component appears to have a render method, but doesn't extend React.Component. \" + 'This is likely to cause errors. Change %s to extend React.Component instead.', componentName, componentName);\n\n          didWarnAboutBadClass[componentName] = true;\n        }\n      }\n\n      if (workInProgress.mode & StrictLegacyMode) {\n        ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);\n      }\n\n      setIsRendering(true);\n      ReactCurrentOwner$1.current = workInProgress;\n      value = renderWithHooks(null, workInProgress, Component, props, context, renderLanes);\n      hasId = checkDidRenderIdHook();\n      setIsRendering(false);\n    }\n\n    {\n      markComponentRenderStopped();\n    } // React DevTools reads this flag.\n\n\n    workInProgress.flags |= PerformedWork;\n\n    {\n      // Support for module components is deprecated and is removed behind a flag.\n      // Whether or not it would crash later, we want to show a good message in DEV first.\n      if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {\n        var _componentName = getComponentNameFromType(Component) || 'Unknown';\n\n        if (!didWarnAboutModulePatternComponent[_componentName]) {\n          error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + \"If you can't use a class try assigning the prototype on the function as a workaround. \" + \"`%s.prototype = React.Component.prototype`. Don't use an arrow function since it \" + 'cannot be called with `new` by React.', _componentName, _componentName, _componentName);\n\n          didWarnAboutModulePatternComponent[_componentName] = true;\n        }\n      }\n    }\n\n    if ( // Run these checks in production only if the flag is off.\n    // Eventually we'll delete this branch altogether.\n     typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {\n      {\n        var _componentName2 = getComponentNameFromType(Component) || 'Unknown';\n\n        if (!didWarnAboutModulePatternComponent[_componentName2]) {\n          error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + \"If you can't use a class try assigning the prototype on the function as a workaround. \" + \"`%s.prototype = React.Component.prototype`. Don't use an arrow function since it \" + 'cannot be called with `new` by React.', _componentName2, _componentName2, _componentName2);\n\n          didWarnAboutModulePatternComponent[_componentName2] = true;\n        }\n      } // Proceed under the assumption that this is a class instance\n\n\n      workInProgress.tag = ClassComponent; // Throw out any hooks that were used.\n\n      workInProgress.memoizedState = null;\n      workInProgress.updateQueue = null; // Push context providers early to prevent context stack mismatches.\n      // During mounting we don't know the child context yet as the instance doesn't exist.\n      // We will invalidate the child context in finishClassComponent() right after rendering.\n\n      var hasContext = false;\n\n      if (isContextProvider(Component)) {\n        hasContext = true;\n        pushContextProvider(workInProgress);\n      } else {\n        hasContext = false;\n      }\n\n      workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null;\n      initializeUpdateQueue(workInProgress);\n      adoptClassInstance(workInProgress, value);\n      mountClassInstance(workInProgress, Component, props, renderLanes);\n      return finishClassComponent(null, workInProgress, Component, true, hasContext, renderLanes);\n    } else {\n      // Proceed under the assumption that this is a function component\n      workInProgress.tag = FunctionComponent;\n\n      {\n\n        if ( workInProgress.mode & StrictLegacyMode) {\n          setIsStrictModeForDevtools(true);\n\n          try {\n            value = renderWithHooks(null, workInProgress, Component, props, context, renderLanes);\n            hasId = checkDidRenderIdHook();\n          } finally {\n            setIsStrictModeForDevtools(false);\n          }\n        }\n      }\n\n      if (getIsHydrating() && hasId) {\n        pushMaterializedTreeId(workInProgress);\n      }\n\n      reconcileChildren(null, workInProgress, value, renderLanes);\n\n      {\n        validateFunctionComponentInDev(workInProgress, Component);\n      }\n\n      return workInProgress.child;\n    }\n  }\n\n  function validateFunctionComponentInDev(workInProgress, Component) {\n    {\n      if (Component) {\n        if (Component.childContextTypes) {\n          error('%s(...): childContextTypes cannot be defined on a function component.', Component.displayName || Component.name || 'Component');\n        }\n      }\n\n      if (workInProgress.ref !== null) {\n        var info = '';\n        var ownerName = getCurrentFiberOwnerNameInDevOrNull();\n\n        if (ownerName) {\n          info += '\\n\\nCheck the render method of `' + ownerName + '`.';\n        }\n\n        var warningKey = ownerName || '';\n        var debugSource = workInProgress._debugSource;\n\n        if (debugSource) {\n          warningKey = debugSource.fileName + ':' + debugSource.lineNumber;\n        }\n\n        if (!didWarnAboutFunctionRefs[warningKey]) {\n          didWarnAboutFunctionRefs[warningKey] = true;\n\n          error('Function components cannot be given refs. ' + 'Attempts to access this ref will fail. ' + 'Did you mean to use React.forwardRef()?%s', info);\n        }\n      }\n\n      if ( Component.defaultProps !== undefined) {\n        var componentName = getComponentNameFromType(Component) || 'Unknown';\n\n        if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {\n          error('%s: Support for defaultProps will be removed from function components ' + 'in a future major release. Use JavaScript default parameters instead.', componentName);\n\n          didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;\n        }\n      }\n\n      if (typeof Component.getDerivedStateFromProps === 'function') {\n        var _componentName3 = getComponentNameFromType(Component) || 'Unknown';\n\n        if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) {\n          error('%s: Function components do not support getDerivedStateFromProps.', _componentName3);\n\n          didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true;\n        }\n      }\n\n      if (typeof Component.contextType === 'object' && Component.contextType !== null) {\n        var _componentName4 = getComponentNameFromType(Component) || 'Unknown';\n\n        if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) {\n          error('%s: Function components do not support contextType.', _componentName4);\n\n          didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true;\n        }\n      }\n    }\n  }\n\n  var SUSPENDED_MARKER = {\n    dehydrated: null,\n    treeContext: null,\n    retryLane: NoLane\n  };\n\n  function mountSuspenseOffscreenState(renderLanes) {\n    return {\n      baseLanes: renderLanes,\n      cachePool: getSuspendedCache(),\n      transitions: null\n    };\n  }\n\n  function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) {\n    var cachePool = null;\n\n    return {\n      baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes),\n      cachePool: cachePool,\n      transitions: prevOffscreenState.transitions\n    };\n  } // TODO: Probably should inline this back\n\n\n  function shouldRemainOnFallback(suspenseContext, current, workInProgress, renderLanes) {\n    // If we're already showing a fallback, there are cases where we need to\n    // remain on that fallback regardless of whether the content has resolved.\n    // For example, SuspenseList coordinates when nested content appears.\n    if (current !== null) {\n      var suspenseState = current.memoizedState;\n\n      if (suspenseState === null) {\n        // Currently showing content. Don't hide it, even if ForceSuspenseFallback\n        // is true. More precise name might be \"ForceRemainSuspenseFallback\".\n        // Note: This is a factoring smell. Can't remain on a fallback if there's\n        // no fallback to remain on.\n        return false;\n      }\n    } // Not currently showing content. Consult the Suspense context.\n\n\n    return hasSuspenseContext(suspenseContext, ForceSuspenseFallback);\n  }\n\n  function getRemainingWorkInPrimaryTree(current, renderLanes) {\n    // TODO: Should not remove render lanes that were pinged during this render\n    return removeLanes(current.childLanes, renderLanes);\n  }\n\n  function updateSuspenseComponent(current, workInProgress, renderLanes) {\n    var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend.\n\n    {\n      if (shouldSuspend(workInProgress)) {\n        workInProgress.flags |= DidCapture;\n      }\n    }\n\n    var suspenseContext = suspenseStackCursor.current;\n    var showFallback = false;\n    var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;\n\n    if (didSuspend || shouldRemainOnFallback(suspenseContext, current)) {\n      // Something in this boundary's subtree already suspended. Switch to\n      // rendering the fallback children.\n      showFallback = true;\n      workInProgress.flags &= ~DidCapture;\n    } else {\n      // Attempting the main content\n      if (current === null || current.memoizedState !== null) {\n        // This is a new mount or this boundary is already showing a fallback state.\n        // Mark this subtree context as having at least one invisible parent that could\n        // handle the fallback state.\n        // Avoided boundaries are not considered since they cannot handle preferred fallback states.\n        {\n          suspenseContext = addSubtreeSuspenseContext(suspenseContext, InvisibleParentSuspenseContext);\n        }\n      }\n    }\n\n    suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);\n    pushSuspenseContext(workInProgress, suspenseContext); // OK, the next part is confusing. We're about to reconcile the Suspense\n    // boundary's children. This involves some custom reconciliation logic. Two\n    // main reasons this is so complicated.\n    //\n    // First, Legacy Mode has different semantics for backwards compatibility. The\n    // primary tree will commit in an inconsistent state, so when we do the\n    // second pass to render the fallback, we do some exceedingly, uh, clever\n    // hacks to make that not totally break. Like transferring effects and\n    // deletions from hidden tree. In Concurrent Mode, it's much simpler,\n    // because we bailout on the primary tree completely and leave it in its old\n    // state, no effects. Same as what we do for Offscreen (except that\n    // Offscreen doesn't have the first render pass).\n    //\n    // Second is hydration. During hydration, the Suspense fiber has a slightly\n    // different layout, where the child points to a dehydrated fragment, which\n    // contains the DOM rendered by the server.\n    //\n    // Third, even if you set all that aside, Suspense is like error boundaries in\n    // that we first we try to render one tree, and if that fails, we render again\n    // and switch to a different tree. Like a try/catch block. So we have to track\n    // which branch we're currently rendering. Ideally we would model this using\n    // a stack.\n\n    if (current === null) {\n      // Initial mount\n      // Special path for hydration\n      // If we're currently hydrating, try to hydrate this boundary.\n      tryToClaimNextHydratableInstance(workInProgress); // This could've been a dehydrated suspense component.\n\n      var suspenseState = workInProgress.memoizedState;\n\n      if (suspenseState !== null) {\n        var dehydrated = suspenseState.dehydrated;\n\n        if (dehydrated !== null) {\n          return mountDehydratedSuspenseComponent(workInProgress, dehydrated);\n        }\n      }\n\n      var nextPrimaryChildren = nextProps.children;\n      var nextFallbackChildren = nextProps.fallback;\n\n      if (showFallback) {\n        var fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes);\n        var primaryChildFragment = workInProgress.child;\n        primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes);\n        workInProgress.memoizedState = SUSPENDED_MARKER;\n\n        return fallbackFragment;\n      } else {\n        return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren);\n      }\n    } else {\n      // This is an update.\n      // Special path for hydration\n      var prevState = current.memoizedState;\n\n      if (prevState !== null) {\n        var _dehydrated = prevState.dehydrated;\n\n        if (_dehydrated !== null) {\n          return updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, nextProps, _dehydrated, prevState, renderLanes);\n        }\n      }\n\n      if (showFallback) {\n        var _nextFallbackChildren = nextProps.fallback;\n        var _nextPrimaryChildren = nextProps.children;\n        var fallbackChildFragment = updateSuspenseFallbackChildren(current, workInProgress, _nextPrimaryChildren, _nextFallbackChildren, renderLanes);\n        var _primaryChildFragment2 = workInProgress.child;\n        var prevOffscreenState = current.child.memoizedState;\n        _primaryChildFragment2.memoizedState = prevOffscreenState === null ? mountSuspenseOffscreenState(renderLanes) : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);\n\n        _primaryChildFragment2.childLanes = getRemainingWorkInPrimaryTree(current, renderLanes);\n        workInProgress.memoizedState = SUSPENDED_MARKER;\n        return fallbackChildFragment;\n      } else {\n        var _nextPrimaryChildren2 = nextProps.children;\n\n        var _primaryChildFragment3 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren2, renderLanes);\n\n        workInProgress.memoizedState = null;\n        return _primaryChildFragment3;\n      }\n    }\n  }\n\n  function mountSuspensePrimaryChildren(workInProgress, primaryChildren, renderLanes) {\n    var mode = workInProgress.mode;\n    var primaryChildProps = {\n      mode: 'visible',\n      children: primaryChildren\n    };\n    var primaryChildFragment = mountWorkInProgressOffscreenFiber(primaryChildProps, mode);\n    primaryChildFragment.return = workInProgress;\n    workInProgress.child = primaryChildFragment;\n    return primaryChildFragment;\n  }\n\n  function mountSuspenseFallbackChildren(workInProgress, primaryChildren, fallbackChildren, renderLanes) {\n    var mode = workInProgress.mode;\n    var progressedPrimaryFragment = workInProgress.child;\n    var primaryChildProps = {\n      mode: 'hidden',\n      children: primaryChildren\n    };\n    var primaryChildFragment;\n    var fallbackChildFragment;\n\n    if ((mode & ConcurrentMode) === NoMode && progressedPrimaryFragment !== null) {\n      // In legacy mode, we commit the primary tree as if it successfully\n      // completed, even though it's in an inconsistent state.\n      primaryChildFragment = progressedPrimaryFragment;\n      primaryChildFragment.childLanes = NoLanes;\n      primaryChildFragment.pendingProps = primaryChildProps;\n\n      if ( workInProgress.mode & ProfileMode) {\n        // Reset the durations from the first pass so they aren't included in the\n        // final amounts. This seems counterintuitive, since we're intentionally\n        // not measuring part of the render phase, but this makes it match what we\n        // do in Concurrent Mode.\n        primaryChildFragment.actualDuration = 0;\n        primaryChildFragment.actualStartTime = -1;\n        primaryChildFragment.selfBaseDuration = 0;\n        primaryChildFragment.treeBaseDuration = 0;\n      }\n\n      fallbackChildFragment = createFiberFromFragment(fallbackChildren, mode, renderLanes, null);\n    } else {\n      primaryChildFragment = mountWorkInProgressOffscreenFiber(primaryChildProps, mode);\n      fallbackChildFragment = createFiberFromFragment(fallbackChildren, mode, renderLanes, null);\n    }\n\n    primaryChildFragment.return = workInProgress;\n    fallbackChildFragment.return = workInProgress;\n    primaryChildFragment.sibling = fallbackChildFragment;\n    workInProgress.child = primaryChildFragment;\n    return fallbackChildFragment;\n  }\n\n  function mountWorkInProgressOffscreenFiber(offscreenProps, mode, renderLanes) {\n    // The props argument to `createFiberFromOffscreen` is `any` typed, so we use\n    // this wrapper function to constrain it.\n    return createFiberFromOffscreen(offscreenProps, mode, NoLanes, null);\n  }\n\n  function updateWorkInProgressOffscreenFiber(current, offscreenProps) {\n    // The props argument to `createWorkInProgress` is `any` typed, so we use this\n    // wrapper function to constrain it.\n    return createWorkInProgress(current, offscreenProps);\n  }\n\n  function updateSuspensePrimaryChildren(current, workInProgress, primaryChildren, renderLanes) {\n    var currentPrimaryChildFragment = current.child;\n    var currentFallbackChildFragment = currentPrimaryChildFragment.sibling;\n    var primaryChildFragment = updateWorkInProgressOffscreenFiber(currentPrimaryChildFragment, {\n      mode: 'visible',\n      children: primaryChildren\n    });\n\n    if ((workInProgress.mode & ConcurrentMode) === NoMode) {\n      primaryChildFragment.lanes = renderLanes;\n    }\n\n    primaryChildFragment.return = workInProgress;\n    primaryChildFragment.sibling = null;\n\n    if (currentFallbackChildFragment !== null) {\n      // Delete the fallback child fragment\n      var deletions = workInProgress.deletions;\n\n      if (deletions === null) {\n        workInProgress.deletions = [currentFallbackChildFragment];\n        workInProgress.flags |= ChildDeletion;\n      } else {\n        deletions.push(currentFallbackChildFragment);\n      }\n    }\n\n    workInProgress.child = primaryChildFragment;\n    return primaryChildFragment;\n  }\n\n  function updateSuspenseFallbackChildren(current, workInProgress, primaryChildren, fallbackChildren, renderLanes) {\n    var mode = workInProgress.mode;\n    var currentPrimaryChildFragment = current.child;\n    var currentFallbackChildFragment = currentPrimaryChildFragment.sibling;\n    var primaryChildProps = {\n      mode: 'hidden',\n      children: primaryChildren\n    };\n    var primaryChildFragment;\n\n    if ( // In legacy mode, we commit the primary tree as if it successfully\n    // completed, even though it's in an inconsistent state.\n    (mode & ConcurrentMode) === NoMode && // Make sure we're on the second pass, i.e. the primary child fragment was\n    // already cloned. In legacy mode, the only case where this isn't true is\n    // when DevTools forces us to display a fallback; we skip the first render\n    // pass entirely and go straight to rendering the fallback. (In Concurrent\n    // Mode, SuspenseList can also trigger this scenario, but this is a legacy-\n    // only codepath.)\n    workInProgress.child !== currentPrimaryChildFragment) {\n      var progressedPrimaryFragment = workInProgress.child;\n      primaryChildFragment = progressedPrimaryFragment;\n      primaryChildFragment.childLanes = NoLanes;\n      primaryChildFragment.pendingProps = primaryChildProps;\n\n      if ( workInProgress.mode & ProfileMode) {\n        // Reset the durations from the first pass so they aren't included in the\n        // final amounts. This seems counterintuitive, since we're intentionally\n        // not measuring part of the render phase, but this makes it match what we\n        // do in Concurrent Mode.\n        primaryChildFragment.actualDuration = 0;\n        primaryChildFragment.actualStartTime = -1;\n        primaryChildFragment.selfBaseDuration = currentPrimaryChildFragment.selfBaseDuration;\n        primaryChildFragment.treeBaseDuration = currentPrimaryChildFragment.treeBaseDuration;\n      } // The fallback fiber was added as a deletion during the first pass.\n      // However, since we're going to remain on the fallback, we no longer want\n      // to delete it.\n\n\n      workInProgress.deletions = null;\n    } else {\n      primaryChildFragment = updateWorkInProgressOffscreenFiber(currentPrimaryChildFragment, primaryChildProps); // Since we're reusing a current tree, we need to reuse the flags, too.\n      // (We don't do this in legacy mode, because in legacy mode we don't re-use\n      // the current tree; see previous branch.)\n\n      primaryChildFragment.subtreeFlags = currentPrimaryChildFragment.subtreeFlags & StaticMask;\n    }\n\n    var fallbackChildFragment;\n\n    if (currentFallbackChildFragment !== null) {\n      fallbackChildFragment = createWorkInProgress(currentFallbackChildFragment, fallbackChildren);\n    } else {\n      fallbackChildFragment = createFiberFromFragment(fallbackChildren, mode, renderLanes, null); // Needs a placement effect because the parent (the Suspense boundary) already\n      // mounted but this is a new fiber.\n\n      fallbackChildFragment.flags |= Placement;\n    }\n\n    fallbackChildFragment.return = workInProgress;\n    primaryChildFragment.return = workInProgress;\n    primaryChildFragment.sibling = fallbackChildFragment;\n    workInProgress.child = primaryChildFragment;\n    return fallbackChildFragment;\n  }\n\n  function retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes, recoverableError) {\n    // Falling back to client rendering. Because this has performance\n    // implications, it's considered a recoverable error, even though the user\n    // likely won't observe anything wrong with the UI.\n    //\n    // The error is passed in as an argument to enforce that every caller provide\n    // a custom message, or explicitly opt out (currently the only path that opts\n    // out is legacy mode; every concurrent path provides an error).\n    if (recoverableError !== null) {\n      queueHydrationError(recoverableError);\n    } // This will add the old fiber to the deletion list\n\n\n    reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated.\n\n    var nextProps = workInProgress.pendingProps;\n    var primaryChildren = nextProps.children;\n    var primaryChildFragment = mountSuspensePrimaryChildren(workInProgress, primaryChildren); // Needs a placement effect because the parent (the Suspense boundary) already\n    // mounted but this is a new fiber.\n\n    primaryChildFragment.flags |= Placement;\n    workInProgress.memoizedState = null;\n    return primaryChildFragment;\n  }\n\n  function mountSuspenseFallbackAfterRetryWithoutHydrating(current, workInProgress, primaryChildren, fallbackChildren, renderLanes) {\n    var fiberMode = workInProgress.mode;\n    var primaryChildProps = {\n      mode: 'visible',\n      children: primaryChildren\n    };\n    var primaryChildFragment = mountWorkInProgressOffscreenFiber(primaryChildProps, fiberMode);\n    var fallbackChildFragment = createFiberFromFragment(fallbackChildren, fiberMode, renderLanes, null); // Needs a placement effect because the parent (the Suspense\n    // boundary) already mounted but this is a new fiber.\n\n    fallbackChildFragment.flags |= Placement;\n    primaryChildFragment.return = workInProgress;\n    fallbackChildFragment.return = workInProgress;\n    primaryChildFragment.sibling = fallbackChildFragment;\n    workInProgress.child = primaryChildFragment;\n\n    if ((workInProgress.mode & ConcurrentMode) !== NoMode) {\n      // We will have dropped the effect list which contains the\n      // deletion. We need to reconcile to delete the current child.\n      reconcileChildFibers(workInProgress, current.child, null, renderLanes);\n    }\n\n    return fallbackChildFragment;\n  }\n\n  function mountDehydratedSuspenseComponent(workInProgress, suspenseInstance, renderLanes) {\n    // During the first pass, we'll bail out and not drill into the children.\n    // Instead, we'll leave the content in place and try to hydrate it later.\n    if ((workInProgress.mode & ConcurrentMode) === NoMode) {\n      {\n        error('Cannot hydrate Suspense in legacy mode. Switch from ' + 'ReactDOM.hydrate(element, container) to ' + 'ReactDOMClient.hydrateRoot(container, <App />)' + '.render(element) or remove the Suspense components from ' + 'the server rendered components.');\n      }\n\n      workInProgress.lanes = laneToLanes(SyncLane);\n    } else if (isSuspenseInstanceFallback(suspenseInstance)) {\n      // This is a client-only boundary. Since we won't get any content from the server\n      // for this, we need to schedule that at a higher priority based on when it would\n      // have timed out. In theory we could render it in this pass but it would have the\n      // wrong priority associated with it and will prevent hydration of parent path.\n      // Instead, we'll leave work left on it to render it in a separate commit.\n      // TODO This time should be the time at which the server rendered response that is\n      // a parent to this boundary was displayed. However, since we currently don't have\n      // a protocol to transfer that time, we'll just estimate it by using the current\n      // time. This will mean that Suspense timeouts are slightly shifted to later than\n      // they should be.\n      // Schedule a normal pri update to render this content.\n      workInProgress.lanes = laneToLanes(DefaultHydrationLane);\n    } else {\n      // We'll continue hydrating the rest at offscreen priority since we'll already\n      // be showing the right content coming from the server, it is no rush.\n      workInProgress.lanes = laneToLanes(OffscreenLane);\n    }\n\n    return null;\n  }\n\n  function updateDehydratedSuspenseComponent(current, workInProgress, didSuspend, nextProps, suspenseInstance, suspenseState, renderLanes) {\n    if (!didSuspend) {\n      // This is the first render pass. Attempt to hydrate.\n      // We should never be hydrating at this point because it is the first pass,\n      // but after we've already committed once.\n      warnIfHydrating();\n\n      if ((workInProgress.mode & ConcurrentMode) === NoMode) {\n        return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes, // TODO: When we delete legacy mode, we should make this error argument\n        // required — every concurrent mode path that causes hydration to\n        // de-opt to client rendering should have an error message.\n        null);\n      }\n\n      if (isSuspenseInstanceFallback(suspenseInstance)) {\n        // This boundary is in a permanent fallback state. In this case, we'll never\n        // get an update and we'll never be able to hydrate the final content. Let's just try the\n        // client side render instead.\n        var digest, message, stack;\n\n        {\n          var _getSuspenseInstanceF = getSuspenseInstanceFallbackErrorDetails(suspenseInstance);\n\n          digest = _getSuspenseInstanceF.digest;\n          message = _getSuspenseInstanceF.message;\n          stack = _getSuspenseInstanceF.stack;\n        }\n\n        var error;\n\n        if (message) {\n          // eslint-disable-next-line react-internal/prod-error-codes\n          error = new Error(message);\n        } else {\n          error = new Error('The server could not finish this Suspense boundary, likely ' + 'due to an error during server rendering. Switched to ' + 'client rendering.');\n        }\n\n        var capturedValue = createCapturedValue(error, digest, stack);\n        return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes, capturedValue);\n      }\n      // any context has changed, we need to treat is as if the input might have changed.\n\n\n      var hasContextChanged = includesSomeLane(renderLanes, current.childLanes);\n\n      if (didReceiveUpdate || hasContextChanged) {\n        // This boundary has changed since the first render. This means that we are now unable to\n        // hydrate it. We might still be able to hydrate it using a higher priority lane.\n        var root = getWorkInProgressRoot();\n\n        if (root !== null) {\n          var attemptHydrationAtLane = getBumpedLaneForHydration(root, renderLanes);\n\n          if (attemptHydrationAtLane !== NoLane && attemptHydrationAtLane !== suspenseState.retryLane) {\n            // Intentionally mutating since this render will get interrupted. This\n            // is one of the very rare times where we mutate the current tree\n            // during the render phase.\n            suspenseState.retryLane = attemptHydrationAtLane; // TODO: Ideally this would inherit the event time of the current render\n\n            var eventTime = NoTimestamp;\n            enqueueConcurrentRenderForLane(current, attemptHydrationAtLane);\n            scheduleUpdateOnFiber(root, current, attemptHydrationAtLane, eventTime);\n          }\n        } // If we have scheduled higher pri work above, this will probably just abort the render\n        // since we now have higher priority work, but in case it doesn't, we need to prepare to\n        // render something, if we time out. Even if that requires us to delete everything and\n        // skip hydration.\n        // Delay having to do this as long as the suspense timeout allows us.\n\n\n        renderDidSuspendDelayIfPossible();\n\n        var _capturedValue = createCapturedValue(new Error('This Suspense boundary received an update before it finished ' + 'hydrating. This caused the boundary to switch to client rendering. ' + 'The usual way to fix this is to wrap the original update ' + 'in startTransition.'));\n\n        return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes, _capturedValue);\n      } else if (isSuspenseInstancePending(suspenseInstance)) {\n        // This component is still pending more data from the server, so we can't hydrate its\n        // content. We treat it as if this component suspended itself. It might seem as if\n        // we could just try to render it client-side instead. However, this will perform a\n        // lot of unnecessary work and is unlikely to complete since it often will suspend\n        // on missing data anyway. Additionally, the server might be able to render more\n        // than we can on the client yet. In that case we'd end up with more fallback states\n        // on the client than if we just leave it alone. If the server times out or errors\n        // these should update this boundary to the permanent Fallback state instead.\n        // Mark it as having captured (i.e. suspended).\n        workInProgress.flags |= DidCapture; // Leave the child in place. I.e. the dehydrated fragment.\n\n        workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result.\n\n        var retry = retryDehydratedSuspenseBoundary.bind(null, current);\n        registerSuspenseInstanceRetry(suspenseInstance, retry);\n        return null;\n      } else {\n        // This is the first attempt.\n        reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress, suspenseInstance, suspenseState.treeContext);\n        var primaryChildren = nextProps.children;\n        var primaryChildFragment = mountSuspensePrimaryChildren(workInProgress, primaryChildren); // Mark the children as hydrating. This is a fast path to know whether this\n        // tree is part of a hydrating tree. This is used to determine if a child\n        // node has fully mounted yet, and for scheduling event replaying.\n        // Conceptually this is similar to Placement in that a new subtree is\n        // inserted into the React tree here. It just happens to not need DOM\n        // mutations because it already exists.\n\n        primaryChildFragment.flags |= Hydrating;\n        return primaryChildFragment;\n      }\n    } else {\n      // This is the second render pass. We already attempted to hydrated, but\n      // something either suspended or errored.\n      if (workInProgress.flags & ForceClientRender) {\n        // Something errored during hydration. Try again without hydrating.\n        workInProgress.flags &= ~ForceClientRender;\n\n        var _capturedValue2 = createCapturedValue(new Error('There was an error while hydrating this Suspense boundary. ' + 'Switched to client rendering.'));\n\n        return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes, _capturedValue2);\n      } else if (workInProgress.memoizedState !== null) {\n        // Something suspended and we should still be in dehydrated mode.\n        // Leave the existing child in place.\n        workInProgress.child = current.child; // The dehydrated completion pass expects this flag to be there\n        // but the normal suspense pass doesn't.\n\n        workInProgress.flags |= DidCapture;\n        return null;\n      } else {\n        // Suspended but we should no longer be in dehydrated mode.\n        // Therefore we now have to render the fallback.\n        var nextPrimaryChildren = nextProps.children;\n        var nextFallbackChildren = nextProps.fallback;\n        var fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating(current, workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes);\n        var _primaryChildFragment4 = workInProgress.child;\n        _primaryChildFragment4.memoizedState = mountSuspenseOffscreenState(renderLanes);\n        workInProgress.memoizedState = SUSPENDED_MARKER;\n        return fallbackChildFragment;\n      }\n    }\n  }\n\n  function scheduleSuspenseWorkOnFiber(fiber, renderLanes, propagationRoot) {\n    fiber.lanes = mergeLanes(fiber.lanes, renderLanes);\n    var alternate = fiber.alternate;\n\n    if (alternate !== null) {\n      alternate.lanes = mergeLanes(alternate.lanes, renderLanes);\n    }\n\n    scheduleContextWorkOnParentPath(fiber.return, renderLanes, propagationRoot);\n  }\n\n  function propagateSuspenseContextChange(workInProgress, firstChild, renderLanes) {\n    // Mark any Suspense boundaries with fallbacks as having work to do.\n    // If they were previously forced into fallbacks, they may now be able\n    // to unblock.\n    var node = firstChild;\n\n    while (node !== null) {\n      if (node.tag === SuspenseComponent) {\n        var state = node.memoizedState;\n\n        if (state !== null) {\n          scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress);\n        }\n      } else if (node.tag === SuspenseListComponent) {\n        // If the tail is hidden there might not be an Suspense boundaries\n        // to schedule work on. In this case we have to schedule it on the\n        // list itself.\n        // We don't have to traverse to the children of the list since\n        // the list will propagate the change when it rerenders.\n        scheduleSuspenseWorkOnFiber(node, renderLanes, workInProgress);\n      } else if (node.child !== null) {\n        node.child.return = node;\n        node = node.child;\n        continue;\n      }\n\n      if (node === workInProgress) {\n        return;\n      }\n\n      while (node.sibling === null) {\n        if (node.return === null || node.return === workInProgress) {\n          return;\n        }\n\n        node = node.return;\n      }\n\n      node.sibling.return = node.return;\n      node = node.sibling;\n    }\n  }\n\n  function findLastContentRow(firstChild) {\n    // This is going to find the last row among these children that is already\n    // showing content on the screen, as opposed to being in fallback state or\n    // new. If a row has multiple Suspense boundaries, any of them being in the\n    // fallback state, counts as the whole row being in a fallback state.\n    // Note that the \"rows\" will be workInProgress, but any nested children\n    // will still be current since we haven't rendered them yet. The mounted\n    // order may not be the same as the new order. We use the new order.\n    var row = firstChild;\n    var lastContentRow = null;\n\n    while (row !== null) {\n      var currentRow = row.alternate; // New rows can't be content rows.\n\n      if (currentRow !== null && findFirstSuspended(currentRow) === null) {\n        lastContentRow = row;\n      }\n\n      row = row.sibling;\n    }\n\n    return lastContentRow;\n  }\n\n  function validateRevealOrder(revealOrder) {\n    {\n      if (revealOrder !== undefined && revealOrder !== 'forwards' && revealOrder !== 'backwards' && revealOrder !== 'together' && !didWarnAboutRevealOrder[revealOrder]) {\n        didWarnAboutRevealOrder[revealOrder] = true;\n\n        if (typeof revealOrder === 'string') {\n          switch (revealOrder.toLowerCase()) {\n            case 'together':\n            case 'forwards':\n            case 'backwards':\n              {\n                error('\"%s\" is not a valid value for revealOrder on <SuspenseList />. ' + 'Use lowercase \"%s\" instead.', revealOrder, revealOrder.toLowerCase());\n\n                break;\n              }\n\n            case 'forward':\n            case 'backward':\n              {\n                error('\"%s\" is not a valid value for revealOrder on <SuspenseList />. ' + 'React uses the -s suffix in the spelling. Use \"%ss\" instead.', revealOrder, revealOrder.toLowerCase());\n\n                break;\n              }\n\n            default:\n              error('\"%s\" is not a supported revealOrder on <SuspenseList />. ' + 'Did you mean \"together\", \"forwards\" or \"backwards\"?', revealOrder);\n\n              break;\n          }\n        } else {\n          error('%s is not a supported value for revealOrder on <SuspenseList />. ' + 'Did you mean \"together\", \"forwards\" or \"backwards\"?', revealOrder);\n        }\n      }\n    }\n  }\n\n  function validateTailOptions(tailMode, revealOrder) {\n    {\n      if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) {\n        if (tailMode !== 'collapsed' && tailMode !== 'hidden') {\n          didWarnAboutTailOptions[tailMode] = true;\n\n          error('\"%s\" is not a supported value for tail on <SuspenseList />. ' + 'Did you mean \"collapsed\" or \"hidden\"?', tailMode);\n        } else if (revealOrder !== 'forwards' && revealOrder !== 'backwards') {\n          didWarnAboutTailOptions[tailMode] = true;\n\n          error('<SuspenseList tail=\"%s\" /> is only valid if revealOrder is ' + '\"forwards\" or \"backwards\". ' + 'Did you mean to specify revealOrder=\"forwards\"?', tailMode);\n        }\n      }\n    }\n  }\n\n  function validateSuspenseListNestedChild(childSlot, index) {\n    {\n      var isAnArray = isArray(childSlot);\n      var isIterable = !isAnArray && typeof getIteratorFn(childSlot) === 'function';\n\n      if (isAnArray || isIterable) {\n        var type = isAnArray ? 'array' : 'iterable';\n\n        error('A nested %s was passed to row #%s in <SuspenseList />. Wrap it in ' + 'an additional SuspenseList to configure its revealOrder: ' + '<SuspenseList revealOrder=...> ... ' + '<SuspenseList revealOrder=...>{%s}</SuspenseList> ... ' + '</SuspenseList>', type, index, type);\n\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  function validateSuspenseListChildren(children, revealOrder) {\n    {\n      if ((revealOrder === 'forwards' || revealOrder === 'backwards') && children !== undefined && children !== null && children !== false) {\n        if (isArray(children)) {\n          for (var i = 0; i < children.length; i++) {\n            if (!validateSuspenseListNestedChild(children[i], i)) {\n              return;\n            }\n          }\n        } else {\n          var iteratorFn = getIteratorFn(children);\n\n          if (typeof iteratorFn === 'function') {\n            var childrenIterator = iteratorFn.call(children);\n\n            if (childrenIterator) {\n              var step = childrenIterator.next();\n              var _i = 0;\n\n              for (; !step.done; step = childrenIterator.next()) {\n                if (!validateSuspenseListNestedChild(step.value, _i)) {\n                  return;\n                }\n\n                _i++;\n              }\n            }\n          } else {\n            error('A single row was passed to a <SuspenseList revealOrder=\"%s\" />. ' + 'This is not useful since it needs multiple rows. ' + 'Did you mean to pass multiple children or an array?', revealOrder);\n          }\n        }\n      }\n    }\n  }\n\n  function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode) {\n    var renderState = workInProgress.memoizedState;\n\n    if (renderState === null) {\n      workInProgress.memoizedState = {\n        isBackwards: isBackwards,\n        rendering: null,\n        renderingStartTime: 0,\n        last: lastContentRow,\n        tail: tail,\n        tailMode: tailMode\n      };\n    } else {\n      // We can reuse the existing object from previous renders.\n      renderState.isBackwards = isBackwards;\n      renderState.rendering = null;\n      renderState.renderingStartTime = 0;\n      renderState.last = lastContentRow;\n      renderState.tail = tail;\n      renderState.tailMode = tailMode;\n    }\n  } // This can end up rendering this component multiple passes.\n  // The first pass splits the children fibers into two sets. A head and tail.\n  // We first render the head. If anything is in fallback state, we do another\n  // pass through beginWork to rerender all children (including the tail) with\n  // the force suspend context. If the first render didn't have anything in\n  // in fallback state. Then we render each row in the tail one-by-one.\n  // That happens in the completeWork phase without going back to beginWork.\n\n\n  function updateSuspenseListComponent(current, workInProgress, renderLanes) {\n    var nextProps = workInProgress.pendingProps;\n    var revealOrder = nextProps.revealOrder;\n    var tailMode = nextProps.tail;\n    var newChildren = nextProps.children;\n    validateRevealOrder(revealOrder);\n    validateTailOptions(tailMode, revealOrder);\n    validateSuspenseListChildren(newChildren, revealOrder);\n    reconcileChildren(current, workInProgress, newChildren, renderLanes);\n    var suspenseContext = suspenseStackCursor.current;\n    var shouldForceFallback = hasSuspenseContext(suspenseContext, ForceSuspenseFallback);\n\n    if (shouldForceFallback) {\n      suspenseContext = setShallowSuspenseContext(suspenseContext, ForceSuspenseFallback);\n      workInProgress.flags |= DidCapture;\n    } else {\n      var didSuspendBefore = current !== null && (current.flags & DidCapture) !== NoFlags;\n\n      if (didSuspendBefore) {\n        // If we previously forced a fallback, we need to schedule work\n        // on any nested boundaries to let them know to try to render\n        // again. This is the same as context updating.\n        propagateSuspenseContextChange(workInProgress, workInProgress.child, renderLanes);\n      }\n\n      suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);\n    }\n\n    pushSuspenseContext(workInProgress, suspenseContext);\n\n    if ((workInProgress.mode & ConcurrentMode) === NoMode) {\n      // In legacy mode, SuspenseList doesn't work so we just\n      // use make it a noop by treating it as the default revealOrder.\n      workInProgress.memoizedState = null;\n    } else {\n      switch (revealOrder) {\n        case 'forwards':\n          {\n            var lastContentRow = findLastContentRow(workInProgress.child);\n            var tail;\n\n            if (lastContentRow === null) {\n              // The whole list is part of the tail.\n              // TODO: We could fast path by just rendering the tail now.\n              tail = workInProgress.child;\n              workInProgress.child = null;\n            } else {\n              // Disconnect the tail rows after the content row.\n              // We're going to render them separately later.\n              tail = lastContentRow.sibling;\n              lastContentRow.sibling = null;\n            }\n\n            initSuspenseListRenderState(workInProgress, false, // isBackwards\n            tail, lastContentRow, tailMode);\n            break;\n          }\n\n        case 'backwards':\n          {\n            // We're going to find the first row that has existing content.\n            // At the same time we're going to reverse the list of everything\n            // we pass in the meantime. That's going to be our tail in reverse\n            // order.\n            var _tail = null;\n            var row = workInProgress.child;\n            workInProgress.child = null;\n\n            while (row !== null) {\n              var currentRow = row.alternate; // New rows can't be content rows.\n\n              if (currentRow !== null && findFirstSuspended(currentRow) === null) {\n                // This is the beginning of the main content.\n                workInProgress.child = row;\n                break;\n              }\n\n              var nextRow = row.sibling;\n              row.sibling = _tail;\n              _tail = row;\n              row = nextRow;\n            } // TODO: If workInProgress.child is null, we can continue on the tail immediately.\n\n\n            initSuspenseListRenderState(workInProgress, true, // isBackwards\n            _tail, null, // last\n            tailMode);\n            break;\n          }\n\n        case 'together':\n          {\n            initSuspenseListRenderState(workInProgress, false, // isBackwards\n            null, // tail\n            null, // last\n            undefined);\n            break;\n          }\n\n        default:\n          {\n            // The default reveal order is the same as not having\n            // a boundary.\n            workInProgress.memoizedState = null;\n          }\n      }\n    }\n\n    return workInProgress.child;\n  }\n\n  function updatePortalComponent(current, workInProgress, renderLanes) {\n    pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);\n    var nextChildren = workInProgress.pendingProps;\n\n    if (current === null) {\n      // Portals are special because we don't append the children during mount\n      // but at commit. Therefore we need to track insertions which the normal\n      // flow doesn't do during mount. This doesn't happen at the root because\n      // the root always starts with a \"current\" with a null child.\n      // TODO: Consider unifying this with how the root works.\n      workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderLanes);\n    } else {\n      reconcileChildren(current, workInProgress, nextChildren, renderLanes);\n    }\n\n    return workInProgress.child;\n  }\n\n  var hasWarnedAboutUsingNoValuePropOnContextProvider = false;\n\n  function updateContextProvider(current, workInProgress, renderLanes) {\n    var providerType = workInProgress.type;\n    var context = providerType._context;\n    var newProps = workInProgress.pendingProps;\n    var oldProps = workInProgress.memoizedProps;\n    var newValue = newProps.value;\n\n    {\n      if (!('value' in newProps)) {\n        if (!hasWarnedAboutUsingNoValuePropOnContextProvider) {\n          hasWarnedAboutUsingNoValuePropOnContextProvider = true;\n\n          error('The `value` prop is required for the `<Context.Provider>`. Did you misspell it or forget to pass it?');\n        }\n      }\n\n      var providerPropTypes = workInProgress.type.propTypes;\n\n      if (providerPropTypes) {\n        checkPropTypes(providerPropTypes, newProps, 'prop', 'Context.Provider');\n      }\n    }\n\n    pushProvider(workInProgress, context, newValue);\n\n    {\n      if (oldProps !== null) {\n        var oldValue = oldProps.value;\n\n        if (objectIs(oldValue, newValue)) {\n          // No change. Bailout early if children are the same.\n          if (oldProps.children === newProps.children && !hasContextChanged()) {\n            return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n          }\n        } else {\n          // The context value changed. Search for matching consumers and schedule\n          // them to update.\n          propagateContextChange(workInProgress, context, renderLanes);\n        }\n      }\n    }\n\n    var newChildren = newProps.children;\n    reconcileChildren(current, workInProgress, newChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  var hasWarnedAboutUsingContextAsConsumer = false;\n\n  function updateContextConsumer(current, workInProgress, renderLanes) {\n    var context = workInProgress.type; // The logic below for Context differs depending on PROD or DEV mode. In\n    // DEV mode, we create a separate object for Context.Consumer that acts\n    // like a proxy to Context. This proxy object adds unnecessary code in PROD\n    // so we use the old behaviour (Context.Consumer references Context) to\n    // reduce size and overhead. The separate object references context via\n    // a property called \"_context\", which also gives us the ability to check\n    // in DEV mode if this property exists or not and warn if it does not.\n\n    {\n      if (context._context === undefined) {\n        // This may be because it's a Context (rather than a Consumer).\n        // Or it may be because it's older React where they're the same thing.\n        // We only want to warn if we're sure it's a new React.\n        if (context !== context.Consumer) {\n          if (!hasWarnedAboutUsingContextAsConsumer) {\n            hasWarnedAboutUsingContextAsConsumer = true;\n\n            error('Rendering <Context> directly is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Consumer> instead?');\n          }\n        }\n      } else {\n        context = context._context;\n      }\n    }\n\n    var newProps = workInProgress.pendingProps;\n    var render = newProps.children;\n\n    {\n      if (typeof render !== 'function') {\n        error('A context consumer was rendered with multiple children, or a child ' + \"that isn't a function. A context consumer expects a single child \" + 'that is a function. If you did pass a function, make sure there ' + 'is no trailing or leading whitespace around it.');\n      }\n    }\n\n    prepareToReadContext(workInProgress, renderLanes);\n    var newValue = readContext(context);\n\n    {\n      markComponentRenderStarted(workInProgress);\n    }\n\n    var newChildren;\n\n    {\n      ReactCurrentOwner$1.current = workInProgress;\n      setIsRendering(true);\n      newChildren = render(newValue);\n      setIsRendering(false);\n    }\n\n    {\n      markComponentRenderStopped();\n    } // React DevTools reads this flag.\n\n\n    workInProgress.flags |= PerformedWork;\n    reconcileChildren(current, workInProgress, newChildren, renderLanes);\n    return workInProgress.child;\n  }\n\n  function markWorkInProgressReceivedUpdate() {\n    didReceiveUpdate = true;\n  }\n\n  function resetSuspendedCurrentOnMountInLegacyMode(current, workInProgress) {\n    if ((workInProgress.mode & ConcurrentMode) === NoMode) {\n      if (current !== null) {\n        // A lazy component only mounts if it suspended inside a non-\n        // concurrent tree, in an inconsistent state. We want to treat it like\n        // a new mount, even though an empty version of it already committed.\n        // Disconnect the alternate pointers.\n        current.alternate = null;\n        workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect\n\n        workInProgress.flags |= Placement;\n      }\n    }\n  }\n\n  function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) {\n    if (current !== null) {\n      // Reuse previous dependencies\n      workInProgress.dependencies = current.dependencies;\n    }\n\n    {\n      // Don't update \"base\" render times for bailouts.\n      stopProfilerTimerIfRunning();\n    }\n\n    markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work.\n\n    if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {\n      // The children don't have any work either. We can skip them.\n      // TODO: Once we add back resuming, we should check if the children are\n      // a work-in-progress set. If so, we need to transfer their effects.\n      {\n        return null;\n      }\n    } // This fiber doesn't have work, but its subtree does. Clone the child\n    // fibers and continue.\n\n\n    cloneChildFibers(current, workInProgress);\n    return workInProgress.child;\n  }\n\n  function remountFiber(current, oldWorkInProgress, newWorkInProgress) {\n    {\n      var returnFiber = oldWorkInProgress.return;\n\n      if (returnFiber === null) {\n        // eslint-disable-next-line react-internal/prod-error-codes\n        throw new Error('Cannot swap the root fiber.');\n      } // Disconnect from the old current.\n      // It will get deleted.\n\n\n      current.alternate = null;\n      oldWorkInProgress.alternate = null; // Connect to the new tree.\n\n      newWorkInProgress.index = oldWorkInProgress.index;\n      newWorkInProgress.sibling = oldWorkInProgress.sibling;\n      newWorkInProgress.return = oldWorkInProgress.return;\n      newWorkInProgress.ref = oldWorkInProgress.ref; // Replace the child/sibling pointers above it.\n\n      if (oldWorkInProgress === returnFiber.child) {\n        returnFiber.child = newWorkInProgress;\n      } else {\n        var prevSibling = returnFiber.child;\n\n        if (prevSibling === null) {\n          // eslint-disable-next-line react-internal/prod-error-codes\n          throw new Error('Expected parent to have a child.');\n        }\n\n        while (prevSibling.sibling !== oldWorkInProgress) {\n          prevSibling = prevSibling.sibling;\n\n          if (prevSibling === null) {\n            // eslint-disable-next-line react-internal/prod-error-codes\n            throw new Error('Expected to find the previous sibling.');\n          }\n        }\n\n        prevSibling.sibling = newWorkInProgress;\n      } // Delete the old fiber and place the new one.\n      // Since the old fiber is disconnected, we have to schedule it manually.\n\n\n      var deletions = returnFiber.deletions;\n\n      if (deletions === null) {\n        returnFiber.deletions = [current];\n        returnFiber.flags |= ChildDeletion;\n      } else {\n        deletions.push(current);\n      }\n\n      newWorkInProgress.flags |= Placement; // Restart work from the new fiber.\n\n      return newWorkInProgress;\n    }\n  }\n\n  function checkScheduledUpdateOrContext(current, renderLanes) {\n    // Before performing an early bailout, we must check if there are pending\n    // updates or context.\n    var updateLanes = current.lanes;\n\n    if (includesSomeLane(updateLanes, renderLanes)) {\n      return true;\n    } // No pending update, but because context is propagated lazily, we need\n\n    return false;\n  }\n\n  function attemptEarlyBailoutIfNoScheduledUpdate(current, workInProgress, renderLanes) {\n    // This fiber does not have any pending work. Bailout without entering\n    // the begin phase. There's still some bookkeeping we that needs to be done\n    // in this optimized path, mostly pushing stuff onto the stack.\n    switch (workInProgress.tag) {\n      case HostRoot:\n        pushHostRootContext(workInProgress);\n        var root = workInProgress.stateNode;\n\n        resetHydrationState();\n        break;\n\n      case HostComponent:\n        pushHostContext(workInProgress);\n        break;\n\n      case ClassComponent:\n        {\n          var Component = workInProgress.type;\n\n          if (isContextProvider(Component)) {\n            pushContextProvider(workInProgress);\n          }\n\n          break;\n        }\n\n      case HostPortal:\n        pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);\n        break;\n\n      case ContextProvider:\n        {\n          var newValue = workInProgress.memoizedProps.value;\n          var context = workInProgress.type._context;\n          pushProvider(workInProgress, context, newValue);\n          break;\n        }\n\n      case Profiler:\n        {\n          // Profiler should only call onRender when one of its descendants actually rendered.\n          var hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes);\n\n          if (hasChildWork) {\n            workInProgress.flags |= Update;\n          }\n\n          {\n            // Reset effect durations for the next eventual effect phase.\n            // These are reset during render to allow the DevTools commit hook a chance to read them,\n            var stateNode = workInProgress.stateNode;\n            stateNode.effectDuration = 0;\n            stateNode.passiveEffectDuration = 0;\n          }\n        }\n\n        break;\n\n      case SuspenseComponent:\n        {\n          var state = workInProgress.memoizedState;\n\n          if (state !== null) {\n            if (state.dehydrated !== null) {\n              pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current)); // We know that this component will suspend again because if it has\n              // been unsuspended it has committed as a resolved Suspense component.\n              // If it needs to be retried, it should have work scheduled on it.\n\n              workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we\n              // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork.\n\n              return null;\n            } // If this boundary is currently timed out, we need to decide\n            // whether to retry the primary children, or to skip over it and\n            // go straight to the fallback. Check the priority of the primary\n            // child fragment.\n\n\n            var primaryChildFragment = workInProgress.child;\n            var primaryChildLanes = primaryChildFragment.childLanes;\n\n            if (includesSomeLane(renderLanes, primaryChildLanes)) {\n              // The primary children have pending work. Use the normal path\n              // to attempt to render the primary children again.\n              return updateSuspenseComponent(current, workInProgress, renderLanes);\n            } else {\n              // The primary child fragment does not have pending work marked\n              // on it\n              pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current)); // The primary children do not have pending work with sufficient\n              // priority. Bailout.\n\n              var child = bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n\n              if (child !== null) {\n                // The fallback children have pending work. Skip over the\n                // primary children and work on the fallback.\n                return child.sibling;\n              } else {\n                // Note: We can return `null` here because we already checked\n                // whether there were nested context consumers, via the call to\n                // `bailoutOnAlreadyFinishedWork` above.\n                return null;\n              }\n            }\n          } else {\n            pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current));\n          }\n\n          break;\n        }\n\n      case SuspenseListComponent:\n        {\n          var didSuspendBefore = (current.flags & DidCapture) !== NoFlags;\n\n          var _hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes);\n\n          if (didSuspendBefore) {\n            if (_hasChildWork) {\n              // If something was in fallback state last time, and we have all the\n              // same children then we're still in progressive loading state.\n              // Something might get unblocked by state updates or retries in the\n              // tree which will affect the tail. So we need to use the normal\n              // path to compute the correct tail.\n              return updateSuspenseListComponent(current, workInProgress, renderLanes);\n            } // If none of the children had any work, that means that none of\n            // them got retried so they'll still be blocked in the same way\n            // as before. We can fast bail out.\n\n\n            workInProgress.flags |= DidCapture;\n          } // If nothing suspended before and we're rendering the same children,\n          // then the tail doesn't matter. Anything new that suspends will work\n          // in the \"together\" mode, so we can continue from the state we had.\n\n\n          var renderState = workInProgress.memoizedState;\n\n          if (renderState !== null) {\n            // Reset to the \"together\" mode in case we've started a different\n            // update in the past but didn't complete it.\n            renderState.rendering = null;\n            renderState.tail = null;\n            renderState.lastEffect = null;\n          }\n\n          pushSuspenseContext(workInProgress, suspenseStackCursor.current);\n\n          if (_hasChildWork) {\n            break;\n          } else {\n            // If none of the children had any work, that means that none of\n            // them got retried so they'll still be blocked in the same way\n            // as before. We can fast bail out.\n            return null;\n          }\n        }\n\n      case OffscreenComponent:\n      case LegacyHiddenComponent:\n        {\n          // Need to check if the tree still needs to be deferred. This is\n          // almost identical to the logic used in the normal update path,\n          // so we'll just enter that. The only difference is we'll bail out\n          // at the next level instead of this one, because the child props\n          // have not changed. Which is fine.\n          // TODO: Probably should refactor `beginWork` to split the bailout\n          // path from the normal path. I'm tempted to do a labeled break here\n          // but I won't :)\n          workInProgress.lanes = NoLanes;\n          return updateOffscreenComponent(current, workInProgress, renderLanes);\n        }\n    }\n\n    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);\n  }\n\n  function beginWork(current, workInProgress, renderLanes) {\n    {\n      if (workInProgress._debugNeedsRemount && current !== null) {\n        // This will restart the begin phase with a new fiber.\n        return remountFiber(current, workInProgress, createFiberFromTypeAndProps(workInProgress.type, workInProgress.key, workInProgress.pendingProps, workInProgress._debugOwner || null, workInProgress.mode, workInProgress.lanes));\n      }\n    }\n\n    if (current !== null) {\n      var oldProps = current.memoizedProps;\n      var newProps = workInProgress.pendingProps;\n\n      if (oldProps !== newProps || hasContextChanged() || ( // Force a re-render if the implementation changed due to hot reload:\n       workInProgress.type !== current.type )) {\n        // If props or context changed, mark the fiber as having performed work.\n        // This may be unset if the props are determined to be equal later (memo).\n        didReceiveUpdate = true;\n      } else {\n        // Neither props nor legacy context changes. Check if there's a pending\n        // update or context change.\n        var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(current, renderLanes);\n\n        if (!hasScheduledUpdateOrContext && // If this is the second pass of an error or suspense boundary, there\n        // may not be work scheduled on `current`, so we check for this flag.\n        (workInProgress.flags & DidCapture) === NoFlags) {\n          // No pending updates or context. Bail out now.\n          didReceiveUpdate = false;\n          return attemptEarlyBailoutIfNoScheduledUpdate(current, workInProgress, renderLanes);\n        }\n\n        if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {\n          // This is a special case that only exists for legacy mode.\n          // See https://github.com/facebook/react/pull/19216.\n          didReceiveUpdate = true;\n        } else {\n          // An update was scheduled on this fiber, but there are no new props\n          // nor legacy context. Set this to false. If an update queue or context\n          // consumer produces a changed value, it will set this to true. Otherwise,\n          // the component will assume the children have not changed and bail out.\n          didReceiveUpdate = false;\n        }\n      }\n    } else {\n      didReceiveUpdate = false;\n\n      if (getIsHydrating() && isForkedChild(workInProgress)) {\n        // Check if this child belongs to a list of muliple children in\n        // its parent.\n        //\n        // In a true multi-threaded implementation, we would render children on\n        // parallel threads. This would represent the beginning of a new render\n        // thread for this subtree.\n        //\n        // We only use this for id generation during hydration, which is why the\n        // logic is located in this special branch.\n        var slotIndex = workInProgress.index;\n        var numberOfForks = getForksAtLevel();\n        pushTreeId(workInProgress, numberOfForks, slotIndex);\n      }\n    } // Before entering the begin phase, clear pending update priority.\n    // TODO: This assumes that we're about to evaluate the component and process\n    // the update queue. However, there's an exception: SimpleMemoComponent\n    // sometimes bails out later in the begin phase. This indicates that we should\n    // move this assignment out of the common path and into each branch.\n\n\n    workInProgress.lanes = NoLanes;\n\n    switch (workInProgress.tag) {\n      case IndeterminateComponent:\n        {\n          return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderLanes);\n        }\n\n      case LazyComponent:\n        {\n          var elementType = workInProgress.elementType;\n          return mountLazyComponent(current, workInProgress, elementType, renderLanes);\n        }\n\n      case FunctionComponent:\n        {\n          var Component = workInProgress.type;\n          var unresolvedProps = workInProgress.pendingProps;\n          var resolvedProps = workInProgress.elementType === Component ? unresolvedProps : resolveDefaultProps(Component, unresolvedProps);\n          return updateFunctionComponent(current, workInProgress, Component, resolvedProps, renderLanes);\n        }\n\n      case ClassComponent:\n        {\n          var _Component = workInProgress.type;\n          var _unresolvedProps = workInProgress.pendingProps;\n\n          var _resolvedProps = workInProgress.elementType === _Component ? _unresolvedProps : resolveDefaultProps(_Component, _unresolvedProps);\n\n          return updateClassComponent(current, workInProgress, _Component, _resolvedProps, renderLanes);\n        }\n\n      case HostRoot:\n        return updateHostRoot(current, workInProgress, renderLanes);\n\n      case HostComponent:\n        return updateHostComponent(current, workInProgress, renderLanes);\n\n      case HostText:\n        return updateHostText(current, workInProgress);\n\n      case SuspenseComponent:\n        return updateSuspenseComponent(current, workInProgress, renderLanes);\n\n      case HostPortal:\n        return updatePortalComponent(current, workInProgress, renderLanes);\n\n      case ForwardRef:\n        {\n          var type = workInProgress.type;\n          var _unresolvedProps2 = workInProgress.pendingProps;\n\n          var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);\n\n          return updateForwardRef(current, workInProgress, type, _resolvedProps2, renderLanes);\n        }\n\n      case Fragment:\n        return updateFragment(current, workInProgress, renderLanes);\n\n      case Mode:\n        return updateMode(current, workInProgress, renderLanes);\n\n      case Profiler:\n        return updateProfiler(current, workInProgress, renderLanes);\n\n      case ContextProvider:\n        return updateContextProvider(current, workInProgress, renderLanes);\n\n      case ContextConsumer:\n        return updateContextConsumer(current, workInProgress, renderLanes);\n\n      case MemoComponent:\n        {\n          var _type2 = workInProgress.type;\n          var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props.\n\n          var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3);\n\n          {\n            if (workInProgress.type !== workInProgress.elementType) {\n              var outerPropTypes = _type2.propTypes;\n\n              if (outerPropTypes) {\n                checkPropTypes(outerPropTypes, _resolvedProps3, // Resolved for outer only\n                'prop', getComponentNameFromType(_type2));\n              }\n            }\n          }\n\n          _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3);\n          return updateMemoComponent(current, workInProgress, _type2, _resolvedProps3, renderLanes);\n        }\n\n      case SimpleMemoComponent:\n        {\n          return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, renderLanes);\n        }\n\n      case IncompleteClassComponent:\n        {\n          var _Component2 = workInProgress.type;\n          var _unresolvedProps4 = workInProgress.pendingProps;\n\n          var _resolvedProps4 = workInProgress.elementType === _Component2 ? _unresolvedProps4 : resolveDefaultProps(_Component2, _unresolvedProps4);\n\n          return mountIncompleteClassComponent(current, workInProgress, _Component2, _resolvedProps4, renderLanes);\n        }\n\n      case SuspenseListComponent:\n        {\n          return updateSuspenseListComponent(current, workInProgress, renderLanes);\n        }\n\n      case ScopeComponent:\n        {\n\n          break;\n        }\n\n      case OffscreenComponent:\n        {\n          return updateOffscreenComponent(current, workInProgress, renderLanes);\n        }\n    }\n\n    throw new Error(\"Unknown unit of work tag (\" + workInProgress.tag + \"). This error is likely caused by a bug in \" + 'React. Please file an issue.');\n  }\n\n  function markUpdate(workInProgress) {\n    // Tag the fiber with an update effect. This turns a Placement into\n    // a PlacementAndUpdate.\n    workInProgress.flags |= Update;\n  }\n\n  function markRef$1(workInProgress) {\n    workInProgress.flags |= Ref;\n\n    {\n      workInProgress.flags |= RefStatic;\n    }\n  }\n\n  var appendAllChildren;\n  var updateHostContainer;\n  var updateHostComponent$1;\n  var updateHostText$1;\n\n  {\n    // Mutation mode\n    appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) {\n      // We only have the top Fiber that was created but we need recurse down its\n      // children to find all the terminal nodes.\n      var node = workInProgress.child;\n\n      while (node !== null) {\n        if (node.tag === HostComponent || node.tag === HostText) {\n          appendInitialChild(parent, node.stateNode);\n        } else if (node.tag === HostPortal) ; else if (node.child !== null) {\n          node.child.return = node;\n          node = node.child;\n          continue;\n        }\n\n        if (node === workInProgress) {\n          return;\n        }\n\n        while (node.sibling === null) {\n          if (node.return === null || node.return === workInProgress) {\n            return;\n          }\n\n          node = node.return;\n        }\n\n        node.sibling.return = node.return;\n        node = node.sibling;\n      }\n    };\n\n    updateHostContainer = function (current, workInProgress) {// Noop\n    };\n\n    updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) {\n      // If we have an alternate, that means this is an update and we need to\n      // schedule a side-effect to do the updates.\n      var oldProps = current.memoizedProps;\n\n      if (oldProps === newProps) {\n        // In mutation mode, this is sufficient for a bailout because\n        // we won't touch this node even if children changed.\n        return;\n      } // If we get updated because one of our children updated, we don't\n      // have newProps so we'll have to reuse them.\n      // TODO: Split the update API as separate for the props vs. children.\n      // Even better would be if children weren't special cased at all tho.\n\n\n      var instance = workInProgress.stateNode;\n      var currentHostContext = getHostContext(); // TODO: Experiencing an error where oldProps is null. Suggests a host\n      // component is hitting the resume path. Figure out why. Possibly\n      // related to `hidden`.\n\n      var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); // TODO: Type this specific to this type of component.\n\n      workInProgress.updateQueue = updatePayload; // If the update payload indicates that there is a change or if there\n      // is a new ref we mark this as an update. All the work is done in commitWork.\n\n      if (updatePayload) {\n        markUpdate(workInProgress);\n      }\n    };\n\n    updateHostText$1 = function (current, workInProgress, oldText, newText) {\n      // If the text differs, mark it as an update. All the work in done in commitWork.\n      if (oldText !== newText) {\n        markUpdate(workInProgress);\n      }\n    };\n  }\n\n  function cutOffTailIfNeeded(renderState, hasRenderedATailFallback) {\n    if (getIsHydrating()) {\n      // If we're hydrating, we should consume as many items as we can\n      // so we don't leave any behind.\n      return;\n    }\n\n    switch (renderState.tailMode) {\n      case 'hidden':\n        {\n          // Any insertions at the end of the tail list after this point\n          // should be invisible. If there are already mounted boundaries\n          // anything before them are not considered for collapsing.\n          // Therefore we need to go through the whole tail to find if\n          // there are any.\n          var tailNode = renderState.tail;\n          var lastTailNode = null;\n\n          while (tailNode !== null) {\n            if (tailNode.alternate !== null) {\n              lastTailNode = tailNode;\n            }\n\n            tailNode = tailNode.sibling;\n          } // Next we're simply going to delete all insertions after the\n          // last rendered item.\n\n\n          if (lastTailNode === null) {\n            // All remaining items in the tail are insertions.\n            renderState.tail = null;\n          } else {\n            // Detach the insertion after the last node that was already\n            // inserted.\n            lastTailNode.sibling = null;\n          }\n\n          break;\n        }\n\n      case 'collapsed':\n        {\n          // Any insertions at the end of the tail list after this point\n          // should be invisible. If there are already mounted boundaries\n          // anything before them are not considered for collapsing.\n          // Therefore we need to go through the whole tail to find if\n          // there are any.\n          var _tailNode = renderState.tail;\n          var _lastTailNode = null;\n\n          while (_tailNode !== null) {\n            if (_tailNode.alternate !== null) {\n              _lastTailNode = _tailNode;\n            }\n\n            _tailNode = _tailNode.sibling;\n          } // Next we're simply going to delete all insertions after the\n          // last rendered item.\n\n\n          if (_lastTailNode === null) {\n            // All remaining items in the tail are insertions.\n            if (!hasRenderedATailFallback && renderState.tail !== null) {\n              // We suspended during the head. We want to show at least one\n              // row at the tail. So we'll keep on and cut off the rest.\n              renderState.tail.sibling = null;\n            } else {\n              renderState.tail = null;\n            }\n          } else {\n            // Detach the insertion after the last node that was already\n            // inserted.\n            _lastTailNode.sibling = null;\n          }\n\n          break;\n        }\n    }\n  }\n\n  function bubbleProperties(completedWork) {\n    var didBailout = completedWork.alternate !== null && completedWork.alternate.child === completedWork.child;\n    var newChildLanes = NoLanes;\n    var subtreeFlags = NoFlags;\n\n    if (!didBailout) {\n      // Bubble up the earliest expiration time.\n      if ( (completedWork.mode & ProfileMode) !== NoMode) {\n        // In profiling mode, resetChildExpirationTime is also used to reset\n        // profiler durations.\n        var actualDuration = completedWork.actualDuration;\n        var treeBaseDuration = completedWork.selfBaseDuration;\n        var child = completedWork.child;\n\n        while (child !== null) {\n          newChildLanes = mergeLanes(newChildLanes, mergeLanes(child.lanes, child.childLanes));\n          subtreeFlags |= child.subtreeFlags;\n          subtreeFlags |= child.flags; // When a fiber is cloned, its actualDuration is reset to 0. This value will\n          // only be updated if work is done on the fiber (i.e. it doesn't bailout).\n          // When work is done, it should bubble to the parent's actualDuration. If\n          // the fiber has not been cloned though, (meaning no work was done), then\n          // this value will reflect the amount of time spent working on a previous\n          // render. In that case it should not bubble. We determine whether it was\n          // cloned by comparing the child pointer.\n\n          actualDuration += child.actualDuration;\n          treeBaseDuration += child.treeBaseDuration;\n          child = child.sibling;\n        }\n\n        completedWork.actualDuration = actualDuration;\n        completedWork.treeBaseDuration = treeBaseDuration;\n      } else {\n        var _child = completedWork.child;\n\n        while (_child !== null) {\n          newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child.lanes, _child.childLanes));\n          subtreeFlags |= _child.subtreeFlags;\n          subtreeFlags |= _child.flags; // Update the return pointer so the tree is consistent. This is a code\n          // smell because it assumes the commit phase is never concurrent with\n          // the render phase. Will address during refactor to alternate model.\n\n          _child.return = completedWork;\n          _child = _child.sibling;\n        }\n      }\n\n      completedWork.subtreeFlags |= subtreeFlags;\n    } else {\n      // Bubble up the earliest expiration time.\n      if ( (completedWork.mode & ProfileMode) !== NoMode) {\n        // In profiling mode, resetChildExpirationTime is also used to reset\n        // profiler durations.\n        var _treeBaseDuration = completedWork.selfBaseDuration;\n        var _child2 = completedWork.child;\n\n        while (_child2 !== null) {\n          newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child2.lanes, _child2.childLanes)); // \"Static\" flags share the lifetime of the fiber/hook they belong to,\n          // so we should bubble those up even during a bailout. All the other\n          // flags have a lifetime only of a single render + commit, so we should\n          // ignore them.\n\n          subtreeFlags |= _child2.subtreeFlags & StaticMask;\n          subtreeFlags |= _child2.flags & StaticMask;\n          _treeBaseDuration += _child2.treeBaseDuration;\n          _child2 = _child2.sibling;\n        }\n\n        completedWork.treeBaseDuration = _treeBaseDuration;\n      } else {\n        var _child3 = completedWork.child;\n\n        while (_child3 !== null) {\n          newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child3.lanes, _child3.childLanes)); // \"Static\" flags share the lifetime of the fiber/hook they belong to,\n          // so we should bubble those up even during a bailout. All the other\n          // flags have a lifetime only of a single render + commit, so we should\n          // ignore them.\n\n          subtreeFlags |= _child3.subtreeFlags & StaticMask;\n          subtreeFlags |= _child3.flags & StaticMask; // Update the return pointer so the tree is consistent. This is a code\n          // smell because it assumes the commit phase is never concurrent with\n          // the render phase. Will address during refactor to alternate model.\n\n          _child3.return = completedWork;\n          _child3 = _child3.sibling;\n        }\n      }\n\n      completedWork.subtreeFlags |= subtreeFlags;\n    }\n\n    completedWork.childLanes = newChildLanes;\n    return didBailout;\n  }\n\n  function completeDehydratedSuspenseBoundary(current, workInProgress, nextState) {\n    if (hasUnhydratedTailNodes() && (workInProgress.mode & ConcurrentMode) !== NoMode && (workInProgress.flags & DidCapture) === NoFlags) {\n      warnIfUnhydratedTailNodes(workInProgress);\n      resetHydrationState();\n      workInProgress.flags |= ForceClientRender | Incomplete | ShouldCapture;\n      return false;\n    }\n\n    var wasHydrated = popHydrationState(workInProgress);\n\n    if (nextState !== null && nextState.dehydrated !== null) {\n      // We might be inside a hydration state the first time we're picking up this\n      // Suspense boundary, and also after we've reentered it for further hydration.\n      if (current === null) {\n        if (!wasHydrated) {\n          throw new Error('A dehydrated suspense component was completed without a hydrated node. ' + 'This is probably a bug in React.');\n        }\n\n        prepareToHydrateHostSuspenseInstance(workInProgress);\n        bubbleProperties(workInProgress);\n\n        {\n          if ((workInProgress.mode & ProfileMode) !== NoMode) {\n            var isTimedOutSuspense = nextState !== null;\n\n            if (isTimedOutSuspense) {\n              // Don't count time spent in a timed out Suspense subtree as part of the base duration.\n              var primaryChildFragment = workInProgress.child;\n\n              if (primaryChildFragment !== null) {\n                // $FlowFixMe Flow doesn't support type casting in combination with the -= operator\n                workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration;\n              }\n            }\n          }\n        }\n\n        return false;\n      } else {\n        // We might have reentered this boundary to hydrate it. If so, we need to reset the hydration\n        // state since we're now exiting out of it. popHydrationState doesn't do that for us.\n        resetHydrationState();\n\n        if ((workInProgress.flags & DidCapture) === NoFlags) {\n          // This boundary did not suspend so it's now hydrated and unsuspended.\n          workInProgress.memoizedState = null;\n        } // If nothing suspended, we need to schedule an effect to mark this boundary\n        // as having hydrated so events know that they're free to be invoked.\n        // It's also a signal to replay events and the suspense callback.\n        // If something suspended, schedule an effect to attach retry listeners.\n        // So we might as well always mark this.\n\n\n        workInProgress.flags |= Update;\n        bubbleProperties(workInProgress);\n\n        {\n          if ((workInProgress.mode & ProfileMode) !== NoMode) {\n            var _isTimedOutSuspense = nextState !== null;\n\n            if (_isTimedOutSuspense) {\n              // Don't count time spent in a timed out Suspense subtree as part of the base duration.\n              var _primaryChildFragment = workInProgress.child;\n\n              if (_primaryChildFragment !== null) {\n                // $FlowFixMe Flow doesn't support type casting in combination with the -= operator\n                workInProgress.treeBaseDuration -= _primaryChildFragment.treeBaseDuration;\n              }\n            }\n          }\n        }\n\n        return false;\n      }\n    } else {\n      // Successfully completed this tree. If this was a forced client render,\n      // there may have been recoverable errors during first hydration\n      // attempt. If so, add them to a queue so we can log them in the\n      // commit phase.\n      upgradeHydrationErrorsToRecoverable(); // Fall through to normal Suspense path\n\n      return true;\n    }\n  }\n\n  function completeWork(current, workInProgress, renderLanes) {\n    var newProps = workInProgress.pendingProps; // Note: This intentionally doesn't check if we're hydrating because comparing\n    // to the current tree provider fiber is just as fast and less error-prone.\n    // Ideally we would have a special version of the work loop only\n    // for hydration.\n\n    popTreeContext(workInProgress);\n\n    switch (workInProgress.tag) {\n      case IndeterminateComponent:\n      case LazyComponent:\n      case SimpleMemoComponent:\n      case FunctionComponent:\n      case ForwardRef:\n      case Fragment:\n      case Mode:\n      case Profiler:\n      case ContextConsumer:\n      case MemoComponent:\n        bubbleProperties(workInProgress);\n        return null;\n\n      case ClassComponent:\n        {\n          var Component = workInProgress.type;\n\n          if (isContextProvider(Component)) {\n            popContext(workInProgress);\n          }\n\n          bubbleProperties(workInProgress);\n          return null;\n        }\n\n      case HostRoot:\n        {\n          var fiberRoot = workInProgress.stateNode;\n          popHostContainer(workInProgress);\n          popTopLevelContextObject(workInProgress);\n          resetWorkInProgressVersions();\n\n          if (fiberRoot.pendingContext) {\n            fiberRoot.context = fiberRoot.pendingContext;\n            fiberRoot.pendingContext = null;\n          }\n\n          if (current === null || current.child === null) {\n            // If we hydrated, pop so that we can delete any remaining children\n            // that weren't hydrated.\n            var wasHydrated = popHydrationState(workInProgress);\n\n            if (wasHydrated) {\n              // If we hydrated, then we'll need to schedule an update for\n              // the commit side-effects on the root.\n              markUpdate(workInProgress);\n            } else {\n              if (current !== null) {\n                var prevState = current.memoizedState;\n\n                if ( // Check if this is a client root\n                !prevState.isDehydrated || // Check if we reverted to client rendering (e.g. due to an error)\n                (workInProgress.flags & ForceClientRender) !== NoFlags) {\n                  // Schedule an effect to clear this container at the start of the\n                  // next commit. This handles the case of React rendering into a\n                  // container with previous children. It's also safe to do for\n                  // updates too, because current.child would only be null if the\n                  // previous render was null (so the container would already\n                  // be empty).\n                  workInProgress.flags |= Snapshot; // If this was a forced client render, there may have been\n                  // recoverable errors during first hydration attempt. If so, add\n                  // them to a queue so we can log them in the commit phase.\n\n                  upgradeHydrationErrorsToRecoverable();\n                }\n              }\n            }\n          }\n\n          updateHostContainer(current, workInProgress);\n          bubbleProperties(workInProgress);\n\n          return null;\n        }\n\n      case HostComponent:\n        {\n          popHostContext(workInProgress);\n          var rootContainerInstance = getRootHostContainer();\n          var type = workInProgress.type;\n\n          if (current !== null && workInProgress.stateNode != null) {\n            updateHostComponent$1(current, workInProgress, type, newProps, rootContainerInstance);\n\n            if (current.ref !== workInProgress.ref) {\n              markRef$1(workInProgress);\n            }\n          } else {\n            if (!newProps) {\n              if (workInProgress.stateNode === null) {\n                throw new Error('We must have new props for new mounts. This error is likely ' + 'caused by a bug in React. Please file an issue.');\n              } // This can happen when we abort work.\n\n\n              bubbleProperties(workInProgress);\n              return null;\n            }\n\n            var currentHostContext = getHostContext(); // TODO: Move createInstance to beginWork and keep it on a context\n            // \"stack\" as the parent. Then append children as we go in beginWork\n            // or completeWork depending on whether we want to add them top->down or\n            // bottom->up. Top->down is faster in IE11.\n\n            var _wasHydrated = popHydrationState(workInProgress);\n\n            if (_wasHydrated) {\n              // TODO: Move this and createInstance step into the beginPhase\n              // to consolidate.\n              if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, currentHostContext)) {\n                // If changes to the hydrated node need to be applied at the\n                // commit-phase we mark this as such.\n                markUpdate(workInProgress);\n              }\n            } else {\n              var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress);\n              appendAllChildren(instance, workInProgress, false, false);\n              workInProgress.stateNode = instance; // Certain renderers require commit-time effects for initial mount.\n              // (eg DOM renderer supports auto-focus for certain elements).\n              // Make sure such renderers get scheduled for later work.\n\n              if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance)) {\n                markUpdate(workInProgress);\n              }\n            }\n\n            if (workInProgress.ref !== null) {\n              // If there is a ref on a host node we need to schedule a callback\n              markRef$1(workInProgress);\n            }\n          }\n\n          bubbleProperties(workInProgress);\n          return null;\n        }\n\n      case HostText:\n        {\n          var newText = newProps;\n\n          if (current && workInProgress.stateNode != null) {\n            var oldText = current.memoizedProps; // If we have an alternate, that means this is an update and we need\n            // to schedule a side-effect to do the updates.\n\n            updateHostText$1(current, workInProgress, oldText, newText);\n          } else {\n            if (typeof newText !== 'string') {\n              if (workInProgress.stateNode === null) {\n                throw new Error('We must have new props for new mounts. This error is likely ' + 'caused by a bug in React. Please file an issue.');\n              } // This can happen when we abort work.\n\n            }\n\n            var _rootContainerInstance = getRootHostContainer();\n\n            var _currentHostContext = getHostContext();\n\n            var _wasHydrated2 = popHydrationState(workInProgress);\n\n            if (_wasHydrated2) {\n              if (prepareToHydrateHostTextInstance(workInProgress)) {\n                markUpdate(workInProgress);\n              }\n            } else {\n              workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext, workInProgress);\n            }\n          }\n\n          bubbleProperties(workInProgress);\n          return null;\n        }\n\n      case SuspenseComponent:\n        {\n          popSuspenseContext(workInProgress);\n          var nextState = workInProgress.memoizedState; // Special path for dehydrated boundaries. We may eventually move this\n          // to its own fiber type so that we can add other kinds of hydration\n          // boundaries that aren't associated with a Suspense tree. In anticipation\n          // of such a refactor, all the hydration logic is contained in\n          // this branch.\n\n          if (current === null || current.memoizedState !== null && current.memoizedState.dehydrated !== null) {\n            var fallthroughToNormalSuspensePath = completeDehydratedSuspenseBoundary(current, workInProgress, nextState);\n\n            if (!fallthroughToNormalSuspensePath) {\n              if (workInProgress.flags & ShouldCapture) {\n                // Special case. There were remaining unhydrated nodes. We treat\n                // this as a mismatch. Revert to client rendering.\n                return workInProgress;\n              } else {\n                // Did not finish hydrating, either because this is the initial\n                // render or because something suspended.\n                return null;\n              }\n            } // Continue with the normal Suspense path.\n\n          }\n\n          if ((workInProgress.flags & DidCapture) !== NoFlags) {\n            // Something suspended. Re-render with the fallback children.\n            workInProgress.lanes = renderLanes; // Do not reset the effect list.\n\n            if ( (workInProgress.mode & ProfileMode) !== NoMode) {\n              transferActualDuration(workInProgress);\n            } // Don't bubble properties in this case.\n\n\n            return workInProgress;\n          }\n\n          var nextDidTimeout = nextState !== null;\n          var prevDidTimeout = current !== null && current.memoizedState !== null;\n          // a passive effect, which is when we process the transitions\n\n\n          if (nextDidTimeout !== prevDidTimeout) {\n            // an effect to toggle the subtree's visibility. When we switch from\n            // fallback -> primary, the inner Offscreen fiber schedules this effect\n            // as part of its normal complete phase. But when we switch from\n            // primary -> fallback, the inner Offscreen fiber does not have a complete\n            // phase. So we need to schedule its effect here.\n            //\n            // We also use this flag to connect/disconnect the effects, but the same\n            // logic applies: when re-connecting, the Offscreen fiber's complete\n            // phase will handle scheduling the effect. It's only when the fallback\n            // is active that we have to do anything special.\n\n\n            if (nextDidTimeout) {\n              var _offscreenFiber2 = workInProgress.child;\n              _offscreenFiber2.flags |= Visibility; // TODO: This will still suspend a synchronous tree if anything\n              // in the concurrent tree already suspended during this render.\n              // This is a known bug.\n\n              if ((workInProgress.mode & ConcurrentMode) !== NoMode) {\n                // TODO: Move this back to throwException because this is too late\n                // if this is a large tree which is common for initial loads. We\n                // don't know if we should restart a render or not until we get\n                // this marker, and this is too late.\n                // If this render already had a ping or lower pri updates,\n                // and this is the first time we know we're going to suspend we\n                // should be able to immediately restart from within throwException.\n                var hasInvisibleChildContext = current === null && (workInProgress.memoizedProps.unstable_avoidThisFallback !== true || !enableSuspenseAvoidThisFallback);\n\n                if (hasInvisibleChildContext || hasSuspenseContext(suspenseStackCursor.current, InvisibleParentSuspenseContext)) {\n                  // If this was in an invisible tree or a new render, then showing\n                  // this boundary is ok.\n                  renderDidSuspend();\n                } else {\n                  // Otherwise, we're going to have to hide content so we should\n                  // suspend for longer if possible.\n                  renderDidSuspendDelayIfPossible();\n                }\n              }\n            }\n          }\n\n          var wakeables = workInProgress.updateQueue;\n\n          if (wakeables !== null) {\n            // Schedule an effect to attach a retry listener to the promise.\n            // TODO: Move to passive phase\n            workInProgress.flags |= Update;\n          }\n\n          bubbleProperties(workInProgress);\n\n          {\n            if ((workInProgress.mode & ProfileMode) !== NoMode) {\n              if (nextDidTimeout) {\n                // Don't count time spent in a timed out Suspense subtree as part of the base duration.\n                var primaryChildFragment = workInProgress.child;\n\n                if (primaryChildFragment !== null) {\n                  // $FlowFixMe Flow doesn't support type casting in combination with the -= operator\n                  workInProgress.treeBaseDuration -= primaryChildFragment.treeBaseDuration;\n                }\n              }\n            }\n          }\n\n          return null;\n        }\n\n      case HostPortal:\n        popHostContainer(workInProgress);\n        updateHostContainer(current, workInProgress);\n\n        if (current === null) {\n          preparePortalMount(workInProgress.stateNode.containerInfo);\n        }\n\n        bubbleProperties(workInProgress);\n        return null;\n\n      case ContextProvider:\n        // Pop provider fiber\n        var context = workInProgress.type._context;\n        popProvider(context, workInProgress);\n        bubbleProperties(workInProgress);\n        return null;\n\n      case IncompleteClassComponent:\n        {\n          // Same as class component case. I put it down here so that the tags are\n          // sequential to ensure this switch is compiled to a jump table.\n          var _Component = workInProgress.type;\n\n          if (isContextProvider(_Component)) {\n            popContext(workInProgress);\n          }\n\n          bubbleProperties(workInProgress);\n          return null;\n        }\n\n      case SuspenseListComponent:\n        {\n          popSuspenseContext(workInProgress);\n          var renderState = workInProgress.memoizedState;\n\n          if (renderState === null) {\n            // We're running in the default, \"independent\" mode.\n            // We don't do anything in this mode.\n            bubbleProperties(workInProgress);\n            return null;\n          }\n\n          var didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags;\n          var renderedTail = renderState.rendering;\n\n          if (renderedTail === null) {\n            // We just rendered the head.\n            if (!didSuspendAlready) {\n              // This is the first pass. We need to figure out if anything is still\n              // suspended in the rendered set.\n              // If new content unsuspended, but there's still some content that\n              // didn't. Then we need to do a second pass that forces everything\n              // to keep showing their fallbacks.\n              // We might be suspended if something in this render pass suspended, or\n              // something in the previous committed pass suspended. Otherwise,\n              // there's no chance so we can skip the expensive call to\n              // findFirstSuspended.\n              var cannotBeSuspended = renderHasNotSuspendedYet() && (current === null || (current.flags & DidCapture) === NoFlags);\n\n              if (!cannotBeSuspended) {\n                var row = workInProgress.child;\n\n                while (row !== null) {\n                  var suspended = findFirstSuspended(row);\n\n                  if (suspended !== null) {\n                    didSuspendAlready = true;\n                    workInProgress.flags |= DidCapture;\n                    cutOffTailIfNeeded(renderState, false); // If this is a newly suspended tree, it might not get committed as\n                    // part of the second pass. In that case nothing will subscribe to\n                    // its thenables. Instead, we'll transfer its thenables to the\n                    // SuspenseList so that it can retry if they resolve.\n                    // There might be multiple of these in the list but since we're\n                    // going to wait for all of them anyway, it doesn't really matter\n                    // which ones gets to ping. In theory we could get clever and keep\n                    // track of how many dependencies remain but it gets tricky because\n                    // in the meantime, we can add/remove/change items and dependencies.\n                    // We might bail out of the loop before finding any but that\n                    // doesn't matter since that means that the other boundaries that\n                    // we did find already has their listeners attached.\n\n                    var newThenables = suspended.updateQueue;\n\n                    if (newThenables !== null) {\n                      workInProgress.updateQueue = newThenables;\n                      workInProgress.flags |= Update;\n                    } // Rerender the whole list, but this time, we'll force fallbacks\n                    // to stay in place.\n                    // Reset the effect flags before doing the second pass since that's now invalid.\n                    // Reset the child fibers to their original state.\n\n\n                    workInProgress.subtreeFlags = NoFlags;\n                    resetChildFibers(workInProgress, renderLanes); // Set up the Suspense Context to force suspense and immediately\n                    // rerender the children.\n\n                    pushSuspenseContext(workInProgress, setShallowSuspenseContext(suspenseStackCursor.current, ForceSuspenseFallback)); // Don't bubble properties in this case.\n\n                    return workInProgress.child;\n                  }\n\n                  row = row.sibling;\n                }\n              }\n\n              if (renderState.tail !== null && now() > getRenderTargetTime()) {\n                // We have already passed our CPU deadline but we still have rows\n                // left in the tail. We'll just give up further attempts to render\n                // the main content and only render fallbacks.\n                workInProgress.flags |= DidCapture;\n                didSuspendAlready = true;\n                cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this\n                // to get it started back up to attempt the next item. While in terms\n                // of priority this work has the same priority as this current render,\n                // it's not part of the same transition once the transition has\n                // committed. If it's sync, we still want to yield so that it can be\n                // painted. Conceptually, this is really the same as pinging.\n                // We can use any RetryLane even if it's the one currently rendering\n                // since we're leaving it behind on this node.\n\n                workInProgress.lanes = SomeRetryLane;\n              }\n            } else {\n              cutOffTailIfNeeded(renderState, false);\n            } // Next we're going to render the tail.\n\n          } else {\n            // Append the rendered row to the child list.\n            if (!didSuspendAlready) {\n              var _suspended = findFirstSuspended(renderedTail);\n\n              if (_suspended !== null) {\n                workInProgress.flags |= DidCapture;\n                didSuspendAlready = true; // Ensure we transfer the update queue to the parent so that it doesn't\n                // get lost if this row ends up dropped during a second pass.\n\n                var _newThenables = _suspended.updateQueue;\n\n                if (_newThenables !== null) {\n                  workInProgress.updateQueue = _newThenables;\n                  workInProgress.flags |= Update;\n                }\n\n                cutOffTailIfNeeded(renderState, true); // This might have been modified.\n\n                if (renderState.tail === null && renderState.tailMode === 'hidden' && !renderedTail.alternate && !getIsHydrating() // We don't cut it if we're hydrating.\n                ) {\n                    // We're done.\n                    bubbleProperties(workInProgress);\n                    return null;\n                  }\n              } else if ( // The time it took to render last row is greater than the remaining\n              // time we have to render. So rendering one more row would likely\n              // exceed it.\n              now() * 2 - renderState.renderingStartTime > getRenderTargetTime() && renderLanes !== OffscreenLane) {\n                // We have now passed our CPU deadline and we'll just give up further\n                // attempts to render the main content and only render fallbacks.\n                // The assumption is that this is usually faster.\n                workInProgress.flags |= DidCapture;\n                didSuspendAlready = true;\n                cutOffTailIfNeeded(renderState, false); // Since nothing actually suspended, there will nothing to ping this\n                // to get it started back up to attempt the next item. While in terms\n                // of priority this work has the same priority as this current render,\n                // it's not part of the same transition once the transition has\n                // committed. If it's sync, we still want to yield so that it can be\n                // painted. Conceptually, this is really the same as pinging.\n                // We can use any RetryLane even if it's the one currently rendering\n                // since we're leaving it behind on this node.\n\n                workInProgress.lanes = SomeRetryLane;\n              }\n            }\n\n            if (renderState.isBackwards) {\n              // The effect list of the backwards tail will have been added\n              // to the end. This breaks the guarantee that life-cycles fire in\n              // sibling order but that isn't a strong guarantee promised by React.\n              // Especially since these might also just pop in during future commits.\n              // Append to the beginning of the list.\n              renderedTail.sibling = workInProgress.child;\n              workInProgress.child = renderedTail;\n            } else {\n              var previousSibling = renderState.last;\n\n              if (previousSibling !== null) {\n                previousSibling.sibling = renderedTail;\n              } else {\n                workInProgress.child = renderedTail;\n              }\n\n              renderState.last = renderedTail;\n            }\n          }\n\n          if (renderState.tail !== null) {\n            // We still have tail rows to render.\n            // Pop a row.\n            var next = renderState.tail;\n            renderState.rendering = next;\n            renderState.tail = next.sibling;\n            renderState.renderingStartTime = now();\n            next.sibling = null; // Restore the context.\n            // TODO: We can probably just avoid popping it instead and only\n            // setting it the first time we go from not suspended to suspended.\n\n            var suspenseContext = suspenseStackCursor.current;\n\n            if (didSuspendAlready) {\n              suspenseContext = setShallowSuspenseContext(suspenseContext, ForceSuspenseFallback);\n            } else {\n              suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);\n            }\n\n            pushSuspenseContext(workInProgress, suspenseContext); // Do a pass over the next row.\n            // Don't bubble properties in this case.\n\n            return next;\n          }\n\n          bubbleProperties(workInProgress);\n          return null;\n        }\n\n      case ScopeComponent:\n        {\n\n          break;\n        }\n\n      case OffscreenComponent:\n      case LegacyHiddenComponent:\n        {\n          popRenderLanes(workInProgress);\n          var _nextState = workInProgress.memoizedState;\n          var nextIsHidden = _nextState !== null;\n\n          if (current !== null) {\n            var _prevState = current.memoizedState;\n            var prevIsHidden = _prevState !== null;\n\n            if (prevIsHidden !== nextIsHidden && ( // LegacyHidden doesn't do any hiding — it only pre-renders.\n            !enableLegacyHidden )) {\n              workInProgress.flags |= Visibility;\n            }\n          }\n\n          if (!nextIsHidden || (workInProgress.mode & ConcurrentMode) === NoMode) {\n            bubbleProperties(workInProgress);\n          } else {\n            // Don't bubble properties for hidden children unless we're rendering\n            // at offscreen priority.\n            if (includesSomeLane(subtreeRenderLanes, OffscreenLane)) {\n              bubbleProperties(workInProgress);\n\n              {\n                // Check if there was an insertion or update in the hidden subtree.\n                // If so, we need to hide those nodes in the commit phase, so\n                // schedule a visibility effect.\n                if ( workInProgress.subtreeFlags & (Placement | Update)) {\n                  workInProgress.flags |= Visibility;\n                }\n              }\n            }\n          }\n          return null;\n        }\n\n      case CacheComponent:\n        {\n\n          return null;\n        }\n\n      case TracingMarkerComponent:\n        {\n\n          return null;\n        }\n    }\n\n    throw new Error(\"Unknown unit of work tag (\" + workInProgress.tag + \"). This error is likely caused by a bug in \" + 'React. Please file an issue.');\n  }\n\n  function unwindWork(current, workInProgress, renderLanes) {\n    // Note: This intentionally doesn't check if we're hydrating because comparing\n    // to the current tree provider fiber is just as fast and less error-prone.\n    // Ideally we would have a special version of the work loop only\n    // for hydration.\n    popTreeContext(workInProgress);\n\n    switch (workInProgress.tag) {\n      case ClassComponent:\n        {\n          var Component = workInProgress.type;\n\n          if (isContextProvider(Component)) {\n            popContext(workInProgress);\n          }\n\n          var flags = workInProgress.flags;\n\n          if (flags & ShouldCapture) {\n            workInProgress.flags = flags & ~ShouldCapture | DidCapture;\n\n            if ( (workInProgress.mode & ProfileMode) !== NoMode) {\n              transferActualDuration(workInProgress);\n            }\n\n            return workInProgress;\n          }\n\n          return null;\n        }\n\n      case HostRoot:\n        {\n          var root = workInProgress.stateNode;\n          popHostContainer(workInProgress);\n          popTopLevelContextObject(workInProgress);\n          resetWorkInProgressVersions();\n          var _flags = workInProgress.flags;\n\n          if ((_flags & ShouldCapture) !== NoFlags && (_flags & DidCapture) === NoFlags) {\n            // There was an error during render that wasn't captured by a suspense\n            // boundary. Do a second pass on the root to unmount the children.\n            workInProgress.flags = _flags & ~ShouldCapture | DidCapture;\n            return workInProgress;\n          } // We unwound to the root without completing it. Exit.\n\n\n          return null;\n        }\n\n      case HostComponent:\n        {\n          // TODO: popHydrationState\n          popHostContext(workInProgress);\n          return null;\n        }\n\n      case SuspenseComponent:\n        {\n          popSuspenseContext(workInProgress);\n          var suspenseState = workInProgress.memoizedState;\n\n          if (suspenseState !== null && suspenseState.dehydrated !== null) {\n            if (workInProgress.alternate === null) {\n              throw new Error('Threw in newly mounted dehydrated component. This is likely a bug in ' + 'React. Please file an issue.');\n            }\n\n            resetHydrationState();\n          }\n\n          var _flags2 = workInProgress.flags;\n\n          if (_flags2 & ShouldCapture) {\n            workInProgress.flags = _flags2 & ~ShouldCapture | DidCapture; // Captured a suspense effect. Re-render the boundary.\n\n            if ( (workInProgress.mode & ProfileMode) !== NoMode) {\n              transferActualDuration(workInProgress);\n            }\n\n            return workInProgress;\n          }\n\n          return null;\n        }\n\n      case SuspenseListComponent:\n        {\n          popSuspenseContext(workInProgress); // SuspenseList doesn't actually catch anything. It should've been\n          // caught by a nested boundary. If not, it should bubble through.\n\n          return null;\n        }\n\n      case HostPortal:\n        popHostContainer(workInProgress);\n        return null;\n\n      case ContextProvider:\n        var context = workInProgress.type._context;\n        popProvider(context, workInProgress);\n        return null;\n\n      case OffscreenComponent:\n      case LegacyHiddenComponent:\n        popRenderLanes(workInProgress);\n        return null;\n\n      case CacheComponent:\n\n        return null;\n\n      default:\n        return null;\n    }\n  }\n\n  function unwindInterruptedWork(current, interruptedWork, renderLanes) {\n    // Note: This intentionally doesn't check if we're hydrating because comparing\n    // to the current tree provider fiber is just as fast and less error-prone.\n    // Ideally we would have a special version of the work loop only\n    // for hydration.\n    popTreeContext(interruptedWork);\n\n    switch (interruptedWork.tag) {\n      case ClassComponent:\n        {\n          var childContextTypes = interruptedWork.type.childContextTypes;\n\n          if (childContextTypes !== null && childContextTypes !== undefined) {\n            popContext(interruptedWork);\n          }\n\n          break;\n        }\n\n      case HostRoot:\n        {\n          var root = interruptedWork.stateNode;\n          popHostContainer(interruptedWork);\n          popTopLevelContextObject(interruptedWork);\n          resetWorkInProgressVersions();\n          break;\n        }\n\n      case HostComponent:\n        {\n          popHostContext(interruptedWork);\n          break;\n        }\n\n      case HostPortal:\n        popHostContainer(interruptedWork);\n        break;\n\n      case SuspenseComponent:\n        popSuspenseContext(interruptedWork);\n        break;\n\n      case SuspenseListComponent:\n        popSuspenseContext(interruptedWork);\n        break;\n\n      case ContextProvider:\n        var context = interruptedWork.type._context;\n        popProvider(context, interruptedWork);\n        break;\n\n      case OffscreenComponent:\n      case LegacyHiddenComponent:\n        popRenderLanes(interruptedWork);\n        break;\n    }\n  }\n\n  var didWarnAboutUndefinedSnapshotBeforeUpdate = null;\n\n  {\n    didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();\n  } // Used during the commit phase to track the state of the Offscreen component stack.\n  // Allows us to avoid traversing the return path to find the nearest Offscreen ancestor.\n  // Only used when enableSuspenseLayoutEffectSemantics is enabled.\n\n\n  var offscreenSubtreeIsHidden = false;\n  var offscreenSubtreeWasHidden = false;\n  var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;\n  var nextEffect = null; // Used for Profiling builds to track updaters.\n\n  var inProgressLanes = null;\n  var inProgressRoot = null;\n  function reportUncaughtErrorInDEV(error) {\n    // Wrapping each small part of the commit phase into a guarded\n    // callback is a bit too slow (https://github.com/facebook/react/pull/21666).\n    // But we rely on it to surface errors to DEV tools like overlays\n    // (https://github.com/facebook/react/issues/21712).\n    // As a compromise, rethrow only caught errors in a guard.\n    {\n      invokeGuardedCallback(null, function () {\n        throw error;\n      });\n      clearCaughtError();\n    }\n  }\n\n  var callComponentWillUnmountWithTimer = function (current, instance) {\n    instance.props = current.memoizedProps;\n    instance.state = current.memoizedState;\n\n    if ( current.mode & ProfileMode) {\n      try {\n        startLayoutEffectTimer();\n        instance.componentWillUnmount();\n      } finally {\n        recordLayoutEffectDuration(current);\n      }\n    } else {\n      instance.componentWillUnmount();\n    }\n  }; // Capture errors so they don't interrupt mounting.\n\n\n  function safelyCallCommitHookLayoutEffectListMount(current, nearestMountedAncestor) {\n    try {\n      commitHookEffectListMount(Layout, current);\n    } catch (error) {\n      captureCommitPhaseError(current, nearestMountedAncestor, error);\n    }\n  } // Capture errors so they don't interrupt unmounting.\n\n\n  function safelyCallComponentWillUnmount(current, nearestMountedAncestor, instance) {\n    try {\n      callComponentWillUnmountWithTimer(current, instance);\n    } catch (error) {\n      captureCommitPhaseError(current, nearestMountedAncestor, error);\n    }\n  } // Capture errors so they don't interrupt mounting.\n\n\n  function safelyCallComponentDidMount(current, nearestMountedAncestor, instance) {\n    try {\n      instance.componentDidMount();\n    } catch (error) {\n      captureCommitPhaseError(current, nearestMountedAncestor, error);\n    }\n  } // Capture errors so they don't interrupt mounting.\n\n\n  function safelyAttachRef(current, nearestMountedAncestor) {\n    try {\n      commitAttachRef(current);\n    } catch (error) {\n      captureCommitPhaseError(current, nearestMountedAncestor, error);\n    }\n  }\n\n  function safelyDetachRef(current, nearestMountedAncestor) {\n    var ref = current.ref;\n\n    if (ref !== null) {\n      if (typeof ref === 'function') {\n        var retVal;\n\n        try {\n          if (enableProfilerTimer && enableProfilerCommitHooks && current.mode & ProfileMode) {\n            try {\n              startLayoutEffectTimer();\n              retVal = ref(null);\n            } finally {\n              recordLayoutEffectDuration(current);\n            }\n          } else {\n            retVal = ref(null);\n          }\n        } catch (error) {\n          captureCommitPhaseError(current, nearestMountedAncestor, error);\n        }\n\n        {\n          if (typeof retVal === 'function') {\n            error('Unexpected return value from a callback ref in %s. ' + 'A callback ref should not return a function.', getComponentNameFromFiber(current));\n          }\n        }\n      } else {\n        ref.current = null;\n      }\n    }\n  }\n\n  function safelyCallDestroy(current, nearestMountedAncestor, destroy) {\n    try {\n      destroy();\n    } catch (error) {\n      captureCommitPhaseError(current, nearestMountedAncestor, error);\n    }\n  }\n\n  var focusedInstanceHandle = null;\n  var shouldFireAfterActiveInstanceBlur = false;\n  function commitBeforeMutationEffects(root, firstChild) {\n    focusedInstanceHandle = prepareForCommit(root.containerInfo);\n    nextEffect = firstChild;\n    commitBeforeMutationEffects_begin(); // We no longer need to track the active instance fiber\n\n    var shouldFire = shouldFireAfterActiveInstanceBlur;\n    shouldFireAfterActiveInstanceBlur = false;\n    focusedInstanceHandle = null;\n    return shouldFire;\n  }\n\n  function commitBeforeMutationEffects_begin() {\n    while (nextEffect !== null) {\n      var fiber = nextEffect; // This phase is only used for beforeActiveInstanceBlur.\n\n      var child = fiber.child;\n\n      if ((fiber.subtreeFlags & BeforeMutationMask) !== NoFlags && child !== null) {\n        child.return = fiber;\n        nextEffect = child;\n      } else {\n        commitBeforeMutationEffects_complete();\n      }\n    }\n  }\n\n  function commitBeforeMutationEffects_complete() {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n      setCurrentFiber(fiber);\n\n      try {\n        commitBeforeMutationEffectsOnFiber(fiber);\n      } catch (error) {\n        captureCommitPhaseError(fiber, fiber.return, error);\n      }\n\n      resetCurrentFiber();\n      var sibling = fiber.sibling;\n\n      if (sibling !== null) {\n        sibling.return = fiber.return;\n        nextEffect = sibling;\n        return;\n      }\n\n      nextEffect = fiber.return;\n    }\n  }\n\n  function commitBeforeMutationEffectsOnFiber(finishedWork) {\n    var current = finishedWork.alternate;\n    var flags = finishedWork.flags;\n\n    if ((flags & Snapshot) !== NoFlags) {\n      setCurrentFiber(finishedWork);\n\n      switch (finishedWork.tag) {\n        case FunctionComponent:\n        case ForwardRef:\n        case SimpleMemoComponent:\n          {\n            break;\n          }\n\n        case ClassComponent:\n          {\n            if (current !== null) {\n              var prevProps = current.memoizedProps;\n              var prevState = current.memoizedState;\n              var instance = finishedWork.stateNode; // We could update instance props and state here,\n              // but instead we rely on them being set during last render.\n              // TODO: revisit this when we implement resuming.\n\n              {\n                if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) {\n                  if (instance.props !== finishedWork.memoizedProps) {\n                    error('Expected %s props to match memoized props before ' + 'getSnapshotBeforeUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                  }\n\n                  if (instance.state !== finishedWork.memoizedState) {\n                    error('Expected %s state to match memoized state before ' + 'getSnapshotBeforeUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.state`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                  }\n                }\n              }\n\n              var snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState);\n\n              {\n                var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate;\n\n                if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {\n                  didWarnSet.add(finishedWork.type);\n\n                  error('%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' + 'must be returned. You have returned undefined.', getComponentNameFromFiber(finishedWork));\n                }\n              }\n\n              instance.__reactInternalSnapshotBeforeUpdate = snapshot;\n            }\n\n            break;\n          }\n\n        case HostRoot:\n          {\n            {\n              var root = finishedWork.stateNode;\n              clearContainer(root.containerInfo);\n            }\n\n            break;\n          }\n\n        case HostComponent:\n        case HostText:\n        case HostPortal:\n        case IncompleteClassComponent:\n          // Nothing to do for these component types\n          break;\n\n        default:\n          {\n            throw new Error('This unit of work tag should not have side-effects. This error is ' + 'likely caused by a bug in React. Please file an issue.');\n          }\n      }\n\n      resetCurrentFiber();\n    }\n  }\n\n  function commitHookEffectListUnmount(flags, finishedWork, nearestMountedAncestor) {\n    var updateQueue = finishedWork.updateQueue;\n    var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;\n\n    if (lastEffect !== null) {\n      var firstEffect = lastEffect.next;\n      var effect = firstEffect;\n\n      do {\n        if ((effect.tag & flags) === flags) {\n          // Unmount\n          var destroy = effect.destroy;\n          effect.destroy = undefined;\n\n          if (destroy !== undefined) {\n            {\n              if ((flags & Passive$1) !== NoFlags$1) {\n                markComponentPassiveEffectUnmountStarted(finishedWork);\n              } else if ((flags & Layout) !== NoFlags$1) {\n                markComponentLayoutEffectUnmountStarted(finishedWork);\n              }\n            }\n\n            {\n              if ((flags & Insertion) !== NoFlags$1) {\n                setIsRunningInsertionEffect(true);\n              }\n            }\n\n            safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);\n\n            {\n              if ((flags & Insertion) !== NoFlags$1) {\n                setIsRunningInsertionEffect(false);\n              }\n            }\n\n            {\n              if ((flags & Passive$1) !== NoFlags$1) {\n                markComponentPassiveEffectUnmountStopped();\n              } else if ((flags & Layout) !== NoFlags$1) {\n                markComponentLayoutEffectUnmountStopped();\n              }\n            }\n          }\n        }\n\n        effect = effect.next;\n      } while (effect !== firstEffect);\n    }\n  }\n\n  function commitHookEffectListMount(flags, finishedWork) {\n    var updateQueue = finishedWork.updateQueue;\n    var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;\n\n    if (lastEffect !== null) {\n      var firstEffect = lastEffect.next;\n      var effect = firstEffect;\n\n      do {\n        if ((effect.tag & flags) === flags) {\n          {\n            if ((flags & Passive$1) !== NoFlags$1) {\n              markComponentPassiveEffectMountStarted(finishedWork);\n            } else if ((flags & Layout) !== NoFlags$1) {\n              markComponentLayoutEffectMountStarted(finishedWork);\n            }\n          } // Mount\n\n\n          var create = effect.create;\n\n          {\n            if ((flags & Insertion) !== NoFlags$1) {\n              setIsRunningInsertionEffect(true);\n            }\n          }\n\n          effect.destroy = create();\n\n          {\n            if ((flags & Insertion) !== NoFlags$1) {\n              setIsRunningInsertionEffect(false);\n            }\n          }\n\n          {\n            if ((flags & Passive$1) !== NoFlags$1) {\n              markComponentPassiveEffectMountStopped();\n            } else if ((flags & Layout) !== NoFlags$1) {\n              markComponentLayoutEffectMountStopped();\n            }\n          }\n\n          {\n            var destroy = effect.destroy;\n\n            if (destroy !== undefined && typeof destroy !== 'function') {\n              var hookName = void 0;\n\n              if ((effect.tag & Layout) !== NoFlags) {\n                hookName = 'useLayoutEffect';\n              } else if ((effect.tag & Insertion) !== NoFlags) {\n                hookName = 'useInsertionEffect';\n              } else {\n                hookName = 'useEffect';\n              }\n\n              var addendum = void 0;\n\n              if (destroy === null) {\n                addendum = ' You returned null. If your effect does not require clean ' + 'up, return undefined (or nothing).';\n              } else if (typeof destroy.then === 'function') {\n                addendum = '\\n\\nIt looks like you wrote ' + hookName + '(async () => ...) or returned a Promise. ' + 'Instead, write the async function inside your effect ' + 'and call it immediately:\\n\\n' + hookName + '(() => {\\n' + '  async function fetchData() {\\n' + '    // You can await here\\n' + '    const response = await MyAPI.getData(someId);\\n' + '    // ...\\n' + '  }\\n' + '  fetchData();\\n' + \"}, [someId]); // Or [] if effect doesn't need props or state\\n\\n\" + 'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching';\n              } else {\n                addendum = ' You returned: ' + destroy;\n              }\n\n              error('%s must not return anything besides a function, ' + 'which is used for clean-up.%s', hookName, addendum);\n            }\n          }\n        }\n\n        effect = effect.next;\n      } while (effect !== firstEffect);\n    }\n  }\n\n  function commitPassiveEffectDurations(finishedRoot, finishedWork) {\n    {\n      // Only Profilers with work in their subtree will have an Update effect scheduled.\n      if ((finishedWork.flags & Update) !== NoFlags) {\n        switch (finishedWork.tag) {\n          case Profiler:\n            {\n              var passiveEffectDuration = finishedWork.stateNode.passiveEffectDuration;\n              var _finishedWork$memoize = finishedWork.memoizedProps,\n                  id = _finishedWork$memoize.id,\n                  onPostCommit = _finishedWork$memoize.onPostCommit; // This value will still reflect the previous commit phase.\n              // It does not get reset until the start of the next commit phase.\n\n              var commitTime = getCommitTime();\n              var phase = finishedWork.alternate === null ? 'mount' : 'update';\n\n              {\n                if (isCurrentUpdateNested()) {\n                  phase = 'nested-update';\n                }\n              }\n\n              if (typeof onPostCommit === 'function') {\n                onPostCommit(id, phase, passiveEffectDuration, commitTime);\n              } // Bubble times to the next nearest ancestor Profiler.\n              // After we process that Profiler, we'll bubble further up.\n\n\n              var parentFiber = finishedWork.return;\n\n              outer: while (parentFiber !== null) {\n                switch (parentFiber.tag) {\n                  case HostRoot:\n                    var root = parentFiber.stateNode;\n                    root.passiveEffectDuration += passiveEffectDuration;\n                    break outer;\n\n                  case Profiler:\n                    var parentStateNode = parentFiber.stateNode;\n                    parentStateNode.passiveEffectDuration += passiveEffectDuration;\n                    break outer;\n                }\n\n                parentFiber = parentFiber.return;\n              }\n\n              break;\n            }\n        }\n      }\n    }\n  }\n\n  function commitLayoutEffectOnFiber(finishedRoot, current, finishedWork, committedLanes) {\n    if ((finishedWork.flags & LayoutMask) !== NoFlags) {\n      switch (finishedWork.tag) {\n        case FunctionComponent:\n        case ForwardRef:\n        case SimpleMemoComponent:\n          {\n            if ( !offscreenSubtreeWasHidden) {\n              // At this point layout effects have already been destroyed (during mutation phase).\n              // This is done to prevent sibling component effects from interfering with each other,\n              // e.g. a destroy function in one component should never override a ref set\n              // by a create function in another component during the same commit.\n              if ( finishedWork.mode & ProfileMode) {\n                try {\n                  startLayoutEffectTimer();\n                  commitHookEffectListMount(Layout | HasEffect, finishedWork);\n                } finally {\n                  recordLayoutEffectDuration(finishedWork);\n                }\n              } else {\n                commitHookEffectListMount(Layout | HasEffect, finishedWork);\n              }\n            }\n\n            break;\n          }\n\n        case ClassComponent:\n          {\n            var instance = finishedWork.stateNode;\n\n            if (finishedWork.flags & Update) {\n              if (!offscreenSubtreeWasHidden) {\n                if (current === null) {\n                  // We could update instance props and state here,\n                  // but instead we rely on them being set during last render.\n                  // TODO: revisit this when we implement resuming.\n                  {\n                    if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) {\n                      if (instance.props !== finishedWork.memoizedProps) {\n                        error('Expected %s props to match memoized props before ' + 'componentDidMount. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                      }\n\n                      if (instance.state !== finishedWork.memoizedState) {\n                        error('Expected %s state to match memoized state before ' + 'componentDidMount. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.state`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                      }\n                    }\n                  }\n\n                  if ( finishedWork.mode & ProfileMode) {\n                    try {\n                      startLayoutEffectTimer();\n                      instance.componentDidMount();\n                    } finally {\n                      recordLayoutEffectDuration(finishedWork);\n                    }\n                  } else {\n                    instance.componentDidMount();\n                  }\n                } else {\n                  var prevProps = finishedWork.elementType === finishedWork.type ? current.memoizedProps : resolveDefaultProps(finishedWork.type, current.memoizedProps);\n                  var prevState = current.memoizedState; // We could update instance props and state here,\n                  // but instead we rely on them being set during last render.\n                  // TODO: revisit this when we implement resuming.\n\n                  {\n                    if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) {\n                      if (instance.props !== finishedWork.memoizedProps) {\n                        error('Expected %s props to match memoized props before ' + 'componentDidUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                      }\n\n                      if (instance.state !== finishedWork.memoizedState) {\n                        error('Expected %s state to match memoized state before ' + 'componentDidUpdate. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.state`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                      }\n                    }\n                  }\n\n                  if ( finishedWork.mode & ProfileMode) {\n                    try {\n                      startLayoutEffectTimer();\n                      instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate);\n                    } finally {\n                      recordLayoutEffectDuration(finishedWork);\n                    }\n                  } else {\n                    instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate);\n                  }\n                }\n              }\n            } // TODO: I think this is now always non-null by the time it reaches the\n            // commit phase. Consider removing the type check.\n\n\n            var updateQueue = finishedWork.updateQueue;\n\n            if (updateQueue !== null) {\n              {\n                if (finishedWork.type === finishedWork.elementType && !didWarnAboutReassigningProps) {\n                  if (instance.props !== finishedWork.memoizedProps) {\n                    error('Expected %s props to match memoized props before ' + 'processing the update queue. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.props`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                  }\n\n                  if (instance.state !== finishedWork.memoizedState) {\n                    error('Expected %s state to match memoized state before ' + 'processing the update queue. ' + 'This might either be because of a bug in React, or because ' + 'a component reassigns its own `this.state`. ' + 'Please file an issue.', getComponentNameFromFiber(finishedWork) || 'instance');\n                  }\n                }\n              } // We could update instance props and state here,\n              // but instead we rely on them being set during last render.\n              // TODO: revisit this when we implement resuming.\n\n\n              commitUpdateQueue(finishedWork, updateQueue, instance);\n            }\n\n            break;\n          }\n\n        case HostRoot:\n          {\n            // TODO: I think this is now always non-null by the time it reaches the\n            // commit phase. Consider removing the type check.\n            var _updateQueue = finishedWork.updateQueue;\n\n            if (_updateQueue !== null) {\n              var _instance = null;\n\n              if (finishedWork.child !== null) {\n                switch (finishedWork.child.tag) {\n                  case HostComponent:\n                    _instance = getPublicInstance(finishedWork.child.stateNode);\n                    break;\n\n                  case ClassComponent:\n                    _instance = finishedWork.child.stateNode;\n                    break;\n                }\n              }\n\n              commitUpdateQueue(finishedWork, _updateQueue, _instance);\n            }\n\n            break;\n          }\n\n        case HostComponent:\n          {\n            var _instance2 = finishedWork.stateNode; // Renderers may schedule work to be done after host components are mounted\n            // (eg DOM renderer may schedule auto-focus for inputs and form controls).\n            // These effects should only be committed when components are first mounted,\n            // aka when there is no current/alternate.\n\n            if (current === null && finishedWork.flags & Update) {\n              var type = finishedWork.type;\n              var props = finishedWork.memoizedProps;\n              commitMount(_instance2, type, props);\n            }\n\n            break;\n          }\n\n        case HostText:\n          {\n            // We have no life-cycles associated with text.\n            break;\n          }\n\n        case HostPortal:\n          {\n            // We have no life-cycles associated with portals.\n            break;\n          }\n\n        case Profiler:\n          {\n            {\n              var _finishedWork$memoize2 = finishedWork.memoizedProps,\n                  onCommit = _finishedWork$memoize2.onCommit,\n                  onRender = _finishedWork$memoize2.onRender;\n              var effectDuration = finishedWork.stateNode.effectDuration;\n              var commitTime = getCommitTime();\n              var phase = current === null ? 'mount' : 'update';\n\n              {\n                if (isCurrentUpdateNested()) {\n                  phase = 'nested-update';\n                }\n              }\n\n              if (typeof onRender === 'function') {\n                onRender(finishedWork.memoizedProps.id, phase, finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, commitTime);\n              }\n\n              {\n                if (typeof onCommit === 'function') {\n                  onCommit(finishedWork.memoizedProps.id, phase, effectDuration, commitTime);\n                } // Schedule a passive effect for this Profiler to call onPostCommit hooks.\n                // This effect should be scheduled even if there is no onPostCommit callback for this Profiler,\n                // because the effect is also where times bubble to parent Profilers.\n\n\n                enqueuePendingPassiveProfilerEffect(finishedWork); // Propagate layout effect durations to the next nearest Profiler ancestor.\n                // Do not reset these values until the next render so DevTools has a chance to read them first.\n\n                var parentFiber = finishedWork.return;\n\n                outer: while (parentFiber !== null) {\n                  switch (parentFiber.tag) {\n                    case HostRoot:\n                      var root = parentFiber.stateNode;\n                      root.effectDuration += effectDuration;\n                      break outer;\n\n                    case Profiler:\n                      var parentStateNode = parentFiber.stateNode;\n                      parentStateNode.effectDuration += effectDuration;\n                      break outer;\n                  }\n\n                  parentFiber = parentFiber.return;\n                }\n              }\n            }\n\n            break;\n          }\n\n        case SuspenseComponent:\n          {\n            commitSuspenseHydrationCallbacks(finishedRoot, finishedWork);\n            break;\n          }\n\n        case SuspenseListComponent:\n        case IncompleteClassComponent:\n        case ScopeComponent:\n        case OffscreenComponent:\n        case LegacyHiddenComponent:\n        case TracingMarkerComponent:\n          {\n            break;\n          }\n\n        default:\n          throw new Error('This unit of work tag should not have side-effects. This error is ' + 'likely caused by a bug in React. Please file an issue.');\n      }\n    }\n\n    if ( !offscreenSubtreeWasHidden) {\n      {\n        if (finishedWork.flags & Ref) {\n          commitAttachRef(finishedWork);\n        }\n      }\n    }\n  }\n\n  function reappearLayoutEffectsOnFiber(node) {\n    // Turn on layout effects in a tree that previously disappeared.\n    // TODO (Offscreen) Check: flags & LayoutStatic\n    switch (node.tag) {\n      case FunctionComponent:\n      case ForwardRef:\n      case SimpleMemoComponent:\n        {\n          if ( node.mode & ProfileMode) {\n            try {\n              startLayoutEffectTimer();\n              safelyCallCommitHookLayoutEffectListMount(node, node.return);\n            } finally {\n              recordLayoutEffectDuration(node);\n            }\n          } else {\n            safelyCallCommitHookLayoutEffectListMount(node, node.return);\n          }\n\n          break;\n        }\n\n      case ClassComponent:\n        {\n          var instance = node.stateNode;\n\n          if (typeof instance.componentDidMount === 'function') {\n            safelyCallComponentDidMount(node, node.return, instance);\n          }\n\n          safelyAttachRef(node, node.return);\n          break;\n        }\n\n      case HostComponent:\n        {\n          safelyAttachRef(node, node.return);\n          break;\n        }\n    }\n  }\n\n  function hideOrUnhideAllChildren(finishedWork, isHidden) {\n    // Only hide or unhide the top-most host nodes.\n    var hostSubtreeRoot = null;\n\n    {\n      // We only have the top Fiber that was inserted but we need to recurse down its\n      // children to find all the terminal nodes.\n      var node = finishedWork;\n\n      while (true) {\n        if (node.tag === HostComponent) {\n          if (hostSubtreeRoot === null) {\n            hostSubtreeRoot = node;\n\n            try {\n              var instance = node.stateNode;\n\n              if (isHidden) {\n                hideInstance(instance);\n              } else {\n                unhideInstance(node.stateNode, node.memoizedProps);\n              }\n            } catch (error) {\n              captureCommitPhaseError(finishedWork, finishedWork.return, error);\n            }\n          }\n        } else if (node.tag === HostText) {\n          if (hostSubtreeRoot === null) {\n            try {\n              var _instance3 = node.stateNode;\n\n              if (isHidden) {\n                hideTextInstance(_instance3);\n              } else {\n                unhideTextInstance(_instance3, node.memoizedProps);\n              }\n            } catch (error) {\n              captureCommitPhaseError(finishedWork, finishedWork.return, error);\n            }\n          }\n        } else if ((node.tag === OffscreenComponent || node.tag === LegacyHiddenComponent) && node.memoizedState !== null && node !== finishedWork) ; else if (node.child !== null) {\n          node.child.return = node;\n          node = node.child;\n          continue;\n        }\n\n        if (node === finishedWork) {\n          return;\n        }\n\n        while (node.sibling === null) {\n          if (node.return === null || node.return === finishedWork) {\n            return;\n          }\n\n          if (hostSubtreeRoot === node) {\n            hostSubtreeRoot = null;\n          }\n\n          node = node.return;\n        }\n\n        if (hostSubtreeRoot === node) {\n          hostSubtreeRoot = null;\n        }\n\n        node.sibling.return = node.return;\n        node = node.sibling;\n      }\n    }\n  }\n\n  function commitAttachRef(finishedWork) {\n    var ref = finishedWork.ref;\n\n    if (ref !== null) {\n      var instance = finishedWork.stateNode;\n      var instanceToUse;\n\n      switch (finishedWork.tag) {\n        case HostComponent:\n          instanceToUse = getPublicInstance(instance);\n          break;\n\n        default:\n          instanceToUse = instance;\n      } // Moved outside to ensure DCE works with this flag\n\n      if (typeof ref === 'function') {\n        var retVal;\n\n        if ( finishedWork.mode & ProfileMode) {\n          try {\n            startLayoutEffectTimer();\n            retVal = ref(instanceToUse);\n          } finally {\n            recordLayoutEffectDuration(finishedWork);\n          }\n        } else {\n          retVal = ref(instanceToUse);\n        }\n\n        {\n          if (typeof retVal === 'function') {\n            error('Unexpected return value from a callback ref in %s. ' + 'A callback ref should not return a function.', getComponentNameFromFiber(finishedWork));\n          }\n        }\n      } else {\n        {\n          if (!ref.hasOwnProperty('current')) {\n            error('Unexpected ref object provided for %s. ' + 'Use either a ref-setter function or React.createRef().', getComponentNameFromFiber(finishedWork));\n          }\n        }\n\n        ref.current = instanceToUse;\n      }\n    }\n  }\n\n  function detachFiberMutation(fiber) {\n    // Cut off the return pointer to disconnect it from the tree.\n    // This enables us to detect and warn against state updates on an unmounted component.\n    // It also prevents events from bubbling from within disconnected components.\n    //\n    // Ideally, we should also clear the child pointer of the parent alternate to let this\n    // get GC:ed but we don't know which for sure which parent is the current\n    // one so we'll settle for GC:ing the subtree of this child.\n    // This child itself will be GC:ed when the parent updates the next time.\n    //\n    // Note that we can't clear child or sibling pointers yet.\n    // They're needed for passive effects and for findDOMNode.\n    // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects).\n    //\n    // Don't reset the alternate yet, either. We need that so we can detach the\n    // alternate's fields in the passive phase. Clearing the return pointer is\n    // sufficient for findDOMNode semantics.\n    var alternate = fiber.alternate;\n\n    if (alternate !== null) {\n      alternate.return = null;\n    }\n\n    fiber.return = null;\n  }\n\n  function detachFiberAfterEffects(fiber) {\n    var alternate = fiber.alternate;\n\n    if (alternate !== null) {\n      fiber.alternate = null;\n      detachFiberAfterEffects(alternate);\n    } // Note: Defensively using negation instead of < in case\n    // `deletedTreeCleanUpLevel` is undefined.\n\n\n    {\n      // Clear cyclical Fiber fields. This level alone is designed to roughly\n      // approximate the planned Fiber refactor. In that world, `setState` will be\n      // bound to a special \"instance\" object instead of a Fiber. The Instance\n      // object will not have any of these fields. It will only be connected to\n      // the fiber tree via a single link at the root. So if this level alone is\n      // sufficient to fix memory issues, that bodes well for our plans.\n      fiber.child = null;\n      fiber.deletions = null;\n      fiber.sibling = null; // The `stateNode` is cyclical because on host nodes it points to the host\n      // tree, which has its own pointers to children, parents, and siblings.\n      // The other host nodes also point back to fibers, so we should detach that\n      // one, too.\n\n      if (fiber.tag === HostComponent) {\n        var hostInstance = fiber.stateNode;\n\n        if (hostInstance !== null) {\n          detachDeletedInstance(hostInstance);\n        }\n      }\n\n      fiber.stateNode = null; // I'm intentionally not clearing the `return` field in this level. We\n      // already disconnect the `return` pointer at the root of the deleted\n      // subtree (in `detachFiberMutation`). Besides, `return` by itself is not\n      // cyclical — it's only cyclical when combined with `child`, `sibling`, and\n      // `alternate`. But we'll clear it in the next level anyway, just in case.\n\n      {\n        fiber._debugOwner = null;\n      }\n\n      {\n        // Theoretically, nothing in here should be necessary, because we already\n        // disconnected the fiber from the tree. So even if something leaks this\n        // particular fiber, it won't leak anything else\n        //\n        // The purpose of this branch is to be super aggressive so we can measure\n        // if there's any difference in memory impact. If there is, that could\n        // indicate a React leak we don't know about.\n        fiber.return = null;\n        fiber.dependencies = null;\n        fiber.memoizedProps = null;\n        fiber.memoizedState = null;\n        fiber.pendingProps = null;\n        fiber.stateNode = null; // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead.\n\n        fiber.updateQueue = null;\n      }\n    }\n  }\n\n  function getHostParentFiber(fiber) {\n    var parent = fiber.return;\n\n    while (parent !== null) {\n      if (isHostParent(parent)) {\n        return parent;\n      }\n\n      parent = parent.return;\n    }\n\n    throw new Error('Expected to find a host parent. This error is likely caused by a bug ' + 'in React. Please file an issue.');\n  }\n\n  function isHostParent(fiber) {\n    return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal;\n  }\n\n  function getHostSibling(fiber) {\n    // We're going to search forward into the tree until we find a sibling host\n    // node. Unfortunately, if multiple insertions are done in a row we have to\n    // search past them. This leads to exponential search for the next sibling.\n    // TODO: Find a more efficient way to do this.\n    var node = fiber;\n\n    siblings: while (true) {\n      // If we didn't find anything, let's try the next sibling.\n      while (node.sibling === null) {\n        if (node.return === null || isHostParent(node.return)) {\n          // If we pop out of the root or hit the parent the fiber we are the\n          // last sibling.\n          return null;\n        }\n\n        node = node.return;\n      }\n\n      node.sibling.return = node.return;\n      node = node.sibling;\n\n      while (node.tag !== HostComponent && node.tag !== HostText && node.tag !== DehydratedFragment) {\n        // If it is not host node and, we might have a host node inside it.\n        // Try to search down until we find one.\n        if (node.flags & Placement) {\n          // If we don't have a child, try the siblings instead.\n          continue siblings;\n        } // If we don't have a child, try the siblings instead.\n        // We also skip portals because they are not part of this host tree.\n\n\n        if (node.child === null || node.tag === HostPortal) {\n          continue siblings;\n        } else {\n          node.child.return = node;\n          node = node.child;\n        }\n      } // Check if this host node is stable or about to be placed.\n\n\n      if (!(node.flags & Placement)) {\n        // Found it!\n        return node.stateNode;\n      }\n    }\n  }\n\n  function commitPlacement(finishedWork) {\n\n\n    var parentFiber = getHostParentFiber(finishedWork); // Note: these two variables *must* always be updated together.\n\n    switch (parentFiber.tag) {\n      case HostComponent:\n        {\n          var parent = parentFiber.stateNode;\n\n          if (parentFiber.flags & ContentReset) {\n            // Reset the text content of the parent before doing any insertions\n            resetTextContent(parent); // Clear ContentReset from the effect tag\n\n            parentFiber.flags &= ~ContentReset;\n          }\n\n          var before = getHostSibling(finishedWork); // We only have the top Fiber that was inserted but we need to recurse down its\n          // children to find all the terminal nodes.\n\n          insertOrAppendPlacementNode(finishedWork, before, parent);\n          break;\n        }\n\n      case HostRoot:\n      case HostPortal:\n        {\n          var _parent = parentFiber.stateNode.containerInfo;\n\n          var _before = getHostSibling(finishedWork);\n\n          insertOrAppendPlacementNodeIntoContainer(finishedWork, _before, _parent);\n          break;\n        }\n      // eslint-disable-next-line-no-fallthrough\n\n      default:\n        throw new Error('Invalid host parent fiber. This error is likely caused by a bug ' + 'in React. Please file an issue.');\n    }\n  }\n\n  function insertOrAppendPlacementNodeIntoContainer(node, before, parent) {\n    var tag = node.tag;\n    var isHost = tag === HostComponent || tag === HostText;\n\n    if (isHost) {\n      var stateNode = node.stateNode;\n\n      if (before) {\n        insertInContainerBefore(parent, stateNode, before);\n      } else {\n        appendChildToContainer(parent, stateNode);\n      }\n    } else if (tag === HostPortal) ; else {\n      var child = node.child;\n\n      if (child !== null) {\n        insertOrAppendPlacementNodeIntoContainer(child, before, parent);\n        var sibling = child.sibling;\n\n        while (sibling !== null) {\n          insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);\n          sibling = sibling.sibling;\n        }\n      }\n    }\n  }\n\n  function insertOrAppendPlacementNode(node, before, parent) {\n    var tag = node.tag;\n    var isHost = tag === HostComponent || tag === HostText;\n\n    if (isHost) {\n      var stateNode = node.stateNode;\n\n      if (before) {\n        insertBefore(parent, stateNode, before);\n      } else {\n        appendChild(parent, stateNode);\n      }\n    } else if (tag === HostPortal) ; else {\n      var child = node.child;\n\n      if (child !== null) {\n        insertOrAppendPlacementNode(child, before, parent);\n        var sibling = child.sibling;\n\n        while (sibling !== null) {\n          insertOrAppendPlacementNode(sibling, before, parent);\n          sibling = sibling.sibling;\n        }\n      }\n    }\n  } // These are tracked on the stack as we recursively traverse a\n  // deleted subtree.\n  // TODO: Update these during the whole mutation phase, not just during\n  // a deletion.\n\n\n  var hostParent = null;\n  var hostParentIsContainer = false;\n\n  function commitDeletionEffects(root, returnFiber, deletedFiber) {\n    {\n      // We only have the top Fiber that was deleted but we need to recurse down its\n      // children to find all the terminal nodes.\n      // Recursively delete all host nodes from the parent, detach refs, clean\n      // up mounted layout effects, and call componentWillUnmount.\n      // We only need to remove the topmost host child in each branch. But then we\n      // still need to keep traversing to unmount effects, refs, and cWU. TODO: We\n      // could split this into two separate traversals functions, where the second\n      // one doesn't include any removeChild logic. This is maybe the same\n      // function as \"disappearLayoutEffects\" (or whatever that turns into after\n      // the layout phase is refactored to use recursion).\n      // Before starting, find the nearest host parent on the stack so we know\n      // which instance/container to remove the children from.\n      // TODO: Instead of searching up the fiber return path on every deletion, we\n      // can track the nearest host component on the JS stack as we traverse the\n      // tree during the commit phase. This would make insertions faster, too.\n      var parent = returnFiber;\n\n      findParent: while (parent !== null) {\n        switch (parent.tag) {\n          case HostComponent:\n            {\n              hostParent = parent.stateNode;\n              hostParentIsContainer = false;\n              break findParent;\n            }\n\n          case HostRoot:\n            {\n              hostParent = parent.stateNode.containerInfo;\n              hostParentIsContainer = true;\n              break findParent;\n            }\n\n          case HostPortal:\n            {\n              hostParent = parent.stateNode.containerInfo;\n              hostParentIsContainer = true;\n              break findParent;\n            }\n        }\n\n        parent = parent.return;\n      }\n\n      if (hostParent === null) {\n        throw new Error('Expected to find a host parent. This error is likely caused by ' + 'a bug in React. Please file an issue.');\n      }\n\n      commitDeletionEffectsOnFiber(root, returnFiber, deletedFiber);\n      hostParent = null;\n      hostParentIsContainer = false;\n    }\n\n    detachFiberMutation(deletedFiber);\n  }\n\n  function recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, parent) {\n    // TODO: Use a static flag to skip trees that don't have unmount effects\n    var child = parent.child;\n\n    while (child !== null) {\n      commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, child);\n      child = child.sibling;\n    }\n  }\n\n  function commitDeletionEffectsOnFiber(finishedRoot, nearestMountedAncestor, deletedFiber) {\n    onCommitUnmount(deletedFiber); // The cases in this outer switch modify the stack before they traverse\n    // into their subtree. There are simpler cases in the inner switch\n    // that don't modify the stack.\n\n    switch (deletedFiber.tag) {\n      case HostComponent:\n        {\n          if (!offscreenSubtreeWasHidden) {\n            safelyDetachRef(deletedFiber, nearestMountedAncestor);\n          } // Intentional fallthrough to next branch\n\n        }\n      // eslint-disable-next-line-no-fallthrough\n\n      case HostText:\n        {\n          // We only need to remove the nearest host child. Set the host parent\n          // to `null` on the stack to indicate that nested children don't\n          // need to be removed.\n          {\n            var prevHostParent = hostParent;\n            var prevHostParentIsContainer = hostParentIsContainer;\n            hostParent = null;\n            recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n            hostParent = prevHostParent;\n            hostParentIsContainer = prevHostParentIsContainer;\n\n            if (hostParent !== null) {\n              // Now that all the child effects have unmounted, we can remove the\n              // node from the tree.\n              if (hostParentIsContainer) {\n                removeChildFromContainer(hostParent, deletedFiber.stateNode);\n              } else {\n                removeChild(hostParent, deletedFiber.stateNode);\n              }\n            }\n          }\n\n          return;\n        }\n\n      case DehydratedFragment:\n        {\n          // Delete the dehydrated suspense boundary and all of its content.\n\n\n          {\n            if (hostParent !== null) {\n              if (hostParentIsContainer) {\n                clearSuspenseBoundaryFromContainer(hostParent, deletedFiber.stateNode);\n              } else {\n                clearSuspenseBoundary(hostParent, deletedFiber.stateNode);\n              }\n            }\n          }\n\n          return;\n        }\n\n      case HostPortal:\n        {\n          {\n            // When we go into a portal, it becomes the parent to remove from.\n            var _prevHostParent = hostParent;\n            var _prevHostParentIsContainer = hostParentIsContainer;\n            hostParent = deletedFiber.stateNode.containerInfo;\n            hostParentIsContainer = true;\n            recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n            hostParent = _prevHostParent;\n            hostParentIsContainer = _prevHostParentIsContainer;\n          }\n\n          return;\n        }\n\n      case FunctionComponent:\n      case ForwardRef:\n      case MemoComponent:\n      case SimpleMemoComponent:\n        {\n          if (!offscreenSubtreeWasHidden) {\n            var updateQueue = deletedFiber.updateQueue;\n\n            if (updateQueue !== null) {\n              var lastEffect = updateQueue.lastEffect;\n\n              if (lastEffect !== null) {\n                var firstEffect = lastEffect.next;\n                var effect = firstEffect;\n\n                do {\n                  var _effect = effect,\n                      destroy = _effect.destroy,\n                      tag = _effect.tag;\n\n                  if (destroy !== undefined) {\n                    if ((tag & Insertion) !== NoFlags$1) {\n                      safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy);\n                    } else if ((tag & Layout) !== NoFlags$1) {\n                      {\n                        markComponentLayoutEffectUnmountStarted(deletedFiber);\n                      }\n\n                      if ( deletedFiber.mode & ProfileMode) {\n                        startLayoutEffectTimer();\n                        safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy);\n                        recordLayoutEffectDuration(deletedFiber);\n                      } else {\n                        safelyCallDestroy(deletedFiber, nearestMountedAncestor, destroy);\n                      }\n\n                      {\n                        markComponentLayoutEffectUnmountStopped();\n                      }\n                    }\n                  }\n\n                  effect = effect.next;\n                } while (effect !== firstEffect);\n              }\n            }\n          }\n\n          recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n          return;\n        }\n\n      case ClassComponent:\n        {\n          if (!offscreenSubtreeWasHidden) {\n            safelyDetachRef(deletedFiber, nearestMountedAncestor);\n            var instance = deletedFiber.stateNode;\n\n            if (typeof instance.componentWillUnmount === 'function') {\n              safelyCallComponentWillUnmount(deletedFiber, nearestMountedAncestor, instance);\n            }\n          }\n\n          recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n          return;\n        }\n\n      case ScopeComponent:\n        {\n\n          recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n          return;\n        }\n\n      case OffscreenComponent:\n        {\n          if ( // TODO: Remove this dead flag\n           deletedFiber.mode & ConcurrentMode) {\n            // If this offscreen component is hidden, we already unmounted it. Before\n            // deleting the children, track that it's already unmounted so that we\n            // don't attempt to unmount the effects again.\n            // TODO: If the tree is hidden, in most cases we should be able to skip\n            // over the nested children entirely. An exception is we haven't yet found\n            // the topmost host node to delete, which we already track on the stack.\n            // But the other case is portals, which need to be detached no matter how\n            // deeply they are nested. We should use a subtree flag to track whether a\n            // subtree includes a nested portal.\n            var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden;\n            offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden || deletedFiber.memoizedState !== null;\n            recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n            offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden;\n          } else {\n            recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n          }\n\n          break;\n        }\n\n      default:\n        {\n          recursivelyTraverseDeletionEffects(finishedRoot, nearestMountedAncestor, deletedFiber);\n          return;\n        }\n    }\n  }\n\n  function commitSuspenseCallback(finishedWork) {\n    // TODO: Move this to passive phase\n    var newState = finishedWork.memoizedState;\n  }\n\n  function commitSuspenseHydrationCallbacks(finishedRoot, finishedWork) {\n\n    var newState = finishedWork.memoizedState;\n\n    if (newState === null) {\n      var current = finishedWork.alternate;\n\n      if (current !== null) {\n        var prevState = current.memoizedState;\n\n        if (prevState !== null) {\n          var suspenseInstance = prevState.dehydrated;\n\n          if (suspenseInstance !== null) {\n            commitHydratedSuspenseInstance(suspenseInstance);\n          }\n        }\n      }\n    }\n  }\n\n  function attachSuspenseRetryListeners(finishedWork) {\n    // If this boundary just timed out, then it will have a set of wakeables.\n    // For each wakeable, attach a listener so that when it resolves, React\n    // attempts to re-render the boundary in the primary (pre-timeout) state.\n    var wakeables = finishedWork.updateQueue;\n\n    if (wakeables !== null) {\n      finishedWork.updateQueue = null;\n      var retryCache = finishedWork.stateNode;\n\n      if (retryCache === null) {\n        retryCache = finishedWork.stateNode = new PossiblyWeakSet();\n      }\n\n      wakeables.forEach(function (wakeable) {\n        // Memoize using the boundary fiber to prevent redundant listeners.\n        var retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);\n\n        if (!retryCache.has(wakeable)) {\n          retryCache.add(wakeable);\n\n          {\n            if (isDevToolsPresent) {\n              if (inProgressLanes !== null && inProgressRoot !== null) {\n                // If we have pending work still, associate the original updaters with it.\n                restorePendingUpdaters(inProgressRoot, inProgressLanes);\n              } else {\n                throw Error('Expected finished root and lanes to be set. This is a bug in React.');\n              }\n            }\n          }\n\n          wakeable.then(retry, retry);\n        }\n      });\n    }\n  } // This function detects when a Suspense boundary goes from visible to hidden.\n  function commitMutationEffects(root, finishedWork, committedLanes) {\n    inProgressLanes = committedLanes;\n    inProgressRoot = root;\n    setCurrentFiber(finishedWork);\n    commitMutationEffectsOnFiber(finishedWork, root);\n    setCurrentFiber(finishedWork);\n    inProgressLanes = null;\n    inProgressRoot = null;\n  }\n\n  function recursivelyTraverseMutationEffects(root, parentFiber, lanes) {\n    // Deletions effects can be scheduled on any fiber type. They need to happen\n    // before the children effects hae fired.\n    var deletions = parentFiber.deletions;\n\n    if (deletions !== null) {\n      for (var i = 0; i < deletions.length; i++) {\n        var childToDelete = deletions[i];\n\n        try {\n          commitDeletionEffects(root, parentFiber, childToDelete);\n        } catch (error) {\n          captureCommitPhaseError(childToDelete, parentFiber, error);\n        }\n      }\n    }\n\n    var prevDebugFiber = getCurrentFiber();\n\n    if (parentFiber.subtreeFlags & MutationMask) {\n      var child = parentFiber.child;\n\n      while (child !== null) {\n        setCurrentFiber(child);\n        commitMutationEffectsOnFiber(child, root);\n        child = child.sibling;\n      }\n    }\n\n    setCurrentFiber(prevDebugFiber);\n  }\n\n  function commitMutationEffectsOnFiber(finishedWork, root, lanes) {\n    var current = finishedWork.alternate;\n    var flags = finishedWork.flags; // The effect flag should be checked *after* we refine the type of fiber,\n    // because the fiber tag is more specific. An exception is any flag related\n    // to reconcilation, because those can be set on all fiber types.\n\n    switch (finishedWork.tag) {\n      case FunctionComponent:\n      case ForwardRef:\n      case MemoComponent:\n      case SimpleMemoComponent:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n\n          if (flags & Update) {\n            try {\n              commitHookEffectListUnmount(Insertion | HasEffect, finishedWork, finishedWork.return);\n              commitHookEffectListMount(Insertion | HasEffect, finishedWork);\n            } catch (error) {\n              captureCommitPhaseError(finishedWork, finishedWork.return, error);\n            } // Layout effects are destroyed during the mutation phase so that all\n            // destroy functions for all fibers are called before any create functions.\n            // This prevents sibling component effects from interfering with each other,\n            // e.g. a destroy function in one component should never override a ref set\n            // by a create function in another component during the same commit.\n\n\n            if ( finishedWork.mode & ProfileMode) {\n              try {\n                startLayoutEffectTimer();\n                commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return);\n              } catch (error) {\n                captureCommitPhaseError(finishedWork, finishedWork.return, error);\n              }\n\n              recordLayoutEffectDuration(finishedWork);\n            } else {\n              try {\n                commitHookEffectListUnmount(Layout | HasEffect, finishedWork, finishedWork.return);\n              } catch (error) {\n                captureCommitPhaseError(finishedWork, finishedWork.return, error);\n              }\n            }\n          }\n\n          return;\n        }\n\n      case ClassComponent:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n\n          if (flags & Ref) {\n            if (current !== null) {\n              safelyDetachRef(current, current.return);\n            }\n          }\n\n          return;\n        }\n\n      case HostComponent:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n\n          if (flags & Ref) {\n            if (current !== null) {\n              safelyDetachRef(current, current.return);\n            }\n          }\n\n          {\n            // TODO: ContentReset gets cleared by the children during the commit\n            // phase. This is a refactor hazard because it means we must read\n            // flags the flags after `commitReconciliationEffects` has already run;\n            // the order matters. We should refactor so that ContentReset does not\n            // rely on mutating the flag during commit. Like by setting a flag\n            // during the render phase instead.\n            if (finishedWork.flags & ContentReset) {\n              var instance = finishedWork.stateNode;\n\n              try {\n                resetTextContent(instance);\n              } catch (error) {\n                captureCommitPhaseError(finishedWork, finishedWork.return, error);\n              }\n            }\n\n            if (flags & Update) {\n              var _instance4 = finishedWork.stateNode;\n\n              if (_instance4 != null) {\n                // Commit the work prepared earlier.\n                var newProps = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps\n                // as the newProps. The updatePayload will contain the real change in\n                // this case.\n\n                var oldProps = current !== null ? current.memoizedProps : newProps;\n                var type = finishedWork.type; // TODO: Type the updateQueue to be specific to host components.\n\n                var updatePayload = finishedWork.updateQueue;\n                finishedWork.updateQueue = null;\n\n                if (updatePayload !== null) {\n                  try {\n                    commitUpdate(_instance4, updatePayload, type, oldProps, newProps, finishedWork);\n                  } catch (error) {\n                    captureCommitPhaseError(finishedWork, finishedWork.return, error);\n                  }\n                }\n              }\n            }\n          }\n\n          return;\n        }\n\n      case HostText:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n\n          if (flags & Update) {\n            {\n              if (finishedWork.stateNode === null) {\n                throw new Error('This should have a text node initialized. This error is likely ' + 'caused by a bug in React. Please file an issue.');\n              }\n\n              var textInstance = finishedWork.stateNode;\n              var newText = finishedWork.memoizedProps; // For hydration we reuse the update path but we treat the oldProps\n              // as the newProps. The updatePayload will contain the real change in\n              // this case.\n\n              var oldText = current !== null ? current.memoizedProps : newText;\n\n              try {\n                commitTextUpdate(textInstance, oldText, newText);\n              } catch (error) {\n                captureCommitPhaseError(finishedWork, finishedWork.return, error);\n              }\n            }\n          }\n\n          return;\n        }\n\n      case HostRoot:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n\n          if (flags & Update) {\n            {\n              if (current !== null) {\n                var prevRootState = current.memoizedState;\n\n                if (prevRootState.isDehydrated) {\n                  try {\n                    commitHydratedContainer(root.containerInfo);\n                  } catch (error) {\n                    captureCommitPhaseError(finishedWork, finishedWork.return, error);\n                  }\n                }\n              }\n            }\n          }\n\n          return;\n        }\n\n      case HostPortal:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n\n          return;\n        }\n\n      case SuspenseComponent:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n          var offscreenFiber = finishedWork.child;\n\n          if (offscreenFiber.flags & Visibility) {\n            var offscreenInstance = offscreenFiber.stateNode;\n            var newState = offscreenFiber.memoizedState;\n            var isHidden = newState !== null; // Track the current state on the Offscreen instance so we can\n            // read it during an event\n\n            offscreenInstance.isHidden = isHidden;\n\n            if (isHidden) {\n              var wasHidden = offscreenFiber.alternate !== null && offscreenFiber.alternate.memoizedState !== null;\n\n              if (!wasHidden) {\n                // TODO: Move to passive phase\n                markCommitTimeOfFallback();\n              }\n            }\n          }\n\n          if (flags & Update) {\n            try {\n              commitSuspenseCallback(finishedWork);\n            } catch (error) {\n              captureCommitPhaseError(finishedWork, finishedWork.return, error);\n            }\n\n            attachSuspenseRetryListeners(finishedWork);\n          }\n\n          return;\n        }\n\n      case OffscreenComponent:\n        {\n          var _wasHidden = current !== null && current.memoizedState !== null;\n\n          if ( // TODO: Remove this dead flag\n           finishedWork.mode & ConcurrentMode) {\n            // Before committing the children, track on the stack whether this\n            // offscreen subtree was already hidden, so that we don't unmount the\n            // effects again.\n            var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden;\n            offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden || _wasHidden;\n            recursivelyTraverseMutationEffects(root, finishedWork);\n            offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden;\n          } else {\n            recursivelyTraverseMutationEffects(root, finishedWork);\n          }\n\n          commitReconciliationEffects(finishedWork);\n\n          if (flags & Visibility) {\n            var _offscreenInstance = finishedWork.stateNode;\n            var _newState = finishedWork.memoizedState;\n\n            var _isHidden = _newState !== null;\n\n            var offscreenBoundary = finishedWork; // Track the current state on the Offscreen instance so we can\n            // read it during an event\n\n            _offscreenInstance.isHidden = _isHidden;\n\n            {\n              if (_isHidden) {\n                if (!_wasHidden) {\n                  if ((offscreenBoundary.mode & ConcurrentMode) !== NoMode) {\n                    nextEffect = offscreenBoundary;\n                    var offscreenChild = offscreenBoundary.child;\n\n                    while (offscreenChild !== null) {\n                      nextEffect = offscreenChild;\n                      disappearLayoutEffects_begin(offscreenChild);\n                      offscreenChild = offscreenChild.sibling;\n                    }\n                  }\n                }\n              }\n            }\n\n            {\n              // TODO: This needs to run whenever there's an insertion or update\n              // inside a hidden Offscreen tree.\n              hideOrUnhideAllChildren(offscreenBoundary, _isHidden);\n            }\n          }\n\n          return;\n        }\n\n      case SuspenseListComponent:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n\n          if (flags & Update) {\n            attachSuspenseRetryListeners(finishedWork);\n          }\n\n          return;\n        }\n\n      case ScopeComponent:\n        {\n\n          return;\n        }\n\n      default:\n        {\n          recursivelyTraverseMutationEffects(root, finishedWork);\n          commitReconciliationEffects(finishedWork);\n          return;\n        }\n    }\n  }\n\n  function commitReconciliationEffects(finishedWork) {\n    // Placement effects (insertions, reorders) can be scheduled on any fiber\n    // type. They needs to happen after the children effects have fired, but\n    // before the effects on this fiber have fired.\n    var flags = finishedWork.flags;\n\n    if (flags & Placement) {\n      try {\n        commitPlacement(finishedWork);\n      } catch (error) {\n        captureCommitPhaseError(finishedWork, finishedWork.return, error);\n      } // Clear the \"placement\" from effect tag so that we know that this is\n      // inserted, before any life-cycles like componentDidMount gets called.\n      // TODO: findDOMNode doesn't rely on this any more but isMounted does\n      // and isMounted is deprecated anyway so we should be able to kill this.\n\n\n      finishedWork.flags &= ~Placement;\n    }\n\n    if (flags & Hydrating) {\n      finishedWork.flags &= ~Hydrating;\n    }\n  }\n\n  function commitLayoutEffects(finishedWork, root, committedLanes) {\n    inProgressLanes = committedLanes;\n    inProgressRoot = root;\n    nextEffect = finishedWork;\n    commitLayoutEffects_begin(finishedWork, root, committedLanes);\n    inProgressLanes = null;\n    inProgressRoot = null;\n  }\n\n  function commitLayoutEffects_begin(subtreeRoot, root, committedLanes) {\n    // Suspense layout effects semantics don't change for legacy roots.\n    var isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;\n\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n      var firstChild = fiber.child;\n\n      if ( fiber.tag === OffscreenComponent && isModernRoot) {\n        // Keep track of the current Offscreen stack's state.\n        var isHidden = fiber.memoizedState !== null;\n        var newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden;\n\n        if (newOffscreenSubtreeIsHidden) {\n          // The Offscreen tree is hidden. Skip over its layout effects.\n          commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);\n          continue;\n        } else {\n          // TODO (Offscreen) Also check: subtreeFlags & LayoutMask\n          var current = fiber.alternate;\n          var wasHidden = current !== null && current.memoizedState !== null;\n          var newOffscreenSubtreeWasHidden = wasHidden || offscreenSubtreeWasHidden;\n          var prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden;\n          var prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden; // Traverse the Offscreen subtree with the current Offscreen as the root.\n\n          offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden;\n          offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden;\n\n          if (offscreenSubtreeWasHidden && !prevOffscreenSubtreeWasHidden) {\n            // This is the root of a reappearing boundary. Turn its layout effects\n            // back on.\n            nextEffect = fiber;\n            reappearLayoutEffects_begin(fiber);\n          }\n\n          var child = firstChild;\n\n          while (child !== null) {\n            nextEffect = child;\n            commitLayoutEffects_begin(child, // New root; bubble back up to here and stop.\n            root, committedLanes);\n            child = child.sibling;\n          } // Restore Offscreen state and resume in our-progress traversal.\n\n\n          nextEffect = fiber;\n          offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden;\n          offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden;\n          commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);\n          continue;\n        }\n      }\n\n      if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {\n        firstChild.return = fiber;\n        nextEffect = firstChild;\n      } else {\n        commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);\n      }\n    }\n  }\n\n  function commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n\n      if ((fiber.flags & LayoutMask) !== NoFlags) {\n        var current = fiber.alternate;\n        setCurrentFiber(fiber);\n\n        try {\n          commitLayoutEffectOnFiber(root, current, fiber, committedLanes);\n        } catch (error) {\n          captureCommitPhaseError(fiber, fiber.return, error);\n        }\n\n        resetCurrentFiber();\n      }\n\n      if (fiber === subtreeRoot) {\n        nextEffect = null;\n        return;\n      }\n\n      var sibling = fiber.sibling;\n\n      if (sibling !== null) {\n        sibling.return = fiber.return;\n        nextEffect = sibling;\n        return;\n      }\n\n      nextEffect = fiber.return;\n    }\n  }\n\n  function disappearLayoutEffects_begin(subtreeRoot) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n      var firstChild = fiber.child; // TODO (Offscreen) Check: flags & (RefStatic | LayoutStatic)\n\n      switch (fiber.tag) {\n        case FunctionComponent:\n        case ForwardRef:\n        case MemoComponent:\n        case SimpleMemoComponent:\n          {\n            if ( fiber.mode & ProfileMode) {\n              try {\n                startLayoutEffectTimer();\n                commitHookEffectListUnmount(Layout, fiber, fiber.return);\n              } finally {\n                recordLayoutEffectDuration(fiber);\n              }\n            } else {\n              commitHookEffectListUnmount(Layout, fiber, fiber.return);\n            }\n\n            break;\n          }\n\n        case ClassComponent:\n          {\n            // TODO (Offscreen) Check: flags & RefStatic\n            safelyDetachRef(fiber, fiber.return);\n            var instance = fiber.stateNode;\n\n            if (typeof instance.componentWillUnmount === 'function') {\n              safelyCallComponentWillUnmount(fiber, fiber.return, instance);\n            }\n\n            break;\n          }\n\n        case HostComponent:\n          {\n            safelyDetachRef(fiber, fiber.return);\n            break;\n          }\n\n        case OffscreenComponent:\n          {\n            // Check if this is a\n            var isHidden = fiber.memoizedState !== null;\n\n            if (isHidden) {\n              // Nested Offscreen tree is already hidden. Don't disappear\n              // its effects.\n              disappearLayoutEffects_complete(subtreeRoot);\n              continue;\n            }\n\n            break;\n          }\n      } // TODO (Offscreen) Check: subtreeFlags & LayoutStatic\n\n\n      if (firstChild !== null) {\n        firstChild.return = fiber;\n        nextEffect = firstChild;\n      } else {\n        disappearLayoutEffects_complete(subtreeRoot);\n      }\n    }\n  }\n\n  function disappearLayoutEffects_complete(subtreeRoot) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n\n      if (fiber === subtreeRoot) {\n        nextEffect = null;\n        return;\n      }\n\n      var sibling = fiber.sibling;\n\n      if (sibling !== null) {\n        sibling.return = fiber.return;\n        nextEffect = sibling;\n        return;\n      }\n\n      nextEffect = fiber.return;\n    }\n  }\n\n  function reappearLayoutEffects_begin(subtreeRoot) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n      var firstChild = fiber.child;\n\n      if (fiber.tag === OffscreenComponent) {\n        var isHidden = fiber.memoizedState !== null;\n\n        if (isHidden) {\n          // Nested Offscreen tree is still hidden. Don't re-appear its effects.\n          reappearLayoutEffects_complete(subtreeRoot);\n          continue;\n        }\n      } // TODO (Offscreen) Check: subtreeFlags & LayoutStatic\n\n\n      if (firstChild !== null) {\n        // This node may have been reused from a previous render, so we can't\n        // assume its return pointer is correct.\n        firstChild.return = fiber;\n        nextEffect = firstChild;\n      } else {\n        reappearLayoutEffects_complete(subtreeRoot);\n      }\n    }\n  }\n\n  function reappearLayoutEffects_complete(subtreeRoot) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect; // TODO (Offscreen) Check: flags & LayoutStatic\n\n      setCurrentFiber(fiber);\n\n      try {\n        reappearLayoutEffectsOnFiber(fiber);\n      } catch (error) {\n        captureCommitPhaseError(fiber, fiber.return, error);\n      }\n\n      resetCurrentFiber();\n\n      if (fiber === subtreeRoot) {\n        nextEffect = null;\n        return;\n      }\n\n      var sibling = fiber.sibling;\n\n      if (sibling !== null) {\n        // This node may have been reused from a previous render, so we can't\n        // assume its return pointer is correct.\n        sibling.return = fiber.return;\n        nextEffect = sibling;\n        return;\n      }\n\n      nextEffect = fiber.return;\n    }\n  }\n\n  function commitPassiveMountEffects(root, finishedWork, committedLanes, committedTransitions) {\n    nextEffect = finishedWork;\n    commitPassiveMountEffects_begin(finishedWork, root, committedLanes, committedTransitions);\n  }\n\n  function commitPassiveMountEffects_begin(subtreeRoot, root, committedLanes, committedTransitions) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n      var firstChild = fiber.child;\n\n      if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {\n        firstChild.return = fiber;\n        nextEffect = firstChild;\n      } else {\n        commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes, committedTransitions);\n      }\n    }\n  }\n\n  function commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes, committedTransitions) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n\n      if ((fiber.flags & Passive) !== NoFlags) {\n        setCurrentFiber(fiber);\n\n        try {\n          commitPassiveMountOnFiber(root, fiber, committedLanes, committedTransitions);\n        } catch (error) {\n          captureCommitPhaseError(fiber, fiber.return, error);\n        }\n\n        resetCurrentFiber();\n      }\n\n      if (fiber === subtreeRoot) {\n        nextEffect = null;\n        return;\n      }\n\n      var sibling = fiber.sibling;\n\n      if (sibling !== null) {\n        sibling.return = fiber.return;\n        nextEffect = sibling;\n        return;\n      }\n\n      nextEffect = fiber.return;\n    }\n  }\n\n  function commitPassiveMountOnFiber(finishedRoot, finishedWork, committedLanes, committedTransitions) {\n    switch (finishedWork.tag) {\n      case FunctionComponent:\n      case ForwardRef:\n      case SimpleMemoComponent:\n        {\n          if ( finishedWork.mode & ProfileMode) {\n            startPassiveEffectTimer();\n\n            try {\n              commitHookEffectListMount(Passive$1 | HasEffect, finishedWork);\n            } finally {\n              recordPassiveEffectDuration(finishedWork);\n            }\n          } else {\n            commitHookEffectListMount(Passive$1 | HasEffect, finishedWork);\n          }\n\n          break;\n        }\n    }\n  }\n\n  function commitPassiveUnmountEffects(firstChild) {\n    nextEffect = firstChild;\n    commitPassiveUnmountEffects_begin();\n  }\n\n  function commitPassiveUnmountEffects_begin() {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n      var child = fiber.child;\n\n      if ((nextEffect.flags & ChildDeletion) !== NoFlags) {\n        var deletions = fiber.deletions;\n\n        if (deletions !== null) {\n          for (var i = 0; i < deletions.length; i++) {\n            var fiberToDelete = deletions[i];\n            nextEffect = fiberToDelete;\n            commitPassiveUnmountEffectsInsideOfDeletedTree_begin(fiberToDelete, fiber);\n          }\n\n          {\n            // A fiber was deleted from this parent fiber, but it's still part of\n            // the previous (alternate) parent fiber's list of children. Because\n            // children are a linked list, an earlier sibling that's still alive\n            // will be connected to the deleted fiber via its `alternate`:\n            //\n            //   live fiber\n            //   --alternate--> previous live fiber\n            //   --sibling--> deleted fiber\n            //\n            // We can't disconnect `alternate` on nodes that haven't been deleted\n            // yet, but we can disconnect the `sibling` and `child` pointers.\n            var previousFiber = fiber.alternate;\n\n            if (previousFiber !== null) {\n              var detachedChild = previousFiber.child;\n\n              if (detachedChild !== null) {\n                previousFiber.child = null;\n\n                do {\n                  var detachedSibling = detachedChild.sibling;\n                  detachedChild.sibling = null;\n                  detachedChild = detachedSibling;\n                } while (detachedChild !== null);\n              }\n            }\n          }\n\n          nextEffect = fiber;\n        }\n      }\n\n      if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null) {\n        child.return = fiber;\n        nextEffect = child;\n      } else {\n        commitPassiveUnmountEffects_complete();\n      }\n    }\n  }\n\n  function commitPassiveUnmountEffects_complete() {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n\n      if ((fiber.flags & Passive) !== NoFlags) {\n        setCurrentFiber(fiber);\n        commitPassiveUnmountOnFiber(fiber);\n        resetCurrentFiber();\n      }\n\n      var sibling = fiber.sibling;\n\n      if (sibling !== null) {\n        sibling.return = fiber.return;\n        nextEffect = sibling;\n        return;\n      }\n\n      nextEffect = fiber.return;\n    }\n  }\n\n  function commitPassiveUnmountOnFiber(finishedWork) {\n    switch (finishedWork.tag) {\n      case FunctionComponent:\n      case ForwardRef:\n      case SimpleMemoComponent:\n        {\n          if ( finishedWork.mode & ProfileMode) {\n            startPassiveEffectTimer();\n            commitHookEffectListUnmount(Passive$1 | HasEffect, finishedWork, finishedWork.return);\n            recordPassiveEffectDuration(finishedWork);\n          } else {\n            commitHookEffectListUnmount(Passive$1 | HasEffect, finishedWork, finishedWork.return);\n          }\n\n          break;\n        }\n    }\n  }\n\n  function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(deletedSubtreeRoot, nearestMountedAncestor) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect; // Deletion effects fire in parent -> child order\n      // TODO: Check if fiber has a PassiveStatic flag\n\n      setCurrentFiber(fiber);\n      commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);\n      resetCurrentFiber();\n      var child = fiber.child; // TODO: Only traverse subtree if it has a PassiveStatic flag. (But, if we\n      // do this, still need to handle `deletedTreeCleanUpLevel` correctly.)\n\n      if (child !== null) {\n        child.return = fiber;\n        nextEffect = child;\n      } else {\n        commitPassiveUnmountEffectsInsideOfDeletedTree_complete(deletedSubtreeRoot);\n      }\n    }\n  }\n\n  function commitPassiveUnmountEffectsInsideOfDeletedTree_complete(deletedSubtreeRoot) {\n    while (nextEffect !== null) {\n      var fiber = nextEffect;\n      var sibling = fiber.sibling;\n      var returnFiber = fiber.return;\n\n      {\n        // Recursively traverse the entire deleted tree and clean up fiber fields.\n        // This is more aggressive than ideal, and the long term goal is to only\n        // have to detach the deleted tree at the root.\n        detachFiberAfterEffects(fiber);\n\n        if (fiber === deletedSubtreeRoot) {\n          nextEffect = null;\n          return;\n        }\n      }\n\n      if (sibling !== null) {\n        sibling.return = returnFiber;\n        nextEffect = sibling;\n        return;\n      }\n\n      nextEffect = returnFiber;\n    }\n  }\n\n  function commitPassiveUnmountInsideDeletedTreeOnFiber(current, nearestMountedAncestor) {\n    switch (current.tag) {\n      case FunctionComponent:\n      case ForwardRef:\n      case SimpleMemoComponent:\n        {\n          if ( current.mode & ProfileMode) {\n            startPassiveEffectTimer();\n            commitHookEffectListUnmount(Passive$1, current, nearestMountedAncestor);\n            recordPassiveEffectDuration(current);\n          } else {\n            commitHookEffectListUnmount(Passive$1, current, nearestMountedAncestor);\n          }\n\n          break;\n        }\n    }\n  } // TODO: Reuse reappearLayoutEffects traversal here?\n\n\n  function invokeLayoutEffectMountInDEV(fiber) {\n    {\n      // We don't need to re-check StrictEffectsMode here.\n      // This function is only called if that check has already passed.\n      switch (fiber.tag) {\n        case FunctionComponent:\n        case ForwardRef:\n        case SimpleMemoComponent:\n          {\n            try {\n              commitHookEffectListMount(Layout | HasEffect, fiber);\n            } catch (error) {\n              captureCommitPhaseError(fiber, fiber.return, error);\n            }\n\n            break;\n          }\n\n        case ClassComponent:\n          {\n            var instance = fiber.stateNode;\n\n            try {\n              instance.componentDidMount();\n            } catch (error) {\n              captureCommitPhaseError(fiber, fiber.return, error);\n            }\n\n            break;\n          }\n      }\n    }\n  }\n\n  function invokePassiveEffectMountInDEV(fiber) {\n    {\n      // We don't need to re-check StrictEffectsMode here.\n      // This function is only called if that check has already passed.\n      switch (fiber.tag) {\n        case FunctionComponent:\n        case ForwardRef:\n        case SimpleMemoComponent:\n          {\n            try {\n              commitHookEffectListMount(Passive$1 | HasEffect, fiber);\n            } catch (error) {\n              captureCommitPhaseError(fiber, fiber.return, error);\n            }\n\n            break;\n          }\n      }\n    }\n  }\n\n  function invokeLayoutEffectUnmountInDEV(fiber) {\n    {\n      // We don't need to re-check StrictEffectsMode here.\n      // This function is only called if that check has already passed.\n      switch (fiber.tag) {\n        case FunctionComponent:\n        case ForwardRef:\n        case SimpleMemoComponent:\n          {\n            try {\n              commitHookEffectListUnmount(Layout | HasEffect, fiber, fiber.return);\n            } catch (error) {\n              captureCommitPhaseError(fiber, fiber.return, error);\n            }\n\n            break;\n          }\n\n        case ClassComponent:\n          {\n            var instance = fiber.stateNode;\n\n            if (typeof instance.componentWillUnmount === 'function') {\n              safelyCallComponentWillUnmount(fiber, fiber.return, instance);\n            }\n\n            break;\n          }\n      }\n    }\n  }\n\n  function invokePassiveEffectUnmountInDEV(fiber) {\n    {\n      // We don't need to re-check StrictEffectsMode here.\n      // This function is only called if that check has already passed.\n      switch (fiber.tag) {\n        case FunctionComponent:\n        case ForwardRef:\n        case SimpleMemoComponent:\n          {\n            try {\n              commitHookEffectListUnmount(Passive$1 | HasEffect, fiber, fiber.return);\n            } catch (error) {\n              captureCommitPhaseError(fiber, fiber.return, error);\n            }\n          }\n      }\n    }\n  }\n\n  var COMPONENT_TYPE = 0;\n  var HAS_PSEUDO_CLASS_TYPE = 1;\n  var ROLE_TYPE = 2;\n  var TEST_NAME_TYPE = 3;\n  var TEXT_TYPE = 4;\n\n  if (typeof Symbol === 'function' && Symbol.for) {\n    var symbolFor = Symbol.for;\n    COMPONENT_TYPE = symbolFor('selector.component');\n    HAS_PSEUDO_CLASS_TYPE = symbolFor('selector.has_pseudo_class');\n    ROLE_TYPE = symbolFor('selector.role');\n    TEST_NAME_TYPE = symbolFor('selector.test_id');\n    TEXT_TYPE = symbolFor('selector.text');\n  }\n  var commitHooks = [];\n  function onCommitRoot$1() {\n    {\n      commitHooks.forEach(function (commitHook) {\n        return commitHook();\n      });\n    }\n  }\n\n  var ReactCurrentActQueue = ReactSharedInternals.ReactCurrentActQueue;\n  function isLegacyActEnvironment(fiber) {\n    {\n      // Legacy mode. We preserve the behavior of React 17's act. It assumes an\n      // act environment whenever `jest` is defined, but you can still turn off\n      // spurious warnings by setting IS_REACT_ACT_ENVIRONMENT explicitly\n      // to false.\n      var isReactActEnvironmentGlobal = // $FlowExpectedError – Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global\n      typeof IS_REACT_ACT_ENVIRONMENT !== 'undefined' ? IS_REACT_ACT_ENVIRONMENT : undefined; // $FlowExpectedError - Flow doesn't know about jest\n\n      var jestIsDefined = typeof jest !== 'undefined';\n      return  jestIsDefined && isReactActEnvironmentGlobal !== false;\n    }\n  }\n  function isConcurrentActEnvironment() {\n    {\n      var isReactActEnvironmentGlobal = // $FlowExpectedError – Flow doesn't know about IS_REACT_ACT_ENVIRONMENT global\n      typeof IS_REACT_ACT_ENVIRONMENT !== 'undefined' ? IS_REACT_ACT_ENVIRONMENT : undefined;\n\n      if (!isReactActEnvironmentGlobal && ReactCurrentActQueue.current !== null) {\n        // TODO: Include link to relevant documentation page.\n        error('The current testing environment is not configured to support ' + 'act(...)');\n      }\n\n      return isReactActEnvironmentGlobal;\n    }\n  }\n\n  var ceil = Math.ceil;\n  var ReactCurrentDispatcher$2 = ReactSharedInternals.ReactCurrentDispatcher,\n      ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner,\n      ReactCurrentBatchConfig$3 = ReactSharedInternals.ReactCurrentBatchConfig,\n      ReactCurrentActQueue$1 = ReactSharedInternals.ReactCurrentActQueue;\n  var NoContext =\n  /*             */\n  0;\n  var BatchedContext =\n  /*               */\n  1;\n  var RenderContext =\n  /*                */\n  2;\n  var CommitContext =\n  /*                */\n  4;\n  var RootInProgress = 0;\n  var RootFatalErrored = 1;\n  var RootErrored = 2;\n  var RootSuspended = 3;\n  var RootSuspendedWithDelay = 4;\n  var RootCompleted = 5;\n  var RootDidNotComplete = 6; // Describes where we are in the React execution stack\n\n  var executionContext = NoContext; // The root we're working on\n\n  var workInProgressRoot = null; // The fiber we're working on\n\n  var workInProgress = null; // The lanes we're rendering\n\n  var workInProgressRootRenderLanes = NoLanes; // Stack that allows components to change the render lanes for its subtree\n  // This is a superset of the lanes we started working on at the root. The only\n  // case where it's different from `workInProgressRootRenderLanes` is when we\n  // enter a subtree that is hidden and needs to be unhidden: Suspense and\n  // Offscreen component.\n  //\n  // Most things in the work loop should deal with workInProgressRootRenderLanes.\n  // Most things in begin/complete phases should deal with subtreeRenderLanes.\n\n  var subtreeRenderLanes = NoLanes;\n  var subtreeRenderLanesCursor = createCursor(NoLanes); // Whether to root completed, errored, suspended, etc.\n\n  var workInProgressRootExitStatus = RootInProgress; // A fatal error, if one is thrown\n\n  var workInProgressRootFatalError = null; // \"Included\" lanes refer to lanes that were worked on during this render. It's\n  // slightly different than `renderLanes` because `renderLanes` can change as you\n  // enter and exit an Offscreen tree. This value is the combination of all render\n  // lanes for the entire render phase.\n\n  var workInProgressRootIncludedLanes = NoLanes; // The work left over by components that were visited during this render. Only\n  // includes unprocessed updates, not work in bailed out children.\n\n  var workInProgressRootSkippedLanes = NoLanes; // Lanes that were updated (in an interleaved event) during this render.\n\n  var workInProgressRootInterleavedUpdatedLanes = NoLanes; // Lanes that were updated during the render phase (*not* an interleaved event).\n\n  var workInProgressRootPingedLanes = NoLanes; // Errors that are thrown during the render phase.\n\n  var workInProgressRootConcurrentErrors = null; // These are errors that we recovered from without surfacing them to the UI.\n  // We will log them once the tree commits.\n\n  var workInProgressRootRecoverableErrors = null; // The most recent time we committed a fallback. This lets us ensure a train\n  // model where we don't commit new loading states in too quick succession.\n\n  var globalMostRecentFallbackTime = 0;\n  var FALLBACK_THROTTLE_MS = 500; // The absolute time for when we should start giving up on rendering\n  // more and prefer CPU suspense heuristics instead.\n\n  var workInProgressRootRenderTargetTime = Infinity; // How long a render is supposed to take before we start following CPU\n  // suspense heuristics and opt out of rendering more content.\n\n  var RENDER_TIMEOUT_MS = 500;\n  var workInProgressTransitions = null;\n\n  function resetRenderTimer() {\n    workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;\n  }\n\n  function getRenderTargetTime() {\n    return workInProgressRootRenderTargetTime;\n  }\n  var hasUncaughtError = false;\n  var firstUncaughtError = null;\n  var legacyErrorBoundariesThatAlreadyFailed = null; // Only used when enableProfilerNestedUpdateScheduledHook is true;\n  var rootDoesHavePassiveEffects = false;\n  var rootWithPendingPassiveEffects = null;\n  var pendingPassiveEffectsLanes = NoLanes;\n  var pendingPassiveProfilerEffects = [];\n  var pendingPassiveTransitions = null; // Use these to prevent an infinite loop of nested updates\n\n  var NESTED_UPDATE_LIMIT = 50;\n  var nestedUpdateCount = 0;\n  var rootWithNestedUpdates = null;\n  var isFlushingPassiveEffects = false;\n  var didScheduleUpdateDuringPassiveEffects = false;\n  var NESTED_PASSIVE_UPDATE_LIMIT = 50;\n  var nestedPassiveUpdateCount = 0;\n  var rootWithPassiveNestedUpdates = null; // If two updates are scheduled within the same event, we should treat their\n  // event times as simultaneous, even if the actual clock time has advanced\n  // between the first and second call.\n\n  var currentEventTime = NoTimestamp;\n  var currentEventTransitionLane = NoLanes;\n  var isRunningInsertionEffect = false;\n  function getWorkInProgressRoot() {\n    return workInProgressRoot;\n  }\n  function requestEventTime() {\n    if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {\n      // We're inside React, so it's fine to read the actual time.\n      return now();\n    } // We're not inside React, so we may be in the middle of a browser event.\n\n\n    if (currentEventTime !== NoTimestamp) {\n      // Use the same start time for all updates until we enter React again.\n      return currentEventTime;\n    } // This is the first update since React yielded. Compute a new start time.\n\n\n    currentEventTime = now();\n    return currentEventTime;\n  }\n  function requestUpdateLane(fiber) {\n    // Special cases\n    var mode = fiber.mode;\n\n    if ((mode & ConcurrentMode) === NoMode) {\n      return SyncLane;\n    } else if ( (executionContext & RenderContext) !== NoContext && workInProgressRootRenderLanes !== NoLanes) {\n      // This is a render phase update. These are not officially supported. The\n      // old behavior is to give this the same \"thread\" (lanes) as\n      // whatever is currently rendering. So if you call `setState` on a component\n      // that happens later in the same render, it will flush. Ideally, we want to\n      // remove the special case and treat them as if they came from an\n      // interleaved event. Regardless, this pattern is not officially supported.\n      // This behavior is only a fallback. The flag only exists until we can roll\n      // out the setState warning, since existing code might accidentally rely on\n      // the current behavior.\n      return pickArbitraryLane(workInProgressRootRenderLanes);\n    }\n\n    var isTransition = requestCurrentTransition() !== NoTransition;\n\n    if (isTransition) {\n      if ( ReactCurrentBatchConfig$3.transition !== null) {\n        var transition = ReactCurrentBatchConfig$3.transition;\n\n        if (!transition._updatedFibers) {\n          transition._updatedFibers = new Set();\n        }\n\n        transition._updatedFibers.add(fiber);\n      } // The algorithm for assigning an update to a lane should be stable for all\n      // updates at the same priority within the same event. To do this, the\n      // inputs to the algorithm must be the same.\n      //\n      // The trick we use is to cache the first of each of these inputs within an\n      // event. Then reset the cached values once we can be sure the event is\n      // over. Our heuristic for that is whenever we enter a concurrent work loop.\n\n\n      if (currentEventTransitionLane === NoLane) {\n        // All transitions within the same event are assigned the same lane.\n        currentEventTransitionLane = claimNextTransitionLane();\n      }\n\n      return currentEventTransitionLane;\n    } // Updates originating inside certain React methods, like flushSync, have\n    // their priority set by tracking it with a context variable.\n    //\n    // The opaque type returned by the host config is internally a lane, so we can\n    // use that directly.\n    // TODO: Move this type conversion to the event priority module.\n\n\n    var updateLane = getCurrentUpdatePriority();\n\n    if (updateLane !== NoLane) {\n      return updateLane;\n    } // This update originated outside React. Ask the host environment for an\n    // appropriate priority, based on the type of event.\n    //\n    // The opaque type returned by the host config is internally a lane, so we can\n    // use that directly.\n    // TODO: Move this type conversion to the event priority module.\n\n\n    var eventLane = getCurrentEventPriority();\n    return eventLane;\n  }\n\n  function requestRetryLane(fiber) {\n    // This is a fork of `requestUpdateLane` designed specifically for Suspense\n    // \"retries\" — a special update that attempts to flip a Suspense boundary\n    // from its placeholder state to its primary/resolved state.\n    // Special cases\n    var mode = fiber.mode;\n\n    if ((mode & ConcurrentMode) === NoMode) {\n      return SyncLane;\n    }\n\n    return claimNextRetryLane();\n  }\n\n  function scheduleUpdateOnFiber(root, fiber, lane, eventTime) {\n    checkForNestedUpdates();\n\n    {\n      if (isRunningInsertionEffect) {\n        error('useInsertionEffect must not schedule updates.');\n      }\n    }\n\n    {\n      if (isFlushingPassiveEffects) {\n        didScheduleUpdateDuringPassiveEffects = true;\n      }\n    } // Mark that the root has a pending update.\n\n\n    markRootUpdated(root, lane, eventTime);\n\n    if ((executionContext & RenderContext) !== NoLanes && root === workInProgressRoot) {\n      // This update was dispatched during the render phase. This is a mistake\n      // if the update originates from user space (with the exception of local\n      // hook updates, which are handled differently and don't reach this\n      // function), but there are some internal React features that use this as\n      // an implementation detail, like selective hydration.\n      warnAboutRenderPhaseUpdatesInDEV(fiber); // Track lanes that were updated during the render phase\n    } else {\n      // This is a normal update, scheduled from outside the render phase. For\n      // example, during an input event.\n      {\n        if (isDevToolsPresent) {\n          addFiberToLanesMap(root, fiber, lane);\n        }\n      }\n\n      warnIfUpdatesNotWrappedWithActDEV(fiber);\n\n      if (root === workInProgressRoot) {\n        // Received an update to a tree that's in the middle of rendering. Mark\n        // that there was an interleaved update work on this root. Unless the\n        // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render\n        // phase update. In that case, we don't treat render phase updates as if\n        // they were interleaved, for backwards compat reasons.\n        if ( (executionContext & RenderContext) === NoContext) {\n          workInProgressRootInterleavedUpdatedLanes = mergeLanes(workInProgressRootInterleavedUpdatedLanes, lane);\n        }\n\n        if (workInProgressRootExitStatus === RootSuspendedWithDelay) {\n          // The root already suspended with a delay, which means this render\n          // definitely won't finish. Since we have a new update, let's mark it as\n          // suspended now, right before marking the incoming update. This has the\n          // effect of interrupting the current render and switching to the update.\n          // TODO: Make sure this doesn't override pings that happen while we've\n          // already started rendering.\n          markRootSuspended$1(root, workInProgressRootRenderLanes);\n        }\n      }\n\n      ensureRootIsScheduled(root, eventTime);\n\n      if (lane === SyncLane && executionContext === NoContext && (fiber.mode & ConcurrentMode) === NoMode && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode.\n      !( ReactCurrentActQueue$1.isBatchingLegacy)) {\n        // Flush the synchronous work now, unless we're already working or inside\n        // a batch. This is intentionally inside scheduleUpdateOnFiber instead of\n        // scheduleCallbackForFiber to preserve the ability to schedule a callback\n        // without immediately flushing it. We only do this for user-initiated\n        // updates, to preserve historical behavior of legacy mode.\n        resetRenderTimer();\n        flushSyncCallbacksOnlyInLegacyMode();\n      }\n    }\n  }\n  function scheduleInitialHydrationOnRoot(root, lane, eventTime) {\n    // This is a special fork of scheduleUpdateOnFiber that is only used to\n    // schedule the initial hydration of a root that has just been created. Most\n    // of the stuff in scheduleUpdateOnFiber can be skipped.\n    //\n    // The main reason for this separate path, though, is to distinguish the\n    // initial children from subsequent updates. In fully client-rendered roots\n    // (createRoot instead of hydrateRoot), all top-level renders are modeled as\n    // updates, but hydration roots are special because the initial render must\n    // match what was rendered on the server.\n    var current = root.current;\n    current.lanes = lane;\n    markRootUpdated(root, lane, eventTime);\n    ensureRootIsScheduled(root, eventTime);\n  }\n  function isUnsafeClassRenderPhaseUpdate(fiber) {\n    // Check if this is a render phase update. Only called by class components,\n    // which special (deprecated) behavior for UNSAFE_componentWillReceive props.\n    return (// TODO: Remove outdated deferRenderPhaseUpdateToNextBatch experiment. We\n      // decided not to enable it.\n       (executionContext & RenderContext) !== NoContext\n    );\n  } // Use this function to schedule a task for a root. There's only one task per\n  // root; if a task was already scheduled, we'll check to make sure the priority\n  // of the existing task is the same as the priority of the next level that the\n  // root has work on. This function is called on every update, and right before\n  // exiting a task.\n\n  function ensureRootIsScheduled(root, currentTime) {\n    var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as\n    // expired so we know to work on those next.\n\n    markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority.\n\n    var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes);\n\n    if (nextLanes === NoLanes) {\n      // Special case: There's nothing to work on.\n      if (existingCallbackNode !== null) {\n        cancelCallback$1(existingCallbackNode);\n      }\n\n      root.callbackNode = null;\n      root.callbackPriority = NoLane;\n      return;\n    } // We use the highest priority lane to represent the priority of the callback.\n\n\n    var newCallbackPriority = getHighestPriorityLane(nextLanes); // Check if there's an existing task. We may be able to reuse it.\n\n    var existingCallbackPriority = root.callbackPriority;\n\n    if (existingCallbackPriority === newCallbackPriority && // Special case related to `act`. If the currently scheduled task is a\n    // Scheduler task, rather than an `act` task, cancel it and re-scheduled\n    // on the `act` queue.\n    !( ReactCurrentActQueue$1.current !== null && existingCallbackNode !== fakeActCallbackNode)) {\n      {\n        // If we're going to re-use an existing task, it needs to exist.\n        // Assume that discrete update microtasks are non-cancellable and null.\n        // TODO: Temporary until we confirm this warning is not fired.\n        if (existingCallbackNode == null && existingCallbackPriority !== SyncLane) {\n          error('Expected scheduled callback to exist. This error is likely caused by a bug in React. Please file an issue.');\n        }\n      } // The priority hasn't changed. We can reuse the existing task. Exit.\n\n\n      return;\n    }\n\n    if (existingCallbackNode != null) {\n      // Cancel the existing callback. We'll schedule a new one below.\n      cancelCallback$1(existingCallbackNode);\n    } // Schedule a new callback.\n\n\n    var newCallbackNode;\n\n    if (newCallbackPriority === SyncLane) {\n      // Special case: Sync React callbacks are scheduled on a special\n      // internal queue\n      if (root.tag === LegacyRoot) {\n        if ( ReactCurrentActQueue$1.isBatchingLegacy !== null) {\n          ReactCurrentActQueue$1.didScheduleLegacyUpdate = true;\n        }\n\n        scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root));\n      } else {\n        scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));\n      }\n\n      {\n        // Flush the queue in a microtask.\n        if ( ReactCurrentActQueue$1.current !== null) {\n          // Inside `act`, use our internal `act` queue so that these get flushed\n          // at the end of the current scope even when using the sync version\n          // of `act`.\n          ReactCurrentActQueue$1.current.push(flushSyncCallbacks);\n        } else {\n          scheduleMicrotask(function () {\n            // In Safari, appending an iframe forces microtasks to run.\n            // https://github.com/facebook/react/issues/22459\n            // We don't support running callbacks in the middle of render\n            // or commit so we need to check against that.\n            if ((executionContext & (RenderContext | CommitContext)) === NoContext) {\n              // Note that this would still prematurely flush the callbacks\n              // if this happens outside render or commit phase (e.g. in an event).\n              flushSyncCallbacks();\n            }\n          });\n        }\n      }\n\n      newCallbackNode = null;\n    } else {\n      var schedulerPriorityLevel;\n\n      switch (lanesToEventPriority(nextLanes)) {\n        case DiscreteEventPriority:\n          schedulerPriorityLevel = ImmediatePriority;\n          break;\n\n        case ContinuousEventPriority:\n          schedulerPriorityLevel = UserBlockingPriority;\n          break;\n\n        case DefaultEventPriority:\n          schedulerPriorityLevel = NormalPriority;\n          break;\n\n        case IdleEventPriority:\n          schedulerPriorityLevel = IdlePriority;\n          break;\n\n        default:\n          schedulerPriorityLevel = NormalPriority;\n          break;\n      }\n\n      newCallbackNode = scheduleCallback$1(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root));\n    }\n\n    root.callbackPriority = newCallbackPriority;\n    root.callbackNode = newCallbackNode;\n  } // This is the entry point for every concurrent task, i.e. anything that\n  // goes through Scheduler.\n\n\n  function performConcurrentWorkOnRoot(root, didTimeout) {\n    {\n      resetNestedUpdateFlag();\n    } // Since we know we're in a React event, we can clear the current\n    // event time. The next update will compute a new event time.\n\n\n    currentEventTime = NoTimestamp;\n    currentEventTransitionLane = NoLanes;\n\n    if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {\n      throw new Error('Should not already be working.');\n    } // Flush any pending passive effects before deciding which lanes to work on,\n    // in case they schedule additional work.\n\n\n    var originalCallbackNode = root.callbackNode;\n    var didFlushPassiveEffects = flushPassiveEffects();\n\n    if (didFlushPassiveEffects) {\n      // Something in the passive effect phase may have canceled the current task.\n      // Check if the task node for this root was changed.\n      if (root.callbackNode !== originalCallbackNode) {\n        // The current task was canceled. Exit. We don't need to call\n        // `ensureRootIsScheduled` because the check above implies either that\n        // there's a new task, or that there's no remaining work on this root.\n        return null;\n      }\n    } // Determine the next lanes to work on, using the fields stored\n    // on the root.\n\n\n    var lanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes);\n\n    if (lanes === NoLanes) {\n      // Defensive coding. This is never expected to happen.\n      return null;\n    } // We disable time-slicing in some cases: if the work has been CPU-bound\n    // for too long (\"expired\" work, to prevent starvation), or we're in\n    // sync-updates-by-default mode.\n    // TODO: We only check `didTimeout` defensively, to account for a Scheduler\n    // bug we're still investigating. Once the bug in Scheduler is fixed,\n    // we can remove this, since we track expiration ourselves.\n\n\n    var shouldTimeSlice = !includesBlockingLane(root, lanes) && !includesExpiredLane(root, lanes) && ( !didTimeout);\n    var exitStatus = shouldTimeSlice ? renderRootConcurrent(root, lanes) : renderRootSync(root, lanes);\n\n    if (exitStatus !== RootInProgress) {\n      if (exitStatus === RootErrored) {\n        // If something threw an error, try rendering one more time. We'll\n        // render synchronously to block concurrent data mutations, and we'll\n        // includes all pending updates are included. If it still fails after\n        // the second attempt, we'll give up and commit the resulting tree.\n        var errorRetryLanes = getLanesToRetrySynchronouslyOnError(root);\n\n        if (errorRetryLanes !== NoLanes) {\n          lanes = errorRetryLanes;\n          exitStatus = recoverFromConcurrentError(root, errorRetryLanes);\n        }\n      }\n\n      if (exitStatus === RootFatalErrored) {\n        var fatalError = workInProgressRootFatalError;\n        prepareFreshStack(root, NoLanes);\n        markRootSuspended$1(root, lanes);\n        ensureRootIsScheduled(root, now());\n        throw fatalError;\n      }\n\n      if (exitStatus === RootDidNotComplete) {\n        // The render unwound without completing the tree. This happens in special\n        // cases where need to exit the current render without producing a\n        // consistent tree or committing.\n        //\n        // This should only happen during a concurrent render, not a discrete or\n        // synchronous update. We should have already checked for this when we\n        // unwound the stack.\n        markRootSuspended$1(root, lanes);\n      } else {\n        // The render completed.\n        // Check if this render may have yielded to a concurrent event, and if so,\n        // confirm that any newly rendered stores are consistent.\n        // TODO: It's possible that even a concurrent render may never have yielded\n        // to the main thread, if it was fast enough, or if it expired. We could\n        // skip the consistency check in that case, too.\n        var renderWasConcurrent = !includesBlockingLane(root, lanes);\n        var finishedWork = root.current.alternate;\n\n        if (renderWasConcurrent && !isRenderConsistentWithExternalStores(finishedWork)) {\n          // A store was mutated in an interleaved event. Render again,\n          // synchronously, to block further mutations.\n          exitStatus = renderRootSync(root, lanes); // We need to check again if something threw\n\n          if (exitStatus === RootErrored) {\n            var _errorRetryLanes = getLanesToRetrySynchronouslyOnError(root);\n\n            if (_errorRetryLanes !== NoLanes) {\n              lanes = _errorRetryLanes;\n              exitStatus = recoverFromConcurrentError(root, _errorRetryLanes); // We assume the tree is now consistent because we didn't yield to any\n              // concurrent events.\n            }\n          }\n\n          if (exitStatus === RootFatalErrored) {\n            var _fatalError = workInProgressRootFatalError;\n            prepareFreshStack(root, NoLanes);\n            markRootSuspended$1(root, lanes);\n            ensureRootIsScheduled(root, now());\n            throw _fatalError;\n          }\n        } // We now have a consistent tree. The next step is either to commit it,\n        // or, if something suspended, wait to commit it after a timeout.\n\n\n        root.finishedWork = finishedWork;\n        root.finishedLanes = lanes;\n        finishConcurrentRender(root, exitStatus, lanes);\n      }\n    }\n\n    ensureRootIsScheduled(root, now());\n\n    if (root.callbackNode === originalCallbackNode) {\n      // The task node scheduled for this root is the same one that's\n      // currently executed. Need to return a continuation.\n      return performConcurrentWorkOnRoot.bind(null, root);\n    }\n\n    return null;\n  }\n\n  function recoverFromConcurrentError(root, errorRetryLanes) {\n    // If an error occurred during hydration, discard server response and fall\n    // back to client side render.\n    // Before rendering again, save the errors from the previous attempt.\n    var errorsFromFirstAttempt = workInProgressRootConcurrentErrors;\n\n    if (isRootDehydrated(root)) {\n      // The shell failed to hydrate. Set a flag to force a client rendering\n      // during the next attempt. To do this, we call prepareFreshStack now\n      // to create the root work-in-progress fiber. This is a bit weird in terms\n      // of factoring, because it relies on renderRootSync not calling\n      // prepareFreshStack again in the call below, which happens because the\n      // root and lanes haven't changed.\n      //\n      // TODO: I think what we should do is set ForceClientRender inside\n      // throwException, like we do for nested Suspense boundaries. The reason\n      // it's here instead is so we can switch to the synchronous work loop, too.\n      // Something to consider for a future refactor.\n      var rootWorkInProgress = prepareFreshStack(root, errorRetryLanes);\n      rootWorkInProgress.flags |= ForceClientRender;\n\n      {\n        errorHydratingContainer(root.containerInfo);\n      }\n    }\n\n    var exitStatus = renderRootSync(root, errorRetryLanes);\n\n    if (exitStatus !== RootErrored) {\n      // Successfully finished rendering on retry\n      // The errors from the failed first attempt have been recovered. Add\n      // them to the collection of recoverable errors. We'll log them in the\n      // commit phase.\n      var errorsFromSecondAttempt = workInProgressRootRecoverableErrors;\n      workInProgressRootRecoverableErrors = errorsFromFirstAttempt; // The errors from the second attempt should be queued after the errors\n      // from the first attempt, to preserve the causal sequence.\n\n      if (errorsFromSecondAttempt !== null) {\n        queueRecoverableErrors(errorsFromSecondAttempt);\n      }\n    }\n\n    return exitStatus;\n  }\n\n  function queueRecoverableErrors(errors) {\n    if (workInProgressRootRecoverableErrors === null) {\n      workInProgressRootRecoverableErrors = errors;\n    } else {\n      workInProgressRootRecoverableErrors.push.apply(workInProgressRootRecoverableErrors, errors);\n    }\n  }\n\n  function finishConcurrentRender(root, exitStatus, lanes) {\n    switch (exitStatus) {\n      case RootInProgress:\n      case RootFatalErrored:\n        {\n          throw new Error('Root did not complete. This is a bug in React.');\n        }\n      // Flow knows about invariant, so it complains if I add a break\n      // statement, but eslint doesn't know about invariant, so it complains\n      // if I do. eslint-disable-next-line no-fallthrough\n\n      case RootErrored:\n        {\n          // We should have already attempted to retry this tree. If we reached\n          // this point, it errored again. Commit it.\n          commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);\n          break;\n        }\n\n      case RootSuspended:\n        {\n          markRootSuspended$1(root, lanes); // We have an acceptable loading state. We need to figure out if we\n          // should immediately commit it or wait a bit.\n\n          if (includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope\n          !shouldForceFlushFallbacksInDEV()) {\n            // This render only included retries, no updates. Throttle committing\n            // retries so that we don't show too many loading states too quickly.\n            var msUntilTimeout = globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now(); // Don't bother with a very short suspense time.\n\n            if (msUntilTimeout > 10) {\n              var nextLanes = getNextLanes(root, NoLanes);\n\n              if (nextLanes !== NoLanes) {\n                // There's additional work on this root.\n                break;\n              }\n\n              var suspendedLanes = root.suspendedLanes;\n\n              if (!isSubsetOfLanes(suspendedLanes, lanes)) {\n                // We should prefer to render the fallback of at the last\n                // suspended level. Ping the last suspended level to try\n                // rendering it again.\n                // FIXME: What if the suspended lanes are Idle? Should not restart.\n                var eventTime = requestEventTime();\n                markRootPinged(root, suspendedLanes);\n                break;\n              } // The render is suspended, it hasn't timed out, and there's no\n              // lower priority work to do. Instead of committing the fallback\n              // immediately, wait for more data to arrive.\n\n\n              root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root, workInProgressRootRecoverableErrors, workInProgressTransitions), msUntilTimeout);\n              break;\n            }\n          } // The work expired. Commit immediately.\n\n\n          commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);\n          break;\n        }\n\n      case RootSuspendedWithDelay:\n        {\n          markRootSuspended$1(root, lanes);\n\n          if (includesOnlyTransitions(lanes)) {\n            // This is a transition, so we should exit without committing a\n            // placeholder and without scheduling a timeout. Delay indefinitely\n            // until we receive more data.\n            break;\n          }\n\n          if (!shouldForceFlushFallbacksInDEV()) {\n            // This is not a transition, but we did trigger an avoided state.\n            // Schedule a placeholder to display after a short delay, using the Just\n            // Noticeable Difference.\n            // TODO: Is the JND optimization worth the added complexity? If this is\n            // the only reason we track the event time, then probably not.\n            // Consider removing.\n            var mostRecentEventTime = getMostRecentEventTime(root, lanes);\n            var eventTimeMs = mostRecentEventTime;\n            var timeElapsedMs = now() - eventTimeMs;\n\n            var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time.\n\n\n            if (_msUntilTimeout > 10) {\n              // Instead of committing the fallback immediately, wait for more data\n              // to arrive.\n              root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root, workInProgressRootRecoverableErrors, workInProgressTransitions), _msUntilTimeout);\n              break;\n            }\n          } // Commit the placeholder.\n\n\n          commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);\n          break;\n        }\n\n      case RootCompleted:\n        {\n          // The work completed. Ready to commit.\n          commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);\n          break;\n        }\n\n      default:\n        {\n          throw new Error('Unknown root exit status.');\n        }\n    }\n  }\n\n  function isRenderConsistentWithExternalStores(finishedWork) {\n    // Search the rendered tree for external store reads, and check whether the\n    // stores were mutated in a concurrent event. Intentionally using an iterative\n    // loop instead of recursion so we can exit early.\n    var node = finishedWork;\n\n    while (true) {\n      if (node.flags & StoreConsistency) {\n        var updateQueue = node.updateQueue;\n\n        if (updateQueue !== null) {\n          var checks = updateQueue.stores;\n\n          if (checks !== null) {\n            for (var i = 0; i < checks.length; i++) {\n              var check = checks[i];\n              var getSnapshot = check.getSnapshot;\n              var renderedValue = check.value;\n\n              try {\n                if (!objectIs(getSnapshot(), renderedValue)) {\n                  // Found an inconsistent store.\n                  return false;\n                }\n              } catch (error) {\n                // If `getSnapshot` throws, return `false`. This will schedule\n                // a re-render, and the error will be rethrown during render.\n                return false;\n              }\n            }\n          }\n        }\n      }\n\n      var child = node.child;\n\n      if (node.subtreeFlags & StoreConsistency && child !== null) {\n        child.return = node;\n        node = child;\n        continue;\n      }\n\n      if (node === finishedWork) {\n        return true;\n      }\n\n      while (node.sibling === null) {\n        if (node.return === null || node.return === finishedWork) {\n          return true;\n        }\n\n        node = node.return;\n      }\n\n      node.sibling.return = node.return;\n      node = node.sibling;\n    } // Flow doesn't know this is unreachable, but eslint does\n    // eslint-disable-next-line no-unreachable\n\n\n    return true;\n  }\n\n  function markRootSuspended$1(root, suspendedLanes) {\n    // When suspending, we should always exclude lanes that were pinged or (more\n    // rarely, since we try to avoid it) updated during the render phase.\n    // TODO: Lol maybe there's a better way to factor this besides this\n    // obnoxiously named function :)\n    suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);\n    suspendedLanes = removeLanes(suspendedLanes, workInProgressRootInterleavedUpdatedLanes);\n    markRootSuspended(root, suspendedLanes);\n  } // This is the entry point for synchronous tasks that don't go\n  // through Scheduler\n\n\n  function performSyncWorkOnRoot(root) {\n    {\n      syncNestedUpdateFlag();\n    }\n\n    if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {\n      throw new Error('Should not already be working.');\n    }\n\n    flushPassiveEffects();\n    var lanes = getNextLanes(root, NoLanes);\n\n    if (!includesSomeLane(lanes, SyncLane)) {\n      // There's no remaining sync work left.\n      ensureRootIsScheduled(root, now());\n      return null;\n    }\n\n    var exitStatus = renderRootSync(root, lanes);\n\n    if (root.tag !== LegacyRoot && exitStatus === RootErrored) {\n      // If something threw an error, try rendering one more time. We'll render\n      // synchronously to block concurrent data mutations, and we'll includes\n      // all pending updates are included. If it still fails after the second\n      // attempt, we'll give up and commit the resulting tree.\n      var errorRetryLanes = getLanesToRetrySynchronouslyOnError(root);\n\n      if (errorRetryLanes !== NoLanes) {\n        lanes = errorRetryLanes;\n        exitStatus = recoverFromConcurrentError(root, errorRetryLanes);\n      }\n    }\n\n    if (exitStatus === RootFatalErrored) {\n      var fatalError = workInProgressRootFatalError;\n      prepareFreshStack(root, NoLanes);\n      markRootSuspended$1(root, lanes);\n      ensureRootIsScheduled(root, now());\n      throw fatalError;\n    }\n\n    if (exitStatus === RootDidNotComplete) {\n      throw new Error('Root did not complete. This is a bug in React.');\n    } // We now have a consistent tree. Because this is a sync render, we\n    // will commit it even if something suspended.\n\n\n    var finishedWork = root.current.alternate;\n    root.finishedWork = finishedWork;\n    root.finishedLanes = lanes;\n    commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions); // Before exiting, make sure there's a callback scheduled for the next\n    // pending level.\n\n    ensureRootIsScheduled(root, now());\n    return null;\n  }\n\n  function flushRoot(root, lanes) {\n    if (lanes !== NoLanes) {\n      markRootEntangled(root, mergeLanes(lanes, SyncLane));\n      ensureRootIsScheduled(root, now());\n\n      if ((executionContext & (RenderContext | CommitContext)) === NoContext) {\n        resetRenderTimer();\n        flushSyncCallbacks();\n      }\n    }\n  }\n  function batchedUpdates$1(fn, a) {\n    var prevExecutionContext = executionContext;\n    executionContext |= BatchedContext;\n\n    try {\n      return fn(a);\n    } finally {\n      executionContext = prevExecutionContext; // If there were legacy sync updates, flush them at the end of the outer\n      // most batchedUpdates-like method.\n\n      if (executionContext === NoContext && // Treat `act` as if it's inside `batchedUpdates`, even in legacy mode.\n      !( ReactCurrentActQueue$1.isBatchingLegacy)) {\n        resetRenderTimer();\n        flushSyncCallbacksOnlyInLegacyMode();\n      }\n    }\n  }\n  function discreteUpdates(fn, a, b, c, d) {\n    var previousPriority = getCurrentUpdatePriority();\n    var prevTransition = ReactCurrentBatchConfig$3.transition;\n\n    try {\n      ReactCurrentBatchConfig$3.transition = null;\n      setCurrentUpdatePriority(DiscreteEventPriority);\n      return fn(a, b, c, d);\n    } finally {\n      setCurrentUpdatePriority(previousPriority);\n      ReactCurrentBatchConfig$3.transition = prevTransition;\n\n      if (executionContext === NoContext) {\n        resetRenderTimer();\n      }\n    }\n  } // Overload the definition to the two valid signatures.\n  // Warning, this opts-out of checking the function body.\n\n  // eslint-disable-next-line no-redeclare\n  function flushSync(fn) {\n    // In legacy mode, we flush pending passive effects at the beginning of the\n    // next event, not at the end of the previous one.\n    if (rootWithPendingPassiveEffects !== null && rootWithPendingPassiveEffects.tag === LegacyRoot && (executionContext & (RenderContext | CommitContext)) === NoContext) {\n      flushPassiveEffects();\n    }\n\n    var prevExecutionContext = executionContext;\n    executionContext |= BatchedContext;\n    var prevTransition = ReactCurrentBatchConfig$3.transition;\n    var previousPriority = getCurrentUpdatePriority();\n\n    try {\n      ReactCurrentBatchConfig$3.transition = null;\n      setCurrentUpdatePriority(DiscreteEventPriority);\n\n      if (fn) {\n        return fn();\n      } else {\n        return undefined;\n      }\n    } finally {\n      setCurrentUpdatePriority(previousPriority);\n      ReactCurrentBatchConfig$3.transition = prevTransition;\n      executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch.\n      // Note that this will happen even if batchedUpdates is higher up\n      // the stack.\n\n      if ((executionContext & (RenderContext | CommitContext)) === NoContext) {\n        flushSyncCallbacks();\n      }\n    }\n  }\n  function isAlreadyRendering() {\n    // Used by the renderer to print a warning if certain APIs are called from\n    // the wrong context.\n    return  (executionContext & (RenderContext | CommitContext)) !== NoContext;\n  }\n  function pushRenderLanes(fiber, lanes) {\n    push(subtreeRenderLanesCursor, subtreeRenderLanes, fiber);\n    subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);\n    workInProgressRootIncludedLanes = mergeLanes(workInProgressRootIncludedLanes, lanes);\n  }\n  function popRenderLanes(fiber) {\n    subtreeRenderLanes = subtreeRenderLanesCursor.current;\n    pop(subtreeRenderLanesCursor, fiber);\n  }\n\n  function prepareFreshStack(root, lanes) {\n    root.finishedWork = null;\n    root.finishedLanes = NoLanes;\n    var timeoutHandle = root.timeoutHandle;\n\n    if (timeoutHandle !== noTimeout) {\n      // The root previous suspended and scheduled a timeout to commit a fallback\n      // state. Now that we have additional work, cancel the timeout.\n      root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above\n\n      cancelTimeout(timeoutHandle);\n    }\n\n    if (workInProgress !== null) {\n      var interruptedWork = workInProgress.return;\n\n      while (interruptedWork !== null) {\n        var current = interruptedWork.alternate;\n        unwindInterruptedWork(current, interruptedWork);\n        interruptedWork = interruptedWork.return;\n      }\n    }\n\n    workInProgressRoot = root;\n    var rootWorkInProgress = createWorkInProgress(root.current, null);\n    workInProgress = rootWorkInProgress;\n    workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;\n    workInProgressRootExitStatus = RootInProgress;\n    workInProgressRootFatalError = null;\n    workInProgressRootSkippedLanes = NoLanes;\n    workInProgressRootInterleavedUpdatedLanes = NoLanes;\n    workInProgressRootPingedLanes = NoLanes;\n    workInProgressRootConcurrentErrors = null;\n    workInProgressRootRecoverableErrors = null;\n    finishQueueingConcurrentUpdates();\n\n    {\n      ReactStrictModeWarnings.discardPendingWarnings();\n    }\n\n    return rootWorkInProgress;\n  }\n\n  function handleError(root, thrownValue) {\n    do {\n      var erroredWork = workInProgress;\n\n      try {\n        // Reset module-level state that was set during the render phase.\n        resetContextDependencies();\n        resetHooksAfterThrow();\n        resetCurrentFiber(); // TODO: I found and added this missing line while investigating a\n        // separate issue. Write a regression test using string refs.\n\n        ReactCurrentOwner$2.current = null;\n\n        if (erroredWork === null || erroredWork.return === null) {\n          // Expected to be working on a non-root fiber. This is a fatal error\n          // because there's no ancestor that can handle it; the root is\n          // supposed to capture all errors that weren't caught by an error\n          // boundary.\n          workInProgressRootExitStatus = RootFatalErrored;\n          workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next\n          // sibling, or the parent if there are no siblings. But since the root\n          // has no siblings nor a parent, we set it to null. Usually this is\n          // handled by `completeUnitOfWork` or `unwindWork`, but since we're\n          // intentionally not calling those, we need set it here.\n          // TODO: Consider calling `unwindWork` to pop the contexts.\n\n          workInProgress = null;\n          return;\n        }\n\n        if (enableProfilerTimer && erroredWork.mode & ProfileMode) {\n          // Record the time spent rendering before an error was thrown. This\n          // avoids inaccurate Profiler durations in the case of a\n          // suspended render.\n          stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);\n        }\n\n        if (enableSchedulingProfiler) {\n          markComponentRenderStopped();\n\n          if (thrownValue !== null && typeof thrownValue === 'object' && typeof thrownValue.then === 'function') {\n            var wakeable = thrownValue;\n            markComponentSuspended(erroredWork, wakeable, workInProgressRootRenderLanes);\n          } else {\n            markComponentErrored(erroredWork, thrownValue, workInProgressRootRenderLanes);\n          }\n        }\n\n        throwException(root, erroredWork.return, erroredWork, thrownValue, workInProgressRootRenderLanes);\n        completeUnitOfWork(erroredWork);\n      } catch (yetAnotherThrownValue) {\n        // Something in the return path also threw.\n        thrownValue = yetAnotherThrownValue;\n\n        if (workInProgress === erroredWork && erroredWork !== null) {\n          // If this boundary has already errored, then we had trouble processing\n          // the error. Bubble it to the next boundary.\n          erroredWork = erroredWork.return;\n          workInProgress = erroredWork;\n        } else {\n          erroredWork = workInProgress;\n        }\n\n        continue;\n      } // Return to the normal work loop.\n\n\n      return;\n    } while (true);\n  }\n\n  function pushDispatcher() {\n    var prevDispatcher = ReactCurrentDispatcher$2.current;\n    ReactCurrentDispatcher$2.current = ContextOnlyDispatcher;\n\n    if (prevDispatcher === null) {\n      // The React isomorphic package does not include a default dispatcher.\n      // Instead the first renderer will lazily attach one, in order to give\n      // nicer error messages.\n      return ContextOnlyDispatcher;\n    } else {\n      return prevDispatcher;\n    }\n  }\n\n  function popDispatcher(prevDispatcher) {\n    ReactCurrentDispatcher$2.current = prevDispatcher;\n  }\n\n  function markCommitTimeOfFallback() {\n    globalMostRecentFallbackTime = now();\n  }\n  function markSkippedUpdateLanes(lane) {\n    workInProgressRootSkippedLanes = mergeLanes(lane, workInProgressRootSkippedLanes);\n  }\n  function renderDidSuspend() {\n    if (workInProgressRootExitStatus === RootInProgress) {\n      workInProgressRootExitStatus = RootSuspended;\n    }\n  }\n  function renderDidSuspendDelayIfPossible() {\n    if (workInProgressRootExitStatus === RootInProgress || workInProgressRootExitStatus === RootSuspended || workInProgressRootExitStatus === RootErrored) {\n      workInProgressRootExitStatus = RootSuspendedWithDelay;\n    } // Check if there are updates that we skipped tree that might have unblocked\n    // this render.\n\n\n    if (workInProgressRoot !== null && (includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootInterleavedUpdatedLanes))) {\n      // Mark the current render as suspended so that we switch to working on\n      // the updates that were skipped. Usually we only suspend at the end of\n      // the render phase.\n      // TODO: We should probably always mark the root as suspended immediately\n      // (inside this function), since by suspending at the end of the render\n      // phase introduces a potential mistake where we suspend lanes that were\n      // pinged or updated while we were rendering.\n      markRootSuspended$1(workInProgressRoot, workInProgressRootRenderLanes);\n    }\n  }\n  function renderDidError(error) {\n    if (workInProgressRootExitStatus !== RootSuspendedWithDelay) {\n      workInProgressRootExitStatus = RootErrored;\n    }\n\n    if (workInProgressRootConcurrentErrors === null) {\n      workInProgressRootConcurrentErrors = [error];\n    } else {\n      workInProgressRootConcurrentErrors.push(error);\n    }\n  } // Called during render to determine if anything has suspended.\n  // Returns false if we're not sure.\n\n  function renderHasNotSuspendedYet() {\n    // If something errored or completed, we can't really be sure,\n    // so those are false.\n    return workInProgressRootExitStatus === RootInProgress;\n  }\n\n  function renderRootSync(root, lanes) {\n    var prevExecutionContext = executionContext;\n    executionContext |= RenderContext;\n    var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack\n    // and prepare a fresh one. Otherwise we'll continue where we left off.\n\n    if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {\n      {\n        if (isDevToolsPresent) {\n          var memoizedUpdaters = root.memoizedUpdaters;\n\n          if (memoizedUpdaters.size > 0) {\n            restorePendingUpdaters(root, workInProgressRootRenderLanes);\n            memoizedUpdaters.clear();\n          } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set.\n          // If we bailout on this work, we'll move them back (like above).\n          // It's important to move them now in case the work spawns more work at the same priority with different updaters.\n          // That way we can keep the current update and future updates separate.\n\n\n          movePendingFibersToMemoized(root, lanes);\n        }\n      }\n\n      workInProgressTransitions = getTransitionsForLanes();\n      prepareFreshStack(root, lanes);\n    }\n\n    {\n      markRenderStarted(lanes);\n    }\n\n    do {\n      try {\n        workLoopSync();\n        break;\n      } catch (thrownValue) {\n        handleError(root, thrownValue);\n      }\n    } while (true);\n\n    resetContextDependencies();\n    executionContext = prevExecutionContext;\n    popDispatcher(prevDispatcher);\n\n    if (workInProgress !== null) {\n      // This is a sync render, so we should have finished the whole tree.\n      throw new Error('Cannot commit an incomplete root. This error is likely caused by a ' + 'bug in React. Please file an issue.');\n    }\n\n    {\n      markRenderStopped();\n    } // Set this to null to indicate there's no in-progress render.\n\n\n    workInProgressRoot = null;\n    workInProgressRootRenderLanes = NoLanes;\n    return workInProgressRootExitStatus;\n  } // The work loop is an extremely hot path. Tell Closure not to inline it.\n\n  /** @noinline */\n\n\n  function workLoopSync() {\n    // Already timed out, so perform work without checking if we need to yield.\n    while (workInProgress !== null) {\n      performUnitOfWork(workInProgress);\n    }\n  }\n\n  function renderRootConcurrent(root, lanes) {\n    var prevExecutionContext = executionContext;\n    executionContext |= RenderContext;\n    var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack\n    // and prepare a fresh one. Otherwise we'll continue where we left off.\n\n    if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {\n      {\n        if (isDevToolsPresent) {\n          var memoizedUpdaters = root.memoizedUpdaters;\n\n          if (memoizedUpdaters.size > 0) {\n            restorePendingUpdaters(root, workInProgressRootRenderLanes);\n            memoizedUpdaters.clear();\n          } // At this point, move Fibers that scheduled the upcoming work from the Map to the Set.\n          // If we bailout on this work, we'll move them back (like above).\n          // It's important to move them now in case the work spawns more work at the same priority with different updaters.\n          // That way we can keep the current update and future updates separate.\n\n\n          movePendingFibersToMemoized(root, lanes);\n        }\n      }\n\n      workInProgressTransitions = getTransitionsForLanes();\n      resetRenderTimer();\n      prepareFreshStack(root, lanes);\n    }\n\n    {\n      markRenderStarted(lanes);\n    }\n\n    do {\n      try {\n        workLoopConcurrent();\n        break;\n      } catch (thrownValue) {\n        handleError(root, thrownValue);\n      }\n    } while (true);\n\n    resetContextDependencies();\n    popDispatcher(prevDispatcher);\n    executionContext = prevExecutionContext;\n\n\n    if (workInProgress !== null) {\n      // Still work remaining.\n      {\n        markRenderYielded();\n      }\n\n      return RootInProgress;\n    } else {\n      // Completed the tree.\n      {\n        markRenderStopped();\n      } // Set this to null to indicate there's no in-progress render.\n\n\n      workInProgressRoot = null;\n      workInProgressRootRenderLanes = NoLanes; // Return the final exit status.\n\n      return workInProgressRootExitStatus;\n    }\n  }\n  /** @noinline */\n\n\n  function workLoopConcurrent() {\n    // Perform work until Scheduler asks us to yield\n    while (workInProgress !== null && !shouldYield()) {\n      performUnitOfWork(workInProgress);\n    }\n  }\n\n  function performUnitOfWork(unitOfWork) {\n    // The current, flushed, state of this fiber is the alternate. Ideally\n    // nothing should rely on this, but relying on it here means that we don't\n    // need an additional field on the work in progress.\n    var current = unitOfWork.alternate;\n    setCurrentFiber(unitOfWork);\n    var next;\n\n    if ( (unitOfWork.mode & ProfileMode) !== NoMode) {\n      startProfilerTimer(unitOfWork);\n      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);\n      stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);\n    } else {\n      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);\n    }\n\n    resetCurrentFiber();\n    unitOfWork.memoizedProps = unitOfWork.pendingProps;\n\n    if (next === null) {\n      // If this doesn't spawn new work, complete the current work.\n      completeUnitOfWork(unitOfWork);\n    } else {\n      workInProgress = next;\n    }\n\n    ReactCurrentOwner$2.current = null;\n  }\n\n  function completeUnitOfWork(unitOfWork) {\n    // Attempt to complete the current unit of work, then move to the next\n    // sibling. If there are no more siblings, return to the parent fiber.\n    var completedWork = unitOfWork;\n\n    do {\n      // The current, flushed, state of this fiber is the alternate. Ideally\n      // nothing should rely on this, but relying on it here means that we don't\n      // need an additional field on the work in progress.\n      var current = completedWork.alternate;\n      var returnFiber = completedWork.return; // Check if the work completed or if something threw.\n\n      if ((completedWork.flags & Incomplete) === NoFlags) {\n        setCurrentFiber(completedWork);\n        var next = void 0;\n\n        if ( (completedWork.mode & ProfileMode) === NoMode) {\n          next = completeWork(current, completedWork, subtreeRenderLanes);\n        } else {\n          startProfilerTimer(completedWork);\n          next = completeWork(current, completedWork, subtreeRenderLanes); // Update render duration assuming we didn't error.\n\n          stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);\n        }\n\n        resetCurrentFiber();\n\n        if (next !== null) {\n          // Completing this fiber spawned new work. Work on that next.\n          workInProgress = next;\n          return;\n        }\n      } else {\n        // This fiber did not complete because something threw. Pop values off\n        // the stack without entering the complete phase. If this is a boundary,\n        // capture values if possible.\n        var _next = unwindWork(current, completedWork); // Because this fiber did not complete, don't reset its lanes.\n\n\n        if (_next !== null) {\n          // If completing this work spawned new work, do that next. We'll come\n          // back here again.\n          // Since we're restarting, remove anything that is not a host effect\n          // from the effect tag.\n          _next.flags &= HostEffectMask;\n          workInProgress = _next;\n          return;\n        }\n\n        if ( (completedWork.mode & ProfileMode) !== NoMode) {\n          // Record the render duration for the fiber that errored.\n          stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing.\n\n          var actualDuration = completedWork.actualDuration;\n          var child = completedWork.child;\n\n          while (child !== null) {\n            actualDuration += child.actualDuration;\n            child = child.sibling;\n          }\n\n          completedWork.actualDuration = actualDuration;\n        }\n\n        if (returnFiber !== null) {\n          // Mark the parent fiber as incomplete and clear its subtree flags.\n          returnFiber.flags |= Incomplete;\n          returnFiber.subtreeFlags = NoFlags;\n          returnFiber.deletions = null;\n        } else {\n          // We've unwound all the way to the root.\n          workInProgressRootExitStatus = RootDidNotComplete;\n          workInProgress = null;\n          return;\n        }\n      }\n\n      var siblingFiber = completedWork.sibling;\n\n      if (siblingFiber !== null) {\n        // If there is more work to do in this returnFiber, do that next.\n        workInProgress = siblingFiber;\n        return;\n      } // Otherwise, return to the parent\n\n\n      completedWork = returnFiber; // Update the next thing we're working on in case something throws.\n\n      workInProgress = completedWork;\n    } while (completedWork !== null); // We've reached the root.\n\n\n    if (workInProgressRootExitStatus === RootInProgress) {\n      workInProgressRootExitStatus = RootCompleted;\n    }\n  }\n\n  function commitRoot(root, recoverableErrors, transitions) {\n    // TODO: This no longer makes any sense. We already wrap the mutation and\n    // layout phases. Should be able to remove.\n    var previousUpdateLanePriority = getCurrentUpdatePriority();\n    var prevTransition = ReactCurrentBatchConfig$3.transition;\n\n    try {\n      ReactCurrentBatchConfig$3.transition = null;\n      setCurrentUpdatePriority(DiscreteEventPriority);\n      commitRootImpl(root, recoverableErrors, transitions, previousUpdateLanePriority);\n    } finally {\n      ReactCurrentBatchConfig$3.transition = prevTransition;\n      setCurrentUpdatePriority(previousUpdateLanePriority);\n    }\n\n    return null;\n  }\n\n  function commitRootImpl(root, recoverableErrors, transitions, renderPriorityLevel) {\n    do {\n      // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which\n      // means `flushPassiveEffects` will sometimes result in additional\n      // passive effects. So we need to keep flushing in a loop until there are\n      // no more pending effects.\n      // TODO: Might be better if `flushPassiveEffects` did not automatically\n      // flush synchronous work at the end, to avoid factoring hazards like this.\n      flushPassiveEffects();\n    } while (rootWithPendingPassiveEffects !== null);\n\n    flushRenderPhaseStrictModeWarningsInDEV();\n\n    if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {\n      throw new Error('Should not already be working.');\n    }\n\n    var finishedWork = root.finishedWork;\n    var lanes = root.finishedLanes;\n\n    {\n      markCommitStarted(lanes);\n    }\n\n    if (finishedWork === null) {\n\n      {\n        markCommitStopped();\n      }\n\n      return null;\n    } else {\n      {\n        if (lanes === NoLanes) {\n          error('root.finishedLanes should not be empty during a commit. This is a ' + 'bug in React.');\n        }\n      }\n    }\n\n    root.finishedWork = null;\n    root.finishedLanes = NoLanes;\n\n    if (finishedWork === root.current) {\n      throw new Error('Cannot commit the same tree as before. This error is likely caused by ' + 'a bug in React. Please file an issue.');\n    } // commitRoot never returns a continuation; it always finishes synchronously.\n    // So we can clear these now to allow a new callback to be scheduled.\n\n\n    root.callbackNode = null;\n    root.callbackPriority = NoLane; // Update the first and last pending times on this root. The new first\n    // pending time is whatever is left on the root fiber.\n\n    var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);\n    markRootFinished(root, remainingLanes);\n\n    if (root === workInProgressRoot) {\n      // We can reset these now that they are finished.\n      workInProgressRoot = null;\n      workInProgress = null;\n      workInProgressRootRenderLanes = NoLanes;\n    } // If there are pending passive effects, schedule a callback to process them.\n    // Do this as early as possible, so it is queued before anything else that\n    // might get scheduled in the commit phase. (See #16714.)\n    // TODO: Delete all other places that schedule the passive effect callback\n    // They're redundant.\n\n\n    if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags || (finishedWork.flags & PassiveMask) !== NoFlags) {\n      if (!rootDoesHavePassiveEffects) {\n        rootDoesHavePassiveEffects = true;\n        // to store it in pendingPassiveTransitions until they get processed\n        // We need to pass this through as an argument to commitRoot\n        // because workInProgressTransitions might have changed between\n        // the previous render and commit if we throttle the commit\n        // with setTimeout\n\n        pendingPassiveTransitions = transitions;\n        scheduleCallback$1(NormalPriority, function () {\n          flushPassiveEffects(); // This render triggered passive effects: release the root cache pool\n          // *after* passive effects fire to avoid freeing a cache pool that may\n          // be referenced by a node in the tree (HostRoot, Cache boundary etc)\n\n          return null;\n        });\n      }\n    } // Check if there are any effects in the whole tree.\n    // TODO: This is left over from the effect list implementation, where we had\n    // to check for the existence of `firstEffect` to satisfy Flow. I think the\n    // only other reason this optimization exists is because it affects profiling.\n    // Reconsider whether this is necessary.\n\n\n    var subtreeHasEffects = (finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags;\n    var rootHasEffect = (finishedWork.flags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags;\n\n    if (subtreeHasEffects || rootHasEffect) {\n      var prevTransition = ReactCurrentBatchConfig$3.transition;\n      ReactCurrentBatchConfig$3.transition = null;\n      var previousPriority = getCurrentUpdatePriority();\n      setCurrentUpdatePriority(DiscreteEventPriority);\n      var prevExecutionContext = executionContext;\n      executionContext |= CommitContext; // Reset this to null before calling lifecycles\n\n      ReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass\n      // of the effect list for each phase: all mutation effects come before all\n      // layout effects, and so on.\n      // The first phase a \"before mutation\" phase. We use this phase to read the\n      // state of the host tree right before we mutate it. This is where\n      // getSnapshotBeforeUpdate is called.\n\n      var shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(root, finishedWork);\n\n      {\n        // Mark the current commit time to be shared by all Profilers in this\n        // batch. This enables them to be grouped later.\n        recordCommitTime();\n      }\n\n\n      commitMutationEffects(root, finishedWork, lanes);\n\n      resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after\n      // the mutation phase, so that the previous tree is still current during\n      // componentWillUnmount, but before the layout phase, so that the finished\n      // work is current during componentDidMount/Update.\n\n      root.current = finishedWork; // The next phase is the layout phase, where we call effects that read\n\n      {\n        markLayoutEffectsStarted(lanes);\n      }\n\n      commitLayoutEffects(finishedWork, root, lanes);\n\n      {\n        markLayoutEffectsStopped();\n      }\n      // opportunity to paint.\n\n\n      requestPaint();\n      executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value.\n\n      setCurrentUpdatePriority(previousPriority);\n      ReactCurrentBatchConfig$3.transition = prevTransition;\n    } else {\n      // No effects.\n      root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were\n      // no effects.\n      // TODO: Maybe there's a better way to report this.\n\n      {\n        recordCommitTime();\n      }\n    }\n\n    var rootDidHavePassiveEffects = rootDoesHavePassiveEffects;\n\n    if (rootDoesHavePassiveEffects) {\n      // This commit has passive effects. Stash a reference to them. But don't\n      // schedule a callback until after flushing layout work.\n      rootDoesHavePassiveEffects = false;\n      rootWithPendingPassiveEffects = root;\n      pendingPassiveEffectsLanes = lanes;\n    } else {\n\n      {\n        nestedPassiveUpdateCount = 0;\n        rootWithPassiveNestedUpdates = null;\n      }\n    } // Read this again, since an effect might have updated it\n\n\n    remainingLanes = root.pendingLanes; // Check if there's remaining work on this root\n    // TODO: This is part of the `componentDidCatch` implementation. Its purpose\n    // is to detect whether something might have called setState inside\n    // `componentDidCatch`. The mechanism is known to be flawed because `setState`\n    // inside `componentDidCatch` is itself flawed — that's why we recommend\n    // `getDerivedStateFromError` instead. However, it could be improved by\n    // checking if remainingLanes includes Sync work, instead of whether there's\n    // any work remaining at all (which would also include stuff like Suspense\n    // retries or transitions). It's been like this for a while, though, so fixing\n    // it probably isn't that urgent.\n\n    if (remainingLanes === NoLanes) {\n      // If there's no remaining work, we can clear the set of already failed\n      // error boundaries.\n      legacyErrorBoundariesThatAlreadyFailed = null;\n    }\n\n    {\n      if (!rootDidHavePassiveEffects) {\n        commitDoubleInvokeEffectsInDEV(root.current, false);\n      }\n    }\n\n    onCommitRoot(finishedWork.stateNode, renderPriorityLevel);\n\n    {\n      if (isDevToolsPresent) {\n        root.memoizedUpdaters.clear();\n      }\n    }\n\n    {\n      onCommitRoot$1();\n    } // Always call this before exiting `commitRoot`, to ensure that any\n    // additional work on this root is scheduled.\n\n\n    ensureRootIsScheduled(root, now());\n\n    if (recoverableErrors !== null) {\n      // There were errors during this render, but recovered from them without\n      // needing to surface it to the UI. We log them here.\n      var onRecoverableError = root.onRecoverableError;\n\n      for (var i = 0; i < recoverableErrors.length; i++) {\n        var recoverableError = recoverableErrors[i];\n        var componentStack = recoverableError.stack;\n        var digest = recoverableError.digest;\n        onRecoverableError(recoverableError.value, {\n          componentStack: componentStack,\n          digest: digest\n        });\n      }\n    }\n\n    if (hasUncaughtError) {\n      hasUncaughtError = false;\n      var error$1 = firstUncaughtError;\n      firstUncaughtError = null;\n      throw error$1;\n    } // If the passive effects are the result of a discrete render, flush them\n    // synchronously at the end of the current task so that the result is\n    // immediately observable. Otherwise, we assume that they are not\n    // order-dependent and do not need to be observed by external systems, so we\n    // can wait until after paint.\n    // TODO: We can optimize this by not scheduling the callback earlier. Since we\n    // currently schedule the callback in multiple places, will wait until those\n    // are consolidated.\n\n\n    if (includesSomeLane(pendingPassiveEffectsLanes, SyncLane) && root.tag !== LegacyRoot) {\n      flushPassiveEffects();\n    } // Read this again, since a passive effect might have updated it\n\n\n    remainingLanes = root.pendingLanes;\n\n    if (includesSomeLane(remainingLanes, SyncLane)) {\n      {\n        markNestedUpdateScheduled();\n      } // Count the number of times the root synchronously re-renders without\n      // finishing. If there are too many, it indicates an infinite update loop.\n\n\n      if (root === rootWithNestedUpdates) {\n        nestedUpdateCount++;\n      } else {\n        nestedUpdateCount = 0;\n        rootWithNestedUpdates = root;\n      }\n    } else {\n      nestedUpdateCount = 0;\n    } // If layout work was scheduled, flush it now.\n\n\n    flushSyncCallbacks();\n\n    {\n      markCommitStopped();\n    }\n\n    return null;\n  }\n\n  function flushPassiveEffects() {\n    // Returns whether passive effects were flushed.\n    // TODO: Combine this check with the one in flushPassiveEFfectsImpl. We should\n    // probably just combine the two functions. I believe they were only separate\n    // in the first place because we used to wrap it with\n    // `Scheduler.runWithPriority`, which accepts a function. But now we track the\n    // priority within React itself, so we can mutate the variable directly.\n    if (rootWithPendingPassiveEffects !== null) {\n      var renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes);\n      var priority = lowerEventPriority(DefaultEventPriority, renderPriority);\n      var prevTransition = ReactCurrentBatchConfig$3.transition;\n      var previousPriority = getCurrentUpdatePriority();\n\n      try {\n        ReactCurrentBatchConfig$3.transition = null;\n        setCurrentUpdatePriority(priority);\n        return flushPassiveEffectsImpl();\n      } finally {\n        setCurrentUpdatePriority(previousPriority);\n        ReactCurrentBatchConfig$3.transition = prevTransition; // Once passive effects have run for the tree - giving components a\n      }\n    }\n\n    return false;\n  }\n  function enqueuePendingPassiveProfilerEffect(fiber) {\n    {\n      pendingPassiveProfilerEffects.push(fiber);\n\n      if (!rootDoesHavePassiveEffects) {\n        rootDoesHavePassiveEffects = true;\n        scheduleCallback$1(NormalPriority, function () {\n          flushPassiveEffects();\n          return null;\n        });\n      }\n    }\n  }\n\n  function flushPassiveEffectsImpl() {\n    if (rootWithPendingPassiveEffects === null) {\n      return false;\n    } // Cache and clear the transitions flag\n\n\n    var transitions = pendingPassiveTransitions;\n    pendingPassiveTransitions = null;\n    var root = rootWithPendingPassiveEffects;\n    var lanes = pendingPassiveEffectsLanes;\n    rootWithPendingPassiveEffects = null; // TODO: This is sometimes out of sync with rootWithPendingPassiveEffects.\n    // Figure out why and fix it. It's not causing any known issues (probably\n    // because it's only used for profiling), but it's a refactor hazard.\n\n    pendingPassiveEffectsLanes = NoLanes;\n\n    if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {\n      throw new Error('Cannot flush passive effects while already rendering.');\n    }\n\n    {\n      isFlushingPassiveEffects = true;\n      didScheduleUpdateDuringPassiveEffects = false;\n    }\n\n    {\n      markPassiveEffectsStarted(lanes);\n    }\n\n    var prevExecutionContext = executionContext;\n    executionContext |= CommitContext;\n    commitPassiveUnmountEffects(root.current);\n    commitPassiveMountEffects(root, root.current, lanes, transitions); // TODO: Move to commitPassiveMountEffects\n\n    {\n      var profilerEffects = pendingPassiveProfilerEffects;\n      pendingPassiveProfilerEffects = [];\n\n      for (var i = 0; i < profilerEffects.length; i++) {\n        var _fiber = profilerEffects[i];\n        commitPassiveEffectDurations(root, _fiber);\n      }\n    }\n\n    {\n      markPassiveEffectsStopped();\n    }\n\n    {\n      commitDoubleInvokeEffectsInDEV(root.current, true);\n    }\n\n    executionContext = prevExecutionContext;\n    flushSyncCallbacks();\n\n    {\n      // If additional passive effects were scheduled, increment a counter. If this\n      // exceeds the limit, we'll fire a warning.\n      if (didScheduleUpdateDuringPassiveEffects) {\n        if (root === rootWithPassiveNestedUpdates) {\n          nestedPassiveUpdateCount++;\n        } else {\n          nestedPassiveUpdateCount = 0;\n          rootWithPassiveNestedUpdates = root;\n        }\n      } else {\n        nestedPassiveUpdateCount = 0;\n      }\n\n      isFlushingPassiveEffects = false;\n      didScheduleUpdateDuringPassiveEffects = false;\n    } // TODO: Move to commitPassiveMountEffects\n\n\n    onPostCommitRoot(root);\n\n    {\n      var stateNode = root.current.stateNode;\n      stateNode.effectDuration = 0;\n      stateNode.passiveEffectDuration = 0;\n    }\n\n    return true;\n  }\n\n  function isAlreadyFailedLegacyErrorBoundary(instance) {\n    return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance);\n  }\n  function markLegacyErrorBoundaryAsFailed(instance) {\n    if (legacyErrorBoundariesThatAlreadyFailed === null) {\n      legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);\n    } else {\n      legacyErrorBoundariesThatAlreadyFailed.add(instance);\n    }\n  }\n\n  function prepareToThrowUncaughtError(error) {\n    if (!hasUncaughtError) {\n      hasUncaughtError = true;\n      firstUncaughtError = error;\n    }\n  }\n\n  var onUncaughtError = prepareToThrowUncaughtError;\n\n  function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) {\n    var errorInfo = createCapturedValueAtFiber(error, sourceFiber);\n    var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane);\n    var root = enqueueUpdate(rootFiber, update, SyncLane);\n    var eventTime = requestEventTime();\n\n    if (root !== null) {\n      markRootUpdated(root, SyncLane, eventTime);\n      ensureRootIsScheduled(root, eventTime);\n    }\n  }\n\n  function captureCommitPhaseError(sourceFiber, nearestMountedAncestor, error$1) {\n    {\n      reportUncaughtErrorInDEV(error$1);\n      setIsRunningInsertionEffect(false);\n    }\n\n    if (sourceFiber.tag === HostRoot) {\n      // Error was thrown at the root. There is no parent, so the root\n      // itself should capture it.\n      captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error$1);\n      return;\n    }\n\n    var fiber = null;\n\n    {\n      fiber = nearestMountedAncestor;\n    }\n\n    while (fiber !== null) {\n      if (fiber.tag === HostRoot) {\n        captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error$1);\n        return;\n      } else if (fiber.tag === ClassComponent) {\n        var ctor = fiber.type;\n        var instance = fiber.stateNode;\n\n        if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {\n          var errorInfo = createCapturedValueAtFiber(error$1, sourceFiber);\n          var update = createClassErrorUpdate(fiber, errorInfo, SyncLane);\n          var root = enqueueUpdate(fiber, update, SyncLane);\n          var eventTime = requestEventTime();\n\n          if (root !== null) {\n            markRootUpdated(root, SyncLane, eventTime);\n            ensureRootIsScheduled(root, eventTime);\n          }\n\n          return;\n        }\n      }\n\n      fiber = fiber.return;\n    }\n\n    {\n      // TODO: Until we re-land skipUnmountedBoundaries (see #20147), this warning\n      // will fire for errors that are thrown by destroy functions inside deleted\n      // trees. What it should instead do is propagate the error to the parent of\n      // the deleted tree. In the meantime, do not add this warning to the\n      // allowlist; this is only for our internal use.\n      error('Internal React error: Attempted to capture a commit phase error ' + 'inside a detached tree. This indicates a bug in React. Likely ' + 'causes include deleting the same fiber more than once, committing an ' + 'already-finished tree, or an inconsistent return pointer.\\n\\n' + 'Error message:\\n\\n%s', error$1);\n    }\n  }\n  function pingSuspendedRoot(root, wakeable, pingedLanes) {\n    var pingCache = root.pingCache;\n\n    if (pingCache !== null) {\n      // The wakeable resolved, so we no longer need to memoize, because it will\n      // never be thrown again.\n      pingCache.delete(wakeable);\n    }\n\n    var eventTime = requestEventTime();\n    markRootPinged(root, pingedLanes);\n    warnIfSuspenseResolutionNotWrappedWithActDEV(root);\n\n    if (workInProgressRoot === root && isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)) {\n      // Received a ping at the same priority level at which we're currently\n      // rendering. We might want to restart this render. This should mirror\n      // the logic of whether or not a root suspends once it completes.\n      // TODO: If we're rendering sync either due to Sync, Batched or expired,\n      // we should probably never restart.\n      // If we're suspended with delay, or if it's a retry, we'll always suspend\n      // so we can always restart.\n      if (workInProgressRootExitStatus === RootSuspendedWithDelay || workInProgressRootExitStatus === RootSuspended && includesOnlyRetries(workInProgressRootRenderLanes) && now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) {\n        // Restart from the root.\n        prepareFreshStack(root, NoLanes);\n      } else {\n        // Even though we can't restart right now, we might get an\n        // opportunity later. So we mark this render as having a ping.\n        workInProgressRootPingedLanes = mergeLanes(workInProgressRootPingedLanes, pingedLanes);\n      }\n    }\n\n    ensureRootIsScheduled(root, eventTime);\n  }\n\n  function retryTimedOutBoundary(boundaryFiber, retryLane) {\n    // The boundary fiber (a Suspense component or SuspenseList component)\n    // previously was rendered in its fallback state. One of the promises that\n    // suspended it has resolved, which means at least part of the tree was\n    // likely unblocked. Try rendering again, at a new lanes.\n    if (retryLane === NoLane) {\n      // TODO: Assign this to `suspenseState.retryLane`? to avoid\n      // unnecessary entanglement?\n      retryLane = requestRetryLane(boundaryFiber);\n    } // TODO: Special case idle priority?\n\n\n    var eventTime = requestEventTime();\n    var root = enqueueConcurrentRenderForLane(boundaryFiber, retryLane);\n\n    if (root !== null) {\n      markRootUpdated(root, retryLane, eventTime);\n      ensureRootIsScheduled(root, eventTime);\n    }\n  }\n\n  function retryDehydratedSuspenseBoundary(boundaryFiber) {\n    var suspenseState = boundaryFiber.memoizedState;\n    var retryLane = NoLane;\n\n    if (suspenseState !== null) {\n      retryLane = suspenseState.retryLane;\n    }\n\n    retryTimedOutBoundary(boundaryFiber, retryLane);\n  }\n  function resolveRetryWakeable(boundaryFiber, wakeable) {\n    var retryLane = NoLane; // Default\n\n    var retryCache;\n\n    switch (boundaryFiber.tag) {\n      case SuspenseComponent:\n        retryCache = boundaryFiber.stateNode;\n        var suspenseState = boundaryFiber.memoizedState;\n\n        if (suspenseState !== null) {\n          retryLane = suspenseState.retryLane;\n        }\n\n        break;\n\n      case SuspenseListComponent:\n        retryCache = boundaryFiber.stateNode;\n        break;\n\n      default:\n        throw new Error('Pinged unknown suspense boundary type. ' + 'This is probably a bug in React.');\n    }\n\n    if (retryCache !== null) {\n      // The wakeable resolved, so we no longer need to memoize, because it will\n      // never be thrown again.\n      retryCache.delete(wakeable);\n    }\n\n    retryTimedOutBoundary(boundaryFiber, retryLane);\n  } // Computes the next Just Noticeable Difference (JND) boundary.\n  // The theory is that a person can't tell the difference between small differences in time.\n  // Therefore, if we wait a bit longer than necessary that won't translate to a noticeable\n  // difference in the experience. However, waiting for longer might mean that we can avoid\n  // showing an intermediate loading state. The longer we have already waited, the harder it\n  // is to tell small differences in time. Therefore, the longer we've already waited,\n  // the longer we can wait additionally. At some point we have to give up though.\n  // We pick a train model where the next boundary commits at a consistent schedule.\n  // These particular numbers are vague estimates. We expect to adjust them based on research.\n\n  function jnd(timeElapsed) {\n    return timeElapsed < 120 ? 120 : timeElapsed < 480 ? 480 : timeElapsed < 1080 ? 1080 : timeElapsed < 1920 ? 1920 : timeElapsed < 3000 ? 3000 : timeElapsed < 4320 ? 4320 : ceil(timeElapsed / 1960) * 1960;\n  }\n\n  function checkForNestedUpdates() {\n    if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {\n      nestedUpdateCount = 0;\n      rootWithNestedUpdates = null;\n      throw new Error('Maximum update depth exceeded. This can happen when a component ' + 'repeatedly calls setState inside componentWillUpdate or ' + 'componentDidUpdate. React limits the number of nested updates to ' + 'prevent infinite loops.');\n    }\n\n    {\n      if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {\n        nestedPassiveUpdateCount = 0;\n        rootWithPassiveNestedUpdates = null;\n\n        error('Maximum update depth exceeded. This can happen when a component ' + \"calls setState inside useEffect, but useEffect either doesn't \" + 'have a dependency array, or one of the dependencies changes on ' + 'every render.');\n      }\n    }\n  }\n\n  function flushRenderPhaseStrictModeWarningsInDEV() {\n    {\n      ReactStrictModeWarnings.flushLegacyContextWarning();\n\n      {\n        ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();\n      }\n    }\n  }\n\n  function commitDoubleInvokeEffectsInDEV(fiber, hasPassiveEffects) {\n    {\n      // TODO (StrictEffects) Should we set a marker on the root if it contains strict effects\n      // so we don't traverse unnecessarily? similar to subtreeFlags but just at the root level.\n      // Maybe not a big deal since this is DEV only behavior.\n      setCurrentFiber(fiber);\n      invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV);\n\n      if (hasPassiveEffects) {\n        invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectUnmountInDEV);\n      }\n\n      invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV);\n\n      if (hasPassiveEffects) {\n        invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV);\n      }\n\n      resetCurrentFiber();\n    }\n  }\n\n  function invokeEffectsInDev(firstChild, fiberFlags, invokeEffectFn) {\n    {\n      // We don't need to re-check StrictEffectsMode here.\n      // This function is only called if that check has already passed.\n      var current = firstChild;\n      var subtreeRoot = null;\n\n      while (current !== null) {\n        var primarySubtreeFlag = current.subtreeFlags & fiberFlags;\n\n        if (current !== subtreeRoot && current.child !== null && primarySubtreeFlag !== NoFlags) {\n          current = current.child;\n        } else {\n          if ((current.flags & fiberFlags) !== NoFlags) {\n            invokeEffectFn(current);\n          }\n\n          if (current.sibling !== null) {\n            current = current.sibling;\n          } else {\n            current = subtreeRoot = current.return;\n          }\n        }\n      }\n    }\n  }\n\n  var didWarnStateUpdateForNotYetMountedComponent = null;\n  function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {\n    {\n      if ((executionContext & RenderContext) !== NoContext) {\n        // We let the other warning about render phase updates deal with this one.\n        return;\n      }\n\n      if (!(fiber.mode & ConcurrentMode)) {\n        return;\n      }\n\n      var tag = fiber.tag;\n\n      if (tag !== IndeterminateComponent && tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent) {\n        // Only warn for user-defined components, not internal ones like Suspense.\n        return;\n      } // We show the whole stack but dedupe on the top component's name because\n      // the problematic code almost always lies inside that component.\n\n\n      var componentName = getComponentNameFromFiber(fiber) || 'ReactComponent';\n\n      if (didWarnStateUpdateForNotYetMountedComponent !== null) {\n        if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {\n          return;\n        }\n\n        didWarnStateUpdateForNotYetMountedComponent.add(componentName);\n      } else {\n        didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);\n      }\n\n      var previousFiber = current;\n\n      try {\n        setCurrentFiber(fiber);\n\n        error(\"Can't perform a React state update on a component that hasn't mounted yet. \" + 'This indicates that you have a side-effect in your render function that ' + 'asynchronously later calls tries to update the component. Move this work to ' + 'useEffect instead.');\n      } finally {\n        if (previousFiber) {\n          setCurrentFiber(fiber);\n        } else {\n          resetCurrentFiber();\n        }\n      }\n    }\n  }\n  var beginWork$1;\n\n  {\n    var dummyFiber = null;\n\n    beginWork$1 = function (current, unitOfWork, lanes) {\n      // If a component throws an error, we replay it again in a synchronously\n      // dispatched event, so that the debugger will treat it as an uncaught\n      // error See ReactErrorUtils for more information.\n      // Before entering the begin phase, copy the work-in-progress onto a dummy\n      // fiber. If beginWork throws, we'll use this to reset the state.\n      var originalWorkInProgressCopy = assignFiberPropertiesInDEV(dummyFiber, unitOfWork);\n\n      try {\n        return beginWork(current, unitOfWork, lanes);\n      } catch (originalError) {\n        if (didSuspendOrErrorWhileHydratingDEV() || originalError !== null && typeof originalError === 'object' && typeof originalError.then === 'function') {\n          // Don't replay promises.\n          // Don't replay errors if we are hydrating and have already suspended or handled an error\n          throw originalError;\n        } // Keep this code in sync with handleError; any changes here must have\n        // corresponding changes there.\n\n\n        resetContextDependencies();\n        resetHooksAfterThrow(); // Don't reset current debug fiber, since we're about to work on the\n        // same fiber again.\n        // Unwind the failed stack frame\n\n        unwindInterruptedWork(current, unitOfWork); // Restore the original properties of the fiber.\n\n        assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);\n\n        if ( unitOfWork.mode & ProfileMode) {\n          // Reset the profiler timer.\n          startProfilerTimer(unitOfWork);\n        } // Run beginWork again.\n\n\n        invokeGuardedCallback(null, beginWork, null, current, unitOfWork, lanes);\n\n        if (hasCaughtError()) {\n          var replayError = clearCaughtError();\n\n          if (typeof replayError === 'object' && replayError !== null && replayError._suppressLogging && typeof originalError === 'object' && originalError !== null && !originalError._suppressLogging) {\n            // If suppressed, let the flag carry over to the original error which is the one we'll rethrow.\n            originalError._suppressLogging = true;\n          }\n        } // We always throw the original error in case the second render pass is not idempotent.\n        // This can happen if a memoized function or CommonJS module doesn't throw after first invocation.\n\n\n        throw originalError;\n      }\n    };\n  }\n\n  var didWarnAboutUpdateInRender = false;\n  var didWarnAboutUpdateInRenderForAnotherComponent;\n\n  {\n    didWarnAboutUpdateInRenderForAnotherComponent = new Set();\n  }\n\n  function warnAboutRenderPhaseUpdatesInDEV(fiber) {\n    {\n      if (isRendering && !getIsUpdatingOpaqueValueInRenderPhaseInDEV()) {\n        switch (fiber.tag) {\n          case FunctionComponent:\n          case ForwardRef:\n          case SimpleMemoComponent:\n            {\n              var renderingComponentName = workInProgress && getComponentNameFromFiber(workInProgress) || 'Unknown'; // Dedupe by the rendering component because it's the one that needs to be fixed.\n\n              var dedupeKey = renderingComponentName;\n\n              if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {\n                didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);\n                var setStateComponentName = getComponentNameFromFiber(fiber) || 'Unknown';\n\n                error('Cannot update a component (`%s`) while rendering a ' + 'different component (`%s`). To locate the bad setState() call inside `%s`, ' + 'follow the stack trace as described in https://reactjs.org/link/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName);\n              }\n\n              break;\n            }\n\n          case ClassComponent:\n            {\n              if (!didWarnAboutUpdateInRender) {\n                error('Cannot update during an existing state transition (such as ' + 'within `render`). Render methods should be a pure ' + 'function of props and state.');\n\n                didWarnAboutUpdateInRender = true;\n              }\n\n              break;\n            }\n        }\n      }\n    }\n  }\n\n  function restorePendingUpdaters(root, lanes) {\n    {\n      if (isDevToolsPresent) {\n        var memoizedUpdaters = root.memoizedUpdaters;\n        memoizedUpdaters.forEach(function (schedulingFiber) {\n          addFiberToLanesMap(root, schedulingFiber, lanes);\n        }); // This function intentionally does not clear memoized updaters.\n        // Those may still be relevant to the current commit\n        // and a future one (e.g. Suspense).\n      }\n    }\n  }\n  var fakeActCallbackNode = {};\n\n  function scheduleCallback$1(priorityLevel, callback) {\n    {\n      // If we're currently inside an `act` scope, bypass Scheduler and push to\n      // the `act` queue instead.\n      var actQueue = ReactCurrentActQueue$1.current;\n\n      if (actQueue !== null) {\n        actQueue.push(callback);\n        return fakeActCallbackNode;\n      } else {\n        return scheduleCallback(priorityLevel, callback);\n      }\n    }\n  }\n\n  function cancelCallback$1(callbackNode) {\n    if ( callbackNode === fakeActCallbackNode) {\n      return;\n    } // In production, always call Scheduler. This function will be stripped out.\n\n\n    return cancelCallback(callbackNode);\n  }\n\n  function shouldForceFlushFallbacksInDEV() {\n    // Never force flush in production. This function should get stripped out.\n    return  ReactCurrentActQueue$1.current !== null;\n  }\n\n  function warnIfUpdatesNotWrappedWithActDEV(fiber) {\n    {\n      if (fiber.mode & ConcurrentMode) {\n        if (!isConcurrentActEnvironment()) {\n          // Not in an act environment. No need to warn.\n          return;\n        }\n      } else {\n        // Legacy mode has additional cases where we suppress a warning.\n        if (!isLegacyActEnvironment()) {\n          // Not in an act environment. No need to warn.\n          return;\n        }\n\n        if (executionContext !== NoContext) {\n          // Legacy mode doesn't warn if the update is batched, i.e.\n          // batchedUpdates or flushSync.\n          return;\n        }\n\n        if (fiber.tag !== FunctionComponent && fiber.tag !== ForwardRef && fiber.tag !== SimpleMemoComponent) {\n          // For backwards compatibility with pre-hooks code, legacy mode only\n          // warns for updates that originate from a hook.\n          return;\n        }\n      }\n\n      if (ReactCurrentActQueue$1.current === null) {\n        var previousFiber = current;\n\n        try {\n          setCurrentFiber(fiber);\n\n          error('An update to %s inside a test was not wrapped in act(...).\\n\\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\\n\\n' + 'act(() => {\\n' + '  /* fire events that update state */\\n' + '});\\n' + '/* assert on the output */\\n\\n' + \"This ensures that you're testing the behavior the user would see \" + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act', getComponentNameFromFiber(fiber));\n        } finally {\n          if (previousFiber) {\n            setCurrentFiber(fiber);\n          } else {\n            resetCurrentFiber();\n          }\n        }\n      }\n    }\n  }\n\n  function warnIfSuspenseResolutionNotWrappedWithActDEV(root) {\n    {\n      if (root.tag !== LegacyRoot && isConcurrentActEnvironment() && ReactCurrentActQueue$1.current === null) {\n        error('A suspended resource finished loading inside a test, but the event ' + 'was not wrapped in act(...).\\n\\n' + 'When testing, code that resolves suspended data should be wrapped ' + 'into act(...):\\n\\n' + 'act(() => {\\n' + '  /* finish loading suspended data */\\n' + '});\\n' + '/* assert on the output */\\n\\n' + \"This ensures that you're testing the behavior the user would see \" + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act');\n      }\n    }\n  }\n\n  function setIsRunningInsertionEffect(isRunning) {\n    {\n      isRunningInsertionEffect = isRunning;\n    }\n  }\n\n  /* eslint-disable react-internal/prod-error-codes */\n  var resolveFamily = null; // $FlowFixMe Flow gets confused by a WeakSet feature check below.\n\n  var failedBoundaries = null;\n  var setRefreshHandler = function (handler) {\n    {\n      resolveFamily = handler;\n    }\n  };\n  function resolveFunctionForHotReloading(type) {\n    {\n      if (resolveFamily === null) {\n        // Hot reloading is disabled.\n        return type;\n      }\n\n      var family = resolveFamily(type);\n\n      if (family === undefined) {\n        return type;\n      } // Use the latest known implementation.\n\n\n      return family.current;\n    }\n  }\n  function resolveClassForHotReloading(type) {\n    // No implementation differences.\n    return resolveFunctionForHotReloading(type);\n  }\n  function resolveForwardRefForHotReloading(type) {\n    {\n      if (resolveFamily === null) {\n        // Hot reloading is disabled.\n        return type;\n      }\n\n      var family = resolveFamily(type);\n\n      if (family === undefined) {\n        // Check if we're dealing with a real forwardRef. Don't want to crash early.\n        if (type !== null && type !== undefined && typeof type.render === 'function') {\n          // ForwardRef is special because its resolved .type is an object,\n          // but it's possible that we only have its inner render function in the map.\n          // If that inner render function is different, we'll build a new forwardRef type.\n          var currentRender = resolveFunctionForHotReloading(type.render);\n\n          if (type.render !== currentRender) {\n            var syntheticType = {\n              $$typeof: REACT_FORWARD_REF_TYPE,\n              render: currentRender\n            };\n\n            if (type.displayName !== undefined) {\n              syntheticType.displayName = type.displayName;\n            }\n\n            return syntheticType;\n          }\n        }\n\n        return type;\n      } // Use the latest known implementation.\n\n\n      return family.current;\n    }\n  }\n  function isCompatibleFamilyForHotReloading(fiber, element) {\n    {\n      if (resolveFamily === null) {\n        // Hot reloading is disabled.\n        return false;\n      }\n\n      var prevType = fiber.elementType;\n      var nextType = element.type; // If we got here, we know types aren't === equal.\n\n      var needsCompareFamilies = false;\n      var $$typeofNextType = typeof nextType === 'object' && nextType !== null ? nextType.$$typeof : null;\n\n      switch (fiber.tag) {\n        case ClassComponent:\n          {\n            if (typeof nextType === 'function') {\n              needsCompareFamilies = true;\n            }\n\n            break;\n          }\n\n        case FunctionComponent:\n          {\n            if (typeof nextType === 'function') {\n              needsCompareFamilies = true;\n            } else if ($$typeofNextType === REACT_LAZY_TYPE) {\n              // We don't know the inner type yet.\n              // We're going to assume that the lazy inner type is stable,\n              // and so it is sufficient to avoid reconciling it away.\n              // We're not going to unwrap or actually use the new lazy type.\n              needsCompareFamilies = true;\n            }\n\n            break;\n          }\n\n        case ForwardRef:\n          {\n            if ($$typeofNextType === REACT_FORWARD_REF_TYPE) {\n              needsCompareFamilies = true;\n            } else if ($$typeofNextType === REACT_LAZY_TYPE) {\n              needsCompareFamilies = true;\n            }\n\n            break;\n          }\n\n        case MemoComponent:\n        case SimpleMemoComponent:\n          {\n            if ($$typeofNextType === REACT_MEMO_TYPE) {\n              // TODO: if it was but can no longer be simple,\n              // we shouldn't set this.\n              needsCompareFamilies = true;\n            } else if ($$typeofNextType === REACT_LAZY_TYPE) {\n              needsCompareFamilies = true;\n            }\n\n            break;\n          }\n\n        default:\n          return false;\n      } // Check if both types have a family and it's the same one.\n\n\n      if (needsCompareFamilies) {\n        // Note: memo() and forwardRef() we'll compare outer rather than inner type.\n        // This means both of them need to be registered to preserve state.\n        // If we unwrapped and compared the inner types for wrappers instead,\n        // then we would risk falsely saying two separate memo(Foo)\n        // calls are equivalent because they wrap the same Foo function.\n        var prevFamily = resolveFamily(prevType);\n\n        if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) {\n          return true;\n        }\n      }\n\n      return false;\n    }\n  }\n  function markFailedErrorBoundaryForHotReloading(fiber) {\n    {\n      if (resolveFamily === null) {\n        // Hot reloading is disabled.\n        return;\n      }\n\n      if (typeof WeakSet !== 'function') {\n        return;\n      }\n\n      if (failedBoundaries === null) {\n        failedBoundaries = new WeakSet();\n      }\n\n      failedBoundaries.add(fiber);\n    }\n  }\n  var scheduleRefresh = function (root, update) {\n    {\n      if (resolveFamily === null) {\n        // Hot reloading is disabled.\n        return;\n      }\n\n      var staleFamilies = update.staleFamilies,\n          updatedFamilies = update.updatedFamilies;\n      flushPassiveEffects();\n      flushSync(function () {\n        scheduleFibersWithFamiliesRecursively(root.current, updatedFamilies, staleFamilies);\n      });\n    }\n  };\n  var scheduleRoot = function (root, element) {\n    {\n      if (root.context !== emptyContextObject) {\n        // Super edge case: root has a legacy _renderSubtree context\n        // but we don't know the parentComponent so we can't pass it.\n        // Just ignore. We'll delete this with _renderSubtree code path later.\n        return;\n      }\n\n      flushPassiveEffects();\n      flushSync(function () {\n        updateContainer(element, root, null, null);\n      });\n    }\n  };\n\n  function scheduleFibersWithFamiliesRecursively(fiber, updatedFamilies, staleFamilies) {\n    {\n      var alternate = fiber.alternate,\n          child = fiber.child,\n          sibling = fiber.sibling,\n          tag = fiber.tag,\n          type = fiber.type;\n      var candidateType = null;\n\n      switch (tag) {\n        case FunctionComponent:\n        case SimpleMemoComponent:\n        case ClassComponent:\n          candidateType = type;\n          break;\n\n        case ForwardRef:\n          candidateType = type.render;\n          break;\n      }\n\n      if (resolveFamily === null) {\n        throw new Error('Expected resolveFamily to be set during hot reload.');\n      }\n\n      var needsRender = false;\n      var needsRemount = false;\n\n      if (candidateType !== null) {\n        var family = resolveFamily(candidateType);\n\n        if (family !== undefined) {\n          if (staleFamilies.has(family)) {\n            needsRemount = true;\n          } else if (updatedFamilies.has(family)) {\n            if (tag === ClassComponent) {\n              needsRemount = true;\n            } else {\n              needsRender = true;\n            }\n          }\n        }\n      }\n\n      if (failedBoundaries !== null) {\n        if (failedBoundaries.has(fiber) || alternate !== null && failedBoundaries.has(alternate)) {\n          needsRemount = true;\n        }\n      }\n\n      if (needsRemount) {\n        fiber._debugNeedsRemount = true;\n      }\n\n      if (needsRemount || needsRender) {\n        var _root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n        if (_root !== null) {\n          scheduleUpdateOnFiber(_root, fiber, SyncLane, NoTimestamp);\n        }\n      }\n\n      if (child !== null && !needsRemount) {\n        scheduleFibersWithFamiliesRecursively(child, updatedFamilies, staleFamilies);\n      }\n\n      if (sibling !== null) {\n        scheduleFibersWithFamiliesRecursively(sibling, updatedFamilies, staleFamilies);\n      }\n    }\n  }\n\n  var findHostInstancesForRefresh = function (root, families) {\n    {\n      var hostInstances = new Set();\n      var types = new Set(families.map(function (family) {\n        return family.current;\n      }));\n      findHostInstancesForMatchingFibersRecursively(root.current, types, hostInstances);\n      return hostInstances;\n    }\n  };\n\n  function findHostInstancesForMatchingFibersRecursively(fiber, types, hostInstances) {\n    {\n      var child = fiber.child,\n          sibling = fiber.sibling,\n          tag = fiber.tag,\n          type = fiber.type;\n      var candidateType = null;\n\n      switch (tag) {\n        case FunctionComponent:\n        case SimpleMemoComponent:\n        case ClassComponent:\n          candidateType = type;\n          break;\n\n        case ForwardRef:\n          candidateType = type.render;\n          break;\n      }\n\n      var didMatch = false;\n\n      if (candidateType !== null) {\n        if (types.has(candidateType)) {\n          didMatch = true;\n        }\n      }\n\n      if (didMatch) {\n        // We have a match. This only drills down to the closest host components.\n        // There's no need to search deeper because for the purpose of giving\n        // visual feedback, \"flashing\" outermost parent rectangles is sufficient.\n        findHostInstancesForFiberShallowly(fiber, hostInstances);\n      } else {\n        // If there's no match, maybe there will be one further down in the child tree.\n        if (child !== null) {\n          findHostInstancesForMatchingFibersRecursively(child, types, hostInstances);\n        }\n      }\n\n      if (sibling !== null) {\n        findHostInstancesForMatchingFibersRecursively(sibling, types, hostInstances);\n      }\n    }\n  }\n\n  function findHostInstancesForFiberShallowly(fiber, hostInstances) {\n    {\n      var foundHostInstances = findChildHostInstancesForFiberShallowly(fiber, hostInstances);\n\n      if (foundHostInstances) {\n        return;\n      } // If we didn't find any host children, fallback to closest host parent.\n\n\n      var node = fiber;\n\n      while (true) {\n        switch (node.tag) {\n          case HostComponent:\n            hostInstances.add(node.stateNode);\n            return;\n\n          case HostPortal:\n            hostInstances.add(node.stateNode.containerInfo);\n            return;\n\n          case HostRoot:\n            hostInstances.add(node.stateNode.containerInfo);\n            return;\n        }\n\n        if (node.return === null) {\n          throw new Error('Expected to reach root first.');\n        }\n\n        node = node.return;\n      }\n    }\n  }\n\n  function findChildHostInstancesForFiberShallowly(fiber, hostInstances) {\n    {\n      var node = fiber;\n      var foundHostInstances = false;\n\n      while (true) {\n        if (node.tag === HostComponent) {\n          // We got a match.\n          foundHostInstances = true;\n          hostInstances.add(node.stateNode); // There may still be more, so keep searching.\n        } else if (node.child !== null) {\n          node.child.return = node;\n          node = node.child;\n          continue;\n        }\n\n        if (node === fiber) {\n          return foundHostInstances;\n        }\n\n        while (node.sibling === null) {\n          if (node.return === null || node.return === fiber) {\n            return foundHostInstances;\n          }\n\n          node = node.return;\n        }\n\n        node.sibling.return = node.return;\n        node = node.sibling;\n      }\n    }\n\n    return false;\n  }\n\n  var hasBadMapPolyfill;\n\n  {\n    hasBadMapPolyfill = false;\n\n    try {\n      var nonExtensibleObject = Object.preventExtensions({});\n      /* eslint-disable no-new */\n\n      new Map([[nonExtensibleObject, null]]);\n      new Set([nonExtensibleObject]);\n      /* eslint-enable no-new */\n    } catch (e) {\n      // TODO: Consider warning about bad polyfills\n      hasBadMapPolyfill = true;\n    }\n  }\n\n  function FiberNode(tag, pendingProps, key, mode) {\n    // Instance\n    this.tag = tag;\n    this.key = key;\n    this.elementType = null;\n    this.type = null;\n    this.stateNode = null; // Fiber\n\n    this.return = null;\n    this.child = null;\n    this.sibling = null;\n    this.index = 0;\n    this.ref = null;\n    this.pendingProps = pendingProps;\n    this.memoizedProps = null;\n    this.updateQueue = null;\n    this.memoizedState = null;\n    this.dependencies = null;\n    this.mode = mode; // Effects\n\n    this.flags = NoFlags;\n    this.subtreeFlags = NoFlags;\n    this.deletions = null;\n    this.lanes = NoLanes;\n    this.childLanes = NoLanes;\n    this.alternate = null;\n\n    {\n      // Note: The following is done to avoid a v8 performance cliff.\n      //\n      // Initializing the fields below to smis and later updating them with\n      // double values will cause Fibers to end up having separate shapes.\n      // This behavior/bug has something to do with Object.preventExtension().\n      // Fortunately this only impacts DEV builds.\n      // Unfortunately it makes React unusably slow for some applications.\n      // To work around this, initialize the fields below with doubles.\n      //\n      // Learn more about this here:\n      // https://github.com/facebook/react/issues/14365\n      // https://bugs.chromium.org/p/v8/issues/detail?id=8538\n      this.actualDuration = Number.NaN;\n      this.actualStartTime = Number.NaN;\n      this.selfBaseDuration = Number.NaN;\n      this.treeBaseDuration = Number.NaN; // It's okay to replace the initial doubles with smis after initialization.\n      // This won't trigger the performance cliff mentioned above,\n      // and it simplifies other profiler code (including DevTools).\n\n      this.actualDuration = 0;\n      this.actualStartTime = -1;\n      this.selfBaseDuration = 0;\n      this.treeBaseDuration = 0;\n    }\n\n    {\n      // This isn't directly used but is handy for debugging internals:\n      this._debugSource = null;\n      this._debugOwner = null;\n      this._debugNeedsRemount = false;\n      this._debugHookTypes = null;\n\n      if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {\n        Object.preventExtensions(this);\n      }\n    }\n  } // This is a constructor function, rather than a POJO constructor, still\n  // please ensure we do the following:\n  // 1) Nobody should add any instance methods on this. Instance methods can be\n  //    more difficult to predict when they get optimized and they are almost\n  //    never inlined properly in static compilers.\n  // 2) Nobody should rely on `instanceof Fiber` for type testing. We should\n  //    always know when it is a fiber.\n  // 3) We might want to experiment with using numeric keys since they are easier\n  //    to optimize in a non-JIT environment.\n  // 4) We can easily go from a constructor to a createFiber object literal if that\n  //    is faster.\n  // 5) It should be easy to port this to a C struct and keep a C implementation\n  //    compatible.\n\n\n  var createFiber = function (tag, pendingProps, key, mode) {\n    // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors\n    return new FiberNode(tag, pendingProps, key, mode);\n  };\n\n  function shouldConstruct$1(Component) {\n    var prototype = Component.prototype;\n    return !!(prototype && prototype.isReactComponent);\n  }\n\n  function isSimpleFunctionComponent(type) {\n    return typeof type === 'function' && !shouldConstruct$1(type) && type.defaultProps === undefined;\n  }\n  function resolveLazyComponentTag(Component) {\n    if (typeof Component === 'function') {\n      return shouldConstruct$1(Component) ? ClassComponent : FunctionComponent;\n    } else if (Component !== undefined && Component !== null) {\n      var $$typeof = Component.$$typeof;\n\n      if ($$typeof === REACT_FORWARD_REF_TYPE) {\n        return ForwardRef;\n      }\n\n      if ($$typeof === REACT_MEMO_TYPE) {\n        return MemoComponent;\n      }\n    }\n\n    return IndeterminateComponent;\n  } // This is used to create an alternate fiber to do work on.\n\n  function createWorkInProgress(current, pendingProps) {\n    var workInProgress = current.alternate;\n\n    if (workInProgress === null) {\n      // We use a double buffering pooling technique because we know that we'll\n      // only ever need at most two versions of a tree. We pool the \"other\" unused\n      // node that we're free to reuse. This is lazily created to avoid allocating\n      // extra objects for things that are never updated. It also allow us to\n      // reclaim the extra memory if needed.\n      workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode);\n      workInProgress.elementType = current.elementType;\n      workInProgress.type = current.type;\n      workInProgress.stateNode = current.stateNode;\n\n      {\n        // DEV-only fields\n        workInProgress._debugSource = current._debugSource;\n        workInProgress._debugOwner = current._debugOwner;\n        workInProgress._debugHookTypes = current._debugHookTypes;\n      }\n\n      workInProgress.alternate = current;\n      current.alternate = workInProgress;\n    } else {\n      workInProgress.pendingProps = pendingProps; // Needed because Blocks store data on type.\n\n      workInProgress.type = current.type; // We already have an alternate.\n      // Reset the effect tag.\n\n      workInProgress.flags = NoFlags; // The effects are no longer valid.\n\n      workInProgress.subtreeFlags = NoFlags;\n      workInProgress.deletions = null;\n\n      {\n        // We intentionally reset, rather than copy, actualDuration & actualStartTime.\n        // This prevents time from endlessly accumulating in new commits.\n        // This has the downside of resetting values for different priority renders,\n        // But works for yielding (the common case) and should support resuming.\n        workInProgress.actualDuration = 0;\n        workInProgress.actualStartTime = -1;\n      }\n    } // Reset all effects except static ones.\n    // Static effects are not specific to a render.\n\n\n    workInProgress.flags = current.flags & StaticMask;\n    workInProgress.childLanes = current.childLanes;\n    workInProgress.lanes = current.lanes;\n    workInProgress.child = current.child;\n    workInProgress.memoizedProps = current.memoizedProps;\n    workInProgress.memoizedState = current.memoizedState;\n    workInProgress.updateQueue = current.updateQueue; // Clone the dependencies object. This is mutated during the render phase, so\n    // it cannot be shared with the current fiber.\n\n    var currentDependencies = current.dependencies;\n    workInProgress.dependencies = currentDependencies === null ? null : {\n      lanes: currentDependencies.lanes,\n      firstContext: currentDependencies.firstContext\n    }; // These will be overridden during the parent's reconciliation\n\n    workInProgress.sibling = current.sibling;\n    workInProgress.index = current.index;\n    workInProgress.ref = current.ref;\n\n    {\n      workInProgress.selfBaseDuration = current.selfBaseDuration;\n      workInProgress.treeBaseDuration = current.treeBaseDuration;\n    }\n\n    {\n      workInProgress._debugNeedsRemount = current._debugNeedsRemount;\n\n      switch (workInProgress.tag) {\n        case IndeterminateComponent:\n        case FunctionComponent:\n        case SimpleMemoComponent:\n          workInProgress.type = resolveFunctionForHotReloading(current.type);\n          break;\n\n        case ClassComponent:\n          workInProgress.type = resolveClassForHotReloading(current.type);\n          break;\n\n        case ForwardRef:\n          workInProgress.type = resolveForwardRefForHotReloading(current.type);\n          break;\n      }\n    }\n\n    return workInProgress;\n  } // Used to reuse a Fiber for a second pass.\n\n  function resetWorkInProgress(workInProgress, renderLanes) {\n    // This resets the Fiber to what createFiber or createWorkInProgress would\n    // have set the values to before during the first pass. Ideally this wouldn't\n    // be necessary but unfortunately many code paths reads from the workInProgress\n    // when they should be reading from current and writing to workInProgress.\n    // We assume pendingProps, index, key, ref, return are still untouched to\n    // avoid doing another reconciliation.\n    // Reset the effect flags but keep any Placement tags, since that's something\n    // that child fiber is setting, not the reconciliation.\n    workInProgress.flags &= StaticMask | Placement; // The effects are no longer valid.\n\n    var current = workInProgress.alternate;\n\n    if (current === null) {\n      // Reset to createFiber's initial values.\n      workInProgress.childLanes = NoLanes;\n      workInProgress.lanes = renderLanes;\n      workInProgress.child = null;\n      workInProgress.subtreeFlags = NoFlags;\n      workInProgress.memoizedProps = null;\n      workInProgress.memoizedState = null;\n      workInProgress.updateQueue = null;\n      workInProgress.dependencies = null;\n      workInProgress.stateNode = null;\n\n      {\n        // Note: We don't reset the actualTime counts. It's useful to accumulate\n        // actual time across multiple render passes.\n        workInProgress.selfBaseDuration = 0;\n        workInProgress.treeBaseDuration = 0;\n      }\n    } else {\n      // Reset to the cloned values that createWorkInProgress would've.\n      workInProgress.childLanes = current.childLanes;\n      workInProgress.lanes = current.lanes;\n      workInProgress.child = current.child;\n      workInProgress.subtreeFlags = NoFlags;\n      workInProgress.deletions = null;\n      workInProgress.memoizedProps = current.memoizedProps;\n      workInProgress.memoizedState = current.memoizedState;\n      workInProgress.updateQueue = current.updateQueue; // Needed because Blocks store data on type.\n\n      workInProgress.type = current.type; // Clone the dependencies object. This is mutated during the render phase, so\n      // it cannot be shared with the current fiber.\n\n      var currentDependencies = current.dependencies;\n      workInProgress.dependencies = currentDependencies === null ? null : {\n        lanes: currentDependencies.lanes,\n        firstContext: currentDependencies.firstContext\n      };\n\n      {\n        // Note: We don't reset the actualTime counts. It's useful to accumulate\n        // actual time across multiple render passes.\n        workInProgress.selfBaseDuration = current.selfBaseDuration;\n        workInProgress.treeBaseDuration = current.treeBaseDuration;\n      }\n    }\n\n    return workInProgress;\n  }\n  function createHostRootFiber(tag, isStrictMode, concurrentUpdatesByDefaultOverride) {\n    var mode;\n\n    if (tag === ConcurrentRoot) {\n      mode = ConcurrentMode;\n\n      if (isStrictMode === true) {\n        mode |= StrictLegacyMode;\n\n        {\n          mode |= StrictEffectsMode;\n        }\n      }\n    } else {\n      mode = NoMode;\n    }\n\n    if ( isDevToolsPresent) {\n      // Always collect profile timings when DevTools are present.\n      // This enables DevTools to start capturing timing at any point–\n      // Without some nodes in the tree having empty base times.\n      mode |= ProfileMode;\n    }\n\n    return createFiber(HostRoot, null, null, mode);\n  }\n  function createFiberFromTypeAndProps(type, // React$ElementType\n  key, pendingProps, owner, mode, lanes) {\n    var fiberTag = IndeterminateComponent; // The resolved type is set if we know what the final type will be. I.e. it's not lazy.\n\n    var resolvedType = type;\n\n    if (typeof type === 'function') {\n      if (shouldConstruct$1(type)) {\n        fiberTag = ClassComponent;\n\n        {\n          resolvedType = resolveClassForHotReloading(resolvedType);\n        }\n      } else {\n        {\n          resolvedType = resolveFunctionForHotReloading(resolvedType);\n        }\n      }\n    } else if (typeof type === 'string') {\n      fiberTag = HostComponent;\n    } else {\n      getTag: switch (type) {\n        case REACT_FRAGMENT_TYPE:\n          return createFiberFromFragment(pendingProps.children, mode, lanes, key);\n\n        case REACT_STRICT_MODE_TYPE:\n          fiberTag = Mode;\n          mode |= StrictLegacyMode;\n\n          if ( (mode & ConcurrentMode) !== NoMode) {\n            // Strict effects should never run on legacy roots\n            mode |= StrictEffectsMode;\n          }\n\n          break;\n\n        case REACT_PROFILER_TYPE:\n          return createFiberFromProfiler(pendingProps, mode, lanes, key);\n\n        case REACT_SUSPENSE_TYPE:\n          return createFiberFromSuspense(pendingProps, mode, lanes, key);\n\n        case REACT_SUSPENSE_LIST_TYPE:\n          return createFiberFromSuspenseList(pendingProps, mode, lanes, key);\n\n        case REACT_OFFSCREEN_TYPE:\n          return createFiberFromOffscreen(pendingProps, mode, lanes, key);\n\n        case REACT_LEGACY_HIDDEN_TYPE:\n\n        // eslint-disable-next-line no-fallthrough\n\n        case REACT_SCOPE_TYPE:\n\n        // eslint-disable-next-line no-fallthrough\n\n        case REACT_CACHE_TYPE:\n\n        // eslint-disable-next-line no-fallthrough\n\n        case REACT_TRACING_MARKER_TYPE:\n\n        // eslint-disable-next-line no-fallthrough\n\n        case REACT_DEBUG_TRACING_MODE_TYPE:\n\n        // eslint-disable-next-line no-fallthrough\n\n        default:\n          {\n            if (typeof type === 'object' && type !== null) {\n              switch (type.$$typeof) {\n                case REACT_PROVIDER_TYPE:\n                  fiberTag = ContextProvider;\n                  break getTag;\n\n                case REACT_CONTEXT_TYPE:\n                  // This is a consumer\n                  fiberTag = ContextConsumer;\n                  break getTag;\n\n                case REACT_FORWARD_REF_TYPE:\n                  fiberTag = ForwardRef;\n\n                  {\n                    resolvedType = resolveForwardRefForHotReloading(resolvedType);\n                  }\n\n                  break getTag;\n\n                case REACT_MEMO_TYPE:\n                  fiberTag = MemoComponent;\n                  break getTag;\n\n                case REACT_LAZY_TYPE:\n                  fiberTag = LazyComponent;\n                  resolvedType = null;\n                  break getTag;\n              }\n            }\n\n            var info = '';\n\n            {\n              if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {\n                info += ' You likely forgot to export your component from the file ' + \"it's defined in, or you might have mixed up default and \" + 'named imports.';\n              }\n\n              var ownerName = owner ? getComponentNameFromFiber(owner) : null;\n\n              if (ownerName) {\n                info += '\\n\\nCheck the render method of `' + ownerName + '`.';\n              }\n            }\n\n            throw new Error('Element type is invalid: expected a string (for built-in ' + 'components) or a class/function (for composite components) ' + (\"but got: \" + (type == null ? type : typeof type) + \".\" + info));\n          }\n      }\n    }\n\n    var fiber = createFiber(fiberTag, pendingProps, key, mode);\n    fiber.elementType = type;\n    fiber.type = resolvedType;\n    fiber.lanes = lanes;\n\n    {\n      fiber._debugOwner = owner;\n    }\n\n    return fiber;\n  }\n  function createFiberFromElement(element, mode, lanes) {\n    var owner = null;\n\n    {\n      owner = element._owner;\n    }\n\n    var type = element.type;\n    var key = element.key;\n    var pendingProps = element.props;\n    var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, lanes);\n\n    {\n      fiber._debugSource = element._source;\n      fiber._debugOwner = element._owner;\n    }\n\n    return fiber;\n  }\n  function createFiberFromFragment(elements, mode, lanes, key) {\n    var fiber = createFiber(Fragment, elements, key, mode);\n    fiber.lanes = lanes;\n    return fiber;\n  }\n\n  function createFiberFromProfiler(pendingProps, mode, lanes, key) {\n    {\n      if (typeof pendingProps.id !== 'string') {\n        error('Profiler must specify an \"id\" of type `string` as a prop. Received the type `%s` instead.', typeof pendingProps.id);\n      }\n    }\n\n    var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode);\n    fiber.elementType = REACT_PROFILER_TYPE;\n    fiber.lanes = lanes;\n\n    {\n      fiber.stateNode = {\n        effectDuration: 0,\n        passiveEffectDuration: 0\n      };\n    }\n\n    return fiber;\n  }\n\n  function createFiberFromSuspense(pendingProps, mode, lanes, key) {\n    var fiber = createFiber(SuspenseComponent, pendingProps, key, mode);\n    fiber.elementType = REACT_SUSPENSE_TYPE;\n    fiber.lanes = lanes;\n    return fiber;\n  }\n  function createFiberFromSuspenseList(pendingProps, mode, lanes, key) {\n    var fiber = createFiber(SuspenseListComponent, pendingProps, key, mode);\n    fiber.elementType = REACT_SUSPENSE_LIST_TYPE;\n    fiber.lanes = lanes;\n    return fiber;\n  }\n  function createFiberFromOffscreen(pendingProps, mode, lanes, key) {\n    var fiber = createFiber(OffscreenComponent, pendingProps, key, mode);\n    fiber.elementType = REACT_OFFSCREEN_TYPE;\n    fiber.lanes = lanes;\n    var primaryChildInstance = {\n      isHidden: false\n    };\n    fiber.stateNode = primaryChildInstance;\n    return fiber;\n  }\n  function createFiberFromText(content, mode, lanes) {\n    var fiber = createFiber(HostText, content, null, mode);\n    fiber.lanes = lanes;\n    return fiber;\n  }\n  function createFiberFromHostInstanceForDeletion() {\n    var fiber = createFiber(HostComponent, null, null, NoMode);\n    fiber.elementType = 'DELETED';\n    return fiber;\n  }\n  function createFiberFromDehydratedFragment(dehydratedNode) {\n    var fiber = createFiber(DehydratedFragment, null, null, NoMode);\n    fiber.stateNode = dehydratedNode;\n    return fiber;\n  }\n  function createFiberFromPortal(portal, mode, lanes) {\n    var pendingProps = portal.children !== null ? portal.children : [];\n    var fiber = createFiber(HostPortal, pendingProps, portal.key, mode);\n    fiber.lanes = lanes;\n    fiber.stateNode = {\n      containerInfo: portal.containerInfo,\n      pendingChildren: null,\n      // Used by persistent updates\n      implementation: portal.implementation\n    };\n    return fiber;\n  } // Used for stashing WIP properties to replay failed work in DEV.\n\n  function assignFiberPropertiesInDEV(target, source) {\n    if (target === null) {\n      // This Fiber's initial properties will always be overwritten.\n      // We only use a Fiber to ensure the same hidden class so DEV isn't slow.\n      target = createFiber(IndeterminateComponent, null, null, NoMode);\n    } // This is intentionally written as a list of all properties.\n    // We tried to use Object.assign() instead but this is called in\n    // the hottest path, and Object.assign() was too slow:\n    // https://github.com/facebook/react/issues/12502\n    // This code is DEV-only so size is not a concern.\n\n\n    target.tag = source.tag;\n    target.key = source.key;\n    target.elementType = source.elementType;\n    target.type = source.type;\n    target.stateNode = source.stateNode;\n    target.return = source.return;\n    target.child = source.child;\n    target.sibling = source.sibling;\n    target.index = source.index;\n    target.ref = source.ref;\n    target.pendingProps = source.pendingProps;\n    target.memoizedProps = source.memoizedProps;\n    target.updateQueue = source.updateQueue;\n    target.memoizedState = source.memoizedState;\n    target.dependencies = source.dependencies;\n    target.mode = source.mode;\n    target.flags = source.flags;\n    target.subtreeFlags = source.subtreeFlags;\n    target.deletions = source.deletions;\n    target.lanes = source.lanes;\n    target.childLanes = source.childLanes;\n    target.alternate = source.alternate;\n\n    {\n      target.actualDuration = source.actualDuration;\n      target.actualStartTime = source.actualStartTime;\n      target.selfBaseDuration = source.selfBaseDuration;\n      target.treeBaseDuration = source.treeBaseDuration;\n    }\n\n    target._debugSource = source._debugSource;\n    target._debugOwner = source._debugOwner;\n    target._debugNeedsRemount = source._debugNeedsRemount;\n    target._debugHookTypes = source._debugHookTypes;\n    return target;\n  }\n\n  function FiberRootNode(containerInfo, tag, hydrate, identifierPrefix, onRecoverableError) {\n    this.tag = tag;\n    this.containerInfo = containerInfo;\n    this.pendingChildren = null;\n    this.current = null;\n    this.pingCache = null;\n    this.finishedWork = null;\n    this.timeoutHandle = noTimeout;\n    this.context = null;\n    this.pendingContext = null;\n    this.callbackNode = null;\n    this.callbackPriority = NoLane;\n    this.eventTimes = createLaneMap(NoLanes);\n    this.expirationTimes = createLaneMap(NoTimestamp);\n    this.pendingLanes = NoLanes;\n    this.suspendedLanes = NoLanes;\n    this.pingedLanes = NoLanes;\n    this.expiredLanes = NoLanes;\n    this.mutableReadLanes = NoLanes;\n    this.finishedLanes = NoLanes;\n    this.entangledLanes = NoLanes;\n    this.entanglements = createLaneMap(NoLanes);\n    this.identifierPrefix = identifierPrefix;\n    this.onRecoverableError = onRecoverableError;\n\n    {\n      this.mutableSourceEagerHydrationData = null;\n    }\n\n    {\n      this.effectDuration = 0;\n      this.passiveEffectDuration = 0;\n    }\n\n    {\n      this.memoizedUpdaters = new Set();\n      var pendingUpdatersLaneMap = this.pendingUpdatersLaneMap = [];\n\n      for (var _i = 0; _i < TotalLanes; _i++) {\n        pendingUpdatersLaneMap.push(new Set());\n      }\n    }\n\n    {\n      switch (tag) {\n        case ConcurrentRoot:\n          this._debugRootType = hydrate ? 'hydrateRoot()' : 'createRoot()';\n          break;\n\n        case LegacyRoot:\n          this._debugRootType = hydrate ? 'hydrate()' : 'render()';\n          break;\n      }\n    }\n  }\n\n  function createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, // TODO: We have several of these arguments that are conceptually part of the\n  // host config, but because they are passed in at runtime, we have to thread\n  // them through the root constructor. Perhaps we should put them all into a\n  // single type, like a DynamicHostConfig that is defined by the renderer.\n  identifierPrefix, onRecoverableError, transitionCallbacks) {\n    var root = new FiberRootNode(containerInfo, tag, hydrate, identifierPrefix, onRecoverableError);\n    // stateNode is any.\n\n\n    var uninitializedFiber = createHostRootFiber(tag, isStrictMode);\n    root.current = uninitializedFiber;\n    uninitializedFiber.stateNode = root;\n\n    {\n      var _initialState = {\n        element: initialChildren,\n        isDehydrated: hydrate,\n        cache: null,\n        // not enabled yet\n        transitions: null,\n        pendingSuspenseBoundaries: null\n      };\n      uninitializedFiber.memoizedState = _initialState;\n    }\n\n    initializeUpdateQueue(uninitializedFiber);\n    return root;\n  }\n\n  var ReactVersion = '18.3.1';\n\n  function createPortal(children, containerInfo, // TODO: figure out the API for cross-renderer implementation.\n  implementation) {\n    var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n\n    {\n      checkKeyStringCoercion(key);\n    }\n\n    return {\n      // This tag allow us to uniquely identify this as a React Portal\n      $$typeof: REACT_PORTAL_TYPE,\n      key: key == null ? null : '' + key,\n      children: children,\n      containerInfo: containerInfo,\n      implementation: implementation\n    };\n  }\n\n  var didWarnAboutNestedUpdates;\n  var didWarnAboutFindNodeInStrictMode;\n\n  {\n    didWarnAboutNestedUpdates = false;\n    didWarnAboutFindNodeInStrictMode = {};\n  }\n\n  function getContextForSubtree(parentComponent) {\n    if (!parentComponent) {\n      return emptyContextObject;\n    }\n\n    var fiber = get(parentComponent);\n    var parentContext = findCurrentUnmaskedContext(fiber);\n\n    if (fiber.tag === ClassComponent) {\n      var Component = fiber.type;\n\n      if (isContextProvider(Component)) {\n        return processChildContext(fiber, Component, parentContext);\n      }\n    }\n\n    return parentContext;\n  }\n\n  function findHostInstanceWithWarning(component, methodName) {\n    {\n      var fiber = get(component);\n\n      if (fiber === undefined) {\n        if (typeof component.render === 'function') {\n          throw new Error('Unable to find node on an unmounted component.');\n        } else {\n          var keys = Object.keys(component).join(',');\n          throw new Error(\"Argument appears to not be a ReactComponent. Keys: \" + keys);\n        }\n      }\n\n      var hostFiber = findCurrentHostFiber(fiber);\n\n      if (hostFiber === null) {\n        return null;\n      }\n\n      if (hostFiber.mode & StrictLegacyMode) {\n        var componentName = getComponentNameFromFiber(fiber) || 'Component';\n\n        if (!didWarnAboutFindNodeInStrictMode[componentName]) {\n          didWarnAboutFindNodeInStrictMode[componentName] = true;\n          var previousFiber = current;\n\n          try {\n            setCurrentFiber(hostFiber);\n\n            if (fiber.mode & StrictLegacyMode) {\n              error('%s is deprecated in StrictMode. ' + '%s was passed an instance of %s which is inside StrictMode. ' + 'Instead, add a ref directly to the element you want to reference. ' + 'Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-find-node', methodName, methodName, componentName);\n            } else {\n              error('%s is deprecated in StrictMode. ' + '%s was passed an instance of %s which renders StrictMode children. ' + 'Instead, add a ref directly to the element you want to reference. ' + 'Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-find-node', methodName, methodName, componentName);\n            }\n          } finally {\n            // Ideally this should reset to previous but this shouldn't be called in\n            // render and there's another warning for that anyway.\n            if (previousFiber) {\n              setCurrentFiber(previousFiber);\n            } else {\n              resetCurrentFiber();\n            }\n          }\n        }\n      }\n\n      return hostFiber.stateNode;\n    }\n  }\n\n  function createContainer(containerInfo, tag, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError, transitionCallbacks) {\n    var hydrate = false;\n    var initialChildren = null;\n    return createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError);\n  }\n  function createHydrationContainer(initialChildren, // TODO: Remove `callback` when we delete legacy mode.\n  callback, containerInfo, tag, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError, transitionCallbacks) {\n    var hydrate = true;\n    var root = createFiberRoot(containerInfo, tag, hydrate, initialChildren, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError); // TODO: Move this to FiberRoot constructor\n\n    root.context = getContextForSubtree(null); // Schedule the initial render. In a hydration root, this is different from\n    // a regular update because the initial render must match was was rendered\n    // on the server.\n    // NOTE: This update intentionally doesn't have a payload. We're only using\n    // the update to schedule work on the root fiber (and, for legacy roots, to\n    // enqueue the callback if one is provided).\n\n    var current = root.current;\n    var eventTime = requestEventTime();\n    var lane = requestUpdateLane(current);\n    var update = createUpdate(eventTime, lane);\n    update.callback = callback !== undefined && callback !== null ? callback : null;\n    enqueueUpdate(current, update, lane);\n    scheduleInitialHydrationOnRoot(root, lane, eventTime);\n    return root;\n  }\n  function updateContainer(element, container, parentComponent, callback) {\n    {\n      onScheduleRoot(container, element);\n    }\n\n    var current$1 = container.current;\n    var eventTime = requestEventTime();\n    var lane = requestUpdateLane(current$1);\n\n    {\n      markRenderScheduled(lane);\n    }\n\n    var context = getContextForSubtree(parentComponent);\n\n    if (container.context === null) {\n      container.context = context;\n    } else {\n      container.pendingContext = context;\n    }\n\n    {\n      if (isRendering && current !== null && !didWarnAboutNestedUpdates) {\n        didWarnAboutNestedUpdates = true;\n\n        error('Render methods should be a pure function of props and state; ' + 'triggering nested component updates from render is not allowed. ' + 'If necessary, trigger nested updates in componentDidUpdate.\\n\\n' + 'Check the render method of %s.', getComponentNameFromFiber(current) || 'Unknown');\n      }\n    }\n\n    var update = createUpdate(eventTime, lane); // Caution: React DevTools currently depends on this property\n    // being called \"element\".\n\n    update.payload = {\n      element: element\n    };\n    callback = callback === undefined ? null : callback;\n\n    if (callback !== null) {\n      {\n        if (typeof callback !== 'function') {\n          error('render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback);\n        }\n      }\n\n      update.callback = callback;\n    }\n\n    var root = enqueueUpdate(current$1, update, lane);\n\n    if (root !== null) {\n      scheduleUpdateOnFiber(root, current$1, lane, eventTime);\n      entangleTransitions(root, current$1, lane);\n    }\n\n    return lane;\n  }\n  function getPublicRootInstance(container) {\n    var containerFiber = container.current;\n\n    if (!containerFiber.child) {\n      return null;\n    }\n\n    switch (containerFiber.child.tag) {\n      case HostComponent:\n        return getPublicInstance(containerFiber.child.stateNode);\n\n      default:\n        return containerFiber.child.stateNode;\n    }\n  }\n  function attemptSynchronousHydration$1(fiber) {\n    switch (fiber.tag) {\n      case HostRoot:\n        {\n          var root = fiber.stateNode;\n\n          if (isRootDehydrated(root)) {\n            // Flush the first scheduled \"update\".\n            var lanes = getHighestPriorityPendingLanes(root);\n            flushRoot(root, lanes);\n          }\n\n          break;\n        }\n\n      case SuspenseComponent:\n        {\n          flushSync(function () {\n            var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n            if (root !== null) {\n              var eventTime = requestEventTime();\n              scheduleUpdateOnFiber(root, fiber, SyncLane, eventTime);\n            }\n          }); // If we're still blocked after this, we need to increase\n          // the priority of any promises resolving within this\n          // boundary so that they next attempt also has higher pri.\n\n          var retryLane = SyncLane;\n          markRetryLaneIfNotHydrated(fiber, retryLane);\n          break;\n        }\n    }\n  }\n\n  function markRetryLaneImpl(fiber, retryLane) {\n    var suspenseState = fiber.memoizedState;\n\n    if (suspenseState !== null && suspenseState.dehydrated !== null) {\n      suspenseState.retryLane = higherPriorityLane(suspenseState.retryLane, retryLane);\n    }\n  } // Increases the priority of thenables when they resolve within this boundary.\n\n\n  function markRetryLaneIfNotHydrated(fiber, retryLane) {\n    markRetryLaneImpl(fiber, retryLane);\n    var alternate = fiber.alternate;\n\n    if (alternate) {\n      markRetryLaneImpl(alternate, retryLane);\n    }\n  }\n  function attemptContinuousHydration$1(fiber) {\n    if (fiber.tag !== SuspenseComponent) {\n      // We ignore HostRoots here because we can't increase\n      // their priority and they should not suspend on I/O,\n      // since you have to wrap anything that might suspend in\n      // Suspense.\n      return;\n    }\n\n    var lane = SelectiveHydrationLane;\n    var root = enqueueConcurrentRenderForLane(fiber, lane);\n\n    if (root !== null) {\n      var eventTime = requestEventTime();\n      scheduleUpdateOnFiber(root, fiber, lane, eventTime);\n    }\n\n    markRetryLaneIfNotHydrated(fiber, lane);\n  }\n  function attemptHydrationAtCurrentPriority$1(fiber) {\n    if (fiber.tag !== SuspenseComponent) {\n      // We ignore HostRoots here because we can't increase\n      // their priority other than synchronously flush it.\n      return;\n    }\n\n    var lane = requestUpdateLane(fiber);\n    var root = enqueueConcurrentRenderForLane(fiber, lane);\n\n    if (root !== null) {\n      var eventTime = requestEventTime();\n      scheduleUpdateOnFiber(root, fiber, lane, eventTime);\n    }\n\n    markRetryLaneIfNotHydrated(fiber, lane);\n  }\n  function findHostInstanceWithNoPortals(fiber) {\n    var hostFiber = findCurrentHostFiberWithNoPortals(fiber);\n\n    if (hostFiber === null) {\n      return null;\n    }\n\n    return hostFiber.stateNode;\n  }\n\n  var shouldErrorImpl = function (fiber) {\n    return null;\n  };\n\n  function shouldError(fiber) {\n    return shouldErrorImpl(fiber);\n  }\n\n  var shouldSuspendImpl = function (fiber) {\n    return false;\n  };\n\n  function shouldSuspend(fiber) {\n    return shouldSuspendImpl(fiber);\n  }\n  var overrideHookState = null;\n  var overrideHookStateDeletePath = null;\n  var overrideHookStateRenamePath = null;\n  var overrideProps = null;\n  var overridePropsDeletePath = null;\n  var overridePropsRenamePath = null;\n  var scheduleUpdate = null;\n  var setErrorHandler = null;\n  var setSuspenseHandler = null;\n\n  {\n    var copyWithDeleteImpl = function (obj, path, index) {\n      var key = path[index];\n      var updated = isArray(obj) ? obj.slice() : assign({}, obj);\n\n      if (index + 1 === path.length) {\n        if (isArray(updated)) {\n          updated.splice(key, 1);\n        } else {\n          delete updated[key];\n        }\n\n        return updated;\n      } // $FlowFixMe number or string is fine here\n\n\n      updated[key] = copyWithDeleteImpl(obj[key], path, index + 1);\n      return updated;\n    };\n\n    var copyWithDelete = function (obj, path) {\n      return copyWithDeleteImpl(obj, path, 0);\n    };\n\n    var copyWithRenameImpl = function (obj, oldPath, newPath, index) {\n      var oldKey = oldPath[index];\n      var updated = isArray(obj) ? obj.slice() : assign({}, obj);\n\n      if (index + 1 === oldPath.length) {\n        var newKey = newPath[index]; // $FlowFixMe number or string is fine here\n\n        updated[newKey] = updated[oldKey];\n\n        if (isArray(updated)) {\n          updated.splice(oldKey, 1);\n        } else {\n          delete updated[oldKey];\n        }\n      } else {\n        // $FlowFixMe number or string is fine here\n        updated[oldKey] = copyWithRenameImpl( // $FlowFixMe number or string is fine here\n        obj[oldKey], oldPath, newPath, index + 1);\n      }\n\n      return updated;\n    };\n\n    var copyWithRename = function (obj, oldPath, newPath) {\n      if (oldPath.length !== newPath.length) {\n        warn('copyWithRename() expects paths of the same length');\n\n        return;\n      } else {\n        for (var i = 0; i < newPath.length - 1; i++) {\n          if (oldPath[i] !== newPath[i]) {\n            warn('copyWithRename() expects paths to be the same except for the deepest key');\n\n            return;\n          }\n        }\n      }\n\n      return copyWithRenameImpl(obj, oldPath, newPath, 0);\n    };\n\n    var copyWithSetImpl = function (obj, path, index, value) {\n      if (index >= path.length) {\n        return value;\n      }\n\n      var key = path[index];\n      var updated = isArray(obj) ? obj.slice() : assign({}, obj); // $FlowFixMe number or string is fine here\n\n      updated[key] = copyWithSetImpl(obj[key], path, index + 1, value);\n      return updated;\n    };\n\n    var copyWithSet = function (obj, path, value) {\n      return copyWithSetImpl(obj, path, 0, value);\n    };\n\n    var findHook = function (fiber, id) {\n      // For now, the \"id\" of stateful hooks is just the stateful hook index.\n      // This may change in the future with e.g. nested hooks.\n      var currentHook = fiber.memoizedState;\n\n      while (currentHook !== null && id > 0) {\n        currentHook = currentHook.next;\n        id--;\n      }\n\n      return currentHook;\n    }; // Support DevTools editable values for useState and useReducer.\n\n\n    overrideHookState = function (fiber, id, path, value) {\n      var hook = findHook(fiber, id);\n\n      if (hook !== null) {\n        var newState = copyWithSet(hook.memoizedState, path, value);\n        hook.memoizedState = newState;\n        hook.baseState = newState; // We aren't actually adding an update to the queue,\n        // because there is no update we can add for useReducer hooks that won't trigger an error.\n        // (There's no appropriate action type for DevTools overrides.)\n        // As a result though, React will see the scheduled update as a noop and bailout.\n        // Shallow cloning props works as a workaround for now to bypass the bailout check.\n\n        fiber.memoizedProps = assign({}, fiber.memoizedProps);\n        var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n        if (root !== null) {\n          scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n        }\n      }\n    };\n\n    overrideHookStateDeletePath = function (fiber, id, path) {\n      var hook = findHook(fiber, id);\n\n      if (hook !== null) {\n        var newState = copyWithDelete(hook.memoizedState, path);\n        hook.memoizedState = newState;\n        hook.baseState = newState; // We aren't actually adding an update to the queue,\n        // because there is no update we can add for useReducer hooks that won't trigger an error.\n        // (There's no appropriate action type for DevTools overrides.)\n        // As a result though, React will see the scheduled update as a noop and bailout.\n        // Shallow cloning props works as a workaround for now to bypass the bailout check.\n\n        fiber.memoizedProps = assign({}, fiber.memoizedProps);\n        var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n        if (root !== null) {\n          scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n        }\n      }\n    };\n\n    overrideHookStateRenamePath = function (fiber, id, oldPath, newPath) {\n      var hook = findHook(fiber, id);\n\n      if (hook !== null) {\n        var newState = copyWithRename(hook.memoizedState, oldPath, newPath);\n        hook.memoizedState = newState;\n        hook.baseState = newState; // We aren't actually adding an update to the queue,\n        // because there is no update we can add for useReducer hooks that won't trigger an error.\n        // (There's no appropriate action type for DevTools overrides.)\n        // As a result though, React will see the scheduled update as a noop and bailout.\n        // Shallow cloning props works as a workaround for now to bypass the bailout check.\n\n        fiber.memoizedProps = assign({}, fiber.memoizedProps);\n        var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n        if (root !== null) {\n          scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n        }\n      }\n    }; // Support DevTools props for function components, forwardRef, memo, host components, etc.\n\n\n    overrideProps = function (fiber, path, value) {\n      fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);\n\n      if (fiber.alternate) {\n        fiber.alternate.pendingProps = fiber.pendingProps;\n      }\n\n      var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n      if (root !== null) {\n        scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n      }\n    };\n\n    overridePropsDeletePath = function (fiber, path) {\n      fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path);\n\n      if (fiber.alternate) {\n        fiber.alternate.pendingProps = fiber.pendingProps;\n      }\n\n      var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n      if (root !== null) {\n        scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n      }\n    };\n\n    overridePropsRenamePath = function (fiber, oldPath, newPath) {\n      fiber.pendingProps = copyWithRename(fiber.memoizedProps, oldPath, newPath);\n\n      if (fiber.alternate) {\n        fiber.alternate.pendingProps = fiber.pendingProps;\n      }\n\n      var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n      if (root !== null) {\n        scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n      }\n    };\n\n    scheduleUpdate = function (fiber) {\n      var root = enqueueConcurrentRenderForLane(fiber, SyncLane);\n\n      if (root !== null) {\n        scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);\n      }\n    };\n\n    setErrorHandler = function (newShouldErrorImpl) {\n      shouldErrorImpl = newShouldErrorImpl;\n    };\n\n    setSuspenseHandler = function (newShouldSuspendImpl) {\n      shouldSuspendImpl = newShouldSuspendImpl;\n    };\n  }\n\n  function findHostInstanceByFiber(fiber) {\n    var hostFiber = findCurrentHostFiber(fiber);\n\n    if (hostFiber === null) {\n      return null;\n    }\n\n    return hostFiber.stateNode;\n  }\n\n  function emptyFindFiberByHostInstance(instance) {\n    return null;\n  }\n\n  function getCurrentFiberForDevTools() {\n    return current;\n  }\n\n  function injectIntoDevTools(devToolsConfig) {\n    var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;\n    var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher;\n    return injectInternals({\n      bundleType: devToolsConfig.bundleType,\n      version: devToolsConfig.version,\n      rendererPackageName: devToolsConfig.rendererPackageName,\n      rendererConfig: devToolsConfig.rendererConfig,\n      overrideHookState: overrideHookState,\n      overrideHookStateDeletePath: overrideHookStateDeletePath,\n      overrideHookStateRenamePath: overrideHookStateRenamePath,\n      overrideProps: overrideProps,\n      overridePropsDeletePath: overridePropsDeletePath,\n      overridePropsRenamePath: overridePropsRenamePath,\n      setErrorHandler: setErrorHandler,\n      setSuspenseHandler: setSuspenseHandler,\n      scheduleUpdate: scheduleUpdate,\n      currentDispatcherRef: ReactCurrentDispatcher,\n      findHostInstanceByFiber: findHostInstanceByFiber,\n      findFiberByHostInstance: findFiberByHostInstance || emptyFindFiberByHostInstance,\n      // React Refresh\n      findHostInstancesForRefresh:  findHostInstancesForRefresh ,\n      scheduleRefresh:  scheduleRefresh ,\n      scheduleRoot:  scheduleRoot ,\n      setRefreshHandler:  setRefreshHandler ,\n      // Enables DevTools to append owner stacks to error messages in DEV mode.\n      getCurrentFiber:  getCurrentFiberForDevTools ,\n      // Enables DevTools to detect reconciler version rather than renderer version\n      // which may not match for third party renderers.\n      reconcilerVersion: ReactVersion\n    });\n  }\n\n  /* global reportError */\n\n  var defaultOnRecoverableError = typeof reportError === 'function' ? // In modern browsers, reportError will dispatch an error event,\n  // emulating an uncaught JavaScript error.\n  reportError : function (error) {\n    // In older browsers and test environments, fallback to console.error.\n    // eslint-disable-next-line react-internal/no-production-logging\n    console['error'](error);\n  };\n\n  function ReactDOMRoot(internalRoot) {\n    this._internalRoot = internalRoot;\n  }\n\n  ReactDOMHydrationRoot.prototype.render = ReactDOMRoot.prototype.render = function (children) {\n    var root = this._internalRoot;\n\n    if (root === null) {\n      throw new Error('Cannot update an unmounted root.');\n    }\n\n    {\n      if (typeof arguments[1] === 'function') {\n        error('render(...): does not support the second callback argument. ' + 'To execute a side effect after rendering, declare it in a component body with useEffect().');\n      } else if (isValidContainer(arguments[1])) {\n        error('You passed a container to the second argument of root.render(...). ' + \"You don't need to pass it again since you already passed it to create the root.\");\n      } else if (typeof arguments[1] !== 'undefined') {\n        error('You passed a second argument to root.render(...) but it only accepts ' + 'one argument.');\n      }\n\n      var container = root.containerInfo;\n\n      if (container.nodeType !== COMMENT_NODE) {\n        var hostInstance = findHostInstanceWithNoPortals(root.current);\n\n        if (hostInstance) {\n          if (hostInstance.parentNode !== container) {\n            error('render(...): It looks like the React-rendered content of the ' + 'root container was removed without using React. This is not ' + 'supported and will cause errors. Instead, call ' + \"root.unmount() to empty a root's container.\");\n          }\n        }\n      }\n    }\n\n    updateContainer(children, root, null, null);\n  };\n\n  ReactDOMHydrationRoot.prototype.unmount = ReactDOMRoot.prototype.unmount = function () {\n    {\n      if (typeof arguments[0] === 'function') {\n        error('unmount(...): does not support a callback argument. ' + 'To execute a side effect after rendering, declare it in a component body with useEffect().');\n      }\n    }\n\n    var root = this._internalRoot;\n\n    if (root !== null) {\n      this._internalRoot = null;\n      var container = root.containerInfo;\n\n      {\n        if (isAlreadyRendering()) {\n          error('Attempted to synchronously unmount a root while React was already ' + 'rendering. React cannot finish unmounting the root until the ' + 'current render has completed, which may lead to a race condition.');\n        }\n      }\n\n      flushSync(function () {\n        updateContainer(null, root, null, null);\n      });\n      unmarkContainerAsRoot(container);\n    }\n  };\n\n  function createRoot(container, options) {\n    if (!isValidContainer(container)) {\n      throw new Error('createRoot(...): Target container is not a DOM element.');\n    }\n\n    warnIfReactDOMContainerInDEV(container);\n    var isStrictMode = false;\n    var concurrentUpdatesByDefaultOverride = false;\n    var identifierPrefix = '';\n    var onRecoverableError = defaultOnRecoverableError;\n    var transitionCallbacks = null;\n\n    if (options !== null && options !== undefined) {\n      {\n        if (options.hydrate) {\n          warn('hydrate through createRoot is deprecated. Use ReactDOMClient.hydrateRoot(container, <App />) instead.');\n        } else {\n          if (typeof options === 'object' && options !== null && options.$$typeof === REACT_ELEMENT_TYPE) {\n            error('You passed a JSX element to createRoot. You probably meant to ' + 'call root.render instead. ' + 'Example usage:\\n\\n' + '  let root = createRoot(domContainer);\\n' + '  root.render(<App />);');\n          }\n        }\n      }\n\n      if (options.unstable_strictMode === true) {\n        isStrictMode = true;\n      }\n\n      if (options.identifierPrefix !== undefined) {\n        identifierPrefix = options.identifierPrefix;\n      }\n\n      if (options.onRecoverableError !== undefined) {\n        onRecoverableError = options.onRecoverableError;\n      }\n\n      if (options.transitionCallbacks !== undefined) {\n        transitionCallbacks = options.transitionCallbacks;\n      }\n    }\n\n    var root = createContainer(container, ConcurrentRoot, null, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError);\n    markContainerAsRoot(root.current, container);\n    var rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container;\n    listenToAllSupportedEvents(rootContainerElement);\n    return new ReactDOMRoot(root);\n  }\n\n  function ReactDOMHydrationRoot(internalRoot) {\n    this._internalRoot = internalRoot;\n  }\n\n  function scheduleHydration(target) {\n    if (target) {\n      queueExplicitHydrationTarget(target);\n    }\n  }\n\n  ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = scheduleHydration;\n  function hydrateRoot(container, initialChildren, options) {\n    if (!isValidContainer(container)) {\n      throw new Error('hydrateRoot(...): Target container is not a DOM element.');\n    }\n\n    warnIfReactDOMContainerInDEV(container);\n\n    {\n      if (initialChildren === undefined) {\n        error('Must provide initial children as second argument to hydrateRoot. ' + 'Example usage: hydrateRoot(domContainer, <App />)');\n      }\n    } // For now we reuse the whole bag of options since they contain\n    // the hydration callbacks.\n\n\n    var hydrationCallbacks = options != null ? options : null; // TODO: Delete this option\n\n    var mutableSources = options != null && options.hydratedSources || null;\n    var isStrictMode = false;\n    var concurrentUpdatesByDefaultOverride = false;\n    var identifierPrefix = '';\n    var onRecoverableError = defaultOnRecoverableError;\n\n    if (options !== null && options !== undefined) {\n      if (options.unstable_strictMode === true) {\n        isStrictMode = true;\n      }\n\n      if (options.identifierPrefix !== undefined) {\n        identifierPrefix = options.identifierPrefix;\n      }\n\n      if (options.onRecoverableError !== undefined) {\n        onRecoverableError = options.onRecoverableError;\n      }\n    }\n\n    var root = createHydrationContainer(initialChildren, null, container, ConcurrentRoot, hydrationCallbacks, isStrictMode, concurrentUpdatesByDefaultOverride, identifierPrefix, onRecoverableError);\n    markContainerAsRoot(root.current, container); // This can't be a comment node since hydration doesn't work on comment nodes anyway.\n\n    listenToAllSupportedEvents(container);\n\n    if (mutableSources) {\n      for (var i = 0; i < mutableSources.length; i++) {\n        var mutableSource = mutableSources[i];\n        registerMutableSourceForHydration(root, mutableSource);\n      }\n    }\n\n    return new ReactDOMHydrationRoot(root);\n  }\n  function isValidContainer(node) {\n    return !!(node && (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE || !disableCommentsAsDOMContainers  ));\n  } // TODO: Remove this function which also includes comment nodes.\n  // We only use it in places that are currently more relaxed.\n\n  function isValidContainerLegacy(node) {\n    return !!(node && (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE || node.nodeType === COMMENT_NODE && node.nodeValue === ' react-mount-point-unstable '));\n  }\n\n  function warnIfReactDOMContainerInDEV(container) {\n    {\n      if (container.nodeType === ELEMENT_NODE && container.tagName && container.tagName.toUpperCase() === 'BODY') {\n        error('createRoot(): Creating roots directly with document.body is ' + 'discouraged, since its children are often manipulated by third-party ' + 'scripts and browser extensions. This may lead to subtle ' + 'reconciliation issues. Try using a container element created ' + 'for your app.');\n      }\n\n      if (isContainerMarkedAsRoot(container)) {\n        if (container._reactRootContainer) {\n          error('You are calling ReactDOMClient.createRoot() on a container that was previously ' + 'passed to ReactDOM.render(). This is not supported.');\n        } else {\n          error('You are calling ReactDOMClient.createRoot() on a container that ' + 'has already been passed to createRoot() before. Instead, call ' + 'root.render() on the existing root instead if you want to update it.');\n        }\n      }\n    }\n  }\n\n  var ReactCurrentOwner$3 = ReactSharedInternals.ReactCurrentOwner;\n  var topLevelUpdateWarnings;\n\n  {\n    topLevelUpdateWarnings = function (container) {\n      if (container._reactRootContainer && container.nodeType !== COMMENT_NODE) {\n        var hostInstance = findHostInstanceWithNoPortals(container._reactRootContainer.current);\n\n        if (hostInstance) {\n          if (hostInstance.parentNode !== container) {\n            error('render(...): It looks like the React-rendered content of this ' + 'container was removed without using React. This is not ' + 'supported and will cause errors. Instead, call ' + 'ReactDOM.unmountComponentAtNode to empty a container.');\n          }\n        }\n      }\n\n      var isRootRenderedBySomeReact = !!container._reactRootContainer;\n      var rootEl = getReactRootElementInContainer(container);\n      var hasNonRootReactChild = !!(rootEl && getInstanceFromNode(rootEl));\n\n      if (hasNonRootReactChild && !isRootRenderedBySomeReact) {\n        error('render(...): Replacing React-rendered children with a new root ' + 'component. If you intended to update the children of this node, ' + 'you should instead have the existing children update their state ' + 'and render the new components instead of calling ReactDOM.render.');\n      }\n\n      if (container.nodeType === ELEMENT_NODE && container.tagName && container.tagName.toUpperCase() === 'BODY') {\n        error('render(): Rendering components directly into document.body is ' + 'discouraged, since its children are often manipulated by third-party ' + 'scripts and browser extensions. This may lead to subtle ' + 'reconciliation issues. Try rendering into a container element created ' + 'for your app.');\n      }\n    };\n  }\n\n  function getReactRootElementInContainer(container) {\n    if (!container) {\n      return null;\n    }\n\n    if (container.nodeType === DOCUMENT_NODE) {\n      return container.documentElement;\n    } else {\n      return container.firstChild;\n    }\n  }\n\n  function noopOnRecoverableError() {// This isn't reachable because onRecoverableError isn't called in the\n    // legacy API.\n  }\n\n  function legacyCreateRootFromDOMContainer(container, initialChildren, parentComponent, callback, isHydrationContainer) {\n    if (isHydrationContainer) {\n      if (typeof callback === 'function') {\n        var originalCallback = callback;\n\n        callback = function () {\n          var instance = getPublicRootInstance(root);\n          originalCallback.call(instance);\n        };\n      }\n\n      var root = createHydrationContainer(initialChildren, callback, container, LegacyRoot, null, // hydrationCallbacks\n      false, // isStrictMode\n      false, // concurrentUpdatesByDefaultOverride,\n      '', // identifierPrefix\n      noopOnRecoverableError);\n      container._reactRootContainer = root;\n      markContainerAsRoot(root.current, container);\n      var rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container;\n      listenToAllSupportedEvents(rootContainerElement);\n      flushSync();\n      return root;\n    } else {\n      // First clear any existing content.\n      var rootSibling;\n\n      while (rootSibling = container.lastChild) {\n        container.removeChild(rootSibling);\n      }\n\n      if (typeof callback === 'function') {\n        var _originalCallback = callback;\n\n        callback = function () {\n          var instance = getPublicRootInstance(_root);\n\n          _originalCallback.call(instance);\n        };\n      }\n\n      var _root = createContainer(container, LegacyRoot, null, // hydrationCallbacks\n      false, // isStrictMode\n      false, // concurrentUpdatesByDefaultOverride,\n      '', // identifierPrefix\n      noopOnRecoverableError);\n\n      container._reactRootContainer = _root;\n      markContainerAsRoot(_root.current, container);\n\n      var _rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container;\n\n      listenToAllSupportedEvents(_rootContainerElement); // Initial mount should not be batched.\n\n      flushSync(function () {\n        updateContainer(initialChildren, _root, parentComponent, callback);\n      });\n      return _root;\n    }\n  }\n\n  function warnOnInvalidCallback$1(callback, callerName) {\n    {\n      if (callback !== null && typeof callback !== 'function') {\n        error('%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback);\n      }\n    }\n  }\n\n  function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {\n    {\n      topLevelUpdateWarnings(container);\n      warnOnInvalidCallback$1(callback === undefined ? null : callback, 'render');\n    }\n\n    var maybeRoot = container._reactRootContainer;\n    var root;\n\n    if (!maybeRoot) {\n      // Initial mount\n      root = legacyCreateRootFromDOMContainer(container, children, parentComponent, callback, forceHydrate);\n    } else {\n      root = maybeRoot;\n\n      if (typeof callback === 'function') {\n        var originalCallback = callback;\n\n        callback = function () {\n          var instance = getPublicRootInstance(root);\n          originalCallback.call(instance);\n        };\n      } // Update\n\n\n      updateContainer(children, root, parentComponent, callback);\n    }\n\n    return getPublicRootInstance(root);\n  }\n\n  var didWarnAboutFindDOMNode = false;\n  function findDOMNode(componentOrElement) {\n    {\n      if (!didWarnAboutFindDOMNode) {\n        didWarnAboutFindDOMNode = true;\n\n        error('findDOMNode is deprecated and will be removed in the next major ' + 'release. Instead, add a ref directly to the element you want ' + 'to reference. Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-find-node');\n      }\n\n      var owner = ReactCurrentOwner$3.current;\n\n      if (owner !== null && owner.stateNode !== null) {\n        var warnedAboutRefsInRender = owner.stateNode._warnedAboutRefsInRender;\n\n        if (!warnedAboutRefsInRender) {\n          error('%s is accessing findDOMNode inside its render(). ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentNameFromType(owner.type) || 'A component');\n        }\n\n        owner.stateNode._warnedAboutRefsInRender = true;\n      }\n    }\n\n    if (componentOrElement == null) {\n      return null;\n    }\n\n    if (componentOrElement.nodeType === ELEMENT_NODE) {\n      return componentOrElement;\n    }\n\n    {\n      return findHostInstanceWithWarning(componentOrElement, 'findDOMNode');\n    }\n  }\n  function hydrate(element, container, callback) {\n    {\n      error('ReactDOM.hydrate is no longer supported in React 18. Use hydrateRoot ' + 'instead. Until you switch to the new API, your app will behave as ' + \"if it's running React 17. Learn \" + 'more: https://reactjs.org/link/switch-to-createroot');\n    }\n\n    if (!isValidContainerLegacy(container)) {\n      throw new Error('Target container is not a DOM element.');\n    }\n\n    {\n      var isModernRoot = isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined;\n\n      if (isModernRoot) {\n        error('You are calling ReactDOM.hydrate() on a container that was previously ' + 'passed to ReactDOMClient.createRoot(). This is not supported. ' + 'Did you mean to call hydrateRoot(container, element)?');\n      }\n    } // TODO: throw or warn if we couldn't hydrate?\n\n\n    return legacyRenderSubtreeIntoContainer(null, element, container, true, callback);\n  }\n  function render(element, container, callback) {\n    {\n      error('ReactDOM.render is no longer supported in React 18. Use createRoot ' + 'instead. Until you switch to the new API, your app will behave as ' + \"if it's running React 17. Learn \" + 'more: https://reactjs.org/link/switch-to-createroot');\n    }\n\n    if (!isValidContainerLegacy(container)) {\n      throw new Error('Target container is not a DOM element.');\n    }\n\n    {\n      var isModernRoot = isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined;\n\n      if (isModernRoot) {\n        error('You are calling ReactDOM.render() on a container that was previously ' + 'passed to ReactDOMClient.createRoot(). This is not supported. ' + 'Did you mean to call root.render(element)?');\n      }\n    }\n\n    return legacyRenderSubtreeIntoContainer(null, element, container, false, callback);\n  }\n  function unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback) {\n    {\n      error('ReactDOM.unstable_renderSubtreeIntoContainer() is no longer supported ' + 'in React 18. Consider using a portal instead. Until you switch to ' + \"the createRoot API, your app will behave as if it's running React \" + '17. Learn more: https://reactjs.org/link/switch-to-createroot');\n    }\n\n    if (!isValidContainerLegacy(containerNode)) {\n      throw new Error('Target container is not a DOM element.');\n    }\n\n    if (parentComponent == null || !has(parentComponent)) {\n      throw new Error('parentComponent must be a valid React Component');\n    }\n\n    return legacyRenderSubtreeIntoContainer(parentComponent, element, containerNode, false, callback);\n  }\n  var didWarnAboutUnmountComponentAtNode = false;\n  function unmountComponentAtNode(container) {\n    {\n      if (!didWarnAboutUnmountComponentAtNode) {\n        didWarnAboutUnmountComponentAtNode = true;\n\n        error('unmountComponentAtNode is deprecated and will be removed in the ' + 'next major release. Switch to the createRoot API. Learn ' + 'more: https://reactjs.org/link/switch-to-createroot');\n      }\n    }\n\n    if (!isValidContainerLegacy(container)) {\n      throw new Error('unmountComponentAtNode(...): Target container is not a DOM element.');\n    }\n\n    {\n      var isModernRoot = isContainerMarkedAsRoot(container) && container._reactRootContainer === undefined;\n\n      if (isModernRoot) {\n        error('You are calling ReactDOM.unmountComponentAtNode() on a container that was previously ' + 'passed to ReactDOMClient.createRoot(). This is not supported. Did you mean to call root.unmount()?');\n      }\n    }\n\n    if (container._reactRootContainer) {\n      {\n        var rootEl = getReactRootElementInContainer(container);\n        var renderedByDifferentReact = rootEl && !getInstanceFromNode(rootEl);\n\n        if (renderedByDifferentReact) {\n          error(\"unmountComponentAtNode(): The node you're attempting to unmount \" + 'was rendered by another copy of React.');\n        }\n      } // Unmount should not be batched.\n\n\n      flushSync(function () {\n        legacyRenderSubtreeIntoContainer(null, null, container, false, function () {\n          // $FlowFixMe This should probably use `delete container._reactRootContainer`\n          container._reactRootContainer = null;\n          unmarkContainerAsRoot(container);\n        });\n      }); // If you call unmountComponentAtNode twice in quick succession, you'll\n      // get `true` twice. That's probably fine?\n\n      return true;\n    } else {\n      {\n        var _rootEl = getReactRootElementInContainer(container);\n\n        var hasNonRootReactChild = !!(_rootEl && getInstanceFromNode(_rootEl)); // Check if the container itself is a React root node.\n\n        var isContainerReactRoot = container.nodeType === ELEMENT_NODE && isValidContainerLegacy(container.parentNode) && !!container.parentNode._reactRootContainer;\n\n        if (hasNonRootReactChild) {\n          error(\"unmountComponentAtNode(): The node you're attempting to unmount \" + 'was rendered by React and is not a top-level container. %s', isContainerReactRoot ? 'You may have accidentally passed in a React root node instead ' + 'of its container.' : 'Instead, have the parent component update its state and ' + 'rerender in order to remove this component.');\n        }\n      }\n\n      return false;\n    }\n  }\n\n  setAttemptSynchronousHydration(attemptSynchronousHydration$1);\n  setAttemptContinuousHydration(attemptContinuousHydration$1);\n  setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority$1);\n  setGetCurrentUpdatePriority(getCurrentUpdatePriority);\n  setAttemptHydrationAtPriority(runWithPriority);\n\n  {\n    if (typeof Map !== 'function' || // $FlowIssue Flow incorrectly thinks Map has no prototype\n    Map.prototype == null || typeof Map.prototype.forEach !== 'function' || typeof Set !== 'function' || // $FlowIssue Flow incorrectly thinks Set has no prototype\n    Set.prototype == null || typeof Set.prototype.clear !== 'function' || typeof Set.prototype.forEach !== 'function') {\n      error('React depends on Map and Set built-in types. Make sure that you load a ' + 'polyfill in older browsers. https://reactjs.org/link/react-polyfills');\n    }\n  }\n\n  setRestoreImplementation(restoreControlledState$3);\n  setBatchingImplementation(batchedUpdates$1, discreteUpdates, flushSync);\n\n  function createPortal$1(children, container) {\n    var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;\n\n    if (!isValidContainer(container)) {\n      throw new Error('Target container is not a DOM element.');\n    } // TODO: pass ReactDOM portal implementation as third argument\n    // $FlowFixMe The Flow type is opaque but there's no way to actually create it.\n\n\n    return createPortal(children, container, null, key);\n  }\n\n  function renderSubtreeIntoContainer(parentComponent, element, containerNode, callback) {\n    return unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback);\n  }\n\n  var Internals = {\n    usingClientEntryPoint: false,\n    // Keep in sync with ReactTestUtils.js.\n    // This is an array for better minification.\n    Events: [getInstanceFromNode, getNodeFromInstance, getFiberCurrentPropsFromNode, enqueueStateRestore, restoreStateIfNeeded, batchedUpdates$1]\n  };\n\n  function createRoot$1(container, options) {\n    {\n      if (!Internals.usingClientEntryPoint && !true) {\n        error('You are importing createRoot from \"react-dom\" which is not supported. ' + 'You should instead import it from \"react-dom/client\".');\n      }\n    }\n\n    return createRoot(container, options);\n  }\n\n  function hydrateRoot$1(container, initialChildren, options) {\n    {\n      if (!Internals.usingClientEntryPoint && !true) {\n        error('You are importing hydrateRoot from \"react-dom\" which is not supported. ' + 'You should instead import it from \"react-dom/client\".');\n      }\n    }\n\n    return hydrateRoot(container, initialChildren, options);\n  } // Overload the definition to the two valid signatures.\n  // Warning, this opts-out of checking the function body.\n\n\n  // eslint-disable-next-line no-redeclare\n  function flushSync$1(fn) {\n    {\n      if (isAlreadyRendering()) {\n        error('flushSync was called from inside a lifecycle method. React cannot ' + 'flush when React is already rendering. Consider moving this call to ' + 'a scheduler task or micro task.');\n      }\n    }\n\n    return flushSync(fn);\n  }\n  var foundDevTools = injectIntoDevTools({\n    findFiberByHostInstance: getClosestInstanceFromNode,\n    bundleType:  1 ,\n    version: ReactVersion,\n    rendererPackageName: 'react-dom'\n  });\n\n  {\n    if (!foundDevTools && canUseDOM && window.top === window.self) {\n      // If we're in Chrome or Firefox, provide a download link if not installed.\n      if (navigator.userAgent.indexOf('Chrome') > -1 && navigator.userAgent.indexOf('Edge') === -1 || navigator.userAgent.indexOf('Firefox') > -1) {\n        var protocol = window.location.protocol; // Don't warn in exotic cases like chrome-extension://.\n\n        if (/^(https?|file):$/.test(protocol)) {\n          // eslint-disable-next-line react-internal/no-production-logging\n          console.info('%cDownload the React DevTools ' + 'for a better development experience: ' + 'https://reactjs.org/link/react-devtools' + (protocol === 'file:' ? '\\nYou might need to use a local HTTP server (instead of file://): ' + 'https://reactjs.org/link/react-devtools-faq' : ''), 'font-weight:bold');\n        }\n      }\n    }\n  }\n\n  exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = Internals;\n  exports.createPortal = createPortal$1;\n  exports.createRoot = createRoot$1;\n  exports.findDOMNode = findDOMNode;\n  exports.flushSync = flushSync$1;\n  exports.hydrate = hydrate;\n  exports.hydrateRoot = hydrateRoot$1;\n  exports.render = render;\n  exports.unmountComponentAtNode = unmountComponentAtNode;\n  exports.unstable_batchedUpdates = batchedUpdates$1;\n  exports.unstable_renderSubtreeIntoContainer = renderSubtreeIntoContainer;\n  exports.version = ReactVersion;\n\n})));"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/react.development.js",
    "content": "/**\n * @license React\n * react.development.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n(function (global, factory) {\n  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n  typeof define === 'function' && define.amd ? define(['exports'], factory) :\n  (global = global || self, factory(global.React = {}));\n}(this, (function (exports) { 'use strict';\n\n  var ReactVersion = '18.3.1';\n\n  // ATTENTION\n  // When adding new symbols to this file,\n  // Please consider also adding to 'react-devtools-shared/src/backend/ReactSymbols'\n  // The Symbol used to tag the ReactElement-like types.\n  var REACT_ELEMENT_TYPE = Symbol.for('react.element');\n  var REACT_PORTAL_TYPE = Symbol.for('react.portal');\n  var REACT_FRAGMENT_TYPE = Symbol.for('react.fragment');\n  var REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode');\n  var REACT_PROFILER_TYPE = Symbol.for('react.profiler');\n  var REACT_PROVIDER_TYPE = Symbol.for('react.provider');\n  var REACT_CONTEXT_TYPE = Symbol.for('react.context');\n  var REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref');\n  var REACT_SUSPENSE_TYPE = Symbol.for('react.suspense');\n  var REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list');\n  var REACT_MEMO_TYPE = Symbol.for('react.memo');\n  var REACT_LAZY_TYPE = Symbol.for('react.lazy');\n  var REACT_OFFSCREEN_TYPE = Symbol.for('react.offscreen');\n  var MAYBE_ITERATOR_SYMBOL = Symbol.iterator;\n  var FAUX_ITERATOR_SYMBOL = '@@iterator';\n  function getIteratorFn(maybeIterable) {\n    if (maybeIterable === null || typeof maybeIterable !== 'object') {\n      return null;\n    }\n\n    var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];\n\n    if (typeof maybeIterator === 'function') {\n      return maybeIterator;\n    }\n\n    return null;\n  }\n\n  /**\n   * Keeps track of the current dispatcher.\n   */\n  var ReactCurrentDispatcher = {\n    /**\n     * @internal\n     * @type {ReactComponent}\n     */\n    current: null\n  };\n\n  /**\n   * Keeps track of the current batch's configuration such as how long an update\n   * should suspend for if it needs to.\n   */\n  var ReactCurrentBatchConfig = {\n    transition: null\n  };\n\n  var ReactCurrentActQueue = {\n    current: null,\n    // Used to reproduce behavior of `batchedUpdates` in legacy mode.\n    isBatchingLegacy: false,\n    didScheduleLegacyUpdate: false\n  };\n\n  /**\n   * Keeps track of the current owner.\n   *\n   * The current owner is the component who should own any components that are\n   * currently being constructed.\n   */\n  var ReactCurrentOwner = {\n    /**\n     * @internal\n     * @type {ReactComponent}\n     */\n    current: null\n  };\n\n  var ReactDebugCurrentFrame = {};\n  var currentExtraStackFrame = null;\n  function setExtraStackFrame(stack) {\n    {\n      currentExtraStackFrame = stack;\n    }\n  }\n\n  {\n    ReactDebugCurrentFrame.setExtraStackFrame = function (stack) {\n      {\n        currentExtraStackFrame = stack;\n      }\n    }; // Stack implementation injected by the current renderer.\n\n\n    ReactDebugCurrentFrame.getCurrentStack = null;\n\n    ReactDebugCurrentFrame.getStackAddendum = function () {\n      var stack = ''; // Add an extra top frame while an element is being validated\n\n      if (currentExtraStackFrame) {\n        stack += currentExtraStackFrame;\n      } // Delegate to the injected renderer-specific implementation\n\n\n      var impl = ReactDebugCurrentFrame.getCurrentStack;\n\n      if (impl) {\n        stack += impl() || '';\n      }\n\n      return stack;\n    };\n  }\n\n  // -----------------------------------------------------------------------------\n\n  var enableScopeAPI = false; // Experimental Create Event Handle API.\n  var enableCacheElement = false;\n  var enableTransitionTracing = false; // No known bugs, but needs performance testing\n\n  var enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber\n  // stuff. Intended to enable React core members to more easily debug scheduling\n  // issues in DEV builds.\n\n  var enableDebugTracing = false; // Track which Fiber(s) schedule render work.\n\n  var ReactSharedInternals = {\n    ReactCurrentDispatcher: ReactCurrentDispatcher,\n    ReactCurrentBatchConfig: ReactCurrentBatchConfig,\n    ReactCurrentOwner: ReactCurrentOwner\n  };\n\n  {\n    ReactSharedInternals.ReactDebugCurrentFrame = ReactDebugCurrentFrame;\n    ReactSharedInternals.ReactCurrentActQueue = ReactCurrentActQueue;\n  }\n\n  // by calls to these methods by a Babel plugin.\n  //\n  // In PROD (or in packages without access to React internals),\n  // they are left as they are instead.\n\n  function warn(format) {\n    {\n      {\n        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n          args[_key - 1] = arguments[_key];\n        }\n\n        printWarning('warn', format, args);\n      }\n    }\n  }\n  function error(format) {\n    {\n      {\n        for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n          args[_key2 - 1] = arguments[_key2];\n        }\n\n        printWarning('error', format, args);\n      }\n    }\n  }\n\n  function printWarning(level, format, args) {\n    // When changing this logic, you might want to also\n    // update consoleWithStackDev.www.js as well.\n    {\n      var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame;\n      var stack = ReactDebugCurrentFrame.getStackAddendum();\n\n      if (stack !== '') {\n        format += '%s';\n        args = args.concat([stack]);\n      } // eslint-disable-next-line react-internal/safe-string-coercion\n\n\n      var argsWithFormat = args.map(function (item) {\n        return String(item);\n      }); // Careful: RN currently depends on this prefix\n\n      argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it\n      // breaks IE9: https://github.com/facebook/react/issues/13610\n      // eslint-disable-next-line react-internal/no-production-logging\n\n      Function.prototype.apply.call(console[level], console, argsWithFormat);\n    }\n  }\n\n  var didWarnStateUpdateForUnmountedComponent = {};\n\n  function warnNoop(publicInstance, callerName) {\n    {\n      var _constructor = publicInstance.constructor;\n      var componentName = _constructor && (_constructor.displayName || _constructor.name) || 'ReactClass';\n      var warningKey = componentName + \".\" + callerName;\n\n      if (didWarnStateUpdateForUnmountedComponent[warningKey]) {\n        return;\n      }\n\n      error(\"Can't call %s on a component that is not yet mounted. \" + 'This is a no-op, but it might indicate a bug in your application. ' + 'Instead, assign to `this.state` directly or define a `state = {};` ' + 'class property with the desired state in the %s component.', callerName, componentName);\n\n      didWarnStateUpdateForUnmountedComponent[warningKey] = true;\n    }\n  }\n  /**\n   * This is the abstract API for an update queue.\n   */\n\n\n  var ReactNoopUpdateQueue = {\n    /**\n     * Checks whether or not this composite component is mounted.\n     * @param {ReactClass} publicInstance The instance we want to test.\n     * @return {boolean} True if mounted, false otherwise.\n     * @protected\n     * @final\n     */\n    isMounted: function (publicInstance) {\n      return false;\n    },\n\n    /**\n     * Forces an update. This should only be invoked when it is known with\n     * certainty that we are **not** in a DOM transaction.\n     *\n     * You may want to call this when you know that some deeper aspect of the\n     * component's state has changed but `setState` was not called.\n     *\n     * This will not invoke `shouldComponentUpdate`, but it will invoke\n     * `componentWillUpdate` and `componentDidUpdate`.\n     *\n     * @param {ReactClass} publicInstance The instance that should rerender.\n     * @param {?function} callback Called after component is updated.\n     * @param {?string} callerName name of the calling function in the public API.\n     * @internal\n     */\n    enqueueForceUpdate: function (publicInstance, callback, callerName) {\n      warnNoop(publicInstance, 'forceUpdate');\n    },\n\n    /**\n     * Replaces all of the state. Always use this or `setState` to mutate state.\n     * You should treat `this.state` as immutable.\n     *\n     * There is no guarantee that `this.state` will be immediately updated, so\n     * accessing `this.state` after calling this method may return the old value.\n     *\n     * @param {ReactClass} publicInstance The instance that should rerender.\n     * @param {object} completeState Next state.\n     * @param {?function} callback Called after component is updated.\n     * @param {?string} callerName name of the calling function in the public API.\n     * @internal\n     */\n    enqueueReplaceState: function (publicInstance, completeState, callback, callerName) {\n      warnNoop(publicInstance, 'replaceState');\n    },\n\n    /**\n     * Sets a subset of the state. This only exists because _pendingState is\n     * internal. This provides a merging strategy that is not available to deep\n     * properties which is confusing. TODO: Expose pendingState or don't use it\n     * during the merge.\n     *\n     * @param {ReactClass} publicInstance The instance that should rerender.\n     * @param {object} partialState Next partial state to be merged with state.\n     * @param {?function} callback Called after component is updated.\n     * @param {?string} Name of the calling function in the public API.\n     * @internal\n     */\n    enqueueSetState: function (publicInstance, partialState, callback, callerName) {\n      warnNoop(publicInstance, 'setState');\n    }\n  };\n\n  var assign = Object.assign;\n\n  var emptyObject = {};\n\n  {\n    Object.freeze(emptyObject);\n  }\n  /**\n   * Base class helpers for the updating state of a component.\n   */\n\n\n  function Component(props, context, updater) {\n    this.props = props;\n    this.context = context; // If a component has string refs, we will assign a different object later.\n\n    this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the\n    // renderer.\n\n    this.updater = updater || ReactNoopUpdateQueue;\n  }\n\n  Component.prototype.isReactComponent = {};\n  /**\n   * Sets a subset of the state. Always use this to mutate\n   * state. You should treat `this.state` as immutable.\n   *\n   * There is no guarantee that `this.state` will be immediately updated, so\n   * accessing `this.state` after calling this method may return the old value.\n   *\n   * There is no guarantee that calls to `setState` will run synchronously,\n   * as they may eventually be batched together.  You can provide an optional\n   * callback that will be executed when the call to setState is actually\n   * completed.\n   *\n   * When a function is provided to setState, it will be called at some point in\n   * the future (not synchronously). It will be called with the up to date\n   * component arguments (state, props, context). These values can be different\n   * from this.* because your function may be called after receiveProps but before\n   * shouldComponentUpdate, and this new state, props, and context will not yet be\n   * assigned to this.\n   *\n   * @param {object|function} partialState Next partial state or function to\n   *        produce next partial state to be merged with current state.\n   * @param {?function} callback Called after state is updated.\n   * @final\n   * @protected\n   */\n\n  Component.prototype.setState = function (partialState, callback) {\n    if (typeof partialState !== 'object' && typeof partialState !== 'function' && partialState != null) {\n      throw new Error('setState(...): takes an object of state variables to update or a ' + 'function which returns an object of state variables.');\n    }\n\n    this.updater.enqueueSetState(this, partialState, callback, 'setState');\n  };\n  /**\n   * Forces an update. This should only be invoked when it is known with\n   * certainty that we are **not** in a DOM transaction.\n   *\n   * You may want to call this when you know that some deeper aspect of the\n   * component's state has changed but `setState` was not called.\n   *\n   * This will not invoke `shouldComponentUpdate`, but it will invoke\n   * `componentWillUpdate` and `componentDidUpdate`.\n   *\n   * @param {?function} callback Called after update is complete.\n   * @final\n   * @protected\n   */\n\n\n  Component.prototype.forceUpdate = function (callback) {\n    this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');\n  };\n  /**\n   * Deprecated APIs. These APIs used to exist on classic React classes but since\n   * we would like to deprecate them, we're not going to move them over to this\n   * modern base class. Instead, we define a getter that warns if it's accessed.\n   */\n\n\n  {\n    var deprecatedAPIs = {\n      isMounted: ['isMounted', 'Instead, make sure to clean up subscriptions and pending requests in ' + 'componentWillUnmount to prevent memory leaks.'],\n      replaceState: ['replaceState', 'Refactor your code to use setState instead (see ' + 'https://github.com/facebook/react/issues/3236).']\n    };\n\n    var defineDeprecationWarning = function (methodName, info) {\n      Object.defineProperty(Component.prototype, methodName, {\n        get: function () {\n          warn('%s(...) is deprecated in plain JavaScript React classes. %s', info[0], info[1]);\n\n          return undefined;\n        }\n      });\n    };\n\n    for (var fnName in deprecatedAPIs) {\n      if (deprecatedAPIs.hasOwnProperty(fnName)) {\n        defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);\n      }\n    }\n  }\n\n  function ComponentDummy() {}\n\n  ComponentDummy.prototype = Component.prototype;\n  /**\n   * Convenience component with default shallow equality check for sCU.\n   */\n\n  function PureComponent(props, context, updater) {\n    this.props = props;\n    this.context = context; // If a component has string refs, we will assign a different object later.\n\n    this.refs = emptyObject;\n    this.updater = updater || ReactNoopUpdateQueue;\n  }\n\n  var pureComponentPrototype = PureComponent.prototype = new ComponentDummy();\n  pureComponentPrototype.constructor = PureComponent; // Avoid an extra prototype jump for these methods.\n\n  assign(pureComponentPrototype, Component.prototype);\n  pureComponentPrototype.isPureReactComponent = true;\n\n  // an immutable object with a single mutable value\n  function createRef() {\n    var refObject = {\n      current: null\n    };\n\n    {\n      Object.seal(refObject);\n    }\n\n    return refObject;\n  }\n\n  var isArrayImpl = Array.isArray; // eslint-disable-next-line no-redeclare\n\n  function isArray(a) {\n    return isArrayImpl(a);\n  }\n\n  /*\n   * The `'' + value` pattern (used in in perf-sensitive code) throws for Symbol\n   * and Temporal.* types. See https://github.com/facebook/react/pull/22064.\n   *\n   * The functions in this module will throw an easier-to-understand,\n   * easier-to-debug exception with a clear errors message message explaining the\n   * problem. (Instead of a confusing exception thrown inside the implementation\n   * of the `value` object).\n   */\n  // $FlowFixMe only called in DEV, so void return is not possible.\n  function typeName(value) {\n    {\n      // toStringTag is needed for namespaced types like Temporal.Instant\n      var hasToStringTag = typeof Symbol === 'function' && Symbol.toStringTag;\n      var type = hasToStringTag && value[Symbol.toStringTag] || value.constructor.name || 'Object';\n      return type;\n    }\n  } // $FlowFixMe only called in DEV, so void return is not possible.\n\n\n  function willCoercionThrow(value) {\n    {\n      try {\n        testStringCoercion(value);\n        return false;\n      } catch (e) {\n        return true;\n      }\n    }\n  }\n\n  function testStringCoercion(value) {\n    // If you ended up here by following an exception call stack, here's what's\n    // happened: you supplied an object or symbol value to React (as a prop, key,\n    // DOM attribute, CSS property, string ref, etc.) and when React tried to\n    // coerce it to a string using `'' + value`, an exception was thrown.\n    //\n    // The most common types that will cause this exception are `Symbol` instances\n    // and Temporal objects like `Temporal.Instant`. But any object that has a\n    // `valueOf` or `[Symbol.toPrimitive]` method that throws will also cause this\n    // exception. (Library authors do this to prevent users from using built-in\n    // numeric operators like `+` or comparison operators like `>=` because custom\n    // methods are needed to perform accurate arithmetic or comparison.)\n    //\n    // To fix the problem, coerce this object or symbol value to a string before\n    // passing it to React. The most reliable way is usually `String(value)`.\n    //\n    // To find which value is throwing, check the browser or debugger console.\n    // Before this exception was thrown, there should be `console.error` output\n    // that shows the type (Symbol, Temporal.PlainDate, etc.) that caused the\n    // problem and how that type was used: key, atrribute, input value prop, etc.\n    // In most cases, this console output also shows the component and its\n    // ancestor components where the exception happened.\n    //\n    // eslint-disable-next-line react-internal/safe-string-coercion\n    return '' + value;\n  }\n  function checkKeyStringCoercion(value) {\n    {\n      if (willCoercionThrow(value)) {\n        error('The provided key is an unsupported type %s.' + ' This value must be coerced to a string before before using it here.', typeName(value));\n\n        return testStringCoercion(value); // throw (to help callers find troubleshooting comments)\n      }\n    }\n  }\n\n  function getWrappedName(outerType, innerType, wrapperName) {\n    var displayName = outerType.displayName;\n\n    if (displayName) {\n      return displayName;\n    }\n\n    var functionName = innerType.displayName || innerType.name || '';\n    return functionName !== '' ? wrapperName + \"(\" + functionName + \")\" : wrapperName;\n  } // Keep in sync with react-reconciler/getComponentNameFromFiber\n\n\n  function getContextName(type) {\n    return type.displayName || 'Context';\n  } // Note that the reconciler package should generally prefer to use getComponentNameFromFiber() instead.\n\n\n  function getComponentNameFromType(type) {\n    if (type == null) {\n      // Host root, text node or just invalid type.\n      return null;\n    }\n\n    {\n      if (typeof type.tag === 'number') {\n        error('Received an unexpected object in getComponentNameFromType(). ' + 'This is likely a bug in React. Please file an issue.');\n      }\n    }\n\n    if (typeof type === 'function') {\n      return type.displayName || type.name || null;\n    }\n\n    if (typeof type === 'string') {\n      return type;\n    }\n\n    switch (type) {\n      case REACT_FRAGMENT_TYPE:\n        return 'Fragment';\n\n      case REACT_PORTAL_TYPE:\n        return 'Portal';\n\n      case REACT_PROFILER_TYPE:\n        return 'Profiler';\n\n      case REACT_STRICT_MODE_TYPE:\n        return 'StrictMode';\n\n      case REACT_SUSPENSE_TYPE:\n        return 'Suspense';\n\n      case REACT_SUSPENSE_LIST_TYPE:\n        return 'SuspenseList';\n\n    }\n\n    if (typeof type === 'object') {\n      switch (type.$$typeof) {\n        case REACT_CONTEXT_TYPE:\n          var context = type;\n          return getContextName(context) + '.Consumer';\n\n        case REACT_PROVIDER_TYPE:\n          var provider = type;\n          return getContextName(provider._context) + '.Provider';\n\n        case REACT_FORWARD_REF_TYPE:\n          return getWrappedName(type, type.render, 'ForwardRef');\n\n        case REACT_MEMO_TYPE:\n          var outerName = type.displayName || null;\n\n          if (outerName !== null) {\n            return outerName;\n          }\n\n          return getComponentNameFromType(type.type) || 'Memo';\n\n        case REACT_LAZY_TYPE:\n          {\n            var lazyComponent = type;\n            var payload = lazyComponent._payload;\n            var init = lazyComponent._init;\n\n            try {\n              return getComponentNameFromType(init(payload));\n            } catch (x) {\n              return null;\n            }\n          }\n\n        // eslint-disable-next-line no-fallthrough\n      }\n    }\n\n    return null;\n  }\n\n  var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n  var RESERVED_PROPS = {\n    key: true,\n    ref: true,\n    __self: true,\n    __source: true\n  };\n  var specialPropKeyWarningShown, specialPropRefWarningShown, didWarnAboutStringRefs;\n\n  {\n    didWarnAboutStringRefs = {};\n  }\n\n  function hasValidRef(config) {\n    {\n      if (hasOwnProperty.call(config, 'ref')) {\n        var getter = Object.getOwnPropertyDescriptor(config, 'ref').get;\n\n        if (getter && getter.isReactWarning) {\n          return false;\n        }\n      }\n    }\n\n    return config.ref !== undefined;\n  }\n\n  function hasValidKey(config) {\n    {\n      if (hasOwnProperty.call(config, 'key')) {\n        var getter = Object.getOwnPropertyDescriptor(config, 'key').get;\n\n        if (getter && getter.isReactWarning) {\n          return false;\n        }\n      }\n    }\n\n    return config.key !== undefined;\n  }\n\n  function defineKeyPropWarningGetter(props, displayName) {\n    var warnAboutAccessingKey = function () {\n      {\n        if (!specialPropKeyWarningShown) {\n          specialPropKeyWarningShown = true;\n\n          error('%s: `key` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://reactjs.org/link/special-props)', displayName);\n        }\n      }\n    };\n\n    warnAboutAccessingKey.isReactWarning = true;\n    Object.defineProperty(props, 'key', {\n      get: warnAboutAccessingKey,\n      configurable: true\n    });\n  }\n\n  function defineRefPropWarningGetter(props, displayName) {\n    var warnAboutAccessingRef = function () {\n      {\n        if (!specialPropRefWarningShown) {\n          specialPropRefWarningShown = true;\n\n          error('%s: `ref` is not a prop. Trying to access it will result ' + 'in `undefined` being returned. If you need to access the same ' + 'value within the child component, you should pass it as a different ' + 'prop. (https://reactjs.org/link/special-props)', displayName);\n        }\n      }\n    };\n\n    warnAboutAccessingRef.isReactWarning = true;\n    Object.defineProperty(props, 'ref', {\n      get: warnAboutAccessingRef,\n      configurable: true\n    });\n  }\n\n  function warnIfStringRefCannotBeAutoConverted(config) {\n    {\n      if (typeof config.ref === 'string' && ReactCurrentOwner.current && config.__self && ReactCurrentOwner.current.stateNode !== config.__self) {\n        var componentName = getComponentNameFromType(ReactCurrentOwner.current.type);\n\n        if (!didWarnAboutStringRefs[componentName]) {\n          error('Component \"%s\" contains the string ref \"%s\". ' + 'Support for string refs will be removed in a future major release. ' + 'This case cannot be automatically converted to an arrow function. ' + 'We ask you to manually fix this case by using useRef() or createRef() instead. ' + 'Learn more about using refs safely here: ' + 'https://reactjs.org/link/strict-mode-string-ref', componentName, config.ref);\n\n          didWarnAboutStringRefs[componentName] = true;\n        }\n      }\n    }\n  }\n  /**\n   * Factory method to create a new React element. This no longer adheres to\n   * the class pattern, so do not use new to call it. Also, instanceof check\n   * will not work. Instead test $$typeof field against Symbol.for('react.element') to check\n   * if something is a React Element.\n   *\n   * @param {*} type\n   * @param {*} props\n   * @param {*} key\n   * @param {string|object} ref\n   * @param {*} owner\n   * @param {*} self A *temporary* helper to detect places where `this` is\n   * different from the `owner` when React.createElement is called, so that we\n   * can warn. We want to get rid of owner and replace string `ref`s with arrow\n   * functions, and as long as `this` and owner are the same, there will be no\n   * change in behavior.\n   * @param {*} source An annotation object (added by a transpiler or otherwise)\n   * indicating filename, line number, and/or other information.\n   * @internal\n   */\n\n\n  var ReactElement = function (type, key, ref, self, source, owner, props) {\n    var element = {\n      // This tag allows us to uniquely identify this as a React Element\n      $$typeof: REACT_ELEMENT_TYPE,\n      // Built-in properties that belong on the element\n      type: type,\n      key: key,\n      ref: ref,\n      props: props,\n      // Record the component responsible for creating this element.\n      _owner: owner\n    };\n\n    {\n      // The validation flag is currently mutative. We put it on\n      // an external backing store so that we can freeze the whole object.\n      // This can be replaced with a WeakMap once they are implemented in\n      // commonly used development environments.\n      element._store = {}; // To make comparing ReactElements easier for testing purposes, we make\n      // the validation flag non-enumerable (where possible, which should\n      // include every environment we run tests in), so the test framework\n      // ignores it.\n\n      Object.defineProperty(element._store, 'validated', {\n        configurable: false,\n        enumerable: false,\n        writable: true,\n        value: false\n      }); // self and source are DEV only properties.\n\n      Object.defineProperty(element, '_self', {\n        configurable: false,\n        enumerable: false,\n        writable: false,\n        value: self\n      }); // Two elements created in two different places should be considered\n      // equal for testing purposes and therefore we hide it from enumeration.\n\n      Object.defineProperty(element, '_source', {\n        configurable: false,\n        enumerable: false,\n        writable: false,\n        value: source\n      });\n\n      if (Object.freeze) {\n        Object.freeze(element.props);\n        Object.freeze(element);\n      }\n    }\n\n    return element;\n  };\n  /**\n   * Create and return a new ReactElement of the given type.\n   * See https://reactjs.org/docs/react-api.html#createelement\n   */\n\n  function createElement(type, config, children) {\n    var propName; // Reserved names are extracted\n\n    var props = {};\n    var key = null;\n    var ref = null;\n    var self = null;\n    var source = null;\n\n    if (config != null) {\n      if (hasValidRef(config)) {\n        ref = config.ref;\n\n        {\n          warnIfStringRefCannotBeAutoConverted(config);\n        }\n      }\n\n      if (hasValidKey(config)) {\n        {\n          checkKeyStringCoercion(config.key);\n        }\n\n        key = '' + config.key;\n      }\n\n      self = config.__self === undefined ? null : config.__self;\n      source = config.__source === undefined ? null : config.__source; // Remaining properties are added to a new props object\n\n      for (propName in config) {\n        if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {\n          props[propName] = config[propName];\n        }\n      }\n    } // Children can be more than one argument, and those are transferred onto\n    // the newly allocated props object.\n\n\n    var childrenLength = arguments.length - 2;\n\n    if (childrenLength === 1) {\n      props.children = children;\n    } else if (childrenLength > 1) {\n      var childArray = Array(childrenLength);\n\n      for (var i = 0; i < childrenLength; i++) {\n        childArray[i] = arguments[i + 2];\n      }\n\n      {\n        if (Object.freeze) {\n          Object.freeze(childArray);\n        }\n      }\n\n      props.children = childArray;\n    } // Resolve default props\n\n\n    if (type && type.defaultProps) {\n      var defaultProps = type.defaultProps;\n\n      for (propName in defaultProps) {\n        if (props[propName] === undefined) {\n          props[propName] = defaultProps[propName];\n        }\n      }\n    }\n\n    {\n      if (key || ref) {\n        var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;\n\n        if (key) {\n          defineKeyPropWarningGetter(props, displayName);\n        }\n\n        if (ref) {\n          defineRefPropWarningGetter(props, displayName);\n        }\n      }\n    }\n\n    return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);\n  }\n  function cloneAndReplaceKey(oldElement, newKey) {\n    var newElement = ReactElement(oldElement.type, newKey, oldElement.ref, oldElement._self, oldElement._source, oldElement._owner, oldElement.props);\n    return newElement;\n  }\n  /**\n   * Clone and return a new ReactElement using element as the starting point.\n   * See https://reactjs.org/docs/react-api.html#cloneelement\n   */\n\n  function cloneElement(element, config, children) {\n    if (element === null || element === undefined) {\n      throw new Error(\"React.cloneElement(...): The argument must be a React element, but you passed \" + element + \".\");\n    }\n\n    var propName; // Original props are copied\n\n    var props = assign({}, element.props); // Reserved names are extracted\n\n    var key = element.key;\n    var ref = element.ref; // Self is preserved since the owner is preserved.\n\n    var self = element._self; // Source is preserved since cloneElement is unlikely to be targeted by a\n    // transpiler, and the original source is probably a better indicator of the\n    // true owner.\n\n    var source = element._source; // Owner will be preserved, unless ref is overridden\n\n    var owner = element._owner;\n\n    if (config != null) {\n      if (hasValidRef(config)) {\n        // Silently steal the ref from the parent.\n        ref = config.ref;\n        owner = ReactCurrentOwner.current;\n      }\n\n      if (hasValidKey(config)) {\n        {\n          checkKeyStringCoercion(config.key);\n        }\n\n        key = '' + config.key;\n      } // Remaining properties override existing props\n\n\n      var defaultProps;\n\n      if (element.type && element.type.defaultProps) {\n        defaultProps = element.type.defaultProps;\n      }\n\n      for (propName in config) {\n        if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {\n          if (config[propName] === undefined && defaultProps !== undefined) {\n            // Resolve default props\n            props[propName] = defaultProps[propName];\n          } else {\n            props[propName] = config[propName];\n          }\n        }\n      }\n    } // Children can be more than one argument, and those are transferred onto\n    // the newly allocated props object.\n\n\n    var childrenLength = arguments.length - 2;\n\n    if (childrenLength === 1) {\n      props.children = children;\n    } else if (childrenLength > 1) {\n      var childArray = Array(childrenLength);\n\n      for (var i = 0; i < childrenLength; i++) {\n        childArray[i] = arguments[i + 2];\n      }\n\n      props.children = childArray;\n    }\n\n    return ReactElement(element.type, key, ref, self, source, owner, props);\n  }\n  /**\n   * Verifies the object is a ReactElement.\n   * See https://reactjs.org/docs/react-api.html#isvalidelement\n   * @param {?object} object\n   * @return {boolean} True if `object` is a ReactElement.\n   * @final\n   */\n\n  function isValidElement(object) {\n    return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;\n  }\n\n  var SEPARATOR = '.';\n  var SUBSEPARATOR = ':';\n  /**\n   * Escape and wrap key so it is safe to use as a reactid\n   *\n   * @param {string} key to be escaped.\n   * @return {string} the escaped key.\n   */\n\n  function escape(key) {\n    var escapeRegex = /[=:]/g;\n    var escaperLookup = {\n      '=': '=0',\n      ':': '=2'\n    };\n    var escapedString = key.replace(escapeRegex, function (match) {\n      return escaperLookup[match];\n    });\n    return '$' + escapedString;\n  }\n  /**\n   * TODO: Test that a single child and an array with one item have the same key\n   * pattern.\n   */\n\n\n  var didWarnAboutMaps = false;\n  var userProvidedKeyEscapeRegex = /\\/+/g;\n\n  function escapeUserProvidedKey(text) {\n    return text.replace(userProvidedKeyEscapeRegex, '$&/');\n  }\n  /**\n   * Generate a key string that identifies a element within a set.\n   *\n   * @param {*} element A element that could contain a manual key.\n   * @param {number} index Index that is used if a manual key is not provided.\n   * @return {string}\n   */\n\n\n  function getElementKey(element, index) {\n    // Do some typechecking here since we call this blindly. We want to ensure\n    // that we don't block potential future ES APIs.\n    if (typeof element === 'object' && element !== null && element.key != null) {\n      // Explicit key\n      {\n        checkKeyStringCoercion(element.key);\n      }\n\n      return escape('' + element.key);\n    } // Implicit key determined by the index in the set\n\n\n    return index.toString(36);\n  }\n\n  function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) {\n    var type = typeof children;\n\n    if (type === 'undefined' || type === 'boolean') {\n      // All of the above are perceived as null.\n      children = null;\n    }\n\n    var invokeCallback = false;\n\n    if (children === null) {\n      invokeCallback = true;\n    } else {\n      switch (type) {\n        case 'string':\n        case 'number':\n          invokeCallback = true;\n          break;\n\n        case 'object':\n          switch (children.$$typeof) {\n            case REACT_ELEMENT_TYPE:\n            case REACT_PORTAL_TYPE:\n              invokeCallback = true;\n          }\n\n      }\n    }\n\n    if (invokeCallback) {\n      var _child = children;\n      var mappedChild = callback(_child); // If it's the only child, treat the name as if it was wrapped in an array\n      // so that it's consistent if the number of children grows:\n\n      var childKey = nameSoFar === '' ? SEPARATOR + getElementKey(_child, 0) : nameSoFar;\n\n      if (isArray(mappedChild)) {\n        var escapedChildKey = '';\n\n        if (childKey != null) {\n          escapedChildKey = escapeUserProvidedKey(childKey) + '/';\n        }\n\n        mapIntoArray(mappedChild, array, escapedChildKey, '', function (c) {\n          return c;\n        });\n      } else if (mappedChild != null) {\n        if (isValidElement(mappedChild)) {\n          {\n            // The `if` statement here prevents auto-disabling of the safe\n            // coercion ESLint rule, so we must manually disable it below.\n            // $FlowFixMe Flow incorrectly thinks React.Portal doesn't have a key\n            if (mappedChild.key && (!_child || _child.key !== mappedChild.key)) {\n              checkKeyStringCoercion(mappedChild.key);\n            }\n          }\n\n          mappedChild = cloneAndReplaceKey(mappedChild, // Keep both the (mapped) and old keys if they differ, just as\n          // traverseAllChildren used to do for objects as children\n          escapedPrefix + ( // $FlowFixMe Flow incorrectly thinks React.Portal doesn't have a key\n          mappedChild.key && (!_child || _child.key !== mappedChild.key) ? // $FlowFixMe Flow incorrectly thinks existing element's key can be a number\n          // eslint-disable-next-line react-internal/safe-string-coercion\n          escapeUserProvidedKey('' + mappedChild.key) + '/' : '') + childKey);\n        }\n\n        array.push(mappedChild);\n      }\n\n      return 1;\n    }\n\n    var child;\n    var nextName;\n    var subtreeCount = 0; // Count of children found in the current subtree.\n\n    var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;\n\n    if (isArray(children)) {\n      for (var i = 0; i < children.length; i++) {\n        child = children[i];\n        nextName = nextNamePrefix + getElementKey(child, i);\n        subtreeCount += mapIntoArray(child, array, escapedPrefix, nextName, callback);\n      }\n    } else {\n      var iteratorFn = getIteratorFn(children);\n\n      if (typeof iteratorFn === 'function') {\n        var iterableChildren = children;\n\n        {\n          // Warn about using Maps as children\n          if (iteratorFn === iterableChildren.entries) {\n            if (!didWarnAboutMaps) {\n              warn('Using Maps as children is not supported. ' + 'Use an array of keyed ReactElements instead.');\n            }\n\n            didWarnAboutMaps = true;\n          }\n        }\n\n        var iterator = iteratorFn.call(iterableChildren);\n        var step;\n        var ii = 0;\n\n        while (!(step = iterator.next()).done) {\n          child = step.value;\n          nextName = nextNamePrefix + getElementKey(child, ii++);\n          subtreeCount += mapIntoArray(child, array, escapedPrefix, nextName, callback);\n        }\n      } else if (type === 'object') {\n        // eslint-disable-next-line react-internal/safe-string-coercion\n        var childrenString = String(children);\n        throw new Error(\"Objects are not valid as a React child (found: \" + (childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString) + \"). \" + 'If you meant to render a collection of children, use an array ' + 'instead.');\n      }\n    }\n\n    return subtreeCount;\n  }\n\n  /**\n   * Maps children that are typically specified as `props.children`.\n   *\n   * See https://reactjs.org/docs/react-api.html#reactchildrenmap\n   *\n   * The provided mapFunction(child, index) will be called for each\n   * leaf child.\n   *\n   * @param {?*} children Children tree container.\n   * @param {function(*, int)} func The map function.\n   * @param {*} context Context for mapFunction.\n   * @return {object} Object containing the ordered map of results.\n   */\n  function mapChildren(children, func, context) {\n    if (children == null) {\n      return children;\n    }\n\n    var result = [];\n    var count = 0;\n    mapIntoArray(children, result, '', '', function (child) {\n      return func.call(context, child, count++);\n    });\n    return result;\n  }\n  /**\n   * Count the number of children that are typically specified as\n   * `props.children`.\n   *\n   * See https://reactjs.org/docs/react-api.html#reactchildrencount\n   *\n   * @param {?*} children Children tree container.\n   * @return {number} The number of children.\n   */\n\n\n  function countChildren(children) {\n    var n = 0;\n    mapChildren(children, function () {\n      n++; // Don't return anything\n    });\n    return n;\n  }\n\n  /**\n   * Iterates through children that are typically specified as `props.children`.\n   *\n   * See https://reactjs.org/docs/react-api.html#reactchildrenforeach\n   *\n   * The provided forEachFunc(child, index) will be called for each\n   * leaf child.\n   *\n   * @param {?*} children Children tree container.\n   * @param {function(*, int)} forEachFunc\n   * @param {*} forEachContext Context for forEachContext.\n   */\n  function forEachChildren(children, forEachFunc, forEachContext) {\n    mapChildren(children, function () {\n      forEachFunc.apply(this, arguments); // Don't return anything.\n    }, forEachContext);\n  }\n  /**\n   * Flatten a children object (typically specified as `props.children`) and\n   * return an array with appropriately re-keyed children.\n   *\n   * See https://reactjs.org/docs/react-api.html#reactchildrentoarray\n   */\n\n\n  function toArray(children) {\n    return mapChildren(children, function (child) {\n      return child;\n    }) || [];\n  }\n  /**\n   * Returns the first child in a collection of children and verifies that there\n   * is only one child in the collection.\n   *\n   * See https://reactjs.org/docs/react-api.html#reactchildrenonly\n   *\n   * The current implementation of this function assumes that a single child gets\n   * passed without a wrapper, but the purpose of this helper function is to\n   * abstract away the particular structure of children.\n   *\n   * @param {?object} children Child collection structure.\n   * @return {ReactElement} The first and only `ReactElement` contained in the\n   * structure.\n   */\n\n\n  function onlyChild(children) {\n    if (!isValidElement(children)) {\n      throw new Error('React.Children.only expected to receive a single React element child.');\n    }\n\n    return children;\n  }\n\n  function createContext(defaultValue) {\n    // TODO: Second argument used to be an optional `calculateChangedBits`\n    // function. Warn to reserve for future use?\n    var context = {\n      $$typeof: REACT_CONTEXT_TYPE,\n      // As a workaround to support multiple concurrent renderers, we categorize\n      // some renderers as primary and others as secondary. We only expect\n      // there to be two concurrent renderers at most: React Native (primary) and\n      // Fabric (secondary); React DOM (primary) and React ART (secondary).\n      // Secondary renderers store their context values on separate fields.\n      _currentValue: defaultValue,\n      _currentValue2: defaultValue,\n      // Used to track how many concurrent renderers this context currently\n      // supports within in a single renderer. Such as parallel server rendering.\n      _threadCount: 0,\n      // These are circular\n      Provider: null,\n      Consumer: null,\n      // Add these to use same hidden class in VM as ServerContext\n      _defaultValue: null,\n      _globalName: null\n    };\n    context.Provider = {\n      $$typeof: REACT_PROVIDER_TYPE,\n      _context: context\n    };\n    var hasWarnedAboutUsingNestedContextConsumers = false;\n    var hasWarnedAboutUsingConsumerProvider = false;\n    var hasWarnedAboutDisplayNameOnConsumer = false;\n\n    {\n      // A separate object, but proxies back to the original context object for\n      // backwards compatibility. It has a different $$typeof, so we can properly\n      // warn for the incorrect usage of Context as a Consumer.\n      var Consumer = {\n        $$typeof: REACT_CONTEXT_TYPE,\n        _context: context\n      }; // $FlowFixMe: Flow complains about not setting a value, which is intentional here\n\n      Object.defineProperties(Consumer, {\n        Provider: {\n          get: function () {\n            if (!hasWarnedAboutUsingConsumerProvider) {\n              hasWarnedAboutUsingConsumerProvider = true;\n\n              error('Rendering <Context.Consumer.Provider> is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Provider> instead?');\n            }\n\n            return context.Provider;\n          },\n          set: function (_Provider) {\n            context.Provider = _Provider;\n          }\n        },\n        _currentValue: {\n          get: function () {\n            return context._currentValue;\n          },\n          set: function (_currentValue) {\n            context._currentValue = _currentValue;\n          }\n        },\n        _currentValue2: {\n          get: function () {\n            return context._currentValue2;\n          },\n          set: function (_currentValue2) {\n            context._currentValue2 = _currentValue2;\n          }\n        },\n        _threadCount: {\n          get: function () {\n            return context._threadCount;\n          },\n          set: function (_threadCount) {\n            context._threadCount = _threadCount;\n          }\n        },\n        Consumer: {\n          get: function () {\n            if (!hasWarnedAboutUsingNestedContextConsumers) {\n              hasWarnedAboutUsingNestedContextConsumers = true;\n\n              error('Rendering <Context.Consumer.Consumer> is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Consumer> instead?');\n            }\n\n            return context.Consumer;\n          }\n        },\n        displayName: {\n          get: function () {\n            return context.displayName;\n          },\n          set: function (displayName) {\n            if (!hasWarnedAboutDisplayNameOnConsumer) {\n              warn('Setting `displayName` on Context.Consumer has no effect. ' + \"You should set it directly on the context with Context.displayName = '%s'.\", displayName);\n\n              hasWarnedAboutDisplayNameOnConsumer = true;\n            }\n          }\n        }\n      }); // $FlowFixMe: Flow complains about missing properties because it doesn't understand defineProperty\n\n      context.Consumer = Consumer;\n    }\n\n    {\n      context._currentRenderer = null;\n      context._currentRenderer2 = null;\n    }\n\n    return context;\n  }\n\n  var Uninitialized = -1;\n  var Pending = 0;\n  var Resolved = 1;\n  var Rejected = 2;\n\n  function lazyInitializer(payload) {\n    if (payload._status === Uninitialized) {\n      var ctor = payload._result;\n      var thenable = ctor(); // Transition to the next state.\n      // This might throw either because it's missing or throws. If so, we treat it\n      // as still uninitialized and try again next time. Which is the same as what\n      // happens if the ctor or any wrappers processing the ctor throws. This might\n      // end up fixing it if the resolution was a concurrency bug.\n\n      thenable.then(function (moduleObject) {\n        if (payload._status === Pending || payload._status === Uninitialized) {\n          // Transition to the next state.\n          var resolved = payload;\n          resolved._status = Resolved;\n          resolved._result = moduleObject;\n        }\n      }, function (error) {\n        if (payload._status === Pending || payload._status === Uninitialized) {\n          // Transition to the next state.\n          var rejected = payload;\n          rejected._status = Rejected;\n          rejected._result = error;\n        }\n      });\n\n      if (payload._status === Uninitialized) {\n        // In case, we're still uninitialized, then we're waiting for the thenable\n        // to resolve. Set it as pending in the meantime.\n        var pending = payload;\n        pending._status = Pending;\n        pending._result = thenable;\n      }\n    }\n\n    if (payload._status === Resolved) {\n      var moduleObject = payload._result;\n\n      {\n        if (moduleObject === undefined) {\n          error('lazy: Expected the result of a dynamic imp' + 'ort() call. ' + 'Instead received: %s\\n\\nYour code should look like: \\n  ' + // Break up imports to avoid accidentally parsing them as dependencies.\n          'const MyComponent = lazy(() => imp' + \"ort('./MyComponent'))\\n\\n\" + 'Did you accidentally put curly braces around the import?', moduleObject);\n        }\n      }\n\n      {\n        if (!('default' in moduleObject)) {\n          error('lazy: Expected the result of a dynamic imp' + 'ort() call. ' + 'Instead received: %s\\n\\nYour code should look like: \\n  ' + // Break up imports to avoid accidentally parsing them as dependencies.\n          'const MyComponent = lazy(() => imp' + \"ort('./MyComponent'))\", moduleObject);\n        }\n      }\n\n      return moduleObject.default;\n    } else {\n      throw payload._result;\n    }\n  }\n\n  function lazy(ctor) {\n    var payload = {\n      // We use these fields to store the result.\n      _status: Uninitialized,\n      _result: ctor\n    };\n    var lazyType = {\n      $$typeof: REACT_LAZY_TYPE,\n      _payload: payload,\n      _init: lazyInitializer\n    };\n\n    {\n      // In production, this would just set it on the object.\n      var defaultProps;\n      var propTypes; // $FlowFixMe\n\n      Object.defineProperties(lazyType, {\n        defaultProps: {\n          configurable: true,\n          get: function () {\n            return defaultProps;\n          },\n          set: function (newDefaultProps) {\n            error('React.lazy(...): It is not supported to assign `defaultProps` to ' + 'a lazy component import. Either specify them where the component ' + 'is defined, or create a wrapping component around it.');\n\n            defaultProps = newDefaultProps; // Match production behavior more closely:\n            // $FlowFixMe\n\n            Object.defineProperty(lazyType, 'defaultProps', {\n              enumerable: true\n            });\n          }\n        },\n        propTypes: {\n          configurable: true,\n          get: function () {\n            return propTypes;\n          },\n          set: function (newPropTypes) {\n            error('React.lazy(...): It is not supported to assign `propTypes` to ' + 'a lazy component import. Either specify them where the component ' + 'is defined, or create a wrapping component around it.');\n\n            propTypes = newPropTypes; // Match production behavior more closely:\n            // $FlowFixMe\n\n            Object.defineProperty(lazyType, 'propTypes', {\n              enumerable: true\n            });\n          }\n        }\n      });\n    }\n\n    return lazyType;\n  }\n\n  function forwardRef(render) {\n    {\n      if (render != null && render.$$typeof === REACT_MEMO_TYPE) {\n        error('forwardRef requires a render function but received a `memo` ' + 'component. Instead of forwardRef(memo(...)), use ' + 'memo(forwardRef(...)).');\n      } else if (typeof render !== 'function') {\n        error('forwardRef requires a render function but was given %s.', render === null ? 'null' : typeof render);\n      } else {\n        if (render.length !== 0 && render.length !== 2) {\n          error('forwardRef render functions accept exactly two parameters: props and ref. %s', render.length === 1 ? 'Did you forget to use the ref parameter?' : 'Any additional parameter will be undefined.');\n        }\n      }\n\n      if (render != null) {\n        if (render.defaultProps != null || render.propTypes != null) {\n          error('forwardRef render functions do not support propTypes or defaultProps. ' + 'Did you accidentally pass a React component?');\n        }\n      }\n    }\n\n    var elementType = {\n      $$typeof: REACT_FORWARD_REF_TYPE,\n      render: render\n    };\n\n    {\n      var ownName;\n      Object.defineProperty(elementType, 'displayName', {\n        enumerable: false,\n        configurable: true,\n        get: function () {\n          return ownName;\n        },\n        set: function (name) {\n          ownName = name; // The inner component shouldn't inherit this display name in most cases,\n          // because the component may be used elsewhere.\n          // But it's nice for anonymous functions to inherit the name,\n          // so that our component-stack generation logic will display their frames.\n          // An anonymous function generally suggests a pattern like:\n          //   React.forwardRef((props, ref) => {...});\n          // This kind of inner function is not used elsewhere so the side effect is okay.\n\n          if (!render.name && !render.displayName) {\n            render.displayName = name;\n          }\n        }\n      });\n    }\n\n    return elementType;\n  }\n\n  var REACT_MODULE_REFERENCE;\n\n  {\n    REACT_MODULE_REFERENCE = Symbol.for('react.module.reference');\n  }\n\n  function isValidElementType(type) {\n    if (typeof type === 'string' || typeof type === 'function') {\n      return true;\n    } // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill).\n\n\n    if (type === REACT_FRAGMENT_TYPE || type === REACT_PROFILER_TYPE || enableDebugTracing  || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || enableLegacyHidden  || type === REACT_OFFSCREEN_TYPE || enableScopeAPI  || enableCacheElement  || enableTransitionTracing ) {\n      return true;\n    }\n\n    if (typeof type === 'object' && type !== null) {\n      if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || // This needs to include all possible module reference object\n      // types supported by any Flight configuration anywhere since\n      // we don't know which Flight build this will end up being used\n      // with.\n      type.$$typeof === REACT_MODULE_REFERENCE || type.getModuleId !== undefined) {\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  function memo(type, compare) {\n    {\n      if (!isValidElementType(type)) {\n        error('memo: The first argument must be a component. Instead ' + 'received: %s', type === null ? 'null' : typeof type);\n      }\n    }\n\n    var elementType = {\n      $$typeof: REACT_MEMO_TYPE,\n      type: type,\n      compare: compare === undefined ? null : compare\n    };\n\n    {\n      var ownName;\n      Object.defineProperty(elementType, 'displayName', {\n        enumerable: false,\n        configurable: true,\n        get: function () {\n          return ownName;\n        },\n        set: function (name) {\n          ownName = name; // The inner component shouldn't inherit this display name in most cases,\n          // because the component may be used elsewhere.\n          // But it's nice for anonymous functions to inherit the name,\n          // so that our component-stack generation logic will display their frames.\n          // An anonymous function generally suggests a pattern like:\n          //   React.memo((props) => {...});\n          // This kind of inner function is not used elsewhere so the side effect is okay.\n\n          if (!type.name && !type.displayName) {\n            type.displayName = name;\n          }\n        }\n      });\n    }\n\n    return elementType;\n  }\n\n  function resolveDispatcher() {\n    var dispatcher = ReactCurrentDispatcher.current;\n\n    {\n      if (dispatcher === null) {\n        error('Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + ' one of the following reasons:\\n' + '1. You might have mismatching versions of React and the renderer (such as React DOM)\\n' + '2. You might be breaking the Rules of Hooks\\n' + '3. You might have more than one copy of React in the same app\\n' + 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.');\n      }\n    } // Will result in a null access error if accessed outside render phase. We\n    // intentionally don't throw our own error because this is in a hot path.\n    // Also helps ensure this is inlined.\n\n\n    return dispatcher;\n  }\n  function useContext(Context) {\n    var dispatcher = resolveDispatcher();\n\n    {\n      // TODO: add a more generic warning for invalid values.\n      if (Context._context !== undefined) {\n        var realContext = Context._context; // Don't deduplicate because this legitimately causes bugs\n        // and nobody should be using this in existing code.\n\n        if (realContext.Consumer === Context) {\n          error('Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be ' + 'removed in a future major release. Did you mean to call useContext(Context) instead?');\n        } else if (realContext.Provider === Context) {\n          error('Calling useContext(Context.Provider) is not supported. ' + 'Did you mean to call useContext(Context) instead?');\n        }\n      }\n    }\n\n    return dispatcher.useContext(Context);\n  }\n  function useState(initialState) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useState(initialState);\n  }\n  function useReducer(reducer, initialArg, init) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useReducer(reducer, initialArg, init);\n  }\n  function useRef(initialValue) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useRef(initialValue);\n  }\n  function useEffect(create, deps) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useEffect(create, deps);\n  }\n  function useInsertionEffect(create, deps) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useInsertionEffect(create, deps);\n  }\n  function useLayoutEffect(create, deps) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useLayoutEffect(create, deps);\n  }\n  function useCallback(callback, deps) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useCallback(callback, deps);\n  }\n  function useMemo(create, deps) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useMemo(create, deps);\n  }\n  function useImperativeHandle(ref, create, deps) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useImperativeHandle(ref, create, deps);\n  }\n  function useDebugValue(value, formatterFn) {\n    {\n      var dispatcher = resolveDispatcher();\n      return dispatcher.useDebugValue(value, formatterFn);\n    }\n  }\n  function useTransition() {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useTransition();\n  }\n  function useDeferredValue(value) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useDeferredValue(value);\n  }\n  function useId() {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useId();\n  }\n  function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {\n    var dispatcher = resolveDispatcher();\n    return dispatcher.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n  }\n\n  // Helpers to patch console.logs to avoid logging during side-effect free\n  // replaying on render function. This currently only patches the object\n  // lazily which won't cover if the log function was extracted eagerly.\n  // We could also eagerly patch the method.\n  var disabledDepth = 0;\n  var prevLog;\n  var prevInfo;\n  var prevWarn;\n  var prevError;\n  var prevGroup;\n  var prevGroupCollapsed;\n  var prevGroupEnd;\n\n  function disabledLog() {}\n\n  disabledLog.__reactDisabledLog = true;\n  function disableLogs() {\n    {\n      if (disabledDepth === 0) {\n        /* eslint-disable react-internal/no-production-logging */\n        prevLog = console.log;\n        prevInfo = console.info;\n        prevWarn = console.warn;\n        prevError = console.error;\n        prevGroup = console.group;\n        prevGroupCollapsed = console.groupCollapsed;\n        prevGroupEnd = console.groupEnd; // https://github.com/facebook/react/issues/19099\n\n        var props = {\n          configurable: true,\n          enumerable: true,\n          value: disabledLog,\n          writable: true\n        }; // $FlowFixMe Flow thinks console is immutable.\n\n        Object.defineProperties(console, {\n          info: props,\n          log: props,\n          warn: props,\n          error: props,\n          group: props,\n          groupCollapsed: props,\n          groupEnd: props\n        });\n        /* eslint-enable react-internal/no-production-logging */\n      }\n\n      disabledDepth++;\n    }\n  }\n  function reenableLogs() {\n    {\n      disabledDepth--;\n\n      if (disabledDepth === 0) {\n        /* eslint-disable react-internal/no-production-logging */\n        var props = {\n          configurable: true,\n          enumerable: true,\n          writable: true\n        }; // $FlowFixMe Flow thinks console is immutable.\n\n        Object.defineProperties(console, {\n          log: assign({}, props, {\n            value: prevLog\n          }),\n          info: assign({}, props, {\n            value: prevInfo\n          }),\n          warn: assign({}, props, {\n            value: prevWarn\n          }),\n          error: assign({}, props, {\n            value: prevError\n          }),\n          group: assign({}, props, {\n            value: prevGroup\n          }),\n          groupCollapsed: assign({}, props, {\n            value: prevGroupCollapsed\n          }),\n          groupEnd: assign({}, props, {\n            value: prevGroupEnd\n          })\n        });\n        /* eslint-enable react-internal/no-production-logging */\n      }\n\n      if (disabledDepth < 0) {\n        error('disabledDepth fell below zero. ' + 'This is a bug in React. Please file an issue.');\n      }\n    }\n  }\n\n  var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher;\n  var prefix;\n  function describeBuiltInComponentFrame(name, source, ownerFn) {\n    {\n      if (prefix === undefined) {\n        // Extract the VM specific prefix used by each line.\n        try {\n          throw Error();\n        } catch (x) {\n          var match = x.stack.trim().match(/\\n( *(at )?)/);\n          prefix = match && match[1] || '';\n        }\n      } // We use the prefix to ensure our stacks line up with native stack frames.\n\n\n      return '\\n' + prefix + name;\n    }\n  }\n  var reentry = false;\n  var componentFrameCache;\n\n  {\n    var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;\n    componentFrameCache = new PossiblyWeakMap();\n  }\n\n  function describeNativeComponentFrame(fn, construct) {\n    // If something asked for a stack inside a fake render, it should get ignored.\n    if ( !fn || reentry) {\n      return '';\n    }\n\n    {\n      var frame = componentFrameCache.get(fn);\n\n      if (frame !== undefined) {\n        return frame;\n      }\n    }\n\n    var control;\n    reentry = true;\n    var previousPrepareStackTrace = Error.prepareStackTrace; // $FlowFixMe It does accept undefined.\n\n    Error.prepareStackTrace = undefined;\n    var previousDispatcher;\n\n    {\n      previousDispatcher = ReactCurrentDispatcher$1.current; // Set the dispatcher in DEV because this might be call in the render function\n      // for warnings.\n\n      ReactCurrentDispatcher$1.current = null;\n      disableLogs();\n    }\n\n    try {\n      // This should throw.\n      if (construct) {\n        // Something should be setting the props in the constructor.\n        var Fake = function () {\n          throw Error();\n        }; // $FlowFixMe\n\n\n        Object.defineProperty(Fake.prototype, 'props', {\n          set: function () {\n            // We use a throwing setter instead of frozen or non-writable props\n            // because that won't throw in a non-strict mode function.\n            throw Error();\n          }\n        });\n\n        if (typeof Reflect === 'object' && Reflect.construct) {\n          // We construct a different control for this case to include any extra\n          // frames added by the construct call.\n          try {\n            Reflect.construct(Fake, []);\n          } catch (x) {\n            control = x;\n          }\n\n          Reflect.construct(fn, [], Fake);\n        } else {\n          try {\n            Fake.call();\n          } catch (x) {\n            control = x;\n          }\n\n          fn.call(Fake.prototype);\n        }\n      } else {\n        try {\n          throw Error();\n        } catch (x) {\n          control = x;\n        }\n\n        fn();\n      }\n    } catch (sample) {\n      // This is inlined manually because closure doesn't do it for us.\n      if (sample && control && typeof sample.stack === 'string') {\n        // This extracts the first frame from the sample that isn't also in the control.\n        // Skipping one frame that we assume is the frame that calls the two.\n        var sampleLines = sample.stack.split('\\n');\n        var controlLines = control.stack.split('\\n');\n        var s = sampleLines.length - 1;\n        var c = controlLines.length - 1;\n\n        while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) {\n          // We expect at least one stack frame to be shared.\n          // Typically this will be the root most one. However, stack frames may be\n          // cut off due to maximum stack limits. In this case, one maybe cut off\n          // earlier than the other. We assume that the sample is longer or the same\n          // and there for cut off earlier. So we should find the root most frame in\n          // the sample somewhere in the control.\n          c--;\n        }\n\n        for (; s >= 1 && c >= 0; s--, c--) {\n          // Next we find the first one that isn't the same which should be the\n          // frame that called our sample function and the control.\n          if (sampleLines[s] !== controlLines[c]) {\n            // In V8, the first line is describing the message but other VMs don't.\n            // If we're about to return the first line, and the control is also on the same\n            // line, that's a pretty good indicator that our sample threw at same line as\n            // the control. I.e. before we entered the sample frame. So we ignore this result.\n            // This can happen if you passed a class to function component, or non-function.\n            if (s !== 1 || c !== 1) {\n              do {\n                s--;\n                c--; // We may still have similar intermediate frames from the construct call.\n                // The next one that isn't the same should be our match though.\n\n                if (c < 0 || sampleLines[s] !== controlLines[c]) {\n                  // V8 adds a \"new\" prefix for native classes. Let's remove it to make it prettier.\n                  var _frame = '\\n' + sampleLines[s].replace(' at new ', ' at '); // If our component frame is labeled \"<anonymous>\"\n                  // but we have a user-provided \"displayName\"\n                  // splice it in to make the stack more readable.\n\n\n                  if (fn.displayName && _frame.includes('<anonymous>')) {\n                    _frame = _frame.replace('<anonymous>', fn.displayName);\n                  }\n\n                  {\n                    if (typeof fn === 'function') {\n                      componentFrameCache.set(fn, _frame);\n                    }\n                  } // Return the line we found.\n\n\n                  return _frame;\n                }\n              } while (s >= 1 && c >= 0);\n            }\n\n            break;\n          }\n        }\n      }\n    } finally {\n      reentry = false;\n\n      {\n        ReactCurrentDispatcher$1.current = previousDispatcher;\n        reenableLogs();\n      }\n\n      Error.prepareStackTrace = previousPrepareStackTrace;\n    } // Fallback to just using the name if we couldn't make it throw.\n\n\n    var name = fn ? fn.displayName || fn.name : '';\n    var syntheticFrame = name ? describeBuiltInComponentFrame(name) : '';\n\n    {\n      if (typeof fn === 'function') {\n        componentFrameCache.set(fn, syntheticFrame);\n      }\n    }\n\n    return syntheticFrame;\n  }\n  function describeFunctionComponentFrame(fn, source, ownerFn) {\n    {\n      return describeNativeComponentFrame(fn, false);\n    }\n  }\n\n  function shouldConstruct(Component) {\n    var prototype = Component.prototype;\n    return !!(prototype && prototype.isReactComponent);\n  }\n\n  function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) {\n\n    if (type == null) {\n      return '';\n    }\n\n    if (typeof type === 'function') {\n      {\n        return describeNativeComponentFrame(type, shouldConstruct(type));\n      }\n    }\n\n    if (typeof type === 'string') {\n      return describeBuiltInComponentFrame(type);\n    }\n\n    switch (type) {\n      case REACT_SUSPENSE_TYPE:\n        return describeBuiltInComponentFrame('Suspense');\n\n      case REACT_SUSPENSE_LIST_TYPE:\n        return describeBuiltInComponentFrame('SuspenseList');\n    }\n\n    if (typeof type === 'object') {\n      switch (type.$$typeof) {\n        case REACT_FORWARD_REF_TYPE:\n          return describeFunctionComponentFrame(type.render);\n\n        case REACT_MEMO_TYPE:\n          // Memo may contain any component type so we recursively resolve it.\n          return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn);\n\n        case REACT_LAZY_TYPE:\n          {\n            var lazyComponent = type;\n            var payload = lazyComponent._payload;\n            var init = lazyComponent._init;\n\n            try {\n              // Lazy may contain any component type so we recursively resolve it.\n              return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn);\n            } catch (x) {}\n          }\n      }\n    }\n\n    return '';\n  }\n\n  var loggedTypeFailures = {};\n  var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame;\n\n  function setCurrentlyValidatingElement(element) {\n    {\n      if (element) {\n        var owner = element._owner;\n        var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);\n        ReactDebugCurrentFrame$1.setExtraStackFrame(stack);\n      } else {\n        ReactDebugCurrentFrame$1.setExtraStackFrame(null);\n      }\n    }\n  }\n\n  function checkPropTypes(typeSpecs, values, location, componentName, element) {\n    {\n      // $FlowFixMe This is okay but Flow doesn't know it.\n      var has = Function.call.bind(hasOwnProperty);\n\n      for (var typeSpecName in typeSpecs) {\n        if (has(typeSpecs, typeSpecName)) {\n          var error$1 = void 0; // Prop type validation may throw. In case they do, we don't want to\n          // fail the render phase where it didn't fail before. So we log it.\n          // After these have been cleaned up, we'll let them throw.\n\n          try {\n            // This is intentionally an invariant that gets caught. It's the same\n            // behavior as without this statement except with a better message.\n            if (typeof typeSpecs[typeSpecName] !== 'function') {\n              // eslint-disable-next-line react-internal/prod-error-codes\n              var err = Error((componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' + 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' + 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.');\n              err.name = 'Invariant Violation';\n              throw err;\n            }\n\n            error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED');\n          } catch (ex) {\n            error$1 = ex;\n          }\n\n          if (error$1 && !(error$1 instanceof Error)) {\n            setCurrentlyValidatingElement(element);\n\n            error('%s: type specification of %s' + ' `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error$1);\n\n            setCurrentlyValidatingElement(null);\n          }\n\n          if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) {\n            // Only monitor this failure once because there tends to be a lot of the\n            // same error.\n            loggedTypeFailures[error$1.message] = true;\n            setCurrentlyValidatingElement(element);\n\n            error('Failed %s type: %s', location, error$1.message);\n\n            setCurrentlyValidatingElement(null);\n          }\n        }\n      }\n    }\n  }\n\n  function setCurrentlyValidatingElement$1(element) {\n    {\n      if (element) {\n        var owner = element._owner;\n        var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null);\n        setExtraStackFrame(stack);\n      } else {\n        setExtraStackFrame(null);\n      }\n    }\n  }\n\n  var propTypesMisspellWarningShown;\n\n  {\n    propTypesMisspellWarningShown = false;\n  }\n\n  function getDeclarationErrorAddendum() {\n    if (ReactCurrentOwner.current) {\n      var name = getComponentNameFromType(ReactCurrentOwner.current.type);\n\n      if (name) {\n        return '\\n\\nCheck the render method of `' + name + '`.';\n      }\n    }\n\n    return '';\n  }\n\n  function getSourceInfoErrorAddendum(source) {\n    if (source !== undefined) {\n      var fileName = source.fileName.replace(/^.*[\\\\\\/]/, '');\n      var lineNumber = source.lineNumber;\n      return '\\n\\nCheck your code at ' + fileName + ':' + lineNumber + '.';\n    }\n\n    return '';\n  }\n\n  function getSourceInfoErrorAddendumForProps(elementProps) {\n    if (elementProps !== null && elementProps !== undefined) {\n      return getSourceInfoErrorAddendum(elementProps.__source);\n    }\n\n    return '';\n  }\n  /**\n   * Warn if there's no key explicitly set on dynamic arrays of children or\n   * object keys are not valid. This allows us to keep track of children between\n   * updates.\n   */\n\n\n  var ownerHasKeyUseWarning = {};\n\n  function getCurrentComponentErrorInfo(parentType) {\n    var info = getDeclarationErrorAddendum();\n\n    if (!info) {\n      var parentName = typeof parentType === 'string' ? parentType : parentType.displayName || parentType.name;\n\n      if (parentName) {\n        info = \"\\n\\nCheck the top-level render call using <\" + parentName + \">.\";\n      }\n    }\n\n    return info;\n  }\n  /**\n   * Warn if the element doesn't have an explicit key assigned to it.\n   * This element is in an array. The array could grow and shrink or be\n   * reordered. All children that haven't already been validated are required to\n   * have a \"key\" property assigned to it. Error statuses are cached so a warning\n   * will only be shown once.\n   *\n   * @internal\n   * @param {ReactElement} element Element that requires a key.\n   * @param {*} parentType element's parent's type.\n   */\n\n\n  function validateExplicitKey(element, parentType) {\n    if (!element._store || element._store.validated || element.key != null) {\n      return;\n    }\n\n    element._store.validated = true;\n    var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);\n\n    if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {\n      return;\n    }\n\n    ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a\n    // property, it may be the creator of the child that's responsible for\n    // assigning it a key.\n\n    var childOwner = '';\n\n    if (element && element._owner && element._owner !== ReactCurrentOwner.current) {\n      // Give the component that originally created this child.\n      childOwner = \" It was passed a child from \" + getComponentNameFromType(element._owner.type) + \".\";\n    }\n\n    {\n      setCurrentlyValidatingElement$1(element);\n\n      error('Each child in a list should have a unique \"key\" prop.' + '%s%s See https://reactjs.org/link/warning-keys for more information.', currentComponentErrorInfo, childOwner);\n\n      setCurrentlyValidatingElement$1(null);\n    }\n  }\n  /**\n   * Ensure that every element either is passed in a static location, in an\n   * array with an explicit keys property defined, or in an object literal\n   * with valid key property.\n   *\n   * @internal\n   * @param {ReactNode} node Statically passed child of any type.\n   * @param {*} parentType node's parent's type.\n   */\n\n\n  function validateChildKeys(node, parentType) {\n    if (typeof node !== 'object') {\n      return;\n    }\n\n    if (isArray(node)) {\n      for (var i = 0; i < node.length; i++) {\n        var child = node[i];\n\n        if (isValidElement(child)) {\n          validateExplicitKey(child, parentType);\n        }\n      }\n    } else if (isValidElement(node)) {\n      // This element was passed in a valid location.\n      if (node._store) {\n        node._store.validated = true;\n      }\n    } else if (node) {\n      var iteratorFn = getIteratorFn(node);\n\n      if (typeof iteratorFn === 'function') {\n        // Entry iterators used to provide implicit keys,\n        // but now we print a separate warning for them later.\n        if (iteratorFn !== node.entries) {\n          var iterator = iteratorFn.call(node);\n          var step;\n\n          while (!(step = iterator.next()).done) {\n            if (isValidElement(step.value)) {\n              validateExplicitKey(step.value, parentType);\n            }\n          }\n        }\n      }\n    }\n  }\n  /**\n   * Given an element, validate that its props follow the propTypes definition,\n   * provided by the type.\n   *\n   * @param {ReactElement} element\n   */\n\n\n  function validatePropTypes(element) {\n    {\n      var type = element.type;\n\n      if (type === null || type === undefined || typeof type === 'string') {\n        return;\n      }\n\n      var propTypes;\n\n      if (typeof type === 'function') {\n        propTypes = type.propTypes;\n      } else if (typeof type === 'object' && (type.$$typeof === REACT_FORWARD_REF_TYPE || // Note: Memo only checks outer props here.\n      // Inner props are checked in the reconciler.\n      type.$$typeof === REACT_MEMO_TYPE)) {\n        propTypes = type.propTypes;\n      } else {\n        return;\n      }\n\n      if (propTypes) {\n        // Intentionally inside to avoid triggering lazy initializers:\n        var name = getComponentNameFromType(type);\n        checkPropTypes(propTypes, element.props, 'prop', name, element);\n      } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {\n        propTypesMisspellWarningShown = true; // Intentionally inside to avoid triggering lazy initializers:\n\n        var _name = getComponentNameFromType(type);\n\n        error('Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?', _name || 'Unknown');\n      }\n\n      if (typeof type.getDefaultProps === 'function' && !type.getDefaultProps.isReactClassApproved) {\n        error('getDefaultProps is only used on classic React.createClass ' + 'definitions. Use a static property named `defaultProps` instead.');\n      }\n    }\n  }\n  /**\n   * Given a fragment, validate that it can only be provided with fragment props\n   * @param {ReactElement} fragment\n   */\n\n\n  function validateFragmentProps(fragment) {\n    {\n      var keys = Object.keys(fragment.props);\n\n      for (var i = 0; i < keys.length; i++) {\n        var key = keys[i];\n\n        if (key !== 'children' && key !== 'key') {\n          setCurrentlyValidatingElement$1(fragment);\n\n          error('Invalid prop `%s` supplied to `React.Fragment`. ' + 'React.Fragment can only have `key` and `children` props.', key);\n\n          setCurrentlyValidatingElement$1(null);\n          break;\n        }\n      }\n\n      if (fragment.ref !== null) {\n        setCurrentlyValidatingElement$1(fragment);\n\n        error('Invalid attribute `ref` supplied to `React.Fragment`.');\n\n        setCurrentlyValidatingElement$1(null);\n      }\n    }\n  }\n  function createElementWithValidation(type, props, children) {\n    var validType = isValidElementType(type); // We warn in this case but don't throw. We expect the element creation to\n    // succeed and there will likely be errors in render.\n\n    if (!validType) {\n      var info = '';\n\n      if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {\n        info += ' You likely forgot to export your component from the file ' + \"it's defined in, or you might have mixed up default and named imports.\";\n      }\n\n      var sourceInfo = getSourceInfoErrorAddendumForProps(props);\n\n      if (sourceInfo) {\n        info += sourceInfo;\n      } else {\n        info += getDeclarationErrorAddendum();\n      }\n\n      var typeString;\n\n      if (type === null) {\n        typeString = 'null';\n      } else if (isArray(type)) {\n        typeString = 'array';\n      } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {\n        typeString = \"<\" + (getComponentNameFromType(type.type) || 'Unknown') + \" />\";\n        info = ' Did you accidentally export a JSX literal instead of a component?';\n      } else {\n        typeString = typeof type;\n      }\n\n      {\n        error('React.createElement: type is invalid -- expected a string (for ' + 'built-in components) or a class/function (for composite ' + 'components) but got: %s.%s', typeString, info);\n      }\n    }\n\n    var element = createElement.apply(this, arguments); // The result can be nullish if a mock or a custom function is used.\n    // TODO: Drop this when these are no longer allowed as the type argument.\n\n    if (element == null) {\n      return element;\n    } // Skip key warning if the type isn't valid since our key validation logic\n    // doesn't expect a non-string/function type and can throw confusing errors.\n    // We don't want exception behavior to differ between dev and prod.\n    // (Rendering will throw with a helpful message and as soon as the type is\n    // fixed, the key warnings will appear.)\n\n\n    if (validType) {\n      for (var i = 2; i < arguments.length; i++) {\n        validateChildKeys(arguments[i], type);\n      }\n    }\n\n    if (type === REACT_FRAGMENT_TYPE) {\n      validateFragmentProps(element);\n    } else {\n      validatePropTypes(element);\n    }\n\n    return element;\n  }\n  var didWarnAboutDeprecatedCreateFactory = false;\n  function createFactoryWithValidation(type) {\n    var validatedFactory = createElementWithValidation.bind(null, type);\n    validatedFactory.type = type;\n\n    {\n      if (!didWarnAboutDeprecatedCreateFactory) {\n        didWarnAboutDeprecatedCreateFactory = true;\n\n        warn('React.createFactory() is deprecated and will be removed in ' + 'a future major release. Consider using JSX ' + 'or use React.createElement() directly instead.');\n      } // Legacy hook: remove it\n\n\n      Object.defineProperty(validatedFactory, 'type', {\n        enumerable: false,\n        get: function () {\n          warn('Factory.type is deprecated. Access the class directly ' + 'before passing it to createFactory.');\n\n          Object.defineProperty(this, 'type', {\n            value: type\n          });\n          return type;\n        }\n      });\n    }\n\n    return validatedFactory;\n  }\n  function cloneElementWithValidation(element, props, children) {\n    var newElement = cloneElement.apply(this, arguments);\n\n    for (var i = 2; i < arguments.length; i++) {\n      validateChildKeys(arguments[i], newElement.type);\n    }\n\n    validatePropTypes(newElement);\n    return newElement;\n  }\n\n  var enableSchedulerDebugging = false;\n  var enableProfiling = false;\n  var frameYieldMs = 5;\n\n  function push(heap, node) {\n    var index = heap.length;\n    heap.push(node);\n    siftUp(heap, node, index);\n  }\n  function peek(heap) {\n    return heap.length === 0 ? null : heap[0];\n  }\n  function pop(heap) {\n    if (heap.length === 0) {\n      return null;\n    }\n\n    var first = heap[0];\n    var last = heap.pop();\n\n    if (last !== first) {\n      heap[0] = last;\n      siftDown(heap, last, 0);\n    }\n\n    return first;\n  }\n\n  function siftUp(heap, node, i) {\n    var index = i;\n\n    while (index > 0) {\n      var parentIndex = index - 1 >>> 1;\n      var parent = heap[parentIndex];\n\n      if (compare(parent, node) > 0) {\n        // The parent is larger. Swap positions.\n        heap[parentIndex] = node;\n        heap[index] = parent;\n        index = parentIndex;\n      } else {\n        // The parent is smaller. Exit.\n        return;\n      }\n    }\n  }\n\n  function siftDown(heap, node, i) {\n    var index = i;\n    var length = heap.length;\n    var halfLength = length >>> 1;\n\n    while (index < halfLength) {\n      var leftIndex = (index + 1) * 2 - 1;\n      var left = heap[leftIndex];\n      var rightIndex = leftIndex + 1;\n      var right = heap[rightIndex]; // If the left or right node is smaller, swap with the smaller of those.\n\n      if (compare(left, node) < 0) {\n        if (rightIndex < length && compare(right, left) < 0) {\n          heap[index] = right;\n          heap[rightIndex] = node;\n          index = rightIndex;\n        } else {\n          heap[index] = left;\n          heap[leftIndex] = node;\n          index = leftIndex;\n        }\n      } else if (rightIndex < length && compare(right, node) < 0) {\n        heap[index] = right;\n        heap[rightIndex] = node;\n        index = rightIndex;\n      } else {\n        // Neither child is smaller. Exit.\n        return;\n      }\n    }\n  }\n\n  function compare(a, b) {\n    // Compare sort index first, then task id.\n    var diff = a.sortIndex - b.sortIndex;\n    return diff !== 0 ? diff : a.id - b.id;\n  }\n\n  // TODO: Use symbols?\n  var ImmediatePriority = 1;\n  var UserBlockingPriority = 2;\n  var NormalPriority = 3;\n  var LowPriority = 4;\n  var IdlePriority = 5;\n\n  function markTaskErrored(task, ms) {\n  }\n\n  /* eslint-disable no-var */\n  var getCurrentTime;\n  var hasPerformanceNow = typeof performance === 'object' && typeof performance.now === 'function';\n\n  if (hasPerformanceNow) {\n    var localPerformance = performance;\n\n    getCurrentTime = function () {\n      return localPerformance.now();\n    };\n  } else {\n    var localDate = Date;\n    var initialTime = localDate.now();\n\n    getCurrentTime = function () {\n      return localDate.now() - initialTime;\n    };\n  } // Max 31 bit integer. The max integer size in V8 for 32-bit systems.\n  // Math.pow(2, 30) - 1\n  // 0b111111111111111111111111111111\n\n\n  var maxSigned31BitInt = 1073741823; // Times out immediately\n\n  var IMMEDIATE_PRIORITY_TIMEOUT = -1; // Eventually times out\n\n  var USER_BLOCKING_PRIORITY_TIMEOUT = 250;\n  var NORMAL_PRIORITY_TIMEOUT = 5000;\n  var LOW_PRIORITY_TIMEOUT = 10000; // Never times out\n\n  var IDLE_PRIORITY_TIMEOUT = maxSigned31BitInt; // Tasks are stored on a min heap\n\n  var taskQueue = [];\n  var timerQueue = []; // Incrementing id counter. Used to maintain insertion order.\n\n  var taskIdCounter = 1; // Pausing the scheduler is useful for debugging.\n  var currentTask = null;\n  var currentPriorityLevel = NormalPriority; // This is set while performing work, to prevent re-entrance.\n\n  var isPerformingWork = false;\n  var isHostCallbackScheduled = false;\n  var isHostTimeoutScheduled = false; // Capture local references to native APIs, in case a polyfill overrides them.\n\n  var localSetTimeout = typeof setTimeout === 'function' ? setTimeout : null;\n  var localClearTimeout = typeof clearTimeout === 'function' ? clearTimeout : null;\n  var localSetImmediate = typeof setImmediate !== 'undefined' ? setImmediate : null; // IE and Node.js + jsdom\n\n  var isInputPending = typeof navigator !== 'undefined' && navigator.scheduling !== undefined && navigator.scheduling.isInputPending !== undefined ? navigator.scheduling.isInputPending.bind(navigator.scheduling) : null;\n\n  function advanceTimers(currentTime) {\n    // Check for tasks that are no longer delayed and add them to the queue.\n    var timer = peek(timerQueue);\n\n    while (timer !== null) {\n      if (timer.callback === null) {\n        // Timer was cancelled.\n        pop(timerQueue);\n      } else if (timer.startTime <= currentTime) {\n        // Timer fired. Transfer to the task queue.\n        pop(timerQueue);\n        timer.sortIndex = timer.expirationTime;\n        push(taskQueue, timer);\n      } else {\n        // Remaining timers are pending.\n        return;\n      }\n\n      timer = peek(timerQueue);\n    }\n  }\n\n  function handleTimeout(currentTime) {\n    isHostTimeoutScheduled = false;\n    advanceTimers(currentTime);\n\n    if (!isHostCallbackScheduled) {\n      if (peek(taskQueue) !== null) {\n        isHostCallbackScheduled = true;\n        requestHostCallback(flushWork);\n      } else {\n        var firstTimer = peek(timerQueue);\n\n        if (firstTimer !== null) {\n          requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);\n        }\n      }\n    }\n  }\n\n  function flushWork(hasTimeRemaining, initialTime) {\n\n\n    isHostCallbackScheduled = false;\n\n    if (isHostTimeoutScheduled) {\n      // We scheduled a timeout but it's no longer needed. Cancel it.\n      isHostTimeoutScheduled = false;\n      cancelHostTimeout();\n    }\n\n    isPerformingWork = true;\n    var previousPriorityLevel = currentPriorityLevel;\n\n    try {\n      if (enableProfiling) {\n        try {\n          return workLoop(hasTimeRemaining, initialTime);\n        } catch (error) {\n          if (currentTask !== null) {\n            var currentTime = getCurrentTime();\n            markTaskErrored(currentTask, currentTime);\n            currentTask.isQueued = false;\n          }\n\n          throw error;\n        }\n      } else {\n        // No catch in prod code path.\n        return workLoop(hasTimeRemaining, initialTime);\n      }\n    } finally {\n      currentTask = null;\n      currentPriorityLevel = previousPriorityLevel;\n      isPerformingWork = false;\n    }\n  }\n\n  function workLoop(hasTimeRemaining, initialTime) {\n    var currentTime = initialTime;\n    advanceTimers(currentTime);\n    currentTask = peek(taskQueue);\n\n    while (currentTask !== null && !(enableSchedulerDebugging )) {\n      if (currentTask.expirationTime > currentTime && (!hasTimeRemaining || shouldYieldToHost())) {\n        // This currentTask hasn't expired, and we've reached the deadline.\n        break;\n      }\n\n      var callback = currentTask.callback;\n\n      if (typeof callback === 'function') {\n        currentTask.callback = null;\n        currentPriorityLevel = currentTask.priorityLevel;\n        var didUserCallbackTimeout = currentTask.expirationTime <= currentTime;\n\n        var continuationCallback = callback(didUserCallbackTimeout);\n        currentTime = getCurrentTime();\n\n        if (typeof continuationCallback === 'function') {\n          currentTask.callback = continuationCallback;\n        } else {\n\n          if (currentTask === peek(taskQueue)) {\n            pop(taskQueue);\n          }\n        }\n\n        advanceTimers(currentTime);\n      } else {\n        pop(taskQueue);\n      }\n\n      currentTask = peek(taskQueue);\n    } // Return whether there's additional work\n\n\n    if (currentTask !== null) {\n      return true;\n    } else {\n      var firstTimer = peek(timerQueue);\n\n      if (firstTimer !== null) {\n        requestHostTimeout(handleTimeout, firstTimer.startTime - currentTime);\n      }\n\n      return false;\n    }\n  }\n\n  function unstable_runWithPriority(priorityLevel, eventHandler) {\n    switch (priorityLevel) {\n      case ImmediatePriority:\n      case UserBlockingPriority:\n      case NormalPriority:\n      case LowPriority:\n      case IdlePriority:\n        break;\n\n      default:\n        priorityLevel = NormalPriority;\n    }\n\n    var previousPriorityLevel = currentPriorityLevel;\n    currentPriorityLevel = priorityLevel;\n\n    try {\n      return eventHandler();\n    } finally {\n      currentPriorityLevel = previousPriorityLevel;\n    }\n  }\n\n  function unstable_next(eventHandler) {\n    var priorityLevel;\n\n    switch (currentPriorityLevel) {\n      case ImmediatePriority:\n      case UserBlockingPriority:\n      case NormalPriority:\n        // Shift down to normal priority\n        priorityLevel = NormalPriority;\n        break;\n\n      default:\n        // Anything lower than normal priority should remain at the current level.\n        priorityLevel = currentPriorityLevel;\n        break;\n    }\n\n    var previousPriorityLevel = currentPriorityLevel;\n    currentPriorityLevel = priorityLevel;\n\n    try {\n      return eventHandler();\n    } finally {\n      currentPriorityLevel = previousPriorityLevel;\n    }\n  }\n\n  function unstable_wrapCallback(callback) {\n    var parentPriorityLevel = currentPriorityLevel;\n    return function () {\n      // This is a fork of runWithPriority, inlined for performance.\n      var previousPriorityLevel = currentPriorityLevel;\n      currentPriorityLevel = parentPriorityLevel;\n\n      try {\n        return callback.apply(this, arguments);\n      } finally {\n        currentPriorityLevel = previousPriorityLevel;\n      }\n    };\n  }\n\n  function unstable_scheduleCallback(priorityLevel, callback, options) {\n    var currentTime = getCurrentTime();\n    var startTime;\n\n    if (typeof options === 'object' && options !== null) {\n      var delay = options.delay;\n\n      if (typeof delay === 'number' && delay > 0) {\n        startTime = currentTime + delay;\n      } else {\n        startTime = currentTime;\n      }\n    } else {\n      startTime = currentTime;\n    }\n\n    var timeout;\n\n    switch (priorityLevel) {\n      case ImmediatePriority:\n        timeout = IMMEDIATE_PRIORITY_TIMEOUT;\n        break;\n\n      case UserBlockingPriority:\n        timeout = USER_BLOCKING_PRIORITY_TIMEOUT;\n        break;\n\n      case IdlePriority:\n        timeout = IDLE_PRIORITY_TIMEOUT;\n        break;\n\n      case LowPriority:\n        timeout = LOW_PRIORITY_TIMEOUT;\n        break;\n\n      case NormalPriority:\n      default:\n        timeout = NORMAL_PRIORITY_TIMEOUT;\n        break;\n    }\n\n    var expirationTime = startTime + timeout;\n    var newTask = {\n      id: taskIdCounter++,\n      callback: callback,\n      priorityLevel: priorityLevel,\n      startTime: startTime,\n      expirationTime: expirationTime,\n      sortIndex: -1\n    };\n\n    if (startTime > currentTime) {\n      // This is a delayed task.\n      newTask.sortIndex = startTime;\n      push(timerQueue, newTask);\n\n      if (peek(taskQueue) === null && newTask === peek(timerQueue)) {\n        // All tasks are delayed, and this is the task with the earliest delay.\n        if (isHostTimeoutScheduled) {\n          // Cancel an existing timeout.\n          cancelHostTimeout();\n        } else {\n          isHostTimeoutScheduled = true;\n        } // Schedule a timeout.\n\n\n        requestHostTimeout(handleTimeout, startTime - currentTime);\n      }\n    } else {\n      newTask.sortIndex = expirationTime;\n      push(taskQueue, newTask);\n      // wait until the next time we yield.\n\n\n      if (!isHostCallbackScheduled && !isPerformingWork) {\n        isHostCallbackScheduled = true;\n        requestHostCallback(flushWork);\n      }\n    }\n\n    return newTask;\n  }\n\n  function unstable_pauseExecution() {\n  }\n\n  function unstable_continueExecution() {\n\n    if (!isHostCallbackScheduled && !isPerformingWork) {\n      isHostCallbackScheduled = true;\n      requestHostCallback(flushWork);\n    }\n  }\n\n  function unstable_getFirstCallbackNode() {\n    return peek(taskQueue);\n  }\n\n  function unstable_cancelCallback(task) {\n    // remove from the queue because you can't remove arbitrary nodes from an\n    // array based heap, only the first one.)\n\n\n    task.callback = null;\n  }\n\n  function unstable_getCurrentPriorityLevel() {\n    return currentPriorityLevel;\n  }\n\n  var isMessageLoopRunning = false;\n  var scheduledHostCallback = null;\n  var taskTimeoutID = -1; // Scheduler periodically yields in case there is other work on the main\n  // thread, like user events. By default, it yields multiple times per frame.\n  // It does not attempt to align with frame boundaries, since most tasks don't\n  // need to be frame aligned; for those that do, use requestAnimationFrame.\n\n  var frameInterval = frameYieldMs;\n  var startTime = -1;\n\n  function shouldYieldToHost() {\n    var timeElapsed = getCurrentTime() - startTime;\n\n    if (timeElapsed < frameInterval) {\n      // The main thread has only been blocked for a really short amount of time;\n      // smaller than a single frame. Don't yield yet.\n      return false;\n    } // The main thread has been blocked for a non-negligible amount of time. We\n\n\n    return true;\n  }\n\n  function requestPaint() {\n\n  }\n\n  function forceFrameRate(fps) {\n    if (fps < 0 || fps > 125) {\n      // Using console['error'] to evade Babel and ESLint\n      console['error']('forceFrameRate takes a positive int between 0 and 125, ' + 'forcing frame rates higher than 125 fps is not supported');\n      return;\n    }\n\n    if (fps > 0) {\n      frameInterval = Math.floor(1000 / fps);\n    } else {\n      // reset the framerate\n      frameInterval = frameYieldMs;\n    }\n  }\n\n  var performWorkUntilDeadline = function () {\n    if (scheduledHostCallback !== null) {\n      var currentTime = getCurrentTime(); // Keep track of the start time so we can measure how long the main thread\n      // has been blocked.\n\n      startTime = currentTime;\n      var hasTimeRemaining = true; // If a scheduler task throws, exit the current browser task so the\n      // error can be observed.\n      //\n      // Intentionally not using a try-catch, since that makes some debugging\n      // techniques harder. Instead, if `scheduledHostCallback` errors, then\n      // `hasMoreWork` will remain true, and we'll continue the work loop.\n\n      var hasMoreWork = true;\n\n      try {\n        hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime);\n      } finally {\n        if (hasMoreWork) {\n          // If there's more work, schedule the next message event at the end\n          // of the preceding one.\n          schedulePerformWorkUntilDeadline();\n        } else {\n          isMessageLoopRunning = false;\n          scheduledHostCallback = null;\n        }\n      }\n    } else {\n      isMessageLoopRunning = false;\n    } // Yielding to the browser will give it a chance to paint, so we can\n  };\n\n  var schedulePerformWorkUntilDeadline;\n\n  if (typeof localSetImmediate === 'function') {\n    // Node.js and old IE.\n    // There's a few reasons for why we prefer setImmediate.\n    //\n    // Unlike MessageChannel, it doesn't prevent a Node.js process from exiting.\n    // (Even though this is a DOM fork of the Scheduler, you could get here\n    // with a mix of Node.js 15+, which has a MessageChannel, and jsdom.)\n    // https://github.com/facebook/react/issues/20756\n    //\n    // But also, it runs earlier which is the semantic we want.\n    // If other browsers ever implement it, it's better to use it.\n    // Although both of these would be inferior to native scheduling.\n    schedulePerformWorkUntilDeadline = function () {\n      localSetImmediate(performWorkUntilDeadline);\n    };\n  } else if (typeof MessageChannel !== 'undefined') {\n    // DOM and Worker environments.\n    // We prefer MessageChannel because of the 4ms setTimeout clamping.\n    var channel = new MessageChannel();\n    var port = channel.port2;\n    channel.port1.onmessage = performWorkUntilDeadline;\n\n    schedulePerformWorkUntilDeadline = function () {\n      port.postMessage(null);\n    };\n  } else {\n    // We should only fallback here in non-browser environments.\n    schedulePerformWorkUntilDeadline = function () {\n      localSetTimeout(performWorkUntilDeadline, 0);\n    };\n  }\n\n  function requestHostCallback(callback) {\n    scheduledHostCallback = callback;\n\n    if (!isMessageLoopRunning) {\n      isMessageLoopRunning = true;\n      schedulePerformWorkUntilDeadline();\n    }\n  }\n\n  function requestHostTimeout(callback, ms) {\n    taskTimeoutID = localSetTimeout(function () {\n      callback(getCurrentTime());\n    }, ms);\n  }\n\n  function cancelHostTimeout() {\n    localClearTimeout(taskTimeoutID);\n    taskTimeoutID = -1;\n  }\n\n  var unstable_requestPaint = requestPaint;\n  var unstable_Profiling =  null;\n\n\n\n  var Scheduler = /*#__PURE__*/Object.freeze({\n    __proto__: null,\n    unstable_ImmediatePriority: ImmediatePriority,\n    unstable_UserBlockingPriority: UserBlockingPriority,\n    unstable_NormalPriority: NormalPriority,\n    unstable_IdlePriority: IdlePriority,\n    unstable_LowPriority: LowPriority,\n    unstable_runWithPriority: unstable_runWithPriority,\n    unstable_next: unstable_next,\n    unstable_scheduleCallback: unstable_scheduleCallback,\n    unstable_cancelCallback: unstable_cancelCallback,\n    unstable_wrapCallback: unstable_wrapCallback,\n    unstable_getCurrentPriorityLevel: unstable_getCurrentPriorityLevel,\n    unstable_shouldYield: shouldYieldToHost,\n    unstable_requestPaint: unstable_requestPaint,\n    unstable_continueExecution: unstable_continueExecution,\n    unstable_pauseExecution: unstable_pauseExecution,\n    unstable_getFirstCallbackNode: unstable_getFirstCallbackNode,\n    get unstable_now () { return getCurrentTime; },\n    unstable_forceFrameRate: forceFrameRate,\n    unstable_Profiling: unstable_Profiling\n  });\n\n  var ReactSharedInternals$1 = {\n    ReactCurrentDispatcher: ReactCurrentDispatcher,\n    ReactCurrentOwner: ReactCurrentOwner,\n    ReactCurrentBatchConfig: ReactCurrentBatchConfig,\n    // Re-export the schedule API(s) for UMD bundles.\n    // This avoids introducing a dependency on a new UMD global in a minor update,\n    // Since that would be a breaking change (e.g. for all existing CodeSandboxes).\n    // This re-export is only required for UMD bundles;\n    // CJS bundles use the shared NPM package.\n    Scheduler: Scheduler\n  };\n\n  {\n    ReactSharedInternals$1.ReactCurrentActQueue = ReactCurrentActQueue;\n    ReactSharedInternals$1.ReactDebugCurrentFrame = ReactDebugCurrentFrame;\n  }\n\n  function startTransition(scope, options) {\n    var prevTransition = ReactCurrentBatchConfig.transition;\n    ReactCurrentBatchConfig.transition = {};\n    var currentTransition = ReactCurrentBatchConfig.transition;\n\n    {\n      ReactCurrentBatchConfig.transition._updatedFibers = new Set();\n    }\n\n    try {\n      scope();\n    } finally {\n      ReactCurrentBatchConfig.transition = prevTransition;\n\n      {\n        if (prevTransition === null && currentTransition._updatedFibers) {\n          var updatedFibersCount = currentTransition._updatedFibers.size;\n\n          if (updatedFibersCount > 10) {\n            warn('Detected a large number of updates inside startTransition. ' + 'If this is due to a subscription please re-write it to use React provided hooks. ' + 'Otherwise concurrent mode guarantees are off the table.');\n          }\n\n          currentTransition._updatedFibers.clear();\n        }\n      }\n    }\n  }\n\n  var didWarnAboutMessageChannel = false;\n  var enqueueTaskImpl = null;\n  function enqueueTask(task) {\n    if (enqueueTaskImpl === null) {\n      try {\n        // read require off the module object to get around the bundlers.\n        // we don't want them to detect a require and bundle a Node polyfill.\n        var requireString = ('require' + Math.random()).slice(0, 7);\n        var nodeRequire = module && module[requireString]; // assuming we're in node, let's try to get node's\n        // version of setImmediate, bypassing fake timers if any.\n\n        enqueueTaskImpl = nodeRequire.call(module, 'timers').setImmediate;\n      } catch (_err) {\n        // we're in a browser\n        // we can't use regular timers because they may still be faked\n        // so we try MessageChannel+postMessage instead\n        enqueueTaskImpl = function (callback) {\n          {\n            if (didWarnAboutMessageChannel === false) {\n              didWarnAboutMessageChannel = true;\n\n              if (typeof MessageChannel === 'undefined') {\n                error('This browser does not have a MessageChannel implementation, ' + 'so enqueuing tasks via await act(async () => ...) will fail. ' + 'Please file an issue at https://github.com/facebook/react/issues ' + 'if you encounter this warning.');\n              }\n            }\n          }\n\n          var channel = new MessageChannel();\n          channel.port1.onmessage = callback;\n          channel.port2.postMessage(undefined);\n        };\n      }\n    }\n\n    return enqueueTaskImpl(task);\n  }\n\n  var actScopeDepth = 0;\n  var didWarnNoAwaitAct = false;\n  function act(callback) {\n    {\n      // `act` calls can be nested, so we track the depth. This represents the\n      // number of `act` scopes on the stack.\n      var prevActScopeDepth = actScopeDepth;\n      actScopeDepth++;\n\n      if (ReactCurrentActQueue.current === null) {\n        // This is the outermost `act` scope. Initialize the queue. The reconciler\n        // will detect the queue and use it instead of Scheduler.\n        ReactCurrentActQueue.current = [];\n      }\n\n      var prevIsBatchingLegacy = ReactCurrentActQueue.isBatchingLegacy;\n      var result;\n\n      try {\n        // Used to reproduce behavior of `batchedUpdates` in legacy mode. Only\n        // set to `true` while the given callback is executed, not for updates\n        // triggered during an async event, because this is how the legacy\n        // implementation of `act` behaved.\n        ReactCurrentActQueue.isBatchingLegacy = true;\n        result = callback(); // Replicate behavior of original `act` implementation in legacy mode,\n        // which flushed updates immediately after the scope function exits, even\n        // if it's an async function.\n\n        if (!prevIsBatchingLegacy && ReactCurrentActQueue.didScheduleLegacyUpdate) {\n          var queue = ReactCurrentActQueue.current;\n\n          if (queue !== null) {\n            ReactCurrentActQueue.didScheduleLegacyUpdate = false;\n            flushActQueue(queue);\n          }\n        }\n      } catch (error) {\n        popActScope(prevActScopeDepth);\n        throw error;\n      } finally {\n        ReactCurrentActQueue.isBatchingLegacy = prevIsBatchingLegacy;\n      }\n\n      if (result !== null && typeof result === 'object' && typeof result.then === 'function') {\n        var thenableResult = result; // The callback is an async function (i.e. returned a promise). Wait\n        // for it to resolve before exiting the current scope.\n\n        var wasAwaited = false;\n        var thenable = {\n          then: function (resolve, reject) {\n            wasAwaited = true;\n            thenableResult.then(function (returnValue) {\n              popActScope(prevActScopeDepth);\n\n              if (actScopeDepth === 0) {\n                // We've exited the outermost act scope. Recursively flush the\n                // queue until there's no remaining work.\n                recursivelyFlushAsyncActWork(returnValue, resolve, reject);\n              } else {\n                resolve(returnValue);\n              }\n            }, function (error) {\n              // The callback threw an error.\n              popActScope(prevActScopeDepth);\n              reject(error);\n            });\n          }\n        };\n\n        {\n          if (!didWarnNoAwaitAct && typeof Promise !== 'undefined') {\n            // eslint-disable-next-line no-undef\n            Promise.resolve().then(function () {}).then(function () {\n              if (!wasAwaited) {\n                didWarnNoAwaitAct = true;\n\n                error('You called act(async () => ...) without await. ' + 'This could lead to unexpected testing behaviour, ' + 'interleaving multiple act calls and mixing their ' + 'scopes. ' + 'You should - await act(async () => ...);');\n              }\n            });\n          }\n        }\n\n        return thenable;\n      } else {\n        var returnValue = result; // The callback is not an async function. Exit the current scope\n        // immediately, without awaiting.\n\n        popActScope(prevActScopeDepth);\n\n        if (actScopeDepth === 0) {\n          // Exiting the outermost act scope. Flush the queue.\n          var _queue = ReactCurrentActQueue.current;\n\n          if (_queue !== null) {\n            flushActQueue(_queue);\n            ReactCurrentActQueue.current = null;\n          } // Return a thenable. If the user awaits it, we'll flush again in\n          // case additional work was scheduled by a microtask.\n\n\n          var _thenable = {\n            then: function (resolve, reject) {\n              // Confirm we haven't re-entered another `act` scope, in case\n              // the user does something weird like await the thenable\n              // multiple times.\n              if (ReactCurrentActQueue.current === null) {\n                // Recursively flush the queue until there's no remaining work.\n                ReactCurrentActQueue.current = [];\n                recursivelyFlushAsyncActWork(returnValue, resolve, reject);\n              } else {\n                resolve(returnValue);\n              }\n            }\n          };\n          return _thenable;\n        } else {\n          // Since we're inside a nested `act` scope, the returned thenable\n          // immediately resolves. The outer scope will flush the queue.\n          var _thenable2 = {\n            then: function (resolve, reject) {\n              resolve(returnValue);\n            }\n          };\n          return _thenable2;\n        }\n      }\n    }\n  }\n\n  function popActScope(prevActScopeDepth) {\n    {\n      if (prevActScopeDepth !== actScopeDepth - 1) {\n        error('You seem to have overlapping act() calls, this is not supported. ' + 'Be sure to await previous act() calls before making a new one. ');\n      }\n\n      actScopeDepth = prevActScopeDepth;\n    }\n  }\n\n  function recursivelyFlushAsyncActWork(returnValue, resolve, reject) {\n    {\n      var queue = ReactCurrentActQueue.current;\n\n      if (queue !== null) {\n        try {\n          flushActQueue(queue);\n          enqueueTask(function () {\n            if (queue.length === 0) {\n              // No additional work was scheduled. Finish.\n              ReactCurrentActQueue.current = null;\n              resolve(returnValue);\n            } else {\n              // Keep flushing work until there's none left.\n              recursivelyFlushAsyncActWork(returnValue, resolve, reject);\n            }\n          });\n        } catch (error) {\n          reject(error);\n        }\n      } else {\n        resolve(returnValue);\n      }\n    }\n  }\n\n  var isFlushing = false;\n\n  function flushActQueue(queue) {\n    {\n      if (!isFlushing) {\n        // Prevent re-entrance.\n        isFlushing = true;\n        var i = 0;\n\n        try {\n          for (; i < queue.length; i++) {\n            var callback = queue[i];\n\n            do {\n              callback = callback(true);\n            } while (callback !== null);\n          }\n\n          queue.length = 0;\n        } catch (error) {\n          // If something throws, leave the remaining callbacks on the queue.\n          queue = queue.slice(i + 1);\n          throw error;\n        } finally {\n          isFlushing = false;\n        }\n      }\n    }\n  }\n\n  var createElement$1 =  createElementWithValidation ;\n  var cloneElement$1 =  cloneElementWithValidation ;\n  var createFactory =  createFactoryWithValidation ;\n  var Children = {\n    map: mapChildren,\n    forEach: forEachChildren,\n    count: countChildren,\n    toArray: toArray,\n    only: onlyChild\n  };\n\n  exports.Children = Children;\n  exports.Component = Component;\n  exports.Fragment = REACT_FRAGMENT_TYPE;\n  exports.Profiler = REACT_PROFILER_TYPE;\n  exports.PureComponent = PureComponent;\n  exports.StrictMode = REACT_STRICT_MODE_TYPE;\n  exports.Suspense = REACT_SUSPENSE_TYPE;\n  exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactSharedInternals$1;\n  exports.act = act;\n  exports.cloneElement = cloneElement$1;\n  exports.createContext = createContext;\n  exports.createElement = createElement$1;\n  exports.createFactory = createFactory;\n  exports.createRef = createRef;\n  exports.forwardRef = forwardRef;\n  exports.isValidElement = isValidElement;\n  exports.lazy = lazy;\n  exports.memo = memo;\n  exports.startTransition = startTransition;\n  exports.unstable_act = act;\n  exports.useCallback = useCallback;\n  exports.useContext = useContext;\n  exports.useDebugValue = useDebugValue;\n  exports.useDeferredValue = useDeferredValue;\n  exports.useEffect = useEffect;\n  exports.useId = useId;\n  exports.useImperativeHandle = useImperativeHandle;\n  exports.useInsertionEffect = useInsertionEffect;\n  exports.useLayoutEffect = useLayoutEffect;\n  exports.useMemo = useMemo;\n  exports.useReducer = useReducer;\n  exports.useRef = useRef;\n  exports.useState = useState;\n  exports.useSyncExternalStore = useSyncExternalStore;\n  exports.useTransition = useTransition;\n  exports.version = ReactVersion;\n\n})));"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/react_input.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\" />\n  <title>Controlled Grafana-like Input Demo</title>\n  <!-- React and ReactDOM via UNPKG -->\n  <script src=\"react.development.js\"></script>\n  <script src=\"react-dom.development.js\"></script>\n  <script>\n    const { useState, useRef } = React;\n\n    function App() {\n      const [value, setValue] = useState('');\n      const inputRef = useRef(null);\n\n      return (\n        React.createElement('div', { style: { padding: '24px', fontFamily: 'sans-serif', maxWidth: '320px' } },\n          React.createElement('h2', null, 'Grafana-like Login Input'),\n          React.createElement('input', {\n            ref: inputRef,\n            type: 'text',\n            placeholder: 'Username or email',\n            value: value,\n            onChange: (e) => setValue(e.target.value),\n            style: { width: '100%', padding: '8px', marginBottom: '12px', fontSize: '16px' }\n          }),\n          React.createElement('p', { id: 'react-state' }, `React state: \"${value}\"`),\n        )\n      );\n    }\n\n    document.addEventListener('DOMContentLoaded', () => {\n      ReactDOM.createRoot(document.getElementById('root')).render(React.createElement(App));\n    });\n  </script>\n</head>\n<body>\n  <div id=\"root\"></div>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/select_options.html",
    "content": "<html>\n<body>\n   <select name=\"numbers\" id=\"numbers-options\" onchange=\"selectOnChange(this)\" multiple>\n      <option value=\"zero\">Zero</option>\n      <option value=\"one\">One</option>\n      <option value=\"two\">Two</option>\n      <option value=\"three\">Three</option>\n      <option value=\"four\">Four</option>\n      <option value=\"five\">Five</option>\n   </select>\n</body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/shadow_and_doc_frag.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>DocumentFragment and ShadowRoot Test page</title>\n</head>\n<body>\n    <h2>DocumentFragment and ShadowRoot Test page</h2>\n    <div id=\"docFrag\"></div>\n\n    <!-- Element that will host the Shadow DOM -->\n    <div id=\"shadowHost\"></div>\n\n    <script>\n        function addDocFrag() {\n            const container = document.getElementById('docFrag');\n            const fragment = document.createDocumentFragment();\n\n            // Add some additional text in a paragraph\n            const paragraph = document.createElement('p');\n            paragraph.id = 'inDocFrag'; // Set the id of the div\n            paragraph.textContent = 'This text is added via a document fragment!';\n            fragment.appendChild(paragraph);\n\n            // Append the fragment to the container\n            container.appendChild(fragment);\n        }\n\n        function addShadowDom() {\n            const shadowHost = document.getElementById('shadowHost');\n            // When mode is set to closed, we cannot access internals with JS.\n            // We will need to create a custom element that exposes these\n            // internals with getters and setters.\n            const shadowRoot = shadowHost.attachShadow({ mode: 'open' });\n\n            // Create a DocumentFragment to add to the Shadow DOM\n            const fragment = document.createDocumentFragment();\n\n            // Add some styled content to the fragment\n            const styleElement = document.createElement('style');\n            styleElement.textContent = `\n                p {\n                    color: blue;\n                    font-weight: bold;\n                }\n            `;\n            fragment.appendChild(styleElement);\n\n            const paragraphElement = document.createElement('p');\n            paragraphElement.id = 'inShadowRootDocFrag';\n            paragraphElement.textContent = 'This is inside Shadow DOM, added via a DocumentFragment!';\n            fragment.appendChild(paragraphElement);\n\n            // Append the DocumentFragment to the Shadow DOM.\n            shadowRoot.appendChild(fragment);\n        }\n\n        function done() {\n            // Create a new div element which will reside in the original Document.\n            const doneDiv = document.createElement('div');\n            doneDiv.id = 'done';\n            doneDiv.textContent = \"All additions to page completed (i'm in the original document)\";\n\n            // Append it to the original Document.\n            document.body.appendChild(doneDiv);\n        }\n\n        addDocFrag();\n        addShadowDom();\n        done();\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/shadow_dom_link.html",
    "content": "<html>\n<head>\n<script>\ncustomElements.define('my-link',\n  class extends HTMLElement {\n    constructor() {\n      super();\n\n      const template = document.getElementById('my-link-template');\n      const templateContent = template.content;\n\n      this.attachShadow({mode: 'open'}).appendChild(\n        templateContent.cloneNode(true)\n      );\n    }\n  }\n);\n\n</script>\n</head>\n<body>\n<template id=\"my-link-template\">\n  <a href=\"#\" id=\"inner-link\"><slot></slot></a>\n</template>\n<my-link>Sign up</my-link>\n</body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/usual.html",
    "content": ""
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/visible.html",
    "content": "<html lang=\"en\">\n    <head></head>\n    <body>\n        <div id='my-div'>My DIV</div>\n        <div id='my-div-2'>My DIV 2</div>\n        <div id='my-div-3' style='display: none;'>My DIV 3</div>\n    </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/wait_for.html",
    "content": "<html lang=\"en\">\n    <head></head>\n    <body>\n        <div id='my-div' style='display: none;'>My DIV</div>\n        <script>\n            function showDiv() {\n                setTimeout(function() {\n                    document.getElementById('my-div').style.display = 'block';\n                }, 200);\n            }\n            \n            showDiv();\n        </script>\n    </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/wait_until.html",
    "content": "<html lang=\"en\">\n    <head>\n      <meta charset=\"UTF-8\">\n      <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n      <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n      <title>WaitUntil options test</title>\n    </head>\n    <body>\n        <script>\n            window.results = [];\n            window.addEventListener('load', (event) => {\n                window.results.push(\"load\");\n            });\n            document.addEventListener('DOMContentLoaded', (event) => {\n                window.results.push(\"DOMContentLoaded\");\n            });\n        </script>\n    </body>\n</html>"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/waitfornavigation_test.html",
    "content": "<!DOCTYPE html>\n<html>\n<head></head>\n<body>\n    <a id=\"page1\" href=\"page1.html\">Go to Page 1</a>\n    <a id=\"page2\" href=\"page2.html\">Go to Page 2</a>\n</body>\n</html> "
  },
  {
    "path": "internal/js/modules/k6/browser/tests/static/web_vitals.html",
    "content": "<!--\n  This web page has sleeps to mimic getting things over the\n  network that could affect a web page as it is being loaded.\n  This helps the web vital library to measure and emit web\n  vitals. A perfect page where everything loads instantly\n  will only emit a couple of web vital metrics as there will\n  not be enough data to work with.\n-->\n\n<html>\n  <head>\n    <title>for web vital</title>\n  </head>\n  <script type=\"text/javascript\">\n    async function myFunction() {\n      await new Promise(r => setTimeout(r, 200));\n\n      document.getElementById(\"onLoadDiv\").innerText = \"⏳\";\n\n      await new Promise(r => setTimeout(r, 200));\n\n      const link = document.createElement('a');\n      link.setAttribute(\"id\", \"clickMe\");\n      link.href = \"javascript:clickMeFunction()\"\n      link.text = \"Click me\"\n      document.body.insertBefore(link, document.getElementById(\"theTable\"));\n\n      document.getElementById(\"onLoadDiv\").innerText = \"⌛️\";\n    }\n    async function clickMeFunction() {\n      document.getElementById(\"amendableDiv\").innerText = \"👍\";\n      await new Promise(r => setTimeout(r, 200));\n      location.reload();\n    }\n  </script>\n  <div id=\"amendableDiv\"></div>\n  <div id=\"onLoadDiv\"></div>\n  <div id=\"textBlock\">\n    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore\n    et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut\n    aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum\n    dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui\n    officia deserunt mollit anim id est laborum.\n  </div>\n  <body onload=\"myFunction()\">\n    <table id=\"theTable\">\n      <tr>\n        <td>Title</td>\n        <td>Review</td>\n      </tr>\n      <tr>\n        <td>Book A</td>\n        <td>Good</td>\n      </tr>\n      <tr>\n        <td>Book B</td>\n        <td>Ok</td>\n      </tr>\n      <tr>\n        <td>Book C</td>\n        <td>Not good</td>\n      </tr>\n      <tr>\n        <td>Book D</td>\n        <td>Very good</td>\n      </tr>\n    </table>\n  </body>\n</html>\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/test_browser.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/sync/errgroup\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/browser\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/chromium\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\n\tk6httpmultibin \"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\tk6metrics \"go.k6.io/k6/metrics\"\n)\n\nconst testBrowserStaticDir = \"static\"\n\n// testBrowser is a test testBrowser for integration testing.\ntype testBrowser struct {\n\tt testing.TB\n\n\tctx    context.Context\n\tcancel context.CancelFunc\n\tvu     *k6test.VU\n\n\tbrowserType *chromium.BrowserType\n\tpid         int // the browser process ID\n\twsURL       string\n\n\t*common.Browser\n\n\t// isBrowserTypeInitialized is true if the browser type has been\n\t// initialized with a VU. Some options can only be used in the\n\t// post-init stage and require the browser type to be initialized.\n\tisBrowserTypeInitialized bool\n\n\t// http is set by the withHTTPServer option.\n\thttp *k6httpmultibin.HTTPMultiBin\n\t// logCache is set by the withLogCache option.\n\tlogCache *logCache\n\t// lookupFunc is set by the withEnvLookup option.\n\tlookupFunc env.LookupFunc\n\t// samples is set by the withSamples option.\n\tsamples chan k6metrics.SampleContainer\n\t// skipClose is set by the withSkipClose option.\n\tskipClose bool\n}\n\n// newTestBrowser configures and launches a new chrome browser.\n//\n// It automatically closes it when `t` returns unless `withSkipClose` option is provided.\n//\n// The following opts are available to customize the testBrowser:\n//   - withEnvLookup: provides a custom lookup function for environment variables.\n//   - withFileServer: enables the HTTPMultiBin server and serves the given files.\n//   - withHTTPServer: enables the HTTPMultiBin server.\n//   - withLogCache: enables the log cache.\n//   - withSamples: provides a channel to receive the browser metrics.\n//   - withSkipClose: skips closing the browser when the test finishes.\nfunc newTestBrowser(tb testing.TB, opts ...func(*testBrowser)) *testBrowser {\n\ttb.Helper()\n\n\ttbr := &testBrowser{t: tb}\n\ttbr.applyDefaultOptions()\n\ttbr.applyOptions(opts...) // apply pre-init stage options.\n\ttbr.vu, tbr.cancel = newTestBrowserVU(tb, tbr)\n\ttbr.browserType = chromium.NewBrowserType(tbr.vu)\n\ttbr.vu.ActivateVU()\n\ttbr.isBrowserTypeInitialized = true // some option require the browser type to be initialized.\n\ttbr.applyOptions(opts...)           // apply post-init stage options.\n\n\tb, pid, err := tbr.browserType.Launch(context.Background(), tbr.vu.Context())\n\tif err != nil {\n\t\ttb.Fatalf(\"testBrowser: %v\", err)\n\t}\n\ttbr.Browser = b\n\ttbr.ctx = tbr.browserType.Ctx\n\ttbr.pid = pid\n\ttbr.wsURL = b.WsURL()\n\ttb.Cleanup(func() {\n\t\tif !tbr.skipClose {\n\t\t\tb.Close()\n\t\t}\n\t})\n\n\treturn tbr\n}\n\n// newTestBrowserVU initializes a new VU for browser testing.\n// It returns the VU and a cancel function to stop the VU.\n// VU contains the context with the custom metrics registry.\nfunc newTestBrowserVU(tb testing.TB, tbr *testBrowser) (_ *k6test.VU, cancel func()) {\n\ttb.Helper()\n\n\tvu := k6test.NewVU(tb, k6test.WithSamples(tbr.samples))\n\tmetricsCtx := k6ext.WithCustomMetrics(\n\t\tvu.Context(),\n\t\tk6ext.RegisterCustomMetrics(k6metrics.NewRegistry()),\n\t)\n\tctx, cancel := context.WithCancel(metricsCtx)\n\ttb.Cleanup(cancel)\n\tvu.CtxField = ctx\n\tvu.InitEnvField.LookupEnv = tbr.lookupFunc\n\n\tmod := browser.New().NewModuleInstance(vu)\n\tjsMod, ok := mod.Exports().Default.(*browser.JSModule)\n\trequire.Truef(tb, ok, \"unexpected default mod export type %T\", mod.Exports().Default)\n\t// Setting the mapped browser into the vu's sobek runtime.\n\trequire.NoError(tb, vu.Runtime().Set(\"browser\", jsMod.Browser))\n\n\treturn vu, cancel\n}\n\n// applyDefaultOptions applies the default options for the testBrowser.\nfunc (b *testBrowser) applyDefaultOptions() {\n\tb.samples = make(chan k6metrics.SampleContainer, 1000)\n\t// default lookup function is env.Lookup so that we can\n\t// pass the environment variables while testing, i.e.: K6_BROWSER_LOG.\n\tb.lookupFunc = env.Lookup\n}\n\n// applyOptions applies the given options to the testBrowser.\nfunc (b *testBrowser) applyOptions(opts ...func(*testBrowser)) {\n\tfor _, opt := range opts {\n\t\topt(b)\n\t}\n}\n\n// withEnvLookup sets the lookup function for environment variables.\n//\n// example:\n//\n//\tb := TestBrowser(t, withEnvLookup(env.ConstLookup(env.BrowserHeadless, \"0\")))\nfunc withEnvLookup(lookupFunc env.LookupFunc) func(*testBrowser) {\n\treturn func(tb *testBrowser) { tb.lookupFunc = lookupFunc }\n}\n\n// withFileServer enables the HTTP test server and serves a file server\n// for static files.\n//\n// see: WithFileServer\n//\n// example:\n//\n//\tb := TestBrowser(t, withFileServer())\nfunc withFileServer() func(*testBrowser) {\n\treturn func(tb *testBrowser) {\n\t\tif !tb.isBrowserTypeInitialized {\n\t\t\treturn\n\t\t}\n\t\tif tb.http == nil {\n\t\t\t// file server needs HTTP server.\n\t\t\tapply := withHTTPServer()\n\t\t\tapply(tb)\n\t\t}\n\t\t_ = tb.withFileServer()\n\t}\n}\n\n// withFileServer serves a file server using the HTTP test server that is\n// accessible via `testBrowserStaticDir` prefix.\n//\n// This method is for enabling the static file server after starting a test\n// browser. For early starting the file server see withFileServer function.\nfunc (b *testBrowser) withFileServer() *testBrowser {\n\tb.t.Helper()\n\n\tconst (\n\t\tslash = string(os.PathSeparator) //nolint:forbidigo\n\t\tpath  = slash + testBrowserStaticDir + slash\n\t)\n\n\tfs := http.FileServer(http.Dir(testBrowserStaticDir))\n\n\treturn b.withHandler(\"/\"+testBrowserStaticDir+\"/\", http.StripPrefix(path, fs).ServeHTTP)\n}\n\n// withHandler adds the given handler to the HTTP test server and makes it\n// accessible with the given pattern.\nfunc (b *testBrowser) withHandler(pattern string, handler http.HandlerFunc) *testBrowser {\n\tb.t.Helper()\n\n\tif b.http == nil {\n\t\tb.t.Fatalf(\"You should enable HTTP test server, see: withHTTPServer option\")\n\t}\n\tb.http.Mux.Handle(pattern, handler)\n\treturn b\n}\n\n// withHTTPServer enables the HTTP test server.\n// It is used to detect whether to enable the HTTP test server.\n//\n// example:\n//\n//\tb := TestBrowser(t, withHTTPServer())\nfunc withHTTPServer() func(*testBrowser) {\n\treturn func(tb *testBrowser) {\n\t\tif !tb.isBrowserTypeInitialized {\n\t\t\treturn\n\t\t}\n\t\tif tb.http != nil {\n\t\t\t// already initialized.\n\t\t\treturn\n\t\t}\n\t\ttb.http = k6httpmultibin.NewHTTPMultiBin(tb.t)\n\t\ttb.vu.StateField.TLSConfig = tb.http.TLSClientConfig\n\t\ttb.vu.StateField.Transport = tb.http.HTTPTransport\n\t}\n}\n\n// withIFrameContent sets up a handler for /iframe that serves a page embedding\n// an iframe with the given content.\nfunc withIFrameContent(iframeHTML string, iframeID string) func(*testBrowser) {\n\treturn func(tb *testBrowser) {\n\t\tif !tb.isBrowserTypeInitialized {\n\t\t\treturn\n\t\t}\n\t\tif tb.http == nil {\n\t\t\tapply := withHTTPServer()\n\t\t\tapply(tb)\n\t\t}\n\n\t\tmux := http.NewServeMux()\n\t\tmux.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n\t\t\tw.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t\t\t_, err := w.Write([]byte(iframeHTML))\n\t\t\trequire.NoError(tb.t, err)\n\t\t})\n\t\tsrv := httptest.NewServer(mux)\n\t\ttb.t.Cleanup(func() {\n\t\t\tsrv.Close()\n\t\t})\n\n\t\ttb.withIFrameURL(srv.URL, iframeID)\n\t}\n}\n\n// withIFrameURL sets up a handler for /iframe that serves a page embedding\n// an iframe with the given URL.\nfunc (tb *testBrowser) withIFrameURL(iframeURL string, iframeID string) {\n\ttb.t.Helper()\n\n\tif tb.http == nil {\n\t\ttb.t.Fatalf(\"You should enable HTTP test server, see: withHTTPServer option\")\n\t}\n\n\tdocHTML := fmt.Sprintf(`<!DOCTYPE html>\n\t\t<html>\n\t\t<head></head>\n\t\t<body>\n\t\t\t<iframe id=\"%s\" src=\"%s\"></iframe>\n\t\t</body>\n\t\t</html>`, iframeID, iframeURL)\n\n\ttb.withHandler(\"/iframe\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.Header().Set(\"Content-Type\", \"text/html; charset=utf-8\")\n\t\t_, err := w.Write([]byte(docHTML))\n\t\trequire.NoError(tb.t, err)\n\t})\n}\n\n// withLogCache enables the log cache.\n//\n// example:\n//\n//\tb := TestBrowser(t, withLogCache())\nfunc withLogCache() func(*testBrowser) {\n\treturn func(tb *testBrowser) {\n\t\tif !tb.isBrowserTypeInitialized {\n\t\t\treturn\n\t\t}\n\t\ttb.logCache = attachLogCache(tb.t, tb.vu.StateField.Logger)\n\t}\n}\n\n// withSamples is used to indicate we want to use a bidirectional channel\n// so that the test can read the metrics being emitted to the channel.\nfunc withSamples(sc chan k6metrics.SampleContainer) func(*testBrowser) {\n\treturn func(tb *testBrowser) { tb.samples = sc }\n}\n\n// withSkipClose skips calling Browser.Close() in t.Cleanup().\n// It indicates that we shouldn't call Browser.Close() in\n// t.Cleanup(), since it will presumably be done by the test.\n//\n// example:\n//\n//\tb := TestBrowser(t, withSkipClose())\nfunc withSkipClose() func(*testBrowser) {\n\treturn func(tb *testBrowser) { tb.skipClose = true }\n}\n\n// GotoNewPage is a wrapper around testBrowser.NewPage and Page.Goto that fails\n// the test if an error occurs. Added this helper to avoid boilerplate code in tests.\nfunc (b *testBrowser) GotoNewPage(url string) *common.Page {\n\tb.t.Helper()\n\n\tp := b.NewPage(nil)\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(url, opts)\n\trequire.NoError(b.t, err)\n\n\treturn p\n}\n\n// GotoPage is a wrapper around Page.Goto that fails the test if an error occurs.\n// Added this helper to avoid boilerplate code in tests.\nfunc (b *testBrowser) GotoPage(p *common.Page, url string) {\n\tb.t.Helper()\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\t_, err := p.Goto(url, opts)\n\trequire.NoError(b.t, err)\n}\n\n// GotoPageAndAssertURL navigates to a URL and asserts that the page URL matches.\nfunc (b *testBrowser) GotoPageAndAssertURL(p *common.Page, url string) {\n\tb.t.Helper()\n\n\tb.GotoPage(p, url)\n\tcurrentURL, err := p.URL()\n\trequire.NoError(b.t, err)\n\trequire.Equal(b.t, url, currentURL)\n}\n\n// AssertURL asserts that the current page URL matches the expected URL.\nfunc (b *testBrowser) AssertURL(p *common.Page, expectedURL string, msgAndArgs ...any) {\n\tb.t.Helper()\n\n\tcurrentURL, err := p.URL()\n\trequire.NoError(b.t, err)\n\tassert.Equal(b.t, expectedURL, currentURL, msgAndArgs...)\n}\n\n// NewPage is a wrapper around Browser.NewPage that fails the test if an\n// error occurs. Added this helper to avoid boilerplate code in tests.\nfunc (b *testBrowser) NewPage(opts *common.BrowserContextOptions) *common.Page {\n\tb.t.Helper()\n\n\tp, err := b.Browser.NewPage(opts)\n\trequire.NoError(b.t, err)\n\n\treturn p\n}\n\n// url returns the listening HTTP test server's url combined with the given path.\nfunc (b *testBrowser) url(path string) string {\n\tb.t.Helper()\n\n\tif b.http == nil {\n\t\tb.t.Fatalf(\"You should enable HTTP test server, see: withHTTPServer option\")\n\t}\n\treturn b.http.ServerHTTP.URL + path\n}\n\n// staticURL is a helper for URL(\"/`testBrowserStaticDir`/\"+ path).\nfunc (b *testBrowser) staticURL(path string) string {\n\tb.t.Helper()\n\treturn b.url(\"/\" + testBrowserStaticDir + \"/\" + path)\n}\n\n// context returns the testBrowser context.\nfunc (b *testBrowser) context() context.Context { return b.ctx }\n\n// cancelContext cancels the testBrowser context.\nfunc (b *testBrowser) cancelContext() { b.cancel() }\n\n// runtime returns a VU runtime.\nfunc (b *testBrowser) runtime() *sobek.Runtime { return b.vu.Runtime() }\n\n// toSobekValue converts a value to sobek value.\nfunc (b *testBrowser) toSobekValue(i any) sobek.Value { return b.runtime().ToValue(i) }\n\n// runJavaScript in the sobek runtime.\nfunc (b *testBrowser) runJavaScript(s string, args ...any) (sobek.Value, error) { //nolint:unparam\n\tb.t.Helper()\n\tv, err := b.runtime().RunString(fmt.Sprintf(s, args...))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"while running %q(%v): %w\", s, args, err)\n\t}\n\treturn v, nil\n}\n\n// Run the given functions in parallel and waits for them to finish.\nfunc (b *testBrowser) run(ctx context.Context, fs ...func() error) error {\n\tb.t.Helper()\n\n\tg, ctx := errgroup.WithContext(ctx)\n\tfor _, f := range fs {\n\t\tg.Go(func() error {\n\t\t\terrc := make(chan error, 1)\n\t\t\tgo func() { errc <- f() }()\n\t\t\tselect {\n\t\t\tcase err := <-errc:\n\t\t\t\treturn err\n\t\t\tcase <-ctx.Done():\n\t\t\t\tif err := common.ContextErr(ctx); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"while running %T: %w\", f, err)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn nil\n\t\t})\n\t}\n\n\tif err := g.Wait(); err != nil {\n\t\treturn fmt.Errorf(\"while waiting for %T: %w\", fs, err)\n\t}\n\n\treturn nil\n}\n\n// awaitWithTimeout is the same as await but takes a timeout and times out the function after the time runs out.\nfunc (b *testBrowser) awaitWithTimeout(timeout time.Duration, fn func() error) error {\n\tb.t.Helper()\n\terrC := make(chan error)\n\tgo func() {\n\t\tdefer close(errC)\n\t\terrC <- fn()\n\t}()\n\n\t// use timer instead of time.After to not leak time.After for the duration of the timeout\n\tt := time.NewTimer(timeout)\n\tdefer t.Stop()\n\n\tselect {\n\tcase err := <-errC:\n\t\treturn err\n\tcase <-t.C:\n\t\treturn fmt.Errorf(\"test timed out after %s\", timeout)\n\t}\n}\n\n// convert is a helper function to convert any value to a given type.\n// returns a pointer to the converted value for convenience.\n//\n// underneath, it uses json.Marshal and json.Unmarshal to do the conversion.\nfunc convert[T any](tb testing.TB, from any, to *T) *T {\n\ttb.Helper()\n\tbuf, err := json.Marshal(from)\n\trequire.NoError(tb, err)\n\trequire.NoError(tb, json.Unmarshal(buf, to))\n\treturn to\n}\n\n// asBool asserts that v is a boolean and returns v as a boolean.\nfunc asBool(tb testing.TB, v any) bool {\n\ttb.Helper()\n\trequire.IsType(tb, true, v)\n\tb, ok := v.(bool)\n\trequire.True(tb, ok)\n\treturn b\n}\n\n// asString asserts that v is a boolean and returns v as a boolean.\nfunc asString(tb testing.TB, v any) string {\n\ttb.Helper()\n\trequire.IsType(tb, \"\", v)\n\ts, ok := v.(string)\n\trequire.True(tb, ok)\n\treturn s\n}\n\n// toPtr is a helper function to convert a value to a pointer.\nfunc toPtr[T any](v T) *T {\n\treturn &v\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/test_browser_proxy.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gorilla/websocket\"\n)\n\n// testBrowserProxy wraps a testBrowser and\n// proxies WS messages to/from it.\ntype testBrowserProxy struct {\n\tt testing.TB\n\n\tmu sync.Mutex // avoid concurrent connect requests\n\n\ttb *testBrowser\n\tts *httptest.Server\n\n\tconnected bool\n}\n\nfunc newTestBrowserProxy(tb testing.TB, b *testBrowser) *testBrowserProxy {\n\ttb.Helper()\n\n\tp := &testBrowserProxy{\n\t\tt:  tb,\n\t\ttb: b,\n\t}\n\tp.ts = httptest.NewServer(p.connHandler())\n\n\treturn p\n}\n\nfunc (p *testBrowserProxy) wsURL() string {\n\tp.t.Helper()\n\n\ttsURL, err := url.Parse(p.ts.URL)\n\tif err != nil {\n\t\tp.t.Fatalf(\"error parsing test server URL: %v\", err)\n\t}\n\treturn fmt.Sprintf(\"ws://%s\", tsURL.Host)\n}\n\nfunc (p *testBrowserProxy) connHandler() http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tp.mu.Lock()\n\t\tdefer p.mu.Unlock()\n\n\t\tupgrader := websocket.Upgrader{} // default options\n\n\t\t// Upgrade in connection from client\n\t\tin, err := upgrader.Upgrade(w, r, nil)\n\t\tif err != nil {\n\t\t\tp.t.Fatalf(\"error upgrading proxy connection: %v\", err)\n\t\t}\n\t\tdefer in.Close() //nolint:errcheck\n\n\t\t// Connect to testBrowser CDP WS\n\t\tout, _, err := websocket.DefaultDialer.Dial(p.tb.wsURL, nil) //nolint:bodyclose\n\t\tif err != nil {\n\t\t\tp.t.Fatalf(\"error connecting to test browser: %v\", err)\n\t\t}\n\t\tdefer out.Close() //nolint:errcheck\n\n\t\tp.connected = true\n\n\t\t// Stop proxy when test exits\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tp.t.Cleanup(func() {\n\t\t\tcancel()     // stop forwarding mssgs\n\t\t\tp.ts.Close() // close test server\n\t\t})\n\n\t\tvar wg sync.WaitGroup\n\t\twg.Add(2)\n\n\t\tgo p.fwdMssgs(ctx, in, out, &wg)\n\t\tgo p.fwdMssgs(ctx, out, in, &wg)\n\n\t\twg.Wait()\n\t})\n}\n\nfunc (p *testBrowserProxy) fwdMssgs(ctx context.Context,\n\tin, out *websocket.Conn, wg *sync.WaitGroup,\n) {\n\tp.t.Helper()\n\tdefer wg.Done()\n\nLOOP:\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tbreak LOOP\n\t\tdefault:\n\t\t\tmt, message, err := in.ReadMessage()\n\t\t\tif err != nil {\n\t\t\t\tvar cerr *websocket.CloseError\n\t\t\t\tif errors.As(err, &cerr) {\n\t\t\t\t\t// If WS conn is closed, just return\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tp.t.Fatalf(\"error reading message: %v\", err)\n\t\t\t}\n\n\t\t\terr = out.WriteMessage(mt, message)\n\t\t\tif err != nil {\n\t\t\t\tvar cerr *websocket.CloseError\n\t\t\t\tif errors.As(err, &cerr) {\n\t\t\t\t\t// If WS conn is closed, just return\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tp.t.Fatalf(\"error writing message: %v\", err)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/test_browser_test.go",
    "content": "package tests\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/env\"\n)\n\nfunc TestTestBrowserAwaitWithTimeoutShortCircuit(t *testing.T) {\n\tt.Parallel()\n\ttb := newTestBrowser(t)\n\tstart := time.Now()\n\trequire.NoError(t, tb.awaitWithTimeout(time.Second*10, func() error {\n\t\truntime.Goexit() // this is what happens when a `require` fails\n\t\treturn nil\n\t}))\n\trequire.Less(t, time.Since(start), time.Second)\n}\n\n// testingT is a wrapper around testing.TB.\ntype testingT struct {\n\ttesting.TB\n\tfatalfCalled bool\n}\n\n// Fatalf skips the test immediately after a test is calling it.\n// This is useful when a test is expected to fail, but we don't\n// want to mark it as a failure since it's expected.\nfunc (t *testingT) Fatalf(format string, args ...any) {\n\tt.fatalfCalled = true\n\tt.SkipNow()\n}\n\nfunc TestTestBrowserWithLookupFunc(t *testing.T) {\n\t// Skip until we get answer from Chromium team in an open issue\n\t// https://issues.chromium.org/issues/364089353.\n\tt.Skip(\"Skipping until we get response from Chromium team\")\n\tt.Parallel()\n\n\ttt := &testingT{TB: t}\n\t// this operation is expected to fail because the remote debugging port is\n\t// invalid, practically testing that the InitEnv.LookupEnv is used.\n\t_ = newTestBrowser(\n\t\ttt,\n\t\twithEnvLookup(env.ConstLookup(env.BrowserArguments, \"remote-debugging-port=99999\")),\n\t)\n\trequire.True(t, tt.fatalfCalled)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/tracing_test.go",
    "content": "package tests\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"go.opentelemetry.io/otel/trace/embedded\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/browser\"\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/k6ext/k6test\"\n\tbrowsertrace \"go.k6.io/k6/internal/js/modules/k6/browser/trace\"\n\n\tk6lib \"go.k6.io/k6/lib\"\n)\n\nconst html = `\n<!DOCTYPE html>\n<html>\n\n<head>\n    <title>Clickable link test</title>\n</head>\n\n<body>\n\t<a id=\"top\" href=\"#bottom\">Go to bottom</a>\n\t<div class=\"main\">\n\t\t<h3>Click Counter</h3>\n\t\t<button id=\"clickme\">Click me: 0</button>\n\t\t<h3>Type input</h3>\n\t\t<input type=\"text\" id=\"typeme\">\n\t</div>\n    <script>\n\tvar button = document.getElementById(\"clickme\"),\n\tcount = 0;\n\tbutton.onclick = function() {\n\t\tcount += 1;\n\t\tbutton.innerHTML = \"Click me: \" + count;\n\t};\n    </script>\n\t<div id=\"bottom\"></div>\n</body>\n\n</html>\n`\n\n// TestTracing verifies that all methods instrumented to generate\n// traces behave correctly.\nfunc TestTracing(t *testing.T) {\n\tt.Parallel()\n\n\t// Init tracing mocks\n\ttracer := &mockTracer{\n\t\tspans: make(map[string]struct{}),\n\t}\n\ttp := &mockTracerProvider{\n\t\ttracer: tracer,\n\t}\n\t// Start test server\n\tts := httptest.NewServer(http.HandlerFunc(\n\t\tfunc(w http.ResponseWriter, r *http.Request) {\n\t\t\t_, err := fmt.Fprint(w, html)\n\t\t\trequire.NoError(t, err)\n\t\t},\n\t))\n\tdefer ts.Close()\n\n\t// Initialize VU and browser module\n\tvu := k6test.NewVU(t, k6test.WithTracerProvider(tp))\n\n\trt := vu.Runtime()\n\troot := browser.New()\n\tmod := root.NewModuleInstance(vu)\n\tjsMod, ok := mod.Exports().Default.(*browser.JSModule)\n\trequire.Truef(t, ok, \"unexpected default mod export type %T\", mod.Exports().Default)\n\trequire.NoError(t, rt.Set(\"browser\", jsMod.Browser))\n\tvu.ActivateVU()\n\n\t// Run the test\n\tvu.StartIteration(t)\n\trequire.NoError(t, tracer.verifySpans(\"iteration\"))\n\tsetupTestTracing(t, rt)\n\n\t// NOTE: These tests run sequentially, not in parallel. This has been done\n\t// on purpose.\n\ttestCases := []struct {\n\t\tname  string\n\t\tjs    string\n\t\tspans []string\n\t}{\n\t\t{\n\t\t\tname: \"browser.newPage\",\n\t\t\tjs:   \"page = await browser.newPage()\",\n\t\t\tspans: []string{\n\t\t\t\t\"browser.newPage\",\n\t\t\t\t\"browser.newContext\",\n\t\t\t\t\"browserContext.newPage\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"page.goto\",\n\t\t\tjs:   fmt.Sprintf(\"page.goto('%s')\", ts.URL),\n\t\t\tspans: []string{\n\t\t\t\t\"page.goto\",\n\t\t\t\t\"navigation\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"page.screenshot\",\n\t\t\tjs:   \"page.screenshot();\",\n\t\t\tspans: []string{\n\t\t\t\t\"page.screenshot\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"locator.click\",\n\t\t\tjs:   \"page.locator('#clickme').click();\",\n\t\t\tspans: []string{\n\t\t\t\t\"locator.click\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"locator.type\",\n\t\t\tjs:   \"page.locator('input#typeme').type('test');\",\n\t\t\tspans: []string{\n\t\t\t\t\"locator.type\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// In this test, since we're using waitForNavigation, which uses a\n\t\t\t// taskqueue, we need to manually clear it by calling page.close.\n\t\t\t// During normal testing runtime it would be cleared when we receive\n\t\t\t// a iterationEnd event from k6.\n\t\t\tname: \"page.reload\",\n\t\t\tjs: `await Promise.all([\n\t\t\t\t\tpage.waitForNavigation(),\n\t\t\t\t\tpage.reload(),\n\t\t\t\t]);\n\t\t\t\tawait page.close();`,\n\t\t\tspans: []string{\n\t\t\t\t\"page.reload\",\n\t\t\t\t\"page.waitForNavigation\",\n\t\t\t\t\"page.close\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"page.waitForTimeout\",\n\t\t\tjs: `page = await browser.context().newPage();\n\t\t\t\t await page.waitForTimeout(10);`,\n\t\t\tspans: []string{\n\t\t\t\t\"browserContext.newPage\",\n\t\t\t\t\"page.waitForTimeout\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"web_vital\",\n\t\t\tjs:   \"page.close();\", // on page.close, web vitals are collected and fired/received.\n\t\t\tspans: []string{\n\t\t\t\t\"web_vital\",\n\t\t\t\t\"page.close\",\n\t\t\t},\n\t\t},\n\t}\n\n\t// Each sub test depends on the previous sub test, so they cannot be ran\n\t// in parallel.\n\tfor _, tc := range testCases {\n\t\tassertJSInEventLoop(t, vu, tc.js)\n\n\t\trequire.NoError(t, tracer.verifySpans(tc.spans...))\n\t}\n}\n\n// This test is testing to ensure that correct number of navigation spans are created\n// and they are created in the correct order.\nfunc TestNavigationSpanCreation(t *testing.T) {\n\tt.Parallel()\n\tsetup := func(t *testing.T) (*mockTracer, *httptest.Server, *k6test.VU) {\n\t\tt.Helper()\n\t\ttracer := &mockTracer{\n\t\t\tspans: make(map[string]struct{}),\n\t\t}\n\t\ttp := &mockTracerProvider{\n\t\t\ttracer: tracer,\n\t\t}\n\t\t// Start test server\n\t\tts := httptest.NewServer(http.HandlerFunc(\n\t\t\tfunc(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t_, err := fmt.Fprint(w, html)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t},\n\t\t))\n\t\tt.Cleanup(ts.Close)\n\n\t\t// Initialize VU and browser module\n\t\tvu := k6test.NewVU(t, k6test.WithTracerProvider(tp))\n\n\t\trt := vu.Runtime()\n\t\troot := browser.New()\n\t\tmod := root.NewModuleInstance(vu)\n\t\tjsMod, ok := mod.Exports().Default.(*browser.JSModule)\n\t\trequire.Truef(t, ok, \"unexpected default mod export type %T\", mod.Exports().Default)\n\t\trequire.NoError(t, rt.Set(\"browser\", jsMod.Browser))\n\t\tvu.ActivateVU()\n\t\treturn tracer, ts, vu\n\t}\n\n\ttestCases := []struct {\n\t\tname     string\n\t\tjs       string\n\t\texpected []string\n\t}{\n\t\t{\n\t\t\tname: \"goto\",\n\t\t\tjs: `\n\t\t\t\tpage = await browser.newPage();\n\t\t\t\tawait page.goto('%s', {waitUntil:'networkidle'});\n\t\t\t\tawait page.close();\n\t\t\t\t`,\n\t\t\texpected: []string{\n\t\t\t\t\"iteration\",\n\t\t\t\t\"browser.newPage\",\n\t\t\t\t\"browser.newContext\",\n\t\t\t\t\"browserContext.newPage\",\n\t\t\t\t\"navigation\", // created when a new page is created\n\t\t\t\t\"page.goto\",\n\t\t\t\t\"navigation\", // created when a navigation occurs after goto\n\t\t\t\t\"page.close\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"reload\",\n\t\t\tjs: `\n\t\t\t\tpage = await browser.newPage();\n\t\t\t\tawait page.goto('%s', {waitUntil:'networkidle'});\n\t\t\t\tawait page.reload({waitUntil:'networkidle'});\n\t\t\t\tawait page.close();\n\t\t\t\t`,\n\t\t\texpected: []string{\n\t\t\t\t\"iteration\",\n\t\t\t\t\"browser.newPage\",\n\t\t\t\t\"browser.newContext\",\n\t\t\t\t\"browserContext.newPage\",\n\t\t\t\t\"navigation\", // created when a new page is created\n\t\t\t\t\"page.goto\",\n\t\t\t\t\"navigation\", // created when a navigation occurs after goto\n\t\t\t\t\"page.reload\",\n\t\t\t\t\"navigation\", // created when a navigation occurs after reload\n\t\t\t\t\"page.close\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"go_back\",\n\t\t\tjs: `\n\t\t\t\tpage = await browser.newPage();\n\t\t\t\tawait page.goto('%s', {waitUntil:'networkidle'});\n\t\t\t\tawait page.goBack();\n\t\t\t\tawait page.close();\n\t\t\t\t`,\n\t\t\texpected: []string{\n\t\t\t\t\"iteration\",\n\t\t\t\t\"browser.newPage\",\n\t\t\t\t\"browser.newContext\",\n\t\t\t\t\"browserContext.newPage\",\n\t\t\t\t\"navigation\", // created when a new page is created\n\t\t\t\t\"page.goto\",\n\t\t\t\t\"navigation\", // created when a navigation occurs after goto\n\t\t\t\t\"page.goBack\",\n\t\t\t\t\"navigation\", // created when going back to the previous page\n\t\t\t\t\"page.close\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"same_page_navigation\",\n\t\t\tjs: `\n\t\t\t\tpage = await browser.newPage();\n\t\t\t\tawait page.goto('%s', {waitUntil:'networkidle'});\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tpage.waitForNavigation(),\n\t\t\t\t\tpage.locator('a[id=\\\"top\\\"]').click(),\n\t\t\t\t]);\n\t\t\t\tawait page.close();\n\t\t\t\t`,\n\t\t\texpected: []string{\n\t\t\t\t\"iteration\",\n\t\t\t\t\"browser.newPage\",\n\t\t\t\t\"browser.newContext\",\n\t\t\t\t\"browserContext.newPage\",\n\t\t\t\t\"navigation\", // created when a new page is created\n\t\t\t\t\"page.goto\",\n\t\t\t\t\"navigation\", // created when a navigation occurs after goto\n\t\t\t\t\"page.waitForNavigation\",\n\t\t\t\t\"locator.click\",\n\t\t\t\t\"navigation\", // created when navigating within the same page\n\t\t\t\t\"page.close\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t// Init tracing mocks\n\t\t\ttracer, ts, vu := setup(t)\n\t\t\t// Run the test\n\t\t\tvu.StartIteration(t)\n\t\t\tdefer vu.EndIteration(t)\n\n\t\t\tassertJSInEventLoop(t, vu, fmt.Sprintf(tc.js, ts.URL))\n\n\t\t\tgot := tracer.cloneOrderedSpans()\n\t\t\t// We can't use assert.Equal since the order of the span creation\n\t\t\t// changes slightly on every test run. Instead we're going to make\n\t\t\t// sure that the slice matches but not the order.\n\t\t\tassert.ElementsMatch(t, tc.expected, got, fmt.Sprintf(\"%s failed\", tc.name))\n\t\t})\n\t}\n}\n\nfunc setupTestTracing(t *testing.T, rt *sobek.Runtime) {\n\tt.Helper()\n\n\t// Declare a global page var that we can use\n\t// throughout the test cases\n\t_, err := rt.RunString(\"var page;\")\n\trequire.NoError(t, err)\n\n\t// Set a sleep function so we can use it to wait\n\t// for async WebVitals processing\n\terr = rt.Set(\"sleep\", func(d int) {\n\t\ttime.Sleep(time.Duration(d) * time.Millisecond)\n\t})\n\trequire.NoError(t, err)\n}\n\nfunc assertJSInEventLoop(t *testing.T, vu *k6test.VU, js string) {\n\tt.Helper()\n\n\tf := fmt.Sprintf(\n\t\t\"test = async function() { %s; }\",\n\t\tjs)\n\n\trt := vu.Runtime()\n\t_, err := rt.RunString(f)\n\trequire.NoError(t, err)\n\n\ttest, ok := sobek.AssertFunction(rt.Get(\"test\"))\n\trequire.True(t, ok)\n\n\terr = vu.Loop.Start(func() error {\n\t\t_, err := test(sobek.Undefined())\n\t\treturn err\n\t})\n\trequire.NoError(t, err)\n}\n\ntype mockTracerProvider struct {\n\tk6lib.TracerProvider\n\n\ttracer trace.Tracer\n}\n\nfunc (m *mockTracerProvider) Tracer(\n\tname string, options ...trace.TracerOption,\n) trace.Tracer {\n\treturn m.tracer\n}\n\ntype mockTracer struct {\n\tembedded.Tracer\n\n\tmu           sync.Mutex\n\tspans        map[string]struct{}\n\torderedSpans []string\n}\n\nfunc (m *mockTracer) Start(\n\tctx context.Context, spanName string, opts ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tm.spans[spanName] = struct{}{}\n\n\t// Ignore web_vital spans since they're non deterministic.\n\tif spanName != \"web_vital\" {\n\t\tm.orderedSpans = append(m.orderedSpans, spanName)\n\t}\n\n\treturn ctx, browsertrace.NoopSpan{}\n}\n\nfunc (m *mockTracer) verifySpans(spanNames ...string) error {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tfor _, sn := range spanNames {\n\t\tif _, ok := m.spans[sn]; !ok {\n\t\t\treturn fmt.Errorf(\"%q span was not found\", sn)\n\t\t}\n\t\tdelete(m.spans, sn)\n\t}\n\n\treturn nil\n}\n\nfunc (m *mockTracer) cloneOrderedSpans() []string {\n\tm.mu.Lock()\n\tdefer m.mu.Unlock()\n\n\tc := make([]string, len(m.orderedSpans))\n\tcopy(c, m.orderedSpans)\n\n\tm.orderedSpans = []string{}\n\n\treturn c\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/webvital_test.go",
    "content": "package tests\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/browser/common\"\n\n\tk6metrics \"go.k6.io/k6/metrics\"\n)\n\n// TestWebVitalMetric is asserting that web vital metrics\n// are being emitted when navigating and interacting with\n// a web page.\nfunc TestWebVitalMetric(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"timeouts on windows\")\n\t}\n\tvar (\n\t\tsamples  = make(chan k6metrics.SampleContainer, 1000)\n\t\tbrowser  = newTestBrowser(t, withFileServer(), withSamples(samples))\n\t\tpage     = browser.NewPage(nil)\n\t\texpected = map[string]bool{\n\t\t\t\"browser_web_vital_ttfb\": false,\n\t\t\t\"browser_web_vital_fcp\":  false,\n\t\t\t\"browser_web_vital_lcp\":  false,\n\t\t\t\"browser_web_vital_fid\":  false,\n\t\t\t\"browser_web_vital_cls\":  false,\n\t\t}\n\t)\n\n\topts := &common.FrameGotoOptions{\n\t\tTimeout: common.DefaultTimeout,\n\t}\n\tresp, err := page.Goto(\n\t\tbrowser.staticURL(\"/web_vitals.html\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, resp)\n\n\t// A click action helps measure first input delay.\n\t// The click action also refreshes the page, which\n\t// also helps the web vital library to measure CLS.\n\terr = browser.run(\n\t\tbrowser.context(),\n\t\tfunc() error { return page.Click(\"#clickMe\", common.NewFrameClickOptions(page.Timeout())) },\n\t\tfunc() error {\n\t\t\t_, err := page.WaitForNavigation(\n\t\t\t\tcommon.NewFrameWaitForNavigationOptions(page.Timeout()), nil)\n\t\t\treturn err\n\t\t},\n\t)\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, page.Close())\n\tclose(samples)\n\tmarkExpectedWebVitalsFromSamples(samples, expected)\n\n\tfor k, v := range expected {\n\t\tassert.True(t, v, \"expected %s to have been measured and emitted\", k)\n\t}\n}\n\nfunc TestWebVitalMetricNoInteraction(t *testing.T) {\n\tt.Parallel()\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"timeouts on windows\")\n\t}\n\tvar (\n\t\tsamples  = make(chan k6metrics.SampleContainer, 1000)\n\t\tbrowser  = newTestBrowser(t, withFileServer(), withSamples(samples))\n\t\texpected = map[string]bool{\n\t\t\t\"browser_web_vital_ttfb\": false,\n\t\t\t\"browser_web_vital_fcp\":  false,\n\t\t\t\"browser_web_vital_lcp\":  false,\n\t\t\t\"browser_web_vital_cls\":  false,\n\t\t}\n\t)\n\n\tpage := browser.NewPage(nil)\n\topts := &common.FrameGotoOptions{\n\t\t// Wait for both load and network idle events\n\t\tWaitUntil: common.LifecycleEventNetworkIdle,\n\t\tTimeout:   common.DefaultTimeout,\n\t}\n\tresp, err := page.Goto(\n\t\tbrowser.staticURL(\"web_vitals.html\"),\n\t\topts,\n\t)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, resp)\n\n\trequire.NoError(t, page.Close())\n\tclose(samples)\n\tmarkExpectedWebVitalsFromSamples(samples, expected)\n\n\tfor k, v := range expected {\n\t\tassert.True(t, v, \"expected %s to have been measured and emitted\", k)\n\t}\n}\n\nfunc markExpectedWebVitalsFromSamples(samples <-chan k6metrics.SampleContainer, expected map[string]bool) {\n\tfor metric := range samples {\n\t\tfor _, s := range metric.GetSamples() {\n\t\t\tif _, ok := expected[s.Metric.Name]; ok {\n\t\t\t\texpected[s.Metric.Name] = true\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/tests/ws/server.go",
    "content": "// Package ws provides a test WebSocket server.\npackage ws\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\tk6netext \"go.k6.io/k6/lib/netext\"\n\tk6types \"go.k6.io/k6/lib/types\"\n\n\t\"github.com/chromedp/cdproto\"\n\tjsonv2 \"github.com/go-json-experiment/json\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/mccutchen/go-httpbin/v2/httpbin\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/net/http2\"\n)\n\n//nolint:gochecknoglobals\nvar defaultJSONV2Options = jsonv2.JoinOptions(\n\tjsonv2.DefaultOptionsV2(),\n\tjsontext.AllowInvalidUTF8(true), // this is needed as chromium sometimes returns invalid utf-8\n)\n\n// Server can be used as a test alternative to a real CDP compatible browser.\ntype Server struct {\n\tt             testing.TB\n\tMux           *http.ServeMux\n\tServerHTTP    *httptest.Server\n\tDialer        *k6netext.Dialer\n\tHTTPTransport *http.Transport\n\tContext       context.Context\n}\n\n// NewServer returns a fully configured and running WS test server.\nfunc NewServer(t testing.TB, opts ...func(*Server)) *Server {\n\tt.Helper()\n\n\t// Create a http.ServeMux and set the httpbin handler as the default\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/\", httpbin.New().Handler())\n\n\t// Initialize the HTTP server and get its details\n\tserver := httptest.NewServer(mux)\n\turl, err := url.Parse(server.URL)\n\trequire.NoError(t, err)\n\tip := net.ParseIP(url.Hostname())\n\trequire.NotNil(t, ip)\n\tdomain, err := k6types.NewHost(ip, \"\")\n\trequire.NoError(t, err)\n\n\t// Set up the dialer with shorter timeouts and the custom domains\n\tdialer := k6netext.NewDialer(net.Dialer{\n\t\tTimeout:   2 * time.Second,\n\t\tKeepAlive: 10 * time.Second,\n\t\tDualStack: true,\n\t}, k6netext.NewResolver(net.LookupIP, 0, k6types.DNSfirst, k6types.DNSpreferIPv4))\n\n\tconst wsURL = \"wsbin.local\"\n\tdialer.Hosts, err = k6types.NewHosts(map[string]k6types.Host{\n\t\twsURL: *domain,\n\t})\n\trequire.NoError(t, err, \"failed to set up dialer hosts\")\n\n\t// Pre-configure the HTTP client transport with the dialer and TLS config (incl. HTTP2 support)\n\ttransport := &http.Transport{\n\t\tDialContext: dialer.DialContext,\n\t}\n\trequire.NoError(t, http2.ConfigureTransport(transport))\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tt.Cleanup(func() {\n\t\tserver.Close()\n\t\tcancel()\n\t})\n\ts := &Server{\n\t\tt:             t,\n\t\tMux:           mux,\n\t\tServerHTTP:    server,\n\t\tDialer:        dialer,\n\t\tHTTPTransport: transport,\n\t\tContext:       ctx,\n\t}\n\tfor _, opt := range opts {\n\t\topt(s)\n\t}\n\treturn s\n}\n\n// WithClosureAbnormalHandler attaches an abnormal closure behavior to Server.\nfunc WithClosureAbnormalHandler(path string) func(*Server) {\n\thandler := func(w http.ResponseWriter, req *http.Request) {\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\tif err != nil {\n\t\t\t// TODO: log\n\t\t\treturn\n\t\t}\n\t\terr = conn.Close() // This forces a connection closure without a proper WS close message exchange\n\t\tif err != nil {\n\t\t\t// TODO: log\n\t\t\treturn\n\t\t}\n\t}\n\treturn func(s *Server) {\n\t\ts.Mux.Handle(path, http.HandlerFunc(handler))\n\t}\n}\n\n// WithEchoHandler attaches an echo handler to Server.\nfunc WithEchoHandler(path string) func(*Server) {\n\thandler := func(w http.ResponseWriter, req *http.Request) {\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tmessageType, r, e := conn.NextReader()\n\t\tif e != nil {\n\t\t\treturn\n\t\t}\n\t\tvar wc io.WriteCloser\n\t\twc, err = conn.NextWriter(messageType)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tif _, err = io.Copy(wc, r); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif err = wc.Close(); err != nil {\n\t\t\treturn\n\t\t}\n\t\terr = conn.WriteControl(websocket.CloseMessage,\n\t\t\twebsocket.FormatCloseMessage(websocket.CloseNormalClosure, \"\"),\n\t\t\ttime.Now().Add(10*time.Second),\n\t\t)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\treturn func(s *Server) {\n\t\ts.Mux.Handle(path, http.HandlerFunc(handler))\n\t}\n}\n\n// WithCDPHandler attaches a custom CDP handler function to Server.\n//\n//nolint:gocognit\nfunc WithCDPHandler(\n\tpath string,\n\tfn func(conn *websocket.Conn, msg *cdproto.Message, writeCh chan cdproto.Message, done chan struct{}),\n\tcmdsReceived *[]cdproto.MethodType,\n) func(*Server) {\n\thandler := func(w http.ResponseWriter, req *http.Request) {\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\tdone := make(chan struct{})\n\t\twriteCh := make(chan cdproto.Message)\n\n\t\tgo func() {\n\t\t\tread := func(conn *websocket.Conn) (*cdproto.Message, error) {\n\t\t\t\t_, buf, err := conn.ReadMessage()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\tvar msg cdproto.Message\n\t\t\t\terr = jsonv2.Unmarshal(buf, &msg, defaultJSONV2Options)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\treturn &msg, nil\n\t\t\t}\n\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-done:\n\t\t\t\t\treturn\n\t\t\t\tdefault:\n\t\t\t\t}\n\n\t\t\t\tmsg, err := read(conn)\n\t\t\t\tif err != nil {\n\t\t\t\t\tclose(done)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif msg.Method != \"\" && cmdsReceived != nil {\n\t\t\t\t\t*cmdsReceived = append(*cmdsReceived, msg.Method)\n\t\t\t\t}\n\n\t\t\t\tfn(conn, msg, writeCh, done)\n\t\t\t}\n\t\t}()\n\n\t\tgo func() {\n\t\t\twrite := func(conn *websocket.Conn, msg *cdproto.Message) {\n\t\t\t\twriter, err := conn.NextWriter(websocket.TextMessage)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tencoder := jsontext.NewEncoder(writer)\n\t\t\t\terr = jsonv2.MarshalEncode(encoder, msg, defaultJSONV2Options)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif err := writer.Close(); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase msg := <-writeCh:\n\t\t\t\t\twrite(conn, &msg)\n\t\t\t\tcase <-done:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\n\t\t<-done // Wait for done channel to be closed before closing connection\n\t}\n\treturn func(s *Server) {\n\t\ts.Mux.Handle(path, http.HandlerFunc(handler))\n\t}\n}\n\n// CDPDefaultHandler is a default handler for the CDP WS server.\nfunc CDPDefaultHandler(conn *websocket.Conn, msg *cdproto.Message, writeCh chan cdproto.Message, done chan struct{}) {\n\tconst (\n\t\ttargetAttachedToTargetEvent = `\n\t\t{\n\t\t\t\"sessionId\": \"session_id_0123456789\",\n\t\t\t\"targetInfo\": {\n\t\t\t\t\"targetId\": \"target_id_0123456789\",\n\t\t\t\t\"type\": \"page\",\n\t\t\t\t\"title\": \"\",\n\t\t\t\t\"url\": \"about:blank\",\n\t\t\t\t\"attached\": true,\n\t\t\t\t\"browserContextId\": \"browser_context_id_0123456789\"\n\t\t\t},\n\t\t\t\"waitingForDebugger\": false\n\t\t}`\n\n\t\ttargetAttachedToTargetResult = `\n\t\t{\n\t\t\t\"sessionId\":\"session_id_0123456789\"\n\t\t}`\n\t)\n\n\tif msg.SessionID != \"\" && msg.Method != \"\" {\n\t\twriteCh <- cdproto.Message{\n\t\t\tID:        msg.ID,\n\t\t\tSessionID: msg.SessionID,\n\t\t}\n\t} else if msg.Method != \"\" {\n\t\tswitch msg.Method {\n\t\tcase cdproto.MethodType(cdproto.CommandTargetAttachToTarget):\n\t\t\twriteCh <- cdproto.Message{\n\t\t\t\tMethod: cdproto.EventTargetAttachedToTarget,\n\t\t\t\tParams: jsontext.Value([]byte(targetAttachedToTargetEvent)),\n\t\t\t}\n\t\t\twriteCh <- cdproto.Message{\n\t\t\t\tID:        msg.ID,\n\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\tResult:    jsontext.Value([]byte(targetAttachedToTargetResult)),\n\t\t\t}\n\t\tdefault:\n\t\t\twriteCh <- cdproto.Message{\n\t\t\t\tID:        msg.ID,\n\t\t\t\tSessionID: msg.SessionID,\n\t\t\t\tResult:    jsontext.Value([]byte(\"{}\")),\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/browser/trace/trace.go",
    "content": "// Package trace provides tracing instrumentation tailored for k6 browser needs.\npackage trace\n\nimport (\n\t\"context\"\n\t\"sync\"\n\n\t\"go.opentelemetry.io/otel/attribute\"\n\t\"go.opentelemetry.io/otel/codes\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"go.opentelemetry.io/otel/trace/noop\"\n\n\tk6lib \"go.k6.io/k6/lib\"\n)\n\nconst tracerName = \"k6.browser\"\n\n// liveSpan represents an active span associated with a page navigation.\n//\n// Because a frame navigation and WebVitals event parsing happen async\n// (see frame_session/onFrameNavigated and frame_session/parseAndEmitWebVitalMetric)\n// there is not a reference to the last span generated from these methods, therefore\n// we have to keep a reference to the active span for each frame from the tracer\n// and make this accessible for these methods.\ntype liveSpan struct {\n\tctx  context.Context\n\tspan trace.Span\n}\n\n// Tracer represents a traces generator tailored to k6 browser needs.\n// Specifically implements methods to generate spans for navigations, API calls and page events,\n// accepting input parameters that allow correlating async operations, such as Web Vitals events,\n// with the page to which they belong to.\ntype Tracer struct {\n\ttrace.Tracer\n\n\tmetadata []attribute.KeyValue\n\n\tliveSpansMu sync.RWMutex\n\tliveSpans   map[string]*liveSpan\n}\n\n// NewTracer creates a new Tracer from the given TracerProvider.\nfunc NewTracer(tp k6lib.TracerProvider, metadata map[string]string, options ...trace.TracerOption) *Tracer {\n\treturn &Tracer{\n\t\tTracer:    tp.Tracer(tracerName, options...),\n\t\tmetadata:  buildMetadataAttributes(metadata),\n\t\tliveSpans: make(map[string]*liveSpan),\n\t}\n}\n\n// Start overrides the underlying OTEL tracer method to include the tracer metadata.\nfunc (t *Tracer) Start(\n\tctx context.Context, spanName string, opts ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\topts = append(opts, trace.WithAttributes(t.metadata...))\n\treturn t.Tracer.Start(ctx, spanName, opts...)\n}\n\n// TraceAPICall adds a new span to the current liveSpan for the given targetID and returns it. It\n// is the caller's responsibility to close the generated span.\n// If there is not a liveSpan for the given targetID, the new span is created based on the given\n// context, which means that it might be a root span or not depending if the context already wraps\n// a span.\nfunc (t *Tracer) TraceAPICall(\n\tctx context.Context, targetID string, spanName string, opts ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\tt.liveSpansMu.Lock()\n\tdefer t.liveSpansMu.Unlock()\n\n\topts = append(opts, trace.WithAttributes(t.metadata...))\n\n\tls := t.liveSpans[targetID]\n\tif ls == nil {\n\t\treturn t.Start(ctx, spanName, opts...)\n\t}\n\n\treturn t.Start(ls.ctx, spanName, opts...)\n}\n\n// TraceNavigation is only to be used when a frame has navigated.\n// It records a new liveSpan for the given targetID which identifies the frame that\n// has navigated. If there was already a liveSpan for the given targetID, it is closed\n// before creating the new one, otherwise it's the caller's responsibility to close the\n// generated span.\n// Posterior calls to TraceEvent or TraceAPICall given the same targetID will try to\n// associate new spans for these actions to the liveSpan created in this call.\nfunc (t *Tracer) TraceNavigation(\n\tctx context.Context, targetID string, opts ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\tt.liveSpansMu.Lock()\n\tdefer t.liveSpansMu.Unlock()\n\n\t// TODO: Should we keep track of all spans, even ones that are closed, to\n\t// ensure we associate web vitals to the spans in the current iteration?\n\n\tls := t.liveSpans[targetID]\n\tif ls != nil {\n\t\t// If there is a previous live span\n\t\t// for the targetID, end it\n\t\tls.span.End()\n\t} else {\n\t\tls = &liveSpan{}\n\t}\n\n\topts = append(opts, trace.WithAttributes(t.metadata...))\n\n\tls.ctx, ls.span = t.Start(ctx, \"navigation\", opts...)\n\tt.liveSpans[targetID] = ls\n\n\treturn ls.ctx, ls.span\n}\n\n// TraceEvent creates a new span representing the specified event and associates it with the current\n// liveSpan for the given targetID only if the spanID matches with the liveSpan.\n// It is the caller's responsibility to close the generated span.\n//\n// If no liveSpan is found for the given targetID, the action is ignored and a noopSpan is returned.\n// If the given spanID does not match the one for the current liveSpan associated with the targetID,\n// it means the specified target has navigated, generating a new span for that navigation, therefore\n// the event is not associated with that span, and instead a noopSpan is returned.\nfunc (t *Tracer) TraceEvent(\n\tctx context.Context, targetID string, eventName string, spanID string, opts ...trace.SpanStartOption,\n) (context.Context, trace.Span) {\n\tt.liveSpansMu.Lock()\n\tdefer t.liveSpansMu.Unlock()\n\n\tls := t.liveSpans[targetID]\n\tif ls == nil {\n\t\t// If there is not a liveSpan for the given targetID,\n\t\t// avoid associating the event with the root span possibly\n\t\t// wrapped in ctx, and instead return a noopSpan\n\t\treturn ctx, NoopSpan{}\n\t}\n\n\tsid := ls.span.SpanContext().SpanID().String()\n\tif sid != spanID {\n\t\t// If the given spanID does not match the current liveSpan for\n\t\t// targetID, it means the target has navigated to a different\n\t\t// page than the one the event should be associated with.\n\t\t// Therefore avoid associating the event with the current span,\n\t\t// and return a noopSpan instead\n\t\treturn ctx, NoopSpan{}\n\t}\n\n\topts = append(opts, trace.WithAttributes(t.metadata...))\n\n\treturn t.Start(ls.ctx, eventName, opts...)\n}\n\nfunc buildMetadataAttributes(metadata map[string]string) []attribute.KeyValue {\n\tmeta := make([]attribute.KeyValue, 0, len(metadata))\n\tfor mk, mv := range metadata {\n\t\tmeta = append(meta, attribute.String(mk, mv))\n\t}\n\n\treturn meta\n}\n\n// NoopSpan represents a noop span.\ntype NoopSpan struct {\n\ttrace.Span\n}\n\n// SpanContext returns a void span context.\nfunc (NoopSpan) SpanContext() trace.SpanContext { return trace.SpanContext{} }\n\n// IsRecording returns false.\nfunc (NoopSpan) IsRecording() bool { return false }\n\n// SetStatus is noop.\nfunc (NoopSpan) SetStatus(codes.Code, string) {}\n\n// SetError is noop.\nfunc (NoopSpan) SetError(bool) {}\n\n// SetAttributes is noop.\nfunc (NoopSpan) SetAttributes(...attribute.KeyValue) {}\n\n// End is noop.\nfunc (NoopSpan) End(...trace.SpanEndOption) {}\n\n// RecordError is noop.\nfunc (NoopSpan) RecordError(error, ...trace.EventOption) {}\n\n// AddEvent is noop.\nfunc (NoopSpan) AddEvent(string, ...trace.EventOption) {}\n\n// SetName is noop.\nfunc (NoopSpan) SetName(string) {}\n\n// TracerProvider returns a noop tracer provider.\nfunc (NoopSpan) TracerProvider() trace.TracerProvider { return noop.NewTracerProvider() }\n"
  },
  {
    "path": "internal/js/modules/k6/crypto/crypto.go",
    "content": "// Package crypto provides common hashing function for the k6\npackage crypto\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/md5\" // #nosec G501 // MD5 is weak, but we need it for compatibility\n\t\"crypto/rand\"\n\t\"crypto/sha1\" // #nosec G505 // SHA1 is weak, but we need it for compatibility\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash\"\n\n\t\"golang.org/x/crypto/md4\"       //nolint:gosec,staticcheck // MD4 is weak, but we need it for compatibility\n\t\"golang.org/x/crypto/ripemd160\" //nolint:gosec,staticcheck // RIPEMD160 is weak, but we need it for compatibility\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// Crypto represents an instance of the crypto module.\n\tCrypto struct {\n\t\trandReader func(b []byte) (n int, err error)\n\t\tvu         modules.VU\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &Crypto{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &Crypto{vu: vu, randReader: rand.Read}\n}\n\n// Exports returns the exports of the execution module.\nfunc (c *Crypto) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"createHash\":  c.createHash,\n\t\t\t\"createHMAC\":  c.createHMAC,\n\t\t\t\"hmac\":        c.hmac,\n\t\t\t\"md4\":         c.md4,\n\t\t\t\"md5\":         c.md5,\n\t\t\t\"randomBytes\": c.randomBytes,\n\t\t\t\"ripemd160\":   c.ripemd160,\n\t\t\t\"sha1\":        c.sha1,\n\t\t\t\"sha256\":      c.sha256,\n\t\t\t\"sha384\":      c.sha384,\n\t\t\t\"sha512\":      c.sha512,\n\t\t\t\"sha512_224\":  c.sha512_224,\n\t\t\t\"sha512_256\":  c.sha512_256,\n\t\t\t\"hexEncode\":   c.hexEncode,\n\t\t},\n\t}\n}\n\n// randomBytes returns random data of the given size.\nfunc (c *Crypto) randomBytes(size int) (*sobek.ArrayBuffer, error) {\n\tif size < 1 {\n\t\treturn nil, errors.New(\"invalid size\")\n\t}\n\tbytes := make([]byte, size)\n\t_, err := c.randReader(bytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tab := c.vu.Runtime().NewArrayBuffer(bytes)\n\treturn &ab, nil\n}\n\n// md4 returns the MD4 hash of input in the given encoding.\nfunc (c *Crypto) md4(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"md4\", input, outputEncoding)\n}\n\n// md5 returns the MD5 hash of input in the given encoding.\nfunc (c *Crypto) md5(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"md5\", input, outputEncoding)\n}\n\n// sha1 returns the SHA1 hash of input in the given encoding.\nfunc (c *Crypto) sha1(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"sha1\", input, outputEncoding)\n}\n\n// sha256 returns the SHA256 hash of input in the given encoding.\nfunc (c *Crypto) sha256(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"sha256\", input, outputEncoding)\n}\n\n// sha384 returns the SHA384 hash of input in the given encoding.\nfunc (c *Crypto) sha384(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"sha384\", input, outputEncoding)\n}\n\n// sha512 returns the SHA512 hash of input in the given encoding.\nfunc (c *Crypto) sha512(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"sha512\", input, outputEncoding)\n}\n\n// sha512_224 returns the SHA512/224 hash of input in the given encoding.\nfunc (c *Crypto) sha512_224(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"sha512_224\", input, outputEncoding)\n}\n\n// shA512_256 returns the SHA512/256 hash of input in the given encoding.\nfunc (c *Crypto) sha512_256(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"sha512_256\", input, outputEncoding)\n}\n\n// ripemd160 returns the RIPEMD160 hash of input in the given encoding.\nfunc (c *Crypto) ripemd160(input any, outputEncoding string) (any, error) {\n\treturn c.buildInputsDigest(\"ripemd160\", input, outputEncoding)\n}\n\n// createHash returns a Hasher instance that uses the given algorithm.\nfunc (c *Crypto) createHash(algorithm string) *Hasher {\n\thashfn := c.parseHashFunc(algorithm)\n\treturn &Hasher{\n\t\truntime: c.vu.Runtime(),\n\t\thash:    hashfn(),\n\t}\n}\n\n// buildInputsDigest implements basic digest calculation for given algorithm and input/output\nfunc (c *Crypto) buildInputsDigest(alg string, input any, outputEncoding string) (any, error) {\n\thasher := c.createHash(alg)\n\n\tif err := hasher.Update(input); err != nil {\n\t\treturn nil, fmt.Errorf(\"%s failed: %w\", alg, err)\n\t}\n\n\treturn hasher.Digest(outputEncoding)\n}\n\n// hexEncode returns a string with the hex representation of the provided byte\n// array or ArrayBuffer.\nfunc (c *Crypto) hexEncode(data any) (string, error) {\n\td, err := common.ToBytes(data)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn hex.EncodeToString(d), nil\n}\n\n// createHMAC returns a new HMAC hash using the given algorithm and key.\nfunc (c *Crypto) createHMAC(algorithm string, key any) (*Hasher, error) {\n\th := c.parseHashFunc(algorithm)\n\tif h == nil {\n\t\treturn nil, fmt.Errorf(\"invalid algorithm: %s\", algorithm)\n\t}\n\n\tkb, err := common.ToBytes(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Hasher{runtime: c.vu.Runtime(), hash: hmac.New(h, kb)}, nil\n}\n\n// HMAC returns a new HMAC hash of input using the given algorithm and key\n// in the given encoding.\nfunc (c *Crypto) hmac(algorithm string, key, input any, outputEncoding string) (any, error) {\n\thasher, err := c.createHMAC(algorithm, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = hasher.Update(input)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn hasher.Digest(outputEncoding)\n}\n\nfunc (c *Crypto) parseHashFunc(a string) func() hash.Hash {\n\tvar h func() hash.Hash\n\tswitch a {\n\tcase \"md4\":\n\t\th = md4.New\n\tcase \"md5\":\n\t\th = md5.New\n\tcase \"sha1\":\n\t\th = sha1.New\n\tcase \"sha256\":\n\t\th = sha256.New\n\tcase \"sha384\":\n\t\th = sha512.New384\n\tcase \"sha512_224\":\n\t\th = sha512.New512_224\n\tcase \"sha512_256\":\n\t\th = sha512.New512_256\n\tcase \"sha512\":\n\t\th = sha512.New\n\tcase \"ripemd160\":\n\t\th = ripemd160.New\n\t}\n\treturn h\n}\n\n// Hasher wraps an hash.Hash with sobek.Runtime.\ntype Hasher struct {\n\truntime *sobek.Runtime\n\thash    hash.Hash\n}\n\n// Update the hash with the input data.\nfunc (hasher *Hasher) Update(input any) error {\n\td, err := common.ToBytes(input)\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = hasher.hash.Write(d)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Digest returns the hash value in the given encoding.\nfunc (hasher *Hasher) Digest(outputEncoding string) (any, error) {\n\tsum := hasher.hash.Sum(nil)\n\n\tswitch outputEncoding {\n\tcase \"base64\":\n\t\treturn base64.StdEncoding.EncodeToString(sum), nil\n\n\tcase \"base64url\":\n\t\treturn base64.URLEncoding.EncodeToString(sum), nil\n\n\tcase \"base64rawurl\":\n\t\treturn base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(sum), nil\n\n\tcase \"hex\":\n\t\treturn hex.EncodeToString(sum), nil\n\n\tcase \"binary\":\n\t\tab := hasher.runtime.NewArrayBuffer(sum)\n\t\treturn &ab, nil\n\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid output encoding: %s\", outputEncoding)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/crypto/crypto_test.go",
    "content": "package crypto\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\ntype MockReader struct{}\n\nfunc (MockReader) Read(_ []byte) (int, error) {\n\treturn -1, errors.New(\"Contrived failure\")\n}\n\nfunc makeRuntime(t *testing.T) *sobek.Runtime {\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tInitEnvField: &common.InitEnvironment{},\n\t\t\tCtxField:     context.Background(),\n\t\t\tStateField:   nil,\n\t\t},\n\t).(*Crypto)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"crypto\", m.Exports().Named))\n\n\treturn rt\n}\n\nfunc TestCryptoAlgorithms(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\tt.Run(\"RandomBytesSuccess\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar buf = crypto.randomBytes(5);\n\t\tif (buf.byteLength !== 5) {\n\t\t\tthrow new Error(\"Incorrect size: \" + buf.byteLength);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"RandomBytesInvalidSize\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tcrypto.randomBytes(-1);`)\n\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"RandomBytesFailure\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\t\tm, ok := New().NewModuleInstance(\n\t\t\t&modulestest.VU{\n\t\t\t\tRuntimeField: rt,\n\t\t\t\tInitEnvField: &common.InitEnvironment{},\n\t\t\t\tCtxField:     context.Background(),\n\t\t\t\tStateField:   nil,\n\t\t\t},\n\t\t).(*Crypto)\n\t\trequire.True(t, ok)\n\t\trequire.NoError(t, rt.Set(\"crypto\", m.Exports().Named))\n\n\t\tm.randReader = MockReader{}.Read\n\t\t_, err := rt.RunString(`\n\t\tcrypto.randomBytes(5);`)\n\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"MD4\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correct = \"aa010fbc1d14c795d86ef98c95479d17\";\n\t\tvar hash = crypto.md4(\"hello world\", \"hex\");\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"MD5\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correct = \"5eb63bbbe01eeed093cb22bb8f5acdc3\";\n\t\tvar hash = crypto.md5(\"hello world\", \"hex\");\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SHA1\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correct = \"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed\";\n\t\tvar hash = crypto.sha1(\"hello world\", \"hex\");\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SHA256\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correct = \"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9\";\n\t\tvar hash = crypto.sha256(\"hello world\", \"hex\");\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SHA384\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correct = \"fdbd8e75a67f29f701a4e040385e2e23986303ea10239211af907fcbb83578b3e417cb71ce646efd0819dd8c088de1bd\";\n\t\tvar hash = crypto.sha384(\"hello world\", \"hex\");\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SHA512\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correct = \"309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f\";\n\t\tvar hash = crypto.sha512(\"hello world\", \"hex\");\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SHA512_224\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar hash = crypto.sha512_224(\"hello world\", \"hex\");\n\t\tvar correct = \"22e0d52336f64a998085078b05a6e37b26f8120f43bf4db4c43a64ee\";\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SHA512_256\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar hash = crypto.sha512_256(\"hello world\", \"hex\");\n\t\tvar correct = \"0ac561fac838104e3f2e4ad107b4bee3e938bf15f2b15f009ccccd61a913f017\";\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"RIPEMD160\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar hash = crypto.ripemd160(\"hello world\", \"hex\");\n\t\tvar correct = \"98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f\";\n\t\tif (hash !== correct) {\n\t\t\tthrow new Error(\"Hash mismatch: \" + hash);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestStreamingApi(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\t// Empty strings are still hashable\n\tt.Run(\"Empty\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correctHex = \"d41d8cd98f00b204e9800998ecf8427e\";\n\n\t\tvar hasher = crypto.createHash(\"md5\");\n\n\t\tvar resultHex = hasher.digest(\"hex\");\n\t\tif (resultHex !== correctHex) {\n\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"UpdateOnce\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correctHex = \"5eb63bbbe01eeed093cb22bb8f5acdc3\";\n\n\t\tvar hasher = crypto.createHash(\"md5\");\n\t\thasher.update(\"hello world\");\n\n\t\tvar resultHex = hasher.digest(\"hex\");\n\t\tif (resultHex !== correctHex) {\n\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"UpdateMultiple\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correctHex = \"5eb63bbbe01eeed093cb22bb8f5acdc3\";\n\n\t\tvar hasher = crypto.createHash(\"md5\");\n\t\thasher.update(\"hello\");\n\t\thasher.update(\" \");\n\t\thasher.update(\"world\");\n\n\t\tvar resultHex = hasher.digest(\"hex\");\n\t\tif (resultHex !== correctHex) {\n\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t}`)\n\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestOutputEncoding(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar correctHex = \"5eb63bbbe01eeed093cb22bb8f5acdc3\";\n\t\tvar correctBase64 = \"XrY7u+Ae7tCTyyK7j1rNww==\";\n\t\tvar correctBase64URL = \"XrY7u-Ae7tCTyyK7j1rNww==\"\n\t\tvar correctBase64RawURL = \"XrY7u-Ae7tCTyyK7j1rNww\";\n\t\tvar correctBinary = [94,182,59,187,224,30,238,208,147,203,34,187,143,90,205,195];\n\n\t\tvar hasher = crypto.createHash(\"md5\");\n\t\thasher.update(\"hello world\");\n\n\t\tvar resultHex = hasher.digest(\"hex\");\n\t\tif (resultHex !== correctHex) {\n\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t}\n\n\t\tvar resultBase64 = hasher.digest(\"base64\");\n\t\tif (resultBase64 !== correctBase64) {\n\t\t\tthrow new Error(\"Base64 encoding mismatch: \" + resultBase64);\n\t\t}\n\n\t\tvar resultBase64URL = hasher.digest(\"base64url\");\n\t\tif (resultBase64URL !== correctBase64URL) {\n\t\t\tthrow new Error(\"Base64 URL encoding mismatch: \" + resultBase64URL);\n\t\t}\n\n\t\tvar resultBase64RawURL = hasher.digest(\"base64rawurl\");\n\t\tif (resultBase64RawURL !== correctBase64RawURL) {\n\t\t\tthrow new Error(\"Base64 raw URL encoding mismatch: \" + resultBase64RawURL);\n\t\t}\n\n\t\t// https://stackoverflow.com/a/16436975/5427244\n\t\tfunction arraysEqual(a, b) {\n\t\t  if (a === b) return true;\n\t\t  if (a == null || b == null) return false;\n\t\t  if (a.length != b.length) return false;\n\n\t\t  for (var i = 0; i < a.length; ++i) {\n\t\t\tif (a[i] !== b[i]) return false;\n\t\t  }\n\t\t  return true;\n\t\t}\n\n\t\tvar resultBinary = new Uint8Array(hasher.digest(\"binary\"));\n\t\tif (!arraysEqual(resultBinary,  correctBinary)) {\n\t\t\tthrow new Error(\"Binary encoding mismatch: \" + JSON.stringify(resultBinary));\n\t\t}\n\t\t`)\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tvar hasher = crypto.createHash(\"md5\");\n\t\thasher.update(\"hello world\");\n\t\thasher.digest(\"someInvalidEncoding\");\n\t\t`)\n\t\tassert.Contains(t, err.Error(), \"invalid output encoding: someInvalidEncoding\")\n\t})\n}\n\nfunc TestHMac(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\ttestData := map[string]string{\n\t\t\"md4\":        \"92d8f5c302cf04cca0144d7a9feb1596\",\n\t\t\"md5\":        \"e04f2ec05c8b12e19e46936b171c9d03\",\n\t\t\"sha1\":       \"c113b62711ff5d8e8100bbb17b998591af81dc24\",\n\t\t\"sha256\":     \"7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e\",\n\t\t\"sha384\":     \"d331e169e2dcfc742e80a3bf4dcc76d0e6425ab3777a3ac217ac6b2552aad5529ed4d40135b06e53a495ac7425d1e462\",\n\t\t\"sha512_224\": \"bac4e6256bdbf81d029aec48af4fdd4b14001db6721f07c429a80817\",\n\t\t\"sha512_256\": \"e3d0763ba92a4f40676c3d5b234d9842b71951e6e0767082cfb3f5e14c124b22\",\n\t\t\"sha512\":     \"cd3146f96a3005024108ff56b025517552435589a4c218411f165da0a368b6f47228b20a1a4bf081e4aae6f07e2790f27194fc77f0addc890e98ce1951cacc9f\",\n\t\t\"ripemd160\":  \"00bb4ce0d6afd4c7424c9d01b8a6caa3e749b08b\",\n\t}\n\tfor algorithm, value := range testData {\n\t\tt.Run(algorithm+\" hasher: valid\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\n\t\t\t_ = rt.Set(\"correctHex\", rt.ToValue(value))\n\t\t\t_ = rt.Set(\"algorithm\", rt.ToValue(algorithm))\n\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar hasher = crypto.createHMAC(algorithm, \"a secret\");\n\t\t\thasher.update(\"some data to hash\");\n\n\t\t\tvar resultHex = hasher.digest(\"hex\");\n\t\t\tif (resultHex !== correctHex) {\n\t\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t\t}`)\n\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tt.Run(algorithm+\" wrapper: valid\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_ = rt.Set(\"correctHex\", rt.ToValue(value))\n\t\t\t_ = rt.Set(\"algorithm\", rt.ToValue(algorithm))\n\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar resultHex = crypto.hmac(algorithm, \"a secret\", \"some data to hash\", \"hex\");\n\t\t\tif (resultHex !== correctHex) {\n\t\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t\t}`)\n\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tt.Run(algorithm+\" ArrayBuffer: valid\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_ = rt.Set(\"correctHex\", rt.ToValue(value))\n\t\t\t_ = rt.Set(\"algorithm\", rt.ToValue(algorithm))\n\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar data = new Uint8Array([115,111,109,101,32,100,97,116,97,32,116,\n\t\t\t\t\t\t\t\t\t\t111,32,104,97,115,104]).buffer;\n\t\t\tvar resultHex = crypto.hmac(algorithm, \"a secret\", data, \"hex\");\n\t\t\tif (resultHex !== correctHex) {\n\t\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t\t}`)\n\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t}\n\n\t// Algorithms not supported or typing error\n\tinvalidData := map[string]string{\n\t\t\"md6\":    \"e04f2ec05c8b12e19e46936b171c9d03\",\n\t\t\"sha526\": \"7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e\",\n\t\t\"sha348\": \"d331e169e2dcfc742e80a3bf4dcc76d0e6425ab3777a3ac217ac6b2552aad5529ed4d40135b06e53a495ac7425d1e462\",\n\t}\n\tfor algorithm, value := range invalidData {\n\t\tt.Run(algorithm+\" hasher: invalid\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_ = rt.Set(\"correctHex\", rt.ToValue(value))\n\t\t\t_ = rt.Set(\"algorithm\", rt.ToValue(algorithm))\n\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar hasher = crypto.createHMAC(algorithm, \"a secret\");\n\t\t\thasher.update(\"some data to hash\");\n\n\t\t\tvar resultHex = hasher.digest(\"hex\");\n\t\t\tif (resultHex !== correctHex) {\n\t\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t\t}`)\n\n\t\t\tassert.Contains(t, err.Error(), \"invalid algorithm: \"+algorithm)\n\t\t})\n\n\t\tt.Run(algorithm+\" wrapper: invalid\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_ = rt.Set(\"correctHex\", rt.ToValue(value))\n\t\t\t_ = rt.Set(\"algorithm\", rt.ToValue(algorithm))\n\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar resultHex = crypto.hmac(algorithm, \"a secret\", \"some data to hash\", \"hex\");\n\t\t\tif (resultHex !== correctHex) {\n\t\t\t\tthrow new Error(\"Hex encoding mismatch: \" + resultHex);\n\t\t\t}`)\n\n\t\t\tassert.Contains(t, err.Error(), \"invalid algorithm: \"+algorithm)\n\t\t})\n\t}\n}\n\nfunc TestHexEncode(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Success\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := sobek.New()\n\t\tinput := []byte{104, 101, 108, 108, 111}\n\t\ttestCases := []any{\n\t\t\tinput, string(input), rt.NewArrayBuffer(input),\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\tt.Run(fmt.Sprintf(\"%T\", tc), func(t *testing.T) { //nolint:paralleltest\n\t\t\t\tc := Crypto{}\n\t\t\t\tout, err := c.hexEncode(tc)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, \"68656c6c6f\", out)\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"InvalidTypeError\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tc := Crypto{vu: &modulestest.VU{\n\t\t\tRuntimeField: sobek.New(),\n\t\t}}\n\n\t\t_, err := c.hexEncode(struct{}{})\n\t\tassert.EqualError(t, err, \"invalid type struct {}, expected string, []byte or ArrayBuffer\")\n\t})\n}\n\nfunc TestAWSv4(t *testing.T) {\n\tt.Parallel()\n\n\t// example values from https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tInitEnvField: &common.InitEnvironment{},\n\t\t\tCtxField:     context.Background(),\n\t\t\tStateField:   nil,\n\t\t},\n\t).(*Crypto)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"crypto\", m.Exports().Named))\n\n\t_, err := rt.RunString(`\n\t\tvar HexEncode = crypto.hexEncode;\n\t\tvar HmacSHA256 = function(data, key) {\n\t\t\treturn crypto.hmac(\"sha256\", key, data, \"binary\");\n\t\t};\n\n\t\tvar expectedKDate    = '969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d'\n\t\tvar expectedKRegion  = '69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c'\n\t\tvar expectedKService = 'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa'\n\t\tvar expectedKSigning = 'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d'\n\n\t\tvar key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY';\n\t\tvar dateStamp = '20120215';\n\t\tvar regionName = 'us-east-1';\n\t\tvar serviceName = 'iam';\n\n\t\tvar kDate = HmacSHA256(dateStamp, \"AWS4\" + key);\n\t\tvar kRegion = HmacSHA256(regionName, kDate);\n\t\tvar kService = HmacSHA256(serviceName, kRegion);\n\t\tvar kSigning = HmacSHA256(\"aws4_request\", kService);\n\n\n\t\tvar hexKDate = HexEncode(kDate);\n\t\tif (expectedKDate != hexKDate) {\n\t\t\tthrow new Error(\"Wrong kDate: expected '\" + expectedKDate + \"' got '\" + hexKDate + \"'\");\n\t\t}\n\t\tvar hexKRegion = HexEncode(kRegion);\n\t\tif (expectedKRegion != hexKRegion) {\n\t\t\tthrow new Error(\"Wrong kRegion: expected '\" + expectedKRegion + \"' got '\" + hexKRegion + \"'\");\n\t\t}\n\t\tvar hexKService = HexEncode(kService);\n\t\tif (expectedKService != hexKService) {\n\t\t\tthrow new Error(\"Wrong kService: expected '\" + expectedKService + \"' got '\" + hexKService + \"'\");\n\t\t}\n\t\tvar hexKSigning = HexEncode(kSigning);\n\t\tif (expectedKSigning != hexKSigning) {\n\t\t\tthrow new Error(\"Wrong kSigning: expected '\" + expectedKSigning + \"' got '\" + hexKSigning + \"'\");\n\t\t}\n\t\t`)\n\tassert.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/crypto/x509/x509.go",
    "content": "// Package x509 provides X.509 certificate parsing for the k6\npackage x509\n\nimport (\n\t\"crypto/dsa\" //nolint:staticcheck\n\t\"crypto/ecdsa\"\n\t\"crypto/rsa\"\n\t\"crypto/sha1\" // #nosec G505\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// X509 represents an instance of the X509 certificate module.\n\tX509 struct {\n\t\tvu modules.VU\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &X509{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &X509{vu: vu}\n}\n\n// Exports returns the exports of the execution module.\nfunc (mi *X509) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"parse\":       mi.parse,\n\t\t\t\"getAltNames\": mi.altNames,\n\t\t\t\"getIssuer\":   mi.issuer,\n\t\t\t\"getSubject\":  mi.subject,\n\t\t},\n\t}\n}\n\n// Certificate is an X.509 certificate\ntype Certificate struct {\n\tSubject            Subject\n\tIssuer             Issuer\n\tNotBefore          string    `js:\"notBefore\"`\n\tNotAfter           string    `js:\"notAfter\"`\n\tAltNames           []string  `js:\"altNames\"`\n\tSignatureAlgorithm string    `js:\"signatureAlgorithm\"`\n\tFingerPrint        []byte    `js:\"fingerPrint\"`\n\tPublicKey          PublicKey `js:\"publicKey\"`\n}\n\n// RDN is a component of an X.509 distinguished name\ntype RDN struct {\n\tType  string\n\tValue string\n}\n\n// Subject is a certificate subject\ntype Subject struct {\n\tCommonName             string `js:\"commonName\"`\n\tCountry                string\n\tPostalCode             string   `js:\"postalCode\"`\n\tStateOrProvinceName    string   `js:\"stateOrProvinceName\"`\n\tLocalityName           string   `js:\"localityName\"`\n\tStreetAddress          string   `js:\"streetAddress\"`\n\tOrganizationName       string   `js:\"organizationName\"`\n\tOrganizationalUnitName []string `js:\"organizationalUnitName\"`\n\tNames                  []RDN\n}\n\n// Issuer is a certificate issuer\ntype Issuer struct {\n\tCommonName          string `js:\"commonName\"`\n\tCountry             string\n\tStateOrProvinceName string `js:\"stateOrProvinceName\"`\n\tLocalityName        string `js:\"localityName\"`\n\tOrganizationName    string `js:\"organizationName\"`\n\tNames               []RDN\n}\n\n// PublicKey is used for decryption and signature verification\ntype PublicKey struct {\n\tAlgorithm string\n\tKey       any\n}\n\n// parse produces an entire X.509 certificate\nfunc (mi X509) parse(encoded []byte) (Certificate, error) {\n\tparsed, err := parseCertificate(encoded)\n\tif err != nil {\n\t\treturn Certificate{}, err\n\t}\n\tcertificate, err := makeCertificate(parsed)\n\tif err != nil {\n\t\treturn Certificate{}, err\n\t}\n\treturn certificate, nil\n}\n\n// altNames extracts alt names\nfunc (mi X509) altNames(encoded []byte) ([]string, error) {\n\tparsed, err := parseCertificate(encoded)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn altNames(parsed), nil\n}\n\n// issuer extracts certificate issuer\nfunc (mi X509) issuer(encoded []byte) (Issuer, error) {\n\tparsed, err := parseCertificate(encoded)\n\tif err != nil {\n\t\treturn Issuer{}, err\n\t}\n\treturn makeIssuer(parsed.Issuer), nil\n}\n\n// subject extracts certificate subject\nfunc (mi X509) subject(encoded []byte) Subject {\n\tparsed, err := parseCertificate(encoded)\n\tif err != nil {\n\t\tcommon.Throw(mi.vu.Runtime(), err)\n\t}\n\treturn makeSubject(parsed.Subject)\n}\n\nfunc parseCertificate(encoded []byte) (*x509.Certificate, error) {\n\tdecoded, _ := pem.Decode(encoded)\n\tif decoded == nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode certificate PEM file\")\n\t}\n\tparsed, err := x509.ParseCertificate(decoded.Bytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse certificate: %w\", err)\n\t}\n\treturn parsed, nil\n}\n\nfunc makeCertificate(parsed *x509.Certificate) (Certificate, error) {\n\tpublicKey, err := makePublicKey(parsed.PublicKey)\n\tif err != nil {\n\t\treturn Certificate{}, err\n\t}\n\treturn Certificate{\n\t\tSubject:            makeSubject(parsed.Subject),\n\t\tIssuer:             makeIssuer(parsed.Issuer),\n\t\tNotBefore:          iso8601(parsed.NotBefore),\n\t\tNotAfter:           iso8601(parsed.NotAfter),\n\t\tAltNames:           altNames(parsed),\n\t\tSignatureAlgorithm: signatureAlgorithm(parsed.SignatureAlgorithm),\n\t\tFingerPrint:        fingerPrint(parsed),\n\t\tPublicKey:          publicKey,\n\t}, nil\n}\n\nfunc makeSubject(subject pkix.Name) Subject {\n\treturn Subject{\n\t\tCommonName:             subject.CommonName,\n\t\tCountry:                first(subject.Country),\n\t\tPostalCode:             first(subject.PostalCode),\n\t\tStateOrProvinceName:    first(subject.Province),\n\t\tLocalityName:           first(subject.Locality),\n\t\tStreetAddress:          first(subject.StreetAddress),\n\t\tOrganizationName:       first(subject.Organization),\n\t\tOrganizationalUnitName: subject.OrganizationalUnit,\n\t\tNames:                  makeRdns(subject.Names),\n\t}\n}\n\nfunc makeIssuer(issuer pkix.Name) Issuer {\n\treturn Issuer{\n\t\tCommonName:          issuer.CommonName,\n\t\tCountry:             first(issuer.Country),\n\t\tStateOrProvinceName: first(issuer.Province),\n\t\tLocalityName:        first(issuer.Locality),\n\t\tOrganizationName:    first(issuer.Organization),\n\t\tNames:               makeRdns(issuer.Names),\n\t}\n}\n\nfunc makePublicKey(parsed any) (PublicKey, error) {\n\tvar algorithm string\n\tswitch parsed.(type) {\n\tcase *dsa.PublicKey:\n\t\talgorithm = \"DSA\"\n\tcase *ecdsa.PublicKey:\n\t\talgorithm = \"ECDSA\"\n\tcase *rsa.PublicKey:\n\t\talgorithm = \"RSA\"\n\tdefault:\n\t\terr := errors.New(\"unsupported public key algorithm\")\n\t\treturn PublicKey{}, err\n\t}\n\treturn PublicKey{\n\t\tAlgorithm: algorithm,\n\t\tKey:       parsed,\n\t}, nil\n}\n\nfunc first(values []string) string {\n\tif len(values) > 0 {\n\t\treturn values[0]\n\t}\n\treturn \"\"\n}\n\nfunc iso8601(value time.Time) string {\n\treturn value.Format(time.RFC3339)\n}\n\nfunc makeRdns(names []pkix.AttributeTypeAndValue) []RDN {\n\tresult := make([]RDN, len(names))\n\tfor i, name := range names {\n\t\tresult[i] = makeRdn(name)\n\t}\n\treturn result\n}\n\nfunc makeRdn(name pkix.AttributeTypeAndValue) RDN {\n\treturn RDN{\n\t\tType:  name.Type.String(),\n\t\tValue: fmt.Sprintf(\"%v\", name.Value),\n\t}\n}\n\nfunc altNames(parsed *x509.Certificate) []string {\n\tcapacity := len(parsed.DNSNames) + len(parsed.EmailAddresses) + len(parsed.IPAddresses) + len(parsed.URIs)\n\tnames := make([]string, 0, capacity)\n\tnames = append(names, parsed.DNSNames...)\n\tnames = append(names, parsed.EmailAddresses...)\n\tnames = append(names, ipAddresses(parsed)...)\n\tnames = append(names, uris(parsed)...)\n\treturn names\n}\n\nfunc ipAddresses(parsed *x509.Certificate) []string {\n\tstrings := make([]string, len(parsed.IPAddresses))\n\tfor i, item := range parsed.IPAddresses {\n\t\tstrings[i] = item.String()\n\t}\n\treturn strings\n}\n\nfunc uris(parsed *x509.Certificate) []string {\n\tstrings := make([]string, len(parsed.URIs))\n\tfor i, item := range parsed.URIs {\n\t\tstrings[i] = item.String()\n\t}\n\treturn strings\n}\n\nfunc signatureAlgorithm(value x509.SignatureAlgorithm) string {\n\tif value == x509.UnknownSignatureAlgorithm {\n\t\treturn \"UnknownSignatureAlgorithm\"\n\t}\n\treturn value.String()\n}\n\nfunc fingerPrint(parsed *x509.Certificate) []byte {\n\tbytes := sha1.Sum(parsed.Raw) // #nosec G401 nosemgrep: use-of-sha1\n\treturn bytes[:]\n}\n"
  },
  {
    "path": "internal/js/modules/k6/crypto/x509/x509_test.go",
    "content": "package x509\n\nimport (\n\t\"context\"\n\tgox509 \"crypto/x509\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nfunc makeRuntime(t *testing.T) *sobek.Runtime {\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tInitEnvField: &common.InitEnvironment{},\n\t\t\tCtxField:     context.Background(),\n\t\t\tStateField:   nil,\n\t\t},\n\t).(*X509)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"x509\", m.Exports().Named))\n\treturn rt\n}\n\ntype Material struct {\n\tdsaCertificate   string\n\tecdsaCertificate string\n\trsaCertificate   string\n\tpublicKey        string\n}\n\nvar material = Material{ //nolint:gochecknoglobals\n\tdsaCertificate: `-----BEGIN CERTIFICATE-----\nMIIFnzCCBUSgAwIBAgIJAPOE4rArGHVcMAsGCWCGSAFlAwQDAjCBsTELMAkGA1UE\nBhMCWloxGTAXBgNVBAgMEEtvcHVuY2V6aXMgS3JhaXMxETAPBgNVBAcMCEFzaHRp\nbm9rMRwwGgYDVQQKDBNFeHVtYnJhbiBDb252ZW50aW9uMRkwFwYDVQQLDBBFeHVt\nYnJhbiBDb3VuY2lsMRUwEwYDVQQDDAxleGNvdW5jaWwuenoxJDAiBgkqhkiG9w0B\nCQEWFWV4Y291bmNpbEBleGFtcGxlLmNvbTAeFw0xOTA1MTAwNDE2MDZaFw0xOTA2\nMDkwNDE2MDZaMIGxMQswCQYDVQQGEwJaWjEZMBcGA1UECAwQS29wdW5jZXppcyBL\ncmFpczERMA8GA1UEBwwIQXNodGlub2sxHDAaBgNVBAoME0V4dW1icmFuIENvbnZl\nbnRpb24xGTAXBgNVBAsMEEV4dW1icmFuIENvdW5jaWwxFTATBgNVBAMMDGV4Y291\nbmNpbC56ejEkMCIGCSqGSIb3DQEJARYVZXhjb3VuY2lsQGV4YW1wbGUuY29tMIID\nRjCCAjkGByqGSM44BAEwggIsAoIBAQCKv/tJtwgLJGrvas2YQmqgjfoQ5s9uQRO9\n+9ELCu4Lstn9nsjmER/+CgXCrAQG/jUKdT6tpz9bUVYspcn+gF2YkDugSbMb4Uci\nFbWjuFSYD7xIe7APGprgogJZeNO6v9vFWLJak4d35Olej1HLQpVPtz5NdR9unh1a\nB9sODuRtnZDJsGWuEYbNN0nbjQReBLwbnJCRo5p8nL+FVfKmFGKC9KK3P3TNM6u5\nXU8KLlXZ40VNbtiIfzKr4aeHy8ob1+0Jy4nirxt2WJPxYW/tbawhHkJXB8R573CR\noxH+2xx5WTsYjSIdI3h+mGufi+nmnO2YQguVMrCJ5AaGlrw7V/KRAiEA9d+jpJs9\nsAccw/DWAnRm+UuvcZ9CFT4ttoPc0UWLKmkCggEAVKjNXly/1gzzKUGZVqYSGwig\nArV109g1vCWg4QavGgVLLqlbSxiz6+0kuLK6vauMipr0i57FRzh0EpZ6faahwQ/L\nbhqXQU+S55m5rFh1eUh428htlOhG5hQYe/EWiqD7nsWzl6z8+/Y5uuq6BksTLej3\nnQJWiLY09SNnKcjVZYe5vs+8ASx6vT2qkGV/UvEEKma1I+0MUDJcHFjnTNwUf7GT\nRmtt7YgDlYX13e9ar89lSPxjXo+r3BSm5iNMC8eG3e91yoT0G4ShI6zf8LzZbaN2\nPK+Bwa+pBYEqvtp69G0NPO+jadx62HoAKFw+BXh2XU1fS09tX7Z2lfsIhIZSlQOC\nAQUAAoIBADJjifXbelASJEgBC9MNcFQM3aeLpMhSXcsIBR7mDGISnig84HwoqJT7\n6lQznzqBrGjYTaNEA6UC6XXda19wugKSDWJ6SvnMekkvOfIeqUom2sd43fYESXJZ\nX6gnbiqShNVwIK+aKpAWn1sqbWkzCcIL2BJdm7ETJeW3+yOXdLCa6p3JbZQSgVDZ\n+GPviNHSX1hyF4FjQW2rrQix5RhEJSV988j6NEZFbuTf7INwpDOg9htRoRihRk3e\nh9kiR6iHl4ZUqSlefyVS40mzlKpPEXtKW2PFE6QLcQLPDzX+JjjAomgs/DIKia2T\nF+3H94NY/zOOcerq+BXwVYZmxhDSOrKjUzBRMB0GA1UdDgQWBBSSb364iDHRI6/2\nJqGGJU+MCQZEoTAfBgNVHSMEGDAWgBSSb364iDHRI6/2JqGGJU+MCQZEoTAPBgNV\nHRMBAf8EBTADAQH/MAsGCWCGSAFlAwQDAgNIADBFAiEA1nr63IX9aaGUPeOUC0Bh\nw3Y7mpv5+sVgtoIi8ljxVSICIFCpEl70YjRVIUKL8N/lJwKxisrJ4+Xxg/DIeGP8\nL8GA\n-----END CERTIFICATE-----`,\n\tecdsaCertificate: `-----BEGIN CERTIFICATE-----\nMIIDXjCCAwWgAwIBAgICBNIwCgYIKoZIzj0EAwIwgdsxCzAJBgNVBAYTAlpaMRkw\nFwYDVQQIExBLb3B1bmNlemlzIEtyYWlzMREwDwYDVQQHEwhBc2h0aW5vazEaMBgG\nA1UECRMRMjIxQiBCYWtlciBTdHJlZXQxDjAMBgNVBBETBTk5OTk5MRwwGgYDVQQK\nExNFeHVtYnJhbiBDb252ZW50aW9uMT0wFwYDVQQLExBFeHVtYnJhbiBDb3VuY2ls\nMCIGA1UECxMbRXh1bWJyYW4gSmFuaXRvcmlhbCBTZXJ2aWNlMRUwEwYDVQQDEwxl\neGNvdW5jaWwuenowHhcNMTkwMTAxMDAwMDAwWhcNMjAwMTAxMDAwMDAwWjCB2zEL\nMAkGA1UEBhMCWloxGTAXBgNVBAgTEEtvcHVuY2V6aXMgS3JhaXMxETAPBgNVBAcT\nCEFzaHRpbm9rMRowGAYDVQQJExEyMjFCIEJha2VyIFN0cmVldDEOMAwGA1UEERMF\nOTk5OTkxHDAaBgNVBAoTE0V4dW1icmFuIENvbnZlbnRpb24xPTAXBgNVBAsTEEV4\ndW1icmFuIENvdW5jaWwwIgYDVQQLExtFeHVtYnJhbiBKYW5pdG9yaWFsIFNlcnZp\nY2UxFTATBgNVBAMTDGV4Y291bmNpbC56ejBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABDKaRQKDiTs8QsKZMwh5rd91rjO66O5Dcc3I2taoQZu9mn+fbV/u4zi4dYAl\nlWrZak7ncRsdtyBmd0iMv12ZRKmjgbYwgbMwgbAGA1UdEQSBqDCBpYITY291bmNp\nbC5leHVtYnJhbi56eoISYWJvdXQuZXhjb3VuY2lsLnp6gRZpbnF1aXJpZXNAZXhj\nb3VuY2lsLnp6gRJwcmVzc0BleGNvdW5jaWwuenqHBMAAAgCHBMAAAhmGGWh0dHA6\nLy9wcmVzcy5leGNvdW5jaWwuenqGJ2h0dHA6Ly9sZWFybmluZy5leGNvdW5jaWwu\nenovaW5kZXguaHRtbDAKBggqhkjOPQQDAgNHADBEAiA/X4Y+Zaw4ziqL4grkY+rm\nsrWfS/JGxLvN49r68cczSwIgWEXFIHMwE+OhKC6z01mIPe2G2CguYHukWyL+BHtT\n+20=\n-----END CERTIFICATE-----`,\n\trsaCertificate: `-----BEGIN CERTIFICATE-----\nMIIE6zCCA9OgAwIBAgICBNIwDQYJKoZIhvcNAQELBQAwgdsxCzAJBgNVBAYTAlpa\nMRkwFwYDVQQIExBLb3B1bmNlemlzIEtyYWlzMREwDwYDVQQHEwhBc2h0aW5vazEa\nMBgGA1UECRMRMjIxQiBCYWtlciBTdHJlZXQxDjAMBgNVBBETBTk5OTk5MRwwGgYD\nVQQKExNFeHVtYnJhbiBDb252ZW50aW9uMT0wFwYDVQQLExBFeHVtYnJhbiBDb3Vu\nY2lsMCIGA1UECxMbRXh1bWJyYW4gSmFuaXRvcmlhbCBTZXJ2aWNlMRUwEwYDVQQD\nEwxleGNvdW5jaWwuenowHhcNMTkwMTAxMDAwMDAwWhcNMjAwMTAxMDAwMDAwWjCB\n2zELMAkGA1UEBhMCWloxGTAXBgNVBAgTEEtvcHVuY2V6aXMgS3JhaXMxETAPBgNV\nBAcTCEFzaHRpbm9rMRowGAYDVQQJExEyMjFCIEJha2VyIFN0cmVldDEOMAwGA1UE\nERMFOTk5OTkxHDAaBgNVBAoTE0V4dW1icmFuIENvbnZlbnRpb24xPTAXBgNVBAsT\nEEV4dW1icmFuIENvdW5jaWwwIgYDVQQLExtFeHVtYnJhbiBKYW5pdG9yaWFsIFNl\ncnZpY2UxFTATBgNVBAMTDGV4Y291bmNpbC56ejCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAN/56ke0JBw+VI2xdjUCry2nWZvYZ1Yg2CpcVH23Ztko/4Em\ny69i0ZOXavoMe+yHLVBQTP2UjQ0kTC+2OmSZcg2NYAxtfkpEd1gPNGtQdb6j5nga\nLIv13rzS7XtTW2Kg2uX0gB8Yi30ZuGy0F5WIL4yoM58jQZYHM4aKvOFpXAlbSIVG\nw4NpuL/GsYK/RgYln//0be6AigDJKVdDV6V2BP3RH7EBAXRADhET2QZ1Sxiu7IGG\nc/Xiy94RccXXivFjqURN8yR0RY+WPPVLyB7PjYuII324/64aBpQ4/Xz5nvl1A358\nWRtg0QDPmOmmUQf9m6VgHUgcrBhoRuXJa8ip3CMCAwEAAaOBtjCBszCBsAYDVR0R\nBIGoMIGlghNjb3VuY2lsLmV4dW1icmFuLnp6ghJhYm91dC5leGNvdW5jaWwuenqB\nFmlucXVpcmllc0BleGNvdW5jaWwuenqBEnByZXNzQGV4Y291bmNpbC56eocEwAAC\nAIcEwAACGYYZaHR0cDovL3ByZXNzLmV4Y291bmNpbC56eoYnaHR0cDovL2xlYXJu\naW5nLmV4Y291bmNpbC56ei9pbmRleC5odG1sMA0GCSqGSIb3DQEBCwUAA4IBAQCI\nlVr5wEwAznmV/MxE5vc4gfHppYzszssPPvvGs0QjuDe9AbN26nEuriren2bcGbcS\npVhl25tfIJd5rvgvWKz+nTQCEGVI4BDFio0Jt5+7CADOsSSFGYQIu0BrjA3vCs87\ngzg3dNaCY65aH0cJE/dVwiS/F2XTr1zvr+uBPExgrA21+FSIlHM0Dot+VGKdCLEO\n6HugOCDBdzKF2hsHeI5LvgXUX5zQ0gnsd93+QuxUmiN7QZZs8tDMD/+efo4OWvp/\nxytSVXVn+cECQLg9hVn+Zx3XO2FA0eOzaWEONnUGghT/Ivw06lUxis5tkAoAU93d\nddBqJe0XUeAX8Zr6EJ82\n-----END CERTIFICATE-----`,\n\tpublicKey: `-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXMLr/Y/vUtIFY75jj0YXfp6lQ\n7iEIbps3BvRE4isTpxs8fXLnLM8LAuJScxiKyrGnj8EMb7LIHkSMBlz6iVj9atY6\nEUEm/VHUnElNquzGyBA50TCfpv6NHPaTvOoB45yQbZ/YB4LO+CsT9eIMDZ4tcU9Z\n+xD10ifJhhIwpZUFIQIDAQAB\n-----END PUBLIC KEY-----`,\n}\n\nfunc TestParse(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\tt.Run(\"DecodeFailure\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tx509.parse(\"bad-certificate\");`)\n\t\tassert.Contains(\n\t\t\tt, err.Error(), \"failed to decode certificate PEM file\")\n\t})\n\n\tt.Run(\"ParseFailure\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tx509.parse(pem);`, material.publicKey))\n\t\tif assert.Error(t, err) {\n\t\t\tassert.Contains(t,\n\t\t\t\terr.Error(),\n\t\t\t\t\"failed to parse certificate\",\n\t\t\t)\n\t\t}\n\t})\n\n\tt.Run(\"SignatureAlgorithm\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.signatureAlgorithm;\n\t\tif (value !== \"SHA256-RSA\") {\n\t\t\tthrow new Error(\"Bad signature algorithm: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"Subject\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tif (typeof cert.subject !== \"object\") {\n\t\t\tthrow new Error(\"Bad subject: \" + typeof cert.subject);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectCommonName\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.subject ? cert.subject.commonName : null;\n\t\tif (value !== \"excouncil.zz\") {\n\t\t\tthrow new Error(\"Bad subject common name: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectCountry\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.subject ? cert.subject.country : null;\n\t\tif (value !== \"ZZ\") {\n\t\t\tthrow new Error(\"Bad subject country: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectPostalCode\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.subject ? cert.subject.postalCode : null;\n\t\tif (value !== \"99999\") {\n\t\t\tthrow new Error(\"Bad subject postal code: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectProvince\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.subject ? cert.subject.stateOrProvinceName : null;\n\t\tif (value !== \"Kopuncezis Krais\") {\n\t\t\tthrow new Error(\"Bad subject province: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectLocality\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.subject ? cert.subject.localityName : null;\n\t\tif (value !== \"Ashtinok\") {\n\t\t\tthrow new Error(\"Bad subject locality: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectStreetAddress\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.subject ? cert.subject.streetAddress : null;\n\t\tif (value !== \"221B Baker Street\") {\n\t\t\tthrow new Error(\"Bad subject street address: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectOrganization\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.subject ? cert.subject.organizationName : null;\n\t\tif (value !== \"Exumbran Convention\") {\n\t\t\tthrow new Error(\"Bad subject organization: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectOrganizationalUnit\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar values =\n\t\t\tcert.subject ? cert.subject.organizationalUnitName : null;\n\t\tif (!(\n\t\t\tvalues.length === 2 &&\n\t\t\tvalues[0] === \"Exumbran Council\" &&\n\t\t\tvalues[1] === \"Exumbran Janitorial Service\"\n\t\t)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Bad subject organizational unit: \" + values.join(\", \")\n\t\t\t);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"SubjectNames\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar values = cert.subject ? cert.subject.names : null;\n\t\tvar strings = values\n\t\t\t? values.map(function(entry) { return entry.type + \": \" + entry.value})\n\t\t\t: null;\n\t\tArray.prototype.includes =\n\t\t\tfunction (value) { return this.indexOf(value) !== -1 }\n\t\tif (!(\n\t\t\tvalues &&\n\t\t\tArray.isArray(values) &&\n\t\t\tvalues.length === 9 &&\n\t\t\tstrings.includes(\"2.5.4.6: ZZ\") &&\n\t\t\tstrings.includes(\"2.5.4.8: Kopuncezis Krais\") &&\n\t\t\tstrings.includes(\"2.5.4.7: Ashtinok\") &&\n\t\t\tstrings.includes(\"2.5.4.9: 221B Baker Street\") &&\n\t\t\tstrings.includes(\"2.5.4.17: 99999\") &&\n\t\t\tstrings.includes(\"2.5.4.10: Exumbran Convention\") &&\n\t\t\tstrings.includes(\"2.5.4.11: Exumbran Council\") &&\n\t\t\tstrings.includes(\"2.5.4.11: Exumbran Janitorial Service\") &&\n\t\t\tstrings.includes(\"2.5.4.3: excouncil.zz\")\n\t\t)) {\n\t\t\tthrow new Error(\"Bad subject names\");\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"Issuer\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tif (typeof cert.issuer !== \"object\") {\n\t\t\tthrow new Error(\"Bad issuer: \" + typeof cert.issuer);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"IssuerCommonName\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.issuer ? cert.issuer.commonName : null;\n\t\tif (value !== \"excouncil.zz\") {\n\t\t\tthrow new Error(\"Bad issuer common name: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"IssuerCountry\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.issuer ? cert.issuer.country : null;\n\t\tif (value !== \"ZZ\") {\n\t\t\tthrow new Error(\"Bad issuer country: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"IssuerProvince\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.issuer ? cert.issuer.stateOrProvinceName : null;\n\t\tif (value !== \"Kopuncezis Krais\") {\n\t\t\tthrow new Error(\"Bad issuer province: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"IssuerLocality\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.issuer ? cert.issuer.localityName : null;\n\t\tif (value !== \"Ashtinok\") {\n\t\t\tthrow new Error(\"Bad issuer locality: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"IssuerOrganization\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.issuer ? cert.issuer.organizationName : null;\n\t\tif (value !== \"Exumbran Convention\") {\n\t\t\tthrow new Error(\"Bad issuer organization: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"IssuerNames\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar values = cert.issuer ? cert.issuer.names : null;\n\t\tvar strings = values\n\t\t\t? values.map(function(entry) { return entry.type + \": \" + entry.value})\n\t\t\t: null;\n\t\tArray.prototype.includes =\n\t\t\tfunction (value) { return this.indexOf(value) !== -1 }\n\t\tif (!(\n\t\t\tvalues &&\n\t\t\tArray.isArray(values) &&\n\t\t\tvalues.length === 9 &&\n\t\t\tstrings.includes(\"2.5.4.6: ZZ\") &&\n\t\t\tstrings.includes(\"2.5.4.8: Kopuncezis Krais\") &&\n\t\t\tstrings.includes(\"2.5.4.7: Ashtinok\") &&\n\t\t\tstrings.includes(\"2.5.4.9: 221B Baker Street\") &&\n\t\t\tstrings.includes(\"2.5.4.17: 99999\") &&\n\t\t\tstrings.includes(\"2.5.4.10: Exumbran Convention\") &&\n\t\t\tstrings.includes(\"2.5.4.11: Exumbran Council\") &&\n\t\t\tstrings.includes(\"2.5.4.11: Exumbran Janitorial Service\") &&\n\t\t\tstrings.includes(\"2.5.4.3: excouncil.zz\")\n\t\t)) {\n\t\t\tthrow new Error(\"Bad subject names\");\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"NotBefore\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.notBefore;\n\t\tif (value !== \"2019-01-01T00:00:00Z\") {\n\t\t\tthrow new Error(\"Bad lower bound: \" + value)\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"NotAfter\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.notAfter;\n\t\tif (value !== \"2020-01-01T00:00:00Z\") {\n\t\t\tthrow new Error(\"Bad upper bound: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"AltNames\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar values = cert.altNames;\n\t\tif (!(\n\t\t\tvalues.length === 8 &&\n\t\t\tvalues[0] === \"council.exumbran.zz\" &&\n\t\t\tvalues[1] === \"about.excouncil.zz\" &&\n\t\t\tvalues[2] === \"inquiries@excouncil.zz\" &&\n\t\t\tvalues[3] === \"press@excouncil.zz\" &&\n\t\t\tvalues[4] === \"192.0.2.0\" &&\n\t\t\tvalues[5] === \"192.0.2.25\" &&\n\t\t\tvalues[6] === \"http://press.excouncil.zz\" &&\n\t\t\tvalues[7] === \"http://learning.excouncil.zz/index.html\"\n\t\t)) {\n\t\t\tthrow new Error(\"Bad alt names: \" + values.join(\", \"));\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"FingerPrint\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.fingerPrint;\n\t\tvar expected = [\n\t\t\t85, 119, 3, 199, 150, 144, 202, 145, 178, 46,\n\t\t\t205, 132, 37, 235, 251, 208, 139, 161, 143, 14\n\t\t]\n\t\tif (value.join(\"\") !== expected.join(\"\")) {\n\t\t\tthrow new Error(\"Bad fingerprint: \" + value.join(\":\"));\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"PublicKey\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tif (typeof cert.publicKey !== \"object\") {\n\t\t\tthrow new Error(\"Bad public key: \" + typeof cert.publicKey);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"RSAPublicKey\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.publicKey;\n\t\tif (!(\n\t\t\tvalue &&\n\t\t\ttypeof value === \"object\" &&\n\t\t\tvalue.algorithm === \"RSA\" &&\n\t\t\ttypeof value.key === \"object\" &&\n\t\t\ttypeof value.key.e === \"number\" &&\n\t\t\ttypeof value.key.n === \"bigint\"\n\t\t)) {\n\t\t\tthrow new Error(\"Bad RSA public key\");\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"RSAPublicKeyExponent\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.publicKey ? cert.publicKey.key.e : null;\n\t\tif (value !== 65537) {\n\t\t\tthrow new Error(\"Bad RSA public key exponent: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"RSAPublicKeyModulus\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.publicKey ? cert.publicKey.key.n.toString(16) : null;\n\t\tvar expected = \"dff9ea47b4241c3e548db1763502af2da7599bd8675620d82a5c547db766d928ff8126cbaf62d193976afa0c7bec872d50504cfd948d0d244c2fb63a6499720d8d600c6d7e4a4477580f346b5075bea3e6781a2c8bf5debcd2ed7b535b62a0dae5f4801f188b7d19b86cb41795882f8ca8339f2341960733868abce1695c095b488546c38369b8bfc6b182bf4606259ffff46dee808a00c929574357a57604fdd11fb1010174400e1113d906754b18aeec818673f5e2cbde1171c5d78af163a9444df32474458f963cf54bc81ecf8d8b88237db8ffae1a069438fd7cf99ef975037e7c591b60d100cf98e9a65107fd9ba5601d481cac186846e5c96bc8a9dc23\";\n\t\tif (value !== expected) {\n\t\t\tthrow new Error(\"Bad RSA public key modulus: \" + value);\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"DSAPublicKey\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.publicKey;\n\t\tif (!(\n\t\t\tvalue &&\n\t\t\ttypeof value === \"object\" &&\n\t\t\tvalue.algorithm === \"DSA\" &&\n\t\t\ttypeof value.key.parameters === \"object\" &&\n\t\t\ttypeof value.key.y === \"bigint\"\n\t\t)) {\n\t\t\tthrow new Error(\"Bad DSA public key\");\n\t\t}`, material.dsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"ECDSAPublicKey\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar cert = x509.parse(pem);\n\t\tvar value = cert.publicKey;\n\t\tif (!(\n\t\t\tvalue &&\n\t\t\ttypeof value === \"object\" &&\n\t\t\tvalue.algorithm === \"ECDSA\" &&\n\t\t\ttypeof value.key.curve === \"object\" &&\n\t\t\ttypeof value.key.x === \"bigint\" &&\n\t\t\ttypeof value.key.y === \"bigint\"\n\t\t)) {\n\t\t\tthrow new Error(\"Bad ECDSA public key\");\n\t\t}`, material.ecdsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestGetAltNames(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\tt.Run(\"Failure\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tx509.getAltNames(\"bad-certificate\");`)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Success\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar altNames = x509.getAltNames(pem);\n\t\tif (!(\n\t\t\tArray.isArray(altNames) &&\n\t\t\taltNames.length === 8 &&\n\t\t\taltNames[0] === \"council.exumbran.zz\" &&\n\t\t\taltNames[1] === \"about.excouncil.zz\" &&\n\t\t\taltNames[2] === \"inquiries@excouncil.zz\" &&\n\t\t\taltNames[3] === \"press@excouncil.zz\" &&\n\t\t\taltNames[4] === \"192.0.2.0\" &&\n\t\t\taltNames[5] === \"192.0.2.25\" &&\n\t\t\taltNames[6] === \"http://press.excouncil.zz\" &&\n\t\t\taltNames[7] === \"http://learning.excouncil.zz/index.html\"\n\t\t)) {\n\t\t\tthrow new Error(\"Bad alt names\");\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestGetIssuer(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\tt.Run(\"Failure\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tx509.getIssuer(\"bad-certificate\");`)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Success\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar issuer = x509.getIssuer(pem);\n\t\tif (!(\n\t\t\ttypeof issuer === \"object\" &&\n\t\t\tissuer.commonName === \"excouncil.zz\" &&\n\t\t\tissuer.country === \"ZZ\" &&\n\t\t\tissuer.stateOrProvinceName === \"Kopuncezis Krais\" &&\n\t\t\tissuer.localityName === \"Ashtinok\" &&\n\t\t\tissuer.organizationName === \"Exumbran Convention\" &&\n\t\t\tArray.isArray(issuer.names) &&\n\t\t\tissuer.names.length === 9\n\t\t)) {\n\t\t\tthrow new Error(\"Bad issuer\");\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestGetSubject(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\tt.Run(\"Failure\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(`\n\t\tx509.getSubject(\"bad-certificate\");`)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Success\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := makeRuntime(t)\n\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar pem = %q;\n\t\tvar subject = x509.getSubject(pem);\n\t\tif (!(\n\t\t\ttypeof subject === \"object\" &&\n\t\t\tsubject.commonName === \"excouncil.zz\" &&\n\t\t\tsubject.country === \"ZZ\" &&\n\t\t\tsubject.postalCode === \"99999\" &&\n\t\t\tsubject.stateOrProvinceName === \"Kopuncezis Krais\" &&\n\t\t\tsubject.localityName === \"Ashtinok\" &&\n\t\t\tsubject.streetAddress === \"221B Baker Street\" &&\n\t\t\tsubject.organizationName === \"Exumbran Convention\" &&\n\t\t\tArray.isArray(subject.organizationalUnitName) &&\n\t\t\tsubject.organizationalUnitName.length === 2 &&\n\t\t\tsubject.organizationalUnitName[0] === \"Exumbran Council\" &&\n\t\t\tsubject.organizationalUnitName[1] ===\n\t\t\t\t\"Exumbran Janitorial Service\" &&\n\t\t\tArray.isArray(subject.names) &&\n\t\t\tsubject.names.length === 9\n\t\t)) {\n\t\t\tthrow new Error(\"Bad subject\");\n\t\t}`, material.rsaCertificate))\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestSignatureAlgorithm(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Known\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tresult := signatureAlgorithm(gox509.MD5WithRSA)\n\t\tassert.Equal(t, \"MD5-RSA\", result)\n\t})\n\n\tt.Run(\"Unknown\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tresult := signatureAlgorithm(gox509.UnknownSignatureAlgorithm)\n\t\tassert.Equal(t, \"UnknownSignatureAlgorithm\", result)\n\t})\n}\n\nfunc TestMakePublicKey(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Unsupported\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := makePublicKey(nil)\n\t\tassert.EqualError(t, err, \"unsupported public key algorithm\")\n\t})\n}\n\nfunc TestMakeCertificateUnsupportedKey(t *testing.T) {\n\tt.Parallel()\n\n\t_, err := makeCertificate(&gox509.Certificate{})\n\tassert.EqualError(t, err, \"unsupported public key algorithm\")\n}\n"
  },
  {
    "path": "internal/js/modules/k6/data/data.go",
    "content": "// Package data implements `k6/data` js module for k6.\n// This modules provide utility types to work with data in an efficient way.\npackage data\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct {\n\t\tshared sharedArrays\n\t}\n\n\t// Data represents an instance of the data module.\n\tData struct {\n\t\tvu     modules.VU\n\t\tshared *sharedArrays\n\t}\n\n\tsharedArrays struct {\n\t\tdata map[string]sharedArray\n\t\tmu   sync.RWMutex\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &Data{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{\n\t\tshared: sharedArrays{\n\t\t\tdata: make(map[string]sharedArray),\n\t\t},\n\t}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (rm *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &Data{\n\t\tvu:     vu,\n\t\tshared: &rm.shared,\n\t}\n}\n\n// Exports returns the exports of the data module.\nfunc (d *Data) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"SharedArray\": d.sharedArray,\n\t\t},\n\t}\n}\n\nconst asyncFunctionNotSupportedMsg = \"SharedArray constructor does not support async functions as second argument\"\n\n// sharedArray is a constructor returning a shareable read-only array\n// indentified by the name and having their contents be whatever the call returns\nfunc (d *Data) sharedArray(call sobek.ConstructorCall) *sobek.Object {\n\trt := d.vu.Runtime()\n\n\tif d.vu.State() != nil {\n\t\tcommon.Throw(rt, errors.New(\"new SharedArray must be called in the init context\"))\n\t}\n\n\tname := call.Argument(0).String()\n\tif name == \"\" {\n\t\tcommon.Throw(rt, errors.New(\"empty name provided to SharedArray's constructor\"))\n\t}\n\tval := call.Argument(1)\n\n\tif common.IsAsyncFunction(rt, val) {\n\t\tcommon.Throw(rt, errors.New(asyncFunctionNotSupportedMsg))\n\t}\n\n\tfn, ok := sobek.AssertFunction(val)\n\tif !ok {\n\t\tcommon.Throw(rt, errors.New(\"a function is expected as the second argument of SharedArray's constructor\"))\n\t}\n\n\tbuilder := func() (sharedArray, error) { return getSharedArrayFromCall(rt, fn) }\n\tarray, err := d.shared.loadOrStore(name, builder)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\treturn array.wrap(rt).ToObject(rt)\n}\n\n// RecordReader is the interface that wraps the action of reading records from a resource.\n//\n// The data module RecordReader interface is implemented by types that can read data that can be\n// treated as records, from data sources such as a CSV file, etc.\ntype RecordReader interface {\n\tRead() (any, error)\n}\n\n// NewSharedArrayFrom creates a new shared array from the provided [RecordReader].\n//\n// This function is not exposed to the JS runtime. It is used internally to instantiate\n// shared arrays without having to go through the whole JS runtime machinery, which effectively has\n// a big performance impact (e.g. when filling a shared array from a CSV file).\n//\n// The rt argument is an explicit runtime parameter to retain control over which VU runtime the\n// function is executed in. This is important because the shared array underlying implementation\n// relies on maintaining a single instance of arrays for the whole test setup and VUs.\n//\n// The name argument uniquely identifies the shared array and must not be empty.\n//\n// The r argument is a [RecordReader] from which records are read and stored in the shared array.\nfunc (d *Data) NewSharedArrayFrom(rt *sobek.Runtime, name string, r RecordReader) (func() *sobek.Object, error) {\n\tif name == \"\" {\n\t\treturn nil, errors.New(\"empty name provided to SharedArray's constructor\")\n\t}\n\n\t// The builder function is passed to loadOrStore, which ensures it is only\n\t// executed once for a given name. This guarantees the underlying data is\n\t// initialized exactly once, even if multiple VUs call this function concurrently\n\t// with the same name.\n\tbuilder := func() (sharedArray, error) {\n\t\tvar arr []string\n\t\tfor {\n\t\t\trecord, err := r.Read()\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn sharedArray{}, fmt.Errorf(\"failed to read record; reason: %w\", err)\n\t\t\t}\n\n\t\t\tmarshaled, err := json.Marshal(record)\n\t\t\tif err != nil {\n\t\t\t\treturn sharedArray{}, fmt.Errorf(\"failed to marshal record; reason: %w\", err)\n\t\t\t}\n\n\t\t\tarr = append(arr, string(marshaled))\n\t\t}\n\n\t\treturn sharedArray{arr: arr}, nil\n\t}\n\n\tarray, err := d.shared.loadOrStore(name, builder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn func() *sobek.Object {\n\t\treturn array.wrap(rt).ToObject(rt)\n\t}, nil\n}\n\n// loadOrStore returns the shared array associated with the given name. If no array\n// exists for that name, it invokes the builder function to create one and stores it.\n//\n// This method is thread-safe. The builder function is guaranteed to be called at most\n// once for each unique name, even if multiple goroutines call loadOrStore concurrently\n// with the same name.\nfunc (s *sharedArrays) loadOrStore(name string, builder func() (sharedArray, error)) (sharedArray, error) {\n\t// Try read-only lookup first\n\ts.mu.RLock()\n\tarr, ok := s.data[name]\n\ts.mu.RUnlock()\n\tif ok {\n\t\treturn arr, nil\n\t}\n\n\t// Not found, acquire write lock\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\t// Double-check after acquiring write lock\n\tif arr, ok = s.data[name]; ok {\n\t\treturn arr, nil\n\t}\n\n\tarr, err := builder()\n\tif err != nil {\n\t\treturn arr, err\n\t}\n\ts.data[name] = arr\n\treturn arr, nil\n}\n\nfunc getSharedArrayFromCall(rt *sobek.Runtime, call sobek.Callable) (sharedArray, error) {\n\tsobekValue, err := call(sobek.Undefined())\n\tif err != nil {\n\t\treturn sharedArray{}, err\n\t}\n\tobj := sobekValue.ToObject(rt)\n\tif obj.ClassName() != \"Array\" {\n\t\treturn sharedArray{}, errors.New(\"only arrays can be made into SharedArray\") // TODO better error\n\t}\n\tarr := make([]string, obj.Get(\"length\").ToInteger())\n\n\tstringifyFunc, _ := sobek.AssertFunction(rt.GlobalObject().Get(\"JSON\").ToObject(rt).Get(\"stringify\"))\n\tvar val sobek.Value\n\tfor i := range arr {\n\t\tval, err = stringifyFunc(sobek.Undefined(), obj.Get(strconv.Itoa(i)))\n\t\tif err != nil {\n\t\t\treturn sharedArray{}, err\n\t\t}\n\t\tarr[i] = val.String()\n\t}\n\n\treturn sharedArray{arr: arr}, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/data/data_test.go",
    "content": "package data\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nfunc TestNewSharedArrayFromReusesExistingArrays(t *testing.T) {\n\tt.Parallel()\n\n\truntime := modulestest.NewRuntime(t)\n\tdataModule, ok := New().NewModuleInstance(runtime.VU).(*Data)\n\trequire.True(t, ok)\n\n\treader := newCountingRecordReader([][]string{\n\t\t{\"a\", \"b\"},\n\t})\n\n\t_, err := dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"shared\", reader)\n\trequire.NoError(t, err)\n\trequire.Positive(t, reader.reads.Load())\n\n\tanotherReader := newCountingRecordReader([][]string{\n\t\t{\"x\", \"y\"},\n\t})\n\n\t_, err = dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"shared\", anotherReader)\n\trequire.NoError(t, err)\n\trequire.Zero(t, anotherReader.reads.Load())\n}\n\nfunc TestSharedArraysLoadOrStoreBuildsOnce(t *testing.T) {\n\tt.Parallel()\n\n\tarrays := &sharedArrays{\n\t\tdata: make(map[string]sharedArray),\n\t}\n\n\tvar buildsCount atomic.Int32\n\tbuilder := func() (sharedArray, error) { //nolint:unparam\n\t\tbuildsCount.Add(1)\n\t\treturn sharedArray{arr: []string{\"v\"}}, nil\n\t}\n\n\tvar wg sync.WaitGroup\n\tconst goroutines = 10\n\tfor range goroutines {\n\t\twg.Go(func() {\n\t\t\t_, _ = arrays.loadOrStore(\"shared\", builder)\n\t\t})\n\t}\n\n\twg.Wait()\n\trequire.Equal(t, int32(1), buildsCount.Load())\n}\n\ntype countingRecordReader struct {\n\trecords [][]string\n\tindex   int\n\treads   atomic.Int32\n}\n\nfunc newCountingRecordReader(records [][]string) *countingRecordReader {\n\treturn &countingRecordReader{records: records}\n}\n\nfunc (r *countingRecordReader) Read() (any, error) {\n\tif r.index >= len(r.records) {\n\t\treturn nil, io.EOF\n\t}\n\n\tr.reads.Add(1)\n\trecord := r.records[r.index]\n\tr.index++\n\treturn record, nil\n}\n\nfunc TestNewSharedArrayFromConcurrentMultiVU(t *testing.T) {\n\tt.Parallel()\n\n\troot := New()\n\tvar totalReads atomic.Int32\n\n\tvar wg sync.WaitGroup\n\tconst vus = 10\n\n\tfor range vus {\n\t\twg.Go(func() {\n\t\t\truntime := modulestest.NewRuntime(t)\n\t\t\tdataModule, ok := root.NewModuleInstance(runtime.VU).(*Data)\n\t\t\trequire.True(t, ok)\n\n\t\t\treader := &sharedCountingRecordReader{\n\t\t\t\trecords: [][]string{{\"a\", \"b\"}, {\"c\", \"d\"}},\n\t\t\t\treads:   &totalReads,\n\t\t\t}\n\t\t\t_, err := dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"concurrent-test\", reader)\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n\n\twg.Wait()\n\t// Only one reader should have been consumed (2 records read once)\n\trequire.Equal(t, int32(2), totalReads.Load())\n}\n\n// sharedCountingRecordReader uses a shared atomic counter across instances.\ntype sharedCountingRecordReader struct {\n\trecords [][]string\n\tindex   int\n\treads   *atomic.Int32\n}\n\nfunc (r *sharedCountingRecordReader) Read() (any, error) {\n\tif r.index >= len(r.records) {\n\t\treturn nil, io.EOF\n\t}\n\n\tr.reads.Add(1)\n\trecord := r.records[r.index]\n\tr.index++\n\treturn record, nil\n}\n\nfunc TestNewSharedArrayFromReaderError(t *testing.T) {\n\tt.Parallel()\n\n\truntime := modulestest.NewRuntime(t)\n\tdataModule, ok := New().NewModuleInstance(runtime.VU).(*Data)\n\trequire.True(t, ok)\n\n\terrReader := &errorRecordReader{\n\t\trecords: [][]string{{\"a\", \"b\"}},\n\t\terrAt:   1, // Error on second read\n\t}\n\n\t_, err := dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"error-test\", errReader)\n\trequire.Error(t, err)\n}\n\ntype errorRecordReader struct {\n\trecords [][]string\n\tindex   int\n\terrAt   int\n}\n\nfunc (r *errorRecordReader) Read() (any, error) {\n\tif r.index == r.errAt {\n\t\treturn nil, errors.New(\"simulated read error\")\n\t}\n\tif r.index >= len(r.records) {\n\t\treturn nil, io.EOF\n\t}\n\trecord := r.records[r.index]\n\tr.index++\n\treturn record, nil\n}\n\nfunc TestNewSharedArrayFromMarshalError(t *testing.T) {\n\tt.Parallel()\n\n\truntime := modulestest.NewRuntime(t)\n\tdataModule, ok := New().NewModuleInstance(runtime.VU).(*Data)\n\trequire.True(t, ok)\n\n\t// channels cannot be marshaled to JSON\n\tunmarshalableReader := &unmarshalableRecordReader{}\n\n\t_, err := dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"marshal-error\", unmarshalableReader)\n\trequire.Error(t, err)\n}\n\ntype unmarshalableRecordReader struct {\n\tcalled bool\n}\n\nfunc (r *unmarshalableRecordReader) Read() (any, error) {\n\tif r.called {\n\t\treturn nil, io.EOF\n\t}\n\tr.called = true\n\t// channels can't be JSON marshaled\n\treturn make(chan int), nil\n}\n\nfunc TestNewSharedArrayFromEmpty(t *testing.T) {\n\tt.Parallel()\n\n\truntime := modulestest.NewRuntime(t)\n\tdataModule, ok := New().NewModuleInstance(runtime.VU).(*Data)\n\trequire.True(t, ok)\n\n\temptyReader := newCountingRecordReader([][]string{})\n\n\tfn, err := dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"empty\", emptyReader)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, fn)\n\tresult := fn()\n\trequire.NotNil(t, result)\n\n\tlength := result.Get(\"length\")\n\trequire.Equal(t, int64(0), length.ToInteger())\n}\n\nfunc TestNewSharedArrayFromDifferentNames(t *testing.T) {\n\tt.Parallel()\n\n\truntime := modulestest.NewRuntime(t)\n\tdataModule, ok := New().NewModuleInstance(runtime.VU).(*Data)\n\trequire.True(t, ok)\n\n\treader1 := newCountingRecordReader([][]string{{\"a\"}})\n\treader2 := newCountingRecordReader([][]string{{\"b\"}})\n\n\t_, err := dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"name1\", reader1)\n\trequire.NoError(t, err)\n\t_, err = dataModule.NewSharedArrayFrom(runtime.VU.Runtime(), \"name2\", reader2)\n\trequire.NoError(t, err)\n\n\t// Both readers should have been consumed since names are different\n\trequire.Positive(t, reader1.reads.Load())\n\trequire.Positive(t, reader2.reads.Load())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/data/share.go",
    "content": "package data\n\nimport (\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n)\n\n// TODO fix it not working really well with setupData or just make it more broken\n// TODO fix it working with console.log\ntype sharedArray struct {\n\tarr []string\n}\n\ntype wrappedSharedArray struct {\n\tsharedArray\n\n\trt       *sobek.Runtime\n\tfreeze   sobek.Callable\n\tisFrozen sobek.Callable\n\tparse    sobek.Callable\n}\n\nfunc (s sharedArray) wrap(rt *sobek.Runtime) sobek.Value {\n\tfreeze, _ := sobek.AssertFunction(rt.GlobalObject().Get(\"Object\").ToObject(rt).Get(\"freeze\"))\n\tisFrozen, _ := sobek.AssertFunction(rt.GlobalObject().Get(\"Object\").ToObject(rt).Get(\"isFrozen\"))\n\tparse, _ := sobek.AssertFunction(rt.GlobalObject().Get(\"JSON\").ToObject(rt).Get(\"parse\"))\n\treturn rt.NewDynamicArray(wrappedSharedArray{\n\t\tsharedArray: s,\n\t\trt:          rt,\n\t\tfreeze:      freeze,\n\t\tisFrozen:    isFrozen,\n\t\tparse:       parse,\n\t})\n}\n\nfunc (s wrappedSharedArray) Set(_ int, _ sobek.Value) bool {\n\tpanic(s.rt.NewTypeError(\"SharedArray is immutable\")) // this is specifically a type error\n}\n\nfunc (s wrappedSharedArray) SetLen(_ int) bool {\n\tpanic(s.rt.NewTypeError(\"SharedArray is immutable\")) // this is specifically a type error\n}\n\nfunc (s wrappedSharedArray) Get(index int) sobek.Value {\n\tif index < 0 || index >= len(s.arr) {\n\t\treturn sobek.Undefined()\n\t}\n\tval, err := s.parse(sobek.Undefined(), s.rt.ToValue(s.arr[index]))\n\tif err != nil {\n\t\tcommon.Throw(s.rt, err)\n\t}\n\n\terr = s.deepFreeze(s.rt, val)\n\tif err != nil {\n\t\tcommon.Throw(s.rt, err)\n\t}\n\n\treturn val\n}\n\nfunc (s wrappedSharedArray) Len() int {\n\treturn len(s.arr)\n}\n\nfunc (s wrappedSharedArray) deepFreeze(rt *sobek.Runtime, val sobek.Value) error {\n\tif val != nil && sobek.IsNull(val) {\n\t\treturn nil\n\t}\n\n\t_, err := s.freeze(sobek.Undefined(), val)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\to := val.ToObject(rt)\n\tif o == nil {\n\t\treturn nil\n\t}\n\tfor _, key := range o.Keys() {\n\t\tprop := o.Get(key)\n\t\tif prop != nil {\n\t\t\t// isFrozen returns true for all non objects so it we don't need to check that\n\t\t\tfrozen, err := s.isFrozen(sobek.Undefined(), prop)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif !frozen.ToBoolean() { // prevent cycles\n\t\t\t\tif err = s.deepFreeze(rt, prop); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/data/share_test.go",
    "content": "package data\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js/compiler\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nconst makeArrayScript = `\nvar array = new data.SharedArray(\"shared\",function() {\n    var n = 50;\n    var arr = new Array(n);\n    for (var i = 0 ; i <n; i++) {\n        arr[i] = {value: \"something\" +i};\n    }\n\treturn arr;\n});\n`\n\nconst initGlobals = `\n\tglobalThis.data = require(\"k6/data\");\n\tglobalThis.SharedArray = data.SharedArray;\n`\n\nfunc newConfiguredRuntime(t testing.TB) (*modulestest.Runtime, error) {\n\truntime := modulestest.NewRuntime(t)\n\n\terr := runtime.SetupModuleSystem(map[string]any{\"k6/data\": New()}, nil, compiler.New(runtime.VU.InitEnv().Logger))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t_, err = runtime.VU.Runtime().RunString(initGlobals)\n\treturn runtime, err\n}\n\nfunc configuredRuntimeFromAnother(t testing.TB, another *modulestest.Runtime) (*modulestest.Runtime, error) {\n\truntime := modulestest.NewRuntime(t)\n\terr := runtime.SetupModuleSystemFromAnother(another)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t_, err = runtime.VU.Runtime().RunString(initGlobals)\n\treturn runtime, err\n}\n\nfunc TestSharedArrayConstructorExceptions(t *testing.T) {\n\tt.Parallel()\n\tcases := map[string]struct {\n\t\tcode, err string\n\t}{\n\t\t\"returning string\": {\n\t\t\tcode: `new SharedArray(\"wat\", function() {return \"whatever\"});`,\n\t\t\terr:  \"only arrays can be made into SharedArray\",\n\t\t},\n\t\t\"empty name\": {\n\t\t\tcode: `new SharedArray(\"\", function() {return []});`,\n\t\t\terr:  \"empty name provided to SharedArray's constructor\",\n\t\t},\n\t\t\"function in the data\": {\n\t\t\tcode: `\n\t\t\tvar s = new SharedArray(\"wat2\", function() {return [{s: function() {}}]});\n\t\t\tif (s[0].s !== undefined) {\n\t\t\t\tthrow \"s[0].s should be undefined\"\n\t\t\t}\n\t\t`,\n\t\t\terr: \"\",\n\t\t},\n\t\t\"not a function\": {\n\t\t\tcode: `var s = new SharedArray(\"wat3\", \"astring\");`,\n\t\t\terr:  \"a function is expected\",\n\t\t},\n\t\t\"async function\": {\n\t\t\tcode: `var s = new SharedArray(\"wat3\", async function() {});`,\n\t\t\terr:  \"SharedArray constructor does not support async functions as second argument\",\n\t\t},\n\t\t\"async lambda\": {\n\t\t\tcode: `var s = new SharedArray(\"wat3\", async () => {});`,\n\t\t\terr:  \"SharedArray constructor does not support async functions as second argument\",\n\t\t},\n\t}\n\n\tfor name, testCase := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\truntime, err := newConfiguredRuntime(t)\n\t\t\trequire.NoError(t, err)\n\t\t\t_, err = runtime.VU.Runtime().RunString(testCase.code)\n\t\t\tif testCase.err == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn // the t.Run\n\t\t\t}\n\n\t\t\trequire.Error(t, err)\n\t\t\texc := new(sobek.Exception)\n\t\t\trequire.True(t, errors.As(err, &exc))\n\t\t\trequire.Contains(t, exc.Error(), testCase.err)\n\t\t})\n\t}\n}\n\nfunc TestSharedArrayAnotherRuntimeExceptions(t *testing.T) {\n\tt.Parallel()\n\n\t// use strict is required as otherwise just nothing happens\n\tcases := map[string]struct {\n\t\tcode, err string\n\t}{\n\t\t\"setting in for-of\": {\n\t\t\tcode: `'use strict'; for (var v of array) { v.data = \"bad\"; }`,\n\t\t\terr:  \"Cannot add property data, object is not extensible\",\n\t\t},\n\t\t\"setting from index\": {\n\t\t\tcode: `'use strict'; array[2].data2 = \"bad2\"`,\n\t\t\terr:  \"Cannot add property data2, object is not extensible\",\n\t\t},\n\t\t\"setting property on the shared array\": {\n\t\t\tcode: `'use strict'; array.something = \"something\"`,\n\t\t\terr:  `Cannot set property \"something\" on a dynamic array`,\n\t\t},\n\t\t\"setting index on the shared array\": {\n\t\t\tcode: `'use strict'; array[2] = \"something\"`,\n\t\t\terr:  \"SharedArray is immutable\",\n\t\t},\n\t}\n\n\tfor name, testCase := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttestRuntime, err := newConfiguredRuntime(t)\n\t\t\trt := testRuntime.VU.Runtime()\n\t\t\trequire.NoError(t, err)\n\t\t\t_, err = rt.RunString(makeArrayScript)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestRuntime, err = configuredRuntimeFromAnother(t, testRuntime)\n\t\t\trt = testRuntime.VU.Runtime()\n\t\t\trequire.NoError(t, err)\n\t\t\t_, err = rt.RunString(makeArrayScript)\n\t\t\trequire.NoError(t, err)\n\t\t\t_, err = rt.RunString(testCase.code)\n\t\t\tif testCase.err == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\treturn // the t.Run\n\t\t\t}\n\n\t\t\trequire.Error(t, err)\n\t\t\texc := new(sobek.Exception)\n\t\t\trequire.True(t, errors.As(err, &exc))\n\t\t\trequire.Contains(t, exc.Error(), testCase.err)\n\t\t})\n\t}\n}\n\nfunc TestSharedArrayAnotherRuntimeWorking(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\tvu := &modulestest.VU{\n\t\tRuntimeField: rt,\n\t\tInitEnvField: &common.InitEnvironment{},\n\t\tCtxField:     context.Background(),\n\t\tStateField:   nil,\n\t}\n\tm, ok := New().NewModuleInstance(vu).(*Data)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"data\", m.Exports().Named))\n\n\t_, err := rt.RunString(makeArrayScript)\n\trequire.NoError(t, err)\n\n\t// create another Runtime with new ctx but keep the initEnv\n\trt = sobek.New()\n\tvu.RuntimeField = rt\n\tvu.CtxField = context.Background()\n\trequire.NoError(t, rt.Set(\"data\", m.Exports().Named))\n\n\t_, err = rt.RunString(`var array = new data.SharedArray(\"shared\", function() {throw \"wat\";});`)\n\trequire.NoError(t, err)\n\n\t_, err = rt.RunString(`\n\tif (array[2].value !== \"something2\") {\n\t\tthrow new Error(\"bad array[2]=\"+array[2].value);\n\t}\n\tif (array.length != 50) {\n\t\tthrow new Error(\"bad length \" +array.length);\n\t}\n\n\tvar i = 0;\n\tfor (var v of array) {\n\t\tif (v.value !== \"something\"+i) {\n\t\t\tthrow new Error(\"bad v.value=\"+v.value+\" for i=\"+i);\n\t\t}\n\t\ti++;\n\t}\n\n\ti = 0;\n\tarray.forEach(function(v){\n\t\tif (v.value !== \"something\"+i) {\n\t\t\tthrow new Error(\"bad v.value=\"+v.value+\" for i=\"+i);\n\t\t}\n\t\ti++;\n\t});\n\n\n\t`)\n\trequire.NoError(t, err)\n}\n\nfunc TestSharedArrayRaceInInitialization(t *testing.T) {\n\tt.Parallel()\n\n\tconst instances = 10\n\tconst repeats = 100\n\tfor range repeats {\n\t\truntimes := make([]*sobek.Runtime, instances)\n\t\tfor j := range instances {\n\t\t\truntime, err := newConfiguredRuntime(t)\n\t\t\trequire.NoError(t, err)\n\t\t\truntimes[j] = runtime.VU.Runtime()\n\t\t}\n\t\tvar wg sync.WaitGroup\n\t\tfor _, rt := range runtimes {\n\t\t\twg.Go(func() {\n\t\t\t\t_, err := rt.RunString(`var array = new data.SharedArray(\"shared\", function() {return [1,2,3,4,5,6,7,8,9, 10]});`)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t})\n\t\t}\n\t\tch := make(chan struct{})\n\t\tgo func() {\n\t\t\twg.Wait()\n\t\t\tclose(ch)\n\t\t}()\n\n\t\tselect {\n\t\tcase <-ch:\n\t\t\t// everything is fine\n\t\tcase <-time.After(time.Second * 10):\n\t\t\tt.Fatal(\"Took too long probably locked up\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/encoding/encoding.go",
    "content": "// Package encoding provides encoding/decoding functionality for the k6\npackage encoding\n\nimport (\n\t\"encoding/base64\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// Encoding represents an instance of the encoding module.\n\tEncoding struct {\n\t\tvu modules.VU\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &Encoding{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &Encoding{vu: vu}\n}\n\n// Exports returns the exports of the encoding module.\nfunc (e *Encoding) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"b64encode\": e.b64Encode,\n\t\t\t\"b64decode\": e.b64Decode,\n\t\t},\n\t}\n}\n\n// b64encode returns the base64 encoding of input as a string.\n// The data type of input can be a string, []byte or ArrayBuffer.\nfunc (e *Encoding) b64Encode(input any, encoding string) string {\n\tdata, err := common.ToBytes(input)\n\tif err != nil {\n\t\tcommon.Throw(e.vu.Runtime(), err)\n\t}\n\tswitch encoding {\n\tcase \"rawstd\":\n\t\treturn base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString(data)\n\tcase \"std\":\n\t\treturn base64.StdEncoding.EncodeToString(data)\n\tcase \"rawurl\":\n\t\treturn base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(data)\n\tcase \"url\":\n\t\treturn base64.URLEncoding.EncodeToString(data)\n\tdefault:\n\t\treturn base64.StdEncoding.EncodeToString(data)\n\t}\n}\n\n// b64decode returns the decoded data of the base64 encoded input string using\n// the given encoding. If format is \"s\" it returns the data as a string,\n// otherwise as an ArrayBuffer.\nfunc (e *Encoding) b64Decode(input, encoding, format string) any {\n\tvar (\n\t\toutput []byte\n\t\terr    error\n\t)\n\n\tswitch encoding {\n\tcase \"rawstd\":\n\t\toutput, err = base64.StdEncoding.WithPadding(base64.NoPadding).DecodeString(input)\n\tcase \"std\":\n\t\toutput, err = base64.StdEncoding.DecodeString(input)\n\tcase \"rawurl\":\n\t\toutput, err = base64.URLEncoding.WithPadding(base64.NoPadding).DecodeString(input)\n\tcase \"url\":\n\t\toutput, err = base64.URLEncoding.DecodeString(input)\n\tdefault:\n\t\toutput, err = base64.StdEncoding.DecodeString(input)\n\t}\n\n\tif err != nil {\n\t\tcommon.Throw(e.vu.Runtime(), err)\n\t}\n\n\tvar out any\n\tif format == \"s\" {\n\t\tout = string(output)\n\t} else {\n\t\tab := e.vu.Runtime().NewArrayBuffer(output)\n\t\tout = &ab\n\t}\n\n\treturn out\n}\n"
  },
  {
    "path": "internal/js/modules/k6/encoding/encoding_test.go",
    "content": "package encoding\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nfunc makeRuntime(t *testing.T) *sobek.Runtime {\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tCtxField:     context.Background(),\n\t\t\tRuntimeField: rt,\n\t\t\tInitEnvField: &common.InitEnvironment{},\n\t\t\tStateField:   nil,\n\t\t},\n\t).(*Encoding)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"encoding\", m.Exports().Named))\n\n\treturn rt\n}\n\nfunc TestEncodingAlgorithms(t *testing.T) {\n\tt.Parallel()\n\n\tif testing.Short() {\n\t\treturn\n\t}\n\n\tt.Run(\"Base64\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"DefaultEnc\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"aGVsbG8gd29ybGQ=\";\n\t\t\tvar encoded = encoding.b64encode(\"hello world\");\n\t\t\tif (encoded !== correct) {\n\t\t\t\tthrow new Error(\"Encoding mismatch: \" + encoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"DefaultDec\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"hello world\";\n\t\t\tvar decBin = encoding.b64decode(\"aGVsbG8gd29ybGQ=\");\n\n\t\t\tvar decText = String.fromCharCode.apply(null, new Uint8Array(decBin));\n\t\t\tdecText = decodeURIComponent(escape(decText));\n\t\t\tif (decText !== correct) {\n\t\t\t\tthrow new Error(\"Decoding mismatch: \" + decText);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"DefaultArrayBufferEnc\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar exp = \"aGVsbG8=\";\n\t\t\tvar input = new Uint8Array([104, 101, 108, 108, 111]); // \"hello\"\n\t\t\tvar encoded = encoding.b64encode(input.buffer);\n\t\t\tif (encoded !== exp) {\n\t\t\t\tthrow new Error(\"Encoding mismatch: \" + encoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"DefaultArrayBufferDec\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar exp = \"hello\";\n\t\t\tvar decBin = encoding.b64decode(\"aGVsbG8=\");\n\t\t\tvar decText = String.fromCharCode.apply(null, new Uint8Array(decBin));\n\t\t\tdecText = decodeURIComponent(escape(decText));\n\t\t\tif (decText !== exp) {\n\t\t\t\tthrow new Error(\"Decoding mismatch: \" + decText);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"DefaultUnicodeEnc\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"44GT44KT44Gr44Gh44Gv5LiW55WM\";\n\t\t\tvar encoded = encoding.b64encode(\"こんにちは世界\", \"std\");\n\t\t\tif (encoded !== correct) {\n\t\t\t\tthrow new Error(\"Encoding mismatch: \" + encoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"DefaultUnicodeDec\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"こんにちは世界\";\n\t\t\tvar decBin = encoding.b64decode(\"44GT44KT44Gr44Gh44Gv5LiW55WM\");\n\t\t\tvar decText = String.fromCharCode.apply(null, new Uint8Array(decBin));\n\t\t\tdecText = decodeURIComponent(escape(decText));\n\t\t\tif (decText !== correct) {\n\t\t\t\tthrow new Error(\"Decoding mismatch: \" + decText);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"StdEnc\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"aGVsbG8gd29ybGQ=\";\n\t\t\tvar encoded = encoding.b64encode(\"hello world\", \"std\");\n\t\t\tif (encoded !== correct) {\n\t\t\t\tthrow new Error(\"Encoding mismatch: \" + encoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"StdDec\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"hello world\";\n\t\t\tvar decoded = encoding.b64decode(\"aGVsbG8gd29ybGQ=\", \"std\", \"s\");\n\t\t\tif (decoded !== correct) {\n\t\t\t\tthrow new Error(\"Decoding mismatch: \" + decoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"RawStdEnc\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"aGVsbG8gd29ybGQ\";\n\t\t\tvar encoded = encoding.b64encode(\"hello world\", \"rawstd\");\n\t\t\tif (encoded !== correct) {\n\t\t\t\tthrow new Error(\"Encoding mismatch: \" + encoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"RawStdDec\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"hello world\";\n\t\t\tvar decoded = encoding.b64decode(\"aGVsbG8gd29ybGQ\", \"rawstd\", \"s\");\n\t\t\tif (decoded !== correct) {\n\t\t\t\tthrow new Error(\"Decoding mismatch: \" + decoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"URLEnc\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"5bCP6aO85by-Li4=\";\n\t\t\tvar encoded = encoding.b64encode(\"小飼弾..\", \"url\");\n\t\t\tif (encoded !== correct) {\n\t\t\t\tthrow new Error(\"Encoding mismatch: \" + encoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"URLDec\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"小飼弾..\";\n\t\t\tvar decoded = encoding.b64decode(\"5bCP6aO85by-Li4=\", \"url\", \"s\");\n\t\t\tif (decoded !== correct) {\n\t\t\t\tthrow new Error(\"Decoding mismatch: \" + decoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"RawURLEnc\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"5bCP6aO85by-Li4\";\n\t\t\tvar encoded = encoding.b64encode(\"小飼弾..\", \"rawurl\");\n\t\t\tif (encoded !== correct) {\n\t\t\t\tthrow new Error(\"Encoding mismatch: \" + encoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"RawURLDec\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trt := makeRuntime(t)\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar correct = \"小飼弾..\";\n\t\t\tvar decoded = encoding.b64decode(\"5bCP6aO85by-Li4\", \"rawurl\", \"s\");\n\t\t\tif (decoded !== correct) {\n\t\t\t\tthrow new Error(\"Decoding mismatch: \" + decoded);\n\t\t\t}`)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/execution/execution.go",
    "content": "// Package execution implements k6/execution which lets script find out more about it is execution.\npackage execution\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// ModuleInstance represents an instance of the execution module.\n\tModuleInstance struct {\n\t\tvu  modules.VU\n\t\tobj *sobek.Object\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\tmi := &ModuleInstance{vu: vu}\n\trt := vu.Runtime()\n\to := rt.NewObject()\n\tdefProp := func(name string, newInfo func() (*sobek.Object, error)) {\n\t\terr := o.DefineAccessorProperty(name, rt.ToValue(func() sobek.Value {\n\t\t\tobj, err := newInfo()\n\t\t\tif err != nil {\n\t\t\t\tcommon.Throw(rt, err)\n\t\t\t}\n\t\t\treturn obj\n\t\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, err)\n\t\t}\n\t}\n\tdefProp(\"instance\", mi.newInstanceInfo)\n\tdefProp(\"scenario\", mi.newScenarioInfo)\n\tdefProp(\"test\", mi.newTestInfo)\n\tdefProp(\"vu\", mi.newVUInfo)\n\n\tmi.obj = o\n\n\treturn mi\n}\n\n// Exports returns the exports of the execution module.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{Default: mi.obj}\n}\n\nvar errRunInInitContext = errors.New(\"getting scenario information outside of the VU context is not supported\")\n\n// newScenarioInfo returns a sobek.Object with property accessors to retrieve\n// information about the scenario the current VU is running in.\nfunc (mi *ModuleInstance) newScenarioInfo() (*sobek.Object, error) {\n\trt := mi.vu.Runtime()\n\tvuState := mi.vu.State()\n\tif vuState == nil {\n\t\treturn nil, errRunInInitContext\n\t}\n\tgetScenarioState := func() *lib.ScenarioState {\n\t\tss := lib.GetScenarioState(mi.vu.Context())\n\t\tif ss == nil {\n\t\t\tcommon.Throw(rt, errRunInInitContext)\n\t\t}\n\t\treturn ss\n\t}\n\n\tsi := map[string]func() any{\n\t\t\"name\": func() any {\n\t\t\treturn getScenarioState().Name\n\t\t},\n\t\t\"executor\": func() any {\n\t\t\treturn getScenarioState().Executor\n\t\t},\n\t\t\"startTime\": func() any {\n\t\t\t//nolint:lll\n\t\t\t// Return the timestamp in milliseconds, since that's how JS\n\t\t\t// timestamps usually are:\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#time_value_or_timestamp_number\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#return_value\n\t\t\treturn getScenarioState().StartTime.UnixNano() / int64(time.Millisecond)\n\t\t},\n\t\t\"progress\": func() any {\n\t\t\tp, _ := getScenarioState().ProgressFn()\n\t\t\treturn p\n\t\t},\n\t\t\"iterationInInstance\": func() any {\n\t\t\tif vuState.GetScenarioLocalVUIter == nil {\n\t\t\t\tcommon.Throw(rt, errRunInInitContext)\n\t\t\t}\n\n\t\t\treturn vuState.GetScenarioLocalVUIter()\n\t\t},\n\t\t\"iterationInTest\": func() any {\n\t\t\tif vuState.GetScenarioGlobalVUIter == nil {\n\t\t\t\tcommon.Throw(rt, errRunInInitContext)\n\t\t\t}\n\n\t\t\treturn vuState.GetScenarioGlobalVUIter()\n\t\t},\n\t}\n\n\treturn newInfoObj(rt, si)\n}\n\n//nolint:lll\nvar errInstanceInfoInitContext = common.NewInitContextError(\"getting instance information in the init context is not supported\")\n\n// newInstanceInfo returns a sobek.Object with property accessors to retrieve\n// information about the local instance stats.\nfunc (mi *ModuleInstance) newInstanceInfo() (*sobek.Object, error) {\n\tes := lib.GetExecutionState(mi.vu.Context())\n\tif es == nil {\n\t\treturn nil, errInstanceInfoInitContext\n\t}\n\trt := mi.vu.Runtime()\n\n\tti := map[string]func() any{\n\t\t\"currentTestRunDuration\": func() any {\n\t\t\treturn float64(es.GetCurrentTestRunDuration()) / float64(time.Millisecond)\n\t\t},\n\t\t\"iterationsCompleted\": func() any {\n\t\t\treturn es.GetFullIterationCount()\n\t\t},\n\t\t\"iterationsInterrupted\": func() any {\n\t\t\treturn es.GetPartialIterationCount()\n\t\t},\n\t\t\"vusActive\": func() any {\n\t\t\treturn es.GetCurrentlyActiveVUsCount()\n\t\t},\n\t\t\"vusInitialized\": func() any {\n\t\t\treturn es.GetInitializedVUsCount()\n\t\t},\n\t}\n\n\treturn newInfoObj(rt, ti)\n}\n\nvar errTestInfoInitContext = common.NewInitContextError(\"getting test options in the init context is not supported\")\n\n// newTestInfo returns a sobek.Object with property accessors to retrieve\n// information and control execution of the overall test run.\nfunc (mi *ModuleInstance) newTestInfo() (*sobek.Object, error) {\n\t// the cache of sobek.Object in the optimal parsed form\n\t// for the consolidated and derived lib.Options\n\tvar optionsObject *sobek.Object\n\trt := mi.vu.Runtime()\n\tti := map[string]func() any{\n\t\t// stop the test run\n\t\t\"abort\": func() any {\n\t\t\treturn func(msg sobek.Value) {\n\t\t\t\treason := errext.AbortTest\n\t\t\t\tif !common.IsNullish(msg) {\n\t\t\t\t\treason = fmt.Sprintf(\"%s: %s\", reason, msg.String())\n\t\t\t\t}\n\t\t\t\trt.Interrupt(&errext.InterruptError{Reason: reason})\n\t\t\t}\n\t\t},\n\t\t\"fail\": func() any {\n\t\t\treturn func(msg sobek.Value) {\n\t\t\t\treason := errext.MarkedAsFailedTest\n\t\t\t\tif !common.IsNullish(msg) {\n\t\t\t\t\treason = fmt.Sprintf(\"%s: %s\", reason, msg.String())\n\t\t\t\t}\n\n\t\t\t\tif mi.vu.State() == nil {\n\t\t\t\t\tcommon.Throw(rt, fmt.Errorf(\"execution.test.fail() called outside of VU context\"))\n\t\t\t\t}\n\n\t\t\t\tmi.vu.State().Logger.Errorf(reason)\n\t\t\t\tmi.vu.State().TestStatus.MarkFailed()\n\t\t\t}\n\t\t},\n\t\t\"options\": func() any {\n\t\t\tvuState := mi.vu.State()\n\t\t\tif vuState == nil {\n\t\t\t\tcommon.Throw(rt, errTestInfoInitContext)\n\t\t\t}\n\t\t\tif optionsObject == nil {\n\t\t\t\topts, err := optionsAsObject(rt, vuState.Options)\n\t\t\t\tif err != nil {\n\t\t\t\t\tcommon.Throw(rt, err)\n\t\t\t\t}\n\t\t\t\toptionsObject = opts\n\t\t\t}\n\t\t\treturn optionsObject\n\t\t},\n\t}\n\n\treturn newInfoObj(rt, ti)\n}\n\nvar errVUInfoInitContex = common.NewInitContextError(\"getting VU information in the init context is not supported\")\n\n// newVUInfo returns a sobek.Object with property accessors to retrieve\n// information about the currently executing VU.\nfunc (mi *ModuleInstance) newVUInfo() (*sobek.Object, error) {\n\tvuState := mi.vu.State()\n\tif vuState == nil {\n\t\treturn nil, errVUInfoInitContex\n\t}\n\trt := mi.vu.Runtime()\n\n\tvi := map[string]func() any{\n\t\t\"idInInstance\":        func() any { return vuState.VUID },\n\t\t\"idInTest\":            func() any { return vuState.VUIDGlobal },\n\t\t\"iterationInInstance\": func() any { return vuState.Iteration },\n\t\t\"iterationInScenario\": func() any {\n\t\t\tif vuState.GetScenarioVUIter == nil {\n\t\t\t\t// hasn't been set yet, no iteration stats available\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\treturn vuState.GetScenarioVUIter()\n\t\t},\n\t}\n\n\to, err := newInfoObj(rt, vi)\n\tif err != nil {\n\t\treturn o, err\n\t}\n\ttagsDynamicObject := rt.NewDynamicObject(&tagsDynamicObject{\n\t\truntime: rt,\n\t\tstate:   vuState,\n\t})\n\n\t// This is kept for backwards compatibility reasons, but should be deprecated,\n\t// since tags are also accessible via vu.metrics.tags.\n\terr = o.Set(\"tags\", tagsDynamicObject)\n\tif err != nil {\n\t\treturn o, err\n\t}\n\tmetrics, err := newInfoObj(rt, map[string]func() any{\n\t\t\"tags\": func() any { return tagsDynamicObject },\n\t\t\"metadata\": func() any {\n\t\t\treturn rt.NewDynamicObject(&metadataDynamicObject{\n\t\t\t\truntime: rt,\n\t\t\t\tstate:   vuState,\n\t\t\t})\n\t\t},\n\t})\n\tif err != nil {\n\t\treturn o, err\n\t}\n\n\terr = o.Set(\"metrics\", metrics)\n\tif err != nil {\n\t\treturn o, err\n\t}\n\n\treturn o, err\n}\n\nfunc newInfoObj(rt *sobek.Runtime, props map[string]func() any) (*sobek.Object, error) {\n\to := rt.NewObject()\n\n\tfor p, get := range props {\n\t\terr := o.DefineAccessorProperty(p, rt.ToValue(get), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn o, nil\n}\n\n// optionsAsObject maps the lib.Options struct that contains the consolidated\n// and derived options configuration in a sobek.Object.\n//\n// When values are not set then the default value returned from JSON is used.\n// Most of the lib.Options are Nullable types so they will be null on default.\nfunc optionsAsObject(rt *sobek.Runtime, options lib.Options) (*sobek.Object, error) {\n\tb, err := json.Marshal(options)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to encode the lib.Options as json: %w\", err)\n\t}\n\n\t// Using the native JS parser function guarantees getting\n\t// the supported types for deep freezing the complex object.\n\tjsonParse, _ := sobek.AssertFunction(rt.GlobalObject().Get(\"JSON\").ToObject(rt).Get(\"parse\"))\n\tparsed, err := jsonParse(sobek.Undefined(), rt.ToValue(string(b)))\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tobj := parsed.ToObject(rt)\n\n\tmustDelete := func(prop string) {\n\t\tdelErr := obj.Delete(prop)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, delErr)\n\t\t}\n\t}\n\tmustSetReadOnlyProperty := func(k string, v any) {\n\t\tdefErr := obj.DefineDataProperty(k, rt.ToValue(v), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, defErr)\n\t\t}\n\t}\n\n\tmustDelete(\"vus\")\n\tmustDelete(\"iterations\")\n\tmustDelete(\"duration\")\n\tmustDelete(\"stages\")\n\n\tconsoleOutput := sobek.Null()\n\tif options.ConsoleOutput.Valid {\n\t\tconsoleOutput = rt.ToValue(options.ConsoleOutput.String)\n\t}\n\tmustSetReadOnlyProperty(\"consoleOutput\", consoleOutput)\n\n\tlocalIPs := sobek.Null()\n\tif options.LocalIPs.Valid {\n\t\traw, marshalErr := options.LocalIPs.MarshalText()\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, marshalErr)\n\t\t}\n\t\tlocalIPs = rt.ToValue(string(raw))\n\t}\n\tmustSetReadOnlyProperty(\"localIPs\", localIPs)\n\n\terr = common.FreezeObject(rt, obj)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\treturn obj, nil\n}\n\ntype tagsDynamicObject struct {\n\truntime *sobek.Runtime\n\tstate   *lib.State\n}\n\n// Get a property value for the key. May return nil if the property does not exist.\nfunc (o *tagsDynamicObject) Get(key string) sobek.Value {\n\ttcv := o.state.Tags.GetCurrentValues()\n\tif tag, ok := tcv.Tags.Get(key); ok {\n\t\treturn o.runtime.ToValue(tag)\n\t}\n\treturn nil\n}\n\n// Set a property value for the key. It returns true if succeed. String, Boolean\n// and Number types are implicitly converted to the Sobek's relative string\n// representation. An exception is raised in case a denied type is provided.\nfunc (o *tagsDynamicObject) Set(key string, val sobek.Value) bool {\n\to.state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\tif err := common.ApplyCustomUserTag(tagsAndMeta, key, val); err != nil {\n\t\t\tpanic(o.runtime.NewTypeError(err.Error()))\n\t\t}\n\t})\n\treturn true\n}\n\n// Has returns true if the property exists.\nfunc (o *tagsDynamicObject) Has(key string) bool {\n\tctv := o.state.Tags.GetCurrentValues()\n\tif _, ok := ctv.Tags.Get(key); ok {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Delete deletes the property for the key. It returns true on success (note,\n// that includes missing property).\nfunc (o *tagsDynamicObject) Delete(key string) bool {\n\to.state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\ttagsAndMeta.DeleteTag(key)\n\t})\n\treturn true\n}\n\n// Keys returns a slice with all existing property keys. The order is not\n// deterministic.\nfunc (o *tagsDynamicObject) Keys() []string {\n\tctv := o.state.Tags.GetCurrentValues()\n\n\ttagsMap := ctv.Tags.Map()\n\tkeys := make([]string, 0, len(tagsMap)+len(ctv.Metadata))\n\tfor k := range tagsMap {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys\n}\n\ntype metadataDynamicObject struct {\n\truntime *sobek.Runtime\n\tstate   *lib.State\n}\n\n// Get a property value for the key. May return nil if the property does not exist.\nfunc (o *metadataDynamicObject) Get(key string) sobek.Value {\n\ttcv := o.state.Tags.GetCurrentValues()\n\tif metadatum, ok := tcv.Metadata[key]; ok {\n\t\treturn o.runtime.ToValue(metadatum)\n\t}\n\treturn nil\n}\n\n// Set a property value for the key. It returns true if successful. String, Boolean\n// and Number types are implicitly converted to the Sobek's relative string\n// representation. An exception is raised in case a denied type is provided.\nfunc (o *metadataDynamicObject) Set(key string, val sobek.Value) bool {\n\to.state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\tif err := common.ApplyCustomUserMetadata(tagsAndMeta, key, val); err != nil {\n\t\t\tpanic(o.runtime.NewTypeError(err.Error()))\n\t\t}\n\t})\n\treturn true\n}\n\n// Has returns true if the property exists.\nfunc (o *metadataDynamicObject) Has(key string) bool {\n\tctv := o.state.Tags.GetCurrentValues()\n\tif _, ok := ctv.Metadata[key]; ok {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Delete deletes the property for the key. It returns true on success (note,\n// that includes missing property).\nfunc (o *metadataDynamicObject) Delete(key string) bool {\n\to.state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\ttagsAndMeta.DeleteMetadata(key)\n\t})\n\treturn true\n}\n\n// Keys returns a slice with all existing property keys. The order is not\n// deterministic.\nfunc (o *metadataDynamicObject) Keys() []string {\n\tctv := o.state.Tags.GetCurrentValues()\n\n\tkeys := make([]string, 0, len(ctv.Metadata))\n\tfor k := range ctv.Metadata {\n\t\tkeys = append(keys, k)\n\t}\n\treturn keys\n}\n"
  },
  {
    "path": "internal/js/modules/k6/execution/execution_test.go",
    "content": "package execution\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/executor\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n//nolint:gochecknoglobals\nvar tagsAndMetricsPropertyNames = map[string]string{\n\t\"tags\":             \"tag\",\n\t\"metrics.tags\":     \"tag\",\n\t\"metrics.metadata\": \"metadata\",\n}\n\nfunc setupTagsExecEnv(t *testing.T) *modulestest.Runtime {\n\ttestRuntime := modulestest.NewRuntime(t)\n\tm, ok := New().NewModuleInstance(testRuntime.VU).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, testRuntime.VU.Runtime().Set(\"exec\", m.Exports().Default))\n\n\treturn testRuntime\n}\n\nfunc TestVUTagsMetadatasGet(t *testing.T) {\n\tt.Parallel()\n\n\tfor prop, propType := range tagsAndMetricsPropertyNames {\n\t\tt.Run(prop, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttenv := setupTagsExecEnv(t)\n\t\t\ttenv.MoveToVUContext(&lib.State{\n\t\t\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"tag-vu\", \"mytag\")),\n\t\t\t})\n\t\t\ttenv.VU.StateField.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\t\ttagsAndMeta.SetMetadata(\"metadata-vu\", \"mymetadata\")\n\t\t\t})\n\t\t\ttag, err := tenv.VU.Runtime().RunString(fmt.Sprintf(`exec.vu.%s[\"%s-vu\"]`, prop, propType))\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"my\"+propType, tag.String())\n\n\t\t\t// not found\n\t\t\ttag, err = tenv.VU.Runtime().RunString(fmt.Sprintf(`exec.vu.%s[\"not-existing-%s\"]`, prop, propType))\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"undefined\", tag.String())\n\t\t})\n\t}\n}\n\nfunc TestVUTagsMetadatasJSONEncoding(t *testing.T) {\n\tt.Parallel()\n\n\tfor prop, propType := range tagsAndMetricsPropertyNames {\n\t\tt.Run(prop, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttenv := setupTagsExecEnv(t)\n\t\t\ttenv.MoveToVUContext(&lib.State{\n\t\t\t\tOptions: lib.Options{\n\t\t\t\t\tSystemTags: metrics.NewSystemTagSet(metrics.TagVU),\n\t\t\t\t},\n\t\t\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet()),\n\t\t\t})\n\t\t\ttenv.VU.State().Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\t\ttagsAndMeta.SetTag(\"tag-vu\", \"42\")\n\t\t\t\ttagsAndMeta.SetMetadata(\"metadata-vu\", \"42\")\n\t\t\t\ttagsAndMeta.SetTag(\"custom-tag\", \"mytag1\")\n\t\t\t\ttagsAndMeta.SetMetadata(\"custom-metadata\", \"mymetadata1\")\n\t\t\t})\n\n\t\t\tencoded, err := tenv.VU.Runtime().RunString(fmt.Sprintf(`JSON.stringify(exec.vu.%s)`, prop))\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.JSONEq(t, fmt.Sprintf(`{\"%[1]s-vu\":\"42\",\"custom-%[1]s\":\"my%[1]s1\"}`, propType), encoded.String())\n\t\t})\n\t}\n}\n\nfunc TestVUTagMetadatasSetSuccessAcceptedTypes(t *testing.T) {\n\tt.Parallel()\n\n\t// bool and numbers are implicitly converted into string\n\n\ttests := map[string]struct {\n\t\tv   any\n\t\texp string\n\t}{\n\t\t\"string\": {v: `\"tag1\"`, exp: \"tag1\"},\n\t\t\"bool\":   {v: true, exp: \"true\"},\n\t\t\"int\":    {v: 101, exp: \"101\"},\n\t\t\"float\":  {v: 3.14, exp: \"3.14\"},\n\t}\n\tfor prop := range tagsAndMetricsPropertyNames {\n\t\tt.Run(prop, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttenv := setupTagsExecEnv(t)\n\t\t\ttenv.MoveToVUContext(&lib.State{\n\t\t\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"vu\", \"42\")),\n\t\t\t})\n\n\t\t\tfor _, tc := range tests {\n\t\t\t\t_, err := tenv.VU.Runtime().RunString(fmt.Sprintf(`exec.vu.%s[\"mytag\"] = %v`, prop, tc.v))\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tval, err := tenv.VU.Runtime().RunString(fmt.Sprintf(`exec.vu.%s[\"mytag\"]`, prop))\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, tc.exp, val.String())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestVUTagsMetadatasSuccessOverwriteSystemTag(t *testing.T) {\n\tt.Parallel()\n\n\ttenv := setupTagsExecEnv(t)\n\ttenv.MoveToVUContext(&lib.State{\n\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"vu\", \"42\")),\n\t})\n\n\t_, err := tenv.VU.Runtime().RunString(`exec.vu.tags[\"vu\"] = \"vu101\"`)\n\trequire.NoError(t, err)\n\tval, err := tenv.VU.Runtime().RunString(`exec.vu.tags[\"vu\"]`)\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"vu101\", val.String())\n}\n\nfunc TestVUTagsMetadataErrorOutOnInvalidValues(t *testing.T) {\n\tt.Parallel()\n\n\tcases := []string{\n\t\t\"null\",\n\t\t\"undefined\",\n\t\t\"[]\",\n\t\t\"{}\",\n\t\t`[1, 3, 5]`,\n\t\t`{f1: \"value1\", f2: 4}`,\n\t\t`{\"foo\": \"bar\"}`,\n\t}\n\tfor prop, propType := range tagsAndMetricsPropertyNames {\n\t\tt.Run(prop, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor _, val := range cases {\n\t\t\t\tlogHook := testutils.NewLogHook(logrus.WarnLevel)\n\t\t\t\ttestLog := logrus.New()\n\t\t\t\ttestLog.AddHook(logHook)\n\t\t\t\ttestLog.SetOutput(io.Discard)\n\t\t\t\ttenv := setupTagsExecEnv(t)\n\t\t\t\ttenv.MoveToVUContext(&lib.State{\n\t\t\t\t\tOptions: lib.Options{\n\t\t\t\t\t\tSystemTags: metrics.NewSystemTagSet(metrics.TagVU),\n\t\t\t\t\t},\n\t\t\t\t\tTags:   lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"vu\", \"42\")),\n\t\t\t\t\tLogger: testLog,\n\t\t\t\t})\n\t\t\t\t_, err := tenv.VU.Runtime().RunString(fmt.Sprintf(`exec.vu.%s[\"custom\"] = %s`, prop, val))\n\t\t\t\tassert.ErrorContains(t, err, \"TypeError: invalid value for metric \"+propType+\" 'custom'\")\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestAbortTest(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\n\tvar (\n\t\trt    = sobek.New()\n\t\tstate = &lib.State{}\n\t\tctx   = context.Background()\n\t)\n\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tInitEnvField: &common.InitEnvironment{},\n\t\t\tCtxField:     ctx,\n\t\t\tStateField:   state,\n\t\t},\n\t).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"exec\", m.Exports().Default))\n\n\tprove := func(t *testing.T, script, reason string) {\n\t\t_, err := rt.RunString(script)\n\t\trequire.NotNil(t, err)\n\t\tvar x *sobek.InterruptedError\n\t\tassert.ErrorAs(t, err, &x)\n\t\tv, ok := x.Value().(*errext.InterruptError)\n\t\trequire.True(t, ok)\n\t\trequire.Equal(t, reason, v.Reason)\n\t}\n\n\tt.Run(\"default reason\", func(t *testing.T) { //nolint:paralleltest\n\t\tprove(t, \"exec.test.abort()\", errext.AbortTest)\n\t})\n\tt.Run(\"custom reason\", func(t *testing.T) { //nolint:paralleltest\n\t\tprove(t, `exec.test.abort(\"mayday\")`, fmt.Sprintf(\"%s: mayday\", errext.AbortTest))\n\t})\n}\n\nfunc TestFailTest(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"default reason\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Set up the logger to write to the buffer so we can assert on it later\n\t\tvar logsBuffer bytes.Buffer\n\t\ttestLogger := logrus.New()\n\t\ttestLogger.AddHook(testutils.NewLogHook(logrus.DebugLevel))\n\t\ttestLogger.SetOutput(&logsBuffer)\n\n\t\t// Prepare the runtime and state for the module, and to be able to\n\t\t// assert the test state at the very end.\n\t\trt := sobek.New()\n\t\tstate := &lib.State{TestStatus: lib.NewTestStatus(), Logger: testLogger}\n\n\t\t// Instantiate the test module instance\n\t\tmodule, ok := New().NewModuleInstance(\n\t\t\t&modulestest.VU{\n\t\t\t\tRuntimeField: rt,\n\t\t\t\tCtxField:     context.Background(),\n\t\t\t\tStateField:   state,\n\t\t\t},\n\t\t).(*ModuleInstance)\n\t\trequire.True(t, ok)\n\t\trequire.NoError(t, rt.Set(\"exec\", module.Exports().Default))\n\n\t\t_, err := rt.RunString(\"exec.test.fail()\")\n\t\trequire.NoError(t, err)\n\n\t\tassert.True(t, state.TestStatus.Failed())\n\t})\n\n\tt.Run(\"custom reason\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Set up the logger to write to the buffer so we can assert on it later\n\t\tvar logsBuffer bytes.Buffer\n\t\ttestLogger := logrus.New()\n\t\ttestLogger.AddHook(testutils.NewLogHook(logrus.DebugLevel))\n\t\ttestLogger.SetOutput(&logsBuffer)\n\n\t\t// Prepare the runtime and state for the module, and to be able to\n\t\t// assert the test state at the very end.\n\t\trt := sobek.New()\n\t\tstate := &lib.State{TestStatus: lib.NewTestStatus(), Logger: testLogger}\n\n\t\t// Instantiate the test module instance\n\t\tmodule, ok := New().NewModuleInstance(\n\t\t\t&modulestest.VU{\n\t\t\t\tRuntimeField: rt,\n\t\t\t\tCtxField:     context.Background(),\n\t\t\t\tStateField:   state,\n\t\t\t},\n\t\t).(*ModuleInstance)\n\t\trequire.True(t, ok)\n\t\trequire.NoError(t, rt.Set(\"exec\", module.Exports().Default))\n\n\t\t_, err := rt.RunString(`exec.test.fail(\"a custom reason\")`)\n\t\trequire.NoError(t, err)\n\n\t\tassert.True(t, state.TestStatus.Failed())\n\t\tassert.Contains(t, logsBuffer.String(), \"a custom reason\")\n\t})\n}\n\nfunc TestOptionsTestFull(t *testing.T) {\n\tt.Parallel()\n\n\texpected := `{\"paused\":true,\"scenarios\":{\"const-vus\":{\"executor\":\"constant-vus\",\"options\":{\"browser\":{\"someOption\":true}},\"startTime\":\"10s\",\"gracefulStop\":\"30s\",\"env\":{\"FOO\":\"bar\"},\"exec\":\"default\",\"tags\":{\"tagkey\":\"tagvalue\"},\"vus\":50,\"duration\":\"10m0s\"}},\"executionSegment\":\"0:1/4\",\"executionSegmentSequence\":\"0,1/4,1/2,1\",\"noSetup\":true,\"setupTimeout\":\"1m0s\",\"noTeardown\":true,\"teardownTimeout\":\"5m0s\",\"rps\":100,\"dns\":{\"ttl\":\"1m\",\"select\":\"roundRobin\",\"policy\":\"any\"},\"maxRedirects\":3,\"userAgent\":\"k6-user-agent\",\"batch\":15,\"batchPerHost\":5,\"httpDebug\":\"full\",\"insecureSkipTLSVerify\":true,\"tlsCipherSuites\":[\"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\"],\"tlsVersion\":{\"min\":\"tls1.2\",\"max\":\"tls1.3\"},\"tlsAuth\":[{\"domains\":[\"example.com\"],\"cert\":\"mycert.pem\",\"key\":\"mycert-key.pem\",\"password\":\"mypwd\"}],\"throw\":true,\"thresholds\":{\"http_req_duration\":[{\"threshold\":\"rate>0.01\",\"abortOnFail\":true,\"delayAbortEval\":\"10s\"}]},\"blacklistIPs\":[\"192.0.2.0/24\"],\"blockHostnames\":[\"test.k6.io\",\"*.example.com\"],\"hosts\":{\"test.k6.io\":\"1.2.3.4:8443\"},\"noConnectionReuse\":true,\"noVUConnectionReuse\":true,\"minIterationDuration\":\"10s\",\"ext\":{\"ext-one\":{\"rawkey\":\"rawvalue\"}},\"summaryTrendStats\":[\"avg\",\"min\",\"max\"],\"summaryTimeUnit\":\"ms\",\"systemTags\":[\"iter\",\"vu\"],\"tags\":null,\"metricSamplesBufferSize\":8,\"noCookiesReset\":true,\"discardResponseBodies\":true,\"consoleOutput\":\"loadtest.log\",\"tags\":{\"runtag-key\":\"runtag-value\"},\"localIPs\":\"192.168.20.12-192.168.20.15,192.168.10.0/27\"}`\n\n\tvar (\n\t\trt    = sobek.New()\n\t\tstate = &lib.State{\n\t\t\tOptions: lib.Options{\n\t\t\t\tPaused: null.BoolFrom(true),\n\t\t\t\tScenarios: map[string]lib.ExecutorConfig{\n\t\t\t\t\t\"const-vus\": executor.ConstantVUsConfig{\n\t\t\t\t\t\tBaseConfig: executor.BaseConfig{\n\t\t\t\t\t\t\tName:         \"const-vus\",\n\t\t\t\t\t\t\tType:         \"constant-vus\",\n\t\t\t\t\t\t\tStartTime:    types.NullDurationFrom(10 * time.Second),\n\t\t\t\t\t\t\tGracefulStop: types.NullDurationFrom(30 * time.Second),\n\t\t\t\t\t\t\tEnv: map[string]string{\n\t\t\t\t\t\t\t\t\"FOO\": \"bar\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tExec: null.StringFrom(\"default\"),\n\t\t\t\t\t\t\tTags: map[string]string{\n\t\t\t\t\t\t\t\t\"tagkey\": \"tagvalue\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tOptions: &lib.ScenarioOptions{\n\t\t\t\t\t\t\t\tBrowser: map[string]any{\n\t\t\t\t\t\t\t\t\t\"someOption\": true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tVUs:      null.IntFrom(50),\n\t\t\t\t\t\tDuration: types.NullDurationFrom(10 * time.Minute),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tExecutionSegment: func() *lib.ExecutionSegment {\n\t\t\t\t\tseg, err := lib.NewExecutionSegmentFromString(\"0:1/4\")\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn seg\n\t\t\t\t}(),\n\t\t\t\tExecutionSegmentSequence: func() *lib.ExecutionSegmentSequence {\n\t\t\t\t\tseq, err := lib.NewExecutionSegmentSequenceFromString(\"0,1/4,1/2,1\")\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn &seq\n\t\t\t\t}(),\n\t\t\t\tNoSetup:               null.BoolFrom(true),\n\t\t\t\tNoTeardown:            null.BoolFrom(true),\n\t\t\t\tNoConnectionReuse:     null.BoolFrom(true),\n\t\t\t\tNoVUConnectionReuse:   null.BoolFrom(true),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(true),\n\t\t\t\tThrow:                 null.BoolFrom(true),\n\t\t\t\tNoCookiesReset:        null.BoolFrom(true),\n\t\t\t\tDiscardResponseBodies: null.BoolFrom(true),\n\t\t\t\tRPS:                   null.IntFrom(100),\n\t\t\t\tMaxRedirects:          null.IntFrom(3),\n\t\t\t\tUserAgent:             null.StringFrom(\"k6-user-agent\"),\n\t\t\t\tBatch:                 null.IntFrom(15),\n\t\t\t\tBatchPerHost:          null.IntFrom(5),\n\t\t\t\tSetupTimeout:          types.NullDurationFrom(1 * time.Minute),\n\t\t\t\tTeardownTimeout:       types.NullDurationFrom(5 * time.Minute),\n\t\t\t\tMinIterationDuration:  types.NullDurationFrom(10 * time.Second),\n\t\t\t\tHTTPDebug:             null.StringFrom(\"full\"),\n\t\t\t\tDNS: types.DNSConfig{\n\t\t\t\t\tTTL:    null.StringFrom(\"1m\"),\n\t\t\t\t\tSelect: types.NullDNSSelect{DNSSelect: types.DNSroundRobin, Valid: true},\n\t\t\t\t\tPolicy: types.NullDNSPolicy{DNSPolicy: types.DNSany, Valid: true},\n\t\t\t\t\tValid:  true,\n\t\t\t\t},\n\t\t\t\tTLSVersion: &lib.TLSVersions{\n\t\t\t\t\tMin: tls.VersionTLS12,\n\t\t\t\t\tMax: tls.VersionTLS13,\n\t\t\t\t},\n\t\t\t\tTLSAuth: []*lib.TLSAuth{\n\t\t\t\t\t{\n\t\t\t\t\t\tTLSAuthFields: lib.TLSAuthFields{\n\t\t\t\t\t\t\tCert:     \"mycert.pem\",\n\t\t\t\t\t\t\tKey:      \"mycert-key.pem\",\n\t\t\t\t\t\t\tPassword: null.StringFrom(\"mypwd\"),\n\t\t\t\t\t\t\tDomains:  []string{\"example.com\"},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tTLSCipherSuites: &lib.TLSCipherSuites{\n\t\t\t\t\ttls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\n\t\t\t\t},\n\t\t\t\tBlacklistIPs: []*lib.IPNet{\n\t\t\t\t\t{\n\t\t\t\t\t\tIPNet: func() net.IPNet {\n\t\t\t\t\t\t\t_, ipv4net, err := net.ParseCIDR(\"192.0.2.1/24\")\n\t\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\t\treturn *ipv4net\n\t\t\t\t\t\t}(),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tThresholds: map[string]metrics.Thresholds{\n\t\t\t\t\t\"http_req_duration\": {\n\t\t\t\t\t\tThresholds: []*metrics.Threshold{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tSource:           \"rate>0.01\",\n\t\t\t\t\t\t\t\tLastFailed:       true,\n\t\t\t\t\t\t\t\tAbortOnFail:      true,\n\t\t\t\t\t\t\t\tAbortGracePeriod: types.NullDurationFrom(10 * time.Second),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tBlockedHostnames: func() types.NullHostnameTrie {\n\t\t\t\t\tbh, err := types.NewNullHostnameTrie([]string{\"test.k6.io\", \"*.example.com\"})\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn bh\n\t\t\t\t}(),\n\t\t\t\tHosts: func() types.NullHosts {\n\t\t\t\t\ths, err := types.NewNullHosts(map[string]types.Host{\n\t\t\t\t\t\t\"test.k6.io\": {\n\t\t\t\t\t\t\tIP:   []byte{0x01, 0x02, 0x03, 0x04},\n\t\t\t\t\t\t\tPort: 8443,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn hs\n\t\t\t\t}(),\n\t\t\t\tExternal: map[string]json.RawMessage{\n\t\t\t\t\t\"ext-one\": json.RawMessage(`{\"rawkey\":\"rawvalue\"}`),\n\t\t\t\t},\n\t\t\t\tSummaryTrendStats: []string{\"avg\", \"min\", \"max\"},\n\t\t\t\tSummaryTimeUnit:   null.StringFrom(\"ms\"),\n\t\t\t\tSystemTags: func() *metrics.SystemTagSet {\n\t\t\t\t\tsysm := metrics.SystemTagSet(metrics.TagIter | metrics.TagVU)\n\t\t\t\t\treturn &sysm\n\t\t\t\t}(),\n\t\t\t\tRunTags:                 map[string]string{\"runtag-key\": \"runtag-value\"},\n\t\t\t\tMetricSamplesBufferSize: null.IntFrom(8),\n\t\t\t\tConsoleOutput:           null.StringFrom(\"loadtest.log\"),\n\t\t\t\tLocalIPs: func() types.NullIPPool {\n\t\t\t\t\tnpool := types.NullIPPool{}\n\t\t\t\t\terr := npool.UnmarshalText([]byte(\"192.168.20.12-192.168.20.15,192.168.10.0/27\"))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\treturn npool\n\t\t\t\t}(),\n\n\t\t\t\t// The following fields are not expected to be\n\t\t\t\t// in the final test.options object\n\t\t\t\tVUs:        null.IntFrom(50),\n\t\t\t\tIterations: null.IntFrom(100),\n\t\t\t\tDuration:   types.NullDurationFrom(10 * time.Second),\n\t\t\t\tStages: []lib.Stage{\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(2 * time.Second),\n\t\t\t\t\t\tTarget:   null.IntFrom(2),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tctx = context.Background()\n\t)\n\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tCtxField:     ctx,\n\t\t\tStateField:   state,\n\t\t},\n\t).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"exec\", m.Exports().Default))\n\n\topts, err := rt.RunString(`JSON.stringify(exec.test.options)`)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, opts)\n\tassert.JSONEq(t, expected, opts.String())\n}\n\nfunc TestOptionsTestSetPropertyDenied(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tCtxField:     context.Background(),\n\t\t\tStateField: &lib.State{\n\t\t\t\tOptions: lib.Options{\n\t\t\t\t\tPaused: null.BoolFrom(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"exec\", m.Exports().Default))\n\n\t_, err := rt.RunString(`exec.test.options.paused = false`)\n\trequire.NoError(t, err)\n\tpaused, err := rt.RunString(`exec.test.options.paused`)\n\trequire.NoError(t, err)\n\tassert.Equal(t, true, rt.ToValue(paused).ToBoolean())\n}\n\nfunc TestScenarioNoAvailableInInitContext(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tCtxField:     context.Background(),\n\t\t\tStateField: &lib.State{\n\t\t\t\tOptions: lib.Options{\n\t\t\t\t\tPaused: null.BoolFrom(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"exec\", m.Exports().Default))\n\n\tscenarioExportedProps := []string{\"name\", \"executor\", \"startTime\", \"progress\", \"iterationInInstance\", \"iterationInTest\"}\n\n\tfor _, code := range scenarioExportedProps {\n\t\tprop := fmt.Sprintf(\"exec.scenario.%s\", code)\n\t\t_, err := rt.RunString(prop)\n\t\trequire.Error(t, err)\n\t\trequire.ErrorContains(t, err, \"getting scenario information outside of the VU context is not supported\")\n\t}\n}\n\nfunc TestOptionsNoAvailableInInitContext(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tCtxField:     context.Background(),\n\t\t},\n\t).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"exec\", m.Exports().Default))\n\n\t_, err := rt.RunString(\"exec.test.options\")\n\trequire.ErrorContains(t, err, \"getting test options in the init context is not supported\")\n}\n\nfunc TestVUDefaultDetails(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\tm, ok := New().NewModuleInstance(\n\t\t&modulestest.VU{\n\t\t\tRuntimeField: rt,\n\t\t\tCtxField:     context.Background(),\n\t\t\tStateField: &lib.State{\n\t\t\t\tOptions: lib.Options{\n\t\t\t\t\tPaused: null.BoolFrom(true),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"exec\", m.Exports().Default))\n\n\tprops := []string{\"idInInstance\", \"idInTest\", \"iterationInInstance\", \"iterationInScenario\"}\n\n\tfor _, code := range props {\n\t\tprop := fmt.Sprintf(\"exec.vu.%s\", code)\n\t\tres, err := rt.RunString(prop)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"0\", res.String())\n\t}\n}\n\nfunc TestTagsDynamicObjectGet(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\ttdo := tagsDynamicObject{\n\t\truntime: rt,\n\t\tstate: &lib.State{\n\t\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"vu\", \"42\")),\n\t\t},\n\t}\n\tval := tdo.Get(\"vu\")\n\trequire.NotNil(t, val)\n\tassert.Equal(t, int64(42), val.ToInteger())\n}\n\nfunc TestTagsDynamicObjectSet(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\ttdo := tagsDynamicObject{\n\t\truntime: rt,\n\t\tstate: &lib.State{\n\t\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"vu\", \"42\")),\n\t\t},\n\t}\n\trequire.True(t, tdo.Set(\"k1\", rt.ToValue(\"v1\")))\n\n\tval := tdo.Get(\"k1\")\n\trequire.NotNil(t, val)\n\tassert.Equal(t, \"v1\", val.String())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/README.md",
    "content": "# Experimental Modules\n\nThis folder are here as a documentation and reference point for k6's experimental modules. \n\nAlthough [accessible in k6 scripts](../../../initcontext.go) under the `k6/experimental` import path, those modules implementations live in their own repository and are not part of the k6 stable release yet:\n* [`k6/experimental/k6-redis`](https://github.com/grafana/xk6-redis)\n* [`k6/experimental/k6-websockets`](https://github.com/grafana/xk6-websockets)\n* [`k6/experimental/k6-timers`](https://github.com/grafana/xk6-timers)\n* [`k6/experimental/k6-browser`](https://github.com/grafana/xk6-browser)\n\nWhile we intend to keep these modules as stable as possible, we may need to add features or introduce breaking changes. This could happen at any time until we release the module as stable. **use them at your own risk**.\n\n## Upgrading\n\nExperimental modules are based on xk6-extensions, and they introduce a cycle dependency between k6 and the extension. When upgrading an extension's version, it's required to run the following steps:\n\n1. Get the feature branch ready to be merged. Note: from the next step rebasing of the feature branch should be denied; otherwise, the commit will be lost and the relative dependencies will be broken.\n2. Make a commit in the feature branch that removes the extension package (and any other problematic experimental modules).\n3. Make a PR in the extension's repository and merge it in its main branch that updates the k6 dependency to the commit generated at the previous point.\n4. Tag the newly merged commit creating a new version.\n5. Make another commit in the feature branch on k6 repository that re-adds this latest version of the extension.\n6. Merge the whole feature branch in k6 master with a `Merge` commit (`Create a merge commit` button on GitHub). It will guarantee that the commit used by the extension is preserved.\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/csv/module.go",
    "content": "// Package csv provides a CSV parser for k6.\npackage csv\n\nimport (\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync/atomic\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/data\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/js/promises\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/experimental/fs\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create instances of our\n\t// module for each VU.\n\tRootModule struct {\n\t\tdataModuleInstance *data.Data\n\t}\n\n\t// ModuleInstance represents an instance of the fs module for a single VU.\n\tModuleInstance struct {\n\t\tvu modules.VU\n\n\t\t*RootModule\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// New returns a pointer to a new [RootModule] instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface and returns a new\n// instance of our module for the given VU.\nfunc (rm *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\tif rm.dataModuleInstance == nil {\n\t\tvar ok bool\n\t\trm.dataModuleInstance, ok = data.New().NewModuleInstance(vu).(*data.Data)\n\t\tif !ok {\n\t\t\tcommon.Throw(vu.Runtime(), errors.New(\"failed to create data module instance\"))\n\t\t}\n\t}\n\n\treturn &ModuleInstance{vu: vu, RootModule: rm}\n}\n\n// Exports implements the modules.Module interface and returns the exports of\n// our module.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"parse\":  mi.Parse,\n\t\t\t\"Parser\": mi.NewParser,\n\t\t},\n\t}\n}\n\n// Parser is a CSV parser.\ntype Parser struct {\n\t// currentLine holds the current line number being read by the parser.\n\tcurrentLine atomic.Int64\n\n\t// reader is the CSV reader that enables to read records from the provided\n\t// input file.\n\treader *Reader\n\n\t// options holds the parser's as provided by the user.\n\toptions options\n\n\t// vu is the VU instance that owns this module instance.\n\tvu modules.VU\n}\n\n// parseSharedArrayNamePrefix is the prefix used for the shared array names created by the Parse function.\nconst parseSharedArrayNamePrefix = \"csv.parse.\"\n\n// Parse parses the provided CSV file, and returns a promise that resolves to a shared array\n// containing the parsed data.\nfunc (mi *ModuleInstance) Parse(file sobek.Value, options sobek.Value) (*sobek.Promise, error) {\n\trt := mi.vu.Runtime()\n\n\t// 1. Make sure the Sobek object is a fs.File (Sobek operation)\n\tvar fileObj fs.File\n\tif err := mi.vu.Runtime().ExportTo(file, &fileObj); err != nil {\n\t\treturn nil, fmt.Errorf(\"first argument expected to be a fs.File instance, got %T instead\", file)\n\t}\n\n\tparserOptions := newDefaultParserOptions()\n\tif options != nil {\n\t\tvar err error\n\t\tparserOptions, err = newParserOptionsFrom(options.ToObject(rt))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to interpret the provided Parser options; reason: %w\", err)\n\t\t}\n\t}\n\n\tr, err := NewReaderFrom(fileObj.ReadSeekStater, parserOptions)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create a new parser; reason: %w\", err)\n\t}\n\n\tunderlyingSharedArrayName, err := buildSharedArrayName(fileObj, parserOptions)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to derive shared array name; reason: %w\", err)\n\t}\n\n\tcallback := mi.vu.RegisterCallback()\n\tpromise, resolve, reject := rt.NewPromise()\n\n\tgo func() {\n\t\t// Because we rely on the data module to create the shared array, we need to\n\t\t// make sure that the data module is initialized before we can proceed, and that we don't instantiate\n\t\t// it multiple times.\n\t\t//\n\t\t// As such we hold a single instance of it in the RootModule, and we use it to create the shared array.\n\t\tfn, err := mi.dataModuleInstance.NewSharedArrayFrom(mi.vu.Runtime(), underlyingSharedArrayName, r)\n\t\tif err != nil {\n\t\t\tcallback(func() error {\n\t\t\t\treturn reject(rt.NewGoError(err))\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tcallback(func() error {\n\t\t\treturn resolve(fn())\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// NewParser creates a new CSV parser instance.\nfunc (mi *ModuleInstance) NewParser(call sobek.ConstructorCall) *sobek.Object {\n\trt := mi.vu.Runtime()\n\n\tif mi.vu.State() != nil {\n\t\tcommon.Throw(rt, errors.New(\"csv Parser constructor must be called in the init context\"))\n\t}\n\n\tif len(call.Arguments) < 1 || sobek.IsUndefined(call.Argument(0)) {\n\t\tcommon.Throw(rt, fmt.Errorf(\"csv Parser constructor takes at least one non-nil source argument\"))\n\t}\n\n\tfileArg := call.Argument(0)\n\tif common.IsNullish(fileArg) {\n\t\tcommon.Throw(rt, fmt.Errorf(\"csv Parser constructor takes at least one non-nil source argument\"))\n\t}\n\n\t// 1. Make sure the Sobek object is a fs.File (Sobek operation)\n\tvar file fs.File\n\tif err := mi.vu.Runtime().ExportTo(fileArg, &file); err != nil {\n\t\tcommon.Throw(\n\t\t\tmi.vu.Runtime(),\n\t\t\tfmt.Errorf(\"first argument expected to be a fs.File instance, got %T instead\", call.Argument(0)),\n\t\t)\n\t}\n\n\toptions := newDefaultParserOptions()\n\tif len(call.Arguments) == 2 && !sobek.IsUndefined(call.Argument(1)) {\n\t\tvar err error\n\t\toptions, err = newParserOptionsFrom(call.Argument(1).ToObject(rt))\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, fmt.Errorf(\"encountered an error while interpreting Parser options; reason: %w\", err))\n\t\t}\n\t}\n\n\t// Instantiate and configure a csv reader using the provided file and options\n\tr, err := NewReaderFrom(file.ReadSeekStater, options)\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"failed to create a new parser; reason: %w\", err))\n\t}\n\n\t// Create a new Parser instance\n\tparser := Parser{\n\t\treader:  r,\n\t\toptions: options,\n\t\tvu:      mi.vu,\n\t}\n\n\treturn rt.ToValue(&parser).ToObject(rt)\n}\n\n// Next returns the next row in the CSV file.\nfunc (p *Parser) Next() *sobek.Promise {\n\tpromise, resolve, reject := promises.New(p.vu)\n\n\tgo func() {\n\t\tvar record any\n\t\tvar done bool\n\t\tvar err error\n\n\t\trecord, err = p.reader.Read()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tresolve(parseResult{Done: true, Value: []string{}})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\treject(err)\n\t\t\treturn\n\t\t}\n\n\t\tp.currentLine.Add(1)\n\n\t\tresolve(parseResult{Done: done, Value: record})\n\t}()\n\n\treturn promise\n}\n\nfunc buildSharedArrayName(file fs.File, opts options) (string, error) {\n\tdelimiter := string(opts.Delimiter)\n\tif delimiter == \"\" {\n\t\tdelimiter = \",\"\n\t}\n\n\t// Use anonymous structs with explicit field ordering instead of maps to ensure\n\t// deterministic JSON marshaling. While encoding/json currently sorts map keys\n\t// alphabetically, this is an implementation detail not guaranteed by the Go\n\t// specification. Structs provide guaranteed field ordering across all Go versions.\n\tpayload := struct {\n\t\tPath    string `json:\"path\"`\n\t\tOptions struct {\n\t\t\tAsObjects     null.Bool `json:\"asObjects\"`\n\t\t\tDelimiter     string    `json:\"delimiter\"`\n\t\t\tFromLine      null.Int  `json:\"fromLine\"`\n\t\t\tSkipFirstLine bool      `json:\"skipFirstLine\"`\n\t\t\tToLine        null.Int  `json:\"toLine\"`\n\t\t} `json:\"options\"`\n\t}{\n\t\tPath: file.Path,\n\t\tOptions: struct {\n\t\t\tAsObjects     null.Bool `json:\"asObjects\"`\n\t\t\tDelimiter     string    `json:\"delimiter\"`\n\t\t\tFromLine      null.Int  `json:\"fromLine\"`\n\t\t\tSkipFirstLine bool      `json:\"skipFirstLine\"`\n\t\t\tToLine        null.Int  `json:\"toLine\"`\n\t\t}{\n\t\t\tAsObjects:     opts.AsObjects,\n\t\t\tDelimiter:     delimiter,\n\t\t\tFromLine:      opts.FromLine,\n\t\t\tSkipFirstLine: opts.SkipFirstLine,\n\t\t\tToLine:        opts.ToLine,\n\t\t},\n\t}\n\n\traw, err := json.Marshal(payload)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tsum := sha256.Sum256(raw)\n\treturn parseSharedArrayNamePrefix + hex.EncodeToString(sum[:]), nil\n}\n\n// parseResult holds the result of a CSV parser's parsing operation such\n// as when calling the [Next].\ntype parseResult struct {\n\t// Done indicates whether the parser has finished reading the file.\n\tDone bool `js:\"done\"`\n\n\t// Value holds the line's records value.\n\tValue any `js:\"value\"`\n}\n\n// options holds options used to configure CSV parsing when utilizing the module.\n//\n// The options can be used to either configure the CSV parser, or the parse function.\n// They offer to customize the behavior of the parser, such as the delimiter, whether\n// to skip the first line, or  to start reading from a specific line, and stop reading\n// at a specific line.\ntype options struct {\n\t// Delimiter is the character that separates the fields in the CSV.\n\tDelimiter rune `js:\"delimiter\"`\n\n\t// SkipFirstLine indicates whether the first line should be skipped.\n\tSkipFirstLine bool `js:\"skipFirstLine\"`\n\n\t// FromLine indicates the line from which to start reading the CSV file.\n\tFromLine null.Int `js:\"fromLine\"`\n\n\t// ToLine indicates the line at which to stop reading the CSV file (inclusive).\n\tToLine null.Int `js:\"toLine\"`\n\n\t// AsObjects indicates that the CSV rows should be returned as objects, where\n\t// the keys are the header column names, and values are the corresponding\n\t// row values.\n\t//\n\t// When this option is enabled, the first line of the CSV file is treated as the header.\n\t//\n\t// If the option is set and no header line is present, this should be considered an error\n\t// case.\n\t//\n\t// This option is incompatible with the [SkipFirstLine] option, and if both are set, an error\n\t// should be returned. Same thing applies if the [FromLine] option is set to a value greater\n\t// than 0.\n\tAsObjects null.Bool `js:\"asObjects\"`\n}\n\n// newDefaultParserOptions creates a new options instance with default values.\nfunc newDefaultParserOptions() options {\n\treturn options{\n\t\tDelimiter:     ',',\n\t\tSkipFirstLine: false,\n\t\tAsObjects:     null.BoolFrom(false),\n\t}\n}\n\n// newParserOptions creates a new options instance from the given Sobek object.\nfunc newParserOptionsFrom(obj *sobek.Object) (options, error) {\n\toptions := newDefaultParserOptions()\n\n\tif obj == nil {\n\t\treturn options, nil\n\t}\n\n\tif v := obj.Get(\"delimiter\"); v != nil {\n\t\tdelimiter := v.String()\n\n\t\t// A delimiter is gonna be treated as a rune in the Go code, so we need to make sure it's a single character.\n\t\tif len(delimiter) > 1 {\n\t\t\treturn options, fmt.Errorf(\"delimiter must be a single character\")\n\t\t}\n\n\t\toptions.Delimiter = rune(delimiter[0])\n\t}\n\n\tif v := obj.Get(\"skipFirstLine\"); v != nil {\n\t\toptions.SkipFirstLine = v.ToBoolean()\n\t}\n\n\tif v := obj.Get(\"fromLine\"); v != nil {\n\t\toptions.FromLine = null.IntFrom(v.ToInteger())\n\t}\n\n\tif v := obj.Get(\"toLine\"); v != nil {\n\t\toptions.ToLine = null.IntFrom(v.ToInteger())\n\t}\n\n\tif v := obj.Get(\"asObjects\"); v != nil {\n\t\toptions.AsObjects = null.BoolFrom(v.ToBoolean())\n\t}\n\n\tif options.FromLine.Valid && options.ToLine.Valid && options.FromLine.Int64 >= options.ToLine.Int64 {\n\t\treturn options, fmt.Errorf(\"fromLine must be less than or equal to toLine\")\n\t}\n\n\treturn options, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/csv/module_test.go",
    "content": "package csv\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/metrics\"\n\n\t\"go.k6.io/k6/lib\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/experimental/fs\"\n\t\"go.k6.io/k6/lib/fsext\"\n\n\t\"go.k6.io/k6/internal/js/compiler\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\n// testFilePath holds the path to the test CSV file.\nconst testFilePath = fsext.FilePathSeparator + \"testdata.csv\"\n\n// csvTestData is a CSV file that contains test data about\n// various composers.\nconst csvTestData = `lastname,firstname,composer,born,died,dates\nScarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757\nDorman,Avner,Avner Dorman,1975,,1975–\nStill,William Grant,William Grant Still,1895,1978,1895–1978\nBacewicz,Grażyna,Grażyna Bacewicz,1909,1969,1909–1969\nProkofiev,Sergei,Sergei Prokofiev,1891,1953,1891–1953\nLash,Han,Han Lash,1981,,1981–\nFranck,César,César Franck,1822,1890,1822–1890\nMessiaen,Olivier,Olivier Messiaen,1908,1992,1908–1992\nBellini,Vincenzo,Vincenzo Bellini,1801,1835,1801–1835\nLigeti,György,György Ligeti,1923,2006,1923–2006\n`\n\nfunc TestParserConstructor(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"constructing a parser without options should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\t  const file = await fs.open(%q);\n\t\t\t  const parser = new csv.Parser(file);\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"constructing a parser with valid options should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\t  const file = await fs.open(%q);\n\t\t\t  const parser = new csv.Parser(file, { delimiter: ';', skipFirstLine: true, fromLine: 0, toLine: 10 });\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"constructing a parser with both asObjects and skipFirstLine options should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\t  const file = await fs.open(%q);\n\t\t\t  const parser = new csv.Parser(file, { delimiter: ';', skipFirstLine: true, asObjects: true });\n\t\t`, testFilePath)))\n\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"constructing a parser with both the asObjects option and fromLine option greater than 0 should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\t  const file = await fs.open(%q);\n\t\t\t  const parser = new csv.Parser(file, { delimiter: ';', fromLine: 1, asObjects: true });\n\t\t`, testFilePath)))\n\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"constructing a parser without providing a file instance should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(`\n\t\t\t// Regardless of whether a file is passed, the parser should not be constructed in the VU context.\n\t\t\tconst parser = new csv.Parser(null);\n\t\t`))\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"csv Parser constructor takes at least one non-nil source argument\")\n\t})\n\n\tt.Run(\"constructing a parser in VU context should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\t\tr.MoveToVUContext(&lib.State{\n\t\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet()),\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(`\n\t\t\t// Note that we pass an empty object here as opening a real file here would lead to the fs.open call\n\t\t\t// itself to fail (as we're not in the init context).\n\t\t\tconst parser = new csv.Parser({}, { delimiter: ';', skipFirstLine: true, fromLine: 0, toLine: 10 });\n\t\t`))\n\n\t\trequire.Error(t, err)\n\t\trequire.Contains(t, err.Error(), \"csv Parser constructor must be called in the init context\")\n\t})\n}\n\nfunc TestParserNext(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"next with default options should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file);\n\n\t\t\t// Parse the header\n\t\t\tlet { done, value } = await parser.next();\n\t\t\tif (done) {\n\t\t\t\tthrow new Error(\"Expected to read a record, but got done=true\");\n\t\t\t}\n\t\t\tif (value.length !== 6) {\n\t\t\t\tthrow new Error(\"Expected 6 fields, but got \" + value.length);\n\t\t\t}\n\t\t\tif (JSON.stringify(value) !== JSON.stringify([\"lastname\", \"firstname\", \"composer\", \"born\", \"died\", \"dates\"])) {\n\t\t\t\tthrow new Error(\"Expected header to be 'lastname,firstname,composer,born,died,dates', but got \" + value);\n\t\t\t}\n\n\t\t\t// Parse the first record\n\t\t\t({ done, value } = await parser.next());\n\t\t\tif (done) {\n\t\t\t\tthrow new Error(\"Expected to read a record, but got done=true\");\n\t\t\t}\n\t\t\tif (value.length !== 6) {\n\t\t\t\tthrow new Error(\"Expected 6 fields, but got \" + value.length);\n\t\t\t}\n\t\t\tif (JSON.stringify(value) !== JSON.stringify([\"Scarlatti\", \"Domenico\", \"Domenico Scarlatti\", \"1685\", \"1757\", \"1685–1757\"])) {\n\t\t\t\tthrow new Error(\"Expected record to be 'Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757', but got \" + value);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"next with delimiter options should respect delimiter and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(strings.ReplaceAll(csvTestData, \",\", \";\")), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file, { delimiter: ';' });\n\n\t\t\t// Parse the header\n\t\t\tlet { done, value } = await parser.next();\n\t\t\tif (done) {\n\t\t\t\tthrow new Error(\"Expected to read a record, but got done=true\");\n\t\t\t}\n\n\t\t\tif (value.length !== 6) {\n\t\t\t\tthrow new Error(\"Expected 6 fields, but got \" + value.length);\n\t\t\t}\n\n\t\t\tif (JSON.stringify(value) !== JSON.stringify([\"lastname\", \"firstname\", \"composer\", \"born\", \"died\", \"dates\"])) {\n\t\t\t\tthrow new Error(\"Expected header to be 'lastname,firstname,composer,born,died,dates', but got \" + value);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"next with skipFirstLine options should ignore header and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file, { skipFirstLine: true });\n\n\t\t\t// Parse the first record\n\t\t\tconst { done, value } = await parser.next();\n\t\t\tif (done) {\n\t\t\t\tthrow new Error(\"Expected to read a record, but got done=true\");\n\t\t\t}\n\t\t\tif (value.length !== 6) {\n\t\t\t\tthrow new Error(\"Expected 6 fields, but got \" + value.length);\n\t\t\t}\n\t\t\tif (JSON.stringify(value) !== JSON.stringify([\"Scarlatti\", \"Domenico\", \"Domenico Scarlatti\", \"1685\", \"1757\", \"1685–1757\"])) {\n\t\t\t\tthrow new Error(\"Expected record to be 'Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757', but got \" + value);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"next with fromLine option should start from provided line number and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file, { fromLine: 9 });\n\n\t\t\t// Parse the first record from the line at index 9\n\t\t\tconst { done, value } = await parser.next();\n\t\t\tif (done) {\n\t\t\t\tthrow new Error(\"Expected to read a record, but got done=true\");\n\t\t\t}\n\t\t\tif (value.length !== 6) {\n\t\t\t\tthrow new Error(\"Expected 6 fields, but got \" + value.length);\n\t\t\t}\n\t\t\tif (JSON.stringify(value) !== JSON.stringify([\"Bellini\", \"Vincenzo\", \"Vincenzo Bellini\", \"1801\", \"1835\", \"1801–1835\"])) {\n\t\t\t\tthrow new Error(\"Expected record to be 'Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757', but got \" + value);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"next with skipFirstLine does not impact fromLine and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file, { skipFirstLine: true, fromLine: 9 });\n\n\t\t\t// Parse the first record from the line at index 9\n\t\t\tconst { done, value } = await parser.next();\n\t\t\tif (done) {\n\t\t\t\tthrow new Error(\"Expected to read a record, but got done=true\");\n\t\t\t}\n\t\t\tif (value.length !== 6) {\n\t\t\t\tthrow new Error(\"Expected 6 fields, but got \" + value.length);\n\t\t\t}\n\t\t\tif (JSON.stringify(value) !== JSON.stringify([\"Bellini\", \"Vincenzo\", \"Vincenzo Bellini\", \"1801\", \"1835\", \"1801–1835\"])) {\n\t\t\t\tthrow new Error(\"Expected record to be 'Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757', but got \" + value);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"next with toLine option should end at provided line number and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file, { toLine: 2 });\n\n\t\t\t// Ignore the header\n\t\t\tawait parser.next();\n\n\t\t\t// Parse the first record\n\t\t\tawait parser.next();\n\n\t\t\t// Because we asked to parse to line 2 we should effectively parse it\n\t\t\tlet { done } = await parser.next();\n\t\t\tif (done) {\n\t\t\t\tthrow new Error(\"Expected to not be done, but got done=true\");\n\t\t\t}\n\n\t\t\t// Finally because we are past line 2 we should be done\n\t\t\t({ done } = await parser.next());\n\t\t\tif (!done) {\n\t\t\t\tthrow new Error(\"Expected to be done, but got done=false\");\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"next with skipFirstLine does not impact fromLine and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file, { skipFirstLine: true, toLine: 2 });\n\n\t\t\t// Ignore the header\n\t\t\tawait parser.next();\n\n\t\t\t// Parse the first record\n\t\t\tawait parser.next();\n\n\t\t\t// Because we asked to parse until line 2, we should be done, and have reached EOF\n\t\t\tconst { done } = await parser.next();\n\t\t\tif (!done) {\n\t\t\t\tthrow new Error(\"Expected to be done, but got done=false\");\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"next with header option should return records as objects and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file, { asObjects: true });\n\t\t\tlet gotParsedCount = 0;\n\n\t\t\tlet { done, value } = await parser.next();\n\t\t\twhile (!done) {\n\t\t\t\tif (typeof value !== 'object' || value === null || Array.isArray(value)) {\n\t\t\t\t\tthrow new Error(\"Expected record to be an object, but got \" + typeof value);\n\t\t\t\t}\n\n\t\t\t\tif (Object.keys(value).length !== 6) {\n\t\t\t\t\tthrow new Error(\"Expected record to have 6 fields, but got \" + Object.keys(value).length);\n\t\t\t\t}\n\n\t\t\t\tgotParsedCount++;\n\t\t\t\t({ done, value } = await parser.next());\n\t\t\t}\n\n\t\t\tif (gotParsedCount !== 10) {\n\t\t\t\tthrow new Error(\"Expected to parse 10 records, but got \" + gotParsedCount);\n\t\t\t}\n\n\t\t`, testFilePath)))\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"calling next on a parser that has reached EOF should return done=true and no value\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst parser = new csv.Parser(file);\n\n\t\t\t// Parse the entire file\n\t\t\tlet { done, value } = await parser.next();\n\t\t\twhile (!done) {\n\t\t\t\t({ done, value } = await parser.next());\n\t\t\t}\n\n\t\t\t// The parser should be done now\n\t\t\t({ done, value } = await parser.next());\n\t\t\tif (!done) {\n\t\t\t\tthrow new Error(\"Expected to be done, but got done=false\");\n\t\t\t}\n\t\t\tif (!Array.isArray(value) || value.length !== 0) {\n\t\t\t\tthrow new Error(\"Expected value to be a zero length array, but got \" + value);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestParse(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"parse with default options should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst csvRecords = await csv.parse(file);\n\n\t\t\tif (csvRecords.length !== 11) {\n\t\t\t\tthrow new Error(\"Expected 11 records, but got \" + csvRecords.length);\n\t\t\t}\n\n\t\t\t// FIXME @oleiade: Ideally we would check the prototype of the returned object is SharedArray, but\n\t\t\t// the prototype of SharedArray is not exposed to the JS runtime as such at the moment.\n\t\t\tif (csvRecords.constructor !== Array) {\n\t\t\t\tthrow new Error(\"Expected the result to be a SharedArray, but got \" + csvRecords.constructor);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"parse respects the delimiter option and should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(strings.ReplaceAll(csvTestData, \",\", \";\")), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst csvRecords = await csv.parse(file, { delimiter: ';' });\n\n\t\t\tif (csvRecords.length !== 11) {\n\t\t\t\tthrow new Error(\"Expected 11 records, but got \" + csvRecords.length);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"parse respects the skipFirstLine option and should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst csvRecords = await csv.parse(file, { skipFirstLine: true });\n\n\t\t\tif (csvRecords.length !== 10) {\n\t\t\t\tthrow new Error(\"Expected 10 records, but got \" + csvRecords.length);\n\t\t\t}\n\n\t\t\tconst wantRecord = [\"Scarlatti\", \"Domenico\", \"Domenico Scarlatti\", \"1685\", \"1757\", \"1685–1757\"];\n\t\t\tif (JSON.stringify(csvRecords[0]) !== JSON.stringify(wantRecord)) {\n\t\t\t\tthrow new Error(\"Expected first record to be 'Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757', but got \" + csvRecords[0]);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"parse respects the fromLine option and should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst csvRecords = await csv.parse(file, { fromLine: 10 });\n\n\t\t\tif (csvRecords.length !== 1) {\n\t\t\t\tthrow new Error(\"Expected 1 records, but got \" + csvRecords.length);\n\t\t\t}\n\n\t\t\tconst wantRecord = [\"Ligeti\",\"György\",\"György Ligeti\",\"1923\",\"2006\",\"1923–2006\"];\n\t\t\tif (JSON.stringify(csvRecords[0]) !== JSON.stringify(wantRecord)) {\n\t\t\t\tthrow new Error(\"Expected first record to be 'Ligeti,György,György Ligeti,1923,2006,1923–2006', but got \" + csvRecords[0]);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"parse respects the toLine option and should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst csvRecords = await csv.parse(file, { toLine: 2 });\n\n\t\t\tif (csvRecords.length !== 3) {\n\t\t\t\tthrow new Error(\"Expected 3 records, but got \" + csvRecords.length);\n\t\t\t}\n\n\t\t\tconst wantRecord = [\"Dorman\",\"Avner\",\"Avner Dorman\",\"1975\",\"\",\"1975–\"];\n\t\t\tif (JSON.stringify(csvRecords[2]) !== JSON.stringify(wantRecord)) {\n\t\t\t\tthrow new Error(\"Expected first record to be 'Dorman,Avner,Avner Dorman,1975,,1975–', but got \" + csvRecords[1]);\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"parse respects the header option, returns records as objects and succeeds\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t// Ensure the testdata.csv file is present on the test filesystem.\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tconst csvRecords = await csv.parse(file, { asObjects: true });\n\n\t\t\tif (csvRecords.length !== 10) {\n\t\t\t\tthrow new Error(\"Expected 10 records, but got \" + csvRecords.length);\n\t\t\t}\n\n\t\t\tfor (const record of csvRecords) {\n\t\t\t\tif (typeof record !== 'object' || record === null || Array.isArray(record)) {\n\t\t\t\t\tthrow new Error(\"Expected record to be an object, but got \" + typeof record);\n\t\t\t\t}\n\n\t\t\t\tif (Object.keys(record).length !== 6) {\n\t\t\t\t\tthrow new Error(\"Expected record to have 6 fields, but got \" + Object.keys(record).length);\n\t\t\t\t}\n\t\t\t}\n\t\t`, testFilePath)))\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"parse with invalid first argument should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(csvTestData), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(`\n\t\t\ttry {\n\t\t\t\tawait csv.parse(5);\n\t\t\t\tthrow new Error(\"Expected csv.parse to reject, but it resolved\");\n\t\t\t} catch (e) {\n\t\t\t\tif (!e.message.includes(\"fs.File instance\")) {\n\t\t\t\t\tthrow new Error(\"Expected error about fs.File, got: \" + e.message);\n\t\t\t\t}\n\t\t\t}\n\t\t`))\n\n\t\trequire.NoError(t, err)\n\t})\n\n\tt.Run(\"parse with asObjects and malformed CSV should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// CSV with header (3 cols) but row has only 2 cols - record length mismatch\n\t\tmalformedCSV := \"a,b,c\\n1,2\\n\"\n\t\tmalformedPath := fsext.FilePathSeparator + \"malformed.csv\"\n\n\t\tr, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\tr.VU.InitEnvField.FileSystems[\"file\"] = newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, malformedPath, []byte(malformedCSV), 0o644)\n\t\t})\n\n\t\t_, err = r.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\ttry {\n\t\t\t\tconst file = await fs.open(%q);\n\t\t\t\tawait csv.parse(file, { asObjects: true });\n\t\t\t\tthrow new Error(\"Expected csv.parse to reject, but it resolved\");\n\t\t\t} catch (e) {\n\t\t\t\tif (!e.message.includes(\"doesn't match header length\") && !e.message.includes(\"failed to read\")) {\n\t\t\t\t\tthrow new Error(\"Expected error about record/header mismatch, got: \" + e.message);\n\t\t\t\t}\n\t\t\t}\n\t\t`, malformedPath)))\n\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestBuildSharedArrayNameDeterministic(t *testing.T) {\n\tt.Parallel()\n\n\tfile := fs.File{Path: \"/tmp/data.csv\"}\n\toptions := newDefaultParserOptions()\n\n\tfirst, err := buildSharedArrayName(file, options)\n\trequire.NoError(t, err)\n\n\tsecond, err := buildSharedArrayName(file, options)\n\trequire.NoError(t, err)\n\trequire.Equal(t, first, second)\n\n\toptions.Delimiter = ';'\n\n\tthird, err := buildSharedArrayName(file, options)\n\trequire.NoError(t, err)\n\trequire.NotEqual(t, first, third)\n}\n\nconst initGlobals = `\n\tglobalThis.fs = require(\"k6/experimental/fs\");\n\tglobalThis.csv = require(\"k6/experimental/csv\");\n`\n\nfunc newConfiguredRuntime(t testing.TB) (*modulestest.Runtime, error) {\n\truntime := modulestest.NewRuntime(t)\n\n\tmodules := map[string]any{\n\t\t\"k6/experimental/fs\":  fs.New(),\n\t\t\"k6/experimental/csv\": New(),\n\t}\n\n\terr := runtime.SetupModuleSystem(modules, nil, compiler.New(runtime.VU.InitEnv().Logger))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Set up the VU environment with an in-memory filesystem and a CWD of \"/\".\n\truntime.VU.InitEnvField.FileSystems = map[string]fsext.Fs{\n\t\t\"file\": fsext.NewMemMapFs(),\n\t}\n\truntime.VU.InitEnvField.CWD = &url.URL{Scheme: \"file\"}\n\n\t// Ensure the `fs` module is available in the VU's runtime.\n\t_, err = runtime.VU.Runtime().RunString(initGlobals)\n\n\treturn runtime, err\n}\n\n// newTestFs is a helper function that creates a new in-memory file system and calls the provided\n// function with it. The provided function is expected to use the file system to create files and\n// directories.\nfunc newTestFs(t *testing.T, fn func(fs fsext.Fs) error) fsext.Fs {\n\tt.Helper()\n\n\tfilesystem := fsext.NewMemMapFs()\n\n\terr := fn(filesystem)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\treturn filesystem\n}\n\n// wrapInAsyncLambda is a helper function that wraps the provided input in an async lambda. This\n// makes the use of `await` statements in the input possible.\nfunc wrapInAsyncLambda(input string) string {\n\t// This makes it possible to use `await` freely on the \"top\" level\n\treturn \"(async () => {\\n \" + input + \"\\n })()\"\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/csv/reader.go",
    "content": "package csv\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"sync/atomic\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/data\"\n)\n\n// Reader is a CSV reader.\n//\n// It wraps a csv.Reader and provides additional functionality such as the ability to stop reading at a specific line.\ntype Reader struct {\n\tcsv *csv.Reader\n\n\t// currentLine tracks the current line number.\n\tcurrentLine atomic.Int64\n\n\t// options holds the reader's options.\n\toptions options\n\n\t// columnNames stores the column names when the asObjects option is enabled\n\t// in order to be able to map each row values to their corresponding column.\n\tcolumnNames []string\n}\n\n// NewReaderFrom creates a new CSV reader from the provided io.Reader.\n//\n// It will check whether the first line should be skipped and consume it if necessary.\n// It will also check whether the reader should start from a specific line and skip lines until that line is reached.\n// We perform these operations here to avoid having to do them in the Read method.\n//\n// Hence, this constructor function can return an error if the first line cannot be skipped or if the reader\n// cannot start from the specified line.\nfunc NewReaderFrom(r io.Reader, options options) (*Reader, error) {\n\tif r == nil {\n\t\treturn nil, fmt.Errorf(\"the reader cannot be nil\")\n\t}\n\n\tif err := validateOptions(options); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif options.Delimiter == 0 {\n\t\toptions.Delimiter = ','\n\t}\n\n\tcsvParser := csv.NewReader(r)\n\tcsvParser.Comma = options.Delimiter\n\n\treader := &Reader{\n\t\tcsv:     csvParser,\n\t\toptions: options,\n\t}\n\n\tasObjectsEnabled := options.AsObjects.Valid && options.AsObjects.Bool\n\tif asObjectsEnabled {\n\t\theader, err := csvParser.Read()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read the first line; reason: %w\", err)\n\t\t}\n\t\treader.columnNames = header\n\t\treader.currentLine.Add(1)\n\t}\n\n\tif options.SkipFirstLine && (!options.FromLine.Valid || options.FromLine.Int64 == 0) {\n\t\tif _, err := csvParser.Read(); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to skip the first line; reason: %w\", err)\n\t\t}\n\n\t\treader.currentLine.Add(1)\n\t}\n\n\tif options.FromLine.Valid && options.FromLine.Int64 > 0 {\n\t\tfor reader.currentLine.Load() < options.FromLine.Int64 {\n\t\t\tif _, err := csvParser.Read(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to skip lines until line %d; reason: %w\", options.FromLine.Int64, err)\n\t\t\t}\n\t\t\treader.currentLine.Add(1)\n\t\t}\n\t}\n\n\treturn reader, nil\n}\n\n// The csv module's read must implement the RecordReader interface.\nvar _ data.RecordReader = (*Reader)(nil)\n\n// Read reads a record from the CSV file.\n//\n// If the `header` option is enabled, it will return a map of the record.\n// Otherwise, it will return the record as a slice of strings.\nfunc (r *Reader) Read() (any, error) {\n\ttoLineSet := r.options.ToLine.Valid\n\n\t// If the `toLine` option was set and we have reached it, we return EOF.\n\tif toLineSet && r.options.ToLine.Int64 > 0 && r.currentLine.Load() > r.options.ToLine.Int64 {\n\t\treturn nil, io.EOF\n\t}\n\n\trecord, err := r.csv.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tr.currentLine.Add(1)\n\n\t// If header option is enabled, return a map of the record.\n\tif r.options.AsObjects.Valid && r.options.AsObjects.Bool {\n\t\tif r.columnNames == nil {\n\t\t\treturn nil, fmt.Errorf(\"the 'asObjects' option is enabled, but no header was found\")\n\t\t}\n\n\t\tif len(record) != len(r.columnNames) {\n\t\t\treturn nil, fmt.Errorf(\"record length (%d) doesn't match header length (%d)\", len(record), len(r.columnNames))\n\t\t}\n\n\t\trecordMap := make(map[string]string)\n\t\tfor i, value := range record {\n\t\t\trecordMap[r.columnNames[i]] = value\n\t\t}\n\n\t\treturn recordMap, nil\n\t}\n\n\treturn record, nil\n}\n\n// validateOptions validates the reader options and returns an error if any validation fails.\nfunc validateOptions(options options) error {\n\tvar (\n\t\tfromLineSet      = options.FromLine.Valid\n\t\ttoLineSet        = options.ToLine.Valid\n\t\tskipFirstLineSet = options.SkipFirstLine\n\t\tasObjectsEnabled = options.AsObjects.Valid && options.AsObjects.Bool\n\t)\n\n\tif asObjectsEnabled && skipFirstLineSet {\n\t\treturn fmt.Errorf(\"the 'header' option cannot be enabled when 'skipFirstLine' is true\")\n\t}\n\n\tif asObjectsEnabled && fromLineSet && options.FromLine.Int64 > 0 {\n\t\treturn fmt.Errorf(\"the 'header' option cannot be enabled when 'fromLine' is set to a value greater than 0\")\n\t}\n\n\tif fromLineSet && options.FromLine.Int64 < 0 {\n\t\treturn fmt.Errorf(\"the 'fromLine' option must be greater than or equal to 0; got %d\", options.FromLine.Int64)\n\t}\n\n\tif toLineSet && options.ToLine.Int64 < 0 {\n\t\treturn fmt.Errorf(\"the 'toLine' option must be greater than or equal to 0; got %d\", options.ToLine.Int64)\n\t}\n\n\tif fromLineSet && toLineSet && options.FromLine.Int64 >= options.ToLine.Int64 {\n\t\treturn fmt.Errorf(\n\t\t\t\"the 'fromLine' option must be less than the 'toLine' option; got 'fromLine': %d, 'toLine': %d\",\n\t\t\toptions.FromLine.Int64, options.ToLine.Int64,\n\t\t)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/csv/reader_test.go",
    "content": "package csv\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNewReaderFrom(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"instantiating a new reader with a nil io.Reader should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := NewReaderFrom(nil, options{})\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"instantiating a new reader with the fromLine option less than 0 should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := NewReaderFrom(\n\t\t\tstrings.NewReader(\"lastname,firstname,composer,born,died,dates\\n\"),\n\t\t\toptions{FromLine: null.NewInt(-1, true)},\n\t\t)\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"instantiating a new reader with the toLine option less than 0 should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := NewReaderFrom(\n\t\t\tstrings.NewReader(\"lastname,firstname,composer,born,died,dates\\n\"),\n\t\t\toptions{ToLine: null.NewInt(-1, true)},\n\t\t)\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"instantiating a new reader with fromLine greater or equal to toLine should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := NewReaderFrom(\n\t\t\tstrings.NewReader(\"lastname,firstname,composer,born,died,dates\\n\"),\n\t\t\toptions{FromLine: null.NewInt(4, true), ToLine: null.NewInt(1, true)},\n\t\t)\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"instantiating a new reader with asObjects option enabled and skipFirstLine option enabled should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := NewReaderFrom(\n\t\t\tstrings.NewReader(\"lastname,firstname,composer,born,died,dates\\n\"),\n\t\t\toptions{AsObjects: null.NewBool(true, true), SkipFirstLine: true},\n\t\t)\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"instantiating a new reader with asObjects option enabled and fromLine option set to a value greater than 0 should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t_, err := NewReaderFrom(\n\t\t\tstrings.NewReader(\"lastname,firstname,composer,born,died,dates\\n\"),\n\t\t\toptions{AsObjects: null.NewBool(true, true), FromLine: null.NewInt(1, true)},\n\t\t)\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"instantiating a new reader with asObjects option enabled and compatible options should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tr, err := NewReaderFrom(\n\t\t\tstrings.NewReader(\"lastname,firstname,composer,born,died,dates\\n\"),\n\t\t\toptions{AsObjects: null.NewBool(true, true)},\n\t\t)\n\t\trequire.NoError(t, err)\n\t\tassert.NotNil(t, r.columnNames)\n\t\tassert.Equal(t, []string{\"lastname\", \"firstname\", \"composer\", \"born\", \"died\", \"dates\"}, r.columnNames)\n\t\tassert.Equal(t, int64(1), r.currentLine.Load())\n\t})\n\n\tt.Run(\"skipFirstLine option skips first line and succeeds\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst csvTestData = \"lastname,firstname,composer,born,died,dates\\n\" +\n\t\t\t\"Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757\\n\"\n\n\t\tr, err := NewReaderFrom(\n\t\t\tstrings.NewReader(csvTestData),\n\t\t\toptions{SkipFirstLine: true},\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\trecords, err := r.csv.Read()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, []string{\"Scarlatti\", \"Domenico\", \"Domenico Scarlatti\", \"1685\", \"1757\", \"1685–1757\"}, records)\n\t})\n\n\tt.Run(\"fromLine option move reading head forward and succeeds\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst csvTestData = \"lastname,firstname,composer,born,died,dates\\n\" +\n\t\t\t\"Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757\\n\" +\n\t\t\t\"Dorman,Avner,Avner Dorman,1975,,1975–\\n\" +\n\t\t\t\"Still,William Grant,William Grant Still,1895,1978,1895–1978\\n\"\n\n\t\tr, err := NewReaderFrom(\n\t\t\tstrings.NewReader(csvTestData),\n\t\t\toptions{FromLine: null.NewInt(2, true)},\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\trecords, err := r.csv.Read()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, []string{\"Dorman\", \"Avner\", \"Avner Dorman\", \"1975\", \"\", \"1975–\"}, records)\n\t})\n\n\tt.Run(\"fromLine option supersedes skipFirstLine option and succeeds\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst csvTestData = \"lastname,firstname,composer,born,died,dates\\n\" +\n\t\t\t\"Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757\\n\" +\n\t\t\t\"Dorman,Avner,Avner Dorman,1975,,1975–\\n\" +\n\t\t\t\"Still,William Grant,William Grant Still,1895,1978,1895–1978\\n\"\n\n\t\tr, err := NewReaderFrom(\n\t\t\tstrings.NewReader(csvTestData),\n\t\t\toptions{SkipFirstLine: true, FromLine: null.NewInt(2, true)},\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\trecords, err := r.csv.Read()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, []string{\"Dorman\", \"Avner\", \"Avner Dorman\", \"1975\", \"\", \"1975–\"}, records)\n\t})\n}\n\nfunc TestReader_Read(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"default behavior should return all lines as slices of strings and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst csvTestData = \"lastname,firstname,composer,born,died,dates\\n\" +\n\t\t\t\"Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757\\n\"\n\n\t\tr, err := NewReaderFrom(\n\t\t\tstrings.NewReader(csvTestData),\n\t\t\toptions{},\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\t// Parsing gotHeader should succeed\n\t\tgotHeader, err := r.Read()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, []string{\"lastname\", \"firstname\", \"composer\", \"born\", \"died\", \"dates\"}, gotHeader)\n\n\t\t// Parsing first line should succeed\n\t\tgotFirstLine, err := r.Read()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, []string{\"Scarlatti\", \"Domenico\", \"Domenico Scarlatti\", \"1685\", \"1757\", \"1685–1757\"}, gotFirstLine)\n\n\t\t// As we've reached EOF, we should get EOF\n\t\t_, err = r.Read()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorIs(t, err, io.EOF)\n\t})\n\n\tt.Run(\"asObjects option should lead to lines being returned as maps and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst csvTestData = \"lastname,firstname,composer,born,died,dates\\n\" +\n\t\t\t\"Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757\\n\"\n\n\t\tr, err := NewReaderFrom(\n\t\t\tstrings.NewReader(csvTestData),\n\t\t\toptions{AsObjects: null.NewBool(true, true)},\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\t// AsObjects line, if present should be ignored and records should be returned as maps\n\t\tfirstRecord, err := r.Read()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, map[string]string{\n\t\t\t\"lastname\":  \"Scarlatti\",\n\t\t\t\"firstname\": \"Domenico\",\n\t\t\t\"composer\":  \"Domenico Scarlatti\",\n\t\t\t\"born\":      \"1685\",\n\t\t\t\"died\":      \"1757\",\n\t\t\t\"dates\":     \"1685–1757\",\n\t\t}, firstRecord)\n\n\t\t// As we've reached EOF, we should get EOF\n\t\t_, err = r.Read()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorIs(t, err, io.EOF)\n\t})\n\n\tt.Run(\"toLine option returns EOF when toLine option is reached and succeeds\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconst csvTestData = \"lastname,firstname,composer,born,died,dates\\n\" +\n\t\t\t\"Scarlatti,Domenico,Domenico Scarlatti,1685,1757,1685–1757\\n\" +\n\t\t\t\"Dorman,Avner,Avner Dorman,1975,,1975–\\n\" +\n\t\t\t\"Still,William Grant,William Grant Still,1895,1978,1895–1978\\n\"\n\n\t\tr, err := NewReaderFrom(\n\t\t\tstrings.NewReader(csvTestData),\n\t\t\toptions{ToLine: null.NewInt(2, true)},\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\t// Parsing header should succeed\n\t\t_, err = r.Read()\n\t\trequire.NoError(t, err)\n\n\t\t// Parsing first line should succeed\n\t\t_, err = r.Read()\n\t\trequire.NoError(t, err)\n\n\t\t// Parsing second line should succeed\n\t\t_, err = r.Read()\n\t\trequire.NoError(t, err)\n\n\t\t// As we've reached `toLine`, we should get EOF\n\t\t_, err = r.Read()\n\t\trequire.Error(t, err)\n\t\trequire.ErrorIs(t, err, io.EOF)\n\t})\n}\n\nfunc TestValidateOptions(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"validateOptions with asObjects and skipFirstLine should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\terr := validateOptions(options{AsObjects: null.NewBool(true, true), SkipFirstLine: true})\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"validateOptions with asObjects and fromLine greater than 0 should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\terr := validateOptions(options{AsObjects: null.NewBool(true, true), FromLine: null.NewInt(1, true)})\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"validateOptions with fromLine less than 0 should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\terr := validateOptions(options{FromLine: null.NewInt(-1, true)})\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"validateOptions with toLine less than 0 should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\terr := validateOptions(options{ToLine: null.NewInt(-1, true)})\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"validateOptions with fromLine greater than toLine should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\terr := validateOptions(options{FromLine: null.NewInt(2, true), ToLine: null.NewInt(1, true)})\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"validateOptions with compatible options should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\terr := validateOptions(options{})\n\t\trequire.NoError(t, err)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/experimental.go",
    "content": "// Package experimental includes experimental module features\npackage experimental\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the root experimental module\n\tRootModule struct{}\n\t// ModuleInstance represents an instance of the experimental module\n\tModuleInstance struct {\n\t\tvu modules.VU\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// NewModuleInstance implements modules.Module interface\nfunc (*RootModule) NewModuleInstance(m modules.VU) modules.Instance {\n\treturn &ModuleInstance{vu: m}\n}\n\n// New returns a new RootModule.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// Exports returns the exports of the experimental module\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"setTimeout\": mi.setTimeout,\n\t\t},\n\t}\n}\n\nfunc (mi *ModuleInstance) setTimeout(f sobek.Callable, t float64) {\n\tif f == nil {\n\t\tcommon.Throw(mi.vu.Runtime(), errors.New(\"setTimeout requires a function as first argument\"))\n\t}\n\t// TODO maybe really return something to use with `clearTimeout\n\t// TODO support arguments ... maybe\n\trunOnLoop := mi.vu.RegisterCallback()\n\tgo func() {\n\t\ttimer := time.NewTimer(time.Duration(t * float64(time.Millisecond)))\n\t\tselect {\n\t\tcase <-timer.C:\n\t\t\trunOnLoop(func() error {\n\t\t\t\t_, err := f(sobek.Undefined())\n\t\t\t\treturn err\n\t\t\t})\n\t\tcase <-mi.vu.Context().Done():\n\t\t\t// TODO log something?\n\n\t\t\ttimer.Stop()\n\t\t\trunOnLoop(func() error { return nil })\n\t\t}\n\t}()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/cache.go",
    "content": "package fs\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// cache is a cache of opened files, designed to minimize redundant file reads, and\n// avoid replicating the content of the files in memory as much as possible.\n//\n// Unlike the underlying [fsext.Fs] which also caches file contents, this cache minimizes\n// synchronization overhead. [fsext.Fs], using `afero`, employs a [sync.RWMutex] for each\n// file access, involving lock/unlock operations. Our cache, however, utilizes a concurrent-safe\n// map (openedFiles), bypassing the need for these locks and enhancing performance.\n//\n// This cache could be seen as redundant, as the underlying [fsext.Fs] implementation\n// already caches the content of the files it opens. However, the current implementation of\n// [fsext.Fs] relies on `afero` under the hood, which in turn relies on a [sync.RWMutex] to\n// protect access to the cached file content. This means that every time a file is opened,\n// the `fsext.Fs` cache is accessed, and the [sync.RWMutex] is locked and unlocked.\n//\n// This cache is designed to avoid this synchronization overhead, by caching the content of\n// the files in a map that is safe for concurrent use, and thus avoid the need for a lock.\n//\n// This leads to a performance improvement, at the cost of holding the content of the files\n// in memory twice, once in the cache's `openedFiles` map, and once in the `fsext.Fs` cache.\n//\n// Note that the current implementation of the cache diverges from the guarantees expressed in the\n// [design document] defining the `fs` module, as it we effectively hold the file's content in memory\n// twice as opposed to once.\n//\n// Future updates (see [#1079](https://github.com/grafana/k6/issues/1079)) may phase out reliance on `afero`.\n// Depending on our new choice for [fsext] implementation, this cache might become obsolete, allowing us\n// to solely depend on [fsext.Fs.Open].\n//\n// [#1079]: https://github.com/grafana/k6/issues/1079\ntype cache struct {\n\t// openedFiles holds a safe for concurrent use map, holding the content\n\t// of the files that were opened by the user.\n\t//\n\t// Keys are expected to be strings holding the openedFiles' path.\n\t// Values are expected to be byte slices holding the content of the opened file.\n\t//\n\t// That way, we can cache the file's content and avoid opening too many\n\t// file descriptor, and re-reading its content every time the file is opened.\n\t//\n\t// Importantly, this also means that if the\n\t// file is modified from outside of k6, the changes will not be reflected in the file's data.\n\topenedFiles sync.Map\n}\n\n// open retrieves the content of a given file from the specified filesystem (fromFs) and\n// stores it in the cache's internal `openedFiles` map.\n//\n// The function cleans the provided filename using filepath.Clean before using it.\n//\n// If the file was previously \"opened\" (and thus cached), it\n// returns the cached content. Otherwise, it reads the file from the\n// filesystem, caches its content, and then returns it.\n//\n// The function is designed to minimize redundant file reads by leveraging an internal cache (openedFiles).\n// In case the cached value is not a byte slice (which should never occur in regular use), it\n// panics with a descriptive error.\n//\n// Parameters:\n//   - filename: The name of the file to be retrieved. This should be a relative or absolute path.\n//   - fromFs: The filesystem (from the fsext package) from which the file should be read if not already cached.\n//\n// Returns:\n//   - A byte slice containing the content of the specified file.\n//   - An error if there's any issue opening or reading the file. If the file content is\n//     successfully cached and returned once, subsequent calls will not produce\n//     file-related errors for the same file, as the cached value will be used.\nfunc (fr *cache) open(filename string, fromFs fsext.Fs) (data []byte, err error) {\n\tfilename = filepath.Clean(filename)\n\n\tif f, ok := fr.openedFiles.Load(filename); ok {\n\t\tdata, ok = f.([]byte)\n\t\tif !ok {\n\t\t\tpanic(fmt.Errorf(\"cache's file %s is not stored as a byte slice\", filename))\n\t\t}\n\n\t\treturn data, nil\n\t}\n\n\t// TODO: re-evaluate opening from the FS this once #1079 is resolved.\n\tf, err := fromFs.Open(filename)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\tcerr := f.Close()\n\t\tif cerr != nil {\n\t\t\terr = fmt.Errorf(\"failed to close file %s: %w\", filename, cerr)\n\t\t}\n\t}()\n\n\tdata, err = io.ReadAll(f)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read the content of file %s: %w\", filename, err)\n\t}\n\n\tfr.openedFiles.Store(filename, data)\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/cache_test.go",
    "content": "package fs\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestFileCacheOpen(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"open succeeds\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcache := &cache{}\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, \"bonjour.txt\", []byte(\"Bonjour, le monde\"), 0o644)\n\t\t})\n\n\t\t_, gotBeforeOk := cache.openedFiles.Load(\"bonjour.txt\")\n\t\tgotData, gotErr := cache.open(\"bonjour.txt\", fs)\n\t\t_, gotAfterOk := cache.openedFiles.Load(\"bonjour.txt\")\n\n\t\tassert.False(t, gotBeforeOk)\n\t\tassert.NoError(t, gotErr)\n\t\tassert.Equal(t, []byte(\"Bonjour, le monde\"), gotData)\n\t\tassert.True(t, gotAfterOk)\n\t})\n\n\tt.Run(\"double open succeeds\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tcache := &cache{}\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, \"bonjour.txt\", []byte(\"Bonjour, le monde\"), 0o644)\n\t\t})\n\n\t\tfirstData, firstErr := cache.open(\"bonjour.txt\", fs)\n\t\t_, gotFirstOk := cache.openedFiles.Load(\"bonjour.txt\")\n\t\tsecondData, secondErr := cache.open(\"bonjour.txt\", fs)\n\t\t_, gotSecondOk := cache.openedFiles.Load(\"bonjour.txt\")\n\n\t\tassert.True(t, gotFirstOk)\n\t\tassert.NoError(t, firstErr)\n\t\tassert.Equal(t, []byte(\"Bonjour, le monde\"), firstData)\n\t\tassert.True(t, gotSecondOk)\n\t\tassert.NoError(t, secondErr)\n\t\tassert.True(t, sameUnderlyingArray(firstData, secondData))\n\t\tassert.Equal(t, []byte(\"Bonjour, le monde\"), secondData)\n\t})\n}\n\n// sameUnderlyingArray returns true if the underlying array of lhs and rhs are the same.\n//\n// This is done by checking that the two slices have a capacity greater than 0 and that\n// the last element of the underlying array is the same for both slices.\n//\n// Once a slice is created, its starting address can move forward, but can never move\n// behond its starting address + its capacity, which is a fixed value for any Go slice.\n//\n// Hence, if the last element of the underlying array is the same for both slices, it\n// means that the underlying array is the same.\n//\n// See [explanation] for more details.\n//\n// [explanation]: https://groups.google.com/g/golang-nuts/c/ks1jvoyMYuc?pli=1\nfunc sameUnderlyingArray(lhs, rhs []byte) bool {\n\treturn cap(lhs) > 0 && cap(rhs) > 0 && &lhs[0:cap(lhs)][cap(lhs)-1] == &rhs[0:cap(rhs)][cap(rhs)-1]\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/errors.go",
    "content": "package fs\n\n// newFsError creates a new Error object of the provided kind and with the\n// provided message.\nfunc newFsError(k errorKind, message string) *fsError {\n\treturn &fsError{\n\t\tName:    k.String(),\n\t\tMessage: message,\n\t\tkind:    k,\n\t}\n}\n\n// errorKind indicates the kind of file system error that has occurred.\n//\n// Its string representation is generated by the `enumer` tool. The\n// `enumer` tool is run by the `go generate` command. See the `go generate`\n// command documentation.\n// The tool itself is not tracked as part of the k6 go.mod file, and\n// therefore must be installed manually using `go install github.com/dmarkham/enumer`.\n//\n//go:generate go run github.com/dmarkham/enumer@v1.5.11 -type=errorKind -output errors_gen.go\ntype errorKind uint8\n\nconst (\n\t// NotFoundError is emitted when a file is not found.\n\tNotFoundError errorKind = iota + 1\n\n\t// InvalidResourceError is emitted when a resource is invalid: for\n\t// instance when attempting to open a directory, which is not supported.\n\tInvalidResourceError\n\n\t// ForbiddenError is emitted when an operation is forbidden.\n\tForbiddenError\n\n\t// TypeError is emitted when an incorrect type has been used.\n\tTypeError\n\n\t// EOFError is emitted when the end of a file has been reached.\n\tEOFError\n)\n\n// fsError represents a custom error object emitted by the fs module.\n//\n// It is used to provide a more detailed error message to the user, and\n// provide a concrete error type that can be used to differentiate between\n// different types of errors.\n//\n// Exposing error types to the user in a way that's compatible with some\n// JavaScript error handling constructs such as `instanceof` is still non-trivial\n// in Go. See the [dedicated goja issue] with have opened for more details.\n//\n// [dedicated goja issue]: https://github.com/dop251/goja/issues/529\ntype fsError struct {\n\t// Name contains the name of the error as formalized by the [ErrorKind]\n\t// type.\n\tName string `json:\"name\"`\n\n\t// Message contains the error message as presented to the user.\n\tMessage string `json:\"message\"`\n\n\t// kind contains the kind of error that has occurred.\n\tkind errorKind\n}\n\n// Ensure that the Error type implements the Go `error` interface.\nvar _ error = (*fsError)(nil)\n\n// Error implements the Go `error` interface.\nfunc (e *fsError) Error() string {\n\treturn e.Name + \": \" + e.Message\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/errors_gen.go",
    "content": "// Code generated by \"enumer -type=errorKind -output errors_gen.go\"; DO NOT EDIT.\n\npackage fs\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _errorKindName = \"NotFoundErrorInvalidResourceErrorForbiddenErrorTypeErrorEOFError\"\n\nvar _errorKindIndex = [...]uint8{0, 13, 33, 47, 56, 64}\n\nconst _errorKindLowerName = \"notfounderrorinvalidresourceerrorforbiddenerrortypeerroreoferror\"\n\nfunc (i errorKind) String() string {\n\ti -= 1\n\tif i >= errorKind(len(_errorKindIndex)-1) {\n\t\treturn fmt.Sprintf(\"errorKind(%d)\", i+1)\n\t}\n\treturn _errorKindName[_errorKindIndex[i]:_errorKindIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _errorKindNoOp() {\n\tvar x [1]struct{}\n\t_ = x[NotFoundError-(1)]\n\t_ = x[InvalidResourceError-(2)]\n\t_ = x[ForbiddenError-(3)]\n\t_ = x[TypeError-(4)]\n\t_ = x[EOFError-(5)]\n}\n\nvar _errorKindValues = []errorKind{NotFoundError, InvalidResourceError, ForbiddenError, TypeError, EOFError}\n\nvar _errorKindNameToValueMap = map[string]errorKind{\n\t_errorKindName[0:13]:       NotFoundError,\n\t_errorKindLowerName[0:13]:  NotFoundError,\n\t_errorKindName[13:33]:      InvalidResourceError,\n\t_errorKindLowerName[13:33]: InvalidResourceError,\n\t_errorKindName[33:47]:      ForbiddenError,\n\t_errorKindLowerName[33:47]: ForbiddenError,\n\t_errorKindName[47:56]:      TypeError,\n\t_errorKindLowerName[47:56]: TypeError,\n\t_errorKindName[56:64]:      EOFError,\n\t_errorKindLowerName[56:64]: EOFError,\n}\n\nvar _errorKindNames = []string{\n\t_errorKindName[0:13],\n\t_errorKindName[13:33],\n\t_errorKindName[33:47],\n\t_errorKindName[47:56],\n\t_errorKindName[56:64],\n}\n\n// errorKindString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc errorKindString(s string) (errorKind, error) {\n\tif val, ok := _errorKindNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _errorKindNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to errorKind values\", s)\n}\n\n// errorKindValues returns all values of the enum\nfunc errorKindValues() []errorKind {\n\treturn _errorKindValues\n}\n\n// errorKindStrings returns a slice of all String values of the enum\nfunc errorKindStrings() []string {\n\tstrs := make([]string, len(_errorKindNames))\n\tcopy(strs, _errorKindNames)\n\treturn strs\n}\n\n// IsAerrorKind returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i errorKind) IsAerrorKind() bool {\n\tfor _, v := range _errorKindValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/file.go",
    "content": "package fs\n\nimport (\n\t\"io\"\n\t\"path/filepath\"\n\t\"sync/atomic\"\n)\n\n// file is an abstraction for interacting with files.\ntype file struct {\n\tpath string `js:\"path\"`\n\n\t// data holds a pointer to the file's data\n\tdata []byte `js:\"data\"`\n\n\t// offset holds the current offset in the file\n\t//\n\t// TODO: using an atomic here does not guarantee ordering of reads and seeks, and leaves\n\t// the behavior not strictly defined. This is something we might want to address in the future, and\n\t// is tracked as part of #3433.\n\toffset atomic.Int64 `js:\"offset\"`\n}\n\n// Stat returns a FileInfo describing the named file.\nfunc (f *file) Stat() *FileInfo {\n\tfilename := filepath.Base(f.path)\n\treturn &FileInfo{Name: filename, Size: f.size()}\n}\n\n// Ensure that `file` implements the Stater interface.\nvar _ Stater = (*file)(nil)\n\n// FileInfo holds information about a file.\ntype FileInfo struct {\n\t// Name holds the base name of the file.\n\tName string `json:\"name\"`\n\n\t// Size holds the size of the file in bytes.\n\tSize int64 `json:\"size\"`\n}\n\n// Read reads up to len(into) bytes into the provided byte slice.\n//\n// It returns the number of bytes read (0 <= n <= len(into)) and any error\n// encountered.\n//\n// If the end of the file has been reached, it returns EOFError.\nfunc (f *file) Read(into []byte) (n int, err error) {\n\tcurrentOffset := f.offset.Load()\n\tfileSize := f.size()\n\n\t// Check if we have reached the end of the file\n\tif currentOffset == fileSize {\n\t\treturn 0, io.EOF\n\t}\n\n\t// Calculate the effective new offset\n\ttargetOffset := currentOffset + int64(len(into))\n\tnewOffset := min(targetOffset, fileSize)\n\n\t// Read the data into the provided slice, and update\n\t// the offset accordingly\n\tn = copy(into, f.data[currentOffset:newOffset])\n\tf.offset.Store(newOffset)\n\n\t// If we've reached or surpassed the end, set the error to EOF\n\tif targetOffset > fileSize {\n\t\terr = io.EOF\n\t}\n\n\treturn n, err\n}\n\n// Ensure that `file` implements the io.Reader interface.\nvar _ io.Reader = (*file)(nil)\n\n// Seek sets the offset for the next operation on the file, under the mode given by `whence`.\n//\n// `offset` indicates the number of bytes to move the offset. Based on\n// the `whence` parameter, the offset is set relative to the start,\n// current offset or end of the file.\n//\n// When using SeekModeStart, the offset must be positive.\n// Negative offsets are allowed when using `SeekModeCurrent` or `SeekModeEnd`.\nfunc (f *file) Seek(offset int64, whence SeekMode) (int64, error) { //nolint:govet\n\tstartingOffset := f.offset.Load()\n\n\tnewOffset := startingOffset\n\tswitch whence {\n\tcase SeekModeStart:\n\t\tif offset < 0 {\n\t\t\treturn 0, newFsError(TypeError, \"offset cannot be negative when using SeekModeStart\")\n\t\t}\n\n\t\tnewOffset = offset\n\tcase SeekModeCurrent:\n\t\tnewOffset += offset\n\tcase SeekModeEnd:\n\t\tif offset > 0 {\n\t\t\treturn 0, newFsError(TypeError, \"offset cannot be positive when using SeekModeEnd\")\n\t\t}\n\n\t\tnewOffset = (f.size() - 1) + offset\n\tdefault:\n\t\treturn 0, newFsError(TypeError, \"invalid seek mode\")\n\t}\n\n\tif newOffset < 0 {\n\t\treturn 0, newFsError(TypeError, \"seeking before start of file\")\n\t}\n\n\tif newOffset > f.size() {\n\t\treturn 0, newFsError(TypeError, \"seeking beyond end of file\")\n\t}\n\n\t// Update the file instance's offset to the new selected position\n\tf.offset.Store(newOffset)\n\n\treturn newOffset, nil\n}\n\nvar _ io.Seeker = (*file)(nil)\n\n// SeekMode is used to specify the seek mode when seeking in a file.\ntype SeekMode = int\n\nconst (\n\t// SeekModeStart sets the offset relative to the start of the file.\n\tSeekModeStart SeekMode = 0\n\n\t// SeekModeCurrent seeks relative to the current offset.\n\tSeekModeCurrent = 1\n\n\t// SeekModeEnd seeks relative to the end of the file.\n\t//\n\t// When using this mode the seek operation will move backwards from\n\t// the end of the file.\n\tSeekModeEnd = 2\n)\n\nfunc (f *file) size() int64 {\n\treturn int64(len(f.data))\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/file_test.go",
    "content": "package fs\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFileImpl(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"read\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestCases := []struct {\n\t\t\tname     string\n\t\t\tinto     []byte\n\t\t\tfileData []byte\n\t\t\toffset   int64\n\t\t\twantInto []byte\n\t\t\twantN    int\n\t\t\twantErr  bool\n\t\t}{\n\t\t\t{\n\t\t\t\tname:     \"reading the entire file into a buffer fitting the whole file should succeed\",\n\t\t\t\tinto:     make([]byte, 5),\n\t\t\t\tfileData: []byte(\"hello\"),\n\t\t\t\toffset:   0,\n\t\t\t\twantInto: []byte(\"hello\"),\n\t\t\t\twantN:    5,\n\t\t\t\twantErr:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"reading a file larger than the provided buffer should succeed\",\n\t\t\t\tinto:     make([]byte, 3),\n\t\t\t\tfileData: []byte(\"hello\"),\n\t\t\t\toffset:   0,\n\t\t\t\twantInto: []byte(\"hel\"),\n\t\t\t\twantN:    3,\n\t\t\t\twantErr:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"reading a file larger than the provided buffer at an offset should succeed\",\n\t\t\t\tinto:     make([]byte, 3),\n\t\t\t\tfileData: []byte(\"hello\"),\n\t\t\t\toffset:   2,\n\t\t\t\twantInto: []byte(\"llo\"),\n\t\t\t\twantN:    3,\n\t\t\t\twantErr:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"reading file data into a zero sized buffer should succeed\",\n\t\t\t\tinto:     []byte{},\n\t\t\t\tfileData: []byte(\"hello\"),\n\t\t\t\toffset:   0,\n\t\t\t\twantInto: []byte{},\n\t\t\t\twantN:    0,\n\t\t\t\twantErr:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"reading past the end of the file should fill the buffer and fail with EOF\",\n\t\t\t\tinto:     make([]byte, 10),\n\t\t\t\tfileData: []byte(\"hello\"),\n\t\t\t\toffset:   0,\n\t\t\t\twantInto: []byte{'h', 'e', 'l', 'l', 'o', 0, 0, 0, 0, 0},\n\t\t\t\twantN:    5,\n\t\t\t\twantErr:  true,\n\t\t\t\t// wantErr:  EOFError,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"reading into a prefilled buffer overrides its content\",\n\t\t\t\tinto:     []byte(\"world!\"),\n\t\t\t\tfileData: []byte(\"hello\"),\n\t\t\t\toffset:   0,\n\t\t\t\twantInto: []byte(\"hello!\"),\n\t\t\t\twantN:    5,\n\t\t\t\twantErr:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"reading an empty file should fail with EOF\",\n\t\t\t\tinto:     make([]byte, 10),\n\t\t\t\tfileData: []byte{},\n\t\t\t\toffset:   0,\n\t\t\t\twantInto: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},\n\t\t\t\twantN:    0,\n\t\t\t\twantErr:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"reading from the end of a file should fail with EOF\",\n\t\t\t\tinto: make([]byte, 10),\n\t\t\t\t// Note that the offset is larger than the file size\n\t\t\t\tfileData: []byte(\"hello\"),\n\t\t\t\toffset:   5,\n\t\t\t\twantInto: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},\n\t\t\t\twantN:    0,\n\t\t\t\twantErr:  true,\n\t\t\t},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tf := &file{\n\t\t\t\t\tpath: \"\",\n\t\t\t\t\tdata: tc.fileData,\n\t\t\t\t}\n\t\t\t\tf.offset.Store(tc.offset)\n\n\t\t\t\tgotN, gotErr := f.Read(tc.into)\n\n\t\t\t\tif gotN != tc.wantN || (gotErr != nil) != tc.wantErr {\n\t\t\t\t\tt.Errorf(\"Read() = %d, %v, want %d, %v\", gotN, gotErr, tc.wantN, tc.wantErr)\n\t\t\t\t}\n\n\t\t\t\tif !bytes.Equal(tc.into, tc.wantInto) {\n\t\t\t\t\tt.Errorf(\"Read() into = %v, want %v\", tc.into, tc.wantInto)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"seek\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttype args struct {\n\t\t\toffset int64\n\t\t\twhence SeekMode\n\t\t}\n\n\t\t// The test file is 100 bytes long\n\t\ttests := []struct {\n\t\t\tname       string\n\t\t\tfileOffset int64\n\t\t\targs       args\n\t\t\twantOffset int64\n\t\t\twantError  bool\n\t\t}{\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeStart within file bounds should succeed\",\n\t\t\t\tfileOffset: 0,\n\t\t\t\targs:       args{50, SeekModeStart},\n\t\t\t\twantOffset: 50,\n\t\t\t\twantError:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeStart beyond file boundaries should fail\",\n\t\t\t\tfileOffset: 0,\n\t\t\t\targs:       args{150, SeekModeStart},\n\t\t\t\twantOffset: 0,\n\t\t\t\twantError:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeStart and a negative offset should fail\",\n\t\t\t\tfileOffset: 0,\n\t\t\t\targs:       args{-50, SeekModeStart},\n\t\t\t\twantOffset: 0,\n\t\t\t\twantError:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeCurrent within file bounds at offset 0 should succeed\",\n\t\t\t\tfileOffset: 0,\n\t\t\t\targs:       args{10, SeekModeCurrent},\n\t\t\t\twantOffset: 10,\n\t\t\t\twantError:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeCurrent within file bounds at non-zero offset should succeed\",\n\t\t\t\tfileOffset: 20,\n\t\t\t\targs:       args{10, SeekModeCurrent},\n\t\t\t\twantOffset: 30,\n\t\t\t\twantError:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeCurrent beyond file boundaries should fail\",\n\t\t\t\tfileOffset: 20,\n\t\t\t\targs:       args{100, SeekModeCurrent},\n\t\t\t\twantOffset: 20,\n\t\t\t\twantError:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeCurrent and a negative offset should succeed\",\n\t\t\t\tfileOffset: 20,\n\t\t\t\targs:       args{-10, SeekModeCurrent},\n\t\t\t\twantOffset: 10,\n\t\t\t\twantError:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeCurrent and an out of bound negative offset should fail\",\n\t\t\t\tfileOffset: 20,\n\t\t\t\targs:       args{-40, SeekModeCurrent},\n\t\t\t\twantOffset: 20,\n\t\t\t\twantError:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeEnd within file bounds should succeed\",\n\t\t\t\tfileOffset: 20,\n\t\t\t\targs:       args{-20, SeekModeEnd},\n\t\t\t\twantOffset: 79,\n\t\t\t\twantError:  false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeEnd beyond file start should fail\",\n\t\t\t\tfileOffset: 20,\n\t\t\t\targs:       args{-110, SeekModeEnd},\n\t\t\t\twantOffset: 19,\n\t\t\t\twantError:  true, // File is 100 bytes long\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek using SeekModeEnd and a positive offset should fail\",\n\t\t\t\tfileOffset: 20,\n\t\t\t\targs:       args{10, SeekModeEnd},\n\t\t\t\twantOffset: 19,\n\t\t\t\twantError:  true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"seek with invalid whence should fail\",\n\t\t\t\tfileOffset: 0,\n\t\t\t\targs:       args{10, SeekMode(42)},\n\t\t\t\twantOffset: 0,\n\t\t\t\twantError:  true,\n\t\t\t},\n\t\t}\n\n\t\tfor _, tt := range tests {\n\t\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tf := &file{data: make([]byte, 100)}\n\t\t\t\tf.offset.Store(tt.fileOffset)\n\n\t\t\t\tgot, err := f.Seek(tt.args.offset, tt.args.whence)\n\t\t\t\tif tt.wantError {\n\t\t\t\t\tassert.Error(t, err, tt.name)\n\t\t\t\t} else {\n\t\t\t\t\tassert.NoError(t, err, tt.name)\n\t\t\t\t\tassert.Equal(t, tt.wantOffset, got, tt.name)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/module.go",
    "content": "// Package fs provides a k6 module that allows users to interact with files from the\n// local filesystem as per the [File API design document].\n//\n// [File API design document]: https://github.com/grafana/k6/blob/master/docs/design/019-file-api.md#proposed-solution\npackage fs\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/js/promises\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create instances of our\n\t// module for each VU.\n\tRootModule struct {\n\t\tcache *cache\n\t}\n\n\t// ModuleInstance represents an instance of the fs module for a single VU.\n\tModuleInstance struct {\n\t\tvu    modules.VU\n\t\tcache *cache\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// New returns a pointer to a new [RootModule] instance.\nfunc New() *RootModule {\n\treturn &RootModule{\n\t\tcache: &cache{},\n\t}\n}\n\n// NewModuleInstance implements the modules.Module interface and returns a new\n// instance of our module for the given VU.\nfunc (rm *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &ModuleInstance{vu: vu, cache: rm.cache}\n}\n\n// Exports implements the modules.Module interface and returns the exports of\n// our module.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"open\": mi.Open,\n\t\t\t\"SeekMode\": map[string]any{\n\t\t\t\t\"Start\":   SeekModeStart,\n\t\t\t\t\"Current\": SeekModeCurrent,\n\t\t\t\t\"End\":     SeekModeEnd,\n\t\t\t},\n\t\t},\n\t}\n}\n\n// Open opens a file and returns a promise that will resolve to a [File] instance\nfunc (mi *ModuleInstance) Open(path sobek.Value) *sobek.Promise {\n\tpromise, resolve, reject := promises.New(mi.vu)\n\n\tif mi.vu.State() != nil {\n\t\treject(newFsError(ForbiddenError, \"open() failed; reason: opening a file is allowed only in the Init context\"))\n\t\treturn promise\n\t}\n\n\tif common.IsNullish(path) {\n\t\treject(newFsError(TypeError, \"open() failed; reason: path cannot be null or undefined\"))\n\t\treturn promise\n\t}\n\n\t// Obtain the underlying path string from the JS value.\n\tpathStr := path.String()\n\tif pathStr == \"\" {\n\t\treject(newFsError(TypeError, \"open() failed; reason: path cannot be empty\"))\n\t\treturn promise\n\t}\n\n\tgo func() {\n\t\tfile, err := mi.openImpl(pathStr)\n\t\tif err != nil {\n\t\t\treject(err)\n\t\t\treturn\n\t\t}\n\n\t\tresolve(file)\n\t}()\n\n\treturn promise\n}\n\nfunc (mi *ModuleInstance) openImpl(path string) (*File, error) {\n\tinitEnv := mi.vu.InitEnv()\n\t// Strip file scheme if available as we should support only this scheme\n\tpath = strings.TrimPrefix(path, \"file://\")\n\n\t// We resolve the path relative to the entrypoint script, as opposed to\n\t// the current working directory (the k6 command is called from).\n\t//\n\t// This is done on purpose, although it diverges in some respect with\n\t// how files are handled in different k6 contexts, so that we cater to\n\t// and intuitive user experience.\n\t//\n\t// See #2781 and #2674.\n\tpath = fsext.Abs(initEnv.CWD.Path, path)\n\n\tfs, ok := initEnv.FileSystems[\"file\"]\n\tif !ok {\n\t\treturn nil, errors.New(\"open() failed; reason: unable to access the file system\")\n\t}\n\n\tif exists, err := fsext.Exists(fs, path); err != nil {\n\t\treturn nil, fmt.Errorf(\"open() failed, unable to verify if %q exists; reason: %w\", path, err)\n\t} else if !exists {\n\t\treturn nil, newFsError(NotFoundError, fmt.Sprintf(\"no such file or directory %q\", path))\n\t}\n\n\tif isDir, err := fsext.IsDir(fs, path); err != nil {\n\t\treturn nil, fmt.Errorf(\"open() failed, unable to verify if %q is a directory; reason: %w\", path, err)\n\t} else if isDir {\n\t\treturn nil, newFsError(\n\t\t\tInvalidResourceError,\n\t\t\tfmt.Sprintf(\"cannot open %q: opening a directory is not supported\", path),\n\t\t)\n\t}\n\n\tdata, err := mi.cache.open(path, fs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfile := &File{\n\t\tPath: path,\n\t\tReadSeekStater: &file{\n\t\t\tpath: path,\n\t\t\tdata: data,\n\t\t},\n\t\tvu:    mi.vu,\n\t\tcache: mi.cache,\n\t}\n\n\treturn file, nil\n}\n\n// Stater is an interface that provides information about a file.\n//\n// Although in the context of this module we have a single implementation\n// of this interface, it is defined to allow exposing the `file`'s behavior\n// to other module through the `ReadSeekStater` interface without having to\n// leak our internal abstraction.\ntype Stater interface {\n\t// Stat returns a FileInfo describing the named file.\n\tStat() *FileInfo\n}\n\n// ReadSeekStater is an interface that combines the io.ReadSeeker and Stater\n// interfaces and ensure that structs implementing it have the necessary\n// methods to interact with files.\ntype ReadSeekStater interface {\n\tio.Reader\n\tio.Seeker\n\tStater\n}\n\n// File represents a file and exposes methods to interact with it.\n//\n// It is a wrapper around the [file] struct, which is meant to be directly\n// exposed to the JS runtime.\ntype File struct {\n\t// Path holds the name of the file, as presented to [Open].\n\tPath string `json:\"path\"`\n\n\t// ReadSeekStater contains the actual implementation of the file logic, and\n\t// interacts with the underlying file system.\n\t//\n\t// Note that we explicitly omit exposing this to JS to avoid leaking\n\t// implementation details, but keep it public so that we can access it\n\t// from other modules that would want to leverage its implementation of\n\t// io.Reader and io.Seeker.\n\tReadSeekStater ReadSeekStater `js:\"-\"`\n\n\t// vu holds a reference to the VU this file is associated with.\n\t//\n\t// We need this to be able to access the VU's runtime, and produce\n\t// promises that are handled by the VU's runtime.\n\tvu modules.VU\n\n\t// cache holds a pointer to the file cache this file is associated\n\t// with. That way we are able to close the file when it's not needed\n\t// anymore.\n\tcache *cache\n}\n\n// Stat returns a promise that will resolve to a [FileInfo] instance describing\n// the file.\nfunc (f *File) Stat() *sobek.Promise {\n\tpromise, resolve, _ := promises.New(f.vu)\n\n\tgo func() {\n\t\tresolve(f.ReadSeekStater.Stat())\n\t}()\n\n\treturn promise\n}\n\n// Read the file's content, and writes it into the provided Uint8Array.\n//\n// Resolves to either the number of bytes read during the operation\n// or EOF (null) if there was nothing more to read.\n//\n// It is possible for a read to successfully return with 0 bytes.\n// This does not indicate EOF.\nfunc (f *File) Read(into sobek.Value) (*sobek.Promise, error) {\n\tpromise, resolve, reject := f.vu.Runtime().NewPromise()\n\n\tif common.IsNullish(into) {\n\t\terr := reject(newFsError(TypeError, \"read() failed; reason: into argument cannot be null or undefined\"))\n\t\treturn promise, err\n\t}\n\n\tintoObj := into.ToObject(f.vu.Runtime())\n\tif !isUint8Array(f.vu.Runtime(), intoObj) {\n\t\terr := reject(newFsError(TypeError, \"read() failed; reason: into argument must be a Uint8Array\"))\n\t\treturn promise, err\n\t}\n\n\t// Obtain the underlying ArrayBuffer from the Uint8Array\n\tab, ok := intoObj.Get(\"buffer\").Export().(sobek.ArrayBuffer)\n\tif !ok {\n\t\terr := reject(newFsError(TypeError, \"read() failed; reason: into argument must be a Uint8Array\"))\n\t\treturn promise, err\n\t}\n\n\t// To avoid concurrency linked to modifying the runtime's `into` buffer from multiple\n\t// goroutines we make sure to work on a separate copy, and will copy the bytes back\n\t// into the runtime's `into` buffer once the promise is resolved.\n\tintoBytes := ab.Bytes()\n\tbuffer := make([]byte, len(intoBytes))\n\n\t// We register a callback to be executed by the VU's runtime.\n\t// This ensures that the modification of the JS runtime's `into` buffer\n\t// occurs on the main thread, during the promise's resolution.\n\tcallback := f.vu.RegisterCallback()\n\tgo func() {\n\t\tn, readErr := f.ReadSeekStater.Read(buffer)\n\t\tcallback(func() error {\n\t\t\t_ = copy(intoBytes[0:n], buffer)\n\n\t\t\t// Read was successful, resolve early with the number of\n\t\t\t// bytes read.\n\t\t\tif readErr == nil {\n\t\t\t\treturn resolve(n)\n\t\t\t}\n\n\t\t\t// If the read operation failed, we need to check if it was an io.EOF error\n\t\t\t// and match it to its fsError counterpart if that's the case.\n\t\t\tif errors.Is(readErr, io.EOF) {\n\t\t\t\treadErr = newFsError(EOFError, \"read() failed; reason: EOF\")\n\t\t\t}\n\n\t\t\tvar fsErr *fsError\n\t\t\tisFSErr := errors.As(readErr, &fsErr)\n\t\t\tif !isFSErr {\n\t\t\t\treturn reject(readErr)\n\t\t\t}\n\n\t\t\tif fsErr.kind == EOFError && n == 0 {\n\t\t\t\treturn resolve(sobek.Null())\n\t\t\t}\n\t\t\treturn resolve(n)\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// Seek seeks to the given `offset` in the file, under the given `whence` mode.\n//\n// The returned promise resolves to the new `offset` (position) within the file, which\n// is expressed in bytes from the selected start, current, or end position depending\n// the provided `whence`.\nfunc (f *File) Seek(offset sobek.Value, whence sobek.Value) (*sobek.Promise, error) {\n\tpromise, resolve, reject := f.vu.Runtime().NewPromise()\n\n\tintOffset, err := exportInt(offset)\n\tif err != nil {\n\t\terr := reject(newFsError(TypeError, \"seek() failed; reason: the offset argument \"+err.Error()))\n\t\treturn promise, err\n\t}\n\n\tintWhence, err := exportInt(whence)\n\tif err != nil {\n\t\terr := reject(newFsError(TypeError, \"seek() failed; reason: the whence argument \"+err.Error()))\n\t\treturn promise, err\n\t}\n\n\tseekMode := SeekMode(intWhence)\n\tswitch seekMode {\n\tcase SeekModeStart, SeekModeCurrent, SeekModeEnd:\n\t\t// Valid modes, do nothing.\n\tdefault:\n\t\terr := reject(newFsError(TypeError, \"seek() failed; reason: the whence argument must be a SeekMode\"))\n\t\treturn promise, err\n\t}\n\n\tcallback := f.vu.RegisterCallback()\n\tgo func() {\n\t\tnewOffset, err := f.ReadSeekStater.Seek(intOffset, seekMode)\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(newOffset)\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\nfunc isUint8Array(rt *sobek.Runtime, o *sobek.Object) bool {\n\tuint8ArrayConstructor := rt.Get(\"Uint8Array\")\n\tif isUint8Array := o.Get(\"constructor\").SameAs(uint8ArrayConstructor); !isUint8Array {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc exportInt(v sobek.Value) (int64, error) {\n\tif common.IsNullish(v) {\n\t\treturn 0, errors.New(\"cannot be null or undefined\")\n\t}\n\n\t// We initially tried using `ExportTo` with a int64 value argument, however\n\t// this led to a string passed as argument not being an error.\n\t// Thus, we explicitly check that the value is a number, by comparing\n\t// its export type to the type of an int64.\n\tif v.ExportType().Kind() != reflect.Int64 {\n\t\treturn 0, errors.New(\"must be a number\")\n\t}\n\n\treturn v.ToInteger(), nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/fs/module_test.go",
    "content": "package fs\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/js/compiler\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst testFileName = \"bonjour.txt\"\n\nfunc TestOpen(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"opening existing file should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttests := []struct {\n\t\t\tname     string\n\t\t\topenPath string\n\t\t\twantPath string\n\t\t}{\n\t\t\t{\n\t\t\t\tname:     \"open absolute path\",\n\t\t\t\topenPath: fsext.FilePathSeparator + testFileName,\n\t\t\t\twantPath: fsext.FilePathSeparator + testFileName,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"open file absolute path\",\n\t\t\t\topenPath: \"file://\" + fsext.FilePathSeparator + testFileName,\n\t\t\t\twantPath: fsext.FilePathSeparator + testFileName,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"open relative path\",\n\t\t\t\topenPath: filepath.Join(\".\", fsext.FilePathSeparator, testFileName),\n\t\t\t\twantPath: fsext.FilePathSeparator + testFileName,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:     \"open path with ..\",\n\t\t\t\topenPath: fsext.FilePathSeparator + \"dir\" + fsext.FilePathSeparator + \"..\" + fsext.FilePathSeparator + testFileName,\n\t\t\t\twantPath: fsext.FilePathSeparator + testFileName,\n\t\t\t},\n\t\t}\n\n\t\tfor _, tt := range tests {\n\t\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\truntime, err := newConfiguredRuntime(t)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\t\t\tfileErr := fsext.WriteFile(fs, tt.wantPath, []byte(\"Bonjour, le monde\"), 0o644)\n\t\t\t\t\tif fileErr != nil {\n\t\t\t\t\t\treturn fileErr\n\t\t\t\t\t}\n\n\t\t\t\t\treturn fs.Mkdir(fsext.FilePathSeparator+\"dir\", 0o644)\n\t\t\t\t})\n\t\t\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\t\t\t\truntime.VU.InitEnvField.CWD = &url.URL{Scheme: \"file\", Path: fsext.FilePathSeparator}\n\n\t\t\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\t\t\tlet file;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfile = await fs.open(%q)\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tthrow \"unexpected error: \" + err\n\t\t\t\t\t}\n\n\t\t\t\t\tif (file.path !== %q) {\n\t\t\t\t\t\tthrow 'unexpected file path ' + file.path + '; expected %q';\n\t\t\t\t\t}\n\t\t\t\t`, tt.openPath, tt.wantPath, tt.wantPath)))\n\n\t\t\t\tassert.NoError(t, err)\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"opening file in VU context should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\truntime.MoveToVUContext(&lib.State{\n\t\t\tTags: lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"tag-vu\", \"mytag\")),\n\t\t})\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(`\n\t\t\ttry {\n\t\t\t\tconst file = await fs.open('bonjour.txt')\n\t\t\t\tthrow 'unexpected promise resolution with result: ' + file;\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'ForbiddenError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err\n\t\t\t\t}\n\t\t\t}\n\n\t\t`))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"calling open without providing a path should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(`\n\t\tlet file;\n\n\t\ttry {\n\t\t\tfile = await fs.open()\n\t\t\tthrow 'unexpected promise resolution with result: ' + file;\n\t\t} catch (err) {\n\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\tthrow 'unexpected error: ' + err\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tfile = await fs.open(null)\n\t\t\tthrow 'unexpected promise resolution with result: ' + file;\n\t\t} catch (err) {\n\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\tthrow 'unexpected error: ' + err\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tfile = await fs.open(undefined)\n\t\t\tthrow 'unexpected promise resolution with result: ' + file;\n\t\t} catch (err) {\n\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\tthrow 'unexpected error: ' + err\n\t\t\t}\n\t\t}\n\t\t`))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"opening directory should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestDirPath := fsext.FilePathSeparator + \"dir\"\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fs.Mkdir(testDirPath, 0o644)\n\t\t})\n\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\ttry {\n\t\t\t\tconst file = await fs.open(%q)\n\t\t\t\tthrow 'unexpected promise resolution with result: ' + res\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'InvalidResourceError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err\n\t\t\t\t}\n\t\t\t}\n\t\t`, testDirPath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"opening non existing file should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(`\n\t\t\ttry {\n\t\t\t\tconst file = await fs.open('doesnotexist.txt')\n\t\t\t\tthrow 'unexpected promise resolution with result: ' + res\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'NotFoundError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err\n\t\t\t\t}\n\t\t\t}\n\t\t`))\n\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestFile(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Stat method should succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"Bonjour, le monde\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q)\n\t\t\tconst info = await file.stat()\n\n\t\t\tif (info.name !== 'bonjour.txt') {\n\t\t\t\tthrow 'unexpected file name ' + info.name + '; expected \\'bonjour.txt\\'';\n\t\t\t}\n\n\t\t\tif (info.size !== 17) {\n\t\t\t\tthrow 'unexpected file size ' + info.size + '; expected 17';\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"read in multiple iterations\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"01234\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\n\t\t\tlet fileContent = new Uint8Array(5);\n\n\t\t\tlet bytesRead;\n\t\t\tlet buffer = new Uint8Array(3);\n\n\t\t\tbytesRead = await file.read(buffer)\n\t\t\tif (bytesRead !== 3) {\n\t\t\t\tthrow 'expected read to return 3, got ' + bytesRead + ' instead';\n\t\t\t}\n\n\t\t\t// We expect the buffer to be filled with the three first\n\t\t\t// bytes of the file.\n\t\t\tif (buffer[0] !== 48 || buffer[1] !== 49 || buffer[2] !== 50) {\n\t\t\t\tthrow 'expected buffer to be [48, 49, 50], got ' + buffer + ' instead';\n\t\t\t}\n\n\t\t\tfileContent.set(buffer, 0);\n\n\t\t\tbytesRead = await file.read(buffer)\n\t\t\tif (bytesRead !== 2) {\n\t\t\t\tthrow 'expected read to return 2, got ' + bytesRead + ' instead';\n\t\t\t}\n\n\t\t\t// We expect the buffer to hold the two last bytes of the\n\t\t\t// file, and as we read only two bytes, its last\n\t\t\t// one is expected to be untouched from the previous read.\n\t\t\tif (buffer[0] !== 51 || buffer[1] !== 52 || buffer[2] !== 50) {\n\t\t\t\tthrow 'expected buffer to be [51, 52, 50], got ' + buffer + ' instead';\n\t\t\t}\n\n\t\t\tfileContent.set(buffer.subarray(0, bytesRead), 3);\n\n\t\t\tbytesRead = await file.read(buffer)\n\t\t\tif (bytesRead !== null) {\n\t\t\t\tthrow 'expected read to return null, got ' + bytesRead + ' instead';\n\t\t\t}\n\n\t\t\t// We expect the buffer to be untouched.\n\t\t\tif (buffer[0] !== 51 || buffer[1] !== 52 || buffer[2] !== 50) {\n\t\t\t\tthrow 'expected buffer to be [51, 52, 50], got ' + buffer + ' instead';\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"read called when end of file reached should return null and succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"012\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tlet buffer = new Uint8Array(3);\n\n\t\t\t// Reading the whole file should return 3.\n\t\t\tlet bytesRead = await file.read(buffer);\n\t\t\tif (bytesRead !== 3) {\n\t\t\t\tthrow 'expected read to return 3, got ' + bytesRead + ' instead';\n\t\t\t}\n\n\t\t\t// Reading from the end of the file should return null and\n\t\t\t// leave the buffer untouched.\n\t\t\tbytesRead = await file.read(buffer);\n\t\t\tif (bytesRead !== null) {\n\t\t\t\tthrow 'expected read to return null got ' + bytesRead + ' instead';\n\t\t\t}\n\n\t\t\tif (buffer[0] !== 48 || buffer[1] !== 49 || buffer[2] !== 50) {\n\t\t\t\tthrow 'expected buffer to be [48, 49, 50], got ' + buffer + ' instead';\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"read called with invalid argument should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"Bonjour, le monde\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q);\n\t\t\tlet bytesRead;\n\n\t\t\t// No argument should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tbytesRead = await file.read()\n\t\t\t} catch(err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// null buffer argument should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tbytesRead = await file.read(null)\n\t\t\t} catch(err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// undefined buffer argument should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tbytesRead = await file.read(undefined)\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Invalid typed array argument should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tbytesRead = await file.read(new Int32Array(5))\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// ArrayBuffer argument should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tbytesRead = await file.read(new ArrayBuffer(5))\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow 'unexpected error: ' + err;\n\t\t\t\t}\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\t// Regression test for [#3309]\n\t//\n\t// [#3309]: https://github.com/grafana/k6/pull/3309#discussion_r1378528010\n\tt.Run(\"read with a buffer of the size of the file + 1 should succeed \", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"012\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\t// file size is 3\n\t\t\tconst file = await fs.open(%q);\n\n\t\t\t// Create a buffer of size fileSize + 1\n\t\t\tlet buffer = new Uint8Array(4);\n\t\t\tlet n = await file.read(buffer)\n\t\t\tif (n !== 3) {\n\t\t\t\tthrow 'expected read to return 10, got ' + n + ' instead';\n\t\t\t}\n\n\t\t\tif (buffer[0] !== 48 || buffer[1] !== 49 || buffer[2] !== 50) {\n\t\t\t\tthrow 'expected buffer to be [48, 49, 50], got ' + buffer + ' instead';\n\t\t\t}\n\n\t\t\tif (buffer[3] !== 0) {\n\t\t\t\tthrow 'expected buffer to be [48, 49, 50, 0], got ' + buffer + ' instead';\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"read called concurrently and later resolved should safely modify the buffer read into\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"012\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tlet file = await fs.open(%q);\n\n\t\t\tlet buffer = new Uint8Array(4)\n\t\t\tlet p1 = file.read(buffer);\n\t\t\tlet p2 = file.read(buffer);\n\n\t\t\tawait Promise.all([p1, p2]);\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"read shouldn't be affected by buffer changes happening before resolution\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"012\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tlet file = await fs.open(%q);\n\n\t\t\tlet buffer = new Uint8Array(5);\n\t\t\tlet p1 = file.read(buffer);\n\t\t\tbuffer[0] = 3;\n\n\t\t\tconst bufferCopy = buffer;\n\n\t\t\tawait p1;\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"seek\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"012\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q)\n\n\t\t\tlet newOffset = await file.seek(1, fs.SeekMode.Start)\n\n\t\t\tif (newOffset != 1) {\n\t\t\t\tthrow \"file.seek(1, fs.SeekMode.Start) returned unexpected offset: \" + newOffset;\n\t\t\t}\n\n\t\t\tnewOffset = await file.seek(-1, fs.SeekMode.Current)\n\t\t\tif (newOffset != 0) {\n\t\t\t\tthrow \"file.seek(-1, fs.SeekMode.Current) returned unexpected offset: \" + newOffset;\n\t\t\t}\n\n\t\t\tnewOffset = await file.seek(0, fs.SeekMode.End)\n\t\t\tif (newOffset != 2) {\n\t\t\t\tthrow \"file.seek(0, fs.SeekMode.End) returned unexpected offset: \" + newOffset;\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"seek with invalid arguments should fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\ttestFilePath := fsext.FilePathSeparator + testFileName\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, testFilePath, []byte(\"hello\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\t_, err = runtime.RunOnEventLoop(wrapInAsyncLambda(fmt.Sprintf(`\n\t\t\tconst file = await fs.open(%q)\n\n\t\t\tlet newOffset\n\n\t\t\t// null offset should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tnewOffset = await file.seek(null)\n\t\t\t\tthrow \"file.seek(null) promise unexpectedly resolved with result: \" + newOffset\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow \"file.seek(null) rejected with unexpected error: \" + err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// undefined offset should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tnewOffset = await file.seek(undefined)\n\t\t\t\tthrow \"file.seek(undefined) promise unexpectedly promise resolved with result: \" + newOffset\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow \"file.seek(undefined) rejected with unexpected error: \" + err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Invalid type offset should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tnewOffset = await file.seek('abc')\n\t\t\t\tthrow \"file.seek('abc') promise unexpectedly resolved with result: \" + newOffset\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow \"file.seek('1') rejected with unexpected error: \" + err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Negative offset should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tnewOffset = await file.seek(-1)\n\t\t\t\tthrow \"file.seek(-1) promise unexpectedly resolved with result: \" + newOffset\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow \"file.seek(-1) rejected with unexpected error: \" + err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Invalid type whence should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tnewOffset = await file.seek(1, 'abc')\n\t\t\t\tthrow \"file.seek(1, 'abc') promise unexpectedly resolved with result: \" + newOffset\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow \"file.seek(1, 'abc') rejected with unexpected error: \" + err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Invalid whence should fail with TypeError.\n\t\t\ttry {\n\t\t\t\tnewOffset = await file.seek(1, -1)\n\t\t\t\tthrow \"file.seek(1, -1) promise unexpectedly resolved with result: \" + newOffset\n\t\t\t} catch (err) {\n\t\t\t\tif (err.name !== 'TypeError') {\n\t\t\t\t\tthrow \"file.seek(1, -1) rejected with unexpected error: \" + err\n\t\t\t\t}\n\t\t\t}\n\t\t`, testFilePath)))\n\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestOpenImpl(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"should panic if the file system is not available\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\t\tdelete(runtime.VU.InitEnvField.FileSystems, \"file\")\n\n\t\tmi := &ModuleInstance{\n\t\t\tvu:    runtime.VU,\n\t\t\tcache: &cache{},\n\t\t}\n\n\t\tf, gotErr := mi.openImpl(testFileName)\n\n\t\tassert.Error(t, gotErr)\n\t\tassert.Nil(t, f)\n\t})\n\n\tt.Run(\"should return an error if the file does not exist\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\tmi := &ModuleInstance{\n\t\t\tvu:    runtime.VU,\n\t\t\tcache: &cache{},\n\t\t}\n\n\t\t_, err = mi.openImpl(testFileName)\n\t\tassert.Error(t, err)\n\t\tvar fsError *fsError\n\t\tassert.ErrorAs(t, err, &fsError)\n\t\tassert.Equal(t, NotFoundError, fsError.kind)\n\t})\n\n\tt.Run(\"should return an error if the path is a directory\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fs.Mkdir(\"/dir\", 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\n\t\tmi := &ModuleInstance{\n\t\t\tvu:    runtime.VU,\n\t\t\tcache: &cache{},\n\t\t}\n\n\t\t_, err = mi.openImpl(\"/dir\")\n\t\tassert.Error(t, err)\n\t\tvar fsError *fsError\n\t\tassert.ErrorAs(t, err, &fsError)\n\t\tassert.Equal(t, InvalidResourceError, fsError.kind)\n\t})\n\n\tt.Run(\"path is resolved relative to the entrypoint script\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime, err := newConfiguredRuntime(t)\n\t\trequire.NoError(t, err)\n\n\t\tfs := newTestFs(t, func(fs fsext.Fs) error {\n\t\t\treturn fsext.WriteFile(fs, \"/bonjour.txt\", []byte(\"Bonjour, le monde\"), 0o644)\n\t\t})\n\t\truntime.VU.InitEnvField.FileSystems[\"file\"] = fs\n\t\truntime.VU.InitEnvField.CWD = &url.URL{Scheme: \"file\", Path: \"/dir\"}\n\n\t\tmi := &ModuleInstance{\n\t\t\tvu:    runtime.VU,\n\t\t\tcache: &cache{},\n\t\t}\n\n\t\t_, err = mi.openImpl(\"../bonjour.txt\")\n\t\tassert.NoError(t, err)\n\t})\n}\n\nconst initGlobals = `\n\tglobalThis.fs = require(\"k6/experimental/fs\");\n`\n\nfunc newConfiguredRuntime(t testing.TB) (*modulestest.Runtime, error) {\n\truntime := modulestest.NewRuntime(t)\n\n\terr := runtime.SetupModuleSystem(map[string]any{\"k6/experimental/fs\": New()}, nil, compiler.New(runtime.VU.InitEnv().Logger))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Set up the VU environment with an in-memory filesystem and a CWD of \"/\".\n\truntime.VU.InitEnvField.FileSystems = map[string]fsext.Fs{\n\t\t\"file\": fsext.NewMemMapFs(),\n\t}\n\truntime.VU.InitEnvField.CWD = &url.URL{Scheme: \"file\"}\n\n\t// Ensure the `fs` module is available in the VU's runtime.\n\t_, err = runtime.VU.Runtime().RunString(initGlobals)\n\n\treturn runtime, err\n}\n\n// newTestFs is a helper function that creates a new in-memory file system and calls the provided\n// function with it. The provided function is expected to use the file system to create files and\n// directories.\nfunc newTestFs(t *testing.T, fn func(fs fsext.Fs) error) fsext.Fs {\n\tt.Helper()\n\n\tfs := fsext.NewMemMapFs()\n\n\terr := fn(fs)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\treturn fs\n}\n\n// wrapInAsyncLambda is a helper function that wraps the provided input in an async lambda. This\n// makes the use of `await` statements in the input possible.\nfunc wrapInAsyncLambda(input string) string {\n\t// This makes it possible to use `await` freely on the \"top\" level\n\treturn \"(async () => {\\n \" + input + \"\\n })()\"\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/errors.go",
    "content": "package streams\n\nimport \"github.com/grafana/sobek\"\n\nfunc newTypeError(rt *sobek.Runtime, message string) *jsError {\n\treturn newJsError(rt, rt.Get(\"TypeError\"), TypeError, message)\n}\n\nfunc newRangeError(rt *sobek.Runtime, message string) *jsError {\n\treturn newJsError(rt, rt.Get(\"RangeError\"), RangeError, message)\n}\n\nfunc newJsError(rt *sobek.Runtime, base sobek.Value, kind errorKind, message string) *jsError {\n\tconstructor, ok := sobek.AssertConstructor(base)\n\tif !ok {\n\t\tthrow(rt, newError(kind, message))\n\t}\n\n\te, err := constructor(nil, rt.ToValue(message))\n\tif err != nil {\n\t\tthrow(rt, newError(kind, message))\n\t}\n\n\treturn &jsError{err: e, msg: message}\n}\n\n// jsError is a wrapper around a JS error object.\n//\n// We need to use it because whenever we need to return a [TypeError]\n// or a [RangeError], we want to use original JS errors, which can be\n// retrieved from Sobek, for instance with: sobek.Runtime.Get(\"TypeError\").\n//\n// However, that is implemented as a [*sobek.Object], but sometimes we\n// need to return that error as a Go [error], or even keep the instance\n// in memory to be returned/thrown later.\n//\n// So, we use this wrapper instead of returning the original JS error.\n// Otherwise, we would need to replace everything typed as [error] with\n// [any] to be compatible, and that would be a mess.\ntype jsError struct {\n\terr *sobek.Object\n\tmsg string\n}\n\nfunc (e *jsError) Error() string {\n\treturn e.msg\n}\n\nfunc (e *jsError) Err() *sobek.Object {\n\treturn e.err\n}\n\nfunc newError(k errorKind, message string) *streamError {\n\treturn &streamError{\n\t\tName:    k.String(),\n\t\tMessage: message,\n\t\tkind:    k,\n\t}\n}\n\n//go:generate enumer -type=errorKind -output errors_gen.go\ntype errorKind uint8\n\nconst (\n\t// TypeError is thrown when an argument is not of an expected type\n\tTypeError errorKind = iota + 1\n\n\t// RangeError is thrown when an argument is not within the expected range\n\tRangeError\n\n\t// RuntimeError is thrown when an error occurs that was caused by the JS runtime\n\t// and is not likely caused by the user, but rather the implementation.\n\tRuntimeError\n\n\t// AssertionError is thrown when an assertion fails\n\tAssertionError\n\n\t// NotSupportedError is thrown when a feature is not supported, or not yet implemented\n\tNotSupportedError\n)\n\ntype streamError struct {\n\t// Name contains the name of the error\n\tName string `json:\"name\"`\n\n\t// Message contains the error message\n\tMessage string `json:\"message\"`\n\n\t// kind contains the kind of error\n\tkind errorKind\n}\n\n// Ensure that the fsError type implements the Go `error` interface\nvar _ error = (*streamError)(nil)\n\nfunc (e *streamError) Error() string {\n\treturn e.Name + \":\" + e.Message\n}\n\nfunc throw(rt *sobek.Runtime, err any) {\n\tif e, ok := err.(*jsError); ok {\n\t\tpanic(e.Err())\n\t}\n\n\tpanic(errToObj(rt, err))\n}\n\nfunc errToObj(rt *sobek.Runtime, err any) sobek.Value {\n\t// Undefined remains undefined.\n\tif sobek.IsUndefined(rt.ToValue(err)) {\n\t\treturn rt.ToValue(err)\n\t}\n\n\tif e, ok := err.(*sobek.Exception); ok {\n\t\treturn e.Value().ToObject(rt)\n\t}\n\n\treturn rt.ToValue(err).ToObject(rt)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/errors_gen.go",
    "content": "// Code generated by \"enumer -type=errorKind -output errors_gen.go\"; DO NOT EDIT.\n\npackage streams\n\nimport (\n\t\"fmt\"\n)\n\nconst _errorKindName = \"TypeErrorRangeErrorRuntimeErrorAssertionErrorNotSupportedError\"\n\nvar _errorKindIndex = [...]uint8{0, 9, 19, 31, 45, 62}\n\nfunc (i errorKind) String() string {\n\ti -= 1\n\tif i >= errorKind(len(_errorKindIndex)-1) {\n\t\treturn fmt.Sprintf(\"errorKind(%d)\", i+1)\n\t}\n\treturn _errorKindName[_errorKindIndex[i]:_errorKindIndex[i+1]]\n}\n\nvar _errorKindValues = []errorKind{1, 2, 3, 4, 5}\n\nvar _errorKindNameToValueMap = map[string]errorKind{\n\t_errorKindName[0:9]:   1,\n\t_errorKindName[9:19]:  2,\n\t_errorKindName[19:31]: 3,\n\t_errorKindName[31:45]: 4,\n\t_errorKindName[45:62]: 5,\n}\n\n// errorKindString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc errorKindString(s string) (errorKind, error) {\n\tif val, ok := _errorKindNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to errorKind values\", s)\n}\n\n// errorKindValues returns all values of the enum\nfunc errorKindValues() []errorKind {\n\treturn _errorKindValues\n}\n\n// IsAerrorKind returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i errorKind) IsAerrorKind() bool {\n\tfor _, v := range _errorKindValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/goja.go",
    "content": "package streams\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// newResolvedPromise instantiates a new resolved promise.\nfunc newResolvedPromise(vu modules.VU, with sobek.Value) *sobek.Promise {\n\tpromise, resolve, _ := vu.Runtime().NewPromise()\n\terr := resolve(with)\n\tif err != nil { // TODO(@mstoykov): likely better to actually call Promise.resolve directly\n\t\tpanic(err)\n\t}\n\n\treturn promise\n}\n\n// newRejectedPromise instantiates a new rejected promise.\nfunc newRejectedPromise(vu modules.VU, with any) *sobek.Promise {\n\tpromise, _, reject := vu.Runtime().NewPromise()\n\terr := reject(with)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn promise\n}\n\n// promiseThen facilitates instantiating a new promise and defining callbacks for to be executed\n// on fulfillment as well as rejection, directly from Go.\nfunc promiseThen(\n\trt *sobek.Runtime,\n\tpromise *sobek.Promise,\n\tonFulfilled, onRejected func(sobek.Value),\n) (*sobek.Promise, error) {\n\tval, err := rt.RunString(\n\t\t`(function(promise, onFulfilled, onRejected) { return promise.then(onFulfilled, onRejected) })`)\n\tif err != nil {\n\t\treturn nil, newError(RuntimeError, \"unable to initialize promiseThen internal helper function\")\n\t}\n\n\tcal, ok := sobek.AssertFunction(val)\n\tif !ok {\n\t\treturn nil, newError(RuntimeError, \"the internal promiseThen helper is not a function\")\n\t}\n\n\tif onRejected == nil {\n\t\tval, err = cal(sobek.Undefined(), rt.ToValue(promise), rt.ToValue(onFulfilled))\n\t} else {\n\t\tval, err = cal(sobek.Undefined(), rt.ToValue(promise), rt.ToValue(onFulfilled), rt.ToValue(onRejected))\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnewPromise, ok := val.Export().(*sobek.Promise)\n\tif !ok {\n\t\treturn nil, newError(RuntimeError, \"unable to cast the internal promiseThen helper's return value to a promise\")\n\t}\n\n\treturn newPromise, nil\n}\n\n// isNumber returns true if the given sobek.Value holds a number\nfunc isNumber(value sobek.Value) bool {\n\t_, isFloat := value.Export().(float64)\n\t_, isInt := value.Export().(int64)\n\n\treturn isFloat || isInt\n}\n\n// isNonNegativeNumber implements the [IsNonNegativeNumber] algorithm.\n//\n// [IsNonNegativeNumber]: https://streams.spec.whatwg.org/#is-non-negative-number\nfunc isNonNegativeNumber(value sobek.Value) bool {\n\tif common.IsNullish(value) {\n\t\treturn false\n\t}\n\n\tif !isNumber(value) {\n\t\treturn false\n\t}\n\n\tif value.ToFloat() < 0 || value.ToInteger() < 0 {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// setReadOnlyPropertyOf sets a read-only property on the given [sobek.Object].\nfunc setReadOnlyPropertyOf(obj *sobek.Object, objName, propName string, propValue sobek.Value) error {\n\terr := obj.DefineDataProperty(propName,\n\t\tpropValue,\n\t\tsobek.FLAG_FALSE,\n\t\tsobek.FLAG_FALSE,\n\t\tsobek.FLAG_TRUE,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to define %s read-only property on %s object; reason: %w\", propName, objName, err)\n\t}\n\n\treturn nil\n}\n\n// isObject determines whether the given [sobek.Value] is a [sobek.Object] or not.\nfunc isObject(val sobek.Value) bool {\n\treturn val != nil && val.ExportType() != nil && val.ExportType().Kind() == reflect.Map\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/module.go",
    "content": "// Package streams provides support for the Web Streams API.\npackage streams\n\nimport (\n\t\"errors\"\n\t\"io\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the module that will be registered with the runtime.\n\tRootModule struct{}\n\n\t// ModuleInstance is the module instance that will be created for each VU.\n\tModuleInstance struct {\n\t\tvu modules.VU\n\t}\n)\n\n// Ensure the interfaces are implemented correctly\nvar (\n\t_ modules.Instance = &ModuleInstance{}\n\t_ modules.Module   = &RootModule{}\n)\n\n// New creates a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance creates a new instance of the module for a specific VU.\nfunc (rm *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &ModuleInstance{\n\t\tvu: vu,\n\t}\n}\n\n// Exports returns the module exports, that will be available in the runtime.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{Named: map[string]any{\n\t\t\"ReadableStream\":              mi.NewReadableStream,\n\t\t\"CountQueuingStrategy\":        mi.NewCountQueuingStrategy,\n\t\t\"ReadableStreamDefaultReader\": mi.NewReadableStreamDefaultReader,\n\t}}\n}\n\n// NewReadableStream is the constructor for the ReadableStream object.\nfunc (mi *ModuleInstance) NewReadableStream(call sobek.ConstructorCall) *sobek.Object {\n\treturn newReadableStream(mi.vu, call)\n}\n\nfunc newReadableStream(vu modules.VU, call sobek.ConstructorCall) *sobek.Object {\n\tvar (\n\t\t// 1. If underlyingSource is missing, set it to null.\n\t\tunderlyingSource *sobek.Object\n\n\t\trt = vu.Runtime()\n\n\t\terr                  error\n\t\tstrategy             *sobek.Object\n\t\tunderlyingSourceDict UnderlyingSource\n\t)\n\n\t// We look for the queuing strategy first, and validate it before\n\t// the underlying source, in order to pass the Web Platform Tests\n\t// constructor tests.\n\tstrategy = initializeStrategy(rt, call)\n\n\t// 2. Let underlyingSourceDict be underlyingSource, converted to an IDL value of type UnderlyingSource.\n\tif len(call.Arguments) > 0 && !sobek.IsUndefined(call.Arguments[0]) {\n\t\t// We first assert that it is an object (requirement)\n\t\tif !isObject(call.Arguments[0]) {\n\t\t\tthrow(rt, newTypeError(rt, \"underlyingSource must be an object\"))\n\t\t}\n\n\t\t// Then we try to convert it to an UnderlyingSource\n\t\tunderlyingSource = call.Arguments[0].ToObject(rt)\n\t\tunderlyingSourceDict, err = NewUnderlyingSourceFromObject(rt, underlyingSource)\n\t\tif err != nil {\n\t\t\tthrow(rt, err)\n\t\t}\n\t}\n\n\t// 3. Perform ! InitializeReadableStream(this).\n\tstream := &ReadableStream{\n\t\truntime: rt,\n\t\tvu:      vu,\n\t}\n\tstream.initialize()\n\n\t// 4. If underlyingSourceDict[\"type\"] is \"bytes\":\n\tif underlyingSourceDict.Type == \"bytes\" {\n\t\tcommon.Throw(stream.runtime, newError(NotSupportedError, \"'bytes' stream is not supported yet\"))\n\t} else { // 5. Otherwise,\n\t\t// 5.1. Assert: underlyingSourceDict[\"type\"] does not exist.\n\t\tif underlyingSourceDict.Type != \"\" {\n\t\t\tcommon.Throw(rt, newError(AssertionError, \"type must not be set for non-byte streams\"))\n\t\t}\n\n\t\t// 5.2. Let sizeAlgorithm be ! ExtractSizeAlgorithm(strategy).\n\t\tsizeAlgorithm := extractSizeAlgorithm(rt, strategy)\n\n\t\t// 5.3. Let highWaterMark be ? ExtractHighWaterMark(strategy, 1).\n\t\thighWaterMark := extractHighWaterMark(rt, strategy, 1)\n\n\t\t// 5.4. Perform ? SetUpReadableStreamDefaultControllerFromUnderlyingSource(...).\n\t\tstream.setupReadableStreamDefaultControllerFromUnderlyingSource(\n\t\t\tunderlyingSource,\n\t\t\tunderlyingSourceDict,\n\t\t\thighWaterMark,\n\t\t\tsizeAlgorithm,\n\t\t)\n\t}\n\n\tstreamObj := rt.ToValue(stream).ToObject(rt)\n\n\tproto := call.This.Prototype()\n\tif proto.Get(\"locked\") == nil {\n\t\terr = proto.DefineAccessorProperty(\"locked\", rt.ToValue(func() sobek.Value {\n\t\t\treturn rt.ToValue(stream.Locked)\n\t\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, newError(RuntimeError, err.Error()))\n\t\t}\n\t}\n\n\terr = streamObj.SetPrototype(proto)\n\tif err != nil {\n\t\tcommon.Throw(rt, newError(RuntimeError, err.Error()))\n\t}\n\n\treturn streamObj\n}\nfunc defaultSizeFunc(_ sobek.Value) (float64, error) { return 1.0, nil }\n\nfunc initializeStrategy(rt *sobek.Runtime, call sobek.ConstructorCall) *sobek.Object {\n\t// Either if the strategy is not provided or if it doesn't have a 'highWaterMark',\n\t// we need to set its default value (highWaterMark=1).\n\t// https://streams.spec.whatwg.org/#rs-prototype\n\tstrArg := rt.NewObject()\n\tif len(call.Arguments) > 1 && !common.IsNullish(call.Arguments[1]) {\n\t\tstrArg = call.Arguments[1].ToObject(rt)\n\t}\n\tif common.IsNullish(strArg.Get(\"highWaterMark\")) {\n\t\tif err := strArg.Set(\"highWaterMark\", rt.ToValue(1)); err != nil {\n\t\t\tcommon.Throw(rt, newError(RuntimeError, err.Error()))\n\t\t}\n\t}\n\n\t// If the stream type is 'bytes', we don't want the size function.\n\t// Except, when it is manually specified.\n\tsize := rt.ToValue(defaultSizeFunc)\n\tif len(call.Arguments) > 0 && !common.IsNullish(call.Arguments[0]) {\n\t\tsrcArg := call.Arguments[0].ToObject(rt)\n\t\tsrcTypeArg := srcArg.Get(\"type\")\n\t\tif !common.IsNullish(srcTypeArg) && srcTypeArg.String() == ReadableStreamTypeBytes {\n\t\t\tsize = nil\n\t\t}\n\t}\n\tif strArg.Get(\"size\") != nil {\n\t\tsize = strArg.Get(\"size\")\n\t}\n\n\tstrCall := sobek.ConstructorCall{Arguments: []sobek.Value{strArg}}\n\treturn newCountQueuingStrategy(rt, strCall, size)\n}\n\n// NewCountQueuingStrategy is the constructor for the [CountQueuingStrategy] object.\n//\n// [CountQueuingStrategy]: https://streams.spec.whatwg.org/#cqs-class\nfunc (mi *ModuleInstance) NewCountQueuingStrategy(call sobek.ConstructorCall) *sobek.Object {\n\trt := mi.vu.Runtime()\n\t// By default, the CountQueuingStrategy has a pre-defined 'size' property.\n\t// It cannot be overwritten by the user.\n\treturn newCountQueuingStrategy(rt, call, rt.ToValue(defaultSizeFunc))\n}\n\n// newCountQueuingStrategy is the underlying constructor for the [CountQueuingStrategy] object.\n//\n// It allows to create a CountQueuingStrategy with or without the 'size' property,\n// depending on how the containing ReadableStream is initialized.\nfunc newCountQueuingStrategy(\n\trt *sobek.Runtime,\n\tcall sobek.ConstructorCall,\n\tsize sobek.Value,\n) *sobek.Object {\n\tobj := rt.NewObject()\n\tobjName := \"CountQueuingStrategy\"\n\n\tif len(call.Arguments) != 1 {\n\t\tthrow(rt, newTypeError(rt, objName+\" takes a single argument\"))\n\t}\n\n\tif !isObject(call.Argument(0)) {\n\t\tthrow(rt, newTypeError(rt, objName+\" argument must be an object\"))\n\t}\n\n\targObj := call.Argument(0).ToObject(rt)\n\tif common.IsNullish(argObj.Get(\"highWaterMark\")) {\n\t\tthrow(rt, newTypeError(rt, objName+\" argument must have 'highWaterMark' property\"))\n\t}\n\n\thighWaterMark := argObj.Get(\"highWaterMark\")\n\tif err := setReadOnlyPropertyOf(obj, objName, \"highWaterMark\", highWaterMark); err != nil {\n\t\tthrow(rt, newTypeError(rt, err.Error()))\n\t}\n\n\tif !common.IsNullish(size) {\n\t\tif err := setReadOnlyPropertyOf(obj, objName, \"size\", size); err != nil {\n\t\t\tthrow(rt, newTypeError(rt, err.Error()))\n\t\t}\n\t}\n\n\treturn obj\n}\n\n// extractHighWaterMark returns the high watermark for the given queuing strategy.\n//\n// It implements the [ExtractHighWaterMark] algorithm.\n//\n// [ExtractHighWaterMark]: https://streams.spec.whatwg.org/#validate-and-normalize-high-water-mark\nfunc extractHighWaterMark(rt *sobek.Runtime, strategy *sobek.Object, defaultHWM float64) float64 {\n\t// 1. If strategy[\"highWaterMark\"] does not exist, return defaultHWM.\n\tif common.IsNullish(strategy.Get(\"highWaterMark\")) {\n\t\treturn defaultHWM\n\t}\n\n\t// 2. Let highWaterMark be strategy[\"highWaterMark\"].\n\thighWaterMark := strategy.Get(\"highWaterMark\")\n\n\t// 3. If highWaterMark is NaN or highWaterMark < 0, throw a RangeError exception.\n\tif sobek.IsNaN(strategy.Get(\"highWaterMark\")) ||\n\t\t!isNumber(strategy.Get(\"highWaterMark\")) ||\n\t\t!isNonNegativeNumber(strategy.Get(\"highWaterMark\")) {\n\t\tthrow(rt, newRangeError(rt, \"highWaterMark must be a non-negative number\"))\n\t}\n\n\t// 4. Return highWaterMark.\n\treturn highWaterMark.ToFloat()\n}\n\n// extractSizeAlgorithm returns the size algorithm for the given queuing strategy.\n//\n// It implements the [ExtractSizeAlgorithm] algorithm.\n//\n// [ExtractSizeAlgorithm]: https://streams.spec.whatwg.org/#make-size-algorithm-from-size-function\nfunc extractSizeAlgorithm(rt *sobek.Runtime, strategy *sobek.Object) SizeAlgorithm {\n\tvar sizeFunc sobek.Callable\n\tsizeProp := strategy.Get(\"size\")\n\n\tif common.IsNullish(sizeProp) {\n\t\tsizeFunc, _ = sobek.AssertFunction(rt.ToValue(func(_ sobek.Value) (float64, error) { return 1.0, nil }))\n\t\treturn sizeFunc\n\t}\n\n\tsizeFunc, isFunc := sobek.AssertFunction(sizeProp)\n\tif !isFunc {\n\t\tthrow(rt, newTypeError(rt, \"size must be a function\"))\n\t}\n\n\treturn sizeFunc\n}\n\n// NewReadableStreamDefaultReader is the constructor for the [ReadableStreamDefaultReader] object.\n//\n// [ReadableStreamDefaultReader]: https://streams.spec.whatwg.org/#readablestreamdefaultreader\nfunc (mi *ModuleInstance) NewReadableStreamDefaultReader(call sobek.ConstructorCall) *sobek.Object {\n\trt := mi.vu.Runtime()\n\n\tif len(call.Arguments) != 1 {\n\t\tthrow(rt, newTypeError(rt, \"ReadableStreamDefaultReader takes a single argument\"))\n\t}\n\n\tstream, ok := call.Argument(0).Export().(*ReadableStream)\n\tif !ok {\n\t\tthrow(rt, newTypeError(rt, \"ReadableStreamDefaultReader argument must be a ReadableStream\"))\n\t}\n\n\t// 1. Perform ? SetUpReadableStreamDefaultReader(this, stream).\n\treader := &ReadableStreamDefaultReader{}\n\treader.setup(stream)\n\n\tobject, err := NewReadableStreamDefaultReaderObject(reader)\n\tif err != nil {\n\t\tthrow(rt, err)\n\t}\n\n\treturn object\n}\n\n// NewReadableStreamFromReader is the equivalent of [NewReadableStreamDefaultReader] but to initialize\n// a new [ReadableStream] from a given [io.Reader] in Go code.\n// It is useful for those situations when a [io.Reader] needs to be surfaced up to the JS runtime.\nfunc NewReadableStreamFromReader(vu modules.VU, reader io.Reader) *sobek.Object {\n\trt := vu.Runtime()\n\treturn newReadableStream(vu, sobek.ConstructorCall{\n\t\tArguments: []sobek.Value{rt.ToValue(underlyingSourceFromReader(vu, reader))},\n\t\tThis:      rt.NewObject(),\n\t})\n}\n\nfunc underlyingSourceFromReader(vu modules.VU, reader io.Reader) *sobek.Object {\n\trt := vu.Runtime()\n\n\tunderlyingSource := vu.Runtime().NewObject()\n\tif err := underlyingSource.Set(\"pull\", rt.ToValue(func(controller *sobek.Object) *sobek.Promise {\n\t\t// Prepare methods\n\t\tcClose, _ := sobek.AssertFunction(controller.Get(\"close\"))\n\t\tcEnqueue, _ := sobek.AssertFunction(controller.Get(\"enqueue\"))\n\n\t\tbuf := make([]byte, 1024)\n\t\tn, err := reader.Read(buf)\n\t\tif err != nil && !errors.Is(err, io.EOF) {\n\t\t\tpanic(err)\n\t\t}\n\n\t\t_, enqueueErr := cEnqueue(nil, rt.ToValue(string(buf[:n])))\n\t\tif enqueueErr != nil {\n\t\t\tpanic(enqueueErr)\n\t\t}\n\n\t\tif err == io.EOF {\n\t\t\t_, closeErr := cClose(nil)\n\t\t\tif closeErr != nil {\n\t\t\t\tpanic(closeErr)\n\t\t\t}\n\t\t}\n\n\t\treturn newResolvedPromise(vu, sobek.Undefined())\n\t})); err != nil {\n\t\tthrow(rt, err)\n\t}\n\n\treturn underlyingSource\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/module_test.go",
    "content": "package streams\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nfunc TestNewReadableStreamFromReader(t *testing.T) {\n\tt.Parallel()\n\n\t// The value to be streamed.\n\texp := \"Hello, World!\"\n\n\t// We initialize the runtime, with the ReadableStream(rs) accessible in JS.\n\tr := modulestest.NewRuntime(t)\n\trs := NewReadableStreamFromReader(r.VU, bytes.NewReader([]byte(exp)))\n\trequire.NoError(t, r.VU.Runtime().Set(\"rs\", rs))\n\n\t// Then, we run some JS code that reads from the ReadableStream(rs).\n\tvar ret sobek.Value\n\terr := r.EventLoop.Start(func() (err error) {\n\t\tret, err = r.VU.Runtime().RunString(`(async () => {\n  const reader = rs.getReader();\n  const {value} = await reader.read();\n  return value;\n})()`)\n\t\treturn err\n\t})\n\tassert.NoError(t, err)\n\n\t// Finally, we expect the returned promise to resolve\n\t// to the expected value (the one we streamed).\n\tp, ok := ret.Export().(*sobek.Promise)\n\trequire.True(t, ok)\n\tassert.Equal(t, exp, p.Result().String())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/queue.go",
    "content": "package streams\n\nimport (\n\t\"errors\"\n\t\"math\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// ValueWithSize holds a value and its corresponding size.\n//\n// It is used to store values in the queue.\ntype ValueWithSize struct {\n\tValue sobek.Value\n\tSize  float64\n}\n\n// QueueWithSizes is a queue of values with sizes.\ntype QueueWithSizes struct {\n\tQueue          []ValueWithSize\n\tQueueTotalSize float64\n\truntime        *sobek.Runtime\n}\n\n// NewQueueWithSizes creates a new queue of values with sizes, as described in the [specification].\n//\n// [specification]: https://streams.spec.whatwg.org/#queue-with-sizes\nfunc NewQueueWithSizes(runtime *sobek.Runtime) *QueueWithSizes {\n\treturn &QueueWithSizes{\n\t\tQueue:   make([]ValueWithSize, 0),\n\t\truntime: runtime,\n\t}\n}\n\n// Enqueue adds a value to the queue, and implements the specification's [EnqueueValueWithSize] abstract operation.\n//\n// [EnqueueValueWithSize]: https://streams.spec.whatwg.org/#enqueue-value-with-size\nfunc (q *QueueWithSizes) Enqueue(value sobek.Value, size float64) error {\n\tif math.IsNaN(size) || size < 0 || math.IsInf(size, 1) { // Check for +Inf\n\t\treturn newRangeError(q.runtime, \"size must be a finite, non-NaN number\")\n\t}\n\n\tvalueWithSize := ValueWithSize{\n\t\tValue: value,\n\t\tSize:  size,\n\t}\n\n\tq.Queue = append(q.Queue, valueWithSize)\n\tq.QueueTotalSize += size\n\n\treturn nil\n}\n\n// Dequeue removes and returns the first value from the queue.\n//\n// It implements the [DequeueValue] abstract operation.\n//\n// [DequeueValue]: https://streams.spec.whatwg.org/#abstract-opdef-dequeue-value\nfunc (q *QueueWithSizes) Dequeue() (sobek.Value, error) {\n\tif len(q.Queue) == 0 {\n\t\treturn nil, newError(AssertionError, \"queue is empty\")\n\t}\n\n\tvalueWithSize := q.Queue[0]\n\tq.Queue = q.Queue[1:]\n\tq.QueueTotalSize -= valueWithSize.Size\n\tif q.QueueTotalSize < 0 {\n\t\tq.QueueTotalSize = 0 // Correct for rounding errors\n\t}\n\n\treturn valueWithSize.Value, nil\n}\n\n// Peek returns the first value from the queue without removing it.\n//\n// It implements the [PeekQueueValue] abstract operation.\n//\n// [PeekQueueValue]: https://streams.spec.whatwg.org/#abstract-opdef-peek-queue-value\nfunc (q *QueueWithSizes) Peek() (sobek.Value, error) {\n\tif len(q.Queue) == 0 {\n\t\treturn nil, errors.New(\"queue is empty\")\n\t}\n\n\treturn q.Queue[0].Value, nil\n}\n\n// Reset clears the queue and resets the total size.\n//\n// It implements the [ResetQueue] abstract operation.\n//\n// [ResetQueue]: https://streams.spec.whatwg.org/#abstract-opdef-reset-queue\nfunc (q *QueueWithSizes) Reset() {\n\tq.Queue = make([]ValueWithSize, 0)\n\tq.QueueTotalSize = 0\n}\n\n// Len returns the length of the queue.\nfunc (q *QueueWithSizes) Len() int {\n\treturn len(q.Queue)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/readable_stream_controller.go",
    "content": "package streams\n\nimport \"github.com/grafana/sobek\"\n\n// ReadableStreamController is the interface implemented by all readable stream controllers.\n//\n// It defines both the specification's shared controller and private methods.\ntype ReadableStreamController interface {\n\tClose()\n\tEnqueue(chunk sobek.Value)\n\tError(err sobek.Value)\n\n\t// cancelSteps performs the controller’s steps that run in reaction to\n\t// the stream being canceled, used to clean up the state stored in the\n\t// controller and inform the underlying source.\n\tcancelSteps(reason any) *sobek.Promise\n\n\t// pullSteps performs the controller’s steps that run when a default reader\n\t// is read from, used to pull from the controller any queued chunks, or\n\t// pull from the underlying source to get more chunks.\n\tpullSteps(readRequest ReadRequest)\n\n\t// releaseSteps performs the controller’s steps that run when a reader is\n\t// released, used to clean up reader-specific resources stored in the controller.\n\treleaseSteps()\n\n\t// toObject returns a [*sobek.Object] that represents the controller.\n\ttoObject() (*sobek.Object, error)\n}\n\n// SizeAlgorithm is a function that returns the size of a chunk.\n// type SizeAlgorithm func(chunk sobek.Value) (float64, error)\ntype SizeAlgorithm = sobek.Callable\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/readable_stream_default_controller.go",
    "content": "package streams\n\nimport (\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// ReadableStreamDefaultController is the default controller for a ReadableStream. It has\n// methods to control the stream's state and internal queue.\n//\n// For more details, see the [specification].\n//\n// [specification]: https://streams.spec.whatwg.org/#rs-default-controller-class\ntype ReadableStreamDefaultController struct {\n\t// Internal slots\n\tcancelAlgorithm UnderlyingSourceCancelCallback\n\n\t// closeRequested is a boolean flag indicating whether the stream has been closed by its\n\t// [UnderlyingSource], but still has chunks in its internal queue that have not yet been\n\t// read.\n\tcloseRequested bool\n\n\t// pullAgain is a boolean flag set to tru if the stream's mechanisms requested a call\n\t// to the [UnderlyingSource]'s pull algorithm to pull more data, but the pull could\n\t// not yet be done since a previous call is still executing.\n\tpullAgain bool\n\n\t// A promise-returning algorithm that pulls data from the underlying source.\n\tpullAlgorithm UnderlyingSourcePullCallback\n\n\t// pulling is a boolean flag set to tru while the [UnderlyingSource]'s pull algorithm is\n\t// executing and the returned promise has not yet fulfilled, used to prevent reentrant\n\t// calls.\n\tpulling bool\n\n\t// queue is a list representing the stream's internal queue of chunks.\n\tqueue *QueueWithSizes\n\n\t// started is a boolean flag indicating whether the [UnderlyingSource] has finished starting.\n\tstarted bool\n\n\t// strategyHWM is a number supplied to the constructor as part of the stream's queuing\n\t// strategy, indicating the point at which the stream will apply backpressure to its\n\t// [UnderlyingSource].\n\tstrategyHWM float64\n\n\t// strategySizeAlgorithm is an algorithm to calculate the size of enqueued chunks, as part\n\t// of stream's queuing strategy.\n\tstrategySizeAlgorithm SizeAlgorithm\n\n\t// stream is the readable stream that this controller controls.\n\tstream *ReadableStream\n}\n\n// Ensure that ReadableStreamDefaultController implements the ReadableStreamController interface.\nvar _ ReadableStreamController = &ReadableStreamDefaultController{}\n\n// NewReadableStreamDefaultControllerObject creates a new [sobek.Object] from a\n// [ReadableStreamDefaultController] instance.\nfunc NewReadableStreamDefaultControllerObject(controller *ReadableStreamDefaultController) (*sobek.Object, error) {\n\trt := controller.stream.runtime\n\tobj := rt.NewObject()\n\tobjName := \"ReadableStreamDefaultController\"\n\n\terr := obj.DefineAccessorProperty(\"desiredSize\", rt.ToValue(func() sobek.Value {\n\t\tdesiredSize := controller.getDesiredSize()\n\t\tif !desiredSize.Valid {\n\t\t\treturn sobek.Null()\n\t\t}\n\t\treturn rt.ToValue(desiredSize.Float64)\n\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Exposing the properties of the [ReadableStreamController] interface\n\tif err := setReadOnlyPropertyOf(obj, objName, \"constructor\", rt.ToValue(func() sobek.Value {\n\t\treturn rt.ToValue(&ReadableStreamDefaultController{})\n\t})); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, objName, \"close\", rt.ToValue(controller.Close)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, objName, \"enqueue\", rt.ToValue(controller.Enqueue)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, objName, \"error\", rt.ToValue(controller.Error)); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn rt.CreateObject(obj), nil\n}\n\n// Close closes the stream.\n//\n// It implements the ReadableStreamDefaultController.close() [specification] algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#rs-default-controller-close\nfunc (controller *ReadableStreamDefaultController) Close() {\n\trt := controller.stream.vu.Runtime()\n\n\t// 1. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.\n\tif !controller.canCloseOrEnqueue() {\n\t\tthrow(rt, newTypeError(rt, \"cannot close or enqueue\"))\n\t}\n\n\t// 2. Perform ! ReadableStreamDefaultControllerClose(this).\n\tcontroller.close()\n}\n\n// Enqueue enqueues a chunk to the stream's internal queue.\n//\n// It implements the ReadableStreamDefaultController.enqueue(chunk) [specification] algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#rs-default-controller-enqueue\nfunc (controller *ReadableStreamDefaultController) Enqueue(chunk sobek.Value) {\n\trt := controller.stream.vu.Runtime()\n\n\t// 1. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(this) is false, throw a TypeError exception.\n\tif !controller.canCloseOrEnqueue() {\n\t\tthrow(rt, newTypeError(rt, \"cannot close or enqueue\"))\n\t}\n\n\t// 2. Perform ? ReadableStreamDefaultControllerEnqueue(this, chunk).\n\tif err := controller.enqueue(chunk); err != nil {\n\t\tthrow(rt, err)\n\t}\n}\n\n// Error signals that the stream has been errored, and performs the necessary cleanup\n// steps.\n//\n// It implements the ReadableStreamDefaultController.error(e) [specification] algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#rs-default-controller-error\nfunc (controller *ReadableStreamDefaultController) Error(err sobek.Value) {\n\tif err == nil {\n\t\terr = sobek.Undefined()\n\t}\n\tcontroller.error(err)\n}\n\n// cancelSteps performs the controller’s steps that run in reaction to\n// the stream being canceled, used to clean up the state stored in the\n// controller and inform the underlying source.\n//\n// It implements the ReadableStreamDefaultControllerCancelSteps [specification]\n// algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-default-controller-cancel-steps\nfunc (controller *ReadableStreamDefaultController) cancelSteps(reason any) *sobek.Promise {\n\t// 1. Perform ! ResetQueue(this).\n\tcontroller.resetQueue()\n\n\t// 2. Let result be the result of performing this.[[cancelAlgorithm]], passing reason.\n\tresult := controller.cancelAlgorithm(reason)\n\n\t// 3. Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).\n\tcontroller.clearAlgorithms()\n\n\t// 4. Return result.\n\tif p, ok := result.Export().(*sobek.Promise); ok {\n\t\treturn p\n\t}\n\n\treturn newRejectedPromise(controller.stream.vu, newError(RuntimeError, \"cancel algorithm error\"))\n}\n\n// pullSteps performs the controller’s steps that run when a default reader\n// is read from, used to pull from the controller any queued chunks, or\n// pull from the underlying source to get more chunks.\n//\n// It implements the [ReadableStreamDefaultControllerPullSteps] specification\n// algorithm.\n//\n// [ReadableStreamDefaultControllerPullSteps]: https://streams.spec.whatwg.org/#rs-default-controller-private-pull\nfunc (controller *ReadableStreamDefaultController) pullSteps(readRequest ReadRequest) {\n\t// 1. Let stream be this.[[stream]].\n\tstream := controller.stream\n\n\t// 2. If this.[[queue]] is not empty,\n\tif controller.queue.Len() > 0 {\n\t\t// 2.1. Let chunk be ! DequeueValue(this).\n\t\tchunk, err := controller.queue.Dequeue()\n\t\tif err != nil {\n\t\t\tcommon.Throw(stream.vu.Runtime(), err)\n\t\t}\n\n\t\t// 2.2. If this.[[closeRequested]] is true and this.[[queue]] is empty,\n\t\tif controller.closeRequested && controller.queue.Len() == 0 {\n\t\t\t// 2.2.1. Perform ! ReadableStreamDefaultControllerClearAlgorithms(this).\n\t\t\tcontroller.clearAlgorithms()\n\t\t\t// 2.2.2. Perform ! ReadableStreamClose(stream).\n\t\t\tstream.close()\n\t\t} else {\n\t\t\t// 2.3. Otherwise, perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).\n\t\t\tcontroller.callPullIfNeeded()\n\t\t}\n\n\t\t// 2. 4. Perform readRequest’s chunk steps, given chunk.\n\t\treadRequest.chunkSteps(chunk)\n\t} else { // 3. Otherwise,\n\t\t// 3.1. Perform ! ReadableStreamAddReadRequest(stream, readRequest).\n\t\tstream.addReadRequest(readRequest)\n\n\t\t// 3.2. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(this).\n\t\tcontroller.callPullIfNeeded()\n\t}\n}\n\n// releaseSteps implements the [ReleaseSteps] contract following the default controller's\n// [specification].\n//\n// [ReleaseSteps]: https://streams.spec.whatwg.org/#abstract-opdef-readablestreamcontroller-releasesteps\n// [specification]: https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultcontroller-releasesteps\nfunc (controller *ReadableStreamDefaultController) releaseSteps() {\n\t// 1.\n\treturn //nolint:staticcheck\n}\n\n// close implements the [ReadableStreamDefaultControllerClose] algorithm\n//\n// [ReadableStreamDefaultControllerClose]: https://streams.spec.whatwg.org/#readable-stream-default-controller-close\nfunc (controller *ReadableStreamDefaultController) close() {\n\t// 1. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return.\n\tif !controller.canCloseOrEnqueue() {\n\t\treturn\n\t}\n\n\t// 2. Let stream be controller.[[stream]]\n\tstream := controller.stream\n\n\t// 3. Set controller.[[closeRequested]] to true.\n\tcontroller.closeRequested = true\n\n\t// 4. If controller.[[queue]] is empty,\n\tif controller.queue.Len() == 0 {\n\t\t// 4.1. Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).\n\t\tcontroller.clearAlgorithms()\n\n\t\t// 4.2. Perform ! ReadableStreamClose(stream).\n\t\tstream.close()\n\t}\n}\n\n// enqueue implements the ReadableStreamDefaultControllerEnqueue(chunk) [specification]\n// algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-default-controller-enqueue\nfunc (controller *ReadableStreamDefaultController) enqueue(chunk sobek.Value) error {\n\t// 1. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return.\n\tif !controller.canCloseOrEnqueue() {\n\t\treturn nil\n\t}\n\n\t// 2. Let stream be controller.[[stream]].\n\tstream := controller.stream\n\n\t// 3. If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0,\n\t// perform ! ReadableStreamFulfillReadRequest(stream, chunk, false).\n\tif stream.isLocked() && stream.getNumReadRequests() > 0 {\n\t\tstream.fulfillReadRequest(chunk, false)\n\t} else { // 4. Otherwise,\n\t\t// 4.1. Let result be the result of performing controller.[[strategySizeAlgorithm]],\n\t\t// passing in chunk, and interpreting the result as a completion record.\n\t\tsize, err := controller.strategySizeAlgorithm(sobek.Undefined(), chunk)\n\t\t// 4.2 If result is an abrupt completion,\n\t\tif err != nil {\n\t\t\t// 4.2.1. Perform ! ReadableStreamDefaultControllerError(controller, result.[[Value]]).\n\t\t\tcontroller.error(err)\n\t\t\t// 4.2.2. Return result.\n\t\t\treturn err\n\t\t}\n\n\t\t// 4.3. Let chunkSize be result.[[Value]].\n\t\tchunkSize := size.ToFloat()\n\n\t\t// 4.4. Let enqueueResult be EnqueueValueWithSize(controller, chunk, chunkSize).\n\t\terr = controller.queue.Enqueue(chunk, chunkSize)\n\t\t// 4.5. If enqueueResult is an abrupt completion,\n\t\tif err != nil {\n\t\t\t// 4.5.1. Perform ! ReadableStreamDefaultControllerError(controller, enqueueResult.[[Value]]).\n\t\t\tcontroller.error(err)\n\t\t\t// 4.5.2. Return enqueueResult.\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// 5. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).\n\tcontroller.callPullIfNeeded()\n\treturn nil\n}\n\n// error implements the [ReadableStreamDefaultControllerError(e)] specification\n// algorithm.\n//\n// [ReadableStreamDefaultControllerError(e)]: https://streams.spec.whatwg.org/#readable-stream-default-controller-error\nfunc (controller *ReadableStreamDefaultController) error(e any) {\n\t// 1. Let stream be controller.[[stream]].\n\tstream := controller.stream\n\n\t// 2. If stream.[[state]] is not \"readable\", return.\n\tif stream.state != ReadableStreamStateReadable {\n\t\treturn\n\t}\n\n\t// 3. Perform ! ResetQueue(controller).\n\tcontroller.resetQueue()\n\n\t// 4. Perform ! ReadableStreamDefaultControllerClearAlgorithms(controller).\n\tcontroller.clearAlgorithms()\n\n\t// 5.Perform ! ReadableStreamError(stream, e).\n\tstream.error(e)\n}\n\n// clearAlgorithms is called once the stream is closed or errored and the algorithms will\n// not be executed anymore.\n//\n// It implements the ReadableStreamDefaultControllerClearAlgorithms [specification]\n// algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-default-controller-clear-algorithms\nfunc (controller *ReadableStreamDefaultController) clearAlgorithms() {\n\t// 1. Set controller.[[pullAlgorithm]] to undefined.\n\tcontroller.pullAlgorithm = nil\n\n\t// 2. Set controller.[[cancelAlgorithm]] to undefined.\n\tcontroller.cancelAlgorithm = nil\n\n\t// 3. Set controller.[[strategySizeAlgorithm]] to undefined.\n\tcontroller.strategySizeAlgorithm = nil\n}\n\n// canCloseOrEnqueue returns true if the stream is in a state where it can be closed or\n// enqueued to, and false otherwise.\n//\n// It implements the ReadableStreamDefaultControllerCanCloseOrEnqueue [specification]\n// algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-default-controller-can-close-or-enqueue\nfunc (controller *ReadableStreamDefaultController) canCloseOrEnqueue() bool {\n\t// 1. Let state be controller.[[stream]].[[state]].\n\tstate := controller.stream.state\n\n\t// 2. If controller.[[closeRequested]] is false and state is \"readable\", return true.\n\tif !controller.closeRequested && state == ReadableStreamStateReadable {\n\t\treturn true\n\t}\n\n\t// 3. Otherwise, return false.\n\treturn false\n}\n\n// resetQueue resets the controller's internal queue.\n//\n// It implements the [ReadableStreamDefaultControllerResetQueue] algorithm's specification\n//\n// [ReadableStreamDefaultControllerResetQueue]: https://streams.spec.whatwg.org/#reset-queue\nfunc (controller *ReadableStreamDefaultController) resetQueue() {\n\t// 1. Assert: container has [[queue]] and [[queueTotalSize]] internal slots.\n\t// ReadableStreamDefaultController.queue && ReadableStreamDefaultController.queueTotalSize\n\n\t// 2. Set container.[[queue]] to a new empty list.\n\t// 3. Set container.[[queueTotalSize]] to 0.\n\tcontroller.queue = NewQueueWithSizes(controller.stream.runtime)\n}\n\n// callPullIfNeeded implements the [specification]'s ReadableStreamDefaultControllerCallPullIfNeeded algorithm\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-default-controller-call-pull-if-needed\nfunc (controller *ReadableStreamDefaultController) callPullIfNeeded() {\n\t// 1. Let shouldPull be ! ReadableStreamDefaultControllerShouldCallPull(controller).\n\tshouldPull := controller.shouldCallPull()\n\n\t// 2. If shouldPull is false, return.\n\tif !shouldPull {\n\t\treturn\n\t}\n\n\t// 3. If controller.[[pulling]] is true,\n\tif controller.pulling {\n\t\t// 3.1. Set controller.[[pullAgain]] to true.\n\t\tcontroller.pullAgain = true\n\t\t// 3.2. Return.\n\t\treturn\n\t}\n\n\t// 4. Assert: controller.[[pullAgain]] is false.\n\tif controller.pullAgain {\n\t\tcommon.Throw(controller.stream.vu.Runtime(), newError(AssertionError, \"controller.pullAgain is true\"))\n\t}\n\n\t// 5. Set controller.[[pulling]] to true.\n\tcontroller.pulling = true\n\n\t// 6. Let pullPromise be the result of performing controller.[[pullAlgorithm]].\n\tcontrollerObj, err := controller.toObject()\n\tif err != nil {\n\t\tcommon.Throw(controller.stream.vu.Runtime(), newError(RuntimeError, err.Error()))\n\t}\n\tpullPromise := controller.pullAlgorithm(controllerObj)\n\n\t_, err = promiseThen(controller.stream.vu.Runtime(), pullPromise,\n\t\t// 7. Upon fulfillment of pullPromise\n\t\tfunc(sobek.Value) {\n\t\t\t// 7.1. Set controller.[[pulling]] to false.\n\t\t\tcontroller.pulling = false\n\n\t\t\t// 7.2. If controller.[[pullAgain]] is true,\n\t\t\tif controller.pullAgain {\n\t\t\t\t// 7.2.1. Set controller.[[pullAgain]] to false.\n\t\t\t\tcontroller.pullAgain = false\n\t\t\t\t// 7.2.2. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).\n\t\t\t\tcontroller.callPullIfNeeded()\n\t\t\t}\n\t\t},\n\n\t\t// 8. Upon rejection of pullPromise with reason e,\n\t\tfunc(reason sobek.Value) {\n\t\t\t// 8.1. Perform ! ReadableStreamDefaultControllerError(controller, e).\n\t\t\tcontroller.error(reason)\n\t\t},\n\t)\n\tif err != nil {\n\t\tcommon.Throw(controller.stream.vu.Runtime(), err)\n\t}\n}\n\n// shouldCallPull implements the [specification]'s ReadableStreamDefaultControllerShouldCallPull algorithm\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-default-controller-should-call-pull\nfunc (controller *ReadableStreamDefaultController) shouldCallPull() bool {\n\t// 1. Let stream be controller.[[stream]].\n\tstream := controller.stream\n\n\t// 2. If ! ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) is false, return false.\n\tif !controller.canCloseOrEnqueue() {\n\t\treturn false\n\t}\n\n\t// 3. If controller.[[started]] is false, return false.\n\tif !controller.started {\n\t\treturn false\n\t}\n\n\t// 4. If ! IsReadableStreamLocked(stream) is true and ! ReadableStreamGetNumReadRequests(stream) > 0, return true.\n\tif stream.isLocked() && stream.getNumReadRequests() > 0 {\n\t\treturn true\n\t}\n\n\t// 5. Let desiredSize be ! ReadableStreamDefaultControllerGetDesiredSize(controller).\n\tdesiredSize := controller.getDesiredSize()\n\n\t// 6. Assert: desiredSize is not null.\n\tif !desiredSize.Valid {\n\t\tcommon.Throw(controller.stream.vu.Runtime(), newError(AssertionError, \"desiredSize is null\"))\n\t}\n\n\t// 7. If desiredSize > 0, return true.\n\tif desiredSize.Float64 > 0 {\n\t\treturn true\n\t}\n\n\t// 8. Return false.\n\treturn false\n}\n\nfunc (controller *ReadableStreamDefaultController) getDesiredSize() null.Float {\n\tstate := controller.stream.state\n\n\tif state == ReadableStreamStateErrored {\n\t\treturn null.NewFloat(0, false)\n\t}\n\n\tif state == ReadableStreamStateClosed {\n\t\treturn null.NewFloat(0, true)\n\t}\n\n\treturn null.NewFloat(controller.strategyHWM-controller.queue.QueueTotalSize, true)\n}\n\nfunc (controller *ReadableStreamDefaultController) toObject() (*sobek.Object, error) {\n\treturn NewReadableStreamDefaultControllerObject(controller)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/readable_stream_default_reader.go",
    "content": "package streams\n\nimport (\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n)\n\n// ReadableStreamDefaultReader represents a default reader designed to be vended by a [ReadableStream].\ntype ReadableStreamDefaultReader struct {\n\tBaseReadableStreamReader\n\n\t// readRequests holds a list of read requests, used when a consumer requests\n\t// chunks sooner than they are available.\n\treadRequests []ReadRequest\n}\n\n// NewReadableStreamDefaultReaderObject creates a new sobek.Object from a [ReadableStreamDefaultReader] instance.\nfunc NewReadableStreamDefaultReaderObject(reader *ReadableStreamDefaultReader) (*sobek.Object, error) {\n\trt := reader.stream.runtime\n\tobj := rt.NewObject()\n\tobjName := \"ReadableStreamDefaultReader\"\n\n\terr := obj.DefineAccessorProperty(\"closed\", rt.ToValue(func() *sobek.Promise {\n\t\tp, _, _ := reader.GetClosed()\n\t\treturn p\n\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, objName, \"cancel\", rt.ToValue(reader.Cancel)); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Exposing the properties of the [ReadableStreamDefaultReader] interface\n\tif err := setReadOnlyPropertyOf(obj, objName, \"read\", rt.ToValue(reader.Read)); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, objName, \"releaseLock\", rt.ToValue(reader.ReleaseLock)); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn obj, nil\n}\n\n// Ensure the ReadableStreamReader interface is implemented correctly\nvar _ ReadableStreamReader = &ReadableStreamDefaultReader{}\n\n// Read returns a [sobek.Promise] providing access to the next chunk in the stream's internal queue.\nfunc (reader *ReadableStreamDefaultReader) Read() *sobek.Promise {\n\tstream := reader.GetStream()\n\n\t// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.\n\tif stream == nil {\n\t\treturn newRejectedPromise(reader.vu, newTypeError(reader.runtime, \"stream is undefined\").Err())\n\t}\n\n\t// 2. Let promise be a new promise.\n\tpromise, resolve, reject := stream.vu.Runtime().NewPromise()\n\n\t// 3. Let readRequest be a new read request with the following items:\n\treadRequest := ReadRequest{\n\t\tchunkSteps: func(chunk any) {\n\t\t\t// Resolve promise with «[ \"value\" → chunk, \"done\" → false ]».\n\t\t\t// TODO(@mstoykov): propagate as error?\n\t\t\terr := resolve(map[string]any{\"value\": chunk, \"done\": false})\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t},\n\t\tcloseSteps: func() {\n\t\t\t// Resolve promise with «[ \"value\" → undefined, \"done\" → true ]».\n\t\t\terr := resolve(map[string]any{\"value\": sobek.Undefined(), \"done\": true})\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t},\n\t\terrorSteps: func(e any) {\n\t\t\t// Reject promise with e.\n\t\t\terr := reject(e)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t},\n\t}\n\n\t// 4. Perform ! ReadableStreamDefaultReaderRead(this, readRequest).\n\treader.read(readRequest)\n\n\t// 5. Return promise.\n\treturn promise\n}\n\n// Cancel returns a [sobek.Promise] that resolves when the stream is canceled.\n//\n// Calling this method signals a loss of interest in the stream by a consumer. The\n// supplied reason argument will be given to the underlying source, which may or\n// may not use it.\n//\n// The `reason` argument is optional, and should hold a human-readable reason for\n// the cancellation. This value may or may not be used.\n//\n// [SetUpReadableStreamDefaultReader]: https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader\nfunc (reader *ReadableStreamDefaultReader) Cancel(reason sobek.Value) *sobek.Promise {\n\t// 1. If this.[[stream]] is undefined, return a promise rejected with a TypeError exception.\n\tif reader.stream == nil {\n\t\treturn newRejectedPromise(reader.vu, newTypeError(reader.runtime, \"stream is undefined\").Err())\n\t}\n\n\t// 2. Return ! ReadableStreamReaderGenericCancel(this, reason).\n\treturn reader.BaseReadableStreamReader.Cancel(reason)\n}\n\n// ReadResult is the result of a read operation\n//\n// It contains the value read from the stream and a boolean indicating whether or not the stream is done.\n// An undefined value indicates that the stream has been closed.\ntype ReadResult struct {\n\tValue sobek.Value\n\tDone  bool\n}\n\n// ReleaseLock releases the reader's lock on the stream.\n//\n// If the associated stream is errored when the lock is released, the\n// reader will appear errored in that same way subsequently; otherwise, the\n// reader will appear closed.\nfunc (reader *ReadableStreamDefaultReader) ReleaseLock() {\n\t// 1. If this.[[stream]] is undefined, return.\n\tif reader.stream == nil {\n\t\treturn\n\t}\n\n\t// 2. Perform ! ReadableStreamDefaultReaderRelease(this).\n\treader.release()\n}\n\n// release implements the [ReadableStreamDefaultReaderRelease] algorithm.\n//\n// [ReadableStreamDefaultReaderRelease]:\n// https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreaderrelease\nfunc (reader *ReadableStreamDefaultReader) release() {\n\t// 1. Perform ! ReadableStreamReaderGenericRelease(reader).\n\treader.BaseReadableStreamReader.release()\n\n\t// 2. Let e be a new TypeError exception.\n\te := newTypeError(reader.runtime, \"reader released\")\n\n\t// 3. Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).\n\treader.errorReadRequests(e.Err())\n}\n\n// setup implements the [SetUpReadableStreamDefaultReader] algorithm.\n//\n// [SetUpReadableStreamDefaultReader]: https://streams.spec.whatwg.org/#set-up-readable-stream-default-reader\nfunc (reader *ReadableStreamDefaultReader) setup(stream *ReadableStream) {\n\trt := stream.vu.Runtime()\n\n\t// 1. If ! IsReadableStreamLocked(stream) is true, throw a TypeError exception.\n\tif stream.isLocked() {\n\t\tthrow(rt, newTypeError(rt, \"stream is locked\"))\n\t}\n\n\t// 2. Perform ! ReadableStreamReaderGenericInitialize(reader, stream).\n\tReadableStreamReaderGenericInitialize(reader, stream)\n\n\t// 3. Set reader.[[readRequests]] to a new empty list.\n\treader.readRequests = []ReadRequest{}\n}\n\n// Implements the [specification]'s ReadableStreamDefaultReaderErrorReadRequests algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#abstract-opdef-readablestreamdefaultreadererrorreadrequests\nfunc (reader *ReadableStreamDefaultReader) errorReadRequests(e any) {\n\t// 1. Let readRequests be reader.[[readRequests]].\n\treadRequests := reader.readRequests\n\n\t// 2. Set reader.[[readRequests]] to a new empty list.\n\treader.readRequests = []ReadRequest{}\n\n\t// 3. For each readRequest of readRequests,\n\tfor _, request := range readRequests {\n\t\t// 3.1. Perform readRequest’s error steps, given e.\n\t\trequest.errorSteps(e)\n\t}\n}\n\n// read implements the [ReadableStreamDefaultReaderRead] algorithm.\n//\n// [ReadableStreamDefaultReaderRead]: https://streams.spec.whatwg.org/#readable-stream-default-reader-read\nfunc (reader *ReadableStreamDefaultReader) read(readRequest ReadRequest) {\n\t// 1. Let stream be reader.[[stream]].\n\tstream := reader.GetStream()\n\n\t// 2. Assert: stream is not undefined.\n\tif stream == nil {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"stream is undefined\"))\n\t}\n\n\t// 3. Set stream.[[disturbed]] to true.\n\tstream.disturbed = true\n\n\tswitch stream.state {\n\tcase ReadableStreamStateClosed:\n\t\t// 4. If stream.[[state]] is \"closed\", perform readRequest’s close steps.\n\t\treadRequest.closeSteps()\n\tcase ReadableStreamStateErrored:\n\t\t// 5. Otherwise, if stream.[[state]] is \"errored\", perform readRequest’s error steps given stream.[[storedError]].\n\t\tif jsErr, ok := stream.storedError.(*jsError); ok {\n\t\t\treadRequest.errorSteps(jsErr.Err())\n\t\t} else {\n\t\t\treadRequest.errorSteps(stream.storedError)\n\t\t}\n\n\tdefault:\n\t\t// 6. Otherwise,\n\t\t// 6.1. Assert: stream.[[state]] is \"readable\".\n\t\tif stream.state != ReadableStreamStateReadable {\n\t\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"stream.state is not readable\"))\n\t\t}\n\n\t\t// 6.2. Perform ! stream.[[controller]].[[PullSteps]](readRequest).\n\t\tstream.controller.pullSteps(readRequest)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/readable_stream_reader.go",
    "content": "package streams\n\nimport (\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// ReadableStreamReader is the interface implemented by all readable stream readers.\ntype ReadableStreamReader interface {\n\tReadableStreamGenericReader\n\n\t// Read returns a [sobek.Promise] providing access to the next chunk in the stream's internal queue.\n\tRead() *sobek.Promise\n\n\t// ReleaseLock releases the reader's lock on the stream.\n\tReleaseLock()\n}\n\n// ReadableStreamGenericReader defines common internal getters/setters\n// and methods that are shared between ReadableStreamDefaultReader and\n// ReadableStreamBYOBReader objects.\n//\n// It implements the [ReadableStreamReaderGeneric] mixin from the specification.\n//\n// Because we are in the context of Sobek, we cannot really define properties\n// the same way as in the spec, so we use getters/setters instead.\n//\n// [ReadableStreamReaderGeneric]: https://streams.spec.whatwg.org/#readablestreamgenericreader\ntype ReadableStreamGenericReader interface {\n\t// GetStream returns the stream that owns this reader.\n\tGetStream() *ReadableStream\n\n\t// SetStream sets the stream that owns this reader.\n\tSetStream(stream *ReadableStream)\n\n\t// GetClosed returns a [sobek.Promise] that resolves when the stream is closed.\n\tGetClosed() (p *sobek.Promise, resolve, reject func(any) error)\n\n\t// SetClosed sets the [sobek.Promise] that resolves when the stream is closed.\n\tSetClosed(p *sobek.Promise, resolve, reject func(any) error)\n\n\t// Cancel returns a [sobek.Promise] that resolves when the stream is canceled.\n\tCancel(reason sobek.Value) *sobek.Promise\n}\n\n// BaseReadableStreamReader is a base implement\ntype BaseReadableStreamReader struct {\n\tclosedPromise            *sobek.Promise\n\tclosedPromiseResolveFunc func(resolve any) error\n\tclosedPromiseRejectFunc  func(reason any) error\n\n\t// stream is a [ReadableStream] instance that owns this reader\n\tstream *ReadableStream\n\n\truntime *sobek.Runtime\n\tvu      modules.VU\n}\n\n// Ensure BaseReadableStreamReader implements the ReadableStreamGenericReader interface correctly\nvar _ ReadableStreamGenericReader = &BaseReadableStreamReader{}\n\n// GetStream returns the stream that owns this reader.\nfunc (reader *BaseReadableStreamReader) GetStream() *ReadableStream {\n\treturn reader.stream\n}\n\n// SetStream sets the stream that owns this reader.\nfunc (reader *BaseReadableStreamReader) SetStream(stream *ReadableStream) {\n\treader.stream = stream\n\treader.runtime = stream.runtime\n\treader.vu = stream.vu\n}\n\n// GetClosed returns the reader's closed promise as well as its resolve and reject functions.\nfunc (reader *BaseReadableStreamReader) GetClosed() (p *sobek.Promise, resolve, reject func(any) error) {\n\treturn reader.closedPromise, reader.closedPromiseResolveFunc, reader.closedPromiseRejectFunc\n}\n\n// SetClosed sets the reader's closed promise as well as its resolve and reject functions.\nfunc (reader *BaseReadableStreamReader) SetClosed(p *sobek.Promise, resolve, reject func(any) error) {\n\treader.closedPromise = p\n\treader.closedPromiseResolveFunc = resolve\n\treader.closedPromiseRejectFunc = reject\n}\n\n// Cancel returns a [sobek.Promise] that resolves when the stream is canceled.\nfunc (reader *BaseReadableStreamReader) Cancel(reason sobek.Value) *sobek.Promise {\n\treturn reader.cancel(reason)\n}\n\n// cancel implements the [ReadableStreamReaderGenericCancel(reader, reason)] [specification] algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-reader-generic-cancel\nfunc (reader *BaseReadableStreamReader) cancel(reason sobek.Value) *sobek.Promise {\n\t// 1. Let stream be reader.[[stream]].\n\tstream := reader.stream\n\n\t// 2. Assert: stream is not undefined.\n\tif stream == nil {\n\t\treturn newRejectedPromise(reader.vu, newTypeError(reader.runtime, \"stream is undefined\"))\n\t}\n\n\t// 3. Return ! ReadableStreamCancel(stream, reason).\n\treturn stream.cancel(reason)\n}\n\n// release implements the [ReadableStreamReaderGenericRelease(reader)] [specification] algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-reader-generic-release\nfunc (reader *BaseReadableStreamReader) release() {\n\t// 1. Let stream be reader.[[stream]].\n\tstream := reader.stream\n\n\t// 2. Assert: stream is not undefined.\n\tif stream == nil {\n\t\tcommon.Throw(reader.vu.Runtime(), newError(AssertionError, \"stream is undefined\"))\n\t}\n\n\t// 3. Assert: stream.[[reader]] is reader.\n\tif stream.reader == nil {\n\t\tcommon.Throw(reader.vu.Runtime(), newError(AssertionError, \"stream is undefined\"))\n\t}\n\n\tvar streamReader *BaseReadableStreamReader\n\tif v, ok := stream.reader.(*ReadableStreamDefaultReader); ok {\n\t\tstreamReader = &v.BaseReadableStreamReader\n\t}\n\n\tif reader != streamReader {\n\t\tcommon.Throw(reader.vu.Runtime(), newError(AssertionError, \"stream reader isn't reader\"))\n\t}\n\n\t// 4. If stream.[[state]] is \"readable\", reject reader.[[closedPromise]] with a TypeError exception.\n\tif stream.state == ReadableStreamStateReadable {\n\t\terr := reader.closedPromiseRejectFunc(newTypeError(reader.runtime, \"stream is readable\").Err())\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t} else { // 5. Otherwise, set reader.[[closedPromise]] to a promise rejected with a TypeError exception.\n\t\treader.closedPromise = newRejectedPromise(stream.vu, newTypeError(reader.runtime, \"stream is not readable\").Err())\n\t}\n\n\t// 6. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.\n\t// FIXME: See https://github.com/dop251/goja/issues/565\n\tvar (\n\t\terr       error\n\t\tdoNothing = func(sobek.Value) {}\n\t)\n\t_, err = promiseThen(stream.vu.Runtime(), reader.closedPromise, doNothing, doNothing)\n\tif err != nil {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(RuntimeError, err.Error()))\n\t}\n\n\t// 7. Perform ! stream.[[controller]].[[ReleaseSteps]]().\n\tstream.controller.releaseSteps()\n\n\t// 8. Set stream.[[reader]] to undefined.\n\tstream.reader = nil\n\tstream.Locked = false\n\n\t// 9. Set reader.[[stream]] to undefined.\n\treader.stream = nil\n}\n\n// ReadRequest is a struct containing three algorithms to perform in reaction to filling the readable stream's\n// internal queue or changing its state\ntype ReadRequest struct {\n\t// chunkSteps is an algorithm taking a chunk, called when a chunk is available for reading.\n\tchunkSteps func(chunk any)\n\n\t// closeSteps is an algorithm taking no arguments, called when no chunks are available because\n\t// the stream is closed.\n\tcloseSteps func()\n\n\t// errorSteps is an algorithm taking a JavaScript value, called when no chunks are available because\n\t// the stream is errored.\n\terrorSteps func(e any)\n}\n\n// ReadableStreamReaderGenericInitialize implements the [specification] ReadableStreamReaderGenericInitialize algorithm.\n//\n// [specification]: https://streams.spec.whatwg.org/#readable-stream-reader-generic-initialize\nfunc ReadableStreamReaderGenericInitialize(reader ReadableStreamGenericReader, stream *ReadableStream) {\n\t// 1. Set reader.[[stream]] to stream.\n\treader.SetStream(stream)\n\n\t// 2. Set stream.[[reader]] to reader.\n\tstream.reader = reader\n\tstream.Locked = true\n\n\tpromise, resolve, reject := stream.runtime.NewPromise()\n\n\tswitch stream.state {\n\t// 3. If stream.[[state]] is \"readable\",\n\tcase ReadableStreamStateReadable:\n\t\t// 3.1 Set reader.[[closedPromise]] to a new promise.\n\t\t// Set later, as we need to set the resolve/reject functions as well.\n\t// 4. Otherwise, if stream.[[state]] is \"closed\",\n\tcase ReadableStreamStateClosed:\n\t\t// 4.1 Set reader.[[closedPromise]] to a promise resolved with undefined.\n\t\terr := resolve(sobek.Undefined())\n\t\tif err != nil {\n\t\t\tpanic(err) // TODO(@mstoykov): probably better to move them out as errors\n\t\t}\n\t// 5. Otherwise,\n\tdefault:\n\t\t// 5.1 Assert: stream.[[state]] is \"errored\".\n\t\tif stream.state != ReadableStreamStateErrored {\n\t\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"stream.state is not \\\"errored\\\"\"))\n\t\t}\n\n\t\t// 5.2 Set reader.[[closedPromise]] to a promise rejected with stream.[[storedError]].\n\t\tif jsErr, ok := stream.storedError.(*jsError); ok {\n\t\t\terr := reject(jsErr.Err())\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t} else {\n\t\t\terr := reject(errToObj(stream.runtime, stream.storedError))\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\n\t\t// 5.3 Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.\n\t\t// See https://github.com/dop251/goja/issues/565\n\t\tvar (\n\t\t\terr       error\n\t\t\tdoNothing = func(sobek.Value) {}\n\t\t)\n\t\t_, err = promiseThen(stream.vu.Runtime(), promise, doNothing, doNothing)\n\t\tif err != nil {\n\t\t\tcommon.Throw(stream.vu.Runtime(), newError(RuntimeError, err.Error()))\n\t\t}\n\t}\n\n\treader.SetClosed(promise, resolve, reject)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/readable_streams.go",
    "content": "package streams\n\nimport (\n\t\"errors\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// ReadableStream is a concrete instance of the general [readable stream] concept.\n//\n// It is adaptable to any chunk type, and maintains an internal queue to keep track of\n// data supplied by the underlying source but not yet read by any consumer.\n//\n// [readable stream]: https://streams.spec.whatwg.org/#rs-class\ntype ReadableStream struct {\n\t// Locked indicate whether the readable stream is locked to a reader\n\tLocked bool\n\n\t// controller holds a [ReadableStreamDefaultController] or [ReadableByteStreamController] created\n\t// with the ability to control the state and queue of this stream.\n\tcontroller ReadableStreamController\n\n\t// disturbed is true when the stream has been read from or canceled\n\tdisturbed bool\n\n\t// reader holds the current reader of the stream if the stream is locked to a reader\n\t// or nil otherwise.\n\treader any\n\n\t// state holds the current state of the stream\n\tstate ReadableStreamState\n\n\t// storedError holds the error that caused the stream to be errored\n\tstoredError any\n\n\tSource *sobek.Object\n\n\truntime *sobek.Runtime\n\tvu      modules.VU\n}\n\n// Cancel cancels the stream and returns a Promise to the user\nfunc (stream *ReadableStream) Cancel(reason sobek.Value) (*sobek.Promise, error) {\n\t// 1. IsReadableStreamLocked(this) is true, return a promise rejected with a TypeError exception.\n\tif stream.isLocked() {\n\t\tpromise, _, reject := stream.vu.Runtime().NewPromise()\n\n\t\tif err := reject(newTypeError(stream.runtime, \"cannot cancel a locked stream\").Err()); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treturn promise, nil\n\t}\n\n\t// 2. Return ! ReadableStreamCancel(reason)\n\treturn stream.cancel(reason), nil\n}\n\n// GetReader implements the [getReader] operation.\n//\n// [getReader]: https://streams.spec.whatwg.org/#rs-get-reader\nfunc (stream *ReadableStream) GetReader(options *sobek.Object) sobek.Value {\n\t// 1. If options[\"mode\"] does not exist, return ? AcquireReadableStreamDefaultReader(this).\n\tif options == nil || common.IsNullish(options) ||\n\t\toptions.Get(\"mode\") == nil || sobek.IsUndefined(options.Get(\"mode\")) {\n\t\tdefaultReader := stream.acquireDefaultReader()\n\t\tdefaultReaderObj, err := NewReadableStreamDefaultReaderObject(defaultReader)\n\t\tif err != nil {\n\t\t\tcommon.Throw(stream.runtime, err)\n\t\t}\n\n\t\treturn defaultReaderObj\n\t}\n\n\t// 2. Assert: options[\"mode\"] is \"byob\".\n\tif options.Get(\"mode\").String() != \"byob\" {\n\t\tthrow(stream.runtime, newTypeError(stream.runtime, \"options.mode is not 'byob'\"))\n\t}\n\n\t// 3. Return ? AcquireReadableStreamBYOBReader(this).\n\tcommon.Throw(stream.runtime, newError(NotSupportedError, \"'byob' mode is not supported yet\"))\n\treturn sobek.Undefined()\n}\n\n// Tee implements the [tee] operation.\n//\n// [tee]: https://streams.spec.whatwg.org/#rs-tee\nfunc (stream *ReadableStream) Tee() sobek.Value {\n\tcommon.Throw(stream.runtime, newError(NotSupportedError, \"'tee()' is not supported yet\"))\n\treturn sobek.Undefined()\n}\n\n// ReadableStreamState represents the current state of a ReadableStream\ntype ReadableStreamState string\n\nconst (\n\t// ReadableStreamStateReadable indicates that the stream is readable, and that more data may be read from the stream.\n\tReadableStreamStateReadable = \"readable\"\n\n\t// ReadableStreamStateClosed indicates that the stream is closed and cannot be read from.\n\tReadableStreamStateClosed = \"closed\"\n\n\t// ReadableStreamStateErrored indicates that the stream has been aborted (errored).\n\tReadableStreamStateErrored = \"errored\"\n)\n\n// ReadableStreamType represents the type of the ReadableStream\ntype ReadableStreamType = string\n\nconst (\n\t// ReadableStreamTypeBytes indicates that the stream is a byte stream.\n\tReadableStreamTypeBytes = \"bytes\"\n)\n\n// isLocked implements the specification's [IsReadableStreamLocked()] abstract operation.\n//\n// [IsReadableStreamLocked()]: https://streams.spec.whatwg.org/#is-readable-stream-locked\nfunc (stream *ReadableStream) isLocked() bool {\n\treturn stream.reader != nil\n}\n\n// initialize implements the specification's [InitializeReadableStream()] abstract operation.\n//\n// [InitializeReadableStream()]: https://streams.spec.whatwg.org/#initialize-readable-stream\nfunc (stream *ReadableStream) initialize() {\n\tstream.state = ReadableStreamStateReadable\n\tstream.reader = nil\n\tstream.Locked = false\n\tstream.storedError = nil\n\tstream.disturbed = false\n}\n\n// setupReadableStreamDefaultControllerFromUnderlyingSource implements the [specification]'s\n// SetUpReadableStreamDefaultController abstract operation.\n//\n// [specification]: https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller-from-underlying-source\nfunc (stream *ReadableStream) setupReadableStreamDefaultControllerFromUnderlyingSource(\n\tunderlyingSource *sobek.Object,\n\tunderlyingSourceDict UnderlyingSource,\n\thighWaterMark float64,\n\tsizeAlgorithm SizeAlgorithm,\n) {\n\t// 1. Let controller be a new ReadableStreamDefaultController.\n\tcontroller := &ReadableStreamDefaultController{}\n\n\t// 2. Let startAlgorithm be an algorithm that returns undefined.\n\tvar startAlgorithm UnderlyingSourceStartCallback = func(*sobek.Object) sobek.Value {\n\t\treturn sobek.Undefined()\n\t}\n\n\t// 3. Let pullAlgorithm be an algorithm that returns a promise resolved with undefined.\n\tvar pullAlgorithm UnderlyingSourcePullCallback = func(*sobek.Object) *sobek.Promise {\n\t\treturn newResolvedPromise(stream.vu, sobek.Undefined())\n\t}\n\n\t// 4. Let cancelAlgorithm be an algorithm that returns a promise resolved with undefined.\n\tvar cancelAlgorithm UnderlyingSourceCancelCallback = func(any) sobek.Value {\n\t\treturn stream.vu.Runtime().ToValue(newResolvedPromise(stream.vu, sobek.Undefined()))\n\t}\n\n\t// 5. If underlyingSourceDict[\"start\"] exists, then set startAlgorithm to an algorithm\n\t// which returns the result of invoking underlyingSourceDict[\"start\"] with argument\n\t// list « controller » and callback this value underlyingSource.\n\tif underlyingSourceDict.startSet {\n\t\tstartAlgorithm = stream.startAlgorithm(underlyingSource, underlyingSourceDict)\n\t}\n\n\t// 6. If underlyingSourceDict[\"pull\"] exists, then set pullAlgorithm to an algorithm which\n\t// returns the result of invoking underlyingSourceDict[\"pull\"] with argument list\n\t// « controller » and callback this value underlyingSource.\n\tif underlyingSourceDict.pullSet {\n\t\tpullAlgorithm = stream.pullAlgorithm(underlyingSource, underlyingSourceDict)\n\t}\n\n\t// 7. If underlyingSourceDict[\"cancel\"] exists, then set cancelAlgorithm to an algorithm which takes an argument\n\t// reason and returns the result of invoking underlyingSourceDict[\"cancel\"] with argument list « reason » and\n\t// callback this value underlyingSource.\n\tif underlyingSourceDict.cancelSet {\n\t\tcancelAlgorithm = stream.cancelAlgorithm(underlyingSource, underlyingSourceDict)\n\t}\n\n\t// 8. Perform ? SetUpReadableStreamDefaultController(...)\n\tstream.setupDefaultController(controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm)\n}\n\nfunc (stream *ReadableStream) startAlgorithm(\n\tunderlyingSource *sobek.Object,\n\tunderlyingSourceDict UnderlyingSource,\n) UnderlyingSourceStartCallback {\n\tcall, ok := sobek.AssertFunction(underlyingSourceDict.Start)\n\tif !ok {\n\t\tthrow(stream.runtime, newTypeError(stream.runtime, \"underlyingSource.[[start]] must be a function\"))\n\t}\n\n\treturn func(obj *sobek.Object) (v sobek.Value) {\n\t\tvar err error\n\t\tv, err = call(underlyingSource, obj)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\n\t\treturn v\n\t}\n}\n\nfunc (stream *ReadableStream) pullAlgorithm(\n\tunderlyingSource *sobek.Object,\n\tunderlyingSourceDict UnderlyingSource,\n) UnderlyingSourcePullCallback {\n\tcall, ok := sobek.AssertFunction(underlyingSourceDict.Pull)\n\tif !ok {\n\t\tthrow(stream.runtime, newTypeError(stream.runtime, \"underlyingSource.[[pull]] must be a function\"))\n\t}\n\n\treturn func(obj *sobek.Object) *sobek.Promise {\n\t\tv, err := call(underlyingSource, obj)\n\t\tif err != nil {\n\t\t\tvar ex *sobek.Exception\n\t\t\tif errors.As(err, &ex) {\n\t\t\t\treturn newRejectedPromise(stream.vu, ex.Value())\n\t\t\t}\n\t\t\treturn newRejectedPromise(stream.vu, err)\n\t\t}\n\n\t\tif p, ok := v.Export().(*sobek.Promise); ok {\n\t\t\treturn p\n\t\t}\n\n\t\treturn newResolvedPromise(stream.vu, v)\n\t}\n}\n\nfunc (stream *ReadableStream) cancelAlgorithm(\n\tunderlyingSource *sobek.Object,\n\tunderlyingSourceDict UnderlyingSource,\n) UnderlyingSourceCancelCallback {\n\tcall, ok := sobek.AssertFunction(underlyingSourceDict.Cancel)\n\tif !ok {\n\t\tthrow(stream.runtime, newTypeError(stream.runtime, \"underlyingSource.[[cancel]] must be a function\"))\n\t}\n\n\treturn func(reason any) sobek.Value {\n\t\tvar p *sobek.Promise\n\n\t\tif e := stream.runtime.Try(func() {\n\t\t\tres, err := call(underlyingSource, stream.runtime.ToValue(reason))\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\n\t\t\tif cp, ok := res.Export().(*sobek.Promise); ok {\n\t\t\t\tp = cp\n\t\t\t}\n\t\t}); e != nil {\n\t\t\tp = newRejectedPromise(stream.vu, e.Value())\n\t\t}\n\n\t\tif p == nil {\n\t\t\tp = newResolvedPromise(stream.vu, sobek.Undefined())\n\t\t}\n\n\t\treturn stream.vu.Runtime().ToValue(p)\n\t}\n}\n\n// setupDefaultController implements the specification's [SetUpReadableStreamDefaultController] abstract operation.\n//\n// [SetUpReadableStreamDefaultController]: https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller\nfunc (stream *ReadableStream) setupDefaultController(\n\tcontroller *ReadableStreamDefaultController,\n\tstartAlgorithm UnderlyingSourceStartCallback,\n\tpullAlgorithm UnderlyingSourcePullCallback,\n\tcancelAlgorithm UnderlyingSourceCancelCallback,\n\thighWaterMark float64,\n\tsizeAlgorithm SizeAlgorithm,\n) {\n\trt := stream.vu.Runtime()\n\n\t// 1. Assert: stream.[[controller]] is undefined.\n\tif stream.controller != nil {\n\t\tcommon.Throw(rt, newError(AssertionError, \"stream.[[controller]] is not undefined\"))\n\t}\n\n\t// 2. Set controller.[[stream]] to stream.\n\tcontroller.stream = stream\n\n\t// 3. Perform ! ResetQueue(controller).\n\tcontroller.resetQueue()\n\n\t// 4. Set controller.[[started]], controller.[[closeRequested]], controller.[[pullAgain]], and\n\t// controller.[[pulling]] to false.\n\tcontroller.started, controller.closeRequested, controller.pullAgain, controller.pulling = false, false, false, false\n\n\t// 5. Set controller.[[strategySizeAlgorithm]] to sizeAlgorithm and controller.[[strategyHWM]] to highWaterMark.\n\tcontroller.strategySizeAlgorithm, controller.strategyHWM = sizeAlgorithm, highWaterMark\n\n\t// 6. Set controller.[[pullAlgorithm]] to pullAlgorithm.\n\tcontroller.pullAlgorithm = pullAlgorithm\n\n\t// 7. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.\n\tcontroller.cancelAlgorithm = cancelAlgorithm\n\n\t// 8. Set stream.[[controller]] to controller.\n\tstream.controller = controller\n\n\t// 9. Let startResult be the result of performing startAlgorithm. (This might throw an exception.)\n\tcontrollerObj, err := controller.toObject()\n\tif err != nil {\n\t\tcommon.Throw(controller.stream.vu.Runtime(), newError(RuntimeError, err.Error()))\n\t}\n\tstartResult := startAlgorithm(controllerObj)\n\n\t// 10. Let startPromise be a promise with startResult.\n\tvar startPromise *sobek.Promise\n\tif common.IsNullish(startResult) {\n\t\tstartPromise = newResolvedPromise(controller.stream.vu, startResult)\n\t} else if p, ok := startResult.Export().(*sobek.Promise); ok {\n\t\tif p.State() == sobek.PromiseStateRejected {\n\t\t\tcontroller.error(p.Result())\n\t\t}\n\t\tstartPromise = p\n\t} else {\n\t\tstartPromise = newResolvedPromise(controller.stream.vu, startResult)\n\t}\n\t_, err = promiseThen(stream.vu.Runtime(), startPromise,\n\t\t// 11. Upon fulfillment of startPromise,\n\t\tfunc(sobek.Value) {\n\t\t\t// 11.1. Set controller.[[started]] to true.\n\t\t\tcontroller.started = true\n\t\t\t// 11.2. Assert: controller.[[pulling]] is false.\n\t\t\tif controller.pulling {\n\t\t\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"controller `pulling` state is not false\"))\n\t\t\t}\n\t\t\t// 11.3. Assert: controller.[[pullAgain]] is false.\n\t\t\tif controller.pullAgain {\n\t\t\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"controller `pullAgain` state is not false\"))\n\t\t\t}\n\t\t\t// 11.4. Perform ! ReadableStreamDefaultControllerCallPullIfNeeded(controller).\n\t\t\tcontroller.callPullIfNeeded()\n\t\t},\n\t\t// 12. Upon rejection of startPromise with reason r,\n\t\tfunc(err sobek.Value) {\n\t\t\tcontroller.error(err)\n\t\t},\n\t)\n\tif err != nil {\n\t\tcommon.Throw(stream.vu.Runtime(), err)\n\t}\n}\n\n// acquireDefaultReader implements the specification's [AcquireReadableStreamDefaultReader] algorithm.\n//\n// [AcquireReadableStreamDefaultReader]: https://streams.spec.whatwg.org/#acquire-readable-stream-reader\nfunc (stream *ReadableStream) acquireDefaultReader() *ReadableStreamDefaultReader {\n\t// 1. Let reader be a new ReadableStreamDefaultReader.\n\treader := &ReadableStreamDefaultReader{}\n\n\t// 2. Perform ? SetUpReadableStreamDefaultReader(reader, stream).\n\treader.setup(stream)\n\n\t// 3. Return reader.\n\treturn reader\n}\n\n// addReadRequest implements the specification's [ReadableStreamAddReadRequest()] abstract operation.\n//\n// [ReadableStreamAddReadRequest()]: https://streams.spec.whatwg.org/#readable-stream-add-read-request\nfunc (stream *ReadableStream) addReadRequest(readRequest ReadRequest) {\n\t// 1. Assert: stream.[[reader]] implements ReadableStreamDefaultReader.\n\tdefaultReader, ok := stream.reader.(*ReadableStreamDefaultReader)\n\tif !ok {\n\t\treadRequest.errorSteps(newError(RuntimeError, \"reader is not a ReadableStreamDefaultReader\"))\n\t\treturn\n\t}\n\n\t// 2. Assert: stream.[[state]] is \"readable\".\n\tif stream.state != ReadableStreamStateReadable {\n\t\treadRequest.errorSteps(newError(AssertionError, \"stream is not readable\"))\n\t\treturn\n\t}\n\n\t// 3. Append readRequest to stream.[[reader]].[[readRequests]].\n\tdefaultReader.readRequests = append(defaultReader.readRequests, readRequest)\n}\n\n// cancel implements the specification's [ReadableStreamCancel()] abstract operation.\n//\n// [ReadableStreamCancel()]: https://streams.spec.whatwg.org/#readable-stream-cancel\nfunc (stream *ReadableStream) cancel(reason sobek.Value) *sobek.Promise {\n\t// 1. Set stream.[[disturbed]] to true.\n\tstream.disturbed = true\n\n\t// 2. If stream.[[state]] is \"closed\", return a promise resolved with undefined.\n\tif stream.state == ReadableStreamStateClosed {\n\t\treturn newResolvedPromise(stream.vu, sobek.Undefined())\n\t}\n\n\t// 3. If stream.[[state]] is \"errored\", return a promise rejected with stream.[[storedError]].\n\tif stream.state == ReadableStreamStateErrored {\n\t\tif jsErr, ok := stream.storedError.(*jsError); ok {\n\t\t\treturn newRejectedPromise(stream.vu, jsErr.Err())\n\t\t}\n\t\treturn newRejectedPromise(stream.vu, stream.storedError)\n\t}\n\n\t// 4. Perform ! ReadableStreamClose(stream).\n\tstream.close()\n\n\t// 5. Let reader be stream.[[reader]].\n\t// 6. If reader is not undefined and reader implements ReadableStreamBYOBReader,\n\t// Not implemented yet: ReadableStreamBYOBReader is not supported yet.\n\n\t// 7. Let sourceCancelPromise be ! stream.[[controller]].[[CancelSteps]](reason).\n\tsourceCancelPromise := stream.controller.cancelSteps(reason)\n\n\t// 8. Return the result of reacting to sourceCancelPromise with a fulfillment step that returns undefined.\n\tpromise, err := promiseThen(stream.vu.Runtime(), sourceCancelPromise,\n\t\t// Mimicking Deno's implementation: https://github.com/denoland/deno/blob/main/ext/web/06_streams.js#L405\n\t\tfunc(sobek.Value) {},\n\t\tfunc(err sobek.Value) { throw(stream.vu.Runtime(), err) },\n\t)\n\tif err != nil {\n\t\tcommon.Throw(stream.vu.Runtime(), err)\n\t}\n\n\treturn promise\n}\n\n// close implements the specification's [ReadableStreamClose()] abstract operation.\n//\n// [ReadableStreamClose()]: https://streams.spec.whatwg.org/#readable-stream-close\nfunc (stream *ReadableStream) close() {\n\t// 1. Assert: stream.[[state]] is \"readable\".\n\tif stream.state != ReadableStreamStateReadable {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"cannot close a stream that is not readable\"))\n\t}\n\n\t// 2. Set stream.[[state]] to \"closed\".\n\tstream.state = ReadableStreamStateClosed\n\n\t// 3. Let reader be stream.[[reader]].\n\treader := stream.reader\n\n\t// 4. If reader is undefined, return.\n\tif reader == nil {\n\t\treturn\n\t}\n\n\t// 5. Resolve reader.[[closedPromise]] with undefined.\n\tgenericReader, ok := reader.(ReadableStreamGenericReader)\n\tif !ok {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"reader is not a ReadableStreamGenericReader\"))\n\t}\n\n\t_, resolveFunc, _ := genericReader.GetClosed()\n\terr := resolveFunc(sobek.Undefined())\n\tif err != nil {\n\t\tpanic(err) // TODO(@mstoykov): propagate as error instead\n\t}\n\n\t// 6. If reader implements ReadableStreamDefaultReader,\n\tdefaultReader, ok := reader.(*ReadableStreamDefaultReader)\n\tif ok {\n\t\t// 6.1. Let readRequests be reader.[[readRequests]].\n\t\treadRequests := defaultReader.readRequests\n\n\t\t// 6.2. Set reader.[[readRequests]] to an empty list.\n\t\tdefaultReader.readRequests = []ReadRequest{}\n\n\t\t// 6.3. For each readRequest of readRequests,\n\t\tfor _, readRequest := range readRequests {\n\t\t\treadRequest.closeSteps()\n\t\t}\n\t}\n}\n\n// error implements the specification's [ReadableStreamError] abstract operation.\n//\n// [ReadableStreamError]: https://streams.spec.whatwg.org/#readable-stream-error\nfunc (stream *ReadableStream) error(e any) {\n\t// 1. Assert: stream.[[state]] is \"readable\".\n\tif stream.state != ReadableStreamStateReadable {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"cannot error a stream that is not readable\"))\n\t}\n\n\t// 2. Set stream.[[state]] to \"errored\".\n\tstream.state = ReadableStreamStateErrored\n\n\t// 3. Set stream.[[storedError]] to e.\n\tstream.storedError = e\n\n\t// 4. Let reader be stream.[[reader]].\n\treader := stream.reader\n\n\t// 5. If reader is undefined, return.\n\tif reader == nil {\n\t\treturn\n\t}\n\n\tgenericReader, ok := reader.(ReadableStreamGenericReader)\n\tif !ok {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"reader is not a ReadableStreamGenericReader\"))\n\t}\n\n\t// 6. Reject reader.[[closedPromise]] with e.\n\tvar err error\n\tpromise, _, rejectFunc := genericReader.GetClosed()\n\tif jsErr, ok := e.(*jsError); ok {\n\t\terr = rejectFunc(jsErr.Err())\n\t} else {\n\t\terr = rejectFunc(e)\n\t}\n\tif err != nil {\n\t\tpanic(err) // TODO(@mstoykov): propagate as error instead\n\t}\n\n\t// 7. Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.\n\t// See https://github.com/dop251/goja/issues/565\n\tdoNothing := func(sobek.Value) {}\n\t_, err = promiseThen(stream.vu.Runtime(), promise, doNothing, doNothing)\n\tif err != nil {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(RuntimeError, err.Error()))\n\t}\n\n\t// 8. If reader implements ReadableStreamDefaultReader,\n\tdefaultReader, ok := reader.(*ReadableStreamDefaultReader)\n\tif ok {\n\t\t// 8.1. Perform ! ReadableStreamDefaultReaderErrorReadRequests(reader, e).\n\t\tdefaultReader.errorReadRequests(e)\n\t\treturn\n\t}\n\n\t// 9. OTHERWISE, reader is a ReadableStreamBYOBReader\n\t// 9.1. Assert: reader implements ReadableStreamBYOBReader.\n\tcommon.Throw(stream.vu.Runtime(), newError(NotSupportedError, \"ReadableStreamBYOBReader is not supported yet\"))\n}\n\n// fulfillReadRequest implements the [ReadableStreamFulfillReadRequest()] algorithm.\n//\n// [ReadableStreamFulfillReadRequest()]: https://streams.spec.whatwg.org/#readable-stream-fulfill-read-request\nfunc (stream *ReadableStream) fulfillReadRequest(chunk any, done bool) {\n\t// 1. Assert: ! ReadableStreamHasDefaultReader(stream) is true.\n\tif !stream.hasDefaultReader() {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"stream does not have a default reader\"))\n\t}\n\n\t// 2. Let reader be stream.[[reader]].\n\treader, ok := stream.reader.(*ReadableStreamDefaultReader)\n\tif !ok {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(RuntimeError, \"reader is not a ReadableStreamDefaultReader\"))\n\t}\n\n\t// 3. Assert: reader.[[readRequests]] is not empty.\n\tif len(reader.readRequests) == 0 {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"reader.[[readRequests]] is empty\"))\n\t}\n\n\t// 4. Let readRequest be reader.[[readRequests]][0].\n\treadRequest := reader.readRequests[0]\n\n\t// 5. Remove readRequest from reader.[[readRequests]].\n\treader.readRequests = reader.readRequests[1:]\n\n\tif done {\n\t\t// 6. If done is true, perform readRequest’s close steps.\n\t\treadRequest.closeSteps()\n\t} else {\n\t\t// 7. Otherwise, perform readRequest’s chunk steps, given chunk.\n\t\treadRequest.chunkSteps(chunk)\n\t}\n}\n\n// getNumReadRequests implements the [ReadableStreamGetNumReadRequests()] algorithm.\n//\n// [ReadableStreamGetNumReadRequests()]: https://streams.spec.whatwg.org/#readable-stream-get-num-read-requests\nfunc (stream *ReadableStream) getNumReadRequests() int {\n\t// 1. Assert: ! ReadableStreamHasDefaultReader(stream) is true.\n\tif !stream.hasDefaultReader() {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(AssertionError, \"stream does not have a default reader\"))\n\t}\n\n\t// 2. Return stream.[[reader]].[[readRequests]]'s size.\n\tdefaultReader, ok := stream.reader.(*ReadableStreamDefaultReader)\n\tif !ok {\n\t\tcommon.Throw(stream.vu.Runtime(), newError(RuntimeError, \"reader is not a ReadableStreamDefaultReader\"))\n\t}\n\n\treturn len(defaultReader.readRequests)\n}\n\n// hasDefaultReader implements the [ReadableStreamHasDefaultReader()] algorithm.\n//\n// [ReadableStreamHasDefaultReader()]: https://streams.spec.whatwg.org/#readable-stream-has-default-reader\nfunc (stream *ReadableStream) hasDefaultReader() bool {\n\t// 1. Let reader be stream.[[reader]].\n\treader := stream.reader\n\n\t// 2. If reader is undefined, return false.\n\tif reader == nil {\n\t\treturn false\n\t}\n\n\t// 3. If reader implements ReadableStreamDefaultReader, return true.\n\t_, ok := reader.(*ReadableStreamDefaultReader)\n\treturn ok\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/readable_streams_test.go",
    "content": "package streams\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/js/modulestest\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst webPlatformTestSuite = \"tests/wpt\"\n\nfunc TestReadableStream(t *testing.T) {\n\tt.Parallel()\n\tif _, err := os.Stat(webPlatformTestSuite); err != nil { //nolint:forbidigo\n\t\tt.Skipf(\"If you want to run Streams tests, you need to run the 'checkout.sh` script in the directory to get \"+\n\t\t\t\"https://github.com/web-platform-tests/wpt at the correct last tested commit (%v)\", err)\n\t}\n\n\tsuites := []string{\n\t\t\"bad-strategies.any.js\",\n\t\t\"bad-underlying-sources.any.js\",\n\t\t\"cancel.any.js\",\n\t\t\"constructor.any.js\",\n\t\t\"count-queuing-strategy-integration.any.js\",\n\t\t\"default-reader.any.js\",\n\t\t\"floating-point-total-queue-size.any.js\",\n\t\t\"general.any.js\",\n\t\t\"reentrant-strategies.any.js\",\n\t\t\"templated.any.js\",\n\t}\n\n\tfor _, suite := range suites {\n\t\tt.Run(suite, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newConfiguredRuntime(t)\n\t\t\tgotErr := ts.EventLoop.Start(func() error {\n\t\t\t\treturn executeTestScript(ts.VU, webPlatformTestSuite+\"/streams/readable-streams\", suite)\n\t\t\t})\n\t\t\tassert.NoError(t, gotErr)\n\t\t})\n\t}\n}\n\nfunc newConfiguredRuntime(t testing.TB) *modulestest.Runtime {\n\trt := modulestest.NewRuntime(t)\n\n\trequire.NoError(t, rt.SetupModuleSystem(nil, nil, nil))\n\n\t// We want to make the [self] available for Web Platform Tests, as it is used in test harness.\n\t_, err := rt.VU.Runtime().RunString(\"var self = this;\")\n\trequire.NoError(t, err)\n\n\t// We also want the streams module exports to be globally available.\n\tm := new(RootModule).NewModuleInstance(rt.VU)\n\tfor k, v := range m.Exports().Named {\n\t\trequire.NoError(t, rt.VU.RuntimeField.Set(k, v))\n\t}\n\n\t// Then, we register the Web Platform Tests harness.\n\tcompileAndRun(t, rt, webPlatformTestSuite, \"resources/testharness.js\")\n\n\t// And the Streams-specific test utilities.\n\tfiles := []string{\n\t\t\"resources/rs-test-templates.js\",\n\t\t\"resources/rs-utils.js\",\n\t\t\"resources/test-utils.js\",\n\t}\n\tfor _, file := range files {\n\t\tcompileAndRun(t, rt, webPlatformTestSuite+\"/streams\", file)\n\t}\n\n\treturn rt\n}\n\nfunc compileAndRun(t testing.TB, runtime *modulestest.Runtime, base, file string) {\n\tprogram, err := modulestest.CompileFile(base, file)\n\trequire.NoError(t, err)\n\n\t_, err = runtime.VU.Runtime().RunProgram(program)\n\trequire.NoError(t, err)\n}\n\nfunc executeTestScript(vu modules.VU, base string, script string) error {\n\tprogram, err := modulestest.CompileFile(base, script)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif _, err = vu.Runtime().RunProgram(program); err != nil {\n\t\treturn err\n\t}\n\n\t// After having executed the tests suite file,\n\t// we use a callback to make sure we wait until all\n\t// the promise-based tests have finished.\n\t// Also, as a mechanism to capture deadlocks caused\n\t// by those promises not resolved during normal execution.\n\tcallback := vu.RegisterCallback()\n\tif err := vu.Runtime().Set(\"wait\", func() {\n\t\tcallback(func() error { return nil })\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\twaitForPromiseTests := `\nif (this.tests && this.tests.promise_tests && typeof this.tests.promise_tests.then === 'function') {\n\tthis.tests.promise_tests.then(() => wait());\n} else {\n\twait();\n}\n`\n\tif _, err = vu.Runtime().RunString(waitForPromiseTests); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/tests/README.md",
    "content": "# Streams API Web Platform Tests \n\nThis directory contains some utilities to run the [Web Platform Tests](https://web-platform-tests.org/) for the \n[Streams API](https://streams.spec.whatwg.org/) against the experimental module available in k6 as\n`k6/experimental/streams`.\n\nThe entry point is the [`checkout.sh`](./checkout.sh) script, which checks out the last commit sha of \n[wpt](https://github.com/web-platform-tests/wpt) that was tested with this module, and applies some patches\n(all the `*.patch` files) on top of it, in order to make the tests compatible with the k6 runtime.\n\n**How to use**\n1. Run `./checkout.sh` to check out the web-platform-tests sources.\n2. Run `go test ../... -tags=wpt` to run the tests.\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/tests/checkout.sh",
    "content": "#!/bin/sh\n\n# Last commit hash it was tested with\nsha=607e64a823b05a2ab53dbad1937f8ff58f2a3ff4\n\n# Checkout concrete files from the web-platform-tests repository\nmkdir -p ./wpt\ncd ./wpt\ngit init\ngit remote add origin https://github.com/web-platform-tests/wpt\ngit sparse-checkout init --cone\ngit sparse-checkout set resources streams\ngit fetch origin --depth=1 \"${sha}\"\ngit checkout ${sha}\n\n# Apply custom patches needed to run the tests in k6/Sobek\nfor patch in ../*.patch\ndo\n    git apply \"$patch\"\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\ndone\n\n# Return to the original directory\ncd -\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/tests/reentrant-strategies.any.js.patch",
    "content": "diff --git a/streams/readable-streams/reentrant-strategies.any.js b/streams/readable-streams/reentrant-strategies.any.js\nindex 8ae7b98e8..ecb2e8436 100644\n--- a/streams/readable-streams/reentrant-strategies.any.js\n+++ b/streams/readable-streams/reentrant-strategies.any.js\n@@ -140,39 +140,40 @@ promise_test(t => {\n   ]);\n }, 'cancel() inside size() should work');\n\n-promise_test(() => {\n-  let controller;\n-  let pipeToPromise;\n-  const ws = recordingWritableStream();\n-  const rs = new ReadableStream({\n-    start(c) {\n-      controller = c;\n-    }\n-  }, {\n-    size() {\n-      if (!pipeToPromise) {\n-        pipeToPromise = rs.pipeTo(ws);\n-      }\n-      return 1;\n-    },\n-    highWaterMark: 1\n-  });\n-  controller.enqueue('a');\n-  assert_not_equals(pipeToPromise, undefined);\n-\n-  // Some pipeTo() implementations need an additional chunk enqueued in order for the first one to be processed. See\n-  // https://github.com/whatwg/streams/issues/794 for background.\n-  controller.enqueue('a');\n-\n-  // Give pipeTo() a chance to process the queued chunks.\n-  return delay(0).then(() => {\n-    assert_array_equals(ws.events, ['write', 'a', 'write', 'a'], 'ws should contain two chunks');\n-    controller.close();\n-    return pipeToPromise;\n-  }).then(() => {\n-    assert_array_equals(ws.events, ['write', 'a', 'write', 'a', 'close'], 'target should have been closed');\n-  });\n-}, 'pipeTo() inside size() should behave as expected');\n+// FIXME: We don't have support yet for pipeTo() nor writable streams.\n+// promise_test(() => {\n+//   let controller;\n+//   let pipeToPromise;\n+//   const ws = recordingWritableStream();\n+//   const rs = new ReadableStream({\n+//     start(c) {\n+//       controller = c;\n+//     }\n+//   }, {\n+//     size() {\n+//       if (!pipeToPromise) {\n+//         pipeToPromise = rs.pipeTo(ws);\n+//       }\n+//       return 1;\n+//     },\n+//     highWaterMark: 1\n+//   });\n+//   controller.enqueue('a');\n+//   assert_not_equals(pipeToPromise, undefined);\n+//\n+//   // Some pipeTo() implementations need an additional chunk enqueued in order for the first one to be processed. See\n+//   // https://github.com/whatwg/streams/issues/794 for background.\n+//   controller.enqueue('a');\n+//\n+//   // Give pipeTo() a chance to process the queued chunks.\n+//   return delay(0).then(() => {\n+//     assert_array_equals(ws.events, ['write', 'a', 'write', 'a'], 'ws should contain two chunks');\n+//     controller.close();\n+//     return pipeToPromise;\n+//   }).then(() => {\n+//     assert_array_equals(ws.events, ['write', 'a', 'write', 'a', 'close'], 'target should have been closed');\n+//   });\n+// }, 'pipeTo() inside size() should behave as expected');\n\n promise_test(() => {\n   let controller;\n@@ -205,7 +206,7 @@ promise_test(() => {\n     assert_equals(calls, 1, 'size() should have been called once');\n     return delay(0);\n   }).then(() => {\n-    assert_true(readResolved);\n+    //assert_true(readResolved);\n     assert_equals(calls, 1, 'size() should only be called once');\n     return readPromise;\n   }).then(({ value, done }) => {\n@@ -240,25 +241,26 @@ promise_test(() => {\n   });\n }, 'getReader() inside size() should work');\n \n-promise_test(() => {\n-  let controller;\n-  let branch1;\n-  let branch2;\n-  const rs = new ReadableStream({\n-    start(c) {\n-      controller = c;\n-    }\n-  }, {\n-    size() {\n-      [branch1, branch2] = rs.tee();\n-      return 1;\n-    }\n-  });\n-  controller.enqueue('a');\n-  assert_true(rs.locked, 'rs should be locked');\n-  controller.close();\n-  return Promise.all([\n-    readableStreamToArray(branch1).then(array => assert_array_equals(array, ['a'], 'branch1 should have one chunk')),\n-    readableStreamToArray(branch2).then(array => assert_array_equals(array, ['a'], 'branch2 should have one chunk'))\n-  ]);\n-}, 'tee() inside size() should work');\n+// FIXME: We don't have support yet for tee().\n+// promise_test(() => {\n+//   let controller;\n+//   let branch1;\n+//   let branch2;\n+//   const rs = new ReadableStream({\n+//     start(c) {\n+//       controller = c;\n+//     }\n+//   }, {\n+//     size() {\n+//       [branch1, branch2] = rs.tee();\n+//       return 1;\n+//     }\n+//   });\n+//   controller.enqueue('a');\n+//   assert_true(rs.locked, 'rs should be locked');\n+//   controller.close();\n+//   return Promise.all([\n+//     readableStreamToArray(branch1).then(array => assert_array_equals(array, ['a'], 'branch1 should have one chunk')),\n+//     readableStreamToArray(branch2).then(array => assert_array_equals(array, ['a'], 'branch2 should have one chunk'))\n+//   ]);\n+// }, 'tee() inside size() should work');\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/tests/rs-test-templates.js.patch",
    "content": "diff --git a/streams/resources/rs-test-templates.js b/streams/resources/rs-test-templates.js\nindex 25751c477..874bd7c3f 100644\n--- a/streams/resources/rs-test-templates.js\n+++ b/streams/resources/rs-test-templates.js\n@@ -14,9 +14,10 @@ self.templatedRSEmpty = (label, factory) => {\n     assert_equals(typeof rs.locked, 'boolean', 'has a boolean locked getter');\n     assert_equals(typeof rs.cancel, 'function', 'has a cancel method');\n     assert_equals(typeof rs.getReader, 'function', 'has a getReader method');\n-    assert_equals(typeof rs.pipeThrough, 'function', 'has a pipeThrough method');\n-    assert_equals(typeof rs.pipeTo, 'function', 'has a pipeTo method');\n-    assert_equals(typeof rs.tee, 'function', 'has a tee method');\n+    // FIXME: Uncomment once we add that support\n+    // assert_equals(typeof rs.pipeThrough, 'function', 'has a pipeThrough method');\n+    // assert_equals(typeof rs.pipeTo, 'function', 'has a pipeTo method');\n+    // assert_equals(typeof rs.tee, 'function', 'has a tee method');\n \n   }, label + ': instances have the correct methods and properties');\n \n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/tests/testharness.js.patch",
    "content": "diff --git a/resources/testharness.js b/resources/testharness.js\nindex c5c375e17..57d201b57 100644\n--- a/resources/testharness.js\n+++ b/resources/testharness.js\n@@ -487,7 +487,11 @@\n         this.all_loaded = false;\n         this.on_loaded_callback = null;\n         Promise.resolve().then(function() {\n-            this.all_loaded = true\n+            // This is the test environment used when we run tests from Go\n+            // code and with the Sobek/k6 runtime. However, we don't want\n+            // all tests to be marked as loaded \"by default\", as it would\n+            // make some of the tests to not be executed at all.\n+            // this.all_loaded = true\n             if (this.on_loaded_callback) {\n                 this.on_loaded_callback();\n             }\n@@ -2631,6 +2635,16 @@\n             this.set_status(status, message, stack);\n             this.phase = this.phases.HAS_RESULT;\n             this.done();\n+\n+            // We don't want to rely on the DOM and other browser-based\n+            // mechanisms for reporting test failures. Instead, we just\n+            // throw the error and make it fail fast, to be aware of it.\n+            //\n+            // In the future, we might want to add a way to report these\n+            // that doesn't rely on a browser, but let all test end before\n+            // actually reporting failures.\n+            // But, as a first iteration, this approach should suffice.\n+            throw `${this.name} failed - ${e}`;\n         } finally {\n             this.current_test = null;\n         }\n@@ -4784,6 +4798,11 @@\n      */\n\n     var tests = new Tests();\n+    // We expose the [tests] global variable through\n+    // the [global_scope], so we can access it from\n+    // Go code, in order to make sure that all test\n+    // have finished from Go code.\n+    global_scope.tests = tests;\n\n     if (global_scope.addEventListener) {\n         var error_handler = function(error, message, stack) {\n"
  },
  {
    "path": "internal/js/modules/k6/experimental/streams/underlying_source.go",
    "content": "package streams\n\nimport (\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// UnderlyingSource represents the underlying source of a ReadableStream, and defines how\n// the underlying data is pulled from the source.\n//\n// [specification]: https://streams.spec.whatwg.org/#dictdef-underlyingsource\ntype UnderlyingSource struct {\n\t// StartFunc is called immediately during the creation of a ReadableStream.\n\t//\n\t// Typically, this is used to a adapt a push source by setting up relevant event listeners.\n\t// If the setup process is asynchronous, it can return a Promise to signal success or\n\t// failure; a rejected promise will error the stream.\n\tStart sobek.Value `json:\"start\"`\n\n\t// PullFunc is  a function that is called whenever the stream's internal queue of chunks\n\t// becomes not full, i.e. whenever the queue's desired size becomes positive.\n\t//\n\t// Generally it will be called repeatedly until the queue reaches its high watermark.\n\t//\n\t// This function will not be called until `start()` successfully completes. Additionally,\n\t// it will only be called repeatedly if it enqueues at least one chunk or fulfills a\n\t// BYOB request; a no-op `pull` implementation will not be continually called.\n\tPull sobek.Value `json:\"pull\"`\n\n\t// CancelFunc is a function that is called when the stream's or reader's `cancel()` method is\n\t// called.\n\t//\n\t// It takes as its argument the same value as was passed to those methods by the consumer.\n\t//\n\t// For all streams, this is generally used to release access to the underlying resource.\n\t//\n\t// If the shutdown process is asynchronous, it can return a promise to signal success or\n\t// failure; the result will be communicated via the return value of the cancel() method\n\t// that was called. Throwing an exception is treated the same as returning a rejected promise.\n\tCancel sobek.Value `json:\"cancel\"`\n\n\t// Type is a string indicating the type of the underlying source.\n\tType ReadableStreamType `json:\"type\"`\n\n\t// AutoAllocateChunkSize (optional) is a non-negative integer indicating the size of\n\t// chunks to allocate when auto-allocating chunks.\n\t//\n\t// Can be set to a positive integer to cause the implementation to automatically\n\t// allocate buffers for the underlying source code to write into. In this case, when\n\t// a consumer is using a default reader, the stream implementation will automatically\n\t// allocate an ArrayBuffer of the given size, so that `controller.byobRequest` is always\n\t// present, as if the consumer was using a BYOB reader.\n\tAutoAllocateChunkSize null.Int `json:\"autoAllocateChunkSize\"`\n\n\t// startSet is true if the start function was set by the user.\n\tstartSet bool\n\n\t// pullSet is true if the pull function was set by the user.\n\tpullSet bool\n\n\t// cancelSet is true if the cancel function was set by the user.\n\tcancelSet bool\n}\n\n// UnderlyingSourceStartCallback is a function that is called immediately during the creation of a ReadableStream.\ntype UnderlyingSourceStartCallback func(controller *sobek.Object) sobek.Value\n\n// UnderlyingSourcePullCallback is a function that is called whenever the stream's internal queue of chunks\n// becomes not full, i.e. whenever the queue's desired size becomes positive.\ntype UnderlyingSourcePullCallback func(controller *sobek.Object) *sobek.Promise\n\n// UnderlyingSourceCancelCallback is a function that is called when the stream's or reader's `cancel()` method is\n// called.\ntype UnderlyingSourceCancelCallback func(reason any) sobek.Value\n\n// NewUnderlyingSourceFromObject creates a new UnderlyingSource from a sobek.Object.\nfunc NewUnderlyingSourceFromObject(rt *sobek.Runtime, obj *sobek.Object) (UnderlyingSource, error) {\n\tvar underlyingSource UnderlyingSource\n\n\tif common.IsNullish(obj) {\n\t\t// If the user didn't provide an underlying source, use the default one.\n\t\treturn underlyingSource, nil\n\t}\n\n\t// We only accept a valid underlyingSource.[[type]]\n\tunderlyingSourceType := obj.Get(\"type\")\n\tif underlyingSourceType != nil &&\n\t\t!sobek.IsUndefined(obj.Get(\"type\")) &&\n\t\tobj.Get(\"type\").String() != ReadableStreamTypeBytes {\n\t\treturn underlyingSource, newTypeError(rt, \"invalid underlying source type\")\n\t}\n\n\tif err := rt.ExportTo(obj, &underlyingSource); err != nil {\n\t\treturn underlyingSource, newTypeError(rt, \"invalid underlying source object\")\n\t}\n\n\tif underlyingSource.Start != nil {\n\t\tunderlyingSource.startSet = true\n\t}\n\n\tif underlyingSource.Pull != nil {\n\t\tunderlyingSource.pullSet = true\n\t}\n\n\tif underlyingSource.Cancel != nil {\n\t\tunderlyingSource.cancelSet = true\n\t}\n\n\treturn underlyingSource, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/client.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/lib/netext/grpcext\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\n\t\"github.com/bufbuild/protocompile\"\n\t\"github.com/grafana/sobek\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/credentials/insecure\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protodesc\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n)\n\n// Client represents a gRPC client that can be used to make RPC requests\ntype Client struct {\n\tmds  map[string]protoreflect.MethodDescriptor\n\tconn *grpcext.Conn\n\tvu   modules.VU\n\taddr string\n\n\ttypes    *protoregistry.Types\n\ttypesMtx sync.Mutex\n}\n\n// Load will parse the given proto files and make the file descriptors available to request.\nfunc (c *Client) Load(importPaths []string, filenames ...string) ([]MethodInfo, error) {\n\tif c.vu.State() != nil {\n\t\treturn nil, errors.New(\"load must be called in the init context\")\n\t}\n\n\tinitEnv := c.vu.InitEnv()\n\tif initEnv == nil {\n\t\treturn nil, errors.New(\"missing init environment\")\n\t}\n\n\t// If no import paths are specified, use the current working directory\n\tif len(importPaths) == 0 {\n\t\timportPaths = append(importPaths, initEnv.CWD.Path)\n\t}\n\n\tfor i, s := range importPaths {\n\t\t// Clean file scheme as it is the only supported scheme and the following APIs do not support them\n\t\timportPaths[i] = strings.TrimPrefix(s, \"file://\")\n\t}\n\n\tresolver := protocompile.WithStandardImports(&protocompile.SourceResolver{\n\t\tImportPaths: importPaths,\n\t\tAccessor: func(filename string) (io.ReadCloser, error) {\n\t\t\tabsFilePath := initEnv.GetAbsFilePath(filename)\n\t\t\treturn initEnv.FileSystems[\"file\"].Open(absFilePath)\n\t\t},\n\t})\n\n\tcompiler := protocompile.Compiler{\n\t\tResolver: resolver,\n\t}\n\n\tfds, err := compiler.Compile(c.vu.Context(), filenames...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfdset := &descriptorpb.FileDescriptorSet{}\n\tseen := make(map[string]struct{})\n\tfor _, fd := range fds {\n\t\tfdset.File = append(fdset.File, walkFileDescriptors(seen, fd)...)\n\t}\n\treturn c.convertToMethodInfo(fdset)\n}\n\n// LoadProtoset will parse the given protoset file (serialized FileDescriptorSet) and make the file\n// descriptors available to request.\nfunc (c *Client) LoadProtoset(protosetPath string) ([]MethodInfo, error) {\n\tif c.vu.State() != nil {\n\t\treturn nil, errors.New(\"load must be called in the init context\")\n\t}\n\n\tinitEnv := c.vu.InitEnv()\n\tif initEnv == nil {\n\t\treturn nil, errors.New(\"missing init environment\")\n\t}\n\n\tabsFilePath := initEnv.GetAbsFilePath(protosetPath)\n\tfdsetFile, err := initEnv.FileSystems[\"file\"].Open(absFilePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"couldn't open protoset: %w\", err)\n\t}\n\n\tdefer func() { _ = fdsetFile.Close() }()\n\tfdsetBytes, err := io.ReadAll(fdsetFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"couldn't read protoset: %w\", err)\n\t}\n\n\tfdset := &descriptorpb.FileDescriptorSet{}\n\tif err = proto.Unmarshal(fdsetBytes, fdset); err != nil {\n\t\treturn nil, fmt.Errorf(\"couldn't unmarshal protoset file %s: %w\", protosetPath, err)\n\t}\n\n\treturn c.convertToMethodInfo(fdset)\n}\n\n// Note: this function was lifted from `lib/options.go`\nfunc decryptPrivateKey(key, password []byte) ([]byte, error) {\n\tblock, _ := pem.Decode(key)\n\tif block == nil {\n\t\treturn nil, errors.New(\"failed to decode PEM key\")\n\t}\n\n\tblockType := block.Type\n\tif blockType == \"ENCRYPTED PRIVATE KEY\" {\n\t\treturn nil, errors.New(\"encrypted pkcs8 formatted key is not supported\")\n\t}\n\t/*\n\t   Even though `DecryptPEMBlock` has been deprecated since 1.16.x it is still\n\t   being used here because it is deprecated due to it not supporting *good* cryptography\n\t   ultimately though we want to support something so we will be using it for now.\n\t*/\n\tdecryptedKey, err := x509.DecryptPEMBlock(block, password) //nolint:staticcheck\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkey = pem.EncodeToMemory(&pem.Block{\n\t\tType:  blockType,\n\t\tBytes: decryptedKey,\n\t})\n\treturn key, nil\n}\n\nfunc buildTLSConfig(parentConfig *tls.Config, certificate, key []byte, caCertificates [][]byte) (*tls.Config, error) {\n\tvar cp *x509.CertPool\n\tif len(caCertificates) > 0 {\n\t\tcp, _ = x509.SystemCertPool()\n\t\tfor i, caCert := range caCertificates {\n\t\t\tif ok := cp.AppendCertsFromPEM(caCert); !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to append ca certificate [%d] from PEM\", i)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Ignoring 'TLS MinVersion is too low' because this tls.Config will inherit MinValue and MaxValue\n\t// from the vu state tls.Config\n\n\ttlsCfg := &tls.Config{\n\t\tCipherSuites:       parentConfig.CipherSuites,\n\t\tInsecureSkipVerify: parentConfig.InsecureSkipVerify, //nolint:gosec\n\t\tMinVersion:         parentConfig.MinVersion,\n\t\tMaxVersion:         parentConfig.MaxVersion,\n\t\tRenegotiation:      parentConfig.Renegotiation,\n\t\tRootCAs:            cp,\n\t}\n\tif len(certificate) > 0 && len(key) > 0 {\n\t\tcert, err := tls.X509KeyPair(certificate, key)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to append certificate from PEM: %w\", err)\n\t\t}\n\t\ttlsCfg.Certificates = []tls.Certificate{cert}\n\t}\n\treturn tlsCfg, nil\n}\n\nfunc buildTLSConfigFromMap(parentConfig *tls.Config, tlsConfigMap map[string]any) (*tls.Config, error) {\n\tvar cert, key, pass []byte\n\tvar ca [][]byte\n\tvar err error\n\tif certstr, ok := tlsConfigMap[\"cert\"].(string); ok {\n\t\tcert = []byte(certstr)\n\t}\n\tif keystr, ok := tlsConfigMap[\"key\"].(string); ok {\n\t\tkey = []byte(keystr)\n\t}\n\tif passwordStr, ok := tlsConfigMap[\"password\"].(string); ok {\n\t\tpass = []byte(passwordStr)\n\t\tif len(pass) > 0 {\n\t\t\tif key, err = decryptPrivateKey(key, pass); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t}\n\tif cas, ok := tlsConfigMap[\"cacerts\"]; ok {\n\t\tvar caCertsArray []any\n\t\tif caCertsArray, ok = cas.([]any); ok {\n\t\t\tca = make([][]byte, len(caCertsArray))\n\t\t\tfor i, entry := range caCertsArray {\n\t\t\t\tvar entryStr string\n\t\t\t\tif entryStr, ok = entry.(string); ok {\n\t\t\t\t\tca[i] = []byte(entryStr)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if caCertStr, caCertStrOk := cas.(string); caCertStrOk {\n\t\t\tca = [][]byte{[]byte(caCertStr)}\n\t\t}\n\t}\n\treturn buildTLSConfig(parentConfig, cert, key, ca)\n}\n\n// Connect is a block dial to the gRPC server at the given address (host:port)\nfunc (c *Client) Connect(addr string, params sobek.Value) (bool, error) {\n\tstate := c.vu.State()\n\tif state == nil {\n\t\treturn false, common.NewInitContextError(\"connecting to a gRPC server in the init context is not supported\")\n\t}\n\n\tp, err := newConnectParams(c.vu, params)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"invalid grpc.connect() parameters: %w\", err)\n\t}\n\n\topts := grpcext.DefaultOptions(c.vu.State)\n\n\tvar tcred credentials.TransportCredentials\n\tif !p.IsPlaintext {\n\t\ttlsCfg := state.TLSConfig.Clone()\n\t\tif len(p.TLS) > 0 {\n\t\t\tif tlsCfg, err = buildTLSConfigFromMap(tlsCfg, p.TLS); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t}\n\t\ttlsCfg.NextProtos = []string{\"h2\"}\n\n\t\ttcred = credentials.NewTLS(tlsCfg)\n\t} else {\n\t\ttcred = insecure.NewCredentials()\n\t}\n\topts = append(opts, grpc.WithTransportCredentials(tcred))\n\n\tif ua := state.Options.UserAgent; ua.Valid {\n\t\topts = append(opts, grpc.WithUserAgent(ua.ValueOrZero()))\n\t}\n\n\tctx, cancel := context.WithTimeout(c.vu.Context(), p.Timeout)\n\tdefer cancel()\n\n\tif p.MaxReceiveSize > 0 {\n\t\topts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(int(p.MaxReceiveSize))))\n\t}\n\n\tif p.MaxSendSize > 0 {\n\t\topts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(int(p.MaxSendSize))))\n\t}\n\n\tif p.Authority != \"\" {\n\t\topts = append(opts, grpc.WithAuthority(p.Authority))\n\t}\n\n\tc.addr = addr\n\tc.conn, err = grpcext.Dial(ctx, addr, c.types, opts...)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tif !p.UseReflectionProtocol {\n\t\treturn true, nil\n\t}\n\n\tctx = metadata.NewOutgoingContext(ctx, p.ReflectionMetadata)\n\n\tfdset, err := c.conn.Reflect(ctx)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\t_, err = c.convertToMethodInfo(fdset)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"can't convert method info: %w\", err)\n\t}\n\n\treturn true, err\n}\n\n// HealthCheck checks if the server side is up and ready to serve responses\nfunc (c *Client) HealthCheck(svc *string) (*grpcext.HealthCheckResponse, error) {\n\tvar service string\n\tif svc != nil {\n\t\tservice = *svc\n\t}\n\treturn c.conn.HealthCheck(c.vu.Context(), service)\n}\n\n// Invoke creates and calls a unary RPC by fully qualified method name\nfunc (c *Client) Invoke(\n\tmethod string,\n\treq sobek.Value,\n\tparams sobek.Value,\n) (*grpcext.InvokeResponse, error) {\n\tgrpcReq, err := c.buildInvokeRequest(method, req, params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn c.conn.Invoke(c.vu.Context(), grpcReq)\n}\n\n// AsyncInvoke creates and calls a unary RPC by fully qualified method name asynchronously\nfunc (c *Client) AsyncInvoke(\n\tmethod string,\n\treq sobek.Value,\n\tparams sobek.Value,\n) (*sobek.Promise, error) {\n\tgrpcReq, err := c.buildInvokeRequest(method, req, params)\n\n\tpromise, resolve, reject := c.vu.Runtime().NewPromise()\n\tif err != nil {\n\t\terr = reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := c.vu.RegisterCallback()\n\tgo func() {\n\t\tres, err := c.conn.Invoke(c.vu.Context(), grpcReq)\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\t\t\treturn resolve(res)\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// buildInvokeRequest creates a new InvokeRequest from the given method name, request object and parameters\nfunc (c *Client) buildInvokeRequest(\n\tmethod string,\n\treq sobek.Value,\n\tparams sobek.Value,\n) (grpcext.InvokeRequest, error) {\n\tgrpcReq := grpcext.InvokeRequest{}\n\n\tstate := c.vu.State()\n\tif state == nil {\n\t\treturn grpcReq, common.NewInitContextError(\"invoking RPC methods in the init context is not supported\")\n\t}\n\tif c.conn == nil {\n\t\treturn grpcReq, errors.New(\"no gRPC connection, you must call connect first\")\n\t}\n\tif method == \"\" {\n\t\treturn grpcReq, errors.New(\"method to invoke cannot be empty\")\n\t}\n\tif method[0] != '/' {\n\t\tmethod = \"/\" + method\n\t}\n\tmethodDesc := c.mds[method]\n\tif methodDesc == nil {\n\t\treturn grpcReq, fmt.Errorf(\"method %q not found in file descriptors\", method)\n\t}\n\n\tp, err := newCallParams(c.vu, params)\n\tif err != nil {\n\t\treturn grpcReq, fmt.Errorf(\"invalid GRPC's client.invoke() parameters: %w\", err)\n\t}\n\n\t// k6 GRPC Invoke's default timeout is 2 minutes\n\tif p.Timeout == time.Duration(0) {\n\t\tp.Timeout = 2 * time.Minute\n\t}\n\n\tif req == nil {\n\t\treturn grpcReq, errors.New(\"request cannot be nil\")\n\t}\n\n\tobject := req.ToObject(c.vu.Runtime())\n\n\tvar stack []*sobek.Object\n\tnormalized, err := normalizeNumberStrings(object, c.vu.Runtime(), stack)\n\tif err != nil {\n\t\treturn grpcReq, fmt.Errorf(\"unable to normalize number strings: %w\", err)\n\t}\n\n\tb, err := normalized.ToObject(c.vu.Runtime()).MarshalJSON()\n\tif err != nil {\n\t\treturn grpcReq, fmt.Errorf(\"unable to serialise request object: %w\", err)\n\t}\n\n\tp.SetSystemTags(state, c.addr, method)\n\n\treturn grpcext.InvokeRequest{\n\t\tMethod:                 method,\n\t\tMethodDescriptor:       methodDesc,\n\t\tTimeout:                p.Timeout,\n\t\tDiscardResponseMessage: p.DiscardResponseMessage,\n\t\tMessage:                b,\n\t\tTagsAndMeta:            &p.TagsAndMeta,\n\t\tMetadata:               p.Metadata,\n\t}, nil\n}\n\n// normalizeNumberStrings recursively traverses a sobek.Value. It creates a deep copy of any\n// objects or arrays, and converts special float values (NaN, Infinity) to their\n// string representations for proper JSON serialization.\nfunc normalizeNumberStrings(v sobek.Value, runtime *sobek.Runtime, stack []*sobek.Object) (sobek.Value, error) {\n\t// If v is a primitive (not an object or array), handle it directly.\n\tif common.IsNullish(v) {\n\t\treturn v, nil\n\t}\n\n\t// Handle special float values.\n\tif v.ExportType().Kind() == reflect.Float64 {\n\t\tf := v.ToFloat()\n\t\tswitch {\n\t\tcase math.IsNaN(f):\n\t\t\treturn runtime.ToValue(\"NaN\"), nil\n\t\tcase math.IsInf(f, 1):\n\t\t\treturn runtime.ToValue(\"Infinity\"), nil\n\t\tcase math.IsInf(f, -1):\n\t\t\treturn runtime.ToValue(\"-Infinity\"), nil\n\t\t}\n\n\t\treturn v, nil\n\t}\n\n\tobj := v.ToObject(runtime)\n\n\t// If it's not a real object (e.g., a string, bool, or regular number primitive),\n\t// after checking for special floats, we can just return it.\n\t// We use obj.ClassName() to distinguish real objects from primitive wrappers.\n\tclassName := obj.ClassName()\n\tif className != \"Object\" && className != \"Array\" {\n\t\treturn v, nil\n\t}\n\n\t// Similar to what's done when marshaling into JSON,\n\t// detect and prevent infinite recursion due to circular object references.\n\tfor _, vis := range stack {\n\t\tif obj.SameAs(vis) {\n\t\t\treturn nil, errors.New(\"cyclic reference to an object found\")\n\t\t}\n\t}\n\tstack = append(stack, obj)\n\n\t// It's a real object or array, so we need to deep-copy and normalize it.\n\tvar newObj *sobek.Object\n\tif className == \"Array\" {\n\t\tnewObj = runtime.NewArray()\n\t} else {\n\t\tnewObj = runtime.NewObject()\n\t}\n\n\tfor _, key := range obj.Keys() {\n\t\tval := obj.Get(key)\n\t\tnormalizedVal, err := normalizeNumberStrings(val, runtime, stack)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif err := newObj.Set(key, normalizedVal); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn newObj, nil\n}\n\n// Close will close the client gRPC connection\nfunc (c *Client) Close() error {\n\tif c.conn == nil {\n\t\treturn nil\n\t}\n\terr := c.conn.Close()\n\tc.conn = nil\n\n\treturn err\n}\n\n// MethodInfo holds information on any parsed method descriptors that can be used by the Sobek VM\ntype MethodInfo struct {\n\tPackage         string\n\tService         string\n\tFullMethod      string\n\tgrpc.MethodInfo `json:\"-\" js:\"-\"`\n}\n\nfunc (c *Client) convertToMethodInfo(fdset *descriptorpb.FileDescriptorSet) ([]MethodInfo, error) {\n\tfiles, err := protodesc.NewFiles(fdset)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar rtn []MethodInfo\n\tif c.mds == nil {\n\t\t// This allows us to call load() multiple times, without overwriting the\n\t\t// previously loaded definitions.\n\t\tc.mds = make(map[string]protoreflect.MethodDescriptor)\n\t}\n\tappendMethodInfo := func(\n\t\tfd protoreflect.FileDescriptor,\n\t\tsd protoreflect.ServiceDescriptor,\n\t\tmd protoreflect.MethodDescriptor,\n\t) {\n\t\tname := fmt.Sprintf(\"/%s/%s\", sd.FullName(), md.Name())\n\t\tc.mds[name] = md\n\t\trtn = append(rtn, MethodInfo{\n\t\t\tMethodInfo: grpc.MethodInfo{\n\t\t\t\tName:           string(md.Name()),\n\t\t\t\tIsClientStream: md.IsStreamingClient(),\n\t\t\t\tIsServerStream: md.IsStreamingServer(),\n\t\t\t},\n\t\t\tPackage:    string(fd.Package()),\n\t\t\tService:    string(sd.Name()),\n\t\t\tFullMethod: name,\n\t\t})\n\t}\n\n\t// We want to avoid concurrent calls to client.load competing\n\t// for registering types, as they may end up panicking if they\n\t// try to register the same types.\n\tc.typesMtx.Lock()\n\tdefer c.typesMtx.Unlock()\n\n\tfiles.RangeFiles(func(fd protoreflect.FileDescriptor) bool {\n\t\tsds := fd.Services()\n\t\tfor i := 0; i < sds.Len(); i++ {\n\t\t\tsd := sds.Get(i)\n\t\t\tmds := sd.Methods()\n\t\t\tfor j := 0; j < mds.Len(); j++ {\n\t\t\t\tmd := mds.Get(j)\n\t\t\t\tappendMethodInfo(fd, sd, md)\n\t\t\t}\n\t\t}\n\n\t\tmessages := fd.Messages()\n\n\t\tstack := make([]protoreflect.MessageDescriptor, 0, messages.Len())\n\t\tfor i := 0; i < messages.Len(); i++ {\n\t\t\tstack = append(stack, messages.Get(i))\n\t\t}\n\n\t\tfor len(stack) > 0 {\n\t\t\tmessage := stack[len(stack)-1]\n\t\t\tstack = stack[:len(stack)-1]\n\n\t\t\t_, errFind := c.types.FindMessageByName(message.FullName())\n\t\t\tif errors.Is(errFind, protoregistry.NotFound) {\n\t\t\t\terr = c.types.RegisterMessage(dynamicpb.NewMessageType(message))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnested := message.Messages()\n\t\t\tfor i := 0; i < nested.Len(); i++ {\n\t\t\t\tstack = append(stack, nested.Get(i))\n\t\t\t}\n\t\t}\n\n\t\treturn true\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn rtn, nil\n}\n\n// walkFileDescriptors recursively walks through a file descriptor and its dependencies,\n// converting them to FileDescriptorProto.\n// This ensures that all dependencies are included in the FileDescriptorSet.\nfunc walkFileDescriptors(seen map[string]struct{}, fd protoreflect.FileDescriptor) []*descriptorpb.FileDescriptorProto {\n\tfds := []*descriptorpb.FileDescriptorProto{}\n\n\tif _, ok := seen[fd.Path()]; ok {\n\t\treturn fds\n\t}\n\tseen[fd.Path()] = struct{}{}\n\tfds = append(fds, protodesc.ToFileDescriptorProto(fd))\n\n\timports := fd.Imports()\n\tfor i := 0; i < imports.Len(); i++ {\n\t\tdep := imports.Get(i).FileDescriptor\n\t\tdeps := walkFileDescriptors(seen, dep)\n\t\tfds = append(fds, deps...)\n\t}\n\treturn fds\n}\n\n// sanitizeMethodName\nfunc sanitizeMethodName(name string) string {\n\tif name == \"\" {\n\t\treturn name\n\t}\n\n\tif !strings.HasPrefix(name, \"/\") {\n\t\tname = \"/\" + name\n\t}\n\n\treturn name\n}\n\n// getMethodDescriptor sanitize it, and gets GRPC method descriptor or an error if not found\nfunc (c *Client) getMethodDescriptor(method string) (protoreflect.MethodDescriptor, error) {\n\tmethod = sanitizeMethodName(method)\n\n\tif method == \"\" {\n\t\treturn nil, errors.New(\"method to invoke cannot be empty\")\n\t}\n\n\tmethodDesc := c.mds[method]\n\n\tif methodDesc == nil {\n\t\treturn nil, fmt.Errorf(\"method %q not found in file descriptors\", method)\n\t}\n\n\treturn methodDesc, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/client_test.go",
    "content": "package grpc_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\tk6grpc \"go.k6.io/k6/internal/js/modules/k6/grpc\"\n\t\"go.k6.io/k6/internal/lib/netext/grpcext\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\tgrpcanytesting \"go.k6.io/k6/internal/lib/testutils/httpmultibin/grpc_any_testing\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin/grpc_testing\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin/grpc_wrappers_testing\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/health\"\n\thealthgrpc \"google.golang.org/grpc/health/grpc_health_v1\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/reflection\"\n\tv1alphagrpc \"google.golang.org/grpc/reflection/grpc_reflection_v1alpha\"\n\tgrpcstats \"google.golang.org/grpc/stats\"\n\t\"google.golang.org/grpc/status\"\n\n\t\"github.com/golang/protobuf/ptypes/any\"\n\t_struct \"github.com/golang/protobuf/ptypes/struct\"\n\t\"github.com/golang/protobuf/ptypes/wrappers\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/known/wrapperspb\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestClient(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []testcase{\n\t\t{\n\t\t\tname: \"BadTLS\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\t// changing the pointer's value\n\t\t\t\t// for affecting the lib.State\n\t\t\t\t// that uses the same pointer\n\t\t\t\t*tb.TLSClientConfig = tls.Config{\n\t\t\t\t\tMinVersion: tls.VersionTLS13,\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {timeout: '1s'})`,\n\t\t\t\terr:  \"certificate signed by unknown authority\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"New\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tif (!client) throw new Error(\"no client created\")`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"LoadNotFound\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.load([], \"./does_not_exist.proto\");`,\n\t\t\t\terr: \"no such file or directory\",\n\t\t\t\t// (rogchap) this is a bit of a hack as windows reports a different system error than unix.\n\t\t\t\twindowsErr: \"The system cannot find the file specified\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Load\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t\tval: []k6grpc.MethodInfo{{MethodInfo: grpc.MethodInfo{Name: \"EmptyCall\", IsClientStream: false, IsServerStream: false}, Package: \"grpc.testing\", Service: \"TestService\", FullMethod: \"/grpc.testing.TestService/EmptyCall\"}, {MethodInfo: grpc.MethodInfo{Name: \"UnaryCall\", IsClientStream: false, IsServerStream: false}, Package: \"grpc.testing\", Service: \"TestService\", FullMethod: \"/grpc.testing.TestService/UnaryCall\"}, {MethodInfo: grpc.MethodInfo{Name: \"StreamingOutputCall\", IsClientStream: false, IsServerStream: true}, Package: \"grpc.testing\", Service: \"TestService\", FullMethod: \"/grpc.testing.TestService/StreamingOutputCall\"}, {MethodInfo: grpc.MethodInfo{Name: \"StreamingInputCall\", IsClientStream: true, IsServerStream: false}, Package: \"grpc.testing\", Service: \"TestService\", FullMethod: \"/grpc.testing.TestService/StreamingInputCall\"}, {MethodInfo: grpc.MethodInfo{Name: \"FullDuplexCall\", IsClientStream: true, IsServerStream: true}, Package: \"grpc.testing\", Service: \"TestService\", FullMethod: \"/grpc.testing.TestService/FullDuplexCall\"}, {MethodInfo: grpc.MethodInfo{Name: \"HalfDuplexCall\", IsClientStream: true, IsServerStream: true}, Package: \"grpc.testing\", Service: \"TestService\", FullMethod: \"/grpc.testing.TestService/HalfDuplexCall\"}},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"LoadProtosetNotFound\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.loadProtoset(\"./does_not_exist.protoset\");`,\n\t\t\t\terr: \"couldn't open protoset\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"LoadProtosetWrongFormat\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.loadProtoset(\"../../../../lib/testutils/httpmultibin/grpc_protoset_testing/test_message.proto\");`,\n\t\t\t\terr: \"couldn't unmarshal protoset\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"LoadProtoset\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.loadProtoset(\"../../../../lib/testutils/httpmultibin/grpc_protoset_testing/test.protoset\");`,\n\t\t\t\tval: []k6grpc.MethodInfo{\n\t\t\t\t\t{\n\t\t\t\t\t\tMethodInfo: grpc.MethodInfo{Name: \"Test\", IsClientStream: false, IsServerStream: false},\n\t\t\t\t\t\tPackage:    \"grpc.protoset.testing\", Service: \"TestService\", FullMethod: \"/grpc.protoset.testing.TestService/Test\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectInit\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");\n\t\t\tclient.connect();`,\n\t\t\t\terr: \"connecting to a gRPC server in the init context is not supported\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeInit\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");\n\t\t\tvar err = client.invoke();\n\t\t\tthrow new Error(err)`,\n\t\t\t\terr: \"invoking RPC methods in the init context is not supported\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"NoConnect\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {})`,\n\t\t\t\terr: \"invoking RPC methods in the init context is not supported\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"UnknownConnectParam\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", { name: \"k6\" });`,\n\t\t\t\terr:  `unknown connect param: \"name\"`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectInvalidTimeout\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", { timeout: \"k6\" });`,\n\t\t\t\terr:  \"invalid duration\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectStringTimeout\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{code: `client.connect(\"GRPCBIN_ADDR\", { timeout: \"1h3s\" });`},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectIntegerTimeout\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{code: `client.connect(\"GRPCBIN_ADDR\", { timeout: 3000 });`},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectFloatTimeout\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{code: `client.connect(\"GRPCBIN_ADDR\", { timeout: 3456.3 });`},\n\t\t},\n\t\t{\n\t\t\tname: \"Connect\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{code: `client.connect(\"GRPCBIN_ADDR\");`},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeNotFound\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"foo/bar\", {})`,\n\t\t\t\terr: `method \"/foo/bar\" not found in file descriptors`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeInvalidParam\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { void: true })`,\n\t\t\t\terr: `unknown param: \"void\"`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"AsyncInvokeInvalidParam\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.asyncInvoke(\"grpc.testing.TestService/EmptyCall\", {}, { void: true }).then(function(resp) {\n\t\t\t\t\tthrow new Error(\"should not be here\")\n\t\t\t\t}, (err) => {\n\t\t\t\t\tthrow new Error(err)\n\t\t\t\t})`,\n\t\t\t\terr: `unknown param: \"void\"`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeNilRequest\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\")`,\n\t\t\t\terr: `request cannot be nil`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeInvalidTimeoutType\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { timeout: true })`,\n\t\t\t\terr: \"invalid timeout value: unable to use type bool as a duration value\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeInvalidTimeout\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { timeout: \"please\" })`,\n\t\t\t\terr: \"invalid duration\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeStringTimeout\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { timeout: \"1h42m\" })`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeFloatTimeout\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { timeout: 400.50 })`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeIntegerTimeout\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { timeout: 2000 })`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeDiscardResponseMessage\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { discardResponseMessage: true })`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Invoke\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(context.Context, *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \"or status: \" + resp.status)\n\t\t\t\t}`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeDiscardResponseMessage\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(context.Context, *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { discardResponseMessage: true })\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \"or status: \" + resp.status)\n\t\t\t\t}\n\t\t\t\tif (resp.message !== null) {\n\t\t\t\t\tthrow new Error(\"unexpected message: \" + JSON.stringify(resp.message))\n\t\t\t\t}`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"AsyncInvoke\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(context.Context, *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.asyncInvoke(\"grpc.testing.TestService/EmptyCall\", {}).then(function(resp) {\n\t\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \"or status: \" + resp.status)\n\t\t\t\t\t}\n\t\t\t\t}, (err) => {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + err)\n\t\t\t\t})\n\t\t\t\t`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"AsyncInvokeDiscardResponseMessage\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(context.Context, *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.asyncInvoke(\"grpc.testing.TestService/EmptyCall\", {}, { discardResponseMessage: true }).then(function(resp) {\n\t\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \"or status: \" + resp.status)\n\t\t\t\t\t}\n\t\t\t\t\tif (resp.message !== null) {\n\t\t\t\t\t\tthrow new Error(\"unexpected message: \" + JSON.stringify(resp.message))\n\t\t\t\t\t}\n\t\t\t\t}, (err) => {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + err)\n\t\t\t\t})\n\t\t\t\t`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"InvokeAnyProto\",\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_any_testing/any_test.proto\");`},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCAnyStub.SumFunc = func(_ context.Context, req *grpcanytesting.SumRequest) (*grpcanytesting.SumReply, error) {\n\t\t\t\t\tvar sumRequestData grpcanytesting.SumRequestData\n\t\t\t\t\tif err := req.Data.UnmarshalTo(&sumRequestData); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\n\t\t\t\t\tsumReplyData := &grpcanytesting.SumReplyData{\n\t\t\t\t\t\tV:   sumRequestData.A + sumRequestData.B,\n\t\t\t\t\t\tErr: \"\",\n\t\t\t\t\t}\n\t\t\t\t\tsumReply := &grpcanytesting.SumReply{\n\t\t\t\t\t\tData: &any.Any{},\n\t\t\t\t\t}\n\t\t\t\t\tif err := sumReply.Data.MarshalFrom(sumReplyData); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\n\t\t\t\t\treturn sumReply, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.any.testing.AnyTestService/Sum\",  {\n\t\t\t\t\tdata: {\n\t\t\t\t\t\t\"@type\": \"type.googleapis.com/grpc.any.testing.SumRequestData\",\n\t\t\t\t\t\t\"a\": 1,\n\t\t\t\t\t\t\"b\": 2,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \"or status: \" + resp.status)\n\t\t\t\t}\n\t\t\t\tif (resp.message.data.v !== \"3\") {\n\t\t\t\t\tthrow new Error(\"unexpected resp message data\")\n\t\t\t\t}`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.any.testing.AnyTestService/Sum\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"RequestMessage\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.UnaryCallFunc = func(_ context.Context, req *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) {\n\t\t\t\t\tif req.Payload == nil || string(req.Payload.Body) != \"负载测试\" {\n\t\t\t\t\t\treturn nil, status.Error(codes.InvalidArgument, \"\")\n\t\t\t\t\t}\n\t\t\t\t\treturn &grpc_testing.SimpleResponse{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{code: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/UnaryCall\", { payload: { body: \"6LSf6L295rWL6K+V\"} })\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"server did not receive the correct request message\")\n\t\t\t\t}`},\n\t\t},\n\t\t{\n\t\t\tname: \"AsyncRequestMessage\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.UnaryCallFunc = func(_ context.Context, req *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) {\n\t\t\t\t\tif req.Payload == nil || string(req.Payload.Body) != \"负载测试\" {\n\t\t\t\t\t\treturn nil, status.Error(codes.InvalidArgument, \"\")\n\t\t\t\t\t}\n\t\t\t\t\treturn &grpc_testing.SimpleResponse{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{code: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.asyncInvoke(\"grpc.testing.TestService/UnaryCall\", { payload: { body: \"6LSf6L295rWL6K+V\"} }).then(function(resp) {\n\t\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\t\tthrow new Error(\"server did not receive the correct request message\")\n\t\t\t\t\t}\n\t\t\t\t}, (err) => {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + err)\n\t\t\t\t});\n\t\t\t\t`},\n\t\t},\n\t\t{\n\t\t\tname: \"RequestHeaders\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(ctx context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\tmd, ok := metadata.FromIncomingContext(ctx)\n\t\t\t\t\tif !ok || len(md[\"x-load-tester\"]) == 0 || md[\"x-load-tester\"][0] != \"k6\" {\n\t\t\t\t\t\treturn nil, status.Error(codes.FailedPrecondition, \"\")\n\t\t\t\t\t}\n\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{code: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { metadata: { \"X-Load-Tester\": \"k6\" } })\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"failed to send correct headers in the request\")\n\t\t\t\t}\n\t\t\t`},\n\t\t},\n\t\t{\n\t\t\tname: \"RequestBinHeaders\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(ctx context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\tmd, ok := metadata.FromIncomingContext(ctx)\n\t\t\t\t\tif !ok || len(md[\"x-load-tester-bin\"]) == 0 || md[\"x-load-tester-bin\"][0] != string([]byte{2, 200}) {\n\t\t\t\t\t\treturn nil, status.Error(codes.FailedPrecondition, \"\")\n\t\t\t\t\t}\n\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{code: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { metadata: { \"X-Load-Tester-bin\": new Uint8Array([2, 200]) } })\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"failed to send correct headers in the request\")\n\t\t\t\t}\n\t\t\t`},\n\t\t},\n\t\t{\n\t\t\tname: \"ResponseMessage\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.UnaryCallFunc = func(context.Context, *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) {\n\t\t\t\t\treturn &grpc_testing.SimpleResponse{\n\t\t\t\t\t\tOauthScope: \"水\",\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/UnaryCall\", {})\n\t\t\t\tif (!resp.message || resp.message.username !== \"\" || resp.message.oauthScope !== \"水\") {\n\t\t\t\t\tthrow new Error(\"unexpected response message: \" + JSON.stringify(resp.message))\n\t\t\t\t}`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/UnaryCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"AsyncResponseMessage\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.UnaryCallFunc = func(context.Context, *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) {\n\t\t\t\t\treturn &grpc_testing.SimpleResponse{\n\t\t\t\t\t\tOauthScope: \"水\",\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tclient.asyncInvoke(\"grpc.testing.TestService/UnaryCall\", {}).then(function(resp) {\n\t\t\t\t\tif (!resp.message || resp.message.username !== \"\" || resp.message.oauthScope !== \"水\") {\n\t\t\t\t\t\tthrow new Error(\"unexpected response message: \" + JSON.stringify(resp.message))\n\t\t\t\t\t}\n\t\t\t\t}, (err) => {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + err)\n\t\t\t\t});\n\t\t\t\t`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/UnaryCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ResponseError\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(context.Context, *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn nil, status.Error(codes.DataLoss, \"foobar\")\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\tif (resp.status !== grpc.StatusDataLoss) {\n\t\t\t\t\tthrow new Error(\"unexpected error status: \" + resp.status)\n\t\t\t\t}\n\t\t\t\tif (!resp.error || resp.error.message !== \"foobar\" || resp.error.code !== 15) {\n\t\t\t\t\tthrow new Error(\"unexpected error object: \" + JSON.stringify(resp.error.code))\n\t\t\t\t}`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ResponseHeaders\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(ctx context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\tmd := metadata.Pairs(\"foo\", \"bar\")\n\t\t\t\t\t_ = grpc.SetHeader(ctx, md)\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"unexpected error status: \" + resp.status)\n\t\t\t\t}\n\t\t\t\tif (!resp.headers || !resp.headers[\"foo\"] || resp.headers[\"foo\"][0] !== \"bar\") {\n\t\t\t\t\tthrow new Error(\"unexpected headers object: \" + JSON.stringify(resp.trailers))\n\t\t\t\t}`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ResponseTrailers\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(ctx context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\tmd := metadata.Pairs(\"foo\", \"bar\")\n\t\t\t\t\t_ = grpc.SetTrailer(ctx, md)\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"unexpected error status: \" + resp.status)\n\t\t\t\t}\n\t\t\t\tif (!resp.trailers || !resp.trailers[\"foo\"] || resp.trailers[\"foo\"][0] !== \"bar\") {\n\t\t\t\t\tthrow new Error(\"unexpected trailers object: \" + JSON.stringify(resp.trailers))\n\t\t\t\t}`,\n\t\t\t\tasserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) {\n\t\t\t\t\tsamplesBuf := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace(\"GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall\"))\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"LoadNotInit\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(ctx context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\tmd := metadata.Pairs(\"foo\", \"bar\")\n\t\t\t\t\t_ = grpc.SetTrailer(ctx, md)\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.load()`,\n\t\t\t\terr:  \"load must be called in the init context\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReflectUnregistered\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {reflect: true})`,\n\t\t\t\terr:  \"rpc error: code = Unimplemented desc = unknown service grpc.reflection.v1alpha.ServerReflection\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Reflect\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {reflect: true})`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReflectV1\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.RegisterV1(tb.ServerGRPC)\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {reflect: true})`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReflectBadParam\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {reflect: \"true\"})`,\n\t\t\t\terr:  `invalid reflect value`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReflectInvokeNoExist\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(_ context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {reflect: true})\n\t\t\t\t\tclient.invoke(\"foo/bar\", {})\n\t\t\t\t`,\n\t\t\t\terr: `method \"/foo/bar\" not found in file descriptors`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReflectInvoke\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\t// this register both reflection APIs v1 and v1alpha\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(_ context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {reflect: true})\n\t\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReflectV1Alpha_Invoke\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\t// this register only v1alpha (this could be removed with removal v1alpha from grpc-go)\n\t\t\t\ts := tb.ServerGRPC\n\t\t\t\tsvr := reflection.NewServer(reflection.ServerOptions{Services: s})\n\t\t\t\tv1alphagrpc.RegisterServerReflectionServer(s, svr)\n\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(_ context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {reflect: true})\n\t\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReflectV1Invoke\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\t// this register only reflection APIs v1\n\t\t\t\treflection.RegisterV1(tb.ServerGRPC)\n\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(_ context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {reflect: true})\n\t\t\t\t\tclient.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"MaxReceiveSizeBadParam\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {maxReceiveSize: \"error\"})`,\n\t\t\t\terr:  `invalid maxReceiveSize value: '\"error\"', it needs to be an integer`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"MaxReceiveSizeNonPositiveInteger\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {maxReceiveSize: -1})`,\n\t\t\t\terr:  `invalid maxReceiveSize value: '-1, it needs to be a positive integer`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ReceivedMessageLargerThanMax\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.UnaryCallFunc = func(_ context.Context, req *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) {\n\t\t\t\t\tresponse := &grpc_testing.SimpleResponse{}\n\t\t\t\t\tresponse.Payload = req.Payload\n\t\t\t\t\treturn response, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {maxReceiveSize: 1})\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/UnaryCall\", { payload: { body: \"testMaxReceiveSize\"} })\n\t\t\t\tif (resp.status == grpc.StatusResourceExhausted) {\n\t\t\t\t\tthrow new Error(resp.error.message)\n\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\terr: `received message larger than max`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"MaxSendSizeBadParam\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {maxSendSize: \"error\"})`,\n\t\t\t\terr:  `invalid maxSendSize value: '\"error\"', it needs to be an integer`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"MaxSendSizeNonPositiveInteger\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `var client = new grpc.Client();`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {maxSendSize: -1})`,\n\t\t\t\terr:  `invalid maxSendSize value: '-1, it needs to be a positive integer`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"SentMessageLargerThanMax\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\ttb.GRPCStub.UnaryCallFunc = func(context.Context, *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) {\n\t\t\t\t\treturn &grpc_testing.SimpleResponse{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {maxSendSize: 1})\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/UnaryCall\", { payload: { body: \"testMaxSendSize\"} })\n\t\t\t\tif (resp.status == grpc.StatusResourceExhausted) {\n\t\t\t\t\tthrow new Error(resp.error.message)\n\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\terr: `trying to send message larger than max`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Close\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\tclient.close();\n\t\t\tclient.invoke();`,\n\t\t\t\terr: \"no gRPC connection\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Wrappers\",\n\t\t\tsetup: func(hb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tsrv := grpc_wrappers_testing.Register(hb.ServerGRPC)\n\n\t\t\t\tsrv.TestStringImplementation = func(_ context.Context, sv *wrappers.StringValue) (*wrappers.StringValue, error) {\n\t\t\t\t\treturn &wrapperspb.StringValue{\n\t\t\t\t\t\tValue: \"hey \" + sv.Value,\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tconst client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_wrappers_testing/test.proto\");\n\t\t\t\t`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\n\t\t\t\tlet respString = client.invoke(\"grpc.wrappers.testing.Service/TestString\", \"John\")\n\t\t\t\tif (respString.message !== \"hey John\") {\n\t\t\t\t\tthrow new Error(\"expected to get 'hey John', but got a \" + respString.message)\n\t\t\t\t}\n\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"WrappersWithReflection\",\n\t\t\tsetup: func(hb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(hb.ServerGRPC)\n\n\t\t\t\tsrv := grpc_wrappers_testing.Register(hb.ServerGRPC)\n\n\t\t\t\tsrv.TestIntegerImplementation = func(_ context.Context, iv *wrappers.Int64Value) (*wrappers.Int64Value, error) {\n\t\t\t\t\treturn &wrappers.Int64Value{\n\t\t\t\t\t\tValue: 2 * iv.Value,\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\n\t\t\t\tsrv.TestStringImplementation = func(_ context.Context, sv *wrappers.StringValue) (*wrappers.StringValue, error) {\n\t\t\t\t\treturn &wrapperspb.StringValue{\n\t\t\t\t\t\tValue: \"hey \" + sv.Value,\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\n\t\t\t\tsrv.TestBooleanImplementation = func(_ context.Context, bv *wrappers.BoolValue) (*wrappers.BoolValue, error) {\n\t\t\t\t\treturn &wrapperspb.BoolValue{\n\t\t\t\t\t\tValue: bv.Value != true,\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\n\t\t\t\tsrv.TestDoubleImplementation = func(_ context.Context, bv *wrappers.DoubleValue) (*wrappers.DoubleValue, error) {\n\t\t\t\t\treturn &wrapperspb.DoubleValue{\n\t\t\t\t\t\tValue: bv.Value * 2,\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tconst client = new grpc.Client();\n\t\t\t\t`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {reflect: true});\n\n\t\t\t\tlet respString = client.invoke(\"grpc.wrappers.testing.Service/TestString\", \"John\")\n\t\t\t\tif (respString.message !== \"hey John\") {\n\t\t\t\t\tthrow new Error(\"expected to get 'hey John', but got a \" + respString.message)\n\t\t\t\t}\n\n\t\t\t\tlet respInt = client.invoke(\"grpc.wrappers.testing.Service/TestInteger\", \"3\")\n\t\t\t\tif (respInt.message !== \"6\") {\n\t\t\t\t\tthrow new Error(\"expected to get '6', but got a \" + respInt.message)\n\t\t\t\t}\n\n\t\t\t\tlet respDouble = client.invoke(\"grpc.wrappers.testing.Service/TestDouble\", \"2.7\")\n\t\t\t\tif (respDouble.message !== 5.4) {\n\t\t\t\t\tthrow new Error(\"expected to get '5.4', but got a \" + respDouble.message)\n\t\t\t\t}\n\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ValueReflection\",\n\t\t\tsetup: func(hb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(hb.ServerGRPC)\n\n\t\t\t\tsrv := grpc_wrappers_testing.Register(hb.ServerGRPC)\n\n\t\t\t\tsrv.TestValueImplementation = func(_ context.Context, in *_struct.Value) (*_struct.Value, error) {\n\t\t\t\t\tif in.GetNumberValue() == 12 {\n\t\t\t\t\t\treturn &_struct.Value{\n\t\t\t\t\t\t\tKind: &_struct.Value_NumberValue{\n\t\t\t\t\t\t\t\tNumberValue: 42,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}, nil\n\t\t\t\t\t}\n\n\t\t\t\t\tif in.GetStringValue() != \"\" {\n\t\t\t\t\t\treturn &_struct.Value{\n\t\t\t\t\t\t\tKind: &_struct.Value_StringValue{\n\t\t\t\t\t\t\t\tStringValue: \"hey \" + in.GetStringValue(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}, nil\n\t\t\t\t\t}\n\n\t\t\t\t\treturn &_struct.Value{\n\t\t\t\t\t\tKind: &_struct.Value_StringValue{\n\t\t\t\t\t\t\tStringValue: \"I don't know what to answer\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tconst client = new grpc.Client();\n\t\t\t\t`,\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", {reflect: true});\n\n\t\t\t\tlet respString = client.invoke(\"grpc.wrappers.testing.Service/TestValue\", \"John\")\n\t\t\t\tif (respString.message !== \"hey John\") {\n\t\t\t\t\tthrow new Error(\"expected to get 'hey John', but got a \" + respString.message)\n\t\t\t\t}\n\n\t\t\t\tlet respNumber = client.invoke(\"grpc.wrappers.testing.Service/TestValue\", 12)\n\t\t\t\tif (respNumber.message !== 42) {\n\t\t\t\t\tthrow new Error(\"expected to get '42', but got a \" + respNumber.message)\n\t\t\t\t}\n\n\t\t\t\tlet respBool = client.invoke(\"grpc.wrappers.testing.Service/TestValue\", false)\n\t\t\t\tif (respBool.message !== \"I don't know what to answer\") {\n\t\t\t\t\tthrow new Error(\"expected to get 'I don't know what to answer', but got a \" + respBool.message)\n\t\t\t\t}\n\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"WrappersSpecialNumberValues\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_wrappers_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tsrv := grpc_wrappers_testing.Register(tb.ServerGRPC)\n\n\t\t\t\tsrv.TestDoubleImplementation = func(_ context.Context, in *wrappers.DoubleValue) (*wrappers.DoubleValue, error) {\n\t\t\t\t\tif math.IsNaN(in.Value) {\n\t\t\t\t\t\treturn &wrappers.DoubleValue{Value: math.NaN()}, nil\n\t\t\t\t\t}\n\t\t\t\t\tif math.IsInf(in.Value, -1) {\n\t\t\t\t\t\treturn &wrappers.DoubleValue{Value: math.Inf(-1)}, nil\n\t\t\t\t\t}\n\t\t\t\t\tif math.IsInf(in.Value, 1) {\n\t\t\t\t\t\treturn &wrappers.DoubleValue{Value: math.Inf(1)}, nil\n\t\t\t\t\t}\n\t\t\t\t\treturn &wrappers.DoubleValue{Value: in.Value}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\n\t\t\t\tlet respNaN = client.invoke(\"grpc.wrappers.testing.Service/TestDouble\", NaN);\n\t\t\t\tif (respNaN.message !== \"NaN\") {\n\t\t\t\t\tthrow new Error(\"expected to get 'NaN', but got a \" + respString.message)\n\t\t\t\t}\n\n\t\t\t\tlet respInfinity = client.invoke(\"grpc.wrappers.testing.Service/TestDouble\", Infinity);\n\t\t\t\tif (respInfinity.message !== \"Infinity\") {\n\t\t\t\t\tthrow new Error(\"expected to get 'Infinity', but got a \" + respString.message)\n\t\t\t\t}\n\n\t\t\t\tlet respNegativeInfinity = client.invoke(\"grpc.wrappers.testing.Service/TestDouble\", -Infinity);\n\t\t\t\tif (respNegativeInfinity.message !== \"-Infinity\") {\n\t\t\t\t\tthrow new Error(\"expected to get '-Infinity', but got a \" + respString.message)\n\t\t\t\t}\n\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ObjectCyclicReference\",\n\t\t\tinitString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_wrappers_testing/test.proto\");`,\n\t\t\t},\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\treflection.Register(tb.ServerGRPC)\n\t\t\t},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\n\t\t\t\tlet obj1 = {};\n\t\t\t\tlet obj2 = {};\n\t\t\t\tobj1.a = obj2;\n\t\t\t\tobj2.b = obj1;\n\n\t\t\t\tlet respNaN = client.invoke(\"grpc.wrappers.testing.Service/TestDouble\", obj1);\n\t\t\t\t`,\n\t\t\t\terr: \"cyclic reference to an object found\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"HealthCheckServing\",\n\t\t\tsetup: func(hb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tgrpcHealthSrv := health.NewServer()\n\t\t\t\thealthgrpc.RegisterHealthServer(hb.ServerGRPC, grpcHealthSrv)\n\t\t\t\tgrpcHealthSrv.SetServingStatus(\"\", healthgrpc.HealthCheckResponse_SERVING)\n\t\t\t},\n\t\t\tinitString: codeBlock{code: `var client = new grpc.Client();`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.healthCheck()\n\t\t\t\tif (resp.status !== grpc.HealthCheckServing) {\n\t\t\t\t\tthrow new Error(\"unexpected status: \" + resp.status)\n\t\t\t\t}`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"HealthCheckNotServing\",\n\t\t\tsetup: func(hb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tgrpcHealthSrv := health.NewServer()\n\t\t\t\thealthgrpc.RegisterHealthServer(hb.ServerGRPC, grpcHealthSrv)\n\t\t\t\tgrpcHealthSrv.SetServingStatus(\"\", healthgrpc.HealthCheckResponse_NOT_SERVING)\n\t\t\t},\n\t\t\tinitString: codeBlock{code: `var client = new grpc.Client();`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.healthCheck()\n\t\t\t\tif (resp.status !== grpc.HealthCheckNotServing) {\n\t\t\t\t\tthrow new Error(\"unexpected status: \" + resp.status)\n\t\t\t\t}`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"HealthCheckUnknown\",\n\t\t\tsetup: func(hb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tgrpcHealthSrv := health.NewServer()\n\t\t\t\thealthgrpc.RegisterHealthServer(hb.ServerGRPC, grpcHealthSrv)\n\t\t\t\tgrpcHealthSrv.SetServingStatus(\"\", healthgrpc.HealthCheckResponse_UNKNOWN)\n\t\t\t},\n\t\t\tinitString: codeBlock{code: `var client = new grpc.Client();`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\t\t\tvar resp = client.healthCheck()\n\t\t\t\tif (resp.status !== grpc.HealthCheckUnknown) {\n\t\t\t\t\tthrow new Error(\"unexpected status: \" + resp.status)\n\t\t\t\t}`,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := newTestState(t)\n\n\t\t\t// setup necessary environment if needed by a test\n\t\t\tif tt.setup != nil {\n\t\t\t\ttt.setup(ts.httpBin)\n\t\t\t}\n\n\t\t\tval, err := ts.Run(tt.initString.code)\n\t\t\tassertResponse(t, tt.initString, err, val, ts)\n\n\t\t\tts.ToVUContext()\n\t\t\tval, err = ts.RunOnEventLoop(tt.vuString.code)\n\t\t\tassertResponse(t, tt.vuString, err, val, ts)\n\t\t})\n\t}\n}\n\nfunc TestClient_TlsParameters(t *testing.T) {\n\tt.Parallel()\n\n\tclientAuthCA := []byte(\"-----BEGIN CERTIFICATE-----\\nMIIBWzCCAQGgAwIBAgIJAIQMBgLi+DV6MAoGCCqGSM49BAMCMBAxDjAMBgNVBAMM\\nBU15IENBMCAXDTIyMDEyMTEyMjkzNloYDzMwMjEwNTI0MTIyOTM2WjAQMQ4wDAYD\\nVQQDDAVNeSBDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHnrghULHa2hSa/C\\nWimwCn42KWdlPqd6/zs3JgLIxTvBHJJlfbhWbBqtybqyovWd3QykHMIpx0NZmpYn\\nG8FoWpmjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\\nDgQWBBSkukBA8lgFvvBJAYKsoSUR+PX71jAKBggqhkjOPQQDAgNIADBFAiEAiFF7\\nY54CMNRSBSVMgd4mQgrzJInRH88KpLsQ7VeOAaQCIEa0vaLln9zxIDZQKocml4Db\\nAEJr8tDzMKIds6sRTBT4\\n-----END CERTIFICATE-----\")\n\tclientAuth := \"-----BEGIN CERTIFICATE-----\\\\nMIIBVzCB/6ADAgECAgkAg/SeNG3XqB0wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwF\\\\nTXkgQ0EwIBcNMjIwMTIxMTUxMjM0WhgPMzAyMTA1MjQxNTEyMzRaMBExDzANBgNV\\\\nBAMMBmNsaWVudDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKM7OJQMYG4KLtDA\\\\ngZ8zOg2PimHMmQnjD2HtI4cSwIUJJnvHWLowbFe9fk6XeP9b3dK1ImUI++/EZdVr\\\\nABAcngejPzA9MA4GA1UdDwEB/wQEAwIBBjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW\\\\nBBSttJe1mcPEnBOZ6wvKPG4zL0m1CzAKBggqhkjOPQQDAgNHADBEAiBPSLgKA/r9\\\\nu/FW6W+oy6Odm1kdNMGCI472iTn545GwJgIgb3UQPOUTOj0IN4JLJYfmYyXviqsy\\\\nzk9eWNHFXDA9U6U=\\\\n-----END CERTIFICATE-----\"\n\tclientAuthKey := (\"-----BEGIN EC PRIVATE KEY-----\\\\nMHcCAQEEINDaMGkOT3thu1A0LfLJr3Jd011/aEG6OArmEQaujwgpoAoGCCqGSM49\\\\nAwEHoUQDQgAEozs4lAxgbgou0MCBnzM6DY+KYcyZCeMPYe0jhxLAhQkme8dYujBs\\\\nV71+Tpd4/1vd0rUiZQj778Rl1WsAEByeBw==\\\\n-----END EC PRIVATE KEY-----\")\n\tclientAuthKeyEncrypted := (\"-----BEGIN EC PRIVATE KEY-----\\\\nProc-Type: 4,ENCRYPTED\\\\nDEK-Info: AES-256-CBC,3E311E9B602231BFB5C752071EE7D652\\\\n\\\\nsAKeqbacug0v4ruE1A0CACwGVEGBQVOl1CiGVp5RsxgNZKXzMS6EsTTNLw378coF\\\\nKXbF+he05HIuzToOz2ANLXov1iCrVpotKVB4l2obTQvg+5VET902ky99Mc9Us7jd\\\\nUwW8LpXlSlhcNWuUfK6wyosL42TbcIxjqZWaESW+6ww=\\\\n-----END EC PRIVATE KEY-----\")\n\n\ttrivialKeyPassword := \"abc123\"\n\ttrivialWrongKeyPassword := \"abc321\"\n\n\t// We need the certificate actually used by the httpmultibin in this test\n\t// as it is the same one for all tests we can get it once here\n\t// This also prevents changes to this to break this test\n\t// as it happened after https://github.com/golang/go/commit/6783377295e0878aa3ad821eefe3d7879064df6d\n\tp := httpmultibin.NewHTTPMultiBin(t)\n\tlocalHostCert := strings.ReplaceAll(string(pem.EncodeToMemory(\n\t\t&pem.Block{\n\t\t\tType:  \"CERTIFICATE\",\n\t\t\tBytes: p.ServerHTTP2.TLS.Certificates[0].Certificate[0],\n\t\t})), \"\\n\", `\\n`)\n\n\ttests := []testcase{\n\t\t{\n\t\t\tname:       \"ConnectTlsEmptyTlsSuccess\",\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", { tls: { }});`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:       \"ConnectTlsInvalidTlsParamCertType\",\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", { tls: { cert: 0 }});`,\n\t\t\t\terr:  `invalid grpc.connect() parameters: invalid tls cert value: 'map[string]interface {}{\"cert\":0}', it needs to be a PEM formatted string`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:       \"ConnectTlsInvalidTlsParamKeyType\",\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", { tls: { cert: \"\", key: 0 }});`,\n\t\t\t\terr:  `invalid grpc.connect() parameters: invalid tls key value: 'map[string]interface {}{\"cert\":\"\", \"key\":0}', it needs to be a PEM formatted string`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:       \"ConnectTlsInvalidTlsParamPasswordType\",\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", { tls: { cert: \"\", key: \"\", password: 0 }});`,\n\t\t\t\terr:  `invalid grpc.connect() parameters: invalid tls password value: 'map[string]interface {}{\"cert\":\"\", \"key\":\"\", \"password\":0}', it needs to be a string`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:       \"ConnectTlsInvalidTlsParamCACertsType\",\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: `client.connect(\"GRPCBIN_ADDR\", { tls: { cert: \"\", key: \"\", cacerts: 0 }});`,\n\t\t\t\terr:  `invalid grpc.connect() parameters: invalid tls cacerts value: 'map[string]interface {}{\"cacerts\":0, \"cert\":\"\", \"key\":\"\"}', it needs to be a string or an array of PEM formatted strings`,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectTls\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tclientCAPool := x509.NewCertPool()\n\t\t\t\tclientCAPool.AppendCertsFromPEM(clientAuthCA)\n\t\t\t\ttb.ServerHTTP2.TLS.ClientAuth = tls.RequireAndVerifyClientCert\n\t\t\t\ttb.ServerHTTP2.TLS.ClientCAs = clientCAPool\n\t\t\t},\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString:   codeBlock{code: fmt.Sprintf(`client.connect(\"GRPCBIN_ADDR\", { tls: { cacerts: [\"%s\"], cert: \"%s\", key: \"%s\" }});`, localHostCert, clientAuth, clientAuthKey)},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectTlsEncryptedKey\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tclientCAPool := x509.NewCertPool()\n\t\t\t\tclientCAPool.AppendCertsFromPEM(clientAuthCA)\n\t\t\t\ttb.ServerHTTP2.TLS.ClientAuth = tls.RequireAndVerifyClientCert\n\t\t\t\ttb.ServerHTTP2.TLS.ClientCAs = clientCAPool\n\t\t\t},\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString:   codeBlock{code: fmt.Sprintf(`client.connect(\"GRPCBIN_ADDR\", { tls: { cacerts: [\"%s\"], cert: \"%s\", key: \"%s\", password: \"%s\" }});`, localHostCert, clientAuth, clientAuthKeyEncrypted, trivialKeyPassword)},\n\t\t},\n\t\t{\n\t\t\tname:       \"ConnectTlsEncryptedKeyDecryptionFailed\",\n\t\t\tinitString: codeBlock{code: \"var client = new grpc.Client();\"},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: fmt.Sprintf(`client.connect(\"GRPCBIN_ADDR\", { timeout: '5s', tls: { cert: \"%s\", key: \"%s\", password: \"%s\" }});`,\n\t\t\t\t\tclientAuth,\n\t\t\t\t\tclientAuthKeyEncrypted,\n\t\t\t\t\ttrivialWrongKeyPassword,\n\t\t\t\t),\n\t\t\t\terr: \"x509: decryption password incorrect\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"ConnectTlsInvokeSuccess\",\n\t\t\tsetup: func(tb *httpmultibin.HTTPMultiBin) {\n\t\t\t\tclientCAPool := x509.NewCertPool()\n\t\t\t\tclientCAPool.AppendCertsFromPEM(clientAuthCA)\n\t\t\t\ttb.ServerHTTP2.TLS.ClientAuth = tls.RequireAndVerifyClientCert\n\t\t\t\ttb.ServerHTTP2.TLS.ClientCAs = clientCAPool\n\t\t\t\ttb.GRPCStub.EmptyCallFunc = func(context.Context, *grpc_testing.Empty) (*grpc_testing.Empty, error) {\n\t\t\t\t\treturn &grpc_testing.Empty{}, nil\n\t\t\t\t}\n\t\t\t},\n\t\t\tinitString: codeBlock{code: `\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`},\n\t\t\tvuString: codeBlock{\n\t\t\t\tcode: fmt.Sprintf(`\n\t\t\t\tclient.connect(\"GRPCBIN_ADDR\", { timeout: '5s', tls: { cacerts: [\"%s\"], cert: \"%s\", key: \"%s\" }});\n\t\t\t\tvar resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {})\n\t\t\t\tif (resp.status !== grpc.StatusOK) {\n\t\t\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \"or status: \" + resp.status)\n\t\t\t\t}`,\n\t\t\t\t\tlocalHostCert,\n\t\t\t\t\tclientAuth,\n\t\t\t\t\tclientAuthKey),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := newTestState(t)\n\n\t\t\t// setup necessary environment if needed by a test\n\t\t\tif tt.setup != nil {\n\t\t\t\ttt.setup(ts.httpBin)\n\t\t\t}\n\n\t\t\tval, err := ts.Run(tt.initString.code)\n\t\t\tassertResponse(t, tt.initString, err, val, ts)\n\n\t\t\tts.ToVUContext()\n\t\t\tval, err = ts.Run(tt.vuString.code)\n\t\t\tassertResponse(t, tt.vuString, err, val, ts)\n\t\t})\n\t}\n}\n\nfunc TestDebugStat(t *testing.T) {\n\tt.Parallel()\n\n\ttests := [...]struct {\n\t\tname     string\n\t\tstat     grpcstats.RPCStats\n\t\texpected string\n\t}{\n\t\t{\n\t\t\t\"OutHeader\",\n\t\t\t&grpcstats.OutHeader{},\n\t\t\t\"Out Header:\",\n\t\t},\n\t\t{\n\t\t\t\"OutTrailer\",\n\t\t\t&grpcstats.OutTrailer{\n\t\t\t\tTrailer: metadata.MD{\n\t\t\t\t\t\"x-trail\": []string{\"out\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"Out Trailer:\",\n\t\t},\n\t\t{\n\t\t\t\"OutPayload\",\n\t\t\t&grpcstats.OutPayload{\n\t\t\t\tPayload: &grpc_testing.SimpleRequest{\n\t\t\t\t\tFillUsername: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"fill_username:\",\n\t\t},\n\t\t{\n\t\t\t\"InHeader\",\n\t\t\t&grpcstats.InHeader{\n\t\t\t\tHeader: metadata.MD{\n\t\t\t\t\t\"x-head\": []string{\"in\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"x-head: in\",\n\t\t},\n\t\t{\n\t\t\t\"InTrailer\",\n\t\t\t&grpcstats.InTrailer{\n\t\t\t\tTrailer: metadata.MD{\n\t\t\t\t\t\"x-trail\": []string{\"in\"},\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"x-trail: in\",\n\t\t},\n\t\t{\n\t\t\t\"InPayload\",\n\t\t\t&grpcstats.InPayload{\n\t\t\t\tPayload: &grpc_testing.SimpleResponse{\n\t\t\t\t\tUsername: \"k6-user\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"username:\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar b bytes.Buffer\n\t\t\tlogger := logrus.New()\n\t\t\tlogger.Out = &b\n\n\t\t\tgrpcext.DebugStat(logger.WithField(\"source\", \"test\"), tt.stat, \"full\")\n\t\t\tassert.Contains(t, b.String(), tt.expected)\n\t\t})\n\t}\n}\n\nfunc TestClientLoadProto(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\ttt := testcase{\n\t\tinitString: codeBlock{\n\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/nested_types/nested_types.proto\");\n\t\t\tclient`,\n\t\t},\n\t}\n\n\tval, err := ts.Run(tt.initString.code)\n\tassertResponse(t, tt.initString, err, val, ts)\n\n\tclient, ok := val.Export().(*k6grpc.Client)\n\trequire.True(t, ok, \"got: %T, want *k6grpc.Client\", client)\n\n\texpectedTypes := []string{\n\t\t\"grpc.testdata.nested.types.Outer\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleAA\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleAA.Inner\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleBB\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleBB.Inner\",\n\t\t\"grpc.testdata.nested.types.MeldOuter\",\n\t}\n\n\tfor _, expected := range expectedTypes {\n\t\tfound, err := client.Types().FindMessageByName(protoreflect.FullName(expected))\n\n\t\tassert.NotNil(t, found, \"Expected to find the message type %s, but an error occurred\", expected)\n\t\tassert.Nil(t, err, \"It was not expected that there would be an error, but it got: %v\", err)\n\t}\n}\n\nfunc TestClientLoadProtoAbsoluteRootWithFile(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\trootPath := ts.VU.InitEnvField.CWD.JoinPath(\"../..\").String()\n\n\ttt := testcase{\n\t\tinitString: codeBlock{\n\t\t\tcode: `\n\t\t\tvar client = new grpc.Client();\n\t\t\tclient.load([\"` + rootPath + `\"], \"../../lib/testutils/httpmultibin/nested_types/nested_types.proto\");\n\t\t\tclient`,\n\t\t},\n\t}\n\n\tval, err := ts.Run(tt.initString.code)\n\tassertResponse(t, tt.initString, err, val, ts)\n\n\tclient, ok := val.Export().(*k6grpc.Client)\n\trequire.True(t, ok, \"got: %T, want *k6grpc.Client\", client)\n\n\texpectedTypes := []string{\n\t\t\"grpc.testdata.nested.types.Outer\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleAA\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleAA.Inner\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleBB\",\n\t\t\"grpc.testdata.nested.types.Outer.MiddleBB.Inner\",\n\t\t\"grpc.testdata.nested.types.MeldOuter\",\n\t}\n\n\tfor _, expected := range expectedTypes {\n\t\tfound, err := client.Types().FindMessageByName(protoreflect.FullName(expected))\n\n\t\tassert.NotNil(t, found, \"Expected to find the message type %s, but an error occurred\", expected)\n\t\tassert.Nil(t, err, \"It was not expected that there would be an error, but it got: %v\", err)\n\t}\n}\n\nfunc TestClientConnectionReflectMetadata(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\treflection.Register(ts.httpBin.ServerGRPC)\n\n\tinitString := codeBlock{\n\t\tcode: `var client = new grpc.Client();`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `client.connect(\"GRPCBIN_ADDR\", {reflect: true, reflectMetadata: {\"x-test\": \"custom-header-for-reflection\"}})`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\t// this should trigger logging of the outgoing gRPC metadata\n\tts.VU.State().Options.HTTPDebug = null.NewString(\"full\", true)\n\n\tval, err = ts.Run(vuString.code)\n\tassertResponse(t, vuString, err, val, ts)\n\n\tentries := ts.loggerHook.Drain()\n\n\t// since we enable debug logging, we should see the metadata in the logs\n\tfoundReflectionCall := false\n\tfor _, entry := range entries {\n\t\tif strings.Contains(entry.Message, \"ServerReflection/ServerReflectionInfo\") {\n\t\t\tfoundReflectionCall = true\n\n\t\t\t// check that the metadata is present\n\t\t\tassert.Contains(t, entry.Message, \"x-test: custom-header-for-reflection\")\n\t\t\t// check that user-agent header is present\n\t\t\tassert.Contains(t, entry.Message, \"user-agent: k6-test\")\n\t\t}\n\t}\n\n\tassert.True(t, foundReflectionCall, \"expected to find a reflection call in the logs, but didn't\")\n}\n\nfunc TestAnyWithNotCommonTypes(t *testing.T) {\n\tt.Parallel()\n\trandseed := time.Now().Unix()\n\tt.Log(\"Random seed is\", randseed)\n\tr := rand.New(rand.NewSource(randseed))\n\twords := []string{\"sum\", \"square\", \"circle\", \"testing\", \"some\"}\n\t// This tests specifically with types that aren't available to the server and are not part of anything precompiled\n\trandWord := func() string {\n\t\treturn words[r.Int()%len(words)]\n\t}\n\tpackageName := randWord() + \".\" + randWord() + \".\" + randWord()\n\tanyTypeName := randWord()\n\tconst testProto = `\n\t\tsyntax = \"proto3\";\n\t\tpackage %s;\n\t\timport \"google/protobuf/any.proto\";\n\n\t\tservice AnyTestService {\n\t\t\trpc Invoke (Request) returns (Empty) {}\n\t\t\trpc Stream (stream Request) returns (Empty) {}\n\t\t}\n\n\t\tmessage Request {\n\t\t\tgoogle.protobuf.Any data = 1;\n\t\t}\n\n\t\tmessage %s {\n\t\t\tint64 a = 1;\n\t\t\tint64 b = 2;\n\t\t}\n\n\t\tmessage Empty {}\n\t`\n\n\tts := newTestState(t)\n\tfs := fsext.NewMemMapFs()\n\n\tts.VU.InitEnvField.FileSystems[\"file\"] = fs\n\terr := fsext.WriteFile(fs, \"/my_proto.proto\", fmt.Appendf(nil, testProto, packageName, anyTypeName), 0x600)\n\trequire.NoError(t, err)\n\n\t// setup necessary environment if needed by a test\n\t_, err = ts.Run(`\n\t\t\t\tvar client = new grpc.Client();\n\t\t\t\tclient.load([\"/\"], \"/my_proto.proto\");\n\t`)\n\n\trequire.NoError(t, err)\n\tts.ToVUContext()\n\tsr := strings.NewReplacer(\"PACKAGENAME\", packageName, \"TYPENAME\", anyTypeName)\n\t_, err = ts.RunOnEventLoop(sr.Replace(`\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tvar resp = client.invoke(\"PACKAGENAME.AnyTestService/Invoke\",  {\n\t\t\tdata: {\n\t\t\t\t\"@type\": \"type.googleapis.com/PACKAGENAME.TYPENAME\",\n\t\t\t\t\"a\": 1,\n\t\t\t\t\"b\": 2,\n\t\t\t},\n\t\t})\n\t\tif (resp.status !== grpc.StatusUnimplemented) {\n\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \" or status: \" + resp.status)\n\t\t}\n\t\tif (resp.error.message !== \"unknown service PACKAGENAME.AnyTestService\") {\n\t\t\tthrow new Error(\"unexpected error: \" + JSON.stringify(resp.error) + \" or status: \" + resp.status)\n\t\t}\n\t\tconst stream = new grpc.Stream(client, 'PACKAGENAME.AnyTestService/Stream', null);\n\t\tstream.on(\"error\", (error) => {\n\t\t\tif (error.message !== \"unknown service PACKAGENAME.AnyTestService\") {\n\t\t\t   throw new Error(\"unexpected error: \" + JSON.stringify(error) + \" or status: \" )\n\t\t\t}\n\t\t})\n\t\tstream.write({\n\t\t\tdata: {\n\t\t\t\t\"@type\": \"type.googleapis.com/PACKAGENAME.TYPENAME\",\n\t\t\t\t\"a\": 1,\n\t\t\t\t\"b\": 2,\n\t\t\t},\n\t\t})\n\t\t`))\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/client_types_test.go",
    "content": "package grpc\n\nimport \"google.golang.org/protobuf/reflect/protoregistry\"\n\n// Types return the client's registry of descriptor types.\n// For testing purposes only.\nfunc (c *Client) Types() *protoregistry.Types {\n\treturn c.types\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/grpc.go",
    "content": "// Package grpc is the root module of the k6-grpc extension.\npackage grpc\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"google.golang.org/grpc/codes\"\n\thealthpb \"google.golang.org/grpc/health/grpc_health_v1\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/mstoykov/k6-taskqueue-lib/taskqueue\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// ModuleInstance represents an instance of the GRPC module for every VU.\n\tModuleInstance struct {\n\t\tvu      modules.VU\n\t\texports map[string]any\n\t\tmetrics *instanceMetrics\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\tmetrics, err := registerMetrics(vu.InitEnv().Registry)\n\tif err != nil {\n\t\tcommon.Throw(vu.Runtime(), fmt.Errorf(\"failed to register GRPC module metrics: %w\", err))\n\t}\n\n\tmi := &ModuleInstance{\n\t\tvu:      vu,\n\t\texports: make(map[string]any),\n\t\tmetrics: metrics,\n\t}\n\n\tmi.exports[\"Client\"] = mi.NewClient\n\tmi.defineConstants()\n\tmi.exports[\"Stream\"] = mi.stream\n\n\treturn mi\n}\n\n// NewClient is the JS constructor for the grpc Client.\nfunc (mi *ModuleInstance) NewClient(_ sobek.ConstructorCall) *sobek.Object {\n\trt := mi.vu.Runtime()\n\treturn rt.ToValue(&Client{vu: mi.vu, types: new(protoregistry.Types)}).ToObject(rt)\n}\n\n// defineConstants defines the constant variables of the module.\nfunc (mi *ModuleInstance) defineConstants() {\n\trt := mi.vu.Runtime()\n\tmustAddCode := func(name string, code codes.Code) {\n\t\tmi.exports[name] = rt.ToValue(code)\n\t}\n\n\tmustAddServingStatus := func(name string, status healthpb.HealthCheckResponse_ServingStatus) {\n\t\tmi.exports[name] = rt.ToValue(status)\n\t}\n\n\tmustAddCode(\"StatusOK\", codes.OK)\n\tmustAddCode(\"StatusCanceled\", codes.Canceled)\n\tmustAddCode(\"StatusUnknown\", codes.Unknown)\n\tmustAddCode(\"StatusInvalidArgument\", codes.InvalidArgument)\n\tmustAddCode(\"StatusDeadlineExceeded\", codes.DeadlineExceeded)\n\tmustAddCode(\"StatusNotFound\", codes.NotFound)\n\tmustAddCode(\"StatusAlreadyExists\", codes.AlreadyExists)\n\tmustAddCode(\"StatusPermissionDenied\", codes.PermissionDenied)\n\tmustAddCode(\"StatusResourceExhausted\", codes.ResourceExhausted)\n\tmustAddCode(\"StatusFailedPrecondition\", codes.FailedPrecondition)\n\tmustAddCode(\"StatusAborted\", codes.Aborted)\n\tmustAddCode(\"StatusOutOfRange\", codes.OutOfRange)\n\tmustAddCode(\"StatusUnimplemented\", codes.Unimplemented)\n\tmustAddCode(\"StatusInternal\", codes.Internal)\n\tmustAddCode(\"StatusUnavailable\", codes.Unavailable)\n\tmustAddCode(\"StatusDataLoss\", codes.DataLoss)\n\tmustAddCode(\"StatusUnauthenticated\", codes.Unauthenticated)\n\n\tmustAddServingStatus(\"HealthCheckUnknown\", healthpb.HealthCheckResponse_UNKNOWN)\n\tmustAddServingStatus(\"HealthCheckServing\", healthpb.HealthCheckResponse_SERVING)\n\tmustAddServingStatus(\"HealthCheckNotServing\", healthpb.HealthCheckResponse_NOT_SERVING)\n\tmustAddServingStatus(\"HealthCheckServiceUnkown\", healthpb.HealthCheckResponse_SERVICE_UNKNOWN)\n}\n\n// Exports returns the exports of the grpc module.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: mi.exports,\n\t}\n}\n\n// stream returns a new stream object\nfunc (mi *ModuleInstance) stream(c sobek.ConstructorCall) *sobek.Object {\n\trt := mi.vu.Runtime()\n\n\tclient, err := extractClient(c.Argument(0), rt)\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"invalid GRPC Stream's client: %w\", err))\n\t}\n\n\tmethodName := sanitizeMethodName(c.Argument(1).String())\n\tmethodDescriptor, err := client.getMethodDescriptor(methodName)\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"invalid GRPC Stream's method: %w\", err))\n\t}\n\n\tp, err := newCallParams(mi.vu, c.Argument(2))\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"invalid GRPC Stream's parameters: %w\", err))\n\t}\n\n\tp.SetSystemTags(mi.vu.State(), client.addr, methodName)\n\n\tlogger := mi.vu.State().Logger.WithField(\"streamMethod\", methodName)\n\n\ts := &stream{\n\t\tvu:               mi.vu,\n\t\tclient:           client,\n\t\tmethodDescriptor: methodDescriptor,\n\t\tmethod:           methodName,\n\t\tlogger:           logger,\n\n\t\ttq: taskqueue.New(mi.vu.RegisterCallback),\n\n\t\tinstanceMetrics: mi.metrics,\n\t\tbuiltinMetrics:  mi.vu.State().BuiltinMetrics,\n\t\tdone:            make(chan struct{}),\n\t\twritingState:    opened,\n\n\t\twriteQueueCh: make(chan message),\n\n\t\teventListeners: newEventListeners(),\n\t\tobj:            rt.NewObject(),\n\t\ttagsAndMeta:    &p.TagsAndMeta,\n\t}\n\n\tdefineStream(rt, s)\n\n\terr = s.beginStream(p)\n\tif err != nil {\n\t\ts.tq.Close()\n\n\t\tcommon.Throw(rt, err)\n\t}\n\n\treturn s.obj\n}\n\n// extractClient extracts & validates a grpc.Client from a sobek.Value.\nfunc extractClient(v sobek.Value, rt *sobek.Runtime) (*Client, error) {\n\tif common.IsNullish(v) {\n\t\treturn nil, errors.New(\"empty gRPC client\")\n\t}\n\n\tclient, ok := v.ToObject(rt).Export().(*Client)\n\tif !ok {\n\t\treturn nil, errors.New(\"not a gRPC client\")\n\t}\n\n\tif client.conn == nil {\n\t\treturn nil, errors.New(\"no gRPC connection, you must call connect first\")\n\t}\n\n\treturn client, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/helpers_test.go",
    "content": "package grpc_test\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc assertResponse(t *testing.T, cb codeBlock, err error, val sobek.Value, ts testState) {\n\tif isWindows && cb.windowsErr != \"\" && err != nil {\n\t\terr = errors.New(strings.ReplaceAll(err.Error(), cb.windowsErr, cb.err))\n\t}\n\tif cb.err == \"\" {\n\t\tassert.NoError(t, err)\n\t} else {\n\t\trequire.Error(t, err)\n\t\tassert.Contains(t, err.Error(), cb.err)\n\t}\n\tif cb.val != nil {\n\t\trequire.NotNil(t, val)\n\t\tassert.Equal(t, cb.val, val.Export())\n\t}\n\tif cb.asserts != nil {\n\t\tcb.asserts(t, ts.httpBin, ts.samples, err)\n\t}\n}\n\nfunc assertMetricEmitted(\n\tt *testing.T,\n\tmetricName string, //nolint:unparam\n\tsampleContainers []metrics.SampleContainer,\n\turl string,\n) {\n\tseenMetric := false\n\n\tfor _, sampleContainer := range sampleContainers {\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\tsurl, ok := sample.Tags.Get(\"url\")\n\t\t\tassert.True(t, ok)\n\t\t\tif surl == url {\n\t\t\t\tif sample.Metric.Name == metricName {\n\t\t\t\t\tseenMetric = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tassert.True(t, seenMetric, \"url %s didn't emit %s\", url, metricName)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/listeners.go",
    "content": "package grpc\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n)\n\nconst (\n\teventData   = \"data\"\n\teventError  = \"error\"\n\teventEnd    = \"end\"\n\teventStatus = \"status\"\n)\n\n// eventListeners keeps track of the eventListeners for each event type\ntype eventListeners struct {\n\tdata   *eventListener\n\terror  *eventListener\n\tend    *eventListener\n\tstatus *eventListener\n}\n\n// eventListener keeps listeners of a certain type\ntype eventListener struct {\n\teventType string\n\n\t// this return sobek.value *and* error in order to return error on exception instead of panic\n\t// https://pkg.go.dev/github.com/grafana/sobek#hdr-Functions\n\tlist []func(sobek.Value, sobek.Value) (sobek.Value, error)\n}\n\n// newListener creates a new listener of a certain type\nfunc newListener(eventType string) *eventListener {\n\treturn &eventListener{\n\t\teventType: eventType,\n\t}\n}\n\n// add adds a listener to the listener list\nfunc (l *eventListener) add(fn func(sobek.Value, sobek.Value) (sobek.Value, error)) {\n\tl.list = append(l.list, fn)\n}\n\n// getType return event listener of a certain type\nfunc (l *eventListeners) getType(t string) *eventListener {\n\tswitch t {\n\tcase eventData:\n\t\treturn l.data\n\tcase eventError:\n\t\treturn l.error\n\tcase eventStatus:\n\t\treturn l.status\n\tcase eventEnd:\n\t\treturn l.end\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// add adds a listener to the listeners\nfunc (l *eventListeners) add(t string, f func(sobek.Value, sobek.Value) (sobek.Value, error)) error {\n\tlist := l.getType(t)\n\n\tif list == nil {\n\t\treturn fmt.Errorf(\"unknown GRPC stream's event type: %s\", t)\n\t}\n\n\tlist.add(f)\n\n\treturn nil\n}\n\n// all returns all possible listeners for a certain event type or an empty array\nfunc (l *eventListeners) all(t string) []func(sobek.Value, sobek.Value) (sobek.Value, error) {\n\tlist := l.getType(t)\n\n\tif list == nil {\n\t\treturn []func(sobek.Value, sobek.Value) (sobek.Value, error){}\n\t}\n\n\treturn list.list\n}\n\nfunc newEventListeners() *eventListeners {\n\treturn &eventListeners{\n\t\tdata:   newListener(eventData),\n\t\terror:  newListener(eventError),\n\t\tstatus: newListener(eventStatus),\n\t\tend:    newListener(eventEnd),\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/metrics.go",
    "content": "package grpc\n\nimport \"go.k6.io/k6/metrics\"\n\n// instanceMetrics contains the metrics for the grpc extension.\ntype instanceMetrics struct {\n\tStreams                 *metrics.Metric\n\tStreamsMessagesSent     *metrics.Metric\n\tStreamsMessagesReceived *metrics.Metric\n}\n\n// registerMetrics registers and returns the metrics in the provided registry\nfunc registerMetrics(registry *metrics.Registry) (*instanceMetrics, error) {\n\tvar err error\n\tm := &instanceMetrics{}\n\n\tif m.Streams, err = registry.NewMetric(\"grpc_streams\", metrics.Counter); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif m.StreamsMessagesSent, err = registry.NewMetric(\"grpc_streams_msgs_sent\", metrics.Counter); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif m.StreamsMessagesReceived, err = registry.NewMetric(\"grpc_streams_msgs_received\", metrics.Counter); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn m, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/params.go",
    "content": "package grpc\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n\t\"google.golang.org/grpc/metadata\"\n)\n\n// callParams is the parameters that can be passed to a gRPC calls\n// like invoke or newStream.\ntype callParams struct {\n\tMetadata               metadata.MD\n\tTagsAndMeta            metrics.TagsAndMeta\n\tTimeout                time.Duration\n\tDiscardResponseMessage bool\n}\n\n// newCallParams constructs the call parameters from the input value.\n// if no input is given, the default values are used.\nfunc newCallParams(vu modules.VU, input sobek.Value) (*callParams, error) {\n\tresult := &callParams{\n\t\tMetadata:    metadata.New(nil),\n\t\tTagsAndMeta: vu.State().Tags.GetCurrentValues(),\n\t}\n\n\tif common.IsNullish(input) {\n\t\treturn result, nil\n\t}\n\n\trt := vu.Runtime()\n\tparams := input.ToObject(rt)\n\n\tfor _, k := range params.Keys() {\n\t\tswitch k {\n\t\tcase \"metadata\":\n\t\t\tmd, err := newMetadata(params.Get(k))\n\t\t\tif err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"invalid metadata param: %w\", err)\n\t\t\t}\n\n\t\t\tresult.Metadata = md\n\t\tcase \"tags\":\n\t\t\tif err := common.ApplyCustomUserTags(rt, &result.TagsAndMeta, params.Get(k)); err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"metric tags: %w\", err)\n\t\t\t}\n\t\tcase \"timeout\":\n\t\t\tvar err error\n\t\t\tv := params.Get(k).Export()\n\t\t\tresult.Timeout, err = types.GetDurationValue(v)\n\t\t\tif err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"invalid timeout value: %w\", err)\n\t\t\t}\n\t\tcase \"discardResponseMessage\":\n\t\t\tresult.DiscardResponseMessage = params.Get(k).ToBoolean()\n\t\tdefault:\n\t\t\treturn result, fmt.Errorf(\"unknown param: %q\", k)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\n// newMetadata constructs a metadata.MD from the input value.\nfunc newMetadata(input sobek.Value) (metadata.MD, error) {\n\tmd := metadata.New(nil)\n\n\tif common.IsNullish(input) {\n\t\treturn md, nil\n\t}\n\n\tv := input.Export()\n\n\trawHeaders, ok := v.(map[string]any)\n\tif !ok {\n\t\treturn md, errors.New(\"must be an object with key-value pairs\")\n\t}\n\n\tfor hk, kv := range rawHeaders {\n\t\tvar val string\n\t\t// The gRPC spec defines that Binary-valued keys end in -bin\n\t\t// https://grpc.io/docs/what-is-grpc/core-concepts/#metadata\n\t\tif strings.HasSuffix(hk, \"-bin\") {\n\t\t\tvar binVal []byte\n\t\t\tif binVal, ok = kv.([]byte); !ok {\n\t\t\t\treturn md, fmt.Errorf(\"%q value must be binary\", hk)\n\t\t\t}\n\n\t\t\t// https://github.com/grpc/grpc-go/blob/v1.57.0/Documentation/grpc-metadata.md#storing-binary-data-in-metadata\n\t\t\tval = string(binVal)\n\t\t} else if val, ok = kv.(string); !ok {\n\t\t\treturn md, fmt.Errorf(\"%q value must be a string\", hk)\n\t\t}\n\n\t\tmd.Append(hk, val)\n\t}\n\n\treturn md, nil\n}\n\n// SetSystemTags sets the system tags for the call.\nfunc (p *callParams) SetSystemTags(state *lib.State, addr string, methodName string) {\n\tif state.Options.SystemTags.Has(metrics.TagURL) {\n\t\tp.TagsAndMeta.SetSystemTagOrMeta(metrics.TagURL, fmt.Sprintf(\"%s%s\", addr, methodName))\n\t}\n\n\tparts := strings.Split(methodName[1:], \"/\")\n\tp.TagsAndMeta.SetSystemTagOrMetaIfEnabled(state.Options.SystemTags, metrics.TagService, parts[0])\n\tp.TagsAndMeta.SetSystemTagOrMetaIfEnabled(state.Options.SystemTags, metrics.TagMethod, parts[1])\n\n\t// Only set the name system tag if the user didn't explicitly set it beforehand\n\tif _, ok := p.TagsAndMeta.Tags.Get(\"name\"); !ok {\n\t\tp.TagsAndMeta.SetSystemTagOrMetaIfEnabled(state.Options.SystemTags, metrics.TagName, methodName)\n\t}\n}\n\n// connectParams is the parameters that can be passed to a gRPC connect call.\ntype connectParams struct {\n\tIsPlaintext           bool\n\tUseReflectionProtocol bool\n\tReflectionMetadata    metadata.MD\n\tTimeout               time.Duration\n\tMaxReceiveSize        int64\n\tMaxSendSize           int64\n\tTLS                   map[string]any\n\tAuthority             string\n}\n\nfunc newConnectParams(vu modules.VU, input sobek.Value) (*connectParams, error) { //nolint:gocognit\n\tresult := &connectParams{\n\t\tIsPlaintext:           false,\n\t\tUseReflectionProtocol: false,\n\t\tTimeout:               time.Minute,\n\t\tMaxReceiveSize:        0,\n\t\tMaxSendSize:           0,\n\t\tAuthority:             \"\",\n\t\tReflectionMetadata:    metadata.New(nil),\n\t}\n\n\tif common.IsNullish(input) {\n\t\treturn result, nil\n\t}\n\n\trt := vu.Runtime()\n\tparams := input.ToObject(rt)\n\n\tfor _, k := range params.Keys() {\n\t\tv := params.Get(k).Export()\n\n\t\tswitch k {\n\t\tcase \"plaintext\":\n\t\t\tvar ok bool\n\t\t\tresult.IsPlaintext, ok = v.(bool)\n\t\t\tif !ok {\n\t\t\t\treturn result, fmt.Errorf(\"invalid plaintext value: '%#v', it needs to be boolean\", v)\n\t\t\t}\n\t\tcase \"timeout\":\n\t\t\tvar err error\n\t\t\tresult.Timeout, err = types.GetDurationValue(v)\n\t\t\tif err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"invalid timeout value: %w\", err)\n\t\t\t}\n\t\tcase \"reflect\":\n\t\t\tvar ok bool\n\t\t\tresult.UseReflectionProtocol, ok = v.(bool)\n\t\t\tif !ok {\n\t\t\t\treturn result, fmt.Errorf(\"invalid reflect value: '%#v', it needs to be boolean\", v)\n\t\t\t}\n\t\tcase \"reflectMetadata\":\n\t\t\tmd, err := newMetadata(params.Get(k))\n\t\t\tif err != nil {\n\t\t\t\treturn result, fmt.Errorf(\"invalid reflectMetadata param: %w\", err)\n\t\t\t}\n\n\t\t\tresult.ReflectionMetadata = md\n\t\tcase \"maxReceiveSize\":\n\t\t\tvar ok bool\n\t\t\tresult.MaxReceiveSize, ok = v.(int64)\n\t\t\tif !ok {\n\t\t\t\treturn result, fmt.Errorf(\"invalid maxReceiveSize value: '%#v', it needs to be an integer\", v)\n\t\t\t}\n\t\t\tif result.MaxReceiveSize < 0 {\n\t\t\t\treturn result, fmt.Errorf(\"invalid maxReceiveSize value: '%#v, it needs to be a positive integer\", v)\n\t\t\t}\n\t\tcase \"maxSendSize\":\n\t\t\tvar ok bool\n\t\t\tresult.MaxSendSize, ok = v.(int64)\n\t\t\tif !ok {\n\t\t\t\treturn result, fmt.Errorf(\"invalid maxSendSize value: '%#v', it needs to be an integer\", v)\n\t\t\t}\n\t\t\tif result.MaxSendSize < 0 {\n\t\t\t\treturn result, fmt.Errorf(\"invalid maxSendSize value: '%#v, it needs to be a positive integer\", v)\n\t\t\t}\n\t\tcase \"tls\":\n\t\t\tif err := parseConnectTLSParam(result, v); err != nil {\n\t\t\t\treturn result, err\n\t\t\t}\n\t\tcase \"authority\":\n\t\t\tvar ok bool\n\t\t\tresult.Authority, ok = v.(string)\n\t\t\tif !ok {\n\t\t\t\treturn result, fmt.Errorf(\"invalid authority value: '%#v', it needs to be a string\", v)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn result, fmt.Errorf(\"unknown connect param: %q\", k)\n\t\t}\n\t}\n\n\treturn result, nil\n}\n\nfunc parseConnectTLSParam(params *connectParams, v any) error {\n\tvar ok bool\n\tparams.TLS, ok = v.(map[string]any)\n\n\tif !ok {\n\t\treturn fmt.Errorf(\"invalid tls value: '%#v', expected (optional) keys: cert, key, password, and cacerts\", v)\n\t}\n\t// optional map keys below\n\tif cert, certok := params.TLS[\"cert\"]; certok {\n\t\tif _, ok = cert.(string); !ok {\n\t\t\treturn fmt.Errorf(\"invalid tls cert value: '%#v', it needs to be a PEM formatted string\", v)\n\t\t}\n\t}\n\tif key, keyok := params.TLS[\"key\"]; keyok {\n\t\tif _, ok = key.(string); !ok {\n\t\t\treturn fmt.Errorf(\"invalid tls key value: '%#v', it needs to be a PEM formatted string\", v)\n\t\t}\n\t}\n\tif pass, passok := params.TLS[\"password\"]; passok {\n\t\tif _, ok = pass.(string); !ok {\n\t\t\treturn fmt.Errorf(\"invalid tls password value: '%#v', it needs to be a string\", v)\n\t\t}\n\t}\n\tif cacerts, cacertsok := params.TLS[\"cacerts\"]; cacertsok {\n\t\tvar cacertsArray []any\n\t\tif cacertsArray, ok = cacerts.([]any); ok {\n\t\t\tfor _, cacertsArrayEntry := range cacertsArray {\n\t\t\t\tif _, ok = cacertsArrayEntry.(string); !ok {\n\t\t\t\t\treturn fmt.Errorf(\"invalid tls cacerts value: '%#v',\"+\n\t\t\t\t\t\t\" it needs to be a string or an array of PEM formatted strings\", v)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if _, ok = cacerts.(string); !ok {\n\t\t\treturn fmt.Errorf(\"invalid tls cacerts value: '%#v',\"+\n\t\t\t\t\" it needs to be a string or an array of PEM formatted strings\", v)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/params_test.go",
    "content": "package grpc\n\nimport (\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestCallParamsInvalidInput(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tName        string\n\t\tJSON        string\n\t\tErrContains string\n\t}{\n\t\t{\n\t\t\tName:        \"InvalidParam\",\n\t\t\tJSON:        `{ void: true }`,\n\t\t\tErrContains: `unknown param: \"void\"`,\n\t\t},\n\t\t{\n\t\t\tName:        \"InvalidTimeoutType\",\n\t\t\tJSON:        `{ timeout: true }`,\n\t\t\tErrContains: `invalid timeout value: unable to use type bool as a duration value`,\n\t\t},\n\t\t{\n\t\t\tName:        \"InvalidTimeout\",\n\t\t\tJSON:        `{ timeout: \"please\" }`,\n\t\t\tErrContains: `invalid duration`,\n\t\t},\n\t\t{\n\t\t\tName:        \"InvalidMetadata\",\n\t\t\tJSON:        `{ metadata: \"lorem\" }`,\n\t\t\tErrContains: `invalid metadata param: must be an object with key-value pairs`,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestRuntime, params := newParamsTestRuntime(t, tc.JSON)\n\n\t\t\t_, err := newCallParams(testRuntime.VU, params)\n\n\t\t\tassert.ErrorContains(t, err, tc.ErrContains)\n\t\t})\n\t}\n}\n\nfunc TestCallParamsMetadata(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tName             string\n\t\tJSON             string\n\t\tExpectedMetadata metadata.MD\n\t}{\n\t\t{\n\t\t\tName:             \"EmptyMetadata\",\n\t\t\tJSON:             `{}`,\n\t\t\tExpectedMetadata: metadata.New(nil),\n\t\t},\n\t\t{\n\t\t\tName:             \"Metadata\",\n\t\t\tJSON:             `{metadata: {foo: \"bar\", baz: \"qux\"}}`,\n\t\t\tExpectedMetadata: metadata.New(map[string]string{\"foo\": \"bar\", \"baz\": \"qux\"}),\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestRuntime, params := newParamsTestRuntime(t, tc.JSON)\n\n\t\t\tp, err := newCallParams(testRuntime.VU, params)\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.ExpectedMetadata, p.Metadata)\n\t\t})\n\t}\n}\n\nfunc TestCallParamsTimeOutParse(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tName    string\n\t\tJSON    string\n\t\tTimeout time.Duration\n\t}{\n\t\t{\n\t\t\tName:    \"StringTimeout\",\n\t\t\tJSON:    `{ timeout: \"1h42m\" }`,\n\t\t\tTimeout: time.Hour + 42*time.Minute,\n\t\t},\n\t\t{\n\t\t\tName:    \"FloatTimeout\",\n\t\t\tJSON:    `{ timeout: 400.50 }`,\n\t\t\tTimeout: 400*time.Millisecond + 500*time.Microsecond,\n\t\t},\n\t\t{\n\t\t\tName:    \"IntegerTimeout\",\n\t\t\tJSON:    `{ timeout: 2000 }`,\n\t\t\tTimeout: 2000 * time.Millisecond,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestRuntime, params := newParamsTestRuntime(t, tc.JSON)\n\n\t\t\tp, err := newCallParams(testRuntime.VU, params)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tc.Timeout, p.Timeout)\n\t\t})\n\t}\n}\n\nfunc TestCallParamsDiscardResponseMessageParse(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tName                   string\n\t\tJSON                   string\n\t\tDiscardResponseMessage bool\n\t}{\n\t\t{\n\t\t\tName:                   \"Empty\",\n\t\t\tJSON:                   `{}`,\n\t\t\tDiscardResponseMessage: false,\n\t\t},\n\t\t{\n\t\t\tName:                   \"DiscardResponseMessageFalse\",\n\t\t\tJSON:                   `{ discardResponseMessage: false }`,\n\t\t\tDiscardResponseMessage: false,\n\t\t},\n\t\t{\n\t\t\tName:                   \"DiscardResponseMessageTrue\",\n\t\t\tJSON:                   `{ discardResponseMessage: true }`,\n\t\t\tDiscardResponseMessage: true,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestRuntime, params := newParamsTestRuntime(t, tc.JSON)\n\n\t\t\tp, err := newCallParams(testRuntime.VU, params)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tassert.Equal(t, tc.DiscardResponseMessage, p.DiscardResponseMessage)\n\t\t})\n\t}\n}\n\nfunc TestConnectParamsAuthority(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tName              string\n\t\tJSON              string\n\t\tExpectedAuthority string\n\t}{\n\t\t{\n\t\t\tName:              \"EmptyAuthority\",\n\t\t\tJSON:              `{authority:\"\"}`,\n\t\t\tExpectedAuthority: \"\",\n\t\t},\n\t\t{\n\t\t\tName:              \"Authority\",\n\t\t\tJSON:              `{authority:\"test.grafana.k6.v1\"}`,\n\t\t\tExpectedAuthority: \"test.grafana.k6.v1\",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestRuntime, params := newParamsTestRuntime(t, tc.JSON)\n\n\t\t\tp, err := newConnectParams(testRuntime.VU, params)\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.ExpectedAuthority, p.Authority)\n\t\t})\n\t}\n}\n\n// newParamsTestRuntime creates a new test runtime\n// that could be used to test the params\n// it also moves to the VU context and creates the params\n// Sobek value that could be used in the tests\nfunc newParamsTestRuntime(t *testing.T, paramsJSON string) (*modulestest.Runtime, sobek.Value) {\n\tt.Helper()\n\n\ttestRuntime := modulestest.NewRuntime(t)\n\tregistry := metrics.NewRegistry()\n\n\tlogger := logrus.New()\n\tlogger.SetLevel(logrus.InfoLevel)\n\tlogger.Out = io.Discard\n\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: metrics.NewSystemTagSet(\n\t\t\t\tmetrics.TagName,\n\t\t\t\tmetrics.TagURL,\n\t\t\t),\n\t\t\tUserAgent: null.StringFrom(\"k6-test\"),\n\t\t},\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t\tLogger:         logger,\n\t}\n\n\ttestRuntime.MoveToVUContext(state)\n\n\t_, err := testRuntime.VU.Runtime().RunString(`let params = ` + paramsJSON + `;`)\n\trequire.NoError(t, err)\n\n\tparams := testRuntime.VU.Runtime().Get(\"params\")\n\trequire.False(t, common.IsNullish(params))\n\n\treturn testRuntime, params\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/stream.go",
    "content": "package grpc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/lib/netext/grpcext\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/metrics\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/mstoykov/k6-taskqueue-lib/taskqueue\"\n\t\"github.com/sirupsen/logrus\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n)\n\n// message is a struct that\ntype message struct {\n\tisClosing bool\n\tmsg       []byte\n}\n\nconst (\n\topened = iota + 1\n\tclosed\n)\n\nconst (\n\ttimestampMetadata = \"ts\"\n)\n\ntype stream struct {\n\tvu     modules.VU\n\tclient *Client\n\n\tlogger logrus.FieldLogger\n\n\tmethodDescriptor protoreflect.MethodDescriptor\n\n\tmethod string\n\tstream *grpcext.Stream\n\n\ttagsAndMeta *metrics.TagsAndMeta\n\ttq          *taskqueue.TaskQueue\n\n\tinstanceMetrics *instanceMetrics\n\tbuiltinMetrics  *metrics.BuiltinMetrics\n\n\tobj *sobek.Object // the object that is given to js to interact with the stream\n\n\twritingState int8\n\tdone         chan struct{}\n\n\twriteQueueCh chan message\n\n\teventListeners *eventListeners\n\n\ttimeoutCancel context.CancelFunc\n}\n\n// defineStream defines the sobek.Object that is given to js to interact with the Stream\nfunc defineStream(rt *sobek.Runtime, s *stream) {\n\tmust(rt, s.obj.DefineDataProperty(\n\t\t\"on\", rt.ToValue(s.on), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\n\tmust(rt, s.obj.DefineDataProperty(\n\t\t\"write\", rt.ToValue(s.write), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\n\tmust(rt, s.obj.DefineDataProperty(\n\t\t\"end\", rt.ToValue(s.end), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n}\n\nfunc (s *stream) beginStream(p *callParams) error {\n\treq := &grpcext.StreamRequest{\n\t\tMethod:                 s.method,\n\t\tMethodDescriptor:       s.methodDescriptor,\n\t\tDiscardResponseMessage: p.DiscardResponseMessage,\n\t\tTagsAndMeta:            &p.TagsAndMeta,\n\t\tMetadata:               p.Metadata,\n\t}\n\n\tctx := s.vu.Context()\n\tvar cancel context.CancelFunc\n\n\tif p.Timeout != time.Duration(0) {\n\t\tctx, cancel = context.WithTimeout(ctx, p.Timeout)\n\t}\n\n\ts.timeoutCancel = cancel\n\n\tstream, err := s.client.conn.NewStream(ctx, *req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create a new stream: %w\", err)\n\t}\n\ts.stream = stream\n\tmetrics.PushIfNotDone(s.vu.Context(), s.vu.State().Samples, metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: s.instanceMetrics.Streams,\n\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t},\n\t\tTime:     time.Now(),\n\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\tValue:    1,\n\t})\n\n\tgo s.loop()\n\n\treturn nil\n}\n\nfunc (s *stream) loop() {\n\tctx := s.vu.Context()\n\twg := new(sync.WaitGroup)\n\n\tdefer func() {\n\t\twg.Wait()\n\t\ts.tq.Close()\n\t}()\n\n\t// read & write data from/to the stream\n\twg.Add(2)\n\tgo s.readData(wg)\n\tgo s.writeData(wg)\n\n\tctxDone := ctx.Done()\n\tfor {\n\t\tselect {\n\t\tcase <-ctxDone:\n\t\t\t// VU is shutting down during an interrupt\n\t\t\t// stream events will not be forwarded to the VU\n\t\t\ts.tq.Queue(func() error {\n\t\t\t\treturn s.closeWithError(nil)\n\t\t\t})\n\t\t\treturn\n\t\tcase <-s.done:\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (s *stream) queueMessage(msg any) {\n\tnow := time.Now()\n\tmetrics.PushIfNotDone(s.vu.Context(), s.vu.State().Samples, metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: s.instanceMetrics.StreamsMessagesReceived,\n\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t},\n\t\tTime:     now,\n\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\tValue:    1,\n\t})\n\n\ts.tq.Queue(func() error {\n\t\trt := s.vu.Runtime()\n\t\tlisteners := s.eventListeners.all(eventData)\n\n\t\tmetadataObj := rt.NewObject()\n\t\terr := metadataObj.Set(timestampMetadata, rt.ToValue(now.Unix()))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tfor _, messageListener := range listeners {\n\t\t\tif _, err := messageListener(rt.ToValue(msg), metadataObj); err != nil {\n\t\t\t\t// TODO(olegbespalov) consider logging the error\n\t\t\t\t_ = s.closeWithError(err)\n\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n}\n\n// readData reads data from the stream and forward them to the readDataChan\nfunc (s *stream) readData(wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\n\tfor {\n\t\tmsg, err := s.stream.ReceiveConverted()\n\n\t\tif err != nil && !isRegularClosing(err) {\n\t\t\ts.logger.WithError(err).Debug(\"error while reading from the stream\")\n\n\t\t\ts.tq.Queue(func() error {\n\t\t\t\treturn s.closeWithError(err)\n\t\t\t})\n\n\t\t\treturn\n\t\t}\n\n\t\tif isRegularClosing(err) {\n\t\t\ts.logger.WithError(err).Debug(\"stream is cancelled/finished\")\n\n\t\t\ts.tq.Queue(func() error {\n\t\t\t\treturn s.closeWithError(err)\n\t\t\t})\n\n\t\t\treturn\n\t\t}\n\n\t\tif msg != nil || !reflect.ValueOf(msg).IsNil() {\n\t\t\ts.queueMessage(msg)\n\t\t}\n\t}\n}\n\nfunc isRegularClosing(err error) bool {\n\treturn errors.Is(err, io.EOF) || errors.Is(err, grpcext.ErrCanceled)\n}\n\n// writeData writes data to the stream\nfunc (s *stream) writeData(wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\n\twriteChannel := make(chan message)\n\n\twg.Go(func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase msg, ok := <-writeChannel:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif msg.isClosing {\n\t\t\t\t\terr := s.stream.CloseSend()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\ts.logger.WithError(err).Error(\"an error happened during stream closing\")\n\t\t\t\t\t}\n\n\t\t\t\t\ts.tq.Queue(func() error {\n\t\t\t\t\t\treturn s.closeWithError(err)\n\t\t\t\t\t})\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\terr := s.stream.Send(msg.msg)\n\t\t\t\tif err != nil {\n\t\t\t\t\ts.processSendError(err)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tmetrics.PushIfNotDone(s.vu.Context(), s.vu.State().Samples, metrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: s.instanceMetrics.StreamsMessagesSent,\n\t\t\t\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t\t\t\t},\n\t\t\t\t\tTime:     time.Now(),\n\t\t\t\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\t\t\t\tValue:    1,\n\t\t\t\t})\n\t\t\tcase <-s.done:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\t{\n\t\tdefer close(writeChannel)\n\n\t\tqueue := make([]message, 0)\n\t\tvar wch chan message\n\t\tvar msg message\n\n\t\tfor {\n\t\t\twch = nil // this way if nothing to read it will just block\n\t\t\tif len(queue) > 0 {\n\t\t\t\tmsg = queue[0]\n\t\t\t\twch = writeChannel\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase msg = <-s.writeQueueCh:\n\t\t\t\tqueue = append(queue, msg)\n\t\t\tcase wch <- msg:\n\t\t\t\tqueue = queue[:copy(queue, queue[1:])]\n\n\t\t\tcase <-s.done:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (s *stream) processSendError(err error) {\n\tif errors.Is(err, io.EOF) {\n\t\ts.logger.WithError(err).Debug(\"skip sending a message stream is cancelled/finished\")\n\t\terr = nil\n\t}\n\n\ts.tq.Queue(func() error {\n\t\treturn s.closeWithError(err)\n\t})\n}\n\n// on registers a handler for a certain event type\nfunc (s *stream) on(event string, handler func(sobek.Value, sobek.Value) (sobek.Value, error)) {\n\tif handler == nil {\n\t\tcommon.Throw(s.vu.Runtime(), fmt.Errorf(\"handler for %q event isn't a callable function\", event))\n\t}\n\n\tif err := s.eventListeners.add(event, handler); err != nil {\n\t\ts.vu.State().Logger.Warnf(\"can't register %s event handler: %s\", event, err)\n\t}\n}\n\n// write writes a message to the stream\nfunc (s *stream) write(input sobek.Value) {\n\tif s.writingState != opened {\n\t\treturn\n\t}\n\n\tif common.IsNullish(input) {\n\t\ts.logger.Warnf(\"can't send empty message\")\n\t\treturn\n\t}\n\n\trt := s.vu.Runtime()\n\n\tb, err := input.ToObject(rt).MarshalJSON()\n\tif err != nil {\n\t\ts.logger.WithError(err).Warnf(\"can't marshal message\")\n\t}\n\n\ts.writeQueueCh <- message{msg: b}\n}\n\n// end closes client the stream\nfunc (s *stream) end() {\n\tif s.writingState == closed {\n\t\treturn\n\t}\n\n\ts.logger.Debugf(\"finishing stream %s writing\", s.method)\n\n\ts.writingState = closed\n\ts.writeQueueCh <- message{isClosing: true}\n}\n\nfunc (s *stream) closeWithError(err error) error {\n\ts.close(err)\n\n\treturn s.callErrorListeners(err)\n}\n\n// close closes the stream and call end event listeners\n// Note: in the regular closing the io.EOF could come\nfunc (s *stream) close(err error) {\n\tif err == nil {\n\t\treturn\n\t}\n\n\tselect {\n\tcase <-s.done:\n\t\ts.logger.Debugf(\"stream %v is already closed\", s.method)\n\t\treturn\n\tdefault:\n\t}\n\n\ts.logger.Debugf(\"stream %s is closing\", s.method)\n\tclose(s.done)\n\n\ts.tq.Queue(func() error {\n\t\treturn s.callEventListeners(eventEnd)\n\t})\n\n\tif s.timeoutCancel != nil {\n\t\ts.timeoutCancel()\n\t}\n}\n\nfunc (s *stream) callErrorListeners(e error) error {\n\tif e == nil || errors.Is(e, io.EOF) {\n\t\treturn nil\n\t}\n\n\trt := s.vu.Runtime()\n\n\tobj := extractError(e)\n\n\tlist := s.eventListeners.all(eventError)\n\n\tif len(list) == 0 {\n\t\ts.logger.Warnf(\"no handlers for error registered, but an error happened: %s\", e)\n\t}\n\n\tnow := time.Now()\n\tmetadataObj := rt.NewObject()\n\terr := metadataObj.Set(timestampMetadata, rt.ToValue(now.Unix()))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, errorListener := range list {\n\t\tif _, err := errorListener(rt.ToValue(obj), metadataObj); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\ntype grpcError struct {\n\t// Code is a gRPC error code.\n\tCode codes.Code `json:\"code\"`\n\t// Details is a list details attached to the error.\n\tDetails []any `json:\"details\"`\n\t// Message is the original error message.\n\tMessage string `json:\"message\"`\n}\n\n// Error to satisfy the error interface.\nfunc (e grpcError) Error() string {\n\treturn fmt.Sprintf(\"code: %d, message: %s\", e.Code, e.Message)\n}\n\n// extractError tries to extract error information from an error.\n// If the error is not a gRPC error, it will be wrapped into a gRPC error.\nfunc extractError(e error) grpcError {\n\tgrpcStatus := status.Convert(e)\n\n\tw := grpcError{\n\t\tCode:    grpcStatus.Code(),\n\t\tDetails: grpcStatus.Details(),\n\t\tMessage: grpcStatus.Message(),\n\t}\n\n\t// fallback to the original error message\n\tif w.Message == \"\" {\n\t\tw.Message = e.Error()\n\t}\n\n\treturn w\n}\n\nfunc (s *stream) callEventListeners(eventType string) error {\n\tnow := time.Now()\n\trt := s.vu.Runtime()\n\n\tmetadataObj := rt.NewObject()\n\terr := metadataObj.Set(timestampMetadata, rt.ToValue(now.Unix()))\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, listener := range s.eventListeners.all(eventType) {\n\t\tif _, err := listener(rt.ToValue(struct{}{}), metadataObj); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// must is a small helper that will panic if err is not nil.\nfunc must(rt *sobek.Runtime, err error) {\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/stream_test.go",
    "content": "package grpc_test\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/grpcservice\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin/grpc_wrappers_testing\"\n\t\"go.k6.io/k6/metrics\"\n\n\t\"github.com/golang/protobuf/ptypes/wrappers\"\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/status\"\n)\n\nfunc TestStream_InvalidHeader(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_testing/test.proto\");`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\t_, err = ts.Run(`\n\tclient.connect(\"GRPCBIN_ADDR\");\n\tnew grpc.Stream(client, \"foo/bar\")`)\n\n\tassert.Error(t, err)\n\tassert.ErrorContains(t, err, `method \"/foo/bar\" not found in file descriptors`)\n}\n\nfunc TestStream_RequestHeaders(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tvar registeredMetadata metadata.MD\n\tstub := &featureExplorerStub{}\n\tstub.listFeatures = func(_ *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error {\n\t\t// collect metadata from the stream context\n\t\tmd, ok := metadata.FromIncomingContext(stream.Context())\n\t\tif ok {\n\t\t\tregisteredMetadata = md\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tgrpcservice.RegisterFeatureExplorerServer(ts.httpBin.ServerGRPC, stub)\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/grpcservice/route_guide.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tlet stream = new grpc.Stream(client, \"main.FeatureExplorer/ListFeatures\", { metadata: { \"X-Load-Tester\": \"k6\" } })\n\t\tstream.write({\n\t\t\tlo: {\n\t\t\t  latitude: 400000000,\n\t\t\t  longitude: -750000000,\n\t\t\t},\n\t\t\thi: {\n\t\t\t  latitude: 420000000,\n\t\t\t  longitude: -730000000,\n\t\t\t},\n\t\t});\n\t\t`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\tval, err = ts.RunOnEventLoop(vuString.code)\n\n\tassertResponse(t, vuString, err, val, ts)\n\n\t// Check that the metadata was registered\n\tassert.Len(t, registeredMetadata[\"x-load-tester\"], 1)\n\tassert.Equal(t, registeredMetadata[\"x-load-tester\"][0], \"k6\")\n}\n\nfunc TestStream_ErrorHandling(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tstub := &featureExplorerStub{}\n\n\tsavedFeatures := []*grpcservice.Feature{\n\t\t{\n\t\t\tName: \"foo\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  1,\n\t\t\t\tLongitude: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"bar\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  3,\n\t\t\t\tLongitude: 4,\n\t\t\t},\n\t\t},\n\t}\n\n\tstub.listFeatures = func(_ *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error {\n\t\tfor _, feature := range savedFeatures {\n\t\t\tif err := stream.Send(feature); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn status.Error(codes.Internal, \"lorem ipsum\")\n\t}\n\n\tgrpcservice.RegisterFeatureExplorerServer(ts.httpBin.ServerGRPC, stub)\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/grpcservice/route_guide.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tlet stream = new grpc.Stream(client, \"main.FeatureExplorer/ListFeatures\")\n\t\tstream.write({\n\t\t\tlo: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t\thi: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t});\n\t\tstream.on('data', function (data) {\n\t\t\tcall('Feature:' + data.name);\n\t\t})\n\t\tstream.on('error', function (e) {\n\t\t\tcall('Code: ' + e.code + ' Message: ' + e.message);\n\t\t});\n\t\t`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\tval, err = ts.RunOnEventLoop(vuString.code)\n\n\tassertResponse(t, vuString, err, val, ts)\n\n\tassert.Equal(t,\n\t\t[]string{\n\t\t\t\"Feature:foo\",\n\t\t\t\"Feature:bar\",\n\t\t\t\"Code: 13 Message: lorem ipsum\",\n\t\t},\n\t\tts.callRecorder.Recorded(),\n\t)\n}\n\n// this test case is checking that everything that server sends\n// after the client finished (client.end called) is delivered to the client\n// and the end event is called\nfunc TestStream_ReceiveAllServerResponsesAfterEnd(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tstub := &featureExplorerStub{}\n\n\tsavedFeatures := []*grpcservice.Feature{\n\t\t{\n\t\t\tName: \"foo\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  1,\n\t\t\t\tLongitude: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"bar\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  3,\n\t\t\t\tLongitude: 4,\n\t\t\t},\n\t\t},\n\t}\n\n\tstub.listFeatures = func(_ *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error {\n\t\tfor _, feature := range savedFeatures {\n\t\t\t// adding a delay to make server response \"slower\"\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\n\t\t\tif err := stream.Send(feature); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tgrpcservice.RegisterFeatureExplorerServer(ts.httpBin.ServerGRPC, stub)\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/grpcservice/route_guide.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tlet stream = new grpc.Stream(client, \"main.FeatureExplorer/ListFeatures\")\n\t\tstream.on('data', function (data) {\n\t\t\tcall('Feature:' + data.name);\n\t\t});\n\t\tstream.on('end', function () {\n\t\t\tcall('End called');\n\t\t});\n\n\t\tstream.write({\n\t\t\tlo: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t\thi: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t});\n\t\tstream.end();\n\t\t`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\tval, err = ts.RunOnEventLoop(vuString.code)\n\n\tassertResponse(t, vuString, err, val, ts)\n\n\tassert.Equal(t, []string{\n\t\t\"Feature:foo\",\n\t\t\"Feature:bar\",\n\t\t\"End called\",\n\t}, ts.callRecorder.Recorded())\n}\n\nfunc TestStream_ReceiveAllServerResponsesAfterEndWithDiscardedMessages(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tstub := &featureExplorerStub{}\n\n\tsavedFeatures := []*grpcservice.Feature{\n\t\t{\n\t\t\tName: \"foo\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  1,\n\t\t\t\tLongitude: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"bar\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  3,\n\t\t\t\tLongitude: 4,\n\t\t\t},\n\t\t},\n\t}\n\n\tstub.listFeatures = func(_ *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error {\n\t\tfor _, feature := range savedFeatures {\n\t\t\t// adding a delay to make server response \"slower\"\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\n\t\t\tif err := stream.Send(feature); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tgrpcservice.RegisterFeatureExplorerServer(ts.httpBin.ServerGRPC, stub)\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/grpcservice/route_guide.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tlet stream = new grpc.Stream(client, \"main.FeatureExplorer/ListFeatures\", { discardResponseMessage: true })\n\t\tstream.on('data', function (data) {\n\t\t\tcall('Data: ' + JSON.stringify(data));\n\t\t});\n\t\tstream.on('end', function () {\n\t\t\tcall('End called');\n\t\t});\n\n\t\tstream.write({\n\t\t\tlo: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t\thi: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t});\n\t\tstream.end();\n\t\t`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\tval, err = ts.RunOnEventLoop(vuString.code)\n\n\tassertResponse(t, vuString, err, val, ts)\n\n\tassert.Equal(t, []string{\n\t\t\"Data: {}\",\n\t\t\"Data: {}\",\n\t\t\"End called\",\n\t}, ts.callRecorder.Recorded())\n}\n\nfunc TestStream_ReceiveMetadata(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tstub := &featureExplorerStub{}\n\n\tsavedFeatures := []*grpcservice.Feature{\n\t\t{\n\t\t\tName: \"foo\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  1,\n\t\t\t\tLongitude: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tName: \"bar\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  3,\n\t\t\t\tLongitude: 4,\n\t\t\t},\n\t\t},\n\t}\n\n\tstub.listFeatures = func(_ *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error {\n\t\tfor _, feature := range savedFeatures {\n\t\t\t// adding a delay to make server response \"slower\"\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\n\t\t\tif err := stream.Send(feature); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tgrpcservice.RegisterFeatureExplorerServer(ts.httpBin.ServerGRPC, stub)\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/grpcservice/route_guide.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tlet stream = new grpc.Stream(client, \"main.FeatureExplorer/ListFeatures\")\n\t\tstream.on('data', function (data, meta) {\n\t\t\tcall(meta.ts);\n\t\t});\n\t\tstream.on('end', function (_, meta) {\n\t\t\tcall(meta.ts);\n\t\t});\n\t\tstream.write({\n\t\t\tlo: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t\thi: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t});\n\t\tstream.end();\n\t\t`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\tval, err = ts.RunOnEventLoop(vuString.code)\n\n\tassertResponse(t, vuString, err, val, ts)\n\n\tfor _, call := range ts.callRecorder.Recorded() {\n\t\tseconds, err := strconv.ParseInt(call, 10, 64)\n\t\tassert.NoError(t, err)\n\t\tmetaTS := time.Unix(seconds, 0)\n\t\tassert.WithinDuration(t, time.Now(), metaTS, 1*time.Minute)\n\t}\n}\n\n// featureExplorerStub is a stub for FeatureExplorerServer\n// it has ability to override methods\ntype featureExplorerStub struct {\n\tgrpcservice.UnimplementedFeatureExplorerServer\n\n\tgetFeature   func(ctx context.Context, point *grpcservice.Point) (*grpcservice.Feature, error)\n\tlistFeatures func(rect *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error\n}\n\nfunc (s *featureExplorerStub) GetFeature(ctx context.Context, point *grpcservice.Point) (*grpcservice.Feature, error) {\n\tif s.getFeature != nil {\n\t\treturn s.getFeature(ctx, point)\n\t}\n\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetFeature not implemented\")\n}\n\nfunc (s *featureExplorerStub) ListFeatures(rect *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error {\n\tif s.listFeatures != nil {\n\t\treturn s.listFeatures(rect, stream)\n\t}\n\n\treturn status.Errorf(codes.Unimplemented, \"method ListFeatures not implemented\")\n}\n\nfunc TestStream_Wrappers(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tstub := grpc_wrappers_testing.Register(ts.httpBin.ServerGRPC)\n\tstub.TestStreamImplementation = func(stream grpc_wrappers_testing.Service_TestStreamServer) error {\n\t\tresult := \"\"\n\n\t\tfor {\n\t\t\tmsg, err := stream.Recv()\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\treturn stream.SendAndClose(&wrappers.StringValue{\n\t\t\t\t\tValue: strings.TrimRight(result, \" \"),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tresult += msg.Value + \" \"\n\t\t}\n\t}\n\n\treplace := func(code string) (sobek.Value, error) {\n\t\treturn ts.VU.Runtime().RunString(ts.httpBin.Replacer.Replace(code))\n\t}\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_wrappers_testing/test.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tlet stream = new grpc.Stream(client, \"grpc.wrappers.testing.Service/TestStream\");\n\t\tstream.on('data', function (data) {\n\t\t\tcall('Result: ' + data);\n\t\t})\n\n\t\tstream.write('Hey');\n\t\tstream.write('John');\n\t\tstream.end();\n\n\t\tstream.on('error', function (e) {\n\t\t\tcall('Code: ' + e.code + ' Message: ' + e.message);\n\t\t});\n\t\t`,\n\t}\n\n\tval, err := replace(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\tval, err = replace(vuString.code)\n\n\tts.EventLoop.WaitOnRegistered()\n\n\tassertResponse(t, vuString, err, val, ts)\n\n\tassert.Equal(t, []string{\"Result: Hey John\"}, ts.callRecorder.Recorded())\n}\n\nfunc TestStream_UndefinedHandler(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tstub := grpc_wrappers_testing.Register(ts.httpBin.ServerGRPC)\n\tstub.TestStreamImplementation = func(stream grpc_wrappers_testing.Service_TestStreamServer) error {\n\t\treturn stream.SendAndClose(&wrappers.StringValue{\n\t\t\tValue: \"test\",\n\t\t})\n\t}\n\n\treplace := func(code string) (sobek.Value, error) {\n\t\treturn ts.VU.Runtime().RunString(ts.httpBin.Replacer.Replace(code))\n\t}\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/httpmultibin/grpc_wrappers_testing/test.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\t\tlet stream = new grpc.Stream(client, \"grpc.wrappers.testing.Service/TestStream\");\n\t\tstream.on('data', undefined);\n\n\t\tstream.end();\n\t\t`,\n\t}\n\n\tval, err := replace(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\t_, err = replace(vuString.code)\n\tts.EventLoop.WaitOnRegistered()\n\n\trequire.ErrorContains(t, err, \"handler for \\\"data\\\" event isn't a callable function\")\n}\n\n// TestStream_MetricsTagsMetadata tests that the metrics tags are correctly\n// added to samples.\nfunc TestStream_MetricsTagsMetadata(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\n\tstub := &featureExplorerStub{}\n\n\tstub.listFeatures = func(_ *grpcservice.Rectangle, stream grpcservice.FeatureExplorer_ListFeaturesServer) error {\n\t\treturn stream.Send(&grpcservice.Feature{\n\t\t\tName: \"foo\",\n\t\t\tLocation: &grpcservice.Point{\n\t\t\t\tLatitude:  1,\n\t\t\t\tLongitude: 2,\n\t\t\t},\n\t\t})\n\t}\n\n\tgrpcservice.RegisterFeatureExplorerServer(ts.httpBin.ServerGRPC, stub)\n\n\tinitString := codeBlock{\n\t\tcode: `\n\t\tvar client = new grpc.Client();\n\t\tclient.load([], \"../../../../lib/testutils/grpcservice/route_guide.proto\");`,\n\t}\n\tvuString := codeBlock{\n\t\tcode: `\n\t\tclient.connect(\"GRPCBIN_ADDR\");\n\n\t\tlet params = {\n\t\t\ttags: { \"tag1\": \"value1\" },\n\t\t};\n\n\t\tlet stream = new grpc.Stream(client, \"main.FeatureExplorer/ListFeatures\", params)\n\t\tstream.on('data', function (data) {\n\t\t\tcall('Feature:' + data.name);\n\t\t});\n\t\tstream.on('end', function () {\n\t\t\tcall('End called');\n\t\t});\n\n\t\tstream.write({\n\t\t\tlo: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t\thi: {\n\t\t\t  latitude: 1,\n\t\t\t  longitude: 2,\n\t\t\t},\n\t\t});\n\t\tstream.end();\n\t\t`,\n\t}\n\n\tval, err := ts.Run(initString.code)\n\tassertResponse(t, initString, err, val, ts)\n\n\tts.ToVUContext()\n\n\tval, err = ts.RunOnEventLoop(vuString.code)\n\n\tassertResponse(t, vuString, err, val, ts)\n\n\texpTags := map[string]string{\"tag1\": \"value1\"}\n\n\tsamplesBuf := metrics.GetBufferedSamples(ts.samples)\n\n\tassert.Len(t, samplesBuf, 4)\n\tfor _, samples := range samplesBuf {\n\t\tfor _, sample := range samples.GetSamples() {\n\t\t\tassertTags(t, sample, expTags)\n\t\t}\n\t}\n}\n\nfunc assertTags(t *testing.T, sample metrics.Sample, tags map[string]string) {\n\tfor k, v := range tags {\n\t\ttag, ok := sample.Tags.Get(k)\n\t\tassert.True(t, ok)\n\t\tassert.Equal(t, v, tag)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/grpc/teststate_test.go",
    "content": "package grpc_test\n\nimport (\n\t\"io\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\txk6grpc \"go.k6.io/k6/internal/js/modules/k6/grpc\"\n)\n\nconst isWindows = runtime.GOOS == \"windows\"\n\n// codeBlock represents an execution of a k6 script.\ntype codeBlock struct {\n\tcode       string\n\tval        any\n\terr        string\n\twindowsErr string\n\tasserts    func(*testing.T, *httpmultibin.HTTPMultiBin, chan metrics.SampleContainer, error)\n}\n\ntype testcase struct {\n\tname       string\n\tsetup      func(*httpmultibin.HTTPMultiBin)\n\tinitString codeBlock // runs in the init context\n\tvuString   codeBlock // runs in the vu context\n}\n\n// callRecorder a helper type that records all calls\ntype callRecorder struct {\n\tsync.Mutex\n\tcalls []string\n}\n\n// Call records a call\nfunc (r *callRecorder) Call(text string) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tr.calls = append(r.calls, text)\n}\n\n// Len just returns the length of the calls\nfunc (r *callRecorder) Len() int {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\treturn len(r.calls)\n}\n\n// Recorded returns the recorded calls\nfunc (r *callRecorder) Recorded() []string {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tresult := make([]string, 0, len(r.calls))\n\tresult = append(result, r.calls...)\n\n\treturn result\n}\n\ntype testState struct {\n\t*modulestest.Runtime\n\thttpBin      *httpmultibin.HTTPMultiBin\n\tsamples      chan metrics.SampleContainer\n\tlogger       logrus.FieldLogger\n\tloggerHook   *testutils.SimpleLogrusHook\n\tcallRecorder *callRecorder\n}\n\n// Run replaces the httpbin address and runs the code.\nfunc (ts *testState) Run(code string) (sobek.Value, error) {\n\treturn ts.VU.Runtime().RunString(ts.httpBin.Replacer.Replace(code))\n}\n\n// RunOnEventLoop replaces the httpbin address and run the code on event loop\nfunc (ts *testState) RunOnEventLoop(code string) (sobek.Value, error) {\n\treturn ts.Runtime.RunOnEventLoop(ts.httpBin.Replacer.Replace(code))\n}\n\n// newTestState creates a new test state.\nfunc newTestState(t *testing.T) testState {\n\tt.Helper()\n\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tsamples := make(chan metrics.SampleContainer, 1000)\n\ttestRuntime := modulestest.NewRuntime(t)\n\n\tcwd, err := os.Getwd() //nolint:forbidigo\n\trequire.NoError(t, err)\n\tfs := fsext.NewOsFs()\n\n\tif isWindows {\n\t\tfs = fsext.NewTrimFilePathSeparatorFs(fs)\n\t}\n\ttestRuntime.VU.InitEnvField.CWD = &url.URL{Scheme: \"file\", Path: filepath.ToSlash(cwd)}\n\ttestRuntime.VU.InitEnvField.FileSystems = map[string]fsext.Fs{\"file\": fs}\n\n\tlogger := logrus.New()\n\tlogger.SetLevel(logrus.InfoLevel)\n\tlogger.Out = io.Discard\n\n\thook := testutils.NewLogHook()\n\tlogger.AddHook(hook)\n\n\trecorder := &callRecorder{\n\t\tcalls: make([]string, 0),\n\t}\n\n\tts := testState{\n\t\tRuntime:      testRuntime,\n\t\thttpBin:      tb,\n\t\tsamples:      samples,\n\t\tlogger:       logger,\n\t\tloggerHook:   hook,\n\t\tcallRecorder: recorder,\n\t}\n\n\tm, ok := xk6grpc.New().NewModuleInstance(ts.VU).(*xk6grpc.ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, ts.VU.Runtime().Set(\"grpc\", m.Exports().Named))\n\trequire.NoError(t, ts.VU.Runtime().Set(\"call\", recorder.Call))\n\n\treturn ts\n}\n\n// ToVUContext moves the test state to the VU context.\nfunc (ts *testState) ToVUContext() {\n\tregistry := metrics.NewRegistry()\n\n\tstate := &lib.State{\n\t\tDialer:    ts.httpBin.Dialer,\n\t\tTLSConfig: ts.httpBin.TLSClientConfig,\n\t\tSamples:   ts.samples,\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: metrics.NewSystemTagSet(\n\t\t\t\tmetrics.TagName,\n\t\t\t\tmetrics.TagURL,\n\t\t\t),\n\t\t\tUserAgent: null.StringFrom(\"k6-test\"),\n\t\t},\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t\tLogger:         ts.logger,\n\t}\n\n\tts.MoveToVUContext(state)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/k6.go",
    "content": "// Package k6 implements the module imported as 'k6' from inside k6.\npackage k6\n\nimport (\n\t\"errors\"\n\t\"math/rand\" // nosemgrep: math-random-used // used to seed the Marh.random of the JS VM that is pseudo random by specification\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nvar (\n\t// ErrGroupInInitContext is returned when group() are using in the init context.\n\tErrGroupInInitContext = common.NewInitContextError(\"Using group() in the init context is not supported\")\n\n\t// ErrCheckInInitContext is returned when check() are using in the init context.\n\tErrCheckInInitContext = common.NewInitContextError(\"Using check() in the init context is not supported\")\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// K6 represents an instance of the k6 module.\n\tK6 struct {\n\t\tvu modules.VU\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &K6{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &K6{vu: vu}\n}\n\n// Exports returns the exports of the k6 module.\nfunc (mi *K6) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"check\":      mi.Check,\n\t\t\t\"fail\":       mi.Fail,\n\t\t\t\"group\":      mi.Group,\n\t\t\t\"randomSeed\": mi.RandomSeed,\n\t\t\t\"sleep\":      mi.Sleep,\n\t\t},\n\t}\n}\n\n// Fail is a fancy way of saying `throw \"something\"`.\nfunc (*K6) Fail(msg string) (sobek.Value, error) {\n\treturn sobek.Undefined(), errors.New(msg)\n}\n\n// Sleep waits the provided seconds before continuing the execution.\nfunc (mi *K6) Sleep(secs float64) {\n\tctx := mi.vu.Context()\n\ttimer := time.NewTimer(time.Duration(secs * float64(time.Second)))\n\tselect {\n\tcase <-timer.C:\n\tcase <-ctx.Done():\n\t\ttimer.Stop()\n\t}\n}\n\n// RandomSeed sets the seed to the random generator used for this VU.\nfunc (mi *K6) RandomSeed(seed int64) {\n\trandSource := rand.New(rand.NewSource(seed)).Float64 //nolint:gosec\n\tmi.vu.Runtime().SetRandSource(randSource)\n}\n\n// Group wraps a function call and executes it within the provided group name.\nfunc (mi *K6) Group(name string, val sobek.Value) (sobek.Value, error) {\n\tstate := mi.vu.State()\n\tif state == nil {\n\t\treturn nil, ErrGroupInInitContext\n\t}\n\n\tif common.IsNullish(val) {\n\t\treturn nil, errors.New(\"group() requires a callback as a second argument\")\n\t}\n\tfn, ok := sobek.AssertFunction(val)\n\tif !ok {\n\t\treturn nil, errors.New(\"group() requires a callback as a second argument\")\n\t}\n\tif common.IsAsyncFunction(mi.vu.Runtime(), val) {\n\t\treturn sobek.Undefined(), errors.New(\"group() does not support async functions as arguments, \" +\n\t\t\t\"please see https://grafana.com/docs/k6/latest/javascript-api/k6/group/ for more info\")\n\t}\n\toldGroupName, _ := state.Tags.GetCurrentValues().Tags.Get(metrics.TagGroup.String())\n\t// TODO: what are we doing if group is not tagged\n\tnewGroupName, err := lib.NewGroupPath(oldGroupName, name)\n\tif err != nil {\n\t\treturn sobek.Undefined(), err\n\t}\n\n\tshouldUpdateTag := state.Options.SystemTags.Has(metrics.TagGroup)\n\tif shouldUpdateTag {\n\t\tstate.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\ttagsAndMeta.SetSystemTagOrMeta(metrics.TagGroup, newGroupName)\n\t\t})\n\t}\n\tdefer func() {\n\t\tif shouldUpdateTag {\n\t\t\tstate.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\t\ttagsAndMeta.SetSystemTagOrMeta(metrics.TagGroup, oldGroupName)\n\t\t\t})\n\t\t}\n\t}()\n\n\tstartTime := time.Now()\n\tret, err := fn(sobek.Undefined())\n\tt := time.Now()\n\n\tctx := mi.vu.Context()\n\tctm := state.Tags.GetCurrentValues()\n\tmetrics.PushIfNotDone(ctx, state.Samples, metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: state.BuiltinMetrics.GroupDuration,\n\t\t\tTags:   ctm.Tags,\n\t\t},\n\t\tTime:     t,\n\t\tValue:    metrics.D(t.Sub(startTime)),\n\t\tMetadata: ctm.Metadata,\n\t})\n\n\treturn ret, err\n}\n\n// Check will emit check metrics for the provided checks.\nfunc (mi *K6) Check(arg0, checks sobek.Value, extras ...sobek.Value) (bool, error) {\n\tstate := mi.vu.State()\n\tif state == nil {\n\t\treturn false, ErrCheckInInitContext\n\t}\n\tif checks == nil {\n\t\treturn false, errors.New(\"no checks provided to `check`\")\n\t}\n\tctx := mi.vu.Context()\n\trt := mi.vu.Runtime()\n\tt := time.Now()\n\n\t// Prepare the metric tags\n\tcommonTagsAndMeta := state.Tags.GetCurrentValues()\n\tif len(extras) > 0 {\n\t\tif err := common.ApplyCustomUserTags(rt, &commonTagsAndMeta, extras[0]); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\n\tsucc := true\n\tvar exc error\n\tobj := checks.ToObject(rt)\n\tfor _, name := range obj.Keys() {\n\t\tif strings.Contains(name, lib.GroupSeparator) {\n\t\t\treturn false, lib.ErrNameContainsGroupSeparator\n\t\t}\n\t\tval := obj.Get(name)\n\n\t\ttags := commonTagsAndMeta.Tags\n\t\tif state.Options.SystemTags.Has(metrics.TagCheck) {\n\t\t\ttags = tags.With(\"check\", name)\n\t\t}\n\n\t\tif common.IsAsyncFunction(rt, val) {\n\t\t\treturn false, errors.New(\"the built-in check() does not support async functions as arguments. \" +\n\t\t\t\t\"Use the JavaScript utils library as a replacement. \" +\n\t\t\t\t\"Refer to https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/check/ for more info\")\n\t\t}\n\n\t\t// Resolve callables into values.\n\t\tfn, ok := sobek.AssertFunction(val)\n\t\tif ok {\n\t\t\ttmpVal, err := fn(sobek.Undefined(), arg0)\n\t\t\tval = tmpVal\n\t\t\tif err != nil {\n\t\t\t\tval = rt.ToValue(false)\n\t\t\t\texc = err\n\t\t\t}\n\t\t}\n\t\tbooleanVal := val.ToBoolean()\n\t\tif !booleanVal {\n\t\t\t// A single failure makes the return value false.\n\t\t\tsucc = false\n\t\t}\n\n\t\tsample := metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: state.BuiltinMetrics.Checks,\n\t\t\t\tTags:   tags,\n\t\t\t},\n\t\t\tTime:     t,\n\t\t\tMetadata: commonTagsAndMeta.Metadata,\n\t\t}\n\t\tif booleanVal {\n\t\t\tsample.Value = 1\n\t\t}\n\n\t\tmetrics.PushIfNotDone(ctx, state.Samples, sample)\n\n\t\tif exc != nil {\n\t\t\treturn false, exc\n\t\t}\n\t}\n\n\treturn succ, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/k6_test.go",
    "content": "package k6\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestFail(t *testing.T) {\n\tt.Parallel()\n\ttc := testCaseRuntime(t)\n\n\t_, err := tc.testRuntime.RunOnEventLoop(`k6.fail(\"blah\")`)\n\tassert.Contains(t, err.Error(), \"blah\")\n}\n\nfunc TestSleep(t *testing.T) {\n\tt.Parallel()\n\n\ttestdata := map[string]time.Duration{\n\t\t\"1\":   1 * time.Second,\n\t\t\"1.0\": 1 * time.Second,\n\t\t\"0.5\": 500 * time.Millisecond,\n\t}\n\tfor name, d := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttc := testCaseRuntime(t)\n\t\t\tstartTime := time.Now()\n\t\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.sleep(1)`)\n\t\t\tendTime := time.Now()\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.True(t, endTime.Sub(startTime) > d, \"did not sleep long enough\")\n\t\t})\n\t}\n\n\tt.Run(\"Cancel\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttc := testCaseRuntime(t)\n\n\t\tdch := make(chan time.Duration)\n\t\tgo func() {\n\t\t\tstartTime := time.Now()\n\t\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.sleep(10)`)\n\t\t\tendTime := time.Now()\n\t\t\tassert.NoError(t, err)\n\t\t\tdch <- endTime.Sub(startTime)\n\t\t}()\n\n\t\ttime.Sleep(1 * time.Second)\n\t\ttc.testRuntime.CancelContext()\n\t\td := <-dch\n\n\t\tassert.True(t, d > 500*time.Millisecond, \"did not sleep long enough\")\n\t\tassert.True(t, d < 2*time.Second, \"slept for too long!!\")\n\t})\n}\n\nfunc TestRandSeed(t *testing.T) {\n\tt.Parallel()\n\n\ttc := testCaseRuntime(t)\n\n\trand := 0.8487305991992138\n\t_, err := tc.testRuntime.RunOnEventLoop(fmt.Sprintf(`\n\t\tvar rnd = Math.random();\n\t\tif (rnd == %.16f) { throw new Error(\"wrong random: \" + rnd); }\n\t`, rand))\n\tassert.NoError(t, err)\n\n\t_, err = tc.testRuntime.RunOnEventLoop(fmt.Sprintf(`\n\t\tk6.randomSeed(12345)\n\t\tvar rnd = Math.random();\n\t\tif (rnd != %.16f) { throw new Error(\"wrong random: \" + rnd); }\n\t`, rand))\n\tassert.NoError(t, err)\n}\n\nfunc TestGroup(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\t\tstate := tc.testRuntime.VU.State()\n\t\trequire.NoError(t, tc.testRuntime.VU.Runtime().Set(\"fn\", func() {\n\t\t\tgroupTag, ok := state.Tags.GetCurrentValues().Tags.Get(\"group\")\n\t\t\trequire.True(t, ok)\n\t\t\tassert.Equal(t, \"::my group\", groupTag)\n\t\t}))\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.group(\"my group\", fn)`)\n\t\tassert.NoError(t, err)\n\t\tgroupTag, ok := state.Tags.GetCurrentValues().Tags.Get(\"group\")\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"\", groupTag)\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.group(\"::\", function() { throw new Error(\"nooo\") })`)\n\t\tassert.Contains(t, err.Error(), \"group and check names may not contain '::'\")\n\t})\n\n\tt.Run(\"async function\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.group(\"something\", async function() { })`)\n\t\tassert.ErrorContains(t, err, \"group() does not support async functions as arguments\")\n\t})\n\n\tt.Run(\"async lambda\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.group(\"something\", async () => { })`)\n\t\tassert.ErrorContains(t, err, \"group() does not support async functions as arguments\")\n\t})\n}\n\nfunc TestCheckObject(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"boolean\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(null, { \"check\": true })`)\n\t\tassert.NoError(t, err)\n\n\t\tbufSamples := metrics.GetBufferedSamples(tc.samples)\n\t\trequire.Len(t, bufSamples, 1)\n\t\tsample, ok := bufSamples[0].(metrics.Sample)\n\t\trequire.True(t, ok)\n\n\t\tassert.NotZero(t, sample.Time)\n\t\tassert.Equal(t, tc.testRuntime.VU.State().BuiltinMetrics.Checks, sample.Metric)\n\t\tassert.Equal(t, float64(1), sample.Value)\n\t\tassert.Equal(t, map[string]string{\n\t\t\t\"group\": \"\",\n\t\t\t\"check\": \"check\",\n\t\t}, sample.Tags.Map())\n\t})\n\n\tt.Run(\"Multiple\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(null, { \"a\": true, \"b\": false })`)\n\t\tassert.NoError(t, err)\n\n\t\tbufSamples := metrics.GetBufferedSamples(tc.samples)\n\t\tassert.Len(t, bufSamples, 2)\n\t\tvar foundA, foundB bool\n\t\tfor _, sampleC := range bufSamples {\n\t\t\tfor _, sample := range sampleC.GetSamples() {\n\t\t\t\tname, ok := sample.Tags.Get(\"check\")\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tswitch name {\n\t\t\t\tcase \"a\":\n\t\t\t\t\tassert.False(t, foundA, \"duplicate 'a'\")\n\t\t\t\t\tfoundA = true\n\t\t\t\tcase \"b\":\n\t\t\t\t\tassert.False(t, foundB, \"duplicate 'b'\")\n\t\t\t\t\tfoundB = true\n\t\t\t\tdefault:\n\t\t\t\t\tassert.Fail(t, name)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tassert.True(t, foundA, \"missing 'a'\")\n\t\tassert.True(t, foundB, \"missing 'b'\")\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(null, { \"::\": true })`)\n\t\tassert.Contains(t, err.Error(), \"group and check names may not contain '::'\")\n\t})\n\n\tt.Run(\"async function\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(\"something\", {\"async\": async function() { }})`)\n\t\tassert.ErrorContains(t, err, \"check() does not support async functions as arguments\")\n\t})\n\n\tt.Run(\"async lambda\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\t\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(\"something\", {\"async\": async () =>{ }})`)\n\t\tassert.ErrorContains(t, err, \"check() does not support async functions as arguments\")\n\t})\n}\n\nfunc TestCheckArray(t *testing.T) {\n\tt.Parallel()\n\ttc := testCaseRuntime(t)\n\n\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(null, [ true ])`)\n\tassert.NoError(t, err)\n\n\tbufSamples := metrics.GetBufferedSamples(tc.samples)\n\trequire.Len(t, bufSamples, 1)\n\tsample, ok := bufSamples[0].(metrics.Sample)\n\trequire.True(t, ok)\n\n\tassert.NotZero(t, sample.Time)\n\tassert.Equal(t, tc.testRuntime.VU.State().BuiltinMetrics.Checks, sample.Metric)\n\tassert.Equal(t, float64(1), sample.Value)\n\tassert.Equal(t, map[string]string{\n\t\t\"group\": \"\",\n\t\t\"check\": \"0\",\n\t}, sample.Tags.Map())\n}\n\nfunc TestCheckContextDone(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"true\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\n\t\ttc.testRuntime.CancelContext()\n\t\tv, err := tc.testRuntime.RunOnEventLoop(` k6.check(null, {\"name\": ()=>{ return true }})`)\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, metrics.GetBufferedSamples(tc.samples), 0)\n\t\tassert.True(t, v.ToBoolean())\n\t})\n\tt.Run(\"false\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttc := testCaseRuntime(t)\n\n\t\ttc.testRuntime.CancelContext()\n\t\tv, err := tc.testRuntime.RunOnEventLoop(`k6.check(null, {\"name\": ()=>{ return false }})`)\n\t\tassert.NoError(t, err)\n\t\tassert.Len(t, metrics.GetBufferedSamples(tc.samples), 0)\n\t\tassert.False(t, v.ToBoolean())\n\t})\n}\n\nfunc TestCheckLiteral(t *testing.T) {\n\tt.Parallel()\n\ttc := testCaseRuntime(t)\n\n\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(null, 12345)`)\n\tassert.NoError(t, err)\n\tassert.Len(t, metrics.GetBufferedSamples(tc.samples), 0)\n}\n\nfunc TestCheckNull(t *testing.T) {\n\tt.Parallel()\n\ttc := testCaseRuntime(t)\n\n\t_, err := tc.testRuntime.RunOnEventLoop(`k6.check(5)`)\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"no checks provided\")\n\tassert.Len(t, metrics.GetBufferedSamples(tc.samples), 0)\n}\n\nfunc TestCheckThrows(t *testing.T) {\n\tt.Parallel()\n\ttc := testCaseRuntime(t)\n\t_, err := tc.testRuntime.RunOnEventLoop(`\n\t\tk6.check(null, {\n\t\t\t\"a\": function() { throw new Error(\"error A\") },\n\t\t\t\"b\": function() { throw new Error(\"error B\") },\n\t\t})\n\t\t`)\n\tassert.EqualError(t, err, \"Error: error A at a (<eval>:3:28(3))\")\n\n\tbufSamples := metrics.GetBufferedSamples(tc.samples)\n\trequire.Len(t, bufSamples, 1)\n\tsample, ok := bufSamples[0].(metrics.Sample)\n\trequire.True(t, ok)\n\n\tassert.NotZero(t, sample.Time)\n\tassert.Equal(t, tc.testRuntime.VU.State().BuiltinMetrics.Checks, sample.Metric)\n\tassert.Equal(t, float64(0), sample.Value)\n\tassert.Equal(t, map[string]string{\n\t\t\"group\": \"\",\n\t\t\"check\": \"a\",\n\t}, sample.Tags.Map())\n}\n\nfunc TestCheckTypes(t *testing.T) {\n\tt.Parallel()\n\ttemplates := map[string]string{\n\t\t\"Literal\":      `k6.check(null,{\"check\": %s})`,\n\t\t\"Callable\":     `k6.check(null,{\"check\": function() { return %s; }})`,\n\t\t\"Callable/Arg\": `k6.check(%s,{\"check\": function(v) {return v; }})`,\n\t}\n\ttestdata := map[string]bool{\n\t\t`0`:         false,\n\t\t`1`:         true,\n\t\t`-1`:        true,\n\t\t`\"\"`:        false,\n\t\t`\"true\"`:    true,\n\t\t`\"false\"`:   true,\n\t\t`true`:      true,\n\t\t`false`:     false,\n\t\t`null`:      false,\n\t\t`undefined`: false,\n\t}\n\tfor name, tpl := range templates {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor value, succ := range testdata {\n\t\t\t\tt.Run(value, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\ttc := testCaseRuntime(t)\n\n\t\t\t\t\tv, err := tc.testRuntime.RunOnEventLoop(fmt.Sprintf(tpl, value))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, succ, v.Export())\n\n\t\t\t\t\tbufSamples := metrics.GetBufferedSamples(tc.samples)\n\t\t\t\t\trequire.Len(t, bufSamples, 1)\n\t\t\t\t\tsample, ok := bufSamples[0].(metrics.Sample)\n\t\t\t\t\trequire.True(t, ok)\n\n\t\t\t\t\tassert.NotZero(t, sample.Time)\n\t\t\t\t\tassert.Equal(t, tc.testRuntime.VU.State().BuiltinMetrics.Checks, sample.Metric)\n\t\t\t\t\tif succ {\n\t\t\t\t\t\tassert.Equal(t, float64(1), sample.Value)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tassert.Equal(t, float64(0), sample.Value)\n\t\t\t\t\t}\n\t\t\t\t\tassert.Equal(t, map[string]string{\n\t\t\t\t\t\t\"group\": \"\",\n\t\t\t\t\t\t\"check\": \"check\",\n\t\t\t\t\t}, sample.Tags.Map())\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCheckTags(t *testing.T) {\n\tt.Parallel()\n\ttc := testCaseRuntime(t)\n\n\tv, err := tc.testRuntime.RunOnEventLoop(`k6.check(null, {\"check\": true}, {a: 1, b: \"2\"})`)\n\trequire.NoError(t, err)\n\tassert.Equal(t, true, v.Export())\n\n\tbufSamples := metrics.GetBufferedSamples(tc.samples)\n\trequire.Len(t, bufSamples, 1)\n\tsample, ok := bufSamples[0].(metrics.Sample)\n\trequire.True(t, ok)\n\n\tassert.NotZero(t, sample.Time)\n\tassert.Equal(t, tc.testRuntime.VU.State().BuiltinMetrics.Checks, sample.Metric)\n\tassert.Equal(t, float64(1), sample.Value)\n\tassert.Equal(t, map[string]string{\n\t\t\"group\": \"\",\n\t\t\"check\": \"check\",\n\t\t\"a\":     \"1\",\n\t\t\"b\":     \"2\",\n\t}, sample.Tags.Map())\n}\n\ntype testCase struct {\n\tsamples     chan metrics.SampleContainer\n\ttestRuntime *modulestest.Runtime\n}\n\nfunc testCaseRuntime(t testing.TB) *testCase {\n\ttestRuntime := modulestest.NewRuntime(t)\n\tm, ok := New().NewModuleInstance(testRuntime.VU).(*K6)\n\trequire.True(t, ok)\n\trequire.NoError(t, testRuntime.VU.RuntimeField.Set(\"k6\", m.Exports().Named))\n\n\tregistry := metrics.NewRegistry()\n\tsamples := make(chan metrics.SampleContainer, 1000)\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tSamples:        samples,\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet().WithTagsFromMap(map[string]string{\"group\": lib.RootGroupPath})),\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t}\n\ttestRuntime.MoveToVUContext(state)\n\n\treturn &testCase{\n\t\tsamples:     samples,\n\t\ttestRuntime: testRuntime,\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/marshalling_test.go",
    "content": "package k6_test\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/js\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestSetupDataMarshalling(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tscript := []byte(tb.Replacer.Replace(`\n\t\timport http from \"k6/http\";\n\t\timport html from \"k6/html\";\n\t\timport ws from \"k6/ws\";\n\n\t\tfunction make_jar() {\n\t\t\tlet jar = http.cookieJar();\n\t\t\tjar.set(\"test\", \"something\")\n\t\t\treturn jar;\n\t\t}\n\n\t\texport function setup() {\n\t\t\tlet res = http.get(\"HTTPBIN_URL/html\");\n\t\t\tlet html_selection = html.parseHTML(res.body);\n\t\t\tlet ws_res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\t\tsocket.on(\"open\", function() {\n\t\t\t\t\tsocket.send(\"test\")\n\t\t\t\t})\n\t\t\t\tsocket.on(\"message\", function (data){\n\t\t\t\t\tif (!data==\"test\") {\n\t\t\t\t\t\tthrow new Error (\"echo'd data doesn't match our message!\");\n\t\t\t\t\t}\n\t\t\t\t\tsocket.close()\n\t\t\t\t});\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\thttp_response: res,\n\t\t\t\thtml_selection: html_selection,\n\t\t\t\thtml_element: html_selection.find('html'),\n\t\t\t\thtml_attribute: html_selection.find('html').children('body').get(0).attributes(),\n\t\t\t\tjar: make_jar(),\n\t\t\t\tws_res: ws_res,\n\t\t\t};\n\t\t}\n\n\t\tfunction get_non_function_properties(object) {\n\t\t\treturn Object.keys(object).filter(element =>\n\t\t\t\ttypeof(object[element]) !== \"function\");\n\t\t}\n\n\t\tfunction arrays_are_equal(first, second) {\n\t\t\tif (first.length != second.length) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn first.every(function(element, idx) {\n\t\t\t\treturn element === second[idx]\n\t\t\t});\n\t\t}\n\n\t\tfunction diff_object_properties(name, first, second) {\n\t\t\tlet first_properties = get_non_function_properties(first).sort();\n\t\t\tlet second_properties = get_non_function_properties(second).sort();\n\t\t\tif (!(arrays_are_equal(first_properties, second_properties))) {\n\t\t\t\tconsole.error(\"for \" + name + \":\\n\" +\n\t\t\t\t\t\"first_properties : \" + JSON.stringify(first_properties) + \"\\n\" +\n\t\t\t\t\t\"second_properties: \" + JSON.stringify(second_properties) + \"\\n\" +\n\t\t\t\t\t\"are not the same\");\n\t\t\t\tthrow new Error(\"not matching \" + name);\n\t\t\t}\n\t\t\tfirst_properties.\n\t\t\t\tfilter(element => typeof(first[element]) === \"object\").\n\t\t\t\t\tforEach(function(element) {\n\t\t\t\t\t\tdiff_object_properties(name+\".\"+element,\n\t\t\t\t\t\t\t\t\t\t\t   first[element],\n\t\t\t\t\t\t\t\t\t\t\t   second[element]);\n\t\t\t});\n\t\t}\n\n\t\texport default function (data) {\n\t\t\tdiff_object_properties(\"setupdata\", data, setup());\n\t\t}\n\t`))\n\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\tpiState := &lib.TestPreInitState{\n\t\tLogger:         testutils.NewLogger(t),\n\t\tBuiltinMetrics: builtinMetrics,\n\t\tRegistry:       registry,\n\t\tUsage:          usage.New(),\n\t}\n\tsourceData := &loader.SourceData{URL: &url.URL{Path: \"/script.js\"}, Data: script}\n\tmoduleResolver := js.NewModuleResolver(loader.Dir(sourceData.URL), piState, nil)\n\trunner, err := js.New(piState, sourceData, nil, moduleResolver)\n\n\trequire.NoError(t, err)\n\n\terr = runner.SetOptions(lib.Options{\n\t\tSetupTimeout: types.NullDurationFrom(5 * time.Second),\n\t\tHosts:        types.NullHosts{Trie: tb.Dialer.Hosts},\n\t})\n\trequire.NoError(t, err)\n\n\tsamples := make(chan<- metrics.SampleContainer, 100)\n\n\tctx := t.Context()\n\trequire.NoError(t, runner.Setup(ctx, samples))\n\tinitVU, err := runner.NewVU(ctx, 1, 1, samples)\n\trequire.NoError(t, err)\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\tassert.NoError(t, vu.RunOnce())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/metrics/metrics.go",
    "content": "// Package metrics implements k6/metrics and let script work with custom metrics.\npackage metrics\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// Metric is a wrapper around custom metrics\ntype Metric struct {\n\tmetric *metrics.Metric\n\tvu     modules.VU\n}\n\n// ErrMetricsAddInInitContext is error returned when adding to metric is done in the init context\nvar ErrMetricsAddInInitContext = common.NewInitContextError(\"Adding to metrics in the init context is not supported\")\n\nfunc (mi *ModuleInstance) newMetric(call sobek.ConstructorCall, t metrics.MetricType) (*sobek.Object, error) {\n\tinitEnv := mi.vu.InitEnv()\n\tif initEnv == nil {\n\t\treturn nil, errors.New(\"metrics must be declared in the init context\")\n\t}\n\trt := mi.vu.Runtime()\n\tc, _ := sobek.AssertFunction(rt.ToValue(func(name string, isTime ...bool) (*sobek.Object, error) {\n\t\tvalueType := metrics.Default\n\t\tif len(isTime) > 0 && isTime[0] {\n\t\t\tvalueType = metrics.Time\n\t\t}\n\t\tm, err := initEnv.Registry.NewMetric(name, t, valueType)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmetric := &Metric{metric: m, vu: mi.vu}\n\t\to := rt.NewObject()\n\t\terr = o.DefineDataProperty(\"name\", rt.ToValue(name), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif err = o.Set(\"add\", rt.ToValue(metric.add)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn o, nil\n\t}))\n\tv, err := c(call.This, call.Arguments...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn v.ToObject(rt), nil\n}\n\nconst warnMessageValueMaxSize = 100\n\nfunc limitValue(v string) string {\n\tvRunes := []rune(v)\n\tif len(vRunes) < warnMessageValueMaxSize {\n\t\treturn v\n\t}\n\tdifference := int64(len(vRunes) - warnMessageValueMaxSize)\n\tomitMsg := append(strconv.AppendInt([]byte(\"... omitting \"), difference, 10), \" characters ...\"...)\n\treturn strings.Join([]string{\n\t\tstring(vRunes[:warnMessageValueMaxSize/2]),\n\t\tstring(vRunes[len(vRunes)-warnMessageValueMaxSize/2:]),\n\t}, string(omitMsg))\n}\n\nfunc (m Metric) add(v sobek.Value, addTags sobek.Value) (bool, error) {\n\tstate := m.vu.State()\n\tif state == nil {\n\t\treturn false, ErrMetricsAddInInitContext\n\t}\n\n\t// return/throw exception if throw enabled, otherwise just log\n\traiseErr := func(err error) (bool, error) { //nolint:unparam // we want to just do `return raiseErr(...)`\n\t\tif state.Options.Throw.Bool {\n\t\t\treturn false, err\n\t\t}\n\t\tstate.Logger.Warn(err)\n\t\treturn false, nil\n\t}\n\traiseNan := func() (bool, error) {\n\t\treturn raiseErr(fmt.Errorf(\"'%s' is an invalid value for metric '%s', a number or a boolean value is expected\",\n\t\t\tlimitValue(v.String()), m.metric.Name))\n\t}\n\n\tif v == nil {\n\t\treturn raiseErr(fmt.Errorf(\"no value was provided for metric '%s', a number or a boolean value is expected\",\n\t\t\tm.metric.Name))\n\t}\n\tif sobek.IsNull(v) {\n\t\treturn raiseNan()\n\t}\n\n\tvfloat := v.ToFloat()\n\tif vfloat == 0 && v.ToBoolean() {\n\t\tvfloat = 1.0\n\t}\n\n\tif math.IsNaN(vfloat) {\n\t\treturn raiseNan()\n\t}\n\n\tctm := state.Tags.GetCurrentValues()\n\tif err := common.ApplyCustomUserTags(m.vu.Runtime(), &ctm, addTags); err != nil {\n\t\treturn false, fmt.Errorf(\"cannot add tags for the '%s' custom metric: %w\", m.metric.Name, err)\n\t}\n\n\tsample := metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: m.metric,\n\t\t\tTags:   ctm.Tags,\n\t\t},\n\t\tTime:     time.Now(),\n\t\tMetadata: ctm.Metadata,\n\t\tValue:    vfloat,\n\t}\n\tmetrics.PushIfNotDone(m.vu.Context(), state.Samples, sample)\n\treturn true, nil\n}\n\ntype (\n\t// RootModule is the root metrics module\n\tRootModule struct{}\n\t// ModuleInstance represents an instance of the metrics module\n\tModuleInstance struct {\n\t\tvu modules.VU\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// NewModuleInstance implements modules.Module interface\nfunc (*RootModule) NewModuleInstance(m modules.VU) modules.Instance {\n\treturn &ModuleInstance{vu: m}\n}\n\n// New returns a new RootModule.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// Exports returns the exports of the metrics module\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"Counter\": mi.XCounter,\n\t\t\t\"Gauge\":   mi.XGauge,\n\t\t\t\"Trend\":   mi.XTrend,\n\t\t\t\"Rate\":    mi.XRate,\n\t\t},\n\t}\n}\n\n// XCounter is a counter constructor\nfunc (mi *ModuleInstance) XCounter(call sobek.ConstructorCall, rt *sobek.Runtime) *sobek.Object {\n\tv, err := mi.newMetric(call, metrics.Counter)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\treturn v\n}\n\n// XGauge is a gauge constructor\nfunc (mi *ModuleInstance) XGauge(call sobek.ConstructorCall, rt *sobek.Runtime) *sobek.Object {\n\tv, err := mi.newMetric(call, metrics.Gauge)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\treturn v\n}\n\n// XTrend is a trend constructor\nfunc (mi *ModuleInstance) XTrend(call sobek.ConstructorCall, rt *sobek.Runtime) *sobek.Object {\n\tv, err := mi.newMetric(call, metrics.Trend)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\treturn v\n}\n\n// XRate is a rate constructor\nfunc (mi *ModuleInstance) XRate(call sobek.ConstructorCall, rt *sobek.Runtime) *sobek.Object {\n\tv, err := mi.newMetric(call, metrics.Rate)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\treturn v\n}\n"
  },
  {
    "path": "internal/js/modules/k6/metrics/metrics_test.go",
    "content": "package metrics\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype addTestValue struct {\n\tJS     string\n\tFloat  float64\n\terrStr string\n\tnoTags bool\n}\n\ntype addTest struct {\n\tval          addTestValue\n\trt           *sobek.Runtime\n\thook         *testutils.SimpleLogrusHook\n\tsamples      chan metrics.SampleContainer\n\tisThrow      bool\n\tmtyp         metrics.MetricType\n\tvalueType    metrics.ValueType\n\tjs           string\n\texpectedTags map[string]string\n}\n\nfunc (a addTest) run(t *testing.T) {\n\t_, err := a.rt.RunString(a.js)\n\tif len(a.val.errStr) != 0 && a.isThrow {\n\t\tif assert.Error(t, err) {\n\t\t\treturn\n\t\t}\n\t} else {\n\t\tassert.NoError(t, err)\n\t\tif len(a.val.errStr) != 0 && !a.isThrow {\n\t\t\tlines := a.hook.Drain()\n\t\t\trequire.Len(t, lines, 1)\n\t\t\tassert.Contains(t, lines[0].Message, a.val.errStr)\n\t\t\treturn\n\t\t}\n\t}\n\tbufSamples := metrics.GetBufferedSamples(a.samples)\n\tif assert.Len(t, bufSamples, 1) {\n\t\tsample, ok := bufSamples[0].(metrics.Sample)\n\t\trequire.True(t, ok)\n\n\t\tassert.NotZero(t, sample.Time)\n\t\tassert.Equal(t, a.val.Float, sample.Value)\n\t\tassert.Equal(t, a.expectedTags, sample.Tags.Map())\n\t\tassert.Equal(t, \"my_metric\", sample.Metric.Name)\n\t\tassert.Equal(t, a.mtyp, sample.Metric.Type)\n\t\tassert.Equal(t, a.valueType, sample.Metric.Contains)\n\t}\n}\n\nfunc TestMetrics(t *testing.T) {\n\tt.Parallel()\n\ttypes := map[string]metrics.MetricType{\n\t\t\"Counter\": metrics.Counter,\n\t\t\"Gauge\":   metrics.Gauge,\n\t\t\"Trend\":   metrics.Trend,\n\t\t\"Rate\":    metrics.Rate,\n\t}\n\tvalues := map[string]addTestValue{\n\t\t\"Float\":                 {JS: `2.5`, Float: 2.5},\n\t\t\"Int\":                   {JS: `5`, Float: 5.0},\n\t\t\"True\":                  {JS: `true`, Float: 1.0},\n\t\t\"False\":                 {JS: `false`, Float: 0.0},\n\t\t\"null\":                  {JS: `null`, errStr: \"is an invalid value for metric\"},\n\t\t\"undefined\":             {JS: `undefined`, errStr: \"is an invalid value for metric\"},\n\t\t\"NaN\":                   {JS: `NaN`, errStr: \"is an invalid value for metric\"},\n\t\t\"string\":                {JS: `\"string\"`, errStr: \"is an invalid value for metric\"},\n\t\t\"string 5\":              {JS: `\"5.3\"`, Float: 5.3},\n\t\t\"some object\":           {JS: `{something: 3}`, errStr: \"is an invalid value for metric\"},\n\t\t\"another metric object\": {JS: `m`, errStr: \"is an invalid value for metric\"},\n\t\t\"no argument\":           {JS: ``, errStr: \"no value was provided\", noTags: true},\n\t}\n\tfor fn, mtyp := range types {\n\t\tt.Run(fn, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor isTime, valueType := range map[bool]metrics.ValueType{false: metrics.Default, true: metrics.Time} {\n\t\t\t\tt.Run(fmt.Sprintf(\"isTime=%v\", isTime), func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\ttest := addTest{\n\t\t\t\t\t\tmtyp:      mtyp,\n\t\t\t\t\t\tvalueType: valueType,\n\t\t\t\t\t}\n\t\t\t\t\ttest.rt = sobek.New()\n\t\t\t\t\ttest.rt.SetFieldNameMapper(common.FieldNameMapper{})\n\t\t\t\t\tregistry := metrics.NewRegistry()\n\t\t\t\t\tmii := &modulestest.VU{\n\t\t\t\t\t\tRuntimeField: test.rt,\n\t\t\t\t\t\tInitEnvField: &common.InitEnvironment{\n\t\t\t\t\t\t\tTestPreInitState: &lib.TestPreInitState{Registry: registry},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tCtxField: context.Background(),\n\t\t\t\t\t}\n\t\t\t\t\tm, ok := New().NewModuleInstance(mii).(*ModuleInstance)\n\t\t\t\t\trequire.True(t, ok)\n\t\t\t\t\trequire.NoError(t, test.rt.Set(\"metrics\", m.Exports().Named))\n\t\t\t\t\ttest.samples = make(chan metrics.SampleContainer, 1000)\n\t\t\t\t\tstate := &lib.State{\n\t\t\t\t\t\tOptions: lib.Options{},\n\t\t\t\t\t\tSamples: test.samples,\n\t\t\t\t\t\tTags: lib.NewVUStateTags(registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\t\"key\": \"value\",\n\t\t\t\t\t\t})),\n\t\t\t\t\t}\n\n\t\t\t\t\tisTimeString := \"\"\n\t\t\t\t\tif isTime {\n\t\t\t\t\t\tisTimeString = `, true`\n\t\t\t\t\t}\n\t\t\t\t\t_, err := test.rt.RunString(fmt.Sprintf(`var m = new metrics.%s(\"my_metric\"%s)`, fn, isTimeString))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tt.Run(\"ExitInit\", func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\t\tmii.StateField = state\n\t\t\t\t\t\tmii.InitEnvField = nil\n\t\t\t\t\t\t_, err := test.rt.RunString(fmt.Sprintf(`new metrics.%s(\"my_metric\")`, fn))\n\t\t\t\t\t\tassert.Contains(t, err.Error(), \"metrics must be declared in the init context\")\n\t\t\t\t\t})\n\t\t\t\t\tmii.StateField = state\n\t\t\t\t\tlogger := logrus.New()\n\t\t\t\t\tlogger.Out = io.Discard\n\t\t\t\t\ttest.hook = testutils.NewLogHook()\n\t\t\t\t\tlogger.AddHook(test.hook)\n\t\t\t\t\tstate.Logger = logger\n\n\t\t\t\t\tfor name, val := range values {\n\t\t\t\t\t\ttest.val = val\n\t\t\t\t\t\tfor _, isThrow := range []bool{false, true} {\n\t\t\t\t\t\t\tstate.Options.Throw.Bool = isThrow\n\t\t\t\t\t\t\ttest.isThrow = isThrow\n\t\t\t\t\t\t\tt.Run(fmt.Sprintf(\"%s/isThrow=%v/Simple\", name, isThrow), func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\t\t\t\ttest.js = fmt.Sprintf(`m.add(%v)`, val.JS)\n\t\t\t\t\t\t\t\ttest.expectedTags = map[string]string{\"key\": \"value\"}\n\t\t\t\t\t\t\t\ttest.run(t)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tif !val.noTags {\n\t\t\t\t\t\t\t\tt.Run(fmt.Sprintf(\"%s/isThrow=%v/Tags\", name, isThrow), func(t *testing.T) { //nolint:paralleltest\n\t\t\t\t\t\t\t\t\ttest.js = fmt.Sprintf(`m.add(%v, {a:1})`, val.JS)\n\t\t\t\t\t\t\t\t\ttest.expectedTags = map[string]string{\"key\": \"value\", \"a\": \"1\"}\n\t\t\t\t\t\t\t\t\ttest.run(t)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMetricGetName(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\tmii := &modulestest.VU{\n\t\tRuntimeField: rt,\n\t\tInitEnvField: &common.InitEnvironment{TestPreInitState: &lib.TestPreInitState{Registry: metrics.NewRegistry()}},\n\t\tCtxField:     context.Background(),\n\t}\n\tm, ok := New().NewModuleInstance(mii).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"metrics\", m.Exports().Named))\n\tv, err := rt.RunString(`\n\t\tvar m = new metrics.Counter(\"my_metric\")\n\t\tm.name\n\t`)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"my_metric\", v.String())\n\n\t_, err = rt.RunString(`\n\t\t\"use strict\";\n\t\tm.name = \"something\"\n\t`)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"TypeError: Cannot assign to read only property 'name'\")\n}\n\nfunc TestMetricDuplicates(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\tmii := &modulestest.VU{\n\t\tRuntimeField: rt,\n\t\tInitEnvField: &common.InitEnvironment{TestPreInitState: &lib.TestPreInitState{Registry: metrics.NewRegistry()}},\n\t\tCtxField:     context.Background(),\n\t}\n\tm, ok := New().NewModuleInstance(mii).(*ModuleInstance)\n\trequire.True(t, ok)\n\trequire.NoError(t, rt.Set(\"metrics\", m.Exports().Named))\n\t_, err := rt.RunString(`\n\t\tvar m = new metrics.Counter(\"my_metric\")\n\t`)\n\trequire.NoError(t, err)\n\n\t_, err = rt.RunString(`\n\t\tvar m2 = new metrics.Counter(\"my_metric\")\n\t`)\n\trequire.NoError(t, err)\n\n\t_, err = rt.RunString(`\n\t\tvar m3 = new metrics.Gauge(\"my_metric\")\n\t`)\n\trequire.Error(t, err)\n\n\t_, err = rt.RunString(`\n\t\tvar m4 = new metrics.Counter(\"my_metric\", true)\n\t`)\n\trequire.Error(t, err)\n\n\tv, err := rt.RunString(`\n\t\tm.name == m2.name && m.name == \"my_metric\" && m3 === undefined && m4 === undefined\n\t`)\n\trequire.NoError(t, err)\n\n\trequire.True(t, v.ToBoolean())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/secrets/secrets.go",
    "content": "// Package secrets implements `k6/secrets` giving access to secrets from secret sources to js code.\npackage secrets\n\nimport (\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/js/promises\"\n\t\"go.k6.io/k6/secretsource\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// Secrets represents an instance of the k6 module.\n\tSecrets struct {\n\t\tvu             modules.VU\n\t\tsecretsManager *secretsource.Manager\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &Secrets{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &Secrets{vu: vu, secretsManager: vu.InitEnv().SecretsManager}\n}\n\n// Exports returns the exports of the k6 module.\nfunc (mi *Secrets) Exports() modules.Exports {\n\ts, err := mi.secrets()\n\tif err != nil {\n\t\tcommon.Throw(mi.vu.Runtime(), err)\n\t}\n\treturn modules.Exports{\n\t\tDefault: s,\n\t\tNamed:   make(map[string]any), // this is intentionally not nil so it doesn't export anything as named exports\n\t}\n}\n\nfunc (mi *Secrets) secrets() (*sobek.Object, error) {\n\tobj, err := secretSourceObjectForSourceName(mi.vu, mi.secretsManager, secretsource.DefaultSourceName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = obj.Set(\"source\", func(sourceName string) (*sobek.Object, error) {\n\t\treturn secretSourceObjectForSourceName(mi.vu, mi.secretsManager, sourceName)\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn obj, nil\n}\n\nfunc secretSourceObjectForSourceName(\n\tvu modules.VU, manager *secretsource.Manager, sourceName string,\n) (*sobek.Object, error) {\n\tobj := vu.Runtime().NewObject()\n\terr := obj.Set(\"get\", func(key string) *sobek.Promise {\n\t\tp, resolve, reject := promises.New(vu)\n\t\tgo func() {\n\t\t\tres, err := manager.Get(sourceName, key)\n\t\t\tif err != nil {\n\t\t\t\treject(err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresolve(res)\n\t\t}()\n\t\treturn p\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn obj, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/secrets/secrets_test.go",
    "content": "package secrets\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/secretsource/mock\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/secretsource\"\n)\n\nfunc testRuntimeWithSecrets(t testing.TB, secretSources map[string]secretsource.Source) *modulestest.Runtime {\n\ttestRuntime := modulestest.NewRuntime(t)\n\tvar err error\n\ttestRuntime.VU.InitEnvField.SecretsManager, _, err = secretsource.NewManager(secretSources)\n\trequire.NoError(t, err)\n\n\tm, ok := New().NewModuleInstance(testRuntime.VU).(*Secrets)\n\trequire.True(t, ok)\n\trequire.NoError(t, testRuntime.VU.RuntimeField.Set(\"secrets\", m.Exports().Default))\n\n\treturn testRuntime\n}\n\nfunc TestSecrets(t *testing.T) {\n\tt.Parallel()\n\n\ttype secretsTest struct {\n\t\tsecretsources map[string]secretsource.Source\n\t\tscript        string\n\t\texpectedValue any\n\t\texpectedError string\n\t}\n\n\tcases := map[string]secretsTest{\n\t\t\"simple\": {\n\t\t\tsecretsources: map[string]secretsource.Source{\n\t\t\t\t\"default\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret\": \"value\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\tscript:        \"await secrets.get('secret')\",\n\t\t\texpectedValue: \"value\",\n\t\t},\n\t\t\"error\": {\n\t\t\tsecretsources: map[string]secretsource.Source{\n\t\t\t\t\"default\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret\": \"value\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\tscript:        \"await secrets.get('not_secret')\",\n\t\t\texpectedError: \"no value\",\n\t\t},\n\t\t\"multiple\": {\n\t\t\tsecretsources: map[string]secretsource.Source{\n\t\t\t\t\"default\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret\": \"value\",\n\t\t\t\t}),\n\t\t\t\t\"second\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret2\": \"value2\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\tscript:        \"await secrets.get('secret')\",\n\t\t\texpectedValue: \"value\",\n\t\t},\n\t\t\"multiple get default\": {\n\t\t\tsecretsources: map[string]secretsource.Source{\n\t\t\t\t\"default\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret\": \"value\",\n\t\t\t\t}),\n\t\t\t\t\"second\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret2\": \"value2\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\tscript:        \"await secrets.source('default').get('secret')\",\n\t\t\texpectedValue: \"value\",\n\t\t},\n\t\t\"multiple get not default\": {\n\t\t\tsecretsources: map[string]secretsource.Source{\n\t\t\t\t\"default\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret\": \"value\",\n\t\t\t\t}),\n\t\t\t\t\"second\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret2\": \"value2\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\tscript:        \"await secrets.source('second').get('secret2')\",\n\t\t\texpectedValue: \"value2\",\n\t\t},\n\t\t\"multiple get wrong\": {\n\t\t\tsecretsources: map[string]secretsource.Source{\n\t\t\t\t\"default\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret\": \"value\",\n\t\t\t\t}),\n\t\t\t\t\"second\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret2\": \"value2\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\tscript:        \"await secrets.source('third').get('secret2')\",\n\t\t\texpectedError: \"no secret source with name \\\"third\\\" is configured\",\n\t\t},\n\t\t\"get secret without source\": {\n\t\t\tsecretsources: map[string]secretsource.Source{},\n\t\t\tscript:        \"await secrets.get('secret')\",\n\t\t\texpectedError: \"no secret sources are configured\",\n\t\t},\n\t\t\"get none existing source\": {\n\t\t\tsecretsources: map[string]secretsource.Source{\n\t\t\t\t\"default\": mock.NewMockSecretSource(map[string]string{\n\t\t\t\t\t\"secret\": \"value\",\n\t\t\t\t}),\n\t\t\t},\n\t\t\tscript:        \"(await secrets.source('second')) != undefined\",\n\t\t\texpectedValue: true,\n\t\t},\n\t}\n\n\tfor name, testCase := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttestruntime := testRuntimeWithSecrets(t, testCase.secretsources)\n\n\t\t\t_, err := testruntime.RunOnEventLoop(\"(async ()=>{globalThis.result = \" + testCase.script + \"})()\")\n\t\t\tif testCase.expectedError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, testCase.expectedError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tv := testruntime.VU.Runtime().GlobalObject().Get(\"result\")\n\t\t\tassert.Equal(t, testCase.expectedValue, v.Export())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/timers/timers.go",
    "content": "// Package timers exposes setInterval setTimeout and co. as a module\npackage timers\n\nimport (\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// RootModule is the global module instance that will create module\n// instances for each VU.\ntype RootModule struct{}\n\n// Timers represents an instance of the timers module.\ntype Timers struct {\n\tvu modules.VU\n}\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &Timers{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &Timers{\n\t\tvu: vu,\n\t}\n}\n\n// Exports returns the exports of the k6 module.\nfunc (e *Timers) Exports() modules.Exports {\n\tglobalThis := e.vu.Runtime().GlobalObject()\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"setTimeout\":    globalThis.Get(\"setTimeout\"),\n\t\t\t\"clearTimeout\":  globalThis.Get(\"clearTimeout\"),\n\t\t\t\"setInterval\":   globalThis.Get(\"setInterval\"),\n\t\t\t\"clearInterval\": globalThis.Get(\"clearInterval\"),\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/aes.go",
    "content": "package webcrypto\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// AESKeyGenParams represents the object that should be passed as\n// the algorithm parameter into `SubtleCrypto.generateKey`, when generating\n// an AES key: that is, when the algorithm is identified as any\n// of AES-CBC, AES-CTR, AES-GCM, or AES-KW.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-keygen-params\ntype AESKeyGenParams struct {\n\tAlgorithm\n\n\t// The length, in bits, of the key.\n\tLength bitLength `js:\"length\"`\n}\n\nvar _ hasAlg = (*AESKeyGenParams)(nil)\n\nfunc (akgp AESKeyGenParams) alg() string {\n\treturn akgp.Name\n}\n\n// newAESKeyGenParams creates a new AESKeyGenParams object, from the\n// normalized algorithm, and the algorithm parameters.\n//\n// It handles the logic involved in handling the `length` attribute,\n// which is not part of the normalized algorithm.\nfunc newAESKeyGenParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*AESKeyGenParams, error) {\n\t// We extract the length attribute from the params object, as it's not\n\t// part of the normalized algorithm, and as accessing the runtime from the\n\t// callback below could lead to a race condition.\n\talgorithmLengthValue, err := traverseObject(rt, params, \"length\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get length from algorithm parameter\")\n\t}\n\n\talgorithmLength := algorithmLengthValue.ToInteger()\n\n\treturn &AESKeyGenParams{\n\t\tAlgorithm: normalized,\n\t\tLength:    bitLength(algorithmLength),\n\t}, nil\n}\n\n// GenerateKey generates a new AES key, according to the algorithm\n// described in the specification.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-keygen-params\nfunc (akgp *AESKeyGenParams) GenerateKey(\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (CryptoKeyGenerationResult, error) {\n\tfor _, usage := range keyUsages {\n\t\tswitch usage {\n\t\tcase WrapKeyCryptoKeyUsage, UnwrapKeyCryptoKeyUsage:\n\t\t\tcontinue\n\t\tcase EncryptCryptoKeyUsage, DecryptCryptoKeyUsage:\n\t\t\t// At the time of writing, the go standard library [doesn't\n\t\t\t// support AES-KW](https://github.com/golang/go/issues/27599), we\n\t\t\t// might want to revisit this in the future.\n\t\t\tif akgp.Name != AESKw {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage\")\n\t\tdefault:\n\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage\")\n\t\t}\n\t}\n\n\tif akgp.Length != 128 && akgp.Length != 192 && akgp.Length != 256 {\n\t\treturn nil, NewError(OperationError, \"invalid key length\")\n\t}\n\n\trandomKey := make([]byte, akgp.Length.asByteLength())\n\tif _, err := rand.Read(randomKey); err != nil {\n\t\t// 4.\n\t\treturn nil, NewError(OperationError, \"could not generate random key\")\n\t}\n\n\t// 5. 6. 7. 8. 9.\n\tkey := CryptoKey{}\n\tkey.Type = SecretCryptoKeyType\n\tkey.Algorithm = &AESKeyAlgorithm{\n\t\tAlgorithm: akgp.Algorithm,\n\t\tLength:    int64(akgp.Length),\n\t}\n\n\t// 10.\n\tkey.Extractable = extractable\n\n\t// 11.\n\tkey.Usages = keyUsages\n\n\t// Set key handle to our random key.\n\tkey.handle = randomKey\n\n\t// 12.\n\treturn &key, nil\n}\n\n// Ensure that AESKeyGenParams implements the KeyGenerator interface.\nvar _ KeyGenerator = &AESKeyGenParams{}\n\n// AESKeyAlgorithm is the algorithm for AES keys as defined in the [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#dfn-AESKeyAlgorithm\ntype AESKeyAlgorithm struct {\n\tAlgorithm\n\n\tLength int64 `js:\"length\"`\n}\n\nvar _ hasAlg = (*AESKeyAlgorithm)(nil)\n\nfunc (aka AESKeyAlgorithm) alg() string {\n\treturn aka.Name\n}\n\n// exportAESKey exports an AES key to its raw representation.\nfunc exportAESKey(key *CryptoKey, format KeyFormat) (any, error) {\n\tif !key.Extractable {\n\t\treturn nil, NewError(InvalidAccessError, \"the key is not extractable\")\n\t}\n\n\t// 1.\n\tif key.handle == nil {\n\t\treturn nil, NewError(OperationError, \"the key is not valid, no data\")\n\t}\n\n\tswitch format {\n\tcase RawKeyFormat:\n\t\thandle, ok := key.handle.([]byte)\n\t\tif !ok {\n\t\t\treturn nil, NewError(ImplementationError, \"exporting key data's bytes failed\")\n\t\t}\n\n\t\treturn handle, nil\n\tcase JwkKeyFormat:\n\t\tm, err := exportSymmetricJWK(key)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(ImplementationError, err.Error())\n\t\t}\n\n\t\treturn m, nil\n\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, unsupportedKeyFormatErrorMsg+\" \"+format)\n\t}\n}\n\n// AESGetLengthParams is the parameters required for algorithms to run the GetLength Operation\ntype AESGetLengthParams struct {\n\tAlgorithm\n\tLength int\n}\n\nfunc newAESGetLengthParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*AESGetLengthParams, error) {\n\tlength, err := traverseObject(rt, params, \"length\")\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"aes length parameter not specified\")\n\t}\n\n\treturn &AESGetLengthParams{\n\t\tAlgorithm: normalized,\n\t\tLength:    int(length.ToInteger()),\n\t}, nil\n}\n\n// GetKeyLength represents the AES function that get the key length from the AES params\nfunc (kgl AESGetLengthParams) GetKeyLength() int {\n\treturn kgl.Length\n}\n\n// AESImportParams is an internal placeholder struct for AES import parameters.\n// Although not described by the specification, we define it to be able to implement\n// our internal KeyImporter interface.\ntype AESImportParams struct {\n\tAlgorithm\n}\n\nfunc newAESImportParams(normalized Algorithm) *AESImportParams {\n\treturn &AESImportParams{\n\t\tAlgorithm: normalized,\n\t}\n}\n\n// ImportKey imports an AES key from its raw representation.\n// It implements the KeyImporter interface.\nfunc (aip *AESImportParams) ImportKey(\n\tformat KeyFormat,\n\tkeyData []byte,\n\t_ bool,\n\tkeyUsages []CryptoKeyUsage,\n) (*CryptoKey, error) {\n\tfor _, usage := range keyUsages {\n\t\tswitch usage {\n\t\tcase EncryptCryptoKeyUsage, DecryptCryptoKeyUsage, WrapKeyCryptoKeyUsage, UnwrapKeyCryptoKeyUsage:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage: \"+usage)\n\t\t}\n\t}\n\n\t// only raw and jwk formats are supported for HMAC\n\tif format != RawKeyFormat && format != JwkKeyFormat {\n\t\treturn nil, NewError(NotSupportedError, unsupportedKeyFormatErrorMsg+\" \"+format)\n\t}\n\n\t// if the key is in JWK format, we need to extract the symmetric key from it\n\tif format == JwkKeyFormat {\n\t\tvar err error\n\t\tkeyData, err = extractSymmetricJWK(keyData)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(DataError, err.Error())\n\t\t}\n\t}\n\n\t// check the key length\n\tif !isAESBitsLengthValid(len(keyData)) {\n\t\treturn nil, NewError(DataError, fmt.Sprintf(\"invalid key length %v bytes\", len(keyData)))\n\t}\n\n\tkey := &CryptoKey{\n\t\tAlgorithm: AESKeyAlgorithm{\n\t\t\tAlgorithm: aip.Algorithm,\n\t\t\tLength:    int64(byteLength(len(keyData)).asBitLength()),\n\t\t},\n\t\tType:   SecretCryptoKeyType,\n\t\thandle: keyData,\n\t}\n\n\treturn key, nil\n}\n\n// isAESBitsLengthValid returns true if the given length is a valid AES key length.\n// As per the [specification].\nfunc isAESBitsLengthValid(length int) bool {\n\treturn length == 16 || length == 24 || length == 32\n}\n\n// Ensure that AESImportParams implements the KeyImporter interface.\nvar _ KeyImporter = &AESImportParams{}\n\n// AESCBCParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.Encrypt`, `SubtleCrypto.Decrypt`, `SubtleCrypto.WrapKey`, or\n// `SubtleCrypto.UnwrapKey`, when using the AES-CBC algorithm.\n//\n// As defined in the [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-cbc-params\ntype AESCBCParams struct {\n\tAlgorithm\n\n\t// Name should be set to AES-CBC.\n\tName string `js:\"name\"`\n\n\t// Iv holds (an ArrayBuffer, a TypedArray, or a DataView) the initialization vector.\n\t// Must be 16 bytes, unpredictable, and preferably cryptographically random.\n\t// However, it need not be secret (for example, it may be transmitted unencrypted along with the ciphertext).\n\tIv []byte `js:\"iv\"`\n}\n\n// Encrypt encrypts the given plaintext using the AES-CBC algorithm, and returns the ciphertext.\n// Implements the WebCryptoAPI `encrypt` method's [specification] for the AES-CBC algorithm.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-cbc\nfunc (acp *AESCBCParams) Encrypt(plaintext []byte, key CryptoKey) ([]byte, error) {\n\t// 1.\n\t// Note that aes.BlockSize stands for the `k` variable as per the specification.\n\tif len(acp.Iv) != aes.BlockSize {\n\t\treturn nil, NewError(OperationError, \"iv length is not 16 bytes\")\n\t}\n\n\t// 2.\n\tpaddedPlainText, err := pKCS7Pad(plaintext, aes.BlockSize)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not pad plaintext\")\n\t}\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(ImplementationError, \"could not get key handle\")\n\t}\n\n\t// 3.\n\tblock, err := aes.NewCipher(keyHandle)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not create cipher\")\n\t}\n\n\tciphertext := make([]byte, len(paddedPlainText))\n\tcbc := cipher.NewCBCEncrypter(block, acp.Iv)\n\tcbc.CryptBlocks(ciphertext, paddedPlainText)\n\n\treturn ciphertext, nil\n}\n\n// Decrypt decrypts the given ciphertext using the AES-CBC algorithm, and returns the plaintext.\n// Implements the WebCryptoAPI's `decrypt` method's [specification] for the AES-CBC algorithm.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-cbc\nfunc (acp *AESCBCParams) Decrypt(ciphertext []byte, key CryptoKey) ([]byte, error) {\n\t// 1.\n\tif len(acp.Iv) != aes.BlockSize {\n\t\treturn nil, NewError(OperationError, \"iv length is invalid, should be 16 bytes\")\n\t}\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(OperationError, \"invalid key handle\")\n\t}\n\n\t// 2.\n\tblock, err := aes.NewCipher(keyHandle)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not create AES cipher\")\n\t}\n\n\tpaddedPlainText := make([]byte, len(ciphertext))\n\tcbc := cipher.NewCBCDecrypter(block, acp.Iv)\n\tcbc.CryptBlocks(paddedPlainText, ciphertext)\n\n\t// 3.\n\tp := paddedPlainText[len(paddedPlainText)-1]\n\tif p == 0 || p > aes.BlockSize {\n\t\treturn nil, NewError(OperationError, \"invalid padding\")\n\t}\n\n\t// 4.\n\tif !bytes.HasSuffix(paddedPlainText, bytes.Repeat([]byte{p}, int(p))) {\n\t\treturn nil, NewError(OperationError, \"invalid padding\")\n\t}\n\n\t// 5.\n\tplaintext := paddedPlainText[:len(paddedPlainText)-int(p)]\n\n\treturn plaintext, nil\n}\n\n// Ensure that AESCBCParams implements the EncryptDecrypter interface.\nvar _ EncryptDecrypter = &AESCBCParams{}\n\n// AESCTRParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.Encrypt`, `SubtleCrypto.Decrypt`, `SubtleCrypto.WrapKey`, or\n// `SubtleCrypto.UnwrapKey`, when using the AES-CTR algorithm.\n//\n// As defined in the [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-ctr-params\ntype AESCTRParams struct {\n\tAlgorithm\n\n\t// Counter holds (an ArrayBuffer, a TypedArray, or a DataView) the initial value of the counter block.\n\t// This must be 16 bytes long (the AES block size). The rightmost length bits of this block are used\n\t// for the counter, and the rest is used for the nonce.\n\t//\n\t// For example, if length is set to 64, then the first half of counter is\n\t// the nonce and the second half is used for the counter.\n\tCounter []byte `js:\"counter\"`\n\n\t// Length holds (a Number) the number of bits in the counter block that are used for the actual counter.\n\t// The counter must be big enough that it doesn't wrap: if the message is n blocks and the counter is m bits long, then\n\t// the following must be true: n <= 2^m.\n\t//\n\t// The NIST SP800-38A standard, which defines CTR, suggests that the counter should occupy half of the counter\n\t// block (see Appendix B.2), so for AES it would be 64.\n\tLength int `js:\"length\"`\n}\n\n// Encrypt encrypts the given plaintext using the AES-CTR algorithm, and returns the ciphertext.\n// Implements the WebCryptoAPI's `encrypt` method's [specification] for the AES-CTR algorithm.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-ctr\nfunc (acp *AESCTRParams) Encrypt(plaintext []byte, key CryptoKey) ([]byte, error) {\n\t// 1.\n\t// Note that aes.BlockSize stands for the `k` variable as per the specification.\n\tif len(acp.Counter) != aes.BlockSize {\n\t\treturn nil, NewError(OperationError, \"counter length is not 16 bytes\")\n\t}\n\n\t// 2.\n\tif acp.Length <= 0 || acp.Length > 128 {\n\t\treturn nil, NewError(OperationError, \"invalid counter length, out of the 0 < x < 128 bounds\")\n\t}\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(ImplementationError, \"could not get key handle\")\n\t}\n\n\t// 3.\n\tblock, err := aes.NewCipher(keyHandle)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not create cipher\")\n\t}\n\n\tciphertext := make([]byte, len(plaintext))\n\tctr := cipher.NewCTR(block, acp.Counter)\n\tctr.XORKeyStream(ciphertext, plaintext)\n\n\treturn ciphertext, nil\n}\n\n// Decrypt decrypts the given ciphertext using the AES-CTR algorithm, and returns the plaintext.\n// Implements the WebCryptoAPI's `decrypt` method's [specification] for the AES-CTR algorithm.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-ctr\nfunc (acp *AESCTRParams) Decrypt(ciphertext []byte, key CryptoKey) ([]byte, error) {\n\t// 1.\n\tif len(acp.Counter) != aes.BlockSize {\n\t\treturn nil, NewError(OperationError, \"counter length is invalid, should be 16 bytes\")\n\t}\n\n\t// 2.\n\tif acp.Length <= 0 || acp.Length > 128 {\n\t\treturn nil, NewError(OperationError, \"invalid length, should be within 1 <= length <= 128 bounds\")\n\t}\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(OperationError, \"invalid key handle\")\n\t}\n\n\t// 3.\n\tblock, err := aes.NewCipher(keyHandle)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not create AES cipher\")\n\t}\n\n\tplaintext := make([]byte, len(ciphertext))\n\tstream := cipher.NewCTR(block, acp.Counter)\n\tstream.XORKeyStream(plaintext, ciphertext)\n\n\treturn plaintext, nil\n}\n\n// Ensure that AESCTRParams implements the EncryptDecrypter interface.\nvar _ EncryptDecrypter = &AESCTRParams{}\n\n// AESGCMParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.Encrypt`, `SubtleCrypto.Decrypt`, `SubtleCrypto.WrapKey`, or\n// `SubtleCrypto.UnwrapKey`, when using the AES-GCM algorithm.\n// As defined in the [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm-params\ntype AESGCMParams struct {\n\tAlgorithm\n\n\t// Iv holds (an ArrayBuffer, a TypedArray, or a DataView) with the initialization vector.\n\t// This must be unique for every encryption operation carried out with a given key.\n\t//\n\t// Put another way: never reuse an IV with the same key.\n\t// The AES-GCM specification recommends that the IV should be 96 bits long, and\n\t// typically contains bits from a random number generator.\n\t//\n\t// Section 8.2 of the specification outlines methods for constructing IVs.\n\t// Note that the IV does not have to be secret, just unique: so it is OK, for example, to\n\t// transmit it in the clear alongside the encrypted message.\n\tIv []byte `js:\"iv\"`\n\n\t// AdditionalData (an ArrayBuffer, a TypedArray, or a DataView) contains additional data that will\n\t// not be encrypted but will be authenticated along with the encrypted data.\n\t//\n\t// If additionalData is given here then the same data must be given in the corresponding call\n\t// to decrypt(): if the data given to the decrypt() call does not match the original data, the\n\t// decryption will throw an exception.\n\t// This gives you a way to authenticate associated data without having to encrypt it.\n\t//\n\t// The bit length of additionalData must be smaller than 2^64 - 1.\n\t//\n\t// The additionalData property is optional and may be omitted without compromising the\n\t// security of the encryption operation.\n\tAdditionalData []byte `js:\"additionalData\"`\n\n\t// TagLength (a Number) determines the size in bits of the authentication tag generated in\n\t// the encryption operation and used for authentication in the corresponding decryption.\n\t//\n\t// According to the Web Crypto specification this must have one of the\n\t// following values: 32, 64, 96, 104, 112, 120, or 128.\n\t// The AES-GCM specification recommends that it should be 96, 104, 112, 120 or 128, although\n\t// 32 or 64 bits may be acceptable\n\t// in some applications: Appendix C of the specification provides additional guidance here.\n\t//\n\t// tagLength is optional and defaults to 128 if it is not specified.\n\tTagLength bitLength `js:\"tagLength\"`\n}\n\n// Encrypt encrypts the given plaintext using the AES-GCM algorithm, and returns the ciphertext.\n// Implements the WebCryptoAPI's `encrypt` method's [specification] for the AES-GCM algorithm.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm\nfunc (agp *AESGCMParams) Encrypt(plaintext []byte, key CryptoKey) ([]byte, error) {\n\t// 1.\n\t// As described in section 8 of AES-GCM [NIST SP800-38D].\n\t// [NIST SP800-38D] https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf\n\tif uint64(len(plaintext)) > maxAESGCMPlaintextLength {\n\t\treturn nil, NewError(OperationError, \"plaintext length is too long\")\n\t}\n\n\t// 2.\n\t// As described in section 8 of AES-GCM [NIST SP800-38D].\n\t// [NIST SP800-38D] https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf\n\t//\n\t// NOTE @oleiade: that the spec targets to support multiple IV lengths\n\t// but go only supports 12 bytes IVs. We therefore are diverging from the\n\t// spec here, and have adjusted the test suite accordingly.\n\tif len(agp.Iv) != 12 {\n\t\treturn nil, NewError(NotSupportedError, \"only 12 bytes long iv are supported\")\n\t}\n\n\t// 3.\n\t// As described in section 8 of AES-GCM [NIST SP800-38D].\n\t// [NIST SP800-38D] https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf\n\tif agp.AdditionalData != nil && (uint64(len(agp.AdditionalData)) > maxAESGcmAdditionalDataLength) {\n\t\treturn nil, NewError(OperationError, \"additional data length is too long\")\n\t}\n\n\t// 4.\n\tvar tagLength bitLength\n\tif agp.TagLength == 0 {\n\t\ttagLength = 128\n\t} else {\n\t\tswitch agp.TagLength {\n\t\tcase 96, 104, 112, 120, 128:\n\t\t\ttagLength = agp.TagLength\n\t\tcase 32, 64:\n\t\t\t// Go's GCM implementation does not support 32 or 64 bit tag lengths.\n\t\t\treturn nil, NewError(NotSupportedError, \"tag length 32 and 64 are not supported\")\n\t\tdefault:\n\t\t\treturn nil, NewError(OperationError, \"invalid tag length, should be one of 96, 104, 112, 120, 128\")\n\t\t}\n\t}\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(ImplementationError, \"could not get key data\")\n\t}\n\n\t// 6.\n\tblock, err := aes.NewCipher(keyHandle)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not create cipher\")\n\t}\n\n\tgcm, err := cipher.NewGCMWithTagSize(block, int(tagLength.asByteLength()))\n\tif err != nil {\n\t\treturn nil, NewError(ImplementationError, \"could not create cipher\")\n\t}\n\n\t// The Golang AES GCM cipher only supports a Nonce/Iv length of 12 bytes,\n\t// as opposed to the looser requirements of the Web Crypto API spec.\n\tif len(agp.Iv) != gcm.NonceSize() {\n\t\treturn nil, NewError(NotSupportedError, \"only 12 bytes long iv are supported\")\n\t}\n\n\t// 7. 8.\n\t// Note that the `Seal` operation adds the tag component at the end of\n\t// the ciphertext.\n\treturn gcm.Seal(nil, agp.Iv, plaintext, agp.AdditionalData), nil\n}\n\n// Decrypt decrypts the given ciphertext using the AES-GCM algorithm, and returns the plaintext.\n// Implements the WebCryptoAPI's `decrypt` method's [specification] for the AES-GCM algorithm.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm\nfunc (agp *AESGCMParams) Decrypt(ciphertext []byte, key CryptoKey) ([]byte, error) {\n\t// 1.\n\tvar tagLength bitLength\n\tif agp.TagLength == 0 {\n\t\ttagLength = 128\n\t} else {\n\t\tswitch agp.TagLength {\n\t\tcase 96, 104, 112, 120, 128:\n\t\t\ttagLength = agp.TagLength\n\t\tcase 32, 64:\n\t\t\t// Go's AES GCM implementation does not support 32 or 64 bit tag lengths.\n\t\t\treturn nil, NewError(OperationError, \"invalid tag length, should be within 96 <= length <= 128 bounds\")\n\t\tdefault:\n\t\t\treturn nil, NewError(OperationError, \"invalid tag length, accepted values are 96, 104, 112, 120, 128\")\n\t\t}\n\t}\n\n\t// 2.\n\t// Note that we multiply the length of the ciphertext by 8, in order\n\t// to get the length in bits.\n\tif byteLength(len(ciphertext)).asBitLength() < tagLength {\n\t\treturn nil, NewError(OperationError, \"ciphertext is too short\")\n\t}\n\n\t// 3.\n\tif len(agp.Iv) < 1 || uint64(len(agp.Iv)) > maxAESGcmIvLength {\n\t\treturn nil, NewError(OperationError, \"iv length is too long\")\n\t}\n\n\t// 4.\n\tif agp.AdditionalData != nil && uint64(len(agp.AdditionalData)) > maxAESGcmAdditionalDataLength {\n\t\treturn nil, NewError(OperationError, \"additional data is too long\")\n\t}\n\n\t// 5. 6. are not necessary as Go's AES GCM implementation perform those steps for us\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(OperationError, \"invalid key handle\")\n\t}\n\n\t// 7. 8.\n\tblock, err := aes.NewCipher(keyHandle)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not create AES cipher\")\n\t}\n\n\tgcm, err := cipher.NewGCMWithTagSize(block, int(tagLength.asByteLength()))\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not create GCM cipher\")\n\t}\n\n\t// The Golang AES GCM cipher only supports a Nonce/Iv length of 12 bytes,\n\tplaintext, err := gcm.Open(nil, agp.Iv, ciphertext, agp.AdditionalData)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not decrypt ciphertext\")\n\t}\n\n\treturn plaintext, nil\n}\n\n// maxAESGCMPlaintextLength holds the value (2 ^ 39) - 256 as specified in\n// The [Web Crypto API spec] for the AES-GCM algorithm encryption operation.\n//\n// [Web Crypto API spec]: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm-encryption-operation\nconst maxAESGCMPlaintextLength uint64 = (1 << 39) - 256\n\n// maxAESGcmAdditionalDataLength holds the value 2 ^ 64 - 1 as specified in\n// the [Web Crypto API spec] for the AES-GCM algorithm encryption operation.\n//\n// [Web Crypto API spec]: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm-encryption-operation\nconst maxAESGcmAdditionalDataLength uint64 = (1 << 64) - 1\n\n// maxAESGcmIvLength holds the value 2 ^ 64 - 1 as specified in\n// the [Web Crypto API spec] for the AES-GCM algorithm encryption operation.\n//\n// [Web Crypto API spec]: https://www.w3.org/TR/WebCryptoAPI/#aes-gcm-encryption-operation\nconst maxAESGcmIvLength uint64 = (1 << 64) - 1\n\nvar (\n\t// ErrInvalidBlockSize is returned when the given block size is invalid.\n\tErrInvalidBlockSize = errors.New(\"invalid block size\")\n\n\t// ErrInvalidPkcs7Data is returned when the given data is invalid.\n\tErrInvalidPkcs7Data = errors.New(\"invalid PKCS7 data\")\n)\n\n// pKCS7Padding adds PKCS7 padding to the given plaintext.\n// It implements section 10.3 of [RFC 2315].\n//\n// [RFC 2315]: https://www.rfc-editor.org/rfc/rfc2315#section-10.3\nfunc pKCS7Pad(plaintext []byte, blockSize int) ([]byte, error) {\n\tif blockSize <= 0 {\n\t\treturn nil, ErrInvalidBlockSize\n\t}\n\n\tif len(plaintext) == 0 {\n\t\treturn nil, ErrInvalidPkcs7Data\n\t}\n\n\tl := len(plaintext)\n\tpadding := blockSize - (l % blockSize)\n\tpaddingText := bytes.Repeat([]byte{byte(padding)}, padding) //nolint:gosec\n\treturn append(plaintext, paddingText...), nil\n}\n\n// unsupportedKeyFormatErrorMsg is the error message returned when an unsupported\n// key format is passed to a function.\n//\n// This is defined as a constant to cater to linter warnings.\nconst unsupportedKeyFormatErrorMsg = \"unsupported key format\"\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/algorithm.go",
    "content": "package webcrypto\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// Algorithm represents\ntype Algorithm struct {\n\tName AlgorithmIdentifier `js:\"name\"`\n}\n\n// AlgorithmIdentifier represents the name of an algorithm.\n// As defined by the [specification]\n//\n// Note that it is defined as an alias of string, instead of a dedicated type,\n// to ensure it is handled as a string by sobek.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#algorithm-dictionary\ntype AlgorithmIdentifier = string\n\nconst (\n\t// RSASsaPkcs1v15 represents the RSA-SHA1 algorithm.\n\tRSASsaPkcs1v15 = \"RSASSA-PKCS1-v1_5\"\n\n\t// RSAPss represents the RSA-PSS algorithm.\n\tRSAPss = \"RSA-PSS\"\n\n\t// RSAOaep represents the RSA-OAEP algorithm.\n\tRSAOaep = \"RSA-OAEP\"\n\n\t// HMAC represents the HMAC algorithm.\n\tHMAC = \"HMAC\"\n\n\t// AESCtr represents the AES-CTR algorithm.\n\tAESCtr = \"AES-CTR\"\n\n\t// AESCbc represents the AES-CBC algorithm.\n\tAESCbc = \"AES-CBC\"\n\n\t// AESGcm represents the AES-GCM algorithm.\n\tAESGcm = \"AES-GCM\"\n\n\t// AESKw represents the AES-KW algorithm.\n\tAESKw = \"AES-KW\"\n\n\t// ECDSA represents the ECDSA algorithm.\n\tECDSA = \"ECDSA\"\n\n\t// ECDH represents the ECDH algorithm.\n\tECDH = \"ECDH\"\n\n\t// PBKDF2 represents the PBKDF2 algorithm\n\tPBKDF2 = \"PBKDF2\"\n)\n\n// HashAlgorithmIdentifier represents the name of a hash algorithm.\n//\n// Note that it is defined as an alias of string, instead of a dedicated type,\n// to ensure it is handled as a string under the hood by sobek.\ntype HashAlgorithmIdentifier = AlgorithmIdentifier\n\nconst (\n\t// SHA1 represents the SHA-1 algorithm.\n\tSHA1 HashAlgorithmIdentifier = \"SHA-1\"\n\n\t// SHA256 represents the SHA-256 algorithm.\n\tSHA256 = \"SHA-256\"\n\n\t// SHA384 represents the SHA-384 algorithm.\n\tSHA384 = \"SHA-384\"\n\n\t// SHA512 represents the SHA-512 algorithm.\n\tSHA512 = \"SHA-512\"\n)\n\n// OperationIdentifier represents the name of an operation.\n//\n// Note that it is defined as an alias of string, instead of a dedicated type,\n// to ensure it is handled as a string by sobek.\ntype OperationIdentifier = string\n\nconst (\n\t// OperationIdentifierSign represents the sign operation.\n\tOperationIdentifierSign OperationIdentifier = \"sign\"\n\n\t// OperationIdentifierVerify represents the verify operation.\n\tOperationIdentifierVerify OperationIdentifier = \"verify\"\n\n\t// OperationIdentifierEncrypt represents the encrypt operation.\n\tOperationIdentifierEncrypt OperationIdentifier = \"encrypt\"\n\n\t// OperationIdentifierDecrypt represents the decrypt operation.\n\tOperationIdentifierDecrypt OperationIdentifier = \"decrypt\"\n\n\t// OperationIdentifierDeriveBits represents the deriveBits operation.\n\tOperationIdentifierDeriveBits OperationIdentifier = \"deriveBits\"\n\n\t// OperationIdentifierDeriveKey represents the deriveKey operation.\n\tOperationIdentifierDeriveKey OperationIdentifier = \"deriveKey\"\n\n\t// OperationIdentifierWrapKey represents the wrapKey operation.\n\tOperationIdentifierWrapKey OperationIdentifier = \"wrapKey\"\n\n\t// OperationIdentifierUnwrapKey represents the unwrapKey operation.\n\tOperationIdentifierUnwrapKey OperationIdentifier = \"unwrapKey\"\n\n\t// OperationIdentifierImportKey represents the importKey operation.\n\tOperationIdentifierImportKey OperationIdentifier = \"importKey\"\n\n\t// OperationIdentifierExportKey represents the exportKey operation.\n\tOperationIdentifierExportKey OperationIdentifier = \"exportKey\"\n\n\t// OperationIdentifierGenerateKey represents the generateKey operation.\n\tOperationIdentifierGenerateKey OperationIdentifier = \"generateKey\"\n\n\t// OperationIdentifierDigest represents the digest operation.\n\tOperationIdentifierDigest OperationIdentifier = \"digest\"\n\n\t// OperationIdentifierGetKeyLength represents a getKeyLength operation\n\tOperationIdentifierGetKeyLength = \"getKeyLength\"\n)\n\n// normalizeAlgorithm normalizes the given algorithm following the\n// algorithm described in the WebCrypto [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#algorithm-normalization-normalize-an-algorithm\nfunc normalizeAlgorithm(rt *sobek.Runtime, v sobek.Value, op AlgorithmIdentifier) (Algorithm, error) {\n\tvar algorithm Algorithm\n\n\t// \"if alg is an instance of a DOMString: return the result of the running the\n\t// normalize algorithm, with the `alg` set to a new Algorithm object whose name\n\t// attribute is set to alg, and with the op set to op.\"\n\tif v.ExportType().Kind() == reflect.String {\n\t\talgorithmString, ok := v.Export().(string)\n\t\tif !ok {\n\t\t\treturn Algorithm{}, NewError(ImplementationError, \"algorithm cannot be interpreted as a string\")\n\t\t}\n\n\t\talgorithmObject := rt.NewObject()\n\t\tif err := algorithmObject.Set(\"name\", algorithmString); err != nil {\n\t\t\treturn Algorithm{}, NewError(ImplementationError, \"unable to transform algorithm string into an object\")\n\t\t}\n\n\t\treturn normalizeAlgorithm(rt, algorithmObject, op)\n\t}\n\n\tif err := rt.ExportTo(v, &algorithm); err != nil {\n\t\treturn Algorithm{}, NewError(SyntaxError, \"algorithm cannot be interpreted as a string or an object\")\n\t}\n\n\talgorithm.Name = normalizeAlgorithmName(algorithm.Name)\n\n\tif !isRegisteredAlgorithm(algorithm.Name, op) {\n\t\treturn Algorithm{}, NewError(\n\t\t\tNotSupportedError,\n\t\t\tfmt.Sprintf(\"algorithm %q doesn't support (in implementation) operation %q\", algorithm.Name, op),\n\t\t)\n\t}\n\n\treturn algorithm, nil\n}\n\nfunc normalizeAlgorithmName(name string) string {\n\t// Algorithm identifiers are always upper cased.\n\t// A registered algorithm provided in lower case format, should\n\t// be considered valid.\n\tname = strings.ToUpper(name)\n\n\t// exception is made for RSASSA-PKCS1-v1_5\n\tif name == strings.ToUpper(RSASsaPkcs1v15) {\n\t\treturn RSASsaPkcs1v15\n\t}\n\n\treturn name\n}\n\n// isRegisteredAlgorithm returns true if the given algorithm name is registered\n// for the given operation. As per steps 1. and 5. of the WebCrypto specification's\n// \"[algorithm normalization]\" algorithm.\n//\n// [algorithm normalization]: https://www.w3.org/TR/WebCryptoAPI/#algorithm-normalization-normalize-an-algorithm\nfunc isRegisteredAlgorithm(algorithmName string, forOperation string) bool {\n\tswitch forOperation {\n\tcase OperationIdentifierDigest:\n\t\treturn isHashAlgorithm(algorithmName)\n\tcase OperationIdentifierGenerateKey:\n\t\t// FIXME: the presence of the hash algorithm here is for HMAC support and should be handled separately\n\t\treturn isAesAlgorithm(algorithmName) ||\n\t\t\tisHashAlgorithm(algorithmName) ||\n\t\t\tisHMACAlgorithm(algorithmName) ||\n\t\t\tisEllipticCurve(algorithmName) ||\n\t\t\tisRSAAlgorithm(algorithmName)\n\tcase OperationIdentifierExportKey, OperationIdentifierImportKey:\n\t\treturn isAesAlgorithm(algorithmName) ||\n\t\t\tisHMACAlgorithm(algorithmName) ||\n\t\t\tisEllipticCurve(algorithmName) ||\n\t\t\tisRSAAlgorithm(algorithmName) ||\n\t\t\tisPBKDF2Algorithm(algorithmName)\n\tcase OperationIdentifierEncrypt, OperationIdentifierDecrypt:\n\t\treturn isAesAlgorithm(algorithmName) || algorithmName == RSAOaep\n\tcase OperationIdentifierSign, OperationIdentifierVerify:\n\t\treturn isHMACAlgorithm(algorithmName) ||\n\t\t\talgorithmName == ECDSA ||\n\t\t\talgorithmName == RSAPss ||\n\t\t\talgorithmName == RSASsaPkcs1v15\n\tcase OperationIdentifierDeriveBits:\n\t\treturn isHashAlgorithm(algorithmName) || isPBKDF2Algorithm(algorithmName) || isECDHAlgorithm(algorithmName)\n\tcase OperationIdentifierDeriveKey:\n\t\treturn isHashAlgorithm(algorithmName) || isPBKDF2Algorithm(algorithmName)\n\tcase OperationIdentifierGetKeyLength:\n\t\treturn isAesAlgorithm(algorithmName)\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc isAesAlgorithm(algorithmName string) bool {\n\treturn algorithmName == AESCbc || algorithmName == AESCtr || algorithmName == AESGcm || algorithmName == AESKw\n}\n\nfunc isHashAlgorithm(algorithmName string) bool {\n\treturn algorithmName == SHA1 || algorithmName == SHA256 || algorithmName == SHA384 || algorithmName == SHA512\n}\n\nfunc isRSAAlgorithm(algorithmName string) bool {\n\treturn algorithmName == RSASsaPkcs1v15 || algorithmName == RSAPss || algorithmName == RSAOaep\n}\n\nfunc isPBKDF2Algorithm(algorithmName string) bool {\n\treturn algorithmName == PBKDF2\n}\n\nfunc isECDHAlgorithm(algorithmName string) bool {\n\treturn algorithmName == ECDH\n}\n\nfunc isHMACAlgorithm(algorithmName string) bool {\n\treturn algorithmName == HMAC\n}\n\n// hasAlg an internal interface that helps us to identify\n// if a given object has an algorithm method.\ntype hasAlg interface {\n\talg() string\n}\n\nfunc isEllipticCurve(algorithmName string) bool {\n\treturn algorithmName == ECDH || algorithmName == ECDSA\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/base64.go",
    "content": "package webcrypto\n\nimport \"encoding/base64\"\n\nfunc base64URLEncode(data []byte) string {\n\treturn base64.RawURLEncoding.EncodeToString(data)\n}\n\nfunc base64URLDecode(data string) ([]byte, error) {\n\treturn base64.RawURLEncoding.DecodeString(data)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/bits.go",
    "content": "package webcrypto\n\nimport \"github.com/grafana/sobek\"\n\n// BitsDeriver is the interface implemented by the parameters used to derive bits\ntype BitsDeriver interface {\n\tDeriveBits(privateKey *CryptoKey, length int) ([]byte, error)\n}\n\nfunc newBitsDeriver(rt *sobek.Runtime, normalized Algorithm, algorithm sobek.Value) (BitsDeriver, error) {\n\tvar deriver BitsDeriver\n\tvar err error\n\n\tswitch normalized.Name {\n\tcase ECDH:\n\t\tderiver, err = newECDHKeyDeriveParams(rt, normalized, algorithm)\n\tcase PBKDF2:\n\t\tderiver, err = newPBKDF2DeriveParams(rt, normalized, algorithm)\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, \"unsupported algorithm for derive bits: \"+normalized.Name)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn deriver, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/cmd_run_test.go",
    "content": "package webcrypto_test\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/cmd\"\n\tk6Tests \"go.k6.io/k6/internal/cmd/tests\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc getSingleFileTestState(tb testing.TB, script string, cliFlags []string, expExitCode exitcodes.ExitCode) *k6Tests.GlobalTestState {\n\tif cliFlags == nil {\n\t\tcliFlags = []string{\"-v\", \"--log-output=stdout\"}\n\t}\n\n\tts := k6Tests.NewGlobalTestState(tb)\n\trequire.NoError(tb, fsext.WriteFile(ts.FS, filepath.Join(ts.Cwd, \"test.js\"), []byte(script), 0o644))\n\tts.CmdArgs = append(append([]string{\"k6\", \"run\"}, cliFlags...), \"test.js\")\n\tts.ExpectedExitCode = int(expExitCode)\n\n\treturn ts\n}\n\n// TestExamplesInputOutput runs same k6's scripts that we have in example folder\n// it check that output contains/not contains cetane things\n// it's not a real test, but it's a good way to check that examples are working\n// between changes\n//\n// We also do use a convention that successful output should contain `level=info` (at least one info message from console.log), e.g.:\n// INFO[0000] deciphered text == original text:  true       source=console\n// and should not contain `level=error` or \"Uncaught\", e.g. outputs like:\n// ERRO[0000] Uncaught (in promise) OperationError: length is too large  executor=per-vu-iterations scenario=default\nfunc TestExamplesInputOutput(t *testing.T) {\n\tt.Parallel()\n\n\toutputShouldContain := []string{\n\t\t\"output: -\",\n\t\t\"default: 1 iterations for each of 1 VUs\",\n\t\t\"1 complete and 0 interrupted iterations\",\n\t\t\"level=info\", // at least one info message\n\t}\n\n\toutputShouldNotContain := []string{\n\t\t\"Uncaught\",\n\t\t\"level=error\", // no error messages\n\t}\n\n\tconst examplesDir = \"../../../../../examples/webcrypto\"\n\n\t// List of the directories containing the examples\n\t// that we should run and check that they produce the expected output\n\t// and not the unexpected one\n\t// it could be a file (ending with .js) or a directory\n\texamples := []string{\n\t\texamplesDir + \"/digest.js\",\n\t\texamplesDir + \"/getRandomValues.js\",\n\t\texamplesDir + \"/randomUUID.js\",\n\t\texamplesDir + \"/generateKey\",\n\t\texamplesDir + \"/derive_bits\",\n\t\texamplesDir + \"/encrypt_decrypt\",\n\t\texamplesDir + \"/sign_verify\",\n\t\texamplesDir + \"/import_export\",\n\t}\n\n\tfor _, path := range examples {\n\t\tlist := getFiles(t, path)\n\n\t\tfor _, file := range list {\n\t\t\tname := filepath.Base(file)\n\n\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\tscript, err := os.ReadFile(filepath.Clean(file)) //nolint:forbidigo // we read an example directly\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tts := getSingleFileTestState(t, string(script), []string{\"-v\", \"--log-output=stdout\"}, 0)\n\n\t\t\t\tcmd.ExecuteWithGlobalState(ts.GlobalState)\n\n\t\t\t\tstdout := ts.Stdout.String()\n\n\t\t\t\tfor _, s := range outputShouldContain {\n\t\t\t\t\tassert.Contains(t, stdout, s)\n\t\t\t\t}\n\t\t\t\tfor _, s := range outputShouldNotContain {\n\t\t\t\t\tassert.NotContains(t, stdout, s)\n\t\t\t\t}\n\n\t\t\t\tassert.Empty(t, ts.Stderr.String())\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc getFiles(t *testing.T, path string) []string {\n\tt.Helper()\n\n\tresult := []string{}\n\n\t// If the path is a file, return it as is\n\tif strings.HasSuffix(path, \".js\") {\n\t\treturn append(result, path)\n\t}\n\n\t// If the path is a directory, return all the files in it\n\tlist, err := os.ReadDir(path) //nolint:forbidigo // we read a directory\n\tif err != nil {\n\t\tt.Fatalf(\"failed to read directory: %v\", err)\n\t}\n\n\tfor _, file := range list {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tresult = append(result, filepath.Join(path, file.Name()))\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/crypto.go",
    "content": "package webcrypto\n\nimport (\n\t\"crypto/rand\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// Crypto represents the Crypto interface of the Web Crypto API.\ntype Crypto struct {\n\tvu modules.VU\n\n\tSubtle    *SubtleCrypto `js:\"subtle\"`\n\tCryptoKey *CryptoKey    `js:\"CryptoKey\"`\n}\n\n// GetRandomValues lets you get cryptographically strong random values.\n// As defined by the Web Crypto API's Crypto.getRandomValues() method\n// [specifications].\n//\n// Do not generate keys using the getRandomValues method. Use the generateKey method instead.\n//\n// The array given as the parameter is filled with random numbers (random in\n// its cryptographic sense, not in its statistical sense).\n//\n// To guarantee enough performance, this implementation is not using a truly\n// random number generator, but is using a pseudo-random number generator\n// seeded with a value with enough entropy. We are using the golang\n// crypto/rand package, which uses the operating system's random number\n// generator.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues\nfunc (c *Crypto) GetRandomValues(typedArray sobek.Value) sobek.Value {\n\tacceptedTypes := []JSType{\n\t\tInt8ArrayConstructor,\n\t\tUint8ArrayConstructor,\n\t\tUint8ClampedArrayConstructor,\n\t\tInt16ArrayConstructor,\n\t\tUint16ArrayConstructor,\n\t\tInt32ArrayConstructor,\n\t\tUint32ArrayConstructor,\n\t}\n\n\t// 1.\n\tif !IsInstanceOf(c.vu.Runtime(), typedArray, acceptedTypes...) {\n\t\tcommon.Throw(c.vu.Runtime(), NewError(TypeMismatchError, \"typedArray parameter isn't a TypedArray instance\"))\n\t}\n\n\t// 2.\n\t// Obtain the length of the typed array, and throw a QuotaExceededError if\n\t// it's too big, as specified in the [spec's] 10.2.1.2 paragraph.\n\t// [spec]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues\n\tobj := typedArray.ToObject(c.vu.Runtime())\n\tobjLength, ok := obj.Get(\"length\").ToNumber().Export().(int64)\n\tif !ok {\n\t\tcommon.Throw(c.vu.Runtime(), NewError(TypeMismatchError, \"typedArray parameter isn't a TypedArray instance\"))\n\t}\n\n\tif objLength > maxRandomValuesLength {\n\t\tcommon.Throw(\n\t\t\tc.vu.Runtime(),\n\t\t\tNewError(\n\t\t\t\tQuotaExceededError,\n\t\t\t\tfmt.Sprintf(\"typedArray parameter is too big; maximum length is %d\", maxRandomValuesLength),\n\t\t\t),\n\t\t)\n\t}\n\n\t// 3.\n\t// Create a buffer of a matching size and fill\n\t// it with random values.\n\t//\n\t// We use crypto/rand.Read() here as it will use /dev/urandom or\n\t// an equivalent on Unix-like systems, and CryptGenRandom()\n\t// on Windows. This is the recommended way to generate random\n\t// by the specification.\n\trandomValues := make([]byte, objLength)\n\t_, err := rand.Read(randomValues)\n\tif err != nil {\n\t\tcommon.Throw(c.vu.Runtime(), err)\n\t}\n\n\tfor i := range objLength {\n\t\terr := obj.Set(strconv.FormatInt(i, 10), randomValues[i])\n\t\tif err != nil {\n\t\t\tcommon.Throw(c.vu.Runtime(), err)\n\t\t}\n\t}\n\n\t// Although the input array has been modified in place,\n\t// the specification stipulates it should also be returned.\n\treturn typedArray\n}\n\n// MaxRandomValues is the maximum number of random values that can be generated\nconst maxRandomValuesLength = 65536\n\n// RandomUUID returns a [RFC4122] compliant v4 UUID string.\n//\n// It implements the Web Crypto API's Crypto.randomUUID() method, as\n// specified in [Web Crypto API's specification] Level 10, section 10.1.2.\n// The UUID is generated using a cryptographically secure random number generator.\n//\n// [RFC4122]: https://tools.ietf.org/html/rfc4122\n// [Web Crypto API's specification]: https://w3c.github.io/webcrypto/#Crypto-method-randomUUID\nfunc (c *Crypto) RandomUUID() string {\n\treturn uuid.New().String()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/elliptic_curve.go",
    "content": "package webcrypto\n\nimport (\n\t\"crypto/ecdh\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/grafana/sobek\"\n)\n\nconst (\n\tp256Canonical = \"P-256\"\n\tp384Canonical = \"P-384\"\n\tp521Canonical = \"P-521\"\n)\n\n// EcKeyAlgorithm is the algorithm for elliptic curve keys as defined in the [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#EcKeyAlgorithm-dictionary\ntype EcKeyAlgorithm struct {\n\tKeyAlgorithm\n\n\t// NamedCurve holds (a String) the name of the elliptic curve to use.\n\tNamedCurve EllipticCurveKind `js:\"namedCurve\"`\n}\n\n// EcKeyImportParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.ImportKey` or `SubtleCrypto.UnwrapKey`, when generating any elliptic-curve-based\n// key pair: that is, when the algorithm is identified as either of ECDSA or ECDH.\ntype EcKeyImportParams struct {\n\tAlgorithm\n\n\t// NamedCurve holds (a String) the name of the elliptic curve to use.\n\tNamedCurve EllipticCurveKind `js:\"namedCurve\"`\n}\n\nfunc newEcKeyImportParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*EcKeyImportParams, error) {\n\tnamedCurve, err := traverseObject(rt, params, \"namedCurve\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get namedCurve from algorithm parameter\")\n\t}\n\n\treturn &EcKeyImportParams{\n\t\tAlgorithm:  normalized,\n\t\tNamedCurve: EllipticCurveKind(namedCurve.String()),\n\t}, nil\n}\n\n// Ensure that EcKeyImportParams implements the KeyImporter interface.\nvar _ KeyImporter = &EcKeyImportParams{}\n\n// ImportKey imports a key according to the algorithm described in the specification.\n// https://www.w3.org/TR/WebCryptoAPI/#ecdh-operations\nfunc (e *EcKeyImportParams) ImportKey(\n\tformat KeyFormat,\n\tkeyData []byte,\n\t_ bool,\n\t_ []CryptoKeyUsage,\n) (*CryptoKey, error) {\n\tvar importFn func(curve EllipticCurveKind, keyData []byte) (any, CryptoKeyType, error)\n\n\tswitch {\n\tcase e.Name == ECDH && format == Pkcs8KeyFormat:\n\t\timportFn = importECDHPrivateKey\n\tcase e.Name == ECDH && format == RawKeyFormat:\n\t\timportFn = importECDHPublicKey\n\tcase e.Name == ECDSA && format == Pkcs8KeyFormat:\n\t\timportFn = importECDSAPrivateKey\n\tcase e.Name == ECDSA && format == RawKeyFormat:\n\t\timportFn = importECDSAPublicKey\n\tcase e.Name == ECDH && format == SpkiKeyFormat:\n\t\timportFn = importECDHSPKIPublicKey\n\tcase e.Name == ECDSA && format == SpkiKeyFormat:\n\t\timportFn = importECDSASPKIPublicKey\n\tcase e.Name == ECDSA && format == JwkKeyFormat:\n\t\timportFn = importECDSAJWK\n\tcase e.Name == ECDH && format == JwkKeyFormat:\n\t\timportFn = importECDHJWK\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, unsupportedKeyFormatErrorMsg+\" \"+format+\" for algorithm \"+e.Name)\n\t}\n\n\thandle, keyType, err := importFn(e.NamedCurve, keyData)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &CryptoKey{\n\t\tAlgorithm: EcKeyAlgorithm{\n\t\t\tKeyAlgorithm: KeyAlgorithm{\n\t\t\t\tAlgorithm: e.Algorithm,\n\t\t\t},\n\t\t\tNamedCurve: e.NamedCurve,\n\t\t},\n\t\tType:   keyType,\n\t\thandle: handle,\n\t}, nil\n}\n\nfunc importECDHPublicKey(curve EllipticCurveKind, keyData []byte) (any, CryptoKeyType, error) {\n\tc, err := pickECDHCurve(curve.String())\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(NotSupportedError, \"invalid ECDH curve \"+string(curve))\n\t}\n\n\thandle, err := c.NewPublicKey(keyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import ECDH public key data: \"+err.Error())\n\t}\n\n\treturn handle, PublicCryptoKeyType, nil\n}\n\nfunc importECDHSPKIPublicKey(_ EllipticCurveKind, keyData []byte) (any, CryptoKeyType, error) {\n\tpk, err := x509.ParsePKIXPublicKey(keyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import ECDH public key data: \"+err.Error())\n\t}\n\n\tecdsaKey, ok := pk.(*ecdsa.PublicKey)\n\tif !ok {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"a public key is not an ECDSA key\")\n\t}\n\n\t// try to restore the ECDH key\n\tkey, err := ecdsaKey.ECDH()\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import key data: \"+err.Error())\n\t}\n\n\treturn key, PublicCryptoKeyType, nil\n}\n\nfunc importECDSASPKIPublicKey(_ EllipticCurveKind, keyData []byte) (any, CryptoKeyType, error) {\n\tpk, err := x509.ParsePKIXPublicKey(keyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import ECDH public key data: \"+err.Error())\n\t}\n\n\tecdsaKey, ok := pk.(*ecdsa.PublicKey)\n\tif !ok {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"a public key is not an ECDSA key\")\n\t}\n\n\t// try to restore the ECDH key\n\treturn ecdsaKey, PublicCryptoKeyType, nil\n}\n\n// EllipticCurveKind represents the kind of elliptic curve that is being used.\ntype EllipticCurveKind string\n\nconst (\n\t// EllipticCurveKindP256 represents the P-256 curve.\n\tEllipticCurveKindP256 EllipticCurveKind = \"P-256\"\n\n\t// EllipticCurveKindP384 represents the P-384 curve.\n\tEllipticCurveKindP384 EllipticCurveKind = \"P-384\"\n\n\t// EllipticCurveKindP521 represents the P-521 curve.\n\tEllipticCurveKindP521 EllipticCurveKind = \"P-521\"\n)\n\nfunc (k EllipticCurveKind) String() string {\n\treturn string(k)\n}\n\n// IsEllipticCurve returns true if the given string is a valid EllipticCurveKind,\n// false otherwise.\nfunc IsEllipticCurve(name string) bool {\n\tswitch name {\n\tcase string(EllipticCurveKindP256):\n\t\treturn true\n\tcase string(EllipticCurveKindP384):\n\t\treturn true\n\tcase string(EllipticCurveKindP521):\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc importECDHPrivateKey(_ EllipticCurveKind, keyData []byte) (any, CryptoKeyType, error) {\n\tparsedKey, err := x509.ParsePKCS8PrivateKey(keyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import ECDH private key data: \"+err.Error())\n\t}\n\n\t// check if the key is an ECDSA key\n\tecdsaKey, ok := parsedKey.(*ecdsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"a private key is not an ECDSA key\")\n\t}\n\n\t// try to restore the ECDH key\n\thandle, err := ecdsaKey.ECDH()\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import key data: \"+err.Error())\n\t}\n\n\treturn handle, PrivateCryptoKeyType, nil\n}\n\nfunc importECDSAPrivateKey(_ EllipticCurveKind, keyData []byte) (any, CryptoKeyType, error) {\n\tparsedKey, err := x509.ParsePKCS8PrivateKey(keyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import ECDSA private key data: \"+err.Error())\n\t}\n\n\tecdsaKey, ok := parsedKey.(*ecdsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"a private key is not an ECDSA key\")\n\t}\n\n\treturn ecdsaKey, PrivateCryptoKeyType, nil\n}\n\nfunc importECDSAPublicKey(curve EllipticCurveKind, keyData []byte) (any, CryptoKeyType, error) {\n\tc, err := pickEllipticCurve(curve.String())\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(NotSupportedError, \"invalid elliptic curve \"+string(curve))\n\t}\n\n\tx, y := elliptic.Unmarshal(c, keyData) //nolint:staticcheck // we need to use the Unmarshal function\n\tif x == nil {\n\t\treturn nil, UnknownCryptoKeyType, NewError(DataError, \"unable to import ECDSA public key data\")\n\t}\n\n\treturn &ecdsa.PublicKey{\n\t\tCurve: c,\n\t\tX:     x,\n\t\tY:     y,\n\t}, PublicCryptoKeyType, nil\n}\n\n// ECKeyGenParams  represents the object that should be passed as the algorithm\n// parameter into `SubtleCrypto.GenerateKey`, when generating any\n// elliptic-curve-based key pair: that is, when the algorithm is identified\n// as either of AlgorithmKindEcdsa or AlgorithmKindEcdh.\ntype ECKeyGenParams struct {\n\tAlgorithm\n\n\t// NamedCurve holds (a String) the name of the curve to use.\n\t// You can use any of the following: CurveKindP256, CurveKindP384, or CurveKindP521.\n\tNamedCurve EllipticCurveKind\n}\n\nvar _ KeyGenerator = &ECKeyGenParams{}\n\nfunc newECKeyGenParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*ECKeyGenParams, error) {\n\tnamedCurve, err := traverseObject(rt, params, \"namedCurve\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get namedCurve from algorithm parameter\")\n\t}\n\n\treturn &ECKeyGenParams{\n\t\tAlgorithm:  normalized,\n\t\tNamedCurve: EllipticCurveKind(namedCurve.String()),\n\t}, nil\n}\n\n// GenerateKey generates a new ECDH/ECDSA key pair, according to the algorithm\n// described in the specification.\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#dfn-EcKeyGenParams\nfunc (ecgp *ECKeyGenParams) GenerateKey(\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (CryptoKeyGenerationResult, error) {\n\tvar keyPairGenerator func(curve EllipticCurveKind, keyUsages []CryptoKeyUsage) (any, any, error)\n\tvar privateKeyUsages, publicKeyUsages []CryptoKeyUsage\n\n\tswitch ecgp.Name {\n\tcase ECDH:\n\t\tkeyPairGenerator = generateECDHKeyPair\n\t\tprivateKeyUsages = []CryptoKeyUsage{DeriveKeyCryptoKeyUsage, DeriveBitsCryptoKeyUsage}\n\t\tpublicKeyUsages = []CryptoKeyUsage{}\n\tcase ECDSA:\n\t\tkeyPairGenerator = generateECDSAKeyPair\n\t\tprivateKeyUsages = []CryptoKeyUsage{SignCryptoKeyUsage}\n\t\tpublicKeyUsages = []CryptoKeyUsage{VerifyCryptoKeyUsage}\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, \"unsupported elliptic algorithm: \"+ecgp.Name)\n\t}\n\n\tif !isValidEllipticCurve(ecgp.NamedCurve) {\n\t\treturn nil, NewError(NotSupportedError, \"elliptic curve \"+string(ecgp.NamedCurve)+\" is not supported\")\n\t}\n\n\tif len(keyUsages) == 0 {\n\t\treturn nil, NewError(SyntaxError, \"key usages cannot be empty\")\n\t}\n\n\talg := EcKeyAlgorithm{\n\t\tKeyAlgorithm: KeyAlgorithm{\n\t\t\tAlgorithm: ecgp.Algorithm,\n\t\t},\n\t\tNamedCurve: ecgp.NamedCurve,\n\t}\n\n\t// wrap the keys in CryptoKey objects\n\tprivateKey := &CryptoKey{\n\t\tType:        PrivateCryptoKeyType,\n\t\tExtractable: extractable,\n\t\tAlgorithm:   alg,\n\t\tUsages: UsageIntersection(\n\t\t\tkeyUsages,\n\t\t\tprivateKeyUsages,\n\t\t),\n\t}\n\n\tpublicKey := &CryptoKey{\n\t\tType:        PublicCryptoKeyType,\n\t\tExtractable: true,\n\t\tAlgorithm:   alg,\n\t\tUsages: UsageIntersection(\n\t\t\tpublicKeyUsages,\n\t\t\tkeyUsages,\n\t\t),\n\t}\n\n\tvar err error\n\tprivateKey.handle, publicKey.handle, err = keyPairGenerator(ecgp.NamedCurve, keyUsages)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &CryptoKeyPair{\n\t\tPrivateKey: privateKey,\n\t\tPublicKey:  publicKey,\n\t}, nil\n}\n\nfunc generateECDHKeyPair(curve EllipticCurveKind, keyUsages []CryptoKeyUsage) (any, any, error) {\n\tfor _, usage := range keyUsages {\n\t\tswitch usage {\n\t\tcase DeriveKeyCryptoKeyUsage, DeriveBitsCryptoKeyUsage:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\treturn nil, nil, NewError(SyntaxError, \"invalid key usage\")\n\t\t}\n\t}\n\n\tc, err := pickECDHCurve(curve.String())\n\tif err != nil {\n\t\treturn nil, nil, NewError(NotSupportedError, err.Error())\n\t}\n\n\t// generate a private & public key\n\trawPrivateKey, err := c.GenerateKey(rand.Reader)\n\tif err != nil {\n\t\treturn nil, nil, NewError(OperationError, \"unable to generate a ECDH key pair\")\n\t}\n\n\treturn rawPrivateKey, rawPrivateKey.PublicKey(), nil\n}\n\nfunc generateECDSAKeyPair(curve EllipticCurveKind, keyUsages []CryptoKeyUsage) (any, any, error) {\n\tfor _, usage := range keyUsages {\n\t\tswitch usage {\n\t\tcase SignCryptoKeyUsage, VerifyCryptoKeyUsage:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\treturn nil, nil, NewError(SyntaxError, \"invalid key usage\")\n\t\t}\n\t}\n\n\tc, err := pickEllipticCurve(curve.String())\n\tif err != nil {\n\t\treturn nil, nil, NewError(NotSupportedError, err.Error())\n\t}\n\n\trawPrivateKey, err := ecdsa.GenerateKey(c, rand.Reader)\n\tif err != nil {\n\t\treturn nil, nil, NewError(OperationError, \"unable to generate a ECDSA key pair\")\n\t}\n\n\treturn rawPrivateKey, &rawPrivateKey.PublicKey, nil\n}\n\n// isValidEllipticCurve returns true if the given elliptic curve is supported,\nfunc isValidEllipticCurve(curve EllipticCurveKind) bool {\n\treturn curve == EllipticCurveKindP256 || curve == EllipticCurveKindP384 || curve == EllipticCurveKindP521\n}\n\nfunc pickECDHCurve(k string) (ecdh.Curve, error) {\n\tswitch k {\n\tcase p256Canonical:\n\t\treturn ecdh.P256(), nil\n\tcase p384Canonical:\n\t\treturn ecdh.P384(), nil\n\tcase p521Canonical:\n\t\treturn ecdh.P521(), nil\n\tdefault:\n\t\treturn nil, errors.New(\"invalid ECDH curve\")\n\t}\n}\n\nfunc pickEllipticCurve(k string) (elliptic.Curve, error) {\n\tswitch k {\n\tcase p256Canonical:\n\t\treturn elliptic.P256(), nil\n\tcase p384Canonical:\n\t\treturn elliptic.P384(), nil\n\tcase p521Canonical:\n\t\treturn elliptic.P521(), nil\n\tdefault:\n\t\treturn nil, errors.New(\"invalid elliptic curve \" + k)\n\t}\n}\n\nfunc exportECKey(ck *CryptoKey, format KeyFormat) (any, error) {\n\tif ck.handle == nil {\n\t\treturn nil, NewError(OperationError, \"key data is not accessible\")\n\t}\n\n\talg, ok := ck.Algorithm.(EcKeyAlgorithm)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, \"key algorithm is not a valid EC algorithm\")\n\t}\n\n\tswitch format {\n\tcase RawKeyFormat:\n\t\tif ck.Type != PublicCryptoKeyType {\n\t\t\treturn nil, NewError(InvalidAccessError, \"key is not a valid elliptic curve public key\")\n\t\t}\n\n\t\tbytes, err := extractPublicKeyBytes(alg.Name, ck.handle)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(OperationError, \"unable to extract public key data: \"+err.Error())\n\t\t}\n\n\t\treturn bytes, nil\n\tcase SpkiKeyFormat:\n\t\tif ck.Type != PublicCryptoKeyType {\n\t\t\treturn nil, NewError(InvalidAccessError, \"key is not a valid elliptic curve public key\")\n\t\t}\n\n\t\tbytes, err := x509.MarshalPKIXPublicKey(ck.handle)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(OperationError, \"unable to marshal key to SPKI format: \"+err.Error())\n\t\t}\n\n\t\treturn bytes, nil\n\tcase Pkcs8KeyFormat:\n\t\tif ck.Type != PrivateCryptoKeyType {\n\t\t\treturn nil, NewError(InvalidAccessError, \"key is not a valid elliptic curve private key\")\n\t\t}\n\n\t\tbytes, err := x509.MarshalPKCS8PrivateKey(ck.handle)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(OperationError, \"unable to marshal key to PKCS8 format: \"+err.Error())\n\t\t}\n\n\t\treturn bytes, nil\n\tcase JwkKeyFormat:\n\t\treturn exportECJWK(ck)\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, unsupportedKeyFormatErrorMsg+\" \"+format)\n\t}\n}\n\nfunc extractPublicKeyBytes(alg string, handle any) ([]byte, error) {\n\tif alg == ECDH {\n\t\tk, ok := handle.(*ecdh.PublicKey)\n\t\tif !ok {\n\t\t\treturn nil, NewError(OperationError, \"key data isn't a valid elliptic curve public key\")\n\t\t}\n\n\t\treturn k.Bytes(), nil\n\t}\n\n\tif alg == ECDSA {\n\t\tk, ok := handle.(*ecdsa.PublicKey)\n\t\tif !ok {\n\t\t\treturn nil, NewError(OperationError, \"key data isn't a valid elliptic curve public key\")\n\t\t}\n\n\t\treturn elliptic.Marshal(k.Curve, k.X, k.Y), nil //nolint:staticcheck // we need to use the Marshal function\n\t}\n\n\treturn nil, errors.New(\"unsupported algorithm \" + alg)\n}\n\n// ECDHKeyDeriveParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.DeriveBits` or `SubtleCrypto.DeriveKey` when generating any elliptic-curve-based\n// key: that is, when the algorithm is identified as ECDH.\ntype ECDHKeyDeriveParams struct {\n\tAlgorithm\n\tPublic *CryptoKey\n}\n\nvar _ BitsDeriver = &ECDHKeyDeriveParams{}\n\nfunc newECDHKeyDeriveParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*ECDHKeyDeriveParams, error) {\n\tvar publicKey *CryptoKey\n\n\tpcValue, err := traverseObject(rt, params, \"public\")\n\tif err != nil {\n\t\treturn nil, NewError(TypeError, \"algorithm does not contain a public key\")\n\t}\n\tif err := rt.ExportTo(pcValue, &publicKey); err != nil {\n\t\treturn nil, NewError(TypeError, \"algorithm's public is not a valid CryptoKey: \"+err.Error())\n\t}\n\tif err := publicKey.Validate(); err != nil {\n\t\treturn nil, NewError(TypeError, \"algorithm's public key is not a valid CryptoKey: \"+err.Error())\n\t}\n\n\tif publicKey.Type != PublicCryptoKeyType {\n\t\treturn nil, NewError(InvalidAccessError, \"algorithm's public key is not a public key\")\n\t}\n\n\tkeyAlgorithmNameValue, err := traverseObject(rt, pcValue, \"algorithm\", \"name\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif normalized.Name != keyAlgorithmNameValue.String() {\n\t\treturn nil, NewError(\n\t\t\tInvalidAccessError,\n\t\t\t\"algorithm name does not match public key's algorithm name: \"+\n\t\t\t\tnormalized.Name+\" != \"+keyAlgorithmNameValue.String(),\n\t\t)\n\t}\n\n\treturn &ECDHKeyDeriveParams{\n\t\tAlgorithm: normalized,\n\t\tPublic:    publicKey,\n\t}, nil\n}\n\n// DeriveBits represents the EC function that derives the key as bits from EC params\nfunc (keyParams ECDHKeyDeriveParams) DeriveBits(privateKey *CryptoKey, length int) ([]byte, error) {\n\tif err := privateKey.Validate(); err != nil {\n\t\treturn nil, NewError(InvalidAccessError, \"provided baseKey is not a valid CryptoKey: \"+err.Error())\n\t}\n\n\tif privateKey.Type != PrivateCryptoKeyType {\n\t\treturn nil, NewError(InvalidAccessError, fmt.Sprintf(\"provided baseKey is not a private key: %v\", privateKey))\n\t}\n\n\tif !privateKey.ContainsUsage(DeriveBitsCryptoKeyUsage) {\n\t\treturn nil, NewError(InvalidAccessError, \"provided baseKey does not contain the 'deriveBits' usage\")\n\t}\n\n\tif err := ensureKeysUseSameCurve(*privateKey, *keyParams.Public); err != nil {\n\t\treturn nil, NewError(InvalidAccessError, err.Error())\n\t}\n\n\tpk, ok := privateKey.handle.(*ecdh.PrivateKey)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, \"key is not a valid ECDH private key\")\n\t}\n\tpc, ok := keyParams.Public.handle.(*ecdh.PublicKey)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, \"key is not a valid ECDH public key\")\n\t}\n\n\tb, err := pk.ECDH(pc)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(b) < length/8 {\n\t\treturn nil, NewError(OperationError, \"length is too large\")\n\t}\n\n\treturn b[:length/8], nil\n}\n\n// The ECDSAParams represents the object that should be passed as the algorithm\n// parameter into `SubtleCrypto.Sign` or `SubtleCrypto.Verify“ when using the\n// ECDSA algorithm.\ntype ECDSAParams struct {\n\t// Name should be set to AlgorithmKindEcdsa.\n\tName AlgorithmIdentifier\n\n\t// Hash identifies the name of the digest algorithm to use.\n\t// You can use any of the following:\n\t//   * [Sha256]\n\t//   * [Sha384]\n\t//   * [Sha512]\n\tHash Algorithm\n}\n\nfunc newECDSAParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*ECDSAParams, error) {\n\thashValue, err := traverseObject(rt, params, \"hash\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get hash from algorithm parameter\")\n\t}\n\n\tnormalizedHash, err := normalizeAlgorithm(rt, hashValue, OperationIdentifierGenerateKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &ECDSAParams{\n\t\tName: normalized.Name,\n\t\tHash: normalizedHash,\n\t}, nil\n}\n\n// Sign .\nfunc (edsa *ECDSAParams) Sign(key CryptoKey, data []byte) ([]byte, error) {\n\tif key.Type != PrivateCryptoKeyType {\n\t\treturn nil, NewError(InvalidAccessError, \"key is not a valid ECDSA private key\")\n\t}\n\n\tk, ok := key.handle.(*ecdsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, \"key is not a valid ECDSA private key\")\n\t}\n\n\t// TODO: explicitly check if the hash algorithm is defined\n\thashFn, ok := getHashFn(edsa.Hash.Name)\n\tif !ok {\n\t\treturn nil, NewError(NotSupportedError, \"unsupported hash algorithm: \"+edsa.Hash.Name)\n\t}\n\n\thasher := hashFn()\n\thasher.Write(data)\n\n\tr, s, err := ecdsa.Sign(rand.Reader, k, hasher.Sum(nil))\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"unable to sign data: \"+err.Error())\n\t}\n\n\tbitSize := k.Curve.Params().BitSize\n\tn := (bitSize + 7) / 8\n\n\trBytes := ensureLength(r.Bytes(), n)\n\tsBytes := ensureLength(s.Bytes(), n)\n\n\treturn append(rBytes, sBytes...), nil\n}\n\n// Helper function to ensure the byte slice has length n\n// prepending it with zeros if necessary.\nfunc ensureLength(b []byte, n int) []byte {\n\tif len(b) == n {\n\t\treturn b\n\t}\n\tresult := make([]byte, n)\n\tcopy(result[n-len(b):], b)\n\treturn result\n}\n\n// Verify .\nfunc (edsa *ECDSAParams) Verify(key CryptoKey, signature []byte, data []byte) (bool, error) {\n\tif key.Type != PublicCryptoKeyType {\n\t\treturn false, NewError(InvalidAccessError, \"key is not a valid ECDSA public key\")\n\t}\n\n\tk, ok := key.handle.(*ecdsa.PublicKey)\n\tif !ok {\n\t\treturn false, NewError(InvalidAccessError, \"key is not a valid ECDSA public key\")\n\t}\n\n\thashFn, ok := getHashFn(edsa.Hash.Name)\n\tif !ok {\n\t\treturn false, NewError(NotSupportedError, \"unsupported hash algorithm: \"+edsa.Hash.Name)\n\t}\n\n\tbitSize := k.Curve.Params().BitSize\n\tn := (bitSize + 7) / 8\n\n\tif len(signature) != 2*n {\n\t\treturn false, nil\n\t}\n\n\thasher := hashFn()\n\thasher.Write(data)\n\n\tr := new(big.Int).SetBytes(signature[:n])\n\ts := new(big.Int).SetBytes(signature[n:])\n\n\treturn ecdsa.Verify(k, hasher.Sum(nil), r, s), nil\n}\n\nfunc convertECDHtoECDSAKey(k *ecdh.PrivateKey) (*ecdsa.PrivateKey, error) {\n\tpk, err := convertPublicECDHtoECDSA(k.PublicKey())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &ecdsa.PrivateKey{\n\t\tPublicKey: *pk,\n\t\tD:         new(big.Int).SetBytes(k.Bytes()),\n\t}, nil\n}\n\nfunc convertPublicECDHtoECDSA(k *ecdh.PublicKey) (*ecdsa.PublicKey, error) {\n\tvar crv elliptic.Curve\n\tswitch k.Curve() {\n\tcase ecdh.P256():\n\t\tcrv = elliptic.P256()\n\tcase ecdh.P384():\n\t\tcrv = elliptic.P384()\n\tcase ecdh.P521():\n\t\tcrv = elliptic.P521()\n\tdefault:\n\t\treturn nil, errors.New(\"curve not supported for converting to ECDSA key\")\n\t}\n\n\tx, y := elliptic.Unmarshal(crv, k.Bytes()) //nolint:staticcheck // we need to use the Unmarshal function\n\tif x == nil {\n\t\treturn nil, fmt.Errorf(\"unable to convert ECDH public key to ECDSA public key, curve: %s\", crv.Params().Name)\n\t}\n\n\treturn &ecdsa.PublicKey{\n\t\tCurve: crv,\n\t\tX:     x,\n\t\tY:     y,\n\t}, nil\n}\n\nfunc ensureKeysUseSameCurve(k1, k2 CryptoKey) error {\n\tecAlg1, ok1 := k1.Algorithm.(EcKeyAlgorithm)\n\tecAlg2, ok2 := k2.Algorithm.(EcKeyAlgorithm)\n\tif !ok1 || !ok2 {\n\t\treturn errors.New(\"keys are not valid elliptic curve keys\")\n\t}\n\n\tif ecAlg1.NamedCurve != ecAlg2.NamedCurve {\n\t\treturn errors.New(\"keys have different curves \" + string(ecAlg1.NamedCurve) + \" and \" + string(ecAlg2.NamedCurve))\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/encryption.go",
    "content": "package webcrypto\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// Encrypter is an interface for encrypting data.\ntype Encrypter interface {\n\tEncrypt(plaintext []byte, key CryptoKey) ([]byte, error)\n}\n\n// Decrypter is an interface for decrypting data.\ntype Decrypter interface {\n\tDecrypt(ciphertext []byte, key CryptoKey) ([]byte, error)\n}\n\n// EncryptDecrypter is an interface for encrypting and decrypting data.\ntype EncryptDecrypter interface {\n\tEncrypter\n\tDecrypter\n}\n\n// newEncryptDecrypter instantiates an EncryptDecrypter based on the provided\n// algorithm and parameters `sobek.Value`.\n//\n// The returned instance can be used to encrypt/decrypt data using the\n// corresponding algorithm.\nfunc newEncryptDecrypter(\n\trt *sobek.Runtime,\n\talgorithm Algorithm,\n\tparams sobek.Value,\n) (EncryptDecrypter, error) {\n\tvar ed EncryptDecrypter\n\tvar err error\n\n\tswitch algorithm.Name {\n\tcase AESCbc:\n\t\ted = new(AESCBCParams)\n\tcase AESCtr:\n\t\ted = new(AESCTRParams)\n\tcase AESGcm:\n\t\ted = new(AESGCMParams)\n\tcase RSAOaep:\n\t\ted = new(RSAOaepParams)\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, \"unsupported algorithm \"+algorithm.Name)\n\t}\n\n\tif err = rt.ExportTo(params, ed); err != nil {\n\t\tstructType := reflect.TypeOf(ed)\n\n\t\terrMsg := fmt.Sprintf(\"invalid algorithm parameters, unable to interpret as %q object\", structType.Name())\n\t\treturn nil, NewError(SyntaxError, errMsg)\n\t}\n\n\treturn ed, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/errors.go",
    "content": "package webcrypto\n\n// ErrorName is a type alias for the name of a WebCryptoError.\n//\n// Note that it is a type alias, and not a binding, so that it is\n// not interpreted as an object by sobek.\ntype ErrorName = string\n\nconst (\n\t// DataError represents the DataError error.\n\tDataError = \"DataError\"\n\n\t// ImplementationError represents the ImplementationError error.\n\t// It is thrown when the error is likely a bug in our implementation.\n\tImplementationError = \"ImplementationError\"\n\n\t// InvalidAccessError represents the InvalidAccessError error.\n\tInvalidAccessError = \"InvalidAccessError\"\n\n\t// NotSupportedError represents the NotSupportedError error.\n\tNotSupportedError ErrorName = \"NotSupportedError\"\n\n\t// OperationError represents the OperationError error.\n\tOperationError = \"OperationError\"\n\n\t// SyntaxError represents the SyntaxError error.\n\tSyntaxError = \"SyntaxError\"\n\n\t// TypeMismatchError represents the TypeMismatchError error.\n\tTypeMismatchError = \"TypeMismatchError\"\n\n\t// TypeError represents the TypeError error.\n\tTypeError = \"TypeError\"\n\n\t// QuotaExceededError is the error thrown if the byteLength of a typedArray\n\t// exceeds 65,536.\n\tQuotaExceededError = \"QuotaExceededError\"\n\n\t// NotImplemented means that we have not implemented the feature yet.\n\tNotImplemented = \"NotImplemented\"\n)\n\nconst (\n\terrMsgNotExpectedPublicKey  = \"given CryptoKey is not a public %s key, it's %T\"\n\terrMsgNotExpectedPrivateKey = \"given CryptoKey is not a private %s key, it's %T\"\n)\n\n// Error represents a custom error emitted by the\n// Web Crypto API.\ntype Error struct {\n\t// Name contains one of the strings associated with an error name.\n\tName string `js:\"name\"`\n\n\t// Message represents message or description associated with the given error name.\n\tMessage string `js:\"message\"`\n}\n\n// Error implements the `error` interface, so WebCryptoError are normal Go errors.\nfunc (e *Error) Error() string {\n\treturn e.Name + \": \" + e.Message\n}\n\n// NewError returns a new WebCryptoError with the given name and message.\nfunc NewError(name, message string) *Error {\n\treturn &Error{\n\t\tName:    name,\n\t\tMessage: message,\n\t}\n}\n\nvar _ error = (*Error)(nil)\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/hash.go",
    "content": "package webcrypto\n\nimport (\n\t\"crypto\"\n\t\"hash\"\n\t\"reflect\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n)\n\n// getHashFn returns the hash function associated with the given name.\n//\n// It returns a generator function, that can be used to create a new\n// hash.Hash instance.\nfunc getHashFn(name string) (func() hash.Hash, bool) {\n\tswitch name {\n\tcase SHA1:\n\t\treturn crypto.SHA1.New, true\n\tcase SHA256:\n\t\treturn crypto.SHA256.New, true\n\tcase SHA384:\n\t\treturn crypto.SHA384.New, true\n\tcase SHA512:\n\t\treturn crypto.SHA512.New, true\n\tdefault:\n\t\treturn nil, false\n\t}\n}\n\n// hasHash an internal interface that helps us to identify\n// if a given object has a hash method.\ntype hasHash interface {\n\thash() string\n}\n\nfunc mapHashFn(hash AlgorithmIdentifier) (crypto.Hash, error) {\n\tunknownHash := crypto.Hash(0)\n\n\tswitch hash {\n\tcase SHA1:\n\t\treturn crypto.SHA1, nil\n\tcase SHA256:\n\t\treturn crypto.SHA256, nil\n\tcase SHA384:\n\t\treturn crypto.SHA384, nil\n\tcase SHA512:\n\t\treturn crypto.SHA512, nil\n\tdefault:\n\t\treturn unknownHash, NewError(NotSupportedError, \"hash algorithm is not supported \"+hash)\n\t}\n}\n\n// extractHash tries to extract the hash from the given parameters.\nfunc extractHash(rt *sobek.Runtime, params sobek.Value) (Algorithm, error) {\n\tv, err := traverseObject(rt, params, \"hash\")\n\tif err != nil {\n\t\treturn Algorithm{}, NewError(SyntaxError, \"could not get hash from algorithm parameter\")\n\t}\n\n\tif common.IsNullish(v) {\n\t\treturn Algorithm{}, NewError(TypeError, \"hash is null or undefined\")\n\t}\n\n\tvar hashName string\n\tif v.ExportType().Kind() == reflect.String {\n\t\t// try string first\n\t\tif !isHashAlgorithm(v.ToString().String()) {\n\t\t\treturn Algorithm{}, NewError(NotSupportedError, \"hash algorithm is not supported \"+v.ToString().String())\n\t\t}\n\n\t\thashName = v.ToString().String()\n\t} else {\n\t\t// otherwise, it should be an object\n\t\tname := v.ToObject(rt).Get(\"name\")\n\t\tif common.IsNullish(name) {\n\t\t\treturn Algorithm{}, NewError(TypeError, \"hash name is null or undefined\")\n\t\t}\n\n\t\thashName = name.ToString().String()\n\t}\n\n\tif !isHashAlgorithm(hashName) {\n\t\treturn Algorithm{}, NewError(NotSupportedError, \"hash algorithm is not supported \"+hashName)\n\t}\n\n\treturn Algorithm{Name: hashName}, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/hmac.go",
    "content": "package webcrypto\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/rand\"\n\t\"crypto/sha1\" //nolint:gosec\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\t\"fmt\"\n\t\"hash\"\n\n\t\"github.com/grafana/sobek\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// HMACKeyGenParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.GenerateKey`, when generating an HMAC key.\ntype HMACKeyGenParams struct {\n\tAlgorithm\n\n\t// Hash represents the name of the digest function to use. You can\n\t// use any of the following: [Sha256], [Sha384],\n\t// or [Sha512].\n\tHash Algorithm `js:\"hash\"`\n\n\t// Length holds (a Number) the length of the key, in bits.\n\t// If this is omitted, the length of the key is equal to the block size\n\t// of the hash function you have chosen.\n\t// Unless you have a good reason to use a different length, omit\n\t// use the default.\n\tLength null.Int `js:\"length\"`\n}\n\nfunc (hkgp HMACKeyGenParams) hash() string {\n\treturn hkgp.Hash.Name\n}\n\n// newHMACKeyGenParams creates a new HMACKeyGenParams object, from the normalized\n// algorithm, and the params parameters passed by the user.\n//\n// It handles the logic of extracting the hash algorithm from the params object,\n// and normalizing it. It also handles the logic of extracting the length\n// attribute from the params object, and setting it to the default value if it's\n// not present as described in the hmac `generateKey` [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#hmac-operations\nfunc newHMACKeyGenParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*HMACKeyGenParams, error) {\n\t// The specification doesn't explicitly tell us what to do if the\n\t// hash field is not present, but we assume it's a mandatory field\n\t// and throw an error if it's not present.\n\thashValue, err := traverseObject(rt, params, \"hash\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get hash from algorithm parameter\")\n\t}\n\n\t// Although the specification doesn't explicitly ask us to do so, we\n\t// normalize the hash algorithm here, as it shares the same definition\n\t// as the AlgorithmIdentifier type, and we'll need it later on.\n\t//\n\t// Note @oleiade: The specification seems to assume that the normalization\n\t// algorithm will normalize the existing Algorithm fields, and leave\n\t// the rest untouched. As we are in the context of a statically typed\n\t// language, we can't do that, so we need to normalize the hash\n\t// algorithm here.\n\tnormalizedHash, err := normalizeAlgorithm(rt, hashValue, OperationIdentifierGenerateKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// As the length attribute is optional and as the key generation process\n\t// differentiates unset from zero-values, we need to handle the case\n\t// where the length attribute is not present in the params object.\n\tvar length null.Int\n\talgorithmLengthValue, err := traverseObject(rt, params, \"length\")\n\tif err == nil {\n\t\tlength = null.IntFrom(algorithmLengthValue.ToInteger())\n\t}\n\n\treturn &HMACKeyGenParams{\n\t\tAlgorithm: normalized,\n\t\tHash:      normalizedHash,\n\t\tLength:    length,\n\t}, nil\n}\n\n// GenerateKey generates a new HMAC key.\nfunc (hkgp *HMACKeyGenParams) GenerateKey(\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (CryptoKeyGenerationResult, error) {\n\t// 1.\n\tfor _, usage := range keyUsages {\n\t\tswitch usage {\n\t\tcase SignCryptoKeyUsage, VerifyCryptoKeyUsage:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage: \"+usage)\n\t\t}\n\t}\n\n\t// 2.\n\t// We extract the length attribute from the algorithm object, as it's not\n\t// part of the normalized algorithm, and as accessing the runtime from the\n\t// callback below could lead to a race condition.\n\tif !hkgp.Length.Valid {\n\t\tvar length bitLength\n\t\tswitch hkgp.Hash.Name {\n\t\tcase SHA1:\n\t\t\tlength = byteLength(sha1.BlockSize).asBitLength()\n\t\tcase SHA256:\n\t\t\tlength = byteLength(sha256.BlockSize).asBitLength()\n\t\tcase SHA384:\n\t\t\tlength = byteLength(sha512.BlockSize).asBitLength()\n\t\tcase SHA512:\n\t\t\tlength = byteLength(sha512.BlockSize).asBitLength()\n\t\tdefault:\n\t\t\t// This case should never happen, as the normalization algorithm\n\t\t\t// should have thrown an error if the hash algorithm is invalid.\n\t\t\treturn nil, NewError(ImplementationError, \"invalid hash algorithm: \"+hkgp.Hash.Name)\n\t\t}\n\n\t\thkgp.Length = null.IntFrom(int64(length))\n\t}\n\n\tif hkgp.Length.Int64 == 0 {\n\t\treturn nil, NewError(OperationError, \"algorithm's length cannot be 0\")\n\t}\n\n\t// 3.\n\trandomKey := make([]byte, bitLength(hkgp.Length.Int64).asByteLength())\n\tif _, err := rand.Read(randomKey); err != nil {\n\t\t// 4.\n\t\treturn nil, NewError(OperationError, \"failed to generate random key; reason:  \"+err.Error())\n\t}\n\n\t// 5.\n\tkey := &CryptoKey{Type: SecretCryptoKeyType, handle: randomKey}\n\n\t// 6.\n\talgorithm := &HMACKeyAlgorithm{}\n\n\t// 7.\n\talgorithm.Name = HMAC\n\talgorithm.Length = hkgp.Length.Int64\n\n\t// 8.\n\thash := KeyAlgorithm{}\n\n\t// 9.\n\thash.Name = hkgp.Hash.Name\n\n\t// 10.\n\talgorithm.Hash = hash\n\n\t// 11. 12. 13.\n\tkey.Algorithm = algorithm\n\tkey.Extractable = extractable\n\tkey.Usages = keyUsages\n\n\treturn key, nil\n}\n\n// Ensure that HMACKeyGenParams implements the KeyGenerator interface.\nvar _ KeyGenerator = &HMACKeyGenParams{}\n\n// HMACKeyAlgorithm represents the algorithm of an HMAC key.\ntype HMACKeyAlgorithm struct {\n\tKeyAlgorithm\n\n\t// Hash represents the inner hash function to use.\n\tHash KeyAlgorithm `js:\"hash\"`\n\n\t// Length represents he length (in bits) of the key.\n\tLength int64 `js:\"length\"`\n}\n\nfunc (hka HMACKeyAlgorithm) hash() string {\n\treturn hka.Hash.Name\n}\n\nfunc exportHMACKey(ck *CryptoKey, format KeyFormat) (any, error) {\n\t// 1.\n\tif ck.handle == nil {\n\t\treturn nil, NewError(OperationError, \"key data is not accessible\")\n\t}\n\n\t// 2.\n\tbits, ok := ck.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(OperationError, \"key underlying data is not of the correct type\")\n\t}\n\n\t// 4.\n\tswitch format {\n\tcase RawKeyFormat:\n\t\treturn bits, nil\n\tcase JwkKeyFormat:\n\t\tm, err := exportSymmetricJWK(ck)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(ImplementationError, err.Error())\n\t\t}\n\n\t\treturn m, nil\n\tdefault:\n\t\t// FIXME: note that we do not support JWK format, yet #37.\n\t\treturn nil, NewError(NotSupportedError, \"unsupported key format \"+format)\n\t}\n}\n\n// HashFn returns the hash function to use for the HMAC key.\nfunc (hka *HMACKeyAlgorithm) HashFn() (func() hash.Hash, error) {\n\thashFn, ok := getHashFn(hka.Hash.Name)\n\tif !ok {\n\t\treturn nil, NewError(NotSupportedError, fmt.Sprintf(\"unsupported key hash algorithm %q\", hka.Hash.Name))\n\t}\n\n\treturn hashFn, nil\n}\n\n// HMACImportParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.GenerateKey`, when generating an HMAC key.\ntype HMACImportParams struct {\n\tAlgorithm\n\n\t// Hash represents the name of the digest function to use. You can\n\t// use any of the following: [Sha256], [Sha384],\n\t// or [Sha512].\n\tHash Algorithm `js:\"hash\"`\n\n\t// Length holds (a Number) the length of the key, in bits.\n\t// If this is omitted, the length of the key is equal to the block size\n\t// of the hash function you have chosen.\n\t// Unless you have a good reason to use a different length, omit\n\t// use the default.\n\tLength null.Int `js:\"length\"`\n}\n\nvar _ hasHash = (*HMACImportParams)(nil)\n\nfunc (hip HMACImportParams) hash() string {\n\treturn hip.Hash.Name\n}\n\n// newHMACImportParams creates a new HMACImportParams object from the given\n// algorithm and params objects.\nfunc newHMACImportParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*HMACImportParams, error) {\n\t// The specification doesn't explicitly tell us what to do if the\n\t// hash field is not present, but we assume it's a mandatory field\n\t// and throw an error if it's not present.\n\thashValue, err := traverseObject(rt, params, \"hash\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get hash from algorithm parameter\")\n\t}\n\n\t// Although the specification doesn't explicitly ask us to do so, we\n\t// normalize the hash algorithm here, as it shares the same definition\n\t// as the AlgorithmIdentifier type, and we'll need it later on.\n\t//\n\t// Note @oleiade: The specification seems to assume that the normalization\n\t// algorithm will normalize the existing Algorithm fields, and leave\n\t// the rest untouched. As we are in the context of a statically typed\n\t// language, we can't do that, so we need to normalize the hash\n\t// algorithm here.\n\tnormalizedHash, err := normalizeAlgorithm(rt, hashValue, OperationIdentifierGenerateKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// As the length attribute is optional and as the key generation process\n\t// differentiates unset from zero-values, we need to handle the case\n\t// where the length attribute is not present in the params object.\n\tvar length null.Int\n\talgorithmLengthValue, err := traverseObject(rt, params, \"length\")\n\tif err == nil {\n\t\tlength = null.IntFrom(algorithmLengthValue.ToInteger())\n\t}\n\n\treturn &HMACImportParams{\n\t\tAlgorithm: normalized,\n\t\tHash:      normalizedHash,\n\t\tLength:    length,\n\t}, nil\n}\n\n// ImportKey imports a key from raw key data. It implements the KeyImporter interface.\nfunc (hip *HMACImportParams) ImportKey(\n\tformat KeyFormat,\n\tkeyData []byte,\n\t_ bool,\n\tkeyUsages []CryptoKeyUsage,\n) (*CryptoKey, error) {\n\t// 2.\n\tfor _, usage := range keyUsages {\n\t\tswitch usage {\n\t\tcase SignCryptoKeyUsage, VerifyCryptoKeyUsage:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage: \"+usage)\n\t\t}\n\t}\n\n\t// 3.\n\tif format != RawKeyFormat && format != JwkKeyFormat {\n\t\treturn nil, NewError(NotSupportedError, \"unsupported key format \"+format)\n\t}\n\n\thash := KeyAlgorithm{Algorithm{Name: hip.Hash.Name}}\n\n\t// 4.\n\tif format == JwkKeyFormat {\n\t\tvar err error\n\t\tkeyData, err = extractSymmetricJWK(keyData)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(DataError, err.Error())\n\t\t}\n\t}\n\n\t// 5. 6.\n\tlength := byteLength(len(keyData)).asBitLength()\n\tif length == 0 {\n\t\treturn nil, NewError(DataError, \"key length cannot be 0\")\n\t}\n\n\t// 7.\n\tif hip.Length.Valid && hip.Length.Int64 != int64(length) {\n\t\treturn nil, NewError(DataError, \"key length cannot be different from the length of the imported data\")\n\t}\n\n\t// 8.\n\tkey := CryptoKey{\n\t\tType:   SecretCryptoKeyType,\n\t\thandle: keyData[:length.asByteLength()],\n\t}\n\n\t// 9.\n\talgorithm := HMACKeyAlgorithm{}\n\n\t// 10.\n\talgorithm.Name = HMAC\n\n\t// 11.\n\talgorithm.Length = int64(length)\n\n\t// 12.\n\talgorithm.Hash = hash\n\n\t// 13.\n\tkey.Algorithm = algorithm\n\n\treturn &key, nil\n}\n\n// Ensure that HMACImportParams implements the KeyImporter interface.\nvar _ KeyImporter = &HMACImportParams{}\n\ntype hmacSignerVerifier struct{}\n\n// Sign .\nfunc (hmacSignerVerifier) Sign(key CryptoKey, data []byte) ([]byte, error) {\n\tkeyAlgorithm, ok := key.Algorithm.(hasHash)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, \"key algorithm does not describe a HMAC key\")\n\t}\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, \"key handle is of incorrect type\")\n\t}\n\n\thashFn, ok := getHashFn(keyAlgorithm.hash())\n\tif !ok {\n\t\treturn nil, NewError(NotSupportedError, \"unsupported hash algorithm \"+keyAlgorithm.hash())\n\t}\n\n\thasher := hmac.New(hashFn, keyHandle)\n\thasher.Write(data)\n\n\treturn hasher.Sum(nil), nil\n}\n\n// Verify .\nfunc (hmacSignerVerifier) Verify(key CryptoKey, signature, data []byte) (bool, error) {\n\tkeyAlgorithm, ok := key.Algorithm.(hasHash)\n\tif !ok {\n\t\treturn false, NewError(InvalidAccessError, \"key algorithm does not describe a HMAC key\")\n\t}\n\n\tkeyHandle, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn false, NewError(InvalidAccessError, \"key handle is of incorrect type\")\n\t}\n\n\thashFn, ok := getHashFn(keyAlgorithm.hash())\n\tif !ok {\n\t\treturn false, NewError(InvalidAccessError, \"key handle is of incorrect type\")\n\t}\n\n\thasher := hmac.New(hashFn, keyHandle)\n\thasher.Write(data)\n\n\treturn hmac.Equal(signature, hasher.Sum(nil)), nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/jwk.go",
    "content": "package webcrypto\n\nimport (\n\t\"crypto/ecdh\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rsa\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n)\n\nconst (\n\t// JWKECKeyType represents the elliptic curve key type.\n\tJWKECKeyType = \"EC\"\n\n\t// JWKOctKeyType represents the symmetric key type.\n\tJWKOctKeyType = \"oct\"\n)\n\n// JsonWebKey represents a JSON Web Key (JsonWebKey) key.\ntype JsonWebKey map[string]any //nolint:revive // we name this type JsonWebKey to match the spec\n\n// Set sets a key-value pair in the JWK.\nfunc (jwk *JsonWebKey) Set(key string, value any) {\n\t(*jwk)[key] = value\n}\n\n// symmetricJWK represents a symmetric JWK key.\n// It is used to unmarshal symmetric keys from JWK format.\ntype symmetricJWK struct {\n\tKty string `json:\"kty\"`\n\tK   string `json:\"k\"`\n}\n\nfunc (jwk *symmetricJWK) validate() error {\n\tif jwk.Kty != JWKOctKeyType {\n\t\treturn fmt.Errorf(\"invalid key type: %s\", jwk.Kty)\n\t}\n\n\tif jwk.K == \"\" {\n\t\treturn errors.New(\"key (k) is required\")\n\t}\n\n\treturn nil\n}\n\n// extractSymmetricJWK extracts the symmetric key from a given JWK key (JSON data).\nfunc extractSymmetricJWK(jsonKeyData []byte) ([]byte, error) {\n\tsk := symmetricJWK{}\n\tif err := json.Unmarshal(jsonKeyData, &sk); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse symmetric JWK: %w\", err)\n\t}\n\n\tif err := sk.validate(); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid symmetric JWK: %w\", err)\n\t}\n\n\tskBytes, err := base64URLDecode(sk.K)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode symmetric key: %w\", err)\n\t}\n\n\treturn skBytes, nil\n}\n\n// exportSymmetricJWK exports a symmetric key as a map of JWK key parameters.\nfunc exportSymmetricJWK(key *CryptoKey) (*JsonWebKey, error) {\n\trawKey, ok := key.handle.([]byte)\n\tif !ok {\n\t\treturn nil, errors.New(\"key's handle isn't a byte slice\")\n\t}\n\n\t// wrap result into the object that is expected to be returned\n\texported := &JsonWebKey{}\n\n\texported.Set(\"k\", base64URLEncode(rawKey))\n\texported.Set(\"kty\", JWKOctKeyType)\n\texported.Set(\"ext\", key.Extractable)\n\texported.Set(\"key_ops\", key.Usages)\n\n\talgV, err := extractAlg(key.Algorithm, len(rawKey))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to extract algorithm: %w\", err)\n\t}\n\texported.Set(\"alg\", algV)\n\n\treturn exported, nil\n}\n\nfunc extractAlg(inAlg any, keyLen int) (string, error) {\n\tswitch alg := inAlg.(type) {\n\tcase hasHash:\n\t\tv := alg.hash()\n\t\tif len(v) < 4 {\n\t\t\treturn \"\", errors.New(\"length of hash algorithm is less than 4: \" + v)\n\t\t}\n\t\treturn \"HS\" + v[4:], nil\n\tcase hasAlg:\n\t\tv := alg.alg()\n\t\tif len(v) < 4 {\n\t\t\treturn \"\", errors.New(\"length of named algorithm is less than 4: \" + v)\n\t\t}\n\n\t\treturn fmt.Sprintf(\"A%d%s\", (8 * keyLen), v[4:]), nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unsupported algorithm: %v\", inAlg)\n\t}\n}\n\n// ecJWK represents an EC JWK key.\n// It is used to unmarshal ECDSA and ECDH keys to and from JWK format.\ntype ecJWK struct {\n\t// Key type\n\tKty string `json:\"kty\"`\n\t// Canonical Curve\n\tCrv string `json:\"crv\"`\n\t// X coordinate\n\tX string `json:\"x\"`\n\t// Y coordinate\n\tY string `json:\"y\"`\n\t// Private scalar\n\tD string `json:\"d\"`\n}\n\nfunc (jwk *ecJWK) validate() error {\n\tif jwk.Kty != JWKECKeyType {\n\t\treturn fmt.Errorf(\"invalid key type: %s\", jwk.Kty)\n\t}\n\n\tif jwk.Crv == \"\" {\n\t\treturn errors.New(\"curve is required\")\n\t}\n\n\tif jwk.X == \"\" {\n\t\treturn errors.New(\"coordinate X is required\")\n\t}\n\n\tif jwk.Y == \"\" {\n\t\treturn errors.New(\"coordinate Y is required\")\n\t}\n\n\treturn nil\n}\n\n// encodeCurveBigInt encodes the private scalar D of an ECDSA key with padding.\nfunc encodeCurveBigInt(data *big.Int, curveBits int) string {\n\t// Determine the expected byte length for the curve\n\tbyteLength := curveBits / 8\n\t// Add one more byte if the bits are not a multiple of 8\n\tif curveBits%8 != 0 {\n\t\tbyteLength++\n\t}\n\n\tdBytes := data.Bytes()\n\tdPadded := padLeft(dBytes, byteLength) // Pad if necessary\n\n\treturn base64URLEncode(dPadded)\n}\n\n// padLeft pads the byte slice with zeros to the left to ensure it has a specific length.\nfunc padLeft(bytes []byte, size int) []byte {\n\tpadding := make([]byte, size-len(bytes))\n\treturn append(padding, bytes...) //nolint:makezero // we need to pad with zeros\n}\n\nfunc exportECJWK(key *CryptoKey) (any, error) {\n\texported := &JsonWebKey{}\n\texported.Set(\"kty\", JWKECKeyType)\n\n\tvar x, y, d *big.Int\n\tvar curveParams *elliptic.CurveParams\n\n\tswitch k := key.handle.(type) {\n\tcase *ecdsa.PrivateKey:\n\t\tx = k.X\n\t\ty = k.Y\n\t\td = k.D\n\t\tcurveParams = k.Params()\n\tcase *ecdsa.PublicKey:\n\t\tx = k.X\n\t\ty = k.Y\n\t\tcurveParams = k.Params()\n\tcase *ecdh.PrivateKey:\n\t\tecdsaKey, err := convertECDHtoECDSAKey(k)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to convert ECDH key to ECDSA key: %w\", err)\n\t\t}\n\n\t\tx = ecdsaKey.X\n\t\ty = ecdsaKey.Y\n\t\td = ecdsaKey.D\n\t\tcurveParams = ecdsaKey.Params()\n\tcase *ecdh.PublicKey:\n\t\tecdsaKey, err := convertPublicECDHtoECDSA(k)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to convert ECDH key to ECDSA key: %w\", err)\n\t\t}\n\n\t\tx = ecdsaKey.X\n\t\ty = ecdsaKey.Y\n\t\tcurveParams = ecdsaKey.Params()\n\tdefault:\n\t\treturn nil, errors.New(\"key's handle isn't an ECDSA/ECDH public/private key\")\n\t}\n\n\texported.Set(\"crv\", curveParams.Name)\n\tcurveBits := curveParams.BitSize\n\n\texported.Set(\"x\", base64URLEncode(x.Bytes()))\n\texported.Set(\"y\", base64URLEncode(y.Bytes()))\n\n\tif d != nil {\n\t\texported.Set(\"d\", encodeCurveBigInt(d, curveBits))\n\t}\n\n\treturn exported, nil\n}\n\nfunc importECDSAJWK(_ EllipticCurveKind, jsonKeyData []byte) (any, CryptoKeyType, error) {\n\tvar jwkKey ecJWK\n\tif err := json.Unmarshal(jsonKeyData, &jwkKey); err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to parse input as EC JWK key: %w\", err)\n\t}\n\n\tif err := jwkKey.validate(); err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"invalid EC JWK key: %w\", err)\n\t}\n\n\tcrv, err := pickEllipticCurve(jwkKey.Crv)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to parse elliptic curve: %w\", err)\n\t}\n\n\tx, err := base64URLDecode(jwkKey.X)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to decode X coordinate: %w\", err)\n\t}\n\n\ty, err := base64URLDecode(jwkKey.Y)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to decode Y coordinate: %w\", err)\n\t}\n\n\tpk := &ecdsa.PublicKey{\n\t\tCurve: crv,\n\t\tX:     new(big.Int).SetBytes(x),\n\t\tY:     new(big.Int).SetBytes(y),\n\t}\n\n\t// if the key is a public key, return it\n\tif jwkKey.D == \"\" {\n\t\treturn pk, PublicCryptoKeyType, nil\n\t}\n\n\td, err := base64URLDecode(jwkKey.D)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to decode D: %w\", err)\n\t}\n\n\treturn &ecdsa.PrivateKey{\n\t\tPublicKey: *pk,\n\t\tD:         new(big.Int).SetBytes(d),\n\t}, PrivateCryptoKeyType, nil\n}\n\nfunc importECDHJWK(_ EllipticCurveKind, jsonKeyData []byte) (any, CryptoKeyType, error) {\n\t// first we do try to parse the key as ECDSA key\n\tkey, _, err := importECDSAJWK(EllipticCurveKindP256, jsonKeyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to parse input as ECDH key: %w\", err)\n\t}\n\n\tswitch key := key.(type) {\n\tcase *ecdsa.PrivateKey:\n\t\tecdhKey, err := key.ECDH()\n\t\tif err != nil {\n\t\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to convert ECDSA key to ECDH key: %w\", err)\n\t\t}\n\n\t\treturn ecdhKey, PrivateCryptoKeyType, nil\n\tcase *ecdsa.PublicKey:\n\t\tecdhKey, err := key.ECDH()\n\t\tif err != nil {\n\t\t\treturn nil, UnknownCryptoKeyType, fmt.Errorf(\"failed to convert ECDSA key to ECDH key: %w\", err)\n\t\t}\n\n\t\treturn ecdhKey, PublicCryptoKeyType, nil\n\tdefault:\n\t\treturn nil, UnknownCryptoKeyType, errors.New(\"input isn't a valid ECDH key\")\n\t}\n}\n\ntype rsaJWK struct {\n\tKty string `json:\"kty\"`          // Key Type\n\tN   string `json:\"n\"`            // Modulus\n\tE   string `json:\"e\"`            // Exponent\n\tD   string `json:\"d,omitempty\"`  // Private exponent\n\tP   string `json:\"p,omitempty\"`  // First prime factor\n\tQ   string `json:\"q,omitempty\"`  // Second prime factor\n\tDp  string `json:\"dp,omitempty\"` // Exponent1\n\tDq  string `json:\"dq,omitempty\"` // Exponent2\n\tQi  string `json:\"qi,omitempty\"` // Coefficient\n}\n\nfunc (jwk *rsaJWK) validate() error {\n\tif jwk.Kty != \"RSA\" {\n\t\treturn fmt.Errorf(\"invalid key type: %s\", jwk.Kty)\n\t}\n\n\tif jwk.N == \"\" {\n\t\treturn errors.New(\"modulus (n) is required\")\n\t}\n\n\tif jwk.E == \"\" {\n\t\treturn errors.New(\"exponent (e) is required\")\n\t}\n\n\t// TODO: consider validating the other fields in future\n\treturn nil\n}\n\nfunc importRSAJWK(jsonKeyData []byte) (any, CryptoKeyType, int, error) {\n\tvar jwk rsaJWK\n\tif err := json.Unmarshal(jsonKeyData, &jwk); err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to parse input as RSA JWK key: %w\", err)\n\t}\n\n\tif err := jwk.validate(); err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"invalid RSA JWK key: %w\", err)\n\t}\n\n\t// decode the various key components\n\tnBytes, err := base64URLDecode(jwk.N)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode modulus: %w\", err)\n\t}\n\teBytes, err := base64URLDecode(jwk.E)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode exponent: %w\", err)\n\t}\n\n\t// convert exponent to an integer\n\teInt := new(big.Int).SetBytes(eBytes).Int64()\n\tpubKey := rsa.PublicKey{\n\t\tN: new(big.Int).SetBytes(nBytes),\n\t\tE: int(eInt),\n\t}\n\n\t// if the private exponent is missing, return the public key\n\tif jwk.D == \"\" {\n\t\treturn pubKey, PublicCryptoKeyType, pubKey.N.BitLen(), nil\n\t}\n\n\tdBytes, err := base64URLDecode(jwk.D)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode private exponent: %w\", err)\n\t}\n\tpBytes, err := base64URLDecode(jwk.P)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode first prime factor: %w\", err)\n\t}\n\tqBytes, err := base64URLDecode(jwk.Q)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode second prime factor: %w\", err)\n\t}\n\tdpBytes, err := base64URLDecode(jwk.Dp)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode first exponent: %w\", err)\n\t}\n\tdqBytes, err := base64URLDecode(jwk.Dq)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode second exponent: %w\", err)\n\t}\n\tqiBytes, err := base64URLDecode(jwk.Qi)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to decode coefficient: %w\", err)\n\t}\n\n\tprivKey := &rsa.PrivateKey{\n\t\tPublicKey: pubKey,\n\t\tD:         new(big.Int).SetBytes(dBytes),\n\t\tPrimes: []*big.Int{\n\t\t\tnew(big.Int).SetBytes(pBytes),\n\t\t\tnew(big.Int).SetBytes(qBytes),\n\t\t},\n\t\tPrecomputed: rsa.PrecomputedValues{\n\t\t\tDp:   new(big.Int).SetBytes(dpBytes),\n\t\t\tDq:   new(big.Int).SetBytes(dqBytes),\n\t\t\tQinv: new(big.Int).SetBytes(qiBytes),\n\t\t},\n\t}\n\n\terr = privKey.Validate()\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, fmt.Errorf(\"failed to validate private key: %w\", err)\n\t}\n\n\treturn privKey, PrivateCryptoKeyType, pubKey.N.BitLen(), nil\n}\n\nfunc exportRSAJWK(key *CryptoKey) (any, error) {\n\texported := &JsonWebKey{}\n\texported.Set(\"kty\", \"RSA\")\n\n\tswitch rsaKey := key.handle.(type) {\n\tcase *rsa.PrivateKey:\n\t\texported.Set(\"n\", base64URLEncode(rsaKey.N.Bytes()))\n\t\texported.Set(\"e\", base64URLEncode(big.NewInt(int64(rsaKey.E)).Bytes()))\n\t\texported.Set(\"d\", base64URLEncode(rsaKey.D.Bytes()))\n\t\texported.Set(\"p\", base64URLEncode(rsaKey.Primes[0].Bytes()))\n\t\texported.Set(\"q\", base64URLEncode(rsaKey.Primes[1].Bytes()))\n\t\texported.Set(\"dp\", base64URLEncode(rsaKey.Precomputed.Dp.Bytes()))\n\t\texported.Set(\"dq\", base64URLEncode(rsaKey.Precomputed.Dq.Bytes()))\n\t\texported.Set(\"qi\", base64URLEncode(rsaKey.Precomputed.Qinv.Bytes()))\n\tcase *rsa.PublicKey:\n\t\texported.Set(\"n\", base64URLEncode(rsaKey.N.Bytes()))\n\t\texported.Set(\"e\", base64URLEncode(big.NewInt(int64(rsaKey.E)).Bytes()))\n\tcase rsa.PublicKey:\n\t\texported.Set(\"n\", base64URLEncode(rsaKey.N.Bytes()))\n\t\texported.Set(\"e\", base64URLEncode(big.NewInt(int64(rsaKey.E)).Bytes()))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"key's handle isn't an RSA public/private key, got: %T\", key.handle)\n\t}\n\n\treturn exported, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/key.go",
    "content": "package webcrypto\n\nimport (\n\t\"errors\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// CryptoKeyGenerationResult represents the result of a key generation operation.\ntype CryptoKeyGenerationResult interface {\n\t// IsKeyPair returns true if the result is a key pair, false otherwise.\n\tIsKeyPair() bool\n\n\t// ResolveCryptoKeyPair returns the underlying CryptoKeyPair, if the result is a key pair, error otherwise.\n\tResolveCryptoKeyPair() (*CryptoKeyPair, error)\n\n\t// ResolveCryptoKey returns the underlying CryptoKey, if the result is a key, error otherwise.\n\tResolveCryptoKey() (*CryptoKey, error)\n}\n\n// CryptoKeyPair represents a key pair for an asymmetric cryptography algorithm, also known as\n// a public-key algorithm.\n//\n// The Private, and Public generic type parameters define the underlying type holding the private,\n// and public key, respectively.\ntype CryptoKeyPair struct {\n\t// PrivateKey holds the private key. For encryption and decryption algorithms,\n\t// this key is used to decrypt. For signing and verification algorithms it is used to sign.\n\tPrivateKey *CryptoKey `js:\"privateKey\"`\n\n\t// PublicKey holds the public key. For encryption and decryption algorithms,\n\t// this key is used to encrypt. For signing and verification algorithms it is used to verify.\n\tPublicKey *CryptoKey `js:\"publicKey\"`\n}\n\n// IsKeyPair .\nfunc (ckp *CryptoKeyPair) IsKeyPair() bool {\n\treturn true\n}\n\n// ResolveCryptoKeyPair returns the underlying CryptoKeyPair.\nfunc (ckp *CryptoKeyPair) ResolveCryptoKeyPair() (*CryptoKeyPair, error) {\n\treturn ckp, nil\n}\n\n// ResolveCryptoKey returns an error since the underlying type is not a CryptoKey.\nfunc (ckp *CryptoKeyPair) ResolveCryptoKey() (*CryptoKey, error) {\n\treturn nil, errors.New(\"not a CryptoKey\")\n}\n\nvar _ CryptoKeyGenerationResult = &CryptoKeyPair{}\n\n// CryptoKey represents a cryptographic key obtained from one of the SubtleCrypto\n// methods `SubtleCrypto.generateKey`, `SubtleCrypto.DeriveKey`, `SubtleCrypto.ImportKey`,\n// or `SubtleCrypto.UnwrapKey`.\ntype CryptoKey struct {\n\t// Type holds the type of the key.\n\tType CryptoKeyType `js:\"type\"`\n\n\t// Extractable indicates whether or not the key may be extracted\n\t// using `SubtleCrypto.ExportKey` or `SubtleCrypto.WrapKey`.\n\t//\n\t// If the value is `true`, the key may be extracted.\n\t// If the value is `false`, the key may not be extracted, and\n\t// `SubtleCrypto.exportKey` and `SubtleCrypto.wrapKey` will fail.\n\tExtractable bool `js:\"extractable\"`\n\n\t// By the time we access the Algorithm field of CryptoKey, we\n\t// generally already know what type of algorithm it is, and are\n\t// really looking to access the specific attributes of that algorithm.\n\t// Thus, the generic parameter type helps us manipulate the\n\t// `CryptoKey` type without having to cast the `Algorithm` field.\n\tAlgorithm any `js:\"algorithm\"`\n\n\t// Usages holds the key usages for which this key can be used.\n\tUsages []CryptoKeyUsage `js:\"usages\"`\n\n\t// handle is an internal slot, holding the underlying key data.\n\t// See [specification](https://www.w3.org/TR/WebCryptoAPI/#dfnReturnLink-0).\n\thandle any\n}\n\n// IsKeyPair .\nfunc (ck *CryptoKey) IsKeyPair() bool {\n\treturn false\n}\n\n// ResolveCryptoKeyPair returns an error since the underlying type is not a CryptoKeyPair.\nfunc (ck *CryptoKey) ResolveCryptoKeyPair() (*CryptoKeyPair, error) {\n\treturn nil, errors.New(\"not a Crypto Key Pair\")\n}\n\n// ResolveCryptoKey returns the underlying CryptoKey.\nfunc (ck *CryptoKey) ResolveCryptoKey() (*CryptoKey, error) {\n\treturn ck, nil\n}\n\n// Validate checks if the key is valid.\nfunc (ck *CryptoKey) Validate() error {\n\tif ck.Type != PrivateCryptoKeyType && ck.Type != PublicCryptoKeyType && ck.Type != SecretCryptoKeyType {\n\t\treturn errors.New(\"invalid key type\")\n\t}\n\n\treturn nil\n}\n\nvar _ CryptoKeyGenerationResult = &CryptoKey{}\n\n// ContainsUsage returns true if the key contains the specified usage.\nfunc (ck *CryptoKey) ContainsUsage(usage CryptoKeyUsage) bool {\n\treturn slices.Contains(ck.Usages, usage)\n}\n\n// CryptoKeyType represents the type of a key.\n//\n// Note that it is defined as an alias of string, instead of a dedicated type,\n// to ensure it is handled as a string by sobek.\ntype CryptoKeyType = string\n\nconst (\n\t// UnknownCryptoKeyType that we set when we don't know the type of the key.\n\tUnknownCryptoKeyType CryptoKeyType = \"unknown\"\n\n\t// SecretCryptoKeyType carries the information that a key is a secret key\n\t// to use with a symmetric algorithm.\n\tSecretCryptoKeyType CryptoKeyType = \"secret\"\n\n\t// PrivateCryptoKeyType carries the information that a key is the private half\n\t// of an asymmetric key pair.\n\tPrivateCryptoKeyType CryptoKeyType = \"private\"\n\n\t// PublicCryptoKeyType carries the information that a key is the public half\n\t// of an asymmetric key pair.\n\tPublicCryptoKeyType CryptoKeyType = \"public\"\n)\n\n// CryptoKeyUsage represents the usage of a key.\n//\n// Note that it is defined as an alias of string, instead of a dedicated type,\n// to ensure it is handled as a string by sobek.\ntype CryptoKeyUsage = string\n\nconst (\n\t// EncryptCryptoKeyUsage indicates that the key may be used to encrypt messages.\n\tEncryptCryptoKeyUsage CryptoKeyUsage = \"encrypt\"\n\n\t// DecryptCryptoKeyUsage indicates that the key may be used to decrypt messages.\n\tDecryptCryptoKeyUsage CryptoKeyUsage = \"decrypt\"\n\n\t// SignCryptoKeyUsage indicates that the key may be used to sign messages.\n\tSignCryptoKeyUsage CryptoKeyUsage = \"sign\"\n\n\t// VerifyCryptoKeyUsage indicates that the key may be used to verify signatures.\n\tVerifyCryptoKeyUsage CryptoKeyUsage = \"verify\"\n\n\t// DeriveKeyCryptoKeyUsage indicates that the key may be used to derive a new key.\n\tDeriveKeyCryptoKeyUsage CryptoKeyUsage = \"deriveKey\"\n\n\t// DeriveBitsCryptoKeyUsage indicates that the key may be used to derive bits.\n\tDeriveBitsCryptoKeyUsage CryptoKeyUsage = \"deriveBits\"\n\n\t// WrapKeyCryptoKeyUsage indicates that the key may be used to wrap another key.\n\tWrapKeyCryptoKeyUsage CryptoKeyUsage = \"wrapKey\"\n\n\t// UnwrapKeyCryptoKeyUsage indicates that the key may be used to unwrap another key.\n\tUnwrapKeyCryptoKeyUsage CryptoKeyUsage = \"unwrapKey\"\n)\n\n// KeyAlgorithm represents the algorithm used to generate a cryptographic key.\ntype KeyAlgorithm struct {\n\tAlgorithm\n}\n\n// KeyGenerator is the interface implemented by the algorithms used to generate\n// cryptographic keys.\ntype KeyGenerator interface {\n\tGenerateKey(extractable bool, keyUsages []CryptoKeyUsage) (CryptoKeyGenerationResult, error)\n}\n\nfunc newKeyGenerator(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (KeyGenerator, error) {\n\tvar kg KeyGenerator\n\tvar err error\n\n\tswitch normalized.Name {\n\tcase AESCbc, AESCtr, AESGcm, AESKw:\n\t\tkg, err = newAESKeyGenParams(rt, normalized, params)\n\tcase HMAC:\n\t\tkg, err = newHMACKeyGenParams(rt, normalized, params)\n\tcase ECDH, ECDSA:\n\t\tkg, err = newECKeyGenParams(rt, normalized, params)\n\tcase RSASsaPkcs1v15, RSAPss, RSAOaep:\n\t\tkg, err = newRsaHashedKeyGenParams(rt, normalized, params)\n\tdefault:\n\t\tvalidAlgorithms := []string{AESCbc, AESCtr, AESGcm, AESKw, HMAC, ECDH, ECDSA, RSASsaPkcs1v15, RSAPss, RSAOaep}\n\t\treturn nil, NewError(\n\t\t\tNotImplemented,\n\t\t\t\"unsupported key generation algorithm '\"+normalized.Name+\"', \"+\n\t\t\t\t\"accepted values are: \"+strings.Join(validAlgorithms, \", \"),\n\t\t)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn kg, nil\n}\n\n// KeyDeriver is the interface implemented by the algorithms used to derive keys\ntype KeyDeriver interface {\n\tDeriveKey(\n\t\tprivateKey *CryptoKey,\n\t\tki KeyImporter,\n\t\tkgl KeyGetLengther,\n\t\tkeyUsages []CryptoKeyUsage,\n\t\textractable bool,\n\t) (*CryptoKey, error)\n}\n\nfunc newKeyDeriver(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (KeyDeriver, error) {\n\tvar kd KeyDeriver\n\tvar err error\n\n\tswitch normalized.Name {\n\tcase PBKDF2:\n\t\tkd, err = newPBKDF2DeriveParams(rt, normalized, params)\n\tdefault:\n\t\treturn nil, errors.New(\"key derivation not implemented for algorithm \" + normalized.Name)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn kd, nil\n}\n\n// KeyGetLengther is the interface implemented by the parameters used to\n// get the key length of cryptographic keys\ntype KeyGetLengther interface {\n\tGetKeyLength() int\n}\n\nfunc newKeyGetLengther(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (KeyGetLengther, error) {\n\tvar kgi KeyGetLengther\n\tvar err error\n\n\tswitch normalized.Name {\n\tcase AESCbc, AESCtr, AESGcm, AESKw:\n\t\tkgi, err = newAESGetLengthParams(rt, normalized, params)\n\tdefault:\n\t\treturn nil, errors.New(\"key get length not implemented for algorithm \" + normalized.Name)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn kgi, nil\n}\n\n// KeyImporter is the interface implemented by the parameters used to import\n// cryptographic keys.\ntype KeyImporter interface {\n\tImportKey(format KeyFormat, keyData []byte, extractable bool, keyUsages []CryptoKeyUsage) (*CryptoKey, error)\n}\n\nfunc newKeyImporter(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (KeyImporter, error) {\n\tvar ki KeyImporter\n\tvar err error\n\n\tswitch normalized.Name {\n\tcase AESCbc, AESCtr, AESGcm, AESKw:\n\t\tki = newAESImportParams(normalized)\n\tcase HMAC:\n\t\tki, err = newHMACImportParams(rt, normalized, params)\n\tcase ECDH, ECDSA:\n\t\tki, err = newEcKeyImportParams(rt, normalized, params)\n\tcase RSASsaPkcs1v15, RSAPss, RSAOaep:\n\t\tki, err = newRsaHashedImportParams(rt, normalized, params)\n\tcase PBKDF2:\n\t\tki = newPBKDF2ImportParams(normalized)\n\tdefault:\n\t\treturn nil, errors.New(\"key import not implemented for algorithm \" + normalized.Name)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ki, nil\n}\n\n// UsageIntersection returns the intersection of two slices of CryptoKeyUsage.\n//\n// It implements the algorithm described in the [specification] to\n// determine the intersection of two slices of CryptoKeyUsage.\n//\n// [specification]: https://w3c.github.io/webcrypto/#concept-usage-intersection\nfunc UsageIntersection(a, b []CryptoKeyUsage) []CryptoKeyUsage {\n\tvar intersection []CryptoKeyUsage\n\n\tfor _, usage := range a {\n\t\t// Note that the intersection algorithm is case-sensitive.\n\t\t// It is also expected to return the occurrence in the a slice \"as-is\".\n\t\tif slices.Contains(b, usage) && !slices.Contains(intersection, usage) {\n\t\t\tintersection = append(intersection, usage)\n\t\t}\n\t}\n\n\treturn intersection\n}\n\n// KeyFormat represents the format of a CryptoKey.\n//\n// Note that it is defined as an alias of string, instead of a dedicated type,\n// to ensure it is handled as a string by sobek.\ntype KeyFormat = string\n\nconst (\n\t// RawKeyFormat indicates that the key is in raw format.\n\tRawKeyFormat KeyFormat = \"raw\"\n\n\t// Pkcs8KeyFormat indicates that the key is in PKCS#8 format.\n\tPkcs8KeyFormat KeyFormat = \"pkcs8\"\n\n\t// SpkiKeyFormat indicates that the key is in SubjectPublicKeyInfo format.\n\tSpkiKeyFormat KeyFormat = \"spki\"\n\n\t// JwkKeyFormat indicates that the key is in JSON Web Key format.\n\tJwkKeyFormat KeyFormat = \"jwk\"\n)\n\n// KeyLength holds the length of the key, in bits.\n//\n// Note that it is defined as an alias of uint16, instead of a dedicated type,\n// to ensure it is handled as a number by sobek.\ntype KeyLength = uint16\n\nconst (\n\t// KeyLength128 represents a 128 bits key length.\n\tKeyLength128 KeyLength = 128\n\n\t// KeyLength192 represents a 192 bits key length.\n\tKeyLength192 KeyLength = 192\n\n\t// KeyLength256 represents a 256 bits key length.\n\tKeyLength256 KeyLength = 256\n\n\t// KeyLength384 represents a 384 bits key length.\n\tKeyLength384 KeyLength = 384\n\n\t// KeyLength512 represents a 512 bits key length.\n\tKeyLength512 KeyLength = 512\n)\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/module.go",
    "content": "// Package webcrypto exports the webcrypto API.\npackage webcrypto\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\nconst cryptoGlobalIdentifier = \"crypto\"\n\ntype (\n\t// RootModule is the global module instance that will create Client\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// ModuleInstance represents an instance of the JS module.\n\tModuleInstance struct {\n\t\tvu modules.VU\n\t}\n)\n\n// Ensure the interfaces are implemented correctly\nvar (\n\t_ modules.Instance = &ModuleInstance{}\n\t_ modules.Module   = &RootModule{}\n)\n\n// New returns a pointer to a new RootModule instance\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface and returns\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &ModuleInstance{\n\t\tvu: vu,\n\t}\n}\n\n// Exports implements the modules.Instance interface and returns\n// the exports of the JS module.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{Named: map[string]any{\n\t\t\"crypto\": mi.vu.Runtime().GlobalObject().Get(cryptoGlobalIdentifier),\n\t}}\n}\n\n// SetupGlobally sets the crypto object globally.\nfunc SetupGlobally(vu modules.VU) error {\n\tif err := vu.Runtime().Set(cryptoGlobalIdentifier, newCryptoObject(vu)); err != nil {\n\t\treturn fmt.Errorf(\"unable to set crypto object globally; reason: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc newCryptoObject(vu modules.VU) *sobek.Object {\n\trt := vu.Runtime()\n\n\tobj := rt.NewObject()\n\n\tcrypto := &Crypto{\n\t\tvu:        vu,\n\t\tSubtle:    &SubtleCrypto{vu: vu},\n\t\tCryptoKey: &CryptoKey{},\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"getRandomValues\", rt.ToValue(crypto.GetRandomValues)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"randomUUID\", rt.ToValue(crypto.RandomUUID)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"subtle\", rt.ToValue(newSubtleCryptoObject(vu))); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"CryptoKey\", rt.ToValue(crypto.CryptoKey)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\treturn obj\n}\n\nfunc newSubtleCryptoObject(vu modules.VU) *sobek.Object {\n\trt := vu.Runtime()\n\n\tobj := rt.NewObject()\n\n\tsubtleCrypto := &SubtleCrypto{vu: vu}\n\n\tif err := setReadOnlyPropertyOf(obj, \"decrypt\", rt.ToValue(subtleCrypto.Decrypt)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"deriveBits\", rt.ToValue(subtleCrypto.DeriveBits)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"deriveKey\", rt.ToValue(subtleCrypto.DeriveKey)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"digest\", rt.ToValue(subtleCrypto.Digest)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"encrypt\", rt.ToValue(subtleCrypto.Encrypt)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"exportKey\", rt.ToValue(subtleCrypto.ExportKey)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"generateKey\", rt.ToValue(subtleCrypto.GenerateKey)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"importKey\", rt.ToValue(subtleCrypto.ImportKey)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"sign\", rt.ToValue(subtleCrypto.Sign)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"unwrapKey\", rt.ToValue(subtleCrypto.UnwrapKey)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"verify\", rt.ToValue(subtleCrypto.Verify)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\tif err := setReadOnlyPropertyOf(obj, \"wrapKey\", rt.ToValue(subtleCrypto.WrapKey)); err != nil {\n\t\tcommon.Throw(rt, NewError(ImplementationError, err.Error()))\n\t}\n\n\treturn obj\n}\n\n// setReadOnlyPropertyOf sets a read-only property on the given [sobek.Object].\nfunc setReadOnlyPropertyOf(obj *sobek.Object, name string, value sobek.Value) error {\n\terr := obj.DefineDataProperty(name,\n\t\tvalue,\n\t\tsobek.FLAG_FALSE,\n\t\tsobek.FLAG_FALSE,\n\t\tsobek.FLAG_TRUE,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to define %s read-only property on TextEncoder object; reason: %w\", name, err)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/params.go",
    "content": "package webcrypto\n\n// From is an interface representing the ability to produce\n// an instance from a given generic input. It is an attempt\n// to create a contract around construction of objects from\n// others.\ntype From[Input, Output any] interface {\n\t// From produces an output of type Output from the\n\t// content of the given input.\n\tFrom(Input) (Output, error)\n}\n\n// AESKwParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.Encrypt`, `SubtleCrypto.Decrypt`, `SubtleCrypto.WrapKey`, or\n// `SubtleCrypto.UnwrapKey`, when using the AES-KW algorithm.\ntype AESKwParams struct {\n\t// Name should be set to AlgorithmKindAesKw.\n\tName AlgorithmIdentifier\n}\n\n// HKDFParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.DeriveKey`, when using the HKDF algorithm.\ntype HKDFParams struct {\n\t// Name should be set to AlgorithmKindHkdf.\n\tName AlgorithmIdentifier\n\n\t// Hash should be set to the name of the digest algorithm to use.\n\t// You can use any of the following:\n\t//   * [Sha256]\n\t//   * [Sha384]\n\t//   * [Sha512]\n\tHash AlgorithmIdentifier\n\n\t// Salt to use. The HKDF specification states that adding\n\t// salt \"adds significantly to the strength of HKDF\".\n\t// Ideally, the salt is a random or pseudo-random value with\n\t// the same length as the output of the digest function.\n\t// Unlike the input key material passed into `SubtleCrypto.DeriveKey`,\n\t// salt does not need to be kept secret.\n\tSalt []byte\n\n\t// Info holds application-specific contextual information.\n\t// This is used to bind the derived key to an application or\n\t// context, and enables you to derive different keys for different\n\t// contexts while using the same input key material.\n\t//\n\t// It's important that this should be independent of the input key material itself.\n\t// This property is required but may be an empty buffer.\n\tInfo []byte\n}\n\n// HMACSignatureParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.Sign`, when using the HMAC algorithm.\ntype HMACSignatureParams struct {\n\t// Name should be set to AlgorithmKindHmac.\n\tName AlgorithmIdentifier\n}\n\n// PBKDF2Params represents the object that should be passed as the algorithm\n// parameter into `SubtleCrypto.DeriveKey`, when using the PBKDF2 algorithm.\ntype PBKDF2Params struct {\n\t// Name should be set to AlgorithmKindPbkdf2.\n\tName AlgorithmIdentifier\n\n\t// FIXME: should also include SHA-1, unfortunately\n\t// Hash identifies the name of the digest algorithm to use.\n\t// You can use any of the following:\n\t//   * [Sha256]\n\t//   * [Sha384]\n\t//   * [Sha512]\n\tHash AlgorithmIdentifier\n\n\t// Salt should hold a random or pseudo-random value of at\n\t// least 16 bytes. Unlike the input key material passed into\n\t// `SubtleCrypto.DeriveKey`, salt does not need to be kept secret.\n\tSalt []byte\n\n\t// Iterations the number of times the hash function will be executed\n\t// in `SubtleCrypto.DeriveKey`. This determines how computationally\n\t// expensive (that is, slow) the `SubtleCrypto.DeriveKey` operation will be.\n\t//\n\t// In this context, slow is good, since it makes it more expensive for an\n\t// attacker to run a dictionary attack against the keys.\n\t// The general guidance here is to use as many iterations as possible,\n\t// subject to keeping an acceptable level of performance for your application.\n\tIterations int\n}\n\n// RSAHashedKeyGenParams represents the object that should be passed as the algorithm\n// parameter into `SubtleCrypto.GenerateKey`, when generating an RSA key pair.\ntype RSAHashedKeyGenParams struct {\n\tAlgorithm\n\n\t// ModulusLength holds (a Number) the length of the RSA modulus, in bits.\n\t// This should be at least 2048. Some organizations are now recommending\n\t// that it should be 4096.\n\tModulusLength int\n\n\t// PublicExponent holds (a Uint8Array) the public exponent to use.\n\t// Unless you have a good reason to use something else, use 65537 here.\n\tPublicExponent []byte\n\n\t// Hash represents the name of the digest function to use. You can\n\t// use any of the following: DigestKindSha256, DigestKindSha384,\n\t// or DigestKindSha512.\n\tHash Algorithm\n}\n\n// RSAHashedImportParams represents the object that should be passed as the\n// algorithm parameter into `SubtleCrypto.ImportKey` or `SubtleCrypto.UnwrapKey`, when\n// importing any RSA-based key pair: that is, when the algorithm is identified as any\n// of RSASSA-PKCS1-v1_5, RSA-PSS, or RSA-OAEP.\ntype RSAHashedImportParams struct {\n\tAlgorithm\n\n\t// Hash represents the name of the digest function to use.\n\t// Note that although you can technically pass SHA-1 here, this is strongly\n\t// discouraged as it is considered vulnerable.\n\tHash Algorithm\n}\n\n// RSAOaepParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.Encrypt`, `SubtleCrypto.Decrypt`, `SubtleCrypto.WrapKey`, or\n// `SubtleCrypto.UnwrapKey`, when using the RSA_OAEP algorithm.\ntype RSAOaepParams struct {\n\tAlgorithm\n\n\t// Label holds (an ArrayBuffer, a TypedArray, or a DataView) an array of bytes that does not\n\t// itself need to be encrypted but which should be bound to the ciphertext.\n\t// A digest of the label is part of the input to the encryption operation.\n\t//\n\t// Unless your application calls for a label, you can just omit this argument\n\t// and it will not affect the security of the encryption operation.\n\tLabel []byte\n}\n\n// RSAPssParams represents the object that should be passed as the algorithm\n// parameter into `SubtleCrypto.Sign` or `SubtleCrypto.Verify`, when using the\n// RSA-PSS algorithm.\ntype RSAPssParams struct {\n\tAlgorithm Algorithm\n\n\t// SaltLength holds (a Number) the length of the random salt to use, in bytes.\n\t// RFC 3447 says that \"typical salt lengths\" are either 0 or the length of the output\n\t// of the digest algorithm selected when this key was generated. For instance,\n\t// when using the SHA256 digest algorithm, the salt length could be 32.\n\tSaltLength int\n}\n\n// RSASsaPkcs1v15Params represents the object that should be passed as the algorithm\ntype RSASsaPkcs1v15Params struct {\n\t// Name should be set to AlgorithmKindRsassaPkcs1v15.\n\tName AlgorithmIdentifier\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/pbkdf2.go",
    "content": "package webcrypto\n\nimport (\n\t\"crypto/pbkdf2\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n)\n\n// PBKDF2KeyImportParams represents the object that should be passed as the algorithm parameter\n// into `SubtleCrypto.ImportKey`, when generating any password based key: that is, when the\n// algorithm is identified as PBKDF2.\ntype PBKDF2KeyImportParams struct {\n\tAlgorithm\n}\n\nfunc newPBKDF2ImportParams(normalized Algorithm) *PBKDF2KeyImportParams {\n\treturn &PBKDF2KeyImportParams{\n\t\tAlgorithm: normalized,\n\t}\n}\n\n// PBKDF2KeyAlgorithm is the algorithm for PBKDF2 keys as defined in the [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#dfn-PBKDF2KeyAlgorithm //TODO: update this to something real\ntype PBKDF2KeyAlgorithm struct {\n\tAlgorithm\n}\n\n// Ensure that PBKDF2ImportParams implements the KeyImporter interface.\nvar (\n\t_ KeyImporter = &PBKDF2KeyImportParams{}\n\t_ BitsDeriver = &PBKDF2Params{}\n\t_ KeyDeriver  = &PBKDF2Params{}\n)\n\n// ImportKey represents the PBKDF2 function that imports the PBKDF2 password as a CryptoSecret\nfunc (keyParams PBKDF2KeyImportParams) ImportKey(\n\tformat KeyFormat,\n\tkeyData []byte,\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (*CryptoKey, error) {\n\tif format != RawKeyFormat {\n\t\treturn nil, NewError(NotSupportedError, \"invalid format: \"+format)\n\t}\n\n\tfor _, usage := range keyUsages {\n\t\tswitch usage {\n\t\tcase DeriveBitsCryptoKeyUsage, DeriveKeyCryptoKeyUsage:\n\t\t\tcontinue\n\t\tdefault:\n\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage: \"+usage)\n\t\t}\n\t}\n\n\tif extractable {\n\t\treturn nil, NewError(SyntaxError, \"invalid value for param extractable \")\n\t}\n\n\treturn &CryptoKey{\n\t\tAlgorithm: PBKDF2KeyAlgorithm(keyParams),\n\t\tType:      SecretCryptoKeyType,\n\t\thandle:    keyData,\n\t}, nil\n}\n\nfunc newPBKDF2DeriveParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*PBKDF2Params, error) {\n\thashValue, err := traverseObject(rt, params, \"hash\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get hash from algorithm parameter\")\n\t}\n\n\tnormalizedHash, err := normalizeAlgorithm(rt, hashValue, OperationIdentifierDeriveBits)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\titerations, err := traverseObject(rt, params, \"iterations\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnumberIterations := iterations.ToInteger()\n\tif numberIterations == 0 {\n\t\treturn nil, NewError(OperationError, \"number of iterations can't be 0\")\n\t}\n\n\tsalt, err := traverseObject(rt, params, \"salt\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tbyteSalt, err := common.ToBytes(salt.Export())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &PBKDF2Params{\n\t\tName:       normalized.Name,\n\t\tHash:       normalizedHash.Name,\n\t\tIterations: int(numberIterations),\n\t\tSalt:       byteSalt,\n\t}, nil\n}\n\n// DeriveBits represents the PBKDF2 function that derives the key as bits from PBKDF2 params\nfunc (keyParams PBKDF2Params) DeriveBits(\n\tbaseKey *CryptoKey,\n\tlength int,\n) ([]byte, error) {\n\tpk, err := validateBaseKey(baseKey, OperationIdentifierDeriveBits)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thashFn, ok := getHashFn(keyParams.Hash)\n\tif !ok {\n\t\treturn nil, NewError(NotSupportedError, \"hash function not supported\")\n\t}\n\n\talg, ok := baseKey.Algorithm.(PBKDF2KeyAlgorithm)\n\tif !ok {\n\t\treturn nil, NewError(OperationError, \"provided baseKey is not a valid algorithm\")\n\t}\n\n\tif alg.Name != keyParams.Name {\n\t\treturn nil, NewError(OperationError,\n\t\t\t\"provided basekey algorithm and deriveKey algorithm name dont match \"+alg.Name+\"!=\"+keyParams.Name,\n\t\t)\n\t}\n\n\tif length%8 != 0 {\n\t\treturn nil, NewError(InvalidAccessError, \"provided length of key must be a multiple of 8\")\n\t}\n\n\tdk, err := pbkdf2.Key(hashFn, string(pk), keyParams.Salt, keyParams.Iterations, length/8)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn dk, nil\n}\n\n// DeriveKey represents the PBKDF2 function that derives a key from the PBKDF2 Parms\nfunc (keyParams PBKDF2Params) DeriveKey(\n\tbaseKey *CryptoKey,\n\tki KeyImporter,\n\tkgl KeyGetLengther,\n\tkeyUsages []CryptoKeyUsage,\n\textractable bool,\n) (*CryptoKey, error) {\n\tpk, err := validateBaseKey(baseKey, OperationIdentifierDeriveKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thashFn, ok := getHashFn(keyParams.Hash)\n\tif !ok {\n\t\treturn nil, NewError(NotSupportedError, \"hash function not supported\")\n\t}\n\n\talg, ok := baseKey.Algorithm.(PBKDF2KeyAlgorithm)\n\tif !ok {\n\t\treturn nil, NewError(OperationError, \"provided baseKey is not a valid algorithm\")\n\t}\n\n\tif alg.Name != keyParams.Name {\n\t\treturn nil, NewError(OperationError,\n\t\t\t\"provided basekey algorithm and deriveKey algorithm name dont match \"+alg.Name+\"!=\"+keyParams.Name,\n\t\t)\n\t}\n\n\tkeyLengthBits := kgl.GetKeyLength()\n\n\tif keyLengthBits%8 != 0 {\n\t\treturn nil, NewError(InvalidAccessError, \"provided length of key must be a multiple of 8\")\n\t}\n\n\tdk, err := pbkdf2.Key(hashFn, string(pk), keyParams.Salt, keyParams.Iterations, keyLengthBits/8)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tderivedKey, err := ki.ImportKey(\"raw\", dk, extractable, keyUsages)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn derivedKey, nil\n}\n\nfunc validateBaseKey(baseKey *CryptoKey, usage CryptoKeyUsage) ([]byte, error) {\n\terr := baseKey.Validate()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif baseKey.Type != SecretCryptoKeyType {\n\t\treturn nil, NewError(InvalidAccessError, \"algorithm's password key is not a secret key\")\n\t}\n\n\tif !baseKey.ContainsUsage(usage) {\n\t\treturn nil, NewError(InvalidAccessError, \"provided baseKey doesn't contain `\"+usage+\"` usage\")\n\t}\n\n\tpk, ok := baseKey.handle.([]byte)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, \"provided baseKey is not a valid PBKDF2 Crypto Key\")\n\t}\n\n\treturn pk, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/rsa.go",
    "content": "package webcrypto\n\nimport (\n\t\"crypto\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// RsaHashedKeyAlgorithm represents the RSA key algorithm as defined by the [specification].\n//\n// [specification]: https://www.w3.org/TR/WebCryptoAPI/#RsaHashedKeyAlgorithm-dictionary\ntype RsaHashedKeyAlgorithm struct {\n\tKeyAlgorithm\n\n\tModulusLength int `js:\"modulusLength\"`\n\n\tHash Algorithm\n}\n\nvar _ KeyGenerator = &RSAHashedKeyGenParams{}\n\nfunc newRsaHashedKeyGenParams(\n\trt *sobek.Runtime,\n\tnormalized Algorithm,\n\tparams sobek.Value,\n) (*RSAHashedKeyGenParams, error) {\n\tmodulusLength, err := traverseObject(rt, params, \"modulusLength\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get modulusLength from algorithm parameter\")\n\t}\n\n\tpublicExponentRaw, err := traverseObject(rt, params, \"publicExponent\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get publicExponent from algorithm parameter\")\n\t}\n\n\tpublicExponent, ok := publicExponentRaw.Export().([]byte)\n\tif !ok {\n\t\treturn nil, NewError(OperationError, \"publicExponent is not a byte array\")\n\t}\n\n\thash, err := extractHash(rt, params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &RSAHashedKeyGenParams{\n\t\tAlgorithm:      normalized,\n\t\tModulusLength:  int(modulusLength.ToInteger()),\n\t\tPublicExponent: publicExponent,\n\t\tHash:           hash,\n\t}, nil\n}\n\n// GenerateKey generates a new RSA key pair.\nfunc (rsakgp *RSAHashedKeyGenParams) GenerateKey(\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (CryptoKeyGenerationResult, error) {\n\tvar privateKeyUsages, publicKeyUsages []CryptoKeyUsage\n\n\tpublicExponent := int(new(big.Int).SetBytes(rsakgp.PublicExponent).Int64())\n\tif err := validatePublicExponent(publicExponent); err != nil {\n\t\treturn nil, NewError(\n\t\t\tOperationError,\n\t\t\tfmt.Sprintf(\"invalid public exponent: %s\", err),\n\t\t)\n\t}\n\n\tif len(keyUsages) == 0 {\n\t\treturn nil, NewError(SyntaxError, \"key usages cannot be empty\")\n\t}\n\n\tif rsakgp.Name == RSASsaPkcs1v15 || rsakgp.Name == RSAPss {\n\t\tprivateKeyUsages = []CryptoKeyUsage{SignCryptoKeyUsage}\n\t\tpublicKeyUsages = []CryptoKeyUsage{VerifyCryptoKeyUsage}\n\t\tfor _, usage := range keyUsages {\n\t\t\tswitch usage {\n\t\t\tcase SignCryptoKeyUsage:\n\t\t\tcase VerifyCryptoKeyUsage:\n\t\t\t\tcontinue\n\t\t\tdefault:\n\t\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage: \"+usage)\n\t\t\t}\n\t\t}\n\t}\n\tif rsakgp.Name == RSAOaep {\n\t\tprivateKeyUsages = []CryptoKeyUsage{DecryptCryptoKeyUsage}\n\t\tpublicKeyUsages = []CryptoKeyUsage{EncryptCryptoKeyUsage}\n\t\tfor _, usage := range keyUsages {\n\t\t\tswitch usage {\n\t\t\tcase EncryptCryptoKeyUsage:\n\t\t\tcase DecryptCryptoKeyUsage:\n\t\t\tcase WrapKeyCryptoKeyUsage:\n\t\t\tcase UnwrapKeyCryptoKeyUsage:\n\t\t\t\tcontinue\n\t\t\tdefault:\n\t\t\t\treturn nil, NewError(SyntaxError, \"invalid key usage: \"+usage)\n\t\t\t}\n\t\t}\n\t}\n\n\talg := RsaHashedKeyAlgorithm{\n\t\tModulusLength: rsakgp.ModulusLength,\n\t\tKeyAlgorithm: KeyAlgorithm{\n\t\t\tAlgorithm: rsakgp.Algorithm,\n\t\t},\n\t\tHash: rsakgp.Hash,\n\t}\n\n\tprivateKey := &CryptoKey{\n\t\tType:        PrivateCryptoKeyType,\n\t\tExtractable: extractable,\n\t\tAlgorithm:   alg,\n\t\tUsages:      UsageIntersection(keyUsages, privateKeyUsages),\n\t}\n\n\tpublicKey := &CryptoKey{\n\t\tType:        PublicCryptoKeyType,\n\t\tExtractable: true,\n\t\tAlgorithm:   alg,\n\t\tUsages:      UsageIntersection(keyUsages, publicKeyUsages),\n\t}\n\n\tvar err error\n\tprivateKey.handle, publicKey.handle, err = generateRSAKeyPair(rsakgp.ModulusLength, publicExponent)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &CryptoKeyPair{\n\t\tPrivateKey: privateKey,\n\t\tPublicKey:  publicKey,\n\t}, nil\n}\n\n// validatePublicExponent validates the public exponent.\n// it's done same way how golang's rsa package does it + additional check for evenness.\nfunc validatePublicExponent(e int) error {\n\tif e%2 == 0 {\n\t\treturn errors.New(\"public exponent is even\")\n\t}\n\n\tif e < 2 {\n\t\treturn errors.New(\"public exponent too small\")\n\t}\n\tif e > 1<<31-1 {\n\t\treturn errors.New(\"public exponent too large\")\n\t}\n\n\treturn nil\n}\n\nfunc generateRSAKeyPair(\n\tmodulusLength int,\n\tpublicExponent int,\n) (any, any, error) {\n\tprivateKey, err := rsa.GenerateKey(rand.Reader, modulusLength)\n\tif err != nil {\n\t\treturn nil, nil, NewError(OperationError, \"could not generate RSA key pair\")\n\t}\n\n\tprivateKey.E = publicExponent\n\n\t// validate the key pair, since we are setting the public exponent manually\n\tif err := privateKey.Validate(); err != nil {\n\t\treturn nil, nil, NewError(OperationError, \"could not validate RSA key pair, check public exponent: \"+err.Error())\n\t}\n\n\treturn privateKey, privateKey.Public(), nil\n}\n\nfunc exportRSAKey(ck *CryptoKey, format KeyFormat) (any, error) {\n\tif ck.handle == nil {\n\t\treturn nil, NewError(OperationError, \"key data is not accessible\")\n\t}\n\n\tswitch format {\n\tcase SpkiKeyFormat:\n\t\tif ck.Type != PublicCryptoKeyType {\n\t\t\treturn nil, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPublicKey, \"RSA\", ck.handle))\n\t\t}\n\n\t\tbytes, err := x509.MarshalPKIXPublicKey(ck.handle)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(OperationError, \"unable to marshal key to SPKI format: \"+err.Error())\n\t\t}\n\n\t\treturn bytes, nil\n\tcase Pkcs8KeyFormat:\n\t\tif ck.Type != PrivateCryptoKeyType {\n\t\t\treturn nil, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPrivateKey, \"RSA\", ck.handle))\n\t\t}\n\n\t\tbytes, err := x509.MarshalPKCS8PrivateKey(ck.handle)\n\t\tif err != nil {\n\t\t\treturn nil, NewError(OperationError, \"unable to marshal key to PKCS8 format: \"+err.Error())\n\t\t}\n\n\t\treturn bytes, nil\n\tcase JwkKeyFormat:\n\t\treturn exportRSAJWK(ck)\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, unsupportedKeyFormatErrorMsg+\" \"+format)\n\t}\n}\n\nfunc newRsaHashedImportParams(\n\trt *sobek.Runtime,\n\tnormalized Algorithm,\n\tparams sobek.Value,\n) (*RSAHashedImportParams, error) {\n\thash, err := extractHash(rt, params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &RSAHashedImportParams{\n\t\tAlgorithm: normalized,\n\t\tHash:      hash,\n\t}, nil\n}\n\n// Ensure that RSAHashedImportParams implements the KeyImporter interface.\nvar _ KeyImporter = &RSAHashedImportParams{}\n\n// ImportKey imports a key according to the algorithm described in the specification.\nfunc (rhkip *RSAHashedImportParams) ImportKey(\n\tformat KeyFormat,\n\tkeyData []byte,\n\t_ bool,\n\tusages []CryptoKeyUsage,\n) (*CryptoKey, error) {\n\tvar importFn func(keyData []byte) (any, CryptoKeyType, int, error)\n\n\tswitch format {\n\tcase Pkcs8KeyFormat:\n\t\timportFn = importRSAPrivateKey\n\tcase SpkiKeyFormat:\n\t\timportFn = importRSAPublicKey\n\tcase JwkKeyFormat:\n\t\timportFn = importRSAJWK\n\tdefault:\n\t\treturn nil, NewError(\n\t\t\tNotSupportedError,\n\t\t\tunsupportedKeyFormatErrorMsg+\" \"+format+\" for algorithm \"+rhkip.Name,\n\t\t)\n\t}\n\n\thandle, keyType, modusLength, err := importFn(keyData)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &CryptoKey{\n\t\tAlgorithm: RsaHashedKeyAlgorithm{\n\t\t\tModulusLength: modusLength,\n\t\t\tKeyAlgorithm: KeyAlgorithm{\n\t\t\t\tAlgorithm: rhkip.Algorithm,\n\t\t\t},\n\t\t\tHash: rhkip.Hash,\n\t\t},\n\t\tType:   keyType,\n\t\tUsages: usages,\n\t\thandle: handle,\n\t}, nil\n}\n\nfunc importRSAPrivateKey(keyData []byte) (any, CryptoKeyType, int, error) {\n\tparsedKey, err := x509.ParsePKCS8PrivateKey(keyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, NewError(DataError, \"unable to import RSA private key data: \"+err.Error())\n\t}\n\n\tprivateKey, ok := parsedKey.(*rsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, UnknownCryptoKeyType, 0, NewError(DataError, fmt.Sprintf(errMsgNotExpectedPrivateKey, \"RSA\", privateKey))\n\t}\n\n\treturn privateKey, PrivateCryptoKeyType, privateKey.N.BitLen(), nil\n}\n\nfunc importRSAPublicKey(keyData []byte) (any, CryptoKeyType, int, error) {\n\tparsedKey, err := x509.ParsePKIXPublicKey(keyData)\n\tif err != nil {\n\t\treturn nil, UnknownCryptoKeyType, 0, NewError(DataError, \"unable to import RSA public key data: \"+err.Error())\n\t}\n\n\tpublicKey, ok := parsedKey.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn nil, UnknownCryptoKeyType, 0, NewError(DataError, fmt.Sprintf(errMsgNotExpectedPublicKey, \"RSA\", publicKey))\n\t}\n\n\treturn publicKey, PublicCryptoKeyType, publicKey.N.BitLen(), nil\n}\n\ntype rsaSsaPkcs1v15SignerVerifier struct{}\n\nvar _ SignerVerifier = &rsaSsaPkcs1v15SignerVerifier{}\n\nfunc (rsasv *rsaSsaPkcs1v15SignerVerifier) Sign(key CryptoKey, data []byte) ([]byte, error) {\n\thash, err := extractHashFromRSAKey(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thashedData := hash.New()\n\thashedData.Write(data)\n\n\trsaKey, ok := key.handle.(*rsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPrivateKey, \"RSA\", key.handle))\n\t}\n\n\tsignature, err := rsa.SignPKCS1v15(rand.Reader, rsaKey, hash, hashedData.Sum(nil))\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not sign data: \"+err.Error())\n\t}\n\n\treturn signature, nil\n}\n\nfunc (rsasv *rsaSsaPkcs1v15SignerVerifier) Verify(key CryptoKey, signature []byte, data []byte) (bool, error) {\n\thash, err := extractHashFromRSAKey(key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\thashedData := hash.New()\n\thashedData.Write(data)\n\n\trsaKey, ok := key.handle.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn false, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPublicKey, \"RSA\", key.handle))\n\t}\n\n\terr = rsa.VerifyPKCS1v15(rsaKey, hash, hashedData.Sum(nil), signature)\n\tif err != nil {\n\t\treturn false, nil //nolint:nilerr\n\t}\n\n\treturn true, nil\n}\n\nfunc extractHashFromRSAKey(key CryptoKey) (crypto.Hash, error) {\n\tunk := crypto.Hash(0)\n\n\trsaHashedAlg, ok := key.Algorithm.(RsaHashedKeyAlgorithm)\n\tif !ok {\n\t\treturn unk, NewError(InvalidAccessError, \"key algorithm is not a RSA hashed key algorithm\")\n\t}\n\n\treturn mapHashFn(rsaHashedAlg.Hash.Name)\n}\n\nfunc newRSAPssParams(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (*RSAPssParams, error) {\n\tsaltLength, err := traverseObject(rt, params, \"saltLength\")\n\tif err != nil {\n\t\treturn nil, NewError(SyntaxError, \"could not get saltLength from algorithm parameter\")\n\t}\n\n\treturn &RSAPssParams{\n\t\tAlgorithm:  normalized,\n\t\tSaltLength: int(saltLength.ToInteger()),\n\t}, nil\n}\n\nvar _ SignerVerifier = &RSAPssParams{}\n\n// Sign signs the given data.\nfunc (rsasv *RSAPssParams) Sign(key CryptoKey, data []byte) ([]byte, error) {\n\trsaKey, ok := key.handle.(*rsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPrivateKey, \"RSA\", key.handle))\n\t}\n\n\thash, err := extractHashFromRSAKey(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thashedData := hash.New()\n\thashedData.Write(data)\n\n\tif rsasv.SaltLength == 0 {\n\t\treturn nil, NewError(ImplementationError, \"k6 RSA-PSS uses standard Golang SDK that doesn't support\"+\n\t\t\t\"salt length=0 but generates salt with maximum length . Sign result might be different.\")\n\t}\n\tsignature, err := rsa.SignPSS(rand.Reader, rsaKey, hash, hashedData.Sum(nil), &rsa.PSSOptions{\n\t\tSaltLength: rsasv.SaltLength,\n\t})\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not sign data: \"+err.Error())\n\t}\n\n\treturn signature, nil\n}\n\n// Verify verifies the signature of the given data.\nfunc (rsasv *RSAPssParams) Verify(key CryptoKey, signature []byte, data []byte) (bool, error) {\n\trsaKey, ok := key.handle.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn false, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPublicKey, \"RSA\", key.handle))\n\t}\n\n\thash, err := extractHashFromRSAKey(key)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\thashedData := hash.New()\n\thashedData.Write(data)\n\n\tif rsasv.SaltLength == 0 {\n\t\treturn false, NewError(ImplementationError, \"k6 RSA-PSS uses standard Golang SDK that doesn't support\"+\n\t\t\t\"salt length=0 but tries to auto-detect salt length if 0 is used. Verify result might be different.\")\n\t}\n\terr = rsa.VerifyPSS(rsaKey, hash, hashedData.Sum(nil), signature, &rsa.PSSOptions{\n\t\tSaltLength: rsasv.SaltLength,\n\t})\n\treturn err == nil, nil\n}\n\n// Encrypt .\nfunc (rsaoaep *RSAOaepParams) Encrypt(plaintext []byte, key CryptoKey) ([]byte, error) {\n\trsaKey, ok := key.handle.(*rsa.PublicKey)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPublicKey, \"RSA\", key.handle))\n\t}\n\n\thash, err := extractHashFromRSAKey(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tciphertext, err := rsa.EncryptOAEP(hash.New(), rand.Reader, rsaKey, plaintext, rsaoaep.Label)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not encrypt data: \"+err.Error())\n\t}\n\n\treturn ciphertext, nil\n}\n\n// Decrypt .\nfunc (rsaoaep *RSAOaepParams) Decrypt(ciphertext []byte, key CryptoKey) ([]byte, error) {\n\trsaKey, ok := key.handle.(*rsa.PrivateKey)\n\tif !ok {\n\t\treturn nil, NewError(InvalidAccessError, fmt.Sprintf(errMsgNotExpectedPrivateKey, \"RSA\", key.handle))\n\t}\n\n\thash, err := extractHashFromRSAKey(key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tplaintext, err := rsa.DecryptOAEP(hash.New(), rand.Reader, rsaKey, ciphertext, rsaoaep.Label)\n\tif err != nil {\n\t\treturn nil, NewError(OperationError, \"could not decrypt data: \"+err.Error())\n\t}\n\n\treturn plaintext, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/signer.go",
    "content": "package webcrypto\n\nimport \"github.com/grafana/sobek\"\n\n// SignerVerifier .\ntype SignerVerifier interface {\n\tSign(key CryptoKey, dataToSign []byte) ([]byte, error)\n\tVerify(key CryptoKey, signature, dataToVerify []byte) (bool, error)\n}\n\nfunc newSignerVerifier(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (SignerVerifier, error) {\n\tswitch normalized.Name {\n\tcase HMAC:\n\t\treturn &hmacSignerVerifier{}, nil\n\tcase ECDSA:\n\t\treturn newECDSAParams(rt, normalized, params)\n\tcase RSASsaPkcs1v15:\n\t\treturn &rsaSsaPkcs1v15SignerVerifier{}, nil\n\tcase RSAPss:\n\t\treturn newRSAPssParams(rt, normalized, params)\n\tdefault:\n\t\treturn nil, NewError(NotSupportedError, \"unsupported algorithm for signing/verifying: \"+normalized.Name)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/sobek.go",
    "content": "package webcrypto\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n)\n\n// exportArrayBuffer interprets the given value as an ArrayBuffer, TypedArray or DataView\n// and returns a copy of the underlying byte slice.\nfunc exportArrayBuffer(rt *sobek.Runtime, v sobek.Value) ([]byte, error) {\n\tif common.IsNullish(v) {\n\t\treturn nil, NewError(TypeError, \"data is null or undefined\")\n\t}\n\n\tasObject := v.ToObject(rt)\n\n\tvar ab sobek.ArrayBuffer\n\tvar ok bool\n\n\tif IsTypedArray(rt, v) {\n\t\tab, ok = asObject.Get(\"buffer\").Export().(sobek.ArrayBuffer)\n\t\tif !ok {\n\t\t\treturn nil, NewError(TypeError, \"TypedArray.buffer is not an ArrayBuffer\")\n\t\t}\n\t} else {\n\t\tab, ok = asObject.Export().(sobek.ArrayBuffer)\n\t\tif !ok {\n\t\t\treturn nil, NewError(OperationError, \"data is neither an ArrayBuffer, nor a TypedArray nor DataView\")\n\t\t}\n\t}\n\n\t// Copy the underlying byte slice to avoid the caller modifying it.\n\t// Ensures this step complies with the expactations of the\n\t// specification: \"Let [...] be the result of getting a copy of the\n\t// bytes held by the [...] parameter\"\n\tbytes := ab.Bytes()\n\tbytesCopy := make([]byte, len(bytes))\n\tcopy(bytesCopy, bytes)\n\n\treturn bytesCopy, nil\n}\n\n// traverseObject traverses the given object using the given fields and returns the value\n// at the end of the traversal. It assumes that all the traversed fields are Objects.\nfunc traverseObject(rt *sobek.Runtime, src sobek.Value, fields ...string) (sobek.Value, error) {\n\tif common.IsNullish(src) {\n\t\treturn nil, NewError(TypeError, \"Object is null or undefined\")\n\t}\n\n\tobj := src.ToObject(rt)\n\tif common.IsNullish(obj) {\n\t\treturn nil, NewError(TypeError, \"Object is null or undefined\")\n\t}\n\n\tfor idx, field := range fields {\n\t\tsrc = obj.Get(field)\n\t\tif common.IsNullish(src) {\n\t\t\treturn nil, NewError(\n\t\t\t\tTypeError,\n\t\t\t\tfmt.Sprintf(\"field %s is null or undefined\", strings.Join(fields[:idx+1], \".\")),\n\t\t\t)\n\t\t}\n\n\t\tobj = src.ToObject(rt)\n\t\tif common.IsNullish(obj) {\n\t\t\treturn nil, NewError(\n\t\t\t\tTypeError,\n\t\t\t\tfmt.Sprintf(\"field %s is not an Object\", strings.Join(fields[:idx+1], \".\")),\n\t\t\t)\n\t\t}\n\t}\n\n\treturn src, nil\n}\n\n// IsInstanceOf returns true if the given value is an instance of the given constructor\n// This uses the technique described in https://github.com/dop251/goja/issues/379#issuecomment-1164441879\nfunc IsInstanceOf(rt *sobek.Runtime, v sobek.Value, instanceOf ...JSType) bool {\n\tvar valid bool\n\n\tfor _, t := range instanceOf {\n\t\tinstanceOfConstructor := rt.Get(string(t))\n\t\tif valid = v.ToObject(rt).Get(\"constructor\").SameAs(instanceOfConstructor); valid {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn valid\n}\n\n// IsTypedArray returns true if the given value is an instance of a Typed Array\nfunc IsTypedArray(rt *sobek.Runtime, v sobek.Value) bool {\n\tasObject := v.ToObject(rt)\n\n\ttypedArrayTypes := []JSType{\n\t\tInt8ArrayConstructor,\n\t\tUint8ArrayConstructor,\n\t\tUint8ClampedArrayConstructor,\n\t\tInt16ArrayConstructor,\n\t\tUint16ArrayConstructor,\n\t\tInt32ArrayConstructor,\n\t\tUint32ArrayConstructor,\n\t\tFloat32ArrayConstructor,\n\t\tFloat64ArrayConstructor,\n\t\tBigInt64ArrayConstructor,\n\t\tBigUint64ArrayConstructor,\n\t}\n\n\treturn IsInstanceOf(rt, asObject, typedArrayTypes...)\n}\n\n// JSType is a string representing a JavaScript type\ntype JSType string\n\nconst (\n\t// ArrayBufferConstructor is the name of the ArrayBufferConstructor constructor\n\tArrayBufferConstructor JSType = \"ArrayBuffer\"\n\n\t// DataViewConstructor is the name of the DataView constructor\n\tDataViewConstructor = \"DataView\"\n\n\t// Int8ArrayConstructor is the name of the Int8ArrayConstructor constructor\n\tInt8ArrayConstructor = \"Int8Array\"\n\n\t// Uint8ArrayConstructor is the name of the Uint8ArrayConstructor constructor\n\tUint8ArrayConstructor = \"Uint8Array\"\n\n\t// Uint8ClampedArrayConstructor is the name of the Uint8ClampedArrayConstructor constructor\n\tUint8ClampedArrayConstructor = \"Uint8ClampedArray\"\n\n\t// Int16ArrayConstructor is the name of the Int16ArrayConstructor constructor\n\tInt16ArrayConstructor = \"Int16Array\"\n\n\t// Uint16ArrayConstructor is the name of the Uint16ArrayConstructor constructor\n\tUint16ArrayConstructor = \"Uint16Array\"\n\n\t// Int32ArrayConstructor is the name of the Int32ArrayConstructor constructor\n\tInt32ArrayConstructor = \"Int32Array\"\n\n\t// Uint32ArrayConstructor is the name of the Uint32ArrayConstructor constructor\n\tUint32ArrayConstructor = \"Uint32Array\"\n\n\t// Float32ArrayConstructor is the name of the Float32ArrayConstructor constructor\n\tFloat32ArrayConstructor = \"Float32Array\"\n\n\t// Float64ArrayConstructor is the name of the Float64ArrayConstructor constructor\n\tFloat64ArrayConstructor = \"Float64Array\"\n\n\t// BigInt64ArrayConstructor is the name of the BigInt64ArrayConstructor constructor\n\tBigInt64ArrayConstructor = \"BigInt64Array\"\n\n\t// BigUint64ArrayConstructor is the name of the BigUint64ArrayConstructor constructor\n\tBigUint64ArrayConstructor = \"BigUint64Array\"\n)\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/sobek_test.go",
    "content": "package webcrypto\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTraverseObject(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"empty object and empty fields\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\tobj := rt.NewObject()\n\n\t\tgotVal, gotErr := traverseObject(rt, obj)\n\n\t\trequire.NoError(t, gotErr)\n\t\tassert.Equal(t, obj, gotVal)\n\t})\n\n\tt.Run(\"empty object and non-empty fields\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\tobj := rt.NewObject()\n\n\t\t_, gotErr := traverseObject(rt, obj, \"foo\")\n\t\tvar gotWebCryptoError *Error\n\t\terrors.As(gotErr, &gotWebCryptoError)\n\n\t\tassert.Error(t, gotErr)\n\t\tassert.True(t, strings.Contains(gotWebCryptoError.Message, \"foo\"))\n\t})\n\n\tt.Run(\"non-empty object and empty fields\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\tobj := rt.NewObject()\n\t\tchildObj := rt.NewObject()\n\t\terr := obj.Set(\"foo\", childObj)\n\t\trequire.NoError(t, err)\n\n\t\t_, gotErr := traverseObject(rt, obj)\n\n\t\tassert.NoError(t, gotErr)\n\t})\n\n\tt.Run(\"non-empty object and non-empty fields\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\tobj := rt.NewObject()\n\t\tchildValue := rt.NewObject()\n\t\terr := obj.Set(\"foo\", childValue)\n\t\trequire.NoError(t, err)\n\n\t\tgotVal, gotErr := traverseObject(rt, obj, \"foo\")\n\n\t\trequire.NoError(t, gotErr)\n\t\tassert.Equal(t, childValue, gotVal)\n\t})\n\n\tt.Run(\"non-empty object and non-empty fields with non-object leaf\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\tobj := rt.NewObject()\n\t\tchildValue := rt.ToValue(\"bar\")\n\t\terr := obj.Set(\"foo\", childValue)\n\t\trequire.NoError(t, err)\n\n\t\tgotValue, gotErr := traverseObject(rt, obj, \"foo\")\n\n\t\tassert.NoError(t, gotErr)\n\t\tassert.Equal(t, childValue, gotValue)\n\t})\n\n\tt.Run(\"non-empty object and non-empty fields with non-existent leaf\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\tobj := rt.NewObject()\n\t\tchildValue := rt.ToValue(\"bar\")\n\t\terr := obj.Set(\"foo\", childValue)\n\t\trequire.NoError(t, err)\n\n\t\t_, gotErr := traverseObject(rt, obj, \"foo\", \"babar\")\n\t\tvar gotWebCryptoError *Error\n\t\terrors.As(gotErr, &gotWebCryptoError)\n\n\t\tassert.Error(t, gotErr)\n\t\tassert.True(t, strings.Contains(gotWebCryptoError.Message, \"foo.babar\"))\n\t})\n\n\tt.Run(\"non-empty object and non-empty fields with non-object intermediate\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\t\tobj := rt.NewObject()\n\t\tchildValue := rt.ToValue(\"bar\")\n\t\terr := obj.Set(\"foo\", childValue)\n\t\trequire.NoError(t, err)\n\n\t\t_, gotErr := traverseObject(rt, obj, \"foo\", \"bar\", \"bonjour\")\n\t\tvar gotWebCryptoError *Error\n\t\terrors.As(gotErr, &gotWebCryptoError)\n\n\t\tassert.Error(t, gotErr)\n\t\tassert.True(t, strings.Contains(gotWebCryptoError.Message, \"foo.bar\"))\n\t})\n\n\tt.Run(\"nil object\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\trt := sobek.New()\n\n\t\t_, gotErr := traverseObject(rt, nil)\n\n\t\tassert.Error(t, gotErr)\n\t})\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/subtle_crypto.go",
    "content": "package webcrypto\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"hash\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// FIXME: SubtleCrypto is described as an \"interface\", should it be a nested module\n// with top-level functions instead then? (as opposed to a struct as it is now)\n\n// FIXME: Make sure we cover the complete range of errors, and that their value makes sense\n\n// SubtleCrypto represents the SubtleCrypto interface of the Web Crypto API.\ntype SubtleCrypto struct {\n\tvu modules.VU\n}\n\n// Encrypt encrypts data.\n//\n// It takes as its arguments a key to encrypt with, some algorithm-specific\n// parameters, and the data to encrypt (also known as \"plaintext\").\n//\n// It returns a Promise which will be fulfilled with the encrypted data (also known as \"ciphertext\").\n//\n// The `algorithm` parameter should be one of:\n//   - an `SubtleCrypto.RSAOaepParams` object\n//   - an `SubtleCrypto.AESCtrParams` object\n//   - an `SubtleCrypto.AESCbcParams` object\n//   - an`SubtleCrypto.AESGcmParams` object\n//\n// The `key` parameter should be a `CryptoKey` to be used for encryption.\n//\n// The `data` parameter should contain the data to be encryption.\nfunc (sc *SubtleCrypto) Encrypt( //nolint:dupl // we have two similar methods\n\talgorithm, key, data sobek.Value,\n) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tplaintext []byte\n\t\tck        CryptoKey\n\t\tencrypter EncryptDecrypter\n\t)\n\n\terr := func() error {\n\t\tvar err error\n\n\t\tplaintext, err = exportArrayBuffer(rt, data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierEncrypt)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = rt.ExportTo(key, &ck); err != nil {\n\t\t\treturn NewError(InvalidAccessError, \"encrypt's key argument does hold not a valid CryptoKey object\")\n\t\t}\n\n\t\tkeyAlgorithmNameValue, err := traverseObject(rt, key.ToObject(rt), \"algorithm\", \"name\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif normalized.Name != keyAlgorithmNameValue.String() {\n\t\t\treturn NewError(InvalidAccessError, \"encrypt's algorithm name does not match key algorithm name\")\n\t\t}\n\n\t\tencrypter, err = newEncryptDecrypter(rt, normalized, algorithm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !ck.ContainsUsage(EncryptCryptoKeyUsage) {\n\t\t\treturn NewError(InvalidAccessError, \"encrypt's key does not contain the 'encrypt' usage\")\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tresult, err := encrypter.Encrypt(plaintext, ck)\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(rt.NewArrayBuffer(result))\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// Decrypt decrypts some encrypted data.\n//\n// It takes as arguments a key to decrypt with, some optional extra parameters, and\n// the data to decrypt (also known as \"ciphertext\").\n//\n// It returns a Promise which will be fulfilled with the decrypted data (also known\n// as \"plaintext\").\n//\n// Note that if the provided `algorithm` is RSA-OAEP, the `key` parameter should hold\n// the `PrivateKey` property of the `CryptoKeyPair`.\n//\n// The `algorithm` parameter should be one of:\n//   - an `SubtleCrypto.RSAOaepParams` object\n//   - an `SubtleCrypto.AESCtrParams` object\n//   - an `SubtleCrypto.AESCbcParams` object\n//   - an `SubtleCrypto.AESGcmParams` object\n//\n// The `key` parameter should be a `CryptoKey` to be used for decryption.\n//\n// The `data` parameter should contain the data to be decrypted.\nfunc (sc *SubtleCrypto) Decrypt( //nolint:dupl // we have two similar methods\n\talgorithm, key, data sobek.Value,\n) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tciphertext []byte\n\t\tck         CryptoKey\n\t\tdecrypter  EncryptDecrypter\n\t)\n\n\terr := func() error {\n\t\tvar err error\n\t\tciphertext, err = exportArrayBuffer(rt, data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierDecrypt)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = rt.ExportTo(key, &ck); err != nil {\n\t\t\treturn NewError(InvalidAccessError, \"decrypt's key argument does hold not a valid CryptoKey object\")\n\t\t}\n\n\t\tkeyAlgorithmNameValue, err := traverseObject(rt, key.ToObject(rt), \"algorithm\", \"name\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif normalized.Name != keyAlgorithmNameValue.String() {\n\t\t\treturn NewError(InvalidAccessError, \"decrypt's algorithm name does not match key algorithm name\")\n\t\t}\n\n\t\tdecrypter, err = newEncryptDecrypter(rt, normalized, algorithm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif !ck.ContainsUsage(DecryptCryptoKeyUsage) {\n\t\t\treturn NewError(InvalidAccessError, \"decrypt's key does not contain the 'decrypt' usage\")\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tresult, err := decrypter.Decrypt(ciphertext, ck)\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(rt.NewArrayBuffer(result))\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// Sign generates a digital signature.\n//\n// It takes as its arguments a key to sign with, some algorithm-specific parameters, and the data to sign.\n// It returns a Promise which will be fulfilled with the signature.\n//\n// Note that if the `algorithm` parameter identifies a public-key cryptosystem, the `key` parameter\n// should be a private key.\n//\n// You can use the corresponding `SubtleCrypto.Verify` method to verify the signature.\n//\n// The `algorithm` parameter should be one of:\n//   - the string \"RSASSA-PKCS1-v1_5\" or an object of the form `{ \"name\": \"RSASSA-PKCS1-v1_5\" }`\n//   - an `SubtleCrypto.RSAPssParams` object\n//   - an `SubtleCrypto.EcdsaParams` object\n//   - the string \"HMAC\" or an object of the form `{ \"name\": \"HMAC\" }`\n//\n// The `key` parameter should be a `CryptoKey` to be used for signing. Note that if\n// `algorithm` identifies a public-key cryptosystem, this is the private key.\n//\n// The `data` parameter should contain the data to be signed.\nfunc (sc *SubtleCrypto) Sign(algorithm, key, data sobek.Value) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tdataToSign []byte\n\t\tck         CryptoKey\n\t\tsigner     SignerVerifier\n\t)\n\n\terr := func() error {\n\t\tvar err error\n\t\t// 2.\n\t\t// We obtain a copy of the key data, because we might need to modify it.\n\t\tdataToSign, err = exportArrayBuffer(rt, data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// 3.\n\t\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierSign)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsigner, err = newSignerVerifier(rt, normalized, algorithm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = rt.ExportTo(key, &ck); err != nil {\n\t\t\treturn NewError(InvalidAccessError, \"key argument does hold not a valid CryptoKey object\")\n\t\t}\n\n\t\tkeyAlgorithmNameValue, err := traverseObject(rt, key.ToObject(rt), \"algorithm\", \"name\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t// 8.\n\t\tif normalized.Name != keyAlgorithmNameValue.String() {\n\t\t\treturn NewError(InvalidAccessError, \"algorithm name does not match key algorithm name\")\n\t\t}\n\n\t\t// 9.\n\t\tif !ck.ContainsUsage(SignCryptoKeyUsage) {\n\t\t\treturn NewError(InvalidAccessError, \"key does not contain the 'sign' usage\")\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tsignature, err := signer.Sign(ck, dataToSign)\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(rt.NewArrayBuffer(signature))\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// Verify verifies a digital signature.\n//\n// It takes as its arguments a key to verify the signature with, some\n// algorithm-specific parameters, the signature, and the original signed data.\n//\n// It returns a Promise which will be fulfilled with a boolean value indicating\n// whether the signature is valid.\n//\n// Note that the `key` parameter should hold the secret key for a symmetric algorithm\n// and the public key for a public-key system.\n//\n// The `algorithm` parameter should be one of:\n//   - the string \"RSASSA-PKCS1-v1_5\" or an object of the form `{ \"name\": \"RSASSA-PKCS1-v1_5\" }`\n//   - an `SubtleCrypto.RSAPssParams` object\n//   - an `SubtleCrypto.EcdsaParams` object\n//   - the string \"HMAC\" or an object of the form `{ \"name\": \"HMAC\" }`\n//\n// The `key` parameter should be a `CryptoKey` to be used for verification. Note that it\n// is the secret key for a symmetric algorithm and the public key for a public-key system.\n//\n// The `signature` parameter should contain the signature to be verified.\n//\n// The `data` parameter should contain the original signed data.\nfunc (sc *SubtleCrypto) Verify(algorithm, key, signature, data sobek.Value) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tsignatureData, signedData []byte\n\t\tverifier                  SignerVerifier\n\t\tck                        CryptoKey\n\t)\n\n\terr := func() error {\n\t\tvar err error\n\n\t\tsignatureData, err = exportArrayBuffer(sc.vu.Runtime(), signature)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tsignedData, err = exportArrayBuffer(sc.vu.Runtime(), data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnormalizedAlgorithm, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierVerify)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tverifier, err = newSignerVerifier(rt, normalizedAlgorithm, algorithm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif err = rt.ExportTo(key, &ck); err != nil {\n\t\t\treturn NewError(InvalidAccessError, \"key argument does hold not a valid CryptoKey object\")\n\t\t}\n\n\t\tkeyAlgorithmNameValue, err := traverseObject(rt, key, \"algorithm\", \"name\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif normalizedAlgorithm.Name != keyAlgorithmNameValue.String() {\n\t\t\treturn NewError(InvalidAccessError, \"algorithm name does not match key algorithm name\")\n\t\t}\n\n\t\tif !ck.ContainsUsage(VerifyCryptoKeyUsage) {\n\t\t\treturn NewError(InvalidAccessError, \"key does not contain the 'verify' usage\")\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tverified, err := verifier.Verify(ck, signatureData, signedData)\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(verified)\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// Digest generates a digest of the given data.\n//\n// A digest is a short fixed-length value derived from some\n// variable-length input. Cryptographic digests should exhibit\n// collision-resistance, meaning that it's hard to come up with\n// two different inputs that have the same digest value.\n//\n// It takes as its arguments an identifier for the digest algorithm\n// to use and the data to digest.\n// It returns a Promise which will be fulfilled with the digest.\n//\n// Supported digest algorithms:\n//   - SHA-1 (not to be used in cryptographic applications)\n//   - SHA-256\n//   - SHA-384\n//   - SHA-512\n//\n// The `data` parameter should contain the data to be digested.\nfunc (sc *SubtleCrypto) Digest(algorithm sobek.Value, data sobek.Value) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\thashFn func() hash.Hash\n\t\tbytes  []byte\n\t)\n\n\terr := func() error {\n\t\tvar err error\n\n\t\t// Validate that the value we received is either an ArrayBuffer, TypedArray, or DataView\n\t\t// This uses the technique described in https://github.com/dop251/goja/issues/379#issuecomment-1164441879\n\t\tif !IsInstanceOf(sc.vu.Runtime(), data, ArrayBufferConstructor, DataViewConstructor) &&\n\t\t\t!IsTypedArray(sc.vu.Runtime(), data) {\n\t\t\treturn errors.New(\"data must be an ArrayBuffer, TypedArray, or DataView\")\n\t\t}\n\n\t\tbytes, err = exportArrayBuffer(rt, data)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierDigest)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar ok bool\n\t\thashFn, ok = getHashFn(normalized.Name)\n\t\tif !ok {\n\t\t\treturn NewError(\n\t\t\t\tNotSupportedError,\n\t\t\t\t\"unsupported digest algorithm '\"+normalized.Name+\"', \"+\n\t\t\t\t\t\"accepted values are: SHA-1, SHA-256, SHA-384, and SHA-512\",\n\t\t\t)\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\thash := hashFn()\n\t\thash.Write(bytes)\n\t\tdigest := hash.Sum(nil)\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(rt.NewArrayBuffer(digest))\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// GenerateKey generate a new key (for symmetric algorithms) or key pair (for public-key algorithms).\n//\n// The generated key will match the algorithm, usages, and extractability given\n// as parameters.\n//\n// It returns a Promise that fulfills with a `SubtleCrypto.CryptoKey` (for symmetric algorithms)\n// or a `SubtleCrypto.CryptoKeyPair` (for public-key algorithms).\n//\n// The `algorithm` parameter should be one of:\n//   - for RSASSA-PKCS1-v1_5, RSA-PSS, or RSA-OAEP: pass an `SubtleCrypto.RSAHashedKeyGenParams` object\n//   - for ECDSA or ECDH: pass an `SubtleCrypto.ECKeyGenParams` object\n//   - an `SubtleCrypto.HMACKeyGenParams` object\n//   - for AES-CTR, AES-CBC, AES-GCM, AES-KW: pass an `SubtleCrypto.AESKeyGenParams`\n//\n// The `extractable` parameter indicates whether it will be possible to export the key\n// using `SubtleCrypto.ExportKey` or `SubtleCrypto.WrapKey`.\n//\n// The `keyUsages` parameter is an array of strings indicating what the key can be used for.\nfunc (sc *SubtleCrypto) GenerateKey(\n\talgorithm sobek.Value, extractable bool, keyUsages []CryptoKeyUsage,\n) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar keyGenerator KeyGenerator\n\n\terr := func() error {\n\t\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierGenerateKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tkeyGenerator, err = newKeyGenerator(rt, normalized, algorithm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tresult, err := func() (CryptoKeyGenerationResult, error) {\n\t\t\tresult, err := keyGenerator.GenerateKey(extractable, keyUsages)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif result.IsKeyPair() {\n\t\t\t\treturn result, nil\n\t\t\t}\n\n\t\t\tcryptoKey, err := result.ResolveCryptoKey()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, NewError(OperationError, \"usages cannot not be empty for a secret or private CryptoKey\")\n\t\t\t}\n\n\t\t\tisSecretKey := cryptoKey.Type == SecretCryptoKeyType\n\t\t\tisPrivateKey := cryptoKey.Type == PrivateCryptoKeyType\n\t\t\tisUsagesEmpty := len(cryptoKey.Usages) == 0\n\t\t\tif (isSecretKey || isPrivateKey) && isUsagesEmpty {\n\t\t\t\treturn nil, NewError(SyntaxError, \"usages cannot not be empty for a secret or private CryptoKey\")\n\t\t\t}\n\n\t\t\treturn result, nil\n\t\t}()\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(result)\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// DeriveKey can be used to derive a secret key from a master key.\n//\n// It takes as arguments some initial key material, the derivation\n// algorithm to use, and the desired properties for the key to derive.\n// It returns a Promise which will be fulfilled with a CryptoKey object\n// representing the new key.\n//\n// Note that if the `algorithm` parameter is ECDH, the `baseKey` parameter\n// should be a private key. Otherwise, it should be the initial key material for\n// the derivation function: for example, for PBKDF2 it might be a password, imported\n// as a CryptoKey using `SubtleCrypto.ImportKey`.\n//\n// The `algorithm` parameter should be one of:\n//   - an `SubtleCrypto.ECDHKeyDeriveParams` object\n//   - an `SubtleCrypto.HKDFParams` object\n//   - an `SubtleCrypto.Pbkdf2Params` object\n//\n// The `baseKey` parameter should be a CryptoKey object representing the input\n// to the derivation algorithm. If `algorithm` is ECDH, then this will be the\n// ECDH private key. Otherwise it will be the initial key material for the derivation\n// function: for example, for PBKDF2 it might be a password, imported as a `SubtleCrypto.CryptoKey`\n// using `SubtleCrypto.ImportKey`.\n//\n// The `derivedKeyType` parameter should be one of:\n//   - an `SubtleCrypto.HMACKeyGenParams` object\n//   - For AES-CTR, AES-CBC, AES-GCM, AES-KW: pass an `SubtleCrypto.AESKeyGenParams`\n//\n// The `extractable` parameter indicates whether it will be possible to export the key\n// using `SubtleCrypto.ExportKey` or `SubtleCrypto.WrapKey`.\n//\n// The `keyUsages` parameter is an array of strings indicating what the key can be used for.\nfunc (sc *SubtleCrypto) DeriveKey(\n\talgorithm sobek.Value,\n\tbaseKey sobek.Value,\n\tderivedKeyType sobek.Value,\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tderiver    KeyDeriver\n\t\tki         KeyImporter\n\t\tkgl        KeyGetLengther\n\t\terr        error\n\t\tprivateKey *CryptoKey\n\t)\n\n\terr = func() error {\n\t\tderiver, ki, kgl, err = getKeyInteractors(rt, algorithm, derivedKeyType)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = rt.ExportTo(baseKey, &privateKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tresult, err := func() (*CryptoKey, error) {\n\t\t\tresult, err := deriver.DeriveKey(\n\t\t\t\tprivateKey,\n\t\t\t\tki,\n\t\t\t\tkgl,\n\t\t\t\tkeyUsages,\n\t\t\t\textractable,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tisSecretKey := result.Type == SecretCryptoKeyType\n\t\t\tisPrivateKey := result.Type == PrivateCryptoKeyType\n\t\t\tisUsagesEmpty := len(keyUsages) == 0\n\t\t\tif (isSecretKey || isPrivateKey) && isUsagesEmpty {\n\t\t\t\treturn nil, NewError(SyntaxError, \"usages cannot not be empty for a secret or private CryptoKey\")\n\t\t\t}\n\n\t\t\tresult.Extractable = extractable\n\t\t\tresult.Usages = keyUsages\n\n\t\t\treturn result, nil\n\t\t}()\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\t\t\treturn resolve(result)\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\nfunc getKeyInteractors(\n\trt *sobek.Runtime,\n\talgorithm sobek.Value,\n\tderivedKeyType sobek.Value,\n) (KeyDeriver, KeyImporter, KeyGetLengther, error) {\n\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierDeriveKey)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tnormalizedDerivedKeyAlgorithmImport, err := normalizeAlgorithm(rt, derivedKeyType, OperationIdentifierImportKey)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tnormalizedDerivedKeyAlgorithmLength, err := normalizeAlgorithm(rt, derivedKeyType, OperationIdentifierGetKeyLength)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tderiver, err := newKeyDeriver(rt, normalized, algorithm)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tif !isAesAlgorithm(normalizedDerivedKeyAlgorithmImport.Name) &&\n\t\t!isHMACAlgorithm(normalizedDerivedKeyAlgorithmImport.Name) {\n\t\treturn nil, nil, nil, NewError(NotSupportedError,\n\t\t\t\"derive key function doesn't support algorithm \"+normalizedDerivedKeyAlgorithmImport.Name,\n\t\t)\n\t}\n\n\tki, err := newKeyImporter(rt, normalizedDerivedKeyAlgorithmImport, derivedKeyType)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\tkgl, err := newKeyGetLengther(rt, normalizedDerivedKeyAlgorithmLength, derivedKeyType)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\treturn deriver, ki, kgl, nil\n}\n\n// DeriveBits derives an array of bits from a base key.\n//\n// It takes as its arguments the base key, the derivation algorithm to use, and the length of the bit string to derive.\n// It returns a Promise which will be fulfilled with an ArrayBuffer containing the derived bits.\n//\n// This method is very similar to `SubtleCrypto.DeriveKey`, except that `SubtleCrypto.DeriveKey` returns\n// a `CryptoKey` object rather than an ArrayBuffer. Essentially `SubtleCrypto.DeriveKey` is composed\n// of `SubtleCrypto.DeriveBits` followed by `SubtleCrypto.ImportKey`.\n//\n// This function supports the same derivation algorithms as deriveKey(): ECDH, HKDF, and PBKDF2\n//\n// Note that if the `algorithm` parameter is ECDH, the `baseKey` parameter should be the ECDH private key.\n// Otherwise it should be the initial key material for the derivation function: for example, for PBKDF2 it might\n// be a password, imported as a `CryptoKey` using `SubtleCrypto.ImportKey`.\n//\n// The `algorithm` parameter should be one of:\n//   - an `SubtleCrypto.ECDHKeyDeriveParams` object\n//   - an `SubtleCrypto.HKDFParams` object\n//   - an `SubtleCrypto.PBKDF2Params` object\n//\n// The `baseKey` parameter should be a `CryptoKey` object representing the input to the derivation algorithm.\n// If `algorithm` is ECDH, then this will be the ECDH private key. Otherwise it will be the initial key material\n// for the derivation function: for example, for PBKDF2 it might be a password, imported as a `CryptoKey`\n// using `SubtleCrypto.ImportKey`.\n//\n// The `length` parameter is the number of bits to derive. The number should be a multiple of 8.\nfunc (sc *SubtleCrypto) DeriveBits(\n\talgorithm sobek.Value,\n\tbaseKey sobek.Value,\n\tlength int,\n) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tderiver    BitsDeriver\n\t\tprivateKey *CryptoKey\n\t)\n\n\terr := func() error {\n\t\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierDeriveBits)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tderiver, err = newBitsDeriver(rt, normalized, algorithm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\terr = rt.ExportTo(baseKey, &privateKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tresult, err := func() ([]byte, error) {\n\t\t\tif length == 0 {\n\t\t\t\treturn nil, NewError(OperationError, \"length can not be 0\")\n\t\t\t}\n\n\t\t\t// currently we don't support lengths that are not multiples of 8\n\t\t\t// https://github.com/grafana/xk6-webcrypto/issues/80\n\t\t\tif length%8 != 0 {\n\t\t\t\treturn nil, NewError(OperationError, \"currently only multiples of 8 are supported for length\")\n\t\t\t}\n\n\t\t\tb, err := deriver.DeriveBits(privateKey, length)\n\t\t\tif err != nil {\n\t\t\t\treturn b, err\n\t\t\t}\n\n\t\t\treturn b, nil\n\t\t}()\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(rt.NewArrayBuffer(result))\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// ImportKey imports a key: that is, it takes as input a key in an external, portable\n// format and gives you a CryptoKey object that you can use in the Web Crypto API.\n//\n// It returns a Promise that fulfills with the imported key as a CryptoKey object.\n//\n// The `format` parameter identifies the format of the key data.\n//\n// The `keyData` parameter is the key data, in the format specified by the `format` parameter.\n//\n// The `algorithm` parameter should be one of:\n//   - for RSASSA-PKCS1-v1_5, RSA-PSS or RSA-OAEP: pass an `SubtleCrypto.RSAHashedImportParams` object\n//   - for ECDSA or ECDH: pass an `SubtleCrypto.EcKeyImportParams` object\n//   - an `SubtleCrypto.HMACImportParams` object\n//   - for AES-CTR, AES-CBC, AES-GCM or AES-KW pass the string identifying\n//     the algorithm or an object of the form `{ name: ALGORITHM }`, where\n//     `ALGORITHM` is the name of the algorithm.\n//   - for PBKDF2: pass the string \"PBKDF2\"\n//   - for HKDF: pass the string \"HKDF\"\nfunc (sc *SubtleCrypto) ImportKey( //nolint:funlen // we have a lot of error handling\n\tformat KeyFormat,\n\tkeyData sobek.Value,\n\talgorithm sobek.Value,\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tkeyBytes []byte\n\t\tki       KeyImporter\n\t)\n\n\terr := func() error {\n\t\tswitch format {\n\t\tcase Pkcs8KeyFormat, RawKeyFormat, SpkiKeyFormat:\n\t\t\tab, err := exportArrayBuffer(rt, keyData)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tkeyBytes = make([]byte, len(ab))\n\t\t\tcopy(keyBytes, ab)\n\t\tcase JwkKeyFormat:\n\t\t\tvar err error\n\t\t\tkeyBytes, err = json.Marshal(keyData.Export())\n\t\t\tif err != nil {\n\t\t\t\treturn NewError(ImplementationError, \"invalid keyData format for JWK format: \"+err.Error())\n\t\t\t}\n\t\tdefault:\n\t\t\treturn NewError(ImplementationError, \"unsupported format \"+format)\n\t\t}\n\t\tnormalized, err := normalizeAlgorithm(rt, algorithm, OperationIdentifierImportKey)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tki, err = newKeyImporter(rt, normalized, algorithm)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tresult, err := func() (*CryptoKey, error) {\n\t\t\tresult, err := ki.ImportKey(format, keyBytes, extractable, keyUsages)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tisSecretKey := result.Type == SecretCryptoKeyType\n\t\t\tisPrivateKey := result.Type == PrivateCryptoKeyType\n\t\t\tisUsagesEmpty := len(keyUsages) == 0\n\t\t\tif (isSecretKey || isPrivateKey) && isUsagesEmpty {\n\t\t\t\treturn nil, NewError(SyntaxError, \"usages cannot not be empty for a secret or private CryptoKey\")\n\t\t\t}\n\n\t\t\tresult.Extractable = extractable\n\t\t\tresult.Usages = keyUsages\n\n\t\t\treturn result, nil\n\t\t}()\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\treturn resolve(result)\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\n// ExportKey exports a key: that is, it takes as input a CryptoKey object and gives\n// you the key in an external, portable format.\n//\n// To export a key, the key must have CryptoKey.extractable set to true.\n//\n// Keys are not exported in an encrypted format: to encrypt keys when exporting\n// them use the SubtleCrypto.wrapKey() API instead.\n//\n// It returns A Promise:\n//   - If format was jwk, then the promise fulfills with a JSON object containing the key.\n//   - Otherwise the promise fulfills with an ArrayBuffer containing the key.\n//\n// The `format` parameter identifies the format of the key data.\n// The `key` parameter is the key to export, as a CryptoKey object.\nfunc (sc *SubtleCrypto) ExportKey( //nolint:funlen // we have a lot of error handling\n\tformat KeyFormat,\n\tkey sobek.Value,\n) (*sobek.Promise, error) {\n\trt := sc.vu.Runtime()\n\n\tvar (\n\t\tck          *CryptoKey\n\t\tkeyExporter func(*CryptoKey, KeyFormat) (any, error)\n\t)\n\n\terr := func() error {\n\t\tkeyObj := key.ToObject(rt)\n\t\tif common.IsNullish(keyObj) {\n\t\t\treturn NewError(InvalidAccessError, \"key is not an object\")\n\t\t}\n\n\t\tvar ok bool\n\t\tck, ok = key.Export().(*CryptoKey)\n\t\tif !ok {\n\t\t\treturn NewError(ImplementationError, \"unable to extract CryptoKey from key object\")\n\t\t}\n\n\t\tvar algorithm Algorithm\n\t\talgObj := keyObj.Get(\"algorithm\")\n\t\tif err := rt.ExportTo(algObj, &algorithm); err != nil {\n\t\t\treturn NewError(SyntaxError, \"key is not a valid Algorithm\")\n\t\t}\n\n\t\tif !isRegisteredAlgorithm(algorithm.Name, OperationIdentifierExportKey) {\n\t\t\treturn NewError(NotSupportedError, \"unsupported algorithm \"+algorithm.Name)\n\t\t}\n\n\t\tif !ck.Extractable {\n\t\t\treturn NewError(InvalidAccessError, \"the key is not extractable\")\n\t\t}\n\n\t\tswitch algorithm.Name {\n\t\tcase AESCbc, AESCtr, AESGcm:\n\t\t\tkeyExporter = exportAESKey\n\t\tcase HMAC:\n\t\t\tkeyExporter = exportHMACKey\n\t\tcase ECDH, ECDSA:\n\t\t\tkeyExporter = exportECKey\n\t\tcase RSASsaPkcs1v15, RSAOaep, RSAPss:\n\t\t\tkeyExporter = exportRSAKey\n\t\tdefault:\n\t\t\treturn NewError(NotSupportedError, \"unsupported algorithm \"+algorithm.Name)\n\t\t}\n\n\t\treturn nil\n\t}()\n\n\tpromise, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\terr := reject(err)\n\t\treturn promise, err\n\t}\n\n\tcallback := sc.vu.RegisterCallback()\n\tgo func() {\n\t\tresult, err := keyExporter(ck, format)\n\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\n\t\t\tif !isBinaryExportedFormat(format) {\n\t\t\t\treturn resolve(result)\n\t\t\t}\n\n\t\t\tb, ok := result.([]byte)\n\t\t\tif !ok {\n\t\t\t\treturn reject(NewError(ImplementationError, \"for \"+format+\" []byte expected as result\"))\n\t\t\t}\n\n\t\t\treturn resolve(rt.NewArrayBuffer(b))\n\t\t})\n\t}()\n\n\treturn promise, nil\n}\n\nfunc isBinaryExportedFormat(format KeyFormat) bool {\n\treturn format == RawKeyFormat || format == Pkcs8KeyFormat || format == SpkiKeyFormat\n}\n\n// WrapKey  \"wraps\" a key.\n//\n// This means that it exports the key in an external, portable format, then encrypts the exported key.\n// Wrapping a key helps protect it in untrusted environments, such as inside an otherwise unprotected data\n// store or in transmission over an unprotected network.\n//\n// As with `SubtleCrypto.ExportKey`, you specify an export format for the key.\n// To export a key, it must have `CryptoKey.Extractable` set to true.\n//\n// But because `SubtleCrypto.WrapKey“ also encrypts the key to be imported, you\n// also need to pass in the key that must be used to encrypt it. This is sometimes called the \"wrapping key\".\n//\n// The inverse of `SubtleCrypto.WrapKey` is `SubtleCrypto.UnwrapKey`: while `SubtleCrypto.WrapKey“ is composed\n// of export + encrypt, unwrapKey is composed of import + decrypt.\n//\n// It returns a Promise that fulfills with an ArrayBuffer containing the encrypted exported key.\n//\n// The `format` parameter identifies the format of the key data.\n// The `key` parameter is the key to export, as a CryptoKey object.\n// The `wrappingKey` parameter is the key to use to encrypt the exported key. The key **must** have\n// the `wrapKey` usage flag set.\n// The `wrapAlgorithm` parameter identifies the algorithm to use to encrypt the exported key, and should be one of:\n//   - an `SubtleCrypto.RSAOaepParams` object\n//   - an `SubtleCrypto.AesCtrParams` object\n//   - an `SubtleCrypto.AesCbcParams` object\n//   - an `SubtleCrypto.AesGcmParams` object\n//   - for the AES-KW algorithm, pass the string \"AES-KW\", or an object of the form `{ name: \"AES-KW\" }`\n//\n//nolint:revive // remove the nolint directive when the method is implemented\nfunc (sc *SubtleCrypto) WrapKey(\n\tformat KeyFormat,\n\tkey sobek.Value,\n\twrappingKey sobek.Value,\n\twrapAlgorithm sobek.Value,\n) (*sobek.Promise, error) {\n\t// TODO: implementation\n\treturn nil, errors.New(\"not implemented\")\n}\n\n// UnwrapKey \"unwraps\" a key.\n//\n// This means that it takes as its input a key that has been exported and then\n// encrypted (also called \"wrapped\"). It decrypts the key and then imports it, returning\n// a `CryptoKey` object that can be used in the Web Crypto API.\n//\n// As with `SubtleCrypto.ImportKey`, you specify the key's import format and other attributes\n// of the key to import details such as whether it is extractable, and which operations it can be used for.\n//\n// But because `SubtleCrypto.UnwrapKey` also decrypts the key to be imported, you also need to pass\n// in the key that must be used to decrypt it. This is sometimes called the \"unwrapping key\".\n//\n// The inverse of `SubtleCrypto.UnwrapKey` is `SubtleCrypto.WrapKey`: while `SubtleCrypto.UnwrapKey` is composed\n// of decrypt + import, `Subtle.WrapKey` is composed of encrypt + export.\n//\n// It returns a Promise that fulfills with the unwrapped key as a CryptoKey object.\n//\n// The `format` parameter identifies the format of the key data.\n//\n// The `wrappedKey` parameter is the key to unwrap.\n//\n// The `unwrappingKey` parameter is the key to use to decrypt the wrapped key. The key **must** have\n//\n// the `unwrapKey` usage flag set.\n//\n// The `unwrapAlgorithm` parameter identifies the algorithm to use to decrypt the wrapped key, and should be one of:\n//   - an `SubtleCrypto.RSAOaepParams` object\n//   - an `SubtleCrypto.AesCtrParams` object\n//   - an `SubtleCrypto.AesCbcParams` object\n//   - an `SubtleCrypto.AesGcmParams` object\n//   - for the AES-KW algorithm, pass the string \"AES-KW\", or an object of the form `{ name: \"AES-KW\" }`\n//\n// The `unwrappedKeyAlgorithm` parameter identifies the algorithm to use to import the unwrapped\n// key, and should be one of:\n//   - for RSASSA-PKCS1-v1_5, RSA-PSS or RSA-OAEP: pass an `SubtleCrypto.RSAHashedImportParams` object\n//   - for ECDSA or ECDH: pass an `SubtleCrypto.EcKeyImportParams` object\n//   - for HMAC: pass an `SubtleCrypto.HMACImportParams` object\n//   - for AES-CTR, AES-CBC, AES-GCM or AES-KW pass the string identifying the algorithm or an object of the form\n//     `{ name: ALGORITHM }`, where `ALGORITHM` is the name of the algorithm.\n//\n// The `extractable` parameter identifies whether the key is extractable.\n//\n// The `keyUsages` parameter identifies the operations that the key can be used for.\n//\n//nolint:revive // remove the nolint directive when the method is implemented\nfunc (sc *SubtleCrypto) UnwrapKey(\n\tformat KeyFormat,\n\twrappedKey []byte,\n\tunwrappingKey sobek.Value,\n\tunwrapAlgo sobek.Value,\n\tunwrappedKeyAlgo sobek.Value,\n\textractable bool,\n\tkeyUsages []CryptoKeyUsage,\n) (*sobek.Promise, error) {\n\t// TODO: implementation\n\treturn nil, errors.New(\"not implemented\")\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/README.md",
    "content": "# k6's WebCrypto API Web Platform Tests \n\nTo be sure that we're compliant with the WebCrypto API specification, we run the [Web Platform Tests](https://web-platform-tests.org/) for the [WebCrypto API](https://www.w3.org/TR/WebCryptoAPI/) against our implementation. This is part of the CI process, and we expect to implement the missing tests when needed. \n\nSometimes, we need to patch the tests to make them compatible with the k6 runtime, all current patches are available in the `wpt-patches` catalog. We try to keep the diff as small as possible.\n\nThe entry point is the [`checkout.sh`](./checkout.sh) script, which checks out the last commit sha of \n[wpt](https://github.com/web-platform-tests/wpt) that was tested with this module, and applies some patches\n(all the `*.patch` files from the wpt-patches catalog) on top of it, in order to make the tests compatible with the k6 runtime.\n\nIf you work on a new web platform test, you could easily re-generate patches by running `./generate-patches.sh`.\n\n**How to use**\n1. Run `./checkout.sh` to check out the web-platform-tests sources.\n2. Run `go test ../... -tags=wpt` to run the tests.\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/checkout.sh",
    "content": "#!/bin/sh\n\n# Last commit hash it was tested with\nsha=75db68b05454e7f3a81e063373defd094c176a16\n\n# Checkout concrete files from the web-platform-tests repository\nmkdir -p ./wpt\ncd ./wpt\ngit init\ngit remote add origin https://github.com/web-platform-tests/wpt\ngit sparse-checkout init --cone\ngit sparse-checkout set resources WebCryptoAPI\ngit fetch origin --depth=1 \"${sha}\"\ngit checkout ${sha}\n\n# Apply custom patches needed to run the tests in k6/Sobek\nfor patch in ../wpt-patches/*.patch\ndo\n    git apply \"$patch\"\n    if [ $? -ne 0 ]; then\n        exit $?\n    fi\ndone\n\n# Return to the original directory\ncd -\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/generate-patches.sh",
    "content": "#!/bin/sh\n\ncd ./wpt\n\n# Generate patches for the WebCryptoAPI tests\ngit diff --name-only | while read file; do\n    safe_name=$(echo \"$file\" | sed 's/\\//__/g')\n    git diff \"$file\" > \"../wpt-patches/${safe_name}.patch\"\ndone\n\n# Return to the original directory\ncd -"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/subtle_crypto_test.go",
    "content": "// Package tests runs part of the Web Platform Tests suite for the k6's WebCrypto API\npackage tests\n\nimport (\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst webPlatformTestSuite = \"./wpt/WebCryptoAPI/\"\n\nfunc TestWebPlatformTestSuite(t *testing.T) {\n\tt.Parallel()\n\n\tif _, err := os.Stat(webPlatformTestSuite); err != nil { //nolint:forbidigo\n\t\tt.Skipf(\"If you want to run WebCrypto tests, you need to run the 'checkout.sh` script in the directory to get \"+\n\t\t\t\"https://github.com/web-platform-tests/wpt at the correct last tested commit (%v)\", err)\n\t}\n\n\ttests := []struct {\n\t\t// catalog is the catalog relatively webPlatformTestSuite where to look files\n\t\tcatalog string\n\t\t// files is the list of files to execute\n\t\tfiles []string\n\t\t// callFn is the function to call after the files are executed\n\t\t// if empty, no function will be called\n\t\tcallFn string\n\t}{\n\t\t// test cases for crypto api\n\t\t{\n\t\t\tcatalog: \"\",\n\t\t\tfiles: []string{\n\t\t\t\t\"getRandomValues.any.js\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcatalog: \"\",\n\t\t\tfiles: []string{\n\t\t\t\t\"randomUUID.https.any.js\",\n\t\t\t},\n\t\t},\n\t\t// test cases for subtle crypto api\n\t\t{\n\t\t\tcatalog: \"digest\",\n\t\t\tfiles: []string{\n\t\t\t\t\"digest.https.any.js\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcatalog: \"generateKey\",\n\t\t\tfiles: []string{\n\t\t\t\t\"successes.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"generateKey\",\n\t\t\tfiles: []string{\n\t\t\t\t\"failures.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"import_export\",\n\t\t\tfiles: []string{\n\t\t\t\t\"symmetric_importKey.https.any.js\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcatalog: \"import_export\",\n\t\t\tfiles: []string{\n\t\t\t\t\"ec_importKey.https.any.js\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcatalog: \"import_export\",\n\t\t\tfiles: []string{\n\t\t\t\t\"rsa_importKey.https.any.js\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tcatalog: \"encrypt_decrypt\",\n\t\t\tfiles: []string{\n\t\t\t\t\"aes_cbc_vectors.js\",\n\t\t\t\t\"aes.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"encrypt_decrypt\",\n\t\t\tfiles: []string{\n\t\t\t\t\"aes_ctr_vectors.js\",\n\t\t\t\t\"aes.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\t// Note @oleiade: although the specification targets support\n\t\t\t// for various iv sizes, go AES GCM cipher only supports 96bits.\n\t\t\t// Thus, although the official WebPlatform test suite contains\n\t\t\t// vectors for various iv sizes, we only test the 96bits one.\n\t\t\tcatalog: \"encrypt_decrypt\",\n\t\t\tfiles: []string{\n\t\t\t\t\"aes_gcm_96_iv_fixtures.js\",\n\t\t\t\t\"aes_gcm_vectors.js\",\n\t\t\t\t\"aes.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\t// RSA-OAEP\n\t\t\tcatalog: \"encrypt_decrypt\",\n\t\t\tfiles: []string{\n\t\t\t\t\"rsa_vectors.js\",\n\t\t\t\t\"rsa.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"sign_verify\",\n\t\t\tfiles: []string{\n\t\t\t\t\"hmac_vectors.js\", \"hmac.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"sign_verify\",\n\t\t\tfiles: []string{\n\t\t\t\t\"ecdsa_vectors.js\",\n\t\t\t\t\"ecdsa.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"sign_verify\",\n\t\t\tfiles: []string{\n\t\t\t\t\"rsa_pss_vectors.js\",\n\t\t\t\t\"rsa.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"sign_verify\",\n\t\t\tfiles: []string{\n\t\t\t\t\"rsa_pss_vectors.js\", \"rsa.js\",\n\t\t\t},\n\t\t\tcallFn: \"run_test\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"derive_bits_keys\",\n\t\t\tfiles: []string{\n\t\t\t\t\"ecdh_bits.js\",\n\t\t\t},\n\t\t\tcallFn: \"define_tests\",\n\t\t},\n\t\t{\n\t\t\tcatalog: \"derive_bits_keys\",\n\t\t\tfiles: []string{\n\t\t\t\t\"pbkdf2.js\",\n\t\t\t\t\"pbkdf2_vectors.js\",\n\t\t\t\t\"pbkdf2.https.any.js\",\n\t\t\t},\n\t\t\tcallFn: \"define_tests\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\ttestName := tt.catalog + \"/\" + strings.Join(tt.files, \"_\")\n\n\t\tt.Run(testName, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tts := newConfiguredRuntime(t)\n\t\t\t// We compile the Web Platform testharness script into a sobek.Program\n\t\t\tcompileAndRun(t, ts, \"./wpt/resources\", \"testharness.js\")\n\n\t\t\tgotErr := ts.EventLoop.Start(func() error {\n\t\t\t\trt := ts.VU.Runtime()\n\t\t\t\t// https://web-platform-tests.org/writing-tests/testharness-api.html#callbacks\n\t\t\t\t// gets back the Test instance for each test when it finishes\n\t\t\t\tcal, ok := sobek.AssertFunction(rt.Get(\"add_result_callback\"))\n\t\t\t\trequire.True(t, ok)\n\t\t\t\t_, err := cal(sobek.Undefined(), rt.ToValue(func(test *sobek.Object) {\n\t\t\t\t\t// TODO(@mstoykov): In some future place do this better and potentially record\n\t\t\t\t\t// and expect failures on unimplemented stuff\n\t\t\t\t\tstatus := test.Get(\"status\").ToInteger()\n\t\t\t\t\tt.Run(test.Get(\"name\").String(), func(t *testing.T) {\n\t\t\t\t\t\t// Report issues\n\t\t\t\t\t\tassert.Equal(t, \"null\", test.Get(\"message\").String())\n\t\t\t\t\t\tassert.Equal(t, \"null\", test.Get(\"stack\").String())\n\t\t\t\t\t\trequire.EqualValues(t, 0, status) // 0 is a PASS, all other values are some kind of failures\n\t\t\t\t\t})\n\t\t\t\t}))\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tfor _, script := range tt.files {\n\t\t\t\t\tcompileAndRun(t, ts, webPlatformTestSuite+tt.catalog, script)\n\t\t\t\t}\n\n\t\t\t\tif tt.callFn == \"\" {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\t_, err = rt.RunString(tt.callFn + `()`)\n\t\t\t\treturn err\n\t\t\t})\n\t\t\trequire.NoError(t, gotErr)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/test_setup_test.go",
    "content": "package tests\n\nimport (\n\t\"testing\"\n\n\tk6encoding \"go.k6.io/k6/internal/js/modules/k6/encoding\"\n\t\"go.k6.io/k6/internal/js/modules/k6/webcrypto\"\n\t\"go.k6.io/k6/js/modulestest\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst initGlobals = `\n\tglobalThis.CryptoKey = crypto.CryptoKey;\n`\n\n// newConfiguredRuntime initializes a new test setup.\n// It prepares a test setup with a mocked redis server and a goja runtime,\n// and event loop, ready to execute scripts as if being executed in the\n// main context of k6.\nfunc newConfiguredRuntime(t testing.TB) *modulestest.Runtime {\n\tvar err error\n\trt := modulestest.NewRuntime(t)\n\n\t// We want to make the [self] available for Web Platform Tests, as it is used in test harness.\n\t_, err = rt.VU.Runtime().RunString(\"var self = this;\")\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, webcrypto.SetupGlobally(rt.VU))\n\n\t// We compile the Web Platform helpers script into a sobek.Program\n\t// TODO: check if we need to compile the helpers.js script each time\n\t// or it can be just yet another test\n\tcompileAndRun(t, rt, \"./util\", \"helpers.js\")\n\n\tm := new(webcrypto.RootModule).NewModuleInstance(rt.VU)\n\n\terr = rt.VU.Runtime().Set(\"crypto\", m.Exports().Named[\"crypto\"])\n\trequire.NoError(t, err)\n\n\t// we define the btoa function in the goja runtime\n\t// so that the Web Platform tests can use it.\n\tencodingModule := k6encoding.New().NewModuleInstance(rt.VU)\n\terr = rt.VU.Runtime().Set(\"btoa\", encodingModule.Exports().Named[\"b64encode\"])\n\trequire.NoError(t, err)\n\n\t_, err = rt.VU.Runtime().RunString(initGlobals)\n\trequire.NoError(t, err)\n\n\treturn rt\n}\n\nfunc compileAndRun(t testing.TB, runtime *modulestest.Runtime, base, file string) {\n\tprogram, err := modulestest.CompileFile(base, file)\n\trequire.NoError(t, err)\n\n\t_, err = runtime.VU.Runtime().RunProgram(program)\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/util/helpers.js",
    "content": "//\n// helpers.js\n//\n// Helper functions used by several WebCryptoAPI tests\n//\n\nvar registeredAlgorithmNames = [\n    \"RSASSA-PKCS1-v1_5\",\n    \"RSA-PSS\",\n    \"RSA-OAEP\",\n    \"ECDSA\",\n    \"ECDH\",\n    \"AES-CTR\",\n    \"AES-CBC\",\n    \"AES-GCM\",\n    \"AES-KW\",\n    \"HMAC\",\n    \"SHA-1\",\n    \"SHA-256\",\n    \"SHA-384\",\n    \"SHA-512\",\n    \"HKDF\",\n    \"PBKDF2\",\n    \"Ed25519\",\n    \"Ed448\",\n    \"X25519\",\n    \"X448\"\n];\n\n\n// Treats an array as a set, and generates an array of all non-empty\n// subsets (which are themselves arrays).\n//\n// The order of members of the \"subsets\" is not guaranteed.\nfunction allNonemptySubsetsOf(arr) {\n    var results = [];\n    var firstElement;\n    var remainingElements;\n\n    for(var i=0; i<arr.length; i++) {\n        firstElement = arr[i];\n        remainingElements = arr.slice(i+1);\n        results.push([firstElement]);\n\n        if (remainingElements.length > 0) {\n            allNonemptySubsetsOf(remainingElements).forEach(function(combination) {\n                combination.push(firstElement);\n                results.push(combination);\n            });\n        }\n    }\n\n    return results;\n}\n\n\n// Create a string representation of keyGeneration parameters for\n// test names and labels.\nfunction objectToString(obj) {\n    var keyValuePairs = [];\n\n    if (Array.isArray(obj)) {\n        return \"[\" + obj.map(function(elem){return objectToString(elem);}).join(\", \") + \"]\";\n    } else if (typeof obj === \"object\") {\n        Object.keys(obj).sort().forEach(function(keyName) {\n            keyValuePairs.push(keyName + \": \" + objectToString(obj[keyName]));\n        });\n        return \"{\" + keyValuePairs.join(\", \") + \"}\";\n    } else if (typeof obj === \"undefined\") {\n        return \"undefined\";\n    } else {\n        return obj.toString();\n    }\n\n    var keyValuePairs = [];\n\n    Object.keys(obj).sort().forEach(function(keyName) {\n        var value = obj[keyName];\n        if (typeof value === \"object\") {\n            value = objectToString(value);\n        } else if (typeof value === \"array\") {\n            value = \"[\" + value.map(function(elem){return objectToString(elem);}).join(\", \") + \"]\";\n        } else {\n            value = value.toString();\n        }\n\n        keyValuePairs.push(keyName + \": \" + value);\n    });\n\n    return \"{\" + keyValuePairs.join(\", \") + \"}\";\n}\n\n// Is key a CryptoKey object with correct algorithm, extractable, and usages?\n// Is it a secret, private, or public kind of key?\nfunction assert_goodCryptoKey(key, algorithm, extractable, usages, kind) {\n    var correctUsages = [];\n\n    var registeredAlgorithmName;\n    registeredAlgorithmNames.forEach(function(name) {\n        if (name.toUpperCase() === algorithm.name.toUpperCase()) {\n            registeredAlgorithmName = name;\n        }\n    });\n\n    // FIXME: this should probably go away as we don't really set constructors\n    // in Goja?\n    // assert_equals(key.constructor, CryptoKey, \"Is a CryptoKey\");\n\n    assert_equals(key.type, kind, \"Is a \" + kind + \" key\");\n    assert_equals(key.extractable, extractable, \"Extractability is correct\");\n\n    assert_equals(key.algorithm.name, registeredAlgorithmName, \"Correct algorithm name\");\n    if (key.algorithm.name.toUpperCase() === \"HMAC\" && algorithm.length === undefined) {\n        switch (key.algorithm.hash.name.toUpperCase()) {\n            case 'SHA-1':\n            case 'SHA-256':\n                assert_equals(key.algorithm.length, 512, \"Correct length\");\n                break;\n            case 'SHA-384':\n            case 'SHA-512':\n                assert_equals(key.algorithm.length, 1024, \"Correct length\");\n                break;\n            default:\n                assert_unreached(\"Unrecognized hash\");\n        }\n    } else {\n        assert_equals(key.algorithm.length, algorithm.length, \"Correct length\");\n    }\n    if ([\"HMAC\", \"RSASSA-PKCS1-v1_5\", \"RSA-PSS\"].includes(registeredAlgorithmName)) {\n        assert_equals(key.algorithm.hash.name.toUpperCase(), algorithm.hash.toUpperCase(), \"Correct hash function\");\n    }\n\n    if (/^(?:Ed|X)(?:25519|448)$/.test(key.algorithm.name)) {\n        assert_false('namedCurve' in key.algorithm, \"Does not have a namedCurve property\");\n    }\n\n    // usages is expected to be provided for a key pair, but we are checking\n    // only a single key. The publicKey and privateKey portions of a key pair\n    // recognize only some of the usages appropriate for a key pair.\n    if (key.type === \"public\") {\n        [\"encrypt\", \"verify\", \"wrapKey\"].forEach(function(usage) {\n            if (usages.includes(usage)) {\n                correctUsages.push(usage);\n            }\n        });\n    } else if (key.type === \"private\") {\n        [\"decrypt\", \"sign\", \"unwrapKey\", \"deriveKey\", \"deriveBits\"].forEach(function(usage) {\n            if (usages.includes(usage)) {\n                correctUsages.push(usage);\n            }\n        });\n    } else {\n        correctUsages = usages;\n    }\n\n    assert_equals((typeof key.usages), \"object\", key.type + \" key.usages is an object\");\n    assert_not_equals(key.usages, null, key.type + \" key.usages isn't null\");\n\n    // The usages parameter could have repeats, but the usages\n    // property of the result should not.\n    var usageCount = 0;\n    key.usages.forEach(function(usage) {\n        usageCount += 1;\n        assert_in_array(usage, correctUsages, \"Has \" + usage + \" usage\");\n    });\n    assert_equals(key.usages.length, usageCount, \"usages property is correct\");\n\n    // FIXME: uncomment when we set Symbol.toStringTag?\n    // assert_equals(key[Symbol.toStringTag], 'CryptoKey', \"has the expected Symbol.toStringTag\");\n}\n\n\n// The algorithm parameter is an object with a name and other\n// properties. Given the name, generate all valid parameters.\nfunction allAlgorithmSpecifiersFor(algorithmName) {\n    var results = [];\n\n    // RSA key generation is slow. Test a minimal set of parameters\n    var hashes = [\"SHA-1\", \"SHA-256\"];\n\n    // EC key generation is a lot faster. Check all curves in the spec\n    var curves = [\"P-256\", \"P-384\", \"P-521\"];\n\n    if (algorithmName.toUpperCase().substring(0, 3) === \"AES\") {\n        // Specifier properties are name and length\n        [128, 192, 256].forEach(function(length) {\n            results.push({name: algorithmName, length: length});\n        });\n    } else if (algorithmName.toUpperCase() === \"HMAC\") {\n        [\n            {hash: \"SHA-1\", length: 160},\n            {hash: \"SHA-256\", length: 256},\n            {hash: \"SHA-384\", length: 384},\n            {hash: \"SHA-512\", length: 512},\n            {hash: \"SHA-1\"},\n            {hash: \"SHA-256\"},\n            {hash: \"SHA-384\"},\n            {hash: \"SHA-512\"},\n        ].forEach(function(hashAlgorithm) {\n            results.push({name: algorithmName, ...hashAlgorithm});\n        });\n    } else if (algorithmName.toUpperCase().substring(0, 3) === \"RSA\") {\n        hashes.forEach(function(hashName) {\n            results.push({name: algorithmName, hash: hashName, modulusLength: 2048, publicExponent: new Uint8Array([1,0,1])});\n        });\n    } else if (algorithmName.toUpperCase().substring(0, 2) === \"EC\") {\n        curves.forEach(function(curveName) {\n            results.push({name: algorithmName, namedCurve: curveName});\n        });\n    } else if (algorithmName.toUpperCase().substring(0, 1) === \"X\" || algorithmName.toUpperCase().substring(0, 2) === \"ED\") {\n        results.push({ name: algorithmName });\n    }\n\n    return results;\n}\n\n\n// Create every possible valid usages parameter, given legal\n// usages. Note that an empty usages parameter is not always valid.\n//\n// There is an optional parameter - mandatoryUsages. If provided,\n// it should be an array containing those usages of which one must be\n// included.\nfunction allValidUsages(validUsages, emptyIsValid, mandatoryUsages) {\n    if (typeof mandatoryUsages === \"undefined\") {\n        mandatoryUsages = [];\n    }\n\n    var okaySubsets = [];\n    allNonemptySubsetsOf(validUsages).forEach(function(subset) {\n        if (mandatoryUsages.length === 0) {\n            okaySubsets.push(subset);\n        } else {\n            for (var i=0; i<mandatoryUsages.length; i++) {\n                if (subset.includes(mandatoryUsages[i])) {\n                    okaySubsets.push(subset);\n                    return;\n                }\n            }\n        }\n    });\n\n    if (emptyIsValid) {\n        okaySubsets.push([]);\n    }\n\n    okaySubsets.push(validUsages.concat(mandatoryUsages).concat(validUsages)); // Repeated values are allowed\n    return okaySubsets;\n}\n\nfunction unique(names) {\n    return [...new Set(names)];\n}\n\n// Algorithm name specifiers are case-insensitive. Generate several\n// case variations of a given name.\nfunction allNameVariants(name, slowTest) {\n    var upCaseName = name.toUpperCase();\n    var lowCaseName = name.toLowerCase();\n    var mixedCaseName = upCaseName.substring(0, 1) + lowCaseName.substring(1);\n\n    // for slow tests effectively cut the amount of work in third by only\n    // returning one variation\n    if (slowTest) return [mixedCaseName];\n    return unique([upCaseName, lowCaseName, mixedCaseName]);\n}"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__derive_bits_keys__ecdh_bits.js.patch",
    "content": "diff --git a/WebCryptoAPI/derive_bits_keys/ecdh_bits.js b/WebCryptoAPI/derive_bits_keys/ecdh_bits.js\nindex 36b29c20a..c9c413599 100644\n--- a/WebCryptoAPI/derive_bits_keys/ecdh_bits.js\n+++ b/WebCryptoAPI/derive_bits_keys/ecdh_bits.js\n@@ -65,15 +65,17 @@ function define_tests() {\n                 });\n             }, namedCurve + \" short result\");\n \n+            // // TODO: once we have support of lengths that are not a multiple of 8 bits, uncomment this test\n+            // https://github.com/grafana/xk6-webcrypto/issues/80\n             // Non-multiple of 8\n-            promise_test(function(test) {\n-                return subtle.deriveBits({name: \"ECDH\", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 11)\n-                .then(function(derivation) {\n-                    assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 11), \"Derived correct bits\");\n-                }, function(err) {\n-                    assert_unreached(\"deriveBits failed with error \" + err.name + \": \" + err.message);\n-                });\n-            }, namedCurve + \" non-multiple of 8 bits\");\n+            // promise_test(function(test) {\n+            //     return subtle.deriveBits({name: \"ECDH\", public: publicKeys[namedCurve]}, privateKeys[namedCurve], 8 * sizes[namedCurve] - 11)\n+            //     .then(function(derivation) {\n+            //         assert_true(equalBuffers(derivation, derivations[namedCurve], 8 * sizes[namedCurve] - 11), \"Derived correct bits\");\n+            //     }, function(err) {\n+            //         assert_unreached(\"deriveBits failed with error \" + err.name + \": \" + err.message);\n+            //     });\n+            // }, namedCurve + \" non-multiple of 8 bits\");\n \n             // Errors to test:\n \n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__derive_bits_keys__pbkdf2.js.patch",
    "content": "diff --git a/WebCryptoAPI/derive_bits_keys/pbkdf2.js b/WebCryptoAPI/derive_bits_keys/pbkdf2.js\nindex 090806ceb..b65728d7f 100644\n--- a/WebCryptoAPI/derive_bits_keys/pbkdf2.js\n+++ b/WebCryptoAPI/derive_bits_keys/pbkdf2.js\n@@ -33,7 +33,7 @@ function define_tests() {\n                         var testName = passwordSize + \" password, \" + saltSize + \" salt, \" + hashName + \", with \" + iterations + \" iterations\";\n \n                         // Check for correct deriveBits result\n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256)\n                             .then(function(derivation) {\n                                 assert_true(equalBuffers(derivation, derivations[passwordSize][saltSize][hashName][iterations]), \"Derived correct key\");\n@@ -52,7 +52,7 @@ function define_tests() {\n                             testName += \" using \" + passwordSize + \" password, \" + saltSize + \" salt, \" + hashName + \", with \" + iterations + \" iterations\";\n \n                             // Test the particular key derivation.\n-                            subsetTest(promise_test, function(test) {\n+                            promise_test(function(test) {\n                                 return subtle.deriveKey({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)\n                                 .then(function(key) {\n                                     // Need to export the key to see that the correct bits were set.\n@@ -72,7 +72,7 @@ function define_tests() {\n \n                             // - illegal name for hash algorithm (NotSupportedError)\n                             var badHash = hashName.substring(0, 3) + hashName.substring(4);\n-                            subsetTest(promise_test, function(test) {\n+                            promise_test(function(test) {\n                                 return subtle.deriveKey({name: \"PBKDF2\", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)\n                                 .then(function(key) {\n                                     assert_unreached(\"bad hash name should have thrown an NotSupportedError\");\n@@ -82,7 +82,7 @@ function define_tests() {\n                             }, testName + \" with bad hash name \" + badHash);\n \n                             // - baseKey usages missing \"deriveKey\" (InvalidAccessError)\n-                            subsetTest(promise_test, function(test) {\n+                            promise_test(function(test) {\n                                 return subtle.deriveKey({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noKey[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)\n                                 .then(function(key) {\n                                     assert_unreached(\"missing deriveKey usage should have thrown an InvalidAccessError\");\n@@ -92,7 +92,7 @@ function define_tests() {\n                             }, testName + \" with missing deriveKey usage\");\n \n                             // - baseKey algorithm does not match PBKDF2 (InvalidAccessError)\n-                            subsetTest(promise_test, function(test) {\n+                            promise_test(function(test) {\n                                 return subtle.deriveKey({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, derivedKeyType.algorithm, true, derivedKeyType.usages)\n                                 .then(function(key) {\n                                     assert_unreached(\"wrong (ECDH) key should have thrown an InvalidAccessError\");\n@@ -104,7 +104,7 @@ function define_tests() {\n                         });\n \n                         // 0 length (OperationError)\n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 0)\n                             .then(function(derivation) {\n                                 assert_unreached(\"0 length should have thrown an OperationError\");\n@@ -114,7 +114,7 @@ function define_tests() {\n                         }, testName + \" with 0 length\");\n \n                         // length not multiple of 8 (OperationError)\n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, baseKeys[passwordSize], 44)\n                             .then(function(derivation) {\n                                 assert_unreached(\"non-multiple of 8 length should have thrown an OperationError\");\n@@ -125,7 +125,7 @@ function define_tests() {\n \n                         // - illegal name for hash algorithm (NotSupportedError)\n                         var badHash = hashName.substring(0, 3) + hashName.substring(4);\n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: badHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256)\n                             .then(function(derivation) {\n                                 assert_unreached(\"bad hash name should have thrown an NotSupportedError\");\n@@ -135,7 +135,7 @@ function define_tests() {\n                         }, testName + \" with bad hash name \" + badHash);\n \n                         // - baseKey usages missing \"deriveBits\" (InvalidAccessError)\n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, noBits[passwordSize], 256)\n                             .then(function(derivation) {\n                                 assert_unreached(\"missing deriveBits usage should have thrown an InvalidAccessError\");\n@@ -145,7 +145,7 @@ function define_tests() {\n                         }, testName + \" with missing deriveBits usage\");\n \n                         // - baseKey algorithm does not match PBKDF2 (InvalidAccessError)\n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: parseInt(iterations)}, wrongKey, 256)\n                             .then(function(derivation) {\n                                 assert_unreached(\"wrong (ECDH) key should have thrown an InvalidAccessError\");\n@@ -156,7 +156,7 @@ function define_tests() {\n                     });\n \n                     // Check that 0 iterations throws proper error\n-                    subsetTest(promise_test, function(test) {\n+                    promise_test(function(test) {\n                         return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], 256)\n                         .then(function(derivation) {\n                             assert_unreached(\"0 iterations should have thrown an error\");\n@@ -172,7 +172,7 @@ function define_tests() {\n                         });\n                         testName += \" using \" + passwordSize + \" password, \" + saltSize + \" salt, \" + hashName + \", with 0 iterations\";\n \n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveKey({name: \"PBKDF2\", salt: salts[saltSize], hash: hashName, iterations: 0}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)\n                             .then(function(derivation) {\n                                 assert_unreached(\"0 iterations should have thrown an error\");\n@@ -188,7 +188,7 @@ function define_tests() {\n                 [1, 1000, 100000].forEach(function(iterations) {\n                     var testName = passwordSize + \" password, \" + saltSize + \" salt, \" + nonDigestHash + \", with \" + iterations + \" iterations\";\n \n-                    subsetTest(promise_test, function(test) {\n+                    promise_test(function(test) {\n                         return subtle.deriveBits({name: \"PBKDF2\", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], 256)\n                         .then(function(derivation) {\n                             assert_unreached(\"non-digest algorithm should have thrown an NotSupportedError\");\n@@ -204,7 +204,7 @@ function define_tests() {\n                         });\n                         testName += \" using \" + passwordSize + \" password, \" + saltSize + \" salt, \" + nonDigestHash + \", with \" + iterations + \" iterations\";\n \n-                        subsetTest(promise_test, function(test) {\n+                        promise_test(function(test) {\n                             return subtle.deriveKey({name: \"PBKDF2\", salt: salts[saltSize], hash: nonDigestHash, iterations: parseInt(iterations)}, baseKeys[passwordSize], derivedKeyType.algorithm, true, derivedKeyType.usages)\n                             .then(function(derivation) {\n                                 assert_unreached(\"non-digest algorithm should have thrown an NotSupportedError\");\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__derive_bits_keys__pbkdf2_vectors.js.patch",
    "content": "diff --git a/WebCryptoAPI/derive_bits_keys/pbkdf2_vectors.js b/WebCryptoAPI/derive_bits_keys/pbkdf2_vectors.js\nindex b074f874a..966d22eaf 100644\n--- a/WebCryptoAPI/derive_bits_keys/pbkdf2_vectors.js\n+++ b/WebCryptoAPI/derive_bits_keys/pbkdf2_vectors.js\n@@ -27,6 +27,8 @@ function getTestData() {\n     // - baseKey algorithm does not match PBKDF2 (InvalidAccessError)\n     // - 0 iterations\n \n+    // uncomment AES-KW & HMAC when implemented for importKey\n+\n     var derivedKeyTypes = [\n         {algorithm: {name: \"AES-CBC\", length: 128}, usages: [\"encrypt\", \"decrypt\"]},\n         {algorithm: {name: \"AES-CBC\", length: 192}, usages: [\"encrypt\", \"decrypt\"]},\n@@ -37,13 +39,13 @@ function getTestData() {\n         {algorithm: {name: \"AES-GCM\", length: 128}, usages: [\"encrypt\", \"decrypt\"]},\n         {algorithm: {name: \"AES-GCM\", length: 192}, usages: [\"encrypt\", \"decrypt\"]},\n         {algorithm: {name: \"AES-GCM\", length: 256}, usages: [\"encrypt\", \"decrypt\"]},\n-        {algorithm: {name: \"AES-KW\", length: 128}, usages: [\"wrapKey\", \"unwrapKey\"]},\n-        {algorithm: {name: \"AES-KW\", length: 192}, usages: [\"wrapKey\", \"unwrapKey\"]},\n-        {algorithm: {name: \"AES-KW\", length: 256}, usages: [\"wrapKey\", \"unwrapKey\"]},\n-        {algorithm: {name: \"HMAC\", hash: \"SHA-1\", length: 256}, usages: [\"sign\", \"verify\"]},\n-        {algorithm: {name: \"HMAC\", hash: \"SHA-256\", length: 256}, usages: [\"sign\", \"verify\"]},\n-        {algorithm: {name: \"HMAC\", hash: \"SHA-384\", length: 256}, usages: [\"sign\", \"verify\"]},\n-        {algorithm: {name: \"HMAC\", hash: \"SHA-512\", length: 256}, usages: [\"sign\", \"verify\"]}\n+        // {algorithm: {name: \"AES-KW\", length: 128}, usages: [\"wrapKey\", \"unwrapKey\"]},\n+        // {algorithm: {name: \"AES-KW\", length: 192}, usages: [\"wrapKey\", \"unwrapKey\"]},\n+        // {algorithm: {name: \"AES-KW\", length: 256}, usages: [\"wrapKey\", \"unwrapKey\"]},\n+        // {algorithm: {name: \"HMAC\", hash: \"SHA-1\", length: 256}, usages: [\"sign\", \"verify\"]},\n+        // {algorithm: {name: \"HMAC\", hash: \"SHA-256\", length: 256}, usages: [\"sign\", \"verify\"]},\n+        // {algorithm: {name: \"HMAC\", hash: \"SHA-384\", length: 256}, usages: [\"sign\", \"verify\"]},\n+        // {algorithm: {name: \"HMAC\", hash: \"SHA-512\", length: 256}, usages: [\"sign\", \"verify\"]}\n     ];\n \n     var passwords = {\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__encrypt_decrypt__aes_gcm_vectors.js.patch",
    "content": "diff --git a/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js b/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js\nindex 965fe9564..0364b93cd 100644\n--- a/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js\n+++ b/WebCryptoAPI/encrypt_decrypt/aes_gcm_vectors.js\n@@ -22,7 +22,10 @@ function getTestVectors() {\n     } = getFixtures();\n \n     var keyLengths = [128, 192, 256];\n-    var tagLengths = [32, 64, 96, 104, 112, 120, 128];\n+    // NOTE @oleiade: The following tag lengths are not supported by the\n+    // current implementation of the AES-GCM algorithm in the Go standard\n+    // library: 32, 64\n+    var tagLengths = [96, 104, 112, 120, 128];\n \n     // All the scenarios that should succeed, if the key has \"encrypt\" usage\n     var passing = [];\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__failures.js.patch",
    "content": "diff --git a/WebCryptoAPI/generateKey/failures.js b/WebCryptoAPI/generateKey/failures.js\nindex e0f0279a6..61495ca75 100644\n--- a/WebCryptoAPI/generateKey/failures.js\n+++ b/WebCryptoAPI/generateKey/failures.js\n@@ -32,10 +32,10 @@ function run_test(algorithmNames) {\n         {name: \"RSA-OAEP\", resultType: \"CryptoKeyPair\", usages: [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"], mandatoryUsages: [\"decrypt\", \"unwrapKey\"]},\n         {name: \"ECDSA\",    resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n         {name: \"ECDH\",     resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n-        {name: \"Ed25519\",  resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n-        {name: \"Ed448\",    resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n-        {name: \"X25519\",   resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n-        {name: \"X448\",     resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n+        // {name: \"Ed25519\",  resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n+        // {name: \"Ed448\",    resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n+        // {name: \"X25519\",   resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n+        // {name: \"X448\",     resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n     ];\n \n     var testVectors = [];\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__generateKey__successes.js.patch",
    "content": "diff --git a/WebCryptoAPI/generateKey/successes.js b/WebCryptoAPI/generateKey/successes.js\nindex a9a168e1a..88861ab87 100644\n--- a/WebCryptoAPI/generateKey/successes.js\n+++ b/WebCryptoAPI/generateKey/successes.js\n@@ -21,17 +21,17 @@ function run_test(algorithmNames, slowTest) {\n         {name: \"AES-CTR\",  resultType: CryptoKey, usages: [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"], mandatoryUsages: []},\n         {name: \"AES-CBC\",  resultType: CryptoKey, usages: [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"], mandatoryUsages: []},\n         {name: \"AES-GCM\",  resultType: CryptoKey, usages: [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"], mandatoryUsages: []},\n-        {name: \"AES-KW\",   resultType: CryptoKey, usages: [\"wrapKey\", \"unwrapKey\"], mandatoryUsages: []},\n+        // {name: \"AES-KW\",   resultType: CryptoKey, usages: [\"wrapKey\", \"unwrapKey\"], mandatoryUsages: []},\n         {name: \"HMAC\",     resultType: CryptoKey, usages: [\"sign\", \"verify\"], mandatoryUsages: []},\n         {name: \"RSASSA-PKCS1-v1_5\", resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n         {name: \"RSA-PSS\",  resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n         {name: \"RSA-OAEP\", resultType: \"CryptoKeyPair\", usages: [\"encrypt\", \"decrypt\", \"wrapKey\", \"unwrapKey\"], mandatoryUsages: [\"decrypt\", \"unwrapKey\"]},\n         {name: \"ECDSA\",    resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n         {name: \"ECDH\",     resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n-        {name: \"Ed25519\",  resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n-        {name: \"Ed448\",    resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n-        {name: \"X25519\",   resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n-        {name: \"X448\",     resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n+        // {name: \"Ed25519\",  resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n+        // {name: \"Ed448\",    resultType: \"CryptoKeyPair\", usages: [\"sign\", \"verify\"], mandatoryUsages: [\"sign\"]},\n+        // {name: \"X25519\",   resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n+        // {name: \"X448\",     resultType: \"CryptoKeyPair\", usages: [\"deriveKey\", \"deriveBits\"], mandatoryUsages: [\"deriveKey\", \"deriveBits\"]},\n     ];\n \n     var testVectors = [];\n@@ -105,7 +105,7 @@ function run_test(algorithmNames, slowTest) {\n             allAlgorithmSpecifiersFor(name).forEach(function(algorithm) {\n                 allValidUsages(vector.usages, false, vector.mandatoryUsages).forEach(function(usages) {\n                     [false, true].forEach(function(extractable) {\n-                        subsetTest(testSuccess, algorithm, extractable, usages, vector.resultType, \"Success\");\n+                        testSuccess(algorithm, extractable, usages, vector.resultType, \"Success\")\n                     });\n                 });\n             });\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__getRandomValues.any.js.patch",
    "content": "diff --git a/WebCryptoAPI/getRandomValues.any.js b/WebCryptoAPI/getRandomValues.any.js\nindex 574134eb7..128c805a5 100644\n--- a/WebCryptoAPI/getRandomValues.any.js\n+++ b/WebCryptoAPI/getRandomValues.any.js\n@@ -1,14 +1,31 @@\n+// k6 throws GoError instead of DOMException, so we need to monkey patch.\n+const originalAssertThrowsDom = self.assert_throws_dom;\n+self.assert_throws_dom = function(expectedErrorName, func, description) {\n+    try {\n+        func();\n+    } catch (e) {\n+        const isGoError = (typeof e === \"object\") && (e.name === \"GoError\");\n+        const msg = isGoError ? (e.message || \"\") : e.toString();\n+        if (msg.includes(expectedErrorName)) {\n+            return; // Treat as correct\n+        }\n+    }\n+\n+    return originalAssertThrowsDom(expectedErrorName, func, description);\n+}\n+\n // Step 1.\n-test(function() {\n-    assert_throws_dom(\"TypeMismatchError\", function() {\n-        self.crypto.getRandomValues(new Float16Array(6))\n-    }, \"Float16Array\")\n+// Float16Array is not supported in k6\n+// test(function() {\n+//     assert_throws_dom(\"TypeMismatchError\", function() {\n+//         self.crypto.getRandomValues(new Float16Array(6))\n+//     }, \"Float16Array\")\n \n-    assert_throws_dom(\"TypeMismatchError\", function() {\n-        const len = 65536 / Float16Array.BYTES_PER_ELEMENT + 1;\n-        self.crypto.getRandomValues(new Float16Array(len));\n-    }, \"Float16Array (too long)\")\n-}, \"Float16 arrays\");\n+//     assert_throws_dom(\"TypeMismatchError\", function() {\n+//         const len = 65536 / Float16Array.BYTES_PER_ELEMENT + 1;\n+//         self.crypto.getRandomValues(new Float16Array(len));\n+//     }, \"Float16Array (too long)\")\n+// }, \"Float16 arrays\");\n \n test(function() {\n     assert_throws_dom(\"TypeMismatchError\", function() {\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__ec_importKey.https.any.js.patch",
    "content": "diff --git a/WebCryptoAPI/import_export/ec_importKey.https.any.js b/WebCryptoAPI/import_export/ec_importKey.https.any.js\nindex a01bfbb0e..4b7ac8cf0 100644\n--- a/WebCryptoAPI/import_export/ec_importKey.https.any.js\n+++ b/WebCryptoAPI/import_export/ec_importKey.https.any.js\n@@ -72,7 +72,8 @@\n \n                 // Test public keys first\n                 allValidUsages(vector.publicUsages, true).forEach(function(usages) {\n-                    ['spki', 'spki_compressed', 'jwk', 'raw', 'raw_compressed'].forEach(function(format) {\n+                    // TODO: k6's webcrypto doesn't support compressed points yet\n+                    ['spki', 'jwk', 'raw'].forEach(function(format) {\n                         var algorithm = {name: vector.name, namedCurve: curve};\n                         var data = keyData[curve];\n                         if (format === \"jwk\") { // Not all fields used for public keys\n@@ -115,7 +116,8 @@\n         promise_test(function(test) {\n             return subtle.importKey(format, keyData, algorithm, extractable, usages).\n             then(function(key) {\n-                assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n+                // this is not yet supported in k6's webcrypto\n+                // assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n                 assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData.d)) ? 'private' : 'public');\n                 if (!extractable) {\n                     return;\n@@ -163,7 +165,8 @@\n         promise_test(function(test) {\n             return subtle.importKey(format, keyData, algorithm, extractable, usages).\n             then(function(key) {\n-                assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n+                // this is not yet supported in k6's webcrypto\n+                // assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n                 assert_goodCryptoKey(key, algorithm, extractable, usages, keyData.d ? 'private' : 'public');\n             }, function(err) {\n                 assert_unreached(\"Threw an unexpected error: \" + err.toString());\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__rsa_importKey.https.any.js.patch",
    "content": "diff --git a/WebCryptoAPI/import_export/rsa_importKey.https.any.js b/WebCryptoAPI/import_export/rsa_importKey.https.any.js\nindex c0917cab6..93d16cfc4 100644\n--- a/WebCryptoAPI/import_export/rsa_importKey.https.any.js\n+++ b/WebCryptoAPI/import_export/rsa_importKey.https.any.js\n@@ -113,7 +113,8 @@\n         promise_test(function(test) {\n             return subtle.importKey(format, keyData[format], algorithm, extractable, usages).\n             then(function(key) {\n-                assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n+                // this is not yet supported in k6's webcrypto\n+                // assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n                 assert_goodCryptoKey(key, algorithm, extractable, usages, (format === 'pkcs8' || (format === 'jwk' && keyData[format].d)) ? 'private' : 'public');\n                 if (!extractable) {\n                     return;\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__import_export__symmetric_importKey.https.any.js.patch",
    "content": "diff --git a/WebCryptoAPI/import_export/symmetric_importKey.https.any.js b/WebCryptoAPI/import_export/symmetric_importKey.https.any.js\nindex 01b318018..7957cb204 100644\n--- a/WebCryptoAPI/import_export/symmetric_importKey.https.any.js\n+++ b/WebCryptoAPI/import_export/symmetric_importKey.https.any.js\n@@ -18,16 +18,17 @@\n \n     // combinations of algorithms, usages, parameters, and formats to test\n     var testVectors = [\n+        // FIXME: uncomment when other symmetric algorithms are supported\n         {name: \"AES-CTR\",               legalUsages: [\"encrypt\", \"decrypt\"],      extractable: [true, false], formats: [\"raw\", \"jwk\"]},\n         {name: \"AES-CBC\",               legalUsages: [\"encrypt\", \"decrypt\"],      extractable: [true, false], formats: [\"raw\", \"jwk\"]},\n         {name: \"AES-GCM\",               legalUsages: [\"encrypt\", \"decrypt\"],      extractable: [true, false], formats: [\"raw\", \"jwk\"]},\n-        {name: \"AES-KW\",                legalUsages: [\"wrapKey\", \"unwrapKey\"],    extractable: [true, false], formats: [\"raw\", \"jwk\"]},\n+        // {name: \"AES-KW\",                legalUsages: [\"wrapKey\", \"unwrapKey\"],    extractable: [true, false], formats: [\"raw\", \"jwk\"]},\n         {name: \"HMAC\", hash: \"SHA-1\",   legalUsages: [\"sign\", \"verify\"],          extractable: [false],       formats: [\"raw\", \"jwk\"]},\n         {name: \"HMAC\", hash: \"SHA-256\", legalUsages: [\"sign\", \"verify\"],          extractable: [false],       formats: [\"raw\", \"jwk\"]},\n         {name: \"HMAC\", hash: \"SHA-384\", legalUsages: [\"sign\", \"verify\"],          extractable: [false],       formats: [\"raw\", \"jwk\"]},\n         {name: \"HMAC\", hash: \"SHA-512\", legalUsages: [\"sign\", \"verify\"],          extractable: [false],       formats: [\"raw\", \"jwk\"]},\n-        {name: \"HKDF\",                  legalUsages: [\"deriveBits\", \"deriveKey\"], extractable: [false],       formats: [\"raw\"]},\n-        {name: \"PBKDF2\",                legalUsages: [\"deriveBits\", \"deriveKey\"], extractable: [false],       formats: [\"raw\"]}\n+        // {name: \"HKDF\",                  legalUsages: [\"deriveBits\", \"deriveKey\"], extractable: [false],       formats: [\"raw\"]},\n+        // {name: \"PBKDF2\",                legalUsages: [\"deriveBits\", \"deriveKey\"], extractable: [false],       formats: [\"raw\"]}\n     ];\n \n \n@@ -69,7 +70,8 @@\n         promise_test(function(test) {\n             return subtle.importKey(format, keyData, algorithm, extractable, usages).\n             then(function(key) {\n-                assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n+                // this is not yet supported in k6's webcrypto\n+                // assert_equals(key.constructor, CryptoKey, \"Imported a CryptoKey object\");\n                 assert_goodCryptoKey(key, hasLength(key.algorithm) ? { length: keySize, ...algorithm } : algorithm, extractable, usages, 'secret');\n                 if (!extractable) {\n                     return;\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__ecdsa_vectors.js.patch",
    "content": "diff --git a/WebCryptoAPI/sign_verify/ecdsa_vectors.js b/WebCryptoAPI/sign_verify/ecdsa_vectors.js\nindex aa9b81ba8..185c82622 100644\n--- a/WebCryptoAPI/sign_verify/ecdsa_vectors.js\n+++ b/WebCryptoAPI/sign_verify/ecdsa_vectors.js\n@@ -90,7 +90,9 @@ function getInvalidTestVectors() {\n         {\n             const vector = structuredClone(validVector);\n             vector.name = `${vector.name} - The signature was truncated by 1 byte`;\n-            vector.signature = vector.signature.subarray(0, vector.signature.byteLength - 1);\n+            // this copyUint8Array is a workaround, since we have to modify the way how we read ArrayBuffers\n+            // https://github.com/grafana/xk6-webcrypto/issues/72\n+            vector.signature = copyUint8Array(vector.signature.subarray(0, vector.signature.byteLength - 1));\n             vectors.push(vector);\n         }\n \n@@ -137,3 +139,26 @@ function getInvalidTestVectors() {\n \n     return vectors;\n }\n+\n+// k6 has no structuredClone\n+// we implement a naive version here\n+function structuredClone(origin) {\n+    return {\n+        name: origin.name,\n+        publicKeyBuffer: copyUint8Array(origin.publicKeyBuffer), // Uint8Array\n+        publicKeyFormat: origin.publicKeyFormat,\n+        publicKey: origin.publicKey,\n+        privateKeyBuffer: copyUint8Array(origin.privateKeyBuffer), // Uint8Array\n+        privateKeyFormat: origin.privateKeyFormat,\n+        privateKey: origin.privateKey,\n+        algorithmName: origin.algorithmName,\n+        namedCurve: origin.namedCurve,\n+        hashName: origin.hashName,\n+        plaintext: copyUint8Array(origin.plaintext), // Uint8Array\n+        signature: copyUint8Array(origin.signature), // Uint8Array\n+    }\n+}\n+\n+function copyUint8Array(a) {\n+    return new Uint8Array(a);\n+}\n\\ No newline at end of file\n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/tests/wpt-patches/WebCryptoAPI__sign_verify__rsa_pss_vectors.js.patch",
    "content": "diff --git a/WebCryptoAPI/sign_verify/rsa.js b/WebCryptoAPI/sign_verify/rsa.js\nindex 5abadd3d4..32a2e2851 100644\n--- a/WebCryptoAPI/sign_verify/rsa.js\n+++ b/WebCryptoAPI/sign_verify/rsa.js\n@@ -13,13 +13,22 @@ function run_test() {\n \n     // Test verification first, because signing tests rely on that working\n     testVectors.forEach(function(vector) {\n+        // k6/Go throws error for RSA-PSS with saltLength=0\n+        const expectsGoError = vector.algorithm.name === \"RSA-PSS\" && vector.algorithm.saltLength === 0;\n         var promise = importVectorKeys(vector, [\"verify\"], [\"sign\"])\n         .then(function(vectors) {\n             promise_test(function(test) {\n                 var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, vector.plaintext)\n                 .then(function(is_verified) {\n+                    if (expectsGoError) {\n+                        assert_unreached(\"Expected Go error for RSA-PSS saltLength=0, but verify succeeded for \" + vector.name);\n+                    }\n                     assert_true(is_verified, \"Signature verified\");\n                 }, function(err) {\n+                    if (expectsGoError) {\n+                        assert_equals(err.name, \"ImplementationError\", \"Go throws ImplementationError for RSA-PSS saltLength=0\");\n+                        return;\n+                    }\n                     assert_unreached(\"Verification should not throw error \" + vector.name + \": \" + err.message + \"'\");\n                 });\n \n@@ -39,14 +48,22 @@ function run_test() {\n \n     // Test verification with an altered buffer after call\n     testVectors.forEach(function(vector) {\n+        const expectsGoError = vector.algorithm.name === \"RSA-PSS\" && vector.algorithm.saltLength === 0;\n         var promise = importVectorKeys(vector, [\"verify\"], [\"sign\"])\n         .then(function(vectors) {\n             promise_test(function(test) {\n                 var signature = copyBuffer(vector.signature);\n                 var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)\n                 .then(function(is_verified) {\n+                    if (expectsGoError) {\n+                        assert_unreached(\"Expected Go error for RSA-PSS saltLength=0, but verify succeeded for \" + vector.name);\n+                    }\n                     assert_true(is_verified, \"Signature verified\");\n                 }, function(err) {\n+                    if (expectsGoError) {\n+                        assert_equals(err.name, \"ImplementationError\", \"Go throws ImplementationError for RSA-PSS saltLength=0\");\n+                        return;\n+                    }\n                     assert_unreached(\"Verification should not throw error \" + vector.name + \": \" + err.message + \"'\");\n                 });\n \n@@ -64,14 +81,22 @@ function run_test() {\n \n     // Check for successful verification even if plaintext is altered after call.\n     testVectors.forEach(function(vector) {\n+        const expectsGoError = vector.algorithm.name === \"RSA-PSS\" && vector.algorithm.saltLength === 0;\n         var promise = importVectorKeys(vector, [\"verify\"], [\"sign\"])\n         .then(function(vectors) {\n             promise_test(function(test) {\n                 var plaintext = copyBuffer(vector.plaintext);\n                 var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext)\n                 .then(function(is_verified) {\n+                    if (expectsGoError) {\n+                        assert_unreached(\"Expected Go error for RSA-PSS saltLength=0, but verify succeeded for \" + vector.name);\n+                    }\n                     assert_true(is_verified, \"Signature verified\");\n                 }, function(err) {\n+                    if (expectsGoError) {\n+                        assert_equals(err.name, \"ImplementationError\", \"Go throws ImplementationError for RSA-PSS saltLength=0\");\n+                        return;\n+                    }\n                     assert_unreached(\"Verification should not throw error \" + vector.name + \": \" + err.message + \"'\");\n                 });\n \n@@ -157,11 +182,16 @@ function run_test() {\n     testVectors.forEach(function(vector) {\n         // RSA signing is deterministic with PKCS#1 v1.5, or PSS with zero-length salts.\n         const isDeterministic = !(\"saltLength\" in vector.algorithm) || vector.algorithm.saltLength == 0;\n+        // k6/Go throws error for RSA-PSS with saltLength=0\n+        const expectsGoError = vector.algorithm.name === \"RSA-PSS\" && vector.algorithm.saltLength === 0;\n         var promise = importVectorKeys(vector, [\"verify\"], [\"sign\"])\n         .then(function(vectors) {\n             promise_test(function(test) {\n                 return subtle.sign(vector.algorithm, vector.privateKey, vector.plaintext)\n                 .then(function(signature) {\n+                    if (expectsGoError) {\n+                        assert_unreached(\"Expected Go error for RSA-PSS saltLength=0, but signing succeeded for \" + vector.name);\n+                    }\n                     if (isDeterministic) {\n                         // If deterministic, we can check the output matches. Otherwise, we can only check it verifies.\n                         assert_true(equalBuffers(signature, vector.signature), \"Signing did not give the expected output\");\n@@ -188,6 +218,11 @@ function run_test() {\n                         assert_unreached(\"second time verify error for test \" + vector.name + \": '\" + err.message + \"'\");\n                     });\n                 }, function(err) {\n+                    // For RSA-PSS with saltLength=0, Go throws ImplementationError - expected\n+                    if (expectsGoError) {\n+                        assert_equals(err.name, \"ImplementationError\", \"Go throws ImplementationError for RSA-PSS saltLength=0\");\n+                        return;\n+                    }\n                     assert_unreached(\"sign error for test \" + vector.name + \": '\" + err.message + \"'\");\n                 });\n             }, vector.name + \" round trip\");\n@@ -280,6 +315,7 @@ function run_test() {\n \n     // Verification should fail with wrong signature\n     testVectors.forEach(function(vector) {\n+        const expectsGoError = vector.algorithm.name === \"RSA-PSS\" && vector.algorithm.saltLength === 0;\n         var promise = importVectorKeys(vector, [\"verify\"], [\"sign\"])\n         .then(function(vectors) {\n             promise_test(function(test) {\n@@ -287,8 +323,15 @@ function run_test() {\n                 signature[0] = 255 - signature[0];\n                 var operation = subtle.verify(vector.algorithm, vector.publicKey, signature, vector.plaintext)\n                 .then(function(is_verified) {\n+                    if (expectsGoError) {\n+                        assert_unreached(\"Expected Go error for RSA-PSS saltLength=0, but verify succeeded for \" + vector.name);\n+                    }\n                     assert_false(is_verified, \"Signature NOT verified\");\n                 }, function(err) {\n+                    if (expectsGoError) {\n+                        assert_equals(err.name, \"ImplementationError\", \"Go throws ImplementationError for RSA-PSS saltLength=0\");\n+                        return;\n+                    }\n                     assert_unreached(\"Verification should not throw error \" + vector.name + \": \" + err.message + \"'\");\n                 });\n \n@@ -337,6 +380,7 @@ function run_test() {\n \n     // Verification should fail with wrong plaintext\n     testVectors.forEach(function(vector) {\n+        const expectsGoError = vector.algorithm.name === \"RSA-PSS\" && vector.algorithm.saltLength === 0;\n         var promise = importVectorKeys(vector, [\"verify\"], [\"sign\"])\n         .then(function(vectors) {\n             promise_test(function(test) {\n@@ -344,8 +388,15 @@ function run_test() {\n                 plaintext[0] = 255 - plaintext[0];\n                 var operation = subtle.verify(vector.algorithm, vector.publicKey, vector.signature, plaintext)\n                 .then(function(is_verified) {\n+                    if (expectsGoError) {\n+                        assert_unreached(\"Expected Go error for RSA-PSS saltLength=0, but verify succeeded for \" + vector.name);\n+                    }\n                     assert_false(is_verified, \"Signature NOT verified\");\n                 }, function(err) {\n+                    if (expectsGoError) {\n+                        assert_equals(err.name, \"ImplementationError\", \"Go throws ImplementationError for RSA-PSS saltLength=0\");\n+                        return;\n+                    }\n                     assert_unreached(\"Verification should not throw error \" + vector.name + \": \" + err.message + \"'\");\n                 });\n \n"
  },
  {
    "path": "internal/js/modules/k6/webcrypto/types.go",
    "content": "package webcrypto\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// bitLength is a type alias for the length of a bits collection.\ntype bitLength int\n\n// asByteLength returns the length of the bits collection in bytes.\nfunc (b bitLength) asByteLength() byteLength {\n\treturn byteLength(b) / 8\n}\n\n// byteLength is a type alias for the length of a byte slice.\ntype byteLength int\n\n// asBitLength returns the length of the byte slice in bits.\nfunc (b byteLength) asBitLength() bitLength {\n\treturn bitLength(b) * 8\n}\n\n// ToBytes tries to return a byte slice from compatible types.\nfunc ToBytes(data any) ([]byte, error) {\n\tswitch dt := data.(type) {\n\tcase []byte:\n\t\treturn dt, nil\n\tcase string:\n\t\treturn []byte(dt), nil\n\tcase sobek.ArrayBuffer:\n\t\treturn dt.Bytes(), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid type %T, expected string, []byte or ArrayBuffer\", data)\n\t}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/autobahn_tests/README.md",
    "content": "# Autobahn test suite\n\nDocs: https://github.com/crossbario/autobahn-testsuite\n\n## Usage\n\nRun the WebSocket server.\n\n```sh\n$ docker run -it --rm \\\n    -v ${PWD}/config:/config \\\n    -v ${PWD}/reports:/reports \\\n    -p 9001:9001 \\\n    -p 8080:8080 \\\n    --name fuzzingserver \\\n    crossbario/autobahn-testsuite\n```\n\nRun the autobahn client test with k6.\n\n```sh\n./k6 run ./script.js\n```\n\nOpen the browser to `http://localhost:8080` for checking the report.\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/autobahn_tests/config/fuzzingserver.json",
    "content": "{\n    \"url\": \"ws://127.0.0.1:9001\",\n    \"outdir\": \"./reports/clients\",\n    \"cases\": [\"*\"],\n    \"exclude-cases\": [\n        \"9.*\",\n        \"12.*\",\n        \"13.*\"\n    ],\n    \"exclude-agent-cases\": {}\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/autobahn_tests/reports/.gitkeep",
    "content": ""
  },
  {
    "path": "internal/js/modules/k6/websockets/autobahn_tests/script.js",
    "content": "import { WebSocket } from \"k6/x/websockets\"\nimport { sleep, check } from \"k6\"\nimport exec from 'k6/execution'\n\nexport let options = {\n\titerations: 247, // get this value from the Autobahn server\n\tvus: 3,\n}\n\nconst base = `ws://127.0.0.1:9001`\nconst agent = \"k6v383\"\n\nexport default function() {\n\tlet testCase = exec.scenario.iterationInTest+1\n\tlet url = `${base}/runCase?case=${testCase}&agent=${agent}`;\n\tlet ws = new WebSocket(url);\n\n\tws.addEventListener(\"open\", () => {\n\t\tconsole.log(`Testing case #${testCase}`)\n\t});\n\n\tws.addEventListener(\"message\", (e) => {\n\t\tif (e.event === 'ERROR') {\n\t\t\tconsole.log(`VU ${__VU}: test: #${testCase} error:`, e.data, `and message:`, e.message)\n\t\t\treturn\n\t\t}\n\t\tws.send(e.data)\n\t})\n\n\tws.addEventListener(\"error\", (e) => {\n\t\tconsole.error(`test: #${testCase} error:`, e)\n\t\tws.close()\n\t})\n}\n\nexport function teardown() {\n\tlet ws = new WebSocket(`${base}/updateReports?agent=${agent}`)\n\tws.addEventListener(\"open\", (e) => {\n\t\tconsole.log(\"Updating the report\")\n\t});\n\n\tws.addEventListener(\"error\", (e) => {\n\t\tconsole.error(\"Updating the report failed:\", e)\n\t\tws.close()\n\t});\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/blob.go",
    "content": "package websockets\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/experimental/streams\"\n\t\"go.k6.io/k6/js/common\"\n)\n\ntype blob struct {\n\ttyp  string\n\tdata *bytes.Buffer\n}\n\nfunc (b *blob) text() string {\n\treturn b.data.String()\n}\n\nfunc (r *WebSocketsAPI) blob(call sobek.ConstructorCall) *sobek.Object {\n\trt := r.vu.Runtime()\n\n\tb := &blob{data: new(bytes.Buffer)}\n\tvar blobParts []any\n\tif len(call.Arguments) > 0 {\n\t\tif err := rt.ExportTo(call.Arguments[0], &blobParts); err != nil {\n\t\t\tcommon.Throw(rt, fmt.Errorf(\"failed to process [blobParts]: %w\", err))\n\t\t}\n\t}\n\n\tif len(blobParts) > 0 {\n\t\tr.fillData(b, blobParts, call)\n\t}\n\n\tif len(call.Arguments) > 1 && !sobek.IsUndefined(call.Arguments[1]) {\n\t\topts := call.Arguments[1]\n\t\tif !isObject(opts) {\n\t\t\tcommon.Throw(rt, errors.New(\"[options] must be an object\"))\n\t\t}\n\n\t\ttypeOpt := opts.ToObject(rt).Get(\"type\")\n\t\tif !sobek.IsUndefined(typeOpt) {\n\t\t\tb.typ = typeOpt.String()\n\t\t}\n\t}\n\n\tobj := rt.NewObject()\n\tmust(rt, obj.DefineAccessorProperty(\"size\", rt.ToValue(func() sobek.Value {\n\t\treturn rt.ToValue(b.data.Len())\n\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, obj.DefineAccessorProperty(\"type\", rt.ToValue(func() sobek.Value {\n\t\treturn rt.ToValue(b.typ)\n\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\n\tmust(rt, obj.Set(\"arrayBuffer\", func(_ sobek.FunctionCall) sobek.Value {\n\t\tpromise, resolve, _ := rt.NewPromise()\n\t\terr := resolve(rt.NewArrayBuffer(b.data.Bytes()))\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn rt.ToValue(promise)\n\t}))\n\tmust(rt, obj.Set(\"bytes\", func(_ sobek.FunctionCall) sobek.Value {\n\t\tpromise, resolve, reject := rt.NewPromise()\n\t\tdata, err := rt.New(rt.Get(\"Uint8Array\"), rt.ToValue(b.data.Bytes()))\n\t\tif err == nil {\n\t\t\terr = resolve(data)\n\t\t} else {\n\t\t\terr = reject(fmt.Errorf(\"failed to create Uint8Array: %w\", err))\n\t\t}\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn rt.ToValue(promise)\n\t}))\n\tmust(rt, obj.Set(\"slice\", func(call sobek.FunctionCall) sobek.Value {\n\t\treturn r.slice(call, b, rt)\n\t}))\n\tmust(rt, obj.Set(\"text\", func(_ sobek.FunctionCall) sobek.Value {\n\t\tpromise, resolve, _ := rt.NewPromise()\n\t\terr := resolve(b.text())\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn rt.ToValue(promise)\n\t}))\n\tmust(rt, obj.Set(\"stream\", func(_ sobek.FunctionCall) sobek.Value {\n\t\treturn rt.ToValue(streams.NewReadableStreamFromReader(r.vu, b.data))\n\t}))\n\n\tproto := call.This.Prototype()\n\tmust(rt, proto.Set(\"toString\", func(_ sobek.FunctionCall) sobek.Value {\n\t\treturn rt.ToValue(\"[object Blob]\")\n\t}))\n\tmust(rt, obj.SetPrototype(proto))\n\n\treturn obj\n}\n\nfunc (r *WebSocketsAPI) fillData(b *blob, blobParts []any, call sobek.ConstructorCall) {\n\trt := r.vu.Runtime()\n\n\tif len(blobParts) > 0 {\n\t\tfor n, part := range blobParts {\n\t\t\tvar err error\n\t\t\tswitch v := part.(type) {\n\t\t\tcase []uint8:\n\t\t\t\t_, err = b.data.Write(v)\n\t\t\tcase []int8, []int16, []int32, []int64, []uint16, []uint32, []uint64, []float32, []float64:\n\t\t\t\terr = binary.Write(b.data, binary.LittleEndian, v)\n\t\t\tcase sobek.ArrayBuffer:\n\t\t\t\t_, err = b.data.Write(v.Bytes())\n\t\t\tcase *sobek.ArrayBuffer:\n\t\t\t\t_, err = b.data.Write(v.Bytes())\n\t\t\tcase string:\n\t\t\t\t_, err = b.data.WriteString(v)\n\t\t\tcase map[string]any:\n\t\t\t\tobj := call.Arguments[0].ToObject(rt).Get(strconv.FormatInt(int64(n), 10)).ToObject(rt)\n\t\t\t\tswitch {\n\t\t\t\tcase isDataView(obj, rt):\n\t\t\t\t\t_, err = b.data.Write(obj.Get(\"buffer\").Export().(sobek.ArrayBuffer).Bytes()) //nolint:forcetypeassert\n\t\t\t\tcase isBlob(obj, r.blobConstructor):\n\t\t\t\t\t_, err = b.data.Write(extractBytes(obj, rt))\n\t\t\t\tdefault:\n\t\t\t\t\terr = fmt.Errorf(\"unsupported type: %T\", part)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\terr = fmt.Errorf(\"unsupported type: %T\", part)\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tcommon.Throw(rt, fmt.Errorf(\"failed to process [blobParts]: %w\", err))\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (r *WebSocketsAPI) slice(call sobek.FunctionCall, b *blob, rt *sobek.Runtime) sobek.Value {\n\tvar (\n\t\tfrom int\n\t\tto   = b.data.Len()\n\t\tct   = \"\"\n\t)\n\n\tif len(call.Arguments) > 0 {\n\t\tfrom = int(call.Arguments[0].ToInteger())\n\t}\n\n\tif len(call.Arguments) > 1 {\n\t\tto = int(call.Arguments[1].ToInteger())\n\t\tif to < 0 {\n\t\t\tto = b.data.Len() + to\n\t\t}\n\t}\n\n\tif len(call.Arguments) > 2 {\n\t\tct = call.Arguments[2].String()\n\t}\n\n\topts := rt.NewObject()\n\tmust(rt, opts.Set(\"type\", ct))\n\n\tsliced, err := rt.New(r.blobConstructor, rt.ToValue([]any{b.data.Bytes()[from:to]}), opts)\n\tmust(rt, err)\n\n\treturn sliced\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/blob_test.go",
    "content": "package websockets\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBlob(t *testing.T) {\n\tt.Parallel()\n\n\ttcs := map[string]struct {\n\t\tblobPartsDef  string\n\t\tbytesExpected []byte\n\t}{\n\t\t\"String\": {\n\t\t\tblobPartsDef:  `[\"PASS\"]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"MultipleStrings\": {\n\t\t\tblobPartsDef:  `[\"P\", \"A\", \"SS\"]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"ArrayBuffer\": {\n\t\t\tblobPartsDef:  `[new Uint8Array([0x50, 0x41, 0x53, 0x53]).buffer]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Int8Array\": {\n\t\t\tblobPartsDef:  `[new Int8Array([0x50, 0x41, 0x53, 0x53])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Uint8Array\": {\n\t\t\tblobPartsDef:  `[new Uint8Array([0x50, 0x41, 0x53, 0x53])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Uint8ClampedArray\": {\n\t\t\tblobPartsDef:  `[new Uint8ClampedArray([0x50, 0x41, 0x53, 0x53])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Int16Array\": {\n\t\t\tblobPartsDef:  `[new Int16Array([0x4150, 0x5353])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Uint16Array\": {\n\t\t\tblobPartsDef:  `[new Uint16Array([0x4150, 0x5353])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Int32Array\": {\n\t\t\tblobPartsDef:  `[new Int32Array([0x53534150])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Uint32Array\": {\n\t\t\tblobPartsDef:  `[new Uint32Array([0x53534150])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Float32Array\": {\n\t\t\tblobPartsDef:  `[new Float32Array(new Uint8Array([0x50, 0x41, 0x53, 0x53]).buffer)]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Float64Array\": {\n\t\t\t// Byte length of Float64Array should be a multiple of 8\n\t\t\tblobPartsDef:  `[new Float64Array(new Uint8Array([0x50, 0x41, 0x53, 0x53, 0x00, 0x00, 0x00, 0x00]).buffer)]`,\n\t\t\tbytesExpected: append([]byte(\"PASS\"), 0x0, 0x0, 0x0, 0x0),\n\t\t},\n\t\t\"DataView\": {\n\t\t\tblobPartsDef:  `[new DataView(new Int8Array([0x50, 0x41, 0x53, 0x53]).buffer)]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"Blob\": {\n\t\t\tblobPartsDef:  `[new Blob([\"PASS\"])]`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t}\n\n\tfor name, tc := range tcs {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestState(t)\n\t\t\tval, err := ts.runtime.RunOnEventLoop(fmt.Sprintf(`\n\t\t\t\t(async () => {\n\t\t\t\t\tconst blobParts = %s;\n\t\t\t\t\tconst blob = new Blob(blobParts);\n\t\t  \t\t\treturn blob.arrayBuffer();\n\t\t\t\t})()\n\t\t\t`, tc.blobPartsDef))\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tp, ok := val.Export().(*sobek.Promise)\n\t\t\trequire.True(t, ok)\n\n\t\t\tab, ok := p.Result().Export().(sobek.ArrayBuffer)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.Equal(t, tc.bytesExpected, ab.Bytes())\n\t\t})\n\t}\n}\n\nfunc TestBlob_type(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\trt := ts.runtime.VU.Runtime()\n\tval, err := ts.runtime.RunOnEventLoop(`\n\t\tnew Blob([\"PASS\"], { type: \"text/example\" });\n\t`)\n\trequire.NoError(t, err)\n\trequire.True(t, isBlob(val.ToObject(rt), ts.module.blobConstructor))\n\trequire.Equal(t, \"text/example\", val.ToObject(rt).Get(\"type\").String())\n}\n\nfunc TestBlob_size(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\trt := ts.runtime.VU.Runtime()\n\tval, err := ts.runtime.RunOnEventLoop(`\n\t\tnew Blob([\"PASS\"]);\n\t`)\n\trequire.NoError(t, err)\n\trequire.True(t, isBlob(val.ToObject(rt), ts.module.blobConstructor))\n\trequire.Equal(t, int64(4), val.ToObject(rt).Get(\"size\").ToInteger())\n}\n\nfunc TestBlob_arrayBuffer(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tval, err := ts.runtime.RunOnEventLoop(`\n\t\t(async () => {\n\t\t\tconst blob = new Blob([\"P\", \"A\", \"SS\"]);\n\t\t\treturn blob.arrayBuffer();\n\t\t})()\n\t`)\n\trequire.NoError(t, err)\n\n\tp, ok := val.Export().(*sobek.Promise)\n\trequire.True(t, ok)\n\n\tab, ok := p.Result().Export().(sobek.ArrayBuffer)\n\trequire.True(t, ok)\n\trequire.Equal(t, []byte(\"PASS\"), ab.Bytes())\n}\n\nfunc TestBlob_bytes(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tval, err := ts.runtime.RunOnEventLoop(`\n\t\t(async () => {\n\t\t\tconst blob = new Blob([\"P\", \"A\", \"SS\"]);\n\t\t\treturn blob.bytes();\n\t\t})()\n\t`)\n\trequire.NoError(t, err)\n\n\tp, ok := val.Export().(*sobek.Promise)\n\trequire.True(t, ok)\n\n\trt := ts.runtime.VU.Runtime()\n\tres := p.Result().ToObject(rt)\n\trequire.True(t, isUint8Array(res, rt))\n\n\tvar resBytes []byte\n\trequire.NoError(t, rt.ExportTo(res.Get(\"buffer\"), &resBytes))\n\trequire.Equal(t, []byte(\"PASS\"), resBytes)\n}\n\nfunc TestBlob_slice(t *testing.T) {\n\tt.Parallel()\n\n\ttcs := map[string]struct {\n\t\tcall          string\n\t\tbytesExpected []byte\n\t\tctExpected    string\n\t}{\n\t\t\"slice()\": {\n\t\t\tcall:          `slice()`,\n\t\t\tbytesExpected: []byte(\"PASS\"),\n\t\t},\n\t\t\"slice(start)\": {\n\t\t\tcall:          `slice(1)`,\n\t\t\tbytesExpected: []byte(\"ASS\"),\n\t\t},\n\t\t\"slice(start, end)\": {\n\t\t\tcall:          `slice(0,1)`,\n\t\t\tbytesExpected: []byte(\"P\"),\n\t\t},\n\t\t\"slice(start, end, contentType)\": {\n\t\t\tcall:          `slice(0,1,\"text/example\")`,\n\t\t\tbytesExpected: []byte(\"P\"),\n\t\t\tctExpected:    \"text/example\",\n\t\t},\n\t}\n\n\tfor name, tc := range tcs {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestState(t)\n\t\t\tval, err := ts.runtime.RunOnEventLoop(fmt.Sprintf(`\n\t\t\t\t(async () => {\n\t\t\t\t\tconst blob = new Blob([\"PASS\"]);\n\t\t\t\t\treturn blob.%s;\n\t\t\t\t})()\n\t\t\t`, tc.call))\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tp, ok := val.Export().(*sobek.Promise)\n\t\t\trequire.True(t, ok)\n\n\t\t\trt := ts.runtime.VU.Runtime()\n\t\t\tassertBlobTypeAndContents(t, ts, p.Result().ToObject(rt), tc.ctExpected, tc.bytesExpected)\n\t\t})\n\t}\n}\n\nfunc assertBlobTypeAndContents(t *testing.T, ts testState, blob *sobek.Object, expType string, expContents []byte) {\n\tt.Helper()\n\n\t// First, we assert the given object is 'instanceof' Blob.\n\trequire.True(t, isBlob(blob, ts.module.blobConstructor))\n\n\t// Then, we assert the type of the blob.\n\trequire.Equal(t, expType, blob.Get(\"type\").String())\n\n\t// Finally, we assert the contents of the blob, by calling `.arrayBuffer()`\n\t// and comparing the result with the expected contents.\n\tcall, ok := sobek.AssertFunction(blob.Get(\"arrayBuffer\"))\n\trequire.True(t, ok)\n\n\tret, err := call(sobek.Undefined())\n\trequire.NoError(t, err)\n\tp, ok := ret.Export().(*sobek.Promise)\n\trequire.True(t, ok)\n\n\tab, ok := p.Result().Export().(sobek.ArrayBuffer)\n\trequire.True(t, ok)\n\trequire.Equal(t, expContents, ab.Bytes())\n}\n\nfunc TestBlob_text(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tval, err := ts.runtime.RunOnEventLoop(`\n\t\t(async () => {\n\t\t\tconst blob = new Blob([\"P\", \"A\", \"SS\"]);\n\t\t\treturn blob.text();\n\t\t})()\n\t`)\n\trequire.NoError(t, err)\n\n\tp, ok := val.Export().(*sobek.Promise)\n\trequire.True(t, ok)\n\n\trequire.Equal(t, \"PASS\", p.Result().String())\n}\n\nfunc TestBlob_stream(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tval, err := ts.runtime.RunOnEventLoop(`\n\t\t(async () => {\n\t\t  const blob = new Blob([\"P\", \"A\", \"SS\"]);\n\t\t  const reader = blob.stream().getReader();\n\t\t  const {value} = await reader.read();\n\t\t  return value;\n\t\t})()\n\t`)\n\trequire.NoError(t, err)\n\n\tp, ok := val.Export().(*sobek.Promise)\n\trequire.True(t, ok)\n\trequire.Equal(t, \"PASS\", p.Result().String())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/events/events.go",
    "content": "// Package events represent the events that can be sent to the client\n// https://dom.spec.whatwg.org/#event\npackage events\n\nconst (\n\t// OPEN is the event name for the open event\n\tOPEN = \"open\"\n\t// CLOSE is the event name for the close event\n\tCLOSE = \"close\"\n\t// MESSAGE is the event name for the message event\n\tMESSAGE = \"message\"\n\t// ERROR is the event name for the error event\n\tERROR = \"error\"\n\t// PING is the event name for the ping event\n\tPING = \"ping\"\n\t// PONG is the event name for the pong event\n\tPONG = \"pong\"\n)\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/helpers.go",
    "content": "package websockets\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n)\n\n// must is a small helper that will panic if err is not nil.\nfunc must(rt *sobek.Runtime, err error) {\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n}\n\nfunc isString(o *sobek.Object, rt *sobek.Runtime) bool {\n\treturn o.Prototype().Get(\"constructor\") == rt.GlobalObject().Get(\"String\")\n}\n\nfunc isArray(o *sobek.Object, rt *sobek.Runtime) bool {\n\treturn o.Prototype().Get(\"constructor\") == rt.GlobalObject().Get(\"Array\")\n}\n\nfunc isUint8Array(o *sobek.Object, rt *sobek.Runtime) bool {\n\treturn o.Prototype().Get(\"constructor\") == rt.GlobalObject().Get(\"Uint8Array\")\n}\n\nfunc isDataView(o *sobek.Object, rt *sobek.Runtime) bool {\n\treturn o.Prototype().Get(\"constructor\") == rt.GlobalObject().Get(\"DataView\")\n}\n\nfunc isBlob(o *sobek.Object, blobConstructor sobek.Value) bool {\n\treturn o.Prototype().Get(\"constructor\") == blobConstructor\n}\n\nfunc isObject(val sobek.Value) bool {\n\treturn val != nil && val.ExportType() != nil && val.ExportType().Kind() == reflect.Map\n}\n\nfunc extractBytes(o *sobek.Object, rt *sobek.Runtime) []byte {\n\tarrayBuffer, ok := sobek.AssertFunction(o.Get(\"arrayBuffer\"))\n\tif !ok {\n\t\tcommon.Throw(rt, errors.New(\"Blob.[arrayBuffer] is not a function\"))\n\t}\n\n\tbuffer, err := arrayBuffer(sobek.Undefined())\n\tif err != nil {\n\t\tcommon.Throw(rt, fmt.Errorf(\"call to Blob.[arrayBuffer] failed: %w\", err))\n\t}\n\n\tp, ok := buffer.Export().(*sobek.Promise)\n\tif !ok {\n\t\tcommon.Throw(rt, errors.New(\"Blob.[arrayBuffer] return is not a Promise\"))\n\t}\n\n\tab, ok := p.Result().Export().(sobek.ArrayBuffer)\n\tif !ok {\n\t\tcommon.Throw(rt, errors.New(\"Blob.[arrayBuffer] promise's return is not an ArrayBuffer\"))\n\t}\n\n\treturn ab.Bytes()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/listeners.go",
    "content": "package websockets\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/internal/js/modules/k6/websockets/events\"\n)\n\n// eventListeners keeps track of the eventListeners for each event type\ntype eventListeners struct {\n\topen    *eventListener\n\tmessage *eventListener\n\terror   *eventListener\n\tclose   *eventListener\n\tping    *eventListener\n\tpong    *eventListener\n}\n\nfunc newEventListeners() *eventListeners {\n\treturn &eventListeners{\n\t\topen:    newListener(events.OPEN),\n\t\tmessage: newListener(events.MESSAGE),\n\t\terror:   newListener(events.ERROR),\n\t\tclose:   newListener(events.CLOSE),\n\t\tping:    newListener(events.PING),\n\t\tpong:    newListener(events.PONG),\n\t}\n}\n\n// eventListener represents a tuple of listeners of a certain type\n// property on represents the eventListener that serves for the on* properties, like onopen, onmessage, etc.\n// property list keeps any other listeners that were added with addEventListener\ntype eventListener struct {\n\teventType string\n\n\t// this return sobek.value *and* error in order to return error on exception instead of panic\n\t// https://pkg.go.dev/github.com/dop251/goja#hdr-Functions\n\ton   func(sobek.Value) (sobek.Value, error)\n\tlist []func(sobek.Value) (sobek.Value, error)\n}\n\n// newListener creates a new listener of a certain type\nfunc newListener(eventType string) *eventListener {\n\treturn &eventListener{\n\t\teventType: eventType,\n\t}\n}\n\n// add adds a listener to the listener list\nfunc (l *eventListener) add(fn func(sobek.Value) (sobek.Value, error)) {\n\tl.list = append(l.list, fn)\n}\n\n// setOn sets a listener for the on* properties, like onopen, onmessage, etc.\nfunc (l *eventListener) setOn(fn func(sobek.Value) (sobek.Value, error)) {\n\tl.on = fn\n}\n\n// getOn returns the on* property for a certain event type\nfunc (l *eventListener) getOn() func(sobek.Value) (sobek.Value, error) {\n\treturn l.on\n}\n\n// return all possible listeners for a certain event type\nfunc (l *eventListener) all() []func(sobek.Value) (sobek.Value, error) {\n\tif l.on == nil {\n\t\treturn l.list\n\t}\n\n\treturn append([]func(sobek.Value) (sobek.Value, error){l.on}, l.list...)\n}\n\n// getTypes return event listener of a certain type\nfunc (l *eventListeners) getType(t string) *eventListener {\n\tswitch t {\n\tcase events.OPEN:\n\t\treturn l.open\n\tcase events.MESSAGE:\n\t\treturn l.message\n\tcase events.ERROR:\n\t\treturn l.error\n\tcase events.CLOSE:\n\t\treturn l.close\n\tcase events.PING:\n\t\treturn l.ping\n\tcase events.PONG:\n\t\treturn l.pong\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// add adds a listener to the listeners\nfunc (l *eventListeners) add(t string, f func(sobek.Value) (sobek.Value, error)) error {\n\tlist := l.getType(t)\n\n\tif list == nil {\n\t\treturn fmt.Errorf(\"unknown event type: %s\", t)\n\t}\n\n\tlist.add(f)\n\n\treturn nil\n}\n\n// all returns all possible listeners for a certain event type or an empty array\nfunc (l *eventListeners) all(t string) []func(sobek.Value) (sobek.Value, error) {\n\tlist := l.getType(t)\n\n\tif list == nil {\n\t\treturn []func(sobek.Value) (sobek.Value, error){}\n\t}\n\n\treturn list.all()\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/main_test.go",
    "content": "package websockets\n\nimport (\n\t\"testing\"\n\n\t\"go.uber.org/goleak\"\n)\n\nfunc TestMain(m *testing.M) {\n\tgoleak.VerifyTestMain(m)\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/params.go",
    "content": "package websockets\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\thttpModule \"go.k6.io/k6/js/modules/k6/http\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// wsParams represent the parameters bag for websocket\ntype wsParams struct {\n\theaders           http.Header\n\tcookieJar         *cookiejar.Jar\n\ttagsAndMeta       *metrics.TagsAndMeta\n\tenableCompression bool\n\tsubprocotols      []string\n}\n\n// buildParams builds WebSocket params and configure some of them\nfunc buildParams(state *lib.State, rt *sobek.Runtime, raw sobek.Value) (*wsParams, error) {\n\ttagsAndMeta := state.Tags.GetCurrentValues()\n\n\tparsed := &wsParams{\n\t\theaders:     make(http.Header),\n\t\tcookieJar:   state.CookieJar,\n\t\ttagsAndMeta: &tagsAndMeta,\n\t}\n\n\tparsed.headers.Set(\"User-Agent\", state.Options.UserAgent.String)\n\n\tif common.IsNullish(raw) {\n\t\treturn parsed, nil\n\t}\n\n\tparams := raw.ToObject(rt)\n\tfor _, k := range params.Keys() {\n\t\tswitch k {\n\t\tcase \"headers\":\n\t\t\theadersV := params.Get(k)\n\t\t\tif common.IsNullish(headersV) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\theadersObj := headersV.ToObject(rt)\n\t\t\tif headersObj == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, key := range headersObj.Keys() {\n\t\t\t\tparsed.headers.Set(key, headersObj.Get(key).String())\n\t\t\t}\n\t\tcase \"tags\":\n\t\t\tif err := common.ApplyCustomUserTags(rt, parsed.tagsAndMeta, params.Get(k)); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid WebSocket tags option: %w\", err)\n\t\t\t}\n\t\tcase \"jar\":\n\t\t\tjarV := params.Get(k)\n\t\t\tif common.IsNullish(jarV) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif v, ok := jarV.Export().(*httpModule.CookieJar); ok {\n\t\t\t\tparsed.cookieJar = v.Jar\n\t\t\t}\n\t\tcase \"compression\":\n\t\t\t// deflate compression algorithm is supported - as defined in RFC7692\n\t\t\t// compression here relies on the implementation in gorilla/websocket package, usage is\n\t\t\t// experimental and may result in decreased performance. package supports\n\t\t\t// only \"no context takeover\" scenario\n\n\t\t\talgoString := strings.TrimSpace(params.Get(k).ToString().String())\n\t\t\tif algoString != \"deflate\" {\n\t\t\t\treturn nil, fmt.Errorf(\"unsupported compression algorithm '%s', supported algorithm is 'deflate'\", algoString)\n\t\t\t}\n\n\t\t\tparsed.enableCompression = true\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown WebSocket's option %s\", k)\n\t\t}\n\t}\n\n\treturn parsed, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/websockets.go",
    "content": "// Package websockets implements to some extend WebSockets API https://websockets.spec.whatwg.org\npackage websockets\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/grafana/sobek\"\n\t\"github.com/mstoykov/k6-taskqueue-lib/taskqueue\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/websockets/events\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// RootModule is the root module for the websockets API\ntype RootModule struct{}\n\n// WebSocketsAPI is the k6 extension implementing the websocket API as defined in https://websockets.spec.whatwg.org\ntype WebSocketsAPI struct { //nolint:revive\n\tvu              modules.VU\n\tblobConstructor sobek.Value\n}\n\nvar _ modules.Module = &RootModule{}\n\n// New websockets root module\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance returns a new instance of the module\nfunc (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\treturn &WebSocketsAPI{\n\t\tvu: vu,\n\t}\n}\n\n// Exports implements the modules.Instance interface's Exports\nfunc (r *WebSocketsAPI) Exports() modules.Exports {\n\tr.blobConstructor = r.vu.Runtime().ToValue(r.blob)\n\treturn modules.Exports{\n\t\tNamed: map[string]any{\n\t\t\t\"WebSocket\": r.websocket,\n\t\t\t\"Blob\":      r.blobConstructor,\n\t\t},\n\t}\n}\n\n// ReadyState is websocket specification's readystate\ntype ReadyState uint8\n\nconst (\n\t// CONNECTING is the state while the web socket is connecting\n\tCONNECTING ReadyState = iota\n\t// OPEN is the state after the websocket is established and before it starts closing\n\tOPEN\n\t// CLOSING is while the websocket is closing but is *not* closed yet\n\tCLOSING\n\t// CLOSED is when the websocket is finally closed\n\tCLOSED\n)\n\ntype webSocket struct {\n\tvu              modules.VU\n\tblobConstructor sobek.Value\n\n\turl            *url.URL\n\tconn           *websocket.Conn\n\ttagsAndMeta    *metrics.TagsAndMeta\n\ttq             *taskqueue.TaskQueue\n\tbuiltinMetrics *metrics.BuiltinMetrics\n\tobj            *sobek.Object // the object that is given to js to interact with the WebSocket\n\tstarted        time.Time\n\n\tdone         chan struct{}\n\twriteQueueCh chan message\n\n\teventListeners *eventListeners\n\n\tsendPings ping\n\n\t// fields that should be seen by js only be updated on the event loop\n\treadyState     ReadyState\n\tbufferedAmount int\n\tbinaryType     string\n\tprotocol       string\n\textensions     []string\n\n\t// fields for `close` event\n\tcloseCode   int\n\tcloseReason string\n}\n\ntype ping struct {\n\tcounter    int\n\ttimestamps map[string]time.Time\n}\n\nfunc (r *WebSocketsAPI) websocket(c sobek.ConstructorCall) *sobek.Object {\n\trt := r.vu.Runtime()\n\n\turl, err := parseURL(c.Argument(0))\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tparams, err := buildParams(r.vu.State(), rt, c.Argument(2))\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tsubprocotolsArg := c.Argument(1)\n\tif !common.IsNullish(subprocotolsArg) {\n\t\tsubprocotolsObj := subprocotolsArg.ToObject(rt)\n\t\tswitch {\n\t\tcase isString(subprocotolsObj, rt):\n\t\t\tparams.subprocotols = append(params.subprocotols, subprocotolsObj.String())\n\t\tcase isArray(subprocotolsObj, rt):\n\t\t\tfor _, key := range subprocotolsObj.Keys() {\n\t\t\t\tparams.subprocotols = append(params.subprocotols, subprocotolsObj.Get(key).String())\n\t\t\t}\n\t\t}\n\t}\n\n\tw := &webSocket{\n\t\tvu:              r.vu,\n\t\tblobConstructor: r.blobConstructor,\n\t\turl:             url,\n\t\ttq:              taskqueue.New(r.vu.RegisterCallback),\n\t\treadyState:      CONNECTING,\n\t\tbuiltinMetrics:  r.vu.State().BuiltinMetrics,\n\t\tdone:            make(chan struct{}),\n\t\twriteQueueCh:    make(chan message),\n\t\teventListeners:  newEventListeners(),\n\t\tobj:             rt.NewObject(),\n\t\ttagsAndMeta:     params.tagsAndMeta,\n\t\tsendPings:       ping{timestamps: make(map[string]time.Time)},\n\t\tbinaryType:      blobBinaryType,\n\t}\n\n\t// Maybe have this after the goroutine below ?!?\n\tdefineWebsocket(rt, w)\n\n\tgo w.establishConnection(params)\n\treturn w.obj\n}\n\n// parseURL parses the url from the first constructor calls argument or returns an error\nfunc parseURL(urlValue sobek.Value) (*url.URL, error) {\n\tif common.IsNullish(urlValue) {\n\t\treturn nil, errors.New(\"WebSocket requires a url\")\n\t}\n\n\t// TODO: throw the SyntaxError (https://websockets.spec.whatwg.org/#dom-websocket-websocket)\n\turlString := urlValue.String()\n\turl, err := url.Parse(urlString)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"WebSocket requires valid url, but got %q which resulted in %w\", urlString, err)\n\t}\n\tif url.Scheme != \"ws\" && url.Scheme != \"wss\" {\n\t\treturn nil, fmt.Errorf(\"WebSocket requires url with scheme ws or wss, but got %q\", url.Scheme)\n\t}\n\tif url.Fragment != \"\" {\n\t\treturn nil, fmt.Errorf(\"WebSocket requires no url fragment, but got %q\", url.Fragment)\n\t}\n\n\treturn url, nil\n}\n\nconst (\n\tarraybufferBinaryType = \"arraybuffer\"\n\tblobBinaryType        = \"blob\"\n)\n\n// defineWebsocket defines all properties and methods for the WebSocket\nfunc defineWebsocket(rt *sobek.Runtime, w *webSocket) {\n\tmust(rt, w.obj.DefineDataProperty(\n\t\t\"addEventListener\", rt.ToValue(w.addEventListener), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineDataProperty(\n\t\t\"send\", rt.ToValue(w.send), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineDataProperty(\n\t\t\"ping\", rt.ToValue(w.ping), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineDataProperty(\n\t\t\"close\", rt.ToValue(w.close), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineDataProperty(\n\t\t\"url\", rt.ToValue(w.url.String()), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineAccessorProperty( // this needs to be with an accessor as we change the value\n\t\t\"readyState\", rt.ToValue(func() sobek.Value {\n\t\t\treturn rt.ToValue((uint)(w.readyState))\n\t\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineAccessorProperty(\n\t\t\"bufferedAmount\", rt.ToValue(func() sobek.Value { return rt.ToValue(w.bufferedAmount) }), nil,\n\t\tsobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineAccessorProperty(\"extensions\",\n\t\trt.ToValue(func() sobek.Value { return rt.ToValue(w.extensions) }), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineAccessorProperty(\n\t\t\"protocol\", rt.ToValue(func() sobek.Value { return rt.ToValue(w.protocol) }), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, w.obj.DefineAccessorProperty(\n\t\t\"binaryType\", rt.ToValue(func() sobek.Value {\n\t\t\treturn rt.ToValue(w.binaryType)\n\t\t}), rt.ToValue(func(s string) error {\n\t\t\tswitch s {\n\t\t\tcase blobBinaryType, arraybufferBinaryType:\n\t\t\t\tw.binaryType = s\n\t\t\t\treturn nil\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(`unknown binaryType %s, the supported ones are \"blob\" and \"arraybuffer\"`, s)\n\t\t\t}\n\t\t}), sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\n\tsetOn := func(property string, el *eventListener) {\n\t\tif el == nil {\n\t\t\t// this is generally should not happen, but we're being defensive\n\t\t\tcommon.Throw(rt, fmt.Errorf(\"not supported on-handler '%s'\", property))\n\t\t}\n\n\t\tmust(rt, w.obj.DefineAccessorProperty(\n\t\t\tproperty, rt.ToValue(func() sobek.Value {\n\t\t\t\treturn rt.ToValue(el.getOn)\n\t\t\t}), rt.ToValue(func(call sobek.FunctionCall) sobek.Value {\n\t\t\t\targ := call.Argument(0)\n\n\t\t\t\t// it's possible to unset handlers by setting them to null\n\t\t\t\tif common.IsNullish(arg) {\n\t\t\t\t\tel.setOn(nil)\n\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\n\t\t\t\tfn, isFunc := sobek.AssertFunction(arg)\n\t\t\t\tif !isFunc {\n\t\t\t\t\tcommon.Throw(rt, fmt.Errorf(\"a value for '%s' should be callable\", property))\n\t\t\t\t}\n\n\t\t\t\tel.setOn(func(v sobek.Value) (sobek.Value, error) { return fn(sobek.Undefined(), v) })\n\n\t\t\t\treturn nil\n\t\t\t}), sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\t}\n\n\tsetOn(\"onmessage\", w.eventListeners.getType(events.MESSAGE))\n\tsetOn(\"onerror\", w.eventListeners.getType(events.ERROR))\n\tsetOn(\"onopen\", w.eventListeners.getType(events.OPEN))\n\tsetOn(\"onclose\", w.eventListeners.getType(events.CLOSE))\n\tsetOn(\"onping\", w.eventListeners.getType(events.PING))\n\tsetOn(\"onpong\", w.eventListeners.getType(events.PONG))\n}\n\ntype message struct {\n\tmtype int // message type consts as defined in gorilla/websocket/conn.go\n\tdata  []byte\n\tt     time.Time\n}\n\n// documented https://websockets.spec.whatwg.org/#concept-websocket-establish\nfunc (w *webSocket) establishConnection(params *wsParams) {\n\tstate := w.vu.State()\n\tw.started = time.Now()\n\tvar tlsConfig *tls.Config\n\tif state.TLSConfig != nil {\n\t\ttlsConfig = state.TLSConfig.Clone()\n\t\ttlsConfig.NextProtos = []string{\"http/1.1\"}\n\t}\n\t// technically we have to do a fetch request here, so ... uh do normal one ;)\n\twsd := websocket.Dialer{\n\t\tHandshakeTimeout: time.Second * 60, // TODO configurable\n\t\t// Pass a custom net.DialContext function to websocket.Dialer that will substitute\n\t\t// the underlying net.Conn with our own tracked netext.Conn\n\t\tNetDialContext:    state.Dialer.DialContext,\n\t\tProxy:             http.ProxyFromEnvironment,\n\t\tTLSClientConfig:   tlsConfig,\n\t\tEnableCompression: params.enableCompression,\n\t\tSubprotocols:      params.subprocotols,\n\t}\n\n\t// this is needed because of how interfaces work and that wsd.Jar is http.Cookiejar\n\tif params.cookieJar != nil {\n\t\twsd.Jar = params.cookieJar\n\t}\n\n\tctx := w.vu.Context()\n\tstart := time.Now()\n\tconn, httpResponse, connErr := wsd.DialContext(ctx, w.url.String(), params.headers)\n\tconnectionEnd := time.Now()\n\tconnectionDuration := metrics.D(connectionEnd.Sub(start))\n\n\tsystemTags := state.Options.SystemTags\n\n\tif conn != nil && conn.RemoteAddr() != nil {\n\t\tif ip, _, err := net.SplitHostPort(conn.RemoteAddr().String()); err == nil {\n\t\t\tw.tagsAndMeta.SetSystemTagOrMetaIfEnabled(systemTags, metrics.TagIP, ip)\n\t\t}\n\t}\n\n\tif httpResponse != nil {\n\t\tdefer func() {\n\t\t\t_ = httpResponse.Body.Close()\n\t\t}()\n\n\t\tw.tagsAndMeta.SetSystemTagOrMetaIfEnabled(systemTags, metrics.TagStatus, strconv.Itoa(httpResponse.StatusCode))\n\t\tif conn != nil {\n\t\t\tw.protocol = conn.Subprotocol()\n\t\t}\n\t\tw.extensions = httpResponse.Header.Values(\"Sec-WebSocket-Extensions\")\n\t\tw.tagsAndMeta.SetSystemTagOrMetaIfEnabled(systemTags, metrics.TagSubproto, w.protocol)\n\t}\n\tw.conn = conn\n\n\tnameTagValue, nameTagManuallySet := params.tagsAndMeta.Tags.Get(metrics.TagName.String())\n\t// After k6 v0.41.0, the `name` and `url` tags have the exact same values:\n\tif nameTagManuallySet {\n\t\tw.tagsAndMeta.SetSystemTagOrMetaIfEnabled(systemTags, metrics.TagURL, nameTagValue)\n\t} else {\n\t\tw.tagsAndMeta.SetSystemTagOrMetaIfEnabled(systemTags, metrics.TagURL, w.url.String())\n\t\tw.tagsAndMeta.SetSystemTagOrMetaIfEnabled(systemTags, metrics.TagName, w.url.String())\n\t}\n\n\tw.emitConnectionMetrics(ctx, start, connectionDuration)\n\tif connErr != nil {\n\t\t// Pass the error to the user script before exiting immediately\n\t\tw.tq.Queue(func() error {\n\t\t\treturn w.connectionClosedWithError(connErr)\n\t\t})\n\t\tw.tq.Close()\n\t\treturn\n\t}\n\tgo w.loop()\n\tw.tq.Queue(func() error {\n\t\treturn w.connectionConnected()\n\t})\n}\n\n// emitConnectionMetrics emits the metrics for a websocket connection.\nfunc (w *webSocket) emitConnectionMetrics(ctx context.Context, start time.Time, duration float64) {\n\tstate := w.vu.State()\n\n\tmetrics.PushIfNotDone(ctx, state.Samples, metrics.ConnectedSamples{\n\t\tSamples: []metrics.Sample{\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{Metric: state.BuiltinMetrics.WSSessions, Tags: w.tagsAndMeta.Tags},\n\t\t\t\tTime:       start,\n\t\t\t\tMetadata:   w.tagsAndMeta.Metadata,\n\t\t\t\tValue:      1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{Metric: state.BuiltinMetrics.WSConnecting, Tags: w.tagsAndMeta.Tags},\n\t\t\t\tTime:       start,\n\t\t\t\tMetadata:   w.tagsAndMeta.Metadata,\n\t\t\t\tValue:      duration,\n\t\t\t},\n\t\t},\n\t\tTags: w.tagsAndMeta.Tags,\n\t\tTime: start,\n\t})\n}\n\nconst writeWait = 10 * time.Second\n\nfunc (w *webSocket) loop() {\n\t// Pass ping/pong events through the main control loop\n\tpingChan := make(chan string)\n\tpongChan := make(chan string)\n\tw.conn.SetPingHandler(func(msg string) error { pingChan <- msg; return nil })\n\tw.conn.SetPongHandler(func(pingID string) error { pongChan <- pingID; return nil })\n\n\tctx := w.vu.Context()\n\twg := new(sync.WaitGroup)\n\n\tdefer func() {\n\t\tmetrics.PushIfNotDone(ctx, w.vu.State().Samples, metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: w.builtinMetrics.WSSessionDuration,\n\t\t\t\tTags:   w.tagsAndMeta.Tags,\n\t\t\t},\n\t\t\tTime:     time.Now(),\n\t\t\tMetadata: w.tagsAndMeta.Metadata,\n\t\t\tValue:    metrics.D(time.Since(w.started)),\n\t\t})\n\t\t_ = w.conn.Close()\n\t\twg.Wait()\n\t\tw.tq.Close()\n\t}()\n\twg.Add(2)\n\tgo w.readPump(wg)\n\tgo w.writePump(wg)\n\n\tctxDone := ctx.Done()\n\tfor {\n\t\tselect {\n\t\tcase <-ctxDone:\n\t\t\t// VU is shutting down during an interrupt\n\t\t\t// socket events will not be forwarded to the VU\n\t\t\tw.queueClose()\n\t\t\tctxDone = nil // this is to block this branch and get through w.done\n\t\tcase <-w.done:\n\t\t\treturn\n\t\tcase pingData := <-pingChan:\n\n\t\t\t// Handle pings received from the server\n\t\t\t// - trigger the `ping` event\n\t\t\t// - reply with pong (needed when `SetPingHandler` is overwritten)\n\t\t\t// WriteControl is okay to be concurrent so we don't need to gsend this over writeChannel\n\t\t\terr := w.conn.WriteControl(websocket.PongMessage, []byte(pingData), time.Now().Add(writeWait))\n\t\t\tw.tq.Queue(func() error {\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn w.callErrorListeners(err)\n\t\t\t\t}\n\n\t\t\t\treturn w.callEventListeners(events.PING)\n\t\t\t})\n\n\t\tcase pingID := <-pongChan:\n\t\t\tw.tq.Queue(func() error {\n\t\t\t\t// Handle pong responses to our pings\n\t\t\t\tw.trackPong(pingID)\n\n\t\t\t\treturn w.callEventListeners(events.PONG)\n\t\t\t})\n\t\t}\n\t}\n}\n\nfunc (w *webSocket) queueMessage(msg *message) {\n\tw.tq.Queue(func() error {\n\t\tif w.readyState != OPEN {\n\t\t\treturn nil // TODO maybe still emit\n\t\t}\n\t\t// TODO maybe emit after all the listeners have fired and skip it if defaultPrevent was called?!?\n\t\tmetrics.PushIfNotDone(w.vu.Context(), w.vu.State().Samples, metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: w.builtinMetrics.WSMessagesReceived,\n\t\t\t\tTags:   w.tagsAndMeta.Tags,\n\t\t\t},\n\t\t\tTime:     msg.t,\n\t\t\tMetadata: w.tagsAndMeta.Metadata,\n\t\t\tValue:    1,\n\t\t})\n\n\t\trt := w.vu.Runtime()\n\t\tev := w.newEvent(events.MESSAGE, msg.t)\n\n\t\tif msg.mtype == websocket.BinaryMessage {\n\t\t\tvar data any\n\t\t\tswitch w.binaryType {\n\t\t\tcase blobBinaryType:\n\t\t\t\tvar err error\n\t\t\t\tdata, err = rt.New(w.blobConstructor, rt.ToValue([]any{msg.data}))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to create Blob: %w\", err)\n\t\t\t\t}\n\t\t\tcase arraybufferBinaryType:\n\t\t\t\tdata = rt.NewArrayBuffer(msg.data)\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(`unknown binaryType %q, the supported ones are \"blob\" and \"arraybuffer\"`, w.binaryType)\n\t\t\t}\n\t\t\tmust(rt, ev.DefineDataProperty(\"data\", rt.ToValue(data), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\t\t} else {\n\t\t\tmust(\n\t\t\t\trt,\n\t\t\t\tev.DefineDataProperty(\"data\", rt.ToValue(string(msg.data)), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE),\n\t\t\t)\n\t\t}\n\t\tmust(\n\t\t\trt,\n\t\t\tev.DefineDataProperty(\"origin\", rt.ToValue(w.url.String()), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE),\n\t\t)\n\n\t\tfor _, messageListener := range w.eventListeners.all(events.MESSAGE) {\n\t\t\tif _, err := messageListener(ev); err != nil {\n\t\t\t\t_ = w.conn.Close()                   // TODO log it?\n\t\t\t\t_ = w.connectionClosedWithError(err) // TODO log it?\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc (w *webSocket) readPump(wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\tfor {\n\t\tmessageType, data, err := w.conn.ReadMessage()\n\t\tif err == nil {\n\t\t\tw.queueMessage(&message{\n\t\t\t\tmtype: messageType,\n\t\t\t\tdata:  data,\n\t\t\t\tt:     time.Now(),\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tvar closeErr *websocket.CloseError\n\t\tvar code int\n\t\tvar reason string\n\t\tif errors.As(err, &closeErr) {\n\t\t\tcode = closeErr.Code\n\t\t\treason = closeErr.Text\n\t\t}\n\n\t\tif !websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {\n\t\t\terr = nil\n\t\t}\n\n\t\terrLocal := err\n\t\tw.tq.Queue(func() error {\n\t\t\tif code != 0 {\n\t\t\t\tw.closeCode = code\n\t\t\t\tw.closeReason = reason\n\t\t\t}\n\t\t\t_ = w.conn.Close()\n\t\t\treturn w.connectionClosedWithError(errLocal)\n\t\t})\n\t\treturn\n\t}\n}\n\nfunc (w *webSocket) writePump(wg *sync.WaitGroup) {\n\tdefer wg.Done()\n\twg.Add(1)\n\tsamplesOutput := w.vu.State().Samples\n\tctx := w.vu.Context()\n\twriteChannel := make(chan message)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase msg, ok := <-writeChannel:\n\t\t\t\tif !ok {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tsize := len(msg.data)\n\n\t\t\t\terr := func() error {\n\t\t\t\t\tif msg.mtype != websocket.PingMessage {\n\t\t\t\t\t\treturn w.conn.WriteMessage(msg.mtype, msg.data)\n\t\t\t\t\t}\n\n\t\t\t\t\t// WriteControl is concurrently okay\n\t\t\t\t\treturn w.conn.WriteControl(msg.mtype, msg.data, msg.t.Add(writeWait))\n\t\t\t\t}()\n\t\t\t\tif err != nil {\n\t\t\t\t\tw.tq.Queue(func() error {\n\t\t\t\t\t\t_ = w.conn.Close() // TODO fix\n\t\t\t\t\t\tcloseErr := w.connectionClosedWithError(err)\n\t\t\t\t\t\treturn closeErr\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// This from the specification needs to happen like that instead of with\n\t\t\t\t// atomics or locks outside of the event loop\n\t\t\t\tw.tq.Queue(func() error {\n\t\t\t\t\tw.bufferedAmount -= size\n\t\t\t\t\treturn nil\n\t\t\t\t})\n\n\t\t\t\tmetrics.PushIfNotDone(ctx, samplesOutput, metrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: w.builtinMetrics.WSMessagesSent,\n\t\t\t\t\t\tTags:   w.tagsAndMeta.Tags,\n\t\t\t\t\t},\n\t\t\t\t\tTime:     time.Now(),\n\t\t\t\t\tMetadata: w.tagsAndMeta.Metadata,\n\t\t\t\t\tValue:    1,\n\t\t\t\t})\n\t\t\tcase <-w.done:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\t{\n\t\tdefer close(writeChannel)\n\t\tqueue := make([]message, 0)\n\t\tvar wch chan message\n\t\tvar msg message\n\t\tfor {\n\t\t\twch = nil // this way if nothing to read it will just block\n\t\t\tif len(queue) > 0 {\n\t\t\t\tmsg = queue[0]\n\t\t\t\twch = writeChannel\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase msg = <-w.writeQueueCh:\n\t\t\t\tqueue = append(queue, msg)\n\t\t\tcase wch <- msg:\n\t\t\t\tqueue = queue[:copy(queue, queue[1:])]\n\t\t\tcase <-w.done:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (w *webSocket) send(msg sobek.Value) {\n\tw.assertStateOpen()\n\n\tswitch o := msg.Export().(type) {\n\tcase string:\n\t\tw.bufferedAmount += len(o)\n\t\tw.writeQueueCh <- message{\n\t\t\tmtype: websocket.TextMessage,\n\t\t\tdata:  []byte(o),\n\t\t\tt:     time.Now(),\n\t\t}\n\tcase *sobek.ArrayBuffer:\n\t\tw.sendArrayBuffer(*o)\n\tcase sobek.ArrayBuffer:\n\t\tw.sendArrayBuffer(o)\n\tcase map[string]any:\n\t\trt := w.vu.Runtime()\n\t\tobj := msg.ToObject(rt)\n\t\tif !isBlob(obj, w.blobConstructor) {\n\t\t\tcommon.Throw(rt, fmt.Errorf(\"unsupported send type %T\", o))\n\t\t}\n\n\t\tb := extractBytes(obj, rt)\n\t\tw.bufferedAmount += len(b)\n\t\tw.writeQueueCh <- message{\n\t\t\tmtype: websocket.BinaryMessage,\n\t\t\tdata:  b,\n\t\t\tt:     time.Now(),\n\t\t}\n\tdefault:\n\t\trt := w.vu.Runtime()\n\t\tisView, err := isArrayBufferView(rt, msg)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt,\n\t\t\t\tfmt.Errorf(\"got error while trying to check if argument is ArrayBufferView: %w\", err))\n\t\t}\n\t\tif !isView {\n\t\t\tcommon.Throw(rt, fmt.Errorf(\"unsupported send type %T\", o))\n\t\t}\n\n\t\tvar b []byte\n\t\terr = rt.ExportTo(msg, &b)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt,\n\t\t\t\tfmt.Errorf(\"got error while trying to export ArrayBufferView to bytes: %w\", err))\n\t\t}\n\t\tw.writeQueueCh <- message{\n\t\t\tmtype: websocket.BinaryMessage,\n\t\t\tdata:  b,\n\t\t\tt:     time.Now(),\n\t\t}\n\t}\n}\n\nfunc (w *webSocket) sendArrayBuffer(o sobek.ArrayBuffer) {\n\tb := o.Bytes()\n\tw.bufferedAmount += len(b)\n\tw.writeQueueCh <- message{\n\t\tmtype: websocket.BinaryMessage,\n\t\tdata:  b,\n\t\tt:     time.Now(),\n\t}\n}\n\nfunc isArrayBufferView(rt *sobek.Runtime, v sobek.Value) (bool, error) {\n\tvar isView sobek.Callable\n\tvar ok bool\n\texc := rt.Try(func() {\n\t\tisView, ok = sobek.AssertFunction(\n\t\t\trt.Get(\"ArrayBuffer\").ToObject(rt).Get(\"isView\"))\n\t})\n\tif exc != nil {\n\t\treturn false, exc\n\t}\n\n\tif !ok {\n\t\treturn false, fmt.Errorf(\"couldn't get ArrayBuffer.isView as it isn't a function\")\n\t}\n\n\tboolValue, err := isView(nil, v)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn boolValue.ToBoolean(), nil\n}\n\n// Ping sends a ping message over the websocket.\nfunc (w *webSocket) ping() {\n\tw.assertStateOpen()\n\n\tpingID := strconv.Itoa(w.sendPings.counter)\n\n\tw.writeQueueCh <- message{\n\t\tmtype: websocket.PingMessage,\n\t\tdata:  []byte(pingID),\n\t\tt:     time.Now(),\n\t}\n\n\tw.sendPings.timestamps[pingID] = time.Now()\n\tw.sendPings.counter++\n}\n\nfunc (w *webSocket) trackPong(pingID string) {\n\tpongTimestamp := time.Now()\n\n\tpingTimestamp, ok := w.sendPings.timestamps[pingID]\n\tif !ok {\n\t\t// We received a pong for a ping we didn't send; ignore\n\t\t// (this shouldn't happen with a compliant server)\n\t\tw.vu.State().Logger.Warnf(\"received pong for unknown ping ID %s\", pingID)\n\n\t\treturn\n\t}\n\n\tmetrics.PushIfNotDone(w.vu.Context(), w.vu.State().Samples, metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: w.builtinMetrics.WSPing,\n\t\t\tTags:   w.tagsAndMeta.Tags,\n\t\t},\n\t\tTime:     pongTimestamp,\n\t\tMetadata: w.tagsAndMeta.Metadata,\n\t\tValue:    metrics.D(pongTimestamp.Sub(pingTimestamp)),\n\t})\n}\n\n// assertStateOpen checks if the websocket is in the OPEN state\n// otherwise it throws an error (panic)\nfunc (w *webSocket) assertStateOpen() {\n\tif w.readyState == OPEN {\n\t\treturn\n\t}\n\n\t// TODO figure out if we should give different error while being closed/closed/connecting\n\tcommon.Throw(w.vu.Runtime(), errors.New(\"InvalidStateError\"))\n}\n\nfunc isValidClientCloseCode(code int) bool {\n\treturn code == 1000 || (code >= 3000 && code <= 4999)\n}\n\nfunc isValidCloseReason(reason string) bool {\n\treturn len([]byte(reason)) <= 123\n}\n\nfunc (w *webSocket) close(code int, reason string) error {\n\tif w.readyState == CLOSED || w.readyState == CLOSING {\n\t\treturn nil\n\t}\n\n\tif code != 0 && !isValidClientCloseCode(code) {\n\t\treturn fmt.Errorf(\n\t\t\t\"InvalidAccessError: Failed to execute 'close' on 'WebSocket': \"+\n\t\t\t\t\"The close code must be either 1000, or between 3000 and 4999. %d is neither\",\n\t\t\tcode,\n\t\t)\n\t}\n\n\tif !isValidCloseReason(reason) {\n\t\treturn errors.New(\n\t\t\t`SyntaxError: Failed to execute 'close' on 'WebSocket': The message must not be greater than 123 bytes`,\n\t\t)\n\t}\n\n\tif code == 0 {\n\t\tcode = websocket.CloseNormalClosure\n\t}\n\n\tw.readyState = CLOSING\n\tw.closeCode = code\n\n\tw.writeQueueCh <- message{\n\t\tmtype: websocket.CloseMessage,\n\t\tdata:  websocket.FormatCloseMessage(code, reason),\n\t\tt:     time.Now(),\n\t}\n\n\treturn nil\n}\n\nfunc (w *webSocket) queueClose() {\n\tw.tq.Queue(func() error {\n\t\treturn w.close(websocket.CloseNormalClosure, \"\")\n\t})\n}\n\n// to be run only on the eventloop\n// from https://websockets.spec.whatwg.org/#feedback-from-the-protocol\nfunc (w *webSocket) connectionConnected() error {\n\tif w.readyState != CONNECTING {\n\t\treturn nil\n\t}\n\tw.readyState = OPEN\n\treturn w.callOpenListeners(time.Now()) // TODO fix time\n}\n\n// to be run only on the eventloop\nfunc (w *webSocket) connectionClosedWithError(err error) error {\n\tif w.readyState == CLOSED {\n\t\treturn nil\n\t}\n\tw.readyState = CLOSED\n\tclose(w.done)\n\n\tif err != nil {\n\t\tvar closeError *websocket.CloseError\n\t\tif !errors.As(err, &closeError) || closeError.Code != websocket.CloseNormalClosure {\n\t\t\tif errList := w.callErrorListeners(err); errList != nil {\n\t\t\t\treturn errList // TODO ... still call the close listeners ?!?\n\t\t\t}\n\t\t}\n\t}\n\treturn w.callEventListeners(events.CLOSE)\n}\n\n// newEvent return an event implementing \"implements\" https://dom.spec.whatwg.org/#event\n// needs to be called on the event loop\n// TODO: move to events\nfunc (w *webSocket) newEvent(eventType string, t time.Time, funcOptions ...func(*sobek.Object)) *sobek.Object {\n\trt := w.vu.Runtime()\n\to := rt.NewObject()\n\n\tmust(rt, o.DefineAccessorProperty(\"type\", rt.ToValue(func() string {\n\t\treturn eventType\n\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tmust(rt, o.DefineAccessorProperty(\"target\", rt.ToValue(func() any {\n\t\treturn w.obj\n\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\t// skip srcElement\n\t// skip currentTarget ??!!\n\t// skip eventPhase ??!!\n\t// skip stopPropagation\n\t// skip cancelBubble\n\t// skip stopImmediatePropagation\n\t// skip a bunch more\n\n\tmust(rt, o.DefineAccessorProperty(\"timestamp\", rt.ToValue(func() float64 {\n\t\treturn float64(t.UnixNano()) / 1_000_000 // milliseconds as double as per the spec\n\t\t// https://w3c.github.io/hr-time/#dom-domhighrestimestamp\n\t}), nil, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\n\tfor _, funcOption := range funcOptions {\n\t\tfuncOption(o)\n\t}\n\n\treturn o\n}\n\nfunc (w *webSocket) callOpenListeners(timestamp time.Time) error {\n\tfor _, openListener := range w.eventListeners.all(events.OPEN) {\n\t\tif _, err := openListener(w.newEvent(events.OPEN, timestamp)); err != nil {\n\t\t\t_ = w.conn.Close()                   // TODO log it?\n\t\t\t_ = w.connectionClosedWithError(err) // TODO log it?\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *webSocket) callErrorListeners(e error) error { // TODO use the error even thought it is not by the spec\n\trt := w.vu.Runtime()\n\n\tev := w.newEvent(events.ERROR, time.Now())\n\tmust(rt, ev.DefineDataProperty(\"error\",\n\t\trt.ToValue(e.Error()),\n\t\tsobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\tfor _, errorListener := range w.eventListeners.all(events.ERROR) {\n\t\tif _, err := errorListener(ev); err != nil { // TODO fix timestamp\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *webSocket) callEventListeners(eventType string) error {\n\tvar event *sobek.Object\n\t// TODO fix timestamp\n\t// TODO: Add 'wasClean' boolean to close events per spec\n\tif eventType == events.CLOSE {\n\t\tevent = w.newEvent(eventType, time.Now(), func(o *sobek.Object) {\n\t\t\trt := w.vu.Runtime()\n\t\t\tif w.closeCode != 0 {\n\t\t\t\tmust(rt, o.DefineDataProperty(\"code\",\n\t\t\t\t\trt.ToValue(w.closeCode), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\t\t\t}\n\t\t\tmust(rt, o.DefineDataProperty(\"reason\",\n\t\t\t\trt.ToValue(w.closeReason), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE))\n\t\t})\n\t} else {\n\t\tevent = w.newEvent(eventType, time.Now())\n\t}\n\n\tfor _, listener := range w.eventListeners.all(eventType) {\n\t\tif _, err := listener(event); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *webSocket) addEventListener(event string, handler func(sobek.Value) (sobek.Value, error)) {\n\t// TODO support options https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#parameters\n\n\tif handler == nil {\n\t\tcommon.Throw(w.vu.Runtime(), fmt.Errorf(\"handler for event type %q isn't a callable function\", event))\n\t}\n\n\tif err := w.eventListeners.add(event, handler); err != nil {\n\t\tw.vu.State().Logger.Warnf(\"can't add event handler: %s\", err)\n\t}\n}\n\n// TODO add remove listeners\n"
  },
  {
    "path": "internal/js/modules/k6/websockets/websockets_test.go",
    "content": "package websockets\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\thttpModule \"go.k6.io/k6/js/modules/k6/http\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// copied from k6/ws\nfunc assertSessionMetricsEmitted(\n\tt *testing.T,\n\tsampleContainers []metrics.SampleContainer,\n\tsubprotocol,\n\turl string,\n\tstatus int, //nolint:unparam // TODO: check why it always same in tests\n\tgroup string, //nolint:unparam // TODO: check why it always same in tests\n) {\n\tt.Helper()\n\tseenSessions := false\n\tseenSessionDuration := false\n\tseenConnecting := false\n\n\trequire.NotEmpty(t, sampleContainers)\n\tfor _, sampleContainer := range sampleContainers {\n\t\trequire.NotEmpty(t, sampleContainer.GetSamples())\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\ttags := sample.Tags.Map()\n\t\t\tif tags[\"url\"] == url {\n\t\t\t\tswitch sample.Metric.Name {\n\t\t\t\tcase metrics.WSConnectingName:\n\t\t\t\t\tseenConnecting = true\n\t\t\t\tcase metrics.WSSessionDurationName:\n\t\t\t\t\tseenSessionDuration = true\n\t\t\t\tcase metrics.WSSessionsName:\n\t\t\t\t\tseenSessions = true\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(t, strconv.Itoa(status), tags[\"status\"])\n\t\t\t\tassert.Equal(t, subprotocol, tags[\"subproto\"])\n\t\t\t\tassert.Equal(t, group, tags[\"group\"])\n\t\t\t}\n\t\t}\n\t}\n\tassert.True(t, seenConnecting, \"url %s didn't emit Connecting\", url)\n\tassert.True(t, seenSessions, \"url %s didn't emit Sessions\", url)\n\tassert.True(t, seenSessionDuration, \"url %s didn't emit SessionDuration\", url)\n}\n\n// also copied from k6/ws\nfunc assertMetricEmittedCount(t *testing.T, metricName string, sampleContainers []metrics.SampleContainer, url string, count int) {\n\tt.Helper()\n\tactualCount := 0\n\n\tfor _, sampleContainer := range sampleContainers {\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\tsurl, ok := sample.Tags.Get(\"url\")\n\t\t\tassert.True(t, ok)\n\t\t\tif surl == url && sample.Metric.Name == metricName {\n\t\t\t\tactualCount++\n\t\t\t}\n\t\t}\n\t}\n\tassert.Equal(t, count, actualCount, \"url %s emitted %s %d times, expected was %d times\", url, metricName, actualCount, count)\n}\n\ntype testState struct {\n\ttb      *httpmultibin.HTTPMultiBin\n\truntime *modulestest.Runtime\n\tsamples chan metrics.SampleContainer\n\tt       testing.TB\n\n\tcallRecorder *callRecorder\n\terrors       chan error\n\n\tmodule *WebSocketsAPI\n}\n\n// callRecorder a helper type that records all calls\ntype callRecorder struct {\n\tsync.Mutex\n\tcalls []string\n}\n\n// Call records a call\nfunc (r *callRecorder) Call(text string) {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tr.calls = append(r.calls, text)\n}\n\n// Len just returns the length of the calls\nfunc (r *callRecorder) Len() int {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\treturn len(r.calls)\n}\n\n// Len just returns the length of the calls\nfunc (r *callRecorder) Recorded() []string {\n\tr.Lock()\n\tdefer r.Unlock()\n\n\tresult := make([]string, 0, len(r.calls))\n\tresult = append(result, r.calls...)\n\n\treturn result\n}\n\nfunc newTestState(t testing.TB) testState {\n\truntime := modulestest.NewRuntime(t)\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tsamples := make(chan metrics.SampleContainer, 1000)\n\tstate := &lib.State{\n\t\tDialer: tb.Dialer,\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: metrics.NewSystemTagSet(\n\t\t\t\tmetrics.TagURL,\n\t\t\t\tmetrics.TagProto,\n\t\t\t\tmetrics.TagStatus,\n\t\t\t\tmetrics.TagSubproto,\n\t\t\t),\n\t\t\tUserAgent: null.StringFrom(\"TestUserAgent\"),\n\t\t},\n\t\tSamples:        samples,\n\t\tTLSConfig:      tb.TLSClientConfig,\n\t\tBuiltinMetrics: runtime.BuiltinMetrics,\n\t\tTags:           lib.NewVUStateTags(runtime.VU.InitEnvField.Registry.RootTagSet()),\n\t}\n\n\trecorder := &callRecorder{\n\t\tcalls: make([]string, 0),\n\t}\n\n\tm := new(RootModule).NewModuleInstance(runtime.VU)\n\trequire.NoError(t, runtime.VU.RuntimeField.Set(\"WebSocket\", m.Exports().Named[\"WebSocket\"]))\n\trequire.NoError(t, runtime.VU.RuntimeField.Set(\"Blob\", m.Exports().Named[\"Blob\"]))\n\trequire.NoError(t, runtime.VU.RuntimeField.Set(\"call\", recorder.Call))\n\n\truntime.MoveToVUContext(state)\n\treturn testState{\n\t\truntime:      runtime,\n\t\ttb:           tb,\n\t\tsamples:      samples,\n\t\tcallRecorder: recorder,\n\t\terrors:       make(chan error, 50),\n\t\tt:            t,\n\t\tmodule:       m.(*WebSocketsAPI),\n\t}\n}\n\nfunc (ts *testState) addHandler(uri string, upgrader *websocket.Upgrader, message *testMessage) {\n\tts.tb.Mux.HandleFunc(uri, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t// when upgrader not passed we should use default one\n\t\tif upgrader == nil {\n\t\t\tupgrader = &websocket.Upgrader{}\n\t\t}\n\n\t\tconn, err := upgrader.Upgrade(w, req, w.Header())\n\t\tif err != nil {\n\t\t\tts.errors <- fmt.Errorf(\"%s cannot upgrade request: %w\", uri, err)\n\t\t\treturn\n\t\t}\n\n\t\tdefer func() {\n\t\t\terr = conn.Close()\n\t\t\tif err != nil {\n\t\t\t\tts.t.Logf(\"error while closing connection in %s: %v\", uri, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t}()\n\n\t\tif message == nil {\n\t\t\treturn\n\t\t}\n\n\t\tif err = conn.WriteMessage(message.kind, message.data); err != nil {\n\t\t\tts.errors <- fmt.Errorf(\"%s cannot write message: %w\", uri, err)\n\t\t\treturn\n\t\t}\n\t}))\n}\n\ntype testMessage struct {\n\tkind int\n\tdata []byte\n}\n\nfunc TestBasic(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.send(\"something\")\n\t\t\tws.close()\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestBasicSendBlob(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.send(new Blob([\"something\"]))\n\t\t\tws.close()\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestAddUndefinedHandler(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.close()\n\t\t})\n\t\tws.addEventListener(\"open\", undefined)\n\t`))\n\trequire.ErrorContains(t, err, \"handler for event type \\\"open\\\" isn't a callable function\")\n}\n\nfunc TestBasicWithOn(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.onopen = () => {\n\t\t\tws.send(\"something\")\n\t\t\tws.close()\n\t\t}\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestReadyState(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tif (ws.readyState != 1){\n\t\t\t\tthrow new Error(\"Expected ready state 1 got \"+ ws.readyState)\n\t\t\t}\n\t\t\tws.addEventListener(\"close\", () => {\n\t\t\t\tif (ws.readyState != 3){\n\t\t\t\t\tthrow new Error(\"Expected ready state 3 got \"+ ws.readyState)\n\t\t\t\t}\n\n\t\t\t})\n\t\t\tws.send(\"something\")\n\t\t\tws.close()\n\t\t})\n\t\tif (ws.readyState != 0){\n\t\t\tthrow new Error(\"Expected ready state 0 got \"+ ws.readyState)\n\t\t}\n\t`))\n\trequire.NoError(t, err)\n}\n\nfunc TestBinaryState(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\tts.runtime.VU.StateField.Logger = logger\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo-invalid\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.send(new Uint8Array([164,41]).buffer)\n\t\t\tif (ws.bufferedAmount != 2) {\n\t\t\t\tthrow \"Expected 2 bufferedAmount got \"+ ws.bufferedAmount\n\t\t\t}\n\t\t\tws.send(\"k6\")\n\t\t\tif (ws.bufferedAmount != 4) {\n\t\t\t\tthrow \"Expected 4 bufferedAmount got \"+ ws.bufferedAmount\n\t\t\t}\n\t\t\tws.onmessage = (e) => {\n\t\t\t\tif (ws.bufferedAmount != 0 && ws.bufferedAmount != 2) { // it is possible one or both were flushed\n\t\t\t\t\tthrow \"Expected 0 or 2 bufferedAmount, but got \"+ ws.bufferedAmount\n\t\t\t\t}\n\t\t\t\tws.close()\n\t\t\t\tcall(JSON.stringify(e))\n\t\t\t}\n\t\t})\n\n\t\tif (ws.binaryType != \"blob\") {\n\t\t\tthrow new Error(\"Wrong binaryType value, expected to be blob got \"+ ws.binaryType)\n\t\t}\n\n\t\tvar thrown = false;\n\t\ttry {\n\t\t\tws.binaryType = \"something\"\n\t\t} catch(e) {\n\t\t\tthrown = true\n\t\t}\n\t\tif (!thrown) {\n\t\t\tthrow new Error(\"Expects ws.binaryType to be writable only with valid values\")\n\t\t}\n\t`))\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 0)\n}\n\nfunc TestBinaryType_Default(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\tts.runtime.VU.StateField.Logger = logger\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo-invalid\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tconst sent = new Uint8Array([164,41]).buffer\n\t\t\tws.send(sent)\n\t\t\tws.onmessage = async (e) => {\n\t\t\t\tif (!(e.data instanceof Blob)) {\n\t\t\t\t\tthrow new Error(\"Wrong event.data type; expected: Blob, got: \"+ typeof e.data)\n\t\t\t\t}\n\t\t\t\tconst received = await e.data.arrayBuffer();\n\n\t\t\t\tif (sent.byteLength !== received.byteLength) {\n\t\t\t\t\tthrow new Error(\"The data received \" + received.byteLength +\" isn't equal to the data sent \"+ sent.byteLength)\n\t\t\t\t}\n\n\t\t\t\tws.close()\n\t\t\t}\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 0)\n}\n\nfunc TestBinaryType_Blob(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\tts.runtime.VU.StateField.Logger = logger\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.binaryType = \"blob\"\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tconst sent = new Uint8Array([164,41]).buffer\n\t\t\tws.send(sent)\n\t\t\tws.onmessage = (e) => {\n\t\t\t\tif (!(e.data instanceof Blob)) {\n\t\t\t\t\tthrow new Error(\"Wrong event.data type; expected: Blob, got: \"+ typeof e.data)\n\t\t\t\t}\n\n\t\t\t\te.data.arrayBuffer().then((ab) => {\n\t\t\t\t\tif (sent.byteLength !== ab.byteLength) {\n\t\t\t\t\t\tthrow new Error(\"The data received isn't equal to the data sent\")\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\t\tws.close()\n\t\t\t}\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 0)\n}\n\nfunc TestBinaryType_ArrayBuffer(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\tts.runtime.VU.StateField.Logger = logger\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.binaryType = \"arraybuffer\"\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tconst sent = new Uint8Array([164,41]).buffer\n\t\t\tws.send(sent)\n\t\t\tws.onmessage = (e) => {\n\t\t\t\tif (!(e.data instanceof ArrayBuffer)) {\n\t\t\t\t\tthrow new Error(\"Wrong event.data type; expected: ArrayBuffer, got: \"+ typeof e.data)\n\t\t\t\t}\n\n\t\t\t\tif (sent.byteLength !== e.data.byteLength) {\n\t\t\t\t\tthrow new Error(\"The data received isn't equal to the data sent\")\n\t\t\t\t}\n\n\t\t\t\tws.close()\n\t\t\t}\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 0)\n}\n\nfunc TestBinaryType_ArrayBuffer_issue_5226(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\tts.runtime.VU.StateField.Logger = logger\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.binaryType = \"arraybuffer\"\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tconst sent = new Uint8Array(1024)\n\t\t\tws.send(sent.subarray(0, 1))\n\t\t\tws.onmessage = (e) => {\n\t\t\t\tif (!(e.data instanceof ArrayBuffer)) {\n\t\t\t\t\tthrow new Error(\"Wrong event.data type; expected: ArrayBuffer, got: \"+ typeof e.data);\n\t\t\t\t}\n\n\t\t\t\tif (e.data.byteLength != 1) {\n\t\t\t\t\tthrow new Error(\"The data received isn't equal to the data sent \"  + e.data.byteLength);\n\t\t\t\t}\n\n\t\t\t\tws.close();\n\t\t\t}\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 0)\n}\n\nfunc TestExceptionDontPanic(t *testing.T) {\n\tt.Parallel()\n\tcases := map[string]struct {\n\t\tscript, expectedError string\n\t}{\n\t\t\"open\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\toops\n\t\t})`,\n\t\t\texpectedError: \"oops is not defined at <eval>:4:4\",\n\t\t},\n\t\t\"onopen\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onopen = () => {\n\t\t\toops\n\t\t}`,\n\t\t\texpectedError: \"oops is not defined at <eval>:4:4\",\n\t\t},\n\t\t\"error\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/badurl\")\n\t\tws.addEventListener(\"error\", () =>{\n\t\t\tinerroridf\n\t\t})\n\t\t`,\n\t\t\texpectedError: \"inerroridf is not defined at <eval>:4:4\",\n\t\t},\n\t\t\"onerror\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/badurl\")\n\t\tws.onerror = () => {\n\t\t\tinerroridf\n\t\t}\n\t\t`,\n\t\t\texpectedError: \"inerroridf is not defined at <eval>:4:4\",\n\t\t},\n\t\t\"close\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\t\tws.close()\n\t\t})\n\t\tws.addEventListener(\"close\", ()=>{\n\t\t\tincloseidf\n\t\t})`,\n\t\t\texpectedError: \"incloseidf is not defined at <eval>:7:4\",\n\t\t},\n\t\t\"onclose\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onopen = () => {\n\t\t\t\tws.close()\n\t\t}\n\t\tws.onclose = () =>{\n\t\t\tincloseidf\n\t\t}`,\n\t\t\texpectedError: \"incloseidf is not defined at <eval>:7:4\",\n\t\t},\n\t\t\"message\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\t\tws.send(\"something\")\n\t\t})\n\t\tws.addEventListener(\"message\", ()=>{\n\t\t\tinmessageidf\n\t\t})`,\n\t\t\texpectedError: \"inmessageidf is not defined at <eval>:7:4\",\n\t\t},\n\t\t\"onmessage\": {\n\t\t\tscript: `\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onopen = () => {\n\t\t\t\tws.send(\"something\")\n\t\t}\n\t\tws.onmessage = () =>{\n\t\t\tinmessageidf\n\t\t}`,\n\t\t\texpectedError: \"inmessageidf is not defined at <eval>:7:4\",\n\t\t},\n\t}\n\tfor name, testcase := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestState(t)\n\t\t\t// This is here as the on in k6 echos and closes, which races to whether we will get the message or not. And that seems like the correct thing to happen either way.\n\t\t\tts.tb.Mux.HandleFunc(\"/ws/echo\", func(w http.ResponseWriter, req *http.Request) {\n\t\t\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdefer func() {\n\t\t\t\t\t_ = conn.Close()\n\t\t\t\t}()\n\t\t\t\tfor {\n\t\t\t\t\tmsgt, msg, err := conn.ReadMessage()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\terr = conn.WriteMessage(msgt, msg)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tsr := ts.tb.Replacer.Replace\n\t\t\t_, err := ts.runtime.RunOnEventLoop(sr(testcase.script))\n\t\t\trequire.Error(t, err)\n\t\t\trequire.ErrorContains(t, err, testcase.expectedError)\n\t\t})\n\t}\n}\n\nfunc TestTwoTalking(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tch1 := make(chan message)\n\tch2 := make(chan message)\n\n\tts.tb.Mux.HandleFunc(\"/ws/couple/\", func(w http.ResponseWriter, req *http.Request) {\n\t\tpath := strings.TrimPrefix(req.URL.Path, \"/ws/couple/\")\n\t\tvar wch chan message\n\t\tvar rch chan message\n\n\t\tswitch path {\n\t\tcase \"1\":\n\t\t\twch = ch1\n\t\t\trch = ch2\n\t\tcase \"2\":\n\t\t\twch = ch2\n\t\t\trch = ch1\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusTeapot)\n\t\t}\n\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tdefer func() {\n\t\t\t_ = conn.Close()\n\t\t}()\n\n\t\tgo func() {\n\t\t\tdefer close(wch)\n\t\t\tfor {\n\t\t\t\tmsgT, msg, err := conn.ReadMessage()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\twch <- message{\n\t\t\t\t\tdata:  msg,\n\t\t\t\t\tmtype: msgT,\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tfor msg := range rch {\n\t\t\terr := conn.WriteMessage(msg.mtype, msg.data)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar count = 0;\n\t\tvar ws1 = new WebSocket(\"WSBIN_URL/ws/couple/1\");\n\t\tws1.addEventListener(\"open\", () => {\n\t\t\tws1.send(\"I am 1\");\n\t\t})\n\t\tws1.addEventListener(\"message\", (e)=>{\n\t\t\tif (e.data != \"I am 2\") {\n\t\t\t\tthrow \"oops\";\n\t\t\t}\n\t\t\tcount++;\n\t\t\tif (count == 2) {\n\t\t\t\tws1.close();\n\t\t\t}\n\t\t})\n\t\tvar ws2 = new WebSocket(\"WSBIN_URL/ws/couple/2\");\n\t\tws2.addEventListener(\"open\", () => {\n\t\t\tws2.send(\"I am 2\");\n\t\t})\n\t\tws2.addEventListener(\"message\", (e)=>{\n\t\t\tif (e.data != \"I am 1\") {\n\t\t\t\tthrow \"oops\";\n\t\t\t}\n\t\t\tcount++;\n\t\t\tif (count == 2) {\n\t\t\t\tws2.close();\n\t\t\t}\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws/couple/1\"), http.StatusSwitchingProtocols, \"\")\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws/couple/2\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestTwoTalkingUsingOn(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tch1 := make(chan message)\n\tch2 := make(chan message)\n\n\tts.tb.Mux.HandleFunc(\"/ws/couple/\", func(w http.ResponseWriter, req *http.Request) {\n\t\tpath := strings.TrimPrefix(req.URL.Path, \"/ws/couple/\")\n\t\tvar wch chan message\n\t\tvar rch chan message\n\n\t\tswitch path {\n\t\tcase \"1\":\n\t\t\twch = ch1\n\t\t\trch = ch2\n\t\tcase \"2\":\n\t\t\twch = ch2\n\t\t\trch = ch1\n\t\tdefault:\n\t\t\tw.WriteHeader(http.StatusTeapot)\n\t\t}\n\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tdefer func() {\n\t\t\t_ = conn.Close()\n\t\t}()\n\n\t\tgo func() {\n\t\t\tdefer close(wch)\n\t\t\tfor {\n\t\t\t\tmsgT, msg, err := conn.ReadMessage()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\twch <- message{\n\t\t\t\t\tdata:  msg,\n\t\t\t\t\tmtype: msgT,\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tfor msg := range rch {\n\t\t\terr := conn.WriteMessage(msg.mtype, msg.data)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar count = 0;\n\t\tvar ws1 = new WebSocket(\"WSBIN_URL/ws/couple/1\");\n\t\tws1.onopen = () => {\n\t\t\tws1.send(\"I am 1\");\n\t\t}\n\n\t\tws1.onmessage = (e) => {\n\t\t\tif (e.data != \"I am 2\") {\n\t\t\t\tthrow \"oops\";\n\t\t\t}\n\t\t\tcount++;\n\t\t\tif (count == 2) {\n\t\t\t\tws1.close();\n\t\t\t}\n\t\t}\n\n\t\tvar ws2 = new WebSocket(\"WSBIN_URL/ws/couple/2\");\n\t\tws2.onopen = () => {\n\t\t\tws2.send(\"I am 2\");\n\t\t}\n\t\tws2.onmessage = (e) => {\n\t\t\tif (e.data != \"I am 1\") {\n\t\t\t\tthrow \"oops\";\n\t\t\t}\n\t\t\tcount++;\n\t\t\tif (count == 2) {\n\t\t\t\tws2.close();\n\t\t\t}\n\t\t}\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws/couple/1\"), http.StatusSwitchingProtocols, \"\")\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws/couple/2\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestSubProtocols(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tts.tb.Mux.HandleFunc(\"/ws/protocols\", func(w http.ResponseWriter, req *http.Request) {\n\t\tconn, err := (&websocket.Upgrader{Subprotocols: []string{\"unsupported\", \"supported\"}}).Upgrade(w, req, w.Header())\n\t\tif conn.Subprotocol() != \"supported\" {\n\t\t\t_ = conn.WriteMessage(websocket.TextMessage, []byte(`bad subprotocol on server `+conn.Subprotocol()))\n\t\t\treturn\n\t\t}\n\t\tch := make(chan message)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tdefer func() {\n\t\t\t_ = conn.Close()\n\t\t}()\n\n\t\tgo func() {\n\t\t\tdefer close(ch)\n\t\t\tfor {\n\t\t\t\tmsgT, msg, err := conn.ReadMessage()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tch <- message{\n\t\t\t\t\tdata:  msg,\n\t\t\t\t\tmtype: msgT,\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t\tfor msg := range ch {\n\t\t\terr := conn.WriteMessage(msg.mtype, msg.data)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tconst ws = new WebSocket(\"WSBIN_URL/ws/protocols\", [\"one\", \"supported\"]);\n\t\tws.onopen = () => {\n\t\t\tif (ws.protocol != \"supported\") {\n\t\t\t\tthrow \"bad protocol \" + ws.protocol;\n\t\t\t}\n\t\t\tws.send(\"hello\");\n\t\t}\n\n\t\tws.onmessage = (e) => {\n\t\t\tif (e.data != \"hello\") {\n\t\t\t\tthrow \"oops\";\n\t\t\t}\n\t\t\tws.close();\n\t\t}\n\t\tws.onerror = (e) => { throw e.error; ws.close();}\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"supported\", sr(\"WSBIN_URL/ws/protocols\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestDialError(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\t// without listeners\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"ws://127.0.0.2\");\n\t`))\n\trequire.NoError(t, err)\n\n\t_, err = ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"ws://127.0.0.2\");\n\t\tws.addEventListener(\"error\", (e) =>{\n\t\t\tws.close();\n\t\t\tthrow new Error(\"The provided url is an invalid endpoint\")\n\t\t})\n\t`))\n\tassert.Error(t, err)\n}\n\nfunc TestOnError(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"ws://127.0.0.2\");\n\t\tws.onerror = (e) => {\n\t\t\tws.close();\n\t\t\tthrow new Error(\"lorem ipsum\")\n\t\t}\n\t`))\n\tassert.Error(t, err)\n\tassert.Equal(t, \"Error: lorem ipsum at <eval>:5:10(7)\", err.Error())\n}\n\nfunc TestOnClose(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onopen = () => {\n\t\t\tws.close()\n\t\t}\n\t\tws.onclose = () =>{\n\t\t\tcall(\"from close\")\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n\tassert.Equal(t, []string{\"from close\"}, ts.callRecorder.Recorded())\n}\n\nfunc TestMixingOnAndAddHandlers(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onopen = () => {\n\t\t\tws.close()\n\t\t}\n\t\tws.addEventListener(\"close\", () => {\n\t\t\tcall(\"from addEventListener\")\n\t\t})\n\t\tws.onclose = () =>{\n\t\t\tcall(\"from onclose\")\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n\tassert.Equal(t, 2, ts.callRecorder.Len())\n\tassert.Contains(t, ts.callRecorder.Recorded(), \"from addEventListener\")\n\tassert.Contains(t, ts.callRecorder.Recorded(), \"from onclose\")\n}\n\nfunc TestOncloseRedefineListener(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onopen = () => {\n\t\t\tws.close()\n\t\t}\n\t\tws.onclose = () =>{\n\t\t\tcall(\"from onclose\")\n\t\t}\n\t\tws.onclose = () =>{\n\t\t\tcall(\"from onclose 2\")\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n\tassert.Equal(t, []string{\"from onclose 2\"}, ts.callRecorder.Recorded())\n}\n\nfunc TestOncloseRedefineWithNull(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onopen = () => {\n\t\t\tws.close()\n\t\t}\n\t\tws.onclose = () =>{\n\t\t\tcall(\"from onclose\")\n\t\t}\n\t\tws.onclose = null\n\t`))\n\tassert.NoError(t, err)\n\tassert.Equal(t, 0, ts.callRecorder.Len())\n}\n\nfunc TestOncloseDefineWithInvalidValue(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws/echo\")\n\t\tws.onclose = 1\n\t`))\n\tassert.Error(t, err)\n\tassert.Contains(t, err.Error(), \"a value for 'onclose' should be callable\")\n}\n\nfunc TestCustomHeaders(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tmu := &sync.Mutex{}\n\tcollected := make(http.Header)\n\n\tts.tb.Mux.HandleFunc(\"/ws-echo-someheader\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tresponseHeaders := w.Header().Clone()\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, responseHeaders)\n\t\tif err != nil {\n\t\t\tts.errors <- fmt.Errorf(\"/ws-echo-someheader cannot upgrade request: %w\", err)\n\t\t\treturn\n\t\t}\n\n\t\tmu.Lock()\n\t\tcollected = req.Header.Clone()\n\t\tmu.Unlock()\n\n\t\terr = conn.Close()\n\t\tif err != nil {\n\t\t\tt.Logf(\"error while closing connection in /ws-echo-someheader: %v\", err)\n\t\t}\n\t}))\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo-someheader\", null, {headers: {\"x-lorem\": \"ipsum\"}})\n\t\tws.onopen = () => {\n\t\t\tws.close()\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo-someheader\"), http.StatusSwitchingProtocols, \"\")\n\n\tmu.Lock()\n\tassert.True(t, len(collected) > 0)\n\tassert.Equal(t, \"ipsum\", collected.Get(\"x-lorem\"))\n\tassert.Equal(t, \"TestUserAgent\", collected.Get(\"User-Agent\"))\n\tmu.Unlock()\n\tassert.Len(t, ts.errors, 0)\n}\n\nfunc TestCookies(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tmu := &sync.Mutex{}\n\tcollected := make(map[string]string)\n\n\tts.tb.Mux.HandleFunc(\"/ws-echo-someheader\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tresponseHeaders := w.Header().Clone()\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, responseHeaders)\n\t\tif err != nil {\n\t\t\tts.errors <- fmt.Errorf(\"/ws-echo-someheader cannot upgrade request: %w\", err)\n\t\t\treturn\n\t\t}\n\n\t\tmu.Lock()\n\t\tfor _, v := range req.Cookies() {\n\t\t\tcollected[v.Name] = v.Value\n\t\t}\n\t\tmu.Unlock()\n\n\t\terr = conn.Close()\n\t\tif err != nil {\n\t\t\tt.Logf(\"error while closing connection in /ws-echo-someheader: %v\", err)\n\t\t}\n\t}))\n\n\terr := ts.runtime.VU.RuntimeField.Set(\"http\", httpModule.New().NewModuleInstance(ts.runtime.VU).Exports().Default)\n\trequire.NoError(t, err)\n\n\tts.runtime.VU.StateField.CookieJar, _ = cookiejar.New(nil)\n\t_, err = ts.runtime.RunOnEventLoop(sr(`\n\t\tvar jar = new http.CookieJar();\n\t\tjar.set(\"HTTPBIN_URL/ws-echo-someheader\", \"someheader\", \"customjar\")\n\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo-someheader\", null, {jar: jar})\n\t\tws.onopen = () => {\n\t\t\tws.close()\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo-someheader\"), http.StatusSwitchingProtocols, \"\")\n\n\tmu.Lock()\n\tassert.True(t, len(collected) > 0)\n\tassert.Equal(t, map[string]string{\"someheader\": \"customjar\"}, collected)\n\tmu.Unlock()\n\n\tassert.Len(t, ts.errors, 0)\n}\n\nfunc TestCookiesDefaultJar(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tmu := &sync.Mutex{}\n\tcollected := make(map[string]string)\n\n\tts.tb.Mux.HandleFunc(\"/ws-echo-someheader\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tresponseHeaders := w.Header().Clone()\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, responseHeaders)\n\t\tif err != nil {\n\t\t\tts.errors <- fmt.Errorf(\"/ws-echo-someheader cannot upgrade request: %w\", err)\n\t\t\treturn\n\t\t}\n\n\t\tmu.Lock()\n\t\tfor _, v := range req.Cookies() {\n\t\t\tcollected[v.Name] = v.Value\n\t\t}\n\t\tmu.Unlock()\n\n\t\terr = conn.Close()\n\t\tif err != nil {\n\t\t\tt.Logf(\"error while closing connection in /ws-echo-someheader: %v\", err)\n\t\t}\n\t}))\n\n\terr := ts.runtime.VU.RuntimeField.Set(\"http\", httpModule.New().NewModuleInstance(ts.runtime.VU).Exports().Default)\n\trequire.NoError(t, err)\n\n\tts.runtime.VU.StateField.CookieJar, _ = cookiejar.New(nil)\n\t_, err = ts.runtime.RunOnEventLoop(sr(`\n\t\thttp.cookieJar().set(\"HTTPBIN_URL/ws-echo-someheader\", \"someheader\", \"defaultjar\")\n\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo-someheader\", null)\n\t\tws.onopen = () => {\n\t\t\tws.close()\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo-someheader\"), http.StatusSwitchingProtocols, \"\")\n\n\tmu.Lock()\n\tassert.True(t, len(collected) > 0)\n\tassert.Equal(t, map[string]string{\"someheader\": \"defaultjar\"}, collected)\n\tmu.Unlock()\n\n\tassert.Len(t, ts.errors, 0)\n}\n\nfunc TestManualNameTag(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tts.runtime.VU.StateField.Options.SystemTags = metrics.ToSystemTagSet([]string{\"url\", \"name\"})\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\t\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\", null, { tags: { name: \"custom\" } } )\n\t\t\t\tws.onopen = () => {\n\t\t\t\t\tws.send(\"test\")\n\t\t\t\t}\n\t\t\t\tws.onmessage = (event) => {\n\t\t\t\t\tif (event.data != \"test\") {\n\t\t\t\t\t\tthrow new Error (\"echo'd data doesn't match our message!\");\n\t\t\t\t\t}\n\t\t\t\t\tws.close()\n\t\t\t\t}\n\t\t\t\tws.onerror = (e) => { throw JSON.stringify(e) }\n\t\t\t`))\n\trequire.NoError(t, err)\n\n\tcontainers := metrics.GetBufferedSamples(ts.samples)\n\trequire.NotEmpty(t, containers)\n\n\tfor _, sampleContainer := range containers {\n\t\trequire.NotEmpty(t, sampleContainer.GetSamples())\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\tdataToCheck := sample.Tags.Map()\n\t\t\trequire.NotEmpty(t, dataToCheck)\n\n\t\t\tassert.Equal(t, \"custom\", dataToCheck[\"url\"])\n\t\t\tassert.Equal(t, \"custom\", dataToCheck[\"name\"])\n\t\t}\n\t}\n}\n\nfunc TestSystemTags(t *testing.T) {\n\tt.Parallel()\n\n\ttestedSystemTags := []string{\"status\", \"subproto\", \"url\", \"ip\"}\n\tfor _, expectedTagStr := range testedSystemTags {\n\t\tt.Run(\"only \"+expectedTagStr, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\texpectedTag, err := metrics.SystemTagString(expectedTagStr)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tts := newTestState(t)\n\t\t\tsr := ts.tb.Replacer.Replace\n\t\t\tts.runtime.VU.StateField.Options.SystemTags = metrics.ToSystemTagSet([]string{expectedTagStr})\n\n\t\t\t_, err = ts.runtime.RunOnEventLoop(sr(`\n\t\t\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\t\t\tws.onopen = () => {\n\t\t\t\t\tws.send(\"test\")\n\t\t\t\t}\n\t\t\t\tws.onmessage = (event) => {\n\t\t\t\t\tif (event.data != \"test\") {\n\t\t\t\t\t\tthrow new Error (\"echo'd data doesn't match our message!\");\n\t\t\t\t\t}\n\t\t\t\t\tws.close()\n\t\t\t\t}\n\t\t\t\tws.onerror = (e) => { throw JSON.stringify(e) }\n\t\t\t`))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tcontainers := metrics.GetBufferedSamples(ts.samples)\n\t\t\trequire.NotEmpty(t, containers)\n\t\t\tfor _, sampleContainer := range containers {\n\t\t\t\trequire.NotEmpty(t, sampleContainer.GetSamples())\n\t\t\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\t\t\tvar dataToCheck map[string]string\n\t\t\t\t\tif metrics.NonIndexableSystemTags.Has(expectedTag) {\n\t\t\t\t\t\tdataToCheck = sample.Metadata\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdataToCheck = sample.Tags.Map()\n\t\t\t\t\t}\n\n\t\t\t\t\trequire.NotEmpty(t, dataToCheck)\n\t\t\t\t\tfor emittedTag := range dataToCheck {\n\t\t\t\t\t\tassert.Equal(t, expectedTagStr, emittedTag)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCustomTags(t *testing.T) {\n\tt.Parallel()\n\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\", null, {tags: {lorem: \"ipsum\", version: 13}})\n\tws.onopen = () => {\n\t\tws.send(\"something\")\n\t\tws.close()\n\t}\n\tws.onerror = (e) => { throw JSON.stringify(e) }\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n\n\tfor _, sampleContainer := range samples {\n\t\trequire.NotEmpty(t, sampleContainer.GetSamples())\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\tdataToCheck := sample.Tags.Map()\n\n\t\t\trequire.NotEmpty(t, dataToCheck)\n\n\t\t\tassert.Equal(t, \"ipsum\", dataToCheck[\"lorem\"])\n\t\t\tassert.Equal(t, \"13\", dataToCheck[\"version\"])\n\t\t\tassert.NotEmpty(t, dataToCheck[\"url\"])\n\t\t}\n\t}\n}\n\nfunc TestCompressionSession(t *testing.T) {\n\tt.Parallel()\n\tconst text string = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sed pharetra sapien. Nunc laoreet molestie ante ac gravida. Etiam interdum dui viverra posuere egestas. Pellentesque at dolor tristique, mattis turpis eget, commodo purus. Nunc orci aliquam.`\n\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tts.addHandler(\"/ws-compression\", &websocket.Upgrader{\n\t\tEnableCompression: true,\n\t\tReadBufferSize:    1024,\n\t\tWriteBufferSize:   1024,\n\t}, &testMessage{websocket.TextMessage, []byte(text)})\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar params = {\n\t\t\t\"compression\": \"deflate\"\n\t\t}\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-compression\", null, params)\n\n\t\tws.onmessage = (event) => {\n\t\t\tif (event.data != \"` + text + `\"){\n\t\t\t\tthrow new Error(\"wrong message received from server: \", event.data)\n\t\t\t}\n\n\t\t\tconst expectedExtension = \"permessage-deflate; server_no_context_takeover; client_no_context_takeover\"\n\t\t\tif (!(ws.extensions.includes(expectedExtension))) {\n\t\t\t\tthrow \"expected value '\" + expectedExtension + \"' missing in \" + JSON.stringify(ws.extensions);\n\t\t\t}\n\n\t\t\tws.close()\n\t\t}\n\n\t\t`))\n\n\trequire.NoError(t, err)\n\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\turl := sr(\"WSBIN_URL/ws-compression\")\n\tassertSessionMetricsEmitted(t, samples, \"\", url, http.StatusSwitchingProtocols, \"\")\n\tassertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samples, url, 1)\n\n\tassert.Len(t, ts.errors, 0)\n}\n\nfunc TestServerWithoutCompression(t *testing.T) {\n\tt.Parallel()\n\tconst text string = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sed pharetra sapien. Nunc laoreet molestie ante ac gravida. Etiam interdum dui viverra posuere egestas. Pellentesque at dolor tristique, mattis turpis eget, commodo purus. Nunc orci aliquam.`\n\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tts.addHandler(\"/ws-compression\", &websocket.Upgrader{}, &testMessage{websocket.TextMessage, []byte(text)})\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar params = {\n\t\t\t\"compression\": \"deflate\"\n\t\t}\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-compression\", null, params)\n\t\tws.onmessage = (event) => {\n\t\t\tif (event.data != \"` + text + `\"){\n\t\t\t\tthrow new Error(\"wrong message received from server: \", event.data)\n\t\t\t}\n\n\t\t\tws.close()\n\t\t}\n\t\t`))\n\n\trequire.NoError(t, err)\n\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\turl := sr(\"WSBIN_URL/ws-compression\")\n\tassertSessionMetricsEmitted(t, samples, \"\", url, http.StatusSwitchingProtocols, \"\")\n\tassertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samples, url, 1)\n\n\tassert.Len(t, ts.errors, 0)\n}\n\nfunc TestCompressionParams(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tcompression   string\n\t\texpectedError string\n\t}{\n\t\t{\n\t\t\tcompression:   `\"\"`,\n\t\t\texpectedError: `unsupported compression algorithm '', supported algorithm is 'deflate'`,\n\t\t},\n\t\t{\n\t\t\tcompression:   `null`,\n\t\t\texpectedError: `unsupported compression algorithm 'null', supported algorithm is 'deflate'`,\n\t\t},\n\t\t{\n\t\t\tcompression:   `undefined`,\n\t\t\texpectedError: `unsupported compression algorithm 'undefined', supported algorithm is 'deflate'`,\n\t\t},\n\t\t{\n\t\t\tcompression:   `\" \"`,\n\t\t\texpectedError: `unsupported compression algorithm '', supported algorithm is 'deflate'`,\n\t\t},\n\t\t{compression: `\"deflate\"`},\n\t\t{compression: `\"deflate \"`},\n\t\t{\n\t\t\tcompression:   `\"gzip\"`,\n\t\t\texpectedError: `unsupported compression algorithm 'gzip', supported algorithm is 'deflate'`,\n\t\t},\n\t\t{\n\t\t\tcompression:   `\"deflate, gzip\"`,\n\t\t\texpectedError: `unsupported compression algorithm 'deflate, gzip', supported algorithm is 'deflate'`,\n\t\t},\n\t\t{\n\t\t\tcompression:   `\"deflate, deflate\"`,\n\t\t\texpectedError: `unsupported compression algorithm 'deflate, deflate', supported algorithm is 'deflate'`,\n\t\t},\n\t\t{\n\t\t\tcompression:   `\"deflate, \"`,\n\t\t\texpectedError: `unsupported compression algorithm 'deflate,', supported algorithm is 'deflate'`,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.compression, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestState(t)\n\t\t\tsr := ts.tb.Replacer.Replace\n\n\t\t\tts.addHandler(\"/ws-compression-param\", &websocket.Upgrader{\n\t\t\t\tEnableCompression: true,\n\t\t\t\tReadBufferSize:    1024,\n\t\t\t\tWriteBufferSize:   1024,\n\t\t\t}, nil)\n\n\t\t\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\t\t\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-compression-param\", null, {\"compression\":` + testCase.compression + `})\n\t\t\t\t\tws.onopen = () => {\n\t\t\t\t\t\tws.close()\n\t\t\t\t\t}\n\t\t\t\t\t`))\n\n\t\t\tif testCase.expectedError == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), testCase.expectedError)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestSessionPing(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\tts := newTestState(t)\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\t\tws.onopen = () => {\n\t\t\t\tws.ping()\n\t\t\t}\n\n\t\t\tws.onpong = () => {\n\t\t\t\tcall(\"from onpong\")\n\t\t\t\tws.close()\n\t\t\t}\n\t\t\tws.onerror = (e) => { throw JSON.stringify(e) }\n\t\t`))\n\n\trequire.NoError(t, err)\n\n\tsamplesBuf := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n\tassert.Equal(t, []string{\"from onpong\"}, ts.callRecorder.Recorded())\n}\n\nfunc TestSessionPingAdd(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\tts := newTestState(t)\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\t\tws.addEventListener(\"open\", () => {\n\t\t\t\tws.ping()\n\t\t\t})\n\n\t\t\tws.onerror = (e) => { throw JSON.stringify(e) }\n\t\t\tws.addEventListener(\"pong\", () => {\n\t\t\t\tcall(\"from onpong\")\n\t\t\t\tws.close()\n\t\t\t})\n\t\t`))\n\n\trequire.NoError(t, err)\n\n\tsamplesBuf := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n\tassert.Equal(t, []string{\"from onpong\"}, ts.callRecorder.Recorded())\n}\n\nfunc TestLockingUpWithAThrow(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\tsr := tb.Replacer.Replace\n\n\tts := newTestState(t)\n\tgo destroySamples(ctx, ts.samples)\n\tts.runtime.VU.CtxField = ctx\n\terr := ts.runtime.EventLoop.Start(func() error {\n\t\t_, runErr := ts.runtime.VU.Runtime().RunString(sr(`\n\t\tlet a = 0;\n\t\tconst connections = 200;\n\t\tasync function s() {\n\t\t\tlet ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\t\tws.addEventListener(\"open\", () => {\n\t\t\t\tws.ping()\n\t\t\t\ta++\n\t\t\t})\n\n\t\t\tws.addEventListener(\"pong\", () => {\n\t\t\t\tws.ping()\n\t\t\t\tif (a == connections){\n\t\t\t\t\ta++\n\t\t\t\t\tws.close()\n\t\t\t\t\tthrow \"s\";\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\t[...Array(connections)].forEach(_ => s())\n\t\t`))\n\t\treturn runErr\n\t})\n\n\tcancel()\n\tassert.ErrorContains(t, err, \"s at <eval>\")\n\tts.runtime.EventLoop.WaitOnRegistered()\n}\n\nfunc TestLockingUpWithAJustGeneralCancel(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\tsr := tb.Replacer.Replace\n\n\tts := newTestState(t)\n\tdefer func() {\n\t\tclose(ts.samples)\n\t}()\n\tgo destroySamples(ctx, ts.samples)\n\tts.runtime.VU.CtxField = ctx\n\trequire.NoError(t, ts.runtime.VU.RuntimeField.Set(\"cancel\", cancel))\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tlet a = 0;\n\t\tconst connections = 1000;\n\t\tasync function s() {\n\t\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\t\tws.addEventListener(\"open\", () => {\n\t\t\t\tws.ping()\n\t\t\t})\n\n\t\t\tws.addEventListener(\"pong\", () => {\n\t\t\t\ttry{\n\t\t\t\t\tws.ping() // this will\n\t\t\t\t} catch(e) {}\n\t\t\t\ta++\n\t\t\t\tif (a == connections){\n\t\t\t\t\tcancel()\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\t[...Array(connections)].forEach(_ => s())\n\t\t`))\n\n\tcancel()\n\tassert.NoError(t, err)\n\tts.runtime.EventLoop.WaitOnRegistered()\n}\n\nfunc destroySamples(ctx context.Context, c <-chan metrics.SampleContainer) {\n\tfor {\n\t\tselect {\n\t\tcase <-c:\n\t\tcase <-ctx.Done():\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc TestArrayBufferViewSupport(t *testing.T) {\n\tt.Parallel()\n\tfor _, name := range []string{ // Commented ones aren't support by Sobek\n\t\t\"Int8Array\", \"Int16Array\", \"Int32Array\",\n\t\t\"Uint8Array\", \"Uint16Array\", \"Uint32Array\", \"Uint8ClampedArray\",\n\t\t// \"BigInt64Array\", \"BigUint64Arrays\",\n\t\t/*\"Float16Array\", */ \"Float32Array\", \"Float64Array\",\n\t} {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttestArrayBufferViewSupport(t, name)\n\t\t})\n\t}\n}\n\nfunc testArrayBufferViewSupport(t *testing.T, viewName string) {\n\tt.Helper()\n\tts := newTestState(t)\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\tts.runtime.VU.StateField.Logger = logger\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(fmt.Sprintf(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tconst sent = new %[1]s([164, 41])\n\t\t\tws.send(sent)\n\t\t\tws.onmessage = async (e) => {\n\t\t\t\tconst received = new %[1]s(await e.data.arrayBuffer());\n\t\t\t\tfor (let i = 0; i < sent.length; i++) {\n\t\t\t\t\tif (sent.at(i) != received.at(i)) {\n\t\t\t\t\t\tthrow \"Values at \" + i + \" were different \" + sent.at(i) + \" vs \" + received.at(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tws.close()\n\t\t\t}\n\t\t})\n\t`, viewName)))\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 0)\n}\n\nfunc TestReadyStateSwitch(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\tts.runtime.VU.StateField.Logger = logger\n\t_, err := ts.runtime.RunOnEventLoop(ts.tb.Replacer.Replace(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\ttry {\n\t\t\tswitch (ws.readyState) {\n\t\t\t\tcase 0:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow \"ws.readyState doesn't get correct value in switch\"\n\t\t\t}\n\t\t} finally {\n\t\t\tws.close()\n\t\t}\n\t`))\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 0)\n}\n\nfunc TestCloseWithCode(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.send(\"something\")\n\t\t\tws.close(1000)\n\t\t})\n\t\tws.addEventListener(\"close\", (event) => {\n\t\t\tif (event.code !== 1000) {\n\t\t\t\tthrow \"Expected code 1000, instead got: \" + event.code\n\t\t\t}\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestCloseWithCodeAndReason(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.send(\"something\")\n\t\t\tws.close(1000, \"a really good reason\")\n\t\t})\n\t\tws.addEventListener(\"close\", (event) => {\n\t\t\tif (event.code !== 1000) {\n\t\t\t\tthrow \"Expected code 1000, instead got: \" + event.code\n\t\t\t}\n\n\t\t\tif (event.reason !== \"\") {\n\t\t\t\tthrow \"Expected empty reason when calling close from client, instead got: \" + event.reason\n\t\t\t}\n\t\t})\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestCloseWithDisallowedCode(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.send(\"something\")\n\t\t\tws.close(1001)\n\t\t})\n\t`))\n\trequire.ErrorContains(t, err, \"InvalidAccessError: Failed to execute 'close' on 'WebSocket': The close code must be either 1000, or between 3000 and 4999\")\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestCloseWithReasonTooLong(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-echo\")\n\t\tws.addEventListener(\"open\", () => {\n\t\t\tws.send(\"something\")\n\t\t\tws.close(1000, \"a really really long reason about why we are closing this connection, which is clearly over the top and too long, long enough to be longer than the allowed amount of 123 bytes\")\n\t\t})\n\t`))\n\trequire.ErrorContains(t, err, \"SyntaxError: Failed to execute 'close' on 'WebSocket': The message must not be greater than 123 bytes\")\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-echo\"), http.StatusSwitchingProtocols, \"\")\n}\n\nfunc TestRemoteCloseWithCodeAndReason(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tts.addHandler(\"/ws-remote-close\", nil, &testMessage{\n\t\tkind: websocket.CloseMessage,\n\t\tdata: websocket.FormatCloseMessage(1001, \"closed by server\"),\n\t})\n\n\t_, err := ts.runtime.RunOnEventLoop(sr(`\n\t\tvar ws = new WebSocket(\"WSBIN_URL/ws-remote-close\");\n\t\tws.onclose = (event) => {\n\t\t\tif (event.code !== 1001) {\n\t\t\t\tthrow new Error(\"Expected code 1001, got: \" + event.code);\n\t\t\t}\n\t\t\tif (event.reason !== \"closed by server\") {\n\t\t\t\tthrow new Error(\"Expected reason 'closed by server', got: \" + event.reason);\n\t\t\t}\n\t\t\tcall(\"remote closed\");\n\t\t};\n\t`))\n\trequire.NoError(t, err)\n\tsamples := metrics.GetBufferedSamples(ts.samples)\n\tassertSessionMetricsEmitted(t, samples, \"\", sr(\"WSBIN_URL/ws-remote-close\"), http.StatusSwitchingProtocols, \"\")\n\tassert.Equal(t, []string{\"remote closed\"}, ts.callRecorder.Recorded())\n}\n"
  },
  {
    "path": "internal/js/modules/k6/ws/ws.go",
    "content": "// Package ws implements a k6/ws for k6. It provides basic functionality to communicate over websockets\n// that *blocks* the event loop while the connection is opened.\npackage ws\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\thttpModule \"go.k6.io/k6/js/modules/k6/http\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype (\n\t// RootModule is the global module instance that will create module\n\t// instances for each VU.\n\tRootModule struct{}\n\n\t// WS represents a module instance of the WebSocket module.\n\tWS struct {\n\t\tvu  modules.VU\n\t\tobj *sobek.Object\n\t}\n)\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &WS{}\n)\n\n// New returns a pointer to a new RootModule instance.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance implements the modules.Module interface to return\n// a new instance for each VU.\nfunc (*RootModule) NewModuleInstance(m modules.VU) modules.Instance {\n\trt := m.Runtime()\n\tmi := &WS{\n\t\tvu: m,\n\t}\n\tobj := rt.NewObject()\n\tif err := obj.Set(\"connect\", mi.Connect); err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tmi.obj = obj\n\treturn mi\n}\n\n// ErrWSInInitContext is returned when websockets are using in the init context\nvar ErrWSInInitContext = common.NewInitContextError(\"using websockets in the init context is not supported\")\n\n// Socket is the representation of the websocket returned to the js.\ntype Socket struct {\n\trt            *sobek.Runtime\n\tctx           context.Context //nolint:containedctx\n\tconn          *websocket.Conn\n\teventHandlers map[string][]sobek.Callable\n\tscheduled     chan sobek.Callable\n\tdone          chan struct{}\n\tshutdownOnce  sync.Once\n\n\tpingSendTimestamps map[string]time.Time\n\tpingSendCounter    int\n\n\ttagsAndMeta    *metrics.TagsAndMeta\n\tsamplesOutput  chan<- metrics.SampleContainer\n\tbuiltinMetrics *metrics.BuiltinMetrics\n}\n\n// HTTPResponse is the http response returned by ws.connect.\ntype HTTPResponse struct {\n\tURL     string            `json:\"url\"`\n\tStatus  int               `json:\"status\"`\n\tHeaders map[string]string `json:\"headers\"`\n\tBody    string            `json:\"body\"`\n\tError   string            `json:\"error\"`\n}\n\ntype message struct {\n\tmtype int // message type consts as defined in gorilla/websocket/conn.go\n\tdata  []byte\n}\n\ntype wsConnectArgs struct {\n\tsetupFn           sobek.Callable\n\theaders           http.Header\n\tenableCompression bool\n\tcookieJar         *cookiejar.Jar\n\ttagsAndMeta       *metrics.TagsAndMeta\n}\n\nconst writeWait = 10 * time.Second\n\n// Exports returns the exports of the ws module.\nfunc (mi *WS) Exports() modules.Exports {\n\treturn modules.Exports{Default: mi.obj}\n}\n\n// Connect establishes a WebSocket connection based on the parameters provided.\n//\n//nolint:funlen\nfunc (mi *WS) Connect(url string, args ...sobek.Value) (*HTTPResponse, error) {\n\tctx := mi.vu.Context()\n\trt := mi.vu.Runtime()\n\tstate := mi.vu.State()\n\tif state == nil {\n\t\treturn nil, ErrWSInInitContext\n\t}\n\n\tparsedArgs, err := parseConnectArgs(state, rt, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tparsedArgs.tagsAndMeta.SetSystemTagOrMetaIfEnabled(state.Options.SystemTags, metrics.TagURL, url)\n\n\tsocket, httpResponse, connEndHook, err := mi.dial(ctx, state, rt, url, parsedArgs)\n\tdefer connEndHook()\n\tif err != nil {\n\t\t// Pass the error to the user script before exiting immediately\n\t\tsocket.handleEvent(\"error\", rt.ToValue(err))\n\t\tif state.Options.Throw.Bool {\n\t\t\treturn nil, err\n\t\t}\n\t\tif httpResponse != nil {\n\t\t\treturn wrapHTTPResponse(httpResponse)\n\t\t}\n\t\treturn &HTTPResponse{Error: err.Error()}, nil\n\t}\n\n\tdefer socket.Close()\n\n\t// Run the user-provided set up function\n\tif _, err := parsedArgs.setupFn(sobek.Undefined(), rt.ToValue(&socket)); err != nil {\n\t\t_ = socket.closeConnection(websocket.CloseGoingAway)\n\t\treturn nil, err\n\t}\n\twsResponse, wsRespErr := wrapHTTPResponse(httpResponse)\n\tif wsRespErr != nil {\n\t\treturn nil, wsRespErr\n\t}\n\twsResponse.URL = url\n\n\t// The connection is now open, emit the event\n\tsocket.handleEvent(\"open\")\n\n\t// Make the default close handler a noop to avoid duplicate closes,\n\t// since we use custom closing logic to call user's event\n\t// handlers and for cleanup. See closeConnection.\n\t// closeConnection is not set directly as a handler here to\n\t// avoid race conditions when calling the Sobek runtime.\n\tsocket.conn.SetCloseHandler(func(_ int, _ string) error { return nil })\n\n\t// Pass ping/pong events through the main control loop\n\tpingChan := make(chan string)\n\tpongChan := make(chan string)\n\tsocket.conn.SetPingHandler(func(msg string) error { pingChan <- msg; return nil })\n\tsocket.conn.SetPongHandler(func(pingID string) error { pongChan <- pingID; return nil })\n\n\treadDataChan := make(chan *message)\n\treadCloseChan := make(chan int)\n\treadErrChan := make(chan error)\n\n\t// Wraps a couple of channels around conn.ReadMessage\n\tgo socket.readPump(readDataChan, readErrChan, readCloseChan)\n\n\t// This is the main control loop. All JS code (including error handlers)\n\t// should only be executed by this thread to avoid race conditions\n\tfor {\n\t\tselect {\n\t\tcase pingData := <-pingChan:\n\t\t\t// Handle pings received from the server\n\t\t\t// - trigger the `ping` event\n\t\t\t// - reply with pong (needed when `SetPingHandler` is overwritten)\n\t\t\terr := socket.conn.WriteControl(websocket.PongMessage, []byte(pingData), time.Now().Add(writeWait))\n\t\t\tif err != nil {\n\t\t\t\tsocket.handleEvent(\"error\", rt.ToValue(err))\n\t\t\t}\n\t\t\tsocket.handleEvent(\"ping\")\n\n\t\tcase pingID := <-pongChan:\n\t\t\t// Handle pong responses to our pings\n\t\t\tsocket.trackPong(pingID)\n\t\t\tsocket.handleEvent(\"pong\")\n\n\t\tcase msg := <-readDataChan:\n\t\t\tmetrics.PushIfNotDone(ctx, socket.samplesOutput, metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: socket.builtinMetrics.WSMessagesReceived,\n\t\t\t\t\tTags:   socket.tagsAndMeta.Tags,\n\t\t\t\t},\n\t\t\t\tTime:     time.Now(),\n\t\t\t\tMetadata: socket.tagsAndMeta.Metadata,\n\t\t\t\tValue:    1,\n\t\t\t})\n\n\t\t\tif msg.mtype == websocket.BinaryMessage {\n\t\t\t\tab := rt.NewArrayBuffer(msg.data)\n\t\t\t\tsocket.handleEvent(\"binaryMessage\", rt.ToValue(&ab))\n\t\t\t} else {\n\t\t\t\tsocket.handleEvent(\"message\", rt.ToValue(string(msg.data)))\n\t\t\t}\n\n\t\tcase readErr := <-readErrChan:\n\t\t\tsocket.handleEvent(\"error\", rt.ToValue(readErr))\n\n\t\tcase code := <-readCloseChan:\n\t\t\t_ = socket.closeConnection(code)\n\n\t\tcase scheduledFn := <-socket.scheduled:\n\t\t\tif _, err := scheduledFn(sobek.Undefined()); err != nil {\n\t\t\t\t_ = socket.closeConnection(websocket.CloseGoingAway)\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\tcase <-ctx.Done():\n\t\t\t// VU is shutting down during an interrupt\n\t\t\t// socket events will not be forwarded to the VU\n\t\t\t_ = socket.closeConnection(websocket.CloseGoingAway)\n\n\t\tcase <-socket.done:\n\t\t\t// This is the final exit point normally triggered by closeConnection\n\t\t\treturn wsResponse, nil\n\t\t}\n\t}\n}\n\nfunc (mi *WS) dial(\n\tctx context.Context, state *lib.State, rt *sobek.Runtime, url string,\n\targs *wsConnectArgs,\n) (*Socket, *http.Response, func(), error) {\n\t// Overriding the NextProtos to avoid talking http2\n\tvar tlsConfig *tls.Config\n\tif state.TLSConfig != nil {\n\t\ttlsConfig = state.TLSConfig.Clone()\n\t\ttlsConfig.NextProtos = []string{\"http/1.1\"}\n\t}\n\n\twsd := websocket.Dialer{\n\t\tHandshakeTimeout: time.Second * 60, // TODO configurable\n\t\t// Pass a custom net.DialContext function to websocket.Dialer that will substitute\n\t\t// the underlying net.Conn with our own tracked netext.Conn\n\t\tNetDialContext:    state.Dialer.DialContext,\n\t\tProxy:             http.ProxyFromEnvironment,\n\t\tTLSClientConfig:   tlsConfig,\n\t\tEnableCompression: args.enableCompression,\n\t}\n\t// this is needed because of how interfaces work and that wsd.Jar is http.Cookiejar\n\tif args.cookieJar != nil {\n\t\twsd.Jar = args.cookieJar\n\t}\n\n\tconnStart := time.Now()\n\tconn, httpResponse, dialErr := wsd.DialContext(ctx, url, args.headers)\n\tconnEnd := time.Now()\n\n\tif state.Options.SystemTags.Has(metrics.TagIP) && conn.RemoteAddr() != nil {\n\t\tif ip, _, err := net.SplitHostPort(conn.RemoteAddr().String()); err == nil {\n\t\t\targs.tagsAndMeta.SetSystemTagOrMeta(metrics.TagIP, ip)\n\t\t}\n\t}\n\n\tif httpResponse != nil {\n\t\tif state.Options.SystemTags.Has(metrics.TagStatus) {\n\t\t\targs.tagsAndMeta.SetSystemTagOrMeta(\n\t\t\t\tmetrics.TagStatus, strconv.Itoa(httpResponse.StatusCode))\n\t\t}\n\n\t\tif state.Options.SystemTags.Has(metrics.TagSubproto) {\n\t\t\targs.tagsAndMeta.SetSystemTagOrMeta(\n\t\t\t\tmetrics.TagSubproto, httpResponse.Header.Get(\"Sec-WebSocket-Protocol\"))\n\t\t}\n\t}\n\n\tsocket := Socket{\n\t\tctx:                ctx,\n\t\trt:                 rt,\n\t\tconn:               conn,\n\t\teventHandlers:      make(map[string][]sobek.Callable),\n\t\tpingSendTimestamps: make(map[string]time.Time),\n\t\tscheduled:          make(chan sobek.Callable),\n\t\tdone:               make(chan struct{}),\n\t\tsamplesOutput:      state.Samples,\n\t\ttagsAndMeta:        args.tagsAndMeta,\n\t\tbuiltinMetrics:     state.BuiltinMetrics,\n\t}\n\n\tconnEndHook := socket.pushSessionMetrics(connStart, connEnd)\n\n\treturn &socket, httpResponse, connEndHook, dialErr\n}\n\n// On is used to configure what the websocket should do on each event.\nfunc (s *Socket) On(event string, handler sobek.Value) {\n\tif handler, ok := sobek.AssertFunction(handler); ok {\n\t\ts.eventHandlers[event] = append(s.eventHandlers[event], handler)\n\t}\n}\n\nfunc (s *Socket) handleEvent(event string, args ...sobek.Value) {\n\tif handlers, ok := s.eventHandlers[event]; ok {\n\t\tfor _, handler := range handlers {\n\t\t\tif _, err := handler(sobek.Undefined(), args...); err != nil {\n\t\t\t\tcommon.Throw(s.rt, err)\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Send writes the given string message to the connection.\nfunc (s *Socket) Send(message string) {\n\tif err := s.conn.WriteMessage(websocket.TextMessage, []byte(message)); err != nil {\n\t\ts.handleEvent(\"error\", s.rt.ToValue(err))\n\t}\n\n\tmetrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: s.builtinMetrics.WSMessagesSent,\n\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t},\n\t\tTime:     time.Now(),\n\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\tValue:    1,\n\t})\n}\n\n// SendBinary writes the given ArrayBuffer message to the connection.\nfunc (s *Socket) SendBinary(message sobek.Value) {\n\tif message == nil {\n\t\tcommon.Throw(s.rt, errors.New(\"missing argument, expected ArrayBuffer\"))\n\t}\n\n\tmsg := message.Export()\n\tif ab, ok := msg.(sobek.ArrayBuffer); ok {\n\t\tif err := s.conn.WriteMessage(websocket.BinaryMessage, ab.Bytes()); err != nil {\n\t\t\ts.handleEvent(\"error\", s.rt.ToValue(err))\n\t\t}\n\t} else {\n\t\tvar jsType string\n\t\tswitch {\n\t\tcase sobek.IsNull(message), sobek.IsUndefined(message):\n\t\t\tjsType = message.String()\n\t\tdefault:\n\t\t\tjsType = message.ToObject(s.rt).Get(\"constructor\").ToObject(s.rt).Get(\"name\").String()\n\t\t}\n\t\tcommon.Throw(s.rt, fmt.Errorf(\"expected ArrayBuffer as argument, received: %s\", jsType))\n\t}\n\n\tmetrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: s.builtinMetrics.WSMessagesSent,\n\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t},\n\t\tTime:     time.Now(),\n\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\tValue:    1,\n\t})\n}\n\n// Ping sends a ping message over the websocket.\nfunc (s *Socket) Ping() {\n\tdeadline := time.Now().Add(writeWait)\n\tpingID := strconv.Itoa(s.pingSendCounter)\n\tdata := []byte(pingID)\n\n\terr := s.conn.WriteControl(websocket.PingMessage, data, deadline)\n\tif err != nil {\n\t\ts.handleEvent(\"error\", s.rt.ToValue(err))\n\t\treturn\n\t}\n\n\ts.pingSendTimestamps[pingID] = time.Now()\n\ts.pingSendCounter++\n}\n\nfunc (s *Socket) trackPong(pingID string) {\n\tpongTimestamp := time.Now()\n\n\tif _, ok := s.pingSendTimestamps[pingID]; !ok {\n\t\t// We received a pong for a ping we didn't send; ignore\n\t\t// (this shouldn't happen with a compliant server)\n\t\treturn\n\t}\n\tpingTimestamp := s.pingSendTimestamps[pingID]\n\n\tmetrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: s.builtinMetrics.WSPing,\n\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t},\n\t\tTime:     pongTimestamp,\n\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\tValue:    metrics.D(pongTimestamp.Sub(pingTimestamp)),\n\t})\n}\n\n// SetTimeout executes the provided function inside the socket's event loop after at least the provided\n// timeout, which is in ms, has elapsed\nfunc (s *Socket) SetTimeout(fn sobek.Callable, timeoutMs float64) error {\n\t// Starts a goroutine, blocks once on the timeout and pushes the callable\n\t// back to the main loop through the scheduled channel.\n\t//\n\t// Intentionally not using the generic GetDurationValue() helper, since this\n\t// API is meant to use ms, similar to the original SetTimeout() JS API.\n\td := time.Duration(timeoutMs * float64(time.Millisecond))\n\tif d <= 0 {\n\t\treturn fmt.Errorf(\"setTimeout requires a >0 timeout parameter, received %.2f\", timeoutMs)\n\t}\n\tgo func() {\n\t\tselect {\n\t\tcase <-time.After(d):\n\t\t\tselect {\n\t\t\tcase s.scheduled <- fn:\n\t\t\tcase <-s.done:\n\t\t\t\treturn\n\t\t\t}\n\n\t\tcase <-s.done:\n\t\t\treturn\n\t\t}\n\t}()\n\n\treturn nil\n}\n\n// SetInterval executes the provided function inside the socket's event loop each interval time, which is\n// in ms\nfunc (s *Socket) SetInterval(fn sobek.Callable, intervalMs float64) error {\n\t// Starts a goroutine, blocks forever on the ticker and pushes the callable\n\t// back to the main loop through the scheduled channel.\n\t//\n\t// Intentionally not using the generic GetDurationValue() helper, since this\n\t// API is meant to use ms, similar to the original SetInterval() JS API.\n\td := time.Duration(intervalMs * float64(time.Millisecond))\n\tif d <= 0 {\n\t\treturn fmt.Errorf(\"setInterval requires a >0 timeout parameter, received %.2f\", intervalMs)\n\t}\n\tgo func() {\n\t\tticker := time.NewTicker(d)\n\t\tdefer ticker.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ticker.C:\n\t\t\t\tselect {\n\t\t\t\tcase s.scheduled <- fn:\n\t\t\t\tcase <-s.done:\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\tcase <-s.done:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn nil\n}\n\n// Close closes the webscocket. If providede the first argument will be used as the code for the close message.\nfunc (s *Socket) Close(args ...sobek.Value) {\n\tcode := websocket.CloseGoingAway\n\tif len(args) > 0 {\n\t\tcode = int(args[0].ToInteger())\n\t}\n\n\t_ = s.closeConnection(code)\n}\n\n// closeConnection cleanly closes the WebSocket connection.\n// Returns an error if sending the close control frame fails.\nfunc (s *Socket) closeConnection(code int) error {\n\tvar err error\n\n\ts.shutdownOnce.Do(func() {\n\t\t// this is because handleEvent can panic ... on purpose so we just make sure we\n\t\t// close the connection and the channel\n\t\tdefer func() {\n\t\t\t_ = s.conn.Close()\n\n\t\t\t// Stop the main control loop\n\t\t\tclose(s.done)\n\t\t}()\n\t\terr = s.conn.WriteControl(websocket.CloseMessage,\n\t\t\twebsocket.FormatCloseMessage(code, \"\"),\n\t\t\ttime.Now().Add(writeWait),\n\t\t)\n\t\tif err != nil {\n\t\t\t// Call the user-defined error handler\n\t\t\ts.handleEvent(\"error\", s.rt.ToValue(err))\n\t\t}\n\n\t\t// Call the user-defined close handler\n\t\ts.handleEvent(\"close\", s.rt.ToValue(code))\n\t})\n\n\treturn err\n}\n\nfunc (s *Socket) pushSessionMetrics(connStart, connEnd time.Time) func() {\n\tconnDuration := metrics.D(connEnd.Sub(connStart))\n\n\tmetrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.ConnectedSamples{\n\t\tSamples: []metrics.Sample{\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: s.builtinMetrics.WSSessions,\n\t\t\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t\t\t},\n\t\t\t\tTime:     connStart,\n\t\t\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\t\t\tValue:    1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: s.builtinMetrics.WSConnecting,\n\t\t\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t\t\t},\n\t\t\t\tTime:     connStart,\n\t\t\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\t\t\tValue:    connDuration,\n\t\t\t},\n\t\t},\n\t\tTags: s.tagsAndMeta.Tags,\n\t\tTime: connStart,\n\t})\n\n\treturn func() {\n\t\tend := time.Now()\n\t\tsessionDuration := metrics.D(end.Sub(connStart))\n\n\t\tmetrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: s.builtinMetrics.WSSessionDuration,\n\t\t\t\tTags:   s.tagsAndMeta.Tags,\n\t\t\t},\n\t\t\tTime:     connStart,\n\t\t\tMetadata: s.tagsAndMeta.Metadata,\n\t\t\tValue:    sessionDuration,\n\t\t})\n\t}\n}\n\n// Wraps conn.ReadMessage in a channel\nfunc (s *Socket) readPump(readChan chan *message, errorChan chan error, closeChan chan int) {\n\tfor {\n\t\tmessageType, data, err := s.conn.ReadMessage()\n\t\tif err != nil {\n\t\t\tif websocket.IsUnexpectedCloseError(\n\t\t\t\terr, websocket.CloseNormalClosure, websocket.CloseGoingAway) {\n\t\t\t\t// Report an unexpected closure\n\t\t\t\tselect {\n\t\t\t\tcase errorChan <- err:\n\t\t\t\tcase <-s.done:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tcode := websocket.CloseGoingAway\n\t\t\te := new(websocket.CloseError)\n\n\t\t\tif errors.As(err, &e) {\n\t\t\t\tcode = e.Code\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase closeChan <- code:\n\t\t\tcase <-s.done:\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tselect {\n\t\tcase readChan <- &message{messageType, data}:\n\t\tcase <-s.done:\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Wrap the raw HTTPResponse we received to a WSHTTPResponse we can pass to the user\nfunc wrapHTTPResponse(httpResponse *http.Response) (*HTTPResponse, error) {\n\twsResponse := HTTPResponse{\n\t\tStatus: httpResponse.StatusCode,\n\t}\n\n\tbody, err := io.ReadAll(httpResponse.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = httpResponse.Body.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\twsResponse.Body = string(body)\n\n\twsResponse.Headers = make(map[string]string, len(httpResponse.Header))\n\tfor k, vs := range httpResponse.Header {\n\t\twsResponse.Headers[k] = strings.Join(vs, \", \")\n\t}\n\n\treturn &wsResponse, nil\n}\n\nfunc parseConnectArgs(state *lib.State, rt *sobek.Runtime, args ...sobek.Value) (*wsConnectArgs, error) {\n\t// The params argument is optional\n\tvar callableV, paramsV sobek.Value\n\tswitch len(args) {\n\tcase 2:\n\t\tparamsV = args[0]\n\t\tcallableV = args[1]\n\tcase 1:\n\t\tparamsV = sobek.Undefined()\n\t\tcallableV = args[0]\n\tdefault:\n\t\treturn nil, errors.New(\"invalid number of arguments to ws.connect\")\n\t}\n\t// Get the callable (required)\n\tsetupFn, isFunc := sobek.AssertFunction(callableV)\n\tif !isFunc {\n\t\treturn nil, errors.New(\"last argument to ws.connect must be a function\")\n\t}\n\n\theaders := make(http.Header)\n\theaders.Set(\"User-Agent\", state.Options.UserAgent.String)\n\ttagsAndMeta := state.Tags.GetCurrentValues()\n\tparsedArgs := &wsConnectArgs{\n\t\tsetupFn:     setupFn,\n\t\theaders:     headers,\n\t\tcookieJar:   state.CookieJar,\n\t\ttagsAndMeta: &tagsAndMeta,\n\t}\n\n\tif common.IsNullish(paramsV) {\n\t\treturn parsedArgs, nil\n\t}\n\n\t// Parse the optional second argument (params)\n\tparams := paramsV.ToObject(rt)\n\tfor _, k := range params.Keys() {\n\t\tswitch k {\n\t\tcase \"headers\":\n\t\t\theadersV := params.Get(k)\n\t\t\tif common.IsNullish(headersV) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\theadersObj := headersV.ToObject(rt)\n\t\t\tif headersObj == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, key := range headersObj.Keys() {\n\t\t\t\tparsedArgs.headers.Set(key, headersObj.Get(key).String())\n\t\t\t}\n\t\tcase \"tags\":\n\t\t\tif err := common.ApplyCustomUserTags(rt, parsedArgs.tagsAndMeta, params.Get(k)); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid ws.connect() metric tags: %w\", err)\n\t\t\t}\n\t\tcase \"jar\":\n\t\t\tjarV := params.Get(k)\n\t\t\tif common.IsNullish(jarV) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif v, ok := jarV.Export().(*httpModule.CookieJar); ok {\n\t\t\t\tparsedArgs.cookieJar = v.Jar\n\t\t\t}\n\t\tcase \"compression\":\n\t\t\t// deflate compression algorithm is supported - as defined in RFC7692\n\t\t\t// compression here relies on the implementation in gorilla/websocket package, usage is\n\t\t\t// experimental and may result in decreased performance. package supports\n\t\t\t// only \"no context takeover\" scenario\n\n\t\t\talgoString := strings.TrimSpace(params.Get(k).ToString().String())\n\t\t\tif algoString == \"\" {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif algoString != \"deflate\" {\n\t\t\t\treturn nil, fmt.Errorf(\"unsupported compression algorithm '%s', supported algorithm is 'deflate'\", algoString)\n\t\t\t}\n\n\t\t\tparsedArgs.enableCompression = true\n\t\t}\n\t}\n\n\treturn parsedArgs, nil\n}\n"
  },
  {
    "path": "internal/js/modules/k6/ws/ws_test.go",
    "content": "package ws\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"net/http/httptest\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\thttpModule \"go.k6.io/k6/js/modules/k6/http\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst statusProtocolSwitch = 101\n\nfunc assertSessionMetricsEmitted(t *testing.T, sampleContainers []metrics.SampleContainer, subprotocol, url string, status int, group string) { //nolint:unparam\n\tseenSessions := false\n\tseenSessionDuration := false\n\tseenConnecting := false\n\n\tfor _, sampleContainer := range sampleContainers {\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\ttags := sample.Tags.Map()\n\t\t\tif tags[\"url\"] == url {\n\t\t\t\tswitch sample.Metric.Name {\n\t\t\t\tcase metrics.WSConnectingName:\n\t\t\t\t\tseenConnecting = true\n\t\t\t\tcase metrics.WSSessionDurationName:\n\t\t\t\t\tseenSessionDuration = true\n\t\t\t\tcase metrics.WSSessionsName:\n\t\t\t\t\tseenSessions = true\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(t, strconv.Itoa(status), tags[\"status\"])\n\t\t\t\tassert.Equal(t, subprotocol, tags[\"subproto\"])\n\t\t\t\tassert.Equal(t, group, tags[\"group\"])\n\t\t\t}\n\t\t}\n\t}\n\tassert.True(t, seenConnecting, \"url %s didn't emit Connecting\", url)\n\tassert.True(t, seenSessions, \"url %s didn't emit Sessions\", url)\n\tassert.True(t, seenSessionDuration, \"url %s didn't emit SessionDuration\", url)\n}\n\nfunc assertMetricEmittedCount(t *testing.T, metricName string, sampleContainers []metrics.SampleContainer, url string, count int) {\n\tt.Helper()\n\tactualCount := 0\n\n\tfor _, sampleContainer := range sampleContainers {\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\tsurl, ok := sample.Tags.Get(\"url\")\n\t\t\tassert.True(t, ok)\n\t\t\tif surl == url && sample.Metric.Name == metricName {\n\t\t\t\tactualCount++\n\t\t\t}\n\t\t}\n\t}\n\tassert.Equal(t, count, actualCount, \"url %s emitted %s %d times, expected was %d times\", url, metricName, actualCount, count)\n}\n\ntype testState struct {\n\t*modulestest.Runtime\n\ttb      *httpmultibin.HTTPMultiBin\n\tsamples chan metrics.SampleContainer\n}\n\nfunc newTestState(t testing.TB) testState {\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\ttestRuntime := modulestest.NewRuntime(t)\n\tsamples := make(chan metrics.SampleContainer, 1000)\n\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.State{\n\t\tDialer: tb.Dialer,\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: metrics.NewSystemTagSet(\n\t\t\t\tmetrics.TagURL,\n\t\t\t\tmetrics.TagProto,\n\t\t\t\tmetrics.TagStatus,\n\t\t\t\tmetrics.TagSubproto,\n\t\t\t),\n\t\t\tUserAgent: null.StringFrom(\"TestUserAgent\"),\n\t\t\tThrow:     null.BoolFrom(true),\n\t\t},\n\t\tSamples:        samples,\n\t\tTLSConfig:      tb.TLSClientConfig,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\n\tm := New().NewModuleInstance(testRuntime.VU)\n\trequire.NoError(t, testRuntime.VU.RuntimeField.Set(\"ws\", m.Exports().Default))\n\ttestRuntime.MoveToVUContext(state)\n\n\treturn testState{\n\t\tRuntime: testRuntime,\n\t\ttb:      tb,\n\t\tsamples: samples,\n\t}\n}\n\nfunc TestSessionConnectWs(t *testing.T) {\n\t// TODO: split and paralelize tests\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.close()\n\t\t});\n\t\tif (res.status != 101) { throw new Error(\"connection failed with status: \" + res.status); }\n\t\t`))\n\trequire.NoError(t, err)\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestSessionConnectWss(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar res = ws.connect(\"WSSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.close()\n\t\t});\n\t\tif (res.status != 101) { throw new Error(\"TLS connection failed with status: \" + res.status); }\n\t\t`))\n\trequire.NoError(t, err)\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestSessionOpen(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar opened = false;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.on(\"open\", function() {\n\t\t\t\topened = true;\n\t\t\t\tsocket.close()\n\t\t\t})\n\t\t});\n\t\tif (!opened) { throw new Error (\"open event not fired\"); }\n\t\t`))\n\trequire.NoError(t, err)\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestSessionSendReceive(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.on(\"open\", function() {\n\t\t\t\tsocket.send(\"test\")\n\t\t\t})\n\t\t\tsocket.on(\"message\", function (data) {\n\t\t\t\tif (!data==\"test\") {\n\t\t\t\t\tthrow new Error (\"echo'd data doesn't match our message!\");\n\t\t\t\t}\n\t\t\t\tsocket.close()\n\t\t\t});\n\t\t});\n\t\t`))\n\trequire.NoError(t, err)\n\tsamplesBuf := metrics.GetBufferedSamples(test.samples)\n\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n\tassertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr(\"WSBIN_URL/ws-echo\"), 1)\n\tassertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr(\"WSBIN_URL/ws-echo\"), 1)\n}\n\nfunc TestSessionInterval(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar counter = 0;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.setInterval(function () {\n\t\t\t\tcounter += 1;\n\t\t\t\tif (counter > 2) { socket.close(); }\n\t\t\t}, 100);\n\t\t});\n\t\tif (counter < 3) {throw new Error (\"setInterval should have been called at least 3 times, counter=\" + counter);}\n\t\t`))\n\trequire.NoError(t, err)\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestSessionNegativeInterval(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar counter = 0;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.setInterval(function () {\n\t\t\t\tcounter += 1;\n\t\t\t\tif (counter > 2) { socket.close(); }\n\t\t\t}, -1.23);\n\t\t});\n\t\t`))\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"setInterval requires a >0 timeout parameter, received -1.23 \")\n}\n\nfunc TestSessionIntervalSub1(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar counter = 0;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.setInterval(function () {\n\t\t\t\tcounter += 1;\n\t\t\t\tif (counter > 2) { socket.close(); }\n\t\t\t}, 0.3);\n\t\t});\n\t\t`))\n\trequire.NoError(t, err)\n}\n\nfunc TestSessionTimeout(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar start = new Date().getTime();\n\t\tvar elapsed = new Date().getTime() - start;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.setTimeout(function () {\n\t\t\t\telapsed = new Date().getTime() - start;\n\t\t\t\tsocket.close();\n\t\t\t}, 500);\n\t\t});\n\t\tif (elapsed > 3000 || elapsed < 500) {\n\t\t\tthrow new Error (\"setTimeout occurred after \" + elapsed + \"ms, expected 500<T<3000\")\n\t\t}`))\n\trequire.NoError(t, err)\n}\n\nfunc TestSessionBadTimeout(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar start = new Date().getTime();\n\t\tvar ellapsed = new Date().getTime() - start;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.setTimeout(function () {\n\t\t\t\tellapsed = new Date().getTime() - start;\n\t\t\t\tsocket.close();\n\t\t\t}, 0);\n\t\t});\n\t\t`))\n\trequire.ErrorContains(t, err, \"setTimeout requires a >0 timeout parameter, received 0.00 \")\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestSessionPing(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar pongReceived = false;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.on(\"open\", function(data) {\n\t\t\t\tsocket.ping();\n\t\t\t});\n\t\t\tsocket.on(\"pong\", function() {\n\t\t\t\tpongReceived = true;\n\t\t\t\tsocket.close();\n\t\t\t});\n\t\t\tsocket.setTimeout(function (){socket.close();}, 3000);\n\t\t});\n\t\tif (!pongReceived) {\n\t\t\tthrow new Error (\"sent ping but didn't get pong back\");\n\t\t}\n\t\t`))\n\trequire.NoError(t, err)\n\tsamplesBuf := metrics.GetBufferedSamples(test.samples)\n\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n\tassertMetricEmittedCount(t, metrics.WSPingName, samplesBuf, sr(\"WSBIN_URL/ws-echo\"), 1)\n}\n\nfunc TestSessionMultipleHandlers(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar pongReceived = false;\n\t\tvar otherPongReceived = false;\n\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.on(\"open\", function(data) {\n\t\t\t\tsocket.ping();\n\t\t\t});\n\t\t\tsocket.on(\"pong\", function() {\n\t\t\t\tpongReceived = true;\n\t\t\t\tif (otherPongReceived) {\n\t\t\t\t\tsocket.close();\n\t\t\t\t}\n\t\t\t});\n\t\t\tsocket.on(\"pong\", function() {\n\t\t\t\totherPongReceived = true;\n\t\t\t\tif (pongReceived) {\n\t\t\t\t\tsocket.close();\n\t\t\t\t}\n\t\t\t});\n\t\t\tsocket.setTimeout(function (){socket.close();}, 3000);\n\t\t});\n\t\tif (!pongReceived || !otherPongReceived) {\n\t\t\tthrow new Error (\"sent ping but didn't get pong back\");\n\t\t}\n\t\t`))\n\trequire.NoError(t, err)\n\tsamplesBuf := metrics.GetBufferedSamples(test.samples)\n\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n\tassertMetricEmittedCount(t, metrics.WSPingName, samplesBuf, sr(\"WSBIN_URL/ws-echo\"), 1)\n}\n\nfunc TestSessionClientClose(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar closed = false;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.on(\"open\", function() {\n\t\t\t\t\t\t\tsocket.close()\n\t\t\t})\n\t\t\tsocket.on(\"close\", function() {\n\t\t\t\t\t\t\tclosed = true;\n\t\t\t})\n\t\t});\n\t\tif (!closed) { throw new Error (\"close event not fired\"); }\n\t\t`))\n\trequire.NoError(t, err)\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestSessionClose(t *testing.T) {\n\tt.Parallel()\n\tserverCloseTests := []struct {\n\t\tname     string\n\t\tendpoint string\n\t}{\n\t\t{\"server_close_ok\", \"/ws-close\"},\n\t\t// Ensure we correctly handle invalid WS server\n\t\t// implementations that close the connection prematurely\n\t\t// without sending a close control frame first.\n\t\t{\"server_close_invalid\", \"/ws-close-invalid\"},\n\t}\n\n\tfor _, tc := range serverCloseTests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\t\tsr := tb.Replacer.Replace\n\n\t\t\ttest := newTestState(t)\n\t\t\t_, err := test.VU.Runtime().RunString(sr(fmt.Sprintf(`\n\t\t\tvar closed = false;\n\t\t\tvar res = ws.connect(\"WSBIN_URL%s\", function(socket){\n\t\t\t\tsocket.on(\"open\", function() {\n\t\t\t\t\tsocket.send(\"test\");\n\t\t\t\t})\n\t\t\t\tsocket.on(\"close\", function() {\n\t\t\t\t\tclosed = true;\n\t\t\t\t})\n\t\t\t});\n\t\t\tif (!closed) { throw new Error (\"close event not fired\"); }\n\t\t\t`, tc.endpoint)))\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestMultiMessage(t *testing.T) {\n\tt.Parallel()\n\n\tregisterMultiMessage := func(tb *httpmultibin.HTTPMultiBin) {\n\t\ttb.Mux.HandleFunc(\"/ws-echo-multi\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfor {\n\t\t\t\tmessageType, r, e := conn.NextReader()\n\t\t\t\tif e != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tvar wc io.WriteCloser\n\t\t\t\twc, err = conn.NextWriter(messageType)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif _, err = io.Copy(wc, r); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif err = wc.Close(); err != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}))\n\t}\n\n\tt.Run(\"send_receive_multiple_ws\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tregisterMultiMessage(tb)\n\t\tsr := tb.Replacer.Replace\n\n\t\ttest := newTestState(t)\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\t\tvar msg1 = \"test1\"\n\t\t\tvar msg2 = \"test2\"\n\t\t\tvar msg3 = \"test3\"\n\t\t\tvar allMsgsRecvd = false\n\t\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo-multi\", (socket) => {\n\t\t\t\tsocket.on(\"open\", () => {\n\t\t\t\t\tsocket.send(msg1)\n\t\t\t\t})\n\t\t\t\tsocket.on(\"message\", (data) => {\n\t\t\t\t\tif (data == msg1){\n\t\t\t\t\t\tsocket.send(msg2)\n\t\t\t\t\t}\n\t\t\t\t\tif (data == msg2){\n\t\t\t\t\t\tsocket.send(msg3)\n\t\t\t\t\t}\n\t\t\t\t\tif (data == msg3){\n\t\t\t\t\t\tallMsgsRecvd = true\n\t\t\t\t\t\tsocket.close()\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (!allMsgsRecvd) {\n\t\t\t\tthrow new Error (\"messages 1,2,3 in sequence, was not received from server\");\n\t\t\t}\n\t\t\t`))\n\t\trequire.NoError(t, err)\n\t\tsamplesBuf := metrics.GetBufferedSamples(test.samples)\n\t\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSBIN_URL/ws-echo-multi\"), statusProtocolSwitch, \"\")\n\t\tassertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr(\"WSBIN_URL/ws-echo-multi\"), 3)\n\t\tassertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr(\"WSBIN_URL/ws-echo-multi\"), 3)\n\t})\n\n\tt.Run(\"send_receive_multiple_wss\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tregisterMultiMessage(tb)\n\t\tsr := tb.Replacer.Replace\n\n\t\ttest := newTestState(t)\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\t\tvar msg1 = \"test1\"\n\t\t\tvar msg2 = \"test2\"\n\t\t\tvar secondMsgReceived = false\n\t\t\tvar res = ws.connect(\"WSSBIN_URL/ws-echo-multi\", (socket) => {\n\t\t\t\tsocket.on(\"open\", () => {\n\t\t\t\t\tsocket.send(msg1)\n\t\t\t\t})\n\t\t\t\tsocket.on(\"message\", (data) => {\n\t\t\t\t\tif (data == msg1){\n\t\t\t\t\t\tsocket.send(msg2)\n\t\t\t\t\t}\n\t\t\t\t\tif (data == msg2){\n\t\t\t\t\t\tsecondMsgReceived = true\n\t\t\t\t\t\tsocket.close()\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (!secondMsgReceived) {\n\t\t\t\tthrow new Error (\"second test message was not received from server!\");\n\t\t\t}\n\t\t\t`))\n\t\trequire.NoError(t, err)\n\t\tsamplesBuf := metrics.GetBufferedSamples(test.samples)\n\t\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSSBIN_URL/ws-echo-multi\"), statusProtocolSwitch, \"\")\n\t\tassertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr(\"WSSBIN_URL/ws-echo-multi\"), 2)\n\t\tassertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr(\"WSSBIN_URL/ws-echo-multi\"), 2)\n\t})\n\n\tt.Run(\"send_receive_text_binary\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tregisterMultiMessage(tb)\n\t\tsr := tb.Replacer.Replace\n\n\t\ttest := newTestState(t)\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\t\tvar msg1 = \"test1\"\n\t\t\tvar msg2 = new Uint8Array([116, 101, 115, 116, 50]); // 'test2'\n\t\t\tvar secondMsgReceived = false\n\t\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo-multi\", (socket) => {\n\t\t\t\tsocket.on(\"open\", () => {\n\t\t\t\t\tsocket.send(msg1)\n\t\t\t\t})\n\t\t\t\tsocket.on(\"message\", (data) => {\n\t\t\t\t\tif (data == msg1){\n\t\t\t\t\t\tsocket.sendBinary(msg2.buffer)\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tsocket.on(\"binaryMessage\", (data) => {\n\t\t\t\t\tlet data2 = new Uint8Array(data)\n\t\t\t\t\tif(JSON.stringify(msg2) == JSON.stringify(data2)){\n\t\t\t\t\t\tsecondMsgReceived = true\n\t\t\t\t\t}\n\t\t\t\t\tsocket.close()\n\t\t\t\t})\n\t\t\t});\n\n\t\t\tif (!secondMsgReceived) {\n\t\t\t\tthrow new Error (\"second test message was not received from server!\");\n\t\t\t}\n\t\t\t`))\n\t\trequire.NoError(t, err)\n\t\tsamplesBuf := metrics.GetBufferedSamples(test.samples)\n\t\tassertSessionMetricsEmitted(t, samplesBuf, \"\", sr(\"WSBIN_URL/ws-echo-multi\"), statusProtocolSwitch, \"\")\n\t\tassertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr(\"WSBIN_URL/ws-echo-multi\"), 2)\n\t\tassertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr(\"WSBIN_URL/ws-echo-multi\"), 2)\n\t})\n}\n\nfunc TestSocketSendBinary(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttest := newTestState(t)\n\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar gotMsg = false;\n\t\tvar res = ws.connect('WSBIN_URL/ws-echo', function(socket){\n\t\t\tvar data = new Uint8Array([104, 101, 108, 108, 111]); // 'hello'\n\n\t\t\tsocket.on('open', function() {\n\t\t\t\tsocket.sendBinary(data.buffer);\n\t\t\t})\n\t\t\tsocket.on('binaryMessage', function(msg) {\n\t\t\t\tgotMsg = true;\n\t\t\t\tlet decText = String.fromCharCode.apply(null, new Uint8Array(msg));\n\t\t\t\tdecText = decodeURIComponent(escape(decText));\n\t\t\t\tif (decText !== 'hello') {\n\t\t\t\t\tthrow new Error('received unexpected binary message: ' + decText);\n\t\t\t\t}\n\t\t\t\tsocket.close()\n\t\t\t});\n\t\t});\n\t\tif (!gotMsg) {\n\t\t\tthrow new Error(\"the 'binaryMessage' handler wasn't called\")\n\t\t}\n\t\t`))\n\t\trequire.NoError(t, err)\n\t})\n\n\terrTestCases := []struct {\n\t\tin, expErrType string\n\t}{\n\t\t{\"\", \"\"},\n\t\t{\"undefined\", \"undefined\"},\n\t\t{\"null\", \"null\"},\n\t\t{\"true\", \"Boolean\"},\n\t\t{\"1\", \"Number\"},\n\t\t{\"3.14\", \"Number\"},\n\t\t{\"'str'\", \"String\"},\n\t\t{\"[1, 2, 3]\", \"Array\"},\n\t\t{\"new Uint8Array([1, 2, 3])\", \"Uint8Array\"},\n\t\t{\"Symbol('a')\", \"Symbol\"},\n\t\t{\"function() {}\", \"Function\"},\n\t}\n\n\tfor _, tc := range errTestCases { //nolint:paralleltest\n\t\tt.Run(fmt.Sprintf(\"err_%s\", tc.expErrType), func(t *testing.T) {\n\t\t\t_, err := test.VU.Runtime().RunString(fmt.Sprintf(sr(`\n\t\t\tvar res = ws.connect('WSBIN_URL/ws-echo', function(socket){\n\t\t\t\tsocket.on('open', function() {\n\t\t\t\t\tsocket.sendBinary(%s);\n\t\t\t\t})\n\t\t\t});\n\t\t`), tc.in))\n\t\t\trequire.Error(t, err)\n\t\t\tif tc.in == \"\" {\n\t\t\t\tassert.Contains(t, err.Error(), \"missing argument, expected ArrayBuffer\")\n\t\t\t} else {\n\t\t\t\tassert.Contains(t, err.Error(), fmt.Sprintf(\"expected ArrayBuffer as argument, received: %s\", tc.expErrType))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestErrors(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"invalid_url\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttest := newTestState(t)\n\t\t_, err := test.VU.Runtime().RunString(`\n\t\tvar res = ws.connect(\"INVALID\", function(socket){\n\t\t\tsocket.on(\"open\", function() {\n\t\t\t\tsocket.close();\n\t\t\t});\n\t\t});\n\t\t`)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"invalid_url_message_panic\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttest := newTestState(t)\n\t\t// Attempting to send a message to a non-existent socket shouldn't panic\n\t\t_, err := test.VU.Runtime().RunString(`\n\t\tvar res = ws.connect(\"INVALID\", function(socket){\n\t\t\tsocket.send(\"new message\");\n\t\t});\n\t\t`)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"error_in_setup\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tsr := tb.Replacer.Replace\n\n\t\ttest := newTestState(t)\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo-invalid\", function(socket){\n\t\t\tthrow new Error(\"error in setup\");\n\t\t});\n\t\t`))\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"send_after_close\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tsr := tb.Replacer.Replace\n\n\t\ttest := newTestState(t)\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar hasError = false;\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo-invalid\", function(socket){\n\t\t\tsocket.on(\"open\", function() {\n\t\t\t\tsocket.close();\n\t\t\t\tsocket.send(\"test\");\n\t\t\t});\n\n\t\t\tsocket.on(\"error\", function(errorEvent) {\n\t\t\t\thasError = true;\n\t\t\t});\n\t\t});\n\t\tif (!hasError) {\n\t\t\tthrow new Error (\"no error emitted for send after close\");\n\t\t}\n\t\t`))\n\t\trequire.NoError(t, err)\n\t\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSBIN_URL/ws-echo-invalid\"), statusProtocolSwitch, \"\")\n\t})\n}\n\nfunc TestConnectWrongStatusCode(t *testing.T) {\n\tt.Parallel()\n\ttest := newTestState(t)\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\ttest.VU.StateField.Options.Throw = null.BoolFrom(false)\n\t_, err := test.VU.Runtime().RunString(sr(`\n\tvar res = ws.connect(\"WSBIN_URL/status/404\", function(socket){});\n\tif (res.status != 404) {\n\t\tthrow new Error (\"no status code set for invalid response\");\n\t}\n\t`))\n\tassert.NoError(t, err)\n}\n\nfunc TestSystemTags(t *testing.T) {\n\tt.Parallel()\n\ttestedSystemTags := []string{\"status\", \"subproto\", \"url\", \"ip\"}\n\tfor _, expectedTagStr := range testedSystemTags {\n\t\tt.Run(\"only \"+expectedTagStr, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\ttest := newTestState(t)\n\t\t\texpectedTag, err := metrics.SystemTagString(expectedTagStr)\n\t\t\trequire.NoError(t, err)\n\t\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\t\ttest.VU.StateField.Options.SystemTags = metrics.ToSystemTagSet([]string{expectedTagStr})\n\t\t\t_, err = test.VU.Runtime().RunString(tb.Replacer.Replace(`\n\t\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo\", function(socket){\n\t\t\t\tsocket.on(\"open\", function() {\n\t\t\t\t\tsocket.send(\"test\")\n\t\t\t\t})\n\t\t\t\tsocket.on(\"message\", function (data){\n\t\t\t\t\tif (!data==\"test\") {\n\t\t\t\t\t\tthrow new Error (\"echo'd data doesn't match our message!\");\n\t\t\t\t\t}\n\t\t\t\t\tsocket.close()\n\t\t\t\t});\n\t\t\t});\n\t\t\t`))\n\t\t\trequire.NoError(t, err)\n\t\t\tcontainers := metrics.GetBufferedSamples(test.samples)\n\t\t\trequire.NotEmpty(t, containers)\n\t\t\tfor _, sampleContainer := range containers {\n\t\t\t\trequire.NotEmpty(t, sampleContainer.GetSamples())\n\t\t\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\t\t\tvar dataToCheck map[string]string\n\t\t\t\t\tif metrics.NonIndexableSystemTags.Has(expectedTag) {\n\t\t\t\t\t\tdataToCheck = sample.Metadata\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdataToCheck = sample.Tags.Map()\n\t\t\t\t\t}\n\n\t\t\t\t\trequire.NotEmpty(t, dataToCheck)\n\t\t\t\t\tfor emittedTag := range dataToCheck {\n\t\t\t\t\t\tassert.Equal(t, expectedTagStr, emittedTag)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestTLSConfig(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"insecure skip verify\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tsr := tb.Replacer.Replace\n\n\t\ttest := newTestState(t)\n\t\ttest.VU.StateField.TLSConfig = &tls.Config{\n\t\t\tInsecureSkipVerify: true,\n\t\t}\n\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar res = ws.connect(\"WSSBIN_URL/ws-echo\", function(socket){\n\t\t\tsocket.close()\n\t\t});\n\t\tif (res.status != 101) { throw new Error(\"TLS connection failed with status: \" + res.status); }\n\t\t`))\n\t\trequire.NoError(t, err)\n\t\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n\t})\n\n\tt.Run(\"custom certificates\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\t\tsr := tb.Replacer.Replace\n\n\t\ttest := newTestState(t)\n\t\ttest.VU.StateField.TLSConfig = tb.TLSClientConfig\n\n\t\t_, err := test.VU.Runtime().RunString(sr(`\n\t\t\tvar res = ws.connect(\"WSSBIN_URL/ws-echo\", function(socket){\n\t\t\t\tsocket.close()\n\t\t\t});\n\t\t\tif (res.status != 101) {\n\t\t\t\tthrow new Error(\"TLS connection failed with status: \" + res.status);\n\t\t\t}\n\t\t`))\n\t\trequire.NoError(t, err)\n\t\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSSBIN_URL/ws-echo\"), statusProtocolSwitch, \"\")\n\t})\n}\n\nfunc TestReadPump(t *testing.T) {\n\tt.Parallel()\n\n\tcloseCodes := []int{websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseInternalServerErr}\n\n\t// Ensure readPump returns the response close code sent by the server\n\tfor _, code := range closeCodes {\n\t\tt.Run(strconv.Itoa(code), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tcloseCode := code\n\t\t\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, r, w.Header())\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tcloseMsg := websocket.FormatCloseMessage(closeCode, \"\")\n\t\t\t\t_ = conn.WriteControl(websocket.CloseMessage, closeMsg, time.Now().Add(time.Second))\n\t\t\t}))\n\t\t\tnumAsserts := 0\n\n\t\t\tt.Cleanup(srv.Close)\n\t\t\tsrvURL := \"ws://\" + srv.Listener.Addr().String()\n\t\t\tconn, resp, err := websocket.DefaultDialer.Dial(srvURL, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tdefer func() {\n\t\t\t\t_ = resp.Body.Close()\n\t\t\t\t_ = conn.Close()\n\t\t\t}()\n\n\t\t\tmsgChan := make(chan *message)\n\t\t\terrChan := make(chan error)\n\t\t\tcloseChan := make(chan int)\n\t\t\ts := &Socket{conn: conn}\n\t\t\tgo s.readPump(msgChan, errChan, closeChan)\n\n\t\treadChans:\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase responseCode := <-closeChan:\n\t\t\t\t\tassert.Equal(t, code, responseCode)\n\t\t\t\t\tnumAsserts++\n\t\t\t\t\tbreak readChans\n\t\t\t\tcase <-errChan:\n\t\t\t\t\tcontinue\n\t\t\t\tcase <-time.After(time.Second):\n\t\t\t\t\tt.Errorf(\"Read timed out\")\n\t\t\t\t\tbreak readChans\n\t\t\t\t}\n\t\t\t}\n\t\t\tassert.Equal(t, numAsserts, 1)\n\t\t})\n\t}\n\n\t// Ensure all close code asserts passed\n}\n\nfunc TestUserAgent(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\ttb.Mux.HandleFunc(\"/ws-echo-useragent\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t// Echo back User-Agent header if it exists\n\t\tresponseHeaders := w.Header().Clone()\n\t\tif ua := req.Header.Get(\"User-Agent\"); ua != \"\" {\n\t\t\tresponseHeaders.Add(\"Echo-User-Agent\", req.Header.Get(\"User-Agent\"))\n\t\t}\n\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, responseHeaders)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"/ws-echo-useragent cannot upgrade request: %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\terr = conn.Close()\n\t\tif err != nil {\n\t\t\tt.Logf(\"error while closing connection in /ws-echo-useragent: %v\", err)\n\t\t\treturn\n\t\t}\n\t}))\n\n\ttest := newTestState(t)\n\n\t// websocket handler should echo back User-Agent as Echo-User-Agent for this test to work\n\t_, err := test.VU.Runtime().RunString(sr(`\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo-useragent\", function(socket){\n\t\t\tsocket.close()\n\t\t})\n\t\tvar userAgent = res.headers[\"Echo-User-Agent\"];\n\t\tif (userAgent == undefined) {\n\t\t\tthrow new Error(\"user agent is not echoed back by test server\");\n\t\t}\n\t\tif (userAgent != \"TestUserAgent\") {\n\t\t\tthrow new Error(\"incorrect user agent: \" + userAgent);\n\t\t}\n\t\t`))\n\trequire.NoError(t, err)\n\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(test.samples), \"\", sr(\"WSBIN_URL/ws-echo-useragent\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestCompression(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"session\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tconst text string = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sed pharetra sapien. Nunc laoreet molestie ante ac gravida. Etiam interdum dui viverra posuere egestas. Pellentesque at dolor tristique, mattis turpis eget, commodo purus. Nunc orci aliquam.`\n\n\t\tts := newTestState(t)\n\t\tsr := ts.tb.Replacer.Replace\n\t\tts.tb.Mux.HandleFunc(\"/ws-compression\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\tupgrader := websocket.Upgrader{\n\t\t\t\tEnableCompression: true,\n\t\t\t\tReadBufferSize:    1024,\n\t\t\t\tWriteBufferSize:   1024,\n\t\t\t}\n\n\t\t\tconn, e := upgrader.Upgrade(w, req, w.Header())\n\t\t\tif e != nil {\n\t\t\t\tt.Fatalf(\"/ws-compression cannot upgrade request: %v\", e)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// send a message and exit\n\t\t\tif e = conn.WriteMessage(websocket.TextMessage, []byte(text)); e != nil {\n\t\t\t\tt.Logf(\"error while sending message in /ws-compression: %v\", e)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\te = conn.Close()\n\t\t\tif e != nil {\n\t\t\t\tt.Logf(\"error while closing connection in /ws-compression: %v\", e)\n\t\t\t\treturn\n\t\t\t}\n\t\t}))\n\n\t\t_, err := ts.VU.Runtime().RunString(sr(`\n\t\t// if client supports compression, it has to send the header\n\t\t// 'Sec-Websocket-Extensions:permessage-deflate; server_no_context_takeover; client_no_context_takeover' to server.\n\t\t// if compression is negotiated successfully, server will reply with header\n\t\t// 'Sec-Websocket-Extensions:permessage-deflate; server_no_context_takeover; client_no_context_takeover'\n\n\t\tvar params = {\n\t\t\t\"compression\": \"deflate\"\n\t\t}\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-compression\", params, function(socket){\n\t\t\tsocket.on('message', (data) => {\n\t\t\t\tif(data != \"` + text + `\"){\n\t\t\t\t\tthrow new Error(\"wrong message received from server: \", data)\n\t\t\t\t}\n\t\t\t\tsocket.close()\n\t\t\t})\n\t\t});\n\n\t\tvar wsExtensions = res.headers[\"Sec-Websocket-Extensions\"].split(';').map(e => e.trim())\n\t\tif (!(wsExtensions.includes(\"permessage-deflate\") && wsExtensions.includes(\"server_no_context_takeover\") && wsExtensions.includes(\"client_no_context_takeover\"))){\n\t\t\tthrow new Error(\"websocket compression negotiation failed\");\n\t\t}\n\t\t`))\n\n\t\trequire.NoError(t, err)\n\t\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(ts.samples), \"\", sr(\"WSBIN_URL/ws-compression\"), statusProtocolSwitch, \"\")\n\t})\n\n\tt.Run(\"params\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestCases := []struct {\n\t\t\tcompression   string\n\t\t\texpectedError string\n\t\t}{\n\t\t\t{compression: \"\"},\n\t\t\t{compression: \"  \"},\n\t\t\t{compression: \"deflate\"},\n\t\t\t{compression: \"deflate \"},\n\t\t\t{\n\t\t\t\tcompression:   \"gzip\",\n\t\t\t\texpectedError: `unsupported compression algorithm 'gzip', supported algorithm is 'deflate'`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tcompression:   \"deflate, gzip\",\n\t\t\t\texpectedError: `unsupported compression algorithm 'deflate, gzip', supported algorithm is 'deflate'`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tcompression:   \"deflate, deflate\",\n\t\t\t\texpectedError: `unsupported compression algorithm 'deflate, deflate', supported algorithm is 'deflate'`,\n\t\t\t},\n\t\t\t{\n\t\t\t\tcompression:   \"deflate, \",\n\t\t\t\texpectedError: `unsupported compression algorithm 'deflate,', supported algorithm is 'deflate'`,\n\t\t\t},\n\t\t}\n\n\t\tfor _, testCase := range testCases {\n\t\t\tt.Run(testCase.compression, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tts := newTestState(t)\n\t\t\t\tsr := ts.tb.Replacer.Replace\n\t\t\t\tts.tb.Mux.HandleFunc(\"/ws-compression-param\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\t\t\tupgrader := websocket.Upgrader{\n\t\t\t\t\t\tEnableCompression: true,\n\t\t\t\t\t\tReadBufferSize:    1024,\n\t\t\t\t\t\tWriteBufferSize:   1024,\n\t\t\t\t\t}\n\n\t\t\t\t\tconn, e := upgrader.Upgrade(w, req, w.Header())\n\t\t\t\t\tif e != nil {\n\t\t\t\t\t\tt.Fatalf(\"/ws-compression-param cannot upgrade request: %v\", e)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\te = conn.Close()\n\t\t\t\t\tif e != nil {\n\t\t\t\t\t\tt.Logf(\"error while closing connection in /ws-compression-param: %v\", e)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}))\n\n\t\t\t\t_, err := ts.VU.Runtime().RunString(sr(`\n\t\t\t\t\tvar res = ws.connect(\"WSBIN_URL/ws-compression-param\", {\"compression\":\"` + testCase.compression + `\"}, function(socket){\n\t\t\t\t\t\tsocket.close()\n\t\t\t\t\t});\n\t\t\t\t`))\n\n\t\t\t\tif testCase.expectedError == \"\" {\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t} else {\n\t\t\t\t\trequire.Error(t, err)\n\t\t\t\t\trequire.Contains(t, err.Error(), testCase.expectedError)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc clearSamples(tb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer) {\n\tctxDone := tb.Context.Done()\n\tfor {\n\t\tselect {\n\t\tcase <-samples:\n\t\tcase <-ctxDone:\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc BenchmarkCompression(b *testing.B) {\n\tconst textMessage = 1\n\tts := newTestState(b)\n\tsr := ts.tb.Replacer.Replace\n\tgo clearSamples(ts.tb, ts.samples)\n\n\ttestCodes := []string{\n\t\tsr(`\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-compression\", {\"compression\":\"deflate\"}, (socket) => {\n\t\t\tsocket.on('message', (data) => {\n\t\t\t\tsocket.close()\n\t\t\t})\n\t\t});\n\t\t`),\n\t\tsr(`\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-compression\", {}, (socket) => {\n\t\t\tsocket.on('message', (data) => {\n\t\t\t\tsocket.close()\n\t\t\t})\n\t\t});\n\t\t`),\n\t}\n\n\tts.tb.Mux.HandleFunc(\"/ws-compression\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tkbData := bytes.Repeat([]byte(\"0123456789\"), 100)\n\n\t\t// upgrade connection, send the first (long) message, disconnect\n\t\tupgrader := websocket.Upgrader{\n\t\t\tEnableCompression: true,\n\t\t\tReadBufferSize:    1024,\n\t\t\tWriteBufferSize:   1024,\n\t\t}\n\n\t\tconn, e := upgrader.Upgrade(w, req, w.Header())\n\n\t\tif e != nil {\n\t\t\tb.Fatalf(\"/ws-compression cannot upgrade request: %v\", e)\n\t\t\treturn\n\t\t}\n\n\t\tif e = conn.WriteMessage(textMessage, kbData); e != nil {\n\t\t\tb.Fatalf(\"/ws-compression cannot write message: %v\", e)\n\t\t\treturn\n\t\t}\n\n\t\te = conn.Close()\n\t\tif e != nil {\n\t\t\tb.Logf(\"error while closing connection in /ws-compression: %v\", e)\n\t\t\treturn\n\t\t}\n\t}))\n\n\tb.ResetTimer()\n\tb.Run(\"compression-enabled\", func(b *testing.B) {\n\t\tfor i := 0; i < b.N; i++ {\n\t\t\tif _, err := ts.VU.Runtime().RunString(testCodes[0]); err != nil {\n\t\t\t\tb.Error(err)\n\t\t\t}\n\t\t}\n\t})\n\tb.Run(\"compression-disabled\", func(b *testing.B) {\n\t\tfor i := 0; i < b.N; i++ {\n\t\t\tif _, err := ts.VU.Runtime().RunString(testCodes[1]); err != nil {\n\t\t\t\tb.Error(err)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc TestCookieJar(t *testing.T) {\n\tt.Parallel()\n\tts := newTestState(t)\n\tsr := ts.tb.Replacer.Replace\n\n\tts.tb.Mux.HandleFunc(\"/ws-echo-someheader\", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tresponseHeaders := w.Header().Clone()\n\t\tif sh, err := req.Cookie(\"someheader\"); err == nil {\n\t\t\tresponseHeaders.Add(\"Echo-Someheader\", sh.Value)\n\t\t}\n\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, responseHeaders)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"/ws-echo-someheader cannot upgrade request: %v\", err)\n\t\t}\n\n\t\terr = conn.Close()\n\t\tif err != nil {\n\t\t\tt.Logf(\"error while closing connection in /ws-echo-someheader: %v\", err)\n\t\t}\n\t}))\n\n\terr := ts.VU.Runtime().Set(\"http\", httpModule.New().NewModuleInstance(ts.VU).Exports().Default)\n\trequire.NoError(t, err)\n\tts.VU.State().CookieJar, _ = cookiejar.New(nil)\n\n\t_, err = ts.VU.Runtime().RunString(sr(`\n\t\tvar res = ws.connect(\"WSBIN_URL/ws-echo-someheader\", function(socket){\n\t\t\tsocket.close()\n\t\t})\n\t\tvar someheader = res.headers[\"Echo-Someheader\"];\n\t\tif (someheader !== undefined) {\n\t\t\tthrow new Error(\"someheader is echoed back by test server even though it doesn't exist\");\n\t\t}\n\n\t\thttp.cookieJar().set(\"HTTPBIN_URL/ws-echo-someheader\", \"someheader\", \"defaultjar\")\n\t\tres = ws.connect(\"WSBIN_URL/ws-echo-someheader\", function(socket){\n\t\t\tsocket.close()\n\t\t})\n\t\tsomeheader = res.headers[\"Echo-Someheader\"];\n\t\tif (someheader != \"defaultjar\") {\n\t\t\tthrow new Error(\"someheader has wrong value \"+ someheader + \" instead of defaultjar\");\n\t\t}\n\n\t\tvar jar = new http.CookieJar();\n\t\tjar.set(\"HTTPBIN_URL/ws-echo-someheader\", \"someheader\", \"customjar\")\n\t\tres = ws.connect(\"WSBIN_URL/ws-echo-someheader\", {jar: jar}, function(socket){\n\t\t\tsocket.close()\n\t\t})\n\t\tsomeheader = res.headers[\"Echo-Someheader\"];\n\t\tif (someheader != \"customjar\") {\n\t\t\tthrow new Error(\"someheader has wrong value \"+ someheader + \" instead of customjar\");\n\t\t}\n\t\t`))\n\trequire.NoError(t, err)\n\n\tassertSessionMetricsEmitted(t, metrics.GetBufferedSamples(ts.samples), \"\", sr(\"WSBIN_URL/ws-echo-someheader\"), statusProtocolSwitch, \"\")\n}\n\nfunc TestWSConnectEnableThrowErrorOption(t *testing.T) {\n\tt.Parallel()\n\tlogHook := testutils.NewLogHook(logrus.WarnLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\ttestLog.SetOutput(io.Discard)\n\tts := newTestState(t)\n\tts.VU.StateField.Logger = testLog\n\t_, err := ts.VU.Runtime().RunString(`\n\t\tvar res = ws.connect(\"INVALID\", function(socket){\n\t\t\tsocket.on(\"open\", function() {\n\t\t\t\tsocket.close();\n\t\t\t});\n\t\t});\n\t\t`)\n\tentries := logHook.Drain()\n\trequire.Len(t, entries, 0)\n\tassert.Error(t, err)\n}\n\nfunc TestWSConnectDisableThrowErrorOption(t *testing.T) {\n\tt.Parallel()\n\tlogHook := testutils.NewLogHook(logrus.WarnLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\ttestLog.SetOutput(io.Discard)\n\n\tts := newTestState(t)\n\tts.VU.StateField.Logger = testLog\n\tts.VU.StateField.Options.Throw = null.BoolFrom(false)\n\t_, err := ts.VU.Runtime().RunString(`\n\t\tvar res = ws.connect(\"INVALID\", function(socket){\n\t\t\tsocket.on(\"open\", function() {\n\t\t\t\tsocket.close();\n\t\t\t});\n\t\t});\n\t\tif (res == null && res.error == null) {\n\t\t\tthrow new Error(\"res.error is expected to be not null\");\n\t\t}\n\n\t\t`)\n\trequire.NoError(t, err)\n\tentries := logHook.Drain()\n\tassert.Empty(t, entries)\n}\n"
  },
  {
    "path": "internal/js/modules_vu.go",
    "content": "package js\n\nimport (\n\t\"context\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/js/eventloop\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/lib\"\n)\n\ntype events struct {\n\tglobal, local *event.System\n}\n\ntype moduleVUImpl struct {\n\tctx       context.Context\n\tinitEnv   *common.InitEnvironment\n\tstate     *lib.State\n\truntime   *sobek.Runtime\n\teventLoop *eventloop.EventLoop\n\tevents    events\n}\n\nfunc (m *moduleVUImpl) Context() context.Context {\n\treturn m.ctx\n}\n\nfunc (m *moduleVUImpl) Events() common.Events {\n\treturn common.Events{Global: m.events.global, Local: m.events.local}\n}\n\nfunc (m *moduleVUImpl) InitEnv() *common.InitEnvironment {\n\treturn m.initEnv\n}\n\nfunc (m *moduleVUImpl) State() *lib.State {\n\treturn m.state\n}\n\nfunc (m *moduleVUImpl) Runtime() *sobek.Runtime {\n\treturn m.runtime\n}\n\nfunc (m *moduleVUImpl) RegisterCallback() func(func() error) {\n\treturn m.eventLoop.RegisterCallback()\n}\n"
  },
  {
    "path": "internal/js/path_resolution_test.go",
    "content": "package js\n\nimport (\n\t\"context\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// This whole file is about tests around https://github.com/grafana/k6/issues/2674\n\nfunc TestPathResolution(t *testing.T) {\n\tt.Parallel()\n\ttestCases := map[string]struct {\n\t\tfsMap         map[string]any\n\t\texpectedLogs  []string\n\t\texpectedError string\n\t}{\n\t\t\"open simple\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.txt\": \"data file\",\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\texport let data = open(\"../../../B/data.txt\");\n\t\t\t\t\tif (data != \"data file\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"open intermediate\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.txt\": \"data file\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\tmodule.exports = open(\"../../B/data.txt\");\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"./../../../C/B/script.js\")\n\t\t\t\t\tif (data != \"data file\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"open complex\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.txt\": \"data file\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\t// Here the path is relative to this module but to the one calling\n\t\t\t\t\tmodule.exports = () =>  open(\"./../data.txt\");\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\tmodule.exports = require(\"./../../C/B/script.js\")();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"./../../../B/B/script.js\");\n\t\t\t\t\tif (data != \"data file\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedLogs: []string{\n\t\t\t\t`open() was used and is currently relative to 'file:///A/B/B/', but in the future it will be aligned with how`,\n\t\t\t},\n\t\t},\n\t\t\"open space in path\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B D/data.txt\": \"data file\",\n\t\t\t\t\"/A/C D/B/script.js\": `\n\t\t\t\t\t// Here the path is relative to this module but to the one calling\n\t\t\t\t\tmodule.exports = () =>  open(\"./../data.txt\");\n\t\t\t\t`,\n\t\t\t\t\"/A/B D/B/script.js\": `\n\t\t\t\t\tmodule.exports = require(\"./../../C D/B/script.js\")();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"./../../../B D/B/script.js\");\n\t\t\t\t\tif (data != \"data file\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedLogs: []string{\n\t\t\t\t`open() was used and is currently relative to 'file:///A/B%20D/B/', but in the future it will be aligned with how `,\n\t\t\t},\n\t\t},\n\t\t\"require simple\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"../../../B/data.js\");\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"require intermediate\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\tmodule.exports = require(\"../../B/data.js\");\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"./../../../C/B/script.js\")\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"require complex\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\tmodule.exports = () =>  require(\"./../../B/data.js\");\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\tmodule.exports = require(\"./../../C/B/script.js\")();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"./../../../B/B/script.js\");\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"require complex wrong\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\tmodule.exports = () =>  require(\"./../data.js\");\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\tmodule.exports = require(\"./../../C/B/script.js\")();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"./../../../B/B/script.js\");\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedError: `The moduleSpecifier \"./../data.js\" couldn't be found on local disk.`,\n\t\t},\n\t\t\"ESM and require\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default function () {\n\t\t\t\t\t\t// Here the path is relative to this module not the calling one\n\t\t\t\t\t\treturn require(\"./../../B/data.js\");\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\timport s from \"./../../C/B/script.js\"\n\t\t\t\t\texport default require(\"./../../C/B/script.js\").default();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\timport data from \"./../../../B/B/script.js\"\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"ESM and require wrong\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default function () {\n\t\t\t\t\t\treturn require(\"./../data.js\");\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\timport s from \"./../../C/B/script.js\"\n\t\t\t\t\texport default require(\"./../../C/B/script.js\").default();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\timport data from \"./../../../B/B/script.js\"\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedError: `The moduleSpecifier \"./../data.js\" couldn't be found on local disk.`,\n\t\t},\n\t\t\"full ESM\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"export default 'export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default function () {\n\t\t\t\t\t\t// Here the path is relative to this module not the calling one\n\t\t\t\t\t\treturn require(\"./../../B/data.js\").default;\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\timport s from \"./../../C/B/script.js\"\n\t\t\t\t\tlet l = s();\n\t\t\t\t\texport default l;\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\timport data from \"./../../../B/B/script.js\"\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"full ESM wrong\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"export default 'export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default function () {\n\t\t\t\t\t\treturn require(\"./../data.js\").default;\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\timport s from \"./../../C/B/script.js\"\n\t\t\t\t\tlet l = s();\n\t\t\t\t\texport default l;\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\timport data from \"./../../../B/B/script.js\"\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedError: `The moduleSpecifier \"./../data.js\" couldn't be found on local disk.`,\n\t\t},\n\t}\n\tfor name, testCase := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\terr := writeToFs(fs, testCase.fsMap)\n\t\t\tfs = fsext.NewCacheOnReadFs(fs, fsext.NewMemMapFs(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\t\t\tb, err := getSimpleBundle(t, \"/main.js\", `export { default } from \"/A/A/A/A/script.js\"`, fs, logger)\n\n\t\t\tif testCase.expectedError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, testCase.expectedError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = b.Instantiate(context.Background(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\tlogs := hook.Drain()\n\n\t\t\tif len(testCase.expectedLogs) == 0 {\n\t\t\t\trequire.Empty(t, logs)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, len(testCase.expectedLogs), len(logs))\n\n\t\t\tfor i, log := range logs {\n\t\t\t\trequire.Contains(t, log.Message, testCase.expectedLogs[i], \"log line %d\", i)\n\t\t\t}\n\t\t})\n\t}\n\n\tpwd, err := url.Parse(\"file:///A/A/A/A/\")\n\trequire.NoError(t, err)\n\n\tfor name, testCase := range testCases {\n\t\tt.Run(\"STDIN-\"+name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\terr := writeToFs(fs, testCase.fsMap)\n\t\t\tfs = fsext.NewCacheOnReadFs(fs, fsext.NewMemMapFs(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\n\t\t\tb, err := getSimpleBundleStdin(t, pwd, testCase.fsMap[\"/A/A/A/A/script.js\"].(string), fs, logger)\n\t\t\tif testCase.expectedError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, testCase.expectedError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = b.Instantiate(context.Background(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\tlogs := hook.Drain()\n\n\t\t\tif len(testCase.expectedLogs) == 0 {\n\t\t\t\trequire.Empty(t, logs)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, len(testCase.expectedLogs), len(logs))\n\n\t\t\tfor i, log := range logs {\n\t\t\t\trequire.Contains(t, log.Message, testCase.expectedLogs[i], \"log line %d\", i)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// writeToFs is a small helper to write a map of paths to contents to the filesystem provided.\n// the content can be either string or []byte anything else panics\nfunc writeToFs(fs fsext.Fs, in map[string]any) error {\n\tfor path, contentAny := range in {\n\t\tvar content []byte\n\t\tswitch contentAny := contentAny.(type) {\n\t\tcase []byte:\n\t\t\tcontent = contentAny\n\t\tcase string:\n\t\t\tcontent = []byte(contentAny)\n\t\tdefault:\n\t\t\tpanic(\"content for \" + path + \" wasn't []byte or string\")\n\t\t}\n\t\tif err := fsext.WriteFile(fs, path, content, 0o644); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc TestImportMetaResolve(t *testing.T) {\n\tt.Parallel()\n\ttestCases := map[string]struct {\n\t\tfsMap         map[string]any\n\t\texpectedLogs  []string\n\t\texpectedError string\n\t}{\n\t\t\"simple\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(import.meta.resolve(\"../../../B/data.js\"));\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"intermediate\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\tmodule.exports = require(import.meta.resolve(\"../../B/data.js\"));\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(import.meta.resolve(\"./../../../C/B/script.js\"))\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedError: `import not supported in script`,\n\t\t},\n\t\t\"intermediate fixed\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"export default 'export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default require(\"../../B/data.js\").default;\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(\"./../../../C/B/script.js\").default;\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"complex\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default () =>  require(import.meta.resolve(\"./../../B/data.js\"));\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\texport default require(import.meta.resolve(\"./../../C/B/script.js\")).default();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(import.meta.resolve(\"./../../../B/B/script.js\")).default;\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"complex wrong\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default () =>  require(import.meta.resolve(\"./../data.js\"));\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\texport default require(import.meta.resolve(\"./../../C/B/script.js\")).default();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(import.meta.resolve(\"./../../../B/B/script.js\")).default;\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedError: `A/C/data.js\" couldn't be found`,\n\t\t},\n\t\t\"complex wrong fixed\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default (specifier) =>  require(specifier);\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\texport default require(import.meta.resolve(\"./../../C/B/script.js\")).default(\n\t\t\t\t\t\timport.meta.resolve(\"./../data.js\")\n\t\t\t\t\t);\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\tlet data = require(import.meta.resolve(\"./../../../B/B/script.js\")).default;\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"ESM and require\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default function () {\n\t\t\t\t\t\t// Here the path is relative to this module not the calling one\n\t\t\t\t\t\treturn require(import.meta.resolve(\"./../../B/data.js\"));\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\timport s from \"./../../C/B/script.js\"\n\t\t\t\t\texport default require(import.meta.resolve(\"./../../C/B/script.js\")).default();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\timport data from \"./../../../B/B/script.js\"\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t\t\"ESM and require wrong\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"module.exports='export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default function () {\n\t\t\t\t\t\treturn require(import.meta.resolve(\"./../data.js\"));\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\timport s from \"./../../C/B/script.js\"\n\t\t\t\t\texport default require(import.meta.resolve(\"./../../C/B/script.js\")).default();\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\timport data from \"./../../../B/B/script.js\"\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t\texpectedError: `The moduleSpecifier \"file:///A/C/data.js\" couldn't be found on local disk.`,\n\t\t},\n\t\t\"full ESM\": {\n\t\t\tfsMap: map[string]any{\n\t\t\t\t\"/A/B/data.js\": \"export default 'export content'\",\n\t\t\t\t\"/A/C/B/script.js\": `\n\t\t\t\t\texport default function (specifier) {\n\t\t\t\t\t\treturn require(specifier).default;\n\t\t\t\t\t}\n\t\t\t\t`,\n\t\t\t\t\"/A/B/B/script.js\": `\n\t\t\t\t\timport s from \"./../../C/B/script.js\"\n\t\t\t\t\tlet l = s(import.meta.resolve(\"../data.js\")); // this will resolve with this module as root\n\t\t\t\t\texport default l;\n\t\t\t\t`,\n\t\t\t\t\"/A/A/A/A/script.js\": `\n\t\t\t\t\timport data from \"./../../../B/B/script.js\"\n\t\t\t\t\tif (data != \"export content\") {\n\t\t\t\t\t\tthrow new Error(\"wrong content \" + data);\n\t\t\t\t\t}\n\t\t\t\t\texport default function() {}\n\t\t\t\t`,\n\t\t\t},\n\t\t},\n\t}\n\tfor name, testCase := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfs := fsext.NewMemMapFs()\n\t\t\terr := writeToFs(fs, testCase.fsMap)\n\t\t\tfs = fsext.NewCacheOnReadFs(fs, fsext.NewMemMapFs(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.WarnLevel)\n\t\t\tb, err := getSimpleBundle(t, \"/main.js\", `export { default } from \"/A/A/A/A/script.js\"`, fs, logger)\n\n\t\t\tif testCase.expectedError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, testCase.expectedError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = b.Instantiate(context.Background(), 0)\n\t\t\trequire.NoError(t, err)\n\t\t\tlogs := hook.Drain()\n\n\t\t\tif len(testCase.expectedLogs) == 0 {\n\t\t\t\trequire.Empty(t, logs)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, len(testCase.expectedLogs), len(logs))\n\n\t\t\tfor i, log := range logs {\n\t\t\t\trequire.Contains(t, log.Message, testCase.expectedLogs[i], \"log line %d\", i)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/runner.go",
    "content": "package js\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"maps\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/sirupsen/logrus\"\n\t\"golang.org/x/net/http2\"\n\t\"golang.org/x/time/rate\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/js/eventloop\"\n\t\"go.k6.io/k6/internal/lib/consts\"\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// Ensure Runner implements the lib.Runner interface\nvar _ lib.Runner = &Runner{}\n\n// TODO: https://github.com/grafana/k6/issues/2186\n// An advanced TLS support should cover the rid of the warning\n//\n//nolint:gochecknoglobals\nvar nameToCertWarning sync.Once\n\n// Runner implements [lib.Runner] and is used to run js tests\ntype Runner struct {\n\tBundle       *Bundle\n\tpreInitState *lib.TestPreInitState\n\n\tBaseDialer net.Dialer\n\tResolver   netext.Resolver\n\t// TODO: Remove ActualResolver, it's a hack to simplify mocking in tests.\n\tActualResolver netext.MultiResolver\n\tRPSLimit       *rate.Limiter\n\tRunTags        *metrics.TagSet\n\n\tconsole    *console\n\tsetupData  []byte\n\tBufferPool *lib.BufferPool\n}\n\n// New returns a new Runner for the provided source\nfunc New(\n\tpiState *lib.TestPreInitState, src *loader.SourceData, filesystems map[string]fsext.Fs, mr *modules.ModuleResolver,\n) (*Runner, error) {\n\tbundle, err := NewBundle(piState, src, filesystems, mr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewFromBundle(piState, bundle)\n}\n\n// NewFromArchive returns a new Runner from the source in the provided archive\nfunc NewFromArchive(piState *lib.TestPreInitState, arc *lib.Archive, mr *modules.ModuleResolver) (*Runner, error) {\n\tbundle, err := NewBundleFromArchive(piState, arc, mr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewFromBundle(piState, bundle)\n}\n\n// NewFromBundle returns a new Runner from the provided Bundle\nfunc NewFromBundle(piState *lib.TestPreInitState, b *Bundle) (*Runner, error) {\n\tdefDNS := types.DefaultDNSConfig()\n\tr := &Runner{\n\t\tBundle:       b,\n\t\tpreInitState: piState,\n\t\tBaseDialer: net.Dialer{\n\t\t\tTimeout:   30 * time.Second,\n\t\t\tKeepAlive: 30 * time.Second,\n\t\t},\n\t\tconsole: newConsole(piState.Logger),\n\t\tResolver: netext.NewResolver(\n\t\t\tnet.LookupIP, 0, defDNS.Select.DNSSelect, defDNS.Policy.DNSPolicy),\n\t\tActualResolver: net.LookupIP,\n\t\tBufferPool:     lib.NewBufferPool(),\n\t}\n\n\terr := r.SetOptions(r.Bundle.Options)\n\n\treturn r, err\n}\n\n// MakeArchive creates an Archive of the runner. There should be a corresponding NewFromArchive() function\n// that will restore the runner from the archive.\nfunc (r *Runner) MakeArchive() *lib.Archive {\n\treturn r.Bundle.makeArchive()\n}\n\n// NewVU returns a new initialized VU.\nfunc (r *Runner) NewVU(\n\tctx context.Context, idLocal, idGlobal uint64, samplesOut chan<- metrics.SampleContainer,\n) (lib.InitializedVU, error) {\n\tvu, err := r.newVU(ctx, idLocal, idGlobal, samplesOut)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn lib.InitializedVU(vu), nil\n}\n\n//nolint:funlen\nfunc (r *Runner) newVU(\n\tctx context.Context, idLocal, idGlobal uint64, samplesOut chan<- metrics.SampleContainer,\n) (*VU, error) {\n\t// Instantiate a new bundle, make a VU out of it.\n\tbi, err := r.Bundle.Instantiate(ctx, idLocal)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar cipherSuites []uint16\n\tif r.Bundle.Options.TLSCipherSuites != nil {\n\t\tcipherSuites = *r.Bundle.Options.TLSCipherSuites\n\t}\n\n\tvar tlsVersions lib.TLSVersions\n\tif r.Bundle.Options.TLSVersion != nil {\n\t\ttlsVersions = *r.Bundle.Options.TLSVersion\n\t}\n\n\ttlsAuth := r.Bundle.Options.TLSAuth\n\tcerts := make([]tls.Certificate, len(tlsAuth))\n\tnameToCert := make(map[string]*tls.Certificate)\n\tfor i, auth := range tlsAuth {\n\t\tcert, errC := auth.Certificate()\n\t\tif errC != nil {\n\t\t\treturn nil, errC\n\t\t}\n\t\tcerts[i] = *cert\n\t\tfor _, name := range auth.Domains {\n\t\t\tnameToCert[name] = cert\n\t\t}\n\t}\n\n\tdialer := &netext.Dialer{\n\t\tDialer:           r.BaseDialer,\n\t\tResolver:         r.Resolver,\n\t\tBlacklist:        r.Bundle.Options.BlacklistIPs,\n\t\tBlockedHostnames: r.Bundle.Options.BlockedHostnames.Trie,\n\t\tHosts:            r.Bundle.Options.Hosts.Trie,\n\t}\n\tif r.Bundle.Options.LocalIPs.Valid {\n\t\tvar ipIndex uint64\n\t\tif idLocal > 0 {\n\t\t\tipIndex = idLocal - 1\n\t\t}\n\t\tdialer.LocalAddr = &net.TCPAddr{IP: r.Bundle.Options.LocalIPs.Pool.GetIP(ipIndex)}\n\t}\n\n\ttlsConfig := &tls.Config{\n\t\tInsecureSkipVerify: r.Bundle.Options.InsecureSkipTLSVerify.Bool, //nolint:gosec\n\t\tCipherSuites:       cipherSuites,\n\t\tMinVersion:         uint16(tlsVersions.Min), //nolint:gosec\n\t\tMaxVersion:         uint16(tlsVersions.Max), //nolint:gosec\n\t\tCertificates:       certs,\n\t\tRenegotiation:      tls.RenegotiateFreelyAsClient,\n\t\tKeyLogWriter:       r.preInitState.KeyLogger,\n\t}\n\t// Follow NameToCertificate in https://pkg.go.dev/crypto/tls@go1.17.6#Config, leave this field nil\n\t// when it is empty\n\tif len(nameToCert) > 0 {\n\t\tnameToCertWarning.Do(func() {\n\t\t\tr.preInitState.Logger.Warn(\n\t\t\t\t\"tlsAuth.domains option could be removed in the next releases, it's recommended to leave it empty \" +\n\t\t\t\t\t\"and let k6 automatically detect from the provided certificate. It follows the Go's NameToCertificate \" +\n\t\t\t\t\t\"deprecation - https://pkg.go.dev/crypto/tls@go1.17#Config.\",\n\t\t\t)\n\t\t})\n\t\ttlsConfig.NameToCertificate = nameToCert //nolint:staticcheck\n\t}\n\ttransport := &http.Transport{\n\t\tProxy:               http.ProxyFromEnvironment,\n\t\tTLSClientConfig:     tlsConfig,\n\t\tDialContext:         dialer.DialContext,\n\t\tDisableCompression:  true,\n\t\tDisableKeepAlives:   r.Bundle.Options.NoConnectionReuse.Bool,\n\t\tMaxIdleConns:        int(r.Bundle.Options.Batch.Int64),\n\t\tMaxIdleConnsPerHost: int(r.Bundle.Options.BatchPerHost.Int64),\n\t}\n\n\tif r.forceHTTP1() {\n\t\ttransport.TLSNextProto = make(map[string]func(string, *tls.Conn) http.RoundTripper) // send over h1 protocol\n\t} else {\n\t\t_ = http2.ConfigureTransport(transport) // send over h2 protocol\n\t}\n\n\tcookieJar, err := cookiejar.New(nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvu := &VU{\n\t\tID:             idLocal,\n\t\tIDGlobal:       idGlobal,\n\t\titeration:      int64(-1),\n\t\tBundleInstance: *bi,\n\t\tRunner:         r,\n\t\tTransport:      transport,\n\t\tDialer:         dialer,\n\t\tCookieJar:      cookieJar,\n\t\tTLSConfig:      tlsConfig,\n\t\tConsole:        r.console,\n\t\tBufferPool:     r.BufferPool,\n\t\tSamples:        samplesOut,\n\t\tscenarioIter:   make(map[string]uint64),\n\t}\n\n\tvu.state = &lib.State{\n\t\tLogger:         vu.Runner.preInitState.Logger,\n\t\tOptions:        vu.Runner.Bundle.Options,\n\t\tTransport:      vu.Transport,\n\t\tDialer:         vu.Dialer,\n\t\tTLSConfig:      vu.TLSConfig,\n\t\tCookieJar:      cookieJar,\n\t\tRPSLimit:       vu.Runner.RPSLimit,\n\t\tBufferPool:     vu.BufferPool,\n\t\tVUID:           vu.ID,\n\t\tVUIDGlobal:     vu.IDGlobal,\n\t\tSamples:        vu.Samples,\n\t\tTags:           lib.NewVUStateTags(vu.Runner.RunTags),\n\t\tBuiltinMetrics: r.preInitState.BuiltinMetrics,\n\t\tTracerProvider: r.preInitState.TracerProvider,\n\t\tUsage:          r.preInitState.Usage,\n\t\tTestStatus:     r.preInitState.TestStatus,\n\t}\n\tvu.moduleVUImpl.state = vu.state\n\t_ = vu.Runtime.Set(\"console\", vu.Console)\n\n\treturn vu, nil\n}\n\n// forceHTTP1 checks if force http1 env variable has been set in order to force requests to be sent over h1\n// TODO: This feature is temporary until #936 is resolved\nfunc (r *Runner) forceHTTP1() bool {\n\tif r.preInitState.LookupEnv == nil {\n\t\treturn false\n\t}\n\tgodebug, _ := r.preInitState.LookupEnv(\"GODEBUG\")\n\tif godebug == \"\" {\n\t\treturn false\n\t}\n\tvariables := strings.SplitAfter(godebug, \",\")\n\n\tfor _, v := range variables {\n\t\tif strings.Trim(v, \",\") == \"http2client=0\" {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Setup runs the setup function if there is one and sets the setupData to the returned value\nfunc (r *Runner) Setup(ctx context.Context, out chan<- metrics.SampleContainer) error {\n\tif !r.IsExecutable(consts.SetupFn) {\n\t\t// do not init a new transient VU or execute setup() if it wasn't\n\t\t// actually defined and exported in the script\n\t\tr.preInitState.Logger.Debugf(\"%s() is not defined or not exported, skipping!\", consts.SetupFn)\n\t\treturn nil\n\t}\n\tr.preInitState.Logger.Debugf(\"Running %s()...\", consts.SetupFn)\n\n\tsetupCtx, setupCancel := context.WithTimeout(ctx, r.getTimeoutFor(consts.SetupFn))\n\tdefer setupCancel()\n\n\tv, err := r.runPart(setupCtx, out, consts.SetupFn, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// r.setupData = nil is special it means undefined from this moment forward\n\tif sobek.IsUndefined(v) {\n\t\tr.setupData = nil\n\t\treturn nil\n\t}\n\n\tr.setupData, err = json.Marshal(v.Export())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshaling setup() data to JSON: %w\", err)\n\t}\n\tvar tmp any\n\treturn json.Unmarshal(r.setupData, &tmp)\n}\n\n// GetSetupData returns the setup data as json if Setup() was specified and executed, nil otherwise\nfunc (r *Runner) GetSetupData() []byte {\n\treturn r.setupData\n}\n\n// SetSetupData saves the externally supplied setup data as json in the runner, so it can be used in VUs\nfunc (r *Runner) SetSetupData(data []byte) {\n\tr.setupData = data\n}\n\n// Teardown runs the teardown function if there is one.\nfunc (r *Runner) Teardown(ctx context.Context, out chan<- metrics.SampleContainer) error {\n\tif !r.IsExecutable(consts.TeardownFn) {\n\t\t// do not init a new transient VU or execute teardown() if it wasn't\n\t\t// actually defined and exported in the script\n\t\tr.preInitState.Logger.Debugf(\"%s() is not defined or not exported, skipping!\", consts.TeardownFn)\n\t\treturn nil\n\t}\n\tr.preInitState.Logger.Debugf(\"Running %s()...\", consts.TeardownFn)\n\n\tteardownCtx, teardownCancel := context.WithTimeout(ctx, r.getTimeoutFor(consts.TeardownFn))\n\tdefer teardownCancel()\n\n\tvar data any\n\tif r.setupData != nil {\n\t\tif err := json.Unmarshal(r.setupData, &data); err != nil {\n\t\t\treturn fmt.Errorf(\"error unmarshaling setup data for teardown() from JSON: %w\", err)\n\t\t}\n\t} else {\n\t\tdata = sobek.Undefined()\n\t}\n\t_, err := r.runPart(teardownCtx, out, consts.TeardownFn, data)\n\treturn err\n}\n\n// GetOptions returns the currently calculated [lib.Options] for the given Runner.\nfunc (r *Runner) GetOptions() lib.Options {\n\treturn r.Bundle.Options\n}\n\n// IsExecutable returns whether the given name is an exported and\n// executable function in the script.\nfunc (r *Runner) IsExecutable(name string) bool {\n\t_, exists := r.Bundle.callableExports[name]\n\treturn exists\n}\n\n// HandleSummary calls the specified summary callback, if supplied.\nfunc (r *Runner) HandleSummary(\n\tctx context.Context,\n\tlegacy *lib.LegacySummary,\n\ts *summary.Summary,\n\tmeta summary.Meta,\n) (map[string]io.Reader, error) {\n\tout := make(chan metrics.SampleContainer, 100)\n\tdefer close(out)\n\n\tgo func() { // discard all metrics\n\t\tfor range out { //nolint:revive\n\t\t}\n\t}()\n\n\tsummaryCtx, cancel := context.WithTimeout(ctx, r.getTimeoutFor(consts.HandleSummaryFn))\n\tdefer cancel()\n\n\tvu, err := r.newVU(summaryCtx, 0, 0, out)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t_ = context.AfterFunc(summaryCtx, func() {\n\t\tvu.Runtime.Interrupt(context.Canceled)\n\t})\n\tvu.moduleVUImpl.ctx = summaryCtx\n\n\tnoColor, enableColors, newMachineReadableSummary,\n\t\tsummaryCode, summaryData, handleSummaryData,\n\t\terr := prepareHandleSummaryCall(\n\t\tr, vu.Runtime, legacy, s, meta,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcallbackResult, err := runUserProvidedHandleSummaryCallback(summaryCtx, vu, handleSummaryData)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\twrapper := strings.Replace(summaryWrapperLambdaCode, \"/*JSLIB_SUMMARY_CODE*/\", summaryCode, 1)\n\thandleSummaryWrapperRaw, err := vu.Runtime.RunString(wrapper)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unexpected error while getting the summary wrapper: %w\", err)\n\t}\n\thandleSummaryWrapper, ok := sobek.AssertFunction(handleSummaryWrapperRaw)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"unexpected error did not get a callable summary wrapper\")\n\t}\n\n\twrapperArgs := prepareHandleWrapperArgs(\n\t\tvu, noColor, enableColors, newMachineReadableSummary, callbackResult, handleSummaryData, summaryData,\n\t)\n\trawResult, _, _, err := vu.runFn(summaryCtx, false, handleSummaryWrapper, nil, wrapperArgs...)\n\n\tif deadlineError := r.checkDeadline(summaryCtx, consts.HandleSummaryFn, rawResult, err); deadlineError != nil {\n\t\treturn nil, deadlineError\n\t}\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unexpected error while generating the summary: %w\", err)\n\t}\n\n\treturn getSummaryResult(rawResult)\n}\n\nfunc prepareHandleSummaryCall(\n\tr *Runner,\n\trt *sobek.Runtime,\n\tlegacy *lib.LegacySummary,\n\ts *summary.Summary,\n\tmeta summary.Meta,\n) (bool, bool, bool, string, sobek.Value, sobek.Value, error) {\n\tvar (\n\t\tnoColor                   bool\n\t\tenableColors              bool\n\t\tnewMachineReadableSummary bool\n\t\tsummaryCode               string\n\t\tsummaryData               sobek.Value\n\t\thandleSummaryData         sobek.Value\n\t\terr                       error\n\t)\n\t// TODO(@joanlopez): Drop this if-else once we stop supporting the legacy summary. Summary wouldn't be nil by then.\n\tif s != nil {\n\t\tnoColor = s.NoColor\n\t\tenableColors = s.EnableColors\n\t\tnewMachineReadableSummary = s.NewMachineReadableSummary\n\t\tsummaryCode = jslibSummaryCode\n\n\t\tsummaryReport, srErr := summarizeReportToObject(rt, s)\n\t\tsummaryData = rt.ToValue(summaryReport)\n\n\t\tif s.NewMachineReadableSummary {\n\t\t\tmrSummary, mrsErr := summary.ToMachineReadable(s, meta)\n\t\t\thandleSummaryData = rt.ToValue(mrSummary)\n\t\t\terr = errors.Join(srErr, mrsErr)\n\t\t} else {\n\t\t\thandleSummaryData = rt.ToValue(summarizeMetricsToObject(legacy, r.Bundle.Options, r.setupData))\n\t\t}\n\t} else {\n\t\tnoColor = legacy.NoColor\n\t\tenableColors = !legacy.NoColor && legacy.UIState.IsStdOutTTY\n\t\tsummaryCode = jslibSummaryLegacyCode\n\t\tsummaryData = rt.ToValue(summarizeMetricsToObject(legacy, r.Bundle.Options, r.setupData))\n\t\thandleSummaryData = summaryData\n\t}\n\n\treturn noColor, enableColors, newMachineReadableSummary, summaryCode, summaryData, handleSummaryData, err\n}\n\nfunc runUserProvidedHandleSummaryCallback(\n\tsummaryCtx context.Context,\n\tvu *VU,\n\thandleSummaryData sobek.Value,\n) (sobek.Value, error) {\n\tfn := vu.getExported(consts.HandleSummaryFn)\n\tif fn == nil {\n\t\treturn sobek.Undefined(), nil\n\t}\n\n\thandleSummaryFn, ok := sobek.AssertFunction(fn)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"exported identifier %s must be a function\", consts.HandleSummaryFn)\n\t}\n\n\tcallbackResult, _, _, err := vu.runFn(summaryCtx, false, handleSummaryFn, nil, handleSummaryData)\n\tif err != nil {\n\t\terrText, fields := errext.Format(err)\n\t\tvu.Runner.preInitState.Logger.WithFields(fields).Error(errText)\n\t}\n\n\t// In case of error, we only want to log it\n\t// but still proceed with the built-in summary handler, so we return nil.\n\treturn callbackResult, nil\n}\n\nfunc prepareHandleWrapperArgs(\n\tvu *VU,\n\tnoColor, enableColors, newMachineReadableSummary bool,\n\tcallbackResult, handleSummaryData, summaryData sobek.Value,\n) []sobek.Value {\n\toptions := map[string]any{\n\t\t// TODO: improve when we can easily export all option values, including defaults?\n\t\t\"summaryTrendStats\":         vu.Runner.Bundle.Options.SummaryTrendStats,\n\t\t\"summaryTimeUnit\":           vu.Runner.Bundle.Options.SummaryTimeUnit.String,\n\t\t\"noColor\":                   noColor, // TODO: move to the (runtime) options\n\t\t\"enableColors\":              enableColors,\n\t\t\"newMachineReadableSummary\": newMachineReadableSummary,\n\t}\n\n\twrapperArgs := []sobek.Value{\n\t\tcallbackResult,\n\t\tvu.Runtime.ToValue(vu.Runner.Bundle.preInitState.RuntimeOptions.SummaryExport.String),\n\t\thandleSummaryData,\n\t\tsummaryData,\n\t\tvu.Runtime.ToValue(options),\n\t}\n\n\treturn wrapperArgs\n}\n\nfunc (r *Runner) checkDeadline(ctx context.Context, name string, result sobek.Value, err error) error {\n\tif deadline, ok := ctx.Deadline(); !ok || !time.Now().After(deadline) {\n\t\treturn nil\n\t}\n\n\t// deadline is reached so we have timed-outed but this might've not been registered correctly\n\t// we could have an error that is not context.Canceled in which case we should return it instead\n\t//nolint:errorlint\n\tif err, ok := err.(*sobek.InterruptedError); ok && result != nil && err.Value() != context.Canceled {\n\t\t// TODO: silence this error?\n\t\treturn err\n\t}\n\t// otherwise we have timeouted\n\treturn newTimeoutError(name, r.getTimeoutFor(name))\n}\n\n// SetOptions sets the test Options to the provided data and makes necessary changes to the Runner.\nfunc (r *Runner) SetOptions(opts lib.Options) error {\n\tr.Bundle.Options = opts\n\tr.RPSLimit = nil\n\tif rps := opts.RPS; rps.Valid && rps.Int64 > 0 {\n\t\tr.RPSLimit = rate.NewLimiter(rate.Limit(rps.Int64), 1)\n\t}\n\n\t// TODO: validate that all exec values are either nil or valid exported methods (or HTTP requests in the future)\n\n\tif opts.ConsoleOutput.Valid {\n\t\t// TODO: fix logger hack, see https://github.com/grafana/k6/issues/2958\n\t\t// and https://github.com/grafana/k6/issues/2968\n\t\tvar formatter logrus.Formatter = &logrus.JSONFormatter{}\n\t\tlevel := logrus.InfoLevel\n\t\tif l, ok := r.preInitState.Logger.(*logrus.Logger); ok { //nolint: forbidigo\n\t\t\tformatter = l.Formatter\n\t\t\tlevel = l.Level\n\t\t}\n\t\tc, err := newFileConsole(opts.ConsoleOutput.String, formatter, level)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tr.console = c\n\t}\n\n\t// FIXME: Resolver probably shouldn't be reset here...\n\t// It's done because the js.Runner is created before the full\n\t// configuration has been processed, at which point we don't have\n\t// access to the DNSConfig, and need to wait for this SetOptions\n\t// call that happens after all config has been assembled.\n\t// We could make DNSConfig part of RuntimeOptions, but that seems\n\t// conceptually wrong since the JS runtime doesn't care about it\n\t// (it needs the actual resolver, not the config), and it would\n\t// require an additional field on Bundle to pass the config through,\n\t// which is arguably worse than this.\n\tif err := r.setResolver(opts.DNS); err != nil {\n\t\treturn err\n\t}\n\n\t// FIXME: add tests\n\tr.RunTags = r.preInitState.Registry.RootTagSet().WithTagsFromMap(r.Bundle.Options.RunTags)\n\n\treturn nil\n}\n\nfunc (r *Runner) setResolver(dns types.DNSConfig) error {\n\tttl, err := parseTTL(dns.TTL.String)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tdnsSel := dns.Select\n\tif !dnsSel.Valid {\n\t\tdnsSel = types.DefaultDNSConfig().Select\n\t}\n\tdnsPol := dns.Policy\n\tif !dnsPol.Valid {\n\t\tdnsPol = types.DefaultDNSConfig().Policy\n\t}\n\tr.Resolver = netext.NewResolver(\n\t\tr.ActualResolver, ttl, dnsSel.DNSSelect, dnsPol.DNSPolicy)\n\n\treturn nil\n}\n\nfunc parseTTL(ttlS string) (time.Duration, error) {\n\tttl := time.Duration(0)\n\tswitch ttlS {\n\tcase \"inf\":\n\t\t// cache \"infinitely\"\n\t\tttl = time.Hour * 24 * 365\n\tcase \"0\":\n\t\t// disable cache\n\tcase \"\":\n\t\tttlS = types.DefaultDNSConfig().TTL.String\n\t\tfallthrough\n\tdefault:\n\t\tvar err error\n\t\tttl, err = types.ParseExtendedDuration(ttlS)\n\t\tif ttl < 0 || err != nil {\n\t\t\treturn ttl, fmt.Errorf(\"invalid DNS TTL: %s\", ttlS)\n\t\t}\n\t}\n\treturn ttl, nil\n}\n\n// Runs an exported function in its own temporary VU, optionally with an argument. Execution is\n// interrupted if the context expires. No error is returned if the part does not exist.\nfunc (r *Runner) runPart(\n\tparentCtx context.Context,\n\tout chan<- metrics.SampleContainer,\n\tname string,\n\targ any,\n) (sobek.Value, error) {\n\tctx, cancel := context.WithCancel(parentCtx)\n\tdefer cancel()\n\n\tvu, err := r.newVU(ctx, 0, 0, out)\n\tif err != nil {\n\t\treturn sobek.Undefined(), err\n\t}\n\tfn, ok := sobek.AssertFunction(vu.getExported(name))\n\tif !ok {\n\t\treturn sobek.Undefined(), nil\n\t}\n\n\t_ = context.AfterFunc(ctx, func() {\n\t\tvu.Runtime.Interrupt(context.Canceled)\n\t})\n\tvu.moduleVUImpl.ctx = ctx\n\n\tgroupPath, err := lib.NewGroupPath(lib.RootGroupPath, name)\n\tif err != nil {\n\t\treturn sobek.Undefined(), err\n\t}\n\n\tif r.Bundle.Options.SystemTags.Has(metrics.TagGroup) {\n\t\tvu.state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\ttagsAndMeta.SetSystemTagOrMeta(metrics.TagGroup, groupPath)\n\t\t})\n\t}\n\tv, _, _, err := vu.runFn(ctx, false, fn, nil, vu.Runtime.ToValue(arg))\n\n\tif deadlineError := r.checkDeadline(ctx, name, v, err); deadlineError != nil {\n\t\treturn nil, deadlineError\n\t}\n\n\treturn v, err\n}\n\n//nolint:gochecknoglobals\nvar sobekPromiseType = reflect.TypeFor[*sobek.Promise]()\n\n// unPromisify gets the result of v if it is a promise, otherwise returns v\nfunc unPromisify(v sobek.Value) sobek.Value {\n\tif !common.IsNullish(v) {\n\t\tif v.ExportType() == sobekPromiseType {\n\t\t\tp, ok := v.Export().(*sobek.Promise)\n\t\t\tif !ok {\n\t\t\t\tpanic(\"Something that was promise did not export to a promise; this shouldn't happen\")\n\t\t\t}\n\t\t\treturn p.Result()\n\t\t}\n\t}\n\n\treturn v\n}\n\n// getTimeoutFor returns the timeout duration for given special script function.\nfunc (r *Runner) getTimeoutFor(stage string) time.Duration {\n\td := time.Duration(0)\n\tswitch stage {\n\tcase consts.SetupFn:\n\t\treturn r.Bundle.Options.SetupTimeout.TimeDuration()\n\tcase consts.TeardownFn:\n\t\treturn r.Bundle.Options.TeardownTimeout.TimeDuration()\n\tcase consts.HandleSummaryFn:\n\t\treturn 2 * time.Minute // TODO: make configurable\n\t}\n\treturn d\n}\n\n// VU implements the [lib.VU] interface for the js [Runner].\ntype VU struct {\n\tBundleInstance\n\n\tRunner    *Runner\n\tTransport *http.Transport\n\tDialer    *netext.Dialer\n\tCookieJar *cookiejar.Jar\n\tTLSConfig *tls.Config\n\tID        uint64 // local to the current instance\n\tIDGlobal  uint64 // global across all instances\n\titeration int64\n\n\tConsole    *console\n\tBufferPool *lib.BufferPool\n\n\tSamples chan<- metrics.SampleContainer\n\n\tsetupData sobek.Value\n\n\tstate *lib.State\n\t// count of iterations executed by this VU in each scenario\n\tscenarioIter map[string]uint64\n}\n\n// Verify that interfaces are implemented\nvar (\n\t_ lib.ActiveVU      = &ActiveVU{}\n\t_ lib.InitializedVU = &VU{}\n)\n\n// ActiveVU holds a VU and its activation parameters\ntype ActiveVU struct {\n\t*VU\n\t*lib.VUActivationParams\n\tbusy chan struct{}\n\n\tscenarioName              string\n\tgetNextIterationCounters  func() (uint64, uint64)\n\tscIterLocal, scIterGlobal uint64\n}\n\n// GetID returns the unique VU ID.\nfunc (u *VU) GetID() uint64 {\n\treturn u.ID\n}\n\n// Activate the VU so it will be able to run code.\nfunc (u *VU) Activate(params *lib.VUActivationParams) lib.ActiveVU {\n\tu.Runtime.ClearInterrupt()\n\n\tif params.Exec == \"\" {\n\t\tparams.Exec = consts.DefaultFn\n\t}\n\n\t// Override the preset global env with any custom env vars\n\tenv := make(map[string]string, len(u.env)+len(params.Env))\n\tmaps.Copy(env, u.env)\n\tmaps.Copy(env, params.Env)\n\t//nolint:errcheck,gosec // see https://github.com/grafana/k6/issues/1722#issuecomment-1761173634\n\tu.Runtime.Set(\"__ENV\", env)\n\n\topts := u.Runner.Bundle.Options\n\n\tu.state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t// Deliberately overwrite tags from previous activations, i.e. ones that\n\t\t// might have come from previous scenarios. We also intentionally clear\n\t\t// out the metadata, it cannot survive between scenarios either.\n\t\ttagsAndMeta.Tags = u.Runner.RunTags.WithTagsFromMap(params.Tags)\n\t\ttagsAndMeta.Metadata = nil\n\n\t\tif opts.SystemTags.Has(metrics.TagVU) {\n\t\t\ttagsAndMeta.SetSystemTagOrMeta(metrics.TagVU, strconv.FormatUint(u.ID, 10))\n\t\t}\n\t\tif opts.SystemTags.Has(metrics.TagIter) {\n\t\t\ttagsAndMeta.SetSystemTagOrMeta(metrics.TagIter, strconv.FormatInt(u.iteration, 10))\n\t\t}\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(opts.SystemTags, metrics.TagGroup, lib.RootGroupPath)\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(opts.SystemTags, metrics.TagScenario, params.Scenario)\n\t})\n\n\tctx := params.RunContext\n\tu.moduleVUImpl.ctx = ctx\n\n\tu.state.GetScenarioVUIter = func() uint64 {\n\t\treturn u.scenarioIter[params.Scenario]\n\t}\n\n\tavu := &ActiveVU{\n\t\tVU:                       u,\n\t\tVUActivationParams:       params,\n\t\tbusy:                     make(chan struct{}, 1),\n\t\tscenarioName:             params.Scenario,\n\t\tscIterLocal:              ^uint64(0),\n\t\tscIterGlobal:             ^uint64(0),\n\t\tgetNextIterationCounters: params.GetNextIterationCounters,\n\t}\n\n\tu.state.GetScenarioLocalVUIter = func() uint64 {\n\t\treturn avu.scIterLocal\n\t}\n\tu.state.GetScenarioGlobalVUIter = func() uint64 {\n\t\treturn avu.scIterGlobal\n\t}\n\n\t// Wait for the run context to be over\n\tcontext.AfterFunc(ctx, func() {\n\t\t// Interrupt the JS runtime\n\t\tu.Runtime.Interrupt(context.Canceled)\n\t\t// Wait for the VU to stop running, if it was, and prevent it from\n\t\t// running again for this activation\n\t\tavu.busy <- struct{}{}\n\n\t\tif params.DeactivateCallback != nil {\n\t\t\tparams.DeactivateCallback(u)\n\t\t}\n\t})\n\n\treturn avu\n}\n\n// RunOnce runs the configured Exec function once.\nfunc (u *ActiveVU) RunOnce() error {\n\tselect {\n\tcase <-u.RunContext.Done():\n\t\treturn u.RunContext.Err() // we are done, return\n\tcase u.busy <- struct{}{}:\n\t\t// nothing else can run now, and the VU cannot be deactivated\n\t}\n\tdefer func() {\n\t\t<-u.busy // unlock deactivation again\n\t}()\n\n\t// Unmarshall the setupData only the first time for each VU so that VUs are isolated but we\n\t// still don't use too much CPU in the middle test\n\tif u.setupData == nil {\n\t\tif u.Runner.setupData != nil {\n\t\t\tvar data any\n\t\t\tif err := json.Unmarshal(u.Runner.setupData, &data); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error unmarshaling setup data for the iteration from JSON: %w\", err)\n\t\t\t}\n\t\t\tu.setupData = u.Runtime.ToValue(data)\n\t\t} else {\n\t\t\tu.setupData = sobek.Undefined()\n\t\t}\n\t}\n\n\tfn := u.getCallableExport(u.Exec)\n\tif fn == nil {\n\t\t// Shouldn't happen; this is validated in cmd.validateScenarioConfig()\n\t\tpanic(fmt.Sprintf(\"function '%s' not found in exports\", u.Exec))\n\t}\n\n\tu.incrIteration()\n\tif err := u.Runtime.Set(\"__ITER\", u.iteration); err != nil {\n\t\tpanic(fmt.Errorf(\"error setting __ITER in Sobek runtime: %w\", err))\n\t}\n\n\tctx, cancel := context.WithCancel(u.RunContext)\n\tdefer cancel()\n\tu.moduleVUImpl.ctx = ctx\n\n\teventIterData := event.IterData{\n\t\tIteration:    u.iteration,\n\t\tVUID:         u.ID,\n\t\tScenarioName: u.scenarioName,\n\t}\n\n\tu.emitAndWaitEvent(&event.Event{Type: event.IterStart, Data: eventIterData})\n\n\t// Call the exported function.\n\t_, isFullIteration, totalTime, err := u.runFn(ctx, true, fn, cancel, u.setupData)\n\tif err != nil {\n\t\tvar x *sobek.InterruptedError\n\t\tif errors.As(err, &x) {\n\t\t\tif v, ok := x.Value().(*errext.InterruptError); ok {\n\t\t\t\tv.Reason = x.Error()\n\t\t\t\terr = v\n\t\t\t}\n\t\t}\n\t\teventIterData.Error = err\n\t}\n\n\tu.emitAndWaitEvent(&event.Event{Type: event.IterEnd, Data: eventIterData})\n\n\t// If MinIterationDuration is specified and the iteration wasn't canceled\n\t// and was less than it, sleep for the remainder\n\tif isFullIteration && u.Runner.Bundle.Options.MinIterationDuration.Valid {\n\t\tdurationDiff := u.Runner.Bundle.Options.MinIterationDuration.TimeDuration() - totalTime\n\t\tif durationDiff > 0 {\n\t\t\tselect {\n\t\t\tcase <-time.After(durationDiff):\n\t\t\tcase <-u.RunContext.Done():\n\t\t\t}\n\t\t}\n\t}\n\n\treturn err\n}\n\nfunc (u *ActiveVU) emitAndWaitEvent(evt *event.Event) {\n\twaitDone := u.moduleVUImpl.events.local.Emit(evt)\n\twaitCtx, waitCancel := context.WithTimeout(u.RunContext, 30*time.Minute)\n\tdefer waitCancel()\n\tif werr := waitDone(waitCtx); werr != nil {\n\t\tu.state.Logger.WithError(werr).Warn()\n\t}\n}\n\nfunc (u *VU) getExported(name string) sobek.Value {\n\treturn u.BundleInstance.getExported(name)\n}\n\n// if isDefault is true, cancel also needs to be provided and it should cancel the provided context\n// TODO remove the need for the above through refactoring of this function and its callees\nfunc (u *VU) runFn(\n\tctx context.Context, isDefault bool, fn sobek.Callable, cancel func(), args ...sobek.Value,\n) (v sobek.Value, isFullIteration bool, t time.Duration, err error) {\n\tif !u.Runner.Bundle.Options.NoCookiesReset.ValueOrZero() {\n\t\tu.state.CookieJar, err = cookiejar.New(nil)\n\t\tif err != nil {\n\t\t\treturn sobek.Undefined(), false, time.Duration(0), err\n\t\t}\n\t}\n\n\topts := &u.Runner.Bundle.Options\n\n\tif opts.SystemTags.Has(metrics.TagIter) {\n\t\tu.state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\ttagsAndMeta.SetSystemTagOrMeta(metrics.TagIter, strconv.FormatInt(u.state.Iteration, 10))\n\t\t})\n\t}\n\n\tstartTime := time.Now()\n\n\tif u.moduleVUImpl.eventLoop == nil {\n\t\tu.moduleVUImpl.eventLoop = eventloop.New(u.moduleVUImpl)\n\t}\n\terr = u.moduleVUImpl.eventLoop.Start(func() (err error) {\n\t\tv, err = fn(sobek.Undefined(), args...) // Actually run the JS script\n\t\treturn err\n\t})\n\n\tselect {\n\tcase <-ctx.Done():\n\t\tisFullIteration = false\n\tdefault:\n\t\tisFullIteration = true\n\t}\n\n\tif cancel != nil {\n\t\tcancel()\n\t\tu.moduleVUImpl.eventLoop.WaitOnRegistered()\n\t}\n\tendTime := time.Now()\n\tvar exception *sobek.Exception\n\tif errors.As(err, &exception) {\n\t\terr = &scriptExceptionError{inner: exception}\n\t}\n\n\tif u.Runner.Bundle.Options.NoVUConnectionReuse.Bool {\n\t\tu.Transport.CloseIdleConnections()\n\t}\n\n\tbuiltinMetrics := u.Runner.preInitState.BuiltinMetrics\n\tctm := u.state.Tags.GetCurrentValues()\n\tu.state.Samples <- u.Dialer.IOSamples(endTime, ctm, builtinMetrics)\n\n\tif isFullIteration && isDefault {\n\t\tu.state.Samples <- iterationSamples(startTime, endTime, ctm, builtinMetrics)\n\t}\n\n\tv = unPromisify(v)\n\n\treturn v, isFullIteration, endTime.Sub(startTime), err\n}\n\nfunc iterationSamples(\n\tstartTime, endTime time.Time, ctm metrics.TagsAndMeta, builtinMetrics *metrics.BuiltinMetrics,\n) metrics.Samples {\n\treturn metrics.Samples([]metrics.Sample{\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.IterationDuration,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     endTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(endTime.Sub(startTime)),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.Iterations,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     endTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    1,\n\t\t},\n\t})\n}\n\nfunc (u *ActiveVU) incrIteration() {\n\tu.iteration++\n\tu.state.Iteration = u.iteration\n\n\tif _, ok := u.scenarioIter[u.scenarioName]; ok {\n\t\tu.scenarioIter[u.scenarioName]++\n\t} else {\n\t\tu.scenarioIter[u.scenarioName] = 0\n\t}\n\t// TODO remove this\n\tif u.getNextIterationCounters != nil {\n\t\tu.scIterLocal, u.scIterGlobal = u.getNextIterationCounters()\n\t}\n}\n\ntype scriptExceptionError struct {\n\tinner *sobek.Exception\n}\n\nvar _ interface {\n\terrext.Exception\n\terrext.HasExitCode\n\terrext.HasHint\n\terrext.HasAbortReason\n} = &scriptExceptionError{}\n\nfunc (s *scriptExceptionError) Error() string {\n\t// this calls String instead of error so that by default if it's printed to print the stacktrace\n\treturn s.inner.String()\n}\n\nfunc (s *scriptExceptionError) StackTrace() string {\n\treturn s.inner.String()\n}\n\nfunc (s *scriptExceptionError) Unwrap() error {\n\treturn s.inner\n}\n\nfunc (s *scriptExceptionError) Hint() string {\n\treturn \"script exception\"\n}\n\nfunc (s *scriptExceptionError) AbortReason() errext.AbortReason {\n\treturn errext.AbortedByScriptError\n}\n\nfunc (s *scriptExceptionError) ExitCode() exitcodes.ExitCode {\n\treturn exitcodes.ScriptException\n}\n"
  },
  {
    "path": "internal/js/runner_test.go",
    "content": "package js\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\tstdlog \"log\"\n\t\"math/big\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\tlogtest \"github.com/sirupsen/logrus/hooks/test\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/time/rate\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/execution/local\"\n\t\"go.k6.io/k6/internal/js/modules/k6\"\n\tk6metrics \"go.k6.io/k6/internal/js/modules/k6/metrics\"\n\t\"go.k6.io/k6/internal/js/modules/k6/ws\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin/grpc_testing\"\n\t\"go.k6.io/k6/internal/lib/testutils/mockoutput\"\n\tk6http \"go.k6.io/k6/js/modules/k6/http\"\n\t\"go.k6.io/k6/lib\"\n\t_ \"go.k6.io/k6/lib/executor\" // TODO: figure out something better\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc TestRunnerNew(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tr, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\texports.counter = 0;\n\t\t\texports.default = function() { exports.counter++; }\n\t\t`)\n\t\trequire.NoError(t, err)\n\n\t\tt.Run(\"NewVU\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tctx := t.Context()\n\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\t\t\tvuc, ok := initVU.(*VU)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.Equal(t, int64(0), vuc.getExported(\"counter\").Export())\n\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\tt.Run(\"RunOnce\", func(t *testing.T) { //nolint:paralleltest\n\t\t\t\terr = vu.RunOnce()\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, int64(1), vuc.getExported(\"counter\").Export())\n\t\t\t})\n\t\t})\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := getSimpleRunner(t, \"/script.js\", `blarg`)\n\t\tassert.EqualError(t, err, \"ReferenceError: blarg is not defined\\n\\tat file:///script.js:1:28(1)\\n\")\n\t})\n}\n\nfunc TestRunnerOptions(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `exports.default = function() {};`)\n\trequire.NoError(t, err)\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\ttestdata := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tassert.Equal(t, r.Bundle.Options, r.GetOptions())\n\t\t\tassert.Equal(t, null.NewBool(false, false), r.Bundle.Options.Paused)\n\t\t\trequire.NoError(t, r.SetOptions(lib.Options{Paused: null.BoolFrom(true)}))\n\t\t\tassert.Equal(t, r.Bundle.Options, r.GetOptions())\n\t\t\tassert.Equal(t, null.NewBool(true, true), r.Bundle.Options.Paused)\n\t\t\trequire.NoError(t, r.SetOptions(lib.Options{Paused: null.BoolFrom(false)}))\n\t\t\tassert.Equal(t, r.Bundle.Options, r.GetOptions())\n\t\t\tassert.Equal(t, null.NewBool(false, true), r.Bundle.Options.Paused)\n\t\t})\n\t}\n}\n\nfunc TestRunnerRPSLimit(t *testing.T) {\n\tt.Parallel()\n\n\tvar nilLimiter *rate.Limiter\n\n\tvariants := []struct {\n\t\tname    string\n\t\toptions lib.Options\n\t\tlimiter *rate.Limiter\n\t}{\n\t\t{\n\t\t\tname:    \"RPS not defined\",\n\t\t\toptions: lib.Options{},\n\t\t\tlimiter: nilLimiter,\n\t\t},\n\t\t{\n\t\t\tname:    \"RPS set to non-zero int\",\n\t\t\toptions: lib.Options{RPS: null.IntFrom(9)},\n\t\t\tlimiter: rate.NewLimiter(rate.Limit(9), 1),\n\t\t},\n\t\t{\n\t\t\tname:    \"RPS set to zero\",\n\t\t\toptions: lib.Options{RPS: null.IntFrom(0)},\n\t\t\tlimiter: nilLimiter,\n\t\t},\n\t\t{\n\t\t\tname:    \"RPS set to below zero value\",\n\t\t\toptions: lib.Options{RPS: null.IntFrom(-1)},\n\t\t\tlimiter: nilLimiter,\n\t\t},\n\t}\n\n\tfor _, variant := range variants {\n\t\tt.Run(variant.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr, err := getSimpleRunner(t, \"/script.js\", `exports.default = function() {};`)\n\t\t\trequire.NoError(t, err)\n\t\t\terr = r.SetOptions(variant.options)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, variant.limiter, r.RPSLimit)\n\t\t})\n\t}\n}\n\nfunc TestOptionsSettingToScript(t *testing.T) {\n\tt.Parallel()\n\n\toptionVariants := []string{\n\t\t\"export var options = {};\",\n\t\t\"export var options = {teardownTimeout: '1s'};\",\n\t}\n\n\tfor i, variant := range optionVariants {\n\t\tt.Run(fmt.Sprintf(\"Variant#%d\", i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tdata := variant + `\n\t\t\t\t\texport default function() {\n\t\t\t\t\t\tif (!options) {\n\t\t\t\t\t\t\tthrow new Error(\"Expected options to be defined!\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (options.teardownTimeout != __ENV.expectedTeardownTimeout) {\n\t\t\t\t\t\t\tthrow new Error(\"expected teardownTimeout to be \" + __ENV.expectedTeardownTimeout + \" but it was \" + options.teardownTimeout);\n\t\t\t\t\t\t}\n\t\t\t\t\t};`\n\t\t\tr, err := getSimpleRunner(t, \"/script.js\", data,\n\t\t\t\tlib.RuntimeOptions{Env: map[string]string{\"expectedTeardownTimeout\": \"4s\"}})\n\t\t\trequire.NoError(t, err)\n\n\t\t\tnewOptions := lib.Options{\n\t\t\t\tTeardownTimeout: types.NullDurationFrom(4 * time.Second),\n\t\t\t}\n\t\t\trequire.NoError(t, r.SetOptions(newOptions))\n\t\t\trequire.Equal(t, newOptions, r.GetOptions())\n\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestOptionsPropagationToScript(t *testing.T) {\n\tt.Parallel()\n\tdata := `\n\t\t\tvar options = { setupTimeout: \"1s\", myOption: \"test\" };\n\t\t\texports.options = options;\n\t\t\texports.default = function() {\n\t\t\t\tif (options.external) {\n\t\t\t\t\tthrow new Error(\"Unexpected property external!\");\n\t\t\t\t}\n\t\t\t\tif (options.myOption != \"test\") {\n\t\t\t\t\tthrow new Error(\"expected myOption to remain unchanged but it was '\" + options.myOption + \"'\");\n\t\t\t\t}\n\t\t\t\tif (options.setupTimeout != __ENV.expectedSetupTimeout) {\n\t\t\t\t\tthrow new Error(\"expected setupTimeout to be \" + __ENV.expectedSetupTimeout + \" but it was \" + options.setupTimeout);\n\t\t\t\t}\n\t\t\t};`\n\n\texpScriptOptions := lib.Options{\n\t\tSetupTimeout: types.NullDurationFrom(1 * time.Second),\n\t}\n\tr1, err := getSimpleRunner(t, \"/script.js\", data,\n\t\tlib.RuntimeOptions{Env: map[string]string{\"expectedSetupTimeout\": \"1s\"}})\n\trequire.NoError(t, err)\n\trequire.Equal(t, expScriptOptions, r1.GetOptions())\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive(),\n\t\tlib.RuntimeOptions{Env: map[string]string{\"expectedSetupTimeout\": \"3s\"}},\n\t)\n\trequire.NoError(t, err)\n\trequire.Equal(t, expScriptOptions, r2.GetOptions())\n\tr2.Bundle.Options.SetupTimeout = types.NullDurationFrom(3 * time.Second)\n\n\ttestdata := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestMetricName(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `\n\t\tvar Counter = require(\"k6/metrics\").Counter;\n\n\t\tvar myCounter = new Counter(\"not ok name @\");\n\n\t\texports.default = function(data) {\n\t\t\tmyCounter.add(1);\n\t\t}\n\t`\n\n\t_, err := getSimpleRunner(t, \"/script.js\", script)\n\trequire.Error(t, err)\n}\n\nfunc TestDataIsolation(t *testing.T) {\n\tt.Parallel()\n\n\tscript := `\n\t\tvar exec = require(\"k6/execution\");\n\t\tvar Counter = require(\"k6/metrics\").Counter;\n\t\tvar sleep = require('k6').sleep;\n\n\t\texports.options = {\n\t\t\tscenarios: {\n\t\t\t\tsc1: {\n\t\t\t\t\texecutor: \"shared-iterations\",\n\t\t\t\t\tvus: 2,\n\t\t\t\t\titerations: 100,\n\t\t\t\t\tmaxDuration: \"9s\",\n\t\t\t\t\tgracefulStop: 0,\n\t\t\t\t\texec: \"sc1\",\n\t\t\t\t},\n\t\t\t\tsc2: {\n\t\t\t\t\texecutor: \"per-vu-iterations\",\n\t\t\t\t\tvus: 1,\n\t\t\t\t\titerations: 1,\n\t\t\t\t\tstartTime: \"11s\",\n\t\t\t\t\texec: \"sc2\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tteardownTimeout: \"5s\",\n\t\t\tsetupTimeout: \"5s\",\n\t\t};\n\t\tvar myCounter = new Counter(\"mycounter\");\n\n\t\texports.setup = function() {\n\t\t\treturn { v: 0 };\n\t\t}\n\n\t\texports.sc1 = function(data) {\n\t\t\tif (data.v !== __ITER) {\n\t\t\t\tthrow new Error(\"sc1: wrong data for iter \" + __ITER + \": \" + JSON.stringify(data));\n\t\t\t}\n\t\t\tif (__ITER != 0 && data.v != exec.vu.tags.myiter) {\n\t\t\t\tthrow new Error(\"sc1: wrong vu tags for iter \" + __ITER + \": \" + JSON.stringify(exec.vu.tags));\n\t\t\t}\n\t\t\tdata.v += 1;\n\t\t\texec.vu.tags.myiter = data.v;\n\t\t\tmyCounter.add(1);\n\t\t\tsleep(0.01);\n\t\t}\n\n\t\texports.sc2 = function(data) {\n\t\t\tif (data.v === 0) {\n\t\t\t\tthrow new Error(\"sc2: wrong data, expected VU to have modified setup data locally: \" + data.v);\n\t\t\t}\n\n\t\t\tif (typeof exec.vu.tags.myiter !== \"undefined\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"sc2: wrong tags, expected VU to have new tags in new scenario: \" +\n\t\t\t\t\tJSON.stringify(exec.vu.tags),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tmyCounter.add(1);\n\t\t}\n\n\t\texports.teardown = function(data) {\n\t\t\tif (data.v !== 0) {\n\t\t\t\tthrow new Error(\"teardown: wrong data: \" + data.v);\n\t\t\t}\n\t\t\tmyCounter.add(1);\n\t\t}\n\t`\n\n\trunner, err := getSimpleRunner(t, \"/script.js\", script)\n\trequire.NoError(t, err)\n\n\toptions := runner.GetOptions()\n\trequire.Empty(t, options.Validate())\n\n\ttestRunState := &lib.TestRunState{\n\t\tTestPreInitState: runner.preInitState,\n\t\tOptions:          options,\n\t\tRunner:           runner,\n\t\tRunTags:          runner.preInitState.Registry.RootTagSet().WithTagsFromMap(options.RunTags),\n\t}\n\n\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\trequire.NoError(t, err)\n\n\tglobalCtx := t.Context()\n\trunCtx, runAbort := execution.NewTestRunContext(globalCtx, testRunState.Logger)\n\n\tmockOutput := mockoutput.New()\n\toutputManager := output.NewManager([]output.Output{mockOutput}, testRunState.Logger, runAbort)\n\tsamples := make(chan metrics.SampleContainer, 1000)\n\twaitForMetricsFlushed, stopOutputs, err := outputManager.Start(samples)\n\trequire.NoError(t, err)\n\tdefer stopOutputs(nil)\n\n\tstopEmission, err := execScheduler.Init(runCtx, samples)\n\trequire.NoError(t, err)\n\n\terrC := make(chan error)\n\tgo func() { errC <- execScheduler.Run(globalCtx, runCtx, samples) }()\n\n\tselect {\n\tcase <-time.After(20 * time.Second):\n\t\trunAbort(fmt.Errorf(\"unexpected abort\"))\n\t\tt.Fatal(\"Test timed out\")\n\tcase err := <-errC:\n\t\tstopEmission()\n\t\tclose(samples)\n\t\trequire.NoError(t, err)\n\t\twaitForMetricsFlushed()\n\t}\n\tvar count int\n\tfor _, s := range mockOutput.Samples {\n\t\tif s.Metric.Name == \"mycounter\" {\n\t\t\tcount += int(s.Value)\n\t\t}\n\t}\n\trequire.Equal(t, 102, count, \"mycounter should be the number of iterations + 1 for the teardown\")\n}\n\nfunc testSetupDataHelper(t *testing.T, data string) {\n\tt.Helper()\n\texpScriptOptions := lib.Options{\n\t\tSetupTimeout:    types.NullDurationFrom(1 * time.Second),\n\t\tTeardownTimeout: types.NullDurationFrom(1 * time.Second),\n\t}\n\tr1, err := getSimpleRunner(t, \"/script.js\", data) // TODO fix this\n\trequire.NoError(t, err)\n\trequire.Equal(t, expScriptOptions, r1.GetOptions())\n\n\ttestdata := map[string]*Runner{\"Source\": r1}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\n\t\t\trequire.NoError(t, r.Setup(ctx, samples))\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestSetupDataReturnValue(t *testing.T) {\n\tt.Parallel()\n\ttestSetupDataHelper(t, `\n\texports.options = { setupTimeout: \"1s\", teardownTimeout: \"1s\" };\n\texports.setup = function() {\n\t\treturn 42;\n\t}\n\texports.default = function(data) {\n\t\tif (data != 42) {\n\t\t\tthrow new Error(\"default: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};\n\n\texports.teardown = function(data) {\n\t\tif (data != 42) {\n\t\t\tthrow new Error(\"teardown: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};`)\n}\n\nfunc TestSetupDataNoSetup(t *testing.T) {\n\tt.Parallel()\n\ttestSetupDataHelper(t, `\n\texports.options = { setupTimeout: \"1s\", teardownTimeout: \"1s\" };\n\texports.default = function(data) {\n\t\tif (data !== undefined) {\n\t\t\tthrow new Error(\"default: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};\n\n\texports.teardown = function(data) {\n\t\tif (data !== undefined) {\n\t\t\tconsole.log(data);\n\t\t\tthrow new Error(\"teardown: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};`)\n}\n\nfunc TestConsoleInInitContext(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\tconsole.log(\"1\");\n\t\t\texports.default = function(data) {\n\t\t\t};\n\t\t`)\n\trequire.NoError(t, err)\n\n\ttestdata := map[string]*Runner{\"Source\": r1}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t})\n\t}\n}\n\nfunc TestSetupDataNoReturn(t *testing.T) {\n\tt.Parallel()\n\ttestSetupDataHelper(t, `\n\texports.options = { setupTimeout: \"1s\", teardownTimeout: \"1s\" };\n\texports.setup = function() { }\n\texports.default = function(data) {\n\t\tif (data !== undefined) {\n\t\t\tthrow new Error(\"default: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};\n\n\texports.teardown = function(data) {\n\t\tif (data !== undefined) {\n\t\t\tthrow new Error(\"teardown: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};`)\n}\n\nfunc TestSetupDataPromise(t *testing.T) {\n\tt.Parallel()\n\ttestSetupDataHelper(t, `\n\texports.options = { setupTimeout: \"1s\", teardownTimeout: \"1s\" };\n\texports.setup = async function() {\n        return await Promise.resolve({\"data\": \"correct\"})\n    }\n\texports.default = function(data) {\n\t\tif (data.data !== \"correct\") {\n\t\t\tthrow new Error(\"default: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};\n\n\texports.teardown = function(data) {\n\t\tif (data.data !== \"correct\") {\n\t\t\tthrow new Error(\"teardown: wrong data: \" + JSON.stringify(data))\n\t\t}\n\t};`)\n}\n\nfunc TestRunnerIntegrationImports(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Modules\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tmodules := []string{\n\t\t\t\"k6\",\n\t\t\t\"k6/http\",\n\t\t\t\"k6/metrics\",\n\t\t\t\"k6/html\",\n\t\t}\n\t\trtOpts := lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"extended\")}\n\t\tfor _, mod := range modules {\n\t\t\tt.Run(mod, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tt.Run(\"Source\", func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\t_, err := getSimpleRunner(t, \"/script.js\",\n\t\t\t\t\t\tfmt.Sprintf(`import \"%s\"; export default function() {}`, mod), rtOpts)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"Files\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestdata := map[string]struct{ filename, path string }{\n\t\t\t\"Absolute\":       {\"/path/script.js\", \"/path/to/lib.js\"},\n\t\t\t\"Relative\":       {\"/path/script.js\", \"./to/lib.js\"},\n\t\t\t\"Adjacent\":       {\"/path/to/script.js\", \"./lib.js\"},\n\t\t\t\"STDIN-Absolute\": {\"/-\", \"/path/to/lib.js\"},\n\t\t\t\"STDIN-Relative\": {\"/-\", \"./path/to/lib.js\"},\n\t\t}\n\t\tfor name, data := range testdata {\n\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tfs := fsext.NewMemMapFs()\n\t\t\t\trequire.NoError(t, fs.MkdirAll(\"/path/to\", 0o755))\n\t\t\t\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/lib.js\", []byte(`exports.default = \"hi!\";`), 0o644))\n\t\t\t\tr1, err := getSimpleRunner(t, data.filename, fmt.Sprintf(`\n\t\t\t\t\tvar hi = require(\"%s\").default;\n\t\t\t\t\texports.default = function() {\n\t\t\t\t\t\tif (hi != \"hi!\") { throw new Error(\"incorrect value\"); }\n\t\t\t\t\t}`, data.path), fs)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\ttestdata := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\t\t\t\tfor name, r := range testdata {\n\t\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\t\tt.Parallel()\n\t\t\t\t\t\tctx := t.Context()\n\t\t\t\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\t\t\t\terr = vu.RunOnce()\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestVURunContext(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\texports.options = { vus: 10 };\n\t\texports.default = function() { fn(); }\n\t`)\n\trequire.NoError(t, err)\n\trequire.NoError(t, r1.SetOptions(r1.GetOptions().Apply(lib.Options{Throw: null.BoolFrom(true)})))\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\ttestdata := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\n\t\t\tvu, err := r.newVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfnCalled := false\n\t\t\trequire.NoError(t, vu.Runtime.Set(\"fn\", func() {\n\t\t\t\tfnCalled = true\n\n\t\t\t\trequire.NotNil(t, vu.moduleVUImpl.Runtime())\n\t\t\t\trequire.Nil(t, vu.moduleVUImpl.InitEnv())\n\n\t\t\t\tstate := vu.moduleVUImpl.State()\n\t\t\t\trequire.NotNil(t, state)\n\t\t\t\tassert.Equal(t, null.IntFrom(10), state.Options.VUs)\n\t\t\t\tassert.Equal(t, null.BoolFrom(true), state.Options.Throw)\n\t\t\t\tassert.NotNil(t, state.Logger)\n\t\t\t\tassert.Equal(t, vu.Transport, state.Transport)\n\t\t\t}))\n\n\t\t\tactiveVU := vu.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = activeVU.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.True(t, fnCalled, \"fn() not called\")\n\t\t})\n\t}\n}\n\nfunc TestVURunInterrupt(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\texports.default = function() { while(true) {} }\n\t\t`)\n\trequire.NoError(t, err)\n\trequire.NoError(t, r1.SetOptions(lib.Options{Throw: null.BoolFrom(true)}))\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\ttestdata := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsamples := newDevNullSampleChannel()\n\t\t\tdefer close(samples)\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond)\n\t\t\tdefer cancel()\n\n\t\t\tvu, err := r.newVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tactiveVU := vu.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = activeVU.RunOnce()\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"context canceled\")\n\t\t})\n\t}\n}\n\nfunc TestVURunInterruptDoesntPanic(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\texports.default = function() { while(true) {} }\n\t\t`)\n\trequire.NoError(t, err)\n\trequire.NoError(t, r1.SetOptions(lib.Options{Throw: null.BoolFrom(true)}))\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\ttestdata := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\t\tdefer cancel()\n\t\t\tsamples := newDevNullSampleChannel()\n\t\t\tdefer close(samples)\n\t\t\tvar wg sync.WaitGroup\n\n\t\t\tinitVU, err := r.newVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tfor range 100 {\n\t\t\t\twg.Add(1)\n\t\t\t\tnewCtx, newCancel := context.WithCancel(ctx)\n\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{\n\t\t\t\t\tRunContext:         newCtx,\n\t\t\t\t\tDeactivateCallback: func(_ lib.InitializedVU) { wg.Done() },\n\t\t\t\t})\n\t\t\t\tch := make(chan struct{})\n\t\t\t\tgo func() {\n\t\t\t\t\tclose(ch)\n\t\t\t\t\tvuErr := vu.RunOnce()\n\t\t\t\t\trequire.Error(t, vuErr)\n\t\t\t\t\tassert.Contains(t, vuErr.Error(), \"context canceled\")\n\t\t\t\t}()\n\t\t\t\t<-ch\n\t\t\t\ttime.Sleep(time.Microsecond * 1) // NOTE: increase this in case of problems ;)\n\t\t\t\tnewCancel()\n\t\t\t\twg.Wait()\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationMetrics(t *testing.T) {\n\tt.Parallel()\n\ttestdata := make(map[string]*Runner, 2)\n\t{\n\t\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\tvar group = require(\"k6\").group;\n\t\tvar Trend = require(\"k6/metrics\").Trend;\n\t\tvar myMetric = new Trend(\"my_metric\");\n\t\texports.default = function() { myMetric.add(5); }\n\t\t`)\n\t\trequire.NoError(t, err)\n\t\ttestdata[\"Source\"] = r1\n\n\t\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\t\trequire.NoError(t, err)\n\t\ttestdata[\"Archive\"] = r2\n\t}\n\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\tdefer close(samples)\n\n\t\t\tctx := t.Context()\n\n\t\t\tvu, err := r.newVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tactiveVU := vu.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = activeVU.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t\tsampleCount := 0\n\t\t\tbuiltinMetrics := r.preInitState.BuiltinMetrics\n\t\t\tfor _, sampleC := range metrics.GetBufferedSamples(samples) {\n\t\t\t\tfor _, s := range sampleC.GetSamples() {\n\t\t\t\t\tswitch sampleCount {\n\t\t\t\t\tcase 0:\n\t\t\t\t\t\tassert.Equal(t, 5.0, s.Value)\n\t\t\t\t\t\tassert.Equal(t, \"my_metric\", s.Metric.Name)\n\t\t\t\t\t\tassert.Equal(t, metrics.Trend, s.Metric.Type)\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tassert.Equal(t, 0.0, s.Value)\n\t\t\t\t\t\tassert.Same(t, builtinMetrics.DataSent, s.Metric, \"`data_sent` sample is before `data_received` and `iteration_duration`\")\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tassert.Equal(t, 0.0, s.Value)\n\t\t\t\t\t\tassert.Same(t, builtinMetrics.DataReceived, s.Metric, \"`data_received` sample is after `data_received`\")\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\tassert.Same(t, builtinMetrics.IterationDuration, s.Metric, \"`iteration-duration` sample is after `data_received`\")\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\tassert.Same(t, builtinMetrics.Iterations, s.Metric, \"`iterations` sample is after `iteration_duration`\")\n\t\t\t\t\t\tassert.Equal(t, float64(1), s.Value)\n\t\t\t\t\t}\n\t\t\t\t\tsampleCount++\n\t\t\t\t}\n\t\t\t}\n\t\t\tassert.Equal(t, sampleCount, 5)\n\t\t})\n\t}\n}\n\nfunc generateTLSCertificate(t *testing.T, host string, notBefore time.Time, validFor time.Duration) ([]byte, []byte) {\n\treturn generateTLSCertificateWithCA(t, host, notBefore, validFor, nil, nil)\n}\n\nfunc generateTLSCertificateWithCA(t *testing.T, host string, notBefore time.Time, validFor time.Duration, parent *x509.Certificate, ppriv *rsa.PrivateKey) ([]byte, []byte) {\n\tpriv, err := rsa.GenerateKey(rand.Reader, 2048)\n\trequire.NoError(t, err)\n\n\t// ECDSA, ED25519 and RSA subject keys should have the DigitalSignature\n\t// KeyUsage bits set in the x509.Certificate template\n\tkeyUsage := x509.KeyUsageDigitalSignature\n\t// Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In\n\t// the context of TLS this KeyUsage is particular to RSA key exchange and\n\t// authentication.\n\tkeyUsage |= x509.KeyUsageKeyEncipherment\n\n\tnotAfter := notBefore.Add(validFor)\n\n\tserialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)\n\tserialNumber, err := rand.Int(rand.Reader, serialNumberLimit)\n\trequire.NoError(t, err)\n\n\ttemplate := x509.Certificate{\n\t\tSerialNumber: serialNumber,\n\t\tSubject: pkix.Name{\n\t\t\tOrganization: []string{\"Acme Co\"},\n\t\t},\n\t\tNotBefore: notBefore,\n\t\tNotAfter:  notAfter,\n\n\t\tKeyUsage:              keyUsage,\n\t\tBasicConstraintsValid: true,\n\t\tSignatureAlgorithm:    x509.SHA256WithRSA,\n\t}\n\n\thosts := strings.SplitSeq(host, \",\")\n\tfor h := range hosts {\n\t\tif ip := net.ParseIP(h); ip != nil {\n\t\t\ttemplate.IPAddresses = append(template.IPAddresses, ip)\n\t\t} else {\n\t\t\ttemplate.DNSNames = append(template.DNSNames, h)\n\t\t}\n\t}\n\n\tif parent == nil {\n\t\ttemplate.IsCA = true\n\t\ttemplate.KeyUsage |= x509.KeyUsageCertSign\n\t\tparent = &template\n\t\tppriv = priv\n\t}\n\n\tderBytes, err := x509.CreateCertificate(rand.Reader, &template, parent, &priv.PublicKey, ppriv)\n\trequire.NoError(t, err)\n\n\tcertPem := pem.EncodeToMemory(&pem.Block{Type: \"CERTIFICATE\", Bytes: derBytes})\n\trequire.NoError(t, err)\n\n\tprivBytes, err := x509.MarshalPKCS8PrivateKey(priv)\n\trequire.NoError(t, err)\n\tkeyPem := pem.EncodeToMemory(&pem.Block{Type: \"PRIVATE KEY\", Bytes: privBytes})\n\trequire.NoError(t, err)\n\treturn certPem, keyPem\n}\n\nfunc getTestServerWithCertificate(t *testing.T, certPem, key []byte) *httptest.Server {\n\tserver := &http.Server{\n\t\tHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t}),\n\t\tReadHeaderTimeout: time.Second,\n\t\tReadTimeout:       time.Second,\n\t}\n\ts := &httptest.Server{}\n\ts.Config = server\n\n\ts.TLS = new(tls.Config)\n\tif s.TLS.NextProtos == nil {\n\t\tnextProtos := []string{\"http/1.1\"}\n\t\tif s.EnableHTTP2 {\n\t\t\tnextProtos = []string{\"h2\"}\n\t\t}\n\t\ts.TLS.NextProtos = nextProtos\n\t}\n\tcert, err := tls.X509KeyPair(certPem, key)\n\trequire.NoError(t, err)\n\ts.TLS.Certificates = append(s.TLS.Certificates, cert)\n\tfor _, suite := range tls.CipherSuites() {\n\t\tif !strings.Contains(suite.Name, \"256\") {\n\t\t\tcontinue\n\t\t}\n\t\ts.TLS.CipherSuites = append(s.TLS.CipherSuites, suite.ID)\n\t}\n\tcertpool := x509.NewCertPool()\n\tcertificate, err := x509.ParseCertificate(cert.Certificate[0])\n\trequire.NoError(t, err)\n\tcertpool.AddCert(certificate)\n\tclient := &http.Client{Transport: &http.Transport{}}\n\tclient.Transport = &http.Transport{\n\t\tTLSClientConfig: &tls.Config{\n\t\t\tRootCAs: certpool,\n\t\t},\n\t\tForceAttemptHTTP2: s.EnableHTTP2,\n\t}\n\ts.Listener, err = (&net.ListenConfig{}).Listen(context.Background(), \"tcp\", \"\")\n\trequire.NoError(t, err)\n\ts.Listener = tls.NewListener(s.Listener, s.TLS)\n\ts.URL = \"https://\" + s.Listener.Addr().String()\n\treturn s\n}\n\nfunc TestVUIntegrationInsecureRequests(t *testing.T) {\n\tt.Parallel()\n\tcertPem, keyPem := generateTLSCertificate(t, \"mybadssl.localhost\", time.Now(), 0)\n\ts := getTestServerWithCertificate(t, certPem, keyPem)\n\tgo func() {\n\t\t_ = s.Config.Serve(s.Listener)\n\t}()\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, s.Config.Close())\n\t})\n\thost, port, err := net.SplitHostPort(s.Listener.Addr().String())\n\trequire.NoError(t, err)\n\tip := net.ParseIP(host)\n\tmybadsslHostname, err := types.NewHost(ip, port)\n\trequire.NoError(t, err)\n\tcert, err := x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0])\n\trequire.NoError(t, err)\n\n\ttestdata := map[string]struct {\n\t\topts   lib.Options\n\t\terrMsg string\n\t}{\n\t\t\"Null\": {\n\t\t\tlib.Options{},\n\t\t\t\"x509: certificate has expired or is not yet valid\",\n\t\t},\n\t\t\"False\": {\n\t\t\tlib.Options{InsecureSkipTLSVerify: null.BoolFrom(false)},\n\t\t\t\"x509: certificate has expired or is not yet valid\",\n\t\t},\n\t\t\"True\": {\n\t\t\tlib.Options{InsecureSkipTLSVerify: null.BoolFrom(true)},\n\t\t\t\"\",\n\t\t},\n\t}\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\t  var http = require(\"k6/http\");;\n        exports.default = function() { http.get(\"https://mybadssl.localhost/\"); }\n\t\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, r1.SetOptions(lib.Options{Throw: null.BoolFrom(true)}.Apply(data.opts)))\n\n\t\t\tr1.Bundle.Options.Hosts, err = types.NewNullHosts(map[string]types.Host{\n\t\t\t\t\"mybadssl.localhost\": *mybadsslHostname,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\t\t\trequire.NoError(t, err)\n\t\t\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\t\t\tfor name, r := range runners {\n\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tr.preInitState.Logger, _ = logtest.NewNullLogger()\n\n\t\t\t\t\tctx := t.Context()\n\t\t\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tinitVU.(*VU).TLSConfig.RootCAs = x509.NewCertPool()\n\t\t\t\t\tinitVU.(*VU).TLSConfig.RootCAs.AddCert(cert)\n\n\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\t\t\terr = vu.RunOnce()\n\t\t\t\t\tif data.errMsg != \"\" {\n\t\t\t\t\t\trequire.Error(t, err)\n\t\t\t\t\t\tassert.Contains(t, err.Error(), data.errMsg)\n\t\t\t\t\t} else {\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationBlacklistOption(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\t\t\tvar http = require(\"k6/http\");;\n\t\t\t\t\texports.default = function() { http.get(\"http://10.1.2.3/\"); }\n\t\t\t\t`)\n\trequire.NoError(t, err)\n\n\tcidr, err := lib.ParseCIDR(\"10.0.0.0/8\")\n\trequire.NoError(t, err)\n\tr1.Bundle.Options.Throw = null.BoolFrom(true)\n\tr1.Bundle.Options.BlacklistIPs = []*lib.IPNet{cidr}\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"IP (10.1.2.3) is in a blacklisted range (10.0.0.0/8)\")\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationBlacklistScript(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\t\t\tvar http = require(\"k6/http\");;\n\n\t\t\t\t\texports.options = {\n\t\t\t\t\t\tthrow: true,\n\t\t\t\t\t\tblacklistIPs: [\"10.0.0.0/8\"],\n\t\t\t\t\t};\n\n\t\t\t\t\texports.default = function() { http.get(\"http://10.1.2.3/\"); }\n\t\t\t\t`)\n\trequire.NoError(t, err)\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"IP (10.1.2.3) is in a blacklisted range (10.0.0.0/8)\")\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationBlockHostnamesOption(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\t\t\tvar http = require(\"k6/http\");\n\t\t\t\t\texports.default = function() { http.get(\"https://k6.io/\"); }\n\t\t\t\t`)\n\trequire.NoError(t, err)\n\n\thostnames, err := types.NewNullHostnameTrie([]string{\"*.io\"})\n\trequire.NoError(t, err)\n\n\tr1.Bundle.Options.Throw = null.BoolFrom(true)\n\tr1.Bundle.Options.BlockedHostnames = hostnames\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\n\t\t\tinitVu, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvu := initVu.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"hostname (k6.io) is in a blocked pattern (*.io)\")\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationBlockHostnamesScript(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\t\t\tvar http = require(\"k6/http\");\n\n\t\t\t\t\texports.options = {\n\t\t\t\t\t\tthrow: true,\n\t\t\t\t\t\tblockHostnames: [\"*.io\"],\n\t\t\t\t\t};\n\n\t\t\t\t\texports.default = function() { http.get(\"https://k6.io/\"); }\n\t\t\t\t`)\n\trequire.NoError(t, err)\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\t\t\tinitVu, err := r.NewVU(ctx, 0, 0, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVu.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"hostname (k6.io) is in a blocked pattern (*.io)\")\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationHosts(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tr1, err := getSimpleRunner(t, \"/script.js\",\n\t\ttb.Replacer.Replace(`\n\t\t\t\t\tvar k6 = require(\"k6\");\n\t\t\t\t\tvar check = k6.check;\n\t\t\t\t\tvar fail = k6.fail;\n\t\t\t\t\tvar http = require(\"k6/http\");;\n\t\t\t\t\texports.default = function() {\n\t\t\t\t\t\tvar res = http.get(\"http://test.loadimpact.com:HTTPBIN_PORT/\");\n\t\t\t\t\t\tcheck(res, {\n\t\t\t\t\t\t\t\"is correct IP\": function(r) { return r.remote_ip === \"127.0.0.1\" }\n\t\t\t\t\t\t}) || fail(\"failed to override dns\");\n\t\t\t\t\t}\n\t\t\t\t`))\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, r1.SetOptions(lib.Options{\n\t\tThrow: null.BoolFrom(true),\n\t\tHosts: func() types.NullHosts {\n\t\t\thosts, er := types.NewNullHosts(map[string]types.Host{\n\t\t\t\t\"test.loadimpact.com\": {IP: net.ParseIP(\"127.0.0.1\")},\n\t\t\t})\n\t\t\trequire.NoError(t, er)\n\n\t\t\treturn hosts\n\t\t}(),\n\t}))\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationTLSConfig(t *testing.T) {\n\tt.Parallel()\n\tcertPem, keyPem := generateTLSCertificate(t, \"sha256-badssl.localhost\", time.Now(), time.Hour)\n\ts := getTestServerWithCertificate(t, certPem, keyPem)\n\tgo func() {\n\t\t_ = s.Config.Serve(s.Listener)\n\t}()\n\tt.Cleanup(func() {\n\t\trequire.NoError(t, s.Config.Close())\n\t})\n\thost, port, err := net.SplitHostPort(s.Listener.Addr().String())\n\trequire.NoError(t, err)\n\tip := net.ParseIP(host)\n\tmybadsslHostname, err := types.NewHost(ip, port)\n\trequire.NoError(t, err)\n\tunsupportedVersionErrorMsg := \"tls: no supported versions satisfy MinVersion and MaxVersion\"\n\ttestdata := map[string]struct {\n\t\topts   lib.Options\n\t\terrMsg string\n\t}{\n\t\t\"NullCipherSuites\": {\n\t\t\tlib.Options{},\n\t\t\t\"\",\n\t\t},\n\t\t\"SupportedCipherSuite\": {\n\t\t\tlib.Options{TLSCipherSuites: &lib.TLSCipherSuites{tls.TLS_RSA_WITH_AES_128_GCM_SHA256}},\n\t\t\t\"\",\n\t\t},\n\t\t\"UnsupportedCipherSuite\": {\n\t\t\tlib.Options{\n\t\t\t\tTLSCipherSuites: &lib.TLSCipherSuites{tls.TLS_RSA_WITH_RC4_128_SHA},\n\t\t\t\tTLSVersion:      &lib.TLSVersions{Max: tls.VersionTLS12},\n\t\t\t},\n\t\t\t\"remote error: tls: handshake failure\",\n\t\t},\n\t\t\"NullVersion\": {\n\t\t\tlib.Options{},\n\t\t\t\"\",\n\t\t},\n\t\t\"SupportedVersion\": {\n\t\t\tlib.Options{TLSVersion: &lib.TLSVersions{Min: tls.VersionTLS12, Max: tls.VersionTLS12}},\n\t\t\t\"\",\n\t\t},\n\t\t\"UnsupportedVersion\": {\n\t\t\tlib.Options{TLSVersion: &lib.TLSVersions{Min: tls.VersionSSL30, Max: tls.VersionSSL30}}, //nolint:staticcheck\n\t\t\tunsupportedVersionErrorMsg,\n\t\t},\n\t}\n\tcert, err := x509.ParseCertificate(s.TLS.Certificates[0].Certificate[0])\n\trequire.NoError(t, err)\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\t\t\tvar http = require(\"k6/http\");;\n\t\t\t\t\texports.default = function() { http.get(\"https://sha256-badssl.localhost/\"); }\n\t\t\t\t`)\n\t\t\trequire.NoError(t, err)\n\n\t\t\topts := lib.Options{Throw: null.BoolFrom(true)}\n\t\t\trequire.NoError(t, r1.SetOptions(opts.Apply(data.opts)))\n\n\t\t\tr1.Bundle.Options.Hosts, err = types.NewNullHosts(map[string]types.Host{\n\t\t\t\t\"sha256-badssl.localhost\": *mybadsslHostname,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\t\t\trequire.NoError(t, err)\n\n\t\t\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\t\t\tfor name, r := range runners {\n\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tr.preInitState.Logger, _ = logtest.NewNullLogger()\n\n\t\t\t\t\tctx := t.Context()\n\t\t\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tinitVU.(*VU).TLSConfig.RootCAs = x509.NewCertPool()\n\t\t\t\t\tinitVU.(*VU).TLSConfig.RootCAs.AddCert(cert)\n\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\t\t\terr = vu.RunOnce()\n\t\t\t\t\tif data.errMsg != \"\" {\n\t\t\t\t\t\trequire.Error(t, err, \"for message %q\", data.errMsg)\n\t\t\t\t\t\tassert.Contains(t, err.Error(), data.errMsg)\n\t\t\t\t\t} else {\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationRequireFunctionError(t *testing.T) {\n\tt.Parallel()\n\tr, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\texports.default = function() { require(\"k6/http\") }\n\t\t`)\n\trequire.NoError(t, err)\n\n\tctx := t.Context()\n\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\terr = vu.RunOnce()\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"only available in the init stage\")\n}\n\nfunc TestVUIntegrationOpenFunctionError(t *testing.T) {\n\tt.Parallel()\n\tr, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\texports.default = function() { open(\"/tmp/foo\") }\n\t\t`)\n\trequire.NoError(t, err)\n\n\tctx := t.Context()\n\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\terr = vu.RunOnce()\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"only available in the init stage\")\n}\n\nfunc TestVUIntegrationOpenFunctionErrorWhenSneaky(t *testing.T) {\n\tt.Parallel()\n\tr, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\tvar sneaky = open;\n\t\t\texports.default = function() { sneaky(\"/tmp/foo\") }\n\t\t`)\n\trequire.NoError(t, err)\n\n\tctx := t.Context()\n\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\terr = vu.RunOnce()\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"only available in the init stage\")\n}\n\nfunc TestVUDoesOpenUnderV0Condition(t *testing.T) {\n\tt.Parallel()\n\n\tbaseFS := fsext.NewMemMapFs()\n\tdata := `\n\t\t\tif (__VU == 0) {\n\t\t\t\tlet data = open(\"/home/somebody/test.json\");\n\t\t\t}\n\t\t\texports.default = function() {\n\t\t\t\tconsole.log(\"hey\")\n\t\t\t}\n\t\t`\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/home/somebody/test.json\", []byte(`42`), fs.ModePerm))\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/script.js\", []byte(data), fs.ModePerm))\n\n\tfs := fsext.NewCacheOnReadFs(baseFS, fsext.NewMemMapFs(), 0)\n\n\tr, err := getSimpleRunner(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\t_, err = r.NewVU(context.Background(), 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n}\n\nfunc TestVUDoesNotOpenUnderConditions(t *testing.T) {\n\tt.Parallel()\n\n\tbaseFS := fsext.NewMemMapFs()\n\tdata := `\n\t\t\tif (__VU > 0) {\n\t\t\t\tlet data = open(\"/home/somebody/test.json\");\n\t\t\t}\n\t\t\texports.default = function() {\n\t\t\t\tconsole.log(\"hey\")\n\t\t\t}\n\t\t`\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/home/somebody/test.json\", []byte(`42`), fs.ModePerm))\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/script.js\", []byte(data), fs.ModePerm))\n\n\tfs := fsext.NewCacheOnReadFs(baseFS, fsext.NewMemMapFs(), 0)\n\n\tr, err := getSimpleRunner(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\t_, err = r.NewVU(context.Background(), 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"open() can't be used with files that weren't previously opened during initialization (__VU==0)\")\n}\n\nfunc TestVUDoesNonExistingPathnUnderConditions(t *testing.T) {\n\tt.Parallel()\n\n\tbaseFS := fsext.NewMemMapFs()\n\tdata := `\n\t\t\tif (__VU == 1) {\n\t\t\t\tlet data = open(\"/home/nobody\");\n\t\t\t}\n\t\t\texports.default = function() {\n\t\t\t\tconsole.log(\"hey\")\n\t\t\t}\n\t\t`\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/script.js\", []byte(data), fs.ModePerm))\n\n\tfs := fsext.NewCacheOnReadFs(baseFS, fsext.NewMemMapFs(), 0)\n\n\tr, err := getSimpleRunner(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\t_, err = r.NewVU(context.Background(), 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"open() can't be used with files that weren't previously opened during initialization (__VU==0)\")\n}\n\nfunc TestVUDoesRequireUnderV0Condition(t *testing.T) {\n\tt.Parallel()\n\n\tbaseFS := fsext.NewMemMapFs()\n\tdata := `\n\t\t\tif (__VU == 0) {\n\t\t\t\tlet data = require(\"/home/somebody/test.js\");\n\t\t\t}\n\t\t\texports.default = function() {\n\t\t\t\tconsole.log(\"hey\")\n\t\t\t}\n\t\t`\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/home/somebody/test.js\", []byte(`exports=42`), fs.ModePerm))\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/script.js\", []byte(data), fs.ModePerm))\n\n\tfs := fsext.NewCacheOnReadFs(baseFS, fsext.NewMemMapFs(), 0)\n\n\tr, err := getSimpleRunner(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\t_, err = r.NewVU(context.Background(), 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n}\n\nfunc TestVUDoesNotRequireUnderConditions(t *testing.T) {\n\tt.Parallel()\n\n\tbaseFS := fsext.NewMemMapFs()\n\tdata := `\n\t\t\tif (__VU > 0) {\n\t\t\t\tlet data = require(\"/home/somebody/test.js\");\n\t\t\t}\n\t\t\texports.default = function() {\n\t\t\t\tconsole.log(\"hey\")\n\t\t\t}\n\t\t`\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/home/somebody/test.js\", []byte(`exports=42`), fs.ModePerm))\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/script.js\", []byte(data), fs.ModePerm))\n\n\tfs := fsext.NewCacheOnReadFs(baseFS, fsext.NewMemMapFs(), 0)\n\n\tr, err := getSimpleRunner(t, \"/script.js\", data, fs)\n\trequire.NoError(t, err)\n\n\t_, err = r.NewVU(context.Background(), 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \" was not previously resolved during initialization (__VU==0)\")\n}\n\nfunc TestVUDoesRequireUnderConditions(t *testing.T) {\n\tt.Parallel()\n\n\tbaseFS := fsext.NewMemMapFs()\n\tdata := `\n\t\t\tif (__VU == 0) {\n\t\t\t\trequire(\"/home/somebody/test.js\");\n\t\t\t\trequire(\"/home/somebody/test2.js\");\n\t\t\t}\n\n\t\t\tif (__VU % 2 == 1) {\n\t\t\t\trequire(\"/home/somebody/test.js\");\n\t\t\t}\n\n\t\t\tif (__VU % 2 == 0) {\n\t\t\t\trequire(\"/home/somebody/test2.js\");\n\t\t\t}\n\n\t\t\texports.default = function() {\n\t\t\t\tconsole.log(\"hey\")\n\t\t\t}\n\t\t`\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/home/somebody/test.js\", []byte(`console.log(\"test.js\", __VU)`), fs.ModePerm))\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/home/somebody/test2.js\", []byte(`console.log(\"test2.js\", __VU)`), fs.ModePerm))\n\trequire.NoError(t, fsext.WriteFile(baseFS, \"/script.js\", []byte(data), fs.ModePerm))\n\n\tfs := fsext.NewCacheOnReadFs(baseFS, fsext.NewMemMapFs(), 0)\n\n\tlogger, hook := testutils.NewLoggerWithHook(t, logrus.InfoLevel)\n\tr, err := getSimpleRunner(t, \"/script.js\", data, fs, logger)\n\trequire.NoError(t, err)\n\tlogs := hook.Drain()\n\trequire.Len(t, logs, 2)\n\n\t_, err = r.NewVU(context.Background(), 1, 1, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n\tlogs = hook.Drain()\n\trequire.Len(t, logs, 1)\n\trequire.Contains(t, logs[0].Message, \"test.js 1\")\n\t_, err = r.NewVU(context.Background(), 2, 2, make(chan metrics.SampleContainer, 100))\n\trequire.NoError(t, err)\n\tlogs = hook.Drain()\n\trequire.Len(t, logs, 1)\n\trequire.Contains(t, logs[0].Message, \"test2.js 2\")\n}\n\nfunc TestVUIntegrationCookiesReset(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tr1, err := getSimpleRunner(t, \"/script.js\", tb.Replacer.Replace(`\n\t\t\tvar http = require(\"k6/http\");;\n\t\t\texports.default = function() {\n\t\t\t\tvar url = \"HTTPBIN_URL\";\n\t\t\t\tvar preRes = http.get(url + \"/cookies\");\n\t\t\t\tif (preRes.status != 200) { throw new Error(\"wrong status (pre): \" + preRes.status); }\n\t\t\t\tif (preRes.json().k1 || preRes.json().k2) {\n\t\t\t\t\tthrow new Error(\"cookies persisted: \" + preRes.body);\n\t\t\t\t}\n\n\t\t\t\tvar res = http.get(url + \"/cookies/set?k2=v2&k1=v1\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\t\tif (res.json().k1 != \"v1\" || res.json().k2 != \"v2\") {\n\t\t\t\t\tthrow new Error(\"wrong cookies: \" + res.body);\n\t\t\t\t}\n\t\t\t}\n\t\t`))\n\trequire.NoError(t, err)\n\tr1.Bundle.Options.Throw = null.BoolFrom(true)\n\tr1.Bundle.Options.MaxRedirects = null.IntFrom(10)\n\tr1.Bundle.Options.Hosts = types.NullHosts{Trie: tb.Dialer.Hosts}\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\tfor range 2 {\n\t\t\t\trequire.NoError(t, vu.RunOnce())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationCookiesNoReset(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tr1, err := getSimpleRunner(t, \"/script.js\", tb.Replacer.Replace(`\n\t\t\tvar http = require(\"k6/http\");;\n\t\t\texports.default = function() {\n\t\t\t\tvar url = \"HTTPBIN_URL\";\n\t\t\t\tif (__ITER == 0) {\n\t\t\t\t\tvar res = http.get(url + \"/cookies/set?k2=v2&k1=v1\");\n\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\t\t\tif (res.json().k1 != \"v1\" || res.json().k2 != \"v2\") {\n\t\t\t\t\t\tthrow new Error(\"wrong cookies: \" + res.body);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (__ITER == 1) {\n\t\t\t\t\tvar res = http.get(url + \"/cookies\");\n\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status (pre): \" + res.status); }\n\t\t\t\t\tif (res.json().k1 != \"v1\" || res.json().k2 != \"v2\") {\n\t\t\t\t\t\tthrow new Error(\"wrong cookies: \" + res.body);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t`))\n\trequire.NoError(t, err)\n\trequire.NoError(t, r1.SetOptions(lib.Options{\n\t\tThrow:          null.BoolFrom(true),\n\t\tMaxRedirects:   null.IntFrom(10),\n\t\tHosts:          types.NullHosts{Trie: tb.Dialer.Hosts},\n\t\tNoCookiesReset: null.BoolFrom(true),\n\t}))\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationVUID(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\texports.default = function() {\n\t\t\t\tif (__VU != 1234) { throw new Error(\"wrong __VU: \" + __VU); }\n\t\t\t}`,\n\t)\n\trequire.NoError(t, err)\n\tr1.Bundle.Options.Throw = null.BoolFrom(true)\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\n\t\t\tinitVU, err := r.NewVU(ctx, 1234, 1234, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestVUIntegrationClientCerts(t *testing.T) {\n\tt.Parallel()\n\n\t// Generate CA key and certificate\n\tcaCertPem, caKeyPem := generateTLSCertificate(t, \"127.0.0.1\", time.Now(), time.Hour)\n\n\tcaCertBlock, _ := pem.Decode(caCertPem)\n\tcaCert, err := x509.ParseCertificate(caCertBlock.Bytes)\n\trequire.NoError(t, err)\n\n\tcaKeyBlock, _ := pem.Decode(caKeyPem)\n\tcaKeyAny, err := x509.ParsePKCS8PrivateKey(caKeyBlock.Bytes)\n\trequire.NoError(t, err)\n\tcaKey, ok := caKeyAny.(*rsa.PrivateKey)\n\trequire.True(t, ok)\n\n\t// Generate server key and certificate\n\tsrvCertPem, srvKeyPem := generateTLSCertificateWithCA(t, \"127.0.0.1\", time.Now(), time.Hour, caCert, caKey)\n\n\t// Generate client Key and Certificate\n\tclCertPem, clKeyPem := generateTLSCertificateWithCA(t, \"127.0.0.1\", time.Now(), time.Hour, caCert, caKey)\n\n\tclientCAPool := x509.NewCertPool()\n\tassert.True(t, clientCAPool.AppendCertsFromPEM(caCertPem))\n\n\tserverCert, err := tls.X509KeyPair(append(srvCertPem, caCertPem...), srvKeyPem)\n\trequire.NoError(t, err)\n\n\ttestdata := map[string]struct {\n\t\twithClientCert     bool\n\t\twithDomains        bool\n\t\tinsecureSkipVerify bool\n\t\terrMsg             string\n\t}{\n\t\t\"WithoutCert\":      {false, false, true, \"remote error: tls:\"},\n\t\t\"WithCert\":         {true, true, true, \"\"},\n\t\t\"VerifyServerCert\": {true, false, false, \"certificate signed by unknown authority\"},\n\t\t\"WithoutDomains\":   {true, false, true, \"\"},\n\t}\n\n\tlistener, err := tls.Listen(\"tcp\", \"127.0.0.1:0\", &tls.Config{\n\t\tCertificates: []tls.Certificate{serverCert},\n\t\tClientAuth:   tls.RequireAndVerifyClientCert,\n\t\tClientCAs:    clientCAPool,\n\t})\n\trequire.NoError(t, err)\n\tsrv := &http.Server{\n\t\tHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t_, _ = fmt.Fprintf(w, \"ok\")\n\t\t}),\n\t\tErrorLog: stdlog.New(io.Discard, \"\", 0),\n\t}\n\tgo func() { _ = srv.Serve(listener) }()\n\tt.Cleanup(func() { _ = listener.Close() })\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr1, err := getSimpleRunner(t, \"/script.js\", fmt.Sprintf(`\n\t\t\tvar http = require(\"k6/http\");\n\t\t\tvar k6 = require(\"k6\");\n\t\t\tvar check = k6.check;\n\t\t\texports.default = function() {\n\t\t\t\tconst res = http.get(\"https://%s\")\n\t\t\t\tcheck(res, {\n\t\t\t\t\t'is status 200': (r) => r.status === 200,\n\t\t\t\t\t'verify resp': (r) => r.body.includes('ok'),\n\t\t\t\t})\n\t\t\t}`, listener.Addr().String()))\n\t\t\trequire.NoError(t, err)\n\n\t\t\topt := lib.Options{Throw: null.BoolFrom(true)}\n\t\t\tif data.insecureSkipVerify {\n\t\t\t\topt.InsecureSkipTLSVerify = null.BoolFrom(true)\n\t\t\t}\n\t\t\tif data.withClientCert {\n\t\t\t\topt.TLSAuth = []*lib.TLSAuth{\n\t\t\t\t\t{\n\t\t\t\t\t\tTLSAuthFields: lib.TLSAuthFields{\n\t\t\t\t\t\t\tCert: string(clCertPem),\n\t\t\t\t\t\t\tKey:  string(clKeyPem),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tif data.withDomains {\n\t\t\t\t\topt.TLSAuth[0].Domains = []string{\"127.0.0.1\"}\n\t\t\t\t}\n\t\t\t\t_, _ = opt.TLSAuth[0].Certificate()\n\t\t\t}\n\t\t\trequire.NoError(t, r1.SetOptions(opt))\n\t\t\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\t\t\trequire.NoError(t, err)\n\n\t\t\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\t\t\tfor name, r := range runners {\n\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tr.preInitState.Logger, _ = logtest.NewNullLogger()\n\t\t\t\t\tctx := t.Context()\n\t\t\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\t\t\terr = vu.RunOnce()\n\t\t\t\t\tif len(data.errMsg) > 0 {\n\t\t\t\t\t\trequire.Error(t, err)\n\t\t\t\t\t\tassert.ErrorContains(t, err, data.errMsg)\n\t\t\t\t\t} else {\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestHTTPRequestInInitContext(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\t_, err := getSimpleRunner(t, \"/script.js\", tb.Replacer.Replace(`\n\t\t\t\t\tvar k6 = require(\"k6\");\n\t\t\t\t\tvar check = k6.check;\n\t\t\t\t\tvar fail = k6.fail;\n\t\t\t\t\tvar http = require(\"k6/http\");;\n\t\t\t\t\tvar res = http.get(\"HTTPBIN_URL/\");\n\t\t\t\t\texports.default = function() {\n\t\t\t\t\t\tconsole.log(test);\n\t\t\t\t\t}\n\t\t\t\t`))\n\trequire.Error(t, err)\n\tassert.Contains(\n\t\tt,\n\t\terr.Error(),\n\t\tk6http.ErrHTTPForbiddenInInitContext.Error())\n}\n\nfunc TestInitContextForbidden(t *testing.T) {\n\tt.Parallel()\n\ttable := [...][3]string{\n\t\t{\n\t\t\t\"http.request\",\n\t\t\t`var http = require(\"k6/http\");;\n\t\t\t var res = http.get(\"HTTPBIN_URL\");\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\tk6http.ErrHTTPForbiddenInInitContext.Error(),\n\t\t},\n\t\t{\n\t\t\t\"http.batch\",\n\t\t\t`var http = require(\"k6/http\");;\n\t\t\t var res = http.batch(\"HTTPBIN_URL/something\", \"HTTPBIN_URL/else\");\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\tk6http.ErrBatchForbiddenInInitContext.Error(),\n\t\t},\n\t\t{\n\t\t\t\"http.cookieJar\",\n\t\t\t`var http = require(\"k6/http\");;\n\t\t\t var jar = http.cookieJar();\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\tk6http.ErrJarForbiddenInInitContext.Error(),\n\t\t},\n\t\t{\n\t\t\t\"check\",\n\t\t\t`var check = require(\"k6\").check;\n\t\t\t check(\"test\", {'is test': function(test) { return test == \"test\"}})\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\tk6.ErrCheckInInitContext.Error(),\n\t\t},\n\t\t{\n\t\t\t\"abortTest\",\n\t\t\t`var test = require(\"k6/execution\").test;\n\t\t\t test.abort();\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\terrext.AbortTest,\n\t\t},\n\t\t{\n\t\t\t\"group\",\n\t\t\t`var group = require(\"k6\").group;\n\t\t\t group(\"group1\", function () { console.log(\"group1\");})\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\tk6.ErrGroupInInitContext.Error(),\n\t\t},\n\t\t{\n\t\t\t\"ws\",\n\t\t\t`var ws = require(\"k6/ws\");\n\t\t\t var url = \"ws://echo.websocket.org\";\n\t\t\t var params = { \"tags\": { \"my_tag\": \"hello\" } };\n\t\t\t var response = ws.connect(url, params, function (socket) {\n\t\t\t   socket.on('open', function open() {\n\t\t\t\t\tconsole.log('connected');\n\t\t\t   })\n\t\t   });\n\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\tws.ErrWSInInitContext.Error(),\n\t\t},\n\t\t{\n\t\t\t\"metric\",\n\t\t\t`var Counter = require(\"k6/metrics\").Counter;\n\t\t\t var counter = Counter(\"myCounter\");\n\t\t\t counter.add(1);\n\t\t\t exports.default = function() { console.log(\"p\"); }`,\n\t\t\tk6metrics.ErrMetricsAddInInitContext.Error(),\n\t\t},\n\t}\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tfor _, test := range table {\n\t\tt.Run(test[0], func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := getSimpleRunner(t, \"/script.js\", tb.Replacer.Replace(test[1]))\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(\n\t\t\t\tt,\n\t\t\t\terr.Error(),\n\t\t\t\ttest[2])\n\t\t})\n\t}\n}\n\nfunc TestArchiveRunningIntegrity(t *testing.T) {\n\tt.Parallel()\n\n\tfileSystem := fsext.NewMemMapFs()\n\tdata := `\n\t\t\tvar fput = open(\"/home/somebody/test.json\");\n\t\t\texports.options = { setupTimeout: \"10s\", teardownTimeout: \"10s\" };\n\t\t\texports.setup = function () {\n\t\t\t\treturn JSON.parse(fput);\n\t\t\t}\n\t\t\texports.default = function(data) {\n\t\t\t\tif (data != 42) {\n\t\t\t\t\tthrow new Error(\"incorrect answer \" + data);\n\t\t\t\t}\n\t\t\t}\n\t\t`\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/home/somebody/test.json\", []byte(`42`), fs.ModePerm))\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/script.js\", []byte(data), fs.ModePerm))\n\tr1, err := getSimpleRunner(t, \"/script.js\", data, fileSystem)\n\trequire.NoError(t, err)\n\n\tbuf := bytes.NewBuffer(nil)\n\trequire.NoError(t, r1.MakeArchive().Write(buf))\n\n\tarc, err := lib.ReadArchive(buf)\n\trequire.NoError(t, err)\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar err error\n\t\t\tch := make(chan metrics.SampleContainer, 100)\n\t\t\tctx, cancel := context.WithCancel(context.Background())\n\t\t\tdefer cancel()\n\t\t\terr = r.Setup(ctx, ch)\n\t\t\tcancel()\n\t\t\trequire.NoError(t, err)\n\t\t\tctx, cancel = context.WithCancel(context.Background())\n\t\t\tdefer cancel()\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\t\t\trequire.NoError(t, err)\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestArchiveNotPanicking(t *testing.T) {\n\tt.Parallel()\n\tfileSystem := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fileSystem, \"/non/existent\", []byte(`42`), fs.ModePerm))\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\tvar fput = open(\"/non/existent\");\n\t\t\texports.default = function(data) {}\n\t\t`, fileSystem)\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tarc.Filesystems = map[string]fsext.Fs{\"file\": fsext.NewMemMapFs()}\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\t// we do want this to error here as this is where we find out that a given file is not in the\n\t// archive\n\trequire.Error(t, err)\n\trequire.Nil(t, r2)\n}\n\nfunc TestStuffNotPanicking(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tr, err := getSimpleRunner(t, \"/script.js\", tb.Replacer.Replace(`\n\t\t\tvar http = require(\"k6/http\");\n\t\t\tvar ws = require(\"k6/ws\");\n\t\t\tvar group = require(\"k6\").group;\n\t\t\tvar parseHTML = require(\"k6/html\").parseHTML;\n\n\t\t\texports.options = { iterations: 1, vus: 1 };\n\n\t\t\texports.default = function() {\n\t\t\t\tvar doc = parseHTML(http.get(\"HTTPBIN_URL/html\").body);\n\n\t\t\t\tvar testCases = [\n\t\t\t\t\tfunction() { return group()},\n\t\t\t\t\tfunction() { return group(\"test\")},\n\t\t\t\t\tfunction() { return group(\"test\", \"wat\")},\n\t\t\t\t\tfunction() { return doc.find('p').each()},\n\t\t\t\t\tfunction() { return doc.find('p').each(\"wat\")},\n\t\t\t\t\tfunction() { return doc.find('p').map()},\n\t\t\t\t\tfunction() { return doc.find('p').map(\"wat\")},\n\t\t\t\t\tfunction() { return ws.connect(\"WSBIN_URL/ws-echo\")},\n\t\t\t\t];\n\n\t\t\t\ttestCases.forEach(function(fn, idx) {\n\t\t\t\t\tvar hasException;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfn();\n\t\t\t\t\t\thasException = false;\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\thasException = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (hasException === false) {\n\t\t\t\t\t\tthrow new Error(\"Expected test case #\" + idx + \" to return an error\");\n\t\t\t\t\t} else if (hasException === undefined) {\n\t\t\t\t\t\tthrow new Error(\"Something strange happened with test case #\" + idx);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t`))\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\n\tch := make(chan metrics.SampleContainer, 1000)\n\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\trequire.NoError(t, err)\n\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\terrC := make(chan error)\n\tgo func() { errC <- vu.RunOnce() }()\n\n\tselect {\n\tcase <-time.After(15 * time.Second):\n\t\tcancel()\n\t\tt.Fatal(\"Test timed out\")\n\tcase err := <-errC:\n\t\tcancel()\n\t\trequire.NoError(t, err)\n\t}\n}\n\nfunc TestPanicOnSimpleHTML(t *testing.T) {\n\tt.Parallel()\n\n\tr, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\tvar parseHTML = require(\"k6/html\").parseHTML;\n\n\t\t\texports.options = { iterations: 1, vus: 1 };\n\n\t\t\texports.default = function() {\n\t\t\t\tvar doc = parseHTML(\"<html>\");\n\t\t\t\tvar o = doc.find(\".something\").slice(0, 4).toArray()\n\t\t\t};\n\t\t`)\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\n\tch := make(chan metrics.SampleContainer, 1000)\n\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\trequire.NoError(t, err)\n\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\terrC := make(chan error)\n\tgo func() { errC <- vu.RunOnce() }()\n\n\tselect {\n\tcase <-time.After(15 * time.Second):\n\t\tcancel()\n\t\tt.Fatal(\"Test timed out\")\n\tcase err := <-errC:\n\t\tcancel()\n\t\trequire.NoError(t, err)\n\t}\n}\n\nfunc TestSystemTags(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\t// Handle paths with custom logic\n\ttb.Mux.HandleFunc(\"/wrong-redirect\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Add(\"Location\", \"%\")\n\t\tw.WriteHeader(http.StatusTemporaryRedirect)\n\t})\n\n\thttpURL, err := url.Parse(tb.ServerHTTP.URL)\n\trequire.NoError(t, err)\n\n\ttestedSystemTags := []struct{ tag, exec, expVal string }{\n\t\t{\"proto\", \"http_get\", \"HTTP/1.1\"},\n\t\t{\"status\", \"http_get\", \"200\"},\n\t\t{\"method\", \"http_get\", \"GET\"},\n\t\t{\"url\", \"http_get\", tb.ServerHTTP.URL},\n\t\t{\"url\", \"https_get\", tb.ServerHTTPS.URL},\n\t\t{\"ip\", \"http_get\", httpURL.Hostname()},\n\t\t{\"name\", \"http_get\", tb.ServerHTTP.URL},\n\t\t{\"group\", \"http_get\", \"\"},\n\t\t{\"vu\", \"http_get\", \"8\"},\n\t\t{\"vu\", \"noop\", \"9\"},\n\t\t{\"iter\", \"http_get\", \"0\"},\n\t\t{\"iter\", \"noop\", \"0\"},\n\t\t{\"tls_version\", \"https_get\", \"tls1.3\"},\n\t\t{\"ocsp_status\", \"https_get\", \"unknown\"},\n\t\t{\"error\", \"bad_url_get\", `dial: connection refused`},\n\t\t{\"error_code\", \"bad_url_get\", \"1212\"},\n\t\t{\"scenario\", \"http_get\", \"default\"},\n\t\t// TODO: add more tests\n\t}\n\n\tfor num, tc := range testedSystemTags {\n\t\tt.Run(fmt.Sprintf(\"TC %d with only %s\", num, tc.tag), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\tr, err := getSimpleRunner(t, \"/script.js\", tb.Replacer.Replace(`\n\t\t\t\tvar http = require(\"k6/http\");\n\n\t\t\t\texports.http_get = function() {\n\t\t\t\t\thttp.get(\"HTTPBIN_IP_URL\");\n\t\t\t\t};\n\t\t\t\texports.https_get = function() {\n\t\t\t\t\thttp.get(\"HTTPSBIN_IP_URL\");\n\t\t\t\t};\n\t\t\t\texports.bad_url_get = function() {\n\t\t\t\t\thttp.get(\"http://127.0.0.1:1\");\n\t\t\t\t};\n\t\t\t\texports.noop = function() {};\n\t\t\t`), lib.RuntimeOptions{CompatibilityMode: null.StringFrom(\"base\")})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NoError(t, r.SetOptions(r.GetOptions().Apply(lib.Options{\n\t\t\t\tThrow:                 null.BoolFrom(false),\n\t\t\t\tTLSVersion:            &lib.TLSVersions{Max: tls.VersionTLS13},\n\t\t\t\tSystemTags:            metrics.ToSystemTagSet([]string{tc.tag}),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(true),\n\t\t\t})))\n\n\t\t\tctx := t.Context()\n\n\t\t\tvu, err := r.NewVU(ctx, uint64(num), 0, samples)\n\t\t\trequire.NoError(t, err)\n\t\t\tactiveVU := vu.Activate(&lib.VUActivationParams{\n\t\t\t\tRunContext: ctx,\n\t\t\t\tExec:       tc.exec,\n\t\t\t\tScenario:   \"default\",\n\t\t\t})\n\t\t\trequire.NoError(t, activeVU.RunOnce())\n\n\t\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\t\trequire.NotEmpty(t, bufSamples)\n\t\t\tfor _, sample := range bufSamples[0].GetSamples() {\n\t\t\t\tassert.NotEmpty(t, sample.Tags)\n\t\t\t\tfor emittedTag, emittedVal := range sample.Tags.Map() {\n\t\t\t\t\tassert.Equal(t, tc.tag, emittedTag)\n\t\t\t\t\tassert.Equal(t, tc.expVal, emittedVal)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype multiFileTestCase struct {\n\tfses       map[string]fsext.Fs\n\trtOpts     lib.RuntimeOptions\n\tcwd        string\n\tscript     string\n\texpInitErr bool\n\texpVUErr   bool\n\tsamples    chan metrics.SampleContainer\n}\n\nfunc runMultiFileTestCase(t *testing.T, tc multiFileTestCase, tb *httpmultibin.HTTPMultiBin) {\n\tt.Helper()\n\trunner, err := getSimpleRunner(t, strings.TrimRight(tc.cwd, \"/\")+\"/script.js\", tc.script, tc.rtOpts, tc.fses)\n\tif tc.expInitErr {\n\t\trequire.Error(t, err)\n\t\treturn\n\t}\n\trequire.NoError(t, err)\n\n\toptions := runner.GetOptions()\n\trequire.Empty(t, options.Validate())\n\n\tctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\n\tdefer cancel()\n\n\tvu, err := runner.NewVU(ctx, 1, 1, tc.samples)\n\trequire.NoError(t, err)\n\n\tjsVU, ok := vu.(*VU)\n\trequire.True(t, ok)\n\tjsVU.state.Dialer = tb.Dialer\n\tjsVU.state.TLSConfig = tb.TLSClientConfig\n\n\tactiveVU := vu.Activate(&lib.VUActivationParams{RunContext: ctx})\n\n\terr = activeVU.RunOnce()\n\tif tc.expVUErr {\n\t\trequire.Error(t, err)\n\t} else {\n\t\trequire.NoError(t, err)\n\t}\n\n\tarc := runner.MakeArchive()\n\trunnerFromArc, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\tvuFromArc, err := runnerFromArc.NewVU(ctx, 2, 2, tc.samples)\n\trequire.NoError(t, err)\n\tjsVUFromArc, ok := vuFromArc.(*VU)\n\trequire.True(t, ok)\n\tjsVUFromArc.state.Dialer = tb.Dialer\n\tjsVUFromArc.state.TLSConfig = tb.TLSClientConfig\n\tactiveVUFromArc := jsVUFromArc.Activate(&lib.VUActivationParams{RunContext: ctx})\n\terr = activeVUFromArc.RunOnce()\n\tif tc.expVUErr {\n\t\trequire.Error(t, err)\n\t\treturn\n\t}\n\trequire.NoError(t, err)\n}\n\nfunc TestComplicatedFileImportsForGRPC(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\ttb.GRPCStub.UnaryCallFunc = func(_ context.Context, _ *grpc_testing.SimpleRequest) (\n\t\t*grpc_testing.SimpleResponse, error,\n\t) {\n\t\treturn &grpc_testing.SimpleResponse{\n\t\t\tUsername: \"foo\",\n\t\t}, nil\n\t}\n\n\tfs := fsext.NewMemMapFs()\n\tprotoFile, err := os.ReadFile(\"../lib/testutils/httpmultibin/grpc_testing/test.proto\") //nolint:forbidigo\n\trequire.NoError(t, err)\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/service.proto\", protoFile, 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/same-dir.proto\", []byte(\n\t\t`syntax = \"proto3\";package whatever;import \"service.proto\";`,\n\t), 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/subdir.proto\", []byte(\n\t\t`syntax = \"proto3\";package whatever;import \"to/service.proto\";`,\n\t), 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/abs.proto\", []byte(\n\t\t`syntax = \"proto3\";package whatever;import \"/path/to/service.proto\";`,\n\t), 0o644))\n\n\tgrpcTestCase := func(expInitErr, expVUErr bool, cwd, loadCode string) multiFileTestCase {\n\t\tscript := tb.Replacer.Replace(fmt.Sprintf(`\n\t\t\tvar grpc = require('k6/net/grpc');\n\t\t\tvar client = new grpc.Client();\n\n\t\t\t%s // load statements\n\n\t\t\texports.default = function() {\n\t\t\t\tclient.connect('GRPCBIN_ADDR', {timeout: '3s'});\n\t\t\t\ttry {\n\t\t\t\t\tvar resp = client.invoke('grpc.testing.TestService/UnaryCall', {})\n\t\t\t\t\tif (!resp.message || resp.error || resp.message.username !== 'foo') {\n\t\t\t\t\t\tthrow new Error('unexpected response message: ' + JSON.stringify(resp.message))\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tclient.close();\n\t\t\t\t}\n\t\t\t}\n\t\t`, loadCode))\n\n\t\treturn multiFileTestCase{\n\t\t\tfses:    map[string]fsext.Fs{\"file\": fs, \"https\": fsext.NewMemMapFs()},\n\t\t\trtOpts:  lib.RuntimeOptions{CompatibilityMode: null.NewString(\"base\", true)},\n\t\t\tsamples: make(chan metrics.SampleContainer, 100),\n\t\t\tcwd:     cwd, expInitErr: expInitErr, expVUErr: expVUErr, script: script,\n\t\t}\n\t}\n\n\ttestCases := []multiFileTestCase{\n\t\tgrpcTestCase(false, true, \"/\", `/* no grpc loads */`), // exp VU error with no proto files loaded\n\n\t\t// Init errors when the protobuf file can't be loaded\n\t\tgrpcTestCase(true, false, \"/\", `client.load(null, 'service.proto');`),\n\t\tgrpcTestCase(true, false, \"/\", `client.load(null, '/wrong/path/to/service.proto');`),\n\t\tgrpcTestCase(true, false, \"/\", `client.load(['/', '/path/'], 'service.proto');`),\n\n\t\t// Direct imports of service.proto\n\t\tgrpcTestCase(false, false, \"/\", `client.load(null, '/path/to/service.proto');`), // full path should be fine\n\t\tgrpcTestCase(false, false, \"/path/to/\", `client.load([], 'service.proto');`),    // file name from same folder\n\t\tgrpcTestCase(false, false, \"/\", `client.load(['./path//to/'], 'service.proto');`),\n\t\tgrpcTestCase(false, false, \"/path/\", `client.load(['./to/'], 'service.proto');`),\n\n\t\tgrpcTestCase(false, false, \"/whatever\", `client.load(['/path/to/'], 'service.proto');`),  // with import paths\n\t\tgrpcTestCase(false, false, \"/path\", `client.load(['/', '/path/to/'], 'service.proto');`), // with import paths\n\t\tgrpcTestCase(false, false, \"/whatever\", `client.load(['../path/to/'], 'service.proto');`),\n\n\t\t// Import another file that imports \"service.proto\" directly\n\t\tgrpcTestCase(true, false, \"/\", `client.load([], '/path/to/same-dir.proto');`),\n\t\tgrpcTestCase(true, false, \"/path/\", `client.load([], 'to/same-dir.proto');`),\n\t\tgrpcTestCase(true, false, \"/\", `client.load(['/path/'], 'to/same-dir.proto');`),\n\t\tgrpcTestCase(false, false, \"/path/to/\", `client.load([], 'same-dir.proto');`),\n\t\tgrpcTestCase(false, false, \"/\", `client.load(['/path/to/'], 'same-dir.proto');`),\n\t\tgrpcTestCase(false, false, \"/whatever\", `client.load(['/other', '/path/to/'], 'same-dir.proto');`),\n\t\tgrpcTestCase(false, false, \"/\", `client.load(['./path//to/'], 'same-dir.proto');`),\n\t\tgrpcTestCase(false, false, \"/path/\", `client.load(['./to/'], 'same-dir.proto');`),\n\t\tgrpcTestCase(false, false, \"/whatever\", `client.load(['../path/to/'], 'same-dir.proto');`),\n\n\t\t// Import another file that imports \"to/service.proto\" directly\n\t\tgrpcTestCase(true, false, \"/\", `client.load([], '/path/to/subdir.proto');`),\n\t\tgrpcTestCase(false, false, \"/path/\", `client.load([], 'subdir.proto');`),\n\t\tgrpcTestCase(false, false, \"/\", `client.load(['/path/'], 'subdir.proto');`),\n\t\tgrpcTestCase(false, false, \"/\", `client.load(['./path/'], 'subdir.proto');`),\n\t\tgrpcTestCase(false, false, \"/whatever\", `client.load(['/other', '/path/'], 'subdir.proto');`),\n\t\tgrpcTestCase(false, false, \"/whatever\", `client.load(['../other', '../path/'], 'subdir.proto');`),\n\n\t\t// Import another file that imports \"/path/to/service.proto\" directly\n\t\tgrpcTestCase(true, false, \"/\", `client.load(['/path'], '/path/to/abs.proto');`),\n\t\tgrpcTestCase(false, false, \"/\", `client.load([], '/path/to/abs.proto');`),\n\t\tgrpcTestCase(false, false, \"/whatever\", `client.load(['/'], '/path/to/abs.proto');`),\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"TestCase_%d\", i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Logf(\n\t\t\t\t\"CWD: %s, expInitErr: %t, expVUErr: %t, script injected with: `%s`\",\n\t\t\t\ttc.cwd, tc.expInitErr, tc.expVUErr, tc.script,\n\t\t\t)\n\t\t\trunMultiFileTestCase(t, tc, tb)\n\t\t})\n\t}\n}\n\nfunc TestMinIterationDurationIsCancellable(t *testing.T) {\n\tt.Parallel()\n\n\tr, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\texports.options = { iterations: 1, vus: 1, minIterationDuration: '1m' };\n\n\t\t\texports.default = function() { /* do nothing */ };\n\t\t`)\n\trequire.NoError(t, err)\n\n\tch := make(chan metrics.SampleContainer, 1000)\n\tctx, cancel := context.WithCancel(context.Background())\n\tinitVU, err := r.NewVU(ctx, 1, 1, ch)\n\trequire.NoError(t, err)\n\n\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\terrC := make(chan error)\n\tgo func() { errC <- vu.RunOnce() }()\n\n\ttime.Sleep(200 * time.Millisecond) // give it some time to actually start\n\n\tcancel() // simulate the end of gracefulStop or a Ctrl+C event\n\n\tselect {\n\tcase <-time.After(3 * time.Second):\n\t\tt.Fatal(\"Test timed out or minIterationDuration prevailed\")\n\tcase err := <-errC:\n\t\trequire.NoError(t, err)\n\t}\n}\n\nfunc TestForceHTTP1Feature(t *testing.T) {\n\tt.Parallel()\n\tcases := map[string]struct {\n\t\tgodebug               string\n\t\texpectedForceH1Result bool\n\t\tprotocol              string\n\t}{\n\t\t\"Force H1 Enabled. Checking for H1\": {\n\t\t\tgodebug:               \"http2client=0,gctrace=1\",\n\t\t\texpectedForceH1Result: true,\n\t\t\tprotocol:              \"HTTP/1.1\",\n\t\t},\n\t\t\"Force H1 Disabled. Checking for H2\": {\n\t\t\tgodebug:               \"test=0\",\n\t\t\texpectedForceH1Result: false,\n\t\t\tprotocol:              \"HTTP/2.0\",\n\t\t},\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tlookupEnv := func(key string) (string, bool) {\n\t\t\t\tif key == \"GODEBUG\" {\n\t\t\t\t\treturn tc.godebug, true\n\t\t\t\t}\n\t\t\t\treturn \"\", false\n\t\t\t}\n\t\t\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\t\t\tdata := fmt.Sprintf(`var k6 = require(\"k6\");\n\t\t\tvar check = k6.check;\n\t\t\tvar fail = k6.fail;\n\t\t\tvar http = require(\"k6/http\");;\n\t\t\texports.default = function() {\n\t\t\t\tvar res = http.get(\"HTTP2BIN_URL\");\n\t\t\t\tif (\n\t\t\t\t\t!check(res, {\n\t\t\t\t\t'checking to see if status was 200': (res) => res.status === 200,\n\t\t\t\t\t'checking to see protocol': (res) => res.proto === '%s'\n\t\t\t\t\t})\n\t\t\t\t) {\n\t\t\t\t\tfail('test failed')\n\t\t\t\t}\n\t\t\t}`, tc.protocol)\n\n\t\t\tr1, err := getSimpleRunner(t, \"/script.js\", tb.Replacer.Replace(data))\n\t\t\trequire.NoError(t, err)\n\t\t\tr1.preInitState.LookupEnv = lookupEnv\n\n\t\t\tassert.Equal(t, tc.expectedForceH1Result, r1.forceHTTP1())\n\n\t\t\terr = r1.SetOptions(lib.Options{\n\t\t\t\tHosts: types.NullHosts{Trie: tb.Dialer.Hosts},\n\t\t\t\t// We disable TLS verify so that we don't get a TLS handshake error since\n\t\t\t\t// the certificates on the endpoint are not certified by a certificate authority\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(true),\n\t\t\t})\n\n\t\t\trequire.NoError(t, err)\n\n\t\t\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\t\t\trequire.NoError(t, err)\n\t\t\tr2.preInitState.LookupEnv = lookupEnv\n\t\t\tassert.Equal(t, tc.expectedForceH1Result, r2.forceHTTP1())\n\n\t\t\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\t\t\tfor name, r := range runners {\n\t\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\t\tctx := t.Context()\n\n\t\t\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\t\t\terr = vu.RunOnce()\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestExecutionInfo(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname, script, expErr string\n\t}{\n\t\t{name: \"vu_ok\", script: `\n\t\tvar exec = require('k6/execution');\n\n\t\texports.default = function() {\n\t\t\tif (exec.vu.idInInstance !== 1) throw new Error('unexpected VU ID: '+exec.vu.idInInstance);\n\t\t\tif (exec.vu.idInTest !== 10) throw new Error('unexpected global VU ID: '+exec.vu.idInTest);\n\t\t\tif (exec.vu.iterationInInstance !== 0) throw new Error('unexpected VU iteration: '+exec.vu.iterationInInstance);\n\t\t\tif (exec.vu.iterationInScenario !== 0) throw new Error('unexpected scenario iteration: '+exec.vu.iterationInScenario);\n\t\t}`},\n\t\t{name: \"vu_err\", script: `\n\t\tvar exec = require('k6/execution');\n\t\texec.vu;\n\t\t`, expErr: \"getting VU information in the init context is not supported\"},\n\t\t{name: \"scenario_ok\", script: `\n\t\tvar exec = require('k6/execution');\n\t\tvar sleep = require('k6').sleep;\n\n\t\texports.default = function() {\n\t\t\tvar si = exec.scenario;\n\t\t\tsleep(0.1);\n\t\t\tif (si.name !== 'default') throw new Error('unexpected scenario name: '+si.name);\n\t\t\tif (si.executor !== 'test-exec') throw new Error('unexpected executor: '+si.executor);\n\t\t\tif (si.startTime > new Date().getTime()) throw new Error('unexpected startTime: '+si.startTime);\n\t\t\tif (si.progress !== 0.1) throw new Error('unexpected progress: '+si.progress);\n\t\t\tif (si.iterationInInstance !== 3) throw new Error('unexpected scenario local iteration: '+si.iterationInInstance);\n\t\t\tif (si.iterationInTest !== 4) throw new Error('unexpected scenario local iteration: '+si.iterationInTest);\n\t\t}`},\n\t\t{name: \"scenario_err\", script: `\n\t\tvar exec = require('k6/execution');\n\t\texec.scenario;\n\t\t`, expErr: \"getting scenario information outside of the VU context is not supported\"},\n\t\t{name: \"test_ok\", script: `\n\t\tvar exec = require('k6/execution');\n\n\t\texports.default = function() {\n\t\t\tvar ti = exec.instance;\n\t\t\tif (ti.currentTestRunDuration !== 0) throw new Error('unexpected test duration: '+ti.currentTestRunDuration);\n\t\t\tif (ti.vusActive !== 1) throw new Error('unexpected vusActive: '+ti.vusActive);\n\t\t\tif (ti.vusInitialized !== 0) throw new Error('unexpected vusInitialized: '+ti.vusInitialized);\n\t\t\tif (ti.iterationsCompleted !== 0) throw new Error('unexpected iterationsCompleted: '+ti.iterationsCompleted);\n\t\t\tif (ti.iterationsInterrupted !== 0) throw new Error('unexpected iterationsInterrupted: '+ti.iterationsInterrupted);\n\t\t}`},\n\t\t{name: \"test_err\", script: `\n\t\tvar exec = require('k6/execution');\n\t\texec.instance;\n\t\t`, expErr: \"getting instance information in the init context is not supported\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tr, err := getSimpleRunner(t, \"/script.js\", tc.script)\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tc.expErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\tr.Bundle.Options.SystemTags = &metrics.DefaultSystemTagSet\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\n\t\t\tctx := t.Context()\n\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 10, samples)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttestRunState := &lib.TestRunState{\n\t\t\t\tTestPreInitState: r.preInitState,\n\t\t\t\tOptions:          r.GetOptions(),\n\t\t\t\tRunner:           r,\n\t\t\t}\n\n\t\t\texecScheduler, err := execution.NewScheduler(testRunState, local.NewController())\n\t\t\trequire.NoError(t, err)\n\n\t\t\tctx = lib.WithExecutionState(ctx, execScheduler.GetState())\n\t\t\tctx = lib.WithScenarioState(ctx, &lib.ScenarioState{\n\t\t\t\tName:      \"default\",\n\t\t\t\tExecutor:  \"test-exec\",\n\t\t\t\tStartTime: time.Now(),\n\t\t\t\tProgressFn: func() (float64, []string) {\n\t\t\t\t\treturn 0.1, nil\n\t\t\t\t},\n\t\t\t})\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{\n\t\t\t\tRunContext:               ctx,\n\t\t\t\tExec:                     \"default\",\n\t\t\t\tGetNextIterationCounters: func() (uint64, uint64) { return 3, 4 },\n\t\t\t})\n\n\t\t\texecState := execScheduler.GetState()\n\t\t\texecState.ModCurrentlyActiveVUsCount(+1)\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestPromiseRejectionIsCleared(t *testing.T) {\n\tt.Parallel()\n\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\nexports.default = () => {\n    let p = new Promise((res) => {\n        if (__ITER == 1) {\n            throw \"oops\"\n        }\n        res(\"yes\");\n    })\n    p.then((r) => {\n        console.log(r);\n    })\n}`)\n\trequire.NoError(t, err)\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive())\n\trequire.NoError(t, err)\n\n\trunners := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range runners {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, make(chan metrics.SampleContainer, 100))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.ErrorContains(t, err, \"Uncaught (in promise) oops\")\n\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestArchivingAnArchiveWorks(t *testing.T) {\n\tt.Parallel()\n\tr1, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\texports.default = function() {}\n\t\t`)\n\trequire.NoError(t, err)\n\n\tarc := r1.MakeArchive()\n\tr2, err := getSimpleArchiveRunner(t, arc)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, r2)\n\n\tarc2 := r2.MakeArchive()\n\tr3, err := getSimpleArchiveRunner(t, arc2)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, r3)\n}\n"
  },
  {
    "path": "internal/js/share_test.go",
    "content": "package js\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestNewSharedArrayIntegration(t *testing.T) {\n\tt.Parallel()\n\tdata := `'use strict';\nvar SharedArray = require(\"k6/data\").SharedArray;\nfunction generateArray() {\n    console.log(\"once\");\n    var n = 50;\n    var arr = new Array(n);\n    for (var i = 0 ; i <n; i++) {\n        arr[i] = {value: \"something\" +i};\n    }\n    return arr;\n}\n\nvar s = new SharedArray(\"something\", generateArray);\n\nexports.default = function() {\n\tif (s[2].value !== \"something2\") {\n\t\tthrow new Error(\"bad s[2]=\"+s[2].value);\n\t}\n\tif (s.length != 50) {\n\t\tthrow new Error(\"bad length \" +_s.length);\n\t}\n\n\tvar i = 0;\n\tfor (var v of s) {\n\t\tif (v.value !== \"something\"+i) {\n\t\t\tthrow new Error(\"bad v.value=\"+v.value+\" for i=\"+i);\n\t\t}\n\t\ti++;\n\t}\n}`\n\n\tlogger := logrus.New()\n\tlogger.SetLevel(logrus.InfoLevel)\n\tlogger.Out = io.Discard\n\thook := testutils.NewLogHook(\n\t\tlogrus.InfoLevel, logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel,\n\t)\n\tlogger.AddHook(hook)\n\n\tr1, err := getSimpleRunner(t, \"/script.js\", data, logger)\n\trequire.NoError(t, err)\n\tentries := hook.Drain()\n\trequire.Len(t, entries, 1)\n\tassert.Equal(t, logrus.InfoLevel, entries[0].Level)\n\tassert.Equal(t, \"once\", entries[0].Message)\n\n\tr2, err := getSimpleArchiveRunner(t, r1.MakeArchive(), logger)\n\trequire.NoError(t, err)\n\tentries = hook.Drain()\n\trequire.Len(t, entries, 1)\n\tassert.Equal(t, logrus.InfoLevel, entries[0].Level)\n\tassert.Equal(t, \"once\", entries[0].Message)\n\n\ttestdata := map[string]*Runner{\"Source\": r1, \"Archive\": r2}\n\tfor name, r := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx := t.Context()\n\n\t\t\tsamples := make(chan metrics.SampleContainer, 100)\n\t\t\tinitVU, err := r.NewVU(ctx, 1, 1, samples)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvu := initVU.Activate(&lib.VUActivationParams{RunContext: ctx})\n\t\t\terr = vu.RunOnce()\n\t\t\trequire.NoError(t, err)\n\t\t\tentries := hook.Drain()\n\t\t\tassert.Len(t, entries, 0)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/js/summary-legacy.js",
    "content": "/**\n * NOTE: This file is a legacy version of the summary generation code, and is kept around for\n * backwards compatibility, until we decide to remove the support for the old summary format.\n *\n * This file contains code used to generate a textual summary of tests results, as displayed\n * in the user's terminal at the end of a k6 test run, also known as \"end of test summary\".\n *\n * The main entry point is the `generateTextSummary` function, which takes the test data,\n * and returns a formatted string summarizing the test results, ready to be written to the terminal.\n *\n * For convenience, the file also exports the `humanizeValue` function.\n */\nexports.humanizeValue = humanizeValue\nexports.textSummary = generateTextSummary\n\nvar forEach = function (obj, callback) {\n\tfor (var key in obj) {\n\t\tif (obj.hasOwnProperty(key)) {\n\t\t\tif (callback(key, obj[key])) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\nvar palette = {\n\tbold: 1,\n\tfaint: 2,\n\tred: 31,\n\tgreen: 32,\n\tcyan: 36,\n\t//TODO: add others?\n}\n\nvar groupPrefix = '█'\nvar detailsPrefix = '↳'\nvar succMark = '✓'\nvar failMark = '✗'\nvar defaultOptions = {\n\tindent: ' ',\n\tenableColors: true,\n\tsummaryTimeUnit: null,\n\tsummaryTrendStats: null,\n}\n\n// strWidth tries to return the actual width the string will take up on the\n// screen, without any terminal formatting, unicode ligatures, etc.\nfunction strWidth(s) {\n\t// TODO: determine if NFC or NFKD are not more appropriate? or just give up? https://hsivonen.fi/string-length/\n\tvar data = s.normalize('NFKC') // This used to be NFKD in Go, but this should be better\n\tvar inEscSeq = false\n\tvar inLongEscSeq = false\n\tvar width = 0\n\tfor (var char of data) {\n\t\tif (char.done) {\n\t\t\tbreak\n\t\t}\n\n\t\t// Skip over ANSI escape codes.\n\t\tif (char == '\\x1b') {\n\t\t\tinEscSeq = true\n\t\t\tcontinue\n\t\t}\n\t\tif (inEscSeq && char == '[') {\n\t\t\tinLongEscSeq = true\n\t\t\tcontinue\n\t\t}\n\t\tif (inEscSeq && inLongEscSeq && char.charCodeAt(0) >= 0x40 && char.charCodeAt(0) <= 0x7e) {\n\t\t\tinEscSeq = false\n\t\t\tinLongEscSeq = false\n\t\t\tcontinue\n\t\t}\n\t\tif (inEscSeq && !inLongEscSeq && char.charCodeAt(0) >= 0x40 && char.charCodeAt(0) <= 0x5f) {\n\t\t\tinEscSeq = false\n\t\t\tcontinue\n\t\t}\n\n\t\tif (!inEscSeq && !inLongEscSeq) {\n\t\t\twidth++\n\t\t}\n\t}\n\treturn width\n}\n\nfunction summarizeCheck(indent, check, decorate) {\n\tif (check.fails == 0) {\n\t\treturn decorate(indent + succMark + ' ' + check.name, palette.green)\n\t}\n\n\tvar succPercent = Math.floor((100 * check.passes) / (check.passes + check.fails))\n\treturn decorate(\n\t\tindent +\n\t\tfailMark +\n\t\t' ' +\n\t\tcheck.name +\n\t\t'\\n' +\n\t\tindent +\n\t\t' ' +\n\t\tdetailsPrefix +\n\t\t'  ' +\n\t\tsuccPercent +\n\t\t'% — ' +\n\t\tsuccMark +\n\t\t' ' +\n\t\tcheck.passes +\n\t\t' / ' +\n\t\tfailMark +\n\t\t' ' +\n\t\tcheck.fails,\n\t\tpalette.red\n\t)\n}\n\nfunction summarizeGroup(indent, group, decorate) {\n\tvar result = []\n\tif (group.name != '') {\n\t\tresult.push(indent + groupPrefix + ' ' + group.name + '\\n')\n\t\tindent = indent + '  '\n\t}\n\n\tfor (var i = 0; i < group.checks.length; i++) {\n\t\tresult.push(summarizeCheck(indent, group.checks[i], decorate))\n\t}\n\tif (group.checks.length > 0) {\n\t\tresult.push('')\n\t}\n\tfor (var i = 0; i < group.groups.length; i++) {\n\t\tArray.prototype.push.apply(result, summarizeGroup(indent, group.groups[i], decorate))\n\t}\n\n\treturn result\n}\n\nfunction displayNameForMetric(name) {\n\tvar subMetricPos = name.indexOf('{')\n\tif (subMetricPos >= 0) {\n\t\treturn '{ ' + name.substring(subMetricPos + 1, name.length - 1) + ' }'\n\t}\n\treturn name\n}\n\nfunction indentForMetric(name) {\n\tif (name.indexOf('{') >= 0) {\n\t\treturn '  '\n\t}\n\treturn ''\n}\n\nfunction humanizeBytes(bytes) {\n\tvar units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n\tvar base = 1000\n\tif (bytes < 10) {\n\t\treturn bytes + ' B'\n\t}\n\n\tvar e = Math.floor(Math.log(bytes) / Math.log(base))\n\tvar suffix = units[e | 0]\n\tvar val = Math.floor((bytes / Math.pow(base, e)) * 10 + 0.5) / 10\n\treturn val.toFixed(val < 10 ? 1 : 0) + ' ' + suffix\n}\n\nvar unitMap = {\n\ts: { unit: 's', coef: 0.001 },\n\tms: { unit: 'ms', coef: 1 },\n\tus: { unit: 'µs', coef: 1000 },\n}\n\nfunction toFixedNoTrailingZeros(val, prec) {\n\t// TODO: figure out something better?\n\treturn parseFloat(val.toFixed(prec)).toString()\n}\n\nfunction toFixedNoTrailingZerosTrunc(val, prec) {\n\tvar mult = Math.pow(10, prec)\n\treturn toFixedNoTrailingZeros(Math.trunc(mult * val) / mult, prec)\n}\n\nfunction humanizeGenericDuration(dur) {\n\tif (dur === 0) {\n\t\treturn '0s'\n\t}\n\n\tif (dur < 0.001) {\n\t\t// smaller than a microsecond, print nanoseconds\n\t\treturn Math.trunc(dur * 1000000) + 'ns'\n\t}\n\tif (dur < 1) {\n\t\t// smaller than a millisecond, print microseconds\n\t\treturn toFixedNoTrailingZerosTrunc(dur * 1000, 2) + 'µs'\n\t}\n\tif (dur < 1000) {\n\t\t// duration is smaller than a second\n\t\treturn toFixedNoTrailingZerosTrunc(dur, 2) + 'ms'\n\t}\n\n\tvar result = toFixedNoTrailingZerosTrunc((dur % 60000) / 1000, dur > 60000 ? 0 : 2) + 's'\n\tvar rem = Math.trunc(dur / 60000)\n\tif (rem < 1) {\n\t\t// less than a minute\n\t\treturn result\n\t}\n\tresult = (rem % 60) + 'm' + result\n\trem = Math.trunc(rem / 60)\n\tif (rem < 1) {\n\t\t// less than an hour\n\t\treturn result\n\t}\n\treturn rem + 'h' + result\n}\n\nfunction humanizeDuration(dur, timeUnit) {\n\tif (timeUnit !== '' && unitMap.hasOwnProperty(timeUnit)) {\n\t\treturn (dur * unitMap[timeUnit].coef).toFixed(2) + unitMap[timeUnit].unit\n\t}\n\n\treturn humanizeGenericDuration(dur)\n}\n\nfunction humanizeValue(val, metric, timeUnit) {\n\tif (metric.type == 'rate') {\n\t\t// Truncate instead of round when decreasing precision to 2 decimal places\n\t\treturn (Math.trunc(val * 100 * 100) / 100).toFixed(2) + '%'\n\t}\n\n\tswitch (metric.contains) {\n\t\tcase 'data':\n\t\t\treturn humanizeBytes(val)\n\t\tcase 'time':\n\t\t\treturn humanizeDuration(val, timeUnit)\n\t\tdefault:\n\t\t\treturn toFixedNoTrailingZeros(val, 6)\n\t}\n}\n\nfunction nonTrendMetricValueForSum(metric, timeUnit) {\n\tswitch (metric.type) {\n\t\tcase 'counter':\n\t\t\treturn [\n\t\t\t\thumanizeValue(metric.values.count, metric, timeUnit),\n\t\t\t\thumanizeValue(metric.values.rate, metric, timeUnit) + '/s',\n\t\t\t]\n\t\tcase 'gauge':\n\t\t\treturn [\n\t\t\t\thumanizeValue(metric.values.value, metric, timeUnit),\n\t\t\t\t'min=' + humanizeValue(metric.values.min, metric, timeUnit),\n\t\t\t\t'max=' + humanizeValue(metric.values.max, metric, timeUnit),\n\t\t\t]\n\t\tcase 'rate':\n\t\t\treturn [\n\t\t\t\thumanizeValue(metric.values.rate, metric, timeUnit),\n\t\t\t\t`${metric.values.passes} out of ${metric.values.passes + metric.values.fails}`,\n\t\t\t]\n\t\tdefault:\n\t\t\treturn ['[no data]']\n\t}\n}\n\nfunction summarizeMetrics(options, data, decorate) {\n\tvar indent = options.indent + '  '\n\tvar result = []\n\n\tvar names = []\n\tvar nameLenMax = 0\n\n\tvar nonTrendValues = {}\n\tvar nonTrendValueMaxLen = 0\n\tvar nonTrendExtras = {}\n\tvar nonTrendExtraMaxLens = [0, 0]\n\n\tvar trendCols = {}\n\tvar numTrendColumns = options.summaryTrendStats.length\n\tvar trendColMaxLens = new Array(numTrendColumns).fill(0)\n\tforEach(data.metrics, function (name, metric) {\n\t\tnames.push(name)\n\t\t// When calculating widths for metrics, account for the indentation on submetrics.\n\t\tvar displayName = indentForMetric(name) + displayNameForMetric(name)\n\t\tvar displayNameWidth = strWidth(displayName)\n\t\tif (displayNameWidth > nameLenMax) {\n\t\t\tnameLenMax = displayNameWidth\n\t\t}\n\n\t\tif (metric.type == 'trend') {\n\t\t\tvar cols = []\n\t\t\tfor (var i = 0; i < numTrendColumns; i++) {\n\t\t\t\tvar tc = options.summaryTrendStats[i]\n\t\t\t\tvar value = metric.values[tc]\n\t\t\t\tif (tc === 'count') {\n\t\t\t\t\tvalue = value.toString()\n\t\t\t\t} else {\n\t\t\t\t\tvalue = humanizeValue(value, metric, options.summaryTimeUnit)\n\t\t\t\t}\n\t\t\t\tvar valLen = strWidth(value)\n\t\t\t\tif (valLen > trendColMaxLens[i]) {\n\t\t\t\t\ttrendColMaxLens[i] = valLen\n\t\t\t\t}\n\t\t\t\tcols[i] = value\n\t\t\t}\n\t\t\ttrendCols[name] = cols\n\t\t\treturn\n\t\t}\n\t\tvar values = nonTrendMetricValueForSum(metric, options.summaryTimeUnit)\n\t\tnonTrendValues[name] = values[0]\n\t\tvar valueLen = strWidth(values[0])\n\t\tif (valueLen > nonTrendValueMaxLen) {\n\t\t\tnonTrendValueMaxLen = valueLen\n\t\t}\n\t\tnonTrendExtras[name] = values.slice(1)\n\t\tfor (var i = 1; i < values.length; i++) {\n\t\t\tvar extraLen = strWidth(values[i])\n\t\t\tif (extraLen > nonTrendExtraMaxLens[i - 1]) {\n\t\t\t\tnonTrendExtraMaxLens[i - 1] = extraLen\n\t\t\t}\n\t\t}\n\t})\n\n\t// sort all metrics but keep sub metrics grouped with their parent metrics\n\tnames.sort(function (metric1, metric2) {\n\t\tvar parent1 = metric1.split('{', 1)[0]\n\t\tvar parent2 = metric2.split('{', 1)[0]\n\t\tvar result = parent1.localeCompare(parent2)\n\t\tif (result !== 0) {\n\t\t\treturn result\n\t\t}\n\t\tvar sub1 = metric1.substring(parent1.length)\n\t\tvar sub2 = metric2.substring(parent2.length)\n\t\treturn sub1.localeCompare(sub2)\n\t})\n\n\tvar getData = function (name) {\n\t\tif (trendCols.hasOwnProperty(name)) {\n\t\t\tvar cols = trendCols[name]\n\t\t\tvar tmpCols = new Array(numTrendColumns)\n\t\t\tfor (var i = 0; i < cols.length; i++) {\n\t\t\t\ttmpCols[i] =\n\t\t\t\t\toptions.summaryTrendStats[i] +\n\t\t\t\t\t'=' +\n\t\t\t\t\tdecorate(cols[i], palette.cyan) +\n\t\t\t\t\t' '.repeat(trendColMaxLens[i] - strWidth(cols[i]))\n\t\t\t}\n\t\t\treturn tmpCols.join(' ')\n\t\t}\n\n\t\tvar value = nonTrendValues[name]\n\t\tvar fmtData = decorate(value, palette.cyan) + ' '.repeat(nonTrendValueMaxLen - strWidth(value))\n\n\t\tvar extras = nonTrendExtras[name]\n\t\tif (extras.length == 1) {\n\t\t\tfmtData = fmtData + ' ' + decorate(extras[0], palette.cyan, palette.faint)\n\t\t} else if (extras.length > 1) {\n\t\t\tvar parts = new Array(extras.length)\n\t\t\tfor (var i = 0; i < extras.length; i++) {\n\t\t\t\tparts[i] =\n\t\t\t\t\tdecorate(extras[i], palette.cyan, palette.faint) +\n\t\t\t\t\t' '.repeat(nonTrendExtraMaxLens[i] - strWidth(extras[i]))\n\t\t\t}\n\t\t\tfmtData = fmtData + ' ' + parts.join(' ')\n\t\t}\n\n\t\treturn fmtData\n\t}\n\n\tfor (var name of names) {\n\t\tvar metric = data.metrics[name]\n\t\tvar mark = ' '\n\t\tvar markColor = function (text) {\n\t\t\treturn text\n\t\t} // noop\n\n\t\tif (metric.thresholds) {\n\t\t\tmark = succMark\n\t\t\tmarkColor = function (text) {\n\t\t\t\treturn decorate(text, palette.green)\n\t\t\t}\n\t\t\tforEach(metric.thresholds, function (name, threshold) {\n\t\t\t\tif (!threshold.ok) {\n\t\t\t\t\tmark = failMark\n\t\t\t\t\tmarkColor = function (text) {\n\t\t\t\t\t\treturn decorate(text, palette.red)\n\t\t\t\t\t}\n\t\t\t\t\treturn true // break\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tvar fmtIndent = indentForMetric(name)\n\t\tvar fmtName = displayNameForMetric(name)\n\t\tfmtName =\n\t\t\tfmtName +\n\t\t\tdecorate(\n\t\t\t\t'.'.repeat(nameLenMax - strWidth(fmtName) - strWidth(fmtIndent) + 3) + ':',\n\t\t\t\tpalette.faint\n\t\t\t)\n\n\t\tresult.push(indent + fmtIndent + markColor(mark) + ' ' + fmtName + ' ' + getData(name))\n\t}\n\n\treturn result\n}\n\nfunction generateTextSummary(data, options) {\n\tvar mergedOpts = Object.assign({}, defaultOptions, data.options, options)\n\tvar lines = []\n\n\t// TODO: move all of these functions into an object with methods?\n\tvar decorate = function (text) {\n\t\treturn text\n\t}\n\tif (mergedOpts.enableColors) {\n\t\tdecorate = function (text, color /*, ...rest*/) {\n\t\t\tvar result = '\\x1b[' + color\n\t\t\tfor (var i = 2; i < arguments.length; i++) {\n\t\t\t\tresult += ';' + arguments[i]\n\t\t\t}\n\t\t\treturn result + 'm' + text + '\\x1b[0m'\n\t\t}\n\t}\n\n\tArray.prototype.push.apply(\n\t\tlines,\n\t\tsummarizeGroup(mergedOpts.indent + '    ', data.root_group, decorate)\n\t)\n\n\tArray.prototype.push.apply(lines, summarizeMetrics(mergedOpts, data, decorate))\n\n\treturn lines.join('\\n')\n}\n\n"
  },
  {
    "path": "internal/js/summary-wrapper.js",
    "content": "(function () {\n    // TODO: Find a better name, more descriptive more this variable.\n    var jslib = {};\n    (function (module, exports) {\n        /*JSLIB_SUMMARY_CODE*/;\n    })({ exports: jslib }, jslib);\n\n    var forEach = function (obj, callback) {\n        for (var key in obj) {\n            if (obj.hasOwnProperty(key)) {\n                if (callback(key, obj[key])) {\n                    break;\n                }\n            }\n        }\n    }\n\n    var transformGroup = function (group) {\n        if (Array.isArray(group.groups)) {\n            var newFormatGroups = group.groups;\n            group.groups = {};\n            for (var i = 0; i < newFormatGroups.length; i++) {\n                group.groups[newFormatGroups[i].name] = transformGroup(newFormatGroups[i]);\n            }\n        }\n        if (Array.isArray(group.checks)) {\n            var newFormatChecks = group.checks;\n            group.checks = {};\n            for (var i = 0; i < newFormatChecks.length; i++) {\n                group.checks[newFormatChecks[i].name] = newFormatChecks[i];\n            }\n        }\n        return group;\n    };\n\n    var oldJSONSummary = function (data) {\n        // Quick copy of the data, since it's easiest to modify it in place.\n        var results = JSON.parse(JSON.stringify(data));\n        delete results.options;\n        delete results.state;\n\n        forEach(results.metrics, function (metricName, metric) {\n            var oldFormatMetric = metric.values;\n            if (metric.thresholds && Object.keys(metric.thresholds).length > 0) {\n                var newFormatThresholds = metric.thresholds;\n                oldFormatMetric.thresholds = {};\n                forEach(newFormatThresholds, function (thresholdName, threshold) {\n                    oldFormatMetric.thresholds[thresholdName] = !threshold.ok;\n                });\n            }\n            if (metric.type == 'rate' && oldFormatMetric.hasOwnProperty('rate')) {\n                oldFormatMetric.value = oldFormatMetric.rate; // sigh...\n                delete oldFormatMetric.rate;\n            }\n            results.metrics[metricName] = oldFormatMetric;\n        });\n\n        results.root_group = transformGroup(results.root_group);\n\n        return JSON.stringify(results, null, 4);\n    };\n\n    return function (summaryCallbackResult, jsonSummaryPath, legacyData, data, options) {\n        let result = summaryCallbackResult;\n        if (!result) {\n            result = {\n                'stdout': '\\n' + jslib.textSummary(data, options) + '\\n\\n',\n            };\n        }\n\n        // TODO: ensure we're returning a map of strings or null/undefined...\n        // and if not, log an error and generate the default summary?\n\n        if (jsonSummaryPath != '') {\n\t        result[jsonSummaryPath] = (options.newMachineReadableSummary)\n\t            ? JSON.stringify(legacyData, null, 4)\n\t\t\t\t: oldJSONSummary(legacyData);\n        }\n\n        return result;\n    };\n})();"
  },
  {
    "path": "internal/js/summary.go",
    "content": "package js\n\nimport (\n\t_ \"embed\" // this is used to embed the contents of summary.js\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// Copied from https://github.com/k6io/jslib.k6.io/tree/master/lib/k6-summary\n//\n//go:embed summary.js\nvar jslibSummaryCode string\n\n// TODO: Remove me once we stop supporting the legacy summary.\n//\n//go:embed summary-legacy.js\nvar jslibSummaryLegacyCode string\n\n//go:embed summary-wrapper.js\nvar summaryWrapperLambdaCode string\n\n// summarizeReportToObject is a method that makes certain transformations to the given [summary.Summary]\n// in order to make it more suitable for the JS code that prints out the end-of-test summary.\n// That includes, non-exclusively, things like transforming certain Go maps into JS objects to preserve\n// the desired order of their keys (e.g. we want to display group results in the same order as groups are defined\n// in code), as that's one of the characteristics of JS objects while it doesn't apply to Go maps (not preserved).\n// TODO: Map \"checks\" into a JS object to get rid of \"OrderedChecks\" and remove that logic from summary.js.\n// TODO: Explore if it's possible to apply the same idea with Thresholds, in order to preserve order from code.\nfunc summarizeReportToObject(rt *sobek.Runtime, s *summary.Summary) (map[string]any, error) {\n\t// We use a JS object to preserve insertion order of groups, so we don't need to pass\n\t// an extra array with the order of groups, but just an object.\n\tvar mapGroups func(groups map[string]summary.Group, sorted []string) (*sobek.Object, error)\n\n\tmapGroup := func(g summary.Group) (map[string]any, error) {\n\t\tgGroupsObj, err := mapGroups(g.Groups, g.GroupsOrder)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tgroupObj := make(map[string]any)\n\t\tgroupObj[\"checks\"] = g.Checks\n\t\tgroupObj[\"metrics\"] = g.Metrics\n\t\tgroupObj[\"groups\"] = gGroupsObj\n\t\treturn groupObj, nil\n\t}\n\n\tmapGroups = func(groups map[string]summary.Group, sorted []string) (*sobek.Object, error) {\n\t\tbaseObj := rt.NewObject()\n\t\tfor _, gName := range sorted {\n\t\t\tgroupObj, err := mapGroup(groups[gName])\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif err := baseObj.Set(gName, groupObj); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\treturn baseObj, nil\n\t}\n\n\tgroups, err := mapGroups(s.Groups, s.GroupsOrder)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tscenarios := make(map[string]any, len(s.Scenarios))\n\tfor name, scenario := range s.Scenarios {\n\t\tscenarioObject := make(map[string]any, len(s.Scenarios))\n\t\tscenarioObject[\"groups\"], err = mapGroups(scenario.Groups, scenario.GroupsOrder)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tscenarioObject[\"checks\"] = scenario.Checks\n\t\tscenarioObject[\"metrics\"] = scenario.Metrics\n\t\tscenarios[name] = scenarioObject\n\t}\n\n\tm := make(map[string]any)\n\tm[\"thresholds\"] = s.Thresholds\n\tm[\"checks\"] = s.Checks\n\tm[\"metrics\"] = s.Metrics\n\tm[\"groups\"] = groups\n\tm[\"scenarios\"] = scenarios\n\treturn m, nil\n}\n\n// TODO: figure out something saner... refactor the sinks and how we deal with\n// metrics in general... so much pain and misery... :sob:\nfunc metricValueGetter(summaryTrendStats []string) func(metrics.Sink, time.Duration) map[string]float64 {\n\ttrendResolvers, err := metrics.GetResolversForTrendColumns(summaryTrendStats)\n\tif err != nil {\n\t\tpanic(err.Error()) // this should have been validated already\n\t}\n\n\treturn func(sink metrics.Sink, t time.Duration) (result map[string]float64) {\n\t\tswitch sink := sink.(type) {\n\t\tcase *metrics.CounterSink:\n\t\t\tresult = sink.Format(t)\n\t\t\tresult[\"rate\"] = sink.Rate(t)\n\t\tcase *metrics.GaugeSink:\n\t\t\tresult = sink.Format(t)\n\t\t\tresult[\"min\"] = sink.Min\n\t\t\tresult[\"max\"] = sink.Max\n\t\tcase *metrics.RateSink:\n\t\t\tresult = sink.Format(t)\n\t\t\tresult[\"passes\"] = float64(sink.Trues)\n\t\t\tresult[\"fails\"] = float64(sink.Total - sink.Trues)\n\t\tcase *metrics.TrendSink:\n\t\t\tresult = make(map[string]float64, len(summaryTrendStats))\n\t\t\tfor _, col := range summaryTrendStats {\n\t\t\t\tresult[col] = trendResolvers[col](sink)\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n\n// summarizeMetricsToObject transforms the summary objects in a way that's\n// suitable to pass to the JS runtime or export to JSON.\nfunc summarizeMetricsToObject(data *lib.LegacySummary, options lib.Options, setupData []byte) map[string]any {\n\tm := make(map[string]any)\n\tm[\"root_group\"] = exportGroup(data.RootGroup)\n\tm[\"options\"] = map[string]any{\n\t\t// TODO: improve when we can easily export all option values, including defaults?\n\t\t\"summaryTrendStats\": options.SummaryTrendStats,\n\t\t\"summaryTimeUnit\":   options.SummaryTimeUnit.String,\n\t\t\"noColor\":           data.NoColor, // TODO: move to the (runtime) options\n\t}\n\tm[\"state\"] = map[string]any{\n\t\t\"isStdOutTTY\":       data.UIState.IsStdOutTTY,\n\t\t\"isStdErrTTY\":       data.UIState.IsStdErrTTY,\n\t\t\"testRunDurationMs\": float64(data.TestRunDuration) / float64(time.Millisecond),\n\t}\n\n\tgetMetricValues := metricValueGetter(options.SummaryTrendStats)\n\n\tmetricsData := make(map[string]any)\n\tfor name, m := range data.Metrics {\n\t\tmetricData := map[string]any{\n\t\t\t\"type\":     m.Type.String(),\n\t\t\t\"contains\": m.Contains.String(),\n\t\t\t\"values\":   getMetricValues(m.Sink, data.TestRunDuration),\n\t\t}\n\n\t\tif len(m.Thresholds.Thresholds) > 0 {\n\t\t\tthresholds := make(map[string]any)\n\t\t\tfor _, threshold := range m.Thresholds.Thresholds {\n\t\t\t\tthresholds[threshold.Source] = map[string]any{\n\t\t\t\t\t\"ok\": !threshold.LastFailed,\n\t\t\t\t}\n\t\t\t}\n\t\t\tmetricData[\"thresholds\"] = thresholds\n\t\t}\n\t\tmetricsData[name] = metricData\n\t}\n\tm[\"metrics\"] = metricsData\n\n\tvar setupDataI any\n\tif setupData != nil {\n\t\tif err := json.Unmarshal(setupData, &setupDataI); err != nil {\n\t\t\t// TODO: log the error\n\t\t\treturn m\n\t\t}\n\t} else {\n\t\tsetupDataI = sobek.Undefined()\n\t}\n\n\tm[\"setup_data\"] = setupDataI\n\n\treturn m\n}\n\nfunc exportGroup(group *lib.Group) map[string]any {\n\tsubGroups := make([]map[string]any, len(group.OrderedGroups))\n\tfor i, subGroup := range group.OrderedGroups {\n\t\tsubGroups[i] = exportGroup(subGroup)\n\t}\n\n\tchecks := make([]map[string]any, len(group.OrderedChecks))\n\tfor i, check := range group.OrderedChecks {\n\t\tchecks[i] = map[string]any{\n\t\t\t\"name\":   check.Name,\n\t\t\t\"path\":   check.Path,\n\t\t\t\"id\":     check.ID,\n\t\t\t\"passes\": check.Passes,\n\t\t\t\"fails\":  check.Fails,\n\t\t}\n\t}\n\n\treturn map[string]any{\n\t\t\"name\":   group.Name,\n\t\t\"path\":   group.Path,\n\t\t\"id\":     group.ID,\n\t\t\"groups\": subGroups,\n\t\t\"checks\": checks,\n\t}\n}\n\nfunc getSummaryResult(rawResult sobek.Value) (map[string]io.Reader, error) {\n\tif common.IsNullish(rawResult) {\n\t\treturn nil, nil //nolint:nilnil // this is actually valid result in this case\n\t}\n\n\trawResultMap, ok := rawResult.Export().(map[string]any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"handleSummary() should return a map with string keys\")\n\t}\n\n\tresults := make(map[string]io.Reader, len(rawResultMap))\n\tfor path, val := range rawResultMap {\n\t\treaderVal, err := common.GetReader(val)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error handling summary object %s: %w\", path, err)\n\t\t}\n\t\tresults[path] = readerVal\n\t}\n\n\treturn results, nil\n}\n"
  },
  {
    "path": "internal/js/summary.js",
    "content": "/**\n * This file contains code used to generate a textual summary of tests results, as displayed\n * in the user's terminal at the end of a k6 test run, also known as \"end of test summary\".\n *\n * The main entry point is the `generateTextSummary` function, which takes the test data as well as a report\n * object containing results for checks, metrics, thresholds, groups, and scenarios, and returns a formatted\n * string summarizing the test results, ready to be written to the terminal.\n *\n * For convenience, the file also exports the `humanizeValue` function.\n */\nexports.humanizeValue = humanizeValue;\nexports.textSummary = generateTextSummary;\n\n/**\n * Generates a textual summary of test results, including checks, metrics, thresholds, groups, and scenarios.\n *\n * @param {Report} report - The report object containing thresholds, checks, metrics, groups, and scenarios.\n * @param {Object} options - Additional options that override defaults.\n * @returns {string} A formatted summary of the test results.\n */\nfunction generateTextSummary(report, options) {\n\tconst mergedOpts = Object.assign({}, defaultOptions, options);\n\n\t// Create a render context holding information such as indentation level to apply\n\tconst context = new RenderContext(0);\n\n\t// Create a formatter with default settings (colors enabled)\n\tconst formatter = new ANSIFormatter(mergedOpts);\n\n\tconst reportGenerator = new TestReportGenerator(\n\t\tformatter,\n\t\tcontext,\n\t\tmergedOpts,\n\t);\n\n\treturn reportGenerator.generate(report);\n}\n\n/**\n * Formats a metric value into a human-readable form, depending on the metric type and content.\n *\n * @param {number} val - The metric value.\n * @param {ReportMetric} metric - The metric object.\n * @param {string|null} timeUnit - The time unit for duration metrics.\n * @returns {string} The humanized metric value.\n */\nfunction humanizeValue(val, metric, timeUnit) {\n\tif (metric.type === 'rate') {\n\t\t// Truncate instead of round when decreasing precision to 2 decimal places\n\t\treturn (Math.trunc(val * 100 * 100) / 100).toFixed(2) + '%';\n\t}\n\n\tswitch (metric.contains) {\n\t\tcase 'data':\n\t\t\treturn humanizeBytes(val);\n\t\tcase 'time':\n\t\t\treturn humanizeDuration(val, timeUnit);\n\t\tdefault:\n\t\t\treturn toFixedNoTrailingZeros(val, 6);\n\t}\n}\n\n/**\n * @typedef {Object} Report\n * @property {Record<string, ReportThreshold>} thresholds - The thresholds report.\n * @property {ReportMetrics} metrics - The metrics report.\n * @property {Record<string, ReportGroup>} groups - The groups report.\n * @property {Record<string, ReportGroup>} scenarios - The scenarios report.\n */\n\n/**\n * @typedef {Object} ReportThreshold\n * @property {string} source - The threshold expression source.\n * @property {boolean} ok - Whether the threshold was satisfied or not.\n */\n\n/**\n * @typedef {Object} ReportGroup\n * @property {ReportChecks} checks - The checks report.\n * @property {ReportMetrics} metrics - The metrics report.\n * @property {Record<string, ReportGroup>} groups - The nested groups report.\n */\n\n/**\n * @typedef {Object} ReportMetric\n * @property {string} name - The name of the reported metric.\n * @property {\"counter\"|\"gauge\"|\"rate\"|\"trend\"} type - The type of the metric.\n * @property {\"time\"|\"data\"|\"default\"} contains - The type of data contained in the metric\n * @property {Record<string, number>} values - Key-value pairs of metric statistics (e.g. min, max, avg).\n * @property {EngineThreshold[]} [thresholds] - Optional array of thresholds associated with this metric.\n */\n\n/**\n * @typedef {Object} ReportMetrics\n * @property {Record<string, ReportMetric>} http - The HTTP metrics.\n * @property {Record<string, ReportMetric>} execution - The execution-related metrics.\n * @property {Record<string, ReportMetric>} network - The network-related metrics.\n * @property {Record<string, ReportMetric>} browser - The browser-related metrics.\n * @property {Record<string, ReportMetric>} webvitals - The web vitals metrics.\n * @property {Record<string, ReportMetric>} grpc - The grpc-related metrics.\n * @property {Record<string, ReportMetric>} websocket - The websocket-related metrics.\n * @property {Record<string, ReportMetric>} miscelaneous - The custom metrics.\n */\n\n/**\n * @typedef {Object} ReportChecks\n * @property {Record<string, ReportMetric>} metrics - The metrics for checks.\n * @property {EngineCheck[]} ordered_checks - The ordered checks.\n */\n\n/**\n * @typedef {Object} ReportMetricThresholds\n * @property {ReportMetric} metric - The metric object.\n * @property {ReportThreshold[]} thresholds - The thresholds for the metric.\n */\n\n/**\n * @typedef {Object} ReportData\n * @property {Record<string, ReportMetric>} metrics - Collection of metrics keyed by their names.\n */\n\n/**\n * @typedef {Object} EngineCheck\n * @property {string} id - The check ID.\n * @property {string} name - The check name.\n * @property {string} path - The check path.\n * @property {number} passes - The number of successful checks.\n * @property {number} fails - The number of failed checks.\n */\n\n/**\n * @typedef {Object} EngineThreshold\n * @property {string} source - The threshold expression source.\n * @property {boolean} ok - Whether the threshold was satisfied or not.\n */\n\n/**\n * @typedef {Object} Options\n * @property {boolean} [enableColors = true] - Whether to enable ANSI colors.\n * @property {string | null} [summaryTimeUnit = null] - The time unit for duration metrics.\n * @property {string[] | null} [summaryTrendStats = null] - The trend statistics to summarize.\n * @property {boolean} [sortByName = true] - Whether to sort metrics by name.\n */\n\n/**\n * Generates a textual summary of test results, including checks, metrics, thresholds, groups, and scenarios.\n */\nclass TestReportGenerator {\n\t/**\n\t * Constructs a TestReportGenerator with a specified formatter\n\t *\n\t * @param {ANSIFormatter} formatter - The ANSI formatter to use for text decoration.\n\t * @param {RenderContext} renderContext - The render context to use for text rendering.\n\t * @param {Options} [options = {}]\n\t */\n\tconstructor(formatter, renderContext, options = {}) {\n\t\tthis.formatter = formatter;\n\t\tthis.renderContext = renderContext;\n\t\tthis.options = options;\n\t}\n\n\t/**\n\t * Generates a textual summary of test results, including checks, metrics, thresholds, groups, and scenarios.\n\t *\n\t * @param {Report} report - The report object containing thresholds, checks, metrics, groups, and scenarios as provided by k6.\n\t * @returns {string} - A formatted summary of the test results.\n\t */\n\tgenerate(report) {\n\t\tconst reportBuilder = new ReportBuilder(\n\t\t\tthis.formatter,\n\t\t\tthis.renderContext,\n\t\t\tthis.options,\n\t\t);\n\t\t// Compute global alignment before building sections\n\t\treportBuilder._computeGlobalMaxNameWidth(report);\n\n\t\treturn reportBuilder\n\t\t\t.addThresholds(report.thresholds)\n\t\t\t.addTotalResults(report)\n\t\t\t.addGroups(report.groups)\n\t\t\t.addScenarios(report.scenarios)\n\t\t\t.build();\n\t}\n}\n\n/**\n * Exposes methods for generating a textual summary of test results.\n */\nclass ReportBuilder {\n\t/**\n\t * Creates a new ReportBuilder with a specified formatter and options.\n\t *\n\t * @param {ANSIFormatter} formatter - The ANSI formatter to use for text decoration.\n\t * @param {RenderContext} renderContext - The render context to use for text rendering.\n\t * @param options\n\t */\n\tconstructor(formatter, renderContext, options) {\n\t\tthis.formatter = formatter;\n\t\tthis.renderContext = renderContext;\n\t\tthis.options = options;\n\t\tthis.sections = [];\n\t\tthis.globalMaxNameWidth = 0;\n\t}\n\n\t/**\n\t * Adds a thresholds section to the report.\n\t *\n\t * @param {Record<string, ReportThreshold>} thresholds - The thresholds to add to the report.\n\t * @returns {ReportBuilder}\n\t */\n\taddThresholds(thresholds) {\n\t\tif (!thresholds || Object.keys(thresholds).length === 0) return this;\n\n\t\tthis.sections.push({\n\t\t\ttitle: 'THRESHOLDS',\n\t\t\tcontent: this._renderThresholds(thresholds),\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a total results section to the report.\n\t *\n\t * @param {Report} report - The report object containing thresholds, checks, metrics, groups, and scenarios as provided by k6.\n\t * @returns {ReportBuilder}\n\t */\n\taddTotalResults(report) {\n\t\tthis.sections.push({\n\t\t\ttitle: 'TOTAL RESULTS',\n\t\t\tcontent: [\n\t\t\t\t...this._renderChecks(report.checks),\n\t\t\t\t...this._renderMetrics(report.metrics, this.renderContext, this.globalMaxNameWidth),\n\t\t\t],\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds groups sections to the report.\n\t *\n\t * @param {Record<string, ReportGroup>} groups - The groups to add to the report.\n\t * @returns {ReportBuilder}\n\t */\n\taddGroups(groups) {\n\t\tif (!groups) return this;\n\n\t\tObject.entries(groups)\n\t\t\t.forEach(([groupName, groupData]) => {\n\t\t\t\tthis.sections.push({\n\t\t\t\t\ttitle: `GROUP: ${groupName}`,\n\t\t\t\t\tcontent: this._renderGroupContent(groupData),\n\t\t\t\t});\n\t\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds scenarios sections to the report.\n\t *\n\t * @param {Record<string, ReportGroup>} scenarios - The scenarios to add to the report.\n\t * @returns {ReportBuilder}\n\t */\n\taddScenarios(scenarios) {\n\t\tif (!scenarios) return this;\n\n\t\tObject.entries(scenarios)\n\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t.forEach(([scenarioName, scenarioData]) => {\n\t\t\t\tthis.sections.push({\n\t\t\t\t\ttitle: `SCENARIO: ${scenarioName}`,\n\t\t\t\t\tcontent: this._renderScenarioContent(scenarioData),\n\t\t\t\t});\n\t\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Computes the global maximum name width across all metrics in all sections.\n\t * This ensures consistent colon alignment across the entire report.\n\t *\n\t * @param {Report} report - The complete report object\n\t * @returns {void}\n\t */\n\t_computeGlobalMaxNameWidth(report) {\n\t\tconst allMetrics = {};\n\t\tconst renderContext = this.renderContext.indentedContext(1);\n\n\t\t// Collect metrics from total results\n\t\tif (report.metrics) {\n\t\t\tObject.assign(allMetrics, ...Object.values(report.metrics))\n\t\t}\n\n\t\t// Collect metrics from groups\n\t\tif (report.groups) {\n\t\t\tthis._collectMetricsFromGroups(report.groups, allMetrics);\n\t\t}\n\n\t\t// Collect metrics from scenarios\n\t\tif (report.scenarios) {\n\t\t\tthis._collectMetricsFromGroups(report.scenarios, allMetrics);\n\t\t}\n\n\t\t// Compute the global max name width\n\t\tthis.globalMaxNameWidth = Object.keys(allMetrics).reduce((max, name) => {\n\t\t\treturn Math.max(max, strWidth(renderContext.indent(renderMetricDisplayName(name))));\n\t\t})\n\t}\n\n\t/**\n\t * Recursively collects metrics from groups/scenarios and their nested groups.\n\t *\n\t * @param {Record<string, ReportGroup>} groups - The groups to collect metrics from\n\t * @param {Object} allMetrics - The accumulator object for all metrics\n\t * @returns {void}\n\t */\n\t_collectMetricsFromGroups(groups, allMetrics) {\n\t\tObject.values(groups).forEach((group) => {\n\t\t\tif (group.metrics) {\n\t\t\t\tObject.assign(allMetrics, ...Object.values(group.metrics))\n\t\t\t}\n\t\t\tif (group.groups) {\n\t\t\t\tthis._collectMetricsFromGroups(group.groups, allMetrics);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Builds the final report by concatenating all sections together, resulting\n\t * in a formatted string ready to be printed to the terminal.\n\t *\n\t * @returns {string}\n\t */\n\tbuild() {\n\t\treturn this.sections\n\t\t\t.map((section) => [\n\t\t\t\trenderTitle(section.title, this.formatter, this.renderContext),\n\t\t\t\t...section.content,\n\t\t\t\t'\\n',\n\t\t\t])\n\t\t\t.flat()\n\t\t\t.reduce((acc, curr) => {\n\t\t\t\treturn (curr === '\\n') ? acc + curr : acc + '\\n' + curr;\n\t\t\t}, '');\n\t}\n\n\t/**\n\t * @param {Record<string, ReportThreshold>} thresholds\n\t * @param {RenderContext} [renderContext]\n\t * @returns {string[]}\n\t * @private\n\t */\n\t_renderThresholds(thresholds, renderContext) {\n\t\t// The thresholds list should be indent one level higher than the title\n\t\trenderContext = renderContext || this.renderContext;\n\t\trenderContext = renderContext.indentedContext(1);\n\n\t\t// Implement threshold rendering logic\n\t\treturn renderThresholds(\n\t\t\tthis._processThresholds(thresholds),\n\t\t\tthis.formatter,\n\t\t\trenderContext,\n\t\t\tthis.options,\n\t\t);\n\t}\n\n\t/**\n\t * @param checks\n\t * @param {RenderContext} [renderContext] - The render context to use for text rendering.\n\t * @returns {string[]}\n\t * @private\n\t */\n\t_renderChecks(checks, renderContext) {\n\t\trenderContext = renderContext || this.renderContext;\n\n\t\treturn checks\n\t\t\t? [...renderChecks(checks, this.formatter, renderContext, this.options), '\\n']\n\t\t\t: [];\n\t}\n\n\t/**\n\t * @param {ReportMetrics} metrics - The metrics to render.\n\t * @param {RenderContext} [renderContext] - The render context to use for text rendering.\n\t * @param {number} [globalMaxNameWidth] - Optional global max name width for cross-section alignment.\n\t * @returns {string[]}\n\t * @private\n\t */\n\t_renderMetrics(metrics, renderContext, globalMaxNameWidth) {\n\t\trenderContext = renderContext || this.renderContext;\n\t\trenderContext = renderContext.indentedContext(1);\n\n\t\t// Collect all metrics into a single object, so we can precompute all formatting information\n\t\tconst allMetrics = Object.entries(metrics).reduce((acc, [_, metrics]) => {\n\t\t\tObject.assign(acc, metrics);\n\t\t\treturn acc;\n\t\t}, {});\n\n\t\t// Precompute all formatting information, using global maxNameWidth if provided\n\t\tconst summaryInfo = computeSummaryInfo(\n\t\t\tallMetrics,\n\t\t\trenderContext,\n\t\t\tthis.options,\n\t\t\tglobalMaxNameWidth || this.globalMaxNameWidth,\n\t\t);\n\n\t\t// Implement metrics rendering logic\n\t\treturn Object.entries(metrics)\n\t\t\t.filter(\n\t\t\t\t([_, sectionMetrics]) => Object.keys(sectionMetrics).length > 0,\n\t\t\t)\n\t\t\t.reduce(\n\t\t\t\t(acc, [sectionName, sectionMetrics]) => (sectionName === \"custom\")\n\t\t\t\t\t? [[sectionName, sectionMetrics], ...acc]\n\t\t\t\t\t: [...acc, [sectionName, sectionMetrics]]\n\t\t\t\t, [])\n\t\t\t.flatMap(([sectionName, sectionMetrics]) => [\n\t\t\t\trenderContext.indent(\n\t\t\t\t\tthis.formatter.boldify(sectionName.toUpperCase()),\n\t\t\t\t),\n\t\t\t\t...renderMetrics(\n\t\t\t\t\tsectionMetrics,\n\t\t\t\t\tsummaryInfo,\n\t\t\t\t\tthis.formatter,\n\t\t\t\t\trenderContext,\n\t\t\t\t\tthis.options,\n\t\t\t\t),\n\t\t\t\t'\\n',\n\t\t\t]);\n\t}\n\n\t/**\n\t * @param {ReportGroup} group - The group data to render.\n\t * @param {RenderContext} [renderContext] - The render context to use for text rendering.\n\t * @returns {string[]}\n\t * @private\n\t */\n\t_renderGroupContent(group, renderContext) {\n\t\trenderContext = renderContext || this.renderContext;\n\n\t\t// Implement group content rendering\n\t\treturn [\n\t\t\t...this._renderChecks(group.checks, renderContext),\n\t\t\t...this._renderMetrics(group.metrics, renderContext, this.globalMaxNameWidth),\n\t\t\t...(group.groups ? this._renderNestedGroups(group.groups, renderContext) : []),\n\t\t];\n\t}\n\n\t/**\n\t * @param {ReportGroup} scenarioData - The scenario data to render.\n\t * @param {RenderContext} [renderContext] - The render context to use for text rendering.\n\t * @returns {string[]}\n\t * @private\n\t */\n\t_renderScenarioContent(scenarioData, renderContext) {\n\t\trenderContext = renderContext || this.renderContext;\n\n\t\t// Similar to group content rendering\n\t\treturn [\n\t\t\t...this._renderChecks(scenarioData.checks, renderContext),\n\t\t\t...this._renderMetrics(scenarioData.metrics, renderContext, this.globalMaxNameWidth),\n\t\t\t...(scenarioData.groups\n\t\t\t\t? this._renderNestedGroups(scenarioData.groups, renderContext)\n\t\t\t\t: []),\n\t\t];\n\t}\n\n\t/**\n\t * @param {Record<string, ReportGroup>} groups - The nested groups data to render.\n\t * @param {RenderContext} [renderContext] - The render context to use for text rendering.\n\t * @returns {string[]}\n\t * @private\n\t */\n\t_renderNestedGroups(groups, renderContext) {\n\t\trenderContext = renderContext || this.renderContext;\n\t\trenderContext = renderContext.indentedContext(1);\n\n\t\t// Render nested groups recursively\n\t\treturn Object.entries(groups)\n\t\t\t.flatMap(([groupName, groupData]) => [\n\t\t\t\trenderTitle(`GROUP: ${groupName}`, this.formatter, renderContext, {\n\t\t\t\t\tprefix: subtitlePrefix,\n\t\t\t\t\tsuffix: '\\n',\n\t\t\t\t}),\n\t\t\t\t...this._renderGroupContent(groupData, renderContext),\n\t\t\t]);\n\t}\n\n\t// Private rendering methods\n\t/**\n\t *\n\t * @param {ReportMetricThresholds} thresholds - The thresholds data to render.\n\t * @returns {Record<string, ReportMetric>}\n\t * @private\n\t */\n\t_processThresholds(thresholds) {\n\t\t// Transform thresholds into a format suitable for rendering\n\t\tconst metrics = {};\n\t\tObject.values(thresholds).forEach((threshold) => {\n\t\t\tmetrics[threshold.metric.name] = {\n\t\t\t\t...threshold.metric,\n\t\t\t\tthresholds: threshold.thresholds,\n\t\t\t};\n\t\t});\n\t\treturn metrics;\n\t}\n}\n\n/**\n * RenderContext is a helper class that provides methods for rendering text\n * with indentation.\n *\n * It is used to keep track of the current indentation level and provide\n * methods for rendering text with the correct indentation.\n *\n * It also facilitates the creation of new RenderContext instances with\n * different indentation levels. That way the indentation level can be\n * easily adjusted relatively to a parent indentation level without having\n * to manage some dedicated state manually.\n */\nclass RenderContext {\n\tconstructor(baseIndentationLevel = 0) {\n\t\tthis.baseIndentationLevel = baseIndentationLevel;\n\t}\n\n\t/**\n\t * Returns a string of spaces for a given indentation level.\n\t *\n\t * @param {number} [level]\n\t * @returns {string}\n\t */\n\tindentLevel(level = 1) {\n\t\treturn ' '.repeat((this.baseIndentationLevel + level) * 2);\n\t}\n\n\t/**\n\t * @param {string} text - The text to indent.\n\t * @param {number} [level]\n\t * @returns {string}\n\t */\n\tindent(text, level = 1) {\n\t\treturn this.indentLevel(level) + text;\n\t}\n\n\t/**\n\t * indentedContext returns a new RenderContext with an incremented base indentation level.\n\t *\n\t * This allows to easily obtain a new RenderContext from a parent one with an\n\t * increased indentation level.\n\t *\n\t * @param {number} increment - The increment to apply to the base indentation level.\n\t * @returns {RenderContext}\n\t */\n\tindentedContext(increment = 1) {\n\t\treturn new RenderContext(this.baseIndentationLevel + increment);\n\t}\n}\n\n/**\n * ANSIFormatter provides methods for decorating text with ANSI color and style codes.\n */\nclass ANSIFormatter {\n\t/**\n\t * Constructs an ANSIFormatter with configurable color and styling options\n\t *\n\t * @param {Object} options - Configuration options for formatting\n\t * @param {boolean} [options.enableColors=true] - Whether to enable color output\n\t */\n\tconstructor(options = {}) {\n\t\tthis.options = {\n\t\t\tenableColors: true,\n\t\t\t...options,\n\t\t};\n\t}\n\n\t/**\n\t * Decorates text with ANSI color and style.\n\t *\n\t * @param {string} text - The text to decorate.\n\t * @param {ANSIColor} color - The ANSI color to apply.\n\t * @param {...ANSIStyle} styles - optional additional styles to apply.\n\t * @returns {string} - Decorated text, or plain text if colors are disabled.\n\t */\n\tdecorate(text, color, ...styles) {\n\t\tif (!this.options.enableColors) {\n\t\t\treturn text;\n\t\t}\n\n\t\tconst colorCode = ANSIColors[color] || ANSIColors.white;\n\t\tconst styleCodes = styles\n\t\t\t.map((style) => ANSIStyles[style])\n\t\t\t.filter(Boolean);\n\n\t\tconst fullCodes = styleCodes.length\n\t\t\t? [...styleCodes, colorCode].join(';')\n\t\t\t: colorCode;\n\n\t\tconst fullSequence = `\\x1b[${fullCodes}m`;\n\n\t\treturn `${fullSequence}${text}\\x1b[0m`;\n\t}\n\n\t/**\n\t * Applies bold styling to text\n\t *\n\t * @param {string} text - Text to make bold\n\t * @returns {string} Bold text\n\t */\n\tboldify(text) {\n\t\tif (!this.options.enableColors) {\n\t\t\treturn text;\n\t\t}\n\t\treturn `\\u001b[1m${text}\\x1b[0m`;\n\t}\n}\n\n/**\n * ANSIColor maps ANSI color names to their respective escape codes.\n *\n * @typedef {'reset'|'black'|'red'|'green'|'yellow'|'blue'|'magenta'|'cyan'|\n *           'white'|'brightRed'|'brightGreen'|'brightYellow'} ANSIColor\n *\n * @typedef {Record<ANSIColor, string>} ANSIColors\n */\nconst ANSIColors = {\n\treset: '\\x1b[0m',\n\n\t// Standard Colors\n\tblack: '30',\n\tred: '31',\n\tgreen: '32',\n\tyellow: '33',\n\tblue: '34',\n\tmagenta: '35',\n\tcyan: '36',\n\twhite: '37',\n\n\t// Bright Colors\n\tbrightRed: '91',\n\tbrightGreen: '92',\n\tbrightYellow: '93',\n};\n\n/**\n * ANSIStyle maps ANSI style names to their respective escape codes.\n *\n * @typedef {'bold' | 'faint' | 'underline' | 'reversed'} ANSIStyle\n *\n * @typedef {Record<ANSIStyle, string>} ANSIStyles\n */\nconst ANSIStyles = {\n\tbold: '1',\n\tfaint: '2',\n\tunderline: '4',\n\treversed: '7',\n};\n\n/**\n * Renders a section title with a specified formatter, indentation level, and options.\n *\n * For example, a bold section title at first indentation level with a block prefix and newline suffix:\n *  █ THRESHOLDS\n *\n * @param {string} title - The section title to render.\n * @param {ANSIFormatter} formatter - The ANSI formatter to use for text decoration.\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @param {Options & Object} options - Additional options for rendering the section title.\n * @param {string} [options.prefix=titlePrefix] - The prefix to use for the section title.\n * @param {string} [options.suffix='\\n'] - The suffix to use for the section title.\n * @returns {string} - The formatted section title.\n */\nfunction renderTitle(\n\ttitle,\n\tformatter,\n\trenderContext,\n\toptions = {prefix: titlePrefix, suffix: '\\n'},\n) {\n\treturn renderContext.indent(\n\t\t`${options.prefix} ${formatter.boldify(title)} ${options.suffix || ''}`,\n\t);\n}\n\n/**\n * Renders a single check into a formatted line ready for output.\n *\n * @param {EngineCheck} check - The check object with name, passes and fails\n * @param {ANSIFormatter} formatter - ANSI formatter used for decorating text.\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @returns {string} - A formatted line summarizing the check.\n */\nfunction renderCheck(check, formatter, renderContext) {\n\t// If the check was successful, immediately render a green line indicating success\n\tif (check.fails === 0) {\n\t\treturn renderContext.indent(\n\t\t\tformatter.decorate(successMark + ' ' + check.name, 'green'),\n\t\t);\n\t}\n\n\t// Other we want to display both the check name and the percentage of successful checks\n\t// in red, along with the number of passes and fails.\n\tconst successfulPct = Math.floor(\n\t\t(100 * check.passes) / (check.passes + check.fails),\n\t);\n\n\tconst checkName = formatter.decorate(failMark + ' ' + check.name, 'red');\n\tconst results = formatter.decorate(\n\t\tsubtitlePrefix +\n\t\t'  ' +\n\t\tsuccessfulPct +\n\t\t'% — ' +\n\t\tsuccessMark +\n\t\t' ' +\n\t\tcheck.passes +\n\t\t' / ' +\n\t\tfailMark +\n\t\t' ' +\n\t\tcheck.fails,\n\t\t'red',\n\t);\n\n\treturn (\n\t\trenderContext.indent(checkName) +\n\t\t'\\n' +\n\t\trenderContext.indent(results, renderContext.baseIndentationLevel + 1)\n\t);\n}\n\n/**\n * Renders checks into a formatted set of lines ready for display in the terminal.\n *\n * @param {ReportChecks} checks\n * @param formatter\n * @param {RenderContext} renderContext\n * @param options\n * @returns {*[]}\n */\nfunction renderChecks(checks, formatter, renderContext, options = {}) {\n\t// If no checks exist, return empty array\n\tif (!checks || !checks.ordered_checks) {\n\t\treturn [];\n\t}\n\n\t// Add indentation to the render context for checks\n\trenderContext = renderContext.indentedContext(1);\n\n\tconst {showPassedChecks = true, showFailedChecks = true} = options;\n\n\t// Process each check and filter based on options\n\tconst renderedChecks = checks.ordered_checks\n\t\t.filter((check) => {\n\t\t\t// Filter logic for passed/failed checks\n\t\t\tif (check.fails === 0 && !showPassedChecks) return false;\n\t\t\treturn !(check.fails > 0 && !showFailedChecks);\n\t\t})\n\t\t.map((check) => renderCheck(check, formatter, renderContext));\n\n\t// Precompute all formatting information\n\tconst summaryInfo = computeSummaryInfo(\n\t\tchecks.metrics,\n\t\trenderContext,\n\t\toptions,\n\t);\n\n\t// Render metrics for checks if they exist\n\tconst checkMetrics = checks.metrics\n\t\t? renderMetrics(checks.metrics, summaryInfo, formatter, renderContext, {\n\t\t\t...options,\n\t\t\tsortByName: false,\n\t\t})\n\t\t: [];\n\n\t// Combine metrics and checks\n\treturn [...checkMetrics, '\\n', ...renderedChecks];\n}\n\n/**\n * Summarizes metrics into an array of formatted lines ready to be printed to stdout.\n *\n * @param {Record<string, ReportMetric>} metrics - The data object containing metrics.\n * @param {SummaryInfo} summaryInfo - An object containing summary information such as maximum name width and trend columns.\n * @param {ANSIFormatter} formatter - An ANSIFormatter function for ANSI colors.\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @param {Options} options - Display options merged with defaultOptions.\n * @returns {string[]}\n */\nfunction renderMetrics(\n\tmetrics,\n\tsummaryInfo,\n\tformatter,\n\trenderContext,\n\toptions,\n) {\n\t// Extract all metric names\n\tlet metricNames = Object.keys(metrics);\n\n\t// If sorting by name is required, do it now\n\tif (options.sortByName) {\n\t\tmetricNames = sortMetricsByName(metricNames);\n\t}\n\n\t// Format each metric line\n\treturn metricNames.map((name) => {\n\t\tconst metric = metrics[name];\n\t\treturn renderMetricLine(\n\t\t\tname,\n\t\t\tmetric,\n\t\t\tsummaryInfo,\n\t\t\toptions,\n\t\t\tformatter,\n\t\t\trenderContext,\n\t\t);\n\t});\n}\n\n/**\n * Renders each thresholds results into a formatted set of lines ready for display in the terminal.\n *\n * @param {Record<string, ReportMetric>} metrics - The data object containing metrics.\n * @param {ANSIFormatter} formatter - ANSI formatter used for decorating text.\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @param {Object} options - Options merged with defaults.\n * @returns {string[]} - Array of formatted lines including threshold statuses.\n */\nfunction renderThresholds(metrics, formatter, renderContext, options) {\n\t// Extract and optionally sort metric names\n\tlet metricNames = Object.keys(metrics);\n\tif (options.sortByName) {\n\t\tmetricNames = sortMetricsByName(metricNames);\n\t}\n\n\t// Precompute all formatting information\n\tconst summaryInfo = computeSummaryInfo(\n\t\tmetrics,\n\t\trenderContext,\n\t\toptions,\n\t);\n\n\t// Format each threshold line by preparing each metric affected by a threshold, as\n\t// well as the thresholds results for each expression.\n\tconst result = [];\n\tfor (const name of metricNames) {\n\t\tconst parentName = name.split('{', 1)[0];\n\t\tconst isSubmetric = name.length > parentName.length;\n\t\tconst parentMetricExists = !!metrics[parentName];\n\n\t\tconst innerContext = (isSubmetric && parentMetricExists)\n\t\t\t? renderContext.indentedContext()\n\t\t\t: renderContext;\n\n\t\tconst line = renderMetricNameForThresholds(\n\t\t\tname,\n\t\t\tparentName,\n\t\t\tisSubmetric,\n\t\t\tparentMetricExists,\n\t\t\tinnerContext\n\t\t);\n\t\tresult.push(line);\n\n\t\tconst metric = metrics[name];\n\t\tif (metric.thresholds) {\n\t\t\tconst thresholdLines = renderThresholdResults(\n\t\t\t\tmetric,\n\t\t\t\tsummaryInfo,\n\t\t\t\tformatter,\n\t\t\t\tinnerContext,\n\t\t\t);\n\t\t\tresult.push(...thresholdLines, '\\n');\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * Renders each threshold result into a formatted set of lines ready for display in the terminal.\n *\n * @param {ReportMetric} metric - The metric with the thresholds to render.\n * @param {SummaryInfo} summaryInfo - An object containing summary information such as maximum name width and trend columns.\n * @param {ANSIFormatter} formatter - ANSIFormatter used for decorating text.\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @returns {string[]} - An array of formatted lines including threshold statuses.\n */\nfunction renderThresholdResults(\n\tmetric,\n\tsummaryInfo,\n\tformatter,\n\trenderContext,\n) {\n\tconst lines = [];\n\n\tforEach(metric.thresholds, (_, threshold) => {\n\t\tconst isSatisfied = threshold.ok;\n\t\tconst statusText = isSatisfied\n\t\t\t? formatter.decorate(successMark, 'green')\n\t\t\t: formatter.decorate(failMark, 'red');\n\n\t\tconst sourceText = formatter.decorate(\n\t\t\t`'${threshold.source.trim()}'`,\n\t\t\t'white',\n\t\t);\n\n\t\tconst metricValueText = renderMetricValueForThresholds(\n\t\t\tmetric,\n\t\t\tthreshold,\n\t\t\tsummaryInfo,\n\t\t\tformatter,\n\t\t)\n\n\t\t// Here we push a line describing the threshold's result\n\t\tlines.push(\n\t\t\trenderContext.indent([statusText, sourceText, metricValueText].join(' ')),\n\t\t);\n\t});\n\n\treturn lines;\n}\n\n/**\n * Renders a metric line into a formatted string for display.\n *\n * @param {string} name - The name of the metric.\n * @param {ReportMetric} metric - The metric object containing details about the metric.\n * @param {SummaryInfo} info - An object containing summary information such as maximum name width and trend columns.\n * @param {Options} options - Configuration options for summarizing metrics.\n * @param {ANSIFormatter} formatter - A function to apply ANSI colors to text.\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @returns {string} - The formatted metric line.\n */\nfunction renderMetricLine(\n\tname,\n\tmetric,\n\tinfo,\n\toptions,\n\tformatter,\n\trenderContext,\n) {\n\tconst {maxNameWidth} = info;\n\n\tconst displayedName = renderMetricDisplayName(name);\n\tconst fmtIndent = renderContext.indentLevel();\n\n\t// Compute the trailing dots:\n\t// Ensure longest metric name gets exactly 3 dots, shorter names get more for alignment\n\tconst currentNameWidth = strWidth(displayedName) + strWidth(fmtIndent);\n\tconst dotsCount = Math.max(3, maxNameWidth - currentNameWidth + 3);\n\tconst dottedName =\n\t\tdisplayedName +\n\t\tformatter.decorate('.'.repeat(dotsCount) + ':', 'white', 'faint');\n\n\tconst dataPart =\n\t\tmetric.type === 'trend'\n\t\t\t? renderTrendData(name, info, formatter)\n\t\t\t: renderNonTrendData(name, info, formatter);\n\n\treturn renderContext.indent(dottedName + ' ' + dataPart);\n}\n\n/**\n * Formats a metric or submetric line for the thresholds' section output.\n *\n * @param {string} name - The name of the metric\n * @param {string} parentName - The name of the parent metric\n * @param {boolean} isSubmetric - Whether the metric is a submetric\n * @param {boolean} parentMetricExists - In case of submetric, whether the parent metric exists\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @returns {string} - The metric name report line\n */\nfunction renderMetricNameForThresholds(\n\tname,\n\tparentName,\n\tisSubmetric,\n\tparentMetricExists,\n\trenderContext,\n) {\n\t// If it's a parent metric, or it's a submetric,\n\t// which parent metric is not included in results, we just print the name.\n\tif (!isSubmetric || !parentMetricExists) {\n\t\treturn renderContext.indent(name);\n\t}\n\n\t// Otherwise, we only print the labels.\n\treturn renderContext.indent(name.substring(parentName.length));\n}\n\n/**\n * Formats the metric's value for the thresholds' section output.\n *\n * @param {ReportMetric} metric - The metric for which value will be rendered.\n * @param {EngineThreshold} threshold - The threshold to use for rendering.\n * @param {SummaryInfo} info - An object containing summary information such as maximum name width and trend columns.\n * @param {ANSIFormatter} formatter - ANSIFormatter used for decorating text.\n * @returns {string} - The metric's value line in the form: `{agg}={value}`\n */\nfunction renderMetricValueForThresholds(\n\tmetric,\n\tthreshold,\n\tinfo,\n\tformatter,\n) {\n\tconst {trendStats, trendCols, trendKeys, nonTrendValues, nonTrendExtras} = info;\n\tconst thresholdAgg = threshold.source.split(/[=><]/)[0].trim();\n\n\tlet value;\n\tswitch (metric.type) {\n\t\tcase 'trend':\n\t\t\tconst trendStatIndex = trendStats.indexOf(thresholdAgg);\n\t\t\tvalue = (trendStatIndex !== -1)\n\t\t\t\t? trendCols[metric.name]?.[trendStatIndex]\n\t\t\t\t: trendKeys[metric.name]?.[thresholdAgg];\n\t\t\tbreak;\n\t\tcase 'counter':\n\t\t\tvalue = (thresholdAgg === 'count')\n\t\t\t\t? nonTrendValues[metric.name]\n\t\t\t\t: nonTrendExtras[metric.name][0];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tvalue = nonTrendValues[metric.name];\n\t}\n\n\treturn [\n\t\tformatter.decorate(thresholdAgg, 'white'),\n\t\tformatter.decorate(value, 'cyan')\n\t].join('=');\n}\n\n/**\n * Format data for trend metrics.\n */\nfunction renderTrendData(name, info, formatter) {\n\tconst {trendStats, trendCols, trendColMaxLens} = info;\n\tconst cols = trendCols[name];\n\n\treturn cols\n\t\t.map((col, i) => {\n\t\t\tconst statName = trendStats[i];\n\t\t\tconst padding = ' '.repeat(trendColMaxLens[i] - strWidth(col));\n\t\t\treturn statName + '=' + formatter.decorate(col, 'cyan') + padding;\n\t\t})\n\t\t.join(' ');\n}\n\n/**\n * Format data for non-trend metrics.\n *\n * @param {string} name - The metric name.\n * @param {SummaryInfo} info - The summary information object.\n * @param {ANSIFormatter} formatter - A decoration function for ANSI colors.\n */\nfunction renderNonTrendData(name, info, formatter) {\n\tconst {\n\t\tnonTrendValues,\n\t\tnonTrendExtras,\n\t\tmaxNonTrendValueLen,\n\t\tnonTrendExtraMaxLens,\n\t} = info;\n\n\tconst value = nonTrendValues[name];\n\tconst extras = nonTrendExtras[name] || [];\n\n\tlet result = formatter.decorate(value, 'cyan');\n\tresult += ' '.repeat(maxNonTrendValueLen - strWidth(value));\n\n\tif (extras.length === 1) {\n\t\t// Single extra value\n\t\tresult += ' ' + formatter.decorate(extras[0], 'cyan', 'faint');\n\t} else if (extras.length > 1) {\n\t\t// Multiple extras need their own spacing\n\t\tconst parts = extras.map((val, i) => {\n\t\t\tconst extraSpace = ' '.repeat(\n\t\t\t\tnonTrendExtraMaxLens[i] - strWidth(val),\n\t\t\t);\n\t\t\treturn formatter.decorate(val, 'cyan', 'faint') + extraSpace;\n\t\t});\n\t\tresult += ' ' + parts.join(' ');\n\t}\n\n\treturn result;\n}\n\n/**\n *\n * @param {number} value\n * @param {string} stat\n * @param {ReportMetric} metric\n * @param {Options} options\n * @returns {string}\n */\nfunction renderTrendValue(value, stat, metric, options) {\n\tif (stat === 'count') {\n\t\treturn value.toString();\n\t}\n\treturn humanizeValue(value, metric, options.summaryTimeUnit);\n}\n\n/**\n * Compute all necessary formatting information such as maximum lengths, trend columns and non-trend values for each\n * metric.\n *\n * @typedef {Object} SummaryInfo\n * @property {number} maxNameWidth - The maximum width of the metric names.\n * @property {Object} nonTrendValues - The non-trend metric values.\n * @property {Object} nonTrendExtras - The non-trend metric extras.\n * @property {Object} trendCols - The trend columns.\n * @property {Object} trendKeys - The trend keys (values that aren't included within `trendStats`).\n * @property {number[]} trendColMaxLens - The trend column maximum lengths.\n * @property {number} numTrendColumns - The number of trend columns.\n * @property {string[]} trendStats - The trend statistics.\n * @property {number} maxNonTrendValueLen - The maximum non-trend value length.\n * @property {number[]} nonTrendExtraMaxLens - The non-trend extra maximum lengths.\n *\n * @param {Record<string, ReportMetric>} metrics - The data object containing metrics.\n * @param {RenderContext} renderContext - The render context to use for text rendering.\n * @param {Options} options - Display options merged with defaultOptions.\n * @param {number} [globalMaxNameWidth] - Optional global max name width for cross-section alignment.\n * @returns {SummaryInfo}\n */\nfunction computeSummaryInfo(metrics, renderContext, options, globalMaxNameWidth) {\n\tconst trendStats = options.summaryTrendStats;\n\tconst numTrendColumns = trendStats.length;\n\n\tconst nonTrendValues = {};\n\tconst nonTrendExtras = {};\n\tconst trendCols = {};\n\n\t// While \"trendCols\" contain the values for each \"trendStats\" aggregation (e.g. p(90) as a sorted array,\n\t// \"trendKeys\" is used to store specific aggregation values that aren't part of \"trendStats\"; mainly for thresholds.\n\tconst trendKeys = {};\n\n\t// Use global maxNameWidth if provided, otherwise compute locally\n\tlet maxNameWidth = globalMaxNameWidth || 0;\n\tlet maxNonTrendValueLen = 0;\n\tlet nonTrendExtraMaxLens = []; // FIXME: \"lens\"?\n\n\t// Initialize tracking arrays for trend widths\n\tconst trendColMaxLens = new Array(numTrendColumns).fill(0);\n\n\tlet metricNames = Object.keys(metrics);\n\t// If sorting by name is required, do it now\n\tif (options.sortByName) {\n\t\tmetricNames = sortMetricsByName(metricNames);\n\t}\n\n\tfor (const name of metricNames) {\n\t\tconst metric = metrics[name];\n\n\t\t// Only compute maxNameWidth if not provided globally\n\t\tif (!globalMaxNameWidth) {\n\t\t\tconst displayName = renderContext.indent(\n\t\t\t\trenderMetricDisplayName(name),\n\t\t\t);\n\t\t\tmaxNameWidth = Math.max(maxNameWidth, strWidth(displayName));\n\t\t}\n\n\t\tif (metric.type === 'trend') {\n\t\t\tconst keys = Object.keys(metric.values).reduce((acc, key) => {\n\t\t\t\tif (!trendStats.includes(key)) {\n\t\t\t\t\tacc[key] = renderTrendValue(metric.values[key], key, metric, options);\n\t\t\t\t}\n\t\t\t\treturn acc;\n\t\t\t}, {});\n\n\t\t\tconst cols = trendStats.map((stat) =>\n\t\t\t\trenderTrendValue(metric.values[stat], stat, metric, options),\n\t\t\t);\n\n\t\t\t// Compute max column widths\n\t\t\tcols.forEach((col, index) => {\n\t\t\t\ttrendColMaxLens[index] = Math.max(\n\t\t\t\t\ttrendColMaxLens[index],\n\t\t\t\t\tstrWidth(col),\n\t\t\t\t);\n\t\t\t});\n\t\t\ttrendCols[name] = cols;\n\t\t\ttrendKeys[name] = keys;\n\t\t} else {\n\t\t\tconst values = nonTrendMetricValueForSum(\n\t\t\t\tmetric,\n\t\t\t\toptions.summaryTimeUnit,\n\t\t\t);\n\t\t\tconst mainValue = values[0]; // FIXME (@oleiade) we should assert that the index exists here\n\t\t\tnonTrendValues[name] = mainValue;\n\t\t\tmaxNonTrendValueLen = Math.max(\n\t\t\t\tmaxNonTrendValueLen,\n\t\t\t\tstrWidth(mainValue),\n\t\t\t);\n\n\t\t\t// FIXME (@oleiade): what the fuck is an extra, really?\n\t\t\tconst extras = values.slice(1);\n\t\t\tnonTrendExtras[name] = extras;\n\t\t\textras.forEach((value, index) => {\n\t\t\t\tconst width = strWidth(value);\n\t\t\t\tif (\n\t\t\t\t\tnonTrendExtraMaxLens[index] === undefined ||\n\t\t\t\t\twidth > nonTrendExtraMaxLens[index]\n\t\t\t\t) {\n\t\t\t\t\tnonTrendExtraMaxLens[index] = width;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\treturn {\n\t\tmaxNameWidth,\n\t\tnonTrendValues,\n\t\tnonTrendExtras,\n\t\ttrendCols,\n\t\ttrendColMaxLens,\n\t\ttrendKeys,\n\t\tnumTrendColumns,\n\t\ttrendStats,\n\t\tmaxNonTrendValueLen,\n\t\tnonTrendExtraMaxLens,\n\t};\n}\n\n/**\n * Sorts metrics by name, keeping sub-metrics grouped with their parent metrics.\n *\n * @param {string[]} metricNames - The metric names to sort.\n * @returns {string[]} - The sorted metric names.\n */\nfunction sortMetricsByName(metricNames) {\n\tmetricNames.sort(function (lhsMetricName, rhsMetricName) {\n\t\tconst lhsParent = lhsMetricName.split('{', 1)[0];\n\t\tconst rhsParent = rhsMetricName.split('{', 1)[0];\n\t\tconst result = lhsParent.localeCompare(rhsParent);\n\t\tif (result !== 0) {\n\t\t\treturn result;\n\t\t}\n\t\tconst lhsSub = lhsMetricName.substring(lhsParent.length);\n\t\tconst rhsSub = rhsMetricName.substring(rhsParent.length);\n\t\treturn lhsSub.localeCompare(rhsSub);\n\t});\n\n\treturn metricNames;\n}\n\n/**\n * A simple iteration utility function for objects.\n *\n * @param {Object} obj - the object to iterate over\n * @param {(key: string, value: any) => (boolean|void)} callback - Callback invoked with (key, value)\n */\nfunction forEach(obj, callback) {\n\tfor (const key in obj) {\n\t\tif (obj.hasOwnProperty(key)) {\n\t\t\tif (callback(key, obj[key])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst titlePrefix = '█';\nconst subtitlePrefix = '↳';\nconst successMark = '✓';\nconst failMark = '✗';\nconst defaultOptions = {\n\tindent: ' ',\n\tenableColors: true, // FIXME (@oleiade): we should ensure we respect this flag\n\tsummaryTimeUnit: null,\n\tsummaryTrendStats: null,\n\tsortByName: true,\n};\n\n/**\n * Compute the width of a string as displayed in a terminal, excluding ANSI codes, terminal\n * formatting, Unicode ligatures, etc.\n *\n * @param {string} s - The string to measure\n * @returns {number} The display width of the string\n */\nfunction strWidth(s) {\n\t// TODO: determine if NFC or NFKD are not more appropriate? or just give up? https://hsivonen.fi/string-length/\n\tconst data = s.normalize('NFKC'); // This used to be NFKD in Go, but this should be better\n\tlet inEscSeq = false;\n\tlet inLongEscSeq = false;\n\tlet width = 0;\n\tfor (const char of data) {\n\t\tif (char.done) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// Skip over ANSI escape codes.\n\t\tif (char === '\\x1b') {\n\t\t\tinEscSeq = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (inEscSeq && char === '[') {\n\t\t\tinLongEscSeq = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\tinEscSeq &&\n\t\t\tinLongEscSeq &&\n\t\t\tchar.charCodeAt(0) >= 0x40 &&\n\t\t\tchar.charCodeAt(0) <= 0x7e\n\t\t) {\n\t\t\tinEscSeq = false;\n\t\t\tinLongEscSeq = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\tinEscSeq &&\n\t\t\t!inLongEscSeq &&\n\t\t\tchar.charCodeAt(0) >= 0x40 &&\n\t\t\tchar.charCodeAt(0) <= 0x5f\n\t\t) {\n\t\t\tinEscSeq = false;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!inEscSeq && !inLongEscSeq) {\n\t\t\twidth++;\n\t\t}\n\t}\n\treturn width;\n}\n\n/**\n * Extracts a display name for a metric, handling sub-metrics (e.g. \"metric{sub}\" -> \"{ sub }\").\n *\n * @param {string} name - The metric name.\n * @returns {string} - The display name\n */\nfunction renderMetricDisplayName(name) {\n\tconst subMetricPos = name.indexOf('{');\n\tif (subMetricPos >= 0) {\n\t\treturn '  { ' + name.substring(subMetricPos + 1, name.length - 1) + ' }';\n\t}\n\treturn name;\n}\n\n/**\n * Converts a number of bytes into a human-readable string with units.\n *\n * @param {number} bytes - The number of bytes.\n * @returns {string} A human-readable string (e.g. \"10 kB\").\n */\nfunction humanizeBytes(bytes) {\n\tconst units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n\tconst base = 1000;\n\tif (bytes < 10) {\n\t\treturn bytes + ' B';\n\t}\n\n\tconst e = Math.floor(Math.log(bytes) / Math.log(base));\n\tconst suffix = units[e | 0];\n\tconst val = Math.floor((bytes / Math.pow(base, e)) * 10 + 0.5) / 10;\n\treturn val.toFixed(val < 10 ? 1 : 0) + ' ' + suffix;\n}\n\nconst unitMap = {\n\ts: {unit: 's', coef: 0.001},\n\tms: {unit: 'ms', coef: 1},\n\tus: {unit: 'µs', coef: 1000},\n};\n\n/**\n * Converts a number to a fixed decimal string, removing trailing zeros.\n *\n * @param {number} val - The number to convert.\n * @param {number} prec - Decimal precision.\n * @returns {string} A string representation of the number without trailing zeros.\n */\nfunction toFixedNoTrailingZeros(val, prec) {\n\treturn parseFloat(val.toFixed(prec)).toString();\n}\n\n/**\n * Truncates a number to a certain precision without rounding, then removes trailing zeros.\n *\n * @param {number} val - The number to truncate.\n * @param {number} prec - Decimal precision.\n * @returns {string} A truncated, not rounded string representation.\n */\nfunction toFixedNoTrailingZerosTrunc(val, prec) {\n\tconst mult = Math.pow(10, prec);\n\treturn toFixedNoTrailingZeros(Math.trunc(mult * val) / mult, prec);\n}\n\n/**\n * Humanizes a duration (in milliseconds) to a human-readable string,\n * choosing appropriate units (ns, µs, ms, s, m, h).\n *\n * @param {number} duration - The duration in milliseconds.\n * @returns {string} Human-readable duration (e.g. \"2.5ms\", \"3s\", \"1m30s\").\n */\nfunction humanizeGenericDuration(duration) {\n\tif (duration === 0) {\n\t\treturn '0s';\n\t}\n\n\tif (duration < 0.001) {\n\t\t// smaller than a microsecond, print nanoseconds\n\t\treturn Math.trunc(duration * 1000000) + 'ns';\n\t}\n\tif (duration < 1) {\n\t\t// smaller than a millisecond, print microseconds\n\t\treturn toFixedNoTrailingZerosTrunc(duration * 1000, 2) + 'µs';\n\t}\n\tif (duration < 1000) {\n\t\t// duration is smaller than a second\n\t\treturn toFixedNoTrailingZerosTrunc(duration, 2) + 'ms';\n\t}\n\n\tlet fixedDuration =\n\t\ttoFixedNoTrailingZerosTrunc(\n\t\t\t(duration % 60000) / 1000,\n\t\t\tduration > 60000 ? 0 : 2,\n\t\t) + 's';\n\tlet rem = Math.trunc(duration / 60000);\n\tif (rem < 1) {\n\t\t// less than a minute\n\t\treturn fixedDuration;\n\t}\n\tfixedDuration = (rem % 60) + 'm' + fixedDuration;\n\trem = Math.trunc(rem / 60);\n\tif (rem < 1) {\n\t\t// less than an hour\n\t\treturn fixedDuration;\n\t}\n\treturn rem + 'h' + fixedDuration;\n}\n\n/**\n * Humanizes a duration according to a specified time unit or uses a generic formatting.\n *\n * @param {number} dur - The duration in milliseconds.\n * @param {string|null} timeUnit - Optional time unit (e.g. \"ms\", \"s\").\n * @returns {string} A human-readable duration string.\n */\nfunction humanizeDuration(dur, timeUnit) {\n\tif (timeUnit !== '' && unitMap.hasOwnProperty(timeUnit)) {\n\t\treturn (\n\t\t\t(dur * unitMap[timeUnit].coef).toFixed(2) + unitMap[timeUnit].unit\n\t\t);\n\t}\n\n\treturn humanizeGenericDuration(dur);\n}\n\n/**\n * Returns the summary values for non-trend metrics (counter, gauge, rate).\n *\n * @param {ReportMetric} metric - The metric to summarize.\n * @param {string|null} timeUnit - The time unit for durations.\n * @returns {string[]} - An array of summary values.\n */\nfunction nonTrendMetricValueForSum(metric, timeUnit) {\n\tswitch (metric.type) {\n\t\tcase 'counter':\n\t\t\treturn [\n\t\t\t\thumanizeValue(metric.values.count, metric, timeUnit),\n\t\t\t\thumanizeValue(metric.values.rate, metric, timeUnit) + '/s',\n\t\t\t];\n\t\tcase 'gauge':\n\t\t\treturn [\n\t\t\t\thumanizeValue(metric.values.value, metric, timeUnit),\n\t\t\t\t'min=' + humanizeValue(metric.values.min, metric, timeUnit),\n\t\t\t\t'max=' + humanizeValue(metric.values.max, metric, timeUnit),\n\t\t\t];\n\t\tcase 'rate':\n\t\t\treturn [\n\t\t\t\thumanizeValue(metric.values.rate, metric, timeUnit),\n\t\t\t\t`${metric.values.passes} out of ${metric.values.passes + metric.values.fails}`,\n\t\t\t];\n\t\tdefault:\n\t\t\treturn ['[no data]'];\n\t}\n}\n"
  },
  {
    "path": "internal/js/summary_test.go",
    "content": "package js\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst (\n\tchecksOut = \"     █ child\\n\\n\" +\n\t\t\"       ✓ check1\\n\" +\n\t\t\"       ✗ check3\\n        ↳  66% — ✓ 10 / ✗ 5\\n\" +\n\t\t\"       ✗ check2\\n        ↳  33% — ✓ 5 / ✗ 10\\n\\n\" +\n\t\t\"   ✓ checks......: 75.00% 45 out of 60\\n\"\n\tcountOut = \"   ✗ http_reqs...: 3      3/s\\n\"\n\tgaugeOut = \"     vus.........: 1      min=1        max=1\\n\"\n\ttrendOut = \"   ✗ my_trend....: avg=15ms min=10ms med=15ms max=20ms p(90)=19ms \" +\n\t\t\"p(95)=19.5ms p(99.9)=19.99ms\\n\"\n)\n\nfunc TestTextSummary(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tstats    []string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\t[]string{\"avg\", \"min\", \"med\", \"max\", \"p(90)\", \"p(95)\", \"p(99.9)\"},\n\t\t\tchecksOut + countOut + trendOut + gaugeOut,\n\t\t},\n\t\t{[]string{\"count\"}, checksOut + countOut + \"   ✗ my_trend....: count=3\\n\" + gaugeOut},\n\t\t{[]string{\"avg\", \"count\"}, checksOut + countOut + \"   ✗ my_trend....: avg=15ms count=3\\n\" + gaugeOut},\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%d_%v\", i, tc.stats), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tlegacySummary := createTestLegacySummary(t)\n\t\t\ttrendStats, err := json.Marshal(tc.stats)\n\t\t\trequire.NoError(t, err)\n\t\t\trunner, err := getSimpleRunner(\n\t\t\t\tt, \"/script.js\",\n\t\t\t\tfmt.Sprintf(`\n\t\t\t\t\texports.options = {summaryTrendStats: %s};\n\t\t\t\t\texports.default = function() {/* we don't run this, metrics are mocked */};\n\t\t\t\t`, string(trendStats)),\n\t\t\t\tlib.RuntimeOptions{CompatibilityMode: null.NewString(\"base\", true)},\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tresult, err := runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\t\t\trequire.NoError(t, err)\n\n\t\t\trequire.Len(t, result, 1)\n\t\t\tstdout := result[\"stdout\"]\n\t\t\trequire.NotNil(t, stdout)\n\t\t\tsummaryOut, err := io.ReadAll(stdout)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"\\n\"+tc.expected+\"\\n\", string(summaryOut))\n\t\t})\n\t}\n}\n\nfunc TestTextSummaryWithSubMetrics(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\tparentMetric, err := registry.NewMetric(\"my_parent\", metrics.Counter)\n\trequire.NoError(t, err)\n\tparentMetric.Sink.Add(metrics.Sample{Value: 11})\n\n\tparentMetricPost, err := registry.NewMetric(\"my_parent_post\", metrics.Counter)\n\trequire.NoError(t, err)\n\tparentMetricPost.Sink.Add(metrics.Sample{Value: 22})\n\n\tsubMetric, err := parentMetric.AddSubmetric(\"sub:1\")\n\trequire.NoError(t, err)\n\tsubMetric.Metric.Sink.Add(metrics.Sample{Value: 1})\n\n\tsubMetricPost, err := parentMetricPost.AddSubmetric(\"sub:2\")\n\trequire.NoError(t, err)\n\tsubMetricPost.Metric.Sink.Add(metrics.Sample{Value: 2})\n\n\tmetrics := map[string]*metrics.Metric{\n\t\tparentMetric.Name:     parentMetric,\n\t\tparentMetricPost.Name: parentMetricPost,\n\t\tsubMetric.Name:        subMetric.Metric,\n\t\tsubMetricPost.Name:    subMetricPost.Metric,\n\t}\n\n\tlegacySummary := &lib.LegacySummary{\n\t\tMetrics:         metrics,\n\t\tRootGroup:       &lib.Group{},\n\t\tTestRunDuration: time.Second,\n\t}\n\n\trunner, err := getSimpleRunner(\n\t\tt,\n\t\t\"/script.js\",\n\t\t\"exports.default = function() {/* we don't run this, metrics are mocked */};\",\n\t\tlib.RuntimeOptions{CompatibilityMode: null.NewString(\"base\", true)},\n\t)\n\trequire.NoError(t, err)\n\n\tresult, err := runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\trequire.NoError(t, err)\n\n\trequire.Len(t, result, 1)\n\tstdout := result[\"stdout\"]\n\trequire.NotNil(t, stdout)\n\n\tsummaryOut, err := io.ReadAll(stdout)\n\trequire.NoError(t, err)\n\n\texpected := \"     my_parent........: 11 11/s\\n\" +\n\t\t\"       { sub:1 }......: 1  1/s\\n\" +\n\t\t\"     my_parent_post...: 22 22/s\\n\" +\n\t\t\"       { sub:2 }......: 2  2/s\\n\"\n\tassert.Equal(t, \"\\n\"+expected+\"\\n\", string(summaryOut))\n}\n\nfunc createTestMetrics(t *testing.T) (map[string]*metrics.Metric, *lib.Group) {\n\tregistry := metrics.NewRegistry()\n\ttestMetrics := make(map[string]*metrics.Metric)\n\n\tgaugeMetric, err := registry.NewMetric(\"vus\", metrics.Gauge)\n\trequire.NoError(t, err)\n\tgaugeMetric.Sink.Add(metrics.Sample{Value: 1})\n\n\tcountMetric, err := registry.NewMetric(\"http_reqs\", metrics.Counter)\n\trequire.NoError(t, err)\n\tcountMetric.Tainted = null.BoolFrom(true)\n\tcountMetric.Thresholds = metrics.Thresholds{Thresholds: []*metrics.Threshold{{Source: \"rate<100\", LastFailed: true}}}\n\n\tchecksMetric, err := registry.NewMetric(\"checks\", metrics.Rate)\n\trequire.NoError(t, err)\n\tchecksMetric.Tainted = null.BoolFrom(false)\n\tchecksMetric.Thresholds = metrics.Thresholds{Thresholds: []*metrics.Threshold{{Source: \"rate>70\", LastFailed: false}}}\n\tsink := metrics.NewTrendSink()\n\n\tsamples := []float64{10.0, 15.0, 20.0}\n\tfor _, s := range samples {\n\t\tsink.Add(metrics.Sample{Value: s})\n\t\tcountMetric.Sink.Add(metrics.Sample{Value: 1})\n\t}\n\n\ttestMetrics[\"vus\"] = gaugeMetric\n\ttestMetrics[\"http_reqs\"] = countMetric\n\ttestMetrics[\"checks\"] = checksMetric\n\ttestMetrics[\"my_trend\"] = &metrics.Metric{\n\t\tName:     \"my_trend\",\n\t\tType:     metrics.Trend,\n\t\tContains: metrics.Time,\n\t\tSink:     sink,\n\t\tTainted:  null.BoolFrom(true),\n\t\tThresholds: metrics.Thresholds{\n\t\t\tThresholds: []*metrics.Threshold{\n\t\t\t\t{\n\t\t\t\t\tSource:     \"my_trend<1000\",\n\t\t\t\t\tLastFailed: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\trootG, err := lib.NewGroup(\"\", nil)\n\trequire.NoError(t, err)\n\tchildG, err := rootG.Group(\"child\")\n\trequire.NoError(t, err)\n\tcheck1, err := childG.Check(\"check1\")\n\trequire.NoError(t, err)\n\tcheck1.Passes = 30\n\n\tcheck3, err := childG.Check(\"check3\") // intentionally before check2\n\trequire.NoError(t, err)\n\tcheck3.Passes = 10\n\tcheck3.Fails = 5\n\n\tcheck2, err := childG.Check(\"check2\")\n\trequire.NoError(t, err)\n\tcheck2.Passes = 5\n\tcheck2.Fails = 10\n\n\tfor i := 0; i < int(check1.Passes+check2.Passes+check3.Passes); i++ {\n\t\tchecksMetric.Sink.Add(metrics.Sample{Value: 1})\n\t}\n\tfor i := 0; i < int(check1.Fails+check2.Fails+check3.Fails); i++ {\n\t\tchecksMetric.Sink.Add(metrics.Sample{Value: 0})\n\t}\n\n\treturn testMetrics, rootG\n}\n\nfunc createTestLegacySummary(t *testing.T) *lib.LegacySummary {\n\tmetrics, rootG := createTestMetrics(t)\n\treturn &lib.LegacySummary{\n\t\tMetrics:         metrics,\n\t\tRootGroup:       rootG,\n\t\tTestRunDuration: time.Second,\n\t}\n}\n\nconst expectedOldJSONExportResult = `{\n    \"root_group\": {\n        \"name\": \"\",\n        \"path\": \"\",\n        \"id\": \"d41d8cd98f00b204e9800998ecf8427e\",\n        \"groups\": {\n            \"child\": {\n                \"name\": \"child\",\n                \"path\": \"::child\",\n                \"id\": \"f41cbb53a398ec1c9fb3d33e20c9b040\",\n                \"groups\": {},\n                \"checks\": {\n                    \"check1\": {\n                        \"name\": \"check1\",\n                        \"path\": \"::child::check1\",\n                        \"id\": \"6289a7a06253a1c3f6137dfb25695563\",\n                        \"passes\":30,\n                        \"fails\": 0\n                    },\n                    \"check2\": {\n                        \"name\": \"check2\",\n                        \"path\": \"::child::check2\",\n                        \"id\": \"06f5922794bef0d4584ba76a49893e1f\",\n                        \"passes\": 5,\n                        \"fails\": 10\n                    },\n                    \"check3\": {\n                        \"name\": \"check3\",\n                        \"path\": \"::child::check3\",\n                        \"id\": \"c7553eca92d3e034b5808332296d304a\",\n                        \"passes\": 10,\n                        \"fails\": 5\n                    }\n                }\n            }\n        },\n        \"checks\": {}\n    },\n    \"metrics\": {\n        \"checks\": {\n            \"value\": 0.75,\n            \"passes\": 45,\n            \"fails\": 15,\n            \"thresholds\": {\n                \"rate>70\": false\n            }\n        },\n        \"http_reqs\": {\n            \"count\": 3,\n            \"rate\": 3,\n            \"thresholds\": {\n                \"rate<100\": true\n            }\n        },\n        \"my_trend\": {\n            \"avg\": 15,\n            \"max\": 20,\n            \"med\": 15,\n            \"min\": 10,\n            \"p(90)\": 19,\n            \"p(95)\": 19.5,\n            \"p(99)\": 19.9,\n            \"count\": 3,\n            \"thresholds\": {\n                \"my_trend<1000\": true\n            }\n        },\n        \"vus\": {\n            \"value\": 1,\n            \"min\": 1,\n            \"max\": 1\n        }\n    }\n}\n`\n\nfunc TestOldJSONExport(t *testing.T) {\n\tt.Parallel()\n\trunner, err := getSimpleRunner(\n\t\tt, \"/script.js\",\n\t\t`\n\t\texports.options = {summaryTrendStats: [\"avg\", \"min\", \"med\", \"max\", \"p(90)\", \"p(95)\", \"p(99)\", \"count\"]};\n\t\texports.default = function() {/* we don't run this, metrics are mocked */};\n\t\t`,\n\t\tlib.RuntimeOptions{\n\t\t\tCompatibilityMode: null.NewString(\"base\", true),\n\t\t\tSummaryExport:     null.StringFrom(\"result.json\"),\n\t\t},\n\t)\n\n\trequire.NoError(t, err)\n\n\tlegacySummary := createTestLegacySummary(t)\n\tresult, err := runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\trequire.NoError(t, err)\n\n\trequire.Len(t, result, 2)\n\trequire.NotNil(t, result[\"stdout\"])\n\ttextSummary, err := io.ReadAll(result[\"stdout\"])\n\trequire.NoError(t, err)\n\tassert.Contains(t, string(textSummary), checksOut+countOut)\n\trequire.NotNil(t, result[\"result.json\"])\n\tjsonExport, err := io.ReadAll(result[\"result.json\"])\n\trequire.NoError(t, err)\n\tassert.JSONEq(t, expectedOldJSONExportResult, string(jsonExport))\n}\n\nconst expectedHandleSummaryRawData = `\n{\n    \"root_group\": {\n        \"groups\": [\n            {\n                \"name\": \"child\",\n                \"path\": \"::child\",\n                \"id\": \"f41cbb53a398ec1c9fb3d33e20c9b040\",\n                \"groups\": [],\n                \"checks\": [\n                        {\n                            \"id\": \"6289a7a06253a1c3f6137dfb25695563\",\n                            \"passes\": 30,\n                            \"fails\": 0,\n                            \"name\": \"check1\",\n                            \"path\": \"::child::check1\"\n                        },\n                        {\n                            \"fails\": 5,\n                            \"name\": \"check3\",\n                            \"path\": \"::child::check3\",\n                            \"id\": \"c7553eca92d3e034b5808332296d304a\",\n                            \"passes\": 10\n                        },\n                        {\n                            \"name\": \"check2\",\n                            \"path\": \"::child::check2\",\n                            \"id\": \"06f5922794bef0d4584ba76a49893e1f\",\n                            \"passes\": 5,\n                            \"fails\": 10\n                        }\n                    ]\n            }\n        ],\n        \"checks\": [],\n        \"name\": \"\",\n        \"path\": \"\",\n        \"id\": \"d41d8cd98f00b204e9800998ecf8427e\"\n    },\n    \"options\": {\n        \"summaryTrendStats\": [\n            \"avg\",\n            \"min\",\n            \"med\",\n            \"max\",\n            \"p(90)\",\n            \"p(95)\",\n            \"p(99)\",\n            \"count\"\n        ],\n        \"summaryTimeUnit\": \"\",\n        \"noColor\": false\n    },\n    \"state\": {\n        \"isStdErrTTY\": false,\n        \"isStdOutTTY\": false,\n        \"testRunDurationMs\": 1000\n    },\n    \"metrics\": {\n        \"checks\": {\n            \"contains\": \"default\",\n            \"values\": {\n                \"passes\": 45,\n                \"fails\": 15,\n                \"rate\": 0.75\n            },\n            \"type\": \"rate\",\n            \"thresholds\": {\n                \"rate>70\": {\n                    \"ok\": true\n                }\n            }\n        },\n        \"my_trend\": {\n            \"thresholds\": {\n                \"my_trend<1000\": {\n                    \"ok\": false\n                }\n            },\n            \"type\": \"trend\",\n            \"contains\": \"time\",\n            \"values\": {\n                \"max\": 20,\n                \"p(90)\": 19,\n                \"p(95)\": 19.5,\n                \"p(99)\": 19.9,\n                \"count\": 3,\n                \"avg\": 15,\n                \"min\": 10,\n                \"med\": 15\n            }\n        },\n        \"vus\": {\n            \"contains\": \"default\",\n            \"values\": {\n                \"value\": 1,\n                \"min\": 1,\n                \"max\": 1\n            },\n            \"type\": \"gauge\"\n        },\n        \"http_reqs\": {\n            \"type\": \"counter\",\n            \"contains\": \"default\",\n            \"values\": {\n                \"count\": 3,\n                \"rate\": 3\n            },\n            \"thresholds\": {\n                \"rate<100\": {\n                    \"ok\": false\n                }\n            }\n        }\n    }\n}`\n\nconst expectedHandleSummaryDataWithSetup = `\n{\n    \"root_group\": {\n        \"groups\": [\n            {\n                \"name\": \"child\",\n                \"path\": \"::child\",\n                \"id\": \"f41cbb53a398ec1c9fb3d33e20c9b040\",\n                \"groups\": [],\n                \"checks\": [\n                        {\n                            \"id\": \"6289a7a06253a1c3f6137dfb25695563\",\n                            \"passes\": 30,\n                            \"fails\": 0,\n                            \"name\": \"check1\",\n                            \"path\": \"::child::check1\"\n                        },\n                        {\n                            \"fails\": 5,\n                            \"name\": \"check3\",\n                            \"path\": \"::child::check3\",\n                            \"id\": \"c7553eca92d3e034b5808332296d304a\",\n                            \"passes\": 10\n                        },\n                        {\n                            \"name\": \"check2\",\n                            \"path\": \"::child::check2\",\n                            \"id\": \"06f5922794bef0d4584ba76a49893e1f\",\n                            \"passes\": 5,\n                            \"fails\": 10\n                        }\n                    ]\n            }\n        ],\n        \"checks\": [],\n        \"name\": \"\",\n        \"path\": \"\",\n        \"id\": \"d41d8cd98f00b204e9800998ecf8427e\"\n    },\n    \"options\": {\n        \"summaryTrendStats\": [\n            \"avg\",\n            \"min\",\n            \"med\",\n            \"max\",\n            \"p(90)\",\n            \"p(95)\",\n            \"p(99)\",\n            \"count\"\n            ],\n            \"summaryTimeUnit\": \"\",\n            \"noColor\": false\n        },\n        \"state\": {\n            \"isStdErrTTY\": false,\n            \"isStdOutTTY\": false,\n            \"testRunDurationMs\": 1000\n        },\n        \"setup_data\": 5,\n        \"metrics\": {\n        \"checks\": {\n            \"contains\": \"default\",\n            \"values\": {\n                \"passes\": 45,\n                \"fails\": 15,\n                \"rate\": 0.75\n            },\n            \"type\": \"rate\",\n            \"thresholds\": {\n                \"rate>70\": {\n                    \"ok\": true\n                }\n            }\n        },\n        \"my_trend\": {\n            \"thresholds\": {\n                \"my_trend<1000\": {\n                    \"ok\": false\n                }\n            },\n            \"type\": \"trend\",\n            \"contains\": \"time\",\n            \"values\": {\n                \"max\": 20,\n                \"p(90)\": 19,\n                \"p(95)\": 19.5,\n                \"p(99)\": 19.9,\n                \"count\": 3,\n                \"avg\": 15,\n                \"min\": 10,\n                \"med\": 15\n            }\n        },\n        \"vus\": {\n            \"contains\": \"default\",\n            \"values\": {\n                \"value\": 1,\n                \"min\": 1,\n                \"max\": 1\n            },\n            \"type\": \"gauge\"\n        },\n        \"http_reqs\": {\n            \"type\": \"counter\",\n            \"contains\": \"default\",\n            \"values\": {\n                \"count\": 3,\n                \"rate\": 3\n            },\n            \"thresholds\": {\n                \"rate<100\": {\n                    \"ok\": false\n                }\n            }\n        }\n    }\n}`\n\nfunc TestRawHandleSummaryData(t *testing.T) {\n\tt.Parallel()\n\trunner, err := getSimpleRunner(\n\t\tt, \"/script.js\",\n\t\t`\n\t\texports.options = {summaryTrendStats: [\"avg\", \"min\", \"med\", \"max\", \"p(90)\", \"p(95)\", \"p(99)\", \"count\"]};\n\t\texports.default = function() { /* we don't run this, metrics are mocked */ };\n\t\texports.handleSummary = function(data) {\n\t\t\treturn {'rawdata.json': JSON.stringify(data)};\n\t\t};\n\t\t`,\n\t\tlib.RuntimeOptions{\n\t\t\tCompatibilityMode: null.NewString(\"base\", true),\n\t\t\t// we still want to check this\n\t\t\tSummaryExport: null.StringFrom(\"old-export.json\"),\n\t\t},\n\t)\n\n\trequire.NoError(t, err)\n\n\tlegacySummary := createTestLegacySummary(t)\n\tresult, err := runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\trequire.NoError(t, err)\n\n\trequire.Len(t, result, 2)\n\trequire.Nil(t, result[\"stdout\"])\n\n\trequire.NotNil(t, result[\"old-export.json\"])\n\toldExport, err := io.ReadAll(result[\"old-export.json\"])\n\trequire.NoError(t, err)\n\tassert.JSONEq(t, expectedOldJSONExportResult, string(oldExport))\n\trequire.NotNil(t, result[\"rawdata.json\"])\n\tnewRawData, err := io.ReadAll(result[\"rawdata.json\"])\n\trequire.NoError(t, err)\n\tassert.JSONEq(t, expectedHandleSummaryRawData, string(newRawData))\n}\n\nfunc TestRawHandleSummaryDataWithSetupData(t *testing.T) {\n\tt.Parallel()\n\trunner, err := getSimpleRunner(\n\t\tt, \"/script.js\",\n\t\t`\n\t\texports.options = {summaryTrendStats: [\"avg\", \"min\", \"med\", \"max\", \"p(90)\", \"p(95)\", \"p(99)\", \"count\"]};\n\t\texports.default = function() { /* we don't run this, metrics are mocked */ };\n\t\texports.handleSummary = function(data) {\n\t\t\tif(data.setup_data != 5) {\n\t\t\t\tthrow new Error(\"handleSummary: wrong data: \" + JSON.stringify(data))\n\t\t\t}\n\t\t\treturn {'dataWithSetup.json': JSON.stringify(data)};\n\t\t};\n\t\t`,\n\t)\n\trequire.NoError(t, err)\n\trunner.SetSetupData([]byte(\"5\"))\n\n\tlegacySummary := createTestLegacySummary(t)\n\tresult, err := runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\trequire.NoError(t, err)\n\tdataWithSetup, err := io.ReadAll(result[\"dataWithSetup.json\"])\n\trequire.NoError(t, err)\n\tassert.JSONEq(t, expectedHandleSummaryDataWithSetup, string(dataWithSetup))\n}\n\nfunc TestRawHandleSummaryPromise(t *testing.T) {\n\tt.Parallel()\n\trunner, err := getSimpleRunner(\n\t\tt, \"/script.js\",\n\t\t`\n\t\texports.options = {summaryTrendStats: [\"avg\", \"min\", \"med\", \"max\", \"p(90)\", \"p(95)\", \"p(99)\", \"count\"]};\n\t\texports.default = function() { /* we don't run this, metrics are mocked */ };\n\t\texports.handleSummary = async function(data) {\n            return await Promise.resolve({'dataWithSetup.json': JSON.stringify(data)});\n\t\t};\n\t\t`,\n\t)\n\trequire.NoError(t, err)\n\trunner.SetSetupData([]byte(\"5\"))\n\n\tlegacySummary := createTestLegacySummary(t)\n\tresult, err := runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\trequire.NoError(t, err)\n\tdataWithSetup, err := io.ReadAll(result[\"dataWithSetup.json\"])\n\trequire.NoError(t, err)\n\tassert.JSONEq(t, expectedHandleSummaryDataWithSetup, string(dataWithSetup))\n}\n\nfunc TestWrongSummaryHandlerExportTypes(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []string{\"{}\", `\"foo\"`, \"null\", \"undefined\", \"123\"}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%d_%s\", i, tc), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trunner, err := getSimpleRunner(t, \"/script.js\",\n\t\t\t\tfmt.Sprintf(`\n\t\t\t\t\texports.default = function() { /* we don't run this, metrics are mocked */ };\n\t\t\t\t\texports.handleSummary = %s;\n\t\t\t\t`, tc),\n\t\t\t\tlib.RuntimeOptions{CompatibilityMode: null.NewString(\"base\", true)},\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tlegacySummary := createTestLegacySummary(t)\n\t\t\t_, err = runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\t\t\trequire.Error(t, err)\n\t\t})\n\t}\n}\n\nfunc TestExceptionInHandleSummaryFallsBackToTextSummary(t *testing.T) {\n\tt.Parallel()\n\n\tlogger := logrus.New()\n\tlogger.SetOutput(io.Discard)\n\tlogHook := testutils.NewLogHook(logrus.ErrorLevel)\n\tlogger.AddHook(logHook)\n\n\trunner, err := getSimpleRunner(t, \"/script.js\", `\n\t\t\texports.default = function() {/* we don't run this, metrics are mocked */};\n\t\t\texports.handleSummary = function(data) {\n\t\t\t\tthrow new Error('intentional error');\n\t\t\t};\n\t\t`, logger, lib.RuntimeOptions{CompatibilityMode: null.NewString(\"base\", true)},\n\t)\n\n\trequire.NoError(t, err)\n\n\tlegacySummary := createTestLegacySummary(t)\n\tresult, err := runner.HandleSummary(t.Context(), legacySummary, nil, summary.Meta{})\n\trequire.NoError(t, err)\n\n\trequire.Len(t, result, 1)\n\trequire.NotNil(t, result[\"stdout\"])\n\ttextSummary, err := io.ReadAll(result[\"stdout\"])\n\trequire.NoError(t, err)\n\tassert.Contains(t, string(textSummary), checksOut+countOut)\n\n\tlogErrors := logHook.Drain()\n\tassert.Equal(t, 1, len(logErrors))\n\terrMsg, err := logErrors[0].String()\n\trequire.NoError(t, err)\n\tassert.Contains(t, errMsg, \"\\\"Error: intentional error\\\\n\\\\tat file:///script.js:4:11(3)\\\\n\")\n\tassert.Equal(t, logrus.Fields{\"hint\": \"script exception\"}, logErrors[0].Data)\n}\n"
  },
  {
    "path": "internal/js/tc39/README.md",
    "content": "# Introduction to a k6's TC39 testing\n\n`js/tc39` package tests k6 [Sobek](https://github.com/grafana/sobek) and the k6 Sobek+esbuild combo against the tc39 test suite.\n\nWays to use it:\n1. run ./checkout.sh to checkout the last commit sha of [test262](https://github.com/tc39/test262)\n   that was tested with this module\n2. Run `go test &> out.log`\n\nThe full list of failing tests, and the error, is in `breaking_test_errors-*.json`. All errors list there with the corresponding error will *not* be counted as errors - this is what the test expects, those specific errors. See reasons for this at the end of this document.\n\nThis is a modified version of [the code in the original goja\nrepo](https://github.com/dop251/goja/blob/master/tc39_test.go) that Sobek was forked from.\n\n## Maintaining the tests\n\nThere are few things to keep in mind when maintaining the tests.\n\n* For most of the time, we aim to have the same version (commit hash) of the test suite as the one that [uses Sobek](https://github.com/grafana/sobek/blob/main/.tc39_test262_checkout.sh#L3). So if Sobek brings a new version of the test suite, we should update the version of the test suite in this package as well.\n* The new version of Sobek could bring a new functionality, so you might need to re-evaluate the `featuresBlockList`, `skipList` and any other list in the `tc39_test.go` file. The way to go is also keeping this lists closer to the Sobek, however they are not the same, so you might need to adjust them.\n* Due to changes to Sobek it's common for the error to change, or there to be now a new error on the previously passing test, or (hopefully) a test that was not passing but now is.\nIn all of those cases `breaking_test_errors-*.json` needs to be updated. Run the test with `-update` flag to update: `go test -update`.\n* Important to mention that there should be a balance between just updating the list of the errors and actually fixing errors. So it's recommended to check the diff of the `breaking_test_errors-*.json` and case by case decide if the error should be updated or the test should be fixed.\n\n\n## Reasons for recording breaking_test_errors.json\n\nUnfortunately k6 doesn't pass all the test that are currently defined as \"interesting\".\nGoja decided to just not run the ones that it knows it fails currently, but this\nmeans that if they stop failing, someone needs to go re-enable these tests.\n\nThis also means that, if the\nprevious breakage was something a user can work around in a certain way, it now might be something\nelse that the user can't workaround or have another problem.\n\nStarting v0.53 k6 doesn't use Babel anymore, it now serves tests for `esbuild`, and for the parts uncovered by Sobek's test suite. It is still possible that we drop the whole package in the future.\n\nFor these reasons, I decided that recording what breaks and checking that it doesn't change is better.\n"
  },
  {
    "path": "internal/js/tc39/breaking_test_errors-stripTypes=false.json",
    "content": "{\n  \"test/annexB/built-ins/Function/createdynfn-html-close-comment-body.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-close-comment-body.js: SyntaxError: SyntaxError: <eval>: Line 4:3 Unexpected token > (and 3 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-html-close-comment-params.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-close-comment-params.js: SyntaxError: SyntaxError: <eval>: Line 2:1 Unexpected token -- (and 5 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-html-open-comment-body.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-open-comment-body.js: SyntaxError: SyntaxError: <eval>: Line 3:1 Unexpected token < (and 2 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-html-open-comment-params.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-open-comment-params.js: SyntaxError: SyntaxError: <eval>: Line 1:21 Unexpected token < (and 5 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-no-line-terminator-html-close-comment-body.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-no-line-terminator-html-close-comment-body.js: SyntaxError: SyntaxError: <eval>: Line 3:3 Unexpected token > (and 3 more errors) <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js: Test262Error: invalid \\\\c escape matched c rather than \\\\c when followed by А Expected SameValue(«cА», «null») to be true <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-invalid-control-escape-character-class.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-invalid-control-escape-character-class.js: Test262Error: Character \\\\ missing from character class [\\\\c\\u0000] <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"a\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"a\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/annexB/built-ins/RegExp/prototype/compile/pattern-string-invalid-u.js-strict:true\": \"test/annexB/built-ins/RegExp/prototype/compile/pattern-string-invalid-u.js: Test262Error: invalid pattern: { Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/AggregateError/errors-iterabletolist.js-strict:true\": \"test/built-ins/AggregateError/errors-iterabletolist.js: Test262Error: GetMethod(obj, @@iterator) returns undefined Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js-strict:true\": \"test/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js: Test262Error: Actual [1, 2] and expected [1, 2] should have the same contents. a.flat(undefined) uses default depth of 1 <at omitted>\",\n  \"test/built-ins/AsyncFunction/AsyncFunction-is-subclass.js-strict:true\": \"test/built-ins/AsyncFunction/AsyncFunction-is-subclass.js: Test262Error: Prototype of constructor is Function Expected SameValue(«function () { [native code] }», «function Function() { [native code] }») to be true <at omitted>\",\n  \"test/built-ins/DataView/prototype/setBigInt64/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setBigInt64/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setBigUint64/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setBigUint64/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setFloat16/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setFloat16/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setFloat32/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setFloat32/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setFloat64/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setFloat64/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setInt16/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setInt16/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setInt32/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setInt32/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setInt8/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setInt8/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setUint16/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setUint16/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setUint32/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setUint32/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setUint8/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setUint8/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/Date/UTC/fp-evaluation-order.js-strict:true\": \"test/built-ins/Date/UTC/fp-evaluation-order.js: Test262Error: order of operations / precision in MakeTime Expected SameValue(«29256», «29312») to be true <at omitted>\",\n  \"test/built-ins/Error/error-message-tostring-symbol.js-strict:true\": \"test/built-ins/Error/error-message-tostring-symbol.js: Test262Error: If _message_ is a Symbol, Error must throw TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Error/isError/bigints.js-strict:true\": \"test/built-ins/Error/isError/bigints.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/error-subclass.js-strict:true\": \"test/built-ins/Error/isError/error-subclass.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/errors.js-strict:true\": \"test/built-ins/Error/isError/errors.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/fake-errors.js-strict:true\": \"test/built-ins/Error/isError/fake-errors.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/is-a-constructor.js-strict:true\": \"test/built-ins/Error/isError/is-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/Error/isError/name.js-strict:true\": \"test/built-ins/Error/isError/name.js: TypeError: Cannot read property 'name' of undefined <at omitted>\",\n  \"test/built-ins/Error/isError/non-error-objects.js-strict:true\": \"test/built-ins/Error/isError/non-error-objects.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/primitives.js-strict:true\": \"test/built-ins/Error/isError/primitives.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/prop-desc.js-strict:true\": \"test/built-ins/Error/isError/prop-desc.js: Test262Error: obj should have an own property isError <at omitted>\",\n  \"test/built-ins/Error/isError/symbols.js-strict:true\": \"test/built-ins/Error/isError/symbols.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js-strict:true\": \"test/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/GeneratorPrototype/return/try-finally-set-property-within-try.js-strict:true\": \"panic while running test/built-ins/GeneratorPrototype/return/try-finally-set-property-within-try.js: runtime error: slice bounds out of range [:-1]\",\n  \"test/built-ins/Iterator/concat/arguments-checked-in-order.js-strict:true\": \"test/built-ins/Iterator/concat/arguments-checked-in-order.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/fresh-iterator-result.js-strict:true\": \"test/built-ins/Iterator/concat/fresh-iterator-result.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/get-iterator-method-only-once.js-strict:true\": \"test/built-ins/Iterator/concat/get-iterator-method-only-once.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/get-iterator-method-throws.js-strict:true\": \"test/built-ins/Iterator/concat/get-iterator-method-throws.js: Test262Error: Expected a Test262Error but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/get-value-after-done.js-strict:true\": \"test/built-ins/Iterator/concat/get-value-after-done.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/inner-iterator-created-in-order.js-strict:true\": \"test/built-ins/Iterator/concat/inner-iterator-created-in-order.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/is-function.js-strict:true\": \"test/built-ins/Iterator/concat/is-function.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/iterable-primitive-wrapper-objects.js-strict:true\": \"test/built-ins/Iterator/concat/iterable-primitive-wrapper-objects.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/length.js-strict:true\": \"test/built-ins/Iterator/concat/length.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/many-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/many-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/name.js-strict:true\": \"test/built-ins/Iterator/concat/name.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-non-object.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-non-object.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-throwing-done.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-throwing-done.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-throwing-value.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-throwing-value.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-throws.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-throws.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/non-constructible.js-strict:true\": \"test/built-ins/Iterator/concat/non-constructible.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/prop-desc.js-strict:true\": \"test/built-ins/Iterator/concat/prop-desc.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/proto.js-strict:true\": \"test/built-ins/Iterator/concat/proto.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/result-is-iterator.js-strict:true\": \"test/built-ins/Iterator/concat/result-is-iterator.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-is-forwarded.js-strict:true\": \"test/built-ins/Iterator/concat/return-is-forwarded.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js-strict:true\": \"test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js-strict:true\": \"test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/single-argument.js-strict:true\": \"test/built-ins/Iterator/concat/single-argument.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js: Test262Error: iterable is undefined Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js: Test262Error: iterable has no iterator method Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/zero-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/zero-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/basic-longest.js-strict:true\": \"test/built-ins/Iterator/zip/basic-longest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/basic-shortest.js-strict:true\": \"test/built-ins/Iterator/zip/basic-shortest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/basic-strict.js-strict:true\": \"test/built-ins/Iterator/zip/basic-strict.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/is-function.js-strict:true\": \"test/built-ins/Iterator/zip/is-function.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-containing-string-objects.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-containing-string-objects.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration-after-reading-options.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration-after-reading-options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration-get-iterator-flattenable-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration-get-iterator-flattenable-abrupt-completion.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration-iterator-step-value-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-primitive.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-primitive.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-non-iterable.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-non-iterable.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/length.js-strict:true\": \"test/built-ins/Iterator/zip/length.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/name.js-strict:true\": \"test/built-ins/Iterator/zip/name.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/non-constructible.js-strict:true\": \"test/built-ins/Iterator/zip/non-constructible.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/options-mode.js-strict:true\": \"test/built-ins/Iterator/zip/options-mode.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/options-padding.js-strict:true\": \"test/built-ins/Iterator/zip/options-padding.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/options.js-strict:true\": \"test/built-ins/Iterator/zip/options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration-get-iterator-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration-get-iterator-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration-iterator-close-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration-iterator-step-value-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/prop-desc.js-strict:true\": \"test/built-ins/Iterator/zip/prop-desc.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/proto.js-strict:true\": \"test/built-ins/Iterator/zip/proto.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/result-is-iterator.js-strict:true\": \"test/built-ins/Iterator/zip/result-is-iterator.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/basic-longest.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/basic-longest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/basic-shortest.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/basic-shortest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/basic-strict.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/basic-strict.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/is-function.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/is-function.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-containing-string-objects.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-containing-string-objects.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-after-reading-options.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-after-reading-options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-deleted.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-deleted.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-enumerable.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-enumerable.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-iterator-flattenable-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-iterator-flattenable-abrupt-completion.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-own-property-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-own-property-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-inherited.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-inherited.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-symbol-key.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-symbol-key.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-undefined.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-undefined.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-primitive.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-primitive.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-step-value-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/length.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/length.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/name.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/name.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/non-constructible.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/non-constructible.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/options-mode.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/options-mode.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/options-padding.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/options-padding.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/options.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/padding-iteration-get-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/padding-iteration-get-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/padding-iteration.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/padding-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/prop-desc.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/prop-desc.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/proto.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/proto.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/result-is-iterator.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/result-is-iterator.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/results-object-from-array.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/results-object-from-array.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/results-object-has-default-attributes.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/results-object-has-default-attributes.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/results-object-has-no-undefined-iterables-properties.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/results-object-has-no-undefined-iterables-properties.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/basic.js-strict:true\": \"test/built-ins/JSON/isRawJSON/basic.js: TypeError: Object has no member 'isRawJSON' <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/builtin.js-strict:true\": \"test/built-ins/JSON/isRawJSON/builtin.js: Test262Error: JSON.isRawJSON is extensible <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/length.js-strict:true\": \"test/built-ins/JSON/isRawJSON/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/name.js-strict:true\": \"test/built-ins/JSON/isRawJSON/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/not-a-constructor.js-strict:true\": \"test/built-ins/JSON/isRawJSON/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/prop-desc.js-strict:true\": \"test/built-ins/JSON/isRawJSON/prop-desc.js: Test262Error: obj should have an own property isRawJSON <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-call-args-after-forward-modification.js-strict:true\": \"test/built-ins/JSON/parse/reviver-call-args-after-forward-modification.js: TypeError: Value is not object coercible <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-context-source-array-literal.js-strict:true\": \"test/built-ins/JSON/parse/reviver-context-source-array-literal.js: Test262Error: context should be an object Expected SameValue(«\\\"undefined\\\"», «\\\"object\\\"») to be true <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-context-source-object-literal.js-strict:true\": \"test/built-ins/JSON/parse/reviver-context-source-object-literal.js: Test262Error: context should be an object Expected SameValue(«\\\"undefined\\\"», «\\\"object\\\"») to be true <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-context-source-primitive-literal.js-strict:true\": \"test/built-ins/JSON/parse/reviver-context-source-primitive-literal.js: Test262Error: context should be an object Expected SameValue(«\\\"undefined\\\"», «\\\"object\\\"») to be true <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-forward-modifies-object.js-strict:true\": \"test/built-ins/JSON/parse/reviver-forward-modifies-object.js: TypeError: Value is not object coercible <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/basic.js-strict:true\": \"test/built-ins/JSON/rawJSON/basic.js: TypeError: Object has no member 'rawJSON' <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/bigint-raw-json-can-be-stringified.js-strict:true\": \"test/built-ins/JSON/rawJSON/bigint-raw-json-can-be-stringified.js: TypeError: Value is not object coercible <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/builtin.js-strict:true\": \"test/built-ins/JSON/rawJSON/builtin.js: Test262Error: JSON.rawJSON is extensible <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/illegal-empty-and-start-end-chars.js-strict:true\": \"test/built-ins/JSON/rawJSON/illegal-empty-and-start-end-chars.js: Test262Error: Expected a SyntaxError but got a TypeError <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/invalid-JSON-text.js-strict:true\": \"test/built-ins/JSON/rawJSON/invalid-JSON-text.js: Test262Error: Expected a SyntaxError but got a TypeError <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/length.js-strict:true\": \"test/built-ins/JSON/rawJSON/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/name.js-strict:true\": \"test/built-ins/JSON/rawJSON/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/not-a-constructor.js-strict:true\": \"test/built-ins/JSON/rawJSON/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/prop-desc.js-strict:true\": \"test/built-ins/JSON/rawJSON/prop-desc.js: Test262Error: obj should have an own property rawJSON <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/returns-expected-object.js-strict:true\": \"test/built-ins/JSON/rawJSON/returns-expected-object.js: TypeError: Object has no member 'rawJSON' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/append-new-values-normalizes-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/append-new-values-normalizes-zero-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/append-new-values.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/append-new-values.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/append-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/append-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/getOrInsert.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/getOrInsert.js: Test262Error: `typeof Map.prototype.getOrInsert` is `function` Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/length.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/name.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/not-a-constructor.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-present-different-key-types.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/returns-value-normalized-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/returns-value-normalized-zero-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values-normalizes-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values-normalizes-zero-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/callbackfn-throws.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/callbackfn-throws.js: Test262Error: Expected a Error but got a TypeError <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/canonical-key-passed-to-callback.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/canonical-key-passed-to-callback.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/check-callback-fn-args.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/check-callback-fn-args.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/check-state-after-callback-fn-throws.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/check-state-after-callback-fn-throws.js: Test262Error: Expected a Error but got a TypeError <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/getOrInsertComputed.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/getOrInsertComputed.js: Test262Error: obj['getOrInsertComputed'] descriptor should be a function Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/not-a-constructor.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-normalized-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-normalized-zero-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/NativeErrors/nativeerror-tostring-message-throws-symbol.js-strict:true\": \"test/built-ins/NativeErrors/nativeerror-tostring-message-throws-symbol.js: Test262Error: If _message_ is a Symbol, EvalError should throw a TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values-__proto__.js-strict:true\": \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values-__proto__.js: Test262Error: Object.setPrototypeOf(ObjProto, { __proto__: null }) throws a TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values.js-strict:true\": \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values.js: Test262Error: Object.setPrototypeOf(ObjProto, Object.create(null)) throws a TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/lookahead-quantifier-match-groups.js-strict:true\": \"test/built-ins/RegExp/lookahead-quantifier-match-groups.js: Test262Error: Actual [a, abc] and expected [a, undefined] should have the same contents. ? quantifier <at omitted>\",\n  \"test/built-ins/RegExp/nullable-quantifier.js-strict:true\": \"test/built-ins/RegExp/nullable-quantifier.js: Test262Error: The regex is expected to match the whole string Expected SameValue(«\\\"a\\\"», «\\\"ab\\\"») to be true <at omitted>\",\n  \"test/built-ins/RegExp/quantifier-integer-limit.js-strict:true\": \"test/built-ins/RegExp/quantifier-integer-limit.js: SyntaxError: Invalid regular expression (regexp2): b{9007199254740991} (Invalid regular expression (regexp2): b{9007199254740991} (error parsing regexp: capture group number out of range in `b{9007199254740991}`)) <at omitted>\",\n  \"test/built-ins/RegExp/unicode_full_case_folding.js-strict:true\": \"test/built-ins/RegExp/unicode_full_case_folding.js: Test262Error: \\\\u0390 does not match \\\\u1fd3 <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_brackets.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_brackets.js: Test262Error: RegExp(\\\"]\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_character_class_escape.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_character_class_escape.js: Test262Error: RegExp(\\\"[\\\\d-a]\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape.js: Test262Error: Invalid IdentityEscape in AtomEscape: '\\\\\\u0000' Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_alpha.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_alpha.js: Test262Error: IdentityEscape in AtomEscape: 'A' Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_c.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_c.js: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_u.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_u.js: Test262Error: RegExp(\\\"\\\\u\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_x.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_x.js: Test262Error: RegExp(\\\"\\\\x\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js: Test262Error: RegExp(\\\"a{\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_octal_escape.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_octal_escape.js: Test262Error: RegExp(\\\"\\\\1\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_quantifiable_assertion.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_quantifiable_assertion.js: Test262Error: RegExp(\\\"(?=.)*\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/String/prototype/replace/regexp-capture-by-index.js-strict:true\": \"test/built-ins/String/prototype/replace/regexp-capture-by-index.js: Test262Error: `$01` before `0` is a capture index in /((((((((((x))))))))))/ Expected SameValue(«\\\"foo-|x|-bar\\\"», «\\\"foo-|x0|-bar\\\"») to be true <at omitted>\",\n  \"test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js-strict:true\": \"test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js: Test262Error: Actual [40, 40, 50, 60] and expected [20, 20, 20, 60] should have the same contents.  (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArray/prototype/with/value-throw-completion.js-strict:true\": \"test/built-ins/TypedArray/prototype/with/value-throw-completion.js: Test262Error: Positive too large index Expected a MyError but got a RangeError (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js: Test262Error: 1 setter should be unreachable! (Testing with BigInt64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js: Test262Error: 1 setter should be unreachable! (Testing with BigInt64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-valid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-valid-index-reflect-set.js: Test262Error: Reflect.set should fail (receiver: another typed array of shorter length) (Testing with BigInt64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-prototype-chain-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-prototype-chain-set.js: Test262Error: 1 setter should be unreachable! (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-reflect-set.js: Test262Error: 1 setter should be unreachable! (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-object.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-object.js: Test262Error: [[Set]] succeeeds <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-proto.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-proto.js: Test262Error: valueOf is called exactly once Expected SameValue(«0», «1») to be true <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-valid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-valid-index-reflect-set.js: Test262Error: Reflect.set should fail (receiver: another typed array of shorter length) (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/adds-object-element.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/adds-object-element.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/getOrInsert.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/getOrInsert.js: Test262Error: typeof WeakMap.prototype.getOrInsert is \\\"function\\\" Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/length.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/name.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/not-a-constructor.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-not-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-not-present-object-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-present-object-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-object-element.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-object-element.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-value-different-callbackfn.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-value-different-callbackfn.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/callbackfn-throws.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/callbackfn-throws.js: Test262Error: function Error() { [native code] } Expected a Error but got a TypeError <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/getOrInsertComputed.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/getOrInsertComputed.js: Test262Error: obj['getOrInsertComputed'] descriptor should be a function Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/not-a-constructor.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-present-object-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/language/comments/hashbang/function-constructor.js-strict:true\": \"test/language/comments/hashbang/function-constructor.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/comments/hashbang/module.js-strict:false\": \"test/language/comments/hashbang/module.js: file:///TestTC39/test262/test/language/comments/hashbang/module.js: Line 1:28 Unexpected token ILLEGAL (and 2 more errors)\",\n  \"test/language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js-strict:true\": \"test/language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/destructuring/binding/syntax/destructuring-object-parameters-function-arguments-length.js-strict:true\": \"test/language/destructuring/binding/syntax/destructuring-object-parameters-function-arguments-length.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/expressions/assignment/fn-name-lhs-cover.js-strict:true\": \"test/language/expressions/assignment/fn-name-lhs-cover.js: Test262Error: obj['name'] descriptor value should be ; obj['name'] value should be  <at omitted>\",\n  \"test/language/expressions/class/class-name-ident-await-escaped-module.js-strict:true\": \"test/language/expressions/class/class-name-ident-await-escaped-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/expressions/class/class-name-ident-await-module.js-strict:true\": \"test/language/expressions/class/class-name-ident-await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/expressions/class/elements/private-getter-is-not-a-own-property.js-strict:true\": \"test/language/expressions/class/elements/private-getter-is-not-a-own-property.js: TypeError: Object has no member '__lookupGetter__' <at omitted>\",\n  \"test/language/expressions/class/elements/private-setter-is-not-a-own-property.js-strict:true\": \"test/language/expressions/class/elements/private-setter-is-not-a-own-property.js: TypeError: Object has no member '__lookupSetter__' <at omitted>\",\n  \"test/language/expressions/greater-than-or-equal/S11.8.4_A4.12_T1.js-strict:true\": \"test/language/expressions/greater-than-or-equal/S11.8.4_A4.12_T1.js: Test262Error: #10: (\\\"\\\\u{10000}\\\" >= \\\"\\\\uFFFF\\\") === false <at omitted>\",\n  \"test/language/expressions/greater-than/S11.8.2_A4.12_T1.js-strict:true\": \"test/language/expressions/greater-than/S11.8.2_A4.12_T1.js: Test262Error: #9: (\\\"\\\\uDC00\\\" > \\\"\\\\uD800\\\") === true <at omitted>\",\n  \"test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js-strict:true\": \"test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js: file:///TestTC39/test262/test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js: Line 28:25 import not supported in script (and 19 more errors)\",\n  \"test/language/expressions/import.meta/same-object-returned.js-strict:true\": \"test/language/expressions/import.meta/same-object-returned.js: file:///TestTC39/test262/test/language/expressions/import.meta/same-object-returned.js: Line 28:9 import not supported in script (and 3 more errors)\",\n  \"test/language/expressions/import.meta/syntax/goal-module-nested-function.js-strict:true\": \"test/language/expressions/import.meta/syntax/goal-module-nested-function.js: file:///TestTC39/test262/test/language/expressions/import.meta/syntax/goal-module-nested-function.js: Line 16:3 import not supported in script (and 4 more errors)\",\n  \"test/language/expressions/import.meta/syntax/goal-module.js-strict:true\": \"test/language/expressions/import.meta/syntax/goal-module.js: file:///TestTC39/test262/test/language/expressions/import.meta/syntax/goal-module.js: Line 15:1 import not supported in script (and 3 more errors)\",\n  \"test/language/expressions/less-than-or-equal/S11.8.3_A4.12_T1.js-strict:true\": \"test/language/expressions/less-than-or-equal/S11.8.3_A4.12_T1.js: Test262Error: #10: (\\\"\\\\u{10000}\\\" <= \\\"\\\\uFFFF\\\") === true <at omitted>\",\n  \"test/language/expressions/less-than/S11.8.1_A4.12_T1.js-strict:true\": \"test/language/expressions/less-than/S11.8.1_A4.12_T1.js: Test262Error: #9: (\\\"\\\\uD800\\\" < \\\"\\\\uDC00\\\") === true <at omitted>\",\n  \"test/language/expressions/optional-chaining/iteration-statement-for-await-of.js-strict:true\": \"test/language/expressions/optional-chaining/iteration-statement-for-await-of.js: test/language/expressions/optional-chaining/iteration-statement-for-await-of.js: Line 32:7 Unexpected token await (and 9 more errors)\",\n  \"test/language/expressions/optional-chaining/member-expression.js-strict:true\": \"test/language/expressions/optional-chaining/member-expression.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/identifiers/part-unicode-15.1.0-class-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0-class-escaped.js: test/language/identifiers/part-unicode-15.1.0-class-escaped.js: Line 20:22 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-15.1.0-class.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0-class.js: test/language/identifiers/part-unicode-15.1.0-class.js: Line 17:11 Unexpected token ILLEGAL (and 4 more errors)\",\n  \"test/language/identifiers/part-unicode-15.1.0-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0-escaped.js: test/language/identifiers/part-unicode-15.1.0-escaped.js: Line 17:5 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-15.1.0.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0.js: test/language/identifiers/part-unicode-15.1.0.js: Line 15:12 Unexpected token ILLEGAL (and 3 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0-class-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0-class-escaped.js: test/language/identifiers/part-unicode-16.0.0-class-escaped.js: Line 20:10 Unexpected token ILLEGAL (and 3 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0-class.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0-class.js: test/language/identifiers/part-unicode-16.0.0-class.js: Line 17:5 Unexpected token ILLEGAL (and 133 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0-escaped.js: test/language/identifiers/part-unicode-16.0.0-escaped.js: Line 17:5 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0.js: test/language/identifiers/part-unicode-16.0.0.js: Line 15:6 Unexpected token ILLEGAL (and 132 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0-class-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0-class-escaped.js: test/language/identifiers/part-unicode-17.0.0-class-escaped.js: Line 20:10 Unexpected token ILLEGAL (and 48 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0-class.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0-class.js: test/language/identifiers/part-unicode-17.0.0-class.js: Line 17:5 Unexpected token ILLEGAL (and 54 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0-escaped.js: test/language/identifiers/part-unicode-17.0.0-escaped.js: Line 17:5 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0.js: test/language/identifiers/part-unicode-17.0.0.js: Line 15:6 Unexpected token ILLEGAL (and 53 more errors)\",\n  \"test/language/import/import-defer/deferred-namespace-object/exotic-object-behavior.js-strict:true\": \"test/language/import/import-defer/deferred-namespace-object/exotic-object-behavior.js: file:///TestTC39/test262/test/language/import/import-defer/deferred-namespace-object/exotic-object-behavior.js: Line 27:14 Unexpected token *\",\n  \"test/language/import/import-defer/deferred-namespace-object/identity.js-strict:true\": \"test/language/import/import-defer/deferred-namespace-object/identity.js: file:///TestTC39/test262/test/language/import/import-defer/deferred-namespace-object/identity.js: Line 36:14 Unexpected token *\",\n  \"test/language/import/import-defer/deferred-namespace-object/to-string-tag.js-strict:true\": \"test/language/import/import-defer/deferred-namespace-object/to-string-tag.js: file:///TestTC39/test262/test/language/import/import-defer/deferred-namespace-object/to-string-tag.js: Line 29:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/get-other-while-dep-evaluating-async/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-dep-evaluating-async/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-dep-evaluating-async/dep-1.1_FIXTURE.js: Line 5:14 Unexpected token * (and 12 more errors)\",\n  \"test/language/import/import-defer/errors/get-other-while-dep-evaluating/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-dep-evaluating/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-dep-evaluating/dep-1_FIXTURE.js: Line 4:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/errors/get-other-while-evaluating-async/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-evaluating-async/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-evaluating-async/dep-1.1_FIXTURE.js: Line 5:14 Unexpected token * (and 12 more errors)\",\n  \"test/language/import/import-defer/errors/get-other-while-evaluating/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-evaluating/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-evaluating/dep_FIXTURE.js: Line 4:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/errors/get-self-while-defer-evaluating/main.js-strict:true\": \"test/language/import/import-defer/errors/get-self-while-defer-evaluating/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-self-while-defer-evaluating/main.js: Line 39:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/get-self-while-evaluating-async/main.js-strict:true\": \"test/language/import/import-defer/errors/get-self-while-evaluating-async/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-self-while-evaluating-async/main.js: Line 44:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/get-self-while-evaluating.js-strict:true\": \"test/language/import/import-defer/errors/get-self-while-evaluating.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-self-while-evaluating.js: Line 39:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/module-throws/third-party-evaluation-after-defer-import.js-strict:true\": \"test/language/import/import-defer/errors/module-throws/third-party-evaluation-after-defer-import.js: file:///TestTC39/test262/test/language/import/import-defer/errors/module-throws/third-party-evaluation-after-defer-import.js: Line 33:14 Unexpected token * (and 2 more errors)\",\n  \"test/language/import/import-defer/errors/module-throws/trigger-evaluation.js-strict:true\": \"test/language/import/import-defer/errors/module-throws/trigger-evaluation.js: file:///TestTC39/test262/test/language/import/import-defer/errors/module-throws/trigger-evaluation.js: Line 33:14 Unexpected token * (and 10 more errors)\",\n  \"test/language/import/import-defer/evaluation-sync/import-defer-does-not-evaluate.js-strict:true\": \"test/language/import/import-defer/evaluation-sync/import-defer-does-not-evaluate.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-sync/import-defer-does-not-evaluate.js: Line 34:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-sync/module-imported-defer-and-eager.js-strict:true\": \"test/language/import/import-defer/evaluation-sync/module-imported-defer-and-eager.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-sync/module-imported-defer-and-eager.js: Line 48:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/flattening-order/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/flattening-order/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/flattening-order/main.js: Line 52:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/import-defer-async-module/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/import-defer-async-module/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/import-defer-async-module/main.js: Line 50:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/import-defer-transitive-async-module/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/import-defer-transitive-async-module/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/import-defer-transitive-async-module/main.js: Line 50:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/sync-dependency-of-deferred-async-module/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/sync-dependency-of-deferred-async-module/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/sync-dependency-of-deferred-async-module/main.js: Line 50:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-getPrototypeOf.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-getPrototypeOf.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-getPrototypeOf.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-isExtensible.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-isExtensible.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-isExtensible.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-preventExtensions.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-preventExtensions.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-preventExtensions.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-private-name-access.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-private-name-access.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-private-name-access.js: Line 30:14 Unexpected token * (and 4 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-set-string-exported.js: Line 19:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-not-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-not-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-set-string-not-exported.js: Line 19:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-setPrototypeOf.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-setPrototypeOf.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-setPrototypeOf.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-exported.js: Line 19:14 Unexpected token * (and 7 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-not-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-not-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-not-exported.js: Line 19:14 Unexpected token * (and 7 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKey-names.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKey-names.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKey-names.js: Line 20:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys-symbols.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys-symbols.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys-symbols.js: Line 20:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys.js: Line 20:14 Unexpected token *\",\n  \"test/language/import/import-defer/syntax/import-attributes.js-strict:true\": \"test/language/import/import-defer/syntax/import-attributes.js: file:///TestTC39/test262/test/language/import/import-defer/syntax/import-attributes.js: Line 22:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/syntax/valid-defer-namespace.js-strict:true\": \"test/language/import/import-defer/syntax/valid-defer-namespace.js: file:///TestTC39/test262/test/language/import/import-defer/syntax/valid-defer-namespace.js: Line 22:14 Unexpected token *\",\n  \"test/language/literals/numeric/non-octal-decimal-integer.js-strict:false\": \"test/language/literals/numeric/non-octal-decimal-integer.js: test/language/literals/numeric/non-octal-decimal-integer.js: Line 28:18 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/literals/regexp/S7.8.5_A1.1_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A1.1_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"\\\\\\\\ud800\\\"», «\\\"\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/S7.8.5_A1.4_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A1.4_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/S7.8.5_A2.1_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A2.1_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"nnnn\\\\\\\\ud800\\\"», «\\\"nnnn\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/S7.8.5_A2.4_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A2.4_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"a\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"a\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/invalid-optional-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-optional-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/invalid-optional-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-optional-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/invalid-range-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-range-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/invalid-range-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-range-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-case-mapping.js-strict:true\": \"test/language/literals/regexp/u-case-mapping.js: Test262Error: Case mapping is not applied in the absence of the `u` flag Expected SameValue(«true», «false») to be true <at omitted>\",\n  \"test/language/literals/regexp/u-invalid-class-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-class-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-extended-pattern-char.js-strict:true\": \"test/language/literals/regexp/u-invalid-extended-pattern-char.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-identity-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-identity-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-legacy-octal-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-legacy-octal-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-non-empty-class-ranges-no-dash-a.js-strict:true\": \"test/language/literals/regexp/u-invalid-non-empty-class-ranges-no-dash-a.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-oob-decimal-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-oob-decimal-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-negative-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-negative-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-negative-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-negative-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/string/S7.8.4_A4.3_T1.js-strict:true\": \"test/language/literals/string/S7.8.4_A4.3_T1.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/string/S7.8.4_A4.3_T2.js-strict:true\": \"test/language/literals/string/S7.8.4_A4.3_T2.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from-and-import-star-as-and-export.js-strict:true\": \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from-and-import-star-as-and-export.js: SyntaxError: The requested module \\\"./namespace-unambiguous-if-import-star-as-and-export.js\\\" contains conflicting star exports for name \\\"foo\\\" <at omitted>\",\n  \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-import-star-as-and-export.js-strict:true\": \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-import-star-as-and-export.js: SyntaxError: The requested module \\\"./namespace-unambiguous-if-import-star-as-and-export.js\\\" contains conflicting star exports for name \\\"foo\\\" <at omitted>\",\n  \"test/language/module-code/early-dup-top-function.js-strict:true\": \"test/language/module-code/early-dup-top-function.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/early-new-target.js-strict:true\": \"test/language/module-code/early-new-target.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/eval-this.js-strict:true\": \"test/language/module-code/eval-this.js: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true <at omitted>\",\n  \"test/language/module-code/export-default-asyncgenerator-declaration-binding.js-strict:true\": \"test/language/module-code/export-default-asyncgenerator-declaration-binding.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/module-code/export-expname-from-as-unpaired-surrogate.js-strict:true\": \"test/language/module-code/export-expname-from-as-unpaired-surrogate.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/export-expname-string-binding.js-strict:true\": \"test/language/module-code/export-expname-string-binding.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/export-expname-unpaired-surrogate.js-strict:true\": \"test/language/module-code/export-expname-unpaired-surrogate.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-iee-err-not-found-as.js-strict:true\": \"test/language/module-code/instn-iee-err-not-found-as.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-iee-err-not-found.js-strict:true\": \"test/language/module-code/instn-iee-err-not-found.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-named-err-not-found-as.js-strict:true\": \"test/language/module-code/instn-named-err-not-found-as.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-named-err-not-found-dflt.js-strict:true\": \"test/language/module-code/instn-named-err-not-found-dflt.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-named-err-not-found.js-strict:true\": \"test/language/module-code/instn-named-err-not-found.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-star-err-not-found.js-strict:true\": \"test/language/module-code/instn-star-err-not-found.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/parse-err-hoist-lex-fun.js-strict:true\": \"test/language/module-code/parse-err-hoist-lex-fun.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/parse-err-return.js-strict:true\": \"test/language/module-code/parse-err-return.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/top-level-await/module-graphs-does-not-hang.js-strict:true\": \"test/language/module-code/top-level-await/module-graphs-does-not-hang.js: dynamic modules not enabled in the host program\",\n  \"test/language/module-code/top-level-await/new-await.js-strict:true\": \"test/language/module-code/top-level-await/new-await.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/top-level-await/no-operand.js-strict:true\": \"test/language/module-code/top-level-await/no-operand.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/top-level-await/pending-async-dep-from-cycle.js-strict:true\": \"test/language/module-code/top-level-await/pending-async-dep-from-cycle.js: Test262Error: Actual [cycle leaf start, cycle leaf end, cycle root start, importer of cycle leaf, cycle root end] and expected [cycle leaf start, cycle leaf end, cycle root start, cycle root end, importer of cycle leaf] should have the same contents. \",\n  \"test/language/reserved-words/await-module.js-strict:true\": \"test/language/reserved-words/await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/class/class-name-ident-await-escaped-module.js-strict:true\": \"test/language/statements/class/class-name-ident-await-escaped-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/class/class-name-ident-await-module.js-strict:true\": \"test/language/statements/class/class-name-ident-await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/class/elements/private-class-field-on-nonextensible-objects.js-strict:true\": \"test/language/statements/class/elements/private-class-field-on-nonextensible-objects.js: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/language/statements/class/elements/private-getter-is-not-a-own-property.js-strict:true\": \"test/language/statements/class/elements/private-getter-is-not-a-own-property.js: TypeError: Object has no member '__lookupGetter__' <at omitted>\",\n  \"test/language/statements/class/elements/private-setter-is-not-a-own-property.js-strict:true\": \"test/language/statements/class/elements/private-setter-is-not-a-own-property.js: TypeError: Object has no member '__lookupSetter__' <at omitted>\",\n  \"test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js-strict:true\": \"test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js: test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js: Line 41:4 Unexpected token * (and 1 more errors)\",\n  \"test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js-strict:true\": \"test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js: test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js: Line 41:4 Unexpected token * (and 1 more errors)\",\n  \"test/language/statements/class/subclass/private-class-field-on-nonextensible-return-override.js-strict:true\": \"test/language/statements/class/subclass/private-class-field-on-nonextensible-return-override.js: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/language/statements/labeled/value-await-module-escaped.js-strict:true\": \"test/language/statements/labeled/value-await-module-escaped.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/labeled/value-await-module.js-strict:true\": \"test/language/statements/labeled/value-await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/with/get-binding-value-call-with-proxy-env.js-strict:false\": \"test/language/statements/with/get-binding-value-call-with-proxy-env.js: Test262Error: Actual [has:Object, get:Symbol(Symbol.unscopables), get:Object] and expected [has:Object, get:Symbol(Symbol.unscopables), has:Object, get:Object] should have the same contents.  <at omitted>\",\n  \"test/language/statements/with/get-binding-value-idref-with-proxy-env.js-strict:false\": \"test/language/statements/with/get-binding-value-idref-with-proxy-env.js: Test262Error: Actual [has:Object, get:Symbol(Symbol.unscopables), get:Object] and expected [has:Object, get:Symbol(Symbol.unscopables), has:Object, get:Object] should have the same contents.  <at omitted>\",\n  \"test/language/statements/with/get-mutable-binding-binding-deleted-in-get-unscopables-strict-mode.js-strict:false\": \"test/language/statements/with/get-mutable-binding-binding-deleted-in-get-unscopables-strict-mode.js: Test262Error: Expected a ReferenceError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/language/statements/with/set-mutable-binding-binding-deleted-with-typed-array-in-proto-chain.js-strict:false\": \"test/language/statements/with/set-mutable-binding-binding-deleted-with-typed-array-in-proto-chain.js: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true <at omitted>\",\n  \"test/language/statements/with/set-mutable-binding-idref-compound-assign-with-proxy-env.js-strict:false\": \"test/language/statements/with/set-mutable-binding-idref-compound-assign-with-proxy-env.js: Test262Error: Actual [has:p, get:Symbol(Symbol.unscopables), get:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] and expected [has:p, get:Symbol(Symbol.unscopables), has:p, get:p, has:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] should have the same contents.  <at omitted>\",\n  \"test/language/statements/with/set-mutable-binding-idref-with-proxy-env.js-strict:false\": \"test/language/statements/with/set-mutable-binding-idref-with-proxy-env.js: Test262Error: Actual [has:p, get:Symbol(Symbol.unscopables), set:p, getOwnPropertyDescriptor:p, defineProperty:p] and expected [has:p, get:Symbol(Symbol.unscopables), has:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] should have the same contents.  <at omitted>\"\n}\n"
  },
  {
    "path": "internal/js/tc39/breaking_test_errors-stripTypes=true.json",
    "content": "{\n  \"test/annexB/built-ins/Function/createdynfn-html-close-comment-body.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-close-comment-body.js: SyntaxError: SyntaxError: <eval>: Line 4:3 Unexpected token > (and 3 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-html-close-comment-params.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-close-comment-params.js: SyntaxError: SyntaxError: <eval>: Line 2:1 Unexpected token -- (and 5 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-html-open-comment-body.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-open-comment-body.js: SyntaxError: SyntaxError: <eval>: Line 3:1 Unexpected token < (and 2 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-html-open-comment-params.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-html-open-comment-params.js: SyntaxError: SyntaxError: <eval>: Line 1:21 Unexpected token < (and 5 more errors) <at omitted>\",\n  \"test/annexB/built-ins/Function/createdynfn-no-line-terminator-html-close-comment-body.js-strict:true\": \"test/annexB/built-ins/Function/createdynfn-no-line-terminator-html-close-comment-body.js: SyntaxError: SyntaxError: <eval>: Line 3:3 Unexpected token > (and 3 more errors) <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-control-escape-russian-letter.js: Test262Error: invalid \\\\c escape matched c rather than \\\\c when followed by А Expected SameValue(«cА», «null») to be true <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-invalid-control-escape-character-class.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-invalid-control-escape-character-class.js: Test262Error: Character \\\\ missing from character class [\\\\c\\u0000] <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js-strict:true\": \"test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"a\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"a\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/annexB/built-ins/RegExp/prototype/compile/pattern-string-invalid-u.js-strict:true\": \"test/annexB/built-ins/RegExp/prototype/compile/pattern-string-invalid-u.js: Test262Error: invalid pattern: { Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/AggregateError/errors-iterabletolist.js-strict:true\": \"test/built-ins/AggregateError/errors-iterabletolist.js: Test262Error: GetMethod(obj, @@iterator) returns undefined Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js-strict:true\": \"test/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js: Test262Error: Actual [1, 2] and expected [1, 2] should have the same contents. a.flat(undefined) uses default depth of 1 <at omitted>\",\n  \"test/built-ins/AsyncFunction/AsyncFunction-is-subclass.js-strict:true\": \"test/built-ins/AsyncFunction/AsyncFunction-is-subclass.js: Test262Error: Prototype of constructor is Function Expected SameValue(«function () { [native code] }», «function Function() { [native code] }») to be true <at omitted>\",\n  \"test/built-ins/DataView/prototype/setBigInt64/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setBigInt64/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setBigUint64/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setBigUint64/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setFloat16/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setFloat16/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setFloat32/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setFloat32/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setFloat64/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setFloat64/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setInt16/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setInt16/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setInt32/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setInt32/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setInt8/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setInt8/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setUint16/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setUint16/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setUint32/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setUint32/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/DataView/prototype/setUint8/immutable-buffer.js-strict:true\": \"test/built-ins/DataView/prototype/setUint8/immutable-buffer.js: TypeError: Object has no member 'transferToImmutable' <at omitted>\",\n  \"test/built-ins/Date/UTC/fp-evaluation-order.js-strict:true\": \"test/built-ins/Date/UTC/fp-evaluation-order.js: Test262Error: order of operations / precision in MakeTime Expected SameValue(«29256», «29312») to be true <at omitted>\",\n  \"test/built-ins/Error/error-message-tostring-symbol.js-strict:true\": \"test/built-ins/Error/error-message-tostring-symbol.js: Test262Error: If _message_ is a Symbol, Error must throw TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Error/isError/bigints.js-strict:true\": \"test/built-ins/Error/isError/bigints.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/error-subclass.js-strict:true\": \"test/built-ins/Error/isError/error-subclass.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/errors.js-strict:true\": \"test/built-ins/Error/isError/errors.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/fake-errors.js-strict:true\": \"test/built-ins/Error/isError/fake-errors.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/is-a-constructor.js-strict:true\": \"test/built-ins/Error/isError/is-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/Error/isError/name.js-strict:true\": \"test/built-ins/Error/isError/name.js: TypeError: Cannot read property 'name' of undefined <at omitted>\",\n  \"test/built-ins/Error/isError/non-error-objects.js-strict:true\": \"test/built-ins/Error/isError/non-error-objects.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/primitives.js-strict:true\": \"test/built-ins/Error/isError/primitives.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Error/isError/prop-desc.js-strict:true\": \"test/built-ins/Error/isError/prop-desc.js: Test262Error: obj should have an own property isError <at omitted>\",\n  \"test/built-ins/Error/isError/symbols.js-strict:true\": \"test/built-ins/Error/isError/symbols.js: TypeError: Object has no member 'isError' <at omitted>\",\n  \"test/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js-strict:true\": \"test/built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/GeneratorPrototype/return/try-finally-set-property-within-try.js-strict:true\": \"panic while running test/built-ins/GeneratorPrototype/return/try-finally-set-property-within-try.js: runtime error: slice bounds out of range [:-1]\",\n  \"test/built-ins/Iterator/concat/arguments-checked-in-order.js-strict:true\": \"test/built-ins/Iterator/concat/arguments-checked-in-order.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/fresh-iterator-result.js-strict:true\": \"test/built-ins/Iterator/concat/fresh-iterator-result.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/get-iterator-method-only-once.js-strict:true\": \"test/built-ins/Iterator/concat/get-iterator-method-only-once.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/get-iterator-method-throws.js-strict:true\": \"test/built-ins/Iterator/concat/get-iterator-method-throws.js: Test262Error: Expected a Test262Error but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/get-value-after-done.js-strict:true\": \"test/built-ins/Iterator/concat/get-value-after-done.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/inner-iterator-created-in-order.js-strict:true\": \"test/built-ins/Iterator/concat/inner-iterator-created-in-order.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/is-function.js-strict:true\": \"test/built-ins/Iterator/concat/is-function.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/iterable-primitive-wrapper-objects.js-strict:true\": \"test/built-ins/Iterator/concat/iterable-primitive-wrapper-objects.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/length.js-strict:true\": \"test/built-ins/Iterator/concat/length.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/many-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/many-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/name.js-strict:true\": \"test/built-ins/Iterator/concat/name.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-called-with-zero-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-non-object.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-non-object.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-throwing-done.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-throwing-done.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-throwing-value-done.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-returns-throwing-value.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-returns-throwing-value.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/next-method-throws.js-strict:true\": \"test/built-ins/Iterator/concat/next-method-throws.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/non-constructible.js-strict:true\": \"test/built-ins/Iterator/concat/non-constructible.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/prop-desc.js-strict:true\": \"test/built-ins/Iterator/concat/prop-desc.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/proto.js-strict:true\": \"test/built-ins/Iterator/concat/proto.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/result-is-iterator.js-strict:true\": \"test/built-ins/Iterator/concat/result-is-iterator.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-is-forwarded.js-strict:true\": \"test/built-ins/Iterator/concat/return-is-forwarded.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js-strict:true\": \"test/built-ins/Iterator/concat/return-is-not-forwarded-after-exhaustion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js-strict:true\": \"test/built-ins/Iterator/concat/return-is-not-forwarded-before-initial-start.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/return-method-called-with-zero-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/single-argument.js-strict:true\": \"test/built-ins/Iterator/concat/single-argument.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-iterable-not-an-object.js: Test262Error: iterable is undefined Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-method-not-callable.js: Test262Error: iterable has no iterator method Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js-strict:true\": \"test/built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/concat/zero-arguments.js-strict:true\": \"test/built-ins/Iterator/concat/zero-arguments.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/basic-longest.js-strict:true\": \"test/built-ins/Iterator/zip/basic-longest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/basic-shortest.js-strict:true\": \"test/built-ins/Iterator/zip/basic-shortest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/basic-strict.js-strict:true\": \"test/built-ins/Iterator/zip/basic-strict.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/is-function.js-strict:true\": \"test/built-ins/Iterator/zip/is-function.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-containing-string-objects.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-containing-string-objects.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration-after-reading-options.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration-after-reading-options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration-get-iterator-flattenable-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration-get-iterator-flattenable-abrupt-completion.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration-iterator-step-value-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-iteration.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-iteration.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterables-primitive.js-strict:true\": \"test/built-ins/Iterator/zip/iterables-primitive.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-non-iterable.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-non-iterable.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-iterator-step-value-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/iterator-zip-iteration.js-strict:true\": \"test/built-ins/Iterator/zip/iterator-zip-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/length.js-strict:true\": \"test/built-ins/Iterator/zip/length.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/name.js-strict:true\": \"test/built-ins/Iterator/zip/name.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/non-constructible.js-strict:true\": \"test/built-ins/Iterator/zip/non-constructible.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/options-mode.js-strict:true\": \"test/built-ins/Iterator/zip/options-mode.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/options-padding.js-strict:true\": \"test/built-ins/Iterator/zip/options-padding.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/options.js-strict:true\": \"test/built-ins/Iterator/zip/options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration-get-iterator-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration-get-iterator-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration-iterator-close-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration-iterator-step-value-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/padding-iteration.js-strict:true\": \"test/built-ins/Iterator/zip/padding-iteration.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zip/prop-desc.js-strict:true\": \"test/built-ins/Iterator/zip/prop-desc.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/proto.js-strict:true\": \"test/built-ins/Iterator/zip/proto.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/result-is-iterator.js-strict:true\": \"test/built-ins/Iterator/zip/result-is-iterator.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-start-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zip/suspended-yield-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/basic-longest.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/basic-longest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/basic-shortest.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/basic-shortest.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/basic-strict.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/basic-strict.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/is-function.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/is-function.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-containing-string-objects.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-containing-string-objects.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-after-reading-options.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-after-reading-options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-deleted.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-deleted.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-enumerable.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-enumerable.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-iterator-flattenable-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-iterator-flattenable-abrupt-completion.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-own-property-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-get-own-property-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-inherited.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-inherited.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-symbol-key.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-symbol-key.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration-undefined.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration-undefined.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-iteration.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterables-primitive.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterables-primitive.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-step-value-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-iterator-step-value-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-longest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-shortest-iterator-close-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-not-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-close-i-is-zero-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration-strict-iterator-step-abrupt-completion.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/iterator-zip-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/length.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/length.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/name.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/name.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/non-constructible.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/non-constructible.js: Test262Error: Expected a TypeError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/options-mode.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/options-mode.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/options-padding.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/options-padding.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/options.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/options.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/padding-iteration-get-abrupt-completion.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/padding-iteration-get-abrupt-completion.js: Test262Error: Expected a ExpectedError but got a ReferenceError <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/padding-iteration.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/padding-iteration.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/prop-desc.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/prop-desc.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/proto.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/proto.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/result-is-iterator.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/result-is-iterator.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/results-object-from-array.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/results-object-from-array.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/results-object-has-default-attributes.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/results-object-has-default-attributes.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/results-object-has-no-undefined-iterables-properties.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/results-object-has-no-undefined-iterables-properties.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-start-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-next.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-next.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-return.js-strict:true\": \"test/built-ins/Iterator/zipKeyed/suspended-yield-iterator-close-calls-return.js: ReferenceError: Iterator is not defined <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/basic.js-strict:true\": \"test/built-ins/JSON/isRawJSON/basic.js: TypeError: Object has no member 'isRawJSON' <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/builtin.js-strict:true\": \"test/built-ins/JSON/isRawJSON/builtin.js: Test262Error: JSON.isRawJSON is extensible <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/length.js-strict:true\": \"test/built-ins/JSON/isRawJSON/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/name.js-strict:true\": \"test/built-ins/JSON/isRawJSON/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/not-a-constructor.js-strict:true\": \"test/built-ins/JSON/isRawJSON/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/JSON/isRawJSON/prop-desc.js-strict:true\": \"test/built-ins/JSON/isRawJSON/prop-desc.js: Test262Error: obj should have an own property isRawJSON <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-call-args-after-forward-modification.js-strict:true\": \"test/built-ins/JSON/parse/reviver-call-args-after-forward-modification.js: TypeError: Value is not object coercible <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-context-source-array-literal.js-strict:true\": \"test/built-ins/JSON/parse/reviver-context-source-array-literal.js: Test262Error: context should be an object Expected SameValue(«\\\"undefined\\\"», «\\\"object\\\"») to be true <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-context-source-object-literal.js-strict:true\": \"test/built-ins/JSON/parse/reviver-context-source-object-literal.js: Test262Error: context should be an object Expected SameValue(«\\\"undefined\\\"», «\\\"object\\\"») to be true <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-context-source-primitive-literal.js-strict:true\": \"test/built-ins/JSON/parse/reviver-context-source-primitive-literal.js: Test262Error: context should be an object Expected SameValue(«\\\"undefined\\\"», «\\\"object\\\"») to be true <at omitted>\",\n  \"test/built-ins/JSON/parse/reviver-forward-modifies-object.js-strict:true\": \"test/built-ins/JSON/parse/reviver-forward-modifies-object.js: TypeError: Value is not object coercible <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/basic.js-strict:true\": \"test/built-ins/JSON/rawJSON/basic.js: TypeError: Object has no member 'rawJSON' <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/bigint-raw-json-can-be-stringified.js-strict:true\": \"test/built-ins/JSON/rawJSON/bigint-raw-json-can-be-stringified.js: TypeError: Value is not object coercible <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/builtin.js-strict:true\": \"test/built-ins/JSON/rawJSON/builtin.js: Test262Error: JSON.rawJSON is extensible <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/illegal-empty-and-start-end-chars.js-strict:true\": \"test/built-ins/JSON/rawJSON/illegal-empty-and-start-end-chars.js: Test262Error: Expected a SyntaxError but got a TypeError <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/invalid-JSON-text.js-strict:true\": \"test/built-ins/JSON/rawJSON/invalid-JSON-text.js: Test262Error: Expected a SyntaxError but got a TypeError <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/length.js-strict:true\": \"test/built-ins/JSON/rawJSON/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/name.js-strict:true\": \"test/built-ins/JSON/rawJSON/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/not-a-constructor.js-strict:true\": \"test/built-ins/JSON/rawJSON/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/prop-desc.js-strict:true\": \"test/built-ins/JSON/rawJSON/prop-desc.js: Test262Error: obj should have an own property rawJSON <at omitted>\",\n  \"test/built-ins/JSON/rawJSON/returns-expected-object.js-strict:true\": \"test/built-ins/JSON/rawJSON/returns-expected-object.js: TypeError: Object has no member 'rawJSON' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/append-new-values-normalizes-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/append-new-values-normalizes-zero-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/append-new-values.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/append-new-values.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/append-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/append-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/getOrInsert.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/getOrInsert.js: Test262Error: `typeof Map.prototype.getOrInsert` is `function` Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/length.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/name.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/not-a-constructor.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/returns-value-if-key-is-present-different-key-types.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsert/returns-value-normalized-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsert/returns-value-normalized-zero-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values-normalizes-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values-normalizes-zero-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/append-new-values.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/append-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/callbackfn-throws.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/callbackfn-throws.js: Test262Error: Expected a Error but got a TypeError <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/canonical-key-passed-to-callback.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/canonical-key-passed-to-callback.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/check-callback-fn-args.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/check-callback-fn-args.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/check-state-after-callback-fn-throws.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/check-state-after-callback-fn-throws.js: Test262Error: Expected a Error but got a TypeError <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/different-types-function-callbackfn-does-not-throw.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/getOrInsertComputed.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/getOrInsertComputed.js: Test262Error: obj['getOrInsertComputed'] descriptor should be a function Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/not-a-constructor.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-different-key-types.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-if-key-is-present-different-key-types.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-normalized-zero-key.js-strict:true\": \"test/built-ins/Map/prototype/getOrInsertComputed/returns-value-normalized-zero-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/NativeErrors/nativeerror-tostring-message-throws-symbol.js-strict:true\": \"test/built-ins/NativeErrors/nativeerror-tostring-message-throws-symbol.js: Test262Error: If _message_ is a Symbol, EvalError should throw a TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values-__proto__.js-strict:true\": \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values-__proto__.js: Test262Error: Object.setPrototypeOf(ObjProto, { __proto__: null }) throws a TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values.js-strict:true\": \"test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values.js: Test262Error: Object.setPrototypeOf(ObjProto, Object.create(null)) throws a TypeError Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-negative-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-negative-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js-strict:true\": \"test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js: SyntaxError: Invalid flags supplied to RegExp constructor 'v' <at omitted>\",\n  \"test/built-ins/RegExp/lookahead-quantifier-match-groups.js-strict:true\": \"test/built-ins/RegExp/lookahead-quantifier-match-groups.js: Test262Error: Actual [a, abc] and expected [a, undefined] should have the same contents. ? quantifier <at omitted>\",\n  \"test/built-ins/RegExp/nullable-quantifier.js-strict:true\": \"test/built-ins/RegExp/nullable-quantifier.js: Test262Error: The regex is expected to match the whole string Expected SameValue(«\\\"a\\\"», «\\\"ab\\\"») to be true <at omitted>\",\n  \"test/built-ins/RegExp/quantifier-integer-limit.js-strict:true\": \"test/built-ins/RegExp/quantifier-integer-limit.js: SyntaxError: Invalid regular expression (regexp2): b{9007199254740991} (Invalid regular expression (regexp2): b{9007199254740991} (error parsing regexp: capture group number out of range in `b{9007199254740991}`)) <at omitted>\",\n  \"test/built-ins/RegExp/unicode_full_case_folding.js-strict:true\": \"test/built-ins/RegExp/unicode_full_case_folding.js: Test262Error: \\\\u0390 does not match \\\\u1fd3 <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_brackets.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_brackets.js: Test262Error: RegExp(\\\"]\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_character_class_escape.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_character_class_escape.js: Test262Error: RegExp(\\\"[\\\\d-a]\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape.js: Test262Error: Invalid IdentityEscape in AtomEscape: '\\\\\\u0000' Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_alpha.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_alpha.js: Test262Error: IdentityEscape in AtomEscape: 'A' Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_c.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_c.js: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_u.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_u.js: Test262Error: RegExp(\\\"\\\\u\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_identity_escape_x.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_identity_escape_x.js: Test262Error: RegExp(\\\"\\\\x\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_incomplete_quantifier.js: Test262Error: RegExp(\\\"a{\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_octal_escape.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_octal_escape.js: Test262Error: RegExp(\\\"\\\\1\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/RegExp/unicode_restricted_quantifiable_assertion.js-strict:true\": \"test/built-ins/RegExp/unicode_restricted_quantifiable_assertion.js: Test262Error: RegExp(\\\"(?=.)*\\\", \\\"u\\\"):  Expected a SyntaxError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/built-ins/String/prototype/replace/regexp-capture-by-index.js-strict:true\": \"test/built-ins/String/prototype/replace/regexp-capture-by-index.js: Test262Error: `$01` before `0` is a capture index in /((((((((((x))))))))))/ Expected SameValue(«\\\"foo-|x|-bar\\\"», «\\\"foo-|x0|-bar\\\"») to be true <at omitted>\",\n  \"test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js-strict:true\": \"test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js: Test262Error: Actual [40, 40, 50, 60] and expected [20, 20, 20, 60] should have the same contents.  (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArray/prototype/with/value-throw-completion.js-strict:true\": \"test/built-ins/TypedArray/prototype/with/value-throw-completion.js: Test262Error: Positive too large index Expected a MyError but got a RangeError (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js: Test262Error: 1 setter should be unreachable! (Testing with BigInt64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js: Test262Error: 1 setter should be unreachable! (Testing with BigInt64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-valid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-valid-index-reflect-set.js: Test262Error: Reflect.set should fail (receiver: another typed array of shorter length) (Testing with BigInt64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-prototype-chain-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-prototype-chain-set.js: Test262Error: 1 setter should be unreachable! (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-reflect-set.js: Test262Error: 1 setter should be unreachable! (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-object.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-object.js: Test262Error: [[Set]] succeeeds <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-proto.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-proto.js: Test262Error: valueOf is called exactly once Expected SameValue(«0», «1») to be true <at omitted>\",\n  \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-valid-index-reflect-set.js-strict:true\": \"test/built-ins/TypedArrayConstructors/internals/Set/key-is-valid-index-reflect-set.js: Test262Error: Reflect.set should fail (receiver: another typed array of shorter length) (Testing with Float64Array and makePassthrough.) <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/adds-object-element.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/adds-object-element.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/getOrInsert.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/getOrInsert.js: Test262Error: typeof WeakMap.prototype.getOrInsert is \\\"function\\\" Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/length.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/length.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/name.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/name.js: TypeError: Cannot convert undefined or null to object <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/not-a-constructor.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-not-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-not-present-object-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsert/returns-value-if-key-is-present-object-key.js: TypeError: Object has no member 'getOrInsert' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-object-element.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-object-element.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-value-different-callbackfn.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/adds-value-different-callbackfn.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/callbackfn-throws.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/callbackfn-throws.js: Test262Error: function Error() { [native code] } Expected a Error but got a TypeError <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/does-not-evaluate-callbackfn-if-key-present.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/getOrInsertComputed.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/getOrInsertComputed.js: Test262Error: obj['getOrInsertComputed'] descriptor should be a function Expected SameValue(«\\\"undefined\\\"», «\\\"function\\\"») to be true <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/not-a-constructor.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/not-a-constructor.js: Test262Error: isConstructor invoked with a non-function value <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/overwrites-mutation-from-callbackfn.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-not-present-object-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-present-object-key.js-strict:true\": \"test/built-ins/WeakMap/prototype/getOrInsertComputed/returns-value-if-key-is-present-object-key.js: TypeError: Object has no member 'getOrInsertComputed' <at omitted>\",\n  \"test/language/comments/hashbang/function-constructor.js-strict:true\": \"test/language/comments/hashbang/function-constructor.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/comments/hashbang/module.js-strict:false\": \"test/language/comments/hashbang/module.js: file:///TestTC39/test262/test/language/comments/hashbang/module.js: Line 1:28 Unexpected token ILLEGAL (and 2 more errors)\",\n  \"test/language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js-strict:true\": \"test/language/destructuring/binding/syntax/destructuring-array-parameters-function-arguments-length.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/destructuring/binding/syntax/destructuring-object-parameters-function-arguments-length.js-strict:true\": \"test/language/destructuring/binding/syntax/destructuring-object-parameters-function-arguments-length.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/expressions/assignment/fn-name-lhs-cover.js-strict:true\": \"test/language/expressions/assignment/fn-name-lhs-cover.js: Test262Error: obj['name'] descriptor value should be ; obj['name'] value should be  <at omitted>\",\n  \"test/language/expressions/class/class-name-ident-await-escaped-module.js-strict:true\": \"test/language/expressions/class/class-name-ident-await-escaped-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/expressions/class/class-name-ident-await-module.js-strict:true\": \"test/language/expressions/class/class-name-ident-await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/expressions/class/elements/private-getter-is-not-a-own-property.js-strict:true\": \"test/language/expressions/class/elements/private-getter-is-not-a-own-property.js: TypeError: Object has no member '__lookupGetter__' <at omitted>\",\n  \"test/language/expressions/class/elements/private-setter-is-not-a-own-property.js-strict:true\": \"test/language/expressions/class/elements/private-setter-is-not-a-own-property.js: TypeError: Object has no member '__lookupSetter__' <at omitted>\",\n  \"test/language/expressions/greater-than-or-equal/S11.8.4_A4.12_T1.js-strict:true\": \"test/language/expressions/greater-than-or-equal/S11.8.4_A4.12_T1.js: Test262Error: #10: (\\\"\\\\u{10000}\\\" >= \\\"\\\\uFFFF\\\") === false <at omitted>\",\n  \"test/language/expressions/greater-than/S11.8.2_A4.12_T1.js-strict:true\": \"test/language/expressions/greater-than/S11.8.2_A4.12_T1.js: Test262Error: #9: (\\\"\\\\uDC00\\\" > \\\"\\\\uD800\\\") === true <at omitted>\",\n  \"test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js-strict:true\": \"test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js: file:///TestTC39/test262/test/language/expressions/import.meta/import-meta-is-an-ordinary-object.js: Line 28:25 import not supported in script (and 19 more errors)\",\n  \"test/language/expressions/import.meta/same-object-returned.js-strict:true\": \"test/language/expressions/import.meta/same-object-returned.js: file:///TestTC39/test262/test/language/expressions/import.meta/same-object-returned.js: Line 28:9 import not supported in script (and 3 more errors)\",\n  \"test/language/expressions/import.meta/syntax/goal-module-nested-function.js-strict:true\": \"test/language/expressions/import.meta/syntax/goal-module-nested-function.js: file:///TestTC39/test262/test/language/expressions/import.meta/syntax/goal-module-nested-function.js: Line 16:3 import not supported in script (and 4 more errors)\",\n  \"test/language/expressions/import.meta/syntax/goal-module.js-strict:true\": \"test/language/expressions/import.meta/syntax/goal-module.js: file:///TestTC39/test262/test/language/expressions/import.meta/syntax/goal-module.js: Line 15:1 import not supported in script (and 3 more errors)\",\n  \"test/language/expressions/less-than-or-equal/S11.8.3_A4.12_T1.js-strict:true\": \"test/language/expressions/less-than-or-equal/S11.8.3_A4.12_T1.js: Test262Error: #10: (\\\"\\\\u{10000}\\\" <= \\\"\\\\uFFFF\\\") === true <at omitted>\",\n  \"test/language/expressions/less-than/S11.8.1_A4.12_T1.js-strict:true\": \"test/language/expressions/less-than/S11.8.1_A4.12_T1.js: Test262Error: #9: (\\\"\\\\uD800\\\" < \\\"\\\\uDC00\\\") === true <at omitted>\",\n  \"test/language/expressions/optional-chaining/iteration-statement-for-await-of.js-strict:true\": \"test/language/expressions/optional-chaining/iteration-statement-for-await-of.js: test/language/expressions/optional-chaining/iteration-statement-for-await-of.js: Line 32:7 Unexpected token await (and 9 more errors)\",\n  \"test/language/expressions/optional-chaining/member-expression.js-strict:true\": \"test/language/expressions/optional-chaining/member-expression.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/identifiers/part-unicode-15.1.0-class-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0-class-escaped.js: test/language/identifiers/part-unicode-15.1.0-class-escaped.js: Line 20:22 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-15.1.0-class.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0-class.js: test/language/identifiers/part-unicode-15.1.0-class.js: Line 17:11 Unexpected token ILLEGAL (and 4 more errors)\",\n  \"test/language/identifiers/part-unicode-15.1.0-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0-escaped.js: test/language/identifiers/part-unicode-15.1.0-escaped.js: Line 17:5 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-15.1.0.js-strict:true\": \"test/language/identifiers/part-unicode-15.1.0.js: test/language/identifiers/part-unicode-15.1.0.js: Line 15:12 Unexpected token ILLEGAL (and 3 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0-class-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0-class-escaped.js: test/language/identifiers/part-unicode-16.0.0-class-escaped.js: Line 20:10 Unexpected token ILLEGAL (and 3 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0-class.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0-class.js: test/language/identifiers/part-unicode-16.0.0-class.js: Line 17:5 Unexpected token ILLEGAL (and 133 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0-escaped.js: test/language/identifiers/part-unicode-16.0.0-escaped.js: Line 17:5 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-16.0.0.js-strict:true\": \"test/language/identifiers/part-unicode-16.0.0.js: test/language/identifiers/part-unicode-16.0.0.js: Line 15:6 Unexpected token ILLEGAL (and 132 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0-class-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0-class-escaped.js: test/language/identifiers/part-unicode-17.0.0-class-escaped.js: Line 20:10 Unexpected token ILLEGAL (and 48 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0-class.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0-class.js: test/language/identifiers/part-unicode-17.0.0-class.js: Line 17:5 Unexpected token ILLEGAL (and 54 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0-escaped.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0-escaped.js: test/language/identifiers/part-unicode-17.0.0-escaped.js: Line 17:5 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/identifiers/part-unicode-17.0.0.js-strict:true\": \"test/language/identifiers/part-unicode-17.0.0.js: test/language/identifiers/part-unicode-17.0.0.js: Line 15:6 Unexpected token ILLEGAL (and 53 more errors)\",\n  \"test/language/import/import-defer/deferred-namespace-object/exotic-object-behavior.js-strict:true\": \"test/language/import/import-defer/deferred-namespace-object/exotic-object-behavior.js: file:///TestTC39/test262/test/language/import/import-defer/deferred-namespace-object/exotic-object-behavior.js: Line 27:14 Unexpected token *\",\n  \"test/language/import/import-defer/deferred-namespace-object/identity.js-strict:true\": \"test/language/import/import-defer/deferred-namespace-object/identity.js: file:///TestTC39/test262/test/language/import/import-defer/deferred-namespace-object/identity.js: Line 36:14 Unexpected token *\",\n  \"test/language/import/import-defer/deferred-namespace-object/to-string-tag.js-strict:true\": \"test/language/import/import-defer/deferred-namespace-object/to-string-tag.js: file:///TestTC39/test262/test/language/import/import-defer/deferred-namespace-object/to-string-tag.js: Line 29:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/get-other-while-dep-evaluating-async/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-dep-evaluating-async/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-dep-evaluating-async/dep-1.1_FIXTURE.js: Line 2:14 Unexpected token * (and 12 more errors)\",\n  \"test/language/import/import-defer/errors/get-other-while-dep-evaluating/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-dep-evaluating/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-dep-evaluating/dep-1_FIXTURE.js: Line 1:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/errors/get-other-while-evaluating-async/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-evaluating-async/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-evaluating-async/dep-1.1_FIXTURE.js: Line 2:14 Unexpected token * (and 12 more errors)\",\n  \"test/language/import/import-defer/errors/get-other-while-evaluating/main.js-strict:true\": \"test/language/import/import-defer/errors/get-other-while-evaluating/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-other-while-evaluating/dep_FIXTURE.js: Line 1:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/errors/get-self-while-defer-evaluating/main.js-strict:true\": \"test/language/import/import-defer/errors/get-self-while-defer-evaluating/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-self-while-defer-evaluating/main.js: Line 39:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/get-self-while-evaluating-async/main.js-strict:true\": \"test/language/import/import-defer/errors/get-self-while-evaluating-async/main.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-self-while-evaluating-async/main.js: Line 44:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/get-self-while-evaluating.js-strict:true\": \"test/language/import/import-defer/errors/get-self-while-evaluating.js: file:///TestTC39/test262/test/language/import/import-defer/errors/get-self-while-evaluating.js: Line 39:14 Unexpected token *\",\n  \"test/language/import/import-defer/errors/module-throws/third-party-evaluation-after-defer-import.js-strict:true\": \"test/language/import/import-defer/errors/module-throws/third-party-evaluation-after-defer-import.js: file:///TestTC39/test262/test/language/import/import-defer/errors/module-throws/third-party-evaluation-after-defer-import.js: Line 33:14 Unexpected token * (and 2 more errors)\",\n  \"test/language/import/import-defer/errors/module-throws/trigger-evaluation.js-strict:true\": \"test/language/import/import-defer/errors/module-throws/trigger-evaluation.js: file:///TestTC39/test262/test/language/import/import-defer/errors/module-throws/trigger-evaluation.js: Line 33:14 Unexpected token * (and 10 more errors)\",\n  \"test/language/import/import-defer/evaluation-sync/import-defer-does-not-evaluate.js-strict:true\": \"test/language/import/import-defer/evaluation-sync/import-defer-does-not-evaluate.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-sync/import-defer-does-not-evaluate.js: Line 34:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-sync/module-imported-defer-and-eager.js-strict:true\": \"test/language/import/import-defer/evaluation-sync/module-imported-defer-and-eager.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-sync/module-imported-defer-and-eager.js: Line 48:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/flattening-order/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/flattening-order/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/flattening-order/main.js: Line 52:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/import-defer-async-module/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/import-defer-async-module/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/import-defer-async-module/main.js: Line 50:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/import-defer-transitive-async-module/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/import-defer-transitive-async-module/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/import-defer-transitive-async-module/main.js: Line 50:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-top-level-await/sync-dependency-of-deferred-async-module/main.js-strict:true\": \"test/language/import/import-defer/evaluation-top-level-await/sync-dependency-of-deferred-async-module/main.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-top-level-await/sync-dependency-of-deferred-async-module/main.js: Line 50:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-exported-then-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-getPrototypeOf.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-getPrototypeOf.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-getPrototypeOf.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-isExtensible.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-isExtensible.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-isExtensible.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-not-exported-then-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-preventExtensions.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-preventExtensions.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-preventExtensions.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-private-name-access.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-private-name-access.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-private-name-access.js: Line 30:14 Unexpected token * (and 4 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-set-string-exported.js: Line 19:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-not-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-set-string-not-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-set-string-not-exported.js: Line 19:14 Unexpected token * (and 5 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-setPrototypeOf.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-setPrototypeOf.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-setPrototypeOf.js: Line 19:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-exported.js: Line 19:14 Unexpected token * (and 7 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-not-exported.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-not-exported.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-super-property-set-not-exported.js: Line 19:14 Unexpected token * (and 7 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-other-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/ignore-symbol-toStringTag-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-exported-string-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-defineOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-defineOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-defineOwnProperty.js: Line 35:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-delete.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-delete.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-delete.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-getOwnProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-getOwnProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-getOwnProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty-in-prototype.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty-in-prototype.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty-in-prototype.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-hasProperty.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-get.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-get.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-get.js: Line 34:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-property-define.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-property-define.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-not-exported-string-super-property-define.js: Line 46:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKey-names.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKey-names.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKey-names.js: Line 20:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys-symbols.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys-symbols.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys-symbols.js: Line 20:14 Unexpected token *\",\n  \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys.js-strict:true\": \"test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys.js: file:///TestTC39/test262/test/language/import/import-defer/evaluation-triggers/trigger-ownPropertyKeys.js: Line 20:14 Unexpected token *\",\n  \"test/language/import/import-defer/syntax/import-attributes.js-strict:true\": \"test/language/import/import-defer/syntax/import-attributes.js: file:///TestTC39/test262/test/language/import/import-defer/syntax/import-attributes.js: Line 22:14 Unexpected token * (and 1 more errors)\",\n  \"test/language/import/import-defer/syntax/valid-defer-namespace.js-strict:true\": \"test/language/import/import-defer/syntax/valid-defer-namespace.js: file:///TestTC39/test262/test/language/import/import-defer/syntax/valid-defer-namespace.js: Line 22:14 Unexpected token *\",\n  \"test/language/literals/numeric/non-octal-decimal-integer.js-strict:false\": \"test/language/literals/numeric/non-octal-decimal-integer.js: test/language/literals/numeric/non-octal-decimal-integer.js: Line 28:18 Unexpected token ILLEGAL (and 1 more errors)\",\n  \"test/language/literals/regexp/S7.8.5_A1.1_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A1.1_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"\\\\\\\\ud800\\\"», «\\\"\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/S7.8.5_A1.4_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A1.4_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/S7.8.5_A2.1_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A2.1_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"nnnn\\\\\\\\ud800\\\"», «\\\"nnnn\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/S7.8.5_A2.4_T2.js-strict:true\": \"test/language/literals/regexp/S7.8.5_A2.4_T2.js: Test262Error: Code unit: d800 Expected SameValue(«\\\"a\\\\\\\\\\\\\\\\\\\\\\\\ud800\\\"», «\\\"a\\\\\\\\\\\\ud800\\\"») to be true <at omitted>\",\n  \"test/language/literals/regexp/invalid-optional-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-optional-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/invalid-optional-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-optional-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/invalid-range-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-range-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/invalid-range-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/invalid-range-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-case-mapping.js-strict:true\": \"test/language/literals/regexp/u-case-mapping.js: Test262Error: Case mapping is not applied in the absence of the `u` flag Expected SameValue(«true», «false») to be true <at omitted>\",\n  \"test/language/literals/regexp/u-invalid-class-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-class-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-extended-pattern-char.js-strict:true\": \"test/language/literals/regexp/u-invalid-extended-pattern-char.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-identity-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-identity-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-legacy-octal-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-legacy-octal-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-non-empty-class-ranges-no-dash-a.js-strict:true\": \"test/language/literals/regexp/u-invalid-non-empty-class-ranges-no-dash-a.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-oob-decimal-escape.js-strict:true\": \"test/language/literals/regexp/u-invalid-oob-decimal-escape.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-negative-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-negative-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-optional-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-optional-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-negative-lookahead.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-negative-lookahead.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/regexp/u-invalid-range-negative-lookbehind.js-strict:true\": \"test/language/literals/regexp/u-invalid-range-negative-lookbehind.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/string/S7.8.4_A4.3_T1.js-strict:true\": \"test/language/literals/string/S7.8.4_A4.3_T1.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/literals/string/S7.8.4_A4.3_T2.js-strict:true\": \"test/language/literals/string/S7.8.4_A4.3_T2.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from-and-import-star-as-and-export.js-strict:true\": \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from-and-import-star-as-and-export.js: SyntaxError: The requested module \\\"./namespace-unambiguous-if-import-star-as-and-export.js\\\" contains conflicting star exports for name \\\"foo\\\" <at omitted>\",\n  \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-import-star-as-and-export.js-strict:true\": \"test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-import-star-as-and-export.js: SyntaxError: The requested module \\\"./namespace-unambiguous-if-import-star-as-and-export.js\\\" contains conflicting star exports for name \\\"foo\\\" <at omitted>\",\n  \"test/language/module-code/early-dup-top-function.js-strict:true\": \"test/language/module-code/early-dup-top-function.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/early-new-target.js-strict:true\": \"test/language/module-code/early-new-target.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/eval-this.js-strict:true\": \"test/language/module-code/eval-this.js: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true <at omitted>\",\n  \"test/language/module-code/export-default-asyncgenerator-declaration-binding.js-strict:true\": \"test/language/module-code/export-default-asyncgenerator-declaration-binding.js: SyntaxError: Async generators are not supported yet <at omitted>\",\n  \"test/language/module-code/export-expname-from-as-unpaired-surrogate.js-strict:true\": \"test/language/module-code/export-expname-from-as-unpaired-surrogate.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/export-expname-string-binding.js-strict:true\": \"test/language/module-code/export-expname-string-binding.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/export-expname-unpaired-surrogate.js-strict:true\": \"test/language/module-code/export-expname-unpaired-surrogate.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-iee-err-not-found-as.js-strict:true\": \"test/language/module-code/instn-iee-err-not-found-as.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-iee-err-not-found.js-strict:true\": \"test/language/module-code/instn-iee-err-not-found.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-named-err-not-found-as.js-strict:true\": \"test/language/module-code/instn-named-err-not-found-as.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-named-err-not-found-dflt.js-strict:true\": \"test/language/module-code/instn-named-err-not-found-dflt.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-named-err-not-found.js-strict:true\": \"test/language/module-code/instn-named-err-not-found.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/instn-star-err-not-found.js-strict:true\": \"test/language/module-code/instn-star-err-not-found.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/parse-err-hoist-lex-fun.js-strict:true\": \"test/language/module-code/parse-err-hoist-lex-fun.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/parse-err-return.js-strict:true\": \"test/language/module-code/parse-err-return.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/top-level-await/module-graphs-does-not-hang.js-strict:true\": \"test/language/module-code/top-level-await/module-graphs-does-not-hang.js: dynamic modules not enabled in the host program\",\n  \"test/language/module-code/top-level-await/new-await.js-strict:true\": \"test/language/module-code/top-level-await/new-await.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/top-level-await/no-operand.js-strict:true\": \"test/language/module-code/top-level-await/no-operand.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/module-code/top-level-await/pending-async-dep-from-cycle.js-strict:true\": \"test/language/module-code/top-level-await/pending-async-dep-from-cycle.js: Test262Error: Actual [cycle leaf start, cycle leaf end, cycle root start, importer of cycle leaf, cycle root end] and expected [cycle leaf start, cycle leaf end, cycle root start, cycle root end, importer of cycle leaf] should have the same contents. \",\n  \"test/language/reserved-words/await-module.js-strict:true\": \"test/language/reserved-words/await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/class/class-name-ident-await-escaped-module.js-strict:true\": \"test/language/statements/class/class-name-ident-await-escaped-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/class/class-name-ident-await-module.js-strict:true\": \"test/language/statements/class/class-name-ident-await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/class/elements/private-class-field-on-nonextensible-objects.js-strict:true\": \"test/language/statements/class/elements/private-class-field-on-nonextensible-objects.js: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/language/statements/class/elements/private-getter-is-not-a-own-property.js-strict:true\": \"test/language/statements/class/elements/private-getter-is-not-a-own-property.js: TypeError: Object has no member '__lookupGetter__' <at omitted>\",\n  \"test/language/statements/class/elements/private-setter-is-not-a-own-property.js-strict:true\": \"test/language/statements/class/elements/private-setter-is-not-a-own-property.js: TypeError: Object has no member '__lookupSetter__' <at omitted>\",\n  \"test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js-strict:true\": \"test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js: test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js: Line 41:4 Unexpected token * (and 1 more errors)\",\n  \"test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js-strict:true\": \"test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js: test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js: Line 41:4 Unexpected token * (and 1 more errors)\",\n  \"test/language/statements/class/subclass/private-class-field-on-nonextensible-return-override.js-strict:true\": \"test/language/statements/class/subclass/private-class-field-on-nonextensible-return-override.js: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/language/statements/labeled/value-await-module-escaped.js-strict:true\": \"test/language/statements/labeled/value-await-module-escaped.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/labeled/value-await-module.js-strict:true\": \"test/language/statements/labeled/value-await-module.js: error is not an object (Test262: This statement should not be evaluated.)\",\n  \"test/language/statements/with/get-binding-value-call-with-proxy-env.js-strict:false\": \"test/language/statements/with/get-binding-value-call-with-proxy-env.js: Test262Error: Actual [has:Object, get:Symbol(Symbol.unscopables), get:Object] and expected [has:Object, get:Symbol(Symbol.unscopables), has:Object, get:Object] should have the same contents.  <at omitted>\",\n  \"test/language/statements/with/get-binding-value-idref-with-proxy-env.js-strict:false\": \"test/language/statements/with/get-binding-value-idref-with-proxy-env.js: Test262Error: Actual [has:Object, get:Symbol(Symbol.unscopables), get:Object] and expected [has:Object, get:Symbol(Symbol.unscopables), has:Object, get:Object] should have the same contents.  <at omitted>\",\n  \"test/language/statements/with/get-mutable-binding-binding-deleted-in-get-unscopables-strict-mode.js-strict:false\": \"test/language/statements/with/get-mutable-binding-binding-deleted-in-get-unscopables-strict-mode.js: Test262Error: Expected a ReferenceError to be thrown but no exception was thrown at all <at omitted>\",\n  \"test/language/statements/with/set-mutable-binding-binding-deleted-with-typed-array-in-proto-chain.js-strict:false\": \"test/language/statements/with/set-mutable-binding-binding-deleted-with-typed-array-in-proto-chain.js: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true <at omitted>\",\n  \"test/language/statements/with/set-mutable-binding-idref-compound-assign-with-proxy-env.js-strict:false\": \"test/language/statements/with/set-mutable-binding-idref-compound-assign-with-proxy-env.js: Test262Error: Actual [has:p, get:Symbol(Symbol.unscopables), get:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] and expected [has:p, get:Symbol(Symbol.unscopables), has:p, get:p, has:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] should have the same contents.  <at omitted>\",\n  \"test/language/statements/with/set-mutable-binding-idref-with-proxy-env.js-strict:false\": \"test/language/statements/with/set-mutable-binding-idref-with-proxy-env.js: Test262Error: Actual [has:p, get:Symbol(Symbol.unscopables), set:p, getOwnPropertyDescriptor:p, defineProperty:p] and expected [has:p, get:Symbol(Symbol.unscopables), has:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] should have the same contents.  <at omitted>\"\n}\n"
  },
  {
    "path": "internal/js/tc39/checkout.sh",
    "content": "#!/bin/sh -e\nsha=3af36bec45bd4f72d4b57366653578e1e4dafef7 # this is just the commit it was last tested with\nmkdir -p ./TestTC39/test262\ncd ./TestTC39/test262\ngit init\ngit remote add origin https://github.com/tc39/test262.git\ngit fetch origin --depth=1 \"${sha}\"\ngit reset --hard \"${sha}\"\ncd -\n"
  },
  {
    "path": "internal/js/tc39/tc39_norace_test.go",
    "content": "//go:build !race\n\n// Heavily influenced by the fantastic work by @dop251 for https://github.com/dop251/goja\n\npackage tc39\n\nimport \"testing\"\n\nfunc (ctx *tc39TestCtx) runTest(name string, f func(t *testing.T)) {\n\tctx.t.Run(name, func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf(t)\n\t})\n}\n\nfunc (ctx *tc39TestCtx) flush() {\n}\n"
  },
  {
    "path": "internal/js/tc39/tc39_race_test.go",
    "content": "//go:build race\n// +build race\n\n// Heavily influenced by the fantastic work by @dop251 for https://github.com/dop251/goja\n\npackage tc39\n\nimport (\n\t\"testing\"\n)\n\nconst (\n\ttc39MaxTestGroupSize = 1000 // to prevent race detector complaining about too many goroutines\n)\n\nfunc (ctx *tc39TestCtx) runTest(name string, f func(t *testing.T)) {\n\tctx.testQueue = append(ctx.testQueue, tc39Test{name: name, f: f})\n\tif len(ctx.testQueue) >= tc39MaxTestGroupSize {\n\t\tctx.flush()\n\t}\n}\n\nfunc (ctx *tc39TestCtx) flush() {\n\tctx.t.Run(\"tc39\", func(t *testing.T) {\n\t\tfor _, tc := range ctx.testQueue {\n\t\t\ttc := tc\n\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\ttc.f(t)\n\t\t\t})\n\t\t}\n\t})\n\tctx.testQueue = ctx.testQueue[:0]\n}\n"
  },
  {
    "path": "internal/js/tc39/tc39_test.go",
    "content": "// Heavily influenced by the fantastic work by @dop251 for https://github.com/dop251/goja\n//\n//nolint:forbidigo\npackage tc39\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/url\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/grafana/sobek/parser\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"gopkg.in/yaml.v3\"\n\n\t\"go.k6.io/k6/internal/js/compiler\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nconst (\n\ttc39BASE = \"TestTC39/test262\"\n)\n\n//nolint:gochecknoglobals\nvar (\n\terrInvalidFormat = errors.New(\"invalid file format\")\n\n\t// ignorableTestError = newSymbol(stringEmpty)\n\n\tsabStub = sobek.MustCompile(\"sabStub.js\", `\n\t\tObject.defineProperty(this, \"SharedArrayBuffer\", {\n\t\t\tget: function() {\n\t\t\t\tthrow IgnorableTestError;\n\t\t\t}\n\t\t});`,\n\t\tfalse)\n\n\tfeaturesBlockList = []string{\n\t\t\"IsHTMLDDA\",                   // not supported at all\n\t\t\"async-iteration\",             // not supported at all\n\t\t\"String.prototype.replaceAll\", // not supported at all, Stage 4 since 2020\n\t\t\"dynamic-import\",              // not support in k6\n\n\t\t// from Sobek\n\t\t\"Symbol.asyncIterator\",\n\t\t\"resizable-arraybuffer\",\n\t\t\"regexp-named-groups\",\n\t\t\"regexp-duplicate-named-groups\",\n\t\t\"regexp-unicode-property-escapes\",\n\t\t\"regexp-match-indices\",\n\t\t\"regexp-modifiers\",\n\t\t\"RegExp.escape\",\n\t\t\"legacy-regexp\",\n\t\t\"tail-call-optimization\",\n\t\t\"Temporal\",\n\t\t\"import-assertions\",\n\t\t\"logical-assignment-operators\",\n\t\t\"Atomics\",\n\t\t\"Atomics.waitAsync\",\n\t\t\"Atomics.pause\",\n\t\t\"FinalizationRegistry\",\n\t\t\"WeakRef\",\n\t\t\"__getter__\",\n\t\t\"__setter__\",\n\t\t\"ShadowRealm\",\n\t\t\"SharedArrayBuffer\",\n\t\t\"decorators\",\n\n\t\t\"regexp-duplicate-named-groups\",\n\t\t\"regexp-v-flag\",\n\t\t\"iterator-helpers\",\n\t\t\"symbols-as-weakmap-keys\",\n\t\t\"uint8array-base64\",\n\t\t\"String.prototype.toWellFormed\",\n\t\t\"explicit-resource-management\",\n\t\t\"set-methods\",\n\t\t\"promise-try\",\n\t\t\"promise-with-resolvers\",\n\t\t\"array-grouping\",\n\t\t\"Math.sumPrecise\",\n\t\t\"Float16Array\",\n\t\t\"arraybuffer-transfer\",\n\t\t\"Array.fromAsync\",\n\t\t\"String.prototype.isWellFormed\",\n\n\t\t\"source-phase-imports\",\n\t\t\"import-attributes\",\n\t}\n\tskipWords = []string{}\n\tskipList  = map[string]bool{\n\t\t\"test/built-ins/Date/parse/without-utc-offset.js\": true, // some other reason ?!? depending on local time\n\n\t\t\"test/built-ins/Array/prototype/concat/arg-length-exceeding-integer-limit.js\": true, // takes forever and is broken\n\t\t\"test/built-ins/Array/prototype/splice/throws-if-integer-limit-exceeded.js\":   true, // takes forever and is broken\n\t\t\"test/built-ins/Array/prototype/unshift/clamps-to-integer-limit.js\":           true, // takes forever and is broken\n\t\t\"test/built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js\":  true, // takes forever and is broken\n\n\t\t// async generator\n\t\t\"test/built-ins/Object/seal/seal-asyncgeneratorfunction.js\": true,\n\t\t\"test/language/expressions/async-generator/name.js\":         true,\n\n\t\t// wrong tests after change in the specification https://github.com/tc39/test262/issues/3407\n\t\t\"test/language/expressions/prefix-decrement/S11.4.5_A6_T3.js\":        true,\n\t\t\"test/language/expressions/prefix-decrement/S11.4.5_A6_T2.js\":        true,\n\t\t\"test/language/expressions/prefix-decrement/S11.4.5_A6_T1.js\":        true,\n\t\t\"test/language/expressions/postfix-increment/S11.3.1_A6_T3.js\":       true,\n\t\t\"test/language/expressions/postfix-increment/S11.3.1_A6_T2.js\":       true,\n\t\t\"test/language/expressions/postfix-increment/S11.3.1_A6_T1.js\":       true,\n\t\t\"test/language/expressions/postfix-decrement/S11.3.2_A6_T3.js\":       true,\n\t\t\"test/language/expressions/postfix-decrement/S11.3.2_A6_T1.js\":       true,\n\t\t\"test/language/expressions/postfix-decrement/S11.3.2_A6_T2.js\":       true,\n\t\t\"test/language/expressions/prefix-increment/S11.4.4_A6_T3.js\":        true,\n\t\t\"test/language/expressions/prefix-increment/S11.4.4_A6_T2.js\":        true,\n\t\t\"test/language/expressions/prefix-increment/S11.4.4_A6_T1.js\":        true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.9_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.9_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.9_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.8_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.8_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.8_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.7_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.7_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.7_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.6_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.6_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.6_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.5_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.5_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.5_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.4_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.3_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.4_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.4_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.3_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.3_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.2_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.2_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.2_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.1_T4.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.1_T2.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.11_T4.js\": true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.11_T2.js\": true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.1_T1.js\":  true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.11_T1.js\": true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.10_T4.js\": true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.10_T2.js\": true,\n\t\t\"test/language/expressions/compound-assignment/S11.13.2_A7.10_T1.js\": true,\n\t\t\"test/language/expressions/assignment/S11.13.1_A7_T3.js\":             true,\n\n\t\t// timezone (apparently it depends on local timezone settings)\n\t\t\"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-8.js\":  true,\n\t\t\"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-9.js\":  true,\n\t\t\"test/built-ins/Date/prototype/toISOString/15.9.5.43-0-10.js\": true,\n\t}\n\tpathBasedBlock = []string{ // This completely skips any path matching it without any kind of message\n\t\t\"test/annexB/built-ins/Date\",\n\t\t\"test/annexB/built-ins/RegExp/prototype/Symbol.split\",\n\t\t\"test/annexB/built-ins/String/prototype/anchor\",\n\t\t\"test/annexB/built-ins/String/prototype/big\",\n\t\t\"test/annexB/built-ins/String/prototype/blink\",\n\t\t\"test/annexB/built-ins/String/prototype/bold\",\n\t\t\"test/annexB/built-ins/String/prototype/fixed\",\n\t\t\"test/annexB/built-ins/String/prototype/fontcolor\",\n\t\t\"test/annexB/built-ins/String/prototype/fontsize\",\n\t\t\"test/annexB/built-ins/String/prototype/italics\",\n\t\t\"test/annexB/built-ins/String/prototype/link\",\n\t\t\"test/annexB/built-ins/String/prototype/small\",\n\t\t\"test/annexB/built-ins/String/prototype/strike\",\n\t\t\"test/annexB/built-ins/String/prototype/sub\",\n\t\t\"test/annexB/built-ins/String/prototype/sup\",\n\n\t\t\"test/annexB/built-ins/RegExp/legacy-accessors/\",\n\t\t\"test/language/literals/string/legacy-\", // legecy string escapes\n\n\t\t\"test/built-ins/Atomics\",\n\t\t\"test/built-ins/BigInt\",\n\t\t\"test/built-ins/SharedArrayBuffer\",\n\n\t\t// Async generators are not currently supported\n\t\t\"test/built-ins/AsyncFromSyncIteratorPrototype\",\n\t\t\"test/built-ins/AsyncGeneratorFunction\",\n\t\t\"test/built-ins/AsyncGeneratorPrototype\",\n\t\t\"test/built-ins/AsyncIteratorPrototype\",\n\t\t\"test/language/eval-code/direct/async-gen\",\n\t\t\"test/language/expressions/async-generator\",\n\t\t\"test/language/expressions/class/elements/after-same-line-gen-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/after-same-line-method-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/after-same-line-static-async-method-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/after-same-line-static-gen-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/after-same-line-static-method-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/multiple-definitions-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/multiple-stacked-definitions-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/new-no-sc-line-gen-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/new-no-sc-line-method-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/new-sc-line-gen-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/new-sc-line-method-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/private-async-generator\",\n\t\t\"test/language/expressions/class/elements/private-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/regular-definitions-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/same-line-async-method-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/same-line-gen-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/same-line-method-rs-static-async-generator\",\n\t\t\"test/language/expressions/class/elements/wrapped-in-sc-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/after-same-line-gen-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/after-same-line-method-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/after-same-line-static-async-method-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/after-same-line-static-gen-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/after-same-line-static-method-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/multiple-definitions-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/multiple-stacked-definitions-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/new-no-sc-line-method-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/new-sc-line-gen-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/new-sc-line-method-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/private-async-generator\",\n\t\t\"test/language/statements/class/elements/private-static-async-generator\",\n\t\t\"test/language/statements/class/elements/regular-definitions-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/same-line-async-method-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/same-line-gen-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/same-line-method-rs-static-async-generator\",\n\t\t\"test/language/statements/class/elements/wrapped-in-sc-rs-static-async-generator\",\n\t\t\"test/language/statements/switch/scope-lex-async-generator.js\",\n\n\t\t\"test/built-ins/FinalizationRegistry\", // still in proposal\n\n\t\t\"test/built-ins/RegExp/property-escapes\",  // none of those work\n\t\t\"test/language/identifiers/start-unicode\", // tests whether some unicode can be used in identifiers, half don't work, take forever\n\n\t\t\"test/built-ins/Object/prototype/__lookup\", // AnnexB lookupGetter lookupSetter\n\t\t\"test/built-ins/Object/prototype/__define\", // AnnexB defineGetter defineSetter\n\n\t\t\"test/language/expressions/dynamic-import\", // not supported\n\n\t\t// Go 1.16 only supports unicode 13; While go 1.21 has support for this - we disable them\n\t\t// so that they aren't flaky between versions.\n\t\t\"test/language/identifiers/start-unicode-14.\",\n\t\t\"test/language/identifiers/part-unicode-14.\",\n\t}\n\n\tupdate = flag.Bool(\"update\", false, \"update breaking_test_errors-*.json files\") //nolint:gochecknoglobals\n)\n\n//nolint:unused\ntype tc39Test struct {\n\tname string\n\tf    func(t *testing.T)\n}\n\ntype tc39BenchmarkItem struct {\n\tname     string\n\tduration time.Duration\n}\n\ntype tc39BenchmarkData []tc39BenchmarkItem\n\ntype tc39TestCtx struct {\n\tbase           string\n\tt              *testing.T\n\tprgCache       map[string]*sobek.Program\n\tprgCacheLock   sync.Mutex\n\tenableBench    bool\n\tbenchmark      tc39BenchmarkData\n\tbenchLock      sync.Mutex\n\ttestQueue      []tc39Test //nolint:unused\n\texpectedErrors map[string]string\n\n\terrorsLock sync.Mutex\n\terrors     map[string]string\n\n\tstripTypes bool\n}\n\ntype TC39MetaNegative struct {\n\tPhase, Type string\n}\n\ntype tc39Meta struct {\n\tNegative TC39MetaNegative\n\tIncludes []string\n\tFlags    []string\n\tFeatures []string\n\tEs5id    string\n\tEs6id    string\n\tEsid     string\n}\n\nfunc (m *tc39Meta) hasFlag(flag string) bool {\n\treturn slices.Contains(m.Flags, flag)\n}\n\nfunc parseTC39File(name string) (*tc39Meta, string, error) {\n\tf, err := os.Open(name)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tdefer f.Close() //nolint:errcheck\n\n\tb, err := io.ReadAll(f)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tmetaStart := bytes.Index(b, []byte(\"/*---\"))\n\tif metaStart == -1 {\n\t\treturn nil, \"\", errInvalidFormat\n\t}\n\n\tmetaStart += 5\n\tmetaEnd := bytes.Index(b, []byte(\"---*/\"))\n\tif metaEnd == -1 || metaEnd <= metaStart {\n\t\treturn nil, \"\", errInvalidFormat\n\t}\n\n\tvar meta tc39Meta\n\terr = yaml.Unmarshal(b[metaStart:metaEnd], &meta)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tif meta.Negative.Type != \"\" && meta.Negative.Phase == \"\" {\n\t\treturn nil, \"\", errors.New(\"negative type is set, but phase isn't\")\n\t}\n\n\treturn &meta, string(b), nil\n}\n\nfunc (*tc39TestCtx) detachArrayBuffer(call sobek.FunctionCall) sobek.Value {\n\tif obj, ok := call.Argument(0).(*sobek.Object); ok {\n\t\tvar buf sobek.ArrayBuffer\n\t\tif sobek.New().ExportTo(obj, &buf) == nil {\n\t\t\t// if buf, ok := obj.Export().(sobek.ArrayBuffer); ok {\n\t\t\tbuf.Detach()\n\t\t\treturn sobek.Undefined()\n\t\t}\n\t}\n\tpanic(sobek.New().NewTypeError(\"detachArrayBuffer() is called with incompatible argument\"))\n}\n\nfunc (ctx *tc39TestCtx) fail(t testing.TB, name string, strict bool, errStr string) {\n\tnameKey := fmt.Sprintf(\"%s-strict:%v\", name, strict)\n\texpected, ok := ctx.expectedErrors[nameKey]\n\tif index := strings.LastIndex(errStr, \" at \"); index != -1 {\n\t\terrStr = errStr[:index] + \" <at omitted>\"\n\t}\n\tif ok {\n\t\tif !assert.Equal(t, expected, errStr) {\n\t\t\tctx.errorsLock.Lock()\n\t\t\tctx.errors[nameKey] = errStr\n\t\t\tctx.errorsLock.Unlock()\n\t\t}\n\t} else {\n\t\tassert.Empty(t, errStr)\n\t\tctx.errorsLock.Lock()\n\t\tctx.errors[nameKey] = errStr\n\t\tctx.errorsLock.Unlock()\n\t}\n}\n\nfunc (ctx *tc39TestCtx) runTC39Test(t testing.TB, name, src string, meta *tc39Meta, strict bool) {\n\tif skipList[name] {\n\t\tt.Skip(\"Excluded\")\n\t}\n\tfailf := func(str string, args ...any) {\n\t\tstr = fmt.Sprintf(str, args...)\n\t\tctx.fail(t, name, strict, str)\n\t}\n\tdefer func() {\n\t\tif x := recover(); x != nil {\n\t\t\tfailf(\"panic while running %s: %v\", name, x)\n\t\t}\n\t}()\n\tvm := sobek.New()\n\t_262 := vm.NewObject()\n\tignorableTestError := vm.NewGoError(fmt.Errorf(\"\"))\n\t_ = vm.Set(\"IgnorableTestError\", ignorableTestError)\n\t_ = _262.Set(\"detachArrayBuffer\", ctx.detachArrayBuffer)\n\t_ = _262.Set(\"createRealm\", func(sobek.FunctionCall) sobek.Value {\n\t\tpanic(ignorableTestError)\n\t})\n\t_ = _262.Set(\"evalScript\", func(call sobek.FunctionCall) sobek.Value {\n\t\tscript := call.Argument(0).String()\n\t\tresult, err := vm.RunString(script)\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\treturn result\n\t})\n\n\t_ = vm.Set(\"$262\", _262)\n\t_ = vm.Set(\"print\", t.Log)\n\t_, err := vm.RunProgram(sabStub)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif strict {\n\t\tsrc = \"'use strict';\\n\" + src\n\t}\n\n\tvar out []string\n\tasync := meta.hasFlag(\"async\")\n\tif async {\n\t\terr = ctx.runFile(ctx.base, path.Join(\"harness\", \"doneprintHandle.js\"), vm)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\t\t_ = vm.Set(\"print\", func(msg string) {\n\t\t\tout = append(out, msg)\n\t\t})\n\t} else {\n\t\t_ = vm.Set(\"print\", t.Log)\n\t}\n\tvar early bool\n\tif meta.hasFlag(\"module\") {\n\t\tearly, err = ctx.runTC39Module(name, src, meta.Includes, vm)\n\t} else {\n\t\tearly, err = ctx.runTC39Script(name, src, meta.Includes, vm, meta.Negative.Type != \"\")\n\t}\n\n\tif err == nil {\n\t\tif meta.Negative.Type != \"\" {\n\t\t\t// vm.vm.prg.dumpCode(t.Logf)\n\t\t\tfailf(\"%s: Expected error: %v\", name, err)\n\t\t\treturn\n\t\t}\n\t\tnameKey := fmt.Sprintf(\"%s-strict:%v\", name, strict)\n\t\texpected, ok := ctx.expectedErrors[nameKey]\n\t\tassert.False(t, ok, \"%s passes but and error %q was expected\", nameKey, expected)\n\t\treturn\n\t}\n\n\tif meta.Negative.Type == \"\" {\n\t\tif err, ok := err.(*sobek.Exception); ok { //nolint:errorlint\n\t\t\tif err.Value() == ignorableTestError {\n\t\t\t\tt.Skip(\"Test threw IgnorableTestError\")\n\t\t\t}\n\t\t}\n\t\tfailf(\"%s: %v\", name, err)\n\t\treturn\n\t}\n\tif meta.Negative.Phase == \"early\" && !early || meta.Negative.Phase == \"runtime\" && early {\n\t\tfailf(\"%s: error %v happened at the wrong phase (expected %s)\", name, err, meta.Negative.Phase)\n\t\treturn\n\t}\n\terrType := getErrType(name, err, failf)\n\n\tif errType != \"\" && errType != meta.Negative.Type {\n\t\t// vm.vm.prg.dumpCode(t.Logf)\n\t\tfailf(\"%s: unexpected error type (%s), expected (%s)\", name, errType, meta.Negative.Type)\n\t\treturn\n\t}\n\n\t/*\n\t\tif vm.vm.sp != 0 {\n\t\t\tt.Fatalf(\"sp: %d\", vm.vm.sp)\n\t\t}\n\n\t\tif l := len(vm.vm.iterStack); l > 0 {\n\t\t\tt.Fatalf(\"iter stack is not empty: %d\", l)\n\t\t}\n\t*/\n\tif async {\n\t\tcomplete := false\n\t\tfor _, line := range out {\n\t\t\tif strings.HasPrefix(line, \"Test262:AsyncTestFailure:\") {\n\t\t\t\tt.Fatal(line)\n\t\t\t} else if line == \"Test262:AsyncTestComplete\" {\n\t\t\t\tcomplete = true\n\t\t\t}\n\t\t}\n\t\tif !complete {\n\t\t\tfor _, line := range out {\n\t\t\t\tt.Log(line)\n\t\t\t}\n\t\t\tt.Fatal(\"Test262:AsyncTestComplete was not printed\")\n\t\t}\n\t}\n}\n\nfunc getErrType(name string, err error, failf func(str string, args ...any)) string {\n\tswitch err := err.(type) { //nolint:errorlint\n\tcase *sobek.Exception:\n\t\tif o, ok := err.Value().(*sobek.Object); ok {\n\t\t\tif c := o.Get(\"constructor\"); c != nil {\n\t\t\t\tif c, ok := c.(*sobek.Object); ok {\n\t\t\t\t\treturn c.Get(\"name\").String()\n\t\t\t\t}\n\t\t\t\tfailf(\"%s: error constructor is not an object (%v)\", name, o)\n\t\t\t\treturn \"\"\n\t\t\t}\n\t\t\tfailf(\"%s: error does not have a constructor (%v)\", name, o)\n\t\t\treturn \"\"\n\t\t}\n\t\tfailf(\"%s: error is not an object (%v)\", name, err.Value())\n\t\treturn \"\"\n\tcase *sobek.CompilerSyntaxError, *parser.Error, parser.ErrorList:\n\t\treturn \"SyntaxError\"\n\tcase *sobek.CompilerReferenceError:\n\t\treturn \"ReferenceError\"\n\tdefault:\n\t\tfailf(\"%s: error is not a JS error: %v\", name, err)\n\t\treturn \"\"\n\t}\n}\n\nfunc shouldBeSkipped(t testing.TB, meta *tc39Meta) {\n\tfor _, feature := range meta.Features {\n\t\tfor _, bl := range featuresBlockList {\n\t\t\tif feature == bl {\n\t\t\t\tt.Skipf(\"Blocklisted feature %s\", feature)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (ctx *tc39TestCtx) runTC39File(name string, t testing.TB) {\n\tp := path.Join(ctx.base, name)\n\tmeta, src, err := parseTC39File(p)\n\tif err != nil {\n\t\t// t.Fatalf(\"Could not parse %s: %v\", name, err)\n\t\tt.Errorf(\"Could not parse %s: %v\", name, err)\n\t\treturn\n\t}\n\n\tshouldBeSkipped(t, meta)\n\n\tvar startTime time.Time\n\tif ctx.enableBench {\n\t\tstartTime = time.Now()\n\t}\n\n\thasRaw := meta.hasFlag(\"raw\")\n\n\t/*\n\t\tif hasRaw || !meta.hasFlag(\"onlyStrict\") {\n\t\t\t// log.Printf(\"Running normal test: %s\", name)\n\t\t\t// t.Logf(\"Running normal test: %s\", name)\n\t\t\tctx.runTC39Test(t, name, src, meta, false)\n\t\t}\n\t*/\n\n\tif !hasRaw && !meta.hasFlag(\"noStrict\") {\n\t\t// log.Printf(\"Running strict test: %s\", name)\n\t\t// t.Logf(\"Running strict test: %s\", name)\n\t\tctx.runTC39Test(t, name, src, meta, true)\n\t} else { // Run test in non strict mode only if we won't run them in strict\n\t\t// NOTE: in practice k6 does not run non strict code at all so this tests make no sense\n\t\t// TODO uncomment the if above and delete this else so we run both parts when the tests\n\t\t// don't take forever\n\t\tctx.runTC39Test(t, name, src, meta, false)\n\t}\n\n\tif ctx.enableBench {\n\t\tctx.benchLock.Lock()\n\t\tctx.benchmark = append(ctx.benchmark, tc39BenchmarkItem{\n\t\t\tname:     name,\n\t\t\tduration: time.Since(startTime),\n\t\t})\n\t\tctx.benchLock.Unlock()\n\t}\n}\n\nfunc breakingTestErrorsFilename(stripTypes bool) string {\n\treturn fmt.Sprintf(\"./breaking_test_errors-stripTypes=%t.json\", stripTypes)\n}\n\nfunc (ctx *tc39TestCtx) init() {\n\tctx.prgCache = make(map[string]*sobek.Program)\n\tctx.errors = make(map[string]string)\n\n\tif !*update {\n\t\tb, err := os.ReadFile(breakingTestErrorsFilename(ctx.stripTypes))\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t\tb = bytes.TrimSpace(b)\n\t\tif len(b) > 0 {\n\t\t\tctx.expectedErrors = make(map[string]string, 1000)\n\t\t\terr = json.Unmarshal(b, &ctx.expectedErrors)\n\t\t\tif err != nil {\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (ctx *tc39TestCtx) compile(base, name string) (*sobek.Program, error) {\n\tctx.prgCacheLock.Lock()\n\tdefer ctx.prgCacheLock.Unlock()\n\n\tprg := ctx.prgCache[name]\n\tif prg == nil {\n\t\tfname := path.Join(base, name)\n\t\tf, err := os.Open(fname)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer f.Close() //nolint:errcheck\n\n\t\tb, err := io.ReadAll(f)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tprg, err = ctx.compileOnly(string(b), name, ctx.stripTypes)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tctx.prgCache[name] = prg\n\t}\n\n\treturn prg, nil\n}\n\nfunc (ctx *tc39TestCtx) runFile(base, name string, vm *sobek.Runtime) error {\n\tprg, err := ctx.compile(base, name)\n\tif err != nil {\n\t\treturn err\n\t}\n\t_, err = vm.RunProgram(prg)\n\treturn err\n}\n\nfunc (ctx *tc39TestCtx) compileOnly(src, name string, stripTypes bool) (*sobek.Program, error) {\n\tcomp := ctx.compiler()\n\tif stripTypes {\n\t\tcode, _, err := compiler.StripTypes(src, name)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsrc = code\n\t}\n\tastProgram, _, err := comp.Parse(src, name, false, false)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn sobek.CompileAST(astProgram, false)\n}\n\nfunc (ctx *tc39TestCtx) compiler() *compiler.Compiler {\n\treturn compiler.New(testutils.NewLogger(ctx.t))\n}\n\nfunc (ctx *tc39TestCtx) runTC39Script(name, src string, includes []string, vm *sobek.Runtime, expectsError bool) (early bool, err error) {\n\tearly = true\n\terr = ctx.runFile(ctx.base, path.Join(\"harness\", \"assert.js\"), vm)\n\tif err != nil {\n\t\treturn early, err\n\t}\n\n\terr = ctx.runFile(ctx.base, path.Join(\"harness\", \"sta.js\"), vm)\n\tif err != nil {\n\t\treturn early, err\n\t}\n\n\tfor _, include := range includes {\n\t\terr = ctx.runFile(ctx.base, path.Join(\"harness\", include), vm)\n\t\tif err != nil {\n\t\t\treturn early, err\n\t\t}\n\t}\n\n\tp, err := ctx.compileOnly(src, name, false)\n\tif err != nil && !expectsError {\n\t\tp, err = ctx.compileOnly(src, name, false)\n\t}\n\tif err != nil {\n\t\treturn early, err\n\t}\n\n\tearly = false\n\t_, err = vm.RunProgram(p)\n\n\treturn early, err\n}\n\nfunc (ctx *tc39TestCtx) runTC39Module(name, src string, includes []string, vm *sobek.Runtime) (early bool, err error) {\n\tmoduleRuntime := modulestest.NewRuntime(ctx.t)\n\tmoduleRuntime.VU.RuntimeField = vm\n\tearly = true\n\terr = ctx.runFile(ctx.base, path.Join(\"harness\", \"assert.js\"), vm)\n\tif err != nil {\n\t\treturn early, err\n\t}\n\n\terr = ctx.runFile(ctx.base, path.Join(\"harness\", \"sta.js\"), vm)\n\tif err != nil {\n\t\treturn early, err\n\t}\n\n\tfor _, include := range includes {\n\t\terr = ctx.runFile(ctx.base, path.Join(\"harness\", include), vm)\n\t\tif err != nil {\n\t\t\treturn early, err\n\t\t}\n\t}\n\n\tu := &url.URL{Scheme: \"file\", Path: \"/\" + path.Join(ctx.base, name)}\n\tbase := u.JoinPath(\"..\")\n\tmr := modules.NewModuleResolver(nil,\n\t\tfunc(specifier *url.URL, _ string) ([]byte, error) {\n\t\t\tb, err := fs.ReadFile(os.DirFS(\".\"), specifier.Path[1:])\n\n\t\t\tif ctx.stripTypes {\n\t\t\t\tcode, _, err := compiler.StripTypes(string(b), name)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tb = []byte(code)\n\t\t\t}\n\t\t\treturn b, err\n\t\t},\n\t\tctx.compiler(), base, usage.New(), testutils.NewLogger(ctx.t))\n\n\tms := modules.NewModuleSystem(mr, moduleRuntime.VU)\n\tmoduleRuntime.VU.InitEnvField.CWD = base\n\n\tearly = false\n\tresult, err := ms.RunSourceData(&loader.SourceData{\n\t\tData: []byte(src),\n\t\tURL:  u,\n\t})\n\tif err == nil {\n\t\tvar finished bool\n\t\t_, finished, err = result.Result()\n\t\tif !finished {\n\t\t\tpanic(\"tc39 has no tests where this should happen\")\n\t\t}\n\t}\n\n\treturn early, err\n}\n\nfunc (ctx *tc39TestCtx) runTC39Tests(name string) {\n\tfiles, err := os.ReadDir(path.Join(ctx.base, name))\n\tif err != nil {\n\t\tctx.t.Fatal(err)\n\t}\n\nouter:\n\tfor _, file := range files {\n\t\tif file.Name()[0] == '.' {\n\t\t\tcontinue\n\t\t}\n\t\tnewName := path.Join(name, file.Name())\n\t\tfor _, skipWord := range skipWords {\n\t\t\tif strings.Contains(newName, skipWord) {\n\t\t\t\tctx.t.Run(newName, func(t *testing.T) {\n\t\t\t\t\tt.Skipf(\"Skip %s because %s is not supported\", newName, skipWord)\n\t\t\t\t})\n\t\t\t\tcontinue outer\n\t\t\t}\n\t\t}\n\t\tfor _, path := range pathBasedBlock { // TODO: use trie / binary search?\n\t\t\tif strings.HasPrefix(newName, path) {\n\t\t\t\tctx.t.Run(newName, func(t *testing.T) {\n\t\t\t\t\tt.Skipf(\"Skip %s because of path based block\", newName)\n\t\t\t\t})\n\t\t\t\tcontinue outer\n\t\t\t}\n\t\t}\n\t\tif file.IsDir() {\n\t\t\tctx.runTC39Tests(newName)\n\t\t} else if strings.HasSuffix(file.Name(), \".js\") && !strings.HasSuffix(file.Name(), \"_FIXTURE.js\") {\n\t\t\tctx.runTest(newName, func(t *testing.T) {\n\t\t\t\tctx.runTC39File(newName, t)\n\t\t\t})\n\t\t}\n\t}\n}\n\n//nolint:paralleltest // this is on purpose so the test can wait for the subtest to finish\nfunc TestTC39(t *testing.T) {\n\tif testing.Short() {\n\t\tt.Skip()\n\t}\n\n\trunTestTC39(t, false)\n\trunTestTC39(t, true)\n}\n\nfunc runTestTC39(t *testing.T, stripTypes bool) {\n\tt.Helper()\n\n\tif _, err := os.Stat(tc39BASE); err != nil {\n\t\tt.Skipf(\"If you want to run tc39 tests, you need to run the 'checkout.sh` script in the directory to get  https://github.com/tc39/test262 at the correct last tested commit (%v)\", err)\n\t}\n\n\tctx := &tc39TestCtx{\n\t\tbase:       tc39BASE,\n\t\tstripTypes: stripTypes,\n\t}\n\tctx.init()\n\t// ctx.enableBench = true\n\n\tt.Run(\"test262\", func(t *testing.T) {\n\t\tctx.t = t\n\t\tctx.runTC39Tests(\"test/language\")\n\t\tctx.runTC39Tests(\"test/built-ins\")\n\t\tctx.runTC39Tests(\"test/harness\")\n\t\tctx.runTC39Tests(\"test/annexB/built-ins\")\n\n\t\tctx.flush()\n\t})\n\n\tif ctx.enableBench {\n\t\tsort.Slice(ctx.benchmark, func(i, j int) bool {\n\t\t\treturn ctx.benchmark[i].duration > ctx.benchmark[j].duration\n\t\t})\n\t\tbench := ctx.benchmark\n\t\tif len(bench) > 50 {\n\t\t\tbench = bench[:50]\n\t\t}\n\t\tfor _, item := range bench {\n\t\t\tfmt.Printf(\"%s\\t%d\\n\", item.name, item.duration/time.Millisecond)\n\t\t}\n\t}\n\tif len(ctx.errors) > 0 && *update {\n\t\tfilename := breakingTestErrorsFilename(ctx.stripTypes)\n\t\tfile, err := os.Create(filepath.Clean(filename))\n\t\tif err != nil {\n\t\t\tt.Logf(\"Error while creating %s: %s\", filename, err)\n\t\t}\n\n\t\tenc := json.NewEncoder(file)\n\t\tenc.SetIndent(\"\", \"  \")\n\t\tenc.SetEscapeHTML(false)\n\t\terr = enc.Encode(ctx.errors)\n\t\tif err != nil {\n\t\t\tt.Logf(\"Error while json encoding errors: %s\", err)\n\t\t}\n\t\terr = file.Close()\n\t\tif err != nil {\n\t\t\tt.Logf(\"Error while closing %s: %s\", filename, err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/js/tc55/timers/timers.go",
    "content": "// Package timers is implementing setInterval setTimeout and co.\npackage timers\n\nimport (\n\t\"fmt\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/mstoykov/k6-taskqueue-lib/taskqueue\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\ntype timers struct {\n\tvu modules.VU\n\n\ttimerIDCounter uint64\n\n\ttimers map[uint64]time.Time\n\t// Maybe in the future if this moves to core it will be expanded to have multiple queues\n\tqueue *timerQueue\n\n\t// this used predominantly to get around very unlikely race conditions as we are adding stuff to the event loop\n\t// from outside of it on multitple timers. And it is easier to just use this then redo half the work it does\n\t// to make that safe\n\ttaskQueue *taskqueue.TaskQueue\n\t// used to synchronize around context closing\n\ttaskQueueCh chan struct{}\n}\n\nconst (\n\tsetTimeoutName  = \"setTimeout\"\n\tsetIntervalName = \"setInterval\"\n)\n\n// SetupGlobally setups implementatins of setTimeout, clearTimeout, setInterval and clearInterval\n// to be accessible globally by setting them on globalThis.\nfunc SetupGlobally(vu modules.VU) error {\n\treturn newTimers(vu).setupGlobally()\n}\n\nfunc newTimers(vu modules.VU) *timers {\n\treturn &timers{\n\t\tvu:     vu,\n\t\ttimers: make(map[uint64]time.Time),\n\t\tqueue:  new(timerQueue),\n\t}\n}\n\nfunc (e *timers) setupGlobally() error {\n\tmapping := map[string]any{\n\t\t\"setTimeout\":    e.setTimeout,\n\t\t\"clearTimeout\":  e.clearTimeout,\n\t\t\"setInterval\":   e.setInterval,\n\t\t\"clearInterval\": e.clearInterval,\n\t}\n\trt := e.vu.Runtime()\n\tfor k, v := range mapping {\n\t\terr := rt.Set(k, v)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error setting up %q globally: %w\", k, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (e *timers) nextID() uint64 {\n\te.timerIDCounter++\n\treturn e.timerIDCounter\n}\n\nfunc (e *timers) call(callback sobek.Callable, args []sobek.Value) error {\n\t// TODO: investigate, not sure GlobalObject() is always the correct value for `this`?\n\t_, err := callback(e.vu.Runtime().GlobalObject(), args...)\n\treturn err\n}\n\nfunc (e *timers) setTimeout(callback sobek.Callable, delay float64, args ...sobek.Value) uint64 {\n\tid := e.nextID()\n\te.timerInitialization(callback, delay, args, false, id)\n\treturn id\n}\n\nfunc (e *timers) clearTimeout(id uint64) {\n\t_, exists := e.timers[id]\n\tif !exists {\n\t\treturn\n\t}\n\tdelete(e.timers, id)\n\n\tfirst := e.queue.first()\n\tif first != nil && first.id == id && e.queue.length() > 1 {\n\t\t// if this is the first in queue we need to reset the first timer\n\t\t// but only if there are more tasks in the queue\n\t\t// and we need to do it after we remove this one, so we are deferring it\n\t\tdefer e.setupTaskTimeout()\n\t}\n\te.queue.remove(id)\n\te.freeEventLoopIfPossible()\n}\n\nfunc (e *timers) freeEventLoopIfPossible() {\n\tif e.queue.length() == 0 && e.taskQueue != nil {\n\t\te.closeTaskQueue()\n\t}\n}\n\nfunc (e *timers) setInterval(callback sobek.Callable, delay float64, args ...sobek.Value) uint64 {\n\tid := e.nextID()\n\te.timerInitialization(callback, delay, args, true, id)\n\treturn id\n}\n\nfunc (e *timers) clearInterval(id uint64) {\n\te.clearTimeout(id)\n}\n\n// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timer-initialisation-steps\n// NOTE: previousId from the specification is always send and it is basically id\nfunc (e *timers) timerInitialization(\n\tcallback sobek.Callable, timeout float64, args []sobek.Value, repeat bool, id uint64,\n) {\n\t// skip all the nesting stuff as we do not care about them\n\tif timeout < 0 {\n\t\ttimeout = 0\n\t}\n\n\tname := setTimeoutName\n\tif repeat {\n\t\tname = setIntervalName\n\t}\n\n\tif callback == nil {\n\t\tcommon.Throw(e.vu.Runtime(), fmt.Errorf(\"%s's callback isn't a callable function\", name))\n\t}\n\n\ttask := func() error {\n\t\t// Specification 8.1: If id does not exist in global's map of active timers, then abort these steps.\n\t\tif _, exist := e.timers[id]; !exist {\n\t\t\treturn nil\n\t\t}\n\n\t\terr := e.call(callback, args)\n\n\t\tif _, exist := e.timers[id]; !exist { // 8.4\n\t\t\treturn err\n\t\t}\n\n\t\tif repeat {\n\t\t\te.timerInitialization(callback, timeout, args, repeat, id)\n\t\t} else {\n\t\t\tdelete(e.timers, id)\n\t\t}\n\n\t\treturn err\n\t}\n\n\te.runAfterTimeout(&timer{\n\t\tid:          id,\n\t\ttask:        task,\n\t\tnextTrigger: time.Now().Add(time.Duration(timeout * float64(time.Millisecond))),\n\t\tname:        name,\n\t})\n}\n\n// https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#run-steps-after-a-timeout\n// Notes: this just takes timers as makes the implementation way easier and we do not currently need\n// most of the functionality provided\nfunc (e *timers) runAfterTimeout(t *timer) {\n\te.timers[t.id] = t.nextTrigger\n\n\t// as we have only one orderingId we have one queue\n\tindex := e.queue.add(t)\n\n\tif index != 0 {\n\t\treturn // not a timer at the very beginning\n\t}\n\n\te.setupTaskTimeout()\n}\n\nfunc (e *timers) runFirstTask() error {\n\tt := e.queue.pop()\n\tif t == nil {\n\t\treturn nil // everything was cleared\n\t}\n\n\terr := t.task()\n\n\tif e.queue.length() > 0 {\n\t\te.setupTaskTimeout()\n\t} else {\n\t\te.freeEventLoopIfPossible()\n\t}\n\n\treturn err\n}\n\nfunc (e *timers) setupTaskTimeout() {\n\te.queue.stopTimer()\n\tdelay := -time.Since(e.timers[e.queue.first().id])\n\tif e.taskQueue == nil {\n\t\te.taskQueue = taskqueue.New(e.vu.RegisterCallback)\n\t\te.setupTaskQueueCloserOnIterationEnd()\n\t}\n\tq := e.taskQueue\n\te.queue.head = time.AfterFunc(delay, func() {\n\t\tq.Queue(e.runFirstTask)\n\t})\n}\n\nfunc (e *timers) closeTaskQueue() {\n\t// this only runs on the event loop\n\tif e.taskQueueCh == nil {\n\t\treturn\n\t}\n\tch := e.taskQueueCh\n\t// so that we do not execute it twice\n\te.taskQueueCh = nil\n\n\tselect {\n\tcase ch <- struct{}{}:\n\t\t// wait for this to happen so we don't need to hit the event loop again\n\t\t// instead this just closes the queue\n\t\t<-ch\n\tcase <-e.vu.Context().Done(): // still shortcircuit if the context is done as we might block otherwise\n\t}\n}\n\n// logger is helper to get a logger either from the state or the initenv\nfunc (e *timers) logger() logrus.FieldLogger {\n\tif state := e.vu.State(); state != nil {\n\t\treturn state.Logger\n\t}\n\treturn e.vu.InitEnv().Logger\n}\n\nfunc (e *timers) setupTaskQueueCloserOnIterationEnd() {\n\tctx := e.vu.Context()\n\tq := e.taskQueue\n\tch := make(chan struct{})\n\te.taskQueueCh = ch\n\tgo func() {\n\t\tselect { // wait for one of the two\n\t\tcase <-ctx.Done():\n\t\t\t// lets report timers won't be executed and clean the fields for the next execution\n\t\t\t// we need to do this on the event loop as we don't want to have a race\n\t\t\tq.Queue(func() error {\n\t\t\t\tlogger := e.logger()\n\t\t\t\tfor _, timer := range e.queue.queue {\n\t\t\t\t\tlogger.Warnf(\"%s %d was stopped because the VU iteration was interrupted\",\n\t\t\t\t\t\ttimer.name, timer.id)\n\t\t\t\t}\n\n\t\t\t\tclear(e.timers)\n\t\t\t\te.queue.stopTimer()\n\t\t\t\te.queue = new(timerQueue)\n\t\t\t\te.taskQueue = nil\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tq.Close()\n\t\tcase <-ch:\n\t\t\te.timers = make(map[uint64]time.Time)\n\t\t\te.queue.stopTimer()\n\t\t\te.queue = new(timerQueue)\n\t\t\te.taskQueue = nil\n\t\t\tq.Close()\n\t\t\tclose(ch)\n\t\t}\n\t}()\n}\n\n// this is just a small struct to keep the internals of a timer\ntype timer struct {\n\tid          uint64\n\tnextTrigger time.Time\n\ttask        func() error\n\tname        string\n}\n\n// this is just a list of timers that should be ordered once after the other\n// this mostly just has methods to work on the slice\ntype timerQueue struct {\n\tqueue []*timer\n\thead  *time.Timer\n}\n\nfunc (tq *timerQueue) add(t *timer) int {\n\ti := slices.IndexFunc(tq.queue, func(tt *timer) bool {\n\t\treturn tt.nextTrigger.After(t.nextTrigger)\n\t})\n\tif i < 0 {\n\t\ti = len(tq.queue)\n\t}\n\ttq.queue = slices.Insert(tq.queue, i, t)\n\treturn i\n}\n\nfunc (tq *timerQueue) stopTimer() {\n\tif tq.head != nil && tq.head.Stop() { // we have a timer and we stopped it before it was over.\n\t\tselect {\n\t\tcase <-tq.head.C:\n\t\tdefault:\n\t\t}\n\t}\n}\n\nfunc (tq *timerQueue) remove(id uint64) {\n\ttq.queue = slices.DeleteFunc(tq.queue, func(t *timer) bool {\n\t\treturn id == t.id\n\t})\n}\n\nfunc (tq *timerQueue) pop() *timer {\n\tlength := len(tq.queue)\n\tif length == 0 {\n\t\treturn nil\n\t}\n\tt := tq.queue[0]\n\ttq.queue = slices.Delete(tq.queue, 0, 1)\n\treturn t\n}\n\nfunc (tq *timerQueue) length() int {\n\treturn len(tq.queue)\n}\n\nfunc (tq *timerQueue) first() *timer {\n\tif tq.length() == 0 {\n\t\treturn nil\n\t}\n\treturn tq.queue[0]\n}\n"
  },
  {
    "path": "internal/js/tc55/timers/timers_test.go",
    "content": "package timers_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nfunc newRuntime(t testing.TB) *modulestest.Runtime {\n\tt.Helper()\n\truntime := modulestest.NewRuntime(t)\n\n\treturn runtime\n}\n\nfunc TestSetTimeout(t *testing.T) {\n\tt.Parallel()\n\n\truntime := newRuntime(t)\n\trt := runtime.VU.Runtime()\n\tvar log []string\n\trequire.NoError(t, rt.Set(\"print\", func(s string) { log = append(log, s) }))\n\n\t_, err := runtime.RunOnEventLoop(`\n\t\tsetTimeout(()=> {\n\t\t\tprint(\"in setTimeout\")\n\t\t})\n\t\tprint(\"outside setTimeout\")\n\t`)\n\trequire.NoError(t, err)\n\trequire.Equal(t, []string{\"outside setTimeout\", \"in setTimeout\"}, log)\n}\n\nfunc TestSetUndefinedFunction(t *testing.T) {\n\tt.Parallel()\n\n\truntime := newRuntime(t)\n\t_, err := runtime.RunOnEventLoop(`\n\t\tsetTimeout(undefined)\n\t`)\n\trequire.Error(t, err, \"setTimeout's callback isn't a callable function\")\n}\n\nfunc TestSetInterval(t *testing.T) {\n\tt.Parallel()\n\truntime := newRuntime(t)\n\n\trt := runtime.VU.Runtime()\n\tvar log []string\n\trequire.NoError(t, rt.Set(\"print\", func(s string) { log = append(log, s) }))\n\trequire.NoError(t, rt.Set(\"sleep10\", func() { time.Sleep(10 * time.Millisecond) }))\n\n\t_, err := runtime.RunOnEventLoop(`\n\t\tvar i = 0;\n\t\tlet s = setInterval(()=> {\n\t\t\tsleep10();\n\t\t\tif (i>1) {\n\t\t\t  print(\"in setInterval\");\n\t\t\t  clearInterval(s);\n\t\t\t}\n\t\t\ti++;\n\t\t}, 1);\n\t\tprint(\"outside setInterval\")\n\t`)\n\trequire.NoError(t, err)\n\trequire.Len(t, log, 2)\n\trequire.Equal(t, \"outside setInterval\", log[0])\n\tfor i, l := range log[1:] {\n\t\trequire.Equal(t, \"in setInterval\", l, i)\n\t}\n}\n\nfunc TestSetTimeoutOrder(t *testing.T) {\n\tt.Parallel()\n\truntime := newRuntime(t)\n\n\trt := runtime.VU.Runtime()\n\tvar log []string\n\trequire.NoError(t, rt.Set(\"print\", func(s string) { log = append(log, s) }))\n\n\tfor i := range 100 {\n\t\t_, err := runtime.RunOnEventLoop(`\n\t\t\tsetTimeout((_) => print(\"one\"), 1);\n\t\t\tsetTimeout((_) => print(\"two\"), 1);\n\t\t\tsetTimeout((_) => print(\"three\"), 1);\n\t\t\tsetTimeout((_) => print(\"last\"), 20);\n\t\t\tsetTimeout((_) => print(\"four\"), 1);\n\t\t\tsetTimeout((_) => print(\"five\"), 1);\n\t\t\tsetTimeout((_) => print(\"six\"), 1);\n\t\t\tprint(\"outside setTimeout\");\n\t\t`)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, []string{\"outside setTimeout\", \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"last\"}, log, i)\n\t\tlog = log[:0]\n\t}\n}\n\nfunc TestSetIntervalOrder(t *testing.T) {\n\tt.Parallel()\n\truntime := newRuntime(t)\n\n\trt := runtime.VU.Runtime()\n\tvar log []string\n\trequire.NoError(t, rt.Set(\"print\", func(s string) { log = append(log, s) }))\n\n\tfor range 100 {\n\t\t_, err := runtime.RunOnEventLoop(`\n\t\t\tvar one = setInterval((_) => print(\"one\"), 1);\n\t\t\tvar two = setInterval((_) => print(\"two\"), 1);\n\t\t\tvar last = setInterval((_) => {\n\t\t\t\tprint(\"last\")\n\t\t\t\tclearInterval(one);\n\t\t\t\tclearInterval(two);\n\t\t\t\tclearInterval(three);\n\t\t\t\tclearInterval(last);\n\t\t\t}, 10);\n\t\t\tvar three = setInterval((_) => print(\"three\"), 1);\n\t\t\tprint(\"outside\");\n\t\t`)\n\t\trequire.NoError(t, err)\n\t\truntime.EventLoop.WaitOnRegistered()\n\t\trequire.GreaterOrEqual(t, len(log), 5)\n\t\trequire.Equal(t, \"outside\", log[0])\n\t\tfor i := 1; i < len(log)-1; i += 3 {\n\t\t\tswitch len(log) - i {\n\t\t\tcase 2:\n\t\t\t\trequire.Equal(t, []string{\"one\"}, log[i:i+1])\n\t\t\tcase 3:\n\t\t\t\trequire.Equal(t, []string{\"one\", \"two\"}, log[i:i+2])\n\t\t\tdefault:\n\t\t\t\trequire.Equal(t, []string{\"one\", \"two\", \"three\"}, log[i:i+3])\n\t\t\t}\n\t\t}\n\t\trequire.Equal(t, \"last\", log[len(log)-1])\n\t\tlog = log[:0]\n\t}\n}\n\nfunc TestSetTimeoutContextCancel(t *testing.T) {\n\tt.Parallel()\n\truntime := newRuntime(t)\n\n\trt := runtime.VU.Runtime()\n\tvar log []string\n\tinterruptChannel := make(chan struct{})\n\trequire.NoError(t, rt.Set(\"print\", func(s string) { log = append(log, s) }))\n\trequire.NoError(t, rt.Set(\"interrupt\", func() {\n\t\tselect {\n\t\tcase interruptChannel <- struct{}{}:\n\t\tdefault:\n\t\t}\n\t}))\n\n\tfor range 2000 {\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\truntime.CancelContext = cancel\n\t\truntime.VU.CtxField = ctx //nolint:fatcontext\n\t\truntime.VU.RuntimeField.ClearInterrupt()\n\t\tconst interruptMsg = \"definitely an interrupt\"\n\t\tsync := make(chan struct{})\n\t\tdefer func() {\n\t\t\tcancel()\n\t\t\t<-sync\n\t\t}()\n\t\tgo func() {\n\t\t\tdefer close(sync)\n\t\t\tselect {\n\t\t\tcase <-interruptChannel:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttime.Sleep(time.Millisecond)\n\t\t\truntime.CancelContext()\n\t\t\truntime.VU.RuntimeField.Interrupt(interruptMsg)\n\t\t}()\n\t\t_, err := runtime.RunOnEventLoop(`\n\t\t\t(async () => {\n\t\t\t\tlet poll = async (resolve, reject) => {\n\t\t\t\t\tawait (async () => 5);\n\t\t\t\t\tsetTimeout(poll, 1, resolve, reject);\n\t\t\t\t\tinterrupt();\n\t\t\t\t}\n\t\t\t\tsetTimeout(async () => {\n\t\t\t\t\tawait new Promise(poll)\n\t\t\t\t}, 0)\n\t\t\t})()\n\t\t`)\n\t\tif err != nil {\n\t\t\trequire.ErrorContains(t, err, interruptMsg)\n\t\t}\n\t\trequire.Empty(t, log)\n\t}\n}\n\nfunc TestClearFirstTimeoutWhenMultiple(t *testing.T) {\n\tt.Parallel()\n\n\truntime := newRuntime(t)\n\trt := runtime.VU.Runtime()\n\tvar log []time.Time\n\n\tstart := time.Now()\n\trequire.NoError(t, rt.Set(\"time\", func() { log = append(log, time.Now()) }))\n\t_, err := runtime.RunOnEventLoop(`\n\t\tsetTimeout(() => {\n\t\t   time();\n\t\t}, 1000);\n\t\tconst cancelTimeout = setTimeout(() => {}, 200);\n\t\tclearTimeout(cancelTimeout);\n\t`)\n\trequire.NoError(t, err)\n\trequire.Len(t, log, 1)\n\trequire.Greater(t, log[0].Sub(start), time.Second)\n}\n"
  },
  {
    "path": "internal/js/timeout_error.go",
    "content": "package js\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/lib/consts\"\n)\n\n// timeoutError is used when some operation times out.\ntype timeoutError struct {\n\tplace string\n\td     time.Duration\n}\n\nvar _ interface {\n\terrext.HasExitCode\n\terrext.HasHint\n\terrext.HasAbortReason\n} = timeoutError{}\n\n// newTimeoutError returns a new timeout error, reporting that a timeout has\n// happened at the given place and given duration.\nfunc newTimeoutError(place string, d time.Duration) timeoutError {\n\treturn timeoutError{place: place, d: d}\n}\n\n// Error returns the timeout error in human readable format.\nfunc (t timeoutError) Error() string {\n\treturn fmt.Sprintf(\"%s() execution timed out after %.f seconds\", t.place, t.d.Seconds())\n}\n\n// Hint potentially returns a hint message for fixing the error.\nfunc (t timeoutError) Hint() string {\n\thint := \"\"\n\n\tswitch t.place {\n\tcase consts.SetupFn:\n\t\thint = \"You can increase the time limit via the setupTimeout option\"\n\tcase consts.TeardownFn:\n\t\thint = \"You can increase the time limit via the teardownTimeout option\"\n\t}\n\treturn hint\n}\n\nfunc (t timeoutError) AbortReason() errext.AbortReason {\n\treturn errext.AbortedByTimeout\n}\n\n// ExitCode returns the corresponding exit code value to the place.\nfunc (t timeoutError) ExitCode() exitcodes.ExitCode {\n\t// TODO: add handleSummary()\n\tswitch t.place {\n\tcase consts.SetupFn:\n\t\treturn exitcodes.SetupTimeout\n\tcase consts.TeardownFn:\n\t\treturn exitcodes.TeardownTimeout\n\tdefault:\n\t\treturn exitcodes.GenericTimeout\n\t}\n}\n"
  },
  {
    "path": "internal/js/timeout_error_test.go",
    "content": "package js\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/lib/consts\"\n)\n\nfunc TestTimeoutError(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tstage, expectedStrContain string\n\t\td                         time.Duration\n\t}{\n\t\t{consts.SetupFn, \"1 seconds\", time.Second},\n\t\t{consts.TeardownFn, \"2 seconds\", time.Second * 2},\n\t\t{\"\", \"0 seconds\", time.Duration(0)},\n\t}\n\n\tfor _, tc := range tests {\n\t\tte := newTimeoutError(tc.stage, tc.d)\n\t\tif !strings.Contains(te.Error(), tc.expectedStrContain) {\n\t\t\tt.Errorf(\"Expected error contains %s, but got: %s\", tc.expectedStrContain, te.Error())\n\t\t}\n\t}\n}\n\nfunc TestTimeoutErrorHint(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tstage string\n\t\tempty bool\n\t}{\n\t\t{consts.SetupFn, false},\n\t\t{consts.TeardownFn, false},\n\t\t{\"not handle\", true},\n\t}\n\n\tfor _, tc := range tests {\n\t\tte := newTimeoutError(tc.stage, time.Second)\n\t\tif tc.empty && te.Hint() != \"\" {\n\t\t\tt.Errorf(\"Expected empty hint, got: %s\", te.Hint())\n\t\t}\n\t\tif !tc.empty && te.Hint() == \"\" {\n\t\t\tt.Errorf(\"Expected non-empty hint, got empty\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/lib/consts/js.go",
    "content": "// Package consts houses some constants needed across k6\npackage consts\n\n// JS constants\nconst (\n\tDefaultFn       = \"default\"\n\tOptions         = \"options\"\n\tSetupFn         = \"setup\"\n\tTeardownFn      = \"teardown\"\n\tHandleSummaryFn = \"handleSummary\"\n)\n"
  },
  {
    "path": "internal/lib/netext/grpcext/conn.go",
    "content": "// Package grpcext allows gRPC requests collecting stats info.\npackage grpcext\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n\n\tprotov1 \"github.com/golang/protobuf/proto\" //nolint:staticcheck,nolintlint // this is the old v1 version\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\thealthpb \"google.golang.org/grpc/health/grpc_health_v1\"\n\t\"google.golang.org/grpc/metadata\"\n\tgrpcstats \"google.golang.org/grpc/stats\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/encoding/prototext\"\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n)\n\n// InvokeRequest represents a unary gRPC request.\ntype InvokeRequest struct {\n\tMethod                 string\n\tMethodDescriptor       protoreflect.MethodDescriptor\n\tTimeout                time.Duration\n\tTagsAndMeta            *metrics.TagsAndMeta\n\tDiscardResponseMessage bool\n\tMessage                []byte\n\tMetadata               metadata.MD\n}\n\n// InvokeResponse represents a gRPC response.\ntype InvokeResponse struct {\n\tMessage  any\n\tError    any\n\tHeaders  map[string][]string\n\tTrailers map[string][]string\n\tStatus   codes.Code\n}\n\n// StreamRequest represents a gRPC stream request.\ntype StreamRequest struct {\n\tMethod                 string\n\tMethodDescriptor       protoreflect.MethodDescriptor\n\tTimeout                time.Duration\n\tDiscardResponseMessage bool\n\tTagsAndMeta            *metrics.TagsAndMeta\n\tMetadata               metadata.MD\n}\n\n// HealthCheckResponse represents a gRPC healthcheck response.\ntype HealthCheckResponse struct {\n\tStatus healthpb.HealthCheckResponse_ServingStatus\n}\n\ntype clientConnCloser interface {\n\tgrpc.ClientConnInterface\n\tClose() error\n}\n\n// Conn is a gRPC client connection.\ntype Conn struct {\n\traw   clientConnCloser\n\ttypes *protoregistry.Types\n}\n\n// DefaultOptions generates an option set\n// with common options for requests from a VU.\nfunc DefaultOptions(getState func() *lib.State) []grpc.DialOption {\n\tdialer := func(ctx context.Context, addr string) (net.Conn, error) {\n\t\treturn getState().Dialer.DialContext(ctx, \"tcp\", addr)\n\t}\n\n\treturn []grpc.DialOption{\n\t\tgrpc.WithBlock(),                  //nolint:staticcheck\n\t\tgrpc.FailOnNonTempDialError(true), //nolint:staticcheck\n\t\tgrpc.WithReturnConnectionError(),  //nolint:staticcheck\n\t\tgrpc.WithStatsHandler(statsHandler{getState: getState}),\n\t\tgrpc.WithContextDialer(dialer),\n\t}\n}\n\n// Dial establish a gRPC connection.\nfunc Dial(ctx context.Context, addr string, types *protoregistry.Types, options ...grpc.DialOption) (*Conn, error) {\n\tconn, err := grpc.DialContext(ctx, addr, options...) //nolint:staticcheck\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &Conn{\n\t\traw:   conn,\n\t\ttypes: types,\n\t}, nil\n}\n\n// Reflect returns using the reflection the FileDescriptorSet describing the service.\nfunc (c *Conn) Reflect(ctx context.Context) (*descriptorpb.FileDescriptorSet, error) {\n\trc := reflectionClient{Conn: c.raw}\n\treturn rc.Reflect(ctx)\n}\n\n// HealthCheck executes a unary gRPC healthcheck Check call.\nfunc (c *Conn) HealthCheck(ctx context.Context, svc string) (*HealthCheckResponse, error) {\n\thealthClient := healthpb.NewHealthClient(c.raw)\n\tres, err := healthClient.Check(ctx, &healthpb.HealthCheckRequest{Service: svc})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &HealthCheckResponse{Status: res.GetStatus()}, nil\n}\n\n// Invoke executes a unary gRPC request.\nfunc (c *Conn) Invoke(\n\tctx context.Context,\n\treq InvokeRequest,\n\topts ...grpc.CallOption,\n) (*InvokeResponse, error) {\n\tif req.Method == \"\" {\n\t\treturn nil, fmt.Errorf(\"url is required\")\n\t}\n\n\tif req.MethodDescriptor == nil {\n\t\treturn nil, fmt.Errorf(\"request method descriptor is required\")\n\t}\n\tif len(req.Message) == 0 {\n\t\treturn nil, fmt.Errorf(\"request message is required\")\n\t}\n\n\tif req.Timeout != time.Duration(0) {\n\t\tvar cancel context.CancelFunc\n\t\tctx, cancel = context.WithTimeout(ctx, req.Timeout)\n\t\tdefer cancel()\n\t}\n\n\tctx = metadata.NewOutgoingContext(ctx, req.Metadata)\n\n\treqdm := dynamicpb.NewMessage(req.MethodDescriptor.Input())\n\tif err := (protojson.UnmarshalOptions{Resolver: c.types}).Unmarshal(req.Message, reqdm); err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to serialise request object to protocol buffer: %w\", err)\n\t}\n\n\tctx = withRPCState(ctx, &rpcState{tagsAndMeta: req.TagsAndMeta})\n\n\tvar resp *dynamicpb.Message\n\tif req.DiscardResponseMessage {\n\t\tresp = dynamicpb.NewMessage((&emptypb.Empty{}).ProtoReflect().Descriptor())\n\t} else {\n\t\tresp = dynamicpb.NewMessage(req.MethodDescriptor.Output())\n\t}\n\n\theader, trailer := metadata.New(nil), metadata.New(nil)\n\n\tcopts := make([]grpc.CallOption, 0, len(opts)+2)\n\tcopts = append(copts, opts...)\n\tcopts = append(copts, grpc.Header(&header), grpc.Trailer(&trailer))\n\n\terr := c.raw.Invoke(ctx, req.Method, reqdm, resp, copts...)\n\n\tresponse := InvokeResponse{\n\t\tHeaders:  header,\n\t\tTrailers: trailer,\n\t}\n\n\tmarshaler := protojson.MarshalOptions{EmitUnpopulated: true, Resolver: c.types}\n\n\tif err != nil {\n\t\tsterr := status.Convert(err)\n\t\tresponse.Status = sterr.Code()\n\n\t\t// (rogchap) when you access a JSON property in Sobek, you are actually accessing the underling\n\t\t// Go type (struct, map, slice etc); because these are dynamic messages the Unmarshaled JSON does\n\t\t// not map back to a \"real\" field or value (as a normal Go type would). If we don't marshal and then\n\t\t// unmarshal back to a map, you will get \"undefined\" when accessing JSON properties, even when\n\t\t// JSON.Stringify() shows the object to be correctly present.\n\n\t\traw, _ := marshaler.Marshal(sterr.Proto())\n\t\terrMsg := make(map[string]any)\n\t\t_ = json.Unmarshal(raw, &errMsg)\n\t\tresponse.Error = errMsg\n\t}\n\n\tif resp != nil && !req.DiscardResponseMessage {\n\t\tmsg, err := convert(marshaler, resp)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to convert response object to JSON: %w\", err)\n\t\t}\n\n\t\tresponse.Message = msg\n\t}\n\treturn &response, nil\n}\n\n// NewStream creates a new gRPC stream.\nfunc (c *Conn) NewStream(\n\tctx context.Context,\n\treq StreamRequest,\n\topts ...grpc.CallOption,\n) (*Stream, error) {\n\tctx = metadata.NewOutgoingContext(ctx, req.Metadata)\n\n\tctx = withRPCState(ctx, &rpcState{tagsAndMeta: req.TagsAndMeta})\n\n\tstream, err := c.raw.NewStream(ctx, &grpc.StreamDesc{\n\t\tStreamName:    string(req.MethodDescriptor.Name()),\n\t\tServerStreams: req.MethodDescriptor.IsStreamingServer(),\n\t\tClientStreams: req.MethodDescriptor.IsStreamingClient(),\n\t}, req.Method, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Stream{\n\t\traw:                    stream,\n\t\tmethod:                 req.Method,\n\t\tmethodDescriptor:       req.MethodDescriptor,\n\t\tdiscardResponseMessage: req.DiscardResponseMessage,\n\t\tmarshaler:              protojson.MarshalOptions{Resolver: c.types, EmitUnpopulated: true},\n\t\tunmarshaler:            protojson.UnmarshalOptions{Resolver: c.types},\n\t}, nil\n}\n\n// Close closes the underhood connection.\nfunc (c *Conn) Close() error {\n\treturn c.raw.Close()\n}\n\ntype statsHandler struct {\n\tgetState func() *lib.State\n}\n\n// TagConn implements the grpcstats.Handler interface\nfunc (statsHandler) TagConn(ctx context.Context, _ *grpcstats.ConnTagInfo) context.Context { // noop\n\treturn ctx\n}\n\n// HandleConn implements the grpcstats.Handler interface\nfunc (statsHandler) HandleConn(context.Context, grpcstats.ConnStats) {\n\t// noop\n}\n\n// TagRPC implements the grpcstats.Handler interface\nfunc (statsHandler) TagRPC(ctx context.Context, _ *grpcstats.RPCTagInfo) context.Context {\n\t// noop\n\treturn ctx\n}\n\n// HandleRPC implements the grpcstats.Handler interface\nfunc (h statsHandler) HandleRPC(ctx context.Context, stat grpcstats.RPCStats) {\n\tstate := h.getState()\n\tstateRPC := getRPCState(ctx)\n\n\t// If the request is done by the reflection handler then the tags will be\n\t// nil. In this case, we can reuse the VU.State's Tags.\n\tif stateRPC == nil {\n\t\t// TODO: investigate this more, there has to be a way to fix it :/\n\t\tctm := state.Tags.GetCurrentValues()\n\t\tstateRPC = &rpcState{tagsAndMeta: &ctm}\n\t}\n\n\tswitch s := stat.(type) {\n\tcase *grpcstats.OutHeader:\n\t\t// TODO: figure out something better, e.g. via TagConn() or TagRPC()?\n\t\tif state.Options.SystemTags.Has(metrics.TagIP) && s.RemoteAddr != nil {\n\t\t\tif ip, _, err := net.SplitHostPort(s.RemoteAddr.String()); err == nil {\n\t\t\t\tstateRPC.tagsAndMeta.SetSystemTagOrMeta(metrics.TagIP, ip)\n\t\t\t}\n\t\t}\n\tcase *grpcstats.End:\n\t\tif state.Options.SystemTags.Has(metrics.TagStatus) {\n\t\t\tstateRPC.tagsAndMeta.SetSystemTagOrMeta(metrics.TagStatus, strconv.Itoa(int(status.Code(s.Error))))\n\t\t}\n\n\t\tmetrics.PushIfNotDone(ctx, state.Samples, metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: state.BuiltinMetrics.GRPCReqDuration,\n\t\t\t\tTags:   stateRPC.tagsAndMeta.Tags,\n\t\t\t},\n\t\t\tTime:     s.EndTime,\n\t\t\tMetadata: stateRPC.tagsAndMeta.Metadata,\n\t\t\tValue:    metrics.D(s.EndTime.Sub(s.BeginTime)),\n\t\t})\n\t}\n\n\t// (rogchap) Re-using --http-debug flag as gRPC is technically still HTTP\n\tif state.Options.HTTPDebug.String != \"\" {\n\t\tlogger := state.Logger.WithField(\"source\", \"http-debug\")\n\t\thttpDebugOption := state.Options.HTTPDebug.String\n\t\tDebugStat(logger, stat, httpDebugOption)\n\t}\n}\n\n// DebugStat prints debugging information based on RPCStats.\nfunc DebugStat(logger logrus.FieldLogger, stat grpcstats.RPCStats, httpDebugOption string) {\n\tswitch s := stat.(type) {\n\tcase *grpcstats.OutHeader:\n\t\tlogger.Infof(\"Out Header:\\nFull Method: %s\\nRemote Address: %s\\n%s\\n\",\n\t\t\ts.FullMethod, s.RemoteAddr, formatMetadata(s.Header))\n\tcase *grpcstats.OutTrailer:\n\t\tif len(s.Trailer) > 0 {\n\t\t\tlogger.Infof(\"Out Trailer:\\n%s\\n\", formatMetadata(s.Trailer))\n\t\t}\n\tcase *grpcstats.OutPayload:\n\t\tif httpDebugOption == \"full\" {\n\t\t\tlogger.Infof(\"Out Payload:\\nWire Length: %d\\nSent Time: %s\\n%s\\n\\n\",\n\t\t\t\ts.WireLength, s.SentTime, formatPayload(s.Payload))\n\t\t}\n\tcase *grpcstats.InHeader:\n\t\tif len(s.Header) > 0 {\n\t\t\tlogger.Infof(\"In Header:\\nWire Length: %d\\n%s\\n\", s.WireLength, formatMetadata(s.Header))\n\t\t}\n\tcase *grpcstats.InTrailer:\n\t\tif len(s.Trailer) > 0 {\n\t\t\tlogger.Infof(\"In Trailer:\\nWire Length: %d\\n%s\\n\", s.WireLength, formatMetadata(s.Trailer))\n\t\t}\n\tcase *grpcstats.InPayload:\n\t\tif httpDebugOption == \"full\" {\n\t\t\tlogger.Infof(\"In Payload:\\nWire Length: %d\\nReceived Time: %s\\n%s\\n\\n\",\n\t\t\t\ts.WireLength, s.RecvTime, formatPayload(s.Payload))\n\t\t}\n\t}\n}\n\nfunc formatMetadata(md metadata.MD) string {\n\tvar sb strings.Builder\n\tfor k, v := range md {\n\t\tsb.WriteString(k)\n\t\tsb.WriteString(\": \")\n\t\tsb.WriteString(strings.Join(v, \", \"))\n\t\tsb.WriteRune('\\n')\n\t}\n\n\treturn sb.String()\n}\n\nfunc formatPayload(payload any) string {\n\tmsg, ok := payload.(proto.Message)\n\tif !ok {\n\t\t// check to see if we are dealing with a APIv1 message\n\t\tmsgV1, ok := payload.(protov1.Message)\n\t\tif !ok {\n\t\t\treturn \"\"\n\t\t}\n\t\tmsg = protov1.MessageV2(msgV1)\n\t}\n\n\tmarshaler := prototext.MarshalOptions{\n\t\tMultiline: true,\n\t\tIndent:    \"  \",\n\t}\n\tb, err := marshaler.Marshal(msg)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn string(b)\n}\n\ntype contextKey string\n\nvar ctxKeyRPCState = contextKey(\"rpcState\") //nolint:gochecknoglobals\n\ntype rpcState struct {\n\ttagsAndMeta *metrics.TagsAndMeta\n}\n\nfunc withRPCState(ctx context.Context, rpcState *rpcState) context.Context {\n\treturn context.WithValue(ctx, ctxKeyRPCState, rpcState)\n}\n\nfunc getRPCState(ctx context.Context) *rpcState {\n\tv := ctx.Value(ctxKeyRPCState)\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn v.(*rpcState) //nolint: forcetypeassert\n}\n"
  },
  {
    "path": "internal/lib/netext/grpcext/conn_test.go",
    "content": "package grpcext\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/bufbuild/protocompile\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n\n\thealthpb \"google.golang.org/grpc/health/grpc_health_v1\"\n)\n\ntype healthcheckmock func(in *healthpb.HealthCheckRequest, out *healthpb.HealthCheckResponse, opts ...grpc.CallOption) error\n\nfunc (im healthcheckmock) Invoke(_ context.Context, _ string, payload, reply any, opts ...grpc.CallOption) error {\n\tin, ok := payload.(*healthpb.HealthCheckRequest)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for payload\")\n\t}\n\tout, ok := reply.(*healthpb.HealthCheckResponse)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for reply\")\n\t}\n\treturn im(in, out, opts...)\n}\n\nfunc (healthcheckmock) Close() error {\n\treturn nil\n}\n\nfunc (healthcheckmock) NewStream(_ context.Context, _ *grpc.StreamDesc, _ string, _ ...grpc.CallOption) (grpc.ClientStream, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc TestHealthCheck(t *testing.T) {\n\tt.Parallel()\n\n\tservingsSvc := \"serving-service\"\n\tnotServingSvc := \"not-serving-service\"\n\thealthReply := func(req *healthpb.HealthCheckRequest, out *healthpb.HealthCheckResponse, _ ...grpc.CallOption) error {\n\t\tvar status healthpb.HealthCheckResponse_ServingStatus\n\t\tswitch req.Service {\n\t\tcase \"\", notServingSvc:\n\t\t\tstatus = healthpb.HealthCheckResponse_NOT_SERVING\n\t\tcase servingsSvc:\n\t\t\tstatus = healthpb.HealthCheckResponse_SERVING\n\t\tdefault:\n\t\t\tstatus = healthpb.HealthCheckResponse_UNKNOWN\n\t\t}\n\n\t\terr := protojson.Unmarshal(fmt.Appendf(nil, `{\"status\":%d}`, status), out)\n\t\trequire.NoError(t, err)\n\n\t\treturn nil\n\t}\n\tc := Conn{raw: healthcheckmock(healthReply)}\n\n\tcases := []struct {\n\t\tname           string\n\t\tsvc            string\n\t\texpectedStatus healthpb.HealthCheckResponse_ServingStatus\n\t}{\n\t\t{\n\t\t\tname:           \"server is not serving\",\n\t\t\tsvc:            \"\",\n\t\t\texpectedStatus: healthpb.HealthCheckResponse_NOT_SERVING,\n\t\t},\n\t\t{\n\t\t\tname:           \"unknown service\",\n\t\t\tsvc:            \"unknown-service\",\n\t\t\texpectedStatus: healthpb.HealthCheckResponse_UNKNOWN,\n\t\t},\n\t\t{\n\t\t\tname:           \"serving service\",\n\t\t\tsvc:            servingsSvc,\n\t\t\texpectedStatus: healthpb.HealthCheckResponse_SERVING,\n\t\t},\n\t\t{\n\t\t\tname:           \"not serving service\",\n\t\t\tsvc:            notServingSvc,\n\t\t\texpectedStatus: healthpb.HealthCheckResponse_NOT_SERVING,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tres, err := c.HealthCheck(context.Background(), tc.svc)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.expectedStatus, res.Status)\n\t\t})\n\t}\n}\n\nfunc TestInvoke(t *testing.T) {\n\tt.Parallel()\n\n\thelloReply := func(_, out *dynamicpb.Message, _ ...grpc.CallOption) error {\n\t\terr := protojson.Unmarshal([]byte(`{\"reply\":\"text reply\"}`), out)\n\t\trequire.NoError(t, err)\n\n\t\treturn nil\n\t}\n\n\tc := Conn{raw: invokemock(helloReply)}\n\tr := InvokeRequest{\n\t\tMethod:           \"/hello.HelloService/SayHello\",\n\t\tMethodDescriptor: methodFromProto(\"SayHello\"),\n\t\tMessage:          []byte(`{\"greeting\":\"text request\"}`),\n\t\tMetadata:         metadata.New(nil),\n\t}\n\tres, err := c.Invoke(context.Background(), r)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, codes.OK, res.Status)\n\tassert.Equal(t, map[string]any{\"reply\": \"text reply\"}, res.Message)\n\tassert.Empty(t, res.Error)\n}\n\nfunc TestInvokeWithCallOptions(t *testing.T) {\n\tt.Parallel()\n\n\treply := func(_, _ *dynamicpb.Message, opts ...grpc.CallOption) error {\n\t\tassert.Len(t, opts, 3) // two by default plus one injected\n\t\treturn nil\n\t}\n\n\tc := Conn{raw: invokemock(reply)}\n\tr := InvokeRequest{\n\t\tMethod:           \"/hello.HelloService/NoOp\",\n\t\tMethodDescriptor: methodFromProto(\"NoOp\"),\n\t\tMessage:          []byte(`{}`),\n\t\tMetadata:         metadata.New(nil),\n\t}\n\tres, err := c.Invoke(context.Background(), r, grpc.UseCompressor(\"fakeone\"))\n\trequire.NoError(t, err)\n\tassert.NotNil(t, res)\n}\n\nfunc TestInvokeWithDiscardResponseMessage(t *testing.T) {\n\tt.Parallel()\n\n\treply := func(_, _ *dynamicpb.Message, opts ...grpc.CallOption) error {\n\t\tassert.Len(t, opts, 3) // two by default plus one injected\n\t\treturn nil\n\t}\n\n\tc := Conn{raw: invokemock(reply)}\n\tr := InvokeRequest{\n\t\tMethod:                 \"/hello.HelloService/NoOp\",\n\t\tMethodDescriptor:       methodFromProto(\"NoOp\"),\n\t\tDiscardResponseMessage: true,\n\t\tMessage:                []byte(`{}`),\n\t\tMetadata:               metadata.New(nil),\n\t}\n\tres, err := c.Invoke(context.Background(), r, grpc.UseCompressor(\"fakeone\"))\n\trequire.NoError(t, err)\n\tassert.NotNil(t, res)\n\tassert.Nil(t, res.Message)\n}\n\nfunc TestInvokeReturnError(t *testing.T) {\n\tt.Parallel()\n\n\thelloReply := func(_, _ *dynamicpb.Message, _ ...grpc.CallOption) error {\n\t\treturn fmt.Errorf(\"test error\")\n\t}\n\n\tc := Conn{raw: invokemock(helloReply)}\n\tr := InvokeRequest{\n\t\tMethod:           \"/hello.HelloService/SayHello\",\n\t\tMethodDescriptor: methodFromProto(\"SayHello\"),\n\t\tMessage:          []byte(`{\"greeting\":\"text request\"}`),\n\t\tMetadata:         metadata.New(nil),\n\t}\n\tres, err := c.Invoke(context.Background(), r)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, codes.Unknown, res.Status)\n\tassert.NotEmpty(t, res.Error)\n\tassert.Equal(t, map[string]any{\"reply\": \"\"}, res.Message)\n}\n\nfunc TestConnInvokeInvalid(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\t// valid arguments\n\t\tctx        = context.Background()\n\t\turl        = \"not-empty-url-for-method\"\n\t\tmd         = metadata.New(nil)\n\t\tmethodDesc = methodFromProto(\"SayHello\")\n\t\tpayload    = []byte(`{\"greeting\":\"test\"}`)\n\t)\n\n\ttests := []struct {\n\t\tname   string\n\t\tctx    context.Context\n\t\treq    InvokeRequest\n\t\texperr string\n\t}{\n\t\t{\n\t\t\tname:   \"EmptyMethod\",\n\t\t\tctx:    ctx,\n\t\t\treq:    InvokeRequest{MethodDescriptor: methodDesc, Message: payload, Metadata: md, Method: \"\"},\n\t\t\texperr: \"url is required\",\n\t\t},\n\t\t{\n\t\t\tname:   \"NullMethodDescriptor\",\n\t\t\tctx:    ctx,\n\t\t\treq:    InvokeRequest{Message: payload, Metadata: nil, Method: url},\n\t\t\texperr: \"method descriptor is required\",\n\t\t},\n\t\t{\n\t\t\tname:   \"NullMessage\",\n\t\t\tctx:    ctx,\n\t\t\treq:    InvokeRequest{MethodDescriptor: methodDesc, Metadata: nil, Method: url},\n\t\t\texperr: \"message is required\",\n\t\t},\n\t\t{\n\t\t\tname:   \"EmptyMessage\",\n\t\t\tctx:    ctx,\n\t\t\treq:    InvokeRequest{MethodDescriptor: methodDesc, Message: []byte{}, Metadata: nil, Method: url},\n\t\t\texperr: \"message is required\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tc := Conn{}\n\t\t\tres, err := c.Invoke(tt.ctx, tt.req)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Nil(t, res)\n\t\t\tassert.Contains(t, err.Error(), tt.experr)\n\t\t})\n\t}\n}\n\nfunc methodFromProto(method string) protoreflect.MethodDescriptor {\n\tpath := \"any-path\"\n\n\tresolver := &protocompile.SourceResolver{\n\t\tAccessor: func(filename string) (io.ReadCloser, error) {\n\t\t\t// a small hack to make sure we are parsing the right file\n\t\t\t// otherwise the parser will try to parse \"google/protobuf/descriptor.proto\"\n\t\t\t// with exactly the same name as the one we are trying to parse for testing\n\t\t\tif filename != path {\n\t\t\t\treturn nil, nil //nolint:nilnil\n\t\t\t}\n\n\t\t\tb := `\nsyntax = \"proto3\";\n\npackage hello;\n\nservice HelloService {\n  rpc SayHello(HelloRequest) returns (HelloResponse);\n  rpc NoOp(Empty) returns (Empty);\n  rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);\n  rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);\n  rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);\n}\n\nmessage HelloRequest {\n  string greeting = 1;\n}\n\nmessage HelloResponse {\n  string reply = 1;\n}\n\nmessage Empty {\n\n}`\n\n\t\t\treturn io.NopCloser(bytes.NewBufferString(b)), nil\n\t\t},\n\t}\n\n\tcompiler := protocompile.Compiler{\n\t\tResolver: resolver,\n\t}\n\n\tfds, err := compiler.Compile(context.Background(), path)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tif len(fds) != 1 {\n\t\tpanic(\"expected exactly one file descriptor\")\n\t}\n\tfd := fds[0]\n\n\tservices := fd.Services()\n\tif services.Len() == 0 {\n\t\tpanic(\"no available services\")\n\t}\n\treturn services.Get(0).Methods().ByName(protoreflect.Name(method))\n}\n\n// invokemock is a mock for the grpc connection supporting only unary requests.\ntype invokemock func(in, out *dynamicpb.Message, opts ...grpc.CallOption) error\n\nfunc (im invokemock) Invoke(_ context.Context, _ string, payload any, reply any, opts ...grpc.CallOption) error {\n\tin, ok := payload.(*dynamicpb.Message)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for payload\")\n\t}\n\tout, ok := reply.(*dynamicpb.Message)\n\tif !ok {\n\t\treturn fmt.Errorf(\"unexpected type for reply\")\n\t}\n\treturn im(in, out, opts...)\n}\n\nfunc (invokemock) NewStream(_ context.Context, _ *grpc.StreamDesc, _ string, _ ...grpc.CallOption) (grpc.ClientStream, error) {\n\tpanic(\"not implemented\")\n}\n\nfunc (invokemock) Close() error {\n\treturn nil\n}\n"
  },
  {
    "path": "internal/lib/netext/grpcext/reflect.go",
    "content": "package grpcext\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/jhump/protoreflect/desc\" //nolint:staticcheck\n\t\"github.com/jhump/protoreflect/grpcreflect\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n)\n\n// ReflectionClient wraps a grpc.ServerReflectionClient.\ntype reflectionClient struct {\n\tConn grpc.ClientConnInterface\n}\n\n// Reflect will use the grpc reflection api to make the file descriptors available to request.\n// It is called in the connect function the first time the Client.Connect function is called.\nfunc (rc *reflectionClient) Reflect(ctx context.Context) (*descriptorpb.FileDescriptorSet, error) {\n\tclient := grpcreflect.NewClientAuto(ctx, rc.Conn)\n\tclient.AllowMissingFileDescriptors()\n\n\tservices, err := client.ListServices()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"can't list services: %w\", err)\n\t}\n\n\tseen := make(map[fileDescriptorLookupKey]bool, len(services))\n\tfdset := &descriptorpb.FileDescriptorSet{\n\t\tFile: make([]*descriptorpb.FileDescriptorProto, 0, len(services)),\n\t}\n\n\tfor _, srv := range services {\n\t\tsrvDescriptor, err := client.ResolveService(srv)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"can't get method on service %q: %w\", srv, err)\n\t\t}\n\n\t\tstack := []*desc.FileDescriptor{srvDescriptor.GetFile()}\n\n\t\tfor len(stack) > 0 {\n\t\t\tfdp := stack[len(stack)-1]\n\t\t\tstack = stack[:len(stack)-1]\n\n\t\t\tfdkey := fileDescriptorLookupKey{\n\t\t\t\tPackage: fdp.GetPackage(),\n\t\t\t\tName:    fdp.GetName(),\n\t\t\t}\n\n\t\t\tstack = append(stack, fdp.GetDependencies()...)\n\n\t\t\tif seen[fdkey] {\n\t\t\t\t// When a proto file contains declarations for multiple services\n\t\t\t\t// then the same proto file is returned multiple times,\n\t\t\t\t// this prevents adding the returned proto file as a duplicate.\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tseen[fdkey] = true\n\t\t\tfdset.File = append(fdset.File, fdp.AsFileDescriptorProto())\n\t\t}\n\t}\n\n\treturn fdset, nil\n}\n\ntype fileDescriptorLookupKey struct {\n\tPackage string\n\tName    string\n}\n"
  },
  {
    "path": "internal/lib/netext/grpcext/stream.go",
    "content": "package grpcext\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n\t\"google.golang.org/protobuf/types/known/emptypb\"\n)\n\n// Stream is the wrapper around the grpc.ClientStream\n// with some handy methods.\ntype Stream struct {\n\tmethod                 string\n\tmethodDescriptor       protoreflect.MethodDescriptor\n\tdiscardResponseMessage bool\n\traw                    grpc.ClientStream\n\tmarshaler              protojson.MarshalOptions\n\tunmarshaler            protojson.UnmarshalOptions\n}\n\n// ErrCanceled canceled by client (k6)\nvar ErrCanceled = errors.New(\"canceled by client (k6)\")\n\n// ReceiveConverted receives a converted message from the stream\n// if the stream has been closed successfully, it returns io.EOF\n// if the stream has been cancelled, it returns ErrCanceled\nfunc (s *Stream) ReceiveConverted() (any, error) {\n\traw, err := s.receive()\n\tif err != nil && !errors.Is(err, io.EOF) {\n\t\treturn nil, err\n\t}\n\n\tif s.discardResponseMessage {\n\t\treturn struct{}{}, err\n\t}\n\n\tmsg, errConv := convert(s.marshaler, raw)\n\tif errConv != nil {\n\t\treturn nil, errConv\n\t}\n\n\treturn msg, err\n}\n\nfunc (s *Stream) receive() (msg *dynamicpb.Message, err error) {\n\tif s.discardResponseMessage {\n\t\tmsg = dynamicpb.NewMessage((&emptypb.Empty{}).ProtoReflect().Descriptor())\n\t} else {\n\t\tmsg = dynamicpb.NewMessage(s.methodDescriptor.Output())\n\t}\n\n\terr = s.raw.RecvMsg(msg)\n\n\t// io.EOF means that the stream has been closed successfully\n\tif err == nil || errors.Is(err, io.EOF) {\n\t\treturn msg, err\n\t}\n\n\tsterr := status.Convert(err)\n\tif sterr.Code() == codes.Canceled {\n\t\treturn nil, ErrCanceled\n\t}\n\n\treturn nil, err\n}\n\n// convert converts the message to the interface{}\n// which could be returned to the JS\n// there is a lot of marshaling/unmarshaling here, but if we just pass the dynamic message\n// the default Marshaller would be used, which would strip any zero/default values from the JSON.\n// eg. given this message:\n//\n//\tmessage Point {\n//\t   double x = 1;\n//\t\t  double y = 2;\n//\t\t  double z = 3;\n//\t}\n//\n// and a value like this:\n// msg := Point{X: 6, Y: 4, Z: 0}\n// would result in JSON output:\n// {\"x\":6,\"y\":4}\n// rather than the desired:\n// {\"x\":6,\"y\":4,\"z\":0}\nfunc convert(marshaler protojson.MarshalOptions, msg *dynamicpb.Message) (any, error) {\n\t// TODO(olegbespalov): add the test that checks that message is not nil\n\n\traw, err := marshaler.Marshal(msg)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal the message: %w\", err)\n\t}\n\n\tvar back any\n\n\terr = json.Unmarshal(raw, &back)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal the message: %w\", err)\n\t}\n\n\treturn back, err\n}\n\n// CloseSend closes the stream\nfunc (s *Stream) CloseSend() error {\n\treturn s.raw.CloseSend()\n}\n\n// BuildMessage builds a message from the input\nfunc (s *Stream) buildMessage(b []byte) (*dynamicpb.Message, error) {\n\tmsg := dynamicpb.NewMessage(s.methodDescriptor.Input())\n\tif err := s.unmarshaler.Unmarshal(b, msg); err != nil {\n\t\treturn nil, fmt.Errorf(\"can't serialise request object to protocol buffer: %w\", err)\n\t}\n\n\treturn msg, nil\n}\n\n// Send sends the message to the stream\nfunc (s *Stream) Send(b []byte) error {\n\tmsg, err := s.buildMessage(b)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn s.raw.SendMsg(msg)\n}\n"
  },
  {
    "path": "internal/lib/strvals/doc.go",
    "content": "// Package strvals provides parsing utilities for strval lines, which follow\n// the format: name=value,topname.subname=value.\npackage strvals\n"
  },
  {
    "path": "internal/lib/strvals/parser.go",
    "content": "package strvals\n\nimport \"fmt\"\n\n// Token represents a key-value token.\ntype Token struct {\n\tKey, Value string\n\tinside     rune // shows whether it's inside a given collection, currently [ means it's an array\n}\n\ntype tokenizer struct {\n\ti          int\n\ts          string\n\tcurrentKey string\n}\n\nfunc (t *tokenizer) readKey() (string, error) {\n\tstart := t.i\n\tfor ; t.i < len(t.s); t.i++ {\n\t\tif t.s[t.i] == '=' && t.i != len(t.s)-1 {\n\t\t\tt.i++\n\n\t\t\treturn t.s[start : t.i-1], nil\n\t\t}\n\t\tif t.s[t.i] == ',' {\n\t\t\tk := t.s[start:t.i]\n\n\t\t\treturn k, fmt.Errorf(\"key `%s` with no value\", k)\n\t\t}\n\t}\n\n\ts := t.s[start:]\n\n\treturn s, fmt.Errorf(\"key `%s` with no value\", s)\n}\n\nfunc (t *tokenizer) readValue() string {\n\tstart := t.i\n\tfor ; t.i < len(t.s); t.i++ {\n\t\tif t.s[t.i] == ',' {\n\t\t\tt.i++\n\n\t\t\treturn t.s[start : t.i-1]\n\t\t}\n\t}\n\n\treturn t.s[start:]\n}\n\nfunc (t *tokenizer) readArray() (string, error) {\n\tstart := t.i\n\tfor ; t.i < len(t.s); t.i++ {\n\t\tif t.s[t.i] == ']' {\n\t\t\tif t.i+1 == len(t.s) || t.s[t.i+1] == ',' {\n\t\t\t\tt.i += 2\n\n\t\t\t\treturn t.s[start : t.i-2], nil\n\t\t\t}\n\t\t\tt.i++\n\n\t\t\treturn t.s[start : t.i-1], fmt.Errorf(\"there was no ',' after an array with key '%s'\", t.currentKey)\n\t\t}\n\t}\n\n\treturn t.s[start:], fmt.Errorf(\"array value for key `%s` didn't end\", t.currentKey)\n}\n\n// Parse parses the input string into key-value tokens following strvals format:\n// name=value,topname.subname=value.\nfunc Parse(s string) ([]Token, error) {\n\tresult := []Token{}\n\tt := &tokenizer{s: s}\n\n\tvar err error\n\tvar value string\n\tfor t.i < len(s) {\n\t\tt.currentKey, err = t.readKey()\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tif t.s[t.i] == '[' {\n\t\t\tt.i++\n\t\t\tvalue, err = t.readArray()\n\n\t\t\tresult = append(result, Token{\n\t\t\t\tKey:    t.currentKey,\n\t\t\t\tValue:  value,\n\t\t\t\tinside: '[',\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn result, err\n\t\t\t}\n\t\t} else {\n\t\t\tvalue = t.readValue()\n\t\t\tresult = append(result, Token{\n\t\t\t\tKey:   t.currentKey,\n\t\t\t\tValue: value,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/lib/strvals/parser_test.go",
    "content": "package strvals\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestParser(t *testing.T) {\n\tt.Parallel()\n\n\tinput := \"loki=something,s.e=2231,s=12,12=3,a=[1,2,3],b=[1],s=c\"\n\ttokens, err := Parse(input)\n\trequire.NoError(t, err)\n\n\texpected := []Token{\n\t\t{Key: \"loki\", Value: \"something\"},\n\t\t{Key: \"s.e\", Value: \"2231\"},\n\t\t{Key: \"s\", Value: \"12\"},\n\t\t{Key: \"12\", Value: \"3\"},\n\t\t{Key: \"a\", Value: \"1,2,3\", inside: '['},\n\t\t{Key: \"b\", Value: \"1\", inside: '['},\n\t\t{Key: \"s\", Value: \"c\"},\n\t}\n\tassert.Equal(t, expected, tokens)\n}\n\nfunc TestParserInvalid(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname     string\n\t\tinput    string\n\t\terrorMsg string\n\t}{\n\t\t{\n\t\t\tname:     \"empty value\",\n\t\t\tinput:    \"empty=\",\n\t\t\terrorMsg: \"key `empty=` with no value\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unclosed array\",\n\t\t\tinput:    \"foo=[1,2,3\",\n\t\t\terrorMsg: \"array value for key `foo` didn't end\",\n\t\t},\n\t\t{\n\t\t\tname:     \"bad characters after array\",\n\t\t\tinput:    \"foo=[1,2,3]bar\",\n\t\t\terrorMsg: \"there was no ',' after an array with key 'foo'\",\n\t\t},\n\t\t{\n\t\t\tname:     \"empty key\",\n\t\t\tinput:    \",foo=bar\",\n\t\t\terrorMsg: \"key `` with no value\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\t_, err := Parse(test.input)\n\t\t\trequire.EqualError(t, err, test.errorMsg)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/lib/summary/doc.go",
    "content": "// Package summary provides types and utility methods for the end-of-test summary.\npackage summary\n"
  },
  {
    "path": "internal/lib/summary/machine_readable.go",
    "content": "package summary\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/build\"\n\tmachinereadable \"go.k6.io/k6/internal/lib/summary/machinereadable\"\n\t\"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar (\n\terrUnsupportedMetricType     = errors.New(\"unsupported metric type\")\n\terrUnsupportedMetricContents = errors.New(\"unsupported metric contents\")\n)\n\n// ToMachineReadable takes a Summary and Meta and builds a machine-readable summary [machinereadable.Summary] from them.\nfunc ToMachineReadable(s *Summary, meta Meta) (machinereadable.Summary, error) {\n\treturn machinereadable.NewSummaryBuilder().\n\t\tConfig(machineReadableSummaryConfigBuilder(s, meta)).\n\t\tMetadata(machineReadableSummaryMetadataBuilder()).\n\t\tResults(machineReadableSummaryResultsBuilder(s)).\n\t\tVersion(machinereadable.SchemaVersion).\n\t\tBuild()\n}\n\nfunc machineReadableSummaryConfigBuilder(s *Summary, meta Meta) *machinereadable.SummarySummaryConfigBuilder {\n\texecutionType := machinereadable.SummarySummaryConfigExecutionLocal\n\tif meta.IsCloud {\n\t\texecutionType = machinereadable.SummarySummaryConfigExecutionCloud\n\t}\n\n\treturn machinereadable.NewSummarySummaryConfigBuilder().\n\t\tDuration(s.TestRunDuration.Seconds()).\n\t\tExecution(executionType).\n\t\tScript(meta.Script)\n}\n\nfunc machineReadableSummaryMetadataBuilder() *machinereadable.SummarySummaryMetadataBuilder {\n\treturn machinereadable.NewSummarySummaryMetadataBuilder().\n\t\tK6Version(build.Version).\n\t\tGeneratedAt(time.Now())\n}\n\nfunc machineReadableSummaryResultsBuilder(s *Summary) *machinereadable.SummarySummaryResultsBuilder {\n\treturn machinereadable.NewSummarySummaryResultsBuilder().\n\t\tChecks(machineReadableSummaryResultsChecksBuilder(s)).\n\t\tMetrics(machineReadableSummaryResultsMetricsBuilder(s.Metrics))\n}\n\nfunc machineReadableSummaryResultsChecksBuilder(s *Summary) *machinereadable.SummarySummaryResultsChecksBuilder {\n\tbuilder := machinereadable.NewSummarySummaryResultsChecksBuilder()\n\tif s.Checks == nil {\n\t\treturn builder\n\t}\n\n\treturn builder.\n\t\tMetrics([]cog.Builder[machinereadable.Metric]{\n\t\t\tmachineReadableMetricBuilder(s.Checks.Metrics.Total),\n\t\t\tmachineReadableMetricBuilder(s.Checks.Metrics.Fail),\n\t\t\tmachineReadableMetricBuilder(s.Checks.Metrics.Success),\n\t\t}).\n\t\tResults(machineReadableSummaryResultsChecksResultsBuilder(s.Checks))\n}\n\nfunc machineReadableSummaryResultsMetricsBuilder(metrics Metrics) []cog.Builder[machinereadable.Metric] {\n\t// We use reflection to traverse the entire struct, so if we ever add a new attribute\n\t// to the metric's struct, with a new category of metrics, we won't forget to add it here.\n\tval := reflect.ValueOf(metrics)\n\n\tmetricBuilders := make([]cog.Builder[machinereadable.Metric], 0)\n\tfor i := 0; i < val.NumField(); i++ {\n\t\tvalue := val.Field(i)\n\t\tmetricsMap, isMetricsMap := value.Interface().(map[string]Metric)\n\t\tif !isMetricsMap {\n\t\t\tcontinue // Theoretically, this should never happen as all the struct fields satisfy the type.\n\t\t}\n\n\t\tfor _, m := range metricsMap {\n\t\t\tmetricBuilders = append(metricBuilders, machineReadableMetricBuilder(m))\n\t\t}\n\t}\n\treturn metricBuilders\n}\n\nfunc machineReadableSummaryResultsChecksResultsBuilder(\n\tchecks *Checks,\n) []cog.Builder[machinereadable.SummarySummaryResultsChecksResults] {\n\tif checks == nil || len(checks.OrderedChecks) == 0 {\n\t\treturn nil\n\t}\n\n\tbuilders := make(\n\t\t[]cog.Builder[machinereadable.SummarySummaryResultsChecksResults], 0, len(checks.OrderedChecks),\n\t)\n\tfor _, c := range checks.OrderedChecks {\n\t\tbuilders = append(builders, machinereadable.NewSummarySummaryResultsChecksResultsBuilder().\n\t\t\tName(c.Name).\n\t\t\tPasses(c.Passes).\n\t\t\tFails(c.Fails))\n\t}\n\treturn builders\n}\n\nfunc machineReadableMetricBuilder(m Metric) *machinereadable.MetricBuilder {\n\tbuilder := machinereadable.NewMetricBuilder().Name(m.Name)\n\n\tif mType, err := machineReadableMetricType(m.Type); err == nil {\n\t\tbuilder = builder.Type(mType)\n\t}\n\n\tif mContains, err := machineReadableMetricContains(m.Contains); err == nil {\n\t\tbuilder = builder.Contains(mContains)\n\t}\n\n\tif mValues, err := machineReadableMetricValues(m); err == nil {\n\t\tbuilder = builder.Values(mValues)\n\t}\n\n\treturn builder\n}\n\nfunc machineReadableMetricType(mType string) (machinereadable.MetricType, error) {\n\tswitch mType {\n\tcase string(machinereadable.MetricTypeCounter):\n\t\treturn machinereadable.MetricTypeCounter, nil\n\tcase string(machinereadable.MetricTypeGauge):\n\t\treturn machinereadable.MetricTypeGauge, nil\n\tcase string(machinereadable.MetricTypeRate):\n\t\treturn machinereadable.MetricTypeRate, nil\n\tcase string(machinereadable.MetricTypeTrend):\n\t\treturn machinereadable.MetricTypeTrend, nil\n\tdefault:\n\t\treturn \"\", errUnsupportedMetricType\n\t}\n}\n\nfunc machineReadableMetricContains(mContains string) (machinereadable.MetricContains, error) {\n\tswitch mContains {\n\tcase string(machinereadable.MetricContainsDefault):\n\t\treturn machinereadable.MetricContainsDefault, nil\n\tcase string(machinereadable.MetricContainsTime):\n\t\treturn machinereadable.MetricContainsTime, nil\n\tcase string(machinereadable.MetricContainsData):\n\t\treturn machinereadable.MetricContainsData, nil\n\tdefault:\n\t\treturn \"\", errUnsupportedMetricContents\n\t}\n}\n\nfunc machineReadableMetricValues(m Metric) (any, error) {\n\tswitch m.Type {\n\tcase string(machinereadable.MetricTypeCounter):\n\t\treturn machinereadable.CounterValues{\n\t\t\tCount: m.Values[\"count\"],\n\t\t}, nil\n\tcase string(machinereadable.MetricTypeGauge):\n\t\treturn machinereadable.GaugeValues{\n\t\t\tMax:   m.Values[\"max\"],\n\t\t\tMin:   m.Values[\"min\"],\n\t\t\tValue: m.Values[\"value\"],\n\t\t}, nil\n\tcase string(machinereadable.MetricTypeRate):\n\t\treturn machinereadable.RateValues{\n\t\t\tMatches: int64(m.Values[\"passes\"]),\n\t\t\tTotal:   int64(m.Values[\"passes\"] + m.Values[\"fails\"]),\n\t\t\tRate:    m.Values[\"rate\"],\n\t\t}, nil\n\tcase string(machinereadable.MetricTypeTrend):\n\t\tvar values machinereadable.TrendValues\n\t\tif avgVal, ok := m.Values[\"avg\"]; ok {\n\t\t\tvalues.Avg = &avgVal\n\t\t}\n\t\tif maxVal, ok := m.Values[\"max\"]; ok {\n\t\t\tvalues.Max = &maxVal\n\t\t}\n\t\tif medVal, ok := m.Values[\"med\"]; ok {\n\t\t\tvalues.Med = &medVal\n\t\t}\n\t\tif minVal, ok := m.Values[\"min\"]; ok {\n\t\t\tvalues.Min = &minVal\n\t\t}\n\t\tif p90Val, ok := m.Values[\"p(90)\"]; ok {\n\t\t\tvalues.P90 = &p90Val\n\t\t}\n\t\tif p95Val, ok := m.Values[\"p(95)\"]; ok {\n\t\t\tvalues.P95 = &p95Val\n\t\t}\n\t\treturn values, nil\n\tdefault:\n\t\treturn nil, errUnsupportedMetricType\n\t}\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/checkout.sh",
    "content": "#!/bin/sh -e\n\nsha=e49468be9020f95472c4b7ec51cef179b4fdd1ca # this is just the commit it was last tested with\n\nSCRIPT_DIR=\"$(CDPATH= cd -- \"$(dirname -- \"$0\")\" && pwd)\"\n\nmkdir -p \"$SCRIPT_DIR/k6-summary\"\ncd \"$SCRIPT_DIR/k6-summary\"\n\ngit init\ngit remote add origin https://github.com/grafana/k6-summary\ngit fetch origin --depth=1 \"${sha}\"\ngit reset --hard \"${sha}\"\n\ncd -\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/clean.sh",
    "content": "#!/bin/sh -e\n\nSCRIPT_DIR=\"$(CDPATH= cd -- \"$(dirname -- \"$0\")\" && pwd)\"\n\n# Remove the cog-generated files\nfind \"$SCRIPT_DIR\" -maxdepth 1 -type f -name '*.go' -exec rm -f {} \\;\nrm -rf \"$SCRIPT_DIR/cog\"\nrm -rf \"$SCRIPT_DIR/docs\"\n\n# Remove the schemas repository\nrm -rf \"$SCRIPT_DIR/k6-summary\"\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/cog/builder.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoRuntime\n\npackage cog\n\ntype Builder[ResourceT any] interface {\n\tBuild() (ResourceT, error)\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/cog/errors.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoRuntime\n\npackage cog\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\ntype BuildErrors []*BuildError\n\nfunc (errs BuildErrors) Error() string {\n\tvar b []byte\n\tfor i, err := range errs {\n\t\tif i > 0 {\n\t\t\tb = append(b, '\\n')\n\t\t}\n\t\tb = append(b, err.Error()...)\n\t}\n\treturn string(b)\n}\n\ntype BuildError struct {\n\tPath    string\n\tMessage string\n}\n\nfunc (err *BuildError) Error() string {\n\treturn fmt.Sprintf(\"%s: %s\", err.Path, err.Message)\n}\n\nfunc MakeBuildErrors(rootPath string, err error) BuildErrors {\n\tvar buildErrs BuildErrors\n\tif errors.As(err, &buildErrs) {\n\t\tfor _, buildErr := range buildErrs {\n\t\t\tbuildErr.Path = rootPath + \".\" + buildErr.Path\n\t\t}\n\n\t\treturn buildErrs\n\t}\n\n\tvar buildErr *BuildError\n\tif errors.As(err, &buildErr) {\n\t\treturn BuildErrors{buildErr}\n\t}\n\n\treturn BuildErrors{&BuildError{\n\t\tPath:    rootPath,\n\t\tMessage: err.Error(),\n\t}}\n}\n\nfunc ToPtr[T any](v T) *T {\n\treturn &v\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/cog-templates/schema_version_const.go.tmpl",
    "content": "{{- $pkg := default \"main\" (index .Packages 0) }}\npackage {{ $pkg }}\n\n// SchemaVersion holds the schema version used to generate the code in this package.\nconst SchemaVersion = \"{{ .Extra.SchemaVersion }}\"\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/cog.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/pipeline.json\n\ndebug: true\n\nparameters:\n    cog_version: 'v0.0.x'\n    schema_version: '1.0.0'\n    go_package_root: 'go.k6.io/k6/internal/lib/summary/machinereadable'\n\ninputs:\n    - jsonschema:\n          path: '%__config_dir%/k6-summary/schemas/summary/%schema_version%/schema.json'\n          package: summary\n\noutput:\n    directory: '%__config_dir%'\n\n    types: true\n    builders: true\n    converters: false\n    api_reference: true\n\n    templates_data:\n        SchemaVersion: '%schema_version%'\n\n    languages:\n        - go:\n              generate_json_marshaller: true\n              generate_strict_unmarshaller: true\n              generate_equal: true\n              generate_validate: true\n              package_root: '%go_package_root%'\n              extra_files_templates:\n                  - '%__config_dir%/cog-templates'\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/countervalues_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[CounterValues] = (*CounterValuesBuilder)(nil)\n\ntype CounterValuesBuilder struct {\n\tinternal *CounterValues\n\terrors   cog.BuildErrors\n}\n\nfunc NewCounterValuesBuilder() *CounterValuesBuilder {\n\tresource := NewCounterValues()\n\tbuilder := &CounterValuesBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *CounterValuesBuilder) Build() (CounterValues, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn CounterValues{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn CounterValues{}, cog.MakeBuildErrors(\"summary.counterValues\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Total count of events\nfunc (builder *CounterValuesBuilder) Count(count float64) *CounterValuesBuilder {\n\tbuilder.internal.Count = count\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/gaugevalues_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[GaugeValues] = (*GaugeValuesBuilder)(nil)\n\ntype GaugeValuesBuilder struct {\n\tinternal *GaugeValues\n\terrors   cog.BuildErrors\n}\n\nfunc NewGaugeValuesBuilder() *GaugeValuesBuilder {\n\tresource := NewGaugeValues()\n\tbuilder := &GaugeValuesBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *GaugeValuesBuilder) Build() (GaugeValues, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn GaugeValues{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn GaugeValues{}, cog.MakeBuildErrors(\"summary.gaugeValues\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Maximum observed value\nfunc (builder *GaugeValuesBuilder) Max(max float64) *GaugeValuesBuilder {\n\tbuilder.internal.Max = max\n\n\treturn builder\n}\n\n// Minimum observed value\nfunc (builder *GaugeValuesBuilder) Min(min float64) *GaugeValuesBuilder {\n\tbuilder.internal.Min = min\n\n\treturn builder\n}\n\n// Current/final gauge value\nfunc (builder *GaugeValuesBuilder) Value(value float64) *GaugeValuesBuilder {\n\tbuilder.internal.Value = value\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/generate.sh",
    "content": "#!/bin/sh -e\n\nSCRIPT_DIR=\"$(CDPATH= cd -- \"$(dirname -- \"$0\")\" && pwd)\"\n\nif [ ! -d \"$SCRIPT_DIR/k6-summary/.git\" ]; then\n    echo \"❌ Schemas repository not found in $SCRIPT_DIR/k6-summary.\"\n    echo \"Please run the checkout script first:\"\n    echo \"  $SCRIPT_DIR/checkout.sh\"\n    exit 1\nfi\n\nif ! command -v cog >/dev/null 2>&1; then\n    echo \"❌ 'cog' CLI not found\"\n    echo \"\"\n    echo \"Please install the binary from GitHub Releases:\"\n    echo \"  https://github.com/grafana/cog/releases\"\n    echo \"\"\n    exit 1\nfi\n\n# We use Go templates file extension convention to avoid issues with the linter,\n# as `cog` templates have invalid Go syntax (i.e. templating syntax).\n# But looks like `cog` expects `.go` files, so we rename them right before code-generation.\nfind \"$SCRIPT_DIR/cog-templates/\" -name \"*.go.tmpl\" -exec bash -c 'mv \"$1\" \"${1%.go.tmpl}.go\"' _ {} \\;\n\n# Run `cog` to generate the source code from the checked out schemas.\ncog generate --config \"$SCRIPT_DIR/cog.yaml\"\n\n# Then we leave the `cog` templates back to their original state.\nfind \"$SCRIPT_DIR/cog-templates/\" -name \"*.go\" -exec bash -c 'mv \"$1\" \"$1.tmpl\"' _ {} \\;\n\n# Move the Go files from the package directory to root (cwd)\nSRC_DIR=\"$SCRIPT_DIR/summary\"\nfind \"$SRC_DIR\" -maxdepth 1 -type f -name '*.go' ! -name '.*' -exec mv -f {} \"$SCRIPT_DIR\" \\;\nrm -rf \"$SRC_DIR\"\n\n# Remote the docs generated by `cog`, as we don't want them for now.\nrm -rf \"$SCRIPT_DIR/docs\"\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/metric_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[Metric] = (*MetricBuilder)(nil)\n\ntype MetricBuilder struct {\n\tinternal *Metric\n\terrors   cog.BuildErrors\n}\n\nfunc NewMetricBuilder() *MetricBuilder {\n\tresource := NewMetric()\n\tbuilder := &MetricBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *MetricBuilder) Build() (Metric, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn Metric{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn Metric{}, cog.MakeBuildErrors(\"summary.metric\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// The type of data the metric contains\nfunc (builder *MetricBuilder) Contains(contains MetricContains /* AnonymousEnumToExplicitType */) *MetricBuilder {\n\tbuilder.internal.Contains = contains\n\n\treturn builder\n}\n\n// The metric name\nfunc (builder *MetricBuilder) Name(name string) *MetricBuilder {\n\tbuilder.internal.Name = name\n\n\treturn builder\n}\n\n// The metric type\nfunc (builder *MetricBuilder) Type(typeArg MetricType /* AnonymousEnumToExplicitType */) *MetricBuilder {\n\tbuilder.internal.Type = typeArg\n\n\treturn builder\n}\n\nfunc (builder *MetricBuilder) Values(values any /* UndiscriminatedDisjunctionToAny */) *MetricBuilder {\n\tbuilder.internal.Values = values\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/ratevalues_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[RateValues] = (*RateValuesBuilder)(nil)\n\ntype RateValuesBuilder struct {\n\tinternal *RateValues\n\terrors   cog.BuildErrors\n}\n\nfunc NewRateValuesBuilder() *RateValuesBuilder {\n\tresource := NewRateValues()\n\tbuilder := &RateValuesBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *RateValuesBuilder) Build() (RateValues, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn RateValues{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn RateValues{}, cog.MakeBuildErrors(\"summary.rateValues\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Number of 'true' events, i.e. occurrences of the event reflected by the metric\nfunc (builder *RateValuesBuilder) Matches(matches int64) *RateValuesBuilder {\n\tbuilder.internal.Matches = matches\n\n\treturn builder\n}\n\n// Proportion of true events, calculated true / total (value between 0 and 1)\nfunc (builder *RateValuesBuilder) Rate(rate float64) *RateValuesBuilder {\n\tbuilder.internal.Rate = rate\n\n\treturn builder\n}\n\n// Total number of events (true and non-true)\nfunc (builder *RateValuesBuilder) Total(total int64) *RateValuesBuilder {\n\tbuilder.internal.Total = total\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/schema_version_const.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     CustomTemplates\n\npackage summary\n\n// SchemaVersion holds the schema version used to generate the code in this package.\nconst SchemaVersion = \"1.0.0\"\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/summary_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[Summary] = (*SummaryBuilder)(nil)\n\ntype SummaryBuilder struct {\n\tinternal *Summary\n\terrors   cog.BuildErrors\n}\n\nfunc NewSummaryBuilder() *SummaryBuilder {\n\tresource := NewSummary()\n\tbuilder := &SummaryBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *SummaryBuilder) Build() (Summary, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn Summary{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn Summary{}, cog.MakeBuildErrors(\"summary.summary\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Configuration information about the test execution\nfunc (builder *SummaryBuilder) Config(config cog.Builder[SummarySummaryConfig]) *SummaryBuilder {\n\tconfigResource, err := config.Build()\n\tif err != nil {\n\t\tbuilder.errors = append(builder.errors, err.(cog.BuildErrors)...)\n\t\treturn builder\n\t}\n\tbuilder.internal.Config = configResource\n\n\treturn builder\n}\n\n// Metadata about the summary generation\nfunc (builder *SummaryBuilder) Metadata(metadata cog.Builder[SummarySummaryMetadata]) *SummaryBuilder {\n\tmetadataResource, err := metadata.Build()\n\tif err != nil {\n\t\tbuilder.errors = append(builder.errors, err.(cog.BuildErrors)...)\n\t\treturn builder\n\t}\n\tbuilder.internal.Metadata = metadataResource\n\n\treturn builder\n}\n\n// Test execution results data\nfunc (builder *SummaryBuilder) Results(results cog.Builder[SummarySummaryResults]) *SummaryBuilder {\n\tresultsResource, err := results.Build()\n\tif err != nil {\n\t\tbuilder.errors = append(builder.errors, err.(cog.BuildErrors)...)\n\t\treturn builder\n\t}\n\tbuilder.internal.Results = resultsResource\n\n\treturn builder\n}\n\n// Schema version in semver 2.0 format (e.g., '1.0.0')\nfunc (builder *SummaryBuilder) Version(version SemVer) *SummaryBuilder {\n\tbuilder.internal.Version = version\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/summarysummaryconfig_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[SummarySummaryConfig] = (*SummarySummaryConfigBuilder)(nil)\n\ntype SummarySummaryConfigBuilder struct {\n\tinternal *SummarySummaryConfig\n\terrors   cog.BuildErrors\n}\n\nfunc NewSummarySummaryConfigBuilder() *SummarySummaryConfigBuilder {\n\tresource := NewSummarySummaryConfig()\n\tbuilder := &SummarySummaryConfigBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *SummarySummaryConfigBuilder) Build() (SummarySummaryConfig, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn SummarySummaryConfig{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn SummarySummaryConfig{}, cog.MakeBuildErrors(\"summary.summarySummaryConfig\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Test run duration in seconds\nfunc (builder *SummarySummaryConfigBuilder) Duration(duration float64) *SummarySummaryConfigBuilder {\n\tbuilder.internal.Duration = duration\n\n\treturn builder\n}\n\n// Type of execution (local or cloud)\nfunc (builder *SummarySummaryConfigBuilder) Execution(execution SummarySummaryConfigExecution /* AnonymousEnumToExplicitType */) *SummarySummaryConfigBuilder {\n\tbuilder.internal.Execution = execution\n\n\treturn builder\n}\n\n// Path or name of the test script\nfunc (builder *SummarySummaryConfigBuilder) Script(script string) *SummarySummaryConfigBuilder {\n\tbuilder.internal.Script = &script\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/summarysummarymetadata_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\t\"time\"\n\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[SummarySummaryMetadata] = (*SummarySummaryMetadataBuilder)(nil)\n\ntype SummarySummaryMetadataBuilder struct {\n\tinternal *SummarySummaryMetadata\n\terrors   cog.BuildErrors\n}\n\nfunc NewSummarySummaryMetadataBuilder() *SummarySummaryMetadataBuilder {\n\tresource := NewSummarySummaryMetadata()\n\tbuilder := &SummarySummaryMetadataBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *SummarySummaryMetadataBuilder) Build() (SummarySummaryMetadata, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn SummarySummaryMetadata{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn SummarySummaryMetadata{}, cog.MakeBuildErrors(\"summary.summarySummaryMetadata\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// RFC3339 timestamp when summary was generated\nfunc (builder *SummarySummaryMetadataBuilder) GeneratedAt(generatedAt time.Time) *SummarySummaryMetadataBuilder {\n\tbuilder.internal.GeneratedAt = generatedAt\n\n\treturn builder\n}\n\n// Version of k6 that generated this summary\nfunc (builder *SummarySummaryMetadataBuilder) K6Version(k6Version SemVer) *SummarySummaryMetadataBuilder {\n\tbuilder.internal.K6Version = k6Version\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/summarysummaryresults_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[SummarySummaryResults] = (*SummarySummaryResultsBuilder)(nil)\n\ntype SummarySummaryResultsBuilder struct {\n\tinternal *SummarySummaryResults\n\terrors   cog.BuildErrors\n}\n\nfunc NewSummarySummaryResultsBuilder() *SummarySummaryResultsBuilder {\n\tresource := NewSummarySummaryResults()\n\tbuilder := &SummarySummaryResultsBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *SummarySummaryResultsBuilder) Build() (SummarySummaryResults, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn SummarySummaryResults{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn SummarySummaryResults{}, cog.MakeBuildErrors(\"summary.summarySummaryResults\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Check execution results\nfunc (builder *SummarySummaryResultsBuilder) Checks(checks cog.Builder[SummarySummaryResultsChecks]) *SummarySummaryResultsBuilder {\n\tchecksResource, err := checks.Build()\n\tif err != nil {\n\t\tbuilder.errors = append(builder.errors, err.(cog.BuildErrors)...)\n\t\treturn builder\n\t}\n\tbuilder.internal.Checks = &checksResource\n\n\treturn builder\n}\n\n// Array of all metrics from the test execution\nfunc (builder *SummarySummaryResultsBuilder) Metrics(metrics []cog.Builder[Metric]) *SummarySummaryResultsBuilder {\n\tmetricsResources := make([]Metric, 0, len(metrics))\n\tfor _, r1 := range metrics {\n\t\tmetricsDepth1, err := r1.Build()\n\t\tif err != nil {\n\t\t\tbuilder.errors = append(builder.errors, err.(cog.BuildErrors)...)\n\t\t\treturn builder\n\t\t}\n\t\tmetricsResources = append(metricsResources, metricsDepth1)\n\t}\n\tbuilder.internal.Metrics = metricsResources\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/summarysummaryresultschecks_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[SummarySummaryResultsChecks] = (*SummarySummaryResultsChecksBuilder)(nil)\n\ntype SummarySummaryResultsChecksBuilder struct {\n\tinternal *SummarySummaryResultsChecks\n\terrors   cog.BuildErrors\n}\n\nfunc NewSummarySummaryResultsChecksBuilder() *SummarySummaryResultsChecksBuilder {\n\tresource := NewSummarySummaryResultsChecks()\n\tbuilder := &SummarySummaryResultsChecksBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *SummarySummaryResultsChecksBuilder) Build() (SummarySummaryResultsChecks, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn SummarySummaryResultsChecks{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn SummarySummaryResultsChecks{}, cog.MakeBuildErrors(\"summary.summarySummaryResultsChecks\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Array of check-related metrics\nfunc (builder *SummarySummaryResultsChecksBuilder) Metrics(metrics []cog.Builder[Metric]) *SummarySummaryResultsChecksBuilder {\n\tmetricsResources := make([]Metric, 0, len(metrics))\n\tfor _, r1 := range metrics {\n\t\tmetricsDepth1, err := r1.Build()\n\t\tif err != nil {\n\t\t\tbuilder.errors = append(builder.errors, err.(cog.BuildErrors)...)\n\t\t\treturn builder\n\t\t}\n\t\tmetricsResources = append(metricsResources, metricsDepth1)\n\t}\n\tbuilder.internal.Metrics = metricsResources\n\n\treturn builder\n}\n\n// Individual check results in execution order\nfunc (builder *SummarySummaryResultsChecksBuilder) Results(results []cog.Builder[SummarySummaryResultsChecksResults]) *SummarySummaryResultsChecksBuilder {\n\tresultsResources := make([]SummarySummaryResultsChecksResults, 0, len(results))\n\tfor _, r1 := range results {\n\t\tresultsDepth1, err := r1.Build()\n\t\tif err != nil {\n\t\t\tbuilder.errors = append(builder.errors, err.(cog.BuildErrors)...)\n\t\t\treturn builder\n\t\t}\n\t\tresultsResources = append(resultsResources, resultsDepth1)\n\t}\n\tbuilder.internal.Results = resultsResources\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/summarysummaryresultschecksresults_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[SummarySummaryResultsChecksResults] = (*SummarySummaryResultsChecksResultsBuilder)(nil)\n\ntype SummarySummaryResultsChecksResultsBuilder struct {\n\tinternal *SummarySummaryResultsChecksResults\n\terrors   cog.BuildErrors\n}\n\nfunc NewSummarySummaryResultsChecksResultsBuilder() *SummarySummaryResultsChecksResultsBuilder {\n\tresource := NewSummarySummaryResultsChecksResults()\n\tbuilder := &SummarySummaryResultsChecksResultsBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *SummarySummaryResultsChecksResultsBuilder) Build() (SummarySummaryResultsChecksResults, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn SummarySummaryResultsChecksResults{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn SummarySummaryResultsChecksResults{}, cog.MakeBuildErrors(\"summary.summarySummaryResultsChecksResults\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Number of times the check failed\nfunc (builder *SummarySummaryResultsChecksResultsBuilder) Fails(fails int64) *SummarySummaryResultsChecksResultsBuilder {\n\tbuilder.internal.Fails = fails\n\n\treturn builder\n}\n\n// Check name\nfunc (builder *SummarySummaryResultsChecksResultsBuilder) Name(name string) *SummarySummaryResultsChecksResultsBuilder {\n\tbuilder.internal.Name = name\n\n\treturn builder\n}\n\n// Number of times the check passed\nfunc (builder *SummarySummaryResultsChecksResultsBuilder) Passes(passes int64) *SummarySummaryResultsChecksResultsBuilder {\n\tbuilder.internal.Passes = passes\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/trendvalues_builder_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoBuilder\n\npackage summary\n\nimport (\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\nvar _ cog.Builder[TrendValues] = (*TrendValuesBuilder)(nil)\n\ntype TrendValuesBuilder struct {\n\tinternal *TrendValues\n\terrors   cog.BuildErrors\n}\n\nfunc NewTrendValuesBuilder() *TrendValuesBuilder {\n\tresource := NewTrendValues()\n\tbuilder := &TrendValuesBuilder{\n\t\tinternal: resource,\n\t\terrors:   make(cog.BuildErrors, 0),\n\t}\n\n\treturn builder\n}\n\nfunc (builder *TrendValuesBuilder) Build() (TrendValues, error) {\n\tif err := builder.internal.Validate(); err != nil {\n\t\treturn TrendValues{}, err\n\t}\n\n\tif len(builder.errors) > 0 {\n\t\treturn TrendValues{}, cog.MakeBuildErrors(\"summary.trendValues\", builder.errors)\n\t}\n\n\treturn *builder.internal, nil\n}\n\n// Average (mean) value\nfunc (builder *TrendValuesBuilder) Avg(avg float64) *TrendValuesBuilder {\n\tbuilder.internal.Avg = &avg\n\n\treturn builder\n}\n\n// Maximum value\nfunc (builder *TrendValuesBuilder) Max(max float64) *TrendValuesBuilder {\n\tbuilder.internal.Max = &max\n\n\treturn builder\n}\n\n// Median value\nfunc (builder *TrendValuesBuilder) Med(med float64) *TrendValuesBuilder {\n\tbuilder.internal.Med = &med\n\n\treturn builder\n}\n\n// Minimum value\nfunc (builder *TrendValuesBuilder) Min(min float64) *TrendValuesBuilder {\n\tbuilder.internal.Min = &min\n\n\treturn builder\n}\n\n// 90th percentile\nfunc (builder *TrendValuesBuilder) P90(p90 float64) *TrendValuesBuilder {\n\tbuilder.internal.P90 = &p90\n\n\treturn builder\n}\n\n// 95th percentile\nfunc (builder *TrendValuesBuilder) P95(p95 float64) *TrendValuesBuilder {\n\tbuilder.internal.P95 = &p95\n\n\treturn builder\n}\n"
  },
  {
    "path": "internal/lib/summary/machinereadable/types_gen.go",
    "content": "// Code generated - EDITING IS FUTILE. DO NOT EDIT.\n//\n// Using jennies:\n//     GoRawTypes\n\npackage summary\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"time\"\n\n\tcog \"go.k6.io/k6/internal/lib/summary/machinereadable/cog\"\n)\n\ntype CounterValues struct {\n\t// Total count of events\n\tCount float64 `json:\"count\"`\n}\n\n// NewCounterValues creates a new CounterValues object.\nfunc NewCounterValues() *CounterValues {\n\treturn &CounterValues{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `CounterValues` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *CounterValues) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"count\"\n\tif fields[\"count\"] != nil {\n\t\tif string(fields[\"count\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"count\"], &resource.Count); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"count\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"count\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"count\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"count\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"CounterValues\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `CounterValues` objects.\nfunc (resource CounterValues) Equals(other CounterValues) bool {\n\tif resource.Count != other.Count {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `CounterValues` fields for violations and returns them.\nfunc (resource CounterValues) Validate() error {\n\tvar errs cog.BuildErrors\n\tif !(resource.Count >= 0) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"count\",\n\t\t\terrors.New(\"must be >= 0\"),\n\t\t)...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\ntype GaugeValues struct {\n\t// Maximum observed value\n\tMax float64 `json:\"max\"`\n\t// Minimum observed value\n\tMin float64 `json:\"min\"`\n\t// Current/final gauge value\n\tValue float64 `json:\"value\"`\n}\n\n// NewGaugeValues creates a new GaugeValues object.\nfunc NewGaugeValues() *GaugeValues {\n\treturn &GaugeValues{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `GaugeValues` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *GaugeValues) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"max\"\n\tif fields[\"max\"] != nil {\n\t\tif string(fields[\"max\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"max\"], &resource.Max); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"max\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"max\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"max\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"max\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"min\"\n\tif fields[\"min\"] != nil {\n\t\tif string(fields[\"min\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"min\"], &resource.Min); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"min\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"min\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"min\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"min\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"value\"\n\tif fields[\"value\"] != nil {\n\t\tif string(fields[\"value\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"value\"], &resource.Value); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"value\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"value\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"value\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"value\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"GaugeValues\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `GaugeValues` objects.\nfunc (resource GaugeValues) Equals(other GaugeValues) bool {\n\tif resource.Max != other.Max {\n\t\treturn false\n\t}\n\tif resource.Min != other.Min {\n\t\treturn false\n\t}\n\tif resource.Value != other.Value {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `GaugeValues` fields for violations and returns them.\nfunc (resource GaugeValues) Validate() error {\n\treturn nil\n}\n\ntype Metric struct {\n\t// The type of data the metric contains\n\tContains MetricContains/* AnonymousEnumToExplicitType */ `json:\"contains\"`\n\t// The metric name\n\tName string `json:\"name\"`\n\t// The metric type\n\tType   MetricType/* AnonymousEnumToExplicitType */ `json:\"type\"`\n\tValues any/* UndiscriminatedDisjunctionToAny */ `json:\"values\"`\n}\n\n// NewMetric creates a new Metric object.\nfunc NewMetric() *Metric {\n\treturn &Metric{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `Metric` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *Metric) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"contains\"\n\tif fields[\"contains\"] != nil {\n\t\tif string(fields[\"contains\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"contains\"], &resource.Contains); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"contains\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"contains\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"contains\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"contains\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"name\"\n\tif fields[\"name\"] != nil {\n\t\tif string(fields[\"name\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"name\"], &resource.Name); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"name\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"name\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"name\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"name\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"type\"\n\tif fields[\"type\"] != nil {\n\t\tif string(fields[\"type\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"type\"], &resource.Type); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"type\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"type\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"type\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"type\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"values\"\n\tif fields[\"values\"] != nil {\n\t\tif string(fields[\"values\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"values\"], &resource.Values); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"values\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"values\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"values\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"values\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"Metric\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `Metric` objects.\nfunc (resource Metric) Equals(other Metric) bool {\n\tif resource.Contains != other.Contains {\n\t\treturn false\n\t}\n\tif resource.Name != other.Name {\n\t\treturn false\n\t}\n\tif resource.Type != other.Type {\n\t\treturn false\n\t}\n\t// is DeepEqual good enough here?\n\tif !reflect.DeepEqual(resource.Values, other.Values) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `Metric` fields for violations and returns them.\nfunc (resource Metric) Validate() error {\n\treturn nil\n}\n\ntype RateValues struct {\n\t// Number of 'true' events, i.e. occurrences of the event reflected by the metric\n\tMatches int64 `json:\"matches\"`\n\t// Proportion of true events, calculated true / total (value between 0 and 1)\n\tRate float64 `json:\"rate\"`\n\t// Total number of events (true and non-true)\n\tTotal int64 `json:\"total\"`\n}\n\n// NewRateValues creates a new RateValues object.\nfunc NewRateValues() *RateValues {\n\treturn &RateValues{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `RateValues` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *RateValues) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"matches\"\n\tif fields[\"matches\"] != nil {\n\t\tif string(fields[\"matches\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"matches\"], &resource.Matches); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"matches\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"matches\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"matches\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"matches\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"rate\"\n\tif fields[\"rate\"] != nil {\n\t\tif string(fields[\"rate\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"rate\"], &resource.Rate); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"rate\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"rate\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"rate\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"rate\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"total\"\n\tif fields[\"total\"] != nil {\n\t\tif string(fields[\"total\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"total\"], &resource.Total); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"total\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"total\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"total\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"total\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"RateValues\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `RateValues` objects.\nfunc (resource RateValues) Equals(other RateValues) bool {\n\tif resource.Matches != other.Matches {\n\t\treturn false\n\t}\n\tif resource.Rate != other.Rate {\n\t\treturn false\n\t}\n\tif resource.Total != other.Total {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `RateValues` fields for violations and returns them.\nfunc (resource RateValues) Validate() error {\n\tvar errs cog.BuildErrors\n\tif !(resource.Matches >= 0) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"matches\",\n\t\t\terrors.New(\"must be >= 0\"),\n\t\t)...)\n\t}\n\tif !(resource.Rate >= 0) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"rate\",\n\t\t\terrors.New(\"must be >= 0\"),\n\t\t)...)\n\t}\n\tif !(resource.Rate <= 1) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"rate\",\n\t\t\terrors.New(\"must be <= 1\"),\n\t\t)...)\n\t}\n\tif !(resource.Total >= 0) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"total\",\n\t\t\terrors.New(\"must be >= 0\"),\n\t\t)...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\ntype SemVer string\n\ntype TrendValues struct {\n\t// Average (mean) value\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tAvg *float64 `json:\"avg,omitempty\"`\n\t// Maximum value\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tMax *float64 `json:\"max,omitempty\"`\n\t// Median value\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tMed *float64 `json:\"med,omitempty\"`\n\t// Minimum value\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tMin *float64 `json:\"min,omitempty\"`\n\t// 90th percentile\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tP90 *float64 `json:\"p(90),omitempty\"`\n\t// 95th percentile\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tP95 *float64 `json:\"p(95),omitempty\"`\n}\n\n// NewTrendValues creates a new TrendValues object.\nfunc NewTrendValues() *TrendValues {\n\treturn &TrendValues{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `TrendValues` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *TrendValues) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"avg\"\n\tif fields[\"avg\"] != nil {\n\t\tif string(fields[\"avg\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"avg\"], &resource.Avg); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"avg\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"avg\")\n\n\t}\n\t// Field \"max\"\n\tif fields[\"max\"] != nil {\n\t\tif string(fields[\"max\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"max\"], &resource.Max); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"max\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"max\")\n\n\t}\n\t// Field \"med\"\n\tif fields[\"med\"] != nil {\n\t\tif string(fields[\"med\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"med\"], &resource.Med); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"med\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"med\")\n\n\t}\n\t// Field \"min\"\n\tif fields[\"min\"] != nil {\n\t\tif string(fields[\"min\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"min\"], &resource.Min); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"min\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"min\")\n\n\t}\n\t// Field \"p(90)\"\n\tif fields[\"p(90)\"] != nil {\n\t\tif string(fields[\"p(90)\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"p(90)\"], &resource.P90); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"p(90)\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"p(90)\")\n\n\t}\n\t// Field \"p(95)\"\n\tif fields[\"p(95)\"] != nil {\n\t\tif string(fields[\"p(95)\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"p(95)\"], &resource.P95); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"p(95)\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"p(95)\")\n\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"TrendValues\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `TrendValues` objects.\nfunc (resource TrendValues) Equals(other TrendValues) bool {\n\tif resource.Avg == nil && other.Avg != nil || resource.Avg != nil && other.Avg == nil {\n\t\treturn false\n\t}\n\n\tif resource.Avg != nil {\n\t\tif *resource.Avg != *other.Avg {\n\t\t\treturn false\n\t\t}\n\t}\n\tif resource.Max == nil && other.Max != nil || resource.Max != nil && other.Max == nil {\n\t\treturn false\n\t}\n\n\tif resource.Max != nil {\n\t\tif *resource.Max != *other.Max {\n\t\t\treturn false\n\t\t}\n\t}\n\tif resource.Med == nil && other.Med != nil || resource.Med != nil && other.Med == nil {\n\t\treturn false\n\t}\n\n\tif resource.Med != nil {\n\t\tif *resource.Med != *other.Med {\n\t\t\treturn false\n\t\t}\n\t}\n\tif resource.Min == nil && other.Min != nil || resource.Min != nil && other.Min == nil {\n\t\treturn false\n\t}\n\n\tif resource.Min != nil {\n\t\tif *resource.Min != *other.Min {\n\t\t\treturn false\n\t\t}\n\t}\n\tif resource.P90 == nil && other.P90 != nil || resource.P90 != nil && other.P90 == nil {\n\t\treturn false\n\t}\n\n\tif resource.P90 != nil {\n\t\tif *resource.P90 != *other.P90 {\n\t\t\treturn false\n\t\t}\n\t}\n\tif resource.P95 == nil && other.P95 != nil || resource.P95 != nil && other.P95 == nil {\n\t\treturn false\n\t}\n\n\tif resource.P95 != nil {\n\t\tif *resource.P95 != *other.P95 {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `TrendValues` fields for violations and returns them.\nfunc (resource TrendValues) Validate() error {\n\treturn nil\n}\n\ntype Summary struct {\n\t// Configuration information about the test execution\n\tConfig SummarySummaryConfig `json:\"config\"`\n\t// Metadata about the summary generation\n\tMetadata SummarySummaryMetadata `json:\"metadata\"`\n\t// Test execution results data\n\tResults SummarySummaryResults `json:\"results\"`\n\t// Schema version in semver 2.0 format (e.g., '1.0.0')\n\tVersion SemVer `json:\"version\"`\n}\n\n// NewSummary creates a new Summary object.\nfunc NewSummary() *Summary {\n\treturn &Summary{\n\t\tConfig:   *NewSummarySummaryConfig(),\n\t\tMetadata: *NewSummarySummaryMetadata(),\n\t\tResults:  *NewSummarySummaryResults(),\n\t}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `Summary` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *Summary) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"config\"\n\tif fields[\"config\"] != nil {\n\t\tif string(fields[\"config\"]) != \"null\" {\n\n\t\t\tresource.Config = SummarySummaryConfig{}\n\t\t\tif err := resource.Config.UnmarshalJSONStrict(fields[\"config\"]); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"config\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"config\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"config\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"config\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"metadata\"\n\tif fields[\"metadata\"] != nil {\n\t\tif string(fields[\"metadata\"]) != \"null\" {\n\n\t\t\tresource.Metadata = SummarySummaryMetadata{}\n\t\t\tif err := resource.Metadata.UnmarshalJSONStrict(fields[\"metadata\"]); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"metadata\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"metadata\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"metadata\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"metadata\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"results\"\n\tif fields[\"results\"] != nil {\n\t\tif string(fields[\"results\"]) != \"null\" {\n\n\t\t\tresource.Results = SummarySummaryResults{}\n\t\t\tif err := resource.Results.UnmarshalJSONStrict(fields[\"results\"]); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"results\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"results\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"results\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"results\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"version\"\n\tif fields[\"version\"] != nil {\n\t\tif string(fields[\"version\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"version\"], &resource.Version); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"version\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"version\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"version\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"version\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"Summary\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `Summary` objects.\nfunc (resource Summary) Equals(other Summary) bool {\n\tif !resource.Config.Equals(other.Config) {\n\t\treturn false\n\t}\n\tif !resource.Metadata.Equals(other.Metadata) {\n\t\treturn false\n\t}\n\tif !resource.Results.Equals(other.Results) {\n\t\treturn false\n\t}\n\tif resource.Version != other.Version {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `Summary` fields for violations and returns them.\nfunc (resource Summary) Validate() error {\n\tvar errs cog.BuildErrors\n\tif err := resource.Config.Validate(); err != nil {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"config\", err)...)\n\t}\n\tif err := resource.Metadata.Validate(); err != nil {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"metadata\", err)...)\n\t}\n\tif err := resource.Results.Validate(); err != nil {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"results\", err)...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Modified by compiler pass 'AnonymousStructsToNamed'\ntype SummarySummaryConfig struct {\n\t// Test run duration in seconds\n\tDuration float64 `json:\"duration\"`\n\t// Type of execution (local or cloud)\n\tExecution SummarySummaryConfigExecution/* AnonymousEnumToExplicitType */ `json:\"execution\"`\n\t// Path or name of the test script\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tScript *string `json:\"script,omitempty\"`\n}\n\n// NewSummarySummaryConfig creates a new SummarySummaryConfig object.\nfunc NewSummarySummaryConfig() *SummarySummaryConfig {\n\treturn &SummarySummaryConfig{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `SummarySummaryConfig` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *SummarySummaryConfig) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"duration\"\n\tif fields[\"duration\"] != nil {\n\t\tif string(fields[\"duration\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"duration\"], &resource.Duration); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"duration\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"duration\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"duration\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"duration\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"execution\"\n\tif fields[\"execution\"] != nil {\n\t\tif string(fields[\"execution\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"execution\"], &resource.Execution); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"execution\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"execution\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"execution\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"execution\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"script\"\n\tif fields[\"script\"] != nil {\n\t\tif string(fields[\"script\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"script\"], &resource.Script); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"script\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"script\")\n\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"SummarySummaryConfig\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `SummarySummaryConfig` objects.\nfunc (resource SummarySummaryConfig) Equals(other SummarySummaryConfig) bool {\n\tif resource.Duration != other.Duration {\n\t\treturn false\n\t}\n\tif resource.Execution != other.Execution {\n\t\treturn false\n\t}\n\tif resource.Script == nil && other.Script != nil || resource.Script != nil && other.Script == nil {\n\t\treturn false\n\t}\n\n\tif resource.Script != nil {\n\t\tif *resource.Script != *other.Script {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `SummarySummaryConfig` fields for violations and returns them.\nfunc (resource SummarySummaryConfig) Validate() error {\n\tvar errs cog.BuildErrors\n\tif !(resource.Duration >= 0) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"duration\",\n\t\t\terrors.New(\"must be >= 0\"),\n\t\t)...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Modified by compiler pass 'AnonymousStructsToNamed'\ntype SummarySummaryMetadata struct {\n\t// RFC3339 timestamp when summary was generated\n\tGeneratedAt time.Time `json:\"generatedAt\"`\n\t// Version of k6 that generated this summary\n\tK6Version SemVer `json:\"k6Version\"`\n}\n\n// NewSummarySummaryMetadata creates a new SummarySummaryMetadata object.\nfunc NewSummarySummaryMetadata() *SummarySummaryMetadata {\n\treturn &SummarySummaryMetadata{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `SummarySummaryMetadata` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *SummarySummaryMetadata) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"generatedAt\"\n\tif fields[\"generatedAt\"] != nil {\n\t\tif string(fields[\"generatedAt\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"generatedAt\"], &resource.GeneratedAt); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"generatedAt\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"generatedAt\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"generatedAt\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"generatedAt\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"k6Version\"\n\tif fields[\"k6Version\"] != nil {\n\t\tif string(fields[\"k6Version\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"k6Version\"], &resource.K6Version); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"k6Version\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"k6Version\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"k6Version\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"k6Version\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"SummarySummaryMetadata\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `SummarySummaryMetadata` objects.\nfunc (resource SummarySummaryMetadata) Equals(other SummarySummaryMetadata) bool {\n\tif resource.GeneratedAt != other.GeneratedAt {\n\t\treturn false\n\t}\n\tif resource.K6Version != other.K6Version {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `SummarySummaryMetadata` fields for violations and returns them.\nfunc (resource SummarySummaryMetadata) Validate() error {\n\treturn nil\n}\n\n// Modified by compiler pass 'AnonymousStructsToNamed'\ntype SummarySummaryResultsChecksResults struct {\n\t// Number of times the check failed\n\tFails int64 `json:\"fails\"`\n\t// Check name\n\tName string `json:\"name\"`\n\t// Number of times the check passed\n\tPasses int64 `json:\"passes\"`\n}\n\n// NewSummarySummaryResultsChecksResults creates a new SummarySummaryResultsChecksResults object.\nfunc NewSummarySummaryResultsChecksResults() *SummarySummaryResultsChecksResults {\n\treturn &SummarySummaryResultsChecksResults{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `SummarySummaryResultsChecksResults` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *SummarySummaryResultsChecksResults) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"fails\"\n\tif fields[\"fails\"] != nil {\n\t\tif string(fields[\"fails\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"fails\"], &resource.Fails); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"fails\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"fails\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"fails\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"fails\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"name\"\n\tif fields[\"name\"] != nil {\n\t\tif string(fields[\"name\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"name\"], &resource.Name); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"name\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"name\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"name\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"name\", errors.New(\"required field is missing from input\"))...)\n\t}\n\t// Field \"passes\"\n\tif fields[\"passes\"] != nil {\n\t\tif string(fields[\"passes\"]) != \"null\" {\n\t\t\tif err := json.Unmarshal(fields[\"passes\"], &resource.Passes); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"passes\", err)...)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"passes\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"passes\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"passes\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"SummarySummaryResultsChecksResults\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `SummarySummaryResultsChecksResults` objects.\nfunc (resource SummarySummaryResultsChecksResults) Equals(other SummarySummaryResultsChecksResults) bool {\n\tif resource.Fails != other.Fails {\n\t\treturn false\n\t}\n\tif resource.Name != other.Name {\n\t\treturn false\n\t}\n\tif resource.Passes != other.Passes {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `SummarySummaryResultsChecksResults` fields for violations and returns them.\nfunc (resource SummarySummaryResultsChecksResults) Validate() error {\n\tvar errs cog.BuildErrors\n\tif !(resource.Fails >= 0) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"fails\",\n\t\t\terrors.New(\"must be >= 0\"),\n\t\t)...)\n\t}\n\tif !(resource.Passes >= 0) {\n\t\terrs = append(errs, cog.MakeBuildErrors(\n\t\t\t\"passes\",\n\t\t\terrors.New(\"must be >= 0\"),\n\t\t)...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Modified by compiler pass 'AnonymousStructsToNamed'\ntype SummarySummaryResultsChecks struct {\n\t// Array of check-related metrics\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tMetrics []Metric `json:\"metrics,omitempty\"`\n\t// Individual check results in execution order\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tResults []SummarySummaryResultsChecksResults `json:\"results,omitempty\"`\n}\n\n// NewSummarySummaryResultsChecks creates a new SummarySummaryResultsChecks object.\nfunc NewSummarySummaryResultsChecks() *SummarySummaryResultsChecks {\n\treturn &SummarySummaryResultsChecks{}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `SummarySummaryResultsChecks` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *SummarySummaryResultsChecks) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"metrics\"\n\tif fields[\"metrics\"] != nil {\n\t\tif string(fields[\"metrics\"]) != \"null\" {\n\n\t\t\tpartialArray := []json.RawMessage{}\n\t\t\tif err := json.Unmarshal(fields[\"metrics\"], &partialArray); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor i1 := range partialArray {\n\t\t\t\tvar result1 Metric\n\n\t\t\t\tresult1 = Metric{}\n\t\t\t\tif err := result1.UnmarshalJSONStrict(partialArray[i1]); err != nil {\n\t\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"metrics[\"+strconv.Itoa(i1)+\"]\", err)...)\n\t\t\t\t}\n\t\t\t\tresource.Metrics = append(resource.Metrics, result1)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"metrics\")\n\n\t}\n\t// Field \"results\"\n\tif fields[\"results\"] != nil {\n\t\tif string(fields[\"results\"]) != \"null\" {\n\n\t\t\tpartialArray := []json.RawMessage{}\n\t\t\tif err := json.Unmarshal(fields[\"results\"], &partialArray); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor i1 := range partialArray {\n\t\t\t\tvar result1 SummarySummaryResultsChecksResults\n\n\t\t\t\tresult1 = SummarySummaryResultsChecksResults{}\n\t\t\t\tif err := result1.UnmarshalJSONStrict(partialArray[i1]); err != nil {\n\t\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"results[\"+strconv.Itoa(i1)+\"]\", err)...)\n\t\t\t\t}\n\t\t\t\tresource.Results = append(resource.Results, result1)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"results\")\n\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"SummarySummaryResultsChecks\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `SummarySummaryResultsChecks` objects.\nfunc (resource SummarySummaryResultsChecks) Equals(other SummarySummaryResultsChecks) bool {\n\n\tif len(resource.Metrics) != len(other.Metrics) {\n\t\treturn false\n\t}\n\n\tfor i1 := range resource.Metrics {\n\t\tif !resource.Metrics[i1].Equals(other.Metrics[i1]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif len(resource.Results) != len(other.Results) {\n\t\treturn false\n\t}\n\n\tfor i1 := range resource.Results {\n\t\tif !resource.Results[i1].Equals(other.Results[i1]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `SummarySummaryResultsChecks` fields for violations and returns them.\nfunc (resource SummarySummaryResultsChecks) Validate() error {\n\tvar errs cog.BuildErrors\n\n\tfor i1 := range resource.Metrics {\n\t\tif err := resource.Metrics[i1].Validate(); err != nil {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"metrics[\"+strconv.Itoa(i1)+\"]\", err)...)\n\t\t}\n\t}\n\n\tfor i1 := range resource.Results {\n\t\tif err := resource.Results[i1].Validate(); err != nil {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"results[\"+strconv.Itoa(i1)+\"]\", err)...)\n\t\t}\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Modified by compiler pass 'AnonymousStructsToNamed'\ntype SummarySummaryResults struct {\n\t// Check execution results\n\t// Modified by compiler pass 'NotRequiredFieldAsNullableType[nullable=true]'\n\tChecks *SummarySummaryResultsChecks `json:\"checks,omitempty\"`\n\t// Array of all metrics from the test execution\n\tMetrics []Metric `json:\"metrics\"`\n}\n\n// NewSummarySummaryResults creates a new SummarySummaryResults object.\nfunc NewSummarySummaryResults() *SummarySummaryResults {\n\treturn &SummarySummaryResults{\n\t\tMetrics: []Metric{},\n\t}\n}\n\n// UnmarshalJSONStrict implements a custom JSON unmarshalling logic to decode `SummarySummaryResults` from JSON.\n// Note: the unmarshalling done by this function is strict. It will fail over required fields being absent from the input, fields having an incorrect type, unexpected fields being present, …\nfunc (resource *SummarySummaryResults) UnmarshalJSONStrict(raw []byte) error {\n\tif raw == nil {\n\t\treturn nil\n\t}\n\tvar errs cog.BuildErrors\n\n\tfields := make(map[string]json.RawMessage)\n\tif err := json.Unmarshal(raw, &fields); err != nil {\n\t\treturn err\n\t}\n\t// Field \"checks\"\n\tif fields[\"checks\"] != nil {\n\t\tif string(fields[\"checks\"]) != \"null\" {\n\n\t\t\tresource.Checks = &SummarySummaryResultsChecks{}\n\t\t\tif err := resource.Checks.UnmarshalJSONStrict(fields[\"checks\"]); err != nil {\n\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"checks\", err)...)\n\t\t\t}\n\n\t\t}\n\t\tdelete(fields, \"checks\")\n\n\t}\n\t// Field \"metrics\"\n\tif fields[\"metrics\"] != nil {\n\t\tif string(fields[\"metrics\"]) != \"null\" {\n\n\t\t\tpartialArray := []json.RawMessage{}\n\t\t\tif err := json.Unmarshal(fields[\"metrics\"], &partialArray); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfor i1 := range partialArray {\n\t\t\t\tvar result1 Metric\n\n\t\t\t\tresult1 = Metric{}\n\t\t\t\tif err := result1.UnmarshalJSONStrict(partialArray[i1]); err != nil {\n\t\t\t\t\terrs = append(errs, cog.MakeBuildErrors(\"metrics[\"+strconv.Itoa(i1)+\"]\", err)...)\n\t\t\t\t}\n\t\t\t\tresource.Metrics = append(resource.Metrics, result1)\n\t\t\t}\n\t\t} else {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"metrics\", errors.New(\"required field is null\"))...)\n\n\t\t}\n\t\tdelete(fields, \"metrics\")\n\t} else {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"metrics\", errors.New(\"required field is missing from input\"))...)\n\t}\n\n\tfor field := range fields {\n\t\terrs = append(errs, cog.MakeBuildErrors(\"SummarySummaryResults\", fmt.Errorf(\"unexpected field '%s'\", field))...)\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Equals tests the equality of two `SummarySummaryResults` objects.\nfunc (resource SummarySummaryResults) Equals(other SummarySummaryResults) bool {\n\tif resource.Checks == nil && other.Checks != nil || resource.Checks != nil && other.Checks == nil {\n\t\treturn false\n\t}\n\n\tif resource.Checks != nil {\n\t\tif !resource.Checks.Equals(*other.Checks) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif len(resource.Metrics) != len(other.Metrics) {\n\t\treturn false\n\t}\n\n\tfor i1 := range resource.Metrics {\n\t\tif !resource.Metrics[i1].Equals(other.Metrics[i1]) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Validate checks all the validation constraints that may be defined on `SummarySummaryResults` fields for violations and returns them.\nfunc (resource SummarySummaryResults) Validate() error {\n\tvar errs cog.BuildErrors\n\tif resource.Checks != nil {\n\t\tif err := resource.Checks.Validate(); err != nil {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"checks\", err)...)\n\t\t}\n\t}\n\n\tfor i1 := range resource.Metrics {\n\t\tif err := resource.Metrics[i1].Validate(); err != nil {\n\t\t\terrs = append(errs, cog.MakeBuildErrors(\"metrics[\"+strconv.Itoa(i1)+\"]\", err)...)\n\t\t}\n\t}\n\n\tif len(errs) == 0 {\n\t\treturn nil\n\t}\n\n\treturn errs\n}\n\n// Modified by compiler pass 'AnonymousEnumToExplicitType'\n// Modified by compiler pass 'PrefixEnumValues'\ntype MetricContains string\n\nconst (\n\tMetricContainsDefault MetricContains = \"default\"\n\tMetricContainsTime    MetricContains = \"time\"\n\tMetricContainsData    MetricContains = \"data\"\n)\n\n// Modified by compiler pass 'AnonymousEnumToExplicitType'\n// Modified by compiler pass 'PrefixEnumValues'\ntype MetricType string\n\nconst (\n\tMetricTypeCounter MetricType = \"counter\"\n\tMetricTypeGauge   MetricType = \"gauge\"\n\tMetricTypeRate    MetricType = \"rate\"\n\tMetricTypeTrend   MetricType = \"trend\"\n)\n\n// Modified by compiler pass 'AnonymousEnumToExplicitType'\n// Modified by compiler pass 'PrefixEnumValues'\ntype SummarySummaryConfigExecution string\n\nconst (\n\tSummarySummaryConfigExecutionLocal SummarySummaryConfigExecution = \"local\"\n\tSummarySummaryConfigExecutionCloud SummarySummaryConfigExecution = \"cloud\"\n)\n"
  },
  {
    "path": "internal/lib/summary/summary.go",
    "content": "package summary\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\n// A Mode specifies the mode of the Summary,\n// which defines how the end-of-test summary will be rendered.\n// TODO(@joanlopez): remove ModeLegacy by k6 v2.0, once we completely drop the support for --summary-mode=legacy.\ntype Mode int\n\n// Possible values for SummaryMode.\nconst (\n\tModeCompact  = Mode(iota) // Compact mode that only displays the total results.\n\tModeFull                  // Extended mode that displays total and partial results.\n\tModeLegacy                // Deprecated. Legacy mode, used for backwards compatibility.\n\tModeDisabled              // Disabled, formerly known as --no-summary.\n)\n\n// ErrInvalidSummaryMode indicates the serialized summary mode is invalid.\nvar ErrInvalidSummaryMode = errors.New(\"invalid summary mode\")\n\nconst (\n\tcompactString  = \"compact\"\n\tfullString     = \"full\"\n\tlegacyString   = \"legacy\"\n\tdisabledString = \"disabled\"\n)\n\n// MarshalJSON serializes a Mode as a human-readable string.\nfunc (m Mode) MarshalJSON() ([]byte, error) {\n\ttxt, err := m.MarshalText()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []byte(`\"` + string(txt) + `\"`), nil\n}\n\n// MarshalText serializes a Mode as a human-readable string.\nfunc (m Mode) MarshalText() ([]byte, error) {\n\tswitch m {\n\tcase ModeCompact:\n\t\treturn []byte(compactString), nil\n\tcase ModeFull:\n\t\treturn []byte(fullString), nil\n\tcase ModeLegacy:\n\t\treturn []byte(legacyString), nil\n\tcase ModeDisabled:\n\t\treturn []byte(disabledString), nil\n\tdefault:\n\t\treturn nil, ErrInvalidSummaryMode\n\t}\n}\n\n// UnmarshalText deserializes a Mode from a string representation.\nfunc (m *Mode) UnmarshalText(data []byte) error {\n\tswitch string(data) {\n\tcase compactString:\n\t\t*m = ModeCompact\n\tcase fullString:\n\t\t*m = ModeFull\n\tcase legacyString:\n\t\t*m = ModeLegacy\n\tcase disabledString:\n\t\t*m = ModeDisabled\n\tdefault:\n\t\treturn ErrInvalidSummaryMode\n\t}\n\n\treturn nil\n}\n\n// String returns a human-readable string representation of a Mode.\nfunc (m Mode) String() string {\n\tswitch m {\n\tcase ModeCompact:\n\t\treturn compactString\n\tcase ModeFull:\n\t\treturn fullString\n\tcase ModeLegacy:\n\t\treturn legacyString\n\tcase ModeDisabled:\n\t\treturn disabledString\n\tdefault:\n\t\treturn \"[INVALID]\"\n\t}\n}\n\n// ValidateMode checks if the provided val is a valid Mode.\nfunc ValidateMode(val string) (m Mode, err error) {\n\tif val == \"\" {\n\t\treturn ModeCompact, nil\n\t}\n\tif err = m.UnmarshalText([]byte(val)); err != nil {\n\t\treturn 0, err\n\t}\n\treturn m, err\n}\n\n// Summary is the data structure that holds all the summary data (thresholds, metrics, checks, etc)\n// as well as some other information, like certain rendering options.\ntype Summary struct {\n\tThresholds `js:\"thresholds\"`\n\tGroup      `js:\"root_group\"`\n\tScenarios  map[string]Group\n\n\tTestRunDuration           time.Duration\n\tNoColor                   bool // TODO: drop this when noColor is part of the (runtime) options\n\tEnableColors              bool\n\tNewMachineReadableSummary bool\n}\n\n// New instantiates a new empty Summary.\nfunc New() *Summary {\n\treturn &Summary{\n\t\tThresholds: NewThresholds(),\n\t\tGroup: Group{\n\t\t\tMetrics: NewMetrics(),\n\t\t\tGroups:  make(map[string]Group),\n\t\t},\n\t\tScenarios: make(map[string]Group),\n\t}\n}\n\n// MetricInfo holds the definition of a metric that will be rendered in the summary,\n// including the name of the metric, its type (Counter, Trend, etc.) and what contains (data amounts, times, etc.).\ntype MetricInfo struct {\n\tName     string\n\tType     string\n\tContains string\n}\n\n// Metric holds all the information needed to display a metric in the summary,\n// including its definition and its values.\ntype Metric struct {\n\tMetricInfo\n\tValues map[string]float64\n}\n\n// NewMetricFrom instantiates a new Metric for a given metrics.Sink and the metric's info.\nfunc NewMetricFrom(info MetricInfo, values map[string]float64) Metric {\n\treturn Metric{\n\t\tMetricInfo: info,\n\t\tValues:     values,\n\t}\n}\n\n// Metrics is a collection of Metric grouped by section (http, network, etc).\ntype Metrics struct {\n\t// HTTP contains summary data specific to HTTP metrics and is used\n\t// to produce the summary HTTP subsection's content.\n\tHTTP map[string]Metric\n\t// Execution contains summary data specific to Execution metrics and is used\n\t// to produce the summary Execution subsection's content.\n\tExecution map[string]Metric\n\t// Network contains summary data specific to Network metrics and is used\n\t// to produce the summary Network subsection's content.\n\tNetwork map[string]Metric\n\n\tBrowser map[string]Metric\n\n\tWebVitals map[string]Metric\n\n\tGrpc map[string]Metric\n\n\tWebSocket map[string]Metric `js:\"websocket\"`\n\n\t// Custom contains user-defined metric results as well as extensions metrics\n\tCustom map[string]Metric\n}\n\n// NewMetrics instantiates an empty collection of Metrics.\nfunc NewMetrics() Metrics {\n\treturn Metrics{\n\t\tHTTP:      make(map[string]Metric),\n\t\tExecution: make(map[string]Metric),\n\t\tNetwork:   make(map[string]Metric),\n\t\tBrowser:   make(map[string]Metric),\n\t\tWebVitals: make(map[string]Metric),\n\t\tGrpc:      make(map[string]Metric),\n\t\tWebSocket: make(map[string]Metric),\n\t\tCustom:    make(map[string]Metric),\n\t}\n}\n\n// ChecksMetrics is the subset of checks-specific metrics.\ntype ChecksMetrics struct {\n\tTotal   Metric `js:\"checks_total\"`\n\tSuccess Metric `js:\"checks_succeeded\"`\n\tFail    Metric `js:\"checks_failed\"`\n}\n\n// Check holds the information to be rendered in the summary for a single check.\ntype Check struct {\n\tName   string `js:\"name\"`\n\tPasses int64  `js:\"passes\"`\n\tFails  int64  `js:\"fails\"`\n}\n\n// Checks holds the checks to be rendered in the summary.\ntype Checks struct {\n\tMetrics       ChecksMetrics\n\tOrderedChecks []*Check\n}\n\n// NewChecks instantiates an empty set of Checks.\nfunc NewChecks() *Checks {\n\tinitChecksMetricData := func(name string, t metrics.MetricType) Metric {\n\t\treturn Metric{\n\t\t\tMetricInfo: MetricInfo{\n\t\t\t\tName:     name,\n\t\t\t\tType:     t.String(),\n\t\t\t\tContains: metrics.Default.String(),\n\t\t\t},\n\t\t\tValues: make(map[string]float64),\n\t\t}\n\t}\n\n\treturn &Checks{\n\t\tMetrics: ChecksMetrics{\n\t\t\tTotal:   initChecksMetricData(\"checks_total\", metrics.Counter),\n\t\t\tSuccess: initChecksMetricData(\"checks_succeeded\", metrics.Rate),\n\t\t\tFail:    initChecksMetricData(\"checks_failed\", metrics.Rate),\n\t\t},\n\t}\n}\n\n// Threshold holds the information of a threshold to be rendered in the summary.\ntype Threshold struct {\n\tSource string `js:\"source\"`\n\tOk     bool   `js:\"ok\"`\n}\n\n// MetricThresholds is the collection of Threshold that belongs to the same metric.\ntype MetricThresholds struct {\n\tMetric     Metric      `js:\"metric\"`\n\tThresholds []Threshold `js:\"thresholds\"`\n}\n\n// Thresholds is a collection of MetricThresholds that will be rendered in the summary.\ntype Thresholds map[string]MetricThresholds\n\n// NewThresholds instantiates an empty collection of Thresholds.\nfunc NewThresholds() Thresholds {\n\tthresholds := make(Thresholds)\n\treturn thresholds\n}\n\n// Group is a group of metrics and subgroups (recursive) that will be rendered in the summary.\ntype Group struct {\n\tChecks      *Checks // Not always present, thus we use a pointer.\n\tMetrics     Metrics\n\tGroups      map[string]Group\n\tGroupsOrder []string // Groups names with the order to be displayed in the summary. Typically same as in code.\n}\n\n// NewGroup instantiates an empty Group.\nfunc NewGroup() Group {\n\treturn Group{\n\t\tMetrics:     NewMetrics(),\n\t\tGroups:      make(map[string]Group),\n\t\tGroupsOrder: make([]string, 0),\n\t}\n}\n\n// Meta holds some metadata associated with the Summary\n// but isn't strictly part of it, like the script.\ntype Meta struct {\n\tScript  string\n\tIsCloud bool\n}\n"
  },
  {
    "path": "internal/lib/testutils/fs.go",
    "content": "package testutils\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// MakeMemMapFs creates a new in-memory filesystem with the given files.\n//\n// It is particularly useful for testing code that interacts with the\n// filesystem, as it  allows to create a filesystem with a known state\n// without having to create temporary directories and files on disk.\n//\n// The keys of the withFiles map are the paths of the files to create, and the\n// values are the contents of the files. The files are created with 644 mode.\n//\n// The filesystem is returned as a [fsext.Fs].\nfunc MakeMemMapFs(t *testing.T, withFiles map[string][]byte) fsext.Fs {\n\tfs := fsext.NewMemMapFs()\n\n\tfor path, data := range withFiles {\n\t\trequire.NoError(t, fsext.WriteFile(fs, path, data, 0o644))\n\t}\n\n\treturn fs\n}\n"
  },
  {
    "path": "internal/lib/testutils/grpcservice/route_guide.pb.go",
    "content": "// Copyright 2015 gRPC authors, with some modification by the k6 team (2021).\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: route_guide.proto\n\npackage grpcservice\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// Points are represented as latitude-longitude pairs in the E7 representation\n// (degrees multiplied by 10**7 and rounded to the nearest integer).\n// Latitudes should be in the range +/- 90 degrees and longitude should be in\n// the range +/- 180 degrees (inclusive).\ntype Point struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tLatitude  int32 `protobuf:\"varint,1,opt,name=latitude,proto3\" json:\"latitude,omitempty\"`\n\tLongitude int32 `protobuf:\"varint,2,opt,name=longitude,proto3\" json:\"longitude,omitempty\"`\n}\n\nfunc (x *Point) Reset() {\n\t*x = Point{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_route_guide_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Point) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Point) ProtoMessage() {}\n\nfunc (x *Point) ProtoReflect() protoreflect.Message {\n\tmi := &file_route_guide_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Point.ProtoReflect.Descriptor instead.\nfunc (*Point) Descriptor() ([]byte, []int) {\n\treturn file_route_guide_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *Point) GetLatitude() int32 {\n\tif x != nil {\n\t\treturn x.Latitude\n\t}\n\treturn 0\n}\n\nfunc (x *Point) GetLongitude() int32 {\n\tif x != nil {\n\t\treturn x.Longitude\n\t}\n\treturn 0\n}\n\n// A latitude-longitude rectangle, represented as two diagonally opposite\n// points \"lo\" and \"hi\".\ntype Rectangle struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// One corner of the rectangle.\n\tLo *Point `protobuf:\"bytes,1,opt,name=lo,proto3\" json:\"lo,omitempty\"`\n\t// The other corner of the rectangle.\n\tHi *Point `protobuf:\"bytes,2,opt,name=hi,proto3\" json:\"hi,omitempty\"`\n}\n\nfunc (x *Rectangle) Reset() {\n\t*x = Rectangle{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_route_guide_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Rectangle) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Rectangle) ProtoMessage() {}\n\nfunc (x *Rectangle) ProtoReflect() protoreflect.Message {\n\tmi := &file_route_guide_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Rectangle.ProtoReflect.Descriptor instead.\nfunc (*Rectangle) Descriptor() ([]byte, []int) {\n\treturn file_route_guide_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Rectangle) GetLo() *Point {\n\tif x != nil {\n\t\treturn x.Lo\n\t}\n\treturn nil\n}\n\nfunc (x *Rectangle) GetHi() *Point {\n\tif x != nil {\n\t\treturn x.Hi\n\t}\n\treturn nil\n}\n\n// A feature names something at a given point.\n//\n// If a feature could not be named, the name is empty.\ntype Feature struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The name of the feature.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// The point where the feature is detected.\n\tLocation *Point `protobuf:\"bytes,2,opt,name=location,proto3\" json:\"location,omitempty\"`\n}\n\nfunc (x *Feature) Reset() {\n\t*x = Feature{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_route_guide_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Feature) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Feature) ProtoMessage() {}\n\nfunc (x *Feature) ProtoReflect() protoreflect.Message {\n\tmi := &file_route_guide_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Feature.ProtoReflect.Descriptor instead.\nfunc (*Feature) Descriptor() ([]byte, []int) {\n\treturn file_route_guide_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Feature) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Feature) GetLocation() *Point {\n\tif x != nil {\n\t\treturn x.Location\n\t}\n\treturn nil\n}\n\n// A RouteNote is a message sent while at a given point.\ntype RouteNote struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The location from which the message is sent.\n\tLocation *Point `protobuf:\"bytes,1,opt,name=location,proto3\" json:\"location,omitempty\"`\n\t// The message to be sent.\n\tMessage string `protobuf:\"bytes,2,opt,name=message,proto3\" json:\"message,omitempty\"`\n}\n\nfunc (x *RouteNote) Reset() {\n\t*x = RouteNote{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_route_guide_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RouteNote) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RouteNote) ProtoMessage() {}\n\nfunc (x *RouteNote) ProtoReflect() protoreflect.Message {\n\tmi := &file_route_guide_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RouteNote.ProtoReflect.Descriptor instead.\nfunc (*RouteNote) Descriptor() ([]byte, []int) {\n\treturn file_route_guide_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *RouteNote) GetLocation() *Point {\n\tif x != nil {\n\t\treturn x.Location\n\t}\n\treturn nil\n}\n\nfunc (x *RouteNote) GetMessage() string {\n\tif x != nil {\n\t\treturn x.Message\n\t}\n\treturn \"\"\n}\n\n// A RouteSummary is received in response to a RecordRoute rpc.\n//\n// It contains the number of individual points received, the number of\n// detected features, and the total distance covered as the cumulative sum of\n// the distance between each point.\ntype RouteSummary struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The number of points received.\n\tPointCount int32 `protobuf:\"varint,1,opt,name=point_count,json=pointCount,proto3\" json:\"point_count,omitempty\"`\n\t// The number of known features passed while traversing the route.\n\tFeatureCount int32 `protobuf:\"varint,2,opt,name=feature_count,json=featureCount,proto3\" json:\"feature_count,omitempty\"`\n\t// The distance covered in metres.\n\tDistance int32 `protobuf:\"varint,3,opt,name=distance,proto3\" json:\"distance,omitempty\"`\n\t// The duration of the traversal in seconds.\n\tElapsedTime int32 `protobuf:\"varint,4,opt,name=elapsed_time,json=elapsedTime,proto3\" json:\"elapsed_time,omitempty\"`\n}\n\nfunc (x *RouteSummary) Reset() {\n\t*x = RouteSummary{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_route_guide_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RouteSummary) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RouteSummary) ProtoMessage() {}\n\nfunc (x *RouteSummary) ProtoReflect() protoreflect.Message {\n\tmi := &file_route_guide_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RouteSummary.ProtoReflect.Descriptor instead.\nfunc (*RouteSummary) Descriptor() ([]byte, []int) {\n\treturn file_route_guide_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *RouteSummary) GetPointCount() int32 {\n\tif x != nil {\n\t\treturn x.PointCount\n\t}\n\treturn 0\n}\n\nfunc (x *RouteSummary) GetFeatureCount() int32 {\n\tif x != nil {\n\t\treturn x.FeatureCount\n\t}\n\treturn 0\n}\n\nfunc (x *RouteSummary) GetDistance() int32 {\n\tif x != nil {\n\t\treturn x.Distance\n\t}\n\treturn 0\n}\n\nfunc (x *RouteSummary) GetElapsedTime() int32 {\n\tif x != nil {\n\t\treturn x.ElapsedTime\n\t}\n\treturn 0\n}\n\nvar File_route_guide_proto protoreflect.FileDescriptor\n\nvar file_route_guide_proto_rawDesc = []byte{\n\t0x0a, 0x11, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x67, 0x75, 0x69, 0x64, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x41, 0x0a, 0x05, 0x50, 0x6f, 0x69,\n\t0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c,\n\t0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,\n\t0x05, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x22, 0x45, 0x0a, 0x09,\n\t0x52, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x02, 0x6c, 0x6f, 0x18,\n\t0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x50, 0x6f, 0x69,\n\t0x6e, 0x74, 0x52, 0x02, 0x6c, 0x6f, 0x12, 0x1b, 0x0a, 0x02, 0x68, 0x69, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52,\n\t0x02, 0x68, 0x69, 0x22, 0x46, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12,\n\t0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,\n\t0x6d, 0x65, 0x12, 0x27, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x50, 0x6f, 0x69, 0x6e,\n\t0x74, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x4e, 0x0a, 0x09, 0x52,\n\t0x6f, 0x75, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61,\n\t0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6d, 0x61, 0x69,\n\t0x6e, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,\n\t0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x0c,\n\t0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1f, 0x0a, 0x0b,\n\t0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x05, 0x52, 0x0a, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x0a,\n\t0x0d, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x75,\n\t0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x03,\n\t0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x21,\n\t0x0a, 0x0c, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04,\n\t0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d,\n\t0x65, 0x32, 0x71, 0x0a, 0x0f, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x45, 0x78, 0x70, 0x6c,\n\t0x6f, 0x72, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75,\n\t0x72, 0x65, 0x12, 0x0b, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a,\n\t0x0d, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x00,\n\t0x12, 0x32, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73,\n\t0x12, 0x0f, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x63, 0x74, 0x61, 0x6e, 0x67, 0x6c,\n\t0x65, 0x1a, 0x0d, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65,\n\t0x22, 0x00, 0x30, 0x01, 0x32, 0x75, 0x0a, 0x0a, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x47, 0x75, 0x69,\n\t0x64, 0x65, 0x12, 0x32, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x6f, 0x75, 0x74,\n\t0x65, 0x12, 0x0b, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x1a, 0x12,\n\t0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61,\n\t0x72, 0x79, 0x22, 0x00, 0x28, 0x01, 0x12, 0x33, 0x0a, 0x09, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x43,\n\t0x68, 0x61, 0x74, 0x12, 0x0f, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x52, 0x6f, 0x75, 0x74, 0x65,\n\t0x4e, 0x6f, 0x74, 0x65, 0x1a, 0x0f, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x52, 0x6f, 0x75, 0x74,\n\t0x65, 0x4e, 0x6f, 0x74, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0f, 0x5a, 0x0d, 0x2e,\n\t0x2f, 0x67, 0x72, 0x70, 0x63, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_route_guide_proto_rawDescOnce sync.Once\n\tfile_route_guide_proto_rawDescData = file_route_guide_proto_rawDesc\n)\n\nfunc file_route_guide_proto_rawDescGZIP() []byte {\n\tfile_route_guide_proto_rawDescOnce.Do(func() {\n\t\tfile_route_guide_proto_rawDescData = protoimpl.X.CompressGZIP(file_route_guide_proto_rawDescData)\n\t})\n\treturn file_route_guide_proto_rawDescData\n}\n\nvar file_route_guide_proto_msgTypes = make([]protoimpl.MessageInfo, 5)\nvar file_route_guide_proto_goTypes = []interface{}{\n\t(*Point)(nil),        // 0: main.Point\n\t(*Rectangle)(nil),    // 1: main.Rectangle\n\t(*Feature)(nil),      // 2: main.Feature\n\t(*RouteNote)(nil),    // 3: main.RouteNote\n\t(*RouteSummary)(nil), // 4: main.RouteSummary\n}\nvar file_route_guide_proto_depIdxs = []int32{\n\t0, // 0: main.Rectangle.lo:type_name -> main.Point\n\t0, // 1: main.Rectangle.hi:type_name -> main.Point\n\t0, // 2: main.Feature.location:type_name -> main.Point\n\t0, // 3: main.RouteNote.location:type_name -> main.Point\n\t0, // 4: main.FeatureExplorer.GetFeature:input_type -> main.Point\n\t1, // 5: main.FeatureExplorer.ListFeatures:input_type -> main.Rectangle\n\t0, // 6: main.RouteGuide.RecordRoute:input_type -> main.Point\n\t3, // 7: main.RouteGuide.RouteChat:input_type -> main.RouteNote\n\t2, // 8: main.FeatureExplorer.GetFeature:output_type -> main.Feature\n\t2, // 9: main.FeatureExplorer.ListFeatures:output_type -> main.Feature\n\t4, // 10: main.RouteGuide.RecordRoute:output_type -> main.RouteSummary\n\t3, // 11: main.RouteGuide.RouteChat:output_type -> main.RouteNote\n\t8, // [8:12] is the sub-list for method output_type\n\t4, // [4:8] is the sub-list for method input_type\n\t4, // [4:4] is the sub-list for extension type_name\n\t4, // [4:4] is the sub-list for extension extendee\n\t0, // [0:4] is the sub-list for field type_name\n}\n\nfunc init() { file_route_guide_proto_init() }\nfunc file_route_guide_proto_init() {\n\tif File_route_guide_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_route_guide_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Point); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_route_guide_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Rectangle); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_route_guide_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Feature); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_route_guide_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RouteNote); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_route_guide_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RouteSummary); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_route_guide_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   5,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   2,\n\t\t},\n\t\tGoTypes:           file_route_guide_proto_goTypes,\n\t\tDependencyIndexes: file_route_guide_proto_depIdxs,\n\t\tMessageInfos:      file_route_guide_proto_msgTypes,\n\t}.Build()\n\tFile_route_guide_proto = out.File\n\tfile_route_guide_proto_rawDesc = nil\n\tfile_route_guide_proto_goTypes = nil\n\tfile_route_guide_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/lib/testutils/grpcservice/route_guide.proto",
    "content": "// Copyright 2015 gRPC authors, with some modification by the k6 team (2021).\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nsyntax = \"proto3\";\n\npackage main;\n\noption go_package = \"./grpcservice\";\n\n// FeatureExplorer is the service for exploring Features.\n// Interface exported by the server.\nservice FeatureExplorer {\n  // A simple RPC.\n  //\n  // Obtains the feature at a given position.\n  //\n  // A feature with an empty name is returned if there's no feature at the given\n  // position.\n  rpc GetFeature(Point) returns (Feature) {}\n\n  // A server-to-client streaming RPC.\n  //\n  // Obtains the Features available within the given Rectangle.  Results are\n  // streamed rather than returned at once (e.g. in a response message with a\n  // repeated field), as the rectangle may cover a large area and contain a\n  // huge number of features.\n  rpc ListFeatures(Rectangle) returns (stream Feature) {}\n}\n\n// Interface exported by the server.\nservice RouteGuide {\n\n  // A client-to-server streaming RPC.\n  //\n  // Accepts a stream of Points on a route being traversed, returning a\n  // RouteSummary when traversal is completed.\n  rpc RecordRoute(stream Point) returns (RouteSummary) {}\n\n  // A Bidirectional streaming RPC.\n  //\n  // Accepts a stream of RouteNotes sent while a route is being traversed,\n  // while receiving other RouteNotes (e.g. from other users).\n  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}\n}\n\n// Points are represented as latitude-longitude pairs in the E7 representation\n// (degrees multiplied by 10**7 and rounded to the nearest integer).\n// Latitudes should be in the range +/- 90 degrees and longitude should be in\n// the range +/- 180 degrees (inclusive).\nmessage Point {\n  int32 latitude = 1;\n  int32 longitude = 2;\n}\n\n// A latitude-longitude rectangle, represented as two diagonally opposite\n// points \"lo\" and \"hi\".\nmessage Rectangle {\n  // One corner of the rectangle.\n  Point lo = 1;\n\n  // The other corner of the rectangle.\n  Point hi = 2;\n}\n\n// A feature names something at a given point.\n//\n// If a feature could not be named, the name is empty.\nmessage Feature {\n  // The name of the feature.\n  string name = 1;\n\n  // The point where the feature is detected.\n  Point location = 2;\n}\n\n// A RouteNote is a message sent while at a given point.\nmessage RouteNote {\n  // The location from which the message is sent.\n  Point location = 1;\n\n  // The message to be sent.\n  string message = 2;\n}\n\n// A RouteSummary is received in response to a RecordRoute rpc.\n//\n// It contains the number of individual points received, the number of\n// detected features, and the total distance covered as the cumulative sum of\n// the distance between each point.\nmessage RouteSummary {\n  // The number of points received.\n  int32 point_count = 1;\n\n  // The number of known features passed while traversing the route.\n  int32 feature_count = 2;\n\n  // The distance covered in metres.\n  int32 distance = 3;\n\n  // The duration of the traversal in seconds.\n  int32 elapsed_time = 4;\n}\n"
  },
  {
    "path": "internal/lib/testutils/grpcservice/route_guide_grpc.pb.go",
    "content": "// Copyright 2015 gRPC authors, with some modification by the k6 team (2021).\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.3.0\n// - protoc             v3.21.12\n// source: route_guide.proto\n\npackage grpcservice\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.32.0 or later.\nconst _ = grpc.SupportPackageIsVersion7\n\nconst (\n\tFeatureExplorer_GetFeature_FullMethodName   = \"/main.FeatureExplorer/GetFeature\"\n\tFeatureExplorer_ListFeatures_FullMethodName = \"/main.FeatureExplorer/ListFeatures\"\n)\n\n// FeatureExplorerClient is the client API for FeatureExplorer service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype FeatureExplorerClient interface {\n\t// A simple RPC.\n\t//\n\t// Obtains the feature at a given position.\n\t//\n\t// A feature with an empty name is returned if there's no feature at the given\n\t// position.\n\tGetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (*Feature, error)\n\t// A server-to-client streaming RPC.\n\t//\n\t// Obtains the Features available within the given Rectangle.  Results are\n\t// streamed rather than returned at once (e.g. in a response message with a\n\t// repeated field), as the rectangle may cover a large area and contain a\n\t// huge number of features.\n\tListFeatures(ctx context.Context, in *Rectangle, opts ...grpc.CallOption) (FeatureExplorer_ListFeaturesClient, error)\n}\n\ntype featureExplorerClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewFeatureExplorerClient(cc grpc.ClientConnInterface) FeatureExplorerClient {\n\treturn &featureExplorerClient{cc}\n}\n\nfunc (c *featureExplorerClient) GetFeature(ctx context.Context, in *Point, opts ...grpc.CallOption) (*Feature, error) {\n\tout := new(Feature)\n\terr := c.cc.Invoke(ctx, FeatureExplorer_GetFeature_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *featureExplorerClient) ListFeatures(ctx context.Context, in *Rectangle, opts ...grpc.CallOption) (FeatureExplorer_ListFeaturesClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &FeatureExplorer_ServiceDesc.Streams[0], FeatureExplorer_ListFeatures_FullMethodName, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &featureExplorerListFeaturesClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype FeatureExplorer_ListFeaturesClient interface {\n\tRecv() (*Feature, error)\n\tgrpc.ClientStream\n}\n\ntype featureExplorerListFeaturesClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *featureExplorerListFeaturesClient) Recv() (*Feature, error) {\n\tm := new(Feature)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// FeatureExplorerServer is the server API for FeatureExplorer service.\n// All implementations must embed UnimplementedFeatureExplorerServer\n// for forward compatibility\ntype FeatureExplorerServer interface {\n\t// A simple RPC.\n\t//\n\t// Obtains the feature at a given position.\n\t//\n\t// A feature with an empty name is returned if there's no feature at the given\n\t// position.\n\tGetFeature(context.Context, *Point) (*Feature, error)\n\t// A server-to-client streaming RPC.\n\t//\n\t// Obtains the Features available within the given Rectangle.  Results are\n\t// streamed rather than returned at once (e.g. in a response message with a\n\t// repeated field), as the rectangle may cover a large area and contain a\n\t// huge number of features.\n\tListFeatures(*Rectangle, FeatureExplorer_ListFeaturesServer) error\n\tmustEmbedUnimplementedFeatureExplorerServer()\n}\n\n// UnimplementedFeatureExplorerServer must be embedded to have forward compatible implementations.\ntype UnimplementedFeatureExplorerServer struct {\n}\n\nfunc (UnimplementedFeatureExplorerServer) GetFeature(context.Context, *Point) (*Feature, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method GetFeature not implemented\")\n}\nfunc (UnimplementedFeatureExplorerServer) ListFeatures(*Rectangle, FeatureExplorer_ListFeaturesServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method ListFeatures not implemented\")\n}\nfunc (UnimplementedFeatureExplorerServer) mustEmbedUnimplementedFeatureExplorerServer() {}\n\n// UnsafeFeatureExplorerServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to FeatureExplorerServer will\n// result in compilation errors.\ntype UnsafeFeatureExplorerServer interface {\n\tmustEmbedUnimplementedFeatureExplorerServer()\n}\n\nfunc RegisterFeatureExplorerServer(s grpc.ServiceRegistrar, srv FeatureExplorerServer) {\n\ts.RegisterService(&FeatureExplorer_ServiceDesc, srv)\n}\n\nfunc _FeatureExplorer_GetFeature_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(Point)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(FeatureExplorerServer).GetFeature(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: FeatureExplorer_GetFeature_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(FeatureExplorerServer).GetFeature(ctx, req.(*Point))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _FeatureExplorer_ListFeatures_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(Rectangle)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(FeatureExplorerServer).ListFeatures(m, &featureExplorerListFeaturesServer{stream})\n}\n\ntype FeatureExplorer_ListFeaturesServer interface {\n\tSend(*Feature) error\n\tgrpc.ServerStream\n}\n\ntype featureExplorerListFeaturesServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *featureExplorerListFeaturesServer) Send(m *Feature) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\n// FeatureExplorer_ServiceDesc is the grpc.ServiceDesc for FeatureExplorer service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar FeatureExplorer_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"main.FeatureExplorer\",\n\tHandlerType: (*FeatureExplorerServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"GetFeature\",\n\t\t\tHandler:    _FeatureExplorer_GetFeature_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"ListFeatures\",\n\t\t\tHandler:       _FeatureExplorer_ListFeatures_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"route_guide.proto\",\n}\n\nconst (\n\tRouteGuide_RecordRoute_FullMethodName = \"/main.RouteGuide/RecordRoute\"\n\tRouteGuide_RouteChat_FullMethodName   = \"/main.RouteGuide/RouteChat\"\n)\n\n// RouteGuideClient is the client API for RouteGuide service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype RouteGuideClient interface {\n\t// A client-to-server streaming RPC.\n\t//\n\t// Accepts a stream of Points on a route being traversed, returning a\n\t// RouteSummary when traversal is completed.\n\tRecordRoute(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RecordRouteClient, error)\n\t// A Bidirectional streaming RPC.\n\t//\n\t// Accepts a stream of RouteNotes sent while a route is being traversed,\n\t// while receiving other RouteNotes (e.g. from other users).\n\tRouteChat(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RouteChatClient, error)\n}\n\ntype routeGuideClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewRouteGuideClient(cc grpc.ClientConnInterface) RouteGuideClient {\n\treturn &routeGuideClient{cc}\n}\n\nfunc (c *routeGuideClient) RecordRoute(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RecordRouteClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &RouteGuide_ServiceDesc.Streams[0], RouteGuide_RecordRoute_FullMethodName, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &routeGuideRecordRouteClient{stream}\n\treturn x, nil\n}\n\ntype RouteGuide_RecordRouteClient interface {\n\tSend(*Point) error\n\tCloseAndRecv() (*RouteSummary, error)\n\tgrpc.ClientStream\n}\n\ntype routeGuideRecordRouteClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *routeGuideRecordRouteClient) Send(m *Point) error {\n\treturn x.ClientStream.SendMsg(m)\n}\n\nfunc (x *routeGuideRecordRouteClient) CloseAndRecv() (*RouteSummary, error) {\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\tm := new(RouteSummary)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *routeGuideClient) RouteChat(ctx context.Context, opts ...grpc.CallOption) (RouteGuide_RouteChatClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &RouteGuide_ServiceDesc.Streams[1], RouteGuide_RouteChat_FullMethodName, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &routeGuideRouteChatClient{stream}\n\treturn x, nil\n}\n\ntype RouteGuide_RouteChatClient interface {\n\tSend(*RouteNote) error\n\tRecv() (*RouteNote, error)\n\tgrpc.ClientStream\n}\n\ntype routeGuideRouteChatClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *routeGuideRouteChatClient) Send(m *RouteNote) error {\n\treturn x.ClientStream.SendMsg(m)\n}\n\nfunc (x *routeGuideRouteChatClient) Recv() (*RouteNote, error) {\n\tm := new(RouteNote)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// RouteGuideServer is the server API for RouteGuide service.\n// All implementations must embed UnimplementedRouteGuideServer\n// for forward compatibility\ntype RouteGuideServer interface {\n\t// A client-to-server streaming RPC.\n\t//\n\t// Accepts a stream of Points on a route being traversed, returning a\n\t// RouteSummary when traversal is completed.\n\tRecordRoute(RouteGuide_RecordRouteServer) error\n\t// A Bidirectional streaming RPC.\n\t//\n\t// Accepts a stream of RouteNotes sent while a route is being traversed,\n\t// while receiving other RouteNotes (e.g. from other users).\n\tRouteChat(RouteGuide_RouteChatServer) error\n\tmustEmbedUnimplementedRouteGuideServer()\n}\n\n// UnimplementedRouteGuideServer must be embedded to have forward compatible implementations.\ntype UnimplementedRouteGuideServer struct {\n}\n\nfunc (UnimplementedRouteGuideServer) RecordRoute(RouteGuide_RecordRouteServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method RecordRoute not implemented\")\n}\nfunc (UnimplementedRouteGuideServer) RouteChat(RouteGuide_RouteChatServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method RouteChat not implemented\")\n}\nfunc (UnimplementedRouteGuideServer) mustEmbedUnimplementedRouteGuideServer() {}\n\n// UnsafeRouteGuideServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to RouteGuideServer will\n// result in compilation errors.\ntype UnsafeRouteGuideServer interface {\n\tmustEmbedUnimplementedRouteGuideServer()\n}\n\nfunc RegisterRouteGuideServer(s grpc.ServiceRegistrar, srv RouteGuideServer) {\n\ts.RegisterService(&RouteGuide_ServiceDesc, srv)\n}\n\nfunc _RouteGuide_RecordRoute_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(RouteGuideServer).RecordRoute(&routeGuideRecordRouteServer{stream})\n}\n\ntype RouteGuide_RecordRouteServer interface {\n\tSendAndClose(*RouteSummary) error\n\tRecv() (*Point, error)\n\tgrpc.ServerStream\n}\n\ntype routeGuideRecordRouteServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *routeGuideRecordRouteServer) SendAndClose(m *RouteSummary) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc (x *routeGuideRecordRouteServer) Recv() (*Point, error) {\n\tm := new(Point)\n\tif err := x.ServerStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc _RouteGuide_RouteChat_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(RouteGuideServer).RouteChat(&routeGuideRouteChatServer{stream})\n}\n\ntype RouteGuide_RouteChatServer interface {\n\tSend(*RouteNote) error\n\tRecv() (*RouteNote, error)\n\tgrpc.ServerStream\n}\n\ntype routeGuideRouteChatServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *routeGuideRouteChatServer) Send(m *RouteNote) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc (x *routeGuideRouteChatServer) Recv() (*RouteNote, error) {\n\tm := new(RouteNote)\n\tif err := x.ServerStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// RouteGuide_ServiceDesc is the grpc.ServiceDesc for RouteGuide service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar RouteGuide_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"main.RouteGuide\",\n\tHandlerType: (*RouteGuideServer)(nil),\n\tMethods:     []grpc.MethodDesc{},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"RecordRoute\",\n\t\t\tHandler:       _RouteGuide_RecordRoute_Handler,\n\t\t\tClientStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"RouteChat\",\n\t\t\tHandler:       _RouteGuide_RouteChat_Handler,\n\t\t\tServerStreams: true,\n\t\t\tClientStreams: true,\n\t\t},\n\t},\n\tMetadata: \"route_guide.proto\",\n}\n"
  },
  {
    "path": "internal/lib/testutils/grpcservice/service.go",
    "content": "// Package grpcservice contains the implementation of the test GRPC service.\npackage grpcservice\n\nimport (\n\tcontext \"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math\"\n\t\"math/rand\" // nosemgrep: math-random-used // used to add random delay in calls\n\t\"os\"\n\tsync \"sync\"\n\t\"time\"\n\n\t\"google.golang.org/protobuf/proto\"\n)\n\n// It generates the Go code for protobuf and the gRPC server used by this implementation.\n// Check the following links for getting more details about protoc generation:\n// * https://grpc.io/docs/protoc-installation\n// * https://grpc.io/docs/languages/go/quickstart/\n//\n//\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative route_guide.proto\n\n// FeatureExplorerImplementation contains an implementation of the FeatureExplorer service.\ntype FeatureExplorerImplementation struct {\n\tLogf func(format string, v ...any)\n\tUnimplementedFeatureExplorerServer\n\tsavedFeatures []*Feature // read-only after initialized\n}\n\n// NewFeatureExplorerServer creates a FeatureExplorer server.\nfunc NewFeatureExplorerServer(features ...*Feature) *FeatureExplorerImplementation {\n\treturn &FeatureExplorerImplementation{savedFeatures: features, Logf: log.Printf}\n}\n\n// GetFeature returns the feature at the given point.\nfunc (s *FeatureExplorerImplementation) GetFeature(_ context.Context, point *Point) (*Feature, error) {\n\ts.Logf(\"GetFeature called with: %+v\\n\", point)\n\n\tn := rand.Intn(1000) //nolint:gosec\n\ttime.Sleep(time.Duration(n) * time.Millisecond)\n\n\tfor _, feature := range s.savedFeatures {\n\t\tif proto.Equal(feature.Location, point) {\n\t\t\treturn feature, nil\n\t\t}\n\t}\n\t// No feature was found, return an unnamed feature\n\treturn &Feature{Location: point}, nil\n}\n\n// ListFeatures lists all features contained within the given bounding Rectangle.\nfunc (s *FeatureExplorerImplementation) ListFeatures(rect *Rectangle, stream FeatureExplorer_ListFeaturesServer) error {\n\ts.Logf(\"ListFeatures called with: %+v\\n\", rect)\n\n\tfor _, feature := range s.savedFeatures {\n\t\tif inRange(feature.Location, rect) {\n\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\tif err := stream.Send(feature); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// RouteGuideImplementation contains an implementation of the RouteGuide service.\ntype RouteGuideImplementation struct {\n\tLogf func(format string, v ...any)\n\tUnimplementedRouteGuideServer\n\tsavedFeatures []*Feature // read-only after initialized\n\n\tmu         sync.Mutex // protects routeNotes\n\trouteNotes map[string][]*RouteNote\n}\n\n// NewRouteGuideServer creates a RouteGuide server.\nfunc NewRouteGuideServer(features ...*Feature) *RouteGuideImplementation {\n\ts := &RouteGuideImplementation{\n\t\tsavedFeatures: features,\n\t\trouteNotes:    make(map[string][]*RouteNote),\n\t\tLogf:          log.Printf,\n\t}\n\treturn s\n}\n\n// RecordRoute records a route composited of a sequence of points.\n//\n// It gets a stream of points, and responds with statistics about the \"trip\":\n// number of points,  number of known features visited, total distance traveled, and\n// total time spent.\nfunc (s *RouteGuideImplementation) RecordRoute(stream RouteGuide_RecordRouteServer) error {\n\ts.Logf(\"RecordRoute called\")\n\n\tvar pointCount, featureCount, distance int32\n\tvar lastPoint *Point\n\tstartTime := time.Now()\n\tfor {\n\t\tpoint, err := stream.Recv()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\tendTime := time.Now()\n\n\t\t\ts.Logf(\"RecordRoute finished, sending summary\")\n\n\t\t\terrClose := stream.SendAndClose(&RouteSummary{\n\t\t\t\tPointCount:   pointCount,\n\t\t\t\tFeatureCount: featureCount,\n\t\t\t\tDistance:     distance,\n\t\t\t\tElapsedTime:  int32(endTime.Sub(startTime).Seconds()),\n\t\t\t})\n\t\t\tif errClose != nil {\n\t\t\t\ts.Logf(\"Close error: %s\\n\", errClose)\n\t\t\t}\n\n\t\t\treturn errClose\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tpointCount++\n\t\tfor _, feature := range s.savedFeatures {\n\t\t\tif proto.Equal(feature.Location, point) {\n\t\t\t\tfeatureCount++\n\t\t\t}\n\t\t}\n\t\tif lastPoint != nil {\n\t\t\tdistance += calcDistance(lastPoint, point)\n\t\t}\n\t\tlastPoint = point\n\t}\n}\n\n// RouteChat receives a stream of message/location pairs, and responds with a stream of all\n// previous messages at each of those locations.\nfunc (s *RouteGuideImplementation) RouteChat(stream RouteGuide_RouteChatServer) error {\n\ts.Logf(\"RouteChat called\")\n\n\tfor {\n\t\tin, err := stream.Recv()\n\t\tif errors.Is(err, io.EOF) {\n\t\t\treturn nil\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tkey := serialize(in.Location)\n\n\t\ts.mu.Lock()\n\t\ts.routeNotes[key] = append(s.routeNotes[key], in)\n\t\t// Note: this copy prevents blocking other clients while serving this one.\n\t\t// We don't need to do a deep copy, because elements in the slice are\n\t\t// insert-only and never modified.\n\t\trn := make([]*RouteNote, len(s.routeNotes[key]))\n\t\tcopy(rn, s.routeNotes[key])\n\t\ts.mu.Unlock()\n\n\t\tfor _, note := range rn {\n\t\t\tif err := stream.Send(note); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n}\n\n// LoadFeatures loads features from a JSON file.\nfunc LoadFeatures(filePath string) []*Feature {\n\tvar data []byte\n\tif filePath != \"\" {\n\t\tvar err error\n\t\tdata, err = os.ReadFile(filePath) //nolint:forbidigo,gosec\n\t\tif err != nil {\n\t\t\tpanic(fmt.Sprintf(\"Failed to load default features: %v\", err))\n\t\t}\n\t} else {\n\t\tdata = []byte(exampleData)\n\t}\n\tvar features []*Feature\n\tif err := json.Unmarshal(data, &features); err != nil {\n\t\tpanic(fmt.Sprintf(\"Failed to load default features: %v\", err))\n\t}\n\treturn features\n}\n\nfunc toRadians(num float64) float64 {\n\treturn num * math.Pi / float64(180)\n}\n\n// calcDistance calculates the distance between two points using the \"haversine\" formula.\n// The formula is based on http://mathforum.org/library/drmath/view/51879.html.\nfunc calcDistance(p1 *Point, p2 *Point) int32 {\n\tconst CordFactor float64 = 1e7\n\tconst R = float64(6371000) // earth radius in metres\n\tlat1 := toRadians(float64(p1.Latitude) / CordFactor)\n\tlat2 := toRadians(float64(p2.Latitude) / CordFactor)\n\tlng1 := toRadians(float64(p1.Longitude) / CordFactor)\n\tlng2 := toRadians(float64(p2.Longitude) / CordFactor)\n\tdlat := lat2 - lat1\n\tdlng := lng2 - lng1\n\n\ta := math.Sin(dlat/2)*math.Sin(dlat/2) +\n\t\tmath.Cos(lat1)*math.Cos(lat2)*\n\t\t\tmath.Sin(dlng/2)*math.Sin(dlng/2)\n\tc := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))\n\n\tdistance := R * c\n\treturn int32(distance)\n}\n\nfunc inRange(point *Point, rect *Rectangle) bool {\n\tleft := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))\n\tright := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))\n\ttop := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))\n\tbottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))\n\n\tif float64(point.Longitude) >= left &&\n\t\tfloat64(point.Longitude) <= right &&\n\t\tfloat64(point.Latitude) >= bottom &&\n\t\tfloat64(point.Latitude) <= top {\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc serialize(point *Point) string {\n\treturn fmt.Sprintf(\"%d %d\", point.Latitude, point.Longitude)\n}\n\n// exampleData is a copy of testdata/route_guide_db.json. It's to avoid\n// specifying file path with `go run`.\nconst exampleData = `[{\n\t\"location\": {\n\t\t \"latitude\": 407838351,\n\t\t \"longitude\": -746143763\n\t},\n\t\"name\": \"Patriots Path, Mendham, NJ 07945, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 408122808,\n\t\t \"longitude\": -743999179\n\t},\n\t\"name\": \"101 New Jersey 10, Whippany, NJ 07981, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 413628156,\n\t\t \"longitude\": -749015468\n\t},\n\t\"name\": \"U.S. 6, Shohola, PA 18458, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 419999544,\n\t\t \"longitude\": -740371136\n\t},\n\t\"name\": \"5 Conners Road, Kingston, NY 12401, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 414008389,\n\t\t \"longitude\": -743951297\n\t},\n\t\"name\": \"Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 419611318,\n\t\t \"longitude\": -746524769\n\t},\n\t\"name\": \"287 Flugertown Road, Livingston Manor, NY 12758, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406109563,\n\t\t \"longitude\": -742186778\n\t},\n\t\"name\": \"4001 Tremley Point Road, Linden, NJ 07036, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 416802456,\n\t\t \"longitude\": -742370183\n\t},\n\t\"name\": \"352 South Mountain Road, Wallkill, NY 12589, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412950425,\n\t\t \"longitude\": -741077389\n\t},\n\t\"name\": \"Bailey Turn Road, Harriman, NY 10926, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412144655,\n\t\t \"longitude\": -743949739\n\t},\n\t\"name\": \"193-199 Wawayanda Road, Hewitt, NJ 07421, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 415736605,\n\t\t \"longitude\": -742847522\n\t},\n\t\"name\": \"406-496 Ward Avenue, Pine Bush, NY 12566, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 413843930,\n\t\t \"longitude\": -740501726\n\t},\n\t\"name\": \"162 Merrill Road, Highland Mills, NY 10930, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 410873075,\n\t\t \"longitude\": -744459023\n\t},\n\t\"name\": \"Clinton Road, West Milford, NJ 07480, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412346009,\n\t\t \"longitude\": -744026814\n\t},\n\t\"name\": \"16 Old Brook Lane, Warwick, NY 10990, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 402948455,\n\t\t \"longitude\": -747903913\n\t},\n\t\"name\": \"3 Drake Lane, Pennington, NJ 08534, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406337092,\n\t\t \"longitude\": -740122226\n\t},\n\t\"name\": \"6324 8th Avenue, Brooklyn, NY 11220, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406421967,\n\t\t \"longitude\": -747727624\n\t},\n\t\"name\": \"1 Merck Access Road, Whitehouse Station, NJ 08889, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 416318082,\n\t\t \"longitude\": -749677716\n\t},\n\t\"name\": \"78-98 Schalck Road, Narrowsburg, NY 12764, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 415301720,\n\t\t \"longitude\": -748416257\n\t},\n\t\"name\": \"282 Lakeview Drive Road, Highland Lake, NY 12743, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 402647019,\n\t\t \"longitude\": -747071791\n\t},\n\t\"name\": \"330 Evelyn Avenue, Hamilton Township, NJ 08619, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412567807,\n\t\t \"longitude\": -741058078\n\t},\n\t\"name\": \"New York State Reference Route 987E, Southfields, NY 10975, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 416855156,\n\t\t \"longitude\": -744420597\n\t},\n\t\"name\": \"103-271 Tempaloni Road, Ellenville, NY 12428, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404663628,\n\t\t \"longitude\": -744820157\n\t},\n\t\"name\": \"1300 Airport Road, North Brunswick Township, NJ 08902, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 407113723,\n\t\t \"longitude\": -749746483\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 402133926,\n\t\t \"longitude\": -743613249\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 400273442,\n\t\t \"longitude\": -741220915\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 411236786,\n\t\t \"longitude\": -744070769\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 411633782,\n\t\t \"longitude\": -746784970\n\t},\n\t\"name\": \"211-225 Plains Road, Augusta, NJ 07822, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 415830701,\n\t\t \"longitude\": -742952812\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 413447164,\n\t\t \"longitude\": -748712898\n\t},\n\t\"name\": \"165 Pedersen Ridge Road, Milford, PA 18337, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 405047245,\n\t\t \"longitude\": -749800722\n\t},\n\t\"name\": \"100-122 Locktown Road, Frenchtown, NJ 08825, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 418858923,\n\t\t \"longitude\": -746156790\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 417951888,\n\t\t \"longitude\": -748484944\n\t},\n\t\"name\": \"650-652 Willi Hill Road, Swan Lake, NY 12783, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 407033786,\n\t\t \"longitude\": -743977337\n\t},\n\t\"name\": \"26 East 3rd Street, New Providence, NJ 07974, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 417548014,\n\t\t \"longitude\": -740075041\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 410395868,\n\t\t \"longitude\": -744972325\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404615353,\n\t\t \"longitude\": -745129803\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406589790,\n\t\t \"longitude\": -743560121\n\t},\n\t\"name\": \"611 Lawrence Avenue, Westfield, NJ 07090, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 414653148,\n\t\t \"longitude\": -740477477\n\t},\n\t\"name\": \"18 Lannis Avenue, New Windsor, NY 12553, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 405957808,\n\t\t \"longitude\": -743255336\n\t},\n\t\"name\": \"82-104 Amherst Avenue, Colonia, NJ 07067, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 411733589,\n\t\t \"longitude\": -741648093\n\t},\n\t\"name\": \"170 Seven Lakes Drive, Sloatsburg, NY 10974, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412676291,\n\t\t \"longitude\": -742606606\n\t},\n\t\"name\": \"1270 Lakes Road, Monroe, NY 10950, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 409224445,\n\t\t \"longitude\": -748286738\n\t},\n\t\"name\": \"509-535 Alphano Road, Great Meadows, NJ 07838, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406523420,\n\t\t \"longitude\": -742135517\n\t},\n\t\"name\": \"652 Garden Street, Elizabeth, NJ 07202, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 401827388,\n\t\t \"longitude\": -740294537\n\t},\n\t\"name\": \"349 Sea Spray Court, Neptune City, NJ 07753, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 410564152,\n\t\t \"longitude\": -743685054\n\t},\n\t\"name\": \"13-17 Stanley Street, West Milford, NJ 07480, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 408472324,\n\t\t \"longitude\": -740726046\n\t},\n\t\"name\": \"47 Industrial Avenue, Teterboro, NJ 07608, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412452168,\n\t\t \"longitude\": -740214052\n\t},\n\t\"name\": \"5 White Oak Lane, Stony Point, NY 10980, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 409146138,\n\t\t \"longitude\": -746188906\n\t},\n\t\"name\": \"Berkshire Valley Management Area Trail, Jefferson, NJ, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404701380,\n\t\t \"longitude\": -744781745\n\t},\n\t\"name\": \"1007 Jersey Avenue, New Brunswick, NJ 08901, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 409642566,\n\t\t \"longitude\": -746017679\n\t},\n\t\"name\": \"6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 408031728,\n\t\t \"longitude\": -748645385\n\t},\n\t\"name\": \"1358-1474 New Jersey 57, Port Murray, NJ 07865, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 413700272,\n\t\t \"longitude\": -742135189\n\t},\n\t\"name\": \"367 Prospect Road, Chester, NY 10918, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404310607,\n\t\t \"longitude\": -740282632\n\t},\n\t\"name\": \"10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 409319800,\n\t\t \"longitude\": -746201391\n\t},\n\t\"name\": \"11 Ward Street, Mount Arlington, NJ 07856, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406685311,\n\t\t \"longitude\": -742108603\n\t},\n\t\"name\": \"300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 419018117,\n\t\t \"longitude\": -749142781\n\t},\n\t\"name\": \"43 Dreher Road, Roscoe, NY 12776, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412856162,\n\t\t \"longitude\": -745148837\n\t},\n\t\"name\": \"Swan Street, Pine Island, NY 10969, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 416560744,\n\t\t \"longitude\": -746721964\n\t},\n\t\"name\": \"66 Pleasantview Avenue, Monticello, NY 12701, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 405314270,\n\t\t \"longitude\": -749836354\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 414219548,\n\t\t \"longitude\": -743327440\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 415534177,\n\t\t \"longitude\": -742900616\n\t},\n\t\"name\": \"565 Winding Hills Road, Montgomery, NY 12549, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406898530,\n\t\t \"longitude\": -749127080\n\t},\n\t\"name\": \"231 Rocky Run Road, Glen Gardner, NJ 08826, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 407586880,\n\t\t \"longitude\": -741670168\n\t},\n\t\"name\": \"100 Mount Pleasant Avenue, Newark, NJ 07104, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 400106455,\n\t\t \"longitude\": -742870190\n\t},\n\t\"name\": \"517-521 Huntington Drive, Manchester Township, NJ 08759, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 400066188,\n\t\t \"longitude\": -746793294\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 418803880,\n\t\t \"longitude\": -744102673\n\t},\n\t\"name\": \"40 Mountain Road, Napanoch, NY 12458, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 414204288,\n\t\t \"longitude\": -747895140\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 414777405,\n\t\t \"longitude\": -740615601\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 415464475,\n\t\t \"longitude\": -747175374\n\t},\n\t\"name\": \"48 North Road, Forestburgh, NY 12777, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404062378,\n\t\t \"longitude\": -746376177\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 405688272,\n\t\t \"longitude\": -749285130\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 400342070,\n\t\t \"longitude\": -748788996\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 401809022,\n\t\t \"longitude\": -744157964\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404226644,\n\t\t \"longitude\": -740517141\n\t},\n\t\"name\": \"9 Thompson Avenue, Leonardo, NJ 07737, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 410322033,\n\t\t \"longitude\": -747871659\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 407100674,\n\t\t \"longitude\": -747742727\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 418811433,\n\t\t \"longitude\": -741718005\n\t},\n\t\"name\": \"213 Bush Road, Stone Ridge, NY 12484, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 415034302,\n\t\t \"longitude\": -743850945\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 411349992,\n\t\t \"longitude\": -743694161\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404839914,\n\t\t \"longitude\": -744759616\n\t},\n\t\"name\": \"1-17 Bergen Court, New Brunswick, NJ 08901, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 414638017,\n\t\t \"longitude\": -745957854\n\t},\n\t\"name\": \"35 Oakland Valley Road, Cuddebackville, NY 12729, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412127800,\n\t\t \"longitude\": -740173578\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 401263460,\n\t\t \"longitude\": -747964303\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 412843391,\n\t\t \"longitude\": -749086026\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 418512773,\n\t\t \"longitude\": -743067823\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404318328,\n\t\t \"longitude\": -740835638\n\t},\n\t\"name\": \"42-102 Main Street, Belford, NJ 07718, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 419020746,\n\t\t \"longitude\": -741172328\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404080723,\n\t\t \"longitude\": -746119569\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 401012643,\n\t\t \"longitude\": -744035134\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 404306372,\n\t\t \"longitude\": -741079661\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 403966326,\n\t\t \"longitude\": -748519297\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 405002031,\n\t\t \"longitude\": -748407866\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 409532885,\n\t\t \"longitude\": -742200683\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 416851321,\n\t\t \"longitude\": -742674555\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 406411633,\n\t\t \"longitude\": -741722051\n\t},\n\t\"name\": \"3387 Richmond Terrace, Staten Island, NY 10303, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 413069058,\n\t\t \"longitude\": -744597778\n\t},\n\t\"name\": \"261 Van Sickle Road, Goshen, NY 10924, USA\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 418465462,\n\t\t \"longitude\": -746859398\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 411733222,\n\t\t \"longitude\": -744228360\n\t},\n\t\"name\": \"\"\n}, {\n\t\"location\": {\n\t\t \"latitude\": 410248224,\n\t\t \"longitude\": -747127767\n\t},\n\t\"name\": \"3 Hasta Way, Newton, NJ 07860, USA\"\n}]`\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_any_testing/any_test.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.28.0\n// \tprotoc        v3.19.4\n// source: any_test.proto\n\npackage grpc_any_testing\n\nimport (\n\tcontext \"context\"\n\treflect \"reflect\"\n\tsync \"sync\"\n\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tanypb \"google.golang.org/protobuf/types/known/anypb\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype SumRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tData *anypb.Any `protobuf:\"bytes,1,opt,name=data,proto3\" json:\"data,omitempty\"`\n}\n\nfunc (x *SumRequest) Reset() {\n\t*x = SumRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_any_test_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SumRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SumRequest) ProtoMessage() {}\n\nfunc (x *SumRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_any_test_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SumRequest.ProtoReflect.Descriptor instead.\nfunc (*SumRequest) Descriptor() ([]byte, []int) {\n\treturn file_any_test_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *SumRequest) GetData() *anypb.Any {\n\tif x != nil {\n\t\treturn x.Data\n\t}\n\treturn nil\n}\n\ntype SumRequestData struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tA int64 `protobuf:\"varint,1,opt,name=a,proto3\" json:\"a,omitempty\"`\n\tB int64 `protobuf:\"varint,2,opt,name=b,proto3\" json:\"b,omitempty\"`\n}\n\nfunc (x *SumRequestData) Reset() {\n\t*x = SumRequestData{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_any_test_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SumRequestData) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SumRequestData) ProtoMessage() {}\n\nfunc (x *SumRequestData) ProtoReflect() protoreflect.Message {\n\tmi := &file_any_test_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SumRequestData.ProtoReflect.Descriptor instead.\nfunc (*SumRequestData) Descriptor() ([]byte, []int) {\n\treturn file_any_test_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *SumRequestData) GetA() int64 {\n\tif x != nil {\n\t\treturn x.A\n\t}\n\treturn 0\n}\n\nfunc (x *SumRequestData) GetB() int64 {\n\tif x != nil {\n\t\treturn x.B\n\t}\n\treturn 0\n}\n\ntype SumReply struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tData *anypb.Any `protobuf:\"bytes,1,opt,name=data,proto3\" json:\"data,omitempty\"`\n}\n\nfunc (x *SumReply) Reset() {\n\t*x = SumReply{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_any_test_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SumReply) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SumReply) ProtoMessage() {}\n\nfunc (x *SumReply) ProtoReflect() protoreflect.Message {\n\tmi := &file_any_test_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SumReply.ProtoReflect.Descriptor instead.\nfunc (*SumReply) Descriptor() ([]byte, []int) {\n\treturn file_any_test_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *SumReply) GetData() *anypb.Any {\n\tif x != nil {\n\t\treturn x.Data\n\t}\n\treturn nil\n}\n\ntype SumReplyData struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tV   int64  `protobuf:\"varint,1,opt,name=v,proto3\" json:\"v,omitempty\"`\n\tErr string `protobuf:\"bytes,2,opt,name=err,proto3\" json:\"err,omitempty\"`\n}\n\nfunc (x *SumReplyData) Reset() {\n\t*x = SumReplyData{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_any_test_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SumReplyData) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SumReplyData) ProtoMessage() {}\n\nfunc (x *SumReplyData) ProtoReflect() protoreflect.Message {\n\tmi := &file_any_test_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SumReplyData.ProtoReflect.Descriptor instead.\nfunc (*SumReplyData) Descriptor() ([]byte, []int) {\n\treturn file_any_test_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *SumReplyData) GetV() int64 {\n\tif x != nil {\n\t\treturn x.V\n\t}\n\treturn 0\n}\n\nfunc (x *SumReplyData) GetErr() string {\n\tif x != nil {\n\t\treturn x.Err\n\t}\n\treturn \"\"\n}\n\nvar File_any_test_proto protoreflect.FileDescriptor\n\nvar file_any_test_proto_rawDesc = []byte{\n\t0x0a, 0x0e, 0x61, 0x6e, 0x79, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x12, 0x10, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x6e, 0x79, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69,\n\t0x6e, 0x67, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x36, 0x0a,\n\t0x0a, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x04, 0x64,\n\t0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67,\n\t0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52,\n\t0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2c, 0x0a, 0x0e, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75,\n\t0x65, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0c, 0x0a, 0x01, 0x61, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x03, 0x52, 0x01, 0x61, 0x12, 0x0c, 0x0a, 0x01, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,\n\t0x52, 0x01, 0x62, 0x22, 0x34, 0x0a, 0x08, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,\n\t0x28, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,\n\t0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,\n\t0x41, 0x6e, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2e, 0x0a, 0x0c, 0x53, 0x75, 0x6d,\n\t0x52, 0x65, 0x70, 0x6c, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x03, 0x52, 0x01, 0x76, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x72, 0x72, 0x18, 0x02,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x72, 0x72, 0x32, 0x53, 0x0a, 0x0e, 0x41, 0x6e, 0x79,\n\t0x54, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x03, 0x53,\n\t0x75, 0x6d, 0x12, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x6e, 0x79, 0x2e, 0x74, 0x65,\n\t0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,\n\t0x1a, 0x1a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x61, 0x6e, 0x79, 0x2e, 0x74, 0x65, 0x73, 0x74,\n\t0x69, 0x6e, 0x67, 0x2e, 0x53, 0x75, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x14,\n\t0x5a, 0x12, 0x2e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x6e, 0x79, 0x5f, 0x74, 0x65, 0x73,\n\t0x74, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_any_test_proto_rawDescOnce sync.Once\n\tfile_any_test_proto_rawDescData = file_any_test_proto_rawDesc\n)\n\nfunc file_any_test_proto_rawDescGZIP() []byte {\n\tfile_any_test_proto_rawDescOnce.Do(func() {\n\t\tfile_any_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_any_test_proto_rawDescData)\n\t})\n\treturn file_any_test_proto_rawDescData\n}\n\nvar file_any_test_proto_msgTypes = make([]protoimpl.MessageInfo, 4)\nvar file_any_test_proto_goTypes = []interface{}{\n\t(*SumRequest)(nil),     // 0: grpc.any.testing.SumRequest\n\t(*SumRequestData)(nil), // 1: grpc.any.testing.SumRequestData\n\t(*SumReply)(nil),       // 2: grpc.any.testing.SumReply\n\t(*SumReplyData)(nil),   // 3: grpc.any.testing.SumReplyData\n\t(*anypb.Any)(nil),      // 4: google.protobuf.Any\n}\nvar file_any_test_proto_depIdxs = []int32{\n\t4, // 0: grpc.any.testing.SumRequest.data:type_name -> google.protobuf.Any\n\t4, // 1: grpc.any.testing.SumReply.data:type_name -> google.protobuf.Any\n\t0, // 2: grpc.any.testing.AnyTestService.Sum:input_type -> grpc.any.testing.SumRequest\n\t2, // 3: grpc.any.testing.AnyTestService.Sum:output_type -> grpc.any.testing.SumReply\n\t3, // [3:4] is the sub-list for method output_type\n\t2, // [2:3] is the sub-list for method input_type\n\t2, // [2:2] is the sub-list for extension type_name\n\t2, // [2:2] is the sub-list for extension extendee\n\t0, // [0:2] is the sub-list for field type_name\n}\n\nfunc init() { file_any_test_proto_init() }\nfunc file_any_test_proto_init() {\n\tif File_any_test_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_any_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SumRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_any_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SumRequestData); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_any_test_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SumReply); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_any_test_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SumReplyData); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_any_test_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   4,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_any_test_proto_goTypes,\n\t\tDependencyIndexes: file_any_test_proto_depIdxs,\n\t\tMessageInfos:      file_any_test_proto_msgTypes,\n\t}.Build()\n\tFile_any_test_proto = out.File\n\tfile_any_test_proto_rawDesc = nil\n\tfile_any_test_proto_goTypes = nil\n\tfile_any_test_proto_depIdxs = nil\n}\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ context.Context\nvar _ grpc.ClientConnInterface\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion6\n\n// AnyTestServiceClient is the client API for AnyTestService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.\ntype AnyTestServiceClient interface {\n\tSum(ctx context.Context, in *SumRequest, opts ...grpc.CallOption) (*SumReply, error)\n}\n\ntype anyTestServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewAnyTestServiceClient(cc grpc.ClientConnInterface) AnyTestServiceClient {\n\treturn &anyTestServiceClient{cc}\n}\n\nfunc (c *anyTestServiceClient) Sum(ctx context.Context, in *SumRequest, opts ...grpc.CallOption) (*SumReply, error) {\n\tout := new(SumReply)\n\terr := c.cc.Invoke(ctx, \"/grpc.any.testing.AnyTestService/Sum\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// AnyTestServiceServer is the server API for AnyTestService service.\ntype AnyTestServiceServer interface {\n\tSum(context.Context, *SumRequest) (*SumReply, error)\n}\n\n// UnimplementedAnyTestServiceServer can be embedded to have forward compatible implementations.\ntype UnimplementedAnyTestServiceServer struct {\n}\n\nfunc (*UnimplementedAnyTestServiceServer) Sum(context.Context, *SumRequest) (*SumReply, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Sum not implemented\")\n}\n\nfunc RegisterAnyTestServiceServer(s *grpc.Server, srv AnyTestServiceServer) {\n\ts.RegisterService(&_AnyTestService_serviceDesc, srv)\n}\n\nfunc _AnyTestService_Sum_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(SumRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(AnyTestServiceServer).Sum(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/grpc.any.testing.AnyTestService/Sum\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(AnyTestServiceServer).Sum(ctx, req.(*SumRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _AnyTestService_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"grpc.any.testing.AnyTestService\",\n\tHandlerType: (*AnyTestServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"Sum\",\n\t\t\tHandler:    _AnyTestService_Sum_Handler,\n\t\t},\n\t},\n\tStreams:  []grpc.StreamDesc{},\n\tMetadata: \"any_test.proto\",\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_any_testing/any_test.proto",
    "content": "\n\nsyntax = \"proto3\";\n\npackage grpc.any.testing;\n\nimport \"google/protobuf/any.proto\";\n\noption go_package =\"./grpc_any_testing\";\n\nservice AnyTestService {\n\trpc Sum (SumRequest) returns (SumReply) {}\n}\n\nmessage SumRequest {\n\tgoogle.protobuf.Any data = 1;\n}\n\nmessage SumRequestData {\n\tint64 a = 1;\n\tint64 b = 2;\n}\n\nmessage SumReply {\n\tgoogle.protobuf.Any data = 1;\n}\n\nmessage SumReplyData {\n\tint64 v = 1;\n\tstring err = 2;\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_protoset_testing/test_message.proto",
    "content": "syntax = \"proto3\";\n\npackage grpc.protoset.testing;\n\noption go_package =\"./grpc_protoset_testing\";\n\nmessage TestMessage {\n\tstring data = 1;\n\tint32 other_data = 2;\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_protoset_testing/test_service.proto",
    "content": "syntax = \"proto3\";\n\npackage grpc.protoset.testing;\n\noption go_package =\"./grpc_protoset_testing\";\n\nimport \"test_message.proto\";\n\nservice TestService {\n\trpc Test (TestRequest) returns (TestReply) {}\n}\n\nmessage TestRequest {\n\tTestMessage msg = 1;\n}\n\nmessage TestReply {\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_testing/nested_types.proto",
    "content": "// The purpose of this proto file is to demonstrate that we can have\n// nested types and that we should be able to load them correctly.\n\nsyntax = \"proto3\";\n\npackage grpc.testing;\n\n// Example to demonstrate that it is possible to define\n// and use message types within other message types\nmessage Outer {      // Level 0\n  message MiddleAA { // Level 1\n    message Inner {  // Level 2\n      int64 ival = 1;\n      bool booly = 2;\n    }\n    Inner inner = 1;\n  }\n\n  message MiddleBB { // Level 1\n    message Inner {  // Level 2\n      int32 ival = 1;\n      bool booly = 2;\n    }\n    Inner inner = 1;\n  }\n\n  MiddleAA middleAA = 1;\n  MiddleBB middleBB = 2;\n}\n\n// Example to demonstrate that it is possible to reuse\n// a message type outside its parent message type\nmessage MeldOuter {\n  Outer.MiddleAA.Inner innerAA = 1;\n  Outer.MiddleBB.Inner innerBB = 2;\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_testing/test.pb.go",
    "content": "// Copyright 2017 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// An integration test service that covers all the method signature permutations\n// of unary/streaming requests/responses.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.28.1\n// \tprotoc        v3.14.0\n// source: test/grpc_testing/test.proto\n\npackage grpc_testing\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The type of payload that should be returned.\ntype PayloadType int32\n\nconst (\n\t// Compressable text format.\n\tPayloadType_COMPRESSABLE PayloadType = 0\n\t// Uncompressable binary format.\n\tPayloadType_UNCOMPRESSABLE PayloadType = 1\n\t// Randomly chosen from all other formats defined in this enum.\n\tPayloadType_RANDOM PayloadType = 2\n)\n\n// Enum value maps for PayloadType.\nvar (\n\tPayloadType_name = map[int32]string{\n\t\t0: \"COMPRESSABLE\",\n\t\t1: \"UNCOMPRESSABLE\",\n\t\t2: \"RANDOM\",\n\t}\n\tPayloadType_value = map[string]int32{\n\t\t\"COMPRESSABLE\":   0,\n\t\t\"UNCOMPRESSABLE\": 1,\n\t\t\"RANDOM\":         2,\n\t}\n)\n\nfunc (x PayloadType) Enum() *PayloadType {\n\tp := new(PayloadType)\n\t*p = x\n\treturn p\n}\n\nfunc (x PayloadType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (PayloadType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_test_grpc_testing_test_proto_enumTypes[0].Descriptor()\n}\n\nfunc (PayloadType) Type() protoreflect.EnumType {\n\treturn &file_test_grpc_testing_test_proto_enumTypes[0]\n}\n\nfunc (x PayloadType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use PayloadType.Descriptor instead.\nfunc (PayloadType) EnumDescriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{0}\n}\n\ntype Empty struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n}\n\nfunc (x *Empty) Reset() {\n\t*x = Empty{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Empty) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Empty) ProtoMessage() {}\n\nfunc (x *Empty) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Empty.ProtoReflect.Descriptor instead.\nfunc (*Empty) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{0}\n}\n\n// A block of data, to simply increase gRPC message size.\ntype Payload struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// The type of data in body.\n\tType PayloadType `protobuf:\"varint,1,opt,name=type,proto3,enum=grpc.testing.PayloadType\" json:\"type,omitempty\"`\n\t// Primary contents of payload.\n\tBody []byte `protobuf:\"bytes,2,opt,name=body,proto3\" json:\"body,omitempty\"`\n}\n\nfunc (x *Payload) Reset() {\n\t*x = Payload{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Payload) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Payload) ProtoMessage() {}\n\nfunc (x *Payload) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Payload.ProtoReflect.Descriptor instead.\nfunc (*Payload) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Payload) GetType() PayloadType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn PayloadType_COMPRESSABLE\n}\n\nfunc (x *Payload) GetBody() []byte {\n\tif x != nil {\n\t\treturn x.Body\n\t}\n\treturn nil\n}\n\n// Unary request.\ntype SimpleRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Desired payload type in the response from the server.\n\t// If response_type is RANDOM, server randomly chooses one from other formats.\n\tResponseType PayloadType `protobuf:\"varint,1,opt,name=response_type,json=responseType,proto3,enum=grpc.testing.PayloadType\" json:\"response_type,omitempty\"`\n\t// Desired payload size in the response from the server.\n\t// If response_type is COMPRESSABLE, this denotes the size before compression.\n\tResponseSize int32 `protobuf:\"varint,2,opt,name=response_size,json=responseSize,proto3\" json:\"response_size,omitempty\"`\n\t// Optional input payload sent along with the request.\n\tPayload *Payload `protobuf:\"bytes,3,opt,name=payload,proto3\" json:\"payload,omitempty\"`\n\t// Whether SimpleResponse should include username.\n\tFillUsername bool `protobuf:\"varint,4,opt,name=fill_username,json=fillUsername,proto3\" json:\"fill_username,omitempty\"`\n\t// Whether SimpleResponse should include OAuth scope.\n\tFillOauthScope bool `protobuf:\"varint,5,opt,name=fill_oauth_scope,json=fillOauthScope,proto3\" json:\"fill_oauth_scope,omitempty\"`\n}\n\nfunc (x *SimpleRequest) Reset() {\n\t*x = SimpleRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SimpleRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SimpleRequest) ProtoMessage() {}\n\nfunc (x *SimpleRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SimpleRequest.ProtoReflect.Descriptor instead.\nfunc (*SimpleRequest) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *SimpleRequest) GetResponseType() PayloadType {\n\tif x != nil {\n\t\treturn x.ResponseType\n\t}\n\treturn PayloadType_COMPRESSABLE\n}\n\nfunc (x *SimpleRequest) GetResponseSize() int32 {\n\tif x != nil {\n\t\treturn x.ResponseSize\n\t}\n\treturn 0\n}\n\nfunc (x *SimpleRequest) GetPayload() *Payload {\n\tif x != nil {\n\t\treturn x.Payload\n\t}\n\treturn nil\n}\n\nfunc (x *SimpleRequest) GetFillUsername() bool {\n\tif x != nil {\n\t\treturn x.FillUsername\n\t}\n\treturn false\n}\n\nfunc (x *SimpleRequest) GetFillOauthScope() bool {\n\tif x != nil {\n\t\treturn x.FillOauthScope\n\t}\n\treturn false\n}\n\n// Unary response, as configured by the request.\ntype SimpleResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Payload to increase message size.\n\tPayload *Payload `protobuf:\"bytes,1,opt,name=payload,proto3\" json:\"payload,omitempty\"`\n\t// The user the request came from, for verifying authentication was\n\t// successful when the client expected it.\n\tUsername string `protobuf:\"bytes,2,opt,name=username,proto3\" json:\"username,omitempty\"`\n\t// OAuth scope.\n\tOauthScope string `protobuf:\"bytes,3,opt,name=oauth_scope,json=oauthScope,proto3\" json:\"oauth_scope,omitempty\"`\n}\n\nfunc (x *SimpleResponse) Reset() {\n\t*x = SimpleResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *SimpleResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*SimpleResponse) ProtoMessage() {}\n\nfunc (x *SimpleResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use SimpleResponse.ProtoReflect.Descriptor instead.\nfunc (*SimpleResponse) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *SimpleResponse) GetPayload() *Payload {\n\tif x != nil {\n\t\treturn x.Payload\n\t}\n\treturn nil\n}\n\nfunc (x *SimpleResponse) GetUsername() string {\n\tif x != nil {\n\t\treturn x.Username\n\t}\n\treturn \"\"\n}\n\nfunc (x *SimpleResponse) GetOauthScope() string {\n\tif x != nil {\n\t\treturn x.OauthScope\n\t}\n\treturn \"\"\n}\n\n// Client-streaming request.\ntype StreamingInputCallRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Optional input payload sent along with the request.\n\tPayload *Payload `protobuf:\"bytes,1,opt,name=payload,proto3\" json:\"payload,omitempty\"`\n}\n\nfunc (x *StreamingInputCallRequest) Reset() {\n\t*x = StreamingInputCallRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *StreamingInputCallRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StreamingInputCallRequest) ProtoMessage() {}\n\nfunc (x *StreamingInputCallRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StreamingInputCallRequest.ProtoReflect.Descriptor instead.\nfunc (*StreamingInputCallRequest) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *StreamingInputCallRequest) GetPayload() *Payload {\n\tif x != nil {\n\t\treturn x.Payload\n\t}\n\treturn nil\n}\n\n// Client-streaming response.\ntype StreamingInputCallResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Aggregated size of payloads received from the client.\n\tAggregatedPayloadSize int32 `protobuf:\"varint,1,opt,name=aggregated_payload_size,json=aggregatedPayloadSize,proto3\" json:\"aggregated_payload_size,omitempty\"`\n}\n\nfunc (x *StreamingInputCallResponse) Reset() {\n\t*x = StreamingInputCallResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *StreamingInputCallResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StreamingInputCallResponse) ProtoMessage() {}\n\nfunc (x *StreamingInputCallResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StreamingInputCallResponse.ProtoReflect.Descriptor instead.\nfunc (*StreamingInputCallResponse) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *StreamingInputCallResponse) GetAggregatedPayloadSize() int32 {\n\tif x != nil {\n\t\treturn x.AggregatedPayloadSize\n\t}\n\treturn 0\n}\n\n// Configuration for a particular response.\ntype ResponseParameters struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Desired payload sizes in responses from the server.\n\t// If response_type is COMPRESSABLE, this denotes the size before compression.\n\tSize int32 `protobuf:\"varint,1,opt,name=size,proto3\" json:\"size,omitempty\"`\n\t// Desired interval between consecutive responses in the response stream in\n\t// microseconds.\n\tIntervalUs int32 `protobuf:\"varint,2,opt,name=interval_us,json=intervalUs,proto3\" json:\"interval_us,omitempty\"`\n}\n\nfunc (x *ResponseParameters) Reset() {\n\t*x = ResponseParameters{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *ResponseParameters) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ResponseParameters) ProtoMessage() {}\n\nfunc (x *ResponseParameters) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use ResponseParameters.ProtoReflect.Descriptor instead.\nfunc (*ResponseParameters) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *ResponseParameters) GetSize() int32 {\n\tif x != nil {\n\t\treturn x.Size\n\t}\n\treturn 0\n}\n\nfunc (x *ResponseParameters) GetIntervalUs() int32 {\n\tif x != nil {\n\t\treturn x.IntervalUs\n\t}\n\treturn 0\n}\n\n// Server-streaming request.\ntype StreamingOutputCallRequest struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Desired payload type in the response from the server.\n\t// If response_type is RANDOM, the payload from each response in the stream\n\t// might be of different types. This is to simulate a mixed type of payload\n\t// stream.\n\tResponseType PayloadType `protobuf:\"varint,1,opt,name=response_type,json=responseType,proto3,enum=grpc.testing.PayloadType\" json:\"response_type,omitempty\"`\n\t// Configuration for each expected response message.\n\tResponseParameters []*ResponseParameters `protobuf:\"bytes,2,rep,name=response_parameters,json=responseParameters,proto3\" json:\"response_parameters,omitempty\"`\n\t// Optional input payload sent along with the request.\n\tPayload *Payload `protobuf:\"bytes,3,opt,name=payload,proto3\" json:\"payload,omitempty\"`\n}\n\nfunc (x *StreamingOutputCallRequest) Reset() {\n\t*x = StreamingOutputCallRequest{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *StreamingOutputCallRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StreamingOutputCallRequest) ProtoMessage() {}\n\nfunc (x *StreamingOutputCallRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StreamingOutputCallRequest.ProtoReflect.Descriptor instead.\nfunc (*StreamingOutputCallRequest) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *StreamingOutputCallRequest) GetResponseType() PayloadType {\n\tif x != nil {\n\t\treturn x.ResponseType\n\t}\n\treturn PayloadType_COMPRESSABLE\n}\n\nfunc (x *StreamingOutputCallRequest) GetResponseParameters() []*ResponseParameters {\n\tif x != nil {\n\t\treturn x.ResponseParameters\n\t}\n\treturn nil\n}\n\nfunc (x *StreamingOutputCallRequest) GetPayload() *Payload {\n\tif x != nil {\n\t\treturn x.Payload\n\t}\n\treturn nil\n}\n\n// Server-streaming response, as configured by the request and parameters.\ntype StreamingOutputCallResponse struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Payload to increase response size.\n\tPayload *Payload `protobuf:\"bytes,1,opt,name=payload,proto3\" json:\"payload,omitempty\"`\n}\n\nfunc (x *StreamingOutputCallResponse) Reset() {\n\t*x = StreamingOutputCallResponse{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_test_grpc_testing_test_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *StreamingOutputCallResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*StreamingOutputCallResponse) ProtoMessage() {}\n\nfunc (x *StreamingOutputCallResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_test_grpc_testing_test_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use StreamingOutputCallResponse.ProtoReflect.Descriptor instead.\nfunc (*StreamingOutputCallResponse) Descriptor() ([]byte, []int) {\n\treturn file_test_grpc_testing_test_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *StreamingOutputCallResponse) GetPayload() *Payload {\n\tif x != nil {\n\t\treturn x.Payload\n\t}\n\treturn nil\n}\n\nvar File_test_grpc_testing_test_proto protoreflect.FileDescriptor\n\nvar file_test_grpc_testing_test_proto_rawDesc = []byte{\n\t0x0a, 0x1c, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x74, 0x65, 0x73, 0x74,\n\t0x69, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c,\n\t0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x07, 0x0a, 0x05,\n\t0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x4c, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,\n\t0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19,\n\t0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61,\n\t0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12,\n\t0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62,\n\t0x6f, 0x64, 0x79, 0x22, 0xf4, 0x01, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65,\n\t0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x67,\n\t0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x79, 0x6c,\n\t0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x72, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61,\n\t0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72,\n\t0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f,\n\t0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x66,\n\t0x69, 0x6c, 0x6c, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01,\n\t0x28, 0x08, 0x52, 0x0c, 0x66, 0x69, 0x6c, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65,\n\t0x12, 0x28, 0x0a, 0x10, 0x66, 0x69, 0x6c, 0x6c, 0x5f, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x73,\n\t0x63, 0x6f, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x6c,\n\t0x4f, 0x61, 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x22, 0x7e, 0x0a, 0x0e, 0x53, 0x69,\n\t0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07,\n\t0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,\n\t0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x79,\n\t0x6c, 0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1a, 0x0a,\n\t0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,\n\t0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x61, 0x75,\n\t0x74, 0x68, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,\n\t0x6f, 0x61, 0x75, 0x74, 0x68, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x22, 0x4c, 0x0a, 0x19, 0x53, 0x74,\n\t0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c,\n\t0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f,\n\t0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e,\n\t0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52,\n\t0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x54, 0x0a, 0x1a, 0x53, 0x74, 0x72, 0x65,\n\t0x61, 0x6d, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65,\n\t0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,\n\t0x61, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x69, 0x7a,\n\t0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61,\n\t0x74, 0x65, 0x64, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x49,\n\t0x0a, 0x12, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65,\n\t0x74, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01,\n\t0x28, 0x05, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65,\n\t0x72, 0x76, 0x61, 0x6c, 0x5f, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x69,\n\t0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x55, 0x73, 0x22, 0xe0, 0x01, 0x0a, 0x1a, 0x53, 0x74,\n\t0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c,\n\t0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,\n\t0x19, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50,\n\t0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x51, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x70,\n\t0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18,\n\t0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73,\n\t0x74, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x72,\n\t0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x12, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,\n\t0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x0a, 0x07, 0x70,\n\t0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67,\n\t0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x79, 0x6c,\n\t0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x4e, 0x0a, 0x1b,\n\t0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43,\n\t0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x70,\n\t0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67,\n\t0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x61, 0x79, 0x6c,\n\t0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2a, 0x3f, 0x0a, 0x0b,\n\t0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x43,\n\t0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x12, 0x0a,\n\t0x0e, 0x55, 0x4e, 0x43, 0x4f, 0x4d, 0x50, 0x52, 0x45, 0x53, 0x53, 0x41, 0x42, 0x4c, 0x45, 0x10,\n\t0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x41, 0x4e, 0x44, 0x4f, 0x4d, 0x10, 0x02, 0x32, 0xbb, 0x04,\n\t0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x35, 0x0a,\n\t0x09, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x70,\n\t0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,\n\t0x13, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x45,\n\t0x6d, 0x70, 0x74, 0x79, 0x12, 0x46, 0x0a, 0x09, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x43, 0x61, 0x6c,\n\t0x6c, 0x12, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67,\n\t0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c,\n\t0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x69,\n\t0x6d, 0x70, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13,\n\t0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43,\n\t0x61, 0x6c, 0x6c, 0x12, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69,\n\t0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70,\n\t0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e,\n\t0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72,\n\t0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c,\n\t0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x69, 0x0a, 0x12, 0x53, 0x74,\n\t0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c,\n\t0x12, 0x27, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e,\n\t0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x43, 0x61,\n\t0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63,\n\t0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69,\n\t0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f,\n\t0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x69, 0x0a, 0x0e, 0x46, 0x75, 0x6c, 0x6c, 0x44, 0x75, 0x70,\n\t0x6c, 0x65, 0x78, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74,\n\t0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67,\n\t0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,\n\t0x74, 0x1a, 0x29, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67,\n\t0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74,\n\t0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01,\n\t0x12, 0x69, 0x0a, 0x0e, 0x48, 0x61, 0x6c, 0x66, 0x44, 0x75, 0x70, 0x6c, 0x65, 0x78, 0x43, 0x61,\n\t0x6c, 0x6c, 0x12, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e,\n\t0x67, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75,\n\t0x74, 0x43, 0x61, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x67,\n\t0x72, 0x70, 0x63, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x53, 0x74, 0x72, 0x65,\n\t0x61, 0x6d, 0x69, 0x6e, 0x67, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x43, 0x61, 0x6c, 0x6c, 0x52,\n\t0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2a, 0x5a, 0x28, 0x67,\n\t0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67,\n\t0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f,\n\t0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_test_grpc_testing_test_proto_rawDescOnce sync.Once\n\tfile_test_grpc_testing_test_proto_rawDescData = file_test_grpc_testing_test_proto_rawDesc\n)\n\nfunc file_test_grpc_testing_test_proto_rawDescGZIP() []byte {\n\tfile_test_grpc_testing_test_proto_rawDescOnce.Do(func() {\n\t\tfile_test_grpc_testing_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_grpc_testing_test_proto_rawDescData)\n\t})\n\treturn file_test_grpc_testing_test_proto_rawDescData\n}\n\nvar file_test_grpc_testing_test_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_test_grpc_testing_test_proto_msgTypes = make([]protoimpl.MessageInfo, 9)\nvar file_test_grpc_testing_test_proto_goTypes = []interface{}{\n\t(PayloadType)(0),                    // 0: grpc.testing.PayloadType\n\t(*Empty)(nil),                       // 1: grpc.testing.Empty\n\t(*Payload)(nil),                     // 2: grpc.testing.Payload\n\t(*SimpleRequest)(nil),               // 3: grpc.testing.SimpleRequest\n\t(*SimpleResponse)(nil),              // 4: grpc.testing.SimpleResponse\n\t(*StreamingInputCallRequest)(nil),   // 5: grpc.testing.StreamingInputCallRequest\n\t(*StreamingInputCallResponse)(nil),  // 6: grpc.testing.StreamingInputCallResponse\n\t(*ResponseParameters)(nil),          // 7: grpc.testing.ResponseParameters\n\t(*StreamingOutputCallRequest)(nil),  // 8: grpc.testing.StreamingOutputCallRequest\n\t(*StreamingOutputCallResponse)(nil), // 9: grpc.testing.StreamingOutputCallResponse\n}\nvar file_test_grpc_testing_test_proto_depIdxs = []int32{\n\t0,  // 0: grpc.testing.Payload.type:type_name -> grpc.testing.PayloadType\n\t0,  // 1: grpc.testing.SimpleRequest.response_type:type_name -> grpc.testing.PayloadType\n\t2,  // 2: grpc.testing.SimpleRequest.payload:type_name -> grpc.testing.Payload\n\t2,  // 3: grpc.testing.SimpleResponse.payload:type_name -> grpc.testing.Payload\n\t2,  // 4: grpc.testing.StreamingInputCallRequest.payload:type_name -> grpc.testing.Payload\n\t0,  // 5: grpc.testing.StreamingOutputCallRequest.response_type:type_name -> grpc.testing.PayloadType\n\t7,  // 6: grpc.testing.StreamingOutputCallRequest.response_parameters:type_name -> grpc.testing.ResponseParameters\n\t2,  // 7: grpc.testing.StreamingOutputCallRequest.payload:type_name -> grpc.testing.Payload\n\t2,  // 8: grpc.testing.StreamingOutputCallResponse.payload:type_name -> grpc.testing.Payload\n\t1,  // 9: grpc.testing.TestService.EmptyCall:input_type -> grpc.testing.Empty\n\t3,  // 10: grpc.testing.TestService.UnaryCall:input_type -> grpc.testing.SimpleRequest\n\t8,  // 11: grpc.testing.TestService.StreamingOutputCall:input_type -> grpc.testing.StreamingOutputCallRequest\n\t5,  // 12: grpc.testing.TestService.StreamingInputCall:input_type -> grpc.testing.StreamingInputCallRequest\n\t8,  // 13: grpc.testing.TestService.FullDuplexCall:input_type -> grpc.testing.StreamingOutputCallRequest\n\t8,  // 14: grpc.testing.TestService.HalfDuplexCall:input_type -> grpc.testing.StreamingOutputCallRequest\n\t1,  // 15: grpc.testing.TestService.EmptyCall:output_type -> grpc.testing.Empty\n\t4,  // 16: grpc.testing.TestService.UnaryCall:output_type -> grpc.testing.SimpleResponse\n\t9,  // 17: grpc.testing.TestService.StreamingOutputCall:output_type -> grpc.testing.StreamingOutputCallResponse\n\t6,  // 18: grpc.testing.TestService.StreamingInputCall:output_type -> grpc.testing.StreamingInputCallResponse\n\t9,  // 19: grpc.testing.TestService.FullDuplexCall:output_type -> grpc.testing.StreamingOutputCallResponse\n\t9,  // 20: grpc.testing.TestService.HalfDuplexCall:output_type -> grpc.testing.StreamingOutputCallResponse\n\t15, // [15:21] is the sub-list for method output_type\n\t9,  // [9:15] is the sub-list for method input_type\n\t9,  // [9:9] is the sub-list for extension type_name\n\t9,  // [9:9] is the sub-list for extension extendee\n\t0,  // [0:9] is the sub-list for field type_name\n}\n\nfunc init() { file_test_grpc_testing_test_proto_init() }\nfunc file_test_grpc_testing_test_proto_init() {\n\tif File_test_grpc_testing_test_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_test_grpc_testing_test_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Empty); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Payload); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SimpleRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*SimpleResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*StreamingInputCallRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*StreamingInputCallResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*ResponseParameters); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*StreamingOutputCallRequest); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_test_grpc_testing_test_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*StreamingOutputCallResponse); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_test_grpc_testing_test_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   9,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_test_grpc_testing_test_proto_goTypes,\n\t\tDependencyIndexes: file_test_grpc_testing_test_proto_depIdxs,\n\t\tEnumInfos:         file_test_grpc_testing_test_proto_enumTypes,\n\t\tMessageInfos:      file_test_grpc_testing_test_proto_msgTypes,\n\t}.Build()\n\tFile_test_grpc_testing_test_proto = out.File\n\tfile_test_grpc_testing_test_proto_rawDesc = nil\n\tfile_test_grpc_testing_test_proto_goTypes = nil\n\tfile_test_grpc_testing_test_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_testing/test.proto",
    "content": "// Copyright 2017 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// An integration test service that covers all the method signature permutations\n// of unary/streaming requests/responses.\nsyntax = \"proto3\";\n\noption go_package = \"./grpc_testing\";\n\npackage grpc.testing;\n\nmessage Empty {}\n\n// The type of payload that should be returned.\nenum PayloadType {\n  // Compressable text format.\n  COMPRESSABLE = 0;\n\n  // Uncompressable binary format.\n  UNCOMPRESSABLE = 1;\n\n  // Randomly chosen from all other formats defined in this enum.\n  RANDOM = 2;\n}\n\n// A block of data, to simply increase gRPC message size.\nmessage Payload {\n  // The type of data in body.\n  PayloadType type = 1;\n  // Primary contents of payload.\n  bytes body = 2;\n}\n\n// Unary request.\nmessage SimpleRequest {\n  // Desired payload type in the response from the server.\n  // If response_type is RANDOM, server randomly chooses one from other formats.\n  PayloadType response_type = 1;\n\n  // Desired payload size in the response from the server.\n  // If response_type is COMPRESSABLE, this denotes the size before compression.\n  int32 response_size = 2;\n\n  // Optional input payload sent along with the request.\n  Payload payload = 3;\n\n  // Whether SimpleResponse should include username.\n  bool fill_username = 4;\n\n  // Whether SimpleResponse should include OAuth scope.\n  bool fill_oauth_scope = 5;\n}\n\n// Unary response, as configured by the request.\nmessage SimpleResponse {\n  // Payload to increase message size.\n  Payload payload = 1;\n\n  // The user the request came from, for verifying authentication was\n  // successful when the client expected it.\n  string username = 2;\n\n  // OAuth scope.\n  string oauth_scope = 3;\n}\n\n// Client-streaming request.\nmessage StreamingInputCallRequest {\n  // Optional input payload sent along with the request.\n  Payload payload = 1;\n\n  // Not expecting any payload from the response.\n}\n\n// Client-streaming response.\nmessage StreamingInputCallResponse {\n  // Aggregated size of payloads received from the client.\n  int32 aggregated_payload_size = 1;\n}\n\n// Configuration for a particular response.\nmessage ResponseParameters {\n  // Desired payload sizes in responses from the server.\n  // If response_type is COMPRESSABLE, this denotes the size before compression.\n  int32 size = 1;\n\n  // Desired interval between consecutive responses in the response stream in\n  // microseconds.\n  int32 interval_us = 2;\n}\n\n// Server-streaming request.\nmessage StreamingOutputCallRequest {\n  // Desired payload type in the response from the server.\n  // If response_type is RANDOM, the payload from each response in the stream\n  // might be of different types. This is to simulate a mixed type of payload\n  // stream.\n  PayloadType response_type = 1;\n\n  // Configuration for each expected response message.\n  repeated ResponseParameters response_parameters = 2;\n\n  // Optional input payload sent along with the request.\n  Payload payload = 3;\n}\n\n// Server-streaming response, as configured by the request and parameters.\nmessage StreamingOutputCallResponse {\n  // Payload to increase response size.\n  Payload payload = 1;\n}\n\n// A simple service to test the various types of RPCs and experiment with\n// performance with various types of payload.\nservice TestService {\n  // One empty request followed by one empty response.\n  rpc EmptyCall(Empty) returns (Empty);\n\n  // One request followed by one response.\n  // The server returns the client payload as-is.\n  rpc UnaryCall(SimpleRequest) returns (SimpleResponse);\n\n  // One request followed by a sequence of responses (streamed download).\n  // The server returns the payload with client desired type and sizes.\n  rpc StreamingOutputCall(StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // A sequence of requests followed by one response (streamed upload).\n  // The server returns the aggregated size of client payload as the result.\n  rpc StreamingInputCall(stream StreamingInputCallRequest)\n      returns (StreamingInputCallResponse);\n\n  // A sequence of requests with each request served by the server immediately.\n  // As one request could lead to multiple responses, this interface\n  // demonstrates the idea of full duplexing.\n  rpc FullDuplexCall(stream StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n\n  // A sequence of requests followed by a sequence of responses.\n  // The server buffers all the client requests and then serves them in order. A\n  // stream of responses are returned to the client when the server starts with\n  // first request.\n  rpc HalfDuplexCall(stream StreamingOutputCallRequest)\n      returns (stream StreamingOutputCallResponse);\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_testing/test_grpc.pb.go",
    "content": "// Copyright 2017 gRPC authors.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//     http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// An integration test service that covers all the method signature permutations\n// of unary/streaming requests/responses.\n\n// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.2.0\n// - protoc             v3.14.0\n// source: test/grpc_testing/test.proto\n\npackage grpc_testing\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.32.0 or later.\nconst _ = grpc.SupportPackageIsVersion7\n\n// TestServiceClient is the client API for TestService service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype TestServiceClient interface {\n\t// One empty request followed by one empty response.\n\tEmptyCall(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)\n\t// One request followed by one response.\n\t// The server returns the client payload as-is.\n\tUnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error)\n\t// One request followed by a sequence of responses (streamed download).\n\t// The server returns the payload with client desired type and sizes.\n\tStreamingOutputCall(ctx context.Context, in *StreamingOutputCallRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error)\n\t// A sequence of requests followed by one response (streamed upload).\n\t// The server returns the aggregated size of client payload as the result.\n\tStreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error)\n\t// A sequence of requests with each request served by the server immediately.\n\t// As one request could lead to multiple responses, this interface\n\t// demonstrates the idea of full duplexing.\n\tFullDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_FullDuplexCallClient, error)\n\t// A sequence of requests followed by a sequence of responses.\n\t// The server buffers all the client requests and then serves them in order. A\n\t// stream of responses are returned to the client when the server starts with\n\t// first request.\n\tHalfDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_HalfDuplexCallClient, error)\n}\n\ntype testServiceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewTestServiceClient(cc grpc.ClientConnInterface) TestServiceClient {\n\treturn &testServiceClient{cc}\n}\n\nfunc (c *testServiceClient) EmptyCall(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {\n\tout := new(Empty)\n\terr := c.cc.Invoke(ctx, \"/grpc.testing.TestService/EmptyCall\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *testServiceClient) UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error) {\n\tout := new(SimpleResponse)\n\terr := c.cc.Invoke(ctx, \"/grpc.testing.TestService/UnaryCall\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *testServiceClient) StreamingOutputCall(ctx context.Context, in *StreamingOutputCallRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[0], \"/grpc.testing.TestService/StreamingOutputCall\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &testServiceStreamingOutputCallClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype TestService_StreamingOutputCallClient interface {\n\tRecv() (*StreamingOutputCallResponse, error)\n\tgrpc.ClientStream\n}\n\ntype testServiceStreamingOutputCallClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *testServiceStreamingOutputCallClient) Recv() (*StreamingOutputCallResponse, error) {\n\tm := new(StreamingOutputCallResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *testServiceClient) StreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[1], \"/grpc.testing.TestService/StreamingInputCall\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &testServiceStreamingInputCallClient{stream}\n\treturn x, nil\n}\n\ntype TestService_StreamingInputCallClient interface {\n\tSend(*StreamingInputCallRequest) error\n\tCloseAndRecv() (*StreamingInputCallResponse, error)\n\tgrpc.ClientStream\n}\n\ntype testServiceStreamingInputCallClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *testServiceStreamingInputCallClient) Send(m *StreamingInputCallRequest) error {\n\treturn x.ClientStream.SendMsg(m)\n}\n\nfunc (x *testServiceStreamingInputCallClient) CloseAndRecv() (*StreamingInputCallResponse, error) {\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\tm := new(StreamingInputCallResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *testServiceClient) FullDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_FullDuplexCallClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[2], \"/grpc.testing.TestService/FullDuplexCall\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &testServiceFullDuplexCallClient{stream}\n\treturn x, nil\n}\n\ntype TestService_FullDuplexCallClient interface {\n\tSend(*StreamingOutputCallRequest) error\n\tRecv() (*StreamingOutputCallResponse, error)\n\tgrpc.ClientStream\n}\n\ntype testServiceFullDuplexCallClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *testServiceFullDuplexCallClient) Send(m *StreamingOutputCallRequest) error {\n\treturn x.ClientStream.SendMsg(m)\n}\n\nfunc (x *testServiceFullDuplexCallClient) Recv() (*StreamingOutputCallResponse, error) {\n\tm := new(StreamingOutputCallResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *testServiceClient) HalfDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_HalfDuplexCallClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[3], \"/grpc.testing.TestService/HalfDuplexCall\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &testServiceHalfDuplexCallClient{stream}\n\treturn x, nil\n}\n\ntype TestService_HalfDuplexCallClient interface {\n\tSend(*StreamingOutputCallRequest) error\n\tRecv() (*StreamingOutputCallResponse, error)\n\tgrpc.ClientStream\n}\n\ntype testServiceHalfDuplexCallClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *testServiceHalfDuplexCallClient) Send(m *StreamingOutputCallRequest) error {\n\treturn x.ClientStream.SendMsg(m)\n}\n\nfunc (x *testServiceHalfDuplexCallClient) Recv() (*StreamingOutputCallResponse, error) {\n\tm := new(StreamingOutputCallResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// TestServiceServer is the server API for TestService service.\n// All implementations must embed UnimplementedTestServiceServer\n// for forward compatibility\ntype TestServiceServer interface {\n\t// One empty request followed by one empty response.\n\tEmptyCall(context.Context, *Empty) (*Empty, error)\n\t// One request followed by one response.\n\t// The server returns the client payload as-is.\n\tUnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error)\n\t// One request followed by a sequence of responses (streamed download).\n\t// The server returns the payload with client desired type and sizes.\n\tStreamingOutputCall(*StreamingOutputCallRequest, TestService_StreamingOutputCallServer) error\n\t// A sequence of requests followed by one response (streamed upload).\n\t// The server returns the aggregated size of client payload as the result.\n\tStreamingInputCall(TestService_StreamingInputCallServer) error\n\t// A sequence of requests with each request served by the server immediately.\n\t// As one request could lead to multiple responses, this interface\n\t// demonstrates the idea of full duplexing.\n\tFullDuplexCall(TestService_FullDuplexCallServer) error\n\t// A sequence of requests followed by a sequence of responses.\n\t// The server buffers all the client requests and then serves them in order. A\n\t// stream of responses are returned to the client when the server starts with\n\t// first request.\n\tHalfDuplexCall(TestService_HalfDuplexCallServer) error\n\tmustEmbedUnimplementedTestServiceServer()\n}\n\n// UnimplementedTestServiceServer must be embedded to have forward compatible implementations.\ntype UnimplementedTestServiceServer struct {\n}\n\nfunc (UnimplementedTestServiceServer) EmptyCall(context.Context, *Empty) (*Empty, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method EmptyCall not implemented\")\n}\nfunc (UnimplementedTestServiceServer) UnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method UnaryCall not implemented\")\n}\nfunc (UnimplementedTestServiceServer) StreamingOutputCall(*StreamingOutputCallRequest, TestService_StreamingOutputCallServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method StreamingOutputCall not implemented\")\n}\nfunc (UnimplementedTestServiceServer) StreamingInputCall(TestService_StreamingInputCallServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method StreamingInputCall not implemented\")\n}\nfunc (UnimplementedTestServiceServer) FullDuplexCall(TestService_FullDuplexCallServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method FullDuplexCall not implemented\")\n}\nfunc (UnimplementedTestServiceServer) HalfDuplexCall(TestService_HalfDuplexCallServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method HalfDuplexCall not implemented\")\n}\nfunc (UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {}\n\n// UnsafeTestServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to TestServiceServer will\n// result in compilation errors.\ntype UnsafeTestServiceServer interface {\n\tmustEmbedUnimplementedTestServiceServer()\n}\n\nfunc RegisterTestServiceServer(s grpc.ServiceRegistrar, srv TestServiceServer) {\n\ts.RegisterService(&TestService_ServiceDesc, srv)\n}\n\nfunc _TestService_EmptyCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(TestServiceServer).EmptyCall(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/grpc.testing.TestService/EmptyCall\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(TestServiceServer).EmptyCall(ctx, req.(*Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _TestService_UnaryCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(SimpleRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(TestServiceServer).UnaryCall(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/grpc.testing.TestService/UnaryCall\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(TestServiceServer).UnaryCall(ctx, req.(*SimpleRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _TestService_StreamingOutputCall_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(StreamingOutputCallRequest)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(TestServiceServer).StreamingOutputCall(m, &testServiceStreamingOutputCallServer{stream})\n}\n\ntype TestService_StreamingOutputCallServer interface {\n\tSend(*StreamingOutputCallResponse) error\n\tgrpc.ServerStream\n}\n\ntype testServiceStreamingOutputCallServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *testServiceStreamingOutputCallServer) Send(m *StreamingOutputCallResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _TestService_StreamingInputCall_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(TestServiceServer).StreamingInputCall(&testServiceStreamingInputCallServer{stream})\n}\n\ntype TestService_StreamingInputCallServer interface {\n\tSendAndClose(*StreamingInputCallResponse) error\n\tRecv() (*StreamingInputCallRequest, error)\n\tgrpc.ServerStream\n}\n\ntype testServiceStreamingInputCallServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *testServiceStreamingInputCallServer) SendAndClose(m *StreamingInputCallResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc (x *testServiceStreamingInputCallServer) Recv() (*StreamingInputCallRequest, error) {\n\tm := new(StreamingInputCallRequest)\n\tif err := x.ServerStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc _TestService_FullDuplexCall_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(TestServiceServer).FullDuplexCall(&testServiceFullDuplexCallServer{stream})\n}\n\ntype TestService_FullDuplexCallServer interface {\n\tSend(*StreamingOutputCallResponse) error\n\tRecv() (*StreamingOutputCallRequest, error)\n\tgrpc.ServerStream\n}\n\ntype testServiceFullDuplexCallServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *testServiceFullDuplexCallServer) Send(m *StreamingOutputCallResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc (x *testServiceFullDuplexCallServer) Recv() (*StreamingOutputCallRequest, error) {\n\tm := new(StreamingOutputCallRequest)\n\tif err := x.ServerStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc _TestService_HalfDuplexCall_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(TestServiceServer).HalfDuplexCall(&testServiceHalfDuplexCallServer{stream})\n}\n\ntype TestService_HalfDuplexCallServer interface {\n\tSend(*StreamingOutputCallResponse) error\n\tRecv() (*StreamingOutputCallRequest, error)\n\tgrpc.ServerStream\n}\n\ntype testServiceHalfDuplexCallServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *testServiceHalfDuplexCallServer) Send(m *StreamingOutputCallResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc (x *testServiceHalfDuplexCallServer) Recv() (*StreamingOutputCallRequest, error) {\n\tm := new(StreamingOutputCallRequest)\n\tif err := x.ServerStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// TestService_ServiceDesc is the grpc.ServiceDesc for TestService service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar TestService_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"grpc.testing.TestService\",\n\tHandlerType: (*TestServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"EmptyCall\",\n\t\t\tHandler:    _TestService_EmptyCall_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"UnaryCall\",\n\t\t\tHandler:    _TestService_UnaryCall_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"StreamingOutputCall\",\n\t\t\tHandler:       _TestService_StreamingOutputCall_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"StreamingInputCall\",\n\t\t\tHandler:       _TestService_StreamingInputCall_Handler,\n\t\t\tClientStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"FullDuplexCall\",\n\t\t\tHandler:       _TestService_FullDuplexCall_Handler,\n\t\t\tServerStreams: true,\n\t\t\tClientStreams: true,\n\t\t},\n\t\t{\n\t\t\tStreamName:    \"HalfDuplexCall\",\n\t\t\tHandler:       _TestService_HalfDuplexCall_Handler,\n\t\t\tServerStreams: true,\n\t\t\tClientStreams: true,\n\t\t},\n\t},\n\tMetadata: \"test/grpc_testing/test.proto\",\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_wrappers_testing/service.go",
    "content": "// Package grpc_wrappers_testing provides a test service that could be used for the testing gRPC wrappers\npackage grpc_wrappers_testing //nolint:revive // we want to be consistent with the other packages\n\nimport (\n\tcontext \"context\"\n\n\t_struct \"github.com/golang/protobuf/ptypes/struct\"\n\twrappers \"github.com/golang/protobuf/ptypes/wrappers\"\n\tgrpc \"google.golang.org/grpc\"\n)\n\n//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative test.proto\n\n// Register registers a test service that could be used for the testing gRPC wrappers\nfunc Register(r grpc.ServiceRegistrar) *Service {\n\ts := &Service{}\n\n\tRegisterServiceServer(r, s)\n\n\treturn s\n}\n\n// Service is the test service for different grpc values and how they are handled\ntype Service struct {\n\tUnimplementedServiceServer\n\n\tTestStringImplementation  func(context.Context, *wrappers.StringValue) (*wrappers.StringValue, error)\n\tTestIntegerImplementation func(context.Context, *wrappers.Int64Value) (*wrappers.Int64Value, error)\n\tTestBooleanImplementation func(context.Context, *wrappers.BoolValue) (*wrappers.BoolValue, error)\n\tTestDoubleImplementation  func(context.Context, *wrappers.DoubleValue) (*wrappers.DoubleValue, error)\n\tTestValueImplementation   func(context.Context, *_struct.Value) (*_struct.Value, error)\n\tTestStreamImplementation  func(Service_TestStreamServer) error\n}\n\n// TestString is getting and returning a string value\nfunc (s *Service) TestString(ctx context.Context, in *wrappers.StringValue) (*wrappers.StringValue, error) {\n\tif s.TestStringImplementation != nil {\n\t\treturn s.TestStringImplementation(ctx, in)\n\t}\n\n\treturn s.UnimplementedServiceServer.TestString(ctx, in)\n}\n\n// TestInteger is getting and returning a integer value\nfunc (s *Service) TestInteger(ctx context.Context, in *wrappers.Int64Value) (*wrappers.Int64Value, error) {\n\tif s.TestIntegerImplementation != nil {\n\t\treturn s.TestIntegerImplementation(ctx, in)\n\t}\n\n\treturn s.UnimplementedServiceServer.TestInteger(ctx, in)\n}\n\n// TestBoolean is getting and returning a boolean value\nfunc (s *Service) TestBoolean(ctx context.Context, in *wrappers.BoolValue) (*wrappers.BoolValue, error) {\n\tif s.TestBooleanImplementation != nil {\n\t\treturn s.TestBooleanImplementation(ctx, in)\n\t}\n\n\treturn s.UnimplementedServiceServer.TestBoolean(ctx, in)\n}\n\n// TestDouble is getting and returning a double value\nfunc (s *Service) TestDouble(ctx context.Context, in *wrappers.DoubleValue) (*wrappers.DoubleValue, error) {\n\tif s.TestDoubleImplementation != nil {\n\t\treturn s.TestDoubleImplementation(ctx, in)\n\t}\n\n\treturn s.UnimplementedServiceServer.TestDouble(ctx, in)\n}\n\n// TestValue is getting and returning a generic value\nfunc (s *Service) TestValue(ctx context.Context, in *_struct.Value) (*_struct.Value, error) {\n\tif s.TestValueImplementation != nil {\n\t\treturn s.TestValueImplementation(ctx, in)\n\t}\n\n\treturn s.UnimplementedServiceServer.TestValue(ctx, in)\n}\n\n// TestStream is testing a stream of values\nfunc (s *Service) TestStream(stream Service_TestStreamServer) error {\n\tif s.TestStreamImplementation != nil {\n\t\treturn s.TestStreamImplementation(stream)\n\t}\n\n\treturn s.UnimplementedServiceServer.TestStream(stream)\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_wrappers_testing/test.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: test.proto\n\npackage grpc_wrappers_testing\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tstructpb \"google.golang.org/protobuf/types/known/structpb\"\n\twrapperspb \"google.golang.org/protobuf/types/known/wrapperspb\"\n\treflect \"reflect\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nvar File_test_proto protoreflect.FileDescriptor\n\nvar file_test_proto_rawDesc = []byte{\n\t0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x67, 0x72,\n\t0x70, 0x63, 0x2e, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x74, 0x65, 0x73, 0x74,\n\t0x69, 0x6e, 0x67, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,\n\t0x6f, 0x32, 0xb6, 0x03, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a,\n\t0x0a, 0x54, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1c, 0x2e, 0x67, 0x6f,\n\t0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74,\n\t0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67,\n\t0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69,\n\t0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x47, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x49,\n\t0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61,\n\t0x6c, 0x75, 0x65, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65,\n\t0x12, 0x45, 0x0a, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x12,\n\t0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,\n\t0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x1a, 0x2e, 0x67, 0x6f,\n\t0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f,\n\t0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x44,\n\t0x6f, 0x75, 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,\n\t0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61,\n\t0x6c, 0x75, 0x65, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,\n\t0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75,\n\t0x65, 0x12, 0x3b, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16,\n\t0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,\n\t0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a,\n\t0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1c, 0x2e, 0x67,\n\t0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53,\n\t0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72,\n\t0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x01, 0x42, 0x19, 0x5a, 0x17, 0x2e, 0x2f,\n\t0x67, 0x72, 0x70, 0x63, 0x5f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x5f, 0x74, 0x65,\n\t0x73, 0x74, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar file_test_proto_goTypes = []interface{}{\n\t(*wrapperspb.StringValue)(nil), // 0: google.protobuf.StringValue\n\t(*wrapperspb.Int64Value)(nil),  // 1: google.protobuf.Int64Value\n\t(*wrapperspb.BoolValue)(nil),   // 2: google.protobuf.BoolValue\n\t(*wrapperspb.DoubleValue)(nil), // 3: google.protobuf.DoubleValue\n\t(*structpb.Value)(nil),         // 4: google.protobuf.Value\n}\nvar file_test_proto_depIdxs = []int32{\n\t0, // 0: grpc.wrappers.testing.Service.TestString:input_type -> google.protobuf.StringValue\n\t1, // 1: grpc.wrappers.testing.Service.TestInteger:input_type -> google.protobuf.Int64Value\n\t2, // 2: grpc.wrappers.testing.Service.TestBoolean:input_type -> google.protobuf.BoolValue\n\t3, // 3: grpc.wrappers.testing.Service.TestDouble:input_type -> google.protobuf.DoubleValue\n\t4, // 4: grpc.wrappers.testing.Service.TestValue:input_type -> google.protobuf.Value\n\t0, // 5: grpc.wrappers.testing.Service.TestStream:input_type -> google.protobuf.StringValue\n\t0, // 6: grpc.wrappers.testing.Service.TestString:output_type -> google.protobuf.StringValue\n\t1, // 7: grpc.wrappers.testing.Service.TestInteger:output_type -> google.protobuf.Int64Value\n\t2, // 8: grpc.wrappers.testing.Service.TestBoolean:output_type -> google.protobuf.BoolValue\n\t3, // 9: grpc.wrappers.testing.Service.TestDouble:output_type -> google.protobuf.DoubleValue\n\t4, // 10: grpc.wrappers.testing.Service.TestValue:output_type -> google.protobuf.Value\n\t0, // 11: grpc.wrappers.testing.Service.TestStream:output_type -> google.protobuf.StringValue\n\t6, // [6:12] is the sub-list for method output_type\n\t0, // [0:6] is the sub-list for method input_type\n\t0, // [0:0] is the sub-list for extension type_name\n\t0, // [0:0] is the sub-list for extension extendee\n\t0, // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_test_proto_init() }\nfunc file_test_proto_init() {\n\tif File_test_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_test_proto_rawDesc,\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   0,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   1,\n\t\t},\n\t\tGoTypes:           file_test_proto_goTypes,\n\t\tDependencyIndexes: file_test_proto_depIdxs,\n\t}.Build()\n\tFile_test_proto = out.File\n\tfile_test_proto_rawDesc = nil\n\tfile_test_proto_goTypes = nil\n\tfile_test_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_wrappers_testing/test.proto",
    "content": "syntax = \"proto3\";\n\npackage grpc.wrappers.testing;\n\n// this proto contains service that helps tests some of well-known types or wrappers\n// https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/wrappers.proto\n\nimport \"google/protobuf/wrappers.proto\";\nimport \"google/protobuf/struct.proto\";\n\noption go_package =\"./grpc_wrappers_testing\";\n\nservice Service {\n   rpc TestString(google.protobuf.StringValue) returns (google.protobuf.StringValue);\n   rpc TestInteger(google.protobuf.Int64Value) returns (google.protobuf.Int64Value);\n   rpc TestBoolean(google.protobuf.BoolValue) returns (google.protobuf.BoolValue);\n   rpc TestDouble(google.protobuf.DoubleValue) returns (google.protobuf.DoubleValue);\n   rpc TestValue(google.protobuf.Value) returns (google.protobuf.Value);\n\n   rpc TestStream(stream google.protobuf.StringValue) returns (google.protobuf.StringValue);\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/grpc_wrappers_testing/test_grpc.pb.go",
    "content": "// Code generated by protoc-gen-go-grpc. DO NOT EDIT.\n// versions:\n// - protoc-gen-go-grpc v1.3.0\n// - protoc             v3.21.12\n// source: test.proto\n\npackage grpc_wrappers_testing\n\nimport (\n\tcontext \"context\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\tstructpb \"google.golang.org/protobuf/types/known/structpb\"\n\twrapperspb \"google.golang.org/protobuf/types/known/wrapperspb\"\n)\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\n// Requires gRPC-Go v1.32.0 or later.\nconst _ = grpc.SupportPackageIsVersion7\n\nconst (\n\tService_TestString_FullMethodName  = \"/grpc.wrappers.testing.Service/TestString\"\n\tService_TestInteger_FullMethodName = \"/grpc.wrappers.testing.Service/TestInteger\"\n\tService_TestBoolean_FullMethodName = \"/grpc.wrappers.testing.Service/TestBoolean\"\n\tService_TestDouble_FullMethodName  = \"/grpc.wrappers.testing.Service/TestDouble\"\n\tService_TestValue_FullMethodName   = \"/grpc.wrappers.testing.Service/TestValue\"\n\tService_TestStream_FullMethodName  = \"/grpc.wrappers.testing.Service/TestStream\"\n)\n\n// ServiceClient is the client API for Service service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.\ntype ServiceClient interface {\n\tTestString(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*wrapperspb.StringValue, error)\n\tTestInteger(ctx context.Context, in *wrapperspb.Int64Value, opts ...grpc.CallOption) (*wrapperspb.Int64Value, error)\n\tTestBoolean(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error)\n\tTestDouble(ctx context.Context, in *wrapperspb.DoubleValue, opts ...grpc.CallOption) (*wrapperspb.DoubleValue, error)\n\tTestValue(ctx context.Context, in *structpb.Value, opts ...grpc.CallOption) (*structpb.Value, error)\n\tTestStream(ctx context.Context, opts ...grpc.CallOption) (Service_TestStreamClient, error)\n}\n\ntype serviceClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewServiceClient(cc grpc.ClientConnInterface) ServiceClient {\n\treturn &serviceClient{cc}\n}\n\nfunc (c *serviceClient) TestString(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) {\n\tout := new(wrapperspb.StringValue)\n\terr := c.cc.Invoke(ctx, Service_TestString_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *serviceClient) TestInteger(ctx context.Context, in *wrapperspb.Int64Value, opts ...grpc.CallOption) (*wrapperspb.Int64Value, error) {\n\tout := new(wrapperspb.Int64Value)\n\terr := c.cc.Invoke(ctx, Service_TestInteger_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *serviceClient) TestBoolean(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) {\n\tout := new(wrapperspb.BoolValue)\n\terr := c.cc.Invoke(ctx, Service_TestBoolean_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *serviceClient) TestDouble(ctx context.Context, in *wrapperspb.DoubleValue, opts ...grpc.CallOption) (*wrapperspb.DoubleValue, error) {\n\tout := new(wrapperspb.DoubleValue)\n\terr := c.cc.Invoke(ctx, Service_TestDouble_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *serviceClient) TestValue(ctx context.Context, in *structpb.Value, opts ...grpc.CallOption) (*structpb.Value, error) {\n\tout := new(structpb.Value)\n\terr := c.cc.Invoke(ctx, Service_TestValue_FullMethodName, in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *serviceClient) TestStream(ctx context.Context, opts ...grpc.CallOption) (Service_TestStreamClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &Service_ServiceDesc.Streams[0], Service_TestStream_FullMethodName, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &serviceTestStreamClient{stream}\n\treturn x, nil\n}\n\ntype Service_TestStreamClient interface {\n\tSend(*wrapperspb.StringValue) error\n\tCloseAndRecv() (*wrapperspb.StringValue, error)\n\tgrpc.ClientStream\n}\n\ntype serviceTestStreamClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *serviceTestStreamClient) Send(m *wrapperspb.StringValue) error {\n\treturn x.ClientStream.SendMsg(m)\n}\n\nfunc (x *serviceTestStreamClient) CloseAndRecv() (*wrapperspb.StringValue, error) {\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\tm := new(wrapperspb.StringValue)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// ServiceServer is the server API for Service service.\n// All implementations must embed UnimplementedServiceServer\n// for forward compatibility\ntype ServiceServer interface {\n\tTestString(context.Context, *wrapperspb.StringValue) (*wrapperspb.StringValue, error)\n\tTestInteger(context.Context, *wrapperspb.Int64Value) (*wrapperspb.Int64Value, error)\n\tTestBoolean(context.Context, *wrapperspb.BoolValue) (*wrapperspb.BoolValue, error)\n\tTestDouble(context.Context, *wrapperspb.DoubleValue) (*wrapperspb.DoubleValue, error)\n\tTestValue(context.Context, *structpb.Value) (*structpb.Value, error)\n\tTestStream(Service_TestStreamServer) error\n\tmustEmbedUnimplementedServiceServer()\n}\n\n// UnimplementedServiceServer must be embedded to have forward compatible implementations.\ntype UnimplementedServiceServer struct {\n}\n\nfunc (UnimplementedServiceServer) TestString(context.Context, *wrapperspb.StringValue) (*wrapperspb.StringValue, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method TestString not implemented\")\n}\nfunc (UnimplementedServiceServer) TestInteger(context.Context, *wrapperspb.Int64Value) (*wrapperspb.Int64Value, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method TestInteger not implemented\")\n}\nfunc (UnimplementedServiceServer) TestBoolean(context.Context, *wrapperspb.BoolValue) (*wrapperspb.BoolValue, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method TestBoolean not implemented\")\n}\nfunc (UnimplementedServiceServer) TestDouble(context.Context, *wrapperspb.DoubleValue) (*wrapperspb.DoubleValue, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method TestDouble not implemented\")\n}\nfunc (UnimplementedServiceServer) TestValue(context.Context, *structpb.Value) (*structpb.Value, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method TestValue not implemented\")\n}\nfunc (UnimplementedServiceServer) TestStream(Service_TestStreamServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method TestStream not implemented\")\n}\nfunc (UnimplementedServiceServer) mustEmbedUnimplementedServiceServer() {}\n\n// UnsafeServiceServer may be embedded to opt out of forward compatibility for this service.\n// Use of this interface is not recommended, as added methods to ServiceServer will\n// result in compilation errors.\ntype UnsafeServiceServer interface {\n\tmustEmbedUnimplementedServiceServer()\n}\n\nfunc RegisterServiceServer(s grpc.ServiceRegistrar, srv ServiceServer) {\n\ts.RegisterService(&Service_ServiceDesc, srv)\n}\n\nfunc _Service_TestString_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(wrapperspb.StringValue)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(ServiceServer).TestString(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: Service_TestString_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(ServiceServer).TestString(ctx, req.(*wrapperspb.StringValue))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _Service_TestInteger_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(wrapperspb.Int64Value)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(ServiceServer).TestInteger(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: Service_TestInteger_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(ServiceServer).TestInteger(ctx, req.(*wrapperspb.Int64Value))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _Service_TestBoolean_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(wrapperspb.BoolValue)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(ServiceServer).TestBoolean(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: Service_TestBoolean_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(ServiceServer).TestBoolean(ctx, req.(*wrapperspb.BoolValue))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _Service_TestDouble_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(wrapperspb.DoubleValue)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(ServiceServer).TestDouble(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: Service_TestDouble_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(ServiceServer).TestDouble(ctx, req.(*wrapperspb.DoubleValue))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _Service_TestValue_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(structpb.Value)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(ServiceServer).TestValue(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: Service_TestValue_FullMethodName,\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(ServiceServer).TestValue(ctx, req.(*structpb.Value))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _Service_TestStream_Handler(srv interface{}, stream grpc.ServerStream) error {\n\treturn srv.(ServiceServer).TestStream(&serviceTestStreamServer{stream})\n}\n\ntype Service_TestStreamServer interface {\n\tSendAndClose(*wrapperspb.StringValue) error\n\tRecv() (*wrapperspb.StringValue, error)\n\tgrpc.ServerStream\n}\n\ntype serviceTestStreamServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *serviceTestStreamServer) SendAndClose(m *wrapperspb.StringValue) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc (x *serviceTestStreamServer) Recv() (*wrapperspb.StringValue, error) {\n\tm := new(wrapperspb.StringValue)\n\tif err := x.ServerStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\n// Service_ServiceDesc is the grpc.ServiceDesc for Service service.\n// It's only intended for direct use with grpc.RegisterService,\n// and not to be introspected or modified (even as a copy)\nvar Service_ServiceDesc = grpc.ServiceDesc{\n\tServiceName: \"grpc.wrappers.testing.Service\",\n\tHandlerType: (*ServiceServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"TestString\",\n\t\t\tHandler:    _Service_TestString_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"TestInteger\",\n\t\t\tHandler:    _Service_TestInteger_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"TestBoolean\",\n\t\t\tHandler:    _Service_TestBoolean_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"TestDouble\",\n\t\t\tHandler:    _Service_TestDouble_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"TestValue\",\n\t\t\tHandler:    _Service_TestValue_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"TestStream\",\n\t\t\tHandler:       _Service_TestStream_Handler,\n\t\t\tClientStreams: true,\n\t\t},\n\t},\n\tMetadata: \"test.proto\",\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/httpmultibin.go",
    "content": "// Package httpmultibin is intended only for use in tests, do not import in production code!\npackage httpmultibin\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/andybalholm/brotli\"\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/mccutchen/go-httpbin/v2/httpbin\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/net/http2\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n\n\tgrpcanytesting \"go.k6.io/k6/internal/lib/testutils/httpmultibin/grpc_any_testing\"\n\tgrpctest \"go.k6.io/k6/internal/lib/testutils/httpmultibin/grpc_testing\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// GetTLSClientConfig returns a TLS config that trusts the supplied\n// httptest.Server certificate as well as all the system root certificates\nfunc GetTLSClientConfig(t testing.TB, srv *httptest.Server) *tls.Config {\n\tvar err error\n\n\tcerts := x509.NewCertPool()\n\n\tif runtime.GOOS != \"windows\" {\n\t\tcerts, err = x509.SystemCertPool()\n\t\trequire.NoError(t, err)\n\t}\n\n\tfor _, c := range srv.TLS.Certificates {\n\t\troots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])\n\t\trequire.NoError(t, err)\n\t\tfor _, root := range roots {\n\t\t\tcerts.AddCert(root)\n\t\t}\n\t}\n\treturn &tls.Config{\n\t\tRootCAs:            certs,\n\t\tInsecureSkipVerify: false,\n\t\tRenegotiation:      tls.RenegotiateFreelyAsClient,\n\t\tMinVersion:         tls.VersionTLS13,\n\t}\n}\n\nconst httpDomain = \"httpbin.local\"\n\n// We have to use example.com if we want a real HTTPS domain with a valid\n// certificate because the default httptest certificate is for example.com:\n// https://golang.org/src/net/http/internal/testcert.go?s=399:410#L10\nconst httpsDomain = \"example.com\"\n\n// HTTPMultiBin can be used as a local alternative of httpbin.org.\n// It offers both http and https servers, as well as real domains\ntype HTTPMultiBin struct {\n\tMux             *http.ServeMux\n\tServerHTTP      *httptest.Server\n\tServerHTTPS     *httptest.Server\n\tServerHTTP2     *httptest.Server\n\tServerGRPC      *grpc.Server\n\tGRPCStub        *GRPCStub\n\tGRPCAnyStub     *GRPCAnyStub\n\tReplacer        *strings.Replacer\n\tTLSClientConfig *tls.Config\n\tDialer          *netext.Dialer\n\tHTTPTransport   *http.Transport\n\tContext         context.Context\n}\n\ntype jsonBody struct {\n\tHeader      http.Header `json:\"headers\"`\n\tCompression string      `json:\"compression\"`\n}\n\n// autocloseHandler handles requests just opening\n// then closing the connection without waiting for the client input.\n// It simulates the server-side closing operation.\nfunc autocloseHandler(t testing.TB) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\trequire.NoError(t, err)\n\n\t\terr = conn.WriteControl(\n\t\t\twebsocket.CloseMessage,\n\t\t\twebsocket.FormatCloseMessage(websocket.CloseNormalClosure, \"\"),\n\t\t\ttime.Now().Add(time.Second))\n\t\trequire.NoError(t, err)\n\n\t\terr = conn.Close()\n\t\trequire.NoError(t, err)\n\t})\n}\n\n// echoHandler handles requests proxying the same request input to the client.\n// If closePrematurely is false then it waits for the client's request to close the connection.\n// If closePrematurely is true then it closes the connection in a brutally\n// without respecting the protocol.\nfunc echoHandler(t testing.TB, closePrematurely bool) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\tconn, err := (&websocket.Upgrader{}).Upgrade(w, req, w.Header())\n\t\trequire.NoError(t, err)\n\n\t\tdefer func() {\n\t\t\t_ = conn.Close()\n\t\t}()\n\n\t\tmessageType, r, e := conn.NextReader()\n\t\tif e != nil {\n\t\t\treturn\n\t\t}\n\t\tvar wc io.WriteCloser\n\t\twc, err = conn.NextWriter(messageType)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tif _, err = io.Copy(wc, r); err != nil {\n\t\t\treturn\n\t\t}\n\t\tif err = wc.Close(); err != nil {\n\t\t\treturn\n\t\t}\n\n\t\t// closePrematurely=true mimics an invalid WS server that doesn't\n\t\t// send a close control frame before closing the connection.\n\t\tif !closePrematurely {\n\t\t\tvar once sync.Once\n\t\t\t// Closing is delegated to the client,\n\t\t\t// it waits the control message for closing.\n\t\t\tcloseReceived := make(chan struct{})\n\t\t\tdefaultCloseHandler := conn.CloseHandler()\n\t\t\tconn.SetCloseHandler(func(code int, text string) error {\n\t\t\t\tonce.Do(func() { close(closeReceived) })\n\t\t\t\treturn defaultCloseHandler(code, text)\n\t\t\t})\n\n\t\t\tfor {\n\t\t\t\tif _, _, err := conn.ReadMessage(); err != nil {\n\t\t\t\t\tonce.Do(func() { close(closeReceived) })\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\t<-closeReceived\n\t\t}\n\t})\n}\n\nfunc writeJSON(w io.Writer, v any) error {\n\te := json.NewEncoder(w)\n\te.SetIndent(\"\", \"  \")\n\tif err := e.Encode(v); err != nil {\n\t\treturn fmt.Errorf(\"failed to encode JSON: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc getEncodedHandler(t testing.TB, compressionType string) http.Handler {\n\treturn http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\tvar (\n\t\t\tencoding string\n\t\t\terr      error\n\t\t\tencw     io.WriteCloser\n\t\t)\n\n\t\tswitch compressionType {\n\t\tcase \"br\":\n\t\t\tencw = brotli.NewWriter(rw)\n\t\t\tencoding = \"br\"\n\t\tcase \"zstd\":\n\t\t\tencw, _ = zstd.NewWriter(rw)\n\t\t\tencoding = \"zstd\"\n\t\t}\n\n\t\trw.Header().Set(\"Content-Type\", \"application/json\")\n\t\trw.Header().Add(\"Content-Encoding\", encoding)\n\t\tdata := jsonBody{\n\t\t\tHeader:      req.Header,\n\t\t\tCompression: encoding,\n\t\t}\n\t\terr = writeJSON(encw, data)\n\t\tif encw != nil {\n\t\t\t_ = encw.Close()\n\t\t}\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc getZstdBrHandler(t testing.TB) http.Handler {\n\treturn http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {\n\t\tencoding := \"zstd, br\"\n\t\trw.Header().Set(\"Content-Type\", \"application/json\")\n\t\trw.Header().Add(\"Content-Encoding\", encoding)\n\t\tdata := jsonBody{\n\t\t\tHeader:      req.Header,\n\t\t\tCompression: encoding,\n\t\t}\n\n\t\tbw := brotli.NewWriter(rw)\n\t\tzw, _ := zstd.NewWriter(bw)\n\t\tdefer func() {\n\t\t\t_ = zw.Close()\n\t\t\t_ = bw.Close()\n\t\t}()\n\n\t\trequire.NoError(t, writeJSON(zw, data))\n\t})\n}\n\n// GRPCStub is an easily customisable TestServiceServer\ntype GRPCStub struct {\n\tgrpctest.TestServiceServer\n\tEmptyCallFunc func(context.Context, *grpctest.Empty) (*grpctest.Empty, error)\n\tUnaryCallFunc func(context.Context, *grpctest.SimpleRequest) (*grpctest.SimpleResponse, error)\n}\n\n// EmptyCall implements the interface for the gRPC TestServiceServer\nfunc (s *GRPCStub) EmptyCall(ctx context.Context, req *grpctest.Empty) (*grpctest.Empty, error) {\n\tif s.EmptyCallFunc != nil {\n\t\treturn s.EmptyCallFunc(ctx, req)\n\t}\n\n\treturn nil, status.Errorf(codes.Unimplemented, \"method EmptyCall not implemented\")\n}\n\n// UnaryCall implements the interface for the gRPC TestServiceServer\nfunc (s *GRPCStub) UnaryCall(ctx context.Context, req *grpctest.SimpleRequest) (*grpctest.SimpleResponse, error) {\n\tif s.UnaryCallFunc != nil {\n\t\treturn s.UnaryCallFunc(ctx, req)\n\t}\n\n\treturn nil, status.Errorf(codes.Unimplemented, \"method UnaryCall not implemented\")\n}\n\n// StreamingOutputCall implements the interface for the gRPC TestServiceServer\nfunc (*GRPCStub) StreamingOutputCall(*grpctest.StreamingOutputCallRequest,\n\tgrpctest.TestService_StreamingOutputCallServer,\n) error {\n\treturn status.Errorf(codes.Unimplemented, \"method StreamingOutputCall not implemented\")\n}\n\n// StreamingInputCall implements the interface for the gRPC TestServiceServer\nfunc (*GRPCStub) StreamingInputCall(grpctest.TestService_StreamingInputCallServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method StreamingInputCall not implemented\")\n}\n\n// FullDuplexCall implements the interface for the gRPC TestServiceServer\nfunc (*GRPCStub) FullDuplexCall(grpctest.TestService_FullDuplexCallServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method FullDuplexCall not implemented\")\n}\n\n// HalfDuplexCall implements the interface for the gRPC TestServiceServer\nfunc (*GRPCStub) HalfDuplexCall(grpctest.TestService_HalfDuplexCallServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method HalfDuplexCall not implemented\")\n}\n\n// GRPCAnyStub is an easily customisable AnyTestServiceServer\ntype GRPCAnyStub struct {\n\tgrpcanytesting.AnyTestServiceServer\n\tSumFunc func(context.Context, *grpcanytesting.SumRequest) (*grpcanytesting.SumReply, error)\n}\n\n// Sum implements the interface for the gRPC AnyTestServiceServer\nfunc (s *GRPCAnyStub) Sum(ctx context.Context, req *grpcanytesting.SumRequest) (*grpcanytesting.SumReply, error) {\n\tif s.SumFunc != nil {\n\t\treturn s.SumFunc(ctx, req)\n\t}\n\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Sum not implemented\")\n}\n\n// NewHTTPMultiBin returns a fully configured and running HTTPMultiBin\n//\n//nolint:funlen\nfunc NewHTTPMultiBin(t testing.TB) *HTTPMultiBin {\n\t// Create a http.ServeMux and set the httpbin handler as the default\n\tmux := http.NewServeMux()\n\tmux.Handle(\"/brotli\", getEncodedHandler(t, \"br\"))\n\tmux.Handle(\"/ws-echo\", echoHandler(t, false))\n\tmux.Handle(\"/ws-echo-invalid\", echoHandler(t, true))\n\tmux.Handle(\"/ws-close\", autocloseHandler(t))\n\tmux.Handle(\"/ws-close-invalid\", echoHandler(t, true))\n\tmux.Handle(\"/zstd\", getEncodedHandler(t, \"zstd\"))\n\tmux.Handle(\"/zstd-br\", getZstdBrHandler(t))\n\tmux.Handle(\"/\", httpbin.New().Handler())\n\n\t// Initialize the HTTP server and get its details\n\thttpSrv := httptest.NewServer(mux)\n\thttpURL, err := url.Parse(httpSrv.URL)\n\trequire.NoError(t, err)\n\thttpIP := net.ParseIP(httpURL.Hostname())\n\trequire.NotNil(t, httpIP)\n\n\t// Initialize the HTTPS server and get its details and tls config\n\thttpsSrv := httptest.NewTLSServer(mux)\n\thttpsURL, err := url.Parse(httpsSrv.URL)\n\trequire.NoError(t, err)\n\thttpsIP := net.ParseIP(httpsURL.Hostname())\n\trequire.NotNil(t, httpsIP)\n\ttlsConfig := GetTLSClientConfig(t, httpsSrv)\n\n\t// Initialize the gRPC server\n\tgrpcSrv := grpc.NewServer()\n\tstub := &GRPCStub{}\n\tgrpctest.RegisterTestServiceServer(grpcSrv, stub)\n\tanyStub := &GRPCAnyStub{}\n\tgrpcanytesting.RegisterAnyTestServiceServer(grpcSrv, anyStub)\n\n\tcmux := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.ProtoMajor == 2 && strings.Contains(r.Header.Get(\"Content-Type\"), \"application/grpc\") {\n\t\t\tgrpcSrv.ServeHTTP(w, r)\n\n\t\t\treturn\n\t\t}\n\t\tmux.ServeHTTP(w, r)\n\t})\n\n\t// Initialize the HTTP2 server, with a copy of the https tls config\n\thttp2Srv := httptest.NewUnstartedServer(cmux)\n\thttp2Srv.EnableHTTP2 = true\n\thttp2Srv.TLS = tlsConfig\n\thttp2Srv.TLS.NextProtos = []string{http2.NextProtoTLS}\n\trequire.NoError(t, err)\n\thttp2Srv.StartTLS()\n\thttp2URL, err := url.Parse(http2Srv.URL)\n\trequire.NoError(t, err)\n\thttp2IP := net.ParseIP(http2URL.Hostname())\n\trequire.NotNil(t, http2IP)\n\n\thttpDomainValue, err := types.NewHost(httpIP, \"\")\n\trequire.NoError(t, err)\n\thttpsDomainValue, err := types.NewHost(httpsIP, \"\")\n\trequire.NoError(t, err)\n\n\t// Set up the dialer with shorter timeouts and the custom domains\n\tdialer := netext.NewDialer(net.Dialer{\n\t\tTimeout:   2 * time.Second,\n\t\tKeepAlive: 10 * time.Second,\n\t}, netext.NewResolver(net.LookupIP, 0, types.DNSfirst, types.DNSpreferIPv4))\n\tdialer.Hosts, err = types.NewHosts(map[string]types.Host{\n\t\thttpDomain:  *httpDomainValue,\n\t\thttpsDomain: *httpsDomainValue,\n\t})\n\trequire.NoError(t, err)\n\n\t// Pre-configure the HTTP client transport with the dialer and TLS config (incl. HTTP2 support)\n\ttransport := &http.Transport{\n\t\tDialContext:     dialer.DialContext,\n\t\tTLSClientConfig: tlsConfig,\n\t}\n\trequire.NoError(t, http2.ConfigureTransport(transport))\n\n\tctx, ctxCancel := context.WithCancel(context.Background())\n\n\tresult := &HTTPMultiBin{\n\t\tMux:         mux,\n\t\tServerHTTP:  httpSrv,\n\t\tServerHTTPS: httpsSrv,\n\t\tServerHTTP2: http2Srv,\n\t\tServerGRPC:  grpcSrv,\n\t\tGRPCStub:    stub,\n\t\tGRPCAnyStub: anyStub,\n\t\tReplacer: strings.NewReplacer(\n\t\t\t\"HTTPBIN_IP_URL\", httpSrv.URL,\n\t\t\t\"HTTPBIN_DOMAIN\", httpDomain,\n\t\t\t\"HTTPBIN_URL\", fmt.Sprintf(\"http://%s\", net.JoinHostPort(httpDomain, httpURL.Port())),\n\t\t\t\"WSBIN_URL\", fmt.Sprintf(\"ws://%s\", net.JoinHostPort(httpDomain, httpURL.Port())),\n\t\t\t\"HTTPBIN_IP\", httpIP.String(),\n\t\t\t\"HTTPBIN_PORT\", httpURL.Port(),\n\t\t\t\"HTTPSBIN_IP_URL\", httpsSrv.URL,\n\t\t\t\"HTTPSBIN_DOMAIN\", httpsDomain,\n\t\t\t\"HTTPSBIN_URL\", fmt.Sprintf(\"https://%s\", net.JoinHostPort(httpsDomain, httpsURL.Port())),\n\t\t\t\"WSSBIN_URL\", fmt.Sprintf(\"wss://%s\", net.JoinHostPort(httpsDomain, httpsURL.Port())),\n\t\t\t\"HTTPSBIN_IP\", httpsIP.String(),\n\t\t\t\"HTTPSBIN_PORT\", httpsURL.Port(),\n\n\t\t\t\"HTTP2BIN_IP_URL\", http2Srv.URL,\n\t\t\t\"HTTP2BIN_DOMAIN\", httpsDomain,\n\t\t\t\"HTTP2BIN_URL\", fmt.Sprintf(\"https://%s\", net.JoinHostPort(httpsDomain, http2URL.Port())),\n\t\t\t\"HTTP2BIN_IP\", http2IP.String(),\n\t\t\t\"HTTP2BIN_PORT\", http2URL.Port(),\n\n\t\t\t\"GRPCBIN_ADDR\", net.JoinHostPort(httpsDomain, http2URL.Port()),\n\t\t),\n\t\tTLSClientConfig: tlsConfig,\n\t\tDialer:          dialer,\n\t\tHTTPTransport:   transport,\n\t\tContext:         ctx,\n\t}\n\n\tt.Cleanup(func() {\n\t\tgrpcSrv.Stop()\n\t\thttp2Srv.Close()\n\t\thttpsSrv.Close()\n\t\thttpSrv.Close()\n\t\tctxCancel()\n\t})\n\treturn result\n}\n"
  },
  {
    "path": "internal/lib/testutils/httpmultibin/nested_types/nested_types.proto",
    "content": "// The purpose of this proto file is to demonstrate that we can have \n// nested types and that we should be able to load them correctly.\n\nsyntax = \"proto3\";\n\npackage grpc.testdata.nested.types;\n\n// Example to demonstrate that it is possible to define\n// and use message types within other message types\nmessage Outer {      // Level 0\n  message MiddleAA { // Level 1\n    message Inner {  // Level 2\n      int64 ival = 1;\n      bool booly = 2;\n    }\n    Inner inner = 1;\n  }\n\n  message MiddleBB { // Level 1\n    message Inner {  // Level 2\n      int32 ival = 1;\n      bool booly = 2;\n    }\n    Inner inner = 1;\n  }\n\n  MiddleAA middleAA = 1;\n  MiddleBB middleBB = 2;\n}\n\n// Example to demonstrate that it is possible to reuse\n// a message type outside its parent message type\nmessage MeldOuter {\n  Outer.MiddleAA.Inner innerAA = 1;\n  Outer.MiddleBB.Inner innerBB = 2;\n}\n"
  },
  {
    "path": "internal/lib/testutils/logrus_hook.go",
    "content": "package testutils\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// SimpleLogrusHook implements the logrus.Hook interface and could be used to check\n// if log messages were outputted\ntype SimpleLogrusHook struct {\n\tHookedLevels []logrus.Level\n\tmutex        sync.Mutex\n\tmessageCache []logrus.Entry\n}\n\n// Levels just returns whatever was stored in the HookedLevels slice\nfunc (smh *SimpleLogrusHook) Levels() []logrus.Level {\n\treturn smh.HookedLevels\n}\n\n// Fire saves whatever message the logrus library passed in the cache\nfunc (smh *SimpleLogrusHook) Fire(e *logrus.Entry) error {\n\tsmh.mutex.Lock()\n\tdefer smh.mutex.Unlock()\n\tsmh.messageCache = append(smh.messageCache, *e)\n\treturn nil\n}\n\n// Drain returns the currently stored messages and deletes them from the cache\nfunc (smh *SimpleLogrusHook) Drain() []logrus.Entry {\n\tsmh.mutex.Lock()\n\tdefer smh.mutex.Unlock()\n\tres := smh.messageCache\n\tsmh.messageCache = []logrus.Entry{}\n\treturn res\n}\n\n// Lines returns the logged lines.\nfunc (smh *SimpleLogrusHook) Lines() []string {\n\tentries := smh.Drain()\n\tlines := make([]string, len(entries))\n\tfor i, entry := range entries {\n\t\tlines[i] = entry.Message\n\t}\n\treturn lines\n}\n\n// Reset clears the internal entry buffer.\nfunc (smh *SimpleLogrusHook) Reset() {\n\tsmh.mutex.Lock()\n\tdefer smh.mutex.Unlock()\n\tsmh.messageCache = []logrus.Entry{}\n}\n\n// LastEntry returns the last entry that was logged (or nil, if no messages were\n// logged or remain).\nfunc (smh *SimpleLogrusHook) LastEntry() *logrus.Entry {\n\tsmh.mutex.Lock()\n\tdefer smh.mutex.Unlock()\n\ti := len(smh.messageCache) - 1\n\tif i < 0 {\n\t\treturn nil\n\t}\n\treturn &smh.messageCache[i]\n}\n\nvar _ logrus.Hook = &SimpleLogrusHook{}\n\n// NewLogHook creates a new SimpleLogrusHook with the given levels and returns\n// it. If no levels are specified, then logrus.AllLevels will be used.\nfunc NewLogHook(levels ...logrus.Level) *SimpleLogrusHook {\n\tif len(levels) == 0 {\n\t\tlevels = logrus.AllLevels\n\t}\n\treturn &SimpleLogrusHook{HookedLevels: levels}\n}\n\n// LogContains is a helper function that checks the provided list of log entries\n// for a message matching the provided level and contents.\nfunc LogContains(logEntries []logrus.Entry, expLevel logrus.Level, expContents string) bool {\n\tfor _, entry := range logEntries {\n\t\tif entry.Level == expLevel && strings.Contains(entry.Message, expContents) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// FilterEntries is a helper function that checks the provided list of log entries\n// for a messages matching the provided level and contents and returns an array with only them.\nfunc FilterEntries(logEntries []logrus.Entry, expLevel logrus.Level, expContents string) []logrus.Entry {\n\tfiltered := make([]logrus.Entry, 0)\n\tfor _, entry := range logEntries {\n\t\tif entry.Level == expLevel && strings.Contains(entry.Message, expContents) {\n\t\t\tfiltered = append(filtered, entry)\n\t\t}\n\t}\n\treturn filtered\n}\n"
  },
  {
    "path": "internal/lib/testutils/minirunner/minirunner.go",
    "content": "// Package minirunner provides a mock implementation of the lib.Runner\n// We use it in tests\npackage minirunner\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// Ensure mock implementations conform to the interfaces.\nvar (\n\t_ lib.Runner        = &MiniRunner{}\n\t_ lib.InitializedVU = &VU{}\n\t_ lib.ActiveVU      = &ActiveVU{}\n)\n\n// MiniRunner partially implements the lib.Runner interface, but instead of\n// using a real JS runtime, it allows us to directly specify the options and\n// functions with Go code.\ntype MiniRunner struct {\n\tFn              func(ctx context.Context, state *lib.State, out chan<- metrics.SampleContainer) error\n\tSetupFn         func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error)\n\tTeardownFn      func(ctx context.Context, out chan<- metrics.SampleContainer) error\n\tHandleSummaryFn func(context.Context, *lib.LegacySummary, *summary.Summary) (map[string]io.Reader, error)\n\n\tSetupData []byte\n\n\tOptions      lib.Options\n\tPreInitState *lib.TestPreInitState\n\n\trunTags *metrics.TagSet\n}\n\n// MakeArchive isn't implemented, it always returns nil and is just here to\n// satisfy the lib.Runner interface.\nfunc (r MiniRunner) MakeArchive() *lib.Archive {\n\treturn nil\n}\n\n// NewVU returns a new VU with an incremental ID.\nfunc (r *MiniRunner) NewVU(\n\t_ context.Context, idLocal, idGlobal uint64, out chan<- metrics.SampleContainer,\n) (lib.InitializedVU, error) {\n\tstate := &lib.State{VUID: idLocal, VUIDGlobal: idGlobal, Iteration: int64(-1)}\n\tif r.runTags != nil {\n\t\tstate.Tags = lib.NewVUStateTags(r.runTags)\n\t}\n\treturn &VU{\n\t\tR:            r,\n\t\tOut:          out,\n\t\tID:           idLocal,\n\t\tIDGlobal:     idGlobal,\n\t\tstate:        state,\n\t\tscenarioIter: make(map[string]uint64),\n\t}, nil\n}\n\n// Setup calls the supplied mock setup() function, if present.\nfunc (r *MiniRunner) Setup(ctx context.Context, out chan<- metrics.SampleContainer) (err error) {\n\tif fn := r.SetupFn; fn != nil {\n\t\tr.SetupData, err = fn(ctx, out)\n\t}\n\treturn err\n}\n\n// GetSetupData returns json representation of the setup data if setup() is\n// specified and was ran, nil otherwise.\nfunc (r MiniRunner) GetSetupData() []byte {\n\treturn r.SetupData\n}\n\n// SetSetupData saves the externally supplied setup data as JSON in the runner.\nfunc (r *MiniRunner) SetSetupData(data []byte) {\n\tr.SetupData = data\n}\n\n// Teardown calls the supplied mock teardown() function, if present.\nfunc (r MiniRunner) Teardown(ctx context.Context, out chan<- metrics.SampleContainer) error {\n\tif fn := r.TeardownFn; fn != nil {\n\t\treturn fn(ctx, out)\n\t}\n\treturn nil\n}\n\n// IsExecutable satisfies lib.Runner, but is mocked for MiniRunner since\n// it doesn't deal with JS.\nfunc (r MiniRunner) IsExecutable(_ string) bool {\n\treturn true\n}\n\n// GetOptions returns the supplied options struct.\nfunc (r MiniRunner) GetOptions() lib.Options {\n\treturn r.Options\n}\n\n// SetOptions allows you to override the runner options.\nfunc (r *MiniRunner) SetOptions(opts lib.Options) error {\n\tr.Options = opts\n\n\tif r.PreInitState != nil {\n\t\tr.runTags = r.PreInitState.Registry.RootTagSet().WithTagsFromMap(r.Options.RunTags)\n\t}\n\n\treturn nil\n}\n\n// HandleSummary calls the specified summary callback, if supplied.\nfunc (r *MiniRunner) HandleSummary(\n\tctx context.Context,\n\tlegacy *lib.LegacySummary,\n\tsummary *summary.Summary,\n\t_ summary.Meta,\n) (map[string]io.Reader, error) {\n\tif r.HandleSummaryFn != nil {\n\t\treturn r.HandleSummaryFn(ctx, legacy, summary)\n\t}\n\treturn nil, nil //nolint:nilnil\n}\n\n// VU is a mock VU, spawned by a MiniRunner.\ntype VU struct {\n\tR            *MiniRunner\n\tOut          chan<- metrics.SampleContainer\n\tID, IDGlobal uint64\n\tIteration    int64\n\tstate        *lib.State\n\t// count of iterations executed by this VU in each scenario\n\tscenarioIter map[string]uint64\n}\n\n// ActiveVU holds a VU and its activation parameters\ntype ActiveVU struct {\n\t*VU\n\t*lib.VUActivationParams\n\tbusy chan struct{}\n\n\tscenarioName              string\n\tgetNextIterations         func() (uint64, uint64)\n\tscIterLocal, scIterGlobal uint64\n}\n\n// GetID returns the unique VU ID.\nfunc (vu *VU) GetID() uint64 {\n\treturn vu.ID\n}\n\n// State returns the VU's State.\nfunc (vu *VU) State() *lib.State {\n\treturn vu.state\n}\n\n// Activate the VU so it will be able to run code.\nfunc (vu *VU) Activate(params *lib.VUActivationParams) lib.ActiveVU {\n\tctx := params.RunContext\n\n\tvu.state.GetScenarioVUIter = func() uint64 {\n\t\treturn vu.scenarioIter[params.Scenario]\n\t}\n\n\tavu := &ActiveVU{\n\t\tVU:                 vu,\n\t\tVUActivationParams: params,\n\t\tbusy:               make(chan struct{}, 1),\n\t\tscenarioName:       params.Scenario,\n\t\tscIterLocal:        ^uint64(0),\n\t\tscIterGlobal:       ^uint64(0),\n\t\tgetNextIterations:  params.GetNextIterationCounters,\n\t}\n\n\tvu.state.GetScenarioLocalVUIter = func() uint64 {\n\t\treturn avu.scIterLocal\n\t}\n\tvu.state.GetScenarioGlobalVUIter = func() uint64 {\n\t\treturn avu.scIterGlobal\n\t}\n\n\tcontext.AfterFunc(ctx, func() {\n\t\t// Wait for the VU to stop running, if it was, and prevent it from\n\t\t// running again for this activation\n\t\tavu.busy <- struct{}{}\n\n\t\tif params.DeactivateCallback != nil {\n\t\t\tparams.DeactivateCallback(vu)\n\t\t}\n\t})\n\n\treturn avu\n}\n\nfunc (vu *ActiveVU) incrIteration() {\n\tvu.Iteration++\n\tvu.state.Iteration = vu.Iteration\n\n\tif _, ok := vu.scenarioIter[vu.scenarioName]; ok {\n\t\tvu.scenarioIter[vu.scenarioName]++\n\t} else {\n\t\tvu.scenarioIter[vu.scenarioName] = 0\n\t}\n\tvu.scIterLocal, vu.scIterGlobal = vu.getNextIterations()\n}\n\n// RunOnce runs the mock default function once, incrementing its iteration.\nfunc (vu *ActiveVU) RunOnce() error {\n\tif vu.R.Fn == nil {\n\t\treturn nil\n\t}\n\n\tselect {\n\tcase <-vu.RunContext.Done():\n\t\treturn vu.RunContext.Err() // we are done, return\n\tcase vu.busy <- struct{}{}:\n\t\t// nothing else can run now, and the VU cannot be deactivated\n\t}\n\tdefer func() {\n\t\t<-vu.busy // unlock deactivation again\n\t}()\n\n\tvu.incrIteration()\n\treturn vu.R.Fn(vu.RunContext, vu.State(), vu.Out)\n}\n"
  },
  {
    "path": "internal/lib/testutils/mockoutput/mockoutput.go",
    "content": "// Package mockoutput implements a mock output for testing purposes.\npackage mockoutput\n\nimport (\n\t\"go.k6.io/k6/metrics\"\n)\n\n// New exists so that the usage from tests avoids repetition, i.e. is\n// mockoutput.New() instead of &mockoutput.MockOutput{}\nfunc New() *MockOutput {\n\treturn &MockOutput{}\n}\n\n// MockOutput can be used in tests to mock an actual output.\ntype MockOutput struct {\n\tSampleContainers []metrics.SampleContainer\n\tSamples          []metrics.Sample\n\n\tDescFn  func() string\n\tStartFn func() error\n\tStopFn  func() error\n}\n\n// AddMetricSamples just saves the results in memory.\nfunc (mo *MockOutput) AddMetricSamples(scs []metrics.SampleContainer) {\n\tmo.SampleContainers = append(mo.SampleContainers, scs...)\n\tfor _, sc := range scs {\n\t\tmo.Samples = append(mo.Samples, sc.GetSamples()...)\n\t}\n}\n\n// Description calls the supplied DescFn callback, if available.\nfunc (mo *MockOutput) Description() string {\n\tif mo.DescFn != nil {\n\t\treturn mo.DescFn()\n\t}\n\treturn \"mock\"\n}\n\n// Start calls the supplied StartFn callback, if available.\nfunc (mo *MockOutput) Start() error {\n\tif mo.StartFn != nil {\n\t\treturn mo.StartFn()\n\t}\n\treturn nil\n}\n\n// Stop calls the supplied StopFn callback, if available.\nfunc (mo *MockOutput) Stop() error {\n\tif mo.StopFn != nil {\n\t\treturn mo.StopFn()\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "internal/lib/testutils/mockresolver/resolver.go",
    "content": "// Package mockresolver provides a mock implementation of netext.Resolver.\npackage mockresolver\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n)\n\n// MockResolver implements netext.Resolver, and allows changing the host\n// mapping at runtime.\ntype MockResolver struct {\n\tm           sync.RWMutex\n\thosts       map[string][]net.IP\n\tResolveHook func(host string, result []net.IP)\n}\n\n// New returns a new MockResolver.\nfunc New(hosts map[string][]net.IP) *MockResolver {\n\tif hosts == nil {\n\t\thosts = make(map[string][]net.IP)\n\t}\n\treturn &MockResolver{hosts: hosts}\n}\n\n// LookupIP returns the first IP mapped for host.\nfunc (r *MockResolver) LookupIP(host string) (net.IP, error) {\n\tif ips, err := r.LookupIPAll(host); err != nil {\n\t\treturn nil, err\n\t} else if len(ips) > 0 {\n\t\treturn ips[0], nil\n\t}\n\treturn nil, nil\n}\n\n// LookupIPAll returns all IPs mapped for host. It mimics the net.LookupIP\n// signature so that it can be used to mock netext.LookupIP in tests.\nfunc (r *MockResolver) LookupIPAll(host string) (ips []net.IP, err error) {\n\tdefer func() {\n\t\tif r.ResolveHook != nil {\n\t\t\tr.ResolveHook(host, ips)\n\t\t}\n\t}()\n\tr.m.RLock()\n\tdefer r.m.RUnlock()\n\tif ips, ok := r.hosts[host]; ok {\n\t\treturn ips, nil\n\t}\n\treturn nil, fmt.Errorf(\"lookup %s: no such host\", host)\n}\n\n// Set the host to resolve to ip.\nfunc (r *MockResolver) Set(host, ip string) {\n\tr.m.Lock()\n\tdefer r.m.Unlock()\n\tr.hosts[host] = []net.IP{net.ParseIP(ip)}\n}\n\n// Unset removes the host.\nfunc (r *MockResolver) Unset(host string) {\n\tr.m.Lock()\n\tdefer r.m.Unlock()\n\tdelete(r.hosts, host)\n}\n"
  },
  {
    "path": "internal/lib/testutils/test_output.go",
    "content": "package testutils\n\nimport (\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// Something that makes the test also be a valid io.Writer, useful for passing it\n// as an output for logs and CLI flag help messages...\ntype testOutput struct{ testing.TB }\n\nfunc (to testOutput) Write(p []byte) (n int, err error) {\n\tto.Logf(\"%s\", p)\n\n\treturn len(p), nil\n}\n\n// NewTestOutput returns a simple io.Writer implementation that uses the test's\n// logger as an output.\nfunc NewTestOutput(t testing.TB) io.Writer {\n\treturn testOutput{t}\n}\n\nfunc newLogger(t testing.TB, level logrus.Level) *logrus.Logger { //nolint:forbidigo\n\tl := logrus.New()\n\tl.SetLevel(level)\n\tvar w io.Writer\n\tif t == nil {\n\t\tw = io.Discard\n\t} else {\n\t\tw = NewTestOutput(t)\n\t}\n\tlogrus.SetOutput(w)\n\treturn l\n}\n\n// NewLogger returns a new logger instance. If the given argument is not nil,\n// the logger will log everything using its t.Logf() method. If its nil, all\n// messages will be discarded.\nfunc NewLogger(t testing.TB) logrus.FieldLogger {\n\treturn newLogger(t, logrus.InfoLevel)\n}\n\n// NewLoggerWithHook calls NewLogger() and attaches a hook with the given\n// levels. If no levels are specified, then logrus.AllLevels will be used and\n// the lowest log level will be Debug.\nfunc NewLoggerWithHook(t testing.TB, levels ...logrus.Level) (logrus.FieldLogger, *SimpleLogrusHook) {\n\tmaxLevel := logrus.PanicLevel\n\tif len(levels) == 0 {\n\t\tlevels = logrus.AllLevels\n\t\tmaxLevel = logrus.DebugLevel\n\t} else {\n\t\tfor _, l := range levels {\n\t\t\tif l > maxLevel {\n\t\t\t\tmaxLevel = l\n\t\t\t}\n\t\t}\n\t}\n\n\tl := newLogger(t, maxLevel)\n\thook := NewLogHook(levels...)\n\tl.AddHook(hook)\n\treturn l, hook\n}\n"
  },
  {
    "path": "internal/lib/testutils/untar.go",
    "content": "// Package testutils contains the test utilities and helpers inside the k6 project.\npackage testutils\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// Untar a simple test helper that untars a `fileName` file to a `destination` path\nfunc Untar(t *testing.T, fileSystem fsext.Fs, fileName string, destination string) error {\n\tt.Helper()\n\n\tarchiveFile, err := fsext.ReadFile(fileSystem, fileName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treader := bytes.NewBuffer(archiveFile)\n\n\ttr := tar.NewReader(reader)\n\n\tfor {\n\t\theader, err := tr.Next()\n\t\tswitch {\n\t\tcase errors.Is(err, io.EOF):\n\t\t\treturn nil\n\t\tcase err != nil:\n\t\t\treturn err\n\t\tcase header == nil:\n\t\t\tcontinue\n\t\t}\n\n\t\tfileName := header.Name\n\t\tif !filepath.IsLocal(fileName) {\n\t\t\treturn errors.New(\"tar file contains non-local file names\")\n\t\t}\n\n\t\ttarget := filepath.Join(destination, filepath.Clean(fileName))\n\n\t\tswitch header.Typeflag {\n\t\tcase tar.TypeDir:\n\t\t\tif _, err := fileSystem.Stat(target); err != nil && !errors.Is(err, fs.ErrNotExist) {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := fileSystem.MkdirAll(target, 0o755); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase tar.TypeReg:\n\t\t\tf, err := fileSystem.OpenFile(target, syscall.O_CREAT|syscall.O_RDWR, fs.FileMode(header.Mode)) //nolint:gosec\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() { _ = f.Close() }()\n\n\t\t\tif _, err := io.CopyN(f, tr, header.Size); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/lib/trace/doc.go",
    "content": "// Package trace provides functionalities for tracing instrumentation.\npackage trace\n"
  },
  {
    "path": "internal/lib/trace/otel.go",
    "content": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp\"\n\t\"go.opentelemetry.io/otel/sdk/resource\"\n\tsdktrace \"go.opentelemetry.io/otel/sdk/trace\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.20.0\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"go.opentelemetry.io/otel/trace/noop\"\n\n\t\"go.k6.io/k6/internal/lib/strvals\"\n)\n\nconst serviceName = \"k6\"\n\nvar (\n\t// ErrInvalidTracesOutput indicates that the defined traces output is not valid.\n\tErrInvalidTracesOutput = errors.New(\"invalid traces output\")\n\t// ErrInvalidProto indicates that the defined exporter protocol is not valid.\n\tErrInvalidProto = errors.New(\"invalid protocol\")\n\t// ErrInvalidURLScheme indicates that the defined exporter URL scheme is not valid.\n\tErrInvalidURLScheme = errors.New(\"invalid URL scheme\")\n\t// ErrInvalidGRPCWithURLPath indicates that an exporter using gRPC protocol does not support URL path.\n\tErrInvalidGRPCWithURLPath = errors.New(\"grpc protocol does not support URL path\")\n)\n\ntype (\n\ttracerProvShutdownFunc func(ctx context.Context) error\n)\n\n// TracerProvider provides methods for tracers initialization and shutdown of the\n// processing pipeline.\ntype TracerProvider struct {\n\ttrace.TracerProvider\n\tshutdown tracerProvShutdownFunc\n}\n\ntype tracerProviderParams struct {\n\tproto    string\n\tendpoint string\n\turlPath  string\n\tinsecure bool\n\theaders  map[string]string\n}\n\nfunc defaultTracerProviderParams() tracerProviderParams {\n\treturn tracerProviderParams{\n\t\tproto:    \"grpc\",\n\t\tendpoint: \"127.0.0.1:4317\",\n\t\tinsecure: true,\n\t\theaders:  make(map[string]string),\n\t}\n}\n\n// NewTracerProvider creates a new tracer provider.\nfunc NewTracerProvider(ctx context.Context, params tracerProviderParams) (*TracerProvider, error) {\n\tclient, err := newClient(params)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating TracerProvider exporter client: %w\", err)\n\t}\n\n\texporter, err := otlptrace.New(ctx, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating TracerProvider exporter: %w\", err)\n\t}\n\n\tprov := sdktrace.NewTracerProvider(\n\t\tsdktrace.WithBatcher(exporter),\n\t\tsdktrace.WithResource(newResource()),\n\t)\n\n\t// Set a noop TracerProvider globally so usage of tracing\n\t// instrumentation is restricted to our own implementation\n\totel.SetTracerProvider(NewNoopTracerProvider())\n\n\treturn &TracerProvider{\n\t\tTracerProvider: prov,\n\t\tshutdown:       prov.Shutdown,\n\t}, nil\n}\n\nfunc newResource() *resource.Resource {\n\treturn resource.NewWithAttributes(\n\t\tsemconv.SchemaURL,\n\t\tsemconv.ServiceName(serviceName),\n\t)\n}\n\nfunc newClient(params tracerProviderParams) (otlptrace.Client, error) {\n\tswitch params.proto {\n\tcase \"http\":\n\t\treturn newHTTPClient(params.endpoint, params.urlPath, params.insecure, params.headers), nil\n\tcase \"grpc\":\n\t\treturn newGRPCClient(params.endpoint, params.insecure, params.headers), nil\n\tdefault:\n\t\treturn nil, ErrInvalidProto\n\t}\n}\n\nfunc newHTTPClient(endpoint, urlPath string, insecure bool, headers map[string]string) otlptrace.Client {\n\topts := []otlptracehttp.Option{\n\t\totlptracehttp.WithEndpoint(endpoint),\n\t\totlptracehttp.WithURLPath(urlPath),\n\t\totlptracehttp.WithHeaders(headers),\n\t}\n\tif insecure {\n\t\topts = append(opts, otlptracehttp.WithInsecure())\n\t}\n\treturn otlptracehttp.NewClient(opts...)\n}\n\nfunc newGRPCClient(endpoint string, insecure bool, headers map[string]string) otlptrace.Client {\n\topts := []otlptracegrpc.Option{\n\t\totlptracegrpc.WithEndpoint(endpoint),\n\t\totlptracegrpc.WithHeaders(headers),\n\t}\n\tif insecure {\n\t\topts = append(opts, otlptracegrpc.WithInsecure())\n\t}\n\treturn otlptracegrpc.NewClient(opts...)\n}\n\n// NewNoopTracerProvider creates a new noop TracerProvider.\nfunc NewNoopTracerProvider() *TracerProvider {\n\tprov := noop.NewTracerProvider()\n\tnoopShutdown := func(context.Context) error { return nil }\n\n\totel.SetTracerProvider(prov)\n\n\treturn &TracerProvider{\n\t\tTracerProvider: prov,\n\t\tshutdown:       noopShutdown,\n\t}\n}\n\n// Shutdown shuts down the TracerProvider releasing any held computational resources.\n// After Shutdown is called, all methods are no-ops.\nfunc (tp *TracerProvider) Shutdown(ctx context.Context) error {\n\treturn tp.shutdown(ctx)\n}\n\n// TracerProviderFromConfigLine initializes a new TracerProvider based on the configuration\n// specified through input line.\n//\n// Supported format is: otel[=<endpoint>:<port>,<other opts>]\n// Where endpoint and port default to: 127.0.0.1:4317\n// And other opts accept:\n//   - proto: http or grpc (default).\n//   - header.<header_name>\n//\n// Example: otel=127.0.0.1:4318/v1/traces,proto=http,header.Authorization=token ***\nfunc TracerProviderFromConfigLine(ctx context.Context, line string) (*TracerProvider, error) {\n\tparams, err := tracerProviderParamsFromConfigLine(line)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewTracerProvider(ctx, params)\n}\n\nfunc tracerProviderParamsFromConfigLine(line string) (tracerProviderParams, error) {\n\tparams := defaultTracerProviderParams()\n\n\tif line == \"otel\" {\n\t\t// Use default params\n\t\treturn params, nil\n\t}\n\n\ttraceOutput, _, _ := strings.Cut(line, \"=\")\n\tif traceOutput != \"otel\" {\n\t\treturn params, fmt.Errorf(\"%w %q\", ErrInvalidTracesOutput, traceOutput)\n\t}\n\n\ttokens, err := strvals.Parse(line)\n\tif err != nil {\n\t\treturn params, fmt.Errorf(\"error while parsing otel configuration %w\", err)\n\t}\n\n\tfor _, token := range tokens {\n\t\tkey := token.Key\n\t\tvalue := token.Value\n\n\t\tvar err error\n\t\tswitch key {\n\t\tcase \"otel\":\n\t\t\terr = params.parseURL(value)\n\t\t\tif err != nil {\n\t\t\t\treturn params, fmt.Errorf(\"couldn't parse the otel URL: %w\", err)\n\t\t\t}\n\t\tcase \"proto\":\n\t\t\terr = params.parseProto(value)\n\t\t\tif err != nil {\n\t\t\t\treturn params, fmt.Errorf(\"couldn't parse the otel proto: %w\", err)\n\t\t\t}\n\t\tdefault:\n\t\t\tif strings.HasPrefix(key, \"header.\") {\n\t\t\t\tparams.parseHeader(key, value)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn params, fmt.Errorf(\"unknown otel config key %s\", key)\n\t\t}\n\t}\n\n\tif params.proto == \"grpc\" && params.urlPath != \"\" {\n\t\treturn params, ErrInvalidGRPCWithURLPath\n\t}\n\n\treturn params, nil\n}\n\nfunc (p *tracerProviderParams) parseURL(s string) error {\n\tu, err := url.Parse(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif u.Scheme != \"http\" && u.Scheme != \"https\" {\n\t\treturn fmt.Errorf(\"%w: %q\", ErrInvalidURLScheme, u.Scheme)\n\t}\n\n\tp.proto = \"http\"\n\tp.endpoint = u.Host\n\tp.urlPath = u.Path\n\tp.insecure = u.Scheme == \"http\"\n\n\treturn nil\n}\n\nfunc (p *tracerProviderParams) parseProto(proto string) error {\n\tif proto != \"http\" && proto != \"grpc\" {\n\t\treturn fmt.Errorf(\"%w: %q\", ErrInvalidProto, proto)\n\t}\n\n\tp.proto = proto\n\n\treturn nil\n}\n\nfunc (p *tracerProviderParams) parseHeader(header, value string) {\n\theaderName := strings.TrimPrefix(header, \"header.\")\n\tp.headers[headerName] = value\n}\n"
  },
  {
    "path": "internal/lib/trace/otel_test.go",
    "content": "package trace\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTracerProviderParamsFromConfigLine(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := [...]struct {\n\t\tname      string\n\t\tline      string\n\t\texpParams tracerProviderParams\n\t\texpErr    error\n\t}{\n\t\t{\n\t\t\tname:      \"default otel\",\n\t\t\tline:      \"otel\",\n\t\t\texpParams: defaultTracerProviderParams(),\n\t\t},\n\t\t{\n\t\t\tname: \"otel with insecure url and custom path\",\n\t\t\tline: \"otel=http://localhost:4444/custom/traces\",\n\t\t\texpParams: tracerProviderParams{\n\t\t\t\tproto:    \"http\",\n\t\t\t\tendpoint: \"localhost:4444\",\n\t\t\t\turlPath:  \"/custom/traces\",\n\t\t\t\tinsecure: true,\n\t\t\t\theaders:  make(map[string]string),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"otel with secure url and no port\",\n\t\t\tline: \"otel=https://localhost\",\n\t\t\texpParams: tracerProviderParams{\n\t\t\t\tproto:    \"http\",\n\t\t\t\tendpoint: \"localhost\",\n\t\t\t\theaders:  make(map[string]string),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"otel with grpc proto\",\n\t\t\tline: \"otel=https://localhost,proto=grpc\",\n\t\t\texpParams: tracerProviderParams{\n\t\t\t\tproto:    \"grpc\",\n\t\t\t\tendpoint: \"localhost\",\n\t\t\t\theaders:  make(map[string]string),\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"otel with headers\",\n\t\t\tline: \"otel=https://localhost,header.Authorization=token ***,header.other=test\",\n\t\t\texpParams: tracerProviderParams{\n\t\t\t\tproto:    \"http\",\n\t\t\t\tendpoint: \"localhost\",\n\t\t\t\theaders: map[string]string{\n\t\t\t\t\t\"Authorization\": \"token ***\",\n\t\t\t\t\t\"other\":         \"test\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:   \"error invalid output\",\n\t\t\tline:   \"invalid\",\n\t\t\texpErr: ErrInvalidTracesOutput,\n\t\t},\n\t\t{\n\t\t\tname:   \"error invalid scheme\",\n\t\t\tline:   \"otel=invalid://localhost:4444/traces\",\n\t\t\texpErr: ErrInvalidURLScheme,\n\t\t},\n\t\t{\n\t\t\tname:   \"error invalid proto\",\n\t\t\tline:   \"otel=http://localhost:4444,proto=invalid\",\n\t\t\texpErr: ErrInvalidProto,\n\t\t},\n\t\t{\n\t\t\tname:   \"error invalid grpc proto with URL path\",\n\t\t\tline:   \"otel=http://localhost:4444/url/path,proto=grpc\",\n\t\t\texpErr: ErrInvalidGRPCWithURLPath,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tparams, err := tracerProviderParamsFromConfigLine(tc.line)\n\t\t\tif err != nil {\n\t\t\t\trequire.ErrorIs(t, err, tc.expErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.Equal(t, tc.expParams, params)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/loader/filesystems.go",
    "content": "package loader\n\nimport (\n\t\"runtime\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// CreateFilesystems creates the correct filesystem map for the current OS\nfunc CreateFilesystems(osfs fsext.Fs) map[string]fsext.Fs {\n\t// We want to eliminate disk access at runtime, so we set up a memory mapped cache that's\n\t// written every time something is read from the real filesystem. This cache is then used for\n\t// successive spawns to read from (they have no access to the real disk).\n\t// Also initialize the same for `https` but the caching is handled manually in the loader package\n\tif runtime.GOOS == \"windows\" {\n\t\t// This is done so that we can continue to use paths with /|\"\\\" through the code but also to\n\t\t// be easier to traverse the cachedFs later as it doesn't work very well if you have windows\n\t\t// volumes\n\t\tosfs = fsext.NewTrimFilePathSeparatorFs(osfs)\n\t}\n\treturn map[string]fsext.Fs{\n\t\t\"file\":  fsext.NewCacheOnReadFs(osfs, fsext.NewMemMapFs(), 0),\n\t\t\"https\": fsext.NewMemMapFs(),\n\t}\n}\n"
  },
  {
    "path": "internal/loader/loader.go",
    "content": "// Package loader is about loading files from either the filesystem or through https requests.\npackage loader\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// SourceData wraps a source file; data and filename.\ntype SourceData struct {\n\tData []byte\n\tURL  *url.URL\n\tPWD  *url.URL\n}\n\nconst (\n\thttpsSchemeCouldntBeLoadedMsg = `The moduleSpecifier \"%s\" couldn't be retrieved from` +\n\t\t` the resolved url \"%s\". Error : \"%s\"`\n\tfileSchemeCouldntBeLoadedMsg = `The moduleSpecifier \"%s\" couldn't be found on ` +\n\t\t`local disk. Make sure that you've specified the right path to the file. If you're ` +\n\t\t`running k6 using the Docker image make sure you have mounted the ` +\n\t\t`local directory (-v /local/path/:/inside/docker/path) containing ` +\n\t\t`your script and modules so that they're accessible by k6 from ` +\n\t\t`inside of the container, see ` +\n\t\t`https://grafana.com/docs/k6/latest/using-k6/modules/#use-modules-with-docker.`\n)\n\ntype unresolvableURLError string\n\nfunc (u unresolvableURLError) Error() string {\n\t// TODO potentially add more things about what k6 supports if users report being confused.\n\treturn fmt.Sprintf(`The moduleSpecifier %q couldn't be recognised as something k6 supports.`, (string)(u))\n}\n\n// Resolve a relative path to an absolute one.\nfunc Resolve(pwd *url.URL, moduleSpecifier string) (*url.URL, error) {\n\tif moduleSpecifier == \"\" {\n\t\treturn nil, errors.New(\"local or remote path required\")\n\t}\n\n\tif moduleSpecifier[0] == '.' || moduleSpecifier[0] == '/' || filepath.IsAbs(moduleSpecifier) {\n\t\treturn resolveFilePath(pwd, moduleSpecifier)\n\t}\n\n\tif strings.Contains(moduleSpecifier, \"://\") {\n\t\tu, err := url.Parse(moduleSpecifier)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif u.Scheme != \"file\" && u.Scheme != \"https\" {\n\t\t\treturn nil,\n\t\t\t\tfmt.Errorf(\"only supported schemes for imports are file and https, %s has `%s`\",\n\t\t\t\t\tmoduleSpecifier, u.Scheme)\n\t\t}\n\t\tif u.Scheme == \"file\" && pwd.Scheme == \"https\" {\n\t\t\treturn nil, fmt.Errorf(\"origin (%s) not allowed to load local file: %s\", pwd, moduleSpecifier)\n\t\t}\n\t\treturn u, err\n\t}\n\n\tif strings.HasPrefix(moduleSpecifier, \"cdnjs.com\") {\n\t\treturn nil, fmt.Errorf(\"cdnjs.com 'special' urls are no longer supported - please use real ones. \" +\n\t\t\t\"You can get yours by going to cdnjs and copy-pasting the full url to the actual JavaScript file\")\n\t}\n\tif strings.HasPrefix(moduleSpecifier, \"github.com\") {\n\t\treturn nil, fmt.Errorf(\"github.com 'special' urls are no longer supported - please use real ones. \" +\n\t\t\t\"You can get yours by going to github and copy-pasting the full url to the actual raw JavaScript file\")\n\t}\n\treturn nil, unresolvableURLError(moduleSpecifier)\n}\n\nfunc resolveFilePath(pwd *url.URL, moduleSpecifier string) (*url.URL, error) {\n\tif pwd.Opaque != \"\" { // this is a loader reference\n\t\tbase, dir, _ := strings.Cut(pwd.Opaque, \"/\")\n\t\tif moduleSpecifier[0] == '/' {\n\t\t\treturn &url.URL{Opaque: path.Join(base, moduleSpecifier)}, nil\n\t\t}\n\t\treturn &url.URL{Opaque: path.Join(base, path.Join(path.Dir(dir+\"/\"), moduleSpecifier))}, nil\n\t}\n\n\t// The file is in format like C:/something/path.js. But this will be decoded as scheme `C`\n\t// ... which is not what we want, we want it to be decoded as file:///C:/something/path.js\n\tif filepath.VolumeName(moduleSpecifier) != \"\" {\n\t\tmoduleSpecifier = \"/\" + moduleSpecifier\n\t}\n\n\t// we always want for the pwd to end in a slash, but filepath/path.Clean strips it so we read\n\t// it if it's missing\n\tfinalPwd := pwd\n\tif pwd.Opaque != \"\" {\n\t\tif !strings.HasSuffix(pwd.Opaque, \"/\") {\n\t\t\tfinalPwd = &url.URL{Opaque: pwd.Opaque + \"/\"}\n\t\t}\n\t} else if !strings.HasSuffix(pwd.Path, \"/\") {\n\t\tfinalPwd = &url.URL{}\n\t\t*finalPwd = *pwd\n\t\tfinalPwd.Path += \"/\"\n\t}\n\treturn finalPwd.Parse(moduleSpecifier)\n}\n\n// Dir returns the directory for the path.\nfunc Dir(old *url.URL) *url.URL {\n\treturn old.ResolveReference(&url.URL{Path: \"./\"})\n}\n\n// Load loads the provided moduleSpecifier from the given filesystems which are map of fsext.Fs\n// for a given scheme which is they key of the map. If the scheme is https then a request will\n// be made if the files is not found in the map and written to the map.\nfunc Load(\n\tlogger logrus.FieldLogger, filesystems map[string]fsext.Fs, moduleSpecifier *url.URL, originalModuleSpecifier string,\n) (*SourceData, error) {\n\tlogger.WithFields(\n\t\tlogrus.Fields{\n\t\t\t\"moduleSpecifier\":         moduleSpecifier,\n\t\t\t\"originalModuleSpecifier\": originalModuleSpecifier,\n\t\t}).Debug(\"Loading...\")\n\n\tvar pathOnFs string\n\tswitch moduleSpecifier.Scheme {\n\tcase \"\":\n\t\tpathOnFs = path.Clean(moduleSpecifier.String())\n\tdefault:\n\t\tpathOnFs = path.Clean(moduleSpecifier.String()[len(moduleSpecifier.Scheme)+len(\":/\"):])\n\t}\n\tscheme := moduleSpecifier.Scheme\n\tif scheme == \"\" {\n\t\tif moduleSpecifier.Opaque == \"\" {\n\t\t\treturn nil, fmt.Errorf(fileSchemeCouldntBeLoadedMsg, originalModuleSpecifier) //nolint:staticcheck\n\t\t}\n\t\tscheme = \"https\"\n\t}\n\n\tpathOnFs, err := url.PathUnescape(filepath.FromSlash(pathOnFs))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata, err := fsext.ReadFile(filesystems[scheme], pathOnFs)\n\n\tif err == nil {\n\t\treturn &SourceData{URL: moduleSpecifier, Data: data}, nil\n\t}\n\tif !errors.Is(err, fs.ErrNotExist) {\n\t\treturn nil, err\n\t}\n\tif scheme != \"https\" {\n\t\treturn nil, fmt.Errorf(fileSchemeCouldntBeLoadedMsg, originalModuleSpecifier) //nolint:staticcheck\n\t}\n\n\tfinalModuleSpecifierURL := moduleSpecifier\n\n\tvar result *SourceData\n\tresult, err = loadRemoteURL(logger, finalModuleSpecifierURL)\n\tif err != nil {\n\t\t//nolint:staticcheck\n\t\treturn nil, fmt.Errorf(httpsSchemeCouldntBeLoadedMsg, originalModuleSpecifier, finalModuleSpecifierURL, err)\n\t}\n\tresult.URL = moduleSpecifier\n\t// TODO maybe make an fsext.Fs which makes request directly and than use CacheOnReadFs\n\t// on top of as with the `file` scheme fs\n\t_ = fsext.WriteFile(filesystems[scheme], pathOnFs, result.Data, 0o644)\n\n\treturn result, nil\n}\n\nfunc loadRemoteURL(logger logrus.FieldLogger, u *url.URL) (*SourceData, error) {\n\toldQuery := u.RawQuery\n\tif u.RawQuery != \"\" {\n\t\tu.RawQuery += \"&\"\n\t}\n\tu.RawQuery += \"_k6=1\"\n\n\tdata, err := fetch(logger, u.String())\n\n\tu.RawQuery = oldQuery\n\t// If this fails, try to fetch without ?_k6=1 - some sources act weird around unknown GET args.\n\tif err != nil {\n\t\tdata, err = fetch(logger, u.String())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// TODO: Parse the HTML, look for meta tags!!\n\t// <meta name=\"k6-import\" content=\"example.com/path/to/real/file.txt\" />\n\t// <meta name=\"k6-import\" content=\"github.com/myusername/repo/file.txt\" />\n\n\treturn &SourceData{URL: u, Data: data}, nil\n}\n\nfunc fetch(logger logrus.FieldLogger, u string) ([]byte, error) {\n\tlogger.WithField(\"url\", u).Debug(\"Fetching source...\")\n\tstartTime := time.Now()\n\tctx, cancel := context.WithTimeout(context.Background(), time.Minute)\n\tdefer cancel()\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tres, err := http.DefaultClient.Do(req) //nolint:gosec\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() { _ = res.Body.Close() }()\n\n\tif res.StatusCode != http.StatusOK {\n\t\tswitch res.StatusCode {\n\t\tcase http.StatusNotFound:\n\t\t\treturn nil, fmt.Errorf(\"not found: %s\", u)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"wrong status code (%d) for: %s\", res.StatusCode, u)\n\t\t}\n\t}\n\n\tdata, err := io.ReadAll(res.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlogger.WithFields(logrus.Fields{\n\t\t\"url\": u,\n\t\t\"t\":   time.Since(startTime),\n\t\t\"len\": len(data),\n\t}).Debug(\"Fetched!\")\n\treturn data, nil\n}\n"
  },
  {
    "path": "internal/loader/loader_test.go",
    "content": "package loader_test\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestDir(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]string{\n\t\t\"/path/to/file.txt\": filepath.FromSlash(\"/path/to/\"),\n\t\t\"-\":                 \"/\",\n\t}\n\tfor name, dir := range testdata {\n\t\tnameURL := &url.URL{Scheme: \"file\", Path: name}\n\t\tdirURL := &url.URL{Scheme: \"file\", Path: filepath.ToSlash(dir)}\n\t\tt.Run(\"path=\"+name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tassert.Equal(t, dirURL, loader.Dir(nameURL))\n\t\t})\n\t}\n}\n\nfunc TestResolve(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Blank\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := loader.Resolve(nil, \"\")\n\t\tassert.EqualError(t, err, \"local or remote path required\")\n\t})\n\n\tt.Run(\"Protocol\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\troot, err := url.Parse(\"file:///\")\n\t\trequire.NoError(t, err)\n\n\t\tt.Run(\"Missing\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tu, err := loader.Resolve(root, \"example.com/html\")\n\t\t\trequire.ErrorContains(t, err, \"The moduleSpecifier \\\"example.com/html\\\" couldn't be recognised as something k6 supports\")\n\t\t\trequire.Nil(t, u)\n\t\t})\n\t\tt.Run(\"WS\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tmoduleSpecifier := \"ws://example.com/html\"\n\t\t\t_, err := loader.Resolve(root, moduleSpecifier)\n\t\t\tassert.EqualError(t, err,\n\t\t\t\t\"only supported schemes for imports are file and https, \"+moduleSpecifier+\" has `ws`\")\n\t\t})\n\n\t\tt.Run(\"HTTP\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tmoduleSpecifier := \"http://example.com/html\"\n\t\t\t_, err := loader.Resolve(root, moduleSpecifier)\n\t\t\tassert.EqualError(t, err,\n\t\t\t\t\"only supported schemes for imports are file and https, \"+moduleSpecifier+\" has `http`\")\n\t\t})\n\t})\n\n\tt.Run(\"Remote Lifting Denied\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tpwdURL, err := url.Parse(\"https://example.com/\")\n\t\trequire.NoError(t, err)\n\n\t\t_, err = loader.Resolve(pwdURL, \"file:///etc/shadow\")\n\t\tassert.EqualError(t, err, \"origin (https://example.com/) not allowed to load local file: file:///etc/shadow\")\n\t})\n\n\tt.Run(\"Fixes missing slash in pwd\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tpwdURL, err := url.Parse(\"https://example.com/path/to\")\n\t\trequire.NoError(t, err)\n\n\t\tmoduleURL, err := loader.Resolve(pwdURL, \"./something\")\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"https://example.com/path/to/something\", moduleURL.String())\n\t\trequire.Equal(t, \"https://example.com/path/to\", pwdURL.String())\n\t})\n}\n\n//nolint:tparallel // this touch the global http.DefaultTransport\nfunc TestLoad(t *testing.T) {\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\tsr := tb.Replacer.Replace\n\n\t// TODO figure out a way to not replace the default transport globally so we can have this tool be in parallel and\n\t// then break it into separate tests instead of having one very long one.\n\toldHTTPTransport := http.DefaultTransport\n\thttp.DefaultTransport = tb.HTTPTransport\n\tt.Cleanup(func() {\n\t\thttp.DefaultTransport = oldHTTPTransport\n\t})\n\t// All of the below handlerFuncs are here as they are used through the test\n\tconst responseStr = \"export function fn() {\\r\\n    return 1234;\\r\\n}\"\n\ttb.Mux.HandleFunc(\"/raw/something\", func(w http.ResponseWriter, r *http.Request) {\n\t\tif _, ok := r.URL.Query()[\"_k6\"]; ok {\n\t\t\thttp.Error(w, \"Internal server error\", http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\t_, err := fmt.Fprint(w, responseStr)\n\t\tassert.NoError(t, err)\n\t})\n\n\ttb.Mux.HandleFunc(\"/invalid\", func(w http.ResponseWriter, _ *http.Request) {\n\t\thttp.Error(w, \"Internal server error\", http.StatusInternalServerError)\n\t})\n\n\tt.Run(\"Local\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestdata := map[string]struct{ pwd, path string }{\n\t\t\t\"Absolute\": {\"/path/\", \"/path/to/file.txt\"},\n\t\t\t\"Relative\": {\"/path/\", \"./to/file.txt\"},\n\t\t\t\"Adjacent\": {\"/path/to/\", \"./file.txt\"},\n\t\t}\n\n\t\tfor name, data := range testdata {\n\t\t\tt.Run(name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tpwdURL, err := url.Parse(\"file://\" + data.pwd)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tmoduleURL, err := loader.Resolve(pwdURL, data.path)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tfilesystems := make(map[string]fsext.Fs)\n\t\t\t\tfilesystems[\"file\"] = fsext.NewMemMapFs()\n\t\t\t\tassert.NoError(t, filesystems[\"file\"].MkdirAll(\"/path/to\", 0o755))\n\t\t\t\tassert.NoError(t, fsext.WriteFile(filesystems[\"file\"], \"/path/to/file.txt\", []byte(\"hi\"), 0o644))\n\t\t\t\tsrc, err := loader.Load(logger, filesystems, moduleURL, data.path)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tassert.Equal(t, \"file:///path/to/file.txt\", src.URL.String())\n\t\t\t\tassert.Equal(t, \"hi\", string(src.Data))\n\t\t\t})\n\t\t}\n\n\t\tt.Run(\"Nonexistent\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfilesystems := make(map[string]fsext.Fs)\n\t\t\tfilesystems[\"file\"] = fsext.NewMemMapFs()\n\t\t\tassert.NoError(t, filesystems[\"file\"].MkdirAll(\"/path/to\", 0o755))\n\t\t\tassert.NoError(t, fsext.WriteFile(filesystems[\"file\"], \"/path/to/file.txt\", []byte(\"hi\"), 0o644))\n\n\t\t\troot, err := url.Parse(\"file:///\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\tpath := filepath.FromSlash(\"/nonexistent\")\n\t\t\tpathURL, err := loader.Resolve(root, \"/nonexistent\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = loader.Load(logger, filesystems, pathURL, path)\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(),\n\t\t\t\tfmt.Sprintf(`The moduleSpecifier \"%s\" couldn't be found on local disk. `,\n\t\t\t\t\tpath))\n\t\t})\n\t})\n\n\tt.Run(\"Remote\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"From local\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfilesystems := map[string]fsext.Fs{\"https\": fsext.NewMemMapFs()}\n\t\t\troot, err := url.Parse(\"file:///\")\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmoduleSpecifier := sr(\"HTTPSBIN_URL/html\")\n\t\t\tmoduleSpecifierURL, err := loader.Resolve(root, moduleSpecifier)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tsrc, err := loader.Load(logger, filesystems, moduleSpecifierURL, moduleSpecifier)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, src.URL, moduleSpecifierURL)\n\t\t\tassert.Contains(t, string(src.Data), \"Herman Melville - Moby-Dick\")\n\t\t})\n\n\t\tt.Run(\"Absolute\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfilesystems := map[string]fsext.Fs{\"https\": fsext.NewMemMapFs()}\n\t\t\tpwdURL, err := url.Parse(sr(\"HTTPSBIN_URL\"))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmoduleSpecifier := sr(\"HTTPSBIN_URL/robots.txt\")\n\t\t\tmoduleSpecifierURL, err := loader.Resolve(pwdURL, moduleSpecifier)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tsrc, err := loader.Load(logger, filesystems, moduleSpecifierURL, moduleSpecifier)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, src.URL.String(), sr(\"HTTPSBIN_URL/robots.txt\"))\n\t\t\tassert.Equal(t, string(src.Data), \"User-agent: *\\nDisallow: /deny\\n\")\n\t\t})\n\n\t\tt.Run(\"Relative\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfilesystems := map[string]fsext.Fs{\"https\": fsext.NewMemMapFs()}\n\t\t\tpwdURL, err := url.Parse(sr(\"HTTPSBIN_URL\"))\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmoduleSpecifier := (\"./robots.txt\")\n\t\t\tmoduleSpecifierURL, err := loader.Resolve(pwdURL, moduleSpecifier)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tsrc, err := loader.Load(logger, filesystems, moduleSpecifierURL, moduleSpecifier)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, sr(\"HTTPSBIN_URL/robots.txt\"), src.URL.String())\n\t\t\tassert.Equal(t, \"User-agent: *\\nDisallow: /deny\\n\", string(src.Data))\n\t\t})\n\t})\n\n\tt.Run(\"No _k6=1 Fallback\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\troot, err := url.Parse(\"file:///\")\n\t\trequire.NoError(t, err)\n\n\t\tmoduleSpecifier := sr(\"HTTPSBIN_URL/raw/something\")\n\t\tmoduleSpecifierURL, err := loader.Resolve(root, moduleSpecifier)\n\t\trequire.NoError(t, err)\n\n\t\tfilesystems := map[string]fsext.Fs{\"https\": fsext.NewMemMapFs()}\n\t\tsrc, err := loader.Load(logger, filesystems, moduleSpecifierURL, moduleSpecifier)\n\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, src.URL.String(), sr(\"HTTPSBIN_URL/raw/something\"))\n\t\tassert.Equal(t, responseStr, string(src.Data))\n\t})\n\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\troot, err := url.Parse(\"file:///\")\n\t\trequire.NoError(t, err)\n\n\t\ttestData := [...]struct {\n\t\t\tname, moduleSpecifier string\n\t\t}{\n\t\t\t{\"URL\", sr(\"HTTPSBIN_URL/invalid\")},\n\t\t\t{\"HOST\", \"https://some-path-that-doesnt-exist.js\"},\n\t\t}\n\n\t\tfor _, data := range testData {\n\t\t\tmoduleSpecifier := data.moduleSpecifier\n\t\t\tt.Run(data.name, func(t *testing.T) {\n\t\t\t\tfilesystems := map[string]fsext.Fs{\"https\": fsext.NewMemMapFs()}\n\t\t\t\tt.Parallel()\n\t\t\t\tmoduleSpecifierURL, err := loader.Resolve(root, moduleSpecifier)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t_, err = loader.Load(logger, filesystems, moduleSpecifierURL, moduleSpecifier)\n\t\t\t\trequire.Error(t, err)\n\t\t\t})\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "internal/loader/readsource.go",
    "content": "package loader\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/url\"\n\t\"path/filepath\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// ReadSource Reads a source file from any supported destination.\nfunc ReadSource(\n\tlogger logrus.FieldLogger, src, pwd string, filesystems map[string]fsext.Fs, stdin io.Reader,\n) (*SourceData, error) {\n\t// 'ToSlash' is here as URL only use '/' as separators, but on Windows paths use '\\'\n\tpwdURL := &url.URL{Scheme: \"file\", Path: filepath.ToSlash(filepath.Clean(pwd)) + \"/\"}\n\tif src == \"-\" {\n\t\tdata, err := io.ReadAll(stdin)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// TODO: don't do it in this way ...\n\t\t//nolint:forcetypeassert\n\t\terr = fsext.WriteFile(filesystems[\"file\"].(fsext.CacheLayerGetter).GetCachingFs(), \"/-\", data, 0o644)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"caching data read from -: %w\", err)\n\t\t}\n\t\treturn &SourceData{URL: &url.URL{Path: \"/-\", Scheme: \"file\"}, Data: data, PWD: pwdURL}, err\n\t}\n\tvar srcLocalPath string\n\tif filepath.IsAbs(src) {\n\t\tsrcLocalPath = src\n\t} else {\n\t\tsrcLocalPath = filepath.Join(pwd, src)\n\t}\n\t// All paths should start with a / in all fses. This is mostly for windows where it will start\n\t// with a volume name : C:\\something.js\n\tsrcLocalPath = filepath.Clean(fsext.FilePathSeparator + srcLocalPath)\n\tif ok, _ := fsext.Exists(filesystems[\"file\"], srcLocalPath); ok {\n\t\t// there is file on the local disk ... lets use it :)\n\t\treturn Load(logger, filesystems, &url.URL{Scheme: \"file\", Path: filepath.ToSlash(srcLocalPath)}, src)\n\t}\n\n\tsrcURL, err := Resolve(pwdURL, filepath.ToSlash(src))\n\tif err != nil {\n\t\tvar unresolvedError unresolvableURLError\n\t\tif errors.As(err, &unresolvedError) {\n\t\t\treturn nil, fmt.Errorf(fileSchemeCouldntBeLoadedMsg, (string)(unresolvedError)) //nolint:staticcheck\n\t\t}\n\t\treturn nil, err\n\t}\n\treturn Load(logger, filesystems, srcURL, src)\n}\n"
  },
  {
    "path": "internal/loader/readsource_test.go",
    "content": "package loader\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\ntype errorReader string\n\nfunc (e errorReader) Read(_ []byte) (int, error) {\n\treturn 0, errors.New((string)(e))\n}\n\nvar _ io.Reader = errorReader(\"\")\n\nfunc TestReadSourceSTDINError(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\t_, err := ReadSource(logger, \"-\", \"\", nil, errorReader(\"1234\"))\n\trequire.Error(t, err)\n\trequire.Equal(t, \"1234\", err.Error())\n}\n\nfunc TestReadSourceSTDINCache(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tdata := []byte(`test contents`)\n\tr := bytes.NewReader(data)\n\tfs := fsext.NewMemMapFs()\n\tsourceData, err := ReadSource(logger, \"-\", \"/path/to/pwd\",\n\t\tmap[string]fsext.Fs{\"file\": fsext.NewCacheOnReadFs(nil, fs, 0)}, r)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &SourceData{\n\t\tURL:  &url.URL{Scheme: \"file\", Path: \"/-\"},\n\t\tData: data,\n\t\tPWD:  &url.URL{Scheme: \"file\", Path: \"/path/to/pwd/\"},\n\t}, sourceData)\n\tfileData, err := fsext.ReadFile(fs, \"/-\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, data, fileData)\n}\n\nfunc TestReadSourceRelative(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tdata := []byte(`test contents`)\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/path/to/somewhere/script.js\", data, 0o644))\n\tsourceData, err := ReadSource(logger, \"../somewhere/script.js\", \"/path/to/pwd\", map[string]fsext.Fs{\"file\": fs}, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &SourceData{\n\t\tURL:  &url.URL{Scheme: \"file\", Path: \"/path/to/somewhere/script.js\"},\n\t\tData: data,\n\t}, sourceData)\n}\n\nfunc TestReadSourceAbsolute(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tdata := []byte(`test contents`)\n\tr := bytes.NewReader(data)\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/a/b\", data, 0o644))\n\trequire.NoError(t, fsext.WriteFile(fs, \"/c/a/b\", []byte(\"wrong\"), 0o644))\n\tsourceData, err := ReadSource(logger, \"/a/b\", \"/c\", map[string]fsext.Fs{\"file\": fs}, r)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &SourceData{\n\t\tURL:  &url.URL{Scheme: \"file\", Path: \"/a/b\"},\n\t\tData: data,\n\t}, sourceData)\n}\n\nfunc TestReadSourceHttps(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tdata := []byte(`test contents`)\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/github.com/something\", data, 0o644))\n\tsourceData, err := ReadSource(logger, \"https://github.com/something\", \"/c\",\n\t\tmap[string]fsext.Fs{\"file\": fsext.NewMemMapFs(), \"https\": fs}, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, &SourceData{\n\t\tURL:  &url.URL{Scheme: \"https\", Host: \"github.com\", Path: \"/something\"},\n\t\tData: data,\n\t}, sourceData)\n}\n\nfunc TestReadSourceHttpError(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tdata := []byte(`test contents`)\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/github.com/something\", data, 0o644))\n\t_, err := ReadSource(logger, \"http://github.com/something\", \"/c\",\n\t\tmap[string]fsext.Fs{\"file\": fsext.NewMemMapFs(), \"https\": fs}, nil)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), `only supported schemes for imports are file and https`)\n}\n\nfunc TestReadSourceMissingFileError(t *testing.T) {\n\tt.Parallel()\n\tlogger := logrus.New()\n\tlogger.SetOutput(testutils.NewTestOutput(t))\n\tfs := fsext.NewMemMapFs()\n\t_, err := ReadSource(logger, \"some file with spaces.js\", \"/c\",\n\t\tmap[string]fsext.Fs{\"file\": fsext.NewMemMapFs(), \"https\": fs}, nil)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), `The moduleSpecifier \"some file with spaces.js\" couldn't be found on local disk.`)\n}\n"
  },
  {
    "path": "internal/log/file.go",
    "content": "package log\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"syscall\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/internal/lib/strvals\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// fileHookBufferSize is a default size for the fileHook's loglines channel.\nconst fileHookBufferSize = 100\n\n// fileHook is a hook to handle writing to local files.\ntype fileHook struct {\n\tfs             fsext.Fs\n\tfallbackLogger logrus.FieldLogger\n\tloglines       chan []byte\n\tpath           string\n\tw              io.WriteCloser\n\tbw             *bufio.Writer\n\tlevels         []logrus.Level\n}\n\n// FileHookFromConfigLine returns new fileHook hook.\nfunc FileHookFromConfigLine(\n\tfs fsext.Fs, getCwd func() (string, error),\n\tfallbackLogger logrus.FieldLogger, line string,\n) (AsyncHook, error) {\n\thook := &fileHook{\n\t\tfs:             fs,\n\t\tfallbackLogger: fallbackLogger,\n\t\tlevels:         logrus.AllLevels,\n\t\tloglines:       make(chan []byte, fileHookBufferSize),\n\t}\n\n\tlogOutput, _, _ := strings.Cut(line, \"=\")\n\tif logOutput != \"file\" {\n\t\treturn nil, fmt.Errorf(\"logfile configuration should be in the form `file=path-to-local-file` but is `%s`\", line)\n\t}\n\tif err := hook.parseArgs(line); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := hook.openFile(getCwd); err != nil {\n\t\treturn nil, err\n\t}\n\treturn hook, nil\n}\n\nfunc (h *fileHook) parseArgs(line string) error {\n\ttokens, err := strvals.Parse(line)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error while parsing logfile configuration %w\", err)\n\t}\n\n\tfor _, token := range tokens {\n\t\tswitch token.Key {\n\t\tcase \"file\":\n\t\t\tif token.Value == \"\" {\n\t\t\t\treturn fmt.Errorf(\"filepath must not be empty\")\n\t\t\t}\n\t\t\th.path = token.Value\n\t\tcase \"level\":\n\t\t\th.levels, err = parseLevels(token.Value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown logfile config key %s\", token.Key)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// openFile opens logfile and initializes writers.\nfunc (h *fileHook) openFile(getCwd func() (string, error)) error {\n\tpath := h.path\n\tif !filepath.IsAbs(path) {\n\t\tcwd, err := getCwd()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"'%s' is a relative path but could not determine CWD: %w\", path, err)\n\t\t}\n\t\tpath = filepath.Join(cwd, path)\n\t}\n\n\tif _, err := h.fs.Stat(filepath.Dir(path)); errors.Is(err, fs.ErrNotExist) {\n\t\treturn fmt.Errorf(\"provided directory '%s' does not exist\", filepath.Dir(path))\n\t}\n\n\tfile, err := h.fs.OpenFile(path, syscall.O_WRONLY|syscall.O_APPEND|syscall.O_CREAT, 0o600)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open logfile %s: %w\", path, err)\n\t}\n\n\th.w = file\n\th.bw = bufio.NewWriter(file)\n\n\treturn nil\n}\n\n// Listen waits for log lines to flush.\nfunc (h *fileHook) Listen(ctx context.Context) {\n\tfor {\n\t\tselect {\n\t\tcase entry := <-h.loglines:\n\t\t\tif _, err := h.bw.Write(entry); err != nil {\n\t\t\t\th.fallbackLogger.Errorf(\"failed to write a log message to a logfile: %w\", err)\n\t\t\t}\n\t\tcase <-ctx.Done():\n\t\t\t// This context is cancelled after the command finishes executing, so it is guaranteed that no more lines\n\t\t\t// will be sent to the channel. However, as it is buffered, it may still have items on it, so we drain any\n\t\t\t// pending log lines that may be there.\n\t\tdrainloop:\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase entry := <-h.loglines:\n\t\t\t\t\tif _, err := h.bw.Write(entry); err != nil {\n\t\t\t\t\t\th.fallbackLogger.Errorf(\"failed to write a log message to a logfile: %w\", err)\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tbreak drainloop\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif err := h.bw.Flush(); err != nil {\n\t\t\t\th.fallbackLogger.Errorf(\"failed to flush buffer: %w\", err)\n\t\t\t}\n\n\t\t\tif err := h.w.Close(); err != nil {\n\t\t\t\th.fallbackLogger.Errorf(\"failed to close logfile: %w\", err)\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Fire writes the log file to defined path.\nfunc (h *fileHook) Fire(entry *logrus.Entry) error {\n\tmessage, err := entry.Bytes()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get a log entry bytes: %w\", err)\n\t}\n\n\th.loglines <- message\n\treturn nil\n}\n\n// Levels returns configured log levels.\nfunc (h *fileHook) Levels() []logrus.Level {\n\treturn h.levels\n}\n"
  },
  {
    "path": "internal/log/file_test.go",
    "content": "package log\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\ntype nopCloser struct {\n\tio.Writer\n\tclosed chan struct{}\n}\n\nfunc (nc *nopCloser) Close() error {\n\tnc.closed <- struct{}{}\n\treturn nil\n}\n\nfunc TestFileHookFromConfigLine(t *testing.T) {\n\tt.Parallel()\n\n\ttests := [...]struct {\n\t\tline       string\n\t\terr        bool\n\t\terrMessage string\n\t\tres        fileHook\n\t}{\n\t\t{\n\t\t\tline: \"file\",\n\t\t\terr:  true,\n\t\t\tres: fileHook{\n\t\t\t\tlevels: logrus.AllLevels,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tline: \"file=/k6.log,level=info\",\n\t\t\terr:  false,\n\t\t\tres: fileHook{\n\t\t\t\tpath:   \"/k6.log\",\n\t\t\t\tlevels: logrus.AllLevels[:5],\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tline: \"file=/a/c/\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline:       \"file=,level=info\",\n\t\t\terr:        true,\n\t\t\terrMessage: \"filepath must not be empty\",\n\t\t},\n\t\t{\n\t\t\tline: \"file=/tmp/k6.log,level=tea\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline: \"file=/tmp/k6.log,unknown\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline: \"file=/tmp/k6.log,level=\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline: \"file=/tmp/k6.log,level=,\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline:       \"file=/tmp/k6.log,unknown=something\",\n\t\t\terr:        true,\n\t\t\terrMessage: \"unknown logfile config key unknown\",\n\t\t},\n\t\t{\n\t\t\tline:       \"unknown=something\",\n\t\t\terr:        true,\n\t\t\terrMessage: \"logfile configuration should be in the form `file=path-to-local-file` but is `unknown=something`\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.line, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgetCwd := func() (string, error) {\n\t\t\t\treturn \"/\", nil\n\t\t\t}\n\n\t\t\tres, err := FileHookFromConfigLine(\n\t\t\t\tfsext.NewMemMapFs(), getCwd, logrus.New(), test.line)\n\n\t\t\tif test.err {\n\t\t\t\trequire.Error(t, err)\n\n\t\t\t\tif test.errMessage != \"\" {\n\t\t\t\t\trequire.Equal(t, test.errMessage, err.Error())\n\t\t\t\t}\n\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.NotNil(t, res.(*fileHook).w)\n\t\t})\n\t}\n}\n\nfunc TestFileHookFire(t *testing.T) {\n\tt.Parallel()\n\n\tvar buffer bytes.Buffer\n\tnc := &nopCloser{\n\t\tWriter: &buffer,\n\t\tclosed: make(chan struct{}),\n\t}\n\n\thook := &fileHook{\n\t\tloglines: make(chan []byte),\n\t\tw:        nc,\n\t\tbw:       bufio.NewWriter(nc),\n\t\tlevels:   logrus.AllLevels,\n\t}\n\n\tctx, cancel := context.WithCancel(context.Background())\n\n\tgo hook.Listen(ctx)\n\n\tlogger := logrus.New()\n\tlogger.AddHook(hook)\n\tlogger.SetOutput(io.Discard)\n\n\tlogger.Info(\"example log line\")\n\n\ttime.Sleep(10 * time.Millisecond)\n\n\tcancel()\n\t<-nc.closed\n\n\tassert.Contains(t, buffer.String(), \"example log line\")\n}\n"
  },
  {
    "path": "internal/log/levels.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\nfunc parseLevels(level string) ([]logrus.Level, error) {\n\tlvl, err := logrus.ParseLevel(level)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unknown log level %s\", level) // specifically use a custom error\n\t}\n\tindex := sort.Search(len(logrus.AllLevels), func(i int) bool {\n\t\treturn logrus.AllLevels[i] > lvl\n\t})\n\n\treturn logrus.AllLevels[:index], nil\n}\n"
  },
  {
    "path": "internal/log/levels_test.go",
    "content": "package log\n\nimport (\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test_getLevels(t *testing.T) {\n\tt.Parallel()\n\n\ttests := [...]struct {\n\t\tlevel  string\n\t\terr    bool\n\t\tlevels []logrus.Level\n\t}{\n\t\t{\n\t\t\tlevel: \"info\",\n\t\t\terr:   false,\n\t\t\tlevels: []logrus.Level{\n\t\t\t\tlogrus.PanicLevel,\n\t\t\t\tlogrus.FatalLevel,\n\t\t\t\tlogrus.ErrorLevel,\n\t\t\t\tlogrus.WarnLevel,\n\t\t\t\tlogrus.InfoLevel,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tlevel: \"error\",\n\t\t\terr:   false,\n\t\t\tlevels: []logrus.Level{\n\t\t\t\tlogrus.PanicLevel,\n\t\t\t\tlogrus.FatalLevel,\n\t\t\t\tlogrus.ErrorLevel,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tlevel:  \"tea\",\n\t\t\terr:    true,\n\t\t\tlevels: nil,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.level, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tlevels, err := parseLevels(test.level)\n\n\t\t\tif test.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.levels, levels)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/log/log.go",
    "content": "// Package log implements various logrus hooks.\npackage log\n\nimport (\n\t\"context\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// AsyncHook extends the logrus.Hook functionality\n// handling logging in a not blocking way.\ntype AsyncHook interface {\n\tlogrus.Hook\n\n\t// Listen waits and handles logrus.Hook.Fire events.\n\t// It stops when the context is canceled.\n\tListen(ctx context.Context)\n}\n"
  },
  {
    "path": "internal/log/loki.go",
    "content": "package log\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/internal/lib/strvals\"\n)\n\n// lokiHook is a Logrus hook for flushing to Loki.\ntype lokiHook struct {\n\tfallbackLogger logrus.FieldLogger\n\taddr           string\n\theaders        [][2]string\n\tlabels         [][2]string\n\tch             chan *logrus.Entry\n\tlimit          int\n\tmsgMaxSize     int\n\tlevels         []logrus.Level\n\tallowedLabels  []string\n\tpushPeriod     time.Duration\n\tclient         *http.Client\n\tprofile        bool\n\tdroppedLabels  map[string]string\n\tdroppedMsg     string\n}\n\nfunc getDefaultLoki() *lokiHook {\n\treturn &lokiHook{\n\t\taddr:          \"http://127.0.0.1:3100/loki/api/v1/push\",\n\t\tlimit:         100,\n\t\tlevels:        logrus.AllLevels,\n\t\tpushPeriod:    time.Second * 1,\n\t\tmsgMaxSize:    1024 * 1024, // 1mb\n\t\tch:            make(chan *logrus.Entry, 1000),\n\t\tallowedLabels: nil,\n\t\tdroppedMsg:    \"k6 dropped %d log messages because they were above the limit of %d messages / %s\",\n\t}\n}\n\n// LokiFromConfigLine returns a new logrus.Hook\n// that pushes logrus.Entrys to loki and is configured\n// through the provided line.\nfunc LokiFromConfigLine(fallbackLogger logrus.FieldLogger, line string) (AsyncHook, error) {\n\th := getDefaultLoki()\n\th.fallbackLogger = fallbackLogger\n\n\tif line != \"loki\" {\n\t\tlogOutput, _, _ := strings.Cut(line, \"=\")\n\t\tif logOutput != \"loki\" {\n\t\t\treturn nil, fmt.Errorf(\"loki configuration should be in the form `loki=url-to-push` but is `%s`\", line)\n\t\t}\n\n\t\terr := h.parseArgs(line)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\th.droppedLabels = make(map[string]string, 2+len(h.labels))\n\th.droppedLabels[\"level\"] = logrus.WarnLevel.String()\n\tfor _, params := range h.labels {\n\t\th.droppedLabels[params[0]] = params[1]\n\t}\n\n\th.droppedMsg = h.filterLabels(h.droppedLabels, h.droppedMsg)\n\th.client = &http.Client{Timeout: h.pushPeriod}\n\treturn h, nil\n}\n\nfunc (h *lokiHook) parseArgs(line string) error {\n\ttokens, err := strvals.Parse(line)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error while parsing loki configuration %w\", err)\n\t}\n\n\tfor _, token := range tokens {\n\t\tkey := token.Key\n\t\tvalue := token.Value\n\n\t\tvar err error\n\t\tswitch key {\n\t\tcase \"loki\":\n\t\t\th.addr = value\n\t\tcase \"pushPeriod\":\n\t\t\th.pushPeriod, err = time.ParseDuration(value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"couldn't parse the loki pushPeriod %w\", err)\n\t\t\t}\n\t\tcase \"profile\":\n\t\t\th.profile = true\n\t\tcase \"limit\":\n\t\t\th.limit, err = strconv.Atoi(value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"couldn't parse the loki limit as a number %w\", err)\n\t\t\t}\n\t\t\tif h.limit < 1 {\n\t\t\t\treturn fmt.Errorf(\"loki limit needs to be a positive number, is %d\", h.limit)\n\t\t\t}\n\t\tcase \"msgMaxSize\":\n\t\t\th.msgMaxSize, err = strconv.Atoi(value)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"couldn't parse the loki msgMaxSize as a number %w\", err)\n\t\t\t}\n\t\t\tif h.msgMaxSize < 1 {\n\t\t\t\treturn fmt.Errorf(\"loki msgMaxSize needs to be a positive number, is %d\", h.msgMaxSize)\n\t\t\t}\n\t\tcase \"level\":\n\t\t\th.levels, err = parseLevels(value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase \"allowedLabels\":\n\t\t\th.allowedLabels = strings.Split(value, \",\")\n\t\tdefault:\n\t\t\tif after, ok := strings.CutPrefix(key, \"label.\"); ok {\n\t\t\t\tlabelKey := after\n\t\t\t\th.labels = append(h.labels, [2]string{labelKey, value})\n\n\t\t\t\tcontinue\n\t\t\t} else if after, ok := strings.CutPrefix(key, \"header.\"); ok {\n\t\t\t\theaderKey := after\n\t\t\t\th.headers = append(h.headers, [2]string{headerKey, value})\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn fmt.Errorf(\"unknown loki config key %s\", key)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Listen fills one of two equally sized slices\n// with entries and then push it while filling the other one.\n//\n// TODO benchmark this\n//\n//nolint:funlen\nfunc (h *lokiHook) Listen(ctx context.Context) {\n\tvar (\n\t\tmsgs       = make([]tmpMsg, h.limit)\n\t\tmsgsToPush = make([]tmpMsg, h.limit)\n\t\tdropped    int\n\t\tcount      int\n\t\tticker     = time.NewTicker(h.pushPeriod)\n\t\tpushCh     = make(chan chan int64)\n\t)\n\n\tpushDone := make(chan struct{})\n\tdefer func() { <-pushDone }()\n\tdefer ticker.Stop()\n\tdefer close(pushCh)\n\n\tgo func() { //nolint:contextcheck\n\t\tdefer close(pushDone)\n\t\toldLogs := make([]tmpMsg, 0, h.limit*2)\n\t\tfor ch := range pushCh {\n\t\t\tmsgsToPush, msgs = msgs, msgsToPush\n\t\t\toldCount, oldDropped := count, dropped\n\t\t\tcount, dropped = 0, 0\n\t\t\tcutOff := <-ch\n\t\t\tclose(ch) // signal that more buffering can continue\n\n\t\t\toldLogs = append(oldLogs, msgsToPush[:oldCount]...)\n\n\t\t\tt := time.Now()\n\t\t\tcutOffIndex := sortAndSplitMsgs(oldLogs, cutOff)\n\t\t\tif cutOffIndex == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tt1 := time.Since(t)\n\n\t\t\tpushMsg := h.createPushMessage(oldLogs, cutOffIndex, oldDropped)\n\t\t\tif cutOffIndex > len(oldLogs) {\n\t\t\t\toldLogs = oldLogs[:0]\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\toldLogs = oldLogs[:copy(oldLogs, oldLogs[cutOffIndex:])]\n\t\t\tt2 := time.Since(t) - t1\n\n\t\t\tvar b bytes.Buffer\n\t\t\t_, err := pushMsg.WriteTo(&b)\n\t\t\tif err != nil {\n\t\t\t\th.fallbackLogger.WithError(err).Error(\"Error while marshaling logs for loki\")\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tsize := b.Len()\n\t\t\tt3 := time.Since(t) - t2 - t1\n\n\t\t\terr = h.push(b)\n\t\t\tif err != nil {\n\t\t\t\th.fallbackLogger.WithError(err).Error(\"Error while sending logs to loki\")\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tt4 := time.Since(t) - t3 - t2 - t1\n\n\t\t\tif h.profile {\n\t\t\t\th.fallbackLogger.Infof(\n\t\t\t\t\t\"sorting=%s, adding=%s marshalling=%s sending=%s count=%d final_size=%d\\n\",\n\t\t\t\t\tt1, t2, t3, t4, cutOffIndex, size)\n\t\t\t}\n\t\t}\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase entry := <-h.ch:\n\t\t\tif count == h.limit {\n\t\t\t\tdropped++\n\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Arguably we can directly generate the final marshalled version of the labels right here\n\t\t\t// through sorting the entry.Data, removing additionalparams from it and then dumping it\n\t\t\t// as the final marshal and appending level and h.labels after it.\n\t\t\t// If we reuse some kind of big enough `[]byte` buffer we can also possibly skip on some\n\t\t\t// of allocation. Combined with the cutoff part and directly pushing in the final data\n\t\t\t// type this can be really a lot faster and to use a lot less memory\n\t\t\tlabels := make(map[string]string, len(entry.Data)+1)\n\t\t\tfor k, v := range entry.Data {\n\t\t\t\tlabels[k] = fmt.Sprint(v) // TODO optimize ?\n\t\t\t}\n\t\t\tfor _, params := range h.labels {\n\t\t\t\tlabels[params[0]] = params[1]\n\t\t\t}\n\t\t\tlabels[\"level\"] = entry.Level.String()\n\t\t\tmsg := h.filterLabels(labels, entry.Message) // TODO we can do this while constructing\n\t\t\t// have the cutoff here ?\n\t\t\t// if we cutoff here we can cut somewhat on the backbuffers and optimize the inserting\n\t\t\t// in/creating of the final Streams that we push\n\t\t\tmsgs[count] = tmpMsg{\n\t\t\t\tlabels: labels,\n\t\t\t\tmsg:    msg,\n\t\t\t\tt:      entry.Time.UnixNano(),\n\t\t\t}\n\t\t\tcount++\n\t\tcase t := <-ticker.C:\n\t\t\tch := make(chan int64)\n\t\t\tpushCh <- ch\n\t\t\tch <- t.Add(-(h.pushPeriod / 2)).UnixNano()\n\t\t\t<-ch\n\t\tcase <-ctx.Done():\n\t\t\tch := make(chan int64)\n\t\t\tpushCh <- ch\n\t\t\tch <- time.Now().Add(time.Second).UnixNano()\n\t\t\t<-ch\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (h *lokiHook) filterLabels(labels map[string]string, msg string) string {\n\tif h.allowedLabels == nil {\n\t\treturn msg\n\t}\n\t// TODO both can be reused as under load this will just generate a lot of *probably* fairly\n\t// similar objects.\n\tvar b strings.Builder\n\tkeys := make([]string, 0, len(labels))\n\tfor key := range labels {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\tb.WriteString(msg)\nouter:\n\tfor _, key := range keys {\n\t\tfor _, label := range h.allowedLabels {\n\t\t\tif label == key {\n\t\t\t\tcontinue outer\n\t\t\t}\n\t\t}\n\t\tb.WriteRune(' ')\n\t\tb.WriteString(key)\n\t\tb.WriteRune('=')\n\t\tb.WriteString(labels[key])\n\t\tdelete(labels, key)\n\t}\n\n\treturn b.String()\n}\n\nfunc sortAndSplitMsgs(msgs []tmpMsg, cutOff int64) int {\n\tif len(msgs) == 0 {\n\t\treturn 0\n\t}\n\n\t// TODO using time.Before was giving a lot of out of order, but even now, there are some, if the\n\t// limit is big enough ...\n\tsort.Slice(msgs, func(i, j int) bool {\n\t\treturn msgs[i].t < msgs[j].t\n\t})\n\n\tcutOffIndex := sort.Search(len(msgs), func(i int) bool {\n\t\treturn msgs[i].t >= cutOff\n\t})\n\n\treturn cutOffIndex\n}\n\nfunc (h *lokiHook) createPushMessage(msgs []tmpMsg, cutOffIndex, dropped int) *lokiPushMessage {\n\tpushMsg := new(lokiPushMessage)\n\tpushMsg.maxSize = h.msgMaxSize\n\tfor _, msg := range msgs[:cutOffIndex] {\n\t\tpushMsg.add(msg)\n\t}\n\tif dropped != 0 {\n\t\tmsg := tmpMsg{\n\t\t\tlabels: h.droppedLabels,\n\t\t\tmsg:    fmt.Sprintf(h.droppedMsg, dropped, h.limit, h.pushPeriod),\n\t\t\tt:      msgs[cutOffIndex-1].t,\n\t\t}\n\t\tpushMsg.add(msg)\n\t}\n\n\treturn pushMsg\n}\n\nfunc (h *lokiHook) push(b bytes.Buffer) error {\n\tbody := b.Bytes()\n\n\treq, err := http.NewRequestWithContext(context.Background(), http.MethodPost, h.addr, &b)\n\tif err != nil {\n\t\treturn err\n\t}\n\treq.GetBody = func() (io.ReadCloser, error) {\n\t\treturn io.NopCloser(bytes.NewBuffer(body)), nil\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tfor _, header := range h.headers {\n\t\treq.Header.Add(header[0], header[1])\n\t}\n\n\tres, err := h.client.Do(req) //nolint:gosec\n\n\tif res != nil {\n\t\tif res.StatusCode >= 400 {\n\t\t\tr, _ := io.ReadAll(res.Body) // maybe limit it to something like the first 1000 characters?\n\n\t\t\treturn fmt.Errorf(\"got %d from loki: %s\", res.StatusCode, string(r))\n\t\t}\n\t\t_, _ = io.Copy(io.Discard, res.Body)\n\t\t_ = res.Body.Close()\n\t}\n\n\treturn err\n}\n\nfunc mapEqual(a, b map[string]string) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor k, v := range a {\n\t\tif v2, ok := b[k]; !ok || v2 != v {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (pushMsg *lokiPushMessage) add(entry tmpMsg) {\n\tvar foundStrm *stream\n\tfor _, strm := range pushMsg.Streams {\n\t\tif mapEqual(strm.Stream, entry.labels) {\n\t\t\tfoundStrm = strm\n\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif foundStrm == nil {\n\t\tfoundStrm = &stream{Stream: entry.labels}\n\t\tpushMsg.Streams = append(pushMsg.Streams, foundStrm)\n\t}\n\n\tfoundStrm.Values = append(foundStrm.Values, logEntry{t: entry.t, msg: entry.msg})\n}\n\n// this is temporary message format used to not keep the logrus.Entry around too long and to make\n// sorting easier\ntype tmpMsg struct {\n\tlabels map[string]string\n\tt      int64\n\tmsg    string\n}\n\n// Fire implements logrus.Hook.\nfunc (h *lokiHook) Fire(entry *logrus.Entry) error {\n\th.ch <- entry\n\n\treturn nil\n}\n\n// Levels implements logrus.Hook.\nfunc (h *lokiHook) Levels() []logrus.Level {\n\treturn h.levels\n}\n\n/*\n\t{\n\t  \"streams\": [\n\t    {\n\t      \"stream\": {\n\t        \"label1\": \"value1\"\n\t        \"label2\": \"value2\"\n\t      },\n\t      \"values\": [ // the nanoseconds need to be in order\n\t          [ \"<unix epoch in nanoseconds>\", \"<log line>\" ],\n\t          [ \"<unix epoch in nanoseconds>\", \"<log line>\" ]\n\t      ]\n\t    }\n\t  ]\n\t}\n*/\ntype lokiPushMessage struct {\n\tStreams []*stream `json:\"streams\"`\n\tmaxSize int\n}\n\nfunc (pushMsg *lokiPushMessage) WriteTo(w io.Writer) (n int64, err error) {\n\tvar k int\n\twrite := func(b []byte) {\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tk, err = w.Write(b)\n\t\tn += int64(k)\n\t}\n\t// 10+ 9 for the amount of nanoseconds between 2001 and 2286 also it overflows in the year 2262 ;)\n\tvar nanoseconds [19]byte\n\twrite([]byte(`{\"streams\":[`))\n\tvar b []byte\n\tfor i, str := range pushMsg.Streams {\n\t\tif i != 0 {\n\t\t\twrite([]byte(`,`))\n\t\t}\n\t\twrite([]byte(`{\"stream\":{`))\n\t\tvar f bool\n\t\tfor k, v := range str.Stream {\n\t\t\tif f {\n\t\t\t\twrite([]byte(`,`))\n\t\t\t}\n\t\t\tf = true\n\t\t\twrite([]byte(`\"`))\n\t\t\twrite([]byte(k))\n\t\t\twrite([]byte(`\":`))\n\t\t\tb, err = json.Marshal(v)\n\t\t\tif err != nil {\n\t\t\t\treturn n, err\n\t\t\t}\n\t\t\twrite(b)\n\t\t}\n\t\twrite([]byte(`},\"values\":[`))\n\t\tfor j, v := range str.Values {\n\t\t\tif j != 0 {\n\t\t\t\twrite([]byte(`,`))\n\t\t\t}\n\t\t\twrite([]byte(`[\"`))\n\t\t\tstrconv.AppendInt(nanoseconds[:0], v.t, 10)\n\t\t\twrite(nanoseconds[:])\n\t\t\twrite([]byte(`\",`))\n\t\t\tmsgRunes := []rune(v.msg)\n\t\t\tif len(msgRunes) > pushMsg.maxSize {\n\t\t\t\tdifference := int64(len(msgRunes) - pushMsg.maxSize)\n\t\t\t\tomitMsg := append(strconv.AppendInt([]byte(\"... omitting \"), difference, 10), \" characters ...\"...)\n\t\t\t\tv.msg = strings.Join([]string{\n\t\t\t\t\tstring(msgRunes[:pushMsg.maxSize/2]),\n\t\t\t\t\tstring(msgRunes[len(msgRunes)-pushMsg.maxSize/2:]),\n\t\t\t\t}, string(omitMsg))\n\t\t\t}\n\n\t\t\tb, err = json.Marshal(v.msg)\n\t\t\tif err != nil {\n\t\t\t\treturn n, err\n\t\t\t}\n\t\t\twrite(b)\n\t\t\twrite([]byte(`]`))\n\t\t}\n\t\twrite([]byte(`]}`))\n\t}\n\n\twrite([]byte(`]}`))\n\n\treturn n, err\n}\n\ntype stream struct {\n\tStream map[string]string `json:\"stream\"`\n\tValues []logEntry        `json:\"values\"`\n}\n\ntype logEntry struct {\n\tt   int64  // nanoseconds\n\tmsg string // maybe intern those as they are likely to be the same for an interval\n}\n\n// rewrite this either with easyjson or with a custom marshalling\nfunc (l logEntry) MarshalJSON() ([]byte, error) {\n\t// 2 for '[]', 1 for ',', 4 for '\"' and 10 + 9 for the amount of nanoseconds between 2001 and\n\t// 2286 also it overflows in the year 2262 ;)\n\tb := make([]byte, 2, len(l.msg)+26)\n\tb[0] = '['\n\tb[1] = '\"'\n\tb = strconv.AppendInt(b, l.t, 10)\n\tb = append(b, '\"', ',', '\"')\n\tb = append(b, l.msg...)\n\tb = append(b, '\"', ']')\n\n\treturn b, nil\n}\n"
  },
  {
    "path": "internal/log/loki_test.go",
    "content": "package log\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSyslogFromConfigLine(t *testing.T) {\n\tt.Parallel()\n\ttests := [...]struct {\n\t\tline string\n\t\terr  bool\n\t\tres  lokiHook\n\t}{\n\t\t{\n\t\t\tline: \"loki\", // default settings\n\t\t\tres: lokiHook{\n\t\t\t\taddr:          \"http://127.0.0.1:3100/loki/api/v1/push\",\n\t\t\t\tlimit:         100,\n\t\t\t\tpushPeriod:    time.Second * 1,\n\t\t\t\tlevels:        logrus.AllLevels,\n\t\t\t\tmsgMaxSize:    1024 * 1024,\n\t\t\t\tdroppedLabels: map[string]string{\"level\": \"warning\"},\n\t\t\t\tdroppedMsg:    \"k6 dropped %d log messages because they were above the limit of %d messages / %s\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tline: \"loki=somewhere:1233,label.something=else,label.foo=bar,limit=32,level=info,allowedLabels=[something],pushPeriod=5m32s,msgMaxSize=1231,header.x-test=123,header.authorization=token foobar\",\n\t\t\tres: lokiHook{\n\t\t\t\taddr:          \"somewhere:1233\",\n\t\t\t\theaders:       [][2]string{{\"x-test\", \"123\"}, {\"authorization\", \"token foobar\"}},\n\t\t\t\tlimit:         32,\n\t\t\t\tpushPeriod:    time.Minute*5 + time.Second*32,\n\t\t\t\tlevels:        logrus.AllLevels[:5],\n\t\t\t\tlabels:        [][2]string{{\"something\", \"else\"}, {\"foo\", \"bar\"}},\n\t\t\t\tmsgMaxSize:    1231,\n\t\t\t\tallowedLabels: []string{\"something\"},\n\t\t\t\tdroppedLabels: map[string]string{\"something\": \"else\"},\n\t\t\t\tdroppedMsg:    \"k6 dropped %d log messages because they were above the limit of %d messages / %s foo=bar level=warning\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tline: \"lokino\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline: \"loki=something,limit=word\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline: \"loki=something,level=notlevel\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline: \"loki=something,unknownoption\",\n\t\t\terr:  true,\n\t\t},\n\t\t{\n\t\t\tline: \"loki=something,label=somethng\",\n\t\t\terr:  true,\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.line, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t// no parallel because this is way too fast and parallel will only slow it down\n\n\t\t\tres, err := LokiFromConfigLine(nil, test.line)\n\t\t\tif test.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\thook, ok := res.(*lokiHook)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.NoError(t, err)\n\n\t\t\ttest.res.client = hook.client\n\t\t\ttest.res.ch = hook.ch\n\t\t\trequire.Equal(t, &test.res, res)\n\t\t})\n\t}\n}\n\nfunc TestLogEntryMarshal(t *testing.T) {\n\tt.Parallel()\n\tentry := logEntry{\n\t\tt:   9223372036854775807, // the actual max\n\t\tmsg: \"something\",\n\t}\n\texpected := []byte(`[\"9223372036854775807\",\"something\"]`)\n\ts, err := json.Marshal(entry)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, expected, s)\n}\n\nfunc TestFilterLabels(t *testing.T) {\n\tt.Parallel()\n\tcases := []struct {\n\t\tallowedLabels  []string\n\t\tlabels         map[string]string\n\t\texpectedLabels map[string]string\n\t\tmsg            string\n\t\tresult         string\n\t}{\n\t\t{\n\t\t\tallowedLabels:  []string{\"a\", \"b\"},\n\t\t\tlabels:         map[string]string{\"a\": \"1\", \"b\": \"2\", \"d\": \"3\", \"c\": \"4\", \"e\": \"5\"},\n\t\t\texpectedLabels: map[string]string{\"a\": \"1\", \"b\": \"2\"},\n\t\t\tmsg:            \"some msg\",\n\t\t\tresult:         \"some msg c=4 d=3 e=5\",\n\t\t},\n\t\t{\n\t\t\tallowedLabels:  []string{\"a\", \"b\"},\n\t\t\tlabels:         map[string]string{\"d\": \"3\", \"c\": \"4\", \"e\": \"5\"},\n\t\t\texpectedLabels: map[string]string{},\n\t\t\tmsg:            \"some msg\",\n\t\t\tresult:         \"some msg c=4 d=3 e=5\",\n\t\t},\n\t\t{\n\t\t\tallowedLabels:  []string{\"a\", \"b\"},\n\t\t\tlabels:         map[string]string{\"a\": \"1\", \"d\": \"3\", \"c\": \"4\", \"e\": \"5\"},\n\t\t\texpectedLabels: map[string]string{\"a\": \"1\"},\n\t\t\tmsg:            \"some msg\",\n\t\t\tresult:         \"some msg c=4 d=3 e=5\",\n\t\t},\n\t}\n\n\tfor i, c := range cases {\n\t\tt.Run(fmt.Sprint(i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\th := &lokiHook{}\n\t\t\th.allowedLabels = c.allowedLabels\n\t\t\tresult := h.filterLabels(c.labels, c.msg)\n\t\t\tassert.Equal(t, c.result, result)\n\t\t\tassert.Equal(t, c.expectedLabels, c.labels)\n\t\t})\n\t}\n}\n\nfunc TestLokiFlushingOnStop(t *testing.T) {\n\tt.Parallel()\n\treceivedData := make(chan string, 1)\n\tsrv := httptest.NewServer(\n\t\thttp.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {\n\t\t\tb, err := io.ReadAll(req.Body)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\treceivedData <- string(b)\n\t\t\tclose(receivedData) // this is mostly as this should never be called twice, so panicking here in that case\n\t\t}),\n\t)\n\tconfigLine := fmt.Sprintf(\"loki=%s,pushPeriod=1h\", srv.URL)\n\th, err := LokiFromConfigLine(nil, configLine)\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\twg := new(sync.WaitGroup)\n\tnow := time.Now()\n\twg.Go(func() {\n\t\terr = h.Fire(&logrus.Entry{Time: now, Level: logrus.InfoLevel, Message: \"test message\"})\n\t\ttime.Sleep(time.Millisecond * 10)\n\t\tcancel()\n\t})\n\th.Listen(ctx)\n\twg.Wait()\n\tselect {\n\tcase data := <-receivedData:\n\t\trequire.JSONEq(t,\n\t\t\tfmt.Sprintf(\n\t\t\t\t`{\"streams\":[{\"stream\":{\"level\":\"info\"},\"values\":[[\"%d\",\"test message\"]]}]}`, now.UnixNano()),\n\t\t\tdata)\n\tdefault:\n\t\tt.Fatal(\"No logs were received from loki before hook has finished\")\n\t}\n}\n\nfunc TestLokiHeaders(t *testing.T) {\n\tt.Parallel()\n\treceivedHeaders := make(chan http.Header, 1)\n\tsrv := httptest.NewServer(\n\t\thttp.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) {\n\t\t\treceivedHeaders <- req.Header\n\t\t\tclose(receivedHeaders) // see comment in TestLokiFlushingOnStop\n\t\t}),\n\t)\n\tconfigLine := fmt.Sprintf(\"loki=%s,pushPeriod=1h,header.X-Foo=bar,header.Test=hello world,header.X-Foo=baz\", srv.URL)\n\th, err := LokiFromConfigLine(nil, configLine)\n\trequire.NoError(t, err)\n\n\tctx, cancel := context.WithCancel(context.Background())\n\twg := new(sync.WaitGroup)\n\tnow := time.Now()\n\twg.Go(func() {\n\t\terr = h.Fire(&logrus.Entry{Time: now, Level: logrus.InfoLevel, Message: \"test message\"})\n\t\ttime.Sleep(time.Millisecond * 10)\n\t\tcancel()\n\t})\n\th.Listen(ctx)\n\twg.Wait()\n\n\tselect {\n\tcase headers := <-receivedHeaders:\n\t\trequire.Equal(t, []string{\"bar\", \"baz\"}, headers[\"X-Foo\"])\n\t\trequire.Equal(t, []string{\"hello world\"}, headers[\"Test\"])\n\tdefault:\n\t\tt.Fatal(\"No logs were received from loki before hook has finished\")\n\t}\n}\n"
  },
  {
    "path": "internal/metrics/engine/engine.go",
    "content": "// Package engine contains the internal metrics engine responsible for\n// aggregating metrics during the test and evaluating thresholds against them.\npackage engine\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nconst thresholdsRate = 2 * time.Second\n\n// MetricsEngine is the internal metrics engine that k6 uses to keep track of\n// aggregated metric sample values. They are used to generate the end-of-test\n// summary and to evaluate the test thresholds.\ntype MetricsEngine struct {\n\tregistry *metrics.Registry\n\tlogger   logrus.FieldLogger\n\n\t// These can be both top-level metrics or sub-metrics\n\tmetricsWithThresholds   []*metrics.Metric\n\tbreachedThresholdsCount uint32\n\n\t// TODO: completely refactor:\n\t//   - make these private, add a method to export the raw data\n\t//   - do not use an unnecessary map for the observed metrics\n\t//   - have one lock per metric instead of a a global one, when\n\t//     the metrics are decoupled from their types\n\tMetricsLock     sync.Mutex\n\tObservedMetrics map[string]*metrics.Metric\n}\n\n// NewMetricsEngine creates a new metrics Engine with the given parameters.\nfunc NewMetricsEngine(registry *metrics.Registry, logger logrus.FieldLogger) (*MetricsEngine, error) {\n\tme := &MetricsEngine{\n\t\tregistry:        registry,\n\t\tlogger:          logger.WithField(\"component\", \"metrics-engine\"),\n\t\tObservedMetrics: make(map[string]*metrics.Metric),\n\t}\n\n\treturn me, nil\n}\n\n// CreateIngester returns a pseudo-Output that uses the given metric samples to\n// update the engine's inner state.\nfunc (me *MetricsEngine) CreateIngester() *OutputIngester {\n\treturn &OutputIngester{\n\t\tlogger:        me.logger.WithField(\"component\", \"metrics-engine-ingester\"),\n\t\tmetricsEngine: me,\n\t\tcardinality:   newCardinalityControl(),\n\t}\n}\n\nfunc (me *MetricsEngine) getThresholdMetricOrSubmetric(name string) (*metrics.Metric, error) {\n\tmetricDefinition, submetricDefinition, _ := strings.Cut(name, \"{\")\n\n\tmetric := me.registry.Get(metricDefinition)\n\tif metric == nil {\n\t\treturn nil, fmt.Errorf(\"metric '%s' does not exist in the script\", metricDefinition)\n\t}\n\n\tif len(submetricDefinition) == 0 { // no sub-metric\n\t\treturn metric, nil\n\t}\n\n\tif submetricDefinition[len(submetricDefinition)-1] != '}' {\n\t\treturn nil, fmt.Errorf(\"missing ending bracket, sub-metric format needs to be 'metric{key:value}'\")\n\t}\n\tsm, err := metric.AddSubmetric(submetricDefinition[:len(submetricDefinition)-1])\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif sm.Metric.Observed {\n\t\t// Do not repeat warnings for the same sub-metrics\n\t\treturn sm.Metric, nil\n\t}\n\n\tif _, ok := sm.Tags.Get(\"vu\"); ok {\n\t\tme.logger.Warnf(\n\t\t\t\"The high-cardinality 'vu' metric tag was made non-indexable in k6 v0.41.0, so thresholds\"+\n\t\t\t\t\" like '%s' that are based on it won't work correctly.\",\n\t\t\tname,\n\t\t)\n\t}\n\n\tif _, ok := sm.Tags.Get(\"iter\"); ok {\n\t\tme.logger.Warnf(\n\t\t\t\"The high-cardinality 'iter' metric tag was made non-indexable in k6 v0.41.0, so thresholds\"+\n\t\t\t\t\" like '%s' that are based on it won't work correctly.\",\n\t\t\tname,\n\t\t)\n\t}\n\n\treturn sm.Metric, nil\n}\n\nfunc (me *MetricsEngine) markObserved(metric *metrics.Metric) {\n\tif !metric.Observed {\n\t\tmetric.Observed = true\n\t\tme.ObservedMetrics[metric.Name] = metric\n\t}\n}\n\n// InitSubMetricsAndThresholds parses the thresholds from the test Options and\n// initializes both the thresholds themselves, as well as any submetrics that\n// were referenced in them.\nfunc (me *MetricsEngine) InitSubMetricsAndThresholds(options lib.Options, onlyLogErrors bool) error {\n\tfor metricName, thresholds := range options.Thresholds {\n\t\tmetric, err := me.getThresholdMetricOrSubmetric(metricName)\n\n\t\tif onlyLogErrors {\n\t\t\tif err != nil {\n\t\t\t\tme.logger.WithError(err).Warnf(\"Invalid metric '%s' in threshold definitions\", metricName)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid metric '%s' in threshold definitions: %w\", metricName, err)\n\t\t}\n\n\t\tmetric.Thresholds = thresholds\n\t\tme.metricsWithThresholds = append(me.metricsWithThresholds, metric)\n\n\t\t// Mark the metric (and the parent metric, if we're dealing with a\n\t\t// submetric) as observed, so they are shown in the end-of-test summary,\n\t\t// even if they don't have any metric samples during the test run\n\t\tme.markObserved(metric)\n\t\tif metric.Sub != nil {\n\t\t\tme.markObserved(metric.Sub.Parent)\n\t\t}\n\t}\n\n\t// TODO: refactor out of here when https://github.com/grafana/k6/issues/1321\n\t// lands and there is a better way to enable a metric with tag\n\tif options.SystemTags.Has(metrics.TagExpectedResponse) {\n\t\t_, err := me.getThresholdMetricOrSubmetric(\"http_req_duration{expected_response:true}\")\n\t\tif err != nil {\n\t\t\treturn err // shouldn't happen, but ¯\\_(ツ)_/¯\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// StartThresholdCalculations spins up a new goroutine to crunch thresholds and\n// returns a callback that will stop the goroutine and finalizes calculations.\nfunc (me *MetricsEngine) StartThresholdCalculations(\n\tingester *OutputIngester,\n\tabortRun func(error),\n\tgetCurrentTestRunDuration func() time.Duration,\n) (finalize func() (breached []string)) {\n\tif len(me.metricsWithThresholds) == 0 {\n\t\treturn nil // no thresholds were defined\n\t}\n\n\tstop := make(chan struct{})\n\tdone := make(chan struct{})\n\n\tgo func() {\n\t\tdefer close(done)\n\t\tticker := time.NewTicker(thresholdsRate)\n\t\tdefer ticker.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ticker.C:\n\t\t\t\tbreached, shouldAbort := me.evaluateThresholds(true, getCurrentTestRunDuration)\n\t\t\t\tif shouldAbort {\n\t\t\t\t\terr := fmt.Errorf(\n\t\t\t\t\t\t\"thresholds on metrics '%s' were crossed; at least one has abortOnFail enabled, stopping test prematurely\",\n\t\t\t\t\t\tstrings.Join(breached, \", \"),\n\t\t\t\t\t)\n\t\t\t\t\tme.logger.Debug(err.Error())\n\t\t\t\t\terr = errext.WithAbortReasonIfNone(\n\t\t\t\t\t\terrext.WithExitCodeIfNone(err, exitcodes.ThresholdsHaveFailed), errext.AbortedByThreshold,\n\t\t\t\t\t)\n\t\t\t\t\tabortRun(err)\n\t\t\t\t}\n\t\t\tcase <-stop:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn func() []string {\n\t\tif ingester != nil {\n\t\t\t// Stop the ingester so we don't get any more metrics\n\t\t\terr := ingester.Stop()\n\t\t\tif err != nil {\n\t\t\t\tme.logger.WithError(err).Warnf(\"There was a problem stopping the output ingester.\")\n\t\t\t}\n\t\t}\n\t\tclose(stop)\n\t\t<-done\n\n\t\tbreached, _ := me.evaluateThresholds(false, getCurrentTestRunDuration)\n\t\treturn breached\n\t}\n}\n\n// evaluateThresholds processes all of the thresholds.\n//\n// TODO: refactor, optimize\nfunc (me *MetricsEngine) evaluateThresholds(\n\tignoreEmptySinks bool,\n\tgetCurrentTestRunDuration func() time.Duration,\n) (breachedThresholds []string, shouldAbort bool) {\n\tme.MetricsLock.Lock()\n\tdefer me.MetricsLock.Unlock()\n\n\tt := getCurrentTestRunDuration()\n\n\tme.logger.Debugf(\"Running thresholds on %d metrics...\", len(me.metricsWithThresholds))\n\tfor _, m := range me.metricsWithThresholds {\n\t\t// If either the metric has no thresholds defined, or its sinks\n\t\t// are empty, let's ignore its thresholds execution at this point.\n\t\tif len(m.Thresholds.Thresholds) == 0 || (ignoreEmptySinks && m.Sink.IsEmpty()) {\n\t\t\tcontinue\n\t\t}\n\t\tm.Tainted = null.BoolFrom(false)\n\n\t\tsucc, err := m.Thresholds.Run(m.Sink, t)\n\t\tif err != nil {\n\t\t\tme.logger.WithField(\"metric_name\", m.Name).WithError(err).Error(\"Threshold error\")\n\t\t\tcontinue\n\t\t}\n\t\tif succ {\n\t\t\tcontinue // threshold passed\n\t\t}\n\t\tbreachedThresholds = append(breachedThresholds, m.Name)\n\t\tm.Tainted = null.BoolFrom(true)\n\t\tif m.Thresholds.Abort {\n\t\t\tshouldAbort = true\n\t\t}\n\t}\n\tif len(breachedThresholds) > 0 {\n\t\tsort.Strings(breachedThresholds)\n\t\tme.logger.Debugf(\"Thresholds on %d metrics crossed: %v\", len(breachedThresholds), breachedThresholds)\n\t}\n\tatomic.StoreUint32(&me.breachedThresholdsCount, uint32(len(breachedThresholds))) //nolint:gosec\n\treturn breachedThresholds, shouldAbort\n}\n\n// GetMetricsWithBreachedThresholdsCount returns the number of metrics for which\n// the thresholds were breached (failed) during the last processing phase. This\n// API is safe to use concurrently.\nfunc (me *MetricsEngine) GetMetricsWithBreachedThresholdsCount() uint32 {\n\treturn atomic.LoadUint32(&me.breachedThresholdsCount)\n}\n"
  },
  {
    "path": "internal/metrics/engine/engine_test.go",
    "content": "package engine\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestNewMetricsEngineWithThresholds(t *testing.T) {\n\tt.Parallel()\n\n\ttrs := &lib.TestRunState{\n\t\tTestPreInitState: &lib.TestPreInitState{\n\t\t\tLogger:   testutils.NewLogger(t),\n\t\t\tRegistry: metrics.NewRegistry(),\n\t\t},\n\t\tOptions: lib.Options{\n\t\t\tThresholds: map[string]metrics.Thresholds{\n\t\t\t\t\"metric1\": {Thresholds: []*metrics.Threshold{}},\n\t\t\t\t\"metric2\": {Thresholds: []*metrics.Threshold{}},\n\t\t\t},\n\t\t},\n\t}\n\t_, err := trs.Registry.NewMetric(\"metric1\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\t_, err = trs.Registry.NewMetric(\"metric2\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\tme, err := NewMetricsEngine(trs.Registry, trs.Logger)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, me)\n\n\trequire.NoError(t, me.InitSubMetricsAndThresholds(trs.Options, false))\n\n\tassert.Len(t, me.metricsWithThresholds, 2)\n}\n\nfunc TestMetricsEngineGetThresholdMetricOrSubmetricError(t *testing.T) {\n\tt.Parallel()\n\n\tcases := []struct {\n\t\tmetricDefinition string\n\t\texpErr           string\n\t}{\n\t\t{metricDefinition: \"metric1{test:a\", expErr: \"missing ending bracket\"},\n\t\t{metricDefinition: \"metric2\", expErr: \"'metric2' does not exist in the script\"},\n\t\t{metricDefinition: \"metric1{}\", expErr: \"submetric criteria for metric 'metric1' cannot be empty\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tme := newTestMetricsEngine(t)\n\t\t\t_, err := me.registry.NewMetric(\"metric1\", metrics.Counter)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = me.getThresholdMetricOrSubmetric(tc.metricDefinition)\n\t\t\tassert.ErrorContains(t, err, tc.expErr)\n\t\t})\n\t}\n}\n\nfunc TestNewMetricsEngineNoThresholds(t *testing.T) {\n\tt.Parallel()\n\n\tme := newTestMetricsEngine(t)\n\trequire.NotNil(t, me)\n\tassert.Empty(t, me.metricsWithThresholds)\n}\n\nfunc TestMetricsEngineCreateIngester(t *testing.T) {\n\tt.Parallel()\n\n\tme := MetricsEngine{\n\t\tlogger: testutils.NewLogger(t),\n\t}\n\tingester := me.CreateIngester()\n\tassert.NotNil(t, ingester)\n\trequire.NoError(t, ingester.Start())\n\trequire.NoError(t, ingester.Stop())\n}\n\nfunc TestMetricsEngineEvaluateThresholdNoAbort(t *testing.T) {\n\tt.Parallel()\n\n\tcases := []struct {\n\t\tthreshold   string\n\t\tabortOnFail bool\n\t\texpBreached []string\n\t}{\n\t\t{threshold: \"count>5\", expBreached: nil},\n\t\t{threshold: \"count<5\", expBreached: []string{\"m1\"}},\n\t\t{threshold: \"count<5\", expBreached: []string{\"m1\"}, abortOnFail: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.threshold, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tme := newTestMetricsEngine(t)\n\n\t\t\tm1, err := me.registry.NewMetric(\"m1\", metrics.Counter)\n\t\t\trequire.NoError(t, err)\n\t\t\tm2, err := me.registry.NewMetric(\"m2\", metrics.Counter)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tths := metrics.NewThresholds([]string{tc.threshold})\n\t\t\trequire.NoError(t, ths.Parse())\n\t\t\tm1.Thresholds = ths\n\t\t\tm1.Thresholds.Thresholds[0].AbortOnFail = tc.abortOnFail\n\n\t\t\tme.metricsWithThresholds = []*metrics.Metric{m1, m2}\n\t\t\tm1.Sink.Add(metrics.Sample{Value: 6.0})\n\n\t\t\tbreached, abort := me.evaluateThresholds(false, zeroTestRunDuration)\n\t\t\trequire.Equal(t, tc.abortOnFail, abort)\n\t\t\tassert.Equal(t, tc.expBreached, breached)\n\t\t})\n\t}\n}\n\nfunc TestMetricsEngineEvaluateIgnoreEmptySink(t *testing.T) {\n\tt.Parallel()\n\n\tme := newTestMetricsEngine(t)\n\n\tm1, err := me.registry.NewMetric(\"m1\", metrics.Counter)\n\trequire.NoError(t, err)\n\tm2, err := me.registry.NewMetric(\"m2\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\tths := metrics.NewThresholds([]string{\"count>5\"})\n\trequire.NoError(t, ths.Parse())\n\tm1.Thresholds = ths\n\tm1.Thresholds.Thresholds[0].AbortOnFail = true\n\n\tme.metricsWithThresholds = []*metrics.Metric{m1, m2}\n\n\tbreached, abort := me.evaluateThresholds(false, zeroTestRunDuration)\n\trequire.True(t, abort)\n\trequire.Equal(t, []string{\"m1\"}, breached)\n\n\tbreached, abort = me.evaluateThresholds(true, zeroTestRunDuration)\n\trequire.False(t, abort)\n\tassert.Empty(t, breached)\n}\n\nfunc newTestMetricsEngine(t *testing.T) *MetricsEngine {\n\tm, err := NewMetricsEngine(metrics.NewRegistry(), testutils.NewLogger(t))\n\trequire.NoError(t, err)\n\treturn m\n}\n\nfunc zeroTestRunDuration() time.Duration {\n\treturn 0\n}\n\n/*\n// FIXME: This test is too brittle,\n// move them as e2e tests and consider to simplify.\n//\nfunc TestSentReceivedMetrics(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\ttr := tb.Replacer.Replace\n\n\ttype testScript struct {\n\t\tCode                 string\n\t\tNumRequests          int64\n\t\tExpectedDataSent     int64\n\t\tExpectedDataReceived int64\n\t}\n\ttestScripts := []testScript{\n\t\t{tr(`import http from \"k6/http\";\n\t\t\texport default function() {\n\t\t\t\thttp.get(\"HTTPBIN_URL/bytes/15000\");\n\t\t\t}`), 1, 0, 15000},\n\t\t// NOTE: This needs to be improved, in the case of HTTPS IN URL\n\t\t// it's highly possible to meet the case when data received is out\n\t\t// of in the possible interval\n\t\t{tr(`import http from \"k6/http\";\n\t\t\texport default function() {\n\t\t\t\thttp.get(\"HTTPBIN_URL/bytes/5000\");\n\t\t\t\thttp.get(\"HTTPSBIN_URL/bytes/5000\");\n\t\t\t\thttp.batch([\"HTTPBIN_URL/bytes/10000\", \"HTTPBIN_URL/bytes/20000\", \"HTTPSBIN_URL/bytes/10000\"]);\n\t\t\t}`), 5, 0, 50000},\n\t\t{tr(`import http from \"k6/http\";\n\t\t\tlet data = \"0123456789\".repeat(100);\n\t\t\texport default function() {\n\t\t\t\thttp.post(\"HTTPBIN_URL/ip\", {\n\t\t\t\t\tfile: http.file(data, \"test.txt\")\n\t\t\t\t});\n\t\t\t}`), 1, 1000, 100},\n\t\t// NOTE(imiric): This needs to keep testing against /ws-echo-invalid because\n\t\t// this test is highly sensitive to metric data, and slightly differing\n\t\t// WS server implementations might introduce flakiness.\n\t\t// See https://github.com/k6io/k6/pull/1149\n\t\t{tr(`import ws from \"k6/ws\";\n\t\t\tlet data = \"0123456789\".repeat(100);\n\t\t\texport default function() {\n\t\t\t\tws.connect(\"WSBIN_URL/ws-echo-invalid\", null, function (socket) {\n\t\t\t\t\tsocket.on('open', function open() {\n\t\t\t\t\t\tsocket.send(data);\n\t\t\t\t\t});\n\t\t\t\t\tsocket.on('message', function (message) {\n\t\t\t\t\t\tsocket.close();\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}`), 2, 1000, 1000},\n\t}\n\n\ttype testCase struct{ Iterations, VUs int64 }\n\ttestCases := []testCase{\n\t\t{1, 1}, {2, 2}, {2, 1}, {5, 2}, {25, 2}, {50, 5},\n\t}\n\n\trunTest := func(t *testing.T, ts testScript, tc testCase, noConnReuse bool) (float64, float64) {\n\t\tr, err := js.New(\n\t\t\tgetTestPreInitState(t),\n\t\t\t&loader.SourceData{URL: &url.URL{Path: \"/script.js\"}, Data: []byte(ts.Code)},\n\t\t\tnil,\n\t\t)\n\t\trequire.NoError(t, err)\n\n\t\tmockOutput := mockoutput.New()\n\t\ttest := newTestEngine(t, nil, r, []output.Output{mockOutput}, lib.Options{\n\t\t\tIterations:            null.IntFrom(tc.Iterations),\n\t\t\tVUs:                   null.IntFrom(tc.VUs),\n\t\t\tHosts:                 types.NullHosts{Trie: tb.Dialer.Hosts, Valid: true},\n\t\t\tInsecureSkipTLSVerify: null.BoolFrom(true),\n\t\t\tNoVUConnectionReuse:   null.BoolFrom(noConnReuse),\n\t\t\tBatch:                 null.IntFrom(20),\n\t\t})\n\n\t\terrC := make(chan error)\n\t\tgo func() { errC <- test.run() }()\n\n\t\tselect {\n\t\tcase <-time.After(10 * time.Second):\n\t\t\tt.Fatal(\"Test timed out\")\n\t\tcase err := <-errC:\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t\ttest.wait()\n\n\t\tcheckData := func(name string, expected int64) float64 {\n\t\t\tdata := getMetricSum(mockOutput, name)\n\t\t\texpectedDataMin := float64(expected * tc.Iterations)\n\t\t\texpectedDataMax := float64((expected + ts.NumRequests*expectedHeaderMaxLength) * tc.Iterations)\n\n\t\t\tif data < expectedDataMin || data > expectedDataMax {\n\t\t\t\tt.Errorf(\n\t\t\t\t\t\"The %s sum should be in the interval [%f, %f] but was %f\",\n\t\t\t\t\tname, expectedDataMin, expectedDataMax, data,\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn data\n\t\t}\n\n\t\treturn checkData(metrics.DataSentName, ts.ExpectedDataSent),\n\t\t\tcheckData(metrics.DataReceivedName, ts.ExpectedDataReceived)\n\t}\n\n\tgetTestCase := func(t *testing.T, ts testScript, tc testCase) func(t *testing.T) {\n\t\treturn func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tnoReuseSent, noReuseReceived := runTest(t, ts, tc, true)\n\t\t\treuseSent, reuseReceived := runTest(t, ts, tc, false)\n\n\t\t\tif noReuseSent < reuseSent {\n\t\t\t\tt.Errorf(\"reuseSent=%f is greater than noReuseSent=%f\", reuseSent, noReuseSent)\n\t\t\t}\n\t\t\tif noReuseReceived < reuseReceived {\n\t\t\t\tt.Errorf(\"reuseReceived=%f is greater than noReuseReceived=%f\", reuseReceived, noReuseReceived)\n\t\t\t}\n\t\t}\n\t}\n\n\t// This Run will not return until the parallel subtests complete.\n\tt.Run(\"group\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfor tsNum, ts := range testScripts {\n\t\t\tfor tcNum, tc := range testCases {\n\t\t\t\tt.Run(\n\t\t\t\t\tfmt.Sprintf(\"SentReceivedMetrics_script[%d]_case[%d](%d,%d)\", tsNum, tcNum, tc.Iterations, tc.VUs),\n\t\t\t\t\tgetTestCase(t, ts, tc),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc TestEmittedMetricsWhenScalingDown(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tscript := []byte(tb.Replacer.Replace(`\n\t\timport http from \"k6/http\";\n\t\timport { sleep } from \"k6\";\n\n\t\texport let options = {\n\t\t\tsystemTags: [\"iter\", \"vu\", \"url\"],\n\t\t\tscenarios: {\n\t\t\t\twe_need_hard_stop_and_ramp_down: {\n\t\t\t\t\texecutor: \"ramping-vus\",\n\t\t\t\t\t// Start with 2 VUs for 4 seconds and then quickly scale down to 1 for the next 4s and then quit\n\t\t\t\t\tstartVUs: 2,\n\t\t\t\t\tstages: [\n\t\t\t\t\t\t{ duration: \"4s\", target: 2 },\n\t\t\t\t\t\t{ duration: \"0s\", target: 1 },\n\t\t\t\t\t\t{ duration: \"4s\", target: 1 },\n\t\t\t\t\t],\n\t\t\t\t\tgracefulStop: \"0s\",\n\t\t\t\t\tgracefulRampDown: \"0s\",\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\n\t\texport default function () {\n\t\t\tconsole.log(\"VU \" + __VU + \" starting iteration #\" + __ITER);\n\t\t\thttp.get(\"HTTPBIN_IP_URL/bytes/15000\");\n\t\t\tsleep(3.1);\n\t\t\thttp.get(\"HTTPBIN_IP_URL/bytes/15000\");\n\t\t\tconsole.log(\"VU \" + __VU + \" ending iteration #\" + __ITER);\n\t\t};\n\t`))\n\n\trunner, err := js.New(\n\t\tgetTestPreInitState(t),\n\t\t&loader.SourceData{URL: &url.URL{Path: \"/script.js\"}, Data: script},\n\t\tnil,\n\t)\n\trequire.NoError(t, err)\n\n\tmockOutput := mockoutput.New()\n\ttest := newTestEngine(t, nil, runner, []output.Output{mockOutput}, lib.Options{})\n\n\terrC := make(chan error)\n\tgo func() { errC <- test.run() }()\n\n\tselect {\n\tcase <-time.After(12 * time.Second):\n\t\tt.Fatal(\"Test timed out\")\n\tcase err := <-errC:\n\t\trequire.NoError(t, err)\n\t\ttest.wait()\n\t\trequire.False(t, test.engine.IsTainted())\n\t}\n\n\t// The 3.1 sleep in the default function would cause the first VU to complete 2 full iterations\n\t// and stat executing its third one, while the second VU will only fully complete 1 iteration\n\t// and will be canceled in the middle of its second one.\n\tassert.Equal(t, 3.0, getMetricSum(mockOutput, metrics.IterationsName))\n\n\t// That means that we expect to see 8 HTTP requests in total, 3*2=6 from the complete iterations\n\t// and one each from the two iterations that would be canceled in the middle of their execution\n\tassert.Equal(t, 8.0, getMetricSum(mockOutput, metrics.HTTPReqsName))\n\n\t// And we expect to see the data_received for all 8 of those requests. Previously, the data for\n\t// the 8th request (the 3rd one in the first VU before the test ends) was cut off by the engine\n\t// because it was emitted after the test officially ended. But that was mostly an unintended\n\t// consequence of the fact that those metrics were emitted only after an iteration ended when\n\t// it was interrupted.\n\tdataReceivedExpectedMin := 15000.0 * 8\n\tdataReceivedExpectedMax := (15000.0 + expectedHeaderMaxLength) * 8\n\tdataReceivedActual := getMetricSum(mockOutput, metrics.DataReceivedName)\n\tif dataReceivedActual < dataReceivedExpectedMin || dataReceivedActual > dataReceivedExpectedMax {\n\t\tt.Errorf(\n\t\t\t\"The data_received sum should be in the interval [%f, %f] but was %f\",\n\t\t\tdataReceivedExpectedMin, dataReceivedExpectedMax, dataReceivedActual,\n\t\t)\n\t}\n\n\t// Also, the interrupted iterations shouldn't affect the average iteration_duration in any way, only\n\t// complete iterations should be taken into account\n\tdurationCount := float64(getMetricCount(mockOutput, metrics.IterationDurationName))\n\tassert.Equal(t, 3.0, durationCount)\n\tdurationSum := getMetricSum(mockOutput, metrics.IterationDurationName)\n\tassert.InDelta(t, 3.35, durationSum/(1000*durationCount), 0.25)\n}\n\nfunc TestMetricsEmission(t *testing.T) {\n\tif !isWindows {\n\t\tt.Parallel()\n\t}\n\n\ttestCases := []struct {\n\t\tmethod             string\n\t\tminIterDuration    string\n\t\tdefaultBody        string\n\t\texpCount, expIters float64\n\t}{\n\t\t// Since emission of Iterations happens before the minIterationDuration\n\t\t// sleep is done, we expect to receive metrics for all executions of\n\t\t// the `default` function, despite of the lower overall duration setting.\n\t\t{\"minIterationDuration\", `\"300ms\"`, \"testCounter.add(1);\", 16.0, 16.0},\n\t\t// With the manual sleep method and no minIterationDuration, the last\n\t\t// `default` execution will be cutoff by the duration setting, so only\n\t\t// 3 sets of metrics are expected.\n\t\t{\"sleepBeforeCounterAdd\", \"null\", \"sleep(0.3); testCounter.add(1); \", 12.0, 12.0},\n\t\t// The counter should be sent, but the last iteration will be incomplete\n\t\t{\"sleepAfterCounterAdd\", \"null\", \"testCounter.add(1); sleep(0.3); \", 16.0, 12.0},\n\t}\n\n\tfor _, tc := range testCases {\n\t\ttc := tc\n\t\tt.Run(tc.method, func(t *testing.T) {\n\t\t\tif !isWindows {\n\t\t\t\tt.Parallel()\n\t\t\t}\n\t\t\trunner, err := js.New(\n\t\t\t\tgetTestPreInitState(t),\n\t\t\t\t&loader.SourceData{URL: &url.URL{Path: \"/script.js\"}, Data: []byte(fmt.Sprintf(`\n\t\t\t\timport { sleep } from \"k6\";\n\t\t\t\timport { Counter } from \"k6/metrics\";\n\n\t\t\t\tlet testCounter = new Counter(\"testcounter\");\n\n\t\t\t\texport let options = {\n\t\t\t\t\tscenarios: {\n\t\t\t\t\t\twe_need_hard_stop: {\n\t\t\t\t\t\t\texecutor: \"constant-vus\",\n\t\t\t\t\t\t\tvus: 4,\n\t\t\t\t\t\t\tduration: \"1s\",\n\t\t\t\t\t\t\tgracefulStop: \"0s\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tminIterationDuration: %s,\n\t\t\t\t};\n\n\t\t\t\texport default function() {\n\t\t\t\t\t%s\n\t\t\t\t}\n\t\t\t\t`, tc.minIterDuration, tc.defaultBody))},\n\t\t\t\tnil,\n\t\t\t)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tmockOutput := mockoutput.New()\n\t\t\ttest := newTestEngine(t, nil, runner, []output.Output{mockOutput}, runner.GetOptions())\n\n\t\t\terrC := make(chan error)\n\t\t\tgo func() { errC <- test.run() }()\n\n\t\t\tselect {\n\t\t\tcase <-time.After(10 * time.Second):\n\t\t\t\tt.Fatal(\"Test timed out\")\n\t\t\tcase err := <-errC:\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\ttest.wait()\n\t\t\t\trequire.False(t, test.engine.IsTainted())\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.expIters, getMetricSum(mockOutput, metrics.IterationsName))\n\t\t\tassert.Equal(t, tc.expCount, getMetricSum(mockOutput, \"testcounter\"))\n\t\t})\n\t}\n}\n*/\n"
  },
  {
    "path": "internal/metrics/engine/ingester.go",
    "content": "package engine\n\nimport (\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nconst (\n\tcollectRate          = 50 * time.Millisecond\n\ttimeSeriesFirstLimit = 100_000\n)\n\nvar _ output.Output = &OutputIngester{}\n\n// IngesterDescription is a short description for ingester.\n// This variable is used from a function in cmd/ui file for matching this output\n// and print a special text.\nconst IngesterDescription = \"Internal Metrics Ingester\"\n\n// OutputIngester implements the output.Output interface and can be used to\n// \"feed\" the MetricsEngine data from a `k6 run` test run.\ntype OutputIngester struct {\n\toutput.SampleBuffer\n\tlogger logrus.FieldLogger\n\n\tmetricsEngine   *MetricsEngine\n\tperiodicFlusher *output.PeriodicFlusher\n\tcardinality     *cardinalityControl\n}\n\n// Description returns a human-readable description of the output.\nfunc (oi *OutputIngester) Description() string {\n\treturn IngesterDescription\n}\n\n// Start the engine by initializing a new output.PeriodicFlusher\nfunc (oi *OutputIngester) Start() error {\n\toi.logger.Debug(\"Starting...\")\n\n\tpf, err := output.NewPeriodicFlusher(collectRate, oi.flushMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\toi.logger.Debug(\"Started!\")\n\toi.periodicFlusher = pf\n\n\treturn nil\n}\n\n// Stop flushes any remaining metrics and stops the goroutine.\nfunc (oi *OutputIngester) Stop() error {\n\toi.logger.Debug(\"Stopping...\")\n\tdefer oi.logger.Debug(\"Stopped!\")\n\toi.periodicFlusher.Stop()\n\treturn nil\n}\n\n// flushMetrics Writes samples to the MetricsEngine\nfunc (oi *OutputIngester) flushMetrics() {\n\tsampleContainers := oi.GetBufferedSamples()\n\tif len(sampleContainers) == 0 {\n\t\treturn\n\t}\n\n\toi.metricsEngine.MetricsLock.Lock()\n\tdefer oi.metricsEngine.MetricsLock.Unlock()\n\n\t// TODO: split metric samples in buckets with a *metrics.Metric key; this will\n\t// allow us to have a per-bucket lock, instead of one global one, and it\n\t// will allow us to split apart the metric Name and Type from its Sink and\n\t// Observed fields...\n\t//\n\t// And, to further optimize things, if every metric (and sub-metric) had a\n\t// sequential integer ID, we would be able to use a slice for these buckets\n\t// and eliminate the map loopkups altogether!\n\n\tfor _, sampleContainer := range sampleContainers {\n\t\tsamples := sampleContainer.GetSamples()\n\n\t\tif len(samples) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, sample := range samples {\n\t\t\tm := sample.Metric               // this should have come from the Registry, no need to look it up\n\t\t\toi.metricsEngine.markObserved(m) // mark it as observed so it shows in the end-of-test summary\n\t\t\tm.Sink.Add(sample)               // finally, add its value to its own sink\n\n\t\t\t// and also to the same for any submetrics that match the metric sample\n\t\t\tfor _, sm := range m.Submetrics {\n\t\t\t\tif !sample.Tags.Contains(sm.Tags) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\toi.metricsEngine.markObserved(sm.Metric)\n\t\t\t\tsm.Metric.Sink.Add(sample)\n\t\t\t}\n\n\t\t\toi.cardinality.Add(sample.TimeSeries)\n\t\t}\n\t}\n\n\tif oi.cardinality.LimitHit() {\n\t\t// TODO: suggest using the Metadata API as an alternative, once it's\n\t\t// available (e.g. move high-cardinality tags as Metadata)\n\t\t// https://github.com/grafana/k6/issues/2766\n\n\t\toi.logger.Warnf(\n\t\t\t\"The test has generated metrics with %d unique time series, \"+\n\t\t\t\t\"which is higher than the suggested limit of %d \"+\n\t\t\t\t\"and could cause high memory usage. \"+\n\t\t\t\t\"Consider not using high-cardinality values like unique IDs as metric tags \"+\n\t\t\t\t\"or, if you need them in the URL, use the name metric tag or URL grouping. \"+\n\t\t\t\t\"See https://grafana.com/docs/k6/latest/using-k6/tags-and-groups/ for details.\",\n\t\t\toi.cardinality.Count(),\n\t\t\ttimeSeriesFirstLimit,\n\t\t)\n\t}\n}\n\ntype cardinalityControl struct {\n\tseen            map[metrics.TimeSeries]struct{}\n\ttimeSeriesLimit int\n}\n\nfunc newCardinalityControl() *cardinalityControl {\n\treturn &cardinalityControl{\n\t\ttimeSeriesLimit: timeSeriesFirstLimit,\n\t\tseen:            make(map[metrics.TimeSeries]struct{}),\n\t}\n}\n\n// Add adds the passed time series to the list of seen items.\nfunc (cc *cardinalityControl) Add(ts metrics.TimeSeries) {\n\tif _, ok := cc.seen[ts]; ok {\n\t\treturn\n\t}\n\tcc.seen[ts] = struct{}{}\n}\n\n// LimitHit checks if the cardinality limit has been hit.\nfunc (cc *cardinalityControl) LimitHit() bool {\n\tif len(cc.seen) <= cc.timeSeriesLimit {\n\t\treturn false\n\t}\n\n\t// we don't care about overflow\n\t// the process should be already OOM\n\t// if the number of generated time series goes higher than N-hundred-million(s).\n\tcc.timeSeriesLimit *= 2\n\treturn true\n}\n\n// Count returns the number of distinct seen time series.\nfunc (cc *cardinalityControl) Count() int {\n\treturn len(cc.seen)\n}\n"
  },
  {
    "path": "internal/metrics/engine/ingester_test.go",
    "content": "package engine\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestIngesterOutputFlushMetrics(t *testing.T) {\n\tt.Parallel()\n\n\tpiState := newTestPreInitState(t)\n\ttestMetric, err := piState.Registry.NewMetric(\"test_metric\", metrics.Trend)\n\trequire.NoError(t, err)\n\n\tingester := OutputIngester{\n\t\tlogger: piState.Logger,\n\t\tmetricsEngine: &MetricsEngine{\n\t\t\tObservedMetrics: make(map[string]*metrics.Metric),\n\t\t},\n\t\tcardinality: newCardinalityControl(),\n\t}\n\trequire.NoError(t, ingester.Start())\n\tingester.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{Metric: testMetric},\n\t\tValue:      21,\n\t}})\n\tingester.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{Metric: testMetric},\n\t\tValue:      21,\n\t}})\n\trequire.NoError(t, ingester.Stop())\n\n\trequire.Len(t, ingester.metricsEngine.ObservedMetrics, 1)\n\tmetric := ingester.metricsEngine.ObservedMetrics[\"test_metric\"]\n\trequire.NotNil(t, metric)\n\trequire.NotNil(t, metric.Sink)\n\tassert.Equal(t, testMetric, metric)\n\n\tsink := metric.Sink.(*metrics.TrendSink)\n\tassert.Equal(t, 42.0, sink.Total())\n}\n\nfunc TestIngesterOutputFlushSubmetrics(t *testing.T) {\n\tt.Parallel()\n\n\tpiState := newTestPreInitState(t)\n\ttestMetric, err := piState.Registry.NewMetric(\"test_metric\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\tme := &MetricsEngine{\n\t\tlogger:          piState.Logger,\n\t\tregistry:        piState.Registry,\n\t\tObservedMetrics: make(map[string]*metrics.Metric),\n\t}\n\t_, err = me.getThresholdMetricOrSubmetric(\"test_metric{a:1}\")\n\trequire.NoError(t, err)\n\n\t// assert that observed metrics is empty before to start\n\trequire.Empty(t, me.ObservedMetrics)\n\n\tingester := OutputIngester{\n\t\tlogger:        piState.Logger,\n\t\tmetricsEngine: me,\n\t\tcardinality:   newCardinalityControl(),\n\t}\n\trequire.NoError(t, ingester.Start())\n\tingester.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: testMetric,\n\t\t\tTags: piState.Registry.RootTagSet().WithTagsFromMap(\n\t\t\t\tmap[string]string{\"a\": \"1\", \"b\": \"2\"}),\n\t\t},\n\t\tValue: 21,\n\t}})\n\trequire.NoError(t, ingester.Stop())\n\n\trequire.Len(t, ingester.metricsEngine.ObservedMetrics, 2)\n\n\t// assert the parent has been observed\n\tmetric := ingester.metricsEngine.ObservedMetrics[\"test_metric\"]\n\trequire.NotNil(t, metric)\n\trequire.NotNil(t, metric.Sink)\n\tassert.IsType(t, &metrics.GaugeSink{}, metric.Sink)\n\n\t// assert the submetric has been observed\n\tmetric = ingester.metricsEngine.ObservedMetrics[\"test_metric{a:1}\"]\n\trequire.NotNil(t, metric)\n\trequire.NotNil(t, metric.Sink)\n\trequire.NotNil(t, metric.Sub)\n\tassert.EqualValues(t, map[string]string{\"a\": \"1\"}, metric.Sub.Tags.Map())\n\tassert.IsType(t, &metrics.GaugeSink{}, metric.Sink)\n}\n\nfunc TestOutputFlushMetricsTimeSeriesWarning(t *testing.T) {\n\tt.Parallel()\n\n\tpiState := newTestPreInitState(t)\n\ttestMetric, err := piState.Registry.NewMetric(\"test_metric\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\tlogger, hook := testutils.NewLoggerWithHook(nil)\n\tingester := OutputIngester{\n\t\tlogger: logger,\n\t\tmetricsEngine: &MetricsEngine{\n\t\t\tObservedMetrics: make(map[string]*metrics.Metric),\n\t\t},\n\t\tcardinality: newCardinalityControl(),\n\t}\n\tingester.cardinality.timeSeriesLimit = 2 // mock the limit\n\n\trequire.NoError(t, ingester.Start())\n\tfor i := range 3 {\n\t\tingester.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: testMetric,\n\t\t\t\tTags: piState.Registry.RootTagSet().WithTagsFromMap(\n\t\t\t\t\tmap[string]string{\"a\": \"1\", \"b\": strconv.Itoa(i)}),\n\t\t\t},\n\t\t\tValue: 21,\n\t\t}})\n\t}\n\trequire.NoError(t, ingester.Stop())\n\n\t// to keep things simple the internal limit is not passed to the message\n\t// the code uses directly the global constant limit\n\texpLine := \"generated metrics with 3 unique time series, \" +\n\t\t\"which is higher than the suggested limit of 100000\"\n\tassert.True(t, testutils.LogContains(hook.Drain(), logrus.WarnLevel, expLine))\n}\n\nfunc TestCardinalityControlAdd(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\tm1, err := registry.NewMetric(\"metric1\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\tm2, err := registry.NewMetric(\"metric2\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\ttags := registry.RootTagSet().With(\"k\", \"v\")\n\n\tcc := newCardinalityControl()\n\t// the first iteration adds two new time series\n\t// the second does not change the count\n\t// because the time series have been already seen before\n\tfor range 2 {\n\t\tcc.Add(metrics.TimeSeries{\n\t\t\tMetric: m1,\n\t\t\tTags:   tags,\n\t\t})\n\t\tcc.Add(metrics.TimeSeries{\n\t\t\tMetric: m2,\n\t\t\tTags:   tags,\n\t\t})\n\t\tassert.Equal(t, 2, len(cc.seen))\n\t}\n}\n\nfunc TestCardinalityControlLimitHit(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\tm1, err := registry.NewMetric(\"metric1\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\tcc := newCardinalityControl()\n\tcc.timeSeriesLimit = 1\n\n\tcc.Add(metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   registry.RootTagSet().With(\"k\", \"1\"),\n\t})\n\tassert.False(t, cc.LimitHit())\n\n\t// the same time series should not impact the counter\n\tcc.Add(metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   registry.RootTagSet().With(\"k\", \"1\"),\n\t})\n\tassert.False(t, cc.LimitHit())\n\n\tcc.Add(metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   registry.RootTagSet().With(\"k\", \"2\"),\n\t})\n\tassert.True(t, cc.LimitHit())\n\tassert.Equal(t, 2, cc.timeSeriesLimit, \"the limit is expected to be raised\")\n}\n\nfunc newTestPreInitState(tb testing.TB) *lib.TestPreInitState {\n\treg := metrics.NewRegistry()\n\tlogger := testutils.NewLogger(tb)\n\treturn &lib.TestPreInitState{\n\t\tLogger:         logger,\n\t\tRuntimeOptions: lib.RuntimeOptions{},\n\t\tRegistry:       reg,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(reg),\n\t}\n}\n"
  },
  {
    "path": "internal/output/cloud/expv2/integration/integration_test.go",
    "content": "package integration\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"sort\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/klauspost/compress/snappy\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output/cloud/expv2\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\t\"google.golang.org/protobuf/proto\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// This test runs an integration tests for the Output cloud.\n// It only calls public API of the Output and\n// it implements a concrete http endpoint where to get\n// the protobuf flush requests.\n\nfunc TestOutputFlush(t *testing.T) {\n\t// TODO: it has 3s for aggregation time\n\t// then it means it will execute for +3s that it is a waste of time\n\t// because it isn't really required.\n\t// Reduce the aggregation time (to 1s?)\n\tt.Parallel()\n\n\tresults := make(chan *pbcloud.MetricSet)\n\tts := httptest.NewServer(metricsHandler(results))\n\tdefer ts.Close()\n\n\t// init conifg\n\tconf := cloudapi.NewConfig()\n\tconf.Host = null.StringFrom(ts.URL)\n\tconf.Token = null.StringFrom(\"my-secret-token\")\n\tconf.AggregationPeriod = types.NullDurationFrom(3 * time.Second)\n\tconf.AggregationWaitPeriod = types.NullDurationFrom(1 * time.Second)\n\n\tlogger := testutils.NewLogger(t)\n\tcc := cloudapi.NewClient(logger, conf.Token.String, conf.Host.String,\n\t\t\"expv2/integration\", conf.Timeout.TimeDuration())\n\n\t// init and start the output\n\to, err := expv2.New(logger, conf, cc)\n\trequire.NoError(t, err)\n\to.SetTestRunID(\"123\")\n\trequire.NoError(t, o.Start())\n\n\t// collect and flush samples\n\to.AddMetricSamples([]metrics.SampleContainer{\n\t\ttestSamples(),\n\t})\n\n\t// wait for results\n\tcapturedMetrics := <-results\n\tclose(results)\n\tassert.NoError(t, o.StopWithTestError(nil))\n\n\t// sort the metrics' result by name to have a deterministic order\n\t// that should be same as the expected json\n\tsort.Slice(capturedMetrics.Metrics, func(i, j int) bool {\n\t\treturn capturedMetrics.Metrics[i].Name < capturedMetrics.Metrics[j].Name\n\t})\n\n\t// read and convert the json version\n\t// of the expected protobuf sent request\n\tvar exp pbcloud.MetricSet\n\texpectedMetrics, err := os.ReadFile(\"./testdata/metricset.json\") //nolint:forbidigo // ReadFile here is used in a test\n\trequire.NoError(t, err)\n\terr = protojson.Unmarshal(expectedMetrics, &exp)\n\trequire.NoError(t, err)\n\n\tactualMetrics, err := protojson.Marshal(capturedMetrics)\n\trequire.NoError(t, err)\n\tassert.JSONEq(t, string(expectedMetrics), string(actualMetrics))\n}\n\nfunc metricsHandler(results chan<- *pbcloud.MetricSet) http.HandlerFunc {\n\treturn func(rw http.ResponseWriter, r *http.Request) {\n\t\ttoken := r.Header.Get(\"Authorization\")\n\t\tif token != \"Token my-secret-token\" {\n\t\t\thttp.Error(rw, fmt.Sprintf(\"token is required; got %q\", token), http.StatusUnauthorized)\n\t\t\treturn\n\t\t}\n\t\tb, err := io.ReadAll(r.Body)\n\t\tif err != nil {\n\t\t\thttp.Error(rw, err.Error(), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tmset, err := metricSetFromRequest(b)\n\t\tif err != nil {\n\t\t\thttp.Error(rw, err.Error(), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tresults <- mset\n\t}\n}\n\nfunc metricSetFromRequest(b []byte) (*pbcloud.MetricSet, error) {\n\tb, err := snappy.Decode(nil, b)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar mset pbcloud.MetricSet\n\terr = proto.Unmarshal(b, &mset)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &mset, nil\n}\n\nfunc testSamples() metrics.Samples {\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric_counter_1\", metrics.Counter)\n\tm2 := r.MustNewMetric(\"metric_gauge_2\", metrics.Gauge)\n\tm3 := r.MustNewMetric(\"metric_rate_3\", metrics.Rate)\n\tm4 := r.MustNewMetric(\"metric_trend_4\", metrics.Trend)\n\n\tsamples := []metrics.Sample{\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: m1,\n\t\t\t\tTags:   r.RootTagSet().With(\"my_label_1\", \"my_label_value_1\"),\n\t\t\t},\n\t\t\tTime:  time.Date(2023, time.May, 1, 1, 0, 0, 0, time.UTC),\n\t\t\tValue: 42.2,\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: m2,\n\t\t\t\tTags:   r.RootTagSet().With(\"my_label_2\", \"my_label_value_2\"),\n\t\t\t},\n\t\t\tTime:  time.Date(2023, time.May, 1, 2, 0, 0, 0, time.UTC),\n\t\t\tValue: 3.14,\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: m3,\n\t\t\t\tTags:   r.RootTagSet().With(\"my_label_3\", \"my_label_value_3\"),\n\t\t\t},\n\t\t\tTime:  time.Date(2023, time.May, 1, 3, 0, 0, 0, time.UTC),\n\t\t\tValue: 2.718,\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: m4,\n\t\t\t\tTags:   r.RootTagSet().With(\"my_label_4\", \"my_label_value_4\"),\n\t\t\t},\n\t\t\tTime:  time.Date(2023, time.May, 1, 4, 0, 0, 0, time.UTC),\n\t\t\tValue: 6,\n\t\t},\n\t}\n\treturn samples\n}\n"
  },
  {
    "path": "internal/output/cloud/expv2/integration/testdata/metricset.json",
    "content": "{\n  \"testRunId\": \"123\",\n  \"aggregationPeriod\": 3,\n  \"metrics\": [\n    {\n      \"name\": \"metric_counter_1\",\n      \"type\": \"METRIC_TYPE_COUNTER\",\n      \"timeSeries\": [\n        {\n          \"labels\": [\n            {\n              \"name\": \"my_label_1\",\n              \"value\": \"my_label_value_1\"\n            }\n          ],\n          \"counterSamples\": {\n            \"values\": [\n              {\n                \"time\": \"2023-05-01T01:00:00Z\",\n                \"value\": 42.2\n              }\n            ]\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"metric_gauge_2\",\n      \"type\": \"METRIC_TYPE_GAUGE\",\n      \"timeSeries\": [\n        {\n          \"labels\": [\n            {\n              \"name\": \"my_label_2\",\n              \"value\": \"my_label_value_2\"\n            }\n          ],\n          \"gaugeSamples\": {\n            \"values\": [\n              {\n                \"time\": \"2023-05-01T02:00:00Z\",\n                \"last\": 3.14,\n                \"min\": 3.14,\n                \"max\": 3.14,\n                \"avg\": 3.14,\n                \"count\": 1\n              }\n            ]\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"metric_rate_3\",\n      \"type\": \"METRIC_TYPE_RATE\",\n      \"timeSeries\": [\n        {\n          \"labels\": [\n            {\n              \"name\": \"my_label_3\",\n              \"value\": \"my_label_value_3\"\n            }\n          ],\n          \"rateSamples\": {\n            \"values\": [\n              {\n                \"time\": \"2023-05-01T03:00:00Z\",\n                \"nonzeroCount\": 1,\n                \"totalCount\": 1\n              }\n            ]\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"metric_trend_4\",\n      \"type\": \"METRIC_TYPE_TREND\",\n      \"timeSeries\": [\n        {\n          \"labels\": [\n            {\n              \"name\": \"my_label_4\",\n              \"value\": \"my_label_value_4\"\n            }\n          ],\n          \"trendHdrSamples\": {\n            \"values\": [\n              {\n                \"time\": \"2023-05-01T04:00:00Z\",\n                \"count\": 1,\n                \"counters\": [\n                  1\n                ],\n                \"spans\": [\n                  {\n                    \"offset\": 827,\n                    \"length\": 1\n                  }\n                ],\n                \"maxValue\": 6,\n                \"minValue\": 6,\n                \"sum\": 6,\n                \"minResolution\": 0.001\n              }\n            ]\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "internal/output/cloud/expv2/pbcloud/gen.go",
    "content": "// Package pbcloud contains the Protobuf definitions used\n// for the metrics flush RPCs.\npackage pbcloud\n\n//go:generate protoc --go_out=. --go_opt=paths=source_relative ./metric.proto\n"
  },
  {
    "path": "internal/output/cloud/expv2/pbcloud/metric.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.31.0\n// \tprotoc        v3.21.12\n// source: metric.proto\n\npackage pbcloud\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\ttimestamppb \"google.golang.org/protobuf/types/known/timestamppb\"\n\treflect \"reflect\"\n\tsync \"sync\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\n// The type of a Metric.\ntype MetricType int32\n\nconst (\n\t// Metric of type METRICTYPE_UNSPECIFIED declared, but not allowed.\n\t// See: https://protobuf.dev/programming-guides/dos-donts/#do-include-an-unspecified-value-in-an-enum.\n\tMetricType_METRIC_TYPE_UNSPECIFIED MetricType = 0\n\tMetricType_METRIC_TYPE_COUNTER     MetricType = 1\n\tMetricType_METRIC_TYPE_GAUGE       MetricType = 2\n\tMetricType_METRIC_TYPE_RATE        MetricType = 3\n\tMetricType_METRIC_TYPE_TREND       MetricType = 4\n)\n\n// Enum value maps for MetricType.\nvar (\n\tMetricType_name = map[int32]string{\n\t\t0: \"METRIC_TYPE_UNSPECIFIED\",\n\t\t1: \"METRIC_TYPE_COUNTER\",\n\t\t2: \"METRIC_TYPE_GAUGE\",\n\t\t3: \"METRIC_TYPE_RATE\",\n\t\t4: \"METRIC_TYPE_TREND\",\n\t}\n\tMetricType_value = map[string]int32{\n\t\t\"METRIC_TYPE_UNSPECIFIED\": 0,\n\t\t\"METRIC_TYPE_COUNTER\":     1,\n\t\t\"METRIC_TYPE_GAUGE\":       2,\n\t\t\"METRIC_TYPE_RATE\":        3,\n\t\t\"METRIC_TYPE_TREND\":       4,\n\t}\n)\n\nfunc (x MetricType) Enum() *MetricType {\n\tp := new(MetricType)\n\t*p = x\n\treturn p\n}\n\nfunc (x MetricType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (MetricType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_metric_proto_enumTypes[0].Descriptor()\n}\n\nfunc (MetricType) Type() protoreflect.EnumType {\n\treturn &file_metric_proto_enumTypes[0]\n}\n\nfunc (x MetricType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// Deprecated: Use MetricType.Descriptor instead.\nfunc (MetricType) EnumDescriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{0}\n}\n\n// MetricSet is the top-level container type\n// that is encoded and sent over the wire.\ntype MetricSet struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tTestRunId string `protobuf:\"bytes,1,opt,name=test_run_id,json=testRunId,proto3\" json:\"test_run_id,omitempty\"`\n\t// Required.\n\t// time bucket size in seconds\n\tAggregationPeriod uint32 `protobuf:\"varint,2,opt,name=aggregation_period,json=aggregationPeriod,proto3\" json:\"aggregation_period,omitempty\"`\n\t// Required.\n\tMetrics []*Metric `protobuf:\"bytes,3,rep,name=metrics,proto3\" json:\"metrics,omitempty\"`\n}\n\nfunc (x *MetricSet) Reset() {\n\t*x = MetricSet{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[0]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *MetricSet) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetricSet) ProtoMessage() {}\n\nfunc (x *MetricSet) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[0]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use MetricSet.ProtoReflect.Descriptor instead.\nfunc (*MetricSet) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{0}\n}\n\nfunc (x *MetricSet) GetTestRunId() string {\n\tif x != nil {\n\t\treturn x.TestRunId\n\t}\n\treturn \"\"\n}\n\nfunc (x *MetricSet) GetAggregationPeriod() uint32 {\n\tif x != nil {\n\t\treturn x.AggregationPeriod\n\t}\n\treturn 0\n}\n\nfunc (x *MetricSet) GetMetrics() []*Metric {\n\tif x != nil {\n\t\treturn x.Metrics\n\t}\n\treturn nil\n}\n\ntype Metric struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Required.\n\t// Can't be of type MetricType.METRICTYPE_UNSPECIFIED (which is zero value).\n\tType MetricType `protobuf:\"varint,2,opt,name=type,proto3,enum=metrics.MetricType\" json:\"type,omitempty\"`\n\t// Optional.\n\tTimeSeries []*TimeSeries `protobuf:\"bytes,3,rep,name=time_series,json=timeSeries,proto3\" json:\"time_series,omitempty\"`\n}\n\nfunc (x *Metric) Reset() {\n\t*x = Metric{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[1]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Metric) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Metric) ProtoMessage() {}\n\nfunc (x *Metric) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[1]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Metric.ProtoReflect.Descriptor instead.\nfunc (*Metric) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{1}\n}\n\nfunc (x *Metric) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Metric) GetType() MetricType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn MetricType_METRIC_TYPE_UNSPECIFIED\n}\n\nfunc (x *Metric) GetTimeSeries() []*TimeSeries {\n\tif x != nil {\n\t\treturn x.TimeSeries\n\t}\n\treturn nil\n}\n\n// Label is a name-value pair.\ntype Label struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tName string `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\t// Required.\n\tValue string `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *Label) Reset() {\n\t*x = Label{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[2]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *Label) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Label) ProtoMessage() {}\n\nfunc (x *Label) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[2]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use Label.ProtoReflect.Descriptor instead.\nfunc (*Label) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{2}\n}\n\nfunc (x *Label) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Label) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\n// TimeSeries is a single metric with a unique set of labels.\ntype TimeSeries struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Optional.\n\tLabels []*Label `protobuf:\"bytes,1,rep,name=labels,proto3\" json:\"labels,omitempty\"`\n\t// Required.\n\t//\n\t// Types that are assignable to Samples:\n\t//\n\t//\t*TimeSeries_CounterSamples\n\t//\t*TimeSeries_GaugeSamples\n\t//\t*TimeSeries_RateSamples\n\t//\t*TimeSeries_TrendHdrSamples\n\tSamples isTimeSeries_Samples `protobuf_oneof:\"samples\"`\n}\n\nfunc (x *TimeSeries) Reset() {\n\t*x = TimeSeries{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[3]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TimeSeries) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TimeSeries) ProtoMessage() {}\n\nfunc (x *TimeSeries) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[3]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TimeSeries.ProtoReflect.Descriptor instead.\nfunc (*TimeSeries) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{3}\n}\n\nfunc (x *TimeSeries) GetLabels() []*Label {\n\tif x != nil {\n\t\treturn x.Labels\n\t}\n\treturn nil\n}\n\nfunc (m *TimeSeries) GetSamples() isTimeSeries_Samples {\n\tif m != nil {\n\t\treturn m.Samples\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetCounterSamples() *CounterSamples {\n\tif x, ok := x.GetSamples().(*TimeSeries_CounterSamples); ok {\n\t\treturn x.CounterSamples\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetGaugeSamples() *GaugeSamples {\n\tif x, ok := x.GetSamples().(*TimeSeries_GaugeSamples); ok {\n\t\treturn x.GaugeSamples\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetRateSamples() *RateSamples {\n\tif x, ok := x.GetSamples().(*TimeSeries_RateSamples); ok {\n\t\treturn x.RateSamples\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetTrendHdrSamples() *TrendHdrSamples {\n\tif x, ok := x.GetSamples().(*TimeSeries_TrendHdrSamples); ok {\n\t\treturn x.TrendHdrSamples\n\t}\n\treturn nil\n}\n\ntype isTimeSeries_Samples interface {\n\tisTimeSeries_Samples()\n}\n\ntype TimeSeries_CounterSamples struct {\n\tCounterSamples *CounterSamples `protobuf:\"bytes,2,opt,name=counter_samples,json=counterSamples,proto3,oneof\"`\n}\n\ntype TimeSeries_GaugeSamples struct {\n\tGaugeSamples *GaugeSamples `protobuf:\"bytes,3,opt,name=gauge_samples,json=gaugeSamples,proto3,oneof\"`\n}\n\ntype TimeSeries_RateSamples struct {\n\tRateSamples *RateSamples `protobuf:\"bytes,4,opt,name=rate_samples,json=rateSamples,proto3,oneof\"`\n}\n\ntype TimeSeries_TrendHdrSamples struct {\n\tTrendHdrSamples *TrendHdrSamples `protobuf:\"bytes,5,opt,name=trend_hdr_samples,json=trendHdrSamples,proto3,oneof\"`\n}\n\nfunc (*TimeSeries_CounterSamples) isTimeSeries_Samples() {}\n\nfunc (*TimeSeries_GaugeSamples) isTimeSeries_Samples() {}\n\nfunc (*TimeSeries_RateSamples) isTimeSeries_Samples() {}\n\nfunc (*TimeSeries_TrendHdrSamples) isTimeSeries_Samples() {}\n\ntype CounterSamples struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tValues []*CounterValue `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *CounterSamples) Reset() {\n\t*x = CounterSamples{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[4]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CounterSamples) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CounterSamples) ProtoMessage() {}\n\nfunc (x *CounterSamples) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[4]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CounterSamples.ProtoReflect.Descriptor instead.\nfunc (*CounterSamples) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{4}\n}\n\nfunc (x *CounterSamples) GetValues() []*CounterValue {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype GaugeSamples struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tValues []*GaugeValue `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *GaugeSamples) Reset() {\n\t*x = GaugeSamples{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[5]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GaugeSamples) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GaugeSamples) ProtoMessage() {}\n\nfunc (x *GaugeSamples) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[5]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GaugeSamples.ProtoReflect.Descriptor instead.\nfunc (*GaugeSamples) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{5}\n}\n\nfunc (x *GaugeSamples) GetValues() []*GaugeValue {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype RateSamples struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tValues []*RateValue `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *RateSamples) Reset() {\n\t*x = RateSamples{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[6]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RateSamples) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RateSamples) ProtoMessage() {}\n\nfunc (x *RateSamples) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[6]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RateSamples.ProtoReflect.Descriptor instead.\nfunc (*RateSamples) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{6}\n}\n\nfunc (x *RateSamples) GetValues() []*RateValue {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype TrendHdrSamples struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tValues []*TrendHdrValue `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n}\n\nfunc (x *TrendHdrSamples) Reset() {\n\t*x = TrendHdrSamples{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[7]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TrendHdrSamples) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TrendHdrSamples) ProtoMessage() {}\n\nfunc (x *TrendHdrSamples) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[7]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TrendHdrSamples.ProtoReflect.Descriptor instead.\nfunc (*TrendHdrSamples) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{7}\n}\n\nfunc (x *TrendHdrSamples) GetValues() []*TrendHdrValue {\n\tif x != nil {\n\t\treturn x.Values\n\t}\n\treturn nil\n}\n\ntype CounterValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tTime  *timestamppb.Timestamp `protobuf:\"bytes,1,opt,name=time,proto3\" json:\"time,omitempty\"`\n\tValue float64                `protobuf:\"fixed64,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n}\n\nfunc (x *CounterValue) Reset() {\n\t*x = CounterValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[8]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *CounterValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*CounterValue) ProtoMessage() {}\n\nfunc (x *CounterValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[8]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use CounterValue.ProtoReflect.Descriptor instead.\nfunc (*CounterValue) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{8}\n}\n\nfunc (x *CounterValue) GetTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.Time\n\t}\n\treturn nil\n}\n\nfunc (x *CounterValue) GetValue() float64 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\ntype GaugeValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tTime *timestamppb.Timestamp `protobuf:\"bytes,1,opt,name=time,proto3\" json:\"time,omitempty\"`\n\t// last observed value\n\tLast float64 `protobuf:\"fixed64,2,opt,name=last,proto3\" json:\"last,omitempty\"`\n\t// count of observations\n\tCount uint32 `protobuf:\"varint,3,opt,name=count,proto3\" json:\"count,omitempty\"`\n\t// min, max, and average of observed values\n\tMin float64 `protobuf:\"fixed64,4,opt,name=min,proto3\" json:\"min,omitempty\"`\n\tMax float64 `protobuf:\"fixed64,5,opt,name=max,proto3\" json:\"max,omitempty\"`\n\tAvg float64 `protobuf:\"fixed64,6,opt,name=avg,proto3\" json:\"avg,omitempty\"`\n}\n\nfunc (x *GaugeValue) Reset() {\n\t*x = GaugeValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[9]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *GaugeValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*GaugeValue) ProtoMessage() {}\n\nfunc (x *GaugeValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[9]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use GaugeValue.ProtoReflect.Descriptor instead.\nfunc (*GaugeValue) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{9}\n}\n\nfunc (x *GaugeValue) GetTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.Time\n\t}\n\treturn nil\n}\n\nfunc (x *GaugeValue) GetLast() float64 {\n\tif x != nil {\n\t\treturn x.Last\n\t}\n\treturn 0\n}\n\nfunc (x *GaugeValue) GetCount() uint32 {\n\tif x != nil {\n\t\treturn x.Count\n\t}\n\treturn 0\n}\n\nfunc (x *GaugeValue) GetMin() float64 {\n\tif x != nil {\n\t\treturn x.Min\n\t}\n\treturn 0\n}\n\nfunc (x *GaugeValue) GetMax() float64 {\n\tif x != nil {\n\t\treturn x.Max\n\t}\n\treturn 0\n}\n\nfunc (x *GaugeValue) GetAvg() float64 {\n\tif x != nil {\n\t\treturn x.Avg\n\t}\n\treturn 0\n}\n\ntype RateValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tTime         *timestamppb.Timestamp `protobuf:\"bytes,1,opt,name=time,proto3\" json:\"time,omitempty\"`\n\tNonzeroCount uint32                 `protobuf:\"varint,2,opt,name=nonzero_count,json=nonzeroCount,proto3\" json:\"nonzero_count,omitempty\"`\n\tTotalCount   uint32                 `protobuf:\"varint,3,opt,name=total_count,json=totalCount,proto3\" json:\"total_count,omitempty\"`\n}\n\nfunc (x *RateValue) Reset() {\n\t*x = RateValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[10]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *RateValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*RateValue) ProtoMessage() {}\n\nfunc (x *RateValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[10]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use RateValue.ProtoReflect.Descriptor instead.\nfunc (*RateValue) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{10}\n}\n\nfunc (x *RateValue) GetTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.Time\n\t}\n\treturn nil\n}\n\nfunc (x *RateValue) GetNonzeroCount() uint32 {\n\tif x != nil {\n\t\treturn x.NonzeroCount\n\t}\n\treturn 0\n}\n\nfunc (x *RateValue) GetTotalCount() uint32 {\n\tif x != nil {\n\t\treturn x.TotalCount\n\t}\n\treturn 0\n}\n\n// BucketSpan represents the consecutive and significant (non-zero) buckets.\n// The concept is imported from the Prometheus' native histogram.\n// It should simplify an eventual transition to Prometheus.\n// https://github.com/prometheus/prometheus/blob/f399f386cef3b19c48157e9678a4f50997db3f41/prompb/io/prometheus/client/metrics.proto#L115-L124\ntype BucketSpan struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\tOffset uint32 `protobuf:\"varint,1,opt,name=offset,proto3\" json:\"offset,omitempty\"` // Gap to previous span, or starting point for 1st span.\n\tLength uint32 `protobuf:\"varint,2,opt,name=length,proto3\" json:\"length,omitempty\"` // Length of the next consecutive buckets.\n}\n\nfunc (x *BucketSpan) Reset() {\n\t*x = BucketSpan{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[11]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *BucketSpan) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BucketSpan) ProtoMessage() {}\n\nfunc (x *BucketSpan) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[11]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use BucketSpan.ProtoReflect.Descriptor instead.\nfunc (*BucketSpan) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{11}\n}\n\nfunc (x *BucketSpan) GetOffset() uint32 {\n\tif x != nil {\n\t\treturn x.Offset\n\t}\n\treturn 0\n}\n\nfunc (x *BucketSpan) GetLength() uint32 {\n\tif x != nil {\n\t\treturn x.Length\n\t}\n\treturn 0\n}\n\ntype TrendHdrValue struct {\n\tstate         protoimpl.MessageState\n\tsizeCache     protoimpl.SizeCache\n\tunknownFields protoimpl.UnknownFields\n\n\t// Required.\n\tTime *timestamppb.Timestamp `protobuf:\"bytes,1,opt,name=time,proto3\" json:\"time,omitempty\"`\n\t// positive buckets starting from bucket 1, each counter is an absolute value.\n\tCounters []uint32      `protobuf:\"varint,2,rep,packed,name=counters,proto3\" json:\"counters,omitempty\"`\n\tSpans    []*BucketSpan `protobuf:\"bytes,3,rep,name=spans,proto3\" json:\"spans,omitempty\"`\n\t// sum of observations\n\tSum float64 `protobuf:\"fixed64,5,opt,name=sum,proto3\" json:\"sum,omitempty\"`\n\t// count of observations\n\tCount uint32 `protobuf:\"varint,6,opt,name=count,proto3\" json:\"count,omitempty\"`\n\t// smallest and largest observed value\n\tMinValue float64 `protobuf:\"fixed64,7,opt,name=min_value,json=minValue,proto3\" json:\"min_value,omitempty\"`\n\tMaxValue float64 `protobuf:\"fixed64,8,opt,name=max_value,json=maxValue,proto3\" json:\"max_value,omitempty\"`\n\t// counters for zero- and infinity-buckets\n\tExtraLowValuesCounter  *uint32 `protobuf:\"varint,9,opt,name=extra_low_values_counter,json=extraLowValuesCounter,proto3,oneof\" json:\"extra_low_values_counter,omitempty\"`\n\tExtraHighValuesCounter *uint32 `protobuf:\"varint,10,opt,name=extra_high_values_counter,json=extraHighValuesCounter,proto3,oneof\" json:\"extra_high_values_counter,omitempty\"`\n\t// min_resolution is a multiplier factor applied to the tracked values of the histogram.\n\t// It is helpful for up and down scaling values and representing different orders of magnitude.\n\t// default = 1.0\n\tMinResolution float64 `protobuf:\"fixed64,11,opt,name=min_resolution,json=minResolution,proto3\" json:\"min_resolution,omitempty\"`\n\t// histogram parameter - number of significant digits used to calculate buckets formula\n\t// default = 2\n\tSignificantDigits *uint32 `protobuf:\"varint,12,opt,name=significant_digits,json=significantDigits,proto3,oneof\" json:\"significant_digits,omitempty\"`\n}\n\nfunc (x *TrendHdrValue) Reset() {\n\t*x = TrendHdrValue{}\n\tif protoimpl.UnsafeEnabled {\n\t\tmi := &file_metric_proto_msgTypes[12]\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tms.StoreMessageInfo(mi)\n\t}\n}\n\nfunc (x *TrendHdrValue) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TrendHdrValue) ProtoMessage() {}\n\nfunc (x *TrendHdrValue) ProtoReflect() protoreflect.Message {\n\tmi := &file_metric_proto_msgTypes[12]\n\tif protoimpl.UnsafeEnabled && x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\n// Deprecated: Use TrendHdrValue.ProtoReflect.Descriptor instead.\nfunc (*TrendHdrValue) Descriptor() ([]byte, []int) {\n\treturn file_metric_proto_rawDescGZIP(), []int{12}\n}\n\nfunc (x *TrendHdrValue) GetTime() *timestamppb.Timestamp {\n\tif x != nil {\n\t\treturn x.Time\n\t}\n\treturn nil\n}\n\nfunc (x *TrendHdrValue) GetCounters() []uint32 {\n\tif x != nil {\n\t\treturn x.Counters\n\t}\n\treturn nil\n}\n\nfunc (x *TrendHdrValue) GetSpans() []*BucketSpan {\n\tif x != nil {\n\t\treturn x.Spans\n\t}\n\treturn nil\n}\n\nfunc (x *TrendHdrValue) GetSum() float64 {\n\tif x != nil {\n\t\treturn x.Sum\n\t}\n\treturn 0\n}\n\nfunc (x *TrendHdrValue) GetCount() uint32 {\n\tif x != nil {\n\t\treturn x.Count\n\t}\n\treturn 0\n}\n\nfunc (x *TrendHdrValue) GetMinValue() float64 {\n\tif x != nil {\n\t\treturn x.MinValue\n\t}\n\treturn 0\n}\n\nfunc (x *TrendHdrValue) GetMaxValue() float64 {\n\tif x != nil {\n\t\treturn x.MaxValue\n\t}\n\treturn 0\n}\n\nfunc (x *TrendHdrValue) GetExtraLowValuesCounter() uint32 {\n\tif x != nil && x.ExtraLowValuesCounter != nil {\n\t\treturn *x.ExtraLowValuesCounter\n\t}\n\treturn 0\n}\n\nfunc (x *TrendHdrValue) GetExtraHighValuesCounter() uint32 {\n\tif x != nil && x.ExtraHighValuesCounter != nil {\n\t\treturn *x.ExtraHighValuesCounter\n\t}\n\treturn 0\n}\n\nfunc (x *TrendHdrValue) GetMinResolution() float64 {\n\tif x != nil {\n\t\treturn x.MinResolution\n\t}\n\treturn 0\n}\n\nfunc (x *TrendHdrValue) GetSignificantDigits() uint32 {\n\tif x != nil && x.SignificantDigits != nil {\n\t\treturn *x.SignificantDigits\n\t}\n\treturn 0\n}\n\nvar File_metric_proto protoreflect.FileDescriptor\n\nvar file_metric_proto_rawDesc = []byte{\n\t0x0a, 0x0c, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07,\n\t0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,\n\t0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x85, 0x01, 0x0a, 0x09, 0x4d, 0x65, 0x74,\n\t0x72, 0x69, 0x63, 0x53, 0x65, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x72,\n\t0x75, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x65, 0x73,\n\t0x74, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,\n\t0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0d, 0x52, 0x11, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,\n\t0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x29, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,\n\t0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,\n\t0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,\n\t0x22, 0x7b, 0x0a, 0x06, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,\n\t0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x27,\n\t0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x6d,\n\t0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70,\n\t0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x34, 0x0a, 0x0b, 0x74, 0x69, 0x6d, 0x65, 0x5f,\n\t0x73, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d,\n\t0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65,\n\t0x73, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0x31, 0x0a,\n\t0x05, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,\n\t0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x22, 0xc4, 0x02, 0x0a, 0x0a, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12,\n\t0x26, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,\n\t0x0e, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52,\n\t0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x42, 0x0a, 0x0f, 0x63, 0x6f, 0x75, 0x6e, 0x74,\n\t0x65, 0x72, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,\n\t0x32, 0x17, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74,\n\t0x65, 0x72, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x48, 0x00, 0x52, 0x0e, 0x63, 0x6f, 0x75,\n\t0x6e, 0x74, 0x65, 0x72, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0d, 0x67,\n\t0x61, 0x75, 0x67, 0x65, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01,\n\t0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x47, 0x61, 0x75,\n\t0x67, 0x65, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x67, 0x61, 0x75,\n\t0x67, 0x65, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x39, 0x0a, 0x0c, 0x72, 0x61, 0x74,\n\t0x65, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x14, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x53, 0x61,\n\t0x6d, 0x70, 0x6c, 0x65, 0x73, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6d,\n\t0x70, 0x6c, 0x65, 0x73, 0x12, 0x46, 0x0a, 0x11, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x5f, 0x68, 0x64,\n\t0x72, 0x5f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,\n\t0x18, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x72, 0x65, 0x6e, 0x64, 0x48,\n\t0x64, 0x72, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x74, 0x72, 0x65,\n\t0x6e, 0x64, 0x48, 0x64, 0x72, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x42, 0x09, 0x0a, 0x07,\n\t0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x22, 0x3f, 0x0a, 0x0e, 0x43, 0x6f, 0x75, 0x6e, 0x74,\n\t0x65, 0x72, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x06, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x74, 0x72,\n\t0x69, 0x63, 0x73, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65,\n\t0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x3b, 0x0a, 0x0c, 0x47, 0x61, 0x75, 0x67,\n\t0x65, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75,\n\t0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69,\n\t0x63, 0x73, 0x2e, 0x47, 0x61, 0x75, 0x67, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76,\n\t0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x0b, 0x52, 0x61, 0x74, 0x65, 0x53, 0x61, 0x6d,\n\t0x70, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01,\n\t0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x52,\n\t0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73,\n\t0x22, 0x41, 0x0a, 0x0f, 0x54, 0x72, 0x65, 0x6e, 0x64, 0x48, 0x64, 0x72, 0x53, 0x61, 0x6d, 0x70,\n\t0x6c, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20,\n\t0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x72,\n\t0x65, 0x6e, 0x64, 0x48, 0x64, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x73, 0x22, 0x54, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61,\n\t0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,\n\t0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,\n\t0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74,\n\t0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x9c, 0x01, 0x0a, 0x0a, 0x47, 0x61,\n\t0x75, 0x67, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65,\n\t0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,\n\t0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,\n\t0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x61, 0x73, 0x74,\n\t0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x04, 0x6c, 0x61, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x75,\n\t0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52,\n\t0x03, 0x6d, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28,\n\t0x01, 0x52, 0x03, 0x6d, 0x61, 0x78, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x76, 0x67, 0x18, 0x06, 0x20,\n\t0x01, 0x28, 0x01, 0x52, 0x03, 0x61, 0x76, 0x67, 0x22, 0x81, 0x01, 0x0a, 0x09, 0x52, 0x61, 0x74,\n\t0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01,\n\t0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,\n\t0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,\n\t0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x7a, 0x65, 0x72,\n\t0x6f, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e,\n\t0x6f, 0x6e, 0x7a, 0x65, 0x72, 0x6f, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x74,\n\t0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d,\n\t0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3c, 0x0a, 0x0a,\n\t0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66,\n\t0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73,\n\t0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01,\n\t0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x93, 0x04, 0x0a, 0x0d, 0x54,\n\t0x72, 0x65, 0x6e, 0x64, 0x48, 0x64, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x04,\n\t0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,\n\t0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,\n\t0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08,\n\t0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x6e,\n\t0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,\n\t0x73, 0x2e, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x70, 0x61, 0x6e, 0x52, 0x05, 0x73, 0x70,\n\t0x61, 0x6e, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01,\n\t0x52, 0x03, 0x73, 0x75, 0x6d, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06,\n\t0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d,\n\t0x69, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08,\n\t0x6d, 0x69, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f,\n\t0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6d, 0x61, 0x78,\n\t0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3c, 0x0a, 0x18, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x6c,\n\t0x6f, 0x77, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65,\n\t0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x15, 0x65, 0x78, 0x74, 0x72, 0x61,\n\t0x4c, 0x6f, 0x77, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,\n\t0x88, 0x01, 0x01, 0x12, 0x3e, 0x0a, 0x19, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x68, 0x69, 0x67,\n\t0x68, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,\n\t0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x01, 0x52, 0x16, 0x65, 0x78, 0x74, 0x72, 0x61, 0x48,\n\t0x69, 0x67, 0x68, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,\n\t0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c,\n\t0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0d, 0x6d, 0x69, 0x6e,\n\t0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x12, 0x73, 0x69,\n\t0x67, 0x6e, 0x69, 0x66, 0x69, 0x63, 0x61, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x69, 0x74, 0x73,\n\t0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x02, 0x52, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x66,\n\t0x69, 0x63, 0x61, 0x6e, 0x74, 0x44, 0x69, 0x67, 0x69, 0x74, 0x73, 0x88, 0x01, 0x01, 0x42, 0x1b,\n\t0x0a, 0x19, 0x5f, 0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x6c, 0x6f, 0x77, 0x5f, 0x76, 0x61, 0x6c,\n\t0x75, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x42, 0x1c, 0x0a, 0x1a, 0x5f,\n\t0x65, 0x78, 0x74, 0x72, 0x61, 0x5f, 0x68, 0x69, 0x67, 0x68, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65,\n\t0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x73, 0x69,\n\t0x67, 0x6e, 0x69, 0x66, 0x69, 0x63, 0x61, 0x6e, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x69, 0x74, 0x73,\n\t0x2a, 0x86, 0x01, 0x0a, 0x0a, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x54, 0x79, 0x70, 0x65, 0x12,\n\t0x1b, 0x0a, 0x17, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55,\n\t0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13,\n\t0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e,\n\t0x54, 0x45, 0x52, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f,\n\t0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x41, 0x55, 0x47, 0x45, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10,\n\t0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x41, 0x54, 0x45,\n\t0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x54, 0x59, 0x50,\n\t0x45, 0x5f, 0x54, 0x52, 0x45, 0x4e, 0x44, 0x10, 0x04, 0x42, 0x28, 0x5a, 0x26, 0x67, 0x6f, 0x2e,\n\t0x6b, 0x36, 0x2e, 0x69, 0x6f, 0x2f, 0x6b, 0x36, 0x2f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2f,\n\t0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x65, 0x78, 0x70, 0x76, 0x32, 0x2f, 0x70, 0x62, 0x63, 0x6c,\n\t0x6f, 0x75, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,\n}\n\nvar (\n\tfile_metric_proto_rawDescOnce sync.Once\n\tfile_metric_proto_rawDescData = file_metric_proto_rawDesc\n)\n\nfunc file_metric_proto_rawDescGZIP() []byte {\n\tfile_metric_proto_rawDescOnce.Do(func() {\n\t\tfile_metric_proto_rawDescData = protoimpl.X.CompressGZIP(file_metric_proto_rawDescData)\n\t})\n\treturn file_metric_proto_rawDescData\n}\n\nvar file_metric_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_metric_proto_msgTypes = make([]protoimpl.MessageInfo, 13)\nvar file_metric_proto_goTypes = []interface{}{\n\t(MetricType)(0),               // 0: metrics.MetricType\n\t(*MetricSet)(nil),             // 1: metrics.MetricSet\n\t(*Metric)(nil),                // 2: metrics.Metric\n\t(*Label)(nil),                 // 3: metrics.Label\n\t(*TimeSeries)(nil),            // 4: metrics.TimeSeries\n\t(*CounterSamples)(nil),        // 5: metrics.CounterSamples\n\t(*GaugeSamples)(nil),          // 6: metrics.GaugeSamples\n\t(*RateSamples)(nil),           // 7: metrics.RateSamples\n\t(*TrendHdrSamples)(nil),       // 8: metrics.TrendHdrSamples\n\t(*CounterValue)(nil),          // 9: metrics.CounterValue\n\t(*GaugeValue)(nil),            // 10: metrics.GaugeValue\n\t(*RateValue)(nil),             // 11: metrics.RateValue\n\t(*BucketSpan)(nil),            // 12: metrics.BucketSpan\n\t(*TrendHdrValue)(nil),         // 13: metrics.TrendHdrValue\n\t(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp\n}\nvar file_metric_proto_depIdxs = []int32{\n\t2,  // 0: metrics.MetricSet.metrics:type_name -> metrics.Metric\n\t0,  // 1: metrics.Metric.type:type_name -> metrics.MetricType\n\t4,  // 2: metrics.Metric.time_series:type_name -> metrics.TimeSeries\n\t3,  // 3: metrics.TimeSeries.labels:type_name -> metrics.Label\n\t5,  // 4: metrics.TimeSeries.counter_samples:type_name -> metrics.CounterSamples\n\t6,  // 5: metrics.TimeSeries.gauge_samples:type_name -> metrics.GaugeSamples\n\t7,  // 6: metrics.TimeSeries.rate_samples:type_name -> metrics.RateSamples\n\t8,  // 7: metrics.TimeSeries.trend_hdr_samples:type_name -> metrics.TrendHdrSamples\n\t9,  // 8: metrics.CounterSamples.values:type_name -> metrics.CounterValue\n\t10, // 9: metrics.GaugeSamples.values:type_name -> metrics.GaugeValue\n\t11, // 10: metrics.RateSamples.values:type_name -> metrics.RateValue\n\t13, // 11: metrics.TrendHdrSamples.values:type_name -> metrics.TrendHdrValue\n\t14, // 12: metrics.CounterValue.time:type_name -> google.protobuf.Timestamp\n\t14, // 13: metrics.GaugeValue.time:type_name -> google.protobuf.Timestamp\n\t14, // 14: metrics.RateValue.time:type_name -> google.protobuf.Timestamp\n\t14, // 15: metrics.TrendHdrValue.time:type_name -> google.protobuf.Timestamp\n\t12, // 16: metrics.TrendHdrValue.spans:type_name -> metrics.BucketSpan\n\t17, // [17:17] is the sub-list for method output_type\n\t17, // [17:17] is the sub-list for method input_type\n\t17, // [17:17] is the sub-list for extension type_name\n\t17, // [17:17] is the sub-list for extension extendee\n\t0,  // [0:17] is the sub-list for field type_name\n}\n\nfunc init() { file_metric_proto_init() }\nfunc file_metric_proto_init() {\n\tif File_metric_proto != nil {\n\t\treturn\n\t}\n\tif !protoimpl.UnsafeEnabled {\n\t\tfile_metric_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*MetricSet); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Metric); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*Label); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TimeSeries); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CounterSamples); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GaugeSamples); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RateSamples); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TrendHdrSamples); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*CounterValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*GaugeValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*RateValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*BucketSpan); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t\tfile_metric_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {\n\t\t\tswitch v := v.(*TrendHdrValue); i {\n\t\t\tcase 0:\n\t\t\t\treturn &v.state\n\t\t\tcase 1:\n\t\t\t\treturn &v.sizeCache\n\t\t\tcase 2:\n\t\t\t\treturn &v.unknownFields\n\t\t\tdefault:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\t}\n\tfile_metric_proto_msgTypes[3].OneofWrappers = []interface{}{\n\t\t(*TimeSeries_CounterSamples)(nil),\n\t\t(*TimeSeries_GaugeSamples)(nil),\n\t\t(*TimeSeries_RateSamples)(nil),\n\t\t(*TimeSeries_TrendHdrSamples)(nil),\n\t}\n\tfile_metric_proto_msgTypes[12].OneofWrappers = []interface{}{}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: file_metric_proto_rawDesc,\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   13,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_metric_proto_goTypes,\n\t\tDependencyIndexes: file_metric_proto_depIdxs,\n\t\tEnumInfos:         file_metric_proto_enumTypes,\n\t\tMessageInfos:      file_metric_proto_msgTypes,\n\t}.Build()\n\tFile_metric_proto = out.File\n\tfile_metric_proto_rawDesc = nil\n\tfile_metric_proto_goTypes = nil\n\tfile_metric_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "internal/output/cloud/expv2/pbcloud/metric.proto",
    "content": "syntax = \"proto3\";\n\npackage metrics;\n\noption go_package = \"go.k6.io/k6/output/cloud/expv2/pbcloud\";\n\nimport \"google/protobuf/timestamp.proto\";\n\n// The type of a Metric.\nenum MetricType {\n  // Metric of type METRICTYPE_UNSPECIFIED declared, but not allowed.\n  // See: https://protobuf.dev/programming-guides/dos-donts/#do-include-an-unspecified-value-in-an-enum.\n  METRIC_TYPE_UNSPECIFIED = 0;\n  METRIC_TYPE_COUNTER = 1;\n  METRIC_TYPE_GAUGE = 2;\n  METRIC_TYPE_RATE = 3;\n  METRIC_TYPE_TREND = 4;\n}\n\n// MetricSet is the top-level container type\n// that is encoded and sent over the wire.\nmessage MetricSet {\n  // Required.\n  string test_run_id = 1;\n\n  // Required.\n  // time bucket size in seconds\n  uint32 aggregation_period = 2;\n\n  // Required.\n  repeated Metric metrics = 3;\n}\n\nmessage Metric {\n  // Required.\n  string name = 1;\n\n  // Required.\n  // Can't be of type MetricType.METRICTYPE_UNSPECIFIED (which is zero value).\n  MetricType type = 2;\n\n  // Optional.\n  repeated TimeSeries time_series = 3;\n}\n\n// Label is a name-value pair.\nmessage Label {\n  // Required.\n  string name = 1;\n\n  // Required.\n  string value = 2;\n}\n\n// TimeSeries is a single metric with a unique set of labels.\nmessage TimeSeries {\n  // Optional.\n  repeated Label labels = 1;\n\n  // Required.\n  oneof samples {\n    CounterSamples counter_samples = 2;\n    GaugeSamples gauge_samples = 3;\n    RateSamples rate_samples = 4;\n    TrendHdrSamples trend_hdr_samples = 5;\n  }\n}\n\nmessage CounterSamples {\n  // Required.\n  repeated CounterValue values = 1;\n}\n\nmessage GaugeSamples {\n  // Required.\n  repeated GaugeValue values = 1;\n}\n\nmessage RateSamples {\n  // Required.\n  repeated RateValue values = 1;\n}\n\nmessage TrendHdrSamples {\n  // Required.\n  repeated TrendHdrValue values = 1;\n}\n\nmessage CounterValue {\n  // Required.\n  google.protobuf.Timestamp time = 1;\n\n  double value = 2;\n}\n\nmessage GaugeValue {\n  // Required.\n  google.protobuf.Timestamp time = 1;\n\n  // last observed value\n  double last = 2;\n  // count of observations\n  uint32 count = 3;\n  // min, max, and average of observed values\n  double min = 4;\n  double max = 5;\n  double avg = 6;\n}\n\nmessage RateValue {\n  // Required.\n  google.protobuf.Timestamp time = 1;\n\n  uint32 nonzero_count = 2;\n  uint32 total_count = 3;\n}\n\n// BucketSpan represents the consecutive and significant (non-zero) buckets.\n// The concept is imported from the Prometheus' native histogram.\n// It should simplify an eventual transition to Prometheus.\n// https://github.com/prometheus/prometheus/blob/f399f386cef3b19c48157e9678a4f50997db3f41/prompb/io/prometheus/client/metrics.proto#L115-L124\nmessage BucketSpan {\n  uint32 offset = 1; // Gap to previous span, or starting point for 1st span.\n  uint32 length = 2; // Length of the next consecutive buckets.\n}\n\nmessage TrendHdrValue {\n  // Required.\n  google.protobuf.Timestamp time = 1;\n\n  // positive buckets starting from bucket 1, each counter is an absolute value.\n  repeated uint32 counters = 2;\n  repeated BucketSpan spans = 3;\n\n  // sum of observations\n  double sum = 5;\n  // count of observations\n  uint32 count = 6;\n  // smallest and largest observed value\n  double min_value = 7;\n  double max_value = 8;\n\n  // counters for zero- and infinity-buckets\n  optional uint32 extra_low_values_counter = 9;\n  optional uint32 extra_high_values_counter = 10;\n\n  // min_resolution is a multiplier factor applied to the tracked values of the histogram.\n  // It is helpful for up and down scaling values and representing different orders of magnitude.\n  // default = 1.0\n  double min_resolution = 11;\n\n  // histogram parameter - number of significant digits used to calculate buckets formula\n  // default = 2\n  optional uint32 significant_digits = 12;\n}\n"
  },
  {
    "path": "internal/output/cloud/insights/collect.go",
    "content": "package insights\n\nimport (\n\t\"strconv\"\n\t\"sync\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights\"\n\t\"go.k6.io/k6/lib/netext/httpext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst (\n\tmetadataTraceIDKey = \"trace_id\"\n\tscenarioTag        = \"scenario\"\n\tgroupTag           = \"group\"\n\tnameTag            = \"name\"\n\tmethodTag          = \"method\"\n\tstatusTag          = \"status\"\n)\n\n// RequestMetadatasCollector is an interface for collecting request metadatas\n// and retrieving them, so they can be flushed using a flusher.\ntype RequestMetadatasCollector interface {\n\tCollectRequestMetadatas([]metrics.SampleContainer)\n\tPopAll() insights.RequestMetadatas\n}\n\n// Collector is an implementation of RequestMetadatasCollector.\n// Its purpose is to filter and store httpext.Trail samples\n// containing tracing data for later flushing.\ntype Collector struct {\n\ttestRunID int64\n\tbuffer    insights.RequestMetadatas\n\tbufferMu  *sync.Mutex\n}\n\n// NewCollector creates a new Collector.\nfunc NewCollector(testRunID int64) *Collector {\n\treturn &Collector{\n\t\ttestRunID: testRunID,\n\t\tbuffer:    nil,\n\t\tbufferMu:  &sync.Mutex{},\n\t}\n}\n\n// CollectRequestMetadatas filters httpext.Trail samples containing trace ids and stores them as\n// insights.RequestMetadatas in the buffer.\nfunc (c *Collector) CollectRequestMetadatas(sampleContainers []metrics.SampleContainer) {\n\tif len(sampleContainers) < 1 {\n\t\treturn\n\t}\n\n\t// TODO(lukasz, other-proto-support): Support grpc/websocket trails.\n\tvar newBuffer insights.RequestMetadatas\n\tfor _, sampleContainer := range sampleContainers {\n\t\ttrail, ok := sampleContainer.(*httpext.Trail)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\ttraceID, found := trail.Metadata[metadataTraceIDKey]\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tm := insights.RequestMetadata{\n\t\t\tTraceID: traceID,\n\t\t\tStart:   trail.EndTime.Add(-trail.Duration),\n\t\t\tEnd:     trail.EndTime,\n\t\t\tTestRunLabels: insights.TestRunLabels{\n\t\t\t\tID:       c.testRunID,\n\t\t\t\tScenario: c.getStringTagFromTrail(trail, scenarioTag),\n\t\t\t\tGroup:    c.getStringTagFromTrail(trail, groupTag),\n\t\t\t},\n\t\t\tProtocolLabels: insights.ProtocolHTTPLabels{\n\t\t\t\tURL:        c.getStringTagFromTrail(trail, nameTag),\n\t\t\t\tMethod:     c.getStringTagFromTrail(trail, methodTag),\n\t\t\t\tStatusCode: c.getIntTagFromTrail(trail, statusTag),\n\t\t\t},\n\t\t}\n\n\t\tnewBuffer = append(newBuffer, m)\n\t}\n\n\tif len(newBuffer) < 1 {\n\t\treturn\n\t}\n\n\tc.bufferMu.Lock()\n\tdefer c.bufferMu.Unlock()\n\n\tc.buffer = append(c.buffer, newBuffer...)\n}\n\n// PopAll returns all collected insights.RequestMetadatas and clears the buffer.\nfunc (c *Collector) PopAll() insights.RequestMetadatas {\n\tc.bufferMu.Lock()\n\tdefer c.bufferMu.Unlock()\n\n\tb := c.buffer\n\tc.buffer = nil\n\treturn b\n}\n\nfunc (c *Collector) getStringTagFromTrail(trail *httpext.Trail, key string) string {\n\tif tag, found := trail.Tags.Get(key); found {\n\t\treturn tag\n\t}\n\n\treturn \"\"\n}\n\nfunc (c *Collector) getIntTagFromTrail(trail *httpext.Trail, key string) int64 {\n\tif tag, found := trail.Tags.Get(key); found {\n\t\ttagInt, err := strconv.ParseInt(tag, 10, 64)\n\t\tif err != nil {\n\t\t\treturn 0\n\t\t}\n\n\t\treturn tagInt\n\t}\n\n\treturn 0\n}\n"
  },
  {
    "path": "internal/output/cloud/insights/collect_test.go",
    "content": "package insights\n\nimport (\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights\"\n\t\"go.k6.io/k6/lib/netext/httpext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc Test_Collector_CollectRequestMetadatas_DoesNothingWithEmptyData(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\ttestRunID := int64(1337)\n\tcol := NewCollector(testRunID)\n\tvar data []metrics.SampleContainer\n\n\t// When\n\tcol.CollectRequestMetadatas(data)\n\n\t// Then\n\trequire.Empty(t, col.buffer)\n}\n\nfunc Test_Collector_CollectRequestMetadatas_FiltersAndStoresHTTPTrailsAsRequestMetadatas(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\ttestRunID := int64(1337)\n\tcol := NewCollector(testRunID)\n\tdata := []metrics.SampleContainer{\n\t\t&httpext.Trail{\n\t\t\tEndTime:  time.Unix(10, 0),\n\t\t\tDuration: time.Second,\n\t\t\tTags: metrics.NewRegistry().RootTagSet().\n\t\t\t\tWith(scenarioTag, \"test-scenario-1\").\n\t\t\t\tWith(groupTag, \"test-group-1\").\n\t\t\t\tWith(nameTag, \"test-url-1\").\n\t\t\t\tWith(methodTag, \"test-method-1\").\n\t\t\t\tWith(statusTag, \"200\"),\n\t\t\tMetadata: map[string]string{\n\t\t\t\tmetadataTraceIDKey: \"test-trace-id-1\",\n\t\t\t},\n\t\t},\n\t\t&httpext.Trail{\n\t\t\t// HTTP trail without trace ID should be ignored\n\t\t},\n\t\t&httpext.Trail{\n\t\t\tEndTime:  time.Unix(20, 0),\n\t\t\tDuration: time.Second,\n\t\t\tTags: metrics.NewRegistry().RootTagSet().\n\t\t\t\tWith(scenarioTag, \"test-scenario-2\").\n\t\t\t\tWith(groupTag, \"test-group-2\").\n\t\t\t\tWith(nameTag, \"test-url-2\").\n\t\t\t\tWith(methodTag, \"test-method-2\").\n\t\t\t\tWith(statusTag, \"401\"),\n\t\t\tMetadata: map[string]string{\n\t\t\t\tmetadataTraceIDKey: \"test-trace-id-2\",\n\t\t\t},\n\t\t},\n\t\t&httpext.Trail{\n\t\t\tEndTime:  time.Unix(20, 0),\n\t\t\tDuration: time.Second,\n\t\t\tTags:     metrics.NewRegistry().RootTagSet(),\n\t\t\t// HTTP trail without `trace_id` metadata key should be ignored\n\t\t\tMetadata: map[string]string{},\n\t\t},\n\t\t&httpext.Trail{\n\t\t\tEndTime:  time.Unix(20, 0),\n\t\t\tDuration: time.Second,\n\t\t\t// If no tags are present, output should be set to `unknown`\n\t\t\tTags: metrics.NewRegistry().RootTagSet(),\n\t\t\tMetadata: map[string]string{\n\t\t\t\tmetadataTraceIDKey: \"test-trace-id-3\",\n\t\t\t},\n\t\t},\n\t}\n\n\t// When\n\tcol.CollectRequestMetadatas(data)\n\n\t// Then\n\trequire.Len(t, col.buffer, 3)\n\trequire.Contains(t, col.buffer, insights.RequestMetadata{\n\t\tTraceID:        \"test-trace-id-1\",\n\t\tStart:          time.Unix(9, 0),\n\t\tEnd:            time.Unix(10, 0),\n\t\tTestRunLabels:  insights.TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\tProtocolLabels: insights.ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t})\n\trequire.Contains(t, col.buffer, insights.RequestMetadata{\n\t\tTraceID:        \"test-trace-id-2\",\n\t\tStart:          time.Unix(19, 0),\n\t\tEnd:            time.Unix(20, 0),\n\t\tTestRunLabels:  insights.TestRunLabels{ID: 1337, Scenario: \"test-scenario-2\", Group: \"test-group-2\"},\n\t\tProtocolLabels: insights.ProtocolHTTPLabels{URL: \"test-url-2\", Method: \"test-method-2\", StatusCode: 401},\n\t})\n\trequire.Contains(t, col.buffer, insights.RequestMetadata{\n\t\tTraceID:        \"test-trace-id-3\",\n\t\tStart:          time.Unix(19, 0),\n\t\tEnd:            time.Unix(20, 0),\n\t\tTestRunLabels:  insights.TestRunLabels{ID: 1337, Scenario: \"\", Group: \"\"},\n\t\tProtocolLabels: insights.ProtocolHTTPLabels{URL: \"\", Method: \"\", StatusCode: 0},\n\t})\n}\n\nfunc Test_Collector_PopAll_DoesNothingWithEmptyData(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tdata := insights.RequestMetadatas{\n\t\tinsights.RequestMetadata{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(9, 0),\n\t\t\tEnd:            time.Unix(10, 0),\n\t\t\tTestRunLabels:  insights.TestRunLabels{ID: 1337, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: insights.ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t\tinsights.RequestMetadata{\n\t\t\tTraceID:        \"test-trace-id-2\",\n\t\t\tStart:          time.Unix(19, 0),\n\t\t\tEnd:            time.Unix(20, 0),\n\t\t\tTestRunLabels:  insights.TestRunLabels{ID: 1337, Scenario: \"unknown\", Group: \"unknown\"},\n\t\t\tProtocolLabels: insights.ProtocolHTTPLabels{URL: \"unknown\", Method: \"unknown\", StatusCode: 0},\n\t\t},\n\t}\n\tcol := &Collector{\n\t\tbuffer:   data,\n\t\tbufferMu: &sync.Mutex{},\n\t}\n\n\t// When\n\tgot := col.PopAll()\n\n\t// Then\n\trequire.Nil(t, col.buffer)\n\trequire.Empty(t, col.buffer)\n\trequire.Equal(t, data, got)\n}\n"
  },
  {
    "path": "internal/output/cloud/insights/doc.go",
    "content": "// Package insights contains the logic for the k6 cloud insights output.\npackage insights\n"
  },
  {
    "path": "internal/output/cloud/insights/enable.go",
    "content": "package insights\n\nimport (\n\t\"go.k6.io/k6/cloudapi\"\n)\n\n// Enabled returns true if the k6 x Tempo feature is enabled.\nfunc Enabled(config cloudapi.Config) bool {\n\t// TODO(lukasz): Check if k6 x Tempo is enabled\n\t//\n\t// We want to check whether a given organization is\n\t// eligible for k6 x Tempo feature. If it isn't, we may\n\t// consider to skip the traces output.\n\t//\n\t// We currently don't have a backend API to check this\n\t// information.\n\treturn config.TracesEnabled.Bool\n}\n"
  },
  {
    "path": "internal/output/cloud/insights/flush.go",
    "content": "package insights\n\nimport (\n\t\"context\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights\"\n)\n\n// Client is an interface for sending request metadatas to the Insights API.\ntype Client interface {\n\tIngestRequestMetadatasBatch(context.Context, insights.RequestMetadatas) error\n\tClose() error\n}\n\n// RequestMetadatasFlusher is an interface for flushing data to the cloud.\ntype RequestMetadatasFlusher interface {\n\tFlush() error\n}\n\n// Flusher is an implementation of RequestMetadatasFlusher.\n// Its purpose is to retrieve data from a collector\n// and send it to the insights backend.\ntype Flusher struct {\n\tclient    Client\n\tcollector RequestMetadatasCollector\n}\n\n// NewFlusher creates a new Flusher.\nfunc NewFlusher(client Client, collector RequestMetadatasCollector) *Flusher {\n\treturn &Flusher{\n\t\tclient:    client,\n\t\tcollector: collector,\n\t}\n}\n\n// Flush retrieves data from the collector and sends it to the insights backend.\nfunc (f *Flusher) Flush() error {\n\trequestMetadatas := f.collector.PopAll()\n\tif len(requestMetadatas) < 1 {\n\t\treturn nil\n\t}\n\n\treturn f.client.IngestRequestMetadatasBatch(context.Background(), requestMetadatas)\n}\n"
  },
  {
    "path": "internal/output/cloud/insights/flush_test.go",
    "content": "package insights\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/cloudapi/insights\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype mockWorkingInsightsClient struct {\n\tingestRequestMetadatasBatchInvoked bool\n\tdataSent                           bool\n\tdata                               insights.RequestMetadatas\n}\n\nfunc (c *mockWorkingInsightsClient) IngestRequestMetadatasBatch(ctx context.Context, data insights.RequestMetadatas) error {\n\tc.ingestRequestMetadatasBatchInvoked = true\n\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tdefault:\n\t}\n\n\tc.dataSent = true\n\tc.data = data\n\n\treturn nil\n}\n\nfunc (c *mockWorkingInsightsClient) Close() error {\n\treturn nil\n}\n\ntype mockFailingInsightsClient struct {\n\terr error\n}\n\nfunc (c *mockFailingInsightsClient) IngestRequestMetadatasBatch(_ context.Context, _ insights.RequestMetadatas) error {\n\treturn c.err\n}\n\nfunc (c *mockFailingInsightsClient) Close() error {\n\treturn nil\n}\n\ntype mockRequestMetadatasCollector struct {\n\tdata insights.RequestMetadatas\n}\n\nfunc (m *mockRequestMetadatasCollector) CollectRequestMetadatas(_ []metrics.SampleContainer) {\n\tpanic(\"implement me\")\n}\n\nfunc (m *mockRequestMetadatasCollector) PopAll() insights.RequestMetadatas {\n\treturn m.data\n}\n\nfunc newMockRequestMetadatas() insights.RequestMetadatas {\n\treturn insights.RequestMetadatas{\n\t\tinsights.RequestMetadata{\n\t\t\tTraceID:        \"test-trace-id-1\",\n\t\t\tStart:          time.Unix(1337, 0),\n\t\t\tEnd:            time.Unix(1338, 0),\n\t\t\tTestRunLabels:  insights.TestRunLabels{ID: 1, Scenario: \"test-scenario-1\", Group: \"test-group-1\"},\n\t\t\tProtocolLabels: insights.ProtocolHTTPLabels{URL: \"test-url-1\", Method: \"test-method-1\", StatusCode: 200},\n\t\t},\n\t\tinsights.RequestMetadata{\n\t\t\tTraceID:        \"test-trace-id-2\",\n\t\t\tStart:          time.Unix(2337, 0),\n\t\t\tEnd:            time.Unix(2338, 0),\n\t\t\tTestRunLabels:  insights.TestRunLabels{ID: 1, Scenario: \"test-scenario-2\", Group: \"test-group-2\"},\n\t\t\tProtocolLabels: insights.ProtocolHTTPLabels{URL: \"test-url-2\", Method: \"test-method-2\", StatusCode: 200},\n\t\t},\n\t}\n}\n\nfunc Test_tracesFlusher_Flush_ReturnsNoErrorWithWorkingInsightsClientAndNonCancelledContextAndNoData(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tdata := insights.RequestMetadatas{}\n\tcli := &mockWorkingInsightsClient{}\n\tcol := &mockRequestMetadatasCollector{data: data}\n\tflusher := NewFlusher(cli, col)\n\n\t// When\n\terr := flusher.Flush()\n\n\t// Then\n\trequire.NoError(t, err)\n\trequire.False(t, cli.ingestRequestMetadatasBatchInvoked)\n\trequire.False(t, cli.dataSent)\n\trequire.Empty(t, cli.data)\n}\n\nfunc Test_tracesFlusher_Flush_ReturnsNoErrorWithWorkingInsightsClientAndNonCancelledContextAndData(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tdata := newMockRequestMetadatas()\n\tcli := &mockWorkingInsightsClient{}\n\tcol := &mockRequestMetadatasCollector{data: data}\n\tflusher := NewFlusher(cli, col)\n\n\t// When\n\terr := flusher.Flush()\n\n\t// Then\n\trequire.NoError(t, err)\n\trequire.True(t, cli.ingestRequestMetadatasBatchInvoked)\n\trequire.True(t, cli.dataSent)\n\trequire.Equal(t, data, cli.data)\n}\n\nfunc Test_tracesFlusher_Flush_ReturnsErrorWithFailingInsightsClientAndNonCancelledContext(t *testing.T) {\n\tt.Parallel()\n\n\t// Given\n\tdata := newMockRequestMetadatas()\n\ttestErr := errors.New(\"test-error\")\n\tcli := &mockFailingInsightsClient{err: testErr}\n\tcol := &mockRequestMetadatasCollector{data: data}\n\tflusher := NewFlusher(cli, col)\n\n\t// When\n\terr := flusher.Flush()\n\n\t// Then\n\trequire.ErrorIs(t, err, testErr)\n}\n"
  },
  {
    "path": "internal/output/cloud/output.go",
    "content": "// Package cloud implements an Output that flushes to the k6 Cloud platform.\npackage cloud\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n\tcloudv2 \"go.k6.io/k6/output/cloud/expv2\"\n)\n\nconst (\n\tdefaultTestName = \"k6 test\"\n\ttestRunIDKey    = \"K6_CLOUDRUN_TEST_RUN_ID\"\n)\n\n// versionedOutput represents an output implementing\n// metrics samples aggregation and flushing to the\n// Cloud remote service.\n//\n// It mainly differs from output.Output\n// because it does not define Stop (that is deprecated)\n// and Description.\ntype versionedOutput interface {\n\tStart() error\n\tStopWithTestError(testRunErr error) error\n\n\tSetTestRunStopCallback(func(error))\n\tSetTestRunID(id string)\n\n\tAddMetricSamples(samples []metrics.SampleContainer)\n}\n\ntype apiVersion int64\n\nconst (\n\tapiVersionUndefined apiVersion = iota\n\tapiVersion1                    // disabled\n\tapiVersion2\n)\n\n// Output sends result data to the k6 Cloud service.\ntype Output struct {\n\tversionedOutput\n\n\tlogger    logrus.FieldLogger\n\tconfig    cloudapi.Config\n\ttestRunID string\n\n\texecutionPlan []lib.ExecutionStep\n\tduration      int64 // in seconds\n\tthresholds    map[string][]*metrics.Threshold\n\n\t// testArchive is the test archive to be uploaded to the cloud\n\t// before the output is Start()-ed.\n\t//\n\t// It is set by the SetArchive method. If it is nil, the output\n\t// will not upload any test archive, such as when the user\n\t// uses the --no-archive-upload flag.\n\ttestArchive *lib.Archive\n\n\tclient       *cloudapi.Client\n\ttestStopFunc func(error)\n\n\tusage *usage.Usage\n}\n\n// Verify that Output implements the wanted interfaces\nvar _ interface {\n\toutput.WithStopWithTestError\n\toutput.WithThresholds\n\toutput.WithTestRunStop\n} = &Output{}\n\n// New creates a new cloud output.\nfunc New(params output.Params) (output.Output, error) {\n\treturn newOutput(params)\n}\n\n// New creates a new cloud output.\nfunc newOutput(params output.Params) (*Output, error) {\n\tconf, warn, err := cloudapi.GetConsolidatedConfig(\n\t\tparams.JSONConfig,\n\t\tparams.Environment,\n\t\tparams.ConfigArgument,\n\t\tparams.ScriptOptions.Cloud,\n\t\tparams.ScriptOptions.External,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif warn != \"\" {\n\t\tparams.Logger.Warn(warn)\n\t}\n\n\tif err := validateRequiredSystemTags(params.ScriptOptions.SystemTags); err != nil {\n\t\treturn nil, err\n\t}\n\n\tlogger := params.Logger.WithFields(logrus.Fields{\"output\": \"cloud\"})\n\n\tif !conf.Name.Valid || conf.Name.String == \"\" {\n\t\tscriptPath := params.ScriptPath.String()\n\t\tif scriptPath == \"\" {\n\t\t\t// Script from stdin without a name, likely from stdin\n\t\t\treturn nil, errors.New(\"script name not set, please specify K6_CLOUD_NAME or options.cloud.name\")\n\t\t}\n\n\t\tconf.Name = null.StringFrom(filepath.Base(scriptPath))\n\t}\n\tif conf.Name.String == \"-\" {\n\t\tconf.Name = null.StringFrom(defaultTestName)\n\t}\n\n\tduration, testEnds := lib.GetEndOffset(params.ExecutionPlan)\n\tif !testEnds {\n\t\treturn nil, errors.New(\"tests with unspecified duration are not allowed when outputting data to k6 cloud\")\n\t}\n\n\tif conf.MetricPushConcurrency.Int64 < 1 {\n\t\treturn nil, fmt.Errorf(\"metrics push concurrency must be a positive number but is %d\",\n\t\t\tconf.MetricPushConcurrency.Int64)\n\t}\n\n\tif conf.MaxTimeSeriesInBatch.Int64 < 1 {\n\t\treturn nil, fmt.Errorf(\"max allowed number of time series in a single batch must be a positive number but is %d\",\n\t\t\tconf.MaxTimeSeriesInBatch.Int64)\n\t}\n\n\tapiClient := cloudapi.NewClient(\n\t\tlogger, conf.Token.String, conf.Host.String, build.Version, conf.Timeout.TimeDuration())\n\n\treturn &Output{\n\t\tconfig:        conf,\n\t\tclient:        apiClient,\n\t\texecutionPlan: params.ExecutionPlan,\n\t\tduration:      int64(duration / time.Second),\n\t\tlogger:        logger,\n\t\tusage:         params.Usage,\n\t\ttestRunID:     params.RuntimeOptions.Env[testRunIDKey],\n\t}, nil\n}\n\n// validateRequiredSystemTags checks if all required tags are present.\nfunc validateRequiredSystemTags(scriptTags *metrics.SystemTagSet) error {\n\tmissingRequiredTags := []string{}\n\trequiredTags := metrics.SystemTagSet(metrics.TagName |\n\t\tmetrics.TagMethod |\n\t\tmetrics.TagStatus |\n\t\tmetrics.TagError |\n\t\tmetrics.TagCheck |\n\t\tmetrics.TagGroup)\n\tfor _, tag := range metrics.SystemTagValues() {\n\t\tif requiredTags.Has(tag) && !scriptTags.Has(tag) {\n\t\t\tmissingRequiredTags = append(missingRequiredTags, tag.String())\n\t\t}\n\t}\n\tif len(missingRequiredTags) > 0 {\n\t\treturn fmt.Errorf(\n\t\t\t\"the cloud output needs the following system tags enabled: %s\",\n\t\t\tstrings.Join(missingRequiredTags, \", \"),\n\t\t)\n\t}\n\treturn nil\n}\n\n// Start calls the k6 Cloud API to initialize the test run, and then starts the\n// goroutine that would listen for metric samples and send them to the cloud.\nfunc (out *Output) Start() error {\n\tif out.config.PushRefID.Valid {\n\t\tout.testRunID = out.config.PushRefID.String\n\t}\n\n\tif out.testRunID != \"\" {\n\t\tout.logger.WithField(\"testRunId\", out.testRunID).Debug(\"Directly pushing metrics without init\")\n\t\treturn out.startVersionedOutput()\n\t}\n\n\tthresholds := make(map[string][]string)\n\tfor name, t := range out.thresholds {\n\t\tfor _, threshold := range t {\n\t\t\tthresholds[name] = append(thresholds[name], threshold.Source)\n\t\t}\n\t}\n\n\ttestRun := &cloudapi.TestRun{\n\t\tName:       out.config.Name.String,\n\t\tProjectID:  out.config.ProjectID.Int64,\n\t\tVUsMax:     int64(lib.GetMaxPossibleVUs(out.executionPlan)), //nolint:gosec\n\t\tThresholds: thresholds,\n\t\tDuration:   out.duration,\n\t\tArchive:    out.testArchive,\n\t}\n\n\tresponse, err := out.client.CreateTestRun(testRun)\n\tif err != nil {\n\t\treturn err\n\t}\n\tout.testRunID = response.ReferenceID\n\n\tif response.ConfigOverride != nil {\n\t\tout.logger.WithFields(logrus.Fields{\n\t\t\t\"override\": response.ConfigOverride,\n\t\t}).Debug(\"overriding config options\")\n\t\tout.config = out.config.Apply(*response.ConfigOverride)\n\t}\n\n\terr = out.startVersionedOutput()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"the Gateway Output failed to start a versioned output: %w\", err)\n\t}\n\n\tout.logger.WithFields(logrus.Fields{\n\t\t\"name\":      out.config.Name,\n\t\t\"projectId\": out.config.ProjectID,\n\t\t\"duration\":  out.duration,\n\t\t\"testRunId\": out.testRunID,\n\t}).Debug(\"Started!\")\n\treturn nil\n}\n\n// Description returns the URL with the test run results.\nfunc (out *Output) Description() string {\n\treturn fmt.Sprintf(\"cloud (%s)\", cloudapi.URLForResults(out.testRunID, out.config))\n}\n\n// SetThresholds receives the thresholds before the output is Start()-ed.\nfunc (out *Output) SetThresholds(scriptThresholds map[string]metrics.Thresholds) {\n\tthresholds := make(map[string][]*metrics.Threshold)\n\tfor name, t := range scriptThresholds {\n\t\tthresholds[name] = append(thresholds[name], t.Thresholds...)\n\t}\n\tout.thresholds = thresholds\n}\n\n// SetTestRunStopCallback receives the function that stops the engine on error\nfunc (out *Output) SetTestRunStopCallback(stopFunc func(error)) {\n\tout.testStopFunc = stopFunc\n}\n\n// SetArchive receives the test artifact to be uploaded to the cloud\n// before the output is Start()-ed.\nfunc (out *Output) SetArchive(archive *lib.Archive) {\n\tout.testArchive = archive\n}\n\nvar _ output.WithArchive = &Output{}\n\n// Stop gracefully stops all metric emission from the output: when all metric\n// samples are emitted, it makes a cloud API call to finish the test run.\n//\n// Deprecated: use StopWithTestError() instead.\nfunc (out *Output) Stop() error {\n\treturn out.StopWithTestError(nil)\n}\n\n// StopWithTestError gracefully stops all metric emission from the output: when\n// all metric samples are emitted, it makes a cloud API call to finish the test\n// run. If testErr was specified, it extracts the RunStatus from it.\nfunc (out *Output) StopWithTestError(testErr error) error {\n\terr := out.versionedOutput.StopWithTestError(testErr)\n\tif err != nil {\n\t\tout.logger.WithError(err).Error(\"An error occurred stopping the output\")\n\t\t// to notify the cloud backend we have no return here\n\t}\n\n\tout.logger.Debug(\"Metric emission stopped, calling cloud API...\")\n\terr = out.testFinished(testErr)\n\tif err != nil {\n\t\tout.logger.WithFields(logrus.Fields{\"error\": err}).Warn(\"Failed to send test finished to the cloud\")\n\t\treturn err\n\t}\n\tout.logger.Debug(\"Cloud output successfully stopped!\")\n\treturn nil\n}\n\nfunc (out *Output) testFinished(testErr error) error {\n\tif out.testRunID == \"\" || out.config.PushRefID.Valid {\n\t\treturn nil\n\t}\n\n\ttestTainted := false\n\tthresholdResults := make(cloudapi.ThresholdResult)\n\tfor name, thresholds := range out.thresholds {\n\t\tthresholdResults[name] = make(map[string]bool)\n\t\tfor _, t := range thresholds {\n\t\t\tthresholdResults[name][t.Source] = t.LastFailed\n\t\t\tif t.LastFailed {\n\t\t\t\ttestTainted = true\n\t\t\t}\n\t\t}\n\t}\n\n\trunStatus := out.getRunStatus(testErr)\n\tout.logger.WithFields(logrus.Fields{\n\t\t\"ref\":        out.testRunID,\n\t\t\"tainted\":    testTainted,\n\t\t\"run_status\": runStatus,\n\t}).Debug(\"Sending test finished\")\n\n\treturn out.client.TestFinished(out.testRunID, thresholdResults, testTainted, runStatus)\n}\n\n// getRunStatus determines the run status of the test based on the error.\nfunc (out *Output) getRunStatus(testErr error) cloudapi.RunStatus {\n\tif testErr == nil {\n\t\treturn cloudapi.RunStatusFinished\n\t}\n\n\tvar err errext.HasAbortReason\n\tif errors.As(testErr, &err) {\n\t\tabortReason := err.AbortReason()\n\t\tswitch abortReason {\n\t\tcase errext.AbortedByUser:\n\t\t\treturn cloudapi.RunStatusAbortedUser\n\t\tcase errext.AbortedByThreshold:\n\t\t\treturn cloudapi.RunStatusAbortedThreshold\n\t\tcase errext.AbortedByScriptError:\n\t\t\treturn cloudapi.RunStatusAbortedScriptError\n\t\tcase errext.AbortedByScriptAbort:\n\t\t\treturn cloudapi.RunStatusAbortedUser // TODO: have a better value than this?\n\t\tcase errext.AbortedByTimeout:\n\t\t\treturn cloudapi.RunStatusAbortedLimit\n\t\tcase errext.AbortedByOutput:\n\t\t\treturn cloudapi.RunStatusAbortedSystem\n\t\tcase errext.AbortedByThresholdsAfterTestEnd:\n\t\t\t// The test run finished normally, it wasn't prematurely aborted by\n\t\t\t// anything while running, but the thresholds failed at the end and\n\t\t\t// k6 will return an error and a non-zero exit code to the user.\n\t\t\t//\n\t\t\t// However, failures are tracked somewhat differently by the k6\n\t\t\t// cloud compared to k6 OSS. It doesn't have a single pass/fail\n\t\t\t// variable with multiple failure states, like k6's exit codes.\n\t\t\t// Instead, it has two variables, result_status and run_status.\n\t\t\t//\n\t\t\t// The status of the thresholds is tracked by the binary\n\t\t\t// result_status variable, which signifies whether the thresholds\n\t\t\t// passed or failed (failure also called \"tainted\" in some places of\n\t\t\t// the API here). The run_status signifies whether the test run\n\t\t\t// finished normally and has a few fixed failures values.\n\t\t\t//\n\t\t\t// So, this specific k6 error will be communicated to the cloud only\n\t\t\t// via result_status, while the run_status will appear normal.\n\t\t\treturn cloudapi.RunStatusFinished\n\t\t}\n\t}\n\n\t// By default, the catch-all error is \"aborted by system\", but let's log that\n\tout.logger.WithError(testErr).Debug(\"unknown test error classified as 'aborted by system'\")\n\treturn cloudapi.RunStatusAbortedSystem\n}\n\nfunc (out *Output) startVersionedOutput() error {\n\tif out.testRunID == \"\" {\n\t\treturn errors.New(\"TestRunID is required\")\n\t}\n\tvar err error\n\n\tusageErr := out.usage.Strings(\"cloud/test_run_id\", out.testRunID)\n\tif usageErr != nil {\n\t\tout.logger.Warning(\"Couldn't report test run id to usage as part of writing to k6 cloud\")\n\t}\n\n\t// TODO: move here the creation of a new cloudapi.Client\n\t// so in the case the config has been overwritten the client uses the correct\n\t// value.\n\t//\n\t// This logic is handled individually by each single output, it has the downside\n\t// that we could break the logic and not catch easly it.\n\n\tswitch out.config.APIVersion.Int64 {\n\tcase int64(apiVersion1):\n\t\terr = errors.New(\"v1 is not supported anymore\")\n\tcase int64(apiVersion2):\n\t\tout.versionedOutput, err = cloudv2.New(out.logger, out.config, out.client)\n\tdefault:\n\t\terr = fmt.Errorf(\"v%d is an unexpected version\", out.config.APIVersion.Int64)\n\t}\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tout.SetTestRunID(out.testRunID)\n\tout.versionedOutput.SetTestRunStopCallback(out.testStopFunc)\n\treturn out.versionedOutput.Start()\n}\n"
  },
  {
    "path": "internal/output/cloud/output_test.go",
    "content": "package cloud\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n\tcloudv2 \"go.k6.io/k6/output/cloud/expv2\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestNewOutputNameResolution(t *testing.T) {\n\tt.Parallel()\n\tmustParse := func(u string) *url.URL {\n\t\tresult, err := url.Parse(u)\n\t\trequire.NoError(t, err)\n\t\treturn result\n\t}\n\n\tcases := []struct {\n\t\turl      *url.URL\n\t\texpected string\n\t}{\n\t\t{\n\t\t\turl: &url.URL{\n\t\t\t\tOpaque: \"go.k6.io/k6/samples/http_get.js\",\n\t\t\t},\n\t\t\texpected: \"http_get.js\",\n\t\t},\n\t\t{\n\t\t\turl:      mustParse(\"http://go.k6.io/k6/samples/http_get.js\"),\n\t\t\texpected: \"http_get.js\",\n\t\t},\n\t\t{\n\t\t\turl:      mustParse(\"file://home/user/k6/samples/http_get.js\"),\n\t\t\texpected: \"http_get.js\",\n\t\t},\n\t\t{\n\t\t\turl:      mustParse(\"file://C:/home/user/k6/samples/http_get.js\"),\n\t\t\texpected: \"http_get.js\",\n\t\t},\n\t}\n\n\tfor _, testCase := range cases {\n\t\tt.Run(testCase.url.String(), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tout, err := newOutput(output.Params{\n\t\t\t\tLogger: testutils.NewLogger(t),\n\t\t\t\tScriptOptions: lib.Options{\n\t\t\t\t\tDuration:   types.NullDurationFrom(1 * time.Second),\n\t\t\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t\t\t},\n\t\t\t\tScriptPath: testCase.url,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, testCase.expected, out.config.Name.String)\n\t\t})\n\t}\n}\n\nfunc TestCloudOutputRequireScriptName(t *testing.T) {\n\tt.Parallel()\n\t_, err := New(output.Params{\n\t\tLogger: testutils.NewLogger(t),\n\t\tScriptOptions: lib.Options{\n\t\t\tDuration:   types.NullDurationFrom(1 * time.Second),\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tScriptPath: &url.URL{Path: \"\"},\n\t})\n\trequire.Error(t, err)\n\tassert.Contains(t, err.Error(), \"script name not set\")\n}\n\nfunc TestOutputCreateTestWithConfigOverwrite(t *testing.T) {\n\tt.Parallel()\n\n\thandler := func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/v1/tests\":\n\t\t\t_, err := fmt.Fprintf(w, `{\n\"reference_id\": \"12345\",\n\"config\": {\n\t\"metricPushInterval\": \"10ms\",\n\t\"aggregationPeriod\": \"40s\"\n}\n}`)\n\t\t\trequire.NoError(t, err)\n\t\tcase \"/v1/tests/12345\":\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\tdefault:\n\t\t\thttp.Error(w, \"not expected path\", http.StatusInternalServerError)\n\t\t}\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(handler))\n\tdefer ts.Close()\n\n\tout, err := newOutput(output.Params{\n\t\tLogger: testutils.NewLogger(t),\n\t\tEnvironment: map[string]string{\n\t\t\t\"K6_CLOUD_HOST\":               ts.URL,\n\t\t\t\"K6_CLOUD_AGGREGATION_PERIOD\": \"30s\",\n\t\t},\n\t\tScriptOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tScriptPath: &url.URL{Path: \"/script.js\"},\n\t\tUsage:      usage.New(),\n\t})\n\trequire.NoError(t, err)\n\trequire.NoError(t, out.Start())\n\n\tassert.Equal(t, types.NullDurationFrom(10*time.Millisecond), out.config.MetricPushInterval)\n\tassert.Equal(t, types.NullDurationFrom(40*time.Second), out.config.AggregationPeriod)\n\n\t// Assert that it overwrites only the provided values\n\texpTimeout := types.NewNullDuration(60*time.Second, false)\n\tassert.Equal(t, expTimeout, out.config.Timeout)\n\n\trequire.NoError(t, out.StopWithTestError(nil))\n}\n\nfunc TestOutputStartVersionError(t *testing.T) {\n\tt.Parallel()\n\to, err := newOutput(output.Params{\n\t\tLogger: testutils.NewLogger(t),\n\t\tScriptOptions: lib.Options{\n\t\t\tDuration:   types.NullDurationFrom(1 * time.Second),\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tEnvironment: map[string]string{\n\t\t\t\"K6_CLOUD_API_VERSION\": \"99\",\n\t\t},\n\t\tScriptPath: &url.URL{Path: \"/script.js\"},\n\t\tUsage:      usage.New(),\n\t})\n\trequire.NoError(t, err)\n\n\to.testRunID = \"123\"\n\terr = o.startVersionedOutput()\n\trequire.ErrorContains(t, err, \"v99 is an unexpected version\")\n}\n\nfunc TestOutputStartVersionedOutputV2(t *testing.T) {\n\tt.Parallel()\n\n\to := Output{\n\t\tlogger:    testutils.NewLogger(t),\n\t\ttestRunID: \"123\",\n\t\tconfig: cloudapi.Config{\n\t\t\tAPIVersion:            null.IntFrom(2),\n\t\t\tHost:                  null.StringFrom(\"fake-cloud-url\"),\n\t\t\tToken:                 null.StringFrom(\"fake-token\"),\n\t\t\tAggregationWaitPeriod: types.NullDurationFrom(1 * time.Second),\n\t\t\t// Here, we are enabling it but silencing the related async ops\n\t\t\tAggregationPeriod:  types.NullDurationFrom(1 * time.Hour),\n\t\t\tMetricPushInterval: types.NullDurationFrom(1 * time.Hour),\n\t\t},\n\t\tusage: usage.New(),\n\t}\n\n\to.client = cloudapi.NewClient(\n\t\tnil, o.config.Token.String, o.config.Host.String, \"v/tests\", o.config.Timeout.TimeDuration())\n\n\terr := o.startVersionedOutput()\n\trequire.NoError(t, err)\n\n\t_, ok := o.versionedOutput.(*cloudv2.Output)\n\tassert.True(t, ok)\n}\n\nfunc TestOutputStartVersionedOutputV1Error(t *testing.T) {\n\tt.Parallel()\n\n\to := Output{\n\t\ttestRunID: \"123\",\n\t\tconfig: cloudapi.Config{\n\t\t\tAPIVersion: null.IntFrom(1),\n\t\t},\n\t\tusage: usage.New(),\n\t}\n\n\terr := o.startVersionedOutput()\n\tassert.ErrorContains(t, err, \"not supported anymore\")\n}\n\nfunc TestOutputStartWithTestRunID(t *testing.T) {\n\tt.Parallel()\n\n\thandler := func(_ http.ResponseWriter, _ *http.Request) {\n\t\t// no calls are expected to the cloud service when\n\t\t// the reference ID is passed\n\t\tt.Error(\"got unexpected call\")\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(handler))\n\tdefer ts.Close()\n\n\tout, err := newOutput(output.Params{\n\t\tLogger: testutils.NewLogger(t),\n\t\tEnvironment: map[string]string{\n\t\t\t\"K6_CLOUD_HOST\":        ts.URL,\n\t\t\t\"K6_CLOUD_PUSH_REF_ID\": \"12345\",\n\t\t},\n\t\tScriptOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tScriptPath: &url.URL{Path: \"/script.js\"},\n\t\tUsage:      usage.New(),\n\t})\n\trequire.NoError(t, err)\n\trequire.NoError(t, out.Start())\n\trequire.NoError(t, out.Stop())\n}\n\nfunc TestCloudOutputDescription(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"WithTestRunDetails\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\to := Output{testRunID: \"74\"}\n\t\to.config.TestRunDetails = null.StringFrom(\"my-custom-string\")\n\t\tassert.Equal(t, \"cloud (my-custom-string)\", o.Description())\n\t})\n\tt.Run(\"WithWebAppURL\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\to := Output{testRunID: \"74\"}\n\t\to.config.WebAppURL = null.StringFrom(\"mywebappurl.com\")\n\t\tassert.Equal(t, \"cloud (mywebappurl.com/runs/74)\", o.Description())\n\t})\n}\n\nfunc TestOutputStopWithTestError(t *testing.T) {\n\tt.Parallel()\n\n\tdone := make(chan struct{})\n\n\thandler := func(w http.ResponseWriter, r *http.Request) {\n\t\tswitch r.URL.Path {\n\t\tcase \"/v1/tests/1234\":\n\t\t\tb, err := io.ReadAll(r.Body)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t// aborted by system status\n\t\t\texpB := `{\"result_status\":0, \"run_status\":6, \"thresholds\":{}}`\n\t\t\trequire.JSONEq(t, expB, string(b))\n\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\tclose(done)\n\t\tdefault:\n\t\t\thttp.Error(w, \"not expected path\", http.StatusInternalServerError)\n\t\t}\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(handler))\n\tdefer ts.Close()\n\n\tout, err := newOutput(output.Params{\n\t\tLogger: testutils.NewLogger(t),\n\t\tEnvironment: map[string]string{\n\t\t\t\"K6_CLOUD_HOST\": ts.URL,\n\t\t},\n\t\tScriptOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tScriptPath: &url.URL{Path: \"/script.js\"},\n\t})\n\trequire.NoError(t, err)\n\n\tcalledStopFn := false\n\tout.testRunID = \"1234\"\n\tout.versionedOutput = versionedOutputMock{\n\t\tcallback: func(fn string) {\n\t\t\tif fn == \"StopWithTestError\" {\n\t\t\t\tcalledStopFn = true\n\t\t\t}\n\t\t},\n\t}\n\n\tfakeErr := errors.New(\"this is my error\")\n\trequire.NoError(t, out.StopWithTestError(fakeErr))\n\tassert.True(t, calledStopFn)\n\n\tselect {\n\tcase <-time.After(1 * time.Second):\n\t\tt.Error(\"timed out\")\n\tcase <-done:\n\t}\n}\n\nfunc TestOutputGetStatusRun(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Success\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\to := Output{}\n\t\tassert.Equal(t, cloudapi.RunStatusFinished, o.getRunStatus(nil))\n\t})\n\tt.Run(\"WithErrorNoAbortReason\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\to := Output{logger: testutils.NewLogger(t)}\n\t\tassert.Equal(t, cloudapi.RunStatusAbortedSystem, o.getRunStatus(errors.New(\"my-error\")))\n\t})\n\tt.Run(\"WithAbortReason\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\to := Output{}\n\t\terrWithReason := errext.WithAbortReasonIfNone(\n\t\t\terrors.New(\"my-original-error\"),\n\t\t\terrext.AbortedByOutput,\n\t\t)\n\t\tassert.Equal(t, cloudapi.RunStatusAbortedSystem, o.getRunStatus(errWithReason))\n\t})\n}\n\nfunc TestOutputProxyAddMetricSamples(t *testing.T) {\n\tt.Parallel()\n\n\tcalled := false\n\to := &Output{\n\t\tversionedOutput: versionedOutputMock{\n\t\t\tcallback: func(fn string) {\n\t\t\t\tif fn != \"AddMetricSamples\" {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tcalled = true\n\t\t\t},\n\t\t},\n\t}\n\to.AddMetricSamples([]metrics.SampleContainer{})\n\tassert.True(t, called)\n}\n\ntype versionedOutputMock struct {\n\tcallback func(name string)\n}\n\nfunc (o versionedOutputMock) Start() error {\n\to.callback(\"Start\")\n\treturn nil\n}\n\nfunc (o versionedOutputMock) StopWithTestError(_ error) error {\n\to.callback(\"StopWithTestError\")\n\treturn nil\n}\n\nfunc (o versionedOutputMock) SetTestRunStopCallback(_ func(error)) {\n\to.callback(\"SetTestRunStopCallback\")\n}\n\nfunc (o versionedOutputMock) SetTestRunID(_ string) {\n\to.callback(\"SetTestRunID\")\n}\n\nfunc (o versionedOutputMock) AddMetricSamples(_ []metrics.SampleContainer) {\n\to.callback(\"AddMetricSamples\")\n}\n"
  },
  {
    "path": "internal/output/csv/config.go",
    "content": "package csv\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"github.com/mstoykov/envconfig\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// Config is the config for the csv output\ntype Config struct {\n\t// Samples.\n\tFileName     null.String        `json:\"file_name\" envconfig:\"K6_CSV_FILENAME\"`\n\tSaveInterval types.NullDuration `json:\"save_interval\" envconfig:\"K6_CSV_SAVE_INTERVAL\"`\n\tTimeFormat   null.String        `json:\"time_format\" envconfig:\"K6_CSV_TIME_FORMAT\"`\n}\n\n// TimeFormat custom enum type\n//\n//go:generate go run github.com/dmarkham/enumer@v1.5.11 -type=TimeFormat -transform=snake -trimprefix TimeFormat -output time_format_gen.go\ntype TimeFormat uint8\n\n// valid defined values for TimeFormat\nconst (\n\tTimeFormatUnix TimeFormat = iota\n\tTimeFormatUnixMilli\n\tTimeFormatUnixMicro\n\tTimeFormatUnixNano\n\tTimeFormatRFC3339\n\tTimeFormatRFC3339Nano\n)\n\n// NewConfig creates a new Config instance with default values for some fields.\nfunc NewConfig() Config {\n\treturn Config{\n\t\tFileName:     null.NewString(\"file.csv\", false),\n\t\tSaveInterval: types.NewNullDuration(1*time.Second, false),\n\t\tTimeFormat:   null.NewString(\"unix\", false),\n\t}\n}\n\n// Apply merges two configs by overwriting properties in the old config\nfunc (c Config) Apply(cfg Config) Config {\n\tif cfg.FileName.Valid {\n\t\tc.FileName = cfg.FileName\n\t}\n\tif cfg.SaveInterval.Valid {\n\t\tc.SaveInterval = cfg.SaveInterval\n\t}\n\tif cfg.TimeFormat.Valid {\n\t\tc.TimeFormat = cfg.TimeFormat\n\t}\n\treturn c\n}\n\n// ParseArg takes an arg string and converts it to a config\nfunc ParseArg(arg string) (Config, error) {\n\tc := NewConfig()\n\n\tif !strings.Contains(arg, \"=\") {\n\t\tc.FileName = null.StringFrom(arg)\n\t\treturn c, nil\n\t}\n\n\tpairs := strings.SplitSeq(arg, \",\")\n\tfor pair := range pairs {\n\t\tk, v, _ := strings.Cut(pair, \"=\")\n\t\tif v == \"\" {\n\t\t\treturn c, fmt.Errorf(\"couldn't parse %q as argument for csv output\", arg)\n\t\t}\n\t\tswitch k {\n\t\tcase \"saveInterval\":\n\t\t\terr := c.SaveInterval.UnmarshalText([]byte(v))\n\t\t\tif err != nil {\n\t\t\t\treturn c, err\n\t\t\t}\n\t\tcase \"fileName\":\n\t\t\tc.FileName = null.StringFrom(v)\n\t\tcase \"timeFormat\":\n\t\t\tc.TimeFormat = null.StringFrom(v)\n\t\tdefault:\n\t\t\treturn c, fmt.Errorf(\"unknown key %q as argument for csv output\", k)\n\t\t}\n\t}\n\n\treturn c, nil\n}\n\n// GetConsolidatedConfig combines {default config values + JSON config +\n// environment vars + arg config values}, and returns the final result.\nfunc GetConsolidatedConfig(\n\tjsonRawConf json.RawMessage, env map[string]string, arg string,\n) (Config, error) {\n\tresult := NewConfig()\n\tif jsonRawConf != nil {\n\t\tjsonConf := Config{}\n\t\tif err := json.Unmarshal(jsonRawConf, &jsonConf); err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tresult = result.Apply(jsonConf)\n\t}\n\n\tenvConfig := Config{}\n\tif err := envconfig.Process(\"\", &envConfig, func(key string) (string, bool) {\n\t\tv, ok := env[key]\n\t\treturn v, ok\n\t}); err != nil {\n\t\t// TODO: get rid of envconfig and actually use the env parameter...\n\t\treturn result, err\n\t}\n\tresult = result.Apply(envConfig)\n\n\tif arg != \"\" {\n\t\turlConf, err := ParseArg(arg)\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tresult = result.Apply(urlConf)\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/output/csv/config_test.go",
    "content": "package csv\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestNewConfig(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := NewConfig()\n\tassert.Equal(t, \"file.csv\", config.FileName.String)\n\tassert.Equal(t, \"1s\", config.SaveInterval.String())\n\tassert.Equal(t, \"unix\", config.TimeFormat.String)\n}\n\nfunc TestApply(t *testing.T) {\n\tt.Parallel()\n\n\tconfigs := []Config{\n\t\t{\n\t\t\tFileName:     null.StringFrom(\"\"),\n\t\t\tSaveInterval: types.NullDurationFrom(2 * time.Second),\n\t\t\tTimeFormat:   null.StringFrom(\"unix\"),\n\t\t},\n\t\t{\n\t\t\tFileName:     null.StringFrom(\"newPath\"),\n\t\t\tSaveInterval: types.NewNullDuration(time.Duration(1), false),\n\t\t\tTimeFormat:   null.StringFrom(\"rfc3339\"),\n\t\t},\n\t}\n\texpected := []struct {\n\t\tFileName     string\n\t\tSaveInterval string\n\t\tTimeFormat   string\n\t}{\n\t\t{\n\t\t\tFileName:     \"\",\n\t\t\tSaveInterval: \"2s\",\n\t\t\tTimeFormat:   \"unix\",\n\t\t},\n\t\t{\n\t\t\tFileName:     \"newPath\",\n\t\t\tSaveInterval: \"1s\",\n\t\t\tTimeFormat:   \"rfc3339\",\n\t\t},\n\t}\n\n\tfor i := range configs {\n\t\tconfig := configs[i]\n\t\texpected := expected[i]\n\n\t\tt.Run(expected.FileName+\"_\"+expected.SaveInterval, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tbaseConfig := NewConfig()\n\t\t\tbaseConfig = baseConfig.Apply(config)\n\n\t\t\tassert.Equal(t, expected.FileName, baseConfig.FileName.String)\n\t\t\tassert.Equal(t, expected.SaveInterval, baseConfig.SaveInterval.String())\n\t\t\tassert.Equal(t, expected.TimeFormat, baseConfig.TimeFormat.String)\n\t\t})\n\t}\n}\n\nfunc TestParseArg(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\tconfig             Config\n\t\texpectedLogEntries []string\n\t\texpectedErr        bool\n\t}{\n\t\t\"test_file.csv\": {\n\t\t\tconfig: Config{\n\t\t\t\tFileName:     null.StringFrom(\"test_file.csv\"),\n\t\t\t\tSaveInterval: types.NewNullDuration(1*time.Second, false),\n\t\t\t\tTimeFormat:   null.NewString(\"unix\", false),\n\t\t\t},\n\t\t},\n\t\t\"saveInterval=5s\": {\n\t\t\tconfig: Config{\n\t\t\t\tFileName:     null.NewString(\"file.csv\", false),\n\t\t\t\tSaveInterval: types.NullDurationFrom(5 * time.Second),\n\t\t\t\tTimeFormat:   null.NewString(\"unix\", false),\n\t\t\t},\n\t\t},\n\t\t\"filename=test.csv,saveInterval=5s\": {\n\t\t\texpectedErr: true,\n\t\t},\n\t\t\"fileName=test.csv,timeFormat=rfc3339\": {\n\t\t\tconfig: Config{\n\t\t\t\tFileName:     null.StringFrom(\"test.csv\"),\n\t\t\t\tSaveInterval: types.NewNullDuration(1*time.Second, false),\n\t\t\t\tTimeFormat:   null.StringFrom(\"rfc3339\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor arg, testCase := range cases {\n\t\tt.Run(arg, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tconfig, err := ParseArg(arg)\n\n\t\t\tif testCase.expectedErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, testCase.config, config)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/output/csv/doc.go",
    "content": "// Package csv implements an output writing metrics in csv format\npackage csv\n"
  },
  {
    "path": "internal/output/csv/output.go",
    "content": "package csv\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\n// Output implements the lib.Output interface for saving to CSV files.\ntype Output struct {\n\toutput.SampleBuffer\n\n\tparams          output.Params\n\tperiodicFlusher *output.PeriodicFlusher\n\n\tlogger    logrus.FieldLogger\n\tfname     string\n\tcsvWriter *csv.Writer\n\tcsvLock   sync.Mutex\n\tcloseFn   func() error\n\n\tresTags      []string\n\tignoredTags  []string\n\trow          []string\n\tsaveInterval time.Duration\n\ttimeFormat   TimeFormat\n}\n\n// New Creates new instance of CSV output\nfunc New(params output.Params) (output.Output, error) {\n\treturn newOutput(params)\n}\n\nfunc newOutput(params output.Params) (*Output, error) {\n\tresTags, ignoredTags, err := buildTagSets(params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlogger := params.Logger.WithFields(logrus.Fields{\n\t\t\"output\":   \"csv\",\n\t\t\"filename\": params.ConfigArgument,\n\t})\n\tconfig, err := GetConsolidatedConfig(params.JSONConfig, params.Environment, params.ConfigArgument)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttimeFormat, err := TimeFormatString(config.TimeFormat.String)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsaveInterval := config.SaveInterval.TimeDuration()\n\tfname := config.FileName.String\n\n\tif fname == \"\" || fname == \"-\" {\n\t\tstdoutWriter := csv.NewWriter(params.StdOut)\n\t\treturn &Output{\n\t\t\tfname:        \"-\",\n\t\t\tresTags:      resTags,\n\t\t\tignoredTags:  ignoredTags,\n\t\t\tcsvWriter:    stdoutWriter,\n\t\t\trow:          make([]string, 3+len(resTags)+2),\n\t\t\tsaveInterval: saveInterval,\n\t\t\ttimeFormat:   timeFormat,\n\t\t\tcloseFn:      func() error { return nil },\n\t\t\tlogger:       logger,\n\t\t\tparams:       params,\n\t\t}, nil\n\t}\n\n\tlogFile, err := params.FS.Create(fname)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tc := Output{\n\t\tfname:        fname,\n\t\tresTags:      resTags,\n\t\tignoredTags:  ignoredTags,\n\t\trow:          make([]string, 3+len(resTags)+2),\n\t\tsaveInterval: saveInterval,\n\t\ttimeFormat:   timeFormat,\n\t\tlogger:       logger,\n\t\tparams:       params,\n\t}\n\n\tif strings.HasSuffix(fname, \".gz\") {\n\t\toutfile := gzip.NewWriter(logFile)\n\t\tcsvWriter := csv.NewWriter(outfile)\n\t\tc.csvWriter = csvWriter\n\t\tc.closeFn = func() error {\n\t\t\t_ = outfile.Close()\n\t\t\treturn logFile.Close()\n\t\t}\n\t} else {\n\t\tcsvWriter := csv.NewWriter(logFile)\n\t\tc.csvWriter = csvWriter\n\t\tc.closeFn = logFile.Close\n\t}\n\n\treturn &c, nil\n}\n\n// buildTagSets builds trackable and ignored tag sets from the\n// output params\nfunc buildTagSets(params output.Params) ([]string, []string, error) {\n\tresTags := []string{}\n\tignoredTags := []string{}\n\ttags := params.ScriptOptions.SystemTags.Map()\n\tfor tag, flag := range tags {\n\t\tsystemTag, err := metrics.SystemTagString(tag)\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\n\t\t// The non-indexable system tags are neither a \"resTag\"\n\t\t// nor an \"ignoreTag\". They aren't a \"resTag\" as they\n\t\t// aren't added as a column in the CSV. Yet they also\n\t\t// shouldn't be ignored as they are added to the\n\t\t// \"metadata\" column\n\t\tif metrics.NonIndexableSystemTags.Has(systemTag) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif flag {\n\t\t\tresTags = append(resTags, tag)\n\t\t} else {\n\t\t\tignoredTags = append(ignoredTags, tag)\n\t\t}\n\t}\n\n\tsort.Strings(resTags)\n\tsort.Strings(ignoredTags)\n\n\treturn resTags, ignoredTags, nil\n}\n\n// Description returns a human-readable description of the output.\nfunc (o *Output) Description() string {\n\tif o.fname == \"\" || o.fname == \"-\" { // TODO rename\n\t\treturn \"csv (stdout)\"\n\t}\n\treturn fmt.Sprintf(\"csv (%s)\", o.fname)\n}\n\n// Start writes the csv header and starts a new output.PeriodicFlusher\nfunc (o *Output) Start() error {\n\to.logger.Debug(\"Starting...\")\n\n\theader := MakeHeader(o.resTags)\n\terr := o.csvWriter.Write(header)\n\tif err != nil {\n\t\to.logger.WithField(\"filename\", o.fname).Error(\"CSV: Error writing column names to file\")\n\t}\n\to.csvWriter.Flush()\n\n\tpf, err := output.NewPeriodicFlusher(o.saveInterval, o.flushMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\to.logger.Debug(\"Started!\")\n\to.periodicFlusher = pf\n\n\treturn nil\n}\n\n// Stop flushes any remaining metrics and stops the goroutine.\nfunc (o *Output) Stop() error {\n\to.logger.Debug(\"Stopping...\")\n\tdefer o.logger.Debug(\"Stopped!\")\n\to.periodicFlusher.Stop()\n\treturn o.closeFn()\n}\n\n// flushMetrics Writes samples to the csv file\nfunc (o *Output) flushMetrics() {\n\tsamples := o.GetBufferedSamples()\n\n\tif len(samples) > 0 {\n\t\to.csvLock.Lock()\n\t\tdefer o.csvLock.Unlock()\n\t\tfor _, sc := range samples {\n\t\t\tfor _, sample := range sc.GetSamples() {\n\t\t\t\trow := SampleToRow(&sample, o.resTags, o.ignoredTags, o.row, o.timeFormat)\n\t\t\t\terr := o.csvWriter.Write(row)\n\t\t\t\tif err != nil {\n\t\t\t\t\to.logger.WithField(\"filename\", o.fname).Error(\"CSV: Error writing to file\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\to.csvWriter.Flush()\n\t}\n}\n\n// MakeHeader creates list of column names for csv file\nfunc MakeHeader(tags []string) []string {\n\ttags = append(tags, \"extra_tags\")\n\ttags = append(tags, \"metadata\")\n\treturn append([]string{\"metric_name\", \"timestamp\", \"metric_value\"}, tags...)\n}\n\n// SampleToRow converts sample into array of strings\nfunc SampleToRow(sample *metrics.Sample, resTags []string, ignoredTags []string, row []string,\n\ttimeFormat TimeFormat,\n) []string {\n\trow[0] = sample.Metric.Name\n\n\tswitch timeFormat {\n\tcase TimeFormatRFC3339:\n\t\trow[1] = sample.Time.Format(time.RFC3339)\n\tcase TimeFormatRFC3339Nano:\n\t\trow[1] = sample.Time.Format(time.RFC3339Nano)\n\tcase TimeFormatUnix:\n\t\trow[1] = strconv.FormatInt(sample.Time.Unix(), 10)\n\tcase TimeFormatUnixMilli:\n\t\trow[1] = strconv.FormatInt(sample.Time.UnixMilli(), 10)\n\tcase TimeFormatUnixMicro:\n\t\trow[1] = strconv.FormatInt(sample.Time.UnixMicro(), 10)\n\tcase TimeFormatUnixNano:\n\t\trow[1] = strconv.FormatInt(sample.Time.UnixNano(), 10)\n\t}\n\n\trow[2] = fmt.Sprintf(\"%f\", sample.Value)\n\t// TODO: optimize all of this - do not use tags.Map(), flip resTags, fix the\n\t// for loops, get rid of IsStringInSlice(), etc.\n\tsampleTags := sample.Tags.Map()\n\tfor ind, tag := range resTags {\n\t\trow[ind+3] = sampleTags[tag]\n\t}\n\n\textraTags := bytes.Buffer{}\n\tprev := false\n\twriteTag := func(tag, val string) bool {\n\t\tif IsStringInSlice(resTags, tag) || IsStringInSlice(ignoredTags, tag) {\n\t\t\treturn true // continue\n\t\t}\n\t\tif prev {\n\t\t\tif _, err := extraTags.WriteString(\"&\"); err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif _, err := extraTags.WriteString(tag); err != nil {\n\t\t\treturn false\n\t\t}\n\n\t\tif _, err := extraTags.WriteString(\"=\"); err != nil {\n\t\t\treturn false\n\t\t}\n\n\t\tif _, err := extraTags.WriteString(val); err != nil {\n\t\t\treturn false\n\t\t}\n\t\tprev = true\n\t\treturn true\n\t}\n\n\tfor tag, val := range sampleTags {\n\t\tif !writeTag(tag, val) {\n\t\t\tbreak\n\t\t}\n\t}\n\trow[len(row)-2] = extraTags.String()\n\textraTags.Reset()\n\tprev = false\n\n\tfor key, val := range sample.Metadata {\n\t\tif !writeTag(key, val) {\n\t\t\tbreak\n\t\t}\n\t}\n\trow[len(row)-1] = extraTags.String()\n\treturn row\n}\n\n// IsStringInSlice returns whether the string is contained within a string slice\nfunc IsStringInSlice(slice []string, str string) bool {\n\tif index := sort.SearchStrings(slice, str); index == len(slice) || slice[index] != str {\n\t\treturn false\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "internal/output/csv/output_test.go",
    "content": "package csv\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc TestMakeHeader(t *testing.T) {\n\tt.Parallel()\n\n\ttestdata := map[string][]string{\n\t\t\"One tag\": {\n\t\t\t\"tag1\",\n\t\t},\n\t\t\"Two tags\": {\n\t\t\t\"tag1\", \"tag2\",\n\t\t},\n\t}\n\n\tfor testname, tags := range testdata {\n\t\tt.Run(testname, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\theader := MakeHeader(tags)\n\t\t\tassert.Equal(t, len(tags)+5, len(header))\n\t\t\tassert.Equal(t, \"metric_name\", header[0])\n\t\t\tassert.Equal(t, \"timestamp\", header[1])\n\t\t\tassert.Equal(t, \"metric_value\", header[2])\n\t\t\tassert.Equal(t, \"extra_tags\", header[len(header)-2])\n\t\t\tassert.Equal(t, \"metadata\", header[len(header)-1])\n\t\t})\n\t}\n}\n\nfunc TestSampleToRow(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\ttestMetric, err := registry.NewMetric(\"my_metric\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\ttestData := []struct {\n\t\ttestname    string\n\t\tsample      *metrics.Sample\n\t\tresTags     []string\n\t\tignoredTags []string\n\t\ttimeFormat  string\n\t}{\n\t\t{\n\t\t\ttestname: \"One res tag, one ignored tag, one extra tag\",\n\t\t\tsample: &metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"tag1\": \"val1\",\n\t\t\t\t\t\t\"tag2\": \"val2\",\n\t\t\t\t\t\t\"tag3\": \"val3\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 0),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\tresTags:     []string{\"tag1\"},\n\t\t\tignoredTags: []string{\"tag2\"},\n\t\t\ttimeFormat:  \"unix\",\n\t\t},\n\t\t{\n\t\t\ttestname: \"Two res tags, three extra tags\",\n\t\t\tsample: &metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"tag1\": \"val1\",\n\t\t\t\t\t\t\"tag2\": \"val2\",\n\t\t\t\t\t\t\"tag3\": \"val3\",\n\t\t\t\t\t\t\"tag4\": \"val4\",\n\t\t\t\t\t\t\"tag5\": \"val5\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 0),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\tresTags:     []string{\"tag1\", \"tag2\"},\n\t\t\tignoredTags: []string{},\n\t\t\ttimeFormat:  \"unix\",\n\t\t},\n\t\t{\n\t\t\ttestname: \"Two res tags, two ignored, with RFC3339 timestamp\",\n\t\t\tsample: &metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"tag1\": \"val1\",\n\t\t\t\t\t\t\"tag2\": \"val2\",\n\t\t\t\t\t\t\"tag3\": \"val3\",\n\t\t\t\t\t\t\"tag4\": \"val4\",\n\t\t\t\t\t\t\"tag5\": \"val5\",\n\t\t\t\t\t\t\"tag6\": \"val6\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 0),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\tresTags:     []string{\"tag1\", \"tag3\"},\n\t\t\tignoredTags: []string{\"tag4\", \"tag6\"},\n\t\t\ttimeFormat:  \"rfc3339\",\n\t\t},\n\t\t{\n\t\t\ttestname: \"Two res tags, two ignored, with Unix Nano timestamp\",\n\t\t\tsample: &metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"tag1\": \"val1\",\n\t\t\t\t\t\t\"tag2\": \"val2\",\n\t\t\t\t\t\t\"tag3\": \"val3\",\n\t\t\t\t\t\t\"tag4\": \"val4\",\n\t\t\t\t\t\t\"tag5\": \"val5\",\n\t\t\t\t\t\t\"tag6\": \"val6\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 25),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\tresTags:     []string{\"tag1\", \"tag3\"},\n\t\t\tignoredTags: []string{\"tag4\", \"tag6\"},\n\t\t\ttimeFormat:  \"unix_nano\",\n\t\t},\n\t\t{\n\t\t\ttestname: \"Two res tags, two ignored, with Unix Micro timestamp\",\n\t\t\tsample: &metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"tag1\": \"val1\",\n\t\t\t\t\t\t\"tag2\": \"val2\",\n\t\t\t\t\t\t\"tag3\": \"val3\",\n\t\t\t\t\t\t\"tag4\": \"val4\",\n\t\t\t\t\t\t\"tag5\": \"val5\",\n\t\t\t\t\t\t\"tag6\": \"val6\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 2125),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\tresTags:     []string{\"tag1\", \"tag3\"},\n\t\t\tignoredTags: []string{\"tag4\", \"tag6\"},\n\t\t\ttimeFormat:  \"unix_micro\",\n\t\t},\n\t\t{\n\t\t\ttestname: \"Two res tags, two ignored, with Unix Milli timestamp\",\n\t\t\tsample: &metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"tag1\": \"val1\",\n\t\t\t\t\t\t\"tag2\": \"val2\",\n\t\t\t\t\t\t\"tag3\": \"val3\",\n\t\t\t\t\t\t\"tag4\": \"val4\",\n\t\t\t\t\t\t\"tag5\": \"val5\",\n\t\t\t\t\t\t\"tag6\": \"val6\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 6482125),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\tresTags:     []string{\"tag1\", \"tag3\"},\n\t\t\tignoredTags: []string{\"tag4\", \"tag6\"},\n\t\t\ttimeFormat:  \"unix_milli\",\n\t\t},\n\t\t{\n\t\t\ttestname: \"Two res tags, two ignored, with RFC3339Nano timestamp\",\n\t\t\tsample: &metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"tag1\": \"val1\",\n\t\t\t\t\t\t\"tag2\": \"val2\",\n\t\t\t\t\t\t\"tag3\": \"val3\",\n\t\t\t\t\t\t\"tag4\": \"val4\",\n\t\t\t\t\t\t\"tag5\": \"val5\",\n\t\t\t\t\t\t\"tag6\": \"val6\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 0),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\tresTags:     []string{\"tag1\", \"tag3\"},\n\t\t\tignoredTags: []string{\"tag4\", \"tag6\"},\n\t\t\ttimeFormat:  \"rfc3339_nano\",\n\t\t},\n\t}\n\n\texpected := []struct {\n\t\tbaseRow  []string\n\t\textraRow []string\n\t}{\n\t\t{\n\t\t\tbaseRow: []string{\n\t\t\t\t\"my_metric\",\n\t\t\t\t\"1562324644\",\n\t\t\t\t\"1.000000\",\n\t\t\t\t\"val1\",\n\t\t\t},\n\t\t\textraRow: []string{\n\t\t\t\t\"tag3=val3\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tbaseRow: []string{\n\t\t\t\t\"my_metric\",\n\t\t\t\t\"1562324644\",\n\t\t\t\t\"1.000000\",\n\t\t\t\t\"val1\",\n\t\t\t\t\"val2\",\n\t\t\t},\n\t\t\textraRow: []string{\n\t\t\t\t\"tag3=val3\",\n\t\t\t\t\"tag4=val4\",\n\t\t\t\t\"tag5=val5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tbaseRow: []string{\n\t\t\t\t\"my_metric\",\n\t\t\t\ttime.Unix(1562324644, 0).Format(time.RFC3339),\n\t\t\t\t\"1.000000\",\n\t\t\t\t\"val1\",\n\t\t\t\t\"val3\",\n\t\t\t},\n\t\t\textraRow: []string{\n\t\t\t\t\"tag2=val2\",\n\t\t\t\t\"tag5=val5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tbaseRow: []string{\n\t\t\t\t\"my_metric\",\n\t\t\t\t\"1562324644000000025\",\n\t\t\t\t\"1.000000\",\n\t\t\t\t\"val1\",\n\t\t\t\t\"val3\",\n\t\t\t},\n\t\t\textraRow: []string{\n\t\t\t\t\"tag2=val2\",\n\t\t\t\t\"tag5=val5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tbaseRow: []string{\n\t\t\t\t\"my_metric\",\n\t\t\t\t\"1562324644000002\",\n\t\t\t\t\"1.000000\",\n\t\t\t\t\"val1\",\n\t\t\t\t\"val3\",\n\t\t\t},\n\t\t\textraRow: []string{\n\t\t\t\t\"tag2=val2\",\n\t\t\t\t\"tag5=val5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tbaseRow: []string{\n\t\t\t\t\"my_metric\",\n\t\t\t\t\"1562324644006\",\n\t\t\t\t\"1.000000\",\n\t\t\t\t\"val1\",\n\t\t\t\t\"val3\",\n\t\t\t},\n\t\t\textraRow: []string{\n\t\t\t\t\"tag2=val2\",\n\t\t\t\t\"tag5=val5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tbaseRow: []string{\n\t\t\t\t\"my_metric\",\n\t\t\t\ttime.Unix(1562324644, 0).Format(time.RFC3339Nano),\n\t\t\t\t\"1.000000\",\n\t\t\t\t\"val1\",\n\t\t\t\t\"val3\",\n\t\t\t},\n\t\t\textraRow: []string{\n\t\t\t\t\"tag2=val2\",\n\t\t\t\t\"tag5=val5\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor i := range testData {\n\t\ttestname, sample := testData[i].testname, testData[i].sample\n\t\tresTags, ignoredTags := testData[i].resTags, testData[i].ignoredTags\n\t\ttimeFormat, err := TimeFormatString(testData[i].timeFormat)\n\t\trequire.NoError(t, err)\n\t\texpectedRow := expected[i]\n\n\t\tt.Run(testname, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\trow := SampleToRow(sample, resTags, ignoredTags, make([]string, 3+len(resTags)+2), timeFormat)\n\t\t\tfor ind, cell := range expectedRow.baseRow {\n\t\t\t\tassert.Equal(t, cell, row[ind])\n\t\t\t}\n\t\t\tfor _, cell := range expectedRow.extraRow {\n\t\t\t\tassert.Contains(t, row[len(row)-2], cell)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc readUnCompressedFile(fileName string, fs fsext.Fs) string {\n\tcsvbytes, err := fsext.ReadFile(fs, fileName)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\n\treturn string(csvbytes)\n}\n\nfunc readCompressedFile(fileName string, fs fsext.Fs) string {\n\tfile, err := fs.Open(fileName)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\n\tgzf, err := gzip.NewReader(file)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\n\tcsvbytes, err := io.ReadAll(gzf)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\n\treturn string(csvbytes)\n}\n\nfunc TestRun(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\ttestMetric, err := registry.NewMetric(\"my_metric\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\ttestData := []struct {\n\t\tsamples        []metrics.SampleContainer\n\t\tfileName       string\n\t\tfileReaderFunc func(fileName string, fs fsext.Fs) string\n\t\ttimeFormat     string\n\t\toutputContent  string\n\t}{\n\t\t{\n\t\t\tsamples: []metrics.SampleContainer{\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\t\"check\": \"val1\",\n\t\t\t\t\t\t\t\"url\":   \"val2\",\n\t\t\t\t\t\t\t\"error\": \"val3\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t\tTime:  time.Unix(1562324643, 0),\n\t\t\t\t\tValue: 1,\n\t\t\t\t},\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\t\"check\": \"val1\",\n\t\t\t\t\t\t\t\"url\":   \"val2\",\n\t\t\t\t\t\t\t\"error\": \"val3\",\n\t\t\t\t\t\t\t\"tag4\":  \"val4\",\n\t\t\t\t\t\t\t\"vu\":    \"1\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t\tMetadata: map[string]string{},\n\t\t\t\t\tTime:     time.Unix(1562324644, 0),\n\t\t\t\t\tValue:    1,\n\t\t\t\t},\n\t\t\t},\n\t\t\tfileName:       \"test\",\n\t\t\tfileReaderFunc: readUnCompressedFile,\n\t\t\ttimeFormat:     \"\",\n\t\t\toutputContent: \"metric_name,timestamp,metric_value,check,error,extra_tags,metadata\\n\" +\n\t\t\t\t\"my_metric,1562324643,1.000000,val1,val3,url=val2,\\n\" +\n\t\t\t\t\"my_metric,1562324644,1.000000,val1,val3,tag4=val4&url=val2&vu=1,\\n\",\n\t\t},\n\t\t{\n\t\t\tsamples: []metrics.SampleContainer{\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\t\"check\": \"val1\",\n\t\t\t\t\t\t\t\"url\":   \"val2\",\n\t\t\t\t\t\t\t\"error\": \"val3\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t\tTime:     time.Unix(1562324643, 0),\n\t\t\t\t\tMetadata: map[string]string{\"y\": \"1\"},\n\t\t\t\t\tValue:    1,\n\t\t\t\t},\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\t\"check\": \"val1\",\n\t\t\t\t\t\t\t\"url\":   \"val2\",\n\t\t\t\t\t\t\t\"error\": \"val3\",\n\t\t\t\t\t\t\t\"name\":  \"val4\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t\tTime:  time.Unix(1562324644, 0),\n\t\t\t\t\tValue: 1,\n\t\t\t\t},\n\t\t\t},\n\t\t\tfileName:       \"test.gz\",\n\t\t\tfileReaderFunc: readCompressedFile,\n\t\t\ttimeFormat:     \"unix\",\n\t\t\toutputContent: \"metric_name,timestamp,metric_value,check,error,extra_tags,metadata\\n\" +\n\t\t\t\t\"my_metric,1562324643,1.000000,val1,val3,url=val2,y=1\\n\" +\n\t\t\t\t\"my_metric,1562324644,1.000000,val1,val3,name=val4&url=val2,\\n\",\n\t\t},\n\t\t{\n\t\t\tsamples: []metrics.SampleContainer{\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\t\"check\": \"val1\",\n\t\t\t\t\t\t\t\"url\":   \"val2\",\n\t\t\t\t\t\t\t\"error\": \"val3\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t\tTime:  time.Unix(1562324644, 0),\n\t\t\t\t\tValue: 1,\n\t\t\t\t},\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: testMetric,\n\t\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\t\"check\": \"val1\",\n\t\t\t\t\t\t\t\"url\":   \"val2\",\n\t\t\t\t\t\t\t\"error\": \"val3\",\n\t\t\t\t\t\t\t\"name\":  \"val4\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t\tTime:     time.Unix(1562324644, 0),\n\t\t\t\t\tMetadata: map[string]string{\"y\": \"2\", \"z\": \"3\"},\n\t\t\t\t\tValue:    1,\n\t\t\t\t},\n\t\t\t},\n\t\t\tfileName:       \"test\",\n\t\t\tfileReaderFunc: readUnCompressedFile,\n\t\t\ttimeFormat:     \"rfc3339\",\n\t\t\toutputContent: \"metric_name,timestamp,metric_value,check,error,extra_tags,metadata\\n\" +\n\t\t\t\t\"my_metric,\" + time.Unix(1562324644, 0).Format(time.RFC3339) + \",1.000000,val1,val3,url=val2,\\n\" +\n\t\t\t\t\"my_metric,\" + time.Unix(1562324644, 0).Format(time.RFC3339) + \",1.000000,val1,val3,name=val4&url=val2,y=2&z=3\\n\",\n\t\t},\n\t}\n\n\tfor i, data := range testData {\n\t\tname := fmt.Sprint(i)\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tmem := fsext.NewMemMapFs()\n\t\t\tenv := make(map[string]string)\n\t\t\tif data.timeFormat != \"\" {\n\t\t\t\tenv[\"K6_CSV_TIME_FORMAT\"] = data.timeFormat\n\t\t\t}\n\n\t\t\toutput, err := newOutput(output.Params{\n\t\t\t\tLogger:         testutils.NewLogger(t),\n\t\t\t\tFS:             mem,\n\t\t\t\tEnvironment:    env,\n\t\t\t\tConfigArgument: data.fileName,\n\t\t\t\tScriptOptions: lib.Options{\n\t\t\t\t\tSystemTags: metrics.NewSystemTagSet(metrics.TagError | metrics.TagCheck | metrics.TagVU),\n\t\t\t\t},\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, output)\n\n\t\t\trequire.NoError(t, output.Start())\n\t\t\toutput.AddMetricSamples(data.samples)\n\t\t\trequire.NoError(t, output.Stop())\n\n\t\t\tfinalOutput := data.fileReaderFunc(data.fileName, mem)\n\t\t\tassert.Equal(t, data.outputContent, sortExtraTagsForTest(t, finalOutput))\n\t\t})\n\t}\n}\n\nfunc sortExtraTagsForTest(t *testing.T, input string) string {\n\tt.Helper()\n\tr := csv.NewReader(strings.NewReader(input))\n\tlines, err := r.ReadAll()\n\trequire.NoError(t, err)\n\tfor i, line := range lines[1:] {\n\t\textraTags := strings.Split(line[len(line)-2], \"&\")\n\t\tsort.Strings(extraTags)\n\t\tlines[i+1][len(line)-2] = strings.Join(extraTags, \"&\")\n\t\textraMetadata := strings.Split(line[len(line)-1], \"&\")\n\t\tsort.Strings(extraMetadata)\n\t\tlines[i+1][len(line)-1] = strings.Join(extraMetadata, \"&\")\n\t}\n\tvar b bytes.Buffer\n\tw := csv.NewWriter(&b)\n\trequire.NoError(t, w.WriteAll(lines))\n\tw.Flush()\n\treturn b.String()\n}\n"
  },
  {
    "path": "internal/output/csv/time_format_gen.go",
    "content": "// Code generated by \"enumer -type=TimeFormat -transform=snake -trimprefix TimeFormat -output time_format_gen.go\"; DO NOT EDIT.\n\npackage csv\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _TimeFormatName = \"unixunix_milliunix_microunix_nanorfc3339rfc3339_nano\"\n\nvar _TimeFormatIndex = [...]uint8{0, 4, 14, 24, 33, 40, 52}\n\nconst _TimeFormatLowerName = \"unixunix_milliunix_microunix_nanorfc3339rfc3339_nano\"\n\nfunc (i TimeFormat) String() string {\n\tif i >= TimeFormat(len(_TimeFormatIndex)-1) {\n\t\treturn fmt.Sprintf(\"TimeFormat(%d)\", i)\n\t}\n\treturn _TimeFormatName[_TimeFormatIndex[i]:_TimeFormatIndex[i+1]]\n}\n\n// An \"invalid array index\" compiler error signifies that the constant values have changed.\n// Re-run the stringer command to generate them again.\nfunc _TimeFormatNoOp() {\n\tvar x [1]struct{}\n\t_ = x[TimeFormatUnix-(0)]\n\t_ = x[TimeFormatUnixMilli-(1)]\n\t_ = x[TimeFormatUnixMicro-(2)]\n\t_ = x[TimeFormatUnixNano-(3)]\n\t_ = x[TimeFormatRFC3339-(4)]\n\t_ = x[TimeFormatRFC3339Nano-(5)]\n}\n\nvar _TimeFormatValues = []TimeFormat{TimeFormatUnix, TimeFormatUnixMilli, TimeFormatUnixMicro, TimeFormatUnixNano, TimeFormatRFC3339, TimeFormatRFC3339Nano}\n\nvar _TimeFormatNameToValueMap = map[string]TimeFormat{\n\t_TimeFormatName[0:4]:        TimeFormatUnix,\n\t_TimeFormatLowerName[0:4]:   TimeFormatUnix,\n\t_TimeFormatName[4:14]:       TimeFormatUnixMilli,\n\t_TimeFormatLowerName[4:14]:  TimeFormatUnixMilli,\n\t_TimeFormatName[14:24]:      TimeFormatUnixMicro,\n\t_TimeFormatLowerName[14:24]: TimeFormatUnixMicro,\n\t_TimeFormatName[24:33]:      TimeFormatUnixNano,\n\t_TimeFormatLowerName[24:33]: TimeFormatUnixNano,\n\t_TimeFormatName[33:40]:      TimeFormatRFC3339,\n\t_TimeFormatLowerName[33:40]: TimeFormatRFC3339,\n\t_TimeFormatName[40:52]:      TimeFormatRFC3339Nano,\n\t_TimeFormatLowerName[40:52]: TimeFormatRFC3339Nano,\n}\n\nvar _TimeFormatNames = []string{\n\t_TimeFormatName[0:4],\n\t_TimeFormatName[4:14],\n\t_TimeFormatName[14:24],\n\t_TimeFormatName[24:33],\n\t_TimeFormatName[33:40],\n\t_TimeFormatName[40:52],\n}\n\n// TimeFormatString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc TimeFormatString(s string) (TimeFormat, error) {\n\tif val, ok := _TimeFormatNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\n\tif val, ok := _TimeFormatNameToValueMap[strings.ToLower(s)]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to TimeFormat values\", s)\n}\n\n// TimeFormatValues returns all values of the enum\nfunc TimeFormatValues() []TimeFormat {\n\treturn _TimeFormatValues\n}\n\n// TimeFormatStrings returns a slice of all String values of the enum\nfunc TimeFormatStrings() []string {\n\tstrs := make([]string, len(_TimeFormatNames))\n\tcopy(strs, _TimeFormatNames)\n\treturn strs\n}\n\n// IsATimeFormat returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i TimeFormat) IsATimeFormat() bool {\n\tfor _, v := range _TimeFormatValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "internal/output/influxdb/bench_test.go",
    "content": "package influxdb\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc benchmarkInfluxdb(b *testing.B, t time.Duration) {\n\tregistry := metrics.NewRegistry()\n\tmetric, err := registry.NewMetric(\"test_gauge\", metrics.Gauge)\n\trequire.NoError(b, err)\n\ttags := registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\"something\": \"else\",\n\t\t\"VU\":        \"21\",\n\t\t\"else\":      \"something\",\n\t})\n\ttestOutputCycle(b, func(rw http.ResponseWriter, r *http.Request) {\n\t\tfor {\n\t\t\ttime.Sleep(t)\n\t\t\tm, _ := io.CopyN(io.Discard, r.Body, 1<<18) // read 1/4 mb a time\n\t\t\tif m == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\trw.WriteHeader(http.StatusNoContent)\n\t}, func(tb testing.TB, c *Output) {\n\t\tb, _ := tb.(*testing.B)\n\n\t\tb.ResetTimer()\n\n\t\tsamples := make(metrics.Samples, 10)\n\t\tfor i := range samples {\n\t\t\tsamples[i] = metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: metric,\n\t\t\t\t\tTags:   tags,\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 2.0,\n\t\t\t}\n\t\t}\n\n\t\tb.ResetTimer()\n\t\tfor i := 0; i < b.N; i++ {\n\t\t\tc.AddMetricSamples([]metrics.SampleContainer{samples})\n\t\t\ttime.Sleep(time.Nanosecond * 20)\n\t\t}\n\t})\n}\n\nfunc BenchmarkInfluxdb1Second(b *testing.B) {\n\tbenchmarkInfluxdb(b, time.Second)\n}\n\nfunc BenchmarkInfluxdb2Second(b *testing.B) {\n\tbenchmarkInfluxdb(b, 2*time.Second)\n}\n\nfunc BenchmarkInfluxdb100Milliseconds(b *testing.B) {\n\tbenchmarkInfluxdb(b, 100*time.Millisecond)\n}\n"
  },
  {
    "path": "internal/output/influxdb/config.go",
    "content": "package influxdb\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// Config represents a k6's influxdb output configuration.\ntype Config struct {\n\t// Connection.\n\tAddr             null.String        `json:\"addr\" envconfig:\"K6_INFLUXDB_ADDR\"`\n\tProxy            null.String        `json:\"proxy\" envconfig:\"K6_INFLUXDB_PROXY\"`\n\tUsername         null.String        `json:\"username\" envconfig:\"K6_INFLUXDB_USERNAME\"`\n\tPassword         null.String        `json:\"password\" envconfig:\"K6_INFLUXDB_PASSWORD\"`\n\tInsecure         null.Bool          `json:\"insecure\" envconfig:\"K6_INFLUXDB_INSECURE\"`\n\tPayloadSize      null.Int           `json:\"payloadSize\" envconfig:\"K6_INFLUXDB_PAYLOAD_SIZE\"`\n\tPushInterval     types.NullDuration `json:\"pushInterval\" envconfig:\"K6_INFLUXDB_PUSH_INTERVAL\"`\n\tConcurrentWrites null.Int           `json:\"concurrentWrites\" envconfig:\"K6_INFLUXDB_CONCURRENT_WRITES\"`\n\n\t// Samples.\n\tDB           null.String `json:\"db\" envconfig:\"K6_INFLUXDB_DB\"`\n\tPrecision    null.String `json:\"precision\" envconfig:\"K6_INFLUXDB_PRECISION\"`\n\tRetention    null.String `json:\"retention\" envconfig:\"K6_INFLUXDB_RETENTION\"`\n\tConsistency  null.String `json:\"consistency\" envconfig:\"K6_INFLUXDB_CONSISTENCY\"`\n\tTagsAsFields []string    `json:\"tagsAsFields,omitempty\" envconfig:\"K6_INFLUXDB_TAGS_AS_FIELDS\"`\n}\n\n// NewConfig creates a new InfluxDB output config with some default values.\nfunc NewConfig() Config {\n\tc := Config{\n\t\tAddr:         null.NewString(\"http://localhost:8086\", false),\n\t\tDB:           null.NewString(\"k6\", false),\n\t\tTagsAsFields: []string{\"vu\", \"iter\", \"url\"},\n\t\tPushInterval: types.NewNullDuration(time.Second, false),\n\n\t\t// The minimum value of pow(2, N) for handling a stressful situation\n\t\t// with the default push interval set to 1s.\n\t\t// Concurrency is not expected for the normal use-case,\n\t\t// the response time should be lower than the push interval set value.\n\t\t// In case of spikes, the response time could go around 2s,\n\t\t// higher values will highlight a not sustainable situation\n\t\t// and the user should adjust the executed script\n\t\t// or the configuration based on the environment and rate expected.\n\t\tConcurrentWrites: null.NewInt(4, false),\n\t}\n\treturn c\n}\n\n// Apply applies a valid config options to the receiver.\nfunc (c Config) Apply(cfg Config) Config {\n\tif cfg.Addr.Valid {\n\t\tc.Addr = cfg.Addr\n\t}\n\tif cfg.Proxy.Valid {\n\t\tc.Proxy = cfg.Proxy\n\t}\n\tif cfg.Username.Valid {\n\t\tc.Username = cfg.Username\n\t}\n\tif cfg.Password.Valid {\n\t\tc.Password = cfg.Password\n\t}\n\tif cfg.Insecure.Valid {\n\t\tc.Insecure = cfg.Insecure\n\t}\n\tif cfg.PayloadSize.Valid && cfg.PayloadSize.Int64 > 0 {\n\t\tc.PayloadSize = cfg.PayloadSize\n\t}\n\tif cfg.DB.Valid {\n\t\tc.DB = cfg.DB\n\t}\n\tif cfg.Precision.Valid {\n\t\tc.Precision = cfg.Precision\n\t}\n\tif cfg.Retention.Valid {\n\t\tc.Retention = cfg.Retention\n\t}\n\tif cfg.Consistency.Valid {\n\t\tc.Consistency = cfg.Consistency\n\t}\n\tif len(cfg.TagsAsFields) > 0 {\n\t\tc.TagsAsFields = cfg.TagsAsFields\n\t}\n\tif cfg.PushInterval.Valid {\n\t\tc.PushInterval = cfg.PushInterval\n\t}\n\n\tif cfg.ConcurrentWrites.Valid {\n\t\tc.ConcurrentWrites = cfg.ConcurrentWrites\n\t}\n\treturn c\n}\n\n// ParseJSON parses the supplied JSON into a Config.\nfunc ParseJSON(data json.RawMessage) (Config, error) {\n\tconf := Config{}\n\terr := json.Unmarshal(data, &conf)\n\treturn conf, err\n}\n\n// ParseURL parses the supplied URL into a Config.\nfunc ParseURL(text string) (Config, error) {\n\tc := Config{}\n\tu, err := url.Parse(text)\n\tif err != nil {\n\t\treturn c, err\n\t}\n\tif u.Host != \"\" {\n\t\tc.Addr = null.StringFrom(u.Scheme + \"://\" + u.Host)\n\t}\n\tif db := strings.TrimPrefix(u.Path, \"/\"); db != \"\" {\n\t\tc.DB = null.StringFrom(db)\n\t}\n\tif u.User != nil {\n\t\tc.Username = null.StringFrom(u.User.Username())\n\t\tpass, _ := u.User.Password()\n\t\tc.Password = null.StringFrom(pass)\n\t}\n\tfor k, vs := range u.Query() {\n\t\tswitch k {\n\t\tcase \"insecure\":\n\t\t\tswitch vs[0] {\n\t\t\tcase \"\":\n\t\t\tcase \"false\":\n\t\t\t\tc.Insecure = null.BoolFrom(false)\n\t\t\tcase \"true\":\n\t\t\t\tc.Insecure = null.BoolFrom(true)\n\t\t\tdefault:\n\t\t\t\treturn c, fmt.Errorf(\"insecure must be true or false, not %s\", vs[0])\n\t\t\t}\n\t\tcase \"payload_size\":\n\t\t\tvar size int\n\t\t\tsize, err = strconv.Atoi(vs[0])\n\t\t\tif err != nil {\n\t\t\t\treturn c, err\n\t\t\t}\n\t\t\tc.PayloadSize = null.IntFrom(int64(size))\n\t\tcase \"precision\":\n\t\t\tc.Precision = null.StringFrom(vs[0])\n\t\tcase \"retention\":\n\t\t\tc.Retention = null.StringFrom(vs[0])\n\t\tcase \"consistency\":\n\t\t\tc.Consistency = null.StringFrom(vs[0])\n\n\t\tcase \"pushInterval\":\n\t\t\terr = c.PushInterval.UnmarshalText([]byte(vs[0]))\n\t\t\tif err != nil {\n\t\t\t\treturn c, err\n\t\t\t}\n\t\tcase \"concurrentWrites\":\n\t\t\tvar writes int\n\t\t\twrites, err = strconv.Atoi(vs[0])\n\t\t\tif err != nil {\n\t\t\t\treturn c, err\n\t\t\t}\n\t\t\tc.ConcurrentWrites = null.IntFrom(int64(writes))\n\t\tcase \"tagsAsFields\":\n\t\t\tc.TagsAsFields = vs\n\t\tdefault:\n\t\t\treturn c, fmt.Errorf(\"unknown query parameter: %s\", k)\n\t\t}\n\t}\n\treturn c, err\n}\n\n// GetConsolidatedConfig combines {default config values + JSON config +\n// environment vars + URL config values}, and returns the final result.\nfunc GetConsolidatedConfig(jsonRawConf json.RawMessage, env map[string]string, url string) (Config, error) {\n\tresult := NewConfig()\n\tif jsonRawConf != nil {\n\t\tjsonConf, err := ParseJSON(jsonRawConf)\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tresult = result.Apply(jsonConf)\n\t}\n\n\tenvConfig := Config{}\n\tif err := envconfig.Process(\"\", &envConfig, func(key string) (string, bool) {\n\t\tv, ok := env[key]\n\t\treturn v, ok\n\t}); err != nil {\n\t\t// TODO: get rid of envconfig and actually use the env parameter...\n\t\treturn result, err\n\t}\n\tresult = result.Apply(envConfig)\n\n\tif url != \"\" {\n\t\turlConf, err := ParseURL(url)\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tresult = result.Apply(urlConf)\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "internal/output/influxdb/config_test.go",
    "content": "package influxdb\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestParseURL(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]Config{\n\t\t\"\":                             {},\n\t\t\"dbname\":                       {DB: null.StringFrom(\"dbname\")},\n\t\t\"/dbname\":                      {DB: null.StringFrom(\"dbname\")},\n\t\t\"http://localhost:8086\":        {Addr: null.StringFrom(\"http://localhost:8086\")},\n\t\t\"http://localhost:8086/dbname\": {Addr: null.StringFrom(\"http://localhost:8086\"), DB: null.StringFrom(\"dbname\")},\n\t}\n\tqueries := map[string]struct {\n\t\tConfig Config\n\t\tErr    string\n\t}{\n\t\t\"?\":                {Config{}, \"\"},\n\t\t\"?insecure=false\":  {Config{Insecure: null.BoolFrom(false)}, \"\"},\n\t\t\"?insecure=true\":   {Config{Insecure: null.BoolFrom(true)}, \"\"},\n\t\t\"?insecure=ture\":   {Config{}, \"insecure must be true or false, not ture\"},\n\t\t\"?payload_size=69\": {Config{PayloadSize: null.IntFrom(69)}, \"\"},\n\t\t\"?payload_size=a\":  {Config{}, \"strconv.Atoi: parsing \\\"a\\\": invalid syntax\"},\n\t}\n\tfor str, data := range testdata {\n\t\tt.Run(str, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tconfig, err := ParseURL(str)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, data, config)\n\n\t\t\tfor q, qdata := range queries {\n\t\t\t\tt.Run(q, func(t *testing.T) {\n\t\t\t\t\tconfig, err := ParseURL(str + q)\n\t\t\t\t\tif qdata.Err != \"\" {\n\t\t\t\t\t\tassert.EqualError(t, err, qdata.Err)\n\t\t\t\t\t} else {\n\t\t\t\t\t\texpected2 := qdata.Config\n\t\t\t\t\t\texpected2.DB = data.DB\n\t\t\t\t\t\texpected2.Addr = data.Addr\n\t\t\t\t\t\tassert.Equal(t, expected2, config)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetConsolidatedConfigHTTPProxy(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Valid Proxy URL\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestdata := map[string]string{\n\t\t\t\"K6_INFLUXDB_PROXY\": \"http://localhost:3128\",\n\t\t}\n\t\tconfig, err := GetConsolidatedConfig(nil, testdata, \"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"http://localhost:3128\", config.Proxy.String)\n\t})\n\tt.Run(\"Invalid Proxy URL\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestdata := map[string]string{\n\t\t\t\"K6_INFLUXDB_PROXY\": \"http://foo\\x7f.com/\",\n\t\t}\n\t\tconfig, err := GetConsolidatedConfig(nil, testdata, \"\")\n\t\tassert.NoError(t, err)\n\t\t_, err = MakeClient(config)\n\t\tassert.Error(t, err)\n\t})\n}\n"
  },
  {
    "path": "internal/output/influxdb/output.go",
    "content": "// Package influxdb provides an output plugin for sending results\n// directly to InfluxDB v1.\n// for the InfluxDB v2 please see an extension\n// https://github.com/grafana/xk6-output-influxdb\npackage influxdb\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"maps\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tclient \"github.com/influxdata/influxdb1-client/v2\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\n// FieldKind defines Enum for tag-to-field type conversion\ntype FieldKind int\n\nconst (\n\t// String field (default)\n\tString FieldKind = iota\n\t// Int field\n\tInt\n\t// Float field\n\tFloat\n\t// Bool field\n\tBool\n)\n\n// Output is the influxdb Output struct\ntype Output struct {\n\toutput.SampleBuffer\n\n\tClient    client.Client\n\tConfig    Config\n\tBatchConf client.BatchPointsConfig\n\n\tlogger          logrus.FieldLogger\n\tparams          output.Params\n\tfieldKinds      map[string]FieldKind\n\tperiodicFlusher *output.PeriodicFlusher\n\tsemaphoreCh     chan struct{}\n\twg              sync.WaitGroup\n}\n\n// New returns new influxdb output\nfunc New(params output.Params) (output.Output, error) {\n\treturn newOutput(params)\n}\n\nfunc newOutput(params output.Params) (*Output, error) {\n\tconf, err := GetConsolidatedConfig(params.JSONConfig, params.Environment, params.ConfigArgument)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcl, err := MakeClient(conf)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tbatchConf := MakeBatchConfig(conf)\n\tif conf.ConcurrentWrites.Int64 <= 0 {\n\t\treturn nil, errors.New(\"influxdb's ConcurrentWrites must be a positive number\")\n\t}\n\tfldKinds, err := MakeFieldKinds(conf)\n\treturn &Output{\n\t\tparams: params,\n\t\tlogger: params.Logger.WithFields(logrus.Fields{\n\t\t\t\"output\": \"InfluxDBv1\",\n\t\t}),\n\t\tClient:      cl,\n\t\tConfig:      conf,\n\t\tBatchConf:   batchConf,\n\t\tfieldKinds:  fldKinds,\n\t\tsemaphoreCh: make(chan struct{}, conf.ConcurrentWrites.Int64),\n\t\twg:          sync.WaitGroup{},\n\t}, err\n}\n\nfunc (o *Output) extractTagsToValues(tags map[string]string, values map[string]any) map[string]any {\n\tfor tag, kind := range o.fieldKinds {\n\t\tif val, ok := tags[tag]; ok {\n\t\t\tvar v any\n\t\t\tvar err error\n\t\t\tswitch kind {\n\t\t\tcase String:\n\t\t\t\tv = val\n\t\t\tcase Bool:\n\t\t\t\tv, err = strconv.ParseBool(val)\n\t\t\tcase Float:\n\t\t\t\tv, err = strconv.ParseFloat(val, 64)\n\t\t\tcase Int:\n\t\t\t\tv, err = strconv.ParseInt(val, 10, 64)\n\t\t\t}\n\t\t\tif err == nil {\n\t\t\t\tvalues[tag] = v\n\t\t\t} else {\n\t\t\t\tvalues[tag] = val\n\t\t\t}\n\t\t\tdelete(tags, tag)\n\t\t}\n\t}\n\treturn values\n}\n\nfunc (o *Output) batchFromSamples(containers []metrics.SampleContainer) (client.BatchPoints, error) {\n\tbatch, err := client.NewBatchPoints(o.BatchConf)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"couldn't make a batch: %w\", err)\n\t}\n\n\ttype cacheItem struct {\n\t\ttags   map[string]string\n\t\tvalues map[string]any\n\t}\n\tcache := map[*metrics.TagSet]cacheItem{}\n\tfor _, container := range containers {\n\t\tsamples := container.GetSamples()\n\t\tfor _, sample := range samples {\n\t\t\tvar tags map[string]string\n\t\t\tvalues := make(map[string]any)\n\t\t\tif cached, ok := cache[sample.Tags]; ok {\n\t\t\t\ttags = cached.tags\n\t\t\t\tmaps.Copy(values, cached.values)\n\t\t\t} else {\n\t\t\t\ttags = sample.Tags.Map()\n\t\t\t\to.extractTagsToValues(tags, values)\n\t\t\t\tcache[sample.Tags] = cacheItem{tags, values}\n\t\t\t}\n\t\t\tvalues[\"value\"] = sample.Value\n\t\t\tvar p *client.Point\n\t\t\tp, err = client.NewPoint(\n\t\t\t\tsample.Metric.Name,\n\t\t\t\ttags,\n\t\t\t\tvalues,\n\t\t\t\tsample.Time,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"couldn't make point from sample: %w\", err)\n\t\t\t}\n\t\t\tbatch.AddPoint(p)\n\t\t}\n\t}\n\n\treturn batch, nil\n}\n\n// Description returns a human-readable description of the output.\nfunc (o *Output) Description() string {\n\treturn fmt.Sprintf(\"InfluxDBv1 (%s)\", o.Config.Addr.String)\n}\n\n// Start tries to open the specified JSON file and starts the goroutine for\n// metric flushing. If gzip encoding is specified, it also handles that.\nfunc (o *Output) Start() error {\n\to.logger.Debug(\"Starting...\")\n\t// Try to create the database if it doesn't exist. Failure to do so is USUALLY harmless; it\n\t// usually means we're either a non-admin user to an existing DB or connecting over UDP.\n\t_, err := o.Client.Query(client.NewQuery(\"CREATE DATABASE \"+o.BatchConf.Database, \"\", \"\"))\n\tif err != nil {\n\t\to.logger.WithError(err).Debug(\"Couldn't create database; most likely harmless\")\n\t}\n\n\tpf, err := output.NewPeriodicFlusher(o.Config.PushInterval.TimeDuration(), o.flushMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\to.logger.Debug(\"Started!\")\n\to.periodicFlusher = pf\n\n\treturn nil\n}\n\n// Stop flushes any remaining metrics and stops the goroutine.\nfunc (o *Output) Stop() error {\n\to.logger.Debug(\"Stopping...\")\n\tdefer o.logger.Debug(\"Stopped!\")\n\to.periodicFlusher.Stop()\n\to.wg.Wait()\n\treturn nil\n}\n\nfunc (o *Output) flushMetrics() {\n\tsamples := o.GetBufferedSamples()\n\tif len(samples) < 1 {\n\t\treturn\n\t}\n\n\to.logger.Debug(\"Committing...\")\n\to.wg.Add(1)\n\to.semaphoreCh <- struct{}{}\n\tgo func() {\n\t\tdefer func() {\n\t\t\t<-o.semaphoreCh\n\t\t\to.wg.Done()\n\t\t}()\n\n\t\to.logger.WithField(\"samples\", len(samples)).Debug(\"Writing...\")\n\n\t\tbatch, err := o.batchFromSamples(samples)\n\t\tif err != nil {\n\t\t\to.logger.WithError(err).Error(\"Couldn't create batch from samples\")\n\t\t\treturn\n\t\t}\n\n\t\to.logger.WithField(\"points\", len(batch.Points())).Debug(\"Writing...\")\n\t\tstartTime := time.Now()\n\t\tif err := o.Client.Write(batch); err != nil {\n\t\t\tmsg := \"Couldn't write stats\"\n\t\t\tif strings.Contains(err.Error(), \"unauthorized access\") {\n\t\t\t\tmsg += \", InfluxDB v2.x isn't supported by this output, if you are using it you may consider to use the extension https://github.com/grafana/xk6-output-influxdb\" //nolint:lll\n\t\t\t}\n\t\t\to.logger.WithError(err).Error(msg)\n\t\t\treturn\n\t\t}\n\t\tt := time.Since(startTime)\n\t\to.logger.WithField(\"t\", t).Debug(\"Batch written!\")\n\n\t\tif t > o.Config.PushInterval.TimeDuration() {\n\t\t\to.logger.WithField(\"t\", t).\n\t\t\t\tWarn(\"The flush operation took higher than the expected set push interval. If you see this message multiple times then the setup or configuration need to be adjusted to achieve a sustainable rate.\") //nolint:lll\n\t\t}\n\t}()\n}\n"
  },
  {
    "path": "internal/output/influxdb/output_test.go",
    "content": "package influxdb\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc TestBadConcurrentWrites(t *testing.T) {\n\tt.Parallel()\n\tlogger := testutils.NewLogger(t)\n\tt.Run(\"0\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := New(output.Params{\n\t\t\tLogger:         logger,\n\t\t\tConfigArgument: \"?concurrentWrites=0\",\n\t\t})\n\t\trequire.Error(t, err)\n\t\trequire.EqualError(t, err, \"influxdb's ConcurrentWrites must be a positive number\")\n\t})\n\n\tt.Run(\"-2\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := New(output.Params{\n\t\t\tLogger:         logger,\n\t\t\tConfigArgument: \"?concurrentWrites=-2\",\n\t\t})\n\t\trequire.Error(t, err)\n\t\trequire.EqualError(t, err, \"influxdb's ConcurrentWrites must be a positive number\")\n\t})\n\n\tt.Run(\"2\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := New(output.Params{\n\t\t\tLogger:         logger,\n\t\t\tConfigArgument: \"?concurrentWrites=2\",\n\t\t})\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc testOutputCycle(t testing.TB, handler http.HandlerFunc, body func(testing.TB, *Output)) {\n\ts := &http.Server{\n\t\tAddr:              \":\",\n\t\tHandler:           handler,\n\t\tMaxHeaderBytes:    1 << 20,\n\t\tReadHeaderTimeout: time.Second,\n\t}\n\tl, err := (&net.ListenConfig{}).Listen(context.Background(), \"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\tdefer func() {\n\t\t_ = l.Close()\n\t}()\n\n\tdefer func() {\n\t\trequire.NoError(t, s.Shutdown(context.Background()))\n\t}()\n\n\tgo func() {\n\t\trequire.Equal(t, http.ErrServerClosed, s.Serve(l))\n\t}()\n\n\tc, err := newOutput(output.Params{\n\t\tLogger:         testutils.NewLogger(t),\n\t\tConfigArgument: \"http://\" + l.Addr().String(),\n\t})\n\trequire.NoError(t, err)\n\n\trequire.NoError(t, c.Start())\n\tbody(t, c)\n\n\trequire.NoError(t, c.Stop())\n}\n\nfunc TestOutput(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\tmetric, err := registry.NewMetric(\"test_gauge\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\tvar samplesRead int\n\tdefer func() {\n\t\trequire.Equal(t, 20, samplesRead)\n\t}()\n\n\ttestOutputCycle(t, func(rw http.ResponseWriter, r *http.Request) {\n\t\tb := bytes.NewBuffer(nil)\n\t\t_, _ = io.Copy(b, r.Body)\n\t\tfor {\n\t\t\ts, err := b.ReadString('\\n')\n\t\t\tif len(s) > 0 {\n\t\t\t\tsamplesRead++\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\trw.WriteHeader(http.StatusNoContent)\n\t}, func(_ testing.TB, c *Output) {\n\t\tsamples := make(metrics.Samples, 10)\n\t\tfor i := range samples {\n\t\t\tsamples[i] = metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: metric,\n\t\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\t\"something\": \"else\",\n\t\t\t\t\t\t\"VU\":        \"21\",\n\t\t\t\t\t\t\"else\":      \"something\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 2.0,\n\t\t\t}\n\t\t}\n\t\tc.AddMetricSamples([]metrics.SampleContainer{samples})\n\t\tc.AddMetricSamples([]metrics.SampleContainer{samples})\n\t})\n}\n\nfunc TestOutputFlushMetricsConcurrency(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\trequests = int32(0)\n\t\tblock    = make(chan struct{})\n\t)\n\n\twg := sync.WaitGroup{}\n\tts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {\n\t\t// block all the received requests\n\t\t// so concurrency will be needed\n\t\t// to not block the flush\n\t\tatomic.AddInt32(&requests, 1)\n\t\twg.Done()\n\t\tblock <- struct{}{}\n\t}))\n\tdefer func() {\n\t\t// unlock the server\n\t\tfor range 4 {\n\t\t\t<-block\n\t\t}\n\t\tclose(block)\n\t\tts.Close()\n\t}()\n\n\tregistry := metrics.NewRegistry()\n\tmetric, err := registry.NewMetric(\"test_gauge\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\to, err := newOutput(output.Params{\n\t\tLogger:         testutils.NewLogger(t),\n\t\tConfigArgument: ts.URL,\n\t})\n\trequire.NoError(t, err)\n\n\tfor i := range 5 {\n\t\tselect {\n\t\tcase o.semaphoreCh <- struct{}{}:\n\t\t\t<-o.semaphoreCh\n\t\t\twg.Add(1)\n\t\t\to.AddMetricSamples([]metrics.SampleContainer{metrics.Samples{\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: metric,\n\t\t\t\t\t\tTags:   registry.RootTagSet(),\n\t\t\t\t\t},\n\t\t\t\t\tTime:  time.Now(),\n\t\t\t\t\tValue: 2.0,\n\t\t\t\t},\n\t\t\t}})\n\t\t\to.flushMetrics()\n\t\tdefault:\n\t\t\t// the 5th request should be rate limited\n\t\t\tassert.Equal(t, 5, i+1)\n\t\t}\n\t}\n\twg.Wait()\n\tassert.Equal(t, 4, int(atomic.LoadInt32(&requests)))\n}\n\nfunc TestExtractTagsToValues(t *testing.T) {\n\tt.Parallel()\n\to, err := newOutput(output.Params{\n\t\tLogger:         testutils.NewLogger(t),\n\t\tConfigArgument: \"?tagsAsFields=stringField&tagsAsFields=stringField2:string&tagsAsFields=boolField:bool&tagsAsFields=floatField:float&tagsAsFields=intField:int\",\n\t})\n\trequire.NoError(t, err)\n\ttags := map[string]string{\n\t\t\"stringField\":  \"string\",\n\t\t\"stringField2\": \"string2\",\n\t\t\"boolField\":    \"true\",\n\t\t\"floatField\":   \"3.14\",\n\t\t\"intField\":     \"12345\",\n\t}\n\tvalues := o.extractTagsToValues(tags, map[string]any{})\n\n\trequire.Equal(t, \"string\", values[\"stringField\"])\n\trequire.Equal(t, \"string2\", values[\"stringField2\"])\n\trequire.Equal(t, true, values[\"boolField\"])\n\trequire.Equal(t, 3.14, values[\"floatField\"])\n\trequire.Equal(t, int64(12345), values[\"intField\"])\n}\n"
  },
  {
    "path": "internal/output/influxdb/util.go",
    "content": "package influxdb\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\tclient \"github.com/influxdata/influxdb1-client/v2\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// MakeClient returns a new InfluxDB client based on the given Config.\nfunc MakeClient(conf Config) (client.Client, error) {\n\tif after, ok := strings.CutPrefix(conf.Addr.String, \"udp://\"); ok {\n\t\treturn client.NewUDPClient(client.UDPConfig{\n\t\t\tAddr:        after,\n\t\t\tPayloadSize: int(conf.PayloadSize.Int64),\n\t\t})\n\t}\n\tif conf.Addr.String == \"\" {\n\t\tconf.Addr = null.StringFrom(\"http://localhost:8086\")\n\t}\n\tclientHTTPConfig := client.HTTPConfig{\n\t\tAddr:               conf.Addr.String,\n\t\tUsername:           conf.Username.String,\n\t\tPassword:           conf.Password.String,\n\t\tUserAgent:          \"k6\",\n\t\tInsecureSkipVerify: conf.Insecure.Bool,\n\t}\n\tif conf.Proxy.Valid {\n\t\tparsedProxyURL, err := url.Parse(conf.Proxy.String)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse the http proxy URL: %w\", err)\n\t\t}\n\t\tclientHTTPConfig.Proxy = http.ProxyURL(parsedProxyURL)\n\t}\n\treturn client.NewHTTPClient(clientHTTPConfig)\n}\n\n// MakeBatchConfig returns a new InfluxDB BatchPointsConfig based on the given\nfunc MakeBatchConfig(conf Config) client.BatchPointsConfig {\n\tif !conf.DB.Valid || conf.DB.String == \"\" {\n\t\tconf.DB = null.StringFrom(\"k6\")\n\t}\n\treturn client.BatchPointsConfig{\n\t\tPrecision:        conf.Precision.String,\n\t\tDatabase:         conf.DB.String,\n\t\tRetentionPolicy:  conf.Retention.String,\n\t\tWriteConsistency: conf.Consistency.String,\n\t}\n}\n\nfunc checkDuplicatedTypeDefinitions(fieldKinds map[string]FieldKind, tag string) error {\n\tif _, found := fieldKinds[tag]; found {\n\t\treturn fmt.Errorf(\"a tag name (%s) shows up more than once in InfluxDB field type configurations\", tag)\n\t}\n\treturn nil\n}\n\n// MakeFieldKinds reads the Config and returns a lookup map of tag names to\n// the field type their values should be converted to.\nfunc MakeFieldKinds(conf Config) (map[string]FieldKind, error) {\n\tfieldKinds := make(map[string]FieldKind)\n\tfor _, tag := range conf.TagsAsFields {\n\t\tfieldName, fieldType, _ := strings.Cut(tag, \":\")\n\t\tif fieldType == \"\" {\n\t\t\tfieldType = \"string\"\n\t\t}\n\n\t\terr := checkDuplicatedTypeDefinitions(fieldKinds, fieldName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tswitch fieldType {\n\t\tcase \"string\":\n\t\t\tfieldKinds[fieldName] = String\n\t\tcase \"bool\":\n\t\t\tfieldKinds[fieldName] = Bool\n\t\tcase \"float\":\n\t\t\tfieldKinds[fieldName] = Float\n\t\tcase \"int\":\n\t\t\tfieldKinds[fieldName] = Int\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"an invalid type (%s) is specified for an InfluxDB field (%s)\",\n\t\t\t\tfieldType, fieldName)\n\t\t}\n\t}\n\n\treturn fieldKinds, nil\n}\n"
  },
  {
    "path": "internal/output/influxdb/util_test.go",
    "content": "package influxdb\n\nimport (\n\t\"testing\"\n\n\tclient \"github.com/influxdata/influxdb1-client/v2\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestMakeBatchConfig(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Empty\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tassert.Equal(t,\n\t\t\tclient.BatchPointsConfig{Database: \"k6\"},\n\t\t\tMakeBatchConfig(Config{}),\n\t\t)\n\t})\n\tt.Run(\"DB Set\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tassert.Equal(t,\n\t\t\tclient.BatchPointsConfig{Database: \"dbname\"},\n\t\t\tMakeBatchConfig(Config{DB: null.StringFrom(\"dbname\")}),\n\t\t)\n\t})\n}\n\nfunc TestFieldKinds(t *testing.T) {\n\tt.Parallel()\n\n\tvar fieldKinds map[string]FieldKind\n\tvar err error\n\n\tconf := NewConfig()\n\tconf.TagsAsFields = []string{\"vu\", \"iter\", \"url\", \"boolField\", \"floatField\", \"intField\"}\n\n\t// Error case 1 (duplicated bool fields)\n\tconf.TagsAsFields = []string{\"vu\", \"iter\", \"url\", \"boolField:bool\", \"boolField:bool\"}\n\t_, err = MakeFieldKinds(conf)\n\trequire.Error(t, err)\n\n\t// Error case 2 (duplicated fields in bool and float fields)\n\tconf.TagsAsFields = []string{\"vu\", \"iter\", \"url\", \"boolField:bool\", \"boolField:float\"}\n\t_, err = MakeFieldKinds(conf)\n\trequire.Error(t, err)\n\n\t// Error case 3 (duplicated fields in BoolFields and IntFields)\n\tconf.TagsAsFields = []string{\"vu\", \"iter\", \"url\", \"boolField:bool\", \"floatField:float\", \"boolField:int\"}\n\t_, err = MakeFieldKinds(conf)\n\trequire.Error(t, err)\n\n\t// Normal case\n\tconf.TagsAsFields = []string{\"vu\", \"iter\", \"url\", \"boolField:bool\", \"floatField:float\", \"intField:int\"}\n\tfieldKinds, err = MakeFieldKinds(conf)\n\trequire.NoError(t, err)\n\n\trequire.Equal(t, Bool, fieldKinds[\"boolField\"])\n\trequire.Equal(t, Float, fieldKinds[\"floatField\"])\n\trequire.Equal(t, Int, fieldKinds[\"intField\"])\n}\n"
  },
  {
    "path": "internal/output/json/benchmark_test.go",
    "content": "package json\n\nimport (\n\t\"bytes\"\n\t\"path\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc BenchmarkFlushMetrics(b *testing.B) {\n\tstdout := new(bytes.Buffer)\n\tdir := b.TempDir()\n\tout, err := New(output.Params{\n\t\tLogger:         testutils.NewLogger(b),\n\t\tStdOut:         stdout,\n\t\tFS:             fsext.NewOsFs(),\n\t\tConfigArgument: path.Join(dir, \"test.gz\"),\n\t})\n\trequire.NoError(b, err)\n\n\tsamples, _ := generateTestMetricSamples(b)\n\tsize := 10000\n\tfor len(samples) < size {\n\t\tmore, _ := generateTestMetricSamples(b)\n\t\tsamples = append(samples, more...)\n\t}\n\tsamples = samples[:size]\n\to, _ := out.(*Output)\n\trequire.NoError(b, o.Start())\n\to.periodicFlusher.Stop()\n\tb.ResetTimer()\n\tb.ReportAllocs()\n\tfor i := 0; i < b.N; i++ {\n\t\to.AddMetricSamples(samples)\n\t\to.flushMetrics()\n\t}\n}\n"
  },
  {
    "path": "internal/output/json/json.go",
    "content": "// Package json is implements an output to put metrics in a json file.\n// Actually a multi line json file.\npackage json\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"maps\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/klauspost/compress/gzip\"\n\t\"github.com/mailru/easyjson/jwriter\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\n// TODO: add option for emitting proper JSON files (https://github.com/k6io/k6/issues/737)\nconst flushPeriod = 200 * time.Millisecond // TODO: make this configurable\n\n// Output funnels all passed metrics to an (optionally gzipped) JSON file.\ntype Output struct {\n\toutput.SampleBuffer\n\n\tparams          output.Params\n\tperiodicFlusher *output.PeriodicFlusher\n\n\tlogger      logrus.FieldLogger\n\tfilename    string\n\tout         io.Writer\n\tcloseFn     func() error\n\tseenMetrics map[string]struct{}\n\tthresholds  map[string]metrics.Thresholds\n}\n\n// New returns a new JSON output.\nfunc New(params output.Params) (output.Output, error) {\n\treturn &Output{\n\t\tparams:   params,\n\t\tfilename: params.ConfigArgument,\n\t\tlogger: params.Logger.WithFields(logrus.Fields{\n\t\t\t\"output\":   \"json\",\n\t\t\t\"filename\": params.ConfigArgument,\n\t\t}),\n\t\tseenMetrics: make(map[string]struct{}),\n\t}, nil\n}\n\n// Description returns a human-readable description of the output.\nfunc (o *Output) Description() string {\n\tif o.filename == \"\" || o.filename == \"-\" {\n\t\treturn \"json(stdout)\"\n\t}\n\treturn fmt.Sprintf(\"json (%s)\", o.filename)\n}\n\n// Start tries to open the specified JSON file and starts the goroutine for\n// metric flushing. If gzip encoding is specified, it also handles that.\nfunc (o *Output) Start() error {\n\to.logger.Debug(\"Starting...\")\n\n\tif o.filename == \"\" || o.filename == \"-\" {\n\t\tw := bufio.NewWriter(o.params.StdOut)\n\t\to.closeFn = func() error {\n\t\t\treturn w.Flush()\n\t\t}\n\t\to.out = w\n\t} else {\n\t\tlogfile, err := o.params.FS.Create(o.filename)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tw := bufio.NewWriter(logfile)\n\n\t\tif strings.HasSuffix(o.filename, \".gz\") {\n\t\t\toutfile := gzip.NewWriter(w)\n\n\t\t\to.closeFn = func() error {\n\t\t\t\t_ = outfile.Close()\n\t\t\t\t_ = w.Flush()\n\t\t\t\treturn logfile.Close()\n\t\t\t}\n\t\t\to.out = outfile\n\t\t} else {\n\t\t\to.closeFn = func() error {\n\t\t\t\t_ = w.Flush()\n\t\t\t\treturn logfile.Close()\n\t\t\t}\n\t\t\to.out = logfile\n\t\t}\n\t}\n\n\tpf, err := output.NewPeriodicFlusher(flushPeriod, o.flushMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\to.logger.Debug(\"Started!\")\n\to.periodicFlusher = pf\n\n\treturn nil\n}\n\n// Stop flushes any remaining metrics and stops the goroutine.\nfunc (o *Output) Stop() error {\n\to.logger.Debug(\"Stopping...\")\n\tdefer o.logger.Debug(\"Stopped!\")\n\to.periodicFlusher.Stop()\n\treturn o.closeFn()\n}\n\n// SetThresholds receives the thresholds before the output is Start()-ed.\nfunc (o *Output) SetThresholds(thresholds map[string]metrics.Thresholds) {\n\tif len(thresholds) == 0 {\n\t\treturn\n\t}\n\to.thresholds = make(map[string]metrics.Thresholds, len(thresholds))\n\tmaps.Copy(o.thresholds, thresholds)\n}\n\nfunc (o *Output) flushMetrics() {\n\tsamples := o.GetBufferedSamples()\n\tstart := time.Now()\n\tvar count int\n\tjw := new(jwriter.Writer)\n\tfor _, sc := range samples {\n\t\tsamples := sc.GetSamples()\n\t\tcount += len(samples)\n\t\tfor _, sample := range samples {\n\t\t\to.handleMetric(sample.Metric, jw)\n\t\t\twrapSample(sample).MarshalEasyJSON(jw)\n\t\t\tjw.RawByte('\\n')\n\t\t}\n\t}\n\n\tif _, err := jw.DumpTo(o.out); err != nil {\n\t\t// Skip metric if it can't be made into JSON or envelope is null.\n\t\to.logger.WithError(err).Error(\"Sample couldn't be marshalled to JSON\")\n\t}\n\tif count > 0 {\n\t\to.logger.WithField(\"t\", time.Since(start)).WithField(\"count\", count).Debug(\"Wrote metrics to JSON\")\n\t}\n}\n\nfunc (o *Output) handleMetric(m *metrics.Metric, jw *jwriter.Writer) {\n\tif _, ok := o.seenMetrics[m.Name]; ok {\n\t\treturn\n\t}\n\to.seenMetrics[m.Name] = struct{}{}\n\n\twrapped := metricEnvelope{\n\t\tType:   \"Metric\",\n\t\tMetric: m.Name,\n\t}\n\twrapped.Data.Name = m.Name\n\twrapped.Data.Type = m.Type\n\twrapped.Data.Contains = m.Contains\n\twrapped.Data.Submetrics = m.Submetrics\n\n\tif ts, ok := o.thresholds[m.Name]; ok {\n\t\twrapped.Data.Thresholds = ts\n\t}\n\n\twrapped.MarshalEasyJSON(jw)\n\tjw.RawByte('\\n')\n}\n"
  },
  {
    "path": "internal/output/json/json_easyjson.go",
    "content": "// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.\n\npackage json\n\nimport (\n\tjson \"encoding/json\"\n\teasyjson \"github.com/mailru/easyjson\"\n\tjlexer \"github.com/mailru/easyjson/jlexer\"\n\tjwriter \"github.com/mailru/easyjson/jwriter\"\n\tmetrics \"go.k6.io/k6/metrics\"\n\ttime \"time\"\n)\n\n// suppress unused package warning\nvar (\n\t_ *json.RawMessage\n\t_ *jlexer.Lexer\n\t_ *jwriter.Writer\n\t_ easyjson.Marshaler\n)\n\nfunc easyjson42239ddeDecodeGoK6IoK6InternalOutputJson(in *jlexer.Lexer, out *sampleEnvelope) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"metric\":\n\t\t\tout.Metric = string(in.String())\n\t\tcase \"type\":\n\t\t\tout.Type = string(in.String())\n\t\tcase \"data\":\n\t\t\teasyjson42239ddeDecode(in, &out.Data)\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjson42239ddeEncodeGoK6IoK6InternalOutputJson(out *jwriter.Writer, in sampleEnvelope) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"metric\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tout.String(string(in.Metric))\n\t}\n\t{\n\t\tconst prefix string = \",\\\"type\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.String(string(in.Type))\n\t}\n\t{\n\t\tconst prefix string = \",\\\"data\\\":\"\n\t\tout.RawString(prefix)\n\t\teasyjson42239ddeEncode(out, in.Data)\n\t}\n\tout.RawByte('}')\n}\n\n// MarshalEasyJSON supports easyjson.Marshaler interface\nfunc (v sampleEnvelope) MarshalEasyJSON(w *jwriter.Writer) {\n\teasyjson42239ddeEncodeGoK6IoK6InternalOutputJson(w, v)\n}\n\n// UnmarshalEasyJSON supports easyjson.Unmarshaler interface\nfunc (v *sampleEnvelope) UnmarshalEasyJSON(l *jlexer.Lexer) {\n\teasyjson42239ddeDecodeGoK6IoK6InternalOutputJson(l, v)\n}\nfunc easyjson42239ddeDecode(in *jlexer.Lexer, out *struct {\n\tTime     time.Time         `json:\"time\"`\n\tValue    float64           `json:\"value\"`\n\tTags     *metrics.TagSet   `json:\"tags\"`\n\tMetadata map[string]string `json:\"metadata,omitempty\"`\n}) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"time\":\n\t\t\tif data := in.Raw(); in.Ok() {\n\t\t\t\tin.AddError((out.Time).UnmarshalJSON(data))\n\t\t\t}\n\t\tcase \"value\":\n\t\t\tout.Value = float64(in.Float64())\n\t\tcase \"tags\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t\tout.Tags = nil\n\t\t\t} else {\n\t\t\t\tif out.Tags == nil {\n\t\t\t\t\tout.Tags = new(metrics.TagSet)\n\t\t\t\t}\n\t\t\t\t(*out.Tags).UnmarshalEasyJSON(in)\n\t\t\t}\n\t\tcase \"metadata\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t} else {\n\t\t\t\tin.Delim('{')\n\t\t\t\tif !in.IsDelim('}') {\n\t\t\t\t\tout.Metadata = make(map[string]string)\n\t\t\t\t} else {\n\t\t\t\t\tout.Metadata = nil\n\t\t\t\t}\n\t\t\t\tfor !in.IsDelim('}') {\n\t\t\t\t\tkey := string(in.String())\n\t\t\t\t\tin.WantColon()\n\t\t\t\t\tvar v1 string\n\t\t\t\t\tv1 = string(in.String())\n\t\t\t\t\t(out.Metadata)[key] = v1\n\t\t\t\t\tin.WantComma()\n\t\t\t\t}\n\t\t\t\tin.Delim('}')\n\t\t\t}\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjson42239ddeEncode(out *jwriter.Writer, in struct {\n\tTime     time.Time         `json:\"time\"`\n\tValue    float64           `json:\"value\"`\n\tTags     *metrics.TagSet   `json:\"tags\"`\n\tMetadata map[string]string `json:\"metadata,omitempty\"`\n}) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"time\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tout.Raw((in.Time).MarshalJSON())\n\t}\n\t{\n\t\tconst prefix string = \",\\\"value\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.Float64(float64(in.Value))\n\t}\n\t{\n\t\tconst prefix string = \",\\\"tags\\\":\"\n\t\tout.RawString(prefix)\n\t\tif in.Tags == nil {\n\t\t\tout.RawString(\"null\")\n\t\t} else {\n\t\t\t(*in.Tags).MarshalEasyJSON(out)\n\t\t}\n\t}\n\tif len(in.Metadata) != 0 {\n\t\tconst prefix string = \",\\\"metadata\\\":\"\n\t\tout.RawString(prefix)\n\t\t{\n\t\t\tout.RawByte('{')\n\t\t\tv2First := true\n\t\t\tfor v2Name, v2Value := range in.Metadata {\n\t\t\t\tif v2First {\n\t\t\t\t\tv2First = false\n\t\t\t\t} else {\n\t\t\t\t\tout.RawByte(',')\n\t\t\t\t}\n\t\t\t\tout.String(string(v2Name))\n\t\t\t\tout.RawByte(':')\n\t\t\t\tout.String(string(v2Value))\n\t\t\t}\n\t\t\tout.RawByte('}')\n\t\t}\n\t}\n\tout.RawByte('}')\n}\nfunc easyjson42239ddeDecodeGoK6IoK6InternalOutputJson1(in *jlexer.Lexer, out *metricEnvelope) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"type\":\n\t\t\tout.Type = string(in.String())\n\t\tcase \"data\":\n\t\t\teasyjson42239ddeDecode1(in, &out.Data)\n\t\tcase \"metric\":\n\t\t\tout.Metric = string(in.String())\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjson42239ddeEncodeGoK6IoK6InternalOutputJson1(out *jwriter.Writer, in metricEnvelope) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"type\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tout.String(string(in.Type))\n\t}\n\t{\n\t\tconst prefix string = \",\\\"data\\\":\"\n\t\tout.RawString(prefix)\n\t\teasyjson42239ddeEncode1(out, in.Data)\n\t}\n\t{\n\t\tconst prefix string = \",\\\"metric\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.String(string(in.Metric))\n\t}\n\tout.RawByte('}')\n}\n\n// MarshalEasyJSON supports easyjson.Marshaler interface\nfunc (v metricEnvelope) MarshalEasyJSON(w *jwriter.Writer) {\n\teasyjson42239ddeEncodeGoK6IoK6InternalOutputJson1(w, v)\n}\n\n// UnmarshalEasyJSON supports easyjson.Unmarshaler interface\nfunc (v *metricEnvelope) UnmarshalEasyJSON(l *jlexer.Lexer) {\n\teasyjson42239ddeDecodeGoK6IoK6InternalOutputJson1(l, v)\n}\nfunc easyjson42239ddeDecode1(in *jlexer.Lexer, out *struct {\n\tName       string               `json:\"name\"`\n\tType       metrics.MetricType   `json:\"type\"`\n\tContains   metrics.ValueType    `json:\"contains\"`\n\tThresholds metrics.Thresholds   `json:\"thresholds\"`\n\tSubmetrics []*metrics.Submetric `json:\"submetrics\"`\n}) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"name\":\n\t\t\tout.Name = string(in.String())\n\t\tcase \"type\":\n\t\t\tif data := in.UnsafeBytes(); in.Ok() {\n\t\t\t\tin.AddError((out.Type).UnmarshalText(data))\n\t\t\t}\n\t\tcase \"contains\":\n\t\t\tif data := in.UnsafeBytes(); in.Ok() {\n\t\t\t\tin.AddError((out.Contains).UnmarshalText(data))\n\t\t\t}\n\t\tcase \"thresholds\":\n\t\t\tif data := in.Raw(); in.Ok() {\n\t\t\t\tin.AddError((out.Thresholds).UnmarshalJSON(data))\n\t\t\t}\n\t\tcase \"submetrics\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t\tout.Submetrics = nil\n\t\t\t} else {\n\t\t\t\tin.Delim('[')\n\t\t\t\tif out.Submetrics == nil {\n\t\t\t\t\tif !in.IsDelim(']') {\n\t\t\t\t\t\tout.Submetrics = make([]*metrics.Submetric, 0, 8)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tout.Submetrics = []*metrics.Submetric{}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tout.Submetrics = (out.Submetrics)[:0]\n\t\t\t\t}\n\t\t\t\tfor !in.IsDelim(']') {\n\t\t\t\t\tvar v3 *metrics.Submetric\n\t\t\t\t\tif in.IsNull() {\n\t\t\t\t\t\tin.Skip()\n\t\t\t\t\t\tv3 = nil\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif v3 == nil {\n\t\t\t\t\t\t\tv3 = new(metrics.Submetric)\n\t\t\t\t\t\t}\n\t\t\t\t\t\teasyjson42239ddeDecodeGoK6IoK6Metrics(in, v3)\n\t\t\t\t\t}\n\t\t\t\t\tout.Submetrics = append(out.Submetrics, v3)\n\t\t\t\t\tin.WantComma()\n\t\t\t\t}\n\t\t\t\tin.Delim(']')\n\t\t\t}\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjson42239ddeEncode1(out *jwriter.Writer, in struct {\n\tName       string               `json:\"name\"`\n\tType       metrics.MetricType   `json:\"type\"`\n\tContains   metrics.ValueType    `json:\"contains\"`\n\tThresholds metrics.Thresholds   `json:\"thresholds\"`\n\tSubmetrics []*metrics.Submetric `json:\"submetrics\"`\n}) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"name\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tout.String(string(in.Name))\n\t}\n\t{\n\t\tconst prefix string = \",\\\"type\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.Raw((in.Type).MarshalJSON())\n\t}\n\t{\n\t\tconst prefix string = \",\\\"contains\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.Raw((in.Contains).MarshalJSON())\n\t}\n\t{\n\t\tconst prefix string = \",\\\"thresholds\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.Raw((in.Thresholds).MarshalJSON())\n\t}\n\t{\n\t\tconst prefix string = \",\\\"submetrics\\\":\"\n\t\tout.RawString(prefix)\n\t\tif in.Submetrics == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {\n\t\t\tout.RawString(\"null\")\n\t\t} else {\n\t\t\tout.RawByte('[')\n\t\t\tfor v4, v5 := range in.Submetrics {\n\t\t\t\tif v4 > 0 {\n\t\t\t\t\tout.RawByte(',')\n\t\t\t\t}\n\t\t\t\tif v5 == nil {\n\t\t\t\t\tout.RawString(\"null\")\n\t\t\t\t} else {\n\t\t\t\t\teasyjson42239ddeEncodeGoK6IoK6Metrics(out, *v5)\n\t\t\t\t}\n\t\t\t}\n\t\t\tout.RawByte(']')\n\t\t}\n\t}\n\tout.RawByte('}')\n}\nfunc easyjson42239ddeDecodeGoK6IoK6Metrics(in *jlexer.Lexer, out *metrics.Submetric) {\n\tisTopLevel := in.IsStart()\n\tif in.IsNull() {\n\t\tif isTopLevel {\n\t\t\tin.Consumed()\n\t\t}\n\t\tin.Skip()\n\t\treturn\n\t}\n\tin.Delim('{')\n\tfor !in.IsDelim('}') {\n\t\tkey := in.UnsafeFieldName(false)\n\t\tin.WantColon()\n\t\tif in.IsNull() {\n\t\t\tin.Skip()\n\t\t\tin.WantComma()\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"name\":\n\t\t\tout.Name = string(in.String())\n\t\tcase \"suffix\":\n\t\t\tout.Suffix = string(in.String())\n\t\tcase \"tags\":\n\t\t\tif in.IsNull() {\n\t\t\t\tin.Skip()\n\t\t\t\tout.Tags = nil\n\t\t\t} else {\n\t\t\t\tif out.Tags == nil {\n\t\t\t\t\tout.Tags = new(metrics.TagSet)\n\t\t\t\t}\n\t\t\t\t(*out.Tags).UnmarshalEasyJSON(in)\n\t\t\t}\n\t\tdefault:\n\t\t\tin.SkipRecursive()\n\t\t}\n\t\tin.WantComma()\n\t}\n\tin.Delim('}')\n\tif isTopLevel {\n\t\tin.Consumed()\n\t}\n}\nfunc easyjson42239ddeEncodeGoK6IoK6Metrics(out *jwriter.Writer, in metrics.Submetric) {\n\tout.RawByte('{')\n\tfirst := true\n\t_ = first\n\t{\n\t\tconst prefix string = \",\\\"name\\\":\"\n\t\tout.RawString(prefix[1:])\n\t\tout.String(string(in.Name))\n\t}\n\t{\n\t\tconst prefix string = \",\\\"suffix\\\":\"\n\t\tout.RawString(prefix)\n\t\tout.String(string(in.Suffix))\n\t}\n\t{\n\t\tconst prefix string = \",\\\"tags\\\":\"\n\t\tout.RawString(prefix)\n\t\tif in.Tags == nil {\n\t\t\tout.RawString(\"null\")\n\t\t} else {\n\t\t\t(*in.Tags).MarshalEasyJSON(out)\n\t\t}\n\t}\n\tout.RawByte('}')\n}\n"
  },
  {
    "path": "internal/output/json/json_test.go",
    "content": "package json\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc getValidator(t testing.TB, expected []string) func(io.Reader) {\n\treturn func(rawJSONLines io.Reader) {\n\t\ts := bufio.NewScanner(rawJSONLines)\n\t\ti := 0\n\t\tfor s.Scan() {\n\t\t\ti++\n\t\t\tif i > len(expected) {\n\t\t\t\tt.Errorf(\"Read unexpected line number %d, expected only %d entries\", i, len(expected))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tassert.JSONEq(t, expected[i-1], string(s.Bytes()))\n\t\t}\n\t\tassert.NoError(t, s.Err())\n\t\tassert.Equal(t, len(expected), i)\n\t}\n}\n\nfunc generateTestMetricSamples(t testing.TB) ([]metrics.SampleContainer, func(io.Reader)) {\n\tregistry := metrics.NewRegistry()\n\n\tmetric1, err := registry.NewMetric(\"my_metric1\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\t_, err = metric1.AddSubmetric(\"a:1,b:2\")\n\trequire.NoError(t, err)\n\n\tmetric2, err := registry.NewMetric(\"my_metric2\", metrics.Counter, metrics.Data)\n\trequire.NoError(t, err)\n\n\ttime1 := time.Date(2021, time.February, 24, 13, 37, 10, 0, time.UTC)\n\ttime2 := time1.Add(10 * time.Second)\n\ttime3 := time2.Add(10 * time.Second)\n\n\tconnTags := registry.RootTagSet().With(\"key\", \"val\")\n\n\tsamples := []metrics.SampleContainer{\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: metric1,\n\t\t\t\tTags:   registry.RootTagSet().With(\"tag1\", \"val1\"),\n\t\t\t},\n\t\t\tTime:     time1,\n\t\t\tValue:    float64(1),\n\t\t\tMetadata: map[string]string{\"meta1\": \"foo\", \"meta2\": \"bar\"},\n\t\t},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: metric1,\n\t\t\t\tTags:   registry.RootTagSet().With(\"tag2\", \"val2\"),\n\t\t\t},\n\t\t\tTime:  time1,\n\t\t\tValue: float64(2),\n\t\t\t// Metadata is nil,\n\t\t},\n\t\tmetrics.ConnectedSamples{Samples: []metrics.Sample{\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: metric2,\n\t\t\t\t\tTags:   connTags,\n\t\t\t\t},\n\t\t\t\tTime:     time2,\n\t\t\t\tValue:    float64(3),\n\t\t\t\tMetadata: map[string]string{},\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: metric1,\n\t\t\t\t\tTags:   connTags,\n\t\t\t\t},\n\t\t\t\tTime:  time2,\n\t\t\t\tValue: float64(4),\n\t\t\t},\n\t\t}, Time: time2, Tags: connTags},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: metric2,\n\t\t\t\tTags:   registry.RootTagSet().With(\"tag3\", \"val3\").With(\"tag4\", \"val4\"),\n\t\t\t},\n\t\t\tTime:     time3,\n\t\t\tValue:    float64(5),\n\t\t\tMetadata: map[string]string{\"meta3\": \"metaval3\"},\n\t\t},\n\t}\n\texpected := []string{\n\t\t`{\"type\":\"Metric\",\"data\":{\"name\":\"my_metric1\",\"type\":\"gauge\",\"contains\":\"default\",\"thresholds\":[\"rate<0.01\",\"p(99)<250\"],\"submetrics\":[{\"name\":\"my_metric1{a:1,b:2}\",\"suffix\":\"a:1,b:2\",\"tags\":{\"a\":\"1\",\"b\":\"2\"}}]},\"metric\":\"my_metric1\"}`,\n\t\t`{\"type\":\"Point\",\"data\":{\"time\":\"2021-02-24T13:37:10Z\",\"value\":1,\"tags\":{\"tag1\":\"val1\"},\"metadata\":{\"meta1\":\"foo\",\"meta2\":\"bar\"}},\"metric\":\"my_metric1\"}`,\n\t\t`{\"type\":\"Point\",\"data\":{\"time\":\"2021-02-24T13:37:10Z\",\"value\":2,\"tags\":{\"tag2\":\"val2\"}},\"metric\":\"my_metric1\"}`,\n\t\t`{\"type\":\"Metric\",\"data\":{\"name\":\"my_metric2\",\"type\":\"counter\",\"contains\":\"data\",\"thresholds\":[],\"submetrics\":null},\"metric\":\"my_metric2\"}`,\n\t\t`{\"type\":\"Point\",\"data\":{\"time\":\"2021-02-24T13:37:20Z\",\"value\":3,\"tags\":{\"key\":\"val\"}},\"metric\":\"my_metric2\"}`,\n\t\t`{\"type\":\"Point\",\"data\":{\"time\":\"2021-02-24T13:37:20Z\",\"value\":4,\"tags\":{\"key\":\"val\"}},\"metric\":\"my_metric1\"}`,\n\t\t`{\"type\":\"Point\",\"data\":{\"time\":\"2021-02-24T13:37:30Z\",\"value\":5,\"tags\":{\"tag3\":\"val3\",\"tag4\":\"val4\"},\"metadata\":{\"meta3\":\"metaval3\"}},\"metric\":\"my_metric2\"}`,\n\t}\n\n\treturn samples, getValidator(t, expected)\n}\n\nfunc TestJsonOutputStdout(t *testing.T) {\n\tt.Parallel()\n\n\tstdout := new(bytes.Buffer)\n\tout, err := New(output.Params{\n\t\tLogger: testutils.NewLogger(t),\n\t\tStdOut: stdout,\n\t})\n\trequire.NoError(t, err)\n\n\tsetThresholds(t, out)\n\trequire.NoError(t, out.Start())\n\n\tsamples, validateResults := generateTestMetricSamples(t)\n\tout.AddMetricSamples(samples[:2])\n\tout.AddMetricSamples(samples[2:])\n\trequire.NoError(t, out.Stop())\n\tvalidateResults(stdout)\n}\n\nfunc TestJsonOutputFileError(t *testing.T) {\n\tt.Parallel()\n\n\tstdout := new(bytes.Buffer)\n\tfs := fsext.NewReadOnlyFs(fsext.NewMemMapFs())\n\tout, err := New(output.Params{\n\t\tLogger:         testutils.NewLogger(t),\n\t\tStdOut:         stdout,\n\t\tFS:             fs,\n\t\tConfigArgument: \"/json-output\",\n\t})\n\trequire.NoError(t, err)\n\tassert.Error(t, out.Start())\n}\n\nfunc TestJsonOutputFile(t *testing.T) {\n\tt.Parallel()\n\n\tstdout := new(bytes.Buffer)\n\tfs := fsext.NewMemMapFs()\n\tout, err := New(output.Params{\n\t\tLogger:         testutils.NewLogger(t),\n\t\tStdOut:         stdout,\n\t\tFS:             fs,\n\t\tConfigArgument: \"/json-output\",\n\t})\n\trequire.NoError(t, err)\n\n\tsetThresholds(t, out)\n\trequire.NoError(t, out.Start())\n\n\tsamples, validateResults := generateTestMetricSamples(t)\n\tout.AddMetricSamples(samples[:2])\n\tout.AddMetricSamples(samples[2:])\n\trequire.NoError(t, out.Stop())\n\n\tassert.Empty(t, stdout.Bytes())\n\tfile, err := fs.Open(\"/json-output\")\n\trequire.NoError(t, err)\n\tvalidateResults(file)\n\tassert.NoError(t, file.Close())\n}\n\nfunc TestJsonOutputFileGzipped(t *testing.T) {\n\tt.Parallel()\n\n\tstdout := new(bytes.Buffer)\n\tfs := fsext.NewMemMapFs()\n\tout, err := New(output.Params{\n\t\tLogger:         testutils.NewLogger(t),\n\t\tStdOut:         stdout,\n\t\tFS:             fs,\n\t\tConfigArgument: \"/json-output.gz\",\n\t})\n\trequire.NoError(t, err)\n\n\tsetThresholds(t, out)\n\trequire.NoError(t, out.Start())\n\n\tsamples, validateResults := generateTestMetricSamples(t)\n\tout.AddMetricSamples(samples[:2])\n\tout.AddMetricSamples(samples[2:])\n\trequire.NoError(t, out.Stop())\n\n\tassert.Empty(t, stdout.Bytes())\n\tfile, err := fs.Open(\"/json-output.gz\")\n\trequire.NoError(t, err)\n\treader, err := gzip.NewReader(file)\n\trequire.NoError(t, err)\n\tvalidateResults(reader)\n\tassert.NoError(t, file.Close())\n}\n\nfunc TestWrapSampleWithSamplePointer(t *testing.T) {\n\tt.Parallel()\n\tout := wrapSample(metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: &metrics.Metric{},\n\t\t},\n\t})\n\tassert.NotEqual(t, (*sampleEnvelope)(nil), out)\n}\n\nfunc setThresholds(t *testing.T, out output.Output) {\n\tt.Helper()\n\n\tjout, ok := out.(*Output)\n\trequire.True(t, ok)\n\n\tts := metrics.NewThresholds([]string{\"rate<0.01\", \"p(99)<250\"})\n\tjout.SetThresholds(map[string]metrics.Thresholds{\"my_metric1\": ts})\n}\n"
  },
  {
    "path": "internal/output/json/wrapper.go",
    "content": "package json\n\nimport (\n\t\"time\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\n//go:generate easyjson -pkg -no_std_marshalers -gen_build_flags -mod=mod .\n\n//easyjson:json\ntype sampleEnvelope struct {\n\tMetric string `json:\"metric\"`\n\tType   string `json:\"type\"`\n\tData   struct {\n\t\tTime     time.Time         `json:\"time\"`\n\t\tValue    float64           `json:\"value\"`\n\t\tTags     *metrics.TagSet   `json:\"tags\"`\n\t\tMetadata map[string]string `json:\"metadata,omitempty\"`\n\t} `json:\"data\"`\n}\n\n// wrapSample is used to package a metric sample in a way that's nice to export\n// to JSON and backwards-compatible.\nfunc wrapSample(sample metrics.Sample) sampleEnvelope {\n\ts := sampleEnvelope{\n\t\tType:   \"Point\",\n\t\tMetric: sample.Metric.Name,\n\t}\n\ts.Data.Time = sample.Time\n\ts.Data.Value = sample.Value\n\ts.Data.Tags = sample.Tags\n\ts.Data.Metadata = sample.Metadata\n\treturn s\n}\n\n//easyjson:json\ntype metricEnvelope struct {\n\tType string `json:\"type\"`\n\tData struct {\n\t\tName       string               `json:\"name\"`\n\t\tType       metrics.MetricType   `json:\"type\"`\n\t\tContains   metrics.ValueType    `json:\"contains\"`\n\t\tThresholds metrics.Thresholds   `json:\"thresholds\"`\n\t\tSubmetrics []*metrics.Submetric `json:\"submetrics\"`\n\t} `json:\"data\"`\n\tMetric string `json:\"metric\"`\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/attribute.go",
    "content": "package opentelemetry\n\nimport (\n\t\"github.com/mstoykov/atlas\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.opentelemetry.io/otel/attribute\"\n)\n\n// newAttributeSet converts a k6 tag set into\n// the equivalent set of opentelemetry attributes\nfunc newAttributeSet(t *metrics.TagSet) attribute.Set {\n\tn := (*atlas.Node)(t)\n\tif n.Len() < 1 {\n\t\treturn *attribute.EmptySet()\n\t}\n\tlabels := make([]attribute.KeyValue, 0, n.Len())\n\tfor !n.IsRoot() {\n\t\tprev, key, value := n.Data()\n\t\tn = prev\n\t\tif key == \"\" || value == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tlabels = append(labels, attribute.String(key, value))\n\t}\n\n\treturn attribute.NewSet(labels...)\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/config.go",
    "content": "package opentelemetry\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nconst (\n\t// grpcExporterType GRPC exporter type\n\t//\n\t// Deprecated: use grpcExporterProtocol\n\tgrpcExporterType = \"grpc\"\n\t// httpExporterType HTTP exporter type\n\t//\n\t// Deprecated: use httpExporterProtocol\n\thttpExporterType = \"http\"\n\n\t// grpcExporterProtocol GRPC exporter type\n\tgrpcExporterProtocol = \"grpc\"\n\t// httpExporterProtocol HTTP exporter type\n\thttpExporterProtocol = \"http/protobuf\"\n)\n\n// Config represents the configuration for the OpenTelemetry output\ntype Config struct {\n\t// ServiceName is the name of the service to use for the metrics\n\t// export, if not set it will use \"k6\"\n\tServiceName null.String `json:\"serviceName\" envconfig:\"K6_OTEL_SERVICE_NAME\"`\n\t// ServiceVersion is the version of the service to use for the metrics\n\t// export, if not set it will use k6's library version\n\tServiceVersion null.String `json:\"serviceVersion\" envconfig:\"K6_OTEL_SERVICE_VERSION\"`\n\t// MetricPrefix is the prefix to use for the metrics\n\tMetricPrefix null.String `json:\"metricPrefix\" envconfig:\"K6_OTEL_METRIC_PREFIX\"`\n\t// FlushInterval is the interval at which to flush metrics from the k6\n\tFlushInterval types.NullDuration `json:\"flushInterval\" envconfig:\"K6_OTEL_FLUSH_INTERVAL\"`\n\n\t// ExporterType sets the type of OpenTelemetry Exporter to use\n\t//\n\t// Deprecated: use ExporterProtocol\n\tExporterType null.String `json:\"exporterType\" envconfig:\"K6_OTEL_EXPORTER_TYPE\"`\n\t// ExporterProtocol sets the protocol of OpenTelemetry Exporter to use\n\tExporterProtocol null.String `json:\"exporterProtocol\" envconfig:\"K6_OTEL_EXPORTER_PROTOCOL\"`\n\t// ExportInterval configures the intervening time between metrics exports\n\tExportInterval types.NullDuration `json:\"exportInterval\" envconfig:\"K6_OTEL_EXPORT_INTERVAL\"`\n\n\t// Headers in W3C Correlation-Context format without additional semi-colon delimited metadata (i.e. \"k1=v1,k2=v2\")\n\tHeaders null.String `json:\"headers\" envconfig:\"K6_OTEL_HEADERS\"`\n\n\t// TLSInsecureSkipVerify disables verification of the server's certificate chain\n\tTLSInsecureSkipVerify null.Bool `json:\"tlsInsecureSkipVerify\" envconfig:\"K6_OTEL_TLS_INSECURE_SKIP_VERIFY\"`\n\t// TLSCertificate is the path to the certificate file (rootCAs) to use for the exporter's TLS connection\n\tTLSCertificate null.String `json:\"tlsCertificate\" envconfig:\"K6_OTEL_TLS_CERTIFICATE\"`\n\t// TLSClientCertificate is the path to the certificate file (must be PEM encoded data)\n\t// to use for the exporter's TLS connection\n\tTLSClientCertificate null.String `json:\"tlsClientCertificate\" envconfig:\"K6_OTEL_TLS_CLIENT_CERTIFICATE\"`\n\t// TLSClientKey is the path to the private key file (must be PEM encoded data) to use for the exporter's TLS connection\n\tTLSClientKey null.String `json:\"tlsClientKey\" envconfig:\"K6_OTEL_TLS_CLIENT_KEY\"`\n\n\t// HTTPExporterInsecure disables client transport security for the Exporter's HTTP\n\t// connection.\n\tHTTPExporterInsecure null.Bool `json:\"httpExporterInsecure\" envconfig:\"K6_OTEL_HTTP_EXPORTER_INSECURE\"`\n\t// HTTPExporterEndpoint sets the target endpoint the OpenTelemetry Exporter\n\t// will connect to.\n\tHTTPExporterEndpoint null.String `json:\"httpExporterEndpoint\" envconfig:\"K6_OTEL_HTTP_EXPORTER_ENDPOINT\"`\n\t// HTTPExporterURLPath sets the target URL path the OpenTelemetry Exporter\n\tHTTPExporterURLPath null.String `json:\"httpExporterURLPath\" envconfig:\"K6_OTEL_HTTP_EXPORTER_URL_PATH\"`\n\n\t// GRPCExporterEndpoint sets the target endpoint the OpenTelemetry Exporter\n\t// will connect to.\n\tGRPCExporterEndpoint null.String `json:\"grpcExporterEndpoint\" envconfig:\"K6_OTEL_GRPC_EXPORTER_ENDPOINT\"`\n\t// GRPCExporterInsecure disables client transport security for the Exporter's gRPC\n\t// connection.\n\tGRPCExporterInsecure null.Bool `json:\"grpcExporterInsecure\" envconfig:\"K6_OTEL_GRPC_EXPORTER_INSECURE\"`\n\n\t// SingleCounterForRate sets the feature flag defining how to export metrics defined as Rate type.\n\t// When it is set to true, metrics are exported as a single counter, using an attribute as discriminator.\n\t// When the opposite, the old method is used generating two different counters.\n\tSingleCounterForRate null.Bool `json:\"singleCounterForRate\" envconfig:\"K6_OTEL_SINGLE_COUNTER_FOR_RATE\"`\n}\n\n// GetConsolidatedConfig combines the options' values from the different sources\n// and returns the merged options. The Order of precedence used is documented\n// in the k6 Documentation https://grafana.com/docs/k6/latest/using-k6/k6-options/how-to/#order-of-precedence.\nfunc GetConsolidatedConfig(jsonRawConf json.RawMessage, env map[string]string) (Config, error) {\n\tcfg := newDefaultConfig()\n\tif jsonRawConf != nil {\n\t\tjsonConf, err := parseJSON(jsonRawConf)\n\t\tif err != nil {\n\t\t\treturn cfg, fmt.Errorf(\"parse JSON options failed: %w\", err)\n\t\t}\n\t\tcfg = cfg.Apply(jsonConf)\n\t}\n\n\tif len(env) > 0 {\n\t\tenvConf, err := parseEnvs(env)\n\t\tif err != nil {\n\t\t\treturn cfg, fmt.Errorf(\"parse environment variables options failed: %w\", err)\n\t\t}\n\t\tcfg = cfg.Apply(envConf)\n\t}\n\n\tif err := cfg.Validate(); err != nil {\n\t\t// TODO: check why k6's still exiting with 255\n\t\treturn cfg, errext.WithExitCodeIfNone(\n\t\t\tfmt.Errorf(\"error validating OpenTelemetry output config: %w\", err),\n\t\t\texitcodes.InvalidConfig,\n\t\t)\n\t}\n\n\treturn cfg, nil\n}\n\n// newDefaultConfig creates a new default config with default values\nfunc newDefaultConfig() Config {\n\treturn Config{\n\t\tServiceName:      null.NewString(\"k6\", false),\n\t\tServiceVersion:   null.NewString(build.Version, false),\n\t\tExporterProtocol: null.NewString(grpcExporterProtocol, false),\n\n\t\tHTTPExporterInsecure: null.NewBool(false, false),\n\t\tHTTPExporterEndpoint: null.NewString(\"localhost:4318\", false),\n\t\tHTTPExporterURLPath:  null.NewString(\"/v1/metrics\", false),\n\n\t\tGRPCExporterInsecure: null.NewBool(false, false),\n\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", false),\n\n\t\tExportInterval: types.NewNullDuration(10*time.Second, false),\n\t\tFlushInterval:  types.NewNullDuration(1*time.Second, false),\n\n\t\tSingleCounterForRate: null.NewBool(true, false),\n\t}\n}\n\n// Apply applies the new config to the existing one\nfunc (cfg Config) Apply(v Config) Config {\n\tif v.ServiceName.Valid {\n\t\tcfg.ServiceName = v.ServiceName\n\t}\n\n\tif v.ServiceVersion.Valid {\n\t\tcfg.ServiceVersion = v.ServiceVersion\n\t}\n\n\tif v.MetricPrefix.Valid {\n\t\tcfg.MetricPrefix = v.MetricPrefix\n\t}\n\n\tif v.FlushInterval.Valid {\n\t\tcfg.FlushInterval = v.FlushInterval\n\t}\n\n\tif v.ExporterProtocol.Valid {\n\t\tcfg.ExporterProtocol = v.ExporterProtocol\n\t}\n\n\tif v.ExporterType.Valid {\n\t\tcfg.ExporterType = v.ExporterType\n\t}\n\n\tif v.ExportInterval.Valid {\n\t\tcfg.ExportInterval = v.ExportInterval\n\t}\n\n\tif v.HTTPExporterInsecure.Valid {\n\t\tcfg.HTTPExporterInsecure = v.HTTPExporterInsecure\n\t}\n\n\tif v.HTTPExporterEndpoint.Valid {\n\t\tcfg.HTTPExporterEndpoint = v.HTTPExporterEndpoint\n\t}\n\n\tif v.HTTPExporterURLPath.Valid {\n\t\tcfg.HTTPExporterURLPath = v.HTTPExporterURLPath\n\t}\n\n\tif v.GRPCExporterEndpoint.Valid {\n\t\tcfg.GRPCExporterEndpoint = v.GRPCExporterEndpoint\n\t}\n\n\tif v.GRPCExporterInsecure.Valid {\n\t\tcfg.GRPCExporterInsecure = v.GRPCExporterInsecure\n\t}\n\n\tif v.TLSInsecureSkipVerify.Valid {\n\t\tcfg.TLSInsecureSkipVerify = v.TLSInsecureSkipVerify\n\t}\n\n\tif v.TLSCertificate.Valid {\n\t\tcfg.TLSCertificate = v.TLSCertificate\n\t}\n\n\tif v.TLSClientCertificate.Valid {\n\t\tcfg.TLSClientCertificate = v.TLSClientCertificate\n\t}\n\n\tif v.TLSClientKey.Valid {\n\t\tcfg.TLSClientKey = v.TLSClientKey\n\t}\n\n\tif v.Headers.Valid {\n\t\tcfg.Headers = v.Headers\n\t}\n\n\tif v.SingleCounterForRate.Valid {\n\t\tcfg.SingleCounterForRate = v.SingleCounterForRate\n\t}\n\n\treturn cfg\n}\n\n// Validate validates the config\nfunc (cfg Config) Validate() error {\n\tif cfg.ServiceName.String == \"\" {\n\t\treturn errors.New(\"providing service name is required\")\n\t}\n\t// TODO: it's not actually required, but we should probably have a default\n\t// check if it works without it\n\tif cfg.ServiceVersion.String == \"\" {\n\t\treturn errors.New(\"providing service version is required\")\n\t}\n\tif err := cfg.validateExporterProtocol(); err != nil {\n\t\treturn err\n\t}\n\tif err := cfg.validateExporterType(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (cfg Config) validateExporterType() error {\n\tif cfg.ExporterType.String != \"\" {\n\t\tif cfg.ExporterType.String != httpExporterType && cfg.ExporterType.String != grpcExporterType {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"unsupported exporter type %q, only %q and %q are supported\",\n\t\t\t\tcfg.ExporterType.String,\n\t\t\t\tgrpcExporterType,\n\t\t\t\thttpExporterType,\n\t\t\t)\n\t\t}\n\t\tswitch cfg.ExporterType.String {\n\t\tcase grpcExporterType:\n\t\t\tif cfg.GRPCExporterEndpoint.String == \"\" {\n\t\t\t\treturn errors.New(\"gRPC exporter endpoint is required\")\n\t\t\t}\n\t\tcase httpExporterType:\n\t\t\tendpoint := cfg.HTTPExporterEndpoint.String\n\t\t\tif endpoint == \"\" {\n\t\t\t\treturn errors.New(\"HTTP exporter endpoint is required\")\n\t\t\t}\n\n\t\t\tif strings.HasPrefix(endpoint, \"http://\") ||\n\t\t\t\tstrings.HasPrefix(endpoint, \"https://\") {\n\t\t\t\treturn errors.New(\"HTTP exporter endpoint must only be host and port, no scheme\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (cfg Config) validateExporterProtocol() error {\n\tif cfg.ExporterProtocol.String != \"\" {\n\t\tif cfg.ExporterProtocol.String != grpcExporterProtocol && cfg.ExporterProtocol.String != httpExporterProtocol {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"unsupported exporter protocol %q, only %q and %q are supported\",\n\t\t\t\tcfg.ExporterProtocol.String,\n\t\t\t\tgrpcExporterProtocol,\n\t\t\t\thttpExporterProtocol,\n\t\t\t)\n\t\t}\n\t\tswitch cfg.ExporterProtocol.String {\n\t\tcase grpcExporterProtocol:\n\t\t\tif cfg.GRPCExporterEndpoint.String == \"\" {\n\t\t\t\treturn errors.New(\"gRPC exporter endpoint is required\")\n\t\t\t}\n\t\tcase httpExporterProtocol:\n\t\t\tendpoint := cfg.HTTPExporterEndpoint.String\n\t\t\tif endpoint == \"\" {\n\t\t\t\treturn errors.New(\"HTTP exporter endpoint is required\")\n\t\t\t}\n\n\t\t\tif strings.HasPrefix(endpoint, \"http://\") ||\n\t\t\t\tstrings.HasPrefix(endpoint, \"https://\") {\n\t\t\t\treturn errors.New(\"HTTP exporter endpoint must only be host and port, no scheme\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// String returns a string representation of the config\nfunc (cfg Config) String() string {\n\tvar endpoint string\n\tprotocol := mergeExporterTypeAndProtocol(cfg)\n\tswitch protocol {\n\tcase httpExporterProtocol:\n\t\tendpoint = \"http\"\n\t\tif !cfg.HTTPExporterInsecure.Bool {\n\t\t\tendpoint += \"s\"\n\t\t}\n\t\tendpoint += \"://\" + cfg.HTTPExporterEndpoint.String + cfg.HTTPExporterURLPath.String\n\tcase grpcExporterProtocol:\n\t\tendpoint = cfg.GRPCExporterEndpoint.String\n\t\tif cfg.GRPCExporterInsecure.Bool {\n\t\t\tprotocol += \" (insecure)\"\n\t\t}\n\tdefault:\n\t\t// This should never happen after validation\n\t\tpanic(\"unsupported OpenTelemetry exporter protocol: \" + protocol)\n\t}\n\n\treturn fmt.Sprintf(\"%s, %s\", protocol, endpoint)\n}\n\n// parseJSON parses the supplied JSON into a Config.\nfunc parseJSON(data json.RawMessage) (Config, error) {\n\tvar c Config\n\terr := json.Unmarshal(data, &c)\n\treturn c, err\n}\n\n// parseEnvs parses the supplied environment variables into a Config.\nfunc parseEnvs(env map[string]string) (Config, error) {\n\tcfg := Config{}\n\n\tif serviceName, ok := env[\"OTEL_SERVICE_NAME\"]; ok {\n\t\tcfg.ServiceName = null.StringFrom(serviceName)\n\t}\n\n\terr := envconfig.Process(\"K6_OTEL_\", &cfg, func(key string) (string, bool) {\n\t\tv, ok := env[key]\n\t\treturn v, ok\n\t})\n\n\treturn cfg, err\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/config_test.go",
    "content": "package opentelemetry\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestConfig(t *testing.T) {\n\tt.Parallel()\n\t// TODO: add more cases\n\ttestCases := map[string]struct {\n\t\tjsonRaw        json.RawMessage\n\t\tenv            map[string]string\n\t\targ            string\n\t\texpectedConfig Config\n\t\terr            string\n\t}{\n\t\t\"default\": {\n\t\t\texpectedConfig: Config{\n\t\t\t\tServiceName:          null.NewString(\"k6\", false),\n\t\t\t\tServiceVersion:       null.NewString(build.Version, false),\n\t\t\t\tExporterProtocol:     null.NewString(grpcExporterProtocol, false),\n\t\t\t\tHTTPExporterInsecure: null.NewBool(false, false),\n\t\t\t\tHTTPExporterEndpoint: null.NewString(\"localhost:4318\", false),\n\t\t\t\tHTTPExporterURLPath:  null.NewString(\"/v1/metrics\", false),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(false, false),\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", false),\n\t\t\t\tExportInterval:       types.NewNullDuration(10*time.Second, false),\n\t\t\t\tFlushInterval:        types.NewNullDuration(1*time.Second, false),\n\t\t\t\tSingleCounterForRate: null.NewBool(true, false),\n\t\t\t},\n\t\t},\n\n\t\t\"environment success merge\": {\n\t\t\tenv: map[string]string{\"K6_OTEL_GRPC_EXPORTER_ENDPOINT\": \"else\", \"K6_OTEL_EXPORT_INTERVAL\": \"4ms\"},\n\t\t\texpectedConfig: Config{\n\t\t\t\tServiceName:          null.NewString(\"k6\", false),\n\t\t\t\tServiceVersion:       null.NewString(build.Version, false),\n\t\t\t\tExporterProtocol:     null.NewString(grpcExporterProtocol, false),\n\t\t\t\tHTTPExporterInsecure: null.NewBool(false, false),\n\t\t\t\tHTTPExporterEndpoint: null.NewString(\"localhost:4318\", false),\n\t\t\t\tHTTPExporterURLPath:  null.NewString(\"/v1/metrics\", false),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(false, false),\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"else\", true),\n\t\t\t\tExportInterval:       types.NewNullDuration(4*time.Millisecond, true),\n\t\t\t\tFlushInterval:        types.NewNullDuration(1*time.Second, false),\n\t\t\t\tSingleCounterForRate: null.NewBool(true, false),\n\t\t\t},\n\t\t},\n\n\t\t\"environment complete overwrite\": {\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_OTEL_SERVICE_NAME\":             \"foo\",\n\t\t\t\t\"K6_OTEL_SERVICE_VERSION\":          \"v0.0.99\",\n\t\t\t\t\"K6_OTEL_EXPORTER_TYPE\":            \"http\",\n\t\t\t\t\"K6_OTEL_EXPORTER_PROTOCOL\":        \"http/protobuf\",\n\t\t\t\t\"K6_OTEL_EXPORT_INTERVAL\":          \"4ms\",\n\t\t\t\t\"K6_OTEL_HTTP_EXPORTER_INSECURE\":   \"true\",\n\t\t\t\t\"K6_OTEL_HTTP_EXPORTER_ENDPOINT\":   \"localhost:5555\",\n\t\t\t\t\"K6_OTEL_HTTP_EXPORTER_URL_PATH\":   \"/foo/bar\",\n\t\t\t\t\"K6_OTEL_GRPC_EXPORTER_INSECURE\":   \"true\",\n\t\t\t\t\"K6_OTEL_GRPC_EXPORTER_ENDPOINT\":   \"else\",\n\t\t\t\t\"K6_OTEL_FLUSH_INTERVAL\":           \"13s\",\n\t\t\t\t\"K6_OTEL_TLS_INSECURE_SKIP_VERIFY\": \"true\",\n\t\t\t\t\"K6_OTEL_TLS_CERTIFICATE\":          \"cert_path\",\n\t\t\t\t\"K6_OTEL_TLS_CLIENT_CERTIFICATE\":   \"client_cert_path\",\n\t\t\t\t\"K6_OTEL_TLS_CLIENT_KEY\":           \"client_key_path\",\n\t\t\t\t\"K6_OTEL_HEADERS\":                  \"key1=value1,key2=value2\",\n\t\t\t\t\"K6_OTEL_SINGLE_COUNTER_FOR_RATE\":  \"false\",\n\t\t\t},\n\t\t\texpectedConfig: Config{\n\t\t\t\tServiceName:           null.NewString(\"foo\", true),\n\t\t\t\tServiceVersion:        null.NewString(\"v0.0.99\", true),\n\t\t\t\tExporterType:          null.NewString(httpExporterType, true),\n\t\t\t\tExporterProtocol:      null.NewString(httpExporterProtocol, true),\n\t\t\t\tExportInterval:        types.NewNullDuration(4*time.Millisecond, true),\n\t\t\t\tHTTPExporterInsecure:  null.NewBool(true, true),\n\t\t\t\tHTTPExporterEndpoint:  null.NewString(\"localhost:5555\", true),\n\t\t\t\tHTTPExporterURLPath:   null.NewString(\"/foo/bar\", true),\n\t\t\t\tGRPCExporterInsecure:  null.NewBool(true, true),\n\t\t\t\tGRPCExporterEndpoint:  null.NewString(\"else\", true),\n\t\t\t\tFlushInterval:         types.NewNullDuration(13*time.Second, true),\n\t\t\t\tTLSInsecureSkipVerify: null.NewBool(true, true),\n\t\t\t\tTLSCertificate:        null.NewString(\"cert_path\", true),\n\t\t\t\tTLSClientCertificate:  null.NewString(\"client_cert_path\", true),\n\t\t\t\tTLSClientKey:          null.NewString(\"client_key_path\", true),\n\t\t\t\tHeaders:               null.NewString(\"key1=value1,key2=value2\", true),\n\t\t\t\tSingleCounterForRate:  null.NewBool(false, true),\n\t\t\t},\n\t\t},\n\n\t\t\"OTEL environment variables\": {\n\t\t\tenv: map[string]string{\n\t\t\t\t\"OTEL_SERVICE_NAME\": \"otel-service\",\n\t\t\t},\n\t\t\texpectedConfig: Config{\n\t\t\t\tServiceName:          null.NewString(\"otel-service\", true),\n\t\t\t\tServiceVersion:       null.NewString(build.Version, false),\n\t\t\t\tExporterProtocol:     null.NewString(grpcExporterProtocol, false),\n\t\t\t\tHTTPExporterInsecure: null.NewBool(false, false),\n\t\t\t\tHTTPExporterEndpoint: null.NewString(\"localhost:4318\", false),\n\t\t\t\tHTTPExporterURLPath:  null.NewString(\"/v1/metrics\", false),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(false, false),\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", false),\n\t\t\t\tExportInterval:       types.NewNullDuration(10*time.Second, false),\n\t\t\t\tFlushInterval:        types.NewNullDuration(1*time.Second, false),\n\t\t\t\tSingleCounterForRate: null.NewBool(true, false),\n\t\t\t},\n\t\t},\n\n\t\t\"JSON complete overwrite\": {\n\t\t\tjsonRaw: json.RawMessage(\n\t\t\t\t`{` +\n\t\t\t\t\t`\"serviceName\":\"bar\",` +\n\t\t\t\t\t`\"serviceVersion\":\"v2.0.99\",` +\n\t\t\t\t\t`\"exporterType\":\"http\",` +\n\t\t\t\t\t`\"exporterProtocol\":\"http/protobuf\",` +\n\t\t\t\t\t`\"exportInterval\":\"15ms\",` +\n\t\t\t\t\t`\"httpExporterInsecure\":true,` +\n\t\t\t\t\t`\"httpExporterEndpoint\":\"localhost:5555\",` +\n\t\t\t\t\t`\"httpExporterURLPath\":\"/foo/bar\",` +\n\t\t\t\t\t`\"grpcExporterInsecure\":true,` +\n\t\t\t\t\t`\"grpcExporterEndpoint\":\"else\",` +\n\t\t\t\t\t`\"flushInterval\":\"13s\",` +\n\t\t\t\t\t`\"tlsInsecureSkipVerify\":true,` +\n\t\t\t\t\t`\"tlsCertificate\":\"cert_path\",` +\n\t\t\t\t\t`\"tlsClientCertificate\":\"client_cert_path\",` +\n\t\t\t\t\t`\"tlsClientKey\":\"client_key_path\",` +\n\t\t\t\t\t`\"headers\":\"key1=value1,key2=value2\",` +\n\t\t\t\t\t`\"singleCounterForRate\":false` +\n\t\t\t\t\t`}`,\n\t\t\t),\n\t\t\texpectedConfig: Config{\n\t\t\t\tServiceName:           null.NewString(\"bar\", true),\n\t\t\t\tServiceVersion:        null.NewString(\"v2.0.99\", true),\n\t\t\t\tExporterType:          null.NewString(httpExporterType, true),\n\t\t\t\tExporterProtocol:      null.NewString(httpExporterProtocol, true),\n\t\t\t\tExportInterval:        types.NewNullDuration(15*time.Millisecond, true),\n\t\t\t\tHTTPExporterInsecure:  null.NewBool(true, true),\n\t\t\t\tHTTPExporterEndpoint:  null.NewString(\"localhost:5555\", true),\n\t\t\t\tHTTPExporterURLPath:   null.NewString(\"/foo/bar\", true),\n\t\t\t\tGRPCExporterInsecure:  null.NewBool(true, true),\n\t\t\t\tGRPCExporterEndpoint:  null.NewString(\"else\", true),\n\t\t\t\tFlushInterval:         types.NewNullDuration(13*time.Second, true),\n\t\t\t\tTLSInsecureSkipVerify: null.NewBool(true, true),\n\t\t\t\tTLSCertificate:        null.NewString(\"cert_path\", true),\n\t\t\t\tTLSClientCertificate:  null.NewString(\"client_cert_path\", true),\n\t\t\t\tTLSClientKey:          null.NewString(\"client_key_path\", true),\n\t\t\t\tHeaders:               null.NewString(\"key1=value1,key2=value2\", true),\n\t\t\t\tSingleCounterForRate:  null.NewBool(false, true),\n\t\t\t},\n\t\t},\n\n\t\t\"JSON success merge\": {\n\t\t\tjsonRaw: json.RawMessage(`{\"exporterType\":\"http\",\"httpExporterEndpoint\":\"localhost:5566\",\"httpExporterURLPath\":\"/lorem/ipsum\",\"exportInterval\":\"15ms\"}`),\n\t\t\texpectedConfig: Config{\n\t\t\t\tServiceName:          null.NewString(\"k6\", false),\n\t\t\t\tServiceVersion:       null.NewString(build.Version, false),\n\t\t\t\tExporterType:         null.NewString(httpExporterType, true),\n\t\t\t\tExporterProtocol:     null.NewString(grpcExporterType, false),\n\t\t\t\tHTTPExporterInsecure: null.NewBool(false, false),\n\t\t\t\tHTTPExporterEndpoint: null.NewString(\"localhost:5566\", true),\n\t\t\t\tHTTPExporterURLPath:  null.NewString(\"/lorem/ipsum\", true),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(false, false),              // default\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", false), // default\n\t\t\t\tExportInterval:       types.NewNullDuration(15*time.Millisecond, true),\n\t\t\t\tFlushInterval:        types.NewNullDuration(1*time.Second, false),\n\t\t\t\tSingleCounterForRate: null.NewBool(true, false),\n\t\t\t},\n\t\t},\n\t\t\"no scheme in http exporter protocol\": {\n\t\t\tjsonRaw: json.RawMessage(`{\"exporterProtocol\":\"http/protobuf\",\"httpExporterEndpoint\":\"http://localhost:5566\",\"httpExporterURLPath\":\"/lorem/ipsum\", \"exportInterval\":\"15ms\"}`),\n\t\t\terr:     `config: HTTP exporter endpoint must only be host and port, no scheme`,\n\t\t},\n\n\t\t\"no scheme in http exporter type\": {\n\t\t\tjsonRaw: json.RawMessage(`{\"exporterType\":\"http\",\"httpExporterEndpoint\":\"http://localhost:5566\",\"httpExporterURLPath\":\"/lorem/ipsum\", \"exportInterval\":\"15ms\"}`),\n\t\t\terr:     `config: HTTP exporter endpoint must only be host and port, no scheme`,\n\t\t},\n\n\t\t\"early error env\": {\n\t\t\tenv: map[string]string{\"K6_OTEL_GRPC_EXPORTER_ENDPOINT\": \"else\", \"K6_OTEL_EXPORT_INTERVAL\": \"4something\"},\n\t\t\terr: `time: unknown unit \"something\" in duration \"4something\"`,\n\t\t},\n\n\t\t\"early error JSON\": {\n\t\t\tjsonRaw: json.RawMessage(`{\"exportInterval\":\"4something\"}`),\n\t\t\terr:     `time: unknown unit \"something\" in duration \"4something\"`,\n\t\t},\n\n\t\t\"unsupported exporter type\": {\n\t\t\tenv: map[string]string{\"K6_OTEL_GRPC_EXPORTER_ENDPOINT\": \"else\", \"K6_OTEL_EXPORT_INTERVAL\": \"4m\", \"K6_OTEL_EXPORTER_TYPE\": \"socket\"},\n\t\t\terr: `error validating OpenTelemetry output config: unsupported exporter type \"socket\", only \"grpc\" and \"http\" are supported`,\n\t\t},\n\n\t\t\"unsupported exporter protocol\": {\n\t\t\tenv: map[string]string{\"K6_OTEL_GRPC_EXPORTER_ENDPOINT\": \"else\", \"K6_OTEL_EXPORT_INTERVAL\": \"4m\", \"K6_OTEL_EXPORTER_PROTOCOL\": \"socket\"},\n\t\t\terr: `error validating OpenTelemetry output config: unsupported exporter protocol \"socket\", only \"grpc\" and \"http/protobuf\" are supported`,\n\t\t},\n\n\t\t\"missing required\": {\n\t\t\tjsonRaw: json.RawMessage(`{\"exporterType\":\"http\",\"httpExporterEndpoint\":\"\",\"httpExporterURLPath\":\"/lorem/ipsum\"}`),\n\t\t\terr:     `HTTP exporter endpoint is required`,\n\t\t},\n\t}\n\n\tfor name, testCase := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tconfig, err := GetConsolidatedConfig(testCase.jsonRaw, testCase.env)\n\t\t\tif testCase.err != \"\" {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), testCase.err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, testCase.expectedConfig, config)\n\t\t})\n\t}\n}\n\nfunc TestConfigString(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := map[string]struct {\n\t\tconfig   Config\n\t\texpected string\n\t}{\n\t\t\"default grpc\": {\n\t\t\tconfig: Config{\n\t\t\t\tExporterProtocol:     null.NewString(grpcExporterProtocol, false),\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", false),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(false, false),\n\t\t\t},\n\t\t\texpected: \"grpc, localhost:4317\",\n\t\t},\n\t\t\"grpc with ExporterProtocol set\": {\n\t\t\tconfig: Config{\n\t\t\t\tExporterProtocol:     null.NewString(grpcExporterProtocol, true),\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", true),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(false, true),\n\t\t\t},\n\t\t\texpected: \"grpc, localhost:4317\",\n\t\t},\n\t\t\"grpc insecure with ExporterProtocol set\": {\n\t\t\tconfig: Config{\n\t\t\t\tExporterProtocol:     null.NewString(grpcExporterProtocol, true),\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", true),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(true, true),\n\t\t\t},\n\t\t\texpected: \"grpc (insecure), localhost:4317\",\n\t\t},\n\t\t\"http/protobuf with ExporterProtocol set\": {\n\t\t\tconfig: Config{\n\t\t\t\tExporterProtocol:     null.NewString(httpExporterProtocol, true),\n\t\t\t\tHTTPExporterEndpoint: null.NewString(\"localhost:4318\", true),\n\t\t\t\tHTTPExporterURLPath:  null.NewString(\"/v1/metrics\", true),\n\t\t\t\tHTTPExporterInsecure: null.NewBool(false, true),\n\t\t\t},\n\t\t\texpected: \"http/protobuf, https://localhost:4318/v1/metrics\",\n\t\t},\n\t\t\"http/protobuf insecure with ExporterProtocol set\": {\n\t\t\tconfig: Config{\n\t\t\t\tExporterProtocol:     null.NewString(httpExporterProtocol, true),\n\t\t\t\tHTTPExporterEndpoint: null.NewString(\"localhost:4318\", true),\n\t\t\t\tHTTPExporterURLPath:  null.NewString(\"/v1/metrics\", true),\n\t\t\t\tHTTPExporterInsecure: null.NewBool(true, true),\n\t\t\t},\n\t\t\texpected: \"http/protobuf, http://localhost:4318/v1/metrics\",\n\t\t},\n\t\t\"deprecated ExporterType http\": {\n\t\t\tconfig: Config{\n\t\t\t\tExporterType:         null.NewString(httpExporterType, true),\n\t\t\t\tHTTPExporterEndpoint: null.NewString(\"localhost:4318\", true),\n\t\t\t\tHTTPExporterURLPath:  null.NewString(\"/v1/metrics\", true),\n\t\t\t\tHTTPExporterInsecure: null.NewBool(false, true),\n\t\t\t},\n\t\t\texpected: \"http/protobuf, https://localhost:4318/v1/metrics\",\n\t\t},\n\t\t\"deprecated ExporterType grpc\": {\n\t\t\tconfig: Config{\n\t\t\t\tExporterType:         null.NewString(grpcExporterType, true),\n\t\t\t\tGRPCExporterEndpoint: null.NewString(\"localhost:4317\", true),\n\t\t\t\tGRPCExporterInsecure: null.NewBool(false, true),\n\t\t\t},\n\t\t\texpected: \"grpc, localhost:4317\",\n\t\t},\n\t}\n\n\tfor name, testCase := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tresult := testCase.config.String()\n\t\t\trequire.Equal(t, testCase.expected, result)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/exporter.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc\"\n\t\"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp\"\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\t\"google.golang.org/grpc/credentials\"\n)\n\nfunc getExporter(cfg Config) (metric.Exporter, error) {\n\t// at the point of writing this code\n\t// ctx isn't used at any point in the exporter\n\t// later on, it could be used for the connection timeout\n\tctx := context.Background()\n\n\ttlsConfig, err := buildTLSConfig(\n\t\tcfg.TLSInsecureSkipVerify,\n\t\tcfg.TLSCertificate,\n\t\tcfg.TLSClientCertificate,\n\t\tcfg.TLSClientKey,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar headers map[string]string\n\tif cfg.Headers.Valid {\n\t\theaders, err = parseHeaders(cfg.Headers.String)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse headers: %w\", err)\n\t\t}\n\t}\n\n\t// TODO: drop the merge when the deprecated exporter type is fully removed\n\tprotocol := mergeExporterTypeAndProtocol(cfg)\n\n\tswitch protocol {\n\tcase grpcExporterProtocol:\n\t\treturn buildGRPCExporter(ctx, cfg, tlsConfig, headers)\n\tcase httpExporterProtocol:\n\t\treturn buildHTTPExporter(ctx, cfg, tlsConfig, headers)\n\tdefault:\n\t\treturn nil, errors.New(\"unsupported exporter protocol \" + cfg.ExporterProtocol.String)\n\t}\n}\n\nfunc mergeExporterTypeAndProtocol(cfg Config) string {\n\tif cfg.ExporterProtocol.Valid {\n\t\treturn cfg.ExporterProtocol.String\n\t}\n\tif cfg.ExporterType.Valid {\n\t\tswitch cfg.ExporterType.String {\n\t\tcase httpExporterType:\n\t\t\treturn httpExporterProtocol\n\t\tcase grpcExporterType:\n\t\t\treturn grpcExporterProtocol\n\t\tdefault:\n\t\t\treturn cfg.ExporterType.String\n\t\t}\n\t}\n\t// return the default value\n\treturn cfg.ExporterProtocol.String\n}\n\nfunc buildHTTPExporter(\n\tctx context.Context,\n\tcfg Config,\n\ttlsConfig *tls.Config,\n\theaders map[string]string,\n) (metric.Exporter, error) {\n\topts := []otlpmetrichttp.Option{\n\t\totlpmetrichttp.WithEndpoint(cfg.HTTPExporterEndpoint.String),\n\t\totlpmetrichttp.WithURLPath(cfg.HTTPExporterURLPath.String),\n\t}\n\n\tif cfg.HTTPExporterInsecure.Bool {\n\t\topts = append(opts, otlpmetrichttp.WithInsecure())\n\t}\n\n\tif len(headers) > 0 {\n\t\topts = append(opts, otlpmetrichttp.WithHeaders(headers))\n\t}\n\n\tif tlsConfig != nil {\n\t\topts = append(opts, otlpmetrichttp.WithTLSClientConfig(tlsConfig))\n\t}\n\n\treturn otlpmetrichttp.New(ctx, opts...)\n}\n\nfunc buildGRPCExporter(\n\tctx context.Context,\n\tcfg Config,\n\ttlsConfig *tls.Config,\n\theaders map[string]string,\n) (metric.Exporter, error) {\n\topt := []otlpmetricgrpc.Option{\n\t\totlpmetricgrpc.WithEndpoint(cfg.GRPCExporterEndpoint.String),\n\t}\n\n\tif cfg.GRPCExporterInsecure.Bool {\n\t\topt = append(opt, otlpmetricgrpc.WithInsecure())\n\t}\n\n\tif len(headers) > 0 {\n\t\topt = append(opt, otlpmetricgrpc.WithHeaders(headers))\n\t}\n\n\tif tlsConfig != nil {\n\t\topt = append(opt, otlpmetricgrpc.WithTLSCredentials(credentials.NewTLS(tlsConfig)))\n\t}\n\n\treturn otlpmetricgrpc.New(ctx, opt...)\n}\n\nfunc parseHeaders(raw string) (map[string]string, error) {\n\theaders := make(map[string]string)\n\tfor header := range strings.SplitSeq(raw, \",\") {\n\t\trawKey, rawValue, ok := strings.Cut(header, \"=\")\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid header %q, expected format key=value\", header)\n\t\t}\n\n\t\tkey, err := url.PathUnescape(rawKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to unescape header key %q: %w\", rawKey, err)\n\t\t}\n\n\t\tvalue, err := url.PathUnescape(rawValue)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to unescape header value %q: %w\", rawValue, err)\n\t\t}\n\n\t\theaders[key] = value\n\t}\n\n\treturn headers, nil\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/output.go",
    "content": "// Package opentelemetry performs output operations for the opentelemetry extension\npackage opentelemetry\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.opentelemetry.io/otel/attribute\"\n\totelMetric \"go.opentelemetry.io/otel/metric\"\n\t\"go.opentelemetry.io/otel/sdk/metric\"\n\t\"go.opentelemetry.io/otel/sdk/resource\"\n\tsemconv \"go.opentelemetry.io/otel/semconv/v1.24.0\"\n\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\n// Output implements the lib.Output interface\ntype Output struct {\n\toutput.SampleBuffer\n\n\tconfig          Config\n\tperiodicFlusher *output.PeriodicFlusher\n\tlogger          logrus.FieldLogger\n\n\tmeterProvider   *metric.MeterProvider\n\tmetricsRegistry *registry\n}\n\nvar _ output.WithStopWithTestError = new(Output)\n\n// New creates an instance of the collector\nfunc New(p output.Params) (*Output, error) {\n\tconf, err := GetConsolidatedConfig(p.JSONConfig, p.Environment)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif conf.ExporterType.Valid {\n\t\tp.Logger.Warn(\"Exporter type is deprecated, please migrate to exporter protocol\")\n\t}\n\n\treturn &Output{\n\t\tconfig: conf,\n\t\tlogger: p.Logger,\n\t}, nil\n}\n\n// Description returns a human-readable description of the output that will be shown in `k6 run`\nfunc (o *Output) Description() string {\n\treturn fmt.Sprintf(\"opentelemetry (%s)\", o.config)\n}\n\n// StopWithTestError flushes all remaining metrics and finalizes the test run\nfunc (o *Output) StopWithTestError(_ error) error {\n\to.logger.Debug(\"Stopping...\")\n\tdefer o.logger.Debug(\"Stopped!\")\n\n\to.periodicFlusher.Stop()\n\n\tif err := o.meterProvider.Shutdown(context.Background()); err != nil {\n\t\to.logger.WithError(err).Error(\"can't shutdown OpenTelemetry metric provider\")\n\t}\n\n\treturn nil\n}\n\n// Stop just implements an old interface (output.Output)\nfunc (o *Output) Stop() error {\n\treturn o.StopWithTestError(nil)\n}\n\n// Start performs initialization tasks prior to Engine using the output\nfunc (o *Output) Start() error {\n\to.logger.Debug(\"Starting output...\")\n\n\tif !o.config.SingleCounterForRate.Bool {\n\t\to.logger.Warn(\"Exporting rate metrics as a pair of counters is deprecated\" +\n\t\t\t\" and will be removed in future releases. Please migrate to the new format.\")\n\t}\n\n\texp, err := getExporter(o.config)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create OpenTelemetry exporter: %w\", err)\n\t}\n\n\tres, err := resource.Merge(resource.Default(),\n\t\tresource.NewSchemaless(\n\t\t\tsemconv.ServiceName(o.config.ServiceName.String),\n\t\t\tsemconv.ServiceVersion(o.config.ServiceVersion.String),\n\t\t))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create OpenTelemetry resource: %w\", err)\n\t}\n\n\tmeterProvider := metric.NewMeterProvider(\n\t\tmetric.WithResource(res),\n\t\tmetric.WithReader(\n\t\t\tmetric.NewPeriodicReader(\n\t\t\t\texp,\n\t\t\t\tmetric.WithInterval(o.config.ExportInterval.TimeDuration()),\n\t\t\t),\n\t\t),\n\t)\n\n\tpf, err := output.NewPeriodicFlusher(o.config.FlushInterval.TimeDuration(), o.flushMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\to.logger.Debug(\"Started!\")\n\to.periodicFlusher = pf\n\to.meterProvider = meterProvider\n\to.metricsRegistry = newRegistry(meterProvider.Meter(\"k6\"), o.logger)\n\n\treturn nil\n}\n\nfunc (o *Output) flushMetrics() {\n\tsamples := o.GetBufferedSamples()\n\tstart := time.Now()\n\tvar count, errCount int\n\tfor _, sc := range samples {\n\t\tsamples := sc.GetSamples()\n\n\t\tfor _, sample := range samples {\n\t\t\tif err := o.dispatch(sample); err != nil {\n\t\t\t\to.logger.WithError(err).Error(\"Error dispatching sample\")\n\t\t\t\terrCount++\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcount++\n\t\t}\n\t}\n\n\tif count > 0 {\n\t\to.logger.\n\t\t\tWithField(\"t\", time.Since(start)).\n\t\t\tWithField(\"count\", count).\n\t\t\tDebug(\"registered metrics in OpenTelemetry metric provider\")\n\t}\n\n\tif errCount > 0 {\n\t\to.logger.\n\t\t\tWithField(\"t\", time.Since(start)).\n\t\t\tWithField(\"count\", errCount).\n\t\t\tWarn(\"can't flush some metrics\")\n\t}\n}\n\nfunc (o *Output) dispatch(entry metrics.Sample) error {\n\tctx := context.Background()\n\tname := normalizeMetricName(o.config, entry.Metric.Name)\n\n\tattributeSet := newAttributeSet(entry.Tags)\n\tattributeSetOpt := otelMetric.WithAttributeSet(attributeSet)\n\n\tunit := normalizeUnit(entry.Metric.Contains)\n\n\tswitch entry.Metric.Type {\n\tcase metrics.Counter:\n\t\tcounter, err := o.metricsRegistry.getOrCreateCounter(name, unit)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tcounter.Add(ctx, entry.Value, attributeSetOpt)\n\tcase metrics.Gauge:\n\t\tgauge, err := o.metricsRegistry.getOrCreateGauge(name, unit)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tgauge.Record(ctx, entry.Value, attributeSetOpt)\n\tcase metrics.Trend:\n\t\ttrend, err := o.metricsRegistry.getOrCreateHistogram(name, unit)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\ttrend.Record(ctx, entry.Value, attributeSetOpt)\n\tcase metrics.Rate:\n\t\tvar err error\n\t\tif o.config.SingleCounterForRate.Bool {\n\t\t\terr = o.singleCounterForRate(ctx, name, attributeSetOpt, entry)\n\t\t} else {\n\t\t\t// Deprecated path, remove with https://github.com/grafana/k6/issues/5185\n\t\t\terr = o.pairOfCountersForRate(ctx, name, attributeSetOpt, entry)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\tdefault:\n\t\treturn fmt.Errorf(\"metric %q has unsupported metric type\", entry.Metric.Name)\n\t}\n\treturn nil\n}\n\nfunc (o *Output) pairOfCountersForRate(\n\tctx context.Context,\n\tmetricName string,\n\tattributeSetOpt otelMetric.MeasurementOption,\n\tentry metrics.Sample,\n) error {\n\tnonZero, total, err := o.metricsRegistry.getOrCreateCountersForRate(metricName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get or create counter for Rate metric %q: %w\", metricName, err)\n\t}\n\tif entry.Value != 0 {\n\t\tnonZero.Add(ctx, 1, attributeSetOpt)\n\t}\n\ttotal.Add(ctx, 1, attributeSetOpt)\n\treturn nil\n}\n\nfunc (o *Output) singleCounterForRate(\n\tctx context.Context,\n\tmetricName string,\n\tattributeSetOpt otelMetric.MeasurementOption,\n\tentry metrics.Sample,\n) error {\n\trate, err := o.metricsRegistry.getOrCreateCounterForRate(metricName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"get or create counter for Rate metric %q: %w\", metricName, err)\n\t}\n\tvar valueType string\n\tif entry.Value != 0 {\n\t\tvalueType = \"nonzero\"\n\t} else {\n\t\tvalueType = \"zero\"\n\t}\n\tvalset := attribute.NewSet(attribute.String(\"condition\", valueType))\n\trate.Add(ctx, 1, attributeSetOpt, otelMetric.WithAttributeSet(valset))\n\treturn nil\n}\n\nfunc normalizeMetricName(cfg Config, name string) string {\n\treturn cfg.MetricPrefix.String + name\n}\n\nfunc normalizeUnit(vt metrics.ValueType) string {\n\tswitch vt {\n\tcase metrics.Time:\n\t\treturn \"ms\"\n\tcase metrics.Data:\n\t\treturn \"By\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/output_test.go",
    "content": "package opentelemetry\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\tcollectormetrics \"go.opentelemetry.io/proto/otlp/collector/metrics/v1\"\n\tcommonpb \"go.opentelemetry.io/proto/otlp/common/v1\"\n\tmetricpb \"go.opentelemetry.io/proto/otlp/metrics/v1\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\ntype MetricsServer interface {\n\tStart() error\n\tStop()\n\tEndpoint() string\n\tLastMetrics() []byte\n}\n\ntype baseServer struct {\n\tmu          sync.Mutex\n\tlastMetrics []byte\n}\n\nfunc (s *baseServer) setLastMetrics(metrics []byte) {\n\ts.mu.Lock()\n\ts.lastMetrics = metrics\n\ts.mu.Unlock()\n}\n\nfunc (s *baseServer) LastMetrics() []byte {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\treturn s.lastMetrics\n}\n\ntype httpMetricsServer struct {\n\tbaseServer\n\tserver *httptest.Server\n}\n\nfunc newHTTPServer() *httpMetricsServer {\n\ts := &httpMetricsServer{}\n\ts.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tif r.Method != http.MethodPost || r.URL.Path != \"/v1/metrics\" {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\n\t\tbody, err := io.ReadAll(r.Body)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\ts.setLastMetrics(body)\n\t\tw.WriteHeader(http.StatusOK)\n\t}))\n\treturn s\n}\n\nfunc (s *httpMetricsServer) Start() error     { return nil }\nfunc (s *httpMetricsServer) Stop()            { s.server.Close() }\nfunc (s *httpMetricsServer) Endpoint() string { return s.server.Listener.Addr().String() }\n\ntype grpcMetricsServer struct {\n\tbaseServer\n\tserver   *grpc.Server\n\tlistener net.Listener\n}\n\nfunc newGRPCServer() (*grpcMetricsServer, error) {\n\tlistener, err := (&net.ListenConfig{}).Listen(context.Background(), \"tcp\", \"localhost:0\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create listener: %w\", err)\n\t}\n\n\ts := &grpcMetricsServer{\n\t\tserver:   grpc.NewServer(),\n\t\tlistener: listener,\n\t}\n\n\tcollectormetrics.RegisterMetricsServiceServer(s.server, &grpcMetricsHandler{\n\t\tUnimplementedMetricsServiceServer: collectormetrics.UnimplementedMetricsServiceServer{},\n\t\tbaseServer:                        &s.baseServer,\n\t})\n\treturn s, nil\n}\n\nfunc (s *grpcMetricsServer) Start() error {\n\terrChan := make(chan error, 1)\n\tgo func() {\n\t\tif err := s.server.Serve(s.listener); err != nil {\n\t\t\terrChan <- fmt.Errorf(\"server failed to serve: %w\", err)\n\t\t}\n\t\tclose(errChan)\n\t}()\n\n\tselect {\n\tcase err := <-errChan:\n\t\treturn err\n\tcase <-time.After(100 * time.Millisecond):\n\t\treturn nil\n\t}\n}\n\nfunc (s *grpcMetricsServer) Stop() {\n\ts.server.Stop()\n\tif err := s.listener.Close(); err != nil {\n\t\t_ = err\n\t}\n}\n\nfunc (s *grpcMetricsServer) Endpoint() string { return s.listener.Addr().String() }\n\ntype grpcMetricsHandler struct {\n\tcollectormetrics.UnimplementedMetricsServiceServer\n\tbaseServer *baseServer\n}\n\nfunc (h *grpcMetricsHandler) Export(_ context.Context, req *collectormetrics.ExportMetricsServiceRequest) (*collectormetrics.ExportMetricsServiceResponse, error) {\n\tdata, err := proto.Marshal(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal request: %w\", err)\n\t}\n\th.baseServer.setLastMetrics(data)\n\treturn &collectormetrics.ExportMetricsServiceResponse{}, nil\n}\n\nfunc createServer(t *testing.T, protocol string) MetricsServer {\n\tswitch protocol {\n\tcase \"http\":\n\t\treturn newHTTPServer()\n\tcase \"grpc\":\n\t\tserver, err := newGRPCServer()\n\t\trequire.NoError(t, err)\n\t\trequire.NoError(t, server.Start())\n\t\treturn server\n\tdefault:\n\t\tt.Fatalf(\"unsupported protocol: %s\", protocol)\n\t\treturn nil\n\t}\n}\n\nfunc TestOutput(t *testing.T) {\n\tt.Parallel()\n\n\ttestProtocols := []string{\"http\", \"grpc\"}\n\ttestCases := []struct {\n\t\tname   string\n\t\tmetric struct {\n\t\t\ttyp   metrics.MetricType\n\t\t\tvalue float64\n\t\t}\n\t\tvalidate func(*testing.T, *collectormetrics.ExportMetricsServiceRequest)\n\t}{\n\t\t{\n\t\t\tname: \"gauge_metric\",\n\t\t\tmetric: struct {\n\t\t\t\ttyp   metrics.MetricType\n\t\t\t\tvalue float64\n\t\t\t}{metrics.Gauge, 42.0},\n\t\t\tvalidate: validateGaugeMetric,\n\t\t},\n\t\t{\n\t\t\tname: \"counter_metric\",\n\t\t\tmetric: struct {\n\t\t\t\ttyp   metrics.MetricType\n\t\t\t\tvalue float64\n\t\t\t}{metrics.Counter, 10.0},\n\t\t\tvalidate: validateCounterMetric,\n\t\t},\n\t\t{\n\t\t\tname: \"rate_metric\",\n\t\t\tmetric: struct {\n\t\t\t\ttyp   metrics.MetricType\n\t\t\t\tvalue float64\n\t\t\t}{metrics.Rate, 6.0},\n\t\t\tvalidate: validateRateMetric,\n\t\t},\n\t\t{\n\t\t\tname: \"trend_metric\",\n\t\t\tmetric: struct {\n\t\t\t\ttyp   metrics.MetricType\n\t\t\t\tvalue float64\n\t\t\t}{metrics.Trend, 25.0},\n\t\t\tvalidate: validateTrendMetric,\n\t\t},\n\t}\n\n\tfor _, proto := range testProtocols {\n\t\tt.Run(fmt.Sprintf(\"%s collector\", proto), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tregistry := metrics.NewRegistry()\n\t\t\tfor _, tc := range testCases {\n\t\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\n\t\t\t\t\tserver := createServer(t, proto)\n\t\t\t\t\tdefer server.Stop()\n\n\t\t\t\t\tconfig := createTestConfig(proto, server.Endpoint())\n\t\t\t\t\toutput := setupOutput(t, config)\n\n\t\t\t\t\tsample := createTestSample(t, registry, tc.metric.typ, tc.metric.value)\n\t\t\t\t\toutput.AddMetricSamples([]metrics.SampleContainer{metrics.Samples([]metrics.Sample{sample})})\n\n\t\t\t\t\trequire.NoError(t, output.Stop())\n\n\t\t\t\t\ttime.Sleep(300 * time.Millisecond)\n\t\t\t\t\tvalidateMetrics(t, server.LastMetrics(), tc.validate)\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc createTestConfig(protocol, endpoint string) map[string]string {\n\tconfig := map[string]string{\n\t\t\"K6_OTEL_SERVICE_NAME\":    \"test_service\",\n\t\t\"K6_OTEL_FLUSH_INTERVAL\":  \"100ms\",\n\t\t\"K6_OTEL_EXPORT_INTERVAL\": \"100ms\",\n\t\t\"K6_OTEL_EXPORTER_TYPE\":   protocol,\n\t\t\"K6_OTEL_METRIC_PREFIX\":   \"test.\",\n\t}\n\n\tif protocol == \"http\" {\n\t\tconfig[\"K6_OTEL_HTTP_EXPORTER_INSECURE\"] = \"true\"\n\t\tconfig[\"K6_OTEL_HTTP_EXPORTER_ENDPOINT\"] = endpoint\n\t\tconfig[\"K6_OTEL_HTTP_EXPORTER_URL_PATH\"] = \"/v1/metrics\"\n\t} else {\n\t\tconfig[\"K6_OTEL_GRPC_EXPORTER_INSECURE\"] = \"true\"\n\t\tconfig[\"K6_OTEL_GRPC_EXPORTER_ENDPOINT\"] = endpoint\n\t}\n\n\treturn config\n}\n\nfunc setupOutput(t *testing.T, config map[string]string) *Output {\n\to, err := New(output.Params{\n\t\tLogger:      testutils.NewLogger(t),\n\t\tEnvironment: config,\n\t})\n\trequire.NoError(t, err)\n\trequire.NoError(t, o.Start())\n\treturn o\n}\n\nfunc createTestSample(t *testing.T, registry *metrics.Registry, metricType metrics.MetricType, value float64) metrics.Sample {\n\tmetricName := metricType.String() + \"_metric\"\n\tmetric, err := registry.NewMetric(metricName, metricType)\n\trequire.NoError(t, err)\n\n\treturn metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: metric,\n\t\t\tTags: registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\"tag1\": \"value1\",\n\t\t\t}),\n\t\t},\n\t\tValue: value,\n\t}\n}\n\nfunc validateMetrics(t *testing.T, data []byte, validate func(*testing.T, *collectormetrics.ExportMetricsServiceRequest)) {\n\trequire.NotNil(t, data, \"No metrics were received by collector\")\n\n\tvar metricsRequest collectormetrics.ExportMetricsServiceRequest\n\terr := proto.Unmarshal(data, &metricsRequest)\n\trequire.NoError(t, err)\n\n\tvalidate(t, &metricsRequest)\n}\n\nfunc validateGaugeMetric(t *testing.T, mr *collectormetrics.ExportMetricsServiceRequest) {\n\tmetric := findMetric(mr, \"test.gauge_metric\")\n\trequire.NotNil(t, metric, \"gauge metric not found\")\n\tgauge := metric.GetGauge()\n\trequire.NotNil(t, gauge)\n\trequire.Len(t, gauge.DataPoints, 1)\n\tassert.Equal(t, 42.0, gauge.DataPoints[0].GetAsDouble())\n\tassertHasAttribute(t, gauge.DataPoints[0].Attributes, \"tag1\", \"value1\")\n}\n\nfunc validateCounterMetric(t *testing.T, mr *collectormetrics.ExportMetricsServiceRequest) {\n\tmetric := findMetric(mr, \"test.counter_metric\")\n\trequire.NotNil(t, metric, \"counter metric not found\")\n\tsum := metric.GetSum()\n\trequire.NotNil(t, sum)\n\trequire.Len(t, sum.DataPoints, 1)\n\tassert.Equal(t, 10.0, sum.DataPoints[0].GetAsDouble())\n\tassertHasAttribute(t, sum.DataPoints[0].Attributes, \"tag1\", \"value1\")\n}\n\nfunc validateRateMetric(t *testing.T, mr *collectormetrics.ExportMetricsServiceRequest) {\n\tmetric := findMetric(mr, \"test.rate_metric.total\")\n\trequire.NotNil(t, metric, \"rate metric not found\")\n\tsum := metric.GetSum()\n\trequire.Len(t, sum.DataPoints, 1)\n\tassert.Equal(t, int64(1), sum.DataPoints[0].GetAsInt())\n\tassertHasAttribute(t, sum.DataPoints[0].Attributes, \"tag1\", \"value1\")\n\tassertHasAttribute(t, sum.DataPoints[0].Attributes, \"condition\", \"nonzero\")\n}\n\nfunc validateTrendMetric(t *testing.T, mr *collectormetrics.ExportMetricsServiceRequest) {\n\tmetric := findMetric(mr, \"test.trend_metric\")\n\trequire.NotNil(t, metric, \"trend metric not found\")\n\thistogram := metric.GetHistogram()\n\trequire.NotNil(t, histogram)\n\trequire.Len(t, histogram.DataPoints, 1)\n\tassert.Equal(t, uint64(1), histogram.DataPoints[0].GetCount())\n\tassert.Equal(t, 25.0, histogram.DataPoints[0].GetSum())\n\tassertHasAttribute(t, histogram.DataPoints[0].Attributes, \"tag1\", \"value1\")\n}\n\nfunc findMetric(mr *collectormetrics.ExportMetricsServiceRequest, name string) *metricpb.Metric {\n\tfor _, rm := range mr.GetResourceMetrics() {\n\t\tfor _, sm := range rm.ScopeMetrics {\n\t\t\tfor _, m := range sm.Metrics {\n\t\t\t\tif m.Name == name {\n\t\t\t\t\treturn m\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc assertHasAttribute(t *testing.T, attrs []*commonpb.KeyValue, key, value string) {\n\tfor _, attr := range attrs {\n\t\tif attr.Key == key {\n\t\t\tassert.Equal(t, value, attr.GetValue().GetStringValue())\n\t\t\treturn\n\t\t}\n\t}\n\tt.Errorf(\"Attribute %s not found\", key)\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/registry.go",
    "content": "package opentelemetry\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n\totelMetric \"go.opentelemetry.io/otel/metric\"\n)\n\n// registry keep track of all metrics that have been used.\ntype registry struct {\n\tmeter  otelMetric.Meter\n\tlogger logrus.FieldLogger\n\n\tcounters     sync.Map\n\tgauges       sync.Map\n\thistograms   sync.Map\n\trateCounters sync.Map\n}\n\n// newRegistry creates a new registry.\nfunc newRegistry(meter otelMetric.Meter, logger logrus.FieldLogger) *registry {\n\treturn &registry{\n\t\tmeter:  meter,\n\t\tlogger: logger,\n\t}\n}\n\nfunc (r *registry) getOrCreateCounter(name, unit string) (otelMetric.Float64Counter, error) {\n\tif counter, ok := r.counters.Load(name); ok {\n\t\tif v, ok := counter.(otelMetric.Float64Counter); ok {\n\t\t\treturn v, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"metric %q is not a counter\", name)\n\t}\n\n\topts := []otelMetric.Float64CounterOption{}\n\tif unit != \"\" {\n\t\topts = append(opts, otelMetric.WithUnit(unit))\n\t}\n\n\tc, err := r.meter.Float64Counter(name, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create counter for %q: %w\", name, err)\n\t}\n\n\tr.logger.Debugf(\"registered counter metric %q\", name)\n\n\tr.counters.Store(name, c)\n\treturn c, nil\n}\n\nfunc (r *registry) getOrCreateHistogram(name, unit string) (otelMetric.Float64Histogram, error) {\n\tif histogram, ok := r.histograms.Load(name); ok {\n\t\tif v, ok := histogram.(otelMetric.Float64Histogram); ok {\n\t\t\treturn v, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"metric %q is not a histogram\", name)\n\t}\n\n\topts := []otelMetric.Float64HistogramOption{}\n\tif unit != \"\" {\n\t\topts = append(opts, otelMetric.WithUnit(unit))\n\t}\n\n\th, err := r.meter.Float64Histogram(name, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create histogram for %q: %w\", name, err)\n\t}\n\n\tr.logger.Debugf(\"registered histogram metric %q\", name)\n\n\tr.histograms.Store(name, h)\n\treturn h, nil\n}\n\nfunc (r *registry) getOrCreateCounterForRate(name string) (otelMetric.Int64Counter, error) {\n\t// k6's rate metric tracks how frequently a non-zero value occurs.\n\t// To be accurate is a percentage, which is a ratio.\n\t// To correctly calculate this metric in a metrics backend,\n\t// we need to split the rate metric via a dedicated attribute.\n\n\ttotalName := name + \".total\"\n\n\tvar err error\n\tvar totalCounter otelMetric.Int64Counter\n\n\tstoredTotalCounter, ok := r.rateCounters.Load(totalName)\n\tif !ok {\n\t\ttotalCounter, err = r.meter.Int64Counter(totalName)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to create counter for %q: %w\", totalName, err)\n\t\t}\n\n\t\tr.rateCounters.Store(totalName, totalCounter)\n\t\tr.logger.Debugf(\"registered counter metric %q\", totalName)\n\t} else {\n\t\ttotalCounter, ok = storedTotalCounter.(otelMetric.Int64Counter)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"metric %q stored not as counter\", totalName)\n\t\t}\n\t}\n\n\treturn totalCounter, nil\n}\n\n// Deprecated: Metrics of Rate type are now exported using a single counter,\n// we want to remove the support for exporting via the pair of counters on k6 v1.4.0.\nfunc (r *registry) getOrCreateCountersForRate(name string) (otelMetric.Int64Counter, otelMetric.Int64Counter, error) {\n\t// k6's rate metric tracks how frequently a non-zero value occurs.\n\t// so to correctly calculate the rate in a metrics backend\n\t// we need to split the rate metric into two counters:\n\t// 2. number of non-zero occurrences\n\t// 1. the total number of occurrences\n\n\tnonZeroName := name + \".occurred\"\n\ttotalName := name + \".total\"\n\n\tvar err error\n\tvar nonZeroCounter, totalCounter otelMetric.Int64Counter\n\n\tstoredNonZeroCounter, ok := r.rateCounters.Load(nonZeroName)\n\tif !ok {\n\t\tnonZeroCounter, err = r.meter.Int64Counter(nonZeroName)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to create counter for %q: %w\", nonZeroName, err)\n\t\t}\n\n\t\tr.rateCounters.Store(nonZeroName, nonZeroCounter)\n\t\tr.logger.Debugf(\"registered counter metric %q\", nonZeroName)\n\t} else {\n\t\tnonZeroCounter, ok = storedNonZeroCounter.(otelMetric.Int64Counter)\n\t\tif !ok {\n\t\t\treturn nil, nil, fmt.Errorf(\"metric %q stored not as counter\", nonZeroName)\n\t\t}\n\t}\n\n\tstoredTotalCounter, ok := r.rateCounters.Load(totalName)\n\tif !ok {\n\t\ttotalCounter, err = r.meter.Int64Counter(totalName)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"failed to create counter for %q: %w\", totalName, err)\n\t\t}\n\n\t\tr.rateCounters.Store(totalName, totalCounter)\n\t\tr.logger.Debugf(\"registered counter metric %q\", totalName)\n\t} else {\n\t\ttotalCounter, ok = storedTotalCounter.(otelMetric.Int64Counter)\n\t\tif !ok {\n\t\t\treturn nil, nil, fmt.Errorf(\"metric %q stored not as counter\", totalName)\n\t\t}\n\t}\n\n\treturn nonZeroCounter, totalCounter, nil\n}\n\nfunc (r *registry) getOrCreateGauge(name, unit string) (otelMetric.Float64Gauge, error) {\n\tif gauge, ok := r.gauges.Load(name); ok {\n\t\tif v, ok := gauge.(otelMetric.Float64Gauge); ok {\n\t\t\treturn v, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"metric %q is not a gauge\", name)\n\t}\n\n\topts := []otelMetric.Float64GaugeOption{}\n\tif unit != \"\" {\n\t\topts = append(opts, otelMetric.WithUnit(unit))\n\t}\n\n\tgauge, err := r.meter.Float64Gauge(name, opts...)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create gauge for %q: %w\", name, err)\n\t}\n\n\tr.logger.Debugf(\"registered gauge metric %q \", name)\n\n\tr.gauges.Store(name, gauge)\n\treturn gauge, nil\n}\n"
  },
  {
    "path": "internal/output/opentelemetry/tls.go",
    "content": "package opentelemetry\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc buildTLSConfig(\n\tinsecureSkipVerify null.Bool,\n\tcertPath, clientCertPath, clientKeyPath null.String,\n) (*tls.Config, error) {\n\tset := false\n\ttlsConfig := &tls.Config{\n\t\tMinVersion: tls.VersionTLS13,\n\t}\n\n\tif insecureSkipVerify.Valid {\n\t\ttlsConfig.InsecureSkipVerify = insecureSkipVerify.Bool\n\t\tset = true\n\t}\n\n\t// Load the root certificate\n\tif certPath.Valid {\n\t\tb, err := os.ReadFile(certPath.String) //nolint:forbidigo\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read root certificate from %q: %w\", certPath.String, err)\n\t\t}\n\n\t\tcp := x509.NewCertPool()\n\t\tif ok := cp.AppendCertsFromPEM(b); !ok {\n\t\t\treturn nil, errors.New(\"failed to append root certificate to the pool\")\n\t\t}\n\n\t\ttlsConfig.RootCAs = cp\n\t\tset = true\n\t}\n\n\t// Load the client certificate\n\tif clientCertPath.Valid {\n\t\tcert, err := tls.LoadX509KeyPair(clientCertPath.String, clientKeyPath.String)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to load client certificate: %w\", err)\n\t\t}\n\n\t\ttlsConfig.Certificates = []tls.Certificate{cert}\n\t\tset = true\n\t}\n\n\tif !set {\n\t\treturn nil, nil //nolint:nilnil // no TLS config set\n\t}\n\n\treturn tlsConfig, nil\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remote/client.go",
    "content": "// Package remote implements the Prometheus remote write protocol.\npackage remote\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/output/prometheusrw/sigv4\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\t\"github.com/klauspost/compress/snappy\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\n// HTTPConfig holds the config for the HTTP client.\ntype HTTPConfig struct {\n\tTimeout   time.Duration\n\tTLSConfig *tls.Config\n\tBasicAuth *BasicAuth\n\tSigV4     *sigv4.Config\n\tHeaders   http.Header\n}\n\n// BasicAuth holds the config for basic authentication.\ntype BasicAuth struct {\n\tUsername, Password string //nolint:gosec\n}\n\n// WriteClient is a client implementation of the Prometheus remote write protocol.\n// It follows the specs defined by the official design document:\n// https://docs.google.com/document/d/1LPhVRSFkGNSuU1fBd81ulhsCPR4hkSZyyBj1SZ8fWOM\ntype WriteClient struct {\n\thc  *http.Client\n\turl *url.URL\n\tcfg *HTTPConfig\n}\n\n// NewWriteClient creates a new WriteClient.\nfunc NewWriteClient(endpoint string, cfg *HTTPConfig) (*WriteClient, error) {\n\tif cfg == nil {\n\t\tcfg = &HTTPConfig{}\n\t}\n\tu, err := url.Parse(endpoint)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twc := &WriteClient{\n\t\thc: &http.Client{\n\t\t\tTimeout: cfg.Timeout,\n\t\t},\n\t\turl: u,\n\t\tcfg: cfg,\n\t}\n\tif cfg.TLSConfig != nil {\n\t\twc.hc.Transport = &http.Transport{\n\t\t\tTLSClientConfig: cfg.TLSConfig,\n\t\t}\n\t}\n\tif cfg.SigV4 != nil {\n\t\ttripper, err := sigv4.NewRoundTripper(cfg.SigV4, wc.hc.Transport)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\twc.hc.Transport = tripper\n\t}\n\treturn wc, nil\n}\n\n// Store sends a batch of samples to the HTTP endpoint,\n// the request is the proto marshaled and encoded.\nfunc (c *WriteClient) Store(ctx context.Context, series []*prompb.TimeSeries) error {\n\tb, err := newWriteRequestBody(series)\n\tif err != nil {\n\t\treturn err\n\t}\n\treq, err := http.NewRequestWithContext(\n\t\tctx, http.MethodPost, c.url.String(), bytes.NewReader(b))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create new HTTP request failed: %w\", err)\n\t}\n\tif c.cfg.BasicAuth != nil {\n\t\treq.SetBasicAuth(c.cfg.BasicAuth.Username, c.cfg.BasicAuth.Password)\n\t}\n\n\tif len(c.cfg.Headers) > 0 {\n\t\treq.Header = c.cfg.Headers.Clone()\n\t}\n\n\treq.Header.Set(\"User-Agent\", \"k6-prometheus-rw-output\")\n\n\t// They are mostly defined by the specs\n\treq.Header.Set(\"Content-Encoding\", \"snappy\")\n\treq.Header.Set(\"Content-Type\", \"application/x-protobuf\")\n\treq.Header.Set(\"X-Prometheus-Remote-Write-Version\", \"0.1.0\")\n\n\tresp, err := c.hc.Do(req) //nolint:gosec\n\tif err != nil {\n\t\treturn fmt.Errorf(\"HTTP POST request failed: %w\", err)\n\t}\n\tdefer func() {\n\t\terr = resp.Body.Close()\n\t\tif err != nil {\n\t\t\tpanic(err)\n\t\t}\n\t}()\n\n\t_, err = io.Copy(io.Discard, resp.Body)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn validateResponseStatus(resp.StatusCode)\n}\n\nfunc newWriteRequestBody(series []*prompb.TimeSeries) ([]byte, error) {\n\tb, err := proto.Marshal(&prompb.WriteRequest{\n\t\tTimeseries: series,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"encoding series as protobuf write request failed: %w\", err)\n\t}\n\tif snappy.MaxEncodedLen(len(b)) < 0 {\n\t\treturn nil, fmt.Errorf(\"the protobuf message is too large to be handled by Snappy encoder; \"+\n\t\t\t\"size: %d, limit: %d\", len(b), math.MaxUint32)\n\t}\n\treturn snappy.Encode(nil, b), nil\n}\n\nfunc validateResponseStatus(code int) error {\n\tif code >= http.StatusOK && code < 300 {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"got status code: %d instead expected a 2xx successful status code\", code)\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remote/client_test.go",
    "content": "package remote\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"math\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\t\"github.com/klauspost/compress/snappy\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/output/prometheusrw/stale\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\nfunc TestNewWriteClient(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"DefaultConfig\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\twc, err := NewWriteClient(\"http://example.com/api/v1/write\", nil)\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, wc)\n\t\tassert.Equal(t, &HTTPConfig{}, wc.cfg)\n\t})\n\n\tt.Run(\"CustomConfig\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\thc := &HTTPConfig{Timeout: time.Second}\n\t\twc, err := NewWriteClient(\"http://example.com/api/v1/write\", hc)\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, wc)\n\t\tassert.Equal(t, hc, wc.cfg)\n\t})\n\n\tt.Run(\"InvalidURL\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\twc, err := NewWriteClient(\"fake://bad url\", nil)\n\t\trequire.Error(t, err)\n\t\tassert.Nil(t, wc)\n\t})\n}\n\nfunc TestClientStore(t *testing.T) {\n\tt.Parallel()\n\th := func(rw http.ResponseWriter, r *http.Request) {\n\t\tassert.Equal(t, \"snappy\", r.Header.Get(\"Content-Encoding\"))\n\t\tassert.Equal(t, \"application/x-protobuf\", r.Header.Get(\"Content-Type\"))\n\t\tassert.Equal(t, \"k6-prometheus-rw-output\", r.Header.Get(\"User-Agent\"))\n\t\tassert.Equal(t, \"0.1.0\", r.Header.Get(\"X-Prometheus-Remote-Write-Version\"))\n\t\tassert.NotEmpty(t, r.Header.Get(\"Content-Length\"))\n\n\t\tb, err := io.ReadAll(r.Body)\n\t\tassert.NoError(t, err)\n\t\tassert.NotEmpty(t, len(b))\n\n\t\trw.WriteHeader(http.StatusNoContent)\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(h))\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tc := &WriteClient{\n\t\thc:  ts.Client(),\n\t\turl: u,\n\t\tcfg: &HTTPConfig{},\n\t}\n\tdata := &prompb.TimeSeries{\n\t\tLabels: []*prompb.Label{\n\t\t\t{\n\t\t\t\tName:  \"label1\",\n\t\t\t\tValue: \"label1-val\",\n\t\t\t},\n\t\t},\n\t\tSamples: []*prompb.Sample{\n\t\t\t{\n\t\t\t\tValue:     8.5,\n\t\t\t\tTimestamp: time.Now().UnixMilli(),\n\t\t\t},\n\t\t},\n\t}\n\terr = c.Store(context.Background(), []*prompb.TimeSeries{data})\n\tassert.NoError(t, err)\n}\n\nfunc TestClientStoreHTTPError(t *testing.T) {\n\tt.Parallel()\n\th := func(w http.ResponseWriter, _ *http.Request) {\n\t\thttp.Error(w, \"bad\", http.StatusUnauthorized)\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(h))\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tc := &WriteClient{\n\t\thc:  ts.Client(),\n\t\turl: u,\n\t\tcfg: &HTTPConfig{},\n\t}\n\tassert.Error(t, c.Store(context.Background(), nil))\n}\n\nfunc TestClientStoreHTTPBasic(t *testing.T) {\n\tt.Parallel()\n\th := func(_ http.ResponseWriter, r *http.Request) {\n\t\tu, pwd, ok := r.BasicAuth()\n\t\trequire.True(t, ok)\n\t\tassert.Equal(t, \"usertest\", u)\n\t\tassert.Equal(t, \"pwdtest\", pwd)\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(h))\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tc := &WriteClient{\n\t\thc:  ts.Client(),\n\t\turl: u,\n\t\tcfg: &HTTPConfig{\n\t\t\tBasicAuth: &BasicAuth{\n\t\t\t\tUsername: \"usertest\",\n\t\t\t\tPassword: \"pwdtest\",\n\t\t\t},\n\t\t},\n\t}\n\tassert.NoError(t, c.Store(context.Background(), nil))\n}\n\nfunc TestClientStoreHeaders(t *testing.T) {\n\tt.Parallel()\n\th := func(_ http.ResponseWriter, r *http.Request) {\n\t\tassert.Equal(t, \"0.1.0\", r.Header.Get(\"X-Prometheus-Remote-Write-Version\"))\n\t\tassert.Equal(t, \"fake\", r.Header.Get(\"X-MY-CUSTOM-HEADER\"))\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(h))\n\tdefer ts.Close()\n\n\tu, err := url.Parse(ts.URL)\n\trequire.NoError(t, err)\n\n\tc := &WriteClient{\n\t\thc:  ts.Client(),\n\t\turl: u,\n\t\tcfg: &HTTPConfig{\n\t\t\tHeaders: http.Header(map[string][]string{\n\t\t\t\t\"X-MY-CUSTOM-HEADER\": {\"fake\"},\n\t\t\t\t// If the same key, of a mandatory protocol's header\n\t\t\t\t// is provided, it will be overwritten.\n\t\t\t\t\"X-Prometheus-Remote-Write-Version\": {\"fake\"},\n\t\t\t}),\n\t\t},\n\t}\n\tassert.NoError(t, c.Store(context.Background(), nil))\n}\n\nfunc TestNewWriteRequestBody(t *testing.T) {\n\tt.Parallel()\n\tts := []*prompb.TimeSeries{\n\t\t{\n\t\t\tLabels:  []*prompb.Label{{Name: \"label1\", Value: \"val1\"}},\n\t\t\tSamples: []*prompb.Sample{{Value: 10.1, Timestamp: time.Unix(1, 0).Unix()}},\n\t\t},\n\t}\n\tb, err := newWriteRequestBody(ts)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, string(b))\n\tassert.Contains(t, string(b), `label1`)\n}\n\nfunc TestNewWriteRequestBodyWithStaleMarker(t *testing.T) {\n\tt.Parallel()\n\n\ttimestamp := time.Date(2022, time.December, 15, 11, 41, 18, 123, time.UTC)\n\n\tts := []*prompb.TimeSeries{\n\t\t{\n\t\t\tLabels: []*prompb.Label{{Name: \"label1\", Value: \"val1\"}},\n\t\t\tSamples: []*prompb.Sample{{\n\t\t\t\tValue:     stale.Marker,\n\t\t\t\tTimestamp: timestamp.UnixMilli(),\n\t\t\t}},\n\t\t},\n\t}\n\tb, err := newWriteRequestBody(ts)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, b)\n\n\tsb, err := snappy.Decode(nil, b)\n\trequire.NoError(t, err)\n\n\tvar series prompb.WriteRequest\n\terr = proto.Unmarshal(sb, &series)\n\trequire.NoError(t, err)\n\trequire.NotEmpty(t, series.Timeseries[0])\n\trequire.NotEmpty(t, series.Timeseries[0].Samples)\n\n\tassert.True(t, math.IsNaN(series.Timeseries[0].Samples[0].Value))\n\tassert.Equal(t, timestamp.UnixMilli(), series.Timeseries[0].Samples[0].Timestamp)\n}\n\nfunc TestValidateStatusCode(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tstatus int\n\t\texpErr bool\n\t}{\n\t\t{status: http.StatusOK, expErr: false},        // Mimir\n\t\t{status: http.StatusNoContent, expErr: false}, // Prometheus\n\t\t{status: http.StatusBadRequest, expErr: true},\n\t}\n\tfor _, tt := range tests {\n\t\terr := validateResponseStatus(tt.status)\n\t\tif tt.expErr {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\t\tassert.NoError(t, err)\n\t}\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/config.go",
    "content": "package remotewrite\n\nimport (\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/output/prometheusrw/remote\"\n\t\"go.k6.io/k6/internal/output/prometheusrw/sigv4\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nconst (\n\tdefaultServerURL    = \"http://localhost:9090/api/v1/write\"\n\tdefaultTimeout      = 5 * time.Second\n\tdefaultPushInterval = 5 * time.Second\n\tdefaultMetricPrefix = \"k6_\"\n)\n\n//nolint:gochecknoglobals\nvar defaultTrendStats = []string{\"p(99)\"}\n\n// Config contains the configuration for the Output.\ntype Config struct {\n\t// ServerURL contains the absolute ServerURL for the Write endpoint where to flush the time series.\n\tServerURL null.String `json:\"url\" envconfig:\"K6_PROMETHEUS_RW_SERVER_URL\"`\n\n\t// Headers contains additional headers that should be included in the HTTP requests.\n\tHeaders map[string]string `json:\"headers\"`\n\n\t// InsecureSkipTLSVerify skips TLS client side checks.\n\tInsecureSkipTLSVerify null.Bool `json:\"insecureSkipTLSVerify\" envconfig:\"K6_PROMETHEUS_RW_INSECURE_SKIP_TLS_VERIFY\"`\n\n\t// TLSMinVersion defines the lowest allowed TLS version for the client (default is 1.3).\n\tTLSMinVersion null.String `json:\"tlsMinVersion\" envconfig:\"K6_PROMETHEUS_RW_TLS_MINIMUM_VERSION\"`\n\n\t// Username is the User for Basic Auth.\n\tUsername null.String `json:\"username\" envconfig:\"K6_PROMETHEUS_RW_USERNAME\"`\n\n\t// Password is the Password for the Basic Auth.\n\tPassword null.String `json:\"password\" envconfig:\"K6_PROMETHEUS_RW_PASSWORD\"`\n\n\t// ClientCertificate is the public key of the SSL certificate.\n\t// It is expected the path of the certificate on the file system.\n\t// If it is required a dedicated Certifacate Authority then it should be added\n\t// to the conventional folders defined by the operating system's registry.\n\tClientCertificate null.String `json:\"clientCertificate\" envconfig:\"K6_PROMETHEUS_RW_CLIENT_CERTIFICATE\"`\n\n\t// ClientCertificateKey is the private key of the SSL certificate.\n\t// It is expected the path of the certificate on the file system.\n\tClientCertificateKey null.String `json:\"clientCertificateKey\" envconfig:\"K6_PROMETHEUS_RW_CLIENT_CERTIFICATE_KEY\"`\n\n\t// BearerToken if set is the token used for the `Authorization` header.\n\tBearerToken null.String `json:\"bearerToken\" envconfig:\"K6_PROMETHEUS_RW_BEARER_TOKEN\"`\n\n\t// PushInterval defines the time between flushes. The Output will wait the set time\n\t// before push a new set of time series to the endpoint.\n\tPushInterval types.NullDuration `json:\"pushInterval\" envconfig:\"K6_PROMETHEUS_RW_PUSH_INTERVAL\"`\n\n\t// TrendAsNativeHistogram defines if the mapping for metrics defined as Trend type\n\t// should map to a Prometheus' Native Histogram.\n\tTrendAsNativeHistogram null.Bool `json:\"trendAsNativeHistogram\" envconfig:\"K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM\"`\n\n\t// TrendStats defines the stats to flush for Trend metrics.\n\t//\n\t// TODO: should we support K6_SUMMARY_TREND_STATS?\n\tTrendStats []string `json:\"trendStats\" envconfig:\"K6_PROMETHEUS_RW_TREND_STATS\"`\n\n\tStaleMarkers null.Bool `json:\"staleMarkers\" envconfig:\"K6_PROMETHEUS_RW_STALE_MARKERS\"`\n\n\t// SigV4Region is the AWS region where the workspace is.\n\tSigV4Region null.String `json:\"sigV4Region\" envconfig:\"K6_PROMETHEUS_RW_SIGV4_REGION\"`\n\n\t// SigV4AccessKey is the AWS access key.\n\tSigV4AccessKey null.String `json:\"sigV4AccessKey\" envconfig:\"K6_PROMETHEUS_RW_SIGV4_ACCESS_KEY\"`\n\n\t// SigV4SecretKey is the AWS secret key.\n\tSigV4SecretKey null.String `json:\"sigV4SecretKey\" envconfig:\"K6_PROMETHEUS_RW_SIGV4_SECRET_KEY\"`\n}\n\n// NewConfig creates an Output's configuration.\nfunc NewConfig() Config {\n\treturn Config{\n\t\tServerURL:             null.StringFrom(defaultServerURL),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tUsername:              null.NewString(\"\", false),\n\t\tPassword:              null.NewString(\"\", false),\n\t\tPushInterval:          types.NullDurationFrom(defaultPushInterval),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            defaultTrendStats,\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t\tSigV4Region:           null.NewString(\"\", false),\n\t\tSigV4AccessKey:        null.NewString(\"\", false),\n\t\tSigV4SecretKey:        null.NewString(\"\", false),\n\t}\n}\n\n// RemoteConfig creates a configuration for the HTTP Remote-write client.\nfunc (conf Config) RemoteConfig() (*remote.HTTPConfig, error) {\n\thc := remote.HTTPConfig{\n\t\tTimeout: defaultTimeout,\n\t}\n\n\t// if at least valid user was configured, use basic auth\n\tif conf.Username.Valid {\n\t\thc.BasicAuth = &remote.BasicAuth{\n\t\t\tUsername: conf.Username.String,\n\t\t\tPassword: conf.Password.String,\n\t\t}\n\t}\n\n\ttlsMinVersion := uint16(tls.VersionTLS13)\n\tif conf.TLSMinVersion.Valid && conf.TLSMinVersion.String == \"1.2\" {\n\t\ttlsMinVersion = tls.VersionTLS12\n\t}\n\n\thc.TLSConfig = &tls.Config{\n\t\tInsecureSkipVerify: conf.InsecureSkipTLSVerify.Bool, //nolint:gosec\n\t\tMinVersion:         tlsMinVersion,\n\t}\n\n\tif conf.ClientCertificate.Valid && conf.ClientCertificateKey.Valid {\n\t\tcert, err := tls.LoadX509KeyPair(conf.ClientCertificate.String, conf.ClientCertificateKey.String)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to load the TLS certificate: %w\", err)\n\t\t}\n\t\thc.TLSConfig.Certificates = []tls.Certificate{cert}\n\t}\n\n\tif isSigV4PartiallyConfigured(conf.SigV4Region, conf.SigV4AccessKey, conf.SigV4SecretKey) {\n\t\treturn nil, errors.New(\n\t\t\t\"sigv4 seems to be partially configured. All of \" +\n\t\t\t\t\"K6_PROMETHEUS_RW_SIGV4_REGION, K6_PROMETHEUS_RW_SIGV4_ACCESS_KEY, K6_PROMETHEUS_RW_SIGV4_SECRET_KEY \" +\n\t\t\t\t\"must all be set. Unset all to bypass sigv4\",\n\t\t)\n\t}\n\n\tif conf.SigV4Region.Valid && conf.SigV4AccessKey.Valid && conf.SigV4SecretKey.Valid {\n\t\thc.SigV4 = &sigv4.Config{\n\t\t\tRegion:             conf.SigV4Region.String,\n\t\t\tAwsAccessKeyID:     conf.SigV4AccessKey.String,\n\t\t\tAwsSecretAccessKey: conf.SigV4SecretKey.String,\n\t\t}\n\t}\n\n\tif len(conf.Headers) > 0 {\n\t\thc.Headers = make(http.Header)\n\t\tfor k, v := range conf.Headers {\n\t\t\thc.Headers.Add(k, v)\n\t\t}\n\t}\n\n\tif conf.BearerToken.String != \"\" {\n\t\tif hc.Headers == nil {\n\t\t\thc.Headers = make(http.Header)\n\t\t}\n\t\thc.Headers.Set(\"Authorization\", \"Bearer \"+conf.BearerToken.String)\n\t}\n\n\treturn &hc, nil\n}\n\n// Apply merges applied Config into base.\nfunc (conf Config) Apply(applied Config) Config {\n\tif applied.ServerURL.Valid {\n\t\tconf.ServerURL = applied.ServerURL\n\t}\n\n\tif applied.InsecureSkipTLSVerify.Valid {\n\t\tconf.InsecureSkipTLSVerify = applied.InsecureSkipTLSVerify\n\t}\n\n\tif applied.TLSMinVersion.Valid {\n\t\tconf.TLSMinVersion = applied.TLSMinVersion\n\t}\n\n\tif applied.Username.Valid {\n\t\tconf.Username = applied.Username\n\t}\n\n\tif applied.Password.Valid {\n\t\tconf.Password = applied.Password\n\t}\n\n\tif applied.BearerToken.Valid {\n\t\tconf.BearerToken = applied.BearerToken\n\t}\n\n\tif applied.SigV4Region.Valid {\n\t\tconf.SigV4Region = applied.SigV4Region\n\t}\n\n\tif applied.SigV4AccessKey.Valid {\n\t\tconf.SigV4AccessKey = applied.SigV4AccessKey\n\t}\n\n\tif applied.SigV4SecretKey.Valid {\n\t\tconf.SigV4SecretKey = applied.SigV4SecretKey\n\t}\n\n\tif applied.PushInterval.Valid {\n\t\tconf.PushInterval = applied.PushInterval\n\t}\n\n\tif applied.TrendAsNativeHistogram.Valid {\n\t\tconf.TrendAsNativeHistogram = applied.TrendAsNativeHistogram\n\t}\n\n\tif applied.StaleMarkers.Valid {\n\t\tconf.StaleMarkers = applied.StaleMarkers\n\t}\n\n\tif len(applied.Headers) > 0 {\n\t\tmaps.Copy(conf.Headers, applied.Headers)\n\t}\n\n\tif len(applied.TrendStats) > 0 {\n\t\tconf.TrendStats = make([]string, len(applied.TrendStats))\n\t\tcopy(conf.TrendStats, applied.TrendStats)\n\t}\n\n\tif applied.ClientCertificate.Valid {\n\t\tconf.ClientCertificate = applied.ClientCertificate\n\t}\n\n\tif applied.ClientCertificateKey.Valid {\n\t\tconf.ClientCertificateKey = applied.ClientCertificateKey\n\t}\n\n\treturn conf\n}\n\n// GetConsolidatedConfig combines the options' values from the different sources\n// and returns the merged options. The Order of precedence used is documented\n// in the k6 Documentation https://k6.io/docs/using-k6/k6-options/how-to/#order-of-precedence.\nfunc GetConsolidatedConfig(jsonRawConf json.RawMessage, env map[string]string, _ string) (Config, error) {\n\tresult := NewConfig()\n\tif jsonRawConf != nil {\n\t\tjsonConf, err := parseJSON(jsonRawConf)\n\t\tif err != nil {\n\t\t\treturn result, fmt.Errorf(\"parse JSON options failed: %w\", err)\n\t\t}\n\t\tresult = result.Apply(jsonConf)\n\t}\n\n\tif len(env) > 0 {\n\t\tenvConf, err := parseEnvs(env)\n\t\tif err != nil {\n\t\t\treturn result, fmt.Errorf(\"parse environment variables options failed: %w\", err)\n\t\t}\n\t\tresult = result.Apply(envConf)\n\t}\n\n\t// TODO: define a way for defining Output's options\n\t// then support them.\n\t// url is the third GetConsolidatedConfig's argument which is omitted for now\n\t//nolint:gocritic\n\t//\n\t//if url != \"\" {\n\t//urlConf, err := parseArg(url)\n\t//if err != nil {\n\t//return result, fmt.Errorf(\"parse argument string options failed: %w\", err)\n\t//}\n\t//result = result.Apply(urlConf)\n\t//}\n\n\treturn result, nil\n}\n\nfunc envMap(env map[string]string, prefix string) map[string]string {\n\tresult := make(map[string]string)\n\tfor ek, ev := range env {\n\t\tif after, ok := strings.CutPrefix(ek, prefix); ok {\n\t\t\tk := after\n\t\t\tresult[k] = ev\n\t\t}\n\t}\n\treturn result\n}\n\nfunc parseEnvs(env map[string]string) (Config, error) {\n\tc := Config{\n\t\tHeaders: make(map[string]string),\n\t}\n\n\terr := envconfig.Process(\"\", &c, func(key string) (string, bool) {\n\t\tv, ok := env[key]\n\t\treturn v, ok\n\t})\n\tif err != nil {\n\t\treturn Config{}, err\n\t}\n\n\t// We don't rely on `envconfig` for headers, as we do use our own logic/syntax with\n\t// dynamically-defined header-associated environment variables.\n\tenvHeaders := envMap(env, \"K6_PROMETHEUS_RW_HEADERS_\")\n\tmaps.Copy(c.Headers, envHeaders)\n\n\tif headers, headersDefined := env[\"K6_PROMETHEUS_RW_HTTP_HEADERS\"]; headersDefined {\n\t\tfor kvPair := range strings.SplitSeq(headers, \",\") {\n\t\t\theader := strings.Split(kvPair, \":\")\n\t\t\tif len(header) != 2 {\n\t\t\t\treturn c, fmt.Errorf(\"the provided header (%s) does not respect the expected format <header key>:<value>\", kvPair)\n\t\t\t}\n\t\t\tc.Headers[header[0]] = header[1]\n\t\t}\n\t}\n\n\treturn c, nil\n}\n\n// parseJSON parses the supplied JSON into a Config.\nfunc parseJSON(data json.RawMessage) (Config, error) {\n\tvar c Config\n\terr := json.Unmarshal(data, &c)\n\treturn c, err\n}\n\n// parseArg parses the supplied string of arguments into a Config.\nfunc parseArg(text string) (Config, error) {\n\tvar c Config\n\topts := strings.SplitSeq(text, \",\")\n\n\tfor opt := range opts {\n\t\tr := strings.SplitN(opt, \"=\", 2)\n\t\tif len(r) != 2 {\n\t\t\treturn c, fmt.Errorf(\"couldn't parse argument %q as option\", opt)\n\t\t}\n\t\tkey, v := r[0], r[1]\n\t\tswitch key {\n\t\tcase \"url\":\n\t\t\tc.ServerURL = null.StringFrom(v)\n\t\tcase \"insecureSkipTLSVerify\":\n\t\t\tif err := c.InsecureSkipTLSVerify.UnmarshalText([]byte(v)); err != nil {\n\t\t\t\treturn c, fmt.Errorf(\"insecureSkipTLSVerify value must be true or false, not %q\", v)\n\t\t\t}\n\t\tcase \"tlsMinVersion\":\n\t\t\tc.TLSMinVersion = null.StringFrom(v)\n\t\tcase \"username\":\n\t\t\tc.Username = null.StringFrom(v)\n\t\tcase \"password\":\n\t\t\tc.Password = null.StringFrom(v)\n\t\tcase \"pushInterval\":\n\t\t\tif err := c.PushInterval.UnmarshalText([]byte(v)); err != nil {\n\t\t\t\treturn c, err\n\t\t\t}\n\t\tcase \"trendAsNativeHistogram\":\n\t\t\tif err := c.TrendAsNativeHistogram.UnmarshalText([]byte(v)); err != nil {\n\t\t\t\treturn c, fmt.Errorf(\"trendAsNativeHistogram value must be true or false, not %q\", v)\n\t\t\t}\n\n\t\t// TODO: add the support for trendStats\n\t\t// strvals doesn't support the same format used by --summary-trend-stats\n\t\t// using the comma as the separator, because it is already used for\n\t\t// dividing the keys.\n\t\t//nolint:gocritic\n\t\t//\n\t\t//if v, ok := params[\"trendStats\"].(string); ok && len(v) > 0 {\n\t\t//c.TrendStats = strings.Split(v, \",\")\n\t\t//}\n\n\t\tcase \"clientCertificate\":\n\t\t\tc.ClientCertificate = null.StringFrom(v)\n\t\tcase \"clientCertificateKey\":\n\t\t\tc.ClientCertificateKey = null.StringFrom(v)\n\n\t\tdefault:\n\t\t\tif !strings.HasPrefix(key, \"headers.\") {\n\t\t\t\treturn c, fmt.Errorf(\"%q is an unknown option's key\", r[0])\n\t\t\t}\n\t\t\tif c.Headers == nil {\n\t\t\t\tc.Headers = make(map[string]string)\n\t\t\t}\n\t\t\tc.Headers[strings.TrimPrefix(key, \"headers.\")] = v\n\t\t}\n\t}\n\n\treturn c, nil\n}\n\nfunc isSigV4PartiallyConfigured(region, accessKey, secretKey null.String) bool {\n\thasRegion := region.Valid && len(strings.TrimSpace(region.String)) != 0\n\thasAccessID := accessKey.Valid && len(strings.TrimSpace(accessKey.String)) != 0\n\thasSecretAccessKey := secretKey.Valid && len(strings.TrimSpace(secretKey.String)) != 0\n\t// either they are all set, or all not set. False if partial\n\tisComplete := (hasRegion && hasAccessID && hasSecretAccessKey) || (!hasRegion && !hasAccessID && !hasSecretAccessKey)\n\treturn !isComplete\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/config_test.go",
    "content": "package remotewrite\n\nimport (\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/output/prometheusrw/remote\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestConfigApply(t *testing.T) {\n\tt.Parallel()\n\n\tfullConfig := Config{\n\t\tServerURL:             null.StringFrom(\"some-url\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tUsername:              null.StringFrom(\"user\"),\n\t\tPassword:              null.StringFrom(\"pass\"),\n\t\tPushInterval:          types.NullDurationFrom(10 * time.Second),\n\t\tHeaders: map[string]string{\n\t\t\t\"X-Header\": \"value\",\n\t\t},\n\t\tTrendStats:   []string{\"p(99)\"},\n\t\tStaleMarkers: null.BoolFrom(true),\n\t}\n\n\t// Defaults should be overwritten by valid values\n\tc := NewConfig()\n\tc = c.Apply(fullConfig)\n\tassert.Equal(t, fullConfig, c)\n\n\t// Defaults shouldn't be impacted by invalid values\n\tc = NewConfig()\n\tc = c.Apply(Config{\n\t\tUsername:              null.NewString(\"user\", false),\n\t\tPassword:              null.NewString(\"pass\", false),\n\t\tInsecureSkipTLSVerify: null.NewBool(false, false),\n\t})\n\tassert.Equal(t, false, c.Username.Valid)\n\tassert.Equal(t, false, c.Password.Valid)\n\tassert.Equal(t, true, c.InsecureSkipTLSVerify.Valid)\n}\n\nfunc TestConfigRemoteConfig(t *testing.T) {\n\tt.Parallel()\n\tu, err := url.Parse(\"https://prometheus.ie/remote\")\n\trequire.NoError(t, err)\n\n\tconfig := Config{\n\t\tServerURL:             null.StringFrom(u.String()),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(true),\n\t\tUsername:              null.StringFrom(\"myuser\"),\n\t\tPassword:              null.StringFrom(\"mypass\"),\n\t\tHeaders: map[string]string{\n\t\t\t\"X-MYCUSTOM-HEADER\": \"val1\",\n\t\t\t// it asserts that Authz header is overwritten if the token is set\n\t\t\t\"Authorization\": \"pre-set-token\",\n\t\t},\n\t\tBearerToken: null.StringFrom(\"my-fake-token\"),\n\t}\n\n\theaders := http.Header{}\n\theaders.Set(\"X-MYCUSTOM-HEADER\", \"val1\")\n\theaders.Set(\"Authorization\", \"Bearer my-fake-token\")\n\texprcc := &remote.HTTPConfig{\n\t\tTimeout: 5 * time.Second,\n\t\tTLSConfig: &tls.Config{\n\t\t\tInsecureSkipVerify: true,\n\t\t\tMinVersion:         tls.VersionTLS13,\n\t\t},\n\t\tBasicAuth: &remote.BasicAuth{\n\t\t\tUsername: \"myuser\",\n\t\t\tPassword: \"mypass\",\n\t\t},\n\t\tHeaders: headers,\n\t}\n\trcc, err := config.RemoteConfig()\n\trequire.NoError(t, err)\n\tassert.Equal(t, exprcc, rcc)\n}\n\nfunc TestConfigRemoteConfigClientCertificateError(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := Config{\n\t\tClientCertificate:    null.StringFrom(\"bad-cert-value\"),\n\t\tClientCertificateKey: null.StringFrom(\"bad-cert-key\"),\n\t}\n\n\trcc, err := config.RemoteConfig()\n\tassert.ErrorContains(t, err, \"TLS certificate\")\n\tassert.Nil(t, rcc)\n}\n\nfunc TestGetConsolidatedConfig(t *testing.T) {\n\tt.Parallel()\n\n\tu, err := url.Parse(\"https://prometheus.ie/remote\")\n\trequire.NoError(t, err)\n\n\ttestCases := map[string]struct {\n\t\tjsonRaw   json.RawMessage\n\t\tenv       map[string]string\n\t\targ       string\n\t\tconfig    Config\n\t\terrString string\n\t}{\n\t\t\"Defaults\": {\n\t\t\tjsonRaw: nil,\n\t\t\tenv:     nil,\n\t\t\targ:     \"\",\n\t\t\tconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tUsername:              null.NewString(\"\", false),\n\t\t\t\tPassword:              null.NewString(\"\", false),\n\t\t\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"JSONSuccess\": {\n\t\t\tjsonRaw: json.RawMessage(fmt.Sprintf(`{\"url\":\"%s\"}`, u.String())),\n\t\t\tconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(u.String()),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tUsername:              null.NewString(\"\", false),\n\t\t\t\tPassword:              null.NewString(\"\", false),\n\t\t\t\tPushInterval:          types.NullDurationFrom(defaultPushInterval),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"MixedSuccess\": {\n\t\t\tjsonRaw: json.RawMessage(fmt.Sprintf(`{\"url\":\"%s\"}`, u.String())),\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_PROMETHEUS_RW_INSECURE_SKIP_TLS_VERIFY\": \"false\",\n\t\t\t\t\"K6_PROMETHEUS_RW_USERNAME\":                 \"u\",\n\t\t\t},\n\t\t\t// arg: \"username=user\",\n\t\t\tconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(u.String()),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tUsername:              null.NewString(\"u\", true),\n\t\t\t\tPassword:              null.NewString(\"\", false),\n\t\t\t\tPushInterval:          types.NullDurationFrom(defaultPushInterval),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"OrderOfPrecedence\": {\n\t\t\tjsonRaw: json.RawMessage(`{\"url\":\"http://json:9090\",\"username\":\"json\",\"password\":\"json\"}`),\n\t\t\tenv: map[string]string{\n\t\t\t\t\"K6_PROMETHEUS_RW_USERNAME\": \"env\",\n\t\t\t\t\"K6_PROMETHEUS_RW_PASSWORD\": \"env\",\n\t\t\t},\n\t\t\t// arg: \"password=arg\",\n\t\t\tconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(\"http://json:9090\"),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tUsername:              null.StringFrom(\"env\"),\n\t\t\t\tPassword:              null.StringFrom(\"env\"),\n\t\t\t\tPushInterval:          types.NullDurationFrom(defaultPushInterval),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"InvalidJSON\": {\n\t\t\tjsonRaw:   json.RawMessage(`{\"invalid-json \"astring\"}`),\n\t\t\terrString: \"parse JSON options failed\",\n\t\t},\n\t\t\"InvalidEnv\": {\n\t\t\tenv:       map[string]string{\"K6_PROMETHEUS_RW_INSECURE_SKIP_TLS_VERIFY\": \"d\"},\n\t\t\terrString: \"parse environment variables options failed\",\n\t\t},\n\t\t//nolint:gocritic\n\t\t//\"InvalidArg\": {\n\t\t//arg:       \"insecureSkipTLSVerify=wrongtime\",\n\t\t//errString: \"parse argument string options failed\",\n\t\t//},\n\t}\n\n\tfor name, testCase := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(testCase.jsonRaw, testCase.env, testCase.arg)\n\t\t\tif len(testCase.errString) > 0 {\n\t\t\t\trequire.NotNil(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), testCase.errString)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.Equal(t, testCase.config, c)\n\t\t})\n\t}\n}\n\nfunc TestParseServerURL(t *testing.T) {\n\tt.Parallel()\n\n\tc, err := parseArg(\"url=http://prometheus.remote:3412/write\")\n\tassert.Nil(t, err)\n\tassert.Equal(t, null.StringFrom(\"http://prometheus.remote:3412/write\"), c.ServerURL)\n\n\tc, err = parseArg(\"url=http://prometheus.remote:3412/write,insecureSkipTLSVerify=false,pushInterval=2s\")\n\tassert.Nil(t, err)\n\tassert.Equal(t, null.StringFrom(\"http://prometheus.remote:3412/write\"), c.ServerURL)\n\tassert.Equal(t, null.BoolFrom(false), c.InsecureSkipTLSVerify)\n\tassert.Equal(t, types.NullDurationFrom(time.Second*2), c.PushInterval)\n\n\tc, err = parseArg(\"headers.X-Header=value\")\n\tassert.Nil(t, err)\n\tassert.Equal(t, map[string]string{\"X-Header\": \"value\"}, c.Headers)\n}\n\n// TODO: replace all the expconfigs below\n// with a function that returns the expected default values,\n// then override only the values to expect differently.\n\nfunc TestOptionServerURL(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"url\":\"http://prometheus:9090/api/v1/write\"}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_SERVER_URL\": \"http://prometheus:9090/api/v1/write\"}},\n\t\t//nolint:gocritic\n\t\t//\"Arg\":  {arg: \"url=http://prometheus:9090/api/v1/write\"},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://prometheus:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tUsername:              null.NewString(\"\", false),\n\t\tPassword:              null.NewString(\"\", false),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t}\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionHeaders(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(\n\t\t\t`{\"headers\":{\"X-MY-HEADER1\":\"hval1\",\"X-MY-HEADER2\":\"hval2\",\"X-Scope-OrgID\":\"my-org-id\",\"another-header\":\"true\",\"empty\":\"\"}}`)},\n\t\t\"Env\": {env: map[string]string{\n\t\t\t\"K6_PROMETHEUS_RW_HEADERS_X-MY-HEADER1\": \"hval1\",\n\t\t\t\"K6_PROMETHEUS_RW_HEADERS_X-MY-HEADER2\": \"hval2\",\n\t\t\t// it assert that the new method using HTTP_HEADERS overwrites it\n\t\t\t\"K6_PROMETHEUS_RW_HEADERS_X-Scope-OrgID\": \"my-org-id-old-method\",\n\t\t\t\"K6_PROMETHEUS_RW_HTTP_HEADERS\":          \"X-Scope-OrgID:my-org-id,another-header:true,empty:\",\n\t\t}},\n\t\t//nolint:gocritic\n\t\t//\"Arg\":  {arg: \"headers.X-MY-HEADER1=hval1,headers.X-MY-HEADER2=hval2\"},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders: map[string]string{\n\t\t\t\"X-MY-HEADER1\":   \"hval1\",\n\t\t\t\"X-MY-HEADER2\":   \"hval2\",\n\t\t\t\"X-Scope-OrgID\":  \"my-org-id\",\n\t\t\t\"another-header\": \"true\",\n\t\t\t\"empty\":          \"\",\n\t\t},\n\t\tTrendStats:   []string{\"p(99)\"},\n\t\tStaleMarkers: null.BoolFrom(false),\n\t}\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionInsecureSkipTLSVerify(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"insecureSkipTLSVerify\":true}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_INSECURE_SKIP_TLS_VERIFY\": \"true\"}},\n\t\t//nolint:gocritic\n\t\t//\"Arg\":  {arg: \"insecureSkipTLSVerify=false\"},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(defaultServerURL),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(true),\n\t\tPushInterval:          types.NullDurationFrom(defaultPushInterval),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t}\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestTLSMinVersion(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ        string\n\t\tenv        map[string]string\n\t\tjsonRaw    json.RawMessage\n\t\twantRccTLS uint16\n\t\texpconfig  Config\n\t}{\n\t\t\"JSON\": {\n\t\t\tjsonRaw:    json.RawMessage(`{\"tlsMinVersion\":\"1.2\"}`),\n\t\t\twantRccTLS: tls.VersionTLS12,\n\t\t\texpconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tTLSMinVersion:         null.NewString(\"1.2\", true), // depends on test case\n\t\t\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"JSON incorrect\": {\n\t\t\tjsonRaw:    json.RawMessage(`{\"tlsMinVersion\":\"\"}`),\n\t\t\twantRccTLS: tls.VersionTLS13,\n\t\t\texpconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tTLSMinVersion:         null.NewString(\"\", true), // depends on test case\n\t\t\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"Env\": {\n\t\t\tenv:        map[string]string{\"K6_PROMETHEUS_RW_TLS_MINIMUM_VERSION\": \"1.2\"},\n\t\t\twantRccTLS: tls.VersionTLS12,\n\t\t\texpconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tTLSMinVersion:         null.NewString(\"1.2\", true), // depends on test case\n\t\t\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"Env incorrect\": {\n\t\t\tenv:        map[string]string{\"K6_PROMETHEUS_RW_TLS_MINIMUM_VERSION\": \"0.0\"},\n\t\t\twantRccTLS: tls.VersionTLS13,\n\t\t\texpconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tTLSMinVersion:         null.NewString(\"0.0\", true), // depends on test case\n\t\t\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t\"version not set\": {\n\t\t\twantRccTLS: tls.VersionTLS13,\n\t\t\texpconfig: Config{\n\t\t\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\t\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\t\t\tTLSMinVersion:         null.NewString(\"\", false), // depends on test case\n\t\t\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\t\t\tHeaders:               make(map[string]string),\n\t\t\t\tTrendStats:            []string{\"p(99)\"},\n\t\t\t\tStaleMarkers:          null.BoolFrom(false),\n\t\t\t},\n\t\t},\n\t\t// should `ParseArgs` function (for CLI flags) be implemented, add \"Arg\" test case(-s)\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(tc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.expconfig, c)\n\n\t\t\texprcc := &remote.HTTPConfig{\n\t\t\t\tTimeout: 5 * time.Second,\n\t\t\t\tTLSConfig: &tls.Config{\n\t\t\t\t\tInsecureSkipVerify: false,\n\t\t\t\t\tMinVersion:         tc.wantRccTLS,\n\t\t\t\t},\n\t\t\t}\n\t\t\trcc, err := c.RemoteConfig()\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, exprcc, rcc)\n\t\t})\n\t}\n}\n\nfunc TestOptionBasicAuth(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"username\":\"user1\",\"password\":\"pass1\"}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_USERNAME\": \"user1\", \"K6_PROMETHEUS_RW_PASSWORD\": \"pass1\"}},\n\t\t//nolint:gocritic\n\t\t//\"Arg\":  {arg: \"username=user1,password=pass1\"},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tUsername:              null.StringFrom(\"user1\"),\n\t\tPassword:              null.StringFrom(\"pass1\"),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionBearerToken(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"bearerToken\":\"my-bearer-token\"}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_BEARER_TOKEN\": \"my-bearer-token\"}},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tBearerToken:           null.StringFrom(\"my-bearer-token\"),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionClientCertificate(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"clientCertificate\":\"client.crt\",\"clientCertificateKey\":\"client.key\"}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_CLIENT_CERTIFICATE\": \"client.crt\", \"K6_PROMETHEUS_RW_CLIENT_CERTIFICATE_KEY\": \"client.key\"}},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tClientCertificate:     null.StringFrom(\"client.crt\"),\n\t\tClientCertificateKey:  null.StringFrom(\"client.key\"),\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionTrendAsNativeHistogram(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"trendAsNativeHistogram\":true}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM\": \"true\"}},\n\t\t//nolint:gocritic\n\t\t//\"Arg\":  {arg: \"trendAsNativeHistogram=true\"},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:              null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify:  null.BoolFrom(false),\n\t\tUsername:               null.NewString(\"\", false),\n\t\tPassword:               null.NewString(\"\", false),\n\t\tPushInterval:           types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:                make(map[string]string),\n\t\tTrendAsNativeHistogram: null.BoolFrom(true),\n\t\tTrendStats:             []string{\"p(99)\"},\n\t\tStaleMarkers:           null.BoolFrom(false),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionPushInterval(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"pushInterval\":\"1m2s\"}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_PUSH_INTERVAL\": \"1m2s\"}},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tUsername:              null.NewString(\"\", false),\n\t\tPassword:              null.NewString(\"\", false),\n\t\tPushInterval:          types.NullDurationFrom((1 * time.Minute) + (2 * time.Second)),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestConfigTrendStats(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"trendStats\":[\"max\",\"p(95)\"]}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_TREND_STATS\": \"max,p(95)\"}},\n\t\t// TODO: support arg, check the comment in the code\n\t\t//nolint:gocritic\n\t\t//\"Arg\":  {arg: \"trendStats=max,p(95)\"},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"max\", \"p(95)\"},\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionStaleMarker(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`{\"staleMarkers\":true}`)},\n\t\t\"Env\":  {env: map[string]string{\"K6_PROMETHEUS_RW_STALE_MARKERS\": \"true\"}},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tStaleMarkers:          null.BoolFrom(true),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n\nfunc TestOptionSigV4(t *testing.T) {\n\tt.Parallel()\n\n\tcases := map[string]struct {\n\t\targ     string\n\t\tenv     map[string]string\n\t\tjsonRaw json.RawMessage\n\t}{\n\t\t\"JSON\": {jsonRaw: json.RawMessage(`\n{\n  \"sigV4Region\":\"us-east-2\",\n  \"sigV4AccessKey\":\"ASIAUZABC123456\",\n  \"sigV4SecretKey\":\"5wfFi0FEaaaaacccc1111111111111\"\n}\n`)},\n\t\t\"Env\": {env: map[string]string{\n\t\t\t\"K6_PROMETHEUS_RW_SIGV4_REGION\":     \"us-east-2\",\n\t\t\t\"K6_PROMETHEUS_RW_SIGV4_ACCESS_KEY\": \"ASIAUZABC123456\",\n\t\t\t\"K6_PROMETHEUS_RW_SIGV4_SECRET_KEY\": \"5wfFi0FEaaaaacccc1111111111111\",\n\t\t}},\n\t}\n\n\texpconfig := Config{\n\t\tServerURL:             null.StringFrom(\"http://localhost:9090/api/v1/write\"),\n\t\tInsecureSkipTLSVerify: null.BoolFrom(false),\n\t\tPushInterval:          types.NullDurationFrom(5 * time.Second),\n\t\tHeaders:               make(map[string]string),\n\t\tTrendStats:            []string{\"p(99)\"},\n\t\tStaleMarkers:          null.BoolFrom(false),\n\t\tSigV4Region:           null.StringFrom(\"us-east-2\"),\n\t\tSigV4AccessKey:        null.StringFrom(\"ASIAUZABC123456\"),\n\t\tSigV4SecretKey:        null.StringFrom(\"5wfFi0FEaaaaacccc1111111111111\"),\n\t}\n\n\tfor name, tc := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tc, err := GetConsolidatedConfig(\n\t\t\t\ttc.jsonRaw, tc.env, tc.arg)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, expconfig, c)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/prometheus.go",
    "content": "package remotewrite\n\nimport (\n\t\"cmp\"\n\t\"slices\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\t\"github.com/mstoykov/atlas\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst namelbl = \"__name__\"\n\n// MapTagSet converts a k6 tag set into\n// the equivalent set of Labels as expected from the\n// Prometheus' data model.\nfunc MapTagSet(t *metrics.TagSet) []*prompb.Label {\n\tn := (*atlas.Node)(t)\n\tif n.Len() < 1 {\n\t\treturn nil\n\t}\n\tlabels := make([]*prompb.Label, 0, n.Len())\n\tfor !n.IsRoot() {\n\t\tprev, key, value := n.Data()\n\t\tn = prev\n\t\tif key == \"\" || value == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tlabels = append(labels, &prompb.Label{Name: key, Value: value})\n\t}\n\treturn labels\n}\n\n// MapSeries converts a k6 time series into\n// the equivalent set of Labels (name+tags) as expected from the\n// Prometheus' data model.\n//\n// The labels are lexicographic sorted as required\n// from the Remote write's specification.\nfunc MapSeries(series metrics.TimeSeries, suffix string) []*prompb.Label {\n\tv := defaultMetricPrefix + series.Metric.Name\n\tif suffix != \"\" {\n\t\tv += \"_\" + suffix\n\t}\n\tlbls := append(MapTagSet(series.Tags), &prompb.Label{\n\t\tName:  namelbl,\n\t\tValue: v,\n\t})\n\tslices.SortStableFunc(lbls, func(i, j *prompb.Label) int {\n\t\treturn cmp.Compare(i.Name, j.Name)\n\t})\n\treturn lbls\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/prometheus_test.go",
    "content": "package remotewrite\n\nimport (\n\t\"cmp\"\n\t\"slices\"\n\t\"testing\"\n\t\"time\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO: test MapSeries with suffix\n\nfunc TestMapSeries(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\ttags := r.RootTagSet().\n\t\tWith(\"tagk1\", \"tagv1\").With(\"b1\", \"v1\").\n\t\t// labels with empty key or value are not allowed\n\t\t// so they will be not added as labels\n\t\tWith(\"tagEmptyValue\", \"\").\n\t\tWith(\"\", \"tagEmptyKey\")\n\n\tseries := metrics.TimeSeries{\n\t\tMetric: &metrics.Metric{\n\t\t\tName: \"test\",\n\t\t\tType: metrics.Counter,\n\t\t},\n\t\tTags: tags,\n\t}\n\n\tlbls := MapSeries(series, \"\")\n\trequire.Len(t, lbls, 3)\n\n\texp := []*prompb.Label{\n\t\t{Name: \"__name__\", Value: \"k6_test\"},\n\t\t{Name: \"b1\", Value: \"v1\"},\n\t\t{Name: \"tagk1\", Value: \"tagv1\"},\n\t}\n\tassert.Equal(t, exp, lbls)\n}\n\n// buildTimeSeries creates a TimSeries with the given name, value and timestamp\nfunc buildTimeSeries(name string, value float64, timestamp time.Time) *prompb.TimeSeries { //nolint:unparam\n\treturn &prompb.TimeSeries{\n\t\tLabels: []*prompb.Label{\n\t\t\t{\n\t\t\t\tName:  \"__name__\",\n\t\t\t\tValue: name,\n\t\t\t},\n\t\t},\n\t\tSamples: []*prompb.Sample{\n\t\t\t{\n\t\t\t\tValue:     value,\n\t\t\t\tTimestamp: timestamp.UnixMilli(),\n\t\t\t},\n\t\t},\n\t}\n}\n\n// assertTimeSeriesMatch asserts if the elements of two slices of TimeSeries matches.\nfunc assertTimeSeriesEqual(t *testing.T, expected []*prompb.TimeSeries, actual []*prompb.TimeSeries) {\n\tt.Helper()\n\trequire.Len(t, actual, len(expected))\n\n\tfor i := range expected {\n\t\tassert.Equal(t, expected[i], actual[i])\n\t}\n}\n\n// sortByLabelName sorts a slice of time series by __name__ label.\nfunc sortByNameLabel(s []*prompb.TimeSeries) {\n\tslices.SortStableFunc(s, func(i, j *prompb.TimeSeries) int {\n\t\treturn cmp.Compare(findNameLabel(i.Labels), findNameLabel(j.Labels))\n\t})\n}\n\n// sortByLabelName sorts a slice of time series by __name__ label.\nfunc findNameLabel(labels []*prompb.Label) string {\n\tfor _, l := range labels {\n\t\tif l.Name == namelbl {\n\t\t\treturn l.Value\n\t\t}\n\t}\n\t// This should never happen whenever we use this test helper.\n\tpanic(\"__name__ label must be present\")\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/remotewrite.go",
    "content": "// Package remotewrite is a k6 output that sends metrics to a Prometheus remote write endpoint.\npackage remotewrite\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/output/prometheusrw/remote\"\n\t\"go.k6.io/k6/internal/output/prometheusrw/stale\"\n\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\t\"github.com/sirupsen/logrus\"\n)\n\nvar _ output.Output = new(Output)\n\n// Output is a k6 output that sends metrics to a Prometheus remote write endpoint.\ntype Output struct {\n\toutput.SampleBuffer\n\n\tconfig             Config\n\tlogger             logrus.FieldLogger\n\tnow                func() time.Time\n\tperiodicFlusher    *output.PeriodicFlusher\n\ttsdb               map[metrics.TimeSeries]*seriesWithMeasure\n\ttrendStatsResolver map[string]func(*metrics.TrendSink) float64\n\n\t// TODO: copy the prometheus/remote.WriteClient interface and depend on it\n\tclient *remote.WriteClient\n}\n\n// New creates a new Output instance.\nfunc New(params output.Params) (*Output, error) {\n\tlogger := params.Logger.WithFields(logrus.Fields{\"output\": \"Prometheus remote write\"})\n\n\tconfig, err := GetConsolidatedConfig(params.JSONConfig, params.Environment, params.ConfigArgument)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclientConfig, err := config.RemoteConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\twc, err := remote.NewWriteClient(config.ServerURL.String, clientConfig)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize the Prometheus remote write client: %w\", err)\n\t}\n\n\to := &Output{\n\t\tclient: wc,\n\t\tconfig: config,\n\t\t// TODO: consider to do this function millisecond-based\n\t\t// so we don't need to truncate all the time we invoke it.\n\t\t// Before we should analyze if in some cases is it useful to have it in ns.\n\t\tnow:    time.Now,\n\t\tlogger: logger,\n\t\ttsdb:   make(map[metrics.TimeSeries]*seriesWithMeasure),\n\t}\n\n\tif len(config.TrendStats) > 0 {\n\t\tif err := o.setTrendStatsResolver(config.TrendStats); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn o, nil\n}\n\n// Description returns a short human-readable description of the output.\nfunc (o *Output) Description() string {\n\treturn fmt.Sprintf(\"Prometheus remote write (%s)\", o.config.ServerURL.String)\n}\n\n// Start initializes the output.\nfunc (o *Output) Start() error {\n\td := o.config.PushInterval.TimeDuration()\n\tperiodicFlusher, err := output.NewPeriodicFlusher(d, o.flush)\n\tif err != nil {\n\t\treturn err\n\t}\n\to.periodicFlusher = periodicFlusher\n\to.logger.WithField(\"flushtime\", d).Debug(\"Output initialized\")\n\treturn nil\n}\n\n// Stop stops the output.\nfunc (o *Output) Stop() error {\n\to.logger.Debug(\"Stopping the output\")\n\tdefer o.logger.Debug(\"Output stopped\")\n\to.periodicFlusher.Stop()\n\n\tif !o.config.StaleMarkers.Bool {\n\t\treturn nil\n\t}\n\tstaleMarkers := o.staleMarkers()\n\tif len(staleMarkers) < 1 {\n\t\to.logger.Debug(\"No time series to mark as stale\")\n\t\treturn nil\n\t}\n\to.logger.WithField(\"staleMarkers\", len(staleMarkers)).Debug(\"Marking time series as stale\")\n\n\terr := o.client.Store(context.Background(), staleMarkers)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marking time series as stale failed: %w\", err)\n\t}\n\treturn nil\n}\n\n// staleMarkers maps all the seen time series with a stale marker.\nfunc (o *Output) staleMarkers() []*prompb.TimeSeries {\n\t// Add 1ms so in the extreme case that the time frame\n\t// between the last and the next flush operation is under-millisecond,\n\t// we can avoid the sample being seen as a duplicate,\n\t// if we force it in the future.\n\t// It is essential because if it overlaps, the remote write discards the last sample,\n\t// so the stale marker and the metric will remain active for the next 5 min\n\t// as the default logic without stale markers.\n\ttimestamp := o.now().\n\t\tTruncate(time.Millisecond).Add(1 * time.Millisecond).UnixMilli()\n\n\tstaleMarkers := make([]*prompb.TimeSeries, 0, len(o.tsdb))\n\tfor _, swm := range o.tsdb {\n\t\tseries := swm.MapPrompb()\n\t\t// series' length is expected to be equal to 1 for most of the cases\n\t\t// the unique exception where more than 1 is expected is when\n\t\t// trend stats have been configured with multiple values.\n\t\tfor _, s := range series {\n\t\t\tif len(s.Samples) < 1 {\n\t\t\t\tif len(s.Histograms) < 1 {\n\t\t\t\t\tpanic(\"data integrity check: samples and native histograms\" +\n\t\t\t\t\t\t\" can't be empty at the same time\")\n\t\t\t\t}\n\t\t\t\ts.Samples = append(s.Samples, &prompb.Sample{})\n\t\t\t}\n\n\t\t\ts.Samples[0].Value = stale.Marker\n\t\t\ts.Samples[0].Timestamp = timestamp\n\t\t}\n\t\tstaleMarkers = append(staleMarkers, series...)\n\t}\n\treturn staleMarkers\n}\n\n// setTrendStatsResolver sets the resolver for the Trend stats.\n//\n// TODO: refactor, the code can be improved\nfunc (o *Output) setTrendStatsResolver(trendStats []string) error {\n\ttrendStatsCopy := make([]string, 0, len(trendStats))\n\thasSum := false\n\t// copy excluding sum\n\tfor _, stat := range trendStats {\n\t\tif stat == \"sum\" {\n\t\t\thasSum = true\n\t\t\tcontinue\n\t\t}\n\t\ttrendStatsCopy = append(trendStatsCopy, stat)\n\t}\n\tresolvers, err := metrics.GetResolversForTrendColumns(trendStatsCopy)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// sum is not supported from GetResolversForTrendColumns\n\t// so if it has been requested\n\t// it adds it specifically\n\tif hasSum {\n\t\tresolvers[\"sum\"] = func(t *metrics.TrendSink) float64 {\n\t\t\treturn t.Total()\n\t\t}\n\t}\n\to.trendStatsResolver = make(TrendStatsResolver, len(resolvers))\n\tfor stat, fn := range resolvers {\n\t\tstatKey := stat\n\n\t\t// the config passes percentiles with p(x) form, for example p(95),\n\t\t// but the mapping generates series name in the form p95.\n\t\t//\n\t\t// TODO: maybe decoupling mapping from the stat resolver keys?\n\t\tif strings.HasPrefix(statKey, \"p(\") {\n\t\t\tstatKey = stat[2 : len(statKey)-1]             // trim the parenthesis\n\t\t\tstatKey = strings.ReplaceAll(statKey, \".\", \"\") // remove dots, p(0.95) => p095\n\t\t\tstatKey = \"p\" + statKey\n\t\t}\n\t\to.trendStatsResolver[statKey] = fn\n\t}\n\treturn nil\n}\n\nfunc (o *Output) flush() {\n\tvar (\n\t\tstart = time.Now()\n\t\tnts   int\n\t)\n\n\tdefer func() {\n\t\td := time.Since(start)\n\t\tokmsg := \"Successful flushed time series to remote write endpoint\"\n\t\tif d > time.Duration(o.config.PushInterval.Duration) {\n\t\t\t// There is no intermediary storage so warn if writing to remote write endpoint becomes too slow\n\t\t\to.logger.WithField(\"nts\", nts).\n\t\t\t\tWarnf(\"%s but it took %s while flush period is %s. Some samples may be dropped.\",\n\t\t\t\t\tokmsg, d.String(), o.config.PushInterval.String())\n\t\t} else {\n\t\t\to.logger.WithField(\"nts\", nts).WithField(\"took\", d).Debug(okmsg)\n\t\t}\n\t}()\n\n\tsamplesContainers := o.GetBufferedSamples()\n\tif len(samplesContainers) < 1 {\n\t\to.logger.Debug(\"no buffered samples, skip the flushing operation\")\n\t\treturn\n\t}\n\n\t// Remote write endpoint accepts TimeSeries structure defined in gRPC. It must:\n\t// a) contain Labels array\n\t// b) have a __name__ label: without it, metric might be unquerable or even rejected\n\t// as a metric without a name. This behaviour depends on underlying storage used.\n\t// c) not have duplicate timestamps within 1 timeseries, see https://github.com/prometheus/prometheus/issues/9210\n\t// Prometheus write handler processes only some fields as of now, so here we'll add only them.\n\n\tpromTimeSeries := o.convertToPbSeries(samplesContainers)\n\tnts = len(promTimeSeries)\n\to.logger.WithField(\"nts\", nts).Debug(\"Converted samples to Prometheus TimeSeries\")\n\n\tif err := o.client.Store(context.Background(), promTimeSeries); err != nil {\n\t\to.logger.WithError(err).Error(\"Failed to send the time series data to the endpoint\")\n\t\treturn\n\t}\n}\n\nfunc (o *Output) convertToPbSeries(samplesContainers []metrics.SampleContainer) []*prompb.TimeSeries {\n\t// The seen map is required because the samples containers\n\t// could have several samples for the same time series\n\t//  in this way, we can aggregate and flush them in a unique value\n\t//  without overloading the remote write endpoint.\n\t//\n\t// It is also essential because the core generates timestamps\n\t// with a higher precision (ns) than Prometheus (ms),\n\t// so we need to aggregate all the samples in the same time bucket.\n\t// More context can be found in the issue\n\t// https://github.com/grafana/xk6-output-prometheus-remote/issues/11\n\tseen := make(map[metrics.TimeSeries]struct{})\n\n\tfor _, samplesContainer := range samplesContainers {\n\t\tsamples := samplesContainer.GetSamples()\n\n\t\tfor _, sample := range samples {\n\t\t\ttruncTime := sample.Time.Truncate(time.Millisecond)\n\t\t\tswm, ok := o.tsdb[sample.TimeSeries]\n\t\t\tif !ok {\n\t\t\t\t// TODO: encapsulate the trend arguments into a Trend Mapping factory\n\t\t\t\tswm = newSeriesWithMeasure(sample.TimeSeries, o.config.TrendAsNativeHistogram.Bool, o.trendStatsResolver)\n\t\t\t\tswm.Latest = truncTime\n\t\t\t\to.tsdb[sample.TimeSeries] = swm\n\t\t\t\tseen[sample.TimeSeries] = struct{}{}\n\t\t\t} else { //nolint:gocritic\n\t\t\t\t// FIXME: remove the gocritic linter inhibition as soon as the rest of the todo are done\n\t\t\t\t// save as a seen item only when the samples have a time greater than\n\t\t\t\t// the previous saved, otherwise some implementations\n\t\t\t\t// could see it as a duplicate and generate warnings (e.g. Mimir)\n\t\t\t\tif truncTime.After(swm.Latest) {\n\t\t\t\t\tswm.Latest = truncTime\n\t\t\t\t\tseen[sample.TimeSeries] = struct{}{}\n\t\t\t\t}\n\n\t\t\t\t// If current == previous:\n\t\t\t\t// the current received time before being truncated had a higher precision.\n\t\t\t\t// It's fine to aggregate them but we avoid to add to the seen map because:\n\t\t\t\t// - in the case it is a new flush operation then we avoid delivering\n\t\t\t\t//   for not generating duplicates\n\t\t\t\t// - in the case it is in the same operation but across sample containers\n\t\t\t\t//   then the time series should be already on the seen map and we can skip\n\t\t\t\t//   to re-add it.\n\n\t\t\t\t// If current < previous:\n\t\t\t\t// - in the case current is a new flush operation, it shouldn't happen,\n\t\t\t\t//   for this reason, we can avoid creating a dedicated logic.\n\t\t\t\t//   TODO: We should evaluate if it would be better to have a defensive condition\n\t\t\t\t//   for handling it, logging a warning or returning an error\n\t\t\t\t//   and avoid aggregating the value.\n\t\t\t\t// - in the case current is in the same operation but across sample containers\n\t\t\t\t//   it's fine to aggregate\n\t\t\t\t//   but same as for the equal condition it can rely on the previous seen value.\n\t\t\t}\n\t\t\tswm.Measure.Add(sample)\n\t\t}\n\t}\n\n\tpbseries := make([]*prompb.TimeSeries, 0, len(seen))\n\tfor s := range seen {\n\t\tpbseries = append(pbseries, o.tsdb[s].MapPrompb()...)\n\t}\n\treturn pbseries\n}\n\ntype seriesWithMeasure struct {\n\tmetrics.TimeSeries\n\tMeasure metrics.Sink\n\n\t// Latest tracks the latest time\n\t// when the measure has been updated\n\t//\n\t// TODO: the logic for this value should stay directly\n\t// in a method in struct\n\tLatest time.Time\n\n\t// TODO: maybe add some caching for the mapping?\n}\n\n// TODO: add unit tests\nfunc (swm seriesWithMeasure) MapPrompb() []*prompb.TimeSeries {\n\tvar newts []*prompb.TimeSeries\n\n\tmapMonoSeries := func(s metrics.TimeSeries, suffix string, t time.Time) prompb.TimeSeries {\n\t\treturn prompb.TimeSeries{\n\t\t\tLabels: MapSeries(s, suffix),\n\t\t\tSamples: []*prompb.Sample{\n\t\t\t\t{Timestamp: t.UnixMilli()},\n\t\t\t},\n\t\t}\n\t}\n\n\t//nolint:forcetypeassert\n\tswitch swm.Metric.Type {\n\tcase metrics.Counter:\n\t\tts := mapMonoSeries(swm.TimeSeries, \"total\", swm.Latest)\n\t\tts.Samples[0].Value = swm.Measure.(*metrics.CounterSink).Value\n\t\tnewts = []*prompb.TimeSeries{&ts}\n\n\tcase metrics.Gauge:\n\t\tts := mapMonoSeries(swm.TimeSeries, \"\", swm.Latest)\n\t\tts.Samples[0].Value = swm.Measure.(*metrics.GaugeSink).Value\n\t\tnewts = []*prompb.TimeSeries{&ts}\n\n\tcase metrics.Rate:\n\t\tts := mapMonoSeries(swm.TimeSeries, \"rate\", swm.Latest)\n\t\t// pass zero duration here because time is useless for formatting rate\n\t\trateVals := swm.Measure.(*metrics.RateSink).Format(time.Duration(0))\n\t\tts.Samples[0].Value = rateVals[\"rate\"]\n\t\tnewts = []*prompb.TimeSeries{&ts}\n\n\tcase metrics.Trend:\n\t\t// TODO:\n\t\t//\t- Add a PrompbMapSinker interface\n\t\t//    and implements it on all the sinks \"extending\" them.\n\t\t//  - Call directly MapPrompb on Measure without any type assertion.\n\t\ttrend, ok := swm.Measure.(prompbMapper)\n\t\tif !ok {\n\t\t\tpanic(\"Measure for Trend types must implement MapPromPb\")\n\t\t}\n\t\tnewts = trend.MapPrompb(swm.TimeSeries, swm.Latest)\n\n\tdefault:\n\t\tpanic(\n\t\t\tfmt.Sprintf(\n\t\t\t\t\"the output reached an unrecoverable state; unable to recognize processed metric %s's type `%s`\",\n\t\t\t\tswm.Metric.Name,\n\t\t\t\tswm.Metric.Type,\n\t\t\t),\n\t\t)\n\t}\n\treturn newts\n}\n\ntype prompbMapper interface {\n\tMapPrompb(series metrics.TimeSeries, t time.Time) []*prompb.TimeSeries\n}\n\nfunc newSeriesWithMeasure(\n\tseries metrics.TimeSeries,\n\ttrendAsNativeHistogram bool,\n\ttsr TrendStatsResolver,\n) *seriesWithMeasure {\n\tvar sink metrics.Sink\n\tswitch series.Metric.Type {\n\tcase metrics.Counter:\n\t\tsink = &metrics.CounterSink{}\n\tcase metrics.Gauge:\n\t\tsink = &metrics.GaugeSink{}\n\tcase metrics.Trend:\n\t\t// TODO: refactor encapsulating in a factory method\n\t\tif trendAsNativeHistogram {\n\t\t\tsink = newNativeHistogramSink(series.Metric)\n\t\t} else {\n\t\t\tvar err error\n\t\t\tsink, err = newExtendedTrendSink(tsr)\n\t\t\tif err != nil {\n\t\t\t\t// the resolver must be already validated\n\t\t\t\tpanic(err)\n\t\t\t}\n\t\t}\n\tcase metrics.Rate:\n\t\tsink = &metrics.RateSink{}\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"metric type %q unsupported\", series.Metric.Type.String()))\n\t}\n\treturn &seriesWithMeasure{\n\t\tTimeSeries: series,\n\t\tMeasure:    sink,\n\t}\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/remotewrite_test.go",
    "content": "package remotewrite\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestOutputDescription(t *testing.T) {\n\tt.Parallel()\n\to := Output{\n\t\tconfig: Config{\n\t\t\tServerURL: null.StringFrom(\"http://remote-url.fake\"),\n\t\t},\n\t}\n\texp := \"Prometheus remote write (http://remote-url.fake)\"\n\tassert.Equal(t, exp, o.Description())\n}\n\nfunc TestOutputConvertToPbSeries(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\tmetric1 := registry.MustNewMetric(\"metric1\", metrics.Counter)\n\ttagset := registry.RootTagSet().With(\"tagk1\", \"tagv1\")\n\n\tsamples := []metrics.SampleContainer{\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: metric1,\n\t\t\t\tTags:   tagset,\n\t\t\t},\n\t\t\tTime:  time.Date(2022, time.September, 1, 0, 0, 0, 0, time.UTC),\n\t\t\tValue: 3,\n\t\t},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: metric1,\n\t\t\t\tTags:   tagset,\n\t\t\t},\n\t\t\tTime:  time.Date(2022, time.August, 31, 0, 0, 0, 0, time.UTC),\n\t\t\tValue: 4,\n\t\t},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: registry.MustNewMetric(\"metric2\", metrics.Counter),\n\t\t\t\tTags:   tagset,\n\t\t\t},\n\t\t\tTime:  time.Date(2022, time.September, 1, 0, 0, 0, 0, time.UTC),\n\t\t\tValue: 2,\n\t\t},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: registry.MustNewMetric(\"metric3\", metrics.Rate),\n\t\t\t\tTags:   tagset,\n\t\t\t},\n\t\t\tTime:  time.Date(2022, time.September, 1, 0, 0, 0, 0, time.UTC),\n\t\t\tValue: 7,\n\t\t},\n\t\tmetrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: registry.MustNewMetric(\"metric4\", metrics.Trend),\n\t\t\t\tTags: registry.RootTagSet().WithTagsFromMap(tagset.Map()).\n\t\t\t\t\tWith(\"We_need\", \"value\").\n\t\t\t\t\tWith(\"a_long\", \"value\").\n\t\t\t\t\tWith(\"list_of\", \"value\").\n\t\t\t\t\tWith(\"tags_to\", \"value\").\n\t\t\t\t\tWith(\"reproduce_5175\", \"value\"),\n\t\t\t},\n\t\t\tTime:  time.Date(2022, time.September, 1, 0, 0, 0, 0, time.UTC),\n\t\t\tValue: 55,\n\t\t},\n\t}\n\n\to := Output{\n\t\ttsdb: make(map[metrics.TimeSeries]*seriesWithMeasure),\n\t}\n\trequire.NoError(t, o.setTrendStatsResolver([]string{\"p(90)\", \"p(95)\", \"max\"}))\n\n\tpbseries := o.convertToPbSeries(samples)\n\trequire.Len(t, pbseries, 6)\n\trequire.Len(t, o.tsdb, 4)\n\n\tunix1sept := int64(1661990400 * 1000) // in ms\n\texp := []*prompb.TimeSeries{\n\t\t{\n\t\t\tLabels: []*prompb.Label{\n\t\t\t\t{Name: \"__name__\", Value: \"k6_metric1_total\"},\n\t\t\t\t{Name: \"tagk1\", Value: \"tagv1\"},\n\t\t\t},\n\t\t\tSamples: []*prompb.Sample{\n\t\t\t\t{Value: 7, Timestamp: unix1sept},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tLabels: []*prompb.Label{\n\t\t\t\t{Name: \"__name__\", Value: \"k6_metric2_total\"},\n\t\t\t\t{Name: \"tagk1\", Value: \"tagv1\"},\n\t\t\t},\n\t\t\tSamples: []*prompb.Sample{\n\t\t\t\t{Value: 2, Timestamp: unix1sept},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tLabels: []*prompb.Label{\n\t\t\t\t{Name: \"__name__\", Value: \"k6_metric3_rate\"},\n\t\t\t\t{Name: \"tagk1\", Value: \"tagv1\"},\n\t\t\t},\n\t\t\tSamples: []*prompb.Sample{\n\t\t\t\t{Value: 1, Timestamp: unix1sept},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tLabels: []*prompb.Label{\n\t\t\t\t{Name: \"We_need\", Value: \"value\"},\n\t\t\t\t{Name: \"__name__\", Value: \"k6_metric4_max\"},\n\t\t\t\t{Name: \"a_long\", Value: \"value\"},\n\t\t\t\t{Name: \"list_of\", Value: \"value\"},\n\t\t\t\t{Name: \"reproduce_5175\", Value: \"value\"},\n\t\t\t\t{Name: \"tagk1\", Value: \"tagv1\"},\n\t\t\t\t{Name: \"tags_to\", Value: \"value\"},\n\t\t\t},\n\t\t\tSamples: []*prompb.Sample{\n\t\t\t\t{Value: 55, Timestamp: unix1sept},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tLabels: []*prompb.Label{\n\t\t\t\t{Name: \"We_need\", Value: \"value\"},\n\t\t\t\t{Name: \"__name__\", Value: \"k6_metric4_p90\"},\n\t\t\t\t{Name: \"a_long\", Value: \"value\"},\n\t\t\t\t{Name: \"list_of\", Value: \"value\"},\n\t\t\t\t{Name: \"reproduce_5175\", Value: \"value\"},\n\t\t\t\t{Name: \"tagk1\", Value: \"tagv1\"},\n\t\t\t\t{Name: \"tags_to\", Value: \"value\"},\n\t\t\t},\n\t\t\tSamples: []*prompb.Sample{\n\t\t\t\t{Value: 55, Timestamp: unix1sept},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tLabels: []*prompb.Label{\n\t\t\t\t{Name: \"We_need\", Value: \"value\"},\n\t\t\t\t{Name: \"__name__\", Value: \"k6_metric4_p95\"},\n\t\t\t\t{Name: \"a_long\", Value: \"value\"},\n\t\t\t\t{Name: \"list_of\", Value: \"value\"},\n\t\t\t\t{Name: \"reproduce_5175\", Value: \"value\"},\n\t\t\t\t{Name: \"tagk1\", Value: \"tagv1\"},\n\t\t\t\t{Name: \"tags_to\", Value: \"value\"},\n\t\t\t},\n\t\t\tSamples: []*prompb.Sample{\n\t\t\t\t{Value: 55, Timestamp: unix1sept},\n\t\t\t},\n\t\t},\n\t}\n\n\tsortByNameLabel(pbseries)\n\tassert.Equal(t, exp, pbseries)\n}\n\n//nolint:paralleltest,tparallel\nfunc TestOutputConvertToPbSeries_WithPreviousState(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\tmetric1 := registry.MustNewMetric(\"metric1\", metrics.Counter)\n\ttagset := registry.RootTagSet().With(\"tagk1\", \"tagv1\")\n\tt0 := time.Date(2022, time.September, 1, 0, 0, 0, 0, time.UTC).Add(10 * time.Millisecond)\n\n\tswm := &seriesWithMeasure{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: metric1,\n\t\t\tTags:   tagset,\n\t\t},\n\t\tLatest: t0,\n\t\t// it's not relevant for this test to initialize the Sink's values\n\t\tMeasure: &metrics.CounterSink{},\n\t}\n\n\to := Output{\n\t\ttsdb: map[metrics.TimeSeries]*seriesWithMeasure{\n\t\t\tswm.TimeSeries: swm,\n\t\t},\n\t}\n\n\ttestcases := []struct {\n\t\tname      string\n\t\ttime      time.Time\n\t\texpSeries int\n\t\texpCount  float64\n\t\texpLatest time.Time\n\t}{\n\t\t{\n\t\t\tname:      \"Before\",\n\t\t\ttime:      time.Date(2022, time.August, 31, 0, 0, 0, 0, time.UTC),\n\t\t\texpSeries: 0,\n\t\t\texpCount:  1,\n\t\t\texpLatest: t0,\n\t\t},\n\t\t{\n\t\t\tname:      \"AfterButSub-ms\", // so equal when truncated\n\t\t\ttime:      t0.Add(10 * time.Microsecond),\n\t\t\texpSeries: 0,\n\t\t\texpCount:  2,\n\t\t\texpLatest: time.Date(2022, time.September, 1, 0, 0, 0, int(10*time.Millisecond), time.UTC),\n\t\t},\n\t\t{\n\t\t\tname:      \"After\",\n\t\t\ttime:      t0.Add(1 * time.Millisecond),\n\t\t\texpSeries: 1,\n\t\t\texpCount:  3,\n\t\t\texpLatest: time.Date(2022, time.September, 1, 0, 0, 0, int(11*time.Millisecond), time.UTC),\n\t\t},\n\t}\n\n\tfor _, tc := range testcases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tpbseries := o.convertToPbSeries([]metrics.SampleContainer{\n\t\t\t\tmetrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: metric1,\n\t\t\t\t\t\tTags:   tagset,\n\t\t\t\t\t},\n\t\t\t\t\tValue: 1,\n\t\t\t\t\tTime:  tc.time,\n\t\t\t\t},\n\t\t\t})\n\t\t\trequire.Len(t, o.tsdb, 1)\n\t\t\trequire.Equal(t, tc.expSeries, len(pbseries))\n\t\t\tassert.Equal(t, tc.expCount, swm.Measure.(*metrics.CounterSink).Value)\n\t\t\tassert.Equal(t, tc.expLatest, swm.Latest)\n\t\t})\n\t}\n}\n\nfunc TestNewSeriesWithK6SinkMeasure(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\texpSink    metrics.Sink\n\t\tmetricType metrics.MetricType\n\t}{\n\t\t{\n\t\t\tmetricType: metrics.Counter,\n\t\t\texpSink:    &metrics.CounterSink{},\n\t\t},\n\t\t{\n\t\t\tmetricType: metrics.Gauge,\n\t\t\texpSink:    &metrics.GaugeSink{},\n\t\t},\n\t\t{\n\t\t\tmetricType: metrics.Rate,\n\t\t\texpSink:    &metrics.RateSink{},\n\t\t},\n\t\t{\n\t\t\tmetricType: metrics.Trend,\n\t\t\texpSink:    &extendedTrendSink{},\n\t\t},\n\t}\n\n\tregistry := metrics.NewRegistry()\n\tfor i, tt := range tests {\n\t\ts := metrics.TimeSeries{\n\t\t\tMetric: registry.MustNewMetric(fmt.Sprintf(\"metric%d\", i), tt.metricType),\n\t\t}\n\t\tresolvers, err := metrics.GetResolversForTrendColumns([]string{\"avg\"})\n\t\trequire.NoError(t, err)\n\t\tswm := newSeriesWithMeasure(s, false, resolvers)\n\t\trequire.NotNil(t, swm)\n\t\tassert.Equal(t, s, swm.TimeSeries)\n\t\trequire.NotNil(t, swm.Measure)\n\t\tassert.IsType(t, tt.expSink, swm.Measure)\n\t}\n}\n\nfunc TestNewSeriesWithNativeHistogramMeasure(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\ts := metrics.TimeSeries{\n\t\tMetric: registry.MustNewMetric(\"metric1\", metrics.Trend),\n\t}\n\n\tswm := newSeriesWithMeasure(s, true, nil)\n\trequire.NotNil(t, swm)\n\tassert.Equal(t, s, swm.TimeSeries)\n\trequire.NotNil(t, swm.Measure)\n\n\tnhs, ok := swm.Measure.(*nativeHistogramSink)\n\trequire.True(t, ok)\n\tassert.NotNil(t, nhs.H)\n}\n\nfunc TestOutputSetTrendStatsResolver(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tstats           []string\n\t\texpResolverKeys []string\n\t}{\n\t\t{\n\t\t\tstats:           []string{},\n\t\t\texpResolverKeys: []string{},\n\t\t},\n\t\t{\n\t\t\tstats:           []string{\"sum\"},\n\t\t\texpResolverKeys: []string{\"sum\"},\n\t\t},\n\t\t{\n\t\t\tstats:           []string{\"avg\"},\n\t\t\texpResolverKeys: []string{\"avg\"},\n\t\t},\n\t\t{\n\t\t\tstats:           []string{\"p(27)\", \"p(0.999)\", \"p(1)\", \"p(0)\"},\n\t\t\texpResolverKeys: []string{\"p27\", \"p0999\", \"p1\", \"p0\"},\n\t\t},\n\t\t{\n\t\t\tstats: []string{\n\t\t\t\t\"count\", \"sum\",\n\t\t\t\t\"max\", \"min\", \"med\", \"avg\", \"p(90)\", \"p(99)\",\n\t\t\t},\n\t\t\texpResolverKeys: []string{\n\t\t\t\t\"count\", \"sum\",\n\t\t\t\t\"max\", \"min\", \"med\", \"avg\", \"p90\", \"p99\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\to := Output{}\n\t\terr := o.setTrendStatsResolver(tt.stats)\n\t\trequire.NoError(t, err)\n\t\trequire.NotNil(t, o.trendStatsResolver)\n\n\t\tassert.Len(t, o.trendStatsResolver, len(tt.expResolverKeys))\n\t\tassert.ElementsMatch(t, tt.expResolverKeys, func() []string {\n\t\t\tkeys := make([]string, 0, len(o.trendStatsResolver))\n\t\t\tfor statKey := range o.trendStatsResolver {\n\t\t\t\tkeys = append(keys, statKey)\n\t\t\t}\n\t\t\treturn keys\n\t\t}())\n\t}\n}\n\nfunc TestOutputStaleMarkers(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\ttrendSinkSeries := metrics.TimeSeries{\n\t\tMetric: registry.MustNewMetric(\"metric1\", metrics.Trend),\n\t\tTags:   registry.RootTagSet(),\n\t}\n\tcounterSinkSeries := metrics.TimeSeries{\n\t\tMetric: registry.MustNewMetric(\"metric2\", metrics.Counter),\n\t\tTags:   registry.RootTagSet(),\n\t}\n\n\to := Output{\n\t\tnow: func() time.Time {\n\t\t\treturn time.Unix(1, 0)\n\t\t},\n\t}\n\terr := o.setTrendStatsResolver([]string{\"p(99)\"})\n\trequire.NoError(t, err)\n\ttrendSink, err := newExtendedTrendSink(o.trendStatsResolver)\n\trequire.NoError(t, err)\n\n\to.tsdb = map[metrics.TimeSeries]*seriesWithMeasure{\n\t\ttrendSinkSeries: {\n\t\t\tTimeSeries: trendSinkSeries,\n\t\t\t// TODO: if Measure is a lighter interface\n\t\t\t// then it can be just a mapper mock.\n\t\t\tMeasure: trendSink,\n\t\t},\n\t\tcounterSinkSeries: {\n\t\t\tTimeSeries: counterSinkSeries,\n\t\t\tMeasure:    &metrics.CounterSink{},\n\t\t},\n\t}\n\n\tmarkers := o.staleMarkers()\n\trequire.Len(t, markers, 2)\n\n\tsortByNameLabel(markers)\n\texpNameLabels := []string{\"k6_metric1_p99\", \"k6_metric2_total\"}\n\texpTimestamp := time.Unix(1, int64(1*time.Millisecond)).UnixMilli()\n\tfor i, expName := range expNameLabels {\n\t\tassert.Equal(t, expName, markers[i].Labels[0].Value)\n\t\tassert.Equal(t, expTimestamp, markers[i].Samples[0].Timestamp)\n\t\tassert.True(t, math.IsNaN(markers[i].Samples[0].Value), \"it isn't a StaleNaN value\")\n\t}\n}\n\nfunc TestOutputStopWithStaleMarkers(t *testing.T) {\n\tt.Parallel()\n\n\tfor _, tc := range []bool{true, false} {\n\t\tbuf := bytes.NewBuffer(nil)\n\t\tlogger := logrus.New()\n\t\tlogger.SetLevel(logrus.DebugLevel)\n\t\tlogger.SetOutput(buf)\n\n\t\to := Output{\n\t\t\tlogger: logger,\n\t\t\tconfig: Config{\n\t\t\t\t// setting a large interval so it does not trigger\n\t\t\t\t// and the trigger can be inoked only when Stop is\n\t\t\t\t// invoked.\n\t\t\t\tPushInterval: types.NullDurationFrom(1 * time.Hour),\n\t\t\t\tStaleMarkers: null.BoolFrom(tc),\n\t\t\t},\n\t\t\tnow: time.Now,\n\t\t}\n\n\t\terr := o.Start()\n\t\trequire.NoError(t, err)\n\t\terr = o.Stop()\n\t\trequire.NoError(t, err)\n\n\t\t// TODO: it isn't optimal to maintain\n\t\t// if a new logline is added in Start or flushMetrics\n\t\t// then this test will break\n\t\t// A mock of the client and check if Store is invoked\n\t\t// should be a more stable method.\n\t\tmessages := buf.String()\n\t\tmsg := \"No time series to mark as stale\"\n\t\tassertfn := assert.Contains\n\t\tif !tc {\n\t\t\tassertfn = assert.NotContains\n\t\t}\n\t\tassertfn(t, messages, msg)\n\t}\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/trend.go",
    "content": "package remotewrite\n\nimport (\n\t\"cmp\"\n\t\"fmt\"\n\t\"slices\"\n\t\"time\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n\tdto \"github.com/prometheus/client_model/go\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TrendStatsResolver is a map of trend stats name and their relative resolver function\ntype TrendStatsResolver map[string]func(*metrics.TrendSink) float64\n\ntype extendedTrendSink struct {\n\t*metrics.TrendSink\n\n\ttrendStats map[string]func(*metrics.TrendSink) float64\n}\n\nfunc newExtendedTrendSink(tsr TrendStatsResolver) (*extendedTrendSink, error) {\n\tif len(tsr) < 1 {\n\t\treturn nil, fmt.Errorf(\"trend stats resolver is empty\")\n\t}\n\treturn &extendedTrendSink{\n\t\tTrendSink:  metrics.NewTrendSink(),\n\t\ttrendStats: tsr,\n\t}, nil\n}\n\n// MapPrompb converts a k6 time series and its relative\n// Sink into the equivalent TimeSeries model as defined from\n// the Remote write specification.\nfunc (sink *extendedTrendSink) MapPrompb(series metrics.TimeSeries, t time.Time) []*prompb.TimeSeries {\n\t// Prometheus metric system does not support Trend so this mapping will\n\t// store a counter for the number of reported values and gauges to keep\n\t// track of aggregated values. Also store a sum of the values to allow\n\t// the calculation of moving averages.\n\t// TODO: when Prometheus implements support for sparse histograms, re-visit this implementation\n\n\ttg := &trendAsGauges{\n\t\tseries: make([]*prompb.TimeSeries, 0, len(sink.trendStats)),\n\t\t// TODO: should we add the base unit suffix?\n\t\t// It could depends from the decision for other metric types\n\t\t// Does k6_http_req_duration_seconds_count make sense?\n\t\tlabels:    MapSeries(series, \"\"),\n\t\ttimestamp: t.UnixMilli(),\n\t}\n\ttg.CacheNameIndex()\n\n\tfor stat, statfn := range sink.trendStats {\n\t\ttg.Append(stat, adaptUnit(series.Metric.Contains, statfn(sink.TrendSink)))\n\t}\n\treturn tg.series\n}\n\ntype trendAsGauges struct {\n\t// series is the slice of the converted TimeSeries.\n\tseries []*prompb.TimeSeries\n\n\t// labels are the shared labels between all the Gauges.\n\tlabels []*prompb.Label\n\n\t// timestamp is the shared timestamp in ms between all the Gauges.\n\ttimestamp int64\n\n\t// ixname is the slice's index\n\t// of the __name__ Label item.\n\t//\n\t// 16 bytes should be enough for the max length\n\t// an higher value will probably generate\n\t// serious issues in other places.\n\tixname uint16\n}\n\nfunc (tg *trendAsGauges) Append(suffix string, v float64) {\n\tts := &prompb.TimeSeries{\n\t\tLabels:  make([]*prompb.Label, len(tg.labels)),\n\t\tSamples: make([]*prompb.Sample, 1),\n\t}\n\tfor i := 0; i < len(tg.labels); i++ {\n\t\tts.Labels[i] = &prompb.Label{\n\t\t\tName:  tg.labels[i].Name,\n\t\t\tValue: tg.labels[i].Value,\n\t\t}\n\t}\n\tts.Labels[tg.ixname].Value += \"_\" + suffix\n\n\tts.Samples[0] = &prompb.Sample{\n\t\tTimestamp: tg.timestamp,\n\t\tValue:     v,\n\t}\n\ttg.series = append(tg.series, ts)\n}\n\n// CacheNameIndex finds the __name__ label's index\n// if it is different from the most common expected case\n// then it caches the value.\n// The labels slice is expected to be sorted.\nfunc (tg *trendAsGauges) CacheNameIndex() {\n\tif tg.labels[0].Name == namelbl {\n\t\t// ixname is expected to be the first in most of the cases\n\t\t// the default value is already 0\n\t\treturn\n\t}\n\n\t// in the case __name__ is not the first\n\t// then search for its position\n\ti, found := slices.BinarySearchFunc(tg.labels, namelbl, func(lbl *prompb.Label, key string) int {\n\t\treturn cmp.Compare(lbl.Name, key)\n\t})\n\tif found {\n\t\ttg.ixname = uint16(i) //nolint:gosec\n\t}\n}\n\ntype nativeHistogramSink struct {\n\tH prometheus.Histogram\n}\n\nfunc newNativeHistogramSink(m *metrics.Metric) *nativeHistogramSink {\n\treturn &nativeHistogramSink{\n\t\tH: prometheus.NewHistogram(prometheus.HistogramOpts{\n\t\t\tName: m.Name,\n\t\t\t// 1.1 is the starting value suggested by Prometheus'\n\t\t\t// It sounds good considering the general purpose\n\t\t\t// it have to address.\n\t\t\t// In the future, we could consider to add more tuning\n\t\t\t// if it will be required.\n\t\t\tNativeHistogramBucketFactor: 1.1,\n\t\t}),\n\t}\n}\n\nfunc (sink *nativeHistogramSink) Add(s metrics.Sample) {\n\t// The Prometheus' convention is to use seconds\n\t// as time unit.\n\t//\n\t// It isn't a requirement but having the current factor fixed to 1.1 then\n\t// have seconds is beneficial for having a better resolution.\n\t//\n\t// The assumption is that an higher precision is required\n\t// in case of under-second and more relaxed in case of higher values.\n\t// If the Value type is not defined any assumption can be done\n\t// because the Sample's Value could contains any unit.\n\tsink.H.Observe(adaptUnit(s.Metric.Contains, s.Value))\n}\n\n// TODO: create a smaller Sink interface for this Output.\n// Sink with only Add and MapPrompb methods should be enough.\n// One method interfaces could be even better, to be checked.\n\n// P implements metrics.Sink.\nfunc (*nativeHistogramSink) P(_ float64) float64 {\n\tpanic(\"Native Histogram Sink has no support of percentile (P)\")\n}\n\n// Format implements metrics.Sink.\nfunc (*nativeHistogramSink) Format(_ time.Duration) map[string]float64 {\n\tpanic(\"Native Histogram Sink has no support of formatting (Format)\")\n}\n\n// IsEmpty implements metrics.Sink.\nfunc (*nativeHistogramSink) IsEmpty() bool {\n\tpanic(\"Native Histogram Sink has no support of emptiness check (IsEmpty)\")\n}\n\n// Drain implements metrics.Sink.\nfunc (*nativeHistogramSink) Drain() ([]byte, error) {\n\tpanic(\"Native Histogram Sink has no support of draining\")\n}\n\n// Merge implements metrics.Sink.\nfunc (*nativeHistogramSink) Merge(_ []byte) error {\n\tpanic(\"Native Histogram Sink has no support of merging\")\n}\n\n// MapPrompb maps the Trend type to the experimental Native Histogram.\nfunc (sink *nativeHistogramSink) MapPrompb(series metrics.TimeSeries, t time.Time) []*prompb.TimeSeries {\n\tsuffix := baseUnit(series.Metric.Contains)\n\tlabels := MapSeries(series, suffix)\n\ttimestamp := t.UnixMilli()\n\n\treturn []*prompb.TimeSeries{\n\t\t{\n\t\t\tLabels: labels,\n\t\t\tHistograms: []*prompb.Histogram{\n\t\t\t\thistogramToHistogramProto(timestamp, sink.H),\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc histogramToHistogramProto(timestamp int64, h prometheus.Histogram) *prompb.Histogram {\n\t// TODO: research more if a better way is possible.\n\tmetric := &dto.Metric{}\n\tif err := h.Write(metric); err != nil {\n\t\tpanic(fmt.Errorf(\"failed to convert Native Histogram to the related Protobuf: %w\", err))\n\t}\n\thmetric := metric.Histogram\n\n\treturn &prompb.Histogram{\n\t\tCount:          &prompb.Histogram_CountInt{CountInt: *hmetric.SampleCount},\n\t\tSum:            *hmetric.SampleSum,\n\t\tSchema:         *hmetric.Schema,\n\t\tZeroThreshold:  *hmetric.ZeroThreshold,\n\t\tZeroCount:      &prompb.Histogram_ZeroCountInt{ZeroCountInt: *hmetric.ZeroCount},\n\t\tNegativeSpans:  toBucketSpanProto(hmetric.NegativeSpan),\n\t\tNegativeDeltas: hmetric.NegativeDelta,\n\t\tPositiveSpans:  toBucketSpanProto(hmetric.PositiveSpan),\n\t\tPositiveDeltas: hmetric.PositiveDelta,\n\t\tTimestamp:      timestamp,\n\t}\n}\n\nfunc toBucketSpanProto(s []*dto.BucketSpan) []*prompb.BucketSpan {\n\tspans := make([]*prompb.BucketSpan, len(s))\n\tfor i := range s {\n\t\tspans[i] = &prompb.BucketSpan{Offset: *s[i].Offset, Length: *s[i].Length}\n\t}\n\treturn spans\n}\n\nfunc baseUnit(vt metrics.ValueType) string {\n\tswitch vt {\n\tcase metrics.Time:\n\t\treturn \"seconds\"\n\tcase metrics.Data:\n\t\treturn \"bytes\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\n// adaptUnit converts the generated value into the expected base unit\n// as requested by the Prometheus convention.\n//\n// Time: converted to seconds from milliseconds.\n// Data: k6 emits it in Bytes so it already fine.\n// Other: use the submitted unit.\nfunc adaptUnit(vt metrics.ValueType, v float64) float64 {\n\tif vt == metrics.Time {\n\t\treturn v / 1000\n\t}\n\treturn v\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/remotewrite/trend_test.go",
    "content": "package remotewrite\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\tprompb \"buf.build/gen/go/prometheus/prometheus/protocolbuffers/go\"\n\tdto \"github.com/prometheus/client_model/go\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/protobuf/encoding/protojson\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestExtendedTrendSinkMapPrompb(t *testing.T) {\n\tt.Parallel()\n\n\tnow := time.Now()\n\tr := metrics.NewRegistry()\n\n\tsample := metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: &metrics.Metric{\n\t\t\t\tName: \"test\",\n\t\t\t\tType: metrics.Trend,\n\t\t\t},\n\t\t\tTags: r.RootTagSet(),\n\t\t},\n\t\tValue: 1.0,\n\t\tTime:  now,\n\t}\n\n\texpected := []*prompb.TimeSeries{\n\t\tbuildTimeSeries(\"k6_test_avg\", 1.0, now),\n\t\tbuildTimeSeries(\"k6_test_count\", 1.0, now),\n\t\tbuildTimeSeries(\"k6_test_max\", 1.0, now),\n\t\tbuildTimeSeries(\"k6_test_med\", 1.0, now),\n\t\tbuildTimeSeries(\"k6_test_min\", 1.0, now),\n\t\tbuildTimeSeries(\"k6_test_p095\", 1.0, now),\n\t\tbuildTimeSeries(\"k6_test_p90\", 1.0, now),\n\t\tbuildTimeSeries(\"k6_test_sum\", 1.0, now),\n\t}\n\tresolver, err := metrics.GetResolversForTrendColumns([]string{\"count\", \"min\", \"max\", \"avg\", \"med\", \"p(90)\", \"p(95)\"})\n\trequire.NoError(t, err)\n\tresolver[\"p90\"] = resolver[\"p(90)\"]\n\tdelete(resolver, \"p(90)\")\n\tresolver[\"p095\"] = resolver[\"p(95)\"]\n\tdelete(resolver, \"p(95)\")\n\tresolver[\"sum\"] = func(t *metrics.TrendSink) float64 {\n\t\treturn t.Total()\n\t}\n\n\tst, err := newExtendedTrendSink(resolver)\n\trequire.NoError(t, err)\n\tst.Add(sample)\n\trequire.Equal(t, uint64(1), st.Count())\n\n\tts := st.MapPrompb(sample.TimeSeries, sample.Time)\n\trequire.Len(t, ts, 8)\n\n\tsortByNameLabel(ts)\n\tassertTimeSeriesEqual(t, expected, ts)\n}\n\nfunc TestTrendAsGaugesFindIxName(t *testing.T) {\n\tt.Parallel()\n\n\tcases := []struct {\n\t\t// they have to be sorted\n\t\tlabels   []string\n\t\texpIndex uint16\n\t}{\n\t\t{\n\t\t\tlabels:   []string{\"tag1\", \"tag2\"},\n\t\t\texpIndex: 0,\n\t\t},\n\t\t{\n\t\t\tlabels:   []string{\"2\", \"__name__\"},\n\t\t\texpIndex: 1,\n\t\t},\n\t\t{\n\t\t\tlabels:   []string{\"__name__\", \"tag1\", \"__name__\"},\n\t\t\texpIndex: 0,\n\t\t},\n\t\t{\n\t\t\tlabels:   []string{\"1\", \"__name__\", \"__name__1\"},\n\t\t\texpIndex: 1,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tlbls := make([]*prompb.Label, 0, len(tc.labels))\n\t\tfor _, l := range tc.labels {\n\t\t\tlbls = append(lbls, &prompb.Label{Name: l})\n\t\t}\n\t\ttg := trendAsGauges{labels: lbls}\n\t\ttg.CacheNameIndex()\n\t\tassert.Equal(t, tc.expIndex, tg.ixname)\n\t}\n}\n\nfunc TestNativeHistogramSinkAdd(t *testing.T) {\n\tt.Parallel()\n\n\tts := metrics.TimeSeries{\n\t\tMetric: &metrics.Metric{\n\t\t\tName:     \"k6_test_metric\",\n\t\t\tContains: metrics.Time,\n\t\t},\n\t}\n\tsink := newNativeHistogramSink(ts.Metric)\n\n\t// k6 passes time values with ms time unit\n\t// the sink converts them to seconds.\n\tsink.Add(metrics.Sample{TimeSeries: ts, Value: float64((3 * time.Second).Milliseconds())})\n\tsink.Add(metrics.Sample{TimeSeries: ts, Value: float64((2 * time.Second).Milliseconds())})\n\n\tdmetric := &dto.Metric{}\n\terr := sink.H.Write(dmetric)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, float64(5), *dmetric.Histogram.SampleSum)\n\n\t// the schema is generated from the bucket factor used\n\tassert.Equal(t, int32(3), *dmetric.Histogram.Schema)\n}\n\nfunc TestNativeHistogramSinkMapPrompb(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\tseries := metrics.TimeSeries{\n\t\tMetric: &metrics.Metric{\n\t\t\tName: \"test\",\n\t\t\tType: metrics.Trend,\n\t\t},\n\t\tTags: r.RootTagSet().With(\"tagk1\", \"tagv1\"),\n\t}\n\n\tst := newNativeHistogramSink(series.Metric)\n\tst.Add(metrics.Sample{\n\t\tTimeSeries: series,\n\t\tValue:      1.52,\n\t\tTime:       time.Unix(1, 0),\n\t})\n\tst.Add(metrics.Sample{\n\t\tTimeSeries: series,\n\t\tValue:      3.14,\n\t\tTime:       time.Unix(2, 0),\n\t})\n\tts := st.MapPrompb(series, time.Unix(3, 0))\n\n\t// It should be the easiest way for asserting the entire struct,\n\t// because the structs contains a bunch of internals value that we don't want to assert.\n\trequire.Len(t, ts, 1)\n\tb, err := protojson.Marshal(ts[0])\n\trequire.NoError(t, err)\n\n\texpected := `{\"labels\":[{\"name\":\"__name__\",\"value\":\"k6_test\"},{\"name\":\"tagk1\",\"value\":\"tagv1\"}],\"histograms\":[{\"countInt\":\"2\",\"positiveDeltas\":[\"1\",\"0\"],\"positiveSpans\":[{\"length\":1,\"offset\":5},{\"length\":1,\"offset\":8}],\"schema\":3,\"sum\":4.66,\"timestamp\":\"3000\",\"zeroCountInt\":\"0\",\"zeroThreshold\":2.938735877055719e-39}]}`\n\tassert.JSONEq(t, expected, string(b))\n}\n\nfunc BenchmarkK6TrendSinkAdd(b *testing.B) {\n\tm := &metrics.Metric{\n\t\tType: metrics.Trend,\n\t\tSink: metrics.NewTrendSink(),\n\t}\n\ts := metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: m,\n\t\t},\n\t\tValue: rand.Float64(),\n\t\tTime:  time.Now(),\n\t}\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tm.Sink.Add(s)\n\t}\n}\n\nfunc TestNativeHistogramSinkMapPrompbWithValueType(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\tseries := metrics.TimeSeries{\n\t\tMetric: &metrics.Metric{\n\t\t\tName:     \"test\",\n\t\t\tType:     metrics.Trend,\n\t\t\tContains: metrics.Time,\n\t\t},\n\t\tTags: r.RootTagSet(),\n\t}\n\n\tst := newNativeHistogramSink(series.Metric)\n\tst.Add(metrics.Sample{\n\t\tTimeSeries: series,\n\t\tValue:      1.52,\n\t\tTime:       time.Unix(1, 0),\n\t})\n\tts := st.MapPrompb(series, time.Unix(2, 0))\n\trequire.Len(t, ts, 1)\n\tassert.Equal(t, \"k6_test_seconds\", ts[0].Labels[0].Value)\n}\n\nfunc TestBaseUnit(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tin  metrics.ValueType\n\t\texp string\n\t}{\n\t\t{in: metrics.Default, exp: \"\"},\n\t\t{in: metrics.Time, exp: \"seconds\"},\n\t\t{in: metrics.Data, exp: \"bytes\"},\n\t}\n\tfor _, tt := range tests {\n\t\tassert.Equal(t, tt.exp, baseUnit(tt.in))\n\t}\n}\n\nfunc BenchmarkHistogramSinkAdd(b *testing.B) {\n\tm := &metrics.Metric{\n\t\tName:     \"bench\",\n\t\tType:     metrics.Trend,\n\t\tContains: metrics.Time,\n\t}\n\tts := newNativeHistogramSink(m)\n\ts := metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: m,\n\t\t},\n\t\tValue: rand.Float64(),\n\t\tTime:  time.Now(),\n\t}\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tts.Add(s)\n\t}\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/sigv4/const.go",
    "content": "package sigv4\n\nconst (\n\t// Amazon Managed Service for Prometheus\n\tawsServiceName = \"aps\"\n\n\tsigningAlgorithm = \"AWS4-HMAC-SHA256\"\n\n\tauthorizationHeaderKey = \"Authorization\"\n\tamzDateKey             = \"X-Amz-Date\"\n\n\t// emptyStringSHA256 is the hex encoded sha256 value of an empty string\n\temptyStringSHA256 = `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`\n\n\t// timeFormat is the time format to be used in the X-Amz-Date header or query parameter\n\ttimeFormat = \"20060102T150405Z\"\n\n\t// shortTimeFormat is the shorten time format used in the credential scope\n\tshortTimeFormat = \"20060102\"\n\n\t// contentSHAKey is the SHA256 of request body\n\tcontentSHAKey = \"X-Amz-Content-Sha256\"\n)\n"
  },
  {
    "path": "internal/output/prometheusrw/sigv4/sigv4.go",
    "content": "// Package sigv4 is responsible to for aws sigv4 signing of requests\npackage sigv4\n\nimport (\n\t\"bytes\"\n\t\"crypto/hmac\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype signer interface {\n\tsign(req *http.Request) error\n}\n\ntype defaultSigner struct {\n\tconfig *Config\n\n\t// noEscape represents the characters that AWS doesn't escape\n\tnoEscape [256]bool\n\n\tignoredHeaders map[string]struct{}\n}\n\nfunc newDefaultSigner(config *Config) signer {\n\tds := &defaultSigner{\n\t\tconfig:   config,\n\t\tnoEscape: buildAwsNoEscape(),\n\t\tignoredHeaders: map[string]struct{}{\n\t\t\t\"Authorization\":   {},\n\t\t\t\"User-Agent\":      {},\n\t\t\t\"X-Amzn-Trace-Id\": {},\n\t\t\t\"Expect\":          {},\n\t\t},\n\t}\n\n\treturn ds\n}\n\nfunc (d *defaultSigner) sign(req *http.Request) error {\n\tnow := time.Now().UTC()\n\tiSO8601Date := now.Format(timeFormat)\n\n\tcredentialScope := buildCredentialScope(now, d.config.Region)\n\n\tpayloadHash, err := d.getPayloadHash(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq.Header.Set(\"Host\", req.Host)\n\treq.Header.Set(amzDateKey, iSO8601Date)\n\treq.Header.Set(contentSHAKey, payloadHash)\n\n\tsignedHeadersStr, canonicalHeaderStr := buildCanonicalHeaders(req, d.ignoredHeaders)\n\n\tcanonicalQueryString := getCanonicalQueryString(req.URL)\n\tcanonicalReq := buildCanonicalString(\n\t\treq.Method,\n\t\tgetCanonicalURI(req.URL, d.noEscape),\n\t\tcanonicalQueryString,\n\t\tcanonicalHeaderStr,\n\t\tsignedHeadersStr,\n\t\tpayloadHash,\n\t)\n\n\tsignature := sign(\n\t\tderiveKey(d.config.AwsSecretAccessKey, d.config.Region),\n\t\tbuildStringToSign(iSO8601Date, credentialScope, canonicalReq),\n\t)\n\n\tauthorizationHeader := fmt.Sprintf(\n\t\t\"%s Credential=%s/%s, SignedHeaders=%s, Signature=%s\",\n\t\tsigningAlgorithm,\n\t\td.config.AwsAccessKeyID,\n\t\tcredentialScope,\n\t\tsignedHeadersStr,\n\t\tsignature,\n\t)\n\n\treq.URL.RawQuery = canonicalQueryString\n\treq.Header.Set(authorizationHeaderKey, authorizationHeader)\n\treturn nil\n}\n\nfunc (d *defaultSigner) getPayloadHash(req *http.Request) (string, error) {\n\tif req.Body == nil {\n\t\treturn emptyStringSHA256, nil\n\t}\n\n\treqBody, err := io.ReadAll(req.Body)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treqBodyBuffer := bytes.NewReader(reqBody)\n\n\thash := sha256.New()\n\tif _, err := io.Copy(hash, reqBodyBuffer); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpayloadHash := hex.EncodeToString(hash.Sum(nil))\n\n\t// ensuring that we keep the request body intact for next tripper\n\treq.Body = io.NopCloser(bytes.NewReader(reqBody))\n\n\treturn payloadHash, nil\n}\n\nfunc buildCredentialScope(signingTime time.Time, region string) string {\n\treturn fmt.Sprintf(\n\t\t\"%s/%s/%s/aws4_request\",\n\t\tsigningTime.UTC().Format(shortTimeFormat),\n\t\tregion,\n\t\tawsServiceName,\n\t)\n}\n\nfunc buildCanonicalString(method, uri, query, canonicalHeaders, signedHeaders, payloadHash string) string {\n\treturn strings.Join([]string{\n\t\tmethod,\n\t\turi,\n\t\tquery,\n\t\tcanonicalHeaders,\n\t\tsignedHeaders,\n\t\tpayloadHash,\n\t}, \"\\n\")\n}\n\n// buildCanonicalHeaders is mostly ported from https://github.com/aws/aws-sdk-go-v2/aws/signer/v4 buildCanonicalHeaders\nfunc buildCanonicalHeaders(\n\treq *http.Request,\n\tignoredHeaders map[string]struct{},\n) (signedHeaders, canonicalHeadersStr string) {\n\tconst hostHeader, contentLengthHeader = \"host\", \"content-length\"\n\thost, header, length := req.Host, req.Header, req.ContentLength\n\n\tsigned := make(http.Header)\n\theaders := append([]string{}, hostHeader)\n\tsigned[hostHeader] = append(signed[hostHeader], host)\n\n\tif length > 0 {\n\t\theaders = append(headers, contentLengthHeader)\n\t\tsigned[contentLengthHeader] = append(signed[contentLengthHeader], strconv.FormatInt(length, 10))\n\t}\n\n\tfor k, v := range header {\n\t\tif _, ok := ignoredHeaders[k]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.EqualFold(k, contentLengthHeader) {\n\t\t\t// prevent signing already handled content-length header.\n\t\t\tcontinue\n\t\t}\n\n\t\tlowerCaseKey := strings.ToLower(k)\n\t\tif _, ok := signed[lowerCaseKey]; ok {\n\t\t\t// include additional values\n\t\t\tsigned[lowerCaseKey] = append(signed[lowerCaseKey], v...)\n\t\t\tcontinue\n\t\t}\n\n\t\theaders = append(headers, lowerCaseKey)\n\t\tsigned[lowerCaseKey] = v\n\t}\n\n\t// aws requires headers to keys to be sorted\n\tsort.Strings(headers)\n\tsignedHeaders = strings.Join(headers, \";\")\n\n\tvar canonicalHeaders strings.Builder\n\tfor _, h := range headers {\n\t\tif h == hostHeader {\n\t\t\t_, _ = fmt.Fprintf(&canonicalHeaders, \"%s:%s\\n\", hostHeader, stripExcessSpaces(host)) //nolint:gosec\n\t\t\tcontinue\n\t\t}\n\n\t\t_, _ = fmt.Fprintf(&canonicalHeaders, \"%s:\", h)\n\t\tvalues := signed[h]\n\t\tfor j, v := range values {\n\t\t\tcleanedValue := strings.TrimSpace(stripExcessSpaces(v))\n\t\t\tcanonicalHeaders.WriteString(cleanedValue)\n\t\t\tif j < len(values)-1 {\n\t\t\t\tcanonicalHeaders.WriteRune(',')\n\t\t\t}\n\t\t}\n\t\tcanonicalHeaders.WriteRune('\\n')\n\t}\n\tcanonicalHeadersStr = canonicalHeaders.String()\n\treturn signedHeaders, canonicalHeadersStr\n}\n\nfunc getCanonicalURI(u *url.URL, noEscape [256]bool) string {\n\treturn escapePath(getURIPath(u), noEscape)\n}\n\nfunc getCanonicalQueryString(u *url.URL) string {\n\tquery := u.Query()\n\n\t// Sort Each Query Key's Values\n\tfor key := range query {\n\t\tsort.Strings(query[key])\n\t}\n\n\tvar rawQuery strings.Builder\n\trawQuery.WriteString(strings.ReplaceAll(query.Encode(), \"+\", \"%20\"))\n\treturn rawQuery.String()\n}\n\nfunc buildStringToSign(amzDate, credentialScope, canonicalRequestString string) string {\n\thash := sha256.New()\n\thash.Write([]byte(canonicalRequestString))\n\treturn strings.Join([]string{\n\t\tsigningAlgorithm,\n\t\tamzDate,\n\t\tcredentialScope,\n\t\thex.EncodeToString(hash.Sum(nil)),\n\t}, \"\\n\")\n}\n\nfunc deriveKey(secretKey, region string) string {\n\tsigningDate := time.Now().UTC().Format(shortTimeFormat)\n\thmacDate := hmacSHA256([]byte(\"AWS4\"+secretKey), signingDate)\n\thmacRegion := hmacSHA256(hmacDate, region)\n\thmacService := hmacSHA256(hmacRegion, awsServiceName)\n\tsigningKey := hmacSHA256(hmacService, \"aws4_request\")\n\treturn string(signingKey)\n}\n\nfunc hmacSHA256(key []byte, data string) []byte {\n\th := hmac.New(sha256.New, key)\n\th.Write([]byte(data))\n\treturn h.Sum(nil)\n}\n\nfunc sign(signingKey string, strToSign string) string {\n\th := hmac.New(sha256.New, []byte(signingKey))\n\th.Write([]byte(strToSign))\n\tsig := hex.EncodeToString(h.Sum(nil))\n\treturn sig\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/sigv4/sigv4_test.go",
    "content": "package sigv4\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBuildCanonicalHeaders(t *testing.T) {\n\tt.Parallel()\n\n\tserviceName := \"mockAPI\"\n\tregion := \"mock-region\"\n\tendpoint := \"https://\" + serviceName + \".\" + region + \".example.com\"\n\n\tnow := time.Now().UTC()\n\tiSO8601Date := now.Format(timeFormat)\n\n\treq, err := http.NewRequestWithContext(context.Background(), http.MethodPost, endpoint, nil)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create request, %v\", err)\n\t}\n\n\treq.Header.Set(\"Host\", req.Host)\n\treq.Header.Set(amzDateKey, iSO8601Date)\n\treq.Header.Set(\"InnerSpace\", \"   inner      space    \")\n\treq.Header.Set(\"LeadingSpace\", \"    leading-space\")\n\treq.Header.Add(\"MultipleSpace\", \"no-space\")\n\treq.Header.Add(\"MultipleSpace\", \"\\ttab-space\")\n\treq.Header.Add(\"MultipleSpace\", \"trailing-space    \")\n\treq.Header.Set(\"NoSpace\", \"no-space\")\n\treq.Header.Set(\"TabSpace\", \"\\ttab-space\\t\")\n\treq.Header.Set(\"TrailingSpace\", \"trailing-space    \")\n\treq.Header.Set(\"WrappedSpace\", \"   wrapped-space    \")\n\n\twantSignedHeader := \"host;innerspace;leadingspace;multiplespace;nospace;tabspace;trailingspace;wrappedspace;x-amz-date\"\n\twantCanonicalHeader := strings.Join([]string{\n\t\t\"host:mockAPI.mock-region.example.com\",\n\t\t\"innerspace:inner space\",\n\t\t\"leadingspace:leading-space\",\n\t\t\"multiplespace:no-space,tab-space,trailing-space\",\n\t\t\"nospace:no-space\",\n\t\t\"tabspace:tab-space\",\n\t\t\"trailingspace:trailing-space\",\n\t\t\"wrappedspace:wrapped-space\",\n\t\t\"x-amz-date:\" + iSO8601Date,\n\t\t\"\",\n\t}, \"\\n\")\n\n\tgotSignedHeaders, gotCanonicalHeader := buildCanonicalHeaders(req, nil)\n\tassert.Equal(t, wantSignedHeader, gotSignedHeaders)\n\tassert.Equal(t, wantCanonicalHeader, gotCanonicalHeader)\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/sigv4/tripper.go",
    "content": "package sigv4\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"strings\"\n)\n\n// Tripper signs each request with sigv4\ntype Tripper struct {\n\tconfig *Config\n\tsigner signer\n\tnext   http.RoundTripper\n}\n\n// Config holds aws access configurations\ntype Config struct {\n\tRegion             string\n\tAwsAccessKeyID     string\n\tAwsSecretAccessKey string\n}\n\nfunc (c *Config) validate() error {\n\tif c == nil {\n\t\treturn errors.New(\"config should not be nil\")\n\t}\n\thasRegion := len(strings.TrimSpace(c.Region)) != 0\n\thasAccessID := len(strings.TrimSpace(c.AwsAccessKeyID)) != 0\n\thasSecretAccessKey := len(strings.TrimSpace(c.AwsSecretAccessKey)) != 0\n\tif !hasRegion || !hasAccessID || !hasSecretAccessKey {\n\t\treturn errors.New(\"sigV4 config `Region`, `AwsAccessKeyID`, `AwsSecretAccessKey` must all be set\")\n\t}\n\treturn nil\n}\n\n// NewRoundTripper creates a new sigv4 round tripper\nfunc NewRoundTripper(config *Config, next http.RoundTripper) (*Tripper, error) {\n\tif err := config.validate(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif next == nil {\n\t\tnext = http.DefaultTransport\n\t}\n\n\ttripper := &Tripper{\n\t\tconfig: config,\n\t\tnext:   next,\n\t\tsigner: newDefaultSigner(config),\n\t}\n\treturn tripper, nil\n}\n\n// RoundTrip implements the tripper interface for sigv4 signing of requests\nfunc (c *Tripper) RoundTrip(req *http.Request) (*http.Response, error) {\n\tif err := c.signer.sign(req); err != nil {\n\t\treturn nil, err\n\t}\n\treturn c.next.RoundTrip(req)\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/sigv4/tripper_test.go",
    "content": "package sigv4\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTripper_request_includes_required_headers(t *testing.T) {\n\tt.Parallel()\n\n\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t// Check if required headers are present\n\t\tauthorization := r.Header.Get(authorizationHeaderKey)\n\t\tamzDate := r.Header.Get(amzDateKey)\n\t\tcontentSHA256 := r.Header.Get(contentSHAKey)\n\n\t\t// Respond to the request\n\t\tw.WriteHeader(http.StatusOK)\n\n\t\tassert.NotEmptyf(t, authorization, \"%s header should be present\", authorizationHeaderKey)\n\t\tassert.NotEmptyf(t, amzDate, \"%s header should be present\", amzDateKey)\n\t\tassert.NotEmpty(t, contentSHA256, \"%s header should be present\", contentSHAKey)\n\t}))\n\tdefer server.Close()\n\n\tclient := http.Client{}\n\ttripper, err := NewRoundTripper(&Config{\n\t\tRegion:             \"us-east1\",\n\t\tAwsSecretAccessKey: \"xyz\",\n\t\tAwsAccessKeyID:     \"abc\",\n\t}, http.DefaultTransport)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tclient.Transport = tripper\n\n\treq, err := http.NewRequestWithContext(context.Background(), http.MethodPost, server.URL, nil)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tresponse, _ := client.Do(req)\n\t_ = response.Body.Close()\n}\n\nfunc TestConfig_Validation(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tshouldError bool\n\t\targ         *Config\n\t}{\n\t\t{\n\t\t\tshouldError: false,\n\t\t\targ: &Config{\n\t\t\t\tRegion:             \"us-east1\",\n\t\t\t\tAwsAccessKeyID:     \"someAccessKey\",\n\t\t\t\tAwsSecretAccessKey: \"someSecretKey\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tshouldError: true,\n\t\t\targ:         nil,\n\t\t},\n\t\t{\n\t\t\tshouldError: true,\n\t\t\targ: &Config{\n\t\t\t\tRegion: \"us-east1\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tshouldError: true,\n\t\t\targ: &Config{\n\t\t\t\tRegion:         \"us-east1\",\n\t\t\t\tAwsAccessKeyID: \"someAccessKeyId\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tshouldError: true,\n\t\t\targ: &Config{\n\t\t\t\tAwsAccessKeyID:     \"SomeAccessKey\",\n\t\t\t\tAwsSecretAccessKey: \"SomeSecretKey\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tgot := tc.arg.validate()\n\t\tif tc.shouldError {\n\t\t\tassert.Error(t, got)\n\t\t\tcontinue\n\t\t}\n\t\tassert.NoError(t, got)\n\t}\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/sigv4/util_test.go",
    "content": "package sigv4\n\nimport (\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStripExcessSpaces(t *testing.T) {\n\tt.Parallel()\n\n\ttestcases := []struct {\n\t\targ  string\n\t\twant string\n\t}{\n\t\t{\n\t\t\targ:  `AWS4-HMAC-SHA256 Credential=AKIDFAKEIDFAKEID/20160628/us-west-2/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=1234567890abcdef1234567890abcdef1234567890abcdef`,\n\t\t\twant: `AWS4-HMAC-SHA256 Credential=AKIDFAKEIDFAKEID/20160628/us-west-2/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=1234567890abcdef1234567890abcdef1234567890abcdef`,\n\t\t},\n\t\t{\n\t\t\targ:  \"a   b   c   d\",\n\t\t\twant: \"a b c d\",\n\t\t},\n\t\t{\n\t\t\targ:  \"   abc   def   ghi   jk   \",\n\t\t\twant: \"abc def ghi jk\",\n\t\t},\n\t\t{\n\t\t\targ:  \"   123    456    789          101112   \",\n\t\t\twant: \"123 456 789 101112\",\n\t\t},\n\t\t{\n\t\t\targ:  \"12     3       1abc123\",\n\t\t\twant: \"12 3 1abc123\",\n\t\t},\n\t\t{\n\t\t\targ:  \"aaa \\t bb\",\n\t\t\twant: \"aaa bb\",\n\t\t},\n\t}\n\n\tfor _, tc := range testcases {\n\t\tassert.Equal(t, tc.want, stripExcessSpaces(tc.arg))\n\t}\n}\n\nfunc TestGetUriPath(t *testing.T) {\n\tt.Parallel()\n\n\ttestcases := map[string]struct {\n\t\targ  string\n\t\twant string\n\t}{\n\t\t\"schema and port\": {\n\t\t\targ:  \"https://localhost:9000\",\n\t\t\twant: \"/\",\n\t\t},\n\t\t\"schema and no port\": {\n\t\t\targ:  \"https://localhost\",\n\t\t\twant: \"/\",\n\t\t},\n\t\t\"no schema\": {\n\t\t\targ:  \"localhost:9000\",\n\t\t\twant: \"/\",\n\t\t},\n\t\t\"no schema + path\": {\n\t\t\targ:  \"localhost:9000/abc123\",\n\t\t\twant: \"/abc123\",\n\t\t},\n\t\t\"no schema, with separator\": {\n\t\t\targ:  \"//localhost:9000\",\n\t\t\twant: \"/\",\n\t\t},\n\t\t\"no scheme, no port, with separator\": {\n\t\t\targ:  \"//localhost\",\n\t\t\twant: \"/\",\n\t\t},\n\t\t\"no scheme, with separator, with path\": {\n\t\t\targ:  \"//localhost:9000/abc123\",\n\t\t\twant: \"/abc123\",\n\t\t},\n\t\t\"no scheme, no port, with separator, with path\": {\n\t\t\targ:  \"//localhost/abc123\",\n\t\t\twant: \"/abc123\",\n\t\t},\n\t\t\"no schema, query string\": {\n\t\t\targ:  \"localhost:9000/abc123?efg=456\",\n\t\t\twant: \"/abc123\",\n\t\t},\n\t}\n\tfor name, tc := range testcases {\n\t\tu, err := url.Parse(tc.arg)\n\t\tif err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tgot := getURIPath(u)\n\t\tif tc.want != got {\n\t\t\tt.Fatalf(\"test %v failed, want %v got %v \\n\", name, tc.want, got)\n\t\t}\n\t}\n}\n\nfunc TestGetUriPath_invalid_url_noescape(t *testing.T) {\n\tt.Parallel()\n\n\targ := &url.URL{\n\t\tOpaque: \"//example.org/bucket/key-._~,!@#$%^&*()\",\n\t}\n\n\twant := \"/bucket/key-._~,!@#$%^&*()\"\n\tgot := getURIPath(arg)\n\tassert.Equal(t, want, got)\n}\n\nfunc TestEscapePath(t *testing.T) {\n\tt.Parallel()\n\n\ttestcases := []struct {\n\t\targ  string\n\t\twant string\n\t}{\n\t\t{\n\t\t\targ:  \"/\",\n\t\t\twant: \"/\",\n\t\t},\n\t\t{\n\t\t\targ:  \"/abc\",\n\t\t\twant: \"/abc\",\n\t\t},\n\t\t{\n\t\t\targ:  \"/abc129\",\n\t\t\twant: \"/abc129\",\n\t\t},\n\t\t{\n\t\t\targ:  \"/abc-def\",\n\t\t\twant: \"/abc-def\",\n\t\t},\n\t\t{\n\t\t\targ:  \"/abc.xyz~123-456\",\n\t\t\twant: \"/abc.xyz~123-456\",\n\t\t},\n\t\t{\n\t\t\targ:  \"/abc def-ghi\",\n\t\t\twant: \"/abc%20def-ghi\",\n\t\t},\n\t\t{\n\t\t\targ:  \"abc!def ghi\",\n\t\t\twant: \"abc%21def%20ghi\",\n\t\t},\n\t}\n\n\tnoEscape := buildAwsNoEscape()\n\n\tfor _, tc := range testcases {\n\t\tassert.Equal(t, tc.want, escapePath(tc.arg, noEscape))\n\t}\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/sigv4/utils.go",
    "content": "package sigv4\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"strings\"\n)\n\nfunc buildAwsNoEscape() [256]bool {\n\tvar noEscape [256]bool\n\n\tfor i := range len(noEscape) {\n\t\t// AWS expects every character except these to be escaped\n\t\tnoEscape[i] = (i >= 'A' && i <= 'Z') ||\n\t\t\t(i >= 'a' && i <= 'z') ||\n\t\t\t(i >= '0' && i <= '9') ||\n\t\t\ti == '-' ||\n\t\t\ti == '.' ||\n\t\t\ti == '_' ||\n\t\t\ti == '~' ||\n\t\t\ti == '/'\n\t}\n\treturn noEscape\n}\n\n// escapePath escapes part of a URL path in Amazon style.\n// except for the noEscape provided.\n// inspired by github.com/aws/smithy-go/encoding/httpbinding EscapePath method\nfunc escapePath(path string, noEscape [256]bool) string {\n\tvar buf bytes.Buffer\n\tfor i := 0; i < len(path); i++ {\n\t\tc := path[i]\n\t\tif noEscape[c] {\n\t\t\tbuf.WriteByte(c)\n\t\t\tcontinue\n\t\t}\n\t\tfmt.Fprintf(&buf, \"%%%02X\", c)\n\t}\n\treturn buf.String()\n}\n\n// stripExcessSpaces will remove the leading and trailing spaces, and side-by-side spaces are converted\n// into a single space.\nfunc stripExcessSpaces(str string) string {\n\tif !strings.Contains(str, \"  \") && !strings.Contains(str, \"\\t\") {\n\t\treturn str\n\t}\n\n\tbuilder := strings.Builder{}\n\tlastFoundSpace := -1\n\tconst space = ' '\n\tstr = strings.TrimSpace(str)\n\tfor i := 0; i < len(str); i++ {\n\t\tif str[i] == space || str[i] == '\\t' {\n\t\t\tlastFoundSpace = i\n\t\t\tcontinue\n\t\t}\n\n\t\tif lastFoundSpace > 0 && builder.Len() != 0 {\n\t\t\tbuilder.WriteByte(space)\n\t\t}\n\t\tbuilder.WriteByte(str[i])\n\t\tlastFoundSpace = -1\n\t}\n\treturn builder.String()\n}\n\n// getURIPath returns the escaped URI component from the provided URL.\n// Ported from inspired by github.com/aws/aws-sdk-go-v2/aws/signer/internal/v4 GetURIPath\nfunc getURIPath(u *url.URL) string {\n\tvar uriPath string\n\n\topaque := u.Opaque\n\tif len(opaque) == 0 {\n\t\turiPath = u.EscapedPath()\n\t}\n\n\tif len(opaque) == 0 && len(uriPath) == 0 {\n\t\treturn \"/\"\n\t}\n\n\tconst schemeSep, pathSep, queryStart = \"//\", \"/\", \"?\"\n\n\t// Cutout the scheme separator if present.\n\tif strings.Index(opaque, schemeSep) == 0 {\n\t\topaque = opaque[len(schemeSep):]\n\t}\n\n\t// Cut off the query string if present.\n\tif idx := strings.Index(opaque, queryStart); idx >= 0 {\n\t\topaque = opaque[:idx]\n\t}\n\n\t// capture URI path starting with first path separator.\n\tif idx := strings.Index(opaque, pathSep); idx >= 0 {\n\t\turiPath = opaque[idx:]\n\t}\n\n\tif len(uriPath) == 0 {\n\t\turiPath = \"/\"\n\t}\n\n\treturn uriPath\n}\n"
  },
  {
    "path": "internal/output/prometheusrw/stale/stale.go",
    "content": "// Package stale handles the staleness process.\n//\n// TODO: migrate here more logic dedicated to this topic\n// from the remote write package.\npackage stale\n\nimport \"math\"\n\n// Marker is the Prometheus Remote Write special value for marking\n// a time series as stale.\n//\n// Check https://www.robustperception.io/staleness-and-promql and\n// https://prometheus.io/docs/prometheus/latest/querying/basics/#staleness\n// for details about the Prometheus staleness markers.\n//\n// The value is the same used by the Prometheus package.\n// https://pkg.go.dev/github.com/prometheus/prometheus/pkg/value#pkg-constants\n//\n// It isn't imported directly to avoid the direct dependency\n// from the big Prometheus project that would bring more\n// dependencies.\n//\n//nolint:gochecknoglobals\nvar Marker = math.Float64frombits(0x7ff0000000000002)\n"
  },
  {
    "path": "internal/output/summary/data.go",
    "content": "package summary\n\nimport (\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype dataModel struct {\n\tthresholds\n\t*aggregatedGroupData\n\tscenarios map[string]*aggregatedGroupData\n}\n\nfunc newDataModel() dataModel {\n\treturn dataModel{\n\t\tthresholds:          make(map[string]metricThresholds),\n\t\taggregatedGroupData: newAggregatedGroupData(),\n\t\tscenarios:           make(map[string]*aggregatedGroupData),\n\t}\n}\n\nfunc (d *dataModel) groupDataFor(scenario string) *aggregatedGroupData {\n\tif groupData, exists := d.scenarios[scenario]; exists {\n\t\treturn groupData\n\t}\n\td.scenarios[scenario] = newAggregatedGroupData()\n\treturn d.scenarios[scenario]\n}\n\nfunc (d *dataModel) storeThresholdsFor(m *metrics.Metric) {\n\tif len(m.Thresholds.Thresholds) == 0 {\n\t\treturn\n\t}\n\n\tif _, exists := d.thresholds[m.Name]; !exists {\n\t\td.thresholds[m.Name] = metricThresholds{\n\t\t\taggregatedMetric: relayAggregatedMetricFrom(m),\n\t\t\ttt:               m.Thresholds.Thresholds,\n\t\t}\n\t}\n}\n\ntype metricThresholds struct {\n\taggregatedMetric\n\ttt []*metrics.Threshold\n}\n\ntype thresholds map[string]metricThresholds\n\ntype aggregatedGroupData struct {\n\tchecks            *aggregatedChecksData\n\taggregatedMetrics aggregatedMetricData\n\tgroupsData        map[string]*aggregatedGroupData\n\tgroupsOrder       []string\n}\n\nfunc newAggregatedGroupData() *aggregatedGroupData {\n\treturn &aggregatedGroupData{\n\t\tchecks:            newAggregatedChecksData(),\n\t\taggregatedMetrics: make(map[string]aggregatedMetric),\n\t\tgroupsData:        make(map[string]*aggregatedGroupData),\n\t\tgroupsOrder:       make([]string, 0),\n\t}\n}\n\nfunc (a *aggregatedGroupData) groupDataFor(group string) *aggregatedGroupData {\n\tif groupData, exists := a.groupsData[group]; exists {\n\t\treturn groupData\n\t}\n\tnewGroupData := newAggregatedGroupData()\n\ta.groupsData[group] = newGroupData\n\ta.groupsOrder = append(a.groupsOrder, group)\n\treturn a.groupsData[group]\n}\n\n// addSample differs from relayAggregatedMetricFrom in that it updates the internally stored metric sink with the\n// sample, which differs from the original metric sink, while relayAggregatedMetricFrom stores the metric and the\n// metric sink from the sample's metric.\nfunc (a *aggregatedGroupData) addSample(sample metrics.Sample) {\n\ta.aggregatedMetrics.addSample(sample)\n\n\tcheckName, hasCheckTag := sample.Tags.Get(metrics.TagCheck.String())\n\tif hasCheckTag && sample.Metric.Name == metrics.ChecksName {\n\t\tcheck := a.checks.checkFor(checkName)\n\t\tif sample.Value == 0 {\n\t\t\tatomic.AddInt64(&check.Fails, 1)\n\t\t} else {\n\t\t\tatomic.AddInt64(&check.Passes, 1)\n\t\t}\n\t}\n}\n\n// aggregatedMetricData is a container that can either hold a reference to a k6 metric stored in the registry, or\n// hold a pointer to such metric but keeping a separated Sink of values in order to keep an aggregated view of the\n// metric values. The latter is useful for tracking aggregated metric values specific to a group or scenario.\ntype aggregatedMetricData map[string]aggregatedMetric\n\n// relayAggregatedMetricFrom instantiates a new aggregatedMetric by relaying the metric's Sink, so the same Sink\n// instance is shared between the original metric and the aggregatedMetric, to avoid duplicating memory allocations.\nfunc relayAggregatedMetricFrom(m *metrics.Metric) aggregatedMetric {\n\treturn aggregatedMetric{\n\t\tMetricInfo: summaryMetricInfoFrom(m),\n\t\tSink:       m.Sink,\n\t}\n}\n\n// summaryMetricInfoFrom creates a new summary.MetricInfo from a k6 metric.\nfunc summaryMetricInfoFrom(m *metrics.Metric) summary.MetricInfo {\n\treturn summary.MetricInfo{\n\t\tName:     m.Name,\n\t\tType:     m.Type.String(),\n\t\tContains: m.Contains.String(),\n\t}\n}\n\n// addSample stores the value of the sample in a separate internal sink completely detached from the underlying metrics.\n// This allows to keep an aggregated view of the values specific to a group or scenario.\nfunc (a aggregatedMetricData) addSample(sample metrics.Sample) {\n\tif _, exists := a[sample.Metric.Name]; !exists {\n\t\ta[sample.Metric.Name] = newAggregatedMetric(sample.Metric)\n\t}\n\n\ta[sample.Metric.Name].Sink.Add(sample)\n}\n\ntype aggregatedMetric struct {\n\tsummary.MetricInfo\n\tSink metrics.Sink\n}\n\nfunc newAggregatedMetric(m *metrics.Metric) aggregatedMetric {\n\treturn aggregatedMetric{\n\t\tMetricInfo: summaryMetricInfoFrom(m),\n\t\tSink:       metrics.NewSink(m.Type),\n\t}\n}\n\ntype aggregatedChecksData struct {\n\tchecks        map[string]*summary.Check\n\torderedChecks []*summary.Check\n}\n\nfunc newAggregatedChecksData() *aggregatedChecksData {\n\treturn &aggregatedChecksData{\n\t\tchecks:        make(map[string]*summary.Check),\n\t\torderedChecks: make([]*summary.Check, 0),\n\t}\n}\n\nfunc (a *aggregatedChecksData) checkFor(name string) *summary.Check {\n\tcheck, ok := a.checks[name]\n\tif !ok {\n\t\tcheck = &summary.Check{\n\t\t\tName: name,\n\t\t}\n\t\ta.checks[name] = check\n\t\ta.orderedChecks = append(a.orderedChecks, check)\n\t}\n\treturn check\n}\n\n// populateSummaryGroup populates a [summary.Group], which is the common type for holding groups data to be displayed\n// in the summary, with the data hold by [aggregatedGroupData], which is the type used specifically by this output\n// implementation aimed to collect data that will be displayed in the summary.\nfunc populateSummaryGroup(\n\tsummaryMode summary.Mode,\n\tsummaryGroup *summary.Group,\n\tgroupData *aggregatedGroupData,\n\ttestRunDuration time.Duration,\n\tsummaryTrendStats []string,\n) {\n\t// First, we populate the checks metrics, which are treated independently.\n\tpopulateSummaryChecks(summaryGroup, groupData, testRunDuration, summaryTrendStats)\n\n\t// Then, we store the metrics.\n\tstoreMetric := func(\n\t\tdest summary.Metrics,\n\t\tinfo summary.MetricInfo,\n\t\tsink metrics.Sink,\n\t\ttestDuration time.Duration,\n\t\tsummaryTrendStats []string,\n\t) {\n\t\tgetMetricValues := metricValueGetter(summaryTrendStats)\n\t\tsummaryMetric := summary.NewMetricFrom(info, getMetricValues(sink, testDuration))\n\n\t\tswitch {\n\t\tcase isSkippedMetric(summaryMode, info.Name):\n\t\t\t// Do nothing, just skip.\n\t\tcase isHTTPMetric(info.Name):\n\t\t\tdest.HTTP[info.Name] = summaryMetric\n\t\tcase isExecutionMetric(info.Name):\n\t\t\tdest.Execution[info.Name] = summaryMetric\n\t\tcase isNetworkMetric(info.Name):\n\t\t\tdest.Network[info.Name] = summaryMetric\n\t\tcase isBrowserMetric(info.Name):\n\t\t\tdest.Browser[info.Name] = summaryMetric\n\t\tcase isGrpcMetric(info.Name):\n\t\t\tdest.Grpc[info.Name] = summaryMetric\n\t\tcase isWebSocketsMetric(info.Name):\n\t\t\tdest.WebSocket[info.Name] = summaryMetric\n\t\tcase isWebVitalsMetric(info.Name):\n\t\t\tdest.WebVitals[info.Name] = summaryMetric\n\t\tdefault:\n\t\t\tdest.Custom[info.Name] = summaryMetric\n\t\t}\n\t}\n\n\tfor _, metricData := range groupData.aggregatedMetrics {\n\t\tstoreMetric(\n\t\t\tsummaryGroup.Metrics,\n\t\t\tmetricData.MetricInfo,\n\t\t\tmetricData.Sink,\n\t\t\ttestRunDuration,\n\t\t\tsummaryTrendStats,\n\t\t)\n\t}\n\n\t// We also set the groups order, so it's preserved from code.\n\tsummaryGroup.GroupsOrder = groupData.groupsOrder\n\n\t// Finally, we keep moving down the hierarchy and populate the nested groups.\n\tfor groupName, subGroupData := range groupData.groupsData {\n\t\tsummarySubGroup := summary.NewGroup()\n\t\tpopulateSummaryGroup(summaryMode, &summarySubGroup, subGroupData, testRunDuration, summaryTrendStats)\n\t\tsummaryGroup.Groups[groupName] = summarySubGroup\n\t}\n}\n\nfunc summaryThresholds(\n\tthresholds thresholds,\n\ttestRunDuration time.Duration,\n\tsummaryTrendStats []string,\n) summary.Thresholds {\n\tgetMetricValues := metricValueGetter(summaryTrendStats)\n\n\trts := make(map[string]summary.MetricThresholds, len(thresholds))\n\tfor mName, mThresholds := range thresholds {\n\t\tmt, exists := rts[mName]\n\t\tif !exists {\n\t\t\tmt = summary.MetricThresholds{\n\t\t\t\tMetric: summary.NewMetricFrom(\n\t\t\t\t\tmThresholds.MetricInfo,\n\t\t\t\t\tgetMetricValues(mThresholds.Sink, testRunDuration),\n\t\t\t\t),\n\t\t\t\tThresholds: make([]summary.Threshold, 0, len(mThresholds.tt)),\n\t\t\t}\n\t\t}\n\n\t\tfor _, threshold := range mThresholds.tt {\n\t\t\tmt.Thresholds = append(mt.Thresholds, summary.Threshold{\n\t\t\t\tSource: threshold.Source,\n\t\t\t\tOk:     !threshold.LastFailed,\n\t\t\t})\n\n\t\t\t// Additionally, if metric is a trend and the threshold source is a percentile,\n\t\t\t// we may need to add the percentile value to the metric values, in case it\n\t\t\t// isn't one of [summaryTrendStats].\n\t\t\tif trendSink, isTrend := mThresholds.Sink.(*metrics.TrendSink); isTrend {\n\t\t\t\tif agg, percentile, isPercentile := extractPercentileThresholdSource(threshold.Source); isPercentile {\n\t\t\t\t\tmt.Metric.Values[agg] = trendSink.P(percentile / 100)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\trts[mName] = mt\n\t}\n\n\treturn rts\n}\n\nfunc populateSummaryChecks(\n\tsummaryGroup *summary.Group,\n\tgroupData *aggregatedGroupData,\n\ttestRunDuration time.Duration,\n\tsummaryTrendStats []string,\n) {\n\tgetMetricValues := metricValueGetter(summaryTrendStats)\n\n\tchecksMetric, exists := groupData.aggregatedMetrics[metrics.ChecksName]\n\tif !exists {\n\t\treturn\n\t}\n\n\tsummaryGroup.Checks = summary.NewChecks()\n\n\ttotalChecks := float64(checksMetric.Sink.(*metrics.RateSink).Total)   //nolint:forcetypeassert\n\tsuccessChecks := float64(checksMetric.Sink.(*metrics.RateSink).Trues) //nolint:forcetypeassert\n\n\tsummaryGroup.Checks.Metrics.Total.Values[\"count\"] = totalChecks\n\tsummaryGroup.Checks.Metrics.Total.Values[\"rate\"] = calculateRate(totalChecks, testRunDuration)\n\n\tsummaryGroup.Checks.Metrics.Success = summary.NewMetricFrom(\n\t\tsummary.MetricInfo{\n\t\t\tName:     \"checks_succeeded\",\n\t\t\tType:     checksMetric.Type,\n\t\t\tContains: checksMetric.Contains,\n\t\t},\n\t\tgetMetricValues(checksMetric.Sink, testRunDuration),\n\t)\n\n\tsummaryGroup.Checks.Metrics.Fail.Values[\"passes\"] = totalChecks - successChecks\n\tsummaryGroup.Checks.Metrics.Fail.Values[\"fails\"] = successChecks\n\tif totalChecks > 0 {\n\t\tsummaryGroup.Checks.Metrics.Fail.Values[\"rate\"] = (totalChecks - successChecks) / totalChecks\n\t} else {\n\t\tsummaryGroup.Checks.Metrics.Fail.Values[\"rate\"] = 0\n\t}\n\n\tsummaryGroup.Checks.OrderedChecks = groupData.checks.orderedChecks\n}\n\nfunc isHTTPMetric(metricName string) bool {\n\treturn oneOfMetrics(metricName,\n\t\tmetrics.HTTPReqsName,\n\t\tmetrics.HTTPReqFailedName,\n\t\tmetrics.HTTPReqDurationName,\n\t\tmetrics.HTTPReqBlockedName,\n\t\tmetrics.HTTPReqConnectingName,\n\t\tmetrics.HTTPReqTLSHandshakingName,\n\t\tmetrics.HTTPReqSendingName,\n\t\tmetrics.HTTPReqWaitingName,\n\t\tmetrics.HTTPReqReceivingName,\n\t)\n}\n\nfunc isExecutionMetric(metricName string) bool {\n\treturn oneOfMetrics(metricName, metrics.VUsName,\n\t\tmetrics.VUsMaxName,\n\t\tmetrics.IterationsName,\n\t\tmetrics.IterationDurationName,\n\t\tmetrics.DroppedIterationsName,\n\t)\n}\n\nfunc isNetworkMetric(metricName string) bool {\n\treturn oneOfMetrics(metricName, metrics.DataSentName, metrics.DataReceivedName)\n}\n\nfunc isBrowserMetric(metricName string) bool {\n\treturn strings.HasPrefix(metricName, \"browser_\") && !isWebVitalsMetric(metricName)\n}\n\nfunc isWebVitalsMetric(metricName string) bool {\n\treturn strings.HasPrefix(metricName, \"browser_web_vital_\")\n}\n\nfunc isGrpcMetric(metricName string) bool {\n\treturn strings.HasPrefix(metricName, \"grpc_\")\n}\n\nfunc isWebSocketsMetric(metricName string) bool {\n\treturn strings.HasPrefix(metricName, \"ws_\")\n}\n\nfunc isSkippedMetric(summaryMode summary.Mode, metricName string) bool {\n\tswitch summaryMode {\n\tcase summary.ModeCompact:\n\t\treturn oneOfMetrics(metricName,\n\t\t\tmetrics.ChecksName, metrics.GroupDurationName,\n\t\t\tmetrics.HTTPReqBlockedName, metrics.HTTPReqConnectingName, metrics.HTTPReqReceivingName,\n\t\t\tmetrics.HTTPReqSendingName, metrics.HTTPReqTLSHandshakingName, metrics.HTTPReqWaitingName,\n\t\t)\n\tdefault:\n\t\treturn oneOfMetrics(metricName,\n\t\t\tmetrics.ChecksName, metrics.GroupDurationName,\n\t\t)\n\t}\n}\n\nfunc oneOfMetrics(metricName string, values ...string) bool {\n\tfor _, v := range values {\n\t\tif strings.HasPrefix(metricName, v) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc calculateRate(count float64, duration time.Duration) float64 {\n\tif duration == 0 {\n\t\treturn 0\n\t}\n\treturn count / (float64(duration) / float64(time.Second))\n}\n\nfunc metricValueGetter(summaryTrendStats []string) func(metrics.Sink, time.Duration) map[string]float64 {\n\ttrendResolvers, err := metrics.GetResolversForTrendColumns(summaryTrendStats)\n\tif err != nil {\n\t\tpanic(err.Error()) // this should have been validated already\n\t}\n\n\treturn func(sink metrics.Sink, t time.Duration) (result map[string]float64) {\n\t\tswitch sink := sink.(type) {\n\t\tcase *metrics.CounterSink:\n\t\t\tresult = sink.Format(t)\n\t\t\tresult[\"rate\"] = sink.Rate(t)\n\t\tcase *metrics.GaugeSink:\n\t\t\tresult = sink.Format(t)\n\t\t\tresult[\"min\"] = sink.Min\n\t\t\tresult[\"max\"] = sink.Max\n\t\tcase *metrics.RateSink:\n\t\t\tresult = sink.Format(t)\n\t\t\tresult[\"passes\"] = float64(sink.Trues)\n\t\t\tresult[\"fails\"] = float64(sink.Total - sink.Trues)\n\t\tcase *metrics.TrendSink:\n\t\t\tresult = make(map[string]float64, len(summaryTrendStats))\n\t\t\tfor _, col := range summaryTrendStats {\n\t\t\t\tresult[col] = trendResolvers[col](sink)\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n}\n\nvar percentileThresholdSourceRe = regexp.MustCompile(`^p\\((\\d+(?:\\.\\d+)?)\\)\\s*([<>=])`)\n\n// TODO(@joanlopez): Evaluate whether we should expose the parsed expression from the threshold.\n// For now, and until we formally decide how do we want the `metrics` package to look like, we do \"manually\"\n// parse the threshold expression here in order to extract, if existing, the percentile aggregation.\nfunc extractPercentileThresholdSource(source string) (agg string, percentile float64, isPercentile bool) {\n\t// We capture the following three matches, in order to detect whether source is a percentile:\n\t// 1. The percentile definition: p(...)\n\t// 2. The percentile value: p(??)\n\t// 3. The beginning of the operator: '<', '>', or '='\n\tconst expectedMatches = 3\n\tmatches := percentileThresholdSourceRe.FindStringSubmatch(strings.TrimSpace(source))\n\n\tif len(matches) == expectedMatches {\n\t\tvar err error\n\t\tpercentile, err = strconv.ParseFloat(matches[1], 64)\n\t\tif err != nil {\n\t\t\treturn \"\", 0, false\n\t\t}\n\n\t\tagg = \"p(\" + matches[1] + \")\"\n\t\tisPercentile = true\n\t\treturn agg, percentile, isPercentile\n\t}\n\n\treturn \"\", 0, false\n}\n"
  },
  {
    "path": "internal/output/summary/data_test.go",
    "content": "package summary\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc Test_extractPercentileThresholdSource(t *testing.T) {\n\tt.Parallel()\n\n\ttests := map[string]struct {\n\t\tsource          string\n\t\texpAgg          string\n\t\texpPercentile   float64\n\t\texpIsPercentile bool\n\t}{\n\t\t\"empty source\": {\n\t\t\tsource: \"\", expAgg: \"\", expPercentile: 0, expIsPercentile: false,\n\t\t},\n\t\t\"invalid source\": {\n\t\t\tsource: \"rate<<<<0.01\", expAgg: \"\", expPercentile: 0, expIsPercentile: false,\n\t\t},\n\t\t\"rate threshold\": {\n\t\t\tsource: \"rate<0.01\", expAgg: \"\", expPercentile: 0, expIsPercentile: false,\n\t\t},\n\t\t\"integer percentile\": {\n\t\t\tsource: \"p(95)<200\", expAgg: \"p(95)\", expPercentile: 95, expIsPercentile: true,\n\t\t},\n\t\t\"floating-point percentile\": {\n\t\t\tsource: \"p(99.9)<=200\", expAgg: \"p(99.9)\", expPercentile: 99.9, expIsPercentile: true,\n\t\t},\n\t\t\"percentile with whitespaces\": {\n\t\t\tsource: \"  p(99.9)  <  200  \", expAgg: \"p(99.9)\", expPercentile: 99.9, expIsPercentile: true,\n\t\t},\n\t}\n\tfor name, tc := range tests {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tagg, percentile, isPercentile := extractPercentileThresholdSource(tc.source)\n\t\t\tassert.Equal(t, tc.expAgg, agg)\n\t\t\tassert.Equal(t, tc.expPercentile, percentile)\n\t\t\tassert.Equal(t, tc.expIsPercentile, isPercentile)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/output/summary/doc.go",
    "content": "// Package summary implements an output that collects metrics to be displayed in the end-of-test summary\npackage summary\n"
  },
  {
    "path": "internal/output/summary/summary.go",
    "content": "package summary\n\nimport (\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/lib/consts\"\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\nconst flushPeriod = 200 * time.Millisecond // TODO: make this configurable\n\nvar _ output.Output = &Output{}\n\n// Output implements the lib.Output interface for collecting metrics' data to be displayed in the end-of-test summary.\ntype Output struct {\n\toutput.SampleBuffer\n\n\tperiodicFlusher *output.PeriodicFlusher\n\tlogger          logrus.FieldLogger\n\n\tdataModel   dataModel\n\tsummaryMode summary.Mode\n}\n\n// New returns a new summary output.\nfunc New(params output.Params) (*Output, error) {\n\tsm, err := summary.ValidateMode(params.RuntimeOptions.SummaryMode.String)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &Output{\n\t\tlogger: params.Logger.WithFields(logrus.Fields{\n\t\t\t\"output\": \"summary\",\n\t\t}),\n\t\tdataModel:   newDataModel(),\n\t\tsummaryMode: sm,\n\t}, nil\n}\n\n// OutputName is the name of the output.\nconst OutputName = \"summary\"\n\n// Description returns a human-readable description of the output.\nfunc (o *Output) Description() string {\n\treturn OutputName\n}\n\n// Start starts a new output.PeriodicFlusher to collect and flush metrics that will be\n// rendered in the end-of-test summary.\nfunc (o *Output) Start() error {\n\tpf, err := output.NewPeriodicFlusher(flushPeriod, o.flushMetrics)\n\tif err != nil {\n\t\treturn err\n\t}\n\to.logger.Debug(\"Started!\")\n\to.periodicFlusher = pf\n\treturn nil\n}\n\n// Stop flushes any remaining metrics and stops the goroutine.\nfunc (o *Output) Stop() error {\n\to.periodicFlusher.Stop()\n\treturn nil\n}\n\nfunc (o *Output) flushMetrics() {\n\tsamples := o.GetBufferedSamples()\n\tfor _, sc := range samples {\n\t\tsamples := sc.GetSamples()\n\t\tfor _, sample := range samples {\n\t\t\to.flushSample(sample)\n\t\t}\n\t}\n}\n\nfunc (o *Output) flushSample(sample metrics.Sample) {\n\t// First, the sample data is stored into the metrics stored at the k6 metrics registry level.\n\to.storeSample(sample)\n\n\tskipGroupSamples := o.summaryMode == summary.ModeCompact || o.summaryMode == summary.ModeLegacy\n\tif skipGroupSamples {\n\t\treturn\n\t}\n\n\t// Then, if the extended mode is enabled, the sample data is stored into each group metrics.\n\t// However, we need to determine whether the groups tree is within a scenario or not.\n\tgroupData := o.dataModel.aggregatedGroupData\n\tif scenarioName, hasScenario := sample.Tags.Get(\"scenario\"); hasScenario && scenarioName != \"default\" {\n\t\tgroupData = o.dataModel.groupDataFor(scenarioName)\n\t\tgroupData.addSample(sample)\n\t}\n\n\tif groupTag, exists := sample.Tags.Get(\"group\"); exists && len(groupTag) > 0 {\n\t\tnormalizedGroupName := strings.TrimPrefix(groupTag, lib.GroupSeparator)\n\t\tif normalizedGroupName == consts.SetupFn || normalizedGroupName == consts.TeardownFn {\n\t\t\treturn // Essentially skip samples tagged with group: setup/teardown.\n\t\t}\n\t\tgroupNames := strings.SplitSeq(normalizedGroupName, lib.GroupSeparator)\n\n\t\t// We traverse over all the groups to create a nested structure,\n\t\t// but we only add the sample to the group the sample belongs to,\n\t\t// cause by definition every group is independent.\n\t\tfor groupName := range groupNames {\n\t\t\tgroupData.groupDataFor(groupName)\n\t\t\tgroupData = groupData.groupsData[groupName]\n\t\t}\n\t\tgroupData.addSample(sample)\n\t}\n}\n\n// Summary returns a lib.Summary of the test run.\nfunc (o *Output) Summary(\n\ttestRunDuration time.Duration,\n\tobservedMetrics map[string]*metrics.Metric,\n\toptions lib.Options,\n) *summary.Summary {\n\ts := summary.New()\n\ts.TestRunDuration = testRunDuration\n\n\tsummaryTrendStats := options.SummaryTrendStats\n\n\t// Process the observed metrics. This is necessary to ensure that we have collected\n\t// all metrics, even those that have no samples, so that we can render them in the summary.\n\to.processObservedMetrics(observedMetrics)\n\n\t// Populate the thresholds.\n\ts.Thresholds = summaryThresholds(o.dataModel.thresholds, testRunDuration, summaryTrendStats)\n\n\t// Populate root group and nested groups recursively.\n\tpopulateSummaryGroup(\n\t\to.summaryMode,\n\t\t&s.Group,\n\t\to.dataModel.aggregatedGroupData,\n\t\ttestRunDuration,\n\t\tsummaryTrendStats,\n\t)\n\n\t// Populate scenario groups and nested groups recursively.\n\tfor scenarioName, scenarioData := range o.dataModel.scenarios {\n\t\tscenarioSummaryGroup := summary.NewGroup()\n\t\tpopulateSummaryGroup(\n\t\t\to.summaryMode,\n\t\t\t&scenarioSummaryGroup,\n\t\t\tscenarioData,\n\t\t\ttestRunDuration,\n\t\t\tsummaryTrendStats,\n\t\t)\n\t\ts.Scenarios[scenarioName] = scenarioSummaryGroup\n\t}\n\n\treturn s\n}\n\n// storeSample relays the sample to the k6 metrics registry relevant metric.\n//\n// If it's a check-specific metric, it will also update the check's pass/fail counters.\nfunc (o *Output) storeSample(sample metrics.Sample) {\n\t// If it's the first time we see this metric, we relay the metric from the sample\n\t// and, we store the thresholds for that particular metric, and its sub-metrics.\n\tif _, exists := o.dataModel.aggregatedMetrics[sample.Metric.Name]; !exists {\n\t\to.dataModel.aggregatedMetrics[sample.Metric.Name] = relayAggregatedMetricFrom(sample.Metric)\n\n\t\to.dataModel.storeThresholdsFor(sample.Metric)\n\t\tfor _, sub := range sample.Metric.Submetrics {\n\t\t\to.dataModel.storeThresholdsFor(sub.Metric)\n\t\t}\n\t}\n\n\tcheckName, hasCheckTag := sample.Tags.Get(metrics.TagCheck.String())\n\tif hasCheckTag && sample.Metric.Name == metrics.ChecksName {\n\t\tcheck := o.dataModel.checks.checkFor(checkName)\n\t\tif sample.Value == 0 {\n\t\t\tatomic.AddInt64(&check.Fails, 1)\n\t\t} else {\n\t\t\tatomic.AddInt64(&check.Passes, 1)\n\t\t}\n\t}\n}\n\n// processObservedMetrics is responsible for ensuring that we have collected\n// all metrics, even those that have no samples, so that we can render them in the summary.\nfunc (o *Output) processObservedMetrics(observedMetrics map[string]*metrics.Metric) {\n\tfor _, m := range observedMetrics {\n\t\tif _, exists := o.dataModel.aggregatedMetrics[m.Name]; !exists {\n\t\t\to.dataModel.aggregatedMetrics[m.Name] = relayAggregatedMetricFrom(m)\n\t\t\to.dataModel.storeThresholdsFor(m)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "internal/output/summary/summary_test.go",
    "content": "package summary\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/consts\"\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n)\n\nfunc TestOutput_Summary(t *testing.T) {\n\tt.Parallel()\n\n\to, err := New(output.Params{\n\t\tLogger: testutils.NewLogger(t),\n\t})\n\trequire.NoError(t, err)\n\n\t// Metrics\n\tchecksMetric := &metrics.Metric{\n\t\tName:     \"checks\",\n\t\tType:     metrics.Rate,\n\t\tContains: metrics.Default,\n\t\tSink: &metrics.RateSink{\n\t\t\tTrues: 3,\n\t\t\tTotal: 5,\n\t\t},\n\t\tObserved: true,\n\t}\n\n\thttpReqsMetric := &metrics.Metric{\n\t\tName:     \"http_reqs\",\n\t\tType:     metrics.Counter,\n\t\tContains: metrics.Default,\n\t\tSink: &metrics.CounterSink{\n\t\t\tValue: 4,\n\t\t\tFirst: time.Now(),\n\t\t},\n\t\tObserved: true,\n\t}\n\n\tauthHTTPReqsMetric := &metrics.Metric{\n\t\tName:     \"http_reqs{group: ::auth}\",\n\t\tType:     metrics.Counter,\n\t\tContains: metrics.Default,\n\t\tSink: &metrics.CounterSink{\n\t\t\tValue: 1,\n\t\t\tFirst: time.Now(),\n\t\t},\n\t\tObserved: true,\n\t}\n\n\t// Thresholds\n\tthresholds := thresholds{\n\t\thttpReqsMetric.Name: {\n\t\t\taggregatedMetric: relayAggregatedMetricFrom(httpReqsMetric),\n\t\t\ttt: []*metrics.Threshold{\n\t\t\t\t{\n\t\t\t\t\tSource: \"count<10\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tSource:     \"rate>2\",\n\t\t\t\t\tLastFailed: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tauthHTTPReqsMetric.Name: {\n\t\t\taggregatedMetric: relayAggregatedMetricFrom(authHTTPReqsMetric),\n\t\t\ttt: []*metrics.Threshold{\n\t\t\t\t{\n\t\t\t\t\tSource:     \"count>1\",\n\t\t\t\t\tLastFailed: true,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// Checks\n\tquickPizzaIsUp := &summary.Check{\n\t\tName:   \"quickpizza.grafana.com is up\",\n\t\tPasses: 3,\n\t\tFails:  2,\n\t}\n\n\tchecks := &aggregatedChecksData{\n\t\tchecks:        map[string]*summary.Check{quickPizzaIsUp.Name: quickPizzaIsUp},\n\t\torderedChecks: []*summary.Check{quickPizzaIsUp},\n\t}\n\n\t// Set up\n\to.dataModel = dataModel{\n\t\tthresholds: thresholds,\n\t\taggregatedGroupData: &aggregatedGroupData{\n\t\t\tchecks: checks,\n\t\t\taggregatedMetrics: map[string]aggregatedMetric{\n\t\t\t\tchecksMetric.Name: {\n\t\t\t\t\tMetricInfo: summaryMetricInfoFrom(checksMetric),\n\t\t\t\t\tSink:       checksMetric.Sink,\n\t\t\t\t},\n\t\t\t\thttpReqsMetric.Name: {\n\t\t\t\t\tMetricInfo: summaryMetricInfoFrom(httpReqsMetric),\n\t\t\t\t\tSink:       httpReqsMetric.Sink,\n\t\t\t\t},\n\t\t\t\tauthHTTPReqsMetric.Name: {\n\t\t\t\t\tMetricInfo: summaryMetricInfoFrom(authHTTPReqsMetric),\n\t\t\t\t\tSink:       authHTTPReqsMetric.Sink,\n\t\t\t\t},\n\t\t\t},\n\t\t\tgroupsData: make(map[string]*aggregatedGroupData),\n\t\t},\n\t}\n\n\ttestRunDuration := time.Second\n\tobservedMetrics := map[string]*metrics.Metric{\n\t\thttpReqsMetric.Name:     httpReqsMetric,\n\t\tauthHTTPReqsMetric.Name: authHTTPReqsMetric,\n\t}\n\toptions := lib.Options{\n\t\tSummaryTrendStats: []string{\"avg\", \"min\", \"max\"},\n\t}\n\n\ts := o.Summary(testRunDuration, observedMetrics, options)\n\n\t// Assert thresholds\n\tassert.Len(t, s.Thresholds, 2)\n\n\thttpReqsThresholds := s.Thresholds[httpReqsMetric.Name].Thresholds\n\tassert.Len(t, httpReqsThresholds, 2)\n\tassert.Equal(t, \"count<10\", httpReqsThresholds[0].Source)\n\tassert.True(t, httpReqsThresholds[0].Ok)\n\tassert.Equal(t, \"rate>2\", httpReqsThresholds[1].Source)\n\tassert.False(t, httpReqsThresholds[1].Ok)\n\n\thttpReqsGroupThresholds := s.Thresholds[authHTTPReqsMetric.Name].Thresholds\n\tassert.Len(t, httpReqsGroupThresholds, 1)\n\tassert.Equal(t, \"count>1\", httpReqsGroupThresholds[0].Source)\n\tassert.False(t, httpReqsGroupThresholds[0].Ok)\n\n\t// Assert checks\n\tchecksTotal := s.Checks.Metrics.Total\n\tassert.Equal(t, \"checks_total\", checksTotal.Name)\n\tassert.Equal(t, map[string]float64{\n\t\t\"count\": 5,\n\t\t\"rate\":  5,\n\t}, checksTotal.Values)\n\n\tchecksSucceeded := s.Checks.Metrics.Success\n\tassert.Equal(t, \"checks_succeeded\", checksSucceeded.Name)\n\tassert.Equal(t, map[string]float64{\n\t\t\"rate\":   0.6,\n\t\t\"passes\": 3,\n\t\t\"fails\":  2,\n\t}, checksSucceeded.Values)\n\n\tchecksFailed := s.Checks.Metrics.Fail\n\tassert.Equal(t, \"checks_failed\", checksFailed.Name)\n\tassert.Equal(t, map[string]float64{\n\t\t\"rate\":   0.4,\n\t\t\"passes\": 2,\n\t\t\"fails\":  3,\n\t}, checksFailed.Values)\n\n\tassert.Len(t, s.Checks.OrderedChecks, 1)\n\tassert.Equal(t, quickPizzaIsUp, s.Checks.OrderedChecks[0])\n\n\t// Assert metrics\n\tassert.Len(t, s.Metrics.HTTP, 2)\n\n\thttpReqsSummaryMetric := s.Metrics.HTTP[httpReqsMetric.Name]\n\tassert.Equal(t, \"http_reqs\", httpReqsSummaryMetric.Name)\n\tassert.Equal(t, \"counter\", httpReqsSummaryMetric.Type)\n\tassert.Equal(t, \"default\", httpReqsSummaryMetric.Contains)\n\tassert.Equal(t, map[string]float64{\n\t\t\"count\": 4,\n\t\t\"rate\":  4,\n\t}, httpReqsSummaryMetric.Values)\n\n\tauthHTTPReqsSummaryMetric := s.Metrics.HTTP[authHTTPReqsMetric.Name]\n\tassert.Equal(t, \"http_reqs{group: ::auth}\", authHTTPReqsSummaryMetric.Name)\n\tassert.Equal(t, \"counter\", authHTTPReqsSummaryMetric.Type)\n\tassert.Equal(t, \"default\", authHTTPReqsSummaryMetric.Contains)\n\tassert.Equal(t, map[string]float64{\n\t\t\"count\": 1,\n\t\t\"rate\":  1,\n\t}, authHTTPReqsSummaryMetric.Values)\n\n\t// Other asserts\n\tassert.Equal(t, testRunDuration, s.TestRunDuration)\n}\n\nfunc TestOutput_AddMetricSamples(t *testing.T) {\n\tt.Parallel()\n\n\treg := metrics.NewRegistry()\n\n\thttpReqsMetric := &metrics.Metric{\n\t\tName:     \"http_reqs\",\n\t\tType:     metrics.Counter,\n\t\tContains: metrics.Default,\n\t\tSink: &metrics.CounterSink{\n\t\t\tValue: 4,\n\t\t\tFirst: time.Now(),\n\t\t},\n\t\tObserved: true,\n\t}\n\n\tauthHTTPReqsMetric := &metrics.Metric{\n\t\tName:     \"http_reqs{group: ::auth}\",\n\t\tType:     metrics.Counter,\n\t\tContains: metrics.Default,\n\t\tSink: &metrics.CounterSink{\n\t\t\tValue: 1,\n\t\t\tFirst: time.Now(),\n\t\t},\n\t\tObserved: true,\n\t}\n\n\tsamples := []metrics.SampleContainer{\n\t\tmetrics.Samples{\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: httpReqsMetric,\n\t\t\t\t\tTags:   reg.RootTagSet().With(\"group\", lib.RootGroupPath),\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: httpReqsMetric,\n\t\t\t\t\tTags:   reg.RootTagSet().With(\"group\", lib.GroupSeparator+consts.SetupFn),\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: httpReqsMetric,\n\t\t\t\t\tTags:   reg.RootTagSet().With(\"group\", lib.GroupSeparator+consts.TeardownFn),\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: authHTTPReqsMetric,\n\t\t\t\t\tTags:   reg.RootTagSet().With(\"group\", lib.GroupSeparator+\"something\"),\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: authHTTPReqsMetric,\n\t\t\t\t\tTags:   reg.RootTagSet().With(\"group\", lib.GroupSeparator+\"auth\"),\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 1,\n\t\t\t},\n\t\t},\n\t\tmetrics.Samples{\n\t\t\t{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: httpReqsMetric,\n\t\t\t\t\tTags:   reg.RootTagSet().With(\"group\", lib.RootGroupPath),\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 3,\n\t\t\t},\n\t\t},\n\t}\n\n\tt.Run(\"compact\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\to, err := New(output.Params{\n\t\t\tRuntimeOptions: lib.RuntimeOptions{\n\t\t\t\tSummaryMode: null.StringFrom(\"compact\"),\n\t\t\t},\n\t\t\tLogger: testutils.NewLogger(t),\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, o.Start())\n\n\t\to.AddMetricSamples(samples)\n\n\t\trequire.NoError(t, o.Stop())\n\n\t\tassert.Len(t, o.dataModel.aggregatedMetrics, 2)\n\n\t\thttpReqsSummaryMetric := o.dataModel.aggregatedMetrics[httpReqsMetric.Name]\n\t\tassert.Equal(t, float64(4), httpReqsSummaryMetric.Sink.(*metrics.CounterSink).Value)\n\n\t\tauthHTTPReqsSummaryMetric := o.dataModel.aggregatedMetrics[authHTTPReqsMetric.Name]\n\t\tassert.Equal(t, float64(1), authHTTPReqsSummaryMetric.Sink.(*metrics.CounterSink).Value)\n\n\t\tassert.Len(t, o.dataModel.groupsData, 0)\n\t})\n\n\tt.Run(\"full\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\to, err := New(output.Params{\n\t\t\tRuntimeOptions: lib.RuntimeOptions{\n\t\t\t\tSummaryMode: null.StringFrom(\"full\"),\n\t\t\t},\n\t\t\tLogger: testutils.NewLogger(t),\n\t\t})\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, o.Start())\n\n\t\to.AddMetricSamples(samples)\n\n\t\trequire.NoError(t, o.Stop())\n\n\t\tassert.Len(t, o.dataModel.aggregatedMetrics, 2)\n\n\t\thttpReqsSummaryMetric := o.dataModel.aggregatedMetrics[httpReqsMetric.Name]\n\t\tassert.Equal(t, float64(4), httpReqsSummaryMetric.Sink.(*metrics.CounterSink).Value)\n\n\t\tauthHTTPReqsSummaryMetric := o.dataModel.aggregatedMetrics[authHTTPReqsMetric.Name]\n\t\tassert.Equal(t, float64(1), authHTTPReqsSummaryMetric.Sink.(*metrics.CounterSink).Value)\n\n\t\tassert.Len(t, o.dataModel.groupsData, 2)\n\t\tassert.Len(t, o.dataModel.groupsData[\"something\"].aggregatedMetrics, 1)\n\t\tassert.Len(t, o.dataModel.groupsData[\"auth\"].aggregatedMetrics, 1)\n\n\t\tauthHTTPReqsSummaryMetric = o.dataModel.groupsData[\"auth\"].aggregatedMetrics[authHTTPReqsMetric.Name]\n\t\tassert.Equal(t, float64(1), authHTTPReqsSummaryMetric.Sink.(*metrics.CounterSink).Value)\n\t\tauthHTTPReqsSummaryMetric = o.dataModel.groupsData[\"something\"].aggregatedMetrics[authHTTPReqsMetric.Name]\n\t\tassert.Equal(t, float64(1), authHTTPReqsSummaryMetric.Sink.(*metrics.CounterSink).Value)\n\n\t\tassert.Equal(t, []string{\"something\", \"auth\"}, o.dataModel.groupsOrder)\n\t})\n}\n"
  },
  {
    "path": "internal/secretsource/file/file.go",
    "content": "// Package file implements secret source that reads the secrets from a file as key=value pairs one per line\npackage file\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/secretsource\"\n)\n\nfunc init() {\n\tsecretsource.RegisterExtension(\"file\", func(params secretsource.Params) (secretsource.Source, error) {\n\t\tfss := &fileSecretSource{}\n\t\terr := fss.parseArg(params.ConfigArgument)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tf, err := params.FS.Open(fss.filename)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tscanner := bufio.NewScanner(f)\n\n\t\tfss.internal = make(map[string]string)\n\t\tfor scanner.Scan() {\n\t\t\tline := scanner.Text()\n\t\t\tk, v, ok := strings.Cut(line, \"=\")\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing %q, needs =\", line)\n\t\t\t}\n\n\t\t\tfss.internal[k] = v\n\t\t}\n\t\treturn fss, nil\n\t})\n}\n\nfunc (fss *fileSecretSource) parseArg(config string) error {\n\tlist := strings.Split(config, \",\")\n\tif len(list) >= 1 {\n\t\tfor _, kv := range list {\n\t\t\tk, v, ok := strings.Cut(kv, \"=\")\n\t\t\tif !ok {\n\t\t\t\tfss.filename = kv\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tswitch k {\n\t\t\tcase \"filename\":\n\t\t\t\tfss.filename = v\n\t\t\tdefault:\n\t\t\t\treturn fmt.Errorf(\"unknown configuration key for file secret source %q\", k)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\ntype fileSecretSource struct {\n\tinternal map[string]string\n\tfilename string\n}\n\nfunc (fss *fileSecretSource) Description() string {\n\treturn fmt.Sprintf(\"file source from %s\", fss.filename)\n}\n\nfunc (fss *fileSecretSource) Get(key string) (string, error) {\n\tv, ok := fss.internal[key]\n\tif !ok {\n\t\treturn \"\", errors.New(\"no value\")\n\t}\n\treturn v, nil\n}\n"
  },
  {
    "path": "internal/secretsource/file/file_test.go",
    "content": "package file\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestParseArg(t *testing.T) {\n\tt.Parallel()\n\ttestCases := map[string]struct {\n\t\tinput            string\n\t\texpectedFilename string\n\t\texpectedError    string\n\t}{\n\t\t\"simple\": {\n\t\t\tinput:            \"something.secret\",\n\t\t\texpectedFilename: \"something.secret\",\n\t\t},\n\t\t\"filename\": {\n\t\t\tinput:            \"filename=something.secret\",\n\t\t\texpectedFilename: \"something.secret\",\n\t\t},\n\t\t\"filename and name\": {\n\t\t\tinput:            \"filename=something.secret\",\n\t\t\texpectedFilename: \"something.secret\",\n\t\t},\n\t\t\"unknownfiled\": {\n\t\t\tinput:         \"filename=something.secret,random=bad\",\n\t\t\texpectedError: \"unknown configuration key for file secret source \\\"random\\\"\",\n\t\t},\n\t}\n\n\tfor name, testCase := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfss := &fileSecretSource{}\n\t\t\terr := fss.parseArg(testCase.input)\n\t\t\tif testCase.expectedError != \"\" {\n\t\t\t\trequire.ErrorContains(t, err, testCase.expectedError)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, testCase.expectedFilename, fss.filename)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/secretsource/init.go",
    "content": "// Package secretsource registers all the internal secret sources when imported\npackage secretsource\n\nimport (\n\t_ \"go.k6.io/k6/internal/secretsource/file\" // import them for init\n\t_ \"go.k6.io/k6/internal/secretsource/mock\" // import them for init\n\t_ \"go.k6.io/k6/internal/secretsource/url\"  // import them for init\n)\n"
  },
  {
    "path": "internal/secretsource/mock/mock.go",
    "content": "// Package mock implements a secret source that is just taking secrets on the cli\npackage mock\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/secretsource\"\n)\n\nfunc init() {\n\tsecretsource.RegisterExtension(\"mock\", newMockSecretSourceFromParams)\n}\n\nfunc newMockSecretSourceFromParams(params secretsource.Params) (secretsource.Source, error) {\n\tlist := strings.Split(params.ConfigArgument, \",\")\n\tsecrets := make(map[string]string, len(list))\n\tfor _, kv := range list {\n\t\tk, v, ok := strings.Cut(kv, \"=\")\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"parsing %q, needs =\", kv)\n\t\t}\n\n\t\tsecrets[k] = v\n\t}\n\treturn NewMockSecretSource(secrets), nil\n}\n\n// NewMockSecretSource returns a new secret source mock with the provided name and map of secrets\nfunc NewMockSecretSource(secrets map[string]string) secretsource.Source {\n\treturn &mockSecretSource{\n\t\tinternal: secrets,\n\t}\n}\n\ntype mockSecretSource struct {\n\tinternal map[string]string\n}\n\nfunc (mss *mockSecretSource) Description() string {\n\treturn \"this is a mock secret source\"\n}\n\nfunc (mss *mockSecretSource) Get(key string) (string, error) {\n\tv, ok := mss.internal[key]\n\tif !ok {\n\t\treturn \"\", errors.New(\"no value\")\n\t}\n\treturn v, nil\n}\n"
  },
  {
    "path": "internal/secretsource/url/url.go",
    "content": "// Package url implements a secret source that fetches secrets from generic HTTP URLs.\n// This can be used as a built-in secret source or as an xk6 extension.\npackage url\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"math/rand\" // nosemgrep: math-random-used // This is being used for retry jitter\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/tidwall/gjson\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/secretsource\"\n\t\"golang.org/x/time/rate\"\n)\n\nvar (\n\terrMissingURLTemplate = errors.New(\"urlTemplate is required\")\n\terrFailedToGetSecret  = errors.New(\"failed to get secret\")\n)\n\n// extConfig holds the configuration for URL-based secrets.\ntype extConfig struct {\n\t// URLTemplate is a URL template with {key} placeholder\n\t// Example: \"https://api.example.com/secrets/{key}\"\n\tURLTemplate string `json:\"urlTemplate\"`\n\n\t// Headers to include in the request (e.g., Authorization headers)\n\tHeaders map[string]string `json:\"headers\"`\n\n\t// Method is the HTTP method to use (default: GET)\n\tMethod null.String `json:\"method\"`\n\n\t// ResponsePath is a JSON path to extract the secret value from the response\n\t// Use dot notation for nested fields (e.g., \"data.value\")\n\t// If empty, the entire response body is treated as the secret\n\tResponsePath null.String `json:\"responsePath\"`\n\n\t// RequestsPerMinuteLimit sets the maximum requests per minute (default: 300)\n\tRequestsPerMinuteLimit null.Int `json:\"requestsPerMinuteLimit\"`\n\n\t// RequestsBurst allows a burst of requests above the rate limit (default: 10)\n\tRequestsBurst null.Int `json:\"requestsBurst\"`\n\n\t// Timeout for HTTP requests (default: 30s)\n\t// Accepts duration strings like \"30s\", \"1m\", \"500ms\"\n\tTimeout types.NullDuration `json:\"timeout\"`\n\n\t// MaxRetries sets the maximum number of retry attempts for failed requests (default: 3)\n\t// Only retries on transient errors (5xx, timeouts, network errors, 429)\n\t// Does not retry on 4xx errors (except 429)\n\tMaxRetries null.Int `json:\"maxRetries\"`\n\n\t// RetryBackoff sets the base backoff duration for retries (default: 1s)\n\t// Uses exponential backoff: wait = (base ^ attempt) + jitter\n\t// Accepts duration strings like \"1s\", \"500ms\", \"2s\"\n\tRetryBackoff types.NullDuration `json:\"retryBackoff\"`\n}\n\n// newConfig creates a new extConfig instance with default values.\nfunc newConfig() extConfig {\n\treturn extConfig{\n\t\tMethod:                 null.StringFrom(http.MethodGet),          // GET method\n\t\tResponsePath:           null.StringFrom(\"\"),                      // Empty response path (use entire response)\n\t\tRequestsPerMinuteLimit: null.IntFrom(300),                        // 300 requests per minute\n\t\tRequestsBurst:          null.IntFrom(10),                         // Allow a burst of 10 requests\n\t\tTimeout:                types.NullDurationFrom(30 * time.Second), // 30 seconds timeout\n\t\tMaxRetries:             null.IntFrom(3),                          // 3 retry attempts\n\t\tRetryBackoff:           types.NullDurationFrom(1 * time.Second),  // 1 second base backoff\n\t}\n}\n\nfunc (c extConfig) Apply(cfg extConfig) extConfig {\n\tresult := c\n\n\tif cfg.URLTemplate != \"\" {\n\t\tresult.URLTemplate = cfg.URLTemplate\n\t}\n\n\tif cfg.Headers != nil {\n\t\tresult.Headers = cfg.Headers\n\t}\n\n\tif cfg.Method.Valid {\n\t\tresult.Method = cfg.Method\n\t}\n\n\tif cfg.ResponsePath.Valid {\n\t\tresult.ResponsePath = cfg.ResponsePath\n\t}\n\n\tif cfg.RequestsPerMinuteLimit.Valid {\n\t\tresult.RequestsPerMinuteLimit = cfg.RequestsPerMinuteLimit\n\t}\n\n\tif cfg.RequestsBurst.Valid {\n\t\tresult.RequestsBurst = cfg.RequestsBurst\n\t}\n\n\tif cfg.Timeout.Valid {\n\t\tresult.Timeout = cfg.Timeout\n\t}\n\n\tif cfg.MaxRetries.Valid {\n\t\tresult.MaxRetries = cfg.MaxRetries\n\t}\n\n\tif cfg.RetryBackoff.Valid {\n\t\tresult.RetryBackoff = cfg.RetryBackoff\n\t}\n\n\treturn result\n}\n\n//nolint:gochecknoinits // This is how k6 secret source registration works.\nfunc init() {\n\tsecretsource.RegisterExtension(\"url\", func(params secretsource.Params) (secretsource.Source, error) {\n\t\tconfig, err := getConfig(params.ConfigArgument, params.FS, params.Environment)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"missing or invalid config: %w\", err)\n\t\t}\n\n\t\treturn &urlSecrets{\n\t\t\tconfig: config,\n\t\t\thttpClient: &http.Client{\n\t\t\t\tTimeout: time.Duration(config.Timeout.Duration),\n\t\t\t},\n\t\t\tlimiter: newLimiter(int(config.RequestsPerMinuteLimit.Int64), int(config.RequestsBurst.Int64)),\n\t\t\tlogger:  params.Logger,\n\t\t}, nil\n\t})\n}\n\ntype urlSecrets struct {\n\tconfig     extConfig\n\thttpClient *http.Client\n\tlimiter    limiter\n\tlogger     logrus.FieldLogger\n}\n\nfunc (us *urlSecrets) Description() string {\n\treturn \"URL-based secret source\"\n}\n\nfunc (us *urlSecrets) Get(key string) (string, error) {\n\tctx := context.Background()\n\n\tif err := us.limiter.Wait(ctx); err != nil {\n\t\treturn \"\", fmt.Errorf(\"rate limiter error: %w\", err)\n\t}\n\n\tvar secret string\n\t// MaxRetries is the number of retries, so total attempts = retries + 1\n\tmaxAttempts := int(us.config.MaxRetries.Int64) + 1\n\tbackoff := time.Duration(us.config.RetryBackoff.Duration)\n\n\terr := retry(ctx, maxAttempts, backoff, us.logger, func() (error, bool) {\n\t\t// Replace {key} placeholder in URL template\n\t\turl := strings.ReplaceAll(us.config.URLTemplate, \"{key}\", key)\n\n\t\treq, err := http.NewRequestWithContext(ctx, us.config.Method.String, url, nil)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to create request: %w\", err), true\n\t\t}\n\n\t\t// Add headers\n\t\tfor k, v := range us.config.Headers {\n\t\t\treq.Header.Set(k, v)\n\t\t}\n\n\t\tresponse, err := us.httpClient.Do(req) //nolint:gosec\n\t\tif err != nil {\n\t\t\t// Network errors are retryable\n\t\t\treturn fmt.Errorf(\"failed to get secret: %w\", err), true\n\t\t}\n\t\tdefer func() { _ = response.Body.Close() }()\n\n\t\tif response.StatusCode != http.StatusOK {\n\t\t\tstatusErr := fmt.Errorf(\"status code %d: %w\", response.StatusCode, errFailedToGetSecret)\n\n\t\t\t// Retry on server errors (5xx) and rate limiting (429)\n\t\t\t// Don't retry on client errors (4xx except 429)\n\t\t\tretryable := response.StatusCode >= 500 || response.StatusCode == http.StatusTooManyRequests\n\t\t\treturn statusErr, retryable\n\t\t}\n\n\t\t// Extract secret value from response\n\t\textractedSecret, err := extractSecretFromResponse(response.Body, us.config.ResponsePath.String)\n\t\tif err != nil {\n\t\t\t// Extraction errors are not retryable (indicates config issue)\n\t\t\treturn fmt.Errorf(\"failed to extract secret: %w\", err), false\n\t\t}\n\n\t\tsecret = extractedSecret\n\t\treturn nil, false\n\t})\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn secret, nil\n}\n\ntype limiter interface {\n\tWait(ctx context.Context) error\n}\n\nfunc newLimiter(requestsPerMinuteLimit, requestsBurst int) *rate.Limiter {\n\t// The calculation below looks wrong because it seems like it's giving\n\t// n min²/req, but the first number is actually time unit/min, so the\n\t// units of the result are time unit/req, which is correct because it's\n\t// the interval of time after which a new token is replenished. In\n\t// other words, the units are time unit/token.\n\ttokenReplenishInterval := time.Minute / time.Duration(requestsPerMinuteLimit)\n\n\treturn rate.NewLimiter(rate.Every(tokenReplenishInterval), requestsBurst)\n}\n\nfunc extractSecretFromResponse(body io.Reader, responsePath string) (string, error) {\n\tconst maxSecretSize = 24 * 1024\n\n\t// Limit reading to prevent memory exhaustion from large responses\n\tlimitedReader := io.LimitReader(body, maxSecretSize+1)\n\tdata, err := io.ReadAll(limitedReader)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to read response body: %w\", err)\n\t}\n\n\tif len(data) > maxSecretSize {\n\t\treturn \"\", fmt.Errorf(\"secret response exceeds maximum size of %d bytes\", maxSecretSize)\n\t}\n\n\tif responsePath == \"\" {\n\t\t// If no path specified, assume response body is the secret\n\t\treturn string(data), nil\n\t}\n\n\tresult := gjson.GetBytes(data, responsePath)\n\n\tif !result.Exists() {\n\t\treturn \"\", fmt.Errorf(\"path %q not found in response\", responsePath)\n\t}\n\n\tif result.Type != gjson.String {\n\t\treturn \"\", fmt.Errorf(\"secret value at path %q is not a string (got %s)\", responsePath, result.Type)\n\t}\n\n\treturn result.String(), nil\n}\n\n// retry retries to execute a provided function until it succeeds or the maximum\n// number of attempts is hit. It waits with exponential backoff between attempts.\n// The backoff calculation is: wait = (base ^ attempt) + random jitter up to 1 second.\n// The do function returns an error and a boolean indicating if the error is retryable.\nfunc retry(\n\tctx context.Context,\n\tattempts int,\n\tbaseBackoff time.Duration,\n\tlogger logrus.FieldLogger,\n\tdo func() (error, bool),\n) error {\n\tr := rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\n\tvar lastErr error\n\tfor i := range attempts {\n\t\tif i > 0 {\n\t\t\t// Calculate exponential backoff: base^attempt + jitter\n\t\t\twait := time.Duration(math.Pow(baseBackoff.Seconds(), float64(i))) * time.Second\n\t\t\tjitter := time.Duration(r.Int63n(1000)) * time.Millisecond\n\t\t\twait += jitter\n\n\t\t\tlogger.WithFields(logrus.Fields{\n\t\t\t\t\"attempt\": i + 1,\n\t\t\t\t\"max\":     attempts,\n\t\t\t\t\"wait\":    wait,\n\t\t\t\t\"error\":   lastErr,\n\t\t\t}).Debug(\"Retrying secret fetch after error\")\n\n\t\t\t// Wait with context cancellation support\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn ctx.Err()\n\t\t\tcase <-time.After(wait):\n\t\t\t}\n\t\t}\n\n\t\terr, retryable := do()\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\tlastErr = err\n\t\tif !retryable {\n\t\t\t// Not a retryable error, fail immediately\n\t\t\tlogger.WithFields(logrus.Fields{\n\t\t\t\t\"attempt\": i + 1,\n\t\t\t\t\"error\":   lastErr,\n\t\t\t}).Debug(\"Non-retryable error encountered, failing immediately\")\n\t\t\treturn lastErr\n\t\t}\n\t}\n\n\tlogger.WithFields(logrus.Fields{\n\t\t\"attempts\": attempts,\n\t\t\"error\":    lastErr,\n\t}).Debug(\"Max retry attempts reached\")\n\n\treturn lastErr\n}\n\nfunc parseInlineConfig(configArg string, fs fsext.Fs) (extConfig, error) {\n\tvar fileCfg extConfig\n\tvar inlineCfg extConfig\n\n\t// Split by comma to parse key=value pairs\n\tparts := strings.SplitSeq(configArg, \",\")\n\tfor part := range parts {\n\t\tkey, value, ok := strings.Cut(part, \"=\")\n\t\tif !ok {\n\t\t\treturn extConfig{}, fmt.Errorf(\"invalid config format %q, expected key=value\", part)\n\t\t}\n\n\t\tif key == \"config\" {\n\t\t\t// Load from file\n\t\t\tvar err error\n\t\t\tfileCfg, err = loadConfigFromFile(value, fs)\n\t\t\tif err != nil {\n\t\t\t\treturn extConfig{}, err\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif err := parseInlineConfigOption(key, value, &inlineCfg); err != nil {\n\t\t\treturn extConfig{}, err\n\t\t}\n\t}\n\n\t// Apply configs in order: file -> inline\n\t// This allows inline config to override file config\n\tconfig := fileCfg.Apply(inlineCfg)\n\n\treturn config, nil\n}\n\nfunc parseInlineConfigOption(key, value string, cfg *extConfig) error {\n\tswitch key {\n\tcase \"urlTemplate\":\n\t\tcfg.URLTemplate = value\n\tcase \"method\":\n\t\tcfg.Method = null.StringFrom(value)\n\tcase \"responsePath\":\n\t\tcfg.ResponsePath = null.StringFrom(value)\n\tcase \"timeout\":\n\t\treturn parseDurationOption(value, &cfg.Timeout, \"timeout\")\n\tcase \"requestsPerMinuteLimit\":\n\t\treturn parseIntOption(value, &cfg.RequestsPerMinuteLimit, \"requestsPerMinuteLimit\")\n\tcase \"requestsBurst\":\n\t\treturn parseIntOption(value, &cfg.RequestsBurst, \"requestsBurst\")\n\tcase \"maxRetries\":\n\t\treturn parseIntOption(value, &cfg.MaxRetries, \"maxRetries\")\n\tcase \"retryBackoff\":\n\t\treturn parseDurationOption(value, &cfg.RetryBackoff, \"retryBackoff\")\n\tdefault:\n\t\treturn parseHeaderOption(key, value, cfg)\n\t}\n\treturn nil\n}\n\nfunc parseIntOption(value string, target *null.Int, optionName string) error {\n\tvar intValue int64\n\t_, err := fmt.Sscanf(value, \"%d\", &intValue)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid %s: %w\", optionName, err)\n\t}\n\t*target = null.IntFrom(intValue)\n\treturn nil\n}\n\nfunc parseDurationOption(value string, target *types.NullDuration, optionName string) error {\n\tduration, err := time.ParseDuration(value)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid %s: %w\", optionName, err)\n\t}\n\t*target = types.NullDurationFrom(duration)\n\treturn nil\n}\n\nfunc parseHeaderOption(key, value string, cfg *extConfig) error {\n\tif !strings.HasPrefix(key, \"headers.\") {\n\t\treturn fmt.Errorf(\"unknown configuration key: %q\", key)\n\t}\n\n\theaderName := strings.TrimPrefix(key, \"headers.\")\n\tif cfg.Headers == nil {\n\t\tcfg.Headers = make(map[string]string)\n\t}\n\tcfg.Headers[headerName] = value\n\treturn nil\n}\n\n// parseEnvConfig reads configuration from environment variables.\n// It looks for variables with the prefix K6_SECRET_SOURCE_URL_.\n// Example environment variables:\n//   - K6_SECRET_SOURCE_URL_URL_TEMPLATE\n//   - K6_SECRET_SOURCE_URL_HEADER_AUTHORIZATION\n//   - K6_SECRET_SOURCE_URL_METHOD\n//   - K6_SECRET_SOURCE_URL_RESPONSE_PATH\n//   - K6_SECRET_SOURCE_URL_TIMEOUT\n//   - K6_SECRET_SOURCE_URL_MAX_RETRIES\n//   - K6_SECRET_SOURCE_URL_RETRY_BACKOFF\n//   - K6_SECRET_SOURCE_URL_REQUESTS_PER_MINUTE_LIMIT\n//   - K6_SECRET_SOURCE_URL_REQUESTS_BURST\n//\n//nolint:gocognit // Function parses multiple env vars, each adding to complexity\nfunc parseEnvConfig(env map[string]string) (extConfig, error) {\n\tvar cfg extConfig\n\n\t// Read URL template (required)\n\tif urlTemplate, ok := env[\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\"]; ok && urlTemplate != \"\" {\n\t\tcfg.URLTemplate = urlTemplate\n\t}\n\n\t// Read method\n\tif method, ok := env[\"K6_SECRET_SOURCE_URL_METHOD\"]; ok && method != \"\" {\n\t\tcfg.Method = null.StringFrom(method)\n\t}\n\n\t// Read response path\n\tif responsePath, ok := env[\"K6_SECRET_SOURCE_URL_RESPONSE_PATH\"]; ok && responsePath != \"\" {\n\t\tcfg.ResponsePath = null.StringFrom(responsePath)\n\t}\n\n\t// Read timeout\n\tif timeoutStr, ok := env[\"K6_SECRET_SOURCE_URL_TIMEOUT\"]; ok && timeoutStr != \"\" {\n\t\tif err := parseDurationOption(timeoutStr, &cfg.Timeout, \"timeout\"); err != nil {\n\t\t\treturn extConfig{}, err\n\t\t}\n\t}\n\n\t// Read max retries\n\tif maxRetriesStr, ok := env[\"K6_SECRET_SOURCE_URL_MAX_RETRIES\"]; ok && maxRetriesStr != \"\" {\n\t\tif err := parseIntOption(maxRetriesStr, &cfg.MaxRetries, \"maxRetries\"); err != nil {\n\t\t\treturn extConfig{}, err\n\t\t}\n\t}\n\n\t// Read retry backoff\n\tif retryBackoffStr, ok := env[\"K6_SECRET_SOURCE_URL_RETRY_BACKOFF\"]; ok && retryBackoffStr != \"\" {\n\t\tif err := parseDurationOption(retryBackoffStr, &cfg.RetryBackoff, \"retryBackoff\"); err != nil {\n\t\t\treturn extConfig{}, err\n\t\t}\n\t}\n\n\t// Read requests per minute limit\n\tif rpmStr, ok := env[\"K6_SECRET_SOURCE_URL_REQUESTS_PER_MINUTE_LIMIT\"]; ok && rpmStr != \"\" {\n\t\tif err := parseIntOption(rpmStr, &cfg.RequestsPerMinuteLimit, \"requestsPerMinuteLimit\"); err != nil {\n\t\t\treturn extConfig{}, err\n\t\t}\n\t}\n\n\t// Read requests burst\n\tif burstStr, ok := env[\"K6_SECRET_SOURCE_URL_REQUESTS_BURST\"]; ok && burstStr != \"\" {\n\t\tif err := parseIntOption(burstStr, &cfg.RequestsBurst, \"requestsBurst\"); err != nil {\n\t\t\treturn extConfig{}, err\n\t\t}\n\t}\n\n\t// Read headers - iterate through all environment variables\n\t// Headers are prefixed with K6_SECRET_SOURCE_URL_HEADER_\n\tfor key, value := range env {\n\t\tif after, ok := strings.CutPrefix(key, \"K6_SECRET_SOURCE_URL_HEADER_\"); ok {\n\t\t\theaderName := after\n\t\t\tif cfg.Headers == nil {\n\t\t\t\tcfg.Headers = make(map[string]string)\n\t\t\t}\n\t\t\tcfg.Headers[headerName] = value\n\t\t}\n\t}\n\n\treturn cfg, nil\n}\n\nfunc loadConfigFromFile(configPath string, fs fsext.Fs) (extConfig, error) {\n\tfile, err := fs.Open(configPath)\n\tif err != nil {\n\t\treturn extConfig{}, fmt.Errorf(\"failed to open config file: %w\", err)\n\t}\n\tdefer func() { _ = file.Close() }()\n\n\tconfigData, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn extConfig{}, fmt.Errorf(\"failed to read config file: %w\", err)\n\t}\n\n\tvar fileCfg extConfig\n\tif err := json.Unmarshal(configData, &fileCfg); err != nil {\n\t\treturn extConfig{}, fmt.Errorf(\"failed to parse JSON config: %w\", err)\n\t}\n\n\treturn fileCfg, nil\n}\n\nfunc validateURLTemplate(urlTemplate string) error {\n\tif urlTemplate == \"\" {\n\t\treturn errMissingURLTemplate\n\t}\n\n\t// Require {key} placeholder to differentiate between secrets\n\tif !strings.Contains(urlTemplate, \"{key}\") {\n\t\treturn errors.New(\"urlTemplate must contain {key} placeholder\")\n\t}\n\n\t// Replace {key} placeholder with a dummy value for validation\n\ttestURL := strings.ReplaceAll(urlTemplate, \"{key}\", \"test\")\n\tparsedURL, err := url.Parse(testURL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"urlTemplate is not a valid URL: %w\", err)\n\t}\n\n\t// Require absolute URL with scheme\n\tif parsedURL.Scheme == \"\" {\n\t\treturn errors.New(\"urlTemplate must be an absolute URL with a scheme (e.g., https://...)\")\n\t}\n\n\treturn nil\n}\n\nfunc getConfig(arg string, fs fsext.Fs, env map[string]string) (extConfig, error) {\n\t// Start with defaults\n\tconfig := newConfig()\n\n\t// Apply environment variables\n\t// Order of precedence (lowest to highest):\n\t// 1. Defaults\n\t// 2. Environment variables\n\t// 3. Config file (if specified)\n\t// 4. Inline CLI flags\n\tenvCfg, err := parseEnvConfig(env)\n\tif err != nil {\n\t\treturn extConfig{}, err\n\t}\n\tconfig = config.Apply(envCfg)\n\n\t// If arg is provided and not empty, parse it (file-based or inline config)\n\tif arg != \"\" {\n\t\texplicitCfg, err := parseInlineConfig(arg, fs)\n\t\tif err != nil {\n\t\t\treturn extConfig{}, err\n\t\t}\n\t\tconfig = config.Apply(explicitCfg)\n\t}\n\n\t// Validate the final config\n\tif err := validateConfig(config); err != nil {\n\t\treturn extConfig{}, err\n\t}\n\n\treturn config, nil\n}\n\nfunc validateConfig(config extConfig) error {\n\t// Validate required fields and value constraints\n\tif err := validateURLTemplate(config.URLTemplate); err != nil {\n\t\treturn err\n\t}\n\n\tif config.Timeout.Duration <= 0 {\n\t\treturn errors.New(\"timeout must be greater than 0\")\n\t}\n\n\tif config.RequestsPerMinuteLimit.Int64 <= 0 {\n\t\treturn errors.New(\"requestsPerMinuteLimit must be greater than 0\")\n\t}\n\n\tif config.RequestsBurst.Int64 <= 0 {\n\t\treturn errors.New(\"requestsBurst must be greater than 0\")\n\t}\n\n\tif config.MaxRetries.Int64 < 0 {\n\t\treturn errors.New(\"maxRetries must be non-negative\")\n\t}\n\n\tif config.RetryBackoff.Duration <= 0 {\n\t\treturn errors.New(\"retryBackoff must be greater than 0\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "internal/secretsource/url/url_test.go",
    "content": "package url\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nconst testConfigFile = \"/config.json\"\n\nfunc TestInlineConfig(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"inline urlTemplate only\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tresult, err := parseInlineConfig(\"urlTemplate=https://api.example.com/secrets/{key}\", fs)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://api.example.com/secrets/{key}\", result.URLTemplate)\n\t\t// parseInlineConfig doesn't apply defaults; only parses explicit config\n\t\t// Defaults are applied at the getConfig level\n\t\tassert.False(t, result.Method.Valid)\n\t\tassert.False(t, result.RequestsPerMinuteLimit.Valid)\n\t})\n\n\tt.Run(\"inline config with multiple options\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := \"urlTemplate=https://api.example.com/{key},method=POST,timeout=60s,maxRetries=5\"\n\t\tresult, err := parseInlineConfig(config, fs)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://api.example.com/{key}\", result.URLTemplate)\n\t\tassert.Equal(t, \"POST\", result.Method.String)\n\t\tassert.Equal(t, 60*time.Second, time.Duration(result.Timeout.Duration))\n\t\tassert.Equal(t, int64(5), result.MaxRetries.Int64)\n\t})\n\n\tt.Run(\"inline config with headers\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := \"urlTemplate=https://api.example.com/{key},headers.Authorization=Bearer token123,headers.X-Custom=value\"\n\t\tresult, err := parseInlineConfig(config, fs)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://api.example.com/{key}\", result.URLTemplate)\n\t\tassert.Equal(t, \"Bearer token123\", result.Headers[\"Authorization\"])\n\t\tassert.Equal(t, \"value\", result.Headers[\"X-Custom\"])\n\t})\n\n\tt.Run(\"mixed file and inline config\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\t// Create a base config file\n\t\tbaseConfig := extConfig{\n\t\t\tURLTemplate: \"https://base.example.com/{key}\",\n\t\t\tMethod:      null.StringFrom(\"GET\"),\n\t\t\tTimeout:     types.NullDurationFrom(30 * time.Second),\n\t\t}\n\t\tconfigData, err := json.Marshal(baseConfig)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\t// Load from file and override with inline config\n\t\tconfig := \"config=\" + testConfigFile + \",timeout=60s,maxRetries=10\"\n\t\tresult, err := parseInlineConfig(config, fs)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://base.example.com/{key}\", result.URLTemplate)\n\t\tassert.Equal(t, 60*time.Second, time.Duration(result.Timeout.Duration))\n\t\tassert.Equal(t, int64(10), result.MaxRetries.Int64)\n\t})\n\n\tt.Run(\"invalid config format\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\t_, err := parseInlineConfig(\"invalid-no-equals\", fs)\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"expected key=value\")\n\t})\n\n\tt.Run(\"unknown config key\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\t_, err := parseInlineConfig(\"urlTemplate=https://api.example.com/{key},unknownKey=value\", fs)\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"unknown configuration key\")\n\t})\n\n\tt.Run(\"invalid timeout format\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\t_, err := parseInlineConfig(\"urlTemplate=https://api.example.com/{key},timeout=invalid\", fs)\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"invalid timeout\")\n\t})\n\n\tt.Run(\"all numeric options\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := \"urlTemplate=https://api.example.com/{key},requestsPerMinuteLimit=100,requestsBurst=20,maxRetries=2\"\n\t\tresult, err := parseInlineConfig(config, fs)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, int64(100), result.RequestsPerMinuteLimit.Int64)\n\t\tassert.Equal(t, int64(20), result.RequestsBurst.Int64)\n\t\tassert.Equal(t, int64(2), result.MaxRetries.Int64)\n\t})\n}\n\nfunc TestExtractSecretFromResponse(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname         string\n\t\tbody         []byte\n\t\tresponsePath string\n\t\texpected     string\n\t\texpectError  bool\n\t\terrorMsg     string\n\t}{\n\t\t{\n\t\t\tname:         \"plain text response\",\n\t\t\tbody:         []byte(\"my-secret-value\"),\n\t\t\tresponsePath: \"\",\n\t\t\texpected:     \"my-secret-value\",\n\t\t\texpectError:  false,\n\t\t},\n\t\t{\n\t\t\tname:         \"simple JSON path\",\n\t\t\tbody:         []byte(`{\"secret\":\"my-secret-value\"}`),\n\t\t\tresponsePath: \"secret\",\n\t\t\texpected:     \"my-secret-value\",\n\t\t\texpectError:  false,\n\t\t},\n\t\t{\n\t\t\tname:         \"nested JSON path\",\n\t\t\tbody:         []byte(`{\"data\":{\"value\":\"my-secret-value\"}}`),\n\t\t\tresponsePath: \"data.value\",\n\t\t\texpected:     \"my-secret-value\",\n\t\t\texpectError:  false,\n\t\t},\n\t\t{\n\t\t\tname:         \"deeply nested JSON path\",\n\t\t\tbody:         []byte(`{\"response\":{\"data\":{\"secret\":{\"value\":\"my-secret-value\"}}}}`),\n\t\t\tresponsePath: \"response.data.secret.value\",\n\t\t\texpected:     \"my-secret-value\",\n\t\t\texpectError:  false,\n\t\t},\n\t\t{\n\t\t\tname:         \"invalid JSON path\",\n\t\t\tbody:         []byte(`{\"secret\":\"my-secret-value\"}`),\n\t\t\tresponsePath: \"nonexistent\",\n\t\t\texpected:     \"\",\n\t\t\texpectError:  true,\n\t\t},\n\t\t{\n\t\t\tname:         \"non-string value\",\n\t\t\tbody:         []byte(`{\"secret\":123}`),\n\t\t\tresponsePath: \"secret\",\n\t\t\texpected:     \"\",\n\t\t\texpectError:  true,\n\t\t},\n\t\t{\n\t\t\tname:         \"invalid JSON\",\n\t\t\tbody:         []byte(`{invalid json`),\n\t\t\tresponsePath: \"secret\",\n\t\t\texpected:     \"\",\n\t\t\texpectError:  true,\n\t\t},\n\t\t{\n\t\t\tname:         \"response exceeds size limit\",\n\t\t\tbody:         bytes.Repeat([]byte(\"x\"), 25*1024), // 25KB\n\t\t\tresponsePath: \"\",\n\t\t\texpected:     \"\",\n\t\t\texpectError:  true,\n\t\t\terrorMsg:     \"exceeds maximum size\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tresult, err := extractSecretFromResponse(bytes.NewReader(tt.body), tt.responsePath)\n\t\t\tif tt.expectError {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tif tt.errorMsg != \"\" {\n\t\t\t\t\tassert.ErrorContains(t, err, tt.errorMsg)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tt.expected, result)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetConfig(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"valid config file\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"https://api.example.com/secrets/{key}\",\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"Bearer token123\",\n\t\t\t},\n\t\t\tMethod:       null.StringFrom(\"GET\"),\n\t\t\tResponsePath: null.StringFrom(\"data.value\"),\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\tresult, err := getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, config.URLTemplate, result.URLTemplate)\n\t\tassert.Equal(t, config.Headers, result.Headers)\n\t\tassert.Equal(t, config.Method.String, result.Method.String)\n\t\tassert.Equal(t, config.ResponsePath.String, result.ResponsePath.String)\n\t\tassert.Equal(t, int64(300), result.RequestsPerMinuteLimit.Int64)\n\t\tassert.Equal(t, int64(10), result.RequestsBurst.Int64)\n\t\tassert.Equal(t, 30*time.Second, time.Duration(result.Timeout.Duration))\n\t})\n\n\tt.Run(\"custom rate limits\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tcustomLimit := 100\n\t\tcustomBurst := 5\n\t\tcustomTimeout := types.NullDurationFrom(60 * time.Second)\n\t\tconfig := extConfig{\n\t\t\tURLTemplate:            \"https://api.example.com/secrets/{key}\",\n\t\t\tRequestsPerMinuteLimit: null.IntFrom(int64(customLimit)),\n\t\t\tRequestsBurst:          null.IntFrom(int64(customBurst)),\n\t\t\tTimeout:                customTimeout,\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\tresult, err := getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, int64(customLimit), result.RequestsPerMinuteLimit.Int64)\n\t\tassert.Equal(t, int64(customBurst), result.RequestsBurst.Int64)\n\t\tassert.Equal(t, customTimeout.Duration, result.Timeout.Duration)\n\t})\n\n\tt.Run(\"missing URL template\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := extConfig{\n\t\t\tHeaders: map[string]string{\n\t\t\t\t\"Authorization\": \"Bearer token123\",\n\t\t\t},\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\tassert.ErrorIs(t, err, errMissingURLTemplate)\n\t})\n\n\tt.Run(\"invalid rate limit\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tinvalidLimit := -1\n\t\tconfig := extConfig{\n\t\t\tURLTemplate:            \"https://api.example.com/secrets/{key}\",\n\t\t\tRequestsPerMinuteLimit: null.IntFrom(int64(invalidLimit)),\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\tassert.ErrorContains(t, err, \"requestsPerMinuteLimit must be greater than 0\")\n\t})\n\n\tt.Run(\"nonexistent config file\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\t\t_, err := getConfig(\"config=/nonexistent/file.json\", fs, nil)\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"failed to open config file\")\n\t})\n\n\tt.Run(\"invalid URL format\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"not a valid url {key}\",\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\tassert.ErrorContains(t, err, \"urlTemplate must be an absolute URL with a scheme\")\n\t})\n\n\tt.Run(\"http scheme is valid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"http://api.example.com/secrets/{key}\",\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\tresult, err := getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"http://api.example.com/secrets/{key}\", result.URLTemplate)\n\t})\n\n\tt.Run(\"https scheme is valid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"https://api.example.com/secrets/{key}\",\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\tresult, err := getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://api.example.com/secrets/{key}\", result.URLTemplate)\n\t})\n\n\tt.Run(\"missing {key} placeholder\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"https://api.example.com/secrets/static-value\",\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\tassert.ErrorContains(t, err, \"must contain {key} placeholder\")\n\t})\n}\n\nfunc TestURLSecrets_Get(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"successful GET request with plain response\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\tassert.Equal(t, \"/secrets/my-key\", req.URL.Path)\n\t\t\tassert.Equal(t, \"GET\", req.Method)\n\t\t\tassert.Equal(t, \"Bearer token123\", req.Header.Get(\"Authorization\"))\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(\"my-secret-value\"))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate: server.URL + \"/secrets/{key}\",\n\t\t\t\tHeaders: map[string]string{\n\t\t\t\t\t\"Authorization\": \"Bearer token123\",\n\t\t\t\t},\n\t\t\t\tMethod:       null.StringFrom(\"GET\"),\n\t\t\t\tResponsePath: null.StringFrom(\"\"),\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"my-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"my-secret-value\", secret)\n\t})\n\n\tt.Run(\"successful GET request with JSON response\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\tassert.Equal(t, \"/api/secrets/api-key\", req.URL.Path)\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(`{\"data\":{\"value\":\"secret-from-json\"}}`))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/api/secrets/{key}\",\n\t\t\t\tMethod:       null.StringFrom(\"GET\"),\n\t\t\t\tResponsePath: null.StringFrom(\"data.value\"),\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"api-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secret-from-json\", secret)\n\t})\n\n\tt.Run(\"HTTP error status code\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t_, err := us.Get(\"nonexistent\")\n\t\tassert.Error(t, err)\n\t\tassert.ErrorIs(t, err, errFailedToGetSecret)\n\t\tassert.Contains(t, err.Error(), \"404\")\n\t})\n\n\tt.Run(\"rate limiter error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{},\n\t\t\tlimiter:    &mockLimiter{shouldError: true},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t_, err := us.Get(\"any-key\")\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"rate limiter error\")\n\t})\n\n\tt.Run(\"multiple keys with URL template\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trequestedKeys := []string{}\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\t// Extract key from path\n\t\t\tkey := strings.TrimPrefix(req.URL.Path, \"/secrets/\")\n\t\t\trequestedKeys = append(requestedKeys, key)\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(\"secret-for-\" + key))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t// Request multiple keys\n\t\tkeys := []string{\"key1\", \"key2\", \"key3\"}\n\t\tfor _, key := range keys {\n\t\t\tsecret, err := us.Get(key)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"secret-for-\"+key, secret)\n\t\t}\n\n\t\tassert.Equal(t, keys, requestedKeys)\n\t})\n}\n\nfunc TestURLSecrets_Get_Retry(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"retry on 500 error then succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tcurrentAttempt := attemptCount\n\t\t\tmu.Unlock()\n\n\t\t\t// Fail first 2 attempts with 500, then succeed\n\t\t\tif currentAttempt <= 2 {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(\"secret-after-retry\"))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"test-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secret-after-retry\", secret)\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.Equal(t, 3, attemptCount, \"should have made 3 attempts (2 failures + 1 success)\")\n\t})\n\n\tt.Run(\"retry on 429 rate limit then succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tcurrentAttempt := attemptCount\n\t\t\tmu.Unlock()\n\n\t\t\t// Return 429 on first attempt, then succeed\n\t\t\tif currentAttempt == 1 {\n\t\t\t\tw.WriteHeader(http.StatusTooManyRequests)\n\t\t\t\t_, _ = w.Write([]byte(`{\"error\":\"rate limit exceeded\"}`))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(\"secret-after-rate-limit\"))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"test-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secret-after-rate-limit\", secret)\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.Equal(t, 2, attemptCount, \"should have made 2 attempts (1 rate limit + 1 success)\")\n\t})\n\n\tt.Run(\"no retry on 401 unauthorized error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tmu.Unlock()\n\n\t\t\tw.WriteHeader(http.StatusUnauthorized)\n\t\t\t_, _ = w.Write([]byte(`{\"error\":\"unauthorized\"}`))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t_, err := us.Get(\"test-key\")\n\t\tassert.Error(t, err)\n\t\tassert.ErrorIs(t, err, errFailedToGetSecret)\n\t\tassert.Contains(t, err.Error(), \"401\")\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.Equal(t, 1, attemptCount, \"should only attempt once for 401 error (no retry)\")\n\t})\n\n\tt.Run(\"no retry on 404 not found error\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tmu.Unlock()\n\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t_, err := us.Get(\"test-key\")\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"404\")\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.Equal(t, 1, attemptCount, \"should only attempt once for 404 error (no retry)\")\n\t})\n\n\tt.Run(\"exhaust all retries with 503 errors\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tmu.Unlock()\n\n\t\t\tw.WriteHeader(http.StatusServiceUnavailable)\n\t\t\t_, _ = w.Write([]byte(\"service unavailable\"))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 2\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t_, err := us.Get(\"test-key\")\n\t\tassert.Error(t, err)\n\t\tassert.ErrorIs(t, err, errFailedToGetSecret)\n\t\tassert.Contains(t, err.Error(), \"503\")\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.Equal(t, 3, attemptCount, \"should have made 3 attempts (maxRetries=2 means 2 retries + 1 initial = 3 total)\")\n\t})\n\n\tt.Run(\"maxRetries=0 means no retries\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tmu.Unlock()\n\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 0\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t_, err := us.Get(\"test-key\")\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"500\")\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.Equal(t, 1, attemptCount, \"should only attempt once when maxRetries=0\")\n\t})\n\n\tt.Run(\"retry with 502 bad gateway then succeed\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tcurrentAttempt := attemptCount\n\t\t\tmu.Unlock()\n\n\t\t\t// Fail first attempt with 502, then succeed\n\t\t\tif currentAttempt == 1 {\n\t\t\t\tw.WriteHeader(http.StatusBadGateway)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(\"secret-after-502\"))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"test-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secret-after-502\", secret)\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.Equal(t, 2, attemptCount, \"should have made 2 attempts (1 failure + 1 success)\")\n\t})\n\n\tt.Run(\"uses default retry config when not specified\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tattemptCount := 0\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tmu.Lock()\n\t\t\tattemptCount++\n\t\t\tcurrentAttempt := attemptCount\n\t\t\tmu.Unlock()\n\n\t\t\t// Fail first 2 attempts, then succeed\n\t\t\tif currentAttempt <= 2 {\n\t\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(\"secret-with-defaults\"))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}\",\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(1 * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"test-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secret-with-defaults\", secret)\n\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\t// Default maxRetries is 3, so should attempt up to 4 times (3 retries + 1 initial)\n\t\tassert.GreaterOrEqual(t, attemptCount, 2, \"should have retried at least once with defaults\")\n\t\tassert.LessOrEqual(t, attemptCount, 4, \"should not exceed default maxRetries\")\n\t})\n}\n\nfunc TestGetConfig_Retry(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"default retry config values\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"https://api.example.com/secrets/{key}\",\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\tresult, err := getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, int64(3), result.MaxRetries.Int64)\n\t\tassert.Equal(t, 1*time.Second, time.Duration(result.RetryBackoff.Duration))\n\t})\n\n\tt.Run(\"custom retry config values\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tcustomRetries := 5\n\t\tcustomBackoff := types.NullDurationFrom(2 * time.Second)\n\t\tconfig := extConfig{\n\t\t\tURLTemplate:  \"https://api.example.com/secrets/{key}\",\n\t\t\tMaxRetries:   null.IntFrom(int64(customRetries)),\n\t\t\tRetryBackoff: customBackoff,\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\tresult, err := getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, int64(customRetries), result.MaxRetries.Int64)\n\t\tassert.Equal(t, customBackoff.Duration, result.RetryBackoff.Duration)\n\t})\n\n\tt.Run(\"invalid maxRetries negative value\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tinvalidRetries := -1\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"https://api.example.com/secrets/{key}\",\n\t\t\tMaxRetries:  null.IntFrom(int64(invalidRetries)),\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\tassert.ErrorContains(t, err, \"maxRetries must be non-negative\")\n\t})\n\n\tt.Run(\"invalid retryBackoff zero value\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tinvalidBackoff := types.NullDurationFrom(0)\n\t\tconfig := extConfig{\n\t\t\tURLTemplate:  \"https://api.example.com/secrets/{key}\",\n\t\t\tRetryBackoff: invalidBackoff,\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\tassert.ErrorContains(t, err, \"retryBackoff must be greater than 0\")\n\t})\n\n\tt.Run(\"maxRetries=0 is valid (disables retries)\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfs := fsext.NewMemMapFs()\n\n\t\tzeroRetries := 0\n\t\tconfig := extConfig{\n\t\t\tURLTemplate: \"https://api.example.com/secrets/{key}\",\n\t\t\tMaxRetries:  null.IntFrom(int64(zeroRetries)),\n\t\t}\n\n\t\tconfigData, err := json.Marshal(config)\n\t\trequire.NoError(t, err)\n\t\terr = fsext.WriteFile(fs, testConfigFile, configData, 0o600)\n\t\trequire.NoError(t, err)\n\n\t\tresult, err := getConfig(\"config=\"+testConfigFile, fs, nil)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, int64(0), result.MaxRetries.Int64)\n\t})\n}\n\nfunc TestURLSecrets_Description(t *testing.T) {\n\tt.Parallel()\n\tus := &urlSecrets{\n\t\tconfig: extConfig{\n\t\t\tURLTemplate: \"https://vault.example.com/api/{key}\",\n\t\t},\n\t}\n\n\tdesc := us.Description()\n\tassert.Contains(t, desc, \"URL-based secret source\")\n}\n\n// TestURLSecrets_JSONResponseIntegration tests that the URL secret source works\n// with various JSON response formats from external secret management systems.\nfunc TestURLSecrets_JSONResponseIntegration(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"JSON API endpoint with nested plaintext field\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Mock secret management API that returns a structured JSON response\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\t// Verify the request format\n\t\t\tassert.Equal(t, \"GET\", req.Method)\n\t\t\tassert.Equal(t, \"Bearer test-token\", req.Header.Get(\"Authorization\"))\n\n\t\t\t// Extract secret ID from path\n\t\t\texpectedPath := \"/secrets/my-secret-id/decrypt\"\n\t\t\tassert.Equal(t, expectedPath, req.URL.Path)\n\n\t\t\t// Return a structured JSON response with metadata and the secret value\n\t\t\tresponse := map[string]any{\n\t\t\t\t\"uuid\":        \"550e8400-e29b-41d4-a716-446655440000\",\n\t\t\t\t\"name\":        \"my-secret\",\n\t\t\t\t\"description\": \"A test secret\",\n\t\t\t\t\"plaintext\":   \"super-secret-value\",\n\t\t\t\t\"org_id\":      12345,\n\t\t\t\t\"stack_id\":    67890,\n\t\t\t\t\"created_at\":  1640000000,\n\t\t\t\t\"created_by\":  \"user@example.com\",\n\t\t\t\t\"modified_at\": 1650000000,\n\t\t\t\t\"labels\": []map[string]string{\n\t\t\t\t\t{\"name\": \"env\", \"value\": \"production\"},\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_ = json.NewEncoder(w).Encode(response)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\t// Configure URL secret source to extract the plaintext field from JSON response\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate: server.URL + \"/secrets/{key}/decrypt\",\n\t\t\t\tHeaders: map[string]string{\n\t\t\t\t\t\"Authorization\": \"Bearer test-token\",\n\t\t\t\t},\n\t\t\t\tMethod:       null.StringFrom(\"GET\"),\n\t\t\t\tResponsePath: null.StringFrom(\"plaintext\"),\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t// Test fetching a secret\n\t\tsecret, err := us.Get(\"my-secret-id\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"super-secret-value\", secret)\n\t})\n\n\tt.Run(\"multiple secret IDs with dynamic path substitution\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Track which secrets were requested\n\t\trequestedSecrets := make(map[string]bool)\n\t\tvar mu sync.Mutex\n\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\t// Extract secret ID from path: /secrets/{id}/decrypt\n\t\t\tpath := req.URL.Path\n\t\t\tsecretID := strings.TrimSuffix(strings.TrimPrefix(path, \"/secrets/\"), \"/decrypt\")\n\n\t\t\tmu.Lock()\n\t\t\trequestedSecrets[secretID] = true\n\t\t\tmu.Unlock()\n\n\t\t\t// Return different secrets based on ID\n\t\t\tvar plaintext string\n\t\t\tswitch secretID {\n\t\t\tcase \"api-key-prod\":\n\t\t\t\tplaintext = \"prod-api-key-value\"\n\t\t\tcase \"db-password\":\n\t\t\t\tplaintext = \"secure-db-password\"\n\t\t\tcase \"jwt-secret\":\n\t\t\t\tplaintext = \"jwt-signing-key\"\n\t\t\tdefault:\n\t\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tresponse := map[string]any{\n\t\t\t\t\"name\":      secretID,\n\t\t\t\t\"plaintext\": plaintext,\n\t\t\t}\n\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_ = json.NewEncoder(w).Encode(response)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate: server.URL + \"/secrets/{key}/decrypt\",\n\t\t\t\tHeaders: map[string]string{\n\t\t\t\t\t\"Authorization\": \"Bearer api-token\",\n\t\t\t\t},\n\t\t\t\tResponsePath: null.StringFrom(\"plaintext\"),\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t// Fetch multiple secrets\n\t\tapiKey, err := us.Get(\"api-key-prod\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"prod-api-key-value\", apiKey)\n\n\t\tdbPassword, err := us.Get(\"db-password\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secure-db-password\", dbPassword)\n\n\t\tjwtSecret, err := us.Get(\"jwt-secret\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"jwt-signing-key\", jwtSecret)\n\n\t\t// Verify all secrets were requested\n\t\tmu.Lock()\n\t\tdefer mu.Unlock()\n\t\tassert.True(t, requestedSecrets[\"api-key-prod\"])\n\t\tassert.True(t, requestedSecrets[\"db-password\"])\n\t\tassert.True(t, requestedSecrets[\"jwt-secret\"])\n\t})\n\n\tt.Run(\"API error responses\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t// Simulate API error (e.g., secret not found)\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\tresponse := map[string]string{\n\t\t\t\t\"code\":    \"not_found\",\n\t\t\t\t\"message\": \"Secret not found\",\n\t\t\t}\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\t_ = json.NewEncoder(w).Encode(response)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}/decrypt\",\n\t\t\t\tResponsePath: null.StringFrom(\"plaintext\"),\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\t_, err := us.Get(\"nonexistent-secret\")\n\t\tassert.Error(t, err)\n\t\tassert.ErrorIs(t, err, errFailedToGetSecret)\n\t\tassert.Contains(t, err.Error(), \"404\")\n\t})\n\n\tt.Run(\"complete URL format with path template\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Test with URL template that includes path segments after the key placeholder\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\t// The URL should be in format: /secrets/{id}/decrypt\n\t\t\tassert.True(t, strings.HasPrefix(req.URL.Path, \"/secrets/\"))\n\t\t\tassert.True(t, strings.HasSuffix(req.URL.Path, \"/decrypt\"))\n\n\t\t\tresponse := map[string]any{\n\t\t\t\t\"plaintext\": \"secret-from-api\",\n\t\t\t}\n\n\t\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_ = json.NewEncoder(w).Encode(response)\n\t\t}))\n\t\tdefer server.Close()\n\n\t\ttimeout := 5\n\t\tmaxRetries := 3\n\t\tretryBackoff := 1\n\t\tus := &urlSecrets{\n\t\t\tconfig: extConfig{\n\t\t\t\t// URL template with key placeholder in the middle of the path\n\t\t\t\tURLTemplate:  server.URL + \"/secrets/{key}/decrypt\",\n\t\t\t\tResponsePath: null.StringFrom(\"plaintext\"),\n\t\t\t\tTimeout:      types.NullDurationFrom(time.Duration(timeout) * time.Second),\n\t\t\t\tMaxRetries:   null.IntFrom(int64(maxRetries)),\n\t\t\t\tRetryBackoff: types.NullDurationFrom(time.Duration(retryBackoff) * time.Second),\n\t\t\t},\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"test-secret-123\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secret-from-api\", secret)\n\t})\n}\n\nfunc TestNewLimiter(t *testing.T) {\n\tt.Parallel()\n\tlimiter := newLimiter(60, 10)\n\trequire.NotNil(t, limiter)\n\n\t// Test that limiter allows burst\n\tctx := context.Background()\n\tfor range 10 {\n\t\terr := limiter.Wait(ctx)\n\t\tassert.NoError(t, err)\n\t}\n\n\t// The 11th request should be delayed (but we won't wait for it in the test)\n\t// Just verify the limiter is functional\n\tassert.NotNil(t, limiter)\n}\n\n// mockLimiter is a mock implementation of the limiter interface for testing\ntype mockLimiter struct {\n\tshouldError bool\n}\n\nfunc (m *mockLimiter) Wait(_ context.Context) error {\n\tif m.shouldError {\n\t\treturn context.Canceled\n\t}\n\treturn nil\n}\n\nfunc TestEnvConfig(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"basic env config with urlTemplate only\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\": \"https://api.example.com/secrets/{key}\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\tresult, err := getConfig(\"\", fs, env)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://api.example.com/secrets/{key}\", result.URLTemplate)\n\t\tassert.Equal(t, \"GET\", result.Method.String)\n\t\tassert.Equal(t, int64(300), result.RequestsPerMinuteLimit.Int64)\n\t})\n\n\tt.Run(\"env config with all options\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\":              \"https://api.example.com/{key}\",\n\t\t\t\"K6_SECRET_SOURCE_URL_METHOD\":                    \"POST\",\n\t\t\t\"K6_SECRET_SOURCE_URL_RESPONSE_PATH\":             \"data.value\",\n\t\t\t\"K6_SECRET_SOURCE_URL_TIMEOUT\":                   \"60s\",\n\t\t\t\"K6_SECRET_SOURCE_URL_MAX_RETRIES\":               \"5\",\n\t\t\t\"K6_SECRET_SOURCE_URL_RETRY_BACKOFF\":             \"2s\",\n\t\t\t\"K6_SECRET_SOURCE_URL_REQUESTS_PER_MINUTE_LIMIT\": \"100\",\n\t\t\t\"K6_SECRET_SOURCE_URL_REQUESTS_BURST\":            \"20\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\tresult, err := getConfig(\"\", fs, env)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://api.example.com/{key}\", result.URLTemplate)\n\t\tassert.Equal(t, \"POST\", result.Method.String)\n\t\tassert.Equal(t, \"data.value\", result.ResponsePath.String)\n\t\tassert.Equal(t, 60*time.Second, time.Duration(result.Timeout.Duration))\n\t\tassert.Equal(t, int64(5), result.MaxRetries.Int64)\n\t\tassert.Equal(t, 2*time.Second, time.Duration(result.RetryBackoff.Duration))\n\t\tassert.Equal(t, int64(100), result.RequestsPerMinuteLimit.Int64)\n\t\tassert.Equal(t, int64(20), result.RequestsBurst.Int64)\n\t})\n\n\tt.Run(\"env config with headers\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\":         \"https://api.example.com/{key}\",\n\t\t\t\"K6_SECRET_SOURCE_URL_HEADER_AUTHORIZATION\": \"Bearer token123\",\n\t\t\t\"K6_SECRET_SOURCE_URL_HEADER_X-Custom\":      \"custom-value\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\tresult, err := getConfig(\"\", fs, env)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"https://api.example.com/{key}\", result.URLTemplate)\n\t\tassert.Equal(t, \"Bearer token123\", result.Headers[\"AUTHORIZATION\"])\n\t\tassert.Equal(t, \"custom-value\", result.Headers[\"X-Custom\"])\n\t})\n\n\tt.Run(\"env config missing urlTemplate\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Don't set K6_SECRET_SOURCE_URL_URL_TEMPLATE\n\t\tenv := map[string]string{}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\t_, err := getConfig(\"\", fs, env)\n\t\tassert.ErrorIs(t, err, errMissingURLTemplate)\n\t})\n\n\tt.Run(\"env config with invalid timeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\": \"https://api.example.com/{key}\",\n\t\t\t\"K6_SECRET_SOURCE_URL_TIMEOUT\":      \"invalid\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\t_, err := getConfig(\"\", fs, env)\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"invalid timeout\")\n\t})\n\n\tt.Run(\"env config with invalid maxRetries\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\": \"https://api.example.com/{key}\",\n\t\t\t\"K6_SECRET_SOURCE_URL_MAX_RETRIES\":  \"not-a-number\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\t_, err := getConfig(\"\", fs, env)\n\t\tassert.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"invalid maxRetries\")\n\t})\n\n\tt.Run(\"env config with negative maxRetries\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\": \"https://api.example.com/{key}\",\n\t\t\t\"K6_SECRET_SOURCE_URL_MAX_RETRIES\":  \"-1\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\t_, err := getConfig(\"\", fs, env)\n\t\tassert.ErrorContains(t, err, \"maxRetries must be non-negative\")\n\t})\n\n\tt.Run(\"env config with invalid URL format\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\": \"not a valid url {key}\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\t_, err := getConfig(\"\", fs, env)\n\t\tassert.ErrorContains(t, err, \"urlTemplate must be an absolute URL with a scheme\")\n\t})\n\n\tt.Run(\"env config missing {key} placeholder\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\": \"https://api.example.com/secrets/static-value\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\t_, err := getConfig(\"\", fs, env)\n\t\tassert.ErrorContains(t, err, \"must contain {key} placeholder\")\n\t})\n}\n\nfunc TestURLSecrets_Get_WithEnvConfig(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"successful request with env config\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\tassert.Equal(t, \"/secrets/my-key\", req.URL.Path)\n\t\t\tassert.Equal(t, \"GET\", req.Method)\n\t\t\tassert.Equal(t, \"Bearer env-token\", req.Header.Get(\"Authorization\"))\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(\"my-secret-value\"))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\":         server.URL + \"/secrets/{key}\",\n\t\t\t\"K6_SECRET_SOURCE_URL_HEADER_AUTHORIZATION\": \"Bearer env-token\",\n\t\t\t\"K6_SECRET_SOURCE_URL_TIMEOUT\":              \"5s\",\n\t\t\t\"K6_SECRET_SOURCE_URL_MAX_RETRIES\":          \"3\",\n\t\t\t\"K6_SECRET_SOURCE_URL_RETRY_BACKOFF\":        \"1s\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\tconfig, err := getConfig(\"\", fs, env)\n\t\trequire.NoError(t, err)\n\n\t\tus := &urlSecrets{\n\t\t\tconfig:     config,\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"my-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"my-secret-value\", secret)\n\t})\n\n\tt.Run(\"successful request with env config and JSON response\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {\n\t\t\tassert.Equal(t, \"/api/secrets/api-key\", req.URL.Path)\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t_, _ = w.Write([]byte(`{\"data\":{\"value\":\"secret-from-json\"}}`))\n\t\t}))\n\t\tdefer server.Close()\n\n\t\t// Set up environment variables\n\t\tenv := map[string]string{\n\t\t\t\"K6_SECRET_SOURCE_URL_URL_TEMPLATE\":  server.URL + \"/api/secrets/{key}\",\n\t\t\t\"K6_SECRET_SOURCE_URL_RESPONSE_PATH\": \"data.value\",\n\t\t\t\"K6_SECRET_SOURCE_URL_TIMEOUT\":       \"5s\",\n\t\t\t\"K6_SECRET_SOURCE_URL_MAX_RETRIES\":   \"3\",\n\t\t\t\"K6_SECRET_SOURCE_URL_RETRY_BACKOFF\": \"1s\",\n\t\t}\n\n\t\tfs := fsext.NewMemMapFs()\n\t\tconfig, err := getConfig(\"\", fs, env)\n\t\trequire.NoError(t, err)\n\n\t\tus := &urlSecrets{\n\t\t\tconfig:     config,\n\t\t\thttpClient: &http.Client{Timeout: 5 * time.Second},\n\t\t\tlimiter:    &mockLimiter{},\n\t\t\tlogger:     testutils.NewLogger(t),\n\t\t}\n\n\t\tsecret, err := us.Get(\"api-key\")\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, \"secret-from-json\", secret)\n\t})\n}\n"
  },
  {
    "path": "internal/ui/banner.go",
    "content": "package ui\n\nimport \"strings\"\n\n// Banner returns the ASCII-art banner with the k6 logo\nfunc Banner() string {\n\tbanner := strings.Join([]string{\n\t\t`         /\\      Grafana   /‾‾/  `,\n\t\t`    /\\  /  \\     |\\  __   /  /   `,\n\t\t`   /  \\/    \\    | |/ /  /   ‾‾\\ `,\n\t\t`  /          \\   |   (  |  (‾)  |`,\n\t\t` / __________ \\  |_|\\_\\  \\_____/ `,\n\t}, \"\\n\")\n\n\treturn banner\n}\n"
  },
  {
    "path": "internal/ui/console/doc.go",
    "content": "// Package console implements the command-line UI for k6.\npackage console\n"
  },
  {
    "path": "internal/ui/console/writer.go",
    "content": "package console\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"sync\"\n)\n\n// Writer syncs writes with a mutex and, if the output is a TTY, clears before\n// newlines.\ntype Writer struct {\n\tRawOutFd int\n\tMutex    *sync.Mutex\n\tWriter   io.Writer\n\tIsTTY    bool\n\n\t// Used for flicker-free persistent objects like the progressbars\n\tPersistentText func()\n}\n\nfunc (w *Writer) Write(p []byte) (n int, err error) {\n\torigLen := len(p)\n\tif w.IsTTY {\n\t\t// Add a TTY code to erase till the end of line with each new line\n\t\t// TODO: check how cross-platform this is...\n\t\tp = bytes.ReplaceAll(p, []byte{'\\n'}, []byte{'\\x1b', '[', '0', 'K', '\\n'})\n\t}\n\n\tw.Mutex.Lock()\n\tn, err = w.Writer.Write(p)\n\tif w.PersistentText != nil {\n\t\tw.PersistentText()\n\t}\n\tw.Mutex.Unlock()\n\n\tif err != nil && n < origLen {\n\t\treturn n, err\n\t}\n\treturn origLen, err\n}\n"
  },
  {
    "path": "internal/ui/doc.go",
    "content": "// Package ui contains some generic UI k6 components.\npackage ui\n"
  },
  {
    "path": "internal/ui/form.go",
    "content": "package ui\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/fatih/color\"\n)\n\n// A Field in a form.\ntype Field interface {\n\tGetKey() string                        // Key for the data map.\n\tGetLabel() string                      // Label to print as the prompt.\n\tGetLabelExtra() string                 // Extra info for the label, eg. defaults.\n\tGetContents(io.Reader) (string, error) // Read the field contents from the supplied reader\n\n\t// Sanitize user input and return the field's native type.\n\tClean(s string) (string, error)\n}\n\n// A Form used to handle user interactions.\ntype Form struct {\n\tBanner string\n\tFields []Field\n}\n\n// Run executes the form against the specified input and output.\nfunc (f Form) Run(r io.Reader, w io.Writer) (map[string]string, error) {\n\tif f.Banner != \"\" {\n\t\tif _, err := fmt.Fprintln(w, color.BlueString(f.Banner)+\"\\n\"); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tdata := make(map[string]string, len(f.Fields))\n\tfor _, field := range f.Fields {\n\t\tfor {\n\t\t\tdisplayLabel := field.GetLabel()\n\t\t\tif extra := field.GetLabelExtra(); extra != \"\" {\n\t\t\t\tdisplayLabel += \" \" + color.New(color.Faint, color.FgCyan).Sprint(\"[\"+extra+\"]\")\n\t\t\t}\n\t\t\tif _, err := fmt.Fprint(w, \"  \"+displayLabel+\": \"); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tcolor.Set(color.FgCyan)\n\t\t\ts, err := field.GetContents(r)\n\n\t\t\tif _, ok := field.(PasswordField); ok {\n\t\t\t\t_, err := fmt.Fprint(w, \"\\n\")\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcolor.Unset()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tv, err := field.Clean(s)\n\t\t\tif err != nil {\n\t\t\t\tif _, printErr := fmt.Fprintln(w, color.RedString(\"- \"+err.Error())); printErr != nil {\n\t\t\t\t\treturn nil, printErr\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdata[field.GetKey()] = v\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "internal/ui/form_fields.go",
    "content": "package ui\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"golang.org/x/term\"\n)\n\n// Verify that the fields implement the interface\nvar (\n\t_ Field = StringField{}\n\t_ Field = PasswordField{}\n)\n\n// StringField is just a simple field for reading cleartext strings\ntype StringField struct {\n\tKey     string\n\tLabel   string\n\tDefault string\n\n\t// Length constraints.\n\tMin, Max int\n}\n\n// GetKey returns the field's key\nfunc (f StringField) GetKey() string {\n\treturn f.Key\n}\n\n// GetLabel returns the field's label\nfunc (f StringField) GetLabel() string {\n\treturn f.Label\n}\n\n// GetLabelExtra returns the field's default value\nfunc (f StringField) GetLabelExtra() string {\n\treturn f.Default\n}\n\n// GetContents simply reads a string in cleartext from the supplied reader\n// It's compllicated and doesn't use t he bufio utils because we can't read ahead\n// of the newline and consume more of the stdin, because we'll mess up the next form field\nfunc (f StringField) GetContents(r io.Reader) (string, error) {\n\tresult := make([]byte, 0, 20)\n\tbuf := make([]byte, 1)\n\tfor {\n\t\tn, err := io.ReadAtLeast(r, buf, 1)\n\t\tif err != nil {\n\t\t\treturn string(result), err\n\t\t}\n\n\t\tif n != 1 {\n\t\t\t// Shouldn't happen, but just in case\n\t\t\treturn string(result), errors.New(\"unexpected input when reading string field\")\n\t\t} else if buf[0] == '\\n' {\n\t\t\treturn string(result), nil\n\t\t}\n\t\tresult = append(result, buf[0])\n\t}\n}\n\n// Clean trims the spaces in the string and checks for min and max length\nfunc (f StringField) Clean(s string) (string, error) {\n\ts = strings.TrimSpace(s)\n\tif f.Min != 0 && len(s) < f.Min {\n\t\treturn \"\", fmt.Errorf(\"invalid input, min length is %d\", f.Min)\n\t}\n\tif f.Max != 0 && len(s) > f.Max {\n\t\treturn \"\", fmt.Errorf(\"invalid input, max length is %d\", f.Max)\n\t}\n\tif s == \"\" {\n\t\ts = f.Default\n\t}\n\treturn s, nil\n}\n\n// PasswordField masks password input\ntype PasswordField struct {\n\tKey   string\n\tLabel string\n\tMin   int\n}\n\n// GetKey returns the field's key\nfunc (f PasswordField) GetKey() string {\n\treturn f.Key\n}\n\n// GetLabel returns the field's label\nfunc (f PasswordField) GetLabel() string {\n\treturn f.Label\n}\n\n// GetLabelExtra doesn't return anything so we don't expose the current password\nfunc (f PasswordField) GetLabelExtra() string {\n\treturn \"\"\n}\n\n// GetContents simply reads a string in cleartext from the supplied reader\nfunc (f PasswordField) GetContents(r io.Reader) (string, error) {\n\tstdin, ok := r.(*os.File) //nolint:forbidigo\n\tif !ok {\n\t\treturn \"\", errors.New(\"cannot read password from the supplied terminal\")\n\t}\n\tpassword, err := term.ReadPassword(int(stdin.Fd())) //nolint:gosec\n\tif err != nil {\n\t\t// Possibly running on Cygwin/mintty which doesn't emulate\n\t\t// pseudo terminals properly, so fallback to plain text input.\n\t\t// Note that passwords will be echoed if this is the case.\n\t\t// See https://github.com/mintty/mintty/issues/56\n\t\t// A workaround is to use winpty or mintty compiled with\n\t\t// Cygwin >=3.1.0 which supports the new ConPTY Windows API.\n\t\tbufR := bufio.NewReader(r)\n\t\tpassword, err = bufR.ReadBytes('\\n')\n\t}\n\treturn string(password), err\n}\n\n// Clean just checks if the minimum length is exceeded, it doesn't trim the string!\nfunc (f PasswordField) Clean(s string) (string, error) {\n\tif f.Min != 0 && len(s) < f.Min {\n\t\treturn \"\", fmt.Errorf(\"invalid input, min length is %d\", f.Min)\n\t}\n\treturn s, nil\n}\n"
  },
  {
    "path": "internal/ui/form_fields_test.go",
    "content": "package ui\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStringField(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Creation\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := StringField{Key: \"key\", Label: \"label\"}\n\t\tassert.Equal(t, \"key\", f.GetKey())\n\t\tassert.Equal(t, \"label\", f.GetLabel())\n\t})\n\n\tt.Run(\"Valid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := StringField{Key: \"key\", Label: \"label\"}\n\t\tv, err := f.Clean(\"uwu\")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"uwu\", v)\n\t})\n\tt.Run(\"Whitespace\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := StringField{Key: \"key\", Label: \"label\"}\n\t\tv, err := f.Clean(\"\\r\\n\\t \")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"\", v)\n\t})\n\tt.Run(\"Min\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := StringField{Key: \"key\", Label: \"label\"}\n\t\tf.Min = 10\n\t\t_, err := f.Clean(\"short\")\n\t\tassert.EqualError(t, err, \"invalid input, min length is 10\")\n\t})\n\tt.Run(\"Max\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := StringField{Key: \"key\", Label: \"label\"}\n\t\tf.Max = 10\n\t\t_, err := f.Clean(\"too dang long\")\n\t\tassert.EqualError(t, err, \"invalid input, max length is 10\")\n\t})\n\tt.Run(\"Default\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := StringField{Key: \"key\", Label: \"label\"}\n\t\tf.Default = \"default\"\n\t\tv, err := f.Clean(\"\")\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, \"default\", v)\n\t})\n}\n"
  },
  {
    "path": "internal/ui/form_test.go",
    "content": "package ui\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestForm(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Blank\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tdata, err := Form{}.Run(strings.NewReader(\"\"), bytes.NewBuffer(nil))\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, map[string]string{}, data)\n\t})\n\tt.Run(\"Banner\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tout := bytes.NewBuffer(nil)\n\t\tdata, err := Form{Banner: \"Hi!\"}.Run(strings.NewReader(\"\"), out)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, map[string]string{}, data)\n\t\tassert.Equal(t, \"Hi!\\n\\n\", out.String())\n\t})\n\tt.Run(\"Field\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := Form{\n\t\t\tFields: []Field{\n\t\t\t\tStringField{Key: \"key\", Label: \"label\"},\n\t\t\t},\n\t\t}\n\t\tin := \"Value\\n\"\n\t\tout := bytes.NewBuffer(nil)\n\t\tdata, err := f.Run(strings.NewReader(in), out)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, map[string]string{\"key\": \"Value\"}, data)\n\t\tassert.Equal(t, \"  label: \", out.String())\n\t})\n\tt.Run(\"Fields\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := Form{\n\t\t\tFields: []Field{\n\t\t\t\tStringField{Key: \"a\", Label: \"label a\"},\n\t\t\t\tStringField{Key: \"b\", Label: \"label b\"},\n\t\t\t},\n\t\t}\n\t\tin := \"1\\n2\\n\"\n\t\tout := bytes.NewBuffer(nil)\n\t\tdata, err := f.Run(strings.NewReader(in), out)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, map[string]string{\"a\": \"1\", \"b\": \"2\"}, data)\n\t\tassert.Equal(t, \"  label a:   label b: \", out.String())\n\t})\n\tt.Run(\"Defaults\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := Form{\n\t\t\tFields: []Field{\n\t\t\t\tStringField{Key: \"a\", Label: \"label a\", Default: \"default a\"},\n\t\t\t\tStringField{Key: \"b\", Label: \"label b\", Default: \"default b\"},\n\t\t\t},\n\t\t}\n\t\tin := \"\\n2\\n\"\n\t\tout := bytes.NewBuffer(nil)\n\t\tdata, err := f.Run(strings.NewReader(in), out)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, map[string]string{\"a\": \"default a\", \"b\": \"2\"}, data)\n\t\tassert.Equal(t, \"  label a [default a]:   label b [default b]: \", out.String())\n\t})\n\tt.Run(\"Errors\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tf := Form{\n\t\t\tFields: []Field{\n\t\t\t\tStringField{Key: \"key\", Label: \"label\", Min: 6, Max: 10},\n\t\t\t},\n\t\t}\n\t\tin := \"short\\ntoo damn long\\nperfect\\n\"\n\t\tout := bytes.NewBuffer(nil)\n\t\tdata, err := f.Run(strings.NewReader(in), out)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, map[string]string{\"key\": \"perfect\"}, data)\n\t\tassert.Equal(t, \"  label: - invalid input, min length is 6\\n  label: - invalid input, max length is 10\\n  label: \", out.String())\n\t})\n}\n"
  },
  {
    "path": "internal/ui/pb/doc.go",
    "content": "// Package pb implements a progressbar component for CLI user interfaces\npackage pb\n"
  },
  {
    "path": "internal/ui/pb/helpers.go",
    "content": "package pb\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"time\"\n)\n\n// GetFixedLengthIntFormat returns \"%0__d\" format argument for fmt functions\n// that will produce a base-10 right-aligned zero-padded string representation\n// of the supplied integer value. The number of characters (i.e. the actual\n// number + how many zeros it will be padded on the left with) in the returned\n// string corresponds to the number of digits in the supplied maxValue.\nfunc GetFixedLengthIntFormat(maxValue int64) (formatStr string) {\n\tresLen := 1\n\tif maxValue < 0 {\n\t\tresLen++\n\t}\n\tfor maxValue /= 10; maxValue != 0; maxValue /= 10 {\n\t\tresLen++\n\t}\n\treturn \"%0\" + strconv.Itoa(resLen) + \"d\"\n}\n\n// GetFixedLengthFloatFormat returns \"%0__.__f\" format argument for fmt\n// functions that will produce a base-10 right-aligned zero-padded string\n// representation of the supplied float value, with the specified decimal\n// precision. The number of characters (i.e. the actual number + maybe dot and\n// precision + how many zeros it will be padded on the left with) in the\n// returned string corresponds to the number of digits in the supplied maxValue\n// and the desired precision.\nfunc GetFixedLengthFloatFormat(maxValue float64, precision uint) (formatStr string) {\n\tresLen := uint(1)\n\tif maxValue < 0 {\n\t\tmaxValue = -maxValue\n\t\tresLen++\n\t}\n\tif maxValue >= 10 {\n\t\tresLen += uint(math.Log10(maxValue))\n\t}\n\tif precision > 0 {\n\t\tresLen += precision + 1\n\t}\n\treturn \"%0\" + strconv.FormatUint(uint64(resLen), 10) + \".\" + strconv.Itoa(int(precision)) + \"f\" //nolint:gosec\n}\n\n// GetFixedLengthDuration takes a *positive* duration and its max value and\n// returns a string with a fixed width so we can prevent UI elements jumping\n// around. The format is \"___d__h__m__s.s\", but leading values can be omitted\n// based on the maxDuration value, the results can be: \"___h__m__s.s\".\n//\n// This is code was inspired by the Go stdlib's time.Duration.String() code.\n// TODO: more flexibility - negative values or variable precision?\nfunc GetFixedLengthDuration(d, maxDuration time.Duration) (result string) {\n\tconst rounding = 100 * time.Millisecond\n\tif d < 0 {\n\t\td = -d\n\t}\n\tif maxDuration < 0 {\n\t\tmaxDuration = -maxDuration\n\t}\n\tif maxDuration < d {\n\t\tmaxDuration = d\n\t}\n\tmaxDuration = maxDuration.Round(rounding)\n\n\t// Largest time is \"106751d23h47m16.9s\", i.e. time.Duration(math.MaxInt64)\n\t// Positions:    0    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15   16   17\n\tbuf := [18]byte{'0', '0', '0', '0', '0', '0', 'd', '0', '0', 'h', '0', '0', 'm', '0', '0', '.', '0', 's'}\n\n\tu := d.Round(rounding) / (rounding)\n\tu, buf[16] = u/10, byte(u%10)+'0' //nolint:gosec\n\tu, buf[14] = u/10, byte(u%10)+'0' //nolint:gosec\n\tif maxDuration < 10*time.Second {\n\t\treturn string(buf[14:])\n\t}\n\n\tu, buf[13] = u/6, byte(u%6)+'0' //nolint:gosec\n\tif maxDuration < time.Minute {\n\t\treturn string(buf[13:])\n\t}\n\n\tu, buf[11] = u/10, byte(u%10)+'0' //nolint:gosec\n\tif maxDuration < 10*time.Minute {\n\t\treturn string(buf[11:])\n\t}\n\n\tu, buf[10] = u/6, byte(u%6)+'0' //nolint:gosec\n\tif maxDuration < time.Hour {\n\t\treturn string(buf[10:])\n\t}\n\n\tu, h := u/24, u%24\n\tbuf[7], buf[8] = byte(h/10)+'0', byte(h%10)+'0' //nolint:gosec\n\tif maxDuration < 10*time.Hour {\n\t\treturn string(buf[8:])\n\t} else if maxDuration < 24*time.Hour {\n\t\treturn string(buf[7:])\n\t}\n\n\tu, buf[5] = u/10, byte(u%10)+'0' //nolint:gosec\n\tremDayPowers := maxDuration / (240 * time.Hour)\n\ti := 5\n\tfor remDayPowers > 0 {\n\t\ti--\n\t\tu, buf[i] = u/10, byte(u%10)+'0' //nolint:gosec\n\t\tremDayPowers /= 10\n\t}\n\n\treturn string(buf[i:])\n}\n\n// Clampf returns the given value, \"clamped\" to the range [floor, ceiling].\nfunc Clampf(val, floor, ceiling float64) float64 {\n\tswitch {\n\tcase val < floor:\n\t\treturn floor\n\tcase val > ceiling:\n\t\treturn ceiling\n\tdefault:\n\t\treturn val\n\t}\n}\n"
  },
  {
    "path": "internal/ui/pb/helpers_test.go",
    "content": "package pb\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestGetFixedLengthInt(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tval, maxVal int64\n\t\texpRes      string\n\t}{\n\t\t{1, 0, \"1\"},\n\t\t{1, 1, \"1\"},\n\t\t{1, 5, \"1\"},\n\t\t{111, 5, \"111\"},\n\t\t{-1, 5, \"-1\"},\n\t\t{-1, -50, \"-01\"},\n\t\t{-1, 50, \"-1\"},\n\n\t\t{1, 15, \"01\"},\n\t\t{1, 15, \"01\"},\n\t\t{1, 150, \"001\"},\n\t\t{1, 1500, \"0001\"},\n\t\t{999, 1500, \"0999\"},\n\t\t{-999, 1500, \"-999\"},\n\t\t{-9999, 1500, \"-9999\"},\n\t\t{1, 10000, \"00001\"},\n\t\t{1234567, 10000, \"1234567\"},\n\t\t{123456790, math.MaxInt64, \"0000000000123456790\"},\n\t\t{-123456790, math.MaxInt64, \"-000000000123456790\"},\n\t\t{math.MaxInt64, math.MaxInt64, \"9223372036854775807\"},\n\t\t{-123456790, math.MinInt64, \"-0000000000123456790\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.expRes, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfmtFormat := GetFixedLengthIntFormat(tc.maxVal)\n\t\t\tres := fmt.Sprintf(fmtFormat, tc.val)\n\t\t\tassert.Equal(t, tc.expRes, res)\n\t\t\tback, err := strconv.ParseInt(res, 10, 64)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.val, back)\n\t\t})\n\t}\n}\n\nfunc TestGetFixedLengthFloat(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tval, maxVal float64\n\t\tprecision   uint\n\t\texpRes      string\n\t}{\n\t\t{0, 0, 0, \"0\"},\n\t\t{0, 0, 2, \"0.00\"},\n\t\t{0, 100, 2, \"000.00\"},\n\t\t{0, -100, 2, \"0000.00\"},\n\t\t{12, -100, 2, \"0012.00\"},\n\t\t{-12, -100, 2, \"-012.00\"},\n\t\t{12, 99, 2, \"12.00\"},\n\t\t{12, 100, 2, \"012.00\"},\n\t\t{1, 0, 0, \"1\"},\n\t\t{1, 0, 1, \"1.0\"},\n\t\t{1, 0, 2, \"1.00\"},\n\t\t{1.01, 0, 1, \"1.0\"},\n\t\t{1.01, 0, 1, \"1.0\"},\n\t\t{1.01, 0, 2, \"1.01\"},\n\t\t{1.007, 0, 2, \"1.01\"},\n\t\t{1.003, 0, 2, \"1.00\"},\n\t\t{1.003, 0, 3, \"1.003\"},\n\t\t{1.003, 0, 4, \"1.0030\"},\n\t\t{1.003, 1, 4, \"1.0030\"},\n\t\t{1.003, 9.999, 4, \"1.0030\"},\n\t\t{1.003, 10, 4, \"01.0030\"},\n\t\t{1.003, -10, 4, \"001.0030\"},\n\t\t{-1.003, -10, 4, \"-01.0030\"},\n\t\t{12.003, 1000, 4, \"0012.0030\"},\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"tc%d_exp_%s\", i, tc.expRes), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfmtFormat := GetFixedLengthFloatFormat(tc.maxVal, tc.precision)\n\t\t\tres := fmt.Sprintf(fmtFormat, tc.val)\n\t\t\tassert.Equal(t, tc.expRes, res)\n\t\t\tback, err := strconv.ParseFloat(res, 64)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tprecPow := math.Pow(10, float64(tc.precision))\n\t\t\texpParseVal := math.Round(tc.val*precPow) / precPow\n\t\t\tassert.Equal(t, expParseVal, back)\n\t\t})\n\t}\n}\n\nfunc TestGetFixedLengthDuration(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tval, maxVal time.Duration\n\t\texpRes      string\n\t}{\n\t\t{0, 0, \"0.0s\"},\n\t\t{1 * time.Second, 0, \"1.0s\"},\n\t\t{9*time.Second + 940*time.Millisecond, 0, \"9.9s\"},\n\t\t{9*time.Second + 950*time.Millisecond, 0, \"10.0s\"},\n\t\t{1100 * time.Millisecond, 0, \"1.1s\"},\n\t\t{-1100 * time.Millisecond, 0, \"1.1s\"},\n\t\t{1100 * time.Millisecond, 10 * time.Second, \"01.1s\"},\n\t\t{1100 * time.Millisecond, 1 * time.Minute, \"0m01.1s\"},\n\t\t{1100 * time.Millisecond, -1 * time.Minute, \"0m01.1s\"},\n\t\t{-1100 * time.Millisecond, -1 * time.Minute, \"0m01.1s\"},\n\t\t{1100 * time.Millisecond, 10 * time.Minute, \"00m01.1s\"},\n\t\t{1100 * time.Millisecond, time.Hour, \"0h00m01.1s\"},\n\t\t{1100 * time.Millisecond, 10 * time.Hour, \"00h00m01.1s\"},\n\t\t{183 * time.Second, 10 * time.Minute, \"03m03.0s\"},\n\t\t{183 * time.Second, 120 * time.Minute, \"0h03m03.0s\"},\n\t\t{183 * time.Second, 10 * time.Hour, \"00h03m03.0s\"},\n\t\t{183 * time.Second, 25 * time.Hour, \"0d00h03m03.0s\"},\n\t\t{25 * time.Hour, 25 * time.Hour, \"1d01h00m00.0s\"},\n\t\t{482 * time.Hour, 25 * time.Hour, \"20d02h00m00.0s\"},\n\t\t{482 * time.Hour, 4800 * time.Hour, \"020d02h00m00.0s\"},\n\t\t{482*time.Hour + 671*time.Second + 65*time.Millisecond, time.Duration(math.MaxInt64), \"000020d02h11m11.1s\"},\n\n\t\t// subtracting a second since rounding doesn't work as expected at the limits of int64\n\t\t{time.Duration(math.MaxInt64) - time.Second, time.Duration(math.MaxInt64), \"106751d23h47m15.9s\"},\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"tc%d_exp_%s\", i, tc.expRes), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tres := GetFixedLengthDuration(tc.val, tc.maxVal)\n\t\t\tassert.Equal(t, tc.expRes, res)\n\n\t\t\texpBackDur := tc.val.Round(100 * time.Millisecond)\n\t\t\tif expBackDur < 0 {\n\t\t\t\texpBackDur = -expBackDur\n\t\t\t}\n\t\t\tbackDur, err := types.ParseExtendedDuration(res)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, expBackDur, backDur)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/ui/pb/progressbar.go",
    "content": "package pb\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/sirupsen/logrus\"\n)\n\n//nolint:gochecknoglobals\nvar (\n\tcolorFaint   = color.New(color.Faint)\n\tstatusColors = map[Status]*color.Color{\n\t\tInterrupted: color.New(color.FgRed),\n\t\tDone:        color.New(color.FgGreen),\n\t\tWaiting:     colorFaint,\n\t}\n)\n\nconst (\n\t// DefaultWidth of the progress bar\n\tDefaultWidth = 40\n\t// threshold below which progress should be rendered as\n\t// percentages instead of filling bars\n\tminWidth = 8\n)\n\n// Status of the progress bar\ntype Status rune\n\n// Progress bar status symbols\nconst (\n\tRunning     Status = ' '\n\tWaiting     Status = '•'\n\tStopping    Status = '↓'\n\tInterrupted Status = '✗'\n\tDone        Status = '✓'\n)\n\n// ProgressBar is a simple thread-safe progressbar implementation with\n// callbacks.\ntype ProgressBar struct {\n\tmutex  sync.RWMutex\n\twidth  int\n\tlogger *logrus.Entry\n\tstatus Status\n\n\tleft     func() string\n\tprogress func() (progress float64, right []string)\n\thijack   func() string\n}\n\n// ProgressBarOption is used for helper functions that modify the progressbar\n// parameters, either in the constructor or via the Modify() method.\ntype ProgressBarOption func(*ProgressBar)\n\n// WithLeft modifies the function that returns the left progressbar value.\nfunc WithLeft(left func() string) ProgressBarOption {\n\treturn func(pb *ProgressBar) { pb.left = left }\n}\n\n// WithConstLeft sets the left progressbar value to the supplied const.\nfunc WithConstLeft(left string) ProgressBarOption {\n\treturn func(pb *ProgressBar) {\n\t\tpb.left = func() string { return left }\n\t}\n}\n\n// WithLogger modifies the logger instance\nfunc WithLogger(logger *logrus.Entry) ProgressBarOption {\n\treturn func(pb *ProgressBar) { pb.logger = logger }\n}\n\n// WithProgress modifies the progress calculation function.\nfunc WithProgress(progress func() (float64, []string)) ProgressBarOption {\n\treturn func(pb *ProgressBar) { pb.progress = progress }\n}\n\n// WithStatus modifies the progressbar status\nfunc WithStatus(status Status) ProgressBarOption {\n\treturn func(pb *ProgressBar) { pb.status = status }\n}\n\n// WithConstProgress sets the progress and right values to the supplied consts.\nfunc WithConstProgress(progress float64, right ...string) ProgressBarOption {\n\treturn func(pb *ProgressBar) {\n\t\tpb.progress = func() (float64, []string) { return progress, right }\n\t}\n}\n\n// WithHijack replaces the progressbar Render function with the argument.\nfunc WithHijack(hijack func() string) ProgressBarOption {\n\treturn func(pb *ProgressBar) { pb.hijack = hijack }\n}\n\n// New creates and initializes a new ProgressBar struct, calling all of the\n// supplied options\nfunc New(options ...ProgressBarOption) *ProgressBar {\n\tpb := &ProgressBar{\n\t\tmutex: sync.RWMutex{},\n\t\twidth: DefaultWidth,\n\t}\n\tpb.Modify(options...)\n\treturn pb\n}\n\n// Left returns the left part of the progressbar in a thread-safe way.\nfunc (pb *ProgressBar) Left() string {\n\tpb.mutex.RLock()\n\tdefer pb.mutex.RUnlock()\n\n\treturn pb.renderLeft(0)\n}\n\n// renderLeft renders the left part of the progressbar, replacing text\n// exceeding maxLen with an ellipsis.\nfunc (pb *ProgressBar) renderLeft(maxLen int) string {\n\tvar left string\n\tif pb.left != nil {\n\t\tl := pb.left()\n\t\tif maxLen > 0 && len(l) > maxLen {\n\t\t\tl = l[:maxLen-3] + \"...\"\n\t\t}\n\t\tleft = l\n\t}\n\treturn left\n}\n\n// Modify changes the progressbar options in a thread-safe way.\nfunc (pb *ProgressBar) Modify(options ...ProgressBarOption) {\n\tpb.mutex.Lock()\n\tdefer pb.mutex.Unlock()\n\tfor _, option := range options {\n\t\toption(pb)\n\t}\n}\n\n// ProgressBarRender stores the different rendered parts of the\n// progress bar UI to allow dynamic positioning and padding of\n// elements in the terminal output (e.g. for responsive progress\n// bars).\ntype ProgressBarRender struct {\n\tRight                                   []string\n\tprogress, progressFill, progressPadding string\n\tLeft, Hijack                            string\n\tstatus                                  Status\n\tColor                                   bool\n}\n\n// Status returns an optionally colorized status string\nfunc (pbr *ProgressBarRender) Status() string {\n\tstatus := \" \"\n\n\tif pbr.status > 0 {\n\t\tstatus = string(pbr.status)\n\t\tif c, ok := statusColors[pbr.status]; pbr.Color && ok {\n\t\t\tstatus = c.Sprint(status)\n\t\t}\n\t}\n\n\treturn status\n}\n\n// Progress returns an assembled and optionally colorized progress string\nfunc (pbr *ProgressBarRender) Progress() string {\n\tvar body string\n\tif pbr.progress != \"\" {\n\t\tbody = fmt.Sprintf(\" %s \", pbr.progress)\n\t} else {\n\t\tpadding := pbr.progressPadding\n\t\tif pbr.Color {\n\t\t\tpadding = colorFaint.Sprint(pbr.progressPadding)\n\t\t}\n\t\tbody = pbr.progressFill + padding\n\t}\n\treturn fmt.Sprintf(\"[%s]\", body)\n}\n\nfunc (pbr ProgressBarRender) String() string {\n\tif pbr.Hijack != \"\" {\n\t\treturn pbr.Hijack\n\t}\n\tvar right string\n\tif len(pbr.Right) > 0 {\n\t\tright = \" \" + strings.Join(pbr.Right, \"  \")\n\t}\n\treturn pbr.Left + \" \" + pbr.Status() + \" \" + pbr.Progress() + right\n}\n\n// Render locks the progressbar struct for reading and calls all of\n// its methods to return the final output. A struct is returned over a\n// plain string to allow dynamic padding and positioning of elements\n// depending on other elements on the screen.\n//   - maxLeft defines the maximum character length of the left-side\n//     text. Characters exceeding this length will be replaced with a\n//     single ellipsis. Passing <=0 disables this.\n//   - widthDelta changes the progress bar width the specified amount of\n//     characters. E.g. passing -2 would shorten the width by 2 chars.\n//     If the resulting width is lower than minWidth, progress will be\n//     rendered as a percentage instead of a filling bar.\nfunc (pb *ProgressBar) Render(maxLeft, widthDelta int) ProgressBarRender {\n\tpb.mutex.RLock()\n\tdefer pb.mutex.RUnlock()\n\n\tvar out ProgressBarRender\n\tif pb.hijack != nil {\n\t\tout.Hijack = pb.hijack()\n\t\treturn out\n\t}\n\n\tvar progress float64\n\tif pb.progress != nil {\n\t\tprogress, out.Right = pb.progress()\n\t\tprogressClamped := Clampf(progress, 0, 1)\n\t\tif progress != progressClamped {\n\t\t\tprogress = progressClamped\n\t\t\tif pb.logger != nil {\n\t\t\t\tpb.logger.Warnf(\"progress value %.2f exceeds valid range, clamped between 0 and 1\", progress)\n\t\t\t}\n\t\t}\n\t}\n\n\twidth := Clampf(float64(pb.width+widthDelta), minWidth, DefaultWidth)\n\tpb.width = int(width)\n\n\tif pb.width > minWidth { //nolint:nestif\n\t\tspace := pb.width - 2\n\t\tfilled := int(float64(space) * progress)\n\n\t\tfilling := \"\"\n\t\tcaret := \"\"\n\t\tif filled > 0 {\n\t\t\tif filled < space {\n\t\t\t\tfilling = strings.Repeat(\"=\", filled-1)\n\t\t\t\tcaret = \">\"\n\t\t\t} else {\n\t\t\t\tfilling = strings.Repeat(\"=\", filled)\n\t\t\t}\n\t\t}\n\n\t\tout.progressPadding = \"\"\n\t\tif space > filled {\n\t\t\tout.progressPadding = strings.Repeat(\"-\", space-filled)\n\t\t}\n\n\t\tout.progressFill = filling + caret\n\t} else {\n\t\tout.progress = fmt.Sprintf(\"%3.f%%\", progress*100)\n\t}\n\n\tout.Left = pb.renderLeft(maxLeft)\n\tout.status = pb.status\n\n\treturn out\n}\n"
  },
  {
    "path": "internal/ui/pb/progressbar_test.go",
    "content": "package pb\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// TODO(imiric): Consider adding logging tests for 100% pb coverage.\n// Unfortunately the following introduces an import cycle: pb -> lib -> pb\n// func getTestLogger() *logger.Entry {\n// \tlogHook := testutils.NewLogHook(logrus.WarnLevel)\n// \ttestLog := logrus.New()\n// \ttestLog.AddHook(logHook)\n// \ttestLog.SetOutput(io.Discard)\n// \treturn logrus.NewEntry(testLog)\n// }\n\nfunc TestProgressBarRender(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\toptions      []ProgressBarOption\n\t\tpbWidthDelta int\n\t\texpected     string\n\t}{\n\t\t{\n\t\t\t[]ProgressBarOption{WithLeft(func() string { return \"left\" })},\n\t\t\t0, \"left   [--------------------------------------]\",\n\t\t},\n\t\t{\n\t\t\t[]ProgressBarOption{WithConstLeft(\"constLeft\")},\n\t\t\t0, \"constLeft   [--------------------------------------]\",\n\t\t},\n\t\t{[]ProgressBarOption{\n\t\t\tWithLeft(func() string { return \"left\" }),\n\t\t\tWithStatus(Done),\n\t\t}, 0, \"left ✓ [--------------------------------------]\"},\n\t\t{[]ProgressBarOption{\n\t\t\tWithLeft(func() string { return \"left\" }),\n\t\t\tWithProgress(func() (float64, []string) { return 0, []string{\"right\"} }),\n\t\t}, 0, \"left   [--------------------------------------] right\"},\n\t\t{[]ProgressBarOption{\n\t\t\tWithLeft(func() string { return \"left\" }),\n\t\t\tWithProgress(func() (float64, []string) { return 0.5, []string{\"right\"} }),\n\t\t}, 0, \"left   [==================>-------------------] right\"},\n\t\t{[]ProgressBarOption{\n\t\t\tWithLeft(func() string { return \"left\" }),\n\t\t\tWithProgress(func() (float64, []string) { return 1.0, []string{\"right\"} }),\n\t\t}, 0, \"left   [======================================] right\"},\n\t\t{[]ProgressBarOption{\n\t\t\tWithLeft(func() string { return \"left\" }),\n\t\t\tWithProgress(func() (float64, []string) { return -1, []string{\"right\"} }),\n\t\t}, 0, \"left   [--------------------------------------] right\"},\n\t\t{[]ProgressBarOption{\n\t\t\tWithLeft(func() string { return \"left\" }),\n\t\t\tWithProgress(func() (float64, []string) { return 2, []string{\"right\"} }),\n\t\t}, 0, \"left   [======================================] right\"},\n\t\t{[]ProgressBarOption{\n\t\t\tWithLeft(func() string { return \"left\" }),\n\t\t\tWithConstProgress(0.2, \"constProgress\"),\n\t\t}, 0, \"left   [======>-------------------------------] constProgress\"},\n\t\t{[]ProgressBarOption{\n\t\t\tWithHijack(func() string { return \"progressbar hijack!\" }),\n\t\t}, 0, \"progressbar hijack!\"},\n\t\t{\n\t\t\t[]ProgressBarOption{WithConstProgress(0.25, \"\")},\n\t\t\t-DefaultWidth, \"   [  25% ] \",\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.expected, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpbar := New(tc.options...)\n\t\t\tassert.NotNil(t, pbar)\n\t\t\tassert.Equal(t, tc.expected, pbar.Render(0, tc.pbWidthDelta).String())\n\t\t})\n\t}\n}\n\nfunc TestProgressBarRenderPaddingMaxLeft(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tmaxLen   int\n\t\tleft     string\n\t\texpected string\n\t}{\n\t\t{-1, \"left\", \"left   [--------------------------------------]\"},\n\t\t{0, \"left\", \"left   [--------------------------------------]\"},\n\t\t{10, \"left_truncated\", \"left_tr...   [--------------------------------------]\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.left, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpbar := New(WithLeft(func() string { return tc.left }))\n\t\t\tassert.NotNil(t, pbar)\n\t\t\tassert.Equal(t, tc.expected, pbar.Render(tc.maxLen, 0).String())\n\t\t})\n\t}\n}\n\nfunc TestProgressBarLeft(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tleft     func() string\n\t\texpected string\n\t}{\n\t\t{nil, \"\"},\n\t\t{func() string { return \" left \" }, \" left \"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.expected, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tpbar := New(WithLeft(tc.left))\n\t\t\tassert.NotNil(t, pbar)\n\t\t\tassert.Equal(t, tc.expected, pbar.Left())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "internal/usage/usage.go",
    "content": "// Package usage implements usage tracking for k6 in order to figure what is being used within a given execution\npackage usage\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n)\n\n// Usage is a way to collect usage data for within k6\ntype Usage struct {\n\tl *sync.Mutex\n\tm map[string]any\n}\n\n// New returns a new empty Usage ready to be used\nfunc New() *Usage {\n\treturn &Usage{\n\t\tl: new(sync.Mutex),\n\t\tm: make(map[string]any),\n\t}\n}\n\n// Strings appends the provided value to a slice of strings that is the value.\n// Appending to the slice if the key is already there.\n// It also works out level of keys\nfunc (u *Usage) Strings(originalKey, value string) error {\n\tu.l.Lock()\n\tdefer u.l.Unlock()\n\tm, newKey, err := u.createLevel(originalKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\toldV, ok := m[newKey]\n\tif !ok {\n\t\tm[newKey] = []string{value}\n\t\treturn nil\n\t}\n\tswitch oldValue := oldV.(type) {\n\tcase []string:\n\t\tm[newKey] = append(oldValue, value)\n\tdefault:\n\t\treturn fmt.Errorf(\"value of key %s is not []string as expected but %T\", originalKey, oldValue)\n\t}\n\treturn nil\n}\n\n// Uint64 adds the provided value to a given key. Creating the key if needed and working out levels of keys\nfunc (u *Usage) Uint64(originalKey string, value uint64) error {\n\tu.l.Lock()\n\tdefer u.l.Unlock()\n\tm, newKey, err := u.createLevel(originalKey)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toldValue, ok := m[newKey]\n\tif !ok {\n\t\tm[newKey] = value\n\t\treturn nil\n\t}\n\tswitch oldVUint64 := oldValue.(type) {\n\tcase uint64:\n\t\tm[newKey] = oldVUint64 + value\n\tdefault:\n\t\treturn fmt.Errorf(\"value of key %s is not uint64 as expected but %T\", originalKey, oldValue)\n\t}\n\treturn nil\n}\n\nfunc (u *Usage) createLevel(key string) (map[string]any, string, error) {\n\tlevelKey, subLevelKey, found := strings.Cut(key, \"/\")\n\tif !found {\n\t\treturn u.m, key, nil\n\t}\n\tif strings.Contains(subLevelKey, \"/\") {\n\t\treturn nil, \"\", fmt.Errorf(\"only one level is permitted in usages: %q\", key)\n\t}\n\n\tlevel, ok := u.m[levelKey]\n\tif !ok {\n\t\tlevel = make(map[string]any)\n\t\tu.m[levelKey] = level\n\t}\n\tlevelMap, ok := level.(map[string]any)\n\tif !ok {\n\t\treturn nil, \"\", fmt.Errorf(\"new level %q for key %q as the key was already used for %T\", levelKey, key, level)\n\t}\n\treturn levelMap, subLevelKey, nil\n}\n\n// Map returns a copy of the internal map\nfunc (u *Usage) Map() map[string]any {\n\tu.l.Lock()\n\tdefer u.l.Unlock()\n\n\treturn deepClone(u.m)\n}\n\nfunc deepClone(m map[string]any) map[string]any {\n\tresult := make(map[string]any, len(m))\n\tfor k, v := range m {\n\t\tif newM, ok := v.(map[string]any); ok {\n\t\t\tv = deepClone(newM)\n\t\t}\n\t\tresult[k] = v\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "internal/usage/usage_test.go",
    "content": "package usage\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestErrors(t *testing.T) {\n\tt.Parallel()\n\tu := New()\n\trequire.NoError(t, u.Uint64(\"test/one\", 1))\n\trequire.NoError(t, u.Uint64(\"test/two\", 1))\n\trequire.NoError(t, u.Uint64(\"test/two\", 1))\n\trequire.NoError(t, u.Strings(\"test/three\", \"three\"))\n\trequire.NoError(t, u.Strings(\"test2/one\", \"one\"))\n\n\trequire.ErrorContains(t, u.Strings(\"test/one\", \"one\"),\n\t\t\"test/one is not []string as expected but uint64\")\n\trequire.ErrorContains(t, u.Uint64(\"test2/one\", 1),\n\t\t\"test2/one is not uint64 as expected but []string\")\n\n\trequire.NoError(t, u.Strings(\"test3\", \"some\"))\n\trequire.ErrorContains(t, u.Strings(\"test3/one\", \"one\"),\n\t\t`new level \"test3\" for key \"test3/one\" as the key was already used for []string`)\n\n\tm := u.Map()\n\trequire.EqualValues(t, map[string]any{\n\t\t\"test\": map[string]any{\n\t\t\t\"one\":   uint64(1),\n\t\t\t\"two\":   uint64(2),\n\t\t\t\"three\": []string{\"three\"},\n\t\t},\n\t\t\"test2\": map[string]any{\n\t\t\t\"one\": []string{\"one\"},\n\t\t},\n\t\t\"test3\": []string{\"some\"},\n\t}, m)\n}\n"
  },
  {
    "path": "js/common/bridge.go",
    "content": "package common\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/serenize/snaker\"\n)\n\n// if a fieldName is the key of this map exactly than the value for the given key should be used as\n// the name of the field in js\n//\n//nolint:gochecknoglobals\nvar fieldNameExceptions = map[string]string{\n\t\"OCSP\": \"ocsp\",\n}\n\n// FieldName returns the JS name for an exported struct field. The name is snake_cased, with respect for\n// certain common initialisms (URL, ID, HTTP, etc).\nfunc FieldName(_ reflect.Type, f reflect.StructField) string {\n\t// PkgPath is non-empty for unexported fields.\n\tif f.PkgPath != \"\" {\n\t\treturn \"\"\n\t}\n\n\t// Allow a `js:\"name\"` tag to override the default name.\n\tif tag := f.Tag.Get(\"js\"); tag != \"\" {\n\t\t// Matching encoding/json, `js:\"-\"` hides a field.\n\t\tif tag == \"-\" {\n\t\t\treturn \"\"\n\t\t}\n\t\treturn tag\n\t}\n\n\tif exception, ok := fieldNameExceptions[f.Name]; ok {\n\t\treturn exception\n\t}\n\n\t// Default to lowercasing the first character of the field name.\n\treturn snaker.CamelToSnake(f.Name)\n}\n\n// if a methodName is the key of this map exactly than the value for the given key should be used as\n// the name of the method in js\n//\n//nolint:gochecknoglobals\nvar methodNameExceptions = map[string]string{\n\t\"JSON\": \"json\",\n\t\"HTML\": \"html\",\n\t\"URL\":  \"url\",\n\t\"OCSP\": \"ocsp\",\n}\n\n// MethodName returns the JS name for an exported method. The first letter of the method's name is\n// lowercased, otherwise it is unaltered.\nfunc MethodName(_ reflect.Type, m reflect.Method) string {\n\t// A field with a name beginning with an X is a constructor, and just gets the prefix stripped.\n\t// Note: They also get some special treatment from Bridge(), see further down.\n\tif m.Name[0] == 'X' {\n\t\treturn m.Name[1:]\n\t}\n\n\tif exception, ok := methodNameExceptions[m.Name]; ok {\n\t\treturn exception\n\t}\n\t// Lowercase the first character of the method name.\n\treturn strings.ToLower(m.Name[0:1]) + m.Name[1:]\n}\n\n// FieldNameMapper for sobek.Runtime.SetFieldNameMapper()\ntype FieldNameMapper struct{}\n\n// FieldName is part of the sobek.FieldNameMapper interface\n// https://godoc.org/github.com/grafana/sobek#FieldNameMapper\nfunc (FieldNameMapper) FieldName(t reflect.Type, f reflect.StructField) string {\n\treturn FieldName(t, f)\n}\n\n// MethodName is part of the sobek.FieldNameMapper interface\n// https://godoc.org/github.com/grafana/sobek#FieldNameMapper\nfunc (FieldNameMapper) MethodName(t reflect.Type, m reflect.Method) string { return MethodName(t, m) }\n"
  },
  {
    "path": "js/common/bridge_test.go",
    "content": "package common\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\ntype bridgeTestFieldsType struct {\n\tExported       string\n\tExportedTag    string `js:\"renamed\"`\n\tExportedHidden string `js:\"-\"`\n\tunexported     string //nolint:unused // actually checked in the test\n\tunexportedTag  string `js:\"unexported\"` //nolint:unused // actually checked in the test\n}\n\ntype bridgeTestMethodsType struct{}\n\nfunc (bridgeTestMethodsType) ExportedFn() {}\n\n//nolint:unused // needed for the actual test to check that it won't be seen\nfunc (bridgeTestMethodsType) unexportedFn() {}\n\nfunc (*bridgeTestMethodsType) ExportedPtrFn() {}\n\n//nolint:unused // needed for the actual test to check that it won't be seen\nfunc (*bridgeTestMethodsType) unexportedPtrFn() {}\n\ntype bridgeTestOddFieldsType struct {\n\tTwoWords string\n\tURL      string\n}\n\ntype bridgeTestConstructorType struct{}\n\ntype bridgeTestConstructorSpawnedType struct{}\n\nfunc (bridgeTestConstructorType) XConstructor() bridgeTestConstructorSpawnedType {\n\treturn bridgeTestConstructorSpawnedType{}\n}\n\nfunc TestFieldNameMapper(t *testing.T) {\n\tt.Parallel()\n\ttestdata := []struct {\n\t\tTyp     reflect.Type\n\t\tFields  map[string]string\n\t\tMethods map[string]string\n\t}{\n\t\t{reflect.TypeFor[bridgeTestFieldsType](), map[string]string{\n\t\t\t\"Exported\":       \"exported\",\n\t\t\t\"ExportedTag\":    \"renamed\",\n\t\t\t\"ExportedHidden\": \"\",\n\t\t\t\"unexported\":     \"\",\n\t\t\t\"unexportedTag\":  \"\",\n\t\t}, nil},\n\t\t{reflect.TypeFor[bridgeTestMethodsType](), nil, map[string]string{\n\t\t\t\"ExportedFn\":   \"exportedFn\",\n\t\t\t\"unexportedFn\": \"\",\n\t\t}},\n\t\t{reflect.TypeFor[bridgeTestOddFieldsType](), map[string]string{\n\t\t\t\"TwoWords\": \"two_words\",\n\t\t\t\"URL\":      \"url\",\n\t\t}, nil},\n\t\t{reflect.TypeFor[bridgeTestConstructorType](), nil, map[string]string{\n\t\t\t\"XConstructor\": \"Constructor\",\n\t\t}},\n\t}\n\tfor _, data := range testdata {\n\t\tfor field, name := range data.Fields {\n\t\t\tt.Run(field, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tf, ok := data.Typ.FieldByName(field)\n\t\t\t\trequire.True(t, ok, \"no such field\")\n\t\t\t\tassert.Equal(t, name, (FieldNameMapper{}).FieldName(data.Typ, f))\n\t\t\t})\n\t\t}\n\t\tfor meth, name := range data.Methods {\n\t\t\tt.Run(meth, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tm, ok := data.Typ.MethodByName(meth)\n\t\t\t\tif name != \"\" {\n\t\t\t\t\trequire.True(t, ok, \"no such method\")\n\t\t\t\t\tassert.Equal(t, name, (FieldNameMapper{}).MethodName(data.Typ, m))\n\t\t\t\t} else {\n\t\t\t\t\tassert.False(t, ok, \"exported by accident\")\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "js/common/event.go",
    "content": "package common\n\nimport \"go.k6.io/k6/internal/event\"\n\n// Events are the event subscriber interfaces for the global event system, and\n// the local (per-VU) event system.\ntype Events struct {\n\tGlobal, Local event.Subscriber\n}\n"
  },
  {
    "path": "js/common/frozen_object.go",
    "content": "package common\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// FreezeObject replicates the JavaScript Object.freeze function.\nfunc FreezeObject(rt *sobek.Runtime, obj sobek.Value) error {\n\tglobal := rt.GlobalObject().Get(\"Object\").ToObject(rt)\n\tfreeze, ok := sobek.AssertFunction(global.Get(\"freeze\"))\n\tif !ok {\n\t\tpanic(\"failed to get the Object.freeze function from the runtime\")\n\t}\n\tisFrozen, ok := sobek.AssertFunction(global.Get(\"isFrozen\"))\n\tif !ok {\n\t\tpanic(\"failed to get the Object.isFrozen function from the runtime\")\n\t}\n\tfobj := &freezing{\n\t\tglobal:   global,\n\t\trt:       rt,\n\t\tfreeze:   freeze,\n\t\tisFrozen: isFrozen,\n\t}\n\treturn fobj.deepFreeze(obj)\n}\n\ntype freezing struct {\n\trt       *sobek.Runtime\n\tglobal   sobek.Value\n\tfreeze   sobek.Callable\n\tisFrozen sobek.Callable\n}\n\nfunc (f *freezing) deepFreeze(val sobek.Value) error {\n\tif val != nil && sobek.IsNull(val) {\n\t\treturn nil\n\t}\n\n\t_, err := f.freeze(sobek.Undefined(), val)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"object freeze failed: %w\", err)\n\t}\n\n\to := val.ToObject(f.rt)\n\tif o == nil {\n\t\treturn nil\n\t}\n\n\tfor _, key := range o.Keys() {\n\t\tprop := o.Get(key)\n\t\tif prop == nil {\n\t\t\tcontinue\n\t\t}\n\t\tfrozen, err := f.isFrozen(sobek.Undefined(), prop)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif frozen.ToBoolean() { // prevent cycles\n\t\t\tcontinue\n\t\t}\n\t\tif err = f.deepFreeze(prop); err != nil {\n\t\t\treturn fmt.Errorf(\"deep freezing the property %s failed: %w\", key, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "js/common/frozen_object_test.go",
    "content": "package common\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFrozenObject(t *testing.T) {\n\tt.Parallel()\n\n\trt := sobek.New()\n\tobj := rt.NewObject()\n\trequire.NoError(t, obj.Set(\"foo\", \"bar\"))\n\trequire.NoError(t, rt.Set(\"obj\", obj))\n\n\tv, err := rt.RunString(`obj.foo`)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"bar\", v.String())\n\n\t// Set a nested object\n\t_, err = rt.RunString(`obj.nested = {propkey: \"value1\"}`)\n\trequire.NoError(t, err)\n\n\t// Not yet frozen\n\tv, err = rt.RunString(`Object.isFrozen(obj)`)\n\trequire.NoError(t, err)\n\trequire.False(t, v.ToBoolean())\n\n\trequire.NoError(t, FreezeObject(rt, obj))\n\n\t// It has been frozen\n\tv, err = rt.RunString(`Object.isFrozen(obj)`)\n\trequire.NoError(t, err)\n\trequire.True(t, v.ToBoolean())\n\n\t// It has deeply frozen the properties\n\tvfoo, err := rt.RunString(`Object.isFrozen(obj.foo)`)\n\trequire.NoError(t, err)\n\trequire.True(t, vfoo.ToBoolean())\n\n\t// And deeply frozen the nested objects\n\tvnested, err := rt.RunString(`Object.isFrozen(obj.nested)`)\n\trequire.NoError(t, err)\n\trequire.True(t, vnested.ToBoolean())\n\n\tnestedProp, err := rt.RunString(`Object.isFrozen(obj.nested.propkey)`)\n\trequire.NoError(t, err)\n\trequire.True(t, nestedProp.ToBoolean())\n\n\t// The assign is silently ignored\n\t_, err = rt.RunString(`obj.foo = \"bad change\"`)\n\trequire.NoError(t, err)\n\n\tv, err = rt.RunString(`obj.foo`)\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"bar\", v.String())\n\n\t// If the strict mode is enabled then it fails\n\tv, err = rt.RunString(`'use strict'; obj.foo = \"bad change\"`)\n\trequire.NotNil(t, err)\n\tassert.Contains(t, err.Error(), \"Cannot assign to read only property 'foo'\")\n\tassert.Nil(t, v)\n}\n"
  },
  {
    "path": "js/common/init_error.go",
    "content": "package common\n\n// InitContextError is an error that happened during the a test init context\ntype InitContextError string\n\n// NewInitContextError returns a new InitContextError with the provided message\nfunc NewInitContextError(msg string) InitContextError {\n\treturn (InitContextError)(msg)\n}\n\nfunc (i InitContextError) Error() string {\n\treturn (string)(i)\n}\n\nfunc (i InitContextError) String() string {\n\treturn (string)(i)\n}\n"
  },
  {
    "path": "js/common/initenv.go",
    "content": "package common\n\nimport (\n\t\"net/url\"\n\t\"path/filepath\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// InitEnvironment contains properties that can be accessed by Go code executed\n// in the k6 init context. It can be accessed by calling common.GetInitEnv().\ntype InitEnvironment struct {\n\t*lib.TestPreInitState\n\tFileSystems map[string]fsext.Fs\n\tCWD         *url.URL\n\t// TODO: get rid of this type altogether? we won't need it if we figure out\n\t// how to handle .tar archive vs regular JS script differences in FileSystems\n}\n\n// GetAbsFilePath should be used to access the FileSystems, since afero has a\n// bug when opening files with relative paths - it caches them from the FS root,\n// not the current working directory... So, if necessary, this method will\n// transform any relative paths into absolute ones, using the CWD.\n//\n// TODO: refactor? It was copied from\n// https://github.com/k6io/k6/blob/c51095ad7304bdd1e82cdb33c91abc331533b886/js/initcontext.go#L211-L222\nfunc (ie *InitEnvironment) GetAbsFilePath(filename string) string {\n\t// Here IsAbs should be enough but unfortunately it doesn't handle absolute paths starting from\n\t// the current drive on windows like `\\users\\noname\\...`. Also it makes it more easy to test and\n\t// will probably be need for archive execution under windows if always consider '/...' as an\n\t// absolute path.\n\tif filename[0] != '/' && filename[0] != '\\\\' && !filepath.IsAbs(filename) {\n\t\tfilename = filepath.Join(ie.CWD.Path, filename)\n\t}\n\tfilename = filepath.Clean(filename)\n\tif filename[0:1] != fsext.FilePathSeparator {\n\t\tfilename = fsext.FilePathSeparator + filename\n\t}\n\treturn filename\n}\n"
  },
  {
    "path": "js/common/interrupt_error.go",
    "content": "package common\n\nimport (\n\t\"errors\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// UnwrapSobekInterruptedError returns the internal error handled by Sobek.\nfunc UnwrapSobekInterruptedError(err error) error {\n\tvar sobekErr *sobek.InterruptedError\n\tif errors.As(err, &sobekErr) {\n\t\tif e, ok := sobekErr.Value().(error); ok {\n\t\t\treturn e\n\t\t}\n\t}\n\treturn err\n}\n"
  },
  {
    "path": "js/common/randsource.go",
    "content": "package common\n\nimport (\n\tcrand \"crypto/rand\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"math/rand\" // nosemgrep: math-random-used // used to seed the Marh.random of the JS VM that is pseudo random by specification\n\n\t\"github.com/grafana/sobek\"\n)\n\n// NewRandSource is copied from Sobek's source code:\n// https://github.com/grafana/sobek/blob/master/sobek/main.go#L44\n// The returned RandSource is NOT safe for concurrent use:\n// https://golang.org/pkg/math/rand/#NewSource\nfunc NewRandSource() sobek.RandSource {\n\tvar seed int64\n\tif err := binary.Read(crand.Reader, binary.LittleEndian, &seed); err != nil {\n\t\tpanic(fmt.Errorf(\"could not read random bytes: %w\", err))\n\t}\n\treturn rand.New(rand.NewSource(seed)).Float64 //nolint:gosec\n}\n"
  },
  {
    "path": "js/common/tags.go",
    "content": "package common\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// ApplyCustomUserTags modifies the given metrics.TagsAndMeta object with the\n// user specified custom tags and metadata.\n// It expects to receive the `keyValues` object in the `{key1: value1, key2:\n// value2, ...}` format.\nfunc ApplyCustomUserTags(rt *sobek.Runtime, tagsAndMeta *metrics.TagsAndMeta, keyValues sobek.Value) error {\n\tif keyValues == nil || sobek.IsNull(keyValues) || sobek.IsUndefined(keyValues) {\n\t\treturn nil\n\t}\n\n\tkeyValuesObj := keyValues.ToObject(rt)\n\n\tfor _, key := range keyValuesObj.Keys() {\n\t\tif err := ApplyCustomUserTag(tagsAndMeta, key, keyValuesObj.Get(key)); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// ApplyCustomUserTag modifies the given metrics.TagsAndMeta object with the\n// given custom tag and theirs value.\nfunc ApplyCustomUserTag(tagsAndMeta *metrics.TagsAndMeta, key string, val sobek.Value) error {\n\tkind := reflect.Invalid\n\tif typ := val.ExportType(); typ != nil {\n\t\tkind = typ.Kind()\n\t}\n\n\tswitch kind {\n\tcase\n\t\treflect.String,\n\t\treflect.Bool,\n\t\treflect.Int64,\n\t\treflect.Float64:\n\n\t\ttagsAndMeta.SetTag(key, val.String())\n\t\treturn nil\n\n\tdefault:\n\t\treturn fmt.Errorf(\n\t\t\t\"invalid value for metric tag '%s': \"+\n\t\t\t\t\"only String, Boolean and Number types are accepted as a metric tag values\",\n\t\t\tkey,\n\t\t)\n\t}\n}\n\n// ApplyCustomUserMetadata modifies the given metrics.TagsAndMeta object with the\n// given custom metadata and their value.\nfunc ApplyCustomUserMetadata(tagsAndMeta *metrics.TagsAndMeta, key string, val sobek.Value) error {\n\tkind := reflect.Invalid\n\tif typ := val.ExportType(); typ != nil {\n\t\tkind = typ.Kind()\n\t}\n\n\tswitch kind {\n\tcase\n\t\treflect.String,\n\t\treflect.Bool,\n\t\treflect.Int64,\n\t\treflect.Float64:\n\n\t\ttagsAndMeta.SetMetadata(key, val.String())\n\t\treturn nil\n\n\tdefault:\n\t\treturn fmt.Errorf(\n\t\t\t\"invalid value for metric metadata '%s': \"+\n\t\t\t\t\"only String, Boolean and Number types are accepted as a metric metadata value\",\n\t\t\tkey,\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "js/common/util.go",
    "content": "// Package common contains helpers for interacting with the JavaScript runtime.\npackage common\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// Throw a JS error; avoids re-wrapping GoErrors.\nfunc Throw(rt *sobek.Runtime, err error) {\n\tif e, ok := err.(*sobek.Exception); ok { //nolint:errorlint // we don't really want to unwrap here\n\t\tpanic(e)\n\t}\n\tpanic(rt.NewGoError(err)) // this catches the stack unlike rt.ToValue\n}\n\n// GetReader tries to return an io.Reader value from an exported Sobek value.\nfunc GetReader(data any) (io.Reader, error) {\n\tswitch r := data.(type) {\n\tcase string:\n\t\treturn bytes.NewBufferString(r), nil\n\tcase []byte:\n\t\treturn bytes.NewBuffer(r), nil\n\tcase io.Reader:\n\t\treturn r, nil\n\tcase sobek.ArrayBuffer:\n\t\treturn bytes.NewBuffer(r.Bytes()), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid type %T, it needs to be a string or ArrayBuffer\", data)\n\t}\n}\n\n// ToBytes tries to return a byte slice from compatible types.\nfunc ToBytes(data any) ([]byte, error) {\n\tswitch dt := data.(type) {\n\tcase []byte:\n\t\treturn dt, nil\n\tcase string:\n\t\treturn []byte(dt), nil\n\tcase sobek.ArrayBuffer:\n\t\treturn dt.Bytes(), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid type %T, expected string, []byte or ArrayBuffer\", data)\n\t}\n}\n\n// ToString tries to return a string from compatible types.\nfunc ToString(data any) (string, error) {\n\tswitch dt := data.(type) {\n\tcase []byte:\n\t\treturn string(dt), nil\n\tcase string:\n\t\treturn dt, nil\n\tcase sobek.ArrayBuffer:\n\t\treturn string(dt.Bytes()), nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"invalid type %T, expected string, []byte or ArrayBuffer\", data)\n\t}\n}\n\n// IsNullish checks if the given value is nullish, i.e. nil, undefined or null.\nfunc IsNullish(v sobek.Value) bool {\n\treturn v == nil || sobek.IsUndefined(v) || sobek.IsNull(v)\n}\n\n// IsAsyncFunction checks if the provided value is an AsyncFunction\nfunc IsAsyncFunction(rt *sobek.Runtime, val sobek.Value) bool {\n\tif IsNullish(val) {\n\t\treturn false\n\t}\n\treturn val.ToObject(rt).Get(\"constructor\").ToObject(rt).Get(\"name\").String() == \"AsyncFunction\"\n}\n"
  },
  {
    "path": "js/common/util_test.go",
    "content": "package common\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestThrow(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\tfn1, ok := sobek.AssertFunction(rt.ToValue(func() { Throw(rt, errors.New(\"aaaa\")) }))\n\trequire.True(t, ok, \"fn1 is invalid\")\n\t_, err := fn1(sobek.Undefined())\n\tassert.EqualError(t, err, \"GoError: aaaa\")\n\n\tfn2, ok := sobek.AssertFunction(rt.ToValue(func() { Throw(rt, err) }))\n\trequire.True(t, ok, \"fn2 is invalid\")\n\t_, err = fn2(sobek.Undefined())\n\tassert.EqualError(t, err, \"GoError: aaaa\")\n}\n\nfunc TestToBytes(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\tb := []byte(\"hello\")\n\ttestCases := []struct {\n\t\tin     any\n\t\texpOut []byte\n\t\texpErr string\n\t}{\n\t\t{b, b, \"\"},\n\t\t{\"hello\", b, \"\"},\n\t\t{rt.NewArrayBuffer(b), b, \"\"},\n\t\t{struct{}{}, nil, \"invalid type struct {}, expected string, []byte or ArrayBuffer\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%T\", tc.in), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tout, err := ToBytes(tc.in)\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\tassert.EqualError(t, err, tc.expErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.Equal(t, tc.expOut, out)\n\t\t})\n\t}\n}\n\nfunc TestToString(t *testing.T) {\n\tt.Parallel()\n\trt := sobek.New()\n\ts := \"hello\"\n\ttestCases := []struct {\n\t\tin             any\n\t\texpOut, expErr string\n\t}{\n\t\t{s, s, \"\"},\n\t\t{\"hello\", s, \"\"},\n\t\t{rt.NewArrayBuffer([]byte(s)), s, \"\"},\n\t\t{struct{}{}, \"\", \"invalid type struct {}, expected string, []byte or ArrayBuffer\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%T\", tc.in), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tout, err := ToString(tc.in)\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\tassert.EqualError(t, err, tc.expErr)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tassert.Equal(t, tc.expOut, out)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "js/modules/cjsmodule.go",
    "content": "package modules\n\nimport (\n\t\"errors\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/grafana/sobek/ast\"\n)\n\n// cjsModule represents a commonJS module\ntype cjsModule struct {\n\tprg                    *sobek.Program\n\texportedNames          []string\n\texportedNamesCallbacks []func([]string)\n}\n\nfunc newCjsModule(prg *sobek.Program) sobek.ModuleRecord {\n\treturn &cjsModule{prg: prg}\n}\n\nfunc (cm *cjsModule) Link() error { return nil }\n\nfunc (cm *cjsModule) InitializeEnvironment() error { return nil }\n\nfunc (cm *cjsModule) Instantiate(_ *sobek.Runtime) (sobek.CyclicModuleInstance, error) {\n\treturn &cjsModuleInstance{w: cm}, nil\n}\n\nfunc (cm *cjsModule) RequestedModules() []string { return nil }\n\nfunc (cm *cjsModule) Evaluate(_ *sobek.Runtime) *sobek.Promise {\n\tpanic(\"this shouldn't be called in the current implementation\")\n}\n\nfunc (cm *cjsModule) GetExportedNames(callback func([]string), _ ...sobek.ModuleRecord) bool {\n\tif cm.exportedNames != nil {\n\t\tcallback(cm.exportedNames)\n\t\treturn true\n\t}\n\tcm.exportedNamesCallbacks = append(cm.exportedNamesCallbacks, callback)\n\treturn false\n}\n\nfunc (cm *cjsModule) ResolveExport(exportName string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) {\n\treturn &sobek.ResolvedBinding{\n\t\tModule:      cm,\n\t\tBindingName: exportName,\n\t}, false\n}\n\ntype cjsModuleInstance struct {\n\tw                *cjsModule\n\texports          *sobek.Object\n\tisEsModuleMarked bool\n}\n\nfunc (cmi *cjsModuleInstance) HasTLA() bool { return false }\n\nfunc (cmi *cjsModuleInstance) RequestedModules() []string { return cmi.w.RequestedModules() }\n\nfunc (cmi *cjsModuleInstance) ExecuteModule(\n\trt *sobek.Runtime, _, _ func(any) error,\n) (sobek.CyclicModuleInstance, error) {\n\tv, err := rt.RunProgram(cmi.w.prg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmodule := rt.NewObject()\n\tcmi.exports = rt.NewObject()\n\t_ = module.Set(\"exports\", cmi.exports)\n\tcall, ok := sobek.AssertFunction(v)\n\tif !ok {\n\t\tpanic(\"Somehow a CommonJS module is not wrapped in a function - \" +\n\t\t\t\"this is a k6 bug, please report it (https://github.com/grafana/k6/issues)\")\n\t}\n\tif _, err = call(cmi.exports, module, cmi.exports); err != nil {\n\t\treturn nil, err\n\t}\n\n\texportsV := module.Get(\"exports\")\n\tif sobek.IsNull(exportsV) {\n\t\treturn nil, errors.New(\"CommonJS's exports must not be null\")\n\t}\n\tcmi.exports = exportsV.ToObject(rt)\n\n\t// this will be called multiple times we only need to update this on the first VU\n\tif cmi.w.exportedNames == nil {\n\t\tcmi.w.exportedNames = cmi.exports.Keys()\n\t\tif cmi.w.exportedNames == nil { // workaround if a CommonJS module does not have exports\n\t\t\tcmi.w.exportedNames = make([]string, 0)\n\t\t}\n\t\tfor _, callback := range cmi.w.exportedNamesCallbacks {\n\t\t\tcallback(cmi.w.exportedNames)\n\t\t}\n\t}\n\t__esModule := cmi.exports.Get(\"__esModule\") //nolint:revive\n\tcmi.isEsModuleMarked = __esModule != nil && __esModule.ToBoolean()\n\treturn cmi, nil\n}\n\nfunc (cmi *cjsModuleInstance) GetBindingValue(name string) sobek.Value {\n\tif name == jsDefaultExportIdentifier {\n\t\td := cmi.exports.Get(jsDefaultExportIdentifier)\n\t\tif d != nil {\n\t\t\treturn d\n\t\t}\n\t\treturn cmi.exports\n\t}\n\n\treturn cmi.exports.Get(name)\n}\n\n// cjsModuleFromString is a helper function which returns CJSModule given the argument it has.\nfunc cjsModuleFromString(prg *ast.Program) (sobek.ModuleRecord, error) {\n\tpgm, err := sobek.CompileAST(prg, true)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn newCjsModule(pgm), nil\n}\n"
  },
  {
    "path": "js/modules/gomodule.go",
    "content": "package modules\n\nimport (\n\t\"github.com/grafana/sobek\"\n)\n\n// This sobek.ModuleRecord wrapper for go/js module which conforms to modules.Module interface\ntype goModule struct {\n\tm                      Module\n\texportedNames          []string\n\texportedNamesCallbacks []func([]string)\n}\n\nfunc (gm *goModule) Link() error { return nil }\n\nfunc (gm *goModule) RequestedModules() []string { return nil }\n\nfunc (gm *goModule) InitializeEnvironment() error { return nil }\n\nfunc (gm *goModule) Instantiate(rt *sobek.Runtime) (sobek.CyclicModuleInstance, error) {\n\t// TODO(@mstoykov): try to work around this in some way maybe hostDefined on Module\n\tvu := rt.GlobalObject().Get(\"vubox\").Export().(vubox).vu //nolint:forcetypeassert\n\tmi := gm.m.NewModuleInstance(vu)\n\t// this will be called multiple times we only need to update this on the first VU\n\tif gm.exportedNames == nil {\n\t\tnamed := mi.Exports().Named\n\n\t\tif named == nil && mi.Exports().Default != nil {\n\t\t\t// If named is nil but default is defined, then try to work with\n\t\t\t// default and extract the names of the object's properties. This\n\t\t\t// behavior isn't ESM compatible, but we do want to allow defaults to\n\t\t\t// be imported as namespaced object, which is also how node works.\n\t\t\tobj := rt.ToValue(mi.Exports().Default).ToObject(rt)\n\t\t\tgm.exportedNames = obj.GetOwnPropertyNames()\n\t\t} else {\n\t\t\tgm.exportedNames = make([]string, 0, len(named))\n\t\t\tfor name := range named {\n\t\t\t\tgm.exportedNames = append(gm.exportedNames, name)\n\t\t\t}\n\t\t}\n\n\t\tfor _, callback := range gm.exportedNamesCallbacks {\n\t\t\tcallback(gm.exportedNames)\n\t\t}\n\t}\n\treturn &goModuleInstance{rt: rt, mi: mi}, nil\n}\n\nfunc (gm *goModule) Evaluate(_ *sobek.Runtime) *sobek.Promise { panic(\"this shouldn't happen\") }\n\nfunc (gm *goModule) GetExportedNames(callback func([]string), _ ...sobek.ModuleRecord) bool {\n\tif gm.exportedNames != nil {\n\t\tcallback(gm.exportedNames)\n\t\treturn true\n\t}\n\tgm.exportedNamesCallbacks = append(gm.exportedNamesCallbacks, callback)\n\treturn false\n}\n\nfunc (gm *goModule) ResolveExport(exportName string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) {\n\treturn &sobek.ResolvedBinding{\n\t\tModule:      gm,\n\t\tBindingName: exportName,\n\t}, false\n}\n\ntype goModuleInstance struct {\n\tmi            Instance\n\trt            *sobek.Runtime\n\tdefaultExport sobek.Value\n}\n\nfunc (gmi *goModuleInstance) ExecuteModule(_ *sobek.Runtime, _, _ func(any) error) (sobek.CyclicModuleInstance, error) {\n\treturn gmi, nil\n}\nfunc (gmi *goModuleInstance) HasTLA() bool { return false }\n\nfunc (gmi *goModuleInstance) GetBindingValue(name string) (v sobek.Value) {\n\tif name == jsDefaultExportIdentifier {\n\t\treturn gmi.getDefaultExport()\n\t}\n\n\texports := gmi.mi.Exports()\n\tif exports.Named != nil {\n\t\treturn gmi.rt.ToValue(exports.Named[name])\n\t}\n\treturn gmi.getDefaultExport().ToObject(gmi.rt).Get(name)\n}\n\nfunc (gmi *goModuleInstance) getDefaultExport() sobek.Value {\n\tif gmi.defaultExport != nil {\n\t\treturn gmi.defaultExport\n\t}\n\n\texports := gmi.mi.Exports()\n\tif exports.Default != nil {\n\t\tgmi.defaultExport = gmi.rt.ToValue(exports.Default)\n\t\treturn gmi.defaultExport\n\t}\n\n\t// if there are only named exports we make a default object out of them\n\t// this allows scripts to modify this acting similar to how it would act\n\t// if the default export was an object to begin with.\n\to := gmi.rt.NewObject()\n\tgmi.defaultExport = o\n\tfor name, value := range exports.Named {\n\t\t_ = o.Set(name, value)\n\t}\n\n\treturn gmi.defaultExport\n}\n"
  },
  {
    "path": "js/modules/gomodule_basic.go",
    "content": "package modules\n\nimport (\n\t\"github.com/grafana/sobek\"\n)\n\n// This sobek.ModuleRecord wrapper for go/js module which does not conform to modules.Module interface\ntype basicGoModule struct {\n\tm                      any\n\texportedNames          []string\n\texportedNamesCallbacks []func([]string)\n}\n\nfunc (bgm *basicGoModule) Link() error { return nil }\n\nfunc (bgm *basicGoModule) Evaluate(_ *sobek.Runtime) *sobek.Promise {\n\tpanic(\"this shouldn't be called\")\n}\n\nfunc (bgm *basicGoModule) InitializeEnvironment() error { return nil }\n\nfunc (bgm *basicGoModule) Instantiate(rt *sobek.Runtime) (sobek.CyclicModuleInstance, error) {\n\to := rt.ToValue(bgm.m).ToObject(rt)\n\n\t// this will be called multiple times we only need to update this on the first VU\n\tif bgm.exportedNames == nil {\n\t\tbgm.exportedNames = o.Keys()\n\t\tfor _, callback := range bgm.exportedNamesCallbacks {\n\t\t\tcallback(bgm.exportedNames)\n\t\t}\n\t}\n\treturn &basicGoModuleInstance{\n\t\tv:      o,\n\t\tmodule: bgm,\n\t}, nil\n}\n\nfunc (bgm *basicGoModule) RequestedModules() []string { return nil }\n\nfunc (bgm *basicGoModule) ResolveExport(name string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) {\n\treturn &sobek.ResolvedBinding{\n\t\tModule:      bgm,\n\t\tBindingName: name,\n\t}, false\n}\n\nfunc (bgm *basicGoModule) GetExportedNames(callback func([]string), _ ...sobek.ModuleRecord) bool {\n\tif bgm.exportedNames != nil {\n\t\tcallback(bgm.exportedNames)\n\t\treturn true\n\t}\n\tbgm.exportedNamesCallbacks = append(bgm.exportedNamesCallbacks, callback)\n\treturn false\n}\n\ntype basicGoModuleInstance struct {\n\tv      *sobek.Object\n\tmodule *basicGoModule\n}\n\nfunc (bgmi *basicGoModuleInstance) GetBindingValue(n string) sobek.Value {\n\tif n == jsDefaultExportIdentifier {\n\t\treturn bgmi.v\n\t}\n\treturn bgmi.v.Get(n)\n}\n\nfunc (bgmi *basicGoModuleInstance) HasTLA() bool { return false }\n\nfunc (bgmi *basicGoModuleInstance) ExecuteModule(\n\t_ *sobek.Runtime, _, _ func(any) error,\n) (sobek.CyclicModuleInstance, error) {\n\treturn bgmi, nil\n}\n"
  },
  {
    "path": "js/modules/k6/html/element.go",
    "content": "package html\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/PuerkitoBio/goquery\"\n\t\"github.com/grafana/sobek\"\n\tgohtml \"golang.org/x/net/html\"\n)\n\nconst (\n\tElementNode  = 1\n\tTextNode     = 3\n\tCommentNode  = 8\n\tDocumentNode = 9\n\tDoctypeNode  = 10\n)\n\ntype Element struct {\n\tnode *gohtml.Node\n\tsel  *Selection\n}\n\ntype Attribute struct {\n\tOwnerElement *Element `json:\"owner_element\"`\n\tName         string   `json:\"name\"`\n\tnsPrefix     string\n\tValue        string `json:\"value\"`\n}\n\nfunc (e Element) attrAsString(name string) string {\n\tval, exists := e.sel.sel.Attr(name)\n\tif !exists {\n\t\treturn \"\"\n\t}\n\treturn val\n}\n\nfunc (e Element) resolveURL(val string) (*url.URL, bool) {\n\tbaseURL, err := url.Parse(e.sel.URL)\n\tif err != nil {\n\t\treturn nil, false\n\t}\n\n\taddURL, err := url.Parse(val)\n\tif err != nil {\n\t\treturn nil, false\n\t}\n\n\treturn baseURL.ResolveReference(addURL), true\n}\n\nfunc (e Element) attrAsURL(name string) (*url.URL, bool) {\n\tval, exists := e.sel.sel.Attr(name)\n\tif !exists {\n\t\treturn nil, false\n\t}\n\n\treturn e.resolveURL(val)\n}\n\nfunc (e Element) attrAsURLString(name string, defaultWhenNoAttr string) string {\n\tif e.sel.URL == \"\" {\n\t\treturn e.attrAsString(name)\n\t}\n\n\turl, ok := e.attrAsURL(name)\n\tif !ok {\n\t\treturn defaultWhenNoAttr\n\t}\n\n\treturn url.String()\n}\n\nfunc (e Element) attrAsInt(name string, defaultVal int) int {\n\tstrVal, exists := e.sel.sel.Attr(name)\n\tif !exists {\n\t\treturn defaultVal\n\t}\n\n\tintVal, err := strconv.Atoi(strVal)\n\tif err != nil {\n\t\treturn defaultVal\n\t}\n\n\treturn intVal\n}\n\nfunc (e Element) attrIsPresent(name string) bool {\n\t_, exists := e.sel.sel.Attr(name)\n\treturn exists\n}\n\nfunc (e Element) ownerFormSel() (*goquery.Selection, bool) {\n\tprtForm := e.sel.sel.Closest(\"form\")\n\tif prtForm.Length() > 0 {\n\t\treturn prtForm, true\n\t}\n\n\tformID := e.attrAsString(\"form\")\n\tif formID == \"\" {\n\t\treturn nil, false\n\t}\n\n\tfindForm := e.sel.sel.Parents().Last().Find(\"#\" + formID)\n\tif findForm.Length() == 0 {\n\t\treturn nil, false\n\t}\n\n\treturn findForm, true\n}\n\nfunc (e Element) ownerFormVal() sobek.Value {\n\tformSel, exists := e.ownerFormSel()\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\treturn selToElement(Selection{e.sel.rt, formSel.Eq(0), e.sel.URL})\n}\n\nfunc (e Element) elemLabels() []sobek.Value {\n\twrapperLbl := e.sel.sel.Closest(\"label\")\n\n\tid := e.attrAsString(\"id\")\n\tif id == \"\" {\n\t\treturn elemList(Selection{e.sel.rt, wrapperLbl, e.sel.URL})\n\t}\n\n\tidLbl := e.sel.sel.Parents().Last().Find(\"label[for=\\\"\" + id + \"\\\"]\")\n\tif idLbl.Size() == 0 {\n\t\treturn elemList(Selection{e.sel.rt, wrapperLbl, e.sel.URL})\n\t}\n\n\tallLbls := wrapperLbl.AddSelection(idLbl)\n\n\treturn elemList(Selection{e.sel.rt, allLbls, e.sel.URL})\n}\n\nfunc (e Element) splitAttr(attrName string) []string {\n\tattr := e.attrAsString(attrName)\n\n\tif attr == \"\" {\n\t\treturn make([]string, 0)\n\t}\n\n\treturn strings.Split(attr, \" \")\n}\n\nfunc (e Element) idOrNameAttr() (string, bool) {\n\tif id, exists := e.sel.sel.Attr(\"id\"); exists {\n\t\treturn id, true\n\t}\n\n\tif name, exists := e.sel.sel.Attr(\"id\"); exists {\n\t\treturn name, true\n\t}\n\n\treturn \"\", false\n}\n\nfunc (a Attribute) Prefix() string {\n\treturn a.nsPrefix\n}\n\nfunc (a Attribute) NamespaceURI() string {\n\treturn namespaceURI(a.nsPrefix)\n}\n\nfunc (a Attribute) LocalName() string {\n\treturn a.Name\n}\n\nfunc (e Element) GetAttribute(name string) sobek.Value {\n\treturn e.sel.Attr(name)\n}\n\nfunc (e Element) GetAttributeNode(name string) sobek.Value {\n\tif attr := getHTMLAttr(e.node, name); attr != nil {\n\t\treturn e.sel.rt.ToValue(Attribute{&e, attr.Key, attr.Namespace, attr.Val})\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) HasAttribute(name string) bool {\n\t_, exists := e.sel.sel.Attr(name)\n\treturn exists\n}\n\nfunc (e Element) HasAttributes() bool {\n\treturn e.sel.sel.Length() > 0 && len(e.node.Attr) > 0\n}\n\nfunc (e Element) Attributes() map[string]Attribute {\n\tattrs := make(map[string]Attribute)\n\tfor i := 0; i < len(e.node.Attr); i++ {\n\t\tattr := e.node.Attr[i]\n\t\tattrs[attr.Key] = Attribute{&e, attr.Key, attr.Namespace, attr.Val}\n\t}\n\treturn attrs\n}\n\nfunc (e Element) ToString() sobek.Value {\n\tif e.sel.sel.Length() == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\tif e.node.Type == gohtml.ElementNode {\n\t\treturn e.sel.rt.ToValue(\"[object html.Node]\")\n\t}\n\n\treturn e.sel.rt.ToValue(fmt.Sprintf(\"[object %s]\", e.NodeName()))\n}\n\nfunc (e Element) HasChildNodes() bool {\n\treturn e.sel.sel.Length() > 0 && e.node.FirstChild != nil\n}\n\nfunc (e Element) TextContent() string {\n\treturn e.sel.sel.Text()\n}\n\n//nolint:revive // var-naming wants this to be ID but this will break the API\nfunc (e Element) Id() string {\n\treturn e.attrAsString(\"id\")\n}\n\nfunc (e Element) IsEqualNode(v sobek.Value) bool {\n\tif other, ok := v.Export().(Element); ok {\n\t\thtmlA, errA := e.sel.sel.Html()\n\t\thtmlB, errB := other.sel.sel.Html()\n\n\t\treturn errA == nil && errB == nil && htmlA == htmlB\n\t}\n\n\treturn false\n}\n\nfunc (e Element) IsSameNode(v sobek.Value) bool {\n\tif other, ok := v.Export().(Element); ok {\n\t\treturn e.node == other.node\n\t}\n\n\treturn false\n}\n\n// Selection returns a Selection object based on the current Element.\n//\n// This function is used to create a Selection object that represents the same HTML\n// content as the Element. It is useful for performing operations or manipulations\n// on the HTML content within the scope of this Element.\n//\n// Example:\n// sel := element.Selection()\nfunc (e Element) Selection() Selection {\n\treturn *e.sel\n}\n\nfunc (e Element) GetElementsByClassName(name string) []sobek.Value {\n\treturn elemList(Selection{e.sel.rt, e.sel.sel.Find(\".\" + name), e.sel.URL})\n}\n\nfunc (e Element) GetElementsByTagName(name string) []sobek.Value {\n\treturn elemList(Selection{e.sel.rt, e.sel.sel.Find(name), e.sel.URL})\n}\n\nfunc (e Element) QuerySelector(selector string) sobek.Value {\n\treturn selToElement(Selection{e.sel.rt, e.sel.sel.Find(selector), e.sel.URL})\n}\n\nfunc (e Element) QuerySelectorAll(selector string) []sobek.Value {\n\treturn elemList(Selection{e.sel.rt, e.sel.sel.Find(selector), e.sel.URL})\n}\n\nfunc (e Element) NodeName() string {\n\treturn goquery.NodeName(e.sel.sel)\n}\n\nfunc (e Element) FirstChild() sobek.Value {\n\treturn nodeToElement(e, e.node.FirstChild)\n}\n\nfunc (e Element) LastChild() sobek.Value {\n\treturn nodeToElement(e, e.node.LastChild)\n}\n\nfunc (e Element) FirstElementChild() sobek.Value {\n\tif child := e.sel.sel.Children().First(); child.Length() > 0 {\n\t\treturn selToElement(Selection{e.sel.rt, child.First(), e.sel.URL})\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) LastElementChild() sobek.Value {\n\tif child := e.sel.sel.Children(); child.Length() > 0 {\n\t\treturn selToElement(Selection{e.sel.rt, child.Last(), e.sel.URL})\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) PreviousSibling() sobek.Value {\n\treturn nodeToElement(e, e.node.PrevSibling)\n}\n\nfunc (e Element) NextSibling() sobek.Value {\n\treturn nodeToElement(e, e.node.NextSibling)\n}\n\nfunc (e Element) PreviousElementSibling() sobek.Value {\n\tif prev := e.sel.sel.Prev(); prev.Length() > 0 {\n\t\treturn selToElement(Selection{e.sel.rt, prev, e.sel.URL})\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) NextElementSibling() sobek.Value {\n\tif next := e.sel.sel.Next(); next.Length() > 0 {\n\t\treturn selToElement(Selection{e.sel.rt, next, e.sel.URL})\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) ParentNode() sobek.Value {\n\tif e.node.Parent != nil {\n\t\treturn nodeToElement(e, e.node.Parent)\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) ParentElement() sobek.Value {\n\tif prt := e.sel.sel.Parent(); prt.Length() > 0 {\n\t\treturn selToElement(Selection{e.sel.rt, prt, e.sel.URL})\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) ChildNodes() []sobek.Value {\n\treturn elemList(e.sel.Contents())\n}\n\nfunc (e Element) Children() []sobek.Value {\n\treturn elemList(e.sel.Children())\n}\n\nfunc (e Element) ChildElementCount() int {\n\treturn e.sel.Children().Size()\n}\n\nfunc (e Element) ClassList() []string {\n\tif clsName, exists := e.sel.sel.Attr(\"class\"); exists {\n\t\treturn strings.Fields(clsName)\n\t}\n\n\treturn nil\n}\n\nfunc (e Element) ClassName() sobek.Value {\n\treturn e.sel.Attr(\"class\")\n}\n\nfunc (e Element) Lang() sobek.Value {\n\tif attr := getHTMLAttr(e.node, \"lang\"); attr != nil && attr.Namespace == \"\" {\n\t\treturn e.sel.rt.ToValue(attr.Val)\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) OwnerDocument() sobek.Value {\n\tif node := getOwnerDocNode(e.node); node != nil {\n\t\treturn nodeToElement(e, node)\n\t}\n\n\treturn sobek.Undefined()\n}\n\nfunc (e Element) NamespaceURI() string {\n\treturn namespaceURI(e.node.Namespace)\n}\n\nfunc (e Element) IsDefaultNamespace() bool {\n\treturn e.node.Namespace == \"\"\n}\n\nfunc getOwnerDocNode(node *gohtml.Node) *gohtml.Node {\n\tfor ; node != nil; node = node.Parent {\n\t\tif node.Type == gohtml.DocumentNode {\n\t\t\treturn node\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (e Element) InnerHTML() sobek.Value {\n\treturn e.sel.Html()\n}\n\nfunc (e Element) NodeType() sobek.Value {\n\tswitch e.node.Type {\n\tcase gohtml.TextNode:\n\t\treturn e.sel.rt.ToValue(TextNode)\n\n\tcase gohtml.DocumentNode:\n\t\treturn e.sel.rt.ToValue(DocumentNode)\n\n\tcase gohtml.ElementNode:\n\t\treturn e.sel.rt.ToValue(ElementNode)\n\n\tcase gohtml.CommentNode:\n\t\treturn e.sel.rt.ToValue(CommentNode)\n\n\tcase gohtml.DoctypeNode:\n\t\treturn e.sel.rt.ToValue(DoctypeNode)\n\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n}\n\nfunc (e Element) NodeValue() sobek.Value {\n\tswitch e.node.Type {\n\tcase gohtml.TextNode:\n\t\treturn e.sel.rt.ToValue(e.sel.Text())\n\n\tcase gohtml.CommentNode:\n\t\treturn e.sel.rt.ToValue(e.sel.Text())\n\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n}\n\nfunc (e Element) Contains(v sobek.Value) bool {\n\tif other, ok := v.Export().(Element); ok {\n\t\t// When testing if a node contains itself, jquery's + goquery's version of Contains()\n\t\t// return true while the DOM API returns false.\n\t\treturn other.node != e.node && e.sel.sel.Contains(other.node)\n\t}\n\n\treturn false\n}\n\nfunc (e Element) Matches(selector string) bool {\n\treturn e.sel.sel.Is(selector)\n}\n"
  },
  {
    "path": "js/modules/k6/html/element_test.go",
    "content": "package html\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst testHTMLElem = `\n<html>\n<head>\n\t<title>This is the title</title>\n</head>\n<body>\n\t<h1 id=\"top\">Lorem ipsum</h1>\n\t<empty></empty>\n\t<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>\n\t<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>\n\tpretext\n\t<div id=\"div_elem\" class=\"class1 class2\" lang=\"en\">\n\t\tinnerfirst\n\t\t<h2 id=\"h2_elem\" class=\"class2\">Nullam id nisi eget ex pharetra imperdiet.</h2>\n\t\t<span id=\"span1\"><b>test content</b></span>\n\t\t<svg id=\"svg_elem\"></svg>\n\t\t<span id=\"span2\">Maecenas augue ligula, aliquet sit amet maximus ut, vestibulum et magna</span>\n\t\tinnerlast\n\t</div>\n\taftertext\n\t<footer>This is the footer.</footer>\n</body>\n`\n\nfunc TestElement(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"NodeName\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"#top\").get(0).nodeName()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"h1\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"NodeType\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"#top\").get(0).nodeType()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"1\", v.String())\n\t\t}\n\t})\n\tt.Run(\"NodeValue\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"#top\").get(0).firstChild().nodeValue()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"Lorem ipsum\", v.String())\n\t\t}\n\t})\n\tt.Run(\"InnerHtml\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"span\").get(0).innerHTML()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"<b>test content</b>\", v.String())\n\t\t}\n\t})\n\tt.Run(\"TextContent\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"b\").get(0).textContent()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"test content\", v.String())\n\t\t}\n\t})\n\tt.Run(\"OwnerDocument\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").get(0).ownerDocument().nodeName()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"#document\", v.String())\n\t\t}\n\t})\n\tt.Run(\"Attributes\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).attributes()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tattrs, ok := v.Export().(map[string]Attribute)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, \"div_elem\", attrs[\"id\"].Value)\n\t\t}\n\t})\n\tt.Run(\"FirstChild\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).firstChild().nodeValue()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"innerfirst\")\n\t\t}\n\t})\n\tt.Run(\"LastChild\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).lastChild().nodeValue()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"innerlast\")\n\t\t}\n\t})\n\tt.Run(\"ChildElementCount\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").get(0).childElementCount()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, int64(6), v.Export())\n\t\t}\n\t})\n\tt.Run(\"FirstElementChild\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).firstElementChild().textContent()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"Nullam id nisi \")\n\t\t}\n\t})\n\tt.Run(\"LastElementChild\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).lastElementChild().textContent()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"Maecenas augue ligula\")\n\t\t}\n\t})\n\tt.Run(\"PreviousSibling\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).previousSibling().textContent()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"pretext\")\n\t\t}\n\t})\n\tt.Run(\"NextSibling\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).nextSibling().textContent()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"aftertext\")\n\t\t}\n\t})\n\tt.Run(\"PreviousElementSibling\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).previousElementSibling().textContent()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"consectetur adipiscing elit\")\n\t\t}\n\t})\n\tt.Run(\"NextElementSibling\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).nextElementSibling().textContent()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Contains(t, v.Export(), \"This is the footer.\")\n\t\t}\n\t})\n\tt.Run(\"ParentElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).parentElement().nodeName()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"body\", v.String())\n\t\t}\n\t})\n\tt.Run(\"ParentNode\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tnodeVal, err1 := rt.RunString(`doc.find(\"html\").get(0).parentNode().nodeName()`)\n\t\tnilVal, err2 := rt.RunString(`doc.find(\"html\").get(0).parentElement()`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, \"#document\", nodeVal.String())\n\t\t\tassert.Equal(t, nil, nilVal.Export())\n\t\t}\n\t})\n\tt.Run(\"ChildNodes\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).childNodes()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tnodes, ok := v.Export().([]sobek.Value)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, 9, len(nodes))\n\t\t\tassert.Contains(t, nodes[0].Export().(Element).TextContent(), \"innerfirst\")\n\t\t\tassert.Contains(t, nodes[8].Export().(Element).TextContent(), \"innerlast\")\n\t\t}\n\t})\n\tt.Run(\"Children\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).children()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tnodes, ok := v.Export().([]sobek.Value)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, 4, len(nodes))\n\t\t\tassert.Contains(t, nodes[0].Export().(Element).TextContent(), \"Nullam id nisi eget ex\")\n\t\t\tassert.Contains(t, nodes[3].Export().(Element).TextContent(), \"Maecenas augue ligula\")\n\t\t}\n\t})\n\tt.Run(\"Selection\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find('div').get(0).selection().find('h2').text()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"Nullam id nisi eget ex pharetra imperdiet.\", v.String())\n\t\t}\n\t})\n\tt.Run(\"ClassList\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).classList()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tclsNames, ok := v.Export().([]string)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, 2, len(clsNames))\n\t\t\tassert.Equal(t, []string{\"class1\", \"class2\"}, clsNames)\n\t\t}\n\t})\n\tt.Run(\"ClassName\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).className()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"class1 class2\", v.String())\n\t\t}\n\t})\n\tt.Run(\"Lang\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).lang()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"en\", v.String())\n\t\t}\n\t})\n\tt.Run(\"ToString\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"div\").get(0).toString()`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"div\").get(0).previousSibling().toString()`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, \"[object html.Node]\", v1.String())\n\t\t\tassert.Equal(t, \"[object #text]\", v2.String())\n\t\t}\n\t})\n\tt.Run(\"HasAttribute\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"div\").get(0).hasAttribute(\"id\")`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"div\").get(0).hasAttribute(\"noattr\")`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, true, v1.Export())\n\t\t\tassert.Equal(t, false, v2.Export())\n\t\t}\n\t})\n\tt.Run(\"GetAttribute\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).getAttribute(\"id\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"div_elem\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"GetAttributeNode\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).getAttributeNode(\"id\")`)\n\t\tif assert.NoError(t, err) && assert.IsType(t, Attribute{}, v.Export()) {\n\t\t\tassert.Equal(t, \"div_elem\", v.Export().(Attribute).Value)\n\t\t}\n\t})\n\tt.Run(\"HasAttributes\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"h1\").get(0).hasAttributes()`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"footer\").get(0).hasAttributes()`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, true, v1.Export())\n\t\t\tassert.Equal(t, false, v2.Export())\n\t\t}\n\t})\n\tt.Run(\"HasChildNodes\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"p\").get(0).hasChildNodes()`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"empty\").get(0).hasChildNodes()`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, true, v1.Export())\n\t\t\tassert.Equal(t, false, v2.Export())\n\t\t}\n\t})\n\tt.Run(\"IsSameNode\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"p\").get(0).isSameNode(doc.find(\"p\").get(1))`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"p\").get(0).isSameNode(doc.find(\"p\").get(0))`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, false, v1.Export())\n\t\t\tassert.Equal(t, true, v2.Export())\n\t\t}\n\t})\n\tt.Run(\"IsEqualNode\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"p\").get(0).isEqualNode(doc.find(\"p\").get(1))`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"p\").get(0).isEqualNode(doc.find(\"p\").get(0))`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, true, v1.Export())\n\t\t\tassert.Equal(t, true, v2.Export())\n\t\t}\n\t})\n\tt.Run(\"GetElementsByClassName\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").get(0).getElementsByClassName(\"class2\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\telems, ok := v.Export().([]sobek.Value)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, \"div_elem\", elems[0].Export().(Element).Id())\n\t\t\tassert.Equal(t, \"h2_elem\", elems[1].Export().(Element).Id())\n\t\t}\n\t})\n\tt.Run(\"GetElementsByTagName\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").get(0).getElementsByTagName(\"span\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\telems, ok := v.Export().([]sobek.Value)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, 2, len(elems))\n\t\t}\n\t})\n\tt.Run(\"QuerySelector\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").get(0).querySelector(\"#div_elem\").id()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"div_elem\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"QuerySelectorAll\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").get(0).querySelectorAll(\"span\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\telems, ok := v.Export().([]sobek.Value)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Len(t, elems, 2)\n\t\t\tassert.Equal(t, \"span1\", elems[0].Export().(Element).Id())\n\t\t\tassert.Equal(t, \"span2\", elems[1].Export().(Element).Id())\n\t\t}\n\t})\n\tt.Run(\"Contains\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"html\").get(0).contains(doc.find(\"body\").get(0))`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"body\").get(0).contains(doc.find(\"body\").get(0))`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, true, v1.Export())\n\t\t\tassert.Equal(t, false, v2.Export())\n\t\t}\n\t})\n\tt.Run(\"Matches\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"div\").get(0).matches(\"#div_elem\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, true, v.Export())\n\t\t}\n\t})\n\tt.Run(\"NamespaceURI\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv, err := rt.RunString(`doc.find(\"#svg_elem\").get(0).namespaceURI()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"http://www.w3.org/2000/svg\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"IsDefaultNamespace\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElem)\n\n\t\tv1, err1 := rt.RunString(`doc.find(\"#svg_elem\").get(0).isDefaultNamespace()`)\n\t\tv2, err2 := rt.RunString(`doc.find(\"#div_elem\").get(0).isDefaultNamespace()`)\n\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\tassert.Equal(t, false, v1.ToBoolean())\n\t\t\tassert.Equal(t, true, v2.ToBoolean())\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "js/modules/k6/html/elements.go",
    "content": "package html\n\nimport (\n\t\"net\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n//go:generate go run gen/gen_elements.go\n//go:generate gofumpt -w .\n\n//nolint:gochecknoglobals\nvar defaultPorts = map[string]string{\n\t\"http\":  \"80\",\n\t\"https\": \"443\",\n\t\"ftp\":   \"21\",\n}\n\n// The code generator depends on the TagName constants being defined before the Element structs\nconst (\n\tAnchorTagName          = \"a\"\n\tAreaTagName            = \"area\"\n\tAudioTagName           = \"audio\"\n\tBaseTagName            = \"base\"\n\tButtonTagName          = \"button\"\n\tCanvasTagName          = \"canvas\"\n\tDataTagName            = \"data\"\n\tDataListTagName        = \"datalist\"\n\tDelTagName             = \"del\"\n\tEmbedTagName           = \"embed\"\n\tFieldSetTagName        = \"fieldset\"\n\tFormTagName            = \"form\"\n\tIFrameTagName          = \"iframe\"\n\tImageTagName           = \"img\"\n\tInputTagName           = \"input\"\n\tInsTagName             = \"ins\"\n\tKeygenTagName          = \"keygen\"\n\tLabelTagName           = \"label\"\n\tLegendTagName          = \"legend\"\n\tLiTagName              = \"li\"\n\tLinkTagName            = \"link\"\n\tMapTagName             = \"map\"\n\tMetaTagName            = \"meta\"\n\tMeterTagName           = \"meter\"\n\tObjectTagName          = \"object\"\n\tOListTagName           = \"ol\"\n\tOptGroupTagName        = \"optgroup\"\n\tOptionTagName          = \"option\"\n\tOutputTagName          = \"output\"\n\tParamTagName           = \"param\"\n\tPreTagName             = \"pre\"\n\tProgressTagName        = \"progress\"\n\tQuoteTagName           = \"quote\"\n\tScriptTagName          = \"script\"\n\tSelectTagName          = \"select\"\n\tSourceTagName          = \"source\"\n\tStyleTagName           = \"style\"\n\tTableTagName           = \"table\"\n\tTableHeadTagName       = \"thead\"\n\tTableFootTagName       = \"tfoot\"\n\tTableBodyTagName       = \"tbody\"\n\tTableRowTagName        = \"tr\"\n\tTableColTagName        = \"col\"\n\tTableDataCellTagName   = \"td\"\n\tTableHeaderCellTagName = \"th\"\n\tTextAreaTagName        = \"textarea\"\n\tTimeTagName            = \"time\"\n\tTitleTagName           = \"title\"\n\tTrackTagName           = \"track\"\n\tUListTagName           = \"ul\"\n\tVideoTagName           = \"video\"\n\n\tmethodPost = \"post\"\n\tmethodGet  = \"get\"\n)\n\n//revive:disable:exported\n\ntype (\n\tHrefElement            struct{ Element }\n\tMediaElement           struct{ Element }\n\tFormFieldElement       struct{ Element }\n\tModElement             struct{ Element }\n\tTableSectionElement    struct{ Element }\n\tTableCellElement       struct{ Element }\n\tAnchorElement          struct{ HrefElement }\n\tAreaElement            struct{ HrefElement }\n\tAudioElement           struct{ MediaElement }\n\tBaseElement            struct{ Element }\n\tButtonElement          struct{ FormFieldElement }\n\tCanvasElement          struct{ Element }\n\tDataElement            struct{ Element }\n\tDataListElement        struct{ Element }\n\tDelElement             struct{ ModElement }\n\tInsElement             struct{ ModElement }\n\tEmbedElement           struct{ Element }\n\tFieldSetElement        struct{ Element }\n\tFormElement            struct{ Element }\n\tIFrameElement          struct{ Element }\n\tImageElement           struct{ Element }\n\tInputElement           struct{ FormFieldElement }\n\tKeygenElement          struct{ Element }\n\tLabelElement           struct{ Element }\n\tLegendElement          struct{ Element }\n\tLiElement              struct{ Element }\n\tLinkElement            struct{ Element }\n\tMapElement             struct{ Element }\n\tMetaElement            struct{ Element }\n\tMeterElement           struct{ Element }\n\tObjectElement          struct{ Element }\n\tOListElement           struct{ Element }\n\tOptGroupElement        struct{ Element }\n\tOptionElement          struct{ Element }\n\tOutputElement          struct{ Element }\n\tParamElement           struct{ Element }\n\tPreElement             struct{ Element }\n\tProgressElement        struct{ Element }\n\tQuoteElement           struct{ Element }\n\tScriptElement          struct{ Element }\n\tSelectElement          struct{ Element }\n\tSourceElement          struct{ Element }\n\tStyleElement           struct{ Element }\n\tTableElement           struct{ Element }\n\tTableHeadElement       struct{ TableSectionElement }\n\tTableFootElement       struct{ TableSectionElement }\n\tTableBodyElement       struct{ TableSectionElement }\n\tTableRowElement        struct{ Element }\n\tTableColElement        struct{ Element }\n\tTableDataCellElement   struct{ TableCellElement }\n\tTableHeaderCellElement struct{ TableCellElement }\n\tTextAreaElement        struct{ Element }\n\tTimeElement            struct{ Element }\n\tTitleElement           struct{ Element }\n\tTrackElement           struct{ Element }\n\tUListElement           struct{ Element }\n\tVideoElement           struct{ MediaElement }\n)\n\nfunc (h HrefElement) hrefURL() *url.URL {\n\thref, exists := h.attrAsURL(\"href\")\n\tif !exists {\n\t\treturn &url.URL{}\n\t}\n\treturn href\n}\n\nfunc (h HrefElement) Hash() string {\n\tfrag := h.hrefURL().Fragment\n\tif frag == \"\" {\n\t\treturn \"\"\n\t}\n\treturn \"#\" + frag\n}\n\nfunc (h HrefElement) Host() string {\n\thref := h.hrefURL()\n\tif href.Host == \"\" {\n\t\treturn \"\"\n\t}\n\n\thost, port, err := net.SplitHostPort(href.Host)\n\tif err != nil {\n\t\treturn href.Host\n\t}\n\n\tdefaultPort := defaultPorts[href.Scheme]\n\tif defaultPort != \"\" && port == defaultPort {\n\t\treturn strings.TrimSuffix(host, \":\"+defaultPort)\n\t}\n\n\treturn href.Host\n}\n\nfunc (h HrefElement) Hostname() string {\n\thostAndPort := h.hrefURL().Host\n\tif hostAndPort == \"\" {\n\t\treturn \"\"\n\t}\n\n\thost, _, err := net.SplitHostPort(hostAndPort)\n\tif err != nil {\n\t\treturn hostAndPort\n\t}\n\n\treturn host\n}\n\nfunc (h HrefElement) Port() string {\n\thostAndPort := h.hrefURL().Host\n\tif hostAndPort == \"\" {\n\t\treturn \"\"\n\t}\n\n\t_, port, err := net.SplitHostPort(hostAndPort)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn port\n}\n\nfunc (h HrefElement) Username() string {\n\tuser := h.hrefURL().User\n\tif user == nil {\n\t\treturn \"\"\n\t}\n\treturn user.Username()\n}\n\nfunc (h HrefElement) Password() string {\n\tuser := h.hrefURL().User\n\tif user == nil {\n\t\treturn \"\"\n\t}\n\n\tpwd, defined := user.Password()\n\tif !defined {\n\t\treturn \"\"\n\t}\n\n\treturn pwd\n}\n\nfunc (h HrefElement) Origin() string {\n\thref := h.hrefURL()\n\n\tif href.Scheme == \"\" {\n\t\treturn \"\"\n\t}\n\n\tif href.Scheme == \"file\" {\n\t\treturn h.Href()\n\t}\n\n\treturn href.Scheme + \"://\" + href.Host\n}\n\nfunc (h HrefElement) Pathname() string {\n\treturn h.hrefURL().Path\n}\n\nfunc (h HrefElement) Protocol() string {\n\tscheme := h.hrefURL().Scheme\n\tif scheme == \"\" {\n\t\treturn \":\"\n\t}\n\treturn scheme\n}\n\nfunc (h HrefElement) RelList() []string {\n\treturn h.splitAttr(\"rel\")\n}\n\nfunc (h HrefElement) Search() string {\n\tq := h.hrefURL().RawQuery\n\tif q == \"\" {\n\t\treturn q\n\t}\n\treturn \"?\" + q\n}\n\nfunc (h HrefElement) Text() string {\n\treturn h.TextContent()\n}\n\nfunc (f FormFieldElement) Form() sobek.Value {\n\treturn f.ownerFormVal()\n}\n\nfunc (f FormFieldElement) formOrElemAttr(attrName string) (string, bool) {\n\tif elemAttr, exists := f.sel.sel.Attr(\"form\" + attrName); exists {\n\t\treturn elemAttr, true\n\t}\n\n\tformSel, exists := f.ownerFormSel()\n\tif !exists {\n\t\treturn \"\", false\n\t}\n\n\tformAttr, exists := formSel.Attr(attrName)\n\tif !exists {\n\t\treturn \"\", false\n\t}\n\n\treturn formAttr, true\n}\n\nfunc (f FormFieldElement) FormAction() string {\n\taction, exists := f.formOrElemAttr(\"action\")\n\tif f.sel.URL == \"\" {\n\t\treturn action\n\t}\n\n\tif !exists || action == \"\" {\n\t\treturn f.sel.URL\n\t}\n\n\tactionURL, ok := f.resolveURL(action)\n\tif !ok {\n\t\treturn action\n\t}\n\n\treturn actionURL.String()\n}\n\nfunc (f FormFieldElement) FormEnctype() string {\n\tenctype, _ := f.formOrElemAttr(\"enctype\")\n\n\tswitch enctype {\n\tcase \"multipart/form-data\":\n\t\treturn enctype\n\tcase \"text/plain\":\n\t\treturn enctype\n\tdefault:\n\t\treturn \"application/x-www-form-urlencoded\"\n\t}\n}\n\nfunc (f FormFieldElement) FormMethod() string {\n\tmethod, _ := f.formOrElemAttr(\"method\")\n\n\tswitch strings.ToLower(method) {\n\tcase methodPost:\n\t\treturn methodPost\n\tdefault:\n\t\treturn methodGet\n\t}\n}\n\nfunc (f FormFieldElement) FormNoValidate() bool {\n\t_, exists := f.formOrElemAttr(\"novalidate\")\n\treturn exists\n}\n\nfunc (f FormFieldElement) FormTarget() string {\n\ttarget, _ := f.formOrElemAttr(\"target\")\n\treturn target\n}\n\nfunc (f FormFieldElement) Labels() []sobek.Value {\n\treturn f.elemLabels()\n}\n\nfunc (f FormFieldElement) Name() string {\n\treturn f.attrAsString(\"name\")\n}\n\nfunc (b ButtonElement) Value() string {\n\treturn valueOrHTML(b.sel.sel)\n}\n\nfunc (c CanvasElement) Width() int {\n\treturn c.attrAsInt(\"width\", 150)\n}\n\nfunc (c CanvasElement) Height() int {\n\treturn c.attrAsInt(\"height\", 150)\n}\n\nfunc (d DataListElement) Options() []sobek.Value {\n\treturn elemList(d.sel.Find(\"option\"))\n}\n\nfunc (f FieldSetElement) Form() sobek.Value {\n\tformSel, exists := f.ownerFormSel()\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\treturn selToElement(Selection{f.sel.rt, formSel, f.sel.URL})\n}\n\nfunc (f FieldSetElement) Type() string {\n\treturn \"fieldset\"\n}\n\nfunc (f FieldSetElement) Elements() []sobek.Value {\n\treturn elemList(f.sel.Find(\"input,select,button,textarea\"))\n}\n\nfunc (f FieldSetElement) Validity() sobek.Value {\n\treturn sobek.Undefined()\n}\n\nfunc (f FormElement) Elements() []sobek.Value {\n\treturn elemList(f.sel.Find(\"input,select,button,textarea,fieldset\"))\n}\n\nfunc (f FormElement) Length() int {\n\treturn f.sel.sel.Find(\"input,select,button,textarea,fieldset\").Size()\n}\n\nfunc (f FormElement) Method() string {\n\tif method := f.attrAsString(\"method\"); method == methodPost {\n\t\treturn methodPost\n\t}\n\n\treturn methodGet\n}\n\nfunc (i InputElement) List() sobek.Value {\n\tlistID := i.attrAsString(\"list\")\n\n\tif listID == \"\" {\n\t\treturn sobek.Undefined()\n\t}\n\n\tswitch i.attrAsString(\"type\") {\n\tcase \"hidden\":\n\t\treturn sobek.Undefined()\n\tcase \"checkbox\":\n\t\treturn sobek.Undefined()\n\tcase \"radio\":\n\t\treturn sobek.Undefined()\n\tcase \"file\":\n\t\treturn sobek.Undefined()\n\tcase \"button\":\n\t\treturn sobek.Undefined()\n\t}\n\n\tdatalist := i.sel.sel.Parents().Last().Find(\"datalist[id=\\\"\" + listID + \"\\\"]\")\n\tif datalist.Length() == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\treturn selToElement(Selection{i.sel.rt, datalist.Eq(0), i.sel.URL})\n}\n\nfunc (k KeygenElement) Form() sobek.Value {\n\treturn k.ownerFormVal()\n}\n\nfunc (k KeygenElement) Labels() []sobek.Value {\n\treturn k.elemLabels()\n}\n\nfunc (l LabelElement) Control() sobek.Value {\n\tforAttr, exists := l.sel.sel.Attr(\"for\")\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\n\tfindControl := l.sel.sel.Parents().Last().Find(\"#\" + forAttr)\n\tif findControl.Length() == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\treturn selToElement(Selection{l.sel.rt, findControl.Eq(0), l.sel.URL})\n}\n\nfunc (l LabelElement) Form() sobek.Value {\n\treturn l.ownerFormVal()\n}\n\nfunc (l LegendElement) Form() sobek.Value {\n\treturn l.ownerFormVal()\n}\n\nfunc (l LinkElement) RelList() []string {\n\treturn l.splitAttr(\"rel\")\n}\n\nfunc (m MapElement) Areas() []sobek.Value {\n\treturn elemList(m.sel.Find(\"area\"))\n}\n\nfunc (m MapElement) Images() []sobek.Value {\n\tname, exists := m.idOrNameAttr()\n\n\tif !exists {\n\t\treturn make([]sobek.Value, 0)\n\t}\n\n\timgs := m.sel.sel.Parents().Last().Find(\"img[usemap=\\\"#\" + name + \"\\\"],object[usemap=\\\"#\" + name + \"\\\"]\")\n\treturn elemList(Selection{m.sel.rt, imgs, m.sel.URL})\n}\n\nfunc (m MeterElement) Labels() []sobek.Value {\n\treturn m.elemLabels()\n}\n\nfunc (o ObjectElement) Form() sobek.Value {\n\treturn o.ownerFormVal()\n}\n\nfunc (o OptionElement) Disabled() bool {\n\tif o.attrIsPresent(\"disabled\") {\n\t\treturn true\n\t}\n\n\toptGroup := o.sel.sel.ParentsFiltered(\"optgroup\")\n\tif optGroup.Length() == 0 {\n\t\treturn false\n\t}\n\n\t_, exists := optGroup.Attr(\"disabled\")\n\treturn exists\n}\n\nfunc (o OptionElement) Form() sobek.Value {\n\tprtForm := o.sel.sel.ParentsFiltered(\"form\")\n\tif prtForm.Length() != 0 {\n\t\treturn selToElement(Selection{o.sel.rt, prtForm.First(), o.sel.URL})\n\t}\n\n\tprtSelect := o.sel.sel.ParentsFiltered(\"select\")\n\tformID, exists := prtSelect.Attr(\"form\")\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\n\townerForm := prtSelect.Parents().Last().Find(\"form#\" + formID)\n\tif ownerForm.Length() == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\treturn selToElement(Selection{o.sel.rt, ownerForm.First(), o.sel.URL})\n}\n\nfunc (o OptionElement) Index() int {\n\toptsHolder := o.sel.sel.ParentsFiltered(\"select,datalist\")\n\tif optsHolder.Length() == 0 {\n\t\treturn 0\n\t}\n\n\treturn optsHolder.Find(\"option\").IndexOfSelection(o.sel.sel)\n}\n\nfunc (o OptionElement) Label() string {\n\tif lbl, exists := o.sel.sel.Attr(\"label\"); exists {\n\t\treturn lbl\n\t}\n\n\treturn o.TextContent()\n}\n\nfunc (o OptionElement) Text() string {\n\treturn o.TextContent()\n}\n\nfunc (o OptionElement) Value() string {\n\treturn valueOrHTML(o.sel.sel)\n}\n\nfunc (o OutputElement) Form() sobek.Value {\n\treturn o.ownerFormVal()\n}\n\nfunc (o OutputElement) Labels() []sobek.Value {\n\treturn o.elemLabels()\n}\n\nfunc (o OutputElement) Value() string {\n\treturn o.TextContent()\n}\n\nfunc (o OutputElement) DefaultValue() string {\n\treturn o.TextContent()\n}\n\nfunc (p ProgressElement) Max() float64 {\n\tmaxStr, exists := p.sel.sel.Attr(\"max\")\n\tif !exists {\n\t\treturn 1.0\n\t}\n\n\tmaxVal, err := strconv.ParseFloat(maxStr, 64)\n\tif err != nil || maxVal < 0 {\n\t\treturn 1.0\n\t}\n\n\treturn maxVal\n}\n\nfunc (p ProgressElement) calcProgress(defaultVal float64) float64 {\n\tvalStr, exists := p.sel.sel.Attr(\"value\")\n\tif !exists {\n\t\treturn defaultVal\n\t}\n\n\tval, err := strconv.ParseFloat(valStr, 64)\n\tif err != nil || val < 0 {\n\t\treturn defaultVal\n\t}\n\n\treturn val / p.Max()\n}\n\nfunc (p ProgressElement) Value() float64 {\n\treturn p.calcProgress(0.0)\n}\n\nfunc (p ProgressElement) Position() float64 {\n\treturn p.calcProgress(-1.0)\n}\n\nfunc (p ProgressElement) Labels() []sobek.Value {\n\treturn p.elemLabels()\n}\n\nfunc (s ScriptElement) Text() string {\n\treturn s.TextContent()\n}\n\nfunc (s SelectElement) Form() sobek.Value {\n\treturn s.ownerFormVal()\n}\n\nfunc (s SelectElement) Labels() []sobek.Value {\n\treturn s.elemLabels()\n}\n\nfunc (s SelectElement) Length() int {\n\treturn s.sel.Find(\"option\").Size()\n}\n\nfunc (s SelectElement) Options() []sobek.Value {\n\treturn elemList(Selection{s.sel.rt, s.sel.sel.Find(\"option\"), s.sel.URL})\n}\n\nfunc (s SelectElement) SelectedIndex() int {\n\toption := s.sel.sel.Find(\"option[selected]\")\n\tif option.Length() == 0 {\n\t\treturn -1\n\t}\n\treturn s.sel.sel.Find(\"option\").IndexOfSelection(option)\n}\n\nfunc (s SelectElement) SelectedOptions() []sobek.Value {\n\treturn elemList(Selection{s.sel.rt, s.sel.sel.Find(\"option[selected]\"), s.sel.URL})\n}\n\nfunc (s SelectElement) Size() int {\n\tif s.attrIsPresent(\"multiple\") {\n\t\treturn 4\n\t}\n\treturn 1\n}\n\nfunc (s SelectElement) Type() string {\n\tif s.attrIsPresent(\"multiple\") {\n\t\treturn \"select-multiple\"\n\t}\n\treturn \"select\"\n}\n\nfunc (s SelectElement) Value() string {\n\toption := s.sel.sel.Find(\"option[selected]\")\n\tif option.Length() == 0 {\n\t\treturn \"\"\n\t}\n\treturn valueOrHTML(option.First())\n}\n\nfunc (s StyleElement) Type() string {\n\ttypeVal := s.attrAsString(\"type\")\n\tif typeVal == \"\" {\n\t\treturn \"text/css\"\n\t}\n\treturn typeVal\n}\n\nfunc (t TableElement) firstChild(elemName string) sobek.Value {\n\tchild := t.sel.sel.ChildrenFiltered(elemName)\n\tif child.Size() == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\treturn selToElement(Selection{t.sel.rt, child, t.sel.URL})\n}\n\nfunc (t TableElement) Caption() sobek.Value {\n\treturn t.firstChild(\"caption\")\n}\n\nfunc (t TableElement) THead() sobek.Value {\n\treturn t.firstChild(\"thead\")\n}\n\nfunc (t TableElement) TFoot() sobek.Value {\n\treturn t.firstChild(\"tfoot\")\n}\n\nfunc (t TableElement) Rows() []sobek.Value {\n\treturn elemList(Selection{t.sel.rt, t.sel.sel.Find(\"tr\"), t.sel.URL})\n}\n\nfunc (t TableElement) TBodies() []sobek.Value {\n\treturn elemList(Selection{t.sel.rt, t.sel.sel.Find(\"tbody\"), t.sel.URL})\n}\n\nfunc (t TableSectionElement) Rows() []sobek.Value {\n\treturn elemList(Selection{t.sel.rt, t.sel.sel.Find(\"tr\"), t.sel.URL})\n}\n\nfunc (t TableCellElement) CellIndex() int {\n\tprtRow := t.sel.sel.ParentsFiltered(\"tr\")\n\tif prtRow.Length() == 0 {\n\t\treturn -1\n\t}\n\treturn prtRow.Find(\"th,td\").IndexOfSelection(t.sel.sel)\n}\n\nfunc (t TableRowElement) Cells() []sobek.Value {\n\treturn elemList(Selection{t.sel.rt, t.sel.sel.Find(\"th,td\"), t.sel.URL})\n}\n\nfunc (t TableRowElement) RowIndex() int {\n\ttable := t.sel.sel.ParentsFiltered(\"table\")\n\tif table.Length() == 0 {\n\t\treturn -1\n\t}\n\treturn table.Find(\"tr\").IndexOfSelection(t.sel.sel)\n}\n\nfunc (t TableRowElement) SectionRowIndex() int {\n\tsection := t.sel.sel.ParentsFiltered(\"thead,tbody,tfoot\")\n\tif section.Length() == 0 {\n\t\treturn -1\n\t}\n\treturn section.Find(\"tr\").IndexOfSelection(t.sel.sel)\n}\n\nfunc (t TextAreaElement) Form() sobek.Value {\n\treturn t.ownerFormVal()\n}\n\nfunc (t TextAreaElement) Length() int {\n\treturn len(t.attrAsString(\"value\"))\n}\n\nfunc (t TextAreaElement) Labels() []sobek.Value {\n\treturn t.elemLabels()\n}\n\nfunc (t TableColElement) Span() int {\n\tspan := t.attrAsInt(\"span\", 1)\n\tif span < 1 {\n\t\treturn 1\n\t}\n\treturn span\n}\n\nfunc (m MediaElement) TextTracks() []sobek.Value {\n\treturn elemList(Selection{m.sel.rt, m.sel.sel.Find(\"track\"), m.sel.URL})\n}\n\nfunc (t TitleElement) Text() string {\n\treturn t.TextContent()\n}\n"
  },
  {
    "path": "js/modules/k6/html/elements_gen.go",
    "content": "// generated by js/modules/k6/html/gen/gen_elements.go;  DO NOT EDIT\npackage html\n\nimport \"github.com/grafana/sobek\"\n\nfunc selToElement(sel Selection) sobek.Value {\n\tif sel.sel.Length() == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\telem := Element{sel.sel.Nodes[0], &sel}\n\n\tswitch elem.node.Data {\n\tcase AnchorTagName:\n\t\treturn sel.rt.ToValue(AnchorElement{HrefElement{elem}})\n\tcase AreaTagName:\n\t\treturn sel.rt.ToValue(AreaElement{HrefElement{elem}})\n\tcase AudioTagName:\n\t\treturn sel.rt.ToValue(AudioElement{MediaElement{elem}})\n\tcase BaseTagName:\n\t\treturn sel.rt.ToValue(BaseElement{elem})\n\tcase ButtonTagName:\n\t\treturn sel.rt.ToValue(ButtonElement{FormFieldElement{elem}})\n\tcase CanvasTagName:\n\t\treturn sel.rt.ToValue(CanvasElement{elem})\n\tcase DataTagName:\n\t\treturn sel.rt.ToValue(DataElement{elem})\n\tcase DataListTagName:\n\t\treturn sel.rt.ToValue(DataListElement{elem})\n\tcase DelTagName:\n\t\treturn sel.rt.ToValue(DelElement{ModElement{elem}})\n\tcase EmbedTagName:\n\t\treturn sel.rt.ToValue(EmbedElement{elem})\n\tcase FieldSetTagName:\n\t\treturn sel.rt.ToValue(FieldSetElement{elem})\n\tcase FormTagName:\n\t\treturn sel.rt.ToValue(FormElement{elem})\n\tcase IFrameTagName:\n\t\treturn sel.rt.ToValue(IFrameElement{elem})\n\tcase ImageTagName:\n\t\treturn sel.rt.ToValue(ImageElement{elem})\n\tcase InputTagName:\n\t\treturn sel.rt.ToValue(InputElement{FormFieldElement{elem}})\n\tcase InsTagName:\n\t\treturn sel.rt.ToValue(InsElement{ModElement{elem}})\n\tcase KeygenTagName:\n\t\treturn sel.rt.ToValue(KeygenElement{elem})\n\tcase LabelTagName:\n\t\treturn sel.rt.ToValue(LabelElement{elem})\n\tcase LegendTagName:\n\t\treturn sel.rt.ToValue(LegendElement{elem})\n\tcase LiTagName:\n\t\treturn sel.rt.ToValue(LiElement{elem})\n\tcase LinkTagName:\n\t\treturn sel.rt.ToValue(LinkElement{elem})\n\tcase MapTagName:\n\t\treturn sel.rt.ToValue(MapElement{elem})\n\tcase MetaTagName:\n\t\treturn sel.rt.ToValue(MetaElement{elem})\n\tcase MeterTagName:\n\t\treturn sel.rt.ToValue(MeterElement{elem})\n\tcase OListTagName:\n\t\treturn sel.rt.ToValue(OListElement{elem})\n\tcase ObjectTagName:\n\t\treturn sel.rt.ToValue(ObjectElement{elem})\n\tcase OptGroupTagName:\n\t\treturn sel.rt.ToValue(OptGroupElement{elem})\n\tcase OptionTagName:\n\t\treturn sel.rt.ToValue(OptionElement{elem})\n\tcase OutputTagName:\n\t\treturn sel.rt.ToValue(OutputElement{elem})\n\tcase ParamTagName:\n\t\treturn sel.rt.ToValue(ParamElement{elem})\n\tcase PreTagName:\n\t\treturn sel.rt.ToValue(PreElement{elem})\n\tcase ProgressTagName:\n\t\treturn sel.rt.ToValue(ProgressElement{elem})\n\tcase QuoteTagName:\n\t\treturn sel.rt.ToValue(QuoteElement{elem})\n\tcase ScriptTagName:\n\t\treturn sel.rt.ToValue(ScriptElement{elem})\n\tcase SelectTagName:\n\t\treturn sel.rt.ToValue(SelectElement{elem})\n\tcase SourceTagName:\n\t\treturn sel.rt.ToValue(SourceElement{elem})\n\tcase StyleTagName:\n\t\treturn sel.rt.ToValue(StyleElement{elem})\n\tcase TableTagName:\n\t\treturn sel.rt.ToValue(TableElement{elem})\n\tcase TableBodyTagName:\n\t\treturn sel.rt.ToValue(TableBodyElement{TableSectionElement{elem}})\n\tcase TableColTagName:\n\t\treturn sel.rt.ToValue(TableColElement{elem})\n\tcase TableDataCellTagName:\n\t\treturn sel.rt.ToValue(TableDataCellElement{TableCellElement{elem}})\n\tcase TableFootTagName:\n\t\treturn sel.rt.ToValue(TableFootElement{TableSectionElement{elem}})\n\tcase TableHeadTagName:\n\t\treturn sel.rt.ToValue(TableHeadElement{TableSectionElement{elem}})\n\tcase TableHeaderCellTagName:\n\t\treturn sel.rt.ToValue(TableHeaderCellElement{TableCellElement{elem}})\n\tcase TableRowTagName:\n\t\treturn sel.rt.ToValue(TableRowElement{elem})\n\tcase TextAreaTagName:\n\t\treturn sel.rt.ToValue(TextAreaElement{elem})\n\tcase TimeTagName:\n\t\treturn sel.rt.ToValue(TimeElement{elem})\n\tcase TitleTagName:\n\t\treturn sel.rt.ToValue(TitleElement{elem})\n\tcase TrackTagName:\n\t\treturn sel.rt.ToValue(TrackElement{elem})\n\tcase UListTagName:\n\t\treturn sel.rt.ToValue(UListElement{elem})\n\tcase VideoTagName:\n\t\treturn sel.rt.ToValue(VideoElement{MediaElement{elem}})\n\tdefault:\n\t\treturn sel.rt.ToValue(elem)\n\t}\n}\n\nfunc (h HrefElement) Download() string {\n\treturn h.attrAsString(\"download\")\n}\n\nfunc (h HrefElement) ReferrerPolicy() string {\n\tattrVal := h.attrAsString(\"referrerpolicy\")\n\tswitch attrVal {\n\tcase \"no-referrer\":\n\t\treturn attrVal\n\tcase \"no-referrer-when-downgrade\":\n\t\treturn attrVal\n\tcase \"origin\":\n\t\treturn attrVal\n\tcase \"origin-when-cross-origin\":\n\t\treturn attrVal\n\tcase \"unsafe-url\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (h HrefElement) Rel() string {\n\treturn h.attrAsString(\"rel\")\n}\n\nfunc (h HrefElement) Href() string {\n\treturn h.attrAsURLString(\"href\", \"\")\n}\n\nfunc (h HrefElement) Target() string {\n\treturn h.attrAsString(\"target\")\n}\n\nfunc (h HrefElement) Type() string {\n\treturn h.attrAsString(\"type\")\n}\n\nfunc (h HrefElement) AccessKey() string {\n\treturn h.attrAsString(\"accesskey\")\n}\n\nfunc (h HrefElement) HrefLang() string {\n\treturn h.attrAsString(\"hreflang\")\n}\n\nfunc (h HrefElement) ToString() string {\n\treturn h.attrAsURLString(\"href\", \"\")\n}\n\nfunc (m MediaElement) Autoplay() bool {\n\treturn m.attrIsPresent(\"autoplay\")\n}\n\nfunc (m MediaElement) Controls() bool {\n\treturn m.attrIsPresent(\"controls\")\n}\n\nfunc (m MediaElement) Loop() bool {\n\treturn m.attrIsPresent(\"loop\")\n}\n\nfunc (m MediaElement) Muted() bool {\n\treturn m.attrIsPresent(\"muted\")\n}\n\nfunc (m MediaElement) Preload() string {\n\tattrVal := m.attrAsString(\"preload\")\n\tswitch attrVal {\n\tcase \"metadata\":\n\t\treturn attrVal\n\tcase \"none\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"auto\"\n\t}\n}\n\nfunc (m MediaElement) Src() string {\n\treturn m.attrAsURLString(\"src\", \"\")\n}\n\nfunc (m MediaElement) CrossOrigin() sobek.Value {\n\tattrVal, exists := m.sel.sel.Attr(\"crossorigin\")\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\tswitch attrVal {\n\tcase \"anonymous\":\n\t\treturn m.sel.rt.ToValue(attrVal)\n\tcase \"use-credentials\":\n\t\treturn m.sel.rt.ToValue(attrVal)\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n}\n\nfunc (m MediaElement) CurrentSrc() string {\n\treturn m.attrAsString(\"src\")\n}\n\nfunc (m MediaElement) DefaultMuted() bool {\n\treturn m.attrIsPresent(\"muted\")\n}\n\nfunc (m MediaElement) MediaGroup() string {\n\treturn m.attrAsString(\"mediagroup\")\n}\n\nfunc (b BaseElement) Href() string {\n\treturn b.attrAsURLString(\"href\", b.sel.URL)\n}\n\nfunc (b BaseElement) Target() string {\n\treturn b.attrAsString(\"target\")\n}\n\nfunc (b ButtonElement) AccessKey() string {\n\treturn b.attrAsString(\"accesskey\")\n}\n\nfunc (b ButtonElement) Autofocus() bool {\n\treturn b.attrIsPresent(\"autofocus\")\n}\n\nfunc (b ButtonElement) Disabled() bool {\n\treturn b.attrIsPresent(\"disabled\")\n}\n\nfunc (b ButtonElement) TabIndex() int {\n\treturn b.attrAsInt(\"tabindex\", 0)\n}\n\nfunc (b ButtonElement) Type() string {\n\tattrVal := b.attrAsString(\"type\")\n\tswitch attrVal {\n\tcase \"button\":\n\t\treturn attrVal\n\tcase \"menu\":\n\t\treturn attrVal\n\tcase \"reset\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"submit\"\n\t}\n}\n\nfunc (d DataElement) Value() string {\n\treturn d.attrAsString(\"value\")\n}\n\nfunc (e EmbedElement) Height() string {\n\treturn e.attrAsString(\"height\")\n}\n\nfunc (e EmbedElement) Width() string {\n\treturn e.attrAsString(\"width\")\n}\n\nfunc (e EmbedElement) Src() string {\n\treturn e.attrAsString(\"src\")\n}\n\nfunc (e EmbedElement) Type() string {\n\treturn e.attrAsString(\"type\")\n}\n\nfunc (f FieldSetElement) Disabled() bool {\n\treturn f.attrIsPresent(\"disabled\")\n}\n\nfunc (f FieldSetElement) Name() string {\n\treturn f.attrAsString(\"name\")\n}\n\nfunc (f FormElement) Action() string {\n\treturn f.attrAsURLString(\"action\", \"\")\n}\n\nfunc (f FormElement) Name() string {\n\treturn f.attrAsString(\"name\")\n}\n\nfunc (f FormElement) Target() string {\n\treturn f.attrAsString(\"target\")\n}\n\nfunc (f FormElement) Enctype() string {\n\tattrVal := f.attrAsString(\"enctype\")\n\tswitch attrVal {\n\tcase \"multipart/form-data\":\n\t\treturn attrVal\n\tcase \"text/plain\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"application/x-www-form-urlencoded\"\n\t}\n}\n\nfunc (f FormElement) Encoding() string {\n\tattrVal := f.attrAsString(\"enctype\")\n\tswitch attrVal {\n\tcase \"multipart/form-data\":\n\t\treturn attrVal\n\tcase \"text/plain\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"application/x-www-form-urlencoded\"\n\t}\n}\n\nfunc (f FormElement) AcceptCharset() string {\n\treturn f.attrAsString(\"accept-charset\")\n}\n\nfunc (f FormElement) Autocomplete() string {\n\tattrVal := f.attrAsString(\"autocomplete\")\n\tswitch attrVal {\n\tcase \"off\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"on\"\n\t}\n}\n\nfunc (f FormElement) NoValidate() bool {\n\treturn f.attrIsPresent(\"novalidate\")\n}\n\nfunc (i IFrameElement) Allowfullscreen() bool {\n\treturn i.attrIsPresent(\"allowfullscreen\")\n}\n\nfunc (i IFrameElement) ReferrerPolicy() string {\n\tattrVal := i.attrAsString(\"referrerpolicy\")\n\tswitch attrVal {\n\tcase \"no-referrer\":\n\t\treturn attrVal\n\tcase \"no-referrer-when-downgrade\":\n\t\treturn attrVal\n\tcase \"origin\":\n\t\treturn attrVal\n\tcase \"origin-when-cross-origin\":\n\t\treturn attrVal\n\tcase \"unsafe-url\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (i IFrameElement) Height() string {\n\treturn i.attrAsString(\"height\")\n}\n\nfunc (i IFrameElement) Width() string {\n\treturn i.attrAsString(\"width\")\n}\n\nfunc (i IFrameElement) Name() string {\n\treturn i.attrAsString(\"name\")\n}\n\nfunc (i IFrameElement) Src() string {\n\treturn i.attrAsURLString(\"src\", \"\")\n}\n\nfunc (i ImageElement) CurrentSrc() string {\n\treturn i.attrAsURLString(\"src\", \"\")\n}\n\nfunc (i ImageElement) Sizes() string {\n\treturn i.attrAsString(\"sizes\")\n}\n\nfunc (i ImageElement) Srcset() string {\n\treturn i.attrAsString(\"srcset\")\n}\n\nfunc (i ImageElement) Alt() string {\n\treturn i.attrAsString(\"alt\")\n}\n\nfunc (i ImageElement) CrossOrigin() sobek.Value {\n\tattrVal, exists := i.sel.sel.Attr(\"crossorigin\")\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\tswitch attrVal {\n\tcase \"anonymous\":\n\t\treturn i.sel.rt.ToValue(attrVal)\n\tcase \"use-credentials\":\n\t\treturn i.sel.rt.ToValue(attrVal)\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n}\n\nfunc (i ImageElement) Height() int {\n\treturn i.attrAsInt(\"height\", 0)\n}\n\nfunc (i ImageElement) Width() int {\n\treturn i.attrAsInt(\"width\", 0)\n}\n\nfunc (i ImageElement) IsMap() bool {\n\treturn i.attrIsPresent(\"ismap\")\n}\n\nfunc (i ImageElement) Name() string {\n\treturn i.attrAsString(\"name\")\n}\n\nfunc (i ImageElement) Src() string {\n\treturn i.attrAsURLString(\"src\", \"\")\n}\n\nfunc (i ImageElement) UseMap() string {\n\treturn i.attrAsString(\"usemap\")\n}\n\nfunc (i ImageElement) ReferrerPolicy() string {\n\tattrVal := i.attrAsString(\"referrerpolicy\")\n\tswitch attrVal {\n\tcase \"no-referrer\":\n\t\treturn attrVal\n\tcase \"no-referrer-when-downgrade\":\n\t\treturn attrVal\n\tcase \"origin\":\n\t\treturn attrVal\n\tcase \"origin-when-cross-origin\":\n\t\treturn attrVal\n\tcase \"unsafe-url\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (i InputElement) Name() string {\n\treturn i.attrAsString(\"name\")\n}\n\nfunc (i InputElement) TabIndex() int {\n\treturn i.attrAsInt(\"tabindex\", 0)\n}\n\nfunc (i InputElement) Type() string {\n\tattrVal := i.attrAsString(\"type\")\n\tswitch attrVal {\n\tcase \"button\":\n\t\treturn attrVal\n\tcase \"checkbox\":\n\t\treturn attrVal\n\tcase \"color\":\n\t\treturn attrVal\n\tcase \"date\":\n\t\treturn attrVal\n\tcase \"datetime-local\":\n\t\treturn attrVal\n\tcase \"email\":\n\t\treturn attrVal\n\tcase \"file\":\n\t\treturn attrVal\n\tcase \"hidden\":\n\t\treturn attrVal\n\tcase \"image\":\n\t\treturn attrVal\n\tcase \"month\":\n\t\treturn attrVal\n\tcase \"number\":\n\t\treturn attrVal\n\tcase \"password\":\n\t\treturn attrVal\n\tcase \"radio\":\n\t\treturn attrVal\n\tcase \"range\":\n\t\treturn attrVal\n\tcase \"reset\":\n\t\treturn attrVal\n\tcase \"search\":\n\t\treturn attrVal\n\tcase \"submit\":\n\t\treturn attrVal\n\tcase \"tel\":\n\t\treturn attrVal\n\tcase \"time\":\n\t\treturn attrVal\n\tcase \"url\":\n\t\treturn attrVal\n\tcase \"week\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"text\"\n\t}\n}\n\nfunc (i InputElement) Disabled() bool {\n\treturn i.attrIsPresent(\"disabled\")\n}\n\nfunc (i InputElement) Autofocus() bool {\n\treturn i.attrIsPresent(\"autofocus\")\n}\n\nfunc (i InputElement) Required() bool {\n\treturn i.attrIsPresent(\"required\")\n}\n\nfunc (i InputElement) Value() string {\n\treturn i.attrAsString(\"value\")\n}\n\nfunc (i InputElement) Checked() bool {\n\treturn i.attrIsPresent(\"checked\")\n}\n\nfunc (i InputElement) DefaultChecked() bool {\n\treturn i.attrIsPresent(\"checked\")\n}\n\nfunc (i InputElement) Alt() string {\n\treturn i.attrAsString(\"alt\")\n}\n\nfunc (i InputElement) Src() string {\n\treturn i.attrAsURLString(\"src\", \"\")\n}\n\nfunc (i InputElement) Height() string {\n\treturn i.attrAsString(\"height\")\n}\n\nfunc (i InputElement) Width() string {\n\treturn i.attrAsString(\"width\")\n}\n\nfunc (i InputElement) Accept() string {\n\treturn i.attrAsString(\"accept\")\n}\n\nfunc (i InputElement) Autocomplete() string {\n\tattrVal := i.attrAsString(\"autocomplete\")\n\tswitch attrVal {\n\tcase \"off\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"on\"\n\t}\n}\n\nfunc (i InputElement) MaxLength() int {\n\treturn i.attrAsInt(\"maxlength\", -1)\n}\n\nfunc (i InputElement) Size() int {\n\treturn i.attrAsInt(\"size\", 0)\n}\n\nfunc (i InputElement) Pattern() string {\n\treturn i.attrAsString(\"pattern\")\n}\n\nfunc (i InputElement) Placeholder() string {\n\treturn i.attrAsString(\"placeholder\")\n}\n\nfunc (i InputElement) Readonly() bool {\n\treturn i.attrIsPresent(\"readonly\")\n}\n\nfunc (i InputElement) Min() string {\n\treturn i.attrAsString(\"min\")\n}\n\nfunc (i InputElement) Max() string {\n\treturn i.attrAsString(\"max\")\n}\n\nfunc (i InputElement) DefaultValue() string {\n\treturn i.attrAsString(\"value\")\n}\n\nfunc (i InputElement) DirName() string {\n\treturn i.attrAsString(\"dirname\")\n}\n\nfunc (i InputElement) AccessKey() string {\n\treturn i.attrAsString(\"accesskey\")\n}\n\nfunc (i InputElement) Multiple() bool {\n\treturn i.attrIsPresent(\"multiple\")\n}\n\nfunc (i InputElement) Step() string {\n\treturn i.attrAsString(\"step\")\n}\n\nfunc (k KeygenElement) Autofocus() bool {\n\treturn k.attrIsPresent(\"autofocus\")\n}\n\nfunc (k KeygenElement) Challenge() string {\n\treturn k.attrAsString(\"challenge\")\n}\n\nfunc (k KeygenElement) Disabled() bool {\n\treturn k.attrIsPresent(\"disabled\")\n}\n\nfunc (k KeygenElement) Keytype() string {\n\tattrVal := k.attrAsString(\"keytype\")\n\tswitch attrVal {\n\tcase \"DSA\":\n\t\treturn attrVal\n\tcase \"EC\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"RSA\"\n\t}\n}\n\nfunc (k KeygenElement) Name() string {\n\treturn k.attrAsString(\"name\")\n}\n\nfunc (k KeygenElement) Type() string {\n\treturn \"keygen\"\n}\n\nfunc (l LabelElement) HtmlFor() string {\n\treturn l.attrAsString(\"for\")\n}\n\nfunc (l LegendElement) AccessKey() string {\n\treturn l.attrAsString(\"accesskey\")\n}\n\nfunc (l LiElement) Value() int {\n\treturn l.attrAsInt(\"value\", 0)\n}\n\nfunc (l LiElement) Type() string {\n\tattrVal := l.attrAsString(\"type\")\n\tswitch attrVal {\n\tcase \"1\":\n\t\treturn attrVal\n\tcase \"a\":\n\t\treturn attrVal\n\tcase \"A\":\n\t\treturn attrVal\n\tcase \"i\":\n\t\treturn attrVal\n\tcase \"I\":\n\t\treturn attrVal\n\tcase \"disc\":\n\t\treturn attrVal\n\tcase \"square\":\n\t\treturn attrVal\n\tcase \"circle\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (l LinkElement) CrossOrigin() sobek.Value {\n\tattrVal, exists := l.sel.sel.Attr(\"crossorigin\")\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\tswitch attrVal {\n\tcase \"anonymous\":\n\t\treturn l.sel.rt.ToValue(attrVal)\n\tcase \"use-credentials\":\n\t\treturn l.sel.rt.ToValue(attrVal)\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n}\n\nfunc (l LinkElement) ReferrerPolicy() string {\n\tattrVal := l.attrAsString(\"referrerpolicy\")\n\tswitch attrVal {\n\tcase \"no-referrer\":\n\t\treturn attrVal\n\tcase \"no-referrer-when-downgrade\":\n\t\treturn attrVal\n\tcase \"origin\":\n\t\treturn attrVal\n\tcase \"origin-when-cross-origin\":\n\t\treturn attrVal\n\tcase \"unsafe-url\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (l LinkElement) Href() string {\n\treturn l.attrAsURLString(\"href\", \"\")\n}\n\nfunc (l LinkElement) Hreflang() string {\n\treturn l.attrAsString(\"hreflang\")\n}\n\nfunc (l LinkElement) Media() string {\n\treturn l.attrAsString(\"media\")\n}\n\nfunc (l LinkElement) Rel() string {\n\treturn l.attrAsString(\"rel\")\n}\n\nfunc (l LinkElement) Target() string {\n\treturn l.attrAsString(\"target\")\n}\n\nfunc (l LinkElement) Type() string {\n\treturn l.attrAsString(\"type\")\n}\n\nfunc (m MapElement) Name() string {\n\treturn m.attrAsString(\"name\")\n}\n\nfunc (m MetaElement) Content() string {\n\treturn m.attrAsString(\"content\")\n}\n\nfunc (m MetaElement) Name() string {\n\treturn m.attrAsString(\"name\")\n}\n\nfunc (m MetaElement) HttpEquiv() string {\n\tattrVal := m.attrAsString(\"http-equiv\")\n\tswitch attrVal {\n\tcase \"default-style\":\n\t\treturn attrVal\n\tcase \"refresh\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"content-type\"\n\t}\n}\n\nfunc (m MeterElement) Min() int {\n\treturn m.attrAsInt(\"min\", 0)\n}\n\nfunc (m MeterElement) Max() int {\n\treturn m.attrAsInt(\"max\", 0)\n}\n\nfunc (m MeterElement) High() int {\n\treturn m.attrAsInt(\"high\", 0)\n}\n\nfunc (m MeterElement) Low() int {\n\treturn m.attrAsInt(\"low\", 0)\n}\n\nfunc (m MeterElement) Optimum() int {\n\treturn m.attrAsInt(\"optimum\", 0)\n}\n\nfunc (m ModElement) Cite() string {\n\treturn m.attrAsString(\"cite\")\n}\n\nfunc (m ModElement) Datetime() string {\n\treturn m.attrAsString(\"datetime\")\n}\n\nfunc (o ObjectElement) Data() string {\n\treturn o.attrAsURLString(\"data\", \"\")\n}\n\nfunc (o ObjectElement) Height() string {\n\treturn o.attrAsString(\"height\")\n}\n\nfunc (o ObjectElement) Name() string {\n\treturn o.attrAsString(\"name\")\n}\n\nfunc (o ObjectElement) Type() string {\n\treturn o.attrAsString(\"type\")\n}\n\nfunc (o ObjectElement) TabIndex() int {\n\treturn o.attrAsInt(\"tabindex\", 0)\n}\n\nfunc (o ObjectElement) TypeMustMatch() bool {\n\treturn o.attrIsPresent(\"typemustmatch\")\n}\n\nfunc (o ObjectElement) UseMap() string {\n\treturn o.attrAsString(\"usemap\")\n}\n\nfunc (o ObjectElement) Width() string {\n\treturn o.attrAsString(\"width\")\n}\n\nfunc (o OListElement) Reversed() bool {\n\treturn o.attrIsPresent(\"reversed\")\n}\n\nfunc (o OListElement) Start() int {\n\treturn o.attrAsInt(\"start\", 0)\n}\n\nfunc (o OListElement) Type() string {\n\tattrVal := o.attrAsString(\"type\")\n\tswitch attrVal {\n\tcase \"a\":\n\t\treturn attrVal\n\tcase \"A\":\n\t\treturn attrVal\n\tcase \"i\":\n\t\treturn attrVal\n\tcase \"I\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"1\"\n\t}\n}\n\nfunc (o OptGroupElement) Disabled() bool {\n\treturn o.attrIsPresent(\"disabled\")\n}\n\nfunc (o OptGroupElement) Label() string {\n\treturn o.attrAsString(\"label\")\n}\n\nfunc (o OptionElement) DefaultSelected() bool {\n\treturn o.attrIsPresent(\"selected\")\n}\n\nfunc (o OptionElement) Selected() bool {\n\treturn o.attrIsPresent(\"selected\")\n}\n\nfunc (o OutputElement) HtmlFor() string {\n\treturn o.attrAsString(\"for\")\n}\n\nfunc (o OutputElement) Name() string {\n\treturn o.attrAsString(\"name\")\n}\n\nfunc (o OutputElement) Type() string {\n\treturn \"output\"\n}\n\nfunc (p ParamElement) Name() string {\n\treturn p.attrAsString(\"name\")\n}\n\nfunc (p ParamElement) Value() string {\n\treturn p.attrAsString(\"value\")\n}\n\nfunc (p PreElement) Name() string {\n\treturn p.attrAsString(\"name\")\n}\n\nfunc (p PreElement) Value() string {\n\treturn p.attrAsString(\"value\")\n}\n\nfunc (q QuoteElement) Cite() string {\n\treturn q.attrAsString(\"cite\")\n}\n\nfunc (s ScriptElement) CrossOrigin() string {\n\treturn s.attrAsString(\"crossorigin\")\n}\n\nfunc (s ScriptElement) Type() string {\n\treturn s.attrAsString(\"type\")\n}\n\nfunc (s ScriptElement) Src() string {\n\treturn s.attrAsURLString(\"src\", \"\")\n}\n\nfunc (s ScriptElement) Charset() string {\n\treturn s.attrAsString(\"charset\")\n}\n\nfunc (s ScriptElement) Async() bool {\n\treturn s.attrIsPresent(\"async\")\n}\n\nfunc (s ScriptElement) Defer() bool {\n\treturn s.attrIsPresent(\"defer\")\n}\n\nfunc (s ScriptElement) NoModule() bool {\n\treturn s.attrIsPresent(\"nomodule\")\n}\n\nfunc (s SelectElement) Autofocus() bool {\n\treturn s.attrIsPresent(\"autofocus\")\n}\n\nfunc (s SelectElement) Disabled() bool {\n\treturn s.attrIsPresent(\"disabled\")\n}\n\nfunc (s SelectElement) Multiple() bool {\n\treturn s.attrIsPresent(\"multiple\")\n}\n\nfunc (s SelectElement) Name() string {\n\treturn s.attrAsString(\"name\")\n}\n\nfunc (s SelectElement) Required() bool {\n\treturn s.attrIsPresent(\"required\")\n}\n\nfunc (s SelectElement) TabIndex() int {\n\treturn s.attrAsInt(\"tabindex\", 0)\n}\n\nfunc (s SourceElement) KeySystem() string {\n\treturn s.attrAsString(\"keysystem\")\n}\n\nfunc (s SourceElement) Media() string {\n\treturn s.attrAsString(\"media\")\n}\n\nfunc (s SourceElement) Sizes() string {\n\treturn s.attrAsString(\"sizes\")\n}\n\nfunc (s SourceElement) Src() string {\n\treturn s.attrAsURLString(\"src\", \"\")\n}\n\nfunc (s SourceElement) Srcset() string {\n\treturn s.attrAsString(\"srcset\")\n}\n\nfunc (s SourceElement) Type() string {\n\treturn s.attrAsString(\"type\")\n}\n\nfunc (s StyleElement) Media() string {\n\treturn s.attrAsString(\"media\")\n}\n\nfunc (t TableElement) Sortable() bool {\n\treturn t.attrIsPresent(\"sortable\")\n}\n\nfunc (t TableCellElement) ColSpan() int {\n\treturn t.attrAsInt(\"colspan\", 1)\n}\n\nfunc (t TableCellElement) RowSpan() int {\n\treturn t.attrAsInt(\"rowspan\", 1)\n}\n\nfunc (t TableCellElement) Headers() string {\n\treturn t.attrAsString(\"headers\")\n}\n\nfunc (t TableHeaderCellElement) Abbr() string {\n\treturn t.attrAsString(\"abbr\")\n}\n\nfunc (t TableHeaderCellElement) Scope() string {\n\tattrVal := t.attrAsString(\"scope\")\n\tswitch attrVal {\n\tcase \"row\":\n\t\treturn attrVal\n\tcase \"col\":\n\t\treturn attrVal\n\tcase \"colgroup\":\n\t\treturn attrVal\n\tcase \"rowgroup\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (t TableHeaderCellElement) Sorted() bool {\n\treturn t.attrIsPresent(\"sorted\")\n}\n\nfunc (t TextAreaElement) Type() string {\n\treturn \"textarea\"\n}\n\nfunc (t TextAreaElement) Value() string {\n\treturn t.attrAsString(\"value\")\n}\n\nfunc (t TextAreaElement) DefaultValue() string {\n\treturn t.attrAsString(\"value\")\n}\n\nfunc (t TextAreaElement) Placeholder() string {\n\treturn t.attrAsString(\"placeholder\")\n}\n\nfunc (t TextAreaElement) Rows() int {\n\treturn t.attrAsInt(\"rows\", 0)\n}\n\nfunc (t TextAreaElement) Cols() int {\n\treturn t.attrAsInt(\"cols\", 0)\n}\n\nfunc (t TextAreaElement) MaxLength() int {\n\treturn t.attrAsInt(\"maxlength\", 0)\n}\n\nfunc (t TextAreaElement) TabIndex() int {\n\treturn t.attrAsInt(\"tabindex\", 0)\n}\n\nfunc (t TextAreaElement) AccessKey() string {\n\treturn t.attrAsString(\"accesskey\")\n}\n\nfunc (t TextAreaElement) ReadOnly() bool {\n\treturn t.attrIsPresent(\"readonly\")\n}\n\nfunc (t TextAreaElement) Required() bool {\n\treturn t.attrIsPresent(\"required\")\n}\n\nfunc (t TextAreaElement) Autocomplete() string {\n\tattrVal := t.attrAsString(\"autocomplete\")\n\tswitch attrVal {\n\tcase \"off\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"on\"\n\t}\n}\n\nfunc (t TextAreaElement) Autocapitalize() string {\n\tattrVal := t.attrAsString(\"autocapitalize\")\n\tswitch attrVal {\n\tcase \"none\":\n\t\treturn attrVal\n\tcase \"off\":\n\t\treturn attrVal\n\tcase \"characters\":\n\t\treturn attrVal\n\tcase \"words\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"sentences\"\n\t}\n}\n\nfunc (t TextAreaElement) Wrap() string {\n\tattrVal := t.attrAsString(\"wrap\")\n\tswitch attrVal {\n\tcase \"hard\":\n\t\treturn attrVal\n\tcase \"off\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"soft\"\n\t}\n}\n\nfunc (t TimeElement) Datetime() string {\n\treturn t.attrAsString(\"datetime\")\n}\n\nfunc (t TrackElement) Kind() string {\n\tattrVal := t.attrAsString(\"kind\")\n\tswitch attrVal {\n\tcase \"captions\":\n\t\treturn attrVal\n\tcase \"descriptions\":\n\t\treturn attrVal\n\tcase \"chapters\":\n\t\treturn attrVal\n\tcase \"metadata\":\n\t\treturn attrVal\n\tdefault:\n\t\treturn \"subtitle\"\n\t}\n}\n\nfunc (t TrackElement) Src() string {\n\treturn t.attrAsURLString(\"src\", \"\")\n}\n\nfunc (t TrackElement) Srclang() string {\n\treturn t.attrAsString(\"srclang\")\n}\n\nfunc (t TrackElement) Label() string {\n\treturn t.attrAsString(\"label\")\n}\n\nfunc (t TrackElement) Default() bool {\n\treturn t.attrIsPresent(\"default\")\n}\n\nfunc (u UListElement) Type() string {\n\treturn u.attrAsString(\"type\")\n}\n"
  },
  {
    "path": "js/modules/k6/html/elements_gen_test.go",
    "content": "package html\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst testGenElems = `<html><body>\n\t<a id=\"a1\" download=\"file:///path/name\" referrerpolicy=\"no-referrer\" rel=\"open\" href=\"http://test.url\" target=\"__blank\" type=\"text/html\" accesskey=\"w\" hreflang=\"es\"></a>\n\t<a id=\"a2\"></a>\n\t<a id=\"a3\" href=\"relpath\"></a>\n\t<a id=\"a4\" href=\"/abspath\"></a>\n\t<a id=\"a5\" href=\"?a=yes-a&b=yes-b\"></a>\n\t<a id=\"a6\" href=\"#testfrag\"></a>\n\t<a id=\"a7\" href=\"../prtpath\"></a>\n\t<a id=\"a8\" href=\"\"></a>\n\t<audio id=\"audio1\" autoplay controls loop muted src=\"foo.wav\" crossorigin=\"anonymous\" mediagroup=\"testgroup\"></audio>\n\t<audio id=\"audio2\"></audio>\n\t<audio id=\"audio3\" src=\"\"></audio>\n\t<base id=\"base1\" href=\"foo.html\" target=\"__any\"></base>\n\t<base id=\"base2\"></base>\n\t<base id=\"base3\" href=\"\" target=\"__any\"></base>\n\t<button id=\"btn1\" accesskey=\"e\" target=\"__any\" autofocus disabled type=\"button\"></button>\n\t<button id=\"btn2\"></button>\n\t<button id=\"btn3\" type=\"invalid_uses_default\"></button> <button id=\"btn3\" type=\"invalid_uses_default\"></button>\n\t<ul><li><data id=\"data1\" value=\"121\"></data></li><li><data id=\"data2\"></data></li></ul>\n\t<embed id=\"embed1\" type=\"video/avi\" src=\"movie.avi\" width=\"640\" height=\"480\">\n\t<fieldset id=\"fset1\" disabled name=\"fset1_name\"></fieldset>\n\t<fieldset id=\"fset2\"></fieldset>\n\t<form id=\"form1\" name=\"form1_name\" target=\"__self\" enctype=\"text/plain\" action=\"submit_url\" accept-charset=\"ISO-8859-1\" autocomplete=\"off\" novalidate></form>\n\t<form id=\"form2\"></form>\n\t<form id=\"form3\" action=\"\"></form>\n\t<iframe id=\"iframe1\" allowfullscreen referrerpolicy=\"no-referrer\" name=\"frame_name\" width=\"640\" height=\"480\" src=\"testframe.html\"></iframe>\n\t<iframe id=\"iframe2\" referrerpolicy=\"use-default-when-invalid\"></iframe>\n\t<iframe id=\"iframe3\" src=\"\"></iframe>\n\t<img id=\"img1\" src=\"test.png\" sizes=\"100vw,50vw\" srcset=\"large.jpg 1024w,medium.jpg 640w\" alt=\"alt text\" crossorigin=\"anonymous\" height=\"50\" width=\"100\" ismap name=\"img_name\" usemap=\"#map_name\" referrerpolicy=\"origin\"/>\n\t<img id=\"img2\" crossorigin=\"use-credentials\" referrerpolicy=\"use-default-when-invalid\"/>\n\t<img id=\"img3\" src=\"\"/>\n\t<input id=\"input1\" name=\"input1_name\" disabled autofocus required value=\"input1-val\" type=\"button\"/>\n\t<input id=\"input2\"/>\n\t<input id=\"input3\" type=\"checkbox\" checked multiple/>\n\t<input id=\"input4\" type=\"checkbox\"/>\n\t<input id=\"input5\" type=\"image\" alt=\"input_img\" src=\"input.png\" width=\"80\" height=\"40\"/>\n\t<input id=\"input5b\" type=\"image\" />\n\t<input id=\"input5c\" type=\"image\" src=\"\"/>\n\t<input id=\"input6\" type=\"file\" accept=\".jpg,.png\"/>\n\t<input id=\"input7\" type=\"text\" autocomplete=\"off\" maxlength=\"10\" size=\"5\" pattern=\"...\" placeholder=\"help text\" readonly min=\"2017-01-01\" max=\"2017-12-12\" dirname=\"input7.dir\" accesskey=\"s\" step=\"0.1\"/>\n\t<keygen id=\"kg1\" autofocus challenge=\"cx1\" disabled keytype=\"DSA\" name=\"kg1_name\"/>\n\t<keygen id=\"kg2\"/>\n\t<label id=\"label1\" for=\"input1_name\"/>\n\t<legend id=\"legend1\" accesskey=\"l\"/>\n\t<li id=\"li1\" type=\"disc\"></li> <li id=\"li2\" value=\"10\" type=\"\"></li>\n\t<link id=\"link1\" crossorigin=\"use-credentials\" referrerpolicy=\"no-referrer\" href=\"test.css\" hreflang=\"pl\" media=\"print\" rel=\"alternate author\" target=\"__self\" type=\"stylesheet\"/>\n\t<link id=\"link2\"/>\n\t<link id=\"link3\" href=\"\"/>\n\t<map id=\"map1\" name=\"map1_name\"></map>\n\t<meta id=\"meta1\" name=\"author\" content=\"author name\" />\n\t<meta id=\"meta2\" http-equiv=\"refresh\" content=\"1;www.test.com\" />\n\t<meter id=\"meter1\" min=\"90\" max=\"110\" low=\"95\" high=\"105\" optimum=\"100\"/>\n\t<ins id=\"ins1\" cite=\"cite.html\" datetime=\"2017-01-01\"/>\n\t<object id=\"object1\" name=\"obj1_name\" data=\"test.png\" type=\"image/png\" width=\"150\" height=\"75\" tabindex=\"6\" typemustmatch usemap=\"#map1_name\"/>\n\t<object id=\"object2\"/>\n\t<object id=\"object3\" data=\"\"/>\n\t<ol id=\"ol1\" reversed start=\"1\" type=\"a\"></ol> <ol id=\"ol2\"></ol>\n\t<optgroup id=\"optgroup1\" disabled label=\"optlabel\"></optgroup>\n\t<optgroup id=\"optgroup2\"></optgroup>\n\t<option id=\"opt1\" selected/><option id=\"opt2\" />\n\t<output id=\"out1\" for=\"input1\" name=\"out1_name\"/>\n\t<param id=\"par1\" name=\"param1_name\" value=\"param1_val\"/>\n\t<pre id=\"pre1\" name=\"pre1_name\" value=\"pre1_val\"/>\n\t<quote id=\"quote1\" cite=\"http://cite.com/url\"/>\n\t<script id=\"script1\" crossorigin=\"use-credentials\" type=\"text/javascript\" src=\"script.js\" charset=\"ISO-8859-1\" defer async nomodule></script>\n\t<script id=\"script2\"></script>\n\t<script id=\"script3\" src=\"\"></script>\n\t<select id=\"select1\" name=\"sel1_name\" autofocus disabled multiple required></select>\n\t<select id=\"select2\"></select>\n\t<source id=\"src1\" keysystem=\"keysys\" media=\"(min-width: 600px)\" sizes=\"100vw,50vw\" srcset=\"large.jpg 1024w,medium.jpg 640w\" src=\"test.png\" type=\"image/png\"></source>\n\t<source id=\"src2\"></source>\n\t<source id=\"src3\" src=\"\"></source>\n\t<style id=\"style1\" media=\"print\"></style>\n\t<table id=\"table1\" sortable><tr><td id=\"td1\" colspan=\"2\" rowspan=\"3\" headers=\"th1\"></th><th id=\"th1\" abbr=\"hdr\" scope=\"row\" sorted>Header</th><th id=\"th2\"></th></tr></table>\n\t<table id=\"table2\"></table>\n\t<textarea id=\"txtarea1\" value=\"init_txt\" placeholder=\"display_txt\" rows=\"10\" cols=\"12\" maxlength=\"128\" accesskey=\"k\" tabIndex=\"4\" readonly required autocomplete=\"off\" autocapitalize=\"words\" wrap=\"hard\"></textarea>\n\t<textarea id=\"txtarea2\"></textarea>\n\t<time id=\"time1\" datetime=\"2017-01-01\"/>\n\t<track id=\"track1\" kind=\"metadata\" src=\"foo.en.vtt\" srclang=\"en\" label=\"English\"></track>\n\t<track id=\"track2\" src=\"foo.sv.vtt\" srclang=\"sv\" label=\"Svenska\"></track>\n\t<track id=\"track3\"></track>\n\t<track id=\"track4\" src=\"\"></track>\n\t<ul id=\"ul1\" type=\"circle\"/>\n\t`\n\nfunc TestGenElementsTestTextProperties(t *testing.T) {\n\tt.Parallel()\n\trt := getTestRuntimeWithDoc(t, testGenElems)\n\n\ttextTests := []struct {\n\t\tid       string\n\t\tproperty string\n\t\tdata     string\n\t}{\n\t\t{\"a1\", \"download\", \"file:///path/name\"},\n\t\t{\"a1\", \"referrerPolicy\", \"no-referrer\"},\n\t\t{\"a1\", \"href\", \"http://test.url\"},\n\t\t{\"a1\", \"target\", \"__blank\"},\n\t\t{\"a1\", \"type\", \"text/html\"},\n\t\t{\"a1\", \"accessKey\", \"w\"},\n\t\t{\"a1\", \"hrefLang\", \"es\"},\n\t\t{\"a1\", \"toString\", \"http://test.url\"},\n\t\t{\"a2\", \"referrerPolicy\", \"\"},\n\t\t{\"a2\", \"accessKey\", \"\"},\n\t\t{\"audio1\", \"src\", \"foo.wav\"},\n\t\t{\"audio1\", \"crossOrigin\", \"anonymous\"},\n\t\t{\"audio1\", \"currentSrc\", \"foo.wav\"},\n\t\t{\"audio1\", \"mediaGroup\", \"testgroup\"},\n\t\t{\"base1\", \"href\", \"foo.html\"},\n\t\t{\"base1\", \"target\", \"__any\"},\n\t\t{\"btn1\", \"accessKey\", \"e\"},\n\t\t{\"btn1\", \"type\", \"button\"},\n\t\t{\"btn2\", \"type\", \"submit\"},\n\t\t{\"btn3\", \"type\", \"submit\"},\n\t\t{\"data1\", \"value\", \"121\"},\n\t\t{\"data2\", \"value\", \"\"},\n\t\t{\"embed1\", \"type\", \"video/avi\"},\n\t\t{\"embed1\", \"src\", \"movie.avi\"},\n\t\t{\"embed1\", \"width\", \"640\"},\n\t\t{\"embed1\", \"height\", \"480\"},\n\t\t{\"fset1\", \"name\", \"fset1_name\"},\n\t\t{\"form1\", \"target\", \"__self\"},\n\t\t{\"form1\", \"action\", \"submit_url\"},\n\t\t{\"form1\", \"enctype\", \"text/plain\"},\n\t\t{\"form1\", \"encoding\", \"text/plain\"},\n\t\t{\"form1\", \"acceptCharset\", \"ISO-8859-1\"},\n\t\t{\"form1\", \"target\", \"__self\"},\n\t\t{\"form1\", \"autocomplete\", \"off\"},\n\t\t{\"form2\", \"enctype\", \"application/x-www-form-urlencoded\"},\n\t\t{\"form2\", \"autocomplete\", \"on\"},\n\t\t{\"iframe1\", \"referrerPolicy\", \"no-referrer\"},\n\t\t{\"iframe2\", \"referrerPolicy\", \"\"},\n\t\t{\"iframe3\", \"referrerPolicy\", \"\"},\n\t\t{\"iframe1\", \"width\", \"640\"},\n\t\t{\"iframe1\", \"height\", \"480\"},\n\t\t{\"iframe1\", \"name\", \"frame_name\"},\n\t\t{\"iframe1\", \"src\", \"testframe.html\"},\n\t\t{\"img1\", \"src\", \"test.png\"},\n\t\t{\"img1\", \"currentSrc\", \"test.png\"},\n\t\t{\"img1\", \"sizes\", \"100vw,50vw\"},\n\t\t{\"img1\", \"srcset\", \"large.jpg 1024w,medium.jpg 640w\"},\n\t\t{\"img1\", \"alt\", \"alt text\"},\n\t\t{\"img1\", \"crossOrigin\", \"anonymous\"},\n\t\t{\"img1\", \"name\", \"img_name\"},\n\t\t{\"img1\", \"useMap\", \"#map_name\"},\n\t\t{\"img1\", \"referrerPolicy\", \"origin\"},\n\t\t{\"img2\", \"crossOrigin\", \"use-credentials\"},\n\t\t{\"img2\", \"referrerPolicy\", \"\"},\n\t\t{\"img3\", \"referrerPolicy\", \"\"},\n\t\t{\"input1\", \"name\", \"input1_name\"},\n\t\t{\"input1\", \"type\", \"button\"},\n\t\t{\"input1\", \"value\", \"input1-val\"},\n\t\t{\"input1\", \"defaultValue\", \"input1-val\"},\n\t\t{\"input2\", \"type\", \"text\"},\n\t\t{\"input2\", \"value\", \"\"},\n\t\t{\"input5\", \"alt\", \"input_img\"},\n\t\t{\"input5\", \"src\", \"input.png\"},\n\t\t{\"input5\", \"width\", \"80\"},\n\t\t{\"input5\", \"height\", \"40\"},\n\t\t{\"input6\", \"accept\", \".jpg,.png\"},\n\t\t{\"input7\", \"autocomplete\", \"off\"},\n\t\t{\"input7\", \"pattern\", \"...\"},\n\t\t{\"input7\", \"placeholder\", \"help text\"},\n\t\t{\"input7\", \"min\", \"2017-01-01\"},\n\t\t{\"input7\", \"max\", \"2017-12-12\"},\n\t\t{\"input7\", \"dirName\", \"input7.dir\"},\n\t\t{\"input7\", \"accessKey\", \"s\"},\n\t\t{\"input7\", \"step\", \"0.1\"},\n\t\t{\"kg1\", \"challenge\", \"cx1\"},\n\t\t{\"kg1\", \"keytype\", \"DSA\"},\n\t\t{\"kg1\", \"name\", \"kg1_name\"},\n\t\t{\"kg2\", \"challenge\", \"\"},\n\t\t{\"kg2\", \"keytype\", \"RSA\"},\n\t\t{\"kg2\", \"type\", \"keygen\"},\n\t\t{\"label1\", \"htmlFor\", \"input1_name\"},\n\t\t{\"legend1\", \"accessKey\", \"l\"},\n\t\t{\"li1\", \"type\", \"disc\"},\n\t\t{\"li2\", \"type\", \"\"},\n\t\t{\"link1\", \"crossOrigin\", \"use-credentials\"},\n\t\t{\"link1\", \"referrerPolicy\", \"no-referrer\"},\n\t\t{\"link1\", \"href\", \"test.css\"},\n\t\t{\"link1\", \"hreflang\", \"pl\"},\n\t\t{\"link1\", \"media\", \"print\"},\n\t\t{\"link1\", \"rel\", \"alternate author\"},\n\t\t{\"link1\", \"target\", \"__self\"},\n\t\t{\"link1\", \"type\", \"stylesheet\"},\n\t\t{\"link2\", \"referrerPolicy\", \"\"},\n\t\t{\"map1\", \"name\", \"map1_name\"},\n\t\t{\"meta1\", \"name\", \"author\"},\n\t\t{\"meta1\", \"content\", \"author name\"},\n\t\t{\"meta2\", \"httpEquiv\", \"refresh\"},\n\t\t{\"meta2\", \"content\", \"1;www.test.com\"},\n\t\t{\"meta2\", \"content\", \"1;www.test.com\"},\n\t\t{\"ins1\", \"cite\", \"cite.html\"},\n\t\t{\"ins1\", \"datetime\", \"2017-01-01\"},\n\t\t{\"object1\", \"data\", \"test.png\"},\n\t\t{\"object1\", \"type\", \"image/png\"},\n\t\t{\"object1\", \"name\", \"obj1_name\"},\n\t\t{\"object1\", \"width\", \"150\"},\n\t\t{\"object1\", \"height\", \"75\"},\n\t\t{\"object1\", \"useMap\", \"#map1_name\"},\n\t\t{\"ol1\", \"type\", \"a\"},\n\t\t{\"optgroup1\", \"label\", \"optlabel\"},\n\t\t{\"out1\", \"htmlFor\", \"input1\"},\n\t\t{\"out1\", \"name\", \"out1_name\"},\n\t\t{\"out1\", \"type\", \"output\"},\n\t\t{\"par1\", \"name\", \"param1_name\"},\n\t\t{\"par1\", \"value\", \"param1_val\"},\n\t\t{\"pre1\", \"name\", \"pre1_name\"},\n\t\t{\"pre1\", \"value\", \"pre1_val\"},\n\t\t{\"quote1\", \"cite\", \"http://cite.com/url\"},\n\t\t{\"script1\", \"crossOrigin\", \"use-credentials\"},\n\t\t{\"script1\", \"type\", \"text/javascript\"},\n\t\t{\"script1\", \"src\", \"script.js\"},\n\t\t{\"script1\", \"charset\", \"ISO-8859-1\"},\n\t\t{\"select1\", \"name\", \"sel1_name\"},\n\t\t{\"src1\", \"keySystem\", \"keysys\"},\n\t\t{\"src1\", \"media\", \"(min-width: 600px)\"},\n\t\t{\"src1\", \"sizes\", \"100vw,50vw\"},\n\t\t{\"src1\", \"srcset\", \"large.jpg 1024w,medium.jpg 640w\"},\n\t\t{\"src1\", \"src\", \"test.png\"},\n\t\t{\"src1\", \"type\", \"image/png\"},\n\t\t{\"td1\", \"headers\", \"th1\"},\n\t\t{\"th1\", \"abbr\", \"hdr\"},\n\t\t{\"th1\", \"scope\", \"row\"},\n\t\t{\"txtarea1\", \"accessKey\", \"k\"},\n\t\t{\"txtarea1\", \"autocomplete\", \"off\"},\n\t\t{\"txtarea1\", \"autocapitalize\", \"words\"},\n\t\t{\"txtarea1\", \"wrap\", \"hard\"},\n\t\t{\"txtarea2\", \"autocomplete\", \"on\"},\n\t\t{\"txtarea2\", \"autocapitalize\", \"sentences\"},\n\t\t{\"txtarea2\", \"wrap\", \"soft\"},\n\t\t{\"track1\", \"kind\", \"metadata\"},\n\t\t{\"track1\", \"src\", \"foo.en.vtt\"},\n\t\t{\"track1\", \"label\", \"English\"},\n\t\t{\"track1\", \"srclang\", \"en\"},\n\t\t{\"track2\", \"kind\", \"subtitle\"},\n\t\t{\"track2\", \"src\", \"foo.sv.vtt\"},\n\t\t{\"track2\", \"srclang\", \"sv\"},\n\t\t{\"track2\", \"label\", \"Svenska\"},\n\t\t{\"time1\", \"datetime\", \"2017-01-01\"},\n\t\t{\"ul1\", \"type\", \"circle\"},\n\t}\n\tfor _, test := range textTests {\n\t\tv, err := rt.RunString(`doc.find(\"#` + test.id + `\").get(0).` + test.property + `()`)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Error for property name '%s' on element id '#%s':\\n%+v \", test.id, test.property, err)\n\t\t} else if v.Export() != test.data {\n\t\t\tt.Errorf(\"Expected '%s' for property name '%s' element id '#%s'. Got '%s'\", test.data, test.property, test.id, v.String())\n\t\t}\n\t}\n}\n\nfunc TestGenElementsBoolProperties(t *testing.T) {\n\tt.Parallel()\n\trt := getTestRuntimeWithDoc(t, testGenElems)\n\n\tboolTests := []struct {\n\t\tidTrue   string\n\t\tidFalse  string\n\t\tproperty string\n\t}{\n\t\t{\"audio1\", \"audio2\", \"autoplay\"},\n\t\t{\"audio1\", \"audio2\", \"controls\"},\n\t\t{\"audio1\", \"audio2\", \"loop\"},\n\t\t{\"audio1\", \"audio2\", \"muted\"},\n\t\t{\"audio1\", \"audio2\", \"defaultMuted\"},\n\t\t{\"btn1\", \"btn2\", \"autofocus\"},\n\t\t{\"btn1\", \"btn2\", \"disabled\"},\n\t\t{\"fset1\", \"fset2\", \"disabled\"},\n\t\t{\"form1\", \"form2\", \"noValidate\"},\n\t\t{\"iframe1\", \"iframe2\", \"allowfullscreen\"},\n\t\t{\"img1\", \"img2\", \"isMap\"},\n\t\t{\"input1\", \"input2\", \"disabled\"},\n\t\t{\"input1\", \"input2\", \"autofocus\"},\n\t\t{\"input1\", \"input2\", \"required\"},\n\t\t{\"input3\", \"input4\", \"checked\"},\n\t\t{\"input3\", \"input4\", \"defaultChecked\"},\n\t\t{\"input7\", \"input1\", \"readonly\"},\n\t\t{\"input3\", \"input4\", \"multiple\"},\n\t\t{\"kg1\", \"kg2\", \"autofocus\"},\n\t\t{\"kg1\", \"kg2\", \"disabled\"},\n\t\t{\"object1\", \"object2\", \"typeMustMatch\"},\n\t\t{\"ol1\", \"ol2\", \"reversed\"},\n\t\t{\"optgroup1\", \"optgroup2\", \"disabled\"},\n\t\t{\"opt1\", \"opt2\", \"selected\"},\n\t\t{\"opt1\", \"opt2\", \"defaultSelected\"},\n\t\t{\"script1\", \"script2\", \"async\"},\n\t\t{\"script1\", \"script2\", \"defer\"},\n\t\t{\"script1\", \"script2\", \"noModule\"},\n\t\t{\"select1\", \"select2\", \"autofocus\"},\n\t\t{\"select1\", \"select2\", \"disabled\"},\n\t\t{\"select1\", \"select2\", \"multiple\"},\n\t\t{\"select1\", \"select2\", \"required\"},\n\t\t{\"table1\", \"table2\", \"sortable\"},\n\n\t\t{\"th1\", \"th2\", \"sorted\"},\n\n\t\t{\"txtarea1\", \"txtarea2\", \"readOnly\"},\n\t\t{\"txtarea1\", \"txtarea2\", \"required\"},\n\t}\n\n\tfor _, test := range boolTests {\n\t\tvT, errT := rt.RunString(`doc.find(\"#` + test.idTrue + `\").get(0).` + test.property + `()`)\n\t\tif errT != nil {\n\t\t\tt.Errorf(\"Error for property name '%s' on element id '#%s':\\n%+v\", test.property, test.idTrue, errT)\n\t\t} else if vT.Export() != true {\n\t\t\tt.Errorf(\"Expected true for property name '%s' on element id '#%s'\", test.property, test.idTrue)\n\t\t}\n\n\t\tvF, errF := rt.RunString(`doc.find(\"#` + test.idFalse + `\").get(0).` + test.property + `()`)\n\t\tif errF != nil {\n\t\t\tt.Errorf(\"Error for property name '%s' on element id '#%s':\\n%+v\", test.property, test.idFalse, errF)\n\t\t} else if vF.Export() != false {\n\t\t\tt.Errorf(\"Expected false for property name '%s' on element id '#%s'\", test.property, test.idFalse)\n\t\t}\n\t}\n}\n\nfunc TestGenElementsIntProperties(t *testing.T) {\n\tt.Parallel()\n\trt := getTestRuntimeWithDoc(t, testGenElems)\n\n\tintTests := []struct {\n\t\tid       string\n\t\tproperty string\n\t\tdata     int\n\t}{\n\t\t{\"img1\", \"width\", 100},\n\t\t{\"img1\", \"height\", 50},\n\t\t{\"input7\", \"maxLength\", 10},\n\t\t{\"input7\", \"size\", 5},\n\t\t{\"li1\", \"value\", 0},\n\t\t{\"li2\", \"value\", 10},\n\t\t{\"meter1\", \"min\", 90},\n\t\t{\"meter1\", \"max\", 110},\n\t\t{\"meter1\", \"low\", 95},\n\t\t{\"meter1\", \"high\", 105},\n\t\t{\"meter1\", \"optimum\", 100},\n\t\t{\"object1\", \"tabIndex\", 6},\n\t\t{\"ol1\", \"start\", 1},\n\t\t{\"td1\", \"colSpan\", 2},\n\t\t{\"td1\", \"rowSpan\", 3},\n\t\t{\"th1\", \"colSpan\", 1},\n\t\t{\"th1\", \"colSpan\", 1},\n\t\t{\"txtarea1\", \"rows\", 10},\n\t\t{\"txtarea1\", \"cols\", 12},\n\t\t{\"txtarea1\", \"maxLength\", 128},\n\t\t{\"txtarea1\", \"tabIndex\", 4},\n\t}\n\tfor _, test := range intTests {\n\t\tv, err := rt.RunString(`doc.find(\"#` + test.id + `\").get(0).` + test.property + `()`)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Error for property name '%s' on element id '#%s':\\n%+v\", test.property, test.id, err)\n\t\t} else if v.Export() != int64(test.data) {\n\t\t\tt.Errorf(\"Expected %d for property name '%s' on element id '#%s'. Got %d\", test.data, test.property, test.id, v.ToInteger())\n\t\t}\n\t}\n}\n\nfunc TestGenElementsNullProperties(t *testing.T) {\n\tt.Parallel()\n\trt := getTestRuntimeWithDoc(t, testGenElems)\n\tnullTests := []struct {\n\t\tid       string\n\t\tproperty string\n\t}{\n\t\t{\"audio2\", \"crossOrigin\"},\n\t\t{\"img3\", \"crossOrigin\"},\n\t\t{\"link2\", \"crossOrigin\"},\n\t}\n\n\tfor _, test := range nullTests {\n\t\tv, err := rt.RunString(`doc.find(\"#` + test.id + `\").get(0).` + test.property + `()`)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Error for property name '%s' on element id '#%s':\\n%+v\", test.property, test.id, err)\n\t\t} else if v.Export() != nil {\n\t\t\tt.Errorf(\"Expected null for property name '%s' on element id '#%s'\", test.property, test.id)\n\t\t}\n\t}\n}\n\nfunc TestGenElementsURLProperties(t *testing.T) {\n\tt.Parallel()\n\trt, mi := getTestRuntimeAndModuleInstanceWithDoc(t, testGenElems)\n\n\tsel, parseError := mi.parseHTML(testGenElems)\n\tif parseError != nil {\n\t\tt.Errorf(\"Unable to parse html\")\n\t}\n\n\turlTests := []struct {\n\t\tid       string\n\t\tproperty string\n\t\tbaseURL  string\n\t\tdata     string\n\t}{\n\t\t{\"a2\", \"href\", \"http://example.com/testpath\", \"\"},\n\t\t{\"a3\", \"href\", \"http://example.com\", \"http://example.com/relpath\"},\n\t\t{\"a3\", \"href\", \"http://example.com/somepath\", \"http://example.com/relpath\"},\n\t\t{\"a3\", \"href\", \"http://example.com/subdir/\", \"http://example.com/subdir/relpath\"},\n\t\t{\"a4\", \"href\", \"http://example.com/\", \"http://example.com/abspath\"},\n\t\t{\"a4\", \"href\", \"http://example.com/subdir/\", \"http://example.com/abspath\"},\n\t\t{\"a5\", \"href\", \"http://example.com/path?a=no-a&c=no-c\", \"http://example.com/path?a=yes-a&b=yes-b\"},\n\t\t{\"a6\", \"href\", \"http://example.com/path#oldfrag\", \"http://example.com/path#testfrag\"},\n\t\t{\"a7\", \"href\", \"http://example.com/prevdir/prevpath\", \"http://example.com/prtpath\"},\n\t\t{\"a8\", \"href\", \"http://example.com/testpath\", \"http://example.com/testpath\"},\n\t\t{\"base1\", \"href\", \"http://example.com\", \"http://example.com/foo.html\"},\n\t\t{\"base2\", \"href\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"base3\", \"href\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"audio1\", \"src\", \"http://example.com\", \"http://example.com/foo.wav\"},\n\t\t{\"audio2\", \"src\", \"http://example.com\", \"\"},\n\t\t{\"audio3\", \"src\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"form1\", \"action\", \"http://example.com/\", \"http://example.com/submit_url\"},\n\t\t{\"form2\", \"action\", \"http://example.com/\", \"\"},\n\t\t{\"form3\", \"action\", \"http://example.com/\", \"http://example.com/\"},\n\t\t{\"iframe1\", \"src\", \"http://example.com\", \"http://example.com/testframe.html\"},\n\t\t{\"iframe2\", \"src\", \"http://example.com\", \"\"},\n\t\t{\"iframe3\", \"src\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"img1\", \"src\", \"http://example.com\", \"http://example.com/test.png\"},\n\t\t{\"img2\", \"src\", \"http://example.com\", \"\"},\n\t\t{\"img3\", \"src\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"input5\", \"src\", \"http://example.com\", \"http://example.com/input.png\"},\n\t\t{\"input5b\", \"src\", \"http://example.com\", \"\"},\n\t\t{\"input5c\", \"src\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"link1\", \"href\", \"http://example.com\", \"http://example.com/test.css\"},\n\t\t{\"link2\", \"href\", \"http://example.com\", \"\"},\n\t\t{\"link3\", \"href\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"object1\", \"data\", \"http://example.com\", \"http://example.com/test.png\"},\n\t\t{\"object2\", \"data\", \"http://example.com\", \"\"},\n\t\t{\"object3\", \"data\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"script1\", \"src\", \"http://example.com\", \"http://example.com/script.js\"},\n\t\t{\"script2\", \"src\", \"http://example.com\", \"\"},\n\t\t{\"script3\", \"src\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"src1\", \"src\", \"http://example.com\", \"http://example.com/test.png\"},\n\t\t{\"src2\", \"src\", \"http://example.com\", \"\"},\n\t\t{\"src3\", \"src\", \"http://example.com\", \"http://example.com\"},\n\t\t{\"track1\", \"src\", \"http://example.com\", \"http://example.com/foo.en.vtt\"},\n\t\t{\"track3\", \"src\", \"http://example.com\", \"\"},\n\t\t{\"track4\", \"src\", \"http://example.com\", \"http://example.com\"},\n\t}\n\tfor _, test := range urlTests {\n\t\tsel.URL = test.baseURL\n\t\trequire.NoError(t, rt.Set(\"urldoc\", sel))\n\n\t\tv, err := rt.RunString(`urldoc.find(\"#` + test.id + `\").get(0).` + test.property + `()`)\n\t\tif err != nil {\n\t\t\tt.Errorf(\"Error for url property '%s' on element id '#%s':\\n%+v\", test.property, test.id, err)\n\t\t} else if v.Export() != test.data {\n\t\t\tt.Errorf(\"Expected '%s' for property name '%s' on element id '#%s', got '%s'\", test.data, test.property, test.id, v.String())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "js/modules/k6/html/elements_test.go",
    "content": "package html\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst testHTMLElems = `\n<html>\n<head><link rel=\"alternate next\"/><title>titletest</title></head>\n<body>\n\t<a href=\"/testhref?querytxt#hashtext\">0</a>\n\t<a href=\"http://example.com:80\">1</a>\n\t<a href=\"http://example.com:81/path/file\">2</a>\n\t<a href=\"https://ssl.example.com:443/\">3</a>\n\t<a href=\"https://ssl.example.com:444/\">4</a>\n\t<a href=\"http://username:password@example.com:80\">5</a>\n\t<a href=\"http://example.com\" rel=\"prev next\" target=\"_self\" type=\"rare\" accesskey=\"q\" hreflang=\"en-US\" media=\"print\">6</a>\n\t<a id=\"blank_anchor\">6</a>\n\t<area href=\"web.address.com\"></area>\n\t<base href=\"/rel/path\" target=\"_self\"></base>\n\n\t<form id=\"form1\" action=\"action_url\" enctype=\"text/plain\" target=\"_self\">\n\t\t<label for=\"form_btn\" id=\"form_btn_label\"></label>\n\t\t<button id=\"form_btn\" name=\"form_btn\" accesskey=\"b\" autofocus disabled></button>\n\t\t<label for=\"form_btn_2\" id=\"form_btn_2_label\"></label>\n\t\t<label id=\"wrapper_label\">\n\t\t\t<button id=\"form_btn_2\" type=\"button\" formaction=\"override_action_url\" formenctype=\"multipart/form-data\" formmethod=\"post\" formnovalidate formtarget=\"_top\" value=\"form_btn_2_initval\"></button>\n\t\t</label>\n\t</form>\n\t<form id=\"form2\"></form>\n\t<button id=\"named_form_btn\" form=\"form2\"></button>\n\t<button id=\"no_form_btn\"></button>\n\t<canvas width=\"200\"></canvas>\n\t<datalist id=\"datalist1\"><option id=\"dl_opt_1\"/><option id=\"dl_opt_2\"/></datalist>\n\t<form method=\"post\" id=\"fieldset_form\"><fieldset id=\"fieldset_1\"><legend id=\"legend_1\">Legend title</legend><input id=\"test_dl_input\" type=\"text\" list=\"datalist1\"><input type=\"text\"><select></select><button></button><textarea></textarea></fieldset></form>\n\t<ul><li id=\"li_nil\"/></ul>\n\t<ol><li id=\"li_first\"/><li value=\"10\"/><li id=\"li_eleven\"/></ol>\n\t<ol value=\"5\"><li id=\"li_plus\"/></ol>\n\t<map id=\"not_this_map\"></map>\n\t<map id=\"find_this_map\"><area/><area/><area/></map>\n\t<img usemap=\"#find_this_map\"/><object usemap=\"#find_this_map\"/><img usemap=\"#not_this_map\"/>\n\t<object id=\"obj_1\" form=\"form1\"/>\n\t<form id=\"form3\"><select id=\"sel1\"><option id=\"opt_1\">txt_label</option><option id=\"opt_2\" disabled label=\"attr_label\" value=\"selected_attr_val\" selected>option 2</option><optgroup disabled><option id=\"opt_3\" selected/></optgroup></select></form>\n\t<select form=\"form3\" id=\"sel2\"><option id=\"opt_4\"/></select>\n\t<label for=\"output1\"></label>\n\t<label><output id=\"output1\" form=\"form3\">defaultVal</output></label>\n\t<progress id=\"progress1\" max=\"100\" value=\"70\"></progress>\n\t<progress id=\"progress2\"></progress>\n\t<script id=\"script1\">script text</script>\n\t<style id=\"style1\"></style>\n\t<table><caption>caption text</caption>\n\t\t<thead><tr id=\"thead_row\"><td></td><th id=\"th_cell\" colSpan=\"2\"></th><td id=\"td_cell\" rowSpan=\"2\" headers=\"th_cell\"></td></tr></thead>\n\t\t<tfoot><tr></tr> <tr></tr> <tr id=\"tfoot_row\"></tr></tfoot>\n\t\t<tbody><tr></tr> <tr id=\"tbody_row\"></tr></tbody>\n\t\t<tr id=\"last_row\"></tr>\n\t</table>\n\t<table><tr id=\"sectionfree_row\"></tr></table>\n\t<video id=\"video1\"><track id=\"trk1\"><track id=\"trk2\"></video>\n</body>\n`\n\nfunc TestElements(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"AnchorElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"Hash\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(0).hash()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"#hashtext\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).hash()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Host\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(1).host()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"example.com\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(2).host()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"example.com:81\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(3).host()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"ssl.example.com\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(4).host()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"ssl.example.com:444\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).host()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Hostname\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(1).hostname()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"example.com\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).hostname()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Port\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(5).port()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"80\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).port()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Username\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(5).username()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"username\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).username()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Password\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(5).password()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"password\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).password()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Origin\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(5).origin()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"http://example.com:80\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).origin()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Pathname\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(1).pathname()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(2).pathname()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"/path/file\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).pathname()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Protocol\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(4).protocol()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"https\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#blank_anchor\").get(0).protocol()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \":\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"RelList\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(6).relList()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, []string{\"prev\", \"next\"}, v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(5).relList()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, []string{}, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Search\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(0).search()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"?querytxt\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Text\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"a\").get(6).text()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"6\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"AreaElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tif v, err := rt.RunString(`doc.find(\"area\").get(0).toString()`); assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"web.address.com\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"ButtonElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form1\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#named_form_btn\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form2\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#no_form_btn\").get(0).form()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, nil, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"formaction\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).formAction()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"action_url\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2\").get(0).formAction()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"override_action_url\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"formenctype\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).formEnctype()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"text/plain\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2\").get(0).formEnctype()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"multipart/form-data\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"formmethod\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).formMethod()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"get\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2\").get(0).formMethod()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"post\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"formnovalidate\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).formNoValidate()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, false, v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2\").get(0).formNoValidate()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, true, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"formtarget\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).formTarget()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"_self\", v.Export())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2\").get(0).formTarget()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"_top\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"labels\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).labels()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 1, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"form_btn_label\", v.Export().([]sobek.Value)[0].Export().(LabelElement).Id())\n\t\t\t}\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2\").get(0).labels()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"wrapper_label\", v.Export().([]sobek.Value)[0].Export().(LabelElement).Id())\n\t\t\t\tassert.Equal(t, \"form_btn_2_label\", v.Export().([]sobek.Value)[1].Export().(LabelElement).Id())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"name\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn\").get(0).name()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form_btn\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"value\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2\").get(0).value()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form_btn_2_initval\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"CanvasElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"width\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"canvas\").get(0).width()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(200), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"height\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\t\tif v, err := rt.RunString(`doc.find(\"canvas\").get(0).height()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(150), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"DataListElement options\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tif v, err := rt.RunString(`doc.find(\"datalist\").get(0).options()`); assert.NoError(t, err) {\n\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\tassert.Equal(t, \"dl_opt_1\", v.Export().([]sobek.Value)[0].Export().(OptionElement).Id())\n\t\t\tassert.Equal(t, \"dl_opt_2\", v.Export().([]sobek.Value)[1].Export().(OptionElement).Id())\n\t\t}\n\t})\n\tt.Run(\"FieldSetElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"elements\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"fieldset\").get(0).elements()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 5, len(v.Export().([]sobek.Value)))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"type\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"fieldset\").get(0).type()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"fieldset\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"fieldset\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"fieldset_form\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"FormElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"elements\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#fieldset_form\").get(0).elements()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 6, len(v.Export().([]sobek.Value)))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"length\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#fieldset_form\").get(0).length()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(6), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"method\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#form1\").get(0).method()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#fieldset_form\").get(0).method()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, \"get\", v1.Export())\n\t\t\t\tassert.Equal(t, \"post\", v2.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"InputElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#test_dl_input\").get(0).list().options()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"LabelElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"control\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2_label\").get(0).control().value()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form_btn_2_initval\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#form_btn_2_label\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form1\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"LegendElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#legend_1\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"fieldset_form\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"LinkElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"rel list\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"link\").get(0).relList()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, []string{\"alternate\", \"next\"}, v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"MapElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"areas\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#find_this_map\").get(0).areas()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 3, len(v.Export().([]sobek.Value)))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"images\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#find_this_map\").get(0).images()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"ObjectElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#obj_1\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form1\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"OptionElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"disabled\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#opt_1\").get(0).disabled()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#opt_2\").get(0).disabled()`)\n\t\t\tv3, err3 := rt.RunString(`doc.find(\"#opt_3\").get(0).disabled()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) && assert.NoError(t, err3) {\n\t\t\t\tassert.Equal(t, false, v1.Export())\n\t\t\t\tassert.Equal(t, true, v2.Export())\n\t\t\t\tassert.Equal(t, true, v3.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#opt_4\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form3\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"index\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#dl_opt_2\").get(0).index()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#opt_3\").get(0).index()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, int64(1), v1.Export())\n\t\t\t\tassert.Equal(t, int64(2), v2.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"label\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#opt_1\").get(0).label()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#opt_2\").get(0).label()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, \"txt_label\", v1.Export())\n\t\t\t\tassert.Equal(t, \"attr_label\", v2.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"text\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#opt_1\").get(0).text()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"txt_label\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"value\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#opt_1\").get(0).value()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#opt_2\").get(0).value()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, \"txt_label\", v1.Export())\n\t\t\t\tassert.Equal(t, \"selected_attr_val\", v2.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"OutputElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"value\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#output1\").get(0).value()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#output1\").get(0).defaultValue()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, \"defaultVal\", v1.Export())\n\t\t\t\tassert.Equal(t, \"defaultVal\", v2.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"labels\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#output1\").get(0).labels()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"ProgressElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"max\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#progress1\").get(0).max()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#progress2\").get(0).max()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, int64(100), v1.Export())\n\t\t\t\tassert.Equal(t, int64(1), v2.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"value\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#progress1\").get(0).value()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#progress2\").get(0).value()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, float64(0.7), v1.Export())\n\t\t\t\tassert.Equal(t, int64(0), v2.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"position\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#progress1\").get(0).position()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#progress2\").get(0).position()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, float64(0.7), v1.Export())\n\t\t\t\tassert.Equal(t, int64(-1), v2.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"ScriptElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"text\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#script1\").get(0).text()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"script text\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"SelectElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#sel2\").get(0).form().id()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form3\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"length\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#sel1\").get(0).length()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"options\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#sel1\").get(0).options()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 3, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"opt_1\", v.Export().([]sobek.Value)[0].Export().(OptionElement).Id())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"selectedOptions\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#sel1\").get(0).selectedOptions()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"opt_2\", v.Export().([]sobek.Value)[0].Export().(OptionElement).Id())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"selectedIndex\", func(t *testing.T) {\n\t\t\tv1, err1 := rt.RunString(`doc.find(\"#sel1\").get(0).selectedIndex()`)\n\t\t\tv2, err2 := rt.RunString(`doc.find(\"#sel2\").get(0).selectedIndex()`)\n\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\tassert.Equal(t, int64(1), v1.Export())\n\t\t\t\tassert.Equal(t, int64(-1), v2.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"value\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#sel1\").get(0).value()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"selected_attr_val\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"StyleElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"text\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#style1\").get(0).type()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"text/css\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"TableElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"caption\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"table\").get(0).caption().textContent()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"caption text\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"thead\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"table\").get(0).tHead().rows()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 1, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"thead_row\", v.Export().([]sobek.Value)[0].Export().(TableRowElement).Id())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"tbody\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"table\").get(0).tBodies()[0].rows()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"tbody_row\", v.Export().([]sobek.Value)[1].Export().(TableRowElement).Id())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"tfoot\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"table\").get(0).tFoot().rows()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 3, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"tfoot_row\", v.Export().([]sobek.Value)[2].Export().(TableRowElement).Id())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"rows\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"table\").get(0).rows()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 7, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"thead_row\", v.Export().([]sobek.Value)[0].Export().(TableRowElement).Id())\n\t\t\t\tassert.Equal(t, \"tfoot_row\", v.Export().([]sobek.Value)[3].Export().(TableRowElement).Id())\n\t\t\t\tassert.Equal(t, \"tbody_row\", v.Export().([]sobek.Value)[5].Export().(TableRowElement).Id())\n\t\t\t\tassert.Equal(t, \"last_row\", v.Export().([]sobek.Value)[6].Export().(TableRowElement).Id())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"TableCellElement\", func(t *testing.T) {\n\t\t\tt.Run(\"cellIndex\", func(t *testing.T) {\n\t\t\t\tif v, err := rt.RunString(`doc.find(\"#td_cell\").get(0).cellIndex()`); assert.NoError(t, err) {\n\t\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t\tt.Run(\"colSpan\", func(t *testing.T) {\n\t\t\t\tv1, err1 := rt.RunString(`doc.find(\"#td_cell\").get(0).colSpan()`)\n\t\t\t\tv2, err2 := rt.RunString(`doc.find(\"#th_cell\").get(0).colSpan()`)\n\t\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\t\tassert.Equal(t, int64(1), v1.Export())\n\t\t\t\t\tassert.Equal(t, int64(2), v2.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t\tt.Run(\"rowSpan\", func(t *testing.T) {\n\t\t\t\tv1, err1 := rt.RunString(`doc.find(\"#td_cell\").get(0).rowSpan()`)\n\t\t\t\tv2, err2 := rt.RunString(`doc.find(\"#th_cell\").get(0).rowSpan()`)\n\t\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\t\tassert.Equal(t, int64(2), v1.Export())\n\t\t\t\t\tassert.Equal(t, int64(1), v2.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t\tt.Run(\"headers\", func(t *testing.T) {\n\t\t\t\tif v, err := rt.RunString(`doc.find(\"#td_cell\").get(0).headers()`); assert.NoError(t, err) {\n\t\t\t\t\tassert.Equal(t, \"th_cell\", v.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t\tt.Run(\"TableRowElement\", func(t *testing.T) {\n\t\t\tt.Run(\"cells\", func(t *testing.T) {\n\t\t\t\tif v, err := rt.RunString(`doc.find(\"#thead_row\").get(0).cells()`); assert.NoError(t, err) {\n\t\t\t\t\tassert.Equal(t, 3, len(v.Export().([]sobek.Value)))\n\t\t\t\t\tassert.Equal(t, \"th_cell\", v.Export().([]sobek.Value)[1].Export().(TableHeaderCellElement).Id())\n\t\t\t\t}\n\t\t\t})\n\t\t\tt.Run(\"colSpan\", func(t *testing.T) {\n\t\t\t\tv1, err1 := rt.RunString(`doc.find(\"#td_cell\").get(0).colSpan()`)\n\t\t\t\tv2, err2 := rt.RunString(`doc.find(\"#th_cell\").get(0).colSpan()`)\n\t\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\t\tassert.Equal(t, int64(1), v1.Export())\n\t\t\t\t\tassert.Equal(t, int64(2), v2.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t\tt.Run(\"sectionRowIndex\", func(t *testing.T) {\n\t\t\t\tv1, err1 := rt.RunString(`doc.find(\"#tfoot_row\").get(0).sectionRowIndex()`)\n\t\t\t\tv2, err2 := rt.RunString(`doc.find(\"#last_row\").get(0).sectionRowIndex()`)\n\t\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\t\tassert.Equal(t, int64(2), v1.Export())\n\t\t\t\t\tassert.Equal(t, int64(0), v2.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t\tt.Run(\"rowIndex\", func(t *testing.T) {\n\t\t\t\tv1, err1 := rt.RunString(`doc.find(\"#tfoot_row\").get(0).rowIndex()`)\n\t\t\t\tv2, err2 := rt.RunString(`doc.find(\"#last_row\").get(0).rowIndex()`)\n\t\t\t\tif assert.NoError(t, err1) && assert.NoError(t, err2) {\n\t\t\t\t\tassert.Equal(t, int64(3), v1.Export())\n\t\t\t\t\tassert.Equal(t, int64(6), v2.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t})\n\tt.Run(\"VideoElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"text tracks\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"#video1\").get(0).textTracks()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, 2, len(v.Export().([]sobek.Value)))\n\t\t\t\tassert.Equal(t, \"trk1\", v.Export().([]sobek.Value)[0].Export().(TrackElement).Id())\n\t\t\t\tassert.Equal(t, \"trk2\", v.Export().([]sobek.Value)[1].Export().(TrackElement).Id())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"TitleElement\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTMLElems)\n\n\t\tt.Run(\"text tracks\", func(t *testing.T) {\n\t\t\tif v, err := rt.RunString(`doc.find(\"title\").get(0).text()`); assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"titletest\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "js/modules/k6/html/gen/gen_elements.go",
    "content": "// Package main - this package generates some of the code for k6/html\npackage main\n\nimport (\n\t\"bytes\"\n\t\"go/ast\"\n\t\"go/format\"\n\t\"go/parser\"\n\t\"go/token\"\n\t\"os\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// Generate elements_gen.go.\n// There are two sections of code which need to be generated.\n// The selToElement function and the attribute accessor methods.\n\n// The first step to generate the selToElement function is parse the TagName constants and Element structs\n// in elements.go using ast.Inspect\n// One of NodeHandlerFunc methods is called for each ast.Node parsed by ast.Inspect\n// The NodeHandlerFunc methods build ElemInfo structs and populate elemInfos in AstInspectState\n// The template later iterates over elemInfos to build the selToElement function\n\ntype nodeHandlerFunc func(node ast.Node) nodeHandlerFunc\n\ntype astInspectState struct {\n\thandler   nodeHandlerFunc\n\telemName  string\n\telemInfos map[string]*elemInfo\n}\n\ntype elemInfo struct {\n\tStructName    string\n\tPrtStructName string\n}\n\n// The attribute accessors are build using function definitions. Each funcion definition has a templateType.\n// The number of TemplateArgs varies based on the TenplateType and is documented below.\ntype (\n\ttemplateType string\n\ttemplateArg  string\n)\n\nconst (\n\tstringTemplate       templateType = \"typeString\"\n\turlTemplate          templateType = \"typeURL\"\n\tboolTemplate         templateType = \"typeBool\"\n\tintTemplate          templateType = \"typeInt\"\n\tconstTemplate        templateType = \"typeConst\"\n\tenumTemplate         templateType = \"typeEnum\"\n\tnullableEnumTemplate templateType = \"typeEnumNullable\"\n)\n\n// Some common TemplateArgs\n//\n//nolint:lll,gochecknoglobals\nvar (\n\t// Default return values for urlTemplate functions. Either an empty string or the current URL.\n\tdefaultURLEmpty = []templateArg{\"\\\"\\\"\"}\n\n\t// Common default return values for intTemplates\n\tdefaultInt0      = []templateArg{\"0\"}\n\tdefaultIntMinus1 = []templateArg{\"-1\"}\n\tdefaultIntPlus1  = []templateArg{\"1\"}\n\n\t// The following are the for various attributes using enumTemplate.\n\t// The first item in the list is the default value.\n\tautocompleteOpts = []templateArg{\"on\", \"off\"}\n\treferrerOpts     = []templateArg{\"\", \"no-referrer\", \"no-referrer-when-downgrade\", \"origin\", \"origin-when-cross-origin\", \"unsafe-url\"}\n\tpreloadOpts      = []templateArg{\"auto\", \"metadata\", \"none\"}\n\tbtnTypeOpts      = []templateArg{\"submit\", \"button\", \"menu\", \"reset\"}\n\tencTypeOpts      = []templateArg{\"application/x-www-form-urlencoded\", \"multipart/form-data\", \"text/plain\"}\n\tinputTypeOpts    = []templateArg{\"text\", \"button\", \"checkbox\", \"color\", \"date\", \"datetime-local\", \"email\", \"file\", \"hidden\", \"image\", \"month\", \"number\", \"password\", \"radio\", \"range\", \"reset\", \"search\", \"submit\", \"tel\", \"time\", \"url\", \"week\"}\n\tkeyTypeOpts      = []templateArg{\"RSA\", \"DSA\", \"EC\"}\n\tkeygenTypeOpts   = []templateArg{\"keygen\"}\n\tliTypeOpts       = []templateArg{\"\", \"1\", \"a\", \"A\", \"i\", \"I\", \"disc\", \"square\", \"circle\"}\n\thttpEquivOpts    = []templateArg{\"content-type\", \"default-style\", \"refresh\"}\n\tolistTypeOpts    = []templateArg{\"1\", \"a\", \"A\", \"i\", \"I\"}\n\tscopeOpts        = []templateArg{\"\", \"row\", \"col\", \"colgroup\", \"rowgroup\"}\n\tautocapOpts      = []templateArg{\"sentences\", \"none\", \"off\", \"characters\", \"words\"}\n\twrapOpts         = []templateArg{\"soft\", \"hard\", \"off\"}\n\tkindOpts         = []templateArg{\"subtitle\", \"captions\", \"descriptions\", \"chapters\", \"metadata\"}\n\n\t// These are the values allowed for the crossorigin attribute, used by the nullableEnumTemplates is always sobek.Undefined\n\tcrossOriginOpts = []templateArg{\"anonymous\", \"use-credentials\"}\n)\n\n// Elem is one of the Element struct names from elements.go\n// Method is the go method name to be generated.\n// Attr is the name of the DOM attribute the method will access, usually the Method name but lowercased.\n// TemplateType determines which type of function is generation by the template\n// TemplateArgs is a list of values to be interpolated in the template.\n\n// The number of TemplateArgs depends on the template type.\n//\n//\tstringTemplate: doesn't use any TemplateArgs\n//\tboolTemplate: doesn't use any TemplateArgs\n//\tconstTemplate: uses 1 Template Arg, the generated function always returns that value\n//\tintTemplate: needs 1 TemplateArg, used as the default return value (when the attribute was empty).\n//\turlTemplate: needs 1 TemplateArg, used as the default, either \"defaultURLEmpty\" or \"defaultURLCurrent\"\n//\tenumTemplate: uses any number or more TemplateArg, the gen'd func always returns one of the values in\n//\t              the TemplateArgs. The first item in the list is used as the default when the attribute\n//\t              was invalid or unset.\n//\tnullableEnumTemplate: similar to the enumTemplate except the default is sobek.Undefined and the\n//\t                      return type is sobek.Value\n//\n//nolint:gochecknoglobals\nvar funcDefs = []struct {\n\tElem, Method, Attr string\n\tTemplateType       templateType\n\tTemplateArgs       []templateArg\n}{\n\t{\"HrefElement\", \"Download\", \"download\", stringTemplate, nil},\n\t{\"HrefElement\", \"ReferrerPolicy\", \"referrerpolicy\", enumTemplate, referrerOpts},\n\t{\"HrefElement\", \"Rel\", \"rel\", stringTemplate, nil},\n\t{\"HrefElement\", \"Href\", \"href\", urlTemplate, defaultURLEmpty},\n\t{\"HrefElement\", \"Target\", \"target\", stringTemplate, nil},\n\t{\"HrefElement\", \"Type\", \"type\", stringTemplate, nil},\n\t{\"HrefElement\", \"AccessKey\", \"accesskey\", stringTemplate, nil},\n\t{\"HrefElement\", \"HrefLang\", \"hreflang\", stringTemplate, nil},\n\t{\"HrefElement\", \"ToString\", \"href\", urlTemplate, defaultURLEmpty},\n\t{\"MediaElement\", \"Autoplay\", \"autoplay\", boolTemplate, nil},\n\t{\"MediaElement\", \"Controls\", \"controls\", boolTemplate, nil},\n\t{\"MediaElement\", \"Loop\", \"loop\", boolTemplate, nil},\n\t{\"MediaElement\", \"Muted\", \"muted\", boolTemplate, nil},\n\t{\"MediaElement\", \"Preload\", \"preload\", enumTemplate, preloadOpts},\n\t{\"MediaElement\", \"Src\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"MediaElement\", \"CrossOrigin\", \"crossorigin\", nullableEnumTemplate, crossOriginOpts},\n\t{\"MediaElement\", \"CurrentSrc\", \"src\", stringTemplate, nil},\n\t{\"MediaElement\", \"DefaultMuted\", \"muted\", boolTemplate, nil},\n\t{\"MediaElement\", \"MediaGroup\", \"mediagroup\", stringTemplate, nil},\n\t{\"BaseElement\", \"Href\", \"href\", urlTemplate, []templateArg{\"b.sel.URL\"}},\n\t{\"BaseElement\", \"Target\", \"target\", stringTemplate, nil},\n\t{\"ButtonElement\", \"AccessKey\", \"accesskey\", stringTemplate, nil},\n\t{\"ButtonElement\", \"Autofocus\", \"autofocus\", boolTemplate, nil},\n\t{\"ButtonElement\", \"Disabled\", \"disabled\", boolTemplate, nil},\n\t{\"ButtonElement\", \"TabIndex\", \"tabindex\", intTemplate, defaultInt0},\n\t{\"ButtonElement\", \"Type\", \"type\", enumTemplate, btnTypeOpts},\n\t{\"DataElement\", \"Value\", \"value\", stringTemplate, nil},\n\t{\"EmbedElement\", \"Height\", \"height\", stringTemplate, nil},\n\t{\"EmbedElement\", \"Width\", \"width\", stringTemplate, nil},\n\t{\"EmbedElement\", \"Src\", \"src\", stringTemplate, nil},\n\t{\"EmbedElement\", \"Type\", \"type\", stringTemplate, nil},\n\t{\"FieldSetElement\", \"Disabled\", \"disabled\", boolTemplate, nil},\n\t{\"FieldSetElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"FormElement\", \"Action\", \"action\", urlTemplate, defaultURLEmpty},\n\t{\"FormElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"FormElement\", \"Target\", \"target\", stringTemplate, nil},\n\t{\"FormElement\", \"Enctype\", \"enctype\", enumTemplate, encTypeOpts},\n\t{\"FormElement\", \"Encoding\", \"enctype\", enumTemplate, encTypeOpts},\n\t{\"FormElement\", \"AcceptCharset\", \"accept-charset\", stringTemplate, nil},\n\t{\"FormElement\", \"Autocomplete\", \"autocomplete\", enumTemplate, autocompleteOpts},\n\t{\"FormElement\", \"NoValidate\", \"novalidate\", boolTemplate, nil},\n\t{\"IFrameElement\", \"Allowfullscreen\", \"allowfullscreen\", boolTemplate, nil},\n\t{\"IFrameElement\", \"ReferrerPolicy\", \"referrerpolicy\", enumTemplate, referrerOpts},\n\t{\"IFrameElement\", \"Height\", \"height\", stringTemplate, nil},\n\t{\"IFrameElement\", \"Width\", \"width\", stringTemplate, nil},\n\t{\"IFrameElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"IFrameElement\", \"Src\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"ImageElement\", \"CurrentSrc\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"ImageElement\", \"Sizes\", \"sizes\", stringTemplate, nil},\n\t{\"ImageElement\", \"Srcset\", \"srcset\", stringTemplate, nil},\n\t{\"ImageElement\", \"Alt\", \"alt\", stringTemplate, nil},\n\t{\"ImageElement\", \"CrossOrigin\", \"crossorigin\", nullableEnumTemplate, crossOriginOpts},\n\t{\"ImageElement\", \"Height\", \"height\", intTemplate, defaultInt0},\n\t{\"ImageElement\", \"Width\", \"width\", intTemplate, defaultInt0},\n\t{\"ImageElement\", \"IsMap\", \"ismap\", boolTemplate, nil},\n\t{\"ImageElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"ImageElement\", \"Src\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"ImageElement\", \"UseMap\", \"usemap\", stringTemplate, nil},\n\t{\"ImageElement\", \"ReferrerPolicy\", \"referrerpolicy\", enumTemplate, referrerOpts},\n\t{\"InputElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"InputElement\", \"TabIndex\", \"tabindex\", intTemplate, defaultInt0},\n\t{\"InputElement\", \"Type\", \"type\", enumTemplate, inputTypeOpts},\n\t{\"InputElement\", \"Disabled\", \"disabled\", boolTemplate, nil},\n\t{\"InputElement\", \"Autofocus\", \"autofocus\", boolTemplate, nil},\n\t{\"InputElement\", \"Required\", \"required\", boolTemplate, nil},\n\t{\"InputElement\", \"Value\", \"value\", stringTemplate, nil},\n\t{\"InputElement\", \"Checked\", \"checked\", boolTemplate, nil},\n\t{\"InputElement\", \"DefaultChecked\", \"checked\", boolTemplate, nil},\n\t{\"InputElement\", \"Alt\", \"alt\", stringTemplate, nil},\n\t{\"InputElement\", \"Src\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"InputElement\", \"Height\", \"height\", stringTemplate, nil},\n\t{\"InputElement\", \"Width\", \"width\", stringTemplate, nil},\n\t{\"InputElement\", \"Accept\", \"accept\", stringTemplate, nil},\n\t{\"InputElement\", \"Autocomplete\", \"autocomplete\", enumTemplate, autocompleteOpts},\n\t{\"InputElement\", \"MaxLength\", \"maxlength\", intTemplate, defaultIntMinus1},\n\t{\"InputElement\", \"Size\", \"size\", intTemplate, defaultInt0},\n\t{\"InputElement\", \"Pattern\", \"pattern\", stringTemplate, nil},\n\t{\"InputElement\", \"Placeholder\", \"placeholder\", stringTemplate, nil},\n\t{\"InputElement\", \"Readonly\", \"readonly\", boolTemplate, nil},\n\t{\"InputElement\", \"Min\", \"min\", stringTemplate, nil},\n\t{\"InputElement\", \"Max\", \"max\", stringTemplate, nil},\n\t{\"InputElement\", \"DefaultValue\", \"value\", stringTemplate, nil},\n\t{\"InputElement\", \"DirName\", \"dirname\", stringTemplate, nil},\n\t{\"InputElement\", \"AccessKey\", \"accesskey\", stringTemplate, nil},\n\t{\"InputElement\", \"Multiple\", \"multiple\", boolTemplate, nil},\n\t{\"InputElement\", \"Step\", \"step\", stringTemplate, nil},\n\t{\"KeygenElement\", \"Autofocus\", \"autofocus\", boolTemplate, nil},\n\t{\"KeygenElement\", \"Challenge\", \"challenge\", stringTemplate, nil},\n\t{\"KeygenElement\", \"Disabled\", \"disabled\", boolTemplate, nil},\n\t{\"KeygenElement\", \"Keytype\", \"keytype\", enumTemplate, keyTypeOpts},\n\t{\"KeygenElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"KeygenElement\", \"Type\", \"type\", constTemplate, keygenTypeOpts},\n\t{\"LabelElement\", \"HtmlFor\", \"for\", stringTemplate, nil},\n\t{\"LegendElement\", \"AccessKey\", \"accesskey\", stringTemplate, nil},\n\t{\"LiElement\", \"Value\", \"value\", intTemplate, defaultInt0},\n\t{\"LiElement\", \"Type\", \"type\", enumTemplate, liTypeOpts},\n\t{\"LinkElement\", \"CrossOrigin\", \"crossorigin\", nullableEnumTemplate, crossOriginOpts},\n\t{\"LinkElement\", \"ReferrerPolicy\", \"referrerpolicy\", enumTemplate, referrerOpts},\n\t{\"LinkElement\", \"Href\", \"href\", urlTemplate, defaultURLEmpty},\n\t{\"LinkElement\", \"Hreflang\", \"hreflang\", stringTemplate, nil},\n\t{\"LinkElement\", \"Media\", \"media\", stringTemplate, nil},\n\t{\"LinkElement\", \"Rel\", \"rel\", stringTemplate, nil},\n\t{\"LinkElement\", \"Target\", \"target\", stringTemplate, nil},\n\t{\"LinkElement\", \"Type\", \"type\", stringTemplate, nil},\n\t{\"MapElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"MetaElement\", \"Content\", \"content\", stringTemplate, nil},\n\t{\"MetaElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"MetaElement\", \"HttpEquiv\", \"http-equiv\", enumTemplate, httpEquivOpts},\n\t{\"MeterElement\", \"Min\", \"min\", intTemplate, defaultInt0},\n\t{\"MeterElement\", \"Max\", \"max\", intTemplate, defaultInt0},\n\t{\"MeterElement\", \"High\", \"high\", intTemplate, defaultInt0},\n\t{\"MeterElement\", \"Low\", \"low\", intTemplate, defaultInt0},\n\t{\"MeterElement\", \"Optimum\", \"optimum\", intTemplate, defaultInt0},\n\t{\"ModElement\", \"Cite\", \"cite\", stringTemplate, nil},\n\t{\"ModElement\", \"Datetime\", \"datetime\", stringTemplate, nil},\n\t{\"ObjectElement\", \"Data\", \"data\", urlTemplate, defaultURLEmpty},\n\t{\"ObjectElement\", \"Height\", \"height\", stringTemplate, nil},\n\t{\"ObjectElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"ObjectElement\", \"Type\", \"type\", stringTemplate, nil},\n\t{\"ObjectElement\", \"TabIndex\", \"tabindex\", intTemplate, defaultInt0},\n\t{\"ObjectElement\", \"TypeMustMatch\", \"typemustmatch\", boolTemplate, nil},\n\t{\"ObjectElement\", \"UseMap\", \"usemap\", stringTemplate, nil},\n\t{\"ObjectElement\", \"Width\", \"width\", stringTemplate, nil},\n\t{\"OListElement\", \"Reversed\", \"reversed\", boolTemplate, nil},\n\t{\"OListElement\", \"Start\", \"start\", intTemplate, defaultInt0},\n\t{\"OListElement\", \"Type\", \"type\", enumTemplate, olistTypeOpts},\n\t{\"OptGroupElement\", \"Disabled\", \"disabled\", boolTemplate, nil},\n\t{\"OptGroupElement\", \"Label\", \"label\", stringTemplate, nil},\n\t{\"OptionElement\", \"DefaultSelected\", \"selected\", boolTemplate, nil},\n\t{\"OptionElement\", \"Selected\", \"selected\", boolTemplate, nil},\n\t{\"OutputElement\", \"HtmlFor\", \"for\", stringTemplate, nil},\n\t{\"OutputElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"OutputElement\", \"Type\", \"type\", constTemplate, []templateArg{\"output\"}},\n\t{\"ParamElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"ParamElement\", \"Value\", \"value\", stringTemplate, nil},\n\t{\"PreElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"PreElement\", \"Value\", \"value\", stringTemplate, nil},\n\t{\"QuoteElement\", \"Cite\", \"cite\", stringTemplate, nil},\n\t{\"ScriptElement\", \"CrossOrigin\", \"crossorigin\", stringTemplate, nil},\n\t{\"ScriptElement\", \"Type\", \"type\", stringTemplate, nil},\n\t{\"ScriptElement\", \"Src\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"ScriptElement\", \"Charset\", \"charset\", stringTemplate, nil},\n\t{\"ScriptElement\", \"Async\", \"async\", boolTemplate, nil},\n\t{\"ScriptElement\", \"Defer\", \"defer\", boolTemplate, nil},\n\t{\"ScriptElement\", \"NoModule\", \"nomodule\", boolTemplate, nil},\n\t{\"SelectElement\", \"Autofocus\", \"autofocus\", boolTemplate, nil},\n\t{\"SelectElement\", \"Disabled\", \"disabled\", boolTemplate, nil},\n\t{\"SelectElement\", \"Multiple\", \"multiple\", boolTemplate, nil},\n\t{\"SelectElement\", \"Name\", \"name\", stringTemplate, nil},\n\t{\"SelectElement\", \"Required\", \"required\", boolTemplate, nil},\n\t{\"SelectElement\", \"TabIndex\", \"tabindex\", intTemplate, defaultInt0},\n\t{\"SourceElement\", \"KeySystem\", \"keysystem\", stringTemplate, nil},\n\t{\"SourceElement\", \"Media\", \"media\", stringTemplate, nil},\n\t{\"SourceElement\", \"Sizes\", \"sizes\", stringTemplate, nil},\n\t{\"SourceElement\", \"Src\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"SourceElement\", \"Srcset\", \"srcset\", stringTemplate, nil},\n\t{\"SourceElement\", \"Type\", \"type\", stringTemplate, nil},\n\t{\"StyleElement\", \"Media\", \"media\", stringTemplate, nil},\n\t{\"TableElement\", \"Sortable\", \"sortable\", boolTemplate, nil},\n\t{\"TableCellElement\", \"ColSpan\", \"colspan\", intTemplate, defaultIntPlus1},\n\t{\"TableCellElement\", \"RowSpan\", \"rowspan\", intTemplate, defaultIntPlus1},\n\t{\"TableCellElement\", \"Headers\", \"headers\", stringTemplate, nil},\n\t{\"TableHeaderCellElement\", \"Abbr\", \"abbr\", stringTemplate, nil},\n\t{\"TableHeaderCellElement\", \"Scope\", \"scope\", enumTemplate, scopeOpts},\n\t{\"TableHeaderCellElement\", \"Sorted\", \"sorted\", boolTemplate, nil},\n\t{\"TextAreaElement\", \"Type\", \"type\", constTemplate, []templateArg{\"textarea\"}},\n\t{\"TextAreaElement\", \"Value\", \"value\", stringTemplate, nil},\n\t{\"TextAreaElement\", \"DefaultValue\", \"value\", stringTemplate, nil},\n\t{\"TextAreaElement\", \"Placeholder\", \"placeholder\", stringTemplate, nil},\n\t{\"TextAreaElement\", \"Rows\", \"rows\", intTemplate, defaultInt0},\n\t{\"TextAreaElement\", \"Cols\", \"cols\", intTemplate, defaultInt0},\n\t{\"TextAreaElement\", \"MaxLength\", \"maxlength\", intTemplate, defaultInt0},\n\t{\"TextAreaElement\", \"TabIndex\", \"tabindex\", intTemplate, defaultInt0},\n\t{\"TextAreaElement\", \"AccessKey\", \"accesskey\", stringTemplate, nil},\n\t{\"TextAreaElement\", \"ReadOnly\", \"readonly\", boolTemplate, nil},\n\t{\"TextAreaElement\", \"Required\", \"required\", boolTemplate, nil},\n\t{\"TextAreaElement\", \"Autocomplete\", \"autocomplete\", enumTemplate, autocompleteOpts},\n\t{\"TextAreaElement\", \"Autocapitalize\", \"autocapitalize\", enumTemplate, autocapOpts},\n\t{\"TextAreaElement\", \"Wrap\", \"wrap\", enumTemplate, wrapOpts},\n\t{\"TimeElement\", \"Datetime\", \"datetime\", stringTemplate, nil},\n\t{\"TrackElement\", \"Kind\", \"kind\", enumTemplate, kindOpts},\n\t{\"TrackElement\", \"Src\", \"src\", urlTemplate, defaultURLEmpty},\n\t{\"TrackElement\", \"Srclang\", \"srclang\", stringTemplate, nil},\n\t{\"TrackElement\", \"Label\", \"label\", stringTemplate, nil},\n\t{\"TrackElement\", \"Default\", \"default\", boolTemplate, nil},\n\t{\"UListElement\", \"Type\", \"type\", stringTemplate, nil},\n}\n\nfunc main() {\n\tfs := token.NewFileSet()\n\tparsedFile, parseErr := parser.ParseFile(fs, \"elements.go\", nil, 0)\n\tif parseErr != nil {\n\t\tlogrus.WithError(parseErr).Fatal(\"Could not parse elements.go\")\n\t}\n\n\t// Initialise the AstInspectState\n\tcollector := &astInspectState{}\n\n\tcollector.handler = collector.defaultHandler\n\tcollector.elemInfos = make(map[string]*elemInfo)\n\n\t// Populate collector.elemInfos\n\tast.Inspect(parsedFile, func(n ast.Node) bool {\n\t\tif n != nil {\n\t\t\tcollector.handler = collector.handler(n)\n\t\t}\n\t\treturn true\n\t})\n\n\t// elemInfos and funcDefs are now complete and the template can be executed.\n\tvar buf bytes.Buffer\n\terr := elemFuncsTemplate.Execute(&buf, struct {\n\t\tElemInfos map[string]*elemInfo\n\t\tFuncDefs  []struct {\n\t\t\tElem, Method, Attr string\n\t\t\tTemplateType       templateType\n\t\t\tTemplateArgs       []templateArg\n\t\t}\n\t\tTemplateTypes struct{ String, URL, Enum, Bool, SobekEnum, Int, Const templateType }\n\t}{\n\t\tcollector.elemInfos,\n\t\tfuncDefs,\n\t\tstruct{ String, URL, Enum, Bool, SobekEnum, Int, Const templateType }{\n\t\t\tstringTemplate, urlTemplate, enumTemplate, boolTemplate, nullableEnumTemplate, intTemplate, constTemplate,\n\t\t},\n\t})\n\tif err != nil {\n\t\tlogrus.WithError(err).Fatal(\"Unable to execute template\")\n\t}\n\n\tsrc, err := format.Source(buf.Bytes())\n\tif err != nil {\n\t\tlogrus.WithError(err).Fatal(\"format.Source on generated code failed\")\n\t}\n\n\tf, err := os.Create(\"elements_gen.go\") //nolint:forbidigo\n\tif err != nil {\n\t\tlogrus.WithError(err).Fatal(\"Unable to create the file 'elements_gen.go'\")\n\t}\n\n\tif _, err = f.Write(src); err != nil {\n\t\tlogrus.WithError(err).Fatal(\"Unable to write to 'elements_gen.go'\")\n\t}\n\n\terr = f.Close()\n\tif err != nil {\n\t\tlogrus.WithError(err).Fatal(\"Unable to close 'elements_gen.go'\")\n\t}\n}\n\n//nolint:gochecknoglobals\nvar elemFuncsTemplate = template.Must(template.New(\"\").Funcs(template.FuncMap{\n\t\"buildStruct\":  buildStruct,\n\t\"returnType\":   returnType,\n\t\"receiverName\": receiverName,\n}).Parse(`// generated by js/modules/k6/html/gen/gen_elements.go;  DO NOT EDIT\npackage html\n\nimport \"github.com/grafana/sobek\"\n\nfunc selToElement(sel Selection) sobek.Value {\n\tif sel.sel.Length() == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\telem := Element{sel.sel.Nodes[0], &sel}\n\n\tswitch elem.node.Data {\n{{- range $elemName, $elemInfo := .ElemInfos }}\n\tcase {{ $elemName }}TagName:\n\t\treturn sel.rt.ToValue({{ buildStruct $elemInfo }})\n{{- end }}\n\tdefault:\n\t\treturn sel.rt.ToValue(elem)\n\t}\n }\n\n{{ $templateTypes := .TemplateTypes }}\n{{ range $funcDef := .FuncDefs -}}\n\nfunc ({{ receiverName $funcDef.Elem }} {{$funcDef.Elem}}) {{$funcDef.Method}}() {{ returnType $funcDef.TemplateType }} {\n{{- if eq $funcDef.TemplateType $templateTypes.Int }}\n\treturn {{ receiverName $funcDef.Elem }}.attrAsInt(\"{{ $funcDef.Attr }}\", {{ index $funcDef.TemplateArgs 0 }})\n{{- else if eq $funcDef.TemplateType $templateTypes.Enum }}\n\tattrVal := {{ receiverName $funcDef.Elem }}.attrAsString(\"{{ $funcDef.Attr }}\")\n\tswitch attrVal {\n\t{{- range $optIdx, $optVal := $funcDef.TemplateArgs }}\n\t{{- if ne $optIdx 0 }}\n\tcase \"{{$optVal}}\":\n\t\treturn attrVal\n\t{{- end }}\n\t{{- end}}\n\tdefault:\n\t\treturn \"{{ index $funcDef.TemplateArgs 0 }}\"\n\t}\n{{- else if eq $funcDef.TemplateType $templateTypes.SobekEnum }}\n\tattrVal, exists := {{ receiverName $funcDef.Elem }}.sel.sel.Attr(\"{{ $funcDef.Attr }}\")\n\tif !exists {\n\t\treturn sobek.Undefined()\n\t}\n\tswitch attrVal {\n\t{{- range $optVal := $funcDef.TemplateArgs }}\n\tcase \"{{$optVal}}\":\n\t\treturn {{ receiverName $funcDef.Elem }}.sel.rt.ToValue(attrVal)\n\t{{- end}}\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n{{- else if eq $funcDef.TemplateType $templateTypes.Const }}\n\treturn \"{{ index $funcDef.TemplateArgs 0 }}\"\n{{- else if eq $funcDef.TemplateType $templateTypes.URL }}\n\treturn {{ receiverName $funcDef.Elem }}.attrAsURLString(\"{{ $funcDef.Attr }}\", {{ index $funcDef.TemplateArgs 0 }})\n{{- else if eq $funcDef.TemplateType $templateTypes.String }}\n\treturn {{ receiverName $funcDef.Elem }}.attrAsString(\"{{ $funcDef.Attr }}\")\n{{- else if eq $funcDef.TemplateType $templateTypes.Bool }}\n\treturn {{ receiverName $funcDef.Elem }}.attrIsPresent(\"{{ $funcDef.Attr }}\")\n{{- end}}\n}\n{{ end }}\n`))\n\n// generate the nested struct, either one or two levels of nesting,\n// ie \"BaseElement{elem}\" or \"ButtonElement{FormFieldElement{elem}})\"\nfunc buildStruct(ei elemInfo) string {\n\tif ei.PrtStructName == \"Element\" {\n\t\treturn ei.StructName + \"{elem}\"\n\t}\n\treturn ei.StructName + \"{\" + ei.PrtStructName + \"{elem}}\"\n}\n\n// Select the correct return type for one of the attribute accessor methods\nfunc returnType(tt templateType) string {\n\tswitch tt {\n\tcase boolTemplate:\n\t\treturn \"bool\"\n\tcase intTemplate:\n\t\treturn \"int\"\n\tcase nullableEnumTemplate:\n\t\treturn \"sobek.Value\"\n\tdefault:\n\t\treturn \"string\"\n\t}\n}\n\n// return the name of the receiver given the name of the type\nfunc receiverName(t string) string {\n\treturn strings.ToLower(t[:1])\n}\n\n// Default node handler functions for ast.Inspect. Return itself unless it's found a \"const\" or \"struct\" keyword\nfunc (ce *astInspectState) defaultHandler(node ast.Node) nodeHandlerFunc {\n\tce.elemName = \"\"\n\tswitch node.(type) {\n\tcase *ast.TypeSpec: // struct keyword\n\t\treturn ce.elementStructHandler\n\n\tcase *ast.ValueSpec: // const keyword\n\t\treturn ce.elementTagNameHandler\n\n\tdefault:\n\t\treturn ce.defaultHandler\n\t}\n}\n\n// Found a tagname constant. The code 'const AnchorTagName = \"a\"' will add an ElemInfo called \"Anchor\",\n// like elemInfos[\"Anchor\"] = ElemInfo{\"\", \"\"}\nfunc (ce *astInspectState) elementTagNameHandler(node ast.Node) nodeHandlerFunc {\n\tswitch x := node.(type) {\n\tcase *ast.Ident:\n\t\tif before, ok := strings.CutSuffix(x.Name, \"TagName\"); ok {\n\t\t\tce.elemName = before\n\t\t\tce.elemInfos[ce.elemName] = &elemInfo{\"\", \"\"}\n\t\t}\n\n\t\treturn ce.defaultHandler\n\n\tdefault:\n\t\treturn ce.defaultHandler\n\t}\n}\n\n// A struct definition was found, keep the elem handler if it's for an Element struct\n// Element structs nest the \"Element\" struct or an intermediate struct like \"HrefElement\",\n// the name of the 'parent' struct is contained in the\n// *ast.Ident node located a few nodes after the TypeSpec node containing struct keyword\n// The nodes in between the ast.TypeSpec and ast.Ident are ignored\nfunc (ce *astInspectState) elementStructHandler(node ast.Node) nodeHandlerFunc {\n\tswitch x := node.(type) {\n\tcase *ast.Ident:\n\t\tif !strings.HasSuffix(x.Name, \"Element\") {\n\t\t\treturn ce.defaultHandler\n\t\t}\n\n\t\tif ce.elemName == \"\" {\n\t\t\tce.elemName = strings.TrimSuffix(x.Name, \"Element\")\n\t\t\t// Ignore elements which don't have a tag name constant meaning no elemInfo\n\t\t\t// structure was created by the TagName handle.\n\t\t\t// It skips the Href, Media, FormField, Mod, TableSection or TableCell structs\n\t\t\t// as these structs are inherited by other elements and not created indepedently.\n\t\t\tif _, ok := ce.elemInfos[ce.elemName]; !ok {\n\t\t\t\treturn ce.defaultHandler\n\t\t\t}\n\n\t\t\tce.elemInfos[ce.elemName].StructName = x.Name\n\t\t\treturn ce.elementStructHandler\n\t\t}\n\n\t\tce.elemInfos[ce.elemName].PrtStructName = x.Name\n\t\treturn ce.defaultHandler\n\n\tcase *ast.StructType:\n\t\treturn ce.elementStructHandler\n\n\tcase *ast.FieldList:\n\t\treturn ce.elementStructHandler\n\n\tcase *ast.Field:\n\t\treturn ce.elementStructHandler\n\n\tdefault:\n\t\treturn ce.defaultHandler\n\t}\n}\n"
  },
  {
    "path": "js/modules/k6/html/html.go",
    "content": "package html\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/PuerkitoBio/goquery\"\n\t\"github.com/grafana/sobek\"\n\tgohtml \"golang.org/x/net/html\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// RootModule is the global module object type. It is instantiated once per test\n// run and will be used to create k6/html module instances for each VU.\ntype RootModule struct{}\n\n// ModuleInstance represents an instance of the HTML module for every VU.\ntype ModuleInstance struct {\n\tvu         modules.VU\n\trootModule *RootModule\n\texports    *sobek.Object\n}\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// New returns a pointer to a new HTML RootModule.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// Exports returns the JS values this module exports.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tDefault: mi.exports,\n\t}\n}\n\n// NewModuleInstance returns an HTML module instance for each VU.\nfunc (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\trt := vu.Runtime()\n\tmi := &ModuleInstance{\n\t\tvu:         vu,\n\t\trootModule: r,\n\t\texports:    rt.NewObject(),\n\t}\n\tif err := mi.exports.Set(\"parseHTML\", mi.parseHTML); err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\treturn mi\n}\n\nfunc (mi *ModuleInstance) parseHTML(src string) (Selection, error) {\n\treturn ParseHTML(mi.vu.Runtime(), src)\n}\n\n// ParseHTML parses the provided HTML source into a Selection object.\nfunc ParseHTML(rt *sobek.Runtime, src string) (Selection, error) {\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(src))\n\tif err != nil {\n\t\treturn Selection{}, err\n\t}\n\treturn Selection{rt: rt, sel: doc.Selection}, nil\n}\n\ntype Selection struct {\n\trt  *sobek.Runtime\n\tsel *goquery.Selection\n\tURL string `json:\"url\"`\n}\n\nfunc (s Selection) emptySelection() Selection {\n\t// Goquery has no direct way to return an empty selection apart from asking for an out of bounds item.\n\treturn s.Eq(s.Size())\n}\n\nfunc (s Selection) buildMatcher(v sobek.Value, sobekFn sobek.Callable) func(int, *goquery.Selection) bool {\n\treturn func(idx int, sel *goquery.Selection) bool {\n\t\tfnRes, fnErr := sobekFn(v, s.rt.ToValue(idx), s.rt.ToValue(sel))\n\t\tif fnErr != nil {\n\t\t\tcommon.Throw(s.rt, fnErr)\n\t\t}\n\n\t\treturn fnRes.ToBoolean()\n\t}\n}\n\nfunc (s Selection) varargFnCall(arg any,\n\tstrFilter func(string) *goquery.Selection,\n\tselFilter func(*goquery.Selection) *goquery.Selection,\n\tnodeFilter func(...*gohtml.Node) *goquery.Selection,\n) Selection {\n\tswitch v := arg.(type) {\n\tcase Selection:\n\t\treturn Selection{s.rt, selFilter(v.sel), s.URL}\n\n\tcase string:\n\t\treturn Selection{s.rt, strFilter(v), s.URL}\n\n\tcase Element:\n\t\treturn Selection{s.rt, nodeFilter(v.node), s.URL}\n\n\tcase sobek.Value:\n\t\treturn s.varargFnCall(v.Export(), strFilter, selFilter, nodeFilter)\n\n\tdefault:\n\t\terr := fmt.Errorf(\"invalid argument, cannot use a '%T' as a selector\", arg)\n\t\tpanic(s.rt.NewGoError(err))\n\t}\n}\n\nfunc (s Selection) adjacent(unfiltered func() *goquery.Selection,\n\tfiltered func(string) *goquery.Selection,\n\tdef ...string,\n) Selection {\n\tif len(def) > 0 {\n\t\treturn Selection{s.rt, filtered(def[0]), s.URL}\n\t}\n\n\treturn Selection{s.rt, unfiltered(), s.URL}\n}\n\nfunc (s Selection) adjacentUntil(until func(string) *goquery.Selection,\n\tuntilSelection func(*goquery.Selection) *goquery.Selection,\n\tfilteredUntil func(string, string) *goquery.Selection,\n\tfilteredUntilSelection func(string, *goquery.Selection) *goquery.Selection,\n\tdef ...sobek.Value,\n) Selection {\n\tswitch len(def) {\n\tcase 0:\n\t\treturn Selection{s.rt, until(\"\"), s.URL}\n\tcase 1:\n\t\tswitch selector := def[0].Export().(type) {\n\t\tcase string:\n\t\t\treturn Selection{s.rt, until(selector), s.URL}\n\n\t\tcase Selection:\n\t\t\treturn Selection{s.rt, untilSelection(selector.sel), s.URL}\n\n\t\tcase nil:\n\t\t\treturn Selection{s.rt, until(\"\"), s.URL}\n\t\t}\n\tcase 2:\n\t\tfilter := def[1].String()\n\n\t\tswitch selector := def[0].Export().(type) {\n\t\tcase string:\n\t\t\treturn Selection{s.rt, filteredUntil(filter, selector), s.URL}\n\n\t\tcase Selection:\n\t\t\treturn Selection{s.rt, filteredUntilSelection(filter, selector.sel), s.URL}\n\n\t\tcase nil:\n\t\t\treturn Selection{s.rt, filteredUntil(filter, \"\"), s.URL}\n\t\t}\n\t}\n\n\terr := fmt.Errorf(\"invalid argument, cannot use a '%T' as a selector\", def[0].Export())\n\tpanic(s.rt.NewGoError(err))\n}\n\nfunc (s Selection) Add(arg any) Selection {\n\treturn s.varargFnCall(arg, s.sel.Add, s.sel.AddSelection, s.sel.AddNodes)\n}\n\nfunc (s Selection) Find(arg any) Selection {\n\treturn s.varargFnCall(arg, s.sel.Find, s.sel.FindSelection, s.sel.FindNodes)\n}\n\nfunc (s Selection) Closest(arg any) Selection {\n\treturn s.varargFnCall(arg, s.sel.Closest, s.sel.ClosestSelection, s.sel.ClosestNodes)\n}\n\nfunc (s Selection) Has(arg any) Selection {\n\treturn s.varargFnCall(arg, s.sel.Has, s.sel.HasSelection, s.sel.HasNodes)\n}\n\nfunc (s Selection) Not(v sobek.Value) Selection {\n\tsobekFn, isFn := sobek.AssertFunction(v)\n\tif !isFn {\n\t\treturn s.varargFnCall(v, s.sel.Not, s.sel.NotSelection, s.sel.NotNodes)\n\t}\n\n\treturn Selection{s.rt, s.sel.NotFunction(s.buildMatcher(v, sobekFn)), s.URL}\n}\n\nfunc (s Selection) Next(def ...string) Selection {\n\treturn s.adjacent(s.sel.Next, s.sel.NextFiltered, def...)\n}\n\nfunc (s Selection) NextAll(def ...string) Selection {\n\treturn s.adjacent(s.sel.NextAll, s.sel.NextAllFiltered, def...)\n}\n\nfunc (s Selection) Prev(def ...string) Selection {\n\treturn s.adjacent(s.sel.Prev, s.sel.PrevFiltered, def...)\n}\n\nfunc (s Selection) PrevAll(def ...string) Selection {\n\treturn s.adjacent(s.sel.PrevAll, s.sel.PrevAllFiltered, def...)\n}\n\nfunc (s Selection) Parent(def ...string) Selection {\n\treturn s.adjacent(s.sel.Parent, s.sel.ParentFiltered, def...)\n}\n\nfunc (s Selection) Parents(def ...string) Selection {\n\treturn s.adjacent(s.sel.Parents, s.sel.ParentsFiltered, def...)\n}\n\nfunc (s Selection) Siblings(def ...string) Selection {\n\treturn s.adjacent(s.sel.Siblings, s.sel.SiblingsFiltered, def...)\n}\n\n// PrevUntil returns all preceding siblings of each element up to but not including the element matched by the selector.\n// The arguments are:\n// 1st argument is the selector. Either a selector string, a Selection object, or nil\n// 2nd argument is the filter. Either a selector string or nil/undefined\nfunc (s Selection) PrevUntil(def ...sobek.Value) Selection {\n\treturn s.adjacentUntil(\n\t\ts.sel.PrevUntil,\n\t\ts.sel.PrevUntilSelection,\n\t\ts.sel.PrevFilteredUntil,\n\t\ts.sel.PrevFilteredUntilSelection,\n\t\tdef...,\n\t)\n}\n\n// NextUntil returns all following siblings of each element up to but not including the element matched by the selector.\n// The arguments are:\n// 1st argument is the selector. Either a selector string, a Selection object, or nil\n// 2nd argument is the filter. Either a selector string or nil/undefined\nfunc (s Selection) NextUntil(def ...sobek.Value) Selection {\n\treturn s.adjacentUntil(\n\t\ts.sel.NextUntil,\n\t\ts.sel.NextUntilSelection,\n\t\ts.sel.NextFilteredUntil,\n\t\ts.sel.NextFilteredUntilSelection,\n\t\tdef...,\n\t)\n}\n\n// ParentsUntil returns the ancestors of each element in the current set of matched elements,\n// up to but not including the element matched by the selector\n// The arguments are:\n// 1st argument is the selector. Either a selector string, a Selection object, or nil\n// 2nd argument is the filter. Either a selector string or nil/undefined\nfunc (s Selection) ParentsUntil(def ...sobek.Value) Selection {\n\treturn s.adjacentUntil(\n\t\ts.sel.ParentsUntil,\n\t\ts.sel.ParentsUntilSelection,\n\t\ts.sel.ParentsFilteredUntil,\n\t\ts.sel.ParentsFilteredUntilSelection,\n\t\tdef...,\n\t)\n}\n\nfunc (s Selection) Size() int {\n\treturn s.sel.Length()\n}\n\nfunc (s Selection) End() Selection {\n\treturn Selection{s.rt, s.sel.End(), s.URL}\n}\n\nfunc (s Selection) Eq(idx int) Selection {\n\treturn Selection{s.rt, s.sel.Eq(idx), s.URL}\n}\n\nfunc (s Selection) First() Selection {\n\treturn Selection{s.rt, s.sel.First(), s.URL}\n}\n\nfunc (s Selection) Last() Selection {\n\treturn Selection{s.rt, s.sel.Last(), s.URL}\n}\n\nfunc (s Selection) Contents() Selection {\n\treturn Selection{s.rt, s.sel.Contents(), s.URL}\n}\n\nfunc (s Selection) Text() string {\n\treturn s.sel.Text()\n}\n\nfunc (s Selection) Attr(name string, def ...sobek.Value) sobek.Value {\n\tval, exists := s.sel.Attr(name)\n\tif !exists {\n\t\tif len(def) > 0 {\n\t\t\treturn def[0]\n\t\t}\n\t\treturn sobek.Undefined()\n\t}\n\treturn s.rt.ToValue(val)\n}\n\n//nolint:revive // var-naming wants this to be HTML but this will break the API\nfunc (s Selection) Html() sobek.Value {\n\tval, err := s.sel.Html()\n\tif err != nil {\n\t\treturn sobek.Undefined()\n\t}\n\treturn s.rt.ToValue(val)\n}\n\nfunc (s Selection) Val() sobek.Value {\n\tswitch goquery.NodeName(s.sel) {\n\tcase InputTagName:\n\t\tval, exists := s.sel.Attr(\"value\")\n\t\tif !exists {\n\t\t\tinputType, _ := s.sel.Attr(\"type\")\n\t\t\tif inputType == \"radio\" || inputType == \"checkbox\" {\n\t\t\t\tval = \"on\"\n\t\t\t} else {\n\t\t\t\tval = \"\"\n\t\t\t}\n\t\t}\n\t\treturn s.rt.ToValue(val)\n\n\tcase ButtonTagName:\n\t\tval, exists := s.sel.Attr(\"value\")\n\t\tif !exists {\n\t\t\tval = \"\"\n\t\t}\n\t\treturn s.rt.ToValue(val)\n\n\tcase TextAreaTagName:\n\t\treturn s.Html()\n\n\tcase OptionTagName:\n\t\treturn s.rt.ToValue(valueOrHTML(s.sel))\n\n\tcase SelectTagName:\n\t\tselected := s.sel.First().Find(\"option[selected]\")\n\t\tif _, exists := s.sel.Attr(\"multiple\"); exists {\n\t\t\treturn s.rt.ToValue(selected.Map(func(_ int, opt *goquery.Selection) string { return valueOrHTML(opt) }))\n\t\t}\n\n\t\treturn s.rt.ToValue(valueOrHTML(selected))\n\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n}\n\nfunc (s Selection) Children(def ...string) Selection {\n\tif len(def) == 0 {\n\t\treturn Selection{s.rt, s.sel.Children(), s.URL}\n\t}\n\n\treturn Selection{s.rt, s.sel.ChildrenFiltered(def[0]), s.URL}\n}\n\nfunc (s Selection) Each(v sobek.Value) Selection {\n\tsobekFn, isFn := sobek.AssertFunction(v)\n\tif !isFn {\n\t\tcommon.Throw(s.rt, errors.New(\"the argument to each() must be a function\"))\n\t}\n\n\tfn := func(idx int, _ *goquery.Selection) {\n\t\tif _, err := sobekFn(v, s.rt.ToValue(idx), selToElement(Selection{s.rt, s.sel.Eq(idx), s.URL})); err != nil {\n\t\t\tcommon.Throw(s.rt, fmt.Errorf(\"the function passed to each() failed: %w\", err))\n\t\t}\n\t}\n\n\treturn Selection{s.rt, s.sel.Each(fn), s.URL}\n}\n\nfunc (s Selection) Filter(v sobek.Value) Selection {\n\tswitch val := v.Export().(type) {\n\tcase string:\n\t\treturn Selection{s.rt, s.sel.Filter(val), s.URL}\n\n\tcase Selection:\n\t\treturn Selection{s.rt, s.sel.FilterSelection(val.sel), s.URL}\n\t}\n\n\tsobekFn, isFn := sobek.AssertFunction(v)\n\tif !isFn {\n\t\tcommon.Throw(s.rt, errors.New(\"the argument to filter() must be a function, a selector or a selection\"))\n\t}\n\n\treturn Selection{s.rt, s.sel.FilterFunction(s.buildMatcher(v, sobekFn)), s.URL}\n}\n\nfunc (s Selection) Is(v sobek.Value) bool {\n\tswitch val := v.Export().(type) {\n\tcase string:\n\t\treturn s.sel.Is(val)\n\n\tcase Selection:\n\t\treturn s.sel.IsSelection(val.sel)\n\n\tdefault:\n\t\tsobekFn, isFn := sobek.AssertFunction(v)\n\t\tif !isFn {\n\t\t\tcommon.Throw(s.rt, errors.New(\"the argument to is() must be a function, a selector or a selection\"))\n\t\t}\n\n\t\treturn s.sel.IsFunction(s.buildMatcher(v, sobekFn))\n\t}\n}\n\n// Map implements ES5 Array.prototype.map\nfunc (s Selection) Map(v sobek.Value) []sobek.Value {\n\tsobekFn, isFn := sobek.AssertFunction(v)\n\tif !isFn {\n\t\tcommon.Throw(s.rt, errors.New(\"the argument to map() must be a function\"))\n\t}\n\n\tvar values []sobek.Value\n\ts.sel.Each(func(idx int, sel *goquery.Selection) {\n\t\tselection := &Selection{sel: sel, URL: s.URL, rt: s.rt}\n\n\t\tif fnRes, fnErr := sobekFn(v, s.rt.ToValue(idx), s.rt.ToValue(selection)); fnErr == nil {\n\t\t\tvalues = append(values, fnRes)\n\t\t}\n\t})\n\n\treturn values\n}\n\nfunc (s Selection) Slice(start int, def ...int) Selection {\n\t// We are forced to check that def[0] is inferior to the length of the array\n\t// otherwise the s.sel.Slice panics. Besides returning the whole array when\n\t// the end value for slicing is superior to the array length is standard in js.\n\tif len(def) > 0 && def[0] < len(s.sel.Nodes) {\n\t\treturn Selection{s.rt, s.sel.Slice(start, def[0]), s.URL}\n\t}\n\n\treturn Selection{s.rt, s.sel.Slice(start, s.sel.Length()), s.URL}\n}\n\nfunc (s Selection) Get(def ...int) sobek.Value {\n\tswitch {\n\tcase len(def) == 0:\n\t\tvar items []sobek.Value\n\t\tfor i := 0; i < len(s.sel.Nodes); i++ {\n\t\t\titems = append(items, selToElement(s.Eq(i)))\n\t\t}\n\t\treturn s.rt.ToValue(items)\n\n\tcase def[0] < s.sel.Length() && def[0] > -s.sel.Length():\n\t\treturn selToElement(s.Eq(def[0]))\n\n\tdefault:\n\t\treturn sobek.Undefined()\n\t}\n}\n\nfunc (s Selection) ToArray() []Selection {\n\titems := make([]Selection, len(s.sel.Nodes))\n\tfor i := range s.sel.Nodes {\n\t\titems[i] = Selection{s.rt, s.sel.Eq(i), s.URL}\n\t}\n\treturn items\n}\n\nfunc (s Selection) Index(def ...sobek.Value) int {\n\tif len(def) == 0 {\n\t\treturn s.sel.Index()\n\t}\n\n\tswitch v := def[0].Export().(type) {\n\tcase Selection:\n\t\treturn s.sel.IndexOfSelection(v.sel)\n\n\tcase string:\n\t\treturn s.sel.IndexSelector(v)\n\n\tcase Element:\n\t\treturn s.sel.IndexOfNode(v.node)\n\n\tdefault:\n\t\treturn -1\n\t}\n}\n\n// Data return the value at the named data store for the first element in the set of matched elements.\n// Mimics jquery.data\n//\n// When 0 arguments: Read all data from attributes beginning with \"data-\".\n// When 1 argument: Append argument to \"data-\" then find for a matching attribute\nfunc (s Selection) Data(def ...string) sobek.Value {\n\tif s.sel.Length() == 0 || len(s.sel.Nodes[0].Attr) == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\tif len(def) > 0 {\n\t\tval, exists := s.sel.Attr(\"data-\" + propertyToAttr(def[0]))\n\t\tif exists {\n\t\t\treturn s.rt.ToValue(convertDataAttrVal(val))\n\t\t}\n\t\treturn sobek.Undefined()\n\t}\n\tdata := make(map[string]any)\n\tfor _, attr := range s.sel.Nodes[0].Attr {\n\t\tif strings.HasPrefix(attr.Key, \"data-\") && len(attr.Key) > 5 {\n\t\t\tdata[attrToProperty(attr.Key[5:])] = convertDataAttrVal(attr.Val)\n\t\t}\n\t}\n\treturn s.rt.ToValue(data)\n}\n"
  },
  {
    "path": "js/modules/k6/html/html_test.go",
    "content": "package html\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst testHTML = `\n<html>\n<head>\n\t<title>This is the title</title>\n</head>\n<body>\n\t<h1 id=\"top\" data-test=\"dataval\" data-num-a=\"123\" data-num-b=\"1.5\" data-not-num-a=\"1.50\" data-not-num-b=\"1.1e02\">Lorem ipsum</h1>\n\n\t<p data-test-b=\"true\" data-opts='{\"id\":101}' data-test-empty=\"\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac dui erat. Pellentesque eu euismod odio, eget fringilla ante. In vitae nulla at est tincidunt gravida sit amet maximus arcu. Sed accumsan tristique massa, blandit sodales quam malesuada eu. Morbi vitae luctus augue. Nunc nec ligula quam. Cras fringilla nulla leo, at dignissim enim accumsan vitae. Sed eu cursus sapien, a rhoncus lorem. Etiam sed massa egestas, bibendum quam sit amet, eleifend ipsum. Maecenas mi ante, consectetur at tincidunt id, suscipit nec sem. Integer congue elit vel ligula commodo ultricies. Suspendisse condimentum laoreet ligula at aliquet.</p>\n\t<p>Nullam id nisi eget ex pharetra imperdiet. Maecenas augue ligula, aliquet sit amet maximus ut, vestibulum et magna. Nam in arcu sed tortor volutpat porttitor sed eget dolor. Duis rhoncus est id dui porttitor, id molestie ex imperdiet. Proin purus ligula, pretium eleifend felis a, tempor feugiat mi. Cras rutrum pulvinar neque, eu dictum arcu. Cras purus metus, fermentum eget malesuada sit amet, dignissim non dui.</p>\n\n\t<form id=\"form1\">\n\t\t<input id=\"text_input\" name=\"text_input\" type=\"text\" value=\"input-text-value\"/>\n\t\t<select id=\"select_one\" name=\"select_one\">\n\t\t\t<option value=\"not this option\">no</option>\n\t\t\t<option value=\"yes this option\" selected>yes</option>\n\t\t</select>\n\t\t<select id=\"select_text\" name=\"select_text\">\n\t\t\t<option>no text</option>\n\t\t\t<option selected>yes text</option>\n\t\t</select>\n\t\t<select id=\"select_multi\" name=\"select_multi\" multiple>\n\t\t\t<option>option 1</option>\n\t\t\t<option selected>option 2</option>\n\t\t\t<option selected>option 3</option>\n\t\t</select>\n\t\t<textarea id=\"textarea\" name=\"textarea\" multiple>Lorem ipsum dolor sit amet</textarea>\n\t</form>\n\n\t<footer>This is the footer.</footer>\n</body>\n`\n\nconst testXML = `\n<ListAllMyBucketsResult>\n   <Buckets>\n      <Bucket>\n          <CreationDate>1654852823</CreationDate>\n          <Name>firstBucket</Name>\n      </Bucket>\n\t  <Bucket>\n\t      <CreationDate>1654852825</CreationDate>\n\t\t  <Name>secondBucket</Name>\n\t  </Bucket>\n   </Buckets>\n   <Owner>\n      <DisplayName>string</DisplayName>\n      <ID>string</ID>\n   </Owner>\n</ListAllMyBucketsResult>\n`\n\nfunc getTestModuleInstance(t testing.TB) (*sobek.Runtime, *ModuleInstance) {\n\trt := sobek.New()\n\trt.SetFieldNameMapper(common.FieldNameMapper{})\n\n\tctx, cancel := context.WithCancel(context.Background())\n\tt.Cleanup(cancel)\n\n\troot := New()\n\tmockVU := &modulestest.VU{\n\t\tRuntimeField: rt,\n\t\tInitEnvField: &common.InitEnvironment{\n\t\t\tTestPreInitState: &lib.TestPreInitState{\n\t\t\t\tRegistry: metrics.NewRegistry(),\n\t\t\t},\n\t\t},\n\t\tCtxField:   ctx,\n\t\tStateField: nil,\n\t}\n\tmi, ok := root.NewModuleInstance(mockVU).(*ModuleInstance)\n\trequire.True(t, ok)\n\n\trequire.NoError(t, rt.Set(\"html\", mi.Exports().Default))\n\n\treturn rt, mi\n}\n\nfunc getTestRuntimeAndModuleInstanceWithDoc(t testing.TB, html string) (*sobek.Runtime, *ModuleInstance) {\n\tt.Helper()\n\n\trt, mi := getTestModuleInstance(t)\n\trequire.NoError(t, rt.Set(\"src\", html))\n\n\t_, err := rt.RunString(`var doc = html.parseHTML(src)`)\n\n\trequire.NoError(t, err)\n\trequire.IsType(t, Selection{}, rt.Get(\"doc\").Export())\n\n\treturn rt, mi\n}\n\nfunc getTestRuntimeWithDoc(t testing.TB, html string) *sobek.Runtime {\n\tt.Helper()\n\n\trt, _ := getTestRuntimeAndModuleInstanceWithDoc(t, html)\n\n\treturn rt\n}\n\nfunc TestParseHTML(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Find\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"h1\")`)\n\t\tif assert.NoError(t, err) && assert.IsType(t, Selection{}, v.Export()) {\n\t\t\tsel := v.Export().(Selection).sel\n\t\t\tassert.Equal(t, 1, sel.Length())\n\t\t\tassert.Equal(t, \"Lorem ipsum\", sel.Text())\n\t\t}\n\t})\n\tt.Run(\"Add\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"Selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").add(\"footer\")`)\n\t\t\tif assert.NoError(t, err) && assert.IsType(t, Selection{}, v.Export()) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t\tassert.Equal(t, \"Lorem ipsumThis is the footer.\", sel.Text())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Selection\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").add(doc.find(\"footer\"))`)\n\t\t\tif assert.NoError(t, err) && assert.IsType(t, Selection{}, v.Export()) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t\tassert.Equal(t, \"Lorem ipsumThis is the footer.\", sel.Text())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Text\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"h1\").text()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"Lorem ipsum\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"Attr\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"h1\").attr(\"id\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"top\", v.Export())\n\t\t}\n\t\tt.Run(\"Default\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").attr(\"id\", \"default\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"top\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Unset\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").attr(\"class\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.True(t, sobek.IsUndefined(v), \"v is not undefined: %v\", v)\n\t\t\t}\n\n\t\t\tt.Run(\"Default\", func(t *testing.T) {\n\t\t\t\tv, err := rt.RunString(`doc.find(\"h1\").attr(\"class\", \"default\")`)\n\t\t\t\tif assert.NoError(t, err) {\n\t\t\t\t\tassert.Equal(t, \"default\", v.Export())\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t})\n\tt.Run(\"Html\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"h1\").html()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"Lorem ipsum\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"Val\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"Input\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#text_input\").val()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"input-text-value\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Select option[selected]\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#select_one option[selected]\").val()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"yes this option\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Select Option Attr\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#select_one\").val()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"yes this option\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Select Option Text\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#select_text\").val()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"yes text\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Select Option Multiple\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#select_multi\").val()`)\n\t\t\tvar opts []string\n\t\t\tif assert.NoError(t, err) && rt.ExportTo(v, &opts) == nil {\n\t\t\t\tassert.Equal(t, 2, len(opts))\n\t\t\t\tassert.Equal(t, \"option 2\", opts[0])\n\t\t\t\tassert.Equal(t, \"option 3\", opts[1])\n\t\t\t}\n\t\t})\n\t\tt.Run(\"TextArea\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#textarea\").val()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"Lorem ipsum dolor sit amet\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Children\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"All\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"head\").children()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 1, sel.Length())\n\t\t\t\tassert.True(t, sel.Is(\"title\"))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"With selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children(\"p\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t\tassert.Equal(t, \"Nullam id nisi\", sel.Last().Text()[0:14])\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Closest\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"textarea\").closest(\"form\").attr(\"id\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"form1\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"Contents\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"head\").contents()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tsel := v.Export().(Selection).sel\n\t\t\tassert.Equal(t, 3, sel.Length())\n\t\t\tassert.Equal(t, \"\\n\\t\", sel.First().Text())\n\t\t}\n\t})\n\tt.Run(\"Each\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"Func arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`{ var elems = []; doc.find(\"#select_multi option\").each(function(idx, elem) { elems[idx] = elem.innerHTML(); }); elems }`)\n\t\t\tvar elems []string\n\t\t\tif assert.NoError(t, err) && rt.ExportTo(v, &elems) == nil {\n\t\t\t\tassert.Equal(t, 3, len(elems))\n\t\t\t\tassert.Equal(t, \"option 1\", elems[0])\n\t\t\t\tassert.Equal(t, \"option 2\", elems[1])\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Invalid arg\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(`doc.find(\"#select_multi option\").each(\"\");`)\n\t\t\tif assert.Error(t, err) {\n\t\t\t\tassert.IsType(t, &sobek.Exception{}, err)\n\t\t\t\tassert.Contains(t, err.Error(), \"must be a function\")\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Is\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"String selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").is(\"h1\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, true, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Function selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").is(function(idx, val){ return val.text() == \"Lorem ipsum\" })`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, true, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Selection selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().first().is(doc.find(\"h1\"))`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, true, v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Filter\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().filter(\"p\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Function\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().filter(function(idx, val){ return val.is(\"p\") })`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Selection\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().filter(doc.find(\"p\"))`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"End\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").children().filter(\"p\").end()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tsel := v.Export().(Selection).sel\n\t\t\tassert.Equal(t, 5, sel.Length())\n\t\t}\n\t})\n\tt.Run(\"Eq\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").children().eq(3).attr(\"id\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"form1\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"First\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").children().first().attr(\"id\")`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"top\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"Last\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"body\").children().last().text()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tassert.Equal(t, \"This is the footer.\", v.Export())\n\t\t}\n\t})\n\tt.Run(\"Has\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"String selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().has(\"input\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(1), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Selection selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().has(doc.find(\"input\")).size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(1), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Map\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"Valid\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#select_multi option\").map(function(idx, val) { return val.text() })`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tmapped, ok := v.Export().([]sobek.Value)\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, 3, len(mapped))\n\t\t\t\tassert.Equal(t, \"option 1\", mapped[0].String())\n\t\t\t\tassert.Equal(t, \"option 2\", mapped[1].String())\n\t\t\t\tassert.Equal(t, \"option 3\", mapped[2].String())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Continues to work with strings\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(`\n\t\t\t\tconst values = doc\n\t\t\t\t\t.find(\"#select_multi option\")\n\t\t\t\t\t.map(function(idx, val) {\n\t\t\t\t\t\treturn val.text()\n\t\t\t\t\t})\n\n\t\t\t\tif (values.length !== 3) {\n\t\t\t\t\tthrow new Error('Expected 3 values, got ' + values.length)\n\t\t\t\t}\n\n\t\t\t\tfor (let i = 0; i < values.length; i++) {\n\t\t\t\t\tif (typeof values[i] !== 'string') {\n\t\t\t\t\t\tthrow new Error('Expected string, got ' + values[i].toString())\n\t\t\t\t\t}\n\n\t\t\t\t\tif (values[i].toString() !== 'option ' + (i + 1)) {\n\t\t\t\t\t\tthrow new Error('Expected value ' + (i + 1) + ', got ' + values[i])\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t`)\n\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"Invalid arg\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(`doc.find(\"#select_multi option\").map(\"\");`)\n\t\t\tif assert.Error(t, err) {\n\t\t\t\tassert.IsType(t, &sobek.Exception{}, err)\n\t\t\t\tassert.Contains(t, err.Error(), \"must be a function\")\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Map with attr must return string\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"#select_multi\").map(function(idx, val) { return val.attr(\"name\") })`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tmapped, ok := v.Export().([]sobek.Value)\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, 1, len(mapped))\n\t\t\t\tassert.Equal(t, \"select_multi\", mapped[0].String())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Valid XML\", func(t *testing.T) {\n\t\t\trt := getTestRuntimeWithDoc(t, testXML)\n\t\t\ttestScript := `\n\t\t\tconst buckets = doc\n\t\t\t\t.find('Buckets')\n\t\t\t\t.children()\n\t\t\t\t.map(function (idx, bucket) {\n\t\t\t\t\tlet bucketObj = {}\n\t\t\t\t\tbucket.children().each(function (idx, elem) {\n\t\t\t\t\t\tswitch (elem.nodeName()) {\n\t\t\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t\t\tObject.assign(bucketObj, { name: elem.textContent() })\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\tcase 'creationdate':\n\t\t\t\t\t\t\t\tObject.assign(bucketObj, { creationDate: parseInt(elem.textContent(), 10) })\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\treturn bucketObj\n\t\t\t\t})\n\n\t\t\tif (buckets.length !== 2) {\n\t\t\t\tthrow new Error('Expected 2 buckets, got ' + buckets.length)\n\t\t\t}\n\n\t\t\tif (buckets[0].name !== 'firstBucket') {\n\t\t\t\tthrow new Error('Expected bucket name to be \"firstBucket\", got ' + buckets[0].name)\n\t\t\t}\n\n\t\t\tif (buckets[0].creationDate !== 1654852823) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Expected bucket creation date to be 1654852823, got ' + buckets[0].creationDate\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tif (buckets[1].name != 'secondBucket') {\n\t\t\t\tthrow new Error('Expected bucket name to be \"secondBucket\", got ' + buckets[1].name)\n\t\t\t}\n\n\t\t\tif (buckets[1].creationDate !== 1654852825) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Expected bucket creation date to be 1654852825, got ' + buckets[1].creationDate\n\t\t\t\t)\n\t\t\t}\n\t\t\t`\n\n\t\t\t_, err := rt.RunString(testScript)\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n\tt.Run(\"Next\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").next()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 1, sel.Length())\n\t\t\t\tassert.True(t, sel.Is(\"p\"))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filter arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").next(\"form\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 1, sel.Length())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"NextAll\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextAll()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 4, sel.Length())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filter arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextAll(\"p\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Prev\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"footer\").prev()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.True(t, sel.Is(\"form\"))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filter arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"footer\").prev(\"form\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 1, sel.Length())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"PrevAll\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").prevAll()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 3, sel.Length())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filter arg\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").prevAll(\"p\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"PrevUntil\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"footer\").prevUntil(\"h1\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Query\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"footer\").prevUntil(doc.find(\"h1\")).size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"String filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").prevUntil(\"h1\", \"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Query filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").prevUntil(doc.find(\"h1\"), \"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"All\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"footer\").prevUntil().size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(4), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"All filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"footer\").prevUntil(null, \"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"NextUntil\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextUntil(\"footer\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Query\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextUntil(doc.find(\"footer\")).size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"String filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextUntil(\"footer\", \"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Query filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextUntil(doc.find(\"footer\"), \"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"All\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextUntil().size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(4), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"All filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").nextUntil(null, \"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Parent\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No filter\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parent().attr(\"id\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form1\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parent(\"form\").attr(\"id\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"form1\", v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Parents\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No filter\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parents().size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parents(\"body\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(1), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"ParentsUntil\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parentsUntil(\"html\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Query\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parentsUntil(doc.find(\"html\")).size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"String filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parentsUntil(\"html\", \"body\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(1), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Query filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parentsUntil(doc.find(\"html\"), \"body\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(1), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"All\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parentsUntil().size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"All filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"textarea\").parentsUntil(null, \"body\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(1), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Not\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"String selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().not(\"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Selection selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().not(doc.find(\"p\")).size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Function selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().not(function(idx, val){ return val.is(\"p\") }).size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Siblings\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No filter\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").siblings().size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(4), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").siblings(\"p\").size()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(2), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Slice\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No filter\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().slice(1, 2)`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 1, sel.Length())\n\t\t\t\tassert.True(t, sel.Is(\"p\"))\n\t\t\t\tassert.Contains(t, sel.Text(), \"Lorem ipsum dolor\")\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Filtered\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().slice(3)`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tsel := v.Export().(Selection).sel\n\t\t\t\tassert.Equal(t, 2, sel.Length())\n\t\t\t\tassert.Equal(t, true, sel.Eq(0).Is(\"form\"))\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Get\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No args\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().get()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\telems, ok := v.Export().([]sobek.Value)\n\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, \"h1\", elems[0].Export().(Element).NodeName())\n\t\t\t\tassert.Equal(t, \"p\", elems[1].Export().(Element).NodeName())\n\t\t\t\tassert.Equal(t, \"footer\", elems[4].Export().(Element).NodeName())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"+ve index\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().get(1)`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\telem, _ := v.Export().(Element)\n\t\t\t\tassert.Contains(t, elem.InnerHTML().Export(), \"Lorem ipsum dolor sit amet\")\n\t\t\t}\n\t\t})\n\t\tt.Run(\"-ve index\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().get(-1)`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\telem, _ := v.Export().(Element)\n\t\t\t\tassert.Equal(t, \"This is the footer.\", elem.InnerHTML().String())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"ToArray\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"p\").toArray()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tarr, ok := v.Export().([]Selection)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, 2, len(arr))\n\t\t\tassert.Equal(t, 1, arr[0].sel.Length())\n\t\t\tassert.Equal(t, 1, arr[1].sel.Length())\n\t\t\tassert.Contains(t, arr[0].sel.Text(), \"Lorem ipsum dolor sit amet\")\n\t\t\tassert.Contains(t, arr[1].sel.Text(), \"Nullam id nisi eget\")\n\t\t}\n\t})\n\tt.Run(\"Index\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"No args\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").index()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(1), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"String selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").index(\"body > *\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(3), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"Selection selector\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"body\").children().index(doc.find(\"footer\"))`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(4), v.Export())\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Data <h1>\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"string attr\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").data(\"test\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"dataval\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"numeric attr 1\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").data(\"num-a\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(123), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"numeric attr 2\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").data(\"num-b\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, float64(1.5), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"not numeric attr 1\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").data(\"not-num-a\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"1.50\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"not numeric attr 2\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").data(\"not-num-b\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, \"1.1e02\", v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"dataset\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"h1\").data()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tdata, ok := v.Export().(map[string]any)\n\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, \"dataval\", data[\"test\"])\n\t\t\t\tassert.Equal(t, float64(123), data[\"numA\"])\n\t\t\t}\n\t\t})\n\t})\n\tt.Run(\"Data <p>\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testHTML)\n\n\t\tt.Run(\"boolean attr\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").data(\"test-b\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, true, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"snakeCase attr name\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").data(\"testB\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, true, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"empty string\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").data(\"test-empty\")`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, nil, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"json attr\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").data(\"opts\").id`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(101), v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"dataset property\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").data().testB`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, true, v.Export())\n\t\t\t}\n\t\t})\n\t\tt.Run(\"dataset object\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"p\").data().opts.id`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tassert.Equal(t, int64(101), v.Export())\n\t\t\t}\n\t\t})\n\t})\n}\n"
  },
  {
    "path": "js/modules/k6/html/serialize.go",
    "content": "package html\n\nimport (\n\tneturl \"net/url\"\n\n\t\"github.com/PuerkitoBio/goquery\"\n\t\"github.com/grafana/sobek\"\n)\n\ntype FormValue struct {\n\tName  string\n\tValue sobek.Value\n}\n\nfunc (s Selection) SerializeArray() []FormValue {\n\tsubmittableSelector := \"input,select,textarea,keygen\"\n\tvar formElements *goquery.Selection\n\tif s.sel.Is(\"form\") {\n\t\tformElements = s.sel.Find(submittableSelector)\n\t} else {\n\t\tformElements = s.sel.Filter(submittableSelector)\n\t}\n\n\tformElements = formElements.FilterFunction(func(_ int, sel *goquery.Selection) bool {\n\t\tname := sel.AttrOr(\"name\", \"\")\n\t\tinputType := sel.AttrOr(\"type\", \"\")\n\t\tdisabled := sel.AttrOr(\"disabled\", \"\")\n\t\tchecked := sel.AttrOr(\"checked\", \"\")\n\n\t\treturn name != \"\" && // Must have a non-empty name\n\t\t\tdisabled != \"disabled\" && // Must not be disabled\n\t\t\tinputType != \"submit\" && // Must not be a button\n\t\t\tinputType != \"button\" &&\n\t\t\tinputType != \"reset\" &&\n\t\t\tinputType != \"image\" && // Must not be an image or file\n\t\t\tinputType != \"file\" &&\n\t\t\t(checked == \"checked\" ||\n\t\t\t\t(inputType != \"checkbox\" && inputType != \"radio\")) // Must be checked if it is an checkbox or radio\n\t})\n\n\tresult := make([]FormValue, len(formElements.Nodes))\n\tformElements.Each(func(i int, sel *goquery.Selection) {\n\t\telement := Selection{s.rt, sel, s.URL}\n\t\tname, _ := sel.Attr(\"name\")\n\t\tresult[i] = FormValue{Name: name, Value: element.Val()}\n\t})\n\treturn result\n}\n\nfunc (s Selection) SerializeObject() map[string]sobek.Value {\n\tformValues := s.SerializeArray()\n\tresult := make(map[string]sobek.Value)\n\tfor i := range formValues {\n\t\tformValue := formValues[i]\n\t\tresult[formValue.Name] = formValue.Value\n\t}\n\n\treturn result\n}\n\nfunc (s Selection) Serialize() string {\n\tformValues := s.SerializeArray()\n\turlValues := make(neturl.Values, len(formValues))\n\tfor i := range formValues {\n\t\tformValue := formValues[i]\n\t\tvalue := formValue.Value.Export()\n\t\tswitch v := value.(type) {\n\t\tcase string:\n\t\t\turlValues.Set(formValue.Name, v)\n\t\tcase []string:\n\t\t\turlValues[formValue.Name] = v\n\t\t}\n\t}\n\treturn urlValues.Encode()\n}\n"
  },
  {
    "path": "js/modules/k6/html/serialize_test.go",
    "content": "package html\n\nimport (\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst testSerializeHTML = `\n<html>\n<head>\n\t<title>This is the title</title>\n</head>\n<body>\n\t<h1 id=\"top\" data-test=\"dataval\" data-num-a=\"123\" data-num-b=\"1.5\" data-not-num-a=\"1.50\" data-not-num-b=\"1.1e02\">Lorem ipsum</h1>\n\t<p data-test-b=\"true\" data-opts='{\"id\":101}' data-test-empty=\"\">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac dui erat. Pellentesque eu euismod odio, eget fringilla ante. In vitae nulla at est tincidunt gravida sit amet maximus arcu. Sed accumsan tristique massa, blandit sodales quam malesuada eu. Morbi vitae luctus augue. Nunc nec ligula quam. Cras fringilla nulla leo, at dignissim enim accumsan vitae. Sed eu cursus sapien, a rhoncus lorem. Etiam sed massa egestas, bibendum quam sit amet, eleifend ipsum. Maecenas mi ante, consectetur at tincidunt id, suscipit nec sem. Integer congue elit vel ligula commodo ultricies. Suspendisse condimentum laoreet ligula at aliquet.</p>\n\t<p>Nullam id nisi eget ex pharetra imperdiet. Maecenas augue ligula, aliquet sit amet maximus ut, vestibulum et magna. Nam in arcu sed tortor volutpat porttitor sed eget dolor. Duis rhoncus est id dui porttitor, id molestie ex imperdiet. Proin purus ligula, pretium eleifend felis a, tempor feugiat mi. Cras rutrum pulvinar neque, eu dictum arcu. Cras purus metus, fermentum eget malesuada sit amet, dignissim non dui.</p>\n\t<form id=\"form1\">\n\t\t<input id=\"text_input\" name=\"text_input\" type=\"text\" value=\"input-text-value\"/>\n\t\t<input id=\"text_input\" name=\"empty_text_input1\" type=\"text\" value=\"\" />\n\t\t<input id=\"text_input\" name=\"empty_text_input2\" type=\"text\" />\n\t\t<select id=\"select_one\" name=\"select_one\">\n\t\t\t<option value=\"not this option\">no</option>\n\t\t\t<option value=\"yes this option\" selected>yes</option>\n\t\t</select>\n\t\t<select id=\"select_text\" name=\"select_text\">\n\t\t\t<option>no text</option>\n\t\t\t<option selected>yes text</option>\n\t\t</select>\n\t\t<select id=\"select_multi\" name=\"select_multi\" multiple>\n\t\t\t<option>option 1</option>\n\t\t\t<option selected>option 2</option>\n\t\t\t<option selected>option 3</option>\n\t\t</select>\n\t\t<textarea id=\"textarea\" name=\"textarea\" multiple>Lorem ipsum dolor sit amet</textarea>\n\t\t<input type=\"checkbox\" id=\"checkbox1\" name=\"checkbox1\" value=\"some checkbox\" checked=\"checked\" />\n\t\t<input type=\"checkbox\" id=\"checkbox2\" name=\"checkbox2\" checked=\"checked\" />\n\t\t<input type=\"checkbox\" id=\"checkbox3\" name=\"checkbox3\" />\n\t\t<input type=\"radio\" id=\"radio1\" name=\"radio1\" value=\"some radio\" checked=\"checked\" />\n\t\t<input type=\"radio\" id=\"radio2\" name=\"radio2\" checked=\"checked\" />\n\t\t<input type=\"radio\" id=\"radio3\" name=\"radio3\" />\n\t</form>\n\t<footer>This is the footer.</footer>\n</body>\n`\n\nfunc TestSerialize(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"SerializeArray\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testSerializeHTML)\n\n\t\tt.Run(\"form\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"form\").serializeArray()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tarr, ok := v.Export().([]FormValue)\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Len(t, arr, 11)\n\n\t\t\t\tassert.Equal(t, \"text_input\", arr[0].Name)\n\t\t\t\tassert.Equal(t, \"input-text-value\", arr[0].Value.String())\n\n\t\t\t\tassert.Equal(t, \"empty_text_input1\", arr[1].Name)\n\t\t\t\tassert.Equal(t, \"\", arr[1].Value.String())\n\n\t\t\t\tassert.Equal(t, \"empty_text_input2\", arr[2].Name)\n\t\t\t\tassert.Equal(t, \"\", arr[2].Value.String())\n\n\t\t\t\tassert.Equal(t, \"select_one\", arr[3].Name)\n\t\t\t\tassert.Equal(t, \"yes this option\", arr[3].Value.String())\n\n\t\t\t\tassert.Equal(t, \"select_text\", arr[4].Name)\n\t\t\t\tassert.Equal(t, \"yes text\", arr[4].Value.String())\n\n\t\t\t\tmultiValues, ok := arr[5].Value.Export().([]string)\n\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, \"select_multi\", arr[5].Name)\n\t\t\t\tassert.Equal(t, 2, len(multiValues))\n\t\t\t\tassert.Equal(t, \"option 2\", multiValues[0])\n\t\t\t\tassert.Equal(t, \"option 3\", multiValues[1])\n\n\t\t\t\tassert.Equal(t, \"textarea\", arr[6].Name)\n\t\t\t\tassert.Equal(t, \"Lorem ipsum dolor sit amet\", arr[6].Value.String())\n\n\t\t\t\tassert.Equal(t, \"checkbox1\", arr[7].Name)\n\t\t\t\tassert.Equal(t, \"some checkbox\", arr[7].Value.String())\n\n\t\t\t\tassert.Equal(t, \"checkbox2\", arr[8].Name)\n\t\t\t\tassert.Equal(t, \"on\", arr[8].Value.String())\n\n\t\t\t\tassert.Equal(t, \"radio1\", arr[9].Name)\n\t\t\t\tassert.Equal(t, \"some radio\", arr[9].Value.String())\n\n\t\t\t\tassert.Equal(t, \"radio2\", arr[10].Name)\n\t\t\t\tassert.Equal(t, \"on\", arr[10].Value.String())\n\t\t\t}\n\t\t})\n\n\t\tt.Run(\"controls\", func(t *testing.T) {\n\t\t\tv, err := rt.RunString(`doc.find(\"input\").serializeArray()`)\n\t\t\tif assert.NoError(t, err) {\n\t\t\t\tarr, ok := v.Export().([]FormValue)\n\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Len(t, arr, 7)\n\n\t\t\t\tassert.Equal(t, \"text_input\", arr[0].Name)\n\t\t\t\tassert.Equal(t, \"input-text-value\", arr[0].Value.String())\n\n\t\t\t\tassert.Equal(t, \"empty_text_input1\", arr[1].Name)\n\t\t\t\tassert.Equal(t, \"\", arr[1].Value.String())\n\n\t\t\t\tassert.Equal(t, \"empty_text_input2\", arr[2].Name)\n\t\t\t\tassert.Equal(t, \"\", arr[2].Value.String())\n\n\t\t\t\tassert.Equal(t, \"checkbox1\", arr[3].Name)\n\t\t\t\tassert.Equal(t, \"some checkbox\", arr[3].Value.String())\n\n\t\t\t\tassert.Equal(t, \"checkbox2\", arr[4].Name)\n\t\t\t\tassert.Equal(t, \"on\", arr[4].Value.String())\n\n\t\t\t\tassert.Equal(t, \"radio1\", arr[5].Name)\n\t\t\t\tassert.Equal(t, \"some radio\", arr[5].Value.String())\n\n\t\t\t\tassert.Equal(t, \"radio2\", arr[6].Name)\n\t\t\t\tassert.Equal(t, \"on\", arr[6].Value.String())\n\t\t\t}\n\t\t})\n\t})\n\n\tt.Run(\"SerializeObject\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testSerializeHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"form\").serializeObject()`)\n\t\tif assert.NoError(t, err) {\n\t\t\tobj, ok := v.Export().(map[string]sobek.Value)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, 11, len(obj))\n\n\t\t\tassert.Equal(t, \"input-text-value\", obj[\"text_input\"].String())\n\t\t\tassert.Equal(t, \"\", obj[\"empty_text_input1\"].String())\n\t\t\tassert.Equal(t, \"\", obj[\"empty_text_input2\"].String())\n\t\t\tassert.Equal(t, \"yes this option\", obj[\"select_one\"].String())\n\t\t\tassert.Equal(t, \"yes text\", obj[\"select_text\"].String())\n\t\t\tassert.Equal(t, \"Lorem ipsum dolor sit amet\", obj[\"textarea\"].String())\n\t\t\tassert.Equal(t, \"some checkbox\", obj[\"checkbox1\"].String())\n\t\t\tassert.Equal(t, \"on\", obj[\"checkbox2\"].String())\n\t\t\tassert.Equal(t, \"some radio\", obj[\"radio1\"].String())\n\t\t\tassert.Equal(t, \"on\", obj[\"radio2\"].String())\n\n\t\t\tmultiValues, ok := obj[\"select_multi\"].Export().([]string)\n\n\t\t\tassert.True(t, ok)\n\t\t\tassert.Equal(t, \"option 2\", multiValues[0])\n\t\t\tassert.Equal(t, \"option 3\", multiValues[1])\n\t\t}\n\t})\n\n\tt.Run(\"Serialize\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\trt := getTestRuntimeWithDoc(t, testSerializeHTML)\n\n\t\tv, err := rt.RunString(`doc.find(\"form\").serialize()`)\n\t\tif assert.NoError(t, err) {\n\t\t\turl := v.String()\n\t\t\tassert.Equal(t, \"checkbox1=some+checkbox\"+\n\t\t\t\t\"&checkbox2=on\"+\n\t\t\t\t\"&empty_text_input1=\"+\n\t\t\t\t\"&empty_text_input2=\"+\n\t\t\t\t\"&radio1=some+radio\"+\n\t\t\t\t\"&radio2=on\"+\n\t\t\t\t\"&select_multi=option+2\"+\n\t\t\t\t\"&select_multi=option+3\"+\n\t\t\t\t\"&select_one=yes+this+option\"+\n\t\t\t\t\"&select_text=yes+text\"+\n\t\t\t\t\"&text_input=input-text-value\"+\n\t\t\t\t\"&textarea=Lorem+ipsum+dolor+sit+amet\", url)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "js/modules/k6/html/util.go",
    "content": "package html\n\nimport (\n\t\"encoding/json\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/PuerkitoBio/goquery\"\n\t\"github.com/grafana/sobek\"\n\t\"github.com/serenize/snaker\"\n\tgohtml \"golang.org/x/net/html\"\n)\n\nfunc attrToProperty(s string) string {\n\tif before, after, ok := strings.Cut(s, \"-\"); ok {\n\t\treturn before + snaker.SnakeToCamel(strings.ReplaceAll(after, \"-\", \"_\"))\n\t}\n\treturn s\n}\n\nfunc propertyToAttr(attrName string) string {\n\treturn strings.ReplaceAll(snaker.CamelToSnake(attrName), \"_\", \"-\")\n}\n\nfunc namespaceURI(prefix string) string {\n\tswitch prefix {\n\tcase \"svg\":\n\t\treturn \"http://www.w3.org/2000/svg\"\n\tcase \"math\":\n\t\treturn \"http://www.w3.org/1998/Math/MathML\"\n\tdefault:\n\t\treturn \"http://www.w3.org/1999/xhtml\"\n\t}\n}\n\nfunc valueOrHTML(s *goquery.Selection) string {\n\tif val, exists := s.Attr(\"value\"); exists {\n\t\treturn val\n\t}\n\n\tif val, err := s.Html(); err == nil {\n\t\treturn val\n\t}\n\n\treturn \"\"\n}\n\nfunc getHTMLAttr(node *gohtml.Node, name string) *gohtml.Attribute {\n\tfor i := 0; i < len(node.Attr); i++ {\n\t\tif node.Attr[i].Key == name {\n\t\t\treturn &node.Attr[i]\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc elemList(s Selection) (items []sobek.Value) {\n\titems = make([]sobek.Value, s.Size())\n\tfor i := 0; i < s.Size(); i++ {\n\t\titems[i] = selToElement(s.Eq(i))\n\t}\n\treturn items\n}\n\nfunc nodeToElement(e Element, node *gohtml.Node) sobek.Value {\n\t// Goquery does not expose a way to build a goquery.Selection with an arbitrary html.Node.\n\t// Workaround by adding a node to an empty Selection\n\temptySel := e.sel.emptySelection()\n\temptySel.sel.Nodes = append(emptySel.sel.Nodes, node)\n\n\treturn selToElement(emptySel)\n}\n\n// Try to read numeric values in data- attributes.\n// Return numeric value when the representation is unchanged by conversion to float and back.\n// Other potentially numeric values (ie \"101.00\" \"1E02\") remain as strings.\nfunc toNumeric(val string) (float64, bool) {\n\tif fltVal, err := strconv.ParseFloat(val, 64); err != nil {\n\t\treturn 0, false\n\t} else if repr := strconv.FormatFloat(fltVal, 'f', -1, 64); repr == val {\n\t\treturn fltVal, true\n\t}\n\treturn 0, false\n}\n\nfunc convertDataAttrVal(val string) any {\n\tif len(val) == 0 {\n\t\treturn sobek.Undefined()\n\t}\n\n\tif val[0] == '{' || val[0] == '[' {\n\t\tvar subdata any\n\n\t\terr := json.Unmarshal([]byte(val), &subdata)\n\t\tif err == nil {\n\t\t\treturn subdata\n\t\t}\n\t\treturn val\n\t}\n\n\tswitch val {\n\tcase \"true\":\n\t\treturn true\n\n\tcase \"false\":\n\t\treturn false\n\n\tcase \"null\":\n\t\treturn sobek.Undefined()\n\n\tcase \"undefined\":\n\t\treturn sobek.Undefined()\n\n\tdefault:\n\t\tif fltVal, isOk := toNumeric(val); isOk {\n\t\t\treturn fltVal\n\t\t}\n\t\treturn val\n\t}\n}\n"
  },
  {
    "path": "js/modules/k6/http/async_request_test.go",
    "content": "package http\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc wrapInAsyncLambda(input string) string {\n\t// This makes it possible to use `await` freely on the \"top\" level\n\treturn \"(async () => {\\n \" + input + \"\\n })()\"\n}\n\nfunc TestAsyncRequest(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"EmptyBody\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\n\t\tsr := ts.tb.Replacer.Replace\n\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(sr(`\n\t\t\t\tvar reqUrl = \"HTTPBIN_URL/cookies\"\n\t\t\t\tvar res = await http.asyncRequest(\"GET\", reqUrl);\n\t\t\t\tvar jar = new http.CookieJar();\n\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\");\n\t\t\t\tres = await http.asyncRequest(\"GET\", reqUrl, null, { cookies: { key2: \"value2\" }, jar: jar });\n\n\t\t\t\tif (res.json().key != \"value\") { throw new Error(\"wrong cookie value: \" + res.json().key); }\n\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.request[\"method\"] !== \"GET\") { throw new Error(\"http request method was not \\\"GET\\\": \" + JSON.stringify(res.request)) }\n\t\t\t\tif (res.request[\"body\"].length != 0) { throw new Error(\"http request body was not null: \" + JSON.stringify(res.request[\"body\"])) }\n\t\t\t\tif (res.request[\"url\"] != reqUrl) {\n\t\t\t\t\tthrow new Error(\"wrong http request url: \" + JSON.stringify(res.request))\n\t\t\t\t}\n\t\t\t\tif (res.request[\"cookies\"][\"key2\"][0].name != \"key2\") { throw new Error(\"wrong http request cookies: \" + JSON.stringify(JSON.stringify(res.request[\"cookies\"][\"key2\"]))) }\n\t\t\t\tif (res.request[\"headers\"][\"User-Agent\"][0] != \"TestUserAgent\") { throw new Error(\"wrong http request headers: \" + JSON.stringify(res.request)) }\n\t\t\t\t`)))\n\t\tassert.NoError(t, err)\n\t})\n\tt.Run(\"NonEmptyBody\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\n\t\tsr := ts.tb.Replacer.Replace\n\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(sr(`\n\t\t\t\tvar res = await http.asyncRequest(\"POST\", \"HTTPBIN_URL/post\", {a: \"a\", b: 2}, {headers: {\"Content-Type\": \"application/x-www-form-urlencoded; charset=utf-8\"}});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.request[\"body\"] != \"a=a&b=2\") { throw new Error(\"http request body was not set properly: \" + JSON.stringify(res.request))}\n\t\t\t\t`)))\n\t\tassert.NoError(t, err)\n\t})\n\tt.Run(\"Concurrent\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\tsr := ts.tb.Replacer.Replace\n\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(sr(`\n            let start = Date.now()\n            let p1 = http.asyncRequest(\"GET\", \"HTTPBIN_URL/delay/200ms\").then(() => { return Date.now() - start})\n            let p2 = http.asyncRequest(\"GET\", \"HTTPBIN_URL/delay/100ms\").then(() =>  { return Date.now() - start})\n            let time1 = await p1;\n            let time2 = await p2;\n            if (time1 < time2) {\n                throw(\"request that should've taken 200ms took less time then one that should take 100ms \" + time1 +\">\" + time2 )\n            }\n\t\t`)))\n\t\tassert.NoError(t, err)\n\t})\n}\n\nfunc TestAsyncRequestResponseCallbackRace(t *testing.T) {\n\t// This test is here only to tease out race conditions\n\tt.Parallel()\n\tts := newTestCase(t)\n\terr := ts.runtime.VU.Runtime().Set(\"q\", func(f func()) {\n\t\trg := ts.runtime.EventLoop.RegisterCallback()\n\t\ttime.AfterFunc(time.Millisecond*5, func() {\n\t\t\trg(func() error {\n\t\t\t\tf()\n\t\t\t\treturn nil\n\t\t\t})\n\t\t})\n\t})\n\trequire.NoError(t, err)\n\terr = ts.runtime.VU.Runtime().Set(\"log\", func(_ string) {\n\t\t// t.Log(s) // uncomment for debugging\n\t})\n\trequire.NoError(t, err)\n\t_, err = ts.runtime.RunOnEventLoop(wrapInAsyncLambda(ts.tb.Replacer.Replace(`\n        let call = (i) => {\n            log(\"s\"+i)\n            if (i > 200) { return null; }\n            http.setResponseCallback(http.expectedStatuses(i))\n            q(() => call(i+1)) // don't use promises as they resolve before eventloop callbacks such as the one from asyncRequest\n        }\n        for (let j = 0; j< 50; j++) {\n            call(0)\n            await http.asyncRequest(\"GET\", \"HTTPBIN_URL/redirect/20\").then(() => log(\"!!!!!!!!!!!!!!!\"+j))\n        }\n    `)))\n\trequire.NoError(t, err)\n}\n\nfunc TestAsyncRequestErrors(t *testing.T) {\n\t// This likely should have a way to do the same for http.request and http.asyncRequest with the same tests\n\tt.Parallel()\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"unsupported protocol\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\n\t\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(`\n            try {\n                http.asyncRequest(\"\", \"\").catch((e) => globalThis.promiseRejected = e )\n            } catch (e) {\n                globalThis.exceptionThrown = e\n            }\n            `))\n\t\t\trequire.NoError(t, err)\n\t\t\tpromiseRejected := ts.runtime.VU.Runtime().Get(\"promiseRejected\")\n\t\t\texceptionThrown := ts.runtime.VU.Runtime().Get(\"exceptionThrown\")\n\t\t\trequire.NotNil(t, promiseRejected)\n\t\t\trequire.True(t, promiseRejected.ToBoolean())\n\t\t\trequire.Nil(t, exceptionThrown)\n\t\t\tassert.Contains(t, promiseRejected.ToString(), \"unsupported protocol scheme\")\n\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\tassert.Nil(t, logEntry)\n\t\t})\n\n\t\tt.Run(\"throw=false\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\t\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(`\n\t\t\t\tvar res = await http.asyncRequest(\"GET\", \"some://example.com\", null, { throw: false });\n\t\t\t\tif (res.error.search('unsupported protocol scheme \"some\"')  == -1) {\n\t\t\t\t\tthrow new Error(\"wrong error:\" + res.error);\n\t\t\t\t}\n\t\t\t\tthrow new Error(\"another error\");\n\t\t\t`))\n\t\t\trequire.ErrorContains(t, err, \"another error\")\n\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\trequire.NotNil(t, logEntry)\n\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\terr, ok := logEntry.Data[\"error\"].(error)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.ErrorContains(t, err, \"unsupported protocol scheme\")\n\t\t\tassert.Equal(t, \"Request Failed\", logEntry.Message)\n\t\t})\n\t})\n\tt.Run(\"InvalidURL\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texpErr := `invalid URL: parse \"https:// test.k6.io\": invalid character \" \" in host name`\n\t\tt.Run(\"throw=true\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\n\t\t\tjs := `\n                try {\n\t\t\t\t    http.asyncRequest(\"GET\", \"https:// test.k6.io\").catch((e) => globalThis.promiseRejected = e )\n                } catch (e) {\n                    globalThis.exceptionThrown = e\n                }\n\t\t\t`\n\t\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(js))\n\t\t\trequire.NoError(t, err)\n\t\t\tpromiseRejected := ts.runtime.VU.Runtime().Get(\"promiseRejected\")\n\t\t\texceptionThrown := ts.runtime.VU.Runtime().Get(\"exceptionThrown\")\n\t\t\trequire.NotNil(t, promiseRejected)\n\t\t\trequire.True(t, promiseRejected.ToBoolean())\n\t\t\trequire.Nil(t, exceptionThrown)\n\t\t\tassert.Contains(t, promiseRejected.ToString(), expErr)\n\t\t})\n\n\t\tt.Run(\"throw=false\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\t\t\trt := ts.runtime.VU.Runtime()\n\t\t\tstate := ts.runtime.VU.State()\n\t\t\tstate.Options.Throw.Bool = false\n\t\t\tdefer func() { state.Options.Throw.Bool = true }()\n\n\t\t\tjs := `\n                var r = await http.asyncRequest(\"GET\", \"https:// test.k6.io\");\n                globalThis.ret = {error: r.error, error_code: r.error_code};\n\t\t\t`\n\t\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(js))\n\t\t\trequire.NoError(t, err)\n\t\t\tret := rt.GlobalObject().Get(\"ret\")\n\t\t\tvar retobj map[string]any\n\t\t\tvar ok bool\n\t\t\tif retobj, ok = ret.Export().(map[string]any); !ok {\n\t\t\t\trequire.Fail(t, \"got wrong return object: %#+v\", retobj)\n\t\t\t}\n\t\t\trequire.Equal(t, int64(1020), retobj[\"error_code\"])\n\t\t\trequire.Equal(t, expErr, retobj[\"error\"])\n\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\trequire.NotNil(t, logEntry)\n\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\terr, ok = logEntry.Data[\"error\"].(error)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.ErrorContains(t, err, expErr)\n\t\t\tassert.Equal(t, \"Request Failed\", logEntry.Message)\n\t\t})\n\n\t\tt.Run(\"throw=false,nopanic\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\t\t\trt := ts.runtime.VU.Runtime()\n\t\t\tstate := ts.runtime.VU.State()\n\t\t\tstate.Options.Throw.Bool = false\n\t\t\tdefer func() { state.Options.Throw.Bool = true }()\n\n\t\t\tjs := `\n                var r = await http.asyncRequest(\"GET\", \"https:// test.k6.io\");\n                r.html();\n                r.json();\n                globalThis.ret = r.error_code; // not reached because of json()\n\t\t\t`\n\t\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(js))\n\t\t\tret := rt.GlobalObject().Get(\"ret\")\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Nil(t, ret)\n\t\t\tassert.Contains(t, err.Error(), \"unexpected end of JSON input\")\n\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\trequire.NotNil(t, logEntry)\n\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\terr, ok := logEntry.Data[\"error\"].(error)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.ErrorContains(t, err, expErr)\n\t\t\tassert.Equal(t, \"Request Failed\", logEntry.Message)\n\t\t})\n\t})\n\n\tt.Run(\"Unroutable\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\t_, err := ts.runtime.RunOnEventLoop(wrapInAsyncLambda(`\n            try {\n                http.asyncRequest(\"GET\", \"http://sdafsgdhfjg/\").catch((e) => globalThis.promiseRejected = e )\n            } catch (e) {\n                globalThis.exceptionThrown = e\n            }`))\n\t\texpErr := \"lookup sdafsgdhfjg\"\n\t\trequire.NoError(t, err)\n\t\tpromiseRejected := ts.runtime.VU.Runtime().Get(\"promiseRejected\")\n\t\texceptionThrown := ts.runtime.VU.Runtime().Get(\"exceptionThrown\")\n\t\trequire.NotNil(t, promiseRejected)\n\t\trequire.True(t, promiseRejected.ToBoolean())\n\t\trequire.Nil(t, exceptionThrown)\n\t\tassert.Contains(t, promiseRejected.ToString(), expErr)\n\t})\n}\n"
  },
  {
    "path": "js/modules/k6/http/batch_test.go",
    "content": "package http\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst invalidURLerr = `invalid URL: parse \"https:// invalidurl.com\": invalid character \" \" in host name`\n\nfunc TestBatchError(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tname, code, expErr string\n\t\tthrow              bool\n\t}{\n\t\t{\n\t\t\tname: \"no arg\", code: ``,\n\t\t\texpErr: `no argument was provided to http.batch()`, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid null arg\", code: `null`,\n\t\t\texpErr: `invalid http.batch() argument type <nil>`, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid undefined arg\", code: `undefined`,\n\t\t\texpErr: `invalid http.batch() argument type <nil>`, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid string arg\", code: `\"https://somevalidurl.com\"`,\n\t\t\texpErr: `invalid http.batch() argument type string`, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid URL short\", code: `[\"https:// invalidurl.com\"]`,\n\t\t\texpErr: invalidURLerr, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid URL short no throw\", code: `[\"https:// invalidurl.com\"]`,\n\t\t\texpErr: invalidURLerr, throw: false,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid URL array\", code: `[ [\"GET\", \"https:// invalidurl.com\"] ]`,\n\t\t\texpErr: invalidURLerr, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid URL array no throw\", code: `[ [\"GET\", \"https:// invalidurl.com\"] ]`,\n\t\t\texpErr: invalidURLerr, throw: false,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid URL object\", code: `[ {method: \"GET\", url: \"https:// invalidurl.com\"} ]`,\n\t\t\texpErr: invalidURLerr, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid object no throw\", code: `[ {method: \"GET\", url: \"https:// invalidurl.com\"} ]`,\n\t\t\texpErr: invalidURLerr, throw: false,\n\t\t},\n\t\t{\n\t\t\tname: \"object no url key\", code: `[ {method: \"GET\"} ]`,\n\t\t\texpErr: `batch request 0 doesn't have a url key`, throw: true,\n\t\t},\n\t\t{\n\t\t\tname: \"multiple arguments\", code: `[\"GET\", \"https://test.k6.io\"],[\"GET\", \"https://test.k6.io\"]`,\n\t\t\texpErr: `http.batch() accepts only an array or an object of requests`, throw: true,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\t\t\tstate := ts.runtime.VU.State()\n\t\t\trt := ts.runtime.VU.Runtime()\n\t\t\toldThrow := state.Options.Throw.Bool\n\t\t\tstate.Options.Throw.Bool = tc.throw\n\t\t\tdefer func() { state.Options.Throw.Bool = oldThrow }()\n\n\t\t\tret, err := rt.RunString(fmt.Sprintf(`\n\t\t\t\t\t\t(function(){\n\t\t\t\t\t\t\tvar r = http.batch(%s);\n\t\t\t\t\t\t\tif (r.length !== 1) throw new Error('unexpected responses length: '+r.length);\n\t\t\t\t\t\t\treturn {error: r[0].error, error_code: r[0].error_code};\n\t\t\t\t\t\t})()`, tc.code))\n\t\t\tif tc.throw {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\tassert.Contains(t, err.Error(), tc.expErr)\n\t\t\t\trequire.Nil(t, ret)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.NotNil(t, ret)\n\t\t\t\tvar retobj map[string]any\n\t\t\t\tvar ok bool\n\t\t\t\tif retobj, ok = ret.Export().(map[string]any); !ok {\n\t\t\t\t\trequire.Fail(t, \"got wrong return object: %#+v\", retobj)\n\t\t\t\t}\n\t\t\t\trequire.Equal(t, int64(1020), retobj[\"error_code\"])\n\t\t\t\trequire.Equal(t, invalidURLerr, retobj[\"error\"])\n\n\t\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\t\trequire.NotNil(t, logEntry)\n\t\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\t\te, ok := logEntry.Data[\"error\"].(error)\n\t\t\t\trequire.True(t, ok)\n\t\t\t\tassert.ErrorContains(t, e, tc.expErr)\n\t\t\t\tassert.Equal(t, \"A batch request failed\", logEntry.Message)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestBatchErrorNoPanic(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct{ name, code string }{\n\t\t{\n\t\t\tname: \"array\", code: `[\n\t\t\t\t\t\t[\"GET\", \"https:// invalidurl.com\"],\n\t\t\t\t\t\t[\"GET\", \"https://somevalidurl.com\"],\n\t\t\t\t\t]`,\n\t\t},\n\t\t{\n\t\t\tname: \"object\", code: `[\n\t\t\t\t\t\t{method: \"GET\", url: \"https:// invalidurl.com\"},\n\t\t\t\t\t\t{method: \"GET\", url: \"https://somevalidurl.com\"},\n\t\t\t\t\t]`,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\t\t\tstate := ts.runtime.VU.State()\n\t\t\trt := ts.runtime.VU.Runtime()\n\t\t\toldThrow := state.Options.Throw.Bool\n\t\t\tstate.Options.Throw.Bool = false\n\t\t\tdefer func() { state.Options.Throw.Bool = oldThrow }()\n\n\t\t\tret, err := rt.RunString(fmt.Sprintf(`\n\t\t\t\t\t\t(function(){\n\t\t\t\t\t\t\tvar r = http.batch(%s);\n\t\t\t\t\t\t\tif (r.length !== 2) throw new Error('unexpected responses length: '+r.length);\n\t\t\t\t\t\t\tif (r[1] !== null) throw new Error('expected response at index 1 to be null');\n\t\t\t\t\t\t\tr[0].html();\n\t\t\t\t\t\t\tr[0].json();\n\t            \t\t    return r[0].error_code; // not reached because of json()\n\t\t\t\t\t\t})()\n\t\t\t\t\t`, tc.code))\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Nil(t, ret)\n\t\t\tassert.Contains(t, err.Error(), \"unexpected end of JSON input\")\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\trequire.NotNil(t, logEntry)\n\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\te, ok := logEntry.Data[\"error\"].(error)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.ErrorContains(t, e, invalidURLerr)\n\t\t\tassert.Equal(t, \"A batch request failed\", logEntry.Message)\n\t\t})\n\t}\n}\n\nfunc TestBatchGet(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Simple\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tsr := tb.Replacer.Replace\n\t\t_, err := rt.RunString(sr(`\n\t\t{\n\t\t\tlet reqs = [\n\t\t\t\t[\"GET\", \"HTTPBIN_URL/\"],\n\t\t\t\t[\"GET\", \"HTTPBIN_IP_URL/\"],\n\t\t\t];\n\t\t\tlet res = http.batch(reqs);\n\t\t\tfor (var key in res) {\n\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + res[key].status); }\n\t\t\t\tif (res[key].url != reqs[key][1]) { throw new Error(\"wrong url: \" + res[key].url); }\n\t\t\t}\n\t\t}`))\n\t\trequire.NoError(t, err)\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_IP_URL/\"), 200, \"\")\n\t})\n\n\tt.Run(\"Tagged\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tsr := tb.Replacer.Replace\n\t\t_, err := rt.RunString(sr(`\n\t\t\t{\n\t\t\t\tlet fragment = \"get\";\n\t\t\t\tlet reqs = [\n\t\t\t\t\t[\"GET\", http.url` + \"`\" + `HTTPBIN_URL/${fragment}` + \"`\" + `],\n\t\t\t\t\t[\"GET\", http.url` + \"`\" + `HTTPBIN_IP_URL/` + \"`\" + `],\n\t\t\t\t];\n\t\t\t\tlet res = http.batch(reqs);\n\t\t\t\tfor (var key in res) {\n\t\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\t\tif (res[key].url != reqs[key][1].url) { throw new Error(\"wrong url: \" + key + \": \" + res[key].url + \" != \" + reqs[key][1].url); }\n\t\t\t\t}\n\t\t\t}`))\n\t\tassert.NoError(t, err)\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/${}\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_IP_URL/\"), 200, \"\")\n\t})\n\n\tt.Run(\"Shorthand\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tsr := tb.Replacer.Replace\n\t\t_, err := rt.RunString(sr(`\n\t\t\t{\n\t\t\t\tlet reqs = [\n\t\t\t\t\t\"HTTPBIN_URL/\",\n\t\t\t\t\t\"HTTPBIN_IP_URL/\",\n\t\t\t\t];\n\t\t\t\tlet res = http.batch(reqs);\n\t\t\t\tfor (var key in res) {\n\t\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\t\tif (res[key].url != reqs[key]) { throw new Error(\"wrong url: \" + key + \": \" + res[key].url); }\n\t\t\t\t}\n\t\t\t}`))\n\t\tassert.NoError(t, err)\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_IP_URL/\"), 200, \"\")\n\t})\n\n\tt.Run(\"ShorthandTagged\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tsr := tb.Replacer.Replace\n\t\t_, err := rt.RunString(sr(`\n\t\t\t\t{\n\t\t\t\t\tlet fragment = \"get\";\n\t\t\t\t\tlet reqs = [\n\t\t\t\t\t\thttp.url` + \"`\" + `HTTPBIN_URL/${fragment}` + \"`\" + `,\n\t\t\t\t\t\thttp.url` + \"`\" + `HTTPBIN_IP_URL/` + \"`\" + `,\n\t\t\t\t\t];\n\t\t\t\t\tlet res = http.batch(reqs);\n\t\t\t\t\tfor (var key in res) {\n\t\t\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\t\t\tif (res[key].url != reqs[key].url) { throw new Error(\"wrong url: \" + key + \": \" + res[key].url + \" != \" + reqs[key].url); }\n\t\t\t\t\t}\n\t\t\t\t}`))\n\t\tassert.NoError(t, err)\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/${}\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_IP_URL/\"), 200, \"\")\n\t})\n\n\tt.Run(\"ObjectForm\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tsr := tb.Replacer.Replace\n\t\t_, err := rt.RunString(sr(`\n\t\t\t{\n\t\t\t\tlet reqs = [\n\t\t\t\t\t{ method: \"GET\", url: \"HTTPBIN_URL/\" },\n\t\t\t\t\t{ url: \"HTTPBIN_IP_URL/\", method: \"GET\"},\n\t\t\t\t];\n\t\t\t\tlet res = http.batch(reqs);\n\t\t\t\tfor (var key in res) {\n\t\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\t\tif (res[key].url != reqs[key].url) { throw new Error(\"wrong url: \" + key + \": \" + res[key].url + \" != \" + reqs[key].url); }\n\t\t\t\t}\n\t\t\t}`))\n\t\tassert.NoError(t, err)\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_IP_URL/\"), 200, \"\")\n\t})\n\n\tt.Run(\"ObjectKeys\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tsr := tb.Replacer.Replace\n\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar reqs = {\n\t\t\t\t\tshorthand: \"HTTPBIN_URL/get?r=shorthand\",\n\t\t\t\t\tarr: [\"GET\", \"HTTPBIN_URL/get?r=arr\", null, {tags: {name: 'arr'}}],\n\t\t\t\t\tobj1: { method: \"GET\", url: \"HTTPBIN_URL/get?r=obj1\" },\n\t\t\t\t\tobj2: { url: \"HTTPBIN_URL/get?r=obj2\", params: {tags: {name: 'obj2'}}, method: \"GET\"},\n\t\t\t\t};\n\t\t\t\tvar res = http.batch(reqs);\n\t\t\t\tfor (var key in res) {\n\t\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\t\tif (res[key].json().args.r != key) { throw new Error(\"wrong request id: \" + key); }\n\t\t\t\t}`))\n\t\tassert.NoError(t, err)\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/get?r=shorthand\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", \"arr\", 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/get?r=obj1\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", \"obj2\", 200, \"\")\n\t})\n\n\tt.Run(\"BodyAndParams\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tsr := tb.Replacer.Replace\n\t\ttestStr := \"testbody\"\n\t\trequire.NoError(t, rt.Set(\"someStrFile\", testStr))\n\t\trequire.NoError(t, rt.Set(\"someBinFile\", []byte(testStr)))\n\n\t\t_, err := rt.RunString(sr(`\n\t\t\t\t\tvar reqs = [\n\t\t\t\t\t\t[\"POST\", \"HTTPBIN_URL/post\", \"testbody\"],\n\t\t\t\t\t\t[\"POST\", \"HTTPBIN_URL/post\", someStrFile],\n\t\t\t\t\t\t[\"POST\", \"HTTPBIN_URL/post\", someBinFile],\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t\turl: \"HTTPBIN_URL/post\",\n\t\t\t\t\t\t\ttest: \"test1\",\n\t\t\t\t\t\t\tbody: \"testbody\",\n\t\t\t\t\t\t}, {\n\t\t\t\t\t\t\tbody: someBinFile,\n\t\t\t\t\t\t\turl: \"HTTPBIN_IP_URL/post\",\n\t\t\t\t\t\t\tparams: { tags: { name: \"myname\" } },\n\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t}, {\n\t\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\t\turl: \"HTTPBIN_IP_URL/post\",\n\t\t\t\t\t\t\tbody: {\n\t\t\t\t\t\t\t\thello: \"world!\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tparams: {\n\t\t\t\t\t\t\t\ttags: { name: \"myname\" },\n\t\t\t\t\t\t\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t];\n\t\t\t\t\tvar res = http.batch(reqs);\n\t\t\t\t\tfor (var key in res) {\n\t\t\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\t\t\tif (res[key].json().data != \"data:application/octet-stream;base64,dGVzdGJvZHk=\" && res[key].json().form.hello != \"world!\") { throw new Error(\"wrong response for \" + key + \": \" + res[key].body); }\n\t\t\t\t\t}`))\n\t\tassert.NoError(t, err)\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"POST\", sr(\"HTTPBIN_URL/post\"), 200, \"\")\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"POST\", \"myname\", 200, \"\")\n\t})\n}\n\nfunc TestBatchPost(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tsr := tb.Replacer.Replace\n\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.batch([ [\"POST\", \"HTTPBIN_URL/post\", { key: \"value\" }] ]);\n\t\t\tfor (var key in res) {\n\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\tif (res[key].json().form.key != \"value\") { throw new Error(\"wrong form: \" + key + \": \" + JSON.stringify(res[key].json().form)); }\n\t\t\t}`))\n\tassert.NoError(t, err)\n\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"POST\", sr(\"HTTPBIN_URL/post\"), 200, \"\")\n}\n\nfunc TestBatchPut(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tsr := tb.Replacer.Replace\n\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.batch([ [\"PUT\", \"HTTPBIN_URL/put\", { key: \"value\" }] ]);\n\t\t\tfor (var key in res) {\n\t\t\t\tif (res[key].status != 200) { throw new Error(\"wrong status: \" + key + \": \" + res[key].status); }\n\t\t\t\tif (res[key].json().form.key != \"value\") { throw new Error(\"wrong form: \" + key + \": \" + JSON.stringify(res[key].json().form)); }\n\t\t\t}`))\n\tassert.NoError(t, err)\n\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"PUT\", sr(\"HTTPBIN_URL/put\"), 200, \"\")\n}\n"
  },
  {
    "path": "js/modules/k6/http/cookiejar.go",
    "content": "package http\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\tneturl \"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/common\"\n)\n\n// ErrJarForbiddenInInitContext is used when a cookie jar was made in the init context\n// TODO: unexport this? there's no reason for this to be exported\nvar ErrJarForbiddenInInitContext = common.NewInitContextError(\"Making cookie jars in the init context is not supported\")\n\n// CookieJar is cookiejar.Jar wrapper to be used in js scripts\ntype CookieJar struct {\n\tmoduleInstance *ModuleInstance\n\t// js is to make it not be accessible from inside Sobek/js, the json is\n\t// for when it is returned from setup().\n\tJar *cookiejar.Jar `js:\"-\" json:\"-\"`\n}\n\n// CookiesForURL return the cookies for a given url as a map of key and values\nfunc (j CookieJar) CookiesForURL(url string) map[string][]string {\n\tu, err := neturl.Parse(url)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tcookies := j.Jar.Cookies(u)\n\tobjs := make(map[string][]string, len(cookies))\n\tfor _, c := range cookies {\n\t\tobjs[c.Name] = append(objs[c.Name], c.Value)\n\t}\n\treturn objs\n}\n\n// Set sets a cookie for a particular url with the given name value and additional opts\nfunc (j CookieJar) Set(url, name, value string, opts sobek.Value) (bool, error) {\n\trt := j.moduleInstance.vu.Runtime()\n\n\tu, err := neturl.Parse(url)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tc := http.Cookie{Name: name, Value: value}\n\tparamsV := opts\n\tif !common.IsNullish(paramsV) {\n\t\tparams := paramsV.ToObject(rt)\n\t\tfor _, k := range params.Keys() {\n\t\t\tswitch strings.ToLower(k) {\n\t\t\tcase \"path\":\n\t\t\t\tc.Path = params.Get(k).String()\n\t\t\tcase \"domain\":\n\t\t\t\tc.Domain = params.Get(k).String()\n\t\t\tcase \"expires\":\n\t\t\t\tvar t time.Time\n\t\t\t\texpires := params.Get(k).String()\n\t\t\t\tif expires != \"\" {\n\t\t\t\t\tt, err = time.Parse(time.RFC1123, expires)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false, fmt.Errorf(`unable to parse \"expires\" date string \"%s\": %w`, expires, err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tc.Expires = t\n\t\t\tcase \"max_age\":\n\t\t\t\tc.MaxAge = int(params.Get(k).ToInteger())\n\t\t\tcase \"secure\":\n\t\t\t\tc.Secure = params.Get(k).ToBoolean()\n\t\t\tcase \"http_only\":\n\t\t\t\tc.HttpOnly = params.Get(k).ToBoolean()\n\t\t\t}\n\t\t}\n\t}\n\tj.Jar.SetCookies(u, []*http.Cookie{&c})\n\treturn true, nil\n}\n\n// Clear all cookies for a particular URL\nfunc (j CookieJar) Clear(url string) error {\n\tu, err := neturl.Parse(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tcookies := j.Jar.Cookies(u)\n\tfor _, c := range cookies {\n\t\tc.MaxAge = -1\n\t}\n\tj.Jar.SetCookies(u, cookies)\n\n\treturn nil\n}\n\n// Delete cookies for a particular URL\nfunc (j CookieJar) Delete(url, name string) error {\n\tif name == \"\" {\n\t\treturn errors.New(\"cookie: is null\")\n\t}\n\n\tu, err := neturl.Parse(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tc := http.Cookie{Name: name, MaxAge: -1}\n\tj.Jar.SetCookies(u, []*http.Cookie{&c})\n\n\treturn nil\n}\n"
  },
  {
    "path": "js/modules/k6/http/doc.go",
    "content": "// Package http implements the k6/http js module for k6.\n// That module is used to make http requests.\npackage http\n"
  },
  {
    "path": "js/modules/k6/http/file.go",
    "content": "package http\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// FileData represents a binary file requiring multipart request encoding\ntype FileData struct {\n\tData        any\n\tFilename    string\n\tContentType string\n}\n\nvar quoteEscaper = strings.NewReplacer(\"\\\\\", \"\\\\\\\\\", `\"`, \"\\\\\\\"\") //nolint:gochecknoglobals\n\nfunc escapeQuotes(s string) string {\n\treturn quoteEscaper.Replace(s)\n}\n\n// File returns a FileData object.\nfunc (mi *ModuleInstance) file(data any, args ...string) (*FileData, error) {\n\t// supply valid default if filename and content-type are not specified\n\tfname, ct := fmt.Sprintf(\"%d\", time.Now().UnixNano()), \"application/octet-stream\"\n\n\tif len(args) > 0 {\n\t\tfname = args[0]\n\n\t\tif len(args) > 1 {\n\t\t\tct = args[1]\n\t\t}\n\t}\n\n\tswitch data.(type) {\n\tcase string, sobek.ArrayBuffer:\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid type %T, expected string or ArrayBuffer\", data)\n\t}\n\n\treturn &FileData{\n\t\tData:        data,\n\t\tFilename:    fname,\n\t\tContentType: ct,\n\t}, nil\n}\n"
  },
  {
    "path": "js/modules/k6/http/file_test.go",
    "content": "package http\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestHTTPFile(t *testing.T) {\n\tt.Parallel()\n\tinput := \"hello\"\n\n\ttestCases := []struct {\n\t\tinput    func(rt *sobek.Runtime) any\n\t\targs     []string\n\t\texpected *FileData\n\t\texpErr   string\n\t}{\n\t\t// We can't really test without specifying a filename argument,\n\t\t// as File() calls time.Now(), so we'd need some time freezing/mocking\n\t\t// or refactoring, or to exclude the field from the assertion.\n\t\t{\n\t\t\tfunc(*sobek.Runtime) any { return input },\n\t\t\t[]string{\"test.bin\"},\n\t\t\t&FileData{Data: input, Filename: \"test.bin\", ContentType: \"application/octet-stream\"},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\tfunc(*sobek.Runtime) any { return input },\n\t\t\t[]string{\"test.txt\", \"text/plain\"},\n\t\t\t&FileData{Data: input, Filename: \"test.txt\", ContentType: \"text/plain\"},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\tfunc(rt *sobek.Runtime) any { return rt.NewArrayBuffer([]byte(input)) },\n\t\t\t[]string{\"test-ab.bin\"},\n\t\t\t&FileData{Data: input, Filename: \"test-ab.bin\", ContentType: \"application/octet-stream\"},\n\t\t\t\"\",\n\t\t},\n\t\t{func(*sobek.Runtime) any { return struct{}{} }, []string{}, &FileData{}, \"GoError: invalid type struct {}, expected string or ArrayBuffer\"},\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%d\", i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\truntime, mi := getTestModuleInstance(t)\n\t\t\trt := runtime.VU.RuntimeField\n\t\t\tcal, _ := sobek.AssertFunction(rt.ToValue(mi.file))\n\t\t\targs := make([]sobek.Value, 1, len(tc.args)+1)\n\t\t\targs[0] = rt.ToValue(tc.input(rt))\n\t\t\tfor _, arg := range tc.args {\n\t\t\t\targs = append(args, rt.ToValue(arg))\n\t\t\t}\n\t\t\t_, err := cal(sobek.Undefined(), args...)\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\trequire.EqualError(t, err, tc.expErr)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestHTTPFileDataInRequest(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\n\t_, err := ts.runtime.VU.Runtime().RunString(ts.tb.Replacer.Replace(`\n    let f = http.file(\"something\");\n    let res = http.request(\"POST\", \"HTTPBIN_URL/post\", f.data);\n    if (res.status != 200) {\n      throw new Error(\"Unexpected status \" + res.status)\n    }`))\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "js/modules/k6/http/http.go",
    "content": "package http\n\nimport (\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/lib/netext/httpext\"\n)\n\n// RootModule is the global module object type. It is instantiated once per test\n// run and will be used to create HTTP module instances for each VU.\n//\n// TODO: add sync.Once for all of the deprecation warnings we might want to do\n// for the old k6/http APIs here, so they are shown only once in a test run.\ntype RootModule struct{}\n\n// ModuleInstance represents an instance of the HTTP module for every VU.\ntype ModuleInstance struct {\n\tvu            modules.VU\n\trootModule    *RootModule\n\tdefaultClient *Client\n\texports       *sobek.Object\n}\n\nvar (\n\t_ modules.Module   = &RootModule{}\n\t_ modules.Instance = &ModuleInstance{}\n)\n\n// New returns a pointer to a new HTTP RootModule.\nfunc New() *RootModule {\n\treturn &RootModule{}\n}\n\n// NewModuleInstance returns an HTTP module instance for each VU.\nfunc (r *RootModule) NewModuleInstance(vu modules.VU) modules.Instance {\n\trt := vu.Runtime()\n\tmi := &ModuleInstance{\n\t\tvu:         vu,\n\t\trootModule: r,\n\t\texports:    rt.NewObject(),\n\t}\n\tmi.defineConstants()\n\n\tmi.defaultClient = &Client{\n\t\t// TODO: configure this from lib.Options and get rid of some of the\n\t\t// things in the VU State struct that should be here. See\n\t\t// https://github.com/grafana/k6/issues/2293\n\t\tmoduleInstance:   mi,\n\t\tresponseCallback: defaultExpectedStatuses.match,\n\t}\n\n\tmustExport := func(name string, value any) {\n\t\tif err := mi.exports.Set(name, value); err != nil {\n\t\t\tcommon.Throw(rt, err)\n\t\t}\n\t}\n\n\tmustExport(\"url\", mi.URL)\n\tmustExport(\"CookieJar\", mi.newCookieJar)\n\tmustExport(\"cookieJar\", mi.getVUCookieJar)\n\tmustExport(\"file\", mi.file) // TODO: deprecate or refactor?\n\n\t// TODO: refactor so the Client actually has better APIs and these are\n\t// wrappers (facades) that convert the old k6 idiosyncratic APIs to the new\n\t// proper Client ones that accept Request objects and don't suck\n\tmustExport(\"get\", func(url sobek.Value, args ...sobek.Value) (*Response, error) {\n\t\t// http.get(url, params) doesn't have a body argument, so we add undefined\n\t\t// as the third argument to http.request(method, url, body, params)\n\t\targs = append([]sobek.Value{sobek.Undefined()}, args...)\n\t\treturn mi.defaultClient.Request(http.MethodGet, url, args...)\n\t})\n\tmustExport(\"head\", func(url sobek.Value, args ...sobek.Value) (*Response, error) {\n\t\t// http.head(url, params) doesn't have a body argument, so we add undefined\n\t\t// as the third argument to http.request(method, url, body, params)\n\t\targs = append([]sobek.Value{sobek.Undefined()}, args...)\n\t\treturn mi.defaultClient.Request(http.MethodHead, url, args...)\n\t})\n\tmustExport(\"post\", mi.defaultClient.getMethodClosure(http.MethodPost))\n\tmustExport(\"put\", mi.defaultClient.getMethodClosure(http.MethodPut))\n\tmustExport(\"patch\", mi.defaultClient.getMethodClosure(http.MethodPatch))\n\tmustExport(\"del\", mi.defaultClient.getMethodClosure(http.MethodDelete))\n\tmustExport(\"options\", mi.defaultClient.getMethodClosure(http.MethodOptions))\n\tmustExport(\"request\", mi.defaultClient.Request)\n\tmustExport(\"asyncRequest\", mi.defaultClient.asyncRequest)\n\tmustExport(\"batch\", mi.defaultClient.Batch)\n\tmustExport(\"setResponseCallback\", mi.defaultClient.SetResponseCallback)\n\n\tmustExport(\"expectedStatuses\", mi.expectedStatuses) // TODO: refactor?\n\n\t// TODO: actually expose the default client as k6/http.defaultClient when we\n\t// have a better HTTP API (e.g. proper Client constructor, an actual Request\n\t// object, custom Transport implementations you can pass the Client, etc.).\n\t// This will allow us to find solutions to many of the issues with the\n\t// current HTTP API that plague us:\n\t// https://github.com/grafana/k6/issues?q=is%3Aopen+is%3Aissue+label%3Anew-http\n\n\treturn mi\n}\n\n// Exports returns the JS values this module exports.\nfunc (mi *ModuleInstance) Exports() modules.Exports {\n\treturn modules.Exports{\n\t\tDefault: mi.exports,\n\t\t// TODO: add new HTTP APIs like Client, Request (see above comment in\n\t\t// NewModuleInstance()), etc. as named exports?\n\t}\n}\n\nfunc (mi *ModuleInstance) defineConstants() {\n\trt := mi.vu.Runtime()\n\tmustAddProp := func(name, val string) {\n\t\terr := mi.exports.DefineDataProperty(\n\t\t\tname, rt.ToValue(val), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_TRUE,\n\t\t)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, err)\n\t\t}\n\t}\n\tmustAddProp(\"TLS_1_0\", netext.TLS_1_0)\n\tmustAddProp(\"TLS_1_1\", netext.TLS_1_1)\n\tmustAddProp(\"TLS_1_2\", netext.TLS_1_2)\n\tmustAddProp(\"TLS_1_3\", netext.TLS_1_3)\n\tmustAddProp(\"OCSP_STATUS_GOOD\", netext.OCSP_STATUS_GOOD)\n\tmustAddProp(\"OCSP_STATUS_REVOKED\", netext.OCSP_STATUS_REVOKED)\n\tmustAddProp(\"OCSP_STATUS_SERVER_FAILED\", netext.OCSP_STATUS_SERVER_FAILED)\n\tmustAddProp(\"OCSP_STATUS_UNKNOWN\", netext.OCSP_STATUS_UNKNOWN)\n\tmustAddProp(\"OCSP_REASON_UNSPECIFIED\", netext.OCSP_REASON_UNSPECIFIED)\n\tmustAddProp(\"OCSP_REASON_KEY_COMPROMISE\", netext.OCSP_REASON_KEY_COMPROMISE)\n\tmustAddProp(\"OCSP_REASON_CA_COMPROMISE\", netext.OCSP_REASON_CA_COMPROMISE)\n\tmustAddProp(\"OCSP_REASON_AFFILIATION_CHANGED\", netext.OCSP_REASON_AFFILIATION_CHANGED)\n\tmustAddProp(\"OCSP_REASON_SUPERSEDED\", netext.OCSP_REASON_SUPERSEDED)\n\tmustAddProp(\"OCSP_REASON_CESSATION_OF_OPERATION\", netext.OCSP_REASON_CESSATION_OF_OPERATION)\n\tmustAddProp(\"OCSP_REASON_CERTIFICATE_HOLD\", netext.OCSP_REASON_CERTIFICATE_HOLD)\n\tmustAddProp(\"OCSP_REASON_REMOVE_FROM_CRL\", netext.OCSP_REASON_REMOVE_FROM_CRL)\n\tmustAddProp(\"OCSP_REASON_PRIVILEGE_WITHDRAWN\", netext.OCSP_REASON_PRIVILEGE_WITHDRAWN)\n\tmustAddProp(\"OCSP_REASON_AA_COMPROMISE\", netext.OCSP_REASON_AA_COMPROMISE)\n}\n\nfunc (mi *ModuleInstance) newCookieJar(_ sobek.ConstructorCall) *sobek.Object {\n\trt := mi.vu.Runtime()\n\tjar, err := cookiejar.New(nil)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\treturn rt.ToValue(&CookieJar{mi, jar}).ToObject(rt)\n}\n\n// getVUCookieJar returns the active cookie jar for the current VU.\nfunc (mi *ModuleInstance) getVUCookieJar(_ sobek.FunctionCall) sobek.Value {\n\trt := mi.vu.Runtime()\n\tif state := mi.vu.State(); state != nil {\n\t\treturn rt.ToValue(&CookieJar{mi, state.CookieJar})\n\t}\n\tcommon.Throw(rt, ErrJarForbiddenInInitContext)\n\treturn nil\n}\n\n// URL creates a new URL wrapper from the provided parts.\nfunc (mi *ModuleInstance) URL(parts []string, pieces ...string) (httpext.URL, error) {\n\tvar name, urlstr string\n\tfor i, part := range parts {\n\t\tname += part\n\t\turlstr += part\n\t\tif i < len(pieces) {\n\t\t\tname += \"${}\"\n\t\t\turlstr += pieces[i]\n\t\t}\n\t}\n\treturn httpext.NewURL(urlstr, name)\n}\n\n// Client represents a stand-alone HTTP client.\n//\n// TODO: move to its own file\ntype Client struct {\n\tmoduleInstance   *ModuleInstance\n\tresponseCallback func(int) bool\n}\n"
  },
  {
    "path": "js/modules/k6/http/http_test.go",
    "content": "package http\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib/netext/httpext\"\n)\n\nfunc getTestModuleInstance(t testing.TB) (*modulestest.Runtime, *ModuleInstance) {\n\truntime := modulestest.NewRuntime(t)\n\tmi, ok := New().NewModuleInstance(runtime.VU).(*ModuleInstance)\n\trequire.True(t, ok)\n\n\trequire.NoError(t, runtime.VU.Runtime().Set(\"http\", mi.Exports().Default))\n\n\treturn runtime, mi\n}\n\nfunc TestTagURL(t *testing.T) {\n\tt.Parallel()\n\n\ttestdata := map[string]struct{ u, n string }{\n\t\t`http://localhost/anything/`:               {\"http://localhost/anything/\", \"http://localhost/anything/\"},\n\t\t`http://localhost/anything/${1+1}`:         {\"http://localhost/anything/2\", \"http://localhost/anything/${}\"},\n\t\t`http://localhost/anything/${1+1}/`:        {\"http://localhost/anything/2/\", \"http://localhost/anything/${}/\"},\n\t\t`http://localhost/anything/${1+1}/${1+2}`:  {\"http://localhost/anything/2/3\", \"http://localhost/anything/${}/${}\"},\n\t\t`http://localhost/anything/${1+1}/${1+2}/`: {\"http://localhost/anything/2/3/\", \"http://localhost/anything/${}/${}/\"},\n\t}\n\tfor expr, data := range testdata {\n\t\tt.Run(\"expr=\"+expr, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\truntime, _ := getTestModuleInstance(t)\n\t\t\trt := runtime.VU.RuntimeField\n\t\t\ttag, err := httpext.NewURL(data.u, data.n)\n\t\t\trequire.NoError(t, err)\n\t\t\tv, err := rt.RunString(\"http.url`\" + expr + \"`\")\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tag, v.Export())\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "js/modules/k6/http/request.go",
    "content": "package http\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/textproto\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/grafana/sobek\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/lib/netext/httpext\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// ErrHTTPForbiddenInInitContext is used when a http requests was made in the init context\nvar ErrHTTPForbiddenInInitContext = common.NewInitContextError(\n\t\"Making http requests in the init context is not supported\")\n\n// ErrBatchForbiddenInInitContext is used when batch was made in the init context\nvar ErrBatchForbiddenInInitContext = common.NewInitContextError(\n\t\"Using batch in the init context is not supported\")\n\nfunc (c *Client) getMethodClosure(method string) func(url sobek.Value, args ...sobek.Value) (*Response, error) {\n\treturn func(url sobek.Value, args ...sobek.Value) (*Response, error) {\n\t\treturn c.Request(method, url, args...)\n\t}\n}\n\n// Request makes an http request of the provided `method` and returns a corresponding response by\n// taking sobek.Values as arguments\nfunc (c *Client) Request(method string, url sobek.Value, args ...sobek.Value) (*Response, error) {\n\tstate := c.moduleInstance.vu.State()\n\tif state == nil {\n\t\treturn nil, ErrHTTPForbiddenInInitContext\n\t}\n\tbody, params := splitRequestArgs(args)\n\n\treq, err := c.parseRequest(method, url, body, params)\n\tif err != nil {\n\t\treturn c.handleParseRequestError(err)\n\t}\n\n\tresp, err := httpext.MakeRequest(c.moduleInstance.vu.Context(), state, req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tc.processResponse(resp, req.ResponseType)\n\treturn c.responseFromHTTPext(resp), nil\n}\n\nfunc splitRequestArgs(args []sobek.Value) (body any, params sobek.Value) {\n\tif len(args) > 0 {\n\t\tbody = args[0].Export()\n\t}\n\tif len(args) > 1 {\n\t\tparams = args[1]\n\t}\n\treturn body, params\n}\n\nfunc (c *Client) handleParseRequestError(err error) (*Response, error) {\n\tstate := c.moduleInstance.vu.State()\n\n\tif state.Options.Throw.Bool {\n\t\treturn nil, err\n\t}\n\tstate.Logger.WithField(\"error\", err).Warn(\"Request Failed\")\n\tr := httpext.NewResponse()\n\tr.Error = err.Error()\n\tvar k6e httpext.K6Error\n\tif errors.As(err, &k6e) {\n\t\tr.ErrorCode = int(k6e.Code)\n\t}\n\treturn &Response{Response: r, client: c}, nil\n}\n\n// asyncRequest makes an http request of the provided `method` and returns a promise. All the networking is done off\n// the event loop and the returned promise will be resolved with the response or rejected with an error\nfunc (c *Client) asyncRequest(method string, url sobek.Value, args ...sobek.Value) (*sobek.Promise, error) {\n\tstate := c.moduleInstance.vu.State()\n\tif c.moduleInstance.vu.State() == nil {\n\t\treturn nil, ErrHTTPForbiddenInInitContext\n\t}\n\n\tbody, params := splitRequestArgs(args)\n\trt := c.moduleInstance.vu.Runtime()\n\treq, err := c.parseRequest(method, url, body, params)\n\tp, resolve, reject := rt.NewPromise()\n\tif err != nil {\n\t\tvar resp *Response\n\t\tif resp, err = c.handleParseRequestError(err); err != nil {\n\t\t\terr = reject(err)\n\t\t} else {\n\t\t\terr = resolve(resp)\n\t\t}\n\t\treturn p, err\n\t}\n\n\tcallback := c.moduleInstance.vu.RegisterCallback()\n\n\tgo func() {\n\t\tresp, err := httpext.MakeRequest(c.moduleInstance.vu.Context(), state, req)\n\t\tcallback(func() error {\n\t\t\tif err != nil {\n\t\t\t\treturn reject(err)\n\t\t\t}\n\t\t\tc.processResponse(resp, req.ResponseType)\n\t\t\treturn resolve(c.responseFromHTTPext(resp))\n\t\t})\n\t}()\n\n\treturn p, nil\n}\n\n// processResponse stores the body as an ArrayBuffer if indicated by\n// respType. This is done here instead of in httpext.readResponseBody to avoid\n// a reverse dependency on js/common or sobek.\nfunc (c *Client) processResponse(resp *httpext.Response, respType httpext.ResponseType) {\n\tif respType == httpext.ResponseTypeBinary && resp.Body != nil {\n\t\tb, ok := resp.Body.([]byte)\n\t\tif !ok {\n\t\t\tpanic(\"got an unexpected type for the response body, only []byte is accepted\")\n\t\t}\n\t\tresp.Body = c.moduleInstance.vu.Runtime().NewArrayBuffer(b)\n\t}\n}\n\nfunc (c *Client) responseFromHTTPext(resp *httpext.Response) *Response {\n\treturn &Response{Response: resp, client: c}\n}\n\n// TODO: break this function up\n//\n//nolint:gocyclo, cyclop, funlen, gocognit\nfunc (c *Client) parseRequest(\n\tmethod string, reqURL, body any, params sobek.Value,\n) (*httpext.ParsedHTTPRequest, error) {\n\trt := c.moduleInstance.vu.Runtime()\n\tstate := c.moduleInstance.vu.State()\n\tif state == nil {\n\t\treturn nil, ErrHTTPForbiddenInInitContext\n\t}\n\n\tif urlJSValue, ok := reqURL.(sobek.Value); ok {\n\t\treqURL = urlJSValue.Export()\n\t}\n\tu, err := httpext.ToURL(reqURL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresult := &httpext.ParsedHTTPRequest{\n\t\tURL: &u,\n\t\tReq: &http.Request{\n\t\t\tMethod: method,\n\t\t\tURL:    u.GetURL(),\n\t\t\tHeader: make(http.Header),\n\t\t},\n\t\tTimeout:          60 * time.Second,\n\t\tThrow:            state.Options.Throw.Bool,\n\t\tRedirects:        state.Options.MaxRedirects,\n\t\tCookies:          make(map[string]*httpext.HTTPRequestCookie),\n\t\tResponseCallback: c.responseCallback,\n\t\tTagsAndMeta:      c.moduleInstance.vu.State().Tags.GetCurrentValues(),\n\t}\n\n\tif state.Options.DiscardResponseBodies.Bool {\n\t\tresult.ResponseType = httpext.ResponseTypeNone\n\t} else {\n\t\tresult.ResponseType = httpext.ResponseTypeText\n\t}\n\n\tformatFormVal := func(v any) string {\n\t\t// TODO: handle/warn about unsupported/nested values\n\t\treturn fmt.Sprintf(\"%v\", v)\n\t}\n\n\thandleObjectBody := func(data map[string]any) error {\n\t\tif !requestContainsFile(data) {\n\t\t\tbodyQuery := make(url.Values, len(data))\n\t\t\tfor k, v := range data {\n\t\t\t\tif arr, ok := v.([]any); ok {\n\t\t\t\t\tfor _, el := range arr {\n\t\t\t\t\t\tbodyQuery.Add(k, formatFormVal(el))\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbodyQuery.Set(k, formatFormVal(v))\n\t\t\t}\n\t\t\tresult.Body = bytes.NewBufferString(bodyQuery.Encode())\n\t\t\tresult.Req.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\t\t\treturn nil\n\t\t}\n\n\t\t// handling multipart request\n\t\tresult.Body = &bytes.Buffer{}\n\t\tmpw := multipart.NewWriter(result.Body)\n\n\t\t// For parameters of type common.FileData, created with open(file, \"b\"),\n\t\t// we write the file boundary to the body buffer.\n\t\t// Otherwise parameters are treated as standard form field.\n\t\tfor k, v := range data {\n\t\t\tswitch ve := v.(type) {\n\t\t\tcase *FileData:\n\t\t\t\t// writing our own part to handle receiving\n\t\t\t\t// different content-type than the default application/octet-stream\n\t\t\t\th := make(textproto.MIMEHeader)\n\t\t\t\tescapedFilename := escapeQuotes(ve.Filename)\n\t\t\t\th.Set(\"Content-Disposition\",\n\t\t\t\t\tfmt.Sprintf(`form-data; name=\"%s\"; filename=\"%s\"`,\n\t\t\t\t\t\tk, escapedFilename))\n\t\t\t\th.Set(\"Content-Type\", ve.ContentType)\n\n\t\t\t\t// this writer will be closed either by the next part or\n\t\t\t\t// the call to mpw.Close()\n\t\t\t\tfw, err := mpw.CreatePart(h)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tdata, err := common.ToBytes(ve.Data)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif _, err := fw.Write(data); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tfw, err := mpw.CreateFormField(k)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tif _, err := fw.Write([]byte(formatFormVal(v))); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif err := mpw.Close(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresult.Req.Header.Set(\"Content-Type\", mpw.FormDataContentType())\n\t\treturn nil\n\t}\n\n\tif body != nil {\n\t\tswitch data := body.(type) {\n\t\tcase map[string]sobek.Value:\n\t\t\t// TODO: fix forms submission and serialization in k6/html before fixing this..\n\t\t\tnewData := map[string]any{}\n\t\t\tfor k, v := range data {\n\t\t\t\tnewData[k] = v.Export()\n\t\t\t}\n\t\t\tif err := handleObjectBody(newData); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase sobek.ArrayBuffer:\n\t\t\tresult.Body = bytes.NewBuffer(data.Bytes())\n\t\tcase map[string]any:\n\t\t\tif err := handleObjectBody(data); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tcase string:\n\t\t\tresult.Body = bytes.NewBufferString(data)\n\t\tcase []byte:\n\t\t\tresult.Body = bytes.NewBuffer(data)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown request body type %T\", body)\n\t\t}\n\t}\n\n\tresult.Req.Header.Set(\"User-Agent\", state.Options.UserAgent.String)\n\n\tif state.CookieJar != nil {\n\t\tresult.ActiveJar = state.CookieJar\n\t}\n\n\t// TODO: ditch sobek.Value, reflections and Object and use a simple go map and type assertions?\n\t//nolint: nestif\n\tif !common.IsNullish(params) {\n\t\tparams := params.ToObject(rt)\n\t\tfor _, k := range params.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"cookies\":\n\t\t\t\tcookiesV := params.Get(k)\n\t\t\t\tif common.IsNullish(cookiesV) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tcookies := cookiesV.ToObject(rt)\n\t\t\t\tif cookies == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor _, key := range cookies.Keys() {\n\t\t\t\t\tcookieV := cookies.Get(key)\n\t\t\t\t\tif common.IsNullish(cookieV) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tswitch cookieV.ExportType() {\n\t\t\t\t\tcase reflect.TypeFor[map[string]any]():\n\t\t\t\t\t\tresult.Cookies[key] = &httpext.HTTPRequestCookie{Name: key, Value: \"\", Replace: false}\n\t\t\t\t\t\tcookie := cookieV.ToObject(rt)\n\t\t\t\t\t\tfor _, attr := range cookie.Keys() {\n\t\t\t\t\t\t\tswitch strings.ToLower(attr) {\n\t\t\t\t\t\t\tcase \"replace\":\n\t\t\t\t\t\t\t\tresult.Cookies[key].Replace = cookie.Get(attr).ToBoolean()\n\t\t\t\t\t\t\tcase \"value\":\n\t\t\t\t\t\t\t\tresult.Cookies[key].Value = cookie.Get(attr).String()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tresult.Cookies[key] = &httpext.HTTPRequestCookie{Name: key, Value: cookieV.String(), Replace: false}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase \"headers\":\n\t\t\t\theadersV := params.Get(k)\n\t\t\t\tif common.IsNullish(headersV) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\theaders := headersV.ToObject(rt)\n\t\t\t\tif headers == nil {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor _, key := range headers.Keys() {\n\t\t\t\t\tstr := headers.Get(key).String()\n\t\t\t\t\tif strings.ToLower(key) == \"host\" {\n\t\t\t\t\t\tresult.Req.Host = str\n\t\t\t\t\t}\n\t\t\t\t\tresult.Req.Header.Set(key, str)\n\t\t\t\t}\n\t\t\tcase \"jar\":\n\t\t\t\tjarV := params.Get(k)\n\t\t\t\tif common.IsNullish(jarV) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif v, ok := jarV.Export().(*CookieJar); ok {\n\t\t\t\t\tresult.ActiveJar = v.Jar\n\t\t\t\t}\n\t\t\tcase \"compression\":\n\t\t\t\talgosString := strings.TrimSpace(params.Get(k).ToString().String())\n\t\t\t\tif algosString == \"\" {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\talgos := strings.Split(algosString, \",\")\n\t\t\t\tvar err error\n\t\t\t\tresult.Compressions = make([]httpext.CompressionType, len(algos))\n\t\t\t\tfor index, algo := range algos {\n\t\t\t\t\talgo = strings.TrimSpace(algo)\n\t\t\t\t\tresult.Compressions[index], err = httpext.CompressionTypeString(algo)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"unknown compression algorithm %s, supported algorithms are %s\",\n\t\t\t\t\t\t\talgo, httpext.CompressionTypeValues())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase \"redirects\":\n\t\t\t\tresult.Redirects = null.IntFrom(params.Get(k).ToInteger())\n\t\t\tcase \"tags\":\n\t\t\t\tif err := common.ApplyCustomUserTags(rt, &result.TagsAndMeta, params.Get(k)); err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid HTTP request metric tags: %w\", err)\n\t\t\t\t}\n\t\t\tcase \"auth\":\n\t\t\t\tresult.Auth = params.Get(k).String()\n\t\t\tcase \"timeout\":\n\t\t\t\tt, err := types.GetDurationValue(params.Get(k).Export())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid timeout value: %w\", err)\n\t\t\t\t}\n\t\t\t\tresult.Timeout = t\n\t\t\tcase \"throw\":\n\t\t\t\tresult.Throw = params.Get(k).ToBoolean()\n\t\t\tcase \"responseType\":\n\t\t\t\tresponseType, err := httpext.ResponseTypeString(params.Get(k).String())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tresult.ResponseType = responseType\n\t\t\tcase \"responseCallback\":\n\t\t\t\tv := params.Get(k).Export()\n\t\t\t\tif v == nil {\n\t\t\t\t\tresult.ResponseCallback = nil\n\t\t\t\t} else if c, ok := v.(*expectedStatuses); ok {\n\t\t\t\t\tresult.ResponseCallback = c.match\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, fmt.Errorf(\"unsupported responseCallback\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif result.ActiveJar != nil {\n\t\thttpext.SetRequestCookies(result.Req, result.ActiveJar, result.Cookies)\n\t}\n\n\treturn result, nil\n}\n\nfunc (c *Client) prepareBatchArray(requests []any) (\n\t[]httpext.BatchParsedHTTPRequest, []*Response, error,\n) {\n\treqCount := len(requests)\n\tbatchReqs := make([]httpext.BatchParsedHTTPRequest, reqCount)\n\tresults := make([]*Response, reqCount)\n\n\tfor i, req := range requests {\n\t\tresp := httpext.NewResponse()\n\t\tparsedReq, err := c.parseBatchRequest(i, req)\n\t\tif err != nil {\n\t\t\tresp.Error = err.Error()\n\t\t\tvar k6e httpext.K6Error\n\t\t\tif errors.As(err, &k6e) {\n\t\t\t\tresp.ErrorCode = int(k6e.Code)\n\t\t\t}\n\t\t\tresults[i] = c.responseFromHTTPext(resp)\n\t\t\treturn batchReqs, results, err\n\t\t}\n\t\tbatchReqs[i] = httpext.BatchParsedHTTPRequest{\n\t\t\tParsedHTTPRequest: parsedReq,\n\t\t\tResponse:          resp,\n\t\t}\n\t\tresults[i] = c.responseFromHTTPext(resp)\n\t}\n\n\treturn batchReqs, results, nil\n}\n\nfunc (c *Client) prepareBatchObject(requests map[string]any) (\n\t[]httpext.BatchParsedHTTPRequest, map[string]*Response, error,\n) {\n\treqCount := len(requests)\n\tbatchReqs := make([]httpext.BatchParsedHTTPRequest, reqCount)\n\tresults := make(map[string]*Response, reqCount)\n\n\ti := 0\n\tfor key, req := range requests {\n\t\tresp := httpext.NewResponse()\n\t\tparsedReq, err := c.parseBatchRequest(key, req)\n\t\tif err != nil {\n\t\t\tresp.Error = err.Error()\n\t\t\tvar k6e httpext.K6Error\n\t\t\tif errors.As(err, &k6e) {\n\t\t\t\tresp.ErrorCode = int(k6e.Code)\n\t\t\t}\n\t\t\tresults[key] = c.responseFromHTTPext(resp)\n\t\t\treturn batchReqs, results, err\n\t\t}\n\t\tbatchReqs[i] = httpext.BatchParsedHTTPRequest{\n\t\t\tParsedHTTPRequest: parsedReq,\n\t\t\tResponse:          resp,\n\t\t}\n\t\tresults[key] = c.responseFromHTTPext(resp)\n\t\ti++\n\t}\n\n\treturn batchReqs, results, nil\n}\n\n// Batch makes multiple simultaneous HTTP requests. The provideds reqsV should be an array of request\n// objects. Batch returns an array of responses and/or error\nfunc (c *Client) Batch(reqsV ...sobek.Value) (any, error) {\n\tstate := c.moduleInstance.vu.State()\n\tif state == nil {\n\t\treturn nil, ErrBatchForbiddenInInitContext\n\t}\n\n\tif len(reqsV) == 0 {\n\t\treturn nil, fmt.Errorf(\"no argument was provided to http.batch()\")\n\t} else if len(reqsV) > 1 {\n\t\treturn nil, fmt.Errorf(\"http.batch() accepts only an array or an object of requests\")\n\t}\n\tvar (\n\t\terr       error\n\t\tbatchReqs []httpext.BatchParsedHTTPRequest\n\t\tresults   any // either []*Response or map[string]*Response\n\t)\n\n\tswitch v := reqsV[0].Export().(type) {\n\tcase []any:\n\t\tbatchReqs, results, err = c.prepareBatchArray(v)\n\tcase map[string]any:\n\t\tbatchReqs, results, err = c.prepareBatchObject(v)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid http.batch() argument type %T\", v)\n\t}\n\n\tif err != nil {\n\t\tif state.Options.Throw.Bool {\n\t\t\treturn nil, err\n\t\t}\n\t\tstate.Logger.WithField(\"error\", err).Warn(\"A batch request failed\")\n\t\treturn results, nil\n\t}\n\n\treqCount := len(batchReqs)\n\terrs := httpext.MakeBatchRequests(\n\t\tc.moduleInstance.vu.Context(), state, batchReqs, reqCount,\n\t\tint(state.Options.Batch.Int64), int(state.Options.BatchPerHost.Int64),\n\t)\n\n\tfor range reqCount {\n\t\tif e := <-errs; e != nil && err == nil { // Save only the first error\n\t\t\terr = e\n\t\t}\n\t}\n\tfor _, req := range batchReqs {\n\t\tif req.Response != nil {\n\t\t\tc.processResponse(req.Response, req.ResponseType)\n\t\t}\n\t}\n\treturn results, err\n}\n\nfunc (c *Client) parseBatchRequest(key any, val any) (*httpext.ParsedHTTPRequest, error) {\n\tvar (\n\t\tmethod       = http.MethodGet\n\t\tok           bool\n\t\tbody, reqURL any\n\t\tparams       sobek.Value\n\t\trt           = c.moduleInstance.vu.Runtime()\n\t)\n\n\tswitch data := val.(type) {\n\tcase []any:\n\t\t// Handling of [\"GET\", \"http://example.com/\"]\n\t\tdataLen := len(data)\n\t\tif dataLen < 2 {\n\t\t\treturn nil, fmt.Errorf(\"invalid batch request '%#v'\", data)\n\t\t}\n\t\tmethod, ok = data[0].(string)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid method type '%#v'\", data[0])\n\t\t}\n\t\treqURL = data[1]\n\t\tif dataLen > 2 {\n\t\t\tbody = data[2]\n\t\t}\n\t\tif dataLen > 3 {\n\t\t\tparams = rt.ToValue(data[3])\n\t\t}\n\n\tcase map[string]any:\n\t\t// Handling of {method: \"GET\", url: \"https://test.k6.io\"}\n\t\tif _, ok := data[\"url\"]; !ok {\n\t\t\treturn nil, fmt.Errorf(\"batch request %v doesn't have a url key\", key)\n\t\t}\n\n\t\treqURL = data[\"url\"]\n\t\tbody = data[\"body\"] // It's fine if it's missing, the map lookup will return\n\n\t\tif newMethod, ok := data[\"method\"]; ok {\n\t\t\tif method, ok = newMethod.(string); !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"invalid method type '%#v'\", newMethod)\n\t\t\t}\n\t\t\tmethod = strings.ToUpper(method)\n\t\t\tif method == http.MethodGet || method == http.MethodHead {\n\t\t\t\tbody = nil\n\t\t\t}\n\t\t}\n\n\t\tif p, ok := data[\"params\"]; ok {\n\t\t\tparams = rt.ToValue(p)\n\t\t}\n\tdefault:\n\t\treqURL = val\n\t}\n\n\treturn c.parseRequest(method, reqURL, body, params)\n}\n\nfunc requestContainsFile(data map[string]any) bool {\n\tfor _, v := range data {\n\t\tif _, ok := v.(*FileData); ok {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "js/modules/k6/http/request_test.go",
    "content": "package http\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"compress/zlib\"\n\t\"context\"\n\t\"crypto/ecdsa\"\n\t\"crypto/elliptic\"\n\t\"crypto/rand\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/big\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/lib/types\"\n\n\t\"github.com/andybalholm/brotli\"\n\t\"github.com/klauspost/compress/zstd\"\n\t\"github.com/mccutchen/go-httpbin/v2/httpbin\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/js/modulestest\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO replace this with the Single version\nfunc assertRequestMetricsEmitted(t *testing.T, sampleContainers []metrics.SampleContainer, method, url string, status int, group string) {\n\tseenDuration := false\n\tseenBlocked := false\n\tseenConnecting := false\n\tseenTLSHandshaking := false\n\tseenSending := false\n\tseenWaiting := false\n\tseenReceiving := false\n\tfor _, sampleContainer := range sampleContainers {\n\t\tfor _, sample := range sampleContainer.GetSamples() {\n\t\t\ttags := sample.Tags.Map()\n\t\t\t// URL expected to be always equal name\n\t\t\t// check https://github.com/grafana/k6/issues/2584#issuecomment-1219618111 to know more\n\t\t\tassert.Equal(t, tags[\"url\"], tags[\"name\"])\n\t\t\tif tags[\"url\"] == url {\n\t\t\t\tswitch sample.Metric.Name {\n\t\t\t\tcase metrics.HTTPReqDurationName:\n\t\t\t\t\tseenDuration = true\n\t\t\t\tcase metrics.HTTPReqBlockedName:\n\t\t\t\t\tseenBlocked = true\n\t\t\t\tcase metrics.HTTPReqConnectingName:\n\t\t\t\t\tseenConnecting = true\n\t\t\t\tcase metrics.HTTPReqTLSHandshakingName:\n\t\t\t\t\tseenTLSHandshaking = true\n\t\t\t\tcase metrics.HTTPReqSendingName:\n\t\t\t\t\tseenSending = true\n\t\t\t\tcase metrics.HTTPReqWaitingName:\n\t\t\t\t\tseenWaiting = true\n\t\t\t\tcase metrics.HTTPReqReceivingName:\n\t\t\t\t\tseenReceiving = true\n\t\t\t\t}\n\n\t\t\t\tassert.Equal(t, strconv.Itoa(status), tags[\"status\"])\n\t\t\t\tassert.Equal(t, method, tags[\"method\"])\n\t\t\t\tassert.Equal(t, group, tags[\"group\"])\n\t\t\t}\n\t\t}\n\t}\n\tassert.Truef(t, seenDuration, \"url %s didn't emit Duration\", url)\n\tassert.Truef(t, seenBlocked, \"url %s didn't emit Blocked\", url)\n\tassert.Truef(t, seenConnecting, \"url %s didn't emit Connecting\", url)\n\tassert.Truef(t, seenTLSHandshaking, \"url %s didn't emit TLSHandshaking\", url)\n\tassert.Truef(t, seenSending, \"url %s didn't emit Sending\", url)\n\tassert.Truef(t, seenWaiting, \"url %s didn't emit Waiting\", url)\n\tassert.Truef(t, seenReceiving, \"url %s didn't emit Receiving\", url)\n}\n\nfunc assertRequestMetricsEmittedSingle(t *testing.T, sampleContainer metrics.SampleContainer, expectedTags map[string]string, metrics []string, callback func(sample metrics.Sample)) {\n\tt.Helper()\n\n\tmetricMap := make(map[string]bool, len(metrics))\n\tfor _, m := range metrics {\n\t\tmetricMap[m] = false\n\t}\n\tfor _, sample := range sampleContainer.GetSamples() {\n\t\ttags := sample.Tags.Map()\n\t\tv, ok := metricMap[sample.Metric.Name]\n\t\tassert.True(t, ok, \"unexpected metric %s\", sample.Metric.Name)\n\t\tassert.False(t, v, \"second metric %s\", sample.Metric.Name)\n\t\tmetricMap[sample.Metric.Name] = true\n\t\tassert.EqualValues(t, expectedTags, tags, \"%s\", tags)\n\t\tif callback != nil {\n\t\t\tcallback(sample)\n\t\t}\n\t}\n\tfor k, v := range metricMap {\n\t\tassert.True(t, v, \"didn't emit %s\", k)\n\t}\n}\n\ntype httpTestCase struct {\n\ttb       *httpmultibin.HTTPMultiBin\n\truntime  *modulestest.Runtime\n\tsamples  chan metrics.SampleContainer\n\tinstance *ModuleInstance\n\n\tlogger logrus.FieldLogger\n\thook   *testutils.SimpleLogrusHook\n}\n\nfunc newTestCase(t testing.TB) *httpTestCase {\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tregistry := metrics.NewRegistry()\n\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\n\thook := testutils.NewLogHook()\n\tlogger.AddHook(hook)\n\n\toptions := lib.Options{\n\t\tMaxRedirects: null.IntFrom(10),\n\t\tUserAgent:    null.StringFrom(\"TestUserAgent\"),\n\t\tThrow:        null.BoolFrom(true),\n\t\tSystemTags:   &metrics.DefaultSystemTagSet,\n\t\tBatch:        null.IntFrom(20),\n\t\tBatchPerHost: null.IntFrom(20),\n\t\t// HTTPDebug:    null.StringFrom(\"full\"),\n\t}\n\tsamples := make(chan metrics.SampleContainer, 1000)\n\n\tstate := &lib.State{\n\t\tOptions:    options,\n\t\tLogger:     logger,\n\t\tTLSConfig:  tb.TLSClientConfig,\n\t\tTransport:  tb.HTTPTransport,\n\t\tBufferPool: lib.NewBufferPool(),\n\t\tSamples:    samples,\n\t\tTags: lib.NewVUStateTags(registry.RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\"group\": lib.RootGroupPath,\n\t\t})),\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t}\n\n\truntime, mi := getTestModuleInstance(t)\n\n\truntime.MoveToVUContext(state)\n\treturn &httpTestCase{\n\t\ttb:       tb,\n\t\tsamples:  samples,\n\t\truntime:  runtime,\n\t\tinstance: mi,\n\t\tlogger:   logger,\n\t\thook:     hook,\n\t}\n}\n\nfunc TestRequest(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\tsr := tb.Replacer.Replace\n\n\t// Handle paths with custom logic\n\ttb.Mux.HandleFunc(\"/digest-auth/failure\", http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {\n\t\ttime.Sleep(2 * time.Second)\n\t}))\n\n\tt.Run(\"Redirects\", func(t *testing.T) {\n\t\tt.Run(\"tracing\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.get(\"HTTPBIN_URL/redirect/9\");\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\n\t\t\treqsCount := 0\n\t\t\tfor _, container := range bufSamples {\n\t\t\t\tfor _, sample := range container.GetSamples() {\n\t\t\t\t\tif sample.Metric.Name == \"http_reqs\" {\n\t\t\t\t\t\treqsCount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tassert.Equal(t, 10, reqsCount)\n\t\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/redirect/9\"), 302, \"\")\n\t\t\tfor i := 8; i > 0; i-- {\n\t\t\t\turl := sr(fmt.Sprintf(\"HTTPBIN_URL/relative-redirect/%d\", i))\n\t\t\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", url, 302, \"\")\n\t\t\t}\n\t\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/get\"), 200, \"\")\n\t\t})\n\n\t\tt.Run(\"10\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`http.get(\"HTTPBIN_URL/redirect/10\")`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"11\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.get(\"HTTPBIN_URL/redirect/11\");\n\t\t\tif (res.status != 302) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\tif (res.url != \"HTTPBIN_URL/relative-redirect/1\") { throw new Error(\"incorrect URL: \" + res.url) }\n\t\t\tif (res.headers[\"Location\"] != \"/get\") { throw new Error(\"incorrect Location header: \" + res.headers[\"Location\"]) }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\n\t\t\tt.Run(\"Unset Max\", func(t *testing.T) {\n\t\t\t\tts.hook.Reset()\n\n\t\t\t\toldOpts := state.Options\n\t\t\t\tdefer func() { state.Options = oldOpts }()\n\t\t\t\tstate.Options.MaxRedirects = null.NewInt(10, false)\n\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/redirect/11\");\n\t\t\t\tif (res.status != 302) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\t\tif (res.url != \"HTTPBIN_URL/relative-redirect/1\") { throw new Error(\"incorrect URL: \" + res.url) }\n\t\t\t\tif (res.headers[\"Location\"] != \"/get\") { throw new Error(\"incorrect Location header: \" + res.headers[\"Location\"]) }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\n\t\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\t\trequire.NotNil(t, logEntry)\n\t\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\t\tassert.Equal(t, sr(\"HTTPBIN_URL/redirect/11\"), logEntry.Data[\"url\"])\n\t\t\t\tassert.Equal(t, \"Stopped after 11 redirects and returned the redirection; pass { redirects: n } in request params or set global maxRedirects to silence this\", logEntry.Message)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"requestScopeRedirects\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.get(\"HTTPBIN_URL/redirect/1\", {redirects: 3});\n\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\tif (res.url != \"HTTPBIN_URL/get\") { throw new Error(\"incorrect URL: \" + res.url) }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"requestScopeNoRedirects\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.get(\"HTTPBIN_URL/redirect/1\", {redirects: 0});\n\t\t\tif (res.status != 302) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\tif (res.url != \"HTTPBIN_URL/redirect/1\") { throw new Error(\"incorrect URL: \" + res.url) }\n\t\t\tif (res.headers[\"Location\"] != \"/get\") { throw new Error(\"incorrect Location header: \" + res.headers[\"Location\"]) }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tt.Run(\"post body\", func(t *testing.T) {\n\t\t\ttb.Mux.HandleFunc(\"/post-redirect\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\trequire.Equal(t, http.MethodPost, r.Method)\n\t\t\t\t_, _ = io.Copy(io.Discard, r.Body)\n\t\t\t\thttp.Redirect(w, r, sr(\"HTTPBIN_URL/post\"), http.StatusPermanentRedirect)\n\t\t\t}))\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.post(\"HTTPBIN_URL/post-redirect\", \"pesho\", {redirects: 1, headers: {\"Content-Type\": \"text\"}});\n\n\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\t\t\tif (res.url != \"HTTPBIN_URL/post\") { throw new Error(\"incorrect URL: \" + res.url) }\n\t\t\tif (res.json().data != \"data:text;base64,cGVzaG8=\") { throw new Error(\"incorrect data : \" + res.json().data) }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n\tt.Run(\"Timeout\", func(t *testing.T) {\n\t\tt.Run(\"10s\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\thttp.get(\"HTTPBIN_URL/delay/1\", {\n\t\t\t\t\ttimeout: 5*1000,\n\t\t\t\t})\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"10s\", func(t *testing.T) {\n\t\t\tts.hook.Reset()\n\n\t\t\tstartTime := time.Now()\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\thttp.get(\"HTTPBIN_URL/delay/10\", {\n\t\t\t\t\ttimeout: 1*1000,\n\t\t\t\t})\n\t\t\t`))\n\t\t\tendTime := time.Now()\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"request timeout\")\n\t\t\tassert.WithinDuration(t, startTime.Add(1*time.Second), endTime, 2*time.Second)\n\n\t\t\tassert.Nil(t, ts.hook.LastEntry())\n\t\t})\n\t\tt.Run(\"10s\", func(t *testing.T) {\n\t\t\tts.hook.Reset()\n\n\t\t\tstartTime := time.Now()\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\thttp.get(\"HTTPBIN_URL/delay/10\", {\n\t\t\t\t\ttimeout: \"1s\",\n\t\t\t\t})\n\t\t\t`))\n\t\t\tendTime := time.Now()\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"request timeout\")\n\t\t\tassert.WithinDuration(t, startTime.Add(1*time.Second), endTime, 2*time.Second)\n\n\t\t\tassert.Nil(t, ts.hook.LastEntry())\n\t\t})\n\t})\n\tt.Run(\"UserAgent\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.get(\"HTTPBIN_URL/headers\");\n\t\t\tvar headers = res.json()[\"headers\"];\n\t\t\tif (headers['User-Agent'] != \"TestUserAgent\") {\n\t\t\t\tthrow new Error(\"incorrect user agent: \" + headers['User-Agent'])\n\t\t\t}\n\t\t`))\n\t\tassert.NoError(t, err)\n\n\t\tt.Run(\"Override\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/headers\", {\n\t\t\t\t\theaders: { \"User-Agent\": \"OtherUserAgent\" },\n\t\t\t\t});\n\t\t\t\tvar headers = res.json()[\"headers\"];\n\t\t\t\tif (headers['User-Agent'] != \"OtherUserAgent\") {\n\t\t\t\t\tthrow new Error(\"incorrect user agent: \" + headers['User-Agent'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tt.Run(\"Override empty\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/headers\", {\n\t\t\t\t\theaders: { \"User-Agent\": \"\" },\n\t\t\t\t});\n\t\t\t\tvar headers = res.json()[\"headers\"]\n\t\t\t\tif (typeof headers['User-Agent'] !== 'undefined') {\n\t\t\t\t\tthrow new Error(\"not undefined user agent: \" +  headers['User-Agent'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tt.Run(\"empty\", func(t *testing.T) {\n\t\t\toldUserAgent := state.Options.UserAgent\n\t\t\tdefer func() {\n\t\t\t\tstate.Options.UserAgent = oldUserAgent\n\t\t\t}()\n\n\t\t\tstate.Options.UserAgent = null.NewString(\"\", true)\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/headers\");\n\t\t\t\tvar headers = res.json()[\"headers\"]\n\t\t\t\tif (typeof headers['User-Agent'] !== 'undefined') {\n\t\t\t\t\tthrow new Error(\"not undefined user agent: \" + headers['User-Agent'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\n\t\tt.Run(\"default\", func(t *testing.T) {\n\t\t\toldUserAgent := state.Options.UserAgent\n\t\t\tdefer func() {\n\t\t\t\tstate.Options.UserAgent = oldUserAgent\n\t\t\t}()\n\n\t\t\tstate.Options.UserAgent = null.NewString(\"Default one\", false)\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/headers\");\n\t\t\t\tvar headers = res.json()[\"headers\"]\n\t\t\t\tif (headers['User-Agent'] != \"Default one\") {\n\t\t\t\t\tthrow new Error(\"incorrect user agent: \" + headers['User-Agent'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n\tt.Run(\"Compression\", func(t *testing.T) {\n\t\tt.Run(\"gzip\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPSBIN_IP_URL/gzip\");\n\t\t\t\tif (res.json()['gzipped'] != true) {\n\t\t\t\t\tthrow new Error(\"unexpected body data: \" + res.json()['gzipped'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"deflate\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/deflate\");\n\t\t\t\tif (res.json()['deflated'] != true) {\n\t\t\t\t\tthrow new Error(\"unexpected body data: \" + res.json()['deflated'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"zstd\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPSBIN_IP_URL/zstd\");\n\t\t\t\tif (res.json()['compression'] != 'zstd') {\n\t\t\t\t\tthrow new Error(\"unexpected body data: \" + res.json()['compression'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"brotli\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPSBIN_IP_URL/brotli\");\n\t\t\t\tif (res.json()['compression'] != 'br') {\n\t\t\t\t\tthrow new Error(\"unexpected body data: \" + res.json()['compression'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"zstd-br\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPSBIN_IP_URL/zstd-br\");\n\t\t\t\tif (res.json()['compression'] != 'zstd, br') {\n\t\t\t\t\tthrow new Error(\"unexpected compression: \" + res.json()['compression'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"custom compression\", func(t *testing.T) {\n\t\t\t// We should not try to decode it\n\t\t\ttb.Mux.HandleFunc(\"/customcompression\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\tw.Header().Set(\"Content-Encoding\", \"custom\")\n\t\t\t\t_, err := w.Write([]byte(`{\"custom\": true}`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}))\n\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/customcompression\");\n\t\t\t\tif (res.json()[\"custom\"] != true) {\n\t\t\t\t\tthrow new Error(\"unexpected body data: \" + res.body)\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n\tt.Run(\"CompressionWithAcceptEncodingHeader\", func(t *testing.T) {\n\t\tt.Run(\"gzip\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar params = { headers: { \"Accept-Encoding\": \"gzip\" } };\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/gzip\", params);\n\t\t\t\tif (res.json()['gzipped'] != true) {\n\t\t\t\t\tthrow new Error(\"unexpected body data: \" + res.json()['gzipped'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"deflate\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar params = { headers: { \"Accept-Encoding\": \"deflate\" } };\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/deflate\", params);\n\t\t\t\tif (res.json()['deflated'] != true) {\n\t\t\t\t\tthrow new Error(\"unexpected body data: \" + res.json()['deflated'])\n\t\t\t\t}\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n\tt.Run(\"HTTP/2\", func(t *testing.T) {\n\t\tmetrics.GetBufferedSamples(samples) // Clean up buffered samples from previous tests\n\t\t_, err := rt.RunString(sr(`\n\t\tvar res = http.request(\"GET\", \"HTTP2BIN_URL/get\");\n\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\t\tif (res.proto != \"HTTP/2.0\") { throw new Error(\"wrong proto: \" + res.proto) }\n\t\t`))\n\t\tassert.NoError(t, err)\n\n\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTP2BIN_URL/get\"), 200, \"\")\n\t\tfor _, sampleC := range bufSamples {\n\t\t\tfor _, sample := range sampleC.GetSamples() {\n\t\t\t\tproto, ok := sample.Tags.Get(\"proto\")\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, \"HTTP/2.0\", proto)\n\t\t\t}\n\t\t}\n\t})\n\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\tts.hook.Reset()\n\n\t\t_, err := rt.RunString(`http.request(\"\", \"\");`)\n\t\trequire.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"unsupported protocol scheme\")\n\n\t\tassert.Nil(t, ts.hook.LastEntry())\n\n\t\tt.Run(\"throw=false\", func(t *testing.T) {\n\t\t\tts.hook.Reset()\n\n\t\t\t_, err := rt.RunString(`\n\t\t\t\tvar res = http.request(\"GET\", \"some://example.com\", null, { throw: false });\n\t\t\t\tif (res.error.search('unsupported protocol scheme \"some\"')  == -1) {\n\t\t\t\t\tthrow new Error(\"wrong error:\" + res.error);\n\t\t\t\t}\n\t\t\t\tthrow new Error(\"another error\");\n\t\t\t`)\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"another error\")\n\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\trequire.NotNil(t, logEntry)\n\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\terr, ok := logEntry.Data[\"error\"].(error)\n\t\t\trequire.True(t, ok)\n\t\t\tassert.ErrorContains(t, err, \"unsupported protocol scheme\")\n\t\t\tassert.Equal(t, \"Request Failed\", logEntry.Message)\n\t\t})\n\t})\n\tt.Run(\"InvalidURL\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\texpErr := `invalid URL: parse \"https:// test.k6.io\": invalid character \" \" in host name`\n\t\tt.Run(\"throw=true\", func(t *testing.T) {\n\t\t\tjs := `\n\t\t\t\thttp.request(\"GET\", \"https:// test.k6.io\");\n\t\t\t\tthrow new Error(\"whoops!\"); // shouldn't be reached\n\t\t\t`\n\t\t\t_, err := rt.RunString(js)\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), expErr)\n\t\t})\n\n\t\tt.Run(\"throw=false\", func(t *testing.T) {\n\t\t\tstate.Options.Throw.Bool = false\n\t\t\tdefer func() { state.Options.Throw.Bool = true }()\n\n\t\t\tts.hook.Reset()\n\n\t\t\tjs := `\n\t\t\t\t(function(){\n\t\t\t\t\tvar r = http.request(\"GET\", \"https:// test.k6.io\");\n\t                return {error: r.error, error_code: r.error_code};\n\t\t\t\t})()\n\t\t\t`\n\t\t\tret, err := rt.RunString(js)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, ret)\n\t\t\tvar retobj map[string]any\n\t\t\tvar ok bool\n\t\t\tif retobj, ok = ret.Export().(map[string]any); !ok {\n\t\t\t\trequire.Fail(t, \"got wrong return object: %#+v\", retobj)\n\t\t\t}\n\t\t\trequire.Equal(t, int64(1020), retobj[\"error_code\"])\n\t\t\trequire.Equal(t, expErr, retobj[\"error\"])\n\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\trequire.NotNil(t, logEntry)\n\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\tassert.ErrorContains(t, logEntry.Data[\"error\"].(error), expErr)\n\t\t\tassert.Equal(t, \"Request Failed\", logEntry.Message)\n\t\t})\n\n\t\tt.Run(\"throw=false,nopanic\", func(t *testing.T) {\n\t\t\tstate.Options.Throw.Bool = false\n\t\t\tdefer func() { state.Options.Throw.Bool = true }()\n\n\t\t\tts.hook.Reset()\n\n\t\t\tjs := `\n\t\t\t\t(function(){\n\t\t\t\t\tvar r = http.request(\"GET\", \"https:// test.k6.io\");\n\t\t\t\t\tr.html();\n\t\t\t\t\tr.json();\n\t                return r.error_code; // not reached because of json()\n\t\t\t\t})()\n\t\t\t`\n\t\t\tret, err := rt.RunString(js)\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Nil(t, ret)\n\t\t\tassert.Contains(t, err.Error(), \"unexpected end of JSON input\")\n\n\t\t\tlogEntry := ts.hook.LastEntry()\n\t\t\trequire.NotNil(t, logEntry)\n\t\t\tassert.Equal(t, logrus.WarnLevel, logEntry.Level)\n\t\t\tassert.ErrorContains(t, logEntry.Data[\"error\"].(error), expErr)\n\t\t\tassert.Equal(t, \"Request Failed\", logEntry.Message)\n\t\t})\n\t})\n\n\tt.Run(\"Unroutable\", func(t *testing.T) {\n\t\t_, err := rt.RunString(`http.request(\"GET\", \"http://sdafsgdhfjg/\");`)\n\t\tassert.Error(t, err)\n\t})\n\n\tt.Run(\"Params\", func(t *testing.T) {\n\t\tfor _, literal := range []string{`undefined`, `null`} {\n\t\t\tt.Run(literal, func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(fmt.Sprintf(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, %s);\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t`), literal))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t})\n\t\t}\n\n\t\tt.Run(\"cookies\", func(t *testing.T) {\n\t\t\tt.Run(\"access\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies/set?key=value\", null, { redirects: 0 });\n\t\t\t\tif (res.cookies.key[0].value != \"value\") { throw new Error(\"wrong cookie value: \" + res.cookies.key[0].value); }\n\t\t\t\tvar props = [\"name\", \"value\", \"domain\", \"path\", \"expires\", \"max_age\", \"secure\", \"http_only\"];\n\t\t\t\tvar cookie = res.cookies.key[0];\n\t\t\t\tfor (var i = 0; i < props.length; i++) {\n\t\t\t\t\tif (cookie[props[i]] === undefined) {\n\t\t\t\t\t\tthrow new Error(\"cookie property not found: \" + props[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (Object.keys(cookie).length != props.length) {\n\t\t\t\t\tthrow new Error(\"cookie has more properties than expected: \" + JSON.stringify(Object.keys(cookie)));\n\t\t\t\t}\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies/set?key=value\"), 302, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"vuJar\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\");\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\", null, { cookies: { key2: \"value2\" } });\n\t\t\t\tif (res.json().key != \"value\") { throw new Error(\"wrong cookie value: \" + res.json().key); }\n\t\t\t\tif (res.json().key2 != \"value2\") { throw new Error(\"wrong cookie value: \" + res.json().key2); }\n\t\t\t\tvar jarCookies = jar.cookiesForURL(\"HTTPBIN_URL/cookies\");\n\t\t\t\tif (jarCookies.key[0] != \"value\") { throw new Error(\"wrong cookie value in jar\"); }\n\t\t\t\tif (jarCookies.key2 != undefined) { throw new Error(\"unexpected cookie in jar\"); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"requestScope\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\", null, { cookies: { key: \"value\" } });\n\t\t\t\tif (res.json().key != \"value\") { throw new Error(\"wrong cookie value: \" + res.json().key); }\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tvar jarCookies = jar.cookiesForURL(\"HTTPBIN_URL/cookies\");\n\t\t\t\tif (jarCookies.key != undefined) { throw new Error(\"unexpected cookie in jar\"); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"requestScopeReplace\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\");\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\", null, { cookies: { key: { value: \"replaced\", replace: true } } });\n\t\t\t\tif (res.json().key != \"replaced\") { throw new Error(\"wrong cookie value: \" + res.json().key); }\n\t\t\t\tvar jarCookies = jar.cookiesForURL(\"HTTPBIN_URL/cookies\");\n\t\t\t\tif (jarCookies.key[0] != \"value\") { throw new Error(\"wrong cookie value in jar\"); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"redirect\", func(t *testing.T) {\n\t\t\t\tt.Run(\"set cookie after redirect\", func(t *testing.T) {\n\t\t\t\t\t// TODO figure out a way to remove this ?\n\t\t\t\t\ttb.Mux.HandleFunc(\"/set-cookie-without-redirect\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t\t\tcookie := http.Cookie{\n\t\t\t\t\t\t\tName:   \"key-foo\",\n\t\t\t\t\t\t\tValue:  \"value-bar\",\n\t\t\t\t\t\t\tPath:   \"/\",\n\t\t\t\t\t\t\tDomain: sr(\"HTTPSBIN_DOMAIN\"),\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\thttp.SetCookie(w, &cookie)\n\t\t\t\t\t\tw.WriteHeader(http.StatusOK)\n\t\t\t\t\t}))\n\t\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/redirect-to?url=HTTPSBIN_URL/set-cookie-without-redirect\");\n\t\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t\t`))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tredirectURL, err := url.Parse(sr(\"HTTPSBIN_URL\"))\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\trequire.Len(t, cookieJar.Cookies(redirectURL), 1)\n\t\t\t\t\trequire.Equal(t, \"key-foo\", cookieJar.Cookies(redirectURL)[0].Name)\n\t\t\t\t\trequire.Equal(t, \"value-bar\", cookieJar.Cookies(redirectURL)[0].Value)\n\n\t\t\t\t\tassertRequestMetricsEmitted(\n\t\t\t\t\t\tt,\n\t\t\t\t\t\tmetrics.GetBufferedSamples(samples),\n\t\t\t\t\t\t\"GET\",\n\t\t\t\t\t\tsr(\"HTTPSBIN_URL/set-cookie-without-redirect\"),\n\t\t\t\t\t\t200,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t)\n\t\t\t\t})\n\t\t\t\tt.Run(\"set cookie before redirect\", func(t *testing.T) {\n\t\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\t\t\tvar res = http.request(\"GET\", \"HTTPSBIN_URL/cookies/set?key=value\");\n\t\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t\t`))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tredirectURL, err := url.Parse(sr(\"HTTPSBIN_URL/cookies\"))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\trequire.Len(t, cookieJar.Cookies(redirectURL), 1)\n\t\t\t\t\trequire.Equal(t, \"key\", cookieJar.Cookies(redirectURL)[0].Name)\n\t\t\t\t\trequire.Equal(t, \"value\", cookieJar.Cookies(redirectURL)[0].Value)\n\n\t\t\t\t\tassertRequestMetricsEmitted(\n\t\t\t\t\t\tt,\n\t\t\t\t\t\tmetrics.GetBufferedSamples(samples),\n\t\t\t\t\t\t\"GET\",\n\t\t\t\t\t\tsr(\"HTTPSBIN_URL/cookies\"),\n\t\t\t\t\t\t200,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t)\n\t\t\t\t})\n\t\t\t\tt.Run(\"set cookie after redirect and before second redirect\", func(t *testing.T) {\n\t\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tstate.CookieJar = cookieJar\n\n\t\t\t\t\t// TODO figure out a way to remove this ?\n\t\t\t\t\ttb.Mux.HandleFunc(\"/set-cookie-and-redirect\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\t\t\t\t\tcookie := http.Cookie{\n\t\t\t\t\t\t\tName:   \"key-foo\",\n\t\t\t\t\t\t\tValue:  \"value-bar\",\n\t\t\t\t\t\t\tPath:   \"/set-cookie-and-redirect\",\n\t\t\t\t\t\t\tDomain: sr(\"HTTPSBIN_DOMAIN\"),\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\thttp.SetCookie(w, &cookie)\n\t\t\t\t\t\thttp.Redirect(w, r, sr(\"HTTPBIN_IP_URL/get\"), http.StatusMovedPermanently)\n\t\t\t\t\t}))\n\n\t\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_IP_URL/redirect-to?url=HTTPSBIN_URL/set-cookie-and-redirect\");\n\t\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t\t`))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\tredirectURL, err := url.Parse(sr(\"HTTPSBIN_URL/set-cookie-and-redirect\"))\n\t\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\t\trequire.Len(t, cookieJar.Cookies(redirectURL), 1)\n\t\t\t\t\trequire.Equal(t, \"key-foo\", cookieJar.Cookies(redirectURL)[0].Name)\n\t\t\t\t\trequire.Equal(t, \"value-bar\", cookieJar.Cookies(redirectURL)[0].Value)\n\n\t\t\t\t\tfor _, cookieLessURL := range []string{\"HTTPSBIN_URL\", \"HTTPBIN_IP_URL/redirect-to\", \"HTTPBIN_IP_URL/get\"} {\n\t\t\t\t\t\tredirectURL, err = url.Parse(sr(cookieLessURL))\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\trequire.Empty(t, cookieJar.Cookies(redirectURL))\n\t\t\t\t\t}\n\n\t\t\t\t\tassertRequestMetricsEmitted(\n\t\t\t\t\t\tt,\n\t\t\t\t\t\tmetrics.GetBufferedSamples(samples),\n\t\t\t\t\t\t\"GET\",\n\t\t\t\t\t\tsr(\"HTTPBIN_IP_URL/get\"),\n\t\t\t\t\t\t200,\n\t\t\t\t\t\t\"\",\n\t\t\t\t\t)\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tt.Run(\"domain\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\", { domain: \"HTTPBIN_DOMAIN\" });\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key != \"value\") {\n\t\t\t\t\tthrow new Error(\"wrong cookie value 1: \" + res.json().key);\n\t\t\t\t}\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key2\", \"value2\", { domain: \"example.com\" });\n\t\t\t\tres = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key != \"value\") {\n\t\t\t\t\tthrow new Error(\"wrong cookie value 2: \" + res.json().key);\n\t\t\t\t}\n\t\t\t\tif (res.json().key2 != undefined) {\n\t\t\t\t\tthrow new Error(\"cookie 'key2' unexpectedly found\");\n\t\t\t\t}\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"path\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\", { path: \"/cookies\" });\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key != \"value\") {\n\t\t\t\t\tthrow new Error(\"wrong cookie value: \" + res.json().key);\n\t\t\t\t}\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key2\", \"value2\", { path: \"/some-other-path\" });\n\t\t\t\tres = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key != \"value\") {\n\t\t\t\t\tthrow new Error(\"wrong cookie value: \" + res.json().key);\n\t\t\t\t}\n\t\t\t\tif (res.json().key2 != undefined) {\n\t\t\t\t\tthrow new Error(\"cookie 'key2' unexpectedly found\");\n\t\t\t\t}\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"expires\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\", { expires: \"Sun, 24 Jul 1983 17:01:02 GMT\" });\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key != undefined) {\n\t\t\t\t\tthrow new Error(\"cookie 'key' unexpectedly found\");\n\t\t\t\t}\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\", { expires: \"Sat, 24 Jul 2083 17:01:02 GMT\" });\n\t\t\t\tres = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key != \"value\") {\n\t\t\t\t\tthrow new Error(\"cookie 'key' not found\");\n\t\t\t\t}\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"secure\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPSBIN_IP_URL/cookies\", \"key\", \"value\", { secure: true });\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPSBIN_IP_URL/cookies\");\n\t\t\t\tif (res.json().key != \"value\") {\n\t\t\t\t\tthrow new Error(\"wrong cookie value: \" + res.json().key);\n\t\t\t\t}\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPSBIN_IP_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"localJar\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = new http.CookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\");\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\", null, { cookies: { key2: \"value2\" }, jar: jar });\n\t\t\t\tif (res.json().key != \"value\") { throw new Error(\"wrong cookie value: \" + res.json().key); }\n\t\t\t\tif (res.json().key2 != \"value2\") { throw new Error(\"wrong cookie value: \" + res.json().key2); }\n\t\t\t\tvar jarCookies = jar.cookiesForURL(\"HTTPBIN_URL/cookies\");\n\t\t\t\tif (jarCookies.key[0] != \"value\") { throw new Error(\"wrong cookie value in jar: \" + jarCookies.key[0]); }\n\t\t\t\tif (jarCookies.key2 != undefined) { throw new Error(\"unexpected cookie in jar\"); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"clear\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\");\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key != \"value\") { throw new Error(\"cookie 'key' unexpectedly don't found\"); }\n\t\t\t\tjar.clear('HTTPBIN_URL/cookies');\n\t\t\t\tres = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key == \"value\") { throw new Error(\"wrong clean: unexpected cookie in jar\"); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"delete\", func(t *testing.T) {\n\t\t\t\tcookieJar, err := cookiejar.New(nil)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tstate.CookieJar = cookieJar\n\t\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar jar = http.cookieJar();\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key1\", \"value1\");\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key2\", \"value2\");\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key1 != \"value1\" || res.json().key2 != \"value2\") { throw new Error(\"cookie 'keys' unexpectedly don't found\"); }\n\t\t\t\tjar.delete('HTTPBIN_URL/cookies', \"key1\");\n\t\t\t\tres = http.request(\"GET\", \"HTTPBIN_URL/cookies\");\n\t\t\t\tif (res.json().key1 == \"value1\" || res.json().key2 != \"value2\"  ) { throw new Error(\"wrong clean: unexpected cookie in jar\"); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/cookies\"), 200, \"\")\n\t\t\t})\n\t\t})\n\n\t\tt.Run(\"auth\", func(t *testing.T) {\n\t\t\tt.Run(\"basic\", func(t *testing.T) {\n\t\t\t\turl := sr(\"http://bob:pass@HTTPBIN_IP:HTTPBIN_PORT/basic-auth/bob/pass\")\n\t\t\t\turlExpected := sr(\"http://****:****@HTTPBIN_IP:HTTPBIN_PORT/basic-auth/bob/pass\")\n\n\t\t\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\t\t\tvar res = http.request(\"GET\", \"%s\", null, {});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t`, url))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", urlExpected, 200, \"\")\n\t\t\t})\n\t\t\tt.Run(\"digest\", func(t *testing.T) {\n\t\t\t\tt.Run(\"success\", func(t *testing.T) {\n\t\t\t\t\turl := sr(\"http://bob:pass@HTTPBIN_IP:HTTPBIN_PORT/digest-auth/auth/bob/pass\")\n\t\t\t\t\turlRaw := sr(\"HTTPBIN_IP_URL/digest-auth/auth/bob/pass\")\n\n\t\t\t\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\t\t\t\tvar res = http.request(\"GET\", \"%s\", null, { auth: \"digest\" });\n\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t\tif (res.error_code != 0) { throw new Error(\"wrong error code: \" + res.error_code); }\n\t\t\t\t\t`, url))\n\t\t\t\t\tassert.NoError(t, err)\n\n\t\t\t\t\tsampleContainers := metrics.GetBufferedSamples(samples)\n\t\t\t\t\tassertRequestMetricsEmitted(t, sampleContainers[0:1], \"GET\", urlRaw, 401, \"\")\n\t\t\t\t\tassertRequestMetricsEmitted(t, sampleContainers[1:2], \"GET\", urlRaw, 200, \"\")\n\t\t\t\t})\n\t\t\t\tt.Run(\"failure\", func(t *testing.T) {\n\t\t\t\t\turl := sr(\"http://bob:pass@HTTPBIN_IP:HTTPBIN_PORT/digest-auth/failure\")\n\n\t\t\t\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\t\t\t\tvar res = http.request(\"GET\", \"%s\", null, { auth: \"digest\", timeout: 1, throw: false });\n\t\t\t\t\t`, url))\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\n\t\tt.Run(\"headers\", func(t *testing.T) {\n\t\t\tfor _, literal := range []string{`null`, `undefined`} {\n\t\t\t\tt.Run(literal, func(t *testing.T) {\n\t\t\t\t\t_, err := rt.RunString(fmt.Sprintf(sr(`\n\t\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, { headers: %s });\n\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t\t`), literal))\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tt.Run(\"object\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, {\n\t\t\t\t\theaders: { \"X-My-Header\": \"value\" },\n\t\t\t\t});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.json().headers[\"X-My-Header\"] != \"value\") { throw new Error(\"wrong X-My-Header: \" + res.json().headers[\"X-My-Header\"]); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"Host\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, {\n\t\t\t\t\theaders: { \"Host\": \"HTTPBIN_DOMAIN\" },\n\t\t\t\t});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.json().headers[\"Host\"] != \"HTTPBIN_DOMAIN\") { throw new Error(\"wrong Host: \" + res.json().headers[\"Host\"]); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"response_request\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, {\n\t\t\t\t\theaders: { \"host\": \"HTTPBIN_DOMAIN\" },\n\t\t\t\t});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.request.headers[\"Host\"] != \"HTTPBIN_DOMAIN\") { throw new Error(\"wrong Host: \" + res.request.headers[\"Host\"]); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"differentHost\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar custHost = 'k6.io';\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, {\n\t\t\t\t\theaders: { \"host\": custHost },\n\t\t\t\t});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.request.headers[\"Host\"] != custHost) { throw new Error(\"wrong Host: \" + res.request.headers[\"Host\"]); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t})\n\t\t})\n\n\t\tt.Run(\"tags\", func(t *testing.T) {\n\t\t\tfor _, literal := range []string{`null`, `undefined`} {\n\t\t\t\tt.Run(literal, func(t *testing.T) {\n\t\t\t\t\t_, err := rt.RunString(fmt.Sprintf(sr(`\n\t\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, { tags: %s });\n\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t\t`), literal))\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tt.Run(\"name/none\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\");\n\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"name/request\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, { tags: { name: \"myReq\" }});\n\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\t// setting name will overwrite both name and url tags\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", \"myReq\", 200, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"name/template\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(\"http.get(http.url`\" + sr(`HTTPBIN_URL/anythingwrong/${1+1}`) + \"`);\")\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\t// There's no /anythingwrong endpoint in the go-httpbin library we're using, hence the 404,\n\t\t\t\t// but it doesn't matter for this test.\n\t\t\t\t//\n\t\t\t\t// Setting name will overwrite both name and url tags\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/anythingwrong/${}\"), 404, \"\")\n\t\t\t})\n\n\t\t\tt.Run(\"object\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, { tags: { tag: \"value\" } });\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\t\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", sr(\"HTTPBIN_URL/headers\"), 200, \"\")\n\t\t\t\tfor _, sampleC := range bufSamples {\n\t\t\t\t\tfor _, sample := range sampleC.GetSamples() {\n\t\t\t\t\t\ttagValue, ok := sample.Tags.Get(\"tag\")\n\t\t\t\t\t\tassert.True(t, ok)\n\t\t\t\t\t\tassert.Equal(t, \"value\", tagValue)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tt.Run(\"tags-precedence\", func(t *testing.T) {\n\t\t\t\toldTags := state.Tags\n\t\t\t\tdefer func() { state.Tags = oldTags }()\n\t\t\t\tstate.Tags = lib.NewVUStateTags(metrics.NewRegistry().RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\t\t\t\"runtag1\": \"val1\",\n\t\t\t\t\t\"runtag2\": \"val2\",\n\t\t\t\t}))\n\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/headers\", null, { tags: { method: \"test\", name: \"myName\", runtag1: \"fromreq\" } });\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\n\t\t\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\t\t\t\t// Setting the name tag will also overwrite the url tag\n\t\t\t\tassertRequestMetricsEmitted(t, bufSamples, \"GET\", \"myName\", 200, \"\")\n\t\t\t\tfor _, sampleC := range bufSamples {\n\t\t\t\t\tfor _, sample := range sampleC.GetSamples() {\n\t\t\t\t\t\ttagValue, ok := sample.Tags.Get(\"method\")\n\t\t\t\t\t\tassert.True(t, ok)\n\t\t\t\t\t\tassert.Equal(t, \"GET\", tagValue)\n\n\t\t\t\t\t\ttagValue, ok = sample.Tags.Get(\"name\")\n\t\t\t\t\t\tassert.True(t, ok)\n\t\t\t\t\t\tassert.Equal(t, \"myName\", tagValue)\n\n\t\t\t\t\t\ttagValue, ok = sample.Tags.Get(\"runtag1\")\n\t\t\t\t\t\tassert.True(t, ok)\n\t\t\t\t\t\tassert.Equal(t, \"fromreq\", tagValue)\n\n\t\t\t\t\t\ttagValue, ok = sample.Tags.Get(\"runtag2\")\n\t\t\t\t\t\tassert.True(t, ok)\n\t\t\t\t\t\tassert.Equal(t, \"val2\", tagValue)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t})\n\n\tt.Run(\"GET\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\tvar res = http.get(\"HTTPBIN_URL/get?a=1&b=2\", {headers: {\"X-We-Want-This\": \"value\"}});\n\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\tif (res.json().args.a != \"1\") { throw new Error(\"wrong ?a: \" + res.json().args.a); }\n\t\tif (res.json().args.b != \"2\") { throw new Error(\"wrong ?b: \" + res.json().args.b); }\n\t\tif (res.request.headers[\"X-We-Want-This\"] != \"value\") { throw new Error(\"Missing or invalid X-We-Want-This header!\"); }\n\t\t`))\n\t\trequire.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/get?a=1&b=2\"), 200, \"\")\n\n\t\tt.Run(\"Tagged\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(`\n\t\t\tvar a = \"1\";\n\t\t\tvar b = \"2\";\n\t\t\tvar res = http.get(http.url` + \"`\" + sr(`HTTPBIN_URL/get?a=${a}&b=${b}`) + \"`\" + `);\n\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\tif (res.json().args.a != a) { throw new Error(\"wrong ?a: \" + res.json().args.a); }\n\t\t\tif (res.json().args.b != b) { throw new Error(\"wrong ?b: \" + res.json().args.b); }\n\t\t\t`)\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/get?a=${}&b=${}\"), 200, \"\")\n\t\t})\n\t})\n\tt.Run(\"HEAD\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\tvar res = http.head(\"HTTPBIN_URL/get?a=1&b=2\", {headers: {\"X-We-Want-This\": \"value\"}});\n\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\tif (res.body.length != 0) { throw new Error(\"HEAD responses shouldn't have a body\"); }\n\t\tif (res.request.headers[\"X-We-Want-This\"] != \"value\") { throw new Error(\"Missing or invalid X-We-Want-This header!\"); }\n\t\t`))\n\t\tassert.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"HEAD\", sr(\"HTTPBIN_URL/get?a=1&b=2\"), 200, \"\")\n\t})\n\n\tt.Run(\"OPTIONS\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\tvar res = http.options(\"HTTPBIN_URL/?a=1&b=2\", null, {headers: {\"X-We-Want-This\": \"value\"}});\n\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\tif (!res.headers[\"Access-Control-Allow-Methods\"]) { throw new Error(\"Missing Access-Control-Allow-Methods header!\"); }\n\t\tif (res.request.headers[\"X-We-Want-This\"] != \"value\") { throw new Error(\"Missing or invalid X-We-Want-This header!\"); }\n\t\t`))\n\t\trequire.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"OPTIONS\", sr(\"HTTPBIN_URL/?a=1&b=2\"), 200, \"\")\n\t})\n\n\t// DELETE HTTP requests shouldn't usually send a request body, they should use url parameters instead; references:\n\t// https://golang.org/pkg/net/http/#Request.ParseForm\n\t// https://stackoverflow.com/questions/299628/is-an-entity-body-allowed-for-an-http-delete-request\n\t// https://tools.ietf.org/html/rfc7231#section-4.3.5\n\tt.Run(\"DELETE\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\tvar res = http.del(\"HTTPBIN_URL/delete?test=mest\", null, {headers: {\"X-We-Want-This\": \"value\"}});\n\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\tif (res.json().args.test != \"mest\") { throw new Error(\"wrong args: \" + JSON.stringify(res.json().args)); }\n\t\tif (res.request.headers[\"X-We-Want-This\"] != \"value\") { throw new Error(\"Missing or invalid X-We-Want-This header!\"); }\n\t\t`))\n\t\trequire.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"DELETE\", sr(\"HTTPBIN_URL/delete?test=mest\"), 200, \"\")\n\t})\n\n\tpostMethods := map[string]string{\n\t\t\"POST\":  \"post\",\n\t\t\"PUT\":   \"put\",\n\t\t\"PATCH\": \"patch\",\n\t}\n\tfor method, fn := range postMethods {\n\t\tt.Run(method, func(t *testing.T) {\n\t\t\t_, err := rt.RunString(fmt.Sprintf(sr(`\n\t\t\t\tvar res = http.%s(\"HTTPBIN_URL/%s\", \"data\", {headers: {\"X-We-Want-This\": \"value\"}});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tvar expectedData = \"data:application/octet-stream;base64,ZGF0YQ==\"\n\t\t\t\tif (res.json().data != expectedData) { throw new Error(\"wrong data: \" + res.json().data); }\n\t\t\t\tif (res.json().headers[\"Content-Type\"]) { throw new Error(\"content type set: \" + res.json().headers[\"Content-Type\"]); }\n\t\t\t\tif (res.request.headers[\"X-We-Want-This\"] != \"value\") { throw new Error(\"Missing or invalid X-We-Want-This header!\"); }\n\t\t\t\t`), fn, strings.ToLower(method)))\n\t\t\trequire.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), method, sr(\"HTTPBIN_URL/\")+strings.ToLower(method), 200, \"\")\n\n\t\t\tt.Run(\"object\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(fmt.Sprintf(sr(`\n\t\t\t\tvar equalArray = function(a, b) {\n\t\t\t\t\treturn a.length === b.length && a.every(function(v, i) { return v === b[i]});\n\t\t\t\t}\n\t\t\t\tvar res = http.%s(\"HTTPBIN_URL/%s\", {a: \"a\", b: 2, c: [\"one\", \"two\"]});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.json().form.a != \"a\") { throw new Error(\"wrong a=: \" + res.json().form.a); }\n\t\t\t\tif (res.json().form.b != \"2\") { throw new Error(\"wrong b=: \" + res.json().form.b); }\n\t\t\t\tif (!equalArray(res.json().form.c, [\"one\", \"two\"])) { throw new Error(\"wrong c: \" + res.json().form.c); }\n\t\t\t\tif (res.json().headers[\"Content-Type\"] != \"application/x-www-form-urlencoded\") { throw new Error(\"wrong content type: \" + res.json().headers[\"Content-Type\"]); }\n\t\t\t\t`), fn, strings.ToLower(method)))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), method, sr(\"HTTPBIN_URL/\")+strings.ToLower(method), 200, \"\")\n\t\t\t\tt.Run(\"Content-Type\", func(t *testing.T) {\n\t\t\t\t\t_, err := rt.RunString(fmt.Sprintf(sr(`\n\t\t\t\t\t\tvar res = http.%s(\"HTTPBIN_URL/%s\", {a: \"a\", b: 2}, {headers: {\"Content-Type\": \"application/x-www-form-urlencoded; charset=utf-8\"}});\n\t\t\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\t\t\tif (res.json().form.a != \"a\") { throw new Error(\"wrong a=: \" + res.json().form.a); }\n\t\t\t\t\t\tif (res.json().form.b != \"2\") { throw new Error(\"wrong b=: \" + res.json().form.b); }\n\t\t\t\t\t\tif (res.json().headers[\"Content-Type\"] != \"application/x-www-form-urlencoded; charset=utf-8\") { throw new Error(\"wrong content type: \" + res.json().headers[\"Content-Type\"]); }\n\t\t\t\t\t\t`), fn, strings.ToLower(method)))\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), method, sr(\"HTTPBIN_URL/\")+strings.ToLower(method), 200, \"\")\n\t\t\t\t})\n\t\t\t})\n\t\t})\n\t}\n\n\tt.Run(\"HTTPRequest\", func(t *testing.T) {\n\t\tt.Run(\"EmptyBody\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar reqUrl = \"HTTPBIN_URL/cookies\"\n\t\t\t\tvar res = http.get(reqUrl);\n\t\t\t\tvar jar = new http.CookieJar();\n\n\t\t\t\tjar.set(\"HTTPBIN_URL/cookies\", \"key\", \"value\");\n\t\t\t\tres = http.request(\"GET\", \"HTTPBIN_URL/cookies\", null, { cookies: { key2: \"value2\" }, jar: jar });\n\n\t\t\t\tif (res.json().key != \"value\") { throw new Error(\"wrong cookie value: \" + res.json().key); }\n\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.request[\"method\"] !== \"GET\") { throw new Error(\"http request method was not \\\"GET\\\": \" + JSON.stringify(res.request)) }\n\t\t\t\tif (res.request[\"body\"].length != 0) { throw new Error(\"http request body was not null: \" + JSON.stringify(res.request[\"body\"])) }\n\t\t\t\tif (res.request[\"url\"] != reqUrl) {\n\t\t\t\t\tthrow new Error(\"wrong http request url: \" + JSON.stringify(res.request))\n\t\t\t\t}\n\t\t\t\tif (res.request[\"cookies\"][\"key2\"][0].name != \"key2\") { throw new Error(\"wrong http request cookies: \" + JSON.stringify(JSON.stringify(res.request[\"cookies\"][\"key2\"]))) }\n\t\t\t\tif (res.request[\"headers\"][\"User-Agent\"][0] != \"TestUserAgent\") { throw new Error(\"wrong http request headers: \" + JSON.stringify(res.request)) }\n\t\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t\tt.Run(\"NonEmptyBody\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.post(\"HTTPBIN_URL/post\", {a: \"a\", b: 2}, {headers: {\"Content-Type\": \"application/x-www-form-urlencoded; charset=utf-8\"}});\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.request[\"body\"] != \"a=a&b=2\") { throw new Error(\"http request body was not set properly: \" + JSON.stringify(res.request))}\n\t\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t})\n}\n\nfunc TestRequestCancellation(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tmi := ts.instance\n\tsr := tb.Replacer.Replace\n\n\tts.hook.Reset()\n\n\ttestVU, ok := mi.vu.(*modulestest.VU)\n\trequire.True(t, ok)\n\n\tnewctx, cancel := context.WithCancel(mi.vu.Context())\n\ttestVU.CtxField = newctx\n\tcancel()\n\n\t_, err := rt.RunString(sr(`http.get(\"HTTPBIN_URL/get/\");`))\n\tassert.Error(t, err)\n\tassert.Nil(t, ts.hook.LastEntry())\n}\n\nfunc TestRequestArrayBufferBody(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tsr := tb.Replacer.Replace\n\n\ttb.Mux.HandleFunc(\"/post-arraybuffer\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\trequire.Equal(t, \"POST\", r.Method)\n\t\tvar in bytes.Buffer\n\t\t_, err := io.Copy(&in, r.Body)\n\t\trequire.NoError(t, err)\n\t\t_, err = w.Write(in.Bytes())\n\t\trequire.NoError(t, err)\n\t}))\n\n\ttestCases := []struct {\n\t\tarr, expected string\n\t}{\n\t\t{\"Uint8Array\", \"104,101,108,108,111\"},\n\t\t{\"Uint16Array\", \"104,0,101,0,108,0,108,0,111,0\"},\n\t\t{\"Uint32Array\", \"104,0,0,0,101,0,0,0,108,0,0,0,108,0,0,0,111,0,0,0\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.arr, func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(fmt.Sprintf(`\n\t\t\tvar arr = new %[1]s([104, 101, 108, 108, 111]); // \"hello\"\n\t\t\tvar res = http.post(\"HTTPBIN_URL/post-arraybuffer\", arr.buffer, { responseType: 'binary' });\n\n\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status) }\n\n\t\t\tvar resTyped = new Uint8Array(res.body);\n\t\t\tvar exp = new %[1]s([%[2]s]);\n\t\t\tif (exp.length !== resTyped.length) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"incorrect data length: expected \" + exp.length + \", received \" + resTypedLength)\n\t\t\t}\n\t\t\tfor (var i = 0; i < exp.length; i++) {\n\t\t\t\tif (exp[i] !== resTyped[i])\t{\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"incorrect data at index \" + i + \": expected \" + exp[i] + \", received \" + resTyped[i])\n\t\t\t\t}\n\t\t\t}\n\t\t\t`, tc.arr, tc.expected)))\n\t\t\tassert.NoError(t, err)\n\t\t})\n\t}\n}\n\nfunc TestRequestCompression(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\t// We don't expect any failed requests\n\tstate.Options.Throw = null.BoolFrom(true)\n\n\ttext := `\n\tLorem ipsum dolor sit amet, consectetur adipiscing elit.\n\tMaecenas sed pharetra sapien. Nunc laoreet molestie ante ac gravida.\n\tEtiam interdum dui viverra posuere egestas. Pellentesque at dolor tristique,\n\tmattis turpis eget, commodo purus. Nunc orci aliquam.`\n\n\tdecompress := func(algo string, input io.Reader) io.Reader {\n\t\tswitch algo {\n\t\tcase \"br\":\n\t\t\tw := brotli.NewReader(input)\n\t\t\treturn w\n\t\tcase \"gzip\":\n\t\t\tw, err := gzip.NewReader(input)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\treturn w\n\t\tcase \"deflate\":\n\t\t\tw, err := zlib.NewReader(input)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\treturn w\n\t\tcase \"zstd\":\n\t\t\tw, err := zstd.NewReader(input)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatal(err)\n\t\t\t}\n\t\t\treturn w\n\t\tdefault:\n\t\t\tt.Fatal(\"unknown algorithm \" + algo)\n\t\t}\n\t\treturn nil // unreachable\n\t}\n\n\tvar (\n\t\texpectedEncoding string\n\t\tactualEncoding   string\n\t)\n\ttb.Mux.HandleFunc(\"/compressed-text\", http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {\n\t\trequire.Equal(t, expectedEncoding, r.Header.Get(\"Content-Encoding\"))\n\n\t\texpectedLength, err := strconv.Atoi(r.Header.Get(\"Content-Length\"))\n\t\trequire.NoError(t, err)\n\t\talgos := strings.Split(actualEncoding, \", \")\n\t\tcompressedBuf := new(bytes.Buffer)\n\t\tn, err := io.Copy(compressedBuf, r.Body)\n\t\trequire.Equal(t, expectedLength, int(n))\n\t\trequire.NoError(t, err)\n\t\tvar prev io.Reader = compressedBuf\n\n\t\tif expectedEncoding != \"\" {\n\t\t\tfor i := len(algos) - 1; i >= 0; i-- {\n\t\t\t\tprev = decompress(algos[i], prev)\n\t\t\t}\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\t\t_, err = io.Copy(&buf, prev)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, text, buf.String())\n\t}))\n\n\ttestCases := []struct {\n\t\tname          string\n\t\tcompression   string\n\t\texpectedError string\n\t}{\n\t\t{compression: \"\"},\n\t\t{compression: \"  \"},\n\t\t{compression: \"gzip\"},\n\t\t{compression: \"gzip, gzip\"},\n\t\t{compression: \"gzip,   gzip \"},\n\t\t{compression: \"gzip,gzip\"},\n\t\t{compression: \"gzip, gzip, gzip, gzip, gzip, gzip, gzip\"},\n\t\t{compression: \"deflate\"},\n\t\t{compression: \"deflate, gzip\"},\n\t\t{compression: \"gzip,deflate, gzip\"},\n\t\t{compression: \"zstd\"},\n\t\t{compression: \"zstd, gzip, deflate\"},\n\t\t{compression: \"br\"},\n\t\t{compression: \"br, gzip, deflate\"},\n\t\t{\n\t\t\tcompression:   \"George\",\n\t\t\texpectedError: `unknown compression algorithm George`,\n\t\t},\n\t\t{\n\t\t\tcompression:   \"gzip, George\",\n\t\t\texpectedError: `unknown compression algorithm George`,\n\t\t},\n\t}\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.compression, func(t *testing.T) {\n\t\t\talgos := strings.Split(testCase.compression, \",\")\n\t\t\tfor i, algo := range algos {\n\t\t\t\talgos[i] = strings.TrimSpace(algo)\n\t\t\t}\n\t\t\texpectedEncoding = strings.Join(algos, \", \")\n\t\t\tactualEncoding = expectedEncoding\n\t\t\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\thttp.post(\"HTTPBIN_URL/compressed-text\", ` + \"`\" + text + \"`\" + `,  {\"compression\": \"` + testCase.compression + `\"});\n\t`))\n\t\t\tif testCase.expectedError == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), testCase.expectedError)\n\t\t\t}\n\t\t})\n\t}\n\n\tt.Run(\"custom set header\", func(t *testing.T) {\n\t\texpectedEncoding = \"not, valid\"\n\t\tactualEncoding = \"gzip, deflate\"\n\n\t\tts.hook.Drain()\n\t\tt.Run(\"encoding\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\t\t\thttp.post(\"HTTPBIN_URL/compressed-text\", ` + \"`\" + text + \"`\" + `,\n\t\t\t\t\t{\"compression\": \"` + actualEncoding + `\",\n\t\t\t\t\t \"headers\": {\"Content-Encoding\": \"` + expectedEncoding + `\"}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t`))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, ts.hook.Drain())\n\t\t})\n\n\t\tt.Run(\"encoding and length\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\t\t\thttp.post(\"HTTPBIN_URL/compressed-text\", ` + \"`\" + text + \"`\" + `,\n\t\t\t\t\t{\"compression\": \"` + actualEncoding + `\",\n\t\t\t\t\t \"headers\": {\"Content-Encoding\": \"` + expectedEncoding + `\",\n\t\t\t\t\t\t\t\t \"Content-Length\": \"12\"}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t`))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotEmpty(t, ts.hook.Drain())\n\t\t})\n\n\t\texpectedEncoding = actualEncoding\n\t\tt.Run(\"correct encoding\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\t\t\thttp.post(\"HTTPBIN_URL/compressed-text\", ` + \"`\" + text + \"`\" + `,\n\t\t\t\t\t{\"compression\": \"` + actualEncoding + `\",\n\t\t\t\t\t \"headers\": {\"Content-Encoding\": \"` + actualEncoding + `\"}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t`))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, ts.hook.Drain())\n\t\t})\n\n\t\t// TODO: move to some other test?\n\t\tt.Run(\"correct length\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(tb.Replacer.Replace(\n\t\t\t\t`http.post(\"HTTPBIN_URL/post\", \"0123456789\", { \"headers\": {\"Content-Length\": \"10\"}});`,\n\t\t\t))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, ts.hook.Drain())\n\t\t})\n\n\t\tt.Run(\"content-length is set\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\t\t\tvar resp = http.post(\"HTTPBIN_URL/post\", \"0123456789\");\n\t\t\t\tif (resp.json().headers[\"Content-Length\"][0] != \"10\") {\n\t\t\t\t\tthrow new Error(\"content-length not set: \" + JSON.stringify(resp.json().headers));\n\t\t\t\t}\n\t\t\t`))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, ts.hook.Drain())\n\t\t})\n\t})\n}\n\nfunc TestResponseTypes(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\t// We don't expect any failed requests\n\tstate.Options.Throw = null.BoolFrom(true)\n\n\ttext := `•?((¯°·._.• ţ€$ţɨɲǥ µɲɨȼ๏ď€ ɨɲ Ќ6 •._.·°¯))؟•`\n\ttextLen := len(text)\n\ttb.Mux.HandleFunc(\"/get-text\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tn, err := w.Write([]byte(text))\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, textLen, n)\n\t}))\n\ttb.Mux.HandleFunc(\"/compare-text\", http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {\n\t\tbody, err := io.ReadAll(r.Body)\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, text, string(body))\n\t}))\n\n\tbinaryLen := 300\n\tbinary := make([]byte, binaryLen)\n\tfor i := range binaryLen {\n\t\tbinary[i] = byte(i)\n\t}\n\ttb.Mux.HandleFunc(\"/get-bin\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tn, err := w.Write(binary)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, binaryLen, n)\n\t}))\n\ttb.Mux.HandleFunc(\"/compare-bin\", http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {\n\t\tbody, err := io.ReadAll(r.Body)\n\t\trequire.NoError(t, err)\n\t\tassert.True(t, bytes.Equal(binary, body))\n\t}))\n\n\treplace := func(s string) string {\n\t\treturn strings.NewReplacer(\n\t\t\t\"EXP_TEXT\", text,\n\t\t\t\"EXP_BIN_LEN\", strconv.Itoa(binaryLen),\n\t\t).Replace(tb.Replacer.Replace(s))\n\t}\n\n\t_, err := rt.RunString(replace(`\n\t\tvar expText = \"EXP_TEXT\";\n\t\tvar expBinLength = EXP_BIN_LEN;\n\n\t\t// Check default behaviour with a unicode text\n\t\tvar respTextImplicit = http.get(\"HTTPBIN_URL/get-text\").body;\n\t\tif (respTextImplicit !== expText) {\n\t\t\tthrow new Error(\"default response body should be '\" + expText + \"' but was '\" + respTextImplicit + \"'\");\n\t\t}\n\t\thttp.post(\"HTTPBIN_URL/compare-text\", respTextImplicit);\n\n\t\t// Check discarding of responses\n\t\tvar respNone = http.get(\"HTTPBIN_URL/get-text\", { responseType: \"none\" }).body;\n\t\tif (respNone != null) {\n\t\t\tthrow new Error(\"none response body should be null but was \" + respNone);\n\t\t}\n\n\t\t// Check binary transmission of the text response as well\n\t\tvar respBin = http.get(\"HTTPBIN_URL/get-text\", { responseType: \"binary\" });\n\n\t\t// Convert a UTF-8 ArrayBuffer to a JS string\n\t\tvar respBinText = String.fromCharCode.apply(null, new Uint8Array(respBin.body));\n\t\tvar strConv = decodeURIComponent(escape(respBinText));\n\t\tif (strConv !== expText) {\n\t\t\tthrow new Error(\"converted response body should be '\" + expText + \"' but was '\" + strConv + \"'\");\n\t\t}\n\t\thttp.post(\"HTTPBIN_URL/compare-text\", respBin.body);\n\n\t\t// Check binary response\n\t\tvar respBin = http.get(\"HTTPBIN_URL/get-bin\", { responseType: \"binary\" });\n\t\tvar respBinTyped = new Uint8Array(respBin.body);\n\t\tif (expBinLength !== respBinTyped.length) {\n\t\t\tthrow new Error(\"response body length should be '\" + expBinLength\n\t\t\t\t\t\t\t+ \"' but was '\" + respBinTyped.length + \"'\");\n\t\t}\n\t\tfor(var i = 0; i < respBinTyped.length; i++) {\n\t\t\tif (respBinTyped[i] !== i%256) {\n\t\t\t\tthrow new Error(\"expected value \" + (i%256) + \" to be at position \"\n\t\t\t\t\t\t\t\t+ i + \" but it was \" + respBinTyped[i]);\n\t\t\t}\n\t\t}\n\t\thttp.post(\"HTTPBIN_URL/compare-bin\", respBin.body);\n\n\t\t// Check ArrayBuffer response\n\t\tvar respBin = http.get(\"HTTPBIN_URL/get-bin\", { responseType: \"binary\" }).body;\n\t\tif (respBin.byteLength !== expBinLength) {\n\t\t\tthrow new Error(\"response body length should be '\" + expBinLength + \"' but was '\" + respBin.byteLength + \"'\");\n\t\t}\n\n\t\t// Check ArrayBuffer responses with http.batch()\n\t\tvar responses = http.batch([\n\t\t\t[\"GET\", \"HTTPBIN_URL/get-bin\", null, { responseType: \"binary\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/get-bin\", null, { responseType: \"binary\" }],\n\t\t]);\n\t\tif (responses.length != 2) {\n\t\t\tthrow new Error(\"expected 2 responses, received \" + responses.length);\n\t\t}\n\t\tfor (var i = 0; i < responses.length; i++) {\n\t\t\tif (responses[i].body.byteLength !== expBinLength) {\n\t\t\t\tthrow new Error(\"response body length should be '\"\n\t\t\t\t\t+ expBinLength + \"' but was '\" + responses[i].body.byteLength + \"'\");\n\t\t\t}\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n\n\t// Verify that if we enable discardResponseBodies globally, the default value is none\n\tstate.Options.DiscardResponseBodies = null.BoolFrom(true)\n\n\t_, err = rt.RunString(replace(`\n\t\tvar expText = \"EXP_TEXT\";\n\n\t\t// Check default behaviour\n\t\tvar respDefault = http.get(\"HTTPBIN_URL/get-text\").body;\n\t\tif (respDefault !== null) {\n\t\t\tthrow new Error(\"default response body should be discarded and null but was \" + respDefault);\n\t\t}\n\n\t\t// Check explicit text response\n\t\tvar respTextExplicit = http.get(\"HTTPBIN_URL/get-text\", { responseType: \"text\" }).body;\n\t\tif (respTextExplicit !== expText) {\n\t\t\tthrow new Error(\"text response body should be '\" + expText + \"' but was '\" + respTextExplicit + \"'\");\n\t\t}\n\t\thttp.post(\"HTTPBIN_URL/compare-text\", respTextExplicit);\n\t`))\n\tassert.NoError(t, err)\n}\n\nfunc checkErrorCode(t testing.TB, sample metrics.Sample, code int, msg string) {\n\terrorMsg, ok := sample.Tags.Get(\"error\")\n\tif msg == \"\" {\n\t\tassert.False(t, ok)\n\t} else {\n\t\tassert.Contains(t, errorMsg, msg)\n\t}\n\terrorCodeStr, ok := sample.Tags.Get(\"error_code\")\n\tif code == 0 {\n\t\tassert.False(t, ok)\n\t} else {\n\t\terrorCode, err := strconv.Atoi(errorCodeStr)\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, code, errorCode)\n\t}\n}\n\nfunc TestErrorCodes(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\tstate.Options.Throw = null.BoolFrom(false)\n\tsr := tb.Replacer.Replace\n\n\t// Handple paths with custom logic\n\ttb.Mux.HandleFunc(\"/no-location-redirect\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.WriteHeader(http.StatusFound)\n\t}))\n\ttb.Mux.HandleFunc(\"/bad-location-redirect\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Location\", \"h\\t:/\") // \\n is forbidden\n\t\tw.WriteHeader(http.StatusFound)\n\t}))\n\n\ttestCases := []struct {\n\t\tname                string\n\t\tstatus              int\n\t\tmoreSamples         int\n\t\texpectedErrorCode   int\n\t\texpectedErrorMsg    string\n\t\texpectedScriptError string\n\t\tscript              string\n\t}{\n\t\t{\n\t\t\tname:              \"Unroutable\",\n\t\t\texpectedErrorCode: 1101,\n\t\t\texpectedErrorMsg:  \"lookup: no such host\",\n\t\t\tscript:            `var res = http.request(\"GET\", \"http://sdafsgdhfjg.com/\");`,\n\t\t},\n\n\t\t{\n\t\t\tname:              \"404\",\n\t\t\tstatus:            404,\n\t\t\texpectedErrorCode: 1404,\n\t\t\tscript:            `var res = http.request(\"GET\", \"HTTPBIN_URL/status/404\");`,\n\t\t},\n\t\t{\n\t\t\tname:              \"Unroutable redirect\",\n\t\t\texpectedErrorCode: 1101,\n\t\t\texpectedErrorMsg:  \"lookup: no such host\",\n\t\t\tmoreSamples:       1,\n\t\t\tscript:            `var res = http.request(\"GET\", \"HTTPBIN_URL/redirect-to?url=http://dafsgdhfjg.com/\");`,\n\t\t},\n\t\t{\n\t\t\tname:              \"Bad location redirect\",\n\t\t\texpectedErrorCode: 1000,\n\t\t\texpectedErrorMsg:  \"failed to parse Location header \\\"h\\\\t:/\\\": \",\n\t\t\tscript:            `var res = http.request(\"GET\", \"HTTPBIN_URL/bad-location-redirect\");`,\n\t\t},\n\t\t{\n\t\t\tname:              \"Missing protocol\",\n\t\t\texpectedErrorCode: 1000,\n\t\t\texpectedErrorMsg:  `unsupported protocol scheme \"\"`,\n\t\t\tscript:            `var res = http.request(\"GET\", \"dafsgdhfjg.com/\");`,\n\t\t},\n\t\t{\n\t\t\tname:        \"Too many redirects\",\n\t\t\tstatus:      302,\n\t\t\tmoreSamples: 2,\n\t\t\tscript: `\n\t\t\tvar res = http.get(\"HTTPBIN_URL/relative-redirect/3\", {redirects: 2});\n\t\t\tif (res.url != \"HTTPBIN_URL/relative-redirect/1\") { throw new Error(\"incorrect URL: \" + res.url) }`,\n\t\t},\n\t\t{\n\t\t\tname:              \"Connection refused redirect\",\n\t\t\tstatus:            0,\n\t\t\tmoreSamples:       1,\n\t\t\texpectedErrorMsg:  `dial: connection refused`,\n\t\t\texpectedErrorCode: 1212,\n\t\t\tscript: `\n\t\t\tvar res = http.get(\"HTTPBIN_URL/redirect-to?url=http%3A%2F%2F127.0.0.1%3A1%2Fpesho\");\n\t\t\tif (res.url != \"http://127.0.0.1:1/pesho\") { throw new Error(\"incorrect URL: \" + res.url) }`,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\t// clear the Samples\n\t\tmetrics.GetBufferedSamples(samples)\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(testCase.script + \"\\n\" + fmt.Sprintf(`\n\t\t\tif (res.status != %d) { throw new Error(\"wrong status: \"+ res.status);}\n\t\t\tif (res.error.indexOf(%q, 0) === -1) { throw new Error(\"wrong error: '\" + res.error + \"'\");}\n\t\t\tif (res.error_code != %d) { throw new Error(\"wrong error_code: \"+ res.error_code);}\n\t\t\t`, testCase.status, testCase.expectedErrorMsg, testCase.expectedErrorCode)))\n\t\t\tif testCase.expectedScriptError == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t} else {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.EqualError(t, err, testCase.expectedScriptError)\n\t\t\t}\n\t\t\tcs := metrics.GetBufferedSamples(samples)\n\t\t\tassert.Len(t, cs, 1+testCase.moreSamples)\n\t\t\tfor _, c := range cs[len(cs)-1:] {\n\t\t\t\tassert.NotZero(t, len(c.GetSamples()))\n\t\t\t\tfor _, sample := range c.GetSamples() {\n\t\t\t\t\tcheckErrorCode(t, sample, testCase.expectedErrorCode, testCase.expectedErrorMsg)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResponseWaitingAndReceivingTimings(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\t// We don't expect any failed requests\n\tstate.Options.Throw = null.BoolFrom(true)\n\n\ttb.Mux.HandleFunc(\"/slow-response\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tflusher, ok := w.(http.Flusher)\n\t\trequire.True(t, ok)\n\n\t\ttime.Sleep(1200 * time.Millisecond)\n\t\tn, err := w.Write([]byte(\"1st bytes!\"))\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, 10, n)\n\n\t\tflusher.Flush()\n\t\ttime.Sleep(1200 * time.Millisecond)\n\n\t\tn, err = w.Write([]byte(\"2nd bytes!\"))\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, 10, n)\n\t}))\n\n\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\tvar resp = http.get(\"HTTPBIN_URL/slow-response\");\n\n\t\tif (resp.timings.waiting < 1000) {\n\t\t\tthrow new Error(\"expected waiting time to be over 1000ms but was \" + resp.timings.waiting);\n\t\t}\n\n\t\tif (resp.timings.receiving < 1000) {\n\t\t\tthrow new Error(\"expected receiving time to be over 1000ms but was \" + resp.timings.receiving);\n\t\t}\n\n\t\tif (resp.body !== \"1st bytes!2nd bytes!\") {\n\t\t\tthrow new Error(\"wrong response body: \" + resp.body);\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n}\n\nfunc TestResponseTimingsWhenTimeout(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\t// We expect a failed request\n\tstate.Options.Throw = null.BoolFrom(false)\n\n\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\tvar resp = http.get(\"HTTPBIN_URL/delay/10\", { timeout: 2500 });\n\n\t\tif (resp.timings.waiting < 2000) {\n\t\t\tthrow new Error(\"expected waiting time to be over 2000ms but was \" + resp.timings.waiting);\n\t\t}\n\n\t\tif (resp.timings.duration < 2000) {\n\t\t\tthrow new Error(\"expected duration time to be over 2000ms but was \" + resp.timings.duration);\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n}\n\nfunc TestNoResponseBodyMangling(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\t// We don't expect any failed requests\n\tstate.Options.Throw = null.BoolFrom(true)\n\n\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t    var batchSize = 100;\n\n\t\tvar requests = [];\n\n\t\tfor (var i = 0; i < batchSize; i++) {\n\t\t\trequests.push([\"GET\", \"HTTPBIN_URL/get?req=\" + i, null, { responseType: (i % 2 ? \"binary\" : \"text\") }]);\n\t\t}\n\n\t\tvar responses = http.batch(requests);\n\n\t\tfor (var i = 0; i < batchSize; i++) {\n\t\t\tvar reqNumber = parseInt(responses[i].json().args.req[0], 10);\n\t\t\tif (i !== reqNumber) {\n\t\t\t\tthrow new Error(\"Response \" + i + \" has \" + reqNumber + \", expected \" + i)\n\t\t\t}\n\t\t}\n\t`))\n\tassert.NoError(t, err)\n}\n\nfunc TestRedirectMetricTags(t *testing.T) {\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\n\ttb.Mux.HandleFunc(\"/redirect/post\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\thttp.Redirect(w, r, \"/get\", http.StatusMovedPermanently)\n\t}))\n\n\tsr := tb.Replacer.Replace\n\tscript := sr(`\n\t\thttp.post(\"HTTPBIN_URL/redirect/post\", {data: \"some data\"});\n\t`)\n\n\t_, err := rt.RunString(script)\n\trequire.NoError(t, err)\n\n\trequire.Len(t, samples, 2)\n\n\tcheckTags := func(sc metrics.SampleContainer, expTags map[string]string) {\n\t\tallSamples := sc.GetSamples()\n\t\tassert.Len(t, allSamples, 9)\n\t\tfor _, s := range allSamples {\n\t\t\tassert.Equal(t, expTags, s.Tags.Map())\n\t\t}\n\t}\n\texpPOSTtags := map[string]string{\n\t\t\"group\":             \"\",\n\t\t\"method\":            \"POST\",\n\t\t\"url\":               sr(\"HTTPBIN_URL/redirect/post\"),\n\t\t\"name\":              sr(\"HTTPBIN_URL/redirect/post\"),\n\t\t\"status\":            \"301\",\n\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\"expected_response\": \"true\",\n\t}\n\texpGETtags := map[string]string{\n\t\t\"group\":             \"\",\n\t\t\"method\":            \"GET\",\n\t\t\"url\":               sr(\"HTTPBIN_URL/get\"),\n\t\t\"name\":              sr(\"HTTPBIN_URL/get\"),\n\t\t\"status\":            \"200\",\n\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\"expected_response\": \"true\",\n\t}\n\tcheckTags(<-samples, expPOSTtags)\n\tcheckTags(<-samples, expGETtags)\n}\n\nfunc BenchmarkHandlingOfResponseBodies(b *testing.B) {\n\tts := newTestCase(b)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\tstate.BufferPool = lib.NewBufferPool()\n\n\tgo func() {\n\t\tctxDone := tb.Context.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-samples:\n\t\t\tcase <-ctxDone:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tmbData := bytes.Repeat([]byte(\"0123456789\"), 100000)\n\ttb.Mux.HandleFunc(\"/1mbdata\", http.HandlerFunc(func(resp http.ResponseWriter, _ *http.Request) {\n\t\t_, err := resp.Write(mbData)\n\t\tif err != nil {\n\t\t\tb.Error(err)\n\t\t}\n\t}))\n\n\ttestCodeTemplate := tb.Replacer.Replace(`\n\t\thttp.get(\"HTTPBIN_URL/\", { responseType: \"TEST_RESPONSE_TYPE\" });\n\t\thttp.post(\"HTTPBIN_URL/post\", { responseType: \"TEST_RESPONSE_TYPE\" });\n\t\thttp.batch([\n\t\t\t[\"GET\", \"HTTPBIN_URL/gzip\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/gzip\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/deflate\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/deflate\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/redirect/5\", null, { responseType: \"TEST_RESPONSE_TYPE\" }], // 6 requests\n\t\t\t[\"GET\", \"HTTPBIN_URL/get\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/html\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/bytes/100000\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/image/png\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/image/jpeg\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/image/jpeg\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/image/webp\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/image/svg\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/forms/post\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/bytes/100000\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t\t[\"GET\", \"HTTPBIN_URL/stream-bytes/100000\", null, { responseType: \"TEST_RESPONSE_TYPE\" }],\n\t\t]);\n\t\thttp.get(\"HTTPBIN_URL/get\", { responseType: \"TEST_RESPONSE_TYPE\" });\n\t\thttp.get(\"HTTPBIN_URL/get\", { responseType: \"TEST_RESPONSE_TYPE\" });\n\t\thttp.get(\"HTTPBIN_URL/1mbdata\", { responseType: \"TEST_RESPONSE_TYPE\" });\n\t`)\n\n\ttestResponseType := func(responseType string) func(b *testing.B) {\n\t\ttestCode := strings.ReplaceAll(testCodeTemplate, \"TEST_RESPONSE_TYPE\", responseType)\n\t\treturn func(b *testing.B) {\n\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\t_, err := rt.RunString(testCode)\n\t\t\t\tif err != nil {\n\t\t\t\t\tb.Error(err)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tb.ResetTimer()\n\tb.Run(\"text\", testResponseType(\"text\"))\n\tb.Run(\"binary\", testResponseType(\"binary\"))\n\tb.Run(\"none\", testResponseType(\"none\"))\n}\n\nfunc TestErrorsWithDecompression(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\tstate.Options.Throw = null.BoolFrom(false)\n\n\ttb.Mux.HandleFunc(\"/broken-archive\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tenc := r.URL.Query()[\"encoding\"][0]\n\t\tw.Header().Set(\"Content-Encoding\", enc)\n\t\t_, _ = fmt.Fprintf(w, \"Definitely not %s, but it's all cool...\", enc)\n\t}))\n\n\t_, err := rt.RunString(tb.Replacer.Replace(`\n\t\tfunction handleResponseEncodingError (encoding) {\n\t\t\tvar resp = http.get(\"HTTPBIN_URL/broken-archive?encoding=\" + encoding);\n\t\t\tif (resp.error_code != 1701) {\n\t\t\t\tthrow new Error(\"Expected error_code 1701 for '\" + encoding +\"', but got \" + resp.error_code);\n\t\t\t}\n\t\t}\n\n\t\t[\"gzip\", \"deflate\", \"br\", \"zstd\"].forEach(handleResponseEncodingError);\n\t`))\n\tassert.NoError(t, err)\n}\n\nfunc TestRequestAndBatchTLS(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"cert_expired\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tts := newTestCase(t)\n\t\trt := ts.runtime.VU.Runtime()\n\t\tstate := ts.runtime.VU.State()\n\n\t\tcert, key := GenerateTLSCertificate(t, \"expired.localhost\", time.Now().Add(-time.Hour), 0)\n\t\ts, client := GetTestServerWithCertificate(t, cert, key)\n\t\tgo func() {\n\t\t\t_ = s.Config.Serve(s.Listener)\n\t\t}()\n\t\tt.Cleanup(func() {\n\t\t\trequire.NoError(t, s.Config.Close())\n\t\t})\n\t\thost, port, err := net.SplitHostPort(s.Listener.Addr().String())\n\t\trequire.NoError(t, err)\n\t\tip := net.ParseIP(host)\n\t\tmybadsslHostname, err := types.NewHost(ip, port)\n\t\trequire.NoError(t, err)\n\t\tstate.Transport = client.Transport\n\t\tstate.TLSConfig = s.TLS\n\t\tstate.Dialer = &netext.Dialer{\n\t\t\tHosts: func() *types.Hosts {\n\t\t\t\thosts, er := types.NewHosts(map[string]types.Host{\"expired.localhost\": *mybadsslHostname})\n\t\t\t\trequire.NoError(t, er)\n\t\t\t\treturn hosts\n\t\t\t}(),\n\t\t}\n\t\tclient.Transport.(*http.Transport).DialContext = state.Dialer.DialContext\n\t\t_, err = rt.RunString(`throw JSON.stringify(http.get(\"https://expired.localhost/\"));`)\n\t\trequire.Error(t, err)\n\t\tassert.Contains(t, err.Error(), \"x509: certificate has expired or is not yet valid\")\n\t})\n\ttlsVersionTests := []struct {\n\t\tName, URL, Version string\n\t}{\n\t\t{Name: \"tls10\", URL: \"tlsv10.localhost\", Version: \"http.TLS_1_0\"},\n\t\t{Name: \"tls11\", URL: \"tlsv11.localhost\", Version: \"http.TLS_1_1\"},\n\t\t{Name: \"tls12\", URL: \"tlsv12.localhost\", Version: \"http.TLS_1_2\"},\n\t}\n\tfor _, versionTest := range tlsVersionTests {\n\t\tt.Run(versionTest.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\t\t\tsamples := ts.samples\n\t\t\trt := ts.runtime.VU.Runtime()\n\t\t\tstate := ts.runtime.VU.State()\n\n\t\t\tcert, key := GenerateTLSCertificate(t, versionTest.URL, time.Now(), time.Hour)\n\t\t\ts, client := GetTestServerWithCertificate(t, cert, key)\n\n\t\t\tswitch versionTest.Name {\n\t\t\tcase \"tls10\":\n\t\t\t\ts.TLS.MaxVersion = tls.VersionTLS10\n\t\t\tcase \"tls11\":\n\t\t\t\ts.TLS.MaxVersion = tls.VersionTLS11\n\t\t\tcase \"tls12\":\n\t\t\t\ts.TLS.MaxVersion = tls.VersionTLS12\n\t\t\tdefault:\n\t\t\t\tpanic(versionTest.Name + \" unsupported\")\n\t\t\t}\n\t\t\ts.TLS.MinVersion = tls.VersionTLS10\n\t\t\tgo func() {\n\t\t\t\t_ = s.Config.Serve(s.Listener)\n\t\t\t}()\n\t\t\tt.Cleanup(func() {\n\t\t\t\trequire.NoError(t, s.Config.Close())\n\t\t\t})\n\t\t\thost, port, err := net.SplitHostPort(s.Listener.Addr().String())\n\t\t\trequire.NoError(t, err)\n\t\t\tip := net.ParseIP(host)\n\t\t\tmybadsslHostname, err := types.NewHost(ip, port)\n\t\t\trequire.NoError(t, err)\n\t\t\thosts, err := types.NewHosts(map[string]types.Host{\n\t\t\t\tversionTest.URL: *mybadsslHostname,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\tstate.Dialer = &netext.Dialer{Hosts: hosts}\n\t\t\tstate.Transport = client.Transport\n\t\t\tstate.TLSConfig = s.TLS\n\t\t\tclient.Transport.(*http.Transport).DialContext = state.Dialer.DialContext\n\t\t\trealURL := \"https://\" + versionTest.URL + \"/\"\n\t\t\t_, err = rt.RunString(fmt.Sprintf(`\n            var res = http.get(\"%s\");\n\t\t\t\t\tif (res.tls_version != %s) { throw new Error(\"wrong TLS version: \" + res.tls_version); }\n\t\t\t\t`, realURL, versionTest.Version))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", realURL, 200, \"\")\n\t\t})\n\t}\n\ttlsCipherSuiteTests := []struct {\n\t\tName, URL, CipherSuite string\n\t\tsuite                  uint16\n\t}{\n\t\t{Name: \"cipher_suite_cbc\", URL: \"cbc.localhost\", CipherSuite: \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\", suite: tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, // TODO fix this to RSA instead of ECDSA\n\t\t{Name: \"cipher_suite_ecc384\", URL: \"ecc384.localhost\", CipherSuite: \"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\", suite: tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},\n\t}\n\tfor _, cipherSuiteTest := range tlsCipherSuiteTests {\n\t\tt.Run(cipherSuiteTest.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tts := newTestCase(t)\n\t\t\tsamples := ts.samples\n\t\t\trt := ts.runtime.VU.Runtime()\n\t\t\tstate := ts.runtime.VU.State()\n\t\t\tcert, key := GenerateTLSCertificate(t, cipherSuiteTest.URL, time.Now(), time.Hour)\n\t\t\ts, client := GetTestServerWithCertificate(t, cert, key, cipherSuiteTest.suite)\n\t\t\tgo func() {\n\t\t\t\t_ = s.Config.Serve(s.Listener)\n\t\t\t}()\n\t\t\tt.Cleanup(func() {\n\t\t\t\trequire.NoError(t, s.Config.Close())\n\t\t\t})\n\t\t\thost, port, err := net.SplitHostPort(s.Listener.Addr().String())\n\t\t\trequire.NoError(t, err)\n\t\t\tip := net.ParseIP(host)\n\t\t\tmybadsslHostname, err := types.NewHost(ip, port)\n\t\t\trequire.NoError(t, err)\n\t\t\thosts, err := types.NewHosts(map[string]types.Host{\n\t\t\t\tcipherSuiteTest.URL: *mybadsslHostname,\n\t\t\t})\n\t\t\trequire.NoError(t, err)\n\t\t\tstate.Dialer = &netext.Dialer{Hosts: hosts}\n\t\t\tstate.Transport = client.Transport\n\t\t\tstate.TLSConfig = s.TLS\n\t\t\tclient.Transport.(*http.Transport).DialContext = state.Dialer.DialContext\n\t\t\trealURL := \"https://\" + cipherSuiteTest.URL + \"/\"\n\t\t\t_, err = rt.RunString(fmt.Sprintf(`\n\t\t\t\t\tvar res = http.get(\"%s\");\n\t\t\t\t\tif (res.tls_cipher_suite != \"%s\") { throw new Error(\"wrong TLS cipher suite: \" + res.tls_cipher_suite); }\n\t\t\t\t`, realURL, cipherSuiteTest.CipherSuite))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", realURL, 200, \"\")\n\t\t})\n\t}\n\tt.Run(\"ocsp_stapled_good\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Skip(\"this started failing on GHA\") // see https://github.com/grafana/k6/issues/1275\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tt.Skip(\"this doesn't work on windows for some reason\")\n\t\t}\n\t\twebsite := \"https://www.wikipedia.org/\"\n\t\tts := newTestCase(t)\n\t\ttb := ts.tb\n\t\tsamples := ts.samples\n\t\trt := ts.runtime.VU.Runtime()\n\t\tstate := ts.runtime.VU.State()\n\t\tstate.Dialer = tb.Dialer\n\t\t_, err := rt.RunString(fmt.Sprintf(`\n\t\t\tvar res = http.request(\"GET\", \"%s\");\n\t\t\tif (res.ocsp.status != http.OCSP_STATUS_GOOD) { throw new Error(\"wrong ocsp stapled response status: \" + res.ocsp.status); }\n\t\t\t`, website))\n\t\tassert.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", website, 200, \"\")\n\t})\n}\n\nfunc TestDigestAuthWithBody(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\n\tstate.Options.Throw = null.BoolFrom(true)\n\tstate.Options.HTTPDebug = null.StringFrom(\"full\")\n\n\ttb.Mux.HandleFunc(\"/digest-auth-with-post/{qop}/{user}/{password}\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\trequire.Equal(t, http.MethodPost, r.Method)\n\t\tbody, err := io.ReadAll(r.Body)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"super secret body\", string(body))\n\t\thttpbin.New().DigestAuth(w, r) // this doesn't read the body\n\t}))\n\n\turlWithCreds := tb.Replacer.Replace(\n\t\t\"http://testuser:testpwd@HTTPBIN_IP:HTTPBIN_PORT/digest-auth-with-post/auth/testuser/testpwd\",\n\t)\n\n\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar res = http.post(%q, \"super secret body\", { auth: \"digest\" });\n\t\tif (res.status !== 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\tif (res.error_code !== 0) { throw new Error(\"wrong error code: \" + res.error_code); }\n\t`, urlWithCreds))\n\trequire.NoError(t, err)\n\n\turlRaw := tb.Replacer.Replace(\n\t\t\"http://HTTPBIN_IP:HTTPBIN_PORT/digest-auth-with-post/auth/testuser/testpwd\")\n\n\tsampleContainers := metrics.GetBufferedSamples(samples)\n\tassertRequestMetricsEmitted(t, sampleContainers[0:1], \"POST\", urlRaw, 401, \"\")\n\tassertRequestMetricsEmitted(t, sampleContainers[1:2], \"POST\", urlRaw, 200, \"\")\n}\n\nfunc TestBinaryResponseWithStatus0(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\tstate.Options.Throw = null.BoolFrom(false)\n\t_, err := rt.RunString(`\n\t\tvar res = http.get(\"https://asdajkdahdqiuwhejkasdnakjdnadasdlkas.com\", { responseType: \"binary\" });\n\t\tif (res.status !== 0) { throw new Error(\"wrong status: \" + res.status); }\n\t\tif (res.body !== null) { throw new Error(\"wrong body: \" + JSON.stringify(res.body)); }\n\t`)\n\trequire.NoError(t, err)\n}\n\nfunc GenerateTLSCertificate(t *testing.T, host string, notBefore time.Time, validFor time.Duration) ([]byte, []byte) {\n\tpriv, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)\n\t// priv, err := ecdsa.GenerateKey(rand.Reader, 2048)\n\trequire.NoError(t, err)\n\n\t// ECDSA, ED25519 and RSA subject keys should have the DigitalSignature\n\t// KeyUsage bits set in the x509.Certificate template\n\tkeyUsage := x509.KeyUsageDigitalSignature\n\t// Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In\n\t// the context of TLS this KeyUsage is particular to RSA key exchange and\n\t// authentication.\n\tkeyUsage |= x509.KeyUsageKeyEncipherment\n\n\tnotAfter := notBefore.Add(validFor)\n\n\tserialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)\n\tserialNumber, err := rand.Int(rand.Reader, serialNumberLimit)\n\trequire.NoError(t, err)\n\n\ttemplate := x509.Certificate{\n\t\tSerialNumber: serialNumber,\n\t\tSubject: pkix.Name{\n\t\t\tOrganization: []string{\"Acme Co\"},\n\t\t},\n\t\tNotBefore: notBefore,\n\t\tNotAfter:  notAfter,\n\n\t\tKeyUsage:              keyUsage,\n\t\tExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},\n\t\tBasicConstraintsValid: true,\n\t\tSignatureAlgorithm:    x509.ECDSAWithSHA256,\n\t}\n\n\thosts := strings.SplitSeq(host, \",\")\n\tfor h := range hosts {\n\t\tif ip := net.ParseIP(h); ip != nil {\n\t\t\ttemplate.IPAddresses = append(template.IPAddresses, ip)\n\t\t} else {\n\t\t\ttemplate.DNSNames = append(template.DNSNames, h)\n\t\t}\n\t}\n\n\ttemplate.IsCA = true\n\ttemplate.KeyUsage |= x509.KeyUsageCertSign\n\n\tderBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)\n\trequire.NoError(t, err)\n\n\tcertPem := pem.EncodeToMemory(&pem.Block{Type: \"CERTIFICATE\", Bytes: derBytes})\n\trequire.NoError(t, err)\n\n\tprivBytes, err := x509.MarshalPKCS8PrivateKey(priv)\n\trequire.NoError(t, err)\n\tkeyPem := pem.EncodeToMemory(&pem.Block{Type: \"PRIVATE KEY\", Bytes: privBytes})\n\trequire.NoError(t, err)\n\treturn certPem, keyPem\n}\n\nfunc GetTestServerWithCertificate(t *testing.T, certPem, key []byte, suitesIDs ...uint16) (*httptest.Server, *http.Client) {\n\tserver := &http.Server{\n\t\tHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tw.WriteHeader(http.StatusOK)\n\t\t}),\n\t\tReadHeaderTimeout: time.Second,\n\t\tReadTimeout:       time.Second,\n\t}\n\ts := &httptest.Server{}\n\ts.Config = server\n\n\ts.TLS = new(tls.Config)\n\tif s.TLS.NextProtos == nil {\n\t\tnextProtos := []string{\"http/1.1\"}\n\t\tif s.EnableHTTP2 {\n\t\t\tnextProtos = []string{\"h2\"}\n\t\t}\n\t\ts.TLS.NextProtos = nextProtos\n\t}\n\tcert, err := tls.X509KeyPair(certPem, key)\n\trequire.NoError(t, err)\n\ts.TLS.Certificates = append(s.TLS.Certificates, cert)\n\tsuites := tls.CipherSuites()\n\tif len(suitesIDs) > 0 {\n\t\tnewSuites := make([]*tls.CipherSuite, 0, len(suitesIDs))\n\t\tfor _, suite := range suites {\n\t\t\tfor _, id := range suitesIDs {\n\t\t\t\tif id == suite.ID {\n\t\t\t\t\tnewSuites = append(newSuites, suite)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tsuites = newSuites\n\t}\n\tif len(suites) == 0 {\n\t\tpanic(\"no suites enabled\")\n\t}\n\tfor _, suite := range suites {\n\t\ts.TLS.CipherSuites = append(s.TLS.CipherSuites, suite.ID)\n\t}\n\tcertpool := x509.NewCertPool()\n\tcertificate, err := x509.ParseCertificate(cert.Certificate[0])\n\trequire.NoError(t, err)\n\tcertpool.AddCert(certificate)\n\tclient := &http.Client{Transport: &http.Transport{}}\n\tclient.Transport = &http.Transport{\n\t\tTLSClientConfig: &tls.Config{\n\t\t\tRootCAs:      certpool,\n\t\t\tMinVersion:   tls.VersionTLS10,\n\t\t\tMaxVersion:   tls.VersionTLS12, // this so that the ciphersuite work\n\t\t\tCipherSuites: suitesIDs,\n\t\t},\n\t\tForceAttemptHTTP2:     s.EnableHTTP2,\n\t\tTLSHandshakeTimeout:   time.Second,\n\t\tResponseHeaderTimeout: time.Second,\n\t\tIdleConnTimeout:       time.Second,\n\t}\n\ts.Listener, err = (&net.ListenConfig{}).Listen(context.Background(), \"tcp\", \"\")\n\trequire.NoError(t, err)\n\ts.Listener = tls.NewListener(s.Listener, s.TLS)\n\treturn s, client\n}\n\nfunc TestGzipped204Response(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\tstate.Options.Throw = null.BoolFrom(true)\n\tsr := tb.Replacer.Replace\n\t// We should not try to decode it\n\ttb.Mux.HandleFunc(\"/gzipempty\", http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Set(\"Content-Encoding\", \"gzip\")\n\t\tw.WriteHeader(http.StatusNoContent)\n\t}))\n\n\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.get(\"HTTPBIN_URL/gzipempty\");\n\t\t\t\tif (res.status != 204) {\n\t\t\t\t\tthrow new Error(\"unexpected status code: \" + res.status)\n\t\t\t\t}\n\t\t\t`))\n\tassert.NoError(t, err)\n}\n"
  },
  {
    "path": "js/modules/k6/http/response.go",
    "content": "package http\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/tidwall/gjson\"\n\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules/k6/html\"\n\t\"go.k6.io/k6/lib/netext/httpext\"\n)\n\n// Response is a representation of an HTTP response to be returned to the Sobek VM\ntype Response struct {\n\t*httpext.Response `js:\"-\"`\n\tclient            *Client\n\n\tcachedJSON    any\n\tvalidatedJSON bool\n}\n\ntype jsonError struct {\n\tline      int\n\tcharacter int\n\terr       error\n}\n\nfunc (j jsonError) Error() string {\n\terrMessage := \"cannot parse json due to an error at line\"\n\treturn fmt.Sprintf(\"%s %d, character %d , error: %v\", errMessage, j.line, j.character, j.err)\n}\n\n// HTML returns the body as an html.Selection\nfunc (res *Response) HTML(selector ...string) html.Selection {\n\trt := res.client.moduleInstance.vu.Runtime()\n\tif res.Body == nil {\n\t\terr := fmt.Errorf(\"the body is null so we can't transform it to HTML\" +\n\t\t\t\" - this likely was because of a request error getting the response\")\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tbody, err := common.ToString(res.Body)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tsel, err := html.ParseHTML(rt, body)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\tsel.URL = res.URL\n\tif len(selector) > 0 {\n\t\tsel = sel.Find(selector[0])\n\t}\n\treturn sel\n}\n\n// JSON parses the body of a response as JSON and returns it to the Sobek VM.\nfunc (res *Response) JSON(selector ...string) sobek.Value {\n\trt := res.client.moduleInstance.vu.Runtime()\n\n\tif res.Body == nil {\n\t\terr := fmt.Errorf(\"the body is null so we can't transform it to JSON\" +\n\t\t\t\" - this likely was because of a request error getting the response\")\n\t\tcommon.Throw(rt, err)\n\t}\n\n\thasSelector := len(selector) > 0\n\tif res.cachedJSON == nil || hasSelector { //nolint:nestif\n\t\tvar v any\n\n\t\tbody, err := common.ToBytes(res.Body)\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, err)\n\t\t}\n\n\t\tif hasSelector {\n\t\t\tif !res.validatedJSON {\n\t\t\t\tif !gjson.ValidBytes(body) {\n\t\t\t\t\treturn sobek.Undefined()\n\t\t\t\t}\n\t\t\t\tres.validatedJSON = true\n\t\t\t}\n\n\t\t\tresult := gjson.GetBytes(body, selector[0])\n\n\t\t\tif !result.Exists() {\n\t\t\t\treturn sobek.Undefined()\n\t\t\t}\n\t\t\treturn rt.ToValue(result.Value())\n\t\t}\n\n\t\tif err := json.Unmarshal(body, &v); err != nil {\n\t\t\tvar syntaxError *json.SyntaxError\n\t\t\tif errors.As(err, &syntaxError) {\n\t\t\t\terr = checkErrorInJSON(body, int(syntaxError.Offset), err)\n\t\t\t}\n\t\t\tcommon.Throw(rt, err)\n\t\t}\n\t\tres.validatedJSON = true\n\t\tres.cachedJSON = v\n\t}\n\n\treturn rt.ToValue(res.cachedJSON)\n}\n\nfunc checkErrorInJSON(input []byte, offset int, err error) error {\n\tlf := '\\n'\n\tstr := string(input)\n\n\t// Humans tend to count from 1.\n\tline := 1\n\tcharacter := 0\n\n\t// SyntaxError.Offset is the number of bytes read (1-based).\n\tif offset > 0 {\n\t\toffset--\n\t}\n\n\tfor i, b := range str {\n\t\tif b == lf {\n\t\t\tline++\n\t\t\tcharacter = 0\n\t\t} else {\n\t\t\tcharacter++\n\t\t}\n\n\t\tif i >= offset {\n\t\t\tif b == lf {\n\t\t\t\tcharacter = 1\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn jsonError{line: line, character: character, err: err}\n}\n\n// SubmitForm parses the body as an html looking for a from and then submitting it\n// TODO: document the actual arguments that can be provided\nfunc (res *Response) SubmitForm(args ...sobek.Value) (*Response, error) {\n\trt := res.client.moduleInstance.vu.Runtime()\n\n\tformSelector := \"form\"\n\tsubmitSelector := \"[type=\\\"submit\\\"]\"\n\tvar fields map[string]sobek.Value\n\trequestParams := sobek.Null()\n\tif len(args) > 0 {\n\t\tparams := args[0].ToObject(rt)\n\t\tfor _, k := range params.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"formSelector\":\n\t\t\t\tformSelector = params.Get(k).String()\n\t\t\tcase \"submitSelector\":\n\t\t\t\tsubmitSelector = params.Get(k).String()\n\t\t\tcase \"fields\":\n\t\t\t\tif rt.ExportTo(params.Get(k), &fields) != nil {\n\t\t\t\t\tfields = nil\n\t\t\t\t}\n\t\t\tcase \"params\":\n\t\t\t\trequestParams = params.Get(k)\n\t\t\t}\n\t\t}\n\t}\n\n\tform := res.HTML(formSelector)\n\tif form.Size() == 0 {\n\t\tcommon.Throw(rt, fmt.Errorf(\"no form found for selector '%s' in response '%s'\", formSelector, res.URL))\n\t}\n\n\tmethodAttr := form.Attr(\"method\")\n\tvar requestMethod string\n\tif methodAttr == sobek.Undefined() {\n\t\t// Use GET by default\n\t\trequestMethod = http.MethodGet\n\t} else {\n\t\trequestMethod = strings.ToUpper(methodAttr.String())\n\t}\n\n\tresponseURL, err := url.Parse(res.URL)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tactionAttr := form.Attr(\"action\")\n\tvar requestURL *url.URL\n\tif actionAttr == sobek.Undefined() {\n\t\t// Use the url of the response if no action is set\n\t\trequestURL = responseURL\n\t} else {\n\t\tactionURL, err := url.Parse(actionAttr.String())\n\t\tif err != nil {\n\t\t\tcommon.Throw(rt, err)\n\t\t}\n\t\trequestURL = responseURL.ResolveReference(actionURL)\n\t}\n\n\t// Set the body based on the form values\n\tvalues := form.SerializeObject()\n\n\t// Set the name + value of the submit button\n\tsubmit := form.Find(submitSelector)\n\tsubmitName := submit.Attr(\"name\")\n\tsubmitValue := submit.Val()\n\tif submitName != sobek.Undefined() && submitValue != sobek.Undefined() {\n\t\tvalues[submitName.String()] = submitValue\n\t}\n\n\t// Set the values supplied in the arguments, overriding automatically set values\n\tmaps.Copy(values, fields)\n\n\tif requestMethod == http.MethodGet {\n\t\tq := url.Values{}\n\t\tfor k, v := range values {\n\t\t\tq.Add(k, v.String())\n\t\t}\n\t\trequestURL.RawQuery = q.Encode()\n\t\treturn res.client.Request(requestMethod, rt.ToValue(requestURL.String()), sobek.Null(), requestParams)\n\t}\n\treturn res.client.Request(\n\t\trequestMethod, rt.ToValue(requestURL.String()),\n\t\trt.ToValue(values), requestParams,\n\t)\n}\n\n// ClickLink parses the body as an html, looks for a link and than makes a request as if the link was\n// clicked\nfunc (res *Response) ClickLink(args ...sobek.Value) (*Response, error) {\n\trt := res.client.moduleInstance.vu.Runtime()\n\n\tselector := \"a[href]\"\n\trequestParams := sobek.Null()\n\tif len(args) > 0 {\n\t\tparams := args[0].ToObject(rt)\n\t\tfor _, k := range params.Keys() {\n\t\t\tswitch k {\n\t\t\tcase \"selector\":\n\t\t\t\tselector = params.Get(k).String()\n\t\t\tcase \"params\":\n\t\t\t\trequestParams = params.Get(k)\n\t\t\t}\n\t\t}\n\t}\n\n\tresponseURL, err := url.Parse(res.URL)\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\n\tlink := res.HTML(selector)\n\tif link.Size() == 0 {\n\t\tcommon.Throw(rt, fmt.Errorf(\"no element found for selector '%s' in response '%s'\", selector, res.URL))\n\t}\n\threfAttr := link.Attr(\"href\")\n\tif hrefAttr == sobek.Undefined() {\n\t\terrmsg := fmt.Errorf(\"no valid href attribute value found on element '%s' in response '%s'\", selector, res.URL)\n\t\tcommon.Throw(rt, errmsg)\n\t}\n\threfURL, err := url.Parse(hrefAttr.String())\n\tif err != nil {\n\t\tcommon.Throw(rt, err)\n\t}\n\trequestURL := responseURL.ResolveReference(hrefURL)\n\n\treturn res.client.Request(http.MethodGet, rt.ToValue(requestURL.String()), sobek.Undefined(), requestParams)\n}\n"
  },
  {
    "path": "js/modules/k6/http/response_callback.go",
    "content": "package http\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n)\n\n//nolint:gochecknoglobals\nvar defaultExpectedStatuses = expectedStatuses{\n\tminmax: [][2]int{{200, 399}},\n}\n\n// expectedStatuses is specifically totally unexported so it can't be used for anything else but\n// SetResponseCallback and nothing can be done from the js side to modify it or make an instance of\n// it except using ExpectedStatuses\ntype expectedStatuses struct {\n\tminmax [][2]int\n\texact  []int\n}\n\nfunc (e expectedStatuses) match(status int) bool {\n\tif slices.Contains(e.exact, status) {\n\t\treturn true\n\t}\n\n\tfor _, v := range e.minmax {\n\t\tif v[0] <= status && status <= v[1] {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// expectedStatuses returns expectedStatuses object based on the provided arguments.\n// The arguments must be either integers or object of `{min: <integer>, max: <integer>}`\n// kind. The \"integer\"ness is checked by the Number.isInteger.\nfunc (mi *ModuleInstance) expectedStatuses(args ...sobek.Value) *expectedStatuses {\n\trt := mi.vu.Runtime()\n\n\tif len(args) == 0 {\n\t\tcommon.Throw(rt, errors.New(\"no arguments\"))\n\t}\n\tvar result expectedStatuses\n\n\tjsIsInt, _ := sobek.AssertFunction(rt.GlobalObject().Get(\"Number\").ToObject(rt).Get(\"isInteger\"))\n\tisInt := func(a sobek.Value) bool {\n\t\tv, err := jsIsInt(sobek.Undefined(), a)\n\t\treturn err == nil && v.ToBoolean()\n\t}\n\n\terrMsg := \"argument number %d to expectedStatuses was neither an integer nor an object like {min:100, max:329}\"\n\tfor i, arg := range args {\n\t\to := arg.ToObject(rt)\n\t\tif o == nil {\n\t\t\tcommon.Throw(rt, fmt.Errorf(errMsg, i+1))\n\t\t}\n\n\t\tif isInt(arg) {\n\t\t\tresult.exact = append(result.exact, int(o.ToInteger()))\n\t\t} else {\n\t\t\tminValue := o.Get(\"min\")\n\t\t\tmaxValue := o.Get(\"max\")\n\t\t\tif minValue == nil || maxValue == nil {\n\t\t\t\tcommon.Throw(rt, fmt.Errorf(errMsg, i+1))\n\t\t\t}\n\t\t\tif !isInt(minValue) || !isInt(maxValue) {\n\t\t\t\tcommon.Throw(rt, fmt.Errorf(\"both min and max need to be integers for argument number %d\", i+1))\n\t\t\t}\n\n\t\t\tresult.minmax = append(result.minmax, [2]int{int(minValue.ToInteger()), int(maxValue.ToInteger())})\n\t\t}\n\t}\n\treturn &result\n}\n\n// SetResponseCallback sets the responseCallback to the value provided. Supported values are\n// expectedStatuses object or a `null` which means that metrics shouldn't be tagged as failed and\n// `http_req_failed` should not be emitted - the behaviour previous to this\nfunc (c *Client) SetResponseCallback(val sobek.Value) {\n\tif val != nil && !sobek.IsNull(val) {\n\t\t// This is done this way as ExportTo exports functions to empty structs without an error\n\t\tif es, ok := val.Export().(*expectedStatuses); ok {\n\t\t\tc.responseCallback = es.match\n\t\t} else {\n\t\t\tcommon.Throw(\n\t\t\t\tc.moduleInstance.vu.Runtime(),\n\t\t\t\tfmt.Errorf(\"unsupported argument, expected http.expectedStatuses\"),\n\t\t\t)\n\t\t}\n\t} else {\n\t\tc.responseCallback = nil\n\t}\n}\n"
  },
  {
    "path": "js/modules/k6/http/response_callback_test.go",
    "content": "package http\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestExpectedStatuses(t *testing.T) {\n\tt.Parallel()\n\truntime, _ := getTestModuleInstance(t)\n\trt := runtime.VU.RuntimeField\n\n\tcases := map[string]struct {\n\t\tcode, err string\n\t\texpected  expectedStatuses\n\t}{\n\t\t\"good example\": {\n\t\t\texpected: expectedStatuses{exact: []int{200, 300}, minmax: [][2]int{{200, 300}}},\n\t\t\tcode:     `(http.expectedStatuses(200, 300, {min: 200, max:300}))`,\n\t\t},\n\n\t\t\"strange example\": {\n\t\t\texpected: expectedStatuses{exact: []int{200, 300}, minmax: [][2]int{{200, 300}}},\n\t\t\tcode:     `(http.expectedStatuses(200, 300, {min: 200, max:300, other: \"attribute\"}))`,\n\t\t},\n\n\t\t\"string status code\": {\n\t\t\tcode: `(http.expectedStatuses(200, \"300\", {min: 200, max:300}))`,\n\t\t\terr:  \"argument number 2 to expectedStatuses was neither an integer nor an object like {min:100, max:329}\",\n\t\t},\n\n\t\t\"string max status code\": {\n\t\t\tcode: `(http.expectedStatuses(200, 300, {min: 200, max:\"300\"}))`,\n\t\t\terr:  \"both min and max need to be integers for argument number 3\",\n\t\t},\n\t\t\"float status code\": {\n\t\t\terr:  \"argument number 2 to expectedStatuses was neither an integer nor an object like {min:100, max:329}\",\n\t\t\tcode: `(http.expectedStatuses(200, 300.5, {min: 200, max:300}))`,\n\t\t},\n\n\t\t\"float max status code\": {\n\t\t\terr:  \"both min and max need to be integers for argument number 3\",\n\t\t\tcode: `(http.expectedStatuses(200, 300, {min: 200, max:300.5}))`,\n\t\t},\n\t\t\"no arguments\": {\n\t\t\tcode: `(http.expectedStatuses())`,\n\t\t\terr:  \"no arguments\",\n\t\t},\n\t}\n\n\tfor name, testCase := range cases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tval, err := rt.RunString(testCase.code)\n\t\t\tif testCase.err == \"\" {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tgot := new(expectedStatuses)\n\t\t\t\terr = rt.ExportTo(val, &got)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, testCase.expected, *got)\n\t\t\t\treturn // the t.Run\n\t\t\t}\n\n\t\t\trequire.Error(t, err)\n\t\t\tvar exc *sobek.Exception\n\t\t\terrors.As(err, &exc)\n\t\t\trequire.ErrorContains(t, exc, testCase.err)\n\t\t})\n\t}\n}\n\ntype expectedSample struct {\n\ttags    map[string]string\n\tmetrics []string\n}\n\nfunc TestResponseCallbackInAction(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\n\tsr := tb.Replacer.Replace\n\n\tHTTPMetricsWithoutFailed := []string{\n\t\tmetrics.HTTPReqsName,\n\t\tmetrics.HTTPReqBlockedName,\n\t\tmetrics.HTTPReqConnectingName,\n\t\tmetrics.HTTPReqDurationName,\n\t\tmetrics.HTTPReqReceivingName,\n\t\tmetrics.HTTPReqWaitingName,\n\t\tmetrics.HTTPReqSendingName,\n\t\tmetrics.HTTPReqTLSHandshakingName,\n\t}\n\n\tallHTTPMetrics := append(HTTPMetricsWithoutFailed, metrics.HTTPReqFailedName) //nolint: gocritic\n\n\ttestCases := map[string]struct {\n\t\tcode            string\n\t\texpectedSamples []expectedSample\n\t}{\n\t\t\"basic\": {\n\t\t\tcode: `http.request(\"GET\", \"HTTPBIN_URL/redirect/1\");`,\n\t\t\texpectedSamples: []expectedSample{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"status\":            \"302\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"true\",\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"status\":            \"200\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"true\",\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"overwrite per request\": {\n\t\t\tcode: `\n\t\t\thttp.setResponseCallback(http.expectedStatuses(200));\n\t\t\thttp.request(\"GET\", \"HTTPBIN_URL/redirect/1\");\n\t\t\t`,\n\t\t\texpectedSamples: []expectedSample{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"status\":            \"302\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"false\", // this is on purpose\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"status\":            \"200\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"true\",\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\n\t\t\"global overwrite\": {\n\t\t\tcode: `http.request(\"GET\", \"HTTPBIN_URL/redirect/1\", null, {responseCallback: http.expectedStatuses(200)});`,\n\t\t\texpectedSamples: []expectedSample{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"status\":            \"302\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"false\", // this is on purpose\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"status\":            \"200\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"true\",\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"per request overwrite with null\": {\n\t\t\tcode: `http.request(\"GET\", \"HTTPBIN_URL/redirect/1\", null, {responseCallback: null});`,\n\t\t\texpectedSamples: []expectedSample{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"url\":    sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"name\":   sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"status\": \"302\",\n\t\t\t\t\t\t\"group\":  \"\",\n\t\t\t\t\t\t\"proto\":  \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: HTTPMetricsWithoutFailed,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"url\":    sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"name\":   sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"status\": \"200\",\n\t\t\t\t\t\t\"group\":  \"\",\n\t\t\t\t\t\t\"proto\":  \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: HTTPMetricsWithoutFailed,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t\"global overwrite with null\": {\n\t\t\tcode: `\n\t\t\thttp.setResponseCallback(null);\n\t\t\thttp.request(\"GET\", \"HTTPBIN_URL/redirect/1\");\n\t\t\t`,\n\t\t\texpectedSamples: []expectedSample{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"url\":    sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"name\":   sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\t\t\t\t\"status\": \"302\",\n\t\t\t\t\t\t\"group\":  \"\",\n\t\t\t\t\t\t\"proto\":  \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: HTTPMetricsWithoutFailed,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"url\":    sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"name\":   sr(\"HTTPBIN_URL/get\"),\n\t\t\t\t\t\t\"status\": \"200\",\n\t\t\t\t\t\t\"group\":  \"\",\n\t\t\t\t\t\t\"proto\":  \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: HTTPMetricsWithoutFailed,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor name, testCase := range testCases {\n\t\trunCode := func(code string) {\n\t\t\tt.Helper()\n\t\t\tts.instance.defaultClient.responseCallback = defaultExpectedStatuses.match\n\n\t\t\t_, err := ts.runtime.RunOnEventLoop(sr(code))\n\t\t\tassert.NoError(t, err)\n\t\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\n\t\t\treqsCount := 0\n\t\t\tfor _, container := range bufSamples {\n\t\t\t\tfor _, sample := range container.GetSamples() {\n\t\t\t\t\tif sample.Metric.Name == \"http_reqs\" {\n\t\t\t\t\t\treqsCount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trequire.Equal(t, len(testCase.expectedSamples), reqsCount)\n\n\t\t\tfor i, expectedSample := range testCase.expectedSamples {\n\t\t\t\tassertRequestMetricsEmittedSingle(t, bufSamples[i], expectedSample.tags, expectedSample.metrics, nil)\n\t\t\t}\n\t\t}\n\t\tt.Run(name, func(_ *testing.T) {\n\t\t\trunCode(testCase.code)\n\t\t})\n\t\tt.Run(\"async_\"+name, func(_ *testing.T) {\n\t\t\trunCode(strings.ReplaceAll(testCase.code, \"http.request\", \"http.asyncRequest\"))\n\t\t})\n\t}\n}\n\nfunc TestResponseCallbackBatch(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\n\tsr := tb.Replacer.Replace\n\n\tHTTPMetricsWithoutFailed := []string{\n\t\tmetrics.HTTPReqsName,\n\t\tmetrics.HTTPReqBlockedName,\n\t\tmetrics.HTTPReqConnectingName,\n\t\tmetrics.HTTPReqDurationName,\n\t\tmetrics.HTTPReqReceivingName,\n\t\tmetrics.HTTPReqWaitingName,\n\t\tmetrics.HTTPReqSendingName,\n\t\tmetrics.HTTPReqTLSHandshakingName,\n\t}\n\n\tallHTTPMetrics := append(HTTPMetricsWithoutFailed, metrics.HTTPReqFailedName) //nolint:gocritic\n\t// IMPORTANT: the tests here depend on the fact that the url they hit can be ordered in the same\n\t// order as the expectedSamples even if they are made concurrently\n\ttestCases := map[string]struct {\n\t\tcode            string\n\t\texpectedSamples []expectedSample\n\t}{\n\t\t\"basic\": {\n\t\t\tcode: `\n\thttp.batch([[\"GET\", \"HTTPBIN_URL/status/200\", null, {responseCallback: null}],\n\t\t\t[\"GET\", \"HTTPBIN_URL/status/201\"],\n\t\t\t[\"GET\", \"HTTPBIN_URL/status/202\", null, {responseCallback: http.expectedStatuses(4)}],\n\t\t\t[\"GET\", \"HTTPBIN_URL/status/405\", null, {responseCallback: http.expectedStatuses(405)}],\n\t]);`,\n\t\t\texpectedSamples: []expectedSample{\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"url\":    sr(\"HTTPBIN_URL/status/200\"),\n\t\t\t\t\t\t\"name\":   sr(\"HTTPBIN_URL/status/200\"),\n\t\t\t\t\t\t\"status\": \"200\",\n\t\t\t\t\t\t\"group\":  \"\",\n\t\t\t\t\t\t\"proto\":  \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: HTTPMetricsWithoutFailed,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/status/201\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/status/201\"),\n\t\t\t\t\t\t\"status\":            \"201\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"true\",\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/status/202\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/status/202\"),\n\t\t\t\t\t\t\"status\":            \"202\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"false\",\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttags: map[string]string{\n\t\t\t\t\t\t\"method\":            \"GET\",\n\t\t\t\t\t\t\"url\":               sr(\"HTTPBIN_URL/status/405\"),\n\t\t\t\t\t\t\"name\":              sr(\"HTTPBIN_URL/status/405\"),\n\t\t\t\t\t\t\"status\":            \"405\",\n\t\t\t\t\t\t\"error_code\":        \"1405\",\n\t\t\t\t\t\t\"group\":             \"\",\n\t\t\t\t\t\t\"expected_response\": \"true\",\n\t\t\t\t\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\t\t\t},\n\t\t\t\t\tmetrics: allHTTPMetrics,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor name, testCase := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tts.instance.defaultClient.responseCallback = defaultExpectedStatuses.match\n\n\t\t\t_, err := rt.RunString(sr(testCase.code))\n\t\t\tassert.NoError(t, err)\n\t\t\tbufSamples := metrics.GetBufferedSamples(samples)\n\n\t\t\treqsCount := 0\n\t\t\tfor _, container := range bufSamples {\n\t\t\t\tfor _, sample := range container.GetSamples() {\n\t\t\t\t\tif sample.Metric.Name == \"http_reqs\" {\n\t\t\t\t\t\treqsCount++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tsort.Slice(bufSamples, func(i, j int) bool {\n\t\t\t\tiURL, _ := bufSamples[i].GetSamples()[0].Tags.Get(\"url\")\n\t\t\t\tjURL, _ := bufSamples[j].GetSamples()[0].Tags.Get(\"url\")\n\t\t\t\treturn iURL < jURL\n\t\t\t})\n\n\t\t\trequire.Equal(t, len(testCase.expectedSamples), reqsCount)\n\n\t\t\tfor i, expectedSample := range testCase.expectedSamples {\n\t\t\t\tassertRequestMetricsEmittedSingle(t, bufSamples[i], expectedSample.tags, expectedSample.metrics, nil)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestResponseCallbackInActionWithoutPassedTag(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\tsr := tb.Replacer.Replace\n\tallHTTPMetrics := []string{\n\t\tmetrics.HTTPReqsName,\n\t\tmetrics.HTTPReqFailedName,\n\t\tmetrics.HTTPReqBlockedName,\n\t\tmetrics.HTTPReqConnectingName,\n\t\tmetrics.HTTPReqDurationName,\n\t\tmetrics.HTTPReqReceivingName,\n\t\tmetrics.HTTPReqSendingName,\n\t\tmetrics.HTTPReqWaitingName,\n\t\tmetrics.HTTPReqTLSHandshakingName,\n\t}\n\tdeleteSystemTag(state, metrics.TagExpectedResponse.String())\n\n\t_, err := rt.RunString(sr(`http.request(\"GET\", \"HTTPBIN_URL/redirect/1\", null, {responseCallback: http.expectedStatuses(200)});`))\n\tassert.NoError(t, err)\n\tbufSamples := metrics.GetBufferedSamples(samples)\n\n\treqsCount := 0\n\tfor _, container := range bufSamples {\n\t\tfor _, sample := range container.GetSamples() {\n\t\t\tif sample.Metric.Name == \"http_reqs\" {\n\t\t\t\treqsCount++\n\t\t\t}\n\t\t}\n\t}\n\n\trequire.Equal(t, 2, reqsCount)\n\n\ttags := map[string]string{\n\t\t\"method\": \"GET\",\n\t\t\"url\":    sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\"name\":   sr(\"HTTPBIN_URL/redirect/1\"),\n\t\t\"status\": \"302\",\n\t\t\"group\":  \"\",\n\t\t\"proto\":  \"HTTP/1.1\",\n\t}\n\tassertRequestMetricsEmittedSingle(t, bufSamples[0], tags, allHTTPMetrics, func(sample metrics.Sample) {\n\t\tif sample.Metric.Name == metrics.HTTPReqFailedName {\n\t\t\trequire.EqualValues(t, 1, sample.Value)\n\t\t}\n\t})\n\ttags[\"url\"] = sr(\"HTTPBIN_URL/get\")\n\ttags[\"name\"] = tags[\"url\"]\n\ttags[\"status\"] = \"200\"\n\tassertRequestMetricsEmittedSingle(t, bufSamples[1], tags, allHTTPMetrics, func(sample metrics.Sample) {\n\t\tif sample.Metric.Name == metrics.HTTPReqFailedName {\n\t\t\trequire.EqualValues(t, 0, sample.Value)\n\t\t}\n\t})\n}\n\nfunc TestDigestWithResponseCallback(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\n\turlWithCreds := tb.Replacer.Replace(\n\t\t\"http://testuser:testpwd@HTTPBIN_IP:HTTPBIN_PORT/digest-auth/auth/testuser/testpwd\",\n\t)\n\n\tallHTTPMetrics := []string{\n\t\tmetrics.HTTPReqsName,\n\t\tmetrics.HTTPReqFailedName,\n\t\tmetrics.HTTPReqBlockedName,\n\t\tmetrics.HTTPReqConnectingName,\n\t\tmetrics.HTTPReqDurationName,\n\t\tmetrics.HTTPReqReceivingName,\n\t\tmetrics.HTTPReqSendingName,\n\t\tmetrics.HTTPReqWaitingName,\n\t\tmetrics.HTTPReqTLSHandshakingName,\n\t}\n\t_, err := rt.RunString(fmt.Sprintf(`\n\t\tvar res = http.get(%q,  { auth: \"digest\" });\n\t\tif (res.status !== 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\tif (res.error_code !== 0) { throw new Error(\"wrong error code: \" + res.error_code); }\n\t`, urlWithCreds))\n\trequire.NoError(t, err)\n\tbufSamples := metrics.GetBufferedSamples(samples)\n\n\treqsCount := 0\n\tfor _, container := range bufSamples {\n\t\tfor _, sample := range container.GetSamples() {\n\t\t\tif sample.Metric.Name == \"http_reqs\" {\n\t\t\t\treqsCount++\n\t\t\t}\n\t\t}\n\t}\n\n\trequire.Equal(t, 2, reqsCount)\n\n\turlRaw := tb.Replacer.Replace(\n\t\t\"http://HTTPBIN_IP:HTTPBIN_PORT/digest-auth/auth/testuser/testpwd\")\n\n\ttags := map[string]string{\n\t\t\"method\":            \"GET\",\n\t\t\"url\":               urlRaw,\n\t\t\"name\":              urlRaw,\n\t\t\"status\":            \"401\",\n\t\t\"group\":             \"\",\n\t\t\"proto\":             \"HTTP/1.1\",\n\t\t\"expected_response\": \"true\",\n\t\t\"error_code\":        \"1401\",\n\t}\n\tassertRequestMetricsEmittedSingle(t, bufSamples[0], tags, allHTTPMetrics, func(sample metrics.Sample) {\n\t\tif sample.Metric.Name == metrics.HTTPReqFailedName {\n\t\t\trequire.EqualValues(t, 0, sample.Value)\n\t\t}\n\t})\n\ttags[\"status\"] = \"200\"\n\tdelete(tags, \"error_code\")\n\tassertRequestMetricsEmittedSingle(t, bufSamples[1], tags, allHTTPMetrics, func(sample metrics.Sample) {\n\t\tif sample.Metric.Name == metrics.HTTPReqFailedName {\n\t\t\trequire.EqualValues(t, 0, sample.Value)\n\t\t}\n\t})\n}\n\nfunc deleteSystemTag(state *lib.State, tag string) {\n\tenabledTags := state.Options.SystemTags.Map()\n\tdelete(enabledTags, tag)\n\ttagsList := make([]string, 0, len(enabledTags))\n\tfor k := range enabledTags {\n\t\ttagsList = append(tagsList, k)\n\t}\n\tstate.Options.SystemTags = metrics.ToSystemTagSet(tagsList)\n}\n"
  },
  {
    "path": "js/modules/k6/http/response_test.go",
    "content": "package http\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst testGetFormHTML = `\n<html>\n<head>\n\t<title>This is the title</title>\n</head>\n<body>\n\t<form method=\"get\" id=\"form1\">\n\t\t<input name=\"input_with_value\" type=\"text\" value=\"value\"/>\n\t\t<input name=\"input_without_value\" type=\"text\"/>\n\t\t<select name=\"select_one\">\n\t\t\t<option value=\"not this option\">no</option>\n\t\t\t<option value=\"yes this option\" selected>yes</option>\n\t\t</select>\n\t\t<select name=\"select_multi\" multiple>\n\t\t\t<option>option 1</option>\n\t\t\t<option selected>option 2</option>\n\t\t\t<option selected>option 3</option>\n\t\t</select>\n\t\t<textarea name=\"textarea\" multiple>Lorem ipsum dolor sit amet</textarea>\n\t</form>\n</body>\n`\n\nconst jsonData = `{\"glossary\": {\n    \"friends\": [\n      {\"first\": \"Dale\", \"last\": \"Murphy\", \"age\": 44},\n      {\"first\": \"Roger\", \"last\": \"Craig\", \"age\": 68},\n      {\"first\": \"Jane\", \"last\": \"Murphy\", \"age\": 47}],\n\t\"GlossDiv\": {\n\t  \"title\": \"S\",\n\t  \"GlossList\": {\n\t    \"GlossEntry\": {\n\t      \"ID\": \"SGML\",\n\t      \"SortAs\": \"SGML\",\n\t      \"GlossTerm\": \"Standard Generalized Markup Language\",\n\t      \"Acronym\": \"SGML\",\n\t      \"Abbrev\": \"ISO 8879:1986\",\n\t      \"GlossDef\": {\n            \"int\": 1123456,\n            \"null\": null,\n            \"intArray\": [1,2,3],\n            \"mixedArray\": [\"123\",123,true,null],\n            \"boolean\": true,\n            \"title\": \"example glossary\",\n            \"para\": \"A meta-markup language, used to create markup languages such as DocBook.\",\n\t  \"GlossSeeAlso\": [\"GML\",\"XML\"]},\n\t\"GlossSee\": \"markup\"}}}}}`\n\nconst invalidJSONData = `{\n\t\"a\":\"apple\",\n\t\"t\":testing\"\n}`\n\nfunc myFormHandler(w http.ResponseWriter, r *http.Request) {\n\tvar body []byte\n\tvar err error\n\tif r.URL.RawQuery != \"\" {\n\t\tbody, err = json.Marshal(struct {\n\t\t\tQuery url.Values `json:\"query\"`\n\t\t}{\n\t\t\tQuery: r.URL.Query(),\n\t\t})\n\t\tif err != nil {\n\t\t\tbody = []byte(`{\"error\": \"failed serializing json\"}`)\n\t\t}\n\t\tw.Header().Set(\"Content-Type\", \"application/json\")\n\t} else {\n\t\tw.Header().Set(\"Content-Type\", \"text/html\")\n\t\tbody = []byte(testGetFormHTML)\n\t}\n\tw.Header().Set(\"Content-Length\", fmt.Sprintf(\"%d\", len(body)))\n\tw.WriteHeader(http.StatusOK)\n\t_, _ = w.Write(body)\n}\n\nfunc jsonHandler(w http.ResponseWriter, _ *http.Request) {\n\tbody := []byte(jsonData)\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.Header().Set(\"Content-Length\", fmt.Sprintf(\"%d\", len(body)))\n\tw.WriteHeader(http.StatusOK)\n\t_, _ = w.Write(body)\n}\n\nfunc invalidJSONHandler(w http.ResponseWriter, _ *http.Request) {\n\tbody := []byte(invalidJSONData)\n\tw.Header().Set(\"Content-Type\", \"application/json\")\n\tw.Header().Set(\"Content-Length\", fmt.Sprintf(\"%d\", len(body)))\n\tw.WriteHeader(http.StatusOK)\n\t_, _ = w.Write(body)\n}\n\nfunc TestCheckErrorInJSON_Offsets(t *testing.T) {\n\ttestCases := []struct {\n\t\tname     string\n\t\tinput    string\n\t\twantLine int\n\t\twantChar int\n\t}{\n\t\t{\n\t\t\tname:     \"invalid-first-byte\",\n\t\t\tinput:    \"a\\nb\",\n\t\t\twantLine: 1,\n\t\t\twantChar: 1,\n\t\t},\n\t\t{\n\t\t\tname:     \"invalid-after-newline\",\n\t\t\tinput:    \"true\\nx\",\n\t\t\twantLine: 2,\n\t\t\twantChar: 1,\n\t\t},\n\t\t{\n\t\t\tname: \"invalid-middle\",\n\t\t\tinput: \"{\\n\" +\n\t\t\t\t\"  \\\"a\\\": 1,\\n\" +\n\t\t\t\t\"  \\\"b\\\": [1, 2, 3,, 4]\\n\" +\n\t\t\t\t\"}\",\n\t\t\twantLine: 3,\n\t\t\twantChar: 17,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tvar v any\n\t\t\terr := json.Unmarshal([]byte(testCase.input), &v)\n\t\t\trequire.Error(t, err)\n\n\t\t\tvar syntaxError *json.SyntaxError\n\t\t\trequire.ErrorAs(t, err, &syntaxError)\n\n\t\t\tjsonErr := checkErrorInJSON([]byte(testCase.input), int(syntaxError.Offset), err)\n\n\t\t\tvar parsed jsonError\n\t\t\trequire.ErrorAs(t, jsonErr, &parsed)\n\t\t\tassert.Equal(t, testCase.wantLine, parsed.line)\n\t\t\tassert.Equal(t, testCase.wantChar, parsed.character)\n\t\t})\n\t}\n}\n\nfunc TestResponse(t *testing.T) {\n\tts := newTestCase(t)\n\ttb := ts.tb\n\tsamples := ts.samples\n\trt := ts.runtime.VU.Runtime()\n\tstate := ts.runtime.VU.State()\n\tsr := tb.Replacer.Replace\n\n\ttb.Mux.HandleFunc(\"/myforms/get\", myFormHandler)\n\ttb.Mux.HandleFunc(\"/json\", jsonHandler)\n\ttb.Mux.HandleFunc(\"/invalidjson\", invalidJSONHandler)\n\n\tt.Run(\"Html\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/html\");\n\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\tif (res.body.indexOf(\"Herman Melville - Moby-Dick\") == -1) { throw new Error(\"wrong body: \" + res.body); }\n\t\t`))\n\t\tassert.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/html\"), 200, \"\")\n\n\t\tt.Run(\"html\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(`\n\t\t\t\tif (res.html().find(\"h1\").text() != \"Herman Melville - Moby-Dick\") { throw new Error(\"wrong title: \" + res.body); }\n\t\t\t`)\n\t\t\tassert.NoError(t, err)\n\n\t\t\tt.Run(\"shorthand\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(`\n\t\t\t\t\tif (res.html(\"h1\").text() != \"Herman Melville - Moby-Dick\") { throw new Error(\"wrong title: \" + res.body); }\n\t\t\t\t`)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t})\n\n\t\t\tt.Run(\"url\", func(t *testing.T) {\n\t\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\t\tif (res.html().url != \"HTTPBIN_URL/html\") { throw new Error(\"url incorrect: \" + res.html().url); }\n\t\t\t\t`))\n\t\t\t\tassert.NoError(t, err)\n\t\t\t})\n\t\t})\n\n\t\tt.Run(\"group\", func(t *testing.T) {\n\t\t\tgroupName, err := lib.NewGroupPath(lib.RootGroupPath, \"my group\")\n\t\t\trequire.NoError(t, err)\n\t\t\tstate.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\t\ttagsAndMeta.SetTag(\"group\", groupName)\n\t\t\t})\n\t\t\tdefer func() {\n\t\t\t\tstate.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) {\n\t\t\t\t\ttagsAndMeta.SetTag(\"group\", \"\")\n\t\t\t\t})\n\t\t\t}()\n\n\t\t\t_, err = rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/html\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tif (res.body.indexOf(\"Herman Melville - Moby-Dick\") == -1) { throw new Error(\"wrong body: \" + res.body); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/html\"), 200, \"::my group\")\n\t\t})\n\n\t\tt.Run(\"NoResponseBody\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`http.get(\"HTTPBIN_URL/html\", {responseType: 'none'}).html();`))\n\t\t\trequire.NotNil(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"the body is null so we can't transform it to HTML\"+\n\t\t\t\t\" - this likely was because of a request error getting the response\")\n\t\t})\n\t})\n\tt.Run(\"Json\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/get?a=1&b=2\");\n\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\tif (res.json().args.a != \"1\") { throw new Error(\"wrong ?a: \" + res.json().args.a); }\n\t\t\tif (res.json().args.b != \"2\") { throw new Error(\"wrong ?b: \" + res.json().args.b); }\n\t\t`))\n\t\tassert.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/get?a=1&b=2\"), 200, \"\")\n\n\t\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`http.request(\"GET\", \"HTTPBIN_URL/html\").json();`))\n\t\t\tassert.Contains(t, err.Error(), \"cannot parse json due to an error at line 1, character 1 , error: invalid character '<' looking for beginning of value\")\n\t\t})\n\n\t\tt.Run(\"Invalid\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`http.request(\"GET\", \"HTTPBIN_URL/invalidjson\").json();`))\n\t\t\tassert.Contains(t, err.Error(), \"cannot parse json due to an error at line 3, character 7 , error: invalid character 'e' in literal true (expecting 'r')\")\n\t\t})\n\n\t\tt.Run(\"NoResponseBody\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`http.get(\"HTTPBIN_URL/json\", {responseType: 'none'}).json();`))\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), \"the body is null so we can't transform it to JSON\"+\n\t\t\t\t\" - this likely was because of a request error getting the response\")\n\t\t})\n\t})\n\tt.Run(\"JsonSelector\", func(t *testing.T) {\n\t\t_, err := rt.RunString(sr(`\n\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/json\");\n\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\n\t\t\tvar value = res.json(\"glossary.friends.1\")\n\t        if (typeof value != \"object\")\n\t\t\t\t{ throw new Error(\"wrong type of result value: \" + value); }\n\t        if (value[\"first\"] != \"Roger\")\n\t\t\t\t{ throw new Error(\"Expected Roger for key first but got: \" + value[\"first\"]); }\n\n\t\t\tvalue = res.json(\"glossary.int1\")\n\t        if (value != undefined)\n\t\t\t\t{ throw new Error(\"Expected undefined, but got: \" + value); }\n\n\t\t\tvalue = res.json(\"glossary.null\")\n\t        if (value != null)\n\t\t\t\t{ throw new Error(\"Expected null, but got: \" + value); }\n\n\t\t\tvalue = res.json(\"glossary.GlossDiv.GlossList.GlossEntry.GlossDef.intArray.#\")\n\t        if (value != 3)\n\t\t\t\t{ throw new Error(\"Expected num 3, but got: \" + value); }\n\n\t\t\tvalue = res.json(\"glossary.GlossDiv.GlossList.GlossEntry.GlossDef.intArray\")[2]\n\t        if (value != 3)\n \t\t\t\t{ throw new Error(\"Expected, num 3, but got: \" + value); }\n\n\t\t\tvalue = res.json(\"glossary.GlossDiv.GlossList.GlossEntry.GlossDef.boolean\")\n\t        if (value != true)\n\t\t\t\t{ throw new Error(\"Expected boolean true, but got: \" + value); }\n\n\t\t\tvalue = res.json(\"glossary.GlossDiv.GlossList.GlossEntry.GlossDef.title\")\n\t        if (value != \"example glossary\")\n\t\t\t\t{ throw new Error(\"Expected 'example glossary'', but got: \" + value); }\n\n\t\t\tvalue =\tres.json(\"glossary.friends.#.first\")[0]\n\t        if (value != \"Dale\")\n\t\t\t\t{ throw new Error(\"Expected 'Dale', but got: \" + value); }\n\t\t`))\n\t\tassert.NoError(t, err)\n\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/json\"), 200, \"\")\n\t})\n\n\tt.Run(\"SubmitForm\", func(t *testing.T) {\n\t\tt.Run(\"withoutArgs\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/forms/post\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.submitForm()\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tvar data = res.json().form\n\t\t\t\tif (data.custname[0] !== \"\" ||\n\t\t\t\t\tdata.extradata !== undefined ||\n\t\t\t\t\tdata.comments[0] !== \"\" ||\n\t\t\t\t\tdata.custemail[0] !== \"\" ||\n\t\t\t\t\tdata.custtel[0] !== \"\" ||\n\t\t\t\t\tdata.delivery[0] !== \"\"\n\t\t\t\t) { throw new Error(\"incorrect body: \" + JSON.stringify(data, null, 4) ); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"POST\", sr(\"HTTPBIN_URL/post\"), 200, \"\")\n\t\t})\n\n\t\tt.Run(\"withFields\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/forms/post\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.submitForm({ fields: { custname: \"test\", extradata: \"test2\" } })\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tvar data = res.json().form\n\t\t\t\tif (data.custname[0] !== \"test\" ||\n\t\t\t\t\tdata.extradata[0] !== \"test2\" ||\n\t\t\t\t\tdata.comments[0] !== \"\" ||\n\t\t\t\t\tdata.custemail[0] !== \"\" ||\n\t\t\t\t\tdata.custtel[0] !== \"\" ||\n\t\t\t\t\tdata.delivery[0] !== \"\"\n\t\t\t\t) { throw new Error(\"incorrect body: \" + JSON.stringify(data, null, 4) ); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"POST\", sr(\"HTTPBIN_URL/post\"), 200, \"\")\n\t\t})\n\n\t\tt.Run(\"withRequestParams\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/forms/post\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.submitForm({ params: { headers: { \"My-Fancy-Header\": \"SomeValue\" } }})\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tvar headers = res.json().headers\n\t\t\t\tif (headers[\"My-Fancy-Header\"][0] !== \"SomeValue\" ) { throw new Error(\"incorrect headers: \" + JSON.stringify(headers)); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"POST\", sr(\"HTTPBIN_URL/post\"), 200, \"\")\n\t\t})\n\n\t\tt.Run(\"withFormSelector\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/forms/post\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.submitForm({ formSelector: 'form[method=\"post\"]' })\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tvar data = res.json().form\n\t\t\t\tif (data.custname[0] !== \"\" ||\n\t\t\t\t\tdata.extradata !== undefined ||\n\t\t\t\t\tdata.comments[0] !== \"\" ||\n\t\t\t\t\tdata.custemail[0] !== \"\" ||\n\t\t\t\t\tdata.custtel[0] !== \"\" ||\n\t\t\t\t\tdata.delivery[0] !== \"\"\n\t\t\t\t) { throw new Error(\"incorrect body: \" + JSON.stringify(data, null, 4) ); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"POST\", sr(\"HTTPBIN_URL/post\"), 200, \"\")\n\t\t})\n\n\t\tt.Run(\"withNonExistentForm\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/forms/post\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres.submitForm({ formSelector: \"#doesNotExist\" })\n\t\t\t`))\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), sr(\"no form found for selector '#doesNotExist' in response 'HTTPBIN_URL/forms/post'\"))\n\t\t})\n\n\t\tt.Run(\"withGetMethod\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/myforms/get\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.submitForm()\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tvar data = res.json().query\n\t\t\t\tif (data.input_with_value[0] !== \"value\" ||\n\t\t\t\t\tdata.input_without_value[0] !== \"\" ||\n\t\t\t\t\tdata.select_one[0] !== \"yes this option\" ||\n\t\t\t\t\tdata.select_multi[0] !== \"option 2,option 3\" ||\n\t\t\t\t\tdata.textarea[0] !== \"Lorem ipsum dolor sit amet\"\n\t\t\t\t) { throw new Error(\"incorrect body: \" + JSON.stringify(data, null, 4) ); }\n\t\t\t`))\n\t\t\trequire.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/myforms/get\"), 200, \"\")\n\t\t})\n\t})\n\n\tt.Run(\"ClickLink\", func(t *testing.T) {\n\t\tt.Run(\"withoutArgs\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/links/10/0\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.clickLink()\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/links/10/1\"), 200, \"\")\n\t\t})\n\n\t\tt.Run(\"withSelector\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/links/10/0\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.clickLink({ selector: 'a:nth-child(4)' })\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/links/10/4\"), 200, \"\")\n\t\t})\n\n\t\tt.Run(\"withNonExistentLink\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL/links/10/0\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.clickLink({ selector: 'a#doesNotExist' })\n\t\t\t`))\n\t\t\trequire.Error(t, err)\n\t\t\tassert.Contains(t, err.Error(), sr(\"no element found for selector 'a#doesNotExist' in response 'HTTPBIN_URL/links/10/0'\"))\n\t\t})\n\n\t\tt.Run(\"withRequestParams\", func(t *testing.T) {\n\t\t\t_, err := rt.RunString(sr(`\n\t\t\t\tvar res = http.request(\"GET\", \"HTTPBIN_URL\");\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tres = res.clickLink({ selector: 'a[href=\"/get\"]', params: { headers: { \"My-Fancy-Header\": \"SomeValue\" } } })\n\t\t\t\tif (res.status != 200) { throw new Error(\"wrong status: \" + res.status); }\n\t\t\t\tvar headers = res.json().headers\n\t\t\t\tif (headers[\"My-Fancy-Header\"][0] !== \"SomeValue\" ) { throw new Error(\"incorrect headers: \" + JSON.stringify(headers)); }\n\t\t\t`))\n\t\t\tassert.NoError(t, err)\n\t\t\tassertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), \"GET\", sr(\"HTTPBIN_URL/get\"), 200, \"\")\n\t\t})\n\t})\n\n\tt.Run(\"FailedRequestHeadersAndCookiesAssignment\", func(t *testing.T) {\n\t\t_, err := rt.RunString(`\n\t\t\tvar res = http.get(\"https://test.k6.i\", { throw: false });\n\t\t\tres.headers[\"custom-key\"] = \"custom-value\";\n\t\t\tif (res.headers[\"custom-key\"] !== \"custom-value\") {\n\t\t\t\tthrow new Error(\"Failed to assign to headers on failed request\");\n\t\t\t}\n\t\t`)\n\t\tassert.NoError(t, err)\n\t})\n}\n"
  },
  {
    "path": "js/modules/k6/http/tls_test.go",
    "content": "package http\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\nfunc TestTLS13Support(t *testing.T) {\n\tt.Parallel()\n\tts := newTestCase(t)\n\tstate := ts.runtime.VU.State()\n\n\tts.tb.Mux.HandleFunc(\"/tls-version\", http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {\n\t\tver := req.TLS.Version\n\t\t_, err := fmt.Fprint(resp, lib.SupportedTLSVersionsToString[lib.TLSVersion(ver)])\n\t\trequire.NoError(t, err)\n\t}))\n\n\t// We don't expect any failed requests\n\tstate.Options.Throw = null.BoolFrom(true)\n\tstate.Options.Apply(lib.Options{TLSVersion: &lib.TLSVersions{Max: tls.VersionTLS13}})\n\n\t_, err := ts.runtime.VU.Runtime().RunString(ts.tb.Replacer.Replace(`\n\t\tvar resp = http.get(\"HTTPSBIN_URL/tls-version\");\n\t\tif (resp.body != \"tls1.3\") {\n\t\t\tthrow new Error(\"unexpected tls version: \" + resp.body);\n\t\t}\n\t`))\n\trequire.NoError(t, err)\n}\n"
  },
  {
    "path": "js/modules/modules.go",
    "content": "// Package modules defines interfaces used for developing k6's JavaScript modules.\npackage modules\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/lib\"\n)\n\nconst extPrefix string = \"k6/x/\"\n\n// Register the given mod as an external JavaScript module that can be imported\n// by name. The name must be unique across all registered modules and must be\n// prefixed with \"k6/x/\", otherwise this function will panic.\nfunc Register(name string, mod any) {\n\tif !strings.HasPrefix(name, extPrefix) {\n\t\tpanic(fmt.Errorf(\"external module names must be prefixed with '%s', tried to register: %s\", extPrefix, name))\n\t}\n\n\text.Register(name, ext.JSExtension, mod)\n}\n\n// Module is the interface js modules should implement in order to get access to the VU\ntype Module interface {\n\t// NewModuleInstance will get modules.VU that should provide the module with a way to interact with the VU.\n\t// This method will be called for *each* VU that imports the module *once* per that VU.\n\tNewModuleInstance(VU) Instance\n}\n\n// Instance is what a module needs to return\ntype Instance interface {\n\tExports() Exports\n}\n\n// VU gives access to the currently executing VU to a module Instance\ntype VU interface {\n\t// Context return the context.Context about the current VU\n\tContext() context.Context\n\n\t// Events allows subscribing to global k6 execution events, such as Init and\n\t// Exit, and to local (per-VU) events, such as IterStart and IterEnd.\n\t// NOTE: This API is EXPERIMENTAL and may be changed, renamed or\n\t// completely removed in a later k6 release.\n\t// FIXME: Subscribing to global events shouldn't be part of this VU (local)\n\t// interface.\n\tEvents() common.Events\n\n\t// InitEnv returns common.InitEnvironment instance if present\n\tInitEnv() *common.InitEnvironment\n\n\t// State returns lib.State if any is present\n\tState() *lib.State\n\n\t// Runtime returns the sobek.Runtime for the current VU\n\tRuntime() *sobek.Runtime\n\n\t// RegisterCallback lets a JS module declare that it wants to run a function\n\t// on the event loop *at a later point in time*. See the documentation for\n\t// `EventLoop.RegisterCallback()` in the `k6/js/eventloop` Go module for\n\t// the very important details on its usage and restrictions.\n\tRegisterCallback() (enqueueCallback func(func() error))\n\n\t// sealing field will help probably with pointing users that they just need to embed this in their Instance\n\t// implementations\n}\n\n// Exports is representation of ESM exports of a module\ntype Exports struct {\n\t// Default is what will be the `default` export of a module\n\tDefault any\n\t// Named is the named exports of a module\n\tNamed map[string]any\n}\n"
  },
  {
    "path": "js/modules/require_impl.go",
    "content": "package modules\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"maps\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/internal/loader\"\n)\n\n// Require is the actual call that implements require\nfunc (ms *ModuleSystem) Require(specifier string) (*sobek.Object, error) {\n\tif !ms.resolver.locked {\n\t\tif err := ms.resolver.usage.Uint64(\"usage/require\", 1); err != nil {\n\t\t\tms.resolver.logger.WithError(err).Warn(\"couldn't report usage\")\n\t\t}\n\t}\n\n\tif specifier == \"\" {\n\t\treturn nil, errors.New(\"require() can't be used with an empty specifier\")\n\t}\n\n\trt := ms.vu.Runtime()\n\tparentModuleStr := getCurrentModuleScript(ms.vu)\n\n\tparentModule, _ := ms.resolver.sobekModuleResolver(nil, parentModuleStr)\n\tm, err := ms.resolver.sobekModuleResolver(parentModule, specifier)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif wm, ok := m.(*goModule); ok {\n\t\tvar gmi *goModuleInstance\n\t\tgmi, err = ms.getModuleInstanceFromGoModule(wm)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\texports := toESModuleExports(gmi.mi.Exports())\n\t\treturn rt.ToValue(exports).ToObject(rt), nil\n\t}\n\terr = m.Link()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar promise *sobek.Promise\n\tif c, ok := m.(sobek.CyclicModuleRecord); ok {\n\t\tpromise = rt.CyclicModuleRecordEvaluate(c, ms.resolver.sobekModuleResolver)\n\t} else {\n\t\tpanic(fmt.Sprintf(\"expected sobek.CyclicModuleRecord, but for some reason got a %T\", m))\n\t}\n\tpromisesThenIgnore(rt, promise)\n\tswitch promise.State() {\n\tcase sobek.PromiseStateRejected:\n\t\terr = promise.Result().Export().(error) //nolint:forcetypeassert\n\tcase sobek.PromiseStateFulfilled:\n\tdefault:\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif cjs, ok := m.(*cjsModule); ok {\n\t\treturn rt.GetModuleInstance(cjs).(*cjsModuleInstance).exports, nil //nolint:forcetypeassert\n\t}\n\treturn rt.NamespaceObjectFor(m), nil\n}\n\nfunc (ms *ModuleSystem) getModuleInstanceFromGoModule(wm *goModule) (wmi *goModuleInstance, err error) {\n\trt := ms.vu.Runtime()\n\tmi := rt.GetModuleInstance(wm)\n\tif mi == nil {\n\t\terr = wm.Link()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tpromise := rt.CyclicModuleRecordEvaluate(wm, ms.resolver.sobekModuleResolver)\n\t\tswitch promise.State() {\n\t\tcase sobek.PromiseStateRejected:\n\t\t\terr = promise.Result().Export().(error) //nolint:forcetypeassert\n\t\tcase sobek.PromiseStateFulfilled:\n\t\tdefault:\n\t\t\tpanic(\"TLA in go modules is not supported in k6 at the moment\")\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tmi = rt.GetModuleInstance(wm)\n\t}\n\tgmi, ok := mi.(*goModuleInstance)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"a goModule instance is of not goModuleInstance type (got %T). \"+\n\t\t\t\"This is a k6 bug please report it (https://github.com/grafana/k6/issues)\", mi))\n\t}\n\treturn gmi, nil\n}\n\n// Resolve returns what the provided specifier will get resolved to if it was to be imported\n// To be used by other parts to get the path\nfunc (ms *ModuleSystem) Resolve(mr sobek.ModuleRecord, specifier string) (*url.URL, error) {\n\tif specifier == \"\" {\n\t\treturn nil, errors.New(\"require() can't be used with an empty specifier\")\n\t}\n\n\tbaseModuleURL := ms.resolver.reversePath(mr)\n\treturn ms.resolver.resolveSpecifier(baseModuleURL, specifier)\n}\n\n// CurrentlyRequiredModule returns the module that is currently being required.\n// It is mostly used for old and somewhat buggy behaviour of the `open` call\nfunc (ms *ModuleSystem) CurrentlyRequiredModule() (*url.URL, error) {\n\tfileStr, err := getPreviousRequiringFile(ms.vu)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar u *url.URL\n\tswitch {\n\t// this works around windows URLs like file://C:/some/path\n\t// url.Parse will think of C: as hostname\n\tcase strings.HasPrefix(fileStr, \"file://\"):\n\t\tu = new(url.URL)\n\t\tu.Scheme = \"file\"\n\t\tu.Path, err = url.PathUnescape(strings.TrimPrefix(fileStr, \"file://\"))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tcase strings.HasPrefix(fileStr, \"https://\"):\n\t\tvar err error\n\t\tu, err = url.Parse(fileStr)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"couldn't parse %q as module url - this is a k6 bug, \"+\n\t\t\t\"please report it (https://github.com/grafana/k6/issues)\", fileStr)\n\t}\n\treturn loader.Dir(u), nil\n}\n\n// ShouldWarnOnParentDirNotMatchingCurrentModuleParentDir is a helper function to figure out if the provided url\n// is the same folder that an import will be to.\n// It also checks if the modulesystem is locked which means we are past the first init context.\n// If false is returned means that we are not in the init context or the path is matching - so no warning should be done\n// If true, the returned path is the module path that it should be relative to - the one that is checked against.\nfunc (ms *ModuleSystem) ShouldWarnOnParentDirNotMatchingCurrentModuleParentDir(vu VU, parentModulePwd *url.URL,\n) (string, bool) {\n\tif ms.resolver.locked {\n\t\treturn \"\", false\n\t}\n\tnormalizePathToURL := func(path string) string {\n\t\tu, err := url.Parse(path)\n\t\tif err != nil {\n\t\t\treturn path\n\t\t}\n\t\treturn loader.Dir(u).String()\n\t}\n\tparentModuleDir := parentModulePwd.String()\n\tparentModuleStr2 := getCurrentModuleScript(vu)\n\tparentModuleStr2Dir := normalizePathToURL(parentModuleStr2)\n\tif parentModuleDir != parentModuleStr2Dir {\n\t\treturn parentModuleStr2, true\n\t}\n\treturn \"\", false\n}\n\nfunc toESModuleExports(exp Exports) any {\n\tif exp.Named == nil {\n\t\treturn exp.Default\n\t}\n\tif exp.Default == nil {\n\t\treturn exp.Named\n\t}\n\n\tresult := make(map[string]any, len(exp.Named)+2)\n\n\tmaps.Copy(result, exp.Named)\n\tresult[jsDefaultExportIdentifier] = exp.Default\n\t// This is to interop with any code that is transpiled by Babel or any similar tool.\n\tresult[\"__esModule\"] = true\n\n\treturn result\n}\n\nfunc getCurrentModuleScript(vu VU) string {\n\trt := vu.Runtime()\n\tvar parent string\n\tvar buf [2]sobek.StackFrame\n\tframes := rt.CaptureCallStack(2, buf[:0])\n\tif len(frames) == 0 || frames[1].SrcName() == \"file:///-\" {\n\t\treturn vu.InitEnv().CWD.JoinPath(\"./-\").String()\n\t}\n\tparent = frames[1].SrcName()\n\n\treturn parent\n}\n\nfunc getPreviousRequiringFile(vu VU) (string, error) {\n\trt := vu.Runtime()\n\tvar buf [1000]sobek.StackFrame\n\tframes := rt.CaptureCallStack(1000, buf[:0])\n\n\tfor i, frame := range frames[1:] { // first one should be the current require\n\t\t// TODO have this precalculated automatically\n\t\tif frame.FuncName() == \"go.k6.io/k6/internal/js.(*requireImpl).require-fm\" {\n\t\t\t// we need to get the one *before* but as we skip the first one the index matches ;)\n\t\t\tresult := frames[i].SrcName()\n\t\t\tif result == \"file:///-\" {\n\t\t\t\treturn vu.InitEnv().CWD.JoinPath(\"./-\").String(), nil\n\t\t\t}\n\t\t\treturn result, nil\n\t\t}\n\t}\n\t// hopefully nobody is calling `require` with 1000 big stack :crossedfingers:\n\tif len(frames) == 1000 {\n\t\treturn \"\", errors.New(\"stack too big\")\n\t}\n\n\t// fallback\n\tresult := frames[len(frames)-1].SrcName()\n\tif result == \"file:///-\" {\n\t\treturn vu.InitEnv().CWD.JoinPath(\"./-\").String(), nil\n\t}\n\treturn result, nil\n}\n\n// sets the provided promise in such way as to ignore falures\n// this is mostly needed as failures are handled separately and we do not want those to lead to stopping the event loop\nfunc promisesThenIgnore(rt *sobek.Runtime, promise *sobek.Promise) {\n\tcall, _ := sobek.AssertFunction(rt.ToValue(promise).ToObject(rt).Get(\"then\"))\n\thandler := rt.ToValue(func(_ sobek.Value) {})\n\t_, _ = call(rt.ToValue(promise), handler, handler)\n}\n"
  },
  {
    "path": "js/modules/resolution.go",
    "content": "package modules\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/grafana/sobek/ast\"\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/js/compiler\"\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/internal/usage\"\n)\n\nconst notPreviouslyResolvedModule = \"the module %q was not previously resolved during initialization (__VU==0)\"\n\nconst jsDefaultExportIdentifier = \"default\"\n\n// FileLoader is a type alias for a function that returns the contents of the referenced file.\ntype FileLoader func(specifier *url.URL, name string) ([]byte, error)\n\ntype moduleCacheElement struct {\n\tmod sobek.ModuleRecord\n\terr error\n}\n\n// ModuleResolver knows how to get base Module that can be initialized\ntype ModuleResolver struct {\n\tcache          map[string]moduleCacheElement\n\tgoModules      map[string]any\n\tloadCJS        FileLoader\n\tcompiler       *compiler.Compiler\n\tlocked         bool\n\treverse        map[any]*url.URL // maybe use sobek.ModuleRecord as key\n\tbase           *url.URL\n\tusage          *usage.Usage\n\tlogger         logrus.FieldLogger\n\tunknownModules []string\n}\n\n// NewModuleResolver returns a new module resolution instance that will resolve.\n// goModules is map of import file to a go module\n// loadCJS is used to load commonjs files\nfunc NewModuleResolver(\n\tgoModules map[string]any, loadCJS FileLoader, c *compiler.Compiler, base *url.URL,\n\tu *usage.Usage, logger logrus.FieldLogger,\n) *ModuleResolver {\n\treturn &ModuleResolver{\n\t\tgoModules: goModules,\n\t\tcache:     make(map[string]moduleCacheElement),\n\t\tloadCJS:   loadCJS,\n\t\tcompiler:  c,\n\t\treverse:   make(map[any]*url.URL),\n\t\tbase:      base,\n\t\tusage:     u,\n\t\tlogger:    logger,\n\t}\n}\n\nfunc (mr *ModuleResolver) resolveSpecifier(basePWD *url.URL, arg string) (*url.URL, error) {\n\tspecifier, err := loader.Resolve(basePWD, arg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn specifier, nil\n}\n\nfunc (mr *ModuleResolver) initializeGoModule(name string) (sobek.ModuleRecord, error) {\n\tif mr.locked {\n\t\treturn nil, fmt.Errorf(notPreviouslyResolvedModule, name)\n\t}\n\tmod, ok := mr.goModules[name]\n\tif !ok {\n\t\tmr.unknownModules = append(mr.unknownModules, name)\n\t\treturn &unknownModule{name: name, requested: make(map[string]struct{})}, nil\n\t}\n\t// we don't want to report extensions and we would have hit cache if this isn't the first time\n\tif !strings.HasPrefix(name, \"k6/x/\") {\n\t\terr := mr.usage.Strings(\"modules\", name)\n\t\tif err != nil {\n\t\t\tmr.logger.WithError(err).Warnf(\"Error while reporting usage of module %q\", name)\n\t\t}\n\t}\n\tk6m, ok := mod.(Module)\n\tif !ok {\n\t\treturn &basicGoModule{m: mod}, nil\n\t}\n\treturn &goModule{m: k6m}, nil\n}\n\nfunc isESM(prg *ast.Program) bool {\n\t// NOTE(@mstoykov): this only exists in order for k6 to figure out if code should be tried as CommonJS\n\t// if it has exports, imports or has top-level-await - it must be ESM, if not it can be CommonJS and there\n\t// isn't much of a downside to treat as one, except some corner cases in the tc39 test suite failing.\n\treturn len(prg.ExportEntries) > 0 || len(prg.ImportEntries) > 0 || prg.HasTLA\n}\n\nfunc (mr *ModuleResolver) resolveLoaded(basePWD *url.URL, arg string, data []byte) (sobek.ModuleRecord, error) {\n\tspecifier, err := mr.resolveSpecifier(basePWD, arg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// try cache with the final specifier\n\tif cached, ok := mr.cache[specifier.String()]; ok {\n\t\treturn cached.mod, cached.err\n\t}\n\tprg, _, err := mr.compiler.Parse(string(data), specifier.String(), false, true)\n\n\t// if there is an error an we can try to parse it wrapped as CommonJS\n\t// if it isn't ESM - we *must* wrap it in order to work\n\tif err != nil || !isESM(prg) {\n\t\tvar newError error\n\t\tprg, _, newError = mr.compiler.Parse(string(data), specifier.String(), true, false)\n\t\tif newError == nil || err == nil {\n\t\t\terr = newError\n\t\t}\n\t}\n\tif err != nil {\n\t\tmr.cache[specifier.String()] = moduleCacheElement{err: err}\n\t\treturn nil, err\n\t}\n\tvar mod sobek.ModuleRecord\n\tif isESM(prg) {\n\t\tmod, err = sobek.ModuleFromAST(prg, mr.sobekModuleResolver)\n\t} else {\n\t\tmod, err = cjsModuleFromString(prg)\n\t}\n\tmr.reverse[mod] = specifier\n\tmr.cache[specifier.String()] = moduleCacheElement{mod: mod, err: err}\n\treturn mod, err\n}\n\n// Lock locks the module's resolution from any further new resolving operation.\n// It means that it relays only its internal cache and on the fact that it has already\n// seen previously the module during the initialization.\n// It is the same approach used for opening file operations.\nfunc (mr *ModuleResolver) Lock() {\n\tmr.locked = true\n}\n\ntype vubox struct {\n\tvu VU\n}\n\nfunc (mr *ModuleResolver) resolve(basePWD *url.URL, arg string) (sobek.ModuleRecord, error) {\n\tswitch {\n\tcase arg == \"k6\", strings.HasPrefix(arg, \"k6/\"):\n\t\t// Builtin or external modules (\"k6\", \"k6/*\", or \"k6/x/*\") are handled\n\t\t// specially, as they don't exist on the filesystem.\n\t\tif cached, ok := mr.cache[arg]; ok {\n\t\t\treturn cached.mod, cached.err\n\t\t}\n\t\tmod, err := mr.initializeGoModule(arg)\n\t\tmr.cache[arg] = moduleCacheElement{mod: mod, err: err}\n\t\treturn mod, err\n\tdefault:\n\t\tspecifier, err := mr.resolveSpecifier(basePWD, arg)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// try cache with the final specifier\n\t\tif cached, ok := mr.cache[specifier.String()]; ok {\n\t\t\treturn cached.mod, cached.err\n\t\t}\n\n\t\tif mr.locked {\n\t\t\treturn nil, fmt.Errorf(notPreviouslyResolvedModule, arg)\n\t\t}\n\t\t// Fall back to loading\n\t\tdata, err := mr.loadCJS(specifier, arg)\n\t\tif err != nil {\n\t\t\tmr.cache[specifier.String()] = moduleCacheElement{err: err}\n\t\t\treturn nil, err\n\t\t}\n\t\treturn mr.resolveLoaded(basePWD, arg, data)\n\t}\n}\n\n// Imported returns the list of imported and resolved modules.\n// Each string represents the path as used for importing.\nfunc (mr *ModuleResolver) Imported() []string {\n\tif len(mr.cache) < 1 {\n\t\treturn nil\n\t}\n\tmodules := make([]string, 0, len(mr.cache))\n\tfor name := range mr.cache {\n\t\tmodules = append(modules, name)\n\t}\n\treturn modules\n}\n\nfunc (mr *ModuleResolver) sobekModuleResolver(\n\treferencingScriptOrModule any, specifier string,\n) (sobek.ModuleRecord, error) {\n\treturn mr.resolve(mr.reversePath(referencingScriptOrModule), specifier)\n}\n\nfunc (mr *ModuleResolver) reversePath(referencingScriptOrModule any) *url.URL {\n\tp, ok := mr.reverse[referencingScriptOrModule]\n\tif !ok {\n\t\tif referencingScriptOrModule != nil {\n\t\t\tpanic(\"fix this\")\n\t\t}\n\t\treturn mr.base\n\t}\n\n\tif p.String() == \"file:///-\" {\n\t\treturn mr.base\n\t}\n\treturn p.JoinPath(\"..\")\n}\n\n// LoadMainModule loads a main module and resolves all it dependencies checking for any linking issues.\n// It does not run any javascript code, just compiling it and resolving module dependencies.\nfunc (mr *ModuleResolver) LoadMainModule(pwd *url.URL, specifier string, data []byte) error {\n\tif _, err := mr.resolveLoaded(pwd, specifier, data); err != nil {\n\t\treturn err\n\t}\n\n\tmod, err := mr.resolve(pwd, specifier)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err = mod.Link(); err != nil {\n\t\treturn err\n\t}\n\t_, ok := mod.(sobek.CyclicModuleRecord)\n\tif !ok {\n\t\tpanic(\"somehow running source data for \" + specifier + \" didn't produce a cyclic module record\")\n\t}\n\n\tif len(mr.unknownModules) > 0 {\n\t\treturn newUnknownModulesError(mr.unknownModules)\n\t}\n\treturn nil\n}\n\n// ModuleSystem is implementing an ESM like module system to resolve js modules for k6 usage\ntype ModuleSystem struct {\n\tvu            VU\n\tinstanceCache map[sobek.ModuleRecord]sobek.ModuleInstance\n\tresolver      *ModuleResolver\n}\n\n// NewModuleSystem returns a new ModuleSystem for the provide VU using the provided resoluter\nfunc NewModuleSystem(resolver *ModuleResolver, vu VU) *ModuleSystem {\n\trt := vu.Runtime()\n\t// TODO:figure out if we can remove this\n\t_ = rt.GlobalObject().DefineDataProperty(\"vubox\",\n\t\trt.ToValue(vubox{vu: vu}), sobek.FLAG_FALSE, sobek.FLAG_FALSE, sobek.FLAG_FALSE)\n\treturn &ModuleSystem{\n\t\tresolver:      resolver,\n\t\tinstanceCache: make(map[sobek.ModuleRecord]sobek.ModuleInstance),\n\t\tvu:            vu,\n\t}\n}\n\n// RunSourceData runs the provided sourceData and adds it to the cache.\n// If a module with the same specifier as the source is already cached\n// it will be used instead of reevaluating the source from the provided SourceData.\nfunc (ms *ModuleSystem) RunSourceData(source *loader.SourceData) (*RunSourceDataResult, error) {\n\tspecifier := source.URL.String()\n\tpwd := source.URL.JoinPath(\"../\")\n\terr := ms.resolver.LoadMainModule(pwd, specifier, source.Data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tmod, err := ms.resolver.resolve(pwd, specifier)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif err = mod.Link(); err != nil {\n\t\treturn nil, err\n\t}\n\tci, ok := mod.(sobek.CyclicModuleRecord)\n\tif !ok {\n\t\tpanic(\"somehow running source data for \" + source.URL.String() + \" didn't produce a cyclic module record\")\n\t}\n\n\trt := ms.vu.Runtime()\n\tpromise := rt.CyclicModuleRecordEvaluate(ci, ms.resolver.sobekModuleResolver)\n\n\tpromisesThenIgnore(rt, promise)\n\n\treturn &RunSourceDataResult{\n\t\tpromise: promise,\n\t\tmod:     mod,\n\t}, nil\n}\n\n// RunSourceDataResult helps with the asynchronous nature of ESM\n// it wraps the promise that is returned from Sobek while at the same time allowing access to the module record\ntype RunSourceDataResult struct {\n\tpromise *sobek.Promise\n\tmod     sobek.ModuleRecord\n}\n\n// Result returns either the underlying module or error if the promise has been completed and true,\n// or false if the promise still hasn't been completed\nfunc (r *RunSourceDataResult) Result() (sobek.ModuleRecord, bool, error) {\n\tswitch r.promise.State() {\n\tcase sobek.PromiseStateRejected:\n\t\treturn nil, true, r.promise.Result().Export().(error) //nolint:forcetypeassert\n\tcase sobek.PromiseStateFulfilled:\n\t\treturn r.mod, true, nil\n\tdefault:\n\t\treturn nil, false, nil\n\t}\n}\n\n// ExportGloballyModule sets all exports of the provided module name on the globalThis.\n// effectively making them globally available\nfunc ExportGloballyModule(rt *sobek.Runtime, modSys *ModuleSystem, moduleName string) {\n\tm, err := modSys.resolver.resolve(nil, moduleName)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\twm, ok := m.(*goModule)\n\tif !ok {\n\t\tpanic(\"trying to globally export stuff that didn't come from go module\")\n\t}\n\tvar gmi *goModuleInstance\n\tgmi, err = modSys.getModuleInstanceFromGoModule(wm)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\texports := gmi.getDefaultExport().ToObject(rt)\n\n\tfor _, key := range exports.Keys() {\n\t\tif err := rt.Set(key, exports.Get(key)); err != nil {\n\t\t\tpanic(fmt.Errorf(\"failed to set '%s' global object: %w\", key, err))\n\t\t}\n\t}\n}\n\n// UnknownModulesError is returned when loading a module was not possbile due to one or more of dependencies\n// that couldn't be resolved.\ntype UnknownModulesError struct {\n\tunknownModules []string\n}\n\nfunc newUnknownModulesError(list []string) UnknownModulesError {\n\tslices.Sort(list)\n\treturn UnknownModulesError{unknownModules: list}\n}\n\nfunc (u UnknownModulesError) Error() string {\n\treturn fmt.Sprintf(\"unknown modules [%s] were tried to be loaded, but couldn't - \"+\n\t\t\"this likely means automatic extension resolution is required or a custom k6 binary with the required extensions\",\n\t\tu.formatList())\n}\n\n// List returns the list of unknown modules that lead to the error\nfunc (u UnknownModulesError) List() []string {\n\treturn slices.Clone(u.unknownModules)\n}\n\nfunc (u UnknownModulesError) formatList() string {\n\tlist := make([]string, len(u.unknownModules))\n\tfor i, m := range u.unknownModules {\n\t\tlist[i] = strconv.Quote(m)\n\t}\n\treturn strings.Join(list, \", \")\n}\n"
  },
  {
    "path": "js/modules/unknown.go",
    "content": "package modules\n\nimport \"github.com/grafana/sobek\"\n\ntype unknownModule struct {\n\tname      string\n\trequested map[string]struct{}\n}\n\nfunc (um *unknownModule) Link() error { return nil }\n\nfunc (um *unknownModule) Evaluate(_ *sobek.Runtime) *sobek.Promise { panic(\"this shouldn't be called\") }\n\nfunc (um *unknownModule) InitializeEnvironment() error { return nil }\n\nfunc (um *unknownModule) Instantiate(_ *sobek.Runtime) (sobek.CyclicModuleInstance, error) {\n\treturn &unknownModuleInstance{module: um}, nil\n}\n\nfunc (um *unknownModule) RequestedModules() []string { return nil }\n\nfunc (um *unknownModule) ResolveExport(name string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) {\n\tum.requested[name] = struct{}{}\n\treturn &sobek.ResolvedBinding{\n\t\tModule:      um,\n\t\tBindingName: name,\n\t}, false\n}\n\nfunc (um *unknownModule) GetExportedNames(_ func([]string), _ ...sobek.ModuleRecord) bool {\n\treturn false\n}\n\ntype unknownModuleInstance struct {\n\tmodule *unknownModule\n}\n\nfunc (umi *unknownModuleInstance) GetBindingValue(_ string) sobek.Value {\n\treturn nil\n}\n\nfunc (umi *unknownModuleInstance) HasTLA() bool { return false }\n\nfunc (umi *unknownModuleInstance) ExecuteModule(_ *sobek.Runtime, _, _ func(any) error,\n) (sobek.CyclicModuleInstance, error) {\n\treturn umi, nil\n}\n"
  },
  {
    "path": "js/modulestest/compile.go",
    "content": "package modulestest\n\nimport (\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\n\t\"github.com/grafana/sobek\"\n)\n\n// CompileFile compiles a JS file as a [*sobek.Program].\n//\n// The base path is used to resolve the file path. The name is the file name.\n//\n// This function facilitates evaluating javascript test files in a [sobek.Runtime] using\n// the [sobek.Runtime.RunProgram] method.\nfunc CompileFile(base, name string) (*sobek.Program, error) {\n\tb, err := os.ReadFile(filepath.Clean(path.Join(base, name))) //nolint:forbidigo\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn sobek.Compile(name, string(b), false)\n}\n"
  },
  {
    "path": "js/modulestest/modulestest.go",
    "content": "package modulestest\n\nimport (\n\t\"context\"\n\n\t\"github.com/grafana/sobek\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n)\n\nvar _ modules.VU = &VU{}\n\n// VU is a modules.VU implementation meant to be used within tests\ntype VU struct {\n\tCtxField              context.Context\n\tInitEnvField          *common.InitEnvironment\n\tEventsField           common.Events\n\tStateField            *lib.State\n\tRuntimeField          *sobek.Runtime\n\tRegisterCallbackField func() func(f func() error)\n}\n\n// Context returns internally set field to conform to modules.VU interface\nfunc (m *VU) Context() context.Context {\n\treturn m.CtxField\n}\n\n// Events returns internally set field to conform to modules.VU interface\nfunc (m *VU) Events() common.Events {\n\treturn m.EventsField\n}\n\n// InitEnv returns internally set field to conform to modules.VU interface\nfunc (m *VU) InitEnv() *common.InitEnvironment {\n\tm.checkIntegrity()\n\treturn m.InitEnvField\n}\n\n// State returns internally set field to conform to modules.VU interface\nfunc (m *VU) State() *lib.State {\n\tm.checkIntegrity()\n\treturn m.StateField\n}\n\n// Runtime returns internally set field to conform to modules.VU interface\nfunc (m *VU) Runtime() *sobek.Runtime {\n\treturn m.RuntimeField\n}\n\n// RegisterCallback is not really implemented\nfunc (m *VU) RegisterCallback() func(f func() error) {\n\treturn m.RegisterCallbackField()\n}\n\nfunc (m *VU) checkIntegrity() {\n\tif m.InitEnvField != nil && m.StateField != nil {\n\t\tpanic(\"there is a bug in the test: InitEnvField and StateField are not allowed at the same time\")\n\t}\n}\n"
  },
  {
    "path": "js/modulestest/runtime.go",
    "content": "// Package modulestest contains helpers to test js modules\npackage modulestest\n\nimport (\n\t\"context\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/grafana/sobek\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/internal/js/compiler\"\n\t\"go.k6.io/k6/internal/js/eventloop\"\n\t\"go.k6.io/k6/internal/js/tc55/timers\"\n\n\t\"go.k6.io/k6/internal/js/modules/k6/webcrypto\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/js/common\"\n\t\"go.k6.io/k6/js/modules\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// Runtime is a helper struct that contains what is needed to run a (simple) module test\ntype Runtime struct {\n\tVU             *VU\n\tEventLoop      *eventloop.EventLoop\n\tCancelContext  func()\n\tBuiltinMetrics *metrics.BuiltinMetrics\n\n\tmr *modules.ModuleResolver\n}\n\n// NewRuntime will create a new test runtime and will cancel the context on test/benchmark end\nfunc NewRuntime(t testing.TB) *Runtime {\n\tctx, cancel := context.WithCancel(context.Background())\n\tt.Cleanup(cancel)\n\tvu := &VU{\n\t\tCtxField:     ctx,\n\t\tRuntimeField: sobek.New(),\n\t}\n\tvu.RuntimeField.SetFieldNameMapper(common.FieldNameMapper{})\n\tvu.InitEnvField = &common.InitEnvironment{\n\t\tTestPreInitState: &lib.TestPreInitState{\n\t\t\tLogger:   testutils.NewLogger(t),\n\t\t\tRegistry: metrics.NewRegistry(),\n\t\t\tUsage:    usage.New(),\n\t\t},\n\t\tCWD: new(url.URL),\n\t}\n\n\teventloop := eventloop.New(vu)\n\tvu.RegisterCallbackField = eventloop.RegisterCallback\n\tresult := &Runtime{\n\t\tVU:             vu,\n\t\tEventLoop:      eventloop,\n\t\tCancelContext:  cancel,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(vu.InitEnvField.Registry),\n\t}\n\trequire.NoError(t, timers.SetupGlobally(vu))\n\trequire.NoError(t, webcrypto.SetupGlobally(vu))\n\t// let's cancel again in case it has changed\n\tt.Cleanup(func() { result.CancelContext() })\n\treturn result\n}\n\n// MoveToVUContext will set the state and nil the InitEnv just as a real VU\nfunc (r *Runtime) MoveToVUContext(state *lib.State) {\n\tr.VU.InitEnvField = nil\n\tr.VU.StateField = state\n}\n\n// SetupModuleSystem sets up the modules system for the Runtime.\n// See [modules.NewModuleResolver] for the meaning of the parameters.\nfunc (r *Runtime) SetupModuleSystem(goModules map[string]any, loader modules.FileLoader, c *compiler.Compiler) error {\n\tif goModules == nil {\n\t\tgoModules = make(map[string]any)\n\t}\n\n\tr.mr = modules.NewModuleResolver(\n\t\tgoModules, loader, c, r.VU.InitEnvField.CWD, r.VU.InitEnvField.Usage, r.VU.InitEnvField.Logger)\n\treturn r.innerSetupModuleSystem()\n}\n\n// SetupModuleSystemFromAnother sets up the modules system for the Runtime by using the resolver of another runtime.\nfunc (r *Runtime) SetupModuleSystemFromAnother(another *Runtime) error {\n\tr.mr = another.mr\n\treturn r.innerSetupModuleSystem()\n}\n\n// RunOnEventLoop will run the given code on the event loop.\n//\n// It is meant as a helper to test code that is expected to be run on the event loop, such\n// as code that returns a promise.\n//\n// A typical usage is to facilitate writing tests for asynchrounous code:\n//\n//\tfunc TestSomething(t *testing.T) {\n//\t    runtime := modulestest.NewRuntime(t)\n//\n//\t    err := runtime.RunOnEventLoop(`\n//\t        doSomethingAsync().then(() => {\n//\t            // do some assertions\n//\t        });\n//\t    `)\n//\t    require.NoError(t, err)\n//\t}\nfunc (r *Runtime) RunOnEventLoop(code string) (value sobek.Value, err error) {\n\tdefer r.EventLoop.WaitOnRegistered()\n\n\terr = r.EventLoop.Start(func() error {\n\t\tvalue, err = r.VU.Runtime().RunString(code)\n\t\treturn err\n\t})\n\n\treturn value, err\n}\n\nfunc (r *Runtime) innerSetupModuleSystem() error {\n\tms := modules.NewModuleSystem(r.mr, r.VU)\n\treturn r.VU.RuntimeField.Set(\"require\", ms.Require)\n}\n"
  },
  {
    "path": "js/promises/promises.go",
    "content": "// Package promises provides helpers for working with promises in k6.\npackage promises\n\nimport (\n\t\"github.com/grafana/sobek\"\n\n\t\"go.k6.io/k6/js/modules\"\n)\n\n// New can be used to create promises that will be dispatched to k6's event loop.\n//\n// Calling the function will create a Sobek promise and return its `resolve` and `reject` callbacks, wrapped\n// in such a way that it will block the k6 JavaScript runtime's event loop from exiting before they are\n// called, even if the promise isn't resolved by the time the current script ends executing.\n//\n// A typical usage would be:\n//\n//\t   func myAsynchronousFunc(vu modules.VU) *(sobek.Promise) {\n//\t\t    promise, resolve, reject := promises.New(vu)\n//\t\t    go func() {\n//\t\t        v, err := someAsyncFunc()\n//\t\t\t\t   if err != nil {\n//\t\t            reject(err)\n//\t\t            return\n//\t\t        }\n//\n//\t\t        resolve(v)\n//\t\t    }()\n//\t\t    return promise\n//\t\t  }\nfunc New(vu modules.VU) (p *sobek.Promise, resolve func(result any), reject func(reason any)) {\n\tp, resolveFunc, rejectFunc := vu.Runtime().NewPromise()\n\tcallback := vu.RegisterCallback()\n\n\tresolve = func(result any) {\n\t\tcallback(func() error {\n\t\t\treturn resolveFunc(result)\n\t\t})\n\t}\n\n\treject = func(reason any) {\n\t\tcallback(func() error {\n\t\t\treturn rejectFunc(reason)\n\t\t})\n\t}\n\n\treturn p, resolve, reject\n}\n"
  },
  {
    "path": "js/promises/promises_test.go",
    "content": "package promises\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/js/modulestest\"\n)\n\nfunc TestNew(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"should resolve\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime := modulestest.NewRuntime(t)\n\t\terr := runtime.EventLoop.Start(func() error {\n\t\t\tpromise, resolve, _ := New(runtime.VU)\n\t\t\terr := runtime.VU.Runtime().Set(\"promise\", promise)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = runtime.VU.Runtime().RunString(`\n\t\t\t\tpromise\n\t\t\t\t\t.then(\n\t\t\t\t\t\tres => { if (res !== \"resolved\") { throw \"unexpected promise resolution with result: \" + res } },\n\t\t\t\t\t\terr => { throw \"unexpected error: \" + err },\n\t\t\t\t\t)\n\t\t\t`)\n\t\t\tgo func() {\n\t\t\t\tresolve(\"resolved\")\n\t\t\t}()\n\n\t\t\treturn err\n\t\t})\n\n\t\tassert.NoError(t, err)\n\t})\n\n\tt.Run(\"should reject\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\truntime := modulestest.NewRuntime(t)\n\t\terr := runtime.EventLoop.Start(func() error {\n\t\t\tpromise, _, reject := New(runtime.VU)\n\t\t\terr := runtime.VU.Runtime().Set(\"promise\", promise)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = runtime.VU.Runtime().RunString(`\n\t\t\t\tpromise\n\t\t\t\t\t.then(\n\t\t\t\t\t\tres => { throw \"unexpected promise resolution with result: \" + res },\n\t\t\t\t\t\terr => { if (err !== \"rejected\") { throw \"unexpected error: \" + err } },\n\t\t\t\t\t)\n\t\t\t`)\n\t\t\tgo func() {\n\t\t\t\treject(\"rejected\")\n\t\t\t}()\n\n\t\t\treturn err\n\t\t})\n\n\t\tassert.NoError(t, err)\n\t})\n}\n"
  },
  {
    "path": "lib/archive.go",
    "content": "package lib\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/url\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/loader\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nvar (\n\tvolumeRE = regexp.MustCompile(`^[/\\\\]?([a-zA-Z]):(.*)`)\n\t// matches a shared folder in Windows before backslack replacement. i.e \\\\VMBOXSVR\\k6\\script.js\n\tsharedRE  = regexp.MustCompile(`^\\\\\\\\([^\\\\]+)`)\n\thomeDirRE = regexp.MustCompile(`(?i)^(/[a-zA-Z])?/(Users|home|Documents and Settings)/(?:[^/]+)`)\n)\n\n// NormalizeAndAnonymizePath Normalizes (to use a / path separator) and anonymizes a file path,\n// by scrubbing usernames from home directories.\nfunc NormalizeAndAnonymizePath(path string) string {\n\tpath = filepath.Clean(path)\n\n\tp := volumeRE.ReplaceAllString(path, `/$1$2`)\n\tp = sharedRE.ReplaceAllString(p, `/nobody`)\n\tp = strings.ReplaceAll(p, \"\\\\\", \"/\")\n\treturn homeDirRE.ReplaceAllString(p, `$1/$2/nobody`)\n}\n\nfunc newNormalizedFs(fs fsext.Fs) fsext.Fs {\n\treturn fsext.NewChangePathFs(fs, fsext.ChangePathFunc(func(name string) (string, error) {\n\t\treturn NormalizeAndAnonymizePath(name), nil\n\t}))\n}\n\n// An Archive is a rollup of all resources and options needed to reproduce a test identically elsewhere.\ntype Archive struct {\n\t// The runner to use, eg. \"js\".\n\tType string `json:\"type\"`\n\n\t// Options to use.\n\tOptions Options `json:\"options\"`\n\n\t// TODO: rewrite the encoding, decoding of json to use another type with only the fields it\n\t// needs in order to remove Filename and Pwd from this\n\t// Filename and contents of the main file being executed.\n\tFilename    string   `json:\"filename\"` // only for json\n\tFilenameURL *url.URL `json:\"-\"`\n\tData        []byte   `json:\"-\"`\n\n\t// Working directory for resolving relative paths.\n\tPwd    string   `json:\"pwd\"` //nolint:gosec // only for json\n\tPwdURL *url.URL `json:\"-\"`\n\n\tFilesystems map[string]fsext.Fs `json:\"-\"`\n\n\t// Environment variables\n\tEnv map[string]string `json:\"env\"`\n\n\tCompatibilityMode string `json:\"compatibilityMode\"`\n\n\tK6Version string `json:\"k6version\"`\n\tGoos      string `json:\"goos\"`\n}\n\nfunc (arc *Archive) getFs(name string) fsext.Fs {\n\tfs, ok := arc.Filesystems[name]\n\tif !ok {\n\t\tfs = fsext.NewMemMapFs()\n\t\tif name == \"file\" {\n\t\t\tfs = newNormalizedFs(fs)\n\t\t}\n\t\tarc.Filesystems[name] = fs\n\t}\n\n\treturn fs\n}\n\nfunc (arc *Archive) loadMetadataJSON(data []byte) (err error) {\n\tif err = json.Unmarshal(data, &arc); err != nil {\n\t\treturn err\n\t}\n\t// Path separator normalization for older archives (<=0.20.0)\n\tif arc.K6Version == \"\" {\n\t\tarc.Filename = NormalizeAndAnonymizePath(arc.Filename)\n\t\tarc.Pwd = NormalizeAndAnonymizePath(arc.Pwd)\n\t}\n\tarc.PwdURL, err = loader.Resolve(&url.URL{Scheme: \"file\", Path: \"/\"}, arc.Pwd)\n\tif err != nil {\n\t\treturn err\n\t}\n\tarc.FilenameURL, err = loader.Resolve(&url.URL{Scheme: \"file\", Path: \"/\"}, arc.Filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// ReadArchive reads an archive created by Archive.Write from a reader.\n//\n//nolint:gocognit\nfunc ReadArchive(in io.Reader) (*Archive, error) {\n\tr := tar.NewReader(in)\n\tarc := &Archive{Filesystems: make(map[string]fsext.Fs, 2)}\n\t// initialize both fses\n\t_ = arc.getFs(\"https\")\n\t_ = arc.getFs(\"file\")\n\tfor {\n\t\thdr, err := r.Next()\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.EOF) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\tif hdr.Typeflag != tar.TypeReg && hdr.Typeflag != tar.TypeRegA { //nolint:staticcheck\n\t\t\tcontinue\n\t\t}\n\n\t\tdata, err := io.ReadAll(r)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tswitch hdr.Name {\n\t\tcase \"metadata.json\":\n\t\t\tif err = arc.loadMetadataJSON(data); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tcontinue\n\t\tcase \"data\":\n\t\t\tarc.Data = data\n\t\t\tcontinue\n\t\t}\n\n\t\t// Path separator normalization for older archives (<=0.20.0)\n\t\tnormPath := NormalizeAndAnonymizePath(hdr.Name)\n\t\tidx := strings.IndexRune(normPath, '/')\n\t\tif idx == -1 {\n\t\t\tcontinue\n\t\t}\n\t\tpfx := normPath[:idx]\n\t\tname := normPath[idx:]\n\n\t\tswitch pfx {\n\t\tcase \"files\", \"scripts\": // old archives\n\t\t\t// in old archives (pre 0.25.0) names without \"_\" at the beginning were  https, the ones with \"_\" are local files\n\t\t\tpfx = \"https\"\n\t\t\tif len(name) >= 2 && name[0:2] == \"/_\" {\n\t\t\t\tpfx = \"file\"\n\t\t\t\tname = name[2:]\n\t\t\t}\n\t\t\tfallthrough\n\t\tcase \"https\", \"file\":\n\t\t\tfileSystem := arc.getFs(pfx)\n\t\t\tname = filepath.FromSlash(name)\n\t\t\tif err = fsext.WriteFile(fileSystem, name, data, fs.FileMode(hdr.Mode)); err != nil { //nolint:gosec\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif err = fileSystem.Chtimes(name, hdr.AccessTime, hdr.ModTime); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unknown file prefix `%s` for file `%s`\", pfx, normPath)\n\t\t}\n\t}\n\tscheme, pathOnFs := getURLPathOnFs(arc.FilenameURL)\n\tvar err error\n\tpathOnFs, err = url.PathUnescape(pathOnFs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = fsext.WriteFile(arc.getFs(scheme), pathOnFs, arc.Data, 0o644) // TODO fix the mode ?\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn arc, nil\n}\n\nfunc normalizeAndAnonymizeURL(u *url.URL) {\n\tif u.Scheme == \"file\" {\n\t\tu.Path = NormalizeAndAnonymizePath(u.Path)\n\t}\n}\n\nfunc getURLPathOnFs(u *url.URL) (scheme string, pathOnFs string) {\n\tscheme = \"https\"\n\tswitch {\n\tcase u.Opaque != \"\":\n\t\treturn scheme, \"/\" + u.Opaque\n\tcase u.Scheme == \"\":\n\t\treturn scheme, path.Clean(u.String()[len(\"//\"):])\n\tdefault:\n\t\tscheme = u.Scheme\n\t}\n\treturn scheme, path.Clean(u.String()[len(u.Scheme)+len(\":/\"):])\n}\n\nfunc getURLtoString(u *url.URL) string {\n\tif u.Opaque == \"\" && u.Scheme == \"\" {\n\t\treturn u.String()[len(\"//\"):] // https url without a scheme\n\t}\n\treturn u.String()\n}\n\n// Write serialises the archive to a writer.\n//\n// The format should be treated as opaque; currently it is simply a TAR rollup, but this may\n// change. If it does change, ReadArchive must be able to handle all previous formats as well as\n// the current one.\n//\n//nolint:funlen,gocognit\nfunc (arc *Archive) Write(out io.Writer) error {\n\tw := tar.NewWriter(out)\n\n\tnow := time.Now()\n\tmetaArc := *arc\n\tnormalizeAndAnonymizeURL(metaArc.FilenameURL)\n\tnormalizeAndAnonymizeURL(metaArc.PwdURL)\n\tmetaArc.Filename = getURLtoString(metaArc.FilenameURL)\n\tmetaArc.Pwd = getURLtoString(metaArc.PwdURL)\n\tactualDataPath, err := url.PathUnescape(path.Join(getURLPathOnFs(metaArc.FilenameURL)))\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar madeLinkToData bool\n\tmetadata, err := metaArc.json()\n\tif err != nil {\n\t\treturn err\n\t}\n\t_ = w.WriteHeader(&tar.Header{\n\t\tName:     \"metadata.json\",\n\t\tMode:     0o644,\n\t\tSize:     int64(len(metadata)),\n\t\tModTime:  now,\n\t\tTypeflag: tar.TypeReg,\n\t})\n\tif _, err = w.Write(metadata); err != nil {\n\t\treturn err\n\t}\n\n\t_ = w.WriteHeader(&tar.Header{\n\t\tName:     \"data\",\n\t\tMode:     0o644,\n\t\tSize:     int64(len(arc.Data)),\n\t\tModTime:  now,\n\t\tTypeflag: tar.TypeReg,\n\t})\n\tif _, err = w.Write(arc.Data); err != nil {\n\t\treturn err\n\t}\n\tfor _, name := range [...]string{\"file\", \"https\"} {\n\t\tfilesystem, ok := arc.Filesystems[name]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif cachedfs, ok := filesystem.(fsext.CacheLayerGetter); ok {\n\t\t\tfilesystem = cachedfs.GetCachingFs()\n\t\t}\n\n\t\t// A couple of things going on here:\n\t\t// - You can't just create file entries, you need to create directory entries too.\n\t\t//   Figure out which directories are in use here.\n\t\t// - We want archives to be comparable by hash, which means the entries need to be written\n\t\t//   in the same order every time. Go maps are shuffled, so we need to sort lists of keys.\n\t\t// - We don't want to leak private information (eg. usernames) in archives, so make sure to\n\t\t//   anonymize paths before stuffing them in a shareable archive.\n\t\tfoundDirs := make(map[string]bool)\n\t\tpaths := make([]string, 0, 10)\n\t\tinfos := make(map[string]fs.FileInfo) // ... fix this ?\n\t\tfiles := make(map[string][]byte)\n\n\t\twalkFunc := filepath.WalkFunc(func(filePath string, info fs.FileInfo, err error) error {\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tnormalizedPath := NormalizeAndAnonymizePath(filePath)\n\n\t\t\tinfos[normalizedPath] = info\n\t\t\tif info.IsDir() {\n\t\t\t\tfoundDirs[normalizedPath] = true\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tpaths = append(paths, normalizedPath)\n\t\t\tfiles[normalizedPath], err = fsext.ReadFile(filesystem, filePath)\n\t\t\treturn err\n\t\t})\n\n\t\tif err = fsext.Walk(filesystem, fsext.FilePathSeparator, walkFunc); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif len(files) == 0 {\n\t\t\tcontinue // we don't need to write anything for this fs, if this is not done the root will be written\n\t\t}\n\t\tdirs := make([]string, 0, len(foundDirs))\n\t\tfor dirpath := range foundDirs {\n\t\t\tdirs = append(dirs, dirpath)\n\t\t}\n\t\tsort.Strings(paths)\n\t\tsort.Strings(dirs)\n\n\t\tfor _, dirPath := range dirs {\n\t\t\t_ = w.WriteHeader(&tar.Header{\n\t\t\t\tName:       path.Clean(path.Join(name, dirPath)),\n\t\t\t\tMode:       0o755, // MemMapFs is buggy\n\t\t\t\tAccessTime: now,   // MemMapFs is buggy\n\t\t\t\tChangeTime: now,   // MemMapFs is buggy\n\t\t\t\tModTime:    now,   // MemMapFs is buggy\n\t\t\t\tTypeflag:   tar.TypeDir,\n\t\t\t})\n\t\t}\n\n\t\tfor _, filePath := range paths {\n\t\t\tfullFilePath := path.Clean(path.Join(name, filePath))\n\t\t\t// we either have opaque\n\t\t\tif fullFilePath == actualDataPath {\n\t\t\t\tmadeLinkToData = true\n\t\t\t\terr = w.WriteHeader(&tar.Header{\n\t\t\t\t\tName:     fullFilePath,\n\t\t\t\t\tSize:     0,\n\t\t\t\t\tTypeflag: tar.TypeLink,\n\t\t\t\t\tLinkname: \"data\",\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\terr = w.WriteHeader(&tar.Header{\n\t\t\t\t\tName:       fullFilePath,\n\t\t\t\t\tMode:       0o644, // MemMapFs is buggy\n\t\t\t\t\tSize:       int64(len(files[filePath])),\n\t\t\t\t\tAccessTime: infos[filePath].ModTime(),\n\t\t\t\t\tChangeTime: infos[filePath].ModTime(),\n\t\t\t\t\tModTime:    infos[filePath].ModTime(),\n\t\t\t\t\tTypeflag:   tar.TypeReg,\n\t\t\t\t})\n\t\t\t\tif err == nil {\n\t\t\t\t\t_, err = w.Write(files[filePath])\n\t\t\t\t}\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif !madeLinkToData {\n\t\t// This should never happen we should always link to `data` from inside the file/https directories\n\t\treturn fmt.Errorf(\"archive creation failed because the main script wasn't present in the cached filesystem\")\n\t}\n\n\treturn w.Close()\n}\n\nfunc (arc *Archive) json() ([]byte, error) {\n\tbuffer := &bytes.Buffer{}\n\tencoder := json.NewEncoder(buffer)\n\t// this prevents <, >, and & from being escaped in JSON strings\n\tencoder.SetEscapeHTML(false)\n\tencoder.SetIndent(\"\", \"  \")\n\tif err := encoder.Encode(arc); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn buffer.Bytes(), nil\n}\n"
  },
  {
    "path": "lib/archive_test.go",
    "content": "package lib\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net/url\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestNormalizeAndAnonymizePath(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]string{\n\t\t\"/tmp\":                            \"/tmp\",\n\t\t\"/tmp/myfile.txt\":                 \"/tmp/myfile.txt\",\n\t\t\"/home/myname\":                    \"/home/nobody\",\n\t\t\"/home/myname/foo/bar/myfile.txt\": \"/home/nobody/foo/bar/myfile.txt\",\n\t\t\"/Users/myname/myfile.txt\":        \"/Users/nobody/myfile.txt\",\n\t\t\"/Documents and Settings/myname/myfile.txt\":           \"/Documents and Settings/nobody/myfile.txt\",\n\t\t\"\\\\\\\\MYSHARED\\\\dir\\\\dir\\\\myfile.txt\":                  \"/nobody/dir/dir/myfile.txt\",\n\t\t\"\\\\NOTSHARED\\\\dir\\\\dir\\\\myfile.txt\":                   \"/NOTSHARED/dir/dir/myfile.txt\",\n\t\t\"C:\\\\Users\\\\myname\\\\dir\\\\myfile.txt\":                  \"/C/Users/nobody/dir/myfile.txt\",\n\t\t\"D:\\\\Documents and Settings\\\\myname\\\\dir\\\\myfile.txt\": \"/D/Documents and Settings/nobody/dir/myfile.txt\",\n\t\t\"C:\\\\uSers\\\\myname\\\\dir\\\\myfile.txt\":                  \"/C/uSers/nobody/dir/myfile.txt\",\n\t\t\"D:\\\\doCUMENts aND Settings\\\\myname\\\\dir\\\\myfile.txt\": \"/D/doCUMENts aND Settings/nobody/dir/myfile.txt\",\n\t}\n\t// TODO: fix this - the issue is that filepath.Clean replaces `/` with whatever the path\n\t// separator is on the current OS and as such this gets confused for shared folder on\n\t// windows :( https://github.com/golang/go/issues/16111\n\tif runtime.GOOS != \"windows\" {\n\t\ttestdata[\"//etc/hosts\"] = \"/etc/hosts\"\n\t}\n\tfor from, to := range testdata {\n\t\tt.Run(\"path=\"+from, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tres := NormalizeAndAnonymizePath(from)\n\t\t\tassert.Equal(t, to, res)\n\t\t\tassert.Equal(t, res, NormalizeAndAnonymizePath(res))\n\t\t})\n\t}\n}\n\nfunc getMapKeys(m map[string]fsext.Fs) []string {\n\tkeys := make([]string, 0, len(m))\n\tfor key := range m {\n\t\tkeys = append(keys, key)\n\t}\n\n\treturn keys\n}\n\nfunc diffMapFilesystems(t *testing.T, first, second map[string]fsext.Fs) {\n\trequire.ElementsMatch(t, getMapKeys(first), getMapKeys(second),\n\t\t\"fs map keys don't match %s, %s\", getMapKeys(first), getMapKeys(second))\n\tfor key, fs := range first {\n\t\tsecondFs := second[key]\n\t\tdiffFilesystems(t, fs, secondFs)\n\t}\n}\n\nfunc diffFilesystems(t *testing.T, first, second fsext.Fs) {\n\tdiffFilesystemsDir(t, first, second, \"/\")\n}\n\nfunc getInfoNames(infos []fs.FileInfo) []string {\n\tnames := make([]string, len(infos))\n\tfor i, info := range infos {\n\t\tnames[i] = info.Name()\n\t}\n\treturn names\n}\n\nfunc diffFilesystemsDir(t *testing.T, first, second fsext.Fs, dirname string) {\n\tfirstInfos, err := fsext.ReadDir(first, dirname)\n\trequire.NoError(t, err, dirname)\n\n\tsecondInfos, err := fsext.ReadDir(first, dirname)\n\trequire.NoError(t, err, dirname)\n\n\trequire.ElementsMatch(t, getInfoNames(firstInfos), getInfoNames(secondInfos), \"directory: \"+dirname)\n\tfor _, info := range firstInfos {\n\t\tpath := fsext.JoinFilePath(dirname, info.Name())\n\t\tif info.IsDir() {\n\t\t\tdiffFilesystemsDir(t, first, second, path)\n\t\t\tcontinue\n\t\t}\n\t\tfirstData, err := fsext.ReadFile(first, path)\n\t\trequire.NoError(t, err, path)\n\n\t\tsecondData, err := fsext.ReadFile(second, path)\n\t\trequire.NoError(t, err, path)\n\n\t\tassert.Equal(t, firstData, secondData, path)\n\t}\n}\n\nfunc TestArchiveReadWrite(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Roundtrip\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tarc1 := &Archive{\n\t\t\tType:      \"js\",\n\t\t\tK6Version: build.Version,\n\t\t\tOptions: Options{\n\t\t\t\tVUs:        null.IntFrom(12345),\n\t\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t\t},\n\t\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/path/to/a.js\"},\n\t\t\tData:        []byte(`// a contents`),\n\t\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/path/to\"},\n\t\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\t\"file\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\"/path/to/a.js\":      []byte(`// a contents`),\n\t\t\t\t\t\"/path/to/b.js\":      []byte(`// b contents`),\n\t\t\t\t\t\"/path/to/file1.txt\": []byte(`hi!`),\n\t\t\t\t\t\"/path/to/file2.txt\": []byte(`bye!`),\n\t\t\t\t}),\n\t\t\t\t\"https\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\"/cdnjs.com/libraries/Faker\":          []byte(`// faker contents`),\n\t\t\t\t\t\"/github.com/loadimpact/k6/README.md\": []byte(`README`),\n\t\t\t\t}),\n\t\t\t},\n\t\t}\n\n\t\tbuf := bytes.NewBuffer(nil)\n\t\trequire.NoError(t, arc1.Write(buf))\n\n\t\tarc1Filesystems := arc1.Filesystems\n\t\tarc1.Filesystems = nil\n\n\t\tarc2, err := ReadArchive(buf)\n\t\trequire.NoError(t, err)\n\n\t\tarc2Filesystems := arc2.Filesystems\n\t\tarc2.Filesystems = nil\n\t\tarc2.Filename = \"\"\n\t\tarc2.Pwd = \"\"\n\n\t\tassert.Equal(t, arc1, arc2)\n\n\t\tdiffMapFilesystems(t, arc1Filesystems, arc2Filesystems)\n\t})\n\n\tt.Run(\"Anonymized\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestdata := []struct {\n\t\t\tPwd, PwdNormAnon string\n\t\t}{\n\t\t\t{\"/home/myname\", \"/home/nobody\"},\n\t\t\t{filepath.FromSlash(\"/C:/Users/Administrator\"), \"/C/Users/nobody\"},\n\t\t}\n\t\tfor _, entry := range testdata {\n\t\t\tarc1 := &Archive{\n\t\t\t\tType: \"js\",\n\t\t\t\tOptions: Options{\n\t\t\t\t\tVUs:        null.IntFrom(12345),\n\t\t\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t\t\t},\n\t\t\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: fmt.Sprintf(\"%s/a.js\", entry.Pwd)},\n\t\t\t\tK6Version:   build.Version,\n\t\t\t\tData:        []byte(`// a contents`),\n\t\t\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: entry.Pwd},\n\t\t\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\t\t\"file\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\tfmt.Sprintf(\"%s/a.js\", entry.Pwd):      []byte(`// a contents`),\n\t\t\t\t\t\tfmt.Sprintf(\"%s/b.js\", entry.Pwd):      []byte(`// b contents`),\n\t\t\t\t\t\tfmt.Sprintf(\"%s/file1.txt\", entry.Pwd): []byte(`hi!`),\n\t\t\t\t\t\tfmt.Sprintf(\"%s/file2.txt\", entry.Pwd): []byte(`bye!`),\n\t\t\t\t\t}),\n\t\t\t\t\t\"https\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\t\"/cdnjs.com/libraries/Faker\":          []byte(`// faker contents`),\n\t\t\t\t\t\t\"/github.com/loadimpact/k6/README.md\": []byte(`README`),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t}\n\t\t\tarc1Anon := &Archive{\n\t\t\t\tType: \"js\",\n\t\t\t\tOptions: Options{\n\t\t\t\t\tVUs:        null.IntFrom(12345),\n\t\t\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t\t\t},\n\t\t\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: fmt.Sprintf(\"%s/a.js\", entry.PwdNormAnon)},\n\t\t\t\tK6Version:   build.Version,\n\t\t\t\tData:        []byte(`// a contents`),\n\t\t\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: entry.PwdNormAnon},\n\n\t\t\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\t\t\"file\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\tfmt.Sprintf(\"%s/a.js\", entry.PwdNormAnon):      []byte(`// a contents`),\n\t\t\t\t\t\tfmt.Sprintf(\"%s/b.js\", entry.PwdNormAnon):      []byte(`// b contents`),\n\t\t\t\t\t\tfmt.Sprintf(\"%s/file1.txt\", entry.PwdNormAnon): []byte(`hi!`),\n\t\t\t\t\t\tfmt.Sprintf(\"%s/file2.txt\", entry.PwdNormAnon): []byte(`bye!`),\n\t\t\t\t\t}),\n\t\t\t\t\t\"https\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\t\"/cdnjs.com/libraries/Faker\":          []byte(`// faker contents`),\n\t\t\t\t\t\t\"/github.com/loadimpact/k6/README.md\": []byte(`README`),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tbuf := bytes.NewBuffer(nil)\n\t\t\trequire.NoError(t, arc1.Write(buf))\n\n\t\t\tarc1Filesystems := arc1Anon.Filesystems\n\t\t\tarc1Anon.Filesystems = nil\n\n\t\t\tarc2, err := ReadArchive(buf)\n\t\t\tassert.NoError(t, err)\n\t\t\tarc2.Filename = \"\"\n\t\t\tarc2.Pwd = \"\"\n\n\t\t\tarc2Filesystems := arc2.Filesystems\n\t\t\tarc2.Filesystems = nil\n\n\t\t\tassert.Equal(t, arc1Anon, arc2)\n\t\t\tdiffMapFilesystems(t, arc1Filesystems, arc2Filesystems)\n\t\t}\n\t})\n}\n\nfunc TestArchiveJSONEscape(t *testing.T) {\n\tt.Parallel()\n\n\tarc := &Archive{}\n\tarc.Filename = \"test<.js\"\n\tb, err := arc.json()\n\tassert.NoError(t, err)\n\tassert.Contains(t, string(b), \"test<.js\")\n}\n\nfunc TestUsingCacheFromCacheOnReadFs(t *testing.T) {\n\tt.Parallel()\n\tbase := fsext.NewMemMapFs()\n\tcached := fsext.NewMemMapFs()\n\t// we specifically have different contents in both places\n\trequire.NoError(t, fsext.WriteFile(base, \"/wrong\", []byte(`ooops`), 0o644))\n\trequire.NoError(t, fsext.WriteFile(cached, \"/correct\", []byte(`test`), 0o644))\n\n\tarc := &Archive{\n\t\tType:        \"js\",\n\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/correct\"},\n\t\tK6Version:   build.Version,\n\t\tData:        []byte(`test`),\n\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/\"},\n\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\"file\": fsext.NewCacheOnReadFs(base, cached, 0),\n\t\t},\n\t}\n\n\tbuf := bytes.NewBuffer(nil)\n\trequire.NoError(t, arc.Write(buf))\n\n\tnewArc, err := ReadArchive(buf)\n\trequire.NoError(t, err)\n\n\tdata, err := fsext.ReadFile(newArc.Filesystems[\"file\"], \"/correct\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"test\", string(data))\n\n\tdata, err = fsext.ReadFile(newArc.Filesystems[\"file\"], \"/wrong\")\n\trequire.Error(t, err)\n\trequire.Nil(t, data)\n}\n\nfunc TestArchiveWithDataNotInFS(t *testing.T) {\n\tt.Parallel()\n\n\tarc := &Archive{\n\t\tType:        \"js\",\n\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/script\"},\n\t\tK6Version:   build.Version,\n\t\tData:        []byte(`test`),\n\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/\"},\n\t\tFilesystems: nil,\n\t}\n\n\tbuf := bytes.NewBuffer(nil)\n\terr := arc.Write(buf)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"the main script wasn't present in the cached filesystem\")\n}\n\nfunc TestMalformedMetadata(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\trequire.NoError(t, fsext.WriteFile(fs, \"/metadata.json\", []byte(\"{,}\"), 0o644))\n\tb, err := dumpMemMapFsToBuf(fs)\n\trequire.NoError(t, err)\n\t_, err = ReadArchive(b)\n\trequire.Error(t, err)\n\trequire.EqualError(t, err, `invalid character ',' looking for beginning of object key string`)\n}\n\nfunc TestStrangePaths(t *testing.T) {\n\tt.Parallel()\n\tpathsToChange := []string{\n\t\t`/path/with spaces/a.js`,\n\t\t`/path/with spaces/a.js`,\n\t\t`/path/with日本語/b.js`,\n\t\t`/path/with spaces and 日本語/file1.txt`,\n\t}\n\tfor _, pathToChange := range pathsToChange {\n\t\totherMap := make(map[string][]byte, len(pathsToChange))\n\t\tfor _, other := range pathsToChange {\n\t\t\totherMap[other] = []byte(`// ` + other + ` contents`)\n\t\t}\n\t\tarc1 := &Archive{\n\t\t\tType:      \"js\",\n\t\t\tK6Version: build.Version,\n\t\t\tOptions: Options{\n\t\t\t\tVUs:        null.IntFrom(12345),\n\t\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t\t},\n\t\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: pathToChange},\n\t\t\tData:        []byte(`// ` + pathToChange + ` contents`),\n\t\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: path.Dir(pathToChange)},\n\t\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\t\"file\": testutils.MakeMemMapFs(t, otherMap),\n\t\t\t},\n\t\t}\n\n\t\tbuf := bytes.NewBuffer(nil)\n\t\trequire.NoError(t, arc1.Write(buf), pathToChange)\n\n\t\tarc1Filesystems := arc1.Filesystems\n\t\tarc1.Filesystems = nil\n\n\t\tarc2, err := ReadArchive(buf)\n\t\trequire.NoError(t, err, pathToChange)\n\n\t\tarc2Filesystems := arc2.Filesystems\n\t\tarc2.Filesystems = nil\n\t\tarc2.Filename = \"\"\n\t\tarc2.Pwd = \"\"\n\n\t\tassert.Equal(t, arc1, arc2, pathToChange)\n\n\t\tarc1Filesystems[\"https\"] = fsext.NewMemMapFs()\n\t\tdiffMapFilesystems(t, arc1Filesystems, arc2Filesystems)\n\t}\n}\n\nfunc TestStdinArchive(t *testing.T) {\n\tt.Parallel()\n\tfs := fsext.NewMemMapFs()\n\t// we specifically have different contents in both places\n\trequire.NoError(t, fsext.WriteFile(fs, \"/-\", []byte(`test`), 0o644))\n\n\tarc := &Archive{\n\t\tType:        \"js\",\n\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/-\"},\n\t\tK6Version:   build.Version,\n\t\tData:        []byte(`test`),\n\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/\"},\n\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\"file\": fs,\n\t\t},\n\t}\n\n\tbuf := bytes.NewBuffer(nil)\n\trequire.NoError(t, arc.Write(buf))\n\n\tnewArc, err := ReadArchive(buf)\n\trequire.NoError(t, err)\n\n\tdata, err := fsext.ReadFile(newArc.Filesystems[\"file\"], \"/-\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"test\", string(data))\n}\n"
  },
  {
    "path": "lib/buffer_pool.go",
    "content": "package lib\n\nimport (\n\t\"bytes\"\n\t\"sync\"\n)\n\n// BufferPool implements a bytes.Buffer pool using sync.Pool\ntype BufferPool struct {\n\tpool *sync.Pool\n}\n\n// NewBufferPool create a new instance of BufferPool using a sync.Pool implementation\n// returning a bytes.NewBuffer for each pooled new element\nfunc NewBufferPool() *BufferPool {\n\treturn &BufferPool{\n\t\tpool: &sync.Pool{\n\t\t\tNew: func() any {\n\t\t\t\treturn bytes.NewBuffer([]byte{})\n\t\t\t},\n\t\t},\n\t}\n}\n\n// Get return a bytes.Buffer from the pool\n//\n//nolint:forcetypeassert\nfunc (bp BufferPool) Get() *bytes.Buffer {\n\treturn bp.pool.Get().(*bytes.Buffer)\n}\n\n// Put return the given bytes.Buffer to the pool calling Buffer.Reset() before\nfunc (bp BufferPool) Put(b *bytes.Buffer) {\n\t// Important to clean the current data from de buffer for the next use,\n\t// otherwise a dirty buffer with the current data will be returned\n\tb.Reset()\n\tbp.pool.Put(b)\n}\n"
  },
  {
    "path": "lib/buffer_pool_test.go",
    "content": "package lib\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestBufferPool(t *testing.T) {\n\tt.Parallel()\n\tpool := NewBufferPool()\n\t// Iterate more than one to avoid GC runs\n\tfor i := 1; i < 10; i++ {\n\t\tb := pool.Get()\n\t\tb.WriteString(\"test\")\n\t\trequire.Equal(t, \"test\", b.String())\n\t\tpool.Put(b)\n\t}\n}\n"
  },
  {
    "path": "lib/compatibility_mode_gen.go",
    "content": "// Code generated by \"enumer -type=CompatibilityMode -transform=snake -trimprefix CompatibilityMode -output compatibility_mode_gen.go\"; DO NOT EDIT.\n\npackage lib\n\nimport (\n\t\"fmt\"\n)\n\nconst _CompatibilityModeName = \"extendedbaseexperimental_enhanced\"\n\nvar _CompatibilityModeIndex = [...]uint8{0, 8, 12, 33}\n\nfunc (i CompatibilityMode) String() string {\n\ti -= 1\n\tif i >= CompatibilityMode(len(_CompatibilityModeIndex)-1) {\n\t\treturn fmt.Sprintf(\"CompatibilityMode(%d)\", i+1)\n\t}\n\treturn _CompatibilityModeName[_CompatibilityModeIndex[i]:_CompatibilityModeIndex[i+1]]\n}\n\nvar _CompatibilityModeValues = []CompatibilityMode{1, 2, 3}\n\nvar _CompatibilityModeNameToValueMap = map[string]CompatibilityMode{\n\t_CompatibilityModeName[0:8]:   1,\n\t_CompatibilityModeName[8:12]:  2,\n\t_CompatibilityModeName[12:33]: 3,\n}\n\n// CompatibilityModeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc CompatibilityModeString(s string) (CompatibilityMode, error) {\n\tif val, ok := _CompatibilityModeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to CompatibilityMode values\", s)\n}\n\n// CompatibilityModeValues returns all values of the enum\nfunc CompatibilityModeValues() []CompatibilityMode {\n\treturn _CompatibilityModeValues\n}\n\n// IsACompatibilityMode returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i CompatibilityMode) IsACompatibilityMode() bool {\n\tfor _, v := range _CompatibilityModeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "lib/context.go",
    "content": "package lib\n\nimport (\n\t\"context\"\n)\n\ntype ctxKey int\n\nconst (\n\tctxKeyExecState ctxKey = iota\n\tctxKeyScenario\n)\n\n// WithExecutionState embeds an ExecutionState in ctx.\nfunc WithExecutionState(ctx context.Context, s *ExecutionState) context.Context {\n\treturn context.WithValue(ctx, ctxKeyExecState, s)\n}\n\n// GetExecutionState returns an ExecutionState from ctx.\nfunc GetExecutionState(ctx context.Context) *ExecutionState {\n\tv := ctx.Value(ctxKeyExecState)\n\tif v == nil {\n\t\treturn nil\n\t}\n\n\treturn v.(*ExecutionState) //nolint:forcetypeassert\n}\n\n// WithScenarioState embeds a ScenarioState in ctx.\nfunc WithScenarioState(ctx context.Context, s *ScenarioState) context.Context {\n\treturn context.WithValue(ctx, ctxKeyScenario, s)\n}\n\n// GetScenarioState returns a ScenarioState from ctx.\nfunc GetScenarioState(ctx context.Context) *ScenarioState {\n\tv := ctx.Value(ctxKeyScenario)\n\tif v == nil {\n\t\treturn nil\n\t}\n\treturn v.(*ScenarioState) //nolint:forcetypeassert\n}\n"
  },
  {
    "path": "lib/doc.go",
    "content": "// Package lib is a kitchen sink of... basically anything that doesn't belong in\n// a specific part of the codebase, ranging from utility functions to universal\n// types to core interfaces.\n//\n// Some of the things in lib do not actually belong in lib, and need to be moved\n// into either submodules, or separate modules like core. Other things are in\n// files that are far too long, or that do not actually make sense.\n//\n// Feel free to move these things.\npackage lib\n"
  },
  {
    "path": "lib/execution.go",
    "content": "package lib\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// MaxTimeToWaitForPlannedVU specifies the maximum allowable time for an executor\n// to wait for a planned VU to be retrieved from the ExecutionState.PlannedVUs\n// buffer. If it's exceeded, k6 will emit a warning log message, since it either\n// means that there's a bug in the k6 scheduling code, or that the machine is\n// overloaded and the scheduling code suffers from delays.\n//\n// Critically, exceeding this time *doesn't* result in an aborted test or any\n// test errors, and the executor will continue to try and borrow the VU\n// (potentially resulting in further warnings). We likely should emit a k6\n// metric about it in the future. TODO: emit a metric every time this is\n// exceeded?\nconst MaxTimeToWaitForPlannedVU = 400 * time.Millisecond\n\n// MaxRetriesGetPlannedVU how many times we should wait for\n// MaxTimeToWaitForPlannedVU before we actually return an error.\nconst MaxRetriesGetPlannedVU = 5\n\n// ExecutionStatus is used to mark the possible states of a test run at any\n// given time in its execution, from its start to its finish.\n//\n//go:generate enumer -type=ExecutionStatus -trimprefix ExecutionStatus -output execution_status_gen.go\ntype ExecutionStatus uint32\n\n// Possible execution status values\nconst (\n\tExecutionStatusCreated ExecutionStatus = iota\n\tExecutionStatusInitVUs\n\tExecutionStatusInitExecutors\n\tExecutionStatusInitDone\n\tExecutionStatusPausedBeforeRun\n\tExecutionStatusStarted\n\tExecutionStatusSetup\n\tExecutionStatusRunning\n\tExecutionStatusTeardown\n\tExecutionStatusEnded\n\tExecutionStatusInterrupted\n\tExecutionStatusMarkedAsFailed\n)\n\n// ExecutionState contains a few different things:\n//   - Some convenience items, that are needed by all executors, like the\n//     execution segment and the unique VU ID generator. By keeping those here,\n//     we can just pass the ExecutionState to the different executors, instead of\n//     individually passing them each item.\n//   - Mutable counters that different executors modify and other parts of\n//     k6 can read, e.g. for the vus and vus_max metrics k6 emits every second.\n//   - Pausing controls and statistics.\n//\n// The counters and timestamps here are primarily meant to be used for\n// information extraction and avoidance of ID collisions. Using many of the\n// counters here for synchronization between VUs could result in HIDDEN data\n// races, because the Go data race detector can't detect any data races\n// involving atomics...\n//\n// The only functionality intended for synchronization is the one revolving\n// around pausing, and uninitializedUnplannedVUs for restricting the number of\n// unplanned VUs being initialized.\ntype ExecutionState struct {\n\t// A portal to the broader test run state, so the different executors have\n\t// access to the test options, built-in metrics, etc.. They will need to\n\t// access things like the current execution segment, the per-run metrics\n\t// tags, different metrics to emit, etc.\n\t//\n\t// Obviously, things here are not meant to be changed... They should be a\n\t// constant during the execution of a single test, but we can't easily\n\t// enforce that via the Go type system...\n\tTest *TestRunState\n\n\tExecutionTuple *ExecutionTuple // TODO Rename, possibly move\n\n\t// vus is the shared channel buffer that contains all of the VUs that have\n\t// been initialized and aren't currently being used by a executor.\n\t//\n\t// It contains both pre-initialized (i.e. planned) VUs, as well as any\n\t// unplanned VUs. Planned VUs are initialized before a test begins, while\n\t// unplanned VUS can be initialized in the middle of the test run by a\n\t// executor and have been relinquished after it has finished working with\n\t// them. Usually, unplanned VUs are initialized by one of the arrival-rate\n\t// executors, after they have exhausted their PreAllocatedVUs. After the\n\t// executor is done with the VUs, it will put in this channel, so it could\n\t// potentially be reused by other executors further along in the test.\n\t//\n\t// Different executors cooperatively borrow VUs from here when they are\n\t// needed and return them when they are done with them. There's no central\n\t// enforcement of correctness, i.e. that a executor takes more VUs from\n\t// here than its execution plan has stipulated. The correctness guarantee\n\t// lies with the actual executors - bugs in one can affect others.\n\t//\n\t// That's why the field is private and we force executors to use the\n\t// GetPlannedVU(), GetUnplannedVU(), and ReturnVU() methods instead of work\n\t// directly with the channel. These methods will emit a warning or can even\n\t// return an error if retrieving a VU takes more than\n\t// MaxTimeToWaitForPlannedVU.\n\tvus chan InitializedVU\n\n\t// The segmented index used to generate unique local (current k6 instance)\n\t// and global (across k6 instances) VU IDs, starting from 1\n\t// (for backwards compatibility...).\n\tvuIDSegIndexMx *sync.Mutex\n\tvuIDSegIndex   *SegmentedIndex\n\n\t// TODO: add something similar, but for iterations? Currently, there isn't\n\t// a straightforward way to get a unique sequential identifier per iteration\n\t// in the context of a single k6 instance. Combining __VU and __ITER gives us\n\t// a unique identifier, but it's unwieldy and somewhat cumbersome.\n\n\t// Total number of currently initialized VUs. Generally equal to\n\t// the VU ID minus 1, since initializedVUs starts from 0 and is\n\t// incremented only after a VU is initialized, while the VU ID is\n\t// incremented before a VU is initialized. It should always be greater than\n\t// or equal to 0, but int64 is used for simplification of the used atomic\n\t// arithmetic operations.\n\tinitializedVUs *int64\n\n\t// Total number of unplanned VUs we haven't initialized yet. It starts\n\t// being equal to GetMaxPossibleVUs(executionPlan)-GetMaxPlannedVUs(), and\n\t// may stay that way if no unplanned VUs are initialized. Once it reaches 0,\n\t// no more unplanned VUs can be initialized.\n\tuninitializedUnplannedVUs *int64\n\n\t// Injected when the execution scheduler's Init function is called, used for\n\t// initializing unplanned VUs.\n\tinitVUFunc InitVUFunc\n\n\t// The number of VUs that are currently executing the test script. This also\n\t// includes any VUs that are in the process of gracefully winding down,\n\t// either at the end of the test, or when VUs are ramping down. It should\n\t// always be greater than or equal to 0, but int64 is used for\n\t// simplification of the used atomic arithmetic operations.\n\tactiveVUs *int64\n\n\t// The total number of full (i.e uninterrupted) iterations that have been\n\t// completed so far.\n\tfullIterationsCount *uint64\n\n\t// The total number of iterations that have been interrupted during their\n\t// execution. The potential interruption causes vary - end of a specified\n\t// script `duration`, scaling down of VUs via `stages`, a user hitting\n\t// Ctrl+C, change of `vus` via the externally controlled executor's REST\n\t// API, etc.\n\tinterruptedIterationsCount *uint64\n\n\t// A machine-readable indicator in which the current state of the test\n\t// execution is currently stored. Useful for the REST API and external\n\t// observability of the k6 test run progress.\n\texecutionStatus *uint32\n\n\t// A nanosecond UNIX timestamp that is set when the test is actually\n\t// started. The default 0 value is used to denote that the test hasn't\n\t// started yet...\n\tstartTime *int64\n\n\t// A nanosecond UNIX timestamp that is set when the test ends, either\n\t// by an early context cancel or at its regularly scheduled time.\n\t// The default 0 value is used to denote that the test hasn't ended yet.\n\tendTime *int64\n\n\t// Stuff related to pausing follows. Read the docs in ExecutionScheduler for\n\t// more information regarding how pausing works in k6.\n\t//\n\t// When we pause the execution in the middle of the test, we save the\n\t// current timestamp in currentPauseTime. When we resume the execution, we\n\t// set currentPauseTime back to 0 and we add the (time.Now() -\n\t// currentPauseTime) duration to totalPausedDuration (unless the test hasn't\n\t// started yet).\n\t//\n\t// Thus, the algorithm for GetCurrentTestRunDuration() is very\n\t// straightforward:\n\t//   - if the test hasn't started, return 0\n\t//   - set endTime to:\n\t//      - the current pauseTime, if not zero\n\t//      - time.Now() otherwise\n\t//   - return (endTime - startTime - totalPausedDuration)\n\t//\n\t// Quickly checking for IsPaused() just means comparing the currentPauseTime\n\t// with 0, a single atomic operation.\n\t//\n\t// But if we want to wait until a script resumes, or be notified of the\n\t// start/resume event from a channel (as part of a select{}), we have to\n\t// acquire the pauseStateLock, get the current resumeNotify instance,\n\t// release the lock and wait to read from resumeNotify (when it's closed by\n\t// Resume()).\n\tcurrentPauseTime    *int64\n\tpauseStateLock      sync.RWMutex\n\ttotalPausedDuration time.Duration // only modified behind the lock\n\tresumeNotify        chan struct{}\n}\n\n// NewExecutionState initializes all of the pointers in the ExecutionState\n// with zeros. It also makes sure that the initial state is unpaused, by\n// setting resumeNotify to an already closed channel.\nfunc NewExecutionState(\n\ttestRunState *TestRunState, et *ExecutionTuple, maxPlannedVUs, maxPossibleVUs uint64,\n) *ExecutionState {\n\tresumeNotify := make(chan struct{})\n\tclose(resumeNotify) // By default the ExecutionState starts unpaused\n\n\tmaxUnplannedUninitializedVUs := int64(maxPossibleVUs - maxPlannedVUs) //nolint:gosec\n\n\tsegIdx := NewSegmentedIndex(et)\n\treturn &ExecutionState{\n\t\tTest:           testRunState,\n\t\tExecutionTuple: et,\n\n\t\tvus: make(chan InitializedVU, maxPossibleVUs),\n\n\t\texecutionStatus:            new(uint32),\n\t\tvuIDSegIndexMx:             new(sync.Mutex),\n\t\tvuIDSegIndex:               segIdx,\n\t\tinitializedVUs:             new(int64),\n\t\tuninitializedUnplannedVUs:  &maxUnplannedUninitializedVUs,\n\t\tactiveVUs:                  new(int64),\n\t\tfullIterationsCount:        new(uint64),\n\t\tinterruptedIterationsCount: new(uint64),\n\t\tstartTime:                  new(int64),\n\t\tendTime:                    new(int64),\n\t\tcurrentPauseTime:           new(int64),\n\t\tpauseStateLock:             sync.RWMutex{},\n\t\ttotalPausedDuration:        0, // Accessed only behind the pauseStateLock\n\t\tresumeNotify:               resumeNotify,\n\t}\n}\n\n// GetUniqueVUIdentifiers returns the next unique VU IDs, both local (for the\n// current instance, exposed as __VU) and global (across k6 instances, exposed\n// in the k6/execution module). It starts from 1, for backwards compatibility.\nfunc (es *ExecutionState) GetUniqueVUIdentifiers() (uint64, uint64) {\n\tes.vuIDSegIndexMx.Lock()\n\tdefer es.vuIDSegIndexMx.Unlock()\n\tscaled, unscaled := es.vuIDSegIndex.Next()\n\treturn uint64(scaled), uint64(unscaled) //nolint:gosec\n}\n\n// GetInitializedVUsCount returns the total number of currently initialized VUs.\n//\n// Important: this doesn't include any temporary/service VUs that are destroyed\n// after they are used. These are created for the initial retrieval of the\n// exported script options and for the execution of setup() and teardown()\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) GetInitializedVUsCount() int64 {\n\treturn atomic.LoadInt64(es.initializedVUs)\n}\n\n// ModInitializedVUsCount changes the total number of currently initialized VUs.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) ModInitializedVUsCount(mod int64) int64 {\n\treturn atomic.AddInt64(es.initializedVUs, mod)\n}\n\n// GetCurrentlyActiveVUsCount returns the number of VUs that are currently\n// executing the test script. This also includes any VUs that are in the process\n// of gracefully winding down.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) GetCurrentlyActiveVUsCount() int64 {\n\treturn atomic.LoadInt64(es.activeVUs)\n}\n\n// ModCurrentlyActiveVUsCount changes the total number of currently active VUs.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) ModCurrentlyActiveVUsCount(mod int64) int64 {\n\treturn atomic.AddInt64(es.activeVUs, mod)\n}\n\n// GetFullIterationCount returns the total of full (i.e uninterrupted) iterations\n// that have been completed so far.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) GetFullIterationCount() uint64 {\n\treturn atomic.LoadUint64(es.fullIterationsCount)\n}\n\n// AddFullIterations increments the number of full (i.e uninterrupted) iterations\n// by the provided amount.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) AddFullIterations(count uint64) uint64 {\n\treturn atomic.AddUint64(es.fullIterationsCount, count)\n}\n\n// GetPartialIterationCount returns the total of partial (i.e interrupted)\n// iterations that have been completed so far.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) GetPartialIterationCount() uint64 {\n\treturn atomic.LoadUint64(es.interruptedIterationsCount)\n}\n\n// AddInterruptedIterations increments the number of partial (i.e interrupted)\n// iterations by the provided amount.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) AddInterruptedIterations(count uint64) uint64 {\n\treturn atomic.AddUint64(es.interruptedIterationsCount, count)\n}\n\n// SetExecutionStatus changes the current execution status to the supplied value\n// and returns the current value.\nfunc (es *ExecutionState) SetExecutionStatus(newStatus ExecutionStatus) (oldStatus ExecutionStatus) {\n\treturn ExecutionStatus(atomic.SwapUint32(es.executionStatus, uint32(newStatus)))\n}\n\n// GetCurrentExecutionStatus returns the current execution status. Don't use\n// this for synchronization unless you've made the k6 behavior somewhat\n// predictable with options like --paused or --linger.\nfunc (es *ExecutionState) GetCurrentExecutionStatus() ExecutionStatus {\n\treturn ExecutionStatus(atomic.LoadUint32(es.executionStatus))\n}\n\n// MarkStarted saves the current timestamp as the test start time.\n//\n// CAUTION: Calling MarkStarted() a second time for the same execution state will\n// result in a panic!\nfunc (es *ExecutionState) MarkStarted() {\n\tif !atomic.CompareAndSwapInt64(es.startTime, 0, time.Now().UnixNano()) {\n\t\tpanic(\"the execution scheduler was started a second time\")\n\t}\n\tes.SetExecutionStatus(ExecutionStatusStarted)\n}\n\n// MarkEnded saves the current timestamp as the test end time.\n//\n// CAUTION: Calling MarkEnded() a second time for the same execution state will\n// result in a panic!\nfunc (es *ExecutionState) MarkEnded() {\n\tif !atomic.CompareAndSwapInt64(es.endTime, 0, time.Now().UnixNano()) {\n\t\tpanic(\"the execution scheduler was stopped a second time\")\n\t}\n\tes.SetExecutionStatus(ExecutionStatusEnded)\n}\n\n// HasStarted returns true if the test has actually started executing.\n// It will return false while a test is in the init phase, or if it has\n// been initially paused. But if will return true if a test is paused\n// midway through its execution (see above for details regarding the\n// feasibility of that pausing for normal executors).\nfunc (es *ExecutionState) HasStarted() bool {\n\treturn atomic.LoadInt64(es.startTime) != 0\n}\n\n// HasEnded returns true if the test has finished executing. It will return\n// false until MarkEnded() is called.\nfunc (es *ExecutionState) HasEnded() bool {\n\treturn atomic.LoadInt64(es.endTime) != 0\n}\n\n// IsPaused quickly returns whether the test is currently paused, by reading\n// the atomic currentPauseTime timestamp\nfunc (es *ExecutionState) IsPaused() bool {\n\treturn atomic.LoadInt64(es.currentPauseTime) != 0\n}\n\n// GetCurrentTestRunDuration returns the duration for which the test has already\n// ran. If the test hasn't started yet, that's 0. If it has started, but has\n// been paused midway through, it will return the time up until the pause time.\n// And if it's currently running, it will return the time since the start time.\n//\n// IMPORTANT: for UI/information purposes only, don't use for synchronization.\nfunc (es *ExecutionState) GetCurrentTestRunDuration() time.Duration {\n\tstartTime := atomic.LoadInt64(es.startTime)\n\tif startTime == 0 {\n\t\t// The test hasn't started yet\n\t\treturn 0\n\t}\n\n\tes.pauseStateLock.RLock()\n\tendTime := atomic.LoadInt64(es.endTime)\n\tpausedDuration := es.totalPausedDuration\n\tes.pauseStateLock.RUnlock()\n\n\tif endTime == 0 {\n\t\tpauseTime := atomic.LoadInt64(es.currentPauseTime)\n\t\tif pauseTime != 0 {\n\t\t\tendTime = pauseTime\n\t\t} else {\n\t\t\t// The test isn't paused or finished, use the current time instead\n\t\t\tendTime = time.Now().UnixNano()\n\t\t}\n\t}\n\n\treturn time.Duration(endTime-startTime) - pausedDuration\n}\n\n// Pause pauses the current execution. It acquires the lock, writes\n// the current timestamp in currentPauseTime, and makes a new\n// channel for resumeNotify.\n// Pause can return an error if the test was already paused.\nfunc (es *ExecutionState) Pause() error {\n\tes.pauseStateLock.Lock()\n\tdefer es.pauseStateLock.Unlock()\n\n\tif !atomic.CompareAndSwapInt64(es.currentPauseTime, 0, time.Now().UnixNano()) {\n\t\treturn errors.New(\"test execution was already paused\")\n\t}\n\tes.resumeNotify = make(chan struct{})\n\treturn nil\n}\n\n// Resume unpauses the test execution. Unless the test wasn't\n// yet started, it calculates the duration between now and\n// the old currentPauseTime and adds it to\n// Resume will emit an error if the test wasn't paused.\nfunc (es *ExecutionState) Resume() error {\n\tes.pauseStateLock.Lock()\n\tdefer es.pauseStateLock.Unlock()\n\n\tcurrentPausedTime := atomic.SwapInt64(es.currentPauseTime, 0)\n\tif currentPausedTime == 0 {\n\t\treturn errors.New(\"test execution wasn't paused\")\n\t}\n\n\t// Check that it's not the pause before execution actually starts\n\tif atomic.LoadInt64(es.startTime) != 0 {\n\t\tes.totalPausedDuration += time.Duration(time.Now().UnixNano() - currentPausedTime)\n\t}\n\n\tclose(es.resumeNotify)\n\n\treturn nil\n}\n\n// ResumeNotify returns a channel which will be closed (i.e. could\n// be read from) as soon as the test execution is resumed.\n//\n// Since tests would likely be paused only rarely, unless you\n// directly need to be notified via a channel that the test\n// isn't paused or that it has resumed, it's probably a good\n// idea to first use the IsPaused() method, since it will be much\n// faster.\n//\n// And, since tests won't be paused most of the time, it's\n// probably better to check for that like this:\n//\n//\tif executionState.IsPaused() {\n//\t    <-executionState.ResumeNotify()\n//\t}\nfunc (es *ExecutionState) ResumeNotify() <-chan struct{} {\n\tes.pauseStateLock.RLock()\n\tdefer es.pauseStateLock.RUnlock()\n\treturn es.resumeNotify\n}\n\n// GetPlannedVU tries to get a pre-initialized VU from the buffer channel. This\n// shouldn't fail and should generally be an instantaneous action, but if it\n// doesn't happen for MaxTimeToWaitForPlannedVU (for example, because the system\n// is overloaded), a warning will be printed. If we reach that timeout more than\n// MaxRetriesGetPlannedVU number of times, this function will return an error,\n// since we either have a bug with some executor, or the machine is very, very\n// overloaded.\n//\n// If modifyActiveVUCount is true, the method would also increment the counter\n// for active VUs. In most cases, that's the desired behavior, but some\n// executors might have to retrieve their reserved VUs without using them\n// immediately - for example, the externally-controlled executor when the\n// configured maxVUs number is greater than the configured starting VUs.\nfunc (es *ExecutionState) GetPlannedVU(logger *logrus.Entry, modifyActiveVUCount bool) (InitializedVU, error) {\n\tfor i := 1; i <= MaxRetriesGetPlannedVU; i++ {\n\t\tselect {\n\t\tcase vu := <-es.vus:\n\t\t\tif modifyActiveVUCount {\n\t\t\t\tes.ModCurrentlyActiveVUsCount(+1)\n\t\t\t}\n\t\t\t// TODO: set environment and exec\n\t\t\treturn vu, nil\n\t\tcase <-time.After(MaxTimeToWaitForPlannedVU):\n\t\t\tlogger.Warnf(\"Could not get a VU from the buffer for %s\", time.Duration(i)*MaxTimeToWaitForPlannedVU)\n\t\t}\n\t}\n\treturn nil, fmt.Errorf(\n\t\t\"could not get a VU from the buffer in %s\",\n\t\tMaxRetriesGetPlannedVU*MaxTimeToWaitForPlannedVU,\n\t)\n}\n\n// SetInitVUFunc is called by the execution scheduler's init function, and it's\n// used for setting the \"constructor\" function used for the initializing\n// unplanned VUs.\n//\n// TODO: figure out a better dependency injection method?\nfunc (es *ExecutionState) SetInitVUFunc(initVUFunc InitVUFunc) {\n\tes.initVUFunc = initVUFunc\n}\n\n// GetUnplannedVU checks if any unplanned VUs remain to be initialized, and if\n// they do, it initializes one and returns it. If all unplanned VUs have already\n// been initialized, it returns one from the global vus buffer, but doesn't\n// automatically increment the active VUs counter in either case.\n//\n// IMPORTANT: GetUnplannedVU() doesn't do any checking if the requesting\n// executor is actually allowed to have the VU at this particular time.\n// Executors are trusted to correctly declare their needs (via their\n// GetExecutionRequirements() methods) and then to never ask for more VUs than\n// they have specified in those requirements.\nfunc (es *ExecutionState) GetUnplannedVU(ctx context.Context, logger *logrus.Entry) (InitializedVU, error) {\n\tremVUs := atomic.AddInt64(es.uninitializedUnplannedVUs, -1)\n\tif remVUs < 0 {\n\t\tlogger.Debug(\"Reusing a previously initialized unplanned VU\")\n\t\tatomic.AddInt64(es.uninitializedUnplannedVUs, 1)\n\t\treturn es.GetPlannedVU(logger, false)\n\t}\n\n\tlogger.Debug(\"Initializing an unplanned VU, this may affect test results\")\n\treturn es.InitializeNewVU(ctx, logger)\n}\n\n// InitializeNewVU creates and returns a brand new VU, updating the relevant\n// tracking counters.\nfunc (es *ExecutionState) InitializeNewVU(ctx context.Context, logger *logrus.Entry) (InitializedVU, error) {\n\tif es.initVUFunc == nil {\n\t\treturn nil, fmt.Errorf(\"initVUFunc wasn't set in the execution state\")\n\t}\n\tnewVU, err := es.initVUFunc(ctx, logger)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tes.ModInitializedVUsCount(+1)\n\treturn newVU, err\n}\n\n// AddInitializedVU is a helper function that adds VUs into the buffer and\n// increases the initialized VUs counter.\nfunc (es *ExecutionState) AddInitializedVU(vu InitializedVU) {\n\tes.vus <- vu\n\tes.ModInitializedVUsCount(+1)\n}\n\n// ReturnVU is a helper function that puts VUs back into the buffer and\n// decreases the active VUs counter.\nfunc (es *ExecutionState) ReturnVU(vu InitializedVU, wasActive bool) {\n\tes.vus <- vu\n\tif wasActive {\n\t\tes.ModCurrentlyActiveVUsCount(-1)\n\t}\n}\n"
  },
  {
    "path": "lib/execution_segment.go",
    "content": "package lib\n\nimport (\n\t\"encoding\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// ExecutionSegment represents a (start, end] partition of the total execution\n// work for a specific test. For example, if we want the split the execution of a\n// test in 2 different parts, we can split it in two segments (0, 0.5] and (0,5, 1].\n//\n// We use rational numbers so it's easier to verify the correctness and easier to\n// reason about portions of indivisible things, like VUs. This way, we can easily\n// split a test in thirds (i.e. (0, 1/3], (1/3, 2/3], (2/3, 1]), without fearing\n// that we'll lose a VU along the way...\n//\n// The most important part is that if work is split between multiple k6 instances,\n// each k6 instance can precisely and reproducibly calculate its share of the work,\n// just by knowing its own segment. There won't be a need to schedule the\n// execution from a master node, or to even know how many other k6 instances are\n// running!\ntype ExecutionSegment struct {\n\t// 0 <= from < to <= 1\n\tfrom *big.Rat\n\tto   *big.Rat\n\n\t// derived, equals to-from, but pre-calculated here for speed\n\tlength *big.Rat\n}\n\n// Ensure we implement those interfaces\nvar (\n\t_ encoding.TextUnmarshaler = &ExecutionSegment{}\n\t_ fmt.Stringer             = &ExecutionSegment{}\n)\n\n// Helpful \"constants\" so we don't initialize them in every function call\nvar (\n\tzeroRat, oneRat      = big.NewRat(0, 1), big.NewRat(1, 1) //nolint:gochecknoglobals\n\toneBigInt, twoBigInt = big.NewInt(1), big.NewInt(2)       //nolint:gochecknoglobals\n)\n\n// NewExecutionSegment validates the supplied arguments (basically, that 0 <=\n// from < to <= 1) and either returns an error, or it returns a\n// fully-initialized and usable execution segment.\nfunc NewExecutionSegment(from, to *big.Rat) (*ExecutionSegment, error) {\n\tif from.Cmp(zeroRat) < 0 {\n\t\treturn nil, fmt.Errorf(\"segment start value must be at least 0 but was %s\", from.FloatString(2))\n\t}\n\tif from.Cmp(to) >= 0 {\n\t\treturn nil, fmt.Errorf(\"segment start(%s) must be less than its end(%s)\", from.FloatString(2), to.FloatString(2))\n\t}\n\tif to.Cmp(oneRat) > 0 {\n\t\treturn nil, fmt.Errorf(\"segment end value can't be more than 1 but was %s\", to.FloatString(2))\n\t}\n\treturn newExecutionSegment(from, to), nil\n}\n\n// newExecutionSegment just creates an ExecutionSegment without validating the arguments\nfunc newExecutionSegment(from, to *big.Rat) *ExecutionSegment {\n\treturn &ExecutionSegment{\n\t\tfrom:   from,\n\t\tto:     to,\n\t\tlength: new(big.Rat).Sub(to, from),\n\t}\n}\n\n// stringToRat is a helper function that tries to convert a string to a rational\n// number while allowing percentage, decimal, and fraction values.\nfunc stringToRat(s string) (*big.Rat, error) {\n\tif before, ok := strings.CutSuffix(s, \"%\"); ok {\n\t\tnum, ok := new(big.Int).SetString(before, 10)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"'%s' is not a valid percentage\", s)\n\t\t}\n\t\treturn new(big.Rat).SetFrac(num, big.NewInt(100)), nil\n\t}\n\trat, ok := new(big.Rat).SetString(s)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"'%s' is not a valid percentage, decimal, fraction or interval value\", s)\n\t}\n\treturn rat, nil\n}\n\n// NewExecutionSegmentFromString validates the supplied string value and returns\n// the newly created ExecutionSegment or and error from it.\n//\n// We are able to parse both single percentage/float/fraction values, and actual\n// (from: to] segments. For the single values, we just treat them as the\n// beginning segment - thus the execution segment can be used as a shortcut for\n// quickly running an arbitrarily scaled-down version of a test.\n//\n// The parsing logic is that values with a colon, i.e. ':', are full segments:\n//\n//\t`1/2:3/4`, `0.5:0.75`, `50%:75%`, and even `2/4:75%` should be (1/2, 3/4]\n//\n// And values without a colon are the end of a first segment:\n//\n//\t`20%`, `0.2`,  and `1/5` should be converted to (0, 1/5]\n//\n// empty values should probably be treated as \"1\", i.e. the whole execution\nfunc NewExecutionSegmentFromString(toStr string) (result *ExecutionSegment, err error) {\n\tfrom := zeroRat\n\tif toStr == \"\" {\n\t\ttoStr = \"1\" // an empty string means a full 0:1 execution segment\n\t}\n\tif strings.ContainsRune(toStr, ':') {\n\t\tvar fromStr string\n\t\tfromStr, toStr, _ = strings.Cut(toStr, \":\")\n\t\tif from, err = stringToRat(fromStr); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tto, err := stringToRat(toStr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn NewExecutionSegment(from, to)\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface, so that\n// execution segments can be specified as CLI flags, environment variables, and\n// JSON strings. It is a wrapper for the NewExecutionFromString() constructor.\nfunc (es *ExecutionSegment) UnmarshalText(text []byte) (err error) {\n\tsegment, err := NewExecutionSegmentFromString(string(text))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*es = *segment\n\treturn nil\n}\n\nfunc (es *ExecutionSegment) String() string {\n\tif es == nil {\n\t\treturn \"0:1\"\n\t}\n\treturn es.from.RatString() + \":\" + es.to.RatString()\n}\n\n// MarshalText implements the encoding.TextMarshaler interface, so is used for\n// text and JSON encoding of the execution segment.\nfunc (es *ExecutionSegment) MarshalText() ([]byte, error) {\n\tif es == nil {\n\t\treturn nil, nil\n\t}\n\treturn []byte(es.String()), nil\n}\n\n// FloatLength is a helper method for getting some more human-readable\n// information about the execution segment.\nfunc (es *ExecutionSegment) FloatLength() float64 {\n\tif es == nil {\n\t\treturn 1.0\n\t}\n\tres, _ := es.length.Float64()\n\treturn res\n}\n\n// Split evenly divides the execution segment into the specified number of\n// equal consecutive execution sub-segments.\nfunc (es *ExecutionSegment) Split(numParts int64) ([]*ExecutionSegment, error) {\n\tif numParts < 1 {\n\t\treturn nil, fmt.Errorf(\"the number of parts must be at least 1, %d received\", numParts)\n\t}\n\n\tfrom, to := zeroRat, oneRat\n\tif es != nil {\n\t\tfrom, to = es.from, es.to\n\t}\n\n\tincrement := new(big.Rat).Sub(to, from)\n\tincrement.Denom().Mul(increment.Denom(), big.NewInt(numParts))\n\n\tresults := make([]*ExecutionSegment, numParts)\n\tfor i := range numParts {\n\t\tsegmentTo := new(big.Rat).Add(from, increment)\n\t\tsegment, err := NewExecutionSegment(from, segmentTo)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresults[i] = segment\n\t\tfrom = segmentTo\n\t}\n\n\tif from.Cmp(to) != 0 {\n\t\treturn nil, fmt.Errorf(\"expected %s and %s to be equal\", from, to)\n\t}\n\n\treturn results, nil\n}\n\n// Equal returns true only if the two execution segments have the same from and\n// to values.\nfunc (es *ExecutionSegment) Equal(other *ExecutionSegment) bool {\n\tif es == other {\n\t\treturn true\n\t}\n\tthisFrom, otherFrom, thisTo, otherTo := zeroRat, zeroRat, oneRat, oneRat\n\tif es != nil {\n\t\tthisFrom, thisTo = es.from, es.to\n\t}\n\tif other != nil {\n\t\totherFrom, otherTo = other.from, other.to\n\t}\n\treturn thisFrom.Cmp(otherFrom) == 0 && thisTo.Cmp(otherTo) == 0\n}\n\n// SubSegment returns a new execution sub-segment - if a is (1/2:1] and b is\n// (0:1/2], then a.SubSegment(b) will return a new segment (1/2, 3/4].\n//\n// The basic formula for c = a.SubSegment(b) is:\n//\n//\tc.from = a.from + b.from * (a.to - a.from)\n//\tc.to = c.from + (b.to - b.from) * (a.to - a.from)\nfunc (es *ExecutionSegment) SubSegment(child *ExecutionSegment) *ExecutionSegment {\n\tif child == nil {\n\t\treturn es // 100% sub-segment is the original segment\n\t}\n\n\tparentFrom, parentLength := zeroRat, oneRat\n\tif es != nil {\n\t\tparentFrom, parentLength = es.from, es.length\n\t}\n\n\tresultFrom := new(big.Rat).Mul(parentLength, child.from)\n\tresultFrom.Add(resultFrom, parentFrom)\n\n\tresultLength := new(big.Rat).Mul(parentLength, child.length)\n\treturn &ExecutionSegment{\n\t\tfrom:   resultFrom,\n\t\tlength: resultLength,\n\t\tto:     new(big.Rat).Add(resultFrom, resultLength),\n\t}\n}\n\n// helper function for rounding (up) of rational numbers to big.Int values\nfunc roundUp(rat *big.Rat) *big.Int {\n\tquo, rem := new(big.Int).QuoRem(rat.Num(), rat.Denom(), new(big.Int))\n\n\tif rem.Mul(rem, twoBigInt).Cmp(rat.Denom()) >= 0 {\n\t\treturn quo.Add(quo, oneBigInt)\n\t}\n\treturn quo\n}\n\n// Scale proportionally scales the supplied value, according to the execution\n// segment's position and size of the work.\nfunc (es *ExecutionSegment) Scale(value int64) int64 {\n\tif es == nil { // no execution segment, i.e. 100%\n\t\treturn value\n\t}\n\t// Instead of the first proposal that used remainders and floor:\n\t//    floor( (value * from) % 1 + value * length )\n\t// We're using an alternative approach with rounding that (hopefully) has\n\t// the same properties, but it's simpler and has better precision:\n\t//    round( (value * from) - round(value * from) + (value * (to - from)) )?\n\t// which reduces to:\n\t//    round( (value * to) - round(value * from) )?\n\n\ttoValue := big.NewRat(value, 1)\n\ttoValue.Mul(toValue, es.to)\n\n\tfromValue := big.NewRat(value, 1)\n\tfromValue.Mul(fromValue, es.from)\n\n\ttoValue.Sub(toValue, new(big.Rat).SetFrac(roundUp(fromValue), oneBigInt))\n\n\treturn roundUp(toValue).Int64()\n}\n\n// InPlaceScaleRat scales rational numbers in-place - it changes the passed\n// argument (and also returns it, to allow for chaining, like many other big.Rat\n// methods).\nfunc (es *ExecutionSegment) InPlaceScaleRat(value *big.Rat) *big.Rat {\n\tif es == nil { // no execution segment, i.e. 100%\n\t\treturn value\n\t}\n\treturn value.Mul(value, es.length)\n}\n\n// CopyScaleRat scales rational numbers without changing them - creates a new\n// bit.Rat object and uses it for the calculation.\nfunc (es *ExecutionSegment) CopyScaleRat(value *big.Rat) *big.Rat {\n\tif es == nil { // no execution segment, i.e. 100%\n\t\treturn value\n\t}\n\treturn new(big.Rat).Mul(value, es.length)\n}\n\n// ExecutionSegmentSequence represents an ordered chain of execution segments,\n// where the end of one segment is the beginning of the next. It can serialized\n// as a comma-separated string of rational numbers \"r1,r2,r3,...,rn\", which\n// represents the sequence (r1, r2], (r2, r3], (r3, r4], ..., (r{n-1}, rn].\n// The empty value should be treated as if there is a single (0, 1] segment.\ntype ExecutionSegmentSequence []*ExecutionSegment\n\n// NewExecutionSegmentSequence validates the that the supplied execution\n// segments are non-overlapping and without gaps. It will return a new execution\n// segment sequence if that is true, and an error if it's not.\nfunc NewExecutionSegmentSequence(segments ...*ExecutionSegment) (ExecutionSegmentSequence, error) {\n\tif len(segments) > 1 {\n\t\tto := segments[0].to\n\t\tfor i, segment := range segments[1:] {\n\t\t\tif segment.from.Cmp(to) != 0 {\n\t\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\t\"the start value %s of segment #%d must be equal to the end value of the previous one, but it is %s\",\n\t\t\t\t\tsegment.from, i+1, to,\n\t\t\t\t)\n\t\t\t}\n\t\t\tto = segment.to\n\t\t}\n\t}\n\treturn ExecutionSegmentSequence(segments), nil\n}\n\n// NewExecutionSegmentSequenceFromString parses strings of the format\n// \"r1,r2,r3,...,rn\", which represents the sequences like (r1, r2], (r2, r3],\n// (r3, r4], ..., (r{n-1}, rn].\nfunc NewExecutionSegmentSequenceFromString(strSeq string) (ExecutionSegmentSequence, error) {\n\tif len(strSeq) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tpoints := strings.Split(strSeq, \",\")\n\tif len(points) < 2 {\n\t\treturn nil, fmt.Errorf(\"at least 2 points are needed for an execution segment sequence, %d given\", len(points))\n\t}\n\tvar start *big.Rat\n\n\tsegments := make([]*ExecutionSegment, 0, len(points)-1)\n\tfor i, point := range points {\n\t\trat, err := stringToRat(point)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif i == 0 {\n\t\t\tstart = rat\n\t\t\tcontinue\n\t\t}\n\n\t\tsegment, err := NewExecutionSegment(start, rat)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsegments = append(segments, segment)\n\t\tstart = rat\n\t}\n\n\treturn NewExecutionSegmentSequence(segments...)\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface, so that\n// execution segment sequences can be specified as CLI flags, environment\n// variables, and JSON strings.\nfunc (ess *ExecutionSegmentSequence) UnmarshalText(text []byte) (err error) {\n\tseq, err := NewExecutionSegmentSequenceFromString(string(text))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*ess = seq\n\treturn nil\n}\n\n// MarshalText implements the encoding.TextMarshaler interface, so is used for\n// text and JSON encoding of the execution segment sequences.\nfunc (ess ExecutionSegmentSequence) MarshalText() ([]byte, error) {\n\treturn []byte(ess.String()), nil\n}\n\n// String just implements the fmt.Stringer interface, encoding the sequence of\n// segments as \"start1,end1,end2,end3,...,endn\".\nfunc (ess ExecutionSegmentSequence) String() string {\n\tresult := make([]string, 0, len(ess)+1)\n\tfor i, s := range ess {\n\t\tif i == 0 {\n\t\t\tresult = append(result, s.from.RatString())\n\t\t}\n\t\tresult = append(result, s.to.RatString())\n\t}\n\treturn strings.Join(result, \",\")\n}\n\n// LCD calculates the lowest common denominator of the sequence.\n// https://en.wikipedia.org/wiki/Least_common_multiple#Using_the_greatest_common_divisor\nfunc (ess ExecutionSegmentSequence) LCD() int64 {\n\tacc := ess[0].length.Denom().Int64()\n\tvar n int64\n\tfor _, seg := range ess[1:] {\n\t\tn = seg.length.Denom().Int64()\n\t\tif acc == n || acc%n == 0 { // short circuit\n\t\t\tcontinue\n\t\t}\n\t\tacc *= (n / gcd(acc, n))\n\t}\n\n\treturn acc\n}\n\n// Greatest common divisor\n// https://en.wikipedia.org/wiki/Euclidean_algorithm\nfunc gcd(a, b int64) int64 {\n\tfor a != b {\n\t\tif a > b {\n\t\t\ta -= b\n\t\t} else {\n\t\t\tb -= a\n\t\t}\n\t}\n\treturn a\n}\n\n// IsFull returns whether the sequences is full, that is, whether it starts at 0\n// and ends at 1. Use GetFilledExecutionSegmentSequence() to get a full sequence.\nfunc (ess ExecutionSegmentSequence) IsFull() bool {\n\treturn len(ess) != 0 && ess[0].from.Cmp(zeroRat) == 0 && ess[len(ess)-1].to.Cmp(oneRat) == 0\n}\n\n// FindSegmentPosition returns the index of the supplied execution segment in\n// the sequence, or an error if the segment isn't present. This shouldn't be\n// used on a nil or empty sequence, it's best to use this method on the result\n// of GetFilledExecutionSegmentSequence().\nfunc (ess ExecutionSegmentSequence) FindSegmentPosition(segment *ExecutionSegment) (int, error) {\n\tfrom := zeroRat\n\tif segment != nil {\n\t\tfrom = segment.from\n\t}\n\tindex := sort.Search(len(ess), func(i int) bool {\n\t\treturn ess[i].from.Cmp(from) >= 0\n\t})\n\n\tif index < 0 || index >= len(ess) || !ess[index].Equal(segment) {\n\t\treturn -1, fmt.Errorf(\"couldn't find segment %s in sequence %s\", segment, ess)\n\t}\n\treturn index, nil\n}\n\n// GetFilledExecutionSegmentSequence makes sure we don't have any gaps in the\n// given execution segment sequence, or a nil one. It makes sure that the whole\n// 0-1 range is filled.\nfunc GetFilledExecutionSegmentSequence(\n\tsequence *ExecutionSegmentSequence, fallback *ExecutionSegment,\n) (result ExecutionSegmentSequence) {\n\tif sequence == nil || len(*sequence) == 0 {\n\t\tif fallback == nil || fallback.length.Cmp(oneRat) == 0 {\n\t\t\t// There is no sequence or a segment, so it means the whole test run\n\t\t\t// is being planned/executed. So we make sure not to have a nil\n\t\t\t// sequence, returning a full; \"0,1\" sequence instead, otherwise we\n\t\t\t// will need to check for nil everywhere...\n\t\t\treturn ExecutionSegmentSequence{newExecutionSegment(zeroRat, oneRat)}\n\t\t}\n\t\t// We don't have a sequence, but we have a defined segment, so we\n\t\t// fill around it with the missing pieces for a full sequence.\n\t\tresult = ExecutionSegmentSequence{fallback}\n\t} else {\n\t\tresult = *sequence\n\t}\n\n\tif result[0].from.Cmp(zeroRat) != 0 {\n\t\tes := newExecutionSegment(zeroRat, result[0].from)\n\t\tresult = append(ExecutionSegmentSequence{es}, result...)\n\t}\n\n\tif result[len(result)-1].to.Cmp(oneRat) != 0 {\n\t\tes := newExecutionSegment(result[len(result)-1].to, oneRat)\n\t\tresult = append(result, es)\n\t}\n\treturn result\n}\n\n// ExecutionSegmentSequenceWrapper is a caching layer on top of the execution\n// segment sequence that allows us to make fast and useful calculations, after\n// a somewhat slow initialization.\ntype ExecutionSegmentSequenceWrapper struct {\n\tExecutionSegmentSequence       // a filled-out segment sequence\n\tlcd                      int64 // pre-calculated least common denominator\n\n\t// The striped offsets, i.e. the repeating indexes that \"belong\" to each\n\t// execution segment in the sequence.\n\toffsets [][]int64\n}\n\n// NewExecutionSegmentSequenceWrapper expects a filled-out execution segment\n// sequence. It pre-calculates the initial caches of and returns a new\n// ExecutionSegmentSequenceWrapper, but doesn't calculate the striped offsets.\nfunc NewExecutionSegmentSequenceWrapper(ess ExecutionSegmentSequence) *ExecutionSegmentSequenceWrapper {\n\tif !ess.IsFull() {\n\t\tpanic(fmt.Sprintf(\"Cannot wrap around a non-full execution segment sequence '%s'\", ess))\n\t}\n\n\tsequenceLength := len(ess)\n\toffsets := make([][]int64, sequenceLength)\n\tlcd := ess.LCD()\n\n\t// This will contain the normalized numerator values (i.e. what they would have\n\t// been if all denominators were equal to the LCD), sorted in descending\n\t// order (i.e. biggest segments are first), with references to their actual\n\t// indexes in the execution segment sequence (i.e. `seq` above).\n\tsortedNormalizedIndexes := make([]struct {\n\t\tnormNumerator int64\n\t\toriginalIndex int\n\t}, sequenceLength)\n\n\tfor i := range ess {\n\t\tnormalizedNumerator := ess[i].length.Num().Int64() * (lcd / ess[i].length.Denom().Int64())\n\t\tsortedNormalizedIndexes[i].normNumerator = normalizedNumerator\n\t\tsortedNormalizedIndexes[i].originalIndex = i\n\t\toffsets[i] = make([]int64, 0, normalizedNumerator+1)\n\t}\n\n\tsort.SliceStable(sortedNormalizedIndexes, func(i, j int) bool {\n\t\treturn sortedNormalizedIndexes[i].normNumerator > sortedNormalizedIndexes[j].normNumerator\n\t})\n\n\t// This is the striping algorithm. Imagine you have a number of rational\n\t// numbers which all add up to 1 (or less), and call them segments. If you\n\t// want each to get proportional amount of anything, you need to give them\n\t// their numerator count of elements for each denominator amount from the\n\t// original elements. So, for 1/3, you give 1 element for each 3 elements.\n\t// For 3/5 - 3 elements for each 5. If you have, for example, a sequence\n\t// with elements with length 3/5 and 1/3, in order to know how to distribute\n\t// it accurately, you need to get the LCD(lowest common denominitor). In\n\t// this case, between 3 and 5, the LCD is 15. Then to transform the numbers\n\t// to have the same, LCD equal, denominator. So 3/5 becomes 9/15 and 1/3\n\t// becomes 5/15. So now for each 15 elements 9 need to go to the 3/5, and 5\n\t// need to go to 1/3. This is what we did above in sortedNormalizedIndexes.\n\t//\n\t// We use the algorithm below to split elements between ExecutionSegments by\n\t// using their length as the rational number. As we would like to get\n\t// non-sequential elements, we try to get the maximum distance between them.\n\t// That is the number of elements divided by the number of elements for any\n\t// given segment, which concidently is the length of the segment reversed.\n\t// The algorithm below does the following:\n\t//  1. Goes through the elements from 0 to the lcd-1\n\t//  2. For each of element, it goes through the segments and looks if the\n\t//     amount of already taken elements by the given segment, multiplied by\n\t//     that segment's length inverted, is equal to or less to the current\n\t//     element index. If it is, give that element to that segment. If not,\n\t//     continue with the next element.\n\t// The code below specifically avoids using big.Rat, for performance\n\t// reasons, which complicates the code somewhat. As additional note, the\n\t// sorting of the segments from biggest to smallest helps with the fact that\n\t// the biggest elements will need to take the most elements, and for them it\n\t// will be the hardest to not get sequential elements.\n\tprev := make([]int64, sequenceLength)\n\tchosenCounts := make([]int64, sequenceLength)\n\tsaveIndex := func(iteration int64, index int, numerator int64) {\n\t\toffsets[index] = append(offsets[index], iteration-prev[index])\n\t\tprev[index] = iteration\n\t\tif int64(len(offsets[index])) == numerator {\n\t\t\toffsets[index] = append(offsets[index], offsets[index][0]+lcd-iteration)\n\t\t}\n\t}\n\tfor i := range lcd {\n\t\tfor sortedIndex, chosenCount := range chosenCounts {\n\t\t\tnum := chosenCount * lcd\n\t\t\tdenom := sortedNormalizedIndexes[sortedIndex].normNumerator\n\t\t\tif i > num/denom || (i == num/denom && num%denom == 0) {\n\t\t\t\tchosenCounts[sortedIndex]++\n\t\t\t\tsaveIndex(i, sortedNormalizedIndexes[sortedIndex].originalIndex, denom)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn &ExecutionSegmentSequenceWrapper{ExecutionSegmentSequence: ess, lcd: lcd, offsets: offsets}\n}\n\n// LCD returns the (cached) least common denominator of the sequence - no need\n// to calculate it again, since we did it in the constructor.\nfunc (essw *ExecutionSegmentSequenceWrapper) LCD() int64 {\n\treturn essw.lcd\n}\n\n// ScaleInt64 scales the provided value for the given segment.\nfunc (essw *ExecutionSegmentSequenceWrapper) ScaleInt64(segmentIndex int, value int64) int64 {\n\tstart := essw.offsets[segmentIndex][0]\n\toffsets := essw.offsets[segmentIndex][1:]\n\tresult := (value / essw.lcd) * int64(len(offsets))\n\tfor gi, i := 0, start; i < value%essw.lcd; gi, i = gi+1, i+offsets[gi] {\n\t\tresult++\n\t}\n\treturn result\n}\n\n// GetStripedOffsets returns the stripped offsets for the given segment\n// the returned values are as follows in order:\n//   - start: the first value that is for the segment\n//   - offsets: a list of offsets from the previous value for the segment. This are only the offsets\n//     to from the start to the next start if we chunk the elements we are going to strip\n//     into lcd sized chunks\n//   - lcd: the LCD of the lengths of all segments in the sequence. This is also the number of\n//     elements after which the algorithm starts to loop and give the same values\nfunc (essw *ExecutionSegmentSequenceWrapper) GetStripedOffsets(segmentIndex int) (int64, []int64, int64) {\n\toffsets := essw.offsets[segmentIndex]\n\treturn offsets[0], offsets[1:], essw.lcd\n}\n\n// GetTuple returns an ExecutionTuple for the specified segment index.\nfunc (essw *ExecutionSegmentSequenceWrapper) GetTuple(segmentIndex int) *ExecutionTuple {\n\treturn &ExecutionTuple{\n\t\tSequence:     essw,\n\t\tSegment:      essw.ExecutionSegmentSequence[segmentIndex],\n\t\tSegmentIndex: segmentIndex,\n\t}\n}\n\n// GetNewExecutionSegmentSequenceFromValue uses the value provided, splits it\n// between all the segments, using the striping offsets in the sequence,\n// generating a new segment sequence. It then returns a new\n// ExecutionSegmentSequenceWrapper, with the new sequence and segments, such\n// that each new segment in the new sequence has length `Scale(value)/value`\n// while keeping the order.\n//\n// Additionally, the position of a given segment index can be tracked (since\n// empty segments are removed), so that you can reconstruct an ExecutionTuple,\n// if required. If the segment with the trackedIndex is not part of the new\n// sequence, or if a new sequence cannot be generated (for example, for 0\n// values), an error will be returned.\nfunc (essw *ExecutionSegmentSequenceWrapper) GetNewExecutionSegmentSequenceFromValue(value int64, trackedIndex int) (\n\tnewSequence *ExecutionSegmentSequenceWrapper, newIndex int, err error,\n) {\n\tif value < 1 {\n\t\treturn nil, -1, fmt.Errorf(\"cannot generate new sequence for value %d\", value)\n\t}\n\n\tif value%essw.lcd == 0 { // the value is perfectly divisible so we will get the same tuple\n\t\treturn essw, trackedIndex, nil\n\t}\n\n\tnewIndex = -1\n\tnewESS := make(ExecutionSegmentSequence, 0, len(essw.ExecutionSegmentSequence)) // this can be smaller\n\n\tprev := int64(0)\n\tfor i := range essw.ExecutionSegmentSequence {\n\t\tnewValue := essw.ScaleInt64(i, value)\n\t\tif newValue == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tcurrentES := newExecutionSegment(big.NewRat(prev, value), big.NewRat(prev+newValue, value))\n\t\tprev += newValue\n\t\tif i == trackedIndex {\n\t\t\tnewIndex = len(newESS)\n\t\t}\n\t\tnewESS = append(newESS, currentES)\n\t}\n\n\tif newIndex == -1 {\n\t\treturn nil, -1, fmt.Errorf(\n\t\t\t\"segment %d (%s) isn't present in the new sequence\",\n\t\t\ttrackedIndex, essw.ExecutionSegmentSequence[trackedIndex],\n\t\t)\n\t}\n\n\treturn NewExecutionSegmentSequenceWrapper(newESS), newIndex, nil\n}\n\n// ExecutionTuple is the combination of an ExecutionSegmentSequence(Wrapper) and\n// a specific ExecutionSegment from it. It gives easy access to the efficient\n// scaling and striping algorithms for that specific segment, since the results\n// are cached in the sequence wrapper. It is also the basis for the\n// SegmentedIndex type below, which is the actual implementation of a segmented\n// (striped) iterator, usable both for segmenting actual iterations and for\n// partitioning data between multiple instances.\n//\n// For example, let's try to segment a load test in 3 unequal parts: 50%, 25%\n// and 25% (so the ExecutionSegmentSequence will contain these segments: 0:1/2,\n// 1/2:3/4, 3/4:1). The building blocks that k6 needs for distributed execution\n// are segmented (non-overlapping) iterators and proportionally dividing integer\n// numbers as fairly as possible between multiple segments in a stable manner.\n//\n// The segmented iterators (i.e. SegmentedIndex values below) will be like this:\n//\n//\tNormal iterator:              0   1   2   3   4   5   6   7   8   9   10  11 ...\n//\tInstance 1 (0:1/2) iterator:  0       2       4       6       8       10     ...\n//\tInstance 2 (1/2:3/4) iterator:    1               5               9          ...\n//\tInstance 2 (3/4:1) iterator:              3               7               11 ...\n//\n// See how every instance has its own uniqe non-overlapping iterator, but when\n// we combine all of them, we cover every possible value in the original one.\n//\n// We also can use this property to scale integer numbers proportionally, as\n// fairly as possible, between the instances, like this:\n//\n//\tGlobal int value to scale:    1   2   3   4   5   6   7   8   9   10  11  12 ...\n//\tCalling ScaleInt64():\n//\t- Instance 1 (0:1/2) value:   1   1   2   2   3   3   4   4   5   5   6   6  ...\n//\t- Instance 2 (1/2:3/4) value: 0   1   1   1   1   2   2   2   2   3   3   3  ...\n//\t- Instance 2 (3/4:1) value:   0   0   0   1   1   1   1   2   2   2   2   3  ...\n//\n// Notice how the sum of the per-instance values is always equal to the global\n// value - this is what ExecutionTuple.ScaleInt64() does. Also compare both\n// tables (their positions match), see how we only increment the value for a\n// particular instance when we would have cycled the iterator on that step.\n//\n// This also makes the scaling stable, in contrast to ExecutionSegment.Scale().\n// Scaled values will only ever increase, since we just increment them in a\n// specific order between instances. There will never be a situation where\n// `ScaleInt64(i)` is less than `ScaleInt64(i+n)` for any positive n!\n//\n// The algorithm that calculates the offsets and everything that's necessary to\n// have these segmented iterators is in NewExecutionSegmentSequenceWrapper().\n// The ExecutionTuple simply exposes them efficiently for a single segment of\n// the sequence, so it's the thing that most users will probably need.\ntype ExecutionTuple struct { // TODO rename? make fields private and have getter methods?\n\tSequence     *ExecutionSegmentSequenceWrapper\n\tSegment      *ExecutionSegment\n\tSegmentIndex int\n}\n\nfunc (et *ExecutionTuple) String() string {\n\treturn fmt.Sprintf(\"%s in %s\", et.Segment, et.Sequence)\n}\n\n// NewExecutionTuple returns a new ExecutionTuple for the provided segment and\n// sequence.\n//\n// TODO: don't return a pointer?\nfunc NewExecutionTuple(segment *ExecutionSegment, sequence *ExecutionSegmentSequence) (*ExecutionTuple, error) {\n\tfilledSeq := GetFilledExecutionSegmentSequence(sequence, segment)\n\twrapper := NewExecutionSegmentSequenceWrapper(filledSeq)\n\tindex, err := wrapper.FindSegmentPosition(segment)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ExecutionTuple{Sequence: wrapper, Segment: segment, SegmentIndex: index}, nil\n}\n\n// ScaleInt64 scales the provided value for our execution segment.\nfunc (et *ExecutionTuple) ScaleInt64(value int64) int64 {\n\tif len(et.Sequence.ExecutionSegmentSequence) == 1 {\n\t\treturn value // if we don't have any segmentation, just return the original value\n\t}\n\treturn et.Sequence.ScaleInt64(et.SegmentIndex, value)\n}\n\n// GetStripedOffsets returns the striped offsets for our execution segment.\nfunc (et *ExecutionTuple) GetStripedOffsets() (int64, []int64, int64) {\n\treturn et.Sequence.GetStripedOffsets(et.SegmentIndex)\n}\n\n// GetNewExecutionTupleFromValue re-segments the sequence, based on the given\n// value (see GetNewExecutionSegmentSequenceFromValue() above), and either\n// returns the new tuple, or an error if the current segment isn't present in\n// the new sequence.\nfunc (et *ExecutionTuple) GetNewExecutionTupleFromValue(value int64) (*ExecutionTuple, error) {\n\tnewSequenceWrapper, newIndex, err := et.Sequence.GetNewExecutionSegmentSequenceFromValue(value, et.SegmentIndex)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ExecutionTuple{\n\t\tSequence:     newSequenceWrapper,\n\t\tSegment:      newSequenceWrapper.ExecutionSegmentSequence[newIndex],\n\t\tSegmentIndex: newIndex,\n\t}, nil\n}\n\n// SegmentedIndex is an iterator that returns both the scaled and the unscaled\n// sequential values according to the given ExecutionTuple. It is not\n// thread-safe, concurrent access has to be externally synchronized.\n//\n// See the documentation for ExecutionTuple above for a visual explanation of\n// how this iterator actually works.\ntype SegmentedIndex struct {\n\tstart, lcd       int64\n\toffsets          []int64\n\tscaled, unscaled int64 // for both the first element(vu) is 1 not 0\n}\n\n// NewSegmentedIndex returns a pointer to a new SegmentedIndex instance,\n// given an ExecutionTuple.\nfunc NewSegmentedIndex(et *ExecutionTuple) *SegmentedIndex {\n\tstart, offsets, lcd := et.GetStripedOffsets()\n\treturn &SegmentedIndex{start: start, lcd: lcd, offsets: offsets}\n}\n\n// Next goes to the next scaled index and moves the unscaled one accordingly.\nfunc (s *SegmentedIndex) Next() (int64, int64) {\n\tif s.scaled == 0 { // the 1 element(VU) is at the start\n\t\ts.unscaled += s.start + 1 // the first element of the start 0, but the here we need it to be 1 so we add 1\n\t} else { // if we are not at the first element we need to go through the offsets, looping over them\n\t\ts.unscaled += s.offsets[int(s.scaled-1)%len(s.offsets)] // slice's index start at 0 ours start at 1\n\t}\n\ts.scaled++\n\n\treturn s.scaled, s.unscaled\n}\n\n// Prev goes to the previous scaled value and sets the unscaled one accordingly.\n// Calling Prev when s.scaled == 0 is undefined.\nfunc (s *SegmentedIndex) Prev() (int64, int64) {\n\tif s.scaled == 1 { // we are the first need to go to the 0th element which means we need to remove the start\n\t\ts.unscaled -= s.start + 1 // this could've been just settign to 0\n\t} else { // not at the first element - need to get the previously added offset so\n\t\ts.unscaled -= s.offsets[int(s.scaled-2)%len(s.offsets)] // slice's index start 0 our start at 1\n\t}\n\ts.scaled--\n\n\treturn s.scaled, s.unscaled\n}\n\n// GoTo sets the scaled index to its biggest value for which the corresponding\n// unscaled index is smaller or equal to value.\nfunc (s *SegmentedIndex) GoTo(value int64) (int64, int64) { // TODO optimize\n\tvar gi int64\n\t// Because of the cyclical nature of the striping algorithm (with a cycle\n\t// length of LCD, the least common denominator), when scaling large values\n\t// (i.e. many multiples of the LCD), we can quickly calculate how many times\n\t// the cycle repeats.\n\twholeCycles := (value / s.lcd)\n\t// So we can set some approximate initial values quickly, since we also know\n\t// precisely how many scaled values there are per cycle length.\n\ts.scaled = wholeCycles * int64(len(s.offsets))\n\ts.unscaled = wholeCycles*s.lcd + s.start + 1 // our indexes are from 1 the start is from 0\n\t// Approach the final value using the slow algorithm with the step by step loop\n\t// TODO: this can be optimized by another array with size offsets that instead of the offsets\n\t// from the previous is the offset from either 0 or start\n\ti := s.start\n\tfor ; i < value%s.lcd; gi, i = gi+1, i+s.offsets[gi] {\n\t\ts.scaled++\n\t\ts.unscaled += s.offsets[gi]\n\t}\n\n\tif gi > 0 { // there were more values after the wholecycles\n\t\t// the last offset actually shouldn't have been added\n\t\ts.unscaled -= s.offsets[gi-1]\n\t} else if s.scaled > 0 { // we didn't actually have more values after the wholecycles but we still had some\n\t\t// in this case the unscaled value needs to move back by the last offset as it would've been\n\t\t// the one to get it from the value it needs to be to it's current one\n\t\ts.unscaled -= s.offsets[len(s.offsets)-1]\n\t}\n\n\tif s.scaled == 0 {\n\t\ts.unscaled = 0 // we would've added the start and 1\n\t}\n\n\treturn s.scaled, s.unscaled\n}\n"
  },
  {
    "path": "lib/execution_segment_test.go",
    "content": "package lib\n\nimport (\n\t\"fmt\"\n\t\"math/big\"\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc stringToES(t *testing.T, str string) *ExecutionSegment {\n\tes := new(ExecutionSegment)\n\trequire.NoError(t, es.UnmarshalText([]byte(str)))\n\treturn es\n}\n\nfunc TestExecutionSegmentEquals(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"nil segment to full\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tvar nilEs *ExecutionSegment\n\t\tfullEs := stringToES(t, \"0:1\")\n\t\trequire.True(t, nilEs.Equal(fullEs))\n\t\trequire.True(t, fullEs.Equal(nilEs))\n\t})\n\n\tt.Run(\"To it's self\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tes := stringToES(t, \"1/2:2/3\")\n\t\trequire.True(t, es.Equal(es)) //nolint:gocritic\n\t})\n}\n\nfunc TestExecutionSegmentNew(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"from is below zero\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := NewExecutionSegment(big.NewRat(-1, 1), big.NewRat(1, 1))\n\t\trequire.Error(t, err)\n\t})\n\tt.Run(\"to is more than 1\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := NewExecutionSegment(big.NewRat(0, 1), big.NewRat(2, 1))\n\t\trequire.Error(t, err)\n\t})\n\tt.Run(\"from is smaller than to\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := NewExecutionSegment(big.NewRat(1, 2), big.NewRat(1, 3))\n\t\trequire.Error(t, err)\n\t})\n\n\tt.Run(\"from is equal to 'to'\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := NewExecutionSegment(big.NewRat(1, 2), big.NewRat(1, 2))\n\t\trequire.Error(t, err)\n\t})\n\tt.Run(\"ok\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, err := NewExecutionSegment(big.NewRat(0, 1), big.NewRat(1, 1))\n\t\trequire.NoError(t, err)\n\t})\n}\n\nfunc TestExecutionSegmentUnmarshalText(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tinput  string\n\t\toutput *ExecutionSegment\n\t\tisErr  bool\n\t}{\n\t\t{input: \"0:1\", output: &ExecutionSegment{from: zeroRat, to: oneRat}},\n\t\t{input: \"0.5:0.75\", output: &ExecutionSegment{from: big.NewRat(1, 2), to: big.NewRat(3, 4)}},\n\t\t{input: \"1/2:3/4\", output: &ExecutionSegment{from: big.NewRat(1, 2), to: big.NewRat(3, 4)}},\n\t\t{input: \"50%:75%\", output: &ExecutionSegment{from: big.NewRat(1, 2), to: big.NewRat(3, 4)}},\n\t\t{input: \"2/4:75%\", output: &ExecutionSegment{from: big.NewRat(1, 2), to: big.NewRat(3, 4)}},\n\t\t{input: \"75%\", output: &ExecutionSegment{from: zeroRat, to: big.NewRat(3, 4)}},\n\t\t{input: \"125%\", isErr: true},\n\t\t{input: \"1a5%\", isErr: true},\n\t\t{input: \"1a5\", isErr: true},\n\t\t{input: \"1a5%:2/3\", isErr: true},\n\t\t{input: \"125%:250%\", isErr: true},\n\t\t{input: \"55%:50%\", isErr: true},\n\t\t// TODO add more strange or not so strange cases\n\t}\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.input, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tes := new(ExecutionSegment)\n\t\t\terr := es.UnmarshalText([]byte(testCase.input))\n\t\t\tif testCase.isErr {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.True(t, es.Equal(testCase.output))\n\n\t\t\t// see if unmarshalling a stringified segment gets you back the same segment\n\t\t\terr = es.UnmarshalText([]byte(es.String()))\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.True(t, es.Equal(testCase.output))\n\t\t})\n\t}\n\n\tt.Run(\"Unmarshal nilSegment.String\", func(t *testing.T) {\n\t\tvar nilEs *ExecutionSegment\n\t\tnilEsStr := nilEs.String()\n\t\trequire.Equal(t, \"0:1\", nilEsStr)\n\n\t\tes := new(ExecutionSegment)\n\t\terr := es.UnmarshalText([]byte(nilEsStr))\n\t\trequire.NoError(t, err)\n\t\trequire.True(t, es.Equal(nilEs))\n\t})\n}\n\nfunc TestExecutionSegmentSplit(t *testing.T) {\n\tt.Parallel()\n\n\tvar nilEs *ExecutionSegment\n\t_, err := nilEs.Split(-1)\n\trequire.Error(t, err)\n\n\t_, err = nilEs.Split(0)\n\trequire.Error(t, err)\n\n\tsegments, err := nilEs.Split(1)\n\trequire.NoError(t, err)\n\trequire.Len(t, segments, 1)\n\tassert.Equal(t, \"0:1\", segments[0].String())\n\n\tsegments, err = nilEs.Split(2)\n\trequire.NoError(t, err)\n\trequire.Len(t, segments, 2)\n\tassert.Equal(t, \"0:1/2\", segments[0].String())\n\tassert.Equal(t, \"1/2:1\", segments[1].String())\n\n\tsegments, err = nilEs.Split(3)\n\trequire.NoError(t, err)\n\trequire.Len(t, segments, 3)\n\tassert.Equal(t, \"0:1/3\", segments[0].String())\n\tassert.Equal(t, \"1/3:2/3\", segments[1].String())\n\tassert.Equal(t, \"2/3:1\", segments[2].String())\n\n\tsecondQuarter, err := NewExecutionSegment(big.NewRat(1, 4), big.NewRat(2, 4))\n\trequire.NoError(t, err)\n\n\tsegments, err = secondQuarter.Split(1)\n\trequire.NoError(t, err)\n\trequire.Len(t, segments, 1)\n\tassert.Equal(t, \"1/4:1/2\", segments[0].String())\n\n\tsegments, err = secondQuarter.Split(2)\n\trequire.NoError(t, err)\n\trequire.Len(t, segments, 2)\n\tassert.Equal(t, \"1/4:3/8\", segments[0].String())\n\tassert.Equal(t, \"3/8:1/2\", segments[1].String())\n\n\tsegments, err = secondQuarter.Split(3)\n\trequire.NoError(t, err)\n\trequire.Len(t, segments, 3)\n\tassert.Equal(t, \"1/4:1/3\", segments[0].String())\n\tassert.Equal(t, \"1/3:5/12\", segments[1].String())\n\tassert.Equal(t, \"5/12:1/2\", segments[2].String())\n\n\tsegments, err = secondQuarter.Split(4)\n\trequire.NoError(t, err)\n\trequire.Len(t, segments, 4)\n\tassert.Equal(t, \"1/4:5/16\", segments[0].String())\n\tassert.Equal(t, \"5/16:3/8\", segments[1].String())\n\tassert.Equal(t, \"3/8:7/16\", segments[2].String())\n\tassert.Equal(t, \"7/16:1/2\", segments[3].String())\n}\n\nfunc TestExecutionSegmentFailures(t *testing.T) {\n\tt.Parallel()\n\tes := new(ExecutionSegment)\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0:0.25\")))\n\trequire.Equal(t, int64(1), es.Scale(2))\n\trequire.Equal(t, int64(1), es.Scale(3))\n\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.25:0.5\")))\n\trequire.Equal(t, int64(0), es.Scale(2))\n\trequire.Equal(t, int64(1), es.Scale(3))\n\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5:0.75\")))\n\trequire.Equal(t, int64(1), es.Scale(2))\n\trequire.Equal(t, int64(0), es.Scale(3))\n\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.75:1\")))\n\trequire.Equal(t, int64(0), es.Scale(2))\n\trequire.Equal(t, int64(1), es.Scale(3))\n}\n\nfunc TestExecutionTupleScale(t *testing.T) {\n\tt.Parallel()\n\tes := new(ExecutionSegment)\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5\")))\n\tet, err := NewExecutionTuple(es, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, int64(1), et.ScaleInt64(2))\n\trequire.Equal(t, int64(2), et.ScaleInt64(3))\n\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5:1.0\")))\n\tet, err = NewExecutionTuple(es, nil)\n\trequire.NoError(t, err)\n\trequire.Equal(t, int64(1), et.ScaleInt64(2))\n\trequire.Equal(t, int64(1), et.ScaleInt64(3))\n\n\tess, err := NewExecutionSegmentSequenceFromString(\"0,0.5,1\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5\")))\n\tet, err = NewExecutionTuple(es, &ess)\n\trequire.NoError(t, err)\n\trequire.Equal(t, int64(1), et.ScaleInt64(2))\n\trequire.Equal(t, int64(2), et.ScaleInt64(3))\n\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5:1.0\")))\n\tet, err = NewExecutionTuple(es, &ess)\n\trequire.NoError(t, err)\n\trequire.Equal(t, int64(1), et.ScaleInt64(2))\n\trequire.Equal(t, int64(1), et.ScaleInt64(3))\n}\n\nfunc TestBigScale(t *testing.T) {\n\tt.Parallel()\n\tes := new(ExecutionSegment)\n\tess, err := NewExecutionSegmentSequenceFromString(\"0,7/20,7/10,1\")\n\trequire.NoError(t, err)\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0:7/20\")))\n\tet, err := NewExecutionTuple(es, &ess)\n\trequire.NoError(t, err)\n\trequire.Equal(t, int64(18), et.ScaleInt64(50))\n}\n\nfunc TestExecutionSegmentCopyScaleRat(t *testing.T) {\n\tt.Parallel()\n\tes := new(ExecutionSegment)\n\ttwoRat := big.NewRat(2, 1)\n\tthreeRat := big.NewRat(3, 1)\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5\")))\n\trequire.Equal(t, oneRat, es.CopyScaleRat(twoRat))\n\trequire.Equal(t, big.NewRat(3, 2), es.CopyScaleRat(threeRat))\n\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5:1.0\")))\n\trequire.Equal(t, oneRat, es.CopyScaleRat(twoRat))\n\trequire.Equal(t, big.NewRat(3, 2), es.CopyScaleRat(threeRat))\n\n\tvar nilEs *ExecutionSegment\n\trequire.Equal(t, twoRat, nilEs.CopyScaleRat(twoRat))\n\trequire.Equal(t, threeRat, nilEs.CopyScaleRat(threeRat))\n}\n\nfunc TestExecutionSegmentInPlaceScaleRat(t *testing.T) {\n\tt.Parallel()\n\tes := new(ExecutionSegment)\n\ttwoRat := big.NewRat(2, 1)\n\tthreeRat := big.NewRat(3, 1)\n\tthreeSecondsRat := big.NewRat(3, 2)\n\trequire.NoError(t, es.UnmarshalText([]byte(\"0.5\")))\n\trequire.Equal(t, oneRat, es.InPlaceScaleRat(twoRat))\n\trequire.Equal(t, oneRat, twoRat)\n\trequire.Equal(t, threeSecondsRat, es.InPlaceScaleRat(threeRat))\n\trequire.Equal(t, threeSecondsRat, threeRat)\n\n\tes = stringToES(t, \"0.5:1.0\")\n\ttwoRat = big.NewRat(2, 1)\n\tthreeRat = big.NewRat(3, 1)\n\trequire.Equal(t, oneRat, es.InPlaceScaleRat(twoRat))\n\trequire.Equal(t, oneRat, twoRat)\n\trequire.Equal(t, threeSecondsRat, es.InPlaceScaleRat(threeRat))\n\trequire.Equal(t, threeSecondsRat, threeRat)\n\n\tvar nilEs *ExecutionSegment\n\ttwoRat = big.NewRat(2, 1)\n\tthreeRat = big.NewRat(3, 1)\n\trequire.Equal(t, big.NewRat(2, 1), nilEs.InPlaceScaleRat(twoRat))\n\trequire.Equal(t, big.NewRat(2, 1), twoRat)\n\trequire.Equal(t, big.NewRat(3, 1), nilEs.InPlaceScaleRat(threeRat))\n\trequire.Equal(t, big.NewRat(3, 1), threeRat)\n}\n\nfunc TestExecutionSegmentSubSegment(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tname              string\n\t\tbase, sub, result *ExecutionSegment\n\t}{\n\t\t// TODO add more strange or not so strange cases\n\t\t{\n\t\t\tname:   \"nil base\",\n\t\t\tbase:   (*ExecutionSegment)(nil),\n\t\t\tsub:    stringToES(t, \"0.2:0.3\"),\n\t\t\tresult: stringToES(t, \"0.2:0.3\"),\n\t\t},\n\n\t\t{\n\t\t\tname:   \"nil sub\",\n\t\t\tbase:   stringToES(t, \"0.2:0.3\"),\n\t\t\tsub:    (*ExecutionSegment)(nil),\n\t\t\tresult: stringToES(t, \"0.2:0.3\"),\n\t\t},\n\t\t{\n\t\t\tname:   \"doc example\",\n\t\t\tbase:   stringToES(t, \"1/2:1\"),\n\t\t\tsub:    stringToES(t, \"0:1/2\"),\n\t\t\tresult: stringToES(t, \"1/2:3/4\"),\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trequire.Equal(t, testCase.result, testCase.base.SubSegment(testCase.sub))\n\t\t})\n\t}\n}\n\nfunc TestSplitBadSegment(t *testing.T) {\n\tt.Parallel()\n\tes := &ExecutionSegment{from: oneRat, to: zeroRat}\n\t_, err := es.Split(5)\n\trequire.Error(t, err)\n}\n\nfunc TestSegmentExecutionFloatLength(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"nil has 1.0\", func(t *testing.T) {\n\t\tvar nilEs *ExecutionSegment\n\t\trequire.Equal(t, 1.0, nilEs.FloatLength())\n\t})\n\n\ttestCases := []struct {\n\t\tes       *ExecutionSegment\n\t\texpected float64\n\t}{\n\t\t// TODO add more strange or not so strange cases\n\t\t{\n\t\t\tes:       stringToES(t, \"1/2:1\"),\n\t\t\texpected: 0.5,\n\t\t},\n\t\t{\n\t\t\tes:       stringToES(t, \"1/3:1\"),\n\t\t\texpected: 0.66666,\n\t\t},\n\n\t\t{\n\t\t\tes:       stringToES(t, \"0:1/2\"),\n\t\t\texpected: 0.5,\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tt.Run(testCase.es.String(), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trequire.InEpsilon(t, testCase.expected, testCase.es.FloatLength(), 0.001)\n\t\t})\n\t}\n}\n\nfunc TestExecutionSegmentSequences(t *testing.T) {\n\tt.Parallel()\n\n\t_, err := NewExecutionSegmentSequence(stringToES(t, \"0:1/3\"), stringToES(t, \"1/2:1\"))\n\tassert.Error(t, err)\n}\n\nfunc TestExecutionSegmentStringSequences(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tseq         string\n\t\texpSegments []string\n\t\texpError    bool\n\t\tcanReverse  bool\n\t\t// TODO: checks for least common denominator and maybe striped partitioning\n\t}{\n\t\t{seq: \"\", expSegments: nil},\n\t\t{seq: \"0.5\", expError: true},\n\t\t{seq: \"1,1\", expError: true},\n\t\t{seq: \"-0.5,1\", expError: true},\n\t\t{seq: \"1/2,1/2\", expError: true},\n\t\t{seq: \"1/2,1/3\", expError: true},\n\t\t{seq: \"0,1,1/2\", expError: true},\n\t\t{seq: \"0.5,1\", expSegments: []string{\"1/2:1\"}},\n\t\t{seq: \"1/2,1\", expSegments: []string{\"1/2:1\"}, canReverse: true},\n\t\t{seq: \"1/3,2/3\", expSegments: []string{\"1/3:2/3\"}, canReverse: true},\n\t\t{seq: \"0,1/3,2/3\", expSegments: []string{\"0:1/3\", \"1/3:2/3\"}, canReverse: true},\n\t\t{seq: \"0,1/3,2/3,1\", expSegments: []string{\"0:1/3\", \"1/3:2/3\", \"2/3:1\"}, canReverse: true},\n\t\t{seq: \"0.5,0.7\", expSegments: []string{\"1/2:7/10\"}},\n\t\t{seq: \"0.5,0.7,1\", expSegments: []string{\"1/2:7/10\", \"7/10:1\"}},\n\t\t{seq: \"0,1/13,2/13,1/3,1/2,3/4,1\", expSegments: []string{\n\t\t\t\"0:1/13\", \"1/13:2/13\", \"2/13:1/3\", \"1/3:1/2\", \"1/2:3/4\", \"3/4:1\",\n\t\t}, canReverse: true},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.seq, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tresult, err := NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\tif tc.expError {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, len(tc.expSegments), len(result))\n\t\t\tfor i, expStrSeg := range tc.expSegments {\n\t\t\t\texpSeg, errl := NewExecutionSegmentFromString(expStrSeg)\n\t\t\t\trequire.NoError(t, errl)\n\t\t\t\tassert.Truef(t, expSeg.Equal(result[i]), \"Segment %d (%s) should be equal to %s\", i, result[i], expSeg)\n\t\t\t}\n\t\t\tif tc.canReverse {\n\t\t\t\tassert.Equal(t, result.String(), tc.seq)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc getTestRand(t testing.TB) *rand.Rand {\n\tt.Helper()\n\tseed := time.Now().UnixNano()\n\tr := rand.New(rand.NewSource(seed))\n\tt.Logf(\"Random source seeded with %d\\n\", seed)\n\treturn r\n}\n\n// Return a randomly distributed sequence of n amount of\n// execution segments whose length totals 1.\nfunc generateRandomSequence(t testing.TB, n, m int64, r *rand.Rand) ExecutionSegmentSequence {\n\tvar err error\n\tess := ExecutionSegmentSequence(make([]*ExecutionSegment, n))\n\tnumerators := make([]int64, n)\n\tvar denominator int64\n\tfor i := range n {\n\t\tnumerators[i] = 1 + r.Int63n(m)\n\t\tdenominator += numerators[i]\n\t}\n\tfrom := big.NewRat(0, 1)\n\tfor i := range n {\n\t\tto := new(big.Rat).Add(big.NewRat(numerators[i], denominator), from)\n\t\tess[i], err = NewExecutionSegment(from, to)\n\t\trequire.NoError(t, err)\n\t\tfrom = to\n\t}\n\n\treturn ess\n}\n\n// Ensure that the sum of scaling all execution segments in\n// the same sequence with scaling factor M results in M itself.\nfunc TestExecutionSegmentScaleConsistency(t *testing.T) {\n\tt.Parallel()\n\n\tr := getTestRand(t)\n\n\tconst numTests = 10\n\tfor range numTests {\n\t\tscale := r.Int31n(99) + 2\n\t\tseq := generateRandomSequence(t, r.Int63n(9)+2, 100, r)\n\n\t\tt.Run(fmt.Sprintf(\"%d_%s\", scale, seq), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar total int64\n\t\t\tfor _, segment := range seq {\n\t\t\t\ttotal += segment.Scale(int64(scale))\n\t\t\t}\n\t\t\tassert.Equal(t, int64(scale), total)\n\t\t})\n\t}\n}\n\n// Ensure that the sum of scaling all execution segments in\n// the same sequence with scaling factor M results in M itself.\nfunc TestExecutionTupleScaleConsistency(t *testing.T) {\n\tt.Parallel()\n\n\tr := getTestRand(t)\n\tconst numTests = 10\n\tfor range numTests {\n\t\tscale := r.Int31n(99) + 2\n\t\tseq := generateRandomSequence(t, r.Int63n(9)+2, 200, r)\n\n\t\tet, err := NewExecutionTuple(seq[0], &seq)\n\t\trequire.NoError(t, err)\n\t\tt.Run(fmt.Sprintf(\"%d_%s\", scale, seq), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar total int64\n\t\t\tfor i, segment := range seq {\n\t\t\t\tassert.True(t, segment.Equal(et.Sequence.ExecutionSegmentSequence[i]))\n\t\t\t\ttotal += et.Sequence.ScaleInt64(i, int64(scale))\n\t\t\t}\n\t\t\tassert.Equal(t, int64(scale), total)\n\t\t})\n\t}\n}\n\nfunc TestExecutionSegmentScaleNoWobble(t *testing.T) {\n\tt.Parallel()\n\n\trequireSegmentScaleGreater := func(t *testing.T, et *ExecutionTuple) {\n\t\tvar i, lastResult int64\n\t\tfor i = 1; i < 1000; i++ {\n\t\t\tresult := et.ScaleInt64(i)\n\t\t\trequire.True(t, result >= lastResult, \"%d<%d\", result, lastResult)\n\t\t\tlastResult = result\n\t\t}\n\t}\n\n\t// Baseline full segment test\n\tt.Run(\"0:1\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tet, err := NewExecutionTuple(nil, nil)\n\t\trequire.NoError(t, err)\n\t\trequireSegmentScaleGreater(t, et)\n\t})\n\n\tr := getTestRand(t)\n\n\t// Random segments\n\tconst numTests = 10\n\tfor range numTests {\n\t\tseq := generateRandomSequence(t, r.Int63n(9)+2, 100, r)\n\n\t\tes := seq[r.Intn(len(seq))]\n\n\t\tet, err := NewExecutionTuple(seq[0], &seq)\n\t\trequire.NoError(t, err)\n\t\tt.Run(es.String(), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trequireSegmentScaleGreater(t, et)\n\t\t})\n\t}\n}\n\nfunc TestGetStripedOffsets(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tseq     string\n\t\tseg     string\n\t\tstart   int64\n\t\toffsets []int64\n\t\tlcd     int64\n\t}{\n\t\t// full sequences\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0:0.3\", start: 0, offsets: []int64{4, 3, 3}, lcd: 10},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.3:0.5\", start: 1, offsets: []int64{4, 6}, lcd: 10},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.5:0.6\", start: 2, offsets: []int64{10}, lcd: 10},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.6:0.7\", start: 3, offsets: []int64{10}, lcd: 10},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.8:0.9\", start: 8, offsets: []int64{10}, lcd: 10},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.9:1\", start: 9, offsets: []int64{10}, lcd: 10},\n\t\t{seq: \"0,0.2,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.9:1\", start: 9, offsets: []int64{10}, lcd: 10},\n\t\t{seq: \"0,0.2,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0:0.2\", start: 1, offsets: []int64{4, 6}, lcd: 10},\n\t\t{seq: \"0,0.2,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.6:0.7\", start: 3, offsets: []int64{10}, lcd: 10},\n\t\t// not full sequences\n\t\t{seq: \"0,0.2,0.5\", seg: \"0:0.2\", start: 3, offsets: []int64{6, 4}, lcd: 10},\n\t\t{seq: \"0,0.2,0.5\", seg: \"0.2:0.5\", start: 1, offsets: []int64{4, 2, 4}, lcd: 10},\n\t\t{seq: \"0,2/5,4/5\", seg: \"0:2/5\", start: 0, offsets: []int64{3, 2}, lcd: 5},\n\t\t{seq: \"0,2/5,4/5\", seg: \"2/5:4/5\", start: 1, offsets: []int64{3, 2}, lcd: 5},\n\t\t// no sequence\n\t\t{seg: \"0:0.2\", start: 1, offsets: []int64{5}, lcd: 5},\n\t\t{seg: \"0:1/5\", start: 1, offsets: []int64{5}, lcd: 5},\n\t\t{seg: \"0:2/10\", start: 1, offsets: []int64{5}, lcd: 5},\n\t\t{seg: \"0:0.4\", start: 1, offsets: []int64{2, 3}, lcd: 5},\n\t\t{seg: \"0:2/5\", start: 1, offsets: []int64{2, 3}, lcd: 5},\n\t\t{seg: \"2/5:4/5\", start: 1, offsets: []int64{3, 2}, lcd: 5},\n\t\t{seg: \"0:4/10\", start: 1, offsets: []int64{2, 3}, lcd: 5},\n\t\t{seg: \"1/10:5/10\", start: 1, offsets: []int64{2, 2, 4, 2}, lcd: 10},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"seq:%s;segment:%s\", tc.seq, tc.seg), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tess, err := NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\trequire.NoError(t, err)\n\t\t\tsegment, err := NewExecutionSegmentFromString(tc.seg)\n\t\t\trequire.NoError(t, err)\n\t\t\tet, err := NewExecutionTuple(segment, &ess)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tstart, offsets, lcd := et.GetStripedOffsets()\n\n\t\t\tassert.Equal(t, tc.start, start)\n\t\t\tassert.Equal(t, tc.offsets, offsets)\n\t\t\tassert.Equal(t, tc.lcd, lcd)\n\n\t\t\tess2, err := NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, ess.String(), ess2.String())\n\t\t})\n\t}\n}\n\nfunc TestSequenceLCD(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tseq string\n\t\tlcd int64\n\t}{\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", lcd: 10},\n\t\t{seq: \"0,0.1,0.5,0.6,0.7,0.8,0.9,1\", lcd: 10},\n\t\t{seq: \"0,0.2,0.5,0.6,0.7,0.8,0.9,1\", lcd: 10},\n\t\t{seq: \"0,1/3,5/6\", lcd: 6},\n\t\t{seq: \"0,1/3,4/7\", lcd: 21},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"seq:%s\", tc.seq), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tess, err := NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tc.lcd, ess.LCD())\n\t\t})\n\t}\n}\n\nfunc BenchmarkGetStripedOffsets(b *testing.B) {\n\tlengths := [...]int64{10, 100}\n\tconst seed = 777\n\tr := rand.New(rand.NewSource(seed))\n\n\tfor _, length := range lengths {\n\t\tb.Run(fmt.Sprintf(\"length%d,seed%d\", length, seed), func(b *testing.B) {\n\t\t\tsequence := generateRandomSequence(b, length, 100, r)\n\t\t\tb.ResetTimer()\n\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\tsegment := sequence[int(r.Int63())%len(sequence)]\n\t\t\t\tet, err := NewExecutionTuple(segment, &sequence)\n\t\t\t\trequire.NoError(b, err)\n\t\t\t\t_, _, _ = et.GetStripedOffsets()\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc BenchmarkGetStripedOffsetsEven(b *testing.B) {\n\tlengths := [...]int64{10, 100, 1000}\n\tgenerateSequence := func(n int64) ExecutionSegmentSequence {\n\t\tvar err error\n\t\tess := ExecutionSegmentSequence(make([]*ExecutionSegment, n))\n\t\tnumerators := make([]int64, n)\n\t\tvar denominator int64\n\t\tfor i := range n {\n\t\t\tnumerators[i] = 1 // nice and simple :)\n\t\t\tdenominator += numerators[i]\n\t\t}\n\t\tess[0], err = NewExecutionSegment(big.NewRat(0, 1), big.NewRat(numerators[0], denominator))\n\t\trequire.NoError(b, err)\n\t\tfor i := int64(1); i < n; i++ {\n\t\t\tess[i], err = NewExecutionSegment(ess[i-1].to, new(big.Rat).Add(big.NewRat(numerators[i], denominator), ess[i-1].to))\n\t\t\trequire.NoError(b, err, \"%d\", i)\n\t\t}\n\n\t\treturn ess\n\t}\n\n\tfor _, length := range lengths {\n\t\tb.Run(fmt.Sprintf(\"length%d\", length), func(b *testing.B) {\n\t\t\tsequence := generateSequence(length)\n\t\t\tb.ResetTimer()\n\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\tsegment := sequence[111233%len(sequence)]\n\t\t\t\tet, err := NewExecutionTuple(segment, &sequence)\n\t\t\t\trequire.NoError(b, err)\n\t\t\t\t_, _, _ = et.GetStripedOffsets()\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetNewExecutionTupleBesedOnValue(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tseq      string\n\t\tseg      string\n\t\tvalue    int64\n\t\texpected string\n\t}{\n\t\t// full sequences\n\t\t{seq: \"0,1/3,2/3,1\", seg: \"0:1/3\", value: 20, expected: \"0,7/20,7/10,1\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"seq:%s;segment:%s\", tc.seq, tc.seg), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tess, err := NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tsegment, err := NewExecutionSegmentFromString(tc.seg)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tet, err := NewExecutionTuple(segment, &ess)\n\t\t\trequire.NoError(t, err)\n\t\t\tnewET, err := et.GetNewExecutionTupleFromValue(tc.value)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, tc.expected, newET.Sequence.String())\n\t\t})\n\t}\n}\n\nfunc mustNewExecutionSegment(str string) *ExecutionSegment {\n\tres, err := NewExecutionSegmentFromString(str)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn res\n}\n\nfunc mustNewExecutionSegmentSequence(str string) *ExecutionSegmentSequence {\n\tres, err := NewExecutionSegmentSequenceFromString(str)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &res\n}\n\nfunc TestNewExecutionTuple(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tseg           *ExecutionSegment\n\t\tseq           *ExecutionSegmentSequence\n\t\tscaleTests    map[int64]int64\n\t\tnewScaleTests map[int64]map[int64]int64 // this is for after calling GetNewExecutionSegmentSequenceFromValue\n\t}{\n\t\t{\n\t\t\t// both segment and sequence are nil\n\t\t\tscaleTests: map[int64]int64{\n\t\t\t\t50: 50,\n\t\t\t\t1:  1,\n\t\t\t\t0:  0,\n\t\t\t},\n\t\t\tnewScaleTests: map[int64]map[int64]int64{\n\t\t\t\t50: {50: 50, 1: 1, 0: 0},\n\t\t\t\t1:  {50: 50, 1: 1, 0: 0},\n\t\t\t\t0:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tseg: mustNewExecutionSegment(\"0:1\"),\n\t\t\t// nil sequence\n\t\t\tscaleTests: map[int64]int64{\n\t\t\t\t50: 50,\n\t\t\t\t1:  1,\n\t\t\t\t0:  0,\n\t\t\t},\n\t\t\tnewScaleTests: map[int64]map[int64]int64{\n\t\t\t\t50: {50: 50, 1: 1, 0: 0},\n\t\t\t\t1:  {50: 50, 1: 1, 0: 0},\n\t\t\t\t0:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tseg: mustNewExecutionSegment(\"0:1\"),\n\t\t\tseq: mustNewExecutionSegmentSequence(\"0,1\"),\n\t\t\tscaleTests: map[int64]int64{\n\t\t\t\t50: 50,\n\t\t\t\t1:  1,\n\t\t\t\t0:  0,\n\t\t\t},\n\t\t\tnewScaleTests: map[int64]map[int64]int64{\n\t\t\t\t50: {50: 50, 1: 1, 0: 0},\n\t\t\t\t1:  {50: 50, 1: 1, 0: 0},\n\t\t\t\t0:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tseg: mustNewExecutionSegment(\"0:1\"),\n\t\t\tseq: mustNewExecutionSegmentSequence(\"\"),\n\t\t\tscaleTests: map[int64]int64{\n\t\t\t\t50: 50,\n\t\t\t\t1:  1,\n\t\t\t\t0:  0,\n\t\t\t},\n\t\t\tnewScaleTests: map[int64]map[int64]int64{\n\t\t\t\t50: {50: 50, 1: 1, 0: 0},\n\t\t\t\t1:  {50: 50, 1: 1, 0: 0},\n\t\t\t\t0:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tseg: mustNewExecutionSegment(\"0:1/3\"),\n\t\t\tseq: mustNewExecutionSegmentSequence(\"0,1/3,2/3,1\"),\n\t\t\tscaleTests: map[int64]int64{\n\t\t\t\t50: 17,\n\t\t\t\t3:  1,\n\t\t\t\t2:  1,\n\t\t\t\t1:  1,\n\t\t\t\t0:  0,\n\t\t\t},\n\t\t\tnewScaleTests: map[int64]map[int64]int64{\n\t\t\t\t50: {50: 17, 1: 1, 0: 0},\n\t\t\t\t20: {50: 18, 1: 1, 0: 0},\n\t\t\t\t3:  {50: 17, 1: 1, 0: 0},\n\t\t\t\t2:  {50: 25, 1: 1, 0: 0},\n\t\t\t\t1:  {50: 50, 1: 1, 0: 0},\n\t\t\t\t0:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tseg: mustNewExecutionSegment(\"1/3:2/3\"),\n\t\t\tseq: mustNewExecutionSegmentSequence(\"0,1/3,2/3,1\"),\n\t\t\tscaleTests: map[int64]int64{\n\t\t\t\t50: 17,\n\t\t\t\t3:  1,\n\t\t\t\t2:  1,\n\t\t\t\t1:  0,\n\t\t\t\t0:  0,\n\t\t\t},\n\t\t\tnewScaleTests: map[int64]map[int64]int64{\n\t\t\t\t50: {50: 17, 1: 0, 0: 0},\n\t\t\t\t20: {50: 17, 1: 0, 0: 0},\n\t\t\t\t3:  {50: 17, 1: 0, 0: 0},\n\t\t\t\t2:  {50: 25, 1: 0, 0: 0},\n\t\t\t\t1:  nil,\n\t\t\t\t0:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tseg: mustNewExecutionSegment(\"2/3:1\"),\n\t\t\tseq: mustNewExecutionSegmentSequence(\"0,1/3,2/3,1\"),\n\t\t\tscaleTests: map[int64]int64{\n\t\t\t\t50: 16,\n\t\t\t\t3:  1,\n\t\t\t\t2:  0,\n\t\t\t\t1:  0,\n\t\t\t\t0:  0,\n\t\t\t},\n\t\t\tnewScaleTests: map[int64]map[int64]int64{\n\t\t\t\t50: {50: 16, 1: 0, 0: 0},\n\t\t\t\t20: {50: 15, 1: 0, 0: 0},\n\t\t\t\t3:  {50: 16, 1: 0, 0: 0},\n\t\t\t\t2:  nil,\n\t\t\t\t1:  nil,\n\t\t\t\t0:  nil,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tt.Run(fmt.Sprintf(\"seg:'%s',seq:'%s'\", testCase.seg, testCase.seq), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tet, err := NewExecutionTuple(testCase.seg, testCase.seq)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tfor scaleValue, result := range testCase.scaleTests {\n\t\t\t\trequire.Equal(t, result, et.ScaleInt64(scaleValue), \"%d->%d\", scaleValue, result)\n\t\t\t}\n\n\t\t\tfor value, newResult := range testCase.newScaleTests {\n\t\t\t\tnewET, err := et.GetNewExecutionTupleFromValue(value)\n\t\t\t\tif newResult == nil {\n\t\t\t\t\trequire.Error(t, err)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tfor scaleValue, result := range newResult {\n\t\t\t\t\trequire.Equal(t, result, newET.ScaleInt64(scaleValue),\n\t\t\t\t\t\t\"GetNewExecutionTupleFromValue(%d)%d->%d\", value, scaleValue, result)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc BenchmarkExecutionSegmentScale(b *testing.B) {\n\ttestCases := []struct {\n\t\tseq string\n\t\tseg string\n\t}{\n\t\t{},\n\t\t{seg: \"0:1\"},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0:0.3\"},\n\t\t{seq: \"0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0:0.1\"},\n\t\t{seg: \"2/5:4/5\"},\n\t\t{seg: \"2235/5213:4/5\"}, // just wanted it to be ugly ;D\n\t}\n\n\tfor _, tc := range testCases {\n\t\tb.Run(fmt.Sprintf(\"seq:%s;segment:%s\", tc.seq, tc.seg), func(b *testing.B) {\n\t\t\tess, err := NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\trequire.NoError(b, err)\n\t\t\tsegment, err := NewExecutionSegmentFromString(tc.seg)\n\t\t\trequire.NoError(b, err)\n\t\t\tif tc.seg == \"\" {\n\t\t\t\tsegment = nil // specifically for the optimization\n\t\t\t}\n\t\t\tet, err := NewExecutionTuple(segment, &ess)\n\t\t\trequire.NoError(b, err)\n\t\t\tfor _, value := range []int64{5, 5523, 5000000, 67280421310721} {\n\t\t\t\tb.Run(fmt.Sprintf(\"segment.Scale(%d)\", value), func(b *testing.B) {\n\t\t\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\t\t\tsegment.Scale(value)\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\t\tb.Run(fmt.Sprintf(\"et.Scale(%d)\", value), func(b *testing.B) {\n\t\t\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\t\t\tet, err = NewExecutionTuple(segment, &ess)\n\t\t\t\t\t\trequire.NoError(b, err)\n\t\t\t\t\t\tet.ScaleInt64(value)\n\t\t\t\t\t}\n\t\t\t\t})\n\n\t\t\t\tet.ScaleInt64(1) // precache\n\t\t\t\tb.Run(fmt.Sprintf(\"et.Scale(%d) prefilled\", value), func(b *testing.B) {\n\t\t\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\t\t\tet.ScaleInt64(value)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TODO: test with randomized things\n\nfunc TestSegmentedIndex(t *testing.T) {\n\tt.Parallel()\n\t// TODO ... more structure ?\n\tt.Run(\"full\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ts := SegmentedIndex{start: 0, lcd: 1, offsets: []int64{1}}\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 1, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 1, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 3, s.unscaled)\n\t\tassert.EqualValues(t, 3, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 1, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\t})\n\n\tt.Run(\"half\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ts := SegmentedIndex{start: 0, lcd: 2, offsets: []int64{2}}\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 1, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 1, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 3, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 5, s.unscaled)\n\t\tassert.EqualValues(t, 3, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 3, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 1, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 1, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\t})\n\n\tt.Run(\"the other half\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ts := SegmentedIndex{start: 1, lcd: 2, offsets: []int64{2}}\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 4, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 6, s.unscaled)\n\t\tassert.EqualValues(t, 3, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 4, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\t})\n\n\tt.Run(\"strange\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ts := SegmentedIndex{start: 1, lcd: 7, offsets: []int64{4, 3}}\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 6, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 9, s.unscaled)\n\t\tassert.EqualValues(t, 3, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 6, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\n\t\ts.Next()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.GoTo(6)\n\t\tassert.EqualValues(t, 6, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.GoTo(5)\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.GoTo(7)\n\t\tassert.EqualValues(t, 6, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.GoTo(8)\n\t\tassert.EqualValues(t, 6, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.GoTo(9)\n\t\tassert.EqualValues(t, 9, s.unscaled)\n\t\tassert.EqualValues(t, 3, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 6, s.unscaled)\n\t\tassert.EqualValues(t, 2, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 2, s.unscaled)\n\t\tassert.EqualValues(t, 1, s.scaled)\n\n\t\ts.Prev()\n\t\tassert.EqualValues(t, 0, s.unscaled)\n\t\tassert.EqualValues(t, 0, s.scaled)\n\t})\n}\n"
  },
  {
    "path": "lib/execution_status_gen.go",
    "content": "// Code generated by \"enumer -type=ExecutionStatus -trimprefix ExecutionStatus -output execution_status_gen.go\"; DO NOT EDIT.\n\npackage lib\n\nimport (\n\t\"fmt\"\n)\n\nconst _ExecutionStatusName = \"CreatedInitVUsInitExecutorsInitDonePausedBeforeRunStartedSetupRunningTeardownEndedInterruptedMarkedAsFailed\"\n\nvar _ExecutionStatusIndex = [...]uint8{0, 7, 14, 27, 35, 50, 57, 62, 69, 77, 82, 93, 107}\n\nfunc (i ExecutionStatus) String() string {\n\tif i >= ExecutionStatus(len(_ExecutionStatusIndex)-1) {\n\t\treturn fmt.Sprintf(\"ExecutionStatus(%d)\", i)\n\t}\n\treturn _ExecutionStatusName[_ExecutionStatusIndex[i]:_ExecutionStatusIndex[i+1]]\n}\n\nvar _ExecutionStatusValues = []ExecutionStatus{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}\n\nvar _ExecutionStatusNameToValueMap = map[string]ExecutionStatus{\n\t_ExecutionStatusName[0:7]:    0,\n\t_ExecutionStatusName[7:14]:   1,\n\t_ExecutionStatusName[14:27]:  2,\n\t_ExecutionStatusName[27:35]:  3,\n\t_ExecutionStatusName[35:50]:  4,\n\t_ExecutionStatusName[50:57]:  5,\n\t_ExecutionStatusName[57:62]:  6,\n\t_ExecutionStatusName[62:69]:  7,\n\t_ExecutionStatusName[69:77]:  8,\n\t_ExecutionStatusName[77:82]:  9,\n\t_ExecutionStatusName[82:93]:  10,\n\t_ExecutionStatusName[93:107]: 11,\n}\n\n// ExecutionStatusString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ExecutionStatusString(s string) (ExecutionStatus, error) {\n\tif val, ok := _ExecutionStatusNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ExecutionStatus values\", s)\n}\n\n// ExecutionStatusValues returns all values of the enum\nfunc ExecutionStatusValues() []ExecutionStatus {\n\treturn _ExecutionStatusValues\n}\n\n// IsAExecutionStatus returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ExecutionStatus) IsAExecutionStatus() bool {\n\tfor _, v := range _ExecutionStatusValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "lib/executor/base_config.go",
    "content": "package executor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/lib/consts\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// DefaultGracefulStopValue is the graceful top value for all executors, unless\n// it's manually changed by the gracefulStop in each one.\n// TODO?: Discard? Or make this actually user-configurable somehow? hello #883...\nvar DefaultGracefulStopValue = 30 * time.Second //nolint:gochecknoglobals\n\nvar scenarioNameWhitelist = regexp.MustCompile(`^[0-9a-zA-Z_-]+$`)\n\nconst scenarioNameErr = \"the scenario name should contain only numbers, latin letters, underscores, and dashes\"\n\n// BaseConfig contains the common config fields for all executors\ntype BaseConfig struct {\n\tName         string               `json:\"-\"` // set via the JS object key\n\tType         string               `json:\"executor\"`\n\tStartTime    types.NullDuration   `json:\"startTime\"`\n\tGracefulStop types.NullDuration   `json:\"gracefulStop\"`\n\tEnv          map[string]string    `json:\"env\"`\n\tExec         null.String          `json:\"exec\"` // function name, externally validated\n\tTags         map[string]string    `json:\"tags\"`\n\tOptions      *lib.ScenarioOptions `json:\"options,omitempty\"`\n\n\t// TODO: future extensions like distribution, others?\n}\n\n// NewBaseConfig returns a default base config with the default values\nfunc NewBaseConfig(name, configType string) BaseConfig {\n\treturn BaseConfig{\n\t\tName:         name,\n\t\tType:         configType,\n\t\tGracefulStop: types.NewNullDuration(DefaultGracefulStopValue, false),\n\t}\n}\n\n// Validate checks some basic things like present name, type, and a positive start time\nfunc (bc BaseConfig) Validate() (result []error) {\n\t// Some just-in-case checks, since those things are likely checked in other places or\n\t// even assigned by us:\n\tif bc.Name == \"\" {\n\t\tresult = append(result, errors.New(\"scenario name can't be empty\"))\n\t}\n\tif !scenarioNameWhitelist.MatchString(bc.Name) {\n\t\tresult = append(result, errors.New(scenarioNameErr))\n\t}\n\tif bc.Exec.Valid && bc.Exec.String == \"\" {\n\t\tresult = append(result, errors.New(\"exec value cannot be empty\"))\n\t}\n\tif bc.Type == \"\" {\n\t\tresult = append(result, errors.New(\"missing or empty type field\"))\n\t}\n\t// The actually reasonable checks:\n\tif bc.StartTime.Duration < 0 {\n\t\tresult = append(result, errors.New(\"the startTime can't be negative\"))\n\t}\n\tif bc.GracefulStop.Duration < 0 {\n\t\tresult = append(result, errors.New(\"the gracefulStop timeout can't be negative\"))\n\t}\n\treturn result\n}\n\n// GetName returns the name of the scenario.\nfunc (bc BaseConfig) GetName() string {\n\treturn bc.Name\n}\n\n// GetType returns the executor's type as a string ID.\nfunc (bc BaseConfig) GetType() string {\n\treturn bc.Type\n}\n\n// GetStartTime returns the starting time, relative to the beginning of the\n// actual test, that this executor is supposed to execute.\nfunc (bc BaseConfig) GetStartTime() time.Duration {\n\treturn bc.StartTime.TimeDuration()\n}\n\n// GetGracefulStop returns how long k6 is supposed to wait for any still\n// running iterations to finish executing at the end of the normal executor\n// duration, before it actually kills them.\n//\n// Of course, that doesn't count when the user manually interrupts the test,\n// then iterations are immediately stopped.\nfunc (bc BaseConfig) GetGracefulStop() time.Duration {\n\treturn bc.GracefulStop.TimeDuration()\n}\n\n// GetEnv returns any specific environment key=value pairs that\n// are configured for the executor.\nfunc (bc BaseConfig) GetEnv() map[string]string {\n\treturn bc.Env\n}\n\n// GetExec returns the configured custom exec value, if any.\nfunc (bc BaseConfig) GetExec() string {\n\texec := bc.Exec.ValueOrZero()\n\tif exec == \"\" {\n\t\texec = consts.DefaultFn\n\t}\n\treturn exec\n}\n\n// GetScenarioOptions returns the options specific to a scenario.\nfunc (bc BaseConfig) GetScenarioOptions() *lib.ScenarioOptions {\n\treturn bc.Options\n}\n\n// GetTags returns any custom tags configured for the scenario.\nfunc (bc BaseConfig) GetTags() map[string]string {\n\treturn bc.Tags\n}\n\n// IsDistributable returns true since by default all executors could be run in\n// a distributed manner.\nfunc (bc BaseConfig) IsDistributable() bool {\n\treturn true\n}\n\n// getBaseInfo is a helper method for the \"parent\" String methods.\nfunc (bc BaseConfig) getBaseInfo(facts ...string) string {\n\tif bc.Exec.Valid {\n\t\tfacts = append(facts, fmt.Sprintf(\"exec: %s\", bc.Exec.String))\n\t}\n\tif bc.StartTime.Duration > 0 {\n\t\tfacts = append(facts, fmt.Sprintf(\"startTime: %s\", bc.StartTime.Duration))\n\t}\n\tif bc.GracefulStop.Duration > 0 {\n\t\tfacts = append(facts, fmt.Sprintf(\"gracefulStop: %s\", bc.GracefulStop.Duration))\n\t}\n\tif len(facts) == 0 {\n\t\treturn \"\"\n\t}\n\treturn \" (\" + strings.Join(facts, \", \") + \")\"\n}\n"
  },
  {
    "path": "lib/executor/base_executor.go",
    "content": "// Package executor defines the executors k6 can use.\npackage executor\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// BaseExecutor is a helper struct that contains common properties and methods\n// between most executors. It is intended to be used as an anonymous struct\n// inside of most of the executors, for the purpose of reducing boilerplate\n// code.\ntype BaseExecutor struct {\n\tconfig         lib.ExecutorConfig\n\texecutionState *lib.ExecutionState\n\titerSegIndexMx *sync.Mutex\n\titerSegIndex   *lib.SegmentedIndex\n\tlogger         *logrus.Entry\n\tprogress       *pb.ProgressBar\n}\n\n// NewBaseExecutor returns an initialized BaseExecutor\nfunc NewBaseExecutor(config lib.ExecutorConfig, es *lib.ExecutionState, logger *logrus.Entry) *BaseExecutor {\n\tsegIdx := lib.NewSegmentedIndex(es.ExecutionTuple)\n\treturn &BaseExecutor{\n\t\tconfig:         config,\n\t\texecutionState: es,\n\t\tlogger:         logger,\n\t\titerSegIndexMx: new(sync.Mutex),\n\t\titerSegIndex:   segIdx,\n\t\tprogress: pb.New(\n\t\t\tpb.WithLeft(config.GetName),\n\t\t\tpb.WithLogger(logger),\n\t\t),\n\t}\n}\n\n// nextIterationCounters next scaled(local) and unscaled(global) iteration counters\nfunc (bs *BaseExecutor) nextIterationCounters() (uint64, uint64) {\n\tbs.iterSegIndexMx.Lock()\n\tdefer bs.iterSegIndexMx.Unlock()\n\tscaled, unscaled := bs.iterSegIndex.Next()\n\treturn uint64(scaled - 1), uint64(unscaled - 1) //nolint:gosec\n}\n\n// Init doesn't do anything for most executors, since initialization of all\n// planned VUs is handled by the executor.\nfunc (bs *BaseExecutor) Init(_ context.Context) error {\n\treturn nil\n}\n\n// GetConfig returns the configuration with which this executor was launched.\nfunc (bs *BaseExecutor) GetConfig() lib.ExecutorConfig {\n\treturn bs.config\n}\n\n// GetLogger returns the executor logger entry.\nfunc (bs *BaseExecutor) GetLogger() *logrus.Entry {\n\treturn bs.logger\n}\n\n// GetProgress just returns the progressbar pointer.\nfunc (bs *BaseExecutor) GetProgress() *pb.ProgressBar {\n\treturn bs.progress\n}\n\n// getMetricTags returns a tag set that can be used to emit metrics by the\n// executor. The VU ID is optional.\nfunc (bs *BaseExecutor) getMetricTags(vuID *uint64) *metrics.TagSet {\n\ttags := bs.executionState.Test.RunTags\n\tif bs.executionState.Test.Options.SystemTags.Has(metrics.TagScenario) {\n\t\ttags = tags.With(\"scenario\", bs.config.GetName())\n\t}\n\tif vuID != nil && bs.executionState.Test.Options.SystemTags.Has(metrics.TagVU) {\n\t\ttags = tags.With(\"vu\", strconv.FormatUint(*vuID, 10))\n\t}\n\treturn tags\n}\n"
  },
  {
    "path": "lib/executor/common_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc simpleRunner(vuFn func(context.Context, *lib.State) error) lib.Runner {\n\treturn &minirunner.MiniRunner{\n\t\tFn: func(ctx context.Context, state *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\t\treturn vuFn(ctx, state)\n\t\t},\n\t}\n}\n\nfunc getTestRunState(tb testing.TB, options lib.Options, runner lib.Runner) *lib.TestRunState {\n\treg := metrics.NewRegistry()\n\tpiState := &lib.TestPreInitState{\n\t\tLogger:         testutils.NewLogger(tb),\n\t\tRuntimeOptions: lib.RuntimeOptions{},\n\t\tRegistry:       reg,\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(reg),\n\t}\n\n\trequire.NoError(tb, runner.SetOptions(options))\n\n\treturn &lib.TestRunState{\n\t\tTestPreInitState: piState,\n\t\tOptions:          options,\n\t\tRunner:           runner,\n\t\tRunTags:          piState.Registry.RootTagSet().WithTagsFromMap(options.RunTags),\n\t}\n}\n\nfunc setupExecutor(t testing.TB, config lib.ExecutorConfig, es *lib.ExecutionState) (\n\tcontext.Context, context.CancelFunc, lib.Executor, *testutils.SimpleLogrusHook,\n) {\n\tctx, cancel := context.WithCancel(context.Background())\n\tengineOut := make(chan metrics.SampleContainer, 100) // TODO: return this for more complicated tests?\n\n\tlogHook := testutils.NewLogHook(logrus.WarnLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\ttestLog.SetOutput(io.Discard)\n\tlogEntry := logrus.NewEntry(testLog)\n\n\tinitVUFunc := func(_ context.Context, _ *logrus.Entry) (lib.InitializedVU, error) {\n\t\tidl, idg := es.GetUniqueVUIdentifiers()\n\t\treturn es.Test.Runner.NewVU(ctx, idl, idg, engineOut)\n\t}\n\tes.SetInitVUFunc(initVUFunc)\n\n\tmaxPlannedVUs := lib.GetMaxPlannedVUs(config.GetExecutionRequirements(es.ExecutionTuple))\n\tinitializeVUs(ctx, t, logEntry, es, maxPlannedVUs, initVUFunc)\n\n\texecutor, err := config.NewExecutor(es, logEntry)\n\trequire.NoError(t, err)\n\n\terr = executor.Init(ctx)\n\trequire.NoError(t, err)\n\treturn ctx, cancel, executor, logHook\n}\n\nfunc initializeVUs(\n\tctx context.Context, t testing.TB, logEntry *logrus.Entry, es *lib.ExecutionState, number uint64, initVU lib.InitVUFunc,\n) {\n\t// This is not how the local ExecutionScheduler initializes VUs, but should do the same job\n\tfor range number {\n\t\t// Not calling es.InitializeNewVU() here to avoid a double increment of initializedVUs,\n\t\t// which is done in es.AddInitializedVU().\n\t\tvu, err := initVU(ctx, logEntry)\n\t\trequire.NoError(t, err)\n\t\tes.AddInitializedVU(vu)\n\t}\n}\n\ntype executorTest struct {\n\toptions lib.Options\n\tstate   *lib.ExecutionState\n\n\tctx      context.Context\n\tcancel   context.CancelFunc\n\texecutor lib.Executor\n\tlogHook  *testutils.SimpleLogrusHook\n}\n\n//nolint:unparam\nfunc setupExecutorTest(\n\tt testing.TB, segmentStr, sequenceStr string, extraOptions lib.Options,\n\trunner lib.Runner, config lib.ExecutorConfig,\n) *executorTest {\n\tvar err error\n\tvar segment *lib.ExecutionSegment\n\tif segmentStr != \"\" {\n\t\tsegment, err = lib.NewExecutionSegmentFromString(segmentStr)\n\t\trequire.NoError(t, err)\n\t}\n\n\tvar sequence lib.ExecutionSegmentSequence\n\tif sequenceStr != \"\" {\n\t\tsequence, err = lib.NewExecutionSegmentSequenceFromString(sequenceStr)\n\t\trequire.NoError(t, err)\n\t}\n\n\tet, err := lib.NewExecutionTuple(segment, &sequence)\n\trequire.NoError(t, err)\n\n\toptions := lib.Options{\n\t\tExecutionSegment:         segment,\n\t\tExecutionSegmentSequence: &sequence,\n\t}.Apply(runner.GetOptions()).Apply(extraOptions)\n\n\ttestRunState := getTestRunState(t, options, runner)\n\n\texecReqs := config.GetExecutionRequirements(et)\n\tes := lib.NewExecutionState(testRunState, et, lib.GetMaxPlannedVUs(execReqs), lib.GetMaxPossibleVUs(execReqs))\n\tctx, cancel, executor, logHook := setupExecutor(t, config, es)\n\n\treturn &executorTest{\n\t\toptions:  options,\n\t\tstate:    es,\n\t\tctx:      ctx,\n\t\tcancel:   cancel,\n\t\texecutor: executor,\n\t\tlogHook:  logHook,\n\t}\n}\n"
  },
  {
    "path": "lib/executor/constant_arrival_rate.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/big\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst constantArrivalRateType = \"constant-arrival-rate\"\n\nfunc init() {\n\tlib.RegisterExecutorConfigType(\n\t\tconstantArrivalRateType,\n\t\tfunc(name string, rawJSON []byte) (lib.ExecutorConfig, error) {\n\t\t\tconfig := NewConstantArrivalRateConfig(name)\n\t\t\terr := lib.StrictJSONUnmarshal(rawJSON, &config)\n\t\t\treturn config, err\n\t\t},\n\t)\n}\n\n// ConstantArrivalRateConfig stores config for the constant arrival-rate executor\ntype ConstantArrivalRateConfig struct {\n\tBaseConfig\n\tRate     null.Int           `json:\"rate\"`\n\tTimeUnit types.NullDuration `json:\"timeUnit\"`\n\tDuration types.NullDuration `json:\"duration\"`\n\n\t// Initialize `PreAllocatedVUs` number of VUs, and if more than that are needed,\n\t// they will be dynamically allocated, until `MaxVUs` is reached, which is an\n\t// absolutely hard limit on the number of VUs the executor will use\n\tPreAllocatedVUs null.Int `json:\"preAllocatedVUs\"`\n\tMaxVUs          null.Int `json:\"maxVUs\"`\n}\n\n// NewConstantArrivalRateConfig returns a ConstantArrivalRateConfig with default values\nfunc NewConstantArrivalRateConfig(name string) *ConstantArrivalRateConfig {\n\treturn &ConstantArrivalRateConfig{\n\t\tBaseConfig: NewBaseConfig(name, constantArrivalRateType),\n\t\tTimeUnit:   types.NewNullDuration(1*time.Second, false),\n\t}\n}\n\n// Make sure we implement the lib.ExecutorConfig interface\nvar _ lib.ExecutorConfig = &ConstantArrivalRateConfig{}\n\n// GetPreAllocatedVUs is just a helper method that returns the scaled pre-allocated VUs.\nfunc (carc ConstantArrivalRateConfig) GetPreAllocatedVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(carc.PreAllocatedVUs.Int64)\n}\n\n// GetMaxVUs is just a helper method that returns the scaled max VUs.\nfunc (carc ConstantArrivalRateConfig) GetMaxVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(carc.MaxVUs.Int64)\n}\n\n// GetDescription returns a human-readable description of the executor options\nfunc (carc ConstantArrivalRateConfig) GetDescription(et *lib.ExecutionTuple) string {\n\tpreAllocatedVUs, maxVUs := carc.GetPreAllocatedVUs(et), carc.GetMaxVUs(et)\n\tmaxVUsRange := fmt.Sprintf(\"maxVUs: %d\", preAllocatedVUs)\n\tif maxVUs > preAllocatedVUs {\n\t\tmaxVUsRange += fmt.Sprintf(\"-%d\", maxVUs)\n\t}\n\n\ttimeUnit := carc.TimeUnit.TimeDuration()\n\tvar arrRatePerSec float64\n\tif maxVUs != 0 { // TODO: do something better?\n\t\tratio := big.NewRat(maxVUs, carc.MaxVUs.Int64)\n\t\tarrRate := big.NewRat(carc.Rate.Int64, int64(timeUnit))\n\t\tarrRate.Mul(arrRate, ratio)\n\t\tarrRatePerSec, _ = getArrivalRatePerSec(arrRate).Float64()\n\t}\n\n\treturn fmt.Sprintf(\"%.2f iterations/s for %s%s\", arrRatePerSec, carc.Duration.Duration,\n\t\tcarc.getBaseInfo(maxVUsRange))\n}\n\n// Validate makes sure all options are configured and valid\nfunc (carc *ConstantArrivalRateConfig) Validate() []error {\n\terrors := carc.BaseConfig.Validate()\n\tif !carc.Rate.Valid {\n\t\terrors = append(errors, fmt.Errorf(\"the iteration rate isn't specified\"))\n\t} else if carc.Rate.Int64 <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the iteration rate must be more than 0\"))\n\t}\n\n\tif carc.TimeUnit.TimeDuration() <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the timeUnit must be more than 0\"))\n\t}\n\n\tif !carc.Duration.Valid {\n\t\terrors = append(errors, fmt.Errorf(\"the duration is unspecified\"))\n\t} else if carc.Duration.TimeDuration() < minDuration {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the duration must be at least %s, but is %s\", minDuration, carc.Duration,\n\t\t))\n\t}\n\n\tif !carc.PreAllocatedVUs.Valid {\n\t\terrors = append(errors, fmt.Errorf(\"the number of preAllocatedVUs isn't specified\"))\n\t} else if carc.PreAllocatedVUs.Int64 < 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of preAllocatedVUs can't be negative\"))\n\t}\n\n\tif !carc.MaxVUs.Valid {\n\t\t// TODO: don't change the config while validating\n\t\tcarc.MaxVUs.Int64 = carc.PreAllocatedVUs.Int64\n\t} else if carc.MaxVUs.Int64 < carc.PreAllocatedVUs.Int64 {\n\t\terrors = append(errors, fmt.Errorf(\"maxVUs can't be less than preAllocatedVUs\"))\n\t}\n\n\treturn errors\n}\n\n// GetExecutionRequirements returns the number of required VUs to run the\n// executor for its whole duration (disregarding any startTime), including the\n// maximum waiting time for any iterations to gracefully stop. This is used by\n// the execution scheduler in its VU reservation calculations, so it knows how\n// many VUs to pre-initialize.\nfunc (carc ConstantArrivalRateConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {\n\treturn []lib.ExecutionStep{\n\t\t{\n\t\t\tTimeOffset:      0,\n\t\t\tPlannedVUs:      uint64(et.ScaleInt64(carc.PreAllocatedVUs.Int64)),                                    //nolint:gosec\n\t\t\tMaxUnplannedVUs: uint64(et.ScaleInt64(carc.MaxVUs.Int64) - et.ScaleInt64(carc.PreAllocatedVUs.Int64)), //nolint:gosec\n\t\t}, {\n\t\t\tTimeOffset:      carc.Duration.TimeDuration() + carc.GracefulStop.TimeDuration(),\n\t\t\tPlannedVUs:      0,\n\t\t\tMaxUnplannedVUs: 0,\n\t\t},\n\t}\n}\n\n// NewExecutor creates a new ConstantArrivalRate executor\nfunc (carc ConstantArrivalRateConfig) NewExecutor(\n\tes *lib.ExecutionState, logger *logrus.Entry,\n) (lib.Executor, error) {\n\treturn &ConstantArrivalRate{\n\t\tBaseExecutor: NewBaseExecutor(&carc, es, logger),\n\t\tconfig:       carc,\n\t}, nil\n}\n\n// HasWork reports whether there is any work to be done for the given execution segment.\nfunc (carc ConstantArrivalRateConfig) HasWork(et *lib.ExecutionTuple) bool {\n\treturn carc.GetMaxVUs(et) > 0\n}\n\n// ConstantArrivalRate tries to execute a specific number of iterations for a\n// specific period.\ntype ConstantArrivalRate struct {\n\t*BaseExecutor\n\tconfig ConstantArrivalRateConfig\n\tet     *lib.ExecutionTuple\n}\n\n// Make sure we implement the lib.Executor interface.\nvar _ lib.Executor = &ConstantArrivalRate{}\n\n// Init values needed for the execution\nfunc (car *ConstantArrivalRate) Init(_ context.Context) error {\n\t// err should always be nil, because Init() won't be called for executors\n\t// with no work, as determined by their config's HasWork() method.\n\tet, err := car.executionState.ExecutionTuple.GetNewExecutionTupleFromValue(car.config.MaxVUs.Int64)\n\tcar.et = et\n\tcar.iterSegIndex = lib.NewSegmentedIndex(et)\n\n\treturn err\n}\n\n// Run executes a constant number of iterations per second.\n//\n// TODO: Split this up and make an independent component that can be reused\n// between the constant and ramping arrival rate executors - that way we can\n// keep the complexity in one well-architected part (with short methods and few\n// lambdas :D), while having both config frontends still be present for maximum\n// UX benefits. Basically, keep the progress bars and scheduling (i.e. at what\n// time should iteration X begin) different, but keep everything else the same.\n// This will allow us to implement https://github.com/k6io/k6/issues/1386\n// and things like all of the TODOs below in one place only.\n//\n//nolint:funlen\nfunc (car ConstantArrivalRate) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) {\n\tgracefulStop := car.config.GetGracefulStop()\n\tduration := car.config.Duration.TimeDuration()\n\tpreAllocatedVUs := car.config.GetPreAllocatedVUs(car.executionState.ExecutionTuple)\n\tmaxVUs := car.config.GetMaxVUs(car.executionState.ExecutionTuple)\n\t// TODO: refactor and simplify\n\tarrivalRate := getScaledArrivalRate(car.et.Segment, car.config.Rate.Int64, car.config.TimeUnit.TimeDuration())\n\ttickerPeriod := getTickerPeriod(arrivalRate).TimeDuration()\n\tarrivalRatePerSec, _ := getArrivalRatePerSec(arrivalRate).Float64()\n\n\t// Make sure the log and the progress bar have accurate information\n\tcar.logger.WithFields(logrus.Fields{\n\t\t\"maxVUs\": maxVUs, \"preAllocatedVUs\": preAllocatedVUs, \"duration\": duration,\n\t\t\"tickerPeriod\": tickerPeriod, \"type\": car.config.GetType(),\n\t}).Debug(\"Starting executor run...\")\n\n\tactiveVUsWg := &sync.WaitGroup{}\n\n\treturnedVUs := make(chan struct{})\n\twaitOnProgressChannel := make(chan struct{})\n\tstartTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(parentCtx, duration, gracefulStop)\n\tdefer func() {\n\t\tcancel()\n\t\t<-waitOnProgressChannel\n\t}()\n\n\tvusPool := newActiveVUPool(car.executionState)\n\tdefer func() {\n\t\t// Make sure all VUs aren't executing iterations anymore, for the cancel()\n\t\t// below to deactivate them.\n\t\t<-returnedVUs\n\t\t// first close the vusPool so we wait for the gracefulShutdown\n\t\tvusPool.Close()\n\t\tcancel()\n\t\tactiveVUsWg.Wait()\n\t}()\n\tactiveVUsCount := uint64(0)\n\n\tvusFmt := pb.GetFixedLengthIntFormat(maxVUs)\n\tprogIters := fmt.Sprintf(\n\t\tpb.GetFixedLengthFloatFormat(arrivalRatePerSec, 2)+\" iters/s\", arrivalRatePerSec)\n\tprogressFn := func() (float64, []string) {\n\t\tspent := time.Since(startTime)\n\t\tcurrActiveVUs := atomic.LoadUint64(&activeVUsCount)\n\t\tprogVUs := fmt.Sprintf(vusFmt+\"/\"+vusFmt+\" VUs\",\n\t\t\tvusPool.Running(), currActiveVUs)\n\n\t\tright := []string{progVUs, duration.String(), progIters}\n\n\t\tif spent > duration {\n\t\t\treturn 1, right\n\t\t}\n\n\t\tspentDuration := pb.GetFixedLengthDuration(spent, duration)\n\t\tprogDur := fmt.Sprintf(\"%s/%s\", spentDuration, duration)\n\t\tright[1] = progDur\n\n\t\treturn math.Min(1, float64(spent)/float64(duration)), right\n\t}\n\tcar.progress.Modify(pb.WithProgress(progressFn))\n\tmaxDurationCtx = lib.WithScenarioState(maxDurationCtx, &lib.ScenarioState{\n\t\tName:       car.config.Name,\n\t\tExecutor:   car.config.Type,\n\t\tStartTime:  startTime,\n\t\tProgressFn: progressFn,\n\t})\n\n\tgo func() {\n\t\ttrackProgress(parentCtx, maxDurationCtx, regDurationCtx, &car, progressFn)\n\t\tclose(waitOnProgressChannel)\n\t}()\n\n\treturnVU := func(u lib.InitializedVU) {\n\t\t// Return the VU without decreasing the global active VU counter, which\n\t\t// is done in the goroutine started by activeVUPool.AddVU, whenever the\n\t\t// VU finishes running an iteration. This results in a more accurate\n\t\t// report of VUs that are _actually_ active.\n\t\tcar.executionState.ReturnVU(u, false)\n\t\tactiveVUsWg.Done()\n\t}\n\n\trunIterationBasic := getIterationRunner(car.executionState, car.logger)\n\tactivateVU := func(initVU lib.InitializedVU) lib.ActiveVU {\n\t\tactiveVUsWg.Add(1)\n\t\tactiveVU := initVU.Activate(getVUActivationParams(\n\t\t\tmaxDurationCtx, car.config.BaseConfig, returnVU,\n\t\t\tcar.nextIterationCounters,\n\t\t))\n\t\tatomic.AddUint64(&activeVUsCount, 1)\n\t\tvusPool.AddVU(maxDurationCtx, activeVU, runIterationBasic)\n\t\treturn activeVU\n\t}\n\n\tremainingUnplannedVUs := maxVUs - preAllocatedVUs\n\tmakeUnplannedVUCh := make(chan struct{})\n\tdefer close(makeUnplannedVUCh)\n\tgo func() {\n\t\tdefer close(returnedVUs)\n\t\tfor range makeUnplannedVUCh {\n\t\t\tcar.logger.Debug(\"Starting initialization of an unplanned VU...\")\n\t\t\tinitVU, err := car.executionState.GetUnplannedVU(maxDurationCtx, car.logger)\n\t\t\tif err != nil {\n\t\t\t\t// TODO figure out how to return it to the Run goroutine\n\t\t\t\tcar.logger.WithError(err).Error(\"Error while allocating unplanned VU\")\n\t\t\t} else {\n\t\t\t\tcar.logger.Debug(\"The unplanned VU finished initializing successfully!\")\n\t\t\t\tactivateVU(initVU)\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Get the pre-allocated VUs in the local buffer\n\tfor range preAllocatedVUs {\n\t\tinitVU, err := car.executionState.GetPlannedVU(car.logger, false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tactivateVU(initVU)\n\t}\n\n\tstart, offsets, _ := car.et.GetStripedOffsets()\n\ttimer := time.NewTimer(time.Hour * 24)\n\t// here the we need the not scaled one\n\tnotScaledTickerPeriod := getTickerPeriod(\n\t\tbig.NewRat(\n\t\t\tcar.config.Rate.Int64,\n\t\t\tint64(car.config.TimeUnit.TimeDuration()),\n\t\t)).TimeDuration()\n\n\tdroppedIterationMetric := car.executionState.Test.BuiltinMetrics.DroppedIterations\n\tshownWarning := false\n\tmetricTags := car.getMetricTags(nil)\n\tfor li, gi := 0, start; ; li, gi = li+1, gi+offsets[li%len(offsets)] {\n\t\tt := notScaledTickerPeriod*time.Duration(gi) - time.Since(startTime)\n\t\ttimer.Reset(t)\n\t\tselect {\n\t\tcase <-timer.C:\n\t\t\tif vusPool.TryRunIteration() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Since there aren't any free VUs available, consider this iteration\n\t\t\t// dropped - we aren't going to try to recover it, but\n\n\t\t\tmetrics.PushIfNotDone(parentCtx, out, metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: droppedIterationMetric,\n\t\t\t\t\tTags:   metricTags,\n\t\t\t\t},\n\t\t\t\tTime:  time.Now(),\n\t\t\t\tValue: 1,\n\t\t\t})\n\n\t\t\t// We'll try to start allocating another VU in the background,\n\t\t\t// non-blockingly, if we have remainingUnplannedVUs...\n\t\t\tif remainingUnplannedVUs == 0 {\n\t\t\t\tif !shownWarning {\n\t\t\t\t\tcar.logger.Warningf(\"Insufficient VUs, reached %d active VUs and cannot initialize more\", maxVUs)\n\t\t\t\t\tshownWarning = true\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tselect {\n\t\t\tcase makeUnplannedVUCh <- struct{}{}: // great!\n\t\t\t\tremainingUnplannedVUs--\n\t\t\tdefault: // we're already allocating a new VU\n\t\t\t}\n\n\t\tcase <-regDurationCtx.Done():\n\t\t\treturn nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/executor/constant_arrival_rate_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc newExecutionSegmentFromString(str string) *lib.ExecutionSegment {\n\tr, err := lib.NewExecutionSegmentFromString(str)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn r\n}\n\nfunc newExecutionSegmentSequenceFromString(str string) *lib.ExecutionSegmentSequence {\n\tr, err := lib.NewExecutionSegmentSequenceFromString(str)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn &r\n}\n\nfunc getTestConstantArrivalRateConfig() *ConstantArrivalRateConfig {\n\treturn &ConstantArrivalRateConfig{\n\t\tBaseConfig:      BaseConfig{GracefulStop: types.NullDurationFrom(1 * time.Second)},\n\t\tTimeUnit:        types.NullDurationFrom(time.Second),\n\t\tRate:            null.IntFrom(50),\n\t\tDuration:        types.NullDurationFrom(5 * time.Second),\n\t\tPreAllocatedVUs: null.IntFrom(10),\n\t\tMaxVUs:          null.IntFrom(20),\n\t}\n}\n\nfunc TestConstantArrivalRateRunNotEnoughAllocatedVUsWarn(t *testing.T) {\n\tt.Parallel()\n\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\ttime.Sleep(time.Second)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestConstantArrivalRateConfig())\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tentries := test.logHook.Drain()\n\trequire.NotEmpty(t, entries)\n\tfor _, entry := range entries {\n\t\trequire.Equal(t,\n\t\t\t\"Insufficient VUs, reached 20 active VUs and cannot initialize more\",\n\t\t\tentry.Message)\n\t\trequire.Equal(t, logrus.WarnLevel, entry.Level)\n\t}\n}\n\nfunc TestConstantArrivalRateRunCorrectRate(t *testing.T) {\n\tt.Parallel()\n\n\tvar count int64\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\tatomic.AddInt64(&count, 1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestConstantArrivalRateConfig())\n\tdefer test.cancel()\n\n\tvar wg sync.WaitGroup\n\twg.Go(func() {\n\t\t// check that we got around the amount of VU iterations as we would expect\n\t\tvar totalCount int64\n\n\t\ti := 5\n\t\tticker := time.NewTicker(time.Second)\n\t\tfor range ticker.C {\n\t\t\ti--\n\t\t\tif i == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrentCount := atomic.SwapInt64(&count, 0)\n\t\t\ttotalCount += currentCount\n\t\t\t// We have a relatively relaxed constraint here, but we also check\n\t\t\t// the final iteration count exactly below:\n\t\t\tassert.InDelta(t, 50, currentCount, 5)\n\t\t}\n\n\t\ttime.Sleep(200 * time.Millisecond) // just in case\n\n\t\tassert.InDelta(t, 250, totalCount+atomic.LoadInt64(&count), 2)\n\t})\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\twg.Wait()\n\trequire.Empty(t, test.logHook.Drain())\n}\n\n//nolint:paralleltest // this is flaky if ran with other tests\nfunc TestConstantArrivalRateRunCorrectTiming(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skipf(\"this test is very flaky on the Windows GitHub Action runners...\")\n\t}\n\ttests := []struct {\n\t\tsegment  string\n\t\tsequence string\n\t\tstart    time.Duration\n\t\tsteps    []int64\n\t}{\n\t\t{\n\t\t\tsegment: \"0:1/3\",\n\t\t\tstart:   time.Millisecond * 20,\n\t\t\tsteps:   []int64{40, 60, 60, 60, 60, 60, 60},\n\t\t},\n\t\t{\n\t\t\tsegment: \"1/3:2/3\",\n\t\t\tstart:   time.Millisecond * 20,\n\t\t\tsteps:   []int64{60, 60, 60, 60, 60, 60, 40},\n\t\t},\n\t\t{\n\t\t\tsegment: \"2/3:1\",\n\t\t\tstart:   time.Millisecond * 20,\n\t\t\tsteps:   []int64{40, 60, 60, 60, 60, 60, 60},\n\t\t},\n\t\t{\n\t\t\tsegment: \"1/6:3/6\",\n\t\t\tstart:   time.Millisecond * 20,\n\t\t\tsteps:   []int64{40, 80, 40, 80, 40, 80, 40},\n\t\t},\n\t\t{\n\t\t\tsegment:  \"1/6:3/6\",\n\t\t\tsequence: \"1/6,3/6\",\n\t\t\tstart:    time.Millisecond * 20,\n\t\t\tsteps:    []int64{40, 80, 40, 80, 40, 80, 40},\n\t\t},\n\t\t// sequences\n\t\t{\n\t\t\tsegment:  \"0:1/3\",\n\t\t\tsequence: \"0,1/3,2/3,1\",\n\t\t\tstart:    time.Millisecond * 0,\n\t\t\tsteps:    []int64{60, 60, 60, 60, 60, 60, 40},\n\t\t},\n\t\t{\n\t\t\tsegment:  \"1/3:2/3\",\n\t\t\tsequence: \"0,1/3,2/3,1\",\n\t\t\tstart:    time.Millisecond * 20,\n\t\t\tsteps:    []int64{60, 60, 60, 60, 60, 60, 40},\n\t\t},\n\t\t{\n\t\t\tsegment:  \"2/3:1\",\n\t\t\tsequence: \"0,1/3,2/3,1\",\n\t\t\tstart:    time.Millisecond * 40,\n\t\t\tsteps:    []int64{60, 60, 60, 60, 60, 100},\n\t\t},\n\t}\n\tfor _, test := range tests {\n\t\tt.Run(fmt.Sprintf(\"segment %s sequence %s\", test.segment, test.sequence), func(t *testing.T) {\n\t\t\tvar count int64\n\t\t\tstartTime := time.Now()\n\t\t\texpectedTimeInt64 := int64(test.start)\n\t\t\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\t\t\tcurrent := atomic.AddInt64(&count, 1)\n\n\t\t\t\texpectedTime := test.start\n\t\t\t\tif current != 1 {\n\t\t\t\t\texpectedTime = time.Duration(atomic.AddInt64(&expectedTimeInt64,\n\t\t\t\t\t\tint64(time.Millisecond)*test.steps[(current-2)%int64(len(test.steps))]))\n\t\t\t\t}\n\n\t\t\t\t// FIXME: replace this check with a unit test asserting that the scheduling is correct,\n\t\t\t\t// without depending on the execution time itself\n\t\t\t\tassert.WithinDuration(t,\n\t\t\t\t\tstartTime.Add(expectedTime),\n\t\t\t\t\ttime.Now(),\n\t\t\t\t\ttime.Millisecond*24,\n\t\t\t\t\t\"%d expectedTime %s\", current, expectedTime,\n\t\t\t\t)\n\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\tconfig := getTestConstantArrivalRateConfig()\n\t\t\tseconds := 2\n\t\t\tconfig.Duration.Duration = types.Duration(time.Second * time.Duration(seconds))\n\t\t\texecTest := setupExecutorTest(\n\t\t\t\tt, test.segment, test.sequence, lib.Options{}, runner, config,\n\t\t\t)\n\t\t\tdefer execTest.cancel()\n\n\t\t\tnewET, err := execTest.state.ExecutionTuple.GetNewExecutionTupleFromValue(config.MaxVUs.Int64)\n\t\t\trequire.NoError(t, err)\n\t\t\trateScaled := newET.ScaleInt64(config.Rate.Int64)\n\n\t\t\tvar wg sync.WaitGroup\n\t\t\twg.Go(func() {\n\t\t\t\t// check that we got around the amount of VU iterations as we would expect\n\t\t\t\tvar currentCount int64\n\n\t\t\t\tfor i := range seconds {\n\t\t\t\t\ttime.Sleep(time.Second)\n\t\t\t\t\tcurrentCount = atomic.LoadInt64(&count)\n\t\t\t\t\tassert.InDelta(t, int64(i+1)*rateScaled, currentCount, 3)\n\t\t\t\t}\n\t\t\t})\n\t\t\tstartTime = time.Now()\n\t\t\tengineOut := make(chan metrics.SampleContainer, 1000)\n\t\t\terr = execTest.executor.Run(execTest.ctx, engineOut)\n\t\t\twg.Wait()\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Empty(t, execTest.logHook.Drain())\n\t\t})\n\t}\n}\n\nfunc TestArrivalRateCancel(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := map[string]lib.ExecutorConfig{\n\t\t\"constant\": getTestConstantArrivalRateConfig(),\n\t\t\"ramping\":  getTestRampingArrivalRateConfig(),\n\t}\n\tfor name, config := range testCases {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := make(chan struct{})\n\t\t\terrCh := make(chan error, 1)\n\t\t\tweAreDoneCh := make(chan struct{})\n\n\t\t\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\t\t\tselect {\n\t\t\t\tcase <-ch:\n\t\t\t\t\t<-ch\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\t\t\tdefer test.cancel()\n\n\t\t\tvar wg sync.WaitGroup\n\t\t\twg.Go(func() {\n\t\t\t\tengineOut := make(chan metrics.SampleContainer, 1000)\n\t\t\t\terrCh <- test.executor.Run(test.ctx, engineOut)\n\t\t\t\tclose(weAreDoneCh)\n\t\t\t})\n\n\t\t\ttime.Sleep(time.Second)\n\t\t\tch <- struct{}{}\n\t\t\ttest.cancel()\n\t\t\ttime.Sleep(time.Second)\n\t\t\tselect {\n\t\t\tcase <-weAreDoneCh:\n\t\t\t\tt.Fatal(\"Run returned before all VU iterations were finished\")\n\t\t\tdefault:\n\t\t\t}\n\t\t\tclose(ch)\n\t\t\t<-weAreDoneCh\n\t\t\twg.Wait()\n\t\t\trequire.NoError(t, <-errCh)\n\t\t\trequire.Empty(t, test.logHook.Drain())\n\t\t})\n\t}\n}\n\nfunc TestConstantArrivalRateDroppedIterations(t *testing.T) {\n\tt.Parallel()\n\tvar count int64\n\n\tconfig := &ConstantArrivalRateConfig{\n\t\tBaseConfig:      BaseConfig{GracefulStop: types.NullDurationFrom(0 * time.Second)},\n\t\tTimeUnit:        types.NullDurationFrom(time.Second),\n\t\tRate:            null.IntFrom(10),\n\t\tDuration:        types.NullDurationFrom(950 * time.Millisecond),\n\t\tPreAllocatedVUs: null.IntFrom(5),\n\t\tMaxVUs:          null.IntFrom(5),\n\t}\n\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\tatomic.AddInt64(&count, 1)\n\t\t<-ctx.Done()\n\t\treturn nil\n\t})\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tlogs := test.logHook.Drain()\n\trequire.Len(t, logs, 1)\n\tassert.Contains(t, logs[0].Message, \"cannot initialize more\")\n\tassert.Equal(t, int64(5), count)\n\tassert.Equal(t, float64(5), sumMetricValues(engineOut, metrics.DroppedIterationsName))\n}\n\nfunc TestConstantArrivalRateGlobalIters(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &ConstantArrivalRateConfig{\n\t\tBaseConfig:      BaseConfig{GracefulStop: types.NullDurationFrom(100 * time.Millisecond)},\n\t\tTimeUnit:        types.NullDurationFrom(950 * time.Millisecond),\n\t\tRate:            null.IntFrom(20),\n\t\tDuration:        types.NullDurationFrom(1 * time.Second),\n\t\tPreAllocatedVUs: null.IntFrom(5),\n\t\tMaxVUs:          null.IntFrom(5),\n\t}\n\n\ttestCases := []struct {\n\t\tseq, seg string\n\t\texpIters []uint64\n\t}{\n\t\t{\"0,1/4,3/4,1\", \"0:1/4\", []uint64{1, 6, 11, 16, 21}},\n\t\t{\"0,1/4,3/4,1\", \"1/4:3/4\", []uint64{0, 2, 4, 5, 7, 9, 10, 12, 14, 15, 17, 19, 20}},\n\t\t{\"0,1/4,3/4,1\", \"3/4:1\", []uint64{3, 8, 13, 18}},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%s_%s\", tc.seq, tc.seg), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotIters := []uint64{}\n\t\t\tvar mx sync.Mutex\n\t\t\trunner := simpleRunner(func(_ context.Context, state *lib.State) error {\n\t\t\t\tmx.Lock()\n\t\t\t\tgotIters = append(gotIters, state.GetScenarioGlobalVUIter())\n\t\t\t\tmx.Unlock()\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\ttest := setupExecutorTest(t, tc.seg, tc.seq, lib.Options{}, runner, config)\n\t\t\tdefer test.cancel()\n\n\t\t\tengineOut := make(chan metrics.SampleContainer, 100)\n\t\t\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\t\t\tassert.Equal(t, tc.expIters, gotIters)\n\t\t})\n\t}\n}\n\nfunc TestConstantArrivalRateActiveVUs(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &ConstantArrivalRateConfig{\n\t\tBaseConfig:      BaseConfig{GracefulStop: types.NullDurationFrom(0 * time.Second)},\n\t\tTimeUnit:        types.NullDurationFrom(time.Second),\n\t\tRate:            null.IntFrom(10),\n\t\tDuration:        types.NullDurationFrom(950 * time.Millisecond),\n\t\tPreAllocatedVUs: null.IntFrom(5),\n\t\tMaxVUs:          null.IntFrom(10),\n\t}\n\n\tvar (\n\t\trunning          int64\n\t\tgetCurrActiveVUs func() int64\n\t\trunMx            sync.Mutex\n\t)\n\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\trunMx.Lock()\n\t\trunning++\n\t\tassert.Equal(t, running, getCurrActiveVUs())\n\t\trunMx.Unlock()\n\t\t// Block the VU to cause the executor to schedule more\n\t\t<-ctx.Done()\n\t\treturn nil\n\t})\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tgetCurrActiveVUs = test.state.GetCurrentlyActiveVUsCount\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\n\tassert.GreaterOrEqual(t, running, int64(5))\n\tassert.LessOrEqual(t, running, int64(10))\n}\n"
  },
  {
    "path": "lib/executor/constant_vus.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst constantVUsType = \"constant-vus\"\n\nfunc init() {\n\tlib.RegisterExecutorConfigType(\n\t\tconstantVUsType,\n\t\tfunc(name string, rawJSON []byte) (lib.ExecutorConfig, error) {\n\t\t\tconfig := NewConstantVUsConfig(name)\n\t\t\terr := lib.StrictJSONUnmarshal(rawJSON, &config)\n\t\t\treturn config, err\n\t\t},\n\t)\n}\n\n// The minimum duration we'll allow users to schedule. This doesn't affect the stages\n// configuration, where 0-duration virtual stages are allowed for instantaneous VU jumps\nconst minDuration = 1 * time.Second\n\n// ConstantVUsConfig stores VUs and duration\ntype ConstantVUsConfig struct {\n\tBaseConfig\n\tVUs      null.Int           `json:\"vus\"`\n\tDuration types.NullDuration `json:\"duration\"`\n}\n\n// NewConstantVUsConfig returns a ConstantVUsConfig with default values\nfunc NewConstantVUsConfig(name string) ConstantVUsConfig {\n\treturn ConstantVUsConfig{\n\t\tBaseConfig: NewBaseConfig(name, constantVUsType),\n\t\tVUs:        null.NewInt(1, false),\n\t}\n}\n\n// Make sure we implement the lib.ExecutorConfig interface\nvar _ lib.ExecutorConfig = &ConstantVUsConfig{}\n\n// GetVUs returns the scaled VUs for the executor.\nfunc (clvc ConstantVUsConfig) GetVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(clvc.VUs.Int64)\n}\n\n// GetDescription returns a human-readable description of the executor options\nfunc (clvc ConstantVUsConfig) GetDescription(et *lib.ExecutionTuple) string {\n\treturn fmt.Sprintf(\"%d looping VUs for %s%s\",\n\t\tclvc.GetVUs(et), clvc.Duration.Duration, clvc.getBaseInfo())\n}\n\n// Validate makes sure all options are configured and valid\nfunc (clvc ConstantVUsConfig) Validate() []error {\n\terrors := clvc.BaseConfig.Validate()\n\tif clvc.VUs.Int64 <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of VUs must be more than 0\"))\n\t}\n\n\tif !clvc.Duration.Valid {\n\t\terrors = append(errors, fmt.Errorf(\"the duration is unspecified\"))\n\t} else if clvc.Duration.TimeDuration() < minDuration {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the duration must be at least %s, but is %s\", minDuration, clvc.Duration,\n\t\t))\n\t}\n\n\treturn errors\n}\n\n// GetExecutionRequirements returns the number of required VUs to run the\n// executor for its whole duration (disregarding any startTime), including the\n// maximum waiting time for any iterations to gracefully stop. This is used by\n// the execution scheduler in its VU reservation calculations, so it knows how\n// many VUs to pre-initialize.\nfunc (clvc ConstantVUsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {\n\treturn []lib.ExecutionStep{\n\t\t{\n\t\t\tTimeOffset: 0,\n\t\t\tPlannedVUs: uint64(clvc.GetVUs(et)), //nolint:gosec\n\t\t},\n\t\t{\n\t\t\tTimeOffset: clvc.Duration.TimeDuration() + clvc.GracefulStop.TimeDuration(),\n\t\t\tPlannedVUs: 0,\n\t\t},\n\t}\n}\n\n// HasWork reports whether there is any work to be done for the given execution segment.\nfunc (clvc ConstantVUsConfig) HasWork(et *lib.ExecutionTuple) bool {\n\treturn clvc.GetVUs(et) > 0\n}\n\n// NewExecutor creates a new ConstantVUs executor\nfunc (clvc ConstantVUsConfig) NewExecutor(es *lib.ExecutionState, logger *logrus.Entry) (lib.Executor, error) {\n\treturn ConstantVUs{\n\t\tBaseExecutor: NewBaseExecutor(clvc, es, logger),\n\t\tconfig:       clvc,\n\t}, nil\n}\n\n// ConstantVUs maintains a constant number of VUs running for the\n// specified duration.\ntype ConstantVUs struct {\n\t*BaseExecutor\n\tconfig ConstantVUsConfig\n}\n\n// Make sure we implement the lib.Executor interface.\nvar _ lib.Executor = &ConstantVUs{}\n\n// Run constantly loops through as many iterations as possible on a fixed number\n// of VUs for the specified duration.\nfunc (clv ConstantVUs) Run(parentCtx context.Context, _ chan<- metrics.SampleContainer) (err error) {\n\tnumVUs := clv.config.GetVUs(clv.executionState.ExecutionTuple)\n\tduration := clv.config.Duration.TimeDuration()\n\tgracefulStop := clv.config.GetGracefulStop()\n\n\twaitOnProgressChannel := make(chan struct{})\n\tstartTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(parentCtx, duration, gracefulStop)\n\tdefer func() {\n\t\tcancel()\n\t\t<-waitOnProgressChannel\n\t}()\n\n\t// Make sure the log and the progress bar have accurate information\n\tclv.logger.WithFields(\n\t\tlogrus.Fields{\"vus\": numVUs, \"duration\": duration, \"type\": clv.config.GetType()},\n\t).Debug(\"Starting executor run...\")\n\n\tprogressFn := func() (float64, []string) {\n\t\tspent := time.Since(startTime)\n\t\tright := []string{fmt.Sprintf(\"%d VUs\", numVUs)}\n\t\tif spent > duration {\n\t\t\tright = append(right, duration.String())\n\t\t\treturn 1, right\n\t\t}\n\t\tright = append(right, fmt.Sprintf(\"%s/%s\",\n\t\t\tpb.GetFixedLengthDuration(spent, duration), duration))\n\t\treturn float64(spent) / float64(duration), right\n\t}\n\tclv.progress.Modify(pb.WithProgress(progressFn))\n\tmaxDurationCtx = lib.WithScenarioState(maxDurationCtx, &lib.ScenarioState{\n\t\tName:       clv.config.Name,\n\t\tExecutor:   clv.config.Type,\n\t\tStartTime:  startTime,\n\t\tProgressFn: progressFn,\n\t})\n\n\tgo func() {\n\t\ttrackProgress(parentCtx, maxDurationCtx, regDurationCtx, clv, progressFn)\n\t\tclose(waitOnProgressChannel)\n\t}()\n\n\t// Actually schedule the VUs and iterations...\n\tactiveVUs := &sync.WaitGroup{}\n\tdefer activeVUs.Wait()\n\n\tregDurationDone := regDurationCtx.Done()\n\trunIteration := getIterationRunner(clv.executionState, clv.logger)\n\n\treturnVU := func(u lib.InitializedVU) {\n\t\tclv.executionState.ReturnVU(u, true)\n\t\tactiveVUs.Done()\n\t}\n\n\thandleVU := func(initVU lib.InitializedVU) {\n\t\tctx, cancel := context.WithCancel(maxDurationCtx)\n\t\tdefer cancel()\n\n\t\tactiveVU := initVU.Activate(\n\t\t\tgetVUActivationParams(ctx, clv.config.BaseConfig, returnVU, clv.nextIterationCounters))\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-regDurationDone:\n\t\t\t\treturn // don't make more iterations\n\t\t\tdefault: // continue looping\n\t\t\t}\n\t\t\trunIteration(maxDurationCtx, activeVU)\n\t\t}\n\t}\n\n\tfor range numVUs {\n\t\tinitVU, err := clv.executionState.GetPlannedVU(clv.logger, true)\n\t\tif err != nil {\n\t\t\tcancel()\n\t\t\treturn err\n\t\t}\n\t\tactiveVUs.Add(1)\n\t\tgo handleVU(initVU)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "lib/executor/constant_vus_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc getTestConstantVUsConfig() ConstantVUsConfig {\n\treturn ConstantVUsConfig{\n\t\tBaseConfig: BaseConfig{GracefulStop: types.NullDurationFrom(100 * time.Millisecond)},\n\t\tVUs:        null.IntFrom(10),\n\t\tDuration:   types.NullDurationFrom(1 * time.Second),\n\t}\n}\n\nfunc TestConstantVUsRun(t *testing.T) {\n\tt.Parallel()\n\tvar result sync.Map\n\n\trunner := simpleRunner(func(ctx context.Context, state *lib.State) error {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\t\tcurrIter, _ := result.LoadOrStore(state.VUID, uint64(0))\n\t\tresult.Store(state.VUID, currIter.(uint64)+1)\n\t\ttime.Sleep(210 * time.Millisecond)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestConstantVUsConfig())\n\tdefer test.cancel()\n\n\trequire.NoError(t, test.executor.Run(test.ctx, nil))\n\n\tvar totalIters uint64\n\tresult.Range(func(_, value any) bool {\n\t\tvuIters := value.(uint64)\n\t\tassert.Equal(t, uint64(5), vuIters)\n\t\ttotalIters += vuIters\n\t\treturn true\n\t})\n\tassert.Equal(t, uint64(50), totalIters)\n}\n"
  },
  {
    "path": "lib/executor/execution_config_shortcuts.go",
    "content": "package executor\n\nimport (\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// ExecutionConflictError is a custom error type used for all of the errors in\n// the DeriveScenariosFromShortcuts() function.\ntype ExecutionConflictError string\n\nfunc (e ExecutionConflictError) Error() string {\n\treturn string(e)\n}\n\nvar _ error = ExecutionConflictError(\"\")\n\nfunc getConstantVUsScenario(duration types.NullDuration, vus null.Int) lib.ScenarioConfigs {\n\tds := NewConstantVUsConfig(lib.DefaultScenarioName)\n\tds.VUs = vus\n\tds.Duration = duration\n\treturn lib.ScenarioConfigs{lib.DefaultScenarioName: ds}\n}\n\nfunc getRampingVUsScenario(stages []lib.Stage, startVUs null.Int) lib.ScenarioConfigs {\n\tds := NewRampingVUsConfig(lib.DefaultScenarioName)\n\tds.StartVUs = startVUs\n\tfor _, s := range stages {\n\t\tif s.Duration.Valid {\n\t\t\tds.Stages = append(ds.Stages, Stage{Duration: s.Duration, Target: s.Target})\n\t\t}\n\t}\n\treturn lib.ScenarioConfigs{lib.DefaultScenarioName: ds}\n}\n\nfunc getSharedIterationsScenario(iters null.Int, duration types.NullDuration, vus null.Int) lib.ScenarioConfigs {\n\tds := NewSharedIterationsConfig(lib.DefaultScenarioName)\n\tds.VUs = vus\n\tds.Iterations = iters\n\tif duration.Valid {\n\t\tds.MaxDuration = duration\n\t}\n\treturn lib.ScenarioConfigs{lib.DefaultScenarioName: ds}\n}\n\n// DeriveScenariosFromShortcuts checks for conflicting options and turns any\n// shortcut options (i.e. duration, iterations, stages) into the proper\n// long-form scenario/executor configuration in the scenarios property.\nfunc DeriveScenariosFromShortcuts(opts lib.Options, logger logrus.FieldLogger) (lib.Options, error) {\n\tresult := opts\n\n\tswitch {\n\tcase opts.Iterations.Valid:\n\t\tif len(opts.Stages) > 0 { // stages isn't nil (not set) and isn't explicitly set to empty\n\t\t\treturn result, ExecutionConflictError(\n\t\t\t\t\"using `iterations` and `stages` options simultaneously is not allowed\",\n\t\t\t)\n\t\t}\n\t\tif opts.Scenarios != nil {\n\t\t\treturn opts, ExecutionConflictError(\n\t\t\t\t\"using `iterations` and `scenarios` options simultaneously is not allowed\",\n\t\t\t)\n\t\t}\n\t\tresult.Scenarios = getSharedIterationsScenario(opts.Iterations, opts.Duration, opts.VUs)\n\n\tcase opts.Duration.Valid:\n\t\tif len(opts.Stages) > 0 { // stages isn't nil (not set) and isn't explicitly set to empty\n\t\t\treturn result, ExecutionConflictError(\n\t\t\t\t\"using `duration` and `stages` options simultaneously is not allowed\",\n\t\t\t)\n\t\t}\n\t\tif opts.Scenarios != nil {\n\t\t\treturn result, ExecutionConflictError(\n\t\t\t\t\"using `duration` and `scenarios` options simultaneously is not allowed\",\n\t\t\t)\n\t\t}\n\t\tif opts.Duration.Duration <= 0 {\n\t\t\t// TODO: move this validation to Validate()?\n\t\t\treturn result, ExecutionConflictError(\n\t\t\t\t\"`duration` option should be more than 0, for infinite duration use the externally-controlled executor\",\n\t\t\t)\n\t\t}\n\t\tresult.Scenarios = getConstantVUsScenario(opts.Duration, opts.VUs)\n\n\tcase len(opts.Stages) > 0: // stages isn't nil (not set) and isn't explicitly set to empty\n\t\tif opts.Scenarios != nil {\n\t\t\treturn opts, ExecutionConflictError(\n\t\t\t\t\"using `stages` and `scenarios` options simultaneously is not allowed\",\n\t\t\t)\n\t\t}\n\t\tresult.Scenarios = getRampingVUsScenario(opts.Stages, opts.VUs)\n\n\tcase len(opts.Scenarios) > 0:\n\t\t// Do nothing, scenarios was explicitly specified\n\n\tdefault:\n\t\t// Check if we should emit some warnings\n\t\tif opts.VUs.Valid && opts.VUs.Int64 != 1 {\n\t\t\tlogger.Warnf(\n\t\t\t\t\"`vus=%d` option will be ignored, it only works in conjunction with `iterations`, `duration`, or `stages`\",\n\t\t\t\topts.VUs.Int64,\n\t\t\t)\n\t\t}\n\t\tif opts.Stages != nil && len(opts.Stages) == 0 {\n\t\t\t// No someone explicitly set stages to empty\n\t\t\tlogger.Warnf(\"`stages` was explicitly set to an empty value, running the script with 1 iteration in 1 VU\")\n\t\t}\n\t\tif opts.Scenarios != nil && len(opts.Scenarios) == 0 {\n\t\t\t// No shortcut, and someone explicitly set execution to empty\n\t\t\tlogger.Warnf(\"`scenarios` was explicitly set to an empty value, running the script with 1 iteration in 1 VU\")\n\t\t}\n\t\t// No execution parameters whatsoever were specified, so we'll create a per-VU iterations config\n\t\t// with 1 VU and 1 iteration.\n\t\tresult.Scenarios = lib.ScenarioConfigs{\n\t\t\tlib.DefaultScenarioName: NewPerVUIterationsConfig(lib.DefaultScenarioName),\n\t\t}\n\t}\n\n\t// TODO: validate the config; questions:\n\t// - separately validate the duration, iterations and stages for better error messages?\n\t// - or reuse the execution validation somehow, at the end? or something mixed?\n\t// - here or in getConsolidatedConfig() or somewhere else?\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "lib/executor/execution_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/lib\"\n)\n\nfunc TestExecutionStateVUIDs(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tseq, seg string\n\t}{\n\t\t{},\n\t\t{seq: \"0,1/4,3/4,1\", seg: \"0:1/4\"},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0.5:0.6\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"seq:%s;segment:%s\", tc.seq, tc.seg), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tess, err := lib.NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\trequire.NoError(t, err)\n\t\t\tsegment, err := lib.NewExecutionSegmentFromString(tc.seg)\n\t\t\trequire.NoError(t, err)\n\t\t\tet, err := lib.NewExecutionTuple(segment, &ess)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tstart, offsets, _ := et.GetStripedOffsets()\n\t\t\tes := lib.NewExecutionState(nil, et, 0, 0)\n\n\t\t\tidl, idg := es.GetUniqueVUIdentifiers()\n\t\t\tassert.EqualValues(t, 1, idl)\n\t\t\texpGlobal := start + 1\n\t\t\tassert.EqualValues(t, expGlobal, idg)\n\n\t\t\tidl, idg = es.GetUniqueVUIdentifiers()\n\t\t\tassert.EqualValues(t, 2, idl)\n\t\t\texpGlobal += offsets[0]\n\t\t\tassert.EqualValues(t, expGlobal, idg)\n\n\t\t\tidl, idg = es.GetUniqueVUIdentifiers()\n\t\t\tassert.EqualValues(t, 3, idl)\n\t\t\texpGlobal += offsets[0]\n\t\t\tassert.EqualValues(t, expGlobal, idg)\n\n\t\t\tseed := time.Now().UnixNano()\n\t\t\tr := rand.New(rand.NewSource(seed))\n\t\t\tt.Logf(\"Random source seeded with %d\\n\", seed)\n\t\t\tcount := 100 + r.Intn(50)\n\t\t\twg := sync.WaitGroup{}\n\t\t\twg.Add(count)\n\t\t\tfor range count {\n\t\t\t\tgo func() {\n\t\t\t\t\tes.GetUniqueVUIdentifiers()\n\t\t\t\t\twg.Done()\n\t\t\t\t}()\n\t\t\t}\n\t\t\twg.Wait()\n\t\t\tidl, idg = es.GetUniqueVUIdentifiers()\n\t\t\tassert.EqualValues(t, 4+count, idl)\n\t\t\tassert.EqualValues(t, (3+count)*int(offsets[0])+int(start+1), idg)\n\t\t})\n\t}\n}\n\nfunc TestExecutionStateGettingVUsWhenNonAreAvailable(t *testing.T) {\n\tt.Parallel()\n\tet, err := lib.NewExecutionTuple(nil, nil)\n\trequire.NoError(t, err)\n\tes := lib.NewExecutionState(nil, et, 0, 0)\n\tlogHook := testutils.NewLogHook(logrus.WarnLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\ttestLog.SetOutput(io.Discard)\n\tvu, err := es.GetPlannedVU(logrus.NewEntry(testLog), true)\n\trequire.Nil(t, vu)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"could not get a VU from the buffer in\")\n\tentries := logHook.Drain()\n\trequire.Equal(t, lib.MaxRetriesGetPlannedVU, len(entries))\n\tfor _, entry := range entries {\n\t\trequire.Contains(t, entry.Message, \"Could not get a VU from the buffer for \")\n\t}\n}\n\nfunc TestExecutionStateGettingVUs(t *testing.T) {\n\tt.Parallel()\n\tlogHook := testutils.NewLogHook(logrus.WarnLevel, logrus.DebugLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\ttestLog.SetOutput(io.Discard)\n\tlogEntry := logrus.NewEntry(testLog)\n\n\tet, err := lib.NewExecutionTuple(nil, nil)\n\trequire.NoError(t, err)\n\tes := lib.NewExecutionState(nil, et, 10, 20)\n\tes.SetInitVUFunc(func(_ context.Context, _ *logrus.Entry) (lib.InitializedVU, error) {\n\t\treturn &minirunner.VU{}, nil\n\t})\n\n\tvar vu lib.InitializedVU\n\tfor i := range 10 {\n\t\trequire.EqualValues(t, i, es.GetInitializedVUsCount())\n\t\tvu, err = es.InitializeNewVU(context.Background(), logEntry)\n\t\trequire.NoError(t, err)\n\t\trequire.EqualValues(t, i+1, es.GetInitializedVUsCount())\n\t\tes.ReturnVU(vu, false)\n\t\trequire.EqualValues(t, 0, es.GetCurrentlyActiveVUsCount())\n\t\trequire.EqualValues(t, i+1, es.GetInitializedVUsCount())\n\t}\n\n\t// Test getting initialized VUs is okay :)\n\tfor i := range 10 {\n\t\trequire.EqualValues(t, i, es.GetCurrentlyActiveVUsCount())\n\t\tvu, err = es.GetPlannedVU(logEntry, true)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, logHook.Drain())\n\t\trequire.NotNil(t, vu)\n\t\trequire.EqualValues(t, i+1, es.GetCurrentlyActiveVUsCount())\n\t\trequire.EqualValues(t, 10, es.GetInitializedVUsCount())\n\t}\n\n\t// Check that getting 1 more planned VU will error out\n\tvu, err = es.GetPlannedVU(logEntry, true)\n\trequire.Nil(t, vu)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"could not get a VU from the buffer in\")\n\tentries := logHook.Drain()\n\trequire.Equal(t, lib.MaxRetriesGetPlannedVU, len(entries))\n\tfor _, entry := range entries {\n\t\trequire.Contains(t, entry.Message, \"Could not get a VU from the buffer for \")\n\t}\n\n\t// Test getting uninitialized vus will work\n\tfor i := range 10 {\n\t\trequire.EqualValues(t, 10+i, es.GetInitializedVUsCount())\n\t\tvu, err = es.GetUnplannedVU(context.Background(), logEntry)\n\t\trequire.NoError(t, err)\n\t\trequire.Empty(t, logHook.Drain())\n\t\trequire.NotNil(t, vu)\n\t\trequire.EqualValues(t, 10+i+1, es.GetInitializedVUsCount())\n\t\trequire.EqualValues(t, 10, es.GetCurrentlyActiveVUsCount())\n\t}\n\n\t// Check that getting 1 more unplanned VU will error out\n\tvu, err = es.GetUnplannedVU(context.Background(), logEntry)\n\trequire.Nil(t, vu)\n\trequire.Error(t, err)\n\trequire.Contains(t, err.Error(), \"could not get a VU from the buffer in\")\n\tentries = logHook.Drain()\n\trequire.Equal(t, lib.MaxRetriesGetPlannedVU, len(entries))\n\tfor _, entry := range entries {\n\t\trequire.Contains(t, entry.Message, \"Could not get a VU from the buffer for \")\n\t}\n}\n\nfunc TestMarkStartedPanicsOnSecondRun(t *testing.T) {\n\tt.Parallel()\n\tet, err := lib.NewExecutionTuple(nil, nil)\n\trequire.NoError(t, err)\n\tes := lib.NewExecutionState(nil, et, 0, 0)\n\trequire.False(t, es.HasStarted())\n\tes.MarkStarted()\n\trequire.True(t, es.HasStarted())\n\trequire.Panics(t, es.MarkStarted)\n}\n\nfunc TestMarkEnded(t *testing.T) {\n\tt.Parallel()\n\tet, err := lib.NewExecutionTuple(nil, nil)\n\trequire.NoError(t, err)\n\tes := lib.NewExecutionState(nil, et, 0, 0)\n\trequire.False(t, es.HasEnded())\n\tes.MarkEnded()\n\trequire.True(t, es.HasEnded())\n\trequire.Panics(t, es.MarkEnded)\n}\n"
  },
  {
    "path": "lib/executor/executors_test.go",
    "content": "package executor\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\t\"time\"\n\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\ntype exp struct {\n\tparseError      bool\n\tvalidationError bool\n\tcustom          func(t *testing.T, cm lib.ScenarioConfigs)\n}\n\ntype configMapTestCase struct {\n\trawJSON  string\n\texpected exp\n}\n\n//nolint:gochecknoglobals\nvar configMapTestCases = []configMapTestCase{\n\t{\"\", exp{parseError: true}},\n\t{\"1234\", exp{parseError: true}},\n\t{\"asdf\", exp{parseError: true}},\n\t{\"'adsf'\", exp{parseError: true}},\n\t{\"[]\", exp{parseError: true}},\n\t{\"{}\", exp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\tassert.Equal(t, cm, lib.ScenarioConfigs{})\n\t}}},\n\t{\"{}asdf\", exp{parseError: true}},\n\t{\"null\", exp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\tassert.Nil(t, cm)\n\t}}},\n\t{`{\"someKey\": {}}`, exp{parseError: true}},\n\t{`{\"someKey\": {\"executor\": \"constant-blah-blah\", \"vus\": 10, \"duration\": \"60s\"}}`, exp{parseError: true}},\n\t{`{\"someKey\": {\"executor\": \"constant-vus\", \"uknownField\": \"should_error\"}}`, exp{parseError: true}},\n\t{`{\"someKey\": {\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"60s\", \"env\": 123}}`, exp{parseError: true}},\n\n\t// Validation errors for constant-vus and the base config\n\t{\n\t\t`{\"someKey\": {\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"60s\",\n\t\t\"gracefulStop\": \"10s\", \"startTime\": \"70s\", \"env\": {\"test\": \"mest\"}, \"exec\": \"someFunc\"}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tsched := NewConstantVUsConfig(\"someKey\")\n\t\t\tsched.VUs = null.IntFrom(10)\n\t\t\tsched.Duration = types.NullDurationFrom(1 * time.Minute)\n\t\t\tsched.GracefulStop = types.NullDurationFrom(10 * time.Second)\n\t\t\tsched.StartTime = types.NullDurationFrom(70 * time.Second)\n\t\t\tsched.Exec = null.StringFrom(\"someFunc\")\n\t\t\tsched.Env = map[string]string{\"test\": \"mest\"}\n\t\t\trequire.Equal(t, cm, lib.ScenarioConfigs{\"someKey\": sched})\n\t\t\trequire.Equal(t, sched.Name, cm[\"someKey\"].GetName())\n\t\t\trequire.Equal(t, sched.Type, cm[\"someKey\"].GetType())\n\t\t\trequire.Equal(t, sched.GetGracefulStop(), cm[\"someKey\"].GetGracefulStop())\n\t\t\trequire.Equal(t,\n\t\t\t\tsched.StartTime.Duration,\n\t\t\t\ttypes.Duration(cm[\"someKey\"].GetStartTime()),\n\t\t\t)\n\t\t\trequire.Equal(t, sched.Env, cm[\"someKey\"].GetEnv())\n\n\t\t\tassert.Empty(t, cm[\"someKey\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"10 looping VUs for 1m0s (exec: someFunc, startTime: 1m10s, gracefulStop: 10s)\", cm[\"someKey\"].GetDescription(et))\n\n\t\t\tschedReqs := cm[\"someKey\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal := lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 70*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tendOffset, isFinal = lib.GetEndOffset(totalReqs)\n\t\t\tassert.Equal(t, 140*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPossibleVUs(schedReqs))\n\t\t}},\n\t},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"duration\": \"60s\"}}`, exp{}},\n\t{`{\"\": {\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"60s\"}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\"}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": 0.5}}`, exp{parseError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": 10}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": 0, \"duration\": \"60s\"}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": -1, \"duration\": \"60s\"}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"0s\"}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"10s\", \"startTime\": \"-10s\"}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"10s\", \"exec\": \"\"}}`, exp{validationError: true}},\n\t{`{\"aname\": {\"executor\": \"constant-vus\", \"vus\": 10, \"duration\": \"10s\", \"gracefulStop\": \"-2s\"}}`, exp{validationError: true}},\n\t// ramping-vus\n\t{\n\t\t`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": 20, \"gracefulStop\": \"15s\", \"gracefulRampDown\": \"10s\",\n\t\t    \"startTime\": \"23s\", \"stages\": [{\"duration\": \"60s\", \"target\": 30}, {\"duration\": \"130s\", \"target\": 10}]}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tsched := NewRampingVUsConfig(\"varloops\")\n\t\t\tsched.GracefulStop = types.NullDurationFrom(15 * time.Second)\n\t\t\tsched.GracefulRampDown = types.NullDurationFrom(10 * time.Second)\n\t\t\tsched.StartVUs = null.IntFrom(20)\n\t\t\tsched.StartTime = types.NullDurationFrom(23 * time.Second)\n\t\t\tsched.Stages = []Stage{\n\t\t\t\t{Target: null.IntFrom(30), Duration: types.NullDurationFrom(60 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(10), Duration: types.NullDurationFrom(130 * time.Second)},\n\t\t\t}\n\t\t\trequire.Equal(t, cm, lib.ScenarioConfigs{\"varloops\": sched})\n\n\t\t\tassert.Empty(t, cm[\"varloops\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"Up to 30 looping VUs for 3m10s over 2 stages (gracefulRampDown: 10s, startTime: 23s, gracefulStop: 15s)\", cm[\"varloops\"].GetDescription(et))\n\n\t\t\tschedReqs := cm[\"varloops\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal := lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 205*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(30), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(30), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tendOffset, isFinal = lib.GetEndOffset(totalReqs)\n\t\t\tassert.Equal(t, 228*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(30), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(30), lib.GetMaxPossibleVUs(schedReqs))\n\t\t}},\n\t},\n\t{\n\t\t`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": 1, \"gracefulStop\": \"0s\", \"gracefulRampDown\": \"10s\",\n\t\t\t\"stages\": [{\"duration\": \"10s\", \"target\": 10}]}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tassert.Empty(t, cm[\"varloops\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"Up to 10 looping VUs for 10s over 1 stages (gracefulRampDown: 10s)\", cm[\"varloops\"].GetDescription(et))\n\n\t\t\tschedReqs := cm[\"varloops\"].GetExecutionRequirements(et)\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPossibleVUs(schedReqs))\n\t\t}},\n\t},\n\t{\n\t\t`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": 1, \"gracefulStop\": \"0s\", \"gracefulRampDown\": \"0s\",\n\t\t\t\"stages\": [{\"duration\": \"10s\", \"target\": 10}, {\"duration\": \"0s\", \"target\": 1}, {\"duration\": \"10s\", \"target\": 5}]}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tassert.Empty(t, cm[\"varloops\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"Up to 10 looping VUs for 20s over 3 stages (gracefulRampDown: 0s)\", cm[\"varloops\"].GetDescription(et))\n\n\t\t\tschedReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(10), lib.GetMaxPossibleVUs(schedReqs))\n\t\t}},\n\t},\n\t{\n\t\t`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": 1, \"gracefulStop\": \"0s\", \"gracefulRampDown\": \"0s\",\n\t\t\t\"stages\": [{\"duration\": \"10s\", \"target\": 10}, {\"duration\": \"0s\", \"target\": 11},{\"duration\": \"0s\", \"target\": 1}, {\"duration\": \"10s\", \"target\": 5}]}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tassert.Empty(t, cm[\"varloops\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"Up to 11 looping VUs for 20s over 4 stages (gracefulRampDown: 0s)\", cm[\"varloops\"].GetDescription(et))\n\n\t\t\tschedReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, uint64(11), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(11), lib.GetMaxPossibleVUs(schedReqs))\n\t\t}},\n\t},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": 0, \"stages\": [{\"duration\": \"60s\", \"target\": 0}]}}`, exp{validationError: true}},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": -1, \"stages\": [{\"duration\": \"60s\", \"target\": 30}]}}`, exp{validationError: true}},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": 2, \"stages\": [{\"duration\": \"-60s\", \"target\": 30}]}}`, exp{validationError: true}},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\", \"startVUs\": 2, \"stages\": [{\"duration\": \"60s\", \"target\": -30}]}}`, exp{validationError: true}},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\", \"stages\": [{\"duration\": \"60s\"}]}}`, exp{validationError: true}},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\", \"stages\": [{\"target\": 30}]}}`, exp{validationError: true}},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\", \"stages\": []}}`, exp{validationError: true}},\n\t{`{\"varloops\": {\"executor\": \"ramping-vus\"}}`, exp{validationError: true}},\n\t// shared-iterations\n\t{\n\t\t`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": 22, \"vus\": 12, \"maxDuration\": \"100s\"}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tsched := NewSharedIterationsConfig(\"ishared\")\n\t\t\tsched.Iterations = null.IntFrom(22)\n\t\t\tsched.MaxDuration = types.NullDurationFrom(100 * time.Second)\n\t\t\tsched.VUs = null.IntFrom(12)\n\n\t\t\tassert.Empty(t, cm[\"ishared\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"22 iterations shared among 12 VUs (maxDuration: 1m40s, gracefulStop: 30s)\", cm[\"ishared\"].GetDescription(et))\n\n\t\t\tschedReqs := cm[\"ishared\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal := lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 130*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(12), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(12), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, schedReqs, totalReqs)\n\n\t\t\tet = mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\"))\n\t\t\tassert.Equal(t, \"8 iterations shared among 4 VUs (maxDuration: 1m40s, gracefulStop: 30s)\", cm[\"ishared\"].GetDescription(et))\n\n\t\t\tschedReqs = cm[\"ishared\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal = lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 130*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(4), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(4), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs = cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, schedReqs, totalReqs)\n\n\t\t\tet = mustNewExecutionTuple(newExecutionSegmentFromString(\"1/3:2/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\"))\n\t\t\tassert.Equal(t, \"7 iterations shared among 4 VUs (maxDuration: 1m40s, gracefulStop: 30s)\", cm[\"ishared\"].GetDescription(et))\n\n\t\t\tschedReqs = cm[\"ishared\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal = lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 130*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(4), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(4), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs = cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, schedReqs, totalReqs)\n\n\t\t\tet = mustNewExecutionTuple(newExecutionSegmentFromString(\"12/13:1\"),\n\t\t\t\tnewExecutionSegmentSequenceFromString(\"0,1/13,2/13,3/13,4/13,5/13,6/13,7/13,8/13,9/13,10/13,11/13,12/13,1\"))\n\t\t\tassert.Equal(t, \"0 iterations shared among 0 VUs (maxDuration: 1m40s, gracefulStop: 30s)\", cm[\"ishared\"].GetDescription(et))\n\n\t\t\tschedReqs = cm[\"ishared\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal = lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, time.Duration(0), endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(0), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(0), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs = cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, schedReqs, totalReqs)\n\t\t}},\n\t},\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\"}}`, exp{}}, // Has 1 VU & 1 iter default values\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": 20}}`, exp{}},\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"vus\": 10}}`, exp{validationError: true}}, // error because VUs are more than iters\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": 20, \"vus\": 10, \"maxDuration\": \"30m\"}}`, exp{}},\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": 20, \"vus\": 10, \"maxDuration\": \"-3m\"}}`, exp{validationError: true}},\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": 20, \"vus\": 10, \"maxDuration\": \"0s\"}}`, exp{validationError: true}},\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": 20, \"vus\": -10}}`, exp{validationError: true}},\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": -1, \"vus\": 1}}`, exp{validationError: true}},\n\t{`{\"ishared\": {\"executor\": \"shared-iterations\", \"iterations\": 20, \"vus\": 30}}`, exp{validationError: true}},\n\t// per-vu-iterations\n\t{\n\t\t`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"iterations\": 23, \"vus\": 13, \"gracefulStop\": 0}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tsched := NewPerVUIterationsConfig(\"ipervu\")\n\t\t\tsched.Iterations = null.IntFrom(23)\n\t\t\tsched.GracefulStop = types.NullDurationFrom(0)\n\t\t\tsched.VUs = null.IntFrom(13)\n\n\t\t\tassert.Empty(t, cm[\"ipervu\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"23 iterations for each of 13 VUs (maxDuration: 10m0s)\", cm[\"ipervu\"].GetDescription(et))\n\n\t\t\tschedReqs := cm[\"ipervu\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal := lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 600*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(13), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(13), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, schedReqs, totalReqs)\n\t\t}},\n\t},\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\"}}`, exp{}}, // Has 1 VU & 1 iter default values\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"iterations\": 20}}`, exp{}},\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"vus\": 10}}`, exp{}},\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"iterations\": 20, \"vus\": 10}}`, exp{}},\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"iterations\": 20, \"vus\": 10, \"maxDuration\": \"-3m\"}}`, exp{validationError: true}},\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"iterations\": 20, \"vus\": 10, \"maxDuration\": \"0s\"}}`, exp{validationError: true}},\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"iterations\": 20, \"vus\": -10}}`, exp{validationError: true}},\n\t{`{\"ipervu\": {\"executor\": \"per-vu-iterations\", \"iterations\": -1, \"vus\": 1}}`, exp{validationError: true}},\n\n\t// constant-arrival-rate\n\t{\n\t\t`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 30, \"timeUnit\": \"1m\", \"duration\": \"10m\", \"preAllocatedVUs\": 20, \"maxVUs\": 30}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tsched := NewConstantArrivalRateConfig(\"carrival\")\n\t\t\tsched.Rate = null.IntFrom(30)\n\t\t\tsched.Duration = types.NullDurationFrom(10 * time.Minute)\n\t\t\tsched.TimeUnit = types.NullDurationFrom(1 * time.Minute)\n\t\t\tsched.PreAllocatedVUs = null.IntFrom(20)\n\t\t\tsched.MaxVUs = null.IntFrom(30)\n\n\t\t\tassert.Empty(t, cm[\"carrival\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tassert.Equal(t, \"0.50 iterations/s for 10m0s (maxVUs: 20-30, gracefulStop: 30s)\", cm[\"carrival\"].GetDescription(et))\n\n\t\t\tschedReqs := cm[\"carrival\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal := lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 630*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(20), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(30), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, schedReqs, totalReqs)\n\t\t}},\n\t},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"10m\", \"preAllocatedVUs\": 20, \"maxVUs\": 30}}`, exp{}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"10m\", \"preAllocatedVUs\": 20, \"maxVUs\": 30, \"timeUnit\": \"-1s\"}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"10m\", \"preAllocatedVUs\": 20, \"maxVUs\": 30, \"timeUnit\": \"0s\"}}`, exp{validationError: true}},\n\t{\n\t\t`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"10m\", \"preAllocatedVUs\": 20}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tassert.Empty(t, cm[\"carrival\"].Validate())\n\t\t\trequire.EqualValues(t, 20, cm[\"carrival\"].(*ConstantArrivalRateConfig).MaxVUs.Int64)\n\t\t}},\n\t},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"10m\", \"maxVUs\": 30}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"preAllocatedVUs\": 20, \"maxVUs\": 30}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"duration\": \"10m\", \"preAllocatedVUs\": 20, \"maxVUs\": 30}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"0m\", \"preAllocatedVUs\": 20, \"maxVUs\": 30}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 0, \"duration\": \"10m\", \"preAllocatedVUs\": 20, \"maxVUs\": 30}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"10m\", \"preAllocatedVUs\": 20, \"maxVUs\": 15}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"0s\", \"preAllocatedVUs\": 20, \"maxVUs\": 25}}`, exp{validationError: true}},\n\t{`{\"carrival\": {\"executor\": \"constant-arrival-rate\", \"rate\": 10, \"duration\": \"10m\", \"preAllocatedVUs\": -2, \"maxVUs\": 25}}`, exp{validationError: true}},\n\t// ramping-arrival-rate\n\t{\n\t\t`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"startRate\": 10, \"timeUnit\": \"30s\", \"preAllocatedVUs\": 20,\n\t\t\"maxVUs\": 50, \"stages\": [{\"duration\": \"3m\", \"target\": 30}, {\"duration\": \"5m\", \"target\": 10}]}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tsched := NewRampingArrivalRateConfig(\"varrival\")\n\t\t\tsched.StartRate = null.IntFrom(10)\n\t\t\tsched.Stages = []Stage{\n\t\t\t\t{Target: null.IntFrom(30), Duration: types.NullDurationFrom(180 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(10), Duration: types.NullDurationFrom(300 * time.Second)},\n\t\t\t}\n\t\t\tsched.TimeUnit = types.NullDurationFrom(30 * time.Second)\n\t\t\tsched.PreAllocatedVUs = null.IntFrom(20)\n\t\t\tsched.MaxVUs = null.IntFrom(50)\n\t\t\trequire.Equal(t, cm, lib.ScenarioConfigs{\"varrival\": sched})\n\n\t\t\tassert.Empty(t, cm[\"varrival\"].Validate())\n\t\t\tassert.Empty(t, cm.Validate())\n\n\t\t\tet, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, \"Up to 1.00 iterations/s for 8m0s over 2 stages (maxVUs: 20-50, gracefulStop: 30s)\", cm[\"varrival\"].GetDescription(et))\n\n\t\t\tschedReqs := cm[\"varrival\"].GetExecutionRequirements(et)\n\t\t\tendOffset, isFinal := lib.GetEndOffset(schedReqs)\n\t\t\tassert.Equal(t, 510*time.Second, endOffset)\n\t\t\tassert.Equal(t, true, isFinal)\n\t\t\tassert.Equal(t, uint64(20), lib.GetMaxPlannedVUs(schedReqs))\n\t\t\tassert.Equal(t, uint64(50), lib.GetMaxPossibleVUs(schedReqs))\n\n\t\t\ttotalReqs := cm.GetFullExecutionRequirements(et)\n\t\t\tassert.Equal(t, schedReqs, totalReqs)\n\t\t}},\n\t},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": 20, \"maxVUs\": 50, \"stages\": [{\"duration\": \"5m\", \"target\": 10}]}}`, exp{}},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": -20, \"maxVUs\": 50, \"stages\": [{\"duration\": \"5m\", \"target\": 10}]}}`, exp{validationError: true}},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"startRate\": -1, \"preAllocatedVUs\": 20, \"maxVUs\": 50, \"stages\": [{\"duration\": \"5m\", \"target\": 10}]}}`, exp{validationError: true}},\n\t{\n\t\t`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": 20, \"stages\": [{\"duration\": \"5m\", \"target\": 10}]}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\tassert.Empty(t, cm[\"varrival\"].Validate())\n\t\t\trequire.EqualValues(t, 20, cm[\"varrival\"].(*RampingArrivalRateConfig).MaxVUs.Int64)\n\t\t}},\n\t},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"maxVUs\": 50, \"stages\": [{\"duration\": \"5m\", \"target\": 10}]}}`, exp{validationError: true}},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": 20, \"maxVUs\": 50}}`, exp{validationError: true}},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": 20, \"maxVUs\": 50, \"stages\": []}}`, exp{validationError: true}},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": 20, \"maxVUs\": 50, \"stages\": [{\"duration\": \"5m\", \"target\": 10}], \"timeUnit\": \"-1s\"}}`, exp{validationError: true}},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": 20, \"maxVUs\": 50, \"stages\": [{\"duration\": \"5m\", \"target\": 10}], \"timeUnit\": \"0s\"}}`, exp{validationError: true}},\n\t{`{\"varrival\": {\"executor\": \"ramping-arrival-rate\", \"preAllocatedVUs\": 30, \"maxVUs\": 20, \"stages\": [{\"duration\": \"5m\", \"target\": 10}]}}`, exp{validationError: true}},\n\t// TODO: more tests of mixed executors and execution plans\n\n\t// scenario options\n\t{\n\t\t`{\"ui\": {\"executor\": \"shared-iterations\", \"iterations\": 22, \"vus\": 12, \"maxDuration\": \"100s\", \"options\": {\"browser\": {\"someBrowserOption\": true}}}}`,\n\t\texp{custom: func(t *testing.T, cm lib.ScenarioConfigs) {\n\t\t\trequire.Empty(t, cm[\"ui\"].Validate())\n\t\t\tsiCfg, ok := cm[\"ui\"].(SharedIterationsConfig)\n\t\t\trequire.True(t, ok)\n\t\t\trequire.NotEmpty(t, siCfg.Options.Browser)\n\t\t\tassert.EqualValues(t, true, siCfg.Options.Browser[\"someBrowserOption\"])\n\t\t}},\n\t},\n\t// only the \"browser\" scenario option is supported\n\t{`{\"ui\": {\"executor\": \"shared-iterations\", \"iterations\": 22, \"vus\": 12, \"maxDuration\": \"100s\", \"options\": {\"unsupported\": {}}}}`, exp{parseError: true}},\n}\n\nfunc TestConfigMapParsingAndValidation(t *testing.T) {\n\tt.Parallel()\n\tfor i, tc := range configMapTestCases {\n\t\tt.Run(fmt.Sprintf(\"TestCase#%d\", i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Log(tc.rawJSON)\n\t\t\tvar result lib.ScenarioConfigs\n\t\t\terr := json.Unmarshal([]byte(tc.rawJSON), &result)\n\t\t\tif tc.expected.parseError {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\n\t\t\tparseErrors := result.Validate()\n\t\t\tif tc.expected.validationError {\n\t\t\t\tassert.NotEmpty(t, parseErrors)\n\t\t\t} else {\n\t\t\t\tassert.Empty(t, parseErrors)\n\t\t\t}\n\t\t\tif tc.expected.custom != nil {\n\t\t\t\ttc.expected.custom(t, result)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// Test that the executor configuration is properly written into an archive, and\n// then read back. The reason this test is not in lib/archive_test.go is to avoid\n// an import cycle (lib -> lib/executor -> lib), since we need to import a\n// lib.ExecutorConfig implementation.\nfunc TestArchiveRoundTripExecutorConfig(t *testing.T) {\n\tt.Parallel()\n\n\texecCfg := ConstantVUsConfig{\n\t\tBaseConfig: BaseConfig{\n\t\t\tName:         \"const-vus\",\n\t\t\tType:         \"constant-vus\",\n\t\t\tStartTime:    types.NullDurationFrom(10 * time.Second),\n\t\t\tGracefulStop: types.NullDurationFrom(30 * time.Second),\n\t\t\tEnv: map[string]string{\n\t\t\t\t\"FOO\": \"bar\",\n\t\t\t},\n\t\t\tExec: null.StringFrom(\"default\"),\n\t\t\tTags: map[string]string{\n\t\t\t\t\"tagkey\": \"tagvalue\",\n\t\t\t},\n\t\t\tOptions: &lib.ScenarioOptions{\n\t\t\t\tBrowser: map[string]any{\n\t\t\t\t\t\"someOption\": \"someValue\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tVUs:      null.IntFrom(50),\n\t\tDuration: types.NullDurationFrom(10 * time.Minute),\n\t}\n\tarc1 := &lib.Archive{\n\t\tType:      \"js\",\n\t\tK6Version: build.Version,\n\t\tOptions: lib.Options{\n\t\t\tScenarios: map[string]lib.ExecutorConfig{\n\t\t\t\t\"const-vus\": execCfg,\n\t\t\t},\n\t\t},\n\t\tFilenameURL: &url.URL{Scheme: \"file\", Path: \"/path/to/a.js\"},\n\t\tData:        []byte(`// a contents`),\n\t\tPwdURL:      &url.URL{Scheme: \"file\", Path: \"/path/to\"},\n\t\tFilesystems: map[string]fsext.Fs{\n\t\t\t\"file\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\"/path/to/a.js\": []byte(`// a contents`),\n\t\t\t}),\n\t\t},\n\t}\n\n\tbuf := bytes.NewBuffer(nil)\n\trequire.NoError(t, arc1.Write(buf))\n\n\tarc2, err := lib.ReadArchive(buf)\n\trequire.NoError(t, err)\n\n\tscenario, ok := arc2.Options.Scenarios[\"const-vus\"]\n\trequire.True(t, ok, \"scenario const-vus not found in archive options\")\n\texecCfg2, ok := scenario.(ConstantVUsConfig)\n\trequire.True(t, ok)\n\n\tassert.EqualValues(t, execCfg, execCfg2)\n}\n"
  },
  {
    "path": "lib/executor/externally_controlled.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst externallyControlledType = \"externally-controlled\"\n\nfunc init() {\n\tlib.RegisterExecutorConfigType(\n\t\texternallyControlledType,\n\t\tfunc(name string, rawJSON []byte) (lib.ExecutorConfig, error) {\n\t\t\tconfig := ExternallyControlledConfig{BaseConfig: NewBaseConfig(name, externallyControlledType)}\n\t\t\terr := lib.StrictJSONUnmarshal(rawJSON, &config)\n\t\t\tif err != nil {\n\t\t\t\treturn config, err\n\t\t\t}\n\t\t\tif !config.MaxVUs.Valid {\n\t\t\t\tconfig.MaxVUs = config.VUs\n\t\t\t}\n\t\t\treturn config, nil\n\t\t},\n\t)\n}\n\n// ExternallyControlledConfigParams contains all of the options that actually\n// determine the scheduling of VUs in the externally controlled executor.\ntype ExternallyControlledConfigParams struct {\n\tVUs      null.Int           `json:\"vus\"`\n\tDuration types.NullDuration `json:\"duration\"` // 0 is a valid value, meaning infinite duration\n\tMaxVUs   null.Int           `json:\"maxVUs\"`\n}\n\n// Validate just checks the control options in isolation.\nfunc (mecc ExternallyControlledConfigParams) Validate() (errors []error) {\n\tif mecc.VUs.Int64 < 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of VUs can't be negative\"))\n\t}\n\n\tif mecc.MaxVUs.Int64 < mecc.VUs.Int64 {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the number of active VUs (%d) must be less than or equal to the number of maxVUs (%d)\",\n\t\t\tmecc.VUs.Int64, mecc.MaxVUs.Int64,\n\t\t))\n\t}\n\n\tif !mecc.Duration.Valid {\n\t\terrors = append(errors, fmt.Errorf(\"the duration must be specified, for infinite duration use 0\"))\n\t} else if mecc.Duration.TimeDuration() < 0 {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the duration can't be negative, for infinite duration use 0\",\n\t\t))\n\t}\n\n\treturn errors\n}\n\n// ExternallyControlledConfig stores the number of currently active VUs, the max\n// number of VUs and the executor duration. The duration can be 0, which means\n// \"infinite duration\", i.e. the user has to manually abort the script.\ntype ExternallyControlledConfig struct {\n\tBaseConfig\n\tExternallyControlledConfigParams\n}\n\n// Make sure we implement the lib.ExecutorConfig interface\nvar _ lib.ExecutorConfig = &ExternallyControlledConfig{}\n\n// GetDescription returns a human-readable description of the executor options\nfunc (mec ExternallyControlledConfig) GetDescription(_ *lib.ExecutionTuple) string {\n\tduration := \"infinite\"\n\tif mec.Duration.Duration != 0 {\n\t\tduration = mec.Duration.String()\n\t}\n\treturn fmt.Sprintf(\n\t\t\"Externally controlled execution with %d VUs, %d max VUs, %s duration\",\n\t\tmec.VUs.Int64, mec.MaxVUs.Int64, duration,\n\t)\n}\n\n// Validate makes sure all options are configured and valid\nfunc (mec ExternallyControlledConfig) Validate() []error {\n\terrors := append(mec.BaseConfig.Validate(), mec.ExternallyControlledConfigParams.Validate()...)\n\tif mec.GracefulStop.Valid {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"gracefulStop is not supported by the externally controlled executor\",\n\t\t))\n\t}\n\treturn errors\n}\n\n// GetExecutionRequirements reserves the configured number of max VUs for the\n// whole duration of the executor, so these VUs can be externally initialized in\n// the beginning of the test.\n//\n// Importantly, if 0 (i.e. infinite) duration is configured, this executor\n// doesn't emit the last step to relinquish these VUs.\n//\n// Also, the externally controlled executor doesn't set MaxUnplannedVUs in the\n// returned steps, since their initialization and usage is directly controlled\n// by the user, can be changed during the test runtime, and is effectively\n// bounded only by the resources of the machine k6 is running on.\n//\n// This is not a problem, because the MaxUnplannedVUs are mostly meant to be\n// used for calculating the maximum possible number of initialized VUs at any\n// point during a test run. That's used for sizing purposes and for user qouta\n// checking in the cloud execution, where the externally controlled executor\n// isn't supported.\nfunc (mec ExternallyControlledConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {\n\tstartVUs := lib.ExecutionStep{\n\t\tTimeOffset:      0,\n\t\tPlannedVUs:      uint64(et.ScaleInt64(mec.MaxVUs.Int64)), //nolint:gosec\n\t\tMaxUnplannedVUs: 0,                                       // intentional, see function comment\n\t}\n\n\tmaxDuration := mec.Duration.TimeDuration()\n\tif maxDuration == 0 {\n\t\t// Infinite duration, don't emit 0 VUs at the end since there's no planned end\n\t\treturn []lib.ExecutionStep{startVUs}\n\t}\n\treturn []lib.ExecutionStep{startVUs, {\n\t\tTimeOffset:      maxDuration,\n\t\tPlannedVUs:      0,\n\t\tMaxUnplannedVUs: 0, // intentional, see function comment\n\t}}\n}\n\n// IsDistributable simply returns false because there's no way to reliably\n// distribute the externally controlled executor.\nfunc (ExternallyControlledConfig) IsDistributable() bool {\n\treturn false\n}\n\n// NewExecutor creates a new ExternallyControlled executor\nfunc (mec ExternallyControlledConfig) NewExecutor(es *lib.ExecutionState, logger *logrus.Entry) (lib.Executor, error) {\n\treturn &ExternallyControlled{\n\t\tBaseExecutor:         NewBaseExecutor(mec, es, logger),\n\t\tconfig:               mec,\n\t\tcurrentControlConfig: mec.ExternallyControlledConfigParams,\n\t\tconfigLock:           &sync.RWMutex{},\n\t\tnewControlConfigs:    make(chan updateConfigEvent),\n\t\tpauseEvents:          make(chan pauseEvent),\n\t\thasStarted:           make(chan struct{}),\n\t}, nil\n}\n\n// HasWork reports whether there is any work to be done for the given execution segment.\nfunc (mec ExternallyControlledConfig) HasWork(_ *lib.ExecutionTuple) bool {\n\t// We can always initialize new VUs via the REST API, so return true.\n\treturn true\n}\n\ntype pauseEvent struct {\n\tisPaused bool\n\terr      chan error\n}\n\ntype updateConfigEvent struct {\n\tnewConfig ExternallyControlledConfigParams\n\terr       chan error\n}\n\n// ExternallyControlled is an implementation of the old k6 executor that could be\n// controlled externally, via the k6 REST API. It implements both the\n// lib.PausableExecutor and the lib.LiveUpdatableExecutor interfaces.\ntype ExternallyControlled struct {\n\t*BaseExecutor\n\tconfig               ExternallyControlledConfig\n\tcurrentControlConfig ExternallyControlledConfigParams\n\tconfigLock           *sync.RWMutex\n\tnewControlConfigs    chan updateConfigEvent\n\tpauseEvents          chan pauseEvent\n\thasStarted           chan struct{}\n}\n\n// Make sure we implement all the interfaces\nvar (\n\t_ lib.Executor              = &ExternallyControlled{}\n\t_ lib.PausableExecutor      = &ExternallyControlled{}\n\t_ lib.LiveUpdatableExecutor = &ExternallyControlled{}\n)\n\n// GetCurrentConfig just returns the executor's current configuration.\nfunc (mex *ExternallyControlled) GetCurrentConfig() ExternallyControlledConfig {\n\tmex.configLock.RLock()\n\tdefer mex.configLock.RUnlock()\n\treturn ExternallyControlledConfig{\n\t\tBaseConfig:                       mex.config.BaseConfig,\n\t\tExternallyControlledConfigParams: mex.currentControlConfig,\n\t}\n}\n\n// GetConfig just returns the executor's current configuration, it's basically\n// an alias of GetCurrentConfig that implements the more generic interface.\nfunc (mex *ExternallyControlled) GetConfig() lib.ExecutorConfig {\n\treturn mex.GetCurrentConfig()\n}\n\n// GetProgress just returns the executor's progress bar instance.\nfunc (mex ExternallyControlled) GetProgress() *pb.ProgressBar {\n\tmex.configLock.RLock()\n\tdefer mex.configLock.RUnlock()\n\treturn mex.progress\n}\n\n// GetLogger just returns the executor's logger instance.\nfunc (mex ExternallyControlled) GetLogger() *logrus.Entry {\n\tmex.configLock.RLock()\n\tdefer mex.configLock.RUnlock()\n\treturn mex.logger\n}\n\n// Init doesn't do anything...\nfunc (mex ExternallyControlled) Init(_ context.Context) error {\n\treturn nil\n}\n\n// SetPaused pauses or resumes the executor.\nfunc (mex *ExternallyControlled) SetPaused(paused bool) error {\n\tselect {\n\tcase <-mex.hasStarted:\n\t\tevent := pauseEvent{isPaused: paused, err: make(chan error)}\n\t\tmex.pauseEvents <- event\n\t\treturn <-event.err\n\tdefault:\n\t\treturn fmt.Errorf(\"cannot pause the externally controlled executor before it has started\")\n\t}\n}\n\n// UpdateConfig validates the supplied config and updates it in real time. It is\n// possible to update the configuration even when k6 is paused, either in the\n// beginning (i.e. when running k6 with --paused) or in the middle of the script\n// execution.\nfunc (mex *ExternallyControlled) UpdateConfig(ctx context.Context, newConf any) error {\n\tnewConfigParams, ok := newConf.(ExternallyControlledConfigParams)\n\tif !ok {\n\t\treturn errors.New(\"invalid config type\")\n\t}\n\tif errs := newConfigParams.Validate(); len(errs) != 0 {\n\t\treturn fmt.Errorf(\"invalid configuration supplied: %s\", lib.ConcatErrors(errs, \", \"))\n\t}\n\n\tif newConfigParams.Duration.Valid && newConfigParams.Duration != mex.config.Duration {\n\t\treturn fmt.Errorf(\"the externally controlled executor duration cannot be changed\")\n\t}\n\tif newConfigParams.MaxVUs.Valid && newConfigParams.MaxVUs.Int64 < mex.config.MaxVUs.Int64 {\n\t\t// This limitation is because the externally controlled executor is\n\t\t// still an executor that participates in the overall k6 scheduling.\n\t\t// Thus, any VUs that were explicitly specified by the user in the\n\t\t// config may be reused from or by other executors.\n\t\treturn fmt.Errorf(\n\t\t\t\"the new number of max VUs cannot be lower than the starting number of max VUs (%d)\",\n\t\t\tmex.config.MaxVUs.Int64,\n\t\t)\n\t}\n\n\tmex.configLock.Lock() // guard against a simultaneous start of the test (which will close hasStarted)\n\tselect {\n\tcase <-mex.hasStarted:\n\t\tmex.configLock.Unlock()\n\t\tevent := updateConfigEvent{newConfig: newConfigParams, err: make(chan error)}\n\t\tmex.newControlConfigs <- event\n\t\treturn <-event.err\n\tcase <-ctx.Done():\n\t\tmex.configLock.Unlock()\n\t\treturn ctx.Err()\n\tdefault:\n\t\tmex.currentControlConfig = newConfigParams\n\t\tmex.configLock.Unlock()\n\t\treturn nil\n\t}\n}\n\n// This is a helper function that is used in run for non-infinite durations.\nfunc (mex *ExternallyControlled) stopWhenDurationIsReached(ctx context.Context, duration time.Duration, cancel func()) {\n\tctxDone := ctx.Done()\n\tcheckInterval := time.NewTicker(100 * time.Millisecond)\n\tfor {\n\t\tselect {\n\t\tcase <-ctxDone:\n\t\t\tcheckInterval.Stop()\n\t\t\treturn\n\n\t\t// TODO: something saner and more optimized that sleeps for pauses and\n\t\t// doesn't depend on the global execution state?\n\t\tcase <-checkInterval.C:\n\t\t\telapsed := mex.executionState.GetCurrentTestRunDuration() - mex.config.StartTime.TimeDuration()\n\t\t\tif elapsed >= duration {\n\t\t\t\tcancel()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// manualVUHandle is a wrapper around the vuHandle helper, used in the\n// ramping-vus executor. Here, instead of using its getVU and returnVU\n// methods to retrieve and return a VU from the global buffer, we use them to\n// accurately update the local and global active VU counters and to ensure that\n// the pausing and reducing VUs operations wait for VUs to fully finish\n// executing their current iterations before returning.\ntype manualVUHandle struct {\n\t*vuHandle\n\tinitVU lib.InitializedVU\n\twg     *sync.WaitGroup\n\n\t// This is the cancel of the local context, used to kill its goroutine when\n\t// we reduce the number of MaxVUs, so that the Go GC can clean up the VU.\n\tcancelVU func()\n}\n\nfunc (rs *externallyControlledRunState) newManualVUHandle(\n\tinitVU lib.InitializedVU, logger *logrus.Entry,\n) *manualVUHandle {\n\twg := sync.WaitGroup{}\n\tstate := rs.executor.executionState\n\tgetVU := func() (lib.InitializedVU, error) {\n\t\twg.Add(1)\n\t\tstate.ModCurrentlyActiveVUsCount(+1)\n\t\tatomic.AddInt64(rs.activeVUsCount, +1)\n\t\treturn initVU, nil\n\t}\n\treturnVU := func(_ lib.InitializedVU) {\n\t\tstate.ModCurrentlyActiveVUsCount(-1)\n\t\tatomic.AddInt64(rs.activeVUsCount, -1)\n\t\twg.Done()\n\t}\n\tctx, cancel := context.WithCancel(rs.ctx)\n\treturn &manualVUHandle{\n\t\tvuHandle: newStoppedVUHandle(ctx, getVU, returnVU,\n\t\t\trs.executor.nextIterationCounters,\n\t\t\t&rs.executor.config.BaseConfig, logger),\n\t\tinitVU:   initVU,\n\t\twg:       &wg,\n\t\tcancelVU: cancel,\n\t}\n}\n\n// externallyControlledRunState is created and initialized by the Run() method\n// of the externally controlled executor. It is used to track and modify various\n// details of the execution, including handling of live config changes.\ntype externallyControlledRunState struct {\n\tctx             context.Context\n\texecutor        *ExternallyControlled\n\tstartMaxVUs     int64             // the scaled number of initially configured MaxVUs\n\tduration        time.Duration     // the total duration of the executor, could be 0 for infinite\n\tactiveVUsCount  *int64            // the current number of active VUs, used only for the progress display\n\tmaxVUs          *int64            // the current number of initialized VUs\n\tvuHandles       []*manualVUHandle // handles for manipulating and tracking all of the VUs\n\tcurrentlyPaused bool              // whether the executor is currently paused\n\n\trunIteration func(context.Context, lib.ActiveVU) bool // a helper closure function that runs a single iteration\n}\n\n// retrieveStartMaxVUs gets and initializes the (scaled) number of MaxVUs\n// from the global VU buffer. These are the VUs that the user originally\n// specified in the JS config, and that the ExecutionScheduler pre-initialized\n// for us.\nfunc (rs *externallyControlledRunState) retrieveStartMaxVUs() error {\n\tfor i := int64(0); i < rs.startMaxVUs; i++ { // get the initial planned VUs from the common buffer\n\t\tinitVU, vuGetErr := rs.executor.executionState.GetPlannedVU(rs.executor.logger, false)\n\t\tif vuGetErr != nil {\n\t\t\treturn vuGetErr\n\t\t}\n\t\tvuHandle := rs.newManualVUHandle(initVU, rs.executor.logger.WithField(\"vuNum\", i))\n\t\tgo vuHandle.runLoopsIfPossible(rs.runIteration)\n\t\trs.vuHandles[i] = vuHandle\n\t}\n\treturn nil\n}\n\nfunc (rs *externallyControlledRunState) progressFn() (float64, []string) {\n\t// TODO: simulate spinner for the other case or cycle 0-100?\n\tcurrentActiveVUs := atomic.LoadInt64(rs.activeVUsCount)\n\tcurrentMaxVUs := atomic.LoadInt64(rs.maxVUs)\n\tvusFmt := pb.GetFixedLengthIntFormat(currentMaxVUs)\n\tprogVUs := fmt.Sprintf(vusFmt+\"/\"+vusFmt+\" VUs\", currentActiveVUs, currentMaxVUs)\n\n\tright := []string{progVUs, rs.duration.String(), \"\"}\n\n\t// TODO: use a saner way to calculate the elapsed time, without relying on\n\t// the global execution state...\n\telapsed := rs.executor.executionState.GetCurrentTestRunDuration() - rs.executor.config.StartTime.TimeDuration()\n\tif elapsed > rs.duration {\n\t\treturn 1, right\n\t}\n\n\tprogress := 0.0\n\tif rs.duration > 0 {\n\t\tprogress = math.Min(1, float64(elapsed)/float64(rs.duration))\n\t}\n\n\tspentDuration := pb.GetFixedLengthDuration(elapsed, rs.duration)\n\tprogDur := fmt.Sprintf(\"%s/%s\", spentDuration, rs.duration)\n\tright[1] = progDur\n\n\treturn progress, right\n}\n\nfunc (rs *externallyControlledRunState) handleConfigChange(oldCfg, newCfg ExternallyControlledConfigParams) error {\n\texecutionState := rs.executor.executionState\n\tet := executionState.ExecutionTuple\n\toldActiveVUs := et.ScaleInt64(oldCfg.VUs.Int64)\n\toldMaxVUs := et.ScaleInt64(oldCfg.MaxVUs.Int64)\n\tnewActiveVUs := et.ScaleInt64(newCfg.VUs.Int64)\n\tnewMaxVUs := et.ScaleInt64(newCfg.MaxVUs.Int64)\n\n\trs.executor.logger.WithFields(logrus.Fields{\n\t\t\"oldActiveVUs\": oldActiveVUs, \"oldMaxVUs\": oldMaxVUs,\n\t\t\"newActiveVUs\": newActiveVUs, \"newMaxVUs\": newMaxVUs,\n\t}).Debug(\"Updating execution configuration...\")\n\n\tfor i := oldMaxVUs; i < newMaxVUs; i++ {\n\t\tselect { // check if the user didn't try to abort k6 while we're scaling up the VUs\n\t\tcase <-rs.ctx.Done():\n\t\t\treturn rs.ctx.Err()\n\t\tdefault: // do nothing\n\t\t}\n\t\tinitVU, vuInitErr := executionState.InitializeNewVU(rs.ctx, rs.executor.logger)\n\t\tif vuInitErr != nil {\n\t\t\treturn vuInitErr\n\t\t}\n\t\tvuHandle := rs.newManualVUHandle(initVU, rs.executor.logger.WithField(\"vuNum\", i))\n\t\tgo vuHandle.runLoopsIfPossible(rs.runIteration)\n\t\trs.vuHandles = append(rs.vuHandles, vuHandle)\n\t}\n\n\tif oldActiveVUs < newActiveVUs {\n\t\tfor i := oldActiveVUs; i < newActiveVUs; i++ {\n\t\t\tif !rs.currentlyPaused {\n\t\t\t\tif err := rs.vuHandles[i].start(); err != nil {\n\t\t\t\t\t// TODO: maybe just log it ?\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor i := newActiveVUs; i < oldActiveVUs; i++ {\n\t\t\trs.vuHandles[i].hardStop()\n\t\t}\n\t\tfor i := newActiveVUs; i < oldActiveVUs; i++ {\n\t\t\trs.vuHandles[i].wg.Wait()\n\t\t}\n\t}\n\n\tif oldMaxVUs > newMaxVUs {\n\t\tfor i := newMaxVUs; i < oldMaxVUs; i++ {\n\t\t\trs.vuHandles[i].cancelVU()\n\t\t\tif i < rs.startMaxVUs {\n\t\t\t\t// return the initial planned VUs to the common buffer\n\t\t\t\texecutionState.ReturnVU(rs.vuHandles[i].initVU, false)\n\t\t\t} else {\n\t\t\t\texecutionState.ModInitializedVUsCount(-1)\n\t\t\t}\n\t\t\trs.vuHandles[i] = nil\n\t\t}\n\t\trs.vuHandles = rs.vuHandles[:newMaxVUs]\n\t}\n\n\tatomic.StoreInt64(rs.maxVUs, newMaxVUs)\n\treturn nil\n}\n\n// Run constantly loops through as many iterations as possible on a variable\n// dynamically controlled number of VUs either for the specified duration, or\n// until the test is manually stopped.\n//\n//nolint:funlen,gocognit\nfunc (mex *ExternallyControlled) Run(parentCtx context.Context, _ chan<- metrics.SampleContainer) (err error) {\n\tmex.configLock.RLock()\n\t// Safely get the current config - it's important that the close of the\n\t// hasStarted channel is inside of the lock, so that there are no data races\n\t// between it and the UpdateConfig() method.\n\tcurrentControlConfig := mex.currentControlConfig\n\tclose(mex.hasStarted)\n\tmex.configLock.RUnlock()\n\n\tctx, cancel := context.WithCancel(parentCtx)\n\twaitOnProgressChannel := make(chan struct{})\n\tdefer func() {\n\t\tcancel()\n\t\t<-waitOnProgressChannel\n\t}()\n\n\tduration := currentControlConfig.Duration.TimeDuration()\n\tif duration > 0 { // Only keep track of duration if it's not infinite\n\t\tgo mex.stopWhenDurationIsReached(ctx, duration, cancel)\n\t}\n\n\tmex.logger.WithFields(\n\t\tlogrus.Fields{\"type\": externallyControlledType, \"duration\": duration},\n\t).Debug(\"Starting executor run...\")\n\n\tstartMaxVUs := mex.executionState.ExecutionTuple.ScaleInt64(mex.config.MaxVUs.Int64)\n\n\tss := &lib.ScenarioState{\n\t\tName:      mex.config.Name,\n\t\tExecutor:  mex.config.Type,\n\t\tStartTime: time.Now(),\n\t}\n\tctx = lib.WithScenarioState(ctx, ss)\n\n\trunState := &externallyControlledRunState{\n\t\tctx:             ctx,\n\t\texecutor:        mex,\n\t\tstartMaxVUs:     startMaxVUs,\n\t\tduration:        duration,\n\t\tvuHandles:       make([]*manualVUHandle, startMaxVUs),\n\t\tcurrentlyPaused: false,\n\t\tactiveVUsCount:  new(int64),\n\t\tmaxVUs:          new(int64),\n\t\trunIteration:    getIterationRunner(mex.executionState, mex.logger),\n\t}\n\tss.ProgressFn = runState.progressFn\n\n\t*runState.maxVUs = startMaxVUs\n\tif err = runState.retrieveStartMaxVUs(); err != nil { //nolint:contextcheck\n\t\treturn err\n\t}\n\n\tmex.progress.Modify(pb.WithProgress(runState.progressFn)) // Keep track of the progress\n\tgo func() {\n\t\ttrackProgress(parentCtx, ctx, ctx, mex, runState.progressFn)\n\t\tclose(waitOnProgressChannel)\n\t}()\n\t//nolint:contextcheck\n\terr = runState.handleConfigChange( // Start by setting MaxVUs to the starting MaxVUs\n\t\tExternallyControlledConfigParams{MaxVUs: mex.config.MaxVUs}, currentControlConfig,\n\t)\n\tif err != nil {\n\t\treturn err\n\t}\n\t//nolint:contextcheck\n\tdefer func() { // Make sure we release the VUs at the end\n\t\terr = runState.handleConfigChange(currentControlConfig, ExternallyControlledConfigParams{})\n\t}()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil\n\t\tcase updateConfigEvent := <-mex.newControlConfigs:\n\t\t\terr := runState.handleConfigChange(currentControlConfig, updateConfigEvent.newConfig) //nolint:contextcheck\n\t\t\tif err != nil {\n\t\t\t\tupdateConfigEvent.err <- err\n\t\t\t\tif errors.Is(ctx.Err(), err) {\n\t\t\t\t\treturn nil // we've already returned an error to the API client, but k6 should stop normally\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tcurrentControlConfig = updateConfigEvent.newConfig\n\t\t\tmex.configLock.Lock()\n\t\t\tmex.currentControlConfig = updateConfigEvent.newConfig\n\t\t\tmex.configLock.Unlock()\n\t\t\tupdateConfigEvent.err <- nil\n\n\t\tcase pauseEvent := <-mex.pauseEvents:\n\t\t\tif pauseEvent.isPaused == runState.currentlyPaused {\n\t\t\t\tpauseEvent.err <- nil\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tactiveVUs := currentControlConfig.VUs.Int64\n\t\t\tif pauseEvent.isPaused {\n\t\t\t\tfor i := range activeVUs {\n\t\t\t\t\trunState.vuHandles[i].gracefulStop()\n\t\t\t\t}\n\t\t\t\tfor i := range activeVUs {\n\t\t\t\t\trunState.vuHandles[i].wg.Wait()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor i := range activeVUs {\n\t\t\t\t\tif err := runState.vuHandles[i].start(); err != nil {\n\t\t\t\t\t\t// TODO again ... just log it?\n\t\t\t\t\t\tpauseEvent.err <- err\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\trunState.currentlyPaused = pauseEvent.isPaused\n\t\t\tpauseEvent.err <- nil\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/executor/externally_controlled_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc getTestExternallyControlledConfig() ExternallyControlledConfig {\n\treturn ExternallyControlledConfig{\n\t\tExternallyControlledConfigParams: ExternallyControlledConfigParams{\n\t\t\tVUs:      null.IntFrom(2),\n\t\t\tMaxVUs:   null.IntFrom(10),\n\t\t\tDuration: types.NullDurationFrom(2 * time.Second),\n\t\t},\n\t}\n}\n\nfunc TestExternallyControlledRun(t *testing.T) {\n\tt.Parallel()\n\n\tdoneIters := new(uint64)\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\tatomic.AddUint64(doneIters, 1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestExternallyControlledConfig())\n\tdefer test.cancel()\n\n\tvar (\n\t\twg     sync.WaitGroup\n\t\terrCh  = make(chan error, 1)\n\t\tdoneCh = make(chan struct{})\n\t)\n\twg.Go(func() {\n\t\ttest.state.MarkStarted()\n\t\terrCh <- test.executor.Run(test.ctx, nil)\n\t\ttest.state.MarkEnded()\n\t\tclose(doneCh)\n\t})\n\n\tupdateConfig := func(vus, maxVUs int64, errMsg string) {\n\t\tnewConfig := ExternallyControlledConfigParams{\n\t\t\tVUs:      null.IntFrom(vus),\n\t\t\tMaxVUs:   null.IntFrom(maxVUs),\n\t\t\tDuration: types.NullDurationFrom(2 * time.Second),\n\t\t}\n\t\terr := test.executor.(*ExternallyControlled).UpdateConfig(test.ctx, newConfig)\n\t\tif errMsg != \"\" {\n\t\t\tassert.EqualError(t, err, errMsg)\n\t\t} else {\n\t\t\tassert.NoError(t, err)\n\t\t}\n\t}\n\n\tvar resultVUCount [][]int64\n\tsnapshot := func() {\n\t\tresultVUCount = append(resultVUCount,\n\t\t\t[]int64{test.state.GetCurrentlyActiveVUsCount(), test.state.GetInitializedVUsCount()})\n\t}\n\n\twg.Go(func() {\n\t\tsnapshotTicker := time.NewTicker(500 * time.Millisecond)\n\t\tticks := 0\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-snapshotTicker.C:\n\t\t\t\tsnapshot()\n\t\t\t\tswitch ticks {\n\t\t\t\tcase 0, 2:\n\t\t\t\t\tupdateConfig(4, 10, \"\")\n\t\t\t\tcase 1:\n\t\t\t\t\tupdateConfig(8, 20, \"\")\n\t\t\t\tcase 3:\n\t\t\t\t\tupdateConfig(15, 10,\n\t\t\t\t\t\t\"invalid configuration supplied: the number of active VUs (15)\"+\n\t\t\t\t\t\t\t\" must be less than or equal to the number of maxVUs (10)\")\n\t\t\t\t\tupdateConfig(-1, 10,\n\t\t\t\t\t\t\"invalid configuration supplied: the number of VUs can't be negative\")\n\t\t\t\t}\n\t\t\t\tticks++\n\t\t\tcase <-doneCh:\n\t\t\t\tsnapshotTicker.Stop()\n\t\t\t\tsnapshot()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n\n\twg.Wait()\n\trequire.NoError(t, <-errCh)\n\tassert.InDelta(t, 48, atomic.LoadUint64(doneIters), 2)\n\tassert.Equal(t, [][]int64{{2, 10}, {4, 10}, {8, 20}, {4, 10}, {0, 10}}, resultVUCount)\n}\n"
  },
  {
    "path": "lib/executor/helpers.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/internal/execution\"\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc sumStagesDuration(stages []Stage) (result time.Duration) {\n\tfor _, s := range stages {\n\t\tresult += s.Duration.TimeDuration()\n\t}\n\treturn result\n}\n\nfunc getStagesUnscaledMaxTarget(unscaledStartValue int64, stages []Stage) int64 {\n\tresult := unscaledStartValue\n\tfor _, s := range stages {\n\t\tif s.Target.Int64 > result {\n\t\t\tresult = s.Target.Int64\n\t\t}\n\t}\n\treturn result\n}\n\n// A helper function to avoid code duplication\nfunc validateStages(stages []Stage) []error {\n\tvar errors []error\n\tif len(stages) == 0 {\n\t\terrors = append(errors, fmt.Errorf(\"at least one stage has to be specified\"))\n\t\treturn errors\n\t}\n\n\tfor i, s := range stages {\n\t\tstageNum := i + 1\n\t\tif !s.Duration.Valid {\n\t\t\terrors = append(errors, fmt.Errorf(\"stage %d doesn't have a duration\", stageNum))\n\t\t} else if s.Duration.Duration < 0 {\n\t\t\terrors = append(errors, fmt.Errorf(\"the duration for stage %d can't be negative\", stageNum))\n\t\t}\n\t\tif !s.Target.Valid {\n\t\t\terrors = append(errors, fmt.Errorf(\"stage %d doesn't have a target\", stageNum))\n\t\t} else if s.Target.Int64 < 0 {\n\t\t\terrors = append(errors, fmt.Errorf(\"the target for stage %d can't be negative\", stageNum))\n\t\t}\n\t}\n\treturn errors\n}\n\n// handleInterrupt returns true if err is InterruptError and if so it\n// cancels the executor context passed with ctx.\nfunc handleInterrupt(ctx context.Context, err error) bool {\n\tif err != nil {\n\t\tif errext.IsInterruptError(err) {\n\t\t\texecution.AbortTestRun(ctx, err)\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// getIterationRunner is a helper function that returns an iteration executor\n// closure. It takes care of updating the execution state statistics and\n// warning messages. And returns whether a full iteration was finished or not\n//\n// TODO: emit the end-of-test iteration metrics here (https://github.com/k6io/k6/issues/1250)\nfunc getIterationRunner(\n\texecutionState *lib.ExecutionState, logger *logrus.Entry,\n) func(context.Context, lib.ActiveVU) bool {\n\treturn func(ctx context.Context, vu lib.ActiveVU) bool {\n\t\terr := vu.RunOnce()\n\n\t\t// TODO: track (non-ramp-down) errors from script iterations as a metric,\n\t\t// and have a default threshold that will abort the script when the error\n\t\t// rate exceeds a certain percentage\n\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\t// Don't log errors or emit iterations metrics from cancelled iterations\n\t\t\texecutionState.AddInterruptedIterations(1)\n\t\t\treturn false\n\t\tdefault:\n\t\t\tif err != nil {\n\t\t\t\tif handleInterrupt(ctx, err) {\n\t\t\t\t\texecutionState.AddInterruptedIterations(1)\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\tvar exception errext.Exception\n\t\t\t\tif errors.As(err, &exception) {\n\t\t\t\t\t// TODO don't count this as a full iteration?\n\t\t\t\t\tlogger.WithField(\"source\", \"stacktrace\").Error(exception.StackTrace())\n\t\t\t\t} else {\n\t\t\t\t\tlogger.Error(err.Error())\n\t\t\t\t}\n\t\t\t\t// TODO: investigate context cancelled errors\n\t\t\t}\n\n\t\t\t// TODO: move emission of end-of-iteration metrics here?\n\t\t\texecutionState.AddFullIterations(1)\n\t\t\treturn true\n\t\t}\n\t}\n}\n\n// getDurationContexts is used to create sub-contexts that can restrict an\n// executor to only run for its allotted time.\n//\n// If the executor doesn't have a graceful stop period for iterations, then\n// both returned sub-contexts will be the same one, with a timeout equal to\n// the supplied regular executor duration.\n//\n// But if a graceful stop is enabled, then the first returned context (and the\n// cancel func) will be for the \"outer\" sub-context. Its timeout will include\n// both the regular duration and the specified graceful stop period. The second\n// context will be a sub-context of the first one and its timeout will include\n// only the regular duration.\n//\n// In either case, the usage of these contexts should be like this:\n//   - As long as the regDurationCtx isn't done, new iterations can be started.\n//   - After regDurationCtx is done, no new iterations should be started; every\n//     VU that finishes an iteration from now on can be returned to the buffer\n//     pool in the ExecutionState struct.\n//   - After maxDurationCtx is done, any VUs with iterations will be\n//     interrupted by the context's closing and will be returned to the buffer.\n//   - If you want to interrupt the execution of all VUs prematurely (e.g. there\n//     was an error or something like that), trigger maxDurationCancel().\n//   - If the whole test is aborted, the parent context will be cancelled, so\n//     that will also cancel these contexts, thus the \"general abort\" case is\n//     handled transparently.\nfunc getDurationContexts(parentCtx context.Context, regularDuration, gracefulStop time.Duration) (\n\tstartTime time.Time, maxDurationCtx, regDurationCtx context.Context, maxDurationCancel func(),\n) {\n\tstartTime = time.Now()\n\tmaxEndTime := startTime.Add(regularDuration + gracefulStop)\n\n\tmaxDurationCtx, maxDurationCancel = context.WithDeadline(parentCtx, maxEndTime)\n\tif gracefulStop == 0 {\n\t\treturn startTime, maxDurationCtx, maxDurationCtx, maxDurationCancel\n\t}\n\tregDurationCtx, _ = context.WithDeadline(maxDurationCtx, startTime.Add(regularDuration)) //nolint:govet\n\treturn startTime, maxDurationCtx, regDurationCtx, maxDurationCancel\n}\n\n// trackProgress is a helper function that monitors certain end-events in an\n// executor and updates its progressbar accordingly.\nfunc trackProgress(\n\tparentCtx, maxDurationCtx, regDurationCtx context.Context,\n\texec lib.Executor, snapshot func() (float64, []string),\n) {\n\tprogressBar := exec.GetProgress()\n\tlogger := exec.GetLogger()\n\n\t<-regDurationCtx.Done() // Wait for the regular context to be over\n\tgracefulStop := exec.GetConfig().GetGracefulStop()\n\tif parentCtx.Err() == nil && gracefulStop > 0 {\n\t\tp, right := snapshot()\n\t\tlogger.WithField(\"gracefulStop\", gracefulStop).Debug(\n\t\t\t\"Regular duration is done, waiting for iterations to gracefully finish\",\n\t\t)\n\t\tprogressBar.Modify(\n\t\t\tpb.WithStatus(pb.Stopping),\n\t\t\tpb.WithConstProgress(p, right...),\n\t\t)\n\t}\n\n\t<-maxDurationCtx.Done()\n\tp, right := snapshot()\n\tconstProg := pb.WithConstProgress(p, right...)\n\tselect {\n\tcase <-parentCtx.Done():\n\t\tprogressBar.Modify(pb.WithStatus(pb.Interrupted), constProg)\n\tdefault:\n\t\tstatus := pb.WithStatus(pb.Done)\n\t\tif p < 1 {\n\t\t\tstatus = pb.WithStatus(pb.Interrupted)\n\t\t}\n\t\tprogressBar.Modify(status, constProg)\n\t}\n}\n\n// getScaledArrivalRate returns a rational number containing the scaled value of\n// the given rate over the given period. This should generally be the first\n// function that's called, before we do any calculations with the users-supplied\n// rates in the arrival-rate executors.\nfunc getScaledArrivalRate(es *lib.ExecutionSegment, rate int64, period time.Duration) *big.Rat {\n\treturn es.InPlaceScaleRat(big.NewRat(rate, int64(period)))\n}\n\n// getTickerPeriod is just a helper function that returns the ticker interval\n// we need for given arrival-rate parameters.\n//\n// It's possible for this function to return a zero duration (i.e. valid=false)\n// and 0 isn't a valid ticker period. This happens so we don't divide by 0 when\n// the arrival-rate period is 0. This case has to be handled separately.\nfunc getTickerPeriod(scaledArrivalRate *big.Rat) types.NullDuration {\n\tif scaledArrivalRate.Sign() == 0 {\n\t\treturn types.NewNullDuration(0, false)\n\t}\n\t// Basically, the ticker rate is time.Duration(1/arrivalRate). Considering\n\t// that time.Duration is represented as int64 nanoseconds, no meaningful\n\t// precision is likely to be lost here...\n\tresult, _ := new(big.Rat).Inv(scaledArrivalRate).Float64()\n\treturn types.NewNullDuration(time.Duration(result), true)\n}\n\n// getArrivalRatePerSec returns the iterations per second rate.\nfunc getArrivalRatePerSec(scaledArrivalRate *big.Rat) *big.Rat {\n\tperSecRate := big.NewRat(int64(time.Second), 1)\n\treturn perSecRate.Mul(perSecRate, scaledArrivalRate)\n}\n\n// TODO: Refactor this, maybe move all scenario things to an embedded struct?\nfunc getVUActivationParams(\n\tctx context.Context, conf BaseConfig, deactivateCallback func(lib.InitializedVU),\n\tnextIterationCounters func() (uint64, uint64),\n) *lib.VUActivationParams {\n\treturn &lib.VUActivationParams{\n\t\tRunContext:               ctx,\n\t\tScenario:                 conf.Name,\n\t\tExec:                     conf.GetExec(),\n\t\tEnv:                      conf.GetEnv(),\n\t\tTags:                     conf.GetTags(),\n\t\tDeactivateCallback:       deactivateCallback,\n\t\tGetNextIterationCounters: nextIterationCounters,\n\t}\n}\n"
  },
  {
    "path": "lib/executor/helpers_test.go",
    "content": "package executor\n\nimport \"go.k6.io/k6/metrics\"\n\nfunc sumMetricValues(samples chan metrics.SampleContainer, metricName string) (sum float64) { //nolint:unparam\n\tfor _, sc := range metrics.GetBufferedSamples(samples) {\n\t\tsamples := sc.GetSamples()\n\t\tfor _, s := range samples {\n\t\t\tif s.Metric.Name == metricName {\n\t\t\t\tsum += s.Value\n\t\t\t}\n\t\t}\n\t}\n\treturn sum\n}\n"
  },
  {
    "path": "lib/executor/per_vu_iterations.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst perVUIterationsType = \"per-vu-iterations\"\n\nfunc init() {\n\tlib.RegisterExecutorConfigType(perVUIterationsType, func(name string, rawJSON []byte) (lib.ExecutorConfig, error) {\n\t\tconfig := NewPerVUIterationsConfig(name)\n\t\terr := lib.StrictJSONUnmarshal(rawJSON, &config)\n\t\treturn config, err\n\t})\n}\n\n// PerVUIterationsConfig stores the number of VUs iterations, as well as maxDuration settings\ntype PerVUIterationsConfig struct {\n\tBaseConfig\n\tVUs         null.Int           `json:\"vus\"`\n\tIterations  null.Int           `json:\"iterations\"`\n\tMaxDuration types.NullDuration `json:\"maxDuration\"`\n}\n\n// NewPerVUIterationsConfig returns a PerVUIterationsConfig with default values\nfunc NewPerVUIterationsConfig(name string) PerVUIterationsConfig {\n\treturn PerVUIterationsConfig{\n\t\tBaseConfig:  NewBaseConfig(name, perVUIterationsType),\n\t\tVUs:         null.NewInt(1, false),\n\t\tIterations:  null.NewInt(1, false),\n\t\tMaxDuration: types.NewNullDuration(10*time.Minute, false), // TODO: shorten?\n\t}\n}\n\n// Make sure we implement the lib.ExecutorConfig interface\nvar _ lib.ExecutorConfig = &PerVUIterationsConfig{}\n\n// GetVUs returns the scaled VUs for the executor.\nfunc (pvic PerVUIterationsConfig) GetVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(pvic.VUs.Int64)\n}\n\n// GetIterations returns the UNSCALED iteration count for the executor. It's\n// important to note that scaling per-VU iteration executor affects only the\n// number of VUs. If we also scaled the iterations, scaling would have quadratic\n// effects instead of just linear.\nfunc (pvic PerVUIterationsConfig) GetIterations() int64 {\n\treturn pvic.Iterations.Int64\n}\n\n// GetDescription returns a human-readable description of the executor options\nfunc (pvic PerVUIterationsConfig) GetDescription(et *lib.ExecutionTuple) string {\n\treturn fmt.Sprintf(\"%d iterations for each of %d VUs%s\",\n\t\tpvic.GetIterations(), pvic.GetVUs(et),\n\t\tpvic.getBaseInfo(fmt.Sprintf(\"maxDuration: %s\", pvic.MaxDuration.Duration)))\n}\n\n// Validate makes sure all options are configured and valid\nfunc (pvic PerVUIterationsConfig) Validate() []error {\n\terrors := pvic.BaseConfig.Validate()\n\tif pvic.VUs.Int64 <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of VUs must be more than 0\"))\n\t}\n\n\tif pvic.Iterations.Int64 <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of iterations must be more than 0\"))\n\t}\n\n\tif pvic.MaxDuration.TimeDuration() < minDuration {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the maxDuration must be at least %s, but is %s\", minDuration, pvic.MaxDuration,\n\t\t))\n\t}\n\n\treturn errors\n}\n\n// GetExecutionRequirements returns the number of required VUs to run the\n// executor for its whole duration (disregarding any startTime), including the\n// maximum waiting time for any iterations to gracefully stop. This is used by\n// the execution scheduler in its VU reservation calculations, so it knows how\n// many VUs to pre-initialize.\nfunc (pvic PerVUIterationsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {\n\treturn []lib.ExecutionStep{\n\t\t{\n\t\t\tTimeOffset: 0,\n\t\t\tPlannedVUs: uint64(pvic.GetVUs(et)), //nolint:gosec\n\t\t},\n\t\t{\n\t\t\tTimeOffset: pvic.MaxDuration.TimeDuration() + pvic.GracefulStop.TimeDuration(),\n\t\t\tPlannedVUs: 0,\n\t\t},\n\t}\n}\n\n// NewExecutor creates a new PerVUIterations executor\nfunc (pvic PerVUIterationsConfig) NewExecutor(\n\tes *lib.ExecutionState, logger *logrus.Entry,\n) (lib.Executor, error) {\n\treturn PerVUIterations{\n\t\tBaseExecutor: NewBaseExecutor(pvic, es, logger),\n\t\tconfig:       pvic,\n\t}, nil\n}\n\n// HasWork reports whether there is any work to be done for the given execution segment.\nfunc (pvic PerVUIterationsConfig) HasWork(et *lib.ExecutionTuple) bool {\n\treturn pvic.GetVUs(et) > 0 && pvic.GetIterations() > 0\n}\n\n// PerVUIterations executes a specific number of iterations with each VU.\ntype PerVUIterations struct {\n\t*BaseExecutor\n\tconfig PerVUIterationsConfig\n}\n\n// Make sure we implement the lib.Executor interface.\nvar _ lib.Executor = &PerVUIterations{}\n\n// Run executes a specific number of iterations with each configured VU.\n//\n//nolint:funlen\nfunc (pvi PerVUIterations) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) {\n\tnumVUs := pvi.config.GetVUs(pvi.executionState.ExecutionTuple)\n\titerations := pvi.config.GetIterations()\n\tduration := pvi.config.MaxDuration.TimeDuration()\n\tgracefulStop := pvi.config.GetGracefulStop()\n\n\twaitOnProgressChannel := make(chan struct{})\n\tstartTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(parentCtx, duration, gracefulStop)\n\tdefer func() {\n\t\tcancel()\n\t\t<-waitOnProgressChannel\n\t}()\n\n\t// Make sure the log and the progress bar have accurate information\n\tpvi.logger.WithFields(logrus.Fields{\n\t\t\"vus\": numVUs, \"iterations\": iterations, \"maxDuration\": duration, \"type\": pvi.config.GetType(),\n\t}).Debug(\"Starting executor run...\")\n\n\ttotalIters := numVUs * iterations\n\tdoneIters := new(uint64)\n\n\tvusFmt := pb.GetFixedLengthIntFormat(numVUs)\n\titersFmt := pb.GetFixedLengthIntFormat(totalIters)\n\tprogressFn := func() (float64, []string) {\n\t\tspent := time.Since(startTime)\n\t\tprogVUs := fmt.Sprintf(vusFmt+\" VUs\", numVUs)\n\t\tcurrentDoneIters := atomic.LoadUint64(doneIters)\n\t\tprogIters := fmt.Sprintf(itersFmt+\"/\"+itersFmt+\" iters, %d per VU\",\n\t\t\tcurrentDoneIters, totalIters, iterations)\n\t\tright := []string{progVUs, duration.String(), progIters}\n\t\tif spent > duration {\n\t\t\treturn 1, right\n\t\t}\n\n\t\tspentDuration := pb.GetFixedLengthDuration(spent, duration)\n\t\tprogDur := fmt.Sprintf(\"%s/%s\", spentDuration, duration)\n\t\tright[1] = progDur\n\n\t\treturn float64(currentDoneIters) / float64(totalIters), right\n\t}\n\tpvi.progress.Modify(pb.WithProgress(progressFn))\n\n\tmaxDurationCtx = lib.WithScenarioState(maxDurationCtx, &lib.ScenarioState{\n\t\tName:       pvi.config.Name,\n\t\tExecutor:   pvi.config.Type,\n\t\tStartTime:  startTime,\n\t\tProgressFn: progressFn,\n\t})\n\tgo func() {\n\t\ttrackProgress(parentCtx, maxDurationCtx, regDurationCtx, pvi, progressFn)\n\t\tclose(waitOnProgressChannel)\n\t}()\n\n\thandleVUsWG := &sync.WaitGroup{}\n\tdefer handleVUsWG.Wait()\n\t// Actually schedule the VUs and iterations...\n\tactiveVUs := &sync.WaitGroup{}\n\tdefer activeVUs.Wait()\n\n\tregDurationDone := regDurationCtx.Done()\n\trunIteration := getIterationRunner(pvi.executionState, pvi.logger)\n\n\treturnVU := func(u lib.InitializedVU) {\n\t\tpvi.executionState.ReturnVU(u, true)\n\t\tactiveVUs.Done()\n\t}\n\n\tdroppedIterationMetric := pvi.executionState.Test.BuiltinMetrics.DroppedIterations\n\thandleVU := func(initVU lib.InitializedVU) {\n\t\tdefer handleVUsWG.Done()\n\t\tctx, cancel := context.WithCancel(maxDurationCtx)\n\t\tdefer cancel()\n\n\t\tvuID := initVU.GetID()\n\t\tactiveVU := initVU.Activate(\n\t\t\tgetVUActivationParams(ctx, pvi.config.BaseConfig, returnVU,\n\t\t\t\tpvi.nextIterationCounters))\n\n\t\tfor i := range iterations {\n\t\t\tselect {\n\t\t\tcase <-regDurationDone:\n\t\t\t\tmetrics.PushIfNotDone(parentCtx, out, metrics.Sample{\n\t\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\t\tMetric: droppedIterationMetric,\n\t\t\t\t\t\tTags:   pvi.getMetricTags(&vuID),\n\t\t\t\t\t},\n\t\t\t\t\tTime:  time.Now(),\n\t\t\t\t\tValue: float64(iterations - i),\n\t\t\t\t})\n\t\t\t\treturn // don't make more iterations\n\t\t\tdefault:\n\t\t\t\t// continue looping\n\t\t\t}\n\t\t\trunIteration(maxDurationCtx, activeVU)\n\t\t\tatomic.AddUint64(doneIters, 1)\n\t\t}\n\t}\n\n\tfor range numVUs {\n\t\tinitializedVU, err := pvi.executionState.GetPlannedVU(pvi.logger, true)\n\t\tif err != nil {\n\t\t\tcancel()\n\t\t\treturn err\n\t\t}\n\t\tactiveVUs.Add(1)\n\t\thandleVUsWG.Add(1)\n\t\tgo handleVU(initializedVU)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "lib/executor/per_vu_iterations_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc getTestPerVUIterationsConfig() PerVUIterationsConfig {\n\treturn PerVUIterationsConfig{\n\t\tBaseConfig:  BaseConfig{GracefulStop: types.NullDurationFrom(1 * time.Second)},\n\t\tVUs:         null.IntFrom(10),\n\t\tIterations:  null.IntFrom(100),\n\t\tMaxDuration: types.NullDurationFrom(3 * time.Second),\n\t}\n}\n\n// Baseline test\nfunc TestPerVUIterationsRun(t *testing.T) {\n\tt.Parallel()\n\tvar result sync.Map\n\n\trunner := simpleRunner(func(_ context.Context, state *lib.State) error {\n\t\tcurrIter, _ := result.LoadOrStore(state.VUID, uint64(0))\n\t\tresult.Store(state.VUID, currIter.(uint64)+1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestPerVUIterationsConfig())\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\n\tvar totalIters uint64\n\tresult.Range(func(_, value any) bool {\n\t\tvuIters := value.(uint64)\n\t\tassert.Equal(t, uint64(100), vuIters)\n\t\ttotalIters += vuIters\n\t\treturn true\n\t})\n\tassert.Equal(t, uint64(1000), totalIters)\n}\n\n// Test that when one VU \"slows down\", others will *not* pick up the workload.\n// This is the reverse behavior of the SharedIterations executor.\nfunc TestPerVUIterationsRunVariableVU(t *testing.T) {\n\tt.Parallel()\n\tvar (\n\t\tresult   sync.Map\n\t\tslowVUID = uint64(1)\n\t)\n\n\trunner := simpleRunner(func(_ context.Context, state *lib.State) error {\n\t\tif state.VUID == slowVUID {\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t}\n\t\tcurrIter, _ := result.LoadOrStore(state.VUID, uint64(0))\n\t\tresult.Store(state.VUID, currIter.(uint64)+1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestPerVUIterationsConfig())\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\n\tval, ok := result.Load(slowVUID)\n\tassert.True(t, ok)\n\n\tvar totalIters uint64\n\tresult.Range(func(key, value any) bool {\n\t\tvuIters := value.(uint64)\n\t\tif key != slowVUID {\n\t\t\tassert.Equal(t, uint64(100), vuIters)\n\t\t}\n\t\ttotalIters += vuIters\n\t\treturn true\n\t})\n\n\t// The slow VU should complete 15 iterations given these timings,\n\t// while the rest should equally complete their assigned 100 iterations.\n\tassert.Equal(t, uint64(15), val)\n\tassert.Equal(t, uint64(915), totalIters)\n}\n\nfunc TestPerVuIterationsEmitDroppedIterations(t *testing.T) {\n\tt.Parallel()\n\tvar count int64\n\n\tconfig := PerVUIterationsConfig{\n\t\tVUs:         null.IntFrom(5),\n\t\tIterations:  null.IntFrom(20),\n\t\tMaxDuration: types.NullDurationFrom(1 * time.Second),\n\t}\n\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\tatomic.AddInt64(&count, 1)\n\t\t<-ctx.Done()\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tassert.Empty(t, test.logHook.Drain())\n\tassert.Equal(t, int64(5), count)\n\tassert.Equal(t, float64(95), sumMetricValues(engineOut, metrics.DroppedIterationsName))\n}\n"
  },
  {
    "path": "lib/executor/ramping_arrival_rate.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst rampingArrivalRateType = \"ramping-arrival-rate\"\n\nfunc init() {\n\tlib.RegisterExecutorConfigType(\n\t\trampingArrivalRateType,\n\t\tfunc(name string, rawJSON []byte) (lib.ExecutorConfig, error) {\n\t\t\tconfig := NewRampingArrivalRateConfig(name)\n\t\t\terr := lib.StrictJSONUnmarshal(rawJSON, &config)\n\t\t\treturn config, err\n\t\t},\n\t)\n}\n\n// RampingArrivalRateConfig stores config for the ramping (i.e. variable)\n// arrival-rate executor.\ntype RampingArrivalRateConfig struct {\n\tBaseConfig\n\tStartRate null.Int           `json:\"startRate\"`\n\tTimeUnit  types.NullDuration `json:\"timeUnit\"`\n\tStages    []Stage            `json:\"stages\"`\n\n\t// Initialize `PreAllocatedVUs` number of VUs, and if more than that are needed,\n\t// they will be dynamically allocated, until `MaxVUs` is reached, which is an\n\t// absolutely hard limit on the number of VUs the executor will use\n\tPreAllocatedVUs null.Int `json:\"preAllocatedVUs\"`\n\tMaxVUs          null.Int `json:\"maxVUs\"`\n}\n\n// NewRampingArrivalRateConfig returns a RampingArrivalRateConfig with default values\nfunc NewRampingArrivalRateConfig(name string) *RampingArrivalRateConfig {\n\treturn &RampingArrivalRateConfig{\n\t\tBaseConfig: NewBaseConfig(name, rampingArrivalRateType),\n\t\tTimeUnit:   types.NewNullDuration(1*time.Second, false),\n\t}\n}\n\n// Make sure we implement the lib.ExecutorConfig interface\nvar _ lib.ExecutorConfig = &RampingArrivalRateConfig{}\n\n// GetPreAllocatedVUs is just a helper method that returns the scaled pre-allocated VUs.\nfunc (varc RampingArrivalRateConfig) GetPreAllocatedVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(varc.PreAllocatedVUs.Int64)\n}\n\n// GetMaxVUs is just a helper method that returns the scaled max VUs.\nfunc (varc RampingArrivalRateConfig) GetMaxVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(varc.MaxVUs.Int64)\n}\n\n// GetDescription returns a human-readable description of the executor options\nfunc (varc RampingArrivalRateConfig) GetDescription(et *lib.ExecutionTuple) string {\n\t// TODO: something better? always show iterations per second?\n\tmaxVUsRange := fmt.Sprintf(\"maxVUs: %d\", et.ScaleInt64(varc.PreAllocatedVUs.Int64))\n\tif varc.MaxVUs.Int64 > varc.PreAllocatedVUs.Int64 {\n\t\tmaxVUsRange += fmt.Sprintf(\"-%d\", et.ScaleInt64(varc.MaxVUs.Int64))\n\t}\n\tmaxUnscaledRate := getStagesUnscaledMaxTarget(varc.StartRate.Int64, varc.Stages)\n\tmaxArrRatePerSec, _ := getArrivalRatePerSec(\n\t\tgetScaledArrivalRate(et.Segment, maxUnscaledRate, varc.TimeUnit.TimeDuration()),\n\t).Float64()\n\n\treturn fmt.Sprintf(\"Up to %.2f iterations/s for %s over %d stages%s\",\n\t\tmaxArrRatePerSec, sumStagesDuration(varc.Stages),\n\t\tlen(varc.Stages), varc.getBaseInfo(maxVUsRange))\n}\n\n// Validate makes sure all options are configured and valid\nfunc (varc *RampingArrivalRateConfig) Validate() []error {\n\terrors := varc.BaseConfig.Validate()\n\n\tif varc.StartRate.Int64 < 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the startRate value can't be negative\"))\n\t}\n\n\tif varc.TimeUnit.TimeDuration() <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the timeUnit must be more than 0\"))\n\t}\n\n\terrors = append(errors, validateStages(varc.Stages)...)\n\n\tif !varc.PreAllocatedVUs.Valid {\n\t\terrors = append(errors, fmt.Errorf(\"the number of preAllocatedVUs isn't specified\"))\n\t} else if varc.PreAllocatedVUs.Int64 < 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of preAllocatedVUs can't be negative\"))\n\t}\n\n\tif !varc.MaxVUs.Valid {\n\t\t// TODO: don't change the config while validating\n\t\tvarc.MaxVUs.Int64 = varc.PreAllocatedVUs.Int64\n\t} else if varc.MaxVUs.Int64 < varc.PreAllocatedVUs.Int64 {\n\t\terrors = append(errors, fmt.Errorf(\"maxVUs can't be less than preAllocatedVUs\"))\n\t}\n\n\treturn errors\n}\n\n// GetExecutionRequirements returns the number of required VUs to run the\n// executor for its whole duration (disregarding any startTime), including the\n// maximum waiting time for any iterations to gracefully stop. This is used by\n// the execution scheduler in its VU reservation calculations, so it knows how\n// many VUs to pre-initialize.\nfunc (varc RampingArrivalRateConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {\n\treturn []lib.ExecutionStep{\n\t\t{\n\t\t\tTimeOffset:      0,\n\t\t\tPlannedVUs:      uint64(et.ScaleInt64(varc.PreAllocatedVUs.Int64)),                                    //nolint:gosec\n\t\t\tMaxUnplannedVUs: uint64(et.ScaleInt64(varc.MaxVUs.Int64) - et.ScaleInt64(varc.PreAllocatedVUs.Int64)), //nolint:gosec\n\t\t},\n\t\t{\n\t\t\tTimeOffset:      sumStagesDuration(varc.Stages) + varc.GracefulStop.TimeDuration(),\n\t\t\tPlannedVUs:      0,\n\t\t\tMaxUnplannedVUs: 0,\n\t\t},\n\t}\n}\n\n// NewExecutor creates a new RampingArrivalRate executor\nfunc (varc RampingArrivalRateConfig) NewExecutor(\n\tes *lib.ExecutionState, logger *logrus.Entry,\n) (lib.Executor, error) {\n\treturn &RampingArrivalRate{\n\t\tBaseExecutor: NewBaseExecutor(&varc, es, logger),\n\t\tconfig:       varc,\n\t}, nil\n}\n\n// HasWork reports whether there is any work to be done for the given execution segment.\nfunc (varc RampingArrivalRateConfig) HasWork(et *lib.ExecutionTuple) bool {\n\treturn varc.GetMaxVUs(et) > 0\n}\n\n// RampingArrivalRate tries to execute a specific number of iterations for a\n// specific period.\n// TODO: combine with the ConstantArrivalRate?\ntype RampingArrivalRate struct {\n\t*BaseExecutor\n\tconfig RampingArrivalRateConfig\n\tet     *lib.ExecutionTuple\n}\n\n// Make sure we implement the lib.Executor interface.\nvar _ lib.Executor = &RampingArrivalRate{}\n\n// Init values needed for the execution\nfunc (varr *RampingArrivalRate) Init(_ context.Context) error {\n\t// err should always be nil, because Init() won't be called for executors\n\t// with no work, as determined by their config's HasWork() method.\n\tet, err := varr.executionState.ExecutionTuple.GetNewExecutionTupleFromValue(varr.config.MaxVUs.Int64)\n\tvarr.et = et\n\tvarr.iterSegIndex = lib.NewSegmentedIndex(et)\n\n\treturn err //nolint:wrapcheck\n}\n\n// cal calculates the  transtitions between stages and gives the next full value produced by the\n// stages. In this explanation we are talking about events and in practice those events are starting\n// of an iteration, but could really be anything that needs to occur at a constant or linear rate.\n//\n// The basic idea is that we make a graph with the X axis being time and the Y axis being\n// events/s we know that the area of the figure between the graph and the X axis is equal to the\n// amount of events done - we multiply time by events per time so we get events ...\n// Mathematics :).\n//\n// Lets look at a simple example - lets say we start with 2 events and the first stage is 5\n// seconds to 2 events/s and then we have a second stage for 5 second that goes up to 3 events\n// (using small numbers because ... well it is easier :D). This will look something like:\n//\n//\t ^\n//\t7|\n//\t6|\n//\t5|\n//\t4|\n//\t3|       ,-+\n//\t2|----+-'  |\n//\t1|    |    |\n//\t +----+----+---------------------------------->\n//\t 0s   5s   10s\n//\n// TODO: bigger and more stages\n//\n// Now the question is when(where on the graph) does the first event happen? Well in this simple\n// case it is easy it will be at 0.5 seconds as we are doing 2 events/s. If we want to know when\n// event n will happen we need to calculate n = 2 * x, where x is the time it will happen, so we\n// need to calculate x = n/2as we are interested in the time, x.\n// So if we just had a constant function for each event n we can calculate n/2 and find out when\n// it needs to start.\n// As we can see though the graph changes as stages change. But we can calculate how many events\n// each stage will have, again it is the area from the start of the stage to it's end and between\n// the graph and the X axis. So in this case we know that the first stage will have 10 full events\n// in it and no more or less. So we are trying to find out when the 12 event will happen the answer\n// will be after the 5th second.\n//\n// The graph doesn't show this well but we are ramping up linearly (we could possibly add\n// other ramping up/down functions later). So at 7.5 seconds for example we should be doing 2.5\n// events/s. You could start slicing the graph constantly and in this way to represent the ramping\n// up/down as a multiple constant functions, and you will get mostly okayish results. But here is\n// where calculus comes into play. Calculus gives us a way of exactly calculate the area for any\n// given function and linear ramp up/downs just happen to be pretty easy(actual math prove in\n// https://github.com/k6io/k6/issues/1299#issuecomment-575661084).\n//\n// One tricky last point is what happens if stage only completes 9.8 events? Let's say that the\n// first stage above was 4.9 seconds long 2 * 4.9 is 9.8, we have 9 events and .8 of an event, what\n// do with do with that? Well the 10th even will happen in the next stage (if any) and will happen\n// when the are from the start till time x is 0.2 (instead of 1) as 0.2 + 0.8 is 10. So the 12th for\n// example will be when the area is 2.2 as 9.8+2.2. So we just carry this around.\n//\n// So in the end what calis doing is to get formulas which will tell it when\n// a given event n in order will happen. It helps itself by knowing that in a given\n// stage will do some given amount (the area of the stage) events and if we past that one we\n// know we are not in that stage.\n//\n// The specific implementation here can only go forward and does incorporate\n// the striping algorithm from the lib.ExecutionTuple for additional speed up but this could\n// possibly be refactored if need for this arises.\nfunc (varc RampingArrivalRateConfig) cal(et *lib.ExecutionTuple, ch chan<- time.Duration) {\n\tstart, offsets, _ := et.GetStripedOffsets()\n\tli := -1\n\t// TODO: move this to a utility function, or directly what GetStripedOffsets uses once we see everywhere we will use it\n\tnext := func() int64 {\n\t\tli++\n\t\treturn offsets[li%len(offsets)]\n\t}\n\tdefer close(ch) // TODO: maybe this is not a good design - closing a channel we get\n\tvar (\n\t\tstageStart                   time.Duration\n\t\ttimeUnit                     = float64(varc.TimeUnit.Duration)\n\t\tdoneSoFar, endCount, to, dur float64\n\t\tfrom                         = float64(varc.StartRate.ValueOrZero()) / timeUnit\n\t\t// start .. starts at 0 but the algorithm works with area so we need to start from 1 not 0\n\t\ti = float64(start + 1)\n\t)\n\n\tfor _, stage := range varc.Stages {\n\t\tto = float64(stage.Target.ValueOrZero()) / timeUnit\n\t\tdur = float64(stage.Duration.Duration)\n\t\tif from != to { // ramp up/down\n\t\t\tendCount += dur * ((to-from)/2 + from)\n\t\t\tfor ; i <= endCount; i += float64(next()) {\n\t\t\t\t// TODO: try to twist this in a way to be able to get i (the only changing part)\n\t\t\t\t// somewhere where it is less in the middle of the equation\n\t\t\t\tx := (from*dur - noNegativeSqrt(dur*(from*from*dur+2*(i-doneSoFar)*(to-from)))) / (from - to)\n\n\t\t\t\tch <- time.Duration(x) + stageStart\n\t\t\t}\n\t\t} else {\n\t\t\tendCount += dur * to\n\t\t\tfor ; i <= endCount; i += float64(next()) {\n\t\t\t\tch <- time.Duration((i-doneSoFar)/to) + stageStart\n\t\t\t}\n\t\t}\n\t\tdoneSoFar = endCount\n\t\tfrom = to\n\t\tstageStart += stage.Duration.TimeDuration()\n\t}\n}\n\n// This is needed because, on some platforms (arm64), sometimes, even though we\n// in *reality* don't get negative results due to the nature of how float64 is\n// implemented, we get negative values (very close to the 0). This would get an\n// sqrt which is *even* smaller and likely will have negligible effects on the\n// final result.\n//\n// TODO: this is probably going to be less necessary if we do some kind of of\n// optimization above and the operations with the float64 are more \"accurate\"\n// even on arm platforms.\nfunc noNegativeSqrt(f float64) float64 {\n\tif !math.Signbit(f) {\n\t\treturn math.Sqrt(f)\n\t}\n\n\treturn 0\n}\n\n// Run executes a variable number of iterations per second.\n//\n// TODO: Split this up and make an independent component that can be reused\n// between the constant and ramping arrival rate executors - that way we can\n// keep the complexity in one well-architected part (with short methods and few\n// lambdas :D), while having both config frontends still be present for maximum\n// UX benefits. Basically, keep the progress bars and scheduling (i.e. at what\n// time should iteration X begin) different, but keep everyhing else the same.\n// This will allow us to implement https://github.com/k6io/k6/issues/1386\n// and things like all of the TODOs below in one place only.\n//\n//nolint:funlen\nfunc (varr RampingArrivalRate) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) {\n\tsegment := varr.executionState.ExecutionTuple.Segment\n\tgracefulStop := varr.config.GetGracefulStop()\n\tduration := sumStagesDuration(varr.config.Stages)\n\tpreAllocatedVUs := varr.config.GetPreAllocatedVUs(varr.executionState.ExecutionTuple)\n\tmaxVUs := varr.config.GetMaxVUs(varr.executionState.ExecutionTuple)\n\n\t// TODO: refactor and simplify\n\ttimeUnit := varr.config.TimeUnit.TimeDuration()\n\tstartArrivalRate := getScaledArrivalRate(segment, varr.config.StartRate.Int64, timeUnit)\n\tmaxUnscaledRate := getStagesUnscaledMaxTarget(varr.config.StartRate.Int64, varr.config.Stages)\n\tmaxArrivalRatePerSec, _ := getArrivalRatePerSec(getScaledArrivalRate(segment, maxUnscaledRate, timeUnit)).Float64()\n\tstartTickerPeriod := getTickerPeriod(startArrivalRate)\n\n\t// Make sure the log and the progress bar have accurate information\n\tvarr.logger.WithFields(logrus.Fields{\n\t\t\"maxVUs\": maxVUs, \"preAllocatedVUs\": preAllocatedVUs, \"duration\": duration, \"numStages\": len(varr.config.Stages),\n\t\t\"startTickerPeriod\": startTickerPeriod.Duration, \"type\": varr.config.GetType(),\n\t}).Debug(\"Starting executor run...\")\n\n\tactiveVUsWg := &sync.WaitGroup{}\n\n\treturnedVUs := make(chan struct{})\n\twaitOnProgressChannel := make(chan struct{})\n\tstartTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(parentCtx, duration, gracefulStop)\n\n\tvusPool := newActiveVUPool(varr.executionState)\n\n\tdefer func() {\n\t\t// Make sure all VUs aren't executing iterations anymore, for the cancel()\n\t\t// below to deactivate them.\n\t\t<-returnedVUs\n\t\t// first close the vusPool so we wait for the gracefulShutdown\n\t\tvusPool.Close()\n\t\tcancel()\n\t\tactiveVUsWg.Wait()\n\t\t<-waitOnProgressChannel\n\t}()\n\n\tactiveVUsCount := uint64(0)\n\ttickerPeriod := int64(startTickerPeriod.Duration)\n\tvusFmt := pb.GetFixedLengthIntFormat(maxVUs)\n\titersFmt := pb.GetFixedLengthFloatFormat(maxArrivalRatePerSec, 2) + \" iters/s\"\n\n\tprogressFn := func() (float64, []string) {\n\t\tcurrActiveVUs := atomic.LoadUint64(&activeVUsCount)\n\t\tcurrentTickerPeriod := atomic.LoadInt64(&tickerPeriod)\n\t\tprogVUs := fmt.Sprintf(vusFmt+\"/\"+vusFmt+\" VUs\",\n\t\t\tvusPool.Running(), currActiveVUs)\n\n\t\titersPerSec := 0.0\n\t\tif currentTickerPeriod > 0 {\n\t\t\titersPerSec = float64(time.Second) / float64(currentTickerPeriod)\n\t\t}\n\t\tprogIters := fmt.Sprintf(itersFmt, itersPerSec)\n\n\t\tright := []string{progVUs, duration.String(), progIters}\n\n\t\tspent := time.Since(startTime)\n\t\tif spent > duration {\n\t\t\treturn 1, right\n\t\t}\n\n\t\tspentDuration := pb.GetFixedLengthDuration(spent, duration)\n\t\tprogDur := fmt.Sprintf(\"%s/%s\", spentDuration, duration)\n\t\tright[1] = progDur\n\n\t\treturn math.Min(1, float64(spent)/float64(duration)), right\n\t}\n\n\tvarr.progress.Modify(pb.WithProgress(progressFn))\n\tmaxDurationCtx = lib.WithScenarioState(maxDurationCtx, &lib.ScenarioState{\n\t\tName:       varr.config.Name,\n\t\tExecutor:   varr.config.Type,\n\t\tStartTime:  startTime,\n\t\tProgressFn: progressFn,\n\t})\n\tgo func() {\n\t\ttrackProgress(parentCtx, maxDurationCtx, regDurationCtx, &varr, progressFn)\n\t\tclose(waitOnProgressChannel)\n\t}()\n\n\treturnVU := func(u lib.InitializedVU) {\n\t\t// Return the VU without decreasing the global active VU counter, which\n\t\t// is done in the goroutine started by activeVUPool.AddVU, whenever the\n\t\t// VU finishes running an iteration. This results in a more accurate\n\t\t// report of VUs that are _actually_ active.\n\t\tvarr.executionState.ReturnVU(u, false)\n\t\tactiveVUsWg.Done()\n\t}\n\n\trunIterationBasic := getIterationRunner(varr.executionState, varr.logger)\n\n\tactivateVU := func(initVU lib.InitializedVU) lib.ActiveVU {\n\t\tactiveVUsWg.Add(1)\n\t\tactiveVU := initVU.Activate(\n\t\t\tgetVUActivationParams(\n\t\t\t\tmaxDurationCtx, varr.config.BaseConfig, returnVU,\n\t\t\t\tvarr.nextIterationCounters))\n\t\tatomic.AddUint64(&activeVUsCount, 1)\n\n\t\tvusPool.AddVU(maxDurationCtx, activeVU, runIterationBasic)\n\t\treturn activeVU\n\t}\n\n\tremainingUnplannedVUs := maxVUs - preAllocatedVUs\n\tmakeUnplannedVUCh := make(chan struct{})\n\tdefer close(makeUnplannedVUCh)\n\tgo func() {\n\t\tdefer close(returnedVUs)\n\n\t\tfor range makeUnplannedVUCh {\n\t\t\tvarr.logger.Debug(\"Starting initialization of an unplanned VU...\")\n\t\t\tinitVU, err := varr.executionState.GetUnplannedVU(maxDurationCtx, varr.logger)\n\t\t\tif err != nil {\n\t\t\t\t// TODO figure out how to return it to the Run goroutine\n\t\t\t\tvarr.logger.WithError(err).Error(\"Error while allocating unplanned VU\")\n\t\t\t} else {\n\t\t\t\tvarr.logger.Debug(\"The unplanned VU finished initializing successfully!\")\n\t\t\t\tactivateVU(initVU)\n\t\t\t}\n\t\t}\n\t}()\n\n\t// Get the pre-allocated VUs in the local buffer\n\tfor range preAllocatedVUs {\n\t\tinitVU, err := varr.executionState.GetPlannedVU(varr.logger, false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tactivateVU(initVU)\n\t}\n\n\tregDurationDone := regDurationCtx.Done()\n\ttimer := time.NewTimer(time.Hour)\n\tstart := time.Now()\n\tch := make(chan time.Duration, 10) // buffer 10 iteration times ahead\n\tvar prevTime time.Duration\n\tshownWarning := false\n\tmetricTags := varr.getMetricTags(nil)\n\tgo varr.config.cal(varr.et, ch)\n\tfor nextTime := range ch {\n\t\tselect {\n\t\tcase <-regDurationDone:\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\t\tatomic.StoreInt64(&tickerPeriod, int64(nextTime-prevTime))\n\t\tprevTime = nextTime\n\t\tb := time.Until(start.Add(nextTime))\n\t\tif b > 0 { // TODO: have a minimal ?\n\t\t\ttimer.Reset(b)\n\t\t\tselect {\n\t\t\tcase <-timer.C:\n\t\t\tcase <-regDurationDone:\n\t\t\t\treturn nil\n\t\t\t}\n\t\t}\n\n\t\tif vusPool.TryRunIteration() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Since there aren't any free VUs available, consider this iteration\n\t\t// dropped - we aren't going to try to recover it, but\n\t\tmetrics.PushIfNotDone(parentCtx, out, metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: varr.executionState.Test.BuiltinMetrics.DroppedIterations,\n\t\t\t\tTags:   metricTags,\n\t\t\t},\n\t\t\tTime:  time.Now(),\n\t\t\tValue: 1,\n\t\t})\n\n\t\t// We'll try to start allocating another VU in the background,\n\t\t// non-blockingly, if we have remainingUnplannedVUs...\n\t\tif remainingUnplannedVUs == 0 {\n\t\t\tif !shownWarning {\n\t\t\t\tvarr.logger.Warningf(\"Insufficient VUs, reached %d active VUs and cannot initialize more\", maxVUs)\n\t\t\t\tshownWarning = true\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tselect {\n\t\tcase makeUnplannedVUCh <- struct{}{}: // great!\n\t\t\tremainingUnplannedVUs--\n\t\tdefault: // we're already allocating a new VU\n\t\t}\n\t}\n\treturn nil\n}\n\n// activeVUPool controls the activeVUs\n// executing the received requests for iterations.\ntype activeVUPool struct {\n\titerations chan struct{}\n\trunning    uint64\n\texecState  *lib.ExecutionState\n\twg         sync.WaitGroup\n}\n\n// newActiveVUPool returns an activeVUPool.\nfunc newActiveVUPool(es *lib.ExecutionState) *activeVUPool {\n\treturn &activeVUPool{\n\t\titerations: make(chan struct{}),\n\t\texecState:  es,\n\t}\n}\n\n// TryRunIteration invokes a request to execute a new iteration.\n// When there are no available VUs to process the request\n// then false is returned.\nfunc (p *activeVUPool) TryRunIteration() bool {\n\tselect {\n\tcase p.iterations <- struct{}{}:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// Running returns the number of the currently running VUs.\nfunc (p *activeVUPool) Running() uint64 {\n\treturn atomic.LoadUint64(&p.running)\n}\n\n// AddVU adds the active VU to the pool of VUs for handling the incoming\n// requests. When a new request is accepted the runfn function is executed. This\n// is also when we change the global active VUs counter, since it results in a\n// more accurate report of VUs that are _actually_ active.\nfunc (p *activeVUPool) AddVU(ctx context.Context, avu lib.ActiveVU, runfn func(context.Context, lib.ActiveVU) bool) {\n\tp.wg.Add(1)\n\tch := make(chan struct{})\n\tgo func() {\n\t\tdefer p.wg.Done()\n\n\t\tclose(ch)\n\t\tfor range p.iterations {\n\t\t\tatomic.AddUint64(&p.running, uint64(1))\n\t\t\tp.execState.ModCurrentlyActiveVUsCount(+1)\n\t\t\trunfn(ctx, avu)\n\t\t\tp.execState.ModCurrentlyActiveVUsCount(-1)\n\t\t\tatomic.AddUint64(&p.running, ^uint64(0))\n\t\t}\n\t}()\n\t<-ch\n}\n\n// Close stops the pool from accepting requests\n// then it will wait for all on-going iterations to complete.\nfunc (p *activeVUPool) Close() {\n\tclose(p.iterations)\n\tp.wg.Wait()\n}\n"
  },
  {
    "path": "lib/executor/ramping_arrival_rate_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc getTestRampingArrivalRateConfig() *RampingArrivalRateConfig {\n\treturn &RampingArrivalRateConfig{\n\t\tBaseConfig: BaseConfig{GracefulStop: types.NullDurationFrom(1 * time.Second)},\n\t\tTimeUnit:   types.NullDurationFrom(time.Second),\n\t\tStartRate:  null.IntFrom(10),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(time.Second * 1),\n\t\t\t\tTarget:   null.IntFrom(10),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(time.Second * 1),\n\t\t\t\tTarget:   null.IntFrom(50),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(time.Second * 1),\n\t\t\t\tTarget:   null.IntFrom(50),\n\t\t\t},\n\t\t},\n\t\tPreAllocatedVUs: null.IntFrom(10),\n\t\tMaxVUs:          null.IntFrom(20),\n\t}\n}\n\nfunc TestRampingArrivalRateRunNotEnoughAllocatedVUsWarn(t *testing.T) {\n\tt.Parallel()\n\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\ttime.Sleep(time.Second)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestRampingArrivalRateConfig())\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tentries := test.logHook.Drain()\n\trequire.NotEmpty(t, entries)\n\tfor _, entry := range entries {\n\t\trequire.Equal(t,\n\t\t\t\"Insufficient VUs, reached 20 active VUs and cannot initialize more\",\n\t\t\tentry.Message)\n\t\trequire.Equal(t, logrus.WarnLevel, entry.Level)\n\t}\n}\n\nfunc TestRampingArrivalRateRunCorrectRate(t *testing.T) {\n\tt.Parallel()\n\tvar count int64\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\tatomic.AddInt64(&count, 1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestRampingArrivalRateConfig())\n\tdefer test.cancel()\n\n\tvar wg sync.WaitGroup\n\twg.Go(func() {\n\t\t// check that we got around the amount of VU iterations as we would expect\n\t\tvar currentCount int64\n\n\t\ttime.Sleep(time.Second)\n\t\tcurrentCount = atomic.SwapInt64(&count, 0)\n\t\tassert.InDelta(t, 10, currentCount, 1)\n\n\t\ttime.Sleep(time.Second)\n\t\tcurrentCount = atomic.SwapInt64(&count, 0)\n\t\tassert.InDelta(t, 30, currentCount, 2)\n\n\t\ttime.Sleep(time.Second)\n\t\tcurrentCount = atomic.SwapInt64(&count, 0)\n\t\tassert.InDelta(t, 50, currentCount, 3)\n\t})\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\twg.Wait()\n\trequire.Empty(t, test.logHook.Drain())\n}\n\nfunc TestRampingArrivalRateRunUnplannedVUs(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &RampingArrivalRateConfig{\n\t\tTimeUnit: types.NullDurationFrom(time.Second),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\t// the minus one makes it so only 9 iterations will be started instead of 10\n\t\t\t\t// as the 10th happens to be just at the end and sometimes doesn't get executed :(\n\t\t\t\tDuration: types.NullDurationFrom(time.Second*2 - 1),\n\t\t\t\tTarget:   null.IntFrom(10),\n\t\t\t},\n\t\t},\n\t\tPreAllocatedVUs: null.IntFrom(1),\n\t\tMaxVUs:          null.IntFrom(3),\n\t}\n\n\tvar count int64\n\tch := make(chan struct{})  // closed when new unplannedVU is started and signal to get to next iterations\n\tch2 := make(chan struct{}) // closed when a second iteration was started on an old VU in order to test it won't start a second unplanned VU in parallel or at all\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\tcur := atomic.AddInt64(&count, 1)\n\t\tswitch cur {\n\t\tcase 1:\n\t\t\t<-ch // wait to start again\n\t\tcase 2:\n\t\t\t<-ch2 // wait to start again\n\t\t}\n\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\ttest.state.SetInitVUFunc(func(ctx context.Context, _ *logrus.Entry) (lib.InitializedVU, error) {\n\t\tcur := atomic.LoadInt64(&count)\n\t\trequire.Equal(t, int64(1), cur)\n\t\ttime.Sleep(time.Second / 2)\n\n\t\tclose(ch)\n\t\ttime.Sleep(time.Millisecond * 150)\n\n\t\tcur = atomic.LoadInt64(&count)\n\t\trequire.Equal(t, int64(2), cur)\n\n\t\ttime.Sleep(time.Millisecond * 150)\n\t\tcur = atomic.LoadInt64(&count)\n\t\trequire.Equal(t, int64(2), cur)\n\n\t\tclose(ch2)\n\t\ttime.Sleep(time.Millisecond * 200)\n\t\tcur = atomic.LoadInt64(&count)\n\t\trequire.NotEqual(t, int64(2), cur)\n\t\tidl, idg := test.state.GetUniqueVUIdentifiers()\n\t\treturn runner.NewVU(ctx, idl, idg, engineOut)\n\t})\n\n\tassert.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tassert.Empty(t, test.logHook.Drain())\n\n\tdroppedIters := sumMetricValues(engineOut, metrics.DroppedIterationsName)\n\tassert.Equal(t, count+int64(droppedIters), int64(9))\n}\n\nfunc TestRampingArrivalRateRunCorrectRateWithSlowRate(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &RampingArrivalRateConfig{\n\t\tTimeUnit: types.NullDurationFrom(time.Second),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(time.Second * 2),\n\t\t\t\tTarget:   null.IntFrom(10),\n\t\t\t},\n\t\t},\n\t\tPreAllocatedVUs: null.IntFrom(1),\n\t\tMaxVUs:          null.IntFrom(3),\n\t}\n\n\tvar count int64\n\tch := make(chan struct{}) // closed when new unplannedVU is started and signal to get to next iterations\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\tcur := atomic.AddInt64(&count, 1)\n\t\tif cur == 1 {\n\t\t\t<-ch // wait to start again\n\t\t}\n\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\ttest.state.SetInitVUFunc(func(ctx context.Context, _ *logrus.Entry) (lib.InitializedVU, error) {\n\t\tt.Log(\"init\")\n\t\tcur := atomic.LoadInt64(&count)\n\t\trequire.Equal(t, int64(1), cur)\n\t\ttime.Sleep(time.Millisecond * 200)\n\t\tclose(ch)\n\t\ttime.Sleep(time.Millisecond * 200)\n\t\tcur = atomic.LoadInt64(&count)\n\t\trequire.NotEqual(t, int64(1), cur)\n\n\t\tidl, idg := test.state.GetUniqueVUIdentifiers()\n\t\treturn runner.NewVU(ctx, idl, idg, engineOut)\n\t})\n\n\tassert.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tassert.Empty(t, test.logHook.Drain())\n\tassert.Equal(t, int64(0), test.state.GetCurrentlyActiveVUsCount())\n\tassert.Equal(t, int64(2), test.state.GetInitializedVUsCount())\n}\n\nfunc TestRampingArrivalRateRunGracefulStop(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &RampingArrivalRateConfig{\n\t\tTimeUnit: types.NullDurationFrom(1 * time.Second),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(2 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(10),\n\t\t\t},\n\t\t},\n\t\tStartRate:       null.IntFrom(10),\n\t\tPreAllocatedVUs: null.IntFrom(10),\n\t\tMaxVUs:          null.IntFrom(10),\n\t\tBaseConfig: BaseConfig{\n\t\t\tGracefulStop: types.NullDurationFrom(5 * time.Second),\n\t\t},\n\t}\n\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\ttime.Sleep(5 * time.Second)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\tdefer close(engineOut)\n\n\tassert.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tassert.Equal(t, int64(0), test.state.GetCurrentlyActiveVUsCount())\n\tassert.Equal(t, int64(10), test.state.GetInitializedVUsCount())\n\tassert.Equal(t, uint64(10), test.state.GetFullIterationCount())\n}\n\nfunc BenchmarkRampingArrivalRateRun(b *testing.B) {\n\ttests := []struct {\n\t\tprealloc null.Int\n\t}{\n\t\t{prealloc: null.IntFrom(10)},\n\t\t{prealloc: null.IntFrom(100)},\n\t\t{prealloc: null.IntFrom(1e3)},\n\t\t{prealloc: null.IntFrom(10e3)},\n\t}\n\n\tfor _, tc := range tests {\n\t\tb.Run(fmt.Sprintf(\"VUs%d\", tc.prealloc.ValueOrZero()), func(b *testing.B) {\n\t\t\tengineOut := make(chan metrics.SampleContainer, 1000)\n\t\t\tdefer close(engineOut)\n\t\t\tgo func() {\n\t\t\t\tfor range engineOut { //nolint:revive // we want to discard samples\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tvar count int64\n\t\t\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\t\t\tatomic.AddInt64(&count, 1)\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\ttestRunState := getTestRunState(b, lib.Options{}, runner)\n\t\t\tes := lib.NewExecutionState(\n\t\t\t\ttestRunState, mustNewExecutionTuple(nil, nil),\n\t\t\t\tuint64(tc.prealloc.Int64), uint64(tc.prealloc.Int64),\n\t\t\t)\n\n\t\t\t// an high target to get the highest rate\n\t\t\ttarget := int64(1e9)\n\n\t\t\tctx, cancel, executor, _ := setupExecutor(\n\t\t\t\tb, &RampingArrivalRateConfig{\n\t\t\t\t\tTimeUnit: types.NullDurationFrom(1 * time.Second),\n\t\t\t\t\tStages: []Stage{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDuration: types.NullDurationFrom(0),\n\t\t\t\t\t\t\tTarget:   null.IntFrom(target),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDuration: types.NullDurationFrom(5 * time.Second),\n\t\t\t\t\t\t\tTarget:   null.IntFrom(target),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tPreAllocatedVUs: tc.prealloc,\n\t\t\t\t\tMaxVUs:          tc.prealloc,\n\t\t\t\t}, es)\n\t\t\tdefer cancel()\n\n\t\t\tb.ResetTimer()\n\t\t\tstart := time.Now()\n\n\t\t\terr := executor.Run(ctx, engineOut)\n\t\t\ttook := time.Since(start)\n\t\t\tassert.NoError(b, err)\n\n\t\t\titerations := float64(atomic.LoadInt64(&count))\n\t\t\tb.ReportMetric(0, \"ns/op\")\n\t\t\tb.ReportMetric(iterations/took.Seconds(), \"iterations/s\")\n\t\t})\n\t}\n}\n\nfunc mustNewExecutionTuple(seg *lib.ExecutionSegment, seq *lib.ExecutionSegmentSequence) *lib.ExecutionTuple {\n\tet, err := lib.NewExecutionTuple(seg, seq)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn et\n}\n\nfunc TestRampingArrivalRateCal(t *testing.T) {\n\tt.Parallel()\n\n\tvar (\n\t\tdefaultTimeUnit = time.Second\n\t\tgetConfig       = func() RampingArrivalRateConfig {\n\t\t\treturn RampingArrivalRateConfig{\n\t\t\t\tStartRate: null.IntFrom(0),\n\t\t\t\tStages: []Stage{ // TODO make this even bigger and longer .. will need more time\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(time.Second * 5),\n\t\t\t\t\t\tTarget:   null.IntFrom(1),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(time.Second * 1),\n\t\t\t\t\t\tTarget:   null.IntFrom(1),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(time.Second * 5),\n\t\t\t\t\t\tTarget:   null.IntFrom(0),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t}\n\t)\n\n\ttestCases := []struct {\n\t\texpectedTimes []time.Duration\n\t\tet            *lib.ExecutionTuple\n\t\ttimeUnit      time.Duration\n\t}{\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 3162, time.Millisecond * 4472, time.Millisecond * 5500, time.Millisecond * 6527, time.Millisecond * 7837, time.Second * 11},\n\t\t\tet:            mustNewExecutionTuple(nil, nil),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 4472, time.Millisecond * 7837},\n\t\t\tet:            mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), nil),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 4472, time.Millisecond * 7837},\n\t\t\tet:            mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,1\")),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 4472, time.Millisecond * 7837},\n\t\t\tet:            mustNewExecutionTuple(newExecutionSegmentFromString(\"1/3:2/3\"), nil),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 4472, time.Millisecond * 7837},\n\t\t\tet:            mustNewExecutionTuple(newExecutionSegmentFromString(\"2/3:1\"), nil),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 3162, time.Millisecond * 6527},\n\t\t\tet:            mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\")),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 4472, time.Millisecond * 7837},\n\t\t\tet:            mustNewExecutionTuple(newExecutionSegmentFromString(\"1/3:2/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\")),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{time.Millisecond * 5500, time.Millisecond * 11000},\n\t\t\tet:            mustNewExecutionTuple(newExecutionSegmentFromString(\"2/3:1\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\")),\n\t\t},\n\t\t{\n\t\t\texpectedTimes: []time.Duration{\n\t\t\t\ttime.Millisecond * 1825, time.Millisecond * 2581, time.Millisecond * 3162, time.Millisecond * 3651, time.Millisecond * 4082, time.Millisecond * 4472,\n\t\t\t\ttime.Millisecond * 4830, time.Millisecond * 5166, time.Millisecond * 5499, time.Millisecond * 5833, time.Millisecond * 6169, time.Millisecond * 6527,\n\t\t\t\ttime.Millisecond * 6917, time.Millisecond * 7348, time.Millisecond * 7837, time.Millisecond * 8418, time.Millisecond * 9174, time.Millisecond * 10999,\n\t\t\t},\n\t\t\tet:       mustNewExecutionTuple(nil, nil),\n\t\t\ttimeUnit: time.Second / 3, // three  times as fast\n\t\t},\n\t\t// TODO: extend more\n\t}\n\n\tfor testNum, testCase := range testCases {\n\t\tet := testCase.et\n\t\texpectedTimes := testCase.expectedTimes\n\t\tconfig := getConfig()\n\t\tconfig.TimeUnit = types.NewNullDuration(testCase.timeUnit, true)\n\t\tif testCase.timeUnit == 0 {\n\t\t\tconfig.TimeUnit = types.NewNullDuration(defaultTimeUnit, true)\n\t\t}\n\n\t\tt.Run(fmt.Sprintf(\"testNum %d - %s timeunit %s\", testNum, et, config.TimeUnit), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tch := make(chan time.Duration)\n\t\t\tgo config.cal(et, ch)\n\t\t\tchanges := make([]time.Duration, 0, len(expectedTimes))\n\t\t\tfor c := range ch {\n\t\t\t\tchanges = append(changes, c)\n\t\t\t}\n\t\t\tassert.Equal(t, len(expectedTimes), len(changes))\n\t\t\tfor i, expectedTime := range expectedTimes {\n\t\t\t\trequire.True(t, i < len(changes))\n\t\t\t\tchange := changes[i]\n\t\t\t\tassert.InEpsilon(t, expectedTime, change, 0.001, \"Expected around %s, got %s\", expectedTime, change)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc BenchmarkCal(b *testing.B) {\n\tfor _, t := range []time.Duration{\n\t\ttime.Second, time.Minute,\n\t} {\n\t\tb.Run(t.String(), func(b *testing.B) {\n\t\t\tconfig := RampingArrivalRateConfig{\n\t\t\t\tTimeUnit:  types.NullDurationFrom(time.Second),\n\t\t\t\tStartRate: null.IntFrom(50),\n\t\t\t\tStages: []Stage{\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(t),\n\t\t\t\t\t\tTarget:   null.IntFrom(49),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(t),\n\t\t\t\t\t\tTarget:   null.IntFrom(50),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\tet := mustNewExecutionTuple(nil, nil)\n\n\t\t\tb.ResetTimer()\n\t\t\tb.RunParallel(func(pb *testing.PB) {\n\t\t\t\tfor pb.Next() {\n\t\t\t\t\tch := make(chan time.Duration, 20)\n\t\t\t\t\tgo config.cal(et, ch)\n\t\t\t\t\tfor c := range ch {\n\t\t\t\t\t\t_ = c\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t}\n}\n\nfunc BenchmarkCalRat(b *testing.B) {\n\tfor _, t := range []time.Duration{\n\t\ttime.Second, time.Minute,\n\t} {\n\t\tb.Run(t.String(), func(b *testing.B) {\n\t\t\tconfig := RampingArrivalRateConfig{\n\t\t\t\tTimeUnit:  types.NullDurationFrom(time.Second),\n\t\t\t\tStartRate: null.IntFrom(50),\n\t\t\t\tStages: []Stage{\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(t),\n\t\t\t\t\t\tTarget:   null.IntFrom(49),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tDuration: types.NullDurationFrom(t),\n\t\t\t\t\t\tTarget:   null.IntFrom(50),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\tet := mustNewExecutionTuple(nil, nil)\n\n\t\t\tb.ResetTimer()\n\t\t\tb.RunParallel(func(pb *testing.PB) {\n\t\t\t\tfor pb.Next() {\n\t\t\t\t\tch := make(chan time.Duration, 20)\n\t\t\t\t\tgo config.calRat(et, ch)\n\t\t\t\t\tfor c := range ch {\n\t\t\t\t\t\t_ = c\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\t}\n}\n\nfunc TestCompareCalImplementation(t *testing.T) {\n\tt.Parallel()\n\t// This test checks that the cal and calRat implementation get roughly similar numbers\n\t// in my experiment the difference is 1(nanosecond) in 7 case for the whole test\n\t// the duration is 1 second for each stage as calRat takes way longer - a longer better test can\n\t// be done when/if it's performance is improved\n\tconfig := RampingArrivalRateConfig{\n\t\tTimeUnit:  types.NullDurationFrom(time.Second),\n\t\tStartRate: null.IntFrom(0),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(200),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(200),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(2000),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(2000),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(300),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(300),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(1333),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(1334),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(1334),\n\t\t\t},\n\t\t},\n\t}\n\n\tet := mustNewExecutionTuple(nil, nil)\n\tchRat := make(chan time.Duration, 20)\n\tch := make(chan time.Duration, 20)\n\tgo config.calRat(et, chRat)\n\tgo config.cal(et, ch)\n\tcount := 0\n\tvar diff int\n\tfor c := range ch {\n\t\tcount++\n\t\tcRat := <-chRat\n\t\tif !assert.InDelta(t, c, cRat, 1, \"%d\", count) {\n\t\t\tdiff++\n\t\t}\n\t}\n\trequire.Equal(t, 0, diff)\n}\n\n// calRat code here is just to check how accurate the cal implemenattion is\n// there are no other tests for it so it depends on the test of cal that it is actually accurate :D\n\n//nolint:gochecknoglobals\nvar two = big.NewRat(2, 1)\n\n// from https://groups.google.com/forum/#!topic/golang-nuts/aIcDf8T-Png\nfunc sqrtRat(x *big.Rat) *big.Rat {\n\tvar z, a, b big.Rat\n\tvar ns, ds big.Int\n\tni, di := x.Num(), x.Denom()\n\tz.SetFrac(ns.Rsh(ni, uint(ni.BitLen())/2), ds.Rsh(di, uint(di.BitLen())/2))\n\tfor i := 10; i > 0; i-- { // TODO: better termination\n\t\ta.Sub(a.Mul(&z, &z), x)\n\t\tf, _ := a.Float64()\n\t\tif f == 0 {\n\t\t\tbreak\n\t\t}\n\t\t// fmt.Println(x, z, i)\n\t\tz.Sub(&z, b.Quo(&a, b.Mul(two, &z)))\n\t}\n\treturn &z\n}\n\n// This implementation is just for reference and accuracy testing\nfunc (varc RampingArrivalRateConfig) calRat(et *lib.ExecutionTuple, ch chan<- time.Duration) {\n\tdefer close(ch)\n\n\tstart, offsets, _ := et.GetStripedOffsets()\n\tli := -1\n\tnext := func() int64 {\n\t\tli++\n\t\treturn offsets[li%len(offsets)]\n\t}\n\tiRat := big.NewRat(start+1, 1)\n\n\tcarry := big.NewRat(0, 1)\n\tdoneSoFar := big.NewRat(0, 1)\n\tendCount := big.NewRat(0, 1)\n\tcurr := varc.StartRate.ValueOrZero()\n\tvar base time.Duration\n\tfor _, stage := range varc.Stages {\n\t\ttarget := stage.Target.ValueOrZero()\n\t\tif target != curr {\n\t\t\tvar (\n\t\t\t\tfrom = big.NewRat(curr, int64(time.Second))\n\t\t\t\tto   = big.NewRat(target, int64(time.Second))\n\t\t\t\tdur  = big.NewRat(stage.Duration.TimeDuration().Nanoseconds(), 1)\n\t\t\t)\n\t\t\t// precalcualations :)\n\t\t\ttoMinusFrom := new(big.Rat).Sub(to, from)\n\t\t\tfromSquare := new(big.Rat).Mul(from, from)\n\t\t\tdurMulSquare := new(big.Rat).Mul(dur, fromSquare)\n\t\t\tfromMulDur := new(big.Rat).Mul(from, dur)\n\t\t\toneOverToMinusFrom := new(big.Rat).Inv(toMinusFrom)\n\n\t\t\tendCount.Add(endCount,\n\t\t\t\tnew(big.Rat).Mul(\n\t\t\t\t\tdur,\n\t\t\t\t\tnew(big.Rat).Add(new(big.Rat).Mul(toMinusFrom, big.NewRat(1, 2)), from)))\n\t\t\tfor ; endCount.Cmp(iRat) >= 0; iRat.Add(iRat, big.NewRat(next(), 1)) {\n\t\t\t\t// even with all of this optimizations sqrtRat is taking so long this is still\n\t\t\t\t// extremely slow ... :(\n\t\t\t\tbuf := new(big.Rat).Sub(iRat, doneSoFar)\n\t\t\t\tbuf.Mul(buf, two)\n\t\t\t\tbuf.Mul(buf, toMinusFrom)\n\t\t\t\tbuf.Add(buf, durMulSquare)\n\t\t\t\tbuf.Mul(buf, dur)\n\t\t\t\tbuf.Sub(fromMulDur, sqrtRat(buf))\n\t\t\t\tbuf.Mul(buf, oneOverToMinusFrom)\n\n\t\t\t\tr, _ := buf.Float64()\n\t\t\t\tch <- base + time.Duration(-r) // the minus is because we don't deive by from-to but by to-from above\n\t\t\t}\n\t\t} else {\n\t\t\tstep := big.NewRat(int64(time.Second), target)\n\t\t\tfirst := big.NewRat(0, 1)\n\t\t\tfirst.Sub(first, carry)\n\t\t\tendCount.Add(endCount, new(big.Rat).Mul(big.NewRat(target, 1), big.NewRat(stage.Duration.TimeDuration().Nanoseconds(), varc.TimeUnit.TimeDuration().Nanoseconds())))\n\n\t\t\tfor ; endCount.Cmp(iRat) >= 0; iRat.Add(iRat, big.NewRat(next(), 1)) {\n\t\t\t\tres := new(big.Rat).Sub(iRat, doneSoFar) // this can get next added to it but will need to change the above for .. so\n\t\t\t\tr, _ := res.Mul(res, step).Float64()\n\t\t\t\tch <- base + time.Duration(r)\n\t\t\t\tfirst.Add(first, step)\n\t\t\t}\n\t\t}\n\t\tdoneSoFar.Set(endCount) // copy\n\t\tcurr = target\n\t\tbase += stage.Duration.TimeDuration()\n\t}\n}\n\nfunc TestRampingArrivalRateGlobalIters(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &RampingArrivalRateConfig{\n\t\tBaseConfig:      BaseConfig{GracefulStop: types.NullDurationFrom(100 * time.Millisecond)},\n\t\tTimeUnit:        types.NullDurationFrom(950 * time.Millisecond),\n\t\tStartRate:       null.IntFrom(0),\n\t\tPreAllocatedVUs: null.IntFrom(4),\n\t\tMaxVUs:          null.IntFrom(5),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(20),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(0),\n\t\t\t},\n\t\t},\n\t}\n\n\ttestCases := []struct {\n\t\tseq, seg string\n\t\texpIters []uint64\n\t}{\n\t\t{\"0,1/4,3/4,1\", \"0:1/4\", []uint64{1, 6, 11, 16}},\n\t\t{\"0,1/4,3/4,1\", \"1/4:3/4\", []uint64{0, 2, 4, 5, 7, 9, 10, 12, 14, 15, 17, 19, 20}},\n\t\t{\"0,1/4,3/4,1\", \"3/4:1\", []uint64{3, 8, 13, 18}},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%s_%s\", tc.seq, tc.seg), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotIters := []uint64{}\n\t\t\tvar mx sync.Mutex\n\t\t\trunner := simpleRunner(func(_ context.Context, state *lib.State) error {\n\t\t\t\tmx.Lock()\n\t\t\t\tgotIters = append(gotIters, state.GetScenarioGlobalVUIter())\n\t\t\t\tmx.Unlock()\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\ttest := setupExecutorTest(t, tc.seg, tc.seq, lib.Options{}, runner, config)\n\t\t\tdefer test.cancel()\n\n\t\t\tengineOut := make(chan metrics.SampleContainer, 100)\n\t\t\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\t\t\tassert.Equal(t, tc.expIters, gotIters)\n\t\t})\n\t}\n}\n\nfunc TestRampingArrivalRateCornerCase(t *testing.T) {\n\tt.Parallel()\n\tconfig := &RampingArrivalRateConfig{\n\t\tTimeUnit:  types.NullDurationFrom(time.Second),\n\t\tStartRate: null.IntFrom(1),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(1),\n\t\t\t},\n\t\t},\n\t\tMaxVUs: null.IntFrom(2),\n\t}\n\n\tet, err := lib.NewExecutionTuple(newExecutionSegmentFromString(\"1/5:2/5\"), newExecutionSegmentSequenceFromString(\"0,1/5,2/5,1\"))\n\trequire.NoError(t, err)\n\n\trequire.False(t, config.HasWork(et))\n}\n\nfunc TestRampingArrivalRateActiveVUs(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &RampingArrivalRateConfig{\n\t\tBaseConfig: BaseConfig{GracefulStop: types.NullDurationFrom(0 * time.Second)},\n\t\tTimeUnit:   types.NullDurationFrom(time.Second),\n\t\tStartRate:  null.IntFrom(10),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(950 * time.Millisecond),\n\t\t\t\tTarget:   null.IntFrom(20),\n\t\t\t},\n\t\t},\n\t\tPreAllocatedVUs: null.IntFrom(5),\n\t\tMaxVUs:          null.IntFrom(10),\n\t}\n\n\tvar (\n\t\trunning          int64\n\t\tgetCurrActiveVUs func() int64\n\t\trunMx            sync.Mutex\n\t)\n\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\trunMx.Lock()\n\t\trunning++\n\t\tassert.Equal(t, running, getCurrActiveVUs())\n\t\trunMx.Unlock()\n\t\t// Block the VU to cause the executor to schedule more\n\t\t<-ctx.Done()\n\t\treturn nil\n\t})\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tgetCurrActiveVUs = test.state.GetCurrentlyActiveVUsCount\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\n\tassert.GreaterOrEqual(t, running, int64(5))\n\tassert.LessOrEqual(t, running, int64(10))\n}\n\nfunc TestRampingArrivalRateActiveVUs_GetExecutionRequirements(t *testing.T) {\n\tt.Parallel()\n\n\ttcs := map[string]struct {\n\t\tpreAllocatedVUs    int64\n\t\tmaxVUs             int64\n\t\tsegment            string\n\t\tsequence           string\n\t\texpPlannedVUs      uint64\n\t\texpMaxUnplannedVUs uint64\n\t}{\n\t\t\"Segmented/Odd\":     {preAllocatedVUs: 1, maxVUs: 4000, segment: \"0:1/4\", sequence: \"0,1/4,1/2,3/4,1\", expPlannedVUs: 1, expMaxUnplannedVUs: 999},\n\t\t\"Segmented/Even\":    {preAllocatedVUs: 100, maxVUs: 4000, segment: \"0:1/4\", sequence: \"0,1/4,1/2,3/4,1\", expPlannedVUs: 25, expMaxUnplannedVUs: 975},\n\t\t\"NotSegmented/Odd\":  {preAllocatedVUs: 1, maxVUs: 4000, segment: \"0:1\", sequence: \"0,1\", expPlannedVUs: 1, expMaxUnplannedVUs: 3999},\n\t\t\"NotSegmented/Even\": {preAllocatedVUs: 100, maxVUs: 4000, segment: \"0:1\", sequence: \"0,1\", expPlannedVUs: 100, expMaxUnplannedVUs: 3900},\n\t}\n\n\tfor name, tc := range tcs {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tconfig := &RampingArrivalRateConfig{\n\t\t\t\tPreAllocatedVUs: null.IntFrom(tc.preAllocatedVUs),\n\t\t\t\tMaxVUs:          null.IntFrom(tc.maxVUs),\n\t\t\t}\n\n\t\t\tet, err := lib.NewExecutionTuple(newExecutionSegmentFromString(tc.segment), newExecutionSegmentSequenceFromString(tc.sequence))\n\t\t\trequire.NoError(t, err)\n\n\t\t\texp := []lib.ExecutionStep{{PlannedVUs: tc.expPlannedVUs, MaxUnplannedVUs: tc.expMaxUnplannedVUs}, {}}\n\t\t\trequire.Equal(t, exp, config.GetExecutionRequirements(et))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "lib/executor/ramping_vus.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst (\n\trampingVUsType = \"ramping-vus\"\n\n\t// maxConcurrentVUs is an arbitrary limit for sanity checks.\n\t// It prevents running an exaggeratedly large number of concurrent VUs which may lead to an out-of-memory.\n\tmaxConcurrentVUs int = 100_000_000\n)\n\nfunc init() {\n\tlib.RegisterExecutorConfigType(\n\t\trampingVUsType,\n\t\tfunc(name string, rawJSON []byte) (lib.ExecutorConfig, error) {\n\t\t\tconfig := NewRampingVUsConfig(name)\n\t\t\terr := lib.StrictJSONUnmarshal(rawJSON, &config)\n\t\t\treturn config, err\n\t\t},\n\t)\n}\n\n// Stage contains\ntype Stage struct {\n\tDuration types.NullDuration `json:\"duration\"`\n\tTarget   null.Int           `json:\"target\"` // TODO: maybe rename this to endVUs? something else?\n\t// TODO: add a progression function?\n}\n\n// RampingVUsConfig stores the configuration for the stages executor\ntype RampingVUsConfig struct {\n\tBaseConfig\n\tStartVUs         null.Int           `json:\"startVUs\"`\n\tStages           []Stage            `json:\"stages\"`\n\tGracefulRampDown types.NullDuration `json:\"gracefulRampDown\"`\n}\n\n// NewRampingVUsConfig returns a RampingVUsConfig with its default values\nfunc NewRampingVUsConfig(name string) RampingVUsConfig {\n\treturn RampingVUsConfig{\n\t\tBaseConfig:       NewBaseConfig(name, rampingVUsType),\n\t\tStartVUs:         null.NewInt(1, false),\n\t\tGracefulRampDown: types.NewNullDuration(30*time.Second, false),\n\t}\n}\n\n// Make sure we implement the lib.ExecutorConfig interface\nvar _ lib.ExecutorConfig = &RampingVUsConfig{}\n\n// GetStartVUs is just a helper method that returns the scaled starting VUs.\nfunc (vlvc RampingVUsConfig) GetStartVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(vlvc.StartVUs.Int64)\n}\n\n// GetGracefulRampDown is just a helper method that returns the graceful\n// ramp-down period as a standard Go time.Duration value...\nfunc (vlvc RampingVUsConfig) GetGracefulRampDown() time.Duration {\n\treturn vlvc.GracefulRampDown.TimeDuration()\n}\n\n// GetDescription returns a human-readable description of the executor options\nfunc (vlvc RampingVUsConfig) GetDescription(et *lib.ExecutionTuple) string {\n\tmaxVUs := et.ScaleInt64(getStagesUnscaledMaxTarget(vlvc.StartVUs.Int64, vlvc.Stages))\n\treturn fmt.Sprintf(\"Up to %d looping VUs for %s over %d stages%s\",\n\t\tmaxVUs, sumStagesDuration(vlvc.Stages), len(vlvc.Stages),\n\t\tvlvc.getBaseInfo(fmt.Sprintf(\"gracefulRampDown: %s\", vlvc.GetGracefulRampDown())))\n}\n\n// Validate makes sure all options are configured and valid\nfunc (vlvc RampingVUsConfig) Validate() []error {\n\terrors := vlvc.BaseConfig.Validate()\n\tif vlvc.StartVUs.Int64 < 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of start VUs can't be negative\"))\n\t}\n\n\tif getStagesUnscaledMaxTarget(vlvc.StartVUs.Int64, vlvc.Stages) <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"either startVUs or one of the stages' target values must be greater than 0\"))\n\t}\n\n\terrors = append(errors, validateStages(vlvc.Stages)...)\n\terrors = append(errors, validateTargetShifts(vlvc.StartVUs.Int64, vlvc.Stages)...)\n\n\treturn errors\n}\n\n// getRawExecutionSteps calculates and returns as execution steps the number of\n// actively running VUs the executor should have at every moment.\n//\n// It doesn't take into account graceful ramp-downs. It also doesn't deal with\n// the end-of-executor drop to 0 VUs, whether graceful or not. These are\n// handled by GetExecutionRequirements(), which internally uses this method and\n// reserveVUsForGracefulRampDowns().\n//\n// The zeroEnd argument tells the method if we should artificially add a step\n// with 0 VUs at offset sum(stages.duration), i.e. when the executor is\n// supposed to end.\n//\n// It's also important to note how scaling works. Say, we ramp up from 0 to 10\n// VUs over 10 seconds and then back to 0, and we want to split the execution in\n// 2 equal segments (i.e. execution segments \"0:0.5\" and \"0.5:1\"). The original\n// execution steps would look something like this:\n//\n//\tVUs  ^\n//\t   10|          *\n//\t    9|         ***\n//\t    8|        *****\n//\t    7|       *******\n//\t    6|      *********\n//\t    5|     ***********\n//\t    4|    *************\n//\t    3|   ***************\n//\t    2|  *****************\n//\t    1| *******************\n//\t    0------------------------> time(s)\n//\t      01234567890123456789012   (t%10)\n//\t      00000000001111111111222   (t/10)\n//\n// The chart for one of the execution segments would look like this:\n//\n//\tVUs  ^\n//\t    5|         XXX\n//\t    4|       XXXXXXX\n//\t    3|     XXXXXXXXXXX\n//\t    2|   XXXXXXXXXXXXXXX\n//\t    1| XXXXXXXXXXXXXXXXXXX\n//\t    0------------------------> time(s)\n//\t      01234567890123456789012   (t%10)\n//\t      00000000001111111111222   (t/10)\n//\n// And the chart for the other execution segment would look like this:\n//\n//\tVUs  ^\n//\t    5|          Y\n//\t    4|        YYYYY\n//\t    3|      YYYYYYYYY\n//\t    2|    YYYYYYYYYYYYY\n//\t    1|  YYYYYYYYYYYYYYYYY\n//\t    0------------------------> time(s)\n//\t      01234567890123456789012   (t%10)\n//\t      00000000001111111111222   (t/10)\n//\n// Notice the time offsets and the slower ramping up and down. All of that is\n// because the sum of the two execution segments has to produce exactly the\n// original shape, as if the test ran on a single machine:\n//\n//\tVUs  ^\n//\t   10|          Y\n//\t    9|         XXX\n//\t    8|        YYYYY\n//\t    7|       XXXXXXX\n//\t    6|      YYYYYYYYY\n//\t    5|     XXXXXXXXXXX\n//\t    4|    YYYYYYYYYYYYY\n//\t    3|   XXXXXXXXXXXXXXX\n//\t    2|  YYYYYYYYYYYYYYYYY\n//\t    1| XXXXXXXXXXXXXXXXXXX\n//\t    0------------------------> time(s)\n//\t      01234567890123456789012   (t%10)\n//\t      00000000001111111111222   (t/10)\n//\n// More information: https://github.com/k6io/k6/issues/997#issuecomment-484416866\nfunc (vlvc RampingVUsConfig) getRawExecutionSteps(et *lib.ExecutionTuple, zeroEnd bool) []lib.ExecutionStep {\n\tvar (\n\t\ttimeTillEnd time.Duration\n\t\tfromVUs     = vlvc.StartVUs.Int64\n\t\tsteps       = make([]lib.ExecutionStep, 0, vlvc.precalculateTheRequiredSteps(et, zeroEnd))\n\t\tindex       = lib.NewSegmentedIndex(et)\n\t)\n\n\t// Reserve the scaled StartVUs at the beginning\n\tscaled, unscaled := index.GoTo(fromVUs)\n\tsteps = append(steps, lib.ExecutionStep{TimeOffset: 0, PlannedVUs: uint64(scaled)}) //nolint:gosec\n\taddStep := func(timeOffset time.Duration, plannedVUs uint64) {\n\t\tif steps[len(steps)-1].PlannedVUs != plannedVUs {\n\t\t\tsteps = append(steps, lib.ExecutionStep{TimeOffset: timeOffset, PlannedVUs: plannedVUs})\n\t\t}\n\t}\n\n\tfor _, stage := range vlvc.Stages {\n\t\tstageEndVUs := stage.Target.Int64\n\t\tstageDuration := stage.Duration.TimeDuration()\n\t\ttimeTillEnd += stageDuration\n\n\t\tstageVUDiff := stageEndVUs - fromVUs\n\t\tif stageVUDiff == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif stageDuration == 0 {\n\t\t\tscaled, unscaled = index.GoTo(stageEndVUs)\n\t\t\taddStep(timeTillEnd, uint64(scaled)) //nolint:gosec\n\t\t\tfromVUs = stageEndVUs\n\t\t\tcontinue\n\t\t}\n\n\t\t// VU reservation for gracefully ramping down is handled as a\n\t\t// separate method: reserveVUsForGracefulRampDowns()\n\t\tif unscaled > stageEndVUs { // ramp down\n\t\t\t// here we don't want to emit for the equal to stageEndVUs as it doesn't go below it\n\t\t\t// it will just go to it\n\t\t\tfor ; unscaled > stageEndVUs; scaled, unscaled = index.Prev() {\n\t\t\t\taddStep(\n\t\t\t\t\t// this is the time that we should go up 1 if we are ramping up\n\t\t\t\t\t// but we are ramping down so we should go 1 down, but because we want to not\n\t\t\t\t\t// stop VUs immediately we stop it on the next unscaled VU's time\n\t\t\t\t\ttimeTillEnd-time.Duration(int64(stageDuration)*(stageEndVUs-unscaled+1)/stageVUDiff),\n\t\t\t\t\tuint64(scaled-1), //nolint:gosec\n\t\t\t\t)\n\t\t\t}\n\t\t} else {\n\t\t\tfor ; unscaled <= stageEndVUs; scaled, unscaled = index.Next() {\n\t\t\t\taddStep(\n\t\t\t\t\ttimeTillEnd-time.Duration(int64(stageDuration)*(stageEndVUs-unscaled)/stageVUDiff),\n\t\t\t\t\tuint64(scaled), //nolint:gosec\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tfromVUs = stageEndVUs\n\t}\n\n\tif zeroEnd && steps[len(steps)-1].PlannedVUs != 0 {\n\t\t// If the last PlannedVUs value wasn't 0, add a last step with 0\n\t\tsteps = append(steps, lib.ExecutionStep{TimeOffset: timeTillEnd, PlannedVUs: 0})\n\t}\n\treturn steps\n}\n\nfunc absInt64(a int64) int64 {\n\tif a < 0 {\n\t\treturn -a\n\t}\n\treturn a\n}\n\nfunc (vlvc RampingVUsConfig) precalculateTheRequiredSteps(et *lib.ExecutionTuple, zeroEnd bool) int {\n\tp := et.ScaleInt64(vlvc.StartVUs.Int64)\n\tvar result int64\n\tresult++ // for the first one\n\n\tif zeroEnd {\n\t\tresult++ // for the last one - this one can be more then needed\n\t}\n\tfor _, stage := range vlvc.Stages {\n\t\tstageEndVUs := et.ScaleInt64(stage.Target.Int64)\n\t\tif stage.Duration.Duration == 0 {\n\t\t\tresult++\n\t\t} else {\n\t\t\tresult += absInt64(p - stageEndVUs)\n\t\t}\n\t\tp = stageEndVUs\n\t}\n\treturn int(result)\n}\n\n// If the graceful ramp-downs are enabled, we need to reserve any VUs that may\n// potentially have to finish running iterations when we're scaling their number\n// down. This would prevent attempts from other executors to use them while the\n// iterations are finishing up during their allotted gracefulRampDown periods.\n//\n// But we also need to be careful to not over-allocate more VUs than we actually\n// need. We should never have more PlannedVUs than the max(startVUs,\n// stage[n].target), even if we're quickly scaling VUs up and down multiple\n// times, one after the other. In those cases, any previously reserved VUs\n// finishing up interrupted iterations should be reused by the executor,\n// instead of new ones being requested from the execution state.\n//\n// Here's an example with graceful ramp-down (i.e. \"uninterruptible\"\n// iterations), where stars represent actively scheduled VUs and dots are used\n// for VUs that are potentially finishing up iterations:\n//\n//\tVUs ^\n//\t    |\n//\t   6|  *..............................\n//\t   5| ***.......*..............................\n//\t   4|*****.....***.....**..............................\n//\t   3|******...*****...***..............................\n//\t   2|*******.*******.****..............................\n//\t   1|***********************..............................\n//\t   0--------------------------------------------------------> time(s)\n//\t     012345678901234567890123456789012345678901234567890123   (t%10)\n//\t     000000000011111111112222222222333333333344444444445555   (t/10)\n//\n// We start with 4 VUs, scale to 6, scale down to 1, scale up to 5, scale down\n// to 1 again, scale up to 4, back to 1, and finally back down to 0. If our\n// gracefulStop timeout was 30s (the default), then we'll stay with 6 PlannedVUs\n// until t=32 in the test above, and the actual executor could run until t=52.\n// See TestRampingVUsConfigExecutionPlanExample() for the above example\n// as a unit test.\n//\n// The algorithm we use below to reserve VUs so that ramping-down VUs can finish\n// their last iterations is pretty simple. It just traverses the raw execution\n// steps and whenever there's a scaling down of VUs, it prevents the number of\n// VUs from decreasing for the configured gracefulRampDown period.\n//\n// Finishing up the test, i.e. making sure we have a step with 0 VUs at time\n// executorEndOffset, is not handled here. Instead GetExecutionRequirements()\n// takes care of that. But to make its job easier, this method won't add any\n// steps with an offset that's greater or equal to executorEndOffset.\nfunc (vlvc RampingVUsConfig) reserveVUsForGracefulRampDowns(\n\trawSteps []lib.ExecutionStep, executorEndOffset time.Duration,\n) []lib.ExecutionStep {\n\trawStepsLen := len(rawSteps)\n\tgracefulRampDownPeriod := vlvc.GetGracefulRampDown()\n\tnewSteps := []lib.ExecutionStep{}\n\n\tlastPlannedVUs := uint64(0)\n\tlastDownwardSlopeStepNum := 0\n\tfor rawStepNum := 0; rawStepNum < rawStepsLen; rawStepNum++ {\n\t\trawStep := rawSteps[rawStepNum]\n\t\t// Add the first step or any step where the number of planned VUs is\n\t\t// greater than the ones in the previous step. We don't need to worry\n\t\t// about reserving time for ramping-down VUs when the number of planned\n\t\t// VUs is growing. That's because the gracefulRampDown period is a fixed\n\t\t// value and any timeouts from early steps with fewer VUs will get\n\t\t// overshadowed by timeouts from latter steps with more VUs.\n\t\tif rawStepNum == 0 || rawStep.PlannedVUs > lastPlannedVUs {\n\t\t\tnewSteps = append(newSteps, rawStep)\n\t\t\tlastPlannedVUs = rawStep.PlannedVUs\n\t\t\tcontinue\n\t\t}\n\n\t\t// We simply skip steps with the same number of planned VUs\n\t\tif rawStep.PlannedVUs == lastPlannedVUs {\n\t\t\tcontinue\n\t\t}\n\n\t\t// If we're here, we have a downward \"slope\" - the lastPlannedVUs are\n\t\t// more than the current rawStep's planned VUs. We're going to look\n\t\t// forward in time (up to gracefulRampDown) and inspect the rawSteps.\n\t\t// There are a 3 possibilities:\n\t\t//  - We find a new step within the gracefulRampDown period which has\n\t\t//    the same number of VUs or greater than lastPlannedVUs. Which\n\t\t//    means that we can just advance rawStepNum to that number and we\n\t\t//    don't need to worry about any of the raw steps in the middle!\n\t\t//    Both their planned VUs and their gracefulRampDown periods will\n\t\t//    be lower than what we're going to set from that new rawStep -\n\t\t//    we've basically found a new upward slope or equal value again.\n\t\t//  - We reach executorEndOffset, in which case we are done - we can't\n\t\t//    add any new steps, since those will be after the executor end\n\t\t//    offset.\n\t\t//  - We reach the end of the rawSteps, or we don't find any higher or\n\t\t//    equal steps to prevStep in the next gracefulRampDown period. So\n\t\t//    we'll simply add a new entry into newSteps with the values\n\t\t//    {timeOffsetWithTimeout, rawStep.PlannedVUs}, in which\n\t\t//    timeOffsetWithTimeout = (prevStep.TimeOffset + gracefulRampDown),\n\t\t//    after which we'll continue with traversing the following rawSteps.\n\t\t//\n\t\t//  In this last case, we can also keep track of the downward slope. We\n\t\t//  can save the last index we've seen, to optimize future lookaheads by\n\t\t//  starting them from the furhest downward slope step index we've seen so\n\t\t//  far. This can be done because the gracefulRampDown is constant, so\n\t\t//  when we're on a downward slope, raw steps will always fall in the\n\t\t//  gracefulRampDown \"shadow\" of their preceding steps on the slope.\n\n\t\tskippedToNewRawStep := false\n\t\ttimeOffsetWithTimeout := rawStep.TimeOffset + gracefulRampDownPeriod\n\n\t\tadvStepStart := max(lastDownwardSlopeStepNum, rawStepNum+1)\n\n\t\twasRampingDown := true\n\t\tfor advStepNum := advStepStart; advStepNum < rawStepsLen; advStepNum++ {\n\t\t\tadvStep := rawSteps[advStepNum]\n\t\t\tif advStep.TimeOffset > timeOffsetWithTimeout {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif advStep.PlannedVUs >= lastPlannedVUs {\n\t\t\t\trawStepNum = advStepNum - 1\n\t\t\t\tskippedToNewRawStep = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif wasRampingDown {\n\t\t\t\tif rawSteps[advStepNum-1].PlannedVUs > advStep.PlannedVUs {\n\t\t\t\t\t// Still ramping down\n\t\t\t\t\tlastDownwardSlopeStepNum = advStepNum\n\t\t\t\t} else {\n\t\t\t\t\t// No longer ramping down\n\t\t\t\t\twasRampingDown = false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Nothing more to do here, found a new \"slope\" with equal or grater\n\t\t// PlannedVUs in the gracefulRampDownPeriod window, so we go to it.\n\t\tif skippedToNewRawStep {\n\t\t\tcontinue\n\t\t}\n\n\t\t// We've reached the absolute executor end offset, and we were already\n\t\t// on a downward \"slope\" (i.e. the previous planned VUs are more than\n\t\t// the current planned VUs), so nothing more we can do here.\n\t\tif timeOffsetWithTimeout >= executorEndOffset {\n\t\t\tbreak\n\t\t}\n\n\t\tnewSteps = append(newSteps, lib.ExecutionStep{\n\t\t\tTimeOffset: timeOffsetWithTimeout,\n\t\t\tPlannedVUs: rawStep.PlannedVUs,\n\t\t})\n\t\tlastPlannedVUs = rawStep.PlannedVUs\n\t}\n\n\treturn newSteps\n}\n\n// GetExecutionRequirements very dynamically reserves exactly the number of\n// required VUs for this executor at every moment of the test.\n//\n// If gracefulRampDown is specified, it will also be taken into account, and the\n// number of needed VUs to handle that will also be reserved. See the\n// documentation of reserveVUsForGracefulRampDowns() for more details.\n//\n// On the other hand, gracefulStop is handled here. To facilitate it, we'll\n// ensure that the last execution step will have 0 VUs and will be at time\n// offset (sum(stages.Duration)+gracefulStop). Any steps that would've been\n// added after it will be ignored. Thus:\n//   - gracefulStop can be less than gracefulRampDown and can cut the graceful\n//     ramp-down periods of the last VUs short.\n//   - gracefulRampDown can be more than gracefulStop:\n//   - If the user manually ramped down VUs at the end of the test (i.e. the\n//     last stage's target is 0), then this will have no effect.\n//   - If the last stage's target is more than 0, the VUs at the end of the\n//     executor's life will have more time to finish their last iterations.\nfunc (vlvc RampingVUsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {\n\tsteps := vlvc.getRawExecutionSteps(et, false)\n\n\texecutorEndOffset := sumStagesDuration(vlvc.Stages) + vlvc.GracefulStop.TimeDuration()\n\t// Handle graceful ramp-downs, if we have them\n\tif vlvc.GracefulRampDown.Duration > 0 {\n\t\tsteps = vlvc.reserveVUsForGracefulRampDowns(steps, executorEndOffset)\n\t}\n\n\t// If the last PlannedVUs value wasn't 0, add a last step with 0\n\tif steps[len(steps)-1].PlannedVUs != 0 {\n\t\tsteps = append(steps, lib.ExecutionStep{TimeOffset: executorEndOffset, PlannedVUs: 0})\n\t}\n\n\treturn steps\n}\n\n// NewExecutor creates a new RampingVUs executor\nfunc (vlvc RampingVUsConfig) NewExecutor(es *lib.ExecutionState, logger *logrus.Entry) (lib.Executor, error) {\n\treturn &RampingVUs{\n\t\tBaseExecutor: NewBaseExecutor(vlvc, es, logger),\n\t\tconfig:       vlvc,\n\t}, nil\n}\n\n// HasWork reports whether there is any work to be done for the given execution segment.\nfunc (vlvc RampingVUsConfig) HasWork(et *lib.ExecutionTuple) bool {\n\treturn lib.GetMaxPlannedVUs(vlvc.GetExecutionRequirements(et)) > 0\n}\n\n// RampingVUs handles the old \"stages\" execution configuration - it loops\n// iterations with a variable number of VUs for the sum of all of the specified\n// stages' duration.\ntype RampingVUs struct {\n\t*BaseExecutor\n\tconfig RampingVUsConfig\n\n\trawSteps, gracefulSteps []lib.ExecutionStep\n}\n\n// Make sure we implement the lib.Executor interface.\nvar _ lib.Executor = &RampingVUs{}\n\n// Init initializes the rampingVUs executor by precalculating the raw\n// and graceful steps.\nfunc (vlv *RampingVUs) Init(_ context.Context) error {\n\tvlv.rawSteps = vlv.config.getRawExecutionSteps(\n\t\tvlv.executionState.ExecutionTuple, true,\n\t)\n\tvlv.gracefulSteps = vlv.config.GetExecutionRequirements(\n\t\tvlv.executionState.ExecutionTuple,\n\t)\n\treturn nil\n}\n\n// Run constantly loops through as many iterations as possible on a variable\n// number of VUs for the specified stages.\nfunc (vlv *RampingVUs) Run(ctx context.Context, _ chan<- metrics.SampleContainer) error {\n\tregularDuration, isFinal := lib.GetEndOffset(vlv.rawSteps)\n\tif !isFinal {\n\t\treturn fmt.Errorf(\"%s expected raw end offset at %s to be final\", vlv.config.GetName(), regularDuration)\n\t}\n\tmaxDuration, isFinal := lib.GetEndOffset(vlv.gracefulSteps)\n\tif !isFinal {\n\t\treturn fmt.Errorf(\"%s expected graceful end offset at %s to be final\", vlv.config.GetName(), maxDuration)\n\t}\n\twaitOnProgressChannel := make(chan struct{})\n\tstartTime, maxDurationCtx, regularDurationCtx, cancel := getDurationContexts(\n\t\tctx, regularDuration, maxDuration-regularDuration,\n\t)\n\tdefer func() {\n\t\tcancel()\n\t\t<-waitOnProgressChannel\n\t}()\n\n\tmaxVUs := lib.GetMaxPlannedVUs(vlv.gracefulSteps)\n\n\tvlv.logger.WithFields(logrus.Fields{\n\t\t\"type\":      vlv.config.GetType(),\n\t\t\"startVUs\":  vlv.config.GetStartVUs(vlv.executionState.ExecutionTuple),\n\t\t\"maxVUs\":    maxVUs,\n\t\t\"duration\":  regularDuration,\n\t\t\"numStages\": len(vlv.config.Stages),\n\t}).Debug(\"Starting executor run...\")\n\n\trunState := &rampingVUsRunState{\n\t\texecutor:       vlv,\n\t\tvuHandles:      make([]*vuHandle, maxVUs),\n\t\tmaxVUs:         maxVUs,\n\t\tactiveVUsCount: new(int64),\n\t\tstarted:        startTime,\n\t\trunIteration:   getIterationRunner(vlv.executionState, vlv.logger),\n\t}\n\n\tprogressFn := runState.makeProgressFn(regularDuration)\n\tmaxDurationCtx = lib.WithScenarioState(maxDurationCtx, &lib.ScenarioState{\n\t\tName:       vlv.config.Name,\n\t\tExecutor:   vlv.config.Type,\n\t\tStartTime:  runState.started,\n\t\tProgressFn: progressFn,\n\t})\n\tvlv.progress.Modify(pb.WithProgress(progressFn))\n\tgo func() {\n\t\ttrackProgress(ctx, maxDurationCtx, regularDurationCtx, vlv, progressFn)\n\t\tclose(waitOnProgressChannel)\n\t}()\n\tdefer runState.wg.Wait()\n\t// this will populate stopped VUs and run runLoopsIfPossible on each VU\n\t// handle in a new goroutine\n\trunState.runLoopsIfPossible(maxDurationCtx, cancel)\n\n\tvar (\n\t\thandleNewMaxAllowedVUs = runState.maxAllowedVUsHandlerStrategy()\n\t\thandleNewScheduledVUs  = runState.scheduledVUsHandlerStrategy()\n\t)\n\thandledGracefulSteps := runState.iterateSteps(\n\t\tctx,\n\t\thandleNewMaxAllowedVUs,\n\t\thandleNewScheduledVUs,\n\t)\n\tgo runState.runRemainingGracefulSteps(\n\t\tctx,\n\t\thandleNewMaxAllowedVUs,\n\t\thandledGracefulSteps,\n\t)\n\treturn nil\n}\n\n// rampingVUsRunState is created and initialized by the Run() method\n// of the ramping VUs executor. It is used to track and modify various\n// details of the execution.\ntype rampingVUsRunState struct {\n\texecutor       *RampingVUs\n\tvuHandles      []*vuHandle // handles for manipulating and tracking all of the VUs\n\tmaxVUs         uint64      // the scaled number of initially configured MaxVUs\n\tactiveVUsCount *int64      // the current number of active VUs, used only for the progress display\n\tstarted        time.Time\n\twg             sync.WaitGroup\n\n\trunIteration func(context.Context, lib.ActiveVU) bool // a helper closure function that runs a single iteration\n}\n\nfunc (rs *rampingVUsRunState) makeProgressFn(regular time.Duration) (progressFn func() (float64, []string)) {\n\tvusFmt := pb.GetFixedLengthIntFormat(int64(rs.maxVUs)) //nolint:gosec\n\tregularDuration := pb.GetFixedLengthDuration(regular, regular)\n\n\treturn func() (float64, []string) {\n\t\tspent := time.Since(rs.started)\n\t\tcur := atomic.LoadInt64(rs.activeVUsCount)\n\t\tprogVUs := fmt.Sprintf(vusFmt+\"/\"+vusFmt+\" VUs\", cur, rs.maxVUs)\n\t\tif spent > regular {\n\t\t\treturn 1, []string{progVUs, regular.String()}\n\t\t}\n\t\tstatus := pb.GetFixedLengthDuration(spent, regular) + \"/\" + regularDuration\n\t\treturn float64(spent) / float64(regular), []string{progVUs, status}\n\t}\n}\n\nfunc (rs *rampingVUsRunState) runLoopsIfPossible(ctx context.Context, cancel func()) {\n\tgetVU := func() (lib.InitializedVU, error) {\n\t\tpvu, err := rs.executor.executionState.GetPlannedVU(rs.executor.logger, false)\n\t\tif err != nil {\n\t\t\trs.executor.logger.WithError(err).Error(\"Cannot get a VU from the buffer\")\n\t\t\tcancel()\n\t\t\treturn pvu, err\n\t\t}\n\t\trs.wg.Add(1)\n\t\tatomic.AddInt64(rs.activeVUsCount, 1)\n\t\trs.executor.executionState.ModCurrentlyActiveVUsCount(+1)\n\t\treturn pvu, err\n\t}\n\treturnVU := func(initVU lib.InitializedVU) {\n\t\trs.executor.executionState.ReturnVU(initVU, false)\n\t\tatomic.AddInt64(rs.activeVUsCount, -1)\n\t\trs.wg.Done()\n\t\trs.executor.executionState.ModCurrentlyActiveVUsCount(-1)\n\t}\n\tfor i := uint64(0); i < rs.maxVUs; i++ {\n\t\trs.vuHandles[i] = newStoppedVUHandle(\n\t\t\tctx, getVU, returnVU, rs.executor.nextIterationCounters,\n\t\t\t&rs.executor.config.BaseConfig, rs.executor.logger.WithField(\"vuNum\", i))\n\t\tgo rs.vuHandles[i].runLoopsIfPossible(rs.runIteration) //nolint:contextcheck\n\t}\n}\n\n// iterateSteps iterates over rawSteps and gracefulSteps in order according to\n// their TimeOffsets, prioritizing rawSteps. It stops iterating once rawSteps\n// are over. And it returns the number of handled gracefulSteps.\nfunc (rs *rampingVUsRunState) iterateSteps(\n\tctx context.Context,\n\thandleNewMaxAllowedVUs, handleNewScheduledVUs func(lib.ExecutionStep),\n) (handledGracefulSteps int) {\n\twait := waiter(ctx, rs.started)\n\ti, j := 0, 0\n\tfor i != len(rs.executor.rawSteps) {\n\t\tr, g := rs.executor.rawSteps[i], rs.executor.gracefulSteps[j]\n\t\tif g.TimeOffset < r.TimeOffset {\n\t\t\tif wait(g.TimeOffset) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\thandleNewMaxAllowedVUs(g)\n\t\t\tj++\n\t\t} else {\n\t\t\tif wait(r.TimeOffset) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\thandleNewScheduledVUs(r)\n\t\t\ti++\n\t\t}\n\t}\n\treturn j\n}\n\n// runRemainingGracefulSteps runs the remaining gracefulSteps concurrently\n// before the gracefulStop timeout period stops VUs.\n//\n// This way we will have run the gracefulSteps at the same time while\n// waiting for the VUs to finish.\n//\n// (gracefulStop = maxDuration-regularDuration)\nfunc (rs *rampingVUsRunState) runRemainingGracefulSteps(\n\tctx context.Context,\n\thandleNewMaxAllowedVUs func(lib.ExecutionStep),\n\thandledGracefulSteps int,\n) {\n\twait := waiter(ctx, rs.started)\n\tfor _, s := range rs.executor.gracefulSteps[handledGracefulSteps:] {\n\t\tif wait(s.TimeOffset) {\n\t\t\treturn\n\t\t}\n\t\thandleNewMaxAllowedVUs(s)\n\t}\n}\n\nfunc (rs *rampingVUsRunState) maxAllowedVUsHandlerStrategy() func(lib.ExecutionStep) {\n\tvar cur uint64 // current number of planned graceful VUs\n\treturn func(graceful lib.ExecutionStep) {\n\t\tpv := graceful.PlannedVUs\n\t\tfor ; pv < cur; cur-- {\n\t\t\trs.vuHandles[cur-1].hardStop()\n\t\t}\n\t\tcur = pv\n\t}\n}\n\nfunc (rs *rampingVUsRunState) scheduledVUsHandlerStrategy() func(lib.ExecutionStep) {\n\tvar cur uint64 // current number of planned raw VUs\n\treturn func(raw lib.ExecutionStep) {\n\t\tpv := raw.PlannedVUs\n\t\tfor ; cur < pv; cur++ {\n\t\t\t_ = rs.vuHandles[cur].start() // TODO: handle the error\n\t\t}\n\t\tfor ; pv < cur; cur-- {\n\t\t\trs.vuHandles[cur-1].gracefulStop()\n\t\t}\n\t}\n}\n\n// waiter returns a function that will sleep/wait for the required time since the startTime and then\n// return. If the context was done before that it will return true otherwise it will return false\n// TODO use elsewhere\n// TODO set start here?\n// TODO move it to a struct type or something and benchmark if that makes a difference\nfunc waiter(ctx context.Context, start time.Time) func(offset time.Duration) bool {\n\ttimer := time.NewTimer(time.Hour * 24)\n\treturn func(offset time.Duration) bool {\n\t\tdiff := offset - time.Since(start)\n\t\tif diff > 0 { // wait until time of event arrives // TODO have a mininum\n\t\t\ttimer.Reset(diff)\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn true // exit if context is cancelled\n\t\t\tcase <-timer.C:\n\t\t\t\t// now we do a step\n\t\t\t}\n\t\t}\n\t\treturn false\n\t}\n}\n\n// validateTargetShifts validates the VU Target shifts.\n// It will append an error for any VU target that is larger than the maximum value allowed.\n// Each Stage needs a Target value. The stages array can be empty. The Targes could be negative.\n//\n// TODO: after https://github.com/grafana/k6/issues/1499 this validation\n// function could be useless.\nfunc validateTargetShifts(startVUs int64, stages []Stage) []error {\n\tvar errors []error\n\n\tif startVUs > int64(maxConcurrentVUs) {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the startVUs exceed max limit of %d\", maxConcurrentVUs))\n\t}\n\n\tfor i := range stages {\n\t\tif stages[i].Target.Int64 > int64(maxConcurrentVUs) {\n\t\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\t\"target for stage %d exceeds max limit of %d\", i+1, maxConcurrentVUs))\n\t\t}\n\t}\n\n\treturn errors\n}\n"
  },
  {
    "path": "lib/executor/ramping_vus_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"math/rand\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestRampingVUsConfigValidation(t *testing.T) {\n\tt.Parallel()\n\tconst maxConcurrentVUs = 100_000_000\n\n\tt.Run(\"no stages\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\terrs := NewRampingVUsConfig(\"default\").Validate()\n\t\trequire.NotEmpty(t, errs)\n\t\tassert.Contains(t, errs[0].Error(), \"one stage has to be specified\")\n\t})\n\tt.Run(\"basic 1 stage\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := NewRampingVUsConfig(\"stage\")\n\t\tc.Stages = []Stage{\n\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(12 * time.Second)},\n\t\t}\n\t\terrs := c.Validate()\n\t\trequire.Empty(t, errs) // by default StartVUs is 1\n\n\t\tc.StartVUs = null.IntFrom(0)\n\t\terrs = c.Validate()\n\t\trequire.NotEmpty(t, errs)\n\t\tassert.Contains(t, errs[0].Error(), \"greater than 0\")\n\t})\n\n\tt.Run(\"If startVUs are larger than maxConcurrentVUs, the validation should return an error\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tc := NewRampingVUsConfig(\"stage\")\n\t\tc.StartVUs = null.IntFrom(maxConcurrentVUs + 1)\n\t\tc.Stages = []Stage{\n\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(1 * time.Second)},\n\t\t}\n\n\t\terrs := c.Validate()\n\t\trequire.NotEmpty(t, errs)\n\t\tassert.Contains(t, errs[0].Error(), \"the startVUs exceed max limit of\")\n\t})\n\n\tt.Run(\"For multiple VU values larger than maxConcurrentVUs, multiple errors are returned\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tc := NewRampingVUsConfig(\"stage\")\n\t\tc.StartVUs = null.IntFrom(maxConcurrentVUs + 1)\n\t\tc.Stages = []Stage{\n\t\t\t{Target: null.IntFrom(maxConcurrentVUs + 2), Duration: types.NullDurationFrom(1 * time.Second)},\n\t\t}\n\n\t\terrs := c.Validate()\n\t\trequire.Len(t, errs, 2)\n\t\tassert.Contains(t, errs[0].Error(), \"the startVUs exceed max limit of\")\n\n\t\tassert.Contains(t, errs[1].Error(), \"target for stage 1 exceeds max limit of\")\n\t})\n\n\tt.Run(\"VU values below maxConcurrentVUs will pass validation\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tc := NewRampingVUsConfig(\"stage\")\n\t\tc.StartVUs = null.IntFrom(0)\n\t\tc.Stages = []Stage{\n\t\t\t{Target: null.IntFrom(maxConcurrentVUs - 1), Duration: types.NullDurationFrom(1 * time.Second)},\n\t\t}\n\n\t\terrs := c.Validate()\n\t\trequire.Empty(t, errs)\n\t})\n}\n\nfunc TestRampingVUsRun(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := RampingVUsConfig{\n\t\tBaseConfig:       BaseConfig{GracefulStop: types.NullDurationFrom(0)},\n\t\tGracefulRampDown: types.NullDurationFrom(0),\n\t\tStartVUs:         null.IntFrom(5),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(5),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(0),\n\t\t\t\tTarget:   null.IntFrom(3),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(3),\n\t\t\t},\n\t\t},\n\t}\n\n\tvar iterCount int64\n\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\t// Sleeping for a weird duration somewhat offset from the\n\t\t// executor ticks to hopefully keep race conditions out of\n\t\t// our control from failing the test.\n\t\ttime.Sleep(300 * time.Millisecond)\n\t\tatomic.AddInt64(&iterCount, 1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tsampleTimes := []time.Duration{\n\t\t500 * time.Millisecond,\n\t\t1000 * time.Millisecond,\n\t\t900 * time.Millisecond,\n\t}\n\n\terrCh := make(chan error)\n\tgo func() { errCh <- test.executor.Run(test.ctx, nil) }()\n\n\tresult := make([]int64, len(sampleTimes))\n\tfor i, d := range sampleTimes {\n\t\ttime.Sleep(d)\n\t\tresult[i] = test.state.GetCurrentlyActiveVUsCount()\n\t}\n\n\trequire.NoError(t, <-errCh)\n\n\tassert.Equal(t, []int64{5, 3, 0}, result)\n\tassert.Equal(t, int64(29), atomic.LoadInt64(&iterCount))\n}\n\nfunc TestRampingVUsGracefulStopWaits(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := RampingVUsConfig{\n\t\tBaseConfig: BaseConfig{GracefulStop: types.NullDurationFrom(time.Second)},\n\t\tStartVUs:   null.IntFrom(1),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(1),\n\t\t\t},\n\t\t},\n\t}\n\n\tvar (\n\t\tstarted = make(chan struct{}) // the iteration started\n\t\tstopped = make(chan struct{}) // the iteration stopped\n\t\tstop    = make(chan struct{}) // the itearation should stop\n\t)\n\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\tclose(started)\n\t\tdefer close(stopped)\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\tt.Fatal(\"The iterations should've ended before the context\")\n\t\tcase <-stop:\n\t\t}\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\terrCh := make(chan error)\n\tgo func() { errCh <- test.executor.Run(test.ctx, nil) }()\n\n\t<-started\n\t// 500 milliseconds more then the duration and 500 less then the gracefulStop\n\ttime.Sleep(time.Millisecond * 1500)\n\tclose(stop)\n\t<-stopped\n\n\trequire.NoError(t, <-errCh)\n}\n\nfunc TestRampingVUsGracefulStopStops(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := RampingVUsConfig{\n\t\tBaseConfig: BaseConfig{GracefulStop: types.NullDurationFrom(time.Second)},\n\t\tStartVUs:   null.IntFrom(1),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(1),\n\t\t\t},\n\t\t},\n\t}\n\n\tvar (\n\t\tstarted = make(chan struct{}) // the iteration started\n\t\tstopped = make(chan struct{}) // the iteration stopped\n\t\tstop    = make(chan struct{}) // the itearation should stop\n\t)\n\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\tclose(started)\n\t\tdefer close(stopped)\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\tcase <-stop:\n\t\t\tt.Fatal(\"The iterations shouldn't have ended before the context\")\n\t\t}\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\terrCh := make(chan error)\n\tgo func() { errCh <- test.executor.Run(test.ctx, nil) }()\n\n\t<-started\n\t// 500 milliseconds more then the gracefulStop + duration\n\ttime.Sleep(time.Millisecond * 2500)\n\tclose(stop)\n\t<-stopped\n\n\trequire.NoError(t, <-errCh)\n}\n\nfunc TestRampingVUsGracefulRampDown(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := RampingVUsConfig{\n\t\tBaseConfig:       BaseConfig{GracefulStop: types.NullDurationFrom(5 * time.Second)},\n\t\tStartVUs:         null.IntFrom(2),\n\t\tGracefulRampDown: types.NullDurationFrom(5 * time.Second),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(2),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(0),\n\t\t\t},\n\t\t},\n\t}\n\n\tvar (\n\t\tstarted = make(chan struct{}) // the iteration started\n\t\tstopped = make(chan struct{}) // the iteration stopped\n\t\tstop    = make(chan struct{}) // the itearation should stop\n\t)\n\n\trunner := simpleRunner(func(ctx context.Context, state *lib.State) error {\n\t\tif state.VUID == 1 { // the first VU will wait here to do stuff\n\t\t\tclose(started)\n\t\t\tdefer close(stopped)\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\tt.Fatal(\"The iterations can't have ended before the context\")\n\t\t\tcase <-stop:\n\t\t\t}\n\t\t} else { // all other (1) VUs will just sleep long enough\n\t\t\ttime.Sleep(2500 * time.Millisecond)\n\t\t}\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\terrCh := make(chan error)\n\tgo func() { errCh <- test.executor.Run(test.ctx, nil) }()\n\n\t<-started\n\t// 500 milliseconds more then the gracefulRampDown + duration\n\ttime.Sleep(2500 * time.Millisecond)\n\tclose(stop)\n\t<-stopped\n\n\tselect {\n\tcase err := <-errCh:\n\t\trequire.NoError(t, err)\n\tcase <-time.After(time.Second): // way too much time\n\t\tt.Fatal(\"Execution should've ended already\")\n\t}\n}\n\n// This test aims to check whether the ramping VU executor interrupts\n// hanging/remaining VUs after the graceful rampdown period finishes.\n//\n//\t              Rampdown         Graceful Rampdown\n//\t              Stage (40ms)     (+30ms)\n//\t              [               ][              ]\n//\t    t 0---5---10---20---30---40---50---60---70\n//\tVU1       *..................................✔ (40+30=70ms)\n//\tVU2           *...................X            (20+30=50ms)\n//\n//\t✔=Finishes,X=Interrupted,.=Sleeps\nfunc TestRampingVUsHandleRemainingVUs(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\tmaxVus                   = 2\n\t\tvuSleepDuration          = 65 * time.Millisecond // Each VU will sleep 65ms\n\t\twantVuFinished    uint32 = 1                     // one VU should finish an iteration\n\t\twantVuInterrupted uint32 = 1                     // one VU should be interrupted\n\t)\n\n\tcfg := RampingVUsConfig{\n\t\tBaseConfig: BaseConfig{\n\t\t\t// Extend the total test duration 50ms more\n\t\t\t//\n\t\t\t// test duration = sum(stages) + GracefulStop\n\t\t\t//\n\t\t\t// This could have been 30ms but increased it to 50ms\n\t\t\t// to prevent the test to become flaky.\n\t\t\tGracefulStop: types.NullDurationFrom(50 * time.Millisecond),\n\t\t},\n\t\t// Wait 30ms more for already started iterations\n\t\t// (Happens in the 2nd stage below: Graceful rampdown period)\n\t\tGracefulRampDown: types.NullDurationFrom(30 * time.Millisecond),\n\t\t// Total test duration is 50ms (excluding the GracefulRampdown period)\n\t\tStages: []Stage{\n\t\t\t// Activate 2 VUs in 10ms\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(10 * time.Millisecond),\n\t\t\t\tTarget:   null.IntFrom(int64(maxVus)),\n\t\t\t},\n\t\t\t// Rampdown to 0 VUs in 40ms\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(40 * time.Millisecond),\n\t\t\t\tTarget:   null.IntFrom(int64(0)),\n\t\t\t},\n\t\t},\n\t}\n\n\tvar (\n\t\tgotVuInterrupted uint32\n\t\tgotVuFinished    uint32\n\t)\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\tselect {\n\t\tcase <-time.After(vuSleepDuration):\n\t\t\tatomic.AddUint32(&gotVuFinished, 1)\n\t\tcase <-ctx.Done():\n\t\t\tatomic.AddUint32(&gotVuInterrupted, 1)\n\t\t}\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, cfg)\n\tdefer test.cancel()\n\n\t// run the executor: this should finish in ~70ms\n\t// sum(stages) + GracefulRampDown\n\trequire.NoError(t, test.executor.Run(test.ctx, nil))\n\n\tassert.Equal(t, wantVuInterrupted, atomic.LoadUint32(&gotVuInterrupted))\n\tassert.Equal(t, wantVuFinished, atomic.LoadUint32(&gotVuFinished))\n}\n\n// Ensure there's no wobble of VUs during graceful ramp-down, without segments.\n// See https://github.com/k6io/k6/issues/1296\nfunc TestRampingVUsRampDownNoWobble(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := RampingVUsConfig{\n\t\tBaseConfig:       BaseConfig{GracefulStop: types.NullDurationFrom(0)},\n\t\tGracefulRampDown: types.NullDurationFrom(1 * time.Second),\n\t\tStartVUs:         null.IntFrom(0),\n\t\tStages: []Stage{\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(3 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(10),\n\t\t\t},\n\t\t\t{\n\t\t\t\tDuration: types.NullDurationFrom(2 * time.Second),\n\t\t\t\tTarget:   null.IntFrom(0),\n\t\t\t},\n\t\t},\n\t}\n\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tsampleTimes := []time.Duration{\n\t\t100 * time.Millisecond,\n\t\t3000 * time.Millisecond,\n\t}\n\tconst rampDownSampleTime = 50 * time.Millisecond\n\trampDownSamples := int((config.Stages[len(config.Stages)-1].Duration.TimeDuration() + config.GracefulRampDown.TimeDuration()) / rampDownSampleTime)\n\n\terrCh := make(chan error)\n\tgo func() { errCh <- test.executor.Run(test.ctx, nil) }()\n\n\tresult := make([]int64, len(sampleTimes)+rampDownSamples)\n\tfor i, d := range sampleTimes {\n\t\ttime.Sleep(d)\n\t\tresult[i] = test.state.GetCurrentlyActiveVUsCount()\n\t}\n\n\t// Sample ramp-down at a higher rate\n\tfor i := len(sampleTimes); i < rampDownSamples; i++ {\n\t\ttime.Sleep(rampDownSampleTime)\n\t\tresult[i] = test.state.GetCurrentlyActiveVUsCount()\n\t}\n\n\trequire.NoError(t, <-errCh)\n\n\t// Some baseline checks\n\tassert.Equal(t, int64(0), result[0])\n\tassert.Equal(t, int64(10), result[1])\n\tassert.Equal(t, int64(0), result[len(result)-1])\n\n\tvuChanges := []int64{result[2]}\n\t// Check ramp-down consistency\n\tfor i := 3; i < len(result[2:]); i++ {\n\t\tif result[i] != result[i-1] {\n\t\t\tvuChanges = append(vuChanges, result[i])\n\t\t}\n\t}\n\tassert.Equal(t, []int64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, vuChanges)\n}\n\nfunc TestRampingVUsConfigExecutionPlanExample(t *testing.T) {\n\tt.Parallel()\n\tet, err := lib.NewExecutionTuple(nil, nil)\n\trequire.NoError(t, err)\n\tconf := NewRampingVUsConfig(\"test\")\n\tconf.StartVUs = null.IntFrom(4)\n\tconf.Stages = []Stage{\n\t\t{Target: null.IntFrom(6), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(5 * time.Second)},\n\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(4 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(4 * time.Second)},\n\t\t{Target: null.IntFrom(4), Duration: types.NullDurationFrom(3 * time.Second)},\n\t\t{Target: null.IntFrom(4), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(0 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(3 * time.Second)},\n\t}\n\n\texpRawStepsNoZeroEnd := []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 6},\n\t\t{TimeOffset: 3 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 3},\n\t\t{TimeOffset: 6 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 9 * time.Second, PlannedVUs: 3},\n\t\t{TimeOffset: 10 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 13 * time.Second, PlannedVUs: 3},\n\t\t{TimeOffset: 14 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 17 * time.Second, PlannedVUs: 3},\n\t\t{TimeOffset: 18 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 1},\n\t}\n\trawStepsNoZeroEnd := conf.getRawExecutionSteps(et, false)\n\tassert.Equal(t, expRawStepsNoZeroEnd, rawStepsNoZeroEnd)\n\tendOffset, isFinal := lib.GetEndOffset(rawStepsNoZeroEnd)\n\tassert.Equal(t, 20*time.Second, endOffset)\n\tassert.Equal(t, false, isFinal)\n\n\trawStepsZeroEnd := conf.getRawExecutionSteps(et, true)\n\tassert.Equal(t,\n\t\tappend(expRawStepsNoZeroEnd, lib.ExecutionStep{TimeOffset: 23 * time.Second, PlannedVUs: 0}),\n\t\trawStepsZeroEnd,\n\t)\n\tendOffset, isFinal = lib.GetEndOffset(rawStepsZeroEnd)\n\tassert.Equal(t, 23*time.Second, endOffset)\n\tassert.Equal(t, true, isFinal)\n\n\t// GracefulStop and GracefulRampDown equal to the default 30 sec\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 6},\n\t\t{TimeOffset: 33 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 42 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 50 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 53 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a longer GracefulStop than the GracefulRampDown\n\tconf.GracefulStop = types.NullDurationFrom(80 * time.Second)\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 6},\n\t\t{TimeOffset: 33 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 42 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 50 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 103 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a much shorter GracefulStop than the GracefulRampDown\n\tconf.GracefulStop = types.NullDurationFrom(3 * time.Second)\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 6},\n\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a zero GracefulStop\n\tconf.GracefulStop = types.NullDurationFrom(0 * time.Second)\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 4},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 5},\n\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 6},\n\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a zero GracefulStop and GracefulRampDown, i.e. raw steps with 0 end cap\n\tconf.GracefulRampDown = types.NullDurationFrom(0 * time.Second)\n\tassert.Equal(t, rawStepsZeroEnd, conf.GetExecutionRequirements(et))\n}\n\nfunc TestRampingVUsConfigExecutionPlanExampleOneThird(t *testing.T) {\n\tt.Parallel()\n\tet, err := lib.NewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), nil)\n\trequire.NoError(t, err)\n\tconf := NewRampingVUsConfig(\"test\")\n\tconf.StartVUs = null.IntFrom(4)\n\tconf.Stages = []Stage{\n\t\t{Target: null.IntFrom(6), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(5 * time.Second)},\n\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(4 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(4 * time.Second)},\n\t\t{Target: null.IntFrom(4), Duration: types.NullDurationFrom(3 * time.Second)},\n\t\t{Target: null.IntFrom(4), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(0 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(3 * time.Second)},\n\t}\n\n\texpRawStepsNoZeroEnd := []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 0},\n\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 0},\n\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 0},\n\t}\n\trawStepsNoZeroEnd := conf.getRawExecutionSteps(et, false)\n\tassert.Equal(t, expRawStepsNoZeroEnd, rawStepsNoZeroEnd)\n\tendOffset, isFinal := lib.GetEndOffset(rawStepsNoZeroEnd)\n\tassert.Equal(t, 20*time.Second, endOffset)\n\tassert.Equal(t, true, isFinal)\n\n\trawStepsZeroEnd := conf.getRawExecutionSteps(et, true)\n\tassert.Equal(t, expRawStepsNoZeroEnd, rawStepsZeroEnd)\n\tendOffset, isFinal = lib.GetEndOffset(rawStepsZeroEnd)\n\tassert.Equal(t, 20*time.Second, endOffset)\n\tassert.Equal(t, true, isFinal)\n\n\t// GracefulStop and GracefulRampDown equal to the default 30 sec\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 42 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 50 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a longer GracefulStop than the GracefulRampDown\n\tconf.GracefulStop = types.NullDurationFrom(80 * time.Second)\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 42 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 50 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a much shorter GracefulStop than the GracefulRampDown\n\tconf.GracefulStop = types.NullDurationFrom(3 * time.Second)\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a zero GracefulStop\n\tconf.GracefulStop = types.NullDurationFrom(0 * time.Second)\n\tassert.Equal(t, []lib.ExecutionStep{\n\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 0},\n\t}, conf.GetExecutionRequirements(et))\n\n\t// Try a zero GracefulStop and GracefulRampDown, i.e. raw steps with 0 end cap\n\tconf.GracefulRampDown = types.NullDurationFrom(0 * time.Second)\n\tassert.Equal(t, rawStepsZeroEnd, conf.GetExecutionRequirements(et))\n}\n\nfunc TestRampingVUsExecutionTupleTests(t *testing.T) {\n\tt.Parallel()\n\n\tconf := NewRampingVUsConfig(\"test\")\n\tconf.StartVUs = null.IntFrom(4)\n\tconf.Stages = []Stage{\n\t\t{Target: null.IntFrom(6), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(5 * time.Second)},\n\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(4 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(4 * time.Second)},\n\t\t{Target: null.IntFrom(4), Duration: types.NullDurationFrom(3 * time.Second)},\n\t\t{Target: null.IntFrom(4), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(0 * time.Second)},\n\t\t{Target: null.IntFrom(1), Duration: types.NullDurationFrom(3 * time.Second)},\n\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(0 * time.Second)},\n\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(3 * time.Second)},\n\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(0 * time.Second)},\n\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t{Target: null.IntFrom(4), Duration: types.NullDurationFrom(4 * time.Second)},\n\t}\n\t/*\n\n\t\t\tGraph of the above:\n\t\t\t^\n\t\t8\t|\n\t\t7\t|\n\t\t6\t| +\n\t\t5\t|/ \\       +           +--+\n\t\t4\t+   \\     / \\     +-+  |  |       *\n\t\t3\t|    \\   /   \\   /  |  |  |      /\n\t\t2\t|     \\ /     \\ /   |  |  | +   /\n\t\t1\t|      +       +    +--+  |/ \\ /\n\t\t0\t+-------------------------+---+------------------------------>\n\t\t    01234567890123456789012345678901234567890\n\n\t*/\n\n\ttestCases := []struct {\n\t\texpectedSteps []lib.ExecutionStep\n\t\tet            *lib.ExecutionTuple\n\t}{\n\t\t{\n\t\t\tet: mustNewExecutionTuple(nil, nil),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 5},\n\t\t\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 6},\n\t\t\t\t{TimeOffset: 3 * time.Second, PlannedVUs: 5},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 6 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 9 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 10 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 5},\n\t\t\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 13 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 14 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 17 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 18 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 5},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 27 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 28 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 29 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 30 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 31 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 32 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 33 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 34 * time.Second, PlannedVUs: 4},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), nil),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 28 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 29 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 32 * time.Second, PlannedVUs: 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,1\")),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 28 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 29 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 32 * time.Second, PlannedVUs: 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"1/3:2/3\"), nil),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 28 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 29 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 32 * time.Second, PlannedVUs: 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"2/3:1\"), nil),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 28 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 29 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 32 * time.Second, PlannedVUs: 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\")),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 10 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 13 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 18 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 27 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 30 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 31 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 34 * time.Second, PlannedVUs: 2},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"1/3:2/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\")),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 12 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 16 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 28 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 29 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 32 * time.Second, PlannedVUs: 1},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"2/3:1\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\")),\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 3 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 6 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 9 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 14 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 17 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 20 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 26 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 33 * time.Second, PlannedVUs: 1},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tet := testCase.et\n\t\texpectedSteps := testCase.expectedSteps\n\n\t\tt.Run(et.String(), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trawStepsNoZeroEnd := conf.getRawExecutionSteps(et, false)\n\t\t\tassert.Equal(t, expectedSteps, rawStepsNoZeroEnd)\n\t\t})\n\t}\n}\n\nfunc TestRampingVUsGetRawExecutionStepsCornerCases(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tname          string\n\t\texpectedSteps []lib.ExecutionStep\n\t\tet            *lib.ExecutionTuple\n\t\tstages        []Stage\n\t\tstart         int64\n\t}{\n\t\t{\n\t\t\tname: \"going up then down straight away\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 5},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 3},\n\t\t\t},\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(0 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(3), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t},\n\t\t\tstart: 2,\n\t\t},\n\t\t{\n\t\t\tname: \"jump up then go up again\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 5},\n\t\t\t},\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t},\n\t\t\tstart: 3,\n\t\t},\n\t\t{\n\t\t\tname: \"up down up down\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 3 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 6 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 0},\n\t\t\t},\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"up down up down in half\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 0},\n\t\t\t},\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/2\"), nil),\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"up down up down in the other half\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 3 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 6 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 0},\n\t\t\t},\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"1/2:1\"), nil),\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"up down up down in with nothing\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 0},\n\t\t\t},\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"2/3:1\"), newExecutionSegmentSequenceFromString(\"0,1/3,2/3,1\")),\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"up down up down in with funky sequence\", // panics if there are no localIndex == 0 guards\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 0},\n\t\t\t},\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"0:1/3\"), newExecutionSegmentSequenceFromString(\"0,1/3,1/2,2/3,1\")),\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(2), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(2 * time.Second)},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"strange\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 11 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 15 * time.Second, PlannedVUs: 5},\n\t\t\t\t{TimeOffset: 18 * time.Second, PlannedVUs: 6},\n\t\t\t\t{TimeOffset: 23 * time.Second, PlannedVUs: 7},\n\t\t\t\t{TimeOffset: 35 * time.Second, PlannedVUs: 8},\n\t\t\t\t{TimeOffset: 44 * time.Second, PlannedVUs: 9},\n\t\t\t},\n\t\t\tet: mustNewExecutionTuple(newExecutionSegmentFromString(\"0:0.3\"), newExecutionSegmentSequenceFromString(\"0,0.3,0.6,0.9,1\")),\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(20), Duration: types.NullDurationFrom(20 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(30), Duration: types.NullDurationFrom(30 * time.Second)},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"more up and down\",\n\t\t\texpectedSteps: []lib.ExecutionStep{\n\t\t\t\t{TimeOffset: 0 * time.Second, PlannedVUs: 0},\n\t\t\t\t{TimeOffset: 1 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 2 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 3 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 4 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 5 * time.Second, PlannedVUs: 5},\n\t\t\t\t{TimeOffset: 6 * time.Second, PlannedVUs: 4},\n\t\t\t\t{TimeOffset: 7 * time.Second, PlannedVUs: 3},\n\t\t\t\t{TimeOffset: 8 * time.Second, PlannedVUs: 2},\n\t\t\t\t{TimeOffset: 9 * time.Second, PlannedVUs: 1},\n\t\t\t\t{TimeOffset: 10 * time.Second, PlannedVUs: 0},\n\t\t\t},\n\t\t\tstages: []Stage{\n\t\t\t\t{Target: null.IntFrom(5), Duration: types.NullDurationFrom(5 * time.Second)},\n\t\t\t\t{Target: null.IntFrom(0), Duration: types.NullDurationFrom(5 * time.Second)},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, testCase := range testCases {\n\t\tconf := NewRampingVUsConfig(\"test\")\n\t\tconf.StartVUs = null.IntFrom(testCase.start)\n\t\tconf.Stages = testCase.stages\n\t\tet := testCase.et\n\t\tif et == nil {\n\t\t\tet = mustNewExecutionTuple(nil, nil)\n\t\t}\n\t\texpectedSteps := testCase.expectedSteps\n\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\trawStepsNoZeroEnd := conf.getRawExecutionSteps(et, false)\n\t\t\tassert.Equal(t, expectedSteps, rawStepsNoZeroEnd)\n\t\t})\n\t}\n}\n\nfunc BenchmarkRampingVUsGetRawExecutionSteps(b *testing.B) {\n\ttestCases := []struct {\n\t\tseq string\n\t\tseg string\n\t}{\n\t\t{},\n\t\t{seg: \"0:1\"},\n\t\t{seq: \"0,0.3,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0:0.3\"},\n\t\t{seq: \"0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1\", seg: \"0:0.1\"},\n\t\t{seg: \"2/5:4/5\"},\n\t\t{seg: \"2235/5213:4/5\"}, // just wanted it to be ugly ;D\n\t}\n\n\tstageCases := []struct {\n\t\tname   string\n\t\tstages string\n\t}{\n\t\t{\n\t\t\tname:   \"normal\",\n\t\t\tstages: `[{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":10000},{\"duration\":\"5m\", \"target\":10000}]`,\n\t\t}, {\n\t\t\tname: \"rollercoaster\",\n\t\t\tstages: `[{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0},\n\t\t\t\t{\"duration\":\"5m\", \"target\":5000},{\"duration\":\"5m\", \"target\":0}]`,\n\t\t},\n\t}\n\tfor _, tc := range testCases {\n\t\tb.Run(fmt.Sprintf(\"seq:%s;segment:%s\", tc.seq, tc.seg), func(b *testing.B) {\n\t\t\tess, err := lib.NewExecutionSegmentSequenceFromString(tc.seq)\n\t\t\trequire.NoError(b, err)\n\t\t\tsegment, err := lib.NewExecutionSegmentFromString(tc.seg)\n\t\t\trequire.NoError(b, err)\n\t\t\tif tc.seg == \"\" {\n\t\t\t\tsegment = nil // specifically for the optimization\n\t\t\t}\n\t\t\tet, err := lib.NewExecutionTuple(segment, &ess)\n\t\t\trequire.NoError(b, err)\n\t\t\tfor _, stageCase := range stageCases {\n\t\t\t\tvar st []Stage\n\t\t\t\trequire.NoError(b, json.Unmarshal([]byte(stageCase.stages), &st))\n\t\t\t\tvlvc := RampingVUsConfig{\n\t\t\t\t\tStages: st,\n\t\t\t\t}\n\t\t\t\tb.Run(stageCase.name, func(b *testing.B) {\n\t\t\t\t\tfor i := 0; i < b.N; i++ {\n\t\t\t\t\t\t_ = vlvc.getRawExecutionSteps(et, false)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\n// TODO: delete in favor of lib.generateRandomSequence() after\n// https://github.com/k6io/k6/issues/1302 is done (can't import now due to\n// import loops...)\nfunc generateRandomSequence(t testing.TB, n, m int64, r *rand.Rand) lib.ExecutionSegmentSequence {\n\tvar err error\n\tess := lib.ExecutionSegmentSequence(make([]*lib.ExecutionSegment, n))\n\tnumerators := make([]int64, n)\n\tvar denominator int64\n\tfor i := range n {\n\t\tnumerators[i] = 1 + r.Int63n(m)\n\t\tdenominator += numerators[i]\n\t}\n\tfrom := big.NewRat(0, 1)\n\tfor i := range n {\n\t\tto := new(big.Rat).Add(big.NewRat(numerators[i], denominator), from)\n\t\tess[i], err = lib.NewExecutionSegment(from, to)\n\t\trequire.NoError(t, err)\n\t\tfrom = to\n\t}\n\n\treturn ess\n}\n\nfunc TestSumRandomSegmentSequenceMatchesNoSegment(t *testing.T) {\n\tt.Parallel()\n\n\tconst (\n\t\tnumTests         = 10\n\t\tmaxStages        = 10\n\t\tminStageDuration = 1 * time.Second\n\t\tmaxStageDuration = 10 * time.Minute\n\t\tmaxVUs           = 300\n\t\tsegmentSeqMaxLen = 15\n\t\tmaxNumerator     = 300\n\t)\n\tgetTestConfig := func(r *rand.Rand, name string) RampingVUsConfig {\n\t\tstagesCount := 1 + r.Int31n(maxStages)\n\t\tstages := make([]Stage, stagesCount)\n\t\tfor s := range stagesCount {\n\t\t\tdur := (minStageDuration + time.Duration(r.Int63n(int64(maxStageDuration-minStageDuration)))).Round(time.Second)\n\t\t\tstages[s] = Stage{Duration: types.NullDurationFrom(dur), Target: null.IntFrom(r.Int63n(maxVUs))}\n\t\t}\n\n\t\tc := NewRampingVUsConfig(name)\n\t\tc.GracefulRampDown = types.NullDurationFrom(0)\n\t\tc.GracefulStop = types.NullDurationFrom(0)\n\t\tc.StartVUs = null.IntFrom(r.Int63n(maxVUs))\n\t\tc.Stages = stages\n\t\treturn c\n\t}\n\n\tsubtractChildSteps := func(t *testing.T, parent, child []lib.ExecutionStep) {\n\t\tt.Logf(\"subtractChildSteps()\")\n\t\tfor _, step := range child {\n\t\t\tt.Logf(\"\tchild planned VUs for time offset %s: %d\", step.TimeOffset, step.PlannedVUs)\n\t\t}\n\t\tsub := uint64(0)\n\t\tci := 0\n\t\tfor pi, p := range parent {\n\t\t\t// We iterate over all parent steps and match them to child steps.\n\t\t\t// Once we have a match, we remove the child step's plannedVUs from\n\t\t\t// the parent steps until a new match, when we adjust the subtracted\n\t\t\t// amount again.\n\t\t\tif p.TimeOffset > child[ci].TimeOffset && ci != len(child)-1 {\n\t\t\t\tt.Errorf(\"ERR Could not match child offset %s with any parent time offset\", child[ci].TimeOffset)\n\t\t\t}\n\t\t\tif p.TimeOffset == child[ci].TimeOffset {\n\t\t\t\tt.Logf(\"Setting sub to %d at t=%s\", child[ci].PlannedVUs, child[ci].TimeOffset)\n\t\t\t\tsub = child[ci].PlannedVUs\n\t\t\t\tif ci != len(child)-1 {\n\t\t\t\t\tci++\n\t\t\t\t}\n\t\t\t}\n\t\t\tt.Logf(\"Subtracting %d VUs (out of %d) at t=%s\", sub, p.PlannedVUs, p.TimeOffset)\n\t\t\tparent[pi].PlannedVUs -= sub\n\t\t}\n\t}\n\n\tfor i := range numTests {\n\t\tname := fmt.Sprintf(\"random%02d\", i)\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tseed := time.Now().UnixNano()\n\t\t\tr := rand.New(rand.NewSource(seed))\n\t\t\tt.Logf(\"Random source seeded with %d\\n\", seed)\n\t\t\tc := getTestConfig(r, name)\n\t\t\tranSeqLen := 2 + r.Int63n(segmentSeqMaxLen-1)\n\t\t\tt.Logf(\"Config: %#v, ranSeqLen: %d\", c, ranSeqLen)\n\t\t\trandomSequence := generateRandomSequence(t, ranSeqLen, maxNumerator, r)\n\t\t\tt.Logf(\"Random sequence: %s\", randomSequence)\n\t\t\tfullSeg, err := lib.NewExecutionTuple(nil, nil)\n\t\t\trequire.NoError(t, err)\n\t\t\tfullRawSteps := c.getRawExecutionSteps(fullSeg, false)\n\n\t\t\tfor _, step := range fullRawSteps {\n\t\t\t\tt.Logf(\"original planned VUs for time offset %s: %d\", step.TimeOffset, step.PlannedVUs)\n\t\t\t}\n\n\t\t\tfor s := 0; s < len(randomSequence); s++ {\n\t\t\t\tet, err := lib.NewExecutionTuple(randomSequence[s], &randomSequence)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tsegRawSteps := c.getRawExecutionSteps(et, false)\n\t\t\t\tsubtractChildSteps(t, fullRawSteps, segRawSteps)\n\t\t\t}\n\n\t\t\tfor _, step := range fullRawSteps {\n\t\t\t\tif step.PlannedVUs != 0 {\n\t\t\t\t\tt.Errorf(\"ERR Remaining planned VUs for time offset %s are not 0 but %d\", step.TimeOffset, step.PlannedVUs)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "lib/executor/shared_iterations.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst sharedIterationsType = \"shared-iterations\"\n\nfunc init() {\n\tlib.RegisterExecutorConfigType(\n\t\tsharedIterationsType,\n\t\tfunc(name string, rawJSON []byte) (lib.ExecutorConfig, error) {\n\t\t\tconfig := NewSharedIterationsConfig(name)\n\t\t\terr := lib.StrictJSONUnmarshal(rawJSON, &config)\n\t\t\treturn config, err\n\t\t},\n\t)\n}\n\n// SharedIterationsConfig stores the number of VUs iterations, as well as maxDuration settings\ntype SharedIterationsConfig struct {\n\tBaseConfig\n\tVUs         null.Int           `json:\"vus\"`\n\tIterations  null.Int           `json:\"iterations\"`\n\tMaxDuration types.NullDuration `json:\"maxDuration\"`\n}\n\n// NewSharedIterationsConfig returns a SharedIterationsConfig with default values\nfunc NewSharedIterationsConfig(name string) SharedIterationsConfig {\n\treturn SharedIterationsConfig{\n\t\tBaseConfig:  NewBaseConfig(name, sharedIterationsType),\n\t\tVUs:         null.NewInt(1, false),\n\t\tIterations:  null.NewInt(1, false),\n\t\tMaxDuration: types.NewNullDuration(10*time.Minute, false), // TODO: shorten?\n\t}\n}\n\n// Make sure we implement the lib.ExecutorConfig interface\nvar _ lib.ExecutorConfig = &SharedIterationsConfig{}\n\n// GetVUs returns the scaled VUs for the executor.\nfunc (sic SharedIterationsConfig) GetVUs(et *lib.ExecutionTuple) int64 {\n\treturn et.ScaleInt64(sic.VUs.Int64)\n}\n\n// GetIterations returns the scaled iteration count for the executor.\nfunc (sic SharedIterationsConfig) GetIterations(et *lib.ExecutionTuple) int64 {\n\t// TODO: Optimize this by probably changing the whole Config API\n\tnewTuple, err := et.GetNewExecutionTupleFromValue(sic.VUs.Int64)\n\tif err != nil {\n\t\treturn 0\n\t}\n\treturn newTuple.ScaleInt64(sic.Iterations.Int64)\n}\n\n// GetDescription returns a human-readable description of the executor options\nfunc (sic SharedIterationsConfig) GetDescription(et *lib.ExecutionTuple) string {\n\treturn fmt.Sprintf(\"%d iterations shared among %d VUs%s\",\n\t\tsic.GetIterations(et), sic.GetVUs(et),\n\t\tsic.getBaseInfo(fmt.Sprintf(\"maxDuration: %s\", sic.MaxDuration.Duration)))\n}\n\n// Validate makes sure all options are configured and valid\nfunc (sic SharedIterationsConfig) Validate() []error {\n\terrors := sic.BaseConfig.Validate()\n\tif sic.VUs.Int64 <= 0 {\n\t\terrors = append(errors, fmt.Errorf(\"the number of VUs must be more than 0\"))\n\t}\n\n\tif sic.Iterations.Int64 < sic.VUs.Int64 {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the number of iterations (%d) can't be less than the number of VUs (%d)\",\n\t\t\tsic.Iterations.Int64, sic.VUs.Int64,\n\t\t))\n\t}\n\n\tif sic.MaxDuration.TimeDuration() < minDuration {\n\t\terrors = append(errors, fmt.Errorf(\n\t\t\t\"the maxDuration must be at least %s, but is %s\", minDuration, sic.MaxDuration,\n\t\t))\n\t}\n\n\treturn errors\n}\n\n// GetExecutionRequirements returns the number of required VUs to run the\n// executor for its whole duration (disregarding any startTime), including the\n// maximum waiting time for any iterations to gracefully stop. This is used by\n// the execution scheduler in its VU reservation calculations, so it knows how\n// many VUs to pre-initialize.\nfunc (sic SharedIterationsConfig) GetExecutionRequirements(et *lib.ExecutionTuple) []lib.ExecutionStep {\n\tvus := sic.GetVUs(et)\n\tif vus == 0 {\n\t\treturn []lib.ExecutionStep{\n\t\t\t{\n\t\t\t\tTimeOffset: 0,\n\t\t\t\tPlannedVUs: 0,\n\t\t\t},\n\t\t}\n\t}\n\n\treturn []lib.ExecutionStep{\n\t\t{\n\t\t\tTimeOffset: 0,\n\t\t\tPlannedVUs: uint64(vus), //nolint:gosec\n\t\t},\n\t\t{\n\t\t\tTimeOffset: sic.MaxDuration.TimeDuration() + sic.GracefulStop.TimeDuration(),\n\t\t\tPlannedVUs: 0,\n\t\t},\n\t}\n}\n\n// NewExecutor creates a new SharedIterations executor\nfunc (sic SharedIterationsConfig) NewExecutor(\n\tes *lib.ExecutionState, logger *logrus.Entry,\n) (lib.Executor, error) {\n\treturn &SharedIterations{\n\t\tBaseExecutor: NewBaseExecutor(sic, es, logger),\n\t\tconfig:       sic,\n\t}, nil\n}\n\n// SharedIterations executes a specific total number of iterations, which are\n// all shared by the configured VUs.\ntype SharedIterations struct {\n\t*BaseExecutor\n\tconfig SharedIterationsConfig\n\tet     *lib.ExecutionTuple\n}\n\n// Make sure we implement the lib.Executor interface.\nvar _ lib.Executor = &SharedIterations{}\n\n// HasWork reports whether there is any work to be done for the given execution segment.\nfunc (sic SharedIterationsConfig) HasWork(et *lib.ExecutionTuple) bool {\n\treturn sic.GetVUs(et) > 0 && sic.GetIterations(et) > 0\n}\n\n// Init values needed for the execution\nfunc (si *SharedIterations) Init(_ context.Context) error {\n\t// err should always be nil, because Init() won't be called for executors\n\t// with no work, as determined by their config's HasWork() method.\n\tet, err := si.executionState.ExecutionTuple.GetNewExecutionTupleFromValue(si.config.VUs.Int64)\n\tsi.et = et\n\tsi.iterSegIndex = lib.NewSegmentedIndex(et)\n\n\treturn err\n}\n\n// Run executes a specific total number of iterations, which are all shared by\n// the configured VUs.\n//\n//nolint:funlen\nfunc (si SharedIterations) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) {\n\tnumVUs := si.config.GetVUs(si.executionState.ExecutionTuple)\n\titerations := si.et.ScaleInt64(si.config.Iterations.Int64)\n\tduration := si.config.MaxDuration.TimeDuration()\n\tgracefulStop := si.config.GetGracefulStop()\n\n\twaitOnProgressChannel := make(chan struct{})\n\tstartTime, maxDurationCtx, regDurationCtx, cancel := getDurationContexts(parentCtx, duration, gracefulStop)\n\tdefer func() {\n\t\tcancel()\n\t\t<-waitOnProgressChannel\n\t}()\n\n\t// Make sure the log and the progress bar have accurate information\n\tsi.logger.WithFields(logrus.Fields{\n\t\t\"vus\": numVUs, \"iterations\": iterations, \"maxDuration\": duration, \"type\": si.config.GetType(),\n\t}).Debug(\"Starting executor run...\")\n\n\ttotalIters := uint64(iterations) //nolint:gosec\n\tdoneIters := new(uint64)\n\tvusFmt := pb.GetFixedLengthIntFormat(numVUs)\n\titersFmt := pb.GetFixedLengthIntFormat(iterations)\n\tprogressFn := func() (float64, []string) {\n\t\tspent := time.Since(startTime)\n\t\tprogVUs := fmt.Sprintf(vusFmt+\" VUs\", numVUs)\n\t\tcurrentDoneIters := atomic.LoadUint64(doneIters)\n\t\tprogIters := fmt.Sprintf(itersFmt+\"/\"+itersFmt+\" shared iters\",\n\t\t\tcurrentDoneIters, totalIters)\n\t\tspentDuration := pb.GetFixedLengthDuration(spent, duration)\n\t\tprogDur := fmt.Sprintf(\"%s/%s\", spentDuration, duration)\n\t\tright := []string{progVUs, progDur, progIters}\n\n\t\treturn float64(currentDoneIters) / float64(totalIters), right\n\t}\n\tsi.progress.Modify(pb.WithProgress(progressFn))\n\tmaxDurationCtx = lib.WithScenarioState(maxDurationCtx, &lib.ScenarioState{\n\t\tName:       si.config.Name,\n\t\tExecutor:   si.config.Type,\n\t\tStartTime:  startTime,\n\t\tProgressFn: progressFn,\n\t})\n\tgo func() {\n\t\ttrackProgress(parentCtx, maxDurationCtx, regDurationCtx, &si, progressFn)\n\t\tclose(waitOnProgressChannel)\n\t}()\n\n\tvar attemptedIters uint64\n\n\t// Actually schedule the VUs and iterations...\n\tactiveVUs := &sync.WaitGroup{}\n\tdefer func() {\n\t\tactiveVUs.Wait()\n\t\tif attemptedIters < totalIters {\n\t\t\tmetrics.PushIfNotDone(parentCtx, out, metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: si.executionState.Test.BuiltinMetrics.DroppedIterations,\n\t\t\t\t\tTags:   si.getMetricTags(nil),\n\t\t\t\t},\n\t\t\t\tValue: float64(totalIters - attemptedIters),\n\t\t\t\tTime:  time.Now(),\n\t\t\t})\n\t\t}\n\t}()\n\n\tregDurationDone := regDurationCtx.Done()\n\trunIteration := getIterationRunner(si.executionState, si.logger)\n\n\treturnVU := func(u lib.InitializedVU) {\n\t\tsi.executionState.ReturnVU(u, true)\n\t\tactiveVUs.Done()\n\t}\n\n\thandleVU := func(initVU lib.InitializedVU) {\n\t\tctx, cancel := context.WithCancel(maxDurationCtx)\n\t\tdefer cancel()\n\n\t\tactiveVU := initVU.Activate(getVUActivationParams(\n\t\t\tctx, si.config.BaseConfig, returnVU, si.nextIterationCounters))\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-regDurationDone:\n\t\t\t\treturn // don't make more iterations\n\t\t\tdefault:\n\t\t\t\t// continue looping\n\t\t\t}\n\n\t\t\tattemptedIterNumber := atomic.AddUint64(&attemptedIters, 1)\n\t\t\tif attemptedIterNumber > totalIters {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trunIteration(maxDurationCtx, activeVU)\n\t\t\tatomic.AddUint64(doneIters, 1)\n\t\t}\n\t}\n\n\tfor range numVUs {\n\t\tinitVU, err := si.executionState.GetPlannedVU(si.logger, true)\n\t\tif err != nil {\n\t\t\tcancel()\n\t\t\treturn err\n\t\t}\n\t\tactiveVUs.Add(1)\n\t\tgo handleVU(initVU)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "lib/executor/shared_iterations_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"slices\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc getTestSharedIterationsConfig() SharedIterationsConfig {\n\treturn SharedIterationsConfig{\n\t\tVUs:         null.IntFrom(10),\n\t\tIterations:  null.IntFrom(100),\n\t\tMaxDuration: types.NullDurationFrom(5 * time.Second),\n\t}\n}\n\n// Baseline test\nfunc TestSharedIterationsRun(t *testing.T) {\n\tt.Parallel()\n\tvar doneIters uint64\n\n\trunner := simpleRunner(func(_ context.Context, _ *lib.State) error {\n\t\tatomic.AddUint64(&doneIters, 1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestSharedIterationsConfig())\n\tdefer test.cancel()\n\n\trequire.NoError(t, test.executor.Run(test.ctx, nil))\n\tassert.Equal(t, uint64(100), doneIters)\n}\n\n// Test that when one VU \"slows down\", others will pick up the workload.\n// This is the reverse behavior of the PerVUIterations executor.\nfunc TestSharedIterationsRunVariableVU(t *testing.T) {\n\tt.Parallel()\n\tvar (\n\t\tresult   sync.Map\n\t\tslowVUID uint64\n\t)\n\n\trunner := simpleRunner(func(_ context.Context, state *lib.State) error {\n\t\ttime.Sleep(10 * time.Millisecond) // small wait to stabilize the test\n\t\t// Pick one VU randomly and always slow it down.\n\t\tsid := atomic.LoadUint64(&slowVUID)\n\t\tif sid == uint64(0) {\n\t\t\tatomic.StoreUint64(&slowVUID, state.VUID)\n\t\t}\n\t\tif sid == state.VUID {\n\t\t\ttime.Sleep(200 * time.Millisecond)\n\t\t}\n\t\tcurrIter, _ := result.LoadOrStore(state.VUID, uint64(0))\n\t\tresult.Store(state.VUID, currIter.(uint64)+1)\n\t\treturn nil\n\t})\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, getTestSharedIterationsConfig())\n\tdefer test.cancel()\n\n\trequire.NoError(t, test.executor.Run(test.ctx, nil))\n\n\tvar totalIters uint64\n\tresult.Range(func(_, value any) bool {\n\t\ttotalIters += value.(uint64)\n\t\treturn true\n\t})\n\n\t// The slow VU should complete 2 iterations given these timings,\n\t// while the rest should randomly complete the other 98 iterations.\n\tval, ok := result.Load(slowVUID)\n\tassert.True(t, ok)\n\tassert.Equal(t, uint64(2), val)\n\tassert.Equal(t, uint64(100), totalIters)\n}\n\nfunc TestSharedIterationsEmitDroppedIterations(t *testing.T) {\n\tt.Parallel()\n\tvar count int64\n\n\trunner := simpleRunner(func(ctx context.Context, _ *lib.State) error {\n\t\tatomic.AddInt64(&count, 1)\n\t\t<-ctx.Done()\n\t\treturn nil\n\t})\n\n\tconfig := &SharedIterationsConfig{\n\t\tVUs:         null.IntFrom(5),\n\t\tIterations:  null.IntFrom(100),\n\t\tMaxDuration: types.NullDurationFrom(1 * time.Second),\n\t}\n\n\ttest := setupExecutorTest(t, \"\", \"\", lib.Options{}, runner, config)\n\tdefer test.cancel()\n\n\tengineOut := make(chan metrics.SampleContainer, 1000)\n\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\tassert.Empty(t, test.logHook.Drain())\n\tassert.Equal(t, int64(5), count)\n\tassert.Equal(t, float64(95), sumMetricValues(engineOut, metrics.DroppedIterationsName))\n}\n\nfunc TestSharedIterationsGlobalIters(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := &SharedIterationsConfig{\n\t\tVUs:         null.IntFrom(5),\n\t\tIterations:  null.IntFrom(50),\n\t\tMaxDuration: types.NullDurationFrom(1 * time.Second),\n\t}\n\n\ttestCases := []struct {\n\t\tseq, seg string\n\t\texpIters []uint64\n\t}{\n\t\t{\"0,1/4,3/4,1\", \"0:1/4\", []uint64{1, 6, 11, 16, 21, 26, 31, 36, 41, 46}},\n\t\t{\"0,1/4,3/4,1\", \"1/4:3/4\", []uint64{0, 2, 4, 5, 7, 9, 10, 12, 14, 15, 17, 19, 20, 22, 24, 25, 27, 29, 30, 32, 34, 35, 37, 39, 40, 42, 44, 45, 47, 49}},\n\t\t{\"0,1/4,3/4,1\", \"3/4:1\", []uint64{3, 8, 13, 18, 23, 28, 33, 38, 43, 48}},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"%s_%s\", tc.seq, tc.seg), func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotIters := []uint64{}\n\t\t\tvar mx sync.Mutex\n\t\t\trunner := simpleRunner(func(_ context.Context, state *lib.State) error {\n\t\t\t\tmx.Lock()\n\t\t\t\tgotIters = append(gotIters, state.GetScenarioGlobalVUIter())\n\t\t\t\tmx.Unlock()\n\t\t\t\treturn nil\n\t\t\t})\n\n\t\t\ttest := setupExecutorTest(t, tc.seg, tc.seq, lib.Options{}, runner, config)\n\t\t\tdefer test.cancel()\n\n\t\t\tengineOut := make(chan metrics.SampleContainer, 100)\n\t\t\trequire.NoError(t, test.executor.Run(test.ctx, engineOut))\n\t\t\tslices.Sort(gotIters)\n\t\t\tassert.Equal(t, tc.expIters, gotIters)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "lib/executor/vu_handle.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\ntype stateType int32\n\n// states\nconst (\n\tstopped stateType = iota\n\tstarting\n\trunning\n\ttoGracefulStop\n\ttoHardStop\n)\n\n/*\nthe below is a state transition table (https://en.wikipedia.org/wiki/State-transition_table)\nshort names for input:\n- start is the method start\n- loop is a loop of runLoopsIfPossible\n- grace is the method gracefulStop\n- hard is the method hardStop\n+-------+-------------------------------------+---------------------------------------------------+\n| input | current         | next state        | notes                                             |\n+-------+-------------------------------------+---------------------------------------------------+\n| start | stopped         | starting          | normal                                            |\n| start | starting        | starting          | nothing                                           |\n| start | running         | running           | nothing                                           |\n| start | toGracefulStop  | running           | we raced with the loop stopping, just continue    |\n| start | toHardStop      | starting          | same as stopped really                            |\n| loop  | stopped         | stopped           | we actually are blocked on canStartIter           |\n| loop  | starting        | running           | get new VU and context                            |\n| loop  | running         | running           | usually fast path                                 |\n| loop  | toGracefulStop  | stopped           | cancel the context and make new one               |\n| loop  | toHardStop      | stopped           | cancel the context and make new one               |\n| grace | stopped         | stopped           | nothing                                           |\n| grace | starting        | stopped           | cancel the context to return the VU               |\n| grace | running         | toGracefulStop    | normal one, the actual work is in the loop        |\n| grace | toGracefulStop  | toGracefulStop    | nothing                                           |\n| grace | toHardSTop      | toHardStop        | nothing                                           |\n| hard  | stopped         | stopped           | nothing                                           |\n| hard  | starting        | stopped           | short circuit as in the grace case, not necessary |\n| hard  | running         | toHardStop        | normal, cancel context and reinitialize it        |\n| hard  | toGracefulStop  | toHardStop        | normal, cancel context and reinitialize it        |\n| hard  | toHardStop      | toHardStop        | nothing                                           |\n+-------+-----------------+-------------------+----------------------------------------------------+\n*/\n\n// This is a helper type used in executors where we have to dynamically control\n// the number of VUs that are simultaneously running. For the moment, it is used\n// in the RampingVUs and the ExternallyControlled executors.\n// Notes on the implementation requirements:\n// - it needs to be able to start and stop VUs in thread safe fashion\n// - for each call to getVU there must be 1 (and only 1) call to returnVU\n// - gracefulStop must let an iteration which has started to finish. For reasons of ease of\n// implementation and lack of good evidence it's not required to let a not started iteration to\n// finish in other words if you call start and then gracefulStop, there is no requirement for\n// 1 iteration to have been started.\n// - hardStop must stop an iteration in process\n// - it's not required but preferable, if where possible to not reactivate VUs and to reuse context\n// as this speed ups the execution\ntype vuHandle struct {\n\tmutex                 *sync.Mutex\n\tparentCtx             context.Context\n\tgetVU                 func() (lib.InitializedVU, error)\n\treturnVU              func(lib.InitializedVU)\n\tnextIterationCounters func() (uint64, uint64)\n\tconfig                *BaseConfig\n\n\tinitVU       lib.InitializedVU\n\tactiveVU     lib.ActiveVU\n\tcanStartIter chan struct{}\n\n\tstate stateType // see the table above for meanings\n\t// stateH []int32 // helper for debugging\n\n\tctx    context.Context\n\tcancel func()\n\tlogger *logrus.Entry\n}\n\nfunc newStoppedVUHandle(\n\tparentCtx context.Context, getVU func() (lib.InitializedVU, error),\n\treturnVU func(lib.InitializedVU),\n\tnextIterationCounters func() (uint64, uint64),\n\tconfig *BaseConfig, logger *logrus.Entry,\n) *vuHandle {\n\tctx, cancel := context.WithCancel(parentCtx)\n\n\treturn &vuHandle{\n\t\tmutex:                 &sync.Mutex{},\n\t\tparentCtx:             parentCtx,\n\t\tgetVU:                 getVU,\n\t\tnextIterationCounters: nextIterationCounters,\n\t\tconfig:                config,\n\n\t\tcanStartIter: make(chan struct{}),\n\t\tstate:        stopped,\n\n\t\tctx:      ctx,\n\t\tcancel:   cancel,\n\t\tlogger:   logger,\n\t\treturnVU: returnVU,\n\t}\n}\n\nfunc (vh *vuHandle) start() (err error) {\n\tvh.mutex.Lock()\n\tdefer vh.mutex.Unlock()\n\n\tswitch vh.state {\n\tcase starting, running:\n\t\treturn nil // nothing to do\n\tcase toGracefulStop: // we raced with the loop, lets not return the vu just to get it back\n\t\tvh.logger.Debug(\"Start\")\n\t\tclose(vh.canStartIter)\n\t\tvh.changeState(running)\n\tcase stopped, toHardStop: // we need to reactivate the VU and remake the context for it\n\t\tvh.logger.Debug(\"Start\")\n\t\tvh.initVU, err = vh.getVU()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvh.activeVU = vh.initVU.Activate(getVUActivationParams(\n\t\t\tvh.ctx, *vh.config, vh.returnVU, vh.nextIterationCounters))\n\t\tclose(vh.canStartIter)\n\t\tvh.changeState(starting)\n\t}\n\treturn nil\n}\n\n// just a helper function for debugging\nfunc (vh *vuHandle) changeState(newState stateType) {\n\t// vh.stateH = append(vh.stateH, newState)\n\tatomic.StoreInt32((*int32)(&vh.state), int32(newState))\n}\n\nfunc (vh *vuHandle) gracefulStop() {\n\tvh.mutex.Lock()\n\tdefer vh.mutex.Unlock()\n\tswitch vh.state {\n\tcase toGracefulStop, toHardStop, stopped:\n\t\treturn // nothing to do\n\tcase starting: // we raced with the loop and apparently it won't do a single iteration\n\t\tvh.cancel()\n\t\tvh.ctx, vh.cancel = context.WithCancel(vh.parentCtx)\n\t\tvh.changeState(stopped)\n\tcase running:\n\t\tvh.changeState(toGracefulStop)\n\t}\n\n\tvh.logger.Debug(\"Graceful stop\")\n\tvh.canStartIter = make(chan struct{})\n}\n\nfunc (vh *vuHandle) hardStop() {\n\tvh.mutex.Lock()\n\tdefer vh.mutex.Unlock()\n\n\tswitch vh.state {\n\tcase toHardStop, stopped:\n\t\treturn // nothing to do\n\tcase starting: // we raced with the loop and apparently it won't do a single iteration\n\t\tvh.changeState(stopped)\n\tcase running, toGracefulStop:\n\t\tvh.changeState(toHardStop)\n\t}\n\tvh.logger.Debug(\"Hard stop\")\n\tvh.cancel()\n\tvh.ctx, vh.cancel = context.WithCancel(vh.parentCtx)\n\tvh.canStartIter = make(chan struct{})\n}\n\n// runLoopsIfPossible is where all the fun is :D. Unfortunately somewhere we need to check most\n// of the cases and this is where this happens.\nfunc (vh *vuHandle) runLoopsIfPossible(runIter func(context.Context, lib.ActiveVU) bool) {\n\t// We can probably initialize here, but it's also easier to just use the slow path in the second\n\t// part of the for loop\n\tdefer func() {\n\t\t// not sure if this is needed, because here the parentCtx is canceled and I would argue it doesn't matter\n\t\t// if we set the correct state\n\t\tvh.mutex.Lock()\n\t\tvh.changeState(stopped)\n\t\tvh.mutex.Unlock()\n\t}()\n\n\tvar (\n\t\texecutorDone = vh.parentCtx.Done()\n\t\tctx          context.Context\n\t\tcancel       func()\n\t\tvu           lib.ActiveVU\n\t)\n\n\tfor {\n\t\tstate := stateType(atomic.LoadInt32((*int32)(&vh.state)))\n\t\tif state == running && runIter(ctx, vu) { // fast path\n\t\t\tcontinue\n\t\t}\n\n\t\t// slow path - something has changed - get what and wait until we can do more iterations\n\t\tvh.mutex.Lock()\n\t\tselect {\n\t\tcase <-executorDone:\n\t\t\t// The whole executor is done, nothing more to do.\n\t\t\tvh.mutex.Unlock()\n\t\t\treturn\n\t\tdefault:\n\t\t}\n\n\t\tswitch vh.state {\n\t\tcase running: // start raced us toGracefulStop\n\t\t\tvh.mutex.Unlock()\n\t\t\tcontinue\n\t\tcase toGracefulStop:\n\t\t\tif cancel != nil {\n\t\t\t\t// we need to cancel the context, to return the vu\n\t\t\t\t// and because *we* did, lets reinitialize it\n\t\t\t\tcancel()\n\t\t\t\tvh.ctx, vh.cancel = context.WithCancel(vh.parentCtx) //nolint:fatcontext // isn't actually on the same context\n\t\t\t}\n\t\t\tfallthrough // to set the state\n\t\tcase toHardStop:\n\t\t\t// we have *now* stopped\n\t\t\tvh.changeState(stopped)\n\t\tcase stopped, starting:\n\t\t\t// there is nothing to do\n\t\t}\n\n\t\tcanStartIter := vh.canStartIter\n\t\tctx = vh.ctx\n\t\tvh.mutex.Unlock()\n\n\t\t// We're are stopped, but the executor isn't done yet, so we wait\n\t\t// for either one of those conditions.\n\t\tselect {\n\t\tcase <-canStartIter: // we can start again\n\t\t\tvh.mutex.Lock()\n\t\t\tselect {\n\t\t\tcase <-vh.canStartIter: // we check again in case of race\n\t\t\t\t// reinitialize\n\t\t\t\tvu, ctx, cancel = vh.activeVU, vh.ctx, vh.cancel\n\t\t\t\tvh.changeState(running)\n\t\t\tdefault:\n\t\t\t\t// well we got raced to here by something ... loop again ...\n\t\t\t}\n\t\t\tvh.mutex.Unlock()\n\t\tcase <-ctx.Done():\n\t\t\t// hardStop was called, start a fresh iteration to get the new\n\t\t\t// context and signal channel\n\t\tcase <-executorDone:\n\t\t\t// The whole executor is done, nothing more to do.\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/executor/vu_handle_test.go",
    "content": "package executor\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/lib/testutils/minirunner\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc mockNextIterations() (uint64, uint64) {\n\treturn 12, 15\n}\n\n// this test is mostly interesting when -race is enabled\nfunc TestVUHandleRace(t *testing.T) {\n\tt.Parallel()\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tlogHook := testutils.NewLogHook(logrus.DebugLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\ttestLog.SetOutput(testutils.NewTestOutput(t))\n\t// testLog.Level = logrus.DebugLevel\n\tlogEntry := logrus.NewEntry(testLog)\n\n\trunner := &minirunner.MiniRunner{}\n\trunner.Fn = func(_ context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\treturn nil\n\t}\n\n\tvar getVUCount uint64\n\tvar returnVUCount uint64\n\tgetVU := func() (lib.InitializedVU, error) {\n\t\treturn runner.NewVU(ctx, atomic.AddUint64(&getVUCount, 1), 0, nil)\n\t}\n\n\treturnVU := func(_ lib.InitializedVU) {\n\t\tatomic.AddUint64(&returnVUCount, 1)\n\t\t// do something\n\t}\n\tvar interruptedIter int64\n\tvar fullIterations int64\n\n\trunIter := func(ctx context.Context, vu lib.ActiveVU) bool {\n\t\t_ = vu.RunOnce()\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\t// Don't log errors or emit iterations metrics from cancelled iterations\n\t\t\tatomic.AddInt64(&interruptedIter, 1)\n\t\t\treturn false\n\t\tdefault:\n\t\t\tatomic.AddInt64(&fullIterations, 1)\n\t\t\treturn true\n\t\t}\n\t}\n\n\tvuHandle := newStoppedVUHandle(ctx, getVU, returnVU, mockNextIterations, &BaseConfig{}, logEntry)\n\tgo vuHandle.runLoopsIfPossible(runIter)\n\tvar wg sync.WaitGroup\n\twg.Add(3)\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor range 10000 {\n\t\t\terr := vuHandle.start()\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor range 1000 {\n\t\t\tvuHandle.gracefulStop()\n\t\t\ttime.Sleep(1 * time.Nanosecond)\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor range 100 {\n\t\t\tvuHandle.hardStop()\n\t\t\ttime.Sleep(10 * time.Nanosecond)\n\t\t}\n\t}()\n\twg.Wait()\n\tvuHandle.hardStop() // STOP it\n\ttime.Sleep(time.Millisecond * 50)\n\tinterruptedBefore := atomic.LoadInt64(&interruptedIter)\n\tfullBefore := atomic.LoadInt64(&fullIterations)\n\t_ = vuHandle.start()\n\ttime.Sleep(time.Millisecond * 50) // just to be sure an iteration will squeeze in\n\tcancel()\n\ttime.Sleep(time.Millisecond * 50)\n\tinterruptedAfter := atomic.LoadInt64(&interruptedIter)\n\tfullAfter := atomic.LoadInt64(&fullIterations)\n\tassert.True(t, interruptedBefore >= interruptedAfter-1,\n\t\t\"too big of a difference %d >= %d - 1\", interruptedBefore, interruptedAfter)\n\tassert.True(t, fullBefore+1 <= fullAfter,\n\t\t\"too small of a difference %d + 1 <= %d\", fullBefore, fullAfter)\n\trequire.Equal(t, atomic.LoadUint64(&getVUCount), atomic.LoadUint64(&returnVUCount))\n}\n\n// this test is mostly interesting when -race is enabled\nfunc TestVUHandleStartStopRace(t *testing.T) {\n\tt.Parallel()\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tlogHook := testutils.NewLogHook(logrus.DebugLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\ttestLog.SetOutput(testutils.NewTestOutput(t))\n\t// testLog.Level = logrus.DebugLevel\n\tlogEntry := logrus.NewEntry(testLog)\n\n\trunner := &minirunner.MiniRunner{}\n\trunner.Fn = func(_ context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\treturn nil\n\t}\n\n\tvar vuID uint64\n\ttestIterations := 10000\n\treturned := make(chan struct{})\n\n\tgetVU := func() (lib.InitializedVU, error) {\n\t\treturned = make(chan struct{})\n\t\treturn runner.NewVU(ctx, atomic.AddUint64(&vuID, 1), 0, nil)\n\t}\n\n\treturnVU := func(v lib.InitializedVU) {\n\t\trequire.Equal(t, atomic.LoadUint64(&vuID), v.(*minirunner.VU).ID)\n\t\tclose(returned)\n\t}\n\tvar interruptedIter int64\n\tvar fullIterations int64\n\n\trunIter := func(ctx context.Context, vu lib.ActiveVU) bool {\n\t\t_ = vu.RunOnce()\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\t// Don't log errors or emit iterations metrics from cancelled iterations\n\t\t\tatomic.AddInt64(&interruptedIter, 1)\n\t\t\treturn false\n\t\tdefault:\n\t\t\tatomic.AddInt64(&fullIterations, 1)\n\t\t\treturn true\n\t\t}\n\t}\n\n\tvuHandle := newStoppedVUHandle(ctx, getVU, returnVU, mockNextIterations, &BaseConfig{}, logEntry)\n\tgo vuHandle.runLoopsIfPossible(runIter)\n\tfor range testIterations {\n\t\terr := vuHandle.start()\n\t\tvuHandle.gracefulStop()\n\t\trequire.NoError(t, err)\n\t\tselect {\n\t\tcase <-returned:\n\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\tgo panic(\"returning took too long\")\n\t\t\ttime.Sleep(time.Second)\n\t\t}\n\t}\n\n\tvuHandle.hardStop() // STOP it\n\ttime.Sleep(time.Millisecond * 5)\n\tinterruptedBefore := atomic.LoadInt64(&interruptedIter)\n\tfullBefore := atomic.LoadInt64(&fullIterations)\n\t_ = vuHandle.start()\n\ttime.Sleep(time.Millisecond * 50) // just to be sure an iteration will squeeze in\n\tcancel()\n\ttime.Sleep(time.Millisecond * 5)\n\tinterruptedAfter := atomic.LoadInt64(&interruptedIter)\n\tfullAfter := atomic.LoadInt64(&fullIterations)\n\tassert.True(t, interruptedBefore >= interruptedAfter-1,\n\t\t\"too big of a difference %d >= %d - 1\", interruptedBefore, interruptedAfter)\n\tassert.True(t, fullBefore+1 <= fullAfter,\n\t\t\"too small of a difference %d + 1 <= %d\", fullBefore, fullAfter)\n}\n\ntype handleVUTest struct {\n\trunner          *minirunner.MiniRunner\n\tgetVUCount      uint32\n\treturnVUCount   uint32\n\tinterruptedIter int64\n\tfullIterations  int64\n}\n\nfunc (h *handleVUTest) getVU() (lib.InitializedVU, error) {\n\treturn h.runner.NewVU(context.Background(), uint64(atomic.AddUint32(&h.getVUCount, 1)), 0, nil)\n}\n\nfunc (h *handleVUTest) returnVU(_ lib.InitializedVU) {\n\tatomic.AddUint32(&h.returnVUCount, 1)\n}\n\nfunc (h *handleVUTest) runIter(ctx context.Context, _ lib.ActiveVU) bool {\n\tselect {\n\tcase <-time.After(time.Second):\n\tcase <-ctx.Done():\n\t}\n\n\tselect {\n\tcase <-ctx.Done():\n\t\t// Don't log errors or emit iterations metrics from cancelled iterations\n\t\tatomic.AddInt64(&h.interruptedIter, 1)\n\t\treturn false\n\tdefault:\n\t\tatomic.AddInt64(&h.fullIterations, 1)\n\t\treturn true\n\t}\n}\n\nfunc TestVUHandleSimple(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"start before gracefulStop finishes\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tlogHook := testutils.NewLogHook(logrus.DebugLevel)\n\t\ttestLog := logrus.New()\n\t\ttestLog.AddHook(logHook)\n\t\ttestLog.SetOutput(testutils.NewTestOutput(t))\n\t\t// testLog.Level = logrus.DebugLevel\n\t\tlogEntry := logrus.NewEntry(testLog)\n\t\ttest := &handleVUTest{runner: &minirunner.MiniRunner{}}\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tdefer cancel()\n\n\t\tvuHandle := newStoppedVUHandle(ctx, test.getVU, test.returnVU, mockNextIterations, &BaseConfig{}, logEntry)\n\t\tvar wg sync.WaitGroup\n\t\twg.Go(func() {\n\t\t\tvuHandle.runLoopsIfPossible(test.runIter)\n\t\t})\n\t\terr := vuHandle.start()\n\t\trequire.NoError(t, err)\n\t\ttime.Sleep(time.Millisecond * 50)\n\t\tvuHandle.gracefulStop()\n\t\t// time.Sleep(time.Millisecond * 5) // No sleep as we want to always not return the VU\n\t\terr = vuHandle.start()\n\t\trequire.NoError(t, err)\n\t\ttime.Sleep(time.Millisecond * 1500)\n\t\tassert.EqualValues(t, 1, atomic.LoadUint32(&test.getVUCount))\n\t\tassert.EqualValues(t, 0, atomic.LoadUint32(&test.returnVUCount))\n\t\tassert.EqualValues(t, 0, atomic.LoadInt64(&test.interruptedIter))\n\t\tassert.EqualValues(t, 1, atomic.LoadInt64(&test.fullIterations))\n\t\tcancel()\n\t\twg.Wait()\n\t\ttime.Sleep(time.Millisecond * 5)\n\t\tassert.EqualValues(t, 1, atomic.LoadUint32(&test.getVUCount))\n\t\tassert.EqualValues(t, 1, atomic.LoadUint32(&test.returnVUCount))\n\t\tassert.EqualValues(t, 1, atomic.LoadInt64(&test.interruptedIter))\n\t\tassert.EqualValues(t, 1, atomic.LoadInt64(&test.fullIterations))\n\t})\n\n\tt.Run(\"start after gracefulStop finishes\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tlogHook := testutils.NewLogHook(logrus.DebugLevel)\n\t\ttestLog := logrus.New()\n\t\ttestLog.AddHook(logHook)\n\t\ttestLog.SetOutput(testutils.NewTestOutput(t))\n\t\t// testLog.Level = logrus.DebugLevel\n\t\tlogEntry := logrus.NewEntry(testLog)\n\t\ttest := &handleVUTest{runner: &minirunner.MiniRunner{}}\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tdefer cancel()\n\n\t\tvuHandle := newStoppedVUHandle(ctx, test.getVU, test.returnVU, mockNextIterations, &BaseConfig{}, logEntry)\n\t\tvar wg sync.WaitGroup\n\t\twg.Go(func() {\n\t\t\tvuHandle.runLoopsIfPossible(test.runIter)\n\t\t})\n\t\terr := vuHandle.start()\n\t\trequire.NoError(t, err)\n\t\ttime.Sleep(time.Millisecond * 50)\n\t\tvuHandle.gracefulStop()\n\t\ttime.Sleep(time.Millisecond * 1500)\n\t\tassert.EqualValues(t, 1, atomic.LoadUint32(&test.getVUCount))\n\t\tassert.EqualValues(t, 1, atomic.LoadUint32(&test.returnVUCount))\n\t\tassert.EqualValues(t, 0, atomic.LoadInt64(&test.interruptedIter))\n\t\tassert.EqualValues(t, 1, atomic.LoadInt64(&test.fullIterations))\n\t\terr = vuHandle.start()\n\t\trequire.NoError(t, err)\n\t\ttime.Sleep(time.Millisecond * 1500)\n\t\tcancel()\n\t\twg.Wait()\n\n\t\ttime.Sleep(time.Millisecond * 50)\n\t\tassert.EqualValues(t, 2, atomic.LoadUint32(&test.getVUCount))\n\t\tassert.EqualValues(t, 2, atomic.LoadUint32(&test.returnVUCount))\n\t\tassert.EqualValues(t, 1, atomic.LoadInt64(&test.interruptedIter))\n\t\tassert.EqualValues(t, 2, atomic.LoadInt64(&test.fullIterations))\n\t})\n\n\tt.Run(\"start after hardStop\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tlogHook := testutils.NewLogHook(logrus.DebugLevel)\n\t\ttestLog := logrus.New()\n\t\ttestLog.AddHook(logHook)\n\t\ttestLog.SetOutput(testutils.NewTestOutput(t))\n\t\t// testLog.Level = logrus.DebugLevel\n\t\tlogEntry := logrus.NewEntry(testLog)\n\t\ttest := &handleVUTest{runner: &minirunner.MiniRunner{}}\n\t\tctx, cancel := context.WithCancel(context.Background())\n\t\tdefer cancel()\n\n\t\tvuHandle := newStoppedVUHandle(ctx, test.getVU, test.returnVU, mockNextIterations, &BaseConfig{}, logEntry)\n\t\tvar wg sync.WaitGroup\n\t\twg.Go(func() {\n\t\t\tvuHandle.runLoopsIfPossible(test.runIter)\n\t\t})\n\t\terr := vuHandle.start()\n\t\trequire.NoError(t, err)\n\t\ttime.Sleep(time.Millisecond * 5)\n\t\tvuHandle.hardStop()\n\t\ttime.Sleep(time.Millisecond * 15)\n\t\tassert.EqualValues(t, 1, atomic.LoadUint32(&test.getVUCount))\n\t\tassert.EqualValues(t, 1, atomic.LoadUint32(&test.returnVUCount))\n\t\tassert.EqualValues(t, 1, atomic.LoadInt64(&test.interruptedIter))\n\t\tassert.EqualValues(t, 0, atomic.LoadInt64(&test.fullIterations))\n\t\terr = vuHandle.start()\n\t\trequire.NoError(t, err)\n\t\ttime.Sleep(time.Millisecond * 1500)\n\t\tcancel()\n\t\twg.Wait()\n\n\t\ttime.Sleep(time.Millisecond * 5)\n\t\tassert.EqualValues(t, 2, atomic.LoadUint32(&test.getVUCount))\n\t\tassert.EqualValues(t, 2, atomic.LoadUint32(&test.returnVUCount))\n\t\tassert.EqualValues(t, 2, atomic.LoadInt64(&test.interruptedIter))\n\t\tassert.EqualValues(t, 1, atomic.LoadInt64(&test.fullIterations))\n\t})\n}\n\nfunc BenchmarkVUHandleIterations(b *testing.B) {\n\tlogHook := testutils.NewLogHook(logrus.DebugLevel)\n\ttestLog := logrus.New()\n\ttestLog.AddHook(logHook)\n\t// testLog.Level = logrus.DebugLevel\n\tlogEntry := logrus.NewEntry(testLog)\n\n\tvar (\n\t\tgetVUCount      uint32\n\t\treturnVUCount   uint32\n\t\tinterruptedIter int64\n\t\tfullIterations  int64\n\t)\n\treset := func() {\n\t\tgetVUCount = 0\n\t\treturnVUCount = 0\n\t\tinterruptedIter = 0\n\t\tfullIterations = 0\n\t}\n\n\trunner := &minirunner.MiniRunner{}\n\trunner.Fn = func(_ context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error {\n\t\treturn nil\n\t}\n\tgetVU := func() (lib.InitializedVU, error) {\n\t\treturn runner.NewVU(context.Background(), uint64(atomic.AddUint32(&getVUCount, 1)), 0, nil)\n\t}\n\n\treturnVU := func(_ lib.InitializedVU) {\n\t\tatomic.AddUint32(&returnVUCount, 1)\n\t}\n\n\trunIter := func(ctx context.Context, _ lib.ActiveVU) bool {\n\t\t// Do nothing\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\t// Don't log errors or emit iterations metrics from cancelled iterations\n\t\t\tatomic.AddInt64(&interruptedIter, 1)\n\t\t\treturn false\n\t\tdefault:\n\t\t\tatomic.AddInt64(&fullIterations, 1)\n\t\t\treturn true\n\t\t}\n\t}\n\n\treset()\n\tctx, cancel := context.WithCancel(context.Background())\n\tdefer cancel()\n\n\tvuHandle := newStoppedVUHandle(ctx, getVU, returnVU, mockNextIterations, &BaseConfig{}, logEntry)\n\tvar wg sync.WaitGroup\n\twg.Go(func() {\n\t\tvuHandle.runLoopsIfPossible(runIter)\n\t})\n\tstart := time.Now()\n\tb.ResetTimer()\n\terr := vuHandle.start()\n\trequire.NoError(b, err)\n\ttime.Sleep(time.Second)\n\tcancel()\n\twg.Wait()\n\tb.StopTimer()\n\ttook := time.Since(start)\n\tb.ReportMetric(float64(atomic.LoadInt64(&fullIterations))/float64(took), \"iterations/ns\")\n}\n"
  },
  {
    "path": "lib/executors.go",
    "content": "package lib\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/ui/pb\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO: remove globals and use some type of explicit dependency injection?\n//\n//nolint:gochecknoglobals\nvar (\n\texecutorConfigTypesMutex   sync.RWMutex\n\texecutorConfigConstructors = make(map[string]ExecutorConfigConstructor)\n)\n\n// ExecutionStep is used by different executors to specify the planned number of\n// VUs they will need at a particular time. The times are relative to their\n// StartTime, i.e. they don't take into account the specific starting time of\n// the executor, as that will be considered by the external execution executor\n// separately.\n//\n// A slice [{t1, v1}, {t2, v2}, {t3, v3}, ..., {tn, vn}] of execution steps\n// means that an executor will need 0 VUs until t1, it will need v1 number of\n// VUs from time t1 until t2, need v2 number of VUs from time t2 to t3, and so\n// on. t1 is usually 0, tn is usually the same as GetMaxDuration() and vn is\n// usually 0.\n//\n// Keep in mind that t(i) may be exactly equal to t(i+i), when there's an abrupt\n// transition in the number of VUs required by an executor. For example, the\n// ramping-vus executor may have 0-duration stages, or it may scale up\n// VUs in its last stage right until the end. These immediate transitions cannot\n// be ignored, since the gracefulStop/gracefulRampDown options potentially allow\n// any started iterations to finish.\n//\n// []ExecutionStep is also used by the ScenarioConfigs, to represent the\n// amount of needed VUs among all executors, during the whole execution of a\n// test script. In that context, each executor's StartTime is accounted for and\n// included in the offsets.\ntype ExecutionStep struct {\n\tTimeOffset      time.Duration\n\tPlannedVUs      uint64\n\tMaxUnplannedVUs uint64\n}\n\n// TODO: make []ExecutionStep or []ExecutorConfig their own type?\n\n// ExecutorConfig is an interface that should be implemented by all executor config types\n//\n//nolint:interfacebloat // We don't have plan to split it.\ntype ExecutorConfig interface {\n\tValidate() []error\n\n\tGetName() string\n\tGetType() string\n\tGetStartTime() time.Duration\n\tGetGracefulStop() time.Duration\n\n\t// This is used to validate whether a particular script can run in the cloud\n\t// or, in the future, in the native k6 distributed execution. Currently only\n\t// the externally-controlled executor should return false.\n\tIsDistributable() bool\n\n\tGetEnv() map[string]string\n\t// Allows us to get the non-default function the executor should run, if it\n\t// has been specified.\n\t//\n\t// TODO: use interface{} so plain http requests can be specified?\n\tGetExec() string\n\tGetTags() map[string]string\n\n\t// Calculates the VU requirements in different stages of the executor's\n\t// execution, including any extensions caused by waiting for iterations to\n\t// finish with graceful stops or ramp-downs.\n\tGetExecutionRequirements(*ExecutionTuple) []ExecutionStep\n\tGetScenarioOptions() *ScenarioOptions\n\n\t// Return a human-readable description of the executor\n\tGetDescription(*ExecutionTuple) string\n\n\tNewExecutor(*ExecutionState, *logrus.Entry) (Executor, error)\n\n\t// HasWork reports whether there is any work for the executor to do with a given segment.\n\tHasWork(*ExecutionTuple) bool\n}\n\n// ScenarioOptions are options specific to a scenario. These include k6 browser\n// options, which are validated by the browser module, and not by k6 core.\ntype ScenarioOptions struct {\n\tBrowser map[string]any `json:\"browser\"`\n}\n\n// ScenarioState holds runtime scenario information returned by the k6/execution\n// JS module.\ntype ScenarioState struct {\n\tName, Executor string\n\tStartTime      time.Time\n\tProgressFn     func() (float64, []string)\n}\n\n// InitVUFunc is just a shorthand so we don't have to type the function\n// signature every time.\ntype InitVUFunc func(context.Context, *logrus.Entry) (InitializedVU, error)\n\n// Executor is the interface all executors should implement\ntype Executor interface {\n\tGetConfig() ExecutorConfig\n\tGetProgress() *pb.ProgressBar\n\tGetLogger() *logrus.Entry\n\n\tInit(ctx context.Context) error\n\tRun(ctx context.Context, engineOut chan<- metrics.SampleContainer) error\n}\n\n// PausableExecutor should be implemented by the executors that can be paused\n// and resumed in the middle of the test execution. Currently, only the\n// externally controlled executor implements it.\ntype PausableExecutor interface {\n\tSetPaused(bool) error\n}\n\n// LiveUpdatableExecutor should be implemented for the executors whose\n// configuration can be modified in the middle of the test execution. Currently,\n// only the manual execution executor implements it.\ntype LiveUpdatableExecutor interface {\n\tUpdateConfig(ctx context.Context, newConfig any) error\n}\n\n// ExecutorConfigConstructor is a simple function that returns a concrete\n// Config instance with the specified name and all default values correctly\n// initialized\ntype ExecutorConfigConstructor func(name string, rawJSON []byte) (ExecutorConfig, error)\n\n// RegisterExecutorConfigType adds the supplied ExecutorConfigConstructor as\n// the constructor for its type in the configConstructors map, in a thread-safe\n// manner\nfunc RegisterExecutorConfigType(configType string, constructor ExecutorConfigConstructor) {\n\texecutorConfigTypesMutex.Lock()\n\tdefer executorConfigTypesMutex.Unlock()\n\n\tif constructor == nil {\n\t\tpanic(\"executor configs: constructor is nil\")\n\t}\n\tif _, configTypeExists := executorConfigConstructors[configType]; configTypeExists {\n\t\tpanic(\"executor configs: lib.RegisterExecutorConfigType called twice for  \" + configType)\n\t}\n\n\texecutorConfigConstructors[configType] = constructor\n}\n\n// ScenarioConfigs can contain mixed executor config types\ntype ScenarioConfigs map[string]ExecutorConfig\n\n// UnmarshalJSON implements the json.Unmarshaler interface in a two-step manner,\n// creating the correct type of configs based on the `type` property.\nfunc (scs *ScenarioConfigs) UnmarshalJSON(data []byte) error {\n\tif len(data) == 0 {\n\t\treturn nil\n\t}\n\n\tif len(data) == 4 && string(data) == \"null\" {\n\t\treturn nil\n\t}\n\n\t// TODO: use a more sophisticated combination of dec.Token() and dec.More(),\n\t// which would allow us to support both arrays and maps for this config?\n\tvar protoConfigs map[string]protoExecutorConfig\n\tif err := StrictJSONUnmarshal(data, &protoConfigs); err != nil {\n\t\treturn err\n\t}\n\n\tresult := make(ScenarioConfigs, len(protoConfigs))\n\tfor k, v := range protoConfigs {\n\t\tif v.executorType == \"\" {\n\t\t\treturn fmt.Errorf(\"scenario '%s' doesn't have a specified executor type\", k)\n\t\t}\n\t\tconfig, err := GetParsedExecutorConfig(k, v.executorType, v.rawJSON)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tresult[k] = config\n\t}\n\n\t*scs = result\n\n\treturn nil\n}\n\n// Validate checks if all of the specified executor options make sense\nfunc (scs ScenarioConfigs) Validate() (errors []error) {\n\tfor name, exec := range scs {\n\t\tif execErr := exec.Validate(); len(execErr) != 0 {\n\t\t\terrors = append(errors,\n\t\t\t\tfmt.Errorf(\"scenario %s has configuration errors: %s\", name, ConcatErrors(execErr, \", \")))\n\t\t}\n\t}\n\treturn errors\n}\n\n// GetSortedConfigs returns a slice with the executor configurations,\n// sorted in a consistent and predictable manner. It is useful when we want or\n// have to avoid using maps with string keys (and tons of string lookups in\n// them) and avoid the unpredictable iterations over Go maps. Slices allow us\n// constant-time lookups and ordered iterations.\n//\n// The configs in the returned slice will be sorted by their start times in an\n// ascending order, and alphabetically by their names (which are unique) if\n// there are ties.\nfunc (scs ScenarioConfigs) GetSortedConfigs() []ExecutorConfig {\n\tconfigs := make([]ExecutorConfig, len(scs))\n\n\t// Populate the configs slice with sorted executor configs\n\ti := 0\n\tfor _, config := range scs {\n\t\tconfigs[i] = config // populate the slice in an unordered manner\n\t\ti++\n\t}\n\tsort.Slice(configs, func(a, b int) bool { // sort by (start time, name)\n\t\tswitch {\n\t\tcase configs[a].GetStartTime() < configs[b].GetStartTime():\n\t\t\treturn true\n\t\tcase configs[a].GetStartTime() == configs[b].GetStartTime():\n\t\t\treturn strings.Compare(configs[a].GetName(), configs[b].GetName()) < 0\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\t})\n\n\treturn configs\n}\n\n// GetFullExecutionRequirements combines the execution requirements from all of\n// the configured executors. It takes into account their start times and their\n// individual VU requirements and calculates the total VU requirements for each\n// moment in the test execution.\nfunc (scs ScenarioConfigs) GetFullExecutionRequirements(et *ExecutionTuple) []ExecutionStep {\n\tsortedConfigs := scs.GetSortedConfigs()\n\n\t// Combine the steps and requirements from all different executors, and\n\t// sort them by their time offset, counting the executors' startTimes as\n\t// well.\n\ttype trackedStep struct {\n\t\tExecutionStep\n\t\tconfigID int\n\t}\n\ttrackedSteps := []trackedStep{}\n\tfor configID, config := range sortedConfigs { // orderly iteration over a slice\n\t\tconfigStartTime := config.GetStartTime()\n\t\tconfigSteps := config.GetExecutionRequirements(et)\n\t\tfor _, cs := range configSteps {\n\t\t\tcs.TimeOffset += configStartTime // add the executor start time to the step time offset\n\t\t\ttrackedSteps = append(trackedSteps, trackedStep{cs, configID})\n\t\t}\n\t}\n\t// Sort by (time offset, config id). It's important that we use stable\n\t// sorting algorithm, since there could be steps with the same time from\n\t// the same executor and their order is important.\n\tsort.SliceStable(trackedSteps, func(a, b int) bool {\n\t\tif trackedSteps[a].TimeOffset == trackedSteps[b].TimeOffset {\n\t\t\treturn trackedSteps[a].configID < trackedSteps[b].configID\n\t\t}\n\n\t\treturn trackedSteps[a].TimeOffset < trackedSteps[b].TimeOffset\n\t})\n\n\t// Go through all of the sorted steps from all of the executors, and\n\t// build a new list of execution steps that consolidates all of their\n\t// requirements. If multiple executors have an execution step at exactly\n\t// the same time offset, they will be combined into a single new execution\n\t// step with the sum of the values from the previous ones.\n\tcurrentTimeOffset := time.Duration(0)\n\tcurrentPlannedVUs := make([]uint64, len(scs))\n\tcurrentMaxUnplannedVUs := make([]uint64, len(scs))\n\tsum := func(data []uint64) (result uint64) { // sigh...\n\t\tfor _, val := range data {\n\t\t\tresult += val\n\t\t}\n\t\treturn result\n\t}\n\tconsolidatedSteps := []ExecutionStep{}\n\taddCurrentStepIfDifferent := func() {\n\t\tnewPlannedVUs := sum(currentPlannedVUs)\n\t\tnewMaxUnplannedVUs := sum(currentMaxUnplannedVUs)\n\t\tstepsLen := len(consolidatedSteps)\n\t\tif stepsLen == 0 ||\n\t\t\tconsolidatedSteps[stepsLen-1].PlannedVUs != newPlannedVUs ||\n\t\t\tconsolidatedSteps[stepsLen-1].MaxUnplannedVUs != newMaxUnplannedVUs {\n\t\t\tconsolidatedSteps = append(consolidatedSteps, ExecutionStep{\n\t\t\t\tTimeOffset:      currentTimeOffset,\n\t\t\t\tPlannedVUs:      newPlannedVUs,\n\t\t\t\tMaxUnplannedVUs: newMaxUnplannedVUs,\n\t\t\t})\n\t\t}\n\t}\n\tfor _, step := range trackedSteps {\n\t\t// TODO: optimize by skipping some steps\n\t\t// If the time offset is different, create a new step with the current values\n\n\t\tcurrentTimeOffset = step.TimeOffset\n\t\tcurrentPlannedVUs[step.configID] = step.PlannedVUs\n\t\tcurrentMaxUnplannedVUs[step.configID] = step.MaxUnplannedVUs\n\t\taddCurrentStepIfDifferent()\n\t}\n\treturn consolidatedSteps\n}\n\n// GetParsedExecutorConfig returns a struct instance corresponding to the supplied\n// config type. It will be fully initialized - with both the default values of\n// the type, as well as with whatever the user had specified in the JSON\nfunc GetParsedExecutorConfig(name, configType string, rawJSON []byte) (result ExecutorConfig, err error) {\n\texecutorConfigTypesMutex.Lock()\n\tdefer executorConfigTypesMutex.Unlock()\n\n\tconstructor, exists := executorConfigConstructors[configType]\n\tif !exists {\n\t\treturn nil, fmt.Errorf(\"unknown executor type '%s'\", configType)\n\t}\n\treturn constructor(name, rawJSON)\n}\n\ntype protoExecutorConfig struct {\n\texecutorType string\n\trawJSON      json.RawMessage\n}\n\n// UnmarshalJSON unmarshals the base config (to get the type), but it also\n// stores the unprocessed JSON so we can parse the full config in the next step\nfunc (pc *protoExecutorConfig) UnmarshalJSON(b []byte) error {\n\tvar tmp struct {\n\t\tExecutorType string `json:\"executor\"`\n\t}\n\terr := json.Unmarshal(b, &tmp)\n\t*pc = protoExecutorConfig{tmp.ExecutorType, b}\n\treturn err\n}\n"
  },
  {
    "path": "lib/fsext/afero_links.go",
    "content": "package fsext\n\nimport (\n\t\"io/fs\"\n\n\t\"github.com/spf13/afero\"\n)\n\n// TODO: reimplement this while tackling https://github.com/grafana/k6/issues/1079\n\n// Fs represents a file system\ntype Fs = afero.Fs\n\n// FilePathSeparator is the FilePathSeparator to be used within a file system\nconst FilePathSeparator = afero.FilePathSeparator\n\n// NewMemMapFs returns a Fs that is in memory\nfunc NewMemMapFs() Fs {\n\treturn afero.NewMemMapFs()\n}\n\n// NewReadOnlyFs returns a Fs wrapping the provided one and returning error on any not read operation.\nfunc NewReadOnlyFs(fs Fs) Fs {\n\treturn afero.NewReadOnlyFs(fs)\n}\n\n// WriteFile writes the provided data to the provided fs in the provided filename\nfunc WriteFile(fs Fs, filename string, data []byte, perm fs.FileMode) error {\n\treturn afero.WriteFile(fs, filename, data, perm)\n}\n\n// ReadFile reads the whole file from the filesystem\nfunc ReadFile(fs Fs, filename string) ([]byte, error) {\n\treturn afero.ReadFile(fs, filename)\n}\n\n// ReadDir reads the info for each file in the provided dirname\nfunc ReadDir(fs Fs, dirname string) ([]fs.FileInfo, error) {\n\treturn afero.ReadDir(fs, dirname)\n}\n\n// NewOsFs returns a new wrapps os.Fs\nfunc NewOsFs() Fs {\n\treturn afero.NewOsFs()\n}\n\n// Exists checks if the provided path exists on the filesystem\nfunc Exists(fs Fs, path string) (bool, error) {\n\treturn afero.Exists(fs, path)\n}\n\n// IsDir checks if the provided path is a directory\nfunc IsDir(fs Fs, path string) (bool, error) {\n\t// TODO move fix here\n\treturn afero.IsDir(fs, path)\n}\n"
  },
  {
    "path": "lib/fsext/cacheonread.go",
    "content": "package fsext\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/spf13/afero\"\n)\n\n// ErrPathNeverRequestedBefore represent an error when path never opened/requested before\nvar ErrPathNeverRequestedBefore = errors.New(\"path never requested before\")\n\n// CacheOnReadFs is wrapper around afero.CacheOnReadFs with the ability to return the filesystem\n// that is used as cache\ntype CacheOnReadFs struct {\n\tafero.Fs\n\tcache afero.Fs\n\n\tlock       *sync.Mutex\n\tcachedOnly bool\n\tcached     map[string]bool\n}\n\n// OnlyCachedEnabler enables the mode of FS that allows to open\n// already opened files (e.g. serve from cache only)\ntype OnlyCachedEnabler interface {\n\tAllowOnlyCached()\n}\n\n// CacheLayerGetter provide a direct access to a cache layer\ntype CacheLayerGetter interface {\n\tGetCachingFs() afero.Fs\n}\n\n// NewCacheOnReadFs returns a new CacheOnReadFs\nfunc NewCacheOnReadFs(base, layer afero.Fs, cacheTime time.Duration) afero.Fs {\n\treturn &CacheOnReadFs{\n\t\tFs:    afero.NewCacheOnReadFs(base, layer, cacheTime),\n\t\tcache: layer,\n\n\t\tlock:       &sync.Mutex{},\n\t\tcachedOnly: false,\n\t\tcached:     make(map[string]bool),\n\t}\n}\n\n// GetCachingFs returns the afero.Fs being used for cache\nfunc (c *CacheOnReadFs) GetCachingFs() afero.Fs {\n\treturn c.cache\n}\n\n// AllowOnlyCached enables the cached only mode of the CacheOnReadFs\nfunc (c *CacheOnReadFs) AllowOnlyCached() {\n\tc.lock.Lock()\n\tc.cachedOnly = true\n\tc.lock.Unlock()\n}\n\n// Open opens file and track the history of opened files\n// if CacheOnReadFs is in the opened only mode it should return\n// an error if file wasn't open before\nfunc (c *CacheOnReadFs) Open(name string) (afero.File, error) {\n\tif err := c.checkOrRemember(name); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn c.Fs.Open(name)\n}\n\n// Stat returns a FileInfo describing the named file, or an error, if any\n// happens.\n// if CacheOnReadFs is in the opened only mode it should return\n// an error if path wasn't open before\nfunc (c *CacheOnReadFs) Stat(path string) (fs.FileInfo, error) {\n\tif err := c.checkOrRemember(path); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn c.Fs.Stat(path)\n}\n\nfunc (c *CacheOnReadFs) checkOrRemember(path string) error {\n\tc.lock.Lock()\n\tdefer c.lock.Unlock()\n\n\tif !c.cachedOnly {\n\t\tc.cached[path] = true\n\t} else if !c.cached[path] {\n\t\treturn ErrPathNeverRequestedBefore\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "lib/fsext/changepathfs.go",
    "content": "package fsext\n\nimport (\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/spf13/afero\"\n)\n\nvar _ afero.Lstater = (*ChangePathFs)(nil)\n\n// ChangePathFs is a filesystem that wraps another afero.Fs and changes all given paths from all\n// file and directory names, with a function, before calling the same method on the wrapped afero.Fs.\n// Heavily based on afero.BasePathFs\ntype ChangePathFs struct {\n\tsource afero.Fs\n\tfn     ChangePathFunc\n}\n\n// ChangePathFile is a file from ChangePathFs\ntype ChangePathFile struct {\n\tafero.File\n\toriginalName string\n}\n\n// NewChangePathFs return a ChangePathFs where all paths will be change with the provided funcs\nfunc NewChangePathFs(source afero.Fs, fn ChangePathFunc) *ChangePathFs {\n\treturn &ChangePathFs{source: source, fn: fn}\n}\n\n// ChangePathFunc is the function that will be called by ChangePathFs to change the path\ntype ChangePathFunc func(name string) (path string, err error)\n\n// NewTrimFilePathSeparatorFs is ChangePathFs that trims a Afero.FilePathSeparator from all paths\n// Heavily based on afero.BasePathFs\nfunc NewTrimFilePathSeparatorFs(source afero.Fs) *ChangePathFs {\n\treturn &ChangePathFs{source: source, fn: ChangePathFunc(func(name string) (path string, err error) {\n\t\tif !strings.HasPrefix(name, afero.FilePathSeparator) {\n\t\t\treturn name, fs.ErrNotExist\n\t\t}\n\n\t\treturn filepath.Clean(strings.TrimPrefix(name, afero.FilePathSeparator)), nil\n\t})}\n}\n\n// Name Returns the name of the file\nfunc (f *ChangePathFile) Name() string {\n\treturn f.originalName\n}\n\n// Chown changes the uid and gid of the named file.\nfunc (b *ChangePathFs) Chown(_ string, _, _ int) error {\n\tpanic(\"unimplemented Chown\")\n}\n\n// Chtimes changes the access and modification times of the named file\nfunc (b *ChangePathFs) Chtimes(name string, atime, mtime time.Time) (err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn &fs.PathError{Op: \"chtimes\", Path: name, Err: err}\n\t}\n\treturn b.source.Chtimes(newName, atime, mtime)\n}\n\n// Chmod changes the mode of the named file to mode.\nfunc (b *ChangePathFs) Chmod(name string, mode fs.FileMode) (err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn &fs.PathError{Op: \"chmod\", Path: name, Err: err}\n\t}\n\treturn b.source.Chmod(newName, mode)\n}\n\n// Name return the name of this FileSystem\nfunc (b *ChangePathFs) Name() string {\n\treturn \"ChangePathFs\"\n}\n\n// Stat returns a FileInfo describing the named file, or an error, if any\n// happens.\nfunc (b *ChangePathFs) Stat(name string) (fi fs.FileInfo, err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn nil, &fs.PathError{Op: \"stat\", Path: name, Err: err}\n\t}\n\treturn b.source.Stat(newName)\n}\n\n// Rename renames a file.\nfunc (b *ChangePathFs) Rename(oldName, newName string) (err error) {\n\tvar newOldName, newNewName string\n\tif newOldName, err = b.fn(oldName); err != nil {\n\t\treturn &fs.PathError{Op: \"rename\", Path: oldName, Err: err}\n\t}\n\tif newNewName, err = b.fn(newName); err != nil {\n\t\treturn &fs.PathError{Op: \"rename\", Path: newName, Err: err}\n\t}\n\treturn b.source.Rename(newOldName, newNewName)\n}\n\n// RemoveAll removes a directory path and any children it contains. It\n// does not fail if the path does not exist (return nil).\nfunc (b *ChangePathFs) RemoveAll(name string) (err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn &fs.PathError{Op: \"remove_all\", Path: name, Err: err}\n\t}\n\treturn b.source.RemoveAll(newName)\n}\n\n// Remove removes a file identified by name, returning an error, if any\n// happens.\nfunc (b *ChangePathFs) Remove(name string) (err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn &fs.PathError{Op: \"remove\", Path: name, Err: err}\n\t}\n\treturn b.source.Remove(newName)\n}\n\n// OpenFile opens a file using the given flags and the given mode.\nfunc (b *ChangePathFs) OpenFile(name string, flag int, mode fs.FileMode) (f afero.File, err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn nil, &fs.PathError{Op: \"openfile\", Path: name, Err: err}\n\t}\n\tsourcef, err := b.source.OpenFile(newName, flag, mode)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ChangePathFile{File: sourcef, originalName: name}, nil\n}\n\n// Open opens a file, returning it or an error, if any happens.\nfunc (b *ChangePathFs) Open(name string) (f afero.File, err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn nil, &fs.PathError{Op: \"open\", Path: name, Err: err}\n\t}\n\tsourcef, err := b.source.Open(newName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ChangePathFile{File: sourcef, originalName: name}, nil\n}\n\n// Mkdir creates a directory in the filesystem, return an error if any\n// happens.\nfunc (b *ChangePathFs) Mkdir(name string, mode fs.FileMode) (err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn &fs.PathError{Op: \"mkdir\", Path: name, Err: err}\n\t}\n\treturn b.source.Mkdir(newName, mode)\n}\n\n// MkdirAll creates a directory path and all parents that does not exist\n// yet.\nfunc (b *ChangePathFs) MkdirAll(name string, mode fs.FileMode) (err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn &fs.PathError{Op: \"mkdir\", Path: name, Err: err}\n\t}\n\treturn b.source.MkdirAll(newName, mode)\n}\n\n// Create creates a file in the filesystem, returning the file and an\n// error, if any happens\nfunc (b *ChangePathFs) Create(name string) (f afero.File, err error) {\n\tvar newName string\n\tif newName, err = b.fn(name); err != nil {\n\t\treturn nil, &fs.PathError{Op: \"create\", Path: name, Err: err}\n\t}\n\tsourcef, err := b.source.Create(newName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ChangePathFile{File: sourcef, originalName: name}, nil\n}\n\n// LstatIfPossible implements the afero.Lstater interface\nfunc (b *ChangePathFs) LstatIfPossible(name string) (fs.FileInfo, bool, error) {\n\tvar newName string\n\tnewName, err := b.fn(name)\n\tif err != nil {\n\t\treturn nil, false, &fs.PathError{Op: \"lstat\", Path: name, Err: err}\n\t}\n\tif lstater, ok := b.source.(afero.Lstater); ok {\n\t\treturn lstater.LstatIfPossible(newName)\n\t}\n\tfi, err := b.source.Stat(newName)\n\treturn fi, false, err\n}\n"
  },
  {
    "path": "lib/fsext/changepathfs_test.go",
    "content": "package fsext\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"path\"\n\t\"strings\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/spf13/afero\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestChangePathFs(t *testing.T) {\n\tt.Parallel()\n\tfilePath := \"/another/path/to/file.txt\"\n\tnewTestFS := func() *ChangePathFs {\n\t\tm := afero.NewMemMapFs()\n\t\tprefix := \"/another/\"\n\t\tc := NewChangePathFs(m, ChangePathFunc(func(name string) (string, error) {\n\t\t\tif !strings.HasPrefix(name, prefix) {\n\t\t\t\treturn \"\", fmt.Errorf(\"path %s doesn't  start with `%s`\", name, prefix)\n\t\t\t}\n\t\t\treturn name[len(prefix):], nil\n\t\t}))\n\n\t\trequire.Equal(t, \"ChangePathFs\", c.Name())\n\t\tf, err := c.Create(filePath)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, filePath, f.Name())\n\t\treturn c\n\t}\n\tt.Run(\"Create\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\n\t\t/** TODO figure out if this is error in MemMapFs\n\t\t_, err = c.Create(filePath)\n\t\trequire.Error(t, err)\n\t\trequire.True(t, os.IsExist(err))\n\t\t*/\n\n\t\t_, err := c.Create(\"/notanother/path/to/file.txt\")\n\t\tcheckErrorPath(t, err, \"/notanother/path/to/file.txt\")\n\t})\n\n\tt.Run(\"Mkdir\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\trequire.NoError(t, c.Mkdir(\"/another/path/too\", 0o644))\n\t\tcheckErrorPath(t, c.Mkdir(\"/notanother/path/too\", 0o644), \"/notanother/path/too\")\n\t})\n\n\tt.Run(\"MkdirAll\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\trequire.NoError(t, c.MkdirAll(\"/another/pattth/too\", 0o644))\n\t\tcheckErrorPath(t, c.MkdirAll(\"/notanother/pattth/too\", 0o644), \"/notanother/pattth/too\")\n\t})\n\n\tt.Run(\"Open\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\tf, err := c.Open(filePath)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, filePath, f.Name())\n\n\t\t_, err = c.Open(\"/notanother/path/to/file.txt\")\n\t\tcheckErrorPath(t, err, \"/notanother/path/to/file.txt\")\n\t})\n\n\tt.Run(\"OpenFile\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\tf, err := c.OpenFile(filePath, syscall.O_RDWR, 0o644)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, filePath, f.Name())\n\n\t\t_, err = c.OpenFile(\"/notanother/path/to/file.txt\", syscall.O_RDWR, 0o644)\n\t\tcheckErrorPath(t, err, \"/notanother/path/to/file.txt\")\n\n\t\t_, err = c.OpenFile(\"/another/nonexistant\", syscall.O_RDWR, 0o644)\n\t\trequire.True(t, errors.Is(err, fs.ErrNotExist))\n\t})\n\n\tt.Run(\"Stat Chmod Chtimes\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\tinfo, err := c.Stat(filePath)\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, \"file.txt\", info.Name())\n\n\t\tsometime := time.Unix(10000, 13)\n\t\trequire.NotEqual(t, sometime, info.ModTime())\n\t\trequire.NoError(t, c.Chtimes(filePath, time.Now(), sometime))\n\t\trequire.Equal(t, sometime, info.ModTime())\n\n\t\tmode := fs.FileMode(0o007)\n\t\trequire.NotEqual(t, mode, info.Mode())\n\t\trequire.NoError(t, c.Chmod(filePath, mode))\n\t\trequire.Equal(t, mode, info.Mode())\n\n\t\t_, err = c.Stat(\"/notanother/path/to/file.txt\")\n\t\tcheckErrorPath(t, err, \"/notanother/path/to/file.txt\")\n\n\t\tcheckErrorPath(t, c.Chtimes(\"/notanother/path/to/file.txt\", time.Now(), time.Now()), \"/notanother/path/to/file.txt\")\n\n\t\tcheckErrorPath(t, c.Chmod(\"/notanother/path/to/file.txt\", mode), \"/notanother/path/to/file.txt\")\n\t})\n\n\tt.Run(\"LstatIfPossible\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\tinfo, ok, err := c.LstatIfPossible(filePath)\n\t\trequire.NoError(t, err)\n\t\trequire.False(t, ok)\n\t\trequire.Equal(t, \"file.txt\", info.Name())\n\n\t\t_, _, err = c.LstatIfPossible(\"/notanother/path/to/file.txt\")\n\t\tcheckErrorPath(t, err, \"/notanother/path/to/file.txt\")\n\t})\n\n\tt.Run(\"Rename\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\tinfo, err := c.Stat(filePath)\n\t\trequire.NoError(t, err)\n\t\trequire.False(t, info.IsDir())\n\n\t\trequire.NoError(t, c.Rename(filePath, \"/another/path/to/file.doc\"))\n\n\t\t_, err = c.Stat(filePath)\n\t\trequire.Error(t, err)\n\t\trequire.True(t, errors.Is(err, fs.ErrNotExist))\n\n\t\tinfo, err = c.Stat(\"/another/path/to/file.doc\")\n\t\trequire.NoError(t, err)\n\t\trequire.False(t, info.IsDir())\n\n\t\tcheckErrorPath(t,\n\t\t\tc.Rename(\"/notanother/path/to/file.txt\", \"/another/path/to/file.doc\"),\n\t\t\t\"/notanother/path/to/file.txt\")\n\n\t\tcheckErrorPath(t,\n\t\t\tc.Rename(filePath, \"/notanother/path/to/file.doc\"),\n\t\t\t\"/notanother/path/to/file.doc\")\n\t})\n\n\tt.Run(\"Remove\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tc := newTestFS()\n\t\tremoveFilePath := \"/another/file/to/remove.txt\"\n\t\t_, err := c.Create(removeFilePath)\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, c.Remove(removeFilePath))\n\n\t\t_, err = c.Stat(removeFilePath)\n\t\trequire.Error(t, err)\n\t\trequire.True(t, errors.Is(err, fs.ErrNotExist))\n\n\t\t_, err = c.Create(removeFilePath)\n\t\trequire.NoError(t, err)\n\n\t\trequire.NoError(t, c.RemoveAll(path.Dir(removeFilePath)))\n\n\t\t_, err = c.Stat(removeFilePath)\n\t\trequire.Error(t, err)\n\t\trequire.True(t, errors.Is(err, fs.ErrNotExist))\n\n\t\tcheckErrorPath(t,\n\t\t\tc.Remove(\"/notanother/path/to/file.txt\"),\n\t\t\t\"/notanother/path/to/file.txt\")\n\n\t\tcheckErrorPath(t,\n\t\t\tc.RemoveAll(\"/notanother/path/to\"),\n\t\t\t\"/notanother/path/to\")\n\t})\n}\n\nfunc checkErrorPath(t *testing.T, err error, path string) {\n\trequire.Error(t, err)\n\tvar perr *fs.PathError\n\trequire.True(t, errors.As(err, &perr))\n\trequire.Equal(t, perr.Path, path)\n}\n"
  },
  {
    "path": "lib/fsext/filepath.go",
    "content": "// Package fsext provides extended file system functions\npackage fsext\n\nimport (\n\t\"path/filepath\"\n)\n\n// JoinFilePath is a wrapper around filepath.Join\n// starting go 1.20 on Windows, Clean (that is using inside the\n// filepath.Join) does not modify the volume name\n// other than to replace occurrences of \"/\" with `\\`.\n// that's why we need to add a leading slash to the path\n// go.1.19: filepath.Join(\"\\\\c:\", \"test\")  // \\c:\\test\n// go.1.20: filepath.Join(\"\\\\c:\", \"test\")  // \\c:test\nfunc JoinFilePath(b, p string) string {\n\treturn filepath.Join(b, filepath.Clean(\"/\"+p))\n}\n\n// Abs returns an absolute representation of path.\n//\n// this implementation allows k6 to handle absolute paths starting from\n// the current drive on windows like `\\users\\noname\\...`. It makes it easier\n// to test and is needed for archive execution under windows (it always consider '/...' as an\n// absolute path).\n//\n// If the path is not absolute it will be joined with root\n// to turn it into an absolute path. The root path is assumed\n// to be a directory.\n//\n// Because k6 does not interact with the OS itself, but with\n// its own virtual file system, it needs to be able to resolve\n// the root path of the file system. In most cases this would be\n// the bundle or init environment's working directory.\nfunc Abs(root, path string) string {\n\tif path[0] != '/' && path[0] != '\\\\' && !filepath.IsAbs(path) {\n\t\tpath = filepath.Join(root, path)\n\t}\n\tpath = filepath.Clean(path)\n\n\tif path[0:1] != FilePathSeparator {\n\t\tpath = FilePathSeparator + path\n\t}\n\n\treturn path\n}\n"
  },
  {
    "path": "lib/fsext/filepath_unix_test.go",
    "content": "//go:build unix\n\npackage fsext_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestJoinFilePath(t *testing.T) {\n\tt.Parallel()\n\n\ttype args struct {\n\t\tb string\n\t\tp string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"join root and some catalog\",\n\t\t\targs: args{\n\t\t\t\tb: \"/\",\n\t\t\t\tp: \"test\",\n\t\t\t},\n\t\t\twant: \"/test\",\n\t\t},\n\t\t{\n\t\t\tname: \"join root and some catalog with leading slash\",\n\t\t\targs: args{\n\t\t\t\tb: \"/\",\n\t\t\t\tp: \"/test\",\n\t\t\t},\n\t\t\twant: \"/test\",\n\t\t},\n\t\t{\n\t\t\tname: \"join root and some catalog with several leading slash\",\n\t\t\targs: args{\n\t\t\t\tb: \"/\",\n\t\t\t\tp: \"//test\",\n\t\t\t},\n\t\t\twant: \"/test\",\n\t\t},\n\t\t{\n\t\t\tname: \"join catalog and some other catalog\",\n\t\t\targs: args{\n\t\t\t\tb: \"/path/to\",\n\t\t\t\tp: \"test\",\n\t\t\t},\n\t\t\twant: \"/path/to/test\",\n\t\t},\n\t\t{\n\t\t\tname: \"join catalog and some other catalog with leading slash\",\n\t\t\targs: args{\n\t\t\t\tb: \"/path/to\",\n\t\t\t\tp: \"/test\",\n\t\t\t},\n\t\t\twant: \"/path/to/test\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, tt.want, fsext.JoinFilePath(tt.args.b, tt.args.p))\n\t\t})\n\t}\n}\n\nfunc TestAbs(t *testing.T) {\n\tt.Parallel()\n\n\ttype args struct {\n\t\troot string\n\t\tpath string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"absolute path\",\n\t\t\targs: args{\n\t\t\t\troot: \"/\",\n\t\t\t\tpath: \"/test\",\n\t\t\t},\n\t\t\twant: \"/test\",\n\t\t},\n\t\t{\n\t\t\tname: \"relative path\",\n\t\t\targs: args{\n\t\t\t\troot: \"/\",\n\t\t\t\tpath: \"test\",\n\t\t\t},\n\t\t\twant: \"/test\",\n\t\t},\n\t\t{\n\t\t\tname: \"relative path with leading dot\",\n\t\t\targs: args{\n\t\t\t\troot: \"/\",\n\t\t\t\tpath: \"./test\",\n\t\t\t},\n\t\t\twant: \"/test\",\n\t\t},\n\t\t{\n\t\t\tname: \"relative path with leading double dot\",\n\t\t\targs: args{\n\t\t\t\troot: \"/\",\n\t\t\t\tpath: \"../test\",\n\t\t\t},\n\t\t\twant: \"/test\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, tt.want, fsext.Abs(tt.args.root, tt.args.path))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "lib/fsext/filepath_windows_test.go",
    "content": "//go:build windows\n\npackage fsext_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc TestJoinFilePath(t *testing.T) {\n\tt.Parallel()\n\n\ttype args struct {\n\t\tb string\n\t\tp string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"join volume and some folder\",\n\t\t\targs: args{\n\t\t\t\tb: \"\\\\c:\",\n\t\t\t\tp: \"test\",\n\t\t\t},\n\t\t\twant: \"\\\\c:\\\\test\",\n\t\t},\n\t\t{\n\t\t\tname: \"join volume and some folder with leading slash\",\n\t\t\targs: args{\n\t\t\t\tb: \"\\\\c:\",\n\t\t\t\tp: \"\\\\test\",\n\t\t\t},\n\t\t\twant: \"\\\\c:\\\\test\",\n\t\t},\n\t\t{\n\t\t\tname: \"join folder and folder\",\n\t\t\targs: args{\n\t\t\t\tb: \"\\\\c:\\\\to\",\n\t\t\t\tp: \"test\",\n\t\t\t},\n\t\t\twant: \"\\\\c:\\\\to\\\\test\",\n\t\t},\n\t\t{\n\t\t\tname: \"join folder and folder with leading slash\",\n\t\t\targs: args{\n\t\t\t\tb: \"\\\\c:\\\\to\",\n\t\t\t\tp: \"\\\\test\",\n\t\t\t},\n\t\t\twant: \"\\\\c:\\\\to\\\\test\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\ttt := tt\n\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, tt.want, fsext.JoinFilePath(tt.args.b, tt.args.p))\n\t\t})\n\t}\n}\n\nfunc TestAbs(t *testing.T) {\n\tt.Parallel()\n\n\ttype args struct {\n\t\troot string\n\t\tpath string\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant string\n\t}{\n\t\t{\n\t\t\tname: \"absolute path\",\n\t\t\targs: args{\n\t\t\t\troot: \"\\\\\",\n\t\t\t\tpath: \"\\\\test\",\n\t\t\t},\n\t\t\twant: \"\\\\test\",\n\t\t},\n\t\t{\n\t\t\tname: \"relative path\",\n\t\t\targs: args{\n\t\t\t\troot: \"\\\\\",\n\t\t\t\tpath: \"test\",\n\t\t\t},\n\t\t\twant: \"\\\\test\",\n\t\t},\n\t\t{\n\t\t\tname: \"relative path with leading dot\",\n\t\t\targs: args{\n\t\t\t\troot: \"\\\\\",\n\t\t\t\tpath: \".\\\\test\",\n\t\t\t},\n\t\t\twant: \"\\\\test\",\n\t\t},\n\t\t{\n\t\t\tname: \"relative path with leading double dot\",\n\t\t\targs: args{\n\t\t\t\troot: \"\\\\\",\n\t\t\t\tpath: \"..\\\\test\",\n\t\t\t},\n\t\t\twant: \"\\\\test\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\ttt := tt\n\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tassert.Equal(t, tt.want, fsext.Abs(tt.args.root, tt.args.path))\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "lib/fsext/trimpathseparator_test.go",
    "content": "package fsext\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/spf13/afero\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTrimAferoPathSeparatorFs(t *testing.T) {\n\tt.Parallel()\n\tm := afero.NewMemMapFs()\n\tf := NewTrimFilePathSeparatorFs(m)\n\texpecteData := []byte(\"something\")\n\terr := afero.WriteFile(f, filepath.FromSlash(\"/path/to/somewhere\"), expecteData, 0o644)\n\trequire.NoError(t, err)\n\tdata, err := afero.ReadFile(m, \"/path/to/somewhere\")\n\trequire.Error(t, err)\n\trequire.True(t, errors.Is(err, fs.ErrNotExist))\n\trequire.Nil(t, data)\n\n\tdata, err = afero.ReadFile(m, \"path/to/somewhere\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, expecteData, data)\n\n\terr = afero.WriteFile(f, filepath.FromSlash(\"path/without/separtor\"), expecteData, 0o644)\n\trequire.Error(t, err)\n\trequire.True(t, errors.Is(err, fs.ErrNotExist))\n\n\terr = afero.WriteFile(f, filepath.FromSlash(\"/path/to//otherpath\"), expecteData, 0o644)\n\trequire.NoError(t, err)\n\tdata, err = afero.ReadFile(m, \"path/to/otherpath\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, expecteData, data)\n}\n"
  },
  {
    "path": "lib/fsext/walk.go",
    "content": "package fsext\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"sort\"\n\n\t\"github.com/spf13/afero\"\n)\n\n// Walk implements afero.Walk, but in a way that it doesn't loop to infinity and doesn't have\n// problems if a given path part looks like a windows volume name\nfunc Walk(fs afero.Fs, root string, walkFn filepath.WalkFunc) error {\n\tinfo, err := fs.Stat(root)\n\tif err != nil {\n\t\treturn walkFn(root, nil, err)\n\t}\n\treturn walk(fs, root, info, walkFn)\n}\n\n// readDirNames reads the directory named by dirname and returns\n// a sorted list of directory entries.\n// adapted from https://github.com/spf13/afero/blob/master/path.go#L27\nfunc readDirNames(fs afero.Fs, dirname string) ([]string, error) {\n\tf, err := fs.Open(dirname)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tinfos, err := f.Readdir(-1)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\terr = f.Close()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnames := make([]string, len(infos))\n\tfor i, info := range infos {\n\t\tnames[i] = info.Name()\n\t}\n\tsort.Strings(names)\n\treturn names, nil\n}\n\n// walk recursively descends path, calling walkFn\n// adapted from https://github.com/spf13/afero/blob/master/path.go#L27\nfunc walk(fileSystem afero.Fs, path string, info fs.FileInfo, walkFn filepath.WalkFunc) error {\n\terr := walkFn(path, info, nil)\n\tif err != nil {\n\t\tif info.IsDir() && errors.Is(err, filepath.SkipDir) {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\n\tif !info.IsDir() {\n\t\treturn nil\n\t}\n\n\tnames, err := readDirNames(fileSystem, path)\n\tif err != nil {\n\t\treturn walkFn(path, info, err)\n\t}\n\n\tfor _, name := range names {\n\t\tfilename := JoinFilePath(path, name)\n\t\tfileInfo, err := fileSystem.Stat(filename)\n\t\tif err != nil {\n\t\t\tif err = walkFn(filename, fileInfo, err); err != nil && !errors.Is(err, filepath.SkipDir) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\n\t\terr = walk(fileSystem, filename, fileInfo, walkFn)\n\t\tif err != nil {\n\t\t\tif !fileInfo.IsDir() || !errors.Is(err, filepath.SkipDir) {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "lib/helpers.go",
    "content": "package lib\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n)\n\n// StrictJSONUnmarshal decodes a JSON in a strict manner, emitting an error if there\n// are unknown fields or unexpected data\nfunc StrictJSONUnmarshal(data []byte, v any) error {\n\tdec := json.NewDecoder(bytes.NewReader(data))\n\tdec.DisallowUnknownFields()\n\tdec.UseNumber()\n\n\tif err := dec.Decode(&v); err != nil {\n\t\treturn err\n\t}\n\tif dec.More() {\n\t\t// TODO: use a custom error?\n\t\treturn fmt.Errorf(\"unexpected data after the JSON object\")\n\t}\n\treturn nil\n}\n\n// GetMaxPlannedVUs returns the maximum number of planned VUs at any stage of\n// the execution plan.\nfunc GetMaxPlannedVUs(steps []ExecutionStep) (result uint64) {\n\tfor _, s := range steps {\n\t\tstepMaxPlannedVUs := s.PlannedVUs\n\t\tif stepMaxPlannedVUs > result {\n\t\t\tresult = stepMaxPlannedVUs\n\t\t}\n\t}\n\treturn result\n}\n\n// GetMaxPossibleVUs returns the maximum number of planned + unplanned (i.e.\n// initialized mid-test) VUs at any stage of the execution plan. Unplanned VUs\n// are possible in some executors, like the arrival-rate ones, as a way to have\n// a low number of pre-allocated VUs, but be able to initialize new ones in the\n// middle of the test, if needed. For example, if the remote system starts\n// responding very slowly and all of the pre-allocated VUs are waiting for it.\n//\n// IMPORTANT 1: Getting planned and unplanned VUs separately for the whole\n// duration of a test can often lead to mistakes. That's why this function is\n// called GetMaxPossibleVUs() and why there is no GetMaxUnplannedVUs() function.\n//\n// As an example, imagine that you have an executor with MaxPlannedVUs=20 and\n// MaxUnplannedVUs=0, followed immediately after by another executor with\n// MaxPlannedVUs=10 and MaxUnplannedVUs=10. The MaxPlannedVUs number for the\n// whole test is 20, and MaxUnplannedVUs is 10, but since those executors won't\n// run concurrently, MaxVUs for the whole test is not 30, rather it's 20, since\n// 20 VUs will be sufficient to run the whole test.\n//\n// IMPORTANT 2: this has one very important exception. The externally controlled\n// executor doesn't use the MaxUnplannedVUs (i.e. this function will return 0),\n// since their initialization and usage is directly controlled by the user and\n// is effectively bounded only by the resources of the machine k6 is running on.\nfunc GetMaxPossibleVUs(steps []ExecutionStep) (result uint64) {\n\tfor _, s := range steps {\n\t\tstepMaxPossibleVUs := s.PlannedVUs + s.MaxUnplannedVUs\n\t\tif stepMaxPossibleVUs > result {\n\t\t\tresult = stepMaxPossibleVUs\n\t\t}\n\t}\n\treturn result\n}\n\n// GetEndOffset returns the time offset of the last step of the execution plan,\n// and whether that step is a final one, i.e. whether the number of planned or\n// unplanned is 0.\nfunc GetEndOffset(steps []ExecutionStep) (lastStepOffset time.Duration, isFinal bool) {\n\tif len(steps) == 0 {\n\t\treturn 0, true\n\t}\n\tlastStep := steps[len(steps)-1]\n\treturn lastStep.TimeOffset, (lastStep.PlannedVUs == 0 && lastStep.MaxUnplannedVUs == 0)\n}\n\n// ConcatErrors is a a helper function for joining error messages into a single\n// string.\n//\n// TODO: use Go 2.0/xerrors style errors so we don't lose error type information and\n// metadata.\nfunc ConcatErrors(errors []error, separator string) string {\n\terrStrings := make([]string, len(errors))\n\tfor i, e := range errors {\n\t\terrStrings[i] = e.Error()\n\t}\n\treturn strings.Join(errStrings, separator)\n}\n"
  },
  {
    "path": "lib/helpers_test.go",
    "content": "package lib\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestStrictJSONUnmarshal(t *testing.T) {\n\tt.Parallel()\n\ttype someElement struct {\n\t\tData  int               `json:\"data\"`\n\t\tProps map[string]string `json:\"props\"`\n\t}\n\n\ttestCases := []struct {\n\t\tdata           string\n\t\texpectedError  bool\n\t\tdestination    any\n\t\texpectedResult any\n\t}{\n\t\t{``, true, &someElement{}, nil},\n\t\t{`123`, true, &someElement{}, nil},\n\t\t{`\"blah\"`, true, &someElement{}, nil},\n\t\t{`null`, false, &someElement{}, &someElement{}},\n\t\t{\n\t\t\t`{\"data\": 123, \"props\": {\"test\": \"mest\"}}`, false, &someElement{},\n\t\t\t&someElement{123, map[string]string{\"test\": \"mest\"}},\n\t\t},\n\t\t{`{\"data\": 123, \"props\": {\"test\": \"mest\"}}asdg`, true, &someElement{}, nil},\n\t}\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"TestCase#%d\", i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\terr := StrictJSONUnmarshal([]byte(tc.data), &tc.destination)\n\t\t\tif tc.expectedError {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, tc.expectedResult, tc.destination)\n\t\t})\n\t}\n}\n\n// TODO: test EventStream very thoroughly\n"
  },
  {
    "path": "lib/limiter.go",
    "content": "package lib\n\nimport (\n\t\"sync\"\n)\n\n// SlotLimiter can restrict the concurrent execution of tasks to the given `slots` limit\ntype SlotLimiter chan struct{}\n\n// NewSlotLimiter initializes and returns a new SlotLimiter with the given slot count\nfunc NewSlotLimiter(slots int) SlotLimiter {\n\tif slots <= 0 {\n\t\treturn nil\n\t}\n\n\tch := make(chan struct{}, slots)\n\tfor range slots {\n\t\tch <- struct{}{}\n\t}\n\treturn ch\n}\n\n// Begin uses up a slot to denote the start of a task exeuction. It's a noop if the number\n// of slots is 0, and if no slots are available, it blocks and waits.\nfunc (sl SlotLimiter) Begin() {\n\tif sl != nil {\n\t\t<-sl\n\t}\n}\n\n// End restores a slot and should be called at the end of a taks execution, preferably\n// from a defer statement right after Begin()\nfunc (sl SlotLimiter) End() {\n\tif sl != nil {\n\t\tsl <- struct{}{}\n\t}\n}\n\n// MultiSlotLimiter can restrict the concurrent execution of different groups of tasks\n// to the given `slots` limit. Each group is represented with a string ID.\ntype MultiSlotLimiter struct {\n\tm     map[string]SlotLimiter\n\tslots int\n\tmutex sync.Mutex\n}\n\n// NewMultiSlotLimiter initializes and returns a new MultiSlotLimiter with the given slot count\n// TODO: move to lib and use something better than a mutex? sync.Map perhaps?\nfunc NewMultiSlotLimiter(slots int) *MultiSlotLimiter {\n\treturn &MultiSlotLimiter{make(map[string]SlotLimiter), slots, sync.Mutex{}}\n}\n\n// Slot is used to retrieve the corresponding slot to the given string ID. If no slot with that ID exists,\n// it creates it and saves it for future use. It is safe to call this method concurrently.\nfunc (l *MultiSlotLimiter) Slot(s string) SlotLimiter {\n\tif l.slots == 0 {\n\t\treturn nil\n\t}\n\n\tl.mutex.Lock()\n\tdefer l.mutex.Unlock()\n\n\tll, ok := l.m[s]\n\tif !ok {\n\t\ttmp := NewSlotLimiter(l.slots)\n\t\tll = tmp\n\t\tl.m[s] = ll\n\t}\n\treturn ll\n}\n"
  },
  {
    "path": "lib/limiter_test.go",
    "content": "package lib\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSlotLimiterSingleSlot(t *testing.T) {\n\tt.Parallel()\n\tl := NewSlotLimiter(1)\n\tl.Begin()\n\tdone := false\n\tgo func() {\n\t\tdone = true\n\t\tl.End()\n\t}()\n\tl.Begin()\n\tassert.True(t, done)\n\tl.End()\n}\n\nfunc TestSlotLimiterUnlimited(t *testing.T) {\n\tt.Parallel()\n\tl := NewSlotLimiter(0)\n\tl.Begin()\n\tl.Begin()\n\tl.Begin()\n}\n\nfunc TestSlotLimiters(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct{ limit, launches, expMid int }{\n\t\t{0, 0, 0},\n\t\t{0, 1, 1},\n\t\t{0, 5, 5},\n\t\t{1, 5, 1},\n\t\t{2, 5, 2},\n\t\t{5, 6, 5},\n\t\t{6, 5, 5},\n\t\t{10, 7, 7},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"limit=%d,launches=%d\", tc.limit, tc.launches), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tl := NewSlotLimiter(tc.limit)\n\t\t\twg := sync.WaitGroup{}\n\n\t\t\tswitch {\n\t\t\tcase tc.limit == 0:\n\t\t\t\twg.Add(tc.launches)\n\t\t\tcase tc.launches < tc.limit:\n\t\t\t\twg.Add(tc.launches)\n\t\t\tdefault:\n\t\t\t\twg.Add(tc.limit)\n\t\t\t}\n\n\t\t\tvar counter uint32\n\n\t\t\tfor i := 0; i < tc.launches; i++ {\n\t\t\t\tgo func() {\n\t\t\t\t\tl.Begin()\n\t\t\t\t\tatomic.AddUint32(&counter, 1)\n\t\t\t\t\twg.Done()\n\t\t\t\t}()\n\t\t\t}\n\t\t\twg.Wait()\n\t\t\tassert.EqualValues(t, tc.expMid, atomic.LoadUint32(&counter))\n\n\t\t\tif tc.limit != 0 && tc.limit < tc.launches {\n\t\t\t\twg.Add(tc.launches - tc.limit)\n\t\t\t\tfor i := 0; i < tc.launches; i++ {\n\t\t\t\t\tl.End()\n\t\t\t\t}\n\t\t\t\twg.Wait()\n\t\t\t\tassert.EqualValues(t, tc.launches, atomic.LoadUint32(&counter))\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestMultiSlotLimiter(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"0\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tl := NewMultiSlotLimiter(0)\n\t\tassert.Nil(t, l.Slot(\"test\"))\n\t})\n\tt.Run(\"1\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tl := NewMultiSlotLimiter(1)\n\t\tassert.Equal(t, l.Slot(\"test\"), l.Slot(\"test\"))\n\t\tassert.NotNil(t, l.Slot(\"test\"))\n\t})\n\tt.Run(\"2\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tl := NewMultiSlotLimiter(1)\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(2)\n\n\t\tvar s1, s2 SlotLimiter\n\t\tgo func() {\n\t\t\ts1 = l.Slot(\"ctest\")\n\t\t\twg.Done()\n\t\t}()\n\t\tgo func() {\n\t\t\ts2 = l.Slot(\"ctest\")\n\t\t\twg.Done()\n\t\t}()\n\t\twg.Wait()\n\n\t\tassert.NotNil(t, s1)\n\t\tassert.Equal(t, s1, s2)\n\t\tassert.Equal(t, s1, l.Slot(\"ctest\"))\n\t\tassert.NotEqual(t, s1, l.Slot(\"dtest\"))\n\t\tassert.NotNil(t, l.Slot(\"dtest\"))\n\t})\n}\n"
  },
  {
    "path": "lib/models.go",
    "content": "package lib\n\nimport (\n\t\"crypto/md5\" //nolint:gosec\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// GroupSeparator for group IDs.\nconst GroupSeparator = \"::\"\n\n// RootGroupPath is the id of the root group\n//\n// Note(@mstoykov): the constant shouldn't be used in all tests in order to not couple the tests too much with it.\n// Changing this will be a breaking change and in this way it will be more obvious.\nconst RootGroupPath = \"\"\n\nvar (\n\t// ErrNameContainsGroupSeparator is emitted if you attempt to instantiate a Group or Check that contains the separator.\n\tErrNameContainsGroupSeparator = errors.New(\"group and check names may not contain '\" + GroupSeparator + \"'\")\n\n\t// ErrCheckGroupIsNil is emitted if you attempt to instantiate a Check (see NewCheck) with a nil Group.\n\tErrCheckGroupIsNil = errors.New(\"check's group must not be nil\")\n)\n\n// StageFields defines the fields used for a Stage; this is a dumb hack to make the JSON code\n// cleaner. pls fix.\ntype StageFields struct {\n\t// Duration of the stage.\n\tDuration types.NullDuration `json:\"duration\"`\n\n\t// If Valid, the VU count will be linearly interpolated towards this value.\n\tTarget null.Int `json:\"target\"`\n}\n\n// A Stage defines a step in a test's timeline.\ntype Stage StageFields\n\n// UnmarshalJSON implements the json.Unmarshaler interface\n// for some reason, implementing UnmarshalText makes encoding/json treat the type as a string.\nfunc (s *Stage) UnmarshalJSON(b []byte) error {\n\tvar fields StageFields\n\tif err := json.Unmarshal(b, &fields); err != nil {\n\t\treturn err\n\t}\n\t*s = Stage(fields)\n\treturn nil\n}\n\n// MarshalJSON implements the json.Marshaler interface\nfunc (s Stage) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(StageFields(s))\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface\nfunc (s *Stage) UnmarshalText(b []byte) error {\n\tvar stage Stage\n\tdurStr, targetStr, _ := strings.Cut(string(b), \":\")\n\tif durStr != \"\" {\n\t\td, err := time.ParseDuration(durStr)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tstage.Duration = types.NullDurationFrom(d)\n\t}\n\tif targetStr != \"\" {\n\t\tt, err := strconv.ParseInt(targetStr, 10, 64)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tstage.Target = null.IntFrom(t)\n\t}\n\t*s = stage\n\treturn nil\n}\n\n// A Group is an organisational block, that samples and checks may be tagged with.\n//\n// For more information, refer to the js/modules/k6.K6.Group() function.\ntype Group struct {\n\t// Arbitrary name of the group.\n\tName string `json:\"name\"`\n\n\t// A group may belong to another group, which may belong to another group, etc. The Path\n\t// describes the hierarchy leading down to this group, with the segments delimited by '::'.\n\t// As an example: a group \"Inner\" inside a group named \"Outer\" would have a path of\n\t// \"::Outer::Inner\". The empty first item is the root group, which is always named \"\".\n\tParent *Group `json:\"-\"`\n\tPath   string `json:\"path\"`\n\n\t// A group's ID is a hash of the Path. It is deterministic between different k6\n\t// instances of the same version, but should be treated as opaque - the hash function\n\t// or length may change.\n\tID string `json:\"id\"`\n\n\t// Groups and checks that are children of this group.\n\tGroups        map[string]*Group `json:\"groups\"`\n\tOrderedGroups []*Group          `json:\"-\"`\n\n\tChecks        map[string]*Check `json:\"checks\"`\n\tOrderedChecks []*Check          `json:\"-\"`\n\n\tgroupMutex sync.Mutex\n\tcheckMutex sync.Mutex\n}\n\n// NewGroup creates a new group with the given name and parent group.\n//\n// The root group must be created with the name \"\" and parent set to nil; this is the only case\n// where a nil parent or empty name is allowed.\nfunc NewGroup(name string, parent *Group) (*Group, error) {\n\told := RootGroupPath\n\tif parent != nil {\n\t\told = parent.Path\n\t}\n\tpath, err := NewGroupPath(old, name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\thash := md5.Sum([]byte(path)) //nolint:gosec // nosemgrep: use-of-md5 // this ID is just for correlation\n\tid := hex.EncodeToString(hash[:])\n\n\treturn &Group{\n\t\tID:     id,\n\t\tPath:   path,\n\t\tName:   name,\n\t\tParent: parent,\n\t\tGroups: make(map[string]*Group),\n\t\tChecks: make(map[string]*Check),\n\t}, nil\n}\n\n// Group creates a child group belonging to this group.\n// This is safe to call from multiple goroutines simultaneously.\nfunc (g *Group) Group(name string) (*Group, error) {\n\tg.groupMutex.Lock()\n\tdefer g.groupMutex.Unlock()\n\tgroup, ok := g.Groups[name]\n\tif !ok {\n\t\tvar err error\n\t\tgroup, err = NewGroup(name, g)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tg.Groups[name] = group\n\t\tg.OrderedGroups = append(g.OrderedGroups, group)\n\t}\n\treturn group, nil\n}\n\n// NewGroupPath ...\nfunc NewGroupPath(old, path string) (string, error) {\n\tif strings.Contains(path, GroupSeparator) {\n\t\treturn \"\", ErrNameContainsGroupSeparator\n\t}\n\tif old == RootGroupPath && path == RootGroupPath {\n\t\treturn RootGroupPath, nil\n\t}\n\treturn old + GroupSeparator + path, nil\n}\n\n// Check creates a child check belonging to this group.\n// This is safe to call from multiple goroutines simultaneously.\nfunc (g *Group) Check(name string) (*Check, error) {\n\tg.checkMutex.Lock()\n\tdefer g.checkMutex.Unlock()\n\tcheck, ok := g.Checks[name]\n\tif !ok {\n\t\tvar err error\n\t\tcheck, err = NewCheck(name, g)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tg.Checks[name] = check\n\t\tg.OrderedChecks = append(g.OrderedChecks, check)\n\t}\n\treturn check, nil\n}\n\n// A Check stores a series of successful or failing tests against a value.\n//\n// For more information, refer to the js/modules/k6.K6.Check() function.\ntype Check struct {\n\t// Arbitrary name of the check.\n\tName string `json:\"name\"`\n\n\t// A Check belongs to a Group, which may belong to other groups. The Path describes\n\t// the hierarchy of these groups, with the segments delimited by '::'.\n\t// As an example: a check \"My Check\" within a group \"Inner\" within a group \"Outer\"\n\t// would have a Path of \"::Outer::Inner::My Check\". The empty first item is the root group,\n\t// which is always named \"\".\n\tGroup *Group `json:\"-\"`\n\tPath  string `json:\"path\"`\n\n\t// A check's ID is a hash of the Path. It is deterministic between different k6\n\t// instances of the same version, but should be treated as opaque - the hash function\n\t// or length may change.\n\tID string `json:\"id\"`\n\n\t// Counters for how many times this check has passed and failed respectively.\n\tPasses int64 `json:\"passes\"`\n\tFails  int64 `json:\"fails\"`\n}\n\n// NewCheck creates a new check with the given name and parent group. The group must not be nil.\nfunc NewCheck(name string, group *Group) (*Check, error) {\n\tif group == nil {\n\t\treturn nil, ErrCheckGroupIsNil\n\t}\n\n\tif strings.Contains(name, GroupSeparator) {\n\t\treturn nil, ErrNameContainsGroupSeparator\n\t}\n\n\tpath := group.Path + GroupSeparator + name\n\thash := md5.Sum([]byte(path)) //nolint:gosec // nosemgrep: use-of-md5 // this ID is just for correlation\n\tid := hex.EncodeToString(hash[:])\n\n\treturn &Check{\n\t\tID:    id,\n\t\tPath:  path,\n\t\tGroup: group,\n\t\tName:  name,\n\t}, nil\n}\n"
  },
  {
    "path": "lib/models_test.go",
    "content": "package lib\n\nimport (\n\t\"encoding/json\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestStageJSON(t *testing.T) {\n\tt.Parallel()\n\ts := Stage{Duration: types.NullDurationFrom(10 * time.Second), Target: null.IntFrom(10)}\n\n\tdata, err := json.Marshal(s)\n\tassert.NoError(t, err)\n\tassert.Equal(t, `{\"duration\":\"10s\",\"target\":10}`, string(data))\n\n\tvar s2 Stage\n\tassert.NoError(t, json.Unmarshal(data, &s2))\n\tassert.Equal(t, s, s2)\n}\n\n// Suggested by @nkovacs in https://github.com/k6io/k6/issues/207#issuecomment-330545467\nfunc TestDataRaces(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Check race\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tgroup, err := NewGroup(\"test\", nil)\n\t\tassert.Nil(t, err, \"NewGroup\")\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(2)\n\t\tvar check1, check2 *Check\n\t\tgo func() {\n\t\t\tvar err error // using the outer err would result in a data race\n\t\t\tcheck1, err = group.Check(\"race\")\n\t\t\tassert.Nil(t, err, \"Check 1\")\n\t\t\twg.Done()\n\t\t}()\n\t\tgo func() {\n\t\t\tvar err error\n\t\t\tcheck2, err = group.Check(\"race\")\n\t\t\tassert.Nil(t, err, \"Check 2\")\n\t\t\twg.Done()\n\t\t}()\n\t\twg.Wait()\n\t\tassert.Equal(t, check1, check2, \"Checks are the same\")\n\t})\n\tt.Run(\"Group race\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tgroup, err := NewGroup(\"test\", nil)\n\t\tassert.Nil(t, err, \"NewGroup\")\n\t\twg := sync.WaitGroup{}\n\t\twg.Add(2)\n\t\tvar group1, group2 *Group\n\t\tgo func() {\n\t\t\tvar err error\n\t\t\tgroup1, err = group.Group(\"race\")\n\t\t\tassert.Nil(t, err, \"Group 1\")\n\t\t\twg.Done()\n\t\t}()\n\t\tgo func() {\n\t\t\tvar err error\n\t\t\tgroup2, err = group.Group(\"race\")\n\t\t\tassert.Nil(t, err, \"Group 2\")\n\t\t\twg.Done()\n\t\t}()\n\t\twg.Wait()\n\t\tassert.Equal(t, group1, group2, \"Groups are the same\")\n\t})\n}\n"
  },
  {
    "path": "lib/netext/dialer.go",
    "content": "package netext\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// Dialer wraps net.Dialer and provides k6 specific functionality -\n// tracing, blacklists and DNS cache and aliases.\ntype Dialer struct {\n\tnet.Dialer\n\n\tResolver         Resolver\n\tBlacklist        []*lib.IPNet\n\tBlockedHostnames *types.HostnameTrie\n\tHosts            *types.Hosts\n\n\tBytesRead    int64\n\tBytesWritten int64\n}\n\n// NewDialer constructs a new Dialer with the given DNS resolver.\nfunc NewDialer(dialer net.Dialer, resolver Resolver) *Dialer {\n\treturn &Dialer{\n\t\tDialer:   dialer,\n\t\tResolver: resolver,\n\t}\n}\n\n// BlackListedIPError is an error that is returned when a given IP is blacklisted\ntype BlackListedIPError struct {\n\tip  net.IP\n\tnet *lib.IPNet\n}\n\nfunc (b BlackListedIPError) Error() string {\n\treturn fmt.Sprintf(\"IP (%s) is in a blacklisted range (%s)\", b.ip, b.net)\n}\n\n// BlockedHostError is returned when a given hostname is blocked\ntype BlockedHostError struct {\n\thostname string\n\tmatch    string\n}\n\nfunc (b BlockedHostError) Error() string {\n\treturn fmt.Sprintf(\"hostname (%s) is in a blocked pattern (%s)\", b.hostname, b.match)\n}\n\n// DialContext wraps the net.Dialer.DialContext and handles the k6 specifics\nfunc (d *Dialer) DialContext(ctx context.Context, proto, addr string) (net.Conn, error) {\n\tdialAddr, err := d.getDialAddr(addr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tconn, err := d.Dialer.DialContext(ctx, proto, dialAddr.String())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tconn = &Conn{conn, &d.BytesRead, &d.BytesWritten}\n\treturn conn, err\n}\n\n// ResolveAddr looks up the IP address for the given host and optionally port.\n// The address is expected in the form \"host:port\" or just \"host\".\n// It returns the resolved IP, and an error if any.\nfunc (d *Dialer) ResolveAddr(addr string) (net.IP, int, error) {\n\t// Check if the address has a port, if not add a dummy port for parsing\n\tif _, _, err := net.SplitHostPort(addr); err != nil {\n\t\t// Address doesn't have a port, add a dummy one\n\t\taddr = net.JoinHostPort(addr, \"0\")\n\t}\n\n\tremote, err := d.getDialAddr(addr)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\treturn remote.IP, remote.Port, nil\n}\n\n// IOSamples returns samples for data send and received since it last call and zeros out.\n// It uses the provided time as the sample time and tags and builtinMetrics to build the samples.\nfunc (d *Dialer) IOSamples(\n\tsampleTime time.Time, ctm metrics.TagsAndMeta, builtinMetrics *metrics.BuiltinMetrics,\n) metrics.SampleContainer {\n\tbytesWritten := atomic.SwapInt64(&d.BytesWritten, 0)\n\tbytesRead := atomic.SwapInt64(&d.BytesRead, 0)\n\treturn metrics.Samples([]metrics.Sample{\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.DataSent,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     sampleTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    float64(bytesWritten),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.DataReceived,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     sampleTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    float64(bytesRead),\n\t\t},\n\t})\n}\n\nfunc (d *Dialer) getDialAddr(addr string) (*types.Host, error) {\n\tremote, err := d.findRemote(addr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, ipnet := range d.Blacklist {\n\t\tif ipnet.Contains(remote.IP) {\n\t\t\treturn nil, BlackListedIPError{ip: remote.IP, net: ipnet}\n\t\t}\n\t}\n\n\treturn remote, nil\n}\n\nfunc (d *Dialer) findRemote(addr string) (*types.Host, error) {\n\thost, port, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tip := net.ParseIP(host)\n\tif d.BlockedHostnames != nil && ip == nil {\n\t\tif match, blocked := d.BlockedHostnames.Contains(host); blocked {\n\t\t\treturn nil, BlockedHostError{hostname: host, match: match}\n\t\t}\n\t}\n\n\tif d.Hosts != nil {\n\t\tremote, e := d.getConfiguredHost(addr, host, port)\n\t\tif e != nil || remote != nil {\n\t\t\treturn remote, e\n\t\t}\n\t}\n\n\tif ip != nil {\n\t\treturn types.NewHost(ip, port)\n\t}\n\n\tip, err = d.Resolver.LookupIP(host)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif ip == nil {\n\t\treturn nil, fmt.Errorf(\"lookup %s: no such host\", host)\n\t}\n\n\treturn types.NewHost(ip, port)\n}\n\nfunc (d *Dialer) getConfiguredHost(addr, host, port string) (*types.Host, error) {\n\tif remote := d.Hosts.Match(addr); remote != nil {\n\t\treturn remote, nil\n\t}\n\n\tif remote := d.Hosts.Match(host); remote != nil {\n\t\tif remote.Port != 0 || port == \"\" {\n\t\t\treturn remote, nil\n\t\t}\n\n\t\tnewPort, err := strconv.Atoi(port)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tnewRemote := *remote\n\t\tnewRemote.Port = newPort\n\n\t\treturn &newRemote, nil\n\t}\n\n\treturn nil, nil //nolint:nilnil\n}\n\n// Conn wraps net.Conn and keeps track of sent and received data size\ntype Conn struct {\n\tnet.Conn\n\n\tBytesRead, BytesWritten *int64\n}\n\nfunc (c *Conn) Read(b []byte) (int, error) {\n\tn, err := c.Conn.Read(b)\n\tif n > 0 {\n\t\tatomic.AddInt64(c.BytesRead, int64(n))\n\t}\n\treturn n, err\n}\n\nfunc (c *Conn) Write(b []byte) (int, error) {\n\tn, err := c.Conn.Write(b)\n\tif n > 0 {\n\t\tatomic.AddInt64(c.BytesWritten, int64(n))\n\t}\n\treturn n, err\n}\n"
  },
  {
    "path": "lib/netext/dialer_test.go",
    "content": "package netext\n\nimport (\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/mockresolver\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestDialerAddr(t *testing.T) {\n\tt.Parallel()\n\tdialer := NewDialer(net.Dialer{}, newResolver())\n\thosts, err := types.NewHosts(\n\t\tmap[string]types.Host{\n\t\t\t\"example.com\":                {IP: net.ParseIP(\"3.4.5.6\")},\n\t\t\t\"example.com:443\":            {IP: net.ParseIP(\"3.4.5.6\"), Port: 8443},\n\t\t\t\"example.com:8080\":           {IP: net.ParseIP(\"3.4.5.6\"), Port: 9090},\n\t\t\t\"example-deny-host.com\":      {IP: net.ParseIP(\"8.9.10.11\")},\n\t\t\t\"example-ipv6.com\":           {IP: net.ParseIP(\"2001:db8::68\")},\n\t\t\t\"example-ipv6.com:443\":       {IP: net.ParseIP(\"2001:db8::68\"), Port: 8443},\n\t\t\t\"example-ipv6-deny-host.com\": {IP: net.ParseIP(\"::1\")},\n\t\t})\n\trequire.NoError(t, err)\n\tdialer.Hosts = hosts\n\tipNet, err := lib.ParseCIDR(\"8.9.10.0/24\")\n\trequire.NoError(t, err)\n\n\tipV6Net, err := lib.ParseCIDR(\"::1/24\")\n\trequire.NoError(t, err)\n\n\tdialer.Blacklist = []*lib.IPNet{ipNet, ipV6Net}\n\n\ttestCases := []struct {\n\t\taddress, expAddress, expErr string\n\t}{\n\t\t// IPv4\n\t\t{\"example-resolver.com:80\", \"1.2.3.4:80\", \"\"},\n\t\t{\"example.com:80\", \"3.4.5.6:80\", \"\"},\n\t\t{\"example.com:443\", \"3.4.5.6:8443\", \"\"},\n\t\t{\"example.com:8080\", \"3.4.5.6:9090\", \"\"},\n\t\t{\"1.2.3.4:80\", \"1.2.3.4:80\", \"\"},\n\t\t{\"1.2.3.4\", \"\", \"address 1.2.3.4: missing port in address\"},\n\t\t{\"example-deny-resolver.com:80\", \"\", \"IP (8.9.10.11) is in a blacklisted range (8.9.10.0/24)\"},\n\t\t{\"example-deny-host.com:80\", \"\", \"IP (8.9.10.11) is in a blacklisted range (8.9.10.0/24)\"},\n\t\t{\"no-such-host.com:80\", \"\", \"lookup no-such-host.com: no such host\"},\n\n\t\t// IPv6\n\t\t{\"example-ipv6.com:443\", \"[2001:db8::68]:8443\", \"\"},\n\t\t{\"[2001:db8:aaaa:1::100]:443\", \"[2001:db8:aaaa:1::100]:443\", \"\"},\n\t\t{\"[::1.2.3.4]\", \"\", \"address [::1.2.3.4]: missing port in address\"},\n\t\t{\"example-ipv6-deny-resolver.com:80\", \"\", \"IP (::1) is in a blacklisted range (::/24)\"},\n\t\t{\"example-ipv6-deny-host.com:80\", \"\", \"IP (::1) is in a blacklisted range (::/24)\"},\n\t\t{\"example-ipv6-deny-host.com:80\", \"\", \"IP (::1) is in a blacklisted range (::/24)\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.address, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\taddr, err := dialer.getDialAddr(tc.address)\n\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\trequire.EqualError(t, err, tc.expErr)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tc.expAddress, addr.String())\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDialerAddrBlockHostnamesStar(t *testing.T) {\n\tt.Parallel()\n\tdialer := NewDialer(net.Dialer{}, newResolver())\n\thosts, err := types.NewHosts(map[string]types.Host{\n\t\t\"example.com\": {IP: net.ParseIP(\"3.4.5.6\")},\n\t})\n\trequire.NoError(t, err)\n\tdialer.Hosts = hosts\n\n\tblocked, err := types.NewHostnameTrie([]string{\"*\"})\n\trequire.NoError(t, err)\n\tdialer.BlockedHostnames = blocked\n\ttestCases := []struct {\n\t\taddress, expAddress, expErr string\n\t}{\n\t\t// IPv4\n\t\t{\"example.com:80\", \"\", \"hostname (example.com) is in a blocked pattern (*)\"},\n\t\t{\"example.com:443\", \"\", \"hostname (example.com) is in a blocked pattern (*)\"},\n\t\t{\"not.com:30\", \"\", \"hostname (not.com) is in a blocked pattern (*)\"},\n\t\t{\"1.2.3.4:80\", \"1.2.3.4:80\", \"\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.address, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\taddr, err := dialer.getDialAddr(tc.address)\n\n\t\t\tif tc.expErr != \"\" {\n\t\t\t\trequire.EqualError(t, err, tc.expErr)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, tc.expAddress, addr.String())\n\t\t\t}\n\t\t})\n\t}\n}\n\n// Benchmarks /etc/hosts like hostname mapping\nfunc BenchmarkDialerHosts(b *testing.B) {\n\thosts, err := types.NewHosts(map[string]types.Host{\n\t\t\"k6.io\":                {IP: []byte(\"192.168.1.1\"), Port: 80},\n\t\t\"specific.k6.io\":       {IP: []byte(\"192.168.1.2\"), Port: 80},\n\t\t\"grafana.com\":          {IP: []byte(\"aa::ff\"), Port: 80},\n\t\t\"specific.grafana.com\": {IP: []byte(\"aa:bb:::ff\"), Port: 80},\n\t})\n\trequire.NoError(b, err)\n\n\tdialer := Dialer{\n\t\tDialer: net.Dialer{},\n\t\tHosts:  hosts,\n\t}\n\n\ttcs := []string{\"k6.io\", \"specific.k6.io\", \"grafana.com\", \"specific.grafana.com\", \"not.exists.com\"}\n\n\tb.ResetTimer()\n\tfor i := 0; i < b.N; i++ {\n\t\tfor _, tc := range tcs {\n\t\t\t//nolint:errcheck\n\t\t\tdialer.getDialAddr(tc)\n\t\t}\n\t}\n}\n\nfunc TestDialerResolveAddr(t *testing.T) {\n\tt.Parallel()\n\tdialer := NewDialer(net.Dialer{}, newResolver())\n\thosts, err := types.NewHosts(\n\t\tmap[string]types.Host{\n\t\t\t\"example.com\":                {IP: net.ParseIP(\"3.4.5.6\")},\n\t\t\t\"example.com:443\":            {IP: net.ParseIP(\"3.4.5.6\"), Port: 8443},\n\t\t\t\"example.com:8080\":           {IP: net.ParseIP(\"3.4.5.6\"), Port: 9090},\n\t\t\t\"example-deny-host.com\":      {IP: net.ParseIP(\"8.9.10.11\")},\n\t\t\t\"example-ipv6.com\":           {IP: net.ParseIP(\"2001:db8::68\")},\n\t\t\t\"example-ipv6.com:443\":       {IP: net.ParseIP(\"2001:db8::68\"), Port: 8443},\n\t\t\t\"example-ipv6-deny-host.com\": {IP: net.ParseIP(\"::1\")},\n\t\t})\n\trequire.NoError(t, err)\n\tdialer.Hosts = hosts\n\tipNet, err := lib.ParseCIDR(\"8.9.10.0/24\")\n\trequire.NoError(t, err)\n\n\tipV6Net, err := lib.ParseCIDR(\"::1/24\")\n\trequire.NoError(t, err)\n\n\tdialer.Blacklist = []*lib.IPNet{ipNet, ipV6Net}\n\n\ttestCases := []struct {\n\t\tname          string\n\t\taddress       string\n\t\texpectedIP    string\n\t\texpectedPort  int\n\t\texpectedError string\n\t}{\n\t\t// IPv4 with port\n\t\t{\"IPv4_with_resolver\", \"example-resolver.com:80\", \"1.2.3.4\", 80, \"\"},\n\t\t{\"IPv4_with_hosts_mapping\", \"example.com:80\", \"3.4.5.6\", 80, \"\"},\n\t\t{\"IPv4_with_custom_port_in_hosts\", \"example.com:443\", \"3.4.5.6\", 8443, \"\"},\n\t\t{\"IPv4_with_different_custom_port\", \"example.com:8080\", \"3.4.5.6\", 9090, \"\"},\n\t\t{\"IPv4_direct_IP\", \"1.2.3.4:80\", \"1.2.3.4\", 80, \"\"},\n\t\t{\"IPv4_blacklisted_via_resolver\", \"example-deny-resolver.com:80\", \"\", 0, \"IP (8.9.10.11) is in a blacklisted range (8.9.10.0/24)\"},\n\t\t{\"IPv4_blacklisted_via_hosts\", \"example-deny-host.com:80\", \"\", 0, \"IP (8.9.10.11) is in a blacklisted range (8.9.10.0/24)\"},\n\t\t{\"IPv4_non-existent_host\", \"no-such-host.com:80\", \"\", 0, \"lookup no-such-host.com: no such host\"},\n\n\t\t// IPv4 without port\n\t\t{\"IPv4_without_port\", \"example-resolver.com\", \"1.2.3.4\", 0, \"\"},\n\t\t{\"IPv4_hosts_mapping_without_port\", \"example.com\", \"3.4.5.6\", 0, \"\"},\n\t\t{\"IPv4_direct_IP_without_port\", \"1.2.3.4\", \"1.2.3.4\", 0, \"\"},\n\n\t\t// IPv6 with port\n\t\t{\"IPv6_with_hosts_mapping\", \"example-ipv6.com:443\", \"2001:db8::68\", 8443, \"\"},\n\t\t{\"IPv6_direct_IP\", \"[2001:db8:aaaa:1::100]:443\", \"2001:db8:aaaa:1::100\", 443, \"\"},\n\t\t{\"IPv6_blacklisted_via_resolver\", \"example-ipv6-deny-resolver.com:80\", \"\", 0, \"IP (::1) is in a blacklisted range (::/24)\"},\n\t\t{\"IPv6_blacklisted_via_hosts\", \"example-ipv6-deny-host.com:80\", \"\", 0, \"IP (::1) is in a blacklisted range (::/24)\"},\n\n\t\t// IPv6 without port\n\t\t{\"IPv6_without_port\", \"example-ipv6.com\", \"2001:db8::68\", 0, \"\"},\n\t\t{\"IPv6_direct_IP_without_port\", \"2001:db8:aaaa:1::100\", \"2001:db8:aaaa:1::100\", 0, \"\"},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tip, port, err := dialer.ResolveAddr(tc.address)\n\n\t\t\tif tc.expectedError != \"\" {\n\t\t\t\trequire.EqualError(t, err, tc.expectedError)\n\t\t\t\trequire.Nil(t, ip)\n\t\t\t\trequire.Equal(t, 0, port)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\trequire.Equal(t, net.ParseIP(tc.expectedIP), ip)\n\t\t\t\trequire.Equal(t, tc.expectedPort, port)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc newResolver() *mockresolver.MockResolver {\n\treturn mockresolver.New(\n\t\tmap[string][]net.IP{\n\t\t\t\"example-resolver.com\":           {net.ParseIP(\"1.2.3.4\")},\n\t\t\t\"example-deny-resolver.com\":      {net.ParseIP(\"8.9.10.11\")},\n\t\t\t\"example-ipv6-deny-resolver.com\": {net.ParseIP(\"::1\")},\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "lib/netext/httpext/batch.go",
    "content": "package httpext\n\nimport (\n\t\"context\"\n\t\"sync/atomic\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\n// BatchParsedHTTPRequest extends the normal parsed HTTP request with a pointer\n// to a Response object, so that the batch goroutines can concurrently store the\n// responses they receive, without any locking.\ntype BatchParsedHTTPRequest struct {\n\t*ParsedHTTPRequest\n\tResponse *Response // this is modified by MakeBatchRequests()\n}\n\n// MakeBatchRequests concurrently makes multiple requests. It spawns\n// min(reqCount, globalLimit) goroutines that asynchronously process all\n// requests coming from the requests channel. Responses are recorded in the\n// pointers contained in each BatchParsedHTTPRequest object, so they need to be\n// pre-initialized. In addition, each processed request would emit either a nil\n// value, or an error, via the returned errors channel. The goroutines exit when\n// the requests channel is closed.\nfunc MakeBatchRequests(\n\tctx context.Context, state *lib.State,\n\trequests []BatchParsedHTTPRequest,\n\treqCount, globalLimit, perHostLimit int,\n) <-chan error {\n\tworkers := min(reqCount, globalLimit)\n\tresult := make(chan error, reqCount)\n\tperHostLimiter := lib.NewMultiSlotLimiter(perHostLimit)\n\n\tmakeRequest := func(req BatchParsedHTTPRequest) {\n\t\tif hl := perHostLimiter.Slot(req.URL.GetURL().Host); hl != nil {\n\t\t\thl.Begin()\n\t\t\tdefer hl.End()\n\t\t}\n\n\t\tresp, err := MakeRequest(ctx, state, req.ParsedHTTPRequest)\n\t\tif resp != nil {\n\t\t\t*req.Response = *resp\n\t\t}\n\t\tresult <- err\n\t}\n\n\tcounter, i32reqCount := int32(-1), int32(reqCount) //nolint:gosec\n\tfor range workers {\n\t\tgo func() {\n\t\t\tfor {\n\t\t\t\treqNum := atomic.AddInt32(&counter, 1)\n\t\t\t\tif reqNum >= i32reqCount {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tmakeRequest(requests[reqNum])\n\t\t\t}\n\t\t}()\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "lib/netext/httpext/compression.go",
    "content": "package httpext\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"compress/zlib\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/andybalholm/brotli\"\n\t\"github.com/klauspost/compress/zstd\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\n// CompressionType is used to specify what compression is to be used to compress the body of a\n// request\n// The conversion and validation methods are auto-generated with https://github.com/alvaroloes/enumer:\n//\n//go:generate enumer -type=CompressionType -transform=snake -trimprefix CompressionType -output compression_type_gen.go\ntype CompressionType uint\n\nconst (\n\t// CompressionTypeGzip compresses through gzip\n\tCompressionTypeGzip CompressionType = iota\n\t// CompressionTypeDeflate compresses through flate\n\tCompressionTypeDeflate\n\t// CompressionTypeZstd compresses through zstd\n\tCompressionTypeZstd\n\t// CompressionTypeBr compresses through brotli\n\tCompressionTypeBr\n\t// TODO: add compress(lzw), maybe bzip2 and others listed at\n\t// https://en.wikipedia.org/wiki/HTTP_compression#Content-Encoding_tokens\n)\n\nfunc compressBody(algos []CompressionType, body io.ReadCloser) (*bytes.Buffer, string, error) {\n\tvar contentEncoding string\n\tvar prevBuf io.Reader = body\n\tvar buf *bytes.Buffer\n\tfor _, compressionType := range algos {\n\t\tif buf != nil {\n\t\t\tprevBuf = buf\n\t\t}\n\t\tbuf = new(bytes.Buffer)\n\n\t\tif contentEncoding != \"\" {\n\t\t\tcontentEncoding += \", \"\n\t\t}\n\t\tcontentEncoding += compressionType.String()\n\t\tvar w io.WriteCloser\n\t\tswitch compressionType {\n\t\tcase CompressionTypeGzip:\n\t\t\tw = gzip.NewWriter(buf)\n\t\tcase CompressionTypeDeflate:\n\t\t\tw = zlib.NewWriter(buf)\n\t\tcase CompressionTypeZstd:\n\t\t\tw, _ = zstd.NewWriter(buf)\n\t\tcase CompressionTypeBr:\n\t\t\tw = brotli.NewWriter(buf)\n\t\tdefault:\n\t\t\treturn nil, \"\", fmt.Errorf(\"unknown compressionType %s\", compressionType)\n\t\t}\n\t\t// we don't close in defer because zlib will write it's checksum again if it closes twice :(\n\t\t_, err := io.Copy(w, prevBuf)\n\t\tif err != nil {\n\t\t\t_ = w.Close()\n\t\t\treturn nil, \"\", err\n\t\t}\n\n\t\tif err = w.Close(); err != nil {\n\t\t\treturn nil, \"\", err\n\t\t}\n\t}\n\n\treturn buf, contentEncoding, body.Close()\n}\n\n//nolint:gochecknoglobals\nvar decompressionErrors = [...]error{\n\tzlib.ErrChecksum, zlib.ErrDictionary, zlib.ErrHeader,\n\tgzip.ErrChecksum, gzip.ErrHeader,\n\t// TODO: handle brotli errors - currently unexported\n\tzstd.ErrReservedBlockType, zstd.ErrCompressedSizeTooBig, zstd.ErrBlockTooSmall, zstd.ErrMagicMismatch,\n\tzstd.ErrWindowSizeExceeded, zstd.ErrWindowSizeTooSmall, zstd.ErrDecoderSizeExceeded, zstd.ErrUnknownDictionary,\n\tzstd.ErrFrameSizeExceeded, zstd.ErrCRCMismatch, zstd.ErrDecoderClosed,\n}\n\nfunc newDecompressionError(originalErr error) K6Error {\n\treturn NewK6Error(\n\t\tresponseDecompressionErrorCode,\n\t\tfmt.Sprintf(\"error decompressing response body (%s)\", originalErr.Error()),\n\t\toriginalErr,\n\t)\n}\n\nfunc wrapDecompressionError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\t// TODO: something more optimized? for example, we won't get zstd errors if\n\t// we don't use it... maybe the code that builds the decompression readers\n\t// could also add an appropriate error-wrapper layer?\n\tfor _, decErr := range &decompressionErrors {\n\t\tif errors.Is(err, decErr) {\n\t\t\treturn newDecompressionError(err)\n\t\t}\n\t}\n\tif strings.HasPrefix(err.Error(), \"brotli: \") { // TODO: submit an upstream patch and fix...\n\t\treturn newDecompressionError(err)\n\t}\n\treturn err\n}\n\nfunc readResponseBody(\n\tstate *lib.State,\n\trespType ResponseType,\n\tresp *http.Response,\n\trespErr error,\n) (any, error) {\n\tif resp == nil || respErr != nil {\n\t\treturn nil, respErr\n\t}\n\n\tif respType == ResponseTypeNone {\n\t\t_, err := io.Copy(io.Discard, resp.Body)\n\t\t_ = resp.Body.Close()\n\n\t\treturn nil, err\n\t}\n\n\trc := &readCloser{resp.Body}\n\t// Ensure that the entire response body is read and closed, e.g. in case of decoding errors\n\tdefer func(respBody io.ReadCloser) {\n\t\t_, _ = io.Copy(io.Discard, respBody)\n\t\t_ = respBody.Close()\n\t}(resp.Body)\n\n\tif (resp.StatusCode >= 100 && resp.StatusCode <= 199) || // 1xx\n\t\tresp.StatusCode == http.StatusNoContent || resp.StatusCode == http.StatusNotModified {\n\t\t// for all three of this status code there is always no content\n\t\t// https://www.rfc-editor.org/rfc/rfc9110.html#section-6.4.1-8\n\t\t// this also prevents trying to read\n\t\treturn nil, nil //nolint:nilnil\n\t}\n\tcontentEncodings := strings.Split(resp.Header.Get(\"Content-Encoding\"), \",\")\n\t// Transparently decompress the body if it's has a content-encoding we\n\t// support. If not, simply return it as it is.\n\tfor i := len(contentEncodings) - 1; i >= 0; i-- {\n\t\tcontentEncoding := strings.TrimSpace(contentEncodings[i])\n\t\tif compression, err := CompressionTypeString(contentEncoding); err == nil {\n\t\t\tdecoder, err := pickDecoder(compression, rc)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, newDecompressionError(err)\n\t\t\t}\n\n\t\t\trc = &readCloser{decoder}\n\t\t}\n\t}\n\n\tbuf := state.BufferPool.Get()\n\tdefer state.BufferPool.Put(buf)\n\t_, err := io.Copy(buf, rc.Reader)\n\tif err != nil {\n\t\trespErr = wrapDecompressionError(err)\n\t}\n\n\terr = rc.Close()\n\tif err != nil && respErr == nil { // Don't overwrite previous errors\n\t\trespErr = wrapDecompressionError(err)\n\t}\n\n\tvar result any\n\t// Binary or string\n\tswitch respType {\n\tcase ResponseTypeText:\n\t\tresult = buf.String()\n\tcase ResponseTypeBinary:\n\t\t// Copy the data to a new slice before we return the buffer to the pool,\n\t\t// because buf.Bytes() points to the underlying buffer byte slice.\n\t\t// The ArrayBuffer wrapping will be done in the js/modules/k6/http\n\t\t// package to avoid a reverse dependency, since it depends on Sobek.\n\t\tbinData := make([]byte, buf.Len())\n\t\tcopy(binData, buf.Bytes())\n\t\tresult = binData\n\tdefault:\n\t\trespErr = fmt.Errorf(\"unknown responseType %s\", respType)\n\t}\n\n\treturn result, respErr\n}\n\nfunc pickDecoder(compression CompressionType, rc *readCloser) (io.Reader, error) {\n\tvar decoder io.Reader\n\tvar err error\n\tswitch compression {\n\tcase CompressionTypeDeflate:\n\t\tdecoder, err = zlib.NewReader(rc)\n\tcase CompressionTypeGzip:\n\t\tdecoder, err = gzip.NewReader(rc)\n\tcase CompressionTypeZstd:\n\t\tdecoder, err = zstd.NewReader(rc)\n\tcase CompressionTypeBr:\n\t\tdecoder = brotli.NewReader(rc)\n\tdefault:\n\t\t// We have not implemented a compression ... :(\n\t\terr = fmt.Errorf(\n\t\t\t\"unsupported compression type %s - this is a bug in k6, please report it\",\n\t\t\tcompression,\n\t\t)\n\t}\n\n\treturn decoder, err\n}\n"
  },
  {
    "path": "lib/netext/httpext/compression_type_gen.go",
    "content": "// Code generated by \"enumer -type=CompressionType -transform=snake -trimprefix CompressionType -output compression_type_gen.go\"; DO NOT EDIT.\n\npackage httpext\n\nimport (\n\t\"fmt\"\n)\n\nconst _CompressionTypeName = \"gzipdeflatezstdbr\"\n\nvar _CompressionTypeIndex = [...]uint8{0, 4, 11, 15, 17}\n\nfunc (i CompressionType) String() string {\n\tif i >= CompressionType(len(_CompressionTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"CompressionType(%d)\", i)\n\t}\n\treturn _CompressionTypeName[_CompressionTypeIndex[i]:_CompressionTypeIndex[i+1]]\n}\n\nvar _CompressionTypeValues = []CompressionType{0, 1, 2, 3}\n\nvar _CompressionTypeNameToValueMap = map[string]CompressionType{\n\t_CompressionTypeName[0:4]:   0,\n\t_CompressionTypeName[4:11]:  1,\n\t_CompressionTypeName[11:15]: 2,\n\t_CompressionTypeName[15:17]: 3,\n}\n\n// CompressionTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc CompressionTypeString(s string) (CompressionType, error) {\n\tif val, ok := _CompressionTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to CompressionType values\", s)\n}\n\n// CompressionTypeValues returns all values of the enum\nfunc CompressionTypeValues() []CompressionType {\n\treturn _CompressionTypeValues\n}\n\n// IsACompressionType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i CompressionType) IsACompressionType() bool {\n\tfor _, v := range _CompressionTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "lib/netext/httpext/digest_transport.go",
    "content": "package httpext\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\n\tdigest \"github.com/Soontao/goHttpDigestClient\"\n)\n\ntype digestTransport struct {\n\toriginalTransport http.RoundTripper\n}\n\n// RoundTrip handles digest auth by behaving like an http.RoundTripper\n//\n// TODO: fix - this is a preliminary solution and is somewhat broken! we're\n// always making 2 HTTP requests when digest authentication is enabled... we\n// should cache the nonces and behave more like a browser... or we should\n// ditch the hacky http.RoundTripper approach and write our own client...\n//\n// Github issue: https://github.com/k6io/k6/issues/800\nfunc (t digestTransport) RoundTrip(req *http.Request) (*http.Response, error) {\n\t// Make the initial request authentication params to compute the\n\t// authorization header\n\tusername := req.URL.User.Username()\n\tpassword, _ := req.URL.User.Password()\n\n\t// Remove the user data from the URL to avoid sending the authorization\n\t// header for basic auth\n\treq.URL.User = nil\n\n\tnoAuthResponse, err := t.originalTransport.RoundTrip(req)\n\tif err != nil || noAuthResponse.StatusCode != http.StatusUnauthorized {\n\t\t// If there was an error, or if the remote server didn't respond with\n\t\t// status 401, we simply return, so the upstream code can deal with it.\n\t\treturn noAuthResponse, err\n\t}\n\n\trespBody, err := io.ReadAll(noAuthResponse.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t_ = noAuthResponse.Body.Close()\n\n\t// Calculate the Authorization header\n\t// TODO: determine if we actually need the body, since I'm not sure that's\n\t// what the `entity` means... maybe a moot point if we change the used\n\t// digest auth library...\n\tchallenge := digest.GetChallengeFromHeader(&noAuthResponse.Header)\n\tchallenge.ComputeResponse(req.Method, req.URL.RequestURI(), string(respBody), username, password)\n\tauthorization := challenge.ToAuthorizationStr()\n\treq.Header.Set(digest.KEY_AUTHORIZATION, authorization)\n\n\tif req.GetBody != nil {\n\t\t// Reset the request body if we need to\n\t\treq.Body, err = req.GetBody()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Actually make the HTTP request with the proper Authorization\n\treturn t.originalTransport.RoundTrip(req)\n}\n"
  },
  {
    "path": "lib/netext/httpext/error_codes.go",
    "content": "package httpext\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"os\"\n\t\"runtime\"\n\t\"syscall\"\n\n\t\"golang.org/x/net/http2\"\n\n\t\"go.k6.io/k6/lib/netext\"\n)\n\n// TODO: maybe rename the type errorCode, so we can have errCode variables? and\n// also the constants would probably be better of if `ErrorCode` was a prefix,\n// not a suffix - they would be much easier for auto-autocompletion at least...\n\ntype errCode uint32\n\nconst (\n\t// non specific\n\tdefaultErrorCode          errCode = 1000\n\tdefaultNetNonTCPErrorCode errCode = 1010\n\tinvalidURLErrorCode       errCode = 1020\n\trequestTimeoutErrorCode   errCode = 1050\n\t// DNS errors\n\tdefaultDNSErrorCode      errCode = 1100\n\tdnsNoSuchHostErrorCode   errCode = 1101\n\tblackListedIPErrorCode   errCode = 1110\n\tblockedHostnameErrorCode errCode = 1111\n\t// tcp errors\n\tdefaultTCPErrorCode      errCode = 1200\n\ttcpBrokenPipeErrorCode   errCode = 1201\n\tnetUnknownErrnoErrorCode errCode = 1202\n\ttcpDialErrorCode         errCode = 1210\n\ttcpDialTimeoutErrorCode  errCode = 1211\n\ttcpDialRefusedErrorCode  errCode = 1212\n\ttcpDialUnknownErrnoCode  errCode = 1213\n\ttcpResetByPeerErrorCode  errCode = 1220\n\t// TLS errors\n\tdefaultTLSErrorCode           errCode = 1300\n\ttlsHeaderErrorCode            errCode = 1301\n\tx509UnknownAuthorityErrorCode errCode = 1310\n\tx509HostnameErrorCode         errCode = 1311\n\n\t// HTTP2 errors\n\tdefaultHTTP2ErrorCode errCode = 1600 //nolint:unused\n\t// HTTP2 GoAway errors\n\tunknownHTTP2GoAwayErrorCode errCode = 1610\n\t// errors till 1611 + 13 are other HTTP2 GoAway errors with a specific errCode\n\n\t// HTTP2 Stream errors\n\tunknownHTTP2StreamErrorCode errCode = 1630\n\t// errors till 1631 + 13 are other HTTP2 Stream errors with a specific errCode\n\n\t// HTTP2 Connection errors\n\tunknownHTTP2ConnectionErrorCode errCode = 1650\n\t// errors till 1651 + 13 are other HTTP2 Connection errors with a specific errCode\n\n\t// Custom k6 content errors, i.e. when the magic fails\n\t// defaultContentError errCode = 1700 // reserved for future use\n\tresponseDecompressionErrorCode errCode = 1701\n)\n\nconst (\n\ttcpResetByPeerErrorCodeMsg  = \"%s: connection reset by peer\"\n\ttcpDialTimeoutErrorCodeMsg  = \"dial: i/o timeout\"\n\ttcpDialRefusedErrorCodeMsg  = \"dial: connection refused\"\n\ttcpBrokenPipeErrorCodeMsg   = \"%s: broken pipe\"\n\tnetUnknownErrnoErrorCodeMsg = \"%s: unknown errno `%d` on %s with message `%s`\"\n\tdnsNoSuchHostErrorCodeMsg   = \"lookup: no such host\"\n\tblackListedIPErrorCodeMsg   = \"ip is blacklisted\"\n\tblockedHostnameErrorMsg     = \"hostname is blocked\"\n\thttp2GoAwayErrorCodeMsg     = \"http2: received GoAway with http2 ErrCode %s\"\n\thttp2StreamErrorCodeMsg     = \"http2: stream error with http2 ErrCode %s\"\n\thttp2ConnectionErrorCodeMsg = \"http2: connection error with http2 ErrCode %s\"\n\tx509HostnameErrorCodeMsg    = \"x509: certificate doesn't match hostname\"\n\tx509UnknownAuthority        = \"x509: unknown authority\"\n\trequestTimeoutErrorCodeMsg  = \"request timeout\"\n\tinvalidURLErrorCodeMsg      = \"invalid URL\"\n)\n\nfunc http2ErrCodeOffset(code http2.ErrCode) errCode {\n\tif code > http2.ErrCodeHTTP11Required {\n\t\treturn 0\n\t}\n\treturn 1 + errCode(code)\n}\n\n//nolint:errorlint\nfunc errorCodeForNetOpError(err *net.OpError) (errCode, string) {\n\t// TODO: refactor this further - a big switch would be more readable, maybe\n\t// we should even check for *os.SyscallError in the main switch body in the\n\t// parent errorCodeForError() function?\n\n\tif err.Net != \"tcp\" && err.Net != \"tcp6\" {\n\t\t// TODO: figure out how this happens\n\t\treturn defaultNetNonTCPErrorCode, err.Error()\n\t}\n\tif sErr, ok := err.Err.(*os.SyscallError); ok {\n\t\tswitch sErr.Unwrap() {\n\t\tcase syscall.ECONNRESET:\n\t\t\treturn tcpResetByPeerErrorCode, fmt.Sprintf(tcpResetByPeerErrorCodeMsg, err.Op)\n\t\tcase syscall.EPIPE:\n\t\t\treturn tcpBrokenPipeErrorCode, fmt.Sprintf(tcpBrokenPipeErrorCodeMsg, err.Op)\n\t\t}\n\t\tcode, msg := getOSSyscallErrorCode(err, sErr)\n\t\tif code != 0 {\n\t\t\treturn code, msg\n\t\t}\n\t}\n\tif err.Op != \"dial\" {\n\t\tswitch inErr := err.Err.(type) {\n\t\tcase syscall.Errno:\n\t\t\treturn netUnknownErrnoErrorCode,\n\t\t\t\tfmt.Sprintf(netUnknownErrnoErrorCodeMsg,\n\t\t\t\t\terr.Op, (int)(inErr), runtime.GOOS, inErr.Error()) //nolint:gosec\n\t\tdefault:\n\t\t\treturn defaultTCPErrorCode, err.Error()\n\t\t}\n\t}\n\n\tif iErr, ok := err.Err.(*os.SyscallError); ok {\n\t\tif errno, ok := iErr.Err.(syscall.Errno); ok {\n\t\t\tif errno == syscall.ECONNREFUSED ||\n\t\t\t\t// 10061 is some connection refused like thing on windows\n\t\t\t\t// TODO: fix by moving to x/sys instead of syscall after\n\t\t\t\t// https://github.com/golang/go/issues/31360 gets resolved\n\t\t\t\t(errno == 10061 && runtime.GOOS == \"windows\") {\n\t\t\t\treturn tcpDialRefusedErrorCode, tcpDialRefusedErrorCodeMsg\n\t\t\t}\n\t\t\treturn tcpDialUnknownErrnoCode,\n\t\t\t\tfmt.Sprintf(\"dial: unknown errno %d error with msg `%s`\", errno, iErr.Err)\n\t\t}\n\t}\n\n\t// Check if the wrapped error isn't something we recognize, e.g. a DNS error\n\tif wrappedErr := errors.Unwrap(err); wrappedErr != nil {\n\t\terrCodeForWrapped, errForWrapped := errorCodeForError(wrappedErr)\n\t\tif errCodeForWrapped != defaultErrorCode {\n\t\t\treturn errCodeForWrapped, errForWrapped\n\t\t}\n\t}\n\n\t// If it's not, return a generic TCP dial error\n\treturn tcpDialErrorCode, err.Error()\n}\n\n// errorCodeForError returns the errorCode and a specific error message for given error.\n//\n//nolint:errorlint\nfunc errorCodeForError(err error) (errCode, string) {\n\t// We explicitly check for `Unwrap()` in the default switch branch, but\n\t// checking for the concrete error types first gives us the opportunity to\n\t// also directly detect high-level errors, if we need to, even if they wrap\n\t// a low level error inside.\n\tswitch e := err.(type) {\n\tcase K6Error:\n\t\treturn e.Code, e.Message\n\tcase *net.DNSError:\n\t\tswitch e.Err {\n\t\tcase \"no such host\": // defined as private in the go stdlib\n\t\t\treturn dnsNoSuchHostErrorCode, dnsNoSuchHostErrorCodeMsg\n\t\tdefault:\n\t\t\treturn defaultDNSErrorCode, err.Error()\n\t\t}\n\tcase netext.BlackListedIPError:\n\t\treturn blackListedIPErrorCode, blackListedIPErrorCodeMsg\n\tcase netext.BlockedHostError:\n\t\treturn blockedHostnameErrorCode, blockedHostnameErrorMsg\n\tcase http2.GoAwayError:\n\t\treturn unknownHTTP2GoAwayErrorCode + http2ErrCodeOffset(e.ErrCode),\n\t\t\tfmt.Sprintf(http2GoAwayErrorCodeMsg, e.ErrCode)\n\tcase http2.StreamError:\n\t\treturn unknownHTTP2StreamErrorCode + http2ErrCodeOffset(e.Code),\n\t\t\tfmt.Sprintf(http2StreamErrorCodeMsg, e.Code)\n\tcase http2.ConnectionError:\n\t\treturn unknownHTTP2ConnectionErrorCode + http2ErrCodeOffset(http2.ErrCode(e)),\n\t\t\tfmt.Sprintf(http2ConnectionErrorCodeMsg, http2.ErrCode(e))\n\tcase *net.OpError:\n\t\treturn errorCodeForNetOpError(e)\n\tcase x509.UnknownAuthorityError:\n\t\treturn x509UnknownAuthorityErrorCode, x509UnknownAuthority\n\tcase x509.HostnameError:\n\t\treturn x509HostnameErrorCode, x509HostnameErrorCodeMsg\n\tcase tls.RecordHeaderError:\n\t\treturn tlsHeaderErrorCode, err.Error()\n\tcase *url.Error:\n\t\treturn errorCodeForError(e.Err)\n\tdefault:\n\t\tif wrappedErr := errors.Unwrap(err); wrappedErr != nil {\n\t\t\treturn errorCodeForError(wrappedErr)\n\t\t}\n\n\t\treturn defaultErrorCode, err.Error()\n\t}\n}\n\n// K6Error is a helper struct that enhances Go errors with custom k6-specific\n// error-codes and more user-readable error messages.\ntype K6Error struct {\n\tCode          errCode\n\tMessage       string\n\tOriginalError error\n}\n\n// NewK6Error is the constructor for K6Error\nfunc NewK6Error(code errCode, msg string, originalErr error) K6Error {\n\treturn K6Error{code, msg, originalErr}\n}\n\n// Error implements the `error` interface, so K6Errors are normal Go errors.\nfunc (k6Err K6Error) Error() string {\n\treturn k6Err.Message\n}\n\n// Unwrap implements the `xerrors.Wrapper` interface, so K6Errors are a bit\n// future-proof Go 2 errors.\nfunc (k6Err K6Error) Unwrap() error {\n\treturn k6Err.OriginalError\n}\n"
  },
  {
    "path": "lib/netext/httpext/error_codes_syscall_posix.go",
    "content": "//go:build !windows\n\npackage httpext\n\nimport (\n\t\"net\"\n\t\"os\"\n)\n\nfunc getOSSyscallErrorCode(_ *net.OpError, _ *os.SyscallError) (errCode, string) {\n\treturn 0, \"\"\n}\n"
  },
  {
    "path": "lib/netext/httpext/error_codes_syscall_windows.go",
    "content": "package httpext\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"syscall\"\n)\n\nfunc getOSSyscallErrorCode(e *net.OpError, se *os.SyscallError) (errCode, string) {\n\tswitch se.Unwrap() {\n\tcase syscall.WSAECONNRESET:\n\t\treturn tcpResetByPeerErrorCode, fmt.Sprintf(tcpResetByPeerErrorCodeMsg, e.Op)\n\t}\n\treturn 0, \"\"\n}\n"
  },
  {
    "path": "lib/netext/httpext/error_codes_test.go",
    "content": "package httpext\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\t\"syscall\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/net/http2\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/httpmultibin\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestDefaultError(t *testing.T) {\n\tt.Parallel()\n\ttestErrorCode(t, defaultErrorCode, fmt.Errorf(\"random error\"))\n}\n\nfunc TestDNSErrors(t *testing.T) {\n\tt.Parallel()\n\tvar (\n\t\tdefaultDNSError = new(net.DNSError)\n\t\tnoSuchHostError = new(net.DNSError)\n\t)\n\n\tnoSuchHostError.Err = \"no such host\" // defined as private in go stdlib\n\ttestTable := map[errCode]error{\n\t\tdefaultDNSErrorCode:    defaultDNSError,\n\t\tdnsNoSuchHostErrorCode: noSuchHostError,\n\t}\n\ttestMapOfErrorCodes(t, testTable)\n}\n\nfunc TestBlackListedIPError(t *testing.T) {\n\tt.Parallel()\n\terr := netext.BlackListedIPError{}\n\ttestErrorCode(t, blackListedIPErrorCode, err)\n\terrorCode, errorMsg := errorCodeForError(err)\n\trequire.NotEqual(t, err.Error(), errorMsg)\n\trequire.Equal(t, blackListedIPErrorCode, errorCode)\n}\n\ntype timeoutError bool\n\nfunc (t timeoutError) Timeout() bool {\n\treturn (bool)(t)\n}\n\nfunc (t timeoutError) Error() string {\n\treturn fmt.Sprintf(\"%t\", t)\n}\n\nfunc TestUnknownNetErrno(t *testing.T) {\n\tt.Parallel()\n\terr := new(net.OpError)\n\terr.Op = \"write\"\n\terr.Net = \"tcp\"\n\terr.Err = syscall.ENOTRECOVERABLE // Highly unlikely to actually need to do anything with this error\n\texpectedError := fmt.Sprintf(\n\t\t\"write: unknown errno `%d` on %s with message `%s`\",\n\t\tsyscall.ENOTRECOVERABLE, runtime.GOOS, err.Err)\n\terrorCode, errorMsg := errorCodeForError(err)\n\trequire.Equal(t, expectedError, errorMsg)\n\trequire.Equal(t, netUnknownErrnoErrorCode, errorCode)\n}\n\nfunc TestTCPErrors(t *testing.T) {\n\tt.Parallel()\n\tvar (\n\t\tnonTCPError       = &net.OpError{Net: \"something\", Err: errors.New(\"non tcp error\")}\n\t\teconnreset        = &net.OpError{Net: \"tcp\", Op: \"write\", Err: &os.SyscallError{Err: syscall.ECONNRESET}}\n\t\tepipeerror        = &net.OpError{Net: \"tcp\", Op: \"write\", Err: &os.SyscallError{Err: syscall.EPIPE}}\n\t\teconnrefused      = &net.OpError{Net: \"tcp\", Op: \"dial\", Err: &os.SyscallError{Err: syscall.ECONNREFUSED}}\n\t\terrnounknown      = &net.OpError{Net: \"tcp\", Op: \"dial\", Err: &os.SyscallError{Err: syscall.E2BIG}}\n\t\ttcperror          = &net.OpError{Net: \"tcp\", Err: errors.New(\"tcp error\")}\n\t\tnotTimeoutedError = &net.OpError{Net: \"tcp\", Op: \"dial\", Err: timeoutError(false)}\n\t)\n\n\ttestTable := map[errCode]error{\n\t\tdefaultNetNonTCPErrorCode: nonTCPError,\n\t\ttcpResetByPeerErrorCode:   econnreset,\n\t\ttcpBrokenPipeErrorCode:    epipeerror,\n\t\ttcpDialRefusedErrorCode:   econnrefused,\n\t\ttcpDialUnknownErrnoCode:   errnounknown,\n\t\tdefaultTCPErrorCode:       tcperror,\n\t\ttcpDialErrorCode:          notTimeoutedError,\n\t}\n\n\ttestMapOfErrorCodes(t, testTable)\n}\n\nfunc testErrorCode(t *testing.T, code errCode, err error) {\n\tt.Helper()\n\tresult, _ := errorCodeForError(err)\n\trequire.Equalf(t, code, result, \"Wrong error code for error `%s`\", err)\n\n\tresult, _ = errorCodeForError(fmt.Errorf(\"foo: %w\", err))\n\trequire.Equalf(t, code, result, \"Wrong error code for error `%s`\", err)\n\n\tresult, _ = errorCodeForError(&url.Error{Err: err})\n\trequire.Equalf(t, code, result, \"Wrong error code for error `%s`\", err)\n}\n\nfunc testMapOfErrorCodes(t *testing.T, testTable map[errCode]error) {\n\tt.Helper()\n\tfor code, err := range testTable {\n\t\ttestErrorCode(t, code, err)\n\t}\n}\n\nfunc TestConnReset(t *testing.T) {\n\tt.Parallel()\n\t// based on https://gist.github.com/jpittis/4357d817dc425ae99fbf719828ab1800\n\tln, err := (&net.ListenConfig{}).Listen(context.Background(), \"tcp\", \"localhost:0\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\taddr := ln.Addr()\n\tch := make(chan error, 10)\n\n\tgo func() {\n\t\tdefer close(ch)\n\t\t// Accept one connection.\n\t\tconn, innerErr := ln.Accept()\n\t\tif innerErr != nil {\n\t\t\tch <- innerErr\n\t\t\treturn\n\t\t}\n\n\t\t// Force an RST\n\t\ttcpConn, ok := conn.(*net.TCPConn)\n\t\trequire.True(t, ok)\n\t\tinnerErr = tcpConn.SetLinger(0)\n\t\tif innerErr != nil {\n\t\t\tch <- innerErr\n\t\t}\n\t\ttime.Sleep(time.Second) // Give time for the http request to start\n\t\t_ = conn.Close()\n\t}()\n\n\tres, err := http.Get(\"http://\" + addr.String()) //nolint:bodyclose,noctx\n\trequire.Nil(t, res)\n\n\tcode, msg := errorCodeForError(err)\n\tassert.Equal(t, tcpResetByPeerErrorCode, code)\n\tassert.Contains(t, msg, fmt.Sprintf(tcpResetByPeerErrorCodeMsg, \"\"))\n\tfor err := range ch {\n\t\tassert.Nil(t, err)\n\t}\n}\n\nfunc TestDnsResolve(t *testing.T) {\n\tt.Parallel()\n\t// this uses the Unwrap path\n\t// this is not happening in our current codebase as the resolution in our code\n\t// happens earlier so it doesn't get wrapped, but possibly happens in other cases as well\n\t_, err := http.Get(\"http://s.com\") //nolint:bodyclose,noctx\n\tcode, msg := errorCodeForError(err)\n\n\tassert.Equal(t, dnsNoSuchHostErrorCode, code)\n\tassert.Equal(t, dnsNoSuchHostErrorCodeMsg, msg)\n}\n\nfunc TestHTTP2StreamError(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\ttb.Mux.HandleFunc(\"/tsr\", func(rw http.ResponseWriter, _ *http.Request) {\n\t\trw.Header().Set(\"Content-Length\", \"100000\")\n\t\trw.WriteHeader(http.StatusOK)\n\n\t\tf, ok := rw.(http.Flusher)\n\t\tif !ok {\n\t\t\tpanic(\"expected http.ResponseWriter to be http.Flusher\")\n\t\t}\n\t\tf.Flush()\n\t\ttime.Sleep(time.Millisecond * 2)\n\t\tpanic(\"expected internal error\")\n\t})\n\tclient := http.Client{\n\t\tTimeout:   time.Second * 3,\n\t\tTransport: tb.HTTPTransport,\n\t}\n\n\tres, err := client.Get(tb.Replacer.Replace(\"HTTP2BIN_URL/tsr\")) //nolint:noctx\n\trequire.NotNil(t, res)\n\trequire.NoError(t, err)\n\t_, err = io.ReadAll(res.Body)\n\t_ = res.Body.Close()\n\trequire.Error(t, err)\n\n\tcode, msg := errorCodeForError(err)\n\tassert.Equal(t, unknownHTTP2StreamErrorCode+errCode(http2.ErrCodeInternal)+1, code)\n\tassert.Contains(t, msg, fmt.Sprintf(http2StreamErrorCodeMsg, http2.ErrCodeInternal))\n}\n\nfunc TestX509HostnameError(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tclient := http.Client{\n\t\tTimeout:   time.Second * 3,\n\t\tTransport: tb.HTTPTransport,\n\t}\n\tvar err error\n\tbadHostname := \"somewhere.else\"\n\tbadHost, err := types.NewHost(net.ParseIP(tb.Replacer.Replace(\"HTTPSBIN_IP\")), \"\")\n\trequire.NoError(t, err)\n\n\ttb.Dialer.Hosts, err = types.NewHosts(map[string]types.Host{\n\t\tbadHostname: *badHost,\n\t})\n\trequire.NoError(t, err)\n\treq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, tb.Replacer.Replace(\"https://\"+badHostname+\":HTTPSBIN_PORT/get\"), nil)\n\trequire.NoError(t, err)\n\tres, err := client.Do(req) //nolint:bodyclose\n\trequire.Nil(t, res)\n\trequire.Error(t, err)\n\n\tcode, msg := errorCodeForError(err)\n\tassert.Equal(t, x509HostnameErrorCode, code)\n\tassert.Contains(t, msg, x509HostnameErrorCodeMsg)\n}\n\nfunc TestX509UnknownAuthorityError(t *testing.T) {\n\tt.Parallel()\n\ttb := httpmultibin.NewHTTPMultiBin(t)\n\n\tclient := http.Client{\n\t\tTimeout: time.Second * 3,\n\t\tTransport: &http.Transport{\n\t\t\tDialContext: tb.HTTPTransport.DialContext,\n\t\t},\n\t}\n\treq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, tb.Replacer.Replace(\"HTTPSBIN_URL/get\"), nil)\n\trequire.NoError(t, err)\n\tres, err := client.Do(req) //nolint:bodyclose\n\trequire.Nil(t, res)\n\trequire.Error(t, err)\n\n\tcode, msg := errorCodeForError(err)\n\tassert.Equal(t, x509UnknownAuthorityErrorCode, code)\n\tassert.Contains(t, msg, x509UnknownAuthority)\n}\n\nfunc TestDefaultTLSError(t *testing.T) {\n\tt.Parallel()\n\n\tl, err := (&net.ListenConfig{}).Listen(context.Background(), \"tcp\", \"127.0.0.1:0\")\n\trequire.NoError(t, err)\n\tgo func() {\n\t\tconn, err := l.Accept()\n\t\trequire.NoError(t, err)\n\t\t_, err = conn.Write([]byte(\"not tls header\")) // we just want to get an error\n\t\trequire.NoError(t, err)\n\t\t// wait so it has time to get the tls header error and not the reset socket one\n\t\ttime.Sleep(time.Second)\n\t}()\n\n\tclient := http.Client{\n\t\tTimeout: time.Second * 3,\n\t\tTransport: &http.Transport{\n\t\t\tTLSClientConfig: &tls.Config{\n\t\t\t\tInsecureSkipVerify: true,\n\t\t\t},\n\t\t},\n\t}\n\n\t_, err = client.Get(\"https://\" + l.Addr().String()) //nolint:bodyclose,noctx\n\trequire.Error(t, err)\n\n\tcode, msg := errorCodeForError(err)\n\tassert.Equal(t, tlsHeaderErrorCode, code)\n\turlError := new(url.Error)\n\trequire.ErrorAs(t, err, &urlError)\n\tassert.Equal(t, urlError.Err.Error(), msg)\n}\n\nfunc TestHTTP2ConnectionError(t *testing.T) {\n\tt.Parallel()\n\ttb := getHTTP2ServerWithCustomConnContext(t)\n\n\t// Pre-configure the HTTP client transport with the dialer and TLS config (incl. HTTP2 support)\n\ttb.Mux.HandleFunc(\"/tsr\", func(_ http.ResponseWriter, req *http.Request) {\n\t\tconn := req.Context().Value(connKey).(*tls.Conn)\n\t\tf := http2.NewFramer(conn, conn)\n\t\trequire.NoError(t, f.WriteData(3213, false, []byte(\"something\")))\n\t})\n\tclient := http.Client{\n\t\tTimeout:   time.Second * 5,\n\t\tTransport: tb.HTTPTransport,\n\t}\n\n\t_, err := client.Get(tb.Replacer.Replace(\"HTTP2BIN_URL/tsr\")) //nolint:bodyclose,noctx\n\tcode, msg := errorCodeForError(err)\n\tassert.Equal(t, unknownHTTP2ConnectionErrorCode+errCode(http2.ErrCodeProtocol)+1, code)\n\tassert.Equal(t, fmt.Sprintf(http2ConnectionErrorCodeMsg, http2.ErrCodeProtocol), msg)\n}\n\nfunc TestHTTP2GoAwayError(t *testing.T) {\n\tt.Parallel()\n\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skip(\"Skipped due to https://github.com/grafana/k6/issues/4098\")\n\t}\n\ttb := getHTTP2ServerWithCustomConnContext(t)\n\ttb.Mux.HandleFunc(\"/tsr\", func(_ http.ResponseWriter, req *http.Request) {\n\t\tconn := req.Context().Value(connKey).(*tls.Conn)\n\t\tf := http2.NewFramer(conn, conn)\n\t\trequire.NoError(t, f.WriteGoAway(4, http2.ErrCodeInadequateSecurity, []byte(\"whatever\")))\n\t\trequire.NoError(t, conn.CloseWrite())\n\t})\n\tclient := http.Client{\n\t\tTimeout:   time.Second * 5,\n\t\tTransport: tb.HTTPTransport,\n\t}\n\n\t_, err := client.Get(tb.Replacer.Replace(\"HTTP2BIN_URL/tsr\")) //nolint:bodyclose,noctx\n\n\trequire.Error(t, err)\n\tcode, msg := errorCodeForError(err)\n\tassert.Equal(t, unknownHTTP2GoAwayErrorCode+errCode(http2.ErrCodeInadequateSecurity)+1, code)\n\tassert.Equal(t, fmt.Sprintf(http2GoAwayErrorCodeMsg, http2.ErrCodeInadequateSecurity), msg)\n}\n\ntype connKeyT int32\n\nconst connKey connKeyT = 2\n\nfunc getHTTP2ServerWithCustomConnContext(t *testing.T) *httpmultibin.HTTPMultiBin {\n\tconst http2Domain = \"example.com\"\n\tmux := http.NewServeMux()\n\thttp2Srv := httptest.NewUnstartedServer(mux)\n\thttp2Srv.EnableHTTP2 = true\n\thttp2Srv.Config.ConnContext = func(ctx context.Context, c net.Conn) context.Context {\n\t\treturn context.WithValue(ctx, connKey, c)\n\t}\n\thttp2Srv.StartTLS()\n\tt.Cleanup(http2Srv.Close)\n\ttlsConfig := httpmultibin.GetTLSClientConfig(t, http2Srv)\n\n\thttp2URL, err := url.Parse(http2Srv.URL)\n\trequire.NoError(t, err)\n\thttp2IP := net.ParseIP(http2URL.Hostname())\n\trequire.NotNil(t, http2IP)\n\thttp2DomainValue, err := types.NewHost(http2IP, \"\")\n\trequire.NoError(t, err)\n\n\t// Set up the dialer with shorter timeouts and the custom domains\n\tdialer := netext.NewDialer(net.Dialer{\n\t\tTimeout:   2 * time.Second,\n\t\tKeepAlive: 10 * time.Second,\n\t}, netext.NewResolver(net.LookupIP, 0, types.DNSfirst, types.DNSpreferIPv4))\n\tdialer.Hosts, err = types.NewHosts(map[string]types.Host{\n\t\thttp2Domain: *http2DomainValue,\n\t})\n\trequire.NoError(t, err)\n\n\ttransport := &http.Transport{\n\t\tDialContext:     dialer.DialContext,\n\t\tTLSClientConfig: tlsConfig,\n\t}\n\trequire.NoError(t, http2.ConfigureTransport(transport))\n\treturn &httpmultibin.HTTPMultiBin{\n\t\tMux:         mux,\n\t\tServerHTTP2: http2Srv,\n\t\tReplacer: strings.NewReplacer(\n\t\t\t\"HTTP2BIN_IP_URL\", http2Srv.URL,\n\t\t\t\"HTTP2BIN_DOMAIN\", http2Domain,\n\t\t\t\"HTTP2BIN_URL\", fmt.Sprintf(\"https://%s\", net.JoinHostPort(http2Domain, http2URL.Port())),\n\t\t\t\"HTTP2BIN_IP\", http2IP.String(),\n\t\t\t\"HTTP2BIN_PORT\", http2URL.Port(),\n\t\t),\n\t\tTLSClientConfig: tlsConfig,\n\t\tDialer:          dialer,\n\t\tHTTPTransport:   transport,\n\t}\n}\n"
  },
  {
    "path": "lib/netext/httpext/httpdebug_transport.go",
    "content": "package httpext\n\nimport (\n\t\"bytes\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/sirupsen/logrus\"\n)\n\ntype httpDebugTransport struct {\n\toriginalTransport http.RoundTripper\n\thttpDebugOption   string\n\tlogger            logrus.FieldLogger\n}\n\n// RoundTrip prints passing HTTP requests and received responses\n//\n// TODO: massively improve this, because the printed information can be wrong:\n//   - https://github.com/k6io/k6/issues/986\n//   - https://github.com/k6io/k6/issues/1042\n//   - https://github.com/k6io/k6/issues/774\nfunc (t httpDebugTransport) RoundTrip(req *http.Request) (*http.Response, error) {\n\tid := uuid.NewString()\n\tt.debugRequest(req, id)\n\tresp, err := t.originalTransport.RoundTrip(req)\n\tt.debugResponse(resp, id)\n\treturn resp, err\n}\n\nfunc (t httpDebugTransport) debugRequest(req *http.Request, requestID string) {\n\tdump, err := httputil.DumpRequestOut(req, t.httpDebugOption == \"full\")\n\tif err != nil {\n\t\tt.logger.Error(err)\n\t}\n\tt.logger.WithField(\"request_id\", requestID).Infof(\"Request:\\n%s\\n\",\n\t\tbytes.ReplaceAll(dump, []byte(\"\\r\\n\"), []byte{'\\n'}))\n}\n\nfunc (t httpDebugTransport) debugResponse(res *http.Response, requestID string) {\n\tif res != nil {\n\t\tdump, err := httputil.DumpResponse(res, t.httpDebugOption == \"full\")\n\t\tif err != nil {\n\t\t\tt.logger.Error(err)\n\t\t}\n\t\tt.logger.WithField(\"request_id\", requestID).Infof(\"Response:\\n%s\\n\",\n\t\t\tbytes.ReplaceAll(dump, []byte(\"\\r\\n\"), []byte{'\\n'}))\n\t}\n}\n"
  },
  {
    "path": "lib/netext/httpext/request.go",
    "content": "package httpext\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/Azure/go-ntlmssp\"\n\t\"github.com/sirupsen/logrus\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// HTTPRequestCookie is a representation of a cookie used for request objects\ntype HTTPRequestCookie struct {\n\tName, Value string\n\tReplace     bool\n}\n\n// Request represents an HTTP request.\ntype Request struct {\n\tMethod  string                          `json:\"method\"`\n\tURL     string                          `json:\"url\"`\n\tHeaders map[string][]string             `json:\"headers\"`\n\tBody    string                          `json:\"body\"`\n\tCookies map[string][]*HTTPRequestCookie `json:\"cookies\"`\n}\n\n// ParsedHTTPRequest is a representation of a request after it has been parsed from a user script.\ntype ParsedHTTPRequest struct {\n\tURL              *URL\n\tBody             *bytes.Buffer\n\tReq              *http.Request\n\tTimeout          time.Duration\n\tAuth             string\n\tThrow            bool\n\tResponseType     ResponseType\n\tResponseCallback func(int) bool\n\tCompressions     []CompressionType\n\tRedirects        null.Int\n\tActiveJar        *cookiejar.Jar\n\tCookies          map[string]*HTTPRequestCookie\n\tTagsAndMeta      metrics.TagsAndMeta\n}\n\n// ncloser matches non-compliant io.Closer implementations (e.g. zstd.Decoder).\ntype ncloser interface {\n\tClose()\n}\n\ntype readCloser struct {\n\tio.Reader\n}\n\n// Close closes readers with differing Close() implementations.\nfunc (r readCloser) Close() error {\n\tvar err error\n\tswitch v := r.Reader.(type) {\n\tcase io.Closer:\n\t\terr = v.Close()\n\tcase ncloser:\n\t\tv.Close()\n\t}\n\treturn err\n}\n\nfunc stdCookiesToHTTPRequestCookies(cookies []*http.Cookie) map[string][]*HTTPRequestCookie {\n\tresult := make(map[string][]*HTTPRequestCookie, len(cookies))\n\tfor _, cookie := range cookies {\n\t\tresult[cookie.Name] = append(result[cookie.Name],\n\t\t\t&HTTPRequestCookie{Name: cookie.Name, Value: cookie.Value})\n\t}\n\treturn result\n}\n\n// TODO: move as a response method? or constructor?\nfunc updateK6Response(k6Response *Response, finishedReq *finishedRequest) {\n\tk6Response.ErrorCode = int(finishedReq.errorCode)\n\tk6Response.Error = finishedReq.errorMsg\n\ttrail := finishedReq.trail\n\n\tif trail.ConnRemoteAddr != nil {\n\t\tremoteHost, remotePortStr, _ := net.SplitHostPort(trail.ConnRemoteAddr.String())\n\t\tremotePort, _ := strconv.Atoi(remotePortStr)\n\t\tk6Response.RemoteIP = remoteHost\n\t\tk6Response.RemotePort = remotePort\n\t}\n\tk6Response.Timings = ResponseTimings{\n\t\tDuration:       metrics.D(trail.Duration),\n\t\tBlocked:        metrics.D(trail.Blocked),\n\t\tConnecting:     metrics.D(trail.Connecting),\n\t\tTLSHandshaking: metrics.D(trail.TLSHandshaking),\n\t\tSending:        metrics.D(trail.Sending),\n\t\tWaiting:        metrics.D(trail.Waiting),\n\t\tReceiving:      metrics.D(trail.Receiving),\n\t}\n}\n\n// MakeRequest makes an HTTP request for the provided ParsedHTTPRequest.\n//\n// TODO: split apart...\n//\n//nolint:cyclop, gocyclo, funlen, gocognit, nestif\nfunc MakeRequest(ctx context.Context, state *lib.State, preq *ParsedHTTPRequest) (*Response, error) {\n\trespReq := &Request{\n\t\tMethod:  preq.Req.Method,\n\t\tURL:     preq.Req.URL.String(),\n\t\tCookies: stdCookiesToHTTPRequestCookies(preq.Req.Cookies()),\n\t\tHeaders: preq.Req.Header,\n\t}\n\n\tif preq.Body != nil {\n\t\t// TODO: maybe hide this behind of flag in order for this to not happen for big post/puts?\n\t\t// should we set this after the compression? what will be the point ?\n\t\trespReq.Body = preq.Body.String()\n\n\t\tif len(preq.Compressions) > 0 {\n\t\t\tcompressedBody, contentEncoding, err := compressBody(preq.Compressions, io.NopCloser(preq.Body))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tpreq.Body = compressedBody\n\n\t\t\tcurrentContentEncoding := preq.Req.Header.Get(\"Content-Encoding\")\n\t\t\tif currentContentEncoding == \"\" {\n\t\t\t\tpreq.Req.Header.Set(\"Content-Encoding\", contentEncoding)\n\t\t\t} else if currentContentEncoding != contentEncoding {\n\t\t\t\tstate.Logger.Warningf(\n\t\t\t\t\t\"There's a mismatch between the desired `compression` the manually set `Content-Encoding` header \"+\n\t\t\t\t\t\t\"in the %s request for '%s', the custom header has precedence and won't be overwritten. \"+\n\t\t\t\t\t\t\"This may result in invalid data being sent to the server.\", preq.Req.Method, preq.Req.URL,\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tpreq.Req.ContentLength = int64(preq.Body.Len()) // This will make Go set the content-length header\n\t\tpreq.Req.GetBody = func() (io.ReadCloser, error) {\n\t\t\t//  using `Bytes()` should reuse the same buffer and as such help with the memory usage. We\n\t\t\t//  should not be writing to it any way so there shouldn't be way to corrupt it (?)\n\t\t\treturn io.NopCloser(bytes.NewBuffer(preq.Body.Bytes())), nil\n\t\t}\n\t\t// as per the documentation using GetBody still requires setting the Body.\n\t\tpreq.Req.Body, _ = preq.Req.GetBody()\n\t}\n\n\tif contentLengthHeader := preq.Req.Header.Get(\"Content-Length\"); contentLengthHeader != \"\" {\n\t\t// The content-length header was set by the user, delete it (since Go\n\t\t// will set it automatically) and warn if there were differences\n\t\tpreq.Req.Header.Del(\"Content-Length\")\n\t\tlength, err := strconv.Atoi(contentLengthHeader)\n\t\tif err != nil || preq.Req.ContentLength != int64(length) {\n\t\t\tstate.Logger.Warnf(\n\t\t\t\t\"The specified Content-Length header %q in the %s request for %s \"+\n\t\t\t\t\t\"doesn't match the actual request body length of %d, so it will be ignored!\",\n\t\t\t\tcontentLengthHeader, preq.Req.Method, preq.Req.URL, preq.Req.ContentLength,\n\t\t\t)\n\t\t}\n\t}\n\n\t// Only set the name system tag if the user didn't explicitly set it beforehand,\n\t// and the Name was generated from a tagged template string (via http.url).\n\tif _, ok := preq.TagsAndMeta.Tags.Get(metrics.TagName.String()); !ok &&\n\t\tstate.Options.SystemTags.Has(metrics.TagName) && preq.URL.Name != \"\" && preq.URL.Name != preq.URL.Clean() {\n\t\tpreq.TagsAndMeta.SetSystemTagOrMeta(metrics.TagName, preq.URL.Name)\n\t}\n\n\t// Check rate limit *after* we've prepared a request; no need to wait with that part.\n\tif rpsLimit := state.RPSLimit; rpsLimit != nil {\n\t\tif err := rpsLimit.Wait(ctx); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\ttracerTransport := newTransport(ctx, state, &preq.TagsAndMeta, preq.ResponseCallback)\n\tvar transport http.RoundTripper = tracerTransport\n\n\tif state.Options.HTTPDebug.String != \"\" {\n\t\t// Combine tags with common log fields\n\t\tcombinedLogFields := map[string]any{\"source\": \"http-debug\", \"vu\": state.VUID, \"iter\": state.Iteration}\n\t\tfor k, v := range preq.TagsAndMeta.Metadata {\n\t\t\tif _, present := combinedLogFields[k]; !present {\n\t\t\t\tcombinedLogFields[k] = v\n\t\t\t}\n\t\t}\n\t\tfor k, v := range preq.TagsAndMeta.Tags.Map() {\n\t\t\tif _, present := combinedLogFields[k]; !present {\n\t\t\t\tcombinedLogFields[k] = v\n\t\t\t}\n\t\t}\n\t\ttransport = httpDebugTransport{\n\t\t\toriginalTransport: transport,\n\t\t\thttpDebugOption:   state.Options.HTTPDebug.String,\n\t\t\tlogger:            state.Logger.WithFields(combinedLogFields),\n\t\t}\n\t}\n\n\tswitch preq.Auth {\n\tcase \"digest\":\n\t\t// Until digest authentication is refactored, the first response will always\n\t\t// be a 401 error, so we expect that.\n\t\tif tracerTransport.responseCallback != nil {\n\t\t\toriginalResponseCallback := tracerTransport.responseCallback\n\t\t\ttracerTransport.responseCallback = func(status int) bool {\n\t\t\t\ttracerTransport.responseCallback = originalResponseCallback\n\t\t\t\treturn status == 401\n\t\t\t}\n\t\t}\n\t\ttransport = digestTransport{originalTransport: transport}\n\tcase \"ntlm\":\n\t\t// The first response of NTLM auth may be a 401 error.\n\t\tif tracerTransport.responseCallback != nil {\n\t\t\toriginalResponseCallback := tracerTransport.responseCallback\n\t\t\ttracerTransport.responseCallback = func(status int) bool {\n\t\t\t\ttracerTransport.responseCallback = originalResponseCallback\n\t\t\t\t// ntlm is connection-level based so we could've already authorized the connection and to now reuse it\n\t\t\t\treturn status == 401 || originalResponseCallback(status)\n\t\t\t}\n\t\t}\n\t\ttransport = ntlmssp.Negotiator{RoundTripper: transport}\n\t}\n\n\tresp := &Response{\n\t\tURL:     preq.URL.URL,\n\t\tRequest: respReq,\n\t\tHeaders: make(map[string]string),\n\t\tCookies: make(map[string][]*HTTPCookie),\n\t}\n\tclient := http.Client{\n\t\tTransport: transport,\n\t\tCheckRedirect: func(req *http.Request, via []*http.Request) error {\n\t\t\tresp.URL = req.URL.String()\n\n\t\t\t// Update active jar with cookies found in \"Set-Cookie\" header(s) of redirect response\n\t\t\tif preq.ActiveJar != nil {\n\t\t\t\tif respCookies := req.Response.Cookies(); len(respCookies) > 0 {\n\t\t\t\t\tpreq.ActiveJar.SetCookies(via[len(via)-1].URL, respCookies)\n\t\t\t\t}\n\t\t\t\treq.Header.Del(\"Cookie\")\n\t\t\t\tSetRequestCookies(req, preq.ActiveJar, preq.Cookies)\n\t\t\t}\n\n\t\t\tif l := len(via); int64(l) > preq.Redirects.Int64 {\n\t\t\t\tif !preq.Redirects.Valid {\n\t\t\t\t\turl := req.URL\n\t\t\t\t\tif l > 0 {\n\t\t\t\t\t\turl = via[0].URL\n\t\t\t\t\t}\n\t\t\t\t\tstate.Logger.WithFields(logrus.Fields{\"url\": url.String()}).Warnf(\n\t\t\t\t\t\t\"Stopped after %d redirects and returned the redirection; pass { redirects: n }\"+\n\t\t\t\t\t\t\t\" in request params or set global maxRedirects to silence this\", l)\n\t\t\t\t}\n\t\t\t\treturn http.ErrUseLastResponse\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\treqCtx, cancelFunc := context.WithTimeout(ctx, preq.Timeout)\n\tdefer cancelFunc()\n\tmreq := preq.Req.WithContext(reqCtx)\n\tres, resErr := client.Do(mreq) //nolint:gosec\n\n\t// TODO(imiric): It would be safer to check for a writeable\n\t// response body here instead of status code, but those are\n\t// wrapped in a read-only body when using client timeouts and are\n\t// unusable until https://github.com/golang/go/issues/31391 is fixed.\n\tif res != nil && res.StatusCode == http.StatusSwitchingProtocols {\n\t\t_ = res.Body.Close()\n\t\treturn nil, fmt.Errorf(\"unsupported response status: %s\", res.Status)\n\t}\n\n\tif resErr == nil {\n\t\tresp.Body, resErr = readResponseBody(state, preq.ResponseType, res, resErr)\n\t\tif resErr != nil && errors.Is(resErr, context.DeadlineExceeded) {\n\t\t\t// TODO This can be more specific that the timeout happened in the middle of the reading of the body\n\t\t\tresErr = NewK6Error(requestTimeoutErrorCode, requestTimeoutErrorCodeMsg, resErr)\n\t\t}\n\t}\n\tfinishedReq := tracerTransport.processLastSavedRequest(wrapDecompressionError(resErr))\n\tif finishedReq != nil {\n\t\tupdateK6Response(resp, finishedReq)\n\t}\n\n\tif resErr == nil {\n\t\tif preq.ActiveJar != nil {\n\t\t\tif rc := res.Cookies(); len(rc) > 0 {\n\t\t\t\tpreq.ActiveJar.SetCookies(res.Request.URL, rc)\n\t\t\t}\n\t\t}\n\n\t\tresp.URL = res.Request.URL.String()\n\t\tresp.Status = res.StatusCode\n\t\tresp.StatusText = res.Status\n\t\tresp.Proto = res.Proto\n\n\t\tif res.TLS != nil {\n\t\t\tresp.setTLSInfo(res.TLS)\n\t\t}\n\n\t\tresp.Headers = make(map[string]string, len(res.Header))\n\t\tfor k, vs := range res.Header {\n\t\t\tresp.Headers[k] = strings.Join(vs, \", \")\n\t\t}\n\n\t\tresCookies := res.Cookies()\n\t\tresp.Cookies = make(map[string][]*HTTPCookie, len(resCookies))\n\t\tfor _, c := range resCookies {\n\t\t\tresp.Cookies[c.Name] = append(resp.Cookies[c.Name], &HTTPCookie{\n\t\t\t\tName:     c.Name,\n\t\t\t\tValue:    c.Value,\n\t\t\t\tDomain:   c.Domain,\n\t\t\t\tPath:     c.Path,\n\t\t\t\tHTTPOnly: c.HttpOnly,\n\t\t\t\tSecure:   c.Secure,\n\t\t\t\tMaxAge:   c.MaxAge,\n\t\t\t\tExpires:  c.Expires.UnixNano() / 1000000,\n\t\t\t})\n\t\t}\n\t}\n\n\tif resErr != nil {\n\t\tif preq.Throw { // if we are going to throw, we shouldn't log it\n\t\t\treturn nil, resErr\n\t\t}\n\n\t\t// Do *not* log errors about the context being cancelled.\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\tdefault:\n\t\t\tstate.Logger.WithField(\"error\", resErr).Warn(\"Request Failed\")\n\t\t}\n\t}\n\n\treturn resp, nil\n}\n\n// SetRequestCookies sets the cookies of the requests getting those cookies both from the jar and\n// from the reqCookies map. The Replace field of the HTTPRequestCookie will be taken into account\nfunc SetRequestCookies(req *http.Request, jar *cookiejar.Jar, reqCookies map[string]*HTTPRequestCookie) {\n\treplacedCookies := make(map[string]struct{})\n\tfor key, reqCookie := range reqCookies {\n\t\treq.AddCookie(&http.Cookie{Name: key, Value: reqCookie.Value})\n\t\tif reqCookie.Replace {\n\t\t\treplacedCookies[key] = struct{}{}\n\t\t}\n\t}\n\tfor _, c := range jar.Cookies(req.URL) {\n\t\tif _, ok := replacedCookies[c.Name]; !ok {\n\t\t\treq.AddCookie(&http.Cookie{Name: c.Name, Value: c.Value})\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/netext/httpext/request_test.go",
    "content": "package httpext\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"runtime\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/mccutchen/go-httpbin/v2/httpbin\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"golang.org/x/time/rate\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype reader func([]byte) (int, error)\n\nfunc (r reader) Read(a []byte) (int, error) {\n\treturn ((func([]byte) (int, error))(r))(a)\n}\n\nconst (\n\tbadReadMsg  = \"bad read error for test\"\n\tbadCloseMsg = \"bad close error for test\"\n)\n\nfunc badReadBody() io.Reader {\n\treturn reader(func(_ []byte) (int, error) {\n\t\treturn 0, errors.New(badReadMsg)\n\t})\n}\n\ntype closer func() error\n\nfunc (c closer) Close() error {\n\treturn ((func() error)(c))()\n}\n\nfunc badCloseBody() io.ReadCloser {\n\treturn struct {\n\t\tio.Reader\n\t\tio.Closer\n\t}{\n\t\tReader: reader(func(_ []byte) (int, error) {\n\t\t\treturn 0, io.EOF\n\t\t}),\n\t\tCloser: closer(func() error {\n\t\t\treturn errors.New(badCloseMsg)\n\t\t}),\n\t}\n}\n\nfunc TestCompressionBodyError(t *testing.T) {\n\tt.Parallel()\n\talgos := []CompressionType{CompressionTypeGzip}\n\tt.Run(\"bad read body\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, _, err := compressBody(algos, io.NopCloser(badReadBody()))\n\t\trequire.Error(t, err)\n\t\trequire.EqualError(t, err, badReadMsg)\n\t})\n\n\tt.Run(\"bad close body\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\t_, _, err := compressBody(algos, badCloseBody())\n\t\trequire.Error(t, err)\n\t\trequire.EqualError(t, err, badCloseMsg)\n\t})\n}\n\nfunc TestMakeRequestError(t *testing.T) {\n\tt.Parallel()\n\tctx, cancel := context.WithCancel(context.Background())\n\tt.Cleanup(cancel)\n\n\tt.Run(\"bad compression algorithm body\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, \"https://wont.be.used\", nil)\n\n\t\trequire.NoError(t, err)\n\t\tbadCompressionType := CompressionType(13)\n\t\trequire.False(t, badCompressionType.IsACompressionType())\n\t\tpreq := &ParsedHTTPRequest{\n\t\t\tReq:          req,\n\t\t\tBody:         new(bytes.Buffer),\n\t\t\tCompressions: []CompressionType{badCompressionType},\n\t\t}\n\t\tstate := &lib.State{\n\t\t\tTransport: http.DefaultTransport,\n\t\t\tLogger:    logrus.New(),\n\t\t\tTags:      lib.NewVUStateTags(metrics.NewRegistry().RootTagSet()),\n\t\t}\n\t\t_, err = MakeRequest(ctx, state, preq)\n\t\trequire.Error(t, err)\n\t\trequire.EqualError(t, err, \"unknown compressionType CompressionType(13)\")\n\t})\n\n\tt.Run(\"invalid upgrade response\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\tw.Header().Add(\"Connection\", \"Upgrade\")\n\t\t\tw.Header().Add(\"Upgrade\", \"h2c\")\n\t\t\tw.WriteHeader(http.StatusSwitchingProtocols)\n\t\t}))\n\t\tdefer srv.Close()\n\t\tctx := t.Context()\n\t\tlogger := logrus.New()\n\t\tlogger.Level = logrus.DebugLevel\n\t\tstate := &lib.State{\n\t\t\tTransport: srv.Client().Transport,\n\t\t\tLogger:    logger,\n\t\t\tTags:      lib.NewVUStateTags(metrics.NewRegistry().RootTagSet()),\n\t\t}\n\t\treq, _ := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL, nil)\n\t\tpreq := &ParsedHTTPRequest{\n\t\t\tReq:         req,\n\t\t\tURL:         &URL{u: req.URL},\n\t\t\tBody:        new(bytes.Buffer),\n\t\t\tTimeout:     10 * time.Second,\n\t\t\tTagsAndMeta: state.Tags.GetCurrentValues(),\n\t\t}\n\n\t\tres, err := MakeRequest(ctx, state, preq)\n\n\t\tassert.Nil(t, res)\n\t\tassert.EqualError(t, err, \"unsupported response status: 101 Switching Protocols\")\n\t})\n}\n\nfunc TestResponseStatus(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"response status\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestCases := []struct {\n\t\t\tname                     string\n\t\t\tstatusCode               int\n\t\t\tstatusCodeExpected       int\n\t\t\tstatusCodeStringExpected string\n\t\t}{\n\t\t\t{\"status 200\", 200, 200, \"200 OK\"},\n\t\t\t{\"status 201\", 201, 201, \"201 Created\"},\n\t\t\t{\"status 202\", 202, 202, \"202 Accepted\"},\n\t\t\t{\"status 203\", 203, 203, \"203 Non-Authoritative Information\"},\n\t\t\t{\"status 204\", 204, 204, \"204 No Content\"},\n\t\t\t{\"status 205\", 205, 205, \"205 Reset Content\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tserver := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\t\t\t\tw.WriteHeader(tc.statusCode)\n\t\t\t\t}))\n\t\t\t\tdefer server.Close()\n\t\t\t\tlogger := logrus.New()\n\t\t\t\tlogger.Level = logrus.DebugLevel\n\t\t\t\tsamples := make(chan<- metrics.SampleContainer, 1)\n\t\t\t\tregistry := metrics.NewRegistry()\n\t\t\t\tstate := &lib.State{\n\t\t\t\t\tTransport:      server.Client().Transport,\n\t\t\t\t\tLogger:         logger,\n\t\t\t\t\tSamples:        samples,\n\t\t\t\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\t\t\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t\t\t\t}\n\t\t\t\treq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, server.URL, nil)\n\t\t\t\trequire.NoError(t, err)\n\n\t\t\t\tpreq := &ParsedHTTPRequest{\n\t\t\t\t\tReq:          req,\n\t\t\t\t\tURL:          &URL{u: req.URL},\n\t\t\t\t\tBody:         new(bytes.Buffer),\n\t\t\t\t\tTimeout:      10 * time.Second,\n\t\t\t\t\tResponseType: ResponseTypeNone,\n\t\t\t\t\tTagsAndMeta:  state.Tags.GetCurrentValues(),\n\t\t\t\t}\n\n\t\t\t\tctx := t.Context()\n\t\t\t\tres, err := MakeRequest(ctx, state, preq)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.statusCodeExpected, res.Status)\n\t\t\t\tassert.Equal(t, tc.statusCodeStringExpected, res.StatusText)\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestURL(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Clean\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestCases := []struct {\n\t\t\turl      string\n\t\t\texpected string\n\t\t}{\n\t\t\t{\"https://example.com/\", \"https://example.com/\"},\n\t\t\t{\"https://example.com/${}\", \"https://example.com/${}\"},\n\t\t\t{\"https://user@example.com/\", \"https://****@example.com/\"},\n\t\t\t{\"https://user:pass@example.com/\", \"https://****:****@example.com/\"},\n\t\t\t{\"https://user:pass@example.com/path?a=1&b=2\", \"https://****:****@example.com/path?a=1&b=2\"},\n\t\t\t{\"https://user:pass@example.com/${}/${}\", \"https://****:****@example.com/${}/${}\"},\n\t\t\t{\"@malformed/url\", \"@malformed/url\"},\n\t\t\t{\"not a url\", \"not a url\"},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\tt.Run(tc.url, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tu, err := url.Parse(tc.url)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tut := URL{u: u, URL: tc.url}\n\t\t\t\trequire.Equal(t, tc.expected, ut.Clean())\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestMakeRequestTimeoutInTheMiddle(t *testing.T) {\n\tt.Parallel()\n\tsrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {\n\t\tw.Header().Add(\"Content-Length\", \"100000\")\n\t\tw.WriteHeader(http.StatusOK)\n\t\tif f, ok := w.(http.Flusher); ok {\n\t\t\tf.Flush()\n\t\t}\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}))\n\tdefer srv.Close()\n\tctx := t.Context()\n\tsamples := make(chan metrics.SampleContainer, 10)\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tTransport:      srv.Client().Transport,\n\t\tSamples:        samples,\n\t\tLogger:         logger,\n\t\tBufferPool:     lib.NewBufferPool(),\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\treq, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, srv.URL, nil)\n\tpreq := &ParsedHTTPRequest{\n\t\tReq:              req,\n\t\tURL:              &URL{u: req.URL, URL: srv.URL},\n\t\tBody:             new(bytes.Buffer),\n\t\tTimeout:          50 * time.Millisecond,\n\t\tResponseCallback: func(i int) bool { return i == 0 },\n\t\tTagsAndMeta:      state.Tags.GetCurrentValues(),\n\t}\n\n\tres, err := MakeRequest(ctx, state, preq)\n\trequire.NoError(t, err)\n\tassert.NotNil(t, res)\n\tassert.Len(t, samples, 1)\n\tsampleCont := <-samples\n\tallSamples := sampleCont.GetSamples()\n\trequire.Len(t, allSamples, 9)\n\texpTags := map[string]string{\n\t\t\"error\":             \"request timeout\",\n\t\t\"error_code\":        \"1050\",\n\t\t\"status\":            \"0\",\n\t\t\"expected_response\": \"true\", // we wait for status code 0\n\t\t\"method\":            \"GET\",\n\t\t\"url\":               srv.URL,\n\t\t\"name\":              srv.URL,\n\t}\n\tfor _, s := range allSamples {\n\t\tassert.Equal(t, expTags, s.Tags.Map())\n\t\tassert.Nil(t, s.Metadata)\n\t}\n}\n\nfunc BenchmarkWrapDecompressionError(b *testing.B) {\n\terr := errors.New(\"error\")\n\tb.ResetTimer()\n\tb.ReportAllocs()\n\tfor i := 0; i < b.N; i++ {\n\t\t_ = wrapDecompressionError(err)\n\t}\n}\n\nfunc TestTrailFailed(t *testing.T) {\n\tt.Parallel()\n\tsrv := httptest.NewTLSServer(httpbin.New().Handler())\n\tt.Cleanup(srv.Close)\n\n\ttestCases := map[string]struct {\n\t\tresponseCallback func(int) bool\n\t\tfailed           null.Bool\n\t}{\n\t\t\"null responsecallback\": {responseCallback: nil, failed: null.NewBool(false, false)},\n\t\t\"unexpected response\":   {responseCallback: func(int) bool { return false }, failed: null.NewBool(true, true)},\n\t\t\"expected response\":     {responseCallback: func(int) bool { return true }, failed: null.NewBool(false, true)},\n\t}\n\tfor name, testCase := range testCases {\n\t\tresponseCallback := testCase.responseCallback\n\t\tfailed := testCase.failed\n\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tctx, cancel := context.WithCancel(context.Background())\n\t\t\tt.Cleanup(cancel)\n\n\t\t\tsamples := make(chan metrics.SampleContainer, 10)\n\t\t\tlogger := logrus.New()\n\t\t\tlogger.Level = logrus.DebugLevel\n\t\t\tregistry := metrics.NewRegistry()\n\t\t\tstate := &lib.State{\n\t\t\t\tOptions: lib.Options{\n\t\t\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t\t\t},\n\t\t\t\tTransport:      srv.Client().Transport,\n\t\t\t\tSamples:        samples,\n\t\t\t\tLogger:         logger,\n\t\t\t\tBufferPool:     lib.NewBufferPool(),\n\t\t\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\t\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t\t\t}\n\t\t\treq, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, srv.URL, nil)\n\t\t\tpreq := &ParsedHTTPRequest{\n\t\t\t\tReq:              req,\n\t\t\t\tURL:              &URL{u: req.URL, URL: srv.URL},\n\t\t\t\tBody:             new(bytes.Buffer),\n\t\t\t\tTimeout:          10 * time.Millisecond,\n\t\t\t\tResponseCallback: responseCallback,\n\t\t\t\tTagsAndMeta:      state.Tags.GetCurrentValues(),\n\t\t\t}\n\t\t\tres, err := MakeRequest(ctx, state, preq)\n\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, res)\n\t\t\trequire.Len(t, samples, 1)\n\t\t\tsample := <-samples\n\n\t\t\ttrail, ok := sample.(*Trail)\n\t\t\trequire.True(t, ok)\n\n\t\t\trequire.Equal(t, failed, trail.Failed)\n\n\t\t\tvar httpReqFailedSampleValue null.Bool\n\t\t\tfor _, s := range sample.GetSamples() {\n\t\t\t\tif s.Metric.Name == metrics.HTTPReqFailedName {\n\t\t\t\t\thttpReqFailedSampleValue.Valid = true\n\t\t\t\t\tif s.Value == 1.0 {\n\t\t\t\t\t\thttpReqFailedSampleValue.Bool = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\trequire.Equal(t, failed, httpReqFailedSampleValue)\n\t\t})\n\t}\n}\n\nfunc TestMakeRequestDialTimeout(t *testing.T) {\n\tif runtime.GOOS == \"windows\" {\n\t\tt.Skipf(\"dial timeout doesn't get returned on windows\") // or we don't match it correctly\n\t}\n\tt.Parallel()\n\tln, err := (&net.ListenConfig{}).Listen(context.Background(), \"tcp\", \"localhost:0\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\taddr := ln.Addr()\n\tdefer func() {\n\t\trequire.NoError(t, ln.Close())\n\t}()\n\tctx := t.Context()\n\tsamples := make(chan metrics.SampleContainer, 10)\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tTransport: &http.Transport{\n\t\t\tDialContext: (&net.Dialer{\n\t\t\t\tTimeout: 1 * time.Microsecond,\n\t\t\t}).DialContext,\n\t\t},\n\t\tSamples:        samples,\n\t\tLogger:         logger,\n\t\tBufferPool:     lib.NewBufferPool(),\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\n\treq, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, \"http://\"+addr.String(), nil)\n\tpreq := &ParsedHTTPRequest{\n\t\tReq:              req,\n\t\tURL:              &URL{u: req.URL, URL: req.URL.String()},\n\t\tBody:             new(bytes.Buffer),\n\t\tTimeout:          500 * time.Millisecond,\n\t\tResponseCallback: func(i int) bool { return i == 0 },\n\t\tTagsAndMeta:      state.Tags.GetCurrentValues(),\n\t}\n\n\tres, err := MakeRequest(ctx, state, preq)\n\trequire.NoError(t, err)\n\tassert.NotNil(t, res)\n\tassert.Len(t, samples, 1)\n\tsampleCont := <-samples\n\tallSamples := sampleCont.GetSamples()\n\trequire.Len(t, allSamples, 9)\n\texpTags := map[string]string{\n\t\t\"error\":             \"dial: i/o timeout\",\n\t\t\"error_code\":        \"1211\",\n\t\t\"status\":            \"0\",\n\t\t\"expected_response\": \"true\", // we wait for status code 0\n\t\t\"method\":            \"GET\",\n\t\t\"url\":               req.URL.String(),\n\t\t\"name\":              req.URL.String(),\n\t}\n\tfor _, s := range allSamples {\n\t\tassert.Equal(t, expTags, s.Tags.Map())\n\t\tassert.Nil(t, s.Metadata)\n\t}\n}\n\nfunc TestMakeRequestTimeoutInTheBegining(t *testing.T) {\n\tt.Parallel()\n\tsrv := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {\n\t\ttime.Sleep(100 * time.Millisecond)\n\t}))\n\tdefer srv.Close()\n\tctx := t.Context()\n\tsamples := make(chan metrics.SampleContainer, 10)\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tTransport:      srv.Client().Transport,\n\t\tSamples:        samples,\n\t\tLogger:         logger,\n\t\tBufferPool:     lib.NewBufferPool(),\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\treq, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, srv.URL, nil)\n\tpreq := &ParsedHTTPRequest{\n\t\tReq:              req,\n\t\tURL:              &URL{u: req.URL, URL: srv.URL},\n\t\tBody:             new(bytes.Buffer),\n\t\tTimeout:          50 * time.Millisecond,\n\t\tResponseCallback: func(i int) bool { return i == 0 },\n\t\tTagsAndMeta:      state.Tags.GetCurrentValues(),\n\t}\n\n\tres, err := MakeRequest(ctx, state, preq)\n\trequire.NoError(t, err)\n\tassert.NotNil(t, res)\n\tassert.Len(t, samples, 1)\n\tsampleCont := <-samples\n\tallSamples := sampleCont.GetSamples()\n\trequire.Len(t, allSamples, 9)\n\texpTags := map[string]string{\n\t\t\"error\":             \"request timeout\",\n\t\t\"error_code\":        \"1050\",\n\t\t\"status\":            \"0\",\n\t\t\"expected_response\": \"true\", // we wait for status code 0\n\t\t\"method\":            \"GET\",\n\t\t\"url\":               srv.URL,\n\t\t\"name\":              srv.URL,\n\t}\n\tfor _, s := range allSamples {\n\t\tassert.Equal(t, expTags, s.Tags.Map())\n\t\tassert.Nil(t, s.Metadata)\n\t}\n}\n\nfunc TestMakeRequestFailedHostInitializesHeadersAndCookies(t *testing.T) {\n\tt.Parallel()\n\tctx := t.Context()\n\tsamples := make(chan metrics.SampleContainer, 10)\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tTransport:      http.DefaultTransport,\n\t\tSamples:        samples,\n\t\tLogger:         logger,\n\t\tBufferPool:     lib.NewBufferPool(),\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\n\tinvalidURL := \"https://test.k6.i\"\n\treq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, invalidURL, nil)\n\trequire.NoError(t, err)\n\n\tpreq := &ParsedHTTPRequest{\n\t\tReq:         req,\n\t\tURL:         &URL{u: req.URL, URL: invalidURL},\n\t\tBody:        new(bytes.Buffer),\n\t\tTimeout:     10 * time.Second,\n\t\tTagsAndMeta: state.Tags.GetCurrentValues(),\n\t}\n\n\tres, err := MakeRequest(ctx, state, preq)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, res)\n\n\tassert.NotNil(t, res.Headers, \"Headers map should be initialized even for failed requests\")\n\tassert.NotNil(t, res.Cookies, \"Cookies map should be initialized even for failed requests\")\n\n\tres.Headers[\"test-key\"] = \"test-value\"\n\tres.Cookies[\"test-cookie\"] = []*HTTPCookie{{Name: \"test\", Value: \"value\"}}\n\tassert.Equal(t, \"test-value\", res.Headers[\"test-key\"])\n\tassert.Equal(t, \"test\", res.Cookies[\"test-cookie\"][0].Name)\n}\n\nfunc TestMakeRequestRPSLimit(t *testing.T) {\n\tt.Parallel()\n\tvar requests int64\n\tts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {\n\t\tatomic.AddInt64(&requests, 1)\n\t}))\n\tdefer ts.Close()\n\n\tctx := t.Context()\n\n\tsamples := make(chan metrics.SampleContainer, 10)\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-samples:\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tlogger := logrus.New()\n\tlogger.Out = io.Discard\n\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tRPSLimit:       rate.NewLimiter(rate.Limit(1), 1),\n\t\tTransport:      ts.Client().Transport,\n\t\tSamples:        samples,\n\t\tLogger:         logger,\n\t\tBufferPool:     lib.NewBufferPool(),\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tTags:           lib.NewVUStateTags(registry.RootTagSet()),\n\t}\n\n\ttimer := time.NewTimer(3 * time.Second)\n\tfor {\n\t\tselect {\n\t\tcase <-timer.C:\n\t\t\ttimer.Stop()\n\t\t\tval := atomic.LoadInt64(&requests)\n\t\t\tassert.NotEmpty(t, val)\n\t\t\tassert.InDelta(t, val, 3, 3)\n\t\t\treturn\n\t\tdefault:\n\t\t\treq, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, ts.URL, nil)\n\t\t\tpreq := &ParsedHTTPRequest{\n\t\t\t\tReq:         req,\n\t\t\t\tURL:         &URL{u: req.URL, URL: ts.URL, Name: ts.URL},\n\t\t\t\tTimeout:     10 * time.Millisecond,\n\t\t\t\tTagsAndMeta: state.Tags.GetCurrentValues(),\n\t\t\t}\n\t\t\t_, err := MakeRequest(ctx, state, preq)\n\t\t\trequire.NoError(t, err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/netext/httpext/response.go",
    "content": "package httpext\n\nimport (\n\t\"crypto/tls\"\n\n\t\"go.k6.io/k6/lib/netext\"\n)\n\n// ResponseType is used in the request to specify how the response body should be treated\n// The conversion and validation methods are auto-generated with https://github.com/alvaroloes/enumer:\n//\n//go:generate enumer -type=ResponseType -transform=snake -json -text -trimprefix ResponseType -output response_type_gen.go\ntype ResponseType uint\n\nconst (\n\t// ResponseTypeText causes k6 to return the response body as a string. It works\n\t// well for web pages and JSON documents, but it can cause issues with\n\t// binary files since their data could be lost when they're converted in the\n\t// UTF-16 strings JavaScript uses.\n\t// This is the default value for backwards-compatibility, unless the global\n\t// discardResponseBodies option is enabled.\n\tResponseTypeText ResponseType = iota\n\t// ResponseTypeBinary causes k6 to return the response body as a []byte, suitable\n\t// for working with binary files without lost data and needless string conversions.\n\tResponseTypeBinary\n\t// ResponseTypeNone causes k6 to fully read the response body while immediately\n\t// discarding the actual data - k6 would set the body of the returned HTTPResponse\n\t// to null. This saves CPU and memory and is suitable for HTTP requests that we just\n\t// want to  measure, but we don't care about their responses' contents. This is the\n\t// default value for all requests if the global discardResponseBodies is enablled.\n\tResponseTypeNone\n)\n\n// ResponseTimings is a struct to put all timings for a given HTTP response/request\ntype ResponseTimings struct {\n\tDuration       float64 `json:\"duration\"`\n\tBlocked        float64 `json:\"blocked\"`\n\tLookingUp      float64 `json:\"looking_up\"`\n\tConnecting     float64 `json:\"connecting\"`\n\tTLSHandshaking float64 `json:\"tls_handshaking\"`\n\tSending        float64 `json:\"sending\"`\n\tWaiting        float64 `json:\"waiting\"`\n\tReceiving      float64 `json:\"receiving\"`\n}\n\n// HTTPCookie is a representation of an http cookies used in the Response object\ntype HTTPCookie struct {\n\tName, Value, Domain, Path string\n\tHTTPOnly, Secure          bool\n\tMaxAge                    int\n\tExpires                   int64\n}\n\n// Response is a representation of an HTTP response\ntype Response struct {\n\tRemoteIP       string                   `json:\"remote_ip\"`\n\tRemotePort     int                      `json:\"remote_port\"`\n\tURL            string                   `json:\"url\"`\n\tStatus         int                      `json:\"status\"`\n\tStatusText     string                   `json:\"status_text\"`\n\tProto          string                   `json:\"proto\"`\n\tHeaders        map[string]string        `json:\"headers\"`\n\tCookies        map[string][]*HTTPCookie `json:\"cookies\"`\n\tBody           any                      `json:\"body\"`\n\tTimings        ResponseTimings          `json:\"timings\"`\n\tTLSVersion     string                   `json:\"tls_version\"`\n\tTLSCipherSuite string                   `json:\"tls_cipher_suite\"`\n\tOCSP           netext.OCSP              `json:\"ocsp\"`\n\tError          string                   `json:\"error\"`\n\tErrorCode      int                      `json:\"error_code\"`\n\tRequest        *Request                 `json:\"request\"`\n}\n\n// NewResponse returns an empty Response instance.\nfunc NewResponse() *Response {\n\treturn &Response{\n\t\tHeaders: make(map[string]string),\n\t\tCookies: make(map[string][]*HTTPCookie),\n\t\tBody:    []byte{},\n\t}\n}\n\nfunc (res *Response) setTLSInfo(tlsState *tls.ConnectionState) {\n\ttlsInfo, oscp := netext.ParseTLSConnState(tlsState)\n\tres.TLSVersion = tlsInfo.Version\n\tres.TLSCipherSuite = tlsInfo.CipherSuite\n\tres.OCSP = oscp\n}\n"
  },
  {
    "path": "lib/netext/httpext/response_type_gen.go",
    "content": "// Code generated by \"enumer -type=ResponseType -transform=snake -json -text -trimprefix ResponseType -output response_type_gen.go\"; DO NOT EDIT.\n\npackage httpext\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\nconst _ResponseTypeName = \"textbinarynone\"\n\nvar _ResponseTypeIndex = [...]uint8{0, 4, 10, 14}\n\nfunc (i ResponseType) String() string {\n\tif i >= ResponseType(len(_ResponseTypeIndex)-1) {\n\t\treturn fmt.Sprintf(\"ResponseType(%d)\", i)\n\t}\n\treturn _ResponseTypeName[_ResponseTypeIndex[i]:_ResponseTypeIndex[i+1]]\n}\n\nvar _ResponseTypeValues = []ResponseType{0, 1, 2}\n\nvar _ResponseTypeNameToValueMap = map[string]ResponseType{\n\t_ResponseTypeName[0:4]:   0,\n\t_ResponseTypeName[4:10]:  1,\n\t_ResponseTypeName[10:14]: 2,\n}\n\n// ResponseTypeString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc ResponseTypeString(s string) (ResponseType, error) {\n\tif val, ok := _ResponseTypeNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to ResponseType values\", s)\n}\n\n// ResponseTypeValues returns all values of the enum\nfunc ResponseTypeValues() []ResponseType {\n\treturn _ResponseTypeValues\n}\n\n// IsAResponseType returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i ResponseType) IsAResponseType() bool {\n\tfor _, v := range _ResponseTypeValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// MarshalJSON implements the json.Marshaler interface for ResponseType\nfunc (i ResponseType) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(i.String())\n}\n\n// UnmarshalJSON implements the json.Unmarshaler interface for ResponseType\nfunc (i *ResponseType) UnmarshalJSON(data []byte) error {\n\tvar s string\n\tif err := json.Unmarshal(data, &s); err != nil {\n\t\treturn fmt.Errorf(\"ResponseType should be a string, got %s\", data)\n\t}\n\n\tvar err error\n\t*i, err = ResponseTypeString(s)\n\treturn err\n}\n\n// MarshalText implements the encoding.TextMarshaler interface for ResponseType\nfunc (i ResponseType) MarshalText() ([]byte, error) {\n\treturn []byte(i.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface for ResponseType\nfunc (i *ResponseType) UnmarshalText(text []byte) error {\n\tvar err error\n\t*i, err = ResponseTypeString(string(text))\n\treturn err\n}\n"
  },
  {
    "path": "lib/netext/httpext/tracer.go",
    "content": "package httpext\n\nimport (\n\t\"crypto/tls\"\n\t\"net\"\n\t\"net/http/httptrace\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"go.k6.io/k6/metrics\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// A Trail represents detailed information about an HTTP request.\n// You'd typically get one from a Tracer.\ntype Trail struct {\n\tEndTime time.Time\n\n\t// Total connect time (Connecting + TLSHandshaking)\n\tConnDuration time.Duration\n\n\t// Total request duration, excluding DNS lookup and connect time.\n\tDuration time.Duration\n\n\tBlocked        time.Duration // Waiting to acquire a connection.\n\tConnecting     time.Duration // Connecting to remote host.\n\tTLSHandshaking time.Duration // Executing TLS handshake.\n\tSending        time.Duration // Writing request.\n\tWaiting        time.Duration // Waiting for first byte.\n\tReceiving      time.Duration // Receiving response.\n\n\t// Detailed connection information.\n\tConnReused     bool\n\tConnRemoteAddr net.Addr\n\n\tFailed null.Bool\n\t// Populated by SaveSamples()\n\tTags     *metrics.TagSet\n\tMetadata map[string]string\n\tSamples  []metrics.Sample\n}\n\n// SaveSamples populates the Trail's sample slice so they're accessible via GetSamples()\nfunc (tr *Trail) SaveSamples(builtinMetrics *metrics.BuiltinMetrics, ctm *metrics.TagsAndMeta) {\n\ttr.Tags = ctm.Tags\n\ttr.Metadata = ctm.Metadata\n\ttr.Samples = make([]metrics.Sample, 0, 9) // this is with 1 more for a possible HTTPReqFailed\n\ttr.Samples = append(tr.Samples, []metrics.Sample{\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqs,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    1,\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqDuration,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(tr.Duration),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqBlocked,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(tr.Blocked),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqConnecting,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(tr.Connecting),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqTLSHandshaking,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(tr.TLSHandshaking),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqSending,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(tr.Sending),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqWaiting,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(tr.Waiting),\n\t\t},\n\t\t{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: builtinMetrics.HTTPReqReceiving,\n\t\t\t\tTags:   ctm.Tags,\n\t\t\t},\n\t\t\tTime:     tr.EndTime,\n\t\t\tMetadata: ctm.Metadata,\n\t\t\tValue:    metrics.D(tr.Receiving),\n\t\t},\n\t}...)\n}\n\n// GetSamples implements the metrics.SampleContainer interface.\nfunc (tr *Trail) GetSamples() []metrics.Sample {\n\treturn tr.Samples\n}\n\n// GetTags implements the metrics.ConnectedSampleContainer interface.\nfunc (tr *Trail) GetTags() *metrics.TagSet {\n\treturn tr.Tags\n}\n\n// GetTime implements the metrics.ConnectedSampleContainer interface.\nfunc (tr *Trail) GetTime() time.Time {\n\treturn tr.EndTime\n}\n\n// Ensure that interfaces are implemented correctly\nvar _ metrics.ConnectedSampleContainer = &Trail{}\n\n// A Tracer wraps \"net/http/httptrace\" to collect granular timings for HTTP requests.\n// Note that since there is not yet an event for the end of a request (there's a PR to\n// add it), you must call Done() at the end of the request to get the full timings.\n// It's NOT safe to reuse Tracers between requests.\n// Cheers, love, the cavalry's here.\ntype Tracer struct {\n\tgetConn              int64\n\tconnectStart         int64\n\tconnectDone          int64\n\ttlsHandshakeStart    int64\n\ttlsHandshakeDone     int64\n\tgotConn              int64\n\twroteRequest         int64\n\tgotFirstResponseByte int64\n\n\tconnReused     bool\n\tconnRemoteAddr net.Addr\n}\n\n// Trace returns a premade ClientTrace that calls all of the Tracer's hooks.\nfunc (t *Tracer) Trace() *httptrace.ClientTrace {\n\treturn &httptrace.ClientTrace{\n\t\tGetConn:              t.GetConn,\n\t\tConnectStart:         t.ConnectStart,\n\t\tConnectDone:          t.ConnectDone,\n\t\tTLSHandshakeStart:    t.TLSHandshakeStart,\n\t\tTLSHandshakeDone:     t.TLSHandshakeDone,\n\t\tGotConn:              t.GotConn,\n\t\tWroteRequest:         t.WroteRequest,\n\t\tGotFirstResponseByte: t.GotFirstResponseByte,\n\t}\n}\n\nfunc now() int64 {\n\treturn time.Now().UnixNano()\n}\n\n// GetConn is called before a connection is created or\n// retrieved from an idle pool. The hostPort is the\n// \"host:port\" of the target or proxy. GetConn is called even\n// if there's already an idle cached connection available.\n//\n// Keep in mind that GetConn won't be called if a connection\n// is reused though, for example when there's a redirect.\n// If it's called, it will be called before all other hooks.\nfunc (t *Tracer) GetConn(_ string) {\n\tt.getConn = now()\n}\n\n// ConnectStart is called when a new connection's Dial begins.\n// If net.Dialer.DualStack (IPv6 \"Happy Eyeballs\") support is\n// enabled (default), this may be called multiple times.\n//\n// If the connection is reused, this won't be called. Otherwise,\n// it will be called after GetConn() and before ConnectDone().\nfunc (t *Tracer) ConnectStart(_, _ string) {\n\t// If using dual-stack dialing, it's possible to get this\n\t// multiple times, so the atomic compareAndSwap ensures\n\t// that only the first call's time is recorded\n\tatomic.CompareAndSwapInt64(&t.connectStart, 0, now())\n}\n\n// ConnectDone is called when a new connection's Dial\n// completes. The provided err indicates whether the\n// connection completed successfully.\n// If net.Dialer.DualStack (\"Happy Eyeballs\") support is\n// enabled (default), this may be called multiple times.\n//\n// If the connection is reused, this won't be called. Otherwise,\n// it will be called after ConnectStart() and before either\n// TLSHandshakeStart() (for TLS connections) or GotConn().\nfunc (t *Tracer) ConnectDone(_, _ string, err error) {\n\t// If using dual-stack dialing, it's possible to get this\n\t// multiple times, so the atomic compareAndSwap ensures\n\t// that only the first call's time is recorded\n\tif err == nil {\n\t\tatomic.CompareAndSwapInt64(&t.connectDone, 0, now())\n\t}\n\t// if there is an error it either is happy eyeballs related and doesn't matter or it will be\n\t// returned by the http call\n}\n\n// TLSHandshakeStart is called when the TLS handshake is started. When\n// connecting to a HTTPS site via a HTTP proxy, the handshake happens after\n// the CONNECT request is processed by the proxy.\n//\n// If the connection is reused, this won't be called. Otherwise,\n// it will be called after ConnectDone() and before TLSHandshakeDone().\nfunc (t *Tracer) TLSHandshakeStart() {\n\tatomic.CompareAndSwapInt64(&t.tlsHandshakeStart, 0, now())\n}\n\n// TLSHandshakeDone is called after the TLS handshake with either the\n// successful handshake's connection state, or a non-nil error on handshake\n// failure.\n//\n// If the connection is reused, this won't be called. Otherwise,\n// it will be called after TLSHandshakeStart() and before GotConn().\n// If the request was cancelled, this could be called after the\n// RoundTrip() method has returned.\nfunc (t *Tracer) TLSHandshakeDone(_ tls.ConnectionState, err error) {\n\tif err == nil {\n\t\tatomic.CompareAndSwapInt64(&t.tlsHandshakeDone, 0, now())\n\t}\n\t// if there is an error it will be returned by the http call\n}\n\n// GotConn is called after a successful connection is\n// obtained. There is no hook for failure to obtain a\n// connection; instead, use the error from Transport.RoundTrip.\n//\n// This is the fist hook called for reused connections. For new\n// connections, it's called either after TLSHandshakeDone()\n// (for TLS connections) or after ConnectDone()\nfunc (t *Tracer) GotConn(info httptrace.GotConnInfo) {\n\tnow := now()\n\n\t// This shouldn't be called multiple times so no synchronization here,\n\t// it's better for the race detector to panic if we're wrong.\n\tt.gotConn = now\n\tt.connReused = info.Reused\n\tt.connRemoteAddr = info.Conn.RemoteAddr()\n\n\t// The Go stdlib's http module can start connecting to a remote server, only\n\t// to abandon that connection even before it was fully established and reuse\n\t// a recently freed already existing connection.\n\t// We overwrite the different timestamps here, so the other callbacks don't\n\t// put incorrect values in them (they use CompareAndSwap)\n\t_, isConnTLS := info.Conn.(*tls.Conn)\n\tif info.Reused {\n\t\tatomic.SwapInt64(&t.connectStart, now)\n\t\tatomic.SwapInt64(&t.connectDone, now)\n\t\tif isConnTLS {\n\t\t\tatomic.SwapInt64(&t.tlsHandshakeStart, now)\n\t\t\tatomic.SwapInt64(&t.tlsHandshakeDone, now)\n\t\t}\n\t} else {\n\t\t// There's a bug in the Go stdlib where an HTTP/2 connection can be reused\n\t\t// but the httptrace.GotConnInfo struct will contain a false Reused property...\n\t\t// That's probably from a previously made connection that was abandoned and\n\t\t// directly put in the connection pool in favor of a just-freed already\n\t\t// established connection...\n\t\t//\n\t\t// Using CompareAndSwap here because the HTTP/2 roundtripper has retries and\n\t\t// it's possible this isn't actually the first request attempt...\n\t\tatomic.CompareAndSwapInt64(&t.connectStart, 0, now)\n\t\tatomic.CompareAndSwapInt64(&t.connectDone, 0, now)\n\t\tif isConnTLS {\n\t\t\tatomic.CompareAndSwapInt64(&t.tlsHandshakeStart, 0, now)\n\t\t\tatomic.CompareAndSwapInt64(&t.tlsHandshakeDone, 0, now)\n\t\t}\n\t}\n}\n\n// WroteRequest is called with the result of writing the\n// request and any body. It may be called multiple times\n// in the case of retried requests.\nfunc (t *Tracer) WroteRequest(info httptrace.WroteRequestInfo) {\n\tif info.Err == nil {\n\t\tatomic.StoreInt64(&t.wroteRequest, now())\n\t}\n\t// if there is an error it will be returned by the http call\n}\n\n// GotFirstResponseByte is called when the first byte of the response\n// headers is available.\n// If the request was cancelled, this could be called after the\n// RoundTrip() method has returned.\nfunc (t *Tracer) GotFirstResponseByte() {\n\tatomic.CompareAndSwapInt64(&t.gotFirstResponseByte, 0, now())\n}\n\n// Done calculates all metrics and should be called when the request is finished.\nfunc (t *Tracer) Done() *Trail {\n\tdone := time.Now()\n\n\ttrail := Trail{\n\t\tConnReused:     t.connReused,\n\t\tConnRemoteAddr: t.connRemoteAddr,\n\t}\n\n\tif t.gotConn != 0 && t.getConn != 0 && t.gotConn > t.getConn {\n\t\ttrail.Blocked = time.Duration(t.gotConn - t.getConn)\n\t}\n\n\t// It's possible for some of the methods of httptrace.ClientTrace to\n\t// actually be called after the http.Client or http.RoundTripper have\n\t// already returned our result and we've called Done(). This happens\n\t// mostly for cancelled requests, but we have to use atomics here as\n\t// well (or use global Tracer locking) so we can avoid data races.\n\tconnectStart := atomic.LoadInt64(&t.connectStart)\n\tconnectDone := atomic.LoadInt64(&t.connectDone)\n\ttlsHandshakeStart := atomic.LoadInt64(&t.tlsHandshakeStart)\n\ttlsHandshakeDone := atomic.LoadInt64(&t.tlsHandshakeDone)\n\tgotConn := atomic.LoadInt64(&t.gotConn)\n\twroteRequest := atomic.LoadInt64(&t.wroteRequest)\n\tgotFirstResponseByte := atomic.LoadInt64(&t.gotFirstResponseByte)\n\n\tif connectDone != 0 && connectStart != 0 {\n\t\ttrail.Connecting = time.Duration(connectDone - connectStart)\n\t}\n\tif tlsHandshakeDone != 0 && tlsHandshakeStart != 0 {\n\t\ttrail.TLSHandshaking = time.Duration(tlsHandshakeDone - tlsHandshakeStart)\n\t}\n\tif wroteRequest != 0 {\n\t\tswitch {\n\t\tcase tlsHandshakeDone != 0:\n\t\t\t// If the request was sent over TLS, we need to use\n\t\t\t// TLS Handshake Done time to calculate sending duration\n\t\t\ttrail.Sending = time.Duration(wroteRequest - tlsHandshakeDone)\n\t\tcase connectDone != 0:\n\t\t\t// Otherwise, use the end of the normal connection\n\t\t\ttrail.Sending = time.Duration(wroteRequest - connectDone)\n\t\tdefault:\n\t\t\t// Finally, this handles the strange HTTP/2 case where the GotConn() hook\n\t\t\t// gets called first, but with Reused=false\n\t\t\ttrail.Sending = time.Duration(wroteRequest - gotConn)\n\t\t}\n\n\t\tif gotFirstResponseByte != 0 {\n\t\t\t// We started receiving at least some response back\n\n\t\t\tif gotFirstResponseByte > wroteRequest {\n\t\t\t\t// For some requests, especially HTTP/2, the server starts responding before the\n\t\t\t\t// client has finished sending the full request\n\t\t\t\ttrail.Waiting = time.Duration(gotFirstResponseByte - wroteRequest)\n\t\t\t}\n\t\t} else {\n\t\t\t// The server never responded to our request\n\t\t\ttrail.Waiting = done.Sub(time.Unix(0, wroteRequest))\n\t\t}\n\t}\n\tif gotFirstResponseByte != 0 {\n\t\ttrail.Receiving = done.Sub(time.Unix(0, gotFirstResponseByte))\n\t}\n\n\t// Calculate total times using adjusted values.\n\ttrail.EndTime = done\n\ttrail.ConnDuration = trail.Connecting + trail.TLSHandshaking\n\ttrail.Duration = trail.Sending + trail.Waiting + trail.Receiving\n\n\treturn &trail\n}\n"
  },
  {
    "path": "lib/netext/httpext/tracer_test.go",
    "content": "package httpext\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/http/httptrace\"\n\t\"runtime\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/mccutchen/go-httpbin/v2/httpbin\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nconst traceDelay = 100 * time.Millisecond\n\nfunc getTestTracer(t *testing.T) (*Tracer, *httptrace.ClientTrace) {\n\ttracer := &Tracer{}\n\tct := tracer.Trace()\n\tif runtime.GOOS == \"windows\" {\n\t\t// HACK: Time resolution is not as accurate on Windows, see:\n\t\t//  https://github.com/golang/go/issues/8687\n\t\t//  https://github.com/golang/go/issues/41087\n\t\t// Which seems to be causing some metrics to have a value of 0,\n\t\t// since e.g. ConnectStart and ConnectDone could register the same time.\n\t\t// So we force delays in the ClientTrace event handlers\n\t\t// to hopefully reduce the chances of this happening.\n\t\tct = &httptrace.ClientTrace{\n\t\t\tConnectStart: func(a, n string) {\n\t\t\t\tt.Logf(\"called ConnectStart at\\t\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.ConnectStart(a, n)\n\t\t\t},\n\t\t\tConnectDone: func(a, n string, e error) {\n\t\t\t\tt.Logf(\"called ConnectDone at\\t\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.ConnectDone(a, n, e)\n\t\t\t},\n\t\t\tGetConn: func(h string) {\n\t\t\t\tt.Logf(\"called GetConn at\\t\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.GetConn(h)\n\t\t\t},\n\t\t\tGotConn: func(i httptrace.GotConnInfo) {\n\t\t\t\tt.Logf(\"called GotConn at\\t\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.GotConn(i)\n\t\t\t},\n\t\t\tTLSHandshakeStart: func() {\n\t\t\t\tt.Logf(\"called TLSHandshakeStart at\\t\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.TLSHandshakeStart()\n\t\t\t},\n\t\t\tTLSHandshakeDone: func(s tls.ConnectionState, e error) {\n\t\t\t\tt.Logf(\"called TLSHandshakeDone at\\t\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.TLSHandshakeDone(s, e)\n\t\t\t},\n\t\t\tWroteRequest: func(i httptrace.WroteRequestInfo) {\n\t\t\t\tt.Logf(\"called WroteRequest at\\t\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.WroteRequest(i)\n\t\t\t},\n\t\t\tGotFirstResponseByte: func() {\n\t\t\t\tt.Logf(\"called GotFirstResponseByte at\\t%v\\n\", now())\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t\ttracer.GotFirstResponseByte()\n\t\t\t},\n\t\t}\n\t}\n\n\treturn tracer, ct\n}\n\nfunc TestTracer(t *testing.T) { //nolint:tparallel\n\tt.Parallel()\n\tsrv := httptest.NewTLSServer(httpbin.New().Handler())\n\tdefer srv.Close()\n\n\ttransport, ok := srv.Client().Transport.(*http.Transport)\n\tassert.True(t, ok)\n\ttransport.DialContext = netext.NewDialer(\n\t\tnet.Dialer{},\n\t\tnetext.NewResolver(net.LookupIP, 0, types.DNSfirst, types.DNSpreferIPv4),\n\t).DialContext\n\n\tvar prev int64\n\tassertLaterOrZero := func(t *testing.T, val int64, canBeZero bool) {\n\t\tif canBeZero && val == 0 {\n\t\t\treturn\n\t\t}\n\t\tif prev > val {\n\t\t\t_, file, line, _ := runtime.Caller(1)\n\t\t\tt.Errorf(\"Expected %d to be greater or equal to %d (from %s:%d)\", val, prev, file, line)\n\t\t\treturn\n\t\t}\n\t\tprev = val\n\t}\n\tregistry := metrics.NewRegistry()\n\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\n\tfor tnum, isReuse := range []bool{false, true, true} { //nolint:paralleltest\n\t\tt.Run(fmt.Sprintf(\"Test #%d\", tnum), func(t *testing.T) {\n\t\t\t// Do not enable parallel testing, test relies on sequential execution\n\t\t\ttracer, ct := getTestTracer(t)\n\t\t\tctx := httptrace.WithClientTrace(context.Background(), ct)\n\t\t\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+\"/get\", nil)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tres, err := transport.RoundTrip(req)\n\t\t\trequire.NoError(t, err)\n\n\t\t\t_, err = io.Copy(io.Discard, res.Body)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.NoError(t, res.Body.Close())\n\t\t\tif runtime.GOOS == \"windows\" {\n\t\t\t\ttime.Sleep(traceDelay)\n\t\t\t}\n\t\t\ttrail := tracer.Done()\n\t\t\tctm := &metrics.TagsAndMeta{Tags: registry.RootTagSet().With(\"tag\", \"value\")}\n\t\t\ttrail.SaveSamples(builtinMetrics, ctm)\n\t\t\tsamples := trail.GetSamples()\n\n\t\t\tassertLaterOrZero(t, tracer.getConn, isReuse)\n\t\t\tassertLaterOrZero(t, tracer.connectStart, isReuse)\n\t\t\tassertLaterOrZero(t, tracer.connectDone, isReuse)\n\t\t\tassertLaterOrZero(t, tracer.tlsHandshakeStart, isReuse)\n\t\t\tassertLaterOrZero(t, tracer.tlsHandshakeDone, isReuse)\n\t\t\tassertLaterOrZero(t, tracer.gotConn, false)\n\t\t\tassertLaterOrZero(t, tracer.wroteRequest, false)\n\t\t\tassertLaterOrZero(t, tracer.gotFirstResponseByte, false)\n\t\t\tassertLaterOrZero(t, now(), false)\n\n\t\t\tassert.Equal(t, strings.TrimPrefix(srv.URL, \"https://\"), trail.ConnRemoteAddr.String())\n\n\t\t\tassert.Len(t, samples, 8)\n\t\t\tseenMetrics := map[*metrics.Metric]bool{}\n\t\t\tfor i, s := range samples {\n\t\t\t\tassert.NotContains(t, seenMetrics, s.Metric)\n\t\t\t\tseenMetrics[s.Metric] = true\n\n\t\t\t\tassert.False(t, s.Time.IsZero())\n\t\t\t\tassert.Equal(t, map[string]string{\"tag\": \"value\"}, s.Tags.Map())\n\n\t\t\t\tswitch s.Metric {\n\t\t\t\tcase builtinMetrics.HTTPReqs:\n\t\t\t\t\tassert.Equal(t, 1.0, s.Value)\n\t\t\t\t\tassert.Equal(t, 0, i, \"`HTTPReqs` is reported before the other HTTP builtinMetrics\")\n\t\t\t\tcase builtinMetrics.HTTPReqConnecting, builtinMetrics.HTTPReqTLSHandshaking:\n\t\t\t\t\tif isReuse {\n\t\t\t\t\t\tassert.Equal(t, 0.0, s.Value)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tfallthrough\n\t\t\t\tcase builtinMetrics.HTTPReqDuration, builtinMetrics.HTTPReqBlocked, builtinMetrics.HTTPReqSending, builtinMetrics.HTTPReqWaiting, builtinMetrics.HTTPReqReceiving:\n\t\t\t\t\tassert.True(t, s.Value > 0.0, \"%s is <= 0\", s.Metric.Name)\n\t\t\t\tdefault:\n\t\t\t\t\tt.Errorf(\"unexpected metric: %s\", s.Metric.Name)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\ntype failingConn struct {\n\tnet.Conn\n\tfailOnConnWrite bool\n}\n\nfunc (c *failingConn) Write(b []byte) (int, error) {\n\tif c.failOnConnWrite {\n\t\tc.failOnConnWrite = false\n\t\treturn 0, errors.New(\"write error\")\n\t}\n\n\treturn c.Conn.Write(b)\n}\n\nfunc TestTracerNegativeHttpSendingValues(t *testing.T) {\n\tt.Parallel()\n\tsrv := httptest.NewTLSServer(httpbin.New().Handler())\n\tdefer srv.Close()\n\n\ttransport, ok := srv.Client().Transport.(*http.Transport)\n\tassert.True(t, ok)\n\n\tdialer := &net.Dialer{}\n\tvar connection *failingConn\n\ttransport.DialContext = func(ctx context.Context, proto, addr string) (net.Conn, error) {\n\t\tconn, err := dialer.DialContext(ctx, proto, addr)\n\t\tconnection = &failingConn{conn, false}\n\t\treturn connection, err\n\t}\n\n\t{\n\t\ttracer := &Tracer{}\n\t\tctx := httptrace.WithClientTrace(context.Background(), tracer.Trace())\n\t\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+\"/get\", nil)\n\t\trequire.NoError(t, err)\n\t\tres, err := transport.RoundTrip(req)\n\t\trequire.NoError(t, err)\n\t\t_, err = io.Copy(io.Discard, res.Body)\n\t\tassert.NoError(t, err)\n\t\tassert.NoError(t, res.Body.Close())\n\t\ttracer.Done()\n\t}\n\n\t// make the next connection write fail\n\tconnection.failOnConnWrite = true\n\n\t{\n\t\ttracer := &Tracer{}\n\t\tctx := httptrace.WithClientTrace(context.Background(), tracer.Trace())\n\t\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+\"/get\", nil)\n\t\trequire.NoError(t, err)\n\t\tres, err := transport.RoundTrip(req)\n\t\trequire.NoError(t, err)\n\t\t_, err = io.Copy(io.Discard, res.Body)\n\t\tassert.NoError(t, err)\n\t\tassert.NoError(t, res.Body.Close())\n\t\ttrail := tracer.Done()\n\t\tregistry := metrics.NewRegistry()\n\t\tbuiltinMetrics := metrics.RegisterBuiltinMetrics(registry)\n\t\ttrail.SaveSamples(builtinMetrics, &metrics.TagsAndMeta{Tags: registry.RootTagSet()})\n\n\t\trequire.True(t, trail.Sending > 0)\n\t}\n}\n\nfunc TestTracerError(t *testing.T) {\n\tt.Parallel()\n\tsrv := httptest.NewTLSServer(httpbin.New().Handler())\n\tdefer srv.Close()\n\n\ttracer := &Tracer{}\n\tctx := httptrace.WithClientTrace(context.Background(), tracer.Trace())\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, srv.URL+\"/get\", nil)\n\trequire.NoError(t, err)\n\n\t_, err = http.DefaultTransport.RoundTrip(req) //nolint:bodyclose\n\n\tassert.Error(t, err)\n}\n\nfunc TestCancelledRequest(t *testing.T) {\n\tt.Parallel()\n\tsrv := httptest.NewTLSServer(httpbin.New().Handler())\n\tt.Cleanup(srv.Close)\n\n\tcancelTest := func(t *testing.T) {\n\t\ttracer := &Tracer{}\n\t\treq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, srv.URL+\"/delay/1\", nil)\n\t\trequire.NoError(t, err)\n\n\t\tctx, cancel := context.WithCancel(httptrace.WithClientTrace(req.Context(), tracer.Trace()))\n\t\treq = req.WithContext(ctx)\n\t\tgo func() {\n\t\t\ttime.Sleep(time.Duration(rand.Int31n(50)) * time.Millisecond)\n\t\t\tcancel()\n\t\t}()\n\n\t\tresp, err := srv.Client().Transport.RoundTrip(req) //nolint:bodyclose\n\t\t_ = tracer.Done()\n\t\tif resp == nil && err == nil {\n\t\t\tt.Errorf(\"Expected either a RoundTrip response or error but got %#v and %#v\", resp, err)\n\t\t}\n\t}\n\n\t// This Run will not return until the parallel subtests complete.\n\tt.Run(\"group\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfor i := range 200 {\n\t\t\tt.Run(fmt.Sprintf(\"TestCancelledRequest_%d\", i),\n\t\t\t\tfunc(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tcancelTest(t)\n\t\t\t\t})\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "lib/netext/httpext/transport.go",
    "content": "// Package httpext provides extensions to the standard net/http package\npackage httpext\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptrace\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/netext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// transport is an implementation of http.RoundTripper that will measure and emit\n// different metrics for each roundtrip\ntype transport struct {\n\tctx              context.Context\n\tstate            *lib.State\n\ttagsAndMeta      *metrics.TagsAndMeta\n\tresponseCallback func(int) bool\n\n\tlastRequest     *unfinishedRequest\n\tlastRequestLock *sync.Mutex\n}\n\n// unfinishedRequest stores the request and the raw result returned from the\n// underlying http.RoundTripper, but before its body has been read\ntype unfinishedRequest struct {\n\tctx      context.Context\n\ttracer   *Tracer\n\trequest  *http.Request\n\tresponse *http.Response\n\terr      error\n}\n\n// finishedRequest is produced once the request has been finalized; it is\n// triggered either by a subsequent RoundTrip, or for the last request in the\n// chain - by the MakeRequest function manually calling the transport method\n// processLastSavedRequest(), after reading the HTTP response body.\ntype finishedRequest struct {\n\t*unfinishedRequest\n\ttrail     *Trail\n\ttlsInfo   netext.TLSInfo\n\terrorCode errCode\n\terrorMsg  string\n}\n\nvar _ http.RoundTripper = &transport{}\n\n// newTransport returns a new http.RoundTripper implementation that wraps around\n// the provided state's Transport. It uses a httpext.Tracer to measure all HTTP\n// requests made through it and annotates and emits the recorded metric samples\n// through the state.Samples channel.\nfunc newTransport(\n\tctx context.Context,\n\tstate *lib.State,\n\ttagsAndMeta *metrics.TagsAndMeta,\n\tresponseCallback func(int) bool,\n) *transport {\n\treturn &transport{\n\t\tctx:              ctx,\n\t\tstate:            state,\n\t\ttagsAndMeta:      tagsAndMeta,\n\t\tresponseCallback: responseCallback,\n\t\tlastRequestLock:  new(sync.Mutex),\n\t}\n}\n\n// Helper method to finish the tracer trail, assemble the tag values and emits\n// the metric samples for the supplied unfinished request.\nfunc (t *transport) measureAndEmitMetrics(unfReq *unfinishedRequest) *finishedRequest {\n\ttrail := unfReq.tracer.Done()\n\n\tresult := &finishedRequest{\n\t\tunfinishedRequest: unfReq,\n\t\ttrail:             trail,\n\t}\n\n\ttagsAndMeta := t.tagsAndMeta.Clone()\n\tenabledTags := t.state.Options.SystemTags\n\tcleanURL := URL{u: unfReq.request.URL, URL: unfReq.request.URL.String()}.Clean()\n\n\t// After k6 v0.41.0, the `name` and `url` tags have the exact same values:\n\tnameTagValue, nameTagManuallySet := tagsAndMeta.Tags.Get(metrics.TagName.String())\n\tif !nameTagManuallySet {\n\t\t// If the user *didn't* manually set a `name` tag value and didn't use\n\t\t// the http.url template literal helper to have k6 automatically set\n\t\t// it (see `lib/netext/httpext.MakeRequest()`), we will use the cleaned\n\t\t// URL value as the value of both `name` and `url` tags.\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagName, cleanURL)\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagURL, cleanURL)\n\t} else {\n\t\t// However, if the user set the `name` tag value somehow, we will use\n\t\t// whatever they set as the value of the `url` tags too, to prevent\n\t\t// high-cardinality values in the indexed tags.\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagURL, nameTagValue)\n\t}\n\n\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagMethod, unfReq.request.Method)\n\n\tif unfReq.err != nil {\n\t\tresult.errorCode, result.errorMsg = errorCodeForError(unfReq.err)\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagError, result.errorMsg)\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagErrorCode, strconv.Itoa(int(result.errorCode)))\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagStatus, \"0\")\n\t} else {\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagStatus, strconv.Itoa(unfReq.response.StatusCode))\n\t\tif unfReq.response.StatusCode >= 400 {\n\t\t\tresult.errorCode = errCode(1000 + unfReq.response.StatusCode) //nolint:gosec\n\t\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagErrorCode, strconv.Itoa(int(result.errorCode)))\n\t\t}\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagProto, unfReq.response.Proto)\n\n\t\tif unfReq.response.TLS != nil {\n\t\t\ttlsInfo, oscp := netext.ParseTLSConnState(unfReq.response.TLS)\n\t\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagTLSVersion, tlsInfo.Version)\n\t\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagOCSPStatus, oscp.Status)\n\t\t\tresult.tlsInfo = tlsInfo\n\t\t}\n\t}\n\tif enabledTags.Has(metrics.TagIP) && trail.ConnRemoteAddr != nil {\n\t\tif ip, _, err := net.SplitHostPort(trail.ConnRemoteAddr.String()); err == nil {\n\t\t\ttagsAndMeta.SetSystemTagOrMeta(metrics.TagIP, ip)\n\t\t}\n\t}\n\tvar failed float64\n\tif t.responseCallback != nil {\n\t\tvar statusCode int\n\t\tif unfReq.err == nil {\n\t\t\tstatusCode = unfReq.response.StatusCode\n\t\t}\n\t\texpected := t.responseCallback(statusCode)\n\t\tif !expected {\n\t\t\tfailed = 1\n\t\t}\n\n\t\ttagsAndMeta.SetSystemTagOrMetaIfEnabled(enabledTags, metrics.TagExpectedResponse, strconv.FormatBool(expected))\n\t}\n\n\ttrail.SaveSamples(t.state.BuiltinMetrics, &tagsAndMeta)\n\tif t.responseCallback != nil {\n\t\ttrail.Failed.Valid = true\n\t\tif failed == 1 {\n\t\t\ttrail.Failed.Bool = true\n\t\t}\n\t\ttrail.Samples = append(trail.Samples,\n\t\t\tmetrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: t.state.BuiltinMetrics.HTTPReqFailed,\n\t\t\t\t\tTags:   tagsAndMeta.Tags,\n\t\t\t\t},\n\t\t\t\tTime:     trail.EndTime,\n\t\t\t\tMetadata: tagsAndMeta.Metadata,\n\t\t\t\tValue:    failed,\n\t\t\t},\n\t\t)\n\t}\n\tmetrics.PushIfNotDone(t.ctx, t.state.Samples, trail)\n\treturn result\n}\n\nfunc (t *transport) saveCurrentRequest(currentRequest *unfinishedRequest) {\n\tt.lastRequestLock.Lock()\n\tunprocessedRequest := t.lastRequest\n\tt.lastRequest = currentRequest\n\tt.lastRequestLock.Unlock()\n\n\tif unprocessedRequest != nil {\n\t\t// This shouldn't happen, since we have one transport per request, but just in case...\n\t\tt.state.Logger.Warnf(\"TracerTransport: unexpected unprocessed request for %s\", unprocessedRequest.request.URL)\n\t\tt.measureAndEmitMetrics(unprocessedRequest)\n\t}\n}\n\nfunc (t *transport) processLastSavedRequest(lastErr error) *finishedRequest {\n\tt.lastRequestLock.Lock()\n\tunprocessedRequest := t.lastRequest\n\tt.lastRequest = nil\n\tt.lastRequestLock.Unlock()\n\n\tif unprocessedRequest != nil {\n\t\t// We don't want to overwrite any previous errors, but if there were\n\t\t// none and we (i.e. the MakeRequest() function) have one, save it\n\t\t// before we emit the metrics.\n\t\tif unprocessedRequest.err == nil && lastErr != nil {\n\t\t\tunprocessedRequest.err = lastErr\n\t\t}\n\n\t\treturn t.measureAndEmitMetrics(unprocessedRequest)\n\t}\n\treturn nil\n}\n\n// RoundTrip is the implementation of http.RoundTripper\nfunc (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {\n\tt.processLastSavedRequest(nil)\n\n\tctx := req.Context()\n\ttracer := &Tracer{}\n\t// nosemgrep: dynamic-httptrace-clienttrace // this is a false possitive\n\treqWithTracer := req.WithContext(httptrace.WithClientTrace(ctx, tracer.Trace()))\n\tresp, err := t.state.Transport.RoundTrip(reqWithTracer)\n\n\tvar netError net.Error\n\tif errors.As(err, &netError) && netError.Timeout() {\n\t\tvar netOpError *net.OpError\n\t\tif errors.As(err, &netOpError) && netOpError.Op == \"dial\" {\n\t\t\terr = NewK6Error(tcpDialTimeoutErrorCode, tcpDialTimeoutErrorCodeMsg, netError)\n\t\t} else {\n\t\t\terr = NewK6Error(requestTimeoutErrorCode, requestTimeoutErrorCodeMsg, netError)\n\t\t}\n\t}\n\n\tt.saveCurrentRequest(&unfinishedRequest{\n\t\tctx:      ctx,\n\t\ttracer:   tracer,\n\t\trequest:  req,\n\t\tresponse: resp,\n\t\terr:      err,\n\t})\n\n\treturn resp, err\n}\n"
  },
  {
    "path": "lib/netext/httpext/transport_test.go",
    "content": "package httpext\n\nimport (\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc BenchmarkMeasureAndEmitMetrics(b *testing.B) {\n\tctx := b.Context()\n\tsamples := make(chan metrics.SampleContainer, 10)\n\tdefer close(samples)\n\tgo func() { // discard all metrics\n\t\tfor range samples { //nolint:revive\n\t\t}\n\t}()\n\tlogger := logrus.New()\n\tlogger.Level = logrus.DebugLevel\n\n\tregistry := metrics.NewRegistry()\n\tstate := &lib.State{\n\t\tOptions: lib.Options{\n\t\t\tSystemTags: &metrics.DefaultSystemTagSet,\n\t\t},\n\t\tBuiltinMetrics: metrics.RegisterBuiltinMetrics(registry),\n\t\tSamples:        samples,\n\t\tLogger:         logger,\n\t}\n\tt := transport{\n\t\tstate:       state,\n\t\tctx:         ctx,\n\t\ttagsAndMeta: &metrics.TagsAndMeta{Tags: registry.RootTagSet()},\n\t}\n\n\tunfRequest := &unfinishedRequest{\n\t\ttracer: &Tracer{},\n\t\tresponse: &http.Response{\n\t\t\tStatusCode: http.StatusOK,\n\t\t},\n\t\trequest: &http.Request{\n\t\t\tURL: &url.URL{\n\t\t\t\tHost:   \"example.com\",\n\t\t\t\tScheme: \"https\",\n\t\t\t},\n\t\t},\n\t}\n\n\tb.Run(\"no responseCallback\", func(b *testing.B) {\n\t\tfor i := 0; i < b.N; i++ {\n\t\t\tt.measureAndEmitMetrics(unfRequest)\n\t\t}\n\t})\n\n\tt.responseCallback = func(_ int) bool { return true }\n\n\tb.Run(\"responseCallback\", func(b *testing.B) {\n\t\tfor i := 0; i < b.N; i++ {\n\t\t\tt.measureAndEmitMetrics(unfRequest)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "lib/netext/httpext/url.go",
    "content": "package httpext\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n)\n\n// A URL wraps net.URL, and preserves the template (if any) the URL was constructed from.\ntype URL struct {\n\tu        *url.URL\n\tName     string // http://example.com/thing/${}/\n\tURL      string // http://example.com/thing/1234/\n\tCleanURL string // URL with masked user credentials, used for output\n}\n\n// NewURL returns a new URL for the provided url and name. The error is returned if the url provided\n// can't be parsed\nfunc NewURL(urlString, name string) (URL, error) {\n\tu, err := url.Parse(urlString)\n\tif err != nil {\n\t\treturn URL{}, NewK6Error(invalidURLErrorCode,\n\t\t\tfmt.Sprintf(\"%s: %s\", invalidURLErrorCodeMsg, err), err)\n\t}\n\tnewURL := URL{u: u, Name: name, URL: urlString}\n\tnewURL.CleanURL = newURL.Clean()\n\tif urlString == name {\n\t\tnewURL.Name = newURL.CleanURL\n\t}\n\treturn newURL, nil\n}\n\n// Clean returns an output-safe representation of URL\nfunc (u URL) Clean() string {\n\tif u.CleanURL != \"\" {\n\t\treturn u.CleanURL\n\t}\n\n\tif u.u == nil || u.u.User == nil {\n\t\treturn u.URL\n\t}\n\n\tif password, passwordOk := u.u.User.Password(); passwordOk {\n\t\t// here 3 is for the '://' and 4 is because of '://' and ':' between the credentials\n\t\treturn u.URL[:len(u.u.Scheme)+3] + \"****:****\" + u.URL[len(u.u.Scheme)+4+len(u.u.User.Username())+len(password):]\n\t}\n\n\t// here 3 in both places is for the '://'\n\treturn u.URL[:len(u.u.Scheme)+3] + \"****\" + u.URL[len(u.u.Scheme)+3+len(u.u.User.Username()):]\n}\n\n// GetURL returns the internal url.URL\nfunc (u URL) GetURL() *url.URL {\n\treturn u.u\n}\n\n// ToURL tries to convert anything passed to it to a k6 URL struct\nfunc ToURL(u any) (URL, error) {\n\tswitch tu := u.(type) {\n\tcase URL:\n\t\t// Handling of http.url`http://example.com/{$id}`\n\t\treturn tu, nil\n\tcase string:\n\t\t// Handling of \"http://example.com/\"\n\t\treturn NewURL(tu, tu)\n\tdefault:\n\t\treturn URL{}, NewK6Error(invalidURLErrorCode,\n\t\t\tfmt.Sprintf(\"%s: '#%v'\", invalidURLErrorCodeMsg, u), nil)\n\t}\n}\n"
  },
  {
    "path": "lib/netext/resolver.go",
    "content": "package netext\n\nimport (\n\t\"math/rand\" // nosemgrep: math-random-used // used for random TTL on DNS resolve\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// MultiResolver returns all IP addresses for the given host.\ntype MultiResolver func(host string) ([]net.IP, error)\n\n// Resolver is an interface that returns DNS information about a given host.\ntype Resolver interface {\n\tLookupIP(host string) (net.IP, error)\n}\n\ntype resolver struct {\n\tresolve     MultiResolver\n\tselectIndex types.DNSSelect\n\tpolicy      types.DNSPolicy\n\trrm         *sync.Mutex\n\trand        *rand.Rand\n\troundRobin  map[string]uint8\n}\n\ntype cacheRecord struct {\n\tips        []net.IP\n\tlastLookup time.Time\n}\n\ntype cacheResolver struct {\n\tresolver\n\tttl   time.Duration\n\tcm    *sync.Mutex\n\tcache map[string]cacheRecord\n}\n\n// NewResolver returns a new DNS resolver. If ttl is not 0, responses\n// will be cached per host for the specified period. The IP returned from\n// LookupIP() will be selected based on the given sel and pol values.\nfunc NewResolver(\n\tactRes MultiResolver, ttl time.Duration, sel types.DNSSelect, pol types.DNSPolicy,\n) Resolver {\n\tr := rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec\n\tres := resolver{\n\t\tresolve:     actRes,\n\t\tselectIndex: sel,\n\t\tpolicy:      pol,\n\t\trrm:         &sync.Mutex{},\n\t\trand:        r,\n\t\troundRobin:  make(map[string]uint8),\n\t}\n\tif ttl == 0 {\n\t\treturn &res\n\t}\n\treturn &cacheResolver{\n\t\tresolver: res,\n\t\tttl:      ttl,\n\t\tcm:       &sync.Mutex{},\n\t\tcache:    make(map[string]cacheRecord),\n\t}\n}\n\n// LookupIP returns a single IP resolved for host, selected according to the\n// configured select and policy options.\nfunc (r *resolver) LookupIP(host string) (net.IP, error) {\n\tips, err := r.resolve(host)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tips = r.applyPolicy(ips)\n\treturn r.selectOne(host, ips), nil\n}\n\n// LookupIP returns a single IP resolved for host, selected according to the\n// configured select and policy options. Results are cached per host and will be\n// refreshed if the last lookup time exceeds the configured TTL (not the TTL\n// returned in the DNS record).\nfunc (r *cacheResolver) LookupIP(host string) (net.IP, error) {\n\tr.cm.Lock()\n\n\tvar ips []net.IP\n\t// TODO: Invalidate? When?\n\tif cr, ok := r.cache[host]; ok && time.Now().Before(cr.lastLookup.Add(r.ttl)) {\n\t\tips = cr.ips\n\t} else {\n\t\tr.cm.Unlock() // The lookup could take some time, so unlock momentarily.\n\t\tvar err error\n\t\tips, err = r.resolve(host)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tips = r.applyPolicy(ips)\n\t\tr.cm.Lock()\n\t\tr.cache[host] = cacheRecord{ips: ips, lastLookup: time.Now()}\n\t}\n\n\tr.cm.Unlock()\n\n\treturn r.selectOne(host, ips), nil\n}\n\nfunc (r *resolver) selectOne(host string, ips []net.IP) net.IP {\n\tif len(ips) == 0 {\n\t\treturn nil\n\t}\n\n\tvar ip net.IP\n\tswitch r.selectIndex {\n\tcase types.DNSfirst:\n\t\treturn ips[0]\n\tcase types.DNSroundRobin:\n\t\tr.rrm.Lock()\n\t\t// NOTE: This index approach is not stable and might result in returning\n\t\t// repeated or skipped IPs if the records change during a test run.\n\t\tip = ips[int(r.roundRobin[host])%len(ips)]\n\t\tr.roundRobin[host]++\n\t\tr.rrm.Unlock()\n\tcase types.DNSrandom:\n\t\tr.rrm.Lock()\n\t\tip = ips[r.rand.Intn(len(ips))]\n\t\tr.rrm.Unlock()\n\t}\n\n\treturn ip\n}\n\nfunc (r *resolver) applyPolicy(ips []net.IP) (retIPs []net.IP) {\n\tif r.policy == types.DNSany {\n\t\treturn ips\n\t}\n\tip4, ip6 := groupByVersion(ips)\n\tswitch r.policy {\n\tcase types.DNSpreferIPv4:\n\t\tretIPs = ip4\n\t\tif len(retIPs) == 0 {\n\t\t\tretIPs = ip6\n\t\t}\n\tcase types.DNSpreferIPv6:\n\t\tretIPs = ip6\n\t\tif len(retIPs) == 0 {\n\t\t\tretIPs = ip4\n\t\t}\n\tcase types.DNSonlyIPv4:\n\t\tretIPs = ip4\n\tcase types.DNSonlyIPv6:\n\t\tretIPs = ip6\n\t// Already checked above, but added to satisfy 'exhaustive' linter.\n\tcase types.DNSany:\n\t\tretIPs = ips\n\t}\n\n\treturn retIPs\n}\n\nfunc groupByVersion(ips []net.IP) (ip4 []net.IP, ip6 []net.IP) {\n\tfor _, ip := range ips {\n\t\tif ip.To4() != nil {\n\t\t\tip4 = append(ip4, ip)\n\t\t} else {\n\t\t\tip6 = append(ip6, ip)\n\t\t}\n\t}\n\n\treturn ip4, ip6\n}\n"
  },
  {
    "path": "lib/netext/resolver_test.go",
    "content": "package netext\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils/mockresolver\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\nfunc TestResolver(t *testing.T) {\n\tt.Parallel()\n\n\thost := \"myhost\"\n\tmr := mockresolver.New(map[string][]net.IP{\n\t\thost: {\n\t\t\tnet.ParseIP(\"127.0.0.10\"),\n\t\t\tnet.ParseIP(\"127.0.0.11\"),\n\t\t\tnet.ParseIP(\"127.0.0.12\"),\n\t\t\tnet.ParseIP(\"2001:db8::10\"),\n\t\t\tnet.ParseIP(\"2001:db8::11\"),\n\t\t\tnet.ParseIP(\"2001:db8::12\"),\n\t\t},\n\t})\n\n\tt.Run(\"LookupIP\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestCases := []struct {\n\t\t\tttl   time.Duration\n\t\t\tsel   types.DNSSelect\n\t\t\tpol   types.DNSPolicy\n\t\t\texpIP []net.IP\n\t\t}{\n\t\t\t{\n\t\t\t\t0, types.DNSfirst, types.DNSpreferIPv4,\n\t\t\t\t[]net.IP{net.ParseIP(\"127.0.0.10\")},\n\t\t\t},\n\t\t\t{\n\t\t\t\ttime.Second, types.DNSfirst, types.DNSpreferIPv4,\n\t\t\t\t[]net.IP{net.ParseIP(\"127.0.0.10\")},\n\t\t\t},\n\t\t\t{0, types.DNSroundRobin, types.DNSonlyIPv6, []net.IP{\n\t\t\t\tnet.ParseIP(\"2001:db8::10\"),\n\t\t\t\tnet.ParseIP(\"2001:db8::11\"),\n\t\t\t\tnet.ParseIP(\"2001:db8::12\"),\n\t\t\t\tnet.ParseIP(\"2001:db8::10\"),\n\t\t\t}},\n\t\t\t{\n\t\t\t\t0, types.DNSfirst, types.DNSpreferIPv6,\n\t\t\t\t[]net.IP{net.ParseIP(\"2001:db8::10\")},\n\t\t\t},\n\t\t\t{0, types.DNSroundRobin, types.DNSpreferIPv4, []net.IP{\n\t\t\t\tnet.ParseIP(\"127.0.0.10\"),\n\t\t\t\tnet.ParseIP(\"127.0.0.11\"),\n\t\t\t\tnet.ParseIP(\"127.0.0.12\"),\n\t\t\t\tnet.ParseIP(\"127.0.0.10\"),\n\t\t\t}},\n\t\t}\n\n\t\tfor _, tc := range testCases {\n\t\t\tt.Run(fmt.Sprintf(\"%s_%s_%s\", tc.ttl, tc.sel, tc.pol), func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tr := NewResolver(mr.LookupIPAll, tc.ttl, tc.sel, tc.pol)\n\t\t\t\tip, err := r.LookupIP(host)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expIP[0], ip)\n\n\t\t\t\tif tc.ttl > 0 {\n\t\t\t\t\trequire.IsType(t, &cacheResolver{}, r)\n\t\t\t\t\tcr, ok := r.(*cacheResolver)\n\t\t\t\t\tassert.True(t, ok)\n\t\t\t\t\tassert.Len(t, cr.cache, 1)\n\t\t\t\t\tassert.Equal(t, tc.ttl, cr.ttl)\n\t\t\t\t\tfirstLookup := cr.cache[host].lastLookup\n\t\t\t\t\ttime.Sleep(cr.ttl + 100*time.Millisecond)\n\t\t\t\t\t_, err = r.LookupIP(host)\n\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\tassert.True(t, cr.cache[host].lastLookup.After(firstLookup))\n\t\t\t\t}\n\n\t\t\t\tif tc.sel == types.DNSroundRobin {\n\t\t\t\t\tips := make([]net.IP, 1, 4)\n\t\t\t\t\tips[0] = ip\n\t\t\t\t\tfor range 3 {\n\t\t\t\t\t\tip, err = r.LookupIP(host)\n\t\t\t\t\t\trequire.NoError(t, err)\n\t\t\t\t\t\tips = append(ips, ip)\n\t\t\t\t\t}\n\t\t\t\t\tassert.Equal(t, tc.expIP, ips)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "lib/netext/tls.go",
    "content": "// Package netext provides extensions to the standard net package\npackage netext\n\nimport (\n\t\"crypto/tls\"\n\n\t\"golang.org/x/crypto/ocsp\"\n\n\t\"go.k6.io/k6/lib\"\n)\n\n//nolint:revive // we want to keep these constants as they are\nconst (\n\tOCSP_STATUS_GOOD                   = \"good\"\n\tOCSP_STATUS_REVOKED                = \"revoked\"\n\tOCSP_STATUS_SERVER_FAILED          = \"server_failed\"\n\tOCSP_STATUS_UNKNOWN                = \"unknown\"\n\tOCSP_REASON_UNSPECIFIED            = \"unspecified\"\n\tOCSP_REASON_KEY_COMPROMISE         = \"key_compromise\"\n\tOCSP_REASON_CA_COMPROMISE          = \"ca_compromise\"\n\tOCSP_REASON_AFFILIATION_CHANGED    = \"affiliation_changed\"\n\tOCSP_REASON_SUPERSEDED             = \"superseded\"\n\tOCSP_REASON_CESSATION_OF_OPERATION = \"cessation_of_operation\"\n\tOCSP_REASON_CERTIFICATE_HOLD       = \"certificate_hold\"\n\tOCSP_REASON_REMOVE_FROM_CRL        = \"remove_from_crl\"\n\tOCSP_REASON_PRIVILEGE_WITHDRAWN    = \"privilege_withdrawn\"\n\tOCSP_REASON_AA_COMPROMISE          = \"aa_compromise\"\n\tTLS_1_0                            = \"tls1.0\"\n\tTLS_1_1                            = \"tls1.1\"\n\tTLS_1_2                            = \"tls1.2\"\n\tTLS_1_3                            = \"tls1.3\"\n)\n\n// TLSInfo keeps TLS details\ntype TLSInfo struct {\n\tVersion     string\n\tCipherSuite string\n}\n\n// OCSP keeps Online Certificate Status Protocol (OCSP) details\ntype OCSP struct {\n\tProducedAt       int64  `json:\"produced_at\"`\n\tThisUpdate       int64  `json:\"this_update\"`\n\tNextUpdate       int64  `json:\"next_update\"`\n\tRevokedAt        int64  `json:\"revoked_at\"`\n\tRevocationReason string `json:\"revocation_reason\"`\n\tStatus           string `json:\"status\"`\n}\n\n// ParseTLSConnState parses tls.ConnectionState and returns TLS and OCSP details\nfunc ParseTLSConnState(tlsState *tls.ConnectionState) (TLSInfo, OCSP) {\n\ttlsInfo := TLSInfo{}\n\tswitch tlsState.Version {\n\tcase tls.VersionTLS10:\n\t\ttlsInfo.Version = TLS_1_0\n\tcase tls.VersionTLS11:\n\t\ttlsInfo.Version = TLS_1_1\n\tcase tls.VersionTLS12:\n\t\ttlsInfo.Version = TLS_1_2\n\tcase tls.VersionTLS13:\n\t\ttlsInfo.Version = TLS_1_3\n\t}\n\n\ttlsInfo.CipherSuite = lib.SupportedTLSCipherSuitesToString[tlsState.CipherSuite]\n\tocspStapledRes := OCSP{Status: OCSP_STATUS_UNKNOWN}\n\n\tif ocspRes, err := ocsp.ParseResponse(tlsState.OCSPResponse, nil); err == nil {\n\t\tswitch ocspRes.Status {\n\t\tcase ocsp.Good:\n\t\t\tocspStapledRes.Status = OCSP_STATUS_GOOD\n\t\tcase ocsp.Revoked:\n\t\t\tocspStapledRes.Status = OCSP_STATUS_REVOKED\n\t\tcase ocsp.ServerFailed:\n\t\t\tocspStapledRes.Status = OCSP_STATUS_SERVER_FAILED\n\t\tcase ocsp.Unknown:\n\t\t\tocspStapledRes.Status = OCSP_STATUS_UNKNOWN\n\t\t}\n\t\tswitch ocspRes.RevocationReason {\n\t\tcase ocsp.Unspecified:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_UNSPECIFIED\n\t\tcase ocsp.KeyCompromise:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_KEY_COMPROMISE\n\t\tcase ocsp.CACompromise:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_CA_COMPROMISE\n\t\tcase ocsp.AffiliationChanged:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_AFFILIATION_CHANGED\n\t\tcase ocsp.Superseded:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_SUPERSEDED\n\t\tcase ocsp.CessationOfOperation:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_CESSATION_OF_OPERATION\n\t\tcase ocsp.CertificateHold:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_CERTIFICATE_HOLD\n\t\tcase ocsp.RemoveFromCRL:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_REMOVE_FROM_CRL\n\t\tcase ocsp.PrivilegeWithdrawn:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_PRIVILEGE_WITHDRAWN\n\t\tcase ocsp.AACompromise:\n\t\t\tocspStapledRes.RevocationReason = OCSP_REASON_AA_COMPROMISE\n\t\t}\n\t\tocspStapledRes.ProducedAt = ocspRes.ProducedAt.Unix()\n\t\tocspStapledRes.ThisUpdate = ocspRes.ThisUpdate.Unix()\n\t\tocspStapledRes.NextUpdate = ocspRes.NextUpdate.Unix()\n\t\tocspStapledRes.RevokedAt = ocspRes.RevokedAt.Unix()\n\t}\n\n\treturn tlsInfo, ocspStapledRes\n}\n"
  },
  {
    "path": "lib/old_archive_test.go",
    "content": "package lib\n\nimport (\n\t\"archive/tar\"\n\t\"bytes\"\n\t\"io/fs\"\n\t\"net/url\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\nfunc dumpMemMapFsToBuf(fileSystem fsext.Fs) (*bytes.Buffer, error) {\n\tb := bytes.NewBuffer(nil)\n\tw := tar.NewWriter(b)\n\terr := fsext.Walk(fileSystem, fsext.FilePathSeparator,\n\t\tfilepath.WalkFunc(func(filePath string, info fs.FileInfo, err error) error {\n\t\t\tif filePath == fsext.FilePathSeparator {\n\t\t\t\treturn nil // skip the root\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif info.IsDir() {\n\t\t\t\treturn w.WriteHeader(&tar.Header{\n\t\t\t\t\tName:     path.Clean(filepath.ToSlash(filePath)[1:]),\n\t\t\t\t\tMode:     0o555,\n\t\t\t\t\tTypeflag: tar.TypeDir,\n\t\t\t\t})\n\t\t\t}\n\t\t\tvar data []byte\n\t\t\tdata, err = fsext.ReadFile(fileSystem, filePath)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\terr = w.WriteHeader(&tar.Header{\n\t\t\t\tName:     path.Clean(filepath.ToSlash(filePath)[1:]),\n\t\t\t\tMode:     0o644,\n\t\t\t\tSize:     int64(len(data)),\n\t\t\t\tTypeflag: tar.TypeReg,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t_, err = w.Write(data)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\treturn nil\n\t\t}))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn b, w.Close()\n}\n\nfunc TestOldArchive(t *testing.T) {\n\tt.Parallel()\n\ttestCases := map[string]string{\n\t\t// map of filename to data for each main file tested\n\t\t\"C:/something/path2\": `windows script`,\n\t\t\"/absolulte/path2\":   `unix script`,\n\t}\n\tfor filename, data := range testCases {\n\t\tt.Run(filename, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tmetadata := `{\"filename\": \"` + filename + `\", \"options\": {}}`\n\t\t\tfs := testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t// files\n\t\t\t\t\"/files/example.com/path/to.js\": []byte(`example.com file`),\n\t\t\t\t\"/files/_/C/something/path\":     []byte(`windows file`),\n\t\t\t\t\"/files/_/absolulte/path\":       []byte(`unix file`),\n\n\t\t\t\t// scripts\n\t\t\t\t\"/scripts/example.com/path/too.js\": []byte(`example.com script`),\n\t\t\t\t\"/scripts/_/C/something/path2\":     []byte(`windows script`),\n\t\t\t\t\"/scripts/_/absolulte/path2\":       []byte(`unix script`),\n\t\t\t\t\"/data\":                            []byte(data),\n\t\t\t\t\"/metadata.json\":                   []byte(metadata),\n\t\t\t})\n\n\t\t\tbuf, err := dumpMemMapFsToBuf(fs)\n\t\t\trequire.NoError(t, err)\n\n\t\t\texpectedFilesystems := map[string]fsext.Fs{\n\t\t\t\t\"file\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\"/C:/something/path\":  []byte(`windows file`),\n\t\t\t\t\t\"/absolulte/path\":     []byte(`unix file`),\n\t\t\t\t\t\"/C:/something/path2\": []byte(`windows script`),\n\t\t\t\t\t\"/absolulte/path2\":    []byte(`unix script`),\n\t\t\t\t}),\n\t\t\t\t\"https\": testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\t\t\"/example.com/path/to.js\":  []byte(`example.com file`),\n\t\t\t\t\t\"/example.com/path/too.js\": []byte(`example.com script`),\n\t\t\t\t}),\n\t\t\t}\n\n\t\t\tarc, err := ReadArchive(buf)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tdiffMapFilesystems(t, expectedFilesystems, arc.Filesystems)\n\t\t})\n\t}\n}\n\nfunc TestUnknownPrefix(t *testing.T) {\n\tt.Parallel()\n\tfs := testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\"/strange/something\": []byte(`github file`),\n\t})\n\tbuf, err := dumpMemMapFsToBuf(fs)\n\trequire.NoError(t, err)\n\n\t_, err = ReadArchive(buf)\n\trequire.Error(t, err)\n\trequire.EqualError(t, err,\n\t\t\"unknown file prefix `strange` for file `strange/something`\")\n}\n\nfunc TestFilenamePwdResolve(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tFilename, Pwd, version              string\n\t\texpectedFilenameURL, expectedPwdURL *url.URL\n\t\texpectedError                       string\n\t}{\n\t\t{\n\t\t\tFilename:            \"/home/nobody/something.js\",\n\t\t\tPwd:                 \"/home/nobody\",\n\t\t\texpectedFilenameURL: &url.URL{Scheme: \"file\", Path: \"/home/nobody/something.js\"},\n\t\t\texpectedPwdURL:      &url.URL{Scheme: \"file\", Path: \"/home/nobody\"},\n\t\t},\n\t\t{\n\t\t\tFilename:      \"github.com/k6io/k6/samples/http2.js\",\n\t\t\tPwd:           \"github.com/k6io/k6/samples\",\n\t\t\texpectedError: \"are no longer supported\",\n\t\t},\n\t\t{\n\t\t\tFilename:      \"cdnjs.com/libraries/Faker\",\n\t\t\tPwd:           \"/home/nobody\",\n\t\t\texpectedError: \"are no longer supported\",\n\t\t},\n\t\t{\n\t\t\tFilename:            \"https://example.com/something/dot.js\",\n\t\t\tPwd:                 \"https://example.com/something\",\n\t\t\texpectedFilenameURL: &url.URL{Host: \"example.com\", Scheme: \"https\", Path: \"/something/dot.js\"},\n\t\t\texpectedPwdURL:      &url.URL{Host: \"example.com\", Scheme: \"https\", Path: \"/something\"},\n\t\t\tversion:             \"0.25.0\",\n\t\t},\n\t\t{\n\t\t\tFilename:      \"ftps://example.com/something/dot.js\",\n\t\t\tPwd:           \"https://example.com/something\",\n\t\t\texpectedError: \"only supported schemes for imports are file and https\",\n\t\t\tversion:       \"0.25.0\",\n\t\t},\n\t\t{\n\t\t\tFilename:      \"https://example.com/something/dot.js\",\n\t\t\tPwd:           \"ftps://example.com/something\",\n\t\t\texpectedError: \"only supported schemes for imports are file and https\",\n\t\t\tversion:       \"0.25.0\",\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tmetadata := `{\n\t\t\"filename\": \"` + test.Filename + `\",\n\t\t\"pwd\": \"` + test.Pwd + `\",\n\t\t\"k6version\": \"` + test.version + `\",\n\t\t\"options\": {}\n\t}`\n\n\t\tbuf, err := dumpMemMapFsToBuf(testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\"/metadata.json\": []byte(metadata),\n\t\t}))\n\t\trequire.NoError(t, err)\n\n\t\tarc, err := ReadArchive(buf)\n\t\tif test.expectedError != \"\" {\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), test.expectedError)\n\t\t} else {\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.expectedFilenameURL, arc.FilenameURL)\n\t\t\trequire.Equal(t, test.expectedPwdURL, arc.PwdURL)\n\t\t}\n\t}\n}\n\nfunc TestDerivedExecutionDiscarding(t *testing.T) {\n\tt.Parallel()\n\tvar emptyConfigMap ScenarioConfigs\n\ttests := []struct {\n\t\tmetadata     string\n\t\texpScenarios any\n\t\texpError     string\n\t}{\n\t\t// Tests to make sure that \"execution\" in the options, the old name for\n\t\t// \"scenarios\" before #1007 was merged, doesn't mess up the options...\n\t\t{\n\t\t\tmetadata: `{\n\t\t\t\t\"filename\": \"/test.js\", \"pwd\": \"/\",\n\t\t\t\t\"options\": { \"execution\": { \"something\": \"invalid\" } }\n\t\t\t}`,\n\t\t\texpScenarios: emptyConfigMap,\n\t\t},\n\t\t{\n\t\t\tmetadata: `{\n\t\t\t\t\"filename\": \"/test.js\", \"pwd\": \"/\",\n\t\t\t\t\"k6version\": \"0.24.0\",\n\t\t\t\t\"options\": { \"execution\": { \"something\": \"invalid\" } }\n\t\t\t}`,\n\t\t\texpScenarios: emptyConfigMap,\n\t\t},\n\t\t{\n\t\t\tmetadata: `blah`,\n\t\t\texpError: \"invalid character\",\n\t\t},\n\t\t{\n\t\t\tmetadata: `{\n\t\t\t\t\"filename\": \"/test.js\", \"pwd\": \"/\",\n\t\t\t\t\"k6version\": \"0.24.0\",\n\t\t\t\t\"options\": \"something invalid\"\n\t\t\t}`,\n\t\t\texpError: \"cannot unmarshal string into Go struct field\",\n\t\t},\n\t\t{\n\t\t\tmetadata: `{\n\t\t\t\t\"filename\": \"/test.js\", \"pwd\": \"/\",\n\t\t\t\t\"k6version\": \"0.25.0\",\n\t\t\t\t\"options\": { \"scenarios\": { \"something\": \"invalid\" } }\n\t\t\t}`,\n\t\t\texpError: \"cannot unmarshal string\",\n\t\t},\n\t\t// TODO: test an actual scenarios unmarshalling, which is currently\n\t\t// impossible due to import cycles...\n\t}\n\n\tfor _, test := range tests {\n\t\tbuf, err := dumpMemMapFsToBuf(testutils.MakeMemMapFs(t, map[string][]byte{\n\t\t\t\"/metadata.json\": []byte(test.metadata),\n\t\t}))\n\t\trequire.NoError(t, err)\n\n\t\tarc, err := ReadArchive(buf)\n\t\tif test.expError != \"\" {\n\t\t\trequire.Errorf(t, err, \"expected error '%s' but got nil\", test.expError)\n\t\t\trequire.Contains(t, err.Error(), test.expError)\n\t\t} else {\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Equal(t, test.expScenarios, arc.Options.Scenarios)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/options.go",
    "content": "package lib\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"reflect\"\n\t\"slices\"\n\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// DefaultScenarioName is used as the default key/ID of the scenario config entries\n// that were created due to the use of the shortcut execution control options (i.e. duration+vus,\n// iterations+vus, or stages)\nconst DefaultScenarioName = \"default\"\n\n// DefaultSummaryTrendStats are the default trend columns shown in the test summary output\n//\n//nolint:gochecknoglobals\nvar DefaultSummaryTrendStats = []string{\"avg\", \"min\", \"med\", \"max\", \"p(90)\", \"p(95)\"}\n\n// TLSVersion describes a TLS version. Serialised to/from JSON as a string, eg. \"tls1.2\".\ntype TLSVersion int\n\n// MarshalJSON implements the json.Marshaler interface\nfunc (v TLSVersion) MarshalJSON() ([]byte, error) {\n\treturn []byte(`\"` + SupportedTLSVersionsToString[v] + `\"`), nil\n}\n\n// UnmarshalJSON implements the json.Unmarshaler interface\nfunc (v *TLSVersion) UnmarshalJSON(data []byte) error {\n\tvar str string\n\tif err := StrictJSONUnmarshal(data, &str); err != nil {\n\t\treturn err\n\t}\n\tif str == \"\" {\n\t\t*v = 0\n\t\treturn nil\n\t}\n\tver, ok := SupportedTLSVersions[str]\n\tif !ok {\n\t\treturn fmt.Errorf(\"unknown TLS version '%s'\", str)\n\t}\n\t*v = ver\n\treturn nil\n}\n\n// Fields for TLSVersions. Unmarshalling hack.\ntype tlsVersionsFields struct {\n\tMin TLSVersion `json:\"min\" ignored:\"true\"` // Minimum allowed version, 0 = any.\n\tMax TLSVersion `json:\"max\" ignored:\"true\"` // Maximum allowed version, 0 = any.\n}\n\n// TLSVersions describes a set (min/max) of TLS versions.\ntype TLSVersions tlsVersionsFields\n\n// UnmarshalJSON implements the json.Unmarshaler interface\nfunc (v *TLSVersions) UnmarshalJSON(data []byte) error {\n\tvar fields tlsVersionsFields\n\tif err := StrictJSONUnmarshal(data, &fields); err != nil {\n\t\tvar ver TLSVersion\n\t\tif err2 := StrictJSONUnmarshal(data, &ver); err2 != nil {\n\t\t\treturn err\n\t\t}\n\t\tfields.Min = ver\n\t\tfields.Max = ver\n\t}\n\t*v = TLSVersions(fields)\n\treturn nil\n}\n\n// TLSCipherSuites represents a list of TLS cipher suites.\n// Marshals and unmarshals from a list of names, eg. \"TLS_ECDHE_RSA_WITH_RC4_128_SHA\".\ntype TLSCipherSuites []uint16\n\n// MarshalJSON will return the JSON representation according to supported TLS cipher suites\nfunc (s *TLSCipherSuites) MarshalJSON() ([]byte, error) {\n\tvar suiteNames []string\n\tfor _, id := range *s {\n\t\tif suiteName, ok := SupportedTLSCipherSuitesToString[id]; ok {\n\t\t\tsuiteNames = append(suiteNames, suiteName)\n\t\t} else {\n\t\t\treturn nil, fmt.Errorf(\"unknown cipher suite id '%d'\", id)\n\t\t}\n\t}\n\n\treturn json.Marshal(suiteNames)\n}\n\n// UnmarshalJSON implements the json.Unmarshaler interface\nfunc (s *TLSCipherSuites) UnmarshalJSON(data []byte) error {\n\tvar suiteNames []string\n\tif err := StrictJSONUnmarshal(data, &suiteNames); err != nil {\n\t\treturn err\n\t}\n\n\tvar suiteIDs []uint16\n\tfor _, name := range suiteNames {\n\t\tif suiteID, ok := SupportedTLSCipherSuites[name]; ok {\n\t\t\tsuiteIDs = append(suiteIDs, suiteID)\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"unknown cipher suite '%s'\", name)\n\t\t}\n\t}\n\n\t*s = suiteIDs\n\n\treturn nil\n}\n\n// TLSAuthFields for TLSAuth. Unmarshalling hack.\ntype TLSAuthFields struct {\n\t// Certificate and key as a PEM-encoded string, including \"-----BEGIN CERTIFICATE-----\".\n\tCert     string      `json:\"cert\"`\n\tKey      string      `json:\"key\"`\n\tPassword null.String `json:\"password\"`\n\n\t// Domains to present the certificate to. May contain wildcards, eg. \"*.example.com\".\n\tDomains []string `json:\"domains\"`\n}\n\n// TLSAuth defines a TLS client certificate to present to certain hosts.\ntype TLSAuth struct {\n\tTLSAuthFields\n\tcertificate *tls.Certificate\n}\n\n// UnmarshalJSON implements the json.Unmarshaler interface\nfunc (c *TLSAuth) UnmarshalJSON(data []byte) error {\n\tif err := StrictJSONUnmarshal(data, &c.TLSAuthFields); err != nil {\n\t\treturn err\n\t}\n\tif _, err := c.Certificate(); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\n// Certificate returns a certificate based on the TLSAuth\n// not thread safe\nfunc (c *TLSAuth) Certificate() (*tls.Certificate, error) {\n\tkey := []byte(c.Key)\n\tvar err error\n\tif c.Password.Valid {\n\t\tkey, err = decryptPrivateKey(c.Key, c.Password.String)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif c.certificate == nil {\n\t\tcert, err := tls.X509KeyPair([]byte(c.Cert), key)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tc.certificate = &cert\n\t}\n\treturn c.certificate, nil\n}\n\nfunc decryptPrivateKey(privKey, password string) ([]byte, error) {\n\tkey := []byte(privKey)\n\n\tblock, _ := pem.Decode(key)\n\tif block == nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode PEM key\")\n\t}\n\n\tblockType := block.Type\n\tif blockType == \"ENCRYPTED PRIVATE KEY\" {\n\t\treturn nil, fmt.Errorf(\"encrypted pkcs8 formatted key is not supported\")\n\t}\n\t/*\n\t   Even though `DecryptPEMBlock` has been deprecated since 1.16.x it is still\n\t   being used here because it is deprecated due to it not supporting *good* crypography\n\t   ultimately though we want to support something so we will be using it for now.\n\t*/\n\tdecryptedKey, err := x509.DecryptPEMBlock(block, []byte(password)) //nolint:staticcheck\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkey = pem.EncodeToMemory(&pem.Block{\n\t\tType:  blockType,\n\t\tBytes: decryptedKey,\n\t})\n\treturn key, nil\n}\n\n// IPNet is a wrapper around net.IPNet for JSON unmarshalling\ntype IPNet struct {\n\tnet.IPNet\n}\n\n// UnmarshalText populates the IPNet from the given CIDR\nfunc (ipnet *IPNet) UnmarshalText(b []byte) error {\n\tnewIPNet, err := ParseCIDR(string(b))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse CIDR '%s': %w\", string(b), err)\n\t}\n\n\t*ipnet = *newIPNet\n\treturn nil\n}\n\n// MarshalText encodes the IPNet representation using CIDR notation.\nfunc (ipnet *IPNet) MarshalText() ([]byte, error) {\n\treturn []byte(ipnet.String()), nil\n}\n\n// ParseCIDR creates an IPNet out of a CIDR string\nfunc ParseCIDR(s string) (*IPNet, error) {\n\t_, ipnet, err := net.ParseCIDR(s)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tparsedIPNet := IPNet{IPNet: *ipnet}\n\n\treturn &parsedIPNet, nil\n}\n\n// Options represent configure options for k6.\ntype Options struct {\n\t// Should the test start in a paused state?\n\tPaused null.Bool `json:\"paused\" envconfig:\"K6_PAUSED\"`\n\n\t// Initial values for VUs, max VUs, duration cap, iteration cap, and stages.\n\t// See the Runner or Executor interfaces for more information.\n\tVUs        null.Int           `json:\"vus\" envconfig:\"K6_VUS\"`\n\tDuration   types.NullDuration `json:\"duration\" envconfig:\"K6_DURATION\"`\n\tIterations null.Int           `json:\"iterations\" envconfig:\"K6_ITERATIONS\"`\n\tStages     []Stage            `json:\"stages\" envconfig:\"K6_STAGES\"`\n\n\t// TODO: remove the `ignored:\"true\"` from the field tags, it's there so that\n\t// the envconfig library will ignore those fields.\n\t//\n\t// We should support specifying execution segments via environment\n\t// variables, but we currently can't, because envconfig has this nasty bug\n\t// (among others): https://github.com/kelseyhightower/envconfig/issues/113\n\tScenarios                ScenarioConfigs           `json:\"scenarios\" ignored:\"true\"`\n\tExecutionSegment         *ExecutionSegment         `json:\"executionSegment\" ignored:\"true\"`\n\tExecutionSegmentSequence *ExecutionSegmentSequence `json:\"executionSegmentSequence\" ignored:\"true\"`\n\n\t// Timeouts for the setup() and teardown() functions\n\tNoSetup         null.Bool          `json:\"noSetup\" envconfig:\"K6_NO_SETUP\"`\n\tSetupTimeout    types.NullDuration `json:\"setupTimeout\" envconfig:\"K6_SETUP_TIMEOUT\"`\n\tNoTeardown      null.Bool          `json:\"noTeardown\" envconfig:\"K6_NO_TEARDOWN\"`\n\tTeardownTimeout types.NullDuration `json:\"teardownTimeout\" envconfig:\"K6_TEARDOWN_TIMEOUT\"`\n\n\t// Limit HTTP requests per second.\n\tRPS null.Int `json:\"rps\" envconfig:\"K6_RPS\"`\n\n\t// DNS handling configuration.\n\tDNS types.DNSConfig `json:\"dns\" envconfig:\"K6_DNS\"`\n\n\t// How many HTTP redirects do we follow?\n\tMaxRedirects null.Int `json:\"maxRedirects\" envconfig:\"K6_MAX_REDIRECTS\"`\n\n\t// Default User Agent string for HTTP requests.\n\tUserAgent null.String `json:\"userAgent\" envconfig:\"K6_USER_AGENT\"`\n\n\t// How many batch requests are allowed in parallel, in total and per host?\n\tBatch        null.Int `json:\"batch\" envconfig:\"K6_BATCH\"`\n\tBatchPerHost null.Int `json:\"batchPerHost\" envconfig:\"K6_BATCH_PER_HOST\"`\n\n\t// Should all HTTP requests and responses be logged (excluding body)?\n\tHTTPDebug null.String `json:\"httpDebug\" envconfig:\"K6_HTTP_DEBUG\"`\n\n\t// Accept invalid or untrusted TLS certificates.\n\tInsecureSkipTLSVerify null.Bool `json:\"insecureSkipTLSVerify\" envconfig:\"K6_INSECURE_SKIP_TLS_VERIFY\"`\n\n\t// Specify TLS versions and cipher suites, and present client certificates.\n\tTLSCipherSuites *TLSCipherSuites `json:\"tlsCipherSuites\" envconfig:\"K6_TLS_CIPHER_SUITES\"`\n\tTLSVersion      *TLSVersions     `json:\"tlsVersion\" ignored:\"true\"`\n\tTLSAuth         []*TLSAuth       `json:\"tlsAuth\" envconfig:\"K6_TLSAUTH\"`\n\n\t// Throw warnings (eg. failed HTTP requests) as errors instead of simply logging them.\n\tThrow null.Bool `json:\"throw\" envconfig:\"K6_THROW\"`\n\n\t// Define thresholds; these take the form of 'metric=[\"snippet1\", \"snippet2\"]'.\n\t// To create a threshold on a derived metric based on tag queries (\"submetrics\"), create a\n\t// metric on a nonexistent metric named 'real_metric{tagA:valueA,tagB:valueB}'.\n\tThresholds map[string]metrics.Thresholds `json:\"thresholds\" envconfig:\"K6_THRESHOLDS\"`\n\n\t// Blacklist IP ranges that tests may not contact. Mainly useful in hosted setups.\n\tBlacklistIPs []*IPNet `json:\"blacklistIPs\" envconfig:\"K6_BLACKLIST_IPS\"`\n\n\t// Block hostname patterns that tests may not contact.\n\tBlockedHostnames types.NullHostnameTrie `json:\"blockHostnames\" envconfig:\"K6_BLOCK_HOSTNAMES\"`\n\n\t// Hosts overrides dns entries for given hosts\n\tHosts types.NullHosts `json:\"hosts\" envconfig:\"K6_HOSTS\"`\n\n\t// Disable keep-alive connections\n\tNoConnectionReuse null.Bool `json:\"noConnectionReuse\" envconfig:\"K6_NO_CONNECTION_REUSE\"`\n\n\t// Do not reuse connections between VU iterations. This gives more realistic results (depending\n\t// on what you're looking for), but you need to raise various kernel limits or you'll get\n\t// errors about running out of file handles or sockets, or being unable to bind addresses.\n\tNoVUConnectionReuse null.Bool `json:\"noVUConnectionReuse\" envconfig:\"K6_NO_VU_CONNECTION_REUSE\"`\n\n\t// MinIterationDuration can be used to force VUs to pause between iterations if a specific\n\t// iteration is shorter than the specified value.\n\tMinIterationDuration types.NullDuration `json:\"minIterationDuration\" envconfig:\"K6_MIN_ITERATION_DURATION\"`\n\n\t// Cloud is the configuration for the k6 Cloud, formerly known as ext.loadimpact.\n\tCloud json.RawMessage `json:\"cloud,omitempty\"`\n\n\t// These values are for third party collectors' benefit.\n\t// Can't be set through env vars.\n\tExternal map[string]json.RawMessage `json:\"ext\" ignored:\"true\"`\n\n\t// Summary trend stats for trend metrics (response times) in CLI output\n\tSummaryTrendStats []string `json:\"summaryTrendStats\" envconfig:\"K6_SUMMARY_TREND_STATS\"`\n\n\t// Summary time unit for summary metrics (response times) in CLI output\n\tSummaryTimeUnit null.String `json:\"summaryTimeUnit\" envconfig:\"K6_SUMMARY_TIME_UNIT\"`\n\n\t// Which system tags to include with metrics (\"method\", \"vu\" etc.)\n\t// Use pointer for identifying whether user provide any tag or not.\n\tSystemTags *metrics.SystemTagSet `json:\"systemTags\" envconfig:\"K6_SYSTEM_TAGS\"`\n\n\t// Tags are key-value pairs to be applied to all samples for the run.\n\tRunTags map[string]string `json:\"tags\" envconfig:\"K6_TAGS\"`\n\n\t// Buffer size of the channel for metric samples; 0 means unbuffered\n\tMetricSamplesBufferSize null.Int `json:\"metricSamplesBufferSize\" envconfig:\"K6_METRIC_SAMPLES_BUFFER_SIZE\"`\n\n\t// Do not reset cookies after a VU iteration\n\tNoCookiesReset null.Bool `json:\"noCookiesReset\" envconfig:\"K6_NO_COOKIES_RESET\"`\n\n\t// Discard Http Responses Body\n\tDiscardResponseBodies null.Bool `json:\"discardResponseBodies\" envconfig:\"K6_DISCARD_RESPONSE_BODIES\"`\n\n\t// Redirect console logging to a file\n\tConsoleOutput null.String `json:\"-\" envconfig:\"K6_CONSOLE_OUTPUT\"`\n\n\t// Specify client IP ranges and/or CIDR from which VUs will make requests\n\tLocalIPs types.NullIPPool `json:\"-\" envconfig:\"K6_LOCAL_IPS\"`\n}\n\n// Apply returns the result of overwriting any fields with any that are set on the argument.\n//\n// Example:\n//\n//\ta := Options{VUs: null.IntFrom(10)}\n//\tb := Options{VUs: null.IntFrom(5)}\n//\ta.Apply(b) // Options{VUs: null.IntFrom(5)}\n//\n//nolint:funlen,gocognit,cyclop\nfunc (o Options) Apply(opts Options) Options {\n\tif opts.Paused.Valid {\n\t\to.Paused = opts.Paused\n\t}\n\tif opts.VUs.Valid {\n\t\to.VUs = opts.VUs\n\t}\n\n\t// Specifying duration, iterations, stages, or execution in a \"higher\" config tier\n\t// will overwrite all of the previous execution settings (if any) from any\n\t// \"lower\" config tiers\n\t// Still, if more than one of those options is simultaneously specified in the same\n\t// config tier, they will be preserved, so the validation after we've consolidated\n\t// all of the options can return an error.\n\tif opts.Duration.Valid || opts.Iterations.Valid || opts.Stages != nil || opts.Scenarios != nil {\n\t\t// TODO: emit a warning or a notice log message if overwrite lower tier config options?\n\t\to.Duration = types.NewNullDuration(0, false)\n\t\to.Iterations = null.NewInt(0, false)\n\t\to.Stages = nil\n\t\to.Scenarios = nil\n\t}\n\n\tif opts.Duration.Valid {\n\t\to.Duration = opts.Duration\n\t}\n\tif opts.Iterations.Valid {\n\t\to.Iterations = opts.Iterations\n\t}\n\tif opts.Stages != nil {\n\t\to.Stages = []Stage{}\n\t\tfor _, s := range opts.Stages {\n\t\t\tif s.Duration.Valid {\n\t\t\t\to.Stages = append(o.Stages, s)\n\t\t\t}\n\t\t}\n\t}\n\t// o.Execution can also be populated by the duration/iterations/stages config shortcuts, but\n\t// that happens after the configuration from the different sources is consolidated. It can't\n\t// happen here, because something like `K6_ITERATIONS=10 k6 run --vus 5 script.js` wont't\n\t// work correctly at this level.\n\tif opts.Scenarios != nil {\n\t\to.Scenarios = opts.Scenarios\n\t}\n\tif opts.ExecutionSegment != nil {\n\t\to.ExecutionSegment = opts.ExecutionSegment\n\t}\n\n\tif opts.ExecutionSegmentSequence != nil {\n\t\to.ExecutionSegmentSequence = opts.ExecutionSegmentSequence\n\t}\n\tif opts.NoSetup.Valid {\n\t\to.NoSetup = opts.NoSetup\n\t}\n\tif opts.SetupTimeout.Valid {\n\t\to.SetupTimeout = opts.SetupTimeout\n\t}\n\tif opts.NoTeardown.Valid {\n\t\to.NoTeardown = opts.NoTeardown\n\t}\n\tif opts.TeardownTimeout.Valid {\n\t\to.TeardownTimeout = opts.TeardownTimeout\n\t}\n\tif opts.RPS.Valid {\n\t\to.RPS = opts.RPS\n\t}\n\tif opts.MaxRedirects.Valid {\n\t\to.MaxRedirects = opts.MaxRedirects\n\t}\n\tif opts.UserAgent.Valid {\n\t\to.UserAgent = opts.UserAgent\n\t}\n\tif opts.Batch.Valid {\n\t\to.Batch = opts.Batch\n\t}\n\tif opts.BatchPerHost.Valid {\n\t\to.BatchPerHost = opts.BatchPerHost\n\t}\n\tif opts.HTTPDebug.Valid {\n\t\to.HTTPDebug = opts.HTTPDebug\n\t}\n\tif opts.InsecureSkipTLSVerify.Valid {\n\t\to.InsecureSkipTLSVerify = opts.InsecureSkipTLSVerify\n\t}\n\tif opts.TLSCipherSuites != nil {\n\t\to.TLSCipherSuites = opts.TLSCipherSuites\n\t}\n\tif opts.TLSVersion != nil {\n\t\to.TLSVersion = opts.TLSVersion\n\t}\n\tif opts.TLSAuth != nil {\n\t\to.TLSAuth = opts.TLSAuth\n\t}\n\tif opts.Throw.Valid {\n\t\to.Throw = opts.Throw\n\t}\n\tif opts.Thresholds != nil {\n\t\to.Thresholds = opts.Thresholds\n\t}\n\tif opts.BlacklistIPs != nil {\n\t\to.BlacklistIPs = opts.BlacklistIPs\n\t}\n\tif opts.BlockedHostnames.Valid {\n\t\to.BlockedHostnames = opts.BlockedHostnames\n\t}\n\tif opts.Hosts.Valid {\n\t\to.Hosts = opts.Hosts\n\t}\n\tif opts.NoConnectionReuse.Valid {\n\t\to.NoConnectionReuse = opts.NoConnectionReuse\n\t}\n\tif opts.NoVUConnectionReuse.Valid {\n\t\to.NoVUConnectionReuse = opts.NoVUConnectionReuse\n\t}\n\tif opts.MinIterationDuration.Valid {\n\t\to.MinIterationDuration = opts.MinIterationDuration\n\t}\n\tif opts.NoCookiesReset.Valid {\n\t\to.NoCookiesReset = opts.NoCookiesReset\n\t}\n\tif opts.Cloud != nil {\n\t\to.Cloud = opts.Cloud\n\t}\n\tif opts.External != nil {\n\t\to.External = opts.External\n\t}\n\tif opts.SummaryTrendStats != nil {\n\t\to.SummaryTrendStats = opts.SummaryTrendStats\n\t}\n\tif opts.SummaryTimeUnit.Valid {\n\t\to.SummaryTimeUnit = opts.SummaryTimeUnit\n\t}\n\tif opts.SystemTags != nil {\n\t\to.SystemTags = opts.SystemTags\n\t}\n\tif len(opts.RunTags) > 0 {\n\t\to.RunTags = opts.RunTags\n\t}\n\tif opts.MetricSamplesBufferSize.Valid {\n\t\to.MetricSamplesBufferSize = opts.MetricSamplesBufferSize\n\t}\n\tif opts.DiscardResponseBodies.Valid {\n\t\to.DiscardResponseBodies = opts.DiscardResponseBodies\n\t}\n\tif opts.ConsoleOutput.Valid {\n\t\to.ConsoleOutput = opts.ConsoleOutput\n\t}\n\tif opts.LocalIPs.Valid {\n\t\to.LocalIPs = opts.LocalIPs\n\t}\n\tif opts.DNS.TTL.Valid {\n\t\to.DNS.TTL = opts.DNS.TTL\n\t}\n\tif opts.DNS.Select.Valid {\n\t\to.DNS.Select = opts.DNS.Select\n\t}\n\tif opts.DNS.Policy.Valid {\n\t\to.DNS.Policy = opts.DNS.Policy\n\t}\n\n\treturn o\n}\n\n// Validate checks if all of the specified options make sense\nfunc (o Options) Validate() []error {\n\t// TODO: validate all of the other options... that we should have already been validating...\n\t// TODO: maybe integrate an external validation lib: https://github.com/avelino/awesome-go#validation\n\tvar validationErrors []error\n\tif o.ExecutionSegmentSequence != nil {\n\t\tvar segmentFound bool\n\t\tif slices.ContainsFunc(*o.ExecutionSegmentSequence, o.ExecutionSegment.Equal) {\n\t\t\tsegmentFound = true\n\t\t}\n\t\tif !segmentFound {\n\t\t\tvalidationErrors = append(validationErrors,\n\t\t\t\tfmt.Errorf(\"provided segment %s can't be found in sequence %s\",\n\t\t\t\t\to.ExecutionSegment, o.ExecutionSegmentSequence))\n\t\t}\n\t}\n\tvalidationErrors = append(validationErrors, o.Scenarios.Validate()...)\n\n\t// Duration\n\tif o.SetupTimeout.Valid && o.SetupTimeout.Duration <= 0 {\n\t\tvalidationErrors = append(validationErrors, errors.New(\"setupTimeout must be positive\"))\n\t}\n\treturn validationErrors\n}\n\n// ForEachSpecified enumerates all struct fields and calls the supplied function with each\n// element that is valid. It panics for any unfamiliar or unexpected fields, so make sure\n// new fields in Options are accounted for.\nfunc (o Options) ForEachSpecified(structTag string, callback func(key string, value any)) {\n\tstructType := reflect.TypeFor[Options]()\n\tstructVal := reflect.ValueOf(o)\n\tfor i := 0; i < structType.NumField(); i++ {\n\t\tfieldType := structType.Field(i)\n\t\tfieldVal := structVal.Field(i)\n\t\tvalue := fieldVal.Interface()\n\n\t\tvar shouldCall bool\n\t\tswitch fieldType.Type.Kind() {\n\t\tcase reflect.Struct:\n\t\t\t// Unpack any guregu/null values\n\t\t\tshouldCall = fieldVal.FieldByName(\"Valid\").Bool()\n\t\t\tvalOrZero := fieldVal.MethodByName(\"ValueOrZero\")\n\t\t\tif shouldCall && valOrZero.IsValid() {\n\t\t\t\tvalue = valOrZero.Call([]reflect.Value{})[0].Interface()\n\t\t\t\tif v, ok := value.(types.Duration); ok {\n\t\t\t\t\tvalue = v.String()\n\t\t\t\t}\n\t\t\t}\n\t\tcase reflect.Slice:\n\t\t\tshouldCall = fieldVal.Len() > 0\n\t\tcase reflect.Map:\n\t\t\tshouldCall = fieldVal.Len() > 0\n\t\tcase reflect.Ptr:\n\t\t\tshouldCall = !fieldVal.IsNil()\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"Unknown Options field %#v\", fieldType))\n\t\t}\n\n\t\tif shouldCall {\n\t\t\tkey, ok := fieldType.Tag.Lookup(structTag)\n\t\t\tif !ok {\n\t\t\t\tkey = fieldType.Name\n\t\t\t}\n\n\t\t\tcallback(key, value)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/options_test.go",
    "content": "package lib\n\nimport (\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"net\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/mstoykov/envconfig\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestOptions(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"Paused\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{Paused: null.BoolFrom(true)})\n\t\tassert.True(t, opts.Paused.Valid)\n\t\tassert.True(t, opts.Paused.Bool)\n\t})\n\tt.Run(\"VUs\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{VUs: null.IntFrom(12345)})\n\t\tassert.True(t, opts.VUs.Valid)\n\t\tassert.Equal(t, int64(12345), opts.VUs.Int64)\n\t})\n\tt.Run(\"Duration\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{Duration: types.NullDurationFrom(2 * time.Minute)})\n\t\tassert.True(t, opts.Duration.Valid)\n\t\tassert.Equal(t, \"2m0s\", opts.Duration.String())\n\t})\n\tt.Run(\"Iterations\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{Iterations: null.IntFrom(1234)})\n\t\tassert.True(t, opts.Iterations.Valid)\n\t\tassert.Equal(t, int64(1234), opts.Iterations.Int64)\n\t})\n\tt.Run(\"Stages\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{Stages: []Stage{\n\t\t\t{Duration: types.NullDurationFrom(1 * time.Second), Target: null.IntFrom(10)},\n\t\t\t{Duration: types.NullDurationFrom(2 * time.Second), Target: null.IntFrom(20)},\n\t\t}})\n\t\tassert.NotNil(t, opts.Stages)\n\t\tassert.Len(t, opts.Stages, 2)\n\t\tassert.Equal(t, 1*time.Second, opts.Stages[0].Duration.TimeDuration())\n\t\tassert.Equal(t, int64(10), opts.Stages[0].Target.Int64)\n\t\tassert.Equal(t, 2*time.Second, opts.Stages[1].Duration.TimeDuration())\n\t\tassert.Equal(t, int64(20), opts.Stages[1].Target.Int64)\n\n\t\temptyStages := []Stage{}\n\t\tassert.Equal(t, emptyStages, Options{}.Apply(Options{Stages: []Stage{{}}}).Stages)\n\t\tassert.Equal(t, emptyStages, Options{}.Apply(Options{Stages: []Stage{}}).Stages)\n\t\tassert.Equal(t, emptyStages, opts.Apply(Options{Stages: []Stage{}}).Stages)\n\t\tassert.Equal(t, emptyStages, opts.Apply(Options{Stages: []Stage{{}}}).Stages)\n\n\t\tassert.Equal(t, opts.Stages, opts.Apply(opts).Stages)\n\n\t\toneStage := []Stage{{Duration: types.NullDurationFrom(5 * time.Second), Target: null.IntFrom(50)}}\n\t\tassert.Equal(t, oneStage, opts.Apply(Options{Stages: oneStage}).Stages)\n\t\tassert.Equal(t, oneStage, Options{}.Apply(opts).Apply(Options{Stages: oneStage}).Apply(Options{Stages: oneStage}).Stages)\n\t})\n\t// Execution overwriting is tested by the config consolidation test in cmd\n\tt.Run(\"RPS\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{RPS: null.IntFrom(12345)})\n\t\tassert.True(t, opts.RPS.Valid)\n\t\tassert.Equal(t, int64(12345), opts.RPS.Int64)\n\t})\n\tt.Run(\"MaxRedirects\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{MaxRedirects: null.IntFrom(12345)})\n\t\tassert.True(t, opts.MaxRedirects.Valid)\n\t\tassert.Equal(t, int64(12345), opts.MaxRedirects.Int64)\n\t})\n\tt.Run(\"UserAgent\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{UserAgent: null.StringFrom(\"foo\")})\n\t\tassert.True(t, opts.UserAgent.Valid)\n\t\tassert.Equal(t, \"foo\", opts.UserAgent.String)\n\t})\n\tt.Run(\"Batch\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{Batch: null.IntFrom(12345)})\n\t\tassert.True(t, opts.Batch.Valid)\n\t\tassert.Equal(t, int64(12345), opts.Batch.Int64)\n\t})\n\tt.Run(\"BatchPerHost\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{BatchPerHost: null.IntFrom(12345)})\n\t\tassert.True(t, opts.BatchPerHost.Valid)\n\t\tassert.Equal(t, int64(12345), opts.BatchPerHost.Int64)\n\t})\n\tt.Run(\"HTTPDebug\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{HTTPDebug: null.StringFrom(\"foo\")})\n\t\tassert.True(t, opts.HTTPDebug.Valid)\n\t\tassert.Equal(t, \"foo\", opts.HTTPDebug.String)\n\t})\n\tt.Run(\"InsecureSkipTLSVerify\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{InsecureSkipTLSVerify: null.BoolFrom(true)})\n\t\tassert.True(t, opts.InsecureSkipTLSVerify.Valid)\n\t\tassert.True(t, opts.InsecureSkipTLSVerify.Bool)\n\t})\n\tt.Run(\"TLSCipherSuites\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tfor suiteName, suiteID := range SupportedTLSCipherSuites {\n\t\t\tt.Run(suiteName, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\topts := Options{}.Apply(Options{TLSCipherSuites: &TLSCipherSuites{suiteID}})\n\n\t\t\t\tassert.NotNil(t, opts.TLSCipherSuites)\n\t\t\t\tassert.Len(t, *(opts.TLSCipherSuites), 1)\n\t\t\t\tassert.Equal(t, suiteID, (*opts.TLSCipherSuites)[0])\n\t\t\t})\n\t\t}\n\n\t\tt.Run(\"JSON\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsCipherSuites\":[\"TLS_ECDHE_RSA_WITH_RC4_128_SHA\"]}`\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t\tassert.Equal(t, &TLSCipherSuites{tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA}, opts.TLSCipherSuites)\n\n\t\t\t\tt.Run(\"Roundtrip\", func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tdata, err := json.Marshal(opts.TLSCipherSuites)\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, `[\"TLS_ECDHE_RSA_WITH_RC4_128_SHA\"]`, string(data))\n\t\t\t\t\tvar vers2 TLSCipherSuites\n\t\t\t\t\tassert.NoError(t, json.Unmarshal(data, &vers2))\n\t\t\t\t\tassert.Equal(t, &vers2, opts.TLSCipherSuites)\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.Run(\"Not a string\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsCipherSuites\":[1.2]}`\n\t\t\t\tassert.Error(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t})\n\t\t\tt.Run(\"Unknown cipher\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsCipherSuites\":[\"foo\"]}`\n\t\t\t\tassert.Error(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t})\n\t\t})\n\t})\n\tt.Run(\"TLSVersion\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tversions := TLSVersions{Min: tls.VersionSSL30, Max: tls.VersionTLS12} //nolint:staticcheck\n\t\topts := Options{}.Apply(Options{TLSVersion: &versions})\n\n\t\tassert.NotNil(t, opts.TLSVersion)\n\t\tassert.Equal(t, TLSVersion(tls.VersionSSL30), opts.TLSVersion.Min) //nolint:staticcheck\n\t\tassert.Equal(t, TLSVersion(tls.VersionTLS12), opts.TLSVersion.Max)\n\n\t\tt.Run(\"JSON\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Run(\"Object\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsVersion\":{\"min\":\"tls1.0\",\"max\":\"tls1.2\"}}`\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t\tassert.Equal(t, &TLSVersions{\n\t\t\t\t\tMin: TLSVersion(tls.VersionTLS10),\n\t\t\t\t\tMax: TLSVersion(tls.VersionTLS12),\n\t\t\t\t}, opts.TLSVersion)\n\n\t\t\t\tt.Run(\"Roundtrip\", func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tdata, err := json.Marshal(opts.TLSVersion)\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, `{\"min\":\"tls1.0\",\"max\":\"tls1.2\"}`, string(data))\n\t\t\t\t\tvar vers2 TLSVersions\n\t\t\t\t\tassert.NoError(t, json.Unmarshal(data, &vers2))\n\t\t\t\t\tassert.Equal(t, &vers2, opts.TLSVersion)\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsVersion\":\"tls1.2\"}`\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t\tassert.Equal(t, &TLSVersions{\n\t\t\t\t\tMin: TLSVersion(tls.VersionTLS12),\n\t\t\t\t\tMax: TLSVersion(tls.VersionTLS12),\n\t\t\t\t}, opts.TLSVersion)\n\t\t\t})\n\t\t\tt.Run(\"Blank\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsVersion\":\"\"}`\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t\tassert.Equal(t, &TLSVersions{}, opts.TLSVersion)\n\t\t\t})\n\t\t\tt.Run(\"Not a string\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsVersion\":1.2}`\n\t\t\t\tassert.Error(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t})\n\t\t\tt.Run(\"Unsupported version\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"tlsVersion\":\"-1\"}`\n\t\t\t\tassert.Error(t, json.Unmarshal([]byte(jsonStr), &opts))\n\n\t\t\t\tjsonStr = `{\"tlsVersion\":\"ssl3.0\"}`\n\t\t\t\tassert.Error(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t})\n\t\t})\n\t})\n\tt.Run(\"TLSAuth\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttlsAuth := []*TLSAuth{\n\t\t\t{TLSAuthFields{\n\t\t\t\tDomains: []string{\"example.com\", \"*.example.com\"},\n\t\t\t\tCert: \"-----BEGIN CERTIFICATE-----\\n\" +\n\t\t\t\t\t\"MIIBoTCCAUegAwIBAgIUQl0J1Gkd6U2NIMwMDnpfH8c1myEwCgYIKoZIzj0EAwIw\\n\" +\n\t\t\t\t\t\"EDEOMAwGA1UEAxMFTXkgQ0EwHhcNMTcwODE1MTYxODAwWhcNMTgwODE1MTYxODAw\\n\" +\n\t\t\t\t\t\"WjAQMQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLaf\\n\" +\n\t\t\t\t\t\"xEOmBHkzbqd9/0VZX/39qO2yQq2Gz5faRdvy38kuLMCV+9HYrfMx6GYCZzTUIq6h\\n\" +\n\t\t\t\t\t\"8QXOrlgYTixuUVfhJNWjfzB9MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggr\\n\" +\n\t\t\t\t\t\"BgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUxmQiq5K3\\n\" +\n\t\t\t\t\t\"KUnVME945Byt3Ysvkh8wHwYDVR0jBBgwFoAU3qEhcpRgpsqo9V+LFns9a+oZIYww\\n\" +\n\t\t\t\t\t\"CgYIKoZIzj0EAwIDSAAwRQIgSGxnJ+/cLUNTzt7fhr/mjJn7ShsTW33dAdfLM7H2\\n\" +\n\t\t\t\t\t\"z/gCIQDyVf8DePtxlkMBScTxZmIlMQdNc6+6VGZQ4QscruVLmg==\\n\" +\n\t\t\t\t\t\"-----END CERTIFICATE-----\",\n\t\t\t\tKey: \"-----BEGIN EC PRIVATE KEY-----\\n\" +\n\t\t\t\t\t\"MHcCAQEEIAfJeoc+XgcqmYV0b4owmofx0LXwPRqOPXMO+PUKxZSgoAoGCCqGSM49\\n\" +\n\t\t\t\t\t\"AwEHoUQDQgAEtp/EQ6YEeTNup33/RVlf/f2o7bJCrYbPl9pF2/LfyS4swJX70dit\\n\" +\n\t\t\t\t\t\"8zHoZgJnNNQirqHxBc6uWBhOLG5RV+Ek1Q==\\n\" +\n\t\t\t\t\t\"-----END EC PRIVATE KEY-----\",\n\t\t\t}, nil},\n\t\t\t{TLSAuthFields{\n\t\t\t\tDomains: []string{\"sub.example.com\"},\n\t\t\t\tCert: \"-----BEGIN CERTIFICATE-----\\n\" +\n\t\t\t\t\t\"MIIBojCCAUegAwIBAgIUWMpVQhmGoLUDd2x6XQYoOOV6C9AwCgYIKoZIzj0EAwIw\\n\" +\n\t\t\t\t\t\"EDEOMAwGA1UEAxMFTXkgQ0EwHhcNMTcwODE1MTYxODAwWhcNMTgwODE1MTYxODAw\\n\" +\n\t\t\t\t\t\"WjAQMQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBfF\\n\" +\n\t\t\t\t\t\"85gu8fDbNGNlsrtnO+4HvuiP4IXA041jjGczD5kUQ8aihS7hg81tSrLNd1jgxkkv\\n\" +\n\t\t\t\t\t\"Po+3TQjzniysiunG3iKjfzB9MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggr\\n\" +\n\t\t\t\t\t\"BgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUU0JfPCQb\\n\" +\n\t\t\t\t\t\"2YpQZV4j1yiRXBa7J64wHwYDVR0jBBgwFoAU3qEhcpRgpsqo9V+LFns9a+oZIYww\\n\" +\n\t\t\t\t\t\"CgYIKoZIzj0EAwIDSQAwRgIhANYDaM18sXAdkjybHccH8xTbBWUNpOYvoHhrGW32\\n\" +\n\t\t\t\t\t\"Ov9JAiEA7QKGpm07tQl8p+t7UsOgZu132dHNZUtfgp1bjWfcapU=\\n\" +\n\t\t\t\t\t\"-----END CERTIFICATE-----\",\n\t\t\t\tKey: \"-----BEGIN EC PRIVATE KEY-----\\n\" +\n\t\t\t\t\t\"MHcCAQEEINVilD5qOBkSy+AYfd41X0QPB5N3Z6OzgoBj8FZmSJOFoAoGCCqGSM49\\n\" +\n\t\t\t\t\t\"AwEHoUQDQgAEF8XzmC7x8Ns0Y2Wyu2c77ge+6I/ghcDTjWOMZzMPmRRDxqKFLuGD\\n\" +\n\t\t\t\t\t\"zW1Kss13WODGSS8+j7dNCPOeLKyK6cbeIg==\\n\" +\n\t\t\t\t\t\"-----END EC PRIVATE KEY-----\",\n\t\t\t}, nil},\n\t\t}\n\t\topts := Options{}.Apply(Options{TLSAuth: tlsAuth})\n\t\tassert.Equal(t, tlsAuth, opts.TLSAuth)\n\n\t\tt.Run(\"Roundtrip\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\toptsData, err := json.Marshal(opts)\n\t\t\tassert.NoError(t, err)\n\n\t\t\tvar opts2 Options\n\t\t\tassert.NoError(t, json.Unmarshal(optsData, &opts2))\n\t\t\trequire.Len(t, opts2.TLSAuth, len(opts.TLSAuth))\n\t\t\tfor i := 0; i < len(opts2.TLSAuth); i++ {\n\t\t\t\tassert.Equal(t, opts.TLSAuth[i].TLSAuthFields, opts2.TLSAuth[i].TLSAuthFields)\n\t\t\t\tcert, err := opts2.TLSAuth[i].Certificate()\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.NotNil(t, cert)\n\t\t\t}\n\t\t})\n\n\t\tt.Run(\"Invalid JSON\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar opts Options\n\t\t\tjsonStr := `{\"tlsAuth\":[\"invalid\"]}`\n\t\t\tassert.Error(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t})\n\n\t\tt.Run(\"Certificate error\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar opts Options\n\t\t\tjsonStr := `{\"tlsAuth\":[{\"Cert\":\"\"}]}`\n\t\t\tassert.Error(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t})\n\t})\n\tt.Run(\"TLSAuth with\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tdomains := []string{\"example.com\", \"*.example.com\"}\n\t\tcert := \"-----BEGIN CERTIFICATE-----\\n\" +\n\t\t\t\"MIIBoTCCAUegAwIBAgIUQl0J1Gkd6U2NIMwMDnpfH8c1myEwCgYIKoZIzj0EAwIw\\n\" +\n\t\t\t\"EDEOMAwGA1UEAxMFTXkgQ0EwHhcNMTcwODE1MTYxODAwWhcNMTgwODE1MTYxODAw\\n\" +\n\t\t\t\"WjAQMQ4wDAYDVQQDEwV1c2VyMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLaf\\n\" +\n\t\t\t\"xEOmBHkzbqd9/0VZX/39qO2yQq2Gz5faRdvy38kuLMCV+9HYrfMx6GYCZzTUIq6h\\n\" +\n\t\t\t\"8QXOrlgYTixuUVfhJNWjfzB9MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggr\\n\" +\n\t\t\t\"BgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUxmQiq5K3\\n\" +\n\t\t\t\"KUnVME945Byt3Ysvkh8wHwYDVR0jBBgwFoAU3qEhcpRgpsqo9V+LFns9a+oZIYww\\n\" +\n\t\t\t\"CgYIKoZIzj0EAwIDSAAwRQIgSGxnJ+/cLUNTzt7fhr/mjJn7ShsTW33dAdfLM7H2\\n\" +\n\t\t\t\"z/gCIQDyVf8DePtxlkMBScTxZmIlMQdNc6+6VGZQ4QscruVLmg==\\n\" +\n\t\t\t\"-----END CERTIFICATE-----\"\n\t\ttests := []struct {\n\t\t\tname         string\n\t\t\tprivateKey   string\n\t\t\tpassword     string\n\t\t\thasError     bool\n\t\t\terrorMessage string\n\t\t}{\n\t\t\t{\n\t\t\t\tname: \"encrypted key and invalid password\",\n\t\t\t\tprivateKey: \"-----BEGIN EC PRIVATE KEY-----\\n\" +\n\t\t\t\t\t\"Proc-Type: 4,ENCRYPTED\\n\" +\n\t\t\t\t\t\"DEK-Info: AES-256-CBC,DF2445CBFE2E5B112FB2B721063757E5\\n\" +\n\t\t\t\t\t\"o/VKNZjQcRM2hatqUkQ0dTolL7i2i5hJX9XYsl+TMsq8ZkC83uY/JdR986QS+W2c\\n\" +\n\t\t\t\t\t\"EoQGtVGVeL0KGvGpzjTX3YAKXM7Lg5btAeS8GvJ9S7YFd8s0q1pqDdffl2RyjJav\\n\" +\n\t\t\t\t\t\"t1jx6XvLu2nBrOUARvHqjkkJQCTdRf2a34GJdbZqE+4=\\n\" +\n\t\t\t\t\t\"-----END EC PRIVATE KEY-----\",\n\t\t\t\tpassword:     \"iZfYGcrgFHOg4nweEo7ufT\",\n\t\t\t\thasError:     true,\n\t\t\t\terrorMessage: \"x509: decryption password incorrect\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"encrypted key and valid password\",\n\t\t\t\tprivateKey: \"-----BEGIN EC PRIVATE KEY-----\\n\" +\n\t\t\t\t\t\"Proc-Type: 4,ENCRYPTED\\n\" +\n\t\t\t\t\t\"DEK-Info: AES-256-CBC,DF2445CBFE2E5B112FB2B721063757E5\\n\" +\n\t\t\t\t\t\"o/VKNZjQcRM2hatqUkQ0dTolL7i2i5hJX9XYsl+TMsq8ZkC83uY/JdR986QS+W2c\\n\" +\n\t\t\t\t\t\"EoQGtVGVeL0KGvGpzjTX3YAKXM7Lg5btAeS8GvJ9S7YFd8s0q1pqDdffl2RyjJav\\n\" +\n\t\t\t\t\t\"t1jx6XvLu2nBrOUARvHqjkkJQCTdRf2a34GJdbZqE+4=\\n\" +\n\t\t\t\t\t\"-----END EC PRIVATE KEY-----\",\n\t\t\t\tpassword:     \"12345\",\n\t\t\t\thasError:     false,\n\t\t\t\terrorMessage: \"\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"encrypted pks8 format key and valid password\",\n\t\t\t\tprivateKey: \"-----BEGIN ENCRYPTED PRIVATE KEY-----\\n\" +\n\t\t\t\t\t\"MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjcfarGfrRgUgICCAAw\\n\" +\n\t\t\t\t\t\"DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEFmtmKEFmThbkbpxmC6iBvoEgZCE\\n\" +\n\t\t\t\t\t\"pDCpH/yCLmSpjdi/PC74I794nzHyCWf/oS0JhM0Q7J+abZP+p5pnreKft1f15Dbw\\n\" +\n\t\t\t\t\t\"QG9alfoM6EffJcVo3gf1tgQrpGGFMwczc4VhQgSGDy0XjZSbd2K0QCFGSmD2ZIR1\\n\" +\n\t\t\t\t\t\"qPG3WepWjKmIsYffGeKZx+FjXHSFeGk7RnssNAyKcPruDQIdWWyXxX1+ugBKuBw=\\n\" +\n\t\t\t\t\t\"-----END ENCRYPTED PRIVATE KEY-----\\n\",\n\t\t\t\tpassword:     \"12345\",\n\t\t\t\thasError:     true,\n\t\t\t\terrorMessage: \"encrypted pkcs8 formatted key is not supported\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"non encrypted key and password\",\n\t\t\t\tprivateKey: \"-----BEGIN EC PRIVATE KEY-----\\n\" +\n\t\t\t\t\t\"MHcCAQEEINVilD5qOBkSy+AYfd41X0QPB5N3Z6OzgoBj8FZmSJOFoAoGCCqGSM49\\n\" +\n\t\t\t\t\t\"AwEHoUQDQgAEF8XzmC7x8Ns0Y2Wyu2c77ge+6I/ghcDTjWOMZzMPmRRDxqKFLuGD\\n\" +\n\t\t\t\t\t\"zW1Kss13WODGSS8+j7dNCPOeLKyK6cbeIg==\\n\" +\n\t\t\t\t\t\"-----END EC PRIVATE KEY-----\",\n\t\t\t\tpassword:     \"12345\",\n\t\t\t\thasError:     true,\n\t\t\t\terrorMessage: \"x509: no DEK-Info header in block\",\n\t\t\t},\n\t\t}\n\t\tfor _, tc := range tests {\n\t\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\ttlsAuth := []*TLSAuth{\n\t\t\t\t\t{TLSAuthFields{\n\t\t\t\t\t\tDomains:  domains,\n\t\t\t\t\t\tCert:     cert,\n\t\t\t\t\t\tKey:      tc.privateKey,\n\t\t\t\t\t\tPassword: null.StringFrom(tc.password),\n\t\t\t\t\t}, nil},\n\t\t\t\t}\n\t\t\t\topts := Options{}.Apply(Options{TLSAuth: tlsAuth})\n\t\t\t\tassert.Equal(t, tlsAuth, opts.TLSAuth)\n\n\t\t\t\tt.Run(\"Roundtrip\", func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\toptsData, err := json.Marshal(opts)\n\t\t\t\t\tassert.NoError(t, err)\n\n\t\t\t\t\tvar opts2 Options\n\t\t\t\t\terr = json.Unmarshal(optsData, &opts2)\n\t\t\t\t\tif tc.hasError {\n\t\t\t\t\t\tassert.Error(t, err)\n\t\t\t\t\t\tassert.Contains(t, err.Error(), tc.errorMessage)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t})\n\tt.Run(\"NoConnectionReuse\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{NoConnectionReuse: null.BoolFrom(true)})\n\t\tassert.True(t, opts.NoConnectionReuse.Valid)\n\t\tassert.True(t, opts.NoConnectionReuse.Bool)\n\t})\n\tt.Run(\"NoVUConnectionReuse\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{NoVUConnectionReuse: null.BoolFrom(true)})\n\t\tassert.True(t, opts.NoVUConnectionReuse.Valid)\n\t\tassert.True(t, opts.NoVUConnectionReuse.Bool)\n\t})\n\tt.Run(\"NoCookiesReset\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{NoCookiesReset: null.BoolFrom(true)})\n\t\tassert.True(t, opts.NoCookiesReset.Valid)\n\t\tassert.True(t, opts.NoCookiesReset.Bool)\n\t})\n\tt.Run(\"BlacklistIPs\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{\n\t\t\tBlacklistIPs: []*IPNet{{\n\t\t\t\tIPNet: net.IPNet{\n\t\t\t\t\tIP:   net.IPv4bcast,\n\t\t\t\t\tMask: net.CIDRMask(31, 32),\n\t\t\t\t},\n\t\t\t}},\n\t\t})\n\t\tassert.NotNil(t, opts.BlacklistIPs)\n\t\tassert.NotEmpty(t, opts.BlacklistIPs)\n\t\tassert.Equal(t, net.IPv4bcast, opts.BlacklistIPs[0].IP)\n\t\tassert.Equal(t, net.CIDRMask(31, 32), opts.BlacklistIPs[0].Mask)\n\n\t\tt.Run(\"JSON\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tb, err := json.Marshal(opts)\n\t\t\trequire.NoError(t, err)\n\n\t\t\tvar uopts Options\n\t\t\terr = json.Unmarshal(b, &uopts)\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.Len(t, uopts.BlacklistIPs, 1)\n\t\t\trequire.Equal(t, \"255.255.255.254/31\", uopts.BlacklistIPs[0].String())\n\t\t})\n\t})\n\tt.Run(\"BlockedHostnames\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tblockedHostnames, err := types.NewNullHostnameTrie([]string{\"test.k6.io\", \"*valid.pattern\"})\n\t\trequire.NoError(t, err)\n\t\topts := Options{}.Apply(Options{BlockedHostnames: blockedHostnames})\n\t\tassert.NotNil(t, opts.BlockedHostnames)\n\t\tassert.Equal(t, blockedHostnames, opts.BlockedHostnames)\n\t})\n\n\tt.Run(\"Hosts\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\thost, err := types.NewHost(net.ParseIP(\"192.0.2.1\"), \"80\")\n\t\tassert.NoError(t, err)\n\n\t\thosts, err := types.NewNullHosts(map[string]types.Host{\n\t\t\t\"test.loadimpact.com\": *host,\n\t\t})\n\t\tassert.NoError(t, err)\n\t\topts := Options{}.Apply(Options{Hosts: hosts})\n\t\tassert.NotNil(t, opts.Hosts)\n\t\tassert.NotEmpty(t, opts.Hosts)\n\n\t\tassert.Equal(t, \"192.0.2.1:80\", opts.Hosts.Trie.Match(\"test.loadimpact.com\").String())\n\t})\n\n\tt.Run(\"Throws\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{Throw: null.BoolFrom(true)})\n\t\tassert.True(t, opts.Throw.Valid)\n\t\tassert.Equal(t, true, opts.Throw.Bool)\n\t})\n\n\tt.Run(\"Thresholds\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{Thresholds: map[string]metrics.Thresholds{\n\t\t\t\"metric\": {\n\t\t\t\tThresholds: []*metrics.Threshold{{}},\n\t\t\t},\n\t\t}})\n\t\tassert.NotNil(t, opts.Thresholds)\n\t\tassert.NotEmpty(t, opts.Thresholds)\n\t})\n\tt.Run(\"External\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\text := map[string]json.RawMessage{\"a\": json.RawMessage(\"1\")}\n\t\topts := Options{}.Apply(Options{External: ext})\n\t\tassert.Equal(t, ext, opts.External)\n\t})\n\n\tt.Run(\"JSON\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tdata, err := json.Marshal(Options{})\n\t\tassert.NoError(t, err)\n\t\tvar opts Options\n\t\tassert.NoError(t, json.Unmarshal(data, &opts))\n\t\tassert.Equal(t, Options{}, opts)\n\t})\n\tt.Run(\"SystemTags\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{SystemTags: metrics.NewSystemTagSet(metrics.TagProto)})\n\t\tassert.NotNil(t, opts.SystemTags)\n\t\tassert.NotEmpty(t, opts.SystemTags)\n\t\tassert.True(t, opts.SystemTags.Has(metrics.TagProto))\n\n\t\tt.Run(\"JSON\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Run(\"Array\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"systemTags\":[\"url\"]}`\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t\tassert.Equal(t, *metrics.NewSystemTagSet(metrics.TagURL), *opts.SystemTags)\n\n\t\t\t\tt.Run(\"Roundtrip\", func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tdata, err := json.Marshal(opts.SystemTags)\n\t\t\t\t\tassert.NoError(t, err)\n\t\t\t\t\tassert.Equal(t, `[\"url\"]`, string(data))\n\t\t\t\t\tvar vers2 metrics.SystemTagSet\n\t\t\t\t\tassert.NoError(t, json.Unmarshal(data, &vers2))\n\t\t\t\t\tassert.Equal(t, vers2, *opts.SystemTags)\n\t\t\t\t})\n\t\t\t})\n\t\t\tt.Run(\"Blank\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar opts Options\n\t\t\t\tjsonStr := `{\"systemTags\":[]}`\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts))\n\t\t\t\tassert.Equal(t, metrics.SystemTagSet(0), *opts.SystemTags)\n\t\t\t})\n\t\t})\n\t})\n\tt.Run(\"SummaryTrendStats\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tstats := []string{\"myStat1\", \"myStat2\"}\n\t\topts := Options{}.Apply(Options{SummaryTrendStats: stats})\n\t\tassert.Equal(t, stats, opts.SummaryTrendStats)\n\t})\n\tt.Run(\"RunTags\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttags := map[string]string{\"myTag\": \"hello\"}\n\t\topts := Options{}.Apply(Options{RunTags: tags})\n\t\tassert.Equal(t, tags, opts.RunTags)\n\t})\n\tt.Run(\"DiscardResponseBodies\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\topts := Options{}.Apply(Options{DiscardResponseBodies: null.BoolFrom(true)})\n\t\tassert.True(t, opts.DiscardResponseBodies.Valid)\n\t\tassert.True(t, opts.DiscardResponseBodies.Bool)\n\t})\n\tt.Run(\"ClientIPRanges\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tclientIPRanges := types.NullIPPool{}\n\t\terr := clientIPRanges.UnmarshalText([]byte(\"129.112.232.12,123.12.0.0/32\"))\n\t\trequire.NoError(t, err)\n\t\topts := Options{}.Apply(Options{LocalIPs: clientIPRanges})\n\t\tassert.NotNil(t, opts.LocalIPs)\n\t})\n}\n\nfunc TestOptionsEnv(t *testing.T) {\n\tt.Parallel()\n\tmustNullIPPool := func(s string) types.NullIPPool {\n\t\tp := types.NullIPPool{}\n\t\terr := p.UnmarshalText([]byte(s))\n\t\trequire.NoError(t, err)\n\t\treturn p\n\t}\n\n\ttestdata := map[struct{ Name, Key string }]map[string]any{\n\t\t{\"Paused\", \"K6_PAUSED\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t{\"VUs\", \"K6_VUS\"}: {\n\t\t\t\"\":    null.Int{},\n\t\t\t\"123\": null.IntFrom(123),\n\t\t},\n\t\t{\"Duration\", \"K6_DURATION\"}: {\n\t\t\t\"\":    types.NullDuration{},\n\t\t\t\"10s\": types.NullDurationFrom(10 * time.Second),\n\t\t},\n\t\t{\"Iterations\", \"K6_ITERATIONS\"}: {\n\t\t\t\"\":    null.Int{},\n\t\t\t\"123\": null.IntFrom(123),\n\t\t},\n\t\t{\"Stages\", \"K6_STAGES\"}: {\n\t\t\t// \"\": []Stage{},\n\t\t\t\"1s\": []Stage{\n\t\t\t\t{\n\t\t\t\t\tDuration: types.NullDurationFrom(1 * time.Second),\n\t\t\t\t},\n\t\t\t},\n\t\t\t\"1s:100\": []Stage{\n\t\t\t\t{Duration: types.NullDurationFrom(1 * time.Second), Target: null.IntFrom(100)},\n\t\t\t},\n\t\t\t\"1s,2s:100\": []Stage{\n\t\t\t\t{Duration: types.NullDurationFrom(1 * time.Second)},\n\t\t\t\t{Duration: types.NullDurationFrom(2 * time.Second), Target: null.IntFrom(100)},\n\t\t\t},\n\t\t},\n\t\t{\"MaxRedirects\", \"K6_MAX_REDIRECTS\"}: {\n\t\t\t\"\":    null.Int{},\n\t\t\t\"123\": null.IntFrom(123),\n\t\t},\n\t\t{\"NoSetup\", \"K6_NO_SETUP\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t{\"NoTeardown\", \"K6_NO_TEARDOWN\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t{\"InsecureSkipTLSVerify\", \"K6_INSECURE_SKIP_TLS_VERIFY\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t// TLSCipherSuites\n\t\t// TLSVersion\n\t\t// TLSAuth\n\t\t{\"NoConnectionReuse\", \"K6_NO_CONNECTION_REUSE\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t{\"NoVUConnectionReuse\", \"K6_NO_VU_CONNECTION_REUSE\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t{\"UserAgent\", \"K6_USER_AGENT\"}: {\n\t\t\t\"\":    null.String{},\n\t\t\t\"Hi!\": null.StringFrom(\"Hi!\"),\n\t\t},\n\t\t{\"LocalIPs\", \"K6_LOCAL_IPS\"}: {\n\t\t\t\"\":                 types.NullIPPool{},\n\t\t\t\"192.168.220.2\":    mustNullIPPool(\"192.168.220.2\"),\n\t\t\t\"192.168.220.0/24\": mustNullIPPool(\"192.168.220.0/24\"),\n\t\t},\n\t\t{\"Throw\", \"K6_THROW\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t{\"NoCookiesReset\", \"K6_NO_COOKIES_RESET\"}: {\n\t\t\t\"\":      null.Bool{},\n\t\t\t\"true\":  null.BoolFrom(true),\n\t\t\t\"false\": null.BoolFrom(false),\n\t\t},\n\t\t// Thresholds\n\t\t// External\n\t}\n\tfor field, data := range testdata {\n\t\tt.Run(field.Name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tfor str, val := range data {\n\t\t\t\tt.Run(`\"`+str+`\"`, func(t *testing.T) {\n\t\t\t\t\tt.Parallel()\n\t\t\t\t\tvar opts Options\n\t\t\t\t\tassert.NoError(t, envconfig.Process(\"k6\", &opts, func(k string) (string, bool) {\n\t\t\t\t\t\tif k == field.Key {\n\t\t\t\t\t\t\treturn str, true\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn \"\", false\n\t\t\t\t\t}))\n\t\t\t\t\tassert.Equal(t, val, reflect.ValueOf(opts).FieldByName(field.Name).Interface())\n\t\t\t\t})\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestCIDRUnmarshal(t *testing.T) {\n\tt.Parallel()\n\ttestData := []struct {\n\t\tinput          string\n\t\texpectedOutput *IPNet\n\t\texpectFailure  bool\n\t}{\n\t\t{\n\t\t\t\"10.0.0.0/8\",\n\t\t\t&IPNet{IPNet: net.IPNet{\n\t\t\t\tIP:   net.IP{10, 0, 0, 0},\n\t\t\t\tMask: net.IPv4Mask(255, 0, 0, 0),\n\t\t\t}},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"fc00:1234:5678::/48\",\n\t\t\t&IPNet{IPNet: net.IPNet{\n\t\t\t\tIP:   net.ParseIP(\"fc00:1234:5678::\"),\n\t\t\t\tMask: net.CIDRMask(48, 128),\n\t\t\t}},\n\t\t\tfalse,\n\t\t},\n\t\t{\"10.0.0.0\", nil, true},\n\t\t{\"fc00:1234:5678::\", nil, true},\n\t\t{\"fc00::1234::/48\", nil, true},\n\t}\n\n\tfor _, data := range testData {\n\t\tt.Run(data.input, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tactualIPNet := &IPNet{}\n\t\t\terr := actualIPNet.UnmarshalText([]byte(data.input))\n\n\t\t\tif data.expectFailure {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\trequire.Contains(t, err.Error(), \"invalid CIDR address: \"+data.input)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, data.expectedOutput, actualIPNet)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestHost(t *testing.T) {\n\tt.Parallel()\n\ttestData := []struct {\n\t\tinput          string\n\t\texpectedOutput *types.Host\n\t\texpectFailure  string\n\t}{\n\t\t{\n\t\t\t\"1.2.3.4\",\n\t\t\t&types.Host{IP: net.ParseIP(\"1.2.3.4\")},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"1.2.3.4:80\",\n\t\t\t&types.Host{IP: net.ParseIP(\"1.2.3.4\"), Port: 80},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"1.2.3.4:asdf\",\n\t\t\tnil,\n\t\t\t\"strconv.Atoi: parsing \\\"asdf\\\": invalid syntax\",\n\t\t},\n\t\t{\n\t\t\t\"2001:0db8:0000:0000:0000:ff00:0042:8329\",\n\t\t\t&types.Host{IP: net.ParseIP(\"2001:0db8:0000:0000:0000:ff00:0042:8329\")},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"2001:db8::68\",\n\t\t\t&types.Host{IP: net.ParseIP(\"2001:db8::68\")},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"[2001:db8::68]:80\",\n\t\t\t&types.Host{IP: net.ParseIP(\"2001:db8::68\"), Port: 80},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t\"[2001:db8::68]:asdf\",\n\t\t\tnil,\n\t\t\t\"strconv.Atoi: parsing \\\"asdf\\\": invalid syntax\",\n\t\t},\n\t}\n\n\tfor _, data := range testData {\n\t\tt.Run(data.input, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tactualHost := &types.Host{}\n\t\t\terr := actualHost.UnmarshalText([]byte(data.input))\n\n\t\t\tif data.expectFailure != \"\" {\n\t\t\t\trequire.EqualError(t, err, data.expectFailure)\n\t\t\t} else {\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, data.expectedOutput, actualHost)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestValidate(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"setupTimeout\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttestData := []struct {\n\t\t\tinput         string\n\t\t\texpectFailure bool\n\t\t\texpectOutput  types.Duration\n\t\t}{\n\t\t\t{\n\t\t\t\tinput:         \"1s\",\n\t\t\t\texpectFailure: false,\n\t\t\t\texpectOutput:  types.Duration(1 * time.Second),\n\t\t\t},\n\t\t\t{\n\t\t\t\tinput:         \"0s\",\n\t\t\t\texpectFailure: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tinput:         \"-1s\",\n\t\t\t\texpectFailure: true,\n\t\t\t},\n\t\t}\n\t\tfor _, data := range testData {\n\t\t\tt.Run(data.input, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tsec, _ := time.ParseDuration(data.input)\n\t\t\t\topts := Options{}.Apply(Options{SetupTimeout: types.NewNullDuration(sec, true)})\n\t\t\t\terrorsSlice := opts.Validate()\n\t\t\t\tif data.expectFailure {\n\t\t\t\t\tassert.Len(t, errorsSlice, 1)\n\t\t\t\t} else {\n\t\t\t\t\tassert.Len(t, errorsSlice, 0)\n\t\t\t\t\tassert.Equal(t, time.Duration(opts.SetupTimeout.Duration), sec)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "lib/runner.go",
    "content": "package lib\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"go.k6.io/k6/internal/lib/summary\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// ActiveVU represents an actively running virtual user.\ntype ActiveVU interface {\n\t// RunOnce runs the configured exported function in the VU once.\n\t// The only way to interrupt the execution is to cancel the context given\n\t// to InitializedVU.Activate()\n\tRunOnce() error\n}\n\n// InitializedVU represents a virtual user ready for work. It needs to be\n// activated (i.e. given a context) before it can actually be used. Activation\n// also requires a callback function, which will be called when the supplied\n// context is done. That way, VUs can be returned to a pool and reused.\ntype InitializedVU interface {\n\t// Activate fully activate the VU so it will be able to run code.\n\tActivate(*VUActivationParams) ActiveVU\n\n\t// GetID returns the unique VU ID.\n\tGetID() uint64\n}\n\n// VUActivationParams are supplied by each executor when it retrieves a VU from\n// the buffer pool and activates it for use.\ntype VUActivationParams struct {\n\tRunContext               context.Context\n\tDeactivateCallback       func(InitializedVU)\n\tEnv, Tags                map[string]string\n\tExec, Scenario           string\n\tGetNextIterationCounters func() (uint64, uint64)\n}\n\n// A Runner is a factory for VUs. It should precompute as much as possible upon\n// creation (parse ASTs, load files into memory, etc.), so that spawning VUs\n// becomes as fast as possible. The Runner doesn't actually *do* anything in\n// itself, the ExecutionScheduler is responsible for wrapping and scheduling\n// these VUs for execution.\n//\n// TODO: Rename this to something more obvious? This name made sense a very long\n// time ago.\n//\n// interfacebloat: We may evaluate in the future to move out some methods;\n// but considering how central it is, it would require a huge effort.\ntype Runner interface {\n\t// MakeArchive creates an Archive of the runner. There should be a corresponding NewFromArchive() function\n\t// that will restore the runner from the archive.\n\tMakeArchive() *Archive\n\n\t// NewVU spawns a new VU. It's fine to make this function rather heavy, if it means a performance\n\t// improvement at runtime. Remember, this is called once per VU and normally only at the start\n\t// of a test - RunOnce() may be called hundreds of thousands of times, and must be fast.\n\tNewVU(ctx context.Context, idLocal, idGlobal uint64, out chan<- metrics.SampleContainer) (InitializedVU, error)\n\n\t// Setup runs pre-test setup, if applicable.\n\tSetup(ctx context.Context, out chan<- metrics.SampleContainer) error\n\n\t// GetSetupData returns json representation of the setup data if setup() is specified and run, nil otherwise\n\tGetSetupData() []byte\n\n\t// SetSetupData saves the externally supplied setup data as json in the runner\n\tSetSetupData([]byte)\n\n\t// Teardown runs post-test teardown, if applicable.\n\tTeardown(ctx context.Context, out chan<- metrics.SampleContainer) error\n\n\t// Get and set options. The initial value will be whatever the script specifies (for JS,\n\t// `export let options = {}`); cmd/run.go will mix this in with CLI-, config- and env-provided\n\t// values and write it back to the runner.\n\tGetOptions() Options\n\tSetOptions(opts Options) error\n\n\t// IsExecutable returns whether the given name is an exported and executable\n\t// function in the script.\n\tIsExecutable(string) bool\n\n\tHandleSummary(context.Context, *LegacySummary, *summary.Summary, summary.Meta) (map[string]io.Reader, error)\n}\n\n// UIState describes the state of the UI, which might influence what\n// handleSummary() returns.\ntype UIState struct {\n\tIsStdOutTTY bool\n\tIsStdErrTTY bool\n}\n"
  },
  {
    "path": "lib/runtime_options.go",
    "content": "package lib\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// CompatibilityMode specifies the JS compatibility mode\n//\n//go:generate enumer -type=CompatibilityMode -transform=snake -trimprefix CompatibilityMode -output compatibility_mode_gen.go\ntype CompatibilityMode uint8\n\nconst (\n\t// CompatibilityModeExtended adds `global` as an alias for `globalThis` on top of the base mode\n\tCompatibilityModeExtended CompatibilityMode = iota + 1\n\t// CompatibilityModeBase is standard Sobek, which means pure vanilla JS following ECMAScript standards.\n\tCompatibilityModeBase\n\t// CompatibilityModeExperimentalEnhanced achieves TypeScript and ES6+ compatibility with esbuild\n\tCompatibilityModeExperimentalEnhanced\n)\n\n// RuntimeOptions are settings passed onto the Sobek JS runtime\ntype RuntimeOptions struct {\n\tTestType null.String `json:\"-\"`\n\n\t// Whether to pass the actual system environment variables to the JS runtime\n\tIncludeSystemEnvVars null.Bool `json:\"includeSystemEnvVars\"`\n\n\t// JS compatibility mode: \"extended\" (Sobek+global) or \"base\" (plain Sobek)\n\t//\n\t// TODO: when we resolve https://github.com/k6io/k6/issues/883, we probably\n\t// should use the CompatibilityMode type directly... but by then, we'd need to have\n\t// some way of knowing if the value has been set by the user or if we're using the\n\t// default one, so we can handle `k6 run --compatibility-mode=base es6_extended_archive.tar`\n\tCompatibilityMode null.String `json:\"compatibilityMode\"`\n\n\t// Environment variables passed onto the runner\n\tEnv map[string]string `json:\"env\"`\n\n\tNoThresholds  null.Bool   `json:\"noThresholds\"`\n\tNoSummary     null.Bool   `json:\"noSummary\"`\n\tSummaryMode   null.String `json:\"summaryMode\"`\n\tSummaryExport null.String `json:\"summaryExport\"`\n\tKeyWriter     null.String `json:\"-\"`\n\tTracesOutput  null.String `json:\"tracesOutput\"`\n\n\t// Until v2\n\tNewMachineReadableSummary null.Bool `json:\"newMachineReadableSummary\"`\n}\n\n// ValidateCompatibilityMode checks if the provided val is a valid compatibility mode\nfunc ValidateCompatibilityMode(val string) (cm CompatibilityMode, err error) {\n\tif val == \"\" {\n\t\treturn CompatibilityModeExtended, nil\n\t}\n\tif cm, err = CompatibilityModeString(val); err != nil {\n\t\tvar compatValues []string\n\t\tfor _, v := range CompatibilityModeValues() {\n\t\t\tcompatValues = append(compatValues, v.String())\n\t\t}\n\t\terr = fmt.Errorf(`invalid compatibility mode \"%s\". Use: \"%s\"`,\n\t\t\tval, strings.Join(compatValues, `\", \"`))\n\t}\n\treturn cm, err\n}\n"
  },
  {
    "path": "lib/state_test.go",
    "content": "package lib\n\nimport (\n\t\"context\"\n\t\"strconv\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestVUStateTagsSync(t *testing.T) {\n\tt.Parallel()\n\n\ttm := NewVUStateTags(metrics.NewRegistry().RootTagSet().With(\"mytag\", \"42\"))\n\tcv := tm.GetCurrentValues()\n\tv, found := cv.Tags.Get(\"mytag\")\n\tassert.True(t, found)\n\tassert.Equal(t, \"42\", v)\n}\n\nfunc TestVUStateTagsSafeConcurrent(t *testing.T) {\n\tt.Parallel()\n\n\twg := &sync.WaitGroup{}\n\twg.Add(2)\n\tdefer wg.Wait()\n\tctx, cancel := context.WithCancel(t.Context())\n\tdefer cancel()\n\n\tstateTags := NewVUStateTags(metrics.NewRegistry().RootTagSet())\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tcount := 0\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-time.Tick(1 * time.Millisecond):\n\t\t\t\tcount++\n\t\t\t\tstateTags.Modify(func(tm *metrics.TagsAndMeta) {\n\t\t\t\t\tval := strconv.Itoa(count)\n\t\t\t\t\ttm.SetMetadata(\"mymeta\", val)\n\t\t\t\t\ttm.SetTag(\"mytag\", val)\n\t\t\t\t})\n\n\t\t\tcase <-ctx.Done():\n\t\t\t\texp := strconv.Itoa(count)\n\t\t\t\tcv := stateTags.GetCurrentValues()\n\t\t\t\tval, ok := cv.Tags.Get(\"mytag\")\n\t\t\t\tassert.True(t, ok)\n\t\t\t\tassert.Equal(t, exp, val)\n\n\t\t\t\tmetaval, metaok := cv.Metadata[\"mymeta\"]\n\t\t\t\tassert.True(t, metaok)\n\t\t\t\tassert.Equal(t, exp, metaval)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-time.Tick(1 * time.Millisecond):\n\t\t\t\tcv := stateTags.GetCurrentValues()\n\t\t\t\tcv.Tags.Get(\"mytag\")\n\t\t\t\tcv.SetMetadata(\"mymeta\", \"foo\") // just to ensure this won't have any effect\n\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\ttime.Sleep(100 * time.Millisecond)\n}\n\nfunc TestVUStateTagsDelete(t *testing.T) {\n\tt.Parallel()\n\tstateTags := NewVUStateTags(metrics.NewRegistry().RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\"key1\": \"value1\",\n\t\t\"key2\": \"value2\",\n\t}))\n\n\tval, ok := stateTags.GetCurrentValues().Tags.Get(\"key1\")\n\trequire.True(t, ok)\n\trequire.Equal(t, \"value1\", val)\n\n\tstateTags.Modify(func(tam *metrics.TagsAndMeta) {\n\t\ttam.DeleteTag(\"key1\")\n\t})\n\t_, ok = stateTags.GetCurrentValues().Tags.Get(\"key1\")\n\tassert.False(t, ok)\n\n\tassert.Equal(t, map[string]string{\"key2\": \"value2\"}, stateTags.GetCurrentValues().Tags.Map())\n}\n\nfunc TestVUStateTagsMap(t *testing.T) {\n\tt.Parallel()\n\ttm := NewVUStateTags(metrics.NewRegistry().RootTagSet().WithTagsFromMap(map[string]string{\n\t\t\"key1\": \"value1\",\n\t\t\"key2\": \"value2\",\n\t}))\n\tm := tm.GetCurrentValues().Tags.Map()\n\tassert.Equal(t, map[string]string{\n\t\t\"key1\": \"value1\",\n\t\t\"key2\": \"value2\",\n\t}, m)\n}\n"
  },
  {
    "path": "lib/summary.go",
    "content": "package lib\n\nimport (\n\t\"time\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\n// LegacySummary contains all the data the summary handler gets.\ntype LegacySummary struct {\n\tMetrics         map[string]*metrics.Metric\n\tRootGroup       *Group\n\tTestRunDuration time.Duration // TODO: use lib.ExecutionState-based interface instead?\n\tNoColor         bool          // TODO: drop this when noColor is part of the (runtime) options\n\tUIState         UIState\n}\n"
  },
  {
    "path": "lib/test_state.go",
    "content": "package lib\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/internal/event\"\n\t\"go.k6.io/k6/internal/lib/trace\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/secretsource\"\n)\n\n// TestPreInitState contains all of the state that can be gathered and built\n// before the test run is initialized.\ntype TestPreInitState struct {\n\tRuntimeOptions RuntimeOptions\n\tRegistry       *metrics.Registry\n\tBuiltinMetrics *metrics.BuiltinMetrics\n\tEvents         *event.System\n\tKeyLogger      io.Writer\n\tLookupEnv      func(key string) (val string, ok bool)\n\tLogger         logrus.FieldLogger\n\tTracerProvider *trace.TracerProvider\n\tUsage          *usage.Usage\n\tSecretsManager *secretsource.Manager\n\n\t// FIXME (@oleiade): is this the way?\n\tTestStatus *TestStatus\n}\n\n// TestStatus holds the test execution status and is used to support marking a test as failed\n// while letting the execution go on.\ntype TestStatus struct {\n\t// failed is a boolean that indicates whether the test has been marked as failed.\n\tfailed bool\n\n\t// failedOnce is a sync.Once that ensures that the test is ever marked as failed only once.\n\tfailedOnce sync.Once\n}\n\n// MarkFailed sets the test status to failed, providing the guarantee that the\n// test will be marked as failed only once, even if multiple VUs or goroutines\n// try to mark it at the same time.\n//\n// This is useful for features that need to mark a test as failed while letting the\n// execution of the test finish normally, e.g. when a test script calls\n// `execution.test.fail()`.\nfunc (ts *TestStatus) MarkFailed() {\n\tts.failedOnce.Do(func() {\n\t\tts.failed = true\n\t})\n}\n\n// Failed returns true if the test has been marked as failed, false otherwise.\nfunc (ts *TestStatus) Failed() bool {\n\treturn ts.failed\n}\n\n// NewTestStatus returns a new TestStatus instance\nfunc NewTestStatus() *TestStatus {\n\treturn &TestStatus{\n\t\tfailed: false,\n\t}\n}\n\n// TestRunState contains the pre-init state as well as all of the state and\n// options that are necessary for actually running the test.\ntype TestRunState struct {\n\t*TestPreInitState\n\n\tOptions Options\n\tRunner  Runner // TODO: rename to something better, see type comment\n\tRunTags *metrics.TagSet\n\n\tGroupSummary *GroupSummary // TODO(@mstoykov): move and rename\n\n\t// TODO: add other properties that are computed or derived after init, e.g.\n\t// thresholds?\n}\n\n// GroupSummaryDescription is the description of the GroupSummary used to identify and ignore it\n// for the purposes of the cli descriptions.\nconst GroupSummaryDescription = \"Internal Group Summary output\"\n\n// GroupSummary is an internal output implementation that facilitates the aggregation of\n// group and check metrics for the purposes of the end of test summary and the REST API\ntype GroupSummary struct {\n\tgroup   *Group // TODO(@mstoykov): move the whole type outside of lib later\n\tch      chan []metrics.SampleContainer\n\tstopped chan struct{}\n\tlogger  logrus.FieldLogger\n}\n\n// NewGroupSummary returns new GroupSummary ready to be started.\nfunc NewGroupSummary(logger logrus.FieldLogger) *GroupSummary {\n\tgroup, _ := NewGroup(RootGroupPath, nil)\n\treturn &GroupSummary{\n\t\tgroup:   group,\n\t\tch:      make(chan []metrics.SampleContainer, 1000),\n\t\tstopped: make(chan struct{}),\n\t\tlogger:  logger,\n\t}\n}\n\n// Group returns the underlying group that has been aggregated\nfunc (gs *GroupSummary) Group() *Group {\n\treturn gs.group\n}\n\n// Description is part of the output.Output interface\nfunc (gs *GroupSummary) Description() string {\n\treturn GroupSummaryDescription\n}\n\nfunc buildGroup(rootGroup *Group, groupName string) (*Group, error) {\n\tgroup := rootGroup\n\tgroups := strings.Split(groupName, \"::\")\n\tvar err error\n\tfor _, groupName := range groups[1:] {\n\t\tgroup, err = group.Group(groupName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn group, nil\n}\n\nfunc (gs *GroupSummary) handleSample(sample metrics.Sample) error {\n\tswitch sample.Metric.Name {\n\tcase \"group_duration\", \"checks\":\n\t\tgroupName, ok := sample.Tags.Get(metrics.TagGroup.String())\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\tgroup, err := buildGroup(gs.group, groupName)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif sample.Metric.Name != \"checks\" {\n\t\t\treturn nil\n\t\t}\n\n\t\tcheckName, ok := sample.Tags.Get(metrics.TagCheck.String())\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\tcheck, err := group.Check(checkName)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif sample.Value == 0 {\n\t\t\tatomic.AddInt64(&check.Fails, 1)\n\t\t} else {\n\t\t\tatomic.AddInt64(&check.Passes, 1)\n\t\t}\n\t}\n\treturn nil\n}\n\n// Start is part of the output.Output interface\nfunc (gs *GroupSummary) Start() error {\n\tgo func() {\n\t\tdefer close(gs.stopped)\n\t\tfor containers := range gs.ch {\n\t\t\tfor _, container := range containers {\n\t\t\t\tfor _, sample := range container.GetSamples() {\n\t\t\t\t\terr := gs.handleSample(sample)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tgs.logger.WithError(err).Warn(\"couldn't handle a sample as part of group summary\")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}()\n\treturn nil\n}\n\n// Stop is part of the output.Output interface\nfunc (gs *GroupSummary) Stop() error {\n\tclose(gs.ch)\n\t<-gs.stopped\n\treturn nil\n}\n\n// AddMetricSamples is part of the output.Output interface\nfunc (gs *GroupSummary) AddMetricSamples(samples []metrics.SampleContainer) {\n\tgs.ch <- samples\n}\n"
  },
  {
    "path": "lib/tlsconfig.go",
    "content": "package lib\n\nimport \"crypto/tls\"\n\n// From https://golang.org/pkg/crypto/tls/#pkg-constants\n\n// SupportedTLSVersions is string-to-constant map of available TLS versions.\n//\n//nolint:gochecknoglobals\nvar SupportedTLSVersions = map[string]TLSVersion{\n\t\"tls1.0\": tls.VersionTLS10,\n\t\"tls1.1\": tls.VersionTLS11,\n\t\"tls1.2\": tls.VersionTLS12,\n\t\"tls1.3\": tls.VersionTLS13,\n}\n\n// SupportedTLSVersionsToString is constant-to-string map of available TLS versions.\n//\n//nolint:gochecknoglobals\nvar SupportedTLSVersionsToString = map[TLSVersion]string{\n\ttls.VersionTLS10: \"tls1.0\",\n\ttls.VersionTLS11: \"tls1.1\",\n\ttls.VersionTLS12: \"tls1.2\",\n\ttls.VersionTLS13: \"tls1.3\",\n}\n\n// SupportedTLSCipherSuites is string-to-constant map of available TLS cipher suites.\n//\n//nolint:gochecknoglobals\nvar SupportedTLSCipherSuites = map[string]uint16{\n\t// TLS 1.0 - 1.2 cipher suites.\n\t\"TLS_RSA_WITH_RC4_128_SHA\":                tls.TLS_RSA_WITH_RC4_128_SHA,\n\t\"TLS_RSA_WITH_3DES_EDE_CBC_SHA\":           tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,\n\t\"TLS_RSA_WITH_AES_128_CBC_SHA\":            tls.TLS_RSA_WITH_AES_128_CBC_SHA,\n\t\"TLS_RSA_WITH_AES_256_CBC_SHA\":            tls.TLS_RSA_WITH_AES_256_CBC_SHA,\n\t\"TLS_RSA_WITH_AES_128_CBC_SHA256\":         tls.TLS_RSA_WITH_AES_128_CBC_SHA256,\n\t\"TLS_RSA_WITH_AES_128_GCM_SHA256\":         tls.TLS_RSA_WITH_AES_128_GCM_SHA256,\n\t\"TLS_RSA_WITH_AES_256_GCM_SHA384\":         tls.TLS_RSA_WITH_AES_256_GCM_SHA384,\n\t\"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA\":        tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,\n\t\"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\":    tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,\n\t\"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\":    tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,\n\t\"TLS_ECDHE_RSA_WITH_RC4_128_SHA\":          tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,\n\t\"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA\":     tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,\n\t\"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\":      tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,\n\t\"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\":      tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,\n\t\"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\":   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,\n\t\"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,\n\t\"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,\n\t\"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,\n\t\"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,\n\t\"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305\":    tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,\n\t\"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305\":  tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,\n\t\"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\":   tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,\n\n\t// TLS 1.3 cipher suites.\n\t\"TLS_AES_128_GCM_SHA256\":       tls.TLS_AES_128_GCM_SHA256,\n\t\"TLS_AES_256_GCM_SHA384\":       tls.TLS_AES_256_GCM_SHA384,\n\t\"TLS_CHACHA20_POLY1305_SHA256\": tls.TLS_CHACHA20_POLY1305_SHA256,\n}\n\n// SupportedTLSCipherSuitesToString is constant-to-string map of available TLS cipher suites.\n//\n//nolint:gochecknoglobals\nvar SupportedTLSCipherSuitesToString = map[uint16]string{\n\ttls.TLS_RSA_WITH_RC4_128_SHA:                \"TLS_RSA_WITH_RC4_128_SHA\",\n\ttls.TLS_RSA_WITH_3DES_EDE_CBC_SHA:           \"TLS_RSA_WITH_3DES_EDE_CBC_SHA\",\n\ttls.TLS_RSA_WITH_AES_128_CBC_SHA:            \"TLS_RSA_WITH_AES_128_CBC_SHA\",\n\ttls.TLS_RSA_WITH_AES_256_CBC_SHA:            \"TLS_RSA_WITH_AES_256_CBC_SHA\",\n\ttls.TLS_RSA_WITH_AES_128_CBC_SHA256:         \"TLS_RSA_WITH_AES_128_CBC_SHA256\",\n\ttls.TLS_RSA_WITH_AES_128_GCM_SHA256:         \"TLS_RSA_WITH_AES_128_GCM_SHA256\",\n\ttls.TLS_RSA_WITH_AES_256_GCM_SHA384:         \"TLS_RSA_WITH_AES_256_GCM_SHA384\",\n\ttls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:        \"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA\",\n\ttls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:    \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA\",\n\ttls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:    \"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA\",\n\ttls.TLS_ECDHE_RSA_WITH_RC4_128_SHA:          \"TLS_ECDHE_RSA_WITH_RC4_128_SHA\",\n\ttls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:     \"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA\",\n\ttls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:      \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA\",\n\ttls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:      \"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA\",\n\ttls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:   \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\",\n\ttls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: \"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\",\n\ttls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:   \"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\",\n\ttls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: \"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\",\n\ttls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\",\n\ttls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:    \"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305\",\n\ttls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305:  \"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305\",\n\ttls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:   \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\",\n\ttls.TLS_AES_128_GCM_SHA256:                  \"TLS_AES_128_GCM_SHA256\",\n\ttls.TLS_AES_256_GCM_SHA384:                  \"TLS_AES_256_GCM_SHA384\",\n\ttls.TLS_CHACHA20_POLY1305_SHA256:            \"TLS_CHACHA20_POLY1305_SHA256\",\n}\n"
  },
  {
    "path": "lib/types/dns.go",
    "content": "package types\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// DNSConfig is the DNS resolver configuration.\ntype DNSConfig struct {\n\t// If positive, defines how long DNS lookups should be returned from the cache.\n\tTTL null.String `json:\"ttl\"`\n\t// Select specifies the strategy to use when picking a single IP if more than one is returned for a host name.\n\tSelect NullDNSSelect `json:\"select\"`\n\t// Policy specifies how to handle returning of IPv4 or IPv6 addresses.\n\tPolicy NullDNSPolicy `json:\"policy\"`\n\t// FIXME: Valid is unused and is only added to satisfy some logic in\n\t// lib.Options.ForEachSpecified(), otherwise it would panic with\n\t// `reflect: call of reflect.Value.Bool on zero Value`.\n\tValid bool `json:\"-\"`\n}\n\n// DefaultDNSConfig returns the default DNS configuration.\nfunc DefaultDNSConfig() DNSConfig {\n\treturn DNSConfig{\n\t\tTTL:    null.NewString(\"5m\", false),\n\t\tSelect: NullDNSSelect{DNSrandom, false},\n\t\tPolicy: NullDNSPolicy{DNSpreferIPv4, false},\n\t}\n}\n\n// DNSPolicy specifies the preference for handling IP versions in DNS resolutions.\n//\n//go:generate enumer -type=DNSPolicy -trimprefix DNS -output dns_policy_gen.go\ntype DNSPolicy uint8\n\n// These are lower camel cased since enumer doesn't support it as a transform option.\n// See https://github.com/alvaroloes/enumer/pull/60 .\nconst (\n\t// DNSpreferIPv4 returns an IPv4 address if available, falling back to IPv6 otherwise.\n\tDNSpreferIPv4 DNSPolicy = iota + 1\n\t// DNSpreferIPv6 returns an IPv6 address if available, falling back to IPv4 otherwise.\n\tDNSpreferIPv6\n\t// DNSonlyIPv4 only returns an IPv4 address and the resolution will fail if no IPv4 address is found.\n\tDNSonlyIPv4\n\t// DNSonlyIPv6 only returns an IPv6 address and the resolution will fail if no IPv6 address is found.\n\tDNSonlyIPv6\n\t// DNSany returns any resolved address regardless of version.\n\tDNSany\n)\n\n// UnmarshalJSON converts JSON data to a valid DNSPolicy\nfunc (d *DNSPolicy) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(`null`)) {\n\t\treturn nil\n\t}\n\tvar s string\n\tif err := json.Unmarshal(data, &s); err != nil {\n\t\treturn err\n\t}\n\tv, err := DNSPolicyString(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*d = v\n\treturn nil\n}\n\n// MarshalJSON returns the JSON representation of d.\nfunc (d DNSPolicy) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(d.String())\n}\n\n// NullDNSPolicy is a nullable wrapper around DNSPolicy, required for the\n// current configuration system.\ntype NullDNSPolicy struct {\n\tDNSPolicy\n\tValid bool\n}\n\n// UnmarshalJSON converts JSON data to a valid NullDNSPolicy.\nfunc (d *NullDNSPolicy) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(`null`)) {\n\t\treturn nil\n\t}\n\tif err := json.Unmarshal(data, &d.DNSPolicy); err != nil {\n\t\treturn err\n\t}\n\td.Valid = true\n\treturn nil\n}\n\n// MarshalJSON returns the JSON representation of d.\nfunc (d NullDNSPolicy) MarshalJSON() ([]byte, error) {\n\tif !d.Valid {\n\t\treturn []byte(`null`), nil\n\t}\n\treturn json.Marshal(d.DNSPolicy)\n}\n\n// DNSSelect is the strategy to use when picking a single IP if more than one\n// is returned for a host name.\n//\n//go:generate enumer -type=DNSSelect -trimprefix DNS -output dns_select_gen.go\ntype DNSSelect uint8\n\n// These are lower camel cased since enumer doesn't support it as a transform option.\n// See https://github.com/alvaroloes/enumer/pull/60 .\nconst (\n\t// DNSfirst returns the first IP from the response.\n\tDNSfirst DNSSelect = iota + 1\n\t// DNSroundRobin rotates the IP returned on each lookup.\n\tDNSroundRobin\n\t// DNSrandom returns a random IP from the response.\n\tDNSrandom\n)\n\n// UnmarshalJSON converts JSON data to a valid DNSSelect\nfunc (d *DNSSelect) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(`null`)) {\n\t\treturn nil\n\t}\n\tvar s string\n\tif err := json.Unmarshal(data, &s); err != nil {\n\t\treturn err\n\t}\n\tv, err := DNSSelectString(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*d = v\n\treturn nil\n}\n\n// MarshalJSON returns the JSON representation of d.\nfunc (d DNSSelect) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(d.String())\n}\n\n// NullDNSSelect is a nullable wrapper around DNSSelect, required for the\n// current configuration system.\ntype NullDNSSelect struct {\n\tDNSSelect\n\tValid bool\n}\n\n// UnmarshalJSON converts JSON data to a valid NullDNSSelect.\nfunc (d *NullDNSSelect) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(`null`)) {\n\t\treturn nil\n\t}\n\tif err := json.Unmarshal(data, &d.DNSSelect); err != nil {\n\t\treturn err\n\t}\n\td.Valid = true\n\treturn nil\n}\n\n// MarshalJSON returns the JSON representation of d.\nfunc (d NullDNSSelect) MarshalJSON() ([]byte, error) {\n\tif !d.Valid {\n\t\treturn []byte(`null`), nil\n\t}\n\treturn json.Marshal(d.DNSSelect)\n}\n\n// String implements fmt.Stringer.\nfunc (c DNSConfig) String() string {\n\treturn fmt.Sprintf(\"ttl=%s,select=%s,policy=%s\",\n\t\tc.TTL.String, c.Select.String(), c.Policy.String())\n}\n\n// UnmarshalJSON implements json.Unmarshaler.\nfunc (c *DNSConfig) UnmarshalJSON(data []byte) error {\n\tvar s struct {\n\t\tTTL    null.String   `json:\"ttl\"`\n\t\tSelect NullDNSSelect `json:\"select\"`\n\t\tPolicy NullDNSPolicy `json:\"policy\"`\n\t}\n\tif err := json.Unmarshal(data, &s); err != nil {\n\t\treturn err\n\t}\n\tc.TTL = s.TTL\n\tc.Select = s.Select\n\tc.Policy = s.Policy\n\treturn nil\n}\n\n// UnmarshalText implements encoding.TextUnmarshaler.\nfunc (c *DNSConfig) UnmarshalText(text []byte) error {\n\tif string(text) == DefaultDNSConfig().String() {\n\t\t*c = DefaultDNSConfig()\n\t\treturn nil\n\t}\n\tvalues := strings.Split(string(text), \",\")\n\tparams := make(map[string]string, len(values))\n\tfor _, value := range values {\n\t\tk, v, _ := strings.Cut(value, \"=\")\n\t\tif v == \"\" {\n\t\t\treturn fmt.Errorf(\"no value for key %s\", value)\n\t\t}\n\t\tparams[k] = v\n\t}\n\treturn c.unmarshal(params)\n}\n\nfunc (c *DNSConfig) unmarshal(params map[string]string) error {\n\tfor k, v := range params {\n\t\tswitch k {\n\t\tcase \"policy\":\n\t\t\tp, err := DNSPolicyString(v)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tc.Policy.DNSPolicy = p\n\t\t\tc.Policy.Valid = true\n\t\tcase \"select\":\n\t\t\ts, err := DNSSelectString(v)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tc.Select.DNSSelect = s\n\t\t\tc.Select.Valid = true\n\t\tcase \"ttl\":\n\t\t\tc.TTL = null.StringFrom(v)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown DNS configuration field: %s\", k)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "lib/types/dns_policy_gen.go",
    "content": "// Code generated by \"enumer -type=DNSPolicy -trimprefix DNS -output dns_policy_gen.go\"; DO NOT EDIT.\n\npackage types\n\nimport (\n\t\"fmt\"\n)\n\nconst _DNSPolicyName = \"preferIPv4preferIPv6onlyIPv4onlyIPv6any\"\n\nvar _DNSPolicyIndex = [...]uint8{0, 10, 20, 28, 36, 39}\n\nfunc (i DNSPolicy) String() string {\n\ti -= 1\n\tif i >= DNSPolicy(len(_DNSPolicyIndex)-1) {\n\t\treturn fmt.Sprintf(\"DNSPolicy(%d)\", i+1)\n\t}\n\treturn _DNSPolicyName[_DNSPolicyIndex[i]:_DNSPolicyIndex[i+1]]\n}\n\nvar _DNSPolicyValues = []DNSPolicy{1, 2, 3, 4, 5}\n\nvar _DNSPolicyNameToValueMap = map[string]DNSPolicy{\n\t_DNSPolicyName[0:10]:  1,\n\t_DNSPolicyName[10:20]: 2,\n\t_DNSPolicyName[20:28]: 3,\n\t_DNSPolicyName[28:36]: 4,\n\t_DNSPolicyName[36:39]: 5,\n}\n\n// DNSPolicyString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc DNSPolicyString(s string) (DNSPolicy, error) {\n\tif val, ok := _DNSPolicyNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to DNSPolicy values\", s)\n}\n\n// DNSPolicyValues returns all values of the enum\nfunc DNSPolicyValues() []DNSPolicy {\n\treturn _DNSPolicyValues\n}\n\n// IsADNSPolicy returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i DNSPolicy) IsADNSPolicy() bool {\n\tfor _, v := range _DNSPolicyValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "lib/types/dns_select_gen.go",
    "content": "// Code generated by \"enumer -type=DNSSelect -trimprefix DNS -output dns_select_gen.go\"; DO NOT EDIT.\n\npackage types\n\nimport (\n\t\"fmt\"\n)\n\nconst _DNSSelectName = \"firstroundRobinrandom\"\n\nvar _DNSSelectIndex = [...]uint8{0, 5, 15, 21}\n\nfunc (i DNSSelect) String() string {\n\ti -= 1\n\tif i >= DNSSelect(len(_DNSSelectIndex)-1) {\n\t\treturn fmt.Sprintf(\"DNSSelect(%d)\", i+1)\n\t}\n\treturn _DNSSelectName[_DNSSelectIndex[i]:_DNSSelectIndex[i+1]]\n}\n\nvar _DNSSelectValues = []DNSSelect{1, 2, 3}\n\nvar _DNSSelectNameToValueMap = map[string]DNSSelect{\n\t_DNSSelectName[0:5]:   1,\n\t_DNSSelectName[5:15]:  2,\n\t_DNSSelectName[15:21]: 3,\n}\n\n// DNSSelectString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc DNSSelectString(s string) (DNSSelect, error) {\n\tif val, ok := _DNSSelectNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to DNSSelect values\", s)\n}\n\n// DNSSelectValues returns all values of the enum\nfunc DNSSelectValues() []DNSSelect {\n\treturn _DNSSelectValues\n}\n\n// IsADNSSelect returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i DNSSelect) IsADNSSelect() bool {\n\tfor _, v := range _DNSSelectValues {\n\t\tif i == v {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "lib/types/hostnametrie.go",
    "content": "package types\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n// NullHostnameTrie is a nullable HostnameTrie, in the same vein as the nullable types provided by\n// package gopkg.in/guregu/null.v3\ntype NullHostnameTrie struct {\n\tTrie  *HostnameTrie\n\tValid bool\n}\n\n// UnmarshalText converts text data to a valid NullHostnameTrie\nfunc (d *NullHostnameTrie) UnmarshalText(data []byte) error {\n\tif len(data) == 0 {\n\t\t*d = NullHostnameTrie{}\n\t\treturn nil\n\t}\n\tvar err error\n\td.Trie, err = NewHostnameTrie(strings.Split(string(data), \",\"))\n\tif err != nil {\n\t\treturn err\n\t}\n\td.Valid = true\n\treturn nil\n}\n\n// UnmarshalJSON converts JSON data to a valid NullHostnameTrie\nfunc (d *NullHostnameTrie) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(`null`)) {\n\t\td.Valid = false\n\t\treturn nil\n\t}\n\n\tvar m []string\n\tvar err error\n\tif err = json.Unmarshal(data, &m); err != nil {\n\t\treturn err\n\t}\n\td.Trie, err = NewHostnameTrie(m)\n\tif err != nil {\n\t\treturn err\n\t}\n\td.Valid = true\n\treturn nil\n}\n\n// Source returns source hostnames that were used during construction.\nfunc (d *NullHostnameTrie) Source() []string {\n\tif d.Trie == nil {\n\t\treturn []string{}\n\t}\n\n\treturn d.Trie.source\n}\n\n// MarshalJSON implements json.Marshaler interface\nfunc (d NullHostnameTrie) MarshalJSON() ([]byte, error) {\n\tif !d.Valid {\n\t\treturn []byte(`null`), nil\n\t}\n\treturn json.Marshal(d.Trie.source)\n}\n\n// HostnameTrie is a tree-structured list of hostname matches with support\n// for wildcards exclusively at the start of the pattern. Items may only\n// be inserted and searched. Internationalized hostnames are valid.\ntype HostnameTrie struct {\n\t*trieNode\n\tsource []string\n}\n\n// NewNullHostnameTrie returns a NullHostnameTrie encapsulating HostnameTrie or an error if the\n// input is incorrect\nfunc NewNullHostnameTrie(source []string) (NullHostnameTrie, error) {\n\th, err := NewHostnameTrie(source)\n\tif err != nil {\n\t\treturn NullHostnameTrie{}, err\n\t}\n\treturn NullHostnameTrie{\n\t\tValid: true,\n\t\tTrie:  h,\n\t}, nil\n}\n\n// NewHostnameTrie returns a pointer to a new HostnameTrie or an error if the input is incorrect\nfunc NewHostnameTrie(source []string) (*HostnameTrie, error) {\n\th := &HostnameTrie{\n\t\tsource: source,\n\t\ttrieNode: &trieNode{\n\t\t\tisLeaf:   false,\n\t\t\tchildren: make(map[rune]*trieNode),\n\t\t},\n\t}\n\tfor _, s := range h.source {\n\t\tif err := h.insert(s); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\treturn h, nil\n}\n\n// Regex description of hostname pattern to enforce blocks by.\n// Global var to avoid compilation penalty at runtime.\n// Based on regex from https://stackoverflow.com/a/106223/5427244\n//\n//nolint:lll\nvar validHostnamePattern = regexp.MustCompile(`^(\\*\\.?)?((([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9]))?$`)\n\nfunc isValidHostnamePattern(s string) error {\n\tif len(validHostnamePattern.FindString(s)) != len(s) {\n\t\treturn fmt.Errorf(\"invalid hostname pattern '%s'\", s)\n\t}\n\treturn nil\n}\n\n// insert inserts a hostname pattern into the HostnameTrie. It returns an error\n// if the hostname pattern is invalid.\nfunc (t *HostnameTrie) insert(s string) error {\n\ts = strings.ToLower(s)\n\tif err := isValidHostnamePattern(s); err != nil {\n\t\treturn err\n\t}\n\n\tt.trieNode.insert(s)\n\treturn nil\n}\n\n// Contains returns whether s matches a pattern in the HostnameTrie\n// along with the matching pattern, if one was found.\nfunc (t *HostnameTrie) Contains(s string) (matchedPattern string, matchFound bool) {\n\ts = strings.ToLower(s)\n\treturn t.contains(s)\n}\n"
  },
  {
    "path": "lib/types/hostnametrie_test.go",
    "content": "package types\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestHostnameTrieInsert(t *testing.T) {\n\tt.Parallel()\n\n\thostnames, err := NewHostnameTrie([]string{\"foo.bar\"})\n\tassert.NoError(t, err)\n\n\tassert.NoError(t, hostnames.insert(\"test.k6.io\"))\n\tassert.Error(t, hostnames.insert(\"inval*d.pattern\"))\n\tassert.NoError(t, hostnames.insert(\"*valid.pattern\"))\n}\n\nfunc TestHostnameTrieContains(t *testing.T) {\n\tt.Parallel()\n\n\ttrie, err := NewHostnameTrie([]string{\"sub.test.k6.io\", \"test.k6.io\", \"*valid.pattern\", \"sub.valid.pattern\"})\n\trequire.NoError(t, err)\n\tcases := map[string]string{\n\t\t\"K6.Io\":                 \"\",\n\t\t\"tEsT.k6.Io\":            \"test.k6.io\",\n\t\t\"TESt.K6.IO\":            \"test.k6.io\",\n\t\t\"sub.test.k6.io\":        \"sub.test.k6.io\",\n\t\t\"sub.sub.test.k6.io\":    \"\",\n\t\t\"blocked.valId.paTtern\": \"*valid.pattern\",\n\t\t\"valId.paTtern\":         \"*valid.pattern\",\n\t\t\"sub.valid.pattern\":     \"sub.valid.pattern\", // use the most specific blocker\n\t\t\"www.sub.valid.pattern\": \"*valid.pattern\",\n\t\t\"example.test.k6.io\":    \"\",\n\t}\n\tfor key, value := range cases {\n\t\thost, pattern := key, value\n\t\tt.Run(host, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tmatch, matches := trie.Contains(host)\n\t\t\tif pattern == \"\" {\n\t\t\t\tassert.False(t, matches)\n\t\t\t\tassert.Empty(t, match)\n\t\t\t} else {\n\t\t\t\tassert.True(t, matches)\n\t\t\t\tassert.Equal(t, pattern, match)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestNullHostnameTrieSource(t *testing.T) {\n\tt.Parallel()\n\n\ttrie, err := NewNullHostnameTrie([]string{\"sub.test.k6.io\", \"test.k6.io\", \"*valid.pattern\", \"sub.valid.pattern\"})\n\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, []string{\"sub.test.k6.io\", \"test.k6.io\", \"*valid.pattern\", \"sub.valid.pattern\"}, trie.Source())\n}\n"
  },
  {
    "path": "lib/types/hosts.go",
    "content": "package types\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst nullJSON = \"null\"\n\n// NullHosts is a wrapper around Hosts like guregu/null\ntype NullHosts struct {\n\tTrie  *Hosts\n\tValid bool\n}\n\n// NewNullHosts returns valid (Valid: true) Hosts\nfunc NewNullHosts(source map[string]Host) (NullHosts, error) {\n\thosts, err := NewHosts(source)\n\tif err != nil {\n\t\treturn NullHosts{}, err\n\t}\n\n\treturn NullHosts{\n\t\tTrie:  hosts,\n\t\tValid: true,\n\t}, nil\n}\n\n// MarshalJSON converts NullHosts to valid JSON\nfunc (n NullHosts) MarshalJSON() ([]byte, error) {\n\tif !n.Valid {\n\t\treturn []byte(nullJSON), nil\n\t}\n\n\tjsonMap := make(map[string]string)\n\tfor k, v := range n.Trie.source {\n\t\tvar right string\n\t\tif v.Port != 0 {\n\t\t\tright = v.String()\n\t\t} else {\n\t\t\tright = v.IP.String()\n\t\t}\n\t\tjsonMap[k] = right\n\t}\n\n\treturn json.Marshal(jsonMap)\n}\n\n// UnmarshalJSON converts JSON to NullHosts\nfunc (n *NullHosts) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(nullJSON)) {\n\t\tn.Trie = nil\n\t\tn.Valid = false\n\t\treturn nil\n\t}\n\n\tjsonSource := make(map[string]string)\n\tif err := json.Unmarshal(data, &jsonSource); err != nil {\n\t\treturn err\n\t}\n\n\tsource := make(map[string]Host)\n\tfor k, v := range jsonSource {\n\t\tip, port, err := net.SplitHostPort(v)\n\t\tif err == nil {\n\t\t\tpInt, err := strconv.Atoi(port)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tsource[k] = Host{IP: net.ParseIP(ip), Port: pInt}\n\t\t} else {\n\t\t\tsource[k] = Host{IP: net.ParseIP(v)}\n\t\t}\n\t}\n\n\thosts, err := NewHosts(source)\n\tif err != nil {\n\t\treturn err\n\t}\n\tn.Trie = hosts\n\tn.Valid = true\n\treturn nil\n}\n\n// Hosts is wrapper around trieNode to integrate with net.TCPAddr\ntype Hosts struct {\n\tn      *trieNode\n\tsource map[string]Host\n}\n\n// NewHosts returns new Hosts from given addresses.\nfunc NewHosts(source map[string]Host) (*Hosts, error) {\n\th := &Hosts{\n\t\tsource: toLowerKeys(source),\n\t\tn: &trieNode{\n\t\t\tchildren: make(map[rune]*trieNode),\n\t\t},\n\t}\n\n\tfor k := range h.source {\n\t\terr := h.insert(k)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn h, nil\n}\n\nfunc toLowerKeys(source map[string]Host) map[string]Host {\n\tresult := make(map[string]Host, len(source))\n\tfor k, v := range source {\n\t\tresult[strings.ToLower(k)] = v\n\t}\n\treturn result\n}\n\n// Regex description of domain(:port)? pattern to enforce blocks by.\n// Global var to avoid compilation penalty at runtime.\n// Based on regex from https://stackoverflow.com/a/106223/5427244\n//\n//nolint:lll\nvar validHostPattern = regexp.MustCompile(`^(\\*\\.?)?((([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9]))?(:[0-9]{1,5})?$`)\n\nfunc isValidHostPattern(s string) error {\n\tif len(validHostPattern.FindString(s)) != len(s) {\n\t\treturn fmt.Errorf(\"invalid host pattern '%s'\", s)\n\t}\n\treturn nil\n}\n\nfunc (t *Hosts) insert(s string) error {\n\ts = strings.ToLower(s) // domains are not case-sensitive\n\n\tif err := isValidHostPattern(s); err != nil {\n\t\treturn err\n\t}\n\n\tt.n.insert(s)\n\n\treturn nil\n}\n\n// Match returns the host matching s, where the value can be one of:\n// - nil (no match)\n// - IP:0 (Only IP match, record does not have port information)\n// - IP:Port\nfunc (t *Hosts) Match(s string) *Host {\n\ts = strings.ToLower(s)\n\tmatch, ok := t.n.contains(s)\n\n\tif !ok {\n\t\treturn nil\n\t}\n\n\taddress := t.source[match]\n\n\treturn &address\n}\n"
  },
  {
    "path": "lib/types/hosts_test.go",
    "content": "package types\n\nimport (\n\t\"encoding/json\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nconst (\n\t// Below 4 are port combinations of hostname to Host matching, all checks true condition\n\tSamePortMapping      = \"same port mapping exists, and it should map\"\n\tEmptyPortMapping     = \"no port given in mapping but hostname exists, it should map\"\n\tNotGivenPortMapping  = \"given port mapping does not exist, it should not map\"\n\tDifferentPortMapping = \"different port mapping exists, and it should map\"\n\t// General not existing scenario\n\tNotInHosts = \"mapping should not exists in hosts\"\n\n\tExactMatch       = \"exact match should happen\"\n\tFallBackWildcard = \"should fallback to wildcard\"\n\t// This value is for checking the below scenario.\n\t// Let's say Hosts contains two values:\n\t// 1. *.foo.io\n\t// 2. specific.foo.io\n\t//\n\t// When not.specific.foo.io is dialed, it passes three steps:\n\t// 1. It matches *.foo.io, but continues for exact matching\n\t// 2. It matches specific.foo.io, but continues for exact matching\n\t// 3. Encounters that not.specific.foo.io does not exist in trie, and fallbacks to the wildcard (step 1)\n\tFallBackWildcardEvenMatch = \"fallback to wildcard, even after exact match\"\n)\n\ntype HostTestCase struct {\n\thostname, expVal, desc string\n}\n\nfunc TestHosts(t *testing.T) {\n\tt.Parallel()\n\n\thosts, err := NewHosts(map[string]Host{\n\t\t// IPv4\n\t\t\"simple.io\":              {IP: net.ParseIP(\"1.2.3.4\")},\n\t\t\"simple.io:80\":           {IP: net.ParseIP(\"1.2.3.4\"), Port: 80},\n\t\t\"simple.io:443\":          {IP: net.ParseIP(\"1.2.3.4\"), Port: 8443},\n\t\t\"only-port.io:443\":       {IP: net.ParseIP(\"5.6.7.8\"), Port: 8443},\n\t\t\"*.wildcard.io\":          {IP: net.ParseIP(\"9.10.11.12\")},\n\t\t\"specific.wildcard.io\":   {IP: net.ParseIP(\"90.100.110.120\")},\n\t\t\"*wildcard-2.io\":         {IP: net.ParseIP(\"13.14.15.16\")},\n\t\t\"specific.wildcard-2.io\": {IP: net.ParseIP(\"130.140.150.160\")},\n\t\t\"with-UPPER-case.io\":     {IP: net.ParseIP(\"17.18.19.20\")},\n\n\t\t// IPv6\n\t\t\"simple-ipv6.io\":              {IP: net.ParseIP(\"aa::bb\")},\n\t\t\"simple-ipv6.io:80\":           {IP: net.ParseIP(\"aa::bb\"), Port: 80},\n\t\t\"simple-ipv6.io:443\":          {IP: net.ParseIP(\"aa::bb\"), Port: 8443},\n\t\t\"only-port-ipv6.io:443\":       {IP: net.ParseIP(\"cc::dd\"), Port: 8443},\n\t\t\"*.wildcard-ipv6.io\":          {IP: net.ParseIP(\"ee::ff\")},\n\t\t\"specific.wildcard-ipv6.io\":   {IP: net.ParseIP(\"ee:11::ff\")},\n\t\t\"*wildcard-2-ipv6.io\":         {IP: net.ParseIP(\"aa::aa\")},\n\t\t\"specific.wildcard-2-ipv6.io\": {IP: net.ParseIP(\"a1::a1\")},\n\t})\n\n\trequire.NoError(t, err)\n\n\tt.Run(\"ipv4\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"no trie functionality, simple checks\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttcs := []HostTestCase{\n\t\t\t\t{\"simple.io\", \"1.2.3.4:0\", EmptyPortMapping},\n\t\t\t\t{\"simple.io:80\", \"1.2.3.4:80\", SamePortMapping},\n\t\t\t\t{\"simple.io:443\", \"1.2.3.4:8443\", DifferentPortMapping},\n\t\t\t\t{\"simple.io:9999\", \"\", NotGivenPortMapping},\n\t\t\t\t{\"only-port.io\", \"\", NotInHosts},\n\t\t\t\t{\"only-port.io:443\", \"5.6.7.8:8443\", DifferentPortMapping},\n\t\t\t\t{\"only-port.io:9999\", \"\", NotGivenPortMapping},\n\t\t\t\t{\"with-upper-case.io\", \"17.18.19.20:0\", EmptyPortMapping},\n\t\t\t\t{\"with-UPPER-case.io\", \"17.18.19.20:0\", EmptyPortMapping},\n\t\t\t}\n\t\t\trunTcs(t, hosts, tcs)\n\t\t})\n\n\t\tt.Run(\"trie functionality\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tt.Run(\"*.sub usage\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttcs := []HostTestCase{\n\t\t\t\t\t{\"foo.wildcard.io\", \"9.10.11.12:0\", FallBackWildcard},\n\t\t\t\t\t{\"specific.wildcard.io\", \"90.100.110.120:0\", ExactMatch},\n\t\t\t\t\t{\"not.specific.wildcard.io\", \"9.10.11.12:0\", FallBackWildcardEvenMatch},\n\t\t\t\t}\n\t\t\t\trunTcs(t, hosts, tcs)\n\t\t\t})\n\n\t\t\tt.Run(\"*sub usage\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttcs := []HostTestCase{\n\t\t\t\t\t{\"wildcard-2.io\", \"13.14.15.16:0\", ExactMatch},\n\t\t\t\t\t{\"foo.wildcard-2.io\", \"13.14.15.16:0\", FallBackWildcard},\n\t\t\t\t\t{\"prefixwildcard-2.io\", \"13.14.15.16:0\", FallBackWildcard},\n\t\t\t\t\t{\"specific.wildcard-2.io\", \"130.140.150.160:0\", ExactMatch},\n\t\t\t\t\t{\"not.specific.wildcard-2.io\", \"13.14.15.16:0\", FallBackWildcardEvenMatch},\n\t\t\t\t}\n\t\t\t\trunTcs(t, hosts, tcs)\n\t\t\t})\n\t\t})\n\t})\n\n\tt.Run(\"ipv6\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tt.Run(\"no trie functionality, simple checks\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\ttcs := []HostTestCase{\n\t\t\t\t{\"simple-ipv6.io\", \"[aa::bb]:0\", EmptyPortMapping},\n\t\t\t\t{\"simple-ipv6.io:80\", \"[aa::bb]:80\", SamePortMapping},\n\t\t\t\t{\"simple-ipv6.io:443\", \"[aa::bb]:8443\", DifferentPortMapping},\n\t\t\t\t{\"simple-ipv6.io:9999\", \"\", NotGivenPortMapping},\n\t\t\t\t{\"only-port-ipv6.io\", \"\", NotInHosts},\n\t\t\t\t{\"only-port-ipv6.io:443\", \"[cc::dd]:8443\", DifferentPortMapping},\n\t\t\t\t{\"only-port-ipv6.io:9999\", \"\", NotGivenPortMapping},\n\t\t\t}\n\t\t\trunTcs(t, hosts, tcs)\n\t\t})\n\n\t\tt.Run(\"trie functionality\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tt.Run(\"*.sub usage\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttcs := []HostTestCase{\n\t\t\t\t\t{\"foo.wildcard-ipv6.io\", \"[ee::ff]:0\", FallBackWildcard},\n\t\t\t\t\t{\"specific.wildcard-ipv6.io\", \"[ee:11::ff]:0\", ExactMatch},\n\t\t\t\t\t{\"not.specific.wildcard-ipv6.io\", \"[ee::ff]:0\", FallBackWildcardEvenMatch},\n\t\t\t\t}\n\t\t\t\trunTcs(t, hosts, tcs)\n\t\t\t})\n\n\t\t\tt.Run(\"*sub usage\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttcs := []HostTestCase{\n\t\t\t\t\t{\"wildcard-2-ipv6.io\", \"[aa::aa]:0\", ExactMatch},\n\t\t\t\t\t{\"foo.wildcard-2-ipv6.io\", \"[aa::aa]:0\", FallBackWildcard},\n\t\t\t\t\t{\"prefixwildcard-2-ipv6.io\", \"[aa::aa]:0\", FallBackWildcard},\n\t\t\t\t\t{\"specific.wildcard-2-ipv6.io\", \"[a1::a1]:0\", ExactMatch},\n\t\t\t\t\t{\"not.specific.wildcard-2-ipv6.io\", \"[aa::aa]:0\", FallBackWildcardEvenMatch},\n\t\t\t\t}\n\t\t\t\trunTcs(t, hosts, tcs)\n\t\t\t})\n\t\t})\n\t})\n\n\tt.Run(\"edge cases\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttcs := []HostTestCase{\n\t\t\t{\"does-not-exists\", \"\", \"simple not existing\"},\n\t\t\t{\"veeeeeeeeeeeery.veeeeeeeery.loooooooooooooooooooooooooooooooooooong-does-not-exist\", \"\", \"long hostname to check end of trie\"},\n\t\t\t{\"\", \"\", \"empty hostname should return empty host\"},\n\t\t\t{\"*\", \"\", \"no match should happen\"},\n\t\t\t{\"*********************\", \"\", \"no match should happen\"},\n\t\t}\n\t\trunTcs(t, hosts, tcs)\n\t})\n}\n\n// runTcs is utility function for testing HostTestCase slice\nfunc runTcs(t *testing.T, at *Hosts, tcs []HostTestCase) {\n\tfor _, tc := range tcs {\n\t\tt.Run(tc.desc+\"-\"+tc.hostname, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\taddr := at.Match(tc.hostname)\n\n\t\t\tif tc.expVal != \"\" {\n\t\t\t\trequire.NotNil(t, addr)\n\t\t\t\trequire.Equal(t, tc.expVal, addr.String())\n\t\t\t} else {\n\t\t\t\trequire.Nil(t, addr)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestHostsJSON(t *testing.T) {\n\tt.Parallel()\n\n\thosts, err := NewNullHosts(map[string]Host{\n\t\t\"example.com\":           {IP: net.ParseIP(\"1.2.3.4\"), Port: 0},\n\t\t\"example-port.com\":      {IP: net.ParseIP(\"5.6.7.8\"), Port: 443},\n\t\t\"example-ipv6.com\":      {IP: net.ParseIP(\"aa::bb\"), Port: 0},\n\t\t\"example-port-ipv6.com\": {IP: net.ParseIP(\"cc::dd\"), Port: 443},\n\t})\n\trequire.NoError(t, err)\n\n\ttcs := []struct {\n\t\tt       NullHosts\n\t\tmarshal string\n\t}{\n\t\t{t: NullHosts{}, marshal: nullJSON},\n\t\t{\n\t\t\tt: hosts, marshal: `\n{\n\t\"example.com\":\"1.2.3.4\",\n\t\"example-port.com\":\"5.6.7.8:443\",\n\t\"example-ipv6.com\":\"aa::bb\",\n\t\"example-port-ipv6.com\":\"[cc::dd]:443\"\n}`,\n\t\t},\n\t}\n\n\tt.Run(\"Marshall\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor _, tc := range tcs {\n\t\t\tt.Run(tc.marshal, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tm, err := json.Marshal(tc.t)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.JSONEq(t, tc.marshal, string(m))\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"Unmarshall\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor _, tc := range tcs {\n\t\t\tt.Run(tc.marshal, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar trie NullHosts\n\t\t\t\terr := json.Unmarshal([]byte(tc.marshal), &trie)\n\t\t\t\trequire.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.t, trie)\n\t\t\t})\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "lib/types/ipblock.go",
    "content": "package types\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"net\"\n\t\"strings\"\n)\n\n// ipBlock represents a continuous segment of IP addresses\ntype ipBlock struct {\n\tfirstIP, count *big.Int\n\tipv6           bool\n}\n\n// ipPoolBlock is similar to ipBlock but instead of knowing its count/size it knows the first index\n// from which it starts in an IPPool\ntype ipPoolBlock struct {\n\tfirstIP, startIndex *big.Int\n}\n\n// IPPool represent a slice of IPBlocks\ntype IPPool struct {\n\tlist  []ipPoolBlock\n\tcount *big.Int\n}\n\nfunc getIPBlock(s string) (*ipBlock, error) {\n\tswitch {\n\tcase strings.Contains(s, \"-\"):\n\t\treturn ipBlockFromRange(s)\n\tcase strings.Contains(s, \"/\"):\n\t\treturn ipBlockFromCIDR(s)\n\tdefault:\n\t\tif net.ParseIP(s) == nil {\n\t\t\treturn nil, fmt.Errorf(\"%s is not a valid IP, IP range or CIDR\", s)\n\t\t}\n\t\treturn ipBlockFromRange(s + \"-\" + s)\n\t}\n}\n\nfunc ipBlockFromRange(s string) (*ipBlock, error) {\n\tip0Str, ip1Str, _ := strings.Cut(s, \"-\")\n\tip0, ip1 := net.ParseIP(ip0Str), net.ParseIP(ip1Str)\n\tif ip0 == nil || ip1 == nil {\n\t\treturn nil, errors.New(\"wrong IP range format: \" + s)\n\t}\n\tif (ip0.To4() == nil) != (ip1.To4() == nil) { // XOR\n\t\treturn nil, errors.New(\"mixed IP range format: \" + s)\n\t}\n\tblock := ipBlockFromTwoIPs(ip0, ip1)\n\n\tif block.count.Sign() <= 0 {\n\t\treturn nil, errors.New(\"negative IP range: \" + s)\n\t}\n\treturn block, nil\n}\n\nfunc ipBlockFromTwoIPs(ip0, ip1 net.IP) *ipBlock {\n\t// This code doesn't do any checks on the validity of the arguments, that should be\n\t// done before and/or after it is called\n\tvar block ipBlock\n\tblock.firstIP = new(big.Int)\n\tblock.count = new(big.Int)\n\tblock.ipv6 = ip0.To4() == nil\n\tif block.ipv6 {\n\t\tblock.firstIP.SetBytes(ip0.To16())\n\t\tblock.count.SetBytes(ip1.To16())\n\t} else {\n\t\tblock.firstIP.SetBytes(ip0.To4())\n\t\tblock.count.SetBytes(ip1.To4())\n\t}\n\tblock.count.Sub(block.count, block.firstIP)\n\tblock.count.Add(block.count, big.NewInt(1))\n\n\treturn &block\n}\n\nfunc ipBlockFromCIDR(s string) (*ipBlock, error) {\n\t_, pnet, err := net.ParseCIDR(s)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parseCIDR() failed parsing %s: %w\", s, err)\n\t}\n\tip0 := pnet.IP\n\t// TODO: this is just to copy it, it will probably be better to copy the bytes ...\n\tip1 := net.ParseIP(ip0.String())\n\tif ip1.To4() == nil {\n\t\tip1 = ip1.To16()\n\t} else {\n\t\tip1 = ip1.To4()\n\t}\n\tfor i := range ip1 {\n\t\tip1[i] |= (255 ^ pnet.Mask[i])\n\t}\n\tblock := ipBlockFromTwoIPs(ip0, ip1)\n\t// in the case of ipv4 if the network is bigger than 31 the first and last IP are reserved so we\n\t// need to reduce the addresses by 2 and increment the first ip\n\tif !block.ipv6 && big.NewInt(2).Cmp(block.count) < 0 {\n\t\tblock.count.Sub(block.count, big.NewInt(2))\n\t\tblock.firstIP.Add(block.firstIP, big.NewInt(1))\n\t}\n\treturn block, nil\n}\n\nfunc (b ipPoolBlock) getIP(index *big.Int) net.IP {\n\t// TODO implement walking ipv6 networks first\n\t// that will probably require more math ... including knowing which is the next network and ...\n\t// thinking about it - it looks like it's going to be kind of hard or badly defined\n\ti := new(big.Int)\n\ti.Add(b.firstIP, index)\n\t// TODO use big.Int.FillBytes when golang 1.14 is no longer supported\n\treturn net.IP(i.Bytes())\n}\n\n// NewIPPool returns an IPPool slice from the provided string representation that should be comma\n// separated list of IPs, IP ranges(ip1-ip2) and CIDRs\nfunc NewIPPool(ranges string) (*IPPool, error) {\n\tss := strings.Split(ranges, \",\")\n\tpool := &IPPool{}\n\tpool.list = make([]ipPoolBlock, len(ss))\n\tpool.count = new(big.Int)\n\tfor i, bs := range ss {\n\t\tr, err := getIPBlock(bs)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tpool.list[i] = ipPoolBlock{\n\t\t\tfirstIP:    r.firstIP,\n\t\t\tstartIndex: new(big.Int).Set(pool.count), // this is how many there are until now\n\t\t}\n\t\tpool.count.Add(pool.count, r.count)\n\t}\n\n\t// The list gets reversed here as later it is searched based on when the index we are looking is\n\t// bigger than startIndex but it will be true always for the first block which is with\n\t// startIndex 0. This can also be fixed by iterating in reverse but this seems better\n\tfor i := 0; i < len(pool.list)/2; i++ {\n\t\tpool.list[i], pool.list[len(pool.list)-1-i] = pool.list[len(pool.list)-1-i], pool.list[i]\n\t}\n\treturn pool, nil\n}\n\n// GetIP return an IP from a pool of IPBlock slice\nfunc (pool *IPPool) GetIP(index uint64) net.IP {\n\treturn pool.GetIPBig(new(big.Int).SetUint64(index))\n}\n\n// GetIPBig returns an IP from the pool with the provided index that is big.Int\nfunc (pool *IPPool) GetIPBig(index *big.Int) net.IP {\n\tindex = new(big.Int).Rem(index, pool.count)\n\tfor _, b := range pool.list {\n\t\tif index.Cmp(b.startIndex) >= 0 {\n\t\t\treturn b.getIP(index.Sub(index, b.startIndex))\n\t\t}\n\t}\n\treturn nil\n}\n\n// NullIPPool is a nullable IPPool\ntype NullIPPool struct {\n\tPool  *IPPool\n\tValid bool\n\traw   []byte\n}\n\n// UnmarshalText converts text data to a valid NullIPPool\nfunc (n *NullIPPool) UnmarshalText(data []byte) error {\n\tif len(data) == 0 {\n\t\t*n = NullIPPool{}\n\t\treturn nil\n\t}\n\tvar err error\n\tn.Pool, err = NewIPPool(string(data))\n\tif err != nil {\n\t\treturn err\n\t}\n\tn.Valid = true\n\tn.raw = data\n\treturn nil\n}\n\n// MarshalText returns the IPs pool in text form\nfunc (n *NullIPPool) MarshalText() ([]byte, error) {\n\treturn n.raw, nil\n}\n"
  },
  {
    "path": "lib/types/ipblock_test.go",
    "content": "package types\n\nimport (\n\t\"math/big\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc get128BigInt(hi, lo int64) *big.Int {\n\tmax64 := new(big.Int).Exp(big.NewInt(2), big.NewInt(64), nil)\n\th := big.NewInt(hi)\n\th.Mul(h, max64)\n\treturn h.Add(h, big.NewInt(lo))\n}\n\nfunc TestIpBlock(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]struct {\n\t\tcount           *big.Int\n\t\tfirstIP, lastIP net.IP\n\t}{\n\t\t\"192.168.0.101\": {new(big.Int).SetInt64(1), net.ParseIP(\"192.168.0.101\"), net.ParseIP(\"192.168.0.101\")},\n\n\t\t\"192.168.0.101-192.168.0.200\":    {new(big.Int).SetInt64(100), net.ParseIP(\"192.168.0.101\"), net.ParseIP(\"192.168.0.200\")},\n\t\t\"192.168.0.100-192.168.0.200\":    {new(big.Int).SetInt64(101), net.ParseIP(\"192.168.0.100\"), net.ParseIP(\"192.168.0.200\")},\n\t\t\"fd00:1:1:0::0-fd00:1:1:ff::3ff\": {get128BigInt(255, 1024), net.ParseIP(\"fd00:1:1:0::0\"), net.ParseIP(\"fd00:1:1:ff::3ff\")},\n\t\t\"fd00:1:1:2::1-fd00:1:1:ff::3ff\": {get128BigInt(253, 1023), net.ParseIP(\"fd00:1:1:2::1\"), net.ParseIP(\"fd00:1:1:ff::3ff\")},\n\n\t\t\"192.168.0.0/16\":  {get128BigInt(0, 65534), net.ParseIP(\"192.168.0.1\"), net.ParseIP(\"192.168.255.254\")},\n\t\t\"192.168.0.1/16\":  {get128BigInt(0, 65534), net.ParseIP(\"192.168.0.1\"), net.ParseIP(\"192.168.255.254\")},\n\t\t\"192.168.0.10/16\": {get128BigInt(0, 65534), net.ParseIP(\"192.168.0.1\"), net.ParseIP(\"192.168.255.254\")},\n\t\t\"192.168.0.10/31\": {get128BigInt(0, 2), net.ParseIP(\"192.168.0.10\"), net.ParseIP(\"192.168.0.11\")},\n\t\t\"192.168.0.10/32\": {get128BigInt(0, 1), net.ParseIP(\"192.168.0.10\"), net.ParseIP(\"192.168.0.10\")},\n\t\t\"fd00::0/120\":     {get128BigInt(0, 256), net.ParseIP(\"fd00::0\"), net.ParseIP(\"fd00::ff\")},\n\t\t\"fd00::1/120\":     {get128BigInt(0, 256), net.ParseIP(\"fd00::0\"), net.ParseIP(\"fd00::ff\")},\n\t\t\"fd00::3/120\":     {get128BigInt(0, 256), net.ParseIP(\"fd00::0\"), net.ParseIP(\"fd00::ff\")},\n\t\t\"fd00::0/112\":     {get128BigInt(0, 65536), net.ParseIP(\"fd00::0\"), net.ParseIP(\"fd00::ffff\")},\n\t\t\"fd00::1/112\":     {get128BigInt(0, 65536), net.ParseIP(\"fd00::0\"), net.ParseIP(\"fd00::ffff\")},\n\t\t\"fd00::2/112\":     {get128BigInt(0, 65536), net.ParseIP(\"fd00::0\"), net.ParseIP(\"fd00::ffff\")},\n\t}\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tb, err := getIPBlock(name)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, data.count, b.count)\n\t\t\tpb := ipPoolBlock{firstIP: b.firstIP}\n\t\t\tidx := big.NewInt(0)\n\t\t\tassert.Equal(t, data.firstIP.To16(), pb.getIP(idx).To16())\n\t\t\tidx.Sub(idx.Add(idx, b.count), big.NewInt(1))\n\t\t\tassert.Equal(t, data.lastIP.To16(), pb.getIP(idx).To16())\n\t\t})\n\t}\n}\n\nfunc TestIPPool(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]struct {\n\t\tcount   *big.Int\n\t\tqueries map[uint64]net.IP\n\t}{\n\t\t\"192.168.0.101\": {\n\t\t\tcount:   new(big.Int).SetInt64(1),\n\t\t\tqueries: map[uint64]net.IP{0: net.ParseIP(\"192.168.0.101\"), 12: net.ParseIP(\"192.168.0.101\")},\n\t\t},\n\t\t\"192.168.0.101,192.168.0.102\": {\n\t\t\tcount: new(big.Int).SetInt64(2),\n\t\t\tqueries: map[uint64]net.IP{\n\t\t\t\t0:  net.ParseIP(\"192.168.0.101\"),\n\t\t\t\t1:  net.ParseIP(\"192.168.0.102\"),\n\t\t\t\t12: net.ParseIP(\"192.168.0.101\"),\n\t\t\t\t13: net.ParseIP(\"192.168.0.102\"),\n\t\t\t},\n\t\t},\n\t\t\"192.168.0.101-192.168.0.105,fd00::2/112\": {\n\t\t\tcount: new(big.Int).SetInt64(65541),\n\t\t\tqueries: map[uint64]net.IP{\n\t\t\t\t0:     net.ParseIP(\"192.168.0.101\"),\n\t\t\t\t1:     net.ParseIP(\"192.168.0.102\"),\n\t\t\t\t5:     net.ParseIP(\"fd00::0\"),\n\t\t\t\t6:     net.ParseIP(\"fd00::1\"),\n\t\t\t\t65541: net.ParseIP(\"192.168.0.101\"),\n\t\t\t},\n\t\t},\n\n\t\t\"192.168.0.101,192.168.0.102,192.168.0.103,192.168.0.104,192.168.0.105-192.168.0.105,fd00::2/112\": {\n\t\t\tcount: new(big.Int).SetInt64(65541),\n\t\t\tqueries: map[uint64]net.IP{\n\t\t\t\t0:     net.ParseIP(\"192.168.0.101\"),\n\t\t\t\t1:     net.ParseIP(\"192.168.0.102\"),\n\t\t\t\t2:     net.ParseIP(\"192.168.0.103\"),\n\t\t\t\t3:     net.ParseIP(\"192.168.0.104\"),\n\t\t\t\t4:     net.ParseIP(\"192.168.0.105\"),\n\t\t\t\t5:     net.ParseIP(\"fd00::0\"),\n\t\t\t\t6:     net.ParseIP(\"fd00::1\"),\n\t\t\t\t65541: net.ParseIP(\"192.168.0.101\"),\n\t\t\t},\n\t\t},\n\t}\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tp, err := NewIPPool(name)\n\t\t\trequire.NoError(t, err)\n\t\t\tassert.Equal(t, data.count, p.count)\n\t\t\tfor q, a := range data.queries {\n\t\t\t\tassert.Equal(t, a.To16(), p.GetIP(q).To16(), \"index %d\", q)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestIpBlockError(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]string{\n\t\t\"whatever\":                       \"not a valid IP\",\n\t\t\"192.168.0.1012\":                 \"not a valid IP\",\n\t\t\"192.168.0.10/244\":               \"invalid CIDR\",\n\t\t\"fd00::0/244\":                    \"invalid CIDR\",\n\t\t\"192.168.0.101-192.168.0.102/32\": \"wrong IP range format\",\n\t\t\"192.168.0.101-fd00::1\":          \"mixed IP range format\",\n\t\t\"fd00::1-192.168.0.101\":          \"mixed IP range format\",\n\t\t\"192.168.0.100-192.168.0.2\":      \"negative IP range\",\n\t\t\"fd00:1:1:0::0-fd00:1:0:ff::3ff\": \"negative IP range\",\n\t}\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := getIPBlock(name)\n\t\t\trequire.Error(t, err)\n\t\t\trequire.Contains(t, err.Error(), data)\n\t\t})\n\t}\n}\n\nfunc TestNullIPPoolMarshalText(t *testing.T) {\n\tt.Parallel()\n\n\trangeInput := \"192.168.20.12-192.168.20.15,192.168.10.0/27\"\n\tp, err := NewIPPool(rangeInput)\n\trequire.NoError(t, err)\n\n\tnullpool := NullIPPool{\n\t\tPool:  p,\n\t\tValid: true,\n\t\traw:   []byte(rangeInput),\n\t}\n\ttext, err := nullpool.MarshalText()\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"192.168.20.12-192.168.20.15,192.168.10.0/27\", string(text))\n}\n"
  },
  {
    "path": "lib/types/net.go",
    "content": "package types\n\nimport (\n\t\"net\"\n\t\"strconv\"\n)\n\n// Host stores information about IP and port\n// for a host.\ntype Host net.TCPAddr\n\n// NewHost creates a pointer to a new address with an IP object.\nfunc NewHost(ip net.IP, portString string) (*Host, error) {\n\tif len(ip) != net.IPv4len && len(ip) != net.IPv6len {\n\t\treturn nil, &net.AddrError{Err: \"invalid IP address\", Addr: ip.String()}\n\t}\n\n\tvar port int\n\tif portString != \"\" {\n\t\tvar err error\n\t\tif port, err = strconv.Atoi(portString); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn &Host{\n\t\tIP:   ip,\n\t\tPort: port,\n\t}, nil\n}\n\n// String converts a Host into a string.\nfunc (h *Host) String() string {\n\treturn (*net.TCPAddr)(h).String()\n}\n\n// MarshalText implements the encoding.TextMarshaler interface.\n// The encoding is the same as returned by String, with one exception:\n// When len(ip) is zero, it returns an empty slice.\nfunc (h *Host) MarshalText() ([]byte, error) {\n\tif h == nil || len(h.IP) == 0 {\n\t\treturn []byte(\"\"), nil\n\t}\n\n\tif len(h.IP) != net.IPv4len && len(h.IP) != net.IPv6len {\n\t\treturn nil, &net.AddrError{Err: \"invalid IP address\", Addr: h.IP.String()}\n\t}\n\n\treturn []byte(h.String()), nil\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface.\n// The IP address is expected in a form accepted by ParseIP.\nfunc (h *Host) UnmarshalText(text []byte) error {\n\tif len(text) == 0 {\n\t\treturn &net.ParseError{Type: \"IP address\", Text: \"<nil>\"}\n\t}\n\n\tip, port, err := splitHostPort(text)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tnh, err := NewHost(ip, port)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*h = *nh\n\n\treturn nil\n}\n\nfunc splitHostPort(text []byte) (net.IP, string, error) {\n\thost, port, err := net.SplitHostPort(string(text))\n\tif err != nil {\n\t\t// This error means that there is no port.\n\t\t// Make host the full text.\n\t\thost = string(text)\n\t}\n\n\tip := net.ParseIP(host)\n\tif ip == nil {\n\t\treturn nil, \"\", &net.ParseError{Type: \"IP address\", Text: host}\n\t}\n\n\treturn ip, port, nil\n}\n"
  },
  {
    "path": "lib/types/trie.go",
    "content": "package types\n\nimport \"strings\"\n\ntype trieNode struct {\n\tisLeaf   bool\n\tchildren map[rune]*trieNode\n}\n\nfunc (t *trieNode) insert(s string) {\n\trunes := []rune(s)\n\n\tif t.children == nil {\n\t\tt.children = map[rune]*trieNode{}\n\t}\n\n\tptr := t\n\tfor i := len(runes) - 1; i >= 0; i-- {\n\t\tc, ok := ptr.children[runes[i]]\n\n\t\tif !ok {\n\t\t\tptr.children[runes[i]] = &trieNode{children: map[rune]*trieNode{}}\n\t\t\tc = ptr.children[runes[i]]\n\t\t}\n\n\t\tptr = c\n\t}\n\n\tptr.isLeaf = true\n}\n\nfunc (t *trieNode) contains(s string) (string, bool) {\n\trs := []rune(s)\n\n\tbuilder, wMatch := strings.Builder{}, \"\"\n\tfound := true\n\n\tptr := t\n\tfor i := len(rs) - 1; i >= 0; i-- {\n\t\tchild, ok := ptr.children[rs[i]]\n\n\t\tif _, wOk := ptr.children['*']; wOk {\n\t\t\twMatch = builder.String() + string('*')\n\t\t}\n\n\t\tif !ok {\n\t\t\tfound = false\n\t\t\tbreak\n\t\t}\n\n\t\tbuilder.WriteRune(rs[i])\n\t\tptr = child\n\t}\n\n\tif found && ptr.isLeaf {\n\t\treturn reverseString(builder.String()), true\n\t}\n\n\tif _, ok := ptr.children['*']; ok {\n\t\tbuilder.WriteRune('*')\n\t\treturn reverseString(builder.String()), true\n\t}\n\n\treturn reverseString(wMatch), wMatch != \"\"\n}\n\nfunc reverseString(s string) string {\n\trs := []rune(s)\n\tfor i, j := 0, len(rs)-1; i < len(rs)/2; i, j = i+1, j-1 {\n\t\trs[i], rs[j] = rs[j], rs[i]\n\t}\n\n\treturn string(rs)\n}\n"
  },
  {
    "path": "lib/types/trie_test.go",
    "content": "package types\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTrieInsert(t *testing.T) {\n\tt.Parallel()\n\n\troot := trieNode{}\n\n\tconst val = \"k6.io\"\n\troot.insert(val)\n\n\tptr := &root\n\tfor i, rs := len(val)-1, []rune(val); i >= 0; i-- {\n\t\tnext, ok := ptr.children[rs[i]]\n\t\trequire.True(t, ok)\n\t\tptr = next\n\t}\n\n\trequire.True(t, ptr.isLeaf)\n}\n\nfunc TestTrieContains(t *testing.T) {\n\tt.Parallel()\n\n\troot := trieNode{}\n\troot.insert(\"k6.io\")\n\troot.insert(\"specific.k6.io\")\n\troot.insert(\"*.k6.io\")\n\n\ttcs := []struct {\n\t\tquery, expVal string\n\t\tfound         bool\n\t}{\n\t\t// Trie functionality\n\t\t{query: \"k6.io\", expVal: \"k6.io\", found: true},\n\t\t{query: \"io\", expVal: \"\", found: false},\n\t\t{query: \"no.k6.no.io\", expVal: \"\", found: false},\n\t\t{query: \"specific.k6.io\", expVal: \"specific.k6.io\", found: true},\n\t\t{query: \"\", expVal: \"\", found: false},\n\t\t{query: \"long.long.long.long.long.long.long.long.no.match\", expVal: \"\", found: false},\n\t\t{query: \"pre.matching.long.long.long.long.test.k6.noio\", expVal: \"\", found: false},\n\n\t\t// Wildcard\n\t\t{query: \"foo.k6.io\", expVal: \"*.k6.io\", found: true},\n\t\t{query: \"specific.k6.io\", expVal: \"specific.k6.io\", found: true},\n\t\t{query: \"not.specific.k6.io\", expVal: \"*.k6.io\", found: true},\n\t}\n\n\tfor _, tc := range tcs {\n\t\tt.Run(tc.query, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tval, ok := root.contains(tc.query)\n\n\t\t\trequire.Equal(t, tc.found, ok)\n\t\t\trequire.Equal(t, tc.expVal, val)\n\t\t})\n\t}\n}\n\nfunc TestReverseString(t *testing.T) {\n\tt.Parallel()\n\n\ttcs := []struct{ str, rev string }{\n\t\t{str: \"even\", rev: \"neve\"},\n\t\t{str: \"odd\", rev: \"ddo\"},\n\t\t{str: \"\", rev: \"\"},\n\t}\n\n\tfor _, tc := range tcs {\n\t\tt.Run(tc.str, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tval := reverseString(tc.str)\n\n\t\t\trequire.Equal(t, tc.rev, val)\n\t\t})\n\t}\n}\n\nfunc BenchmarkTrieInsert(b *testing.B) {\n\tarr := []string{\n\t\t\"k6.io\", \"*.sub.k6.io\", \"specific.sub.k6.io\",\n\t\t\"grafana.com\", \"*.sub.sub.grafana.com\", \"test.sub.sub.grafana.com\",\n\t}\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\troot := trieNode{}\n\t\tfor _, v := range arr {\n\t\t\troot.insert(v)\n\t\t}\n\t}\n}\n\nfunc BenchmarkTrieContains(b *testing.B) {\n\troot := trieNode{}\n\tarr := []string{\n\t\t\"k6.io\", \"*.sub.k6.io\", \"specific.sub.k6.io\",\n\t\t\"grafana.com\", \"*.sub.sub.grafana.com\", \"test.sub.sub.grafana.com\",\n\t}\n\n\tfor _, v := range arr {\n\t\troot.insert(v)\n\t}\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\tfor _, v := range arr {\n\t\t\troot.contains(v)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "lib/types/types.go",
    "content": "// Package types contains types used in the codebase\n// Most of the types have a Null prefix like gopkg.in/guregu/null.v3\n// and UnmarshalJSON and MarshalJSON methods.\npackage types\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// TODO: something better that won't require so much boilerplate and casts for NullDuration values...\n\n// Duration is an alias for time.Duration that de/serialises to JSON as human-readable strings.\ntype Duration time.Duration\n\nfunc (d Duration) String() string {\n\treturn time.Duration(d).String()\n}\n\n// ParseExtendedDuration is a helper function that allows for string duration\n// values containing days.\nfunc ParseExtendedDuration(data string) (result time.Duration, err error) {\n\t// Assume millisecond values if data is provided with no units\n\tif t, errp := strconv.ParseFloat(data, 64); errp == nil {\n\t\treturn time.Duration(t * float64(time.Millisecond)), nil\n\t}\n\n\tdPos := strings.IndexByte(data, 'd')\n\tif dPos < 0 {\n\t\treturn time.ParseDuration(data)\n\t}\n\n\tvar hours time.Duration\n\tif dPos+1 < len(data) { // case \"12d\"\n\t\thours, err = time.ParseDuration(data[dPos+1:])\n\t\tif err != nil {\n\t\t\treturn result, err\n\t\t}\n\t\tif hours < 0 {\n\t\t\treturn 0, fmt.Errorf(\"invalid time format '%s'\", data[dPos+1:])\n\t\t}\n\t}\n\n\tdays, err := strconv.ParseInt(data[:dPos], 10, 64)\n\tif err != nil {\n\t\treturn result, err\n\t}\n\tif days < 0 {\n\t\thours = -hours\n\t}\n\treturn time.Duration(days)*24*time.Hour + hours, nil\n}\n\n// UnmarshalText converts text data to Duration\nfunc (d *Duration) UnmarshalText(data []byte) error {\n\tv, err := ParseExtendedDuration(string(data))\n\tif err != nil {\n\t\treturn err\n\t}\n\t*d = Duration(v)\n\treturn nil\n}\n\n// UnmarshalJSON converts JSON data to Duration\nfunc (d *Duration) UnmarshalJSON(data []byte) error {\n\tif len(data) > 0 && data[0] == '\"' {\n\t\tvar str string\n\t\tif err := json.Unmarshal(data, &str); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tv, err := ParseExtendedDuration(str)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\t*d = Duration(v)\n\t} else if t, errp := strconv.ParseFloat(string(data), 64); errp == nil {\n\t\t*d = Duration(t * float64(time.Millisecond))\n\t} else {\n\t\treturn fmt.Errorf(\"'%s' is not a valid duration value\", string(data))\n\t}\n\n\treturn nil\n}\n\n// MarshalJSON returns the JSON representation of d\nfunc (d Duration) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(d.String())\n}\n\n// NullDuration is a nullable Duration, in the same vein as the nullable types provided by\n// package gopkg.in/guregu/null.v3.\ntype NullDuration struct {\n\tDuration\n\tValid bool\n}\n\n// NewNullDuration is a simple helper constructor function\nfunc NewNullDuration(d time.Duration, valid bool) NullDuration {\n\treturn NullDuration{Duration(d), valid}\n}\n\n// NullDurationFrom returns a new valid NullDuration from a time.Duration.\nfunc NullDurationFrom(d time.Duration) NullDuration {\n\treturn NullDuration{Duration(d), true}\n}\n\n// UnmarshalText converts text data to a valid NullDuration\nfunc (d *NullDuration) UnmarshalText(data []byte) error {\n\tif len(data) == 0 {\n\t\t*d = NullDuration{}\n\t\treturn nil\n\t}\n\tif err := d.Duration.UnmarshalText(data); err != nil {\n\t\treturn err\n\t}\n\td.Valid = true\n\treturn nil\n}\n\n// UnmarshalJSON converts JSON data to a valid NullDuration\nfunc (d *NullDuration) UnmarshalJSON(data []byte) error {\n\tif bytes.Equal(data, []byte(`null`)) {\n\t\td.Valid = false\n\t\treturn nil\n\t}\n\tif err := json.Unmarshal(data, &d.Duration); err != nil {\n\t\treturn err\n\t}\n\td.Valid = true\n\treturn nil\n}\n\n// MarshalJSON returns the JSON representation of d\nfunc (d NullDuration) MarshalJSON() ([]byte, error) {\n\tif !d.Valid {\n\t\treturn []byte(`null`), nil\n\t}\n\treturn d.Duration.MarshalJSON()\n}\n\n// ValueOrZero returns the underlying Duration value of d if valid or\n// its zero equivalent otherwise. It matches the existing guregu/null API.\nfunc (d NullDuration) ValueOrZero() Duration {\n\tif !d.Valid {\n\t\treturn Duration(0)\n\t}\n\n\treturn d.Duration\n}\n\n// TimeDuration returns a NullDuration's value as a stdlib Duration.\nfunc (d NullDuration) TimeDuration() time.Duration {\n\treturn time.Duration(d.Duration)\n}\n\nfunc getInt64(v any) (int64, error) {\n\tswitch n := v.(type) {\n\tcase int:\n\t\treturn int64(n), nil\n\tcase int8:\n\t\treturn int64(n), nil\n\tcase int16:\n\t\treturn int64(n), nil\n\tcase int32:\n\t\treturn int64(n), nil\n\tcase int64:\n\t\treturn n, nil\n\tcase uint:\n\t\treturn int64(n), nil //nolint:gosec\n\tcase uint8:\n\t\treturn int64(n), nil\n\tcase uint16:\n\t\treturn int64(n), nil\n\tcase uint32:\n\t\treturn int64(n), nil\n\tcase uint64:\n\t\tif n > math.MaxInt64 {\n\t\t\treturn 0, fmt.Errorf(\"%d is too big\", n)\n\t\t}\n\t\treturn int64(n), nil\n\tdefault:\n\t\treturn 0, fmt.Errorf(\"unable to use type %T as a duration value\", v)\n\t}\n}\n\n// GetDurationValue is a helper function that can convert a lot of different\n// types to time.Duration.\n//\n// TODO: move to a separate package and check for integer overflows?\nfunc GetDurationValue(v any) (time.Duration, error) {\n\tswitch d := v.(type) {\n\tcase time.Duration:\n\t\treturn d, nil\n\tcase string:\n\t\treturn ParseExtendedDuration(d)\n\tcase float32:\n\t\treturn time.Duration(float64(d) * float64(time.Millisecond)), nil\n\tcase float64:\n\t\treturn time.Duration(d * float64(time.Millisecond)), nil\n\tdefault:\n\t\tn, err := getInt64(v)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\t\treturn time.Duration(n) * time.Millisecond, nil\n\t}\n}\n"
  },
  {
    "path": "lib/types/types_test.go",
    "content": "package types\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestParseExtendedDuration(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tdurStr string\n\t\texpErr bool\n\t\texpDur time.Duration\n\t}{\n\t\t{\"\", true, 0},\n\t\t{\"d\", true, 0},\n\t\t{\"d2h\", true, 0},\n\t\t{\"d2h\", true, 0},\n\t\t{\"2.1d\", true, 0},\n\t\t{\"2d-2h\", true, 0},\n\t\t{\"-2d-2h\", true, 0},\n\t\t{\"2+d\", true, 0},\n\t\t{\"2da\", true, 0},\n\t\t{\"2-d\", true, 0},\n\t\t{\"1.12s\", false, 1120 * time.Millisecond},\n\t\t{\"0d1.12s\", false, 1120 * time.Millisecond},\n\t\t{\"10d1.12s\", false, 240*time.Hour + 1120*time.Millisecond},\n\t\t{\"1s\", false, 1 * time.Second},\n\t\t{\"1d\", false, 24 * time.Hour},\n\t\t{\"20d\", false, 480 * time.Hour},\n\t\t{\"1d23h\", false, 47 * time.Hour},\n\t\t{\"1d24h15m\", false, 48*time.Hour + 15*time.Minute},\n\t\t{\"1d25h80m\", false, 50*time.Hour + 20*time.Minute},\n\t\t{\"0d25h120m80s\", false, 27*time.Hour + 80*time.Second},\n\t\t{\"-1d2h\", false, -26 * time.Hour},\n\t\t{\"-1d24h\", false, -48 * time.Hour},\n\t\t{\"2d1ns\", false, 48*time.Hour + 1},\n\t\t{\"-2562047h47m16.854775807s\", false, time.Duration(math.MinInt64 + 1)},\n\t\t{\"-106751d23h47m16.854775807s\", false, time.Duration(math.MinInt64 + 1)},\n\t\t{\"2562047h47m16.854775807s\", false, time.Duration(math.MaxInt64)},\n\t\t{\"106751d23h47m16.854775807s\", false, time.Duration(math.MaxInt64)},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"tc_%s_exp\", tc.durStr), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tresult, err := ParseExtendedDuration(tc.durStr)\n\t\t\tif tc.expErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expDur, result)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDuration(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"String\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tassert.Equal(t, \"1m15s\", Duration(75*time.Second).String())\n\t})\n\tt.Run(\"JSON\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"Unmarshal\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Run(\"Number\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d Duration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`75000`), &d))\n\t\t\t\tassert.Equal(t, Duration(75*time.Second), d)\n\t\t\t})\n\t\t\tt.Run(\"Seconds\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d Duration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`\"75s\"`), &d))\n\t\t\t\tassert.Equal(t, Duration(75*time.Second), d)\n\t\t\t})\n\t\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d Duration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`\"1m15s\"`), &d))\n\t\t\t\tassert.Equal(t, Duration(75*time.Second), d)\n\t\t\t})\n\t\t\tt.Run(\"Extended\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d Duration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`\"1d2h1m15s\"`), &d))\n\t\t\t\tassert.Equal(t, Duration(26*time.Hour+75*time.Second), d)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"Marshal\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\td := Duration(75 * time.Second)\n\t\t\tdata, err := json.Marshal(d)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Equal(t, `\"1m15s\"`, string(data))\n\t\t})\n\t})\n\tt.Run(\"Text\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tvar d Duration\n\t\tassert.NoError(t, d.UnmarshalText([]byte(`10s`)))\n\t\tassert.Equal(t, Duration(10*time.Second), d)\n\t})\n}\n\nfunc TestNullDuration(t *testing.T) {\n\tt.Parallel()\n\tt.Run(\"String\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tassert.Equal(t, \"1m15s\", Duration(75*time.Second).String())\n\t})\n\tt.Run(\"JSON\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"Unmarshal\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Run(\"Number\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d NullDuration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`75000`), &d))\n\t\t\t\tassert.Equal(t, NullDuration{Duration(75 * time.Second), true}, d)\n\t\t\t})\n\t\t\tt.Run(\"Seconds\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d NullDuration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`\"75s\"`), &d))\n\t\t\t\tassert.Equal(t, NullDuration{Duration(75 * time.Second), true}, d)\n\t\t\t})\n\t\t\tt.Run(\"String\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d NullDuration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`\"1m15s\"`), &d))\n\t\t\t\tassert.Equal(t, NullDuration{Duration(75 * time.Second), true}, d)\n\t\t\t})\n\t\t\tt.Run(\"Null\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d NullDuration\n\t\t\t\tassert.NoError(t, json.Unmarshal([]byte(`null`), &d))\n\t\t\t\tassert.Equal(t, NullDuration{Duration(0), false}, d)\n\t\t\t})\n\t\t})\n\t\tt.Run(\"Marshal\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tt.Run(\"Valid\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\td := NullDuration{Duration(75 * time.Second), true}\n\t\t\t\tdata, err := json.Marshal(d)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, `\"1m15s\"`, string(data))\n\t\t\t})\n\t\t\tt.Run(\"null\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\t\t\t\tvar d NullDuration\n\t\t\t\tdata, err := json.Marshal(d)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, `null`, string(data))\n\t\t\t})\n\t\t})\n\t})\n\tt.Run(\"Text\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tvar d NullDuration\n\t\tassert.NoError(t, d.UnmarshalText([]byte(`10s`)))\n\t\tassert.Equal(t, NullDurationFrom(10*time.Second), d)\n\n\t\tt.Run(\"Empty\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tvar d NullDuration\n\t\t\tassert.NoError(t, d.UnmarshalText([]byte(``)))\n\t\t\tassert.Equal(t, NullDuration{}, d)\n\t\t})\n\t})\n}\n\nfunc TestNullDurationFrom(t *testing.T) {\n\tt.Parallel()\n\tassert.Equal(t, NullDuration{Duration(10 * time.Second), true}, NullDurationFrom(10*time.Second))\n}\n\nfunc TestGetDurationValue(t *testing.T) {\n\tt.Parallel()\n\ttestCases := []struct {\n\t\tval      any\n\t\texpError bool\n\t\texp      time.Duration\n\t}{\n\t\t{false, true, 0},\n\t\t{time.Now(), true, 0},\n\t\t{\"invalid\", true, 0},\n\t\t{uint64(math.MaxInt64) + 1, true, 0},\n\n\t\t{int8(100), false, 100 * time.Millisecond},\n\t\t{uint8(100), false, 100 * time.Millisecond},\n\t\t{uint(1000), false, time.Second},\n\t\t{int(1000), false, time.Second},\n\t\t{uint16(1000), false, time.Second},\n\t\t{int16(1000), false, time.Second},\n\t\t{uint32(1000), false, time.Second},\n\t\t{int32(1000), false, time.Second},\n\t\t{uint(1000), false, time.Second},\n\t\t{int(1000), false, time.Second},\n\t\t{uint64(1000), false, time.Second},\n\t\t{int64(1000), false, time.Second},\n\t\t{1000, false, time.Second},\n\t\t{1000, false, time.Second},\n\t\t{1000.0, false, time.Second},\n\t\t{float32(1000.0), false, time.Second},\n\t\t{float64(1000.001), false, time.Second + time.Microsecond},\n\t\t{\"1000\", false, time.Second},\n\t\t{\"1000.001\", false, time.Second + time.Microsecond},\n\t\t{\"1s\", false, time.Second},\n\t\t{\"1.5s\", false, 1500 * time.Millisecond},\n\t\t{time.Second, false, time.Second},\n\t\t{\"1d3h1s\", false, 27*time.Hour + time.Second},\n\t\t// TODO: test for int overflows when that's implemented\n\t}\n\n\tfor i, tc := range testCases {\n\t\tt.Run(fmt.Sprintf(\"testcase_%02d\", i), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tres, err := GetDurationValue(tc.val)\n\t\t\tif tc.expError {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.exp, res)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "lib/vu_state.go",
    "content": "package lib\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.opentelemetry.io/otel/trace\"\n\t\"golang.org/x/time/rate\"\n\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// DialContexter is an interface that can dial with a context\ntype DialContexter interface {\n\tDialContext(ctx context.Context, network, addr string) (net.Conn, error)\n}\n\n// TracerProvider provides methods for OTEL tracers initialization.\ntype TracerProvider interface {\n\tTracer(name string, options ...trace.TracerOption) trace.Tracer\n}\n\n// AddrResolver is an interface for DNS resolution.\ntype AddrResolver interface {\n\t// ResolveAddr looks up the IP address for the given host and optionally port.\n\t// It uses the same DNS resolution logic as DialContext, respecting the\n\t// DNS, Hosts, Blacklist IP, and Block hostnames options.\n\t// The address can be in the form \"host:port\" or just \"host\".\n\t// It returns the resolved IP, the port (0 if not specified), and an error if resolution fails.\n\tResolveAddr(addr string) (net.IP, int, error)\n}\n\n// State provides the volatile state for a VU.\n//\n// TODO: rename to VUState or, better yet, move to some other Go package outside\n// of lib/, where it's more obvious that this is the VU state.\ntype State struct {\n\t// Global options and built-in metrics.\n\t//\n\t// TODO: remove them from here, the built-in metrics and the script options\n\t// are not part of a VU's unique \"state\", they are global and the same for\n\t// all VUs. Figure out how to thread them some other way, e.g. through the\n\t// TestPreInitState. The Samples channel might also benefit from that...\n\tOptions        Options\n\tBuiltinMetrics *metrics.BuiltinMetrics\n\n\t// Logger instance for every VU.\n\tLogger logrus.FieldLogger\n\n\t// Networking equipment.\n\tDialer DialContexter\n\n\t// TODO: move a lot of the things below to the k6/http ModuleInstance, see\n\t// https://github.com/grafana/k6/issues/2293.\n\tTransport http.RoundTripper\n\tCookieJar *cookiejar.Jar\n\tTLSConfig *tls.Config\n\n\t// Rate limits.\n\tRPSLimit *rate.Limiter\n\n\t// Sample channel, possibly buffered\n\tSamples chan<- metrics.SampleContainer\n\n\t// Buffer pool; use instead of allocating fresh buffers when possible.\n\tBufferPool *BufferPool\n\n\tVUID, VUIDGlobal uint64\n\tIteration        int64\n\n\t// TODO: rename this field with one more representative\n\t// because it includes now also the metadata.\n\tTags *VUStateTags\n\n\t// These will be assigned on VU activation.\n\t// Returns the iteration number of this VU in the current scenario.\n\tGetScenarioVUIter func() uint64\n\t// Returns the iteration number across all VUs in the current scenario\n\t// unique to this single k6 instance.\n\t// TODO: Maybe this doesn't belong here but in ScenarioState?\n\tGetScenarioLocalVUIter func() uint64\n\t// Returns the iteration number across all VUs in the current scenario\n\t// unique globally across k6 instances (taking into account execution\n\t// segments).\n\tGetScenarioGlobalVUIter func() uint64\n\n\t// Tracing instrumentation.\n\tTracerProvider TracerProvider\n\n\t// Usage is a way to report usage statistics\n\tUsage *usage.Usage\n\n\t// TestStatus holds the test status and is used to support marking a test as failed\n\t// in a thread-safe manner. It is used to ensure that the test status is only\n\t// marked as failed once, even if multiple VUs or goroutines, try to mark it at the same time.\n\tTestStatus *TestStatus\n}\n\n// GetAddrResolver returns the AddrResolver implementation or nil if not available.\nfunc (s *State) GetAddrResolver() AddrResolver {\n\tresolver, ok := s.Dialer.(AddrResolver)\n\tif !ok {\n\t\treturn nil\n\t}\n\n\treturn resolver\n}\n\n// VUStateTags wraps the current VU's tags and ensures a thread-safe way to\n// access and modify them exists. This is necessary because the VU tags and\n// metadata can be modified from the JS scripts via the `vu.tags` API in the\n// `k6/execution` built-in module.\ntype VUStateTags struct {\n\tmutex       sync.RWMutex\n\ttagsAndMeta *metrics.TagsAndMeta\n}\n\n// NewVUStateTags initializes a new VUStateTags and returns it. It's important\n// that tags is not nil and initialized via metrics.Registry.RootTagSet().\nfunc NewVUStateTags(tags *metrics.TagSet) *VUStateTags {\n\tif tags == nil {\n\t\tpanic(\"the metrics.TagSet must be initialized for creating a new lib.VUStateTags\")\n\t}\n\treturn &VUStateTags{\n\t\tmutex: sync.RWMutex{},\n\t\ttagsAndMeta: &metrics.TagsAndMeta{\n\t\t\tTags: tags,\n\t\t\t// metadata is intentionally nil by default\n\t\t},\n\t}\n}\n\n// GetCurrentValues returns the current value of the VU tags and a copy of the\n// metadata (if any) in a thread-safe way.\nfunc (tg *VUStateTags) GetCurrentValues() metrics.TagsAndMeta {\n\ttg.mutex.RLock()\n\tdefer tg.mutex.RUnlock()\n\treturn tg.tagsAndMeta.Clone()\n}\n\n// Modify allows the thread-safe modification of the current VU tags and metadata.\nfunc (tg *VUStateTags) Modify(callback func(tagsAndMeta *metrics.TagsAndMeta)) {\n\ttg.mutex.Lock()\n\tdefer tg.mutex.Unlock()\n\tcallback(tg.tagsAndMeta)\n}\n"
  },
  {
    "path": "lib/vu_state_test.go",
    "content": "package lib\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\n// mockDialerWithResolver is a mock that implements both DialContexter and AddrResolver\ntype mockDialerWithResolver struct{}\n\nfunc (m *mockDialerWithResolver) DialContext(_ context.Context, _, _ string) (net.Conn, error) {\n\treturn nil, errors.ErrUnsupported\n}\n\nfunc (m *mockDialerWithResolver) ResolveAddr(_ string) (net.IP, int, error) {\n\treturn nil, 0, errors.ErrUnsupported\n}\n\n// mockDialerWithoutResolver is a mock that only implements DialContexter\ntype mockDialerWithoutResolver struct{}\n\nfunc (m *mockDialerWithoutResolver) DialContext(_ context.Context, _, _ string) (net.Conn, error) {\n\treturn nil, errors.ErrUnsupported\n}\n\nfunc TestGetAddrResolver(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"returns_same_instance_when_Dialer_implements_AddrResolver\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tmock := &mockDialerWithResolver{}\n\n\t\tstate := &State{\n\t\t\tDialer: mock,\n\t\t}\n\n\t\tresolver := state.GetAddrResolver()\n\t\trequire.NotNil(t, resolver)\n\t\trequire.Same(t, mock, resolver)\n\t})\n\n\tt.Run(\"returns_nil_when_Dialer_does_not_implement_AddrResolver\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tmock := &mockDialerWithoutResolver{}\n\n\t\tstate := &State{\n\t\t\tDialer: mock,\n\t\t}\n\n\t\tresolver := state.GetAddrResolver()\n\t\trequire.Nil(t, resolver)\n\t})\n}\n"
  },
  {
    "path": "main.go",
    "content": "// Package main is the entry point for the k6 CLI application. It assembles all the crucial components for the running.\npackage main\n\nimport (\n\t\"go.k6.io/k6/cmd\"\n)\n\nfunc main() {\n\tcmd.Execute()\n}\n"
  },
  {
    "path": "metrics/builtin.go",
    "content": "package metrics\n\n//nolint:revive\nconst (\n\tVUsName               = \"vus\"\n\tVUsMaxName            = \"vus_max\"\n\tIterationsName        = \"iterations\"\n\tIterationDurationName = \"iteration_duration\"\n\tDroppedIterationsName = \"dropped_iterations\"\n\n\tChecksName        = \"checks\"\n\tGroupDurationName = \"group_duration\"\n\n\tHTTPReqsName              = \"http_reqs\"\n\tHTTPReqFailedName         = \"http_req_failed\"\n\tHTTPReqDurationName       = \"http_req_duration\"\n\tHTTPReqBlockedName        = \"http_req_blocked\"\n\tHTTPReqConnectingName     = \"http_req_connecting\"\n\tHTTPReqTLSHandshakingName = \"http_req_tls_handshaking\"\n\tHTTPReqSendingName        = \"http_req_sending\"\n\tHTTPReqWaitingName        = \"http_req_waiting\"\n\tHTTPReqReceivingName      = \"http_req_receiving\"\n\n\tWSSessionsName         = \"ws_sessions\"\n\tWSMessagesSentName     = \"ws_msgs_sent\"\n\tWSMessagesReceivedName = \"ws_msgs_received\"\n\tWSPingName             = \"ws_ping\"\n\tWSSessionDurationName  = \"ws_session_duration\"\n\tWSConnectingName       = \"ws_connecting\"\n\n\tGRPCReqDurationName = \"grpc_req_duration\"\n\n\tDataSentName     = \"data_sent\"\n\tDataReceivedName = \"data_received\"\n)\n\n// BuiltinMetrics represent all the builtin metrics of k6\ntype BuiltinMetrics struct {\n\tVUs               *Metric\n\tVUsMax            *Metric\n\tIterations        *Metric\n\tIterationDuration *Metric\n\tDroppedIterations *Metric\n\n\t// Runner-emitted.\n\tChecks        *Metric\n\tGroupDuration *Metric\n\n\t// HTTP-related.\n\tHTTPReqs              *Metric\n\tHTTPReqFailed         *Metric\n\tHTTPReqDuration       *Metric\n\tHTTPReqBlocked        *Metric\n\tHTTPReqConnecting     *Metric\n\tHTTPReqTLSHandshaking *Metric\n\tHTTPReqSending        *Metric\n\tHTTPReqWaiting        *Metric\n\tHTTPReqReceiving      *Metric\n\n\t// Websocket-related\n\tWSSessions         *Metric\n\tWSMessagesSent     *Metric\n\tWSMessagesReceived *Metric\n\tWSPing             *Metric\n\tWSSessionDuration  *Metric\n\tWSConnecting       *Metric\n\n\t// gRPC-related\n\tGRPCReqDuration *Metric\n\n\t// Network-related; used for future protocols as well.\n\tDataSent     *Metric\n\tDataReceived *Metric\n}\n\n// RegisterBuiltinMetrics register and returns the builtin metrics in the provided registry\nfunc RegisterBuiltinMetrics(registry *Registry) *BuiltinMetrics {\n\treturn &BuiltinMetrics{\n\t\tVUs:               registry.MustNewMetric(VUsName, Gauge),\n\t\tVUsMax:            registry.MustNewMetric(VUsMaxName, Gauge),\n\t\tIterations:        registry.MustNewMetric(IterationsName, Counter),\n\t\tIterationDuration: registry.MustNewMetric(IterationDurationName, Trend, Time),\n\t\tDroppedIterations: registry.MustNewMetric(DroppedIterationsName, Counter),\n\n\t\tChecks:        registry.MustNewMetric(ChecksName, Rate),\n\t\tGroupDuration: registry.MustNewMetric(GroupDurationName, Trend, Time),\n\n\t\tHTTPReqs:              registry.MustNewMetric(HTTPReqsName, Counter),\n\t\tHTTPReqFailed:         registry.MustNewMetric(HTTPReqFailedName, Rate),\n\t\tHTTPReqDuration:       registry.MustNewMetric(HTTPReqDurationName, Trend, Time),\n\t\tHTTPReqBlocked:        registry.MustNewMetric(HTTPReqBlockedName, Trend, Time),\n\t\tHTTPReqConnecting:     registry.MustNewMetric(HTTPReqConnectingName, Trend, Time),\n\t\tHTTPReqTLSHandshaking: registry.MustNewMetric(HTTPReqTLSHandshakingName, Trend, Time),\n\t\tHTTPReqSending:        registry.MustNewMetric(HTTPReqSendingName, Trend, Time),\n\t\tHTTPReqWaiting:        registry.MustNewMetric(HTTPReqWaitingName, Trend, Time),\n\t\tHTTPReqReceiving:      registry.MustNewMetric(HTTPReqReceivingName, Trend, Time),\n\n\t\tWSSessions:         registry.MustNewMetric(WSSessionsName, Counter),\n\t\tWSMessagesSent:     registry.MustNewMetric(WSMessagesSentName, Counter),\n\t\tWSMessagesReceived: registry.MustNewMetric(WSMessagesReceivedName, Counter),\n\t\tWSPing:             registry.MustNewMetric(WSPingName, Trend, Time),\n\t\tWSSessionDuration:  registry.MustNewMetric(WSSessionDurationName, Trend, Time),\n\t\tWSConnecting:       registry.MustNewMetric(WSConnectingName, Trend, Time),\n\n\t\tGRPCReqDuration: registry.MustNewMetric(GRPCReqDurationName, Trend, Time),\n\n\t\tDataSent:     registry.MustNewMetric(DataSentName, Counter, Data),\n\t\tDataReceived: registry.MustNewMetric(DataReceivedName, Counter, Data),\n\t}\n}\n"
  },
  {
    "path": "metrics/metric.go",
    "content": "package metrics\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// A Metric defines the shape of a set of data.\ntype Metric struct {\n\tregistry *Registry  `json:\"-\"`\n\tName     string     `json:\"name\"`\n\tType     MetricType `json:\"type\"`\n\tContains ValueType  `json:\"contains\"`\n\n\t// TODO: decouple the metrics from the sinks and thresholds... have them\n\t// linked, but not in the same struct?\n\tTainted    null.Bool    `json:\"tainted\"`\n\tThresholds Thresholds   `json:\"thresholds\"`\n\tSubmetrics []*Submetric `json:\"submetrics\"`\n\tSub        *Submetric   `json:\"-\"`\n\tSink       Sink         `json:\"-\"`\n\tObserved   bool         `json:\"-\"`\n}\n\n// A Submetric represents a filtered dataset based on a parent metric.\ntype Submetric struct {\n\tName   string  `json:\"name\"`\n\tSuffix string  `json:\"suffix\"` // TODO: rename?\n\tTags   *TagSet `json:\"tags\"`\n\n\tMetric *Metric `json:\"-\"`\n\tParent *Metric `json:\"-\"`\n}\n\n// AddSubmetric creates a new submetric from the key:value threshold definition\n// and adds it to the metric's submetrics list.\nfunc (m *Metric) AddSubmetric(keyValues string) (*Submetric, error) {\n\tkeyValues = strings.TrimSpace(keyValues)\n\tif len(keyValues) == 0 {\n\t\treturn nil, fmt.Errorf(\"submetric criteria for metric '%s' cannot be empty\", m.Name)\n\t}\n\tkvs := strings.Split(keyValues, \",\")\n\ttags := m.registry.RootTagSet()\n\tfor _, kv := range kvs {\n\t\tif kv == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tk, v, _ := strings.Cut(kv, \":\")\n\n\t\tkey := strings.Trim(strings.TrimSpace(k), `\"'`)\n\t\tif v == \"\" {\n\t\t\ttags = tags.With(key, \"\")\n\t\t\tcontinue\n\t\t}\n\n\t\tvalue := strings.Trim(strings.TrimSpace(v), `\"'`)\n\t\ttags = tags.With(key, value)\n\t}\n\n\tfor _, sm := range m.Submetrics {\n\t\tif tags == sm.Tags {\n\t\t\treturn sm, nil\n\t\t}\n\t}\n\n\tsubMetric := &Submetric{\n\t\tName:   m.Name + \"{\" + keyValues + \"}\",\n\t\tSuffix: keyValues,\n\t\tTags:   tags,\n\t\tParent: m,\n\t}\n\tsubMetricMetric := m.registry.newMetric(subMetric.Name, m.Type, m.Contains)\n\tsubMetricMetric.Sub = subMetric // sigh\n\tsubMetric.Metric = subMetricMetric\n\n\tm.Submetrics = append(m.Submetrics, subMetric)\n\n\treturn subMetric, nil\n}\n\n// ErrMetricNameParsing indicates parsing a metric name failed\nvar ErrMetricNameParsing = errors.New(\"parsing metric name failed\")\n\n// ParseMetricName parses a metric name expression of the form metric_name{tag_key:tag_value,...}\n// Its first return value is the parsed metric name, second are parsed tags as as slice\n// of \"key:value\" strings. On failure, it returns an error containing the `ErrMetricNameParsing` in its chain.\nfunc ParseMetricName(name string) (string, []string, error) {\n\topeningTokenPos := strings.IndexByte(name, '{')\n\tclosingTokenPos := strings.LastIndexByte(name, '}')\n\tcontainsOpeningToken := openingTokenPos != -1\n\tcontainsClosingToken := closingTokenPos != -1\n\n\t// Neither the opening '{' token nor the closing '}' token\n\t// are present, thus the metric name only consists of a literal.\n\tif !containsOpeningToken && !containsClosingToken {\n\t\treturn name, nil, nil\n\t}\n\n\t// If the name contains an opening or closing token, but not\n\t// its counterpart, the expression is malformed.\n\tif (containsOpeningToken && !containsClosingToken) ||\n\t\t(!containsOpeningToken && containsClosingToken) {\n\t\treturn \"\", nil, fmt.Errorf(\n\t\t\t\"%w, metric %q has unmatched opening/close curly brace\",\n\t\t\tErrMetricNameParsing, name,\n\t\t)\n\t}\n\n\t// If the closing brace token appears before the opening one,\n\t// the expression is malformed\n\tif closingTokenPos < openingTokenPos {\n\t\treturn \"\", nil, fmt.Errorf(\"%w, metric %q closing curly brace appears before opening one\", ErrMetricNameParsing, name)\n\t}\n\n\t// If the last character is not a closing brace token,\n\t// the expression is malformed.\n\tif closingTokenPos != (len(name) - 1) {\n\t\terr := fmt.Errorf(\n\t\t\t\"%w, metric %q lacks a closing curly brace in its last position\",\n\t\t\tErrMetricNameParsing,\n\t\t\tname,\n\t\t)\n\t\treturn \"\", nil, err\n\t}\n\n\t// We already know the position of the opening and closing curly brace\n\t// tokens. Thus, we extract the string in between them, and split its\n\t// content to obtain the tags key values.\n\ttags := strings.Split(name[openingTokenPos+1:closingTokenPos], \",\")\n\n\t// For each tag definition, ensure it is correctly formed\n\tfor i, t := range tags {\n\t\t_, value, _ := strings.Cut(t, \":\")\n\n\t\tif value == \"\" {\n\t\t\treturn \"\", nil, fmt.Errorf(\"%w, metric %q tag expression is malformed\", ErrMetricNameParsing, t)\n\t\t}\n\n\t\ttags[i] = strings.TrimSpace(t)\n\t}\n\n\treturn name[0:openingTokenPos], tags, nil\n}\n"
  },
  {
    "path": "metrics/metric_test.go",
    "content": "package metrics\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNewMetric(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]struct {\n\t\tType     MetricType\n\t\tSinkType Sink\n\t}{\n\t\t\"Counter\": {Counter, &CounterSink{}},\n\t\t\"Gauge\":   {Gauge, &GaugeSink{}},\n\t\t\"Trend\":   {Trend, NewTrendSink()},\n\t\t\"Rate\":    {Rate, &RateSink{}},\n\t}\n\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tr := NewRegistry()\n\t\t\tm := r.newMetric(\"my_metric\", data.Type)\n\t\t\tassert.Equal(t, \"my_metric\", m.Name)\n\t\t\tassert.IsType(t, data.SinkType, m.Sink)\n\t\t})\n\t}\n}\n\nfunc TestAddSubmetric(t *testing.T) {\n\tt.Parallel()\n\ttestdata := map[string]struct {\n\t\terr  bool\n\t\ttags map[string]string\n\t}{\n\t\t\"\":                        {true, nil},\n\t\t\"  \":                      {true, nil},\n\t\t\"a\":                       {false, map[string]string{\"a\": \"\"}},\n\t\t\"a:1\":                     {false, map[string]string{\"a\": \"1\"}},\n\t\t\" a : 1 \":                 {false, map[string]string{\"a\": \"1\"}},\n\t\t\"a,b\":                     {false, map[string]string{\"a\": \"\", \"b\": \"\"}},\n\t\t` a:\"\",b: ''`:             {false, map[string]string{\"a\": \"\", \"b\": \"\"}},\n\t\t`a:1,b:2`:                 {false, map[string]string{\"a\": \"1\", \"b\": \"2\"}},\n\t\t` a : 1, b : 2 `:          {false, map[string]string{\"a\": \"1\", \"b\": \"2\"}},\n\t\t`a : '1' , b : \"2\"`:       {false, map[string]string{\"a\": \"1\", \"b\": \"2\"}},\n\t\t`\" a\" : ' 1' , b : \"2 \" `: {false, map[string]string{\" a\": \" 1\", \"b\": \"2 \"}}, //nolint:gocritic\n\t}\n\n\tfor name, expected := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tr := NewRegistry()\n\t\t\tm := r.MustNewMetric(\"metric\", Trend)\n\t\t\tsm, err := m.AddSubmetric(name)\n\t\t\tif expected.err {\n\t\t\t\trequire.Error(t, err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\trequire.NoError(t, err)\n\t\t\trequire.NotNil(t, sm)\n\t\t\tassert.EqualValues(t, expected.tags, sm.Tags.Map())\n\t\t})\n\t}\n}\n\nfunc TestParseMetricName(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname                 string\n\t\tmetricNameExpression string\n\t\twantMetricName       string\n\t\twantTags             []string\n\t\twantErr              bool\n\t}{\n\t\t{\n\t\t\tname:                 \"metric name without tags\",\n\t\t\tmetricNameExpression: \"test_metric\",\n\t\t\twantMetricName:       \"test_metric\",\n\t\t\twantErr:              false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with single tag\",\n\t\t\tmetricNameExpression: \"test_metric{abc:123}\",\n\t\t\twantMetricName:       \"test_metric\",\n\t\t\twantTags:             []string{\"abc:123\"},\n\t\t\twantErr:              false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with multiple tags\",\n\t\t\tmetricNameExpression: \"test_metric{abc:123,easyas:doremi}\",\n\t\t\twantMetricName:       \"test_metric\",\n\t\t\twantTags:             []string{\"abc:123\", \"easyas:doremi\"},\n\t\t\twantErr:              false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with multiple spaced tags\",\n\t\t\tmetricNameExpression: \"test_metric{abc:123, easyas:doremi}\",\n\t\t\twantMetricName:       \"test_metric\",\n\t\t\twantTags:             []string{\"abc:123\", \"easyas:doremi\"},\n\t\t\twantErr:              false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with group tag\",\n\t\t\tmetricNameExpression: \"test_metric{group:::mygroup}\",\n\t\t\twantMetricName:       \"test_metric\",\n\t\t\twantTags:             []string{\"group:::mygroup\"},\n\t\t\twantErr:              false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with valid name and repeated curly braces tokens in tags definition\",\n\t\t\tmetricNameExpression: \"http_req_duration{name:http://${}.com}\",\n\t\t\twantMetricName:       \"http_req_duration\",\n\t\t\twantTags:             []string{\"name:http://${}.com\"},\n\t\t\twantErr:              false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with valid name and repeated curly braces and colon tokens in tags definition\",\n\t\t\tmetricNameExpression: \"http_req_duration{name:http://${}.com,url:ssh://github.com:grafana/k6}\",\n\t\t\twantMetricName:       \"http_req_duration\",\n\t\t\twantTags:             []string{\"name:http://${}.com\", \"url:ssh://github.com:grafana/k6\"},\n\t\t\twantErr:              false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with tag definition missing `:value`\",\n\t\t\tmetricNameExpression: \"test_metric{easyas}\",\n\t\t\twantErr:              true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with tag definition missing value\",\n\t\t\tmetricNameExpression: \"test_metric{easyas:}\",\n\t\t\twantErr:              true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with mixed valid and invalid tag definitions\",\n\t\t\tmetricNameExpression: \"test_metric{abc:123,easyas:}\",\n\t\t\twantErr:              true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with valid name and unmatched opening tags definition token\",\n\t\t\tmetricNameExpression: \"test_metric{abc:123,easyas:doremi\",\n\t\t\twantErr:              true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with valid name and unmatched closing tags definition token\",\n\t\t\tmetricNameExpression: \"test_metricabc:123,easyas:doremi}\",\n\t\t\twantErr:              true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with valid name and invalid starting tags definition token\",\n\t\t\tmetricNameExpression: \"test_metric}abc:123,easyas:doremi}\",\n\t\t\twantErr:              true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with valid name and invalid curly braces in tags definition\",\n\t\t\tmetricNameExpression: \"test_metric}abc{bar\",\n\t\t\twantErr:              true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"metric name with valid name and trailing characters after closing curly brace in tags definition\",\n\t\t\tmetricNameExpression: \"test_metric{foo:ba}r\",\n\t\t\twantErr:              true,\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotMetricName, gotTags, gotErr := ParseMetricName(tt.metricNameExpression)\n\n\t\t\tassert.Equal(t,\n\t\t\t\tgotErr != nil, tt.wantErr,\n\t\t\t\t\"ParseMetricName() error = %v, wantErr %v\", gotErr, tt.wantErr,\n\t\t\t)\n\n\t\t\tif gotErr != nil {\n\t\t\t\tassert.ErrorIs(t,\n\t\t\t\t\tgotErr, ErrMetricNameParsing,\n\t\t\t\t\t\"ParseMetricName() error chain should contain ErrMetricNameParsing\",\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttt.wantMetricName, gotMetricName,\n\t\t\t\t\"ParseMetricName() gotMetricName = %v, want %v\", gotMetricName, tt.wantMetricName,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttt.wantTags, gotTags,\n\t\t\t\t\"ParseMetricName() gotTags = %v, want %v\", gotTags, tt.wantTags,\n\t\t\t)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "metrics/metric_type.go",
    "content": "package metrics\n\nimport (\n\t\"errors\"\n\t\"slices\"\n)\n\n// A MetricType specifies the type of a metric.\ntype MetricType int\n\n// Possible values for MetricType.\nconst (\n\tCounter = MetricType(iota) // A counter that sums its data points\n\tGauge                      // A gauge that displays the latest value\n\tTrend                      // A trend, min/max/avg/med are interesting\n\tRate                       // A rate, displays % of values that aren't 0\n)\n\n// ErrInvalidMetricType indicates the serialized metric type is invalid.\nvar ErrInvalidMetricType = errors.New(\"invalid metric type\")\n\nconst (\n\tcounterString = \"counter\"\n\tgaugeString   = \"gauge\"\n\ttrendString   = \"trend\"\n\trateString    = \"rate\"\n\n\tdefaultString = \"default\"\n\ttimeString    = \"time\"\n\tdataString    = \"data\"\n)\n\n// MarshalJSON serializes a MetricType as a human readable string.\nfunc (t MetricType) MarshalJSON() ([]byte, error) {\n\ttxt, err := t.MarshalText()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []byte(`\"` + string(txt) + `\"`), nil\n}\n\n// MarshalText serializes a MetricType as a human readable string.\nfunc (t MetricType) MarshalText() ([]byte, error) {\n\tswitch t {\n\tcase Counter:\n\t\treturn []byte(counterString), nil\n\tcase Gauge:\n\t\treturn []byte(gaugeString), nil\n\tcase Trend:\n\t\treturn []byte(trendString), nil\n\tcase Rate:\n\t\treturn []byte(rateString), nil\n\tdefault:\n\t\treturn nil, ErrInvalidMetricType\n\t}\n}\n\n// UnmarshalText deserializes a MetricType from a string representation.\nfunc (t *MetricType) UnmarshalText(data []byte) error {\n\tswitch string(data) {\n\tcase counterString:\n\t\t*t = Counter\n\tcase gaugeString:\n\t\t*t = Gauge\n\tcase trendString:\n\t\t*t = Trend\n\tcase rateString:\n\t\t*t = Rate\n\tdefault:\n\t\treturn ErrInvalidMetricType\n\t}\n\n\treturn nil\n}\n\nfunc (t MetricType) String() string {\n\tswitch t {\n\tcase Counter:\n\t\treturn counterString\n\tcase Gauge:\n\t\treturn gaugeString\n\tcase Trend:\n\t\treturn trendString\n\tcase Rate:\n\t\treturn rateString\n\tdefault:\n\t\treturn \"[INVALID]\"\n\t}\n}\n\n// supportedAggregationMethods returns the list of threshold aggregation methods\n// that can be used against this MetricType.\nfunc (t MetricType) supportedAggregationMethods() []string {\n\tswitch t {\n\tcase Counter:\n\t\treturn []string{tokenCount, tokenRate}\n\tcase Gauge:\n\t\treturn []string{tokenValue}\n\tcase Rate:\n\t\treturn []string{tokenRate}\n\tcase Trend:\n\t\treturn []string{\n\t\t\ttokenAvg,\n\t\t\ttokenMin,\n\t\t\ttokenMax,\n\t\t\ttokenMed,\n\t\t\ttokenPercentile,\n\t\t}\n\tdefault:\n\t\t// unreachable!\n\t\tpanic(\"unreachable\")\n\t}\n}\n\n// supportsAggregationMethod returns whether the MetricType supports a\n// given threshold aggregation method or not.\nfunc (t MetricType) supportsAggregationMethod(aggregationMethod string) bool {\n\treturn slices.Contains(t.supportedAggregationMethods(), aggregationMethod)\n}\n"
  },
  {
    "path": "metrics/package.go",
    "content": "// Package metrics contains various k6 components that deal with metrics and\n// thresholds.\npackage metrics\n\n// TODO: move most things from the stats/ package here\n\n// TODO: maybe even move the outputs to a sub-folder here? it may be worth it to\n// do a new Output v2 implementation that uses channels and is more usable and\n// easier to write? this way the old extensions can still work for a while, with\n// an adapter and a deprecation notice\n"
  },
  {
    "path": "metrics/registry.go",
    "content": "package metrics\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"sync\"\n\n\t\"github.com/mstoykov/atlas\"\n)\n\n// Registry is what can create metrics\ntype Registry struct {\n\tmetrics map[string]*Metric\n\tl       sync.RWMutex\n\n\trootTagSet *atlas.Node\n}\n\n// NewRegistry returns a new registry\nfunc NewRegistry() *Registry {\n\treturn &Registry{\n\t\tmetrics: make(map[string]*Metric),\n\t\t// All the new TagSts must branch out from this root, otherwise\n\t\t// comparing them and using their Equals() method won't work correctly.\n\t\trootTagSet: atlas.New(),\n\t}\n}\n\nconst (\n\tnameRegexString = \"^[a-zA-Z_][a-zA-Z0-9_]{1,128}$\"\n\tbadNameWarning  = \"Metric names must only include up to 128 ASCII letters, numbers, or underscores \" +\n\t\t\"and start with a letter or an underscore.\"\n)\n\nvar compileNameRegex = regexp.MustCompile(nameRegexString)\n\nfunc checkName(name string) bool {\n\treturn compileNameRegex.MatchString(name)\n}\n\n// NewMetric returns new metric registered to this registry\n// TODO have multiple versions returning specific metric types when we have such things\nfunc (r *Registry) NewMetric(name string, typ MetricType, t ...ValueType) (*Metric, error) {\n\tr.l.Lock()\n\tdefer r.l.Unlock()\n\n\tif !checkName(name) {\n\t\treturn nil, fmt.Errorf(\"Invalid metric name: '%s'. %s\", name, badNameWarning) //nolint:staticcheck\n\t}\n\toldMetric, ok := r.metrics[name]\n\n\tif !ok {\n\t\tm := r.newMetric(name, typ, t...)\n\t\tr.metrics[name] = m\n\t\treturn m, nil\n\t}\n\tif oldMetric.Type != typ {\n\t\treturn nil, fmt.Errorf(\"metric '%s' already exists but with type %s, instead of %s\", name, oldMetric.Type, typ)\n\t}\n\tif len(t) > 0 {\n\t\tif t[0] != oldMetric.Contains {\n\t\t\treturn nil, fmt.Errorf(\"metric '%s' already exists but with a value type %s, instead of %s\",\n\t\t\t\tname, oldMetric.Contains, t[0])\n\t\t}\n\t}\n\treturn oldMetric, nil\n}\n\n// MustNewMetric is like NewMetric, but will panic if there is an error\nfunc (r *Registry) MustNewMetric(name string, typ MetricType, t ...ValueType) *Metric {\n\tm, err := r.NewMetric(name, typ, t...)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn m\n}\n\n// All returns all the registered metrics.\nfunc (r *Registry) All() []*Metric {\n\tr.l.RLock()\n\tdefer r.l.RUnlock()\n\n\tif len(r.metrics) < 1 {\n\t\treturn nil\n\t}\n\ts := make([]*Metric, 0, len(r.metrics))\n\tfor _, m := range r.metrics {\n\t\ts = append(s, m)\n\t}\n\treturn s\n}\n\nfunc (r *Registry) newMetric(name string, mt MetricType, vt ...ValueType) *Metric {\n\tvalueType := Default\n\tif len(vt) > 0 {\n\t\tvalueType = vt[0]\n\t}\n\n\tsink := NewSink(mt)\n\treturn &Metric{\n\t\tregistry: r,\n\t\tName:     name,\n\t\tType:     mt,\n\t\tContains: valueType,\n\t\tSink:     sink,\n\t}\n}\n\n// Get returns the Metric with the given name. If that metric doesn't exist,\n// Get() will return a nil value.\nfunc (r *Registry) Get(name string) *Metric {\n\treturn r.metrics[name]\n}\n\n// RootTagSet is the empty root set that all other TagSets must originate from.\nfunc (r *Registry) RootTagSet() *TagSet {\n\treturn (*TagSet)(r.rootTagSet)\n}\n"
  },
  {
    "path": "metrics/registry_test.go",
    "content": "package metrics\n\nimport (\n\t\"strconv\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestRegistryNewMetric(t *testing.T) {\n\tt.Parallel()\n\tr := NewRegistry()\n\n\tsomethingCounter, err := r.NewMetric(\"something\", Counter)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"something\", somethingCounter.Name)\n\n\tsomethingCounterAgain, err := r.NewMetric(\"something\", Counter)\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"something\", somethingCounterAgain.Name)\n\trequire.Same(t, somethingCounter, somethingCounterAgain)\n\n\t_, err = r.NewMetric(\"something\", Gauge)\n\trequire.Error(t, err)\n\n\t_, err = r.NewMetric(\"something\", Counter, Time)\n\trequire.Error(t, err)\n}\n\nfunc TestMetricNames(t *testing.T) {\n\tt.Parallel()\n\ttestMap := map[string]bool{\n\t\t\"simple\":       true,\n\t\t\"still_simple\": true,\n\t\t\"\":             false,\n\t\t\"@\":            false,\n\t\t\"a\":            false, // too short\n\t\t\"special\\n\\t\":  false,\n\t\t// this has both hangul and japanese numerals .\n\t\t\"hello.World_in_한글一안녕一세상\": false,\n\t\t// too long\n\t\t\"tooolooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooog\": false,\n\t}\n\n\tfor key, value := range testMap {\n\t\tt.Run(key, func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tassert.Equal(t, value, checkName(key), key)\n\t\t})\n\t}\n}\n\nfunc TestRegistryBranchTagSetRootWith(t *testing.T) {\n\tt.Parallel()\n\n\traw := map[string]string{\n\t\t\"key\":  \"val\",\n\t\t\"key2\": \"val2\",\n\t}\n\n\tr := NewRegistry()\n\ttags := r.RootTagSet().WithTagsFromMap(raw)\n\trequire.NotNil(t, tags)\n\n\tassert.Equal(t, raw, tags.Map())\n}\n\nfunc TestRegistryAll(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Empty\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tr := NewRegistry()\n\t\tassert.Nil(t, r.All())\n\t})\n\n\tt.Run(\"MultipleItems\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tr := NewRegistry()\n\n\t\texp := make([]string, 5)\n\t\tfor i := 1; i <= 5; i++ {\n\t\t\tname := \"metric\" + strconv.Itoa(i)\n\t\t\t_, err := r.NewMetric(name, Counter)\n\t\t\trequire.NoError(t, err)\n\n\t\t\texp[i-1] = name\n\t\t}\n\t\tmetrics := r.All()\n\t\trequire.Len(t, metrics, 5)\n\n\t\tnames := func(m []*Metric) []string {\n\t\t\ts := make([]string, len(m))\n\t\t\tfor i := range m {\n\t\t\t\ts[i] = m[i].Name\n\t\t\t}\n\t\t\treturn s\n\t\t}\n\t\tassert.ElementsMatch(t, exp, names(metrics))\n\t})\n}\n"
  },
  {
    "path": "metrics/sample.go",
    "content": "package metrics\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// A TimeSeries uniquely identifies the metric and the set of metric tags that a\n// Sample (i.e. a metric measurement) has. TimeSeries objects are comparable\n// with the == operator and can be used as map indexes.\ntype TimeSeries struct {\n\tMetric *Metric\n\tTags   *TagSet\n}\n\n// A Sample is a single metric measurement at a specific point in time. It can\n// have two sets of string key=value metadata:\n//   - indexed Tags for low-cardinality data that are part of the TimeSeries\n//   - optional non-indexed Metadata that are meant for high-cardinality information\ntype Sample struct {\n\tTimeSeries\n\tTime  time.Time\n\tValue float64\n\n\t// Optional high-cardinality metadata that won't be indexed in atlas.\n\t//\n\t// It can be nil if it wasn't explicitly specified, reduce memory\n\t// allocations and GC overhead.\n\tMetadata map[string]string\n}\n\n// SampleContainer is a simple abstraction that allows sample\n// producers to attach extra information to samples they return\ntype SampleContainer interface {\n\tGetSamples() []Sample\n}\n\n// Samples is just the simplest SampleContainer implementation\n// that will be used when there's no need for extra information\ntype Samples []Sample\n\n// GetSamples just implements the SampleContainer interface\nfunc (s Samples) GetSamples() []Sample {\n\treturn s\n}\n\n// ConnectedSampleContainer is an extension of the SampleContainer\n// interface that should be implemented when emitted samples\n// are connected and share the same time and tags.\ntype ConnectedSampleContainer interface {\n\tSampleContainer\n\tGetTags() *TagSet\n\tGetTime() time.Time\n}\n\n// ConnectedSamples is the simplest ConnectedSampleContainer\n// implementation that will be used when there's no need for\n// extra information\ntype ConnectedSamples struct {\n\tSamples []Sample\n\tTags    *TagSet\n\tTime    time.Time\n}\n\n// GetSamples implements the SampleContainer and ConnectedSampleContainer\n// interfaces and returns the stored slice with samples.\nfunc (cs ConnectedSamples) GetSamples() []Sample {\n\treturn cs.Samples\n}\n\n// GetTags implements ConnectedSampleContainer interface and returns stored tags.\nfunc (cs ConnectedSamples) GetTags() *TagSet {\n\treturn cs.Tags\n}\n\n// GetTime implements ConnectedSampleContainer interface and returns stored time.\nfunc (cs ConnectedSamples) GetTime() time.Time {\n\treturn cs.Time\n}\n\n// GetSamples implement the ConnectedSampleContainer interface\n// for a single Sample, since it's obviously connected with itself :)\nfunc (s Sample) GetSamples() []Sample {\n\treturn []Sample{s}\n}\n\n// GetTags implements ConnectedSampleContainer interface\n// and returns the sample's tags.\nfunc (s Sample) GetTags() *TagSet {\n\treturn s.Tags\n}\n\n// GetTime just implements ConnectedSampleContainer interface\n// and returns the sample's time.\nfunc (s Sample) GetTime() time.Time {\n\treturn s.Time\n}\n\n// Ensure that interfaces are implemented correctly\nvar (\n\t_ SampleContainer = Sample{}\n\t_ SampleContainer = Samples{}\n)\n\nvar (\n\t_ ConnectedSampleContainer = Sample{}\n\t_ ConnectedSampleContainer = ConnectedSamples{}\n)\n\n// GetBufferedSamples will read all present (i.e. buffered or currently being pushed)\n// values in the input channel and return them as a slice.\nfunc GetBufferedSamples(input <-chan SampleContainer) (result []SampleContainer) {\n\tfor {\n\t\tselect {\n\t\tcase val, ok := <-input:\n\t\t\tif !ok {\n\t\t\t\treturn result\n\t\t\t}\n\t\t\tresult = append(result, val)\n\t\tdefault:\n\t\t\treturn result\n\t\t}\n\t}\n}\n\n// PushIfNotDone first checks if the supplied context is done and doesn't push\n// the sample container if it is.\nfunc PushIfNotDone(ctx context.Context, output chan<- SampleContainer, sample SampleContainer) bool {\n\tif ctx.Err() != nil {\n\t\treturn false\n\t}\n\toutput <- sample\n\treturn true\n}\n\n// GetResolversForTrendColumns checks if passed trend columns are valid for use in\n// the summary output and then returns a map of the corresponding resolvers.\nfunc GetResolversForTrendColumns(trendColumns []string) (map[string]func(s *TrendSink) float64, error) {\n\tstaticResolvers := map[string]func(s *TrendSink) float64{\n\t\t\"avg\":   func(s *TrendSink) float64 { return s.Avg() },\n\t\t\"min\":   func(s *TrendSink) float64 { return s.Min() },\n\t\t\"med\":   func(s *TrendSink) float64 { return s.P(0.5) },\n\t\t\"max\":   func(s *TrendSink) float64 { return s.Max() },\n\t\t\"count\": func(s *TrendSink) float64 { return float64(s.Count()) },\n\t}\n\tdynamicResolver := func(percentile float64) func(s *TrendSink) float64 {\n\t\treturn func(s *TrendSink) float64 {\n\t\t\treturn s.P(percentile / 100)\n\t\t}\n\t}\n\n\tresult := make(map[string]func(s *TrendSink) float64, len(trendColumns))\n\n\tfor _, stat := range trendColumns {\n\t\tif staticStat, ok := staticResolvers[stat]; ok {\n\t\t\tresult[stat] = staticStat\n\t\t\tcontinue\n\t\t}\n\n\t\tpercentile, err := parsePercentile(stat)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult[stat] = dynamicResolver(percentile)\n\t}\n\n\treturn result, nil\n}\n\n// parsePercentile is a helper function to parse and validate percentile notations\nfunc parsePercentile(stat string) (float64, error) {\n\tif !strings.HasPrefix(stat, \"p(\") || !strings.HasSuffix(stat, \")\") {\n\t\treturn 0, fmt.Errorf(\"invalid trend stat '%s', unknown format\", stat)\n\t}\n\n\tpercentile, err := strconv.ParseFloat(stat[2:len(stat)-1], 64)\n\n\tif err != nil || (percentile < 0) || (percentile > 100) {\n\t\treturn 0, fmt.Errorf(\"invalid percentile trend stat value '%s', provide a number between 0 and 100\", stat)\n\t}\n\n\treturn percentile, nil\n}\n"
  },
  {
    "path": "metrics/sample_test.go",
    "content": "package metrics\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSampleImplementations(t *testing.T) {\n\tt.Parallel()\n\tr := NewRegistry()\n\tsampleTags := r.RootTagSet().With(\"key1\", \"val1\").With(\"key2\", \"val2\")\n\tnow := time.Now()\n\n\tsample := Sample{\n\t\tTimeSeries: TimeSeries{\n\t\t\tMetric: r.MustNewMetric(\"test_metric\", Counter),\n\t\t\tTags:   sampleTags,\n\t\t},\n\t\tTime:  now,\n\t\tValue: 1.0,\n\t}\n\tsamples := Samples(sample.GetSamples())\n\tcSamples := ConnectedSamples{\n\t\tSamples: []Sample{sample},\n\t\tTime:    now,\n\t\tTags:    sampleTags,\n\t}\n\texp := []Sample{sample}\n\tassert.Equal(t, exp, sample.GetSamples())\n\tassert.Equal(t, exp, samples.GetSamples())\n\tassert.Equal(t, exp, cSamples.GetSamples())\n\tassert.Equal(t, now, sample.GetTime())\n\tassert.Equal(t, now, cSamples.GetTime())\n\tassert.Equal(t, sample.GetTags(), cSamples.GetTags())\n}\n\nfunc TestGetResolversForTrendColumnsValidation(t *testing.T) {\n\tt.Parallel()\n\tvalidateTests := []struct {\n\t\tstats  []string\n\t\texpErr bool\n\t}{\n\t\t{[]string{}, false},\n\t\t{[]string{\"avg\", \"min\", \"med\", \"max\", \"p(0)\", \"p(99)\", \"p(99.999)\", \"count\"}, false},\n\t\t{[]string{\"avg\", \"p(err)\"}, true},\n\t\t{[]string{\"nil\", \"p(err)\"}, true},\n\t\t{[]string{\"p90\"}, true},\n\t\t{[]string{\"p(90\"}, true},\n\t\t{[]string{\" avg\"}, true},\n\t\t{[]string{\"avg \"}, true},\n\t\t{[]string{\"\", \"avg \"}, true},\n\t\t{[]string{\"p(-1)\"}, true},\n\t\t{[]string{\"p(101)\"}, true},\n\t\t{[]string{\"p(1)\"}, false},\n\t}\n\n\tfor _, tc := range validateTests {\n\t\tt.Run(fmt.Sprintf(\"%v\", tc.stats), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\t_, err := GetResolversForTrendColumns(tc.stats)\n\t\t\tif tc.expErr {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetResolversForTrendColumnsCalculation(t *testing.T) {\n\tt.Parallel()\n\n\tcustomResolversTests := []struct {\n\t\tstats      string\n\t\tpercentile float64\n\t}{\n\t\t{\"p(50)\", 0.5},\n\t\t{\"p(99)\", 0.99},\n\t\t{\"p(99.9)\", 0.999},\n\t\t{\"p(99.99)\", 0.9999},\n\t\t{\"p(99.999)\", 0.99999},\n\t}\n\n\tfor _, tc := range customResolversTests {\n\t\tt.Run(fmt.Sprintf(\"%v\", tc.stats), func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := createTestTrendSink(100)\n\n\t\t\tres, err := GetResolversForTrendColumns([]string{tc.stats})\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.Len(t, res, 1)\n\t\t\tfor k := range res {\n\t\t\t\tassert.InDelta(t, sink.P(tc.percentile), res[k](sink), 0.000001)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc createTestTrendSink(count int) *TrendSink {\n\tsink := NewTrendSink()\n\n\tfor i := range count {\n\t\tsink.Add(Sample{Value: float64(i)})\n\t}\n\n\treturn sink\n}\n"
  },
  {
    "path": "metrics/sink.go",
    "content": "package metrics\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"sort\"\n\t\"time\"\n)\n\nvar (\n\t_ Sink = &CounterSink{}\n\t_ Sink = &GaugeSink{}\n\t_ Sink = NewTrendSink()\n\t_ Sink = &RateSink{}\n)\n\n// Sink is a sample sink which will accumulate data in specific way\ntype Sink interface {\n\tAdd(s Sample)                              // Add a sample to the sink.\n\tFormat(t time.Duration) map[string]float64 // Data for thresholds.\n\tIsEmpty() bool                             // Check if the Sink is empty.\n}\n\n// NewSink creates the related Sink for\n// the provided MetricType.\nfunc NewSink(mt MetricType) Sink {\n\tvar sink Sink\n\tswitch mt {\n\tcase Counter:\n\t\tsink = &CounterSink{}\n\tcase Gauge:\n\t\tsink = &GaugeSink{}\n\tcase Trend:\n\t\tsink = NewTrendSink()\n\tcase Rate:\n\t\tsink = &RateSink{}\n\tdefault:\n\t\t// Should not be possible to create\n\t\t// an invalid metric type except for specific\n\t\t// and controlled tests\n\t\tpanic(fmt.Sprintf(\"MetricType %q is not supported\", mt))\n\t}\n\treturn sink\n}\n\n// CounterSink is a sink that represents a Counter\ntype CounterSink struct {\n\tValue float64\n\tFirst time.Time\n}\n\n// Add a single sample to the sink\nfunc (c *CounterSink) Add(s Sample) {\n\tc.Value += s.Value\n\tif c.First.IsZero() {\n\t\tc.First = s.Time\n\t}\n}\n\n// IsEmpty indicates whether the CounterSink is empty.\nfunc (c *CounterSink) IsEmpty() bool { return c.First.IsZero() }\n\n// Format counter and return a map\nfunc (c *CounterSink) Format(t time.Duration) map[string]float64 {\n\treturn map[string]float64{\n\t\t\"count\": c.Value,\n\t\t\"rate\":  c.Rate(t),\n\t}\n}\n\n// Rate calculates the rate (per second) of the counter,\n// based on the given duration.\nfunc (c *CounterSink) Rate(t time.Duration) float64 {\n\tif t == 0 {\n\t\treturn 0\n\t}\n\treturn c.Value / (float64(t) / float64(time.Second))\n}\n\n// GaugeSink is a sink represents a Gauge\ntype GaugeSink struct {\n\tValue    float64\n\tMax, Min float64\n\tminSet   bool\n}\n\n// IsEmpty indicates whether the GaugeSink is empty.\nfunc (g *GaugeSink) IsEmpty() bool { return !g.minSet }\n\n// Add a single sample to the sink\nfunc (g *GaugeSink) Add(s Sample) {\n\tg.Value = s.Value\n\tif s.Value > g.Max {\n\t\tg.Max = s.Value\n\t}\n\tif s.Value < g.Min || !g.minSet {\n\t\tg.Min = s.Value\n\t\tg.minSet = true\n\t}\n}\n\n// Format gauge and return a map\nfunc (g *GaugeSink) Format(_ time.Duration) map[string]float64 {\n\treturn map[string]float64{\"value\": g.Value}\n}\n\n// NewTrendSink makes a Trend sink with the OpenHistogram circllhist histogram.\nfunc NewTrendSink() *TrendSink {\n\treturn &TrendSink{}\n}\n\n// TrendSink is a sink for a Trend\ntype TrendSink struct {\n\tvalues []float64\n\tsorted bool\n\n\tcount    uint64\n\tmin, max float64\n\tsum      float64\n}\n\n// IsEmpty indicates whether the TrendSink is empty.\nfunc (t *TrendSink) IsEmpty() bool { return t.count == 0 }\n\n// Add a single sample into the trend\nfunc (t *TrendSink) Add(s Sample) {\n\tif t.count == 0 {\n\t\tt.max, t.min = s.Value, s.Value\n\t} else {\n\t\tif s.Value > t.max {\n\t\t\tt.max = s.Value\n\t\t}\n\t\tif s.Value < t.min {\n\t\t\tt.min = s.Value\n\t\t}\n\t}\n\n\tt.values = append(t.values, s.Value)\n\tt.sorted = false\n\tt.count++\n\tt.sum += s.Value\n}\n\n// P calculates the given percentile from sink values.\nfunc (t *TrendSink) P(pct float64) float64 {\n\tswitch t.count {\n\tcase 0:\n\t\treturn 0\n\tcase 1:\n\t\treturn t.values[0]\n\tdefault:\n\t\tif !t.sorted {\n\t\t\tsort.Float64s(t.values)\n\t\t\tt.sorted = true\n\t\t}\n\n\t\t// If percentile falls on a value in Values slice, we return that value.\n\t\t// If percentile does not fall on a value in Values slice, we calculate (linear interpolation)\n\t\t// the value that would fall at percentile, given the values above and below that percentile.\n\t\ti := pct * (float64(t.count) - 1.0)\n\t\tj := t.values[int(math.Floor(i))]\n\t\tk := t.values[int(math.Ceil(i))]\n\t\tf := i - math.Floor(i)\n\t\treturn j + (k-j)*f\n\t}\n}\n\n// Min returns the minimum value.\nfunc (t *TrendSink) Min() float64 {\n\treturn t.min\n}\n\n// Max returns the maximum value.\nfunc (t *TrendSink) Max() float64 {\n\treturn t.max\n}\n\n// Count returns the number of recorded values.\nfunc (t *TrendSink) Count() uint64 {\n\treturn t.count\n}\n\n// Avg returns the average (i.e. mean) value.\nfunc (t *TrendSink) Avg() float64 {\n\tif t.count > 0 {\n\t\treturn t.sum / float64(t.count)\n\t}\n\treturn 0\n}\n\n// Total returns the total (i.e. \"sum\") value for all measurements.\nfunc (t *TrendSink) Total() float64 {\n\treturn t.sum\n}\n\n// Format trend and return a map\nfunc (t *TrendSink) Format(_ time.Duration) map[string]float64 {\n\t// TODO: respect the summaryTrendStats for REST API\n\treturn map[string]float64{\n\t\t\"min\":   t.Min(),\n\t\t\"max\":   t.Max(),\n\t\t\"avg\":   t.Avg(),\n\t\t\"med\":   t.P(0.5),\n\t\t\"p(90)\": t.P(0.90),\n\t\t\"p(95)\": t.P(0.95),\n\t}\n}\n\n// RateSink is a sink for a rate\ntype RateSink struct {\n\tTrues int64\n\tTotal int64\n}\n\n// IsEmpty indicates whether the RateSink is empty.\nfunc (r *RateSink) IsEmpty() bool { return r.Total == 0 }\n\n// Add a single sample to the rate\nfunc (r *RateSink) Add(s Sample) {\n\tr.Total++\n\tif s.Value != 0 {\n\t\tr.Trues++\n\t}\n}\n\n// Format rate and return a map\nfunc (r RateSink) Format(_ time.Duration) map[string]float64 {\n\tvar rate float64\n\tif r.Total > 0 {\n\t\trate = float64(r.Trues) / float64(r.Total)\n\t}\n\n\treturn map[string]float64{\"rate\": rate}\n}\n"
  },
  {
    "path": "metrics/sink_test.go",
    "content": "package metrics\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNewSink(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tsink any\n\t\tmt   MetricType\n\t}{\n\t\t{mt: Counter, sink: &CounterSink{}},\n\t\t{mt: Gauge, sink: &GaugeSink{}},\n\t\t{mt: Rate, sink: &RateSink{}},\n\t\t{mt: Trend, sink: NewTrendSink()},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.sink, NewSink(tc.mt))\n\t}\n}\n\nfunc TestNewSinkInvalidMetricType(t *testing.T) {\n\tt.Parallel()\n\tassert.Panics(t, func() { NewSink(MetricType(6)) })\n}\n\nfunc TestCounterSink(t *testing.T) {\n\tt.Parallel()\n\tsamples10 := []float64{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 100.0}\n\tnow := time.Now()\n\n\tt.Run(\"add\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"one value\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := CounterSink{}\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 1.0, Time: now})\n\t\t\tassert.Equal(t, 1.0, sink.Value)\n\t\t\tassert.Equal(t, now, sink.First)\n\t\t})\n\t\tt.Run(\"values\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := CounterSink{}\n\t\t\tfor _, s := range samples10 {\n\t\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s, Time: now})\n\t\t\t}\n\t\t\tassert.Equal(t, 145.0, sink.Value)\n\t\t\tassert.Equal(t, now, sink.First)\n\t\t})\n\t})\n\tt.Run(\"format\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tsink := CounterSink{}\n\t\tfor _, s := range samples10 {\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s, Time: now})\n\t\t}\n\t\tassert.Equal(t, map[string]float64{\"count\": 145, \"rate\": 145.0}, sink.Format(1*time.Second))\n\t})\n}\n\nfunc TestGaugeSink(t *testing.T) {\n\tt.Parallel()\n\tsamples6 := []float64{1.0, 2.0, 3.0, 4.0, 10.0, 5.0}\n\n\tt.Run(\"add\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"one value\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := GaugeSink{}\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 1.0})\n\t\t\tassert.Equal(t, 1.0, sink.Value)\n\t\t\tassert.Equal(t, 1.0, sink.Min)\n\t\t\tassert.Equal(t, true, sink.minSet)\n\t\t\tassert.Equal(t, 1.0, sink.Max)\n\t\t})\n\t\tt.Run(\"values\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := GaugeSink{}\n\t\t\tfor _, s := range samples6 {\n\t\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t\t}\n\t\t\tassert.Equal(t, 5.0, sink.Value)\n\t\t\tassert.Equal(t, 1.0, sink.Min)\n\t\t\tassert.Equal(t, true, sink.minSet)\n\t\t\tassert.Equal(t, 10.0, sink.Max)\n\t\t})\n\t})\n\tt.Run(\"format\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tsink := GaugeSink{}\n\t\tfor _, s := range samples6 {\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t}\n\t\tassert.Equal(t, map[string]float64{\"value\": 5.0}, sink.Format(0))\n\t})\n}\n\nfunc TestTrendSink(t *testing.T) {\n\tt.Parallel()\n\n\tunsortedSamples10 := []float64{0.0, 100.0, 30.0, 80.0, 70.0, 60.0, 50.0, 40.0, 90.0, 20.0}\n\n\tt.Run(\"add\", func(t *testing.T) {\n\t\tt.Run(\"one value\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 7.0})\n\t\t\tassert.Equal(t, uint64(1), sink.Count())\n\t\t\tassert.Equal(t, 7.0, sink.Min())\n\t\t\tassert.Equal(t, 7.0, sink.Max())\n\t\t\tassert.Equal(t, 7.0, sink.Avg())\n\t\t\tassert.Equal(t, 7.0, sink.Total())\n\t\t\tassert.Equal(t, []float64{7.0}, sink.values)\n\t\t})\n\t\tt.Run(\"values\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tfor _, s := range unsortedSamples10 {\n\t\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t\t}\n\t\t\tassert.Equal(t, uint64(len(unsortedSamples10)), sink.Count())\n\t\t\tassert.Equal(t, 0.0, sink.Min())\n\t\t\tassert.Equal(t, 100.0, sink.Max())\n\t\t\tassert.Equal(t, 54.0, sink.Avg())\n\t\t\tassert.Equal(t, 540.0, sink.Total())\n\t\t\tassert.Equal(t, unsortedSamples10, sink.values)\n\t\t})\n\t\tt.Run(\"negative\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tfor _, s := range []float64{-10, -20} {\n\t\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t\t}\n\t\t\tassert.Equal(t, uint64(2), sink.Count())\n\t\t\tassert.Equal(t, -20.0, sink.Min())\n\t\t\tassert.Equal(t, -10.0, sink.Max())\n\t\t\tassert.Equal(t, -15.0, sink.Avg())\n\t\t\tassert.Equal(t, -30.0, sink.Total())\n\t\t\tassert.Equal(t, []float64{-10, -20}, sink.values)\n\t\t})\n\t\tt.Run(\"mixed\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tfor _, s := range []float64{1.4, 0, -1.2} {\n\t\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t\t}\n\t\t\tassert.Equal(t, uint64(3), sink.Count())\n\t\t\tassert.Equal(t, -1.2, sink.Min())\n\t\t\tassert.Equal(t, 1.4, sink.Max())\n\t\t\tassert.Equal(t, 0.067, math.Round(sink.Avg()*1000)/1000)\n\t\t\tassert.Equal(t, 0.199, math.Floor(sink.Total()*1000)/1000)\n\t\t\tassert.Equal(t, []float64{1.4, 0, -1.2}, sink.values)\n\t\t})\n\t})\n\n\ttolerance := 0.000001\n\tt.Run(\"percentile\", func(t *testing.T) {\n\t\tt.Run(\"no values\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tfor i := 1; i <= 100; i++ {\n\t\t\t\tassert.Equal(t, 0.0, sink.P(float64(i)/100.0))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"one value\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 10.0})\n\t\t\tfor i := 1; i <= 100; i++ {\n\t\t\t\tassert.Equal(t, 10.0, sink.P(float64(i)/100.0))\n\t\t\t}\n\t\t})\n\t\tt.Run(\"two values\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 5.0})\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 10.0})\n\t\t\tassert.Equal(t, false, sink.sorted)\n\t\t\tassert.Equal(t, 5.0, sink.P(0.0))\n\t\t\tassert.Equal(t, 7.5, sink.P(0.5))\n\t\t\tassert.Equal(t, 5+(10-5)*0.95, sink.P(0.95))\n\t\t\tassert.Equal(t, 5+(10-5)*0.99, sink.P(0.99))\n\t\t\tassert.Equal(t, 10.0, sink.P(1.0))\n\t\t\tassert.Equal(t, true, sink.sorted)\n\t\t})\n\t\tt.Run(\"more than 2\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tsink := NewTrendSink()\n\t\t\tfor _, s := range unsortedSamples10 {\n\t\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t\t}\n\t\t\tassert.InDelta(t, 0.0, sink.P(0.0), tolerance)\n\t\t\tassert.InDelta(t, 55.0, sink.P(0.5), tolerance)\n\t\t\tassert.InDelta(t, 95.5, sink.P(0.95), tolerance)\n\t\t\tassert.InDelta(t, 99.1, sink.P(0.99), tolerance)\n\t\t\tassert.InDelta(t, 100.0, sink.P(1.0), tolerance)\n\t\t\tassert.Equal(t, true, sink.sorted)\n\t\t})\n\t})\n\tt.Run(\"format\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tsink := NewTrendSink()\n\t\tfor _, s := range unsortedSamples10 {\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t}\n\t\texpected := map[string]float64{\n\t\t\t\"min\":   0.0,\n\t\t\t\"max\":   100.0,\n\t\t\t\"avg\":   54.0,\n\t\t\t\"med\":   55.0,\n\t\t\t\"p(90)\": 91.0,\n\t\t\t\"p(95)\": 95.5,\n\t\t}\n\t\tresult := sink.Format(0)\n\t\trequire.Equal(t, len(expected), len(result))\n\t\tfor k, expV := range expected {\n\t\t\tassert.Contains(t, result, k)\n\t\t\tassert.InDelta(t, expV, result[k], tolerance)\n\t\t}\n\t})\n}\n\nfunc TestRateSink(t *testing.T) {\n\tt.Parallel()\n\tsamples6 := []float64{1.0, 0.0, 1.0, 0.0, 0.0, 1.0}\n\n\tt.Run(\"add\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tt.Run(\"one true\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := RateSink{}\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 1.0})\n\t\t\tassert.Equal(t, int64(1), sink.Total)\n\t\t\tassert.Equal(t, int64(1), sink.Trues)\n\t\t})\n\t\tt.Run(\"one false\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := RateSink{}\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: 0.0})\n\t\t\tassert.Equal(t, int64(1), sink.Total)\n\t\t\tassert.Equal(t, int64(0), sink.Trues)\n\t\t})\n\t\tt.Run(\"values\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\t\t\tsink := RateSink{}\n\t\t\tfor _, s := range samples6 {\n\t\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t\t}\n\t\t\tassert.Equal(t, int64(6), sink.Total)\n\t\t\tassert.Equal(t, int64(3), sink.Trues)\n\t\t})\n\t})\n\tt.Run(\"format\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tsink := RateSink{}\n\t\tfor _, s := range samples6 {\n\t\t\tsink.Add(Sample{TimeSeries: TimeSeries{Metric: &Metric{}}, Value: s})\n\t\t}\n\t\tassert.Equal(t, map[string]float64{\"rate\": 0.5}, sink.Format(0))\n\t})\n}\n"
  },
  {
    "path": "metrics/system_tag.go",
    "content": "package metrics\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"sort\"\n\t\"strings\"\n)\n\n// SystemTag values are bit-shifted identifiers of all of the various system tags that k6 has.\n//\n//go:generate enumer -type=SystemTag -transform=snake -trimprefix=Tag -output system_tag_gen.go\ntype SystemTag uint32\n\n// SystemTagSet is a bitmask that is used to keep track which system tags should\n// be included in metric Samples.\ntype SystemTagSet SystemTag\n\n// Default system tags includes all of the system tags emitted with metrics by default.\nconst (\n\tTagProto SystemTag = 1 << iota\n\tTagSubproto\n\tTagStatus\n\tTagMethod\n\tTagURL\n\tTagName\n\tTagGroup\n\tTagCheck\n\tTagError\n\tTagErrorCode\n\tTagTLSVersion\n\tTagScenario\n\tTagService\n\tTagExpectedResponse\n\n\t// System tags not enabled by default.\n\tTagIter // non-indexable\n\tTagVU   // non-indexable\n\tTagOCSPStatus\n\tTagIP\n)\n\n// DefaultSystemTagSet includes all of the system tags emitted with metrics by default.\n// Other tags that are not enabled by default include: iter, vu, ocsp_status, ip\n//\n//nolint:gochecknoglobals\nvar DefaultSystemTagSet = SystemTagSet(\n\tTagProto | TagSubproto | TagStatus | TagMethod | TagURL | TagName | TagGroup |\n\t\tTagCheck | TagError | TagErrorCode | TagTLSVersion | TagScenario | TagService | TagExpectedResponse)\n\n// NonIndexableSystemTags are high cardinality system tags (i.e. metadata).\n//\n//nolint:gochecknoglobals\nvar NonIndexableSystemTags = SystemTagSet(TagIter | TagVU)\n\n// Add adds a tag to tag set.\nfunc (i *SystemTagSet) Add(tag SystemTag) {\n\tif i == nil {\n\t\ti = new(SystemTagSet)\n\t}\n\t*i |= SystemTagSet(tag)\n}\n\n// Has checks a tag included in tag set.\nfunc (i *SystemTagSet) Has(tag SystemTag) bool {\n\tif i == nil {\n\t\treturn false\n\t}\n\treturn *i&SystemTagSet(tag) != 0\n}\n\n// Map returns the EnabledTags with current value from SystemTagSet\nfunc (i SystemTagSet) Map() EnabledTags {\n\tm := EnabledTags{}\n\tfor _, tag := range SystemTagValues() {\n\t\tif i.Has(tag) {\n\t\t\tm[tag.String()] = true\n\t\t}\n\t}\n\treturn m\n}\n\n// SetString returns comma separated list of the string representation of all values in the set\nfunc (i SystemTagSet) SetString() string {\n\tvar keys []string\n\tfor _, tag := range SystemTagValues() {\n\t\tif i.Has(tag) {\n\t\t\tkeys = append(keys, tag.String())\n\t\t}\n\t}\n\treturn strings.Join(keys, \",\")\n}\n\n// ToSystemTagSet converts list of tags to SystemTagSet\n// TODO: emit error instead of discarding invalid values.\nfunc ToSystemTagSet(tags []string) *SystemTagSet {\n\tts := new(SystemTagSet)\n\tfor _, tag := range tags {\n\t\tif v, err := SystemTagString(tag); err == nil {\n\t\t\tts.Add(v)\n\t\t}\n\t}\n\treturn ts\n}\n\n// NewSystemTagSet returns a SystemTagSet from input.\nfunc NewSystemTagSet(tags ...SystemTag) *SystemTagSet {\n\tts := new(SystemTagSet)\n\tfor _, tag := range tags {\n\t\tts.Add(tag)\n\t}\n\treturn ts\n}\n\n// MarshalJSON converts the SystemTagSet to a list (JS array).\nfunc (i *SystemTagSet) MarshalJSON() ([]byte, error) {\n\tvar tags []string\n\tfor _, tag := range SystemTagValues() {\n\t\tif i.Has(tag) {\n\t\t\ttags = append(tags, tag.String())\n\t\t}\n\t}\n\tsort.Strings(tags)\n\n\treturn json.Marshal(tags)\n}\n\n// UnmarshalJSON converts the tag list back to expected tag set.\nfunc (i *SystemTagSet) UnmarshalJSON(data []byte) error {\n\tvar tags []string\n\tif err := json.Unmarshal(data, &tags); err != nil {\n\t\treturn err\n\t}\n\tif len(tags) != 0 {\n\t\t*i = *ToSystemTagSet(tags)\n\t}\n\n\treturn nil\n}\n\n// UnmarshalText converts the tag list to SystemTagSet.\nfunc (i *SystemTagSet) UnmarshalText(data []byte) error {\n\tlist := bytes.SplitSeq(data, []byte(\",\"))\n\n\tfor key := range list {\n\t\tkey := strings.TrimSpace(string(key))\n\t\tif key == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif v, err := SystemTagString(key); err == nil {\n\t\t\ti.Add(v)\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "metrics/system_tag_gen.go",
    "content": "// Code generated by \"enumer -type=SystemTag -transform=snake -trimprefix=Tag -output system_tag_gen.go\"; DO NOT EDIT.\n\npackage metrics\n\nimport (\n\t\"fmt\"\n)\n\nconst _SystemTagName = \"protosubprotostatusmethodurlnamegroupcheckerrorerror_codetls_versionscenarioserviceexpected_responseitervuocsp_statusip\"\n\nvar _SystemTagMap = map[SystemTag]string{\n\t1:      _SystemTagName[0:5],\n\t2:      _SystemTagName[5:13],\n\t4:      _SystemTagName[13:19],\n\t8:      _SystemTagName[19:25],\n\t16:     _SystemTagName[25:28],\n\t32:     _SystemTagName[28:32],\n\t64:     _SystemTagName[32:37],\n\t128:    _SystemTagName[37:42],\n\t256:    _SystemTagName[42:47],\n\t512:    _SystemTagName[47:57],\n\t1024:   _SystemTagName[57:68],\n\t2048:   _SystemTagName[68:76],\n\t4096:   _SystemTagName[76:83],\n\t8192:   _SystemTagName[83:100],\n\t16384:  _SystemTagName[100:104],\n\t32768:  _SystemTagName[104:106],\n\t65536:  _SystemTagName[106:117],\n\t131072: _SystemTagName[117:119],\n}\n\nfunc (i SystemTag) String() string {\n\tif str, ok := _SystemTagMap[i]; ok {\n\t\treturn str\n\t}\n\treturn fmt.Sprintf(\"SystemTag(%d)\", i)\n}\n\nvar _SystemTagValues = []SystemTag{1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072}\n\nvar _SystemTagNameToValueMap = map[string]SystemTag{\n\t_SystemTagName[0:5]:     1,\n\t_SystemTagName[5:13]:    2,\n\t_SystemTagName[13:19]:   4,\n\t_SystemTagName[19:25]:   8,\n\t_SystemTagName[25:28]:   16,\n\t_SystemTagName[28:32]:   32,\n\t_SystemTagName[32:37]:   64,\n\t_SystemTagName[37:42]:   128,\n\t_SystemTagName[42:47]:   256,\n\t_SystemTagName[47:57]:   512,\n\t_SystemTagName[57:68]:   1024,\n\t_SystemTagName[68:76]:   2048,\n\t_SystemTagName[76:83]:   4096,\n\t_SystemTagName[83:100]:  8192,\n\t_SystemTagName[100:104]: 16384,\n\t_SystemTagName[104:106]: 32768,\n\t_SystemTagName[106:117]: 65536,\n\t_SystemTagName[117:119]: 131072,\n}\n\n// SystemTagString retrieves an enum value from the enum constants string name.\n// Throws an error if the param is not part of the enum.\nfunc SystemTagString(s string) (SystemTag, error) {\n\tif val, ok := _SystemTagNameToValueMap[s]; ok {\n\t\treturn val, nil\n\t}\n\treturn 0, fmt.Errorf(\"%s does not belong to SystemTag values\", s)\n}\n\n// SystemTagValues returns all values of the enum\nfunc SystemTagValues() []SystemTag {\n\treturn _SystemTagValues\n}\n\n// IsASystemTag returns \"true\" if the value is listed in the enum definition. \"false\" otherwise\nfunc (i SystemTag) IsASystemTag() bool {\n\t_, ok := _SystemTagMap[i]\n\treturn ok\n}\n"
  },
  {
    "path": "metrics/system_tag_test.go",
    "content": "package metrics\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSystemTagSetMarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\ttagset   SystemTagSet\n\t\texpected string\n\t}{\n\t\t{SystemTagSet(TagIP), `[\"ip\"]`},\n\t\t{SystemTagSet(TagIP | TagProto | TagGroup), `[\"group\",\"ip\",\"proto\"]`},\n\t\t{0, `null`},\n\t}\n\n\tfor _, tc := range tests {\n\t\tts := tc.tagset\n\t\tgot, err := json.Marshal(&ts)\n\t\trequire.Nil(t, err)\n\t\trequire.Equal(t, tc.expected, string(got))\n\t}\n}\n\nfunc TestSystemTagSet_UnmarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\ttags []byte\n\t\tsets []SystemTag\n\t}{\n\t\t{[]byte(`[]`), []SystemTag{}},\n\t\t{[]byte(`[\"ip\", \"proto\"]`), []SystemTag{TagIP, TagProto}},\n\t}\n\n\tfor _, tc := range tests {\n\t\tts := new(SystemTagSet)\n\t\trequire.Nil(t, json.Unmarshal(tc.tags, ts))\n\t\tfor _, tag := range tc.sets {\n\t\t\tassert.True(t, ts.Has(tag))\n\t\t}\n\t}\n}\n\nfunc TestSystemTagSetTextUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\ttestMatrix := map[string]SystemTag{\n\t\t\"\":                      0,\n\t\t\"ip\":                    TagIP,\n\t\t\"ip,proto\":              TagIP | TagProto,\n\t\t\"   ip  ,  proto  \":     TagIP | TagProto,\n\t\t\"   ip  ,   ,  proto  \": TagIP | TagProto,\n\t\t\"   ip  ,,  proto  ,,\":  TagIP | TagProto,\n\t}\n\n\tfor input, expected := range testMatrix {\n\t\tset := new(SystemTagSet)\n\t\terr := set.UnmarshalText([]byte(input))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, SystemTagSet(expected), *set)\n\t}\n}\n\nfunc TestTagSetMarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\ttagset   EnabledTags\n\t\texpected string\n\t}{\n\t\t{tagset: EnabledTags{\"ip\": true, \"proto\": true, \"group\": true, \"custom\": true}, expected: `[\"custom\",\"group\",\"ip\",\"proto\"]`},\n\t\t{tagset: EnabledTags{}, expected: `[]`},\n\t}\n\n\tfor _, tc := range tests {\n\t\tts := tc.tagset\n\t\tgot, err := json.Marshal(&ts)\n\t\trequire.Nil(t, err)\n\t\trequire.Equal(t, tc.expected, string(got))\n\t}\n}\n\nfunc TestTagSet_UnmarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\ttags []byte\n\t\tsets EnabledTags\n\t}{\n\t\t{[]byte(`[]`), EnabledTags{}},\n\t\t{[]byte(`[\"ip\",\"custom\", \"proto\"]`), EnabledTags{\"ip\": true, \"proto\": true, \"custom\": true}},\n\t}\n\n\tfor _, tc := range tests {\n\t\tts := new(EnabledTags)\n\t\trequire.Nil(t, json.Unmarshal(tc.tags, ts))\n\t\tfor tag := range tc.sets {\n\t\t\tassert.True(t, (*ts)[tag])\n\t\t}\n\t}\n}\n\nfunc TestTagSetTextUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\ttestMatrix := map[string]EnabledTags{\n\t\t\"\":                           make(EnabledTags),\n\t\t\"ip\":                         {\"ip\": true},\n\t\t\"ip,proto\":                   {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,  proto  \":          {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,   ,  proto  \":      {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,,  proto  ,,\":       {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,custom,  proto  ,,\": {\"ip\": true, \"custom\": true, \"proto\": true},\n\t}\n\n\tfor input, expected := range testMatrix {\n\t\tset := new(EnabledTags)\n\t\terr := set.UnmarshalText([]byte(input))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, *set)\n\t}\n}\n"
  },
  {
    "path": "metrics/tags.go",
    "content": "package metrics\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"maps\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/mailru/easyjson\"\n\t\"github.com/mailru/easyjson/jlexer\"\n\t\"github.com/mailru/easyjson/jwriter\"\n\t\"github.com/mstoykov/atlas\"\n)\n\n// A TagSet represents an immutable set of metric tags. For the efficient and\n// thread-safe storage of the key=value tag pairs, it uses the\n// https://github.com/mstoykov/atlas data structure.\n//\n// Assuming all tag sets start from the same root (see Registry.RootTagSet()),\n// you can compare *TagSet values of different metric Samples with the `==` Go\n// operator to check if they have the same tags, and you can also use *TagSet\n// values for map indexes and caching.\n//\n// See also the TimeSeries type for comparing a Sample's {metric+tags} for\n// equality at the same time.\ntype TagSet atlas.Node\n\n// With returns another TagSet object that contains the combination of the\n// current receiver tags and the name=value tag from its parameters.\n//\n// It doesn't modify the receiver, it will either return an already existing\n// TagSet with these tags, if it exists, or create a new TagSet with them and\n// return it.\n//\n// If a tag with the specified name already exists in the set, it will be\n// overwritten with the new value in the returned set.\nfunc (ts *TagSet) With(name, value string) *TagSet {\n\treturn (*TagSet)(((*atlas.Node)(ts)).AddLink(name, value))\n}\n\n// Without returns another TagSet object that contains all of the tags from the\n// existing TagSet except the one with the given key.\n//\n// It doesn't modify the receiver, it will either return an already existing\n// TagSet with these tags, if it exists, or create a new TagSet with them and\n// return it.\n//\n// If a tag with the specified name doesn't exist in the set, it will return the\n// receiver.\nfunc (ts *TagSet) Without(name string) *TagSet {\n\treturn (*TagSet)(((*atlas.Node)(ts)).DeleteKey(name))\n}\n\n// Get returns the value of the tag with the given name and true, if that tag\n// exists in the set, and an empty string and false otherwise.\nfunc (ts *TagSet) Get(name string) (string, bool) {\n\treturn ((*atlas.Node)(ts)).ValueByKey(name)\n}\n\n// Contains checks that each key=value tag pair in the provided TagSet exists in\n// the receiver tag set as well, i.e. that the given set is a sub-set of it.\nfunc (ts *TagSet) Contains(other *TagSet) bool {\n\treturn ((*atlas.Node)(ts)).Contains((*atlas.Node)(other))\n}\n\n// IsEmpty checks if the tag set is empty, i.e. if it's the root atlas node.\nfunc (ts *TagSet) IsEmpty() bool {\n\treturn ((*atlas.Node)(ts)).IsRoot()\n}\n\n// Map returns a {key: value} string map with all of the tags in the set.\nfunc (ts *TagSet) Map() map[string]string {\n\treturn ((*atlas.Node)(ts)).Path()\n}\n\n// WithTagsFromMap sorts the given tags by their keys and adds them to the\n// current tag set one by one, without branching out. This is generally\n// discouraged and sequential usage of the TagSet.With() method should be\n// preferred and used in a consistent sequence, whenever possible.\n//\n// The only place this method should be used is if we already have a\n// map[string]string of tags, e.g. with the test-wide --tags from the root, with\n// scenario.tags, with custom per-request tags from a user, etc. Then it's more\n// efficient to sort their keys before we add them. If we don't, go map\n// iteration happens in pseudo-random order and this will generate a lot of\n// useless dead-end atlas Nodes on multiple TagSet accretions.\nfunc (ts *TagSet) WithTagsFromMap(m map[string]string) *TagSet {\n\tif len(m) == 0 {\n\t\treturn ts\n\t}\n\n\t// We sort the keys so the TagSet generation is consistent across multiple\n\t// invocations. This should create fewer dead-end atlas Nodes.\n\tkeys := make([]string, 0, len(m))\n\tfor k := range m {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Strings(keys)\n\n\ttags := ts\n\tfor i := 0; i < len(keys); i++ {\n\t\ttags = tags.With(keys[i], m[keys[i]])\n\t}\n\n\treturn tags\n}\n\n// MarshalEasyJSON supports easyjson.Marshaler interface for better performance.\nfunc (ts *TagSet) MarshalEasyJSON(w *jwriter.Writer) {\n\tw.RawByte('{')\n\tfirst := true\n\n\tn := (*atlas.Node)(ts)\n\tfor !n.IsRoot() {\n\t\tprev, key, value := n.Data()\n\t\tif first {\n\t\t\tfirst = false\n\t\t} else {\n\t\t\tw.RawByte(',')\n\t\t}\n\t\tw.String(key)\n\t\tw.RawByte(':')\n\t\tw.String(value)\n\t\tn = prev\n\t}\n\tw.RawByte('}')\n}\n\n// MarshalJSON serializes the tags to a JSON string.\nfunc (ts *TagSet) MarshalJSON() ([]byte, error) {\n\tw := &jwriter.Writer{NoEscapeHTML: true}\n\tts.MarshalEasyJSON(w)\n\treturn w.Buffer.BuildBytes(), w.Error\n}\n\n// UnmarshalEasyJSON WILL ALWAYS RETURN AN ERROR because a TagSet needs to be\n// started from a common atlas root. This function exists to prevent any\n// automatic reflection-based attempts at unmarshaling.\nfunc (ts *TagSet) UnmarshalEasyJSON(l *jlexer.Lexer) {\n\tl.AddError(errors.New(\"metrics.TagSet cannot be directly unmarshalled from JSON\"))\n}\n\n// UnmarshalJSON WILL ALWAYS RETURN AN ERROR because a TagSet needs to be\n// started from a common atlas root. This function exists to prevent any\n// automatic reflection-based attempts at unmarshaling.\nfunc (ts *TagSet) UnmarshalJSON([]byte) error {\n\treturn errors.New(\"metrics.TagSet cannot be directly unmarshalled from JSON\")\n}\n\n// Ensure *TagSet implements the listed interfaces at compile-time.\nvar _ interface {\n\teasyjson.Marshaler\n\teasyjson.Unmarshaler\n\tjson.Marshaler\n\tjson.Unmarshaler\n} = &TagSet{}\n\n// TagsAndMeta is a helper type that provides easy group manipulation of the\n// indexed Tags and the non-indexed Metadata values together. While both of them\n// are part of a metric Sample, the TagsAndMeta type isn't used there because\n// the Tags participate in the Sample's TimeSeries and the Metadata does not.\n//\n// Instead, this type is mostly used by the VU and JS code while it assembles\n// the final consolidated Tags and Metadata values to put in the Sample.\n//\n// IMPORTANT: this data structure is not thread safe! The methods of the\n// lib.VUStateTags type are where the synchronization happens.\ntype TagsAndMeta struct {\n\tTags     *TagSet\n\tMetadata map[string]string // could be nil\n}\n\n// SetTag adds the given key=value tag to the Tags.\nfunc (tm *TagsAndMeta) SetTag(key, value string) {\n\ttm.Tags = tm.Tags.With(key, value)\n}\n\n// SetMetadata adds the given key=value datum to the Metadata.\nfunc (tm *TagsAndMeta) SetMetadata(key, value string) {\n\tif tm.Metadata == nil {\n\t\ttm.Metadata = map[string]string{key: value}\n\t\treturn\n\t}\n\ttm.Metadata[key] = value\n}\n\n// SetSystemTagOrMetaIfEnabled checks if the supplied SystemTag is enabled in\n// this test run (i.e. is in the SystemTagSet) and passes it to\n// SetSystemTagOrMeta() if it is.\nfunc (tm *TagsAndMeta) SetSystemTagOrMetaIfEnabled(enabledSystemTags *SystemTagSet, tag SystemTag, value string) {\n\tif !enabledSystemTags.Has(tag) {\n\t\treturn\n\t}\n\ttm.SetSystemTagOrMeta(tag, value)\n}\n\n// SetSystemTagOrMeta automatically adds the system tag either as an indexed tag\n// or an unindexed one (metadata), based on the NonIndexableSystemTags set.\nfunc (tm *TagsAndMeta) SetSystemTagOrMeta(tag SystemTag, value string) {\n\tif NonIndexableSystemTags.Has(tag) {\n\t\ttm.SetMetadata(tag.String(), value)\n\t} else {\n\t\ttm.SetTag(tag.String(), value)\n\t}\n}\n\n// DeleteTag removes the given key from tags.\nfunc (tm *TagsAndMeta) DeleteTag(key string) {\n\ttm.Tags = tm.Tags.Without(key)\n}\n\n// DeleteMetadata removes the given key from metadata.\nfunc (tm *TagsAndMeta) DeleteMetadata(key string) {\n\tif tm.Metadata != nil {\n\t\tdelete(tm.Metadata, key)\n\t}\n}\n\n// Clone makes a complete copy of the current TagsAndMeta object and returns it.\nfunc (tm TagsAndMeta) Clone() TagsAndMeta {\n\tres := TagsAndMeta{Tags: tm.Tags}\n\tif tm.Metadata == nil {\n\t\treturn res\n\t}\n\tres.Metadata = make(map[string]string, len(tm.Metadata))\n\tmaps.Copy(res.Metadata, tm.Metadata)\n\treturn res\n}\n\n// EnabledTags is a string to bool map (for lookup efficiency) that is used to keep track\n// of which system tags and non-system tags to include.\n//\n// TODO: move to types.StringSet or something like that, this isn't metrics specific\ntype EnabledTags map[string]bool\n\n// UnmarshalText converts the tag list to EnabledTags.\nfunc (i *EnabledTags) UnmarshalText(data []byte) error {\n\tlist := bytes.Split(data, []byte(\",\"))\n\tif *i == nil {\n\t\t*i = make(EnabledTags, len(list))\n\t}\n\n\tfor _, key := range list {\n\t\tkey := strings.TrimSpace(string(key))\n\t\tif key == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\t(*i)[key] = true\n\t}\n\n\treturn nil\n}\n\n// MarshalJSON converts the EnabledTags to a list (JS array).\nfunc (i *EnabledTags) MarshalJSON() ([]byte, error) {\n\tvar tags []string\n\tif *i != nil {\n\t\ttags = make([]string, 0, len(*i))\n\t\tfor tag := range *i {\n\t\t\ttags = append(tags, tag)\n\t\t}\n\t\tsort.Strings(tags)\n\t}\n\n\treturn json.Marshal(tags)\n}\n\n// UnmarshalJSON converts the tag list back to expected tag set.\nfunc (i *EnabledTags) UnmarshalJSON(data []byte) error {\n\tvar tags []string\n\tif err := json.Unmarshal(data, &tags); err != nil {\n\t\treturn err\n\t}\n\t*i = make(EnabledTags, len(tags))\n\tfor _, tag := range tags {\n\t\t(*i)[tag] = true\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "metrics/tags_test.go",
    "content": "package metrics\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestTagsWith(t *testing.T) {\n\tt.Parallel()\n\n\ttm := NewRegistry().RootTagSet().With(\"key1\", \"val1\")\n\ttm2 := tm.With(\"key2\", \"val2\")\n\ttm = tm.With(\"key3\", \"val3\")\n\n\tassert.Equal(t, map[string]string{\"key1\": \"val1\", \"key3\": \"val3\"}, tm.Map())\n\tassert.Equal(t, map[string]string{\n\t\t\"key1\": \"val1\",\n\t\t\"key2\": \"val2\",\n\t}, tm2.Map())\n\n\tassert.Equal(t, map[string]string{\"key2\": \"val2\"}, tm2.Without(\"key1\").Map())\n}\n\nfunc TestRootTagSet(t *testing.T) {\n\tt.Parallel()\n\n\tr := NewRegistry()\n\n\troot := r.RootTagSet()\n\trequire.NotNil(t, root)\n\tassert.True(t, root == r.RootTagSet())\n\tassert.True(t, root == root.Without(\"foo\"))\n\tassert.True(t, root.IsEmpty())\n\tassert.Equal(t, map[string]string{}, root.Map())\n\n\tval, ok := root.Get(\"foo\")\n\tassert.False(t, ok)\n\tassert.Empty(t, val)\n\n\trJSON, err := root.MarshalJSON()\n\trequire.NoError(t, err)\n\tassert.Equal(t, \"{}\", string(rJSON))\n}\n\nfunc TestTagSets(t *testing.T) {\n\tt.Parallel()\n\n\tr := NewRegistry()\n\troot := r.RootTagSet()\n\n\ttags := root.With(\"tag1\", \"value1\")\n\tassert.True(t, root != tags)\n\tassert.True(t, tags == root.With(\"tag1\", \"value1\"))\n\tassert.False(t, tags.IsEmpty())\n\tassert.Equal(t, map[string]string{\"tag1\": \"value1\"}, tags.Map())\n\n\ttags2 := tags.\n\t\tWith(\"tag2\", \"value2\").\n\t\tWithTagsFromMap(map[string]string{\"tag1\": \"foo\", \"tag3\": \"value3\"}).\n\t\tWithout(\"tag3\")\n\n\tassert.Equal(t, map[string]string{\"tag1\": \"foo\", \"tag2\": \"value2\"}, tags2.Map())\n\n\tval, ok := tags2.Get(\"foo\")\n\tassert.False(t, ok)\n\tassert.Empty(t, val)\n\n\tval, ok = tags2.Get(\"tag1\")\n\tassert.True(t, ok)\n\tassert.Equal(t, val, \"foo\")\n\n\tassert.True(t, tags2 == tags2.Without(\"foo\"))\n\n\trJSON, err := tags2.MarshalJSON()\n\trequire.NoError(t, err)\n\tassert.Equal(t, `{\"tag1\":\"foo\",\"tag2\":\"value2\"}`, string(rJSON))\n\n\tassert.True(t, tags2.Contains(root))\n\tassert.False(t, tags2.Contains(tags))\n\n\ttags3 := tags.With(\"tag1\", \"foo\")\n\tassert.True(t, tags2.Contains(tags3))\n\ttags4 := tags3.With(\"tag3\", \"value3\")\n\tassert.False(t, tags2.Contains(tags4))\n\tassert.False(t, tags4.Contains(tags2))\n\tassert.True(t, tags4.Contains(tags3))\n\tassert.True(t, tags4.Contains(tags4))\n}\n\nfunc TestBigTagSetMarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\texpectedJSON := `{\"tag0\":\"value0\",\"tag1\":\"value1\",\"tag2\":\"value2\",\"tag3\":\"value3\",\"tag4\":\"value4\",\"tag5\":\"value5\",\"tag6\":\"value6\",\"tag7\":\"value7\"}`\n\tassert.Greater(t, len(expectedJSON), 128)\n\n\ttags := NewRegistry().RootTagSet()\n\tfor i := range 8 {\n\t\ttags = tags.With(fmt.Sprintf(\"tag%d\", i), fmt.Sprintf(\"value%d\", i))\n\t}\n\n\trJSON, err := tags.MarshalJSON()\n\trequire.NoError(t, err)\n\tassert.Equal(t, expectedJSON, string(rJSON))\n}\n\nfunc TestTagSetContains(t *testing.T) {\n\tt.Parallel()\n\n\tr := NewRegistry()\n\troot := r.RootTagSet()\n\n\tst := root.With(\"maintag\", \"mainvalue\")\n\n\tbranch := st.With(\"tag1\", \"val1\").With(\"tag2\", \"val2\")\n\tinner := st.With(\"tag1\", \"val1\")\n\touter := st.With(\"tag3\", \"val2\")\n\n\tassert.True(t, st.Contains(st))\n\tassert.True(t, branch.Contains(st))\n\tassert.True(t, branch.Contains(inner))\n\tassert.False(t, branch.Contains(outer))\n\tassert.False(t, st.Contains(outer))\n}\n\nfunc TestTagsAndMetaSetTag(t *testing.T) {\n\tt.Parallel()\n\n\tr := NewRegistry()\n\ttm := TagsAndMeta{Tags: r.RootTagSet()}\n\ttm.SetTag(\"k1\", \"v1\")\n\t_, ok := tm.Tags.Get(\"k1\")\n\tassert.True(t, ok)\n}\n\nfunc TestTagsAndMetaDeleteTag(t *testing.T) {\n\tt.Parallel()\n\n\tr := NewRegistry()\n\ttm := TagsAndMeta{Tags: r.RootTagSet()}\n\ttm.Tags = tm.Tags.With(\"k1\", \"v1\")\n\t_, ok := tm.Tags.Get(\"k1\")\n\tassert.True(t, ok)\n\n\ttm.DeleteTag(\"k1\")\n\t_, ok = tm.Tags.Get(\"k1\")\n\tassert.False(t, ok)\n}\n\nfunc TestTagsAndMetaSetMetadata(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"WhenNil\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttm := TagsAndMeta{}\n\t\ttm.SetMetadata(\"k1\", \"v1\")\n\t\t_, ok := tm.Metadata[\"k1\"]\n\t\tassert.True(t, ok)\n\t})\n\n\tt.Run(\"WhenNotNil\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\ttm := TagsAndMeta{Metadata: make(map[string]string)}\n\t\ttm.SetMetadata(\"k2\", \"v2\")\n\t\t_, ok := tm.Metadata[\"k2\"]\n\t\tassert.True(t, ok)\n\t})\n}\n\nfunc TestTagsAndMetaDeleteMetadata(t *testing.T) {\n\tt.Parallel()\n\n\ttm := TagsAndMeta{Metadata: make(map[string]string)}\n\ttm.Metadata[\"k1\"] = \"v1\"\n\t_, ok := tm.Metadata[\"k1\"]\n\tassert.True(t, ok)\n\n\ttm.DeleteMetadata(\"k1\")\n\t_, ok = tm.Metadata[\"k1\"]\n\tassert.False(t, ok)\n}\n\nfunc TestTagsAndMetaSetSystemTagOrMetaIfEnabled(t *testing.T) {\n\tt.Parallel()\n\ttm := TagsAndMeta{}\n\n\ttm.SetSystemTagOrMetaIfEnabled(&DefaultSystemTagSet, TagIter, \"10\")\n\t_, ok := tm.Metadata[\"iter\"]\n\tassert.False(t, ok)\n\n\ttm.SetSystemTagOrMetaIfEnabled(&NonIndexableSystemTags, TagIter, \"10\")\n\t_, ok = tm.Metadata[\"iter\"]\n\tassert.True(t, ok)\n}\n\nfunc TestTagsAndMetaSetSystemTagOrMeta(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"Tag\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tr := NewRegistry()\n\t\ttm := TagsAndMeta{Tags: r.RootTagSet()}\n\t\ttm.SetSystemTagOrMeta(TagIter, \"10\")\n\n\t\t_, ok := tm.Metadata[\"iter\"]\n\t\tassert.True(t, ok)\n\t\t_, ok = tm.Tags.Get(\"iter\")\n\t\tassert.False(t, ok)\n\t})\n\n\tt.Run(\"Metadata\", func(t *testing.T) {\n\t\tt.Parallel()\n\t\tr := NewRegistry()\n\t\ttm := TagsAndMeta{Tags: r.RootTagSet()}\n\t\ttm.SetSystemTagOrMeta(TagName, \"hello-request\")\n\n\t\t_, ok := tm.Tags.Get(\"name\")\n\t\tassert.True(t, ok)\n\t\t_, ok = tm.Metadata[\"name\"]\n\t\tassert.False(t, ok)\n\t})\n}\n\nfunc TestTagsAndMetaClone(t *testing.T) {\n\tt.Parallel()\n\n\tr := NewRegistry()\n\ttags := r.RootTagSet().With(\"k1\", \"v1\")\n\tmeta := map[string]string{\"k2\": \"v2\"}\n\ttm := TagsAndMeta{Tags: tags, Metadata: meta}\n\n\ttm2 := tm.Clone()\n\trequire.NotNil(t, tm2.Tags)\n\trequire.NotNil(t, tm2.Metadata)\n\tassert.Equal(t, tm, tm2)\n\tassert.False(t, &tm.Metadata == &tm2.Metadata)\n}\n\nfunc TestEnabledTagsMarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\ttagset   EnabledTags\n\t\texpected string\n\t}{\n\t\t{tagset: EnabledTags{\"ip\": true, \"proto\": true, \"group\": true, \"custom\": true}, expected: `[\"custom\",\"group\",\"ip\",\"proto\"]`},\n\t\t{tagset: EnabledTags{}, expected: `[]`},\n\t}\n\n\tfor _, tc := range tests {\n\t\tts := tc.tagset\n\t\tgot, err := json.Marshal(&ts)\n\t\trequire.Nil(t, err)\n\t\trequire.Equal(t, tc.expected, string(got))\n\t}\n}\n\nfunc TestEnabledTagsUnmarshalJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\ttags []byte\n\t\tsets EnabledTags\n\t}{\n\t\t{[]byte(`[]`), EnabledTags{}},\n\t\t{[]byte(`[\"ip\",\"custom\", \"proto\"]`), EnabledTags{\"ip\": true, \"proto\": true, \"custom\": true}},\n\t}\n\n\tfor _, tc := range tests {\n\t\tts := new(EnabledTags)\n\t\trequire.Nil(t, json.Unmarshal(tc.tags, ts))\n\t\tfor tag := range tc.sets {\n\t\t\tassert.True(t, (*ts)[tag])\n\t\t}\n\t}\n}\n\nfunc TestEnabledTagsTextUnmarshal(t *testing.T) {\n\tt.Parallel()\n\n\ttestMatrix := map[string]EnabledTags{\n\t\t\"\":                           make(EnabledTags),\n\t\t\"ip\":                         {\"ip\": true},\n\t\t\"ip,proto\":                   {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,  proto  \":          {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,   ,  proto  \":      {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,,  proto  ,,\":       {\"ip\": true, \"proto\": true},\n\t\t\"   ip  ,custom,  proto  ,,\": {\"ip\": true, \"custom\": true, \"proto\": true},\n\t}\n\n\tfor input, expected := range testMatrix {\n\t\tset := new(EnabledTags)\n\t\terr := set.UnmarshalText([]byte(input))\n\t\trequire.NoError(t, err)\n\t\trequire.Equal(t, expected, *set)\n\t}\n}\n"
  },
  {
    "path": "metrics/thresholds.go",
    "content": "package metrics\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/lib/types\"\n)\n\n// Threshold is a representation of a single threshold for a single metric\ntype Threshold struct {\n\t// Source is the text based source of the threshold\n\tSource string\n\t// LastFailed is a marker if the last testing of this threshold failed\n\tLastFailed bool\n\t// AbortOnFail marks if a given threshold fails that the whole test should be aborted\n\tAbortOnFail bool\n\t// AbortGracePeriod is a the minimum amount of time a test should be running before a failing\n\t// this threshold will abort the test\n\tAbortGracePeriod types.NullDuration\n\t// parsed is the threshold expression parsed from the Source\n\tparsed *thresholdExpression\n}\n\nfunc newThreshold(src string, abortOnFail bool, gracePeriod types.NullDuration) *Threshold {\n\treturn &Threshold{\n\t\tSource:           src,\n\t\tAbortOnFail:      abortOnFail,\n\t\tAbortGracePeriod: gracePeriod,\n\t\tparsed:           nil,\n\t}\n}\n\nfunc (t *Threshold) runNoTaint(sinks map[string]float64) (bool, error) {\n\t// Extract the sink value for the aggregation method used in the threshold\n\t// expression. Considering we already validated thresholds before starting\n\t// the execution, we assume that a missing sink entry means that no samples\n\t// are available yet, and that it's safe to ignore this run.\n\tlhs, ok := sinks[t.parsed.SinkKey()]\n\tif !ok {\n\t\treturn true, nil\n\t}\n\n\t// Apply the threshold expression operator to the left and\n\t// right hand side values\n\tvar passes bool\n\tswitch t.parsed.Operator {\n\tcase \">\":\n\t\tpasses = lhs > t.parsed.Value\n\tcase \">=\":\n\t\tpasses = lhs >= t.parsed.Value\n\tcase \"<=\":\n\t\tpasses = lhs <= t.parsed.Value\n\tcase \"<\":\n\t\tpasses = lhs < t.parsed.Value\n\tcase \"==\", \"===\":\n\t\t// Considering a sink always maps to float64 values,\n\t\t// strictly equal is equivalent to loosely equal\n\t\tpasses = lhs == t.parsed.Value\n\tcase \"!=\":\n\t\tpasses = lhs != t.parsed.Value\n\tdefault:\n\t\t// The parseThresholdExpression function should ensure that no invalid\n\t\t// operator gets through, but let's protect our future selves anyhow.\n\t\treturn false, fmt.Errorf(\"unable to apply threshold %s over metrics; \"+\n\t\t\t\"reason: %s is an invalid operator\",\n\t\t\tt.Source,\n\t\t\tt.parsed.Operator,\n\t\t)\n\t}\n\n\t// Perform the actual threshold verification\n\treturn passes, nil\n}\n\nfunc (t *Threshold) run(sinks map[string]float64) (bool, error) {\n\tpasses, err := t.runNoTaint(sinks)\n\tt.LastFailed = !passes\n\treturn passes, err\n}\n\ntype thresholdConfig struct {\n\tThreshold        string             `json:\"threshold\"`\n\tAbortOnFail      bool               `json:\"abortOnFail\"`\n\tAbortGracePeriod types.NullDuration `json:\"delayAbortEval\"`\n}\n\n// used internally for JSON marshalling\ntype rawThresholdConfig thresholdConfig\n\nfunc (tc *thresholdConfig) UnmarshalJSON(data []byte) error {\n\t// shortcircuit unmarshalling for simple string format\n\tif err := json.Unmarshal(data, &tc.Threshold); err == nil {\n\t\treturn nil\n\t}\n\n\trawConfig := (*rawThresholdConfig)(tc)\n\treturn json.Unmarshal(data, rawConfig)\n}\n\nfunc (tc thresholdConfig) MarshalJSON() ([]byte, error) {\n\tvar data any = tc.Threshold\n\tif tc.AbortOnFail {\n\t\tdata = rawThresholdConfig(tc)\n\t}\n\n\treturn MarshalJSONWithoutHTMLEscape(data)\n}\n\n// Thresholds is the combination of all Thresholds for a given metric\ntype Thresholds struct {\n\tThresholds []*Threshold\n\tAbort      bool\n\tsinked     map[string]float64\n}\n\n// NewThresholds returns Thresholds objects representing the provided source strings\nfunc NewThresholds(sources []string) Thresholds {\n\ttcs := make([]thresholdConfig, len(sources))\n\tfor i, source := range sources {\n\t\ttcs[i].Threshold = source\n\t}\n\n\treturn newThresholdsWithConfig(tcs)\n}\n\nfunc newThresholdsWithConfig(configs []thresholdConfig) Thresholds {\n\tthresholds := make([]*Threshold, len(configs))\n\tsinked := make(map[string]float64)\n\n\tfor i, config := range configs {\n\t\tt := newThreshold(config.Threshold, config.AbortOnFail, config.AbortGracePeriod)\n\t\tthresholds[i] = t\n\t}\n\n\treturn Thresholds{thresholds, false, sinked}\n}\n\nfunc (ts *Thresholds) runAll(timeSpentInTest time.Duration) (bool, error) {\n\tsucceeded := true\n\tfor i, threshold := range ts.Thresholds {\n\t\tb, err := threshold.run(ts.sinked)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"threshold %d run error: %w\", i, err)\n\t\t}\n\n\t\tif !b {\n\t\t\tsucceeded = false\n\n\t\t\tif ts.Abort || !threshold.AbortOnFail {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tts.Abort = !threshold.AbortGracePeriod.Valid ||\n\t\t\t\tthreshold.AbortGracePeriod.Duration < types.Duration(timeSpentInTest)\n\t\t}\n\t}\n\n\treturn succeeded, nil\n}\n\n// Run processes all the thresholds with the provided Sink at the provided time and returns if any\n// of them fails\nfunc (ts *Thresholds) Run(sink Sink, duration time.Duration) (bool, error) {\n\t// Initialize the sinks store\n\tts.sinked = make(map[string]float64)\n\n\t// FIXME: Remove this comment as soon as the metrics.Sink does not expose Format anymore.\n\t//\n\t// As of December 2021, this block reproduces the behavior of the\n\t// metrics.Sink.Format behavior. As we intend to try to get away from it,\n\t// we instead implement the behavior directly here.\n\t//\n\t// For more details, see https://github.com/grafana/k6/issues/2320\n\tswitch sinkImpl := sink.(type) {\n\tcase *CounterSink:\n\t\tts.sinked[\"count\"] = sinkImpl.Value\n\t\tts.sinked[\"rate\"] = sinkImpl.Value / (float64(duration) / float64(time.Second))\n\tcase *GaugeSink:\n\t\tts.sinked[\"value\"] = sinkImpl.Value\n\tcase *TrendSink:\n\t\tts.sinked[\"min\"] = sinkImpl.Min()\n\t\tts.sinked[\"max\"] = sinkImpl.Max()\n\t\tts.sinked[\"avg\"] = sinkImpl.Avg()\n\t\tts.sinked[\"med\"] = sinkImpl.P(0.5)\n\n\t\t// Parse the percentile thresholds and insert them in\n\t\t// the sinks mapping.\n\t\tfor _, threshold := range ts.Thresholds {\n\t\t\tif threshold.parsed.AggregationMethod != tokenPercentile {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tkey := fmt.Sprintf(\"p(%g)\", threshold.parsed.AggregationValue.Float64)\n\t\t\tts.sinked[key] = sinkImpl.P(threshold.parsed.AggregationValue.Float64 / 100)\n\t\t}\n\tcase *RateSink:\n\t\t// We want to avoid division by zero, which\n\t\t// would lead to [#2520](https://github.com/grafana/k6/issues/2520)\n\t\tif sinkImpl.Total > 0 {\n\t\t\tts.sinked[\"rate\"] = float64(sinkImpl.Trues) / float64(sinkImpl.Total)\n\t\t}\n\tdefault:\n\t\treturn false, fmt.Errorf(\"unable to run Thresholds; reason: unknown sink type\")\n\t}\n\n\treturn ts.runAll(duration)\n}\n\n// Parse parses the Thresholds and fills each Threshold.parsed field with the result.\n// It effectively asserts they are syntaxically correct.\nfunc (ts *Thresholds) Parse() error {\n\tfor _, t := range ts.Thresholds {\n\t\tparsed, err := parseThresholdExpression(t.Source)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tt.parsed = parsed\n\t}\n\n\treturn nil\n}\n\n// ErrInvalidThreshold indicates a threshold is not valid\nvar ErrInvalidThreshold = errors.New(\"invalid threshold\")\n\n// Validate ensures a threshold definition is consistent with the metric it applies to.\n// Given a metric registry and a metric name to apply the expressions too, Validate will\n// assert that each threshold expression uses an aggregation method that's supported by the\n// provided metric. It returns an error otherwise.\n// Note that this function expects the passed in thresholds to have been parsed already, and\n// have their Parsed (ThresholdExpression) field already filled.\nfunc (ts *Thresholds) Validate(metricName string, r *Registry) error {\n\tparsedMetricName, _, err := ParseMetricName(metricName)\n\tif err != nil {\n\t\tparseErr := fmt.Errorf(\"unable to validate threshold expressions; reason: %w\", err)\n\t\treturn errext.WithExitCodeIfNone(parseErr, exitcodes.InvalidConfig)\n\t}\n\n\t// Obtain the metric the thresholds apply to from the registry.\n\t// if the metric doesn't exist, then we return an error indicating\n\t// the InvalidConfig exitcode should be used.\n\tmetric := r.Get(parsedMetricName)\n\tif metric == nil {\n\t\terr := fmt.Errorf(\"%w defined on %s; reason: no metric name %q found\", ErrInvalidThreshold, metricName, metricName)\n\t\treturn errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)\n\t}\n\n\tfor _, threshold := range ts.Thresholds {\n\t\t// Return a digestable error if we attempt to validate a threshold\n\t\t// that hasn't been parsed yet.\n\t\tif threshold.parsed == nil {\n\t\t\tthresholdExpression, err := parseThresholdExpression(threshold.Source)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"unable to validate threshold %q on metric %s; reason: \"+\n\t\t\t\t\t\"parsing threshold failed %w\", threshold.Source, metricName, err)\n\t\t\t}\n\n\t\t\tthreshold.parsed = thresholdExpression\n\t\t}\n\n\t\t// If the threshold's expression aggregation method is not\n\t\t// supported for the metric we validate against, then we return\n\t\t// an error indicating the InvalidConfig exitcode should be used.\n\t\tif !metric.Type.supportsAggregationMethod(threshold.parsed.AggregationMethod) {\n\t\t\terr := fmt.Errorf(\n\t\t\t\t\"%w %q applied on metric %s; reason: \"+\n\t\t\t\t\t\"unsupported aggregation method %s on metric of type %s. \"+\n\t\t\t\t\t\"supported aggregation methods for this metric are: %s\",\n\t\t\t\tErrInvalidThreshold, threshold.Source, metricName,\n\t\t\t\tthreshold.parsed.AggregationMethod, metric.Type,\n\t\t\t\tstrings.Join(metric.Type.supportedAggregationMethods(), \", \"),\n\t\t\t)\n\t\t\treturn errext.WithExitCodeIfNone(err, exitcodes.InvalidConfig)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// UnmarshalJSON is implementation of json.Unmarshaler\nfunc (ts *Thresholds) UnmarshalJSON(data []byte) error {\n\tvar configs []thresholdConfig\n\tif err := json.Unmarshal(data, &configs); err != nil {\n\t\treturn err\n\t}\n\n\t*ts = newThresholdsWithConfig(configs)\n\n\treturn nil\n}\n\n// MarshalJSON is implementation of json.Marshaler\nfunc (ts Thresholds) MarshalJSON() ([]byte, error) {\n\tconfigs := make([]thresholdConfig, len(ts.Thresholds))\n\tfor i, t := range ts.Thresholds {\n\t\tconfigs[i].Threshold = t.Source\n\t\tconfigs[i].AbortOnFail = t.AbortOnFail\n\t\tconfigs[i].AbortGracePeriod = t.AbortGracePeriod\n\t}\n\n\treturn MarshalJSONWithoutHTMLEscape(configs)\n}\n\n// MarshalJSONWithoutHTMLEscape marshals t to JSON without escaping characters\n// for safe use in HTML.\nfunc MarshalJSONWithoutHTMLEscape(t any) ([]byte, error) {\n\tbuffer := &bytes.Buffer{}\n\tencoder := json.NewEncoder(buffer)\n\tencoder.SetEscapeHTML(false)\n\terr := encoder.Encode(t)\n\tbytes := buffer.Bytes()\n\tif err == nil && len(bytes) > 0 {\n\t\t// Remove the newline appended by Encode() :-/\n\t\t// See https://github.com/golang/go/issues/37083\n\t\tbytes = bytes[:len(bytes)-1]\n\t}\n\treturn bytes, err\n}\n\nvar (\n\t_ json.Unmarshaler = &Thresholds{}\n\t_ json.Marshaler   = &Thresholds{}\n)\n"
  },
  {
    "path": "metrics/thresholds_parser.go",
    "content": "package metrics\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"gopkg.in/guregu/null.v3\"\n)\n\n// thresholdExpression holds the parsed result of a threshold expression,\n// as described in: https://grafana.com/docs/k6/latest/using-k6/thresholds/#threshold-syntax\ntype thresholdExpression struct {\n\t// AggregationMethod holds the aggregation method parsed\n\t// from the threshold expression. Possible values are described\n\t// by `aggregationMethodTokens`.\n\tAggregationMethod string\n\n\t// AggregationValue will hold the aggregation method's pivot value\n\t// in the event it is a percentile. For instance: an expression of the form p(99.9) < 200,\n\t// would result in AggregationValue to be set to 99.9.\n\tAggregationValue null.Float\n\n\t// Operator holds the operator parsed from the threshold expression.\n\t// Possible values are described by `operatorTokens`.\n\tOperator string\n\n\t// Value holds the value parsed from the threshold expression.\n\tValue float64\n}\n\n// SinkKey computes the key used to index a thresholdExpression in the engine's sinks.\n//\n// During execution, the engine \"sinks\" metrics into a internal mapping, so that\n// thresholds can be asserted against them. This method is a helper to normalize the\n// sink the threshold expression should be applied to.\n//\n// Because a threshold expression's aggregation method can either be\n// a static keyword (\"count\", \"rate\", etc...), or a parametric\n// expression (\"p(somefloatingpointvalue)\"), we need to handle this\n// case specifically. If we encounter the percentile aggregation method token,\n// we recompute the whole \"p(value)\" expression in order to look for it in the\n// sinks.\nfunc (te *thresholdExpression) SinkKey() string {\n\tif te.AggregationMethod == tokenPercentile {\n\t\treturn fmt.Sprintf(\"%s(%g)\", tokenPercentile, te.AggregationValue.Float64)\n\t}\n\n\treturn te.AggregationMethod\n}\n\n// parseThresholdExpression parses a threshold condition expression,\n// as defined in a JS script (for instance p(95)<1000), into a thresholdExpression\n// instance.\n//\n// It is expected to be of the form: `aggregation_method operator value`.\n// As defined by the following BNF:\n// ```\n// assertion           -> aggregation_method whitespace* operator whitespace* float\n// aggregation_method  -> trend | rate | gauge | counter\n// counter             -> \"count\" | \"rate\"\n// gauge               -> \"value\"\n// rate                -> \"rate\"\n// trend               -> \"avg\" | \"min\" | \"max\" | \"med\" | percentile\n// percentile          -> \"p(\" float \")\"\n// operator            -> \">\" | \">=\" | \"<=\" | \"<\" | \"==\" | \"===\" | \"!=\"\n// float               -> digit+ (\".\" digit+)?\n// digit               -> \"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\"\n// whitespace          -> \" \"\n// ```\nfunc parseThresholdExpression(input string) (*thresholdExpression, error) {\n\t// Scanning makes no assumption on the underlying values, and only\n\t// checks that the expression has the right format.\n\tmethod, operator, value, err := scanThresholdExpression(input)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed parsing threshold expression %q; reason: %w\", input, err)\n\t}\n\n\tparsedMethod, parsedMethodValue, err := parseThresholdAggregationMethod(method)\n\tif err != nil {\n\t\terr = fmt.Errorf(\"failed parsing threshold expression's %q left hand side; \"+\n\t\t\t\"reason: %w\", input, err,\n\t\t)\n\t\treturn nil, err\n\t}\n\n\tparsedValue, err := strconv.ParseFloat(value, 64)\n\tif err != nil {\n\t\terr = fmt.Errorf(\"failed parsing threshold expresion's %q right hand side; \"+\n\t\t\t\"reason: %w\", input, err,\n\t\t)\n\t\treturn nil, err\n\t}\n\n\tcondition := &thresholdExpression{\n\t\tAggregationMethod: parsedMethod,\n\t\tAggregationValue:  parsedMethodValue,\n\t\tOperator:          operator,\n\t\tValue:             parsedValue,\n\t}\n\n\treturn condition, nil\n}\n\n// Define accepted threshold expression operators tokens\nconst (\n\ttokenLessEqual     = \"<=\"\n\ttokenLess          = \"<\"\n\ttokenGreaterEqual  = \">=\"\n\ttokenGreater       = \">\"\n\ttokenStrictlyEqual = \"===\"\n\ttokenLooselyEqual  = \"==\"\n\ttokenBangEqual     = \"!=\"\n)\n\n// operatorTokens defines the list of operator-related tokens\n// used in threshold expressions parsing.\n//\n// It is meant to be used during the scan of threshold expressions.\n// Although declared as a `var`, being an array, it is effectively\n// immutable and can be considered constant.\n//\n// Note that because scanning uses a substring parser, and will match\n// the smallest common substring, the actual slice order matters.\n// Longer tokens with symbols in common with shorter ones must appear\n// first in the list in order to be effectively matched.\nvar operatorTokens = [7]string{ //nolint:gochecknoglobals\n\ttokenLessEqual,\n\ttokenLess,\n\ttokenGreaterEqual,\n\ttokenGreater,\n\ttokenStrictlyEqual,\n\ttokenLooselyEqual,\n\ttokenBangEqual,\n}\n\n// scanThresholdExpression scans a threshold condition expression of the\n// form: `aggregation_method operator value`. An invalid or unknown operator\n// will produce an error. However, no assertions regarding\n// either the left-hand side aggregation method nor the right-hand\n// side value will be made: they will be returned as is, only trimmed from\n// their spaces.\nfunc scanThresholdExpression(input string) (string, string, string, error) {\n\tfor _, op := range operatorTokens {\n\t\tleft, right, _ := strings.Cut(input, op)\n\t\tif right != \"\" {\n\t\t\treturn strings.TrimSpace(left), op, strings.TrimSpace(right), nil\n\t\t}\n\t}\n\n\treturn \"\", \"\", \"\", fmt.Errorf(\"malformed threshold expression\")\n}\n\n// Define accepted threshold expression aggregation tokens\n// Percentile token `p(..)` is accepted too but handled separately.\nconst (\n\ttokenValue      = \"value\"\n\ttokenCount      = \"count\"\n\ttokenRate       = \"rate\"\n\ttokenAvg        = \"avg\"\n\ttokenMin        = \"min\"\n\ttokenMed        = \"med\"\n\ttokenMax        = \"max\"\n\ttokenPercentile = \"p\"\n)\n\n// aggregationMethodTokens defines the list of aggregation method\n// used in the parsing of threshold expressions.\n//\n// It is meant to be used during the parsing of threshold expressions.\n// Although declared as a `var`, being an array, it is effectively\n// immutable and can be considered constant.\nvar aggregationMethodTokens = [8]string{ //nolint:gochecknoglobals\n\ttokenValue,\n\ttokenCount,\n\ttokenRate,\n\ttokenAvg,\n\ttokenMin,\n\ttokenMed,\n\ttokenMax,\n\ttokenPercentile,\n}\n\n// parseThresholdAggregationMethod will parse a threshold condition expression's method.\n// It assumes the provided input argument is already trimmed and cleaned up.\n// If it encounters a percentile method, it will parse it and verify it\n// boils down to an expression of the form: `p(float64)`, but will return\n// it verbatim, as a string.\nfunc parseThresholdAggregationMethod(input string) (string, null.Float, error) {\n\t// Is the input one of the methods keywords?\n\tfor _, m := range aggregationMethodTokens {\n\t\t// Percentile expressions being of the form p(value),\n\t\t// they won't be matched here.\n\t\tif m == input {\n\t\t\treturn m, null.Float{}, nil\n\t\t}\n\t}\n\n\t// Otherwise, attempt to parse a percentile expression\n\tif strings.HasPrefix(input, tokenPercentile+\"(\") && strings.HasSuffix(input, \")\") {\n\t\taggregationValue, err := strconv.ParseFloat(trimDelimited(\"p(\", input, \")\"), 64)\n\t\tif err != nil {\n\t\t\treturn \"\", null.Float{}, fmt.Errorf(\"malformed percentile value; reason: %w\", err)\n\t\t}\n\n\t\treturn tokenPercentile, null.FloatFrom(aggregationValue), nil\n\t}\n\n\treturn \"\", null.Float{}, fmt.Errorf(\"failed parsing method from expression\")\n}\n\nfunc trimDelimited(prefix, input, suffix string) string {\n\treturn strings.TrimSuffix(strings.TrimPrefix(input, prefix), suffix)\n}\n"
  },
  {
    "path": "metrics/thresholds_parser_test.go",
    "content": "package metrics\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestParseThresholdExpression(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname           string\n\t\tinput          string\n\t\twantExpression *thresholdExpression\n\t\twantErr        bool\n\t}{\n\t\t{\n\t\t\tname:           \"unknown expression's operator fails\",\n\t\t\tinput:          \"count!20\",\n\t\t\twantExpression: nil,\n\t\t\twantErr:        true,\n\t\t},\n\t\t{\n\t\t\tname:           \"unknown expression's method fails\",\n\t\t\tinput:          \"foo>20\",\n\t\t\twantExpression: nil,\n\t\t\twantErr:        true,\n\t\t},\n\t\t{\n\t\t\tname:           \"non numerical expression's value fails\",\n\t\t\tinput:          \"count>abc\",\n\t\t\twantExpression: nil,\n\t\t\twantErr:        true,\n\t\t},\n\t\t{\n\t\t\tname:           \"valid threshold expression syntax\",\n\t\t\tinput:          \"count>20\",\n\t\t\twantExpression: &thresholdExpression{AggregationMethod: \"count\", Operator: \">\", Value: 20},\n\t\t\twantErr:        false,\n\t\t},\n\t}\n\tfor _, testCase := range tests {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotExpression, gotErr := parseThresholdExpression(testCase.input)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantErr,\n\t\t\t\tgotErr != nil,\n\t\t\t\t\"parseThresholdExpression() error = %v, wantErr %v\", gotErr, testCase.wantErr,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantExpression,\n\t\t\t\tgotExpression,\n\t\t\t\t\"parseThresholdExpression() gotExpression = %v, want %v\", gotExpression, testCase.wantExpression,\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc BenchmarkParseThresholdExpression(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = parseThresholdExpression(\"count>20\")\n\t}\n}\n\nfunc TestParseThresholdAggregationMethod(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname            string\n\t\tinput           string\n\t\twantMethod      string\n\t\twantMethodValue null.Float\n\t\twantErr         bool\n\t}{\n\t\t{\n\t\t\tname:            \"count method is parsed\",\n\t\t\tinput:           \"count\",\n\t\t\twantMethod:      tokenCount,\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"rate method is parsed\",\n\t\t\tinput:           \"rate\",\n\t\t\twantMethod:      tokenRate,\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"value method is parsed\",\n\t\t\tinput:           \"value\",\n\t\t\twantMethod:      tokenValue,\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"avg method is parsed\",\n\t\t\tinput:           \"avg\",\n\t\t\twantMethod:      tokenAvg,\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"min method is parsed\",\n\t\t\tinput:           \"min\",\n\t\t\twantMethod:      tokenMin,\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"max method is parsed\",\n\t\t\tinput:           \"max\",\n\t\t\twantMethod:      tokenMax,\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"med method is parsed\",\n\t\t\tinput:           \"med\",\n\t\t\twantMethod:      tokenMed,\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"percentile method with integer value is parsed\",\n\t\t\tinput:           \"p(99)\",\n\t\t\twantMethod:      tokenPercentile,\n\t\t\twantMethodValue: null.FloatFrom(99),\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"percentile method with floating point value is parsed\",\n\t\t\tinput:           \"p(99.9)\",\n\t\t\twantMethod:      tokenPercentile,\n\t\t\twantMethodValue: null.FloatFrom(99.9),\n\t\t\twantErr:         false,\n\t\t},\n\t\t{\n\t\t\tname:            \"parsing invalid method fails\",\n\t\t\tinput:           \"foo\",\n\t\t\twantMethod:      \"\",\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         true,\n\t\t},\n\t\t{\n\t\t\tname:            \"parsing empty percentile expression fails\",\n\t\t\tinput:           \"p()\",\n\t\t\twantMethod:      \"\",\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         true,\n\t\t},\n\t\t{\n\t\t\tname:            \"parsing incomplete percentile expression fails\",\n\t\t\tinput:           \"p(99\",\n\t\t\twantMethod:      \"\",\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         true,\n\t\t},\n\t\t{\n\t\t\tname:            \"parsing non-numerical percentile value fails\",\n\t\t\tinput:           \"p(foo)\",\n\t\t\twantMethod:      \"\",\n\t\t\twantMethodValue: null.Float{},\n\t\t\twantErr:         true,\n\t\t},\n\t}\n\tfor _, testCase := range tests {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotMethod, gotMethodValue, gotErr := parseThresholdAggregationMethod(testCase.input)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantErr,\n\t\t\t\tgotErr != nil,\n\t\t\t\t\"parseThresholdAggregationMethod() error = %v, wantErr %v\", gotErr, testCase.wantErr,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantMethod,\n\t\t\t\tgotMethod,\n\t\t\t\t\"parseThresholdAggregationMethod() gotMethod = %v, want %v\", gotMethod, testCase.wantMethod,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantMethodValue,\n\t\t\t\tgotMethodValue,\n\t\t\t\t\"parseThresholdAggregationMethod() gotMethodValue = %v, want %v\", gotMethodValue, testCase.wantMethodValue,\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc BenchmarkParseThresholdAggregationMethod(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _, _ = parseThresholdAggregationMethod(\"p(99.9)\")\n\t}\n}\n\nfunc TestScanThresholdExpression(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname         string\n\t\tinput        string\n\t\twantMethod   string\n\t\twantOperator string\n\t\twantValue    string\n\t\twantErr      bool\n\t}{\n\t\t{\n\t\t\tname:         \"expression with <= operator is scanned\",\n\t\t\tinput:        \"foo<=bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \"<=\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression with < operator is scanned\",\n\t\t\tinput:        \"foo<bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \"<\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression with >= operator is scanned\",\n\t\t\tinput:        \"foo>=bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \">=\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression with > operator is scanned\",\n\t\t\tinput:        \"foo>bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \">\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression with === operator is scanned\",\n\t\t\tinput:        \"foo===bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \"===\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression with == operator is scanned\",\n\t\t\tinput:        \"foo==bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \"==\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression with != operator is scanned\",\n\t\t\tinput:        \"foo!=bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \"!=\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression's method is trimmed\",\n\t\t\tinput:        \"  foo  <=bar\",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \"<=\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression's value is trimmed\",\n\t\t\tinput:        \"foo<=  bar  \",\n\t\t\twantMethod:   \"foo\",\n\t\t\twantOperator: \"<=\",\n\t\t\twantValue:    \"bar\",\n\t\t\twantErr:      false,\n\t\t},\n\t\t{\n\t\t\tname:         \"expression with unknown operator fails\",\n\t\t\tinput:        \"foo!bar\",\n\t\t\twantMethod:   \"\",\n\t\t\twantOperator: \"\",\n\t\t\twantValue:    \"\",\n\t\t\twantErr:      true,\n\t\t},\n\t}\n\tfor _, testCase := range tests {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tgotMethod, gotOperator, gotValue, gotErr := scanThresholdExpression(testCase.input)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantErr,\n\t\t\t\tgotErr != nil,\n\t\t\t\t\"scanThresholdExpression() error = %v, wantErr %v\", gotErr, testCase.wantErr,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantMethod,\n\t\t\t\tgotMethod,\n\t\t\t\t\"scanThresholdExpression() gotMethod = %v, want %v\", gotMethod, testCase.wantMethod,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantOperator,\n\t\t\t\tgotOperator,\n\t\t\t\t\"scanThresholdExpression() gotOperator = %v, want %v\", gotOperator, testCase.wantOperator,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantValue,\n\t\t\t\tgotValue,\n\t\t\t\t\"scanThresholdExpression() gotValue = %v, want %v\", gotValue, testCase.wantValue,\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc BenchmarkScanThresholdExpression(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _, _, _ = scanThresholdExpression(\"foo<=bar\")\n\t}\n}\n"
  },
  {
    "path": "metrics/thresholds_test.go",
    "content": "package metrics\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"gopkg.in/guregu/null.v3\"\n)\n\nfunc TestNewThreshold(t *testing.T) {\n\tt.Parallel()\n\n\tsrc := `rate<0.01`\n\tabortOnFail := false\n\tgracePeriod := types.NullDurationFrom(2 * time.Second)\n\n\tgotThreshold := newThreshold(src, abortOnFail, gracePeriod)\n\n\tassert.Equal(t, src, gotThreshold.Source)\n\tassert.False(t, gotThreshold.LastFailed)\n\tassert.Equal(t, abortOnFail, gotThreshold.AbortOnFail)\n\tassert.Equal(t, gracePeriod, gotThreshold.AbortGracePeriod)\n\tassert.Nil(t, gotThreshold.parsed)\n}\n\nfunc TestThreshold_runNoTaint(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname             string\n\t\tparsed           *thresholdExpression\n\t\tabortGracePeriod types.NullDuration\n\t\tsinks            map[string]float64\n\t\twantOk           bool\n\t\twantErr          bool\n\t}{\n\t\t{\n\t\t\tname:             \"valid expression using the > operator over passing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenGreater, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 1},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression using the > operator over passing threshold and defined abort grace period\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenGreater, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(2 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 1},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression using the >= operator over passing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenGreaterEqual, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.01},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression using the <= operator over passing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenLessEqual, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.01},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression using the < operator over passing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenLess, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.00001},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression using the == operator over passing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenLooselyEqual, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.01},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression using the === operator over passing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenStrictlyEqual, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.01},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression using != operator over passing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenBangEqual, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.02},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression over failing threshold\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenGreater, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.00001},\n\t\t\twantOk:           false,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\tname:             \"valid expression over non-existing sink\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenGreater, 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"med\": 27.2},\n\t\t\twantOk:           true,\n\t\t\twantErr:          false,\n\t\t},\n\t\t{\n\t\t\t// The ParseThresholdCondition constructor should ensure that no invalid\n\t\t\t// operator gets through, but let's protect our future selves anyhow.\n\t\t\tname:             \"invalid expression operator\",\n\t\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, \"&\", 0.01},\n\t\t\tabortGracePeriod: types.NullDurationFrom(0 * time.Second),\n\t\t\tsinks:            map[string]float64{\"rate\": 0.00001},\n\t\t\twantOk:           false,\n\t\t\twantErr:          true,\n\t\t},\n\t}\n\n\tfor _, testCase := range tests {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tthreshold := &Threshold{\n\t\t\t\tLastFailed:       false,\n\t\t\t\tAbortOnFail:      false,\n\t\t\t\tAbortGracePeriod: testCase.abortGracePeriod,\n\t\t\t\tparsed:           testCase.parsed,\n\t\t\t}\n\n\t\t\tgotOk, gotErr := threshold.runNoTaint(testCase.sinks)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantErr,\n\t\t\t\tgotErr != nil,\n\t\t\t\t\"Threshold.runNoTaint() error = %v, wantErr %v\", gotErr, testCase.wantErr,\n\t\t\t)\n\n\t\t\tassert.Equal(t,\n\t\t\t\ttestCase.wantOk,\n\t\t\t\tgotOk,\n\t\t\t\t\"Threshold.runNoTaint() gotOk = %v, want %v\", gotOk, testCase.wantOk,\n\t\t\t)\n\t\t})\n\t}\n}\n\nfunc BenchmarkRunNoTaint(b *testing.B) {\n\tthreshold := &Threshold{\n\t\tSource:           \"rate>0.01\",\n\t\tLastFailed:       false,\n\t\tAbortOnFail:      false,\n\t\tAbortGracePeriod: types.NullDurationFrom(2 * time.Second),\n\t\tparsed:           &thresholdExpression{tokenRate, null.Float{}, tokenGreater, 0.01},\n\t}\n\n\tsinks := map[string]float64{\"rate\": 1}\n\n\tb.ResetTimer()\n\n\tfor i := 0; i < b.N; i++ {\n\t\t_, _ = threshold.runNoTaint(sinks)\n\t}\n}\n\nfunc TestThresholdRun(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"true\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tsinks := map[string]float64{\"rate\": 0.0001}\n\t\tparsed, parseErr := parseThresholdExpression(\"rate<0.01\")\n\t\trequire.NoError(t, parseErr)\n\t\tthreshold := newThreshold(`rate<0.01`, false, types.NullDuration{})\n\t\tthreshold.parsed = parsed\n\n\t\tt.Run(\"no taint\", func(t *testing.T) { //nolint:paralleltest\n\t\t\tb, err := threshold.runNoTaint(sinks)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.True(t, b)\n\t\t\tassert.False(t, threshold.LastFailed)\n\t\t})\n\n\t\tt.Run(\"taint\", func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tb, err := threshold.run(sinks)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.True(t, b)\n\t\t\tassert.False(t, threshold.LastFailed)\n\t\t})\n\t})\n\n\tt.Run(\"false\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tsinks := map[string]float64{\"rate\": 1}\n\t\tparsed, parseErr := parseThresholdExpression(\"rate<0.01\")\n\t\trequire.NoError(t, parseErr)\n\t\tthreshold := newThreshold(`rate<0.01`, false, types.NullDuration{})\n\t\tthreshold.parsed = parsed\n\n\t\tt.Run(\"no taint\", func(t *testing.T) { //nolint:paralleltest\n\t\t\tb, err := threshold.runNoTaint(sinks)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.False(t, b)\n\t\t\tassert.False(t, threshold.LastFailed)\n\t\t})\n\n\t\tt.Run(\"taint\", func(t *testing.T) { //nolint:paralleltest\n\t\t\tb, err := threshold.run(sinks)\n\t\t\tassert.NoError(t, err)\n\t\t\tassert.False(t, b)\n\t\t\tassert.True(t, threshold.LastFailed)\n\t\t})\n\t})\n}\n\nfunc TestThresholdsParse(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"valid threshold expressions\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Prepare a Thresholds collection containing syntaxically\n\t\t// correct thresholds\n\t\tts := Thresholds{\n\t\t\tThresholds: []*Threshold{\n\t\t\t\tnewThreshold(\"rate<1\", false, types.NullDuration{}),\n\t\t\t},\n\t\t}\n\n\t\t// Collect the result of the parsing operation\n\t\tgotErr := ts.Parse()\n\n\t\tassert.NoError(t, gotErr, \"Parse shouldn't fail parsing valid expressions\")\n\t\tassert.Condition(t, func() bool {\n\t\t\tfor _, threshold := range ts.Thresholds {\n\t\t\t\tif threshold.parsed == nil {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true\n\t\t}, \"Parse did not fail, but some Thresholds' parsed field is left empty\")\n\t})\n\n\tt.Run(\"invalid threshold expressions\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Prepare a Thresholds collection containing syntaxically\n\t\t// correct thresholds\n\t\tts := Thresholds{\n\t\t\tThresholds: []*Threshold{\n\t\t\t\tnewThreshold(\"foo&1\", false, types.NullDuration{}),\n\t\t\t},\n\t\t}\n\n\t\t// Collect the result of the parsing operation\n\t\tgotErr := ts.Parse()\n\n\t\tassert.Error(t, gotErr, \"Parse should fail parsing invalid expressions\")\n\t\tassert.Condition(t, func() bool {\n\t\t\tfor _, threshold := range ts.Thresholds {\n\t\t\t\tif threshold.parsed == nil {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t}, \"Parse failed, but some Thresholds' parsed field was not empty\")\n\t})\n\n\tt.Run(\"mixed valid/invalid threshold expressions\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\t// Prepare a Thresholds collection containing syntaxically\n\t\t// correct thresholds\n\t\tts := Thresholds{\n\t\t\tThresholds: []*Threshold{\n\t\t\t\tnewThreshold(\"rate<1\", false, types.NullDuration{}),\n\t\t\t\tnewThreshold(\"foo&1\", false, types.NullDuration{}),\n\t\t\t},\n\t\t}\n\n\t\t// Collect the result of the parsing operation\n\t\tgotErr := ts.Parse()\n\n\t\tassert.Error(t, gotErr, \"Parse should fail parsing invalid expressions\")\n\t\tassert.Condition(t, func() bool {\n\t\t\tfor _, threshold := range ts.Thresholds {\n\t\t\t\tif threshold.parsed == nil {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false\n\t\t}, \"Parse failed, but some Thresholds' parsed field was not empty\")\n\t})\n}\n\nfunc TestThresholdsValidate(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"validating thresholds applied to a non existing metric fails\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestRegistry := NewRegistry()\n\n\t\t// Prepare a Thresholds collection containing syntaxically\n\t\t// correct thresholds\n\t\tts := Thresholds{\n\t\t\tThresholds: []*Threshold{\n\t\t\t\tnewThreshold(\"rate<1\", false, types.NullDuration{}),\n\t\t\t},\n\t\t}\n\n\t\tparseErr := ts.Parse()\n\t\trequire.NoError(t, parseErr)\n\n\t\tvar wantErr errext.HasExitCode\n\n\t\t// Collect the result of the parsing operation\n\t\tgotErr := ts.Validate(\"non-existing\", testRegistry)\n\n\t\tassert.Error(t, gotErr)\n\t\tassert.ErrorIs(t, gotErr, ErrInvalidThreshold)\n\t\tassert.ErrorAs(t, gotErr, &wantErr)\n\t\tassert.Equal(t, exitcodes.InvalidConfig, wantErr.ExitCode())\n\t})\n\n\tt.Run(\"validating unparsed thresholds fails\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestRegistry := NewRegistry()\n\t\t_, err := testRegistry.NewMetric(\"test_counter\", Counter)\n\t\trequire.NoError(t, err)\n\n\t\t// Prepare a Thresholds collection containing syntaxically\n\t\t// correct thresholds\n\t\tts := Thresholds{\n\t\t\tThresholds: []*Threshold{\n\t\t\t\tnewThreshold(\"rate<1\", false, types.NullDuration{}),\n\t\t\t},\n\t\t}\n\n\t\t// Note that we're not parsing the thresholds\n\n\t\t// Collect the result of the parsing operation\n\t\tgotErr := ts.Validate(\"non-existing\", testRegistry)\n\n\t\tassert.Error(t, gotErr)\n\t})\n\n\tt.Run(\"thresholds supported aggregation methods for metrics\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\ttestRegistry := NewRegistry()\n\t\ttestCounter, err := testRegistry.NewMetric(\"test_counter\", Counter)\n\t\trequire.NoError(t, err)\n\t\t_, err = testCounter.AddSubmetric(\"foo:bar\")\n\t\trequire.NoError(t, err)\n\t\t_, err = testCounter.AddSubmetric(\"abc:123,easyas:doremi\")\n\t\trequire.NoError(t, err)\n\n\t\t_, err = testRegistry.NewMetric(\"test_rate\", Rate)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = testRegistry.NewMetric(\"test_gauge\", Gauge)\n\t\trequire.NoError(t, err)\n\n\t\t_, err = testRegistry.NewMetric(\"test_trend\", Trend)\n\t\trequire.NoError(t, err)\n\n\t\ttests := []struct {\n\t\t\tname       string\n\t\t\tmetricName string\n\t\t\tthresholds Thresholds\n\t\t\twantErr    bool\n\t\t}{\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'count' is valid against a counter metric\",\n\t\t\t\tmetricName: \"test_counter\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"count==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'rate' is valid against a counter metric\",\n\t\t\t\tmetricName: \"test_counter\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"rate==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'rate' is valid against a counter single tag submetric\",\n\t\t\t\tmetricName: \"test_counter{foo:bar}\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"rate==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'rate' is valid against a counter multi-tag submetric\",\n\t\t\t\tmetricName: \"test_counter{abc:123,easyas:doremi}\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"rate==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'value' is valid against a gauge metric\",\n\t\t\t\tmetricName: \"test_gauge\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"value==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'rate' is valid against a rate metric\",\n\t\t\t\tmetricName: \"test_rate\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"rate==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'avg' is valid against a trend metric\",\n\t\t\t\tmetricName: \"test_trend\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"avg==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'min' is valid against a trend metric\",\n\t\t\t\tmetricName: \"test_trend\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"min==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'max' is valid against a trend metric\",\n\t\t\t\tmetricName: \"test_trend\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"max==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'med' is valid against a trend metric\",\n\t\t\t\tmetricName: \"test_trend\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"med==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname:       \"threshold expression using 'p(value)' is valid against a trend metric\",\n\t\t\t\tmetricName: \"test_trend\",\n\t\t\t\tthresholds: Thresholds{\n\t\t\t\t\tThresholds: []*Threshold{newThreshold(\"p(99)==1\", false, types.NullDuration{})},\n\t\t\t\t},\n\t\t\t\twantErr: false,\n\t\t\t},\n\t\t}\n\n\t\tfor _, testCase := range tests {\n\t\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\t// Ensure thresholds are parsed\n\t\t\t\tparseErr := testCase.thresholds.Parse()\n\t\t\t\trequire.NoError(t, parseErr)\n\n\t\t\t\tgotErr := testCase.thresholds.Validate(testCase.metricName, testRegistry)\n\n\t\t\t\tassert.Equal(t,\n\t\t\t\t\ttestCase.wantErr,\n\t\t\t\t\tgotErr != nil,\n\t\t\t\t\t\"Thresholds.Validate() error = %v, wantErr %v\", gotErr, testCase.wantErr,\n\t\t\t\t)\n\n\t\t\t\tif testCase.wantErr {\n\t\t\t\t\tvar targetErr errext.HasExitCode\n\n\t\t\t\t\tassert.ErrorIs(t,\n\t\t\t\t\t\tgotErr,\n\t\t\t\t\t\tErrInvalidThreshold,\n\t\t\t\t\t\t\"Validate error chain should contain an ErrInvalidThreshold error\",\n\t\t\t\t\t)\n\n\t\t\t\t\tassert.ErrorAs(t,\n\t\t\t\t\t\tgotErr,\n\t\t\t\t\t\t&targetErr,\n\t\t\t\t\t\t\"Validate error chain should contain an errext.HasExitCode error\",\n\t\t\t\t\t)\n\n\t\t\t\t\tassert.Equal(t,\n\t\t\t\t\t\texitcodes.InvalidConfig,\n\t\t\t\t\t\ttargetErr.ExitCode(),\n\t\t\t\t\t\t\"Validate error should have been exitcodes.InvalidConfig\",\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t})\n}\n\nfunc TestNewThresholds(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"empty\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := NewThresholds([]string{})\n\t\tassert.Len(t, ts.Thresholds, 0)\n\t})\n\tt.Run(\"two\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tsources := []string{`rate<0.01`, `p(95)<200`}\n\t\tts := NewThresholds(sources)\n\t\tassert.Len(t, ts.Thresholds, 2)\n\t\tfor i, th := range ts.Thresholds {\n\t\t\tassert.Equal(t, sources[i], th.Source)\n\t\t\tassert.False(t, th.LastFailed)\n\t\t\tassert.False(t, th.AbortOnFail)\n\t\t}\n\t})\n}\n\nfunc TestNewThresholdsWithConfig(t *testing.T) {\n\tt.Parallel()\n\n\tt.Run(\"empty\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tts := NewThresholds([]string{})\n\t\tassert.Len(t, ts.Thresholds, 0)\n\t})\n\tt.Run(\"two\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tconfigs := []thresholdConfig{\n\t\t\t{`rate<0.01`, false, types.NullDuration{}},\n\t\t\t{`p(95)<200`, true, types.NullDuration{}},\n\t\t}\n\t\tts := newThresholdsWithConfig(configs)\n\t\tassert.Len(t, ts.Thresholds, 2)\n\t\tfor i, th := range ts.Thresholds {\n\t\t\tassert.Equal(t, configs[i].Threshold, th.Source)\n\t\t\tassert.False(t, th.LastFailed)\n\t\t\tassert.Equal(t, configs[i].AbortOnFail, th.AbortOnFail)\n\t\t}\n\t})\n}\n\nfunc TestThresholdsRunAll(t *testing.T) {\n\tt.Parallel()\n\n\tzero := types.NullDuration{}\n\toneSec := types.NullDurationFrom(time.Second)\n\ttwoSec := types.NullDurationFrom(2 * time.Second)\n\ttestdata := map[string]struct {\n\t\tsucceeded bool\n\t\terr       bool\n\t\tabort     bool\n\t\tgrace     types.NullDuration\n\t\tsources   []string\n\t}{\n\t\t\"one passing\":                {true, false, false, zero, []string{`rate<0.01`}},\n\t\t\"one failing\":                {false, false, false, zero, []string{`p(95)<200`}},\n\t\t\"two passing\":                {true, false, false, zero, []string{`rate<0.1`, `rate<0.01`}},\n\t\t\"two failing\":                {false, false, false, zero, []string{`p(95)<200`, `rate<0.1`}},\n\t\t\"two mixed\":                  {false, false, false, zero, []string{`rate<0.01`, `p(95)<200`}},\n\t\t\"one aborting\":               {false, false, true, zero, []string{`p(95)<200`}},\n\t\t\"abort with grace period\":    {false, false, true, oneSec, []string{`p(95)<200`}},\n\t\t\"no abort with grace period\": {false, false, true, twoSec, []string{`p(95)<200`}},\n\t}\n\n\tfor name, data := range testdata {\n\t\tt.Run(name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tthresholds := NewThresholds(data.sources)\n\t\t\tgotParseErr := thresholds.Parse()\n\t\t\trequire.NoError(t, gotParseErr)\n\t\t\tthresholds.sinked = map[string]float64{\"rate\": 0.0001, \"p(95)\": 500}\n\t\t\tthresholds.Thresholds[0].AbortOnFail = data.abort\n\t\t\tthresholds.Thresholds[0].AbortGracePeriod = data.grace\n\n\t\t\trunDuration := 1500 * time.Millisecond\n\n\t\t\tsucceeded, err := thresholds.runAll(runDuration)\n\n\t\t\tif data.err {\n\t\t\t\tassert.Error(t, err)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t}\n\n\t\t\tif data.succeeded {\n\t\t\t\tassert.True(t, succeeded)\n\t\t\t} else {\n\t\t\t\tassert.False(t, succeeded)\n\t\t\t}\n\n\t\t\tif data.abort && data.grace.Duration < types.Duration(runDuration) {\n\t\t\t\tassert.True(t, thresholds.Abort)\n\t\t\t} else {\n\t\t\t\tassert.False(t, thresholds.Abort)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc getTrendSink(values ...float64) *TrendSink {\n\tsink := NewTrendSink()\n\tfor _, v := range values {\n\t\tsink.Add(Sample{Value: v})\n\t}\n\treturn sink\n}\n\nfunc TestThresholdsRun(t *testing.T) {\n\tt.Parallel()\n\n\ttype args struct {\n\t\tsink                 Sink\n\t\tthresholdExpressions []string\n\t\tduration             time.Duration\n\t}\n\ttests := []struct {\n\t\tname    string\n\t\targs    args\n\t\twant    bool\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\tname: \"Running thresholds of existing sink\",\n\t\t\targs: args{\n\t\t\t\tsink:                 &CounterSink{Value: 1234.5},\n\t\t\t\tthresholdExpressions: []string{\"count<2000\"},\n\t\t\t\tduration:             0,\n\t\t\t},\n\t\t\twant:    true,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Running thresholds of existing sink but failing threshold\",\n\t\t\targs: args{\n\t\t\t\tsink:                 &CounterSink{Value: 3000},\n\t\t\t\tthresholdExpressions: []string{\"count<2000\"},\n\t\t\t\tduration:             0,\n\t\t\t},\n\t\t\twant:    false,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Running threshold on non existing sink does not fail\",\n\t\t\targs: args{\n\t\t\t\tsink:                 &CounterSink{},\n\t\t\t\tthresholdExpressions: []string{\"p(95)<2000\"},\n\t\t\t\tduration:             0,\n\t\t\t},\n\t\t\twant:    true,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Running threshold on trend sink with no values and passing med statement succeeds\",\n\t\t\targs: args{\n\t\t\t\tsink:                 getTrendSink(),\n\t\t\t\tthresholdExpressions: []string{\"med<39\"},\n\t\t\t\tduration:             0,\n\t\t\t},\n\t\t\twant:    true,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Running threshold on trend sink with no values and non passing med statement fails\",\n\t\t\targs: args{\n\t\t\t\tsink:                 getTrendSink(),\n\t\t\t\tthresholdExpressions: []string{\"med>39\"},\n\t\t\t\tduration:             0,\n\t\t\t},\n\t\t\twant:    false,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Running threshold on trend sink with values and passing med statement succeeds\",\n\t\t\targs: args{\n\t\t\t\tsink:                 getTrendSink(70, 80, 90),\n\t\t\t\tthresholdExpressions: []string{\"med>39\"},\n\t\t\t\tduration:             0,\n\t\t\t},\n\t\t\twant:    true,\n\t\t\twantErr: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Running threshold on trend sink with values and failing med statement fails\",\n\t\t\targs: args{\n\t\t\t\tsink:                 getTrendSink(70, 80, 90),\n\t\t\t\tthresholdExpressions: []string{\"med<39\"},\n\t\t\t\tduration:             0,\n\t\t\t},\n\t\t\twant:    false,\n\t\t\twantErr: false,\n\t\t},\n\t}\n\tfor _, testCase := range tests {\n\t\tt.Run(testCase.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tthresholds := NewThresholds(testCase.args.thresholdExpressions)\n\t\t\tgotParseErr := thresholds.Parse()\n\t\t\trequire.NoError(t, gotParseErr)\n\n\t\t\tgotOk, gotErr := thresholds.Run(testCase.args.sink, testCase.args.duration)\n\t\t\tassert.Equal(t, testCase.wantErr, gotErr != nil, \"Thresholds.Run() error = %v, wantErr %v\", gotErr, testCase.wantErr)\n\t\t\tassert.Equal(t, testCase.want, gotOk, \"Thresholds.Run() = %v, want %v\", gotOk, testCase.want)\n\t\t})\n\t}\n}\n\nfunc TestThresholdsJSON(t *testing.T) {\n\tt.Parallel()\n\n\ttestdata := []struct {\n\t\tJSON        string\n\t\tsources     []string\n\t\tabortOnFail bool\n\t\tgracePeriod types.NullDuration\n\t\toutputJSON  string\n\t}{\n\t\t{\n\t\t\t`[]`,\n\t\t\t[]string{},\n\t\t\tfalse,\n\t\t\ttypes.NullDuration{},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t`[\"rate<0.01\"]`,\n\t\t\t[]string{\"rate<0.01\"},\n\t\t\tfalse,\n\t\t\ttypes.NullDuration{},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t`[\"rate<0.01\"]`,\n\t\t\t[]string{\"rate<0.01\"},\n\t\t\tfalse,\n\t\t\ttypes.NullDuration{},\n\t\t\t`[\"rate<0.01\"]`,\n\t\t},\n\t\t{\n\t\t\t`[\"rate<0.01\",\"p(95)<200\"]`,\n\t\t\t[]string{\"rate<0.01\", \"p(95)<200\"},\n\t\t\tfalse,\n\t\t\ttypes.NullDuration{},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t`[{\"threshold\":\"rate<0.01\"}]`,\n\t\t\t[]string{\"rate<0.01\"},\n\t\t\tfalse,\n\t\t\ttypes.NullDuration{},\n\t\t\t`[\"rate<0.01\"]`,\n\t\t},\n\t\t{\n\t\t\t`[{\"threshold\":\"rate<0.01\",\"abortOnFail\":true,\"delayAbortEval\":null}]`,\n\t\t\t[]string{\"rate<0.01\"},\n\t\t\ttrue,\n\t\t\ttypes.NullDuration{},\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t`[{\"threshold\":\"rate<0.01\",\"abortOnFail\":true,\"delayAbortEval\":\"2s\"}]`,\n\t\t\t[]string{\"rate<0.01\"},\n\t\t\ttrue,\n\t\t\ttypes.NullDurationFrom(2 * time.Second),\n\t\t\t\"\",\n\t\t},\n\t\t{\n\t\t\t`[{\"threshold\":\"rate<0.01\",\"abortOnFail\":false}]`,\n\t\t\t[]string{\"rate<0.01\"},\n\t\t\tfalse,\n\t\t\ttypes.NullDuration{},\n\t\t\t`[\"rate<0.01\"]`,\n\t\t},\n\t\t{\n\t\t\t`[{\"threshold\":\"rate<0.01\"}, \"p(95)<200\"]`,\n\t\t\t[]string{\"rate<0.01\", \"p(95)<200\"},\n\t\t\tfalse,\n\t\t\ttypes.NullDuration{},\n\t\t\t`[\"rate<0.01\",\"p(95)<200\"]`,\n\t\t},\n\t}\n\n\tfor _, data := range testdata {\n\t\tt.Run(data.JSON, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tvar ts Thresholds\n\t\t\tassert.NoError(t, json.Unmarshal([]byte(data.JSON), &ts))\n\t\t\tassert.Equal(t, len(data.sources), len(ts.Thresholds))\n\t\t\tfor i, src := range data.sources {\n\t\t\t\tassert.Equal(t, src, ts.Thresholds[i].Source)\n\t\t\t\tassert.Equal(t, data.abortOnFail, ts.Thresholds[i].AbortOnFail)\n\t\t\t\tassert.Equal(t, data.gracePeriod, ts.Thresholds[i].AbortGracePeriod)\n\t\t\t}\n\n\t\t\tt.Run(\"marshal\", func(t *testing.T) { //nolint:paralleltest\n\t\t\t\tdata2, err := MarshalJSONWithoutHTMLEscape(ts)\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\toutput := data.JSON\n\t\t\t\tif data.outputJSON != \"\" {\n\t\t\t\t\toutput = data.outputJSON\n\t\t\t\t}\n\t\t\t\tassert.Equal(t, output, string(data2))\n\t\t\t})\n\t\t})\n\t}\n\n\tt.Run(\"bad JSON\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar ts Thresholds\n\t\tassert.Error(t, json.Unmarshal([]byte(\"42\"), &ts))\n\t\tassert.Nil(t, ts.Thresholds)\n\t\tassert.False(t, ts.Abort)\n\t})\n\n\tt.Run(\"bad source\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar ts Thresholds\n\t\tassert.Nil(t, ts.Thresholds)\n\t\tassert.False(t, ts.Abort)\n\t})\n}\n"
  },
  {
    "path": "metrics/units.go",
    "content": "package metrics\n\nimport (\n\t\"time\"\n)\n\nconst timeUnit = time.Millisecond\n\n// D formats a duration for emission.\n// The reverse of D() is ToD().\nfunc D(d time.Duration) float64 {\n\treturn float64(d) / float64(timeUnit)\n}\n\n// ToD converts an emitted duration to a time.Duration.\n// The reverse of ToD() is D().\nfunc ToD(d float64) time.Duration {\n\treturn time.Duration(d * float64(timeUnit))\n}\n\n// B formats a boolean value for emission.\nfunc B(b bool) float64 {\n\tif b {\n\t\treturn 1\n\t}\n\treturn 0\n}\n"
  },
  {
    "path": "metrics/value_type.go",
    "content": "package metrics\n\nimport \"errors\"\n\n// Possible values for ValueType.\nconst (\n\tDefault = ValueType(iota) // Values are presented as-is\n\tTime                      // Values are time durations (milliseconds)\n\tData                      // Values are data amounts (bytes)\n)\n\n// ErrInvalidValueType indicates the serialized value type is invalid.\nvar ErrInvalidValueType = errors.New(\"invalid value type\")\n\n// ValueType holds the type of values a metric contains.\ntype ValueType int\n\n// MarshalJSON serializes a ValueType to a JSON string.\nfunc (t ValueType) MarshalJSON() ([]byte, error) {\n\ttxt, err := t.MarshalText()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []byte(`\"` + string(txt) + `\"`), nil\n}\n\n// MarshalText serializes a ValueType as a human readable string.\nfunc (t ValueType) MarshalText() ([]byte, error) {\n\tswitch t {\n\tcase Default:\n\t\treturn []byte(defaultString), nil\n\tcase Time:\n\t\treturn []byte(timeString), nil\n\tcase Data:\n\t\treturn []byte(dataString), nil\n\tdefault:\n\t\treturn nil, ErrInvalidValueType\n\t}\n}\n\n// UnmarshalText deserializes a ValueType from a string representation.\nfunc (t *ValueType) UnmarshalText(data []byte) error {\n\tswitch string(data) {\n\tcase defaultString:\n\t\t*t = Default\n\tcase timeString:\n\t\t*t = Time\n\tcase dataString:\n\t\t*t = Data\n\tdefault:\n\t\treturn ErrInvalidValueType\n\t}\n\n\treturn nil\n}\n\nfunc (t ValueType) String() string {\n\tswitch t {\n\tcase Default:\n\t\treturn defaultString\n\tcase Time:\n\t\treturn timeString\n\tcase Data:\n\t\treturn dataString\n\tdefault:\n\t\treturn \"[INVALID]\"\n\t}\n}\n"
  },
  {
    "path": "modtools_frozen.yml",
    "content": "- path: github.com/spf13/afero\n  minVersion: v1.1.2\n  validUntil: 2029-08-04T16:29:18+03:00\n- path: github.com/influxdata/influxdb1-client\n  minVersion: v0.0.0-20190402204710-8ff2fc3824fc\n  validUntil: 2029-08-04T16:29:55+03:00\n- path: gopkg.in/guregu/null.v3\n  minVersion: v3.3.0\n  validUntil: 2029-08-04T16:32:44+03:00\n- path: gopkg.in/yaml.v3\n  minVersion: v3.0.0-20200313102051-9f266ea9e77c\n  validUntil: 2029-08-04T16:32:56+03:00\n- path: github.com/spf13/cobra\n  minVersion: v1.4.0\n  validUntil: 2049-07-26T17:21:52+03:00\n- path: github.com/spf13/pflag\n  minVersion: v1.0.5\n  validUntil: 2049-07-26T17:21:57+03:00\n- path: github.com/andybalholm/cascadia\n  minVersion: v1.1.0\n  validUntil: 2049-07-26T17:24:57+03:00\n"
  },
  {
    "path": "output/cloud/expv2/collect.go",
    "content": "package expv2\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype timeBucket struct {\n\tTime  int64\n\tSinks map[metrics.TimeSeries]metricValue\n}\n\n// bucketQ is a queue for buffering the aggregated metrics\n// that have to be flushed. It is expected to be used concurrently.\ntype bucketQ struct {\n\tm       sync.Mutex\n\tbuckets []timeBucket\n}\n\n// PopAll returns a slice with all the pushed buckets.\n// It returns a nil slice if the queue is empty.\nfunc (q *bucketQ) PopAll() []timeBucket {\n\tq.m.Lock()\n\tdefer q.m.Unlock()\n\n\tif len(q.buckets) < 1 {\n\t\treturn nil\n\t}\n\n\t// return the enqueued slice and its relative array and allocate a new one\n\t// using the same capacity.\n\tb := q.buckets\n\tq.buckets = make([]timeBucket, 0, len(b))\n\treturn b\n}\n\n// Push enqueues a new item in the queue.\nfunc (q *bucketQ) Push(b []timeBucket) {\n\tif len(b) < 1 {\n\t\treturn\n\t}\n\tq.m.Lock()\n\tq.buckets = append(q.buckets, b...)\n\tq.m.Unlock()\n}\n\ntype collector struct {\n\tbq      bucketQ\n\tnowFunc func() time.Time\n\n\taggregationPeriod time.Duration\n\twaitPeriod        time.Duration\n\n\t// we should no longer have to handle metrics that have times long in the past. So instead of a\n\t// map, we can probably use a simple slice (or even an array!) as a ring buffer to store the\n\t// aggregation buckets. This should save us a some time, since it would make the lookups and WaitPeriod\n\t// checks basically O(1). And even if for some reason there are occasional metrics with past times that\n\t// don't fit in the chosen ring buffer size, we could just send them along to the buffer unaggregated\n\ttimeBuckets map[int64]map[metrics.TimeSeries]metricValue\n}\n\nfunc newCollector(aggrPeriod, waitPeriod time.Duration) (*collector, error) {\n\tif aggrPeriod == 0 {\n\t\treturn nil, errors.New(\"aggregation period is not allowed to be zero\")\n\t}\n\tif aggrPeriod != aggrPeriod.Truncate(time.Second) {\n\t\treturn nil, errors.New(\"aggregation period is not allowed to have sub-second precision\")\n\t}\n\tif waitPeriod == 0 {\n\t\t// TODO: we could simplify the expiring logic\n\t\t// just having an internal static logic.\n\t\t// Like skip only not closed buckets bucketEnd > now.\n\t\treturn nil, errors.New(\"aggregation wait period is not allowed to be zero\")\n\t}\n\tif waitPeriod != waitPeriod.Truncate(time.Second) {\n\t\treturn nil, errors.New(\"aggregation wait period is not allowed to have sub-second precision\")\n\t}\n\treturn &collector{\n\t\tbq:                bucketQ{},\n\t\tnowFunc:           time.Now,\n\t\ttimeBuckets:       make(map[int64]map[metrics.TimeSeries]metricValue),\n\t\taggregationPeriod: aggrPeriod,\n\t\twaitPeriod:        waitPeriod,\n\t}, nil\n}\n\n// CollectSamples drain the buffer and collect all the samples.\nfunc (c *collector) CollectSamples(containers []metrics.SampleContainer) {\n\t// Distribute all newly buffered samples into related buckets\n\tfor _, sampleContainer := range containers {\n\t\tsamples := sampleContainer.GetSamples()\n\n\t\tfor i := range samples {\n\t\t\tc.collectSample(samples[i])\n\t\t}\n\t}\n\tc.bq.Push(c.expiredBuckets())\n}\n\n// DropExpiringDelay drops the waiting time for buckets\n// for the expiring checks.\nfunc (c *collector) DropExpiringDelay() {\n\tc.waitPeriod = 0\n}\n\nfunc (c *collector) collectSample(s metrics.Sample) {\n\tbucketID := c.bucketID(s.Time)\n\n\t// Get or create a time bucket\n\tbucket, ok := c.timeBuckets[bucketID]\n\tif !ok {\n\t\tbucket = make(map[metrics.TimeSeries]metricValue)\n\t\tc.timeBuckets[bucketID] = bucket\n\t}\n\n\t// Get or create the bucket's sinks map per time series\n\tsink, ok := bucket[s.TimeSeries]\n\tif !ok {\n\t\tsink = newMetricValue(s.Metric.Type)\n\t\tbucket[s.TimeSeries] = sink\n\t}\n\n\tsink.Add(s.Value)\n}\n\nfunc (c *collector) expiredBuckets() []timeBucket {\n\t// Still too recent buckets\n\t// where we prefer to wait a bit more\n\t// then, hopefully, we can aggregate more samples before flushing.\n\tbucketCutoffID := c.bucketCutoffID()\n\n\t// Here, it avoids pre-allocation\n\t// because it expects to be zero for most of the time\n\tvar expired []timeBucket\n\n\t// Mark as expired all aggregation buckets older than bucketCutoffID\n\tfor bucketID, seriesSinks := range c.timeBuckets {\n\t\tif bucketID > bucketCutoffID {\n\t\t\tcontinue\n\t\t}\n\n\t\texpired = append(expired, timeBucket{\n\t\t\tTime:  c.timeFromBucketID(bucketID),\n\t\t\tSinks: seriesSinks,\n\t\t})\n\t\tdelete(c.timeBuckets, bucketID)\n\t}\n\n\treturn expired\n}\n\nfunc (c *collector) bucketID(t time.Time) int64 {\n\treturn t.UnixNano() / int64(c.aggregationPeriod)\n}\n\nfunc (c *collector) timeFromBucketID(id int64) int64 {\n\treturn id * int64(c.aggregationPeriod)\n}\n\nfunc (c *collector) bucketCutoffID() int64 {\n\treturn c.nowFunc().Add(-c.waitPeriod).UnixNano() / int64(c.aggregationPeriod)\n}\n"
  },
  {
    "path": "output/cloud/expv2/collect_test.go",
    "content": "package expv2\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestNewCollectorError(t *testing.T) {\n\tt.Parallel()\n\n\t// TODO: more cases\n\t_, err := newCollector(4*time.Second+300*time.Millisecond, 1*time.Second)\n\trequire.ErrorContains(t, err, \"sub-second precision\")\n\n\t_, err = newCollector(4*time.Second, 1*time.Second+300*time.Millisecond)\n\trequire.ErrorContains(t, err, \"sub-second precision\")\n}\n\nfunc TestCollectorCollectSample(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\tm1, err := r.NewMetric(\"metric1\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\ttags := r.RootTagSet().With(\"t1\", \"v1\")\n\tsamples := metrics.Samples(make([]metrics.Sample, 3))\n\n\tc := collector{\n\t\taggregationPeriod: 3 * time.Second,\n\t\twaitPeriod:        1 * time.Second,\n\t\ttimeBuckets:       make(map[int64]map[metrics.TimeSeries]metricValue),\n\t\tnowFunc: func() time.Time {\n\t\t\treturn time.Unix(31, 0)\n\t\t},\n\t}\n\tfor i := range samples {\n\t\tsample := metrics.Sample{\n\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\tMetric: m1,\n\t\t\t\tTags:   tags,\n\t\t\t},\n\t\t\tValue: 1.0,\n\t\t\tTime:  time.Unix(int64((i+1)*10), 0), // 10, 20, 30\n\t\t}\n\t\tc.collectSample(sample)\n\t}\n\n\tassert.Len(t, c.timeBuckets, 3)\n}\n\nfunc TestCollectorCollectSampleAggregateNumbers(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\tm1, err := r.NewMetric(\"metric1\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\ttags := r.RootTagSet().With(\"t1\", \"v1\")\n\tsamples := metrics.Samples(make([]metrics.Sample, 3))\n\n\tc := collector{\n\t\taggregationPeriod: 3 * time.Second,\n\t\twaitPeriod:        1 * time.Second,\n\t\ttimeBuckets:       make(map[int64]map[metrics.TimeSeries]metricValue),\n\t\tnowFunc: func() time.Time {\n\t\t\treturn time.Unix(31, 0)\n\t\t},\n\t}\n\tts := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   tags,\n\t}\n\n\tfor i := range samples {\n\t\tsample := metrics.Sample{\n\t\t\tTimeSeries: ts,\n\t\t\tValue:      3.5,\n\t\t\t// it generates time // 11, 12, 13\n\t\t\t// then it will apply the following formula\n\t\t\t// for finding the bucketID\n\t\t\t// id(x) = floor(unixnano/aggregation)\n\t\t\t// e.g id(11) = floor(11/3) = floor(3.x) = 3\n\t\t\tTime: time.Unix(int64((i+1)+10), 0),\n\t\t}\n\t\tc.collectSample(sample)\n\t}\n\n\trequire.Len(t, c.timeBuckets, 2)\n\tassert.Contains(t, c.timeBuckets, int64(3))\n\tassert.Contains(t, c.timeBuckets, int64(4))\n\n\tsink, ok := c.timeBuckets[4][ts].(*counter)\n\trequire.True(t, ok)\n\tassert.Equal(t, 7.0, sink.Sum)\n}\n\nfunc TestDropExpiringDelay(t *testing.T) {\n\tt.Parallel()\n\n\tc := collector{waitPeriod: 1 * time.Second}\n\tc.DropExpiringDelay()\n\tassert.Zero(t, c.waitPeriod)\n}\n\nfunc TestCollectorExpiredBucketsNoExipired(t *testing.T) {\n\tt.Parallel()\n\n\tc := collector{\n\t\taggregationPeriod: 3 * time.Second,\n\t\twaitPeriod:        1 * time.Second,\n\t\tnowFunc: func() time.Time {\n\t\t\treturn time.Unix(10, 0)\n\t\t},\n\t\ttimeBuckets: map[int64]map[metrics.TimeSeries]metricValue{\n\t\t\t6: {},\n\t\t},\n\t}\n\trequire.Nil(t, c.expiredBuckets())\n}\n\nfunc TestCollectorExpiredBuckets(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\tm1, err := r.NewMetric(\"metric1\", metrics.Counter)\n\trequire.NoError(t, err)\n\n\tts1 := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"t1\", \"v1\"),\n\t}\n\tts2 := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"t1\", \"v2\"),\n\t}\n\n\tc := collector{\n\t\taggregationPeriod: 3 * time.Second,\n\t\twaitPeriod:        1 * time.Second,\n\t\tnowFunc: func() time.Time {\n\t\t\treturn time.Unix(10, 0)\n\t\t},\n\t\ttimeBuckets: map[int64]map[metrics.TimeSeries]metricValue{\n\t\t\t3: {\n\t\t\t\tts1: &counter{Sum: 10},\n\t\t\t\tts2: &counter{Sum: 4},\n\t\t\t},\n\t\t},\n\t}\n\texpired := c.expiredBuckets()\n\trequire.Len(t, expired, 1)\n\n\tassert.NotZero(t, expired[0].Time)\n\n\texp := map[metrics.TimeSeries]metricValue{\n\t\tts1: &counter{Sum: 10},\n\t\tts2: &counter{Sum: 4},\n\t}\n\tassert.Equal(t, exp, expired[0].Sinks)\n}\n\nfunc TestCollectorExpiredBucketsCutoff(t *testing.T) {\n\tt.Parallel()\n\n\tc := collector{\n\t\taggregationPeriod: 3 * time.Second,\n\t\twaitPeriod:        1 * time.Second,\n\t\tnowFunc: func() time.Time {\n\t\t\treturn time.Unix(10, 0)\n\t\t},\n\t\ttimeBuckets: map[int64]map[metrics.TimeSeries]metricValue{\n\t\t\t3: {},\n\t\t\t6: {},\n\t\t\t9: {},\n\t\t},\n\t}\n\texpired := c.expiredBuckets()\n\trequire.Len(t, expired, 1)\n\tassert.Len(t, c.timeBuckets, 2)\n\tassert.NotContains(t, c.timeBuckets, 3)\n\n\trequire.Len(t, expired, 1)\n\texpDateTime := time.Unix(9, 0).UTC().UnixNano()\n\tassert.Equal(t, expDateTime, expired[0].Time)\n}\n\nfunc TestCollectorBucketID(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tunixSeconds int64\n\t\tunixNano    int64\n\t\texp         int64\n\t}{\n\t\t{0, 0, 0},\n\t\t{2, 0, 0},\n\t\t{3, 0, 1},\n\t\t{28, 0, 9},\n\t\t{59, 7, 19},\n\t}\n\n\tc := collector{aggregationPeriod: 3 * time.Second}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.exp, c.bucketID(time.Unix(tc.unixSeconds, 0)))\n\t}\n}\n\nfunc TestCollectorTimeFromBucketID(t *testing.T) {\n\tt.Parallel()\n\n\tc := collector{aggregationPeriod: 3 * time.Second}\n\n\t// exp = TimeFromUnix(bucketID * aggregationPeriod) = Time(49 * 3s)\n\texp := time.Date(1970, time.January, 1, 0, 2, 27, 0, time.UTC).UnixNano()\n\tassert.Equal(t, exp, c.timeFromBucketID(49))\n}\n\nfunc TestCollectorBucketCutoffID(t *testing.T) {\n\tt.Parallel()\n\n\tc := collector{\n\t\taggregationPeriod: 3 * time.Second,\n\t\twaitPeriod:        1 * time.Second,\n\t\tnowFunc: func() time.Time {\n\t\t\t// 1st May 2023 - 01:06:06 + 8ns\n\t\t\treturn time.Date(2023, time.May, 1, 1, 6, 6, 8, time.UTC)\n\t\t},\n\t}\n\t// exp = floor((now-1s)/3s) = floor(1682903165/3)\n\tassert.Equal(t, int64(560967721), c.bucketCutoffID())\n}\n\nfunc TestBucketQPush(t *testing.T) {\n\tt.Parallel()\n\n\tbq := bucketQ{}\n\tbq.Push([]timeBucket{{Time: int64(1 * time.Second)}})\n\trequire.Len(t, bq.buckets, 1)\n}\n\nfunc TestBucketQPopAll(t *testing.T) {\n\tt.Parallel()\n\tbq := bucketQ{\n\t\tbuckets: []timeBucket{\n\t\t\t{Time: int64(1 * time.Second)},\n\t\t\t{Time: int64(2 * time.Second)},\n\t\t},\n\t}\n\tbuckets := bq.PopAll()\n\trequire.Len(t, buckets, 2)\n\tassert.NotZero(t, buckets[0].Time)\n\n\tassert.NotNil(t, bq.buckets)\n\tassert.Empty(t, bq.buckets)\n}\n\nfunc TestBucketQPushPopConcurrency(t *testing.T) {\n\tt.Parallel()\n\tvar (\n\t\tcount = 0\n\t\tbq    = bucketQ{}\n\t\tsink  = &counter{}\n\n\t\tstop = time.After(100 * time.Millisecond)\n\t\tpop  = make(chan struct{}, 10)\n\t\tdone = make(chan struct{})\n\t)\n\n\tgo func() {\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-done:\n\t\t\t\tclose(pop)\n\t\t\t\treturn\n\t\t\tcase <-pop:\n\t\t\t\tb := bq.PopAll()\n\t\t\t\t_ = append(b, timeBucket{})\n\t\t\t}\n\t\t}\n\t}()\n\n\tnow := time.Now().Truncate(time.Second).UnixNano()\n\tfor {\n\t\tselect {\n\t\tcase <-stop:\n\t\t\tclose(done)\n\t\t\treturn\n\t\tdefault:\n\t\t\tcount++\n\t\t\tbq.Push([]timeBucket{\n\t\t\t\t{\n\t\t\t\t\tTime: now,\n\t\t\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\t\t\t{}: sink,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\n\t\t\tif count%5 == 0 { // a fixed-arbitrary flush rate\n\t\t\t\tpop <- struct{}{}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "output/cloud/expv2/flush.go",
    "content": "package expv2\n\nimport (\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n\t\"go.k6.io/k6/metrics\"\n)\n\ntype pusher interface {\n\tpush(samples *pbcloud.MetricSet) error\n}\n\ntype metricsFlusher struct {\n\ttestRunID                  string\n\tbq                         *bucketQ\n\tclient                     pusher\n\tlogger                     logrus.FieldLogger\n\tdiscardedLabels            map[string]struct{}\n\taggregationPeriodInSeconds uint32\n\tmaxSeriesInBatch           int\n\tbatchPushConcurrency       int\n}\n\n// flush flushes the queued buckets sending them to the remote Cloud service.\n// If the number of time series collected is bigger than maximum batch size\n// then it splits in chunks.\nfunc (f *metricsFlusher) flush() error {\n\t// drain the buffer\n\tbuckets := f.bq.PopAll()\n\tif len(buckets) < 1 {\n\t\treturn nil\n\t}\n\n\t// Pivot the data structure from a slice of Timebuckets\n\t// to a metric set of time series where each has nested samples.\n\t//\n\t// The Protobuf payload structure has the metric as the first level\n\t// instead of the current slice of buckets that knows about the metric\n\t// only in deeply nested levels. So, we need to go through the buckets\n\t// and group them by metric. To avoid doing too many loops and allocations,\n\t// the metricSetBuilder is used for doing it during the traverse of the buckets.\n\n\tvar (\n\t\tstart       = time.Now()\n\t\tbatches     []*pbcloud.MetricSet\n\t\tseriesCount int\n\t)\n\n\tdefer func() {\n\t\tf.logger.\n\t\t\tWithField(\"t\", time.Since(start)).\n\t\t\tWithField(\"series\", seriesCount).\n\t\t\tWithField(\"buckets\", len(buckets)).\n\t\t\tWithField(\"batches\", len(batches)).Debug(\"Flush the queued buckets\")\n\t}()\n\n\tmsb := newMetricSetBuilder(f.testRunID, f.aggregationPeriodInSeconds)\n\tfor i := range buckets {\n\t\tfor timeSeries, sink := range buckets[i].Sinks {\n\t\t\tmsb.addTimeSeries(buckets[i].Time, timeSeries, sink)\n\t\t\tif len(msb.seriesIndex) < f.maxSeriesInBatch {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// We hit the batch size, let's flush\n\t\t\tseriesCount += len(msb.seriesIndex)\n\t\t\tbatches = append(batches, msb.MetricSet)\n\t\t\tf.reportDiscardedLabels(msb.discardedLabels)\n\n\t\t\t// Reset the builder\n\t\t\tmsb = newMetricSetBuilder(f.testRunID, f.aggregationPeriodInSeconds)\n\t\t}\n\t}\n\n\t// send the last (or the unique) MetricSet chunk to the remote service\n\tif len(msb.seriesIndex) != 0 {\n\t\tseriesCount += len(msb.seriesIndex)\n\t\tbatches = append(batches, msb.MetricSet)\n\t\tf.reportDiscardedLabels(msb.discardedLabels)\n\t}\n\n\treturn f.flushBatches(batches)\n}\n\nfunc (f *metricsFlusher) flushBatches(batches []*pbcloud.MetricSet) error {\n\tvar (\n\t\tworkers  = min(len(batches), f.batchPushConcurrency)\n\t\terrs     = make(chan error, workers)\n\t\tfeed     = make(chan *pbcloud.MetricSet)\n\t\tfinalErr error\n\t)\n\n\tfor i := 0; i < workers; i++ {\n\t\tgo func() {\n\t\t\tfor chunk := range feed {\n\t\t\t\tif err := f.client.push(chunk); err != nil {\n\t\t\t\t\terrs <- err\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\terrs <- nil\n\t\t}()\n\t}\n\nouter:\n\tfor i := range batches {\n\t\tselect {\n\t\tcase err := <-errs:\n\t\t\tworkers--\n\t\t\tfinalErr = err\n\t\t\tbreak outer\n\t\tcase feed <- batches[i]:\n\t\t}\n\t}\n\n\tclose(feed)\n\n\tfor ; workers != 0; workers-- {\n\t\terr := <-errs\n\t\tif err != nil && finalErr == nil {\n\t\t\tfinalErr = err\n\t\t}\n\t}\n\treturn finalErr\n}\n\nfunc (f *metricsFlusher) reportDiscardedLabels(discardedLabels map[string]struct{}) {\n\tfor key := range discardedLabels {\n\t\tif _, ok := f.discardedLabels[key]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tf.discardedLabels[key] = struct{}{}\n\t\tf.logger.Warnf(\"Tag %s has been discarded since it is reserved for Cloud operations.\", key)\n\t}\n}\n\ntype metricSetBuilder struct {\n\tMetricSet *pbcloud.MetricSet\n\n\t// TODO: If we will introduce the metricID then we could\n\t// just use it as map's key (map[uint64]pbcloud.Metric). It is faster.\n\t// Or maybe, when we will have a better vision around the dynamic tracking\n\t// for metrics (https://github.com/grafana/k6/issues/1321) then we could consider\n\t// if an array, with the length equals to the number of registered metrics,\n\t// could eventually work.\n\t//\n\t// TODO: we may evaluate to replace it with\n\t// map[*metrics.Metric][]*pbcloud.TimeSeries)\n\t// and use a sync.Pool for the series slice.\n\t// We need dedicated benchmarks before doing it.\n\t//\n\t// metrics tracks the related metric conversion\n\t// into a protobuf structure.\n\tmetrics map[*metrics.Metric]*pbcloud.Metric\n\n\t// seriesIndex tracks the index of the time series XYZ\n\t// in the related slice in\n\t// metrics[XYZ].<pbcloud.Metric>.TimeSeries.\n\t// It supports the iterative process for appending\n\t// the aggregated measurements for each time series.\n\tseriesIndex map[metrics.TimeSeries]int\n\n\t// discardedLabels tracks the labels that have been discarded\n\t// since they are reserved for internal usage by the Cloud service.\n\tdiscardedLabels map[string]struct{}\n}\n\nfunc newMetricSetBuilder(testRunID string, aggrPeriodSec uint32) metricSetBuilder {\n\tbuilder := metricSetBuilder{\n\t\tMetricSet: &pbcloud.MetricSet{},\n\t\t// TODO: evaluate if removing the pointer from pbcloud.Metric\n\t\t// is a better trade-off\n\t\tmetrics:         make(map[*metrics.Metric]*pbcloud.Metric),\n\t\tseriesIndex:     make(map[metrics.TimeSeries]int),\n\t\tdiscardedLabels: nil,\n\t}\n\tbuilder.MetricSet.TestRunId = testRunID\n\tbuilder.MetricSet.AggregationPeriod = aggrPeriodSec\n\treturn builder\n}\n\nfunc (msb *metricSetBuilder) addTimeSeries(timestamp int64, timeSeries metrics.TimeSeries, sink metricValue) {\n\tpbmetric, ok := msb.metrics[timeSeries.Metric]\n\tif !ok {\n\t\tpbmetric = &pbcloud.Metric{\n\t\t\tName: timeSeries.Metric.Name,\n\t\t\tType: mapMetricTypeProto(timeSeries.Metric.Type),\n\t\t}\n\t\tmsb.metrics[timeSeries.Metric] = pbmetric\n\t\tmsb.MetricSet.Metrics = append(msb.MetricSet.Metrics, pbmetric)\n\t}\n\n\tvar pbTimeSeries *pbcloud.TimeSeries\n\tif ix, ok := msb.seriesIndex[timeSeries]; !ok {\n\t\tlabels, discardedLabels := mapTimeSeriesLabelsProto(timeSeries.Tags)\n\t\tmsb.recordDiscardedLabels(discardedLabels)\n\n\t\tpbTimeSeries = &pbcloud.TimeSeries{\n\t\t\tLabels: labels,\n\t\t}\n\t\tpbmetric.TimeSeries = append(pbmetric.TimeSeries, pbTimeSeries)\n\t\tmsb.seriesIndex[timeSeries] = len(pbmetric.TimeSeries) - 1\n\t} else {\n\t\tpbTimeSeries = pbmetric.TimeSeries[ix]\n\t}\n\taddBucketToTimeSeriesProto(pbTimeSeries, timeSeries.Metric.Type, timestamp, sink)\n}\n\nfunc (msb *metricSetBuilder) recordDiscardedLabels(labels []string) {\n\tif len(labels) == 0 {\n\t\treturn\n\t}\n\n\tif msb.discardedLabels == nil {\n\t\tmsb.discardedLabels = make(map[string]struct{})\n\t}\n\n\tfor _, key := range labels {\n\t\tif _, ok := msb.discardedLabels[key]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tmsb.discardedLabels[key] = struct{}{}\n\t}\n}\n"
  },
  {
    "path": "output/cloud/expv2/flush_test.go",
    "content": "package expv2\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO: additional case\n// case: add when the metric already exist\n// case: add when the metric and the timeseries already exist\n\nfunc TestMetricSetBuilderAddTimeBucket(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric1\", metrics.Counter)\n\ttimeSeries := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"key1\", \"val1\"),\n\t}\n\n\tmsb := newMetricSetBuilder(\"testrunid-123\", 1)\n\tmsb.addTimeSeries(1, timeSeries, &counter{})\n\n\tassert.Contains(t, msb.metrics, m1)\n\trequire.Contains(t, msb.seriesIndex, timeSeries)\n\tassert.Equal(t, 0, msb.seriesIndex[timeSeries]) // TODO: assert with another number\n\n\trequire.Len(t, msb.MetricSet.Metrics, 1)\n\tassert.Len(t, msb.MetricSet.Metrics[0].TimeSeries, 1)\n}\n\nfunc TestMetricsFlusherFlushInBatchWithinBucket(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tseries        int\n\t\texpFlushCalls int\n\t}{\n\t\t{series: 5, expFlushCalls: 2},\n\t\t{series: 2, expFlushCalls: 1},\n\t}\n\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric1\", metrics.Counter)\n\tfor _, tc := range testCases {\n\t\tlogger, _ := testutils.NewLoggerWithHook(t)\n\n\t\tbq := &bucketQ{}\n\t\tpm := &pusherMock{}\n\t\tmf := metricsFlusher{\n\t\t\tbq:                   bq,\n\t\t\tclient:               pm,\n\t\t\tlogger:               logger,\n\t\t\tdiscardedLabels:      make(map[string]struct{}),\n\t\t\tmaxSeriesInBatch:     3,\n\t\t\tbatchPushConcurrency: 5,\n\t\t}\n\n\t\tbq.buckets = make([]timeBucket, 0, tc.series)\n\t\tsinks := make(map[metrics.TimeSeries]metricValue)\n\t\tfor i := 0; i < tc.series; i++ {\n\t\t\tts := metrics.TimeSeries{\n\t\t\t\tMetric: m1,\n\t\t\t\tTags:   r.RootTagSet().With(\"key1\", \"val\"+strconv.Itoa(i)),\n\t\t\t}\n\n\t\t\tsinks[ts] = &counter{Sum: float64(1)}\n\t\t}\n\t\trequire.Len(t, sinks, tc.series)\n\n\t\tbq.Push([]timeBucket{{Time: 1, Sinks: sinks}})\n\t\terr := mf.flush()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, tc.expFlushCalls, pm.timesCalled())\n\t}\n}\n\nfunc TestMetricsFlusherFlushInBatchAcrossBuckets(t *testing.T) {\n\tt.Parallel()\n\n\ttestCases := []struct {\n\t\tseries       int\n\t\texpPushCalls int\n\t}{\n\t\t{series: 5, expPushCalls: 2},\n\t\t{series: 2, expPushCalls: 1},\n\t}\n\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric1\", metrics.Counter)\n\tfor _, tc := range testCases {\n\t\tlogger, _ := testutils.NewLoggerWithHook(t)\n\n\t\tbq := &bucketQ{}\n\t\tpm := &pusherMock{}\n\t\tmf := metricsFlusher{\n\t\t\tbq:                   bq,\n\t\t\tclient:               pm,\n\t\t\tlogger:               logger,\n\t\t\tdiscardedLabels:      make(map[string]struct{}),\n\t\t\tmaxSeriesInBatch:     3,\n\t\t\tbatchPushConcurrency: 5,\n\t\t}\n\n\t\tbq.buckets = make([]timeBucket, 0, tc.series)\n\t\tfor i := 0; i < tc.series; i++ {\n\t\t\tts := metrics.TimeSeries{\n\t\t\t\tMetric: m1,\n\t\t\t\tTags:   r.RootTagSet().With(\"key1\", \"val\"+strconv.Itoa(i)),\n\t\t\t}\n\t\t\tbq.Push([]timeBucket{\n\t\t\t\t{\n\t\t\t\t\tTime: int64(i) + 1,\n\t\t\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\t\t\tts: &counter{Sum: float64(1)},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\trequire.Len(t, bq.buckets, tc.series)\n\n\t\terr := mf.flush()\n\t\trequire.NoError(t, err)\n\t\tassert.Equal(t, tc.expPushCalls, pm.timesCalled())\n\t}\n}\n\nfunc TestFlushWithReservedLabels(t *testing.T) {\n\tt.Parallel()\n\n\tlogger, hook := testutils.NewLoggerWithHook(t)\n\n\tmutex := sync.Mutex{}\n\tcollected := make([]*pbcloud.MetricSet, 0)\n\n\tbq := &bucketQ{}\n\tpm := &pusherMock{\n\t\thook: func(ms *pbcloud.MetricSet) {\n\t\t\tmutex.Lock()\n\t\t\tcollected = append(collected, ms)\n\t\t\tmutex.Unlock()\n\t\t},\n\t}\n\n\tmf := metricsFlusher{\n\t\tbq:                   bq,\n\t\tclient:               pm,\n\t\tmaxSeriesInBatch:     2,\n\t\tlogger:               logger,\n\t\tdiscardedLabels:      make(map[string]struct{}),\n\t\tbatchPushConcurrency: 5,\n\t}\n\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric1\", metrics.Counter)\n\n\tts1 := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"key1\", \"val1\").With(\"__name__\", \"val2\").With(\"test_run_id\", \"testrunid-123\"),\n\t}\n\tbq.Push([]timeBucket{\n\t\t{\n\t\t\tTime: 1,\n\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\tts1: &counter{Sum: float64(1)},\n\t\t\t},\n\t\t},\n\t})\n\n\tts2 := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"key1\", \"val2\").With(\"__name__\", \"val2\"),\n\t}\n\tbq.Push([]timeBucket{\n\t\t{\n\t\t\tTime: 2,\n\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\tts2: &counter{Sum: float64(1)},\n\t\t\t},\n\t\t},\n\t})\n\n\terr := mf.flush()\n\trequire.NoError(t, err)\n\n\tloglines := hook.Drain()\n\trequire.Len(t, collected, 1)\n\n\t// check that warnings sown only once per label\n\tassert.Len(t, testutils.FilterEntries(loglines, logrus.WarnLevel, \"Tag __name__ has been discarded since it is reserved for Cloud operations.\"), 1)\n\tassert.Len(t, testutils.FilterEntries(loglines, logrus.WarnLevel, \"Tag test_run_id has been discarded since it is reserved for Cloud operations.\"), 1)\n\n\t// check that flusher is not sending labels with reserved names\n\trequire.Len(t, collected[0].Metrics, 1)\n\n\tts := collected[0].Metrics[0].TimeSeries\n\trequire.Len(t, ts[0].Labels, 1)\n\tassert.Equal(t, \"key1\", ts[0].Labels[0].Name)\n\tassert.Equal(t, \"val1\", ts[0].Labels[0].Value)\n\n\trequire.Len(t, ts[1].Labels, 1)\n\tassert.Equal(t, \"key1\", ts[1].Labels[0].Name)\n\tassert.Equal(t, \"val2\", ts[1].Labels[0].Value)\n}\n\nfunc TestFlushMaxSeriesInBatch(t *testing.T) {\n\tt.Parallel()\n\n\tlogger := testutils.NewLogger(t)\n\n\tmutex := sync.Mutex{}\n\tcollected := make([]*pbcloud.MetricSet, 0)\n\n\tbq := &bucketQ{}\n\tpm := &pusherMock{\n\t\thook: func(ms *pbcloud.MetricSet) {\n\t\t\tmutex.Lock()\n\t\t\tcollected = append(collected, ms)\n\t\t\tmutex.Unlock()\n\t\t},\n\t}\n\n\tmf := metricsFlusher{\n\t\tbq:                   bq,\n\t\tclient:               pm,\n\t\tmaxSeriesInBatch:     2,\n\t\tlogger:               logger,\n\t\tdiscardedLabels:      make(map[string]struct{}),\n\t\tbatchPushConcurrency: 5,\n\t}\n\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric1\", metrics.Counter)\n\n\tts1 := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"key1\", \"val1\"),\n\t}\n\tbq.Push([]timeBucket{\n\t\t{\n\t\t\tTime: 1,\n\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\tts1: &counter{Sum: float64(1)},\n\t\t\t},\n\t\t},\n\t})\n\n\tts2 := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"key1\", \"val2\"),\n\t}\n\tbq.Push([]timeBucket{\n\t\t{\n\t\t\tTime: 2,\n\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\tts2: &counter{Sum: float64(2)},\n\t\t\t},\n\t\t},\n\t})\n\n\tts3 := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"key1\", \"val3\"),\n\t}\n\tbq.Push([]timeBucket{\n\t\t{\n\t\t\tTime: 3,\n\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\tts3: &counter{Sum: float64(3)},\n\t\t\t},\n\t\t},\n\t})\n\terr := mf.flush()\n\trequire.NoError(t, err)\n\n\trequire.Len(t, collected, 2)\n\n\t// Collect all label values across all batches (order-independent)\n\t// to avoid flakiness from concurrent batch pushing\n\tallLabelValues := make(map[string]struct{})\n\tbatchSizes := make([]int, 0, len(collected))\n\n\tfor _, ms := range collected {\n\t\trequire.Len(t, ms.Metrics, 1)\n\t\tts := ms.Metrics[0].TimeSeries\n\t\tbatchSizes = append(batchSizes, len(ts))\n\n\t\tfor _, series := range ts {\n\t\t\trequire.Len(t, series.Labels, 1)\n\t\t\tassert.Equal(t, \"key1\", series.Labels[0].Name)\n\t\t\tallLabelValues[series.Labels[0].Value] = struct{}{}\n\t\t}\n\t}\n\n\t// Verify all expected values were flushed\n\tassert.Contains(t, allLabelValues, \"val1\")\n\tassert.Contains(t, allLabelValues, \"val2\")\n\tassert.Contains(t, allLabelValues, \"val3\")\n\tassert.Len(t, allLabelValues, 3)\n\n\t// Verify batch sizes: one batch with 2 series, one with 1 series\n\tassert.ElementsMatch(t, []int{2, 1}, batchSizes)\n}\n\ntype pusherMock struct {\n\t// hook is called when the push method is called.\n\thook func(*pbcloud.MetricSet)\n\t// errFn if this defined, it is called at the end of push\n\t// and result error is returned.\n\terrFn      func() error\n\tpushCalled int64\n}\n\nfunc (pm *pusherMock) timesCalled() int {\n\treturn int(atomic.LoadInt64(&pm.pushCalled))\n}\n\nfunc (pm *pusherMock) push(ms *pbcloud.MetricSet) error {\n\tif pm.hook != nil {\n\t\tpm.hook(ms)\n\t}\n\n\tatomic.AddInt64(&pm.pushCalled, 1)\n\n\tif pm.errFn != nil {\n\t\treturn pm.errFn()\n\t}\n\n\treturn nil\n}\n\nfunc TestMetricsFlusherErrorCase(t *testing.T) {\n\tt.Parallel()\n\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric1\", metrics.Counter)\n\n\tlogger, _ := testutils.NewLoggerWithHook(t)\n\n\tbq := &bucketQ{}\n\tpm := &pusherMock{\n\t\terrFn: func() error {\n\t\t\treturn errors.New(\"some error\")\n\t\t},\n\t}\n\tmf := metricsFlusher{\n\t\tbq:                   bq,\n\t\tclient:               pm,\n\t\tlogger:               logger,\n\t\tdiscardedLabels:      make(map[string]struct{}),\n\t\tmaxSeriesInBatch:     3,\n\t\tbatchPushConcurrency: 2,\n\t}\n\n\tseries := 7\n\n\tbq.buckets = make([]timeBucket, 0, series)\n\tfor i := range series {\n\t\tts := metrics.TimeSeries{\n\t\t\tMetric: m1,\n\t\t\tTags:   r.RootTagSet().With(\"key1\", \"val\"+strconv.Itoa(i)),\n\t\t}\n\t\tbq.Push([]timeBucket{\n\t\t\t{\n\t\t\t\tTime: int64(i) + 1,\n\t\t\t\tSinks: map[metrics.TimeSeries]metricValue{\n\t\t\t\t\tts: &counter{Sum: float64(1)},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t}\n\trequire.Len(t, bq.buckets, series)\n\n\terr := mf.flush()\n\trequire.Error(t, err)\n\t// since the push happens concurrently the number of the calls could vary,\n\t// but at least one call should happen and it should be less than the\n\t// batchPushConcurrency\n\tassert.LessOrEqual(t, pm.timesCalled(), mf.batchPushConcurrency)\n\tassert.GreaterOrEqual(t, pm.timesCalled(), 1)\n}\n"
  },
  {
    "path": "output/cloud/expv2/hdr.go",
    "content": "package expv2\n\nimport (\n\t\"slices\"\n\n\t\"go.k6.io/k6/internal/ds/histogram\"\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n)\n\n// histogramAsProto converts the histogram into the equivalent Protobuf version.\nfunc histogramAsProto(h *histogram.Hdr, time int64) *pbcloud.TrendHdrValue {\n\tvar (\n\t\tindexes  []uint32\n\t\tcounters []uint32\n\t\tspans    []*pbcloud.BucketSpan\n\t)\n\n\t// allocate only if at least one item is available, in the case of only\n\t// untrackable values, then Indexes and Buckets are expected to be empty.\n\tif len(h.Buckets) > 0 {\n\t\tindexes = make([]uint32, 0, len(h.Buckets))\n\t\tfor index := range h.Buckets {\n\t\t\tindexes = append(indexes, index)\n\t\t}\n\t\tslices.Sort(indexes)\n\n\t\t// init the counters\n\t\tcounters = make([]uint32, 1, len(h.Buckets))\n\t\tcounters[0] = h.Buckets[indexes[0]]\n\t\t// open the first span\n\t\tspans = append(spans, &pbcloud.BucketSpan{Offset: indexes[0], Length: 1})\n\t}\n\n\tfor i := 1; i < len(indexes); i++ {\n\t\tcounters = append(counters, h.Buckets[indexes[i]])\n\n\t\t// if the current and the previous indexes are not consecutive\n\t\t// consider as closed the current on-going span and start a new one.\n\t\tif zerosBetween := indexes[i] - indexes[i-1] - 1; zerosBetween > 0 {\n\t\t\tspans = append(spans, &pbcloud.BucketSpan{Offset: zerosBetween, Length: 1})\n\t\t\tcontinue\n\t\t}\n\n\t\tspans[len(spans)-1].Length++\n\t}\n\n\thval := &pbcloud.TrendHdrValue{\n\t\tTime:          timestampAsProto(time),\n\t\tMinValue:      h.Min,\n\t\tMaxValue:      h.Max,\n\t\tSum:           h.Sum,\n\t\tCount:         h.Count,\n\t\tCounters:      counters,\n\t\tSpans:         spans,\n\t\tMinResolution: h.MinimumResolution,\n\t}\n\tif h.ExtraLowBucket > 0 {\n\t\thval.ExtraLowValuesCounter = &h.ExtraLowBucket\n\t}\n\tif h.ExtraHighBucket > 0 {\n\t\thval.ExtraHighValuesCounter = &h.ExtraHighBucket\n\t}\n\treturn hval\n}\n"
  },
  {
    "path": "output/cloud/expv2/hdr_test.go",
    "content": "package expv2\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"go.k6.io/k6/internal/ds/histogram\"\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n)\n\nfunc TestHistogramAsProto(t *testing.T) {\n\tt.Parallel()\n\n\tuint32ptr := func(v uint32) *uint32 {\n\t\treturn &v\n\t}\n\n\tcases := []struct {\n\t\tname          string\n\t\tvals          []float64\n\t\tminResolution float64\n\t\texp           *pbcloud.TrendHdrValue\n\t}{\n\t\t{\n\t\t\tname: \"EmptyHistogram\",\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tMaxValue: -math.MaxFloat64,\n\t\t\t\tMinValue: math.MaxFloat64,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"UntrackableValues\",\n\t\t\tvals:          []float64{-0.23, 1<<64 - 1},\n\t\t\tminResolution: 1.0,\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tExtraLowValuesCounter:  uint32ptr(1),\n\t\t\t\tExtraHighValuesCounter: uint32ptr(1),\n\t\t\t\tCounters:               nil,\n\t\t\t\tSpans:                  nil,\n\t\t\t\tCount:                  2,\n\t\t\t\tMinValue:               -0.23,\n\t\t\t\tMaxValue:               1<<64 - 1,\n\t\t\t\tSum:                    (1 << 64) - 1 - 0.23,\n\t\t\t\tMinResolution:          1.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"SimpleValuesWithLowerResolution\",\n\t\t\tvals:          []float64{7, 8, 9, 11, 12, 11.5, 10.5},\n\t\t\tminResolution: 1.0,\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tCount:                  7,\n\t\t\t\tExtraLowValuesCounter:  nil,\n\t\t\t\tExtraHighValuesCounter: nil,\n\t\t\t\tCounters:               []uint32{1, 1, 1, 2, 2},\n\t\t\t\tSpans: []*pbcloud.BucketSpan{\n\t\t\t\t\t{Offset: 7, Length: 3},\n\t\t\t\t\t{Offset: 1, Length: 2}, // 11\n\t\t\t\t},\n\t\t\t\tMinValue:      7,\n\t\t\t\tMaxValue:      12,\n\t\t\t\tSum:           69,\n\t\t\t\tMinResolution: 1.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"SimpleValues\",\n\t\t\tvals:          []float64{7, 8, 9, 11, 12, 11.5, 10.5},\n\t\t\tminResolution: .001,\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tCount:                  7,\n\t\t\t\tExtraLowValuesCounter:  nil,\n\t\t\t\tExtraHighValuesCounter: nil,\n\t\t\t\tCounters:               []uint32{1, 1, 1, 1, 1, 1, 1},\n\t\t\t\tSpans: []*pbcloud.BucketSpan{\n\t\t\t\t\t{Offset: 858, Length: 1},\n\t\t\t\t\t{Offset: 31, Length: 1}, // 890\n\t\t\t\t\t{Offset: 17, Length: 1}, // 908\n\t\t\t\t\t{Offset: 23, Length: 1}, // 932\n\t\t\t\t\t{Offset: 6, Length: 1},  // 939\n\t\t\t\t\t{Offset: 7, Length: 1},  // 947\n\t\t\t\t\t{Offset: 7, Length: 1},  // 955\n\t\t\t\t},\n\t\t\t\tMinValue:      7,\n\t\t\t\tMaxValue:      12,\n\t\t\t\tSum:           69,\n\t\t\t\tMinResolution: .001,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"WithZeroPointValues\",\n\t\t\tvals:          []float64{2, 0.01, 3},\n\t\t\tminResolution: .001,\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tCount:                  3,\n\t\t\t\tExtraLowValuesCounter:  nil,\n\t\t\t\tExtraHighValuesCounter: nil,\n\t\t\t\tCounters:               []uint32{1, 1, 1},\n\t\t\t\tSpans: []*pbcloud.BucketSpan{\n\t\t\t\t\t{\n\t\t\t\t\t\tOffset: 10,\n\t\t\t\t\t\tLength: 1,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tOffset: 623,\n\t\t\t\t\t\tLength: 1,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tOffset: 64,\n\t\t\t\t\t\tLength: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMinValue:      0.01,\n\t\t\t\tMaxValue:      3,\n\t\t\t\tSum:           5.01,\n\t\t\t\tMinResolution: .001,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"VeryBasic\",\n\t\t\tvals:          []float64{2, 1.1, 3},\n\t\t\tminResolution: 1.0,\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tCount:                  3,\n\t\t\t\tExtraLowValuesCounter:  nil,\n\t\t\t\tExtraHighValuesCounter: nil,\n\t\t\t\tCounters:               []uint32{2, 1},\n\t\t\t\tSpans: []*pbcloud.BucketSpan{\n\t\t\t\t\t{\n\t\t\t\t\t\tOffset: 2,\n\t\t\t\t\t\tLength: 2,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMinValue:      1.1,\n\t\t\t\tMaxValue:      3,\n\t\t\t\tSum:           6.1,\n\t\t\t\tMinResolution: 1.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"LongerSequence\",\n\t\t\tvals: []float64{\n\t\t\t\t2275, 52.25, 268.85, 383.47, 18.49,\n\t\t\t\t163.85, 4105, 835.27, 52, 18.28, 238.44, 39751, 18.86,\n\t\t\t\t967.05, 967.01, 967, 4123.5, 270.69, 677.27,\n\t\t\t},\n\t\t\t// It uses 1.0 as resolution for keeping numbers smaller\n\t\t\t// and the test more controllable.\n\t\t\tminResolution: 1.0,\n\t\t\t// Sorted:\n\t\t\t//     18.28,18.49,18.86,52,52.25,163.85,\n\t\t\t//     238.44,268.85,270.69,383.47,677.27,835.27,967,967.01,967.05\n\t\t\t//     2275, 4105, 4123.5, 39751\n\t\t\t// Distribution\n\t\t\t// - {x<256}: 19:3, 52:1, 53:1, 164:1, 239:1\n\t\t\t// - {x >= 256}: 262:1, 263:1, 320:1, 425:1, 465:1, 497:1 498:2\n\t\t\t// - {x > 1k}: 654:1, 768:2, 1179:1\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tCount:    19,\n\t\t\t\tCounters: []uint32{3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1},\n\t\t\t\tSpans: []*pbcloud.BucketSpan{\n\t\t\t\t\t{Offset: 19, Length: 1},\n\t\t\t\t\t{Offset: 32, Length: 2},\n\t\t\t\t\t{Offset: 110, Length: 1},\n\t\t\t\t\t{Offset: 74, Length: 1},\n\t\t\t\t\t{Offset: 22, Length: 2}, // 262\n\t\t\t\t\t{Offset: 56, Length: 1},\n\t\t\t\t\t{Offset: 104, Length: 1},\n\t\t\t\t\t{Offset: 39, Length: 1},\n\t\t\t\t\t{Offset: 31, Length: 2},\n\t\t\t\t\t{Offset: 155, Length: 1}, // 654\n\t\t\t\t\t{Offset: 113, Length: 1},\n\t\t\t\t\t{Offset: 410, Length: 1},\n\t\t\t\t},\n\t\t\t\tExtraLowValuesCounter:  nil,\n\t\t\t\tExtraHighValuesCounter: nil,\n\t\t\t\tMinValue:               18.28,\n\t\t\t\tMaxValue:               39751,\n\t\t\t\tSum:                    56153.280000000006,\n\t\t\t\tMinResolution:          1.0,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"Unrealistic\",\n\t\t\tvals:          []float64{math.MaxUint32},\n\t\t\tminResolution: .001,\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tCount:                  1,\n\t\t\t\tExtraLowValuesCounter:  nil,\n\t\t\t\tExtraHighValuesCounter: nil,\n\t\t\t\tCounters:               []uint32{1},\n\t\t\t\tSpans: []*pbcloud.BucketSpan{\n\t\t\t\t\t{\n\t\t\t\t\t\tOffset: 4601,\n\t\t\t\t\t\tLength: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMinValue:      math.MaxUint32,\n\t\t\t\tMaxValue:      math.MaxUint32,\n\t\t\t\tSum:           math.MaxUint32,\n\t\t\t\tMinResolution: .001,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:          \"DefaultMinimumResolution\",\n\t\t\tvals:          []float64{200, 100, 200.1},\n\t\t\tminResolution: .001,\n\t\t\texp: &pbcloud.TrendHdrValue{\n\t\t\t\tCount:                  3,\n\t\t\t\tExtraLowValuesCounter:  nil,\n\t\t\t\tExtraHighValuesCounter: nil,\n\t\t\t\tMinResolution:          .001,\n\t\t\t\tCounters:               []uint32{1, 2},\n\t\t\t\tSpans: []*pbcloud.BucketSpan{\n\t\t\t\t\t{\n\t\t\t\t\t\tOffset: 1347,\n\t\t\t\t\t\tLength: 1,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tOffset: 127,\n\t\t\t\t\t\tLength: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tMinValue: 100,\n\t\t\t\tMaxValue: 200.1,\n\t\t\t\tSum:      500.1,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\th := histogram.NewHdr()\n\t\t\th.MinimumResolution = tc.minResolution\n\n\t\t\tfor _, v := range tc.vals {\n\t\t\t\th.Add(v)\n\t\t\t}\n\t\t\ttc.exp.Time = &timestamppb.Timestamp{Seconds: 1}\n\t\t\thproto := histogramAsProto(h, time.Unix(1, 0).UnixNano())\n\t\t\trequire.Equal(t, tc.exp.Count, hproto.Count)\n\t\t\trequire.Equal(t, tc.exp.Counters, hproto.Counters)\n\t\t\trequire.Equal(t, len(tc.exp.Spans), len(hproto.Spans))\n\t\t\tassert.Equal(t, tc.exp, hproto, tc.name)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "output/cloud/expv2/mapping.go",
    "content": "package expv2\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/mstoykov/atlas\"\n\t\"google.golang.org/protobuf/types/known/timestamppb\"\n\n\t\"go.k6.io/k6/internal/ds/histogram\"\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO: unit test\nfunc mapTimeSeriesLabelsProto(tags *metrics.TagSet) ([]*pbcloud.Label, []string) {\n\tlabels := make([]*pbcloud.Label, 0, ((*atlas.Node)(tags)).Len())\n\tvar discardedLabels []string\n\n\t// TODO: move this as a shared func\n\t// https://github.com/grafana/k6/issues/2764\n\tn := (*atlas.Node)(tags)\n\tif n.Len() < 1 {\n\t\treturn labels, discardedLabels\n\t}\n\tfor !n.IsRoot() {\n\t\tprev, key, value := n.Data()\n\n\t\tn = prev\n\t\tif !isReservedLabelName(key) {\n\t\t\tlabels = append(labels, &pbcloud.Label{Name: key, Value: value})\n\t\t\tcontinue\n\t\t}\n\n\t\tif discardedLabels == nil {\n\t\t\tdiscardedLabels = make([]string, 0, 1)\n\t\t}\n\n\t\tdiscardedLabels = append(discardedLabels, key)\n\t}\n\treturn labels, discardedLabels\n}\n\nfunc isReservedLabelName(name string) bool {\n\t// this is a reserved label prefix for the prometheus\n\tif strings.HasPrefix(name, \"__\") {\n\t\treturn true\n\t}\n\n\treturn name == \"test_run_id\"\n}\n\n// TODO: unit test\nfunc mapMetricTypeProto(mt metrics.MetricType) pbcloud.MetricType {\n\tvar mtype pbcloud.MetricType\n\tswitch mt {\n\tcase metrics.Counter:\n\t\tmtype = pbcloud.MetricType_METRIC_TYPE_COUNTER\n\tcase metrics.Gauge:\n\t\tmtype = pbcloud.MetricType_METRIC_TYPE_GAUGE\n\tcase metrics.Rate:\n\t\tmtype = pbcloud.MetricType_METRIC_TYPE_RATE\n\tcase metrics.Trend:\n\t\tmtype = pbcloud.MetricType_METRIC_TYPE_TREND\n\t}\n\treturn mtype\n}\n\n// TODO: unit test\nfunc addBucketToTimeSeriesProto(\n\ttimeSeries *pbcloud.TimeSeries,\n\tmt metrics.MetricType,\n\ttime int64,\n\tvalue metricValue,\n) {\n\tif timeSeries.Samples == nil {\n\t\tinitTimeSeriesSamples(timeSeries, mt)\n\t}\n\n\tswitch typedMetricValue := value.(type) {\n\tcase *counter:\n\t\tsamples := timeSeries.GetCounterSamples()\n\t\tsamples.Values = append(samples.Values, &pbcloud.CounterValue{\n\t\t\tTime:  timestampAsProto(time),\n\t\t\tValue: typedMetricValue.Sum,\n\t\t})\n\tcase *gauge:\n\t\tsamples := timeSeries.GetGaugeSamples()\n\t\tsamples.Values = append(samples.Values, &pbcloud.GaugeValue{\n\t\t\tTime:  timestampAsProto(time),\n\t\t\tLast:  typedMetricValue.Last,\n\t\t\tMin:   typedMetricValue.Max,\n\t\t\tMax:   typedMetricValue.Min,\n\t\t\tAvg:   typedMetricValue.Avg,\n\t\t\tCount: typedMetricValue.Count,\n\t\t})\n\tcase *rate:\n\t\tsamples := timeSeries.GetRateSamples()\n\t\tsamples.Values = append(samples.Values, &pbcloud.RateValue{\n\t\t\tTime:         timestampAsProto(time),\n\t\t\tNonzeroCount: typedMetricValue.NonZeroCount,\n\t\t\tTotalCount:   typedMetricValue.Total,\n\t\t})\n\tcase *histogram.Hdr:\n\t\tsamples := timeSeries.GetTrendHdrSamples()\n\t\tsamples.Values = append(samples.Values, histogramAsProto(typedMetricValue, time))\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"MetricType %q is not supported\", mt))\n\t}\n}\n\n// TODO: unit test\nfunc initTimeSeriesSamples(timeSeries *pbcloud.TimeSeries, mt metrics.MetricType) {\n\tswitch mt {\n\tcase metrics.Counter:\n\t\ttimeSeries.Samples = &pbcloud.TimeSeries_CounterSamples{\n\t\t\tCounterSamples: &pbcloud.CounterSamples{},\n\t\t}\n\tcase metrics.Gauge:\n\t\ttimeSeries.Samples = &pbcloud.TimeSeries_GaugeSamples{\n\t\t\tGaugeSamples: &pbcloud.GaugeSamples{},\n\t\t}\n\tcase metrics.Rate:\n\t\ttimeSeries.Samples = &pbcloud.TimeSeries_RateSamples{\n\t\t\tRateSamples: &pbcloud.RateSamples{},\n\t\t}\n\tcase metrics.Trend:\n\t\ttimeSeries.Samples = &pbcloud.TimeSeries_TrendHdrSamples{\n\t\t\tTrendHdrSamples: &pbcloud.TrendHdrSamples{},\n\t\t}\n\t}\n}\n\nfunc timestampAsProto(unixnano int64) *timestamppb.Timestamp {\n\tsec := unixnano / 1e9\n\treturn &timestamppb.Timestamp{\n\t\tSeconds: sec,\n\t\t// sub-second precision for aggregation is not expected\n\t\t// so we don't waste cpu-time computing nanos.\n\t\t//\n\t\t// In the case this assumption is changed then enable them\n\t\t// by int32(unixnano - (sec * 1e9))\n\t\tNanos: 0,\n\t}\n}\n"
  },
  {
    "path": "output/cloud/expv2/mapping_test.go",
    "content": "package expv2\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTimestampAsProto(t *testing.T) {\n\tt.Parallel()\n\n\tdate := time.Unix(10, 0).UTC()\n\ttimestamp := timestampAsProto(date.UnixNano())\n\tassert.Equal(t, date, timestamp.AsTime())\n\n\t// sub-second precision is not supported\n\tdate = time.Unix(10, 282).UTC()\n\ttimestamp = timestampAsProto(date.UnixNano())\n\tassert.Equal(t, time.Unix(10, 0).UTC(), timestamp.AsTime())\n}\n"
  },
  {
    "path": "output/cloud/expv2/metrics_client.go",
    "content": "package expv2\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/klauspost/compress/snappy\"\n\t\"google.golang.org/protobuf/proto\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n)\n\n// metricsClient is a Protobuf over HTTP client for sending\n// the collected metrics from the Cloud output\n// to the remote service.\ntype metricsClient struct {\n\thttpClient *cloudapi.Client\n\turl        string\n}\n\n// newMetricsClient creates and initializes a new MetricsClient.\nfunc newMetricsClient(c *cloudapi.Client, testRunID string) (*metricsClient, error) {\n\t// The cloudapi.Client works across different versions of the API, the test\n\t// lifecycle management is under /v1 instead the metrics ingestion is /v2.\n\t// Unfortunately, the current client has v1 hard-coded so we need to trim the wrong path\n\t// to be able to replace it with the correct one.\n\t// A versioned client would be better but it would require a breaking change\n\t// and considering that other services (e.g. k6-operator) depend on it,\n\t// we want to stabilize the API before.\n\tu := c.BaseURL()\n\tif !strings.HasSuffix(u, \"/v1\") {\n\t\treturn nil, errors.New(\"a /v1 suffix is expected in the Cloud service's BaseURL path\")\n\t}\n\tif testRunID == \"\" {\n\t\treturn nil, errors.New(\"TestRunID of the test is required\")\n\t}\n\treturn &metricsClient{\n\t\thttpClient: c,\n\t\turl:        strings.TrimSuffix(u, \"/v1\") + \"/v2/metrics/\" + testRunID,\n\t}, nil\n}\n\n// Push the provided metrics for the given test run ID.\nfunc (mc *metricsClient) push(samples *pbcloud.MetricSet) error {\n\tb, err := newRequestBody(samples)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq, err := http.NewRequestWithContext(\n\t\tcontext.Background(), http.MethodPost, mc.url, io.NopCloser(bytes.NewReader(b)))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treq.GetBody = func() (io.ReadCloser, error) {\n\t\treturn io.NopCloser(bytes.NewReader(b)), nil\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/x-protobuf\")\n\treq.Header.Set(\"Content-Encoding\", \"snappy\")\n\treq.Header.Set(\"K6-Metrics-Protocol-Version\", \"2.0\")\n\n\terr = mc.httpClient.Do(req, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc newRequestBody(data *pbcloud.MetricSet) ([]byte, error) {\n\tb, err := proto.Marshal(data)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"encoding metrics as Protobuf write request failed: %w\", err)\n\t}\n\t// TODO: use the framing format\n\t// https://github.com/google/snappy/blob/main/framing_format.txt\n\t// It can be done replacing the encode with\n\t// https://pkg.go.dev/github.com/klauspost/compress/snappy#NewBufferedWriter\n\tif snappy.MaxEncodedLen(len(b)) < 0 {\n\t\treturn nil, fmt.Errorf(\"the Protobuf message is too large to be handled by Snappy encoder; \"+\n\t\t\t\"size: %d, limit: %d\", len(b), 0xffffffff)\n\t}\n\treturn snappy.Encode(nil, b), nil\n}\n"
  },
  {
    "path": "output/cloud/expv2/metrics_client_test.go",
    "content": "package expv2\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/internal/output/cloud/expv2/pbcloud\"\n)\n\nfunc TestMetricsClientPush(t *testing.T) {\n\tt.Parallel()\n\n\treqs := 0\n\th := func(_ http.ResponseWriter, r *http.Request) {\n\t\treqs++\n\n\t\tassert.Equal(t, \"/v2/metrics/test-ref-id\", r.URL.Path)\n\t\tassert.Equal(t, http.MethodPost, r.Method)\n\t\tassert.Equal(t, \"Token fake-token\", r.Header.Get(\"Authorization\"))\n\t\tassert.Contains(t, r.Header.Get(\"User-Agent\"), \"k6cloud/v0.4\")\n\t\tassert.Equal(t, \"application/x-protobuf\", r.Header.Get(\"Content-Type\"))\n\t\tassert.Equal(t, \"snappy\", r.Header.Get(\"Content-Encoding\"))\n\t\tassert.Equal(t, \"2.0\", r.Header.Get(\"K6-Metrics-Protocol-Version\"))\n\t\tb, err := io.ReadAll(r.Body)\n\t\trequire.NoError(t, err)\n\t\tassert.NotEmpty(t, b)\n\t}\n\n\tts := httptest.NewServer(http.HandlerFunc(h))\n\tdefer ts.Close()\n\n\tc := cloudapi.NewClient(nil, \"fake-token\", ts.URL, \"k6cloud/v0.4\", 1*time.Second)\n\tmc, err := newMetricsClient(c, \"test-ref-id\")\n\trequire.NoError(t, err)\n\n\tmset := pbcloud.MetricSet{}\n\terr = mc.push(&mset)\n\trequire.NoError(t, err)\n\tassert.Equal(t, 1, reqs)\n}\n\nfunc TestMetricsClientPushUnexpectedStatus(t *testing.T) {\n\tt.Parallel()\n\n\th := func(rw http.ResponseWriter, _ *http.Request) {\n\t\trw.WriteHeader(http.StatusInternalServerError)\n\t}\n\tts := httptest.NewServer(http.HandlerFunc(h))\n\tdefer ts.Close()\n\n\tc := cloudapi.NewClient(nil, \"fake-token\", ts.URL, \"k6cloud/v0.4\", 1*time.Second)\n\tmc, err := newMetricsClient(c, \"test-ref-id\")\n\trequire.NoError(t, err)\n\n\terr = mc.push(nil)\n\tassert.ErrorContains(t, err, \"500 Internal Server Error\")\n}\n"
  },
  {
    "path": "output/cloud/expv2/output.go",
    "content": "// Package expv2 contains a Cloud output using a Protobuf\n// binary format for encoding payloads.\npackage expv2\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/errext\"\n\t\"go.k6.io/k6/errext/exitcodes\"\n\t\"go.k6.io/k6/internal/build\"\n\t\"go.k6.io/k6/internal/cloudapi/insights\"\n\tinsightsOutput \"go.k6.io/k6/internal/output/cloud/insights\"\n\t\"go.k6.io/k6/metrics\"\n\t\"go.k6.io/k6/output\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// flusher is an interface for flushing data to the cloud.\ntype flusher interface {\n\tflush() error\n}\n\n// Output sends result data to the k6 Cloud service.\ntype Output struct {\n\toutput.SampleBuffer\n\n\tlogger      logrus.FieldLogger\n\tconfig      cloudapi.Config\n\tcloudClient *cloudapi.Client\n\ttestRunID   string\n\n\tcollector *collector\n\tflushing  flusher\n\n\tinsightsClient            insightsOutput.Client\n\trequestMetadatasCollector insightsOutput.RequestMetadatasCollector\n\trequestMetadatasFlusher   insightsOutput.RequestMetadatasFlusher\n\n\t// wg tracks background goroutines\n\twg sync.WaitGroup\n\n\t// stop signal to graceful stop\n\tstop chan struct{}\n\n\t// abort signal to interrupt immediately all background goroutines\n\tabort        chan struct{}\n\tabortOnce    sync.Once\n\ttestStopFunc func(error)\n}\n\n// New creates a new cloud output.\nfunc New(logger logrus.FieldLogger, conf cloudapi.Config, _ *cloudapi.Client) (*Output, error) {\n\t// TODO: move this creation operation to the centralized output. Reducing the probability to\n\t// break the logic for the config overwriting.\n\t//\n\t// It creates a new client because in the case the backend has overwritten\n\t// the config we need to use the new set.\n\treturn &Output{\n\t\tconfig: conf,\n\t\tlogger: logger.WithField(\"output\", \"cloudv2\"),\n\t\tabort:  make(chan struct{}),\n\t\tstop:   make(chan struct{}),\n\t\tcloudClient: cloudapi.NewClient(\n\t\t\tlogger, conf.Token.String, conf.Host.String, build.Version, conf.Timeout.TimeDuration()),\n\t}, nil\n}\n\n// SetTestRunID sets the Cloud's test run id.\nfunc (o *Output) SetTestRunID(id string) {\n\to.testRunID = id\n}\n\n// SetTestRunStopCallback receives the function that\n// that stops the engine when it is called.\n// It should be called on critical errors.\nfunc (o *Output) SetTestRunStopCallback(stopFunc func(error)) {\n\to.testStopFunc = stopFunc\n}\n\n// Start starts the goroutine that would listen\n// for metric samples and send them to the cloud.\nfunc (o *Output) Start() error {\n\to.logger.Debug(\"Starting...\")\n\tdefer o.logger.Debug(\"Started!\")\n\n\tvar err error\n\to.collector, err = newCollector(\n\t\to.config.AggregationPeriod.TimeDuration(),\n\t\to.config.AggregationWaitPeriod.TimeDuration())\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to initialize the samples collector: %w\", err)\n\t}\n\n\tmc, err := newMetricsClient(o.cloudClient, o.testRunID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to initialize the http metrics flush client: %w\", err)\n\t}\n\to.flushing = &metricsFlusher{\n\t\ttestRunID:                  o.testRunID,\n\t\tbq:                         &o.collector.bq,\n\t\tclient:                     mc,\n\t\tlogger:                     o.logger,\n\t\tdiscardedLabels:            make(map[string]struct{}),\n\t\taggregationPeriodInSeconds: uint32(o.config.AggregationPeriod.TimeDuration().Seconds()),\n\t\tmaxSeriesInBatch:           int(o.config.MaxTimeSeriesInBatch.Int64),\n\t\t// TODO: when the migration from v1 is over\n\t\t// change the default of cloudapi.MetricPushConcurrency to use GOMAXPROCS(0)\n\t\tbatchPushConcurrency: int(o.config.MetricPushConcurrency.Int64),\n\t}\n\n\to.runPeriodicFlush()\n\to.periodicInvoke(o.config.AggregationPeriod.TimeDuration(), o.collectSamples)\n\n\tif insightsOutput.Enabled(o.config) {\n\t\ttestRunID, err := strconv.ParseInt(o.testRunID, 10, 64)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\to.requestMetadatasCollector = insightsOutput.NewCollector(testRunID)\n\n\t\tinsightsClientConfig := insights.NewDefaultClientConfigForTestRun(\n\t\t\to.config.TracesHost.String,\n\t\t\to.config.Token.String,\n\t\t\ttestRunID,\n\t\t)\n\t\tinsightsClient := insights.NewClient(insightsClientConfig)\n\n\t\tif err := insightsClient.Dial(context.Background()); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\to.insightsClient = insightsClient\n\t\to.requestMetadatasFlusher = insightsOutput.NewFlusher(insightsClient, o.requestMetadatasCollector)\n\t\to.runFlushRequestMetadatas()\n\t}\n\n\to.logger.WithField(\"config\", printableConfig(o.config)).Debug(\"Started!\")\n\n\treturn nil\n}\n\n// StopWithTestError gracefully stops all metric emission from the output.\nfunc (o *Output) StopWithTestError(_ error) error {\n\to.logger.Debug(\"Stopping...\")\n\tdefer o.logger.Debug(\"Stopped!\")\n\n\tclose(o.stop)\n\to.wg.Wait()\n\n\tselect {\n\tcase <-o.abort:\n\t\treturn nil\n\tdefault:\n\t}\n\n\t// Drain the SampleBuffer and force the aggregation for flushing\n\t// all the queued samples even if they haven't yet passed the\n\t// wait period.\n\to.collector.DropExpiringDelay()\n\to.collectSamples()\n\to.flushMetrics()\n\n\t// Flush all the remaining request metadatas.\n\tif insightsOutput.Enabled(o.config) {\n\t\to.flushRequestMetadatas()\n\t\tif err := o.insightsClient.Close(); err != nil {\n\t\t\to.logger.WithError(err).Error(\"Failed to close the insights client\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (o *Output) runPeriodicFlush() {\n\tt := time.NewTicker(o.config.MetricPushInterval.TimeDuration())\n\n\to.wg.Add(1)\n\n\tgo func() {\n\t\tdefer func() {\n\t\t\tt.Stop()\n\t\t\to.wg.Done()\n\t\t}()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-t.C:\n\t\t\t\to.flushMetrics()\n\t\t\tcase <-o.stop:\n\t\t\t\treturn\n\t\t\tcase <-o.abort:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n}\n\n// AddMetricSamples receives the samples streaming.\nfunc (o *Output) AddMetricSamples(s []metrics.SampleContainer) {\n\t// TODO: this and the next operation are two locking operations,\n\t// evaluate to do something smarter, maybe having a lock-free\n\t// queue.\n\tselect {\n\tcase <-o.abort:\n\t\treturn\n\tdefault:\n\t}\n\n\t// TODO: when we will have a very good optimized\n\t// bucketing process we may evaluate to drop this\n\t// buffer.\n\t//\n\t// If the bucketing process is efficient, the single\n\t// operation could be a bit longer than just enqueuing\n\t// but it could be fast enough to justify to direct\n\t// run it and save some memory across the e2e operation.\n\t//\n\t// It requires very specific benchmark.\n\to.SampleBuffer.AddMetricSamples(s)\n}\n\nfunc (o *Output) periodicInvoke(d time.Duration, callback func()) {\n\to.wg.Go(func() {\n\t\tt := time.NewTicker(d)\n\t\tdefer t.Stop()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-t.C:\n\t\t\t\tcallback()\n\t\t\tcase <-o.stop:\n\t\t\t\treturn\n\t\t\tcase <-o.abort:\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc (o *Output) collectSamples() {\n\tsamples := o.GetBufferedSamples()\n\to.collector.CollectSamples(samples)\n\n\tif insightsOutput.Enabled(o.config) {\n\t\to.requestMetadatasCollector.CollectRequestMetadatas(samples)\n\t}\n}\n\n// flushMetrics receives a set of metric samples.\nfunc (o *Output) flushMetrics() {\n\tstart := time.Now()\n\n\terr := o.flushing.flush()\n\tif err != nil {\n\t\to.handleFlushError(err)\n\t\treturn\n\t}\n\n\to.logger.WithField(\"t\", time.Since(start)).Trace(\"Successfully flushed buffered samples to the cloud\")\n}\n\nfunc (o *Output) runFlushRequestMetadatas() {\n\tt := time.NewTicker(o.config.TracesPushInterval.TimeDuration())\n\n\tfor i := int64(0); i < o.config.TracesPushConcurrency.Int64; i++ {\n\t\to.wg.Go(func() {\n\t\t\tdefer t.Stop()\n\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase <-t.C:\n\t\t\t\t\to.flushRequestMetadatas()\n\t\t\t\tcase <-o.stop:\n\t\t\t\t\treturn\n\t\t\t\tcase <-o.abort:\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\n// flushRequestMetadatas periodically flushes traces collected in RequestMetadatasCollector using flusher.\nfunc (o *Output) flushRequestMetadatas() {\n\tstart := time.Now()\n\n\terr := o.requestMetadatasFlusher.Flush()\n\tif err != nil {\n\t\to.logger.WithError(err).WithField(\"t\", time.Since(start)).Error(\"Failed to push trace samples to the cloud\")\n\n\t\treturn\n\t}\n\n\to.logger.WithField(\"t\", time.Since(start)).Trace(\"Successfully flushed buffered trace samples to the cloud\")\n}\n\n// handleFlushError handles errors generated from the flushing operation.\n// It may interrupt the metric collection or invoke aborting of the test.\n//\n// note: The actual test execution should continue, since for local k6 run tests\n// the end-of-test summary (or any other outputs) will still work,\n// but the cloud output doesn't send any more metrics.\n// Instead, if cloudapi.Config.StopOnError is enabled the cloud output should\n// stop the whole test run too. This logic should be handled by the caller.\nfunc (o *Output) handleFlushError(err error) {\n\t// Don't actually handle any errors if we were aborted\n\tselect {\n\tcase <-o.abort:\n\t\treturn\n\tdefault:\n\t}\n\n\to.logger.WithError(err).Error(\"Failed to push metrics to the cloud\")\n\n\tvar errResp cloudapi.ResponseError\n\tif !errors.As(err, &errResp) || errResp.Response == nil {\n\t\treturn\n\t}\n\t// The Cloud service returns the error code 4 when it doesn't accept any more metrics.\n\t// So, when k6 sees that, the cloud output just stops prematurely.\n\tif errResp.Response.StatusCode != http.StatusForbidden || errResp.Code != 4 {\n\t\treturn\n\t}\n\n\t// Do not close multiple times (that would panic) in the case\n\t// we hit this multiple times and/or concurrently\n\to.abortOnce.Do(func() {\n\t\to.logger.WithError(err).Warn(\"Interrupt sending metrics to cloud due to an error\")\n\n\t\tclose(o.abort)\n\n\t\tif o.config.StopOnError.Bool {\n\t\t\tserr := errext.WithAbortReasonIfNone(\n\t\t\t\terrext.WithExitCodeIfNone(err, exitcodes.ExternalAbort),\n\t\t\t\terrext.AbortedByOutput,\n\t\t\t)\n\n\t\t\tif o.testStopFunc != nil {\n\t\t\t\to.testStopFunc(serr)\n\t\t\t}\n\t\t}\n\t})\n}\n\nfunc printableConfig(c cloudapi.Config) map[string]any {\n\tm := map[string]any{\n\t\t\"host\":                  c.Host.String,\n\t\t\"name\":                  c.Name.String,\n\t\t\"timeout\":               c.Timeout.String(),\n\t\t\"webAppURL\":             c.WebAppURL.String,\n\t\t\"projectID\":             c.ProjectID.Int64,\n\t\t\"pushRefID\":             c.PushRefID.String,\n\t\t\"stopOnError\":           c.StopOnError.Bool,\n\t\t\"testRunDetails\":        c.TestRunDetails.String,\n\t\t\"aggregationPeriod\":     c.AggregationPeriod.String(),\n\t\t\"aggregationWaitPeriod\": c.AggregationWaitPeriod.String(),\n\t\t\"maxTimeSeriesInBatch\":  c.MaxTimeSeriesInBatch.Int64,\n\t\t\"metricPushConcurrency\": c.MetricPushConcurrency.Int64,\n\t\t\"metricPushInterval\":    c.MetricPushInterval.String(),\n\t\t\"token\":                 \"\",\n\t}\n\n\tif c.Token.Valid {\n\t\tm[\"token\"] = \"***\"\n\t}\n\n\treturn m\n}\n"
  },
  {
    "path": "output/cloud/expv2/output_test.go",
    "content": "package expv2\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\t\"gopkg.in/guregu/null.v3\"\n\n\t\"go.k6.io/k6/cloudapi\"\n\t\"go.k6.io/k6/internal/lib/testutils\"\n\t\"go.k6.io/k6/lib/types\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestNew(t *testing.T) {\n\tt.Parallel()\n\n\tlogger, hook := testutils.NewLoggerWithHook(t)\n\tc := cloudapi.NewClient(logger, \"my-token\", \"the-host\", \"v/foo\", 1*time.Second)\n\to, err := New(logger, cloudapi.Config{APIVersion: null.IntFrom(99)}, c)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, o)\n\n\t// assert the prefixed logging\n\to.logger.Info(\"aaa\")\n\tloglines := hook.Drain()\n\trequire.Len(t, loglines, 1)\n\tassert.Equal(t, \"cloudv2\", loglines[0].Data[\"output\"])\n\n\t// assert the config set\n\tassert.Equal(t, int64(99), o.config.APIVersion.Int64)\n}\n\nfunc TestNewWithConfigOverwritten(t *testing.T) {\n\tt.Parallel()\n\n\tlogger := testutils.NewLogger(t)\n\tc := cloudapi.NewClient(logger, \"my-token\", \"the-host\", \"v/foo\", 1*time.Second)\n\tconf := cloudapi.Config{Host: null.StringFrom(\"the-new-host\")}\n\to, err := New(logger, conf, c)\n\trequire.NoError(t, err)\n\trequire.NotNil(t, o)\n\tassert.Equal(t, \"the-new-host/v1\", o.cloudClient.BaseURL())\n}\n\nfunc TestOutputSetTestRunID(t *testing.T) {\n\tt.Parallel()\n\to := Output{}\n\to.SetTestRunID(\"my-test-run-id\")\n\tassert.Equal(t, \"my-test-run-id\", o.testRunID)\n}\n\nfunc TestOutputSetTestRunStopCallback(t *testing.T) {\n\tt.Parallel()\n\tcalled := false\n\to := Output{}\n\to.SetTestRunStopCallback(func(e error) {\n\t\tassert.EqualError(t, e, \"my new fake error\")\n\t\tcalled = true\n\t})\n\to.testStopFunc(errors.New(\"my new fake error\"))\n\tassert.True(t, called)\n}\n\nfunc TestOutputCollectSamples(t *testing.T) {\n\tt.Parallel()\n\n\tconf := cloudapi.Config{\n\t\tHost:                  null.StringFrom(\"flush-is-disabled\"),\n\t\tToken:                 null.StringFrom(\"a-fake-token\"),\n\t\tAggregationWaitPeriod: types.NewNullDuration(5*time.Second, true),\n\t\t// Manually control and trigger the various steps\n\t\t// instead to be time dependent\n\t\tAggregationPeriod:  types.NewNullDuration(1*time.Hour, true),\n\t\tMetricPushInterval: types.NewNullDuration(1*time.Hour, true),\n\t}\n\tlogger := testutils.NewLogger(t)\n\tcc := cloudapi.NewClient(\n\t\tlogger, conf.Token.String, conf.Host.String, \"v/test\", conf.Timeout.TimeDuration())\n\to, err := New(logger, conf, cc)\n\trequire.NoError(t, err)\n\n\to.SetTestRunID(\"ref-id-123\")\n\trequire.NoError(t, o.Start())\n\trequire.Empty(t, o.collector.bq.PopAll())\n\n\to.collector.aggregationPeriod = 3 * time.Second\n\to.collector.nowFunc = func() time.Time {\n\t\t// the cut off will be set to (22-1)\n\t\treturn time.Date(2023, time.May, 1, 1, 1, 20, 0, time.UTC)\n\t}\n\n\tr := metrics.NewRegistry()\n\tm1 := r.MustNewMetric(\"metric1\", metrics.Counter)\n\tts := metrics.TimeSeries{\n\t\tMetric: m1,\n\t\tTags:   r.RootTagSet().With(\"key1\", \"val1\"),\n\t}\n\n\ts1 := metrics.Sample{\n\t\tTimeSeries: ts,\n\t\tTime:       time.Date(2023, time.May, 1, 1, 1, 15, 0, time.UTC),\n\t\tValue:      1.0,\n\t}\n\n\ts2 := metrics.Sample{\n\t\tTimeSeries: ts,\n\t\tTime:       time.Date(2023, time.May, 1, 1, 1, 18, 0, time.UTC),\n\t\tValue:      2.0,\n\t}\n\n\ts3 := metrics.Sample{\n\t\tTimeSeries: ts,\n\t\tTime:       time.Date(2023, time.May, 1, 1, 1, 15, 0, time.UTC),\n\t\tValue:      4.0,\n\t}\n\n\to.collector.CollectSamples([]metrics.SampleContainer{\n\t\tmetrics.Samples{s1},\n\t\tmetrics.Samples{s2},\n\t\tmetrics.Samples{s3},\n\t})\n\tbuckets := o.collector.bq.PopAll()\n\trequire.Len(t, buckets, 1)\n\trequire.Contains(t, buckets[0].Sinks, ts)\n\trequire.Len(t, buckets[0].Sinks, 1)\n\n\tcounter, ok := buckets[0].Sinks[ts].(*counter)\n\trequire.True(t, ok)\n\tassert.Equal(t, 5.0, counter.Sum)\n\n\texpTime := time.Date(2023, time.May, 1, 1, 1, 15, 0, time.UTC).UnixNano()\n\tassert.Equal(t, expTime, buckets[0].Time)\n}\n\nfunc TestOutputHandleFlushError(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname                    string\n\t\terr                     error\n\t\tabort                   bool\n\t\texpStopMetricCollection bool\n\t\texpAborted              bool\n\t}{\n\t\t{\n\t\t\tname:                    \"no stop on generic errors\",\n\t\t\terr:                     errors.New(\"a fake unknown error\"),\n\t\t\tabort:                   true,\n\t\t\texpStopMetricCollection: false,\n\t\t\texpAborted:              false,\n\t\t},\n\t\t{\n\t\t\tname: \"error code equals 4 but no abort\",\n\t\t\terr: cloudapi.ResponseError{\n\t\t\t\tResponse: &http.Response{StatusCode: http.StatusForbidden},\n\t\t\t\tCode:     4,\n\t\t\t},\n\t\t\tabort:                   false,\n\t\t\texpStopMetricCollection: true,\n\t\t\texpAborted:              false,\n\t\t},\n\t\t{\n\t\t\tname: \"error code equals 4 and abort\",\n\t\t\terr: cloudapi.ResponseError{\n\t\t\t\tResponse: &http.Response{StatusCode: http.StatusForbidden},\n\t\t\t\tCode:     4,\n\t\t\t},\n\t\t\tabort:                   true,\n\t\t\texpStopMetricCollection: true,\n\t\t\texpAborted:              true,\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tt.Parallel()\n\n\t\t\tstopFuncCalled := false\n\t\t\tstopMetricCollection := false\n\n\t\t\to := Output{\n\t\t\t\tlogger: testutils.NewLogger(t),\n\t\t\t\ttestStopFunc: func(error) {\n\t\t\t\t\tstopFuncCalled = true\n\t\t\t\t},\n\t\t\t\tabort: make(chan struct{}),\n\t\t\t}\n\t\t\to.config.StopOnError = null.BoolFrom(tc.abort)\n\n\t\t\tdone := make(chan struct{})\n\t\t\tstopped := make(chan struct{})\n\n\t\t\tgo func() {\n\t\t\t\tdefer close(stopped)\n\n\t\t\t\t<-done\n\t\t\t\tselect {\n\t\t\t\tcase <-o.abort:\n\t\t\t\t\tstopMetricCollection = true\n\t\t\t\tdefault:\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\to.handleFlushError(tc.err)\n\t\t\tclose(done)\n\t\t\t<-stopped\n\n\t\t\tassert.Equal(t, tc.expStopMetricCollection, stopMetricCollection)\n\t\t\tassert.Equal(t, tc.expAborted, stopFuncCalled)\n\t\t})\n\t}\n}\n\n// assert that the output does not stuck or panic\n// when it is called doesn't stuck\nfunc TestOutputHandleFlushErrorMultipleTimes(t *testing.T) {\n\tt.Parallel()\n\n\tvar stopFuncCalled int\n\to := Output{\n\t\tlogger: testutils.NewLogger(t),\n\t\tabort:  make(chan struct{}),\n\t\ttestStopFunc: func(error) {\n\t\t\tstopFuncCalled++\n\t\t},\n\t}\n\to.config.StopOnError = null.BoolFrom(true)\n\n\ter := cloudapi.ResponseError{\n\t\tResponse: &http.Response{\n\t\t\tStatusCode: http.StatusForbidden,\n\t\t},\n\t\tCode: 4,\n\t}\n\to.handleFlushError(fmt.Errorf(\"first error: %w\", er))\n\to.handleFlushError(fmt.Errorf(\"second error: %w\", er))\n\tassert.Equal(t, 1, stopFuncCalled)\n}\n\nfunc TestOutputAddMetricSamples(t *testing.T) {\n\tt.Parallel()\n\n\tstopSamples := make(chan struct{})\n\to := Output{\n\t\tabort: stopSamples,\n\t}\n\trequire.Empty(t, o.GetBufferedSamples())\n\n\ts := metrics.Sample{}\n\to.AddMetricSamples([]metrics.SampleContainer{\n\t\tmetrics.Samples([]metrics.Sample{s}),\n\t})\n\trequire.Len(t, o.GetBufferedSamples(), 1)\n\n\t// Not accept samples anymore when the chan is closed\n\tclose(stopSamples)\n\to.AddMetricSamples([]metrics.SampleContainer{\n\t\tmetrics.Samples([]metrics.Sample{s}),\n\t})\n\trequire.Empty(t, o.GetBufferedSamples())\n}\n\nfunc TestOutputPeriodicInvoke(t *testing.T) {\n\tt.Parallel()\n\n\tstop := make(chan struct{})\n\tvar called uint64\n\tcb := func() {\n\t\tupdated := atomic.AddUint64(&called, 1)\n\t\tif updated == 2 {\n\t\t\tclose(stop)\n\t\t}\n\t}\n\to := Output{stop: stop}\n\to.periodicInvoke(time.Duration(1), cb) // loop\n\t<-stop\n\tassert.Greater(t, atomic.LoadUint64(&called), uint64(1))\n}\n\nfunc TestOutputStopWithTestError(t *testing.T) {\n\tt.Parallel()\n\n\tconfig := cloudapi.NewConfig()\n\tconfig.Host = null.StringFrom(\"host-is-required-but-flush-isnot-expected\")\n\tconfig.Token = null.StringFrom(\"token-is-required\")\n\tconfig.AggregationPeriod = types.NullDurationFrom(1 * time.Hour)\n\n\tlogger := testutils.NewLogger(t)\n\tcc := cloudapi.NewClient(\n\t\tlogger, config.Token.String, config.Host.String, \"v/test\", config.Timeout.TimeDuration())\n\to, err := New(logger, config, cc)\n\trequire.NoError(t, err)\n\n\to.SetTestRunID(\"1234\")\n\trequire.NoError(t, o.Start())\n\trequire.NoError(t, o.StopWithTestError(errors.New(\"an error\")))\n}\n\nfunc TestOutputFlushTicks(t *testing.T) {\n\tt.Parallel()\n\n\tdone := make(chan struct{})\n\n\t// It blocks on the first request so it asserts that the flush\n\t// operations continues concurrently if one more tick is sent in the meantime.\n\t//\n\t// The second request unblocks.\n\tvar requestsCount int64\n\tflusherMock := func() {\n\t\tupdated := atomic.AddInt64(&requestsCount, 1)\n\t\tif updated == 2 {\n\t\t\tclose(done)\n\t\t\treturn\n\t\t}\n\t}\n\n\to := Output{logger: testutils.NewLogger(t)}\n\to.config.MetricPushInterval = types.NullDurationFrom(100 * time.Millisecond) // loop\n\to.flushing = flusherFunc(flusherMock)\n\to.runPeriodicFlush()\n\n\tselect {\n\tcase <-time.After(5 * time.Second):\n\t\tt.Error(\"timed out\")\n\tcase <-done:\n\t\tassert.NotZero(t, atomic.LoadInt64(&requestsCount))\n\t}\n}\n\nfunc TestOutputFlushWorkersStop(t *testing.T) {\n\tt.Parallel()\n\n\tt.Skip(\"test timeouts in CI\")\n\n\to := Output{\n\t\tlogger: testutils.NewLogger(t),\n\t\tstop:   make(chan struct{}),\n\t}\n\to.config.MetricPushInterval = types.NullDurationFrom(1 * time.Millisecond)\n\n\tonce := sync.Once{}\n\tflusherMock := func() {\n\t\t// it asserts that flushers are set and the flush is invoked\n\t\tonce.Do(func() { close(o.stop) })\n\t}\n\n\to.flushing = flusherFunc(flusherMock)\n\to.runPeriodicFlush()\n\n\t// it asserts that all flushers exit\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tdefer close(done)\n\t\to.wg.Wait()\n\t}()\n\tselect {\n\tcase <-time.After(time.Second):\n\t\tt.Error(\"timed out\")\n\tcase <-done:\n\t}\n}\n\nfunc TestOutputFlushWorkersAbort(t *testing.T) {\n\tt.Parallel()\n\n\to := Output{\n\t\tlogger: testutils.NewLogger(t),\n\t\tabort:  make(chan struct{}),\n\t}\n\to.config.MetricPushInterval = types.NullDurationFrom(1 * time.Millisecond)\n\n\tonce := sync.Once{}\n\tflusherMock := func() {\n\t\t// it asserts that flushers are set and the flush func is invoked\n\t\tonce.Do(func() { close(o.abort) })\n\t}\n\n\to.flushing = flusherFunc(flusherMock)\n\to.runPeriodicFlush()\n\n\t// it asserts that all flushers exit\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tdefer close(done)\n\t\to.wg.Wait()\n\t}()\n\tselect {\n\tcase <-time.After(time.Second):\n\t\tt.Error(\"timed out\")\n\tcase <-done:\n\t}\n}\n\nfunc TestOutputFlushRequestMetadatasConcurrently(t *testing.T) {\n\tt.Parallel()\n\n\tdone := make(chan struct{})\n\n\t// It blocks on the first request, so it asserts that the flush\n\t// operations continues concurrently if one more tick is sent in the meantime.\n\t//\n\t// The second request unblocks.\n\tvar requestsCount int64\n\tflusherMock := func() {\n\t\tupdated := atomic.AddInt64(&requestsCount, 1)\n\t\tif updated == 2 {\n\t\t\tclose(done)\n\t\t\treturn\n\t\t}\n\t\t<-done\n\t}\n\n\to := Output{logger: testutils.NewLogger(t)}\n\to.config.TracesPushConcurrency = null.IntFrom(2)\n\to.config.TracesPushInterval = types.NullDurationFrom(1) // loop\n\to.requestMetadatasFlusher = flusherFunc(flusherMock)\n\to.runFlushRequestMetadatas()\n\n\tselect {\n\tcase <-time.After(5 * time.Second):\n\t\tt.Error(\"timed out\")\n\tcase <-done:\n\t\tassert.NotZero(t, atomic.LoadInt64(&requestsCount))\n\t}\n}\n\nfunc TestOutputFlushRequestMetadatasStop(t *testing.T) {\n\tt.Parallel()\n\n\to := Output{\n\t\tlogger: testutils.NewLogger(t),\n\t\tstop:   make(chan struct{}),\n\t}\n\to.config.TracesPushInterval = types.NullDurationFrom(1 * time.Millisecond)\n\n\tonce := sync.Once{}\n\tflusherMock := func() {\n\t\t// it asserts that flushers are set and the flush is invoked\n\t\tonce.Do(func() { close(o.stop) })\n\t}\n\n\to.requestMetadatasFlusher = flusherFunc(flusherMock)\n\to.runFlushRequestMetadatas()\n\n\t// it asserts that all flushers exit\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tdefer close(done)\n\t\to.wg.Wait()\n\t}()\n\tselect {\n\tcase <-time.After(time.Second):\n\t\tt.Error(\"timed out\")\n\tcase <-done:\n\t}\n}\n\nfunc TestOutputFlushRequestMetadatasAbort(t *testing.T) {\n\tt.Parallel()\n\n\to := Output{\n\t\tlogger: testutils.NewLogger(t),\n\t\tabort:  make(chan struct{}),\n\t}\n\to.config.TracesPushInterval = types.NullDurationFrom(1 * time.Millisecond)\n\n\tonce := sync.Once{}\n\tflusherMock := func() {\n\t\t// it asserts that flushers are set and the flush func is invoked\n\t\tonce.Do(func() { close(o.abort) })\n\t}\n\n\to.requestMetadatasFlusher = flusherFunc(flusherMock)\n\to.runFlushRequestMetadatas()\n\n\t// it asserts that all flushers exit\n\tdone := make(chan struct{})\n\tgo func() {\n\t\tdefer close(done)\n\t\to.wg.Wait()\n\t}()\n\tselect {\n\tcase <-time.After(time.Second):\n\t\tt.Error(\"timed out\")\n\tcase <-done:\n\t}\n}\n\ntype flusherFunc func()\n\nfunc (ff flusherFunc) Flush() error {\n\treturn ff.flush()\n}\n\nfunc (ff flusherFunc) flush() error {\n\tff()\n\treturn nil\n}\n\nfunc TestPrintableConfig(t *testing.T) {\n\tt.Parallel()\n\n\tc := cloudapi.NewConfig()\n\tc.Host = null.NewString(\"http://test.host\", false)\n\tc.Name = null.NewString(\"test-name\", false)\n\tc.PushRefID = null.NewString(\"test-id-123\", false)\n\tc.StopOnError = null.NewBool(true, false)\n\tc.MetricPushConcurrency = null.NewInt(5, false)\n\tc.AggregationPeriod = types.NewNullDuration(10*time.Second, false)\n\tc.ProjectID = null.NewInt(123, false)\n\tc.Token = null.StringFrom(\"my personal token\")\n\n\texp := map[string]any{\n\t\t\"host\":                  \"http://test.host\",\n\t\t\"name\":                  \"test-name\",\n\t\t\"pushRefID\":             \"test-id-123\",\n\t\t\"projectID\":             int64(123),\n\t\t\"token\":                 \"***\",\n\t\t\"stopOnError\":           true,\n\t\t\"aggregationPeriod\":     \"10s\",\n\t\t\"metricPushConcurrency\": int64(5),\n\t}\n\n\tassert.Subset(t, printableConfig(c), exp)\n}\n"
  },
  {
    "path": "output/cloud/expv2/sink.go",
    "content": "package expv2\n\nimport (\n\t\"fmt\"\n\n\t\"go.k6.io/k6/internal/ds/histogram\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO:A potential optimization\n// https://github.com/grafana/k6/pull/3085#discussion_r1210415981\ntype metricValue interface {\n\tAdd(v float64)\n}\n\nfunc newMetricValue(mt metrics.MetricType) metricValue {\n\tvar am metricValue\n\tswitch mt {\n\tcase metrics.Counter:\n\t\tam = &counter{}\n\tcase metrics.Gauge:\n\t\tam = &gauge{}\n\tcase metrics.Rate:\n\t\tam = &rate{}\n\tcase metrics.Trend:\n\t\tam = histogram.NewHdr()\n\tdefault:\n\t\t// Should not be possible to create\n\t\t// an invalid metric type except for specific\n\t\t// and controlled tests\n\t\tpanic(fmt.Sprintf(\"MetricType %q is not supported\", mt))\n\t}\n\treturn am\n}\n\ntype counter struct {\n\tSum float64\n}\n\nfunc (c *counter) Add(v float64) {\n\tc.Sum += v\n}\n\ntype gauge struct {\n\tLast     float64\n\tSum      float64\n\tMin, Max float64\n\tAvg      float64\n\tCount    uint32\n\n\tminSet bool\n}\n\nfunc (g *gauge) Add(v float64) {\n\tg.Last = v\n\tg.Count++\n\tg.Sum += v\n\tg.Avg = g.Sum / float64(g.Count)\n\n\tif v > g.Max {\n\t\tg.Max = v\n\t}\n\tif !g.minSet || v < g.Min {\n\t\tg.Min = v\n\t\tg.minSet = true\n\t}\n}\n\ntype rate struct {\n\tNonZeroCount uint32\n\tTotal        uint32\n}\n\nfunc (r *rate) Add(v float64) {\n\tr.Total++\n\tif v != 0 {\n\t\tr.NonZeroCount++\n\t}\n}\n"
  },
  {
    "path": "output/cloud/expv2/sink_test.go",
    "content": "package expv2\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"go.k6.io/k6/internal/ds/histogram\"\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestNewSink(t *testing.T) {\n\tt.Parallel()\n\ttests := []struct {\n\t\tmt  metrics.MetricType\n\t\texp any\n\t}{\n\t\t{metrics.Counter, &counter{}},\n\t\t{metrics.Gauge, &gauge{}},\n\t\t{metrics.Rate, &rate{}},\n\t\t{metrics.Trend, histogram.NewHdr()},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.exp, newMetricValue(tc.mt))\n\t}\n}\n\nfunc TestCounterAdd(t *testing.T) {\n\tt.Parallel()\n\n\tc := counter{}\n\tc.Add(2.3)\n\tassert.Equal(t, 2.3, c.Sum)\n\n\tc.Add(1.78)\n\tassert.Equal(t, 4.08, c.Sum)\n}\n\nfunc TestGaugeAdd(t *testing.T) {\n\tt.Parallel()\n\n\tg := gauge{}\n\tg.Add(28)\n\n\texp := gauge{\n\t\tLast:   28,\n\t\tSum:    28,\n\t\tMin:    28,\n\t\tMax:    28,\n\t\tAvg:    28,\n\t\tCount:  1,\n\t\tminSet: true,\n\t}\n\tassert.Equal(t, exp, g)\n\n\tg.Add(8.28)\n\texp = gauge{\n\t\tLast:   8.28,\n\t\tSum:    36.28,\n\t\tMin:    8.28,\n\t\tMax:    28,\n\t\tAvg:    18.14,\n\t\tCount:  2,\n\t\tminSet: true,\n\t}\n\tassert.Equal(t, exp, g)\n}\n\nfunc TestRateAdd(t *testing.T) {\n\tt.Parallel()\n\n\tr := rate{}\n\tr.Add(91)\n\n\texp := rate{\n\t\tNonZeroCount: 1,\n\t\tTotal:        1,\n\t}\n\tassert.Equal(t, exp, r)\n\n\tr.Add(0)\n\texp.Total = 2\n\tassert.Equal(t, exp, r)\n}\n"
  },
  {
    "path": "output/extensions.go",
    "content": "package output\n\nimport \"go.k6.io/k6/ext\"\n\n// Constructor returns an instance of an output extension module.\ntype Constructor func(Params) (Output, error)\n\n// RegisterExtension registers the given output extension constructor. This\n// function panics if a module with the same name is already registered.\nfunc RegisterExtension(name string, c Constructor) {\n\text.Register(name, ext.OutputExtension, c)\n}\n"
  },
  {
    "path": "output/helpers.go",
    "content": "package output\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\n// SampleBuffer is a simple thread-safe buffer for metric samples. It should be\n// used by most outputs, since we generally want to flush metric samples to the\n// remote service asynchronously. We want to do it only every several seconds,\n// and we don't want to block the Engine in the meantime.\ntype SampleBuffer struct {\n\tsync.Mutex\n\tbuffer []metrics.SampleContainer\n\tmaxLen int\n}\n\n// AddMetricSamples adds the given metric samples to the internal buffer.\nfunc (sc *SampleBuffer) AddMetricSamples(samples []metrics.SampleContainer) {\n\tif len(samples) == 0 {\n\t\treturn\n\t}\n\tsc.Lock()\n\tsc.buffer = append(sc.buffer, samples...)\n\tsc.Unlock()\n}\n\n// GetBufferedSamples returns the currently buffered metric samples and makes a\n// new internal buffer with some hopefully realistic size. If the internal\n// buffer is empty, it will return nil.\nfunc (sc *SampleBuffer) GetBufferedSamples() []metrics.SampleContainer {\n\tsc.Lock()\n\tdefer sc.Unlock()\n\n\tbuffered, bufferedLen := sc.buffer, len(sc.buffer)\n\tif bufferedLen == 0 {\n\t\treturn nil\n\t}\n\tif bufferedLen > sc.maxLen {\n\t\tsc.maxLen = bufferedLen\n\t}\n\t// Make the new buffer halfway between the previously allocated size and the\n\t// maximum buffer size we've seen so far, to hopefully reduce copying a bit.\n\tsc.buffer = make([]metrics.SampleContainer, 0, (bufferedLen+sc.maxLen)/2)\n\n\treturn buffered\n}\n\n// PeriodicFlusher is a small helper for asynchronously flushing buffered metric\n// samples on regular intervals. The biggest benefit is having a Stop() method\n// that waits for one last flush before it returns.\ntype PeriodicFlusher struct {\n\tperiod        time.Duration\n\tflushCallback func()\n\tstop          chan struct{}\n\tstopped       chan struct{}\n\tonce          *sync.Once\n}\n\nfunc (pf *PeriodicFlusher) run() {\n\tticker := time.NewTicker(pf.period)\n\tdefer ticker.Stop()\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\tpf.flushCallback()\n\t\tcase <-pf.stop:\n\t\t\tpf.flushCallback()\n\t\t\tclose(pf.stopped)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// Stop waits for the periodic flusher flush one last time and exit. You can\n// safely call Stop() multiple times from different goroutines, you just can't\n// call it from inside of the flushing function.\nfunc (pf *PeriodicFlusher) Stop() {\n\tpf.once.Do(func() {\n\t\tclose(pf.stop)\n\t})\n\t<-pf.stopped\n}\n\n// NewPeriodicFlusher creates a new PeriodicFlusher and starts its goroutine.\nfunc NewPeriodicFlusher(period time.Duration, flushCallback func()) (*PeriodicFlusher, error) {\n\tif period <= 0 {\n\t\treturn nil, fmt.Errorf(\"metric flush period should be positive but was %s\", period)\n\t}\n\n\tpf := &PeriodicFlusher{\n\t\tperiod:        period,\n\t\tflushCallback: flushCallback,\n\t\tstop:          make(chan struct{}),\n\t\tstopped:       make(chan struct{}),\n\t\tonce:          &sync.Once{},\n\t}\n\n\tgo pf.run()\n\n\treturn pf, nil\n}\n"
  },
  {
    "path": "output/helpers_test.go",
    "content": "package output\n\nimport (\n\t\"math/rand\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n\n\t\"go.k6.io/k6/metrics\"\n)\n\nfunc TestSampleBufferBasics(t *testing.T) {\n\tt.Parallel()\n\n\tregistry := metrics.NewRegistry()\n\tmetric, err := registry.NewMetric(\"my_metric\", metrics.Rate)\n\trequire.NoError(t, err)\n\n\tsingle := metrics.Sample{\n\t\tTimeSeries: metrics.TimeSeries{\n\t\t\tMetric: metric,\n\t\t\tTags:   registry.RootTagSet().WithTagsFromMap(map[string]string{\"tag1\": \"val1\"}),\n\t\t},\n\t\tTime:  time.Now(),\n\t\tValue: float64(123),\n\t}\n\tconnected := metrics.ConnectedSamples{Samples: []metrics.Sample{single, single}, Time: single.Time}\n\tbuffer := SampleBuffer{}\n\n\tassert.Empty(t, buffer.GetBufferedSamples())\n\tbuffer.AddMetricSamples([]metrics.SampleContainer{single, single})\n\tbuffer.AddMetricSamples([]metrics.SampleContainer{single, connected, single})\n\tassert.Equal(t, []metrics.SampleContainer{single, single, single, connected, single}, buffer.GetBufferedSamples())\n\tassert.Empty(t, buffer.GetBufferedSamples())\n\n\t// Verify some internals\n\tassert.Equal(t, 5, cap(buffer.buffer))\n\tbuffer.AddMetricSamples([]metrics.SampleContainer{single, connected})\n\tbuffer.AddMetricSamples(nil)\n\tbuffer.AddMetricSamples([]metrics.SampleContainer{})\n\tbuffer.AddMetricSamples([]metrics.SampleContainer{single})\n\tassert.Equal(t, []metrics.SampleContainer{single, connected, single}, buffer.GetBufferedSamples())\n\tassert.Equal(t, 4, cap(buffer.buffer))\n\tbuffer.AddMetricSamples([]metrics.SampleContainer{single})\n\tassert.Equal(t, []metrics.SampleContainer{single}, buffer.GetBufferedSamples())\n\tassert.Equal(t, 3, cap(buffer.buffer))\n\tassert.Empty(t, buffer.GetBufferedSamples())\n}\n\nfunc TestSampleBufferConcurrently(t *testing.T) {\n\tt.Parallel()\n\n\tseed := time.Now().UnixNano()\n\tr := rand.New(rand.NewSource(seed))\n\tt.Logf(\"Random source seeded with %d\\n\", seed)\n\n\tregistry := metrics.NewRegistry()\n\tmetric, err := registry.NewMetric(\"my_metric\", metrics.Gauge)\n\trequire.NoError(t, err)\n\n\tproducersCount := 50 + r.Intn(50)\n\tsampleCount := 10 + r.Intn(10)\n\tsleepModifier := 10 + r.Intn(10)\n\tbuffer := SampleBuffer{}\n\n\twg := make(chan struct{})\n\tfillBuffer := func() {\n\t\tfor i := range sampleCount {\n\t\t\tbuffer.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{\n\t\t\t\tTimeSeries: metrics.TimeSeries{\n\t\t\t\t\tMetric: metric,\n\t\t\t\t\tTags:   registry.RootTagSet().WithTagsFromMap(map[string]string{\"tag1\": \"val1\"}),\n\t\t\t\t},\n\t\t\t\tTime:  time.Unix(1562324644, 0),\n\t\t\t\tValue: float64(i),\n\t\t\t}})\n\t\t\ttime.Sleep(time.Duration(i*sleepModifier) * time.Microsecond)\n\t\t}\n\t\twg <- struct{}{}\n\t}\n\tfor range producersCount {\n\t\tgo fillBuffer()\n\t}\n\n\ttimer := time.NewTicker(5 * time.Millisecond)\n\ttimeout := time.After(5 * time.Second)\n\tdefer timer.Stop()\n\treadSamples := make([]metrics.SampleContainer, 0, sampleCount*producersCount)\n\tfinishedProducers := 0\nloop:\n\tfor {\n\t\tselect {\n\t\tcase <-timer.C:\n\t\t\treadSamples = append(readSamples, buffer.GetBufferedSamples()...)\n\t\tcase <-wg:\n\t\t\tfinishedProducers++\n\t\t\tif finishedProducers == producersCount {\n\t\t\t\treadSamples = append(readSamples, buffer.GetBufferedSamples()...)\n\t\t\t\tbreak loop\n\t\t\t}\n\t\tcase <-timeout:\n\t\t\tt.Fatalf(\"test timed out\")\n\t\t}\n\t}\n\tassert.Equal(t, sampleCount*producersCount, len(readSamples))\n\tfor _, s := range readSamples {\n\t\trequire.NotNil(t, s)\n\t\tss := s.GetSamples()\n\t\trequire.Len(t, ss, 1)\n\t\tassert.Equal(t, \"my_metric\", ss[0].Metric.Name)\n\t}\n}\n\nfunc TestPeriodicFlusherBasics(t *testing.T) {\n\tt.Parallel()\n\n\tf, err := NewPeriodicFlusher(-1*time.Second, func() {})\n\tassert.Error(t, err)\n\tassert.Nil(t, f)\n\tf, err = NewPeriodicFlusher(0, func() {})\n\tassert.Error(t, err)\n\tassert.Nil(t, f)\n\n\tcount := 0\n\twg := &sync.WaitGroup{}\n\twg.Add(1)\n\tf, err = NewPeriodicFlusher(100*time.Millisecond, func() {\n\t\tcount++\n\t\tif count == 2 {\n\t\t\twg.Done()\n\t\t}\n\t})\n\tassert.NotNil(t, f)\n\tassert.Nil(t, err)\n\twg.Wait()\n\tf.Stop()\n\tassert.Equal(t, 3, count)\n}\n\nfunc TestPeriodicFlusherConcurrency(t *testing.T) {\n\tt.Parallel()\n\n\tseed := time.Now().UnixNano()\n\tr := rand.New(rand.NewSource(seed))\n\trandStops := 10 + r.Intn(10)\n\tt.Logf(\"Random source seeded with %d\\n\", seed)\n\n\tcount := 0\n\twg := &sync.WaitGroup{}\n\twg.Add(1)\n\tf, err := NewPeriodicFlusher(1000*time.Microsecond, func() {\n\t\t// Sleep intentionally may be longer than the flush period. Also, this\n\t\t// should never happen concurrently, so it's intentionally not locked.\n\t\ttime.Sleep(time.Duration(700+r.Intn(1000)) * time.Microsecond)\n\t\tcount++\n\t\tif count == 100 {\n\t\t\twg.Done()\n\t\t}\n\t})\n\tassert.NotNil(t, f)\n\tassert.Nil(t, err)\n\twg.Wait()\n\n\tstopWG := &sync.WaitGroup{}\n\tstopWG.Add(randStops)\n\tfor range randStops {\n\t\tgo func() {\n\t\t\tf.Stop()\n\t\t\tstopWG.Done()\n\t\t}()\n\t}\n\tstopWG.Wait()\n\tassert.True(t, count >= 101) // due to the short intervals, we might not get exactly 101\n}\n"
  },
  {
    "path": "output/manager.go",
    "content": "package output\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// TODO: completely get rid of this, see https://github.com/grafana/k6/issues/2430\nconst sendBatchToOutputsRate = 50 * time.Millisecond\n\n// Manager can be used to manage multiple outputs at the same time.\ntype Manager struct {\n\toutputs []Output\n\tlogger  logrus.FieldLogger\n\n\ttestStopCallback func(error)\n}\n\n// NewManager returns a new manager for the given outputs.\nfunc NewManager(outputs []Output, logger logrus.FieldLogger, testStopCallback func(error)) *Manager {\n\treturn &Manager{\n\t\toutputs:          outputs,\n\t\tlogger:           logger.WithField(\"component\", \"output-manager\"),\n\t\ttestStopCallback: testStopCallback,\n\t}\n}\n\n// Start spins up all configured outputs and then starts a new goroutine that\n// pipes metrics from the given samples channel to them.\n//\n// If some output fails to start, it stops the already started ones. This may\n// take some time, since some outputs make initial network requests to set up\n// whatever remote services are going to listen to them.\n//\n// If all outputs start successfully, this method will return 2 callbacks. The\n// first one, wait(), will block until the samples channel has been closed and\n// all of its buffered metrics have been sent to all outputs. The second\n// callback will call the Stop() or StopWithTestError() method of every output.\nfunc (om *Manager) Start(samplesChan chan metrics.SampleContainer) (wait func(), finish func(error), err error) {\n\tif err := om.startOutputs(); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\twg := &sync.WaitGroup{}\n\twg.Add(1)\n\n\tsendToOutputs := func(sampleContainers []metrics.SampleContainer) {\n\t\tfor _, out := range om.outputs {\n\t\t\tout.AddMetricSamples(sampleContainers)\n\t\t}\n\t}\n\n\tgo func() {\n\t\tdefer wg.Done()\n\t\tticker := time.NewTicker(sendBatchToOutputsRate)\n\t\tdefer ticker.Stop()\n\n\t\tbuffer := make([]metrics.SampleContainer, 0, cap(samplesChan))\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase sampleContainer, ok := <-samplesChan:\n\t\t\t\tif !ok {\n\t\t\t\t\tsendToOutputs(buffer)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tbuffer = append(buffer, sampleContainer)\n\t\t\tcase <-ticker.C:\n\t\t\t\tsendToOutputs(buffer)\n\t\t\t\tbuffer = make([]metrics.SampleContainer, 0, cap(buffer))\n\t\t\t}\n\t\t}\n\t}()\n\n\twait = wg.Wait\n\tfinish = func(testErr error) {\n\t\twait() // just in case, though it shouldn't be needed if API is used correctly\n\t\tom.stopOutputs(testErr, len(om.outputs))\n\t}\n\treturn wait, finish, nil\n}\n\n// startOutputs spins up all configured outputs. If some output fails to start,\n// it stops the already started ones. This may take some time, since some\n// outputs make initial network requests to set up whatever remote services are\n// going to listen to them.\nfunc (om *Manager) startOutputs() error {\n\tom.logger.Debugf(\"Starting %d outputs...\", len(om.outputs))\n\tfor i, out := range om.outputs {\n\t\tif stopOut, ok := out.(WithTestRunStop); ok {\n\t\t\tstopOut.SetTestRunStopCallback(om.testStopCallback)\n\t\t}\n\n\t\tif err := out.Start(); err != nil {\n\t\t\tom.stopOutputs(err, i)\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (om *Manager) stopOutputs(testErr error, upToID int) {\n\tom.logger.Debugf(\"Stopping %d outputs...\", upToID)\n\tfor i := range upToID {\n\t\tout := om.outputs[i]\n\t\tvar err error\n\t\tif sout, ok := out.(WithStopWithTestError); ok {\n\t\t\terr = sout.StopWithTestError(testErr)\n\t\t} else {\n\t\t\terr = out.Stop()\n\t\t}\n\n\t\tif err != nil {\n\t\t\tom.logger.WithError(err).Errorf(\"Stopping output %d failed\", i)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "output/types.go",
    "content": "// Package output contains the interfaces that k6 outputs (and output\n// extensions) have to implement, as well as some helpers to make their\n// implementation and management easier.\npackage output\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/url\"\n\n\t\"github.com/sirupsen/logrus\"\n\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib\"\n\t\"go.k6.io/k6/lib/fsext\"\n\t\"go.k6.io/k6/metrics\"\n)\n\n// Params contains all possible constructor parameters an output may need.\ntype Params struct {\n\tOutputType     string // --out $OutputType=$ConfigArgument, K6_OUT=\"$OutputType=$ConfigArgument\"\n\tConfigArgument string\n\tJSONConfig     json.RawMessage\n\n\tLogger         logrus.FieldLogger\n\tEnvironment    map[string]string\n\tStdOut         io.Writer\n\tStdErr         io.Writer\n\tFS             fsext.Fs\n\tScriptPath     *url.URL\n\tScriptOptions  lib.Options\n\tRuntimeOptions lib.RuntimeOptions\n\tExecutionPlan  []lib.ExecutionStep\n\tUsage          *usage.Usage\n}\n\n// TODO: make v2 with buffered channels?\n\n// An Output abstracts the process of funneling samples to an external storage\n// backend, such as a file or something like an InfluxDB instance.\n//\n// N.B: All outputs should have non-blocking AddMetricSamples() methods and\n// should spawn their own goroutine to flush metrics asynchronously.\ntype Output interface {\n\t// Returns a human-readable description of the output that will be shown in\n\t// `k6 run`. For extensions it probably should include the version as well.\n\tDescription() string\n\n\t// Start is called before the Engine tries to use the output and should be\n\t// used for any long initialization tasks, as well as for starting a\n\t// goroutine to asynchronously flush metrics to the output.\n\tStart() error\n\n\t// A method to receive the latest metric samples from the Engine. This\n\t// method is never called concurrently, so do not do anything blocking here\n\t// that might take a long time. Preferably, just use the SampleBuffer or\n\t// something like it to buffer metrics until they are flushed.\n\tAddMetricSamples(samples []metrics.SampleContainer)\n\n\t// Flush all remaining metrics and finalize the test run.\n\tStop() error\n}\n\n// WithThresholds is an output that requires the Engine to give it the\n// thresholds before it can be started.\ntype WithThresholds interface {\n\tOutput\n\tSetThresholds(map[string]metrics.Thresholds)\n}\n\n// WithArchive is an output that can receive the archive object in order\n// to upload it to the cloud.\ntype WithArchive interface {\n\tOutput\n\tSetArchive(archive *lib.Archive)\n}\n\n// WithTestRunStop is an output that can stop the test run mid-way through,\n// interrupting the whole test run execution if some internal condition occurs,\n// completely independently from the thresholds. It requires a callback function\n// which expects an error and triggers the Engine to stop.\ntype WithTestRunStop interface {\n\tOutput\n\tSetTestRunStopCallback(func(error))\n}\n\n// WithStopWithTestError allows output to receive the error value that the test\n// finished with. It could be nil, if the test finished normally.\n//\n// If this interface is implemented by the output, StopWithError() will be\n// called instead of Stop().\n//\n// TODO: refactor the main interface to use this method instead of Stop()? Or\n// something else along the lines of https://github.com/grafana/k6/issues/2430 ?\ntype WithStopWithTestError interface {\n\tOutput\n\tStopWithTestError(testRunErr error) error // nil testRunErr means error-free test run\n}\n\n// WithBuiltinMetrics means the output can receive the builtin metrics.\ntype WithBuiltinMetrics interface {\n\tOutput\n\tSetBuiltinMetrics(builtinMetrics *metrics.BuiltinMetrics)\n}\n"
  },
  {
    "path": "packaging/Dockerfile",
    "content": "FROM debian:bullseye-20250811@sha256:8ec25a9073e8cc89a184a6256e219828196d75203375a8ad4f0977f3011f2115\n\nLABEL maintainer=\"k6 Developers <developers@k6.io>\"\n\nENV DEBIAN_FRONTEND=noninteractive\n\nRUN apt-get update -y && \\\n    apt-get install -y apt-utils createrepo-c curl git gnupg2 python3-pip unzip rpm\n\nRUN pip3 install \"s3cmd==2.4.0\"\n\n# Download awscli, check GPG signature and install.\nCOPY ./awscli-key.gpg .\nRUN export GNUPGHOME=\"$(mktemp -d)\" && \\\n    gpg2 --import ./awscli-key.gpg && \\\n    fpr=\"$(gpg2 --with-colons --fingerprint aws-cli | grep '^fpr' | cut -d: -f10)\" && \\\n    gpg2 --export-ownertrust && echo \"${fpr}:6:\" | gpg2 --import-ownertrust && \\\n    curl -fsSL --remote-name-all \\\n      \"https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.26.5.zip\"{,.sig} && \\\n    gpg2 --verify awscli*.sig awscli*.zip && \\\n    unzip -q awscli*.zip && \\\n    ./aws/install && \\\n    rm -rf aws* \"$GNUPGHOME\"\n\nRUN addgroup --gid 1000 k6 && \\\n    useradd --create-home --shell /bin/bash --no-log-init \\\n      --uid 1000 --gid 1000 k6\n\nCOPY bin/ /usr/local/bin/\n\nUSER k6\nWORKDIR /home/k6\n\nCOPY --chown=k6:k6 ./k6-rpm-repo.spec rpmbuild/SPECS/\nCOPY --chown=k6:k6 ./k6-rpm.repo rpmbuild/SOURCES/k6-io.repo\n\nENTRYPOINT [\"/usr/local/bin/entrypoint.sh\"]\n"
  },
  {
    "path": "packaging/bin/create-deb-repo.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\n\n# External dependencies:\n# - https://salsa.debian.org/apt-team/apt (apt-ftparchive, packaged in apt-utils)\n# - https://github.com/s3tools/s3cmd\n#   s3cmd expects AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to be set in the\n#   environment.\n# - https://gnupg.org/\n#   For signing the script expects the private signing key to already be\n#   imported and PGPKEYID and PGP_SIGN_KEY_PASSPHRASE to be set in the\n#   environment.\n# - generate_index.py\n#   For generating the index.html of each directory. It's available in the\n#   packaging/bin directory of the k6 repo, and should be in $PATH.\n\n_s3bucket=\"${S3_BUCKET}\"\n_usage=\"Usage: $0 <pkgdir> <repodir> [s3bucket=${_s3bucket}]\"\nPKGDIR=\"${1?${_usage}}\"  # The directory where .deb files are located\nREPODIR=\"${2?${_usage}}\" # The package repository working directory\nS3PATH=\"${3-${_s3bucket}}/deb\"\n# Remove packages older than N number of days (730 is roughly ~2 years).\nREMOVE_PKG_DAYS=730\n\nlog() {\n  echo \"$(date -Iseconds) $*\"\n}\n\ndelete_old_pkgs() {\n  find \"$1\" -name '*.deb' -type f -daystart -mtime \"+${REMOVE_PKG_DAYS}\" -print0 | xargs -r0 rm -v\n\n  # Remove any dangling .asc files\n  find \"$1\" -name '*.asc' -type f -print0 | while read -r -d $'\\0' f; do\n    if ! [ -r \"${f%.*}\" ]; then\n      rm -v \"$f\"\n    fi\n  done\n}\n\nsync_to_s3() {\n  log \"Syncing to S3 ...\"\n  s3cmd sync --delete-removed \"${REPODIR}/\" \"s3://${S3PATH}/\"\n\n  # Set a short cache expiration for index and repo metadata files.\n  # We set --acl-private since we manage ACLs ourselves and don't want\n  # s3cmd to modify them. Otherwise, we receive AccessControlListNotSupported.\n  s3cmd modify --acl-private --recursive --exclude='*' \\\n    --include='index.html' --include='*Release*' --include='Packages*' \\\n    --add-header='Cache-Control: max-age=60,must-revalidate' \"s3://${S3PATH}/\"\n}\n\n# We don't publish i386 packages, but the repo structure is needed for\n# compatibility on some systems. See https://unix.stackexchange.com/a/272916 .\narchitectures=\"amd64 i386\"\n\npushd . > /dev/null\nmkdir -p \"$REPODIR\" && cd \"$_\"\n\nfor arch in $architectures; do\n  bindir=\"dists/stable/main/binary-$arch\"\n  mkdir -p \"$bindir\"\n  # Download existing files\n  # TODO: Consider doing this over the CDN with curl to avoid S3 egress costs,\n  # but that would involve parsing the index.html, checking the checksum\n  # manually, etc.\n  s3cmd sync --exclude='*' --include='*.deb' --include='*.asc' \\\n    \"s3://${S3PATH}/${bindir}/\" \"$bindir/\"\n\n  # Copy the new packages in\n  find \"$PKGDIR\" -name \"*$arch*.deb\" -type f -print0 | xargs -r0 cp -avt \"$bindir\"\n  # Generate signatures for files that don't have it\n  # TODO: Switch to debsign instead? This is currently done as Bintray did it,\n  # but the signature is not validated by apt/dpkg.\n  # https://blog.packagecloud.io/eng/2014/10/28/howto-gpg-sign-verify-deb-packages-apt-repositories/\n  find \"$bindir\" -type f -name '*.deb' -print0 | while read -r -d $'\\0' f; do\n    if ! [ -r \"${f}.asc\" ]; then\n      gpg2 --default-key=\"$PGPKEYID\" --passphrase=\"$PGP_SIGN_KEY_PASSPHRASE\" \\\n        --pinentry-mode=loopback --yes --detach-sign --armor -o \"${f}.asc\" \"$f\"\n    fi\n  done\n  apt-ftparchive packages \"$bindir\" | tee \"$bindir/Packages\"\n  gzip -fk \"$bindir/Packages\"\n  bzip2 -fk \"$bindir/Packages\"\n\n  delete_old_pkgs \"$bindir\"\ndone\n\nlog \"Creating release file...\"\napt-ftparchive release \\\n  -o APT::FTPArchive::Release::Origin=\"k6\" \\\n  -o APT::FTPArchive::Release::Label=\"k6\" \\\n  -o APT::FTPArchive::Release::Suite=\"stable\" \\\n  -o APT::FTPArchive::Release::Codename=\"stable\" \\\n  -o APT::FTPArchive::Release::Architectures=\"$architectures\" \\\n  -o APT::FTPArchive::Release::Components=\"main\" \\\n  -o APT::FTPArchive::Release::Date=\"$(date -Ru)\" \\\n  \"dists/stable\" > \"dists/stable/Release\"\n\n# Sign release file\ngpg2 --default-key=\"$PGPKEYID\" --passphrase=\"$PGP_SIGN_KEY_PASSPHRASE\" \\\n  --pinentry-mode=loopback --yes --detach-sign --armor \\\n  -o \"dists/stable/Release.gpg\" \"dists/stable/Release\"\ngpg2 --default-key=\"$PGPKEYID\" --passphrase=\"$PGP_SIGN_KEY_PASSPHRASE\" \\\n  --pinentry-mode=loopback --yes --clear-sign \\\n  -o \"dists/stable/InRelease\" \"dists/stable/Release\"\n\nlog \"Generating index.html ...\"\ngenerate_index.py -r\n\npopd > /dev/null\n\nsync_to_s3\n"
  },
  {
    "path": "packaging/bin/create-msi-repo.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\n\n# External dependencies:\n# - https://github.com/s3tools/s3cmd\n#   s3cmd expects AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to be set in the\n#   environment.\n# - generate_index.py\n#   For generating the index.html of each directory. It's available in the\n#   packaging/bin directory of the k6 repo, and should be in $PATH.\n\n_s3bucket=\"${S3_BUCKET}\"\n_usage=\"Usage: $0 <pkgdir> <repodir> [s3bucket=${_s3bucket}]\"\nPKGDIR=\"${1?${_usage}}\"  # The directory where .msi files are located\nREPODIR=\"${2?${_usage}}\" # The package repository working directory\nS3PATH=\"${3-${_s3bucket}}/msi\"\n# Remove packages older than N number of days (730 is roughly ~2 years).\nREMOVE_PKG_DAYS=730\n\nlog() {\n  echo \"$(date -Iseconds) $*\"\n}\n\ndelete_old_pkgs() {\n  find \"$1\" -name '*.msi' -type f -daystart -mtime \"+${REMOVE_PKG_DAYS}\" -print0 | xargs -r0 rm -v\n}\n\nsync_to_s3() {\n  log \"Syncing to S3 ...\"\n  s3cmd sync --delete-removed \"${REPODIR}/\" \"s3://${S3PATH}/\"\n\n  # Set a short cache expiration for index files and the latest MSI package.\n  # We set --private-acl since we manage ACLs ourselves and don't want\n  # s3cmd to modify them. Otherwise, we receive AccessControlListNotSupported.\n  s3cmd modify --acl-private --recursive --exclude='*' \\\n    --include='index.html' --include='k6-latest-amd64.msi' \\\n    --add-header='Cache-Control: max-age=60,must-revalidate' \"s3://${S3PATH}/\"\n}\n\nmkdir -p \"$REPODIR\"\n\n# Download existing packages\n# For MSI packages this is only done to be able to generate the index.html correctly.\n# Should we fake it and create empty files that have the same timestamp and size as the original ones?\ns3cmd sync --exclude='*' --include='*.msi' \"s3://${S3PATH}/\" \"$REPODIR/\"\n\n# Copy the new packages in\nfind \"$PKGDIR\" -name \"*.msi\" -type f -print0 | xargs -r0 cp -avt \"$REPODIR\"\n\ndelete_old_pkgs \"$REPODIR\"\n\n# Update the latest package. This could be done with S3 redirects, but\n# CloudFront caches redirects aggressively and I wasn't able to invalidate it.\nlatest=\"$(find \"$REPODIR\" -name '*.msi' -printf '%P\\n' | sort | tail -1)\"\ncp -p \"${REPODIR}/${latest}\" \"${REPODIR}/k6-latest-amd64.msi\"\n\nlog \"Generating index.html ...\"\n(cd \"$REPODIR\" && generate_index.py -r)\n\nsync_to_s3\n"
  },
  {
    "path": "packaging/bin/create-rpm-repo.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\n\n# External dependencies:\n# - https://github.com/rpm-software-management/createrepo_c\n# - https://github.com/s3tools/s3cmd\n#   s3cmd expects AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to be set in the\n#   environment.\n# - https://gnupg.org/\n#   For signing the script expects the private signing key to already be\n#   imported.\n# - generate_index.py\n#   For generating the index.html of each directory. It's available in the\n#   packaging/bin directory of the k6 repo, and should be in $PATH.\n\n_s3bucket=\"${S3_BUCKET}\"\n_usage=\"Usage: $0 <pkgdir> <repodir> [s3bucket=${_s3bucket}]\"\nPKGDIR=\"${1?${_usage}}\"  # The directory where .rpm files are located\nREPODIR=\"${2?${_usage}}\" # The package repository working directory\nS3PATH=\"${3-${_s3bucket}}/rpm\"\n# Remove packages older than N number of days (730 is roughly ~2 years).\nREMOVE_PKG_DAYS=730\n\nlog() {\n  echo \"$(date -Iseconds) $*\"\n}\n\ndelete_old_pkgs() {\n  find \"$1\" -name '*.rpm' -type f -daystart -mtime \"+${REMOVE_PKG_DAYS}\" -print0 | xargs -r0 rm -v\n}\n\nsync_to_s3() {\n  log \"Syncing to S3 ...\"\n  s3cmd sync --delete-removed \"${REPODIR}/\" \"s3://${S3PATH}/\"\n\n  # Set a short cache expiration for index and repo metadata files.\n  # We set --acl-private since we manage ACLs ourselves and don't want\n  # s3cmd to modify them. Otherwise, we receive AccessControlListNotSupported.\n  s3cmd modify --acl-private --recursive --exclude='*' \\\n    --include='index.html' --include='/repodata/*' \\\n    --add-header='Cache-Control: max-age=60,must-revalidate' \"s3://${S3PATH}/\"\n}\n\n# Setup RPM signing\nif ! [ -r \"$HOME/.rpmmacros\" ]; then\n  cat > \"$HOME/.rpmmacros\" <<EOF\n%_gpgbin        $(command -v gpg2)\n%_gpg_path      $HOME/.gnupg\n%_gpg_name      k6\n%_gpg_pass      -\n%__gpg_sign_cmd   %{__gpg} gpg2 --default-key=\"$PGPKEYID\" --no-verbose \\\n  --no-armor --pinentry-mode=loopback --yes --no-secmem-warning \\\n  --passphrase=\"$PGP_SIGN_KEY_PASSPHRASE\" --detach-sign \\\n  -o %{__signature_filename} %{__plaintext_filename}\nEOF\nfi\n\narchitectures=\"x86_64\"\n\npushd . > /dev/null\nmkdir -p \"$REPODIR\" && cd \"$_\"\n\nfor arch in $architectures; do\n  mkdir -p \"$arch\" && cd \"$_\"\n\n  # Download existing packages\n  # TODO: Consider doing this over the CDN with curl to avoid S3 egress costs,\n  # but that would involve parsing the index.html, checking the checksum\n  # manually, etc.\n  s3cmd sync --exclude='*' --include='*.rpm' \"s3://${S3PATH}/${arch}/\" ./\n\n  # Copy the new packages in and generate signatures\n  # FIXME: The architecture naming used by yum docs and in public RPM repos is\n  # \"x86_64\", whereas our packages are named with \"amd64\". So we do a replacement\n  # here, but we should probably consider naming them with \"x86_64\" instead.\n  find \"$PKGDIR\" -name \"*${arch/x86_64/amd64}*.rpm\" -type f -print0 | while read -r -d $'\\0' f; do\n    cp -av \"$f\" \"$PWD/\"\n    rpm --addsign \"${f##*/}\"\n  done\n  createrepo_c .\n  cd -\n\n  delete_old_pkgs \"$arch\"\ndone\n\n# Create the RPM repository package if it doesn't exist already.\n# This is a bit hacky as it expects the GPG key to exist and the $HOME/rpmbuild\n# directory to have been pre-populated, but it's done here so that the index\n# generation script can pick up the file.\ns3cmd get \"s3://${S3PATH}/repo.rpm\" \"${REPODIR}/repo.rpm\" >/dev/null || {\n  mkdir -p \"$HOME/rpmbuild/SOURCES\"\n  cp -av \"${REPODIR}/../key.gpg\" \"$HOME/rpmbuild/SOURCES/RPM-GPG-KEY-k6-io\"\n  rpmbuild -ba \"$HOME/rpmbuild/SPECS/k6-rpm-repo.spec\"\n  cp -av \"$(find \"$HOME/rpmbuild/RPMS/\" -type f -name '*.rpm')\" \"${REPODIR}/repo.rpm\"\n}\n\nlog \"Generating index.html ...\"\ngenerate_index.py -r\n\npopd > /dev/null\n\nsync_to_s3\n"
  },
  {
    "path": "packaging/bin/entrypoint.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\n\n# Generate repositories for k6 packages and sync them from/to AWS S3.\n# These scripts use both s3cmd and aws-cli, since the latter doesn't\n# preserve timestamps and doesn't compute/check hashes, relying instead\n# on timestamps or file size to determine whether a sync should be done.\n# aws-cli is still used for invalidating the CloudFront cache, which\n# doesn't work with s3cmd...\n# See:\n# - https://github.com/aws/aws-cli/issues/3069#issuecomment-818732309\n# - https://github.com/s3tools/s3cmd/issues/536\n# - https://github.com/s3tools/s3cmd/issues/790\n\nlog() {\n  echo \"$(date -Iseconds) $*\"\n}\n\nsignkeypath=\"$PWD/sign-key.gpg\"\ns3bucket=\"${S3_BUCKET}\"\npkgdir=\"$PWD/Packages\"\n\nif ! [ -r \"$signkeypath\" ]; then\n  log \"ERROR: Signing key not found at '$signkeypath'\"\n  exit 1\nfi\n\ngpg2 --import --batch --passphrase=\"$PGP_SIGN_KEY_PASSPHRASE\" \"$signkeypath\"\nexport PGPKEYID=\"$(gpg2 --list-secret-keys --with-colons | grep '^sec' | cut -d: -f5)\"\n# Export and sync the GPG pub key if it doesn't exist in S3 already.\nmkdir -p \"$pkgdir\"\ns3cmd get \"s3://${s3bucket}/key.gpg\" \"${pkgdir}/key.gpg\" || {\n  gpg2 --export --armor --output \"${pkgdir}/key.gpg\" \"$PGPKEYID\"\n  s3cmd put \"${pkgdir}/key.gpg\" \"s3://${s3bucket}/key.gpg\"\n}\n\nfor repo in deb rpm msi; do\n  log \"Creating ${repo} repository ...\"\n  \"create-${repo}-repo.sh\" \"$PWD/dist\" \"${pkgdir}/${repo}\"\ndone\n\n# Generate and sync the main index.html\n(cd \"$pkgdir\" && generate_index.py)\ns3cmd put --add-header='Cache-Control: max-age=60,must-revalidate' \\\n  \"${pkgdir}/index.html\" \"s3://${s3bucket}/index.html\"\n\n# Invalidate CloudFront cache for index files, repo metadata and the latest MSI package.\nIFS=' ' read -ra indexes <<< \\\n  \"$(find \"${pkgdir}\" -name 'index.html' -type f | sed \"s:^${pkgdir}::\" | sort | paste -sd' ')\"\naws cloudfront create-invalidation --distribution-id \"$AWS_CF_DISTRIBUTION\" \\\n  --paths \"${indexes[@]}\" \"/msi/k6-latest-amd64.msi\" \\\n  \"/deb/dists/stable/\"{Release,Release.gpg,InRelease} \\\n  \"/deb/dists/stable/main/binary-amd64\"/Packages{,.gz,.bz2} \\\n  \"/rpm/x86_64/repodata/*\"\n\nexec \"$@\"\n"
  },
  {
    "path": "packaging/bin/generate_index.py",
    "content": "#!/usr/bin/env python3\n# ---\n# Copyright 2020 glowinthedark\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n#\n# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#\n# See the License for the specific language governing permissions and limitations under the License.\n# ---\n#\n# Generate index.html files for\n# all subdirectories in a directory tree.\n\n# -handle symlinked files and folders: displayed with custom icons\n\n# By default only the current folder is processed.\n\n# Use -r or --recursive to process nested folders.\n# Source: https://gist.githubusercontent.com/glowinthedark/625eb4caeca12c5aa52778a3b4b0adb4/\n\nimport argparse\nimport datetime\nimport os\nimport sys\nfrom pathlib import Path\n\nindex_file_name = 'index.html'\n\n\ndef process_dir(top_dir, opts):\n    glob_patt = opts.filter or '*'\n\n    path_top_dir: Path\n    path_top_dir = Path(top_dir)\n    index_file = None\n\n    index_path = Path(path_top_dir, index_file_name)\n\n    if opts.verbose:\n        print(f'Traversing dir {path_top_dir.absolute()}')\n\n    try:\n        index_file = open(index_path, \"w\")\n    except Exception as e:\n        print('cannot create file %s %s' % (index_path, e))\n        return\n\n    index_file.write(\"\"\"<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>k6 Packages</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <style>\n    * { padding: 0; margin: 0; }\n\n    body {\n        font-family: sans-serif;\n        text-rendering: optimizespeed;\n        background-color: #ffffff;\n    }\n\n    a {\n        color: #006ed3;\n        text-decoration: none;\n    }\n\n    a:hover,\n    h1 a:hover {\n        color: #319cff;\n    }\n\n    header,\n    #summary {\n        padding-left: 5%;\n        padding-right: 5%;\n    }\n\n    th:first-child,\n    td:first-child {\n        width: 5%;\n    }\n\n    th:last-child,\n    td:last-child {\n        width: 5%;\n    }\n\n    header {\n        padding-top: 25px;\n        padding-bottom: 15px;\n        background-color: #f2f2f2;\n    }\n\n    h1 {\n        display: inline-block;\n        vertical-align: bottom;\n        font-size: 20px;\n        font-weight: normal;\n        white-space: nowrap;\n        overflow-x: hidden;\n        text-overflow: ellipsis;\n        color: #999;\n    }\n\n    h1 a {\n        color: #000;\n        margin: 0 4px;\n    }\n\n    h1 a:hover {\n        text-decoration: underline;\n    }\n\n    h1 a:first-child {\n        margin: 0;\n    }\n\n    svg.logo {\n        display: inline-block;\n        vertical-align: middle;\n        width: 2.5em;\n        height: 2.5em;\n    }\n\n    main {\n        display: block;\n    }\n\n    .meta {\n        font-size: 12px;\n        font-family: Verdana, sans-serif;\n        border-bottom: 1px solid #9C9C9C;\n        padding-top: 10px;\n        padding-bottom: 10px;\n    }\n\n    .meta-item {\n        margin-right: 1em;\n    }\n\n    #filter {\n        padding: 4px;\n        border: 1px solid #CCC;\n    }\n\n    table {\n        width: 100%;\n        border-collapse: collapse;\n    }\n\n    tr {\n        border-bottom: 1px dashed #dadada;\n    }\n\n    tbody tr:hover {\n        background-color: #ffffec;\n    }\n\n    th,\n    td {\n        text-align: left;\n        padding: 10px 0;\n    }\n\n    th {\n        padding-top: 15px;\n        padding-bottom: 15px;\n        font-size: 16px;\n        white-space: nowrap;\n    }\n\n    th a {\n        color: black;\n    }\n\n    th svg {\n        vertical-align: middle;\n    }\n\n    td {\n        white-space: nowrap;\n        font-size: 14px;\n    }\n\n    td:nth-child(2) {\n        width: 80%;\n    }\n\n    td:nth-child(3) {\n        padding: 0 20px 0 20px;\n    }\n\n    th:nth-child(4),\n    td:nth-child(4) {\n        text-align: right;\n    }\n\n    td:nth-child(2) svg {\n        position: absolute;\n    }\n\n    td .name {\n        margin-left: 1.75em;\n        word-break: break-all;\n        overflow-wrap: break-word;\n        white-space: pre-wrap;\n    }\n\n    td .goup {\n        margin-left: 1.75em;\n        padding: 0;\n        word-break: break-all;\n        overflow-wrap: break-word;\n        white-space: pre-wrap;\n    }\n\n    .icon {\n        margin-right: 5px;\n    }\n\n    tr.clickable {\n        cursor: pointer;\n    }\n    tr.clickable a {\n        display: block;\n    }\n\n    @media (max-width: 600px) {\n\n        * {\n            font-size: 1.06rem;\n        }\n        .hideable {\n            display: none;\n        }\n\n        td:nth-child(2) {\n            width: auto;\n        }\n\n        th:nth-child(3),\n        td:nth-child(3) {\n            padding-right: 5%;\n            text-align: right;\n        }\n\n        h1 {\n            color: #000;\n        }\n\n        h1 a {\n            margin: 0;\n        }\n\n        #filter {\n            max-width: 100px;\n        }\n    }\n    </style>\n</head>\n<body>\n    <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" height=\"0\" width=\"0\" style=\"position: absolute;\">\n    <defs>\n        <!-- Go-up -->\n        <g id=\"go-up\">\n            <path d=\"M10,9V5L3,12L10,19V14.9C15,14.9 18.5,16.5 21,20C20,15 17,10 10,9Z\" fill=\"#696969\"/>\n        </g>\n\n        <!-- Folder -->\n        <g id=\"folder\" fill-rule=\"nonzero\" fill=\"none\">\n            <path d=\"M285.22 37.55h-142.6L110.9 0H31.7C14.25 0 0 16.9 0 37.55v75.1h316.92V75.1c0-20.65-14.26-37.55-31.7-37.55z\" fill=\"#FFA000\"/>\n            <path d=\"M285.22 36H31.7C14.25 36 0 50.28 0 67.74v158.7c0 17.47 14.26 31.75 31.7 31.75H285.2c17.44 0 31.7-14.3 31.7-31.75V67.75c0-17.47-14.26-31.75-31.7-31.75z\" fill=\"#FFCA28\"/>\n        </g>\n        <g id=\"folder-shortcut\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n            <g id=\"folder-shortcut-group\" fill-rule=\"nonzero\">\n                <g id=\"folder-shortcut-shape\">\n                    <path d=\"M285.224876,37.5486902 L142.612438,37.5486902 L110.920785,0 L31.6916529,0 C14.2612438,0 0,16.8969106 0,37.5486902 L0,112.646071 L316.916529,112.646071 L316.916529,75.0973805 C316.916529,54.4456008 302.655285,37.5486902 285.224876,37.5486902 Z\" id=\"Shape\" fill=\"#FFA000\"></path>\n                    <path d=\"M285.224876,36 L31.6916529,36 C14.2612438,36 0,50.2838568 0,67.7419039 L0,226.451424 C0,243.909471 14.2612438,258.193328 31.6916529,258.193328 L285.224876,258.193328 C302.655285,258.193328 316.916529,243.909471 316.916529,226.451424 L316.916529,67.7419039 C316.916529,50.2838568 302.655285,36 285.224876,36 Z\" id=\"Shape\" fill=\"#FFCA28\"></path>\n                </g>\n                <path d=\"M126.154134,250.559184 C126.850974,251.883673 127.300549,253.006122 127.772602,254.106122 C128.469442,255.206122 128.919016,256.104082 129.638335,257.002041 C130.559962,258.326531 131.728855,259 133.100057,259 C134.493737,259 135.415364,258.55102 136.112204,257.67551 C136.809044,257.002041 137.258619,255.902041 137.258619,254.577551 C137.258619,253.904082 137.258619,252.804082 137.033832,251.457143 C136.786566,249.908163 136.561779,249.032653 136.561779,248.583673 C136.089726,242.814286 135.864939,237.920408 135.864939,233.273469 C135.864939,225.057143 136.786566,217.514286 138.180246,210.846939 C139.798713,204.202041 141.889234,198.634694 144.429328,193.763265 C147.216689,188.869388 150.678411,184.873469 154.836973,181.326531 C158.995535,177.779592 163.626149,174.883673 168.481552,172.661224 C173.336954,170.438776 179.113983,168.665306 185.587852,167.340816 C192.061722,166.218367 198.760378,165.342857 205.481514,164.669388 C212.18017,164.220408 219.598146,163.995918 228.162535,163.995918 L246.055591,163.995918 L246.055591,195.514286 C246.055591,197.736735 246.752431,199.510204 248.370899,201.059184 C250.214153,202.608163 252.079886,203.506122 254.372715,203.506122 C256.463236,203.506122 258.531277,202.608163 260.172223,201.059184 L326.102289,137.797959 C327.720757,136.24898 328.642384,134.47551 328.642384,132.253061 C328.642384,130.030612 327.720757,128.257143 326.102289,126.708163 L260.172223,63.4469388 C258.553756,61.8979592 256.463236,61 254.395194,61 C252.079886,61 250.236632,61.8979592 248.393377,63.4469388 C246.77491,64.9959184 246.07807,66.7693878 246.07807,68.9918367 L246.07807,100.510204 L228.162535,100.510204 C166.863084,100.510204 129.166282,117.167347 115.274437,150.459184 C110.666301,161.54898 108.350993,175.310204 108.350993,191.742857 C108.350993,205.279592 113.903236,223.912245 124.760454,247.438776 C125.00772,248.112245 125.457294,249.010204 126.154134,250.559184 Z\" id=\"Shape\" fill=\"#FFFFFF\" transform=\"translate(218.496689, 160.000000) scale(-1, 1) translate(-218.496689, -160.000000) \"></path>\n            </g>\n        </g>\n\n        <!-- File -->\n        <g id=\"file\" stroke=\"#000\" stroke-width=\"25\" fill=\"#FFF\" fill-rule=\"evenodd\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n            <path d=\"M13 24.12v274.76c0 6.16 5.87 11.12 13.17 11.12H239c7.3 0 13.17-4.96 13.17-11.12V136.15S132.6 13 128.37 13H26.17C18.87 13 13 17.96 13 24.12z\"/>\n            <path d=\"M129.37 13L129 113.9c0 10.58 7.26 19.1 16.27 19.1H249L129.37 13z\"/>\n        </g>\n        <g id=\"file-shortcut\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n            <g id=\"file-shortcut-group\" transform=\"translate(13.000000, 13.000000)\">\n                <g id=\"file-shortcut-shape\" stroke=\"#000000\" stroke-width=\"25\" fill=\"#FFFFFF\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n                    <path d=\"M0,11.1214886 L0,285.878477 C0,292.039924 5.87498876,296.999983 13.1728373,296.999983 L225.997983,296.999983 C233.295974,296.999983 239.17082,292.039942 239.17082,285.878477 L239.17082,123.145388 C239.17082,123.145388 119.58541,2.84217094e-14 115.369423,2.84217094e-14 L13.1728576,2.84217094e-14 C5.87500907,-1.71479982e-05 0,4.96022995 0,11.1214886 Z\" id=\"rect1171\"></path>\n                    <path d=\"M116.37005,0 L116,100.904964 C116,111.483663 123.258008,120 132.273377,120 L236,120 L116.37005,0 L116.37005,0 Z\" id=\"rect1794\"></path>\n                </g>\n                <path d=\"M47.803141,294.093878 C48.4999811,295.177551 48.9495553,296.095918 49.4216083,296.995918 C50.1184484,297.895918 50.5680227,298.630612 51.2873415,299.365306 C52.2089688,300.44898 53.3778619,301 54.7490634,301 C56.1427436,301 57.0643709,300.632653 57.761211,299.916327 C58.4580511,299.365306 58.9076254,298.465306 58.9076254,297.381633 C58.9076254,296.830612 58.9076254,295.930612 58.6828382,294.828571 C58.4355724,293.561224 58.2107852,292.844898 58.2107852,292.477551 C57.7387323,287.757143 57.5139451,283.753061 57.5139451,279.95102 C57.5139451,273.228571 58.4355724,267.057143 59.8292526,261.602041 C61.44772,256.165306 63.5382403,251.610204 66.0783349,247.62449 C68.8656954,243.620408 72.3274172,240.35102 76.4859792,237.44898 C80.6445412,234.546939 85.2751561,232.177551 90.1305582,230.359184 C94.9859603,228.540816 100.76299,227.089796 107.236859,226.006122 C113.710728,225.087755 120.409385,224.371429 127.13052,223.820408 C133.829177,223.453061 141.247152,223.269388 149.811542,223.269388 L167.704598,223.269388 L167.704598,249.057143 C167.704598,250.87551 168.401438,252.326531 170.019905,253.593878 C171.86316,254.861224 173.728893,255.595918 176.021722,255.595918 C178.112242,255.595918 180.180284,254.861224 181.82123,253.593878 L247.751296,201.834694 C249.369763,200.567347 250.291391,199.116327 250.291391,197.297959 C250.291391,195.479592 249.369763,194.028571 247.751296,192.761224 L181.82123,141.002041 C180.202763,139.734694 178.112242,139 176.044201,139 C173.728893,139 171.885639,139.734694 170.042384,141.002041 C168.423917,142.269388 167.727077,143.720408 167.727077,145.538776 L167.727077,171.326531 L149.811542,171.326531 C88.5120908,171.326531 50.8152886,184.955102 36.9234437,212.193878 C32.3153075,221.267347 30,232.526531 30,245.971429 C30,257.046939 35.5522422,272.291837 46.4094607,291.540816 C46.6567266,292.091837 47.1063009,292.826531 47.803141,294.093878 Z\" id=\"Shape-Copy\" fill=\"#000000\" fill-rule=\"nonzero\" transform=\"translate(140.145695, 220.000000) scale(-1, 1) translate(-140.145695, -220.000000) \"></path>\n            </g>\n        </g>\n\n        <!-- k6 Logo -->\n        <g id=\"logo\">\n          <path d=\"M220.727,213.731H.5L73.815,57.346l44.163,32.466L175.581,0Zm-80.746-33.778h.471a21.028,21.028,0,0,0,14.619-5.876,19.166,19.166,0,0,0,6.284-14.454,17.546,17.546,0,0,0-6.057-13.873,18.426,18.426,0,0,0-12.568-5.412h-.361a6.567,6.567,0,0,0-1.83.251l11.626-17.282-9.262-6.465-4.383,6.465-11.2,17.109c-1.925,2.836-3.535,5.334-4.533,7.07a40.655,40.655,0,0,0-2.663,5.726,17.816,17.816,0,0,0-1.272,6.6,19.145,19.145,0,0,0,6.206,14.3,20.709,20.709,0,0,0,14.485,5.876Zm-49.237-18.6,12.836,18.154H117.3l-15.1-21.06,13.41-18.617-8.9-6.159-3.927,5.184-12.058,17V121.674l-12.019-9.8V179.5H90.727V161.336ZM140,168.618a8.837,8.837,0,1,1,0-17.675h.079a8.639,8.639,0,0,1,6.229,2.663,8.228,8.228,0,0,1,2.663,6.127A8.978,8.978,0,0,1,140,168.6Z\" transform=\"translate(-0.5 -0.001)\" fill=\"#7d64ff\"/>\n        </g>\n    </defs>\n    </svg>\n<header>\n    <a href=\"/\" title=\"Home\">\n      <svg class=\"logo\" viewBox=\"0 0 220.227 213.73\"><use xlink:href=\"#logo\"></use></svg>\n    </a>\n    <h1>\"\"\"\n        f'{path_top_dir.name}'\n    \"\"\"</h1>\n</header>\n<main>\n<div class=\"listing\">\n    <table aria-describedby=\"summary\">\n        <thead>\n        <tr>\n            <th></th>\n            <th>Name</th>\n            <th>Size</th>\n            <th class=\"hideable\">\n                Modified\n            </th>\n            <th class=\"hideable\"></th>\n        </tr>\n        </thead>\n        <tbody>\n        <tr class=\"clickable\">\n            <td></td>\n            <td><a href=\"..\"><svg width=\"1.5em\" height=\"1em\" version=\"1.1\" viewBox=\"0 0 24 24\"><use xlink:href=\"#go-up\"></use></svg>\n<span class=\"goup\">..</span></a></td>\n            <td>&mdash;</td>\n            <td class=\"hideable\">&mdash;</td>\n            <td class=\"hideable\"></td>\n        </tr>\n\"\"\")\n\n    # sort dirs first\n    sorted_entries = sorted(path_top_dir.glob(glob_patt), key= lambda p: (p.is_file(), p.name))\n\n    entry: Path\n    for entry in sorted_entries:\n\n        # don't include index.html in the file listing\n        if entry.name.lower() == index_file_name.lower():\n            continue\n\n        if entry.is_dir() and opts.recursive:\n            process_dir(entry, opts)\n\n        # From Python 3.6, os.access() accepts path-like objects\n        if (not entry.is_symlink()) and not os.access(str(entry), os.W_OK):\n            print(f\"*** WARNING *** entry {entry.absolute()} is not writable! SKIPPING!\")\n            continue\n        if opts.verbose:\n            print(f'{entry.absolute()}')\n\n        size_bytes = -1  ## is a folder\n        size_pretty = '&mdash;'\n        last_modified = '-'\n        last_modified_human_readable = '-'\n        last_modified_iso = ''\n        try:\n            if entry.is_file():\n                size_bytes = entry.stat().st_size\n                size_pretty = pretty_size(size_bytes)\n\n            if entry.is_dir() or entry.is_file():\n                last_modified = datetime.datetime.fromtimestamp(entry.stat().st_mtime).replace(microsecond=0)\n                last_modified_iso = last_modified.isoformat()\n                last_modified_human_readable = last_modified.strftime(\"%c\")\n\n        except Exception as e:\n            print('ERROR accessing file name:', e, entry)\n            continue\n\n        entry_path = str(entry.name)\n\n        if entry.is_dir() and not entry.is_symlink():\n            entry_type = 'folder'\n            entry_path = os.path.join(entry.name, '')\n\n        elif entry.is_dir() and entry.is_symlink():\n            entry_type = 'folder-shortcut'\n            print('dir-symlink', entry.absolute())\n\n        elif entry.is_file() and entry.is_symlink():\n            entry_type = 'file-shortcut'\n            print('file-symlink', entry.absolute())\n\n        else:\n            entry_type = 'file'\n\n        index_file.write(f\"\"\"\n        <tr class=\"file\">\n            <td></td>\n            <td>\n                <a href=\"{entry_path}\">\n                    <svg width=\"1.5em\" height=\"1em\" version=\"1.1\" viewBox=\"0 0 265 323\"><use xlink:href=\"#{entry_type}\"></use></svg>\n                    <span class=\"name\">{entry.name}</span>\n                </a>\n            </td>\n            <td data-order=\"{size_bytes}\">{size_pretty}</td>\n            <td class=\"hideable\"><time datetime=\"{last_modified_iso}\">{last_modified_human_readable}</time></td>\n            <td class=\"hideable\"></td>\n        </tr>\n\"\"\")\n\n    index_file.write(\"\"\"\n            </tbody>\n        </table>\n    </div>\n</main>\n</body>\n</html>\"\"\")\n    if index_file:\n        index_file.close()\n\n\n# bytes pretty-printing\nUNITS_MAPPING = [\n    (1024 ** 5, ' PB'),\n    (1024 ** 4, ' TB'),\n    (1024 ** 3, ' GB'),\n    (1024 ** 2, ' MB'),\n    (1024 ** 1, ' KB'),\n    (1024 ** 0, (' byte', ' bytes')),\n]\n\n\ndef pretty_size(bytes, units=UNITS_MAPPING):\n    \"\"\"Human-readable file sizes.\n\n    ripped from https://pypi.python.org/pypi/hurry.filesize/\n    \"\"\"\n    for factor, suffix in units:\n        if bytes >= factor:\n            break\n    amount = int(bytes / factor)\n\n    if isinstance(suffix, tuple):\n        singular, multiple = suffix\n        if amount == 1:\n            suffix = singular\n        else:\n            suffix = multiple\n    return str(amount) + suffix\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(description='''DESCRIPTION:\n    Generate directory index files (recursive is OFF by default).\n    Start from current dir or from folder passed as first positional argument.\n    Optionally filter by file types with --filter \"*.py\". ''')\n\n    parser.add_argument('top_dir',\n                        nargs='?',\n                        action='store',\n                        help='top folder from which to start generating indexes, '\n                             'use current folder if not specified',\n                        default=os.getcwd())\n\n    parser.add_argument('--filter', '-f',\n                        help='only include files matching glob',\n                        required=False)\n\n    parser.add_argument('--recursive', '-r',\n                        action='store_true',\n                        help=\"recursively process nested dirs (FALSE by default)\",\n                        required=False)\n\n    parser.add_argument('--verbose', '-v',\n                        action='store_true',\n                        help='***WARNING: this can take a very long time with complex file tree structures***'\n                             ' verbosely list every processed file',\n                        required=False)\n\n    config = parser.parse_args(sys.argv[1:])\n    process_dir(config.top_dir, config)\n"
  },
  {
    "path": "packaging/docker-compose.yml",
    "content": "services:\n  packager:\n    build:\n      context: .\n    image: ghcr.io/grafana/k6packager:latest\n    environment:\n      - AWS_ACCESS_KEY_ID\n      - AWS_CF_DISTRIBUTION\n      - AWS_DEFAULT_REGION\n      - AWS_SECRET_ACCESS_KEY\n      - AWS_SESSION_TOKEN\n      - PGP_SIGN_KEY_PASSPHRASE\n      - S3_BUCKET\n    volumes:\n      - ../dist:/home/k6/dist\n      - ./sign-key.gpg:/home/k6/sign-key.gpg\n"
  },
  {
    "path": "packaging/k6-rpm-repo.spec",
    "content": "Name:           k6-rpm\nVersion:        0.0.2\nRelease:        1\nSummary:        k6 RPM Repository Configuration\nGroup:          System Environment/Base\nLicense:        AGPL-3.0\nURL:            https://dl.k6.io\nSource0:        RPM-GPG-KEY-k6-io\nSource1:        k6-io.repo\nBuildRoot:      %{_builddir}/%{name}-%{version}-rpmroot\nBuildArch:      noarch\n\n%description\nThis package installs the repository GPG and repo files for the k6 software repository.\n\n%prep\n%setup -c -T\n\n%build\n\n%install\nrm -rf $RPM_BUILD_ROOT\n\n# gpg\ninstall -Dpm 644 %{SOURCE0} $RPM_BUILD_ROOT%{_sysconfdir}/pki/rpm-gpg/RPM-GPG-KEY-k6-io\n\n# yum\ninstall -dm 755 $RPM_BUILD_ROOT%{_sysconfdir}/yum.repos.d\ninstall -pm 644 %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/yum.repos.d\n\n%clean\nrm -rf $RPM_BUILD_ROOT\n\n%files\n%defattr(-,root,root,-)\n%{_sysconfdir}/pki/rpm-gpg/RPM-GPG-KEY-k6-io\n%config %{_sysconfdir}/yum.repos.d/k6-io.repo\n"
  },
  {
    "path": "packaging/k6-rpm.repo",
    "content": "[k6]\nname=k6\nbaseurl=https://dl.k6.io/rpm/$basearch\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=0\nmetadata_expire=1d\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-k6-io\n"
  },
  {
    "path": "packaging/k6.wxs",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n    <Product Id=\"*\" UpgradeCode=\"8C5F9495-F697-4780-ABFD-90DCC2F681B6\" Version=\"$(var.VERSION)\" Language=\"1033\" Name=\"k6\" Manufacturer=\"Grafana Labs\">\n        <Package InstallerVersion=\"300\" Compressed=\"yes\"/>\n        <MajorUpgrade AllowSameVersionUpgrades=\"yes\" DowngradeErrorMessage=\"A later version of [ProductName] is already installed. Setup will now exit.\"/>\n\n        <Icon Id=\"k6Icon\" SourceFile=\"k6.ico\"/>\n        <Property Id=\"ARPPRODUCTICON\" Value=\"k6Icon\"/>\n\n        <Media Id=\"1\" Cabinet=\"k6.cab\" EmbedCab=\"yes\" />\n\n        <!-- Step 1: Define the directory structure -->\n        <Directory Id=\"TARGETDIR\" Name=\"SourceDir\">\n            <Directory Id=\"ProgramFiles64Folder\">\n                <Directory Id=\"INSTALLDIR\" Name=\"k6\"/>\n            </Directory>\n        </Directory>\n\n        <!-- Step 2: Add files to your installer package -->\n        <DirectoryRef Id=\"INSTALLDIR\">\n            <Component Id=\"k6.exe\" Guid=\"*\">\n                <File Id=\"k6.exe\" Source=\"k6.exe\" KeyPath=\"yes\" />\n            </Component>\n            <Component Id=\"PathEnv\" Guid=\"2DFDBB7D-292E-462c-A3E3-2FA14FFCD05D\" >\n              <Environment Id=\"Path\" Name=\"PATH\" Value=\"[INSTALLDIR]\" Permanent=\"no\" Part=\"last\" Action=\"set\" System=\"yes\" Separator=\";\" />\n              <CreateFolder />\n            </Component>\n        </DirectoryRef>\n\n        <!-- Step 3: Tell WiX to install the files -->\n        <Feature Id=\"MainApplication\" Title=\"Main Application\" Level=\"1\">\n            <ComponentRef Id=\"k6.exe\" />\n            <ComponentRef Id=\"PathEnv\" />\n        </Feature>\n\n         <UI Id=\"k6InstallUI\">\n            <Property Id=\"WIXUI_INSTALLDIR\" Value=\"INSTALLDIR\" />\n            <Property Id=\"WIXUI_EXITDIALOGOPTIONALTEXT\" Value=\"k6 has been successfully installed.\" />\n         </UI>\n\n        <UIRef Id=\"WixUI_InstallDir\" />\n        <UIRef Id=\"WixUI_ErrorProgressText\" />\n        <WixVariable Id=\"WixUIBannerBmp\" Value=\"thin-white-stripe.jpg\"/>\n        <WixVariable Id=\"WixUIDialogBmp\" Value=\"full-white-stripe.jpg\"/>\n        <WixVariable Id=\"WixUILicenseRtf\" Value=\"LICENSE.rtf\"/>\n    </Product>\n</Wix>\n"
  },
  {
    "path": "packaging/nfpm.yaml",
    "content": "name: \"k6\"\narch: \"${GOARCH}\"\nplatform: \"linux\"\nversion: \"${VERSION}\"\nversion_schema: semver\nsection: \"default\"\nmaintainer: \"Raintank Inc. d.b.a. Grafana Labs\"\ndescription: |\n  Load testing for the 21st century.\ndepends:\n- ca-certificates\nhomepage: \"https://k6.io\"\nlicense: \"AGPL-3.0\"\ncontents:\n- src: ./k6\n  dst: /usr/bin/k6\n\ndeb:\n  compression: xz\n  fields:\n    Bugs: https://github.com/grafana/k6/issues"
  },
  {
    "path": "release notes/template.md",
    "content": "k6 `<version>` is here 🎉! This release includes:\n\n- (_optional_) `<highlight of breaking changes>`\n- `<Summary of new features>` (_one or multiple bullets_)\n\n## Breaking changes\n\n- `#pr`, `<small_break_1>`\n- `#pr`, `<small_break_2>`\n\n### (_optional h3_) `<big_breaking_change>` `#pr`\n\n## New features\n\n_optional intro here_\n\n### `<big_feature_1>` `#pr`\n\n_what, why, and what this means for the user_\n\n### `<big_feature_n>` `#pr`\n\n_what, why, and what this means for the user_\n\n## UX improvements and enhancements\n\n_Format as `<number> <present_verb> <object>. <credit>`_:\n\n- _`#999` Gives terminal output prettier printing. Thanks to `@person` for the help!_\n- `#pr` `<description>`\n- `#pr` `<description>`\n\n## Bug fixes\n\n_Format as `<number> <present_verb> <object>. <credit>`_:\n\n- _`#111` Fixes race condition in runtime_\n\n## Maintenance and internal improvements\n\n_Format as `<number> <present_verb> <object>. <credit>`_:\n\n- _`#2770` Refactors parts of the JS module._\n\n## _Optional_ Roadmap\n\n_Discussion of future plans_\n"
  },
  {
    "path": "release notes/v0.19.0.md",
    "content": "The first release of 2018! :tada:\n\nWe have contributions from 10 people outside of Load Impact in this release, yay! To celebrate that and make onboarding of new users and contributors easier we’ve improved the [README](https://github.com/loadimpact/k6) to give a better overview of the project and the [Contributing guide](https://github.com/loadimpact/k6/blob/master/CONTRIBUTING.md) with better instructions how to get a k6 dev environment set up.\n\nA big thanks to the following people for contributing to this release: @antekresic, @borjacampina, @cstyan, @dstpierre, @ivoreis, @jonathon-l, @marklagendijk, @Ripolin, @tbroadley, and @tmcgannon\n \n## New Features!\n\n### HAR to JS converter (#291, #453)\nk6 now has a builtin command `k6 convert recording.har > recording.js` to convert HAR files to JS. This is great for being able to quickly go from a browser/proxy recording to a k6 script, a common flow for getting started with a new test case.\n\nThanks to @borjacampina for their work on this!\n\n**Docs**: [HAR converter](https://docs.k6.io/docs/session-recording-har-support)\n \n### CLI/options: RPS limiter\nA global request per second limiter has been added to k6. It will trigger if the RPS level goes above the set value, blocking further requests for a short period to maintain the desired level.\n\n```js\nexport let options = {\n    rps: 100\n};\n```\n\nOr `--rps` on the CLI.\n\n### CLI: Logging in JSON format (#434)\nYou can now output logs in JSON format! It looks something like this:\n`{\"level\":\"debug\",\"msg\":\"Engine terminated cleanly\",\"time\":\"2017-12-20T12:30:35Z\"}`\n\nThanks to @ivoreis for this PR!\n\n### k6/http: Automatic decompression of deflate encoded response bodies (#419)\nAdds handling of deflate (as specified in [RFC 1950](https://tools.ietf.org/html/rfc1950)) encoded response bodies by automatically decompressing them.\n \n### k6/http: Automatic decompression of gzip encoded response bodies (#438)\nSame as the one above but for gzip. k6 previously automatically handled gzip compressed bodies as long as no `Accept-Encoding` header was explicitly specified when making a request, but this adds transparent decompression as long as the `Content-Encoding` header in a response is set to gzip.\n\nThanks to @Ripolin for discovering the discrepancy in the handling of gzipped responses and for fixing it!\n\n### k6/http: TLS handshaking metric (#454)\nk6 will now measure TLS handshaking time. The metric is called `http_req_tls_handshaking` and is accessible in scripts as `res.timings.tls_handshaking`.\n\nThanks to @antekresic for this PR!\n\n### k6/html: Form serialization methods (#435)\nThis feature adds some missing jQuery APIs for serializing form elements to a URL-encoded string, array or object.\n\n```js\nimport http from \"k6/http\";\n\nexport default function() {\n    let res = http.get(“https://example.com/form”);\n    let form = res.html().find('form');\n    const serialized = form.serializeObject();\n}\n```\n\nThanks to @marklagendijk for their work on this!\n\n**Docs**: [serialize()](https://docs.k6.io/v1.0/docs/selectionserialize), [serializeArray()](https://docs.k6.io/v1.0/docs/selectionserializearray) and [serializeObject()](https://docs.k6.io/v1.0/docs/selectionserializeobject)\n\n### k6/http: Form submission method (#437, #445)\nA sister feature to the one above, adding a `submitForm(...)` method to the response object for making it easier to work with HTML form submissions.\n\n```js\nimport http from \"k6/http\";\n\nexport default function() {\n    let res = http.get(“https://example.com/form”);\n    res = res.submitForm({ fields: { message: \"hello world\" });\n}\n```\n\nAgain, thanks to @marklagendijk for their work on this!\n\n**Docs**: [Response.submitForm()](https://docs.k6.io/v1.0/docs/responsesubmitform-params) and [Working with HTML forms](https://docs.k6.io/v1.0/docs/working-with-html-forms)\n\n### k6/http: Add back OPTIONS method (#451)\nUp until v0.13.0 k6 supported `CONNECT`, `OPTIONS` and `TRACE` methods, besides the more common HTTP methods. In v0.13.0 these methods were then lost in a big refactor where we switched JS engine from [Otto](github.com/robertkrimen/otto) to [goja](https://github.com/dop251/goja).\n\nThanks to @cstyan for this PR!\n\n### k6/http: Link click method (#459)\nA wrapper around the Selection API to locate an link/anchor tag in the response HTML and generate a click request. It adds a `clickLink(...)` method to the response object.\n\n```js\nimport http from \"k6/http\";\n\nexport default function() {\n    let res = http.get(\"https://httpbin.org/links/10/0\");\n    res = res.clickLink({ selector: 'a:nth-child(4)' })\n}\n```\n\nYet again, thanks to @marklagendijk for their work on this!\n\n**Docs**: [Response.clickLink()](https://docs.k6.io/v1.0/docs/responseclicklink-params)\n\n### Metrics: `iteration_duration` metric, `vu` and `iter` tags (#460)\nA new metric, `iteration_duration`, has been added to k6. It measures the time it takes to run one full iteration of the default/main function. Most builtin metrics (http, group, checks etc.) are now also automatically tagged with `vu` and `iter` tags, representing the VU and iteration number where the metric data point was collected.\n\n### CLI: Specify what stats to report for trend metrics (#462)\nA new CLI option `--summary-trend-stats avg,med,max,p(95),p(99),p(99.9)` for specifying what stats to show for trend metrics (response times) in the summary output after a test run has finished.\n\nThanks @antekresic for this contribution!\n\n### k6/http: Set default user-agent (#466)\nBy default k6 will now send a user-agent string in the following format: `k6/0.19.0 (https://k6.io/);`.\n \n## Bugs fixed!\n\n* k6/http: The val() Selection method now properly returns an empty string for input fields when the value attribute is missing. (#435, thanks @marklagendijk)\n\n* k6/http: Fixed three bugs related to cookie handling when doing redirects. (#479, thanks @marklagendijk)\n\n* Archive: Fixed JSON encoding of <, > and & characters. (#421, thanks @dstpierre)\n\n* Engine: Improved stability of some tests to decrease flakiness of CI builds.\n\n* Stats: Fixed median calculation when sample count is even (#432, thanks @tmcgannon)\n\n* Docs: Fixed typo in README (#433, thanks @tbroadley)\n\n* Docs: Fixed broken link in README (#482, thanks @jonathon-l)"
  },
  {
    "path": "release notes/v0.20.0.md",
    "content": "Lots of goodies in this release! :tada:\n\nWe are working towards a 1.0 release of k6, and as part of this release we've also published our roadmap for 2018 in the Github wiki, [here it is](https://github.com/loadimpact/k6/wiki/Roadmap). We welcome comments and discussion relating to the roadmap, both in the corresponding issues as well as in [Slack](https://k6.io/slack/).\n\nOnce again we saw contributions from several members of the community in this release, from 9 people outside of Load Impact, woop woop! A big thanks to the following people for contributing to this release: @antekresic, @cstyan, @cyberw, @danron, @dstpierre, @luizbafilho, @marklagendijk, @na-- and @pkruhlei.\n\nTwo of the above contributors have also become full time employees of Load Impact since the last release, to accelerate the development of k6. We welcome @luizbafilho and @na-- to the distributed k6 core team!\n\nTo see the current plan for the next release, check out [this milestone](https://github.com/loadimpact/k6/milestone/3).\n\n## New Features!\n\n### k6/http: Support for binary files and multipart requests (#370, #420 and #524)\nThe init context [`open()`](https://docs.k6.io/docs/open-filepath) function now supports binary files:\n\n```js\nimport http from \"k6/http\";\nimport {md5} from \"k6/crypto\";\n\nlet binFile = open(\"./image.png\", \"b\");\n\nexport default function() {\n    console.log(md5(binFile, \"hex\"));\n}\n```\n\nand the HTTP module has handily gained support for multipart requests:\n\n```js\nimport http from \"k6/http\";\n\nlet binFile = open(\"./image.png\", \"b\");\n\nexport default function() {\n    var data = {\n        field: \"this is a standard form field\",\n        file: http.file(binFile, \"my image file.png\")\n    };\n    var res = http.post(\"https://example.com/upload\", data);\n}\n```\n\nThanks @dstpierre for their work on this!\n\n**Docs**: [Multipart requests](https://docs.k6.io/v1.0/docs/multipart-requests-file-uploads)\n\n### k6/http: Request information through response object (#447)\nRequest information is now exposed through the [Response object](https://docs.k6.io/docs/response-k6http):\n\n```js\nimport http from \"k6/http\";\n\nexport default function() {\n    let res = http.get(\"https://example.com/\")\n    console.log(`Method: ${res.request.method}`);\n    new Map(Object.entries(res.request.headers)).forEach((v, k) => console.log(`Header: ${k}=${v}`));\n    console.log(`Body: ${res.request.method}`);\n}\n```\n\nThanks to @cstyan for their work on this!\n\n**Docs**: [Request information](https://docs.k6.io/v1.0/docs/response-k6http)\n\n### Lifecycle: setup/teardown functions (#457)\nFinally k6 has the same basic test lifecycle hooks as many \"normal\" testing tools, setup and teardown, and you have the full JS API of k6 available within these functions which means you can make HTTP calls etc. that you can’t do in the global/init scope.\n\nTo use the lifecycle hooks you simply define an exported setup() and/or teardown() function in your script:\n\n```js\nexport function setup() {\n\treturn { “data”: “passed to main and teardown function” };\n}\n\nexport function teardown(data)  {\n\tconsole.log(JSON.stringify(data));\n}\n\nexport default function(data) {\nif (data.v != 1) {\n\t\tthrow new Error(\"incorrect data: \" + JSON.stringify(data));\n\t}\n}\n```\n\n**Docs**: [Test life cycle](https://docs.k6.io/v1.0/docs/test-life-cycle)\n\n### CLI: HTTP debug flag (#447)\nIf you specify `--http-debug` when running a test k6 will now continuously print request and response information.\n\nThanks to @marklagendijk for their work on this!\n\n**Docs**: [HTTP debugging](https://docs.k6.io/v1.0/docs/http-debugging)\n\n\n### Options: DNS override (#494)\nOverriding DNS resolution of hostnames can come in handy when testing a system that is run in multiple environments (dev, staging, prod etc.) with different IP addresses but responds to the same `Host` header.\n\n```js\nimport http from \"k6/http\";\n\nexport let options = {\n    hosts: {\n        \"loadimpact.com\": \"1.2.3.4\",\n        \"test.loadimpact.com\": \"5.6.7.8\"\n    }\n};\n\nexport default function() {\n    http.get(\"http://loadimpact.com/\");\n    http.get(\"http://test.loadimpact.com/\");\n}\n```\n\nTip: you can use [environment variables](https://docs.k6.io/docs/environment-variables) to switch the IP based on environment.\n\nThanks @luizbafilho for their work on this!\n\n**Docs**: [DNS Override option](https://docs.k6.io/docs/options)\n\n### CLI: Add `-e` flag environment variable flag (#495)\n\nYou can now specify any number of environment variables on the command line using the `-e NAME=VALUE` flag.\n\nAs a matter of security, when running `k6 cloud ...` or `k6 archive ...` the system's environment variables will not be included in the resulting archive, you'll now have to use the new `--include-system-env-vars` flag to get that behavior. When executing `k6 run ...` the system's environment will continue to be exposed to your script.\n\nWe encourage the use of `-e NAME=VALUE` to make environment variable use explicit and compatible across local and cloud execution.\n\nThanks @na-- for their work on this!\n\n**Docs**: [Environment variables](https://docs.k6.io/v1.0/docs/environment-variables)\n\n### HAR converter: Add `--no-batch` flag (#497)\n\nA `--no-batch` CLI flag has been added to `k6 convert` command to disable the creation of batch request statements in favor of individual `http.get/del/options/patch/post/put` statements.\n\nThanks @danron and @cyberw for their work on this!\n\n\n### HAR converter: Add `--return-on-failed-check` flag (#499)\n\nA `--return-on-failed-check` CLI flag has been added to `k6 convert` command to optionally return/exit the current VU iteration if a response status code check fails (requires the existing `--enable-status-code-checks` to be specified as well).\n\nThanks @cyberw for their work on this!\n\n### HAR converter: Add `--correlate` flag (#500)\n\nA first step towards doing correlations when converting HAR to JS has implemented. In this first iteration, if `--correlate` is specified the converter will try to detect issues with redirects.\n\nThanks @cyberw for their work on this!\n\n### Stats: Use linear interpolation when calculating percentiles (#498)\n\nThe percentile calculation has been changed to use linear interpolation of two bounding values if percentile doesn't precisely fall on a value/sample index.\n\n### Thresholds: Support for aborting test early as soon as threshold is hit (#508)\n\nUp until now thresholds were evaluated continuously throughout the test but could never abort a running test.\nThis PR adds functionality to specify that a test run should abort the test as soon as a threshold evaluates to false, optionally with a delay in threshold evaluation to avoid aborting to early when the number of samples collected is low.\n\n```js\nexport let options = {\n    thresholds: {\n        \"http_req_duration\": [\"avg<100\", { threshold: \"p(95)<200\", abortOnFail: true, delayAbortEval: \"30s\" }]\n    }\n};\n```\n\nThanks @antekresic for their work on this!\n\n**Docs**: [Thresholds with abort](https://docs.k6.io/v1.0/docs/thresholds#section-aborting-a-test-when-a-threshold-is-crossed)\n\n### Docker: Use full Alpine as base image for k6 (#514)\n\nThanks @pkruhlei for their contribution!\n\n### CLI: Option to whitelist what tags should be added to metric samples (#525)\n\nAdds a CLI option `--system-tags \"url,method,status\"` to specify a whitelist of system tags that will be included in the metrics output.\n\nThe following tags can be specified:\n\n- `url` (http, websocket)\n- `method` (http)\n- `status` (http, websocket)\n- `proto` (http)\n- `subproto` (websocket)\n- `error` (http)\n- `name` (http)\n- `group` (http)\n- `check` (http)\n- `tls_version` (http)\n- `ocsp_status` (http)\n- `iter` (vu)\n- `vu` (vu)\n\nAll but the last 3 (`ocsp_status`, `iter`, `vu`) are included by default. Some collectors (e.g. `cloud`) could require that certain tags are included.\n\n**Docs**: [System tags](https://docs.k6.io/v1.0/docs/tags-and-groups#section-system-tags)\n\n### k6/http: Support for HTTP Digest Authentication (#533)\n\n```js\nimport http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function() {\n    // Passing username and password as part of URL plus the auth option will authenticate using HTTP Digest authentication\n    let res = http.get(\"http://user:passwd@httpbin.org/digest-auth/auth/user/passwd\", {auth: \"digest\"});\n\n    // Verify response\n    check(res, {\n        \"status is 200\": (r) => r.status === 200,\n        \"is authenticated\": (r) => r.json().authenticated === true,\n        \"is correct user\": (r) => r.json().user === \"user\"\n    });\n}\n```\n\n**Docs**: [HTTP Params](http://k6.readme.io/docs/params-k6http)\n\n## Bugs fixed!\n\n* HAR converter: Fixed issue with construction of `body` parameter when `PostData.Params` values are present. (#489)\n\n* Stats: Fixed output of rate metrics to truncate rather than round when converting to string representation from float for summary output.\n\n* Stats: Fixes issue where calls to `TrendSink.P()` and `TrendSink.Format()` could return wrong results if `TrendSink.Calc()` hadn't been previously called. (#498)\n\n* Cloud/Insights: Fixed issue causing default test name to be empty when parsing script from STDIN (#510)\n\n* Cloud/Insights: Fixed handling of unexpected responses from server. (#522)\n\n* Stats: Fixed issue with calculation of `data_received` and `data_sent` metrics. (#523)\n\n* WebSockets: Fixed issue that different TLS settings like `InsecureSkipTLSVerify` were ignored for websockets (#531)\n\n## Breaking changes\n\n* The `SummaryTrendStats` configuration option has been renamed to `summaryTrendStats`, to match all of the other JS option names."
  },
  {
    "path": "release notes/v0.21.0.md",
    "content": "v0.21.0 is here! :tada:\n\nWe're happy to see continued contributions from members of the community in this release, from 4 people outside of Load Impact this time around. A big thanks to the following people for contributing to this release: @antekresic, @cyberw, @danron and @jmccann. Also, thanks to everyone that contributed in other ways on Github, in Slack and for spreading the word about k6!\n\nTo see the current plan for the next release, check out [this milestone](https://github.com/loadimpact/k6/milestone/4), which we aim to make the v1.0 release!\n\nHave a look at [our roadmap](https://github.com/loadimpact/k6/wiki/Roadmap) for what's up ahead, beyond the v1.0 release.\n\n## New Features!\n\n### CLI/Options: Add `--tag` flag and `tags` option to set test-wide tags (#553)\n\nYou can now specify any number of tags on the command line using the `--tag NAME=VALUE` flag. You can also use the `tags` option to the set tags in the code.\n\nThe specified tags will be applied across all metrics. However if you have set a tag with the same name on a request, check or custom metric in the code that tag value will have precedence.\n\nThanks to @antekresic for their work on this!\n\n**Docs**: [Test wide tags](https://docs.k6.io/v1.0/docs/tags-and-groups#section-test-wide-tags) and [Options](https://docs.k6.io/v1.0/docs/options#section-available-options)\n\n### CLI/Options: Add `--summary-time-unit` flag (#638)\n\nYou can now specify the time unit used to show the summary trend stats. It can be: 's' for seconds, 'ms' for milliseconds or 'us' microseconds.\n\n```bash\n$ k6 run --summary-time-unit ms ~/script.js\n```\n\n**Docs**: [Options](https://docs.k6.io/v1.0/docs/options#section-available-options)\n\n### k6/http: Support for HTTP NTLM Authentication (#556)\n\n```js\nimport http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function() {\n    // Passing username and password as part of URL plus the auth option will authenticate using HTTP Digest authentication\n    let res = http.get(\"http://user:passwd@example.com/path\", {auth: \"ntlm\"});\n\n    // Verify response\n    check(res, {\n        \"status is 200\": (r) => r.status === 200\n    });\n}\n```\n\n**Docs**: [HTTP Params](http://k6.readme.io/docs/params-k6http)\n\n### HAR converter: Add support for correlating JSON values (#516)\n\nThere is now support for correlating JSON values in recordings, replacing recorded request values with references to the previous response.\n\nThanks to @cyberw for their work on this!\n\n### InfluxDB output: Add support for sending certain sample tags as fields (#585)\n\nSince InfluxDB indexes tags, highly variable information like `vu`, `iter` or even `url` may lead to high memory usage. The InfluxDB documentation [recommends](https://docs.influxdata.com/influxdb/v1.5/concepts/schema_and_data_layout/#encouraged-schema-design) to use fields in that case, which is what k6 does now. There is a new `INFLUXDB_TAGS_AS_FIELDS` option (`collectors.influxdb.tagsAsFields` in the global k6 JSON config) that specifies which of the tags k6 emits will be sent as fields to InfluxDB. By default that's only `url` (but not `name`), `vu` and `iter` (if enabled).\n\nThanks to @danron for their work on this!\n\n### Configurable setup and teardown timeouts (#602)\n\nPreviously the `setup()` and `teardown()` functions timed out after 10 seconds. Now that period is configurable via the `setupTimeout` and `teardownTimeout` script options or the `K6_SETUP_TIMEOUT` and `K6_TEARDOWN_TIMEOUT` environment variables. The default timeouts are still 10 seconds and at this time there are no CLI options for changing them to avoid clutter.\n\n### In-client aggregation for metrics streamed to the cloud (#600)\n\nMetrics streamed to the Load Impact cloud can be partially aggregated to reduce bandwidth usage and processing times. Outlier metrics are automatically detected and excluded from that aggregation.\n\n**Docs**: [Load Impact Insights Aggregation](https://docs.k6.io/docs/load-impact-insights#section-aggregation)\n\n### HAR converter: Set more realistic sleep time (#608)\n\nThe default sleep time added at the end of the generated test has been changed from 2-4s to 20-40s to be more realistic (although still probably on the low end for some types of sites [1][2]).\n\n[1] - https://moz.com/blog/ecommerce-benchmark-kpi-study-2017\n[2] - https://www.brafton.com/blog/strategy/brafton-2017-content-marketing-benchmark-report/\n\n### Remote IP address as an optional system metric tag (#616)\n\nIt's now possible to add the remote server's IP address to the tags for HTTP and WebSocket metrics. The `ip` [system tag](https://docs.k6.io/docs/tags-and-groups#section-system-tags) is not included by default, but it could easily be enabled by modifying the `systemTags` [option](https://docs.k6.io/docs/options).\n\n### Raw log format (#634)\nThere is a new log format called `raw`. When used, it will print only the log message without adding any debug information like, date or the log level. It should be useful for debuging scripts when printing a HTML response for example.\n\n```\n$ k6 run --log-format raw ~/script.js\n```\n\n### Option to output metrics to Apache Kafka (#617)\n\nThere is now support for outputing metrics to Apache Kafka! You can configure a Kafka broker (or multiple ones), topic and message format directly from the command line like this:\n\n`k6 --out kafka=brokers={broker1,broker2},topic=k6,format=json`\n\nThe default `format` is `json`, but you can also use the [InfluxDB line protocol](https://docs.influxdata.com/influxdb/v1.5/write_protocols/line_protocol_tutorial/) for direct ingestion by InfluxDB:\n\n`k6 --out kafka=brokers=my_broker_host,topic=k6metrics,format=influxdb`\n\nYou can even specify format options such as the [`tagsAsFields` option](#influxdb-output-add-support-for-sending-certain-sample-tags-as-fields-585) for InfluxDB:\n\n`k6 --out kafka=brokers=someBroker,topic=someTopic,format=influxdb,influxdb.tagsAsFields={url,name,myCustomTag}`\n\n**Docs**: [Apache Kafka output](https://docs.k6.io/docs/results-output#section-apache-kafka-output)\n\nThanks to @jmccann for their work on this!\n\n\n### Multiple outputs (#624)\n\nIt's now possible to simultaneously send the emitted metrics to several outputs by using the CLI `--out` flag multiple times, for example:\n`k6 run --out json=test.json --out influxdb=http://localhost:8086/k6`\n\nThanks to @jmccann for their work on this!\n\n### Cloud execution: CLI flag to exit k6 when test reaches running state  (#632)\n\nThere's now a new CLI flag `--exit-on-running` when running cloud tests (`k6 cloud ...`) to have k6 exit when the test reaches the running state.\n\n## UX\n\n* Clearer error message when using `open` function outside init context (#563)\n* Better error message when a script or module can't be found (#565). Thanks to @antekresic for their work on this!\n\n## Internals\n\n* Removed all httpbin.org usage in tests, now a local transient HTTP server is used instead (#555). Thanks to @mccutchen for the great [go-httpbin](https://github.com/mccutchen/go-httpbin) library!\n* Fixed various data races and enabled automated testing with `-race` (#564)\n\n## Bugs\n* Archive: archives generated on Windows can now run on *nix and vice versa. (#566)\n* Submetrics are being tagged properly now. (#609)\n* HTML: fixed the `Selection.each(fn)` function, which was returning only the first element. (#610)\n* Invalid Stages option won't keep k6 running indefinitely. (#615)\n* the `--no-color` option is now being repected for the logs. (#634)\n\n## Breaking changes\n* The Load Impact cloud configuration options `no_compress` and `project_id` and the `payload_size` InfluxDB option have been renamed to `noCompress`, `projectID` and `payloadSize` respectively, to match the other JS option names.\n"
  },
  {
    "path": "release notes/v0.21.1.md",
    "content": "A bug fix release to fix some issues in the v0.21.0 release.\n\n## Bugs fixed!\n\n* Multiple bugs in the HTTP request and batch handling (#642)\n* Fix negative `http_req_sending` values in the summary (#651)\n* Respect the `setup()` and `teardown()` timeouts even when triggered by the API (#661)"
  },
  {
    "path": "release notes/v0.22.0.md",
    "content": "v0.22.0 is here! :tada:\n\nWe're making an intermediary release before v1.0.0, as we wanted to get some changes out quicker. Thanks to @mohanprasaths for contributing to this release!\n\nTo see what's left for the v1.0.0 release, check out [this milestone](https://github.com/loadimpact/k6/milestone/4)!\n\nAlso, have a look at [our roadmap](https://github.com/loadimpact/k6/wiki/Roadmap) for what's up ahead, beyond the v1.0 release.\n\n## New Features!\n* New JS API to set seed for PRNG. Now, you are able to set a seed to get reproducible (pseudo-)random numbers. (#677)\n\n```js\nimport {randomSeed} from \"k6\";\n\nrandomSeed(123456789);\nlet rnd = Math.random();\nconsole.log(rnd)\n```\n\n* A new option `--no-vu-connection-reuse` lets users close HTTP `keep-alive` connections between iterations of a VU. (#676)\n* You can now set the minimum and maximum sleep time at the end of an iteration with the new `--min-sleep` and `--max-sleep` HAR coverter CLI flags. (#694)\n* Another new feature in the HAR converter enabled users to specify a JSON file with [script options](https://docs.k6.io/docs/options) that would be added to the options of the generated scripts with the new `--options` flag. (#694)\n\n\n## UX\n\n\n### Automated deb, rpm, msi and nuget package builds (#675)\n\nPreviously we only had [Homebrew releases](https://github.com/loadimpact/k6#mac) for Mac and simple archives with [plain binary releases](https://github.com/loadimpact/k6/releases) for all other platforms. From now on, we'll also automatically build installation packages for Windows and rpm or deb based Linux distributions and upload them to bintray on every new release: [https://bintray.com/loadimpact](https://bintray.com/loadimpact/)\n\nFor Debian-based Linux distributions, you have to do something like this to install k6:\n\n```sh\nsudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 379CE192D401AB61\necho \"deb https://dl.bintray.com/loadimpact/deb stable main\" | sudo tee -a /etc/apt/sources.list\nsudo apt-get update\nsudo apt-get install k6\n```\n\nAnd for rpm-based ones like Fedora and CentOS:\n\n```sh\nwget https://bintray.com/loadimpact/rpm/rpm -O bintray-loadimpact-rpm.repo\nsudo mv bintray-loadimpact-rpm.repo /etc/yum.repos.d/\nsudo yum install k6\n```\n\nFor Windows you can download and install the [latest `.msi` package](https://dl.bintray.com/loadimpact/windows/k6-latest-amd64.msi) or, if you use the [chocolatey package manager](https://chocolatey.org/), follow [these instructions](https://bintray.com/repo/buildSettings?repoPath=%2Floadimpact%2Fchoco) to set up the k6 repository.\n\n\n### Other UX improvements\n\n* There's a new option to reset the saved cloud token: `k6 login cloud --reset` (#672)\n* The check and group names in the summary at the end of a test now appear in the order they were defined. Thanks to @mohanprasaths for fixing this! (#674)\n\n## Internals\n\n### Real-time metrics (#678)\n\nPreviously most metrics were emitted only when a script iteration ended. With these changes, metrics would be continuously pushed in real-time, even in the middle of a script iteration. This should slightly decrease memory usage and help a lot with the aggregation efficiency of the cloud collector.\n\n### Portable builds (#658)\n\nBefore this, k6 builds that were done with just the standard Go language tools (i.e. `go get`, `go build`, etc.) [were not portable](https://github.com/loadimpact/k6/issues/545) because static resources like JS libraries had to be embedded in the binary after the build. Building fully portable binaries was done with the `build-release.sh` script (which used go.rice to bundle the static resources in the binary), but now that embedding is done beforehand and is committed in the git repo, so commands like `go get/build/install` produce fully-portable binary files without extra steps.\n\n## Bugs fixed!\n\n* Metrics emitted by `setup()` and `teardown()` are not discarded anymore. They are emitted and have the implicit root `group` tag values of `setup` and `teardown` respectively (#678)\n* Fixed a potential `nil` pointer error when the `k6 cloud` command is interrupted. (#682)\n\n## Breaking Changes\n* The `--no-connection-reuse` option has been re-purposed and now disables keep-alive connections globally. The newly added `--no-vu-connection-reuse` option does what was previously done by `--no-connection-reuse` - it closes any open connections between iterations of a VU, but allows for reusing them inside of a single iteration. (#676)\n"
  },
  {
    "path": "release notes/v0.22.1.md",
    "content": "A minor release that adds some UX improvements and fixes some of the issues in the v0.22.0 release.\n\n## UX\n\n* The consolidated user-supplied options (the final combination of config file options, exported script `options`, environment variables and command-line flags) are now exported back into the `options` script variable and can be accessed from the script. Thanks to @mohanprasaths for working on this! (#681 and #713)\n* Improved error messages when outputting results to or executing tests in the Load Impact cloud (#716)\n\n## Bugs fixed!\n\n* Logging: using the `--no-color` flag caused k6 to print output intended for `sdtout` to `stderr` instead. (#712)\n* Logging: some error messages originating from Go's standard library did not obey the `--logformat` option. (#712)\n* JSON output: when the standard output was used, the JSON collector closed it before k6 was finished printing the end-of-test summary to it (#715)\n* Metrics: some zero-filled metrics were emitted when scaling down the number of VUs (#710)\n"
  },
  {
    "path": "release notes/v0.23.0.md",
    "content": "v0.23.0 is here! :tada:\n\nHopefully this is the last intermediary release before v1.0.0. It is a bit light on new features, but it includes a lot of bug fixes and minor improvements! Also, the `latest` Docker tag will point to this release until we release the next stable one. Users wanting to use the bleeding edge k6 features can do that via the new `master` docker tag, which is pushed by every CI build of the git `master` branch.\n\nThanks to @sherrman, @ofauchon, @AndriiChuzhynov, @entone, @mariolopjr, and @tkbky for contributing to this release!\n\nTo see what's left for the v1.0.0 release, check out [this milestone](https://github.com/loadimpact/k6/milestone/4)!\n\nAlso, have a look at [our roadmap](https://github.com/loadimpact/k6/wiki/Roadmap) for what's up ahead, beyond the v1.0 release.\n\n## New Features!\n\n### New option: No Cookies Reset (#729)\n\nA new option has been added that disables the default behavior of resetting the [cookie jar](https://docs.k6.io/docs/cookies) after each VU iteration. If it's enabled, saved cookies will be persisted across VU iterations. For the moment there's no CLI flag for this option, instead it can only be set via the `noCookiesReset` key from the exported script `options` or via the `K6_NO_COOKIES_RESET` environment variable.\n\n### k6/http: New options to discard the response body or to specify its type (#742 and #749)\n\nYou can now specify what the type of an HTTP response's body should be with the new `responseType` request option. The possible values for it are `text` (the default), `binary` and `none`. The default `text` response type is backward-compatible, it doesn't change the current k6 behavior of returning the `body` attribute of the `http/Response` object as a string. It's well suited for working with web pages, text-based APIs and similar HTTP responses, but it can be unsuitable when dealing with binary files.\n\nThat's mostly because JavaScript strings are encoded with UTF-16 and converting binary data to it will frequently mangle some of the data. The new `binary` response type allows us to avoid that, it causes k6 to return the HTTP response's `body` as a byte array. This allows us to deal with the binary data without mangling it:\n```js\nimport http from 'k6/http';\nimport { sha256 } from 'k6/crypto';\n\nexport default function () {\n    const expectedLogoHash = \"fce7a09dde7c25b9822eca8438b7a5c397c2709e280e8e50f04d98bc8a66f4d9\";\n\n    let resp = http.get(\"http://test.loadimpact.com/images/logo.png\", { responseType: \"binary\" });\n    let logoHash = sha256(resp.body, \"hex\");\n    if (logoHash !== expectedLogoHash) {\n        throw new Error(`Expected logo hash to be ${expectedLogoHash} but it was ${logoHash}`);\n    }\n    http.post(\"https://httpbin.org/post\", resp.body);\n};\n```\n\nSaving HTTP response bodies is generally useful, especially when we need to use them (or parts of them) in subsequent requests. But in many cases it makes little to no sense to spend memory on saving the response body. For example, when requesting static website assets (JS, CSS, images etc.) or web pages without needed information, the actual file contents rarely matter when running load tests.\n\nFor cases like that, the value `none` for the `responseType` option allows k6 to discard incoming data on arrival, in order to save CPU cycles and prevent unnecessary copying of data. When enabled, the actual HTTP response body would be fully downloaded (so that the load test and all HTTP metrics for that request are still accurate), it just won't be saved in memory and passed on to the JavaScript runtime at all - the `response.body` attribute would be `null`:\n\n```js\nimport http from 'k6/http';\nimport { check } from \"k6\";\n\nexport default function () {\n    const url = \"http://test.loadimpact.com\";\n    let resp = http.get(url);\n    let cssFile = resp.html().find(\"link[rel='stylesheet']\").attr(\"href\");\n\n    check(http.get(`${url}/${cssFile}`, { responseType: \"none\" }), {\n        \"body was empty\": (res) => res.body === null,\n        \"response code was 200\": (res) => res.status == 200,\n        \"timings are present\": (res) => res.timings.duration > 0,\n    });\n};\n```\n\nFor convenience, there's also a new global config option that causes k6 to discard response bodies by default by switching the default `responseType` value to `none`. It can be enabled via the `--discard-response-bodies` CLI flag, the `K6_DISCARD_RESPONSE_BODIES` environment variable, or the `discardResponseBodies` script option:\n```js\nimport http from 'k6/http';\nexport let options = {\n  discardResponseBodies: true,\n};\nexport default function () {\n  let response = http.get(\"http://test.loadimpact.com\", { responseType: \"text\" });\n  // ... do something with the response, but ignore the contents of static files:\n  http.batch([\n    \"http://test.loadimpact.com/images/logo.png\",\n    \"http://test.loadimpact.com/style.css\"\n  ]);\n};\n```\n\nThanks to @sherrman for reporting the binary handling issues that prompted the addition of the `responseType` option! And thanks to @ofauchon for implementing both of the discard response body options, of which the local per-request one was later transformed into the `responseType=none` value!\n\n### k6/http: The `Response.json()` method now supports selectors\n\nThe selectors are implemented with the [gjson](https://github.com/tidwall/gjson#path-syntax) library and allow optimized lookups and basic filtering of JSON elements in HTTP responses, which could be especially useful in combination with k6 checks:\n\n```js\nimport http from \"k6/http\";\nimport { check } from \"k6\";\n\nexport default function () {\n\tlet resp = http.get(\"https://api.spacexdata.com/v2/launches/\");\n\n\tlet currentYear = (new Date()).getFullYear();\n\tcheck(resp, {\n\t\t\"falcon heavy\": (r) => r.json(\"#[flight_number==55].rocket.second_stage.payloads.0.payload_id\") === \"Tesla Roadster\",\n\t\t\"no failure this year\": (r) => r.json(\"#[launch_success==false]#.launch_year\").every((y) => y < currentYear),\n\t\t\"success ratio\": (r) => r.json(\"#[launch_success==true]#\").length > 10 * r.json(\"#[launch_success==false]#\").length,\n\t});\n}\n\n```\n\nThanks to @AndriiChuzhynov for implementing this! (#766)\n\n### New option: disable the summary at the end of a test (#729)\n\nA new option that disables the end-of-test summary has been added. That summary is often superfluous when k6 tests are run in a distributed execution mode, or when the generated metrics are piped to an external output like InfluxDB or Load Impact Insights. The option can be enabled with the `--no-summary` CLI flag or the `K6_NO_SUMMARY` environment variable. When both it and the and the `--no-thresholds` option are enabled, k6 won't store any generated metrics in-memory, making the test execution a bit more efficient.\n\n### New option: set a minimum iteration duration (#821)\n\nYou can now specify the minimum amount of time a single iteration should take via the new `minIterationDuration` option. It's also configurable via the `--min-iteration-duration` CLI flag and `K6_MIN_ITERATION_DURATION` environment variable. This setting only applies for full iterations, so any interrupted iterations due to ramping down of VUs from a stage or at the end of the tests can still be shorter.\n\n## UX\n\n* Added a warning when the maximum number of VUs is more than the total number of iterations (#802)\n\n## Internals\n\n* Cloud output: improved outlier metric detection for small batches. (#744)\n* Use 20 as the default values of the `batch` and `batchPerHost` options. They determine the maximum number of parallel requests (in total and per-host respectively) an `http.batch()` call will make per VU. The previous value for `batch` was 10 and for `batchPerHost` it was 0 (unlimited). We now also use their values to determine the maximum number of open idle connections in a VU. (#685)\n* Due to refactoring needed for the redirect fixes, the NTLM authentication library k6 uses is changed from [this](https://github.com/ThomsonReutersEikon/go-ntlm/) to [this](https://github.com/Azure/go-ntlmssp). (#753)\n* Switched the default CircleCI tests and linting to use Go 1.11.2, but we still maintain 1.10 compatibility by running all of the tests with Go 1.10.3 too. Official k6 standalone builds will also be done with Go 1.11+ from now on. (#813)\n* Automated docker builds of the git `master` branch will now tag the resulting docker image as `master` as well. The `latest` docker tag will point to the latest stable official release, so it will be equivalent to `v0.23.0` until we release the next k6 version. (#846)\n\n## Bugs fixed!\n\n* UI: The interactive `k6 login influxdb` command failed to write the supplied options to the config file. (#734)\n* UI: Password input is now masked in `k6 login influxdb` and `k6 login cloud`. (#734)\n* Config: Environment variables can now be used to modify k6's behavior in the `k6 login` subcommands. (#734)\n* HTTP: Binary response bodies were mangled because there was no way to avoid converting them to UTF-16 JavaScript strings. (#749)\n* Config: Stages were appended instead of overwritten from upper config \"tiers\", and were doubled when supplied via the CLI flag. (#759)\n* HAR converter: Fixed a panic due to a missing array length check. (#760)\n* HTTP: `http.batch()` calls could panic because of a data race when the `batchPerHost` global option was used. (#770)\n* Docker: Fixed the grafana image in the docker-compose setup. Thanks @entone and @mariolopjr! (#783)\n* Config: Stages configured via the script `options` or environment variables couldn't be disabled via the CLI flags. (#786)\n* UI: Don't report infinities and extreme speeds when tests take 0 time. Thanks @tkbky! (#790)\n* HTTP: Correct metric tracking when HTTP requests are redirected. (#753)\n* HAR converter: Added escaping for page IDs and names in the generated scripts. (#801)\n* Setup data: Distinguish between `undefined` (when there is no `setup()` function or when it doesn't return anything) and `null` (when `setup()` explicitly returns `null`) values for the setup `data` that's passed to the default function and `teardown()`. (#799)\n* Setup data: Prevent data races by having each VU have its own independent copy of the setup data. (#799)\n* HAR converter: Support HAR files that don't have a `pages` array. (#806)\n* Setup data: The property names of some of the internal k6 objects like `http.Response` weren't properly encoded when they were returned from the `setup()` function. (#804)\n* UX: Instead of panicking on some operations in the init context, we now return an error that the given action is not supported; this includes making HTTP requests (batched or not), websockets, adding to custom metrics, making checks and groups, or initializing cookie jars. (#811)\n* Cloud execution: properly send specific environment variables to the cloud option validation endpoint when running `k6 cloud`. Most notably this includes K6_CLOUD_PROJECT_ID. (#829)\n* Cloud execution and archive running: Fixed an issue when files were imported or opened with their full paths and they were in the users' home folders. (#823)\n* Script: Fixed a panic when `group()` is called without a callback function. (#841)\n\n## Breaking changes\n* Metric names are now restricted to only allow Unicode letters or numbers, spaces, and the following special characters: `._!?/&#()<>%-`. They also need to be between 1 and 128 characters. Previously practically anything was a valid metric name. (#810)\n"
  },
  {
    "path": "release notes/v0.23.1.md",
    "content": "A minor release that fixes some of the issues in the v0.23.0 release.\n\n## Bugs fixed!\n\n* Cloud: Fixed the interaction between the environment variable and JSON-based configuration, and the Load Impact specific `env.loadimpact` JS options. Now only the `projectID`, `name` and `token` fields will be populated (without overriding other fields) when executing scripts with `k6 cloud`, and taken into account when sending metrics to Load Impact Insights with `k6 run -o cloud`. (#848, #871, #872)\n* JS: Fixed a Babel transformation issue that caused closing brackets to sometimes be commented out. (#853)\n* JS: Fixed environment variable propagation when executing script bundles. (#853)\n* HAR converter: Fixed a panic due to a missing nil check. (#861)\n* Cloud: Limit the amount of samples that k6 sends in a single package to the ingest by splitting them up. (#860)\n* Metrics: Fix the incorrect tracing of some corner case HTTP requests that resulted in negative or hugely positive metric values. (#862)\n"
  },
  {
    "path": "release notes/v0.24.0.md",
    "content": "v0.24.0 is here! :tada:\n\nAnother intermediary release that was mostly focused on refactoring and bugfixes, but also has quite a few new features, including the ability to output metrics to StatsD and Datadog!\n\nThanks to @cheesedosa, @ivoreis, @bookmoons, and @oboukili for contributing to this release!\n\n## New Features!\n\n### Redirect `console` messages to a file (#833)\n\nYou can now specify a file to which all things logged by `console.log()` and other `console` methods will get written to. The CLI flag to specify the output file path is `--console-output`, and you can also do it via the `K6_CONSOLE_OUTPUT` environment variable. For security reasons, there's no way to configure this from inside of the script.\n\nThanks to @cheesedosa for both proposing and implementing this!\n\n### New result outputs: StatsD and Datadog (#915)\n\nYou can now output any metrics k6 collects to StatsD or Datadog by running `k6 run --out statsd script.js` or `k6 run --out datadog script.js` respectively. Both are very similar, but Datadog has a concept of metric tags, the key-value metadata pairs that will allow you to distinguish between requests for different URLs, response statuses, different groups, etc.\n\nSome details:\n- By default both outputs send metrics to a local agent listening on `localhost:8125` (currently only UDP is supported as a transport). You can change this address via the `K6_DATADOG_ADDR` or `K6_STATSD_ADDR` environment variables, by setting their values in the format of `address:port`.\n- The new outputs also support adding a `namespace` - a prefix before all the metric names. You can set it via the `K6_DATADOG_NAMESPACE` or `K6_STATSD_NAMESPACE` environment variables respectively. Its default value is `k6.` - notice the dot at the end.\n- You can configure how often data batches are sent via the  `K6_STATSD_PUSH_INTERVAL` / `K6_DATADOG_PUSH_INTEVAL` environment variables. The default value is `1s`.\n- Another performance tweak can be done by changing the default buffer size of 20 through `K6_STATSD_BUFFER_SIZE` / `K6_DATADOG_BUFFER_SIZE`.\n- In the case of Datadog, there is an additional configuration `K6_DATADOG_TAG_BLACKLIST`, which by default is equal to `` (nothing). This is a comma separated list of tags that should *NOT* be sent to Datadog. All other metric tags that k6 emits will be sent.\n\nThanks to @ivoreis for their work on this!\n\n### k6/crypto: random bytes method (#922)\nThis feature adds a method to return an array with a number of cryptographically random bytes. It will either return exactly the amount of bytes requested or will throw an exception if something went wrong.\n\n```js\nimport crypto from \"k6/crypto\";\n\nexport default function() {\n    var bytes = crypto.randomBytes(42);\n}\n```\n\nThanks to @bookmoons for their work on this!\n\n### k6/crypto: add a `binary` output encoding to the crypto functions (#952)\n\nBesides `hex` and `base64`, you can now also use `binary` as the encoding parameter for the [k6 crypto](https://docs.k6.io/docs/k6crypto) hashing and HMAC functions.\n\n### New feature: unified error codes (#907)\n\nError codes are unique numbers that can be used to identify and handle different application and network errors more easily. For the moment, these error codes are applicable only for errors that happen during HTTP requests, but they will be reused and extended to support other protocols in future k6 releases.\n\nWhen an error occurs, its code is determined and returned as both the `error_code` field of the [`http.Response`](https://docs.k6.io/docs/response-k6http) object, and also attached as the `error_code` [tag](https://docs.k6.io/docs/tags-and-groups#section-system-tags) to any [metrics](https://docs.k6.io/docs/result-metrics#section-http-specific-built-in-metrics) associated with that request. Additionally, for more details, the `error` metric tag and `http.Response` field will still contain the actual string error message.\n\nError codes for different errors are as distinct as possible, but for easier handling and grouping, codes in different error categories are also grouped in broad ranges. The current error code ranges are:\n\n- 1000-1099 - General errors\n- 1100-1199 - DNS errors\n- 1200-1299 - TCP errors\n- 1300-1399 - TLS errors\n- 1400-1499 - HTTP 4xx errors\n- 1500-1599 - HTTP 5xx errors\n- 1600-1699 - HTTP/2 specific errors\n\nFor a list of all current error codes, see the docs page [here](https://docs.k6.io/docs/error-codes).\n\n## Internals\n\n- Improvements in the integration with [loadimpact.com](https://loadimpact.com/). (#910 and #934)\n- Most of the HTTP request code has been refactored out of the `js` packages and is now independent from the goja JS runtime. This was done mostly so we can implement the error codes feature (#907), but will allow us more flexibility in the future. (#928)\n- As a preparation for the upcoming big refactoring of how VUs are scheduled in k6, including the arrival-rate based execution, we've added the future `execution` configuration framework. It currently doesn't do anything besides warn users that use execution option combinations that won't be supported in future k6 versions. See the Breaking Changes section in these release notes for more information. (#913)\n- Switched to [golangci-lint](https://github.com/golangci/golangci-lint) via [golangci.com](https://golangci.com/) for code linting in this repo. The gometalinter check in CircleCI is still enabled as well, but it will be removed in the following few weeks. (#943)\n- Switched to Go 1.12.1 for building and testing k6, removed official support for 1.10. (#944 and #966)\n\n## Bugs fixed!\n\n* JS: Consistently report setup/teardown timeouts as such and switch the error message to be more expressive. (#890)\n* JS: Correctly exit with non zero exit code when setup or teardown timeouts. (#892)\n* Thresholds: When outputting metrics to [loadimpact.com](https://loadimpact.com/), fix the incorrect reporting of threshold statuses at the end of the test. (#894)\n- UX: `--quiet`/`-q` doesn't hide the summary stats at the end of the test. When necessary, they can still be hidden via the explicit `--no-summary` flag. Thanks, @oboukili! (#937)\n\n## Breaking changes\n\nNone in this release, but in preparation for the next one, some execution option combinations will emit warnings, since they will no longer be supported in future k6 releases. Specifically, you won't be able to simultaneously run k6 with `stages` and `duration` set, or with `iterations` and `stages`, or with `duration` and `iterations`, or with all three. These VU schedulers (and much more, including arrival-rate based ones!) will still be supported in future k6 releases. They will just be independent from each other, unlike their current implementation where there's one scheduler with 3 different conflicting constraints."
  },
  {
    "path": "release notes/v0.25.0.md",
    "content": "k6 v0.25.0 is here! :tada:\n\nThis release contains mostly bug fixes, though it also has a few new features, enhancements, and performance improvements. These include HTTP request compression, `brotli` and `zstd` support, massive VU RAM usage and initialization time decreases, support for importing files via `https` and `file` URLs, and opt-in TLS 1.3 support.\n\nThanks to @THoelzel, @matlockx, @bookmoons, @cuonglm, and @imiric for contributing to this release!\n\n## New features and enhancements!\n\n### HTTP: request body compression + brotli and zstd decompression (#989, #1082)\n\nNow k6 can compress the body of any HTTP request before sending it (#989). That can be enabled by setting the new `compression` option in the [`http.Params` object](https://docs.k6.io/docs/params-k6http). Doing so will cause k6 to transparently compress the supplied request body and correctly set both `Content-Encoding` and `Content-Length`, unless they were manually set in the request `headers` by the user. The currently supported algorithms are `deflate`, `gzip`, `brotli` and `zstd`, as well as any combination of them separated by commas (`,`).\n\nk6 now also transparently decompresses `brotli` and `zstd` HTTP responses - previously only `deflate` and `gzip` were supported. Thanks, @imiric! (#1082)\n\n```js\nimport http from 'k6/http';\nimport { check } from \"k6\";\n\nexport default function () {\n    // Test gzip compression\n    let gzippedReqResp = http.post(\"https://httpbin.org/post\", \"foobar\".repeat(1000), { compression: \"gzip\" });\n    check(gzippedReqResp, {\n        \"request gzip content-encoding\": (r) => r.json().headers[\"Content-Encoding\"] === \"gzip\",\n        \"actually compressed body\": (r) => r.json().data.length < 200,\n    });\n\n    // Test br decompression\n    let brotliResp = http.get(\"https://httpbin.org/brotli\", {\n        headers: {\n            \"Accept-Encoding\": \"gzip, deflate, br\"\n        },\n    });\n    check(brotliResp, {\n        \"br content-encoding header\": (r) => r.headers[\"Content-Encoding\"] === \"br\",\n        \"br confirmed in body\": (r) => r.json().brotli === true,\n    });\n\n    // Test zstd decompression\n    let zstdResp = http.get(\"https://facebook.com/\", {\n        headers: {\n            \"Accept-Encoding\": \"zstd\"\n        },\n    });\n    check(zstdResp, {\n        \"zstd content-encoding header\": (r) => r.headers[\"Content-Encoding\"] === \"zstd\",\n        \"readable HTML in body\": (r) => r.body.includes(\"html\"),\n    });\n};\n```\n\n### Performance improvement: reuse the parsed core-js library across VUs (#1038)\n\nk6 uses the awesome [core-js](https://github.com/zloirock/core-js) library to support new JavaScript features. It is included as a polyfill in each VU (i.e. JS runtime) and previously, it was parsed anew for every VU initialization. Now, the parsing result is cached after the first time and shared between VUs, leading to over **2x reduction of VU memory usage and initialization times** for simple scripts!\n\nThanks, @matlockx, for noticing this opportunity for massive optimization!\n\n### JS files can now be imported via `https` and `file` URLs (#1059)\n\nPreviously, k6 had a mechanism for importing files via HTTPS URLs, but required that the used URLs not contain the `https` scheme. As a move to align k6 more closely with the rest of the JS ecosystem, we now allow and encourage users to use full URLs with a scheme (e.g. `import fromurlencoded from \"https://jslib.k6.io/form-urlencoded/3.0.0/index.js\"`) when they want to load remote files. `file` URLs are also supported as another way to load local modules (normal absolute and relative file paths still work) from the local system, which may be especially useful for Windows scripts.\n\nThe old way of importing remote scripts from scheme-less URLs is still supported, though except for the GitHub and cdnjs shortcut loaders, it is in the process of deprecation and will result in a warning.\n\n### Opt-in support for TLS 1.3 and more TLS ciphers (#1084)\n\nFollowing its opt-in support in Go 1.12, you can now choose to enable support for TLS 1.3 in your k6 scripts. It won't be used by default, but you can enable it by setting the `tlsVersion` (or it's `max` sub-option) to `tls1.3`:\n\n```js\nimport http from 'k6/http';\nimport { check } from \"k6\";\n\nexport let options = {\n    tlsVersion: {\n        min: \"tls1.2\",\n        max: \"tls1.3\",\n    }\n};\n\nexport default function () {\n    let resp = http.get(\"https://www.howsmyssl.com/a/check\");\n    check(resp, {\n        \"status is 200\": (resp) => resp.status === 200,\n        \"tls 1.3\": (resp) => resp.json().tls_version === \"TLS 1.3\",\n    });\n};\n```\n\nAlso, all [cipher suites supported by Go](https://golang.org/pkg/crypto/tls/#pkg-constants) 1.12 are now supported by k6 as well. Thanks, @cuonglm!\n\n## Bugs fixed!\n\n* JS: Many fixes for `open()`: (#965)\n  - don't panic with an empty filename (`\"\"`)\n  - don't make HTTP requests (#963)\n  - correctly open simple filenames like `\"file.json\"` and paths such as `\"relative/path/to.txt\"` as relative (to the current working directory) paths; previously they had to start with a dot (i.e. `\"./relative/path/to.txt\"`) for that to happen\n  - windows: work with paths starting with `/` or `\\` as absolute from the current drive\n\n* HTTP: Correctly always set `response.url` to be the URL that was ultimately fetched (i.e. after any potential redirects), even if there were non http errors. (#990)\n* HTTP: Correctly detect connection refused errors on dial. (#998)\n* JS: Run imports once per VU. (#975, #1040)\n* Config: Fix blacklistIPs JS configuration. Thanks, @THoelzel! (#1004)\n* HTTP: Fix a bunch of HTTP measurement and handling issues (#1047)\n  - the `http_req_receiving` metric was measured incorrectly (#1041)\n  - binary response bodies could get mangled in an `http.batch()` call (#1044)\n  - timed out requests could produce wrong metrics (#925)\n* JS: Many fixes for importing files and for URL imports in archives. (#1059)\n* Config: Stop saving and ignore the derived `execution` values, which were wrongly saved in archive bundles' `metadata.json` by k6 v0.24.0. (#1057, #1076)\n* Config: Fix handling of commas in environment variable values specified as CLI flags. (#1077)\n\n## Internals\n\n* CI: removed the gometalinter check in CircleCI, since that project [was deprecated](https://github.com/alecthomas/gometalinter/issues/590) and now exclusively rely on [golangci-lint](https://github.com/golangci/golangci-lint). (#1039)\n* Archive bundles: The support for URL imports included a lot of refactoring and internal k6 changes. This included significant changes in the structure of `.tar` archive bundles. k6 v0.25.0 is backwards compatible and can execute bundles generated by older k6 versions, but the reverse is not true. (#1059)\n* Archive bundles: The k6 version and the operating system are now saved in the archive bundles' `metadata.json` file. (#1057, #1059)\n\n## Breaking changes\n\n* Previously, the `Content-Length` header value was always automatically set by k6 - if the header value was manually specified by the user, it would have been ignored and silently overwritten. Now, k6 would set the `Content-Length` value only if it wasn't already set by the user. (#989, #1094)\n"
  },
  {
    "path": "release notes/v0.25.1.md",
    "content": "A minor release that fixes some of the issues in the v0.25.0 release.\n\n## Bugs fixed!\n\n* Config: Properly handle the `systemTags` JS/JSON option and the `K6_SYSTEM_TAGS` environment variable. Thanks, @cuonglm! (#1092)\n* HTTP: Fix how request bodies are internally specified so we can properly handle redirects and can retry some HTTP/2 requests. (#1093)\n* HTTP: Fix the handling of response decoding errors and slightly improve the `digest` auth and `--http-debug` code. (#1102)\n* HTTP: Always set the correct `Content-Length` header for all requests. (#1106)\n* JS: Fix a panic when executing archive bundles for scripts with unsuccessful `import` / `require()` calls. (#1097)\n* JS: Fix some issues related to the handling of `exports` corner cases. (#1099)"
  },
  {
    "path": "release notes/v0.26.0.md",
    "content": "k6 v0.26.0 is here! :tada:\n\nThis release contains mostly bug fixes, though it also has several new features and enhancements! They include a new JS compatibility mode option, exporting the end-of-test summary to a JSON report file, speedups to the InfluxDB and JSON outputs, `http.batch()` improvements, a brand new CSV output, multiple layered HTTP response body decompression, being able to use `console` in the init context, a new optional column in the summary, and Docker improvements!\n\n\nThanks to  @Sirozha1337, @openmohan, @MMartyn, @KajdeMunter, @dmitrytokarev and @dimatock for contributing to this release!\n\n## New features and enhancements!\n\n### A new JavaScript compatibility mode option (#1206)\n\nThis adds a way to disable the automatic script transformation by [Babel](https://babeljs.io/) (v6.4.2) and loading of [core-js (v2)](https://github.com/zloirock/core-js) polyfills, bundled in k6. With the new `base` compatibility mode, k6 will instead rely only on the [goja](https://github.com/dop251/goja/) runtime and what is built into k6.\nThis can be configured through the new `--compatibility-mode` CLI flag and the `K6_COMPATIBILITY_MODE` environment variable. The possible values currently are:\n\n- `extended`: this is the default and current compatibility mode, which uses Babel and core.js to achieve ES6+ compatibility.\n- `base`: an optional mode that disables loading of Babel and core.js, running scripts with only goja's native ES5.1+ compatibility. If the test scripts don't require ES6 compatibility (e.g. they were previously transformed by Babel), this option can be used to reduce RAM usage during test runs.\n\nMore info what this means can be found in the [documentation](https://docs.k6.io/docs/javascript-compatibility-mode).\n\nOur benchmarks show a considerable drop in memory usage - around 80% for simple scripts, and around 50% in the case of 2MB script with a lot of static data in it. The CPU usage is mostly unchanged, except that k6 initializes test runs a lot faster. All of those benefits will be most noticeable if k6 is used with big number of VUs (1k+). More performance comparisons can be found in #1167.\n\n### JSON export of the end-of-test summary report (#1168)\n\nThis returns (from the very early days of k6) the ability to output the data from the end of test summary in a machine-readable JSON file.\nThis report can be enabled by the `--summary-export <file_path>` CLI flag or the `K6_SUMMARY_EXPORT` environment variable. The resulting JSON file will include data for all test metrics, checks and thresholds.\n\n### New CSV output (#1067)\n\nThere is an entirely new `csv` output that can be enabled by using the `--out csv` CLI flag. There are two things that can be configured: the output file with `K6_CSV_FILENAME` (by default it's `file.csv`), and the interval of pushing metrics to disk, which is configured with `K6_CSV_SAVE_INTERVAL` (1 second by default). Both of those can be configured by the CLI as well: `--out csv=somefile.csv` will output to `somefile.csv` and `--out csv=file_name=somefile.csv,save_interval=2s` will output again to `somefile.csv`, but will flush the data every 2 seconds instead of every second.\n\nThe first line of the output is the names of columns and looks like:\n```\nmetric_name,timestamp,metric_value,check,error,error_code,group,method,name,proto,status,subproto,tls_version,url,extra_tags\nhttp_reqs,1573131887,1.000000,,,,,GET,http://httpbin.org/,HTTP/1.1,200,,,http://httpbin.org/,\nhttp_req_duration,1573131887,116.774321,,,,,GET,http://httpbin.org/,HTTP/1.1,200,,,http://httpbin.org/,\nhttp_req_blocked,1573131887,148.691247,,,,,GET,http://httpbin.org/,HTTP/1.1,200,,,http://httpbin.org/,\nhttp_req_connecting,1573131887,112.593448,,,,,GET,http://httpbin.org/,HTTP/1.1,200,,,http://httpbin.org/,\n```\n\nAll thanks to @Sirozha1337!\n\n\n### JSON output optimizations (#1114)\n\nThe JSON output no longer blocks the goroutine sending samples to the file, but instead (like all other outputs) buffers the samples and writes them at regular intervals (100ms and is currently not configurable). It also uses a slightly faster way of encoding the data, which should decrease the memory usage by a small amount.\n\nAnother improvement is the ability to compress the generated JSON file by simply adding `.gz` to the end of the file name. Compressed files are typically 30x smaller.\n\n### InfluxDB output improvements (#1113)\n\nThe InfluxDB output has been updated to use less memory and try to send smaller and consistent chunks of data to InfluxDB, in order to not drop packets and be more efficient. This is primarily done by sending data in parallel, as this seems to be better from a performance perspective, and more importantly, queuing data in separate packets, so that we don't send the data for a big time period all at once. Also, the used library was updated, which also decreased the memory usage.\n\nTwo new options were added:\n- `K6_INFLUXDB_PUSH_INTERVAL` - configures at what interval the collected data is queued to be sent to InfluxDB. By default this is \"1s\".\n- `K6_INFLUXDB_CONCURRENT_WRITES` - configures the number of concurrent write calls to InfluxDB. If this limit is reached the next writes will be queued and made when a slot is freed. By default this is 10.\n\n### `console` is now available in the init context (#982):\n\nThis wasn't supported for the longest time, which made debugging things outside of VU code much harder, but now it's here! :tada:\n\nIn order to get this feature shipped in a timely manner, it currently has a known bug. The output of `console` calls in the init context will always be written to the `stderr`, even if the `--console-output` option is specified. This bug is tracked in https://github.com/loadimpact/k6/issues/1131\n\n### HTTP response body decompression with multiple layered algorithms (#1125)\n\nIn v0.25.0 compressing bodies was added and it had support for multiple layered algorithms. Now this is also true for decompressing bodies when k6 gets them as responses.\n\n\n### New optional `count` column in the end-of-test summary (#1143)\n\nThe `--summary-trend-stats` now also recognizes `count` as a valid column and will output the count of samples in all `Trend` metrics. This could be especially useful for custom `Trend` metrics, since with them you no longer need to specify a separate accompanying `Counter` metric.\n\n### Docker Compose refactor (#1183)\n\nThe example docker-compose that enabled easy running of InfluxDB+Grafana+k6 was refactored and all the images were updated to use the latest stable versions.\n\nThanks, @KajdeMunter!\n\nAlso the k6 `Dockerfile` Alpine version was bumped to 3.10. Thanks @dmitrytokarev!\n\n### `http.batch()` improvements and optimizations (#1259)\n\nWe made several small improvements to the mechanism for executing multiple HTTP requests simultaneously from a single VU:\n- Calling `http.batch()` should now be more efficient, especially for many requests, because of reduced locking, type conversions, and goroutine spawning.\n- The default value for `batchPerHost` has been reduced from `0` (unlimited) to `6`, to more closely match browser behavior. The default value for the `batch` option remains unchanged at `20`.\n- Calling `http.batch(arg)`, where `arg` is an array, would now return an array. Previously, this would have returned an object with integer keys, as explained in [#767](https://github.com/loadimpact/k6/issues/767)... Now `http.batch()` will return an array when you pass it an array, and return an object when you pass an object.\n\n## UX\n\n* Better timeout messages for `setup` and `teardown` timeouts, including hints on how to fix them. (#1173)\n* When a folder is passed to `open()`, the resulting error message will now include the path to the specified folder. (#1238)\n* The `k6 version` output will now include more information - the git commit it was built from (in most cases), as well as the used Go version and architecture. (#1235)\n\n## Bugs fixed!\n* Cloud: Stop sending metrics to the cloud output when the cloud returns that you have reached the limit. (#1130)\n* JS: Fail a `check` if an uncaught error is thrown inside of it. (#1137)\n* HTTP: Replace any user credentials in the metric sample tags with `*` when emitting HTTP metrics. (#1132)\n* WS: Many fixes:\n  - return an error instead of panicking if an error occurs during the making of the WebSocket connection (#1127)\n  - calling the `error` handler on an error when closing the WebSocket, instead of calling with a null (#1118)\n  - correctly handle server initiated close (#1186)\n* JSON: Better error messages when parsing JSON fails. Now telling you at which line and row the error is instead of just the offset. Thanks, @openmohan! (#905)\n* HTTP: Use Request's `GetBody` in order to be able to get the body multiple times for a single request as needed in 308 redirects of posts and if the server sends GOAWAY with no error. (#1093)\n* JS: Don't export internal go struct fields of script options.(#1151)\n* JS: Ignore `minIterationDuration` for `setup` and `teardown`. (#1175)\n* HTTP: Return error on any request that returns 101 status code as k6 currently doesn't support any protocol upgrade behavior. (#1172)\n* HTTP: Correctly capture TCP reset by peer and broken pipe errors and give them the appropriate `error_code` metric tag values. (#1164)\n* Config: Don't interpret non-`K6_` prefixed environment variables as k6 configuration, most notably `DURATION` and `ITERATIONS`. (#1215)\n* JS/html: `Selection.map` was not wrapping the nodes it was outputting, which lead to wrongly using the internal `Goquery.Selection` instead of k6's `Selection`. Thanks to @MMartyn for reporting this! (#1198)\n* HTTP: When there are redirects, k6 will now correctly set the cookie for the current URL, instead of for the one the current response is redirecting to. Thanks @dimatock! (#1201)\n* Cloud: Add token to make calls to the cloud API idempotent. (#1208)\n* Cloud: Improve aggregation of HTTP metrics for requests to different URLs, but with the same explicitly set `name` tag. (#1220)\n* Cloud: Fix a bug where you weren't able to run a script, outputting to cloud, if it was using the shortcut URLs for github/cdnjs. (#1237)\n* Config: The previous default value for `batchPerHost` of `20` wasn't propagated properly and was instead `0`. (#1264)\n\n\n## Internals\n\n* CI: Stop using external service for testing WebSockets (#1138) and remove the last use of the external `httpbin.org`. (#1213)\n* Switched to Go 1.13.5 for building and testing k6, removed official support for 1.11.\n* CI: Fix a test on MacOS. (#1142)\n* CI: Fixing flaky tests. (#1149, #1223)\n* Drop an external dependency for getting user's `configdir`. (#1162)\n* Use bitmask for checking whether system tags are enabled, adding some small speedup where this is required. (#1148)\n* Update `envconfig` as it was very old and the newer versions had fixes and features we want. (#1214)\n* Metrics: Emit iterations as part of `netext.NetTrail`, instead of as a standalone one. Also cutting down on amount of bytes we sent to the cloud output. (#1203)\n* JS: goja has been updated to the latest `master` version (commit [`007eef3`](https://github.com/dop251/goja/commit/007eef3bc40fd33b3dbb80ec16da59e8b63b8572)) (#1259)\n* All official binary packages now are built with `-trimpath` and `CGO_ENABLED=0`. Previously the GitHub release assets were built with `CGO_ENABLED=0`, making them unsuitable for non-glibc systems (like Alpine Linux). (#1244, #1245)\n\n\n## Breaking changes\n\n- The output of `k6 version` is different. It now contains not only the k6 version number, but also information about the git commit, build date, Go version and system architecture. For example, if previously the output of `k6 version` looked like `k6 v0.25.1`, now it is like this: `k6 v0.26.0 (2019-12-16T10:58:59+0000/v0.26.0-0-gaeec9a7f, go1.13.5, linux/amd64)`. (#1235)\n\n- We had to make a few minor breaking changes in the course of improving `http.batch()` (#1259):\n  - The default value for `batchPerHost` has been reduced from `0` (unlimited) to `6`, to more closely match browser behavior. The default value for the `batch` option remains unchanged at `20`.\n  - Calling `http.batch(arg)`, where `arg` is an array, would now return an array. Previously, this would have returned an object with integer keys, as explained in [#767](https://github.com/loadimpact/k6/issues/767)... Now `http.batch()` will return an array when you pass it an array, and return an object when you pass an object.\n"
  },
  {
    "path": "release notes/v0.26.1.md",
    "content": "k6 v0.26.1 is here! This is a minor release that supports the rebranding of LoadImpact to k6, the new [k6.io website](https://k6.io/), and the new [k6 cloud service](https://k6.io/cloud)! :tada:\n\nIn practical terms, all that it means for k6 is that the URLs for cloud tests will point to https://app.k6.io, instead of https://app.loadimpact.com. The old URLs (and old k6 versions) will still continue to work - for the next 3 months the old app and the new one would work in parallel, and after that period the old app will redirect to the new one. Nothing changes in regards to the k6 open source project and our commitment to it!\n\nYou can find more information about the rebranding in our blog post about it: https://k6.io/blog/load-impact-rebranding-to-k6\n\n# Changes in this release compared to v0.26.0:\n\n* Fix how HTTP request timeouts are specified internally. This is not a bug in current k6 releases, it only affects k6 if it is compiled with Go 1.14, which at this time is still not officially released. (#1261)\n* Improve the official docker image to use an unprivileged user. Thanks, @funkypenguin! (#1314)\n* Fix the unintentional sharing of `__ENV` between VUs, which could result in data races and crashes of k6. (#1329)\n* Update cloud URLs to point to https://app.k6.io instead of https://app.loadimpact.com. (#1335)"
  },
  {
    "path": "release notes/v0.26.2.md",
    "content": "k6 v0.26.2 is a minor release that updates the used Go version for the Windows builds to Go 1.13.8. Due to an oversight, previous v0.26 k6 builds for Windows used an old Go version, while builds of other OSes used the correct one. This is meant to address an issue in the Go net/http package: https://github.com/golang/go/issues/34285 .\n\nThere are no functional changes compared to v0.26.1.\n"
  },
  {
    "path": "release notes/v0.27.0.md",
    "content": "k6 v0.27.0 is here! :tada:\n\nThis is a milestone release containing a major overhaul to the execution subsystem of k6, along with many improvements and bug fixes.\n\n## New features and enhancements!\n\n### New execution engine ([#1007](https://github.com/loadimpact/k6/pull/1007))\n\nAfter 1.5 years in the making, the k6 team is proud to release the first public version of the new execution engine, offering users new ways of modeling advanced load testing scenarios that can more closely represent real-world traffic patterns.\n\nThese new scenarios are entirely optional, and the vast majority of existing k6 scripts and options should continue to work the same as before. There are several minor [breaking changes](#breaking-changes) and fixes of previously undefined behavior, but please [create a new issue](https://github.com/loadimpact/k6/issues/new?labels=bug&template=bug_report.md) if you find some issue we haven't explicitly noted as a breaking change.\n\nSee the [documentation](https://k6.io/docs/using-k6/scenarios) for details and examples, or keep reading for the summary.\n\n#### New executors\n\nSome of the currently possible script execution patterns were formalized into standalone executors:\n\n- `shared-iterations`: a fixed number of iterations are \"shared\" by all VUs, and the test ends once all iterations are executed. This executor is equivalent to the global `vus` and `iterations` (plus optional `duration`) options.\n- `constant-vus`: a fixed number of VUs execute as many iterations as possible for a specified amount of time. This executor is equivalent to the global `vus` and `duration` options.\n- `ramping-vus`: a variable number of VUs execute as many iterations as possible for a specified amount of time. This executor is equivalent to the global `stages` option.\n- `externally-controlled`: control and scale execution at runtime via k6's REST API or the CLI.\n\nYou'd still be able to use the global `vus`, `iterations`, `duration`, and `stages` options, they are not deprecated! They are just transparently converted to one of the above executors underneath the hood. And if your test run needs just a single, simple scenario, you may never need to use more than these shortcut options. For more complicated use cases however, you can now fine-tune any of these executors with additional options, and use multiple different executors in the same test run, via the new `scenarios` option, described below.\n\nAdditionally, besides the 4 \"old\" executor types, there are 3 new executors, added to support some of the most frequently requested load testing scenarios that were previously difficult or impossible to model in k6:\n\n- `per-vu-iterations`: each VU executes a fixed number of iterations ([#381](https://github.com/loadimpact/k6/issues/381)).\n- `constant-arrival-rate`: iterations are started at a specified fixed rate, for a specified duration. This allows k6 to dynamically change the amount of active VUs during a test run, to achieve the specified amount of iterations per period. This can be very useful for a more accurate representation of RPS (requests per second), for example. See [#550](https://github.com/loadimpact/k6/issues/550) for details.\n- `ramping-arrival-rate`: a variable number of iterations are executed in a specified period of time. This is similar to the ramping VUs executor, but instead of specifying how many VUs should loop through the script at any given point in time, the iterations per second k6 should execute at that point in time can be specified.\n\nIt's important to also note that all of these executors, except the `externally-controlled` one, can be used both in local k6 execution with `k6 run`, and in the distributed cloud execution with `k6 cloud`. This even includes \"old\" executors that were previously unavailable in the cloud, like the `shared-iterations` one. Now, you can execute something like `k6 cloud --iterations 10000 --vus 100 script.js` without any issues.\n\n#### Execution scenarios and executor options\n\nMultiple execution scenarios can now be configured in a single test run via the new `scenarios` option. These scenarios can run both sequentially and in parallel, and can independently execute different script functions, have different executor types and execution options, and have custom environment variables and metrics tags.\n\nAn example using 3 scenarios:\n\n```js\nimport http from 'k6/http';\nimport { sleep } from 'k6';\n\nexport let options = {\n    scenarios: {\n        my_web_test: { // some arbitrary scenario name\n            executor: 'constant-vus',\n            vus: 50,\n            duration: '5m',\n            gracefulStop: '0s', // do not wait for iterations to finish in the end\n            tags: { test_type: 'website' }, // extra tags for the metrics generated by this scenario\n            exec: 'webtest', // the function this scenario will execute\n        },\n        my_api_test_1: {\n            executor: 'constant-arrival-rate',\n            rate: 90, timeUnit: '1m', // 90 iterations per minute, i.e. 1.5 RPS\n            duration: '5m',\n            preAllocatedVUs: 10, // the size of the VU (i.e. worker) pool for this scenario\n            maxVUs: 10, // we don't want to allocate more VUs mid-test in this scenario\n\n            tags: { test_type: 'api' }, // different extra metric tags for this scenario\n            env: { MY_CROC_ID: '1' }, // and we can specify extra environment variables as well!\n            exec: 'apitest', // this scenario is executing different code than the one above!\n        },\n        my_api_test_2: {\n            executor: 'ramping-arrival-rate',\n            startTime: '30s', // the ramping API test starts a little later\n            startRate: 50, timeUnit: '1s', // we start at 50 iterations per second\n            stages: [\n                { target: 200, duration: '30s' }, // go from 50 to 200 iters/s in the first 30 seconds\n                { target: 200, duration: '3m30s' }, // hold at 200 iters/s for 3.5 minutes\n                { target: 0, duration: '30s' }, // ramp down back to 0 iters/s over the last 30 second\n            ],\n            preAllocatedVUs: 50, // how large the initial pool of VUs would be\n            maxVUs: 100, // if the preAllocatedVUs are not enough, we can initialize more\n\n            tags: { test_type: 'api' }, // different extra metric tags for this scenario\n            env: { MY_CROC_ID: '2' }, // same function, different environment variables\n            exec: 'apitest', // same function as the scenario above, but with different env vars\n        },\n    },\n    discardResponseBodies: true,\n    thresholds: {\n        // we can set different thresholds for the different scenarios because\n        // of the extra metric tags we set!\n        'http_req_duration{test_type:api}': ['p(95)<250', 'p(99)<350'],\n        'http_req_duration{test_type:website}': ['p(99)<500'],\n        // we can reference the scenario names as well\n        'http_req_duration{scenario:my_api_test_2}': ['p(99)<300'],\n    }\n};\n\nexport function webtest() {\n    http.get('https://test.k6.io/contacts.php');\n    sleep(Math.random() * 2);\n}\n\nexport function apitest() {\n    http.get(`https://test-api.k6.io/public/crocodiles/${__ENV.MY_CROC_ID}/`);\n    // no need for sleep() here, the iteration pacing will be controlled by the\n    // arrival-rate executors above!\n}\n```\n\nAs shown in the example above and the [documentation](https://k6.io/docs/using-k6/scenarios), all executors have some additional options that improve their flexibility and facilitate code reuse, especially in multi-scenario test runs:\n- Each executor has a `startTime` property, which defines at what time, relative to the beginning of the whole test run, the scenario will start being executed. \n- Executors have a new `gracefulStop` property that allows for iterations to complete gracefully for some amount of time after the normal executor duration is over ([#879](https://github.com/loadimpact/k6/issues/879), [#1033](https://github.com/loadimpact/k6/issues/1033)). The `ramping-vus` executor additionally also has `gracefulRampDown`, to give iterations time to finish when VUs are ramped down. The default value for both options is `30s`, so it's a slight breaking change, but the old behavior of immediately interrupting iterations can easily be restored by setting these options to `0s`.\n- Different executors can execute different functions other than the `default` exported one. This can be specified by the `exec` option in each `scenarios` config, and allows for more flexibility in organizing your tests, easier code reuse, building test suites, etc.\n- To allow for even greater script flexibility and code reuse, you can specify different environment variables and tags in each scenario, via the new `env` and `tags` executor options respectively.\n- k6 may now emit a new `dropped_iterations` metric in the `shared-iterations`, `per-vu-iterations`, `constant-arrival-rate` and `ramping-arrival-rate` executors; this is done if it can't run an iteration on time, depending on the configured rates (for the arrival-rate executors) or scenario `maxDuration` (for the iteration-based executors), so it's generally a sign of a poor config or an overloaded system under test ([#1529](https://github.com/loadimpact/k6/pull/1529)).\n\n\nWe've also introduced new `--execution-segment` and `--execution-segment-sequence` options, which allow for relatively easy partitioning of test runs across multiple k6 instances. Initially this applies to the test execution (all new executor types are supported!), but opens the door to test data partitioning, an often requested feature. See [#997](https://github.com/loadimpact/k6/issues/997) for more details.\n\n## UX\n\n- CLI: There are separate descriptions and real-time thread-safe progress bars for each individual executor.\n- CLI: Improve module import error message ([#1439](https://github.com/loadimpact/k6/issues/1439)).\n- JS: The `__VU` variable is now available in the script init context, allowing easier splitting of test input data per VU and reducing RAM usage ([#889](https://github.com/loadimpact/k6/issues/889)).\n- A new method to stop engine execution via the REST API ([#1352](https://github.com/loadimpact/k6/issues/1352)). Thanks @hynd!\n\n## Bugs fixed!\n- CLI: Stop `--http-debug` from exiting k6 on request dump error ([#1402](https://github.com/loadimpact/k6/issues/1402)). Thanks @berndhartzer!\n- CLI: JSON output is now less noisy ([#1469](https://github.com/loadimpact/k6/issues/1469)). Thanks @michiboo!\n- CLI: k6 doesn't exit when using `iterations` with `stages` ([#812](https://github.com/loadimpact/k6/issues/812)).\n- CLI: Mismatch in check counts in the end-of-test summary ([#1033](https://github.com/loadimpact/k6/issues/1033)).\n- Config: Better validation of `stages` ([#875](https://github.com/loadimpact/k6/issues/875)).\n- JS: Rare panics in goja ([#867](https://github.com/loadimpact/k6/issues/867),[#1552](https://github.com/loadimpact/k6/issues/1552)).\n- HTTP: Fix request timeout and wrong context used for pushing metrics ([#1260](https://github.com/loadimpact/k6/issues/1260)).\n- Execution: Fix sometimes skipping iterations with a `context cancelled` error when rapidly ramping up and down ([#1283](https://github.com/loadimpact/k6/issues/1283)).\n- WebSockets: Fix possible connection hanging when the main context is cancelled ([#1260](https://github.com/loadimpact/k6/issues/1542)).\n- WebSockets: Avoid leaking goroutines ([#1513](https://github.com/loadimpact/k6/issues/1513)).\n- WebSockets: Emit WS metrics as soon as possible instead of when the connection is closed ([#885](https://github.com/loadimpact/k6/issues/885)).\n\n\n## Internals\n\n- As mentioned above, [#1007](https://github.com/loadimpact/k6/issues/1007) was almost a complete re-write of the execution scheduling parts of k6. This involved deep architectural changes in how test runs are executed and improved overall code coverage by around 2%.\n- Switched to Go 1.14 for building and testing k6, bringing some fixes and performance improvements.\n- WebSockets: Updated gorilla/websocket library bringing minor performance improvements ([#1515](https://github.com/loadimpact/k6/pull/1515)).\n- Code cleanup and formatting. Thanks @thinkerou!\n\n\n## Breaking changes\n\n- Execution config options (`scenarios`, `stages`, `iterations`, `duration`) from \"upper\" config layers overwrite execution options from \"lower\" (i.e. CLI flags > environment variables > JS options > JSON options) config layers. For example, the `--iterations` CLI flag will overwrite any execution options set as environment variables (e.g. `K6_DURATION`, `K6_STAGES`, etc.) or script options (`stages: [ /* ... */]`, `scenarios: { /* ... */ }`, etc. ).\n\n- Previously, if the `iterations` and `vus` script options were specified, but `duration` was not, the script could have ran practically indefinitely, given a sufficiently large number or length of the used iterations. There was no implicit or explicit time limit, one of the reasons this execution pattern was not allowed in `k6 cloud` test runs before. From k6 v0.27.0, by default, if the specified iterations haven't finished, these scripts will abort after 10 minutes, the default `maxDuration` value of `shared-iterations` executors. This default value can easily be changed by either setting the `maxDuration` option in the corresponding `scenarios` entry, or, if just the execution shortcuts were used to run the script, by setting the `duration` / `--duration` / `K6_DURATION` script option.\n\n- Previously, all iterations were interruptible - as soon as the specified `duration` expired, or when VUs were ramped down in a stage, any running iterations were interrupted. Now all executors besides the `externally-controlled` one have a `gracefulStop` period of `30s` by default ([#898](https://github.com/loadimpact/k6/issues/898)). Additionally, the `ramping-vus` executor has a `gracefulRampDown` parameter that configures the ramp-down grace period. For those periods, no new iterations will be started by the executors, but any currently running iterations will be allowed up to the specified periods to finish their execution.\n\n- Using different execution config options on the same level is now a configuration conflict error and will abort the script. For example, executing `k6 run --duration 10s --stages 5s:20 script.js` won't work ([#812](https://github.com/loadimpact/k6/issues/812)). The only exception is combining `duration` and `iterations`, which will result in a `shared-iterations` executor with the specified non-default `maxDuration` ([#1058](https://github.com/loadimpact/k6/issues/1058)).\n\n- The k6 REST API for controlling script execution (i.e. the `k6 pause`, `k6 scale` commands) now only works when a `externally-controlled` executor is configured in the `scenarios` config. The initial pausing of a test (i.e. `k6 run --paused script.js`) still works with all executor types, but once the test is started with `k6 resume` (or the corresponding REST API call), it can't be paused again unless only the `externally-controlled` executor is used.\n\n- Previously, running a script with `k6 run --paused script.js` would have still executed the script's `setup()` function (if it was present and wasn't explicitly disabled with `--no-setup`) and paused immediately after. Now, k6 will pause before it executes `setup()`.\n\n- Previously, if you ramped down and ramped up VUs via `stages`, the `__VU` global variables would have been incremented on the ramp-ups. This will no longer happen, the max value of `__VU` across a test run will never exceed the number of initialized VUs.\n\n- The `vusMax` / `K6_VUS_MAX` / ` -m` / `--max` option is deprecated - it was previously used for the control of the initialized VUs by the REST API. Since that has now been restricted to the `externally-controlled` executor, the equivalent option there is called `maxVUs`.\n\n- Tests with infinite duration are now only possible via the `externally-controlled` executor.\n\n- k6 will now exit with an error if `--address` is specified but the API server is unable to start. Previously this would've resulted in a warning message.\n\n- The format returned by `Date.prototype.toUTCString()` was changed from `Thu Jan 01 1970 00:00:00 GMT+0000 (UTC)` to `Thu, 01 Jan 1970 00:00:00 GMT`. This is a fix that aligns it with the ECMAScript spec. See https://github.com/dop251/goja/issues/119 .\n\n- The default `setupTimeout` and `teardownTimeout` values were changed from 10s to 60s ([#1356](https://github.com/loadimpact/k6/pull/1356)).\n"
  },
  {
    "path": "release notes/v0.27.1.md",
    "content": "k6 v0.27.1 is a minor release with a few bugfixes and almost no functional changes compared to v0.27.0.\n\nThe biggest fix was resolving a panic (and some `k6 login` errors) when k6 was ran through git bash / Mintty on Windows ([#1559](https://github.com/loadimpact/k6/issues/1559)).\n\nk6 will now work in those terminals, however, if you're using [git bash](https://gitforwindows.org/) or [Mintty](https://mintty.github.io/) as your terminal on Windows, you might not get the best user experience out of k6. Consider using a different terminal like [Windows Terminal](https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701), PowerShell or [Cmder](https://cmder.net/). Alternatively, to [work around](https://github.com/mintty/mintty/wiki/Tips#inputoutput-interaction-with-alien-programs) the issues with the incompatible terminals, you can try running k6 through [`winpty`](https://github.com/rprichard/winpty), which should already be preinstalled in your git bash environment: `winpty k6 run script.js`.\n\nIf you're using the Windows Subsystem for Linux (WSL), you are probably going to get better experience by using the official Linux k6 binary or .deb package. For all other cases of running k6 on Windows, the normal k6 Windows binary / `.msi` package should work well.\n\n### Other minor fixes and changes:\n\n- The Go version that k6 is compiled with was updated to 1.14.6, to incorporate the [latest Go fixes](https://github.com/golang/go/issues?q=milestone%3AGo1.14.6+label%3ACherryPickApproved) ([#1563](https://github.com/loadimpact/k6/pull/1563)).\n- If the [`throw` option](https://k6.io/docs/using-k6/options#throw) is enabled, warnings for failed HTTP requests will no longer be logged to the console ([#1199](https://github.com/loadimpact/k6/issues/1199)).\n- Metric sample packets sent to the cloud with `k6 run --out cloud` can now be sent in parallel via the new `K6_CLOUD_METRIC_PUSH_CONCURRENCY` option, with a default value of `1` ([#1569](https://github.com/loadimpact/k6/pull/1569)).\n- The `gracefulRampDown` VU requirement calculations for the `ramping-vus` executor were greatly optimized for large test runs ([#1567](https://github.com/loadimpact/k6/pull/1567)).\n- Fixed a rare bug where `dropped_iterations` wouldn't be emitted by the `per-vu-iterations` executor on time due to a race ([#1357](https://github.com/loadimpact/k6/issues/1357)).\n- Metrics, including checks, from `setup()` and `teardown()`, were not correctly shown in local k6 runs ([#949](https://github.com/loadimpact/k6/issues/949)).\n"
  },
  {
    "path": "release notes/v0.28.0.md",
    "content": "k6 v0.28.0 is here! :tada: It's a small release that adds some much requested features and a few important bugfixes!\n\nStarting with this release, we'll be trying to stick to a new 8-week fixed release schedule for new k6 versions. This release comes ~8 weeks after v0.27.0 was released, and k6 v0.29.0 should be released in mid-November.\n\n## New features and enhancements!\n\n### Cloud execution logs ([#1599](https://github.com/loadimpact/k6/pull/1599))\n\nLogs from distributed k6 cloud test runs will now be shown in the terminal that executed the `k6 cloud` command, as well as in the k6 cloud web app on [app.k6.io](https://app.k6.io/)! :tada: This means that, if your script contains `console.log()` / `console.warn()` / etc. calls, or some of your requests or iterations fail, you'd be able to see that and debug them much more easily! Even `--http-debug` data should be proxied, up to 10000 bytes per message. To prevent abuse and not to overwhelm any user terminals, cloud logs are rate-limited at 10 messages per second per instance, for now, but that should be more than enough to debug most issues!\n\nThis feature is enabled by default, though you can disable it with `k6 cloud --show-logs=false script.js`.\n\n\n### Pushing k6 logs to loki ([#1576](https://github.com/loadimpact/k6/pull/1576))\n\nk6 can now push its execution logs to a loki server! This can be done via the new `--log-output` CLI flag or the `K6_LOG_OUTPUT` environment variable option. For example, `k6 run --log-output \"loki=https://my-loki-server/loki/api/v1/push,limit=100,level=info,msgMaxSize=10000\"` will push up to 100 k6 log messages per second, of severity `INFO` and up, truncated to `10000` bytes, to `https://my-loki-server`.\n\n### Optional port to host mappings ([#1489](https://github.com/loadimpact/k6/pull/1489))\n\n@calavera added an extension for the host mapping feature. Now you can specify different port numbers via the [`hosts` option](https://k6.io/docs/using-k6/options#hosts), like this:\n\n```js\nimport http from 'k6/http';\n\nexport let options = {\n    hosts: {\n        'test.k6.io': '127.0.0.1:8080',\n    },\n};\n```\n\n### Support for specifying data types to InfluxDB fields ([#1395](https://github.com/loadimpact/k6/pull/1395))\n\n@TamiTakamiya added support for specifying the data type (int/float/bool/string) of fields that are emitted to InfluxDB outputs.\n\nIn order to specify the data type, you should:\n- Use the environment variable `K6_INFLUXDB_TAGS_AS_FIELDS`, which is used to specify which k6 metric tag values should be sent as nonindexable fields (instead of tags) to an InfluxDB output. This is specified as a comma-separated string, and is now extended to optionally allow specifying a data type to each name.\n- Each pair of field name and its data type is represented in the format `(name):(data_type)`, for example, `event_processing_time:int`.\n- One of four data types (`int`, `float`, `bool` and `string`) can be specified to one field name.\n- When the colon and a `data_type` are omitted, for example `transaction_id`, it is interpreted as a string field.\n\nA complete example can look like this: `export K6_INFLUXDB_TAGS_AS_FIELDS=\"vu:int,iter:int,url:string,boolField:bool,floatField:float\"`\n\n_Note: If you have existing InfluxDB databases that contain fields whose data types are different from the ones that you want to save in future k6 test executions, you may want to create a new database or change field names as the current InfluxDB offers limited support for changing fields' data type. See the [InfluxDB documentation](https://docs.influxdata.com/influxdb/v1.8/troubleshooting/frequently-asked-questions/#can-i-change-a-field-s-data-type) for more details._\n\n### Support for automatic gzip-ing of the CSV output result ([#1566](https://github.com/loadimpact/k6/pull/1566))\n\n@thejasbabu added support to gzip archiving the file emitted by the CSV output on the fly. To use it, simply append `.gz` at the end of the file name, like this: `k6 run --out csv=test.csv.gz test.js`\n\n## UX\n\n- Various spacing and progress bar rendering issues were improved ([#1580](https://github.com/loadimpact/k6/issues/1580)).\n- The k6 ASCII logo was made a bit more proportional ([#1615](https://github.com/loadimpact/k6/pull/1615/commits/54a3168f0945fa8243edb7540fe78ad7ac66a8dc)). Thanks, @rawtaz!\n- The docker-compose example setup from the k6 repo now contains a built-in simple dashboard ([#1610](https://github.com/loadimpact/k6/pull/1610)). Thanks, @jeevananthank!\n- Some logs now have a `source` field specifying if a log comes from `console`, `http-debug` or `stacktrace` (when an exception has bubbled to the top of the iteration).\n\n## Bugs fixed!\n\n- Network: IPv6 support was fixed as a part of the new `hosts` port mapping ([#1489](https://github.com/loadimpact/k6/pull/1489)). Thanks, @calavera!\n- Metrics: Fixed the wrong `name` metric tag for redirected requests ([#1474](https://github.com/loadimpact/k6/issues/1474)).\n- UI: Fixed a `divide by zero` panic caused by some unusual execution environments that present a TTY, but return `0` for the terminal size ([#1581](https://github.com/loadimpact/k6/pull/1581)).\n- Config: Fixed the parsing of `K6_DATADOG_TAG_BLACKLIST` ([#1602](https://github.com/loadimpact/k6/issues/1602)).\n- Config: Fixed marshaling of `tlsCipherSuites` and `tlsVersion` ([#1603](https://github.com/loadimpact/k6/pull/1603)). Thanks, @berndhartzer!\n- WebSockets: Fixed a `ws.SetTimeout()` and `ws.SetInterval()` panic when float values were passed ([#1608](https://github.com/loadimpact/k6/pull/1608)).\n\n## Internals\n\n- goja, the JavaScript runtime k6 uses, was updated to the latest version. This means that k6 with `--compatibility-mode=base` now supports some standard library features from ES6 ([goja's PR](https://github.com/dop251/goja/pull/180)), though no new syntax yet. In future versions we plan to drop some current core.js modules that are no longer needed, which should greatly reduce memory usage per VU ([#1588](https://github.com/loadimpact/k6/pull/1588)).\n- Go modules are now used to manage the k6 dependencies instead of `dep` ([#1584](https://github.com/loadimpact/k6/pull/1584)).\n\n## Breaking changes\n\n- `k6 cloud` will now proxy execution logs back to the client machine. To disable this behavior, use `k6 cloud --show-logs=false`.\n\n- `--http-debug` request and response dumps are now emitted through the logging sub-system, to facilitate the cloud log proxying ([#1577](https://github.com/loadimpact/k6/pull/1577)).\n"
  },
  {
    "path": "release notes/v0.29.0.md",
    "content": "k6 v0.29.0 is here! :tada: It's a feature-packed release with tons of much-requested changes and additions, a lot of them implemented by awesome external contributors! :heart:\n\nAs promised in the previous release notes, we're trying to stick to a roughly 8-week release cycle, so you can expect the next k6 version at the start of January 2021, barring any bugfix releases before that.\n\n## New features\n\n### Initial support for gRPC ([#1623](https://github.com/loadimpact/k6/pull/1623))\n\nk6 now supports unary gRPC calls via the new `k6/net/grpc` built-in module. Streaming RPCs are not yet supported and the **JS API is in beta**, so there might be slight breaking changes to the API in future k6 versions, but it's a good start on the road to fully supporting this much-requested protocol!\n\nThis is a simple example of how the new module can be used with [grpcb.in](https://grpcb.in/):\n```js\nimport grpc from \"k6/net/grpc\";\n\nlet client = new grpc.Client();\n// Download addsvc.proto for https://grpcb.in/, located at:\n// https://raw.githubusercontent.com/moul/pb/master/addsvc/addsvc.proto\n// and put it in the same folder as this script.\nclient.load(null, \"addsvc.proto\");\n\nexport default () => {\n    client.connect(\"grpcb.in:9001\", { timeout: \"5s\" });\n\n    let response = client.invoke(\"addsvc.Add/Sum\", {\n        a: 1,\n        b: 2\n    });\n    console.log(response.message.v); // should print 3\n\n    client.close();\n}\n```\n\nYou can find more information and examples how to use k6's new gRPC testing capabilities in [our documentation](https://k6.io/docs/javascript-api/k6-net-grpc).\n\nHuge thanks to @rogchap for adding this feature!\n\n### New options for configuring DNS resolution ([#1612](https://github.com/loadimpact/k6/pull/1612))\n\nYou can now control some aspects of how k6 performs DNS resolution! Previously, k6 would have cached DNS responses indefinitely ([#726](https://github.com/loadimpact/k6/issues/726)) and always picked the first resolved IP ([#738](https://github.com/loadimpact/k6/issues/738)) for all connections. This caused issues, especially when load testing services that relied on DNS for load-balancing or auto-scaling.\n\nFor technical reasons explored in ([#726](https://github.com/loadimpact/k6/issues/726)), k6 v0.29.0 still doesn't respect the actual TTL value of resolved IPs, that will be fixed in a future k6 version. For now, it simply allows users to specify a global static DNS TTL value and resolution strategy manually. It also has better defaults! Now, by default, the global DNS TTL value is 5 minutes and, if the DNS resolution returned multiple IPs, k6 will pick a random (preferably IPv4) one for each connection.\n\nYou can also configure this behavior with the new `--dns` CLI flag, the `K6_DNS` environment variable, or the `dns` script/JSON option. Three DNS resolution options are exposed in this k6 version: `ttl`, `select`, and `policy`.\n\nPossible `ttl` values are :\n- `0`: no caching at all - each request will trigger a new DNS lookup.\n- `inf`: cache any resolved IPs for the duration of the test run _(the old k6 behavior)_.\n- any time duration like `60s`, `5m30s`, `10m`, `2h`, etc.; if no unit is specified (e.g. `ttl=3000`), k6 assumes milliseconds. _The new default value is `5m`._\n\nPossible `select` values are:\n- `first` - always pick the first resolved IP _(the old k6 behavior)_.\n- `random` - pick a random IP for every new connection _(the new default value)_.\n- `roundRobin` - iterate sequentially over the resolved IPs.\n\nPossible `policy` values are:\n- `preferIPv4`: use IPv4 addresses, if available, otherwise fall back to IPv6 _(the new default value)_.\n- `preferIPv6`: use IPv6 addresses, if available, otherwise fall back to IPv4.\n- `onlyIPv4`: only use IPv4 addresses, ignore any IPv6 ones.\n- `onlyIPv6`: only use IPv6 addresses, ignore any IPv4 ones.\n- `any`: no preference, use all addresses _(the old k6 behavior)_.\n\nHere are some configuration examples:\n\n```bash\nk6 run --dns \"ttl=inf,select=first,policy=any\" script.js # this is the old k6 behavior\nK6_DNS=\"select=random,ttl=5m,policy=preferIPv4\" k6 cloud script.js # new default behavior\n# syntax for the JSON config file or for the exported script `options`:\necho '{\"dns\": {\"select\": \"roundRobin\", \"ttl\": \"1h33m7s\", \"policy\": \"onlyIPv6\"}}' > config.json\nk6 run --config \"config.json\" script.js\n```\n\n### Support for Go extensions ([#1688](https://github.com/loadimpact/k6/pull/1688))\n\nAfter some discussions ([#1353](https://github.com/loadimpact/k6/issues/1353)) and exploration of different approaches for Go-based k6 extensions, we've settled on adopting something very similar to [caddy's extensions](https://caddyserver.com/docs/extending-caddy). In short, [`xk6`](https://github.com/k6io/xk6) (modeled after [`xcaddy`](https://github.com/caddyserver/xcaddy)) is a small stand-alone tool that will be able to build custom k6 binaries with 3rd party extensions bundled in. The extensions can be simple Git repositories (no central infrastructure needed!) with Go modules. They will be fully compiled, not interpreted, a part of the final custom k6 binary users will be able to build with k6.\n\nxk6 is not yet stable or documented, so any extension authors will struggle until we stabilize and document everything in the coming weeks. The important part is that the k6 changes that would allow xk6 to work were implemented in [#1688](https://github.com/loadimpact/k6/pull/1688), so k6 v0.29.0 is the first version compatible with xk6!\n\nExpect more information soon, but for a brief example, xk6 will work somewhat like this:\n\n```bash\nxk6 build v0.29.0 --with github.com/k6io/xk6-k8s --with github.com/k6io/xk6-sql@v0.1.1\n\n./k6 run some-script-with-sql-and-k8s.js\n```\n\nThanks, @andremedeiros, for pushing us to add plugins in k6 and for making a valiant attempt to harness Go's poor plugin API! Thank you, @mardukbp, for pointing us towards the xcaddy approach and explaining its benefits!\n\n### Support for setting local IPs, potentially from multiple NICs ([#1682](https://github.com/loadimpact/k6/pull/1682))\n\nYou can now specify a list of source IPs, IP ranges and CIDRs for `k6 run`, from which VUs will make requests via the new `--local-ips` CLI flag or `K6_LOCAL_IPS` environment variable. The IPs will be sequentially given out to VUs, allowing you to distribute load between different local addresses. This option doesn't change anything on the OS level, so the IPs need to already be configured on the OS level in order for k6 to be able to use them.\n\nThe biggest use case for this feature is splitting the network traffic from k6 between multiple network adapters, thus potentially greatly increasing the available network throughput. For example, if you have 2 NICs, you can run k6 with `--local-ips=\"<IP-from-first-NIC>,<IP-from-second-NIC>\"` to balance the traffic equally between them - half of the VUs will use the first IP and the other half will use the second. This can scale to any number of NICs, and you can repeat some local IPs to give them more traffic. For example, `--local-ips=\"<IP1>,<IP2>,<IP3>,<IP3>\"` will split VUs between 3 different source IPs in a 25%:25%:50% ratio.\n\nThanks to @ofauchon, @srguglielmo, and @divfor for working on previous iterations of this!\n\n### New option for blocking hostnames ([#1666](https://github.com/loadimpact/k6/pull/1666))\n\nYou can now block network traffic by hostnames with the new `--block-hostnames` CLI flag / `K6_BLOCK_HOSTNAMES` environment variable / `blockHostnames` JS/JSON option. Wildcards are also supported at the beginning, allowing you to easily block a domain and all of its subdomains. For example, this will make sure k6 never attempts to connect to any `k6.io` subdomain (`test.k6.io`, `test-api.k6.io`, etc.) and `www.example.com`:\n\n```js\nexport let options = {\n  blockHostnames: [\"*.k6.io\" , \"www.example.com\"],\n};\n```\n\nThanks to @krashanoff for implementing this feature!\n\n## UX and enhancements\n\n- HTTP: The [gjson library](https://github.com/tidwall/gjson/) k6 uses for handling the HTTP `Response.json(selector)` behavior was updated, so we now support more [modifiers](https://github.com/tidwall/gjson/blob/master/SYNTAX.md#modifiers) like `@flatten` and multipaths ([#1626](https://github.com/loadimpact/k6/pull/1626)). Thanks, @sondnm!\n- HTTP: The status text returned by the server can now be accessed from the new `Response.status_text` field ([#1649](https://github.com/loadimpact/k6/pull/1649)). Thanks, @lcd1232!\n- HTTP: `--http-debug` now emits extra UUID values that can be used to match HTTP requests and their responses ([#1644](https://github.com/loadimpact/k6/pull/1644)). Thanks, @repl-david-winiarski!\n- Logging: A new `allowedLabels` sub-option is added to the Loki configuration ([#1639](https://github.com/loadimpact/k6/pull/1639)).\n- Cloud: when aborting a `k6 cloud` test with `Ctrl+C`, k6 will now wait for the cloud service to fully abort the test run before returning. A second `Ctrl+C` will cause it to immediately exit ([#1647](https://github.com/loadimpact/k6/pull/1647)), ([#1705](https://github.com/loadimpact/k6/pull/1705)). Thanks, @theerapatcha!\n- JS: k6 will now attempt to recover from Go panics that occur in VU code, so they will be treated similarly to JS exceptions ([#1697](https://github.com/loadimpact/k6/pull/1697)). This is just a precaution that should never be needed. panics should not happen and if one occurs, please report it in our issue tracker, since it's most likely a bug in k6.\n\n## Bugs fixed!\n\n- JS: [goja](https://github.com/dop251/goja), the JS runtime k6 uses, was updated to its latest version, to fix some issues with regular expressions after its previous update ([#1707](https://github.com/loadimpact/k6/pull/1707)).\n- JS: Prevent loops with `--compatibility-mode=extended` when Babel can transpile the code but goja can't parse it ([#1651](https://github.com/loadimpact/k6/pull/1651)).\n- JS: Fixed a bug that rarely caused a `context canceled` error message to be shown ([#1677](https://github.com/loadimpact/k6/pull/1677)).\n- HTTP: Setting an empty `userAgent` option caused k6 to revert to the default Go `User-Agent` header value of `Go-http-client`. Now something like `--user-agent=''` will cause k6 to not send the `User-Agent` header at all ([#1695](https://github.com/loadimpact/k6/pull/1695)).\n- Cloud: `k6 cloud --quiet` didn't just hide the progressbar, but caused the k6 process to exit as soon as the cloud test was created, without waiting for it to finish. `k6 cloud -q` is now fixed to be similar to the `k6 run -q` behavior, but if the old behavior was wanted, something close to it can be recreated by using `k6 cloud --exit-on-running` ([#1702](https://github.com/loadimpact/k6/pull/1702)).\n\n## Internals\n\n- We switched to GitHub Actions for our CI ([#1640](https://github.com/loadimpact/k6/pull/1640)).\n- We've updated to Go 1.15 for building the official k6 binary releases ([#1679](https://github.com/loadimpact/k6/pull/1679))\n\n## Breaking changes\n\n- As mentioned above, DNS resolution defaults were changed. If you want to use the old k6 behavior of always picking the first IP, no IPv4 preference, and caching DNS responses indefinitely, run k6 with `--dns=\"ttl=inf,select=first,policy=any\"`.\n"
  },
  {
    "path": "release notes/v0.30.0.md",
    "content": "k6 v0.30.0 is here! :tada: It was a bit of a slow after-holiday release, but it still packs a few major new features and improvements that users have been requesting for a long time!\n\n## New features\n\n### Share memory between VUs using read-only arrays ([#1739](https://github.com/loadimpact/k6/pull/1739))\n\nk6 has long had an issue with the handling of big data files with test fixtures. For example, if you have a huge `users.json` file with test users for your application:\n```js\n[\n  {\"username\": \"user1\", \"password\": \"password1\", \"other\": \"some-long-data-....-1\"},\n  {\"username\": \"user2\", \"password\": \"password2\", \"other\": \"some-long-data-....-2\"},\n  // ... ~1 million more users or more... :D\n  {\"username\": \"user999999\", \"password\": \"password999999\", \"other\": \"some-long-data-....-999999\"}\n]\n```\n\nIf you just use `JSON.parse(open('users.json'))` in your script, then every VU will have a copy of the whole huge data set. Every VU in k6 is a separate JavaScript runtime, so there wasn't a thread-safe way to share data between them. Until now, that is!\n\nWe've added a new built-in `SharedArray` object in the new `k6/data` module that allows VUs to share read-only data:\n```js\nimport { SharedArray } from 'k6/data';\nimport { sleep } from 'k6';\nimport http from 'k6/http';\n\nlet users = new SharedArray('someName', function () {\n    // This function will be called only once, in the first init context\n    // execution. Every other VU will just get a memory-safe read-only reference\n    // to the already loaded data.\n    console.log('Loading users.json, this happens only once...');\n    // You are not restricted to JSON, you can do anything - parse a CSV or XML\n    // file, generate random data, etc. - as long as you return an array.\n    return JSON.parse(open('users.json'));\n});\n\nexport let options = { vus: 10, duration: '30s' };\nexport default function () {\n    let randomUserID = Math.floor(Math.random() * users.length);\n    let user = users[randomUserID]; // alternatively, we can also use __VU and/or __ITER\n    console.log(`VU ${__VU} is running iteration ${__ITER} with user ${user.username}...`);\n    http.post('https://httpbin.test.k6.io/post', JSON.stringify(user));\n    sleep(Math.random() * 2); // or, better yet, use arrival-rate\n}\n```\n\nNotice how `Loading users.json` is logged only once, but each VU uses the `users` variable like a normal JS array. The data is read only once and we have just a single copy of the huge array in memory! Behind the scenes, k6 uses a JS [`Proxy`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to transparently copy only the row each VU requests in `users[randomUserID]` to it. This on-demand copying is a bit inefficient, but it's still leagues better than having a copy of the huge array in every VU! And you can avoid the copying in every iteration by pinning the data used by every VU and having `let user = users[randomUserID]` in the [init context](https://k6.io/docs/using-k6/test-life-cycle)!\n\nAnd yes, you can have multiple `SharedArray` objects in the same script, just make sure to give them unique names - this is what `someName` in the script above was for. Because VUs are independent JS runtimes, we need some way to differentiate between the different shared memory objects, so we require them to have unique names. These names are also the IDs that any [xk6](https://github.com/k6io/xk6) extensions would need to use to access them.\n\nThis works both locally and in the cloud. We advise everyone who deals with large data files to wrap them in a `SharedArray` and give this new feature a try. The required script changes should be minimal, while the memory usage should be significantly lower. Hopefully, we can finally consider one of the biggest blockers k6 users have had for a long time solved! :tada:\n\n### Support a `handleSummary()` callback at the end of the test ([#1768](https://github.com/loadimpact/k6/pull/1768))\n\nYou can now `export` a function called `handleSummary()` and k6 will call it at the end of the test run, after even `teardown()`. `handleSummary()` will be called with a JS object containing the same information that is used to generate the end-of-test summary and `--summary-export`, and allows users to completely customize how the end-of-test summary looks like.\n\nBesides customizing the end-of-test CLI summary (if `handleSummary()` is exported, k6 will not print the default), you can also transform the summary data to various machine or human-readable formats and save it to files. This allows the creation of JS helper functions that generate JSON, CSV, XML (JUnit/xUnit/etc.), HTML, etc. files from the summary data. Even binary formats like PDF are not out of reach, potentially, with an appropriate JS library that works in k6! You can also send the generated reports to a remote server by making an HTTP request with them (or using any of the other protocols k6 already supports)! Here's a simple example:\n\n```js\nimport http from 'k6/http';\nimport k6example from 'https://raw.githubusercontent.com/loadimpact/k6/master/samples/thresholds_readme_example.js';\nexport default k6example; // use some predefined example to generate some data\nexport const options = { vus: 5, iterations: 10 };\n\n// These are still very much WIP and untested, but you can use them as is or write your own!\nimport { jUnit, textSummary } from 'https://jslib.k6.io/k6-summary/0.0.1/index.js';\n\nexport function handleSummary(data) {\n    console.log('Preparing the end-of-test summary...');\n\n    // Send the results to some remote server or trigger a hook\n    let resp = http.post('https://httpbin.test.k6.io/anything', JSON.stringify(data));\n    if (resp.status != 200) {\n        console.error('Could not send summary, got status ' + resp.status);\n    }\n\n    return {\n        'stdout': textSummary(data, { indent: ' ', enableColors: true}), // Show the text summary to stdout...\n        'junit.xml': jUnit(data), // but also transform it and save it as a JUnit XML...\n        'summary.json': JSON.stringify(data), // and a JSON with all the details...\n        // And any other JS transformation of the data you can think of,\n        // you can write your own JS helpers to transform the summary data however you like!\n    }\n}\n```\n\nk6 expects `handleSummary()` to return a `{key1: value1, key2: value2, ...}` map. The values can be string or `ArrayBuffer` and represent the generated summary report contents. The keys should be strings and determine where the contents will be displayed or saved: `stdout` for [standard output](https://en.wikipedia.org/wiki/Standard_streams), `stderr` for standard error, or a path to a file on the system (which will be overwritten).\n\nThe format of the `data` parameter is similar but not identical to the data format of `--summary-export`. The format of `--summary-export` remains unchanged, for backwards compatibility, but the data format for this new k6 feature was made more extensible and had some of the ambiguities and issues from the previous format fixed. We can't cover the new format in the release notes, though you can easily see what it contains by using `return { 'stdout': JSON.stringify(data)};` in `handleSummary()`! :smile:\n\nThis feature is only available for local `k6 run` tests for now, though we plan to support [`k6 cloud`](https://k6.io/docs/cloud) tests eventually. And, as mentioned in the snippet above, the JS helper functions that transform the summary in various formats are far from final, so keep an eye on [jslib.k6.io](https://jslib.k6.io/) for updates. Or, better yet, submit PRs with improvements and more transformations at https://github.com/loadimpact/jslib.k6.io :smile:\n\n## Other enhancements and UX improvements\n\n- CI: k6 releases for Windows will now be digitally signed, which should reduce the number and severity of warnings Windows users see; the warnings would hopefully disappear altogether once Microsoft sees enough usage of the signed k6 releases to trust us ([#1746](https://github.com/loadimpact/k6/pull/1746)). The installer and binary were also enhanced with more metadata and had their look updated with the new k6 logo and styling ([#1727](https://github.com/loadimpact/k6/pull/1727)).\n- JS: [goja](https://github.com/dop251/goja), the JS runtime k6 uses, was updated to its latest `master` version. This includes a few bugfixes and support for several new features, so [`--compatibility-mode=base`](https://k6.io/docs/using-k6/javascript-compatibility-mode) is even more feature-rich at no additional runtime cost. We are contributing patches to goja in an effort to completely drop core.js and have the benefit of lower CPU and memory usage per VU even with `--compatibility-mode=extended` in the next k6 version! :tada:\n- Config: integer values for `duration` and similar time values in the exported script `options` and environment variables are now treated as milliseconds. Similarly, the `timeout` option in [`http.Params`](https://k6.io/docs/javascript-api/k6-http/params) can now be \"stringy\", e.g. `\"30s\"`, `\"1m10s\"`, etc. ([#1738](https://github.com/loadimpact/k6/pull/1738)).\n- HTTP: k6 now accepts `ArrayBuffer` values for the HTTP request body ([#1776](https://github.com/loadimpact/k6/pull/1776)). This is a prelude/MVP for us gradually adopting `ArrayBuffer` for all binary data in k6 ([#1020](https://github.com/loadimpact/k6/issues/1020)).\n- Docker: We've added `WORKDIR /home/k6` to our official `Dockerfile` ([#1794](https://github.com/loadimpact/k6/pull/1794)).\n\n\n## Bugs fixed!\n\n- HTTP: updated the `golang.org/x/crypto` and `golang.org/x/net` dependencies, which should have resolved some corner case issues with HTTP/2 connections, since k6 depends on `golang.org/x/net/http2` ([#1734](https://github.com/loadimpact/k6/pull/1734)).\n- HTTP: fixed a couple of issues with `blockHostnames` that prevented zero-length matches for wildcards, as well as the explicit blocking of a domain and its sub-domain at the same time ([#1723](https://github.com/loadimpact/k6/pull/1723)).\n- Logs: if logs are streamed to a loki instance, k6 will now wait for them to finish being pushed before it exits - this will specifically mean that logs and errors in the init context will be propagated ([#1694](https://github.com/loadimpact/k6/pull/1694)).\n- HTTP: fixed the missing `host` value from [`http.Response.request.headers`](https://k6.io/docs/javascript-api/k6-http/response) when it was explicitly set in the HTTP request params. ([#1744](https://github.com/loadimpact/k6/pull/1744)). Thanks, @noelzubin!\n- UI: fixed the lack of newline after `k6 login` password inputs ([#1749](https://github.com/loadimpact/k6/pull/1749)). Thanks, @paroar!\n- HTML: fixed a panic in the [`html.Selection.slice()`](https://k6.io/docs/javascript-api/k6-html/selection/selection-slice-start-end) method ([#1756](https://github.com/loadimpact/k6/pull/1756)). Thanks, @asettouf!\n- Summary: fixed random ordering of groups and checks in the end-of-test summary, they should now be shown in the order of their occurrence ([#1788](https://github.com/loadimpact/k6/pull/1788)).\n- Summary: the value for `Rate` metrics in the `--summary-export` JSON file was was always `0`, regardless of the `pass/(pass+fail)` ratio ([#1768](https://github.com/loadimpact/k6/pull/1768)).\n\n\n## Internals\n\n- JS: Added automated tc39/test262 tests in our CI pipeline, so we have greater assurance that we're not breaking things when we update our JS runtime or when we finally drop core.js ([#1747](https://github.com/loadimpact/k6/pull/1747)).\n- CI: We've enabled more CI tests on Windows, now that we've switched to GitHub Actions ([#1720](https://github.com/loadimpact/k6/pull/1720)).\n\n\n## Breaking changes\n\nSome of the changes above deserve a special second mention, since they either slightly break previously documented k6 behavior, or fix previously undefined behavior and bugs that someone might have inadvertently relied on:\n\n- Summary: `--no-summary` now also disables `--summary-export` ([#1768](https://github.com/loadimpact/k6/pull/1768)). You can recreate the previous behavior of `k6 run --no-summary --summary-export=summary.json script.js` by having an empty exported `handleSummary()` function in your script (so that the default text summary is not shown by k6) and executing only `k6 run --summary-export=summary.json script.js`. Or omitting `--summary-export` as well and using `handleSummary()` as shown above.\n- Config: integer values for `duration` and similar time values in the exported script `options` and environment variables are now treated as milliseconds. This was previously undefined behavior, but instead of k6 erroring out, it silently accepted and treated such values as nanoseconds ([#1738](https://github.com/loadimpact/k6/pull/1738)).\n- Docker: We've added `WORKDIR /home/k6` to our official `Dockerfile` ([#1794](https://github.com/loadimpact/k6/pull/1794))."
  },
  {
    "path": "release notes/v0.31.0.md",
    "content": "k6 v0.31.0 is here! :tada: It's a smaller release with some significant performance improvements, a new `http_req_failed` metric and changes to the output subsystem that enable output extensions with [xk6](https://github.com/k6io/xk6)!\n\n## New features\n\n### Output cleanup and extensions ([#1874](https://github.com/loadimpact/k6/pull/1874))\n\nThe state of k6's output packages has been a development pain point for a long time, which made it difficult to add new outputs in a consistent way. In the refactor done in v0.31.0, this has been mostly addressed and outputs now implement a simpler and cleaner `Output` interface.\n\nIn addition to this, it is now possible to implement custom k6 output extensions in Go with [xk6](https://github.com/k6io/xk6)! This is very useful if you use a system that's currently not supported by [the built-in outputs](https://k6.io/docs/getting-started/results-output), or need some custom handling of the metrics k6 produces.\n\nWriting output extensions is done very similarly to [how JS module extensions are currently written](https://k6.io/blog/extending-k6-with-xk6), though instead of calling `js/modules.Register()`, you should implement the new [`Output` interface](https://github.com/loadimpact/k6/blob/2036baeaa83d76ce17aae95fef7e78e3ef24c735/output/types.go#L51-L74) and call [`output.RegisterExtension()`](https://github.com/loadimpact/k6/blob/2036baeaa83d76ce17aae95fef7e78e3ef24c735/output/extensions.go#L47) with your constructor.\n\nWe are working on the proper documentation for this, as well as the overdue xk6 documentation about JS extensions, so keep a lookout for those on [k6.io/docs](https://k6.io/docs/).\n\n\n### Marking requests as failed ([#1856](https://github.com/loadimpact/k6/pull/1856))\n\nIt's now possible to declare expected HTTP response statuses for either the entire test or for individual HTTP requests, and k6 will emit a new `http_req_failed` metric as well as tag HTTP metrics with `expected_response: <bool>`. By default, k6 will now fail requests that return HTTP 4xx/5xx response codes.\n\nFor example:\n\n```javascript\nimport http from 'k6/http';\n\n// Set expected statuses globally for all requests.\nhttp.setResponseCallback(http.expectedStatuses({min: 200, max: 399}, 418));\n\nexport default function () {\n  // This request will be marked as failed.\n  http.get('https://httpbin.test.k6.io/status/400');\n  // This request will be considered as \"passed\" because of the responseCallback override.\n  http.get('https://httpbin.test.k6.io/status/400', { responseCallback: http.expectedStatuses(400) });\n}\n```\n\nRunning this script will produce a summary like:\n\n```\nhttp_req_duration..............: avg=204.57ms min=203.31ms med=204.57ms max=205.82ms p(90)=205.57ms p(95)=205.7ms\n  { expected_response:true }...: avg=203.31ms min=203.31ms med=203.31ms max=203.31ms p(90)=203.31ms p(95)=203.31ms\nhttp_req_failed................: 50.00% ✓ 1   ✗ 1\n```\n\nNote the new `http_req_duration` sub-metric for expected responses only, and the new `http_req_failed` `Rate` metric. This new metric and metric tag have many potential use cases, and one of the most important ones is the ability to set better [thresholds](https://k6.io/docs/using-k6/thresholds). For example:\n- `'http_req_failed': ['rate<0.1']`, i.e. fail the test if more than 10% of requests fail.\n- `'http_req_duration{expected_response:true}': ['p(95)<300', 'p(99.9)<500']` - fail the test if the 95th percentile HTTP request duration is above 300ms or the 99.9th percentile is above 500ms; specifying `expected_response:true` here may be important, because a lot of times failed requests may return more quickly than normal ones, thus skewing the results and wrongly satisfying the threshold.\n\nIf the response callback is not specified, the default expected statuses will be `{min: 200, max: 399}`. The previous behavior of not emitting anything can be achieved by setting the callback to `null`, i.e. `http.setResponseCallback(null)`. Additionally, the `expected_response` tag can be disabled by removing it from the default list of [system tags](https://k6.io/docs/using-k6/options#system-tags), e.g. `k6 run --system-tags 'proto,subproto,status,method,url,name,group,check,error,error_code,tls_version,scenario,service'`.\n\nThe `http.setResponseCallback()` is planned to allow arbitrary JS functions to process responses in the future, but for now only the `http.expectedStatuses()` callback is supported.\n\n\n## Other enhancements and UX improvements\n\n- JS: Because of the awesome improvements to [goja](https://github.com/dop251/goja), the JS runtime k6 uses, it's no longer necessary for k6 to load [core.js](https://github.com/zloirock/core-js) to polyfill missing JS features when using the default [`--compatibility-mode=extended`](https://k6.io/docs/using-k6/javascript-compatibility-mode). So in v0.31.0 core.js has been dropped entirely, yielding some significant CPU and memory usage improvements. The actual numbers will depend on the use case, but for simple tests users can expect a memory drop of about 2MB per VU (from ~2.7MB to ~600KB), and a slight CPU decrease of about 5-10%. For more complex tests with a lot of JS code this benefit won't be as pronounced. Another benefit of this change is that initializing VUs and starting a test is substantially faster than before! ([#1824](https://github.com/loadimpact/k6/pull/1824))\n- JS: Also because of goja improvements, some unused Babel plugins were disabled which should have minor performance benefits as well. ([#1822](https://github.com/loadimpact/k6/pull/1822))\n- JS: Expanded `ArrayBuffer` support in most internal modules, so now you can pass `ArrayBuffer` to `http.file()`, in `k6/encoding` and `k6/crypto` functions. This makes working with binary files more efficient as it doesn't require string translations. In upcoming versions we plan to expand this to the WebSocket module, as well as make some potentially breaking changes for APIs that currently return an array of integers or string (see the details in the Breaking Changes announcement below). ([#1800](https://github.com/loadimpact/k6/pull/1800))\n- The Docker image base was updated to Alpine 3.13. Thanks @andriisoldatenko! ([#1821](https://github.com/loadimpact/k6/pull/1821))\n- The Debian package now includes `ca-certificates` as a dependency. Thanks @Bablzz! ([#1854](https://github.com/loadimpact/k6/pull/1854))\n\n\n## Bugs fixed!\n\n- Execution: Aborting a test during VU initialization (e.g. with `^C`) will now properly propagate to any used outputs. ([#1869](https://github.com/loadimpact/k6/pull/1869))\n- Execution: A race condition between the Engine and the outputs' finalization code was fixed, ensuring that all metrics are properly emitted before exiting. ([#1869](https://github.com/loadimpact/k6/pull/1869))\n- Execution: Another race condition in the Engine was fixed, which may have resulted in the end-of-test summary missing some of the last test metric data. ([#1888](https://github.com/loadimpact/k6/pull/1888))\n- Cloud: the test name is now properly validated and will raise an error if not set via the `ext.loadimpact.name` JS option or config, or the `K6_CLOUD_NAME` environment variable. ([#1870](https://github.com/loadimpact/k6/pull/1870))\n- JS: Babel is now also run on compilation errors, which improves support of some obscure language features. ([#1861](https://github.com/loadimpact/k6/pull/1861))\n- JS: `SharedArray` introduced in v0.30.0 can now be iterated with [`forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach). ([#1848](https://github.com/loadimpact/k6/pull/1848))\n\n\n## Internals\n\n- JS: `SharedArray` was rewritten using `goja.DynamicArray` making it more performant and easier to reason about. ([#1848](https://github.com/loadimpact/k6/pull/1848))\n- JS: Some TC39 tests for unsupported features were disabled, improving the runtime of the test suite. ([#1816](https://github.com/loadimpact/k6/pull/1816))\n- CI: Some more tests were enabled on Windows. ([#1855](https://github.com/loadimpact/k6/pull/1855))\n\n\n## Breaking changes\n\n- JS: While we don't expect the core.js removal and Babel changes to impact the vast majority of users, those were substantial changes in how k6 interprets JS and a minority of users might experience issues with their tests. Please report any unexpected JavaScript errors by creating a GitHub issue. In particular `Promise` is now `undefined`, and some unused Babel plugins like `transform-es2015-for-of` and `transform-regenerator` were also removed. This means that some workarounds like the ones mentioned [here](https://github.com/loadimpact/k6/issues/779#issuecomment-674311032) and [here](https://stackoverflow.com/a/65849645/96213) also won't work as is and will need additional polyfills and plugins to work properly.\n\n## Planned future breaking changes\n\nThe following are not breaking changes in _this_ release, but we'd like to announce them so users can prepare for them in upcoming releases (likely k6 v0.32.0).\n\n- JS: The `ArrayBuffer` changes in this release are backwards compatible and shouldn't cause any issues, but in v0.32.0 some JS APIs that currently return an array of integers or string for binary data will return `ArrayBuffer` instead. This is the case for `open()` when used with the `'b'` argument, response bodies for requests that specify `responseType: 'binary'`, `crypto.randomBytes()`, `hasher.digest('binary')`, and `encoding.b64decode()`. `Response.json()` and `Response.html()` will also probably stop working when used with requests that specify `responseType: 'binary'`. These changes shouldn't be a problem for most users that were simply using these values to pass them to other internal modules (e.g. opening a binary file and passing it to `http.post()`), but if the scripts modified the binary data or depended on the current array of integers or string values they will need to be adapted to use [typed arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays) instead. You can follow the discussion in [PR #1841](https://github.com/loadimpact/k6/pull/1841) and [issue #1020](https://github.com/loadimpact/k6/issues/1020).\n- As part of the rebranding of Load Impact to k6, the k6 GitHub repository will be moved from https://github.com/loadimpact/k6 to https://github.com/k6io/k6 . Additionally because of Go's usage of URLs in package imports, the URL will be changed throughout the codebase. Since GitHub will maintain a redirect from the old location we don't expect this to impact a lot of users, or even external k6 contributors and xk6 developers, but be aware that the new URL should be used moving forward.\n- Because of the [sunsetting of Bintray](https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/), the DEB, RPM, MSI and Chocolatey package repositories currently hosted on Bintray will be moved to a self-hosted solution sometime in the upcoming weeks. We'll communicate these changes via our [blog](https://k6.io/blog/) as well as the [official documentation](https://k6.io/docs/getting-started/installation).\n"
  },
  {
    "path": "release notes/v0.31.1.md",
    "content": "k6 v0.31.1 is a patch release with a single bugfix.\n\nThe bugfix is about the cloud output and the new `http_req_failed` metric in k6 v0.31.0. Due to additional state being used for its transport to the k6 cloud, and a misunderstanding of what a functional call from a library dependency does, the `http_req_failed` values were always set to `1`. This did not affect any other output or the end of test summary. ([#1908](https://github.com/loadimpact/k6/issues/1908))\n"
  },
  {
    "path": "release notes/v0.32.0.md",
    "content": "k6 v0.32.0 is here! :tada: It's a smaller release, featuring mostly chores that we never got to or that needed to be done in this release cycle, but also includes a significant performance improvement for arrival-rate executors and some breaking changes.\n\n## Move out of Bintray\n\nBintray has [stopped servicing users on 1st of May](https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/), which meant that we needed to move the deb and rpm repositories out of there before then. Please follow the new [installation instructions](https://k6.io/docs/getting-started/installation/) and the \"Note about Bintray\" to find out how to remove the old repository if you have used them.\n\n## Notable changes\n\n### Move all outputs to new Output interface introduced in v0.31.0 and other related changes\n\nWe started on this in the previous v0.31.0 release and now all internal outputs implement the new `Output` interface we provided for [xk6 output extensions](https://github.com/k6io/k6/blob/master/release%20notes/v0.31.0.md#output-cleanup-and-extensions-1874). Additionally one of the old built-in outputs is being deprecated and one renamed:\n\n1. The `kafka` output has been somewhat neglected since it was added 3 years ago. Additionally it brings a lot of complexity and isn't well understood by anyone on the team. Given that output extensions are possible since the last version, [the Kafka output has been moved to one](https://github.com/k6io/xk6-output-kafka). The built-in output will continue to work for a few more k6 versions, emitting a deprecation warning when used, so that everyone has time to transition to the extension. All future improvements will happen only in the extension, the built-in output is frozen until it's dropped.\n2. We are also deprecating/renaming the `datadog` output. It should've probably always been just a configuration of the `statsd` output and now in k6 v0.32.0, it is going to be just that. We've added a new `K6_STATSD_ENABLE_TAGS` option to the `statsd` output, which, when enabled (it's `false` by default), will send metric tags the same way the `datadog` output did before. That is, instead of using the `datadog` output, you should use the `statsd` one with `K6_STATSD_ENABLE_TAGS=true`. Additionally, the new `K6_STATSD_TAG_BLOCKLIST` option can be used to *not* send tags that the user doesn't want to, similar to the old `K6_DATADOG_TAG_BLACKLIST` option.\nThis makes it cleaner to also emit metrics to other services that accept the same data and tag formats, such as New Relic, Amazon Cloudwatch, and statsd >v0.9.0. The old `datadog` output will still work for a few k6 versions, emitting a warning to switch to `statsd` when used.\n\nApart from a message about them being deprecated, nothing should be changed from the actual refactoring yet, but we advise users to use the proposed alternatives starting with this release.\n\n#### `json` output emits thresholds defined on the metrics ([#1886](https://github.com/k6io/k6/pull/1886))\n\nPrevious to this change [thresholds](https://k6.io/docs/using-k6/thresholds/) were not included in the `json` output. Now the `Metric` JSON object will get its `thresholds` field properly populated.\n\nThanks to @codebien for this contribution!\n#### `cloud` output has an option to abort the test if aborted from the cloud ([#1965](https://github.com/k6io/k6/pull/1965))\n\nIn v0.26.0 we made the cloud output [stop emitting metrics](https://github.com/k6io/k6/pull/1130) if it gets a particular error from the backend, as that meant that the test was aborted in the cloud. Now we added `K6_CLOUD_ABORT_ON_ERROR` to be able to say that it should not only stop emitting metrics, but also stop the execution of the local k6 test run. The default configuration is `false`, so it is backwards compatible. This also works when the test is aborted by the user or if cloud execution limits are reached, which would also lead to the test being aborted.\n\n\n### Full stack traces for init context and setup/teardown exceptions ([#1971](https://github.com/k6io/k6/pull/1971))\n\nFor a long time, if there was an exception in either the init context or in the `setup()` or `teardown()` invocations, the stack trace would be just the last line, making it really hard to debug issues there. Now there is a full stack trace and, as such errors will result in aborted k6 execution, `k6 run` will also exit with exit code `107`, signalling a script error.\n\n\n### Considerable performance improvements for arrival rate executors ([#1955](https://github.com/k6io/k6/pull/1955))\n\nDue to a *wrong* re-usage for a particular internal data structure, the arrival rate executors were having a much worse performance than expected. With this release they should be a lot more performant, especially with large numbers of VUs.\n\n\n### Updating the majority of our dependencies and dropping some\n\nThe list is too long and we have been postponing updating for quite some time now, but we have finally updated all our dependencies that we don't want to drop. This could lead to some stability problems, which is why it was done early on in the cycle. While the team has not found any regressions, given all the updates we could have missed something so please [open a issue](https://github.com/k6io/k6/issues) if you find anything.\n\nSome notable updates:\n- goja, the JS engine we use got support for `let`/`const` which allowed us to disable a Babel plugin. Previous to this if you had a particularly *long* script sometimes Babel took upwards of 30 minutes to transpile. Now even our worst contender that previously took 51 minutes is transpiled in less than a minute :tada:. Also `globalThis` is now available.\n- updating the gRPC libraries fixed bug ([#1928](https://github.com/k6io/k6/issues/1928)) and probably others. ([#1937](https://github.com/k6io/k6/pull/1937))\n\n### `ArrayBuffer` is now supported in all JS APIs dealing with binary data, including in WebSocket messages ([#1841](https://github.com/k6io/k6/pull/1841))\n\nBesides the minor breaking changes (see the \"Breaking changes\" section below), it's now possible to send binary WS messages with the `socket.sendBinary()` function and to receive binary messages with the `binaryMessage` event handler:\n\n  ```javascript\n  const binFile = open('./file.pdf', 'b');\n\n  export default function () {\n    ws.connect('http://wshost/', function(socket) {\n      socket.on('open', function() {\n        socket.sendBinary(binFile);\n      });\n\n      socket.on('binaryMessage', function(msg) {\n        // msg is an ArrayBuffer, so we can wrap it in a typed array directly.\n        new Uint8Array(msg);\n      });\n    });\n  }\n  ```\n\n### Official arm64 releases for macOS and Linux ([#2000](https://github.com/k6io/k6/pull/2000))\n\nWe will now publish binary arm64 releases for macOS and Linux for new k6 releases. Support for these new architectures should be stable, given Go's cross-platform compatibility, but please report any issues you experience.\n\n## Other enhancements and UX improvements\n\n- Options: k6 will now warn you on unrecognised configuration JS options in most cases instead of just silently ignoring them. ([#1919](https://github.com/k6io/k6/pull/1919))\n- error_code: the tag `error_code` should now be set more accurately in some cases. ([#1952](https://github.com/k6io/k6/pull/1951))\n- TLS: dropped support for SSLv3 encryption. This was [dropped by Go](https://github.com/golang/go/issues/32716), but now we no longer consider `ssl3.0` a valid value for the `tlsVersion` k6 option. Thanks @codebien! ([#1897](https://github.com/k6io/k6/pull/1897))\n\n## Bugs fixed!\n\n- Arrival-rate executors could in some cases report twice as many used VUs than what was actually true. ([#1954](https://github.com/k6io/k6/issues/1954) fixed by [#1955](https://github.com/k6io/k6/pull/1955))\n- In cases of an error while reading the response body, the newly added `responseCallback` in v0.31.0 would be evaluated with the returned status code, while the reported one would be `0`, as the response errored out and k6 does not return incomplete responses. Now `responseCallback` will also receive a `0` status. ([#1962](https://github.com/k6io/k6/pull/1962))\n- Fix Kafka output not being usable with the InfluxDB format after v0.31.0 changes. ([#1914](https://github.com/k6io/k6/pull/1914))\n- Error out with a user friendly message if `ramping-vus` executor would've not run a single iteration instead of just doing nothing. ([#1942](https://github.com/k6io/k6/pull/1942))\n\n## Internals\n\n- JS: Added a way for JS modules to have per VU initialization and object. This can also be used by xk6 modules by implementing [`go.k6.io/k6/js/modules#HasModuleInstancePerVU`](https://pkg.go.dev/go.k6.io/k6/js/modules#HasModuleInstancePerVU). (Part of [#1911](https://github.com/k6io/k6/pull/1911))\n\n\n## Breaking changes\n\n### Support for `ArrayBuffer` in all k6 JS APIs ([#1841](https://github.com/k6io/k6/pull/1841))\n\nContinuing from k6 [v0.31.0](https://github.com/k6io/k6/releases/tag/v0.31.0), we're finalizing the transition to `ArrayBuffer` values for working with binary data. This release introduces some changes that might break scripts that relied on the previous `array of integers` or `string` result types, returned by some of our JS APIs. Specifically these cases now return `ArrayBuffer` instead: `open(..., 'b')`, HTTP response bodies for requests that specified `responseType: 'binary'` (including when `http.batch()` is used), `crypto.randomBytes()`, `hasher.digest('binary')` and `encoding.b64decode()`.\n  The previous default behavior of returning string from `encoding.b64decode()` can be replicated with a new optional `format` argument and a value of `\"s\"`: `encoding.b64decode(\"5bCP6aO85by-Li4=\", \"url\", \"s\")`.\n  Most of these shouldn't cause issues if the script is simply passing the values to another k6 API (e.g. opening a file as binary and passing it to `http.post()`), but in other cases the script will need to be modified to wrap the `ArrayBuffer` in a [typed array view](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays) and use that API instead.\n\n\n### Deprecating official 32-bit binary releases ([#2000](https://github.com/k6io/k6/pull/2000))\n\nWe have stopped offering official builds for 32-bit Windows and Linux binaries, as they were causing [issues in some cases](https://github.com/k6io/k6/issues/1979), and users were likely using them by mistake instead of necessity.\n\n### Moved repo and renamed k6 Go module paths to `go.k6.io/k6` ([#2010](https://github.com/k6io/k6/pull/2010))\n\nWe moved the repository location from https://github.com/loadimpact/k6 to https://github.com/k6io/k6. Instead of also moving the Go module paths to the new repo location, we decided to use custom ones with our own domain, for more control. This will be a breaking change for all [xk6](https://github.com/k6io/xk6) extensions, since they import parts of k6 by source to register themselves.\n\n### New `.deb` and `.rpm` repositories\n\nWe already mentioned this in the [v0.31.0](https://github.com/k6io/k6/releases/tag/v0.31.0) release, but because of the Bintray shutdown, we had to move our `.deb` and `.rpm` repositories. They are now located at [dl.k6.io](https://dl.k6.io/), and you can use the updated [installation instructions](https://k6.io/docs/getting-started/installation/) to transition to them.\n"
  },
  {
    "path": "release notes/v0.33.0.md",
    "content": "k6 v0.33.0 is here! :tada: It's a small release that includes a bunch of minor bugfixes and enhancements, but is also laying the groundwork for some major new features like the upcoming `k6/execution` API in k6 v0.34.0.\n\n## Acquired by Grafana Labs\n\nLoad Impact, the company behind k6, was acquired by Grafana Labs! :tada: Nothing changes regarding the k6 development for now, and any changes in the future will only be in the direction of accelerating our existing roadmap and plans, as well as better integration between k6 and the awesome Grafana tools. For more details, see the [official Grafana press release](https://grafana.com/about/press/2021-06-17-grafana-labs-brings-modern-open-source-load-testing-to-observability-with-acquisition-of-k6/).\n\n## Enhancements and UX improvements\n\n- The `--verbose` help message and the statsd warning message were improved ([#2005](https://github.com/k6io/k6/pull/2005)). Thanks, @vishalkuo!\n- The `noColor` k6 option and the current UI state are now propagated to the [`handleSummary()` function](https://k6.io/docs/results-visualization/end-of-test-summary/#handlesummary-callback). The `state` object has the `isStdErrTTY`, `isStdOutTTY` and `testRunDurationMs` keys ([#1975](https://github.com/k6io/k6/pull/1975)).\n- The error message when an HTTP request times out was improved (previously it was `context deadline exceeded`) and it now has an `error_code` value of `1050` ([#2008](https://github.com/k6io/k6/pull/2008)). Thanks, @vishalkuo!\n- Script errors will no longer have the confusing `GoError` prefix in their error messages ([#1775](https://github.com/k6io/k6/pull/1775)).\n- All [custom metric objects](https://k6.io/docs/javascript-api/k6-metrics/) now have a `name` property ([#2058](https://github.com/k6io/k6/pull/2058) and [#2076](https://github.com/k6io/k6/pull/2076)). Thanks, @olimpias and @david-gourde!\n- Top-level JS arrays will now be properly encoded when sent in the body of a `application/x-www-form-urlencoded` request ([#2060](https://github.com/k6io/k6/pull/2060)). Thanks, @noelzubin!\n\n## Bugs fixed!\n\n- The [`minIterationDuration`](https://k6.io/docs/using-k6/options/#minimum-iteration-duration) option was uninterruptible and could delay the stopping of a scenario even after `gracefulStop` had expired. ([#2035](https://github.com/k6io/k6/pull/2035)).\n- The `error_code` detection for HTTP/2, x509 and TLS (and potentially others) was unreliable ([#2025](https://github.com/k6io/k6/pull/2025)).\n- k6 used to panic when `responseType` was `binary`, but there was no response body actually returned, e.g. when there was an HTTP error ([#2041](https://github.com/k6io/k6/pull/2041)).\n- The [`throw` option](https://k6.io/docs/using-k6/options/#throw) was not respected when there was an invalid URL ([#2045](https://github.com/k6io/k6/pull/2045)). Thanks, @gchaincl!\n- k6 would return an exit code of `103` instead of `107` for script errors when initializing non-service VUs ([#2046](https://github.com/k6io/k6/pull/2046)).\n- Deleted library versions from cdnjs could previously cause a panic ([#2047](https://github.com/k6io/k6/pull/2047)).\n- The correct error message for missing files was not shown when the filename contained spaces ([#1973](https://github.com/k6io/k6/pull/1973)).\n- The regular expressions for the `github` and `cdnjs` \"magic\" loaders were slightly wrong ([#2066](https://github.com/k6io/k6/pull/2066)).\n- A potential (harmless) data race could have been caused by an unintentional copying of a data struct ([#2067](https://github.com/k6io/k6/pull/2067)).\n- The segmentation of small `ramping-arrival-rate` scenarios was not optimal ([#1863](https://github.com/k6io/k6/pull/1863#discussion_r655352623)).\n\n\n## Internals\n\n- The default end-of-test summary is now completely generated by the same [`k6-summary` JS code](https://jslib.k6.io/k6-summary/0.0.1/index.js) that is hosted on [jslib.k6.io](https://jslib.k6.io/) ([#1975](https://github.com/k6io/k6/pull/1975)). That PR also improved the k6 TTY detection and removed a few Go dependencies and code hacks, though it also caused us to bump the minimum required Go version for compiling k6 to Go 1.16 (because of its usage of [`go:embed`](https://golang.org/pkg/embed/)).\n- Arrival-rate executors will no longer create a new goroutine for every new iteration ([#1957](https://github.com/k6io/k6/pull/1957) and [#2038](https://github.com/k6io/k6/pull/2038)).\n- We have enabled GitHub's CodeQL checks for the Go parts of the repo ([#1961](https://github.com/k6io/k6/pull/1961)). Thanks, @jfcg!\n- We have added the necessary k6 core changes for providing execution information to scripts [#1863](https://github.com/k6io/k6/pull/1863)! This was the groundwork for the extended replacement of the [`__VU` and `__ITER` execution context variables](https://k6.io/docs/using-k6/execution-context-variables/) we plan to introduce. The new API will be able to return other information as well, for example which scenario the current iteration is in, what's the number of the current VU/iteration globally across all k6 instances, or in the current scenario, etc. These APIs are still not available to JS scripts, but we plan to expose them via the [`k6/x/execution` xk6 extension](https://github.com/k6io/xk6-execution) for now and iterate on them in the following weeks, releasing a stable version in k6 v0.34.0.\n\n\n## Breaking changes\n\n- The `k6 cloud` exit code for a failed cloud test was changed from `99` to `97` ([#2046](https://github.com/k6io/k6/pull/2046)).\n- The default value of `K6_STATSD_TAG_BLOCKLIST` and `K6_DATADOG_TAG_BLACKLIST` is now `vu,iter,url` ([#2063](https://github.com/k6io/k6/pull/2063)).\n- The `__ITER` execution context variable is no longer set in `setup()` and `teardown()` due to [#1863](https://github.com/k6io/k6/pull/1863). This might be better classified as removing a previously undefined behavior instead of a breaking change, but it's still worth mentioning.\n\n"
  },
  {
    "path": "release notes/v0.34.0.md",
    "content": "k6 v0.34.0 is here! :tada: It introduces the already announced `k6/execution` API and includes some more enhancements and a bunch of minor bug fixes.\n\n## New k6 JavaScript API - `k6/execution`\n\nThe [k6/execution](https://k6.io/docs/javascript-api/k6-execution) module allows the fetching of information about the current VU, instance (mostly relevant in distributed/cloud) or scenario execution state through a series of exported properties.\n\n### How to use\n\nSome of the previously suggested solutions with the globally available `__VU` and `__ITER` values, such as for [getting a unique object per iteration from an array](https://community.k6.io/t/when-parameterizing-data-how-do-i-not-use-the-same-data-more-than-once-in-a-test/42/2) or [`SharedArray`](https://k6.io/docs/javascript-api/k6-data/sharedarray/), can be done by using the `scenario.iterationInTest` property, which is guaranteed to be unique across VUs, even for distributed or cloud tests. For example:\n\n```js\nimport exec from \"k6/execution\";\nimport { SharedArray } from \"k6/data\";\n\nconst data = new SharedArray(\"my dataset\", function(){\n  return JSON.parse(open('my-large-dataset.json'));\n})\n\nexport const options = {\n  scenarios :{\n    \"use-all-the-data\": {\n      executor: \"shared-iterations\",\n      vus: 100,\n      iterations: data.length,\n      maxDuration: \"1h\"\n    }\n  }\n}\n\nexport default function() {\n  // this is unique even in the cloud\n  var item = data[exec.scenario.iterationInTest];\n  http.post(\"https://httpbin.test.k6.io/anything?endpoint=amazing\", item)\n}\n```\n\nYou can read the full documentation [here](https://k6.io/docs/javascript-api/k6-execution).\n\n## Enhancements and UX improvements\n\n* Warn Windows users on importing dependencies or opening files as absolute paths ([#2078](https://github.com/grafana/k6/pull/2078)).\n* Pass setup data object into [handleSummary callback](https://k6.io/docs/results-visualization/end-of-test-summary/#handlesummary-callback) ([#2103](https://github.com/grafana/k6/pull/2103)). Thanks, @SamuelJohnson01997!\n\n## Breaking changes\n\n* The deprecated outputs Datadog and Kafka have been removed ([#2081](https://github.com/grafana/k6/pull/2081)).\n\n## Bugs fixed!\n\n* Use the `POST` HTTP request method instead of `GET` for pushing logs to Loki ([#2100](https://github.com/grafana/k6/pull/2100)).\n* Encode the [`blacklistIPs` option](https://k6.io/docs/using-k6/options/#blacklist-ips) using the CIDR notation in JSON ([#2083](https://github.com/grafana/k6/pull/2083)).\n* `ext.loadimpact` option has the same precedence as the script configuration during the consolidation process ([#2099](https://github.com/grafana/k6/pull/2099)).\n* The WebSocket connection used for tailing logs from the k6 Cloud is reestablished in the case of an unexpected error ([#2090](https://github.com/grafana/k6/pull/2090)).\n\n## Internals\n\n* A simpler and clearer API has been added as an alternative to `common.Bind`, which also gives JS modules and extensions easy access to some [useful internal objects and runtime information](https://pkg.go.dev/go.k6.io/k6@v0.34.0/js/modules#Instance) ([#2108](https://github.com/grafana/k6/pull/2108)). This API is not yet stable, it's very likely to change more in future k6 versions.\n* Speeding ups TC39 tests using a pool of Babel compilers ([#1839](https://github.com/grafana/k6/pull/1839)).\n* Goja and some internal dependencies have been updated adding the native support for Arrow functions, Destructuring, Default arguments and Computed properties features. For the same reason, the relative Babel's plugins supporting those features are not required anymore so they have been disabled ([#2109](https://github.com/grafana/k6/pull/2109), [#2092](https://github.com/grafana/k6/pull/2092)).\n"
  },
  {
    "path": "release notes/v0.34.1.md",
    "content": "k6 v0.34.1 is a patch release with a few minor bugfixes:\n\n- There was a minor bug in the new [`k6/execution` API](https://k6.io/docs/javascript-api/k6-execution/) added to k6 v0.34.0 - some of its properties weren't usable with the [`externally-controlled` executor](https://k6.io/docs/using-k6/scenarios/executors/externally-controlled/) ([#2132](https://github.com/grafana/k6/pull/2132)).\n- goja, the JavaScript runtime that k6 uses, was updated to its latest version ([#2135](https://github.com/grafana/k6/pull/2135)), which fixed a couple of bugs:\n  - A newly introduced JS bug from k6 v0.34.0, where [rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) were undefined when the functions also had an internal lambda ([#2131](https://github.com/grafana/k6/issues/2131)). Thanks for reporting, @efdknittlfrank!\n  - An old JS bug, first introduced in k6 v0.28.0, which caused `Response.json()` to not have a `length` property when the response was a JSON array, i.e.`response.json().hasOwnProperty('length')` was returning `false` ([#2133](https://github.com/grafana/k6/issues/2133)). Thanks for reporting, @julien-sugg!\n"
  },
  {
    "path": "release notes/v0.35.0.md",
    "content": "k6 v0.35.0 is here! :tada: It introduces several new features that nicely enhance its usability and also contains a whole lot of fixes and ongoing efforts with refactoring.\n\nIn total, we have closed 14 issues. We have also branched out three new [xk6 extensions](https://k6.io/docs/misc/k6-extensions/) during this release :star:\n\n## New features\n\n### Ability to set VU-wide custom metric tags ([#2172](https://github.com/grafana/k6/pull/2172))\n\nk6 now supports setting tags for VUs as part of the Execution API with an easy key-value interface. These tags are attached to the metrics emitted by the VU. Example usage:\n\n```js\nimport http from 'k6/http';\nimport exec from 'k6/execution';\n\nexport const options = {\n    duration: '10s',\n    vus: 3,\n};\n\nexport default function () {\n    exec.vu.tags['mytag'] = 'value';\n    exec.vu.tags['vuId'] = exec.vu.idInTest;\n\n    console.log(`mytag is ${exec.vu.tags['mytag']} and my VU's ID in tags ${exec.vu.tags['vuId']}`);\n\n    // the metrics these HTTP requests emit will get tagged with `mytag` and `vuId`:\n    http.batch(['https://test.k6.io', 'https://test-api.k6.io']);\n}\n```\n\nOne of the most requested use cases for this feature is that now we can tag all metrics with the current stage number. [With a bit of JS code](https://github.com/grafana/k6/issues/796#issuecomment-959396841) it is possible to calculate which stage of a [`ramping-vus`](https://k6.io/docs/using-k6/scenarios/executors/ramping-vus/) or [`ramping-arrival-rate`](https://k6.io/docs/using-k6/scenarios/executors/ramping-arrival-rate/) scenario the VU is currently in. This in turn allows the setting of [thresholds](https://k6.io/docs/using-k6/thresholds/) only on the metrics that were emitted in specific stages of the test run! :tada:\n\nThere are some caveats, however: values can be only of `String`, `Number` or `Boolean` type, while values of other types will result either in a warning or an exception if [`throw` option](https://k6.io/docs/using-k6/options/#throw) is enabled. Additionally, given that k6 has a whole bunch of system tags, one should be careful with using them as keys. You can read complete information about VU tags in [`k6/execution` docs](https://k6.io/docs/javascript-api/k6-execution/#vu).\n\n### Initial basic support for JS promises\n\nWith the goja update in [#2197](https://github.com/grafana/k6/pull/2197), you can now make a `Promise` and chain it in your k6 scripts:\n\n```js\nexport default function () {\n    var p = new Promise((resolve, reject) => {\n        console.log('do something promising!');\n        reject('here');\n    });\n\n    p.then(\n        (s) => { console.log('fulfilled with', s) },\n        (s) => { console.log('rejected with', s) },\n    );\n}\n```\n\nIt must be noted that `Promise`s are not used by k6 itself yet but this addition is a stepping stone for implementing async functionality in future releases. Thanks, @dop251, for your awesome work in developing [goja](https://github.com/dop251/goja)! :heart:\n\n### Support for gRPC server reflection ([#2160](https://github.com/grafana/k6/pull/2160))\n\nk6's gRPC capabilities were extended with a support for server reflection which allows one to use gRPC even without a `proto` file at hand. In other words, the following script is now possible:\n\n```js\nimport grpc from 'k6/net/grpc';\nimport { check } from \"k6\";\n\nlet client = new grpc.Client();\n\nexport default () => {\n\tclient.connect(\"127.0.0.1:10000\", {plaintext: true, reflect: true})\n\tconst response = client.invoke(\"main.RouteGuide/GetFeature\", {\n\t\tlatitude: 410248224,\n\t\tlongitude: -747127767\n\t})\n\n\tcheck(response, {\"status is OK\": (r) => r && r.status === grpc.StatusOK});\n\tconsole.log(JSON.stringify(response.message))\n\n\tclient.close()\n}\n```\n\nYou can read more about the protocol [here](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md). Thanks, @joshcarp, for putting a lot of effort into this feature!\n\n### Other changes and UX improvements\n\n- Support for cookie jars in `k6/ws` ([#2193](https://github.com/grafana/k6/pull/2193)).\n- Forbid `metric.Add` calls to let `NaN` values through. Instead, k6 will log nice warnings or throw an exception if `--throw` is enabled ([#1876](https://github.com/grafana/k6/pull/1876), [#2219](https://github.com/grafana/k6/pull/2219)).\n- Support for compression in websockets ([#2162](https://github.com/grafana/k6/pull/2162)). Thanks, @cooliscool!\n- Switch to camel case for CLI options to the outputs ([#2150](https://github.com/grafana/k6/pull/2150)). Thanks, @JosephWoodward!\n- Much neater error message on `nil` response body ([#2195](https://github.com/grafana/k6/pull/2195)). Thanks, @daniel-shuy!\n\n## New xk6 extensions\n\n### xk6-browser\n\n[xk6-browser](https://github.com/grafana/xk6-browser) is a browser automation extension which relies on [Chrome Devtools Protocol](https://chromedevtools.github.io/devtools-protocol/). With xk6-browser, you can interact with the browser to test your web applications end-to-end while accessing all of the k6 core features, including protocol-level APIs and other k6 extensions. It’s a single tool for both protocol and browser-level testing.\n\nThe browser extension comes with an [API](https://k6.io/docs/javascript-api/k6-x-browser/) that aims for rough compatibility with the [Playwright API](https://playwright.dev/docs/api/class-playwright) for NodeJS, meaning k6 users do not have to learn an entirely new API.\n\n### xk6-output-remote-write\n\nPrometheus is now officially supported in k6 OSS with a [xk6-output-remote-write extension](https://github.com/grafana/xk6-output-prometheus-remote). This is an output extension with implementation for [Prometheus Remote-Write protocol](https://docs.google.com/document/d/1LPhVRSFkGNSuU1fBd81ulhsCPR4hkSZyyBj1SZ8fWOM/edit#heading=h.3p42p5s8n0ui) which means that beyond Prometheus, any compatible remote-write solution can be used with it. You can read the full guide to using the extension in the [relevant tutorial](https://k6.io/docs/results-visualization/prometheus/).\n\n### xk6-output-influxdb\n\nAfter hard work at working out how to integrate InfluxDB v2 API, it was decided to pull that integration into a new [xk6-output-influxdb extension](https://github.com/grafana/xk6-output-influxdb) [for now](https://github.com/grafana/k6/issues/1730#issuecomment-964239639). The built-in `influxdb` output in k6 still supports only InfluxDB v1, as before, with some minor optimizations ([#2190](https://github.com/grafana/k6/pull/2190)).\n\nPlease try out the new extensions and tell us what you think!\n\n## Breaking changes\n\n- The addition of common metrics registry ([#2071](https://github.com/grafana/k6/pull/2071)) no longer allows defining custom metrics with the same name as one of the builtin metrics, e.g. `new Counter(\"http_req_duration\")` will now abort. Similarly, an attempt to redefine a metric with the same name but with different type will error out. Builtin metrics may no longer be referenced as global objects in xk6 extensions either.\n- Fix inconsistency in environment variables' names: use `K6_NO_SETUP` and `K6_NO_TEARDOWN` options instead of `NO_SETUP` and `NO_TEARDOWN` ([#2140](https://github.com/grafana/k6/pull/2140)).\n- Module interfaces were changed as part of refactoring efforts. Any JS module that needs access to the VU must now implement the new interfaces. This change can impact some xk6 extensions ([#2234](https://github.com/grafana/k6/pull/2234)).\n\n## Bugs fixed!\n\n- Fix of a misleading sorting of custom submetrics in the default end-of-test summary ([#2198](https://github.com/grafana/k6/pull/2198)). Thanks, @knittl!\n- Fix for extensions depending on `afero.FS`: implement a newer version of the `afero.FS` interface for internal filesystems so that extension depending on that or newer version can be built ([#2216](https://github.com/grafana/k6/pull/2216)).\n- Fix for websockets: websockets now use the global `User-Agent` setting ([#2151](https://github.com/grafana/k6/pull/2151)). Thanks, @cooliscool!\n- Fixes for tests, Github actions, and Loki integration ([#2205](https://github.com/grafana/k6/pull/2205), [#2153](https://github.com/grafana/k6/pull/2153), [#2220](https://github.com/grafana/k6/pull/2220)).\n\n## Maintenance\n\n- Update a whole bunch of dependencies ([#2159](https://github.com/grafana/k6/pull/2159), [#2170](https://github.com/grafana/k6/pull/2170), [#2165](https://github.com/grafana/k6/pull/2165)).\n- Switch to Go 1.17 ([#2156](https://github.com/grafana/k6/pull/2156)). Thanks, @b5710546232!\n- Get rid of `mapstructure` ([#2223](https://github.com/grafana/k6/pull/2223)).\n- Minor but necessary cleanups ([#2164](https://github.com/grafana/k6/pull/2164), [#2192](https://github.com/grafana/k6/pull/2192)).\n\n## hacktoberfest\n\nk6 participated in this year's [hacktoberfest](https://github.com/grafana/k6/issues?q=is%3Aissue+label%3Ahacktoberfest+is%3Aclosed+milestone%3Av0.35.0) and we would like to thank all contributors! Here're some additional improvements made by the community members:\n\n- Add multi-message WebSockets tests ([#2184](https://github.com/grafana/k6/pull/2184)).\n- Try out the new and shiny Github forms which are already improving the formatting of k6's new issues ([#2174](https://github.com/grafana/k6/pull/2174),[#2179](https://github.com/grafana/k6/pull/2179)).\n- An improved writing style and correctness in our README ([#2189](https://github.com/grafana/k6/pull/2189), [#2152](https://github.com/grafana/k6/pull/2152), [#2169](https://github.com/grafana/k6/pull/2169), [#2181](https://github.com/grafana/k6/pull/2181)) and in some other places ([#2182](https://github.com/grafana/k6/pull/2182)).\n\nThank you, @knittl, @cooliscool, @JosephWoodward, @b5710546232, @nontw, @divshacker, @daniel-shuy, @Sayanta66, @marooncoder09, @idivyanshbansal, @saintmalik, @EricSmekens, for helping make k6 better :smile:"
  },
  {
    "path": "release notes/v0.36.0.md",
    "content": "k6 v0.36.0 is here! 🎉 It introduces a couple of new features which enhance its usability, includes a number of fixes, and the result of ongoing refactoring efforts.\n\n## New Features!\n\n### Source Maps support ([#2082](https://github.com/grafana/k6/pull/2082))\n\nFollowing [#2082](https://github.com/grafana/k6/pull/2082), k6 now has support for [Source Maps](https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map). k6 will try to load source maps either from the file system(s) or from inside the script, based on the standard(-ish) `//#sourceMappingURL=` comments. Furthermore, as k6 internally uses Babel to transform ES6+ scripts to ES5.1+, it will now make use of its ability to generate source maps, including combining with previously generated ones, to report correct line numbers. This should fix [#1804](https://github.com/grafana/k6/issues/1804); however, we anticipate some more issues will arise, and further tweaking will be necessary.\n\nThus, given an `imported.js` module such as:\n```javascript\nexport function f1() {\n  throw \"line 2\";\n}\n\n  throw \"line 6\";\n}\n\nexport function f3() {\n  throw \"line 10\";\n}\n```\n\nand a k6 test script importing it as such:\n```javascript\nimport { f2 } from \"./imported.js\"\n\nexport default function() {\n  f2();\n}\n```\n\nPrevious versions of k6 would report an error stack trace indicating an invalid line number in `imported.js` (10):\n```\nERRO[0000] line 6\n        at f2 (file:///some/path/imported.js:10:61(2))\n        at file:///some/path/sourcemap.js:4:20(4) executor=per-vu-iterations scenario=default source=stacktrace\n```\n\nStarting with `v0.36.0` and source maps support, k6 would now report the exception at the correct line in `imported.js`:\n```\nERRO[0000] line 6\n        at f2 (file:///some/path/imported.js:6:2(2))\n        at file:///some/path/loadtest.js:4:2(4)\n        at native executor=per-vu-iterations scenario=default source=stacktrace\n```\n\n#### Temporary warning\n\nNote that if a file size is greater than **250kb** and the internal Babel is needed, Babel will not generate source map. This is because during internal testing it was found this takes *3x* to *4x* more memory, potentially leading to OOM (standing for \"Out Of Memory\", a state in which the OS kills a process for using too much memory) on bigger inputs. If required, you can control the accepted file size limit via the temporary `K6_DEBUG_SOURCEMAP_FILESIZE_LIMIT=524288` environment variable; which will be removed after we no longer rely on Babel ([#2296](https://github.com/grafana/k6/issues/2296)). A pre-generated source map will always be loaded. For more details, check [#2345](https://github.com/grafana/k6/pull/2345).\n\n### Ability to abort tests ([#2093](https://github.com/grafana/k6/pull/2093))\n\nThanks to the contribution of @gernest ([#2093](https://github.com/grafana/k6/pull/2093)), k6 now has the ability to abort a test run from within the test script. The newly added `test.abort()` function in the [`k6/execution` module](https://k6.io/docs/javascript-api/k6-execution/) allows k6 scripts to immediately abort the test execution - the VU that called it will abort immediately and any other VUs in the same or other instances (in the case of `k6 cloud`) will also be interrupted and abort soon after. Local `k6 run` tests will exit with a code of `108`, so this event can also be easily detected in a CI script. \n\nAborting is possible during initialization:\n```javascript\nimport exec from \"k6/execution\";\nexec.test.abort();\n```\n\nAs well as inside the default function:\n```javascript\nimport exec from \"k6/execution\";\n\nexport default function() {\n  // Note that you can abort with a specific message too\n  exec.test.abort(\"this is the reason\");\n}\n\nexport function teardown() {\n  console.log(\"teardown will still be called after test.abort()\");\n}\n```\n\n### k6 inspect extended output ([#2279](https://github.com/grafana/k6/pull/2279))\n\nFollowing [#2279](https://github.com/grafana/k6/pull/2279), the `k6 inspect` command now supports an `--execution-requirements` flag. When used, the command's output will include fields related to the execution requirements, by deriving k6's configuration from the execution context, and including the `maxVUs` and `totalDuration` fields in the output.\n\n\n### Forcing HTTP/1 protocol ([#2222](https://github.com/grafana/k6/pull/2222))\n\nThanks to the work of @sjordhani22, [#2222](https://github.com/grafana/k6/pull/2222) made it possible to force k6 to use version 1.1 of the protocol when firing HTTP requests. \n\nIt can be done by setting the `http2client=0` value in the `GODEBUG` environment variable:\n\n```\nGODEBUG=http2client=0 k6 run testscript.js\n```\n\n**N.B**: the usage of the `GODEBUG` variable is considered temporary, and expected to change in the future. If you start using this feature, keep an eye out for potential future changes.\n\n## Extensions\n\n`v0.36.0` marks the switch of some of our internal modules to [a new Go/JavaScript module API](https://k6.io/docs/extensions/guides/create-an-extension/#advanced-javascript-extension). We expect this change to make the process of developing internal JavaScript modules and advanced JavaScript extensions easier and more streamlined in the future. Although this switch to a new API does not introduce breaking changes for existing extensions yet, we anticipate deprecating the old extension API (e.g. `common.Bind()`, `lib.WithState()`, etc.) at an undecided point in the future.\n\nFor more details, see: [#2243](https://github.com/grafana/k6/pull/2243), [#2241](https://github.com/grafana/k6/pull/2241), [#2239](https://github.com/grafana/k6/pull/2239), [#2242](https://github.com/grafana/k6/pull/2242), [#2226](https://github.com/grafana/k6/pull/2226), and [#2232](https://github.com/grafana/k6/pull/2232).\n\n## Breaking changes\n\n### Restricting file opening to init context\n\nVUs are now restricted to only `open()` files that were also opened in the [init context](https://k6.io/docs/using-k6/test-life-cycle/#init-and-vu-stages) of the first VU - the one that was initialized to get the exported `options` from the JS script (`__VU==0`). While it was somewhat possible to open files *only* in other *VUs* (*e.g* `__VU==2`) in the past, it was [unreliable](https://github.com/grafana/k6/issues/1771). [#2314](https://github.com/grafana/k6/pull/2314) ensures that k6 would now throw an error in a similar scenario. This means that you can still open files only for some VUs, but you need to have opened all of those files in the initial VU (`__VU==0`).\n\n```javascript \nlet file;\n\nif (__VU == 0) {\n  open(\"./file1.bin\")\n  open(\"./file2.bin\")\n} else if (__VU % 2 == 0) {\n  file = open(\"./file1.bin\")\n} else {\n  file = open(\"./file2.bin\")\n}\n\nexport default () => {\n  // use file for something\n}\n```\n\n## Bugs Fixed!\n\n\n* We addressed an issue uncovered by [our community](https://community.k6.io/t/v0-35-0-grpc-server-reflection-error/2383), which kept our users from using GRPC with multiple services definition in a single *proto* file. This issue was solved in [#2265](https://github.com/grafana/k6/pull/2265).\n* Thanks to the contribution of @Resousse, we've now updated k6's [`go-ntlmssp`](https://github.com/Azure/go-ntlmssp) dependency. The updating PR [#2290](https://github.com/grafana/k6/pull/2290) indeed fixes issues with NTLM Authentication backends returning two authorization headers. \n\n## Maintenance\n\n- We have refactored our implementation of the RampingVU executor, for better clarity and maintainability. See [#2155](https://github.com/grafana/k6/pull/2155).\n- [#2316](https://github.com/grafana/k6/pull/2316) relaxed quite a few of the code linting rules we applied to k6's code. It also revamped our Makefile, so the new `make ci-like-lint` target will run the exact same [golangci-lint](https://github.com/golangci/golangci-lint) version that will be used in our GitHub Actions CI pipeline.\n- [#2304](https://github.com/grafana/k6/pull/2304) prepared the removal of external dependencies from k6's JSONAPI compliant REST API, and deprecated the `api.v1`'s `client.Call` method in favor of its newer `client.CallAPI` counterpart. It allows us to both reduce our reliance on external dependencies and improve its maintainability.\n- We have updated our [Goja](https://github.com/dop251/goja) dependency, our JS interpreter, to its latest available version. Unfortunately, some of the new features are not always usable, yet. Namely, Goja now supports the [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) syntax, but the Babel version we use presently does not. Which means that if Babel needs to be used, optional chaining can't be. See [#2317](https://github.com/grafana/k6/pull/2317) and [#2238](https://github.com/grafana/k6/pull/2238).\n- Thanks to @knittl, [#2312](https://github.com/grafana/k6/pull/2312) upgraded [loadimpact/k6](https://hub.docker.com/r/loadimpact/k6) docker image base to Alpine *3.15*.\n\n\n# Known Bugs\n\n- [#2226](https://github.com/grafana/k6/pull/2226) introduced an unintended breaking change to `http.head()`. The signature in k6 v0.35.0 was `http.head(url, [params])` and was inadvertently changed to `http.head(url, [body], [params])` in v0.36.0. That change will be reverted in k6 v0.37.0, but until then, we suggest users use the stable `http.request('HEAD', url, null, params)` API for HTTP HEAD requests that need to specify custom [parameters](https://k6.io/docs/javascript-api/k6-http/params). Thanks, @[grantyoung](https://github.com/grantyoung), for reporting the problem ([#2401](https://github.com/grafana/k6/issues/2401))!\n"
  },
  {
    "path": "release notes/v0.37.0.md",
    "content": "k6 v0.37.0 is here! 🎉 Mainly it contains fixes and ongoing efforts with refactoring.\n\n## New Features!\n\n### Added experimental basic event loop ([#882](https://github.com/grafana/k6/issues/882))\n\nWe added basic event loop support in k6 ([#2228](https://github.com/grafana/k6/pull/2228) and [#2373](https://github.com/grafana/k6/pull/2373)) :tada: This was just the first step and isn't used by any of the existing k6 JS APIs yet. For now, it is only available to [xk6 extensions](https://k6.io/docs/extensions/guides/what-are-k6-extensions/) like [this one](https://github.com/MStoykov/xk6-events) that adds support for `setTimeout()`, `setInterval()`, `clearTimeout()` and `clearInterval()`.\n\nExpect to see more changes related to event loops in the next k6 releases, where event loops will start being used by some core k6 modules! For example, by improving some existing JavaScript APIs to have support for callbacks or return `Promise` values, so they can be used asynchronously. We expect this change will unlock a lot of previously difficult use cases (see [#882](https://github.com/grafana/k6/issues/882)), though we'll likely iterate on these new APIs as experimental extensions for a while, to stabilize them before we merge them into the core.\n\n:information_source: If you are an extension developer, please use it and give your feedback. But take into consideration that it's likely that the current Go API may change.\n\n### Added an option to output k6 logs to a file through --log-output ([#2285](https://github.com/grafana/k6/pull/2285))\n\nThis is on top of the already supported options for sending logs to stdout/stderr and to [Grafana Loki](https://grafana.com/oss/loki/). This new feature speaks for itself with simple usage examples:\n\n```sh\nk6 run --log-output file=./k6.log --logformat json ./examples/stages.js\n```\n\nAnd one more with a defined minimal log level:\n\n```sh\nk6 run --log-output file=./k6.log,level=info --logformat json ./examples/stages.js\n```\n\nThanks, @[alyakimenko](https://github.com/alyakimenko) for the contribution!\n\n**Docs**: [Using file output](https://k6.io/docs/using-k6/options/#file)\n\n## Breaking changes\n\n### Introduced stricter thresholds parsing ([#2400](https://github.com/grafana/k6/pull/2400))\n\nIn the past, thresholds were evaluated using a JavaScript runtime. For a multitude of reasons, this wasn't satisfying. As of **v0.37.0**, thresholds are now parsed directly in Go. As a result, k6 will now return an error message on thresholds that do not strictly match [the documented specification](https://k6.io/docs/using-k6/thresholds/), instead of just silently ignoring them. Another change is that when a non syntactically correct threshold expression is detected, k6 will immediately interrupt its execution before even starting the load test run.\n\nBelow you can find examples of the thresholds expressions that won't work anymore:\n\n```js\nexport const options = {\n    thresholds: {\n        \"http_req_duration\": [\n            // although the aggregation method and values are correct, \n            // the equal sign is invalid; use == or ===\n            \"rate=200\",\n            // thresholds do not support javascript expressions anymore\n            \"throw new Error('wat')\",\n            // it fails, as foo is not a valid threshold expression's aggregation method keyword\n            \"foo>500\",\n        ],\n    },\n};\n```\n\n### Extensions\n\n`v0.37.0` finalizes ([#2376](https://github.com/grafana/k6/pull/2376)) the switching of our internal modules ([gRPC module refactoring](https://github.com/grafana/k6/pull/2365)) to [a new Go/JavaScript module API](https://k6.io/docs/extensions/guides/create-an-extension/#advanced-javascript-extension).\n\n:warning: It's important to highlight that the old API (e.g. methods like `context.WithRuntime`, `common.Bind` and others [#2384](https://github.com/grafana/k6/pull/2384)) is deprecated and will be removed in the next k6 release (`v0.38.0`). For this release, every extension that isn't using the new API will get a warning message like this:\n\n```sh\nWARN[0000] Module 'k6/x/sql' is using deprecated APIs that will be removed in k6 v0.38.0, for more details on how to update it see https://k6.io/docs/extensions/guides/create-an-extension/#advanced-javascript-extension\n```\n\nWe did migrations for some xk6 extensions (see connected issues to the task [#2344](https://github.com/grafana/k6/issues/2344)). The pull requests can serve as examples on how to transition your extension to the new API.\n\n### Docker Repository\n\nWe migrated our Docker Hub repository from `loadimpact/k6` to [grafana/k6](https://hub.docker.com/r/grafana/k6) ([#2377](https://github.com/grafana/k6/pull/2377)).\n\n```sh\ndocker run -i grafana/k6 run - <script.js\n```\n\nWe will continue publishing our docker image releases as both `loadimpact/k6` and `grafana/k6` for several more releases, but if you use the old one in your local or CI environments, please plan the migration.\n\n## Enhancements and UX improvements\n\n- We continued work on the source map feature: add samples ([#2339](https://github.com/grafana/k6/pull/2339)) and improve loading and parsing ([#2355](https://github.com/grafana/k6/pull/2355)).\n- Updated installation from source instructions ([#2359](https://github.com/grafana/k6/pull/2359)). Thanks, @[karitham](https://github.com/Karitham), for making the change.\n- Enabled more TC39 tests: [optional-chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) ([#2338](https://github.com/grafana/k6/pull/2338)) and async ([#2396](https://github.com/grafana/k6/pull/2396)).\n- We updated our [Code of Conduct](https://github.com/grafana/k6/blob/master/CODE_OF_CONDUCT.md) and a few GitHub URLs ([#2416](https://github.com/grafana/k6/pull/2416)).\n\n## Bugs fixed!\n\n- [`http.head`](https://k6.io/docs/javascript-api/k6-http/head-url-params/) started taking a body as a second argument ([#2402](https://github.com/grafana/k6/pull/2402)) by mistake in v0.36.0. It is now back to its old signature `http.head(url, [params])`.\n- Fixed [options.scenarios'](https://k6.io/docs/using-k6/options/#scenarios) JSON marshaling ([#2392](https://github.com/grafana/k6/pull/2392)).\n- Metrics' names display again in k6's Rest API ([#2421](https://github.com/grafana/k6/pull/2421)).\n- We improved argument validation for [`check`](https://k6.io/docs/javascript-api/k6/check-val-sets-tags)([#2387](https://github.com/grafana/k6/pull/2387)), [`http.batch`](https://k6.io/docs/javascript-api/k6-http/batch-requests)([#2415](https://github.com/grafana/k6/pull/2415)) and [metrics' constructors](https://k6.io/docs/javascript-api/k6-metrics/) ([#2427](https://github.com/grafana/k6/pull/2427)).\n\n## Internals\n\n- We updated our CI to improve developer experience. Dependency and linter checks now run only for pull requests ([#2403](https://github.com/grafana/k6/pull/2403)).\n- This release also contains a few refactoring PRs that fix linters errors ([#2334](https://github.com/grafana/k6/pull/2334), [#2331](https://github.com/grafana/k6/pull/2331) and [#2341](https://github.com/grafana/k6/pull/2341)), remove global variable usage ([#2336](https://github.com/grafana/k6/pull/2336), [#2358](https://github.com/grafana/k6/pull/2358), [#2353](https://github.com/grafana/k6/pull/2353) and [#2357](https://github.com/grafana/k6/pull/2357)) and remove an unnecessary dependency ([#2313](https://github.com/grafana/k6/pull/2313)) which makes our codebase more consistent and maintainable.\n- The `headers` parameter in k6's GRPC module is marked as deprecated ([#2370](https://github.com/grafana/k6/pull/2370)).\n- Switched `envconfig` to our own fork ([#2337](https://github.com/grafana/k6/pull/2337)) in order to abstract the `os` package and improve testability.\n"
  },
  {
    "path": "release notes/v0.38.0.md",
    "content": "k6 v0.38.0 is here! 🎉\n\n## New Features!\n\n### AWS JSLib\n\nThere's a new addition to the officially supported k6 JavaScript libraries: [k6-jslib-aws](https://github.com/grafana/k6-jslib-aws).\nThis library lets users interact with a selection of AWS services directly from their scripts. The library currently implements support for the [S3](https://k6.io/docs/javascript-api/jslib/aws/s3client/) and the [Secrets Manager](https://k6.io/docs/javascript-api/jslib/aws/secretsmanagerclient/) services.\n\n[The AWS JS lib documentation](https://k6.io/docs/javascript-api/jslib/aws) has examples and details on how to use the library in your scripts.\n\n### Accessing the consolidated and derived options from the default function ([#2493](https://github.com/grafana/k6/pull/2493))\n\nThe `k6/execution` core module now lets you access the [consolidated and derived](https://k6.io/docs/using-k6/options/#where-to-set-options) options that k6 computed before it started executing the test. You can access consolidated options through the `exec.test.options` property. Note that consolidated options are frozen and cannot be modified. [The k6 execution module's documentation](https://k6.io/docs/javascript-api/k6-execution/#test) has examples and details on how to use the functionality in your scripts.\n\n```javascript\nimport exec from \"k6/execution\";\n\nexport const options = {\n    vus: 10,\n    duration: \"30s\",\n};\n\nexport default function () {\n    console.log(exec.test.options.scenarios.default.vus); // 10\n}\n```\n\n### Tagging metric values with the current scenario stage\n\nWith the new consolidated script options, we've added a few helper functions to the [k6-jslib-utils](https://k6.io/docs/javascript-api/jslib/utils) library. You can use them to automatically tag all the emitted metric samples by k6 with the currently running stage.\n\n[The k6 documentation](https://k6.io/docs/using-k6/tags-and-groups/#tagging-stages) has examples and details on how to use it.\n\n### Dumping SSL keys to an NSS formatted key log file ([#2487](https://github.com/grafana/k6/pull/2487))\n\nThis release adds the ability to dump SSL keys while making TLS connections.\nYou then can use these keys to decrypt all traffic that k6 generates.\n\nTo accomplish this, set the `SSLKEYLOGFILE` environment variable to some file path and run k6.\nThis will populate the file with the keys.\nThen you can use Wireshark to capture the traffic, decrypt it, and use that for debugging.\n\n[Here's an example that uses curl to inspect TLS traffic](https://daniel.haxx.se/blog/2018/01/15/inspect-curls-tls-traffic/).\n\n## Breaking Changes\n\n### `console` methods now pretty print objects and arrays ([2375](https://github.com/grafana/k6/pull/2375))\n\nFor convenience, all `console` methods such as `console.log()` and `console.info()` will now automatically `JSON.stringify()` objects and arrays passed to them. Thus, instead of `console.log({'foo': 'bar'})` printing `[object Object]`, it will now print `{'foo': 'bar'}`, which will make the experience of debugging k6 scripts easier and more intuitive.\n\nTo achieve the previous behavior, cast the `Object` to a `String`, as in `console.log(String({'foo': 'bar'}))`.\n\n```javascript\nexport default function () {\n    console.log([1, 2, \"test\", [\"foo\", \"bar\"], { user: \"Bob\" }]);\n    // before: 1,2,test,foo,bar,[object Object]\n    // after: [1,2,\"test\",[\"foo\",\"bar\"],{\"user\":\"Bob\"}]\n}\n```\n\n### The Go types in the `stats` package were moved to the `metrics` package [#2433](https://github.com/grafana/k6/pull/2433)\n\nFor convenience and to facilitate further developments, the types and functionalities that used to live in k6's `stats` package have been moved to the `metrics` package. The `stats` package is, as of **v0.38.0**, removed in favor of the `metrics` package. Besides, [#2442](https://github.com/grafana/k6/pull/2442) removed the `stats.New` function in favor of initializing new metric via a `register.NewMetric` call instead.  \n\n### Deprecation\n\n-   [#2499](https://github.com/grafana/k6/pull/2499) removed support for the deprecated maxVUs option.\nIt had been removed in k6 v0.27.0, however using the CLI flag resulted only in a deprecation warning.\nNow, using this flag will generate an error.\n-   This release drops some leftovers from the previous version of our JS module Go APIs. As of **v0.38.0**, these are now unsupported:\n    -   The deprecated `common.Bind` ([#2488](https://github.com/grafana/k6/pull/2448)) and `common.BindToGlobal` ([#2451](https://github.com/grafana/k6/pull/2451)) functions.\n    -   The context-based (`common/context.go` [#2488](https://github.com/grafana/k6/pull/2448)) utils have also been removed.\n\n## Enhancements and UX improvements\n\n### Stricter thresholds' evaluation before the execution starts ([#2330](https://github.com/grafana/k6/issues/2330))\n\nk6 **v0.37.0** already improved threshold parsing by switching its underlying implementation from JavaScript to Go. k6 **v0.38.0** introduces two additional improvements:\n\n-   k6 will now parse and evaluate thresholds before the execution starts. If a threshold is invalid, as described below, k6 will immediately exit without starting the load test.\n-   k6 will now detect invalid thresholds:\n    ```javascript\n    export const options = {\n        // ...\n        thresholds: {\n            // Incorrect thresholds expressions:\n            http_req_failed: [\"rave<0.01\"], // e.g. \"rave\" is not a valid aggregation method\n            // Thresholds applying to a non-existing metrics:\n            iDoNotExist: [\"p(95)<200\"], // e.g. the metric 'iDoNotExist' does not exist\n            // Thresholds applying an aggregation method that's unsupported by the metric they apply to:\n            my_counter: [\"p(95)<200\"], // Counter metrics do not support the p() aggregation method\n        },\n    };\n    ```\n\n### Disabling colors ([#2410](https://github.com/grafana/k6/pull/2410))\n\nIn addition to the [`--no-color` CLI flag](https://k6.io/docs/using-k6/options/#no-color), the ANSI color escape codes emitted by k6 can now also be disabled by setting the `NO_COLOR` or `K6_NO_COLOR` environment variables, following the [NO_COLOR standard](https://no-color.org/).\n\n```bash\n# No color output\nK6_NO_COLOR=true k6 run script.js\n\n# No color output\nNO_COLOR= k6 run script.js\n```\n\n### Support for encrypted TLS private keys ([#2488](https://github.com/grafana/k6/pull/2488))\n\nYou can now use passphrase-protected private keys when authenticating with TLS. Using the `password` property of an options' `tlsAuth` object, you can now indicate the passphrase to decrypt a private key. Note that this support is limited to the scope of [RFC1423](https://datatracker.ietf.org/doc/html/rfc1423) and does not support PKCS8 keys, as they're not yet supported by the Golang standard library.\n\n```javascript\nexport const options = {\n    tlsAuth: [\n        {\n            domains: [\"example.com\"],\n            cert: open(\"mycert.pem\"),\n            key: open(\"mycert-key.pem\"),\n            password: \"mycert-passphrase\",\n        },\n    ],\n};\n```\n\nThanks, @Gabrielopesantos, for the [contribution](https://github.com/grafana/k6/pull/2488).\n\n### Improve JSON output's performance ([#2436](https://github.com/grafana/k6/pull/2436))\n\nThe JSON output was optimized and now should be around 2x more performant at outputting metrics. This means that it either can export twice as many metrics, or use half the resources to do the same amount of metrics.\n\nAs a side effect, there is a slight breaking change: the `tags` field is no longer sorted.\n\n### Treat panics as interrupt errors ([#2453](https://github.com/grafana/k6/pull/2453))\n\nWe changed the behavior of how k6 treats Go panics, which may happen because of bugs in k6 or in a JavaScript k6 extension. Previously, the behavior was to catch the panic and log it as an error.\n\nStarting with **v0.38.0**, whenever k6 observes a Go panic, it logs an error like before, but more importantly, it will abort the script execution and k6 will exit with a non-0 exit code. This will help extension authors to identify issues in their extensions more easily.\n\n### Miscellaneous\n\n-   [#2411](https://github.com/grafana/k6/pull/2411) The k6 command-line UI (logo, test description, and progress bars) can now effectively be disabled using the [`--quiet`](https://k6.io/docs/using-k6/options/#quiet) flag.\n-   [#2429](https://github.com/grafana/k6/pull/2429) `lib/types` now exposes the source of the `NullHostnameTrie` to simplify access to an original list of the hostnames.\n\n## Extensions\n\n### PoC for a new Web Sockets JS API\n\nWe built a new xk6 extension, https://github.com/grafana/xk6-websockets, with a proof of concept implementation for a new JavaScript Web Sockets API. This API uses the global event loops [introduced in k6 v0.37.0](https://github.com/grafana/k6/releases/tag/v0.37.0) to allow a single VU to have multiple concurrent web socket connections open simultaneously, greatly reducing the resources needed for large tests. It also is a step towards supporting the [official Web Sockets JS standard](https://websockets.spec.whatwg.org/), potentially allowing the usage of more third-party JS libraries in the future.\n\nPlease share any feedback you have about the new extension since it's likely that we'll adopt a future version of it into the k6 core in one of the next several k6 releases.\n\n### gRPC module refactored to enable gRPC extensions to use it\n\n[#2484](https://github.com/grafana/k6/pull/2484) moved out in a new dedicated Go `lib/netext/grpcext` package all the parts not strictly required from the `js/k6/net/grpc` module for binding the gRPC operations and the JavaScript runtime. It facilitates the development of extensions based on gRPC without the direct dependency on the `goja` runtime. Furthermore, the new [Dial](https://github.com/grafana/k6/blob/bef458906f6884a99843573223028981c0a8b8db/lib/netext/grpcext/conn.go#L72-L81) function accepts a [grpc.DialOption](HTTPS://pkg.go.dev/google.golang.org/grpc@v1.45.0#DialOption) variadic for customizing the dialing operation.\n\n### Event loop testing\n\nWith this release, you can [export the event loop](https://pkg.go.dev/go.k6.io/k6/js/eventloop) added in v0.37.0. This lets extension developers test event-loop-dependent APIs.\n\nThere were also updates to [modulestest.VU](https://pkg.go.dev/go.k6.io/k6/js/modulestest#VU) to support the new API. Head to GitHub to [see it in action](https://github.com/grafana/k6/tree/master/cmd/integration_tests/testmodules/events).\n\n## Bugs Fixed!\n\n-   [#2456](https://github.com/grafana/k6/pull/2456): Fixed a very unlikely panic involving arrival rate executors and execution segments with very low VU counts.\n-   [#2349](https://github.com/grafana/k6/issues/2349): Thanks to @rainingmaster it is now possible to leave the options' tlsAuth `domains` property empty.\n-   [#1346](https://github.com/grafana/k6/issues/1346): Thresholds over custom metrics for which no data was collected will now be evaluated.\n-   [#2390](https://github.com/grafana/k6/issues/2390): Thresholds over sub-metrics with empty tag values will now return the appropriate results.\n-   [#2480](https://github.com/grafana/k6/issues/2480): Fixed an error occurring when passing the `data` property of an `http.file()` result as a request body.\n\n## Known issues\n\n-   @hecnavsanz [reported to us](https://github.com/grafana/k6/issues/2500) that in certain scenarios, k6's UI might inaccurately report a test as failed :x: when it actually succeeded :white_check_mark:. This is caused by some concurrency issue in our codebase that only affects the report's UI, and has no impact on the actual test result. A [fix](https://github.com/grafana/k6/pull/2502) is in the works, but won't be ready for this version. We expect to ship it with the next k6 release instead.\n\n## Maintenance\n\n### Dependencies\n\n-   [#2479](https://github.com/grafana/k6/pull/2479) updated k6's Goja version to `9037c2b61cbf`.\n-   [#2449](https://github.com/grafana/k6/pull/2449), [#2446](https://github.com/grafana/k6/pull/2446), [#2444](https://github.com/grafana/k6/pull/2444), and [#2443](https://github.com/grafana/k6/pull/2443) updated k6 Go dependencies to their latest compatible versions.\n\n### Other\n\n-   [#2504](https://github.com/grafana/k6/pull/2504) updated our installation instructions to reflect the recent changes in the behavior of the `go install` command. Thanks, @JamieEdge, for your contribution!\n-   [#2437](https://github.com/grafana/k6/pull/2437) refreshed our contribution guidelines.\n-   [#2431](https://github.com/grafana/k6/pull/2437) refreshed out our dependencies update workflow, process, and guidelines.\n"
  },
  {
    "path": "release notes/v0.38.1.md",
    "content": "k6 v0.38.1 is a patch release containing a bugfix!\n\n### Threshold sub-metric selectors containing reserved symbols would fail ([#2512](https://github.com/grafana/k6/issues/2512))\n\nThere was a bug in threshold sub-metric selector parsing, which led to errors when users would use specific symbols such as `{`, `}` or `:` as part of their definitions. For instance, thresholds used for sub-metrics with [URL Grouping](https://k6.io/docs/using-k6/http-requests/#url-grouping) like `http_req_duration{name:\"http://example.com/${}\"}` would have led to failures in `v0.38.0`. \n\nThe error messages for invalid metric, sub-metric and threshold definitions were also improved.\n\nSpecial thanks to @efdknittlfrank, who reported and helped us track down the issue.\n"
  },
  {
    "path": "release notes/v0.38.2.md",
    "content": "k6 v0.38.2 is a patch release containing a couple of bugfixes!\n\n### Threshold over sub-metrics without samples would result in `NaN` ([#2520](https://github.com/grafana/k6/issues/2520))\n\nThere was a bug in thresholds applied to sub-metrics set to `abortOnFail`: leading k6 to evaluate thresholds that would have likely aborted before they had a chance of passing (because no samples for the given metric were recorded yet). This bug would have led to such thresholds' results value to be `NaN` rather than a numerical value. The following script, for instance:\n\n```javascript\nimport { check, sleep } from 'k6';\n\nimport http from 'k6/http';\n\nexport const options = {\n  scenarios: {\n    iWillFail: {\n      exec: 'iWillFail',\n      executor: 'constant-vus',\n      startTime: '2s',\n      vus: 1,\n      duration: '30s',\n    },\n  },\n\n  thresholds: {\n    'checks{type:read}': [{ threshold: 'rate>0.9', abortOnFail: true }],\n  },\n};\n\nexport function iWillFail() {\n  let res = http.get(`https://test-api.k6.io/`);\n\n  check(res, {\n    'read status is 200': (r) => r.status === 200,\n  }, { type: 'read' });\n\n  sleep(1);\n}\n```\n\n\nWould result in the following:\n\n```\n✗ { type:read }...: NaN% ✓ 0 ✗ 0  \nvus...............: 0 min=0 max=0\nvus_max...........: 1 min=1 max=1\n```\n\nThis issue was introduced by recent changes to how we handle thresholds in the k6 engine and is now addressed in `v0.38.2`.\n\n### Sub-metrics without values rendered below an incorrect parent metric ([#2518](https://github.com/grafana/k6/issues/2518))\n\nThere was in how thresholds over sub-metrics that didn't receive any samples would be displayed under an incorrect parent metric. For instance, the following script:\n\n```javascript\nimport { Counter } from 'k6/metrics';\n\nconst counter1 = new Counter(\"one\");\nconst counter2 = new Counter(\"two\");\n\nexport const options = {\n    thresholds: {\n        'one{tag:xyz}': [],\n    },\n};\n\nexport default function() {\n    console.log('not submitting metric1');\n    counter2.add(42);\n}\n```\n\nWould have led to the following output, where the {tag:xyz} sub-metric is displayed under `iterations` instead of `one`:\n\n```\ndata_received........: 0 B 0 B/s\ndata_sent............: 0 B 0 B/s\niteration_duration...: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s\niterations...........: 1 499.950005/s\n  { tag:xyz }........: 0 0/s\ntwo..................: 42 20997.90021/s\n```\n\nWhen we would have expected it to produce:\n\n```\none..................: 0 0/s\n  { tag:xyz }........: 0 0/s\ntwo..................: 42\n```\n\nThis issue has been addressed in [#2519](https://github.com/grafana/k6/pull/2519), and k6 `v0.38.2` now displays sub-metrics under their actual parents, even when they have received no samples.\n\n\nSpecial thanks to @efdknittlfrank, who reported and helped us track down the issue."
  },
  {
    "path": "release notes/v0.38.3.md",
    "content": "k6 v0.38.3 is a patch release containing a single fix\n\n### Threshold over already defined sub-metrics will result in an error ([#2538](https://github.com/grafana/k6/issues/2538))\n\nThere was a bug where we were checking if a submetric had already been added. Unfortunately, we didn't check that this will work with the one submetric we have by default `http_req_duration{expected_response:true}`. After v0.38.0 defining a threshold on it would result in an error.\n\nAs this definitely shouldn't happen in that case and we don't see a particular case where that will be problematic - adding a submetric again just reuses the already added one instead.\n\nThis issue has been addressed in [#2539](https://github.com/grafana/k6/pull/2539), and k6 `v0.38.3` will now lead you add a threshold on `http_req_duration{expected_response:true}`.\n"
  },
  {
    "path": "release notes/v0.39.0.md",
    "content": "k6 v0.39.0 is here! :tada: It's a small release that includes a bunch of bugfixes and minor enhancements. Much of our focus was on some upcoming big changes. You can read about what's coming up next in the [Roadmap and future plans section](#roadmap-and-future-plans).\n\n## Enhancements and UX improvements\n\n- [#2274](https://github.com/grafana/k6/pull/2274) and [#2560](https://github.com/grafana/k6/pull/2560) improved the `csv` output with support for a new `timeFormat` option. The possible values are `unix` (default) and `rfc3399`. You can also configure it through the `K6_CSV_TIME_FORMAT` environment variable. Thanks, @rpocklin!\n- [#2509](https://github.com/grafana/k6/pull/2509) added the `clear()` and `delete()` methods to the [`CookieJar` object](https://k6.io/docs/javascript-api/k6-http/cookiejar/) from the [`k6/http`](https://k6.io/docs/javascript-api/k6-http/) module. Thanks, @Maksimall89!\n- [#2282](https://github.com/grafana/k6/pull/2282) increased the precision of the iteration-progress bar in the UI. Thanks, @m3hm3t and @DarkAEther!\n- [#2568](https://github.com/grafana/k6/pull/2568) added more descriptive error messages when there were problems with parsing a config file.\n\n## Bug fixes\n\n- [#2523](https://github.com/grafana/k6/pull/2523) fixed a gRPC marshaling error when `any.proto` was used for a type. Thanks, @Flowersea!\n- [#2534](https://github.com/grafana/k6/pull/2534) fixed the return type of [`Selection.map()`](https://k6.io/docs/javascript-api/k6-html/selection/selection-map) from the [`k6/html` module](https://k6.io/docs/javascript-api/k6-html/) to the correct object types instead of a forced array of strings.\n- [#2502](https://github.com/grafana/k6/pull/2502) made it so k6 waits for scenario executors to fully finish before updating their final progress in the UI, preventing misleading red crosses ([#2500](https://github.com/grafana/k6/issues/2500)).\n- [#2524](https://github.com/grafana/k6/pull/2524) fixed a bug where GoError string contained missing URL values ([#2537](https://github.com/grafana/k6/issues/2537)).\n- [#2530](https://github.com/grafana/k6/pull/2530) fixed a wrong error message on remote resolution.\n- [#2542](https://github.com/grafana/k6/pull/2542) fixed a bug where `Rate` metric and sub-metric values were shown as `NaN` in the end-of-test summary if there were no measured values for them during the test run.\n- [#2558](https://github.com/grafana/k6/pull/2558) fixed a panic when trying to set the value of a [`vu.tags` element from `k6/execution`](https://k6.io/docs/javascript-api/k6-execution/#vu) to `null` or `undefined`.\n- [#2567](https://github.com/grafana/k6/pull/2567) fixed a panic when trying to access some [`k6/execution`](https://k6.io/docs/javascript-api/k6-execution/) properties outside of a VU context, e.g. trying to access `execution.scenario` in `setup()`.\n\n## Maintenance and internal improvements\n\n- [#2550](https://github.com/grafana/k6/pull/2550) updated the used Go version to 1.18.\n- [#2524](https://github.com/grafana/k6/pull/2524), [#2551](https://github.com/grafana/k6/pull/2551), [#2552](https://github.com/grafana/k6/pull/2552), [#2553](https://github.com/grafana/k6/pull/2553), [#2554](https://github.com/grafana/k6/pull/2554), [#2555](https://github.com/grafana/k6/pull/2555) updated various Go dependencies in k6.\n- [#2583](https://github.com/grafana/k6/pull/2583) added a deprecation warning for thresholds that use the `url`, `error`, `vu` or `iter` tags, which [will become](#refactoring-metrics) un-indexable in the future.\n\n# Roadmap and future plans\n\nAs the lack of big changes in this release suggests, we've focused the last few months' efforts on a few areas that haven't yet been merged into the core of k6.\n\nIn this section, we'd like to inform the community about important features that we're currently working on - our short-term roadmap in a sense. We'll also use it to give notice of breaking changes we plan to make in the near future.\n\n## `k6/experimental/*` JS modules\n\nOver the last several k6 releases, among a lot of other refactorings, we've added support for JavaScript event loops ([#2228](https://github.com/grafana/k6/pull/2228)) in k6 VUs and added a new Go API for exposing built-in and xk6 extension modules to user scripts ([announcement](https://github.com/grafana/k6/blob/master/release%20notes/v0.36.0.md#extensions), [docs](https://k6.io/docs/extensions/guides/create-an-extension/#advanced-javascript-extension)). This has given us (and any xk6-extension authors!) the ability to better support various asynchronous streaming/messaging/etc. protocols ([#882](https://github.com/grafana/k6/issues/882#issue-392218655)).\n\nWe've started building some of these newly possible APIs as [xk6 extensions](https://k6.io/docs/extensions/) first, to be able to iterate on them more quickly and get some user feedback while we are building them. [xk6-websockets](https://github.com/grafana/xk6-websockets), [xk6-timers](https://github.com/grafana/xk6-timers) and [xk6-redis](https://github.com/grafana/xk6-redis/) are some of the first such APIs, but we plan to also work on support for gRPC streaming ([#2020](https://github.com/grafana/k6/issues/2020)), messaging protocols ([#1269](https://github.com/grafana/k6/issues/1269)), a new and better HTTP API ([#2461](https://github.com/grafana/k6/issues/2461)) and many others in the future!\n\nWe want to eventually include a lot of these APIs in the k6 core as built-in modules that users can directly use, without needing to mess with xk6 or Go compilation. However, because we try to keep the built-in k6 APIs stable and backwards-compatible, we want to get more user feedback before we do that, while we are still free to iterate and make (hopefully minor) breaking changes.\n\nSo, we decided to create a new middle ground between the unstable and purely external xk6 extensions and the stable built-in k6 APIs―built-in `k6/experimental/*` modules! Our goal is that, starting with the next k6 v0.40.0 release, we'll start releasing some or all of these core-bound extensions as built-in k6 modules under these `k6/experimental/` import paths. This will let k6 users, both OSS and Cloud, to give us feedback and help us improve the APIs before we stabilize them.\n\nAs is hopefully clear from the name, our usual guarantees of API stability won't apply to these modules while they are still experimental. We reserve the right to make breaking changes in `experimental` modules, up to and including completely dropping them. We don't expect big breaking changes will need to happen often, but we want to be clear they aren't impossible. Finally, when an API has been stabilized and made available under a regular import path, we'll deprecate its experimental import path. To make the transition easier, both import paths will be available simultaneously for at least one k6 version.\n\n## Native support for ECMAScript modules\n\nAt the moment, k6 has support for [ECMAScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) (ESM, i.e. `import`, `export`, etc.) via [automatic transpilation](https://k6.io/docs/using-k6/javascript-compatibility-mode/) of scripts by the built-in [Babel.js](https://babeljs.io/). That mostly works, but it has caused some performance and compatibility problems ([#824](https://github.com/grafana/k6/issues/824#issuecomment-915918351) and [#2168](https://github.com/grafana/k6/issues/2168#issuecomment-1014276690) among others), so we want to support ESM modules and all other ES6 features directly in k6, without the need for Babel.js ([#2296](https://github.com/grafana/k6/issues/2296#issuecomment-993356717)). [goja](https://github.com/dop251/goja), the JavaScript runtime we use to evaluate k6 scripts, doesn't yet have native ESM support, so we are currently working on adding it there, to then be able to support ECMAScript modules natively in k6!\n\nThat work has been ongoing for a while and we're making progress, but it will likely not be ready in time for the next k6 v0.40.0 release. We are mentioning it here because we will probably need to make a few minor breaking changes and fixes of currently undefined behavior in k6 to support ESM modules natively.\n\nFor example, at the moment, some values like the consolidated script `options` were unintentionally made available globally, in all JS modules of a test, instead of just in the exported `options` value from the main JS module. That is not the intended or documented behavior, it's somewhere between a bug and undefined behavior, and we'll need to fix it ([#2571](https://github.com/grafana/k6/pull/2571)) and other similar issues like it, starting in k6 v0.40.0. We don't expect many scripts to break because of these fixes, but we'll nevertheless announce them in the release notes of the k6 version that they happen in.\n\n## Refactoring metrics\n\nOver the last several k6 releases, we've also slowly been refactoring and improving the metrics internals in k6 (see [#2071](https://github.com/grafana/k6/pull/2071), [#2330](https://github.com/grafana/k6/issues/2330), [#2426](https://github.com/grafana/k6/pull/2426), [#2463](https://github.com/grafana/k6/pull/2463), [#2433](https://github.com/grafana/k6/pull/2433), [#2442](https://github.com/grafana/k6/pull/2442), among others). This has already brought many side benefits and minor bugfixes, and we still have a lot of work left (e.g. [#1889](https://github.com/grafana/k6/issues/1889), [#572](https://github.com/grafana/k6/issues/572), [#2430](https://github.com/grafana/k6/issues/2430), [#1831](https://github.com/grafana/k6/issues/1831)), but we've finally reached the point where we can almost start implementing some major new features effectively!\n\nOne of the upcoming next big steps is the introduction of a \"time series\" concept internally in k6 ([#2580](https://github.com/grafana/k6/issues/2580)). We'll start to efficiently group samples (i.e. metric measurements) with the same metric and tags into a single `TimeSeries`, which would unlock many of possibilities that were previously too inefficient to implement.\n\nAnother upcoming metrics-related change would be the refactoring of [metric tags](https://k6.io/docs/using-k6/tags-and-groups/#tags) into two distinct types ([#2584](https://github.com/grafana/k6/issues/2584)) - ones that can be used for indexing (so, in the `TimeSeries` mentioned above, in [sub-metric thresholds](https://k6.io/docs/using-k6/thresholds/#thresholds-on-tags), in certain outputs that do aggregation based on tags, etc. ) and ones that cannot (e.g. high-cardinality metadata that's often unique for every data point).\n\nUnfortunately, we'll need to make a few minor breaking changes. The current [`url`, `error`, `vu` and `iter` system tags](https://k6.io/docs/using-k6/tags-and-groups/#system-tags) will be made non-indexable by default, to reflect their usually very high cardinality, so they won't be usable in thresholds. Instead of `error`, the `error_code` tag should be used there. And instead of `url`, users should already use the `name` tag to avoid issues, see the [documentation about URL grouping](https://k6.io/docs/using-k6/http-requests/#url-grouping). k6 v0.39.0 still supports thresholds with these tags, it will just print a warning if they are used.\n\n### Prometheus remote-write output\n\nBecause of these changes, we'll finally be able to refactor and improve the [Prometheus remote-write output extension](https://github.com/grafana/xk6-output-prometheus-remote/). Our goal is to make it more efficient, polish its rough edges, and merge it into the k6 core as a built-in output module in the near future.\n\n### Tracing support\n\nAnother new feature these changes would unlock is support for distributed tracing ([#2128](https://github.com/grafana/k6/issues/2128)).\n\nBecause of the upcoming support for high-cardinality unindexable metric tags, we'll be able to safely attach things like the unique trace and span IDs to every metric measurement without negatively affecting other parts of k6."
  },
  {
    "path": "release notes/v0.40.0.md",
    "content": "k6 v0.40.0 is here! This release includes:\n- Breaking changes to some undocumented and unintentional edge behaviors.\n- New experimental modules and first-class support for JavaScript classes.\n- Bugs and refactorings to pave the way for future features.\n\nFinally, the [Roadmap](#roadmap-and-future-plans) goes over the plans for the next cycles.\n\n## Breaking changes\n\n- [#2632](https://github.com/grafana/k6/pull/2632) During the refactoring to set tags to `metric.add` in the order they are provided, we discovered that you could provide tags as a key-value pair map *multiple* times in the same call. This was never the intended use and was never documented. As it was undocumented, and as such functionality makes no sense alongside every other API k6 has, we decided to remove this ability.\n- [#2582](https://github.com/grafana/k6/pull/2582) [For extensions using the event loop] Previously, if `RegisterCallback` result was called twice, the second call would silently break the event loop. This has never been expected behavior, and calling it twice is always a bug in the code using it. Now, calling the `RegisterCallback` result twice leads to a panic.\n- [#2596](https://github.com/grafana/k6/pull/2596) The `tainted` property of the Metric type is no longer outputted by the JSON output. That property was likely always going to have a `false` value as it was outputted at the beginning of the test.\n\n### Main module/script no longer pollutes the global scope [#2571](https://github.com/grafana/k6/pull/2571)\n\nDuring the ESM changes, we found that anything defined in the main module scope was also accessible globally. This was because it was directly evaluated in the global scope.\nThis has now been remedied and is no longer the case. This is a *breaking* change, but given that the whole point of modules (CommonJS or ESM) is to separate them, this is obviously rather a bug than a feature.\n\nOn that note, we've seen [reports](https://github.com/grafana/k6/issues/2623) by people who have this global accessibility of the main module (intentionally or not). Still, it seems relatively rare, with only a few usages in a script. So if you need to access something globally, our suggested workaround is to set it explicitly on the [global object `globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis).\n\n### `k6/ws` now respects the `throw` option [#2247](https://github.com/grafana/k6/issues/2247)\n\n`k6/http` has used the [`throw` option](https://k6.io/docs/using-k6/k6-options/reference/#throw) to figure out whether it should throw an exception on errors or return a response object with an error set on it (and log it).\n\nThis functionality is finally also available for `k6/ws`, which previously would've *always* thrown an exception and thus involved more scripting in handling it ([#2616](https://github.com/grafana/k6/pull/2616)).\n\nThis is a minor breaking change. By default, `throw` is `false`, so it now no longer throws an exception but instead returns a Response with `error` property.\n\nThank you, @fatelei, for making this change!\n\n## New Features\n\n### Experimental modules [#2630](https://github.com/grafana/k6/pull/2630) and [#2656](https://github.com/grafana/k6/pull/2656)\n\nAs mentioned in the v0.39.0 release notes, we're happy to announce that this release brings experimental modules. The main idea behind this initiative is to get community feedback earlier, which will help us improve them faster. We encourage you to try experimental modules out and provide feedback through the community forums or GitHub issues. \n\nThis release contains three experimental modules:\n- `k6/experimental/redis` - support for interaction with [Redis](https://redis.io/)\n- `k6/experimental/websockets` - a new Websockets API that copies the \"web\" [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)\n- `k6/experimental/timers` - adding [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout)/[`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) and [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval)/[`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) implementations.\n\nImportant to highlight that the **k6 team does not guarantee backward compatibility for these modules** and may change or remove them altogether. Also, their import paths, starting with `k6/experimental`, will break when the modules stop being experimental. Of course, we are going to try to limit those breaking changes to a minimum and, when possible, do them in a backward compatible way for at least a version.\n\n<details>\n<summary> Redis example </summary>\n\nHere is a fairly big example using [xk6-redis](https://github.com/grafana/xk6-redis) as an experimental module to keep track of data in Redis:\n\n```javascript\nimport { check } from \"k6\";\nimport http from \"k6/http\";\nimport redis from \"k6/experimental/redis\"; // this will be `k6/x/redis` if you are using it as extension\nimport { textSummary } from \"https://jslib.k6.io/k6-summary/0.0.1/index.js\";\n\nexport const options = {\n  scenarios: {\n    usingRedisData: {\n      executor: \"shared-iterations\",\n      vus: 10,\n      iterations: 200,\n      exec: \"measureUsingRedisData\",\n    },\n  },\n};\n\n// Instantiate a new redis client\nconst redisClient = new redis.Client({\n  addrs: __ENV.REDIS_ADDRS.split(\",\") || new Array(\"localhost:6379\"), // in the form of \"host:port\", separated by commas\n  password: __ENV.REDIS_PASSWORD || \"\",\n});\n\n// Prepare an array of crocodile ids for later use\n// in the context of the measureUsingRedisData function.\nconst crocodileIDs = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);\n\nexport function setup() {\n  redisClient.sadd(\"crocodile_ids\", ...crocodileIDs);\n}\n\nexport function measureUsingRedisData() {\n  // Pick a random crocodile id from the dedicated redis set,\n  // we have filled in setup().\n  redisClient\n    .srandmember(\"crocodile_ids\")\n    .then((randomID) => {\n      const url = `https://test-api.k6.io/public/crocodiles/${randomID}`;\n      const res = http.get(url);\n\n      check(res, {\n        \"status is 200\": (r) => r.status === 200,\n        \"content-type is application/json\": (r) =>\n          r.headers[\"Content-Type\"] === \"application/json\",\n      });\n\n      return url;\n    })\n    .then((url) => redisClient.hincrby(\"k6_crocodile_fetched\", url, 1));\n}\n\nexport function teardown() {\n  redisClient.del(\"crocodile_ids\");\n}\n\nexport function handleSummary(data) {\n  redisClient\n    .hgetall(\"k6_crocodile_fetched\")\n    .then((fetched) => Object.assign(data, { k6_crocodile_fetched: fetched }))\n    .then((data) =>\n      redisClient.set(`k6_report_${Date.now()}`, JSON.stringify(data))\n    )\n    .then(() => redisClient.del(\"k6_crocodile_fetched\"));\n\n  return {\n    stdout: textSummary(data, { indent: \"  \", enableColors: true }),\n  };\n}\n```\n\nThis example also showcases how to write some data and clean up after yourself.\n</details>\n\nThe extension does *not* run a Redis server. You need to separately handle running, scaling, and connecting infrastructure to Redis.\n\nThe [xk6-redis repository](https://github.com/grafana/xk6-redis) has more examples, and the module is [documented in the official k6 documentation](https://k6.io/docs/javascript-api/k6-experimental-redis/).\n\n<details>\n<summary> WebSockets example </summary>\n\nThis is a rewrite of the current WebSocket example at https://test-api.k6.io/.\n\n\nThis showcases how a single VU can run multiple WebSockets connections asynchronously and how to stop them after a period using the timeout and interval functions.\n\n```javascript\nimport { randomString, randomIntBetween } from \"https://jslib.k6.io/k6-utils/1.1.0/index.js\";\nimport { WebSocket } from \"k6/experimental/websockets\"\nimport { setTimeout, clearTimeout, setInterval, clearInterval } from \"k6/experimental/timers\"\n\nlet chatRoomName = 'publicRoom'; // choose your chat room name\nlet sessionDuration = randomIntBetween(5000, 60000); // user session between 5s and 1m\n\n\nexport default function() {\n  for (let i = 0; i < 4; i++) {\n    startWSWorker(i)\n  }\n}\n\nfunction startWSWorker(id) {\n  let url = `wss://test-api.k6.io/ws/crocochat/${chatRoomName}/`;\n  let ws = new WebSocket(url);\n  ws.addEventListener(\"open\", () => {\n    ws.send(JSON.stringify({ 'event': 'SET_NAME', 'new_name': `Croc ${__VU}:${id}` }));\n\n    ws.addEventListener(\"message\", (e) => {\n      let msg = JSON.parse(e.data);\n      if (msg.event === 'CHAT_MSG') {\n        console.log(`VU ${__VU}:${id} received: ${msg.user} says: ${msg.message}`)\n      }\n      else if (msg.event === 'ERROR') {\n        console.error(`VU ${__VU}:${id} received:: ${msg.message}`)\n      }\n      else {\n        console.log(`VU ${__VU}:${id} received unhandled message: ${msg.message}`)\n      }\n    })\n\n\n    let intervalId = setInterval(() => {\n      ws.send(JSON.stringify({ 'event': 'SAY', 'message': `I'm saying ${randomString(5)}` }));\n    }, randomIntBetween(2000, 8000)); // say something every 2-8seconds\n\n\n    let timeout1id = setTimeout(function() {\n      clearInterval(intervalId)\n      console.log(`VU ${__VU}:${id}: ${sessionDuration}ms passed, leaving the chat`);\n      ws.send(JSON.stringify({ 'event': 'LEAVE' }));\n    }, sessionDuration);\n\n    let timeout2id = setTimeout(function() {\n      console.log(`Closing the socket forcefully 3s after graceful LEAVE`);\n      ws.close();\n    }, sessionDuration + 3000);\n\n    ws.addEventListener(\"close\", () => {\n      clearTimeout(timeout1id);\n      clearTimeout(timeout2id);\n      console.log(`VU ${__VU}:${id}: disconnected`);\n    })\n  });\n}\n```\n</details>\n\nNote that no k6 iterations finish if any WebSocket is still open or if a timeout or an interval is not cleared or triggered. This means that your script must take care of clearing all intervals and closing the WebSocket at some point. However, k6 still kills the whole process if it takes too long to stop after the maximum test duration is reached.\n\nCurrent issues and future improvements for the WebSockets API can be found in its [issue tracker](https://github.com/grafana/xk6-websockets/issues). Currently, documentation is available through [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), though some features are not yet supported:\n- no Blob binary type - ArrayBuffer is the default\n- no `onMessage` and co. - only addEventListener\n\n### First-class support for JavaScript Classes\n\nAs part of [updating goja](https://github.com/grafana/k6/pull/2610), k6 got native support for classes. Again, that's native, as in not by transpiling by the internal Babel.\n\nBecause this actually implements classes as described in the latest ECMAScript specification, this also means we get a ton of additional class features that were never previously supported (for example, private fields). Additionally, at least one bug [#1763](https://github.com/grafana/k6/issues/1763) was fixed as a result of this, but probably many more as well.\n\nDue to this fairly significant change, some code could behave differently. Please report any issues, though consider that it's possible that the new behavior is just the correct one.\n\nOther updates from goja are:\n- optimizations around using strings and some access patterns\n- support for `\\u{01234}` Unicode point syntax in regexp\n- Fixed a case where interrupting the VM did not work, especially around try/catch usage ([#2600](https://github.com/grafana/k6/pull/2600)). This was particularly problematic for k6, as it could lead to k6 hanging.\n\nMany thanks to @dop251 for continuing to improve goja! \n\n#### New Test runtime for module extension developers [#2598](https://github.com/grafana/k6/issues/2598)\n\nWhile we develop extensions internally, we often need to repeatedly create the same structure. With the addition of the event loops, it is now required to set it up as well. Even k6 team members get parts of this wrong every once in a while, so we added a small type to be used by (extension) module developers to write tests easier ([#2602](https://github.com/grafana/k6/pull/2602)). \n\n[This API](https://pkg.go.dev/go.k6.io/k6@v0.39.1-0.20220819115243-e09bb8727786/js/modulestest#Runtime) will likely change and evolve as we add more functionality or as we change the k6 internal API.\n\n## Bug fixes\n\n- [#2585](https://github.com/grafana/k6/pull/2585) `http.batch()` now displays an error if it is not given exactly 1 argument([#1289](https://github.com/grafana/k6/issues/1289)). Thanks, @vanshaj!\n- [#2596](https://github.com/grafana/k6/pull/2596) Fixes a potential data race in the JSON output. Includes a breaking change where `tainted` property is no longer outputted. That property was (likely) always going to have the value `false` as it was outputted at the beginning of the test.\n- [#2604](https://github.com/grafana/k6/pull/2604) Fixes SSL keylogger not working with absolute paths.\n- [#2637](https://github.com/grafana/k6/pull/2637) Fixes setting the options `rps` to `0` or below leading to exceptions. Now setting it to 0 or below disables the limit. Thanks, @tbourrely. [#2613](https://github.com/grafana/k6/issues/2613)\n- [#2278](https://github.com/grafana/k6/issues/2278) Reading `options.tags` directly was not possible. This was fixed by accident by [#2631](https://github.com/grafana/k6/pull/2631).  `k6/execution` is still the recommended way to access the [final options of the test](https://k6.io/docs/javascript-api/k6-execution/#get-test-options).\n\n## Maintenance and internal improvements\n\n- [#2590](https://github.com/grafana/k6/pull/2590) Updates direct dependencies without any interesting changes apart goja.\n- [#2591](https://github.com/grafana/k6/pull/2591) Changes to the CI process to always build rpm/deb and windows packages and use nfpm to do it. \n- [#2593](https://github.com/grafana/k6/pull/2593) Internal cleanup after finally removing `common.Bind`.\n- [#2597](https://github.com/grafana/k6/pull/2597) Fixes go benchmarks we have broken over time.\n- [#2599](https://github.com/grafana/k6/pull/2599) Reformats `//nolint` comments as part of getting ready for go 1.19.\n- A bunch of fixes for tests [#2589](https://github.com/grafana/k6/pull/2589), [#2620](https://github.com/grafana/k6/pull/2620), [#2625](https://github.com/grafana/k6/pull/2625), [#2643](https://github.com/grafana/k6/pull/2543), [#2647](https://github.com/grafana/k6/pull/2647), [#2648](https://github.com/grafana/k6/pull/2648),\n- [#2607](https://github.com/grafana/k6/pull/2607) Fixes the build badge in the README. Thanks @AetherUnbound!\n- [#2614](https://github.com/grafana/k6/pull/2614) Fixes advice for RPM install on Amazon Linux.\n- [#2615](https://github.com/grafana/k6/pull/2615) Improves documentation of the RegisterCallback, following feedback on how hard it was to understand.\n- [#2627](https://github.com/grafana/k6/pull/2627) Create distinct test state objects for the pre-init and run phases.\n- [#2635](https://github.com/grafana/k6/pull/2635) Drop License header in each file.\n- [#2636](https://github.com/grafana/k6/pull/2636) Add [SECURITY.md](https://github.com/grafana/k6/security/policy) with instructions how to report security issues responsibly.\n- [#2641](https://github.com/grafana/k6/pull/2641) Fix spelling of `lose`. Thanks @spazm!\n- Update to golangci-lint v1.47.2 and enable a bunch more linters. [#2609](https://github.com/grafana/k6/pull/2609), [#2611](https://github.com/grafana/k6/pull/2611). Also, drop obsolete configurations [#2619](https://github.com/grafana/k6/pull/2619).\n\n## Roadmap and future plans\n\nThis section discusses our plans for future versions. Notice that two big ticket items are here again―ESM modules and metric refactoring. They remain on the roadmap mostly for the sheer size of the work required on both, but also for some unforeseen needed changes, which actually should make them better in the long run. It also so happens that it is vacation season so the k6 team rightfully is taking some personal time away.\n\n### Native support for ECMAScript modules\n\nNative ESM support is coming. A [PR to k6](https://github.com/grafana/k6/pull/2563) is under development, and there's a branch that will become a PR to goja to add the support there. The k6 team is hopeful that this will land in the next version, v0.41.0!\n\nIt turned out that there were a lot more things to be added as functionality - dynamic import, and the [tc39](https://tc39.es/) group released the latest ECMAScript specification adding support of top-level await in modules. While neither k6 nor goja has support for the `async`/`await` syntax, yet, this changes significantly the internal of the change, which did require a not insignificant refactor.\n\nAdditionally, as previously mentioned, there were a bunch of changes to goja, including adding class support which also needed to be integrated.\n\nA future breaking change is that using CommonJS style exports along import/export syntax in the *same* file will no longer be possible.\n\n```javascript\nimport http from \"k6/http\"\n\nexports.default = function() {} // this will start to error out\n```\n\nIt will still be possible to import a CommonJS module and `require` an ES module or use `require` in an ES module. Having a dependency cycle mixing and matching CommonJS and ESM is also unlikely to work properly, but *might* do so in particular cases.\n\nThis is really expected to have never been done by anyone as there isn't really much of a reason for this, but it is currently supported due to Babel transpiling everything to CommonJS behind the scenes.\n\n### Refactoring metrics\n\nThe refactoring of metrics is underway, with a [PR](https://github.com/grafana/k6/pull/2594) for more performant internal representation. Unfortunately, this took longer to get to a stable state, and given the size and the type of change, the k6 team decided to *hold* merging it until very near the end of the cycle. It also doesn't have any noticeable change for most users. Instead, it will be merged early in the v0.41.0 release cycle, and then more changes to use it will be made through the release cycle.\n\nSome of those changes include supporting non-indexable tags, which also have a read [PR](https://github.com/grafana/k6/pull/2654). This change is also essential for historical reasons connected with how the `name`  tag works. As such, it also needed to be merged to release the internal metric refactor.\n\nFuture breaking change: as part of the many changes and experiments, we found out that we can keep `url` as an indexable tag. Previously the plan was that it *along* `vu` and `iter` will become non-indexable. However, the `url` tag is *heavily* used and enabled by default. Because of that (and other internal reasons), the new change will be that `url` will stay indexable, but if used with `name` will be overwritten to have the same value as `name`. Arguably this is what most users would want in the case when they are using `name`. We plan to add a *non* indexable `raw_url` tag for those that do not. As such, we no longer will be [printing a warning when `url` is used](https://github.com/grafana/k6/pull/2655) in thresholds.\n\nEven so, we did make a bunch of changes to the internals of k6 that will pave the way forward ([#2629](https://github.com/grafana/k6/pull/2629), [#2631](https://github.com/grafana/k6/pull/2631)).\n\nWe are also still working on incorporating the newly developed time series data model for the [Prometheus remote-write output extension](https://github.com/grafana/xk6-output-prometheus-remote). We are fixing bugs and improving the extension with the goal of eventually integrating it as a core built-in k6 output module in a future k6 release.\n\n[Distributed tracing support](https://github.com/grafana/k6/issues/2128) itself needs non-indexable tag support. Once that is merged, more work in that direction will be started.\n"
  },
  {
    "path": "release notes/v0.41.0.md",
    "content": "k6 v0.41.0 is here! :tada: It has relatively few user-facing changes, but includes massive internal improvements that pave the way for some awesome features for the near future. Unfortunately, this work also required us to make a few [minor breaking changes](#breaking-changes).\n\n## Breaking changes\n\n### Changes in the `url`, `iter` and `vu` system metric tags\n\nAs we warned in the release notes for k6 [v0.39.0](https://github.com/grafana/k6/blob/2fe2dd32b3827eeeeb3959aff63a6b402aab0a5a/release%20notes/v0.39.0.md#roadmap-and-future-plans) and [v0.40.0](https://github.com/grafana/k6/blob/2fe2dd32b3827eeeeb3959aff63a6b402aab0a5a/release%20notes/v0.40.0.md), we've been fundamentally [refactoring the metrics sub-systems](#metric-time-series) of k6. We now have efficient support for time series, which required a few minor user-facing breaking changes:\n\n- If [URL grouping](https://k6.io/docs/using-k6/http-requests/#url-grouping) is used for HTTP requests (that is, if the [`http.url` helper](https://k6.io/docs/javascript-api/k6-http/urlurl/) is used or the `name` metric tag is specified), then the `url` tag in the resulting `http_req_*` metric samples will also have the same value as the `name` tag. Previously, k6 did this only for [the `cloud` output](https://k6.io/docs/results-output/real-time/cloud/), but now it does this universally ([#2703](https://github.com/grafana/k6/pull/2703)).\n- The [`vu` and `iter` system tags](https://k6.io/docs/using-k6/tags-and-groups/#system-tags), which are disabled by default, have been transformed into [high-cardinality metrics metadata](#internal-support-for-high-cardinality-metrics-metadata) instead. It means that they will no longer be usable in thresholds, and various outputs may emit them differently or ignore them completely ([#2726](https://github.com/grafana/k6/pull/2726)).\n\n### Changes in the Go metrics APIs\n\nWhile the user-facing changes from our metrics refactoring are few and relatively minor, and there are no changes to JavaScript APIs yet, we have extensively refactored our internal Go APIs ([#2594](https://github.com/grafana/k6/pull/2594), [#2726](https://github.com/grafana/k6/pull/2726), [#2727](https://github.com/grafana/k6/pull/2727)). The [`metrics.Sample`](https://github.com/grafana/k6/blob/2fe2dd32b3827eeeeb3959aff63a6b402aab0a5a/metrics/sample.go#L11-L33) and [`metrics.TagSet`](https://github.com/grafana/k6/blob/2fe2dd32b3827eeeeb3959aff63a6b402aab0a5a/metrics/tags.go#L16-L157) types are now entirely different. We also have high-cardinality metadata attributes in each `Sample` and at the VU level (see the [combined `TagsAndMeta` code](https://github.com/grafana/k6/blob/2fe2dd32b3827eeeeb3959aff63a6b402aab0a5a/metrics/tags.go#L159-L231) and [how it is used in the per-VU `State` object](https://github.com/grafana/k6/blob/2fe2dd32b3827eeeeb3959aff63a6b402aab0a5a/lib/vu_state.go#L83-L119)).\n\n### `k6 convert` is officially deprecated ([#2714](https://github.com/grafana/k6/pull/2714))\n\n`k6 convert` has been a sub-command to convert a [HAR file recording](https://en.wikipedia.org/wiki/HAR_(file_format)) of HTTP traffic into a preliminary k6 script that makes roughly the same requests. It has been long neglected and softly deprecated in favor of the newer and more feature-rich [har-to-k6 standalone converter](https://github.com/grafana/har-to-k6).\n\nWe have now officially deprecated `k6 convert`. The command still works and will continue to do so for a few more k6 versions. However, it's not visible from `k6 --help` and will emit a warning when used. Please see the [documentation for the standalone har-to-k6 converter](https://k6.io/docs/test-authoring/recording-a-session/har-converter/) and [open an issue](https://github.com/grafana/har-to-k6/issues) (or comment on an existing one) if you have any problems with it.\n\n## New Features, enhancements, and UX improvements\n\n- [#2679](https://github.com/grafana/k6/pull/2679) added support for `maxReceiveSize` and `maxSendSize` parameters in the [gRPC's `Client.connect()` method](https://k6.io/docs/javascript-api/k6-net-grpc/client/client-connect/). Thanks, @ariasmn!\n- [#2605](https://github.com/grafana/k6/pull/2605) introduced a new `--exclude-env-vars` CLI flag to [`k6 archive`](https://k6.io/docs/misc/archive-command/) that causes it to not include the provided environment variables in the resulting archive bundle's `metadata.json` file.\n- [#2700](https://github.com/grafana/k6/issues/2700) added support for loading gRPC protoset files. Thanks, @jklipp!\n\n## Bug fixes\n\n- [#2678](https://github.com/grafana/k6/pull/2678) fixed the Docker image labels. Thanks, @knittl, for reporting the problem ([#2677](https://github.com/grafana/k6/issues/2677))!\n- [#2689](https://github.com/grafana/k6/pull/2689) fixed the REST API's `Content-Type` response header. Thanks, @wingyplus!\n- [#2691](https://github.com/grafana/k6/pull/2691) fixed the detailed `k6 version` information embedded in the k6 releases.\n- [#2693](https://github.com/grafana/k6/pull/2693) fixed a bug that made the k6 event loop unusable when a Promise rejection was left unhandled.\n- [#2696](https://github.com/grafana/k6/pull/2696) fixed a problem with HTTP redirects with empty `Location` headers ([#2474](https://github.com/grafana/k6/issues/2474)) by updating the Go version we use to compile k6 to 1.19.x. Thanks, @agilob!\n- [#2705](https://github.com/grafana/k6/pull/2705) fixed a panic in the `k6/net/grpc` module ([#2661](https://github.com/grafana/k6/issues/2661)). Thanks, @c47gao and @robpickerill!\n- [#2738](https://github.com/grafana/k6/pull/2738) fixed a panic when a Promise was rejected with an `undefined` reason.\n- [#2739](https://github.com/grafana/k6/pull/2739) fixed hidden stack traces in certain types of errors originating from k6's Go code.\n\n## Maintenance and internal improvements\n\nWe had a few minor changes in this release:\n\n- [#2687](https://github.com/grafana/k6/pull/2687) improved our logging tests. Thanks, @nsmith5!\n- [#2696](https://github.com/grafana/k6/pull/2696) updated the used Go version to 1.19.x and the Alpine version in our Docker image to 3.16. Thanks, @agilob!\n- [#2707](https://github.com/grafana/k6/pull/2707), [#2708](https://github.com/grafana/k6/pull/2708), [#2709](https://github.com/grafana/k6/pull/2709), [#2710](https://github.com/grafana/k6/pull/2710) updated most of the Go dependencies k6 has.\n- [#2716](https://github.com/grafana/k6/pull/2716) refactored how custom JS tags are applied to metrics and cleaned up validation for invalid tag values.\n\nWe also have a couple of significant improvements that will help us develop exciting new features soon:\n\n### Metric time series ([#2594](https://github.com/grafana/k6/pull/2594))\n\nPrevious to [#2594](https://github.com/grafana/k6/pull/2594), k6 didn't have an efficient way to group metric samples with the same tags. It meant that a whole class of applications for processing and aggregating metrics were nearly impossible to do or, at best, very inefficient.\n\nAt the cost of some minor [breaking changes](#breaking-changes), we now have a performant internal representation to group metric samples with the same tags at the time of the action that generated them, i.e. the time of metric measurement. With this, k6 can efficiently group samples for the same action (e.g. an HTTP request to a specific URL) over time and construct time series with them.\n\n### Internal support for high-cardinality metrics metadata ([#2726](https://github.com/grafana/k6/pull/2726), [#2727](https://github.com/grafana/k6/pull/2727))\n\nAs described in the previous section, the efficient grouping of metric samples into time series works well for relatively low-cardinality data. However, k6 needed some way to attach high-cardinality metadata as well. This is necessary for data that's unique or random, such as Trace and Span IDs in distributed tracing or user IDs in tests with huge data sets.\n\nk6 v0.41.0 has added support for attaching high-cardinality metadata to metric samples, and the `vu` and `iter` system tags have been transformed into such metadata (see the [breaking changes section](#breaking-changes) above), but it is not yet accessible from user scripts. There is no JavaScript API to modify this metadata, only built-in k6 Go modules and [xk6](https://github.com/grafana/xk6) Go extensions can make use of it, for now.\n"
  },
  {
    "path": "release notes/v0.42.0.md",
    "content": "k6 v0.42.0 is here!  :tada:\n\nThis release includes:\n- A tiny breaking change to improve WebSockets response handling.\n- A new experimental output.\n- More features in our experimental WebSocket module.\n- Wildcard support for `hosts`.\n- Some bug fixes, UX improvements, and maintenance.\n\n## Breaking changes\n\n- [#2712](https://github.com/grafana/k6/pull/2712) `k6/ws` returns an HTTP response for failed connections instead of an undefined behavior. Thanks, @brietaylor.\n\n## New Features\n\n### Experimental Prometheus Remote Write Output [#2784](https://github.com/grafana/k6/pull/2784)\n\nThis release brings a new builtin Output to any [Prometheus Remote Write](https://docs.google.com/document/d/1LPhVRSFkGNSuU1fBd81ulhsCPR4hkSZyyBj1SZ8fWOM/edit) implementations (e.g. [Prometheus](https://prometheus.io/docs/prometheus/latest/feature_flags/#remote-write-receiver), [Mimir](https://grafana.com/docs/mimir/latest/operators-guide/reference-http-api/#remote-write)). This is an experimental feature, and future releases could introduce breaking changes.\n\nThe following example uses `k6 run` with the new output. It uses the defaults options, such as the Remote Write server URL (http://localhost:9090/api/v1/write):\n\n```sh\nk6 run -o experimental-prometheus-rw script.js\n```\n\nIt supports the new and convenient experimental [Native Histogram](https://prometheus.io/docs/practices/histograms) feature, added in Prometheus `v2.40.0`. It's not enabled by default, but we expect to make it the default way to map k6 [Trend metrics](https://k6.io/docs/javascript-api/k6-metrics/trend) once the Prometheus project signals that its mature enough and when more Remote Write implementations support it. For now, if you want to use it, you need to set the environment variable `K6_PROMETHEUS_RW_TREND_AS_NATIVE_HISTOGRAM` to `true`.\n\nYou can find [complete documentation](https://k6.io/docs/results-output/real-time/prometheus-remote-write) with more examples, use cases, and available configurations.\n\n### More features for the experimental websockets module [#2786](https://github.com/grafana/k6/pull/2786) \n\nThe `k6/experimental/websockets` module that we announced in the [v0.40.0 release](https://github.com/grafana/k6/releases/tag/v0.40.0) got an update that extends its functionality.\n\nIt brings some useful features that the `k6/ws` module already has, like cookies, custom headers, compression and tags customization support, the syntax to define event handlers (`onopen`, `onmessage`, etc.) and `ping`/`pong` functionality.\n\nThis is still an experimental module, but with the recent changes we think it's usable for most users. So whether you're writing a new WebSocket test, or currently using the `k6/ws` module, we invite you to give it a try, and report any issues in the project's [issue tracker](https://github.com/grafana/xk6-websockets/issues).\n\n<details>\n<summary> Expand to see an example of the new WebSockets functionality</summary>\n\nThis example customizes tags for a WebSocket connection, sets up handlers using the new `on*` syntax, and demonstrates the `ping`/`pong` feature.\n\n```javascript\nimport { WebSocket } from \"k6/experimental/websockets\";\nimport {\n  setTimeout,\n  clearTimeout,\n  setInterval,\n  clearInterval\n} from \"k6/experimental/timers\";\n\nconst CLOSED_STATE = 3\n\nexport default function () {\n  const params = {\n    \"tags\": {\n      \"my_tag\": \"hello\"\n    }\n  };\n\n  const ws = new WebSocket('ws://localhost:10000', null, params);\n\n  ws.onopen = () => {\n    console.log('connected');\n    ws.send(Date.now().toString());\n  };\n\n  let intervalId = setInterval(() => {\n    ws.ping();\n    console.log(\"Pinging every 1 sec (setInterval test)\");\n  }, 1000);\n\n  let timeout1id = setTimeout(function () {\n    console.log('2 seconds passed, closing the socket');\n    clearInterval(intervalId);\n    ws.close();\n  }, 2000);\n\n  ws.onclose = () => {\n    clearTimeout(timeout1id);\n    console.log('disconnected');\n  };\n\n  ws.onping = () => {\n    console.log(\"PING!\");\n  };\n\n  ws.onpong = () => {\n    console.log(\"PONG!\");\n  };\n\n  // Multiple event handlers on the same event\n  ws.addEventListener(\"pong\", () => {\n    console.log(\"OTHER PONG!\");\n  });\n\n  ws.onmessage = (m) => {\n    let parsed = parseInt(m.data, 10)\n    if (Number.isNaN(parsed)) {\n      console.log('Not a number received: ', m.data);\n      return\n    }\n\n    console.log(`Roundtrip time: ${Date.now() - parsed} ms`);\n\n    let timeoutId = setTimeout(function () {\n      if (ws.readyState == CLOSED_STATE) {\n        console.log(\"Socket closed, not sending anything\");\n\n        clearTimeout(timeoutId);\n        return;\n      }\n\n      ws.send(Date.now().toString());\n    }, 500);\n  };\n\n  ws.onerror = (e) => {\n    if (e.error != \"websocket: close sent\") {\n      console.log('An unexpected error occurred: ', e.error);\n    }\n  };\n};\n```\n</details>\n\nThe [module docs](https://k6.io/docs/javascript-api/k6-experimental/websockets) has a complete reference, and some examples.\n\n### Wildcard support for `hosts` option [#2747](https://github.com/grafana/k6/pull/2747)\n\nThanks to the great effort from @eugercek, the [hosts](https://k6.io/docs/using-k6/k6-options/reference/#hosts) option now accepts domains that contain a wildcard at the beginning.\nIt can be helpful for setting multiple subdomains of the same domain, so instead of setting `subdomain1.k6.io': '1.2.3.4', 'subdomain2.k6.io': '1.2.3.4'` it is possible to use the wildcard for setting directly `*.k6.io: '1.2.3.4'`.\n\n```js\nexport const options = {\n  hosts: {\n    '*.k6.io': '1.2.3.4',\n  },\n}\n```\n\n### Enhancements and UX improvements\n\n- [#2660](https://github.com/grafana/k6/pull/2660) Pre-loads the operating system TLS certificates. Thanks, @tbourrely.\n- [#2791](https://github.com/grafana/k6/pull/2791) Initializes VUs for `setup()` and `teardown()` only if they are defined in the script.\n\n## Bug fixes\n\n- [#2759](https://github.com/grafana/k6/pull/2759) Ensures the evaluation of thresholds over trend metrics' median.\n- [#2759](https://github.com/grafana/k6/pull/2789) Fixes a few potential Output data races for interrupted test runs.\n- [#2767](https://github.com/grafana/k6/pull/2767) Fixes the emission of `ws_session_duration` when setup throws an error.\n- [#2773](https://github.com/grafana/k6/pull/2773) Ensures that JavaScript runtime makes only one copy of the exports for each module including built-in ones.\n\n## Maintenance and internal improvements\n\nWe had a few minor changes in this release:\n\n- [#2757](https://github.com/grafana/k6/pull/2757) goja runtime has been updated.\n- [#2768](https://github.com/grafana/k6/pull/2768) `WS.Connect()` has been refactored.\n- [#2770](https://github.com/grafana/k6/pull/2770) Refactored parts of the js module.\n- [#2782](https://github.com/grafana/k6/pull/2782) Covered more relative path test cases for `require` and `open`.\n- [#2789](https://github.com/grafana/k6/pull/2789), [#2792](https://github.com/grafana/k6/pull/2792), [#2795](https://github.com/grafana/k6/pull/2795), [#2796](https://github.com/grafana/k6/pull/2796) Improved stability of the integration tests.\n- [#2791](https://github.com/grafana/k6/pull/2777) Optimized the performance of the internal Trie implementation. Thanks, @eugercek.\n\n**Full Changelog**: https://github.com/grafana/k6/compare/v0.41.0...v0.42.0\n"
  },
  {
    "path": "release notes/v0.43.0.md",
    "content": "k6 v0.43.0 is here! :tada:\n\nNotable changes in this release include:\n- [xk6-browser](https://github.com/grafana/xk6-browser) is now bundled in k6 as an experimental module, and usable without a separate binary or compilation step!\n- Native support for JavaScript's `async`/`await`.\n- A new experimental module for distributed tracing.\n- Large refactoring of core components to simplify the code base, improve maintainability, and increase test coverage.\n- Bug fixes, UX improvements, and maintenance.\n\nKeep reading for the details.\n\n## Breaking changes\n\n- [#2807](https://github.com/grafana/k6/pull/2807) Use non-zero exit codes for tests aborted by Ctrl+C or the REST API.\n\n  Aborting a test run with Ctrl+C will now exit with code `105`, and stopping via the REST API will exit with code `103`.\n\n\n## New Features\n\n### xk6-browser is now a built-in module [#2884](https://github.com/grafana/k6/pull/2884)\n\nThis release includes [xk6-browser](https://github.com/grafana/xk6-browser) as an experimental module. This means you can now also use the main k6 binary for browser automation and end-to-end testing, without needing to build a custom binary with [xk6](https://github.com/grafana/xk6).\n\nAll xk6-browser scripts that work with v0.8.0 will continue to work with the built-in module in k6 v0.43.0. To use them, change the import path from `k6/x/browser` to `k6/experimental/browser`, and set the environment variable `K6_BROWSER_ENABLED` to `true`. The requirement to specify the environment variable is temporary and may be removed in a future k6 release. It was added to minimize the risks with k6 unexpectedly launching a browser (or another process) from k6 scripts. It's also a mechanism we use in the k6 Cloud, where browser tests are currently disabled.\n\nFor details, review the [script example](https://github.com/grafana/k6/blob/v0.43.0/samples/experimental/browser.js), or the updated [browser module documentation](https://k6.io/docs/javascript-api/k6-browser/).\n\nThe module is currently under the `experimental` namespace, which means we reserve the decision to introduce breaking changes in the future. However, our mid-term goal is to drop the `experimental` label and make browser support a stable part of the k6 feature set, eventually enabling it in k6 Cloud as well.\n\n\n### Native support for JavaScript's `async`/`await` [#2830](https://github.com/grafana/k6/pull/2830)\n\nIn [v0.35.0](https://github.com/grafana/k6/releases/tag/v0.35.0) we added support for asynchronous functionality in k6 scripts with the addition of `Promise`.\n\nWhile useful, the experience wasn't very friendly. Scripts had to use the `.then()` API to chain Promises, instead of the `await` syntax available in most other JavaScript runtimes, and the `async` keyword wasn't supported. [Some workarounds were possible](https://github.com/grafana/k6/issues/779#issuecomment-964027280), but it required a separate build pipeline to transpile the syntax into the older ES5.1+ standard supported by k6.\n\nThat is, until now! :tada: With invaluable help from @dop251, who maintains [goja](https://github.com/dop251/goja), the JS VM k6 uses, v0.43.0 brings native `async`/`await` to your k6 scripts. This functionality works just as you'd expect in other JS runtimes, and makes working with async APIs much more convenient. For details, review the following [`http.asyncRequest()` example](#httpasyncrequest-2877).\n\nOne caveat to note: async functions can't be passed to `group()` or `check()`. These functions are incompatible with asynchronous behavior, so you will get an error if trying to do so.\n\n\n### Experimental JavaScript module for distributed tracing [#2853](https://github.com/grafana/k6/pull/2853) [#2854](https://github.com/grafana/k6/pull/2854) [#2855](https://github.com/grafana/k6/pull/2855)\n\nThis release brings a new experimental JavaScript module that adds [distributed tracing](https://en.wikipedia.org/wiki/Tracing_(software)) support to k6. With one call in `init` context, you can instrument your test script's HTTP requests. If the system you're testing is instrumented in the same way, this module brings visibility to SUT behavior for the lifetime of each request.\n\nAn example:\n\n```javascript\nimport tracing from 'k6/experimental/tracing';\nimport http from 'k6/http';\n\ntracing.instrumentHTTP({\n  propagator: 'w3c',\n});\n\nexport default () => {\n  http.get('https://httpbin.test.k6.io/get', {\n    headers: {\n      'X-Example-Header': 'instrumented/get',\n    },\n  });\n};\n```\n\nFor details and examples, refer to the [tracing module documentation](https://https://k6.io/docs/javascript-api/k6-experimental/tracing/).\n\n\n### `http.asyncRequest` [#2877](https://github.com/grafana/k6/pull/2877)\n\nThe `k6/http` module has a new `asyncRequest` function that takes the same arguments as [`http.request()`](https://k6.io/docs/javascript-api/k6-http/request/), but returns a `Promise` that, when used with `await`, will be resolved with a `Response` object. This gives you more control over script execution, as potentially the most time-consuming calls—making HTTP requests—will no longer block the thread of execution.\n\nAn example issuing a POST request:\n\n```javascript\nimport http from 'k6/http';\n\nexport default async function () {\n  const resPromise = http.asyncRequest(\n    'POST', 'https://httpbin.test.k6.io/post', { name: 'Bert' });\n  // Do something else here, make other requests, etc.\n  // Then when you're ready to use the response:\n  const resp = await resPromise;\n  console.log(resp.json().form.name); // Bert\n}\n```\n\nThis is one of the first steps towards migrating our APIs to be asynchronous, and similar changes can be expected in the future.\n\nYou can read more about `asyncRequest` in the [documentation](https://k6.io/docs/javascript-api/k6-http/asyncrequest/).\n\n\n### Enhancements and UX improvements\n\n- [#2754](https://github.com/grafana/k6/pull/2754), [#2805](https://github.com/grafana/k6/pull/2805) The output of the `k6 version` command has been enhanced to also show the version of all extensions built into the k6 binary produced by [xk6](https://github.com/grafana/xk6). Thanks, @HarrisChu!\n- [#2800](https://github.com/grafana/k6/pull/2800) Improved handling of the Ctrl+C signal to gracefully abort the test during VU initialization.\n- [#2803](https://github.com/grafana/k6/pull/2803) Ensure the REST API server is shut down after the test ends.\n- [#2867](https://github.com/grafana/k6/pull/2867) Added the ability to display test run details and logs from k6 Cloud.\n- [#2890](https://github.com/grafana/k6/pull/2890) Added a method for JavaScript modules to lookup environment variables without directly accessing the `os` package.\n- [#2910](https://github.com/grafana/k6/pull/2910) Added a bit more context when parsing the script options, so that it is more obvious what fails.\n\n\n## Bug fixes\n\n- [#2829](https://github.com/grafana/k6/pull/2829) The `csv` output now correctly shows `vu` and `iter` system tags. This fixes a regression introduced in v0.40.0. Thanks, @leonyork!\n- [#2851](https://github.com/grafana/k6/pull/2851) Calling `k6/execution.test.abort()` within a `group()` now correctly exits the k6 process with code `108`. Thanks for reporting this, @pomeh!\n- [#2896](https://github.com/grafana/k6/pull/2896) Fixed a panic in `k6/ws` when using `Socket.setInterval()` with values between 0 and 1.\n- [#2903](https://github.com/grafana/k6/pull/2903) Fixed a [regression](https://github.com/grafana/k6/issues/2902) introduced in v0.42.0 where k6 will load the wrong module if the same import specifier has already been loaded, but they are pointing to different absolute paths, based on the files they are imported from.\n- [#2907](https://github.com/grafana/k6/pull/2907) Fixed the exit code and `run_status` value when the `cloud` output aborts a test.\n\n\n## Maintenance and internal improvements\n\n- [#2809](https://github.com/grafana/k6/pull/2809), [#2810](https://github.com/grafana/k6/pull/2810), [#2812](https://github.com/grafana/k6/pull/2812), [#2813](https://github.com/grafana/k6/pull/2813), [#2815](https://github.com/grafana/k6/pull/2815), [#2885](https://github.com/grafana/k6/pull/2885), [#2893](https://github.com/grafana/k6/pull/2893) A core component of test execution, the `Engine`, was removed, and the behavior heavily refactored. This change simplifies the code base and unblocks further improvements.\n- [#2821](https://github.com/grafana/k6/pull/2821), [#2864](https://github.com/grafana/k6/pull/2864) Our high-level integration test suite was refactored and expanded, increasing the coverage of behavior that closely replicates real-world usage.\n- [#2803](https://github.com/grafana/k6/pull/2803) Enabled checking for goroutine leaks.\n- [#2883](https://github.com/grafana/k6/pull/2883) The goja runtime has been updated.\n- [#2845](https://github.com/grafana/k6/pull/2845) Lint fixes in the `k6/http` module.\n- [#2831](https://github.com/grafana/k6/pull/2831) Compatibility with TC39 error messages was improved.\n- [#2846](https://github.com/grafana/k6/pull/2846) The initialization of `js.Bundle` was simplified.\n- [#2861](https://github.com/grafana/k6/pull/2861), [#2870](https://github.com/grafana/k6/pull/2870) Some deprecated features and dependencies in our CI pipeline were removed.\n- [#2882](https://github.com/grafana/k6/pull/2882) Our Dockerfile was improved with some linter suggestions. Thanks, @kempsterc!\n\n**Full Changelog**: https://github.com/grafana/k6/compare/v0.42.0...v0.43.0\n"
  },
  {
    "path": "release notes/v0.43.1.md",
    "content": "k6 v0.43.1 is a patch release containing a few bugfixes:\n- [#2926](https://github.com/grafana/k6/pull/2926) fixed a panic in `setup()` code when `vu.iterationInScenario` from `k6/execution` was used.\n- [#2934](https://github.com/grafana/k6/pull/2934) fixed a wrongly printed internal output ID to the `stdout` UI.\n- [#2938](https://github.com/grafana/k6/pull/2938) fixed a synchronization bug that caused k6 to get stuck after the end-of-test summary when sending the usage report took more than 3s. Thanks for [reporting this](https://github.com/grafana/k6/issues/2937), @ichasepucks!"
  },
  {
    "path": "release notes/v0.44.0.md",
    "content": "k6 v0.44.0 is here! 🎉 This release includes:\n\n- A new `k6/experimental/webcrypto` module implementing (partially) the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) specification.\n- A sampling option for the experimental tracing module.\n- Memory usage improvements.\n- Bug fixes and UX improvements.\n\nSome highlights from the `k6/experimental/browser` module are:\n\n- `locator.click` is now asynchronous, which is a breaking change.\n- `browserContext.addCookies` has now been implemented.\n- `browserType.Connect` has been implemented so k6 can now connect to an already running Chrome/Chromium browser instance.\n- Web vitals are natively supported when working with the browser module.\n\n## Breaking changes\n\nThe browser module is still in an `experimental` stage, and therefore breaking changes are expected as we are improving the APIs to make them more user-friendly.\n\n- [browser#790](https://github.com/grafana/xk6-browser/pull/790) Converted `locator.click` to async to have feature parity with `page.click` and `elementHandle.click`. Users must remember to work with `promise.All` and `page.waitForNavigation()` when a click action results in navigation.\n\n    A `locator.click` action that doesn't result in navigation can be used like so:\n    ```javascript\n    const tails = page.locator(\"input[value='Bet on tails!']\");\n    await tails.click(),\n    ```\n\n    A `locator.click` action that does result in a navigation can be used like so:\n    ```javascript\n    const tails = page.locator(\"input[value='Bet on tails!']\");\n    await Promise.all([\n      page.waitForNavigation(),\n      tails.click(),\n    ]);\n    ```\n\n- [browser#817](https://github.com/grafana/xk6-browser/pull/817) We've removed `--no-sandbox` from the default Chrome launch arguments. Now Chrome will launch with a sandbox, which is a more secure way of running the browser. If you are running tests under a `root` user, the browser will no longer launch unless the `--no-sandbox` argument is supplied. You can still pass this flag when launching a new Chrome instance using the `args` parameter on `chromium.launch`:\n\n    ```javascript\n    const browser = chromium.launch({\n      args: ['no-sandbox'],\n    });\n    ```\n\n- [browser#844](https://github.com/grafana/xk6-browser/pull/844) Removed the exported `version` param from the root module. Users should from now on reference the k6 version instead of the browser module version.\n- [browser#838](https://github.com/grafana/xk6-browser/pull/838) Removed the first meaningful paint metric. This metric is being deprecated across all the browsers, because the metric's definition relies on browser-specific implementation details, and we've now introduced web vitals in the browser module which is a reliable industry standard way to measure frontend performance. You can find more details [here](https://developer.chrome.com/en/docs/lighthouse/performance/first-meaningful-paint/).\n- [browser#843](https://github.com/grafana/xk6-browser/pull/843) Removed the build step from Github Actions. From this release onwards, no new standalone browser binaries will be built and available from the [releases](https://github.com/grafana/xk6-browser/releases) section. The latest version of the browser module will be available in the k6 binary which can be found in the [k6 releases](https://github.com/grafana/k6/releases) page.\n\n## New features\n\n### A new `k6/experimental/webcrypto` module implementing the Web Crypto API specification [#3007](https://github.com/grafana/k6/pull/3007)\n\nThis release includes a new `k6/experimental/webcrypto` module partially implementing the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) specification in k6.\n\n<details>\n<summary> Expand to see an example of the new functionality.</summary>\n\nThis example shows encrypting and decrypting of a \"Hello, World!\" string using AES-CBC algorithm.\n\n```javascript\nimport { crypto } from 'k6/experimental/webcrypto';\n\nexport default async function () {\n  const key = await crypto.subtle.generateKey(\n    {\n      name: 'AES-CBC',\n      length: 256,\n    },\n    true,\n    ['encrypt', 'decrypt']\n  );\n\n  const encoded = stringToArrayBuffer('Hello, World!');\n  const iv = crypto.getRandomValues(new Uint8Array(16));\n\n  const ciphertext = await crypto.subtle.encrypt(\n    {\n      name: 'AES-CBC',\n      iv: iv,\n    },\n    key,\n    encoded\n  );\n\n  const plaintext = await crypto.subtle.decrypt(\n    {\n      name: 'AES-CBC',\n      iv: iv,\n    },\n    key,\n    ciphertext\n  );\n\n  console.log(\n    'deciphered text == original text: ',\n    arrayBufferToHex(plaintext) === arrayBufferToHex(encoded)\n  );\n}\n\nfunction arrayBufferToHex(buffer) {\n  return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join('');\n}\n\nfunction stringToArrayBuffer(str) {\n  var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char\n  var bufView = new Uint16Array(buf);\n  for (var i = 0, strLen = str.length; i < strLen; i++) {\n    bufView[i] = str.charCodeAt(i);\n  }\n  return buf;\n}\n```\n</details>\n\nYou can see the list of currently supported APIs and algorithms in the project's [README](https://github.com/grafana/xk6-webcrypto/blob/v0.1.0/README.md#current-state). Documentation for the module is available [here](https://k6.io/docs/javascript-api/k6-experimental/webcrypto/).\n\n### Add sampling capabilities to the experimental tracing module [#2886](https://github.com/grafana/k6/pull/2886)\n\nThis release adds sampling capabilities to the tracing module. You can now specify a sampling rate with the `sampling` option when initializing a Client, or in the `tracing.InstrumentHTTP` function.\n\n### `browserContext.addCookies` [browser#760](https://github.com/grafana/xk6-browser/pull/760)\n\nCookies can now be added to a `BrowserContext` and all new `Page`s created from this context will have the cookie assigned to them. Thanks @zucchinho for implementing this feature!\n\n```javascript\nconst context = browser.newContext()\ncontext.addCookies([{name: 'myCookie', value: 'hello world', url: 'https://test.k6.io'}])\nconst page = context.newPage()\n```\n\n### `browserType.Connect` [browser#800](https://github.com/grafana/xk6-browser/pull/800)\n\nThere are cases where the user may want to connect to a remote browser instance where they have more control over the browser lifecycle, such as when working in a resource bound environment. This feature enables users to connect to a manually started Chrome/Chromium browser instance. It's a simple case of replacing `browser.launch` with `browser.connect` and supplying the CDP url as the first argument. Not all `launch` options will work with `connect` since the browser instance should already have started prior to working with `connect`. Since we assume that the user had decided to take ownership of starting the browser, we have made `browser.close` a NOOP when working with `browser.connect`, so the user will need to close the browser themselves.\n\n```javascript\nconst browser = chromium.connect('ws://127.0.0.1:1234/devtools/browser/e3bb7e53-ad0f-46f3-ae89-a8416868f4ce')\nconst page = browser.newPage();\n```\n\n### Web Vitals are now natively supported by the browser module [browser#836](https://github.com/grafana/xk6-browser/pull/836) [browser#847](https://github.com/grafana/xk6-browser/pull/847)\n\nWeb vitals are the defacto way for developers to measure their frontend performance using the core metrics:\n\n- Largest contentful paint ([LCP](https://web.dev/lcp/))\n- First input delay ([FID](https://web.dev/fid/))\n- Cumulative layout shift ([CLS](https://web.dev/cls/))\n\nThese measurements are now calculated for all tests without any additional work from your side. Simply run your test as you have been doing and you will be presented with the new metrics in the output. This is the output after running the [examples/fillform.js](https://github.com/grafana/xk6-browser/blob/main/examples/fillform.js) script:\n\n```bash\nwebvital_cumulative_layout_shift..........: avg=0        min=0        med=0        max=0        p(90)=0        p(95)=0\nwebvital_cumulative_layout_shift_good.....: 1       0.323332/s\nwebvital_first_contentful_paint...........: avg=278.86ms min=141.1ms  med=229.39ms max=466.1ms  p(90)=418.76ms p(95)=442.43ms\nwebvital_first_contentful_paint_good......: 3       0.969995/s\nwebvital_first_input_delay................: avg=300µs    min=200µs    med=300µs    max=399.99µs p(90)=379.99µs p(95)=389.99µs\nwebvital_first_input_delay_good...........: 2       0.646663/s\nwebvital_interaction_to_next_paint........: avg=16ms     min=16ms     med=16ms     max=16ms     p(90)=16ms     p(95)=16ms\nwebvital_interaction_to_next_paint_good...: 1       0.323332/s\nwebvital_largest_content_paint............: avg=303.6ms  min=141.1ms  med=303.6ms  max=466.1ms  p(90)=433.6ms  p(95)=449.85ms\nwebvital_largest_content_paint_good.......: 2       0.646663/s\nwebvital_time_to_first_byte...............: avg=205.23ms min=104.79ms med=188.39ms max=322.5ms  p(90)=295.67ms p(95)=309.08ms\nwebvital_time_to_first_byte_good..........: 3       0.969995/s\n```\n\nYou may have noticed other metrics in there too. We rely on the [web-vitals](https://github.com/GoogleChrome/web-vitals) JS library which exposes a few more metrics, so we've left them in for you to experiment with. You can find more details on all the browser module metrics in our [documentation](https://k6.io/docs/using-k6-browser/browser-metrics/).\n\nYou will no longer see `browser_first_contentful_paint` in the summary, and instead you can work with `webvital_first_contentful_paint`.\n\n### UX improvements and enhancements\n\n- [#2906](https://github.com/grafana/k6/pull/2906) Added multiple date-time formats for CSV output. Thanks, @Azanul!\n- [#2916](https://github.com/grafana/k6/pull/2916) k6 started to show the actual binary's name in the usage help. Thanks, @ariasmn!\n- [#2942](https://github.com/grafana/k6/pull/2942) Reference 'k6 cloud' instead of 'Load Impact' in docs and errors.\n- [#2985](https://github.com/grafana/k6/pull/2985) Added support of async functions for `setup` and `handleSummary`.\n- [#2901](https://github.com/grafana/k6/pull/2901) Added a warning when the number of time series exceeds 100 000, which could lead to potential out-of-memory issues.\n- [#2997](https://github.com/grafana/k6/pull/2997) Added a new exit code (`109`), used on a go panic.\n- [browser#788](https://github.com/grafana/xk6-browser/pull/788) Updated the browser readme to highlight that it is now a module in k6.\n- [browser#803](https://github.com/grafana/xk6-browser/pull/803) Users are now warned if the `browser.close` method is called more than once.\n- [browser#820](https://github.com/grafana/xk6-browser/pull/820) Added error handling to wildcard selectors, which cleans up the error output in the terminal.\n- [browser#848](https://github.com/grafana/xk6-browser/pull/848) Multiple k6 instances can now connect to one browser to run concurrent tests. This update empowers high-concurrency browser testing with multiple VUs and instances. Using the new `browserType.Connect` API, users can now connect to an existing browser instance and execute concurrent tests, which was not possible previously.\n\n## Bug fixes\n\n- [#2984](https://github.com/grafana/k6/pull/2984) Fixed wrongly assigned HTTP `POST` and `PUT` methods for the `tracing.instrumentHTTP`. Thanks, @marcin-maciej-seweryn!\n- [#2928](https://github.com/grafana/k6/pull/2928) Handled a new behavior of `filepath.Join` on windows with go1.20, which could cause issues for the `k6 archive` and `k6 cloud` commands.\n- [#2915](https://github.com/grafana/k6/pull/2915) Fixed `check` that could return incorrect values for some cases with many preallocated VUs.\n- [#2953](https://github.com/grafana/k6/pull/2953) Fixed active VU reporting by arrival-rate executors.\n- [#3006](https://github.com/grafana/k6/pull/3006) `xk6-websockets` updated to v0.2.0 which fixes a lock up of the whole k6.\n- [#3023](https://github.com/grafana/k6/pull/3023) Fixed Trend.Max's support of negative values.\n- [browser#781](https://github.com/grafana/xk6-browser/pull/781) Fixed mapping of `response` object's function from `jSON` to `json`.\n- [browser#779](https://github.com/grafana/xk6-browser/pull/779) Cleared Zombie processes on panic.\n- [browser#834](https://github.com/grafana/xk6-browser/pull/834) Fixed `page.close` so that it closes the current page and not the whole browser context.\n\n## Maintenance and internal improvements\n\n### Improved the per-VU buffer pool [#2879](https://github.com/grafana/k6/pull/2879)\n\nImproved the per-VU buffer pool which should greatly reduce memory usage, at a minor expense of higher CPU usage and lower request throughput. In some cases, this change can [reduce memory usage up to 50%](https://github.com/grafana/k6/issues/794#issuecomment-1406522459).\n\nThanks to @davidpst for the contribution!\n\nOther minor changes in this release:\n\n- [#3004](https://github.com/grafana/k6/pull/3004) Changed `eventloop.WaitOnRegistered` to execute all scheduled callbacks.\n- [#2881](https://github.com/grafana/k6/pull/2881) Refactored how modules are loaded. This is a preparation for the upcoming ESM support.\n- [#2920](https://github.com/grafana/k6/pull/2920) Updated Go version that we use for k6 compilation to 1.20.x. The docker image is also updated to use alpine:3.17.\n- [#2986](https://github.com/grafana/k6/pull/2986) Refactored goja's `isNullish` to be a part of `js/common`.\n- [#2960](https://github.com/grafana/k6/pull/2960) Refactored `sirupsen/logrus` usage.\n- [#2999](https://github.com/grafana/k6/pull/2999) Directly embed `lib.TestPreInitState` in `js/common.InitEnvironment`.\n- [#2892](https://github.com/grafana/k6/pull/2892) Added z/OS build flags for IBM z/OS compatibility. Thanks, @msradam!\n- [#2833](https://github.com/grafana/k6/pull/2833) Fixed detected memory leaks.\n- [#2931](https://github.com/grafana/k6/pull/2931), [#2940](https://github.com/grafana/k6/pull/2940), [#2895](https://github.com/grafana/k6/pull/2895), [#3002](https://github.com/grafana/k6/pull/3002) Updated k6's dependencies. Added `goja`'s generator support.\n- [#2947](https://github.com/grafana/k6/pull/2947), [#2943](https://github.com/grafana/k6/pull/2943), [#2946](https://github.com/grafana/k6/pull/2946), [#3009](https://github.com/grafana/k6/pull/3009), [#3012](https://github.com/grafana/k6/pull/3012), [#2894](https://github.com/grafana/k6/pull/2894) Tests' fixes, refactoring, and improvements.\n- [#2891](https://github.com/grafana/k6/pull/2891), [#2921](https://github.com/grafana/k6/pull/2921), [#2923](https://github.com/grafana/k6/pull/2923), [#2990](https://github.com/grafana/k6/pull/2990), [#2995](https://github.com/grafana/k6/pull/2995), [#3016](https://github.com/grafana/k6/pull/3016), [#2989](https://github.com/grafana/k6/pull/2989) Linters and formatting fixes.\n- [#3005](https://github.com/grafana/k6/pull/3005) The samples catalog was renamed to examples.\n- [browser#776](https://github.com/grafana/xk6-browser/pull/776) Fixed a test for preset flags for Chrome on macOS.\n- [browser#782](https://github.com/grafana/xk6-browser/pull/782), [browser#783](https://github.com/grafana/xk6-browser/pull/783), [browser#826](https://github.com/grafana/xk6-browser/pull/826) Fixed and refactored the Go-JS mapping.\n- [browser#797](https://github.com/grafana/xk6-browser/pull/797), [browser#832](https://github.com/grafana/xk6-browser/pull/832) Fixed multi browser close.\n- [browser#796](https://github.com/grafana/xk6-browser/pull/796), [browser#810](https://github.com/grafana/xk6-browser/pull/810) Refactored `browserContext.SetExtraHTTPHeaders` to work with errors and ErrFatal.\n- [browser#798](https://github.com/grafana/xk6-browser/pull/798), [browser#799](https://github.com/grafana/xk6-browser/pull/799) Added more tests for the Go-JS mapping layer.\n- [browser#802](https://github.com/grafana/xk6-browser/pull/802) Added a helper to assert on the logs and dump the logs for easier debugging.\n- [browser#807](https://github.com/grafana/xk6-browser/pull/807) Fixed incorrect keyboard key code on up/down key presses.\n- [browser#819](https://github.com/grafana/xk6-browser/pull/819) `Browser.Launch` now transitions to `Browser.Connect` when a CDP URL is provided in an environment variable.\n- [browser#821](https://github.com/grafana/xk6-browser/pull/821), [browser#824](https://github.com/grafana/xk6-browser/pull/824), [browser#830](https://github.com/grafana/xk6-browser/pull/830) Upgraded dependencies and fixed breaking changes.\n"
  },
  {
    "path": "release notes/v0.44.1.md",
    "content": "k6 v0.44.1 is a patch release that fixes a couple of packaging issues:\n- [#3055](https://github.com/grafana/k6/issues/3055) due to an oversight, the k6 package signing key in our RPM repository wasn't updated when its expiration date was extended in March.\n- [#3060](https://github.com/grafana/k6/issues/3060) fixed building of Docker image due to a missing pinned `ca-certificates` version.\n\nThere are no functional changes in k6 compared to v0.44.0.\n"
  },
  {
    "path": "release notes/v0.45.0.md",
    "content": "k6 v0.45.0 is here 🎉! This release includes:\n\n- Experimental gRPC streaming support.\n- Update scripts in the cloud without running tests.\n- JS Metadata API.\n- A lot of internal changes and bugfixes.\n\n## Breaking changes\n\n* [#3066](https://github.com/grafana/k6/pull/3066) k6 will warn users about metric names [incompatible with OpenTelemetry or Prometheus](https://k6.io/docs/using-k6/metrics/#metric-name-restrictions). This is planned to [become an error](https://github.com/grafana/k6/issues/3065) with v0.48.0.\n* [browser#851](https://github.com/grafana/xk6-browser/pull/851) Remove existing browser namespaced metrics. These have been deprecated in favor of Web Vitals metrics.\n\n## New features\n\n### Experimental gRPC module with streaming support [#3107](https://github.com/grafana/k6/pull/3107)\n\nThere is a new experimental module `k6/experimental/grpc`. It is a copy of the `k6/net/grpc` module with added stream support [#2020](https://github.com/grafana/k6/issues/2020). \n\n\n<details>\n<summary> Expand to see an example of the new functionality.</summary>\n\nThis example shows server streaming:\n\n```javascript\nimport { Client, Stream } from 'k6/experimental/grpc';\nimport { sleep } from 'k6';\n\nconst COORD_FACTOR = 1e7;\n// to run this sample, you need to start the grpc server first.\n// to start the grpc server, run the following command in k6 repository's root:\n// go run -mod=mod examples/grpc_server/*.go\n// (golang should be installed)\nconst GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';\nconst GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../grpc_server/route_guide.proto';\n\nlet client = new Client();\n\nclient.load([], GRPC_PROTO_PATH);\n\nexport default () => {\n  client.connect(GRPC_ADDR, { plaintext: true });\n\n  const stream = new Stream(client, 'main.FeatureExplorer/ListFeatures', null);\n\n  stream.on('data', function (feature) {\n    console.log(\n      'Found feature called \"' +\n        feature.name +\n        '\" at ' +\n        feature.location.latitude / COORD_FACTOR +\n        ', ' +\n        feature.location.longitude / COORD_FACTOR\n    );\n  });\n\n  stream.on('end', function () {\n    // The server has finished sending\n    client.close();\n    console.log('All done');\n  });\n\n  stream.on('error', function (e) {\n    // An error has occurred and the stream has been closed.\n    console.log('Error: ' + JSON.stringify(e));\n  });\n\n  // send a message to the server\n  stream.write({\n    lo: {\n      latitude: 400000000,\n      longitude: -750000000,\n    },\n    hi: {\n      latitude: 420000000,\n      longitude: -730000000,\n    },\n  });\n\n  sleep(0.5);\n};\n```\n</details>\n\nYou can just replace `k6/net/grpc` import with `k6/experimental/grpc` to use the new functionality. Documentation for the module is available [here](https://k6.io/docs/javascript-api/k6-experimental/grpc/).\n\nIn the future, this functionality will be moved to the `k6/net/grpc` module.\n\n### You can now only upload a test to the cloud without running it [#3030](https://github.com/grafana/k6/pull/3030)\n\nFor [years users have wanted](https://github.com/grafana/k6-cloud-feature-requests/issues/22) to be able to update the test that is saved in the cloud but *not* run it at this exact point.\n\nThis is now possible by adding `--upload-only` when invoking `k6 cloud` as in `k6 cloud --upload-only script.js`.\n\nThis is likely going to be most useful in a CI on the actual test script project. Now that CI can just run `k6 cloud --upload-only new-version-of-script.js` on \"release\".\n\nAnd later on that newer version will be used. For example by a [scheduled run](https://k6.io/docs/cloud/manage/scheduled-tests/). \n\n### Setting sample metadata API [#3037](https://github.com/grafana/k6/pull/3037)\n\nSupport for high-cardinality metrics metadata was added in v0.41.0, but it wasn't accessible from test scripts. It's now possible to set or delete metadata for the whole VU with a similar API as used for tags:\n```javascript\nimport exec from \"k6/execution\";\n\nexport default () => {\n  exec.vu.metrics.metadata[\"my_cool_id\"] = \"a very unique value\";\n  // all metrics from here on will have this metadata set\n  delete exec.vu.metrics.metadata[\"my_cool_id\"];\n  // all metrics from here on will *not* have the metadata set\n}\n```\n\nThis also introduces the sub-object `metrics` on the `vu` object.\nApart from `metadata` it has another property `tags`. This is meant to be the new way to set tags instead of using `exec.vu.tags`. \n\nThere are no current plans to replace `exec.vu.tags` with `exec.vu.metrics.tags`.\n\n### UX improvements and enhancements\n\n- [#3099](https://github.com/grafana/k6/pull/3099) replace \"breached\" with \"crossed\" in logs around thresholds. Thanks to @MattDodsonEnglish 🙇.\n- [#3102](https://github.com/grafana/k6/pull/3102) Better error message when SharedArray constructor is provided with an async function. This is not supported, but the original message wasn't very clear.\n- [#3089](https://github.com/grafana/k6/pull/3089) Add Software Bill of Materials (SBOM) reports to k6 releases. Thanks to @SadFaceSmith 🙇.\n- [goja#510](https://github.com/dop251/goja/pull/510) `JSON.parse` will now fail with a friendlier error message.\n\n## Bug fixes\n\n* [browser#852](https://github.com/grafana/xk6-browser/pull/852) Fix `Locator.WaitFor` for `detached` and `hidden` states.\n* [browser#859](https://github.com/grafana/xk6-browser/pull/859) Fix remote object parsing when subtype is `null`.\n\n## Maintenance and internal improvements\n\n- [#2991](https://github.com/grafana/k6/pull/2991) Refactor JS modules system so that is usable in tests. Which allowed enabling the tc39 tests for modules [#3040](https://github.com/grafana/k6/pull/3040).\n- [#3025](https://github.com/grafana/k6/pull/3025) Internally stop referring to afero and use an internal package to do all file system interaction. That package still uses afero.\n- [#3036](https://github.com/grafana/k6/pull/3036) and [#3053](https://github.com/grafana/k6/pull/3053) Add options to `scenarios` for usage by browser module. \n* [#3058](https://github.com/grafana/k6/pull/3058) fix repetitive `the`. Thank you, @cuishuang 🙇.\n- [#3064](https://github.com/grafana/k6/pull/3064), [#3070](https://github.com/grafana/k6/pull/3070),  [#3075](https://github.com/grafana/k6/pull/3075) and [#3106](https://github.com/grafana/k6/pull/3106) Go dependencies updates. \n- [#3067](https://github.com/grafana/k6/pull/3067) Add method to retrieve all registered metrics.\n- [#3068](https://github.com/grafana/k6/pull/3068) Add metric Sink constructor.\n- [#3078](https://github.com/grafana/k6/pull/3078) Pin base Docker builder image to Alpine 3.17. Thank you, @arukiidou 🙇.\n- [#3086](https://github.com/grafana/k6/pull/3086) Fix downloading `.golangci.yml` for PRs from forks. \n- [#3088](https://github.com/grafana/k6/pull/3088) Make TestDNSResolver less flaky. \n- [#3094](https://github.com/grafana/k6/pull/3094) Fix example from the run command. Thanks to @rocktwotj 🙇.\n- [#3095](https://github.com/grafana/k6/pull/3095) Maintenance update of `.golangci.yml`.\n- [#3103](https://github.com/grafana/k6/pull/3103) Fix lint and logical issues in `k6/data` module tests.\n- [#3045](https://github.com/grafana/k6/pull/3045), [#3049](https://github.com/grafana/k6/pull/3049), [#3073](https://github.com/grafana/k6/pull/3073) and [#3044](https://github.com/grafana/k6/pull/3044) New issues are now automatically assigned to maintainers, to improve response time on issues. Both new issue and new PR assignments are now not using external actions.\n- [#3109](https://github.com/grafana/k6/pull/3109) Add a way to get the cloudapi Client's base URL. Thanks to @yorugac 🙇.\n\n## Roadmap\n\nWe're excited to share [our public roadmap](https://github.com/orgs/grafana/projects/443/views/1), outlining the upcoming features and improvements we have planned.\n\nWe hope this updated roadmap provides a clear overview of our plans for k6's future development. As always, we welcome feedback, corrections, and suggestions to make this roadmap more comprehensive, accessible, and valuable for the k6 community.\n\n### Cloud output v2\n\nWork on a new version of the cloud output has been ongoing over this cycle.\n\nWhile functionally it is now mostly complete, we feel like more testing is still needed and some smaller issues need to be ironed out.\n\nOver the next cycle we will be testing it internally, and in v0.46.0 it will be generally available as the default Cloud output. It will still be possible to use the current version via an option, but we plan to gradually deprecate it.\n\nThe new output has some benefits over the previous one:\n- Binary (protobuf) format instead of JSON [#2963](https://github.com/grafana/k6/pull/2963)\n- Samples aggregation for every metric instead of only for HTTP ones [#3071](https://github.com/grafana/k6/pull/3071)\n- HDR Histogram generation for trend-type metrics [#3027](https://github.com/grafana/k6/pull/3027)\n\nThis in general makes the payload sent for tests with a lot of samples much smaller, which also in most cases has turned out to lower the CPU and memory usage.\n\n Other related PRs: [#3041](https://github.com/grafana/k6/pull/3041), [#3061](https://github.com/grafana/k6/pull/3061), [#3063](https://github.com/grafana/k6/pull/3063), [#3072](https://github.com/grafana/k6/pull/3072), [#3082](https://github.com/grafana/k6/pull/3082), [#3083](https://github.com/grafana/k6/pull/3083), [#3085](https://github.com/grafana/k6/pull/3085), [#3098](https://github.com/grafana/k6/pull/3098), [#3105](https://github.com/grafana/k6/pull/3105)\n"
  },
  {
    "path": "release notes/v0.46.0.md",
    "content": "k6 `v0.46` is here 🎉! This release includes:\n\n- xk6-browser extension version bump to `v1.0.2`, which includes breaking changes.\n- Send custom headers to Loki log output\n- Cloud Traces, the new integration between k6 and [Tempo](https://github.com/grafana/tempo)\n- Ability to configure TLS per gRPC connection\n- Cloud output v2\n- And many UX improvements, bug fixes, and internal improvements\n\n## Breaking Changes\n\n### Browser\n\nIn this release, the xk6-browser extension version is bumped up to `v1.0.2`, as it includes multiple breaking changes concerning options, browser lifecycle, and metrics. See the [migration guide](https://k6.io/docs/using-k6-browser/migrating-to-k6-v0-46/) for making your test scripts compatible with the new version.\n\n**Options** `devtools`, `env` and `proxy` are deprecated ([browser#868](https://github.com/grafana/xk6-browser/pull/868), [browser#870](https://github.com/grafana/xk6-browser/pull/870), [browser#872](https://github.com/grafana/xk6-browser/pull/872)). Additionally, browser `launch`/`connect` options are no longer defined in the corresponding JS API methods, instead the test execution related options are now defined inside the browser scenario options (see [#3036](https://github.com/grafana/k6/pull/3036)), and the other more \"environmental options\", such as `headless`, `debug`, `executablePath`, are set as ENV vars. Also, the `slowMo` option is no longer supported, although it might be supported again in the future through a different API ([browser#876](https://github.com/grafana/xk6-browser/pull/876)).\n\n**Metrics** also went through a few changes. The Web Vitals metrics are renamed to use the `browser_` prefix and short namings (e.g.: `webvital_first_input_delay` -> `browser_web_vital_fid`) ([browser#885](https://github.com/grafana/xk6-browser/pull/885), [browser#903](https://github.com/grafana/xk6-browser/pull/903)), and the rating metric is removed, as it is now set as a label in the corresponding Web Vitals metrics ([browser#915](https://github.com/grafana/xk6-browser/pull/915)).\nThe browser HTTP metrics have also been modified, as these are now split from the HTTP module ones, so there are new `browser_` prefixed HTTP metrics, specifically for request duration and failed requests ([browser#916](https://github.com/grafana/xk6-browser/pull/916)).\n\nAnother big change introduced in this version affects the way the **browser lifecycle** is handled. Users no longer have to explicitly initialize/close the browser instance through the JS API. Instead, a browser instance will be automatically initialized/closed at the beginning/end of each iteration if the browser type is set in scenario options (see [#3036](https://github.com/grafana/k6/pull/3036)). This also means that the `chromium` entity from `k6/experimental/browser` import path is no longer valid. Instead, the `browser` entity provides access to the browser methods such as `browser.newPage()` ([browser#910](https://github.com/grafana/xk6-browser/pull/910), [browser#944](https://github.com/grafana/xk6-browser/pull/944)). This change means that the `browser.on()` method is no longer applicable, and therefore it has been removed ([browser#919](https://github.com/grafana/xk6-browser/pull/919)).\n\nAdditionally, related to **import changes**, the browser module version is no longer an exported field ([browser#923](https://github.com/grafana/xk6-browser/pull/923)).\n\nLast but not least, this release also includes constraints on **browser contexts** usage as now only one `browserContext` is allowed per iteration, which means that the user can create a new `browserContext`, close it, and then create it again; but can not have more than one \"live\" `browserContext`. Instead, [scenarios](https://k6.io/docs/using-k6/scenarios/) should be used to separate independent actions in a test ([browser#929](https://github.com/grafana/xk6-browser/pull/929), [browser#945](https://github.com/grafana/xk6-browser/pull/945)).\n\nWith all these changes, a simple browser test now looks like:\n```js\nimport { browser } from 'k6/experimental/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium', // chromium is the only supported browser type so as long as\n                            // the option is set, Chromium/Google Chrome will be used\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = browser.newPage();\n  try {\n    await page.goto('https://grafana.com')\n  } finally {\n    page.close();\n  }\n}\n```\n\n### Deprecations\n\n- [#3121](https://github.com/grafana/k6/issues/3121) deprecates the `loadimpact/k6` docker image. We recommend switching to the `grafana/k6` image as soon as possible.\n\n\n## New features\n\n### Loki log output sending additional headers [#3227](https://github.com/grafana/k6/pull/3227)\n\nk6 has been able to send logs to [Loki](https://github.com/grafana/loki) for nearly 3 years since [v0.28.0](https://github.com/grafana/k6/releases/tag/v0.28.0) but didn't support any way to authenticate.\n\nNow, it can be configured to send additional headers on every request.\n\nThis can be done by using the new `header` config option, similar to `label`:\n\n```\nk6 --log-output=loki=http://example.org,header.X-My-Header=123,header.Authorization=mytoken ...\n```\n\nThe example above will now send the header `X-My-Header` with the value `123` and the `Authorization` header with the value `mytoken`.\n\nThanks to @federicotdn for adding this feature.\n\n### Cloud Traces [#3100](https://github.com/grafana/k6/pull/3100), [#3202](https://github.com/grafana/k6/pull/3202)\n\nThis release supports the new integration between k6 and Tempo in the cloud. [Grafana Cloud k6](https://grafana.com/products/cloud/k6) and Grafana Cloud Tempo customers will be able to start their traces in k6 using the existing `k6/experimental/tracing` module to enrich their test run analysis page with metrics and aggregations from tracing data.\n\nThe new Cloud traces will work \"out of the box\" for `k6 cloud` runs. In case of `k6 run` execution, the `K6_CLOUD_TRACES_ENABLED` environment variable has to be set to `true`.\n\n### Ability to configure TLS per gRPC connection [#3159](https://github.com/grafana/k6/pull/3159), [xk6-grpc#25](https://github.com/grafana/xk6-grpc/pull/25)\n\nThe `k6/net/grpc` and `k6/experimental/grpc` modules now support configuring TLS per-connection via [ConnectParams](https://k6.io/docs/javascript-api/k6-net-grpc/client/client-connect/#connectparams). This is useful when connecting to a single gRPC server, using different TLS settings for each VUs, as well as when connecting to multiple gRPC servers from the same VU.\n\n<details>\n<summary> Expand to see an example of the new functionality.</summary>\n\n```javascript\nimport grpc from \"k6/experimental/grpc\";\nimport { check } from \"k6\";\nimport { SharedArray } from \"k6/data\";\nimport exec from \"k6/execution\";\n\n// note: the services in this example don't exist. If you would like\n// to run this example, make sure to replace the URLs, and\n// the cacerts, cert, key, and password variables.\nconst grpcArgs = new SharedArray(\"grpc\", () => {\n    // Using SharedArray here so that not every VU gets a copy of every certificate a key\n    return [\n        {\n            host: \"foo1.grpcbin.test.k6.io:9001\",\n            plaintext: false,\n            params: {\n                tls: {\n                    cacerts: [open(\"cacerts0.pem\")],\n                    cert: open(\"cert0.pem\"),\n                    key: open(\"key0.pem\"),\n                },\n            },\n        },\n        {\n            host: \"foo2.grpcbin.test.k6.io:9002\",\n            params: {\n                plaintext: false,\n                tls: {\n                    cacerts: open(\"cacerts1.pem\"),\n                    cert: open(\"cert1.pem\"),\n                    key: open(\"key1.pem\"),\n                    password: \"cert1-passphrase\",\n                },\n            },\n        },\n    ];\n});\n\nconst client = new grpc.Client();\n\nexport default () => {\n    if (__ITER === 0) {\n        // Take one config and use it for this one VU\n        let grpcArg = grpcArgs[exec.vu.idInTest % grpcArgs.length];\n        client.connect(grpcArg.host, grpcArg.params);\n    }\n\n    const response = client.invoke(\"hello.HelloService/SayHello\", {\n        greeting: \"Bert\",\n    });\n\n    check(response, {\n        \"status is OK\": (r) => r && r.status === grpc.StatusOK,\n    });\n\n    console.log(JSON.stringify(response.message));\n};\n```\n\n</details>\n\nThanks @chrismoran-mica for the contribution 🙇‍♂️.\n\n### Cloud Output v2 [#3117](https://github.com/grafana/k6/issues/3117)\n\nAfter years of great service, we decided to refresh the k6 Cloud output introducing a more efficient end-to-end solution for ingesting the generated tests' metrics. The main change regards the protocol used for flushing metrics that is now a binary-based payload over HTTP.\n\nThe new output reduces the resources a load generator uses for tests that produce many metrics. There is no significant difference in the user experience; it's expected to be the same.\n\nThe one thing worth highlighting is that the new output is strict about tags, and it'll drops tags if they are reserved. For example:\n\n- A custom tag named `test_run_id`, since that is reserved for internal k6 Cloud operations\n- Any tag with a key that starts with two underscores (`__`), that is marked by Prometheus convention as reserved\n\nThis is not yet the default Cloud output for the test runs executed from local machines (`k6 run -o cloud`), but it is expected to be transparently enabled in the upcoming weeks.\n\nThe full list of related PRs: [#3104](https://github.com/grafana/k6/pull/3104), [#3108](https://github.com/grafana/k6/pull/3108), [#3120](https://github.com/grafana/k6/pull/3120), [#3125](https://github.com/grafana/k6/pull/3125), [#3162](https://github.com/grafana/k6/pull/3162), [#3169](https://github.com/grafana/k6/pull/3169), [#3182](https://github.com/grafana/k6/pull/3182), [#3186](https://github.com/grafana/k6/pull/3186), [#3187](https://github.com/grafana/k6/pull/3187), [#3193](https://github.com/grafana/k6/pull/3193), [#3195](https://github.com/grafana/k6/pull/3195), [#3206](https://github.com/grafana/k6/pull/3206), [#3226](https://github.com/grafana/k6/pull/3226), [#3157](https://github.com/grafana/k6/pull/3157), [#3172](https://github.com/grafana/k6/pull/3172).\n\n\n## UX improvements and enhancements\n\n- [#3176](https://github.com/grafana/k6/pull/3176) Adds a `js/promises` package, which enables extension developers to easily create promises that will be dispatched to the eventloop using the `New` function.\n- [#3181](https://github.com/grafana/k6/pull/3181) Adds a `RunOnEventLoop` method to the `modulestest.Runtime` type, which allows extensions developers to run code on the event loop from their tests.\n- [xk6-grpc#19](https://github.com/grafana/xk6-grpc/pull/19) Fixes EOF (end of file) error that was produced when writing to a closed gRPC stream. Additionally, if no error handlers are set up, the error is logged to the console.\n- [browser#881](https://github.com/grafana/xk6-browser/pull/881) Adds a new `browser_http_req_failed` metric.\n- [browser#901](https://github.com/grafana/xk6-browser/pull/901) Adds support for shadow DOM piercing in `locator`. Thanks to @tmc for its implementation.\n- [browser#953](https://github.com/grafana/xk6-browser/pull/953) Improves Web Vitals reporting for better accuracy and consistency.\n\n## Bug fixes\n\n- [#3178](https://github.com/grafana/k6/pull/3178), [xk6-grpc#23](https://github.com/grafana/xk6-grpc/pull/23) Fixes the registration of nested protobuf messages in the gRPC module. Thanks @thiagodpf for reporting and fixing the bug!\n- [#3194](https://github.com/grafana/k6/pull/3194) Fixes loki log output exiting before push is finished.\n- [#3231](https://github.com/grafana/k6/pull/3231) Fixes the tracing module sampling option to default to `1.0` when not set by the user.\n- [browser#866](https://github.com/grafana/xk6-browser/pull/866) Disables the timeout on browser process execution.\n- [browser#942](https://github.com/grafana/xk6-browser/pull/942) Fixes deadlock in `frameNavigated`.\n- [browser#943](https://github.com/grafana/xk6-browser/pull/943) Fixes a race condition in navigation and lifecycle events.\n- [browser#979](https://github.com/grafana/xk6-browser/pull/979) Fixes a deadlock on `pagehide` event evaluation when `page.close()` is called.\n- [browser#980](https://github.com/grafana/xk6-browser/pull/980) Fixes Loki log output for console log serializer.\n- [browser#991](https://github.com/grafana/xk6-browser/pull/991) Fixes data directory not being cleared during `browser.close()` panic.\n\n## Maintenance and internal improvements\n\n- [#3112](https://github.com/grafana/k6/pull/3112) Adds an event system for core JS modules.\n- [#3170](https://github.com/grafana/k6/pull/3170) Upgraded the version of gRPC k6 demo service dependency to address a security vulnerability ([CVE-2023-32731]).\n- [#3211](https://github.com/grafana/k6/pull/3211) Updates the experimental gRPC module version used by k6.\n- [#3210](https://github.com/grafana/k6/pull/3210) Updates the xk6-output-prometheus-remote version used by k6.\n- [#3136](https://github.com/grafana/k6/pull/3136) Updates k6 Go dependencies.\n- [#3131](https://github.com/grafana/k6/pull/3131) Updates our Pull Request template to be more structured and include a checklist for contributors.\n- [#3177](https://github.com/grafana/k6/pull/3177) Updates the version of golangci-lint we use to the latest version.\n- [#3163](https://github.com/grafana/k6/pull/3163) Fixes our [gRPC example](https://github.com/grafana/k6/blob/8fa0e6b9a8b63f430df34047e4393b281ff9ee30/examples/grpc.js).\n- [#3196](https://github.com/grafana/k6/pull/3196) Logs packages lint fixes, and test for loki flushing at end.\n- [browser#849](https://github.com/grafana/xk6-browser/pull/849), [browser#972](https://github.com/grafana/xk6-browser/pull/972), [browser#977](https://github.com/grafana/xk6-browser/pull/977), [browser#978](https://github.com/grafana/xk6-browser/pull/978), [browser#983](https://github.com/grafana/xk6-browser/pull/983) Log fixes and improvements.\n- [browser#889](https://github.com/grafana/xk6-browser/pull/889), [browser#889](https://github.com/grafana/xk6-browser/pull/899), [browser#902](https://github.com/grafana/xk6-browser/pull/902), [browser#935](https://github.com/grafana/xk6-browser/pull/935), [browser#936](https://github.com/grafana/xk6-browser/pull/936) Internal refactors.\n- [browser#904](https://github.com/grafana/xk6-browser/pull/904), [browser#959](https://github.com/grafana/xk6-browser/pull/959) Test fixes.\n - [browser#906](https://github.com/grafana/xk6-browser/pull/906) Parses the scenarios JSON definition from the `K6_INSTANCE_SCENARIOS` environment variable.\n - [browser#918](https://github.com/grafana/xk6-browser/pull/918) Replaces the usage of `os.LookupEnv` for k6 `LookupEnv` and abstracts environment variables lookup.\n - [browser#984](https://github.com/grafana/xk6-browser/pull/984) Ensures CDP requests message ID are unique at the connection scope.\n\n"
  },
  {
    "path": "release notes/v0.47.0.md",
    "content": "k6 `v0.47.0` is here 🎉! This release includes:\n\n## Deprecations\n\n- [#3347](https://github.com/grafana/k6/pull/3347) The built-in `statsd` output option has been deprecated, and users should use the [xk6-output-statsd](https://github.com/LeonAdato/xk6-output-statsd) extension instead. See [#2982](https://github.com/grafana/k6/issues/2982) for future plans.\n- [#3288](https://github.com/grafana/k6/pull/3288) Loading remote modules now requires users to prepend them with `https://`. Before, k6 would try to resolve importing remote modules by prepending `https://` if it was missing. This behavior has been deprecated and will be fully removed in the next release (v0.48.0).\n\n## New features\n\n### Add gRPC's binary metadata support [#3234](https://github.com/grafana/k6/pull/3234), [xk6-grpc#46](https://github.com/grafana/xk6-grpc/pull/46)\n\nThe k6 gRPC modules (`k6/net/grpc` and `k6/experimental/grpc`) now support handling binary metadata that uses the `-bin` postfix, according to the gRPC specification.\n\n```js\nlet resp = client.invoke(\"grpc.testing.TestService/EmptyCall\", {}, { metadata: { \"X-Load-Tester-bin\": new Uint8Array([2, 200]) } })\n```\n\nThanks to @sapphire-janrain for the contribution!\n\n### Add gRPC's reflection metadata support [#3343](https://github.com/grafana/k6/pull/3343), [xk6-grpc#46](https://github.com/grafana/xk6-grpc/pull/46)\n\nThe k6 gRPC modules (`k6/net/grpc` and `k6/experimental/grpc`) now support adding metadata to reflection requests by using a new connection parameter [`reflectMetadata`](https://k6.io/docs/javascript-api/k6-net-grpc/client/client-connect/#connectparams).\n\n### Higher precision for Trend metrics in Grafana Cloud k6 [#3302](https://github.com/grafana/k6/pull/3302)\n\nGrafana Cloud k6 is now able to store and visualize Trend metrics up to 3 digits of precision for decimal numbers.\n\n### Docker support for browser-based tests [#3199](https://github.com/grafana/k6/pull/3199)\n\nk6 is now publishig Docker images that include Chromium web browser. This allows k6 users to run tests that use [Browser API](https://k6.io/docs/javascript-api/k6-experimental/browser/) without having to install Chrome first. Check the [\"A note on running browser tests\" section](https://hub.docker.com/r/grafana/k6) of the Overview page on DockerHub for details.\n\n### Docker images for ARM64 architecture [#3320](https://github.com/grafana/k6/pull/3320)\n\nThe k6's release process now builds and pushes dedicated Docker images for ARM64. Check k6's [tags page](https://hub.docker.com/r/grafana/k6/tags) on DockerHub for details.\n\n### New authentication methods and HTTP headers API for Prometheus remote write output [xk6-output-prometheus-remote#143](https://github.com/grafana/xk6-output-prometheus-remote/pull/143), [xk6-output-prometheus-remote#145](https://github.com/grafana/xk6-output-prometheus-remote/pull/145), [xk6-output-prometheus-remote#147](https://github.com/grafana/xk6-output-prometheus-remote/pull/147)\n\nThe experimental Prometheus remote write output now supports two new authentication methods: Bearer token and TLS certificates. Check out the [documentation](https://k6.io/docs/results-output/real-time/prometheus-remote-write/#options) to learn more about how to define them using the new environment variables.\nWe've also added the `K6_PROMETHEUS_RW_HTTP_HEADERS` that defines a new and more convenient way to set custom HTTP headers to pass through each flush metrics' request. \n\n### Improved the browser module's cookie API\n\nThe browser module now provides a more complete and robust API for handling cookies. The cookie API was stabilized by defining a new [`Cookie` class](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/cookie) ([browser#1008](https://github.com/grafana/xk6-browser/pull/1008), [browser#1030](https://github.com/grafana/xk6-browser/pull/1030)) that can be used while creating and retrieving cookies. This enabled us to add a new [`browserContext.cookies([urls])`](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/cookies/) method ([browser#1005](https://github.com/grafana/xk6-browser/pull/1005)) that returns all cookies from the current [browser context](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext). The new API also supports filtering cookies by URL ([browser#1016](https://github.com/grafana/xk6-browser/pull/1016)).\n\nThat led to fixing a bug where the `expires` field was not being set correctly while adding cookies using the [`context.addCookie()`](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/addcookies/) method ([browser#1031](https://github.com/grafana/xk6-browser/pull/1031)). Lastly, the existing [`context.clearCookies()`](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext/clearcookies) method was fixed to clear all cookies from the current [browser context](https://k6.io/docs/javascript-api/k6-experimental/browser/browsercontext) ([browser#1040](https://github.com/grafana/xk6-browser/pull/1040)).\n\n```js\nconst context = browser.newContext();\ncontext.addCookies([\n    {name: 'foo', value: 'bar', url: 'https://test.k6.io'},\n    {name: 'baz', value: 'qux', url: 'https://grafana.com'},\n]);\n\nconst cookies = context.cookies('https://test.k6.io');\nconsole.log(cookies.length);         // 1\nconsole.log(cookies[0].name);        // foo\nconsole.log(cookies[0].value);       // bar\n\ncontext.clearCookies();\nconsole.log(context.cookies.length); // 0\n```\n\n### Add support for browser module's `page.on('console')` [browser#1006](https://github.com/grafana/xk6-browser/pull/1006)\n\nAllows users to register a handler to be executed every time the `console` API methods are called from within the page's JavaScript context. The arguments passed into the handler are defined by the [ConsoleMessage](https://k6.io/docs/javascript-api/k6-experimental/browser/consolemessage/) class.\n\n```js\npage.on('console', msg => {\n    check(msg, {\n        'assertConsoleMessageType': msg => msg.type() == 'log',\n        'assertConsoleMessageText': msg => msg.text() == 'this is a console.log message 42',\n        'assertConsoleMessageArgs0': msg => msg.args()[0].jsonValue() == 'this is a console.log message',\n        'assertConsoleMessageArgs1': msg => msg.args()[1].jsonValue() == 42,\n    });\n});\n\npage.evaluate(() => console.log('this is a console.log message', 42));\n```\n\n## UX improvements and enhancements\n\n- [#3338](https://github.com/grafana/k6/pull/3338), [xk6-grpc#48](https://github.com/grafana/xk6-grpc/pull/48) Adds support for the gRPC reflection protocol v1.\n- [#3290](https://github.com/grafana/k6/pull/3290) Adds error logging when executing `setup` and `teardown` via REST API. Thanks to @kmtym1998 for the contribution!\n- [#3327](https://github.com/grafana/k6/pull/3327) Adds commit identifier for the k6 build when running `k6 version`.\n- [#3340](https://github.com/grafana/k6/pull/3340) Updates k6 ``*-with-browser`` Docker images to automatically set the `no-sandbox` environment variable.\n- [#3335](https://github.com/grafana/k6/pull/3335) The character limit for metric names increased from 63 to 128 after the OpenTelemetry update. k6 will return an error starting on the next release (v0.48.0) if users hit the limit.\n- [browser#1007](https://github.com/grafana/xk6-browser/pull/1007) Adds a `k6` object (`window.k6 = {};`) to help identify k6 browser module tests.\n- [browser#1022](https://github.com/grafana/xk6-browser/pull/1022) Refactors the `check` in `examples/fillform.js` so that it matches the type definitions and documentation for `check`.\n\n## Bug fixes\n\n- [xk6-grpc#47](https://github.com/grafana/xk6-grpc/pull/47) Fixes the premature closing of a gRPC stream when a stream's client has finished sending. Thanks to @thiagodpf for reporting!\n- [#3344](https://github.com/grafana/k6/pull/3344), [xk6-grpc#49](https://github.com/grafana/xk6-grpc/pull/49) Adds support for Google's protobuf wrappers. Thanks to @zibul444 for reporting!\n- [#3308](https://github.com/grafana/k6/pull/3308) Updates `goja` version, and fixes a compiler bug when a class is declared in a function with an argument.\n- [browser#1039](https://github.com/grafana/xk6-browser/pull/1039) Fixes `goja` conversions while adding and retrieving cookies.\n- [browser#1038](https://github.com/grafana/xk6-browser/pull/1038) Fixes read/write data race for edge case with remote browsers.\n- [browser#1034](https://github.com/grafana/xk6-browser/pull/1034) Fixes `page.reload` & `page.setContent` to use the default navigation timeout over the default timeout.\n- [browser#1033](https://github.com/grafana/xk6-browser/pull/1033) Fixes the `page` timeouts so it is actually used after being set.\n\n## Maintenance and internal improvements\n\n- [#3342](https://github.com/grafana/k6/pull/3342) Updates xk6-grpc to the latest version. This change brings all the latest fixes and improvements to the experimental gRPC module.\n- [#3271](https://github.com/grafana/k6/pull/3271),[#3272](https://github.com/grafana/k6/pull/3272) Updates the golangci version and adds the `interfacebloat` linter.\n- [#3279](https://github.com/grafana/k6/pull/3279) Fixes the CI not publishing the SBOM file on a new release.\n- [#3283](https://github.com/grafana/k6/pull/3283) Updates the Go version in k6's CI used to build the binaries.\n- [#3341](https://github.com/grafana/k6/pull/3341), [#3339](https://github.com/grafana/k6/pull/3339) Updates `goja`, includes runtime initialization speed-up and a fix for source indexes.\n- [#3311](https://github.com/grafana/k6/pull/3311) Updates the `alpine` image version that is used as the base of the k6 Docker image.\n- [browser#1043](https://github.com/grafana/xk6-browser/pull/1043), [browser#1021](https://github.com/grafana/xk6-browser/pull/1021), [browser#1019](https://github.com/grafana/xk6-browser/pull/1019), [browser#1014](https://github.com/grafana/xk6-browser/pull/1014) Fixes xk6-browser tests.\n- [browser#1000](https://github.com/grafana/xk6-browser/pull/1000), [browser#1024](https://github.com/grafana/xk6-browser/pull/1024) Refines xk6-browser issue and PR templates.\n- [browser#1003](https://github.com/grafana/xk6-browser/pull/1003), [browser#1009](https://github.com/grafana/xk6-browser/pull/1009), [browser#1010](https://github.com/grafana/xk6-browser/pull/1010) Internal changes to xk6-browser.\n- [browser#997](https://github.com/grafana/xk6-browser/pull/997) Updates xk6-browser readme.\n- [browser#962](https://github.com/grafana/xk6-browser/pull/962) CI fixes.\n- [browser#1035](https://github.com/grafana/xk6-browser/pull/1035) Refactors `int64` timeout to `time.Duration`, to help avoid confusion as to whether a timeout is in milliseconds or seconds.\n\n## Roadmap\n\n### Native ECMAScript Modules support\n\nWork on this [epic issue](https://github.com/grafana/k6/issues/3265) has been picked up and there is some progress in the underlying implementation.\n\nOne of the main internal changes will be dropping [Babel](https://babeljs.io), which is currently used to transpile [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) code to [CommonJS](https://en.wikipedia.org/wiki/CommonJS).\n\nFor users, it will mean better JavaScript support as this change will automatically get [object spread](https://github.com/grafana/k6/issues/824) working and likely faster startup for *big* scripts. In the future, this also means JavaScript compatibility will be easier to add, since it'll only need to be supported in the JavaScript VM we use - [goja](https://github.com/dop251/goja).\n\nThere's a risk that some k6 tests using both CommonJS and ECMAScript modules syntax will change in behavior. In practice, using both should never really be done as they're not compatible.\n\nBecause there are risks involved, we are going to do this very carefully and only once we have done a lot of tests. That means this is currently planned for v0.49.0, but with the majority of the remaining work done in the v0.48.0 cycle.\n\nThis way, we will also be able to have most of our users test these changes from our `master` branch, using Docker images, for example.\n\n### Future breaking changes\n\nThere are several changes in the next release that are entering the final stage of their deprecation period. That means the next release will include the following breaking changes:\n\n- [#3065](https://github.com/grafana/k6/issues/3065) Metric names will be limited to 128 characters and a set of allowed symbols. This was going to be changed to a 63 character limit to ensure compatibility with OpenTelemetry standards, but since then, the OTel limit has been updated to 255 characters. You can find more details about the changes in the linked issue.\n- [#3365](https://github.com/grafana/k6/pull/3365) The `k6 converter` command will be removed.\n- [#3350](https://github.com/grafana/k6/pull/3350) The `headers` param for the gRPC module will be removed. Users should use the [metadata](https://k6.io/docs/javascript-api/k6-experimental/grpc/params) property instead.\n- [#3287](https://github.com/grafana/k6/issues/3287) Loading remote modules will require users to include the `https://` protocol in their URLs, otherwise it will return an error.\n- CSV output no longer accepts arguments in snake case (for example, [fileName](https://k6.io/docs/results-output/real-time/csv/#csv-options) should be used instead of `file_name`).\n- The `--logformat` flag for defining the Log format option will be removed. [--log-format](https://k6.io/docs/using-k6/k6-options/reference/#logformat) should be used instead.\n\nWe recommend checking this list to see if you are impacted, and updating your scripts or CI/CD processes to avoid any issues. If you have any feedback, please open an issue.\n"
  },
  {
    "path": "release notes/v0.48.0.md",
    "content": "k6 v0.48.0 is here 🎉! This release includes:\n\n- Numerous long-awaited breaking changes.\n- A new `k6 new` subcommand to generate a new test script.\n- A new `k6/experimental/fs` module for file interactions.\n- CPU and network throttling support for the k6 browser module.\n\n## Breaking changes\n\nThis release includes several breaking changes, mainly cleaning up deprecations from previous versions. They should have a straightforward migration process, and not heavily impact existing users.\n\n- [#3448](https://github.com/grafana/k6/pull/3448) limits metric names, aligning to both OpenTelemetry (OTEL) and Prometheus name requirements, while still being limited to 128 ASCII characters. Warnings about the limit started in [v0.45](https://github.com/grafana/k6/releases/tag/v0.45.0).\n- [#3439](https://github.com/grafana/k6/pull/3439) changes the `Client` signature in `k6/experimental/redis` module. Refer to the module-related section below.\n- [#3350](https://github.com/grafana/k6/pull/3350) removes the `grpc.invoke()`'s parameter `headers`, deprecated in k6 [v0.37](https://github.com/grafana/k6/releases/tag/v0.37.0). Use the `metadata` parameter instead.\n- [#3389](https://github.com/grafana/k6/pull/3389) removes the `--logformat` flag, deprecated in [v0.38](https://github.com/grafana/k6/releases/tag/v0.38.0). Use the `--log-format` flag instead.\n- [#3390](https://github.com/grafana/k6/pull/3390) removes all CSV output's CLI arguments, deprecated in [v0.35](https://github.com/grafana/k6/releases/tag/v0.35.0). This change makes the CSV output consistent with other output formats.\n- [#3365](https://github.com/grafana/k6/pull/3365) removes the `k6 convert` CLI command, deprecated in [v0.41](https://github.com/grafana/k6/releases/tag/v0.41.0). Use the [har-to-k6](https://github.com/grafana/har-to-k6) package instead.\n- [#3451](https://github.com/grafana/k6/pull/3451) removes logic that would attempt to prepend a `https://` scheme to module specifiers that were not recognized. Deprecated in k6 [v0.25](https://github.com/grafana/k6/releases/tag/v0.25.0). Use full URLs if you want to load remote modules instead.\n\n## New features\n\n### Add `k6 new` subcommand [#3394](https://github.com/grafana/k6/pull/3394)\n\n`k6` now has a `new` subcommand that generates a new test script. This is useful for new users who want to get started quickly, or for experienced users who want to save time when creating new test scripts. To use the subcommand, open your terminal and type:\n\n```bash\nk6 new [filename]\n```\n\nIf no filename is provided, k6 uses `script.js` as the default filename. The subcommand will create a new file with the provided name in the current directory, and populate it with a basic test script that can be run with `k6 run`.\n\n### Add a `k6/experimental/fs` module [#3165](https://github.com/grafana/k6/pull/3165)\n\n`k6` now has a new `k6/experimenal/fs` module providing a memory-efficient way to handle file interactions within your test scripts. It currently offers support for opening files, reading their content, seeking through it, and retrieving metadata about them.\n\nUnlike the traditional [open](https://grafana.com/docs/k6/latest/javascript-api/init-context/open/) function, which loads a file multiple times into memory, the filesystem module reduces memory usage by loading the file as little as possible, and sharing the same memory space between all VUs. This approach significantly reduces the memory footprint of your test script and lets you load and process large files without running out of memory.\n\nFor more information, refer to the [module documentation](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/fs/).\n\n<details>\n<summary> Expand to see an example of the new functionality.</summary>\n\nThis example shows the new module usage:\n\n```javascript\nimport fs from 'k6/experimental/fs';\n\n// k6 doesn't support async in the init context. We use a top-level async function for `await`.\n//\n// Each Virtual User gets its own `file` copy.\n// So, operations like `seek` or `read` won't impact other VUs.\nlet file;\n(async function () {\n  file = await open('bonjour.txt');\n})();\n\nexport default async function () {\n  // About information about the file\n  const fileinfo = await file.stat();\n  if (fileinfo.name != 'bonjour.txt') {\n    throw new Error('Unexpected file name');\n  }\n\n  const buffer = new Uint8Array(128);\n\n  let totalBytesRead = 0;\n  while (true) {\n    // Read into the buffer\n    const bytesRead = await file.read(buffer);\n    if (bytesRead == null) {\n      // EOF\n      break;\n    }\n\n    // Do something useful with the content of the buffer\n    totalBytesRead += bytesRead;\n\n    // If bytesRead is less than the buffer size, we've read the whole file\n    if (bytesRead < buffer.byteLength) {\n      break;\n    }\n  }\n\n  // Check that we read the expected number of bytes\n  if (totalBytesRead != fileinfo.size) {\n    throw new Error('Unexpected number of bytes read');\n  }\n\n  // Seek back to the beginning of the file\n  await file.seek(0, SeekMode.Start);\n}\n```\n\n</details>\n\n### Redis (m)TLS support and new Client constructor options [#3439](https://github.com/grafana/k6/pull/3439), [xk6-redis/#17](https://github.com/grafana/xk6-redis/pull/17)\n\nIn this release, the `k6/experimental/redis` module receives several important updates, including breaking changes.\n\n#### Connection URLs\n\nThe `Client` constructor now supports connection URLs to configure connections to Redis servers or clusters. These URLs can be in the format `redis://[[username][:password]@][host][:port][/db-number]` for standard connections, or `rediss://[[username][]:password@]][host][:port][/db-number]` for TLS-secured connections. For more details, refer to the [documentation](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/).\n\n##### Example usage\n\n```javascript\nimport redis from 'k6/experimental/redis';\n\nconst redisClient = new redis.Client('redis://someusername:somepassword@localhost:6379/0');\n```\n\n#### Revamped Options object\n\nThe `Client` constructor has been updated with a new [Options](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/redis-options/) object format. This change aligns the module with familiar patterns from Node.js and Deno libraries, offering enhanced flexibility and control over Redis connections. For more details, refer to the [documentation](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/redis/redis-options/).\n\n<details>\n<summary> Expand to see an example of the new functionality.</summary>\n\nThis example shows the usage of the new `Options` object:\n\n```javascript\nimport redis from 'k6/experimental/redis';\n\nconst redisClient = new redis.Client({\n  socket: {\n    host: 'localhost',\n    port: 6379,\n  },\n  username: 'someusername',\n  password: 'somepassword',\n});\n```\n</details>\n\n#### (m)TLS support\n\nThe Redis module now includes (m)TLS support, enhancing security for connections. This update also improves support for Redis clusters and sentinel modes (failover). For connections using self-signed certificates, enable k6's [insecureSkipTLSVerify](https://grafana.com/docs/k6/latest/using-k6/k6-options/reference/#insecure-skip-tls-verify) option (set to `true`).\n\n<details>\n<summary> Expand to see an example of the new functionality.</summary>\n\nThis example shows the configuration of a TLS connection:\n\n```javascript\nimport redis from 'k6/experimental/redis';\n\nconst redisClient = new redis.Client({\n  socket: {\n    host: 'localhost',\n    port: 6379,\n    tls: {\n      ca: [open('ca.crt')],\n      cert: open('client.crt'), // client certificate\n      key: open('client.key'), // client private key\n    },\n  },\n});\n```\n</details>\n\n### Add tracing instrumentation [#3445](https://github.com/grafana/k6/pull/3445)\n\n`k6` now supports a new *traces output* option that allows you to configure the output for traces generated during its execution. This option can be set through the `--traces-output` argument in the `k6 run` command or by setting the `K6_TRACES_OUTPUT` environment variable.\n\nCurrently, no traces are generated by `k6` itself, but this feature represents the first step towards richer tracing functionalities in `k6` and its extensions.\n\nBy default traces output is set to `none`, and currently the only supported output is `otel` which uses the [opentelemetry-go](https://github.com/open-telemetry/opentelemetry-go)'s [Open Telemetry](https://opentelemetry.io/) API and SDK implementations. The format for the `otel` *traces output* configuration is the following:\n\n```\n--traces-output=<endpoint>[,opt1=val1,opt2=val2]\n```\n\nWhere `opt`s can be one of the following options:\n* `proto`: Specifies the protocol to use in the connection to the traces backend. Supports `grpc` *(default)* and `http`.\n* `header.<header_name>`: Specifies an additional header to include in the connection to the traces backend.\n\nExample:\n\n```\nK6_TRACES_OUTPUT=https://traces.k6.io/v1/traces,proto=http,header.Authorization=Bearer token\n```\n\n### Add support for browser module's `page.throttleCPU` [browser#1095](https://github.com/grafana/xk6-browser/pull/1095)\n\nThe browser module now supports throttling the CPU from chrome/chromium's perspective by using the `throttleCPU` API, which helps emulate slower devices when testing the website's frontend. It requires an argument of type `CPUProfile`, which includes a `rate` field that is a slow-down factor, where `1` means no throttling, `2` means 2x slowdown, and so on. For more details, refer to the [documentation](https://grafana.com/docs/k6/v0.48.x/javascript-api/k6-experimental/browser/page/throttlecpu).\n\n```js\n...\n  const context = browser.newContext();\n  const page = context.newPage();\n\n  try {\n    page.throttleCPU({ rate: 4 });\n...\n```\n\n### Add support for browser module's `page.throttleNetwork` [browser#1094](https://github.com/grafana/xk6-browser/pull/1094)\n\nThe browser module now supports throttling the characteristics of the network from chrome/chromium's perspective by using the `throttleNetwork` API, which helps emulate slow network connections when testing the website's frontend. It requires an argument of type `NetworkProfile`, with a definition of:\n\n```ts\nexport interface NetworkProfile {\n    /*\n     * Minimum latency from request sent to response headers received (ms).\n     */\n    latency: number;\n    \n    /*\n     * Maximal aggregated download throughput (bytes/sec). -1 disables download\n     * throttling.\n     */\n    download: number;\n    \n    /*\n     * Maximal aggregated upload throughput (bytes/sec). -1 disables upload\n     * throttling.\n     */\n    upload: number;\n}\n```\n\nYou can either define your own network profiles or use the ones we have defined by importing `networkProfiles` from the `browser` module. For more details, refer to the [documentation](https://grafana.com/docs/k6/v0.48.x/javascript-api/k6-experimental/browser/page/throttlenetwork).\n\n```js\nimport { browser, networkProfiles } from 'k6/experimental/browser';\n...\n  const context = browser.newContext();\n  const page = context.newPage();\n\n  try {\n    page.throttleNetwork(networkProfiles['Slow 3G']);\n...\n```\n\n## k6's documentation is moving under [grafana.com/docs/k6](https://grafana.com/docs/k6)\n\nIt's not directly part of the k6 v0.48 release, but we believe it is worth mentioning that we're moving the documentation from [k6.io/docs](https://k6.io/docs/) to [grafana.com/docs/k6](https://grafana.com/docs/k6).\n\nThe legacy documentation space `k6.io/docs` will be available for a while, but we encourage you to update your bookmarks and links to the new domain.\n\n## UX improvements and enhancements\n\n- [browser#1074](https://github.com/grafana/xk6-browser/pull/1074) adds a new `browser.closeContext()` [method](https://grafana.com/docs/k6/v0.48.x/javascript-api/k6-experimental/browser/closecontext) to facilitate closing the current active browser context.\n- [#3370](https://github.com/grafana/k6/pull/3370) adds a new flag `--profiling-enabled` which enables exposing [pprof](https://go.dev/blog/pprof) profiling endpoints. The profiling endpoints are exposed on the same port as the HTTP REST API under the `/debug/pprof/` path. This can be useful for extension developers.\n- [#3442](https://github.com/grafana/k6/pull/3442) adds a new `--version` flag, which has the same output as `k6 version` command. Thanks, @ffapitalle!\n- [#3423](https://github.com/grafana/k6/pull/3423) adds an environment variable `K6_INFLUXDB_PROXY` to the InfluxDB output which allows specifying proxy. Thanks, @IvanovOleg!\n- [#3398](https://github.com/grafana/k6/pull/3398) enables k6 cloud traces by default.\n- [#3400](https://github.com/grafana/k6/pull/3400) sets a binary-based cloud output (a.k.a. cloud output v2) as the default version for streaming metrics from a local test run via `-o cloud`.\n- [#3452](https://github.com/grafana/k6/pull/3452) adds `fsext.Abs` helper function.\n\n## Bug fixes\n\n- [#3380](https://github.com/grafana/k6/pull/3380) corrects `console.debug()`, aligning `-v` output to `--console-output` and `stdout`.\n- [#3416](https://github.com/grafana/k6/pull/3416) prints the stack trace when there's an exception in `handleSummary()`.\n- [#3438](https://github.com/grafana/k6/pull/3438) prevents an error on HTTP requests with `content-encoding` header and HTTP statuses known for having no body.\n- [browser#1077](https://github.com/grafana/xk6-browser/pull/1077) fixes `browserContext.clearPermissions` to clear permissions without panic.\n- [browser#1042](https://github.com/grafana/xk6-browser/pull/1042) fixes `browserContext.waitForEvent` which involved promisifying the `waitForEvent` API.\n- [browser#1078](https://github.com/grafana/xk6-browser/pull/1078) fixes request interception deadlock to improve stability.\n- [browser#1101](https://github.com/grafana/xk6-browser/pull/1101) fixes `page.$` so that it returns `null` when no matches with given selector are found.\n- [#3397](https://github.com/grafana/k6/pull/3397), [#3427](https://github.com/grafana/k6/pull/3427), [#3417](https://github.com/grafana/k6/pull/3417) update `goja` dependency. Fixes a possible panic and proper handling circular types at `JSON.stringify`. Fixes an issue about dumping the correct stack trace when an error is re-thrown.\n- [browser#1106](https://github.com/grafana/xk6-browser/pull/1106) fixes an NPE on NavigateFrame when navigate occurs in the same document.\n- [browser#1096](https://github.com/grafana/xk6-browser/pull/1096) fixes a panic when trying to interact within nested `iframe`s. Thanks, @bandorko!\n\n## Maintenance and internal improvements\n\n- [#3378](https://github.com/grafana/k6/pull/3378) fixes usage of `gh` in GitHub actions creating the OSS release.\n- [#3386](https://github.com/grafana/k6/pull/3386), [#3387](https://github.com/grafana/k6/pull/3387), [#3388](https://github.com/grafana/k6/pull/3388), [browser#1047](https://github.com/grafana/xk6-browser/pull/1047) update dependencies.\n- [#3393](https://github.com/grafana/k6/pull/3393), [#3399](https://github.com/grafana/k6/pull/3399) fix lint issues in the `js` package.\n- [#3381](https://github.com/grafana/k6/pull/3381) disables temporarily ARM tests on GitHub Actions.\n- [#3401](https://github.com/grafana/k6/pull/3401), [#3469](https://github.com/grafana/k6/pull/3469) refactors a Makefile, removes `make ci-like-lint` in favor of `make lint`. Updates a golangci-lint version to v1.55.2.\n- [#3410](https://github.com/grafana/k6/pull/3410) fixes the `tests` reference in the all rule of the Makefile. Thanks, @flyck!\n- [#3402](https://github.com/grafana/k6/pull/3402) adds a test-case for the `k6 cloud`.\n- [#3421](https://github.com/grafana/k6/pull/3421) updates dependencies for xk6 integration tests.\n- [browser#1075](https://github.com/grafana/xk6-browser/pull/1075), [browser#1076](https://github.com/grafana/xk6-browser/pull/1076) refactors `clearPermissions` and `grantPermissions`.\n- [browser#1043](https://github.com/grafana/xk6-browser/pull/1043) refines tests.\n- [browser#1069](https://github.com/grafana/xk6-browser/pull/1069), [browser#1090](https://github.com/grafana/xk6-browser/pull/1090) refactor internal.\n- [browser#1102](https://github.com/grafana/xk6-browser/pull/1102) uses `force` and `noWaitAfter` in `frame.newAction`.\n- [#3443](https://github.com/grafana/k6/pull/3443) mentions that k6-core team aims to support the last two major golang versions for building a k6 binary.\n- [#3437](https://github.com/grafana/k6/pull/3437) switches k6 cloud traces to a new hostname.\n- [#3429](https://github.com/grafana/k6/pull/3429) increases timeout expectations for the `TestSetupTimeout` test.\n- [#3446](https://github.com/grafana/k6/pull/3446) moves log tokenizer to `lib/strvals` package.\n\n## Roadmap\n\n### Graduating from experimental\n\nIt has been a while since we've introduced the `k6/experimental` namespace. This namespace was specifically created to test new features before we fully committed to them. Thanks to it, we have been able to iterate on features and receive valuable feedback from the community before adding them to the core of k6.\n\nIn the following releases, we're going to graduate `k6/experimental/grpc` and `k6/experimental/timers`.\n\nThese modules' \"experimental\" versions will remain available for a couple of releases, but the goal is to remove the \"experimental\" imports for them in favor of the core-only imports.\n\n### New dashboard features\n\nWe're happy to announce our work on a new, upcoming dashboard feature. Based on the [xk6-dashboard](https://github.com/grafana/xk6-dashboard) extension, this upcoming feature will enable you to visualize your test runs and their results in your web browser, in real time. The k6 maintainers team is starting to work towards its integration into the core of k6, and we're aiming to release it in the next couple of releases.\n\nWhile the final user-experience might differ, you can already try it out by following the instructions in the [xk6-dashboard](https://github.com/grafana/xk6-dashboard) repository. We update the extension on a regular basis as we're converging towards the first release of the feature in k6. Go ahead and give it a try! Let us know what you think about it!"
  },
  {
    "path": "release notes/v0.49.0.md",
    "content": "k6 `v0.49.0` is here 🎉! This release:\n\n- Adds a built-in [web dashboard](https://grafana.com/docs/k6/latest/results-output/web-dashboard/) that displays test results in real time.\n- Introduces `clear` functionality to the browser module's `locator` classes.\n- Merges the gRPC experimental module back into the gRPC core module.\n- Enables the ability to get the selection from an element in `k6/html`.\n- Collects internal modules and outputs used by a script.\n- Prepares `k6/experimental/timers` for stabilization.\n\n\n## Breaking changes\n\n- [#3494](https://github.com/grafana/k6/pull/3494) stops updating `loadimpact/k6` docker image. If you still use it, please migrate to the [grafana/k6](https://hub.docker.com/r/grafana/k6) image.\n- [browser#1111](https://github.com/grafana/xk6-browser/pull/1111) removes `timeout` option for `isVisible` and `isHidden` since the API no longer waits for the element to appear on the page.\n\n## New features\n\n### Web Dashboard\n\nThe new [web dashboard](https://grafana.com/docs/k6/latest/results-output/web-dashboard/) brings real-time visualization to load testing. This feature allows users to monitor test progress and analyze\nresults dynamically, enhancing the overall testing experience.\n\n#### Real-time test results\n\nActivate this feature using the environment variable `K6_WEB_DASHBOARD=true`. For this initial release, the dashboard is not enabled by default to allow users to opt into this new experience as it evolves.\n\n```bash\nK6_WEB_DASHBOARD=true k6 run script.js\n```\n\nOnce enabled and the test script is running, navigate to [http://localhost:5665](http://localhost:5665) in your web browser to access the dashboard.\n\n![k6 Web Dashboard Overview](https://github.com/grafana/xk6-dashboard/blob/master/screenshot/k6-dashboard-overview-light.png?raw=true)\n\n#### Test report\n\nThe web dashboard also offers an HTML test report (see [an example](https://github.com/grafana/xk6-dashboard/blob/master/screenshot/k6-dashboard-html-report-screen-view.png?raw=true)) for detailed analysis, enabling easy sharing and downloading capabilities for\ncollaboration.\n\nTo access and download the report, click on the **Report** button in the dashboard's top right corner or use the `K6_WEB_DASHBOARD_EXPORT` environment variable.\n\n```bash\nK6_WEB_DASHBOARD=true K6_WEB_DASHBOARD_EXPORT=test-report.html k6 run script.js\n```\n\n### Add `clear` to the `locator` class [browser#1149](https://github.com/grafana/xk6-browser/pull/1149)\n\nThe new `clear` method on the `locator` class clears the text boxes and input fields. This is useful when navigating to a website where the text boxes and input fields already contain a value that needs to be cleared before filling it with a specific value.\n\n<details>\n<summary> Expand to see an example of the new functionality.</summary>\n\n```javascript\nimport { check } from 'k6';\nimport { browser } from 'k6/experimental/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function() {\n  const context = browser.newContext();\n  const page = context.newPage();\n\n  await page.goto('https://test.k6.io/my_messages.php', { waitUntil: 'networkidle' });\n  \n  // To mimic an input field with existing text.\n  page.locator('input[name=\"login\"]').type('admin');\n\n  check(page, {\n    'not_empty': p => p.locator('input[name=\"login\"]').inputValue() != '',\n  });\n\n  // Clear the text.\n  page.locator('input[name=\"login\"]').clear();\n\n  check(page, {\n    'empty': p => p.locator('input[name=\"login\"]').inputValue() == '',\n  });\n\n  page.close();\n}\n```\n\n</details>\n\n### Add tracing to the browser module [browser#1100](https://github.com/grafana/xk6-browser/pull/1100)\n\nThe browser module now generates traces that provide a representation of its inner workings, such as API methods executed (for example `browser.newPage` and `page.goto`), page navigations, and [Web Vitals](https://grafana.com/docs/k6/latest/using-k6-browser/metrics/#googles-core-web-vitals) measurements.\n\nCurrently, the instrumented methods are a subset of all the methods exposed by the browser module API, but this will be extended in the future.\n\nThe traces generation for the browser module depends on the overall `k6` traces option introduced in [v0.48.0](https://github.com/grafana/k6/releases/tag/v0.48.0). Check out the [documentation](https://grafana.com/docs/k6/latest/using-k6/k6-options/reference/#traces-output) to learn more about it.\n\n### gRPC streaming API becomes part of the k6 core [#3490](https://github.com/grafana/k6/pull/3490)\n\nWith this release, gRPC's streaming API becomes part of the core's `k6/net/grpc` module. The experimental `k6/experimental/grpc` has been back-merged into the core.\n\nYou can still use import `k6/experimental/grpc` for a couple of releases, but it's deprecated and will be removed in the future (planned in k6 version `v0.51.0`).\n\nTo migrate your scripts, replace `k6/experimental/grpc` with `k6/net/grpc` in your script imports, and the code should work as before.\n\n### k6/html: Extract selection from element [#3519](https://github.com/grafana/k6/pull/3519)\n\n[`k6/html`](https://grafana.com/docs/k6/latest/javascript-api/k6-html/) has been around for a while and allows you to search within an HTML document with a jQuery-like API called [Selection](https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/), and also has support for the more standard [Element](https://grafana.com/docs/k6/latest/javascript-api/k6-html/element/) that represents DOM element.\n\nFor a long time, you could get an Element from a Selection using the [`.get(index)`](https://grafana.com/docs/k6/latest/javascript-api/k6-html/selection/selection-get/), but you couldn't get back to a Selection from an Element.\n\nThis is not a common case, but one that requires quite a bit of code. For example, see the following jQuery snippet:\n\n```javascript\nlet li = http.get(\"https://test.k6.io\").html().find(\"li\");\nli.each(function(_, element) {\n    // here element is an element not a selection\n    // but what if for each li we want to select something more?\n    // in jquery that will be:\n   let container = $(element).closest('ul.header-icons');\n    // but what should `$` do?\n    // in a browser there is only 1 html document that you have access to\n    // in k6 though you can be working with multiple ones, so `$` can't know which one it should\n    // work against\n});\n```\n\nIn order to support the above example, you can use `selection`, without going to the element:\n\n```javascript\nlet li = http.get(\"https://test.k6.io\").html().find(\"li\");\nfor (; li.size() > 0; li = li.next()) {\n    let ul = li.closest('ul.header-icons'); // li here is still a selection and we iterate over it.\n}\n```\n\nThis is not always possible though, and arguably isn't what most users will naturally do.\n\nBecause of this, we have now added a new [`.selection()`](https://grafana.com/docs/k6/latest/javascript-api/k6-html/element/element-selection/) which returns a selection for its element.\n\n\n```javascript\n   let li = http.get(\"https://test.k6.io\").html().find(\"li\");\n   li.each(function(_, element) {\n      let container = element.selection().closest('ul.header-icons');\n        // .. more code\n   });\n```\n\nThanks to @Azhovan! :bow: :tada:\n\n### Collect usage data on imported internal modules and outputs [#3525](https://github.com/grafana/k6/pull/3525)\n\nk6 now collects usage data of the modules and outputs that are being used when the [usage report](https://grafana.com/docs/k6/latest/misc/usage-collection) is enabled. The data collection is only related to the built-in k6 modules and outputs. Private, custom modules and extensions [are never collected](https://github.com/grafana/k6/blob/f35e67902605877ebf2c5e9c8673cd7faf4cdc1e/cmd/report.go#L33-L57). The usage report is enabled by default in k6, but it is possible to opt-out using the [no-usage-report](https://grafana.com/docs/k6/latest/using-k6/k6-options/reference/#no-usage-report) option.\n\nWe always want to improve the product, but at the same time, we need to pay attention to where we allocate our resources. Having data of what are the most used modules and outputs gives us better confidence to make decisions because we are supported by data.\nThe data can let us know what percentage of our users will benefit from the introduction of a new feature and also, how many of them would be impacted in case of a breaking change.\n\n## UX improvements and enhancements\n\n- [#3529](https://github.com/grafana/k6/pull/3529) enables the k6 cloud traces output by default.\n- [#3440](https://github.com/grafana/k6/pull/3440) adds a fallback for using built-in certificates if the OS provides none. Thanks to `@mem` for working on it!\n- [browser#1104](https://github.com/grafana/xk6-browser/pull/1104) adds support for browser module traces metadata. Users can define *key-value* metadata that will be included as attributes in every generated span.\n- [browser#1135](https://github.com/grafana/xk6-browser/pull/1135) improves the array output from `console` in the k6 logs.\n- [browser#1137](https://github.com/grafana/xk6-browser/pull/1137), [browser#1145](https://github.com/grafana/xk6-browser/pull/1145) improves the error messages displayed when Chrome or Chromium isn't found.\n- [#3543](https://github.com/grafana/k6/pull/3543) replaces documentation URLs to `grafana.com/docs/k6/latest/`.\n\n## Bug fixes\n\n- [#3485](https://github.com/grafana/k6/pull/3485) fixes the REST API always logging a 200 status code response, which was found as part of fixing lint issues in the code.\n- [browser#1129](https://github.com/grafana/xk6-browser/pull/1129) mitigates the risk of panics when the website under test uses the `console`.\n- [browser#1133](https://github.com/grafana/xk6-browser/pull/1133) fixes `BigInt` parsing.\n- [browser#1108](https://github.com/grafana/xk6-browser/pull/1108), [browser#1110](https://github.com/grafana/xk6-browser/pull/1110) fixes `isVisible` and `isHidden` so that it doesn't wait for an element to match with the given `selector`, allowing it to continue on with the test script when elements are not on the page.\n- [browser#1121](https://github.com/grafana/xk6-browser/pull/1121) fixes `dblClick` so that it works with `onDblClick` and performs two clicks on the specified element.\n- [browser#1152](https://github.com/grafana/xk6-browser/pull/1152) fixes a nil pointer dereference when navigating around on SPA websites.\n\n## Maintenance and internal improvements\n\n- [#3204](https://github.com/grafana/k6/pull/3204) internal refactor to make future distributed execution work easier. With a small fix to tests in [#3531](https://github.com/grafana/k6/pull/3531). Thanks to @na-- :tada:.\n- Lint fixes throughout the k6 code base [#3460](https://github.com/grafana/k6/pull/3460), [#3462](https://github.com/grafana/k6/pull/3462), [#3463](https://github.com/grafana/k6/pull/3463), [#3478](https://github.com/grafana/k6/pull/3478), [#3479](https://github.com/grafana/k6/pull/3479), [#3480](https://github.com/grafana/k6/pull/3480), [#3481](https://github.com/grafana/k6/pull/3481), [#3482](https://github.com/grafana/k6/pull/3482), [#3483](https://github.com/grafana/k6/pull/3483), [#3484](https://github.com/grafana/k6/pull/3484), [#3485](https://github.com/grafana/k6/pull/3485), [#3495](https://github.com/grafana/k6/pull/3495).\n- [#3473](https://github.com/grafana/k6/pull/3473) refinements to the release process.\n- Dependency updates across k6 [#3500](https://github.com/grafana/k6/pull/3500), [#3501](https://github.com/grafana/k6/pull/3501), [#3502](https://github.com/grafana/k6/pull/3502), [#3503](https://github.com/grafana/k6/pull/3503), [#3509](https://github.com/grafana/k6/pull/3509), [#3513](https://github.com/grafana/k6/pull/3513), [#3537](https://github.com/grafana/k6/pull/3537), [#3539](https://github.com/grafana/k6/pull/3539), [#3540](https://github.com/grafana/k6/pull/3540).\n- [#3489](https://github.com/grafana/k6/pull/3489) migrates pull-requests assignment to `CODEOWNERS` from GitHub Action.\n- [#3496](https://github.com/grafana/k6/pull/3496) checks for security issues with a scheduled trivy scan.\n- [#3517](https://github.com/grafana/k6/pull/3517) adds unit tests to the cloadapi package. This is the first contribution by external contributor @nilskch. Thanks for this @nilskch :bow:.\n- [#3520](https://github.com/grafana/k6/pull/3520) stops using deprecated by golang net.Dialer.DualStack option.\n- [#3526](https://github.com/grafana/k6/pull/3526) refactors to JavaScript package test around `open` and `require` and their handling of paths.\n- [#3527](https://github.com/grafana/k6/pull/3527) generates test certificates for more tests during the test. This, among other things, fixes macOS tests.\n- [#3528](https://github.com/grafana/k6/pull/3528) enables macOS tests in GitHub Actions.\n- [browser#1134](https://github.com/grafana/xk6-browser/pull/1134) adds a new error type when parsing objects.\n- [browser#1107](https://github.com/grafana/xk6-browser/pull/1107), [browser#1109](https://github.com/grafana/xk6-browser/pull/1109) refactor internals.\n\n\n##  Roadmap\n\nAs mentioned earlier, there's work in progress to make xk6-timers stable as part of the next release. You can find more information on issue [#3297](https://github.com/grafana/k6/issues/3297).\n"
  },
  {
    "path": "release notes/v0.50.0.md",
    "content": "k6 `v0.50.0` is here 🎉! \n\nThis release:\n- Adds support for uploading files from the browser module.\n- Introduces the `options.cloud` option.\n- Stabilizes the previously experimental timers module as the `k6/timers` module.\n- Brings JSON Web Key support to the `k6/experimental/webcrypto` module.\n\n## Breaking changes\n\n- [websockets#60](https://github.com/grafana/xk6-websockets/pull/60) allows manually setting the `name` tag, which also overwrites the `url` tag with the `name` value. This change makes it consistent with the logic that was implemented in k6 v0.41. Thanks, @mkadirtan for contributing!\n\n### Browser APIs to Async\n\nIn future releases, we are going to be moving most of the synchronous browser APIs to asynchronous ones (promisifying them). We expect this will affect most of our users, so we are posting this upfront before making the change. Here are the reasons for making this large breaking change:\n\n1. Most browser APIs use some form of long-running IO operation (networking) to perform the requested action on the web browser against the website under test. We need to avoid blocking JavaScript's runtime event loop for such operations.\n2. We're going to add more asynchronous event-based APIs (such as [page.on](https://github.com/grafana/xk6-browser/issues/1227)) that our current synchronous APIs would block.\n3. To align with how developers expect to work with JavaScript APIs.\n4. To have better compatibility with Playwright.\n\nYou can find a list of all the APIs that we expect to convert to async in a comment in issue [browser#428](https://github.com/grafana/xk6-browser/issues/428#issuecomment-1964020837).\n\nAwaiting on something that’s not a thenable just returns that value, which means you can add the `await` keyword against APIs that will become async to future proof your test scripts.\n\n## New features\n\n### Add support for uploading files from the browser module [browser#1097](https://github.com/grafana/xk6-browser/pull/1097), [browser#1244](https://github.com/grafana/xk6-browser/pull/1244)\n\nYou can now upload files using the available input forms on the website under test. The new API is `setInputFiles` which can be called from a `page`, `frame` or `elementHandle` types. It can upload one or more files encoded in the test script. To upload files from the local file system, work with the [experimental fs module](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/fs/).\n\n<details>\n<summary>Expand to see the examples.</summary>\n\nFor the following examples, we will use the HTML file:\n\n```html\n<html>\n\n<body>\n    <form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">\n        <input type=\"file\" name=\"upl\" id=\"upload\" multiple />\n        <input type=\"submit\" value=\"Send\" />\n    </form>\n</body>\n\n</html>\n```\n\nUploading a file can be achieved with the following script:\n\n```js\n// Import the k6 encoder module.\nimport encoding from 'k6/encoding';\n...\nexport default async function () {\n  const page = browser.newPage();\n\n  await page.goto(url)\n\n  // Encode and upload some data into a plain text file called test.txt.\n  page.setInputFiles('input[id=\"upload\"]', { name: 'test.txt', mimetype: 'text/plain', buffer: encoding.b64encode('Hello World') })\n  \n  // Click on the submit button on the form to upload the file.\n  const submitButton = page.locator('input[type=\"submit\"]')\n  await Promise.all([page.waitForNavigation(), submitButton.click()])\n\n  page.close();\n}\n```\n\nUploading multiple files can be done with the use of an array:\n\n```js\npage.setInputFiles('input[id=\"upload\"]',\n    [{ name: 'test.txt', mimetype: 'text/plain', buffer: encoding.b64encode('Hello World') },\n    { name: 'test.json', mimetype: 'text/json', buffer: encoding.b64encode('{\"message\": \"Hello World\"}') }])\n```\n\n</details>\n\nThanks to @bandorko! :bow: :tada:\n\n### Introducing options.cloud [#3348](https://github.com/grafana/k6/pull/3348), [#3407](https://github.com/grafana/k6/pull/3407)\n\nIn this release, we introduce a new way of defining cloud options. From now on, you can use `options.cloud` instead of `options.ext.loadimpact`. \n\nTo migrate, you can move the `loadimpact` object to the root of the `options` object and rename it to `cloud`. For example:\n\n```javascript\nexport let options = {\n    ext: {\n        loadimpact: {\n            name: \"Legacy way of defining cloud options\",\n            projectID: 12345,\n        }\n    }\n};\n\nexport let options = {\n    cloud: {\n        name: \"Current way of defining cloud options\",\n        projectID: 12345,\n    }\n};\n```\n\nAll scripts with legacy `options.ext.loadimpact` will continue to function as before. There's no planned sunset date for the legacy option, but we highly encourage using `options.cloud` going forward. For more details about cloud options, refer to [Cloud options](https://grafana.com/docs/grafana-cloud/k6/author-run/cloud-scripting-extras/cloud-options/).\n\n### Timers API becomes part of the k6 core [#3587](https://github.com/grafana/k6/pull/3587)\n\nWith this release, the timers API is no longer experimental and can be imported as `k6/timers` instead of as `k6/experimental/timers`. The later will be supported until `v0.52.0`.\n\nYou can also contribute to the discussion on making the current timer exports globally available in [#3589](https://github.com/grafana/k6/issues/3589), or just give it a :+1:.\n\n### JSON Web Key support in `k6/experimental/webcrypto` module [webcrypto#61](https://github.com/grafana/xk6-webcrypto/pull/61)\n\nThe experimental webcrypto module now supports the JSON Web Key (JWK) format, using the `importKey` and `exportKey` methods.\n\nThis allows you to import and export keys in the JWK format for the supported algorithms.\n\n```js\nconst generatedKey = await crypto.subtle.generateKey({name: \"AES-CBC\", length: \"256\"}, true, [ \"encrypt\", \"decrypt\"]);\n\nconst exportedKey = await crypto.subtle.exportKey(\"jwk\", generatedKey);\n```\n\n## UX improvements and enhancements\n\n- [browser#1197](https://github.com/grafana/xk6-browser/pull/1197), [browser#1202](https://github.com/grafana/xk6-browser/pull/1202), [browser#1203](https://github.com/grafana/xk6-browser/pull/1203), [browser#1221](https://github.com/grafana/xk6-browser/pull/1221) adds the ability to upload screenshots to a remote location.\n- [browser#1209](https://github.com/grafana/xk6-browser/pull/1209) adds a shadow DOM usage example.\n- [browser#1233](https://github.com/grafana/xk6-browser/pull/1233) returns actionable errors for `evaluate` APIs.\n- [browser#1228](https://github.com/grafana/xk6-browser/pull/1228), [browser#1232](https://github.com/grafana/xk6-browser/pull/1232), [browser#1235](https://github.com/grafana/xk6-browser/pull/1235) injects the `testRunId` into the `window.k6` object for external applications to query (for example, Grafana Faro).\n\n### Browser Context Isolation [browser#1112](https://github.com/grafana/xk6-browser/issues/1112)\n\nWith this release, we have overhauled and (tremendously) improved the performance and stability of the browser module. It's now possible to run tests with a larger number of VUs concurrently without any performance issues. Previously, when running tests with multiple VUs concurrently, each VU's browser context would attach to the pages from the other VUs' browser contexts. This led to unexpected behavior and performance issues and, to an extent, reduced the module's capability to run multi-VU tests.\n\n## Bug fixes\n\n- [#3653](https://github.com/grafana/k6/pull/3653) fixes a connectivity issue with non-lowercase `options.hosts`.\n- [browser#1215](https://github.com/grafana/xk6-browser/pull/1215) fixes a data race during logging that panics.\n- [browser#1238](https://github.com/grafana/xk6-browser/pull/1238) fixes fill functionality for textarea. Thanks @bandorko for the fix! :bow: :tada:\n- [browser#1242](https://github.com/grafana/xk6-browser/pull/1242) fixes XPath evaluation on `DocumentFragment`.\n\n## Maintenance and internal improvements\n\n- [browser#1164](https://github.com/grafana/xk6-browser/pull/1164), [browser#1166](https://github.com/grafana/xk6-browser/pull/1166), [browser#1171](https://github.com/grafana/xk6-browser/pull/1171),\n  [browser#1173](https://github.com/grafana/xk6-browser/pull/1173), [browser#1175](https://github.com/grafana/xk6-browser/pull/1175), [browser#1179](https://github.com/grafana/xk6-browser/pull/1179),\n  [browser#1183](https://github.com/grafana/xk6-browser/pull/1183), [browser#1186](https://github.com/grafana/xk6-browser/pull/1186), [browser#1188](https://github.com/grafana/xk6-browser/pull/1188),\n  [browser#1189](https://github.com/grafana/xk6-browser/pull/1189), [browser#1190](https://github.com/grafana/xk6-browser/pull/1190), [browser#1191](https://github.com/grafana/xk6-browser/pull/1191),\n  [browser#1193](https://github.com/grafana/xk6-browser/pull/1193), [browser#1163](https://github.com/grafana/xk6-browser/pull/1163), [browser#1205](https://github.com/grafana/xk6-browser/pull/1205),\n  [browser#1217](https://github.com/grafana/xk6-browser/pull/1217) refactors internals to improve stability.\n- [browser#850](https://github.com/grafana/xk6-browser/pull/850), [browser#1211](https://github.com/grafana/xk6-browser/pull/1211), [browser#1212](https://github.com/grafana/xk6-browser/pull/1212),\n  [browser#1214](https://github.com/grafana/xk6-browser/pull/1214), [browser#1216](https://github.com/grafana/xk6-browser/pull/1216) refactors to work with errors.Join and sets the minimum Go version to 1.20.\n- [browser#1220](https://github.com/grafana/xk6-browser/pull/1220) adds more logging.\n- [browser#1112](https://github.com/grafana/xk6-browser/issues/1112) fixes deadlock issues when running multiple VUs, iterations, and Chrome instances.\n- [browser#1246](https://github.com/grafana/xk6-browser/issues/1246) removes logging of in-flight requests when a request fails.\n- [#3586](https://github.com/grafana/k6/pull/3586) fixes file traversal for the test.\n- [#3588](https://github.com/grafana/k6/pull/3588) updates `codeql` GitHub action to v3.\n* [webcrypto#62](https://github.com/grafana/xk6-webcrypto/pull/62) fixes display error message in the console and does minor maintenance.\n* [webcrypto#60](https://github.com/grafana/xk6-webcrypto/pull/60) leverages some of the k6 APIs to handle JavaScript operations.\n* [webcrypto#59](https://github.com/grafana/xk6-webcrypto/pull/59) makes `newTestSetup` rely on k6's modulestest.\n* [webcrypto#58](https://github.com/grafana/xk6-webcrypto/pull/58) addresses linter issues related to repeated static strings.\n* [3633](https://github.com/grafana/k6/pull/3633) updates k6 dependencies.\n"
  },
  {
    "path": "release notes/v0.51.0.md",
    "content": "k6 `v0.51.0` is here 🎉! Some special mentions included in this release:\n\n- [A new experimental streams module](#introduction-of-k6experimentalstreams-module-3696)\n- [New algorithms for WebCrypto module](#new-features-and-updates-of-webcrypto-api-support-3714)\n- [Timers are globally available](#timers-globally-available-3589)\n\n## Breaking changes\n\n### Transition browser APIs to Async\n\nIn the last release notes [we mentioned](https://github.com/grafana/k6/blob/master/release%20notes/v0.50.0.md#browser-apis-to-async) this breaking change, and we wanted to remind and update you on the plan. In the **next** release (v0.52.0), most of the synchronous browser APIs will be migrated to be asynchronous (promisifying them). We expect this will affect most if not all of our users.\n\nThis breaking change will require you to add `await` in front of most of the browser module APIs. Without this `await` you will witness undocumented and unknown behavior during the runtime. To make the migration simpler we advise that you work with the latest [k6 type definitions](https://grafana.com/docs/k6/latest/set-up/configure-k6-intellisense/).\n\nYou can find a list of all the APIs that we expect to convert to async in a comment in issue [browser#428](https://github.com/grafana/xk6-browser/issues/428#issuecomment-1964020837).\n\nAwaiting on something that’s not a thenable just returns that value, which means you can add the `await` keyword today on the APIs that will become async to future proof your test scripts.\n\nHere are the reasons for making this large breaking change:\n\n1. Most browser APIs use some form of long-running IO operation (networking) to perform the requested action on the web browser against the website under test. We need to avoid blocking JavaScript's runtime event loop for such operations.\n2. We're going to add more asynchronous event-based APIs (such as [page.on](https://github.com/grafana/xk6-browser/issues/1227)) that our current synchronous APIs would block.\n3. To align with how developers expect to work with JavaScript APIs.\n4. To have better compatibility with Playwright.\n\nAs a starting point, we have migrated a single API (the `tap` method), which you can find the details below that will help visualize the upcoming breaking changes.\n\n### Browser `Tap` is now an async method grafana/xk6-browser#1268\n\nThis release converts the `Tap` method in the `browser` module into an asynchronous method. This change is necessary to ensure that the method can be used in async contexts and to align with the rest of the browser module's planned asynchronous API. To use the `Tap` method, you must now add the `await` keyword before the method call.\n\nAffected components:\n- [`locator.tap`](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/browser/locator/tap/)\n- [`page.tap`](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/browser/page/tap/)\n- [`frame.tap`](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/browser/frame/)\n- [`elementHandle.tap`](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/browser/elementhandle/)\n\nSee the following example for how to use the `Tap` method after this change:\n\n**Before**:\n\n```javascript\nimport browser from 'k6/experimental/browser'\n\n// ...\n\nexport default function () {\n\t// ...\n\tpage.tap(selector, { modifiers: [\"Alt\", \"Control\", \"Meta\", \"Shift\"] });\n\t// ...\n}\n```\n\n**After**:\n\n```javascript\nimport browser from 'k6/experimental/browser'\n\n// ...\n\nexport default function () {\n\t// ...\n\tawait page.tap(selector, { modifiers: [\"Alt\", \"Control\", \"Meta\", \"Shift\"] });\n\t// ...\n}\n```\n\n### `k6/experimental/websockets` will not default `binaryType` to `\"arraybuffer\"'\n\nAs part of the stabilization of the API it needs to become as close to the specification.\n\nEarly in the development the idea of adding `Blob` support as part was deemed feature creep and was dropped in favor of going with only `\"arraybuffer\"`. But the specification defaults to returning binary responses as `Blob` - which was another thing that was changed.\n\nWhile adding `Blob` is still on our radar, moving the default is always going to be a breaking change that we need to do to align with the specification.\n\nFor this release there is now a warning that will be printed if `binaryType` is not set to `\"arraybuffer\"` *and* a binary response is received. The warning will go away when `binaryType` is set to `\"arraybuffer\"`.\n\nIn the next release the warning will become an error.\n\nMore info and place for discussion can be found in an [this issue](https://github.com/grafana/xk6-websockets/issues/67).\n\n### `k6/experimental/grpc` is no longer available [#3530](https://github.com/grafana/k6/pull/3530)\n\nAs the last step of the graduation process for the experimental gRPC module, we completely removed the module. It is now fully integrated into the stable `k6/net/grpc` module. So, if you haven't done this yet, replace your imports from `k6/experimental/grpc` to `k6/net/grpc`.\n\n### Deprecations\n\nThe following pull requests start the process to introduce breaking changes. They are currently starting to emit warning if their condition is hit, but they will turn to return errors in the future release.\nIt is recommended to use the suggested alternative, or to fix the script if you see the warning message.\n\n- [#3681](https://github.com/grafana/k6/pull/3681) Use of not-compliant `require` expressions.\n- [#3680](https://github.com/grafana/k6/pull/3680) Modules resolution of modules not previously seen during the initialization phase.\n- [#3676](https://github.com/grafana/k6/pull/3676) Working directory is set to the current location when the script is provided using stdin, instead of the root folder.\n- [#3530](https://github.com/grafana/k6/pull/3671) Automagically resolve modules from cdnjs and github \"URLs\".\n\n## New features\n\n### Introduction of `k6/experimental/streams` module [#3696](https://github.com/grafana/k6/pull/3696)\n\nThis release of k6 introduces the new `k6/experimental/streams` module, which partially supports the JavaScript\nStreams API, focusing initially on the `ReadableStream` construct.\n\nWith the `ReadableStream`, users can define and consume data streams within k6 scripts. This is particularly useful for\nefficiently handling large datasets or for processing data sequentially in a controlled flow.\n\n<details>\n<summary> Expand to see an example of stream's usage</summary>\n\nThe following example demonstrates creating and consuming a simple stream that emits numbers until it reaches a predefined limit:\n\n```javascript\nimport { ReadableStream } from 'k6/experimental/streams'\n\nfunction numbersStream() {\n    let currentNumber = 0\n\n\treturn new ReadableStream({\n\t\tstart(controller) {\n\t\t\tconst fn = () => {\n\t\t\t\tif (currentNumber < 5) {\n\t\t\t\t\tcontroller.enqueue(++currentNumber)\n\t\t\t\t\tsetTimeout(fn, 1000)\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontroller.close()\n\t\t\t}\n\t\t\tsetTimeout(fn, 1000)\n\t\t},\n\t})\n}\n\nexport default async function () {\n\tconst stream = numbersStream()\n\tconst reader = stream.getReader()\n\n\twhile (true) {\n\t\tconst { done, value } = await reader.read()\n\t\tif (done) break\n\t\tconsole.log(`received number ${value} from stream`)\n\t}\n\n\tconsole.log('we are done')\n}\n```\n\n</details>\n\nFor more advanced examples, please head to the MDN Web Docs on the [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API).\n\n#### Limitations\n\nCurrently, users can define and consume readable streams. However, this release does not include support for byte readers\nand controllers, nor does it include support the `tee`, `pipeTo`, and\n`pipeThrough` methods of the `ReadableStream` object.\n\n### New features and updates of WebCrypto API support [#3714](https://github.com/grafana/k6/pull/3714)\n\nThis release brings support for asymmetric cryptography to the `k6/experimental/webcrypto` module. We added support of the elliptic curves algorithms ECDH ([xk6-webcrypto#67](https://github.com/grafana/xk6-webcrypto/pull/67)) and ECDSA ([xk6-webcrypto#69](https://github.com/grafana/xk6-webcrypto/pull/69)) algorithms along with new import/export key formats like `spki` and `pkcs8`.\n\nOne of the newly added operations is `deriveBits`, which allows parties to generate a unique shared secret by using shared public and non-shared private keys.\n\n<details>\n<summary> Expand to see an example of generating a shared secret for Alice and Bob.</summary>\n\n```javascript\nimport { crypto } from 'k6/experimental/webcrypto';\n\nexport default async function () {\n  // Generate a key pair for Alice\n  const aliceKeyPair = await crypto.subtle.generateKey(\n    {\n      name: 'ECDH',\n      namedCurve: 'P-256',\n    },\n    true,\n    ['deriveKey', 'deriveBits']\n  );\n\n  // Generate a key pair for Bob\n  const bobKeyPair = await crypto.subtle.generateKey(\n    {\n      name: 'ECDH',\n      namedCurve: 'P-256',\n    },\n    true,\n    ['deriveKey', 'deriveBits']\n  );\n\n  // Derive shared secret for Alice\n  const aliceSharedSecret = await deriveSharedSecret(aliceKeyPair.privateKey, bobKeyPair.publicKey);\n\n  // Derive shared secret for Bob\n  const bobSharedSecret = await deriveSharedSecret(bobKeyPair.privateKey, aliceKeyPair.publicKey);\n\n  // alice shared secret and bob shared secret should be the same\n  console.log('alice shared secret: ' + printArrayBuffer(aliceSharedSecret));\n  console.log('bob shared secret: ' + printArrayBuffer(bobSharedSecret));\n}\n\nasync function deriveSharedSecret(privateKey, publicKey) {\n  return crypto.subtle.deriveBits(\n    {\n      name: 'ECDH',\n      public: publicKey,\n    },\n    privateKey,\n    256\n  );\n}\n\nconst printArrayBuffer = (buffer) => {\n  const view = new Uint8Array(buffer);\n  return Array.from(view);\n};\n```\n\n</details>\n\nThe `sign` and `verify` operations got support for ECDSA algorithm. The `sign` operation allows you to sign a message with a private key, while the `verify` operation allows you to verify the signature with a public key.\n\nOther notable updates and fixes:\n\n- [xk6-webcrypto#68](https://github.com/grafana/xk6-webcrypto/pull/68) fixes a degradation for the sign/verify operations for HMAC algorithm.\n- [xk6-webcrypto#75](https://github.com/grafana/xk6-webcrypto/pull/75), [xk6-webcrypto#76](https://github.com/grafana/xk6-webcrypto/pull/76) refactor webcrypto module to be thread-safe.\n- [xk6-webcrypto#74](https://github.com/grafana/xk6-webcrypto/pull/74) adds JWK import/export support for ECDH and ECDSA. Refactors JWK import/export to use only go standard library.\n\nSee [webcrypto's module documentation](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/webcrypto/) for more details.\n\n### Timers globally available [#3589](https://github.com/grafana/k6/pull/3589)\n\n`setTimeout`, `setInterval` and related clear functions have been part of the JavaScript ecosystem, probably for as long as it has existed.\n\nIn the previous releases we stabilized and made them available through `k6/timers` module. While the module isn't going anywhere and might get more identifiers, `setTimeout` is usually used without importing it. For this reason it is now globally available along `clearTimeout`, `setInterval` and `clearInterval`.\n\nNo code needs to be changed, but you no longer need to import `k6/timers` to use this functionality.\n\n## UX improvements and enhancements\n\n- [#3670](https://github.com/grafana/k6/issues/3670) adds the ability to [enable profiling](https://grafana.com/docs/k6/latest/using-k6/k6-options/reference/#profiling-enabled) via environment variable. Thanks @Bablzz for your contribution!\n- [#3655](https://github.com/grafana/k6/pull/3655) clarifies the error message for the validation of scenario's name.\n- [#3693](https://github.com/grafana/k6/pull/3693) adds a gRPC client's `asyncInvoke` method to the `k6/net/grpc` module. It's [a non-blocking version](https://grafana.com/docs/k6/latest/javascript-api/k6-net-grpc/client/client-async-invoke/) of the `invoke` method.\n- [browser#1259](https://github.com/grafana/xk6-browser/pull/1259), [browser#1260](https://github.com/grafana/xk6-browser/pull/1260) adds errors to the traces that the browser module generates.\n\n## Bug fixes\n\n- [#3708](https://github.com/grafana/k6/pull/3708) denies access to `execution.test.options` from Init context.\n- [#3672](https://github.com/grafana/k6/pull/3672) picks the correct value when [SystemTags](https://grafana.com/docs/k6/latest/using-k6/k6-options/reference/#system-tags) are set via the `k6_SYSTEM_TAGS` environment variable.\n- [#3657](https://github.com/grafana/k6/pull/3657) fixes a panic when `mappings` field is empty in the provided SourceMap.\n- [#3717](https://github.com/grafana/k6/pull/3717) returns a correct line number when an inlined SourceMap is used.\n- [browser#1261](https://github.com/grafana/xk6-browser/pull/1261) fixes dispose context canceled errors.\n- [browser#1254](https://github.com/grafana/xk6-browser/pull/1254) fixes an indefinite wait when testing websites with iframes.\n- [browser#1291](https://github.com/grafana/xk6-browser/pull/1291) fixes a panic on dispose of resources during a navigation.\n\n## Maintenance and internal improvements\n\n- [#3663](https://github.com/grafana/k6/pull/3663), [#3673](https://github.com/grafana/k6/pull/3673) updates several dependencies.\n- [#3674](https://github.com/grafana/k6/pull/3674) updates the Go version, now k6 binary is built and tested using Go 1.22.\n- [#3688](https://github.com/grafana/k6/pull/3688) updates the link to installation instructions for `golangci-lint` in the contribution guide. Thanks @yomek33 for your contribution!\n- [browser#1262](https://github.com/grafana/xk6-browser/pull/1262) fixes a flaky test.\n- [browser#1264](https://github.com/grafana/xk6-browser/pull/1264) removes unimplemented APIs.\n\n## Future plans\n\n### Use Blob as default value for WebSocket.binaryType \n\nAs the changes in documentation mention, [`binaryType`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/binaryType) was by default set to `arraybuffer`, now instead it is `\"\"` (empty string).\nIn a not so remote future, instead, we expect to introduce and use Blob object.\n\n### WebCrypto graduation\n\nWebCrypto got more features in the current release, and we expect to continue its expansion in the next iterations. Reaching a wider coverage will push WebCrypto module to being graduated as a stable module.\n\n### Streams API\n\nIn the not so distant future, we have plans to start using the Streams API in existing modules. Our first iteration being adding a `.readable` property to the already existing [fs.File](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/fs/file) object.\n\n### Improve user experience for Cloud related commands\n\nIn the near future, we intend to reiterate on `k6 cloud` and related commands to create a simplified and more ergonomic user experience.\n\n### Remove experimental timers module\n\nThe `k6/experimental/timers` module is now part of the stable k6 API as `k6/timers` and via the globally available functions. The next release will make the experimental import no longer available.\n"
  },
  {
    "path": "release notes/v0.52.0.md",
    "content": "k6 `v0.52.0` is here 🎉! Some special mentions included in this release:\n\n- [We've switched to our own fork of `goja` named `sobek`](#switch-goja-to-our-own-fork-named-sobek-3775).\n- [Panics are no longer captured](#panics-are-no-longer-being-captured-3777).\n- [We've added experimental support for TypeScript and ES6+](#experimental-support-for-typescript-and-es6-using-esbuild-3738).\n- `k6/browser` has [graduated from an experimental module](#k6browser-has-graduated-from-an-experimental-module-3793), and now has a [fully Async API](#k6browser-has-now-a-fully-async-api-browser428).\n\n## Breaking changes\n\n### Switch `goja` to our own fork named `sobek` [#3775](https://github.com/grafana/k6/pull/3775)\n\nTo accelerate the development speed and bring ECMAScript Modules (ESM) support to k6 earlier (https://github.com/grafana/k6/issues/3265),\nwe have decided to create a fork of the [`goja`](https://github.com/dop251/goja/) project under the Grafana GitHub organization,\nnamed [`sobek`](https://github.com/grafana/sobek).\n\nStarting on this release, k6 (and its extensions) now use `sobek` instead of the original `goja`, for all (of the\npublicly exposed parts of the API) except for a couple of packages that are only used internally by k6.\n\nAll k6 extensions linked in the docs have had a PR for this transition opened, as explained in this [comment](https://github.com/grafana/k6/issues/3773#issuecomment-2182113677). Any extension author who hasn't gotten a PR can follow the same steps.\n\nFind further details in [#3772](https://github.com/grafana/k6/issues/3772) and [#3773](https://github.com/grafana/k6/issues/3773).\n\n### Panics are no longer being captured [#3777](https://github.com/grafana/k6/pull/3777)\n\nSince this release, Go panics are no longer being captured by k6. This means that if a panic occurs while running a test,\nthe k6 process will crash, and the panic stack trace will be printed to the console.\n\nWe decided to change this behavior because it's something that was left from the past as a safeguard, but it's not as\ngood as it might seem. For most cases with multiple goroutines/async, it's not enough and also makes a bunch of potential\nbugs seem like less of an issue.\n\nThus, this will help us to identify and fix bugs earlier, improve the overall stability of k6, and\nmost likely make the experience of developing k6 extensions friendlier.\n\n### `lib.State` no longer has `Group` [#3750](https://github.com/grafana/k6/pull/3750)\n\nAs the result of refactoring the implementation of `group` and `check` methods, in order to decouple them, and thus \nenable other future improvements, the `lib.State` object no longer has a `Group` field.\n\nThis change should not affect most users, except for a couple of extensions, for which the use of `Group` was\nalready questionable:\n- `xk6-fasthttp`\n- `xk6-g0`\n\n### Other breaking changes\n\n- [#3797](https://github.com/grafana/k6/pull/3797) starts using `-` as a special value for `--archive-out` to output the archive to stdout.\n- [browser#1318](https://github.com/grafana/xk6-browser/pull/1318) makes the `Mouse.up` and `Mouse.down` methods no longer take x and y coordinates. Instead, they dispatch events on the current mouse position.\n\n## New features\n\n### Experimental support for TypeScript and ES6+ using esbuild [#3738](https://github.com/grafana/k6/pull/3738)\n\nThis release of k6 introduces experimental support for TypeScript and ES6+ using esbuild, thanks to a new\n[compatibility mode](https://grafana.com/docs/k6/latest/using-k6/javascript-typescript-compatibility-mode/) named `experimental_enhanced`.\n\n```sh\nk6 run --compatibility-mode=experimental_enhanced script.js\n```\n\nWith this new compatibility mode, the test source code is transformed using esbuild instead of Babel, which also means\nthat source files with the extension _\".ts\"_ are loaded by esbuild's TypeScript loader, which results in partial \nTypeScript support: it removes the type information but doesn't provide type safety.\n\n### `k6/browser` has graduated from an experimental module [#3793](https://github.com/grafana/k6/pull/3793)\n\nThe browser module is now available as `k6/browser` instead of `k6/experimental/browser`. The previous `k6/experimental/browser` module will be removed on September 23rd, 2024. Refer to [the migration guide](https://grafana.com/docs/k6/latest/using-k6-browser/migrating-to-k6-v0-52/) for more information on how to update your scripts.\n\n### `k6/browser` has now a fully Async API [browser#428](https://github.com/grafana/xk6-browser/issues/428)\n\nThis release introduces a fully Async API for the `k6/browser` module. This means that nearly all the methods in the module now return promises. This change is part of the ongoing effort to make the browser module more user-friendly and easier to use. Please see [the browser documentation](https://grafana.com/docs/k6/latest/javascript-api/k6-browser) for more information on how to use the new Async API.\n\nRelated Changes:\n- [browser#1310](https://github.com/grafana/xk6-browser/pull/1310), [browser#1311](https://github.com/grafana/xk6-browser/pull/1311), [browser#1312](https://github.com/grafana/xk6-browser/pull/1312), [browser#1316](https://github.com/grafana/xk6-browser/pull/1316), [browser#1328](https://github.com/grafana/xk6-browser/pull/1328), [browser#1337](https://github.com/grafana/xk6-browser/pull/1337), [browser#1367](https://github.com/grafana/xk6-browser/pull/1367), [browser#1366](https://github.com/grafana/xk6-browser/pull/1366), [browser#1314](https://github.com/grafana/xk6-browser/pull/1314), [browser#1332](https://github.com/grafana/xk6-browser/pull/1332), [browser#1323](https://github.com/grafana/xk6-browser/pull/1323), [browser#1355](https://github.com/grafana/xk6-browser/pull/1355), [browser#1348](https://github.com/grafana/xk6-browser/pull/1348), [browser#1364](https://github.com/grafana/xk6-browser/pull/1364) Migrates `Browser`, `BrowserContext`, `ElementHandle`, `Frame`, `JSHandle`, `Keyboard`, `Locator`, `Mouse`, `Page`, `Request`, `Response` APIs to async.\n\n## UX improvements and enhancements\n\n- [#3740](https://github.com/grafana/k6/pull/3740) enables k6 extensions to initialize `ReadableStream` objects from Go code (`io.Reader`).\n- [#3798](https://github.com/grafana/k6/pull/3798) adjusts a severity level of a log message from `warn` to `debug` for cases when k6 can't detect the terminal's size.\n- [#3797](https://github.com/grafana/k6/pull/3797) makes it possible to output the archive to stdout by using `-` as the `--archive-out`. Thanks to @roobre! :bow: :tada:\n- [browser#1370](https://github.com/grafana/xk6-browser/issues/1370) makes the `GetAttribute` method now return `false` when the attribute is missing, making it easier to check for the presence of an attribute.\n- [browser#1371](https://github.com/grafana/xk6-browser/issues/1371) makes the `TextContent` method now return `false` when the element's text content cannot be grabbed (like a JS `document`), making it easier to check for the presence of text content.\n- [browser#1376](https://github.com/grafana/xk6-browser/pull/1376) makes `Request.headerValue` and `Response.headerValue` to be case-insensitive.\n- [browser#1368](https://github.com/grafana/xk6-browser/pull/1368) enhances `await` usage in Javascript examples.\n- [browser#1326](https://github.com/grafana/xk6-browser/pull/1326) adds forgotten `BrowserContext.browser` and `Page.context` mappings.\n- [browser#1360](https://github.com/grafana/xk6-browser/pull/1360), [browser#1327](https://github.com/grafana/xk6-browser/pull/1327), [browser#1335](https://github.com/grafana/xk6-browser/pull/1335), [browser#1365](https://github.com/grafana/xk6-browser/pull/1365), [browser#1313](https://github.com/grafana/xk6-browser/pull/1313), [browser#1322](https://github.com/grafana/xk6-browser/pull/1322), [browser#1330](https://github.com/grafana/xk6-browser/pull/1330), [browser#1343](https://github.com/grafana/xk6-browser/pull/1343), [browser#1345](https://github.com/grafana/xk6-browser/pull/1345), [browser#1352](https://github.com/grafana/xk6-browser/pull/1352) turns the `Browser`, `BrowserContext`, `ElementHandle`, `JSHandle`, `Keyboard`, `Mouse`, `Locator`, and `Page` types' panics into errors for stability and better error handling.\n\n## Bug fixes\n\n- [#3774](https://github.com/grafana/k6/pull/3774) fixes a `require` warning for those tests using the stdin.\n- [#3776](https://github.com/grafana/k6/pull/3776) fixes a panic caused by passing an undefined handler to timers.\n- [#3779](https://github.com/grafana/k6/pull/3779) fixes a panic caused by registering an undefined handler in gRPC streams.\n- [xk6-websockets#73](https://github.com/grafana/xk6-websockets/pull/73) fixes a panic caused by registering an undefined handler in WebSockets.\n- [browser#1369](https://github.com/grafana/xk6-browser/pull/1369) improves `valueFromRemoteObject` `null` detection by returning a Go `nil` instead of `\"null\"` as a `string`.\n- [browser#1386](https://github.com/grafana/xk6-browser/pull/1386) correctly handles empty string flags that don't have a value.\n- [browser#1380](https://github.com/grafana/xk6-browser/pull/1380) ensures that `JSHandle.evaluate` and `JSHandle.evaluateHandle` both set themselves as the first argument.\n- [browser#1346](https://github.com/grafana/xk6-browser/pull/1346) fixes an IFrame panic (\"we either navigate top level or have old version of the navigated frame\") that happens during navigation.\n- [browser#1349](https://github.com/grafana/xk6-browser/pull/1349), [browser#1354](https://github.com/grafana/xk6-browser/pull/1354) fixes `Request` mappings.\n- [browser#1334](https://github.com/grafana/xk6-browser/pull/1334) fixes an issue where clicking on a link that opens a new tab never navigates to the href link.\n- [browser#1318](https://github.com/grafana/xk6-browser/pull/1318) fixes the `Mouse.move` to correctly dispatch a `down` event.\n- [browser#1301](https://github.com/grafana/xk6-browser/pull/1301) fixes an error that occurs when working with a second tab and navigating to a URL.\n- [browser#1387](https://github.com/grafana/xk6-browser/pull/1387) fixes a panic when the new document or request is missing.\n\n## Maintenance and internal improvements\n\n- [#3752](https://github.com/grafana/k6/pull/3752), [#3767](https://github.com/grafana/k6/pull/3767), [#3770](https://github.com/grafana/k6/pull/3770), [#3780](https://github.com/grafana/k6/pull/3780), [#3782](https://github.com/grafana/k6/pull/3782), [#3795](https://github.com/grafana/k6/pull/3795) updates several dependencies.\n- [#3786](https://github.com/grafana/k6/pull/3786), [#3787](https://github.com/grafana/k6/pull/3787), [#3788](https://github.com/grafana/k6/pull/3788), [#3789](https://github.com/grafana/k6/pull/3789), [#3803](https://github.com/grafana/k6/pull/3803) updates experimental modules.\n- [#3749](https://github.com/grafana/k6/pull/3749) stops printing `goja` stack traces on panics, which has been empty since a while.\n- [#3760](https://github.com/grafana/k6/pull/3760) fixes race conditions in ramping-vus tests.\n- [#3769](https://github.com/grafana/k6/pull/3769) removes a linter setting no longer used.\n- [#3800](https://github.com/grafana/k6/pull/3800) adds test coverage for outputting the archive to stdout.\n- [browser#1298](https://github.com/grafana/xk6-browser/pull/1298) splits browser mappings into separate files for better organization and maintainability.\n- [browser#1321](https://github.com/grafana/xk6-browser/pull/1321) adds test helpers for async VU execution to reduce the boilerplate in the tests.\n- [browser#1357](https://github.com/grafana/xk6-browser/pull/1357) updates `Group` and `Tag` usage for the latest k6.\n- [browser#1361](https://github.com/grafana/xk6-browser/pull/1361) precalculates the browser version information to prevent I/O calls when the `version` and `userAgent` methods are called. This change allows the browser module to expose these methods as a sync API to be consistent with the Playwright's API.\n- [browser#1377](https://github.com/grafana/xk6-browser/pull/1377) uses the `goja` fork called `sobek` in the browser module.\n- [browser#1373](https://github.com/grafana/xk6-browser/pull/1373) provides sync and async APIs within the browser module for making the migration to the async API easier.\n\n## Roadmap\n\n### Native ECMAScript modules\n\nAs mentioned above, the k6 team has forked [`goja`](https://github.com/dop251/goja/) into [`sobek`](https://github.com/grafana/sobek) and is currently working on [native ECMAScript modules support](https://github.com/grafana/k6/issues/3265). The current work in progress can be found in this [PR](https://github.com/grafana/k6/pull/3456) and any feedback is welcome.\n\nAs part of that there likely will be some breaking changes due to the current not native support allowing stuff that shouldn't work. Like for example mixing [CommonJS](https://en.wikipedia.org/wiki/CommonJS) and ESM in the same file. Which is for example why we have added a [warning](https://github.com/grafana/k6/pull/3807) that it won't work. \n\nSupport across multiple files is *also* not standard but due to amount of users that seems to be mixing them *across* files a lot of work has been done to support it. It is still likely that in the future warnings and potentially at some point future breaking changes will be enacted.\n\n### OpenTelemetry metrics output\n\nWe're also happy to share that this release cycle, we've been working on [xk6-output-opentelemetry](https://grafana.com/docs/k6/latest/results-output/real-time/opentelemetry/), a k6 output extension that allows you to send k6 metrics to OpenTelemetry-compatible backends. We're looking for feedback from the community. If you're interested, please try it and let us know [via the extension repository](https://github.com/grafana/xk6-output-opentelemetry/issues)!\n\nDepending on the feedback, we plan to include this extension as an experimental output in the next k6 release.\n"
  },
  {
    "path": "release notes/v0.53.0.md",
    "content": "k6 `v0.53.0` is here 🎉! This release includes:\n\n- Native ECMAScript modules support\n- New experimental OpenTelemetry metrics output\n- Blob support in experimental websockets module\n- Consolidate cloud features and commands under `k6 cloud`\n- Breaking change: remove magic URL resolutions\n\n## Breaking changes\n\n### Require is now specification compliant and always resolves based on the file it is written in [#3534](https://github.com/grafana/k6/issues/3534)\n\nThe `require` function in k6 used to resolve identifiers based on the current \"root of execution\" (more on that later). In a lot of cases, that aligns with the file the `require` is written in or a file in the same folder, which leads to the same result. In a small subset of cases, this isn't the case.\n\nIn every other implementation, and more or less by the CommonJS specification, `require` should always be relative to the file it is written in.\n\nThis also aligns with how ESM and dynamic `import` also work. In order to align with them `require` now uses the same underlying implementation.\n\nThere was a warning message for the last 2 releases trying to tease out cases where that would be problematic.\n\n<details>\n  <summary>\"root of execution\" explanation</summary>\n\nThis is very much an implementation detail that has leaked and likely a not intended one.\n\nWhenever a file is `require`-ed it becomes the \"root of execution\", and both `require` and `open` become relative to it. Once the `require` finishes, the previous \"root of execution\" gets restored. Outside of the `init` context execution, the main file is the \"root of execution\".\n\nExample:\n\nHave 3 files:\nmain.js\n```javascript\nconst s = require(\"./A/a.js\")\nif (s() != 5) {\n\tthrow \"Bad\"\n}\nmodule.exports.default = () =>{} // just for k6 to not error\n```\n\n/A/a.js:\n```javascript\nmodule.exports = function () {\n  return require(\"./b.js\");\n}\n```\n/A/b.js\n```javascript\nmodule.exports = 5\n```\nIn this example when `require` is called in `/A/a.js` the `main.js` is once again the \"root of execution\". If you call the function in `/A/a.js` just after defining it though, it will work as expected.\n\n</details>\n\nYou can use the newly added `import.meta.resolve()` function if you want to create a path that is relevant to the currently calling module. That will let you call it outside of a helper class and provide the path to it. Refer to [docs](https://grafana.com/docs/k6/latest/javascript-api/import.meta/resolve/) for more details.\n\n### ECMAScript Modules (ESM) Native Support related breaking changes\n\nAs part of the ESM native support implementation, two common broken patterns in the ecosystem became apparent.\n\nOne is arguably a developer experience improvement, and the other is a consequence of the previous implementation.\n\n#### Mixing CommonJS and ESM\n\nPreviously, k6 used a transpiler (Babel) internally to transpile ESM syntax to CommonJS. That led to all code always being CommonJS, and if you had CommonJS next to it, Babel would not complain.\n\nAs k6 (or the underlying JS VM implementation) did not understand ESM in itself and that CommonJS is a 100% during execution feature, this was not easy to detect or prevent.\n\nWe added a [warning](https://github.com/grafana/k6/pull/3807) in v0.52.0 to give users time for migration.\n\nTo fix this - all you need is to stick to either CommonJS or ESM within each file.\n\n<details>\n  <summary>Code examples and proposed changes</summary>\n\n```javascript\nimport { sleep } from \"k6\";\n\nmodule.exports.default = func() { ...}\n```\n\nIn the example above both ESM and CommonJS are used in the same file.\n\nYou can either replace:\n\n```javascript\nmodule.exports.default = func() {}\n```\n\nWith the ESM syntax:\n\n```javascript\nexport default func() {}\n```\n\nOr replace:\n\n```javascript\nimport { sleep } from \"k6\";\n```\n\nWith CommonJS:\n\n```javascript\nconst sleep = require(\"k6\").sleep;\n```\n\n</details>\n\n#### Imported identifier that can't be resolved are now errors\n\nPrevious to this, if you were using the ESM syntax and imported the `foo` identifier, but the exporting file didn't export it, there wouldn't be an error.\n\nbar.js:\n```javascript\nexport const notfoo = 5;\n```\n\nmain.js\n```javascript\nimport { foo } from \"./bar.js\"\nexport default function () {\n    foo.bar(); // throws exception here\n}\n```\n\nThe example would not error out, but when it is accessed, there would be an exception as `foo` would be `undefined`.\n\nWith native ESM support, that is an error as defined by the specification and will occur sooner.\n\nThis arguably improves UX/DX, but we have reports that some users have imports like this but do not use them. So, they wouldn't be getting exceptions, but they would now get errors.\n\nThe solution, in this case, is to stop importing the not exported identifiers.\n\n### No more \"magic\" URL resolution\n\nFor a long time, k6 has supported special _magic_ URLs that aren't really that.\n\nThose were URLs without a scheme that:\n\n1. Started with `github.com`, and if pasted to a browser won't open to a file. Their appeal was that you can more easily write them by hand if you know the path within a GitHub repo.\n2. Started with `cdnjs.com`, and if pasted to a browser will open a web page with all the versions of the library. The appeal here is that you will get the latest version.\n\nBoth of them had problems though.\n\nThe GitHub ones seemed to have never been used by users, likely because you need to guess what the path should look like, and you can always just go get a real URL to the raw file.\n\nWhile the cdnjs ones have some more usage, they are both a lot more complicated to support, as they require multiple requests to figure out what needs to be loaded. They also change over time. In addition the only known use at the moment is based on a very old example from an issue and it is even pointing to concrete, old version, of a library.\n\nGiven that this can be done with a normal URL, we have decided to drop support for this and have warned users for the last couple of versions.\n\n### Deprecated `k6/experimental/tracing` in favor of a JavaScript implementation\n\n`k6/experimental/tracing` is arguably not very well named, and there is a good chance we would like to use the name for actual trace and span support within k6 in the future.\n\nOn top of that it can now be fully supported in js code, which is why [http-instrumentation-tempo\n](https://grafana.com/docs/k6/latest/javascript-api/jslib/http-instrumentation-tempo/) was created.\n\nThe JavaScript implementation is a drop-in replacement, so all you need to do is replace `k6/experimental/tracing` with `https://jslib.k6.io/http-instrumentation-tempo/1.0.0/index.js`.\n\nThe module is [planned to be removed in v0.55.0](https://github.com/grafana/k6/pull/3855), planned for November 11th, 2024.\n\n### Experimental websockets now require `binaryType` to be set to receive binary messages\n\nAs part of the stabilization of the `k6/experimental/websockets` we need to move the default value of `binaryType` to `blob`. It was previously `arraybuffer` and since the last version there was a warning that it needs to be set in order for binary messages to be received.\n\nThat warning is now an error.\n\nIn the future we will move the default value to `blob` and remove the error.\n\n## New features\n\nThe new features include:\n- Native ESM support, which also brings some quality of life JavaScript features\n- Blob support in the experimental websockets module\n- Experimental OpenTelemetry metrics output\n- Consolidating cloud related commands and features under `k6 cloud`\n\n### Native ESM support [#3456](https://github.com/grafana/k6/pull/3456)\n\nWith this feature k6 is now ES6+ compliant natively. Which means (asterisk free) support for [the spread operator with object](https://github.com/grafana/k6/issues/824), [private class fields](https://github.com/grafana/k6/issues/2887) and [optional chaining](https://github.com/grafana/k6/issues/2168)\n\nBut also faster startup times, more consistent errors and easier addition of features as we now only need to add them to Sobek instead of also them being supported in the internal Babel.\n\n<details>\n  <summary>History of compatibility mode and ECMAScript specification compliance</summary>\n\nSome history: More than 6 years ago k6 started using core-js and babel to get ES6+ features. core-js is a implementation of a lot of the types and their features such as [`String.prototype.matchAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll) among other things, and Babel gets one piece of code that uses some syntax and returns a piece of code doing the same thing (mostly) but with different syntax. Usually with the idea of supporting newer syntax but returning code that can run on runtimes which only support old syntax.\n\nThis is great, but it means that:\n1. For core-js each VU needs to run a bunch of JS code each initialization so it can polyfill everything that is missing\n2. Babel needs to be parsed and loaded and then given files to transpile on each start.\n\nBoth of those aren't that big problems usually, but the runtime k6 uses is fairly fast, but isn't V8. What it lacks in speed it gets back in being easy to interact with from Go, the language k6 is written in.\n\nBut it means that now on each start it needs to do a bunch of work that adds up.\n\nSo long time ago for people who would want to not have to do this we added [compatibility-mode=base](https://github.com/grafana/k6/pull/1206). This allowed you to potentially not use this features and get a big speedup. Or use them outside of k6 and likely still get significant speed up if you cut down on it.\n\nAt the same time the author and maintainer of the JS runtime we used (goja) did implement a *big* portion of what we were missing from core-js and also Babel. After some experiments to cut down the core-js we import we ended up contributing back the remaining parts and dropping the whole library. Which lead to 5 times reduction of memory per VU for simple scripts. And even for fairly complicated ones.\n\nWith this in mind we did try to cut down Babel as well and contribute back the simpler things it was used for. This over the years lead to small pieces of what Babel did being moved to goja and then disabled in Babel. Some of those were just easy wins, some of those were things that had very bad pathological cases where using a particular syntax made transpilation times explode.\n\nIn all of that work there always were small (or not so small) breaking changes due to many factors - sometimes our new implementation was slightly wrong and we needed to fix, sometimes more than what was in the standard was enabled in core-js or Babel, sometimes the standard changed on those. And sometimes the implementation in Babel or core-js wasn't as full and didn't account for all corner cases.\n\nECMAScript Modules(ESM) is the last such feature that Babel was used for. It also happens to be likely the one *most* people used, due to the fact that it is the standard way to reuse code and import libraries.\n\nWhile the work on this feature started over 2 years ago, it both depended on other features that weren't there yet, but also interacts with more or less every other feature that is part of the ECMAScript standard.\n\nAlong the way there were many internal refactors as well as additional tests to make certain we can be as backwards compatible as possible. But there also ended up being things that just weren't going to be compatible, like the listed breaking changes.\n\n</details>\n\nAfter ESM now being natively supported, compatibility-mode `base` vs `extended` has only 1 feature difference - aliasing `global` to `globalThis` to make it a bit more compatible with (old) Node.js. There is ongoing [discussion](https://github.com/grafana/k6/issues/3864) if that as well should be removed.\n\nFor the purposes of having less intrusive changes and shipping this earlier a few things have not been implemented in k6. That includes top-level-await and dynamic import support. Both of them are likely to land in the next version.\n\n### `import.meta.resolve()` gets an URL from a relative path the same way `import` or `require` does [#3873](https://github.com/grafana/k6/pull/3873)\n\nAs part of the move to ESM a lot of cases where k6 currently do not resolve the same relative path to the same file were found. Some of those were fixed - as those in `require`, but others haven't.\n\nIt also became apparent some users do use the relativity of `require`, but also `open`. As we move to make this consistent among uses, we decided to let users have a better transition path forward.\n\nUsing `import.meta.resolve` will give you just a new URL that can be used in all functions and it will give you the same result.\n\n`import.meta.resolve` uses the same algorithm and relativity as ESM import syntax. Refer to [docs](https://grafana.com/docs/k6/latest/javascript-api/import.meta/resolve/) for more details.\n\n### Blob support in the experimental websockets module [grafana/xk6-websockets#74](https://github.com/grafana/xk6-websockets/pull/74)\n\nIn order to support the default `WebSocket.binaryType` type as per spec (`\"blob\"`),  we have added support for the [`Blob` interface](https://developer.mozilla.org/en-US/docs/Web/API/Blob) as part of the features included in the `xk6-websockets` module. \n\nSo, from now on it can be used with `import { Blob } from \"k6/experimental/websockets\";`. In the future, apart from graduating this module to stable, we might also want to expose the `Blob` interface globally (no imports will be required). But for now, please remind that its support is still experimental, as the entire module is. Refer to the [docs](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/websockets/blob/) for more details.\n\n### Experimental OpenTelemetry Output [#3834](https://github.com/grafana/k6/pull/3834)\n\nThis release introduces a new experimental output for OpenTelemetry. This allows users to send k6 metrics to any OpenTelemetry-compatible backends. More details and usage examples can be found in the [documentation](https://grafana.com/docs/k6/latest/results-output/real-time/opentelemetry/).\n\nTo output metrics to OpenTelemetry, use the `experimental-opentelemetry` output option:\n\n```bash\n k6 run -o experimental-opentelemetry examples/script.js\n```\n\nIf you have any feedback or issues, please let us know directly in [the extension repository](https://github.com/grafana/xk6-output-opentelemetry/issues).\n\n### Consolidating cloud features under `k6 cloud` [#3813](https://github.com/grafana/k6/pull/3813)\n\nThis release introduces the first iteration of the revamped cloud-related commands under the `k6 cloud` command, featuring two new subcommands:\n\n- `k6 cloud login`: replaces `k6 login cloud` for authenticating with the cloud service. It supports token-based authentication only. The previous authentication method using email and password will still be available through the legacy `k6 login cloud` command, which is now deprecated and will be removed in a future release (no removal date set yet).\n\n- `k6 cloud run`: is the new official way to run k6 on the cloud service, serving as an alternative to the existing `k6 cloud` command. The `k6 cloud` command will remain available for a few more versions but will eventually function only as a wrapper for all cloud-related commands, without any direct functionality.\n\n## UX improvements and enhancements\n\n- [#3783](https://github.com/grafana/k6/pull/3783) Set correct exit code on invalid configurations. Thank you @ariasmn!\n- [#3686](https://github.com/grafana/k6/pull/3868) Adjust logging of the executor lack of work. Thank you @athishaves!\n\n## Bug fixes\n\n- [#3746](https://github.com/grafana/k6/pull/3746) Fix tags for metrics from gRPC streams. Thank you @cchamplin!\n- [#3845](https://github.com/grafana/k6/pull/3845) Fix logging to file sometimes missing lines. Thank you @roobre!\n- [browser#1391](https://github.com/grafana/xk6-browser/pull/1391) Fix race conditions in internal event handling.\n\n## Maintenance and internal improvements\n\n- [#3792](https://github.com/grafana/k6/pull/3792), [#3817](https://github.com/grafana/k6/pull/3817), [#3863](https://github.com/grafana/k6/pull/3863) Finalize moving to Sobek, our fork of goja.\n- [#3815](https://github.com/grafana/k6/pull/3815), [#3840](https://github.com/grafana/k6/pull/3840), [#3821](https://github.com/grafana/k6/pull/3821), [#3836](https://github.com/grafana/k6/pull/3836), [#3840](https://github.com/grafana/k6/pull/3840), [#3844](https://github.com/grafana/k6/pull/3844), [#3821](https://github.com/grafana/k6/pull/3821) Update dependencies.\n- [#3830](https://github.com/grafana/k6/pull/3830), [#3831](https://github.com/grafana/k6/pull/3831), [#3862](https://github.com/grafana/k6/pull/3862) Refactoring and cleanup around ESM PR.\n- [browser#1389](https://github.com/grafana/xk6-browser/pull/1389) Move deserialization of `BrowserContextOptions` into mapping layer.\n- [#3841](https://github.com/grafana/k6/pull/3841) Add browser and cloud support information to the README. Thank you @sniku!\n- [#3843](https://github.com/grafana/k6/pull/3837), [#3847](https://github.com/grafana/k6/pull/3847) `k6/experimental/timers` deprecation warning updates.\n- [#3851](https://github.com/grafana/k6/pull/3851) Simplify gRPC streams metrics tags tests.\n- [#3870](https://github.com/grafana/k6/pull/3870) Update tests to work with go1.22.\n\n\n## Roadmap\n\n### Future breaking changes\n\n#### Experimental browser module removal\n\nIn the previous release, the browser module graduated from experimental to stable. The `k6/experimental/browser` module will be removed in `v0.54.0`. To keep your scripts working you need to [migrate to the `k6/browser` module](https://grafana.com/docs/k6/latest/using-k6-browser/migrating-to-k6-v0-52/).\n\n#### Experimental timers module removal\n\nThe experimental timers module has been deprecated for a few versions. It both has a stable import path `k6/timers`, but also all of it's current exports are available globally.\n\nIn the next version `v0.54.0` the experimental timers module will be removed.\n\n#### Experimental tracing module removal\n\nThe experimental tracing module is deprecated in this version. In two versions(`v0.55.0`) the experimental module will be removed.\n\nTo keep your scripts working you need to [migrate to http-instrumentation-tempo jslib](https://grafana.com/docs/k6/latest/javascript-api/jslib/http-instrumentation-tempo/#migration-from-k6experimentaltracing).\n\n#### StatsD removal\n\nIn this release, we also fixed the version where we will remove the StatsD output. The StatsD output [is going to be removed in the `v0.55.0`](https://github.com/grafana/k6/pull/3849) release. If you are using the StatsD output, please consider migrating to the extension [LeonAdato/xk6-output-statsd](https://github.com/LeonAdato/xk6-output-statsd).\n\n#### Potentially dropping `global` from `extended` compatibility-mode\n\nCurrently `global` is aliased to `globalThis` when `extended` compatibility-mode is used. This is currently the only difference with the `base` compatibility-mode.\n\nGiven that this seems to have very low usage it might be dropped in the future. See the [issue](https://github.com/grafana/k6/issues/3864) for more info or if you want to comment on this.\n"
  },
  {
    "path": "release notes/v0.54.0.md",
    "content": "k6 `v0.54.0` is here 🎉! This release includes:\n\n- A new experimental CSV module\n- New `k6 cloud` commands for local execution and uploading script files\n- New ECMAScript features\n- Updated logo and branding\n\n## Breaking changes\n\n- [#3913](https://github.com/grafana/k6/pull/3913) changes the mapping of Golang's `math/big.Int` type to `bigint` type in k6.\n- [#3922](https://github.com/grafana/k6/pull/3922) removes `lib.Min` and `lib.Max` from k6's Go API, which could affect custom extensions that rely on these functions.\n- [#3838](https://github.com/grafana/k6/pull/3838) removes `k6/experimental/timers` - they are now available globally and no import is needed.\n- [#3944](https://github.com/grafana/k6/pull/3944) updates to `k6/experimental/websockets`, which makes the `binaryType` default value equal to `\"blob\"`. With this change, `k6/experimental/websockets` is now compliant with the specification.\n\n## New features\n\n### Branding changes and logo [`#3946`](https://github.com/grafana/k6/pull/3946), [`#3953`](https://github.com/grafana/k6/pull/3953), [`#3969`](https://github.com/grafana/k6/pull/3969)\n\nAs part of joining Grafana Labs in 2021, k6 was renamed to Grafana k6. The original k6 logo and branding was purple, which didn't fit very well next to the Grafana Labs orange logo and all its other products.\n\nIn this release, we have a new logo in a new color, and the terminal banner has been redesigned to match the current branding more closely.\n\n<p align=\"center\">\n  <img src=\"https://github.com/grafana/k6/blob/31e3db711850fdd270e56e53feb3a2e4209e542a/assets/logo.svg\" alt=\"Grafana k6 logo\" width=\"210\">\n</p>\n\n### New experimental CSV module for efficient CSV data handling [`#3743`](https://github.com/grafana/k6/pull/3743)\n\nWe’ve added a new experimental CSV module to k6 for more efficient and convenient CSV parsing and streaming, addressing the limitations of preexisting JavaScript-based solutions like [papaparse](https://www.papaparse.com/).\n\n#### What is it?\n\nThe CSV module offers two key features:\n\n* `csv.parse()`: This function parses a CSV file into a [SharedArray](https://grafana.com/docs/k6/latest/javascript-api/k6-data/sharedarray/) at once using Go-based processing for faster parsing and lower memory usage compared to JavaScript alternatives.\n* `csv.Parser`: This class provides a streaming parser to read CSV files line-by-line, minimizing memory consumption and offering more control over parsing through a stream-like API. This is ideal for scenarios where memory optimization or fine-grained control of the parsing process is crucial.\n\n#### Benefits for users\n\n* **Faster Parsing**: `csv.parse` bypasses most of the JavaScript runtime, offering significant speed improvements for large files.\n* **Lower Memory Usage**: Both solutions support shared memory across virtual users (VUs) with the `fs.open` function.\n* **Flexibility**: Choose between full-file parsing with `csv.parse()` or memory-efficient streaming with `csv.Parser`.\n\n#### Tradeoffs\n\n* **`csv.Parse`**: Parses the entire file in the initialization phase of the test, which can increase startup time and memory usage for large files. Best suited for scenarios where performance is prioritized over memory consumption.\n* **`csv.Parser`**: Reads the file line-by-line, making it more memory-efficient but potentially slower due to reading overhead for each line. Ideal for scenarios where memory usage is a concern or where fine-grained control over parsing is needed.\n \n#### Example usage\n\n<details>\n<summary> Expand to see an example of Parsing a full CSV file into a SharedArray.</summary>\n\n```javascript\nimport { open } from 'k6/experimental/fs'\nimport csv from 'k6/experimental/csv'\nimport { scenario } from 'k6/execution'\n\nexport const options = {\n    iterations: 10,\n}\n\nlet file;\nlet csvRecords;\n(async function () {\n    file = await open('data.csv');\n\n    // The `csv.parse` function consumes the entire file at once, and returns\n    // the parsed records as a SharedArray object.\n    csvRecords = await csv.parse(file, {delimiter: ','})\n})();\n\n\nexport default async function() {\n    // The csvRecords a SharedArray. Each element is a record from the CSV file, represented as an array\n    // where each element is a field from the CSV record.\n    //\n    // Thus, `csvRecords[scenario.iterationInTest]` will give us the record for the current iteration.\n    console.log(csvRecords[scenario.iterationInTest])\n}\n```\n\n</details>\n\n<details>\n<summary> Expand to see an example of streaming a CSV file line-by-line.</summary>\n\n```javascript\nimport { open } from 'k6/experimental/fs'\nimport csv from 'k6/experimental/csv'\n\nexport const options = {\n    iterations: 10,\n}\n\nlet file;\nlet parser;\n(async function () {\n    file = await open('data.csv');\n    parser = new csv.Parser(file);\n})();\n\nexport default async function() {\n    // The parser `next` method attempts to read the next row from the CSV file.\n    //\n    // It returns an iterator-like object with a `done` property that indicates whether\n    // there are more rows to read, and a `value` property that contains the row fields\n    // as an array.\n    const {done, value} = await parser.next();\n    if (done) {\n        throw new Error(\"No more rows to read\");\n    }\n\n    // We expect the `value` property to be an array of strings, where each string is a field\n    // from the CSV record.\n    console.log(done, value);\n}\n```\n\n</details>\n\n### New `k6 cloud run --local-execution` flag for local execution of cloud tests [`#3904`](https://github.com/grafana/k6/pull/3904), and [#3931](https://github.com/grafana/k6/pull/3931)\n\nThis release introduces the `--local-execution` flag for the k6 cloud run command, allowing you to run test executions locally while sending metrics to Grafana Cloud k6.\n\n```bash\nk6 cloud run --local-execution script.js\n```\n\nBy default, using the `--local-execution` flag uploads the test archive to Grafana Cloud k6. If you want to disable this upload, use the `--no-archive-upload` flag.\n\nThe `--local-execution` flag currently functions similarly to the `k6 run -o cloud` command, which is now considered deprecated (though it is not planned to be removed). Future updates will enhance `--local-execution` with additional capabilities that the `k6 run -o cloud` command does not offer.\n\n### New `k6 cloud upload` command for uploading test files to the cloud [`#3906`](https://github.com/grafana/k6/pull/3906)\n\nWe continue to refine and improve the cloud service to improve how we handle uploading test files, so we've added a new `k6 cloud upload` command that replaces the `k6 cloud --upload-only` flag, which is now considered deprecated.\n\n### gRPC module updates driven by contributors\n\n#### New `discardResponseMessage` option\n\n[#3877](https://github.com/grafana/k6/pull/3877) and [#3820](https://github.com/grafana/k6/pull/3820) add a new option for the gRPC module `discardResponseMessage`, which allows users to discard the messages received from the server.\n\n```javascript\nconst resp = client.invoke('main.RouteGuide/GetFeature', req, {discardResponseMessage: true});\n```\n\nThis reduces the amount of memory required and the amount of garbage collection, which reduces the load on the testing machine and can help produce more reliable test results.\n\nThank you, @lzakharov!\n\n#### New argument `meta` for gRPC's stream callbacks\n\n[#3801](https://github.com/grafana/k6/pull/3801) adds a new argument `meta` to gRPC's stream callback, which handles the timestamp of the original event (for example, when a message has been received).\n\n```javascript\nlet stream = new grpc.Stream(client, \"main.FeatureExplorer/ListFeatures\")\nstream.on('data', function (data, meta) {\n    // will print the timestamp when message has been received\n    call(meta.ts);\n});\n```\n\nThank you, @cchamplin!\n\n#### Allow missing file descriptors for gRPC reflection\n\n[#3871](https://github.com/grafana/k6/pull/3871) allows missing file descriptors for gRPC reflection.\n\nThank you, @Lordnibbler!\n\n### Sobek updates brings support of new ECMAScript features into k6 [`#3899`](https://github.com/grafana/k6/pull/3899), [`#3925`](https://github.com/grafana/k6/pull/3925), [`#3913`](https://github.com/grafana/k6/pull/3913)\n\nWith this release, we've updated [Sobek](https://github.com/grafana/sobek) (the `ECMAScript` implementation in Go) which contains the new ECMAScript features that are now available in k6.\n\nThis includes support for numeric literal separators:\n\n```javascript\nconst billion = 1_000_000_000\n```\n\nSupport for `BigInt`, the values which are too large to be represented by the number primitive:\n\n```javascript\nconst huge = BigInt(9007199254740991);\n```\n\nNote: Before k6 version v0.54, Golang's type `math/big.Int` mapped to another type, so this might be a breaking change for some extensions or users.\n\nRegExp dotAll support, where you can match newline characters with `.`:\n\n```javascript\nconst str1 = \"bar\\nexample foo example\";\n\nconst regex1 = /bar.example/s;\n\nconsole.log(regex1.dotAll); // true\n```\n\nSupport for ES2023 Array methods: [`with`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/with), [`toSpliced`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSpliced), [`toReversed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toReversed) and [`toSorted`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted).\n\nThank you @shiroyk for adding both the new array methods and BitInt :bow:.\n\n### New `setChecked` method for the browser module [`browser#1403`](https://github.com/grafana/xk6-browser/pull/1403)\n\nPreviously, users could check or uncheck checkbox and radio button elements using the [`check`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/check/) and [`uncheck`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/uncheck/) methods. Now, we've added a `setChecked` method that allows users to set a checkbox or radio button to either the checked or unchecked state with a single method and a boolean argument.\n\n```javascript\nawait page.setChecked('#checkbox', true);   // check the checkbox\nawait page.setChecked('#checkbox', false);  // uncheck the checkbox\n```\n\n[Page](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/setchecked/), [Frame](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/frame/setchecked/), [ElementHandle](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/elementhandle/setchecked/), and [Locator](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/setchecked/) now support the new `setChecked` method.\n\n### Async `check` function utility [`k6-utils#13`](https://github.com/grafana/k6-jslib-utils/pull/13)\n\nWriting concise code can be difficult when using [the k6 `check` function](https://grafana.com/docs/k6/latest/javascript-api/k6/check/) with async code since it doesn't support async APIs. A solution that we have suggested so far is to declare a temporary variable, wait for the value that is to be checked, and then check the result later. However, this approach can clutter the code with single-use declarations and unnecessary variable names, for example:\n\n```javascript\nconst checked = await p.locator('.checked').isChecked();\n\ncheck(checked, {\n    'checked': c => c,\n});\n```\n\nTo address this limitation, we've added a version of the `check` function to [jslib.k6.io](https://jslib.k6.io/) that makes working with `async`/`await` simpler. The `check` function is a drop-in replacement for the built-in check, with added support for async code. Any `Promise`s will be awaited, and the result is reported once the operation has been completed:\n\n```javascript\n// Import the new check function from jslib.k6.io/k6-utils\nimport { check } from 'https://jslib.k6.io/k6-utils/1.5.0/index.js';\n\n// ...\n\n// Use the new check function with async code\ncheck(page, {\n    'checked': async p => p.locator('.checked').isChecked(),\n});\n```\n\nCheck out [the `check` utility function's documentation](https://grafana.com/docs/k6/latest/javascript-api/jslib/utils/check/) for more information on how to use it.\n### `k6/experimnetal/websockets` updates towards WebSockets API compatibility\n\n#### Support ArrayBufferViews in `send` for `k6/experimental/websockets` [#3944](https://github.com/grafana/k6/pull/3844)\n\nAs part of making `k6/experimental/websockets` compliant with the [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), it now supports Uint8Array and other ArrayBufferViews directly as arguments to `send`, instead of having to specifically provide their `buffer`.\n\nThis should make the module more compliant with libraries that use the WebSocket API.\n\nThanks to @pixeldrew for [reporting](https://github.com/grafana/xk6-websockets/issues/75) this. :bow:\n#### `readyState` actually being a number [#3972](https://github.com/grafana/k6/pull/3972)\n\nDue to goja/Sobek internal workings, `readyState` wasn't exactly a number in JavaScript code. This had some abnormal behavior, which limited interoperability with libraries.\n\nThis has been fixed, and `readyState` is a regular number from the JavaScript perspective.\n\nThanks to @dougw-bc for [reporting](https://github.com/grafana/xk6-websockets/issues/79) this. :bow:\n\n### Rework of how usage is being collected internally and additional counters [`#3917`](https://github.com/grafana/k6/pull/3917) and [`#3951`](https://github.com/grafana/k6/pull/3951)\n\nAs part of working on k6 over the years, we have often wondered if users use certain features or if they see a strange corner case behavior.\n\nWe have usually made guesses or tried to extrapolate from experience on issues we see. Unfortunately, this isn't always easy or possible, and it's definitely very skewed. As such, we usually also add warning messages to things we intend to break to inform people and ask them to report problems. But we usually see very little activity, especially before we make changes.\n\nThis also only works for things we want to remove, and it doesn't help us know if people use new functionality at all or if there are patterns we don't expect.\n\nWhile k6 has been collecting usage for a while, they're surface-level things, such as how many VUs were run, the k6 version, or which *internal* modules were loaded. The system for this was also very rigid, requiring a lot of work to add simple things, such as if someone used the `require` function.\n\nThis process has been reworked to make things easier, and a few new usage reports have been added:\n\n- When Grafana Cloud is used, it will also tell us which test run it is. We already have most of the information reported through metrics and from the test being executed in the cloud. But this will help us filter cloud test runs from local runs and potentially warn cloud users if they're using experimental modules that will be removed.\n- The number of files parsed, as well as the number of .ts files parsed. This will help us understand if people use small or big projects and if TypeScript support is being used.\n- Usage of `require`. Now that we have ESM native support, using `require` and CommonJS adds complexity. It's interesting to us whether removing this in the future - likely years, given its support in other runtimes, is feasible.\n- Usage of `global`. This will help us decide if we can [drop compatibility-mode](https://github.com/grafana/k6/issues/3864) differences or even the whole concept.\n\n## UX improvements and enhancements\n\n- [#3898](https://github.com/grafana/k6/pull/3898) adds `SetupTimeout` option validation. Thank you, @tsukasaI!\n- [#3930](https://github.com/grafana/k6/pull/3930) adds token validation for `k6 cloud login`, so now you get immediate feedback right after logging in.\n- [#3876](https://github.com/grafana/k6/pull/3876), [#3923](https://github.com/grafana/k6/pull/3923) adjusts the process' exit code for cloud test runs where thresholds have failed.\n- [#3765](https://github.com/grafana/k6/pull/3765) stops using the confusing `✓` and `✗` for `Rate` metrics, and instead uses the form: `{x} out of {y}`.\n\n## Bug fixes\n\n- [#3947](https://github.com/grafana/k6/pull/3947) fixes panic when `options` is `nil` (e.g. exported from a module where it isn't really exported).\n- [#3901](https://github.com/grafana/k6/pull/3901) fixes the `cloud` command not being display in the `k6` command's help text.\n- [browser#1406](https://github.com/grafana/xk6-browser/pull/1406) fixes panic on iframe attach when iframe didn't contain any UI elements.\n- [browser#1420](https://github.com/grafana/xk6-browser/pull/1420) uses the VU context to control the iterations lifecycle which helps k6 shutdown in a timely manner when a test is aborted.\n- [browser#1421](https://github.com/grafana/xk6-browser/pull/1421) fixes the navigation span by starting when the page starts to load so that it's a better representation of how long the test was on a page.\n- [browser#1408](https://github.com/grafana/xk6-browser/pull/1408), [browser#1422](https://github.com/grafana/xk6-browser/pull/1422) fixes the `page.reload` API so handles `null` responses without exceptions.\n- [browser#1435](https://github.com/grafana/xk6-browser/pull/1435) fixes an NPD when performing a `click` action.\n- [browser#1438](https://github.com/grafana/xk6-browser/pull/1438) fixes a goroutine that waits indefinitely when writing to a channel.\n- [#3968](https://github.com/grafana/k6/pull/3968) fixes an issue with the event system where it was dropping events which led to it hanging indefinitely.\n- [browser#1442](https://github.com/grafana/xk6-browser/pull/1442) fixes `browser.close` to abort the cdp close request when the browser process has already exited.\n\n## Maintenance and internal improvements\n\n- [#3915](https://github.com/grafana/k6/pull/3915) switches `go.mod` to the go1.21, introduces toolchain.\n- [#3938](https://github.com/grafana/k6/pull/3938) updates k6's CI workflows to go 1.23.\n- [#3939](https://github.com/grafana/k6/pull/3939) updates Dockerfile to use go 1.23 and alpine 3.20.\n- [#3909](https://github.com/grafana/k6/pull/3909) fixes `ExitCode` description typo. Thank you, @eltociear!\n- [#3926](https://github.com/grafana/k6/pull/3926) documents maintenance of tc39 tests.\n- [#3881](https://github.com/grafana/k6/pull/3881) adds top-level roadmap link.\n- [#3945](https://github.com/grafana/k6/pull/3945) updates the endpoint where [usage reports](https://grafana.com/docs/k6/latest/set-up/usage-collection/) are sent to.\n- [browser#1419](https://github.com/grafana/xk6-browser/pull/1419), [browser#1423](https://github.com/grafana/xk6-browser/pull/1423) add a new remote file upload protocol.\n- [#3900](https://github.com/grafana/k6/pull/3900), [#3902](https://github.com/grafana/k6/pull/3902) update golangci-lint to 1.60.1 and add `fatcontext` and `cononicalheader` as linters.\n- [#3908](https://github.com/grafana/k6/pull/3908) drops `NetTrail` internal type to simplify internal implementation on emitting iteration and data transmission metric.\n- [#3933](https://github.com/grafana/k6/pull/3933) adds a `testutils.MakeMemMapFs` test helper facilitating simulating a file system in tests.\n- [#3943](https://github.com/grafana/k6/pull/3943) raises `TestStreamLogsToLogger` log sending delay to improve the reliability of tests.\n- [#3935](https://github.com/grafana/k6/pull/3935) refactors some js tests to remove repeated setup code.\n- [#3903](https://github.com/grafana/k6/pull/3903), [#3912](https://github.com/grafana/k6/pull/3912), [#3928](https://github.com/grafana/k6/pull/3928), [#3910](https://github.com/grafana/k6/pull/3910), [#3954](https://github.com/grafana/k6/pull/3954), [#3963](https://github.com/grafana/k6/pull/3963), [#3965](https://github.com/grafana/k6/pull/3965), [#3966](https://github.com/grafana/k6/pull/3966), [#3965](https://github.com/grafana/k6/pull/3965), [#3970](https://github.com/grafana/k6/pull/3970) update dependencies.\n\n## Roadmap\n\nIn version 0.52.0, the browser module [transitioned](https://github.com/grafana/k6/pull/3793) from experimental to stable. The new module is more stable and has a [full Async API](https://github.com/grafana/xk6-browser/pull/1374). To ensure your scripts continue working, you must migrate to the new `k6/browser` module and discontinue using the previous `k6/experimental/browser` module. Please see [the migration guide](https://grafana.com/docs/k6/latest/using-k6-browser/migrating-to-k6-v0-52/) for more details.\n"
  },
  {
    "path": "release notes/v0.55.0.md",
    "content": "k6 `v0.55.0` is here 🎉! This release includes:\n\n- ⚠️ The deprecated StatsD output has been removed.\n- ⚠️ The experimental `k6/experimental/tracing` module has been removed.\n- 🆕 URL grouping support in the browser module.\n- 🆕 Top-level `await` support.\n- 🔐 Complete RSA support for `k6/experimental/webcrypto`.\n\n## Breaking changes\n\n### `k6/experimental/tracing` module removed [`#3855`](https://github.com/grafana/k6/pull/3855)\n\nThe experimental `k6/experimental/tracing` module has been removed, in favor of a replacement [jslib](https://jslib.k6.io/http-instrumentation-tempo/) polyfill, please consult our [guide on how to migrate](https://grafana.com/docs/k6/latest/javascript-api/jslib/http-instrumentation-tempo/#migration-from-k6experimentaltracing), [`#3855`](https://github.com/grafana/k6/pull/3855).\n\n### StatsD output removed [`#3849`](https://github.com/grafana/k6/pull/3849)\n\nThe StatsD output was deprecated in k6 v0.47.0 and is now removed. You could still output results to StatsD using the community xk6 extension [LeonAdato/xk6-output-statsd](https://github.com/LeonAdato/xk6-output-statsd). Thanks, @LeonAdato for taking over the extension!\n\n### `open` will have a breaking change in the future.\n\nCurrently, `open` opens relative files based on an unusual root, similar to how `require` behaved before it was updated for ESM compatibility. To make k6 more consistent, `open` and other functions like it will start handling relative paths in the same way as imports and `require`.\nFor a more in-depth explanation, please refer to the related [issue](https://github.com/grafana/k6/issues/3857).\n\nWith this version, k6 will start emitting warnings when it detects that in the future, this will break. We recommend using [`import.meta.resolve()`](https://grafana.com/docs/k6/latest/javascript-api/import.meta/resolve/) as a way to make your scripts future proof.\n\n### `http.file#data` now truly has the same type as the provided data [`#4009`](https://github.com/grafana/k6/pull/4009)\n\nPreviously `http.file#data` was always a slice of byte (`[]byte`) - which was very likely a bug and a leftover from years past.\n\nThe original aim (also documented) was to have the same type as the data provided when creating the `http.file` object, and it is now effectively the case.\n\n## New features\n\n### Top-level await support [`4007`](https://github.com/grafana/k6/pull/4007)\n\nAfter the initial native support for ECMAScript modules, k6 can now load those modules asynchronously which also allows `await` to be used in the top-level of a module. That is you can write `await someFunc()` directly in the top most level of a module instead of having to make an async function that you call that can than use `await`.\n\nUntil now, you had to wrap your code in an async function to use `await` in the top-level of a module. For example, the following code:\n\n```javascript\nimport { open } from 'k6/experimental/fs'\nimport csv from 'k6/experimental/csv'\n\nlet file;\nlet parser;\n(async function () {\n\tfile = await open('data.csv');\n\tparser = new csv.Parser(file);\n})();\n```\n\nCan now be written as:\n\n```javascript\nimport { open } from 'k6/experimental/fs'\nimport csv from 'k6/experimental/csv'\n\nconst file = await open('data.csv');\nconst parser = new csv.Parser(file);\n```\n\nThis should make using the increasing number of async APIs in k6 easier in the [init context](https://grafana.com/docs/k6/latest/using-k6/test-lifecycle/#the-init-stage).\n\nThis is not allowed in case of using the CommonJS modules, only ECMAScript modules, as CommonJS modules are synchronous by definition.\n\n### Complete[^1] RSA support for `k6/experimental/webcrypto` [`#4025`](https://github.com/grafana/k6/pull/4025)\n\nThis update includes support for the RSA family of algorithms, including `RSA-OAEP`, `RSA-PSS` and `RSASSA-PKCS1-v1_5`. You can use these algorithms with the `crypto.subtle` API in the same way as the other algorithms, precisely for `generateKey`, `importKey`, `exportKey`, `encrypt`, `decrypt`, `sign`, and `verify` operations.\n\nBy implementing RSA support, we make our WebCrypto API implementation more complete and useful for a broader range of use cases.\n\n[^1]: Since under the hood we do fully rely on the Golang's SDK, our implementation doesn't support zero salt lengths for the `RSA-PSS` `sign`/`verify` operations.\n\n#### Example usage\n\n<details>\n<summary>Expand to see an example of generation RSA-PSS key pair.</summary>\n\n```javascript\nimport { crypto } from \"k6/experimental/webcrypto\";\n\nexport default async function () {\n  const keyPair = await crypto.subtle.generateKey(\n    {\n      name: \"RSA-PSS\",\n      modulusLength: 2048,\n      publicExponent: new Uint8Array([1, 0, 1]),\n      hash: { name: \"SHA-1\" },\n    },\n    true,\n    [\"sign\", \"verify\"]\n  );\n\n  console.log(JSON.stringify(keyPair));\n}\n```\n\n</details>\n\n### `page.on('metric)` to group urls [browser#371](https://github.com/grafana/xk6-browser/issues/371), [browser#1487](https://github.com/grafana/xk6-browser/issues/1487)\n\nModern websites are complex and make a high number of requests to function as intended by their developers. These requests no longer serve only content for display to the end user but also retrieve insights, analytics, advertisements, and for cache-busting purposes. Such requests are usually generated dynamically and may contain frequently changing IDs, posing challenges when correlating and analyzing your k6 test results.\n\nWhen load testing a website using the k6 browser module, these dynamic requests can result in a high number of similar-looking requests, making it difficult to correlate them and extract valuable insights. This can also lead to test errors, such as a \"too-many-metrics\" error, due to high cardinality from metrics tagged with similar but dynamically changing URLs.\n\nThis issue also affects synthetic tests. While you may not encounter the \"too-many-metrics\" error, you may end up with a large amount of uncorrelated metric data that cannot be tracked effectively over time.\n\nTo address this in the browser module, we have implemented `page.on('metric')`, which allows you to define URL patterns using regex for matching. When a match is found, the URL and name tags for the metric are replaced with the new name.\n\n#### Example usage\n\n<details>\n<summary>Expand to see an example of working with `page.on('metric')`.</summary>\n\n```js\n\nimport { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n            type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function() {\n  const page = await browser.newPage();\n\n  // Here, we set up an event listener using page.on('metric').\n  // You can call page.on('metric') multiple times, and each callback function\n  // will be executed in the order that page.on was called.\n  page.on('metric', (metric) => {\n    // Currently, metric.tag is the only available method on the metric object.\n    // It enables matching on the URL tag using a specified regex pattern.\n    // You can call metric.tag multiple times within the callback function.\n    metric.tag({\n      // This is the new name assigned to any metric that matches the defined\n      // URL pattern below.\n      name: 'test',\n      // Provide one or more match patterns here. Any metrics that match a pattern\n      // will use the new name specified above.\n      matches: [\n        // Each match pattern can include a URL and an optional method.\n        // When a method is specified, the metric must match both the URL pattern\n        // and the method. If no method is provided, the pattern will match all\n        // HTTP methods.\n        {url: /^https:\\/\\/test\\.k6\\.io\\/\\?q=[0-9a-z]+$/, method: 'GET'},\n      ]\n    });\n  });\n\n  try {\n    // The following lines are for demonstration purposes.\n    // Visiting URLs with different query parameters (q) to illustrate matching.\n    await page.goto('https://test.k6.io/?q=abc123');\n    await page.goto('https://test.k6.io/?q=def456');\n  } finally {\n    // Ensure the page is closed after testing.\n    await page.close();\n  }\n}\n\n```\n\n</details>\n\n### `ControlOrMeta` support in the keyboard [browser#1457](https://github.com/grafana/xk6-browser/pull/1457)\n\nThis approach enables tests to be written for all platforms, accommodating either `Control` or `Meta` for keyboard actions. For example, `Control+click` on Windows and `Meta+click`on Mac to open a link in a new window.\n\n#### Example usage\n\n<details>\n<summary>Expand to see an example usage of `ControlOrMeta`</summary>\n\n```js\n  await page.keyboard.down('ControlOrMeta');\n\n  // Open the link in a new tab.\n  // Wait for the new page to be created.\n  const browserContext = browser.context();\n  const [newTab] = await Promise.all([\n    browserContext.waitForEvent('page'),\n    await page.locator('a[href=\"/my_messages.php\"]').click()\n  ]);\n\n  await page.keyboard.up('ControlOrMeta');\n```\n\n</details>\n\n## UX improvements and enhancements\n\n- [browser#1462](https://github.com/grafana/xk6-browser/pull/1462) Enhances `waitForSelector` error message to better reflect why a selector doesn't resolve to an element.\n- [#4028](https://github.com/grafana/k6/pull/4028) Adds support of SigV4 signing for the `experimental-prometheus-rw` output. This allows users to authenticate with AWS services that require SigV4 signing. Thanks, @obanby for the contribution!\n- [#4026](https://github.com/grafana/k6/pull/4026) Allows setting of service.name from the `OTEL_SERVICE_NAME` environment variable for the `experimental-opentelemetry` output. This aligns better with standard OTEL practices. Thanks, @TimotejKovacka for the contribution!\n- [browser#1426](https://github.com/grafana/xk6-browser/issues/1426) Instruments `page.waitForTimeout` with tracing which will allow it to be displayed in the timeline.\n\n## Bug fixes\n\n- [browser#1452](https://github.com/grafana/xk6-browser/pull/1452) Fixes a possible deadlock when working with `page.on`.\n- [browser#1469](https://github.com/grafana/xk6-browser/pull/1469) Fixes `locator.waitFor` so it waits between navigations and doesn't throw an error.\n- [browser#1488](https://github.com/grafana/xk6-browser/pull/1488), [browser#1493](https://github.com/grafana/xk6-browser/pull/1493) Fixes memory leaks.\n- [#4017](https://github.com/grafana/k6/pull/4017) Fixes a bug where k6 would not stop when a test was aborted right after an `await` statement. \n\n## Maintenance and internal improvements\n\n- [browser#1448](https://github.com/grafana/xk6-browser/pull/1448) Updates examples to use the new async `check` helper.\n- [browser#1473](https://github.com/grafana/xk6-browser/pull/1473), [browser#1474](https://github.com/grafana/xk6-browser/pull/1474), [browser#1477](https://github.com/grafana/xk6-browser/pull/1477), [browser#1478](https://github.com/grafana/xk6-browser/pull/1478), [browser#1475](https://github.com/grafana/xk6-browser/pull/1475), [browser#1479](https://github.com/grafana/xk6-browser/pull/1479) Generalizes `page.on` event code to streamline the addition and running of additional events.\n- [browser#1439](https://github.com/grafana/xk6-browser/pull/1439) Updates README to remove outdated information.\n- [browser#1496](https://github.com/grafana/xk6-browser/pull/1496) Adds the `downloadsPath` option to specify the download directory. The browser module doesn't yet respect this option, but it will in the next release.\n- [browser#1447](https://github.com/grafana/xk6-browser/pull/1447) Updates the CDP dependency.\n- [browser#1281](https://github.com/grafana/xk6-browser/issues/1281), [browser#1277](https://github.com/grafana/xk6-browser/issues/1277), [browser#1275](https://github.com/grafana/xk6-browser/issues/1275) Removes Sobek out of business logic layers.\n- [#4037](https://github.com/grafana/k6/pull/4037), [#4043](https://github.com/grafana/k6/pull/4043) Updates recommendation to use `check` polyfill, for the async checks.\n- [#4039](https://github.com/grafana/k6/pull/4039) Updates maintainers in auto-assigner workflow.\n"
  },
  {
    "path": "release notes/v0.55.1.md",
    "content": "k6 `v0.55.1` is here 🎉! This release includes:\n\n- Dependency updates for `golang.org/x/net`.\n\n## Maintenance and internal improvements\n\n- [#4134](https://github.com/grafana/k6/pull/4134) Updates `golang.org/x/net` which contains a fix for CVE-2024-45338.\n"
  },
  {
    "path": "release notes/v0.55.2.md",
    "content": "k6 `v0.55.2` is a patch release that fixes packaging issue.\n\nThere are no functional changes in k6 compared to v0.55.1.\n"
  },
  {
    "path": "release notes/v0.56.0.md",
    "content": "k6 `v0.56.0` is here 🎉! This release includes:\n\n- We've merged xk6-browser into k6.\n- Many small improvements, bug fixes and internal refactors.\n\n## Breaking changes\n\n- [browser#1541](https://github.com/grafana/xk6-browser/pull/1541) Removes `accessibility-events` from a test, which is no longer a valid permission that can be granted by the latest version of Chromium/Chrome.\n- [#4093](https://github.com/grafana/k6/pull/4093) Unexports `lib/consts.FullVersion` from the k6's Golang API.\n\n## New features\n\n### Merge browser code in k6 codebase [#4056](https://github.com/grafana/k6/pull/4056)\n\nWhile the browser module has been stabilized, the codebase was not moved inside of k6.\n\nAs part of the stabilization this is now also merged in the k6 codebase. In the following months we would move issues from the [xk6-browser](https://github.com/grafana/xk6-browser) repo and then archive it.\n\n## UX improvements and enhancements\n\n- [browser#1536](https://github.com/grafana/xk6-browser/pull/1536) Removes `Headless` from the user agent to prevent test traffic from being blocked.\n- [browser#1553](https://github.com/grafana/xk6-browser/pull/1553) Reduces logging noise produced by the browser module.\n- [#4093](https://github.com/grafana/k6/pull/4093) Introduces a `--json` flag to a `k6 version` sub-command, which switches an output to a JSON format.\n- [#4140](https://github.com/grafana/k6/pull/4140) Tags browser module metrics with a `resource_type` tag which can be one of these values: `\"Document\"`, `\"Stylesheet\"`, `\"Image\"`, `\"Media\"`, `\"Font\"`, `\"Script\"`, `\"TextTrack\"`, `\"XHR\"`, `\"Fetch\"`, `\"Prefetch\"`, `\"EventSource\"`, `\"WebSocket\"`, `\"Manifest\"`, `\"SignedExchange\"`, `\"Ping\"`, `\"CSPViolationReport\"`, `\"Preflight\"`, `\"Other\"`, or `\"Unknown\"`.\n- [#4092](https://github.com/grafana/k6/pull/4092) Populates `__ENV.K6_CLOUDRUN_TEST_RUN_ID` with the corresponding value for local executions streaming results to the Cloud: `k6 cloud run --local-execution`.\n\n## Bug fixes\n\n- [browser#1507](https://github.com/grafana/xk6-browser/pull/1507) Fixes the `Geolocation.Accuracy` field.\n- [browser#1515](https://github.com/grafana/xk6-browser/pull/1515) Fixes Sobek `Object.Get(key)` by returning `*[]any` instead of `[]any`.\n- [browser#1534](https://github.com/grafana/xk6-browser/pull/1534) Fixes `locator` APIs to wait during a navigation without erroring out.\n- [browser#1538](https://github.com/grafana/xk6-browser/pull/1538) Fixes `frame.title`.\n- [browser#1542](https://github.com/grafana/xk6-browser/pull/1542) Fixes a panic which can occur when a frame navigates.\n- [browser#1547](https://github.com/grafana/xk6-browser/pull/1547) Fixes a panic due to events associated to stale frames.\n- [browser#1552](https://github.com/grafana/xk6-browser/pull/1552) Fixes a panic for `locator.selectOption` when value is an object.\n- [browser#1559](https://github.com/grafana/xk6-browser/pull/1559) Fixes a panic for `page.screenshot`.\n- [browser#1544](https://github.com/grafana/xk6-browser/pull/1544) Fixes a nil pointer dereference when calling `evaluate` or `evaluateHandle` with an invalid page function.\n- [#4058](https://github.com/grafana/k6/pull/4058) Fixes the namespaced object export when default is the only one available.\n- [#4132](https://github.com/grafana/k6/pull/4132) Returns an error when a page is `null` during the creation of a page.\n\n## Maintenance and internal improvements\n\n- [browser#1504](https://github.com/grafana/xk6-browser/pull/1504), [browser#1510](https://github.com/grafana/xk6-browser/pull/1510), [browser#1511](https://github.com/grafana/xk6-browser/pull/1511) [browser#1512](https://github.com/grafana/xk6-browser/pull/1512) [browser#1513](https://github.com/grafana/xk6-browser/pull/1513), [browser#1518](https://github.com/grafana/xk6-browser/pull/1518), [browser#1519](https://github.com/grafana/xk6-browser/pull/1519), [browser#1520](https://github.com/grafana/xk6-browser/pull/1520), [browser#1523](https://github.com/grafana/xk6-browser/pull/1523), [browser#1521](https://github.com/grafana/xk6-browser/pull/1521), [browser#1524](https://github.com/grafana/xk6-browser/pull/1524), [browser#1526](https://github.com/grafana/xk6-browser/pull/1526), [browser#1527](https://github.com/grafana/xk6-browser/pull/1527), [browser#1531](https://github.com/grafana/xk6-browser/pull/1531)  Removes Sobek out of business logic layers.\n- [browser#1528](https://github.com/grafana/xk6-browser/pull/1528), [browser#1529](https://github.com/grafana/xk6-browser/pull/1529), [browser#1557](https://github.com/grafana/xk6-browser/pull/1557) Aligns repo with k6.\n- [browser#1517](https://github.com/grafana/xk6-browser/pull/1517) Fixes internal tests.\n- [browser#1540](https://github.com/grafana/xk6-browser/pull/1540) Refactors internals.\n- [#4049](https://github.com/grafana/k6/pull/4049), [#4095](https://github.com/grafana/k6/pull/4095), [browser#1535](https://github.com/grafana/xk6-browser/pull/1535), [browser#1537](https://github.com/grafana/xk6-browser/pull/1537), [#4073](https://github.com/grafana/k6/pull/4073), [#4101](https://github.com/grafana/k6/pull/4101), [#4103](https://github.com/grafana/k6/pull/4103), [#4104](https://github.com/grafana/k6/pull/4104), [#4134](https://github.com/grafana/k6/pull/4134), [#4148](https://github.com/grafana/k6/pull/4148) Updates dependencies.\n- [#4057](https://github.com/grafana/k6/pull/4057) Update k6-taskqueue-lib to drop goja dependency.\n- [#4076](https://github.com/grafana/k6/pull/4076) modules.NewModuleInstance doc updates.\n- [#4137](https://github.com/grafana/k6/pull/4137), [#4148](https://github.com/grafana/k6/pull/4148) Updates a dependency and adds release notes.\n- [#4099](https://github.com/grafana/k6/pull/4099), [#4114](https://github.com/grafana/k6/pull/4114) Fixes to CI after browser merge, around running tests on windows.\n- [#4102](https://github.com/grafana/k6/pull/4102) Fix windows-packaging CI after update of the windows github action.\n- [#4047](https://github.com/grafana/k6/pull/4047) Uses `(*Regexp).MatchString` to avoid unnecessary `[]byte` conversions. Thanks, @Juneezee for the contribution.\n- [#4055](https://github.com/grafana/k6/pull/4055) Updates release template.\n- [#4143](https://github.com/grafana/k6/pull/4143) Fix k6packager workflow which also broke v0.55.1 initial release.\n- [#4063](https://github.com/grafana/k6/pull/4063) Updates usage report to return whether k6 was ran from CI.\n- [#4072](https://github.com/grafana/k6/pull/4072) Uses the precompiled 'gotip' on the xk6 workflow.\n- [#4084](https://github.com/grafana/k6/pull/4084) Updates usage report to return usage of the deprecated 'ext.loadimpact' option.\n\n## Roadmap\n\n### Removal of deprecated `k6/experimental/browser` module\n\nSince `v0.52.0` we have had a non experimental version of the browser module (`k6/browser`). We urge you to [migrate](https://grafana.com/docs/k6/latest/using-k6-browser/migrating-to-k6-v0-52/) your scripts over to the non experimental browser module as we will be removing the experimental version of it in the next release (`v0.57.0`).\n\n"
  },
  {
    "path": "release notes/v0.57.0.md",
    "content": "k6 `v0.57.0` is here 🎉! This release includes:\n\n- Introducing helpers for functional testing.\n- The `k6 new` command now supports templates and ProjectIDs.\n- The `k6/experimental/csv` module gets a new `asObjects` option.\n- We no longer support the `k6/experimental/browser` module, in favor of `k6/browser`.\n- Moving most of non-public APIs to the `internal` package.\n\n## Breaking changes\n\n- [#4161](https://github.com/grafana/k6/pull/4161) Drops `k6/experimental/browser`. If you're still using it, follow the [instructions](https://grafana.com/docs/k6/latest/using-k6-browser/migrating-to-k6-v0-52/) to move to the graduated and stable `k6/browser` module.\n- [#4133](https://github.com/grafana/k6/pull/4133) Moves all not publicly used APIs in `internal` package. This was based on the publicly available extensions for k6 and may break private ones. More APIs will likely be removed or updated in follow-up releases after this more mechanical change.\n- [#4292](https://github.com/grafana/k6/pull/4292) TypeScript is automatically supported and recognized if the script files use the `.ts` extension. It also deprecates `experimental_enhanced` compatibility mode as it is no longer necessary.\n\n## New features\n\n### New functional testing focused official jslib [k6-testing](https://github.com/grafana/k6-jslib-testing)\n\nThe k6 team has been developing a new official jslib dedicated to functional testing. While it is still under active development and will potentially see breaking changes, the set of APIs and behaviors it offers are meant to make their way into k6 eventually, and it is now available for early feedback.\n\n[k6-testing](https://github.com/grafana/k6-jslib-testing) is a k6 JavaScript library that offers a seamless way to write functional tests in k6, using a Playwright-compatible assertions API. It exposes an `expect` function, with which assertions can be performed using specific matchers that reflect the expected results.\nUnlike current k6's `check` when `expects` assertions fail, the test will immediately fail with a clear error message, including the expected and actual values in a similar fashion to what users would observe when using Playwright assertions. \n\n[There are many generic matchers](https://github.com/grafana/k6-jslib-testing?tab=readme-ov-file#3-standard-assertions) (and more to come), such as `toEqual`, `toBe`, or `toBeTruthy`, to only name a few, that can be used to assert conditions during a k6 test.\n\n```javascript\nimport { expect } from 'https://jslib.k6.io/k6-testing/0.2.0/index.js';\n\nexport default function () {\n    const response = http.get('https://test.k6.io');\n    expect(response.status).toEqual(200);\n    expect(response.body).toBeTruthy();\n    expect(response.json()).toEqual(JSON.stringify({ message: 'Hello, world!' }));\n}\n```\n\n[k6-jslib-testing](https://github.com/grafana/k6-jslib-testing) also includes browser-specific async matchers that wait until the expected condition is met such as `toBeVisible`, `toBeDisabled`, or `toBeChecked`, to name a few.\n\n```javascript\nimport { expect } from \"https://jslib.k6.io/k6-testing/0.2.0/index.js\";\nimport { browser } from \"k6/browser\";\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: \"shared-iterations\",\n      options: {\n        browser: {\n          type: \"chromium\",\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  try {\n    // Navigate to the page\n    await page.goto(\"https://test.k6.io/my_messages.php\");\n\n    // Type into the login input field: 'testlogin'\n    const loc = await page.locator('input[name=\"login\"]');\n    await loc.type(\"testlogin\");\n\n    // Assert that the login input field is visible\n    await expect(page.locator('input[name=\"login\"]')).toBeVisible();\n\n    // Expecting this to fail as we have typed 'testlogin' into the input instead of 'foo'\n    await expect(page.locator('input[name=\"login\"]')).toHaveValue(\"foo\");\n  } finally {\n    await page.close();\n  }\n}\n```\n\nIt is currently available as part of the [jslib.k6.io](https://jslib.k6.io) repository and is available to use in your k6 tests by adding the following import:\n\n```javascript\nimport { expect } from \"https://jslib.k6.io/k6-testing/0.2.0/index.js\";\n```\n\nTry it out and give us feedback or contribute to the project on the [k6-jslib-testing repository](https://github.com/grafana/k6-jslib-testing)!\n\n### `--template` and `--project-id` flags for `k6 new` command [#4153](https://github.com/grafana/k6/pull/4153)\n\nThe `k6 new` command has been revamped to provide an improved experience when scaffolding new k6 tests. It now supports a `--template` flag with options such as `minimal`, `protocol`, and `browser`, letting you generate a script tailored to your specific use case.\n\nThe command also now accepts a `--project-id` flag, which allows you to easily parameterize the test's Grafana Cloud configuration.\n\n```sh\n# Create a new k6 script using the 'protocol' template\n$ k6 new --template protocol\n\n# Create a Grafana k6 cloud-ready script with a specific project ID\n$ k6 new --project-id 12345\n```\n\n### New `asObjects` option in `k6/experimental/csv` module [#4295](https://github.com/grafana/k6/pull/4295)\n\nThe CSV module's parsing operations now support the `asObjects` option, which enables parsing CSV data into JavaScript objects instead of arrays of strings (the default behavior).\n\nWhen `asObjects` is set to `true`, the module parses CSV data into objects where:\n\n- Column names from the header row become object keys.\n- Column values become the corresponding object values.\n- An error is thrown if no header row exists or if options modify the parsing start point.\n\nWith the option set to `true`,\n\n```js\nimport http from 'k6/http';\nimport csv from 'k6/experimental/csv';\n\nconst csvData = csv.parse('data.csv', { asObjects: true });\n```\n\nthe following CSV file:\n\n```csv\nname,age,city\nJohn,30,New York\nJane,25,Los Angeles\n```\n\nwill be parsed into the following JavaScript objects:\n\n```js\n[\n  { name: 'John', age: '30', city: 'New York' },\n  { name: 'Jane', age: '25', city: 'Los Angeles' },\n]\n```\n\nRefer to the [CSV module's documentation](https://grafana.com/docs/k6/latest/javascript-api/k6-experimental/csv/) for more information.\n\n## UX improvements and enhancements\n\n- [#4176](https://github.com/grafana/k6/pull/4176) Warns on using shorthand options when that override scenarios.\n- [#4293](https://github.com/grafana/k6/pull/4293) Renames browser data directory name prefix from `xk6-browser-data-` to `k6browser-data-`.\n- [#4513](https://github.com/grafana/k6/pull/4513) Adds support for `file` scheme URLs across file loading APIs - `open`, `k6/experimental/fs.open` and `k6/net/grpc.Client#load`.\n- [#4517](https://github.com/grafana/k6/pull/4517) Switches from the legacy examples to quickpizza.grafana.com.\n\n## Bug fixes\n\n- [#4536](https://github.com/grafana/k6/pull/4536), [#4534](https://github.com/grafana/k6/pull/4534), [#4533](https://github.com/grafana/k6/pull/4533), [#4531](https://github.com/grafana/k6/pull/4531), [#4530](https://github.com/grafana/k6/pull/4530), [#4528](https://github.com/grafana/k6/pull/4528), [#4523](https://github.com/grafana/k6/pull/4523), [#4522](https://github.com/grafana/k6/pull/4522), [#4521](https://github.com/grafana/k6/pull/4521) Fix possible data races while using k6 browser's APIs.\n- [#4174](https://github.com/grafana/k6/pull/4174) Fixes an NPD during a click, which could occur when either the load generator or chrome instance is under a lot of load.\n- [#4192](https://github.com/grafana/k6/pull/4192) Fixes a memory leak in general event handling between components.\n- [#4280](https://github.com/grafana/k6/pull/4280) Fixes an NPD by not disposing of the original handle.\n- [#4288](https://github.com/grafana/k6/pull/4288) Cleans up browser download path artifacts after a test run.\n- [#4532](https://github.com/grafana/k6/pull/4532) Fixes `--local-execution` runs by isolating `Archive`'s urls.\n\n## Maintenance and internal improvements\n\n- [#4184](https://github.com/grafana/k6/pull/4184) Fixes some browser Windows tests.\n- [#4131](https://github.com/grafana/k6/pull/4131) Moves experimental WebSocket code into the k6 codebase.\n- [#4143](https://github.com/grafana/k6/pull/4143) Fixes for k6packager workflow building image to do k6 releases.\n- [#4172](https://github.com/grafana/k6/pull/4172) Drops Slack URL from the README.\n- [#4173](https://github.com/grafana/k6/pull/4173) Updates dependencies in gRPC example server.\n- [#4187](https://github.com/grafana/k6/pull/4187) Removes packaging folder from browser module - not needed after it was moved to the k6 codebase.\n- [#4188](https://github.com/grafana/k6/pull/4188), [#4190](https://github.com/grafana/k6/pull/4190) Merge xk6-webcrypto extension code into k6.\n- [#4189](https://github.com/grafana/k6/pull/4189) Uses `modulestest` to make experimental streams test simpler.\n- [#4191](https://github.com/grafana/k6/pull/4191) Removes BaseEventEmitter from components that don't work with it.\n- [#4201](https://github.com/grafana/k6/pull/4201) Tracks more dependencies to dependabot.\n- [#4212](https://github.com/grafana/k6/pull/4212) Fixes gRPC tests after update to golang internal test certificates.\n- [#4213](https://github.com/grafana/k6/pull/4213) Updates k6-taskqueue-lib to v0.1.3.\n- [#4271](https://github.com/grafana/k6/pull/4271) Runs dependabot weekly instead of daily.\n- [#4275](https://github.com/grafana/k6/pull/4275) Fixes the `browser` module working with reused VUs that originally weren't used in browser scenarios.\n- [#4276](https://github.com/grafana/k6/pull/4276) REST API stays on while outputs are flushing, only stopping after that.\n- [#4294](https://github.com/grafana/k6/pull/4294) TestStreamLogsToLogger: increase wait time to get less flakiness.\n- [#4209](https://github.com/grafana/k6/pull/4209), [#4208](https://github.com/grafana/k6/pull/4208), [#4196](https://github.com/grafana/k6/pull/4196), [#4195](https://github.com/grafana/k6/pull/4195), [#4193](https://github.com/grafana/k6/pull/4193), [#4177](https://github.com/grafana/k6/pull/4177), [#4163](https://github.com/grafana/k6/pull/4163), [#4151](https://github.com/grafana/k6/pull/4151), [#4213](https://github.com/grafana/k6/pull/4213) Update direct dependencies.\n- [#4198](https://github.com/grafana/k6/pull/4198) Adds a multiple forward-slash test case. Thanks, @apatruni, for the contribution!\n- [#4504](https://github.com/grafana/k6/pull/4504), [#4506](https://github.com/grafana/k6/pull/4506) Update the golangci-lint version.\n- [#4298](https://github.com/grafana/k6/pull/4298) Adds test coverage for configuration file's operations.\n"
  },
  {
    "path": "release notes/v0.58.0.md",
    "content": "The `v0.58.0` release mirrors the previous `v1.0.0-rc1` release to allow automation tools to recognize it as the latest version.\nFor example, Homebrew's k6 formulae and pkg.go.dev do not automatically fetch unstable versions such as `v1.0.0-rc1`, which is legitimately the expected behavior for these tools.\n\nHowever, this has been the default for all previous `v0.*` releases, where they were considered the latest stable version—even if they were under a version typically associated with unstable releases. To address this, we will continue releasing mirrored versions under `v0.*` for necessary release candidates.\n\nThis practice will end once the official stable `v1.0.0` release is available, after which we will follow the standard SemVer lifecycle to simplify the workflow for everyone.\n\nThe release notes for [v1.0.0-rc1](https://github.com/grafana/k6/releases/v1.0.0-rc1) provide a detailed look at all the changes that have been implemented since `v0.57.0` and are now part of this version.\n"
  },
  {
    "path": "release notes/v0.59.0.md",
    "content": "The `v0.59.0` release mirrors the previous `v1.0.0-rc2` release to allow automation tools to recognize it as the latest version.\nFor example, Homebrew's k6 formulae and pkg.go.dev do not automatically fetch unstable versions such as `v1.0.0-rc2`, which is legitimately the expected behavior for these tools.\n\nHowever, this has been the default for all previous `v0.*` releases, where they were considered the latest stable version—even if they were under a version typically associated with unstable releases. To address this, we will continue releasing mirrored versions under `v0.*` for necessary release candidates.\n\nThis practice will end once the official stable `v1.0.0` release is available, after which we will follow the standard SemVer lifecycle to simplify the workflow for everyone.\n\nThe release notes for [v1.0.0-rc2](https://github.com/grafana/k6/releases/v1.0.0-rc2) provide a detailed look at all the changes that have been implemented since `v1.0.0-rc1`/`v0.58.0` and are now part of this version.\n"
  },
  {
    "path": "release notes/v1.0.0-rc1.md",
    "content": "k6 `v1.0.0-rc1` is here 🎉!\n\nThis release marks a special, non-conventional milestone in the k6 software life-cycle, serving as a preview of the upcoming version 1.0.0.\n\nThe purpose of this release is to give the community a chance to test the new version, identify any potential issues, and test migrations of any parts affected by breaking changes. If you encounter any problems or have trouble with the migration, we encourage you to report them by creating an issue. Your feedback will help improve the final release. If no critical issues are reported, we plan to release the final `v1.0.0` within the next month.\n\nHere’s a glimpse of what’s new in this release:\n\n- `k6/experimental/webcrypto` promoted to stable and available globally under `crypto`.\n- A revamped end-of-test summary aiming to bring an easier way to understand test results.\n- `k6/browser` provided an API for tracking network requests and responses.\n- The new `k6/secrets` module for retrieving secrets with extension support.\n\n## Breaking changes\n\n- [#4541](https://github.com/grafana/k6/pull/4541) Commas(`,`) are now supported in the values of the `--tag` CLI flag. This is a breaking change, as previously, a comma meant the start of a new set of tag-values. As a comma is a valid symbol for the value of a tag, this is necessary to have equivalency between different ways of setting tags. This still allows multiple tags to be set on the CLI with multiple `--tag key=value` arguments.\n\n### A new default path for the configuration file [#4301](https://github.com/grafana/k6/pull/4301)\n\nWhen running the `k6 cloud login` or the deprecated `k6 login` commands, a configuration file was automatically created at `{USER_CONFIG_DIR}/loadimpact/config.json`. Now, the configuration file is created at `{USER_CONFIG_DIR}/k6/config.json`.\n\nTo migrate your configuration file to the new path:\n\n1. Run `k6 cloud login` or `k6 login` to automatically migrate the configuration file to the new location.\n2. Run `k6 cloud run` or `k6 run` to verify that the version is now fully functional and no related warning is emitted.\n\nThe configuration file in the old path remains available and can continue to be used with the previous k6 versions. If you're not using an old version of k6 anymore, consider deleting the files manually.\n\nThe `k6 run` commands search for the configuration file in the new location. If it can't find it, it tries to fall back on the old path and then logs a warning message suggesting to migrate it.\n\n## New features\n\n### A revamped end-of-test summary aiming to bring an easier way to understand test results [#4089](https://github.com/grafana/k6/pull/4089), [#4649](https://github.com/grafana/k6/pull/4649)\n\nThe end-of-test-summary has been revamped to make it easier for users to understand test results. That includes:\n- A new format to summarize the results of the user-defined [Checks](https://grafana.com/docs/k6/latest/using-k6/checks/) and [Thresholds](https://grafana.com/docs/k6/latest/using-k6/thresholds/).\n- Now metrics are split into different sections, making it easier to focus on what really matters.\n\n![End of test summary example](https://github.com/user-attachments/assets/68036748-f7be-45e1-b69a-65fa18c458ee)\n\nThe new end-of-test summary is enabled by default for users, but you can use the `summary-mode` flag to choose between different modes:\n- `compact` *(default)*: what you can see in the example above, with the most relevant information.\n- `full`: similar to `compact`, but also includes some more detailed metrics and results for each [group](https://grafana.com/docs/k6/latest/using-k6/tags-and-groups/#groups) and [scenario](https://grafana.com/docs/k6/latest/using-k6/scenarios/) defined in the test. \n- `legacy`: the old summary format for backward compatibility.\n\n> Note: The data structure received by the [`handleSummary`](https://grafana.com/docs/k6/latest/results-output/end-of-test/custom-summary/) function, \n> as well as the data exported using `--summary-export`, has not changed in this release. However, these may change in upcoming releases, which could introduce breaking changes.\n\n### Browser: Tracking network requests and responses [#4290](https://github.com/grafana/k6/issues/4290), [#4296](https://github.com/grafana/k6/issues/4296)\n\nThe [browser module](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/) adds support for tracking network requests and responses. This feature is especially useful for validating certain aspects of the requests and responses to determine whether the test was successful. It can also be used to debug issues with the test script or the tested application. Refer to the [documentation](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/on/) for more details.\n\nFor example, to track all requests and responses made by a page, you can use the following script:\n\n```javascript\nimport { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  // registers a handler that logs all requests made by the page\n  page.on('request', async request => console.log(request.url()));\n  // registers a handler that logs all responses received by the page\n  page.on('response', async response => console.log(response.url()));\n\n  await page.goto('https://quickpizza.grafana.com/', { waitUntil: 'networkidle' });\n  await page.close();\n}\n```\n\nThe output might look like this:\n\n```bash\nINFO[0000] https://quickpizza.grafana.com/                  source=console\nINFO[0001] https://quickpizza.grafana.com/api/tools         source=console\nINFO[0001] https://quickpizza.grafana.com/images/pizza.png  source=console\n...\n```\n\n### `k6/experimental/webcrypto` promoted to stable and available globally under `crypto` [#4278](https://github.com/grafana/k6/pull/4278)\n\nWith this release, the `k6/experimental/webcrypto` module is promoted to stable and available globally under `crypto`. That means you can remove the `import { crypto } from 'k6/experimental/webcrypto';` statement from your scripts and still use the module. \n\n```javascript\nexport default function () {\n  const myUUID = crypto.randomUUID();\n\n  console.log(myUUID);\n}\n```\n\n`k6/experimental/webcrypto` is deprecated and will be removed in `v1.1.0`.\n\n### Support for custom templates in `k6 new` command [#4618](https://github.com/grafana/k6/pull/4618)\n\nThe `k6 new` command now accepts a path to a file to use as a template for the new script. Templates use [Go templates syntax](https://pkg.go.dev/text/template#pkg-overview) and can include the following variables:\n\n- `ScriptName`: The name of the new script.\n- `ProjectID`: The ID of the Grafana Cloud project to use for the new script.\n\nTo generate a new script using a custom template, use the following command:\n\n```sh\nk6 new --template /path/to/my-template.js\n```\n\n### Secret Sources [#4514](https://github.com/grafana/k6/pull/4514), [#4621](https://github.com/grafana/k6/pull/4621), [#4637](https://github.com/grafana/k6/pull/4637)\n\nWe've added support for retrieving secrets from different sources. Among other things, this means that the values received from a secret source will be redacted from the logs. Refer to the [documentation](https://grafana.com/docs/k6/latest/using-k6/secret-source) for more details.\n\nThe two implementations available are to read secrets from a key-value file or from CLI flags, which are meant mostly to test the feature. We've also included extension support, which can be used to implement retrieving secrets from more secure sources.\n\nIn the future, we'll likely include additional implementations that are more production-ready.\n\nHere's an example where we log the secret directly, make a request, and then log the whole response. In both cases, the secrets are redacted from the logs.\n\n```javascript\nimport http from 'k6/http';\nimport secrets from 'k6/secrets';\n\nexport default async () => {\n  const my_secret = await secrets.get('cool'); // get secret from a source with the provided identifier\n  console.log(my_secret);\n  const response = await http.asyncRequest(\"GET\", \"https://httpbin.org/get\", null, {\n    headers: {\n      \"Custom-Authentication\": `Bearer ${await secrets.get(\"else\")}`,\n    }\n  })\n  console.log(response.body)\n}\n```\n\n```shell\n$ k6 run --secret-source=mock=cool=\"not cool secret\",else=\"totally a secret\" script.js\n...\nINFO[0000] ***SECRET_REDACTED***                         source=console\nINFO[0031] {\n  \"args\": {},\n  \"headers\": {\n    \"Custom-Authentication\": \"Bearer ***SECRET_REDACTED***\",\n    \"Host\": \"httpbin.org\",\n    \"User-Agent\": \"k6/1.0.0-rc1 (https://k6.io/)\",\n    \"X-Amzn-Trace-Id\": \"Root=1-67dd6691-18eeaf5d1782bf292da5037c\"\n  },\n  \"origin\": \"1.1.1.1\",\n  \"url\": \"https://httpbin.org/get\"\n}  source=console\n...\n```\n\n## UX improvements and enhancements\n\n- [#4547](https://github.com/grafana/k6/pull/4547) The k6 banner now outputs with the original TrueColor (24-bit) logo only if the terminal supports it.\n- [#4590](https://github.com/grafana/k6/pull/4590) Moves the `docker-compose` example with InfluxDB to the `examples/docker-compose` directory and adds an opentelemetry example.\n- [#4602](https://github.com/grafana/k6/pull/4602), [#4629](https://github.com/grafana/k6/pull/4629) Improves the error message on options error from script. k6 now will try to print the part of the options that fails as JSON.\n- [#4612](https://github.com/grafana/k6/pull/4612) Updates the link included in the local modules' error message. Thanks, @tanurrra!\n\n## Bug fixes\n\n- [#4544](https://github.com/grafana/k6/pull/4544) Fixes race in `ReadableStream.cancel` and run WPT test with race detection for easier finding of similar problems.\n- [#4567](https://github.com/grafana/k6/pull/4567), [#4558](https://github.com/grafana/k6/pull/4558), [#4574](https://github.com/grafana/k6/pull/4574), [#4610](https://github.com/grafana/k6/pull/4610) Fixes race conditions with the browser module's `ElementHandle`, `Mouse`, `Keyboard`, and `Response`.\n- [#4641](https://github.com/grafana/k6/pull/4641) Fixes JSON marshalling of tagset. Thank you @dvordrova 🙇.\n\n## Maintenance and internal improvements\n\n- [#4519](https://github.com/grafana/k6/pull/4519), [#4562](https://github.com/grafana/k6/pull/4562) Moves the Prometheus remote write, and OpenTelemetry outputs' code to the k6 repository.\n- [#4545](https://github.com/grafana/k6/pull/4545) Tries to stabilize MacOS CI by making browser throttle.js easier to run for it.\n- [#4546](https://github.com/grafana/k6/pull/4546), [#4643](https://github.com/grafana/k6/pull/4643) Reduce flakiness of the test suite.\n- [#4552](https://github.com/grafana/k6/pull/4552) Updates the fallback x509 certificates for CA roots.\n- [#4561](https://github.com/grafana/k6/pull/4561), [#4638](https://github.com/grafana/k6/pull/4638) Update Sobek to fix a bug in `Function.apply`, logical assignment support, array destructuring in exports, better cross-os source map support.\n- [#4563](https://github.com/grafana/k6/pull/4563) Fix `k6/timers` reporting as always being used.\n- [#4603](https://github.com/grafana/k6/pull/4603) Homogenize package docs comment block format.\n- [#4605](https://github.com/grafana/k6/pull/4605) Refactor the code responsible for `lib.RuntimeOptions` loading.\n- [#4606](https://github.com/grafana/k6/pull/4606), [#4604](https://github.com/grafana/k6/pull/4604) Bump k6 to depend on greater or equal Go 1.23 versions, build with 1.24, then use a compatible golangci-lint version. \n- [#4611](https://github.com/grafana/k6/pull/4611) Extract the HDR histogram implementation into a shared package.\n- [#4616](https://github.com/grafana/k6/pull/4616), [#4613](https://github.com/grafana/k6/pull/4613), [#4627](https://github.com/grafana/k6/pull/4627), [#4615](https://github.com/grafana/k6/pull/4615), [#4592](https://github.com/grafana/k6/pull/4592), [#4578](https://github.com/grafana/k6/pull/4578), [#4554](https://github.com/grafana/k6/pull/4554), [#4553](https://github.com/grafana/k6/pull/4553), [#4552](https://github.com/grafana/k6/pull/4552), [#4527](https://github.com/grafana/k6/pull/4527), [#4550](https://github.com/grafana/k6/pull/4550) Update direct dependencies.\n- [#4639](https://github.com/grafana/k6/pull/4639) Pushes the `latest` docker image tag even for `rc` releases.\n"
  },
  {
    "path": "release notes/v1.0.0-rc2.md",
    "content": "k6 `v1.0.0-rc2` is here 🎉!\n\nContinuing our commitment beyond the v1.0.0 release, we are pleased to announce a new release candidate that includes several significant changes:\n\n- Native support for extensions in the Cloud\n- New test failure control with `execution.test.fail`\n\n## New features\n\n### Native support for extensions in the Cloud [#4671](https://github.com/grafana/k6/pull/4671)\n\nThe new Binary Provisioning feature automatically requests and uses custom k6 binaries with the required extensions for your tests. This allows you to run scripts that use extensions without manually rebuilding k6 as it was in the past by depending on tools like `xk6`. The system caches binaries locally for efficiency, and any additional runs with the same dependencies will use the same binary and will run faster.\n\nBinary Provisioning is available for all k6 Cloud users (free and paid plans). It is an experimental feature, it's enabled by opt-in with the feature flag `K6_BINARY_PROVISIONING=true`.\n\nBinary provisioning is a limited set of extensions that are supported, and it's not available for the `k6 run` command that might be added in the future. However, local development is supported with the `k6 cloud --local-execution` command if a cloud token is provided by the canonical login methods.\nCheck out [the documentation](https://grafana.com/docs/grafana-cloud/testing/k6/author-run/use-k6-extensions) for additional details.\n### Test failure control with `execution.test.fail` [#4672](https://github.com/grafana/k6/pull/4672)\n\nThe new [`execution.test.fail`](https://grafana.com/docs/k6/latest/javascript-api/k6-execution/#test-fail) function allows you to explicitly fail a test while letting it continue execution until completion. This gives you more control over test outcomes while still collecting all metrics and completing necessary cleanup tasks.\n\n## UX improvements and enhancements\n\n- [#4698](https://github.com/grafana/k6/pull/4698) Displays threshold values even when are not configured in `summaryTrendStats` option.\n- [#4699](https://github.com/grafana/k6/pull/4699) Drops the link of the legacy k6 website from the user agent.\n\n## Bug fixes\n\n- [#4717](https://github.com/grafana/k6/pull/4717) Safeguards against `pressedKeys` being updated concurrently in the browser module.\n- [#4665](https://github.com/grafana/k6/pull/4665) Prevents race condition between `Ended` & `Interrupted` execution states.\n- [#4677](https://github.com/grafana/k6/pull/4677) Makes `secretsource` also redact `float32` and `float64` values.\n\n## Maintenance and internal improvements\n\n- [#4675](https://github.com/grafana/k6/pull/4675), [#4676](https://github.com/grafana/k6/pull/4676), [#4678](https://github.com/grafana/k6/pull/4678) Move several packages to `internal` as preparations for v1.0.0 stabilization\n- [#4686](https://github.com/grafana/k6/pull/4686) Drops the redundant `NO_COLOR` detection.\n- [#4709](https://github.com/grafana/k6/pull/4709) Fixes JS native objects override to avoid a page under the test from overwriting native JavaScript objects, like `Set` and `Map`.\n- [#4726](https://github.com/grafana/k6/pull/4726) Unifies the internal/cmd.Execute methods.\n- [#4703](https://github.com/grafana/k6/pull/4703) Makes wptTests run without tags or skip if repos not checkout.\n- [#4701](https://github.com/grafana/k6/pull/4701) Fixes WebCrypto errors not propagating from the tests.\n- [#4691](https://github.com/grafana/k6/pull/4691), [#4674](https://github.com/grafana/k6/pull/4674), [#4673](https://github.com/grafana/k6/pull/4673), [#4663](https://github.com/grafana/k6/pull/4663) Bumps the versions for `OpenTelemetry`, `grpc`, `golang/x` and `esbuild` dependencies.\n- [#4691](https://github.com/grafana/k6/pull/4691) Bumps x509roots/fallback dependency for fallback certificates.\n- [#4739](https://github.com/grafana/k6/pull/4739) Removes deprecated `GetLayoutMetrics.VisualViewport` CDP usage.\n"
  },
  {
    "path": "release notes/v1.0.0.md",
    "content": "# Grafana k6 v1.0 is here! 🎉\n\nAfter 9 years of iteration and countless community contributions, we're thrilled to announce **Grafana k6 v1.0**. \n\nWhile many features and capabilities in this release were introduced gradually in previous versions, **k6 v1.0 marks a turning point**: a commitment to stability, formal support guarantees, and transparency in how we evolve and develop the project from here. This milestone is more than a version number; it's about trust, reliability, and empowering you to test confidently.\n\n## Thank you, k6 community! 🌍\n\nThis release wouldn't be possible without you:\n\n- ⭐️ 27000+ GitHub stars.\n- 🧠 9000+ git commits.\n- 🤝 200+ contributors.\n- 🔁 Countless test runs of any scale, in every timezone.\n\nIt's been amazing to watch k6 grow from a simple load testing command-line tool into a comprehensive reliability tool, used by teams worldwide and supported by a passionate and dedicated community.\n\nTo everyone who filed bugs, built extensions and libraries, or championed k6:️\n**Thank you!** You've shaped what k6 is today. 🙇‍♂️\n\n## What's New in k6 1.0?\n\n### 1. Stability You Can Build On\n\n- ✅ **Semantic Versioning**: k6 now follows [Semantic Versioning 2.0](https://semver.org/). Breaking changes will only happen in major releases, with prior deprecation warnings.\n- 🔒 **2-Year Support Guarantees**: Every major version will be supported with critical fixes for **at least two years**; upgrade on your schedule.\n- 📦 **Public API Surface**: We've established a clearly delineated and supported API surface for the k6 codebase. Extensions, integrations, and projects building on top of the k6 code now have a stable foundation to rely on.\n\n🔎 Read more in our [versioning and stability guarantees](https://grafana.com/docs/k6/latest/reference/versioning-and-stability-guarantees/) guide.\n\n### 2. First-Class TypeScript Support\n\nWrite type-safe and maintainable tests—no transpilation needed. Simply save your file with a `.ts` extension and run it directly using `k6 run script.ts`.\n\n```typescript\nimport http from 'k6/http';  \n\n// PizzaRequest defines the request body format the quickpizza API expects\nexport interface PizzaRequest {\n    maxCaloriesPerSlice: number;\n    mustBeVegetarian: boolean;\n}\n\nexport default function () {  \n    const payload: PizzaRequest = {\n        maxCaloriesPerSlice: 500, // Type-checked!  \n        mustBeVegetarian: true,\n    }\n\n  http.post(\n    'https://quickpizza.grafana.com/api/pizza',\n    JSON.stringify(payload),\n    { \n        headers: { \n          \"Content-Type\": \"application/json\",\n          \"Authorization\": \"Token \" + \"abcdef0123456789\"\n        } as Record<string, string>\n    });  \n}  \n```\n\n### 3. Extensions Made Simple\n\nWith k6 v1.0, extensions now work out of the box in `k6 cloud run` and `k6 cloud run --local-execution`. Support for `k6 run` is coming soon.\n\n✅ No more xk6 toolchain.\n✅ No manual builds.\n✅ Import an extension's module and go.\n\n```javascript\nimport faker from 'k6/x/faker';\n\nexport default function () {\n  console.log(faker.person.firstName());\n}\n```\n\nTo try the experimental feature, first enable its feature flag, then run it on Grafana Cloud with the following command:\n\n```bash\nK6_BINARY_PROVISIONING=true k6 cloud run script.js,\n```\n\nor if you want to run it locally and stream the results to Grafana Cloud then use:\n\n```bash\nK6_BINARY_PROVISIONING=true k6 cloud run --local-execution script.js\n```\n\n### 4. Revamped test summary\n\nThe new end-of-test summary makes it easier to **understand results and spot issues**:\n\n* 📊 **Hierarchical output**: Metrics are grouped by scenario, group, and category.\n* ✅ **Improved thresholds & checks**: Clearer layout for faster debugging.\n* 🔍 **Multiple summary modes**:\n  * `compact` (default): big picture results, focusing on essentials.\n  * `full`: full picture results, providing granularity.\n \n```\nk6 run --summary-mode=full script.ts\n```\n\n![end-of-test-summary](https://github.com/user-attachments/assets/02984ff9-6ed2-4eb2-9637-daf5058f2de6)\n\n### 5. Quality of Life Upgrades\n\n- Stable modules: `k6/browser`, `k6/net/grpc`, and `k6/crypto` are now production-ready.\n- Improved Grafana Cloud integration: Stream local test results to Grafana Cloud with `k6 cloud run --local-execution`.\n"
  },
  {
    "path": "release notes/v1.1.0.md",
    "content": "k6 `v1.1.0` is here 🎉! This release includes:\n\n- New `count`, `nth`, `first`, and `last` methods for the browser module's Locator API [#4797](https://github.com/grafana/k6/pull/4797), [#4825](https://github.com/grafana/k6/pull/4825)\n- The `k6/experimental/webcrypto` module has been removed as its functionality is available globally.\n- Group results in the `full` end-of-test summary are now sorted as in code and properly indented.\n\n## Breaking changes\n\n*As per our [stability guarantees](https://grafana.com/docs/k6/latest/reference/versioning-and-stability-guarantees/),\nbreaking changes across minor releases are allowed only for experimental features.*\n\n### Breaking changes for experimental modules\n\n#### Remove experimental `k6/experimental/webcrypto` module [#4851](https://github.com/grafana/k6/pull/4851)\n\nThe [WebCrypto API](https://grafana.com/docs/k6/latest/javascript-api/crypto/) has been available globally since `v1.0.0-rc1` (or `v0.58.0`), and now the experimental import (`k6/experimental/webcrypto`) is no longer available.\n\nThe required change for users is to remove the `import`; the rest of the code should work.\n\n## New features\n\n### New `count` method for the browser module's Locator API [#4797](https://github.com/grafana/k6/pull/4797)\n\nThe new `locator.Count` method returns the number of elements matching the `locator`. Unlike other Locator API methods, `locator.Count` returns the result immediately and doesn't wait for the elements to be visible.\n\n```javascript\nimport { expect } from \"https://jslib.k6.io/k6-testing/0.4.0/index.js\";\nimport { browser } from 'k6/browser'\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function () {\n  const page = await browser.newPage()\n  await page.goto('https://quickpizza.grafana.com/login')\n\n  expect(await page.locator('input').count()).toEqual(3);\n\n  await page.close();\n}\n```\n\n### New `nth`, `first` and `last` methods for the browser module's Locator API [#4825](https://github.com/grafana/k6/pull/4825)\n\nThe new Locator API methods, `nth`, `first`, and `last`, can select a single element from multiple elements matched by a `locator`. For example, selecting a single item from a catalogue of items on an e-commerce website. Because items in this catalogue generally change often and selecting an exact element may fail in future test runs, the new methods help to prevent flaky tests, leading to more reliable tests.\n\n```javascript\nimport { expect } from \"https://jslib.k6.io/k6-testing/0.4.0/index.js\";\nimport { browser } from 'k6/browser'\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n}\n\nexport default async function () {\n  const page = await browser.newPage()\n  await page.goto('https://quickpizza.grafana.com')\n\n  await expect(await page.locator('p').first()).toContainText('QuickPizza');\n  await expect(await page.locator('p').nth(4)).toContainText('QuickPizza Labs.');\n  await expect(await page.locator('p').last()).toContainText('Contribute to QuickPizza');\n\n  await page.close();\n}\n```\n\n## UX improvements and enhancements\n\n- [#4807](https://github.com/grafana/k6/pull/4807) Sorts `full` end-of-test summary group results as in code and fixes the indentation. Thanks, @the-it, for the contribution! \n- [#4832](https://github.com/grafana/k6/pull/4832) Uses consistent error messages in the execution config options.\n\n## Bug fixes\n\n- [#4794](https://github.com/grafana/k6/pull/4794) Fixes race conditions from stringifying types in `k6/browser`.\n- [#4809](https://github.com/grafana/k6/pull/4809) Fixes the `locator.fill` method when used on react based websites.\n- [#4831](https://github.com/grafana/k6/pull/4831) Fixes the Dockerfile for k8s use by setting the user to `12345` instead of `k6` to avoid having to work with `runAsUser` in the pod manifest file.\n- [#4845](https://github.com/grafana/k6/pull/4845) Fixes an infrequent panic when `click` is called.\n\n## Maintenance and internal improvements\n\n- [#4608](https://github.com/grafana/k6/pull/4608) Enables the 'copyloopvar' linter.\n- [#4744](https://github.com/grafana/k6/pull/4744) Updates the 'golangci-lint' linter to v2.\n- [#4746](https://github.com/grafana/k6/pull/4746) Adds a collection of small `k6/browser` performance improvements.\n- [#4750](https://github.com/grafana/k6/pull/4750) Fixes the lint GHA.\n- [#4775](https://github.com/grafana/k6/pull/4775) Updates the version of the golangci-lint GHA.\n- [#4784](https://github.com/grafana/k6/pull/4784) Fixes the golangci-lint version detection and execution. Thanks, @tbourrely, for the contribution!\n- [#4785](https://github.com/grafana/k6/pull/4785) Updates the `chromedp/cdproto` dependency and adjusts the Browser module accordingly.\n- [#4800](https://github.com/grafana/k6/pull/4800) Allows un/marshaling of invalid UTF-8 when using JSONv2 within the Browser module. \n- [#4802](https://github.com/grafana/k6/pull/4802) Fixes the `examples/grpc_server` and updates its dependencies. \n- [#4822](https://github.com/grafana/k6/pull/4822) Uses the `CODECOV_TOKEN` variable for GH Workflows from Vault.\n- [#4831](https://github.com/grafana/k6/pull/4831) Fixes the default user defined in the Dockerfile.\n- [#4833](https://github.com/grafana/k6/pull/4833) Retrieves secrets from Vault and adjusts the 'k6packager' deployment process.\n- [#4837](https://github.com/grafana/k6/pull/4837), [#4847](https://github.com/grafana/k6/pull/4847) Prevent Codecov from running on forks.\n- [#4848](https://github.com/grafana/k6/pull/4848) Enables CI pipelines to be executed also on ARM (`ubuntu-24.04-arm`). Thanks, @nadiamoe, for the contribution!\n- [#4855](https://github.com/grafana/k6/pull/4855) Adds some changes to make Browser tests more stable.\n- [#4780](https://github.com/grafana/k6/pull/4780), [#4781](https://github.com/grafana/k6/pull/4781), [#4782](https://github.com/grafana/k6/pull/4782), [#4786](https://github.com/grafana/k6/pull/4786), [#4798](https://github.com/grafana/k6/pull/4798), [#4816](https://github.com/grafana/k6/pull/4816), [#4821](https://github.com/grafana/k6/pull/4821), [#4835](https://github.com/grafana/k6/pull/4835), [#4840](https://github.com/grafana/k6/pull/4840) Update direct dependencies.\n- [#4864](https://github.com/grafana/k6/pull/4864) Updates the logging to debug and adds more context to it when waiting for an element to be detached.\n\n## Roadmap\n\n### Official Testing/Assertions Module\nWe're working to integrate a built-in testing and assertions module that's compatible with Playwright's in k6. You can try the current implementation using the [k6 testing jslib](https://github.com/grafana/k6-jslib-testing), which serves as our work-in-progress implementation for what will become the official `k6/test` module (final name TBD). We'd love your feedback on issue [#4805](https://github.com/grafana/k6/issues/4805).\n\n### Enhanced Machine-Readable Test Results\n\nWe're developing the next version of k6's end-of-test summary to make it easier to integrate test results into CI/CD pipelines and automated workflows. This new format will be officially supported, versioned, and designed specifically for programmatic use. Follow our progress, and provide us with feedback on issue [#4803](https://github.com/grafana/k6/issues/4803)."
  },
  {
    "path": "release notes/v1.2.0.md",
    "content": "k6 v1.2.0 is here 🎉! This release includes:\n\n- Automatic extension resolution (previously Binary Provisioning) enabled for everyone\n- gRPC gets better handling of `NaN` and `Infinity` float values and easier health check\n- Browser module gets `page.route`, all the `page.getBy*` APIs, `locator.all()`, and `page.waitForURL`\n\n## Breaking changes\n\nAs per our [stability guarantees](https://grafana.com/docs/k6/latest/reference/versioning-and-stability-guarantees/),\nbreaking changes across minor releases are allowed only for experimental features.\n\n### Breaking changes for experimental modules\n\n- The experimental Open Telemetry and Prometheus outputs now default to TLSv1.3. This should've been the default to begin with. It is not expected that anyone should be affected, apart from making it more secure for the metrics output to send messages.\n\n## New features\n\n### Automatic extension resolution\n\nk6 extensions allow you to add custom functionality to your tests, such as connecting to databases, message queues, or specialized networking protocols. Previously, using extensions [required manual building](https://grafana.com/docs/k6/latest/extensions/run/build-k6-binary-using-go) of a custom k6 binary with the extensions compiled in. This new version introduces the _Automatic Extension Resolution_ functionality, previously named Binary Provisioning, which is enabled by default and automatically detects when your script imports extensions and handles the complexity of provisioning the right k6 binary for you.\n\n```javascript\nimport faker from \"k6/x/faker\";\n\nexport default function () {\n  console.log(faker.person.firstName());\n}\n```\n\nThe previous experimental versions only supported official extensions. [#4922](https://github.com/grafana/k6/pull/4922) added the support to use any extension listed in the [community list](https://grafana.com/docs/k6/latest/extensions/explore/) by setting the `K6_ENABLE_COMMUNITY_EXTENSIONS` environment variable.\n\n```\nK6_ENABLE_COMMUNITY_EXTENSIONS=true k6 run script.js\n```\n\nNote, Community extensions are only supported for local test executions (using `k6 run` or `k6 cloud run --local-execution`). When running tests on Grafana Cloud k6, only official extensions are allowed.\n\nCheck out the new [extensions documentation](https://grafana.com/docs/k6/latest/extensions/) for additional details.\n\n### Handling of NaN and Infinity float values in gRPC [#4631](https://github.com/grafana/k6/pull/4631)\n\nPreviously, float values of `NaN` or `Infinity` were marshalled as `null`. This has now changed to use their string representation, aligning with other gRPC APIs.\n\nThere are no changes required in the scripts.\n\nThis is also the first contribution by @ariasmn. Thank you @ariasmn for taking the time to make the PR and answer all our questions.\n\n### Health check for gRPC APIs [#4853](https://github.com/grafana/k6/pull/4853)\n\nThe k6 gRPC module now has a `client.healthCheck()` method that simplifies checking the status of a gRPC service. This method eliminates the need for manual `invoke` calls, making it particularly useful for readiness checks and service discovery.\n\nBefore, you had to write boilerplate code to perform a health check:\n```javascript\nimport grpc from 'k6/grpc';\n\nconst client = new grpc.Client();\n// ...\nconst response = client.invoke('grpc.health.v1.Health/Check', { service: 'my-service' });\n```\n\nNow, you can simplify this with the `healthCheck()` method:\n```javascript\nimport grpc from 'k6/grpc';\n\nconst client = new grpc.Client();\nclient.connect('grpc.test.k6.io:443');\n\n// Check the health of a specific service\nconst response = client.healthCheck('my-service');\n\n// Check the health of the overall gRPC server\nconst overallResponse = client.healthCheck();\n\nclient.close();\n```\n\nCheck out the [client.healthCheck](https://grafana.com/docs/k6/latest/using-k6/protocols/grpc/#health-checking-protocol) documentation for additional details.\nThank you, @tbourrely, for contributing this feature.\n\n### Assertions Library (Preview) [#4067](https://github.com/grafana/k6/issues/4067)\n\nk6 now provides an [assertions](https://grafana.com/docs/k6/latest/using-k6/assertions) library to help you verify your application behaves as expected during testing.\n\nThe library introduces the [`expect`](https://grafana.com/docs/k6/latest/javascript-api/jslib/testing/expect) function with a set of expressive matchers. Pass a value to [`expect()`](https://grafana.com/docs/k6/latest/javascript-api/jslib/testing/expect) and chain it with a matcher that defines the expected outcome. The library caters to both protocol testing [HTTP/API](https://grafana.com/docs/k6/latest/using-k6/protocols) and [browser](https://grafana.com/docs/k6/latest/using-k6-browser) testing scenarios.\n\nThe API is inspired by Playwright's assertion syntax, offering a fluent interface for more readable and reliable tests.\n\n```javascript\nimport { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';\nimport { browser } from 'k6/browser';\nimport http from 'k6/http';\n\nexport function protocolTest() {\n  // Get the home page of k6's Quick Pizza app\n  const response = http.get('https://quickpizza.grafana.com/');\n\n  // Simple assertions\n  expect(response.status).toBe(200);\n  expect(response.error).toEqual('');\n  expect(response.body).toBeDefined();\n}\n\nexport async function browserTest() {\n  const page = await browser.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/');\n\n    // Assert the \"Pizza Please\" button is visible\n    await expect(page.locator('button[name=pizza-please]')).toBeVisible();\n  } finally {\n    await page.close();\n  }\n}\n\nexport const options = {\n  scenarios: {\n    // Protocol tests\n    protocol: {\n      executor: 'shared-iterations',\n      vus: 1,\n      iterations: 1,\n      exec: 'protocolTest',\n    },\n\n    // Browser tests\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n      exec: 'browserTest',\n    },\n  },\n};\n```\n\n#### Preview feature\n\nThis feature is ready to use, but still in preview:\n* No breaking changes are neither planned, nor expected.\n* Some functionality may be missing or rough around the edges.\n* We expect to keep adding matchers and improving coverage.\n\nWe welcome your feedback, and invite you to share your suggestions and contributions on [GitHub](https://github.com/grafana/k6-jslib-testing).\n\n### Add `page.getByRole` API [#4843](https://github.com/grafana/k6/pull/4843)\n\nThe browser module now supports `page.getByRole()`, which allows you to locate elements based on their [ARIA roles](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles). This provides a more semantic and accessible way to find elements, making your tests more robust and aligned with how users actually interact with web applications.\n\nARIA roles represent the purpose or function of an element (like button, link, textbox, etc.), making them excellent selectors for testing since they're less likely to change when the UI is refactored compared to CSS classes or IDs.\n\nExample usage:\n```javascript\n// Find elements by role\nawait page.getByRole('button').click();\n\n// Find elements by role and accessible name\nawait page.getByRole('button', { name: 'Submit' }).click();\n\n// `name` works with regex too\nawait page.getByRole('textbox', { name: /^Username$/ }).fill('admin');\n\n// Work with specific states\nawait page.getByRole('checkbox', { name: 'Accept terms', checked: true }).click();\n\n// Find headings by level\nawait page.getByRole('heading', { level: 2, name: 'Section Title' }).textContent();\n\n### Add `page.getByAltText` [#4881](https://github.com/grafana/k6/pull/4881)\n\nThe browser module now includes `page.getByAltText()`, which provides a convenient way to select elements that have an `alt` text attribute. This is particularly useful for locating images or other elements that rely on alternative text for accessibility.\n\nPreviously, you would have to use CSS or XPath selectors to find these elements:\n```javascript\n// Using CSS selector\nconst locator = page.locator('img[alt=\"World Map\"]');\n\n// Using XPath selector\nconst locator = page.locator('//img[@alt=\"World Map\"]');\n```\n\nNow, you can simplify this by using `getByAltText()`:\n```javascript\nconst locator = page.getByAltText('World Map');\n\n// Find an image with alt text that starts with 'World'\nconst locator = page.getByAltText(/^World/);\n```\n\n### Add `page.getByLabel` [#4890](https://github.com/grafana/k6/pull/4890)\n\nThe browser module now includes `page.getByLabel()`, which provides a convenient way to locate form elements and other interactive components by their associated label text. This method works with both explicit `<label>` elements and elements that have an `aria-label` attribute, making it particularly useful for finding form inputs, buttons, and other interactive elements.\n\nPreviously, you would need to use XPath selectors to find elements by their label text, since CSS selectors cannot easily handle the relationship between labels and form elements:\n\n```javascript\n// Using XPath to find input by label text  \nconst locator = page.locator('//label[text()=\"Password\"]');\n\n// Or using aria-label with CSS\nconst locator = page.locator('[aria-label=\"Username\"]');\n```\n\nNow, you can simplify this with `getByLabel()`:\n\n```javascript\n// Works with both <label> elements and aria-label attributes\nconst passwordInput = page.getByLabel('Password');\n\n// Works with regex too\nconst usernameInput = page.getByLabel(/^Username$/);\n```\n\n### Add `page.getByPlaceholder` [#4904](https://github.com/grafana/k6/pull/4904)\n\nThe browser module now includes `page.getByPlaceholder()`, which provides a convenient way to locate form elements by their placeholder text. This is particularly useful for finding input fields, textareas, and other form controls that use placeholder text to guide user input.\n\nPreviously, you would need to use CSS or XPath selectors to find elements by their placeholder attribute:\n\n```javascript\n// Using CSS selector\nconst locator = page.locator('input[placeholder=\"Enter your name\"]');\n\n// Using XPath selector  \nconst locator = page.locator('//input[@placeholder=\"Enter your name\"]');\n```\n\nNow, you can simplify this with `getByPlaceholder()`:\n\n```javascript\nconst nameInput = page.getByPlaceholder('Enter your name');\n\n// Works with regex too\nconst emailInput = page.getByPlaceholder(/^Email/);\n```\n\n### Add `page.getByTitle` [#4910](https://github.com/grafana/k6/pull/4910)\n\nThe browser module now includes `page.getByTitle()`, which provides a convenient way to locate elements by their `title` attribute. This is particularly useful for finding tooltips, buttons, or any other elements that use the `title` attribute to provide extra information.\n\nPreviously, you would need to use CSS or XPath selectors to find these elements:\n\n```javascript\n// Using CSS selector\nconst locator = page.locator('div[title=\"Information box\"]');\n\n// Using XPath selector\nconst locator = page.locator('//div[@title=\"Information box\"]');\n```\n\nNow, you can simplify this with `getByTitle()`:\n\n```javascript\nconst infoBox = page.getByTitle('Information box');\n\n// Works with regex too\nconst saveButton = page.getByTitle(/^Save/);\n```\n\n### Add `page.getByTestId` [#4911](https://github.com/grafana/k6/pull/4911)\n\nThe browser module now includes `page.getByTestId()`, which provides a convenient way to locate elements by their `data-testid` attribute. This is particularly useful for creating resilient tests that are not affected by changes to the UI, since `data-testid` attributes are specifically added for testing purposes and are not expected to change.\n\nPreviously, you would need to use CSS or XPath selectors to find these elements:\n\n```javascript\n// Using CSS selector\nconst locator = page.locator('button[data-testid=\"submit-button\"]');\n\n// Using XPath selector\nconst locator = page.locator('//button[@data-testid=\"submit-button\"]');\n```\n\nNow, you can simplify this with `getByTestId()`:\n\n```javascript\nconst submitButton = page.getByTestId('submit-button');\n\n// Works with regex too\nconst usernameInput = page.getByTestId(/^username/);\n```\n\n### Add `page.getByText` [#4912](https://github.com/grafana/k6/pull/4912)\n\nThe browser module now includes `page.getByText()`, which allows you to locate elements by their text content. This provides a convenient way to find elements like buttons, links, and other interactive components that are identified by their visible text.\n\nPreviously, you would need to use XPath selectors to find elements by their text content, since CSS selectors cannot directly query the text of an element:\n\n```javascript\n// Using XPath selector\nconst locator = page.locator('//div[text()=\"Hello World\"]');\n```\n\nNow, you can simplify this with `getByText()`:\n\n```javascript\nconst helloWorldElement = page.getByText('Hello World');\n\n// Works with regex too\nconst submitButton = page.getByText(/^Submit/);\n```\n\n### Add `page.route` [#4953](https://github.com/grafana/k6/pull/4953) [#4961](https://github.com/grafana/k6/pull/4961), [#4971](https://github.com/grafana/k6/pull/4971), [#4985](https://github.com/grafana/k6/pull/4985)\n\nThe browser module now supports `page.route()`, which allows you to intercept and handle network requests before they are sent. This is particularly useful for testing scenarios where you need to mock API responses, block certain resources, or modify request behavior.\n\nThe route handler receives a `route` object that provides methods to `abort()`, `continue()`, or `fulfill()` the request.\n\nYou can use `page.route()` to:\n- **Block requests**: Prevent certain resources from loading (e.g., images, ads, analytics) with `abort()`.\n    ```javascript\n    // Block all image requests\n    await page.route(/(\\.png$)|(\\.jpg$)|(\\.jpeg$)/, async (route) => {\n        await route.abort();\n    });\n    ```\n- **Mock responses**: Return custom responses without hitting real endpoints with `fulfill()`.\n    ```javascript\n    // Mock API responses\n    await page.route('**/api/users', async (route) => {\n        await route.fulfill({\n            status: 200,\n            contentType: 'application/json',\n            body: JSON.stringify([{ id: 1, name: 'Mock User' }])\n        });\n    });\n    ```\n- **Modify requests**: Change headers, URL, or request body before they're sent with `continue()`.\n    ```javascript\n    // Continue with modified headers\n    await page.route('**/api/**', async (route) => {\n        await route.continue({\n            headers: {\n            ...route.request().headers(),\n            'Authorization': 'Bearer mock-token'\n            }\n        });\n    });\n    ```\n\n### Add `locator.all()` [#4899](https://github.com/grafana/k6/pull/4899)\n\nThe browser module now supports the `locator.all()` method, which returns an array of locators for all elements matching the selector. This is particularly useful when you need to interact with multiple similar elements on a page, such as items in a list or multiple buttons with the same styling.\n\nExample usage:\n```javascript\n// Get all list items and iterate through them\nconst items = await page.locator('li').all();\nfor (const item of items) {\n  console.log(await item.textContent());\n}\n```\n\n### Add `waitForURL` in `frame` and `page` [#4917](https://github.com/grafana/k6/pull/4917), [#4920](https://github.com/grafana/k6/pull/4920)\n\nThe browser module now includes the `waitForURL` method for both `page` and `frame` objects.\n\nAs a prerequiste to this enhancement, `waitForNavigation` now accepts a `url` option. This also allows you to wait for a specific URL during navigation. **It is advised that you work with `waitForURL` instead**.\n\nThe `waitForURL` method first checks if the current page URL already matches the expected pattern. If it does, it waits for the load state to complete. Otherwise, it waits for a navigation to the specified URL. This approach prevents race conditions where a page might complete navigation before the wait condition is set up, which is particularly useful when dealing with pages that perform multiple redirects. It supports both string patterns and regular expressions:\n\n```javascript\n// Wait for navigation to a specific URL\nawait Promise.all([\n  page.waitForURL('https://quickpizza.grafana.com/my_messages.php'),\n  page.locator('a[href=\"/my_messages.php\"]').click(),\n]);\n\n// Using regex pattern\nawait Promise.all([\n  page.waitForURL(/.*\\/contacts\\.php.*/),\n  page.locator('a[href^=\"/contacts.php\"]').click()\n]);\n```\n\nWhile `waitForURL` provides a convenient way to wait for specific URLs, we still recommend using element-based waiting strategies or the locator API with its built-in auto-waiting capabilities for more reliable tests.\n\n## UX improvements and enhancements\n\n- [#4878](https://github.com/grafana/k6/pull/4878) Do not report NaN percentages when there are no checks in the end of test summary. Thank you @Fernando-hub527 for the fix.\n- [#4897](https://github.com/grafana/k6/pull/4897) Support string-labels in `locator.selectOption` in the browser module.\n- [#4898](https://github.com/grafana/k6/pull/4898) Add support for `authority` pseudo header to the gRPC module. Thank you @Oursin for the changes.\n- [#4916](https://github.com/grafana/k6/pull/4916) Print errors more consistently and correctly.\n- [#4918](https://github.com/grafana/k6/pull/4918) Surface navigation errors from navigation events in the browser module.\n- [#4919](https://github.com/grafana/k6/pull/4919) `page.url()` now doesn't make a call to the browser but instead uses a cached version. Making it a lot faster and aligned with playwright.\n- [#4932](https://github.com/grafana/k6/pull/4932) Making it more clear that the requests were aborted in the browser module.\n- [#4944](https://github.com/grafana/k6/pull/4944) Add Prometheus metrics endpoint. Thank you @gouthamve.\n- [#5040](https://github.com/grafana/k6/pull/5040) Use new `expect()` syntax in script templates.\n- [#4976](https://github.com/grafana/k6/pull/4976) Align metrics in end of test summary with using less dots and less horizontal space.\n\n## Bug fixes\n\n- [#4850](https://github.com/grafana/k6/pull/4850) Fixes incorrect conversions between integer types in the browser module.\n- [#4973](https://github.com/grafana/k6/pull/4973) Fixes panic when `BrowserContext` is requested before creating a `Page` in the browser module.\n- [#4975](https://github.com/grafana/k6/pull/4975) Fixes potential race conditions in the browser module.\n- [#5015](https://github.com/grafana/k6/pull/5015) Fixes `waitForNavigation` now blocking the iteration from ending if `page.close` is not called.\n- [#5017](https://github.com/grafana/k6/pull/5017) Fixes potential race conditions in gRPC module, when it gets protobuf defintions from remote server.\n\n## Maintenance and internal improvements\n\n- [#4666](https://github.com/grafana/k6/pull/4666) Lowers the log level on some cloud output logs that were too noisy.\n- [#4879](https://github.com/grafana/k6/pull/4879), [#4945](https://github.com/grafana/k6/pull/4945) Updates of software used by the internal k6packager that packages k6.\n- [#4886](https://github.com/grafana/k6/pull/4886) Prevents running Winsign for public forks to avoid failing and wasting CI time.\n- [#4892](https://github.com/grafana/k6/pull/4892), [#4901](https://github.com/grafana/k6/pull/4901), [#4909](https://github.com/grafana/k6/pull/4909), [#4927](https://github.com/grafana/k6/pull/4927), [#4928](https://github.com/grafana/k6/pull/4928), [#4929](https://github.com/grafana/k6/pull/4929), [#4939](https://github.com/grafana/k6/pull/4939), [#4954](https://github.com/grafana/k6/pull/4954), [#4965](https://github.com/grafana/k6/pull/4965), [#4977](https://github.com/grafana/k6/pull/4977), [#5000](https://github.com/grafana/k6/pull/5000), [#5001](https://github.com/grafana/k6/pull/5001), [#5041](https://github.com/grafana/k6/pull/5041), [#5043](https://github.com/grafana/k6/pull/5043) Updates dependencies.\n- [#4925](https://github.com/grafana/k6/pull/4925) Configures Dependabot to update all OTel dependencies.\n- [#4914](https://github.com/grafana/k6/pull/4914), [#4967](https://github.com/grafana/k6/pull/4967), [#4974](https://github.com/grafana/k6/pull/4974), [#4990](https://github.com/grafana/k6/pull/4990), [#4991](https://github.com/grafana/k6/pull/4991), [#5007](https://github.com/grafana/k6/pull/5007), [#5008](https://github.com/grafana/k6/pull/5008) PRs trying to get the CI tests to be more stable.\n- [#4923](https://github.com/grafana/k6/pull/4923) Mention k6 studio in the readme for more visibility.\n- [#4931](https://github.com/grafana/k6/pull/4931) Lower the debug log on internal implementation detail error.\n- [#4943](https://github.com/grafana/k6/pull/4943), [#4946](https://github.com/grafana/k6/pull/4946), [#4948](https://github.com/grafana/k6/pull/4948) Fix the CI not checking generated files and pinning versions.\n- [#4949](https://github.com/grafana/k6/pull/4949) Updates to Linux Alpine 3.22 for building the k6 docker image.\n- [#4950](https://github.com/grafana/k6/pull/4950) Adds Dependabot rule to update the main Dockerfile dependencies.\n- [#4958](https://github.com/grafana/k6/pull/4958) Passes k6's file system to k6deps (for automatic extension resolution).\n- [#4959](https://github.com/grafana/k6/pull/4959) Copies Zizmor configuration in the repository to make it work for forks.\n- [#4960](https://github.com/grafana/k6/pull/4960) Reduces `waitForNavigation` complexity.\n- [#4969](https://github.com/grafana/k6/pull/4969), [#4986](https://github.com/grafana/k6/pull/4986) Updates around semgrep scanning for security issues.\n- [#4994](https://github.com/grafana/k6/pull/4994) Configures Dependabot to update dependencies in Github actions.\n- [#4996](https://github.com/grafana/k6/pull/4996), [#4997](https://github.com/grafana/k6/pull/4997), [#4998](https://github.com/grafana/k6/pull/4998) Updates to github actions dependancies.\n- [#5014](https://github.com/grafana/k6/pull/5014) Adds a test for running tests with the automatic extension resolution disabled.\n- [#5016](https://github.com/grafana/k6/pull/5016) Fix internal/cmd/tests with automatic extension resolution enabled.\n- [#5020](https://github.com/grafana/k6/pull/5020) Fix examples with browser using the wrong endpoints.\n"
  },
  {
    "path": "release notes/v1.2.1.md",
    "content": "k6 v1.2.1 is here 🎉! This release includes:\n\n- Automatic extension resolution (previously Binary Provisioning) enabled for everyone\n- gRPC gets better handling of `NaN` and `Infinity` float values and easier health check\n- Browser module gets `page.route`, all the `page.getBy*` APIs, `locator.all()`, and `page.waitForURL`\n\nNote: An old xk6-browser repo v1.2.0 tag was pushed by mistake. It was left over on the machine since the merging of the two repos. As such it can not be used as a go module or installed with `go install`. For this reason v1.2.1 is released.\n\n## Breaking changes\n\nAs per our [stability guarantees](https://grafana.com/docs/k6/latest/reference/versioning-and-stability-guarantees/),\nbreaking changes across minor releases are allowed only for experimental features.\n\n### Breaking changes for experimental modules\n\n- The experimental Open Telemetry and Prometheus outputs now default to TLSv1.3. This should've been the default to begin with. It is not expected that anyone should be affected, apart from making it more secure for the metrics output to send messages.\n\n## New features\n\n### Automatic extension resolution\n\nk6 extensions allow you to add custom functionality to your tests, such as connecting to databases, message queues, or specialized networking protocols. Previously, using extensions [required manual building](https://grafana.com/docs/k6/latest/extensions/run/build-k6-binary-using-go) of a custom k6 binary with the extensions compiled in. This new version introduces the _Automatic Extension Resolution_ functionality, previously named Binary Provisioning, which is enabled by default and automatically detects when your script imports extensions and handles the complexity of provisioning the right k6 binary for you.\n\n```javascript\nimport faker from \"k6/x/faker\";\n\nexport default function () {\n  console.log(faker.person.firstName());\n}\n```\n\nThe previous experimental versions only supported official extensions. [#4922](https://github.com/grafana/k6/pull/4922) added the support to use any extension listed in the [community list](https://grafana.com/docs/k6/latest/extensions/explore/) by setting the `K6_ENABLE_COMMUNITY_EXTENSIONS` environment variable.\n\n```\nK6_ENABLE_COMMUNITY_EXTENSIONS=true k6 run script.js\n```\n\nNote, Community extensions are only supported for local test executions (using `k6 run` or `k6 cloud run --local-execution`). When running tests on Grafana Cloud k6, only official extensions are allowed.\n\nCheck out the new [extensions documentation](https://grafana.com/docs/k6/latest/extensions/) for additional details.\n\n### Handling of NaN and Infinity float values in gRPC [#4631](https://github.com/grafana/k6/pull/4631)\n\nPreviously, float values of `NaN` or `Infinity` were marshalled as `null`. This has now changed to use their string representation, aligning with other gRPC APIs.\n\nThere are no changes required in the scripts.\n\nThis is also the first contribution by @ariasmn. Thank you @ariasmn for taking the time to make the PR and answer all our questions.\n\n### Health check for gRPC APIs [#4853](https://github.com/grafana/k6/pull/4853)\n\nThe k6 gRPC module now has a `client.healthCheck()` method that simplifies checking the status of a gRPC service. This method eliminates the need for manual `invoke` calls, making it particularly useful for readiness checks and service discovery.\n\nBefore, you had to write boilerplate code to perform a health check:\n```javascript\nimport grpc from 'k6/grpc';\n\nconst client = new grpc.Client();\n// ...\nconst response = client.invoke('grpc.health.v1.Health/Check', { service: 'my-service' });\n```\n\nNow, you can simplify this with the `healthCheck()` method:\n```javascript\nimport grpc from 'k6/grpc';\n\nconst client = new grpc.Client();\nclient.connect('grpc.test.k6.io:443');\n\n// Check the health of a specific service\nconst response = client.healthCheck('my-service');\n\n// Check the health of the overall gRPC server\nconst overallResponse = client.healthCheck();\n\nclient.close();\n```\n\nCheck out the [client.healthCheck](https://grafana.com/docs/k6/latest/using-k6/protocols/grpc/#health-checking-protocol) documentation for additional details.\nThank you, @tbourrely, for contributing this feature.\n\n### Assertions Library (Preview) [#4067](https://github.com/grafana/k6/issues/4067)\n\nk6 now provides an [assertions](https://grafana.com/docs/k6/latest/using-k6/assertions) library to help you verify your application behaves as expected during testing.\n\nThe library introduces the [`expect`](https://grafana.com/docs/k6/latest/javascript-api/jslib/testing/expect) function with a set of expressive matchers. Pass a value to [`expect()`](https://grafana.com/docs/k6/latest/javascript-api/jslib/testing/expect) and chain it with a matcher that defines the expected outcome. The library caters to both protocol testing [HTTP/API](https://grafana.com/docs/k6/latest/using-k6/protocols) and [browser](https://grafana.com/docs/k6/latest/using-k6-browser) testing scenarios.\n\nThe API is inspired by Playwright's assertion syntax, offering a fluent interface for more readable and reliable tests.\n\n```javascript\nimport { expect } from 'https://jslib.k6.io/k6-testing/0.5.0/index.js';\nimport { browser } from 'k6/browser';\nimport http from 'k6/http';\n\nexport function protocolTest() {\n  // Get the home page of k6's Quick Pizza app\n  const response = http.get('https://quickpizza.grafana.com/');\n\n  // Simple assertions\n  expect(response.status).toBe(200);\n  expect(response.error).toEqual('');\n  expect(response.body).toBeDefined();\n}\n\nexport async function browserTest() {\n  const page = await browser.newPage();\n\n  try {\n    await page.goto('https://quickpizza.grafana.com/');\n\n    // Assert the \"Pizza Please\" button is visible\n    await expect(page.locator('button[name=pizza-please]')).toBeVisible();\n  } finally {\n    await page.close();\n  }\n}\n\nexport const options = {\n  scenarios: {\n    // Protocol tests\n    protocol: {\n      executor: 'shared-iterations',\n      vus: 1,\n      iterations: 1,\n      exec: 'protocolTest',\n    },\n\n    // Browser tests\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n      exec: 'browserTest',\n    },\n  },\n};\n```\n\n#### Preview feature\n\nThis feature is ready to use, but still in preview:\n* No breaking changes are neither planned, nor expected.\n* Some functionality may be missing or rough around the edges.\n* We expect to keep adding matchers and improving coverage.\n\nWe welcome your feedback, and invite you to share your suggestions and contributions on [GitHub](https://github.com/grafana/k6-jslib-testing).\n\n### Add `page.getByRole` API [#4843](https://github.com/grafana/k6/pull/4843)\n\nThe browser module now supports `page.getByRole()`, which allows you to locate elements based on their [ARIA roles](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles). This provides a more semantic and accessible way to find elements, making your tests more robust and aligned with how users actually interact with web applications.\n\nARIA roles represent the purpose or function of an element (like button, link, textbox, etc.), making them excellent selectors for testing since they're less likely to change when the UI is refactored compared to CSS classes or IDs.\n\nExample usage:\n```javascript\n// Find elements by role\nawait page.getByRole('button').click();\n\n// Find elements by role and accessible name\nawait page.getByRole('button', { name: 'Submit' }).click();\n\n// `name` works with regex too\nawait page.getByRole('textbox', { name: /^Username$/ }).fill('admin');\n\n// Work with specific states\nawait page.getByRole('checkbox', { name: 'Accept terms', checked: true }).click();\n\n// Find headings by level\nawait page.getByRole('heading', { level: 2, name: 'Section Title' }).textContent();\n\n### Add `page.getByAltText` [#4881](https://github.com/grafana/k6/pull/4881)\n\nThe browser module now includes `page.getByAltText()`, which provides a convenient way to select elements that have an `alt` text attribute. This is particularly useful for locating images or other elements that rely on alternative text for accessibility.\n\nPreviously, you would have to use CSS or XPath selectors to find these elements:\n```javascript\n// Using CSS selector\nconst locator = page.locator('img[alt=\"World Map\"]');\n\n// Using XPath selector\nconst locator = page.locator('//img[@alt=\"World Map\"]');\n```\n\nNow, you can simplify this by using `getByAltText()`:\n```javascript\nconst locator = page.getByAltText('World Map');\n\n// Find an image with alt text that starts with 'World'\nconst locator = page.getByAltText(/^World/);\n```\n\n### Add `page.getByLabel` [#4890](https://github.com/grafana/k6/pull/4890)\n\nThe browser module now includes `page.getByLabel()`, which provides a convenient way to locate form elements and other interactive components by their associated label text. This method works with both explicit `<label>` elements and elements that have an `aria-label` attribute, making it particularly useful for finding form inputs, buttons, and other interactive elements.\n\nPreviously, you would need to use XPath selectors to find elements by their label text, since CSS selectors cannot easily handle the relationship between labels and form elements:\n\n```javascript\n// Using XPath to find input by label text  \nconst locator = page.locator('//label[text()=\"Password\"]');\n\n// Or using aria-label with CSS\nconst locator = page.locator('[aria-label=\"Username\"]');\n```\n\nNow, you can simplify this with `getByLabel()`:\n\n```javascript\n// Works with both <label> elements and aria-label attributes\nconst passwordInput = page.getByLabel('Password');\n\n// Works with regex too\nconst usernameInput = page.getByLabel(/^Username$/);\n```\n\n### Add `page.getByPlaceholder` [#4904](https://github.com/grafana/k6/pull/4904)\n\nThe browser module now includes `page.getByPlaceholder()`, which provides a convenient way to locate form elements by their placeholder text. This is particularly useful for finding input fields, textareas, and other form controls that use placeholder text to guide user input.\n\nPreviously, you would need to use CSS or XPath selectors to find elements by their placeholder attribute:\n\n```javascript\n// Using CSS selector\nconst locator = page.locator('input[placeholder=\"Enter your name\"]');\n\n// Using XPath selector  \nconst locator = page.locator('//input[@placeholder=\"Enter your name\"]');\n```\n\nNow, you can simplify this with `getByPlaceholder()`:\n\n```javascript\nconst nameInput = page.getByPlaceholder('Enter your name');\n\n// Works with regex too\nconst emailInput = page.getByPlaceholder(/^Email/);\n```\n\n### Add `page.getByTitle` [#4910](https://github.com/grafana/k6/pull/4910)\n\nThe browser module now includes `page.getByTitle()`, which provides a convenient way to locate elements by their `title` attribute. This is particularly useful for finding tooltips, buttons, or any other elements that use the `title` attribute to provide extra information.\n\nPreviously, you would need to use CSS or XPath selectors to find these elements:\n\n```javascript\n// Using CSS selector\nconst locator = page.locator('div[title=\"Information box\"]');\n\n// Using XPath selector\nconst locator = page.locator('//div[@title=\"Information box\"]');\n```\n\nNow, you can simplify this with `getByTitle()`:\n\n```javascript\nconst infoBox = page.getByTitle('Information box');\n\n// Works with regex too\nconst saveButton = page.getByTitle(/^Save/);\n```\n\n### Add `page.getByTestId` [#4911](https://github.com/grafana/k6/pull/4911)\n\nThe browser module now includes `page.getByTestId()`, which provides a convenient way to locate elements by their `data-testid` attribute. This is particularly useful for creating resilient tests that are not affected by changes to the UI, since `data-testid` attributes are specifically added for testing purposes and are not expected to change.\n\nPreviously, you would need to use CSS or XPath selectors to find these elements:\n\n```javascript\n// Using CSS selector\nconst locator = page.locator('button[data-testid=\"submit-button\"]');\n\n// Using XPath selector\nconst locator = page.locator('//button[@data-testid=\"submit-button\"]');\n```\n\nNow, you can simplify this with `getByTestId()`:\n\n```javascript\nconst submitButton = page.getByTestId('submit-button');\n\n// Works with regex too\nconst usernameInput = page.getByTestId(/^username/);\n```\n\n### Add `page.getByText` [#4912](https://github.com/grafana/k6/pull/4912)\n\nThe browser module now includes `page.getByText()`, which allows you to locate elements by their text content. This provides a convenient way to find elements like buttons, links, and other interactive components that are identified by their visible text.\n\nPreviously, you would need to use XPath selectors to find elements by their text content, since CSS selectors cannot directly query the text of an element:\n\n```javascript\n// Using XPath selector\nconst locator = page.locator('//div[text()=\"Hello World\"]');\n```\n\nNow, you can simplify this with `getByText()`:\n\n```javascript\nconst helloWorldElement = page.getByText('Hello World');\n\n// Works with regex too\nconst submitButton = page.getByText(/^Submit/);\n```\n\n### Add `page.route` [#4953](https://github.com/grafana/k6/pull/4953) [#4961](https://github.com/grafana/k6/pull/4961), [#4971](https://github.com/grafana/k6/pull/4971), [#4985](https://github.com/grafana/k6/pull/4985)\n\nThe browser module now supports `page.route()`, which allows you to intercept and handle network requests before they are sent. This is particularly useful for testing scenarios where you need to mock API responses, block certain resources, or modify request behavior.\n\nThe route handler receives a `route` object that provides methods to `abort()`, `continue()`, or `fulfill()` the request.\n\nYou can use `page.route()` to:\n- **Block requests**: Prevent certain resources from loading (e.g., images, ads, analytics) with `abort()`.\n    ```javascript\n    // Block all image requests\n    await page.route(/(\\.png$)|(\\.jpg$)|(\\.jpeg$)/, async (route) => {\n        await route.abort();\n    });\n    ```\n- **Mock responses**: Return custom responses without hitting real endpoints with `fulfill()`.\n    ```javascript\n    // Mock API responses\n    await page.route('**/api/users', async (route) => {\n        await route.fulfill({\n            status: 200,\n            contentType: 'application/json',\n            body: JSON.stringify([{ id: 1, name: 'Mock User' }])\n        });\n    });\n    ```\n- **Modify requests**: Change headers, URL, or request body before they're sent with `continue()`.\n    ```javascript\n    // Continue with modified headers\n    await page.route('**/api/**', async (route) => {\n        await route.continue({\n            headers: {\n            ...route.request().headers(),\n            'Authorization': 'Bearer mock-token'\n            }\n        });\n    });\n    ```\n\n### Add `locator.all()` [#4899](https://github.com/grafana/k6/pull/4899)\n\nThe browser module now supports the `locator.all()` method, which returns an array of locators for all elements matching the selector. This is particularly useful when you need to interact with multiple similar elements on a page, such as items in a list or multiple buttons with the same styling.\n\nExample usage:\n```javascript\n// Get all list items and iterate through them\nconst items = await page.locator('li').all();\nfor (const item of items) {\n  console.log(await item.textContent());\n}\n```\n\n### Add `waitForURL` in `frame` and `page` [#4917](https://github.com/grafana/k6/pull/4917), [#4920](https://github.com/grafana/k6/pull/4920)\n\nThe browser module now includes the `waitForURL` method for both `page` and `frame` objects.\n\nAs a prerequiste to this enhancement, `waitForNavigation` now accepts a `url` option. This also allows you to wait for a specific URL during navigation. **It is advised that you work with `waitForURL` instead**.\n\nThe `waitForURL` method first checks if the current page URL already matches the expected pattern. If it does, it waits for the load state to complete. Otherwise, it waits for a navigation to the specified URL. This approach prevents race conditions where a page might complete navigation before the wait condition is set up, which is particularly useful when dealing with pages that perform multiple redirects. It supports both string patterns and regular expressions:\n\n```javascript\n// Wait for navigation to a specific URL\nawait Promise.all([\n  page.waitForURL('https://quickpizza.grafana.com/my_messages.php'),\n  page.locator('a[href=\"/my_messages.php\"]').click(),\n]);\n\n// Using regex pattern\nawait Promise.all([\n  page.waitForURL(/.*\\/contacts\\.php.*/),\n  page.locator('a[href^=\"/contacts.php\"]').click()\n]);\n```\n\nWhile `waitForURL` provides a convenient way to wait for specific URLs, we still recommend using element-based waiting strategies or the locator API with its built-in auto-waiting capabilities for more reliable tests.\n\n## UX improvements and enhancements\n\n- [#4878](https://github.com/grafana/k6/pull/4878) Do not report NaN percentages when there are no checks in the end of test summary. Thank you @Fernando-hub527 for the fix.\n- [#4897](https://github.com/grafana/k6/pull/4897) Support string-labels in `locator.selectOption` in the browser module.\n- [#4898](https://github.com/grafana/k6/pull/4898) Add support for `authority` pseudo header to the gRPC module. Thank you @Oursin for the changes.\n- [#4916](https://github.com/grafana/k6/pull/4916) Print errors more consistently and correctly.\n- [#4918](https://github.com/grafana/k6/pull/4918) Surface navigation errors from navigation events in the browser module.\n- [#4919](https://github.com/grafana/k6/pull/4919) `page.url()` now doesn't make a call to the browser but instead uses a cached version. Making it a lot faster and aligned with playwright.\n- [#4932](https://github.com/grafana/k6/pull/4932) Making it more clear that the requests were aborted in the browser module.\n- [#4944](https://github.com/grafana/k6/pull/4944) Add Prometheus metrics endpoint. Thank you @gouthamve.\n- [#5040](https://github.com/grafana/k6/pull/5040) Use new `expect()` syntax in script templates.\n- [#4976](https://github.com/grafana/k6/pull/4976) Align metrics in end of test summary with using less dots and less horizontal space.\n\n## Bug fixes\n\n- [#4850](https://github.com/grafana/k6/pull/4850) Fixes incorrect conversions between integer types in the browser module.\n- [#4973](https://github.com/grafana/k6/pull/4973) Fixes panic when `BrowserContext` is requested before creating a `Page` in the browser module.\n- [#4975](https://github.com/grafana/k6/pull/4975) Fixes potential race conditions in the browser module.\n- [#5015](https://github.com/grafana/k6/pull/5015) Fixes `waitForNavigation` now blocking the iteration from ending if `page.close` is not called.\n- [#5017](https://github.com/grafana/k6/pull/5017) Fixes potential race conditions in gRPC module, when it gets protobuf defintions from remote server.\n\n## Maintenance and internal improvements\n\n- [#4666](https://github.com/grafana/k6/pull/4666) Lowers the log level on some cloud output logs that were too noisy.\n- [#4879](https://github.com/grafana/k6/pull/4879), [#4945](https://github.com/grafana/k6/pull/4945) Updates of software used by the internal k6packager that packages k6.\n- [#4886](https://github.com/grafana/k6/pull/4886) Prevents running Winsign for public forks to avoid failing and wasting CI time.\n- [#4892](https://github.com/grafana/k6/pull/4892), [#4901](https://github.com/grafana/k6/pull/4901), [#4909](https://github.com/grafana/k6/pull/4909), [#4927](https://github.com/grafana/k6/pull/4927), [#4928](https://github.com/grafana/k6/pull/4928), [#4929](https://github.com/grafana/k6/pull/4929), [#4939](https://github.com/grafana/k6/pull/4939), [#4954](https://github.com/grafana/k6/pull/4954), [#4965](https://github.com/grafana/k6/pull/4965), [#4977](https://github.com/grafana/k6/pull/4977), [#5000](https://github.com/grafana/k6/pull/5000), [#5001](https://github.com/grafana/k6/pull/5001), [#5041](https://github.com/grafana/k6/pull/5041), [#5043](https://github.com/grafana/k6/pull/5043) Updates dependencies.\n- [#4925](https://github.com/grafana/k6/pull/4925) Configures Dependabot to update all OTel dependencies.\n- [#4914](https://github.com/grafana/k6/pull/4914), [#4967](https://github.com/grafana/k6/pull/4967), [#4974](https://github.com/grafana/k6/pull/4974), [#4990](https://github.com/grafana/k6/pull/4990), [#4991](https://github.com/grafana/k6/pull/4991), [#5007](https://github.com/grafana/k6/pull/5007), [#5008](https://github.com/grafana/k6/pull/5008) PRs trying to get the CI tests to be more stable.\n- [#4923](https://github.com/grafana/k6/pull/4923) Mention k6 studio in the readme for more visibility.\n- [#4931](https://github.com/grafana/k6/pull/4931) Lower the debug log on internal implementation detail error.\n- [#4943](https://github.com/grafana/k6/pull/4943), [#4946](https://github.com/grafana/k6/pull/4946), [#4948](https://github.com/grafana/k6/pull/4948) Fix the CI not checking generated files and pinning versions.\n- [#4949](https://github.com/grafana/k6/pull/4949) Updates to Linux Alpine 3.22 for building the k6 docker image.\n- [#4950](https://github.com/grafana/k6/pull/4950) Adds Dependabot rule to update the main Dockerfile dependencies.\n- [#4958](https://github.com/grafana/k6/pull/4958) Passes k6's file system to k6deps (for automatic extension resolution).\n- [#4959](https://github.com/grafana/k6/pull/4959) Copies Zizmor configuration in the repository to make it work for forks.\n- [#4960](https://github.com/grafana/k6/pull/4960) Reduces `waitForNavigation` complexity.\n- [#4969](https://github.com/grafana/k6/pull/4969), [#4986](https://github.com/grafana/k6/pull/4986) Updates around semgrep scanning for security issues.\n- [#4994](https://github.com/grafana/k6/pull/4994) Configures Dependabot to update dependencies in Github actions.\n- [#4996](https://github.com/grafana/k6/pull/4996), [#4997](https://github.com/grafana/k6/pull/4997), [#4998](https://github.com/grafana/k6/pull/4998) Updates to github actions dependancies.\n- [#5014](https://github.com/grafana/k6/pull/5014) Adds a test for running tests with the automatic extension resolution disabled.\n- [#5016](https://github.com/grafana/k6/pull/5016) Fix internal/cmd/tests with automatic extension resolution enabled.\n- [#5020](https://github.com/grafana/k6/pull/5020) Fix examples with browser using the wrong endpoints.\n"
  },
  {
    "path": "release notes/v1.3.0.md",
    "content": "k6 v1.3.0 is here 🎉! This release includes:\n\n- Browser module gets:\n  - `locator.locator`, `locator.contentFrame`, and `FrameLocator.locator` for powerful locator chaining and iframe handling.\n  - `locator|frame|FrameLocator.getBy*` for targeting elements without relying on brittle CSS selectors.\n  - `locator.filter` for filtering locators for more precise element targeting.\n  - `locator.boundingBox` for retrieving element geometry.\n  -  `page.waitForResponse` for waiting on specific HTTP responses.\n\n## Deprecations\n\n### A new summary mode `disabled` has been introduced to replace the \"no summary\" option [#5118](https://github.com/grafana/k6/pull/5118)\n\nThe `--no-summary` flag and its corresponding environment variable `K6_NO_SUMMARY` have been deprecated in favor of\nthe new `disabled` summary mode. This change unifies the configuration experience for controlling the end-of-test summary.\n\nYou can now disable the end-of-test summary with either `--summary-mode=disabled` or `K6_SUMMARY_MODE=disabled`.\n\n### The `legacy` summary mode has been deprecated [#5138](https://github.com/grafana/k6/pull/5138)\n\nThe `legacy` summary mode was introduced in k6 v1.0, when the end-of-test summary was revamped with the addition of two\nnew modes: `compact` and `full`.\n\nIts purpose was to ease the transition for users who relied heavily on the old summary format. \nHowever, we’ve now reached the point where it’s time to deprecate it. \n\nThe plan is to fully remove it in k6 v2.0, so please migrate to either `compact` or `full` to ensure readiness for the \nnext major release.\n\n## New features\n\n### `locator.locator` [#5073](https://github.com/grafana/k6/pull/5073)\n\nThe [`locator.locator`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/locator/) method allows you to define locators relative to a parent locator, enabling powerful locator chaining and nesting. This feature lets you create more precise element targeting by combining multiple selectors in a hierarchical manner.\n\n```javascript\nawait page\n  .locator('[data-testid=\"inventory\"]')\n  .locator('[data-item=\"apples\"]')\n  .locator('button.add')\n  .click();\n```\n\nThis nesting capability provides a more intuitive way to navigate complex DOM structures and serves as the foundation for other `locator` APIs in this release that require such hierarchical targeting.\n\n### `locator.contentFrame` [#5075](https://github.com/grafana/k6/pull/5075)\n\nThe browser module now supports [`locator.contentFrame()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/contentframe/), which returns a new type [`frameLocator`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/framelocator/). This method is essential for switching context from the parent page to iframe contents.\n\n`frameLocator` types target iframe elements on the page and provide a gateway to interact with their contents. Unlike regular `locator`s that work within the current `frame` context, `frameLocator`s specifically target iframe elements and prepare them for content interaction.\n\nThis approach is essential for iframe interaction because:\n- Iframes create separate DOM contexts that require special handling.\n- Browsers enforce security boundaries between frames.\n- Iframe content may load asynchronously and needs proper waiting.\n- Using `elementHandle` for iframe interactions is error-prone and can lead to stale references, while `frameLocator` provide reliable, auto-retrying approaches.\n\nExample usage:\n```javascript\n// Get iframe element and switch to its content frame\nconst iframeLocator = page.locator('iframe[name=\"payment-form\"]');\nconst frame = await iframeLocator.contentFrame();\n```\n\n### `frameLocator.locator` [#5075](https://github.com/grafana/k6/pull/5075)\n\nWe've also added [`frameLocator.locator`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/framelocator/locator/) which allows you to create `locator`s for elements inside an iframe. Once you've targeted an iframe with `page.contentFrame()`, you can use `.locator()` to find and interact with elements within that iframe's content with the `frameLocator` type.\n\nExample usage:\n```javascript\n// Target an iframe and interact with elements inside it\nconst iframe = page.locator('iframe[name=\"checkout-frame\"]').contentFrame();\nawait iframe.locator('input[name=\"card-number\"]').fill('4111111111111111');\nawait iframe.locator('button[type=\"submit\"]').click();\n```\n\nThis functionality enables testing of complex web applications that use iframes for embedded content, payment processing, authentication widgets, and third-party integrations.\n\n### `locator.boundingBox` [#5076](https://github.com/grafana/k6/pull/5076)\n\nThe browser module now supports [`locator.boundingBox()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/boundingbox/), which returns the bounding box of an element as a rectangle with position and size information. This method provides essential geometric data about elements on the page, making it valuable for visual testing, and layout verification.\n\nUsing `locator.boundingBox()` is recommended over `elementHandle.boundingBox()` because locators have built-in auto-waiting and retry logic, making them more resilient to dynamic content and DOM changes. While element handles can become stale if the page updates, locators represent a live query that gets re-evaluated, ensuring more reliable test execution.\n\nThe method returns a rectangle object with `x`, `y`, `width`, and `height` properties, or `null` if the element is not visible:\n\n```javascript\n// Get bounding box of an element\nconst submitButton = page.locator('button[type=\"submit\"]');\nconst rect = await submitButton.boundingBox();\n```\n\n### Locator filtering [#5114](https://github.com/grafana/k6/pull/5114), [#5150](https://github.com/grafana/k6/pull/5150)\n\nThe browser module now supports filtering options for locators, allowing you to create more precise and reliable element selections. This enhancement improves the robustness of your tests by enabling you to target elements that contain or exclude specific text, reducing reliance on brittle CSS selectors.\n\n[**`locator.filter()`**](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/filter/) creates a new `locator` that matches only elements containing or excluding specified text.\n\n```javascript\n// Filter list items that contain specific text\nconst product2Item = page\n  .locator('li')\n  .filter({ hasText: 'Product 2' });\n\n// Filter items that do NOT contain specific text using regex\nconst otherProducts = page\n  .locator('li')\n  .filter({ hasNotText: /Product 2/ });\n```\n\nIt's also possible to filter locators during their creation with options.\n\n**`page.locator(selector, options)`** creates page locators with optional text filtering:\n\n```javascript\n// Create locators with text filtering during creation\nconst submitButton = page.locator('button', { hasText: 'Submit Order' });\nawait submitButton.click();\n```\n\n**`frame.locator(selector, options)`** creates frame locators with optional text filtering:\n\n```javascript\n// Filter elements within frame context\nconst frame = page.mainFrame();\nconst input = frame.locator('input', { hasNotText: 'Disabled' });\n```\n\n**`locator.locator(selector, options)`** chains locators with optional text filtering:\n\n```javascript\n// Chain locators with filtering options\nawait page\n  .locator('[data-testid=\"inventory\"]')\n  .locator('[data-item=\"apples\"]', { hasText: 'Green' })\n  .click();\n```\n\n**`frameLocator.locator(selector, options)`** create locators within iframe content with optional text filtering:\n\n```javascript\n// Filter elements within iframe content\nconst iframe = page.locator('iframe').contentFrame();\nawait iframe.locator('button', { hasText: 'Submit Payment' }).click();\n```\n\n### `frame.getBy*`, `locator.getBy*`, `frameLocator.getBy*` [#5105](https://github.com/grafana/k6/pull/5105), [#5106](https://github.com/grafana/k6/pull/5106), [#5135](https://github.com/grafana/k6/pull/5135)\n\nThe browser module now supports all `getBy*` methods on `frame`, `locator`, and `frameLocator` types, expanding on the `page.getBy*` APIs introduced in v1.2.1. This enhancement provides consistent element targeting across all browser automation contexts, improving Playwright compatibility and offering more flexible testing workflows. The available methods on all types are:\n\n- `getByRole()` - Find elements by ARIA role\n- `getByText()` - Find elements by text content  \n- `getByLabel()` - Find elements by associated label text\n- `getByPlaceholder()` - Find elements by placeholder text\n- `getByAltText()` - Find elements by alt text\n- `getByTitle()` - Find elements by title attribute\n- `getByTestId()` - Find elements by data-testid attribute\n\n#### Examples across different types\n\n```javascript\n// Frame context\nconst frame = page.mainFrame();\nawait frame.getByRole('button', { name: 'Submit' }).click();\nawait frame.getByLabel('Email').fill('user@example.com');\n\n// Locator context (for scoped searches)\nconst form = page.locator('form.checkout');\nawait form.getByRole('textbox', { name: 'Card number' }).fill('4111111111111111');\nawait form.getByTestId('submit-button').click();\n\n// FrameLocator context (for iframe content)\nconst paymentFrame = page.locator('iframe').contentFrame();\nawait paymentFrame.getByLabel('Cardholder name').fill('John Doe');\nawait paymentFrame.getByRole('button', { name: 'Pay now' }).click();\n\n// Chaining for precise targeting\nawait page\n  .locator('.product-list')\n  .getByText('Premium Plan')\n  .getByRole('button', { name: 'Select' })\n  .click();\n```\n\nThis expansion makes k6 browser automation more versatile and aligns with modern testing practices where element targeting by semantic attributes (roles, labels, text) is preferred over fragile CSS and XPath selectors.\n\n### `page.waitForResponse` [#5002](https://github.com/grafana/k6/pull/5002)\n\nThe browser module now supports [`page.waitForResponse()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitforresponse/), which allows you to wait for HTTP responses that match specific URL patterns during browser automation. This method is particularly valuable for testing scenarios where you need to ensure specific network requests complete before proceeding with test actions.\n\nThe method supports multiple URL pattern matching strategies:\n\n```javascript\n// Wait for exact URL match\nawait page.waitForResponse('https://api.example.com/data');\n\n// Wait for regex pattern match\nawait page.waitForResponse(/\\/api\\/.*\\.json$/);\n\n// Use with Promise.all for coordinated actions\nawait Promise.all([\n  page.waitForResponse('https://api.example.com/user-data'),\n  page.click('button[data-testid=\"load-user-data\"]')\n]);\n```\n\nThis complements the existing `waitForURL` method by focusing on HTTP responses rather than navigation events, providing more granular control over network-dependent test scenarios.\n\nThank you, @HasithDeAlwis, for contributing this feature.\n\n## UX improvements and enhancements\n\n- [#5117](https://github.com/grafana/k6/pull/5117) Unifies unauthenticated errors for Cloud commands.\n- [#5125](https://github.com/grafana/k6/pull/5125) Changes a warn log to a debug when a worker type is used on a website under test.\n- [#5111](https://github.com/grafana/k6/pull/5111) Adds retries to actionability based APIs (`locator`) when elements aren't visible.\n- [#5004](https://github.com/grafana/k6/pull/5004) Removes undefined headers from `route.continue`/`fulfill`.\n- [#4984](https://github.com/grafana/k6/pull/4984) Adds link to documentation in `k6 --help` output. Thank you, @Nishant891 for the change.\n\n## Bug fixes\n\n- [#5079](https://github.com/grafana/k6/pull/5079) Fixes version of k6 when it is built with xk6.\n- [#5057](https://github.com/grafana/k6/pull/5057) Fixes a panic on the deprecated `k6 login cloud` command. Thanks @indygriffiths for reporting it!\n- [#5059](https://github.com/grafana/k6/pull/5059) Fixes group order in end of test summary when scenarios are used.\n- [#5081](https://github.com/grafana/k6/pull/5081) Fixes auto extension resolution only working if binary is called `k6` after a fix in v1.2.2.\n- [#5089](https://github.com/grafana/k6/pull/5089) Fixes gRPC calls not using loaded types and erroring out, especially around the usage of `Any`.\n- [#5071](https://github.com/grafana/k6/pull/5071), [#5086](https://github.com/grafana/k6/pull/5086), [#5163](https://github.com/grafana/k6/pull/5163) Fixes `click` action in browser module when working in `iframe`s and CORS.\n- [#5084](https://github.com/grafana/k6/pull/5084) Fixes a browser module issue when adopting elements from `util` to `main` execution contexts in Chromium.\n- [#5178](https://github.com/grafana/k6/pull/5178) Fixes a subtle metric labelling issue in Prometheus RW output. \n- [#5200](https://github.com/grafana/k6/pull/5200) Fixes a bug where clearTimeout would not recalculate the timer but instead will run the next timer earlier if it used to remove the earliest one. Thanks to @kyriog :bow:.\n\n## Maintenance and internal improvements\n\n- [#5165](https://github.com/grafana/k6/pull/5165) Fixes arguments order for multiple `{require|assert}.{Equal|NotEqual}` and equivalent calls.\n- [#5157](https://github.com/grafana/k6/pull/5157) Fixes the test `TestURLSkipRequest` for Chrome 140+.\n- [#5074](https://github.com/grafana/k6/pull/5074), [#5078](https://github.com/grafana/k6/pull/5078) Uses common.IsNullish through the code instead of other variants of it or custom helpers.\n- [#5072](https://github.com/grafana/k6/pull/5072), [#5107](https://github.com/grafana/k6/pull/5107), [#5108](https://github.com/grafana/k6/pull/5108) Update k6packager debian to latest LTS and fixes due to the update.\n- [#5051](https://github.com/grafana/k6/pull/5051), [#5052](https://github.com/grafana/k6/pull/5052), [#5053](https://github.com/grafana/k6/pull/5053) Adds tests and refactors `getBy*` and `waitForURL` implementations.\n- [#5101](https://github.com/grafana/k6/pull/5101) Updates times to nanoseconds to make tests less flakey in CI.\n- [#5122](https://github.com/grafana/k6/pull/5122) Migrates to use a new code signing process for Windows binaries instead of using the static code-signing certificate. Thanks @martincostello for the contribution!\n- [#5048](https://github.com/grafana/k6/pull/5048) Updates release issue template after v1.2.0\n- [#5046](https://github.com/grafana/k6/pull/5046) Adds architecture overview and code authoring instructions for Claude Code and alike.\n\n## Roadmap\n\n### Deprecation of First Input Delay (FID) Web Vital\n\nFollowing the official [web vitals guidance](https://web.dev/blog/fid), First Input Delay (FID) is no longer a Core Web Vital as of September 9, 2024, having been replaced by Interaction to Next Paint (INP). The k6 browser module already emits INP metrics, and we're planning to deprecate FID support to align with industry standards.\n\nFID only measures the delay before the browser runs your event handler, so it ignores the time your code takes and the delay to paint the UI—often underestimating how slow an interaction feels. INP captures the full interaction latency (input delay + processing + next paint) across a page’s interactions, so it better reflects real user-perceived responsiveness and is replacing FID.\n\n#### Planned timeline\n\n- v1.4.x+: Deprecation warnings will appear in the terminal when FID metrics are used [#5179](https://github.com/grafana/k6/issues/5179).\n- Grafana Cloud k6: Similar deprecation warnings will be shown in the cloud platform.\n- v2.0: Complete removal of FID metric support.\n\n#### Action required\n\nIf you're currently using FID in your test scripts for thresholds or relying on it in external integrations, you should migrate to using INP as soon as possible.\n\n```javascript\n// Instead of relying on FID\nexport const options = {\n  thresholds: {\n    // 'browser_web_vital_fid': ['p(95)<100'], // Deprecated\n    'browser_web_vital_inp': ['p(95)<200'], // Use INP instead\n  },\n};\n```\n\nThis change ensures k6 browser testing stays aligned with modern web performance best practices and Core Web Vitals standards.\n\n### OpenTelemetry stabilization\n\nWe aim to stabilize OpenTelemetry's experimental metric output, promoting vendor neutrality for metric outputs. OpenTelemetry is becoming the standard protocol for metric format in observability. Our goal is to enable k6 users to utilize their preferred metric backend storage without any technological imposition.\n"
  },
  {
    "path": "release notes/v1.4.0.md",
    "content": "k6 `v1.4.0` is here 🎉! This release includes:\n\n- OpenTelemetry output graduated from experimental to stable status.\n- Changes in the Browser module:\n  - `page.waitForRequest` for waiting on specific HTTP requests.\n  - `QueryAll` methods now return elements in DOM order.\n  - `locator.evaluate` and `locator.evaluateHandle` for executing JavaScript code in the page context with access to the matching element.\n  - `page.unroute(url)` and `page.unrouteAll` for removing routes registered with `page.route`.\n\n## Breaking changes\n\nAs per our [stability guarantees](https://grafana.com/docs/k6/latest/reference/versioning-and-stability-guarantees/), breaking changes across minor releases are allowed only for experimental features.\n\n### Breaking changes for experimental modules\n\n- [#5164](https://github.com/grafana/k6/pull/5164) OpenTelemetry output now exports rate metrics as a single counter with `zero`/`nonzero` labels instead of separate metrics.\n- [#5333](https://github.com/grafana/k6/pull/5333) OpenTelemetry output configuration: `K6_OTEL_EXPORTER_TYPE` is deprecated in favor of `K6_OTEL_EXPORTER_PROTOCOL` to align with OpenTelemetry standards.\n\n### Breaking changes for undefined behaviours\n- [#5320](https://github.com/grafana/k6/pull/5320), [#5239](https://github.com/grafana/k6/pull/5239), [#5342](https://github.com/grafana/k6/pull/5342) Automatic extension resolution now only inspects ES module `import` statements and no longer supports CommonJS `require()` calls. CommonJS `require()` calls are dynamic, and it is not possible to know for certain if they will be called, or if they will be called with static strings - the only way they were even previously loaded. This functionality was a quirk of the previous implementation and had numerous problems. Additionally, `use k6` directives are now only recognized when they appear at the beginning of files (after optional shebang and whitespace/comments). This was the original intention, but due to implementation bugs, it did not accurately reflect what was happening.\n\n## New features\n\n### OpenTelemetry output graduation [#5334](https://github.com/grafana/k6/pull/5334)\n\nThe OpenTelemetry output has graduated from experimental status and is now available as a stable output using the name `opentelemetry`. This change makes OpenTelemetry the recommended vendor-agnostic solution for exporting k6 telemetry data.\n\nYou can now use the stable output name in your k6 commands:\n\n```bash\n# Previous experimental usage (still supported for backward compatibility)\nk6 run --out experimental-opentelemetry script.js\n\n# New stable usage\nk6 run --out opentelemetry script.js\n```\n\nThe `experimental-opentelemetry` name will continue to work for backward compatibility for now but it's deprecated and we might remove it in future versions. We recommend migrating to use the new `opentelemetry` name.\n\n### `page.waitForRequest` [#5330](https://github.com/grafana/k6/pull/5330)\n\nThe browser module now supports [`page.waitForRequest()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitforrequest/), which allows you to wait for HTTP requests that match specific URL patterns during browser automation. This method is particularly valuable for testing scenarios where you need to ensure specific network requests are initiated before proceeding with test actions.\n\nThe method supports multiple URL pattern matching strategies:\n\n```javascript\n// Wait for exact URL match\nconst requestPromise = page.waitForRequest('https://api.example.com/data');\nawait page.click('button[data-testid=\"load-data\"]');\nconst request = await requestPromise;\n\n// Wait for regex pattern match\nawait page.waitForRequest(/\\/api\\/.*\\.json$/);\n\n// Use with Promise.all for coordinated actions\nawait Promise.all([\n  page.waitForRequest('https://api.example.com/user-data'),\n  page.click('button[data-testid=\"load-user-data\"]')\n]);\n```\n\nThis complements the existing [`page.waitForResponse()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitforresponse/) method by focusing on HTTP requests rather than responses, providing more granular control over network-dependent test scenarios.\n\n### `page.unroute(url)` and `page.unrouteAll()` [#5223](https://github.com/grafana/k6/pull/5223)\n\nThe browser module now supports [`page.unroute(url)`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/unroute/) and [`page.unrouteAll()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/unrouteall/), allowing you to remove routes previously registered with `page.route`.\n\nExample usage:\n```javascript\nawait page.route(/.*\\/api\\/pizza/, function (route) {\n  console.log('Modifying request to /api/pizza');\n  route.continue({\n    postData: JSON.stringify({\n      customName: 'My Pizza',\n    }),\n  });\n});\n...\n\nawait page.unroute(/.*\\/api\\/pizza/); // The URL needs to be exactly the same as the one used in the call to the `route` function\n```\n\n```javascript\nawait page.route(/.*\\/api\\/pizza/, function (route) {\n  console.log('Modifying request to /api/pizza');\n  route.continue({\n    postData: JSON.stringify({\n      customName: 'My Pizza',\n    }),\n  });\n});\n...\n\nawait page.unrouteAll();\n```\n\n### `locator.evaluate` and `locator.evaluateHandle` [#5306](https://github.com/grafana/k6/pull/5306)\n\nThe browser module now supports [`locator.evaluate`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/evaluate/) and [`locator.evaluateHandle`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/evaluatehandle/), allowing you to execute JavaScript code in the page context with access to the matching element. The only difference between `evaluate` and `evaluateHandle` is that `evaluateHandle` returns a [JSHandle](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/jshandle/).\n\nExample usage:\n```javascript\nawait check(page, {\n  'calling evaluate': async p => {\n    const n = await p.locator('#pizza-name').evaluate(pizzaName => pizzaName.textContent);\n    return n == 'Our recommendation:';\n  }\n});\n\nawait check(page, {\n  'calling evaluate with arguments': async p => {\n    const n = await p.locator('#pizza-name').evaluate((pizzaName, extra) => pizzaName.textContent + extra, ' Super pizza!');\n    return n == 'Our recommendation: Super pizza!';\n  }\n});\n```\n\n```javascript\nconst jsHandle = await page.locator('#pizza-name').evaluateHandle((pizzaName) => pizzaName);\n\nconst obj = await jsHandle.evaluateHandle((handle) => {\n  return { innerText: handle.innerText };\n});\nconsole.log(await obj.jsonValue()); // {\"innerText\":\"Our recommendation:\"}\n```\n\n### New officially supported [k6 DNS extension](https://github.com/grafana/xk6-dns)\n\nThe [`xk6-dns` extension](https://grafana.com/docs/k6/latest/javascript-api/k6-x-dns) is now officially supported in k6 OSS and k6 Cloud. You can import `k6/x/dns` directly in your scripts thanks to [automatic extension resolution](https://grafana.com/docs/grafana-cloud/testing/k6/author-run/use-k6-extensions/), with no custom build required.\n\nUse it to perform DNS resolution testing as part of your tests: resolve names via custom or system DNS, measure resolution latency and errors, validate records before HTTP steps, compare resolvers, and even load test DNS servers in end‑to‑end scenarios.\n\nFor example:\n\n```javascript\nimport dns from 'k6/x/dns';\n\nexport default function () {\n  const answer = dns.resolve('grafana.com', { recordType: 'A' });\n  console.log(answer.records.map(({ address }) => address).join(', '));\n}\n```\n\nThe extension currently supports A and AAAA record lookups. If you would like to see additional record types supported, please consider [contributing to the extension](https://github.com/grafana/xk6-dns).\n\n\n### Automatic extension resolution improvements [#5320](https://github.com/grafana/k6/pull/5320), [#5239](https://github.com/grafana/k6/pull/5239), [#5342](https://github.com/grafana/k6/pull/5342), [#5332](https://github.com/grafana/k6/pull/5332), [#5240](https://github.com/grafana/k6/pull/5240)\n\nAutomatic extension resolution has been completely reimplemented to use k6's internal module loader instead of the external `k6deps`/esbuild pipeline. This change brings significant improvements in reliability and maintainability.\n\nAs part of the rewrite, a few issues and unintended _features_ were found, namely:\n1. Trying to follow `require` calls, which, due to their dynamic nature, don't work particularly stably. That is, depending on where and how the `require` call was used, k6 might decide whether it is needed or not. And it definitely doesn't work when using actual string variables. Support for CommonJS is primarily for backward compatibility, so after an internal discussion, we opted not to support it at all. We could bring this back until v2, if there is enough interest. However, in the long term, it is intended that this not be part of k6.\n2. \"use k6 with ...\" directives were parsed from the whole file instead of just the beginning, which leads to numerous problems, and was not the intended case. As such, they are now only parsed at the beginning of files (not just the main one) with potential empty lines and comments preceding them.\n\n**Example:**\n\n```javascript\n// main.js\n\"use k6 with k6/x/faker\"\nimport { faker } from 'k6/x/faker';\nimport { helper } from './utils.js';\n\nexport default function() {\n  console.log(faker.name());\n  helper();\n}\n```\nOr, an example using the directive with CommonJS\n```javascript\n// utils.js\n\"use k6 with k6/x/redis\"\nconst redis = require('k6/x/redis');\n\nexports.helper = function() {\n  // Use redis extension\n}\n```\n\nIn this example, k6 will detect both `k6/x/faker` and `k6/x/redis` extensions from the `use k6` directives in both files and provision a binary that includes both extensions if needed.\n\nOther fixes this brings are:\n1. Fixes for path related issues (irregardless of usage of the feature) on windows, especially between drives. It is possible there were problems on other OSes that were just not reported. [#5176](https://github.com/grafana/k6/issues/5176)\n2. Syntax errors were not reported as such, as the underlying `esbuild` parsing will fail, but won't be handled well. [#5127](https://github.com/grafana/k6/issues/5127), [#5104](https://github.com/grafana/k6/issues/5104)\n\n3. Propagating exit codes from a sub-process running the new k6. This lets you use the result of the exit code.\n\n## UX improvements and enhancements\n\n- [#5307](https://github.com/grafana/k6/pull/5307) `QueryAll` methods now return elements in DOM order. Thank you, @shota3506, for the contribution.\n- [#5159](https://github.com/grafana/k6/pull/5159) Simplifies warning message for legacy config files.\n- [#5343](https://github.com/grafana/k6/pull/5343) Explictly marks the option's default values.\n\n## Bug fixes\n\n- [#5242](https://github.com/grafana/k6/pull/5242) Fixes cleanup errors on Windows for browser tests. \n- [#5246](https://github.com/grafana/k6/pull/5246) Fixes the support for TypeScript source code from stdin.\n- [#5322](https://github.com/grafana/k6/pull/5322) Fixes `browser.newPageInContext` bug where pages created in a non-existing browser context.\n\n## Maintenance and internal improvements\n\n- [#5238](https://github.com/grafana/k6/pull/5238) Browser: Fix early context cancellation in tests\n- [#5347](https://github.com/grafana/k6/pull/5347), [#5349](https://github.com/grafana/k6/pull/5349) Browser: Move `k6ext.Promise` to the mapping layer.\n- [#5340](https://github.com/grafana/k6/pull/5340) Browser: Simplify page event iteration by using an iterator.\n- [#5315](https://github.com/grafana/k6/pull/5315), [#5311](https://github.com/grafana/k6/pull/5311) Browser: Revamped page event listening internals for addition of new features and better maintainability.\n- [#5339](https://github.com/grafana/k6/pull/5339) Browser: Remove unused `VU` fields.\n- [#5314](https://github.com/grafana/k6/pull/5314) Browser: Refactor pattern matcher.\n- [#5222](https://github.com/grafana/k6/pull/5222) Browser: Fix linter errors and warnings.\n- [#5207](https://github.com/grafana/k6/pull/5207) Browser: Refactor and improve selector parsing. Thank you, @elmiringos for the contribution.\n- [#5313](https://github.com/grafana/k6/pull/5313), [#5321](https://github.com/grafana/k6/pull/5321) Update to k6provider v0.2.0 and update code to use the new API.\n- [#4682](https://github.com/grafana/k6/pull/4682) Update go-httpbin dependency to v2 and update tests to accommodate breaking changes.\n- [#5309](https://github.com/grafana/k6/pull/5309) Update cdproto dependency and fix syntax changes in browser module.\n- [#5209](https://github.com/grafana/k6/pull/5209) Update golangci-lint to v2.5.0 and fix related linting issues.\n- [#5308](https://github.com/grafana/k6/pull/5308) Format Go Doc comments. Thank you, @shota3506 for the contribution.\n- [#5184](https://github.com/grafana/k6/pull/5184) Migrates Prometheus Remote-Write output configuration parsing to `envconfig`.\n- [#5304](https://github.com/grafana/k6/pull/5304) Bumps the minimum required Go version to 1.24.\n- [#5214](https://github.com/grafana/k6/pull/5214) Update release issue template after 1.3.0\n- [#5303](https://github.com/grafana/k6/pull/5303) Fixes code scanning alert no. 102: Incorrect conversion between integer types.\n- [#5302](https://github.com/grafana/k6/pull/5302), [#5244](https://github.com/grafana/k6/pull/5244) Refactors Sobek out of business logic and into mapping layer for the browser module.\n- [#5247](https://github.com/grafana/k6/pull/5247) Refactors indirection out of locator.go.\n- [#4234](https://github.com/grafana/k6/pull/5234), [#5301](https://github.com/grafana/k6/pull/5301), [#5300](https://github.com/grafana/k6/pull/5300), [#5208](https://github.com/grafana/k6/pull/5208) Updates renovate config.\n- [#5355](https://github.com/grafana/k6/pull/5355), [#5354](https://github.com/grafana/k6/pull/5354), [#5353](https://github.com/grafana/k6/pull/5353), [#5352](https://github.com/grafana/k6/pull/5352), [#5351](https://github.com/grafana/k6/pull/5351), [#5324](https://github.com/grafana/k6/pull/5324), [#5293](https://github.com/grafana/k6/pull/5293), [#5292](https://github.com/grafana/k6/pull/5292), [#5291](https://github.com/grafana/k6/pull/5291), [#5290](https://github.com/grafana/k6/pull/5290), [#5288](https://github.com/grafana/k6/pull/5288), [#5287](https://github.com/grafana/k6/pull/5287), [#5286](https://github.com/grafana/k6/pull/5286), [#5284](https://github.com/grafana/k6/pull/5284), [#5283](https://github.com/grafana/k6/pull/5283), [#5282](https://github.com/grafana/k6/pull/5282), [#5268](https://github.com/grafana/k6/pull/5268), [#5267](https://github.com/grafana/k6/pull/5267), [#5266](https://github.com/grafana/k6/pull/5266), [#5265](https://github.com/grafana/k6/pull/5265), [#5258](https://github.com/grafana/k6/pull/5258), [#5257](https://github.com/grafana/k6/pull/5257), [#5256](https://github.com/grafana/k6/pull/5256), [#5253](https://github.com/grafana/k6/pull/5253), [#5252](https://github.com/grafana/k6/pull/5252), [#5251](https://github.com/grafana/k6/pull/5251), Updates dependencies.\n- [#5216](https://github.com/grafana/k6/pull/5216) Refactors `TestPageOnResponse` to fail fast on errors. Thank you, @rMaxiQp for the contribution.\n- [#5203](https://github.com/grafana/k6/pull/5203), [#5201](https://github.com/grafana/k6/pull/5201) Adds WinGet support to the project.\n- [#5220](https://github.com/grafana/k6/pull/5220) Switches from gouuid to google/uuid. Thank you, @mikelolasagasti for the contribution.\n- [#5344](https://github.com/grafana/k6/pull/5344), [#5345](https://github.com/grafana/k6/pull/5345) Uses .env context for ghcr login when publishing docker images.\n- [#5331](https://github.com/grafana/k6/pull/5331) Reports `require` calls during the initial loading of modules, instead for each call in all execution of all VUs.\n- [#5218](https://github.com/grafana/k6/pull/5218) Adds user AgnesToulet to the auto assign issue workflow.\n"
  },
  {
    "path": "release notes/v1.5.0.md",
    "content": "k6 1.5.0 is here 🎉! This release includes:\n\n- Changes in the browser module:\n  - `page.waitForEvent()` for event-based synchronization with page events.\n  - `locator.pressSequentially()` for character-by-character typing simulation.\n- Improved debugging with deep object logging in `console.log()`.\n- Extended WebSocket support with close code and reason information.\n- Enhanced extension ecosystem with custom subcommands and DNS resolver access.\n- URL-based secret management for external secret services.\n- New machine-readable summary format for test results.\n\n## Breaking changes\n\nAs per our [stability guarantees](https://grafana.com/docs/k6/latest/reference/versioning-and-stability-guarantees/), breaking changes across minor releases are allowed only for experimental features.\n\n### Breaking changes for experimental modules\n\n- [#5237](https://github.com/grafana/k6/pull/5237) Deprecates the `experimental/redis` module. The module will be removed in a future release. Users should migrate to alternative solutions, such as [the official k6 Redis extension](https://github.com/grafana/xk6-redis).\n\n## New features\n\n### `page.waitForEvent()` [#5478](https://github.com/grafana/k6/pull/5478)\n\nThe browser module now supports [`page.waitForEvent()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/waitforevent/), which blocks the caller until a specified event is captured. If a predicate is provided, it waits for an event that satisfies the predicate. This method is particularly valuable for testing scenarios where you need to synchronize your test flow with specific browser or page events before proceeding with the next action.\n\nEvent-driven synchronization is vital for test reliability, especially when dealing with asynchronous operations where timing is unpredictable. This is more robust than using fixed delays and helps avoid flaky tests.\n\n```javascript\nimport { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  // Wait for a console message containing specific text\n  const msgPromise = page.waitForEvent('console', msg => msg.text().includes('hello'));\n  await page.evaluate(() => console.log('hello world'));\n  const msg = await msgPromise;\n  console.log(msg.text());\n  // Output: hello world\n\n  // Wait for a response from a specific URL with timeout\n  const resPromise = page.waitForEvent('response', {\n    predicate: res => res.url().includes('/api/data'),\n    timeout: 5000,\n  });\n  await page.click('button#fetch-data');\n  const res = await resPromise;\n\n  await page.close();\n}\n```\n\n### `locator.pressSequentially()` [#5457](https://github.com/grafana/k6/pull/5457)\n\nThe browser module now supports [`locator.pressSequentially()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/presssequentially/), which types text character by character, firing keyboard events (`keydown`, `keypress`, `keyup`) for each character. This method is essential for testing features that depend on gradual typing to trigger specific behaviors, such as autocomplete suggestions, real-time input validation per character, or dynamic character counters. Thank you, @rajan2345, for the contribution 🎉\n\nThe method supports a configurable delay between keystrokes, enabling you to simulate realistic typing speeds and test time-dependent input handlers:\n\n```javascript\nimport { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  try {\n    await page.goto('https://test.k6.io/browser.php');\n\n    // Type text character by character\n    const searchInput = page.locator('#text1');\n    await searchInput.pressSequentially('Hello World');\n\n    // Type with delay to simulate realistic typing speed\n    await searchInput.clear();\n    await searchInput.pressSequentially('test query', { delay: 100 });\n  } finally {\n    await page.close();\n  }\n}\n```\n\nThis complements existing text input methods: [`locator.fill()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/fill/) for simple form filling, [`locator.type()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/type/) for gradual typing without keyboard events, and now `pressSequentially` for character-by-character typing with full keyboard event firing. Thank you, @rajan2345, for the contribution 🎉\n\n### `console.log()` Deep Object Logging [#5460](https://github.com/grafana/k6/pull/5460)\n\n`console.log()` now properly traverses and displays complex JavaScript structures, including functions, classes, and circular references. Previously, Sobek's JSON marshaling would lose nested functions, classes, and other non-serializable types, making debugging painful.\n\nObjects with mixed function and class properties are now properly displayed:\n\n```javascript\nconsole.log({\n  one: class {},\n  two: function() {}\n});\n// Before: {}\n// After:  {\"one\":\"[object Function]\",\"two\":\"[object Function]\"}\n```\n\nNested arrays and objects with functions are now fully traversed:\n\n```javascript\nconsole.log([\n  { handler: class {} },\n  { data: [1, 2, class {}] }\n]);\n// Before: [{},{\"data\":[1,2,null]}]\n// After:  [{\"handler\":\"[object Function]\"},{\"data\":[1,2,\"[object Function]\"]}]\n```\n\nComplex objects with multiple property types are properly preserved:\n\n```javascript\nconsole.log({\n  a: [1, 2, 3],\n  b: class {},\n  c: () => {},\n  d: function() {},\n  e: [1, () => {}, function() {}, class {}, 2]\n});\n// Before: {\"a\":[1,2,3],\"e\":[1,null,null,null,2]}\n// After:  {\n//   \"a\":[1,2,3],\n//   \"b\":\"[object Function]\",\n//   \"c\":\"[object Function]\",\n//   \"d\":\"[object Function]\",\n//   \"e\":[1,\"[object Function]\",\"[object Function]\",\"[object Function]\",2]\n// }\n```\n\nCircular references are now properly detected and marked:\n\n```javascript\nconst obj = {\n  fn: function() {},\n  foo: {}\n};\nobj.foo = obj;\n\nconsole.log(obj);\n// Before: [object Object]\n// After:  {\"fn\":\"[object Function]\",\"foo\":\"[Circular]\"}\n```\n\nThis improvement makes debugging k6 test scripts significantly easier when working with API responses, event handlers, and complex state objects.\n\n### `experimental/websockets` - Close Code and Reason Support [#5376](https://github.com/grafana/k6/pull/5376)\n\nThe experimental WebSockets module now supports sending close codes and reasons when closing connections, and properly captures close event information. This is essential for testing WebSocket\nimplementations that rely on specific close codes to determine whether a connection was closed normally or due to an error.\n\n```javascript\nimport ws from 'k6/experimental/websockets';\n\nexport default function () {\n  const socket = ws.connect('ws://example.com', (socket) => {\n    socket.on('close', (data) => {\n      console.log(`Connection closed with code: ${data.code}, reason: ${data.reason}`);\n      // Output: Connection closed with code: 1000, reason: Normal closure\n    });\n  });\n\n  // Close with code and reason\n  socket.close(1000, 'Normal closure');\n}\n```\n\nThanks, @etodanik, for the contribution 🎉\n\n### Subcommand Extension Support [#5399](https://github.com/grafana/k6/pull/5399)\n\nExtensions can now register custom subcommands under the `k6 x` namespace, enabling custom command-line tools that integrate seamlessly with k6. This provides a consistent and discoverable way for extensions to offer specialized CLI utilities while maintaining k6's familiar command structure.\n\nExtensions can now define custom commands like:\n\n```bash\nk6 x my-tool --help\nk6 x debug --inspect\n```\n\nThis integration pattern allows extension authors to provide powerful tooling that feels native to the k6 ecosystem.\n\n### DNS Resolver Access [#5421](https://github.com/grafana/k6/pull/5421)\n\nExtensions can now access k6's DNS resolver for custom DNS handling and networking extensions. The resolver respects k6's configuration including `hosts` overrides, custom DNS servers, and DNS caching settings. This enables extensions to use it directly instead of having to reproduce the functionality. Which also makes them work the same way as native modules.\n\n### Machine-Readable Summary Format [#5338](https://github.com/grafana/k6/pull/5338)\n\nA new machine-readable summary format for the end-of-test summary is now available, providing structured, programmatic shapes via `--summary-export` and `handleSummary()`. This format is designed for easier integration with external systems and analytics pipelines.\n\nThe new format is currently opt-in via the `--new-machine-readable-summary` flag or `K6_NEW_MACHINE_READABLE_SUMMARY` environment variable, and will become the default in k6 v2:\n\n```bash\nk6 run script.js --new-machine-readable-summary --summary-export=summary.json\n```\n\nThis makes it easier to integrate k6 results into CI/CD pipelines, dashboards, and custom analysis tools.\n\n### URL-Based Secret Management [#5413](https://github.com/grafana/k6/pull/5413)\n\nThe secret management system now supports URL-based secret sources, allowing k6 to fetch secrets from HTTP endpoints. This let users implement a simple HTTP API to provide secrets to a test. There is mock implementation, but no particular production ready implementation is provided at this time. In the future there is potential for proxies to other systems including HashiCorp Vault, AWS Secrets Manager or Azure Key Vault.\n\n## UX improvements and enhancements\n\n- [#5458](https://github.com/grafana/k6/pull/5458) Adds link to k6 extensions list in README for better discoverability.\n- [#5366](https://github.com/grafana/k6/pull/5366) Adds multi-source secret example for better documentation of secret management patterns.\n\n## Bug fixes\n\n- [#5374](https://github.com/grafana/k6/pull/5374) Fixes `getBy*` selectors when using quotes inside element names.\n- [#5477](https://github.com/grafana/k6/pull/5477) Fixes retry mechanism when frame has been detached.\n- [#5461](https://github.com/grafana/k6/pull/5461) Fixes panic when using nil `page.on` handlers.\n- [#5401](https://github.com/grafana/k6/pull/5401) Fixes panic when assigning to nil headers and cookies when host is not found. Thanks, @chojs23, for the contribution 🎉\n- [#5379](https://github.com/grafana/k6/pull/5379) Fixes browsers not being stopped in tests due to `EndIteration`.\n- [#5439](https://github.com/grafana/k6/pull/5439) Fixes loading files with spaces.\n- [#5406](https://github.com/grafana/k6/pull/5406) Fixes error messages after Sobek/goja changes.\n- [#5381](https://github.com/grafana/k6/pull/5381) Fixes version command JSON output for output extensions.\n- [#5358](https://github.com/grafana/k6/pull/5358) Fixes sending correct data when using `ArrayViews` in experimental/websockets.\n- [#5488](https://github.com/grafana/k6/pull/5488) Fixes a goroutine leak when performing CDP requests.\n\n## Maintenance and internal improvements\n\n- [#5464](https://github.com/grafana/k6/pull/5464) Adds `ExecutionStatusMarkedAsFailed` status for improved test execution tracking.\n- [#5467](https://github.com/grafana/k6/pull/5467) Refactors span error recording to avoid boilerplate code.\n- [#5438](https://github.com/grafana/k6/pull/5438) Unblocks the release workflow for package publishing.\n- [#5436](https://github.com/grafana/k6/pull/5436) Optimizes browser module allocations and improves CI stability.\n- [#5411](https://github.com/grafana/k6/pull/5411) Extends base config and stops updating go.mod toolchain.\n- [#5408](https://github.com/grafana/k6/pull/5408) Removes redundant GitHub Actions rule.\n- [#5415](https://github.com/grafana/k6/pull/5415) Updates Sobek dependency to latest version.\n- [#5392](https://github.com/grafana/k6/pull/5392) Updates OpenTelemetry proto module to v1.9.0.\n- [#5357](https://github.com/grafana/k6/pull/5357) Refactors browser module task queue usage.\n- [#5378](https://github.com/grafana/k6/pull/5378) Fixes `TestNavigationSpanCreation` test in the browser module.\n- [#5482](https://github.com/grafana/k6/pull/5482) Fixes tests and subcommand handling in version command.\n- [#5255](https://github.com/grafana/k6/pull/5255) Updates gRPC module to v1.77.0.\n- [#5506](https://github.com/grafana/k6/pull/5506) Updates xk6-redis to v0.3.6.\n- [#5473](https://github.com/grafana/k6/pull/5473) Updates compression library to v1.18.2.\n- [#5505](https://github.com/grafana/k6/pull/5505) Removes `close` call in integration tests.\n- [#5517](https://github.com/grafana/k6/pull/5517) Removes `SECURITY.md` to sync with Grafana's org-wide security policy documentation.\n- [#5528](https://github.com/grafana/k6/pull/5528) Resolves CVE-2025-61729. Thanks, @SimKev2, for the contribution 🎉\n\n## Roadmap\n\n### Deprecation of First Input Delay (FID) Web Vital\n\nFollowing the official [web vitals guidance](https://web.dev/blog/fid), First Input Delay (FID) is no longer a Core Web Vital as of September 9, 2024, having been replaced by Interaction to Next Paint (INP). The k6 browser module already emits INP metrics, and we're planning to deprecate FID support to align with industry standards.\n\nFID only measures the delay before the browser runs your event handler, so it ignores the time your code takes and the delay to paint the UI—often underestimating how slow an interaction feels. INP captures the full interaction latency (input delay + processing + next paint) across a page’s interactions, so it better reflects real user-perceived responsiveness and is replacing FID.\n\n#### Action required\n\nIf you're currently using FID in your test scripts for thresholds or relying on it in external integrations, you should migrate to using INP as soon as possible.\n\n```javascript\n// Instead of relying on FID\nexport const options = {\n  thresholds: {\n    // 'browser_web_vital_fid': ['p(95)<100'], // Deprecated\n    'browser_web_vital_inp': ['p(95)<200'], // Use INP instead\n  },\n};\n```\n\nThis change ensures k6 browser testing stays aligned with modern web performance best practices and Core Web Vitals standards.\n"
  },
  {
    "path": "release notes/v1.6.0.md",
    "content": "k6 v1.6.0 is here 🎉! This release includes:\n\n- Cloud commands now support configurable default Grafana Cloud stack.\n- New `k6 deps` command for analyzing script dependencies.\n- Browser APIs enhancements with `frameLocator()`, `goBack()`, `goForward()` methods.\n- Crypto module adds PBKDF2 support for password-based key derivation.\n- `jslib` gets a new TOTP library for time-based one-time password generation and validation.\n- New [mcp-k6](https://github.com/grafana/mcp-k6) MCP server for AI-assisted k6 script writing.\n\n## Breaking changes\n\nThere are no breaking changes in this release.\n\n## New features\n\n### Configurable default stack for Cloud commands [#5420](https://github.com/grafana/k6/pull/5420)\n\nCloud commands now support configuring the default Grafana Cloud stack you want to use. The stack slug (or stack id) is used by the Cloud to determine which default project to use when not explicitly provided.\n\nPreviously, users had to specify the project id for every test run. With this change, you can configure a default stack during login, and k6 will use it to automatically resolve the appropriate default project. This is particularly useful for organizations with multiple Grafana Cloud stacks or when working across different teams and environments.\n\nUsers can also set up a specific stack for every test run, either using the new option `stackID` or the environment variable `K6_CLOUD_STACK_ID`.\n\nPlease note that, in k6 v2, this stack information will become **mandatory** to run a test.\n\n```bash\n# Login interactively and select default stack\nk6 cloud login\n\n# Login and set default stack with token\nk6 cloud login --token $MY_TOKEN --stack my-stack-slug\n\n# Run test using the configured default stack\nk6 cloud run script.js\n\n# Run test using a specific stack\nK6_CLOUD_STACK_ID=12345 k6 cloud run script.js\n\n# Stack id can also be set in the options\nexport const options = {\n  cloud: {\n    stackID: 123,\n    projectID: 789,  // If the project does not belong to the stack, this will throw an error\n  },\n};\n```\n\nThis simplifies the cloud testing workflow and prepares k6 for upcoming changes to the Grafana Cloud k6 authentication process, where the stack will eventually become mandatory.\n\n### `k6 deps` command and manifest support [#5410](https://github.com/grafana/k6/pull/5410), [#5427](https://github.com/grafana/k6/pull/5427)\n\nA new `k6 deps` command is now available to analyze and list all dependencies of a given script or archive. This is particularly useful for understanding which extensions are required to run a script, especially when using auto extension resolution.\n\nThe command identifies all imports in your script and lists dependencies that might be needed for building a new binary with auto extension resolution. Like auto extension resolution itself, this only accounts for imports, not dynamic `require()` calls.\n\n```bash\n# Analyze script dependencies\nk6 deps script.js\n\n# Output in JSON format for programmatic consumption\nk6 deps --json script.js\n\n# Analyze archived test dependencies\nk6 deps archive.tar\n```\n\nThis makes it easier to understand extension requirements, share scripts with clear dependency information, and integrate k6 into automated build pipelines.\n\nIn addition, k6 now supports a manifest that specifies default version constraints for dependencies when no version is defined in the script using pragmas. If a dependency is imported without an explicit version, it defaults to \"*\", and the manifest can be used to replace that with a concrete version constraint.\n\nThe manifest is set through an environment variable as JSON with keys being a dependency and values being constraints:\n\n```\nK6_DEPENDENCIES_MANIFEST='{\"k6/x/faker\": \">=v0.4.4\"}' k6 run scripts.js\n```\n\nIn this example, if the script only imports `k6/x/faker` and does not use a `use k6 with k6/x/faker ...` directive, it will set the version constraint to `>=v0.4.4`. It will not make any changes if `k6/x/faker` is not a dependency of the script at all.\n\n### Browser module: `frameLocator()` method [#5487](https://github.com/grafana/k6/pull/5487)\n\nThe browser module now supports [`frameLocator()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/locator/framelocator/) on `Page`, `Frame`, `Locator`, and `FrameLocator` objects. This method creates a locator for working with `iframe` elements without the need to explicitly switch contexts, making it much easier to interact with embedded content.\n\nFrame locators are particularly valuable when testing applications with nested iframes, as they allow you to chain locators naturally while maintaining readability:\n\n<details>\n<summary>Click to expand example code</summary>\n\n```javascript\nimport { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  try {\n    await page.goto('https://example.com');\n\n    // Locate an iframe and interact with elements inside it\n    const frame = page.frameLocator('#payment-iframe');\n    await frame.locator('#card-number').fill('4242424242424242');\n    await frame.locator('#submit-button').click();\n\n    // Chain frame locators for nested iframes\n    const nestedFrame = page\n      .frameLocator('#outer-frame')\n      .frameLocator('#inner-frame');\n    await nestedFrame.locator('#nested-content').click();\n  } finally {\n    await page.close();\n  }\n}\n```\n\n</details>\n\nThis complements existing frame handling methods and provides a more intuitive API for working with iframe-heavy applications.\n\n### Browser module: `goBack()` and `goForward()` navigation methods [#5494](https://github.com/grafana/k6/pull/5494)\n\nThe browser module now supports [`page.goBack()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/goback/) and [`page.goForward()`](https://grafana.com/docs/k6/latest/javascript-api/k6-browser/page/goforward/) methods for browser history navigation. These methods allow you to navigate the page's history, similar to clicking the browser's back/forward buttons.\n\n<details>\n<summary>Click to expand example code</summary>\n\n```javascript\nimport { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  try {\n    await page.goto('https://example.com');\n    await page.goto('https://example.com/page2');\n    \n    // Navigate back to the previous page\n    await page.goBack();\n    \n    // Navigate forward again\n    await page.goForward();\n    \n    // Both methods support optional timeout and waitUntil parameters\n    await page.goBack({ waitUntil: 'networkidle' });\n  } finally {\n    await page.close();\n  }\n}\n```\n\n</details>\n\n### Browser module: Request event handlers [#5481](https://github.com/grafana/k6/pull/5481), [#5486](https://github.com/grafana/k6/pull/5486)\n\nThe browser module now supports `page.on('requestfailed')` and `page.on('requestfinished')` event handlers, enabling better monitoring and debugging of network activity during browser tests.\n\nThe `requestfailed` event fires when a request fails (network errors, aborts, etc.), while `requestfinished` fires when a request completes successfully. \n\n<details>\n<summary>Click to expand example code</summary>\n\n```javascript\nimport { browser } from 'k6/browser';\n\nexport const options = {\n  scenarios: {\n    ui: {\n      executor: 'shared-iterations',\n      options: {\n        browser: {\n          type: 'chromium',\n        },\n      },\n    },\n  },\n};\n\nexport default async function () {\n  const page = await browser.newPage();\n\n  // Monitor failed requests\n  page.on('requestfailed', (request) => {\n    console.log(`Request failed: ${request.url()}`);\n  });\n\n  // Monitor successful requests\n  page.on('requestfinished', (request) => {\n    console.log(`Request finished: ${request.url()}`);\n  });\n\n  await page.goto('https://example.com');\n  await page.close();\n}\n```\n\n</details>\n\nThese event handlers provide deeper insights into network behavior during browser testing and help identify issues that might not be immediately visible.\n\n### Crypto module: PBKDF2 support [#5380](https://github.com/grafana/k6/pull/5380)\n\nThe crypto module now supports PBKDF2 for deriving cryptographic keys from passwords. PBKDF2 is widely used for password hashing and key derivation in security-sensitive applications, and this addition enables testing of systems that use PBKDF2 for authentication or encryption.\n\nFor usage examples, check out the [one provided](https://github.com/grafana/k6/blob/b7c19129a8dc5a69bb519e7b313eab6473114e6f/examples/webcrypto/derive_key/derive-key-pbkdf2.js) in the repository or refer to the [documentation](https://grafana.com/docs/k6/latest/javascript-api/crypto/pbkdf2params).\n\n### WebSockets module is now stable [#5586](https://github.com/grafana/k6/pull/5586)\n\nThe websockets module has been promoted to stable status and is now available via the `k6/websockets` path.\nThe experimental `k6/experimental/websockets` module will be removed in a future release. Users should migrate to the stable `k6/websockets` module.\n\nTo migrate, simply update your import statement:\n\n```javascript\n// Old (experimental)\nimport ws from 'k6/experimental/websockets';\n\n// New (stable)\nimport ws from 'k6/websockets';\n```\n\nNo other changes are required because the API is the same.\n\n### Console logging: ArrayBuffer and TypedArray support [#5496](https://github.com/grafana/k6/pull/5496)\n\n`console.log()` now properly displays `ArrayBuffer` and `TypedArray` objects, making it easier to debug binary data handling in your test scripts. Previously, these types would not display useful information, making debugging difficult when working with binary protocols, file uploads, or WebSocket binary messages.\n\n<details>\n<summary>Click to expand example code</summary>\n\n```javascript\n// Log ArrayBuffer - shows detailed byte contents\nconst buffer = new ArrayBuffer(8);\nconst view = new Int32Array(buffer);\nview[0] = 4;\nview[1] = 2;\nconsole.log(buffer);\n// Output: ArrayBuffer { [Uint8Contents]: <04 00 00 00 02 00 00 00>, byteLength: 8 }\n\n// Log TypedArrays - shows type, length, and values\nconst int32 = new Int32Array([4, 2]);\nconsole.log(int32);\n// Output: Int32Array(2) [ 4, 2 ]\n\n// Nested objects with TypedArrays\nconsole.log({ v: int32 });\n// Output: { v: Int32Array(2) [ 4, 2 ] }\n\n// Complex nested structures\nconsole.log({ \n  name: \"test\", \n  buffer: buffer, \n  view: int32 \n});\n// Output: { name: \"test\", buffer: ArrayBuffer {...}, view: Int32Array(2) [...] }\n```\n\n</details>\n\n### Configurable TLS version for Experimental Prometheus output [#5537](https://github.com/grafana/k6/pull/5537)\n\nThe experimental Prometheus remote write output now supports configuring the minimum TLS version used for connections. This allows you to meet specific security requirements or compatibility constraints when sending metrics to Prometheus endpoints.\n\nIf not set, the default minimum TLS version is 1.3.\n\n```bash\nK6_PROMETHEUS_RW_TLS_MIN_VERSION=1.3 k6 run script.js -o experimental-prometheus-rw\n```\n\n### A new TOTP library [k6-totp](https://github.com/grafana/k6-jslib-totp)\n\nA new TOTP (Time-based One-Time Password) library is now available in [jslib.k6.io](https://jslib.k6.io), enabling k6 scripts to generate and validate time-based one-time passwords. This is particularly useful for testing applications that use TOTP-based two-factor authentication (2FA), such as authenticator apps like Google Authenticator or Authy. See the documentation at [k6-totp](https://grafana.com/docs/k6/latest/javascript-api/jslib/totp/).\n\n<details>\n<summary>Click to expand example code</summary>\n\n```javascript\nimport http from 'k6/http';\nimport { TOTP } from 'https://jslib.k6.io/totp/1.0.0/index.js';\n\nexport default async function () {\n  // Initialize TOTP with your secret key (base32 encoded)\n  // The second parameter is the number of digits (typically 6 or 8)\n  const totp = new TOTP('GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ', 6);\n\n  // Generate the current TOTP code\n  const code = await totp.gen();\n  console.log(`Generated TOTP code: ${code}`);\n\n  // Use the TOTP code in authentication\n  const response = http.post('https://api.example.com/login', JSON.stringify({\n    username: 'user@example.com',\n    password: 'password123',\n    totpCode: code\n  }), {\n    headers: { 'Content-Type': 'application/json' }\n  });\n\n  // Optionally verify a TOTP code\n  const isValid = await totp.verify(code);\n  console.log(`Code is valid: ${isValid}`);\n}\n```\n\n</details>\n\nThe library follows [the standard TOTP RFC 6238 specification](https://datatracker.ietf.org/doc/html/rfc6238), ensuring compatibility with standard authenticator applications.\n\n### Introducing mcp-k6: AI-assisted k6 script writing [mcp-k6](https://github.com/grafana/mcp-k6)\n\n[mcp-k6](https://github.com/grafana/mcp-k6) is an experimental [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server for k6. Once connected to your AI assistant or MCP-compatible editor (such as Cursor, VS Code, or Claude Desktop), it helps you write better k6 scripts faster and run them with confidence.\n\nWith mcp-k6, your AI assistant can:\n\n- **Write accurate scripts:** Create up-to-date scripts by referring to embedded k6 documentation and TypeScript definitions to reduce API hallucinations.\n- **Validate scripts:** Catch syntax errors, missing imports, and `export default function` declarations before execution.\n- **Run tests locally:** Execute scripts and review results without leaving your editor.\n- **Generate scripts:** Create tests from requirements using guided prompts that follow k6 best practices.\n- **Convert browser tests:** Transform Playwright tests into k6 browser scripts while preserving test logic.\n\nTo get started, install mcp-k6 via Docker, Homebrew, or from source, then configure it with your editor. See the [documentation](https://grafana.com/docs/k6/latest/set-up/configure-ai-assistant/) for installation instructions and setup guides.\n\n## UX improvements and enhancements\n\n- [#5423](https://github.com/grafana/k6/pull/5423) Adds new execution status `ExecutionStatusMarkedAsFailed` when a test is explicitly marked as failed using `exec.test.fail()`.\n- [#5590](https://github.com/grafana/k6/pull/5590) Adds deprecation notice to encourage users to configure their stack when using Cloud CLI commands.\n- [#5607](https://github.com/grafana/k6/pull/5607), [#5608](https://github.com/grafana/k6/pull/5608) Documentation improvements for Cloud CLI commands.\n\n## Bug fixes\n\n- [#5503](https://github.com/grafana/k6/pull/5503) Fixes a memory leak in `csv.parse()` where each VU created its own copy of CSV data instead of sharing it.\n- [#5425](https://github.com/grafana/k6/pull/5425) Fixes CLI validation of summary trend stats to properly accept valid configurations.\n- [#5132](https://github.com/grafana/k6/pull/5132) Fixes missing exception when using `saltLength: 0` with RSA-PSS sign/verify operations.\n- [#5602](https://github.com/grafana/k6/pull/5602) Fixes `Config.String()` in the OpenTelemetry output to properly display `ExporterProtocol`.\n- [#5578](https://github.com/grafana/k6/pull/5578) Fixes error hiding when the secret value is empty.\n- [#5546](https://github.com/grafana/k6/pull/5546) Corrects JSON error position reporting in HTTP requests.\n- [#5526](https://github.com/grafana/k6/pull/5526) Fixes browser context cancellation during target attachment to prevent test flakiness.\n- [#5611](https://github.com/grafana/k6/pull/5611) Fixes the fallback directory for the binaries cache when it's not possible to get one from the system.\n\n## Maintenance and internal improvements\n\n- [#5603](https://github.com/grafana/k6/pull/5603) Upgrades Alpine images in the Dockerfile to the latest versions.\n- [#5498](https://github.com/grafana/k6/pull/5498) Makes `WaitForEvent` mapping more type-safe and consistent by using a typed event name parameter instead of a raw string.\n- [#5561](https://github.com/grafana/k6/pull/5561) Improves context-cancellation visibility in browser module by preserving and surfacing deterministic cancellation causes, helping diagnose race conditions and flaky tests.\n- [#5414](https://github.com/grafana/k6/pull/5414) Makes `make generate` command OS-agnostic for cross-platform compatibility.\n- [#5245](https://github.com/grafana/k6/pull/5245) Replaces `github.com/jhump/protoreflect/desc/protoparse` with `github.com/bufbuild/protocompile` for better protobuf parsing.\n- [#5465](https://github.com/grafana/k6/pull/5465) Adds new `cloudapi/v6` package with authentication features.\n- [#5573](https://github.com/grafana/k6/pull/5573) Optimizes cloud login by running legacy migration only once.\n- [#5570](https://github.com/grafana/k6/pull/5570) Moves browser tests into its own test workflow for improved CI performance.\n- [#5560](https://github.com/grafana/k6/pull/5560) Refactors browser module mouse options parsing to mapping layer.\n- [#5554](https://github.com/grafana/k6/pull/5554) Refactors `onAttachedToTarget` context done detection for better maintainability.\n- [#5553](https://github.com/grafana/k6/pull/5553) Fixes `TestFlushMaxSeriesInBatch` non-deterministic behavior.\n- [#5489](https://github.com/grafana/k6/pull/5489) Addresses `frameLocator` PR review comments and improves code organization.\n- [#5559](https://github.com/grafana/k6/pull/5559) Updates issue auto-assignment to exclude internal team members.\n- [#5536](https://github.com/grafana/k6/pull/5536) Configures stale PR workflow to close PRs after 2 months of inactivity.\n- [#5568](https://github.com/grafana/k6/pull/5568) Disables flaky tests in CI.\n- [#5531](https://github.com/grafana/k6/pull/5531) Improves release template for TypeScript fork synchronization.\n- [#5509](https://github.com/grafana/k6/pull/5509), [#5508](https://github.com/grafana/k6/pull/5508) Updates error logging from error to debug level for user-unactionable internal issues.\n- [#5621](https://github.com/grafana/k6/pull/5621) Disables `t.Parallel()` on `TestCompile` for now, to reduce flakiness in CI.\n\n## Roadmap\n\nWe've started looking into k6 v2! The major release will focus on introducing breaking changes that have accumulated throughout the v1.x series, such as removing deprecated APIs and changing default behaviors. New features will continue to be incrementally released in v1.x minor versions as usual until the v2.0.0 release.\n\n## External contributors\n\nA huge thank you to the external contributors who helped during this release: @LBaronceli, @baeseokjae, @chojs23, @pkalsi97, @weillercarvalho, @ariasmn, @rahulmedicharla, @janHildebrandt98 and @shota3506! 🙏\n"
  },
  {
    "path": "release notes/v1.6.1.md",
    "content": "k6 `v1.6.1` is here! This patch release includes:\n\n- Bug fix for a race condition in the experimental CSV module\n- Bug fix for manifest k6 version override\n- Version updates for Go toolchain and Docker images\n\n## Bug fixes\n\n- [#5632](https://github.com/grafana/k6/pull/5632) Fixes a race condition in the `experimental/csv` module when multiple files with async code use `csv.parse` in parallel during initialization.\n- [#5642](https://github.com/grafana/k6/pull/5642) Fixes an issue where k6 was not always added as a build dependency, preventing manifests from overriding the k6 version.\n\n## Maintenance and security updates\n\n- [#5641](https://github.com/grafana/k6/pull/5641) Adds chromium as an explicit dependency for `with-browser` Docker image.\n- [#5646](https://github.com/grafana/k6/pull/5646) Updates Go toolchain version to 1.24.13.\n- [#5654](https://github.com/grafana/k6/pull/5654) Updates the used Go version in the Docker image to v1.25.7.\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"github>grafana/grafana-renovate-config//presets/k6/k6-engine-base.json\",\n    \"schedule:weekly\"\n  ],\n  \"ignorePaths\": [\n    \"**/vendor/**\",\n    \".github/workflows/xk6-tests/**\"\n  ],\n  \"prConcurrentLimit\": 50,\n  \"packageRules\": [\n    {\n      \"description\": \"Enable gomod updates with common options\",\n      \"matchManagers\": [\n        \"gomod\"\n      ],\n      \"enabled\": true,\n      \"postUpdateOptions\": [\n        \"gomodTidy\",\n        \"gomodUpdateImportPaths\"\n      ]\n    },\n    {\n      \"description\": \"Do not update indirect dependencies\",\n      \"matchManagers\": [\"gomod\"],\n      \"matchDepTypes\": [\"indirect\"],\n      \"enabled\": false\n    },\n    {\n      \"groupName\": \"golangx\",\n      \"description\": \"Group golang.org/x modules\",\n      \"matchManagers\": [\n        \"gomod\"\n      ],\n      \"matchPackageNames\": [\n        \"/^golang\\\\.org/x//\"\n      ]\n    },\n    {\n      \"groupName\": \"googles\",\n      \"description\": \"Group google.golang.org modules\",\n      \"matchManagers\": [\n        \"gomod\"\n      ],\n      \"matchPackageNames\": [\n        \"/^google\\\\.golang\\\\.org//\"\n      ]\n    },\n    {\n      \"description\": \"Disable list for frozen Go modules - see Dependencies.md and modtools_frozen.yml\",\n      \"matchManagers\": [\n        \"gomod\"\n      ],\n      \"enabled\": false,\n      \"matchPackageNames\": [\n        \"github.com/andybalholm/cascadia\",\n        \"github.com/sirupsen/logrus\",\n        \"github.com/spf13/afero\",\n        \"github.com/spf13/cobra\",\n        \"github.com/spf13/pflag\",\n        \"github.com/influxdata/influxdb1-client\",\n        \"gopkg.in/guregu/null.v3\",\n        \"gopkg.in/yaml.v3\"\n      ]\n    },\n    {\n      \"description\": \"k6 dockerfiles\",\n      \"matchManagers\": [\n        \"docker\"\n      ],\n      \"ignorePaths\": [\n        \"packaging/**\"\n      ],\n      \"extends\": [\n        \"schedule:monthly\"\n      ]\n    },\n    {\n      \"description\": \"Dockerfiles packaging tool\",\n      \"matchManagers\": [\n        \"docker\"\n      ],\n      \"matchFileNames\": [\n        \"packaging/**\"\n      ],\n      \"extends\": [\n        \"schedule:quarterly\"\n      ]\n    },\n    {\n      \"groupName\": \"examples/\",\n      \"description\": \"Grouped updates for examples folder with a low frequency\",\n      \"matchFileNames\": [\n        \"examples/**\"\n      ],\n      \"extends\": [\n        \"schedule:quarterly\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "secretsource/doc.go",
    "content": "// Package secretsource is a package to provide secret source interface and common functionality\n// This functionality is to be used to provide k6 with a way to get secrets and help it handle them correctly.\n// Predominantly by redacting them from logs.\npackage secretsource\n"
  },
  {
    "path": "secretsource/extension.go",
    "content": "package secretsource\n\nimport (\n\t\"github.com/sirupsen/logrus\"\n\t\"go.k6.io/k6/ext\"\n\t\"go.k6.io/k6/internal/usage\"\n\t\"go.k6.io/k6/lib/fsext\"\n)\n\n// Constructor returns an instance of a secret source extension module.\n// This should return an instance of [Source] given the parameters.\n// The Secret Source should not log its secrets and any returned secret will be cached and redacted\n// by the [Manager]. No additional work needs to be done by the Secret source apart from retrieving\n// the secret.\ntype Constructor func(Params) (Source, error)\n\n// Source is the interface a secret source needs to implement\ntype Source interface {\n\t// Human readable description to be printed on the cli\n\tDescription() string\n\t// Get retrives the value for a given key and returns it.\n\t// Logging the value before it is returned is going to lead to it being leaked.\n\t// The error might lead to an exception visible to users.\n\tGet(key string) (value string, err error)\n}\n\n// Params contains all possible constructor parameters an output may need.\ntype Params struct {\n\tConfigArgument string // the string on the cli\n\n\tLogger      logrus.FieldLogger\n\tEnvironment map[string]string\n\tFS          fsext.Fs\n\tUsage       *usage.Usage\n}\n\n// RegisterExtension registers the given secret source extension constructor.\n// This function panics if a module with the same name is already registered.\nfunc RegisterExtension(name string, c Constructor) {\n\text.Register(name, ext.SecretSourceExtension, c)\n}\n"
  },
  {
    "path": "secretsource/hook.go",
    "content": "package secretsource\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// secretsHook is a Logrus hook for hiding secrets from entries before they get logged\ntype secretsHook struct {\n\tsecrets  []string\n\tmx       sync.RWMutex\n\treplacer *strings.Replacer\n}\n\n// Levels is part of the [logrus.Hook]\nfunc (s *secretsHook) Levels() []logrus.Level { return logrus.AllLevels }\n\n// Add is used to add a new secret to be redacted.\n// Adding the same secret multiple times will not error, but is not recommended.\n// It is users job to not keep adding the same secret over time but only once.\nfunc (s *secretsHook) add(secret string) {\n\tif strings.TrimSpace(secret) == \"\" {\n\t\treturn\n\t}\n\ts.mx.Lock()\n\tdefer s.mx.Unlock()\n\ts.secrets = append(s.secrets, secret, \"***SECRET_REDACTED***\")\n\ts.replacer = strings.NewReplacer(s.secrets...)\n}\n\n// Fire is part of the [logrus.Hook]\nfunc (s *secretsHook) Fire(entry *logrus.Entry) error {\n\ts.mx.Lock()\n\t// there is no way for us to get a secret after we got a log for it so we can use that to cache the replacer\n\treplacer := s.replacer\n\ts.mx.Unlock()\n\tif replacer == nil { // no secrets no work\n\t\treturn nil\n\t}\n\tentry.Message = replacer.Replace(entry.Message)\n\n\t// replace both keys and values with\n\tfor k, v := range entry.Data {\n\t\tnewk := replacer.Replace(k)\n\t\tif newk != k {\n\t\t\tentry.Data[newk] = v\n\t\t\tdelete(entry.Data, k)\n\t\t\tk = newk\n\t\t}\n\t\tentry.Data[k] = recursiveReplace(v, replacer)\n\t}\n\n\treturn nil\n}\n\nfunc recursiveReplace(v any, replacer *strings.Replacer) any {\n\tswitch s := v.(type) {\n\tcase string:\n\t\treturn replacer.Replace(s)\n\tcase int, uint, int64, int32, int16, int8, uint64, uint32, uint16, uint8, float32, float64:\n\t\t// if the secret is encodable in 64 bits ... it is probably not a great secret\n\t\treturn v\n\tcase time.Duration:\n\t\treturn v\n\t}\n\treturn fmt.Sprintf(\"Had a logrus.fields value with type %T, \"+\n\t\t\"please report that this is unsupported and will be redacted in all logs in case it contains secrets\", v)\n}\n"
  },
  {
    "path": "secretsource/hook_test.go",
    "content": "package secretsource\n\nimport (\n\t\"testing\"\n\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestSecretsHookAddIgnoresEmptySecrets(t *testing.T) {\n\tt.Parallel()\n\n\thook := &secretsHook{}\n\n\t// Add an empty secret - this should not cause global redaction\n\thook.add(\"\")\n\n\t// Add a normal secret\n\thook.add(\"actualsecret\")\n\n\tentry := &logrus.Entry{\n\t\tMessage: \"This is a test message with actualsecret in it\",\n\t\tData:    logrus.Fields{},\n\t}\n\n\terr := hook.Fire(entry)\n\trequire.NoError(t, err)\n\n\t// The message should have \"actualsecret\" redacted but should still be readable\n\t// It should NOT be character-by-character redacted\n\tassert.Equal(t, \"This is a test message with ***SECRET_REDACTED*** in it\", entry.Message)\n\tassert.NotContains(t, entry.Message, \"***SECRET_REDACTED***T***SECRET_REDACTED***h***SECRET_REDACTED***\")\n}\n\nfunc TestSecretsHookFireWithNoSecretsLeavesMessageUnchanged(t *testing.T) {\n\tt.Parallel()\n\n\thook := &secretsHook{}\n\n\t// Add only an empty secret\n\thook.add(\"\")\n\n\tentry := &logrus.Entry{\n\t\tMessage: \"This is a normal message\",\n\t\tData:    logrus.Fields{},\n\t}\n\n\terr := hook.Fire(entry)\n\trequire.NoError(t, err)\n\n\t// The message should remain unchanged\n\tassert.Equal(t, \"This is a normal message\", entry.Message)\n}\n\nfunc TestSecretsHook_NormalOperation(t *testing.T) {\n\tt.Parallel()\n\n\thook := &secretsHook{}\n\n\thook.add(\"secret123\")\n\thook.add(\"anotherSecret\")\n\n\tentry := &logrus.Entry{\n\t\tMessage: \"Log with secret123 and anotherSecret\",\n\t\tData: logrus.Fields{\n\t\t\t\"key1\": \"value with secret123\",\n\t\t\t\"key2\": \"value with anotherSecret\",\n\t\t},\n\t}\n\n\terr := hook.Fire(entry)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"Log with ***SECRET_REDACTED*** and ***SECRET_REDACTED***\", entry.Message)\n\tassert.Equal(t, \"value with ***SECRET_REDACTED***\", entry.Data[\"key1\"])\n\tassert.Equal(t, \"value with ***SECRET_REDACTED***\", entry.Data[\"key2\"])\n}\n\nfunc TestSecretsHook_RecursiveReplace(t *testing.T) {\n\tt.Parallel()\n\n\thook := &secretsHook{}\n\thook.add(\"mysecret\")\n\n\tentry := &logrus.Entry{\n\t\tMessage: \"Test\",\n\t\tData: logrus.Fields{\n\t\t\t\"stringValue\": \"contains mysecret here\",\n\t\t\t\"intValue\":    42,\n\t\t\t\"floatValue\":  3.14,\n\t\t},\n\t}\n\n\terr := hook.Fire(entry)\n\trequire.NoError(t, err)\n\n\tassert.Equal(t, \"contains ***SECRET_REDACTED*** here\", entry.Data[\"stringValue\"])\n\tassert.Equal(t, 42, entry.Data[\"intValue\"])\n\tassert.Equal(t, 3.14, entry.Data[\"floatValue\"])\n}\n"
  },
  {
    "path": "secretsource/manager.go",
    "content": "package secretsource\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/sirupsen/logrus\"\n)\n\n// DefaultSourceName is the name for the default secret source\nconst DefaultSourceName = \"default\"\n\n// Manager manages secrets making certain for them to be redacted from logs\ntype Manager struct {\n\thook    *secretsHook\n\tsources map[string]Source\n\tcache   map[string]*sync.Map\n}\n\n// NewManager returns a new NewManager with the provided secretsHook and will redact secrets from the hook\nfunc NewManager(sources map[string]Source) (*Manager, logrus.Hook, error) {\n\tcache := make(map[string]*sync.Map, len(sources)-1)\n\thook := &secretsHook{}\n\tif len(sources) == 0 {\n\t\treturn &Manager{\n\t\t\thook:  hook,\n\t\t\tcache: cache,\n\t\t}, hook, nil\n\t}\n\tdefaultSource := sources[\"default\"]\n\tif defaultSource != nil {\n\t\tcache[\"default\"] = new(sync.Map)\n\t}\n\tfor k, source := range sources {\n\t\tif k == \"default\" {\n\t\t\tcontinue\n\t\t}\n\t\tif source == defaultSource {\n\t\t\tcache[k] = cache[\"default\"]\n\t\t\tcontinue\n\t\t}\n\t\tcache[k] = new(sync.Map)\n\t}\n\tsm := &Manager{\n\t\thook:    hook,\n\t\tsources: sources,\n\t\tcache:   cache,\n\t}\n\treturn sm, hook, nil\n}\n\n// Get is the way to get a secret for the provided source name and key of the secret.\n// It can be used with the [DefaultSourceName].\n// This automatically starts redacting the secret before returning it.\nfunc (sm *Manager) Get(sourceName, key string) (string, error) {\n\tif len(sm.cache) == 0 {\n\t\treturn \"\", errors.New(\"no secret sources are configured\")\n\t}\n\tsourceCache, ok := sm.cache[sourceName]\n\tif !ok {\n\t\treturn \"\", UnknownSourceError(sourceName)\n\t}\n\tv, ok := sourceCache.Load(key)\n\tif ok {\n\t\treturn v.(string), nil //nolint:forcetypeassert\n\t}\n\tsource := sm.sources[sourceName]\n\tvalue, err := source.Get(key)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tsourceCache.Store(key, value)\n\tsm.hook.add(value)\n\treturn value, err\n}\n\n// UnknownSourceError is returned when a unknown source is requested\ntype UnknownSourceError string\n\nfunc (u UnknownSourceError) Error() string {\n\treturn fmt.Sprintf(\"no secret source with name %q is configured\", (string)(u))\n}\n"
  },
  {
    "path": "subcommand/extension.go",
    "content": "// Package subcommand provides functionality for registering k6 subcommand extensions.\n//\n// This package allows external modules to register new subcommands that will be\n// available in the k6 CLI. Subcommand extensions are registered during\n// package initialization and are called when the corresponding subcommand is invoked.\npackage subcommand\n\nimport (\n\t\"github.com/spf13/cobra\"\n\t\"go.k6.io/k6/cmd/state\"\n\t\"go.k6.io/k6/ext\"\n)\n\n// Constructor is a function type that creates a new cobra.Command for a subcommand extension.\n// It receives a GlobalState instance that provides access to configuration, logging,\n// file system, and other shared k6 runtime state. The returned Command will be\n// integrated into k6's CLI as a subcommand.\n//\n// WARNING: The GlobalState parameter is read-only and must not be modified or altered\n// in any way. Modifying the GlobalState can make k6 core unstable and lead to\n// unpredictable behavior.\ntype Constructor func(*state.GlobalState) *cobra.Command\n\n// RegisterExtension registers a subcommand extension with the given name and constructor function.\n//\n// The name parameter specifies the subcommand name that users will invoke (e.g., \"k6 <name>\").\n// The constructor function will be called when k6 initializes to create the cobra.Command\n// instance for this subcommand.\n//\n// This function must be called during package initialization (typically in an init() function)\n// and will panic if a subcommand with the same name is already registered.\n//\n// The name parameter and the returned Command's Name() must match.\nfunc RegisterExtension(name string, c Constructor) {\n\text.Register(name, ext.SubcommandExtension, c)\n}\n"
  },
  {
    "path": "vendor/buf.build/gen/go/gogo/protobuf/protocolbuffers/go/LICENSE",
    "content": "Copyright (c) 2013, The GoGo Authors. All rights reserved.\n\nProtocol Buffers for Go with Gadgets\n\nGo support for Protocol Buffers - Google's data interchange format\n\nCopyright 2010 The Go Authors.  All rights reserved.\nhttps://github.com/golang/protobuf\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n    * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"
  },
  {
    "path": "vendor/buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto/gogo.pb.go",
    "content": "// Protocol Buffers for Go with Gadgets\n//\n// Copyright (c) 2013, The GoGo Authors. All rights reserved.\n// http://github.com/gogo/protobuf\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11\n// \tprotoc        (unknown)\n// source: gogoproto/gogo.proto\n\n//go:build !protoopaque\n\npackage gogoproto\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdescriptorpb \"google.golang.org/protobuf/types/descriptorpb\"\n\treflect \"reflect\"\n\tunsafe \"unsafe\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nvar file_gogoproto_gogo_proto_extTypes = []protoimpl.ExtensionInfo{\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62001,\n\t\tName:          \"gogoproto.goproto_enum_prefix\",\n\t\tTag:           \"varint,62001,opt,name=goproto_enum_prefix\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62021,\n\t\tName:          \"gogoproto.goproto_enum_stringer\",\n\t\tTag:           \"varint,62021,opt,name=goproto_enum_stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62022,\n\t\tName:          \"gogoproto.enum_stringer\",\n\t\tTag:           \"varint,62022,opt,name=enum_stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         62023,\n\t\tName:          \"gogoproto.enum_customname\",\n\t\tTag:           \"bytes,62023,opt,name=enum_customname\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62024,\n\t\tName:          \"gogoproto.enumdecl\",\n\t\tTag:           \"varint,62024,opt,name=enumdecl\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumValueOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         66001,\n\t\tName:          \"gogoproto.enumvalue_customname\",\n\t\tTag:           \"bytes,66001,opt,name=enumvalue_customname\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63001,\n\t\tName:          \"gogoproto.goproto_getters_all\",\n\t\tTag:           \"varint,63001,opt,name=goproto_getters_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63002,\n\t\tName:          \"gogoproto.goproto_enum_prefix_all\",\n\t\tTag:           \"varint,63002,opt,name=goproto_enum_prefix_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63003,\n\t\tName:          \"gogoproto.goproto_stringer_all\",\n\t\tTag:           \"varint,63003,opt,name=goproto_stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63004,\n\t\tName:          \"gogoproto.verbose_equal_all\",\n\t\tTag:           \"varint,63004,opt,name=verbose_equal_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63005,\n\t\tName:          \"gogoproto.face_all\",\n\t\tTag:           \"varint,63005,opt,name=face_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63006,\n\t\tName:          \"gogoproto.gostring_all\",\n\t\tTag:           \"varint,63006,opt,name=gostring_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63007,\n\t\tName:          \"gogoproto.populate_all\",\n\t\tTag:           \"varint,63007,opt,name=populate_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63008,\n\t\tName:          \"gogoproto.stringer_all\",\n\t\tTag:           \"varint,63008,opt,name=stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63009,\n\t\tName:          \"gogoproto.onlyone_all\",\n\t\tTag:           \"varint,63009,opt,name=onlyone_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63013,\n\t\tName:          \"gogoproto.equal_all\",\n\t\tTag:           \"varint,63013,opt,name=equal_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63014,\n\t\tName:          \"gogoproto.description_all\",\n\t\tTag:           \"varint,63014,opt,name=description_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63015,\n\t\tName:          \"gogoproto.testgen_all\",\n\t\tTag:           \"varint,63015,opt,name=testgen_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63016,\n\t\tName:          \"gogoproto.benchgen_all\",\n\t\tTag:           \"varint,63016,opt,name=benchgen_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63017,\n\t\tName:          \"gogoproto.marshaler_all\",\n\t\tTag:           \"varint,63017,opt,name=marshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63018,\n\t\tName:          \"gogoproto.unmarshaler_all\",\n\t\tTag:           \"varint,63018,opt,name=unmarshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63019,\n\t\tName:          \"gogoproto.stable_marshaler_all\",\n\t\tTag:           \"varint,63019,opt,name=stable_marshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63020,\n\t\tName:          \"gogoproto.sizer_all\",\n\t\tTag:           \"varint,63020,opt,name=sizer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63021,\n\t\tName:          \"gogoproto.goproto_enum_stringer_all\",\n\t\tTag:           \"varint,63021,opt,name=goproto_enum_stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63022,\n\t\tName:          \"gogoproto.enum_stringer_all\",\n\t\tTag:           \"varint,63022,opt,name=enum_stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63023,\n\t\tName:          \"gogoproto.unsafe_marshaler_all\",\n\t\tTag:           \"varint,63023,opt,name=unsafe_marshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63024,\n\t\tName:          \"gogoproto.unsafe_unmarshaler_all\",\n\t\tTag:           \"varint,63024,opt,name=unsafe_unmarshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63025,\n\t\tName:          \"gogoproto.goproto_extensions_map_all\",\n\t\tTag:           \"varint,63025,opt,name=goproto_extensions_map_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63026,\n\t\tName:          \"gogoproto.goproto_unrecognized_all\",\n\t\tTag:           \"varint,63026,opt,name=goproto_unrecognized_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63027,\n\t\tName:          \"gogoproto.gogoproto_import\",\n\t\tTag:           \"varint,63027,opt,name=gogoproto_import\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63028,\n\t\tName:          \"gogoproto.protosizer_all\",\n\t\tTag:           \"varint,63028,opt,name=protosizer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63029,\n\t\tName:          \"gogoproto.compare_all\",\n\t\tTag:           \"varint,63029,opt,name=compare_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63030,\n\t\tName:          \"gogoproto.typedecl_all\",\n\t\tTag:           \"varint,63030,opt,name=typedecl_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63031,\n\t\tName:          \"gogoproto.enumdecl_all\",\n\t\tTag:           \"varint,63031,opt,name=enumdecl_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63032,\n\t\tName:          \"gogoproto.goproto_registration\",\n\t\tTag:           \"varint,63032,opt,name=goproto_registration\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63033,\n\t\tName:          \"gogoproto.messagename_all\",\n\t\tTag:           \"varint,63033,opt,name=messagename_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63034,\n\t\tName:          \"gogoproto.goproto_sizecache_all\",\n\t\tTag:           \"varint,63034,opt,name=goproto_sizecache_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63035,\n\t\tName:          \"gogoproto.goproto_unkeyed_all\",\n\t\tTag:           \"varint,63035,opt,name=goproto_unkeyed_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64001,\n\t\tName:          \"gogoproto.goproto_getters\",\n\t\tTag:           \"varint,64001,opt,name=goproto_getters\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64003,\n\t\tName:          \"gogoproto.goproto_stringer\",\n\t\tTag:           \"varint,64003,opt,name=goproto_stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64004,\n\t\tName:          \"gogoproto.verbose_equal\",\n\t\tTag:           \"varint,64004,opt,name=verbose_equal\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64005,\n\t\tName:          \"gogoproto.face\",\n\t\tTag:           \"varint,64005,opt,name=face\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64006,\n\t\tName:          \"gogoproto.gostring\",\n\t\tTag:           \"varint,64006,opt,name=gostring\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64007,\n\t\tName:          \"gogoproto.populate\",\n\t\tTag:           \"varint,64007,opt,name=populate\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         67008,\n\t\tName:          \"gogoproto.stringer\",\n\t\tTag:           \"varint,67008,opt,name=stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64009,\n\t\tName:          \"gogoproto.onlyone\",\n\t\tTag:           \"varint,64009,opt,name=onlyone\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64013,\n\t\tName:          \"gogoproto.equal\",\n\t\tTag:           \"varint,64013,opt,name=equal\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64014,\n\t\tName:          \"gogoproto.description\",\n\t\tTag:           \"varint,64014,opt,name=description\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64015,\n\t\tName:          \"gogoproto.testgen\",\n\t\tTag:           \"varint,64015,opt,name=testgen\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64016,\n\t\tName:          \"gogoproto.benchgen\",\n\t\tTag:           \"varint,64016,opt,name=benchgen\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64017,\n\t\tName:          \"gogoproto.marshaler\",\n\t\tTag:           \"varint,64017,opt,name=marshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64018,\n\t\tName:          \"gogoproto.unmarshaler\",\n\t\tTag:           \"varint,64018,opt,name=unmarshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64019,\n\t\tName:          \"gogoproto.stable_marshaler\",\n\t\tTag:           \"varint,64019,opt,name=stable_marshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64020,\n\t\tName:          \"gogoproto.sizer\",\n\t\tTag:           \"varint,64020,opt,name=sizer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64023,\n\t\tName:          \"gogoproto.unsafe_marshaler\",\n\t\tTag:           \"varint,64023,opt,name=unsafe_marshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64024,\n\t\tName:          \"gogoproto.unsafe_unmarshaler\",\n\t\tTag:           \"varint,64024,opt,name=unsafe_unmarshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64025,\n\t\tName:          \"gogoproto.goproto_extensions_map\",\n\t\tTag:           \"varint,64025,opt,name=goproto_extensions_map\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64026,\n\t\tName:          \"gogoproto.goproto_unrecognized\",\n\t\tTag:           \"varint,64026,opt,name=goproto_unrecognized\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64028,\n\t\tName:          \"gogoproto.protosizer\",\n\t\tTag:           \"varint,64028,opt,name=protosizer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64029,\n\t\tName:          \"gogoproto.compare\",\n\t\tTag:           \"varint,64029,opt,name=compare\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64030,\n\t\tName:          \"gogoproto.typedecl\",\n\t\tTag:           \"varint,64030,opt,name=typedecl\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64033,\n\t\tName:          \"gogoproto.messagename\",\n\t\tTag:           \"varint,64033,opt,name=messagename\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64034,\n\t\tName:          \"gogoproto.goproto_sizecache\",\n\t\tTag:           \"varint,64034,opt,name=goproto_sizecache\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64035,\n\t\tName:          \"gogoproto.goproto_unkeyed\",\n\t\tTag:           \"varint,64035,opt,name=goproto_unkeyed\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65001,\n\t\tName:          \"gogoproto.nullable\",\n\t\tTag:           \"varint,65001,opt,name=nullable\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65002,\n\t\tName:          \"gogoproto.embed\",\n\t\tTag:           \"varint,65002,opt,name=embed\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65003,\n\t\tName:          \"gogoproto.customtype\",\n\t\tTag:           \"bytes,65003,opt,name=customtype\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65004,\n\t\tName:          \"gogoproto.customname\",\n\t\tTag:           \"bytes,65004,opt,name=customname\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65005,\n\t\tName:          \"gogoproto.jsontag\",\n\t\tTag:           \"bytes,65005,opt,name=jsontag\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65006,\n\t\tName:          \"gogoproto.moretags\",\n\t\tTag:           \"bytes,65006,opt,name=moretags\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65007,\n\t\tName:          \"gogoproto.casttype\",\n\t\tTag:           \"bytes,65007,opt,name=casttype\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65008,\n\t\tName:          \"gogoproto.castkey\",\n\t\tTag:           \"bytes,65008,opt,name=castkey\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65009,\n\t\tName:          \"gogoproto.castvalue\",\n\t\tTag:           \"bytes,65009,opt,name=castvalue\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65010,\n\t\tName:          \"gogoproto.stdtime\",\n\t\tTag:           \"varint,65010,opt,name=stdtime\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65011,\n\t\tName:          \"gogoproto.stdduration\",\n\t\tTag:           \"varint,65011,opt,name=stdduration\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65012,\n\t\tName:          \"gogoproto.wktpointer\",\n\t\tTag:           \"varint,65012,opt,name=wktpointer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n}\n\n// Extension fields to descriptorpb.EnumOptions.\nvar (\n\t// optional bool goproto_enum_prefix = 62001;\n\tE_GoprotoEnumPrefix = &file_gogoproto_gogo_proto_extTypes[0]\n\t// optional bool goproto_enum_stringer = 62021;\n\tE_GoprotoEnumStringer = &file_gogoproto_gogo_proto_extTypes[1]\n\t// optional bool enum_stringer = 62022;\n\tE_EnumStringer = &file_gogoproto_gogo_proto_extTypes[2]\n\t// optional string enum_customname = 62023;\n\tE_EnumCustomname = &file_gogoproto_gogo_proto_extTypes[3]\n\t// optional bool enumdecl = 62024;\n\tE_Enumdecl = &file_gogoproto_gogo_proto_extTypes[4]\n)\n\n// Extension fields to descriptorpb.EnumValueOptions.\nvar (\n\t// optional string enumvalue_customname = 66001;\n\tE_EnumvalueCustomname = &file_gogoproto_gogo_proto_extTypes[5]\n)\n\n// Extension fields to descriptorpb.FileOptions.\nvar (\n\t// optional bool goproto_getters_all = 63001;\n\tE_GoprotoGettersAll = &file_gogoproto_gogo_proto_extTypes[6]\n\t// optional bool goproto_enum_prefix_all = 63002;\n\tE_GoprotoEnumPrefixAll = &file_gogoproto_gogo_proto_extTypes[7]\n\t// optional bool goproto_stringer_all = 63003;\n\tE_GoprotoStringerAll = &file_gogoproto_gogo_proto_extTypes[8]\n\t// optional bool verbose_equal_all = 63004;\n\tE_VerboseEqualAll = &file_gogoproto_gogo_proto_extTypes[9]\n\t// optional bool face_all = 63005;\n\tE_FaceAll = &file_gogoproto_gogo_proto_extTypes[10]\n\t// optional bool gostring_all = 63006;\n\tE_GostringAll = &file_gogoproto_gogo_proto_extTypes[11]\n\t// optional bool populate_all = 63007;\n\tE_PopulateAll = &file_gogoproto_gogo_proto_extTypes[12]\n\t// optional bool stringer_all = 63008;\n\tE_StringerAll = &file_gogoproto_gogo_proto_extTypes[13]\n\t// optional bool onlyone_all = 63009;\n\tE_OnlyoneAll = &file_gogoproto_gogo_proto_extTypes[14]\n\t// optional bool equal_all = 63013;\n\tE_EqualAll = &file_gogoproto_gogo_proto_extTypes[15]\n\t// optional bool description_all = 63014;\n\tE_DescriptionAll = &file_gogoproto_gogo_proto_extTypes[16]\n\t// optional bool testgen_all = 63015;\n\tE_TestgenAll = &file_gogoproto_gogo_proto_extTypes[17]\n\t// optional bool benchgen_all = 63016;\n\tE_BenchgenAll = &file_gogoproto_gogo_proto_extTypes[18]\n\t// optional bool marshaler_all = 63017;\n\tE_MarshalerAll = &file_gogoproto_gogo_proto_extTypes[19]\n\t// optional bool unmarshaler_all = 63018;\n\tE_UnmarshalerAll = &file_gogoproto_gogo_proto_extTypes[20]\n\t// optional bool stable_marshaler_all = 63019;\n\tE_StableMarshalerAll = &file_gogoproto_gogo_proto_extTypes[21]\n\t// optional bool sizer_all = 63020;\n\tE_SizerAll = &file_gogoproto_gogo_proto_extTypes[22]\n\t// optional bool goproto_enum_stringer_all = 63021;\n\tE_GoprotoEnumStringerAll = &file_gogoproto_gogo_proto_extTypes[23]\n\t// optional bool enum_stringer_all = 63022;\n\tE_EnumStringerAll = &file_gogoproto_gogo_proto_extTypes[24]\n\t// optional bool unsafe_marshaler_all = 63023;\n\tE_UnsafeMarshalerAll = &file_gogoproto_gogo_proto_extTypes[25]\n\t// optional bool unsafe_unmarshaler_all = 63024;\n\tE_UnsafeUnmarshalerAll = &file_gogoproto_gogo_proto_extTypes[26]\n\t// optional bool goproto_extensions_map_all = 63025;\n\tE_GoprotoExtensionsMapAll = &file_gogoproto_gogo_proto_extTypes[27]\n\t// optional bool goproto_unrecognized_all = 63026;\n\tE_GoprotoUnrecognizedAll = &file_gogoproto_gogo_proto_extTypes[28]\n\t// optional bool gogoproto_import = 63027;\n\tE_GogoprotoImport = &file_gogoproto_gogo_proto_extTypes[29]\n\t// optional bool protosizer_all = 63028;\n\tE_ProtosizerAll = &file_gogoproto_gogo_proto_extTypes[30]\n\t// optional bool compare_all = 63029;\n\tE_CompareAll = &file_gogoproto_gogo_proto_extTypes[31]\n\t// optional bool typedecl_all = 63030;\n\tE_TypedeclAll = &file_gogoproto_gogo_proto_extTypes[32]\n\t// optional bool enumdecl_all = 63031;\n\tE_EnumdeclAll = &file_gogoproto_gogo_proto_extTypes[33]\n\t// optional bool goproto_registration = 63032;\n\tE_GoprotoRegistration = &file_gogoproto_gogo_proto_extTypes[34]\n\t// optional bool messagename_all = 63033;\n\tE_MessagenameAll = &file_gogoproto_gogo_proto_extTypes[35]\n\t// optional bool goproto_sizecache_all = 63034;\n\tE_GoprotoSizecacheAll = &file_gogoproto_gogo_proto_extTypes[36]\n\t// optional bool goproto_unkeyed_all = 63035;\n\tE_GoprotoUnkeyedAll = &file_gogoproto_gogo_proto_extTypes[37]\n)\n\n// Extension fields to descriptorpb.MessageOptions.\nvar (\n\t// optional bool goproto_getters = 64001;\n\tE_GoprotoGetters = &file_gogoproto_gogo_proto_extTypes[38]\n\t// optional bool goproto_stringer = 64003;\n\tE_GoprotoStringer = &file_gogoproto_gogo_proto_extTypes[39]\n\t// optional bool verbose_equal = 64004;\n\tE_VerboseEqual = &file_gogoproto_gogo_proto_extTypes[40]\n\t// optional bool face = 64005;\n\tE_Face = &file_gogoproto_gogo_proto_extTypes[41]\n\t// optional bool gostring = 64006;\n\tE_Gostring = &file_gogoproto_gogo_proto_extTypes[42]\n\t// optional bool populate = 64007;\n\tE_Populate = &file_gogoproto_gogo_proto_extTypes[43]\n\t// optional bool stringer = 67008;\n\tE_Stringer = &file_gogoproto_gogo_proto_extTypes[44]\n\t// optional bool onlyone = 64009;\n\tE_Onlyone = &file_gogoproto_gogo_proto_extTypes[45]\n\t// optional bool equal = 64013;\n\tE_Equal = &file_gogoproto_gogo_proto_extTypes[46]\n\t// optional bool description = 64014;\n\tE_Description = &file_gogoproto_gogo_proto_extTypes[47]\n\t// optional bool testgen = 64015;\n\tE_Testgen = &file_gogoproto_gogo_proto_extTypes[48]\n\t// optional bool benchgen = 64016;\n\tE_Benchgen = &file_gogoproto_gogo_proto_extTypes[49]\n\t// optional bool marshaler = 64017;\n\tE_Marshaler = &file_gogoproto_gogo_proto_extTypes[50]\n\t// optional bool unmarshaler = 64018;\n\tE_Unmarshaler = &file_gogoproto_gogo_proto_extTypes[51]\n\t// optional bool stable_marshaler = 64019;\n\tE_StableMarshaler = &file_gogoproto_gogo_proto_extTypes[52]\n\t// optional bool sizer = 64020;\n\tE_Sizer = &file_gogoproto_gogo_proto_extTypes[53]\n\t// optional bool unsafe_marshaler = 64023;\n\tE_UnsafeMarshaler = &file_gogoproto_gogo_proto_extTypes[54]\n\t// optional bool unsafe_unmarshaler = 64024;\n\tE_UnsafeUnmarshaler = &file_gogoproto_gogo_proto_extTypes[55]\n\t// optional bool goproto_extensions_map = 64025;\n\tE_GoprotoExtensionsMap = &file_gogoproto_gogo_proto_extTypes[56]\n\t// optional bool goproto_unrecognized = 64026;\n\tE_GoprotoUnrecognized = &file_gogoproto_gogo_proto_extTypes[57]\n\t// optional bool protosizer = 64028;\n\tE_Protosizer = &file_gogoproto_gogo_proto_extTypes[58]\n\t// optional bool compare = 64029;\n\tE_Compare = &file_gogoproto_gogo_proto_extTypes[59]\n\t// optional bool typedecl = 64030;\n\tE_Typedecl = &file_gogoproto_gogo_proto_extTypes[60]\n\t// optional bool messagename = 64033;\n\tE_Messagename = &file_gogoproto_gogo_proto_extTypes[61]\n\t// optional bool goproto_sizecache = 64034;\n\tE_GoprotoSizecache = &file_gogoproto_gogo_proto_extTypes[62]\n\t// optional bool goproto_unkeyed = 64035;\n\tE_GoprotoUnkeyed = &file_gogoproto_gogo_proto_extTypes[63]\n)\n\n// Extension fields to descriptorpb.FieldOptions.\nvar (\n\t// optional bool nullable = 65001;\n\tE_Nullable = &file_gogoproto_gogo_proto_extTypes[64]\n\t// optional bool embed = 65002;\n\tE_Embed = &file_gogoproto_gogo_proto_extTypes[65]\n\t// optional string customtype = 65003;\n\tE_Customtype = &file_gogoproto_gogo_proto_extTypes[66]\n\t// optional string customname = 65004;\n\tE_Customname = &file_gogoproto_gogo_proto_extTypes[67]\n\t// optional string jsontag = 65005;\n\tE_Jsontag = &file_gogoproto_gogo_proto_extTypes[68]\n\t// optional string moretags = 65006;\n\tE_Moretags = &file_gogoproto_gogo_proto_extTypes[69]\n\t// optional string casttype = 65007;\n\tE_Casttype = &file_gogoproto_gogo_proto_extTypes[70]\n\t// optional string castkey = 65008;\n\tE_Castkey = &file_gogoproto_gogo_proto_extTypes[71]\n\t// optional string castvalue = 65009;\n\tE_Castvalue = &file_gogoproto_gogo_proto_extTypes[72]\n\t// optional bool stdtime = 65010;\n\tE_Stdtime = &file_gogoproto_gogo_proto_extTypes[73]\n\t// optional bool stdduration = 65011;\n\tE_Stdduration = &file_gogoproto_gogo_proto_extTypes[74]\n\t// optional bool wktpointer = 65012;\n\tE_Wktpointer = &file_gogoproto_gogo_proto_extTypes[75]\n)\n\nvar File_gogoproto_gogo_proto protoreflect.FileDescriptor\n\nconst file_gogoproto_gogo_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x14gogoproto/gogo.proto\\x12\\tgogoproto\\x1a google/protobuf/descriptor.proto:N\\n\" +\n\t\"\\x13goproto_enum_prefix\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xb1\\xe4\\x03 \\x01(\\bR\\x11goprotoEnumPrefix:R\\n\" +\n\t\"\\x15goproto_enum_stringer\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc5\\xe4\\x03 \\x01(\\bR\\x13goprotoEnumStringer:C\\n\" +\n\t\"\\renum_stringer\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc6\\xe4\\x03 \\x01(\\bR\\fenumStringer:G\\n\" +\n\t\"\\x0fenum_customname\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc7\\xe4\\x03 \\x01(\\tR\\x0eenumCustomname::\\n\" +\n\t\"\\benumdecl\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc8\\xe4\\x03 \\x01(\\bR\\benumdecl:V\\n\" +\n\t\"\\x14enumvalue_customname\\x12!.google.protobuf.EnumValueOptions\\x18у\\x04 \\x01(\\tR\\x13enumvalueCustomname:N\\n\" +\n\t\"\\x13goproto_getters_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x99\\xec\\x03 \\x01(\\bR\\x11goprotoGettersAll:U\\n\" +\n\t\"\\x17goproto_enum_prefix_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9a\\xec\\x03 \\x01(\\bR\\x14goprotoEnumPrefixAll:P\\n\" +\n\t\"\\x14goproto_stringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9b\\xec\\x03 \\x01(\\bR\\x12goprotoStringerAll:J\\n\" +\n\t\"\\x11verbose_equal_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9c\\xec\\x03 \\x01(\\bR\\x0fverboseEqualAll:9\\n\" +\n\t\"\\bface_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9d\\xec\\x03 \\x01(\\bR\\afaceAll:A\\n\" +\n\t\"\\fgostring_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9e\\xec\\x03 \\x01(\\bR\\vgostringAll:A\\n\" +\n\t\"\\fpopulate_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9f\\xec\\x03 \\x01(\\bR\\vpopulateAll:A\\n\" +\n\t\"\\fstringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa0\\xec\\x03 \\x01(\\bR\\vstringerAll:?\\n\" +\n\t\"\\vonlyone_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa1\\xec\\x03 \\x01(\\bR\\n\" +\n\t\"onlyoneAll:;\\n\" +\n\t\"\\tequal_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa5\\xec\\x03 \\x01(\\bR\\bequalAll:G\\n\" +\n\t\"\\x0fdescription_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa6\\xec\\x03 \\x01(\\bR\\x0edescriptionAll:?\\n\" +\n\t\"\\vtestgen_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa7\\xec\\x03 \\x01(\\bR\\n\" +\n\t\"testgenAll:A\\n\" +\n\t\"\\fbenchgen_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa8\\xec\\x03 \\x01(\\bR\\vbenchgenAll:C\\n\" +\n\t\"\\rmarshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa9\\xec\\x03 \\x01(\\bR\\fmarshalerAll:G\\n\" +\n\t\"\\x0funmarshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xaa\\xec\\x03 \\x01(\\bR\\x0eunmarshalerAll:P\\n\" +\n\t\"\\x14stable_marshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xab\\xec\\x03 \\x01(\\bR\\x12stableMarshalerAll:;\\n\" +\n\t\"\\tsizer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xac\\xec\\x03 \\x01(\\bR\\bsizerAll:Y\\n\" +\n\t\"\\x19goproto_enum_stringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xad\\xec\\x03 \\x01(\\bR\\x16goprotoEnumStringerAll:J\\n\" +\n\t\"\\x11enum_stringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xae\\xec\\x03 \\x01(\\bR\\x0fenumStringerAll:P\\n\" +\n\t\"\\x14unsafe_marshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xaf\\xec\\x03 \\x01(\\bR\\x12unsafeMarshalerAll:T\\n\" +\n\t\"\\x16unsafe_unmarshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb0\\xec\\x03 \\x01(\\bR\\x14unsafeUnmarshalerAll:[\\n\" +\n\t\"\\x1agoproto_extensions_map_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb1\\xec\\x03 \\x01(\\bR\\x17goprotoExtensionsMapAll:X\\n\" +\n\t\"\\x18goproto_unrecognized_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb2\\xec\\x03 \\x01(\\bR\\x16goprotoUnrecognizedAll:I\\n\" +\n\t\"\\x10gogoproto_import\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb3\\xec\\x03 \\x01(\\bR\\x0fgogoprotoImport:E\\n\" +\n\t\"\\x0eprotosizer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb4\\xec\\x03 \\x01(\\bR\\rprotosizerAll:?\\n\" +\n\t\"\\vcompare_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb5\\xec\\x03 \\x01(\\bR\\n\" +\n\t\"compareAll:A\\n\" +\n\t\"\\ftypedecl_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb6\\xec\\x03 \\x01(\\bR\\vtypedeclAll:A\\n\" +\n\t\"\\fenumdecl_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb7\\xec\\x03 \\x01(\\bR\\venumdeclAll:Q\\n\" +\n\t\"\\x14goproto_registration\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb8\\xec\\x03 \\x01(\\bR\\x13goprotoRegistration:G\\n\" +\n\t\"\\x0fmessagename_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb9\\xec\\x03 \\x01(\\bR\\x0emessagenameAll:R\\n\" +\n\t\"\\x15goproto_sizecache_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xba\\xec\\x03 \\x01(\\bR\\x13goprotoSizecacheAll:N\\n\" +\n\t\"\\x13goproto_unkeyed_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xbb\\xec\\x03 \\x01(\\bR\\x11goprotoUnkeyedAll:J\\n\" +\n\t\"\\x0fgoproto_getters\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x81\\xf4\\x03 \\x01(\\bR\\x0egoprotoGetters:L\\n\" +\n\t\"\\x10goproto_stringer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x83\\xf4\\x03 \\x01(\\bR\\x0fgoprotoStringer:F\\n\" +\n\t\"\\rverbose_equal\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x84\\xf4\\x03 \\x01(\\bR\\fverboseEqual:5\\n\" +\n\t\"\\x04face\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x85\\xf4\\x03 \\x01(\\bR\\x04face:=\\n\" +\n\t\"\\bgostring\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x86\\xf4\\x03 \\x01(\\bR\\bgostring:=\\n\" +\n\t\"\\bpopulate\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x87\\xf4\\x03 \\x01(\\bR\\bpopulate:=\\n\" +\n\t\"\\bstringer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xc0\\x8b\\x04 \\x01(\\bR\\bstringer:;\\n\" +\n\t\"\\aonlyone\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x89\\xf4\\x03 \\x01(\\bR\\aonlyone:7\\n\" +\n\t\"\\x05equal\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x8d\\xf4\\x03 \\x01(\\bR\\x05equal:C\\n\" +\n\t\"\\vdescription\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x8e\\xf4\\x03 \\x01(\\bR\\vdescription:;\\n\" +\n\t\"\\atestgen\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x8f\\xf4\\x03 \\x01(\\bR\\atestgen:=\\n\" +\n\t\"\\bbenchgen\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x90\\xf4\\x03 \\x01(\\bR\\bbenchgen:?\\n\" +\n\t\"\\tmarshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x91\\xf4\\x03 \\x01(\\bR\\tmarshaler:C\\n\" +\n\t\"\\vunmarshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x92\\xf4\\x03 \\x01(\\bR\\vunmarshaler:L\\n\" +\n\t\"\\x10stable_marshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x93\\xf4\\x03 \\x01(\\bR\\x0fstableMarshaler:7\\n\" +\n\t\"\\x05sizer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x94\\xf4\\x03 \\x01(\\bR\\x05sizer:L\\n\" +\n\t\"\\x10unsafe_marshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x97\\xf4\\x03 \\x01(\\bR\\x0funsafeMarshaler:P\\n\" +\n\t\"\\x12unsafe_unmarshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x98\\xf4\\x03 \\x01(\\bR\\x11unsafeUnmarshaler:W\\n\" +\n\t\"\\x16goproto_extensions_map\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x99\\xf4\\x03 \\x01(\\bR\\x14goprotoExtensionsMap:T\\n\" +\n\t\"\\x14goproto_unrecognized\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9a\\xf4\\x03 \\x01(\\bR\\x13goprotoUnrecognized:A\\n\" +\n\t\"\\n\" +\n\t\"protosizer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9c\\xf4\\x03 \\x01(\\bR\\n\" +\n\t\"protosizer:;\\n\" +\n\t\"\\acompare\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9d\\xf4\\x03 \\x01(\\bR\\acompare:=\\n\" +\n\t\"\\btypedecl\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9e\\xf4\\x03 \\x01(\\bR\\btypedecl:C\\n\" +\n\t\"\\vmessagename\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xa1\\xf4\\x03 \\x01(\\bR\\vmessagename:N\\n\" +\n\t\"\\x11goproto_sizecache\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xa2\\xf4\\x03 \\x01(\\bR\\x10goprotoSizecache:J\\n\" +\n\t\"\\x0fgoproto_unkeyed\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xa3\\xf4\\x03 \\x01(\\bR\\x0egoprotoUnkeyed:;\\n\" +\n\t\"\\bnullable\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xe9\\xfb\\x03 \\x01(\\bR\\bnullable:5\\n\" +\n\t\"\\x05embed\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xea\\xfb\\x03 \\x01(\\bR\\x05embed:?\\n\" +\n\t\"\\n\" +\n\t\"customtype\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xeb\\xfb\\x03 \\x01(\\tR\\n\" +\n\t\"customtype:?\\n\" +\n\t\"\\n\" +\n\t\"customname\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xec\\xfb\\x03 \\x01(\\tR\\n\" +\n\t\"customname:9\\n\" +\n\t\"\\ajsontag\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xed\\xfb\\x03 \\x01(\\tR\\ajsontag:;\\n\" +\n\t\"\\bmoretags\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xee\\xfb\\x03 \\x01(\\tR\\bmoretags:;\\n\" +\n\t\"\\bcasttype\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xef\\xfb\\x03 \\x01(\\tR\\bcasttype:9\\n\" +\n\t\"\\acastkey\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf0\\xfb\\x03 \\x01(\\tR\\acastkey:=\\n\" +\n\t\"\\tcastvalue\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf1\\xfb\\x03 \\x01(\\tR\\tcastvalue:9\\n\" +\n\t\"\\astdtime\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf2\\xfb\\x03 \\x01(\\bR\\astdtime:A\\n\" +\n\t\"\\vstdduration\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf3\\xfb\\x03 \\x01(\\bR\\vstdduration:?\\n\" +\n\t\"\\n\" +\n\t\"wktpointer\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf4\\xfb\\x03 \\x01(\\bR\\n\" +\n\t\"wktpointerB^\\n\" +\n\t\"\\x13com.google.protobufB\\n\" +\n\t\"GoGoProtosZ;buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto\"\n\nvar file_gogoproto_gogo_proto_goTypes = []any{\n\t(*descriptorpb.EnumOptions)(nil),      // 0: google.protobuf.EnumOptions\n\t(*descriptorpb.EnumValueOptions)(nil), // 1: google.protobuf.EnumValueOptions\n\t(*descriptorpb.FileOptions)(nil),      // 2: google.protobuf.FileOptions\n\t(*descriptorpb.MessageOptions)(nil),   // 3: google.protobuf.MessageOptions\n\t(*descriptorpb.FieldOptions)(nil),     // 4: google.protobuf.FieldOptions\n}\nvar file_gogoproto_gogo_proto_depIdxs = []int32{\n\t0,  // 0: gogoproto.goproto_enum_prefix:extendee -> google.protobuf.EnumOptions\n\t0,  // 1: gogoproto.goproto_enum_stringer:extendee -> google.protobuf.EnumOptions\n\t0,  // 2: gogoproto.enum_stringer:extendee -> google.protobuf.EnumOptions\n\t0,  // 3: gogoproto.enum_customname:extendee -> google.protobuf.EnumOptions\n\t0,  // 4: gogoproto.enumdecl:extendee -> google.protobuf.EnumOptions\n\t1,  // 5: gogoproto.enumvalue_customname:extendee -> google.protobuf.EnumValueOptions\n\t2,  // 6: gogoproto.goproto_getters_all:extendee -> google.protobuf.FileOptions\n\t2,  // 7: gogoproto.goproto_enum_prefix_all:extendee -> google.protobuf.FileOptions\n\t2,  // 8: gogoproto.goproto_stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 9: gogoproto.verbose_equal_all:extendee -> google.protobuf.FileOptions\n\t2,  // 10: gogoproto.face_all:extendee -> google.protobuf.FileOptions\n\t2,  // 11: gogoproto.gostring_all:extendee -> google.protobuf.FileOptions\n\t2,  // 12: gogoproto.populate_all:extendee -> google.protobuf.FileOptions\n\t2,  // 13: gogoproto.stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 14: gogoproto.onlyone_all:extendee -> google.protobuf.FileOptions\n\t2,  // 15: gogoproto.equal_all:extendee -> google.protobuf.FileOptions\n\t2,  // 16: gogoproto.description_all:extendee -> google.protobuf.FileOptions\n\t2,  // 17: gogoproto.testgen_all:extendee -> google.protobuf.FileOptions\n\t2,  // 18: gogoproto.benchgen_all:extendee -> google.protobuf.FileOptions\n\t2,  // 19: gogoproto.marshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 20: gogoproto.unmarshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 21: gogoproto.stable_marshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 22: gogoproto.sizer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 23: gogoproto.goproto_enum_stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 24: gogoproto.enum_stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 25: gogoproto.unsafe_marshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 26: gogoproto.unsafe_unmarshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 27: gogoproto.goproto_extensions_map_all:extendee -> google.protobuf.FileOptions\n\t2,  // 28: gogoproto.goproto_unrecognized_all:extendee -> google.protobuf.FileOptions\n\t2,  // 29: gogoproto.gogoproto_import:extendee -> google.protobuf.FileOptions\n\t2,  // 30: gogoproto.protosizer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 31: gogoproto.compare_all:extendee -> google.protobuf.FileOptions\n\t2,  // 32: gogoproto.typedecl_all:extendee -> google.protobuf.FileOptions\n\t2,  // 33: gogoproto.enumdecl_all:extendee -> google.protobuf.FileOptions\n\t2,  // 34: gogoproto.goproto_registration:extendee -> google.protobuf.FileOptions\n\t2,  // 35: gogoproto.messagename_all:extendee -> google.protobuf.FileOptions\n\t2,  // 36: gogoproto.goproto_sizecache_all:extendee -> google.protobuf.FileOptions\n\t2,  // 37: gogoproto.goproto_unkeyed_all:extendee -> google.protobuf.FileOptions\n\t3,  // 38: gogoproto.goproto_getters:extendee -> google.protobuf.MessageOptions\n\t3,  // 39: gogoproto.goproto_stringer:extendee -> google.protobuf.MessageOptions\n\t3,  // 40: gogoproto.verbose_equal:extendee -> google.protobuf.MessageOptions\n\t3,  // 41: gogoproto.face:extendee -> google.protobuf.MessageOptions\n\t3,  // 42: gogoproto.gostring:extendee -> google.protobuf.MessageOptions\n\t3,  // 43: gogoproto.populate:extendee -> google.protobuf.MessageOptions\n\t3,  // 44: gogoproto.stringer:extendee -> google.protobuf.MessageOptions\n\t3,  // 45: gogoproto.onlyone:extendee -> google.protobuf.MessageOptions\n\t3,  // 46: gogoproto.equal:extendee -> google.protobuf.MessageOptions\n\t3,  // 47: gogoproto.description:extendee -> google.protobuf.MessageOptions\n\t3,  // 48: gogoproto.testgen:extendee -> google.protobuf.MessageOptions\n\t3,  // 49: gogoproto.benchgen:extendee -> google.protobuf.MessageOptions\n\t3,  // 50: gogoproto.marshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 51: gogoproto.unmarshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 52: gogoproto.stable_marshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 53: gogoproto.sizer:extendee -> google.protobuf.MessageOptions\n\t3,  // 54: gogoproto.unsafe_marshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 55: gogoproto.unsafe_unmarshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 56: gogoproto.goproto_extensions_map:extendee -> google.protobuf.MessageOptions\n\t3,  // 57: gogoproto.goproto_unrecognized:extendee -> google.protobuf.MessageOptions\n\t3,  // 58: gogoproto.protosizer:extendee -> google.protobuf.MessageOptions\n\t3,  // 59: gogoproto.compare:extendee -> google.protobuf.MessageOptions\n\t3,  // 60: gogoproto.typedecl:extendee -> google.protobuf.MessageOptions\n\t3,  // 61: gogoproto.messagename:extendee -> google.protobuf.MessageOptions\n\t3,  // 62: gogoproto.goproto_sizecache:extendee -> google.protobuf.MessageOptions\n\t3,  // 63: gogoproto.goproto_unkeyed:extendee -> google.protobuf.MessageOptions\n\t4,  // 64: gogoproto.nullable:extendee -> google.protobuf.FieldOptions\n\t4,  // 65: gogoproto.embed:extendee -> google.protobuf.FieldOptions\n\t4,  // 66: gogoproto.customtype:extendee -> google.protobuf.FieldOptions\n\t4,  // 67: gogoproto.customname:extendee -> google.protobuf.FieldOptions\n\t4,  // 68: gogoproto.jsontag:extendee -> google.protobuf.FieldOptions\n\t4,  // 69: gogoproto.moretags:extendee -> google.protobuf.FieldOptions\n\t4,  // 70: gogoproto.casttype:extendee -> google.protobuf.FieldOptions\n\t4,  // 71: gogoproto.castkey:extendee -> google.protobuf.FieldOptions\n\t4,  // 72: gogoproto.castvalue:extendee -> google.protobuf.FieldOptions\n\t4,  // 73: gogoproto.stdtime:extendee -> google.protobuf.FieldOptions\n\t4,  // 74: gogoproto.stdduration:extendee -> google.protobuf.FieldOptions\n\t4,  // 75: gogoproto.wktpointer:extendee -> google.protobuf.FieldOptions\n\t76, // [76:76] is the sub-list for method output_type\n\t76, // [76:76] is the sub-list for method input_type\n\t76, // [76:76] is the sub-list for extension type_name\n\t0,  // [0:76] is the sub-list for extension extendee\n\t0,  // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_gogoproto_gogo_proto_init() }\nfunc file_gogoproto_gogo_proto_init() {\n\tif File_gogoproto_gogo_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_gogoproto_gogo_proto_rawDesc), len(file_gogoproto_gogo_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   0,\n\t\t\tNumExtensions: 76,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_gogoproto_gogo_proto_goTypes,\n\t\tDependencyIndexes: file_gogoproto_gogo_proto_depIdxs,\n\t\tExtensionInfos:    file_gogoproto_gogo_proto_extTypes,\n\t}.Build()\n\tFile_gogoproto_gogo_proto = out.File\n\tfile_gogoproto_gogo_proto_goTypes = nil\n\tfile_gogoproto_gogo_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "vendor/buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto/gogo_protoopaque.pb.go",
    "content": "// Protocol Buffers for Go with Gadgets\n//\n// Copyright (c) 2013, The GoGo Authors. All rights reserved.\n// http://github.com/gogo/protobuf\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//     * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//     * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11\n// \tprotoc        (unknown)\n// source: gogoproto/gogo.proto\n\n//go:build protoopaque\n\npackage gogoproto\n\nimport (\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\tdescriptorpb \"google.golang.org/protobuf/types/descriptorpb\"\n\treflect \"reflect\"\n\tunsafe \"unsafe\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\nvar file_gogoproto_gogo_proto_extTypes = []protoimpl.ExtensionInfo{\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62001,\n\t\tName:          \"gogoproto.goproto_enum_prefix\",\n\t\tTag:           \"varint,62001,opt,name=goproto_enum_prefix\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62021,\n\t\tName:          \"gogoproto.goproto_enum_stringer\",\n\t\tTag:           \"varint,62021,opt,name=goproto_enum_stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62022,\n\t\tName:          \"gogoproto.enum_stringer\",\n\t\tTag:           \"varint,62022,opt,name=enum_stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         62023,\n\t\tName:          \"gogoproto.enum_customname\",\n\t\tTag:           \"bytes,62023,opt,name=enum_customname\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         62024,\n\t\tName:          \"gogoproto.enumdecl\",\n\t\tTag:           \"varint,62024,opt,name=enumdecl\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.EnumValueOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         66001,\n\t\tName:          \"gogoproto.enumvalue_customname\",\n\t\tTag:           \"bytes,66001,opt,name=enumvalue_customname\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63001,\n\t\tName:          \"gogoproto.goproto_getters_all\",\n\t\tTag:           \"varint,63001,opt,name=goproto_getters_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63002,\n\t\tName:          \"gogoproto.goproto_enum_prefix_all\",\n\t\tTag:           \"varint,63002,opt,name=goproto_enum_prefix_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63003,\n\t\tName:          \"gogoproto.goproto_stringer_all\",\n\t\tTag:           \"varint,63003,opt,name=goproto_stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63004,\n\t\tName:          \"gogoproto.verbose_equal_all\",\n\t\tTag:           \"varint,63004,opt,name=verbose_equal_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63005,\n\t\tName:          \"gogoproto.face_all\",\n\t\tTag:           \"varint,63005,opt,name=face_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63006,\n\t\tName:          \"gogoproto.gostring_all\",\n\t\tTag:           \"varint,63006,opt,name=gostring_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63007,\n\t\tName:          \"gogoproto.populate_all\",\n\t\tTag:           \"varint,63007,opt,name=populate_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63008,\n\t\tName:          \"gogoproto.stringer_all\",\n\t\tTag:           \"varint,63008,opt,name=stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63009,\n\t\tName:          \"gogoproto.onlyone_all\",\n\t\tTag:           \"varint,63009,opt,name=onlyone_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63013,\n\t\tName:          \"gogoproto.equal_all\",\n\t\tTag:           \"varint,63013,opt,name=equal_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63014,\n\t\tName:          \"gogoproto.description_all\",\n\t\tTag:           \"varint,63014,opt,name=description_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63015,\n\t\tName:          \"gogoproto.testgen_all\",\n\t\tTag:           \"varint,63015,opt,name=testgen_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63016,\n\t\tName:          \"gogoproto.benchgen_all\",\n\t\tTag:           \"varint,63016,opt,name=benchgen_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63017,\n\t\tName:          \"gogoproto.marshaler_all\",\n\t\tTag:           \"varint,63017,opt,name=marshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63018,\n\t\tName:          \"gogoproto.unmarshaler_all\",\n\t\tTag:           \"varint,63018,opt,name=unmarshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63019,\n\t\tName:          \"gogoproto.stable_marshaler_all\",\n\t\tTag:           \"varint,63019,opt,name=stable_marshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63020,\n\t\tName:          \"gogoproto.sizer_all\",\n\t\tTag:           \"varint,63020,opt,name=sizer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63021,\n\t\tName:          \"gogoproto.goproto_enum_stringer_all\",\n\t\tTag:           \"varint,63021,opt,name=goproto_enum_stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63022,\n\t\tName:          \"gogoproto.enum_stringer_all\",\n\t\tTag:           \"varint,63022,opt,name=enum_stringer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63023,\n\t\tName:          \"gogoproto.unsafe_marshaler_all\",\n\t\tTag:           \"varint,63023,opt,name=unsafe_marshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63024,\n\t\tName:          \"gogoproto.unsafe_unmarshaler_all\",\n\t\tTag:           \"varint,63024,opt,name=unsafe_unmarshaler_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63025,\n\t\tName:          \"gogoproto.goproto_extensions_map_all\",\n\t\tTag:           \"varint,63025,opt,name=goproto_extensions_map_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63026,\n\t\tName:          \"gogoproto.goproto_unrecognized_all\",\n\t\tTag:           \"varint,63026,opt,name=goproto_unrecognized_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63027,\n\t\tName:          \"gogoproto.gogoproto_import\",\n\t\tTag:           \"varint,63027,opt,name=gogoproto_import\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63028,\n\t\tName:          \"gogoproto.protosizer_all\",\n\t\tTag:           \"varint,63028,opt,name=protosizer_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63029,\n\t\tName:          \"gogoproto.compare_all\",\n\t\tTag:           \"varint,63029,opt,name=compare_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63030,\n\t\tName:          \"gogoproto.typedecl_all\",\n\t\tTag:           \"varint,63030,opt,name=typedecl_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63031,\n\t\tName:          \"gogoproto.enumdecl_all\",\n\t\tTag:           \"varint,63031,opt,name=enumdecl_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63032,\n\t\tName:          \"gogoproto.goproto_registration\",\n\t\tTag:           \"varint,63032,opt,name=goproto_registration\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63033,\n\t\tName:          \"gogoproto.messagename_all\",\n\t\tTag:           \"varint,63033,opt,name=messagename_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63034,\n\t\tName:          \"gogoproto.goproto_sizecache_all\",\n\t\tTag:           \"varint,63034,opt,name=goproto_sizecache_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FileOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         63035,\n\t\tName:          \"gogoproto.goproto_unkeyed_all\",\n\t\tTag:           \"varint,63035,opt,name=goproto_unkeyed_all\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64001,\n\t\tName:          \"gogoproto.goproto_getters\",\n\t\tTag:           \"varint,64001,opt,name=goproto_getters\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64003,\n\t\tName:          \"gogoproto.goproto_stringer\",\n\t\tTag:           \"varint,64003,opt,name=goproto_stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64004,\n\t\tName:          \"gogoproto.verbose_equal\",\n\t\tTag:           \"varint,64004,opt,name=verbose_equal\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64005,\n\t\tName:          \"gogoproto.face\",\n\t\tTag:           \"varint,64005,opt,name=face\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64006,\n\t\tName:          \"gogoproto.gostring\",\n\t\tTag:           \"varint,64006,opt,name=gostring\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64007,\n\t\tName:          \"gogoproto.populate\",\n\t\tTag:           \"varint,64007,opt,name=populate\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         67008,\n\t\tName:          \"gogoproto.stringer\",\n\t\tTag:           \"varint,67008,opt,name=stringer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64009,\n\t\tName:          \"gogoproto.onlyone\",\n\t\tTag:           \"varint,64009,opt,name=onlyone\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64013,\n\t\tName:          \"gogoproto.equal\",\n\t\tTag:           \"varint,64013,opt,name=equal\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64014,\n\t\tName:          \"gogoproto.description\",\n\t\tTag:           \"varint,64014,opt,name=description\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64015,\n\t\tName:          \"gogoproto.testgen\",\n\t\tTag:           \"varint,64015,opt,name=testgen\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64016,\n\t\tName:          \"gogoproto.benchgen\",\n\t\tTag:           \"varint,64016,opt,name=benchgen\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64017,\n\t\tName:          \"gogoproto.marshaler\",\n\t\tTag:           \"varint,64017,opt,name=marshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64018,\n\t\tName:          \"gogoproto.unmarshaler\",\n\t\tTag:           \"varint,64018,opt,name=unmarshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64019,\n\t\tName:          \"gogoproto.stable_marshaler\",\n\t\tTag:           \"varint,64019,opt,name=stable_marshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64020,\n\t\tName:          \"gogoproto.sizer\",\n\t\tTag:           \"varint,64020,opt,name=sizer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64023,\n\t\tName:          \"gogoproto.unsafe_marshaler\",\n\t\tTag:           \"varint,64023,opt,name=unsafe_marshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64024,\n\t\tName:          \"gogoproto.unsafe_unmarshaler\",\n\t\tTag:           \"varint,64024,opt,name=unsafe_unmarshaler\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64025,\n\t\tName:          \"gogoproto.goproto_extensions_map\",\n\t\tTag:           \"varint,64025,opt,name=goproto_extensions_map\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64026,\n\t\tName:          \"gogoproto.goproto_unrecognized\",\n\t\tTag:           \"varint,64026,opt,name=goproto_unrecognized\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64028,\n\t\tName:          \"gogoproto.protosizer\",\n\t\tTag:           \"varint,64028,opt,name=protosizer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64029,\n\t\tName:          \"gogoproto.compare\",\n\t\tTag:           \"varint,64029,opt,name=compare\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64030,\n\t\tName:          \"gogoproto.typedecl\",\n\t\tTag:           \"varint,64030,opt,name=typedecl\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64033,\n\t\tName:          \"gogoproto.messagename\",\n\t\tTag:           \"varint,64033,opt,name=messagename\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64034,\n\t\tName:          \"gogoproto.goproto_sizecache\",\n\t\tTag:           \"varint,64034,opt,name=goproto_sizecache\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.MessageOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         64035,\n\t\tName:          \"gogoproto.goproto_unkeyed\",\n\t\tTag:           \"varint,64035,opt,name=goproto_unkeyed\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65001,\n\t\tName:          \"gogoproto.nullable\",\n\t\tTag:           \"varint,65001,opt,name=nullable\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65002,\n\t\tName:          \"gogoproto.embed\",\n\t\tTag:           \"varint,65002,opt,name=embed\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65003,\n\t\tName:          \"gogoproto.customtype\",\n\t\tTag:           \"bytes,65003,opt,name=customtype\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65004,\n\t\tName:          \"gogoproto.customname\",\n\t\tTag:           \"bytes,65004,opt,name=customname\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65005,\n\t\tName:          \"gogoproto.jsontag\",\n\t\tTag:           \"bytes,65005,opt,name=jsontag\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65006,\n\t\tName:          \"gogoproto.moretags\",\n\t\tTag:           \"bytes,65006,opt,name=moretags\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65007,\n\t\tName:          \"gogoproto.casttype\",\n\t\tTag:           \"bytes,65007,opt,name=casttype\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65008,\n\t\tName:          \"gogoproto.castkey\",\n\t\tTag:           \"bytes,65008,opt,name=castkey\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*string)(nil),\n\t\tField:         65009,\n\t\tName:          \"gogoproto.castvalue\",\n\t\tTag:           \"bytes,65009,opt,name=castvalue\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65010,\n\t\tName:          \"gogoproto.stdtime\",\n\t\tTag:           \"varint,65010,opt,name=stdtime\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65011,\n\t\tName:          \"gogoproto.stdduration\",\n\t\tTag:           \"varint,65011,opt,name=stdduration\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n\t{\n\t\tExtendedType:  (*descriptorpb.FieldOptions)(nil),\n\t\tExtensionType: (*bool)(nil),\n\t\tField:         65012,\n\t\tName:          \"gogoproto.wktpointer\",\n\t\tTag:           \"varint,65012,opt,name=wktpointer\",\n\t\tFilename:      \"gogoproto/gogo.proto\",\n\t},\n}\n\n// Extension fields to descriptorpb.EnumOptions.\nvar (\n\t// optional bool goproto_enum_prefix = 62001;\n\tE_GoprotoEnumPrefix = &file_gogoproto_gogo_proto_extTypes[0]\n\t// optional bool goproto_enum_stringer = 62021;\n\tE_GoprotoEnumStringer = &file_gogoproto_gogo_proto_extTypes[1]\n\t// optional bool enum_stringer = 62022;\n\tE_EnumStringer = &file_gogoproto_gogo_proto_extTypes[2]\n\t// optional string enum_customname = 62023;\n\tE_EnumCustomname = &file_gogoproto_gogo_proto_extTypes[3]\n\t// optional bool enumdecl = 62024;\n\tE_Enumdecl = &file_gogoproto_gogo_proto_extTypes[4]\n)\n\n// Extension fields to descriptorpb.EnumValueOptions.\nvar (\n\t// optional string enumvalue_customname = 66001;\n\tE_EnumvalueCustomname = &file_gogoproto_gogo_proto_extTypes[5]\n)\n\n// Extension fields to descriptorpb.FileOptions.\nvar (\n\t// optional bool goproto_getters_all = 63001;\n\tE_GoprotoGettersAll = &file_gogoproto_gogo_proto_extTypes[6]\n\t// optional bool goproto_enum_prefix_all = 63002;\n\tE_GoprotoEnumPrefixAll = &file_gogoproto_gogo_proto_extTypes[7]\n\t// optional bool goproto_stringer_all = 63003;\n\tE_GoprotoStringerAll = &file_gogoproto_gogo_proto_extTypes[8]\n\t// optional bool verbose_equal_all = 63004;\n\tE_VerboseEqualAll = &file_gogoproto_gogo_proto_extTypes[9]\n\t// optional bool face_all = 63005;\n\tE_FaceAll = &file_gogoproto_gogo_proto_extTypes[10]\n\t// optional bool gostring_all = 63006;\n\tE_GostringAll = &file_gogoproto_gogo_proto_extTypes[11]\n\t// optional bool populate_all = 63007;\n\tE_PopulateAll = &file_gogoproto_gogo_proto_extTypes[12]\n\t// optional bool stringer_all = 63008;\n\tE_StringerAll = &file_gogoproto_gogo_proto_extTypes[13]\n\t// optional bool onlyone_all = 63009;\n\tE_OnlyoneAll = &file_gogoproto_gogo_proto_extTypes[14]\n\t// optional bool equal_all = 63013;\n\tE_EqualAll = &file_gogoproto_gogo_proto_extTypes[15]\n\t// optional bool description_all = 63014;\n\tE_DescriptionAll = &file_gogoproto_gogo_proto_extTypes[16]\n\t// optional bool testgen_all = 63015;\n\tE_TestgenAll = &file_gogoproto_gogo_proto_extTypes[17]\n\t// optional bool benchgen_all = 63016;\n\tE_BenchgenAll = &file_gogoproto_gogo_proto_extTypes[18]\n\t// optional bool marshaler_all = 63017;\n\tE_MarshalerAll = &file_gogoproto_gogo_proto_extTypes[19]\n\t// optional bool unmarshaler_all = 63018;\n\tE_UnmarshalerAll = &file_gogoproto_gogo_proto_extTypes[20]\n\t// optional bool stable_marshaler_all = 63019;\n\tE_StableMarshalerAll = &file_gogoproto_gogo_proto_extTypes[21]\n\t// optional bool sizer_all = 63020;\n\tE_SizerAll = &file_gogoproto_gogo_proto_extTypes[22]\n\t// optional bool goproto_enum_stringer_all = 63021;\n\tE_GoprotoEnumStringerAll = &file_gogoproto_gogo_proto_extTypes[23]\n\t// optional bool enum_stringer_all = 63022;\n\tE_EnumStringerAll = &file_gogoproto_gogo_proto_extTypes[24]\n\t// optional bool unsafe_marshaler_all = 63023;\n\tE_UnsafeMarshalerAll = &file_gogoproto_gogo_proto_extTypes[25]\n\t// optional bool unsafe_unmarshaler_all = 63024;\n\tE_UnsafeUnmarshalerAll = &file_gogoproto_gogo_proto_extTypes[26]\n\t// optional bool goproto_extensions_map_all = 63025;\n\tE_GoprotoExtensionsMapAll = &file_gogoproto_gogo_proto_extTypes[27]\n\t// optional bool goproto_unrecognized_all = 63026;\n\tE_GoprotoUnrecognizedAll = &file_gogoproto_gogo_proto_extTypes[28]\n\t// optional bool gogoproto_import = 63027;\n\tE_GogoprotoImport = &file_gogoproto_gogo_proto_extTypes[29]\n\t// optional bool protosizer_all = 63028;\n\tE_ProtosizerAll = &file_gogoproto_gogo_proto_extTypes[30]\n\t// optional bool compare_all = 63029;\n\tE_CompareAll = &file_gogoproto_gogo_proto_extTypes[31]\n\t// optional bool typedecl_all = 63030;\n\tE_TypedeclAll = &file_gogoproto_gogo_proto_extTypes[32]\n\t// optional bool enumdecl_all = 63031;\n\tE_EnumdeclAll = &file_gogoproto_gogo_proto_extTypes[33]\n\t// optional bool goproto_registration = 63032;\n\tE_GoprotoRegistration = &file_gogoproto_gogo_proto_extTypes[34]\n\t// optional bool messagename_all = 63033;\n\tE_MessagenameAll = &file_gogoproto_gogo_proto_extTypes[35]\n\t// optional bool goproto_sizecache_all = 63034;\n\tE_GoprotoSizecacheAll = &file_gogoproto_gogo_proto_extTypes[36]\n\t// optional bool goproto_unkeyed_all = 63035;\n\tE_GoprotoUnkeyedAll = &file_gogoproto_gogo_proto_extTypes[37]\n)\n\n// Extension fields to descriptorpb.MessageOptions.\nvar (\n\t// optional bool goproto_getters = 64001;\n\tE_GoprotoGetters = &file_gogoproto_gogo_proto_extTypes[38]\n\t// optional bool goproto_stringer = 64003;\n\tE_GoprotoStringer = &file_gogoproto_gogo_proto_extTypes[39]\n\t// optional bool verbose_equal = 64004;\n\tE_VerboseEqual = &file_gogoproto_gogo_proto_extTypes[40]\n\t// optional bool face = 64005;\n\tE_Face = &file_gogoproto_gogo_proto_extTypes[41]\n\t// optional bool gostring = 64006;\n\tE_Gostring = &file_gogoproto_gogo_proto_extTypes[42]\n\t// optional bool populate = 64007;\n\tE_Populate = &file_gogoproto_gogo_proto_extTypes[43]\n\t// optional bool stringer = 67008;\n\tE_Stringer = &file_gogoproto_gogo_proto_extTypes[44]\n\t// optional bool onlyone = 64009;\n\tE_Onlyone = &file_gogoproto_gogo_proto_extTypes[45]\n\t// optional bool equal = 64013;\n\tE_Equal = &file_gogoproto_gogo_proto_extTypes[46]\n\t// optional bool description = 64014;\n\tE_Description = &file_gogoproto_gogo_proto_extTypes[47]\n\t// optional bool testgen = 64015;\n\tE_Testgen = &file_gogoproto_gogo_proto_extTypes[48]\n\t// optional bool benchgen = 64016;\n\tE_Benchgen = &file_gogoproto_gogo_proto_extTypes[49]\n\t// optional bool marshaler = 64017;\n\tE_Marshaler = &file_gogoproto_gogo_proto_extTypes[50]\n\t// optional bool unmarshaler = 64018;\n\tE_Unmarshaler = &file_gogoproto_gogo_proto_extTypes[51]\n\t// optional bool stable_marshaler = 64019;\n\tE_StableMarshaler = &file_gogoproto_gogo_proto_extTypes[52]\n\t// optional bool sizer = 64020;\n\tE_Sizer = &file_gogoproto_gogo_proto_extTypes[53]\n\t// optional bool unsafe_marshaler = 64023;\n\tE_UnsafeMarshaler = &file_gogoproto_gogo_proto_extTypes[54]\n\t// optional bool unsafe_unmarshaler = 64024;\n\tE_UnsafeUnmarshaler = &file_gogoproto_gogo_proto_extTypes[55]\n\t// optional bool goproto_extensions_map = 64025;\n\tE_GoprotoExtensionsMap = &file_gogoproto_gogo_proto_extTypes[56]\n\t// optional bool goproto_unrecognized = 64026;\n\tE_GoprotoUnrecognized = &file_gogoproto_gogo_proto_extTypes[57]\n\t// optional bool protosizer = 64028;\n\tE_Protosizer = &file_gogoproto_gogo_proto_extTypes[58]\n\t// optional bool compare = 64029;\n\tE_Compare = &file_gogoproto_gogo_proto_extTypes[59]\n\t// optional bool typedecl = 64030;\n\tE_Typedecl = &file_gogoproto_gogo_proto_extTypes[60]\n\t// optional bool messagename = 64033;\n\tE_Messagename = &file_gogoproto_gogo_proto_extTypes[61]\n\t// optional bool goproto_sizecache = 64034;\n\tE_GoprotoSizecache = &file_gogoproto_gogo_proto_extTypes[62]\n\t// optional bool goproto_unkeyed = 64035;\n\tE_GoprotoUnkeyed = &file_gogoproto_gogo_proto_extTypes[63]\n)\n\n// Extension fields to descriptorpb.FieldOptions.\nvar (\n\t// optional bool nullable = 65001;\n\tE_Nullable = &file_gogoproto_gogo_proto_extTypes[64]\n\t// optional bool embed = 65002;\n\tE_Embed = &file_gogoproto_gogo_proto_extTypes[65]\n\t// optional string customtype = 65003;\n\tE_Customtype = &file_gogoproto_gogo_proto_extTypes[66]\n\t// optional string customname = 65004;\n\tE_Customname = &file_gogoproto_gogo_proto_extTypes[67]\n\t// optional string jsontag = 65005;\n\tE_Jsontag = &file_gogoproto_gogo_proto_extTypes[68]\n\t// optional string moretags = 65006;\n\tE_Moretags = &file_gogoproto_gogo_proto_extTypes[69]\n\t// optional string casttype = 65007;\n\tE_Casttype = &file_gogoproto_gogo_proto_extTypes[70]\n\t// optional string castkey = 65008;\n\tE_Castkey = &file_gogoproto_gogo_proto_extTypes[71]\n\t// optional string castvalue = 65009;\n\tE_Castvalue = &file_gogoproto_gogo_proto_extTypes[72]\n\t// optional bool stdtime = 65010;\n\tE_Stdtime = &file_gogoproto_gogo_proto_extTypes[73]\n\t// optional bool stdduration = 65011;\n\tE_Stdduration = &file_gogoproto_gogo_proto_extTypes[74]\n\t// optional bool wktpointer = 65012;\n\tE_Wktpointer = &file_gogoproto_gogo_proto_extTypes[75]\n)\n\nvar File_gogoproto_gogo_proto protoreflect.FileDescriptor\n\nconst file_gogoproto_gogo_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\x14gogoproto/gogo.proto\\x12\\tgogoproto\\x1a google/protobuf/descriptor.proto:N\\n\" +\n\t\"\\x13goproto_enum_prefix\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xb1\\xe4\\x03 \\x01(\\bR\\x11goprotoEnumPrefix:R\\n\" +\n\t\"\\x15goproto_enum_stringer\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc5\\xe4\\x03 \\x01(\\bR\\x13goprotoEnumStringer:C\\n\" +\n\t\"\\renum_stringer\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc6\\xe4\\x03 \\x01(\\bR\\fenumStringer:G\\n\" +\n\t\"\\x0fenum_customname\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc7\\xe4\\x03 \\x01(\\tR\\x0eenumCustomname::\\n\" +\n\t\"\\benumdecl\\x12\\x1c.google.protobuf.EnumOptions\\x18\\xc8\\xe4\\x03 \\x01(\\bR\\benumdecl:V\\n\" +\n\t\"\\x14enumvalue_customname\\x12!.google.protobuf.EnumValueOptions\\x18у\\x04 \\x01(\\tR\\x13enumvalueCustomname:N\\n\" +\n\t\"\\x13goproto_getters_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x99\\xec\\x03 \\x01(\\bR\\x11goprotoGettersAll:U\\n\" +\n\t\"\\x17goproto_enum_prefix_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9a\\xec\\x03 \\x01(\\bR\\x14goprotoEnumPrefixAll:P\\n\" +\n\t\"\\x14goproto_stringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9b\\xec\\x03 \\x01(\\bR\\x12goprotoStringerAll:J\\n\" +\n\t\"\\x11verbose_equal_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9c\\xec\\x03 \\x01(\\bR\\x0fverboseEqualAll:9\\n\" +\n\t\"\\bface_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9d\\xec\\x03 \\x01(\\bR\\afaceAll:A\\n\" +\n\t\"\\fgostring_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9e\\xec\\x03 \\x01(\\bR\\vgostringAll:A\\n\" +\n\t\"\\fpopulate_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\x9f\\xec\\x03 \\x01(\\bR\\vpopulateAll:A\\n\" +\n\t\"\\fstringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa0\\xec\\x03 \\x01(\\bR\\vstringerAll:?\\n\" +\n\t\"\\vonlyone_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa1\\xec\\x03 \\x01(\\bR\\n\" +\n\t\"onlyoneAll:;\\n\" +\n\t\"\\tequal_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa5\\xec\\x03 \\x01(\\bR\\bequalAll:G\\n\" +\n\t\"\\x0fdescription_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa6\\xec\\x03 \\x01(\\bR\\x0edescriptionAll:?\\n\" +\n\t\"\\vtestgen_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa7\\xec\\x03 \\x01(\\bR\\n\" +\n\t\"testgenAll:A\\n\" +\n\t\"\\fbenchgen_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa8\\xec\\x03 \\x01(\\bR\\vbenchgenAll:C\\n\" +\n\t\"\\rmarshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xa9\\xec\\x03 \\x01(\\bR\\fmarshalerAll:G\\n\" +\n\t\"\\x0funmarshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xaa\\xec\\x03 \\x01(\\bR\\x0eunmarshalerAll:P\\n\" +\n\t\"\\x14stable_marshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xab\\xec\\x03 \\x01(\\bR\\x12stableMarshalerAll:;\\n\" +\n\t\"\\tsizer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xac\\xec\\x03 \\x01(\\bR\\bsizerAll:Y\\n\" +\n\t\"\\x19goproto_enum_stringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xad\\xec\\x03 \\x01(\\bR\\x16goprotoEnumStringerAll:J\\n\" +\n\t\"\\x11enum_stringer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xae\\xec\\x03 \\x01(\\bR\\x0fenumStringerAll:P\\n\" +\n\t\"\\x14unsafe_marshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xaf\\xec\\x03 \\x01(\\bR\\x12unsafeMarshalerAll:T\\n\" +\n\t\"\\x16unsafe_unmarshaler_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb0\\xec\\x03 \\x01(\\bR\\x14unsafeUnmarshalerAll:[\\n\" +\n\t\"\\x1agoproto_extensions_map_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb1\\xec\\x03 \\x01(\\bR\\x17goprotoExtensionsMapAll:X\\n\" +\n\t\"\\x18goproto_unrecognized_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb2\\xec\\x03 \\x01(\\bR\\x16goprotoUnrecognizedAll:I\\n\" +\n\t\"\\x10gogoproto_import\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb3\\xec\\x03 \\x01(\\bR\\x0fgogoprotoImport:E\\n\" +\n\t\"\\x0eprotosizer_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb4\\xec\\x03 \\x01(\\bR\\rprotosizerAll:?\\n\" +\n\t\"\\vcompare_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb5\\xec\\x03 \\x01(\\bR\\n\" +\n\t\"compareAll:A\\n\" +\n\t\"\\ftypedecl_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb6\\xec\\x03 \\x01(\\bR\\vtypedeclAll:A\\n\" +\n\t\"\\fenumdecl_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb7\\xec\\x03 \\x01(\\bR\\venumdeclAll:Q\\n\" +\n\t\"\\x14goproto_registration\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb8\\xec\\x03 \\x01(\\bR\\x13goprotoRegistration:G\\n\" +\n\t\"\\x0fmessagename_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xb9\\xec\\x03 \\x01(\\bR\\x0emessagenameAll:R\\n\" +\n\t\"\\x15goproto_sizecache_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xba\\xec\\x03 \\x01(\\bR\\x13goprotoSizecacheAll:N\\n\" +\n\t\"\\x13goproto_unkeyed_all\\x12\\x1c.google.protobuf.FileOptions\\x18\\xbb\\xec\\x03 \\x01(\\bR\\x11goprotoUnkeyedAll:J\\n\" +\n\t\"\\x0fgoproto_getters\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x81\\xf4\\x03 \\x01(\\bR\\x0egoprotoGetters:L\\n\" +\n\t\"\\x10goproto_stringer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x83\\xf4\\x03 \\x01(\\bR\\x0fgoprotoStringer:F\\n\" +\n\t\"\\rverbose_equal\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x84\\xf4\\x03 \\x01(\\bR\\fverboseEqual:5\\n\" +\n\t\"\\x04face\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x85\\xf4\\x03 \\x01(\\bR\\x04face:=\\n\" +\n\t\"\\bgostring\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x86\\xf4\\x03 \\x01(\\bR\\bgostring:=\\n\" +\n\t\"\\bpopulate\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x87\\xf4\\x03 \\x01(\\bR\\bpopulate:=\\n\" +\n\t\"\\bstringer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xc0\\x8b\\x04 \\x01(\\bR\\bstringer:;\\n\" +\n\t\"\\aonlyone\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x89\\xf4\\x03 \\x01(\\bR\\aonlyone:7\\n\" +\n\t\"\\x05equal\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x8d\\xf4\\x03 \\x01(\\bR\\x05equal:C\\n\" +\n\t\"\\vdescription\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x8e\\xf4\\x03 \\x01(\\bR\\vdescription:;\\n\" +\n\t\"\\atestgen\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x8f\\xf4\\x03 \\x01(\\bR\\atestgen:=\\n\" +\n\t\"\\bbenchgen\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x90\\xf4\\x03 \\x01(\\bR\\bbenchgen:?\\n\" +\n\t\"\\tmarshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x91\\xf4\\x03 \\x01(\\bR\\tmarshaler:C\\n\" +\n\t\"\\vunmarshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x92\\xf4\\x03 \\x01(\\bR\\vunmarshaler:L\\n\" +\n\t\"\\x10stable_marshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x93\\xf4\\x03 \\x01(\\bR\\x0fstableMarshaler:7\\n\" +\n\t\"\\x05sizer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x94\\xf4\\x03 \\x01(\\bR\\x05sizer:L\\n\" +\n\t\"\\x10unsafe_marshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x97\\xf4\\x03 \\x01(\\bR\\x0funsafeMarshaler:P\\n\" +\n\t\"\\x12unsafe_unmarshaler\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x98\\xf4\\x03 \\x01(\\bR\\x11unsafeUnmarshaler:W\\n\" +\n\t\"\\x16goproto_extensions_map\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x99\\xf4\\x03 \\x01(\\bR\\x14goprotoExtensionsMap:T\\n\" +\n\t\"\\x14goproto_unrecognized\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9a\\xf4\\x03 \\x01(\\bR\\x13goprotoUnrecognized:A\\n\" +\n\t\"\\n\" +\n\t\"protosizer\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9c\\xf4\\x03 \\x01(\\bR\\n\" +\n\t\"protosizer:;\\n\" +\n\t\"\\acompare\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9d\\xf4\\x03 \\x01(\\bR\\acompare:=\\n\" +\n\t\"\\btypedecl\\x12\\x1f.google.protobuf.MessageOptions\\x18\\x9e\\xf4\\x03 \\x01(\\bR\\btypedecl:C\\n\" +\n\t\"\\vmessagename\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xa1\\xf4\\x03 \\x01(\\bR\\vmessagename:N\\n\" +\n\t\"\\x11goproto_sizecache\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xa2\\xf4\\x03 \\x01(\\bR\\x10goprotoSizecache:J\\n\" +\n\t\"\\x0fgoproto_unkeyed\\x12\\x1f.google.protobuf.MessageOptions\\x18\\xa3\\xf4\\x03 \\x01(\\bR\\x0egoprotoUnkeyed:;\\n\" +\n\t\"\\bnullable\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xe9\\xfb\\x03 \\x01(\\bR\\bnullable:5\\n\" +\n\t\"\\x05embed\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xea\\xfb\\x03 \\x01(\\bR\\x05embed:?\\n\" +\n\t\"\\n\" +\n\t\"customtype\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xeb\\xfb\\x03 \\x01(\\tR\\n\" +\n\t\"customtype:?\\n\" +\n\t\"\\n\" +\n\t\"customname\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xec\\xfb\\x03 \\x01(\\tR\\n\" +\n\t\"customname:9\\n\" +\n\t\"\\ajsontag\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xed\\xfb\\x03 \\x01(\\tR\\ajsontag:;\\n\" +\n\t\"\\bmoretags\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xee\\xfb\\x03 \\x01(\\tR\\bmoretags:;\\n\" +\n\t\"\\bcasttype\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xef\\xfb\\x03 \\x01(\\tR\\bcasttype:9\\n\" +\n\t\"\\acastkey\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf0\\xfb\\x03 \\x01(\\tR\\acastkey:=\\n\" +\n\t\"\\tcastvalue\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf1\\xfb\\x03 \\x01(\\tR\\tcastvalue:9\\n\" +\n\t\"\\astdtime\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf2\\xfb\\x03 \\x01(\\bR\\astdtime:A\\n\" +\n\t\"\\vstdduration\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf3\\xfb\\x03 \\x01(\\bR\\vstdduration:?\\n\" +\n\t\"\\n\" +\n\t\"wktpointer\\x12\\x1d.google.protobuf.FieldOptions\\x18\\xf4\\xfb\\x03 \\x01(\\bR\\n\" +\n\t\"wktpointerB^\\n\" +\n\t\"\\x13com.google.protobufB\\n\" +\n\t\"GoGoProtosZ;buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto\"\n\nvar file_gogoproto_gogo_proto_goTypes = []any{\n\t(*descriptorpb.EnumOptions)(nil),      // 0: google.protobuf.EnumOptions\n\t(*descriptorpb.EnumValueOptions)(nil), // 1: google.protobuf.EnumValueOptions\n\t(*descriptorpb.FileOptions)(nil),      // 2: google.protobuf.FileOptions\n\t(*descriptorpb.MessageOptions)(nil),   // 3: google.protobuf.MessageOptions\n\t(*descriptorpb.FieldOptions)(nil),     // 4: google.protobuf.FieldOptions\n}\nvar file_gogoproto_gogo_proto_depIdxs = []int32{\n\t0,  // 0: gogoproto.goproto_enum_prefix:extendee -> google.protobuf.EnumOptions\n\t0,  // 1: gogoproto.goproto_enum_stringer:extendee -> google.protobuf.EnumOptions\n\t0,  // 2: gogoproto.enum_stringer:extendee -> google.protobuf.EnumOptions\n\t0,  // 3: gogoproto.enum_customname:extendee -> google.protobuf.EnumOptions\n\t0,  // 4: gogoproto.enumdecl:extendee -> google.protobuf.EnumOptions\n\t1,  // 5: gogoproto.enumvalue_customname:extendee -> google.protobuf.EnumValueOptions\n\t2,  // 6: gogoproto.goproto_getters_all:extendee -> google.protobuf.FileOptions\n\t2,  // 7: gogoproto.goproto_enum_prefix_all:extendee -> google.protobuf.FileOptions\n\t2,  // 8: gogoproto.goproto_stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 9: gogoproto.verbose_equal_all:extendee -> google.protobuf.FileOptions\n\t2,  // 10: gogoproto.face_all:extendee -> google.protobuf.FileOptions\n\t2,  // 11: gogoproto.gostring_all:extendee -> google.protobuf.FileOptions\n\t2,  // 12: gogoproto.populate_all:extendee -> google.protobuf.FileOptions\n\t2,  // 13: gogoproto.stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 14: gogoproto.onlyone_all:extendee -> google.protobuf.FileOptions\n\t2,  // 15: gogoproto.equal_all:extendee -> google.protobuf.FileOptions\n\t2,  // 16: gogoproto.description_all:extendee -> google.protobuf.FileOptions\n\t2,  // 17: gogoproto.testgen_all:extendee -> google.protobuf.FileOptions\n\t2,  // 18: gogoproto.benchgen_all:extendee -> google.protobuf.FileOptions\n\t2,  // 19: gogoproto.marshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 20: gogoproto.unmarshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 21: gogoproto.stable_marshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 22: gogoproto.sizer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 23: gogoproto.goproto_enum_stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 24: gogoproto.enum_stringer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 25: gogoproto.unsafe_marshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 26: gogoproto.unsafe_unmarshaler_all:extendee -> google.protobuf.FileOptions\n\t2,  // 27: gogoproto.goproto_extensions_map_all:extendee -> google.protobuf.FileOptions\n\t2,  // 28: gogoproto.goproto_unrecognized_all:extendee -> google.protobuf.FileOptions\n\t2,  // 29: gogoproto.gogoproto_import:extendee -> google.protobuf.FileOptions\n\t2,  // 30: gogoproto.protosizer_all:extendee -> google.protobuf.FileOptions\n\t2,  // 31: gogoproto.compare_all:extendee -> google.protobuf.FileOptions\n\t2,  // 32: gogoproto.typedecl_all:extendee -> google.protobuf.FileOptions\n\t2,  // 33: gogoproto.enumdecl_all:extendee -> google.protobuf.FileOptions\n\t2,  // 34: gogoproto.goproto_registration:extendee -> google.protobuf.FileOptions\n\t2,  // 35: gogoproto.messagename_all:extendee -> google.protobuf.FileOptions\n\t2,  // 36: gogoproto.goproto_sizecache_all:extendee -> google.protobuf.FileOptions\n\t2,  // 37: gogoproto.goproto_unkeyed_all:extendee -> google.protobuf.FileOptions\n\t3,  // 38: gogoproto.goproto_getters:extendee -> google.protobuf.MessageOptions\n\t3,  // 39: gogoproto.goproto_stringer:extendee -> google.protobuf.MessageOptions\n\t3,  // 40: gogoproto.verbose_equal:extendee -> google.protobuf.MessageOptions\n\t3,  // 41: gogoproto.face:extendee -> google.protobuf.MessageOptions\n\t3,  // 42: gogoproto.gostring:extendee -> google.protobuf.MessageOptions\n\t3,  // 43: gogoproto.populate:extendee -> google.protobuf.MessageOptions\n\t3,  // 44: gogoproto.stringer:extendee -> google.protobuf.MessageOptions\n\t3,  // 45: gogoproto.onlyone:extendee -> google.protobuf.MessageOptions\n\t3,  // 46: gogoproto.equal:extendee -> google.protobuf.MessageOptions\n\t3,  // 47: gogoproto.description:extendee -> google.protobuf.MessageOptions\n\t3,  // 48: gogoproto.testgen:extendee -> google.protobuf.MessageOptions\n\t3,  // 49: gogoproto.benchgen:extendee -> google.protobuf.MessageOptions\n\t3,  // 50: gogoproto.marshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 51: gogoproto.unmarshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 52: gogoproto.stable_marshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 53: gogoproto.sizer:extendee -> google.protobuf.MessageOptions\n\t3,  // 54: gogoproto.unsafe_marshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 55: gogoproto.unsafe_unmarshaler:extendee -> google.protobuf.MessageOptions\n\t3,  // 56: gogoproto.goproto_extensions_map:extendee -> google.protobuf.MessageOptions\n\t3,  // 57: gogoproto.goproto_unrecognized:extendee -> google.protobuf.MessageOptions\n\t3,  // 58: gogoproto.protosizer:extendee -> google.protobuf.MessageOptions\n\t3,  // 59: gogoproto.compare:extendee -> google.protobuf.MessageOptions\n\t3,  // 60: gogoproto.typedecl:extendee -> google.protobuf.MessageOptions\n\t3,  // 61: gogoproto.messagename:extendee -> google.protobuf.MessageOptions\n\t3,  // 62: gogoproto.goproto_sizecache:extendee -> google.protobuf.MessageOptions\n\t3,  // 63: gogoproto.goproto_unkeyed:extendee -> google.protobuf.MessageOptions\n\t4,  // 64: gogoproto.nullable:extendee -> google.protobuf.FieldOptions\n\t4,  // 65: gogoproto.embed:extendee -> google.protobuf.FieldOptions\n\t4,  // 66: gogoproto.customtype:extendee -> google.protobuf.FieldOptions\n\t4,  // 67: gogoproto.customname:extendee -> google.protobuf.FieldOptions\n\t4,  // 68: gogoproto.jsontag:extendee -> google.protobuf.FieldOptions\n\t4,  // 69: gogoproto.moretags:extendee -> google.protobuf.FieldOptions\n\t4,  // 70: gogoproto.casttype:extendee -> google.protobuf.FieldOptions\n\t4,  // 71: gogoproto.castkey:extendee -> google.protobuf.FieldOptions\n\t4,  // 72: gogoproto.castvalue:extendee -> google.protobuf.FieldOptions\n\t4,  // 73: gogoproto.stdtime:extendee -> google.protobuf.FieldOptions\n\t4,  // 74: gogoproto.stdduration:extendee -> google.protobuf.FieldOptions\n\t4,  // 75: gogoproto.wktpointer:extendee -> google.protobuf.FieldOptions\n\t76, // [76:76] is the sub-list for method output_type\n\t76, // [76:76] is the sub-list for method input_type\n\t76, // [76:76] is the sub-list for extension type_name\n\t0,  // [0:76] is the sub-list for extension extendee\n\t0,  // [0:0] is the sub-list for field type_name\n}\n\nfunc init() { file_gogoproto_gogo_proto_init() }\nfunc file_gogoproto_gogo_proto_init() {\n\tif File_gogoproto_gogo_proto != nil {\n\t\treturn\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_gogoproto_gogo_proto_rawDesc), len(file_gogoproto_gogo_proto_rawDesc)),\n\t\t\tNumEnums:      0,\n\t\t\tNumMessages:   0,\n\t\t\tNumExtensions: 76,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_gogoproto_gogo_proto_goTypes,\n\t\tDependencyIndexes: file_gogoproto_gogo_proto_depIdxs,\n\t\tExtensionInfos:    file_gogoproto_gogo_proto_extTypes,\n\t}.Build()\n\tFile_gogoproto_gogo_proto = out.File\n\tfile_gogoproto_gogo_proto_goTypes = nil\n\tfile_gogoproto_gogo_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "vendor/buf.build/gen/go/prometheus/prometheus/protocolbuffers/go/remote.pb.go",
    "content": "// Copyright 2016 Prometheus Team\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11\n// \tprotoc        (unknown)\n// source: remote.proto\n\n//go:build !protoopaque\n\npackage _go\n\nimport (\n\t_ \"buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tunsafe \"unsafe\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype ReadRequest_ResponseType int32\n\nconst (\n\t// Server will return a single ReadResponse message with matched series that includes list of raw samples.\n\t// It's recommended to use streamed response types instead.\n\t//\n\t// Response headers:\n\t// Content-Type: \"application/x-protobuf\"\n\t// Content-Encoding: \"snappy\"\n\tReadRequest_SAMPLES ReadRequest_ResponseType = 0\n\t// Server will stream a delimited ChunkedReadResponse message that\n\t// contains XOR or HISTOGRAM(!) encoded chunks for a single series.\n\t// Each message is following varint size and fixed size bigendian\n\t// uint32 for CRC32 Castagnoli checksum.\n\t//\n\t// Response headers:\n\t// Content-Type: \"application/x-streamed-protobuf; proto=prometheus.ChunkedReadResponse\"\n\t// Content-Encoding: \"\"\n\tReadRequest_STREAMED_XOR_CHUNKS ReadRequest_ResponseType = 1\n)\n\n// Enum value maps for ReadRequest_ResponseType.\nvar (\n\tReadRequest_ResponseType_name = map[int32]string{\n\t\t0: \"SAMPLES\",\n\t\t1: \"STREAMED_XOR_CHUNKS\",\n\t}\n\tReadRequest_ResponseType_value = map[string]int32{\n\t\t\"SAMPLES\":             0,\n\t\t\"STREAMED_XOR_CHUNKS\": 1,\n\t}\n)\n\nfunc (x ReadRequest_ResponseType) Enum() *ReadRequest_ResponseType {\n\tp := new(ReadRequest_ResponseType)\n\t*p = x\n\treturn p\n}\n\nfunc (x ReadRequest_ResponseType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ReadRequest_ResponseType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_remote_proto_enumTypes[0].Descriptor()\n}\n\nfunc (ReadRequest_ResponseType) Type() protoreflect.EnumType {\n\treturn &file_remote_proto_enumTypes[0]\n}\n\nfunc (x ReadRequest_ResponseType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype WriteRequest struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tTimeseries    []*TimeSeries          `protobuf:\"bytes,1,rep,name=timeseries,proto3\" json:\"timeseries,omitempty\"`\n\tMetadata      []*MetricMetadata      `protobuf:\"bytes,3,rep,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *WriteRequest) Reset() {\n\t*x = WriteRequest{}\n\tmi := &file_remote_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *WriteRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WriteRequest) ProtoMessage() {}\n\nfunc (x *WriteRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *WriteRequest) GetTimeseries() []*TimeSeries {\n\tif x != nil {\n\t\treturn x.Timeseries\n\t}\n\treturn nil\n}\n\nfunc (x *WriteRequest) GetMetadata() []*MetricMetadata {\n\tif x != nil {\n\t\treturn x.Metadata\n\t}\n\treturn nil\n}\n\nfunc (x *WriteRequest) SetTimeseries(v []*TimeSeries) {\n\tx.Timeseries = v\n}\n\nfunc (x *WriteRequest) SetMetadata(v []*MetricMetadata) {\n\tx.Metadata = v\n}\n\ntype WriteRequest_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tTimeseries []*TimeSeries\n\tMetadata   []*MetricMetadata\n}\n\nfunc (b0 WriteRequest_builder) Build() *WriteRequest {\n\tm0 := &WriteRequest{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Timeseries = b.Timeseries\n\tx.Metadata = b.Metadata\n\treturn m0\n}\n\n// ReadRequest represents a remote read request.\ntype ReadRequest struct {\n\tstate   protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tQueries []*Query               `protobuf:\"bytes,1,rep,name=queries,proto3\" json:\"queries,omitempty\"`\n\t// accepted_response_types allows negotiating the content type of the response.\n\t//\n\t// Response types are taken from the list in the FIFO order. If no response type in `accepted_response_types` is\n\t// implemented by server, error is returned.\n\t// For request that do not contain `accepted_response_types` field the SAMPLES response type will be used.\n\tAcceptedResponseTypes []ReadRequest_ResponseType `protobuf:\"varint,2,rep,packed,name=accepted_response_types,json=acceptedResponseTypes,proto3,enum=prometheus.ReadRequest_ResponseType\" json:\"accepted_response_types,omitempty\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *ReadRequest) Reset() {\n\t*x = ReadRequest{}\n\tmi := &file_remote_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReadRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadRequest) ProtoMessage() {}\n\nfunc (x *ReadRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ReadRequest) GetQueries() []*Query {\n\tif x != nil {\n\t\treturn x.Queries\n\t}\n\treturn nil\n}\n\nfunc (x *ReadRequest) GetAcceptedResponseTypes() []ReadRequest_ResponseType {\n\tif x != nil {\n\t\treturn x.AcceptedResponseTypes\n\t}\n\treturn nil\n}\n\nfunc (x *ReadRequest) SetQueries(v []*Query) {\n\tx.Queries = v\n}\n\nfunc (x *ReadRequest) SetAcceptedResponseTypes(v []ReadRequest_ResponseType) {\n\tx.AcceptedResponseTypes = v\n}\n\ntype ReadRequest_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tQueries []*Query\n\t// accepted_response_types allows negotiating the content type of the response.\n\t//\n\t// Response types are taken from the list in the FIFO order. If no response type in `accepted_response_types` is\n\t// implemented by server, error is returned.\n\t// For request that do not contain `accepted_response_types` field the SAMPLES response type will be used.\n\tAcceptedResponseTypes []ReadRequest_ResponseType\n}\n\nfunc (b0 ReadRequest_builder) Build() *ReadRequest {\n\tm0 := &ReadRequest{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Queries = b.Queries\n\tx.AcceptedResponseTypes = b.AcceptedResponseTypes\n\treturn m0\n}\n\n// ReadResponse is a response when response_type equals SAMPLES.\ntype ReadResponse struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\t// In same order as the request's queries.\n\tResults       []*QueryResult `protobuf:\"bytes,1,rep,name=results,proto3\" json:\"results,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ReadResponse) Reset() {\n\t*x = ReadResponse{}\n\tmi := &file_remote_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReadResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadResponse) ProtoMessage() {}\n\nfunc (x *ReadResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ReadResponse) GetResults() []*QueryResult {\n\tif x != nil {\n\t\treturn x.Results\n\t}\n\treturn nil\n}\n\nfunc (x *ReadResponse) SetResults(v []*QueryResult) {\n\tx.Results = v\n}\n\ntype ReadResponse_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// In same order as the request's queries.\n\tResults []*QueryResult\n}\n\nfunc (b0 ReadResponse_builder) Build() *ReadResponse {\n\tm0 := &ReadResponse{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Results = b.Results\n\treturn m0\n}\n\ntype Query struct {\n\tstate            protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tStartTimestampMs int64                  `protobuf:\"varint,1,opt,name=start_timestamp_ms,json=startTimestampMs,proto3\" json:\"start_timestamp_ms,omitempty\"`\n\tEndTimestampMs   int64                  `protobuf:\"varint,2,opt,name=end_timestamp_ms,json=endTimestampMs,proto3\" json:\"end_timestamp_ms,omitempty\"`\n\tMatchers         []*LabelMatcher        `protobuf:\"bytes,3,rep,name=matchers,proto3\" json:\"matchers,omitempty\"`\n\tHints            *ReadHints             `protobuf:\"bytes,4,opt,name=hints,proto3\" json:\"hints,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *Query) Reset() {\n\t*x = Query{}\n\tmi := &file_remote_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Query) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query) ProtoMessage() {}\n\nfunc (x *Query) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Query) GetStartTimestampMs() int64 {\n\tif x != nil {\n\t\treturn x.StartTimestampMs\n\t}\n\treturn 0\n}\n\nfunc (x *Query) GetEndTimestampMs() int64 {\n\tif x != nil {\n\t\treturn x.EndTimestampMs\n\t}\n\treturn 0\n}\n\nfunc (x *Query) GetMatchers() []*LabelMatcher {\n\tif x != nil {\n\t\treturn x.Matchers\n\t}\n\treturn nil\n}\n\nfunc (x *Query) GetHints() *ReadHints {\n\tif x != nil {\n\t\treturn x.Hints\n\t}\n\treturn nil\n}\n\nfunc (x *Query) SetStartTimestampMs(v int64) {\n\tx.StartTimestampMs = v\n}\n\nfunc (x *Query) SetEndTimestampMs(v int64) {\n\tx.EndTimestampMs = v\n}\n\nfunc (x *Query) SetMatchers(v []*LabelMatcher) {\n\tx.Matchers = v\n}\n\nfunc (x *Query) SetHints(v *ReadHints) {\n\tx.Hints = v\n}\n\nfunc (x *Query) HasHints() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\treturn x.Hints != nil\n}\n\nfunc (x *Query) ClearHints() {\n\tx.Hints = nil\n}\n\ntype Query_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tStartTimestampMs int64\n\tEndTimestampMs   int64\n\tMatchers         []*LabelMatcher\n\tHints            *ReadHints\n}\n\nfunc (b0 Query_builder) Build() *Query {\n\tm0 := &Query{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.StartTimestampMs = b.StartTimestampMs\n\tx.EndTimestampMs = b.EndTimestampMs\n\tx.Matchers = b.Matchers\n\tx.Hints = b.Hints\n\treturn m0\n}\n\ntype QueryResult struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\t// Samples within a time series must be ordered by time.\n\tTimeseries    []*TimeSeries `protobuf:\"bytes,1,rep,name=timeseries,proto3\" json:\"timeseries,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *QueryResult) Reset() {\n\t*x = QueryResult{}\n\tmi := &file_remote_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *QueryResult) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryResult) ProtoMessage() {}\n\nfunc (x *QueryResult) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *QueryResult) GetTimeseries() []*TimeSeries {\n\tif x != nil {\n\t\treturn x.Timeseries\n\t}\n\treturn nil\n}\n\nfunc (x *QueryResult) SetTimeseries(v []*TimeSeries) {\n\tx.Timeseries = v\n}\n\ntype QueryResult_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Samples within a time series must be ordered by time.\n\tTimeseries []*TimeSeries\n}\n\nfunc (b0 QueryResult_builder) Build() *QueryResult {\n\tm0 := &QueryResult{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Timeseries = b.Timeseries\n\treturn m0\n}\n\n// ChunkedReadResponse is a response when response_type equals STREAMED_XOR_CHUNKS.\n// We strictly stream full series after series, optionally split by time. This means that a single frame can contain\n// partition of the single series, but once a new series is started to be streamed it means that no more chunks will\n// be sent for previous one. Series are returned sorted in the same way TSDB block are internally.\ntype ChunkedReadResponse struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tChunkedSeries []*ChunkedSeries       `protobuf:\"bytes,1,rep,name=chunked_series,json=chunkedSeries,proto3\" json:\"chunked_series,omitempty\"`\n\t// query_index represents an index of the query from ReadRequest.queries these chunks relates to.\n\tQueryIndex    int64 `protobuf:\"varint,2,opt,name=query_index,json=queryIndex,proto3\" json:\"query_index,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ChunkedReadResponse) Reset() {\n\t*x = ChunkedReadResponse{}\n\tmi := &file_remote_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ChunkedReadResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ChunkedReadResponse) ProtoMessage() {}\n\nfunc (x *ChunkedReadResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ChunkedReadResponse) GetChunkedSeries() []*ChunkedSeries {\n\tif x != nil {\n\t\treturn x.ChunkedSeries\n\t}\n\treturn nil\n}\n\nfunc (x *ChunkedReadResponse) GetQueryIndex() int64 {\n\tif x != nil {\n\t\treturn x.QueryIndex\n\t}\n\treturn 0\n}\n\nfunc (x *ChunkedReadResponse) SetChunkedSeries(v []*ChunkedSeries) {\n\tx.ChunkedSeries = v\n}\n\nfunc (x *ChunkedReadResponse) SetQueryIndex(v int64) {\n\tx.QueryIndex = v\n}\n\ntype ChunkedReadResponse_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tChunkedSeries []*ChunkedSeries\n\t// query_index represents an index of the query from ReadRequest.queries these chunks relates to.\n\tQueryIndex int64\n}\n\nfunc (b0 ChunkedReadResponse_builder) Build() *ChunkedReadResponse {\n\tm0 := &ChunkedReadResponse{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.ChunkedSeries = b.ChunkedSeries\n\tx.QueryIndex = b.QueryIndex\n\treturn m0\n}\n\nvar File_remote_proto protoreflect.FileDescriptor\n\nconst file_remote_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\fremote.proto\\x12\\n\" +\n\t\"prometheus\\x1a\\vtypes.proto\\x1a\\x14gogoproto/gogo.proto\\\"\\x90\\x01\\n\" +\n\t\"\\fWriteRequest\\x12<\\n\" +\n\t\"\\n\" +\n\t\"timeseries\\x18\\x01 \\x03(\\v2\\x16.prometheus.TimeSeriesB\\x04\\xc8\\xde\\x1f\\x00R\\n\" +\n\t\"timeseries\\x12<\\n\" +\n\t\"\\bmetadata\\x18\\x03 \\x03(\\v2\\x1a.prometheus.MetricMetadataB\\x04\\xc8\\xde\\x1f\\x00R\\bmetadataJ\\x04\\b\\x02\\x10\\x03\\\"\\xce\\x01\\n\" +\n\t\"\\vReadRequest\\x12+\\n\" +\n\t\"\\aqueries\\x18\\x01 \\x03(\\v2\\x11.prometheus.QueryR\\aqueries\\x12\\\\\\n\" +\n\t\"\\x17accepted_response_types\\x18\\x02 \\x03(\\x0e2$.prometheus.ReadRequest.ResponseTypeR\\x15acceptedResponseTypes\\\"4\\n\" +\n\t\"\\fResponseType\\x12\\v\\n\" +\n\t\"\\aSAMPLES\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13STREAMED_XOR_CHUNKS\\x10\\x01\\\"A\\n\" +\n\t\"\\fReadResponse\\x121\\n\" +\n\t\"\\aresults\\x18\\x01 \\x03(\\v2\\x17.prometheus.QueryResultR\\aresults\\\"\\xc2\\x01\\n\" +\n\t\"\\x05Query\\x12,\\n\" +\n\t\"\\x12start_timestamp_ms\\x18\\x01 \\x01(\\x03R\\x10startTimestampMs\\x12(\\n\" +\n\t\"\\x10end_timestamp_ms\\x18\\x02 \\x01(\\x03R\\x0eendTimestampMs\\x124\\n\" +\n\t\"\\bmatchers\\x18\\x03 \\x03(\\v2\\x18.prometheus.LabelMatcherR\\bmatchers\\x12+\\n\" +\n\t\"\\x05hints\\x18\\x04 \\x01(\\v2\\x15.prometheus.ReadHintsR\\x05hints\\\"E\\n\" +\n\t\"\\vQueryResult\\x126\\n\" +\n\t\"\\n\" +\n\t\"timeseries\\x18\\x01 \\x03(\\v2\\x16.prometheus.TimeSeriesR\\n\" +\n\t\"timeseries\\\"x\\n\" +\n\t\"\\x13ChunkedReadResponse\\x12@\\n\" +\n\t\"\\x0echunked_series\\x18\\x01 \\x03(\\v2\\x19.prometheus.ChunkedSeriesR\\rchunkedSeries\\x12\\x1f\\n\" +\n\t\"\\vquery_index\\x18\\x02 \\x01(\\x03R\\n\" +\n\t\"queryIndexB;Z9buf.build/gen/go/prometheus/prometheus/protocolbuffers/gob\\x06proto3\"\n\nvar file_remote_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_remote_proto_msgTypes = make([]protoimpl.MessageInfo, 6)\nvar file_remote_proto_goTypes = []any{\n\t(ReadRequest_ResponseType)(0), // 0: prometheus.ReadRequest.ResponseType\n\t(*WriteRequest)(nil),          // 1: prometheus.WriteRequest\n\t(*ReadRequest)(nil),           // 2: prometheus.ReadRequest\n\t(*ReadResponse)(nil),          // 3: prometheus.ReadResponse\n\t(*Query)(nil),                 // 4: prometheus.Query\n\t(*QueryResult)(nil),           // 5: prometheus.QueryResult\n\t(*ChunkedReadResponse)(nil),   // 6: prometheus.ChunkedReadResponse\n\t(*TimeSeries)(nil),            // 7: prometheus.TimeSeries\n\t(*MetricMetadata)(nil),        // 8: prometheus.MetricMetadata\n\t(*LabelMatcher)(nil),          // 9: prometheus.LabelMatcher\n\t(*ReadHints)(nil),             // 10: prometheus.ReadHints\n\t(*ChunkedSeries)(nil),         // 11: prometheus.ChunkedSeries\n}\nvar file_remote_proto_depIdxs = []int32{\n\t7,  // 0: prometheus.WriteRequest.timeseries:type_name -> prometheus.TimeSeries\n\t8,  // 1: prometheus.WriteRequest.metadata:type_name -> prometheus.MetricMetadata\n\t4,  // 2: prometheus.ReadRequest.queries:type_name -> prometheus.Query\n\t0,  // 3: prometheus.ReadRequest.accepted_response_types:type_name -> prometheus.ReadRequest.ResponseType\n\t5,  // 4: prometheus.ReadResponse.results:type_name -> prometheus.QueryResult\n\t9,  // 5: prometheus.Query.matchers:type_name -> prometheus.LabelMatcher\n\t10, // 6: prometheus.Query.hints:type_name -> prometheus.ReadHints\n\t7,  // 7: prometheus.QueryResult.timeseries:type_name -> prometheus.TimeSeries\n\t11, // 8: prometheus.ChunkedReadResponse.chunked_series:type_name -> prometheus.ChunkedSeries\n\t9,  // [9:9] is the sub-list for method output_type\n\t9,  // [9:9] is the sub-list for method input_type\n\t9,  // [9:9] is the sub-list for extension type_name\n\t9,  // [9:9] is the sub-list for extension extendee\n\t0,  // [0:9] is the sub-list for field type_name\n}\n\nfunc init() { file_remote_proto_init() }\nfunc file_remote_proto_init() {\n\tif File_remote_proto != nil {\n\t\treturn\n\t}\n\tfile_types_proto_init()\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_remote_proto_rawDesc), len(file_remote_proto_rawDesc)),\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   6,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_remote_proto_goTypes,\n\t\tDependencyIndexes: file_remote_proto_depIdxs,\n\t\tEnumInfos:         file_remote_proto_enumTypes,\n\t\tMessageInfos:      file_remote_proto_msgTypes,\n\t}.Build()\n\tFile_remote_proto = out.File\n\tfile_remote_proto_goTypes = nil\n\tfile_remote_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "vendor/buf.build/gen/go/prometheus/prometheus/protocolbuffers/go/remote_protoopaque.pb.go",
    "content": "// Copyright 2016 Prometheus Team\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11\n// \tprotoc        (unknown)\n// source: remote.proto\n\n//go:build protoopaque\n\npackage _go\n\nimport (\n\t_ \"buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tunsafe \"unsafe\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype ReadRequest_ResponseType int32\n\nconst (\n\t// Server will return a single ReadResponse message with matched series that includes list of raw samples.\n\t// It's recommended to use streamed response types instead.\n\t//\n\t// Response headers:\n\t// Content-Type: \"application/x-protobuf\"\n\t// Content-Encoding: \"snappy\"\n\tReadRequest_SAMPLES ReadRequest_ResponseType = 0\n\t// Server will stream a delimited ChunkedReadResponse message that\n\t// contains XOR or HISTOGRAM(!) encoded chunks for a single series.\n\t// Each message is following varint size and fixed size bigendian\n\t// uint32 for CRC32 Castagnoli checksum.\n\t//\n\t// Response headers:\n\t// Content-Type: \"application/x-streamed-protobuf; proto=prometheus.ChunkedReadResponse\"\n\t// Content-Encoding: \"\"\n\tReadRequest_STREAMED_XOR_CHUNKS ReadRequest_ResponseType = 1\n)\n\n// Enum value maps for ReadRequest_ResponseType.\nvar (\n\tReadRequest_ResponseType_name = map[int32]string{\n\t\t0: \"SAMPLES\",\n\t\t1: \"STREAMED_XOR_CHUNKS\",\n\t}\n\tReadRequest_ResponseType_value = map[string]int32{\n\t\t\"SAMPLES\":             0,\n\t\t\"STREAMED_XOR_CHUNKS\": 1,\n\t}\n)\n\nfunc (x ReadRequest_ResponseType) Enum() *ReadRequest_ResponseType {\n\tp := new(ReadRequest_ResponseType)\n\t*p = x\n\treturn p\n}\n\nfunc (x ReadRequest_ResponseType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (ReadRequest_ResponseType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_remote_proto_enumTypes[0].Descriptor()\n}\n\nfunc (ReadRequest_ResponseType) Type() protoreflect.EnumType {\n\treturn &file_remote_proto_enumTypes[0]\n}\n\nfunc (x ReadRequest_ResponseType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype WriteRequest struct {\n\tstate                 protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Timeseries *[]*TimeSeries         `protobuf:\"bytes,1,rep,name=timeseries,proto3\"`\n\txxx_hidden_Metadata   *[]*MetricMetadata     `protobuf:\"bytes,3,rep,name=metadata,proto3\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *WriteRequest) Reset() {\n\t*x = WriteRequest{}\n\tmi := &file_remote_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *WriteRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*WriteRequest) ProtoMessage() {}\n\nfunc (x *WriteRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *WriteRequest) GetTimeseries() []*TimeSeries {\n\tif x != nil {\n\t\tif x.xxx_hidden_Timeseries != nil {\n\t\t\treturn *x.xxx_hidden_Timeseries\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *WriteRequest) GetMetadata() []*MetricMetadata {\n\tif x != nil {\n\t\tif x.xxx_hidden_Metadata != nil {\n\t\t\treturn *x.xxx_hidden_Metadata\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *WriteRequest) SetTimeseries(v []*TimeSeries) {\n\tx.xxx_hidden_Timeseries = &v\n}\n\nfunc (x *WriteRequest) SetMetadata(v []*MetricMetadata) {\n\tx.xxx_hidden_Metadata = &v\n}\n\ntype WriteRequest_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tTimeseries []*TimeSeries\n\tMetadata   []*MetricMetadata\n}\n\nfunc (b0 WriteRequest_builder) Build() *WriteRequest {\n\tm0 := &WriteRequest{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Timeseries = &b.Timeseries\n\tx.xxx_hidden_Metadata = &b.Metadata\n\treturn m0\n}\n\n// ReadRequest represents a remote read request.\ntype ReadRequest struct {\n\tstate                            protoimpl.MessageState     `protogen:\"opaque.v1\"`\n\txxx_hidden_Queries               *[]*Query                  `protobuf:\"bytes,1,rep,name=queries,proto3\"`\n\txxx_hidden_AcceptedResponseTypes []ReadRequest_ResponseType `protobuf:\"varint,2,rep,packed,name=accepted_response_types,json=acceptedResponseTypes,proto3,enum=prometheus.ReadRequest_ResponseType\"`\n\tunknownFields                    protoimpl.UnknownFields\n\tsizeCache                        protoimpl.SizeCache\n}\n\nfunc (x *ReadRequest) Reset() {\n\t*x = ReadRequest{}\n\tmi := &file_remote_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReadRequest) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadRequest) ProtoMessage() {}\n\nfunc (x *ReadRequest) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ReadRequest) GetQueries() []*Query {\n\tif x != nil {\n\t\tif x.xxx_hidden_Queries != nil {\n\t\t\treturn *x.xxx_hidden_Queries\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *ReadRequest) GetAcceptedResponseTypes() []ReadRequest_ResponseType {\n\tif x != nil {\n\t\treturn x.xxx_hidden_AcceptedResponseTypes\n\t}\n\treturn nil\n}\n\nfunc (x *ReadRequest) SetQueries(v []*Query) {\n\tx.xxx_hidden_Queries = &v\n}\n\nfunc (x *ReadRequest) SetAcceptedResponseTypes(v []ReadRequest_ResponseType) {\n\tx.xxx_hidden_AcceptedResponseTypes = v\n}\n\ntype ReadRequest_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tQueries []*Query\n\t// accepted_response_types allows negotiating the content type of the response.\n\t//\n\t// Response types are taken from the list in the FIFO order. If no response type in `accepted_response_types` is\n\t// implemented by server, error is returned.\n\t// For request that do not contain `accepted_response_types` field the SAMPLES response type will be used.\n\tAcceptedResponseTypes []ReadRequest_ResponseType\n}\n\nfunc (b0 ReadRequest_builder) Build() *ReadRequest {\n\tm0 := &ReadRequest{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Queries = &b.Queries\n\tx.xxx_hidden_AcceptedResponseTypes = b.AcceptedResponseTypes\n\treturn m0\n}\n\n// ReadResponse is a response when response_type equals SAMPLES.\ntype ReadResponse struct {\n\tstate              protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Results *[]*QueryResult        `protobuf:\"bytes,1,rep,name=results,proto3\"`\n\tunknownFields      protoimpl.UnknownFields\n\tsizeCache          protoimpl.SizeCache\n}\n\nfunc (x *ReadResponse) Reset() {\n\t*x = ReadResponse{}\n\tmi := &file_remote_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReadResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadResponse) ProtoMessage() {}\n\nfunc (x *ReadResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ReadResponse) GetResults() []*QueryResult {\n\tif x != nil {\n\t\tif x.xxx_hidden_Results != nil {\n\t\t\treturn *x.xxx_hidden_Results\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *ReadResponse) SetResults(v []*QueryResult) {\n\tx.xxx_hidden_Results = &v\n}\n\ntype ReadResponse_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// In same order as the request's queries.\n\tResults []*QueryResult\n}\n\nfunc (b0 ReadResponse_builder) Build() *ReadResponse {\n\tm0 := &ReadResponse{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Results = &b.Results\n\treturn m0\n}\n\ntype Query struct {\n\tstate                       protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_StartTimestampMs int64                  `protobuf:\"varint,1,opt,name=start_timestamp_ms,json=startTimestampMs,proto3\"`\n\txxx_hidden_EndTimestampMs   int64                  `protobuf:\"varint,2,opt,name=end_timestamp_ms,json=endTimestampMs,proto3\"`\n\txxx_hidden_Matchers         *[]*LabelMatcher       `protobuf:\"bytes,3,rep,name=matchers,proto3\"`\n\txxx_hidden_Hints            *ReadHints             `protobuf:\"bytes,4,opt,name=hints,proto3\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *Query) Reset() {\n\t*x = Query{}\n\tmi := &file_remote_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Query) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Query) ProtoMessage() {}\n\nfunc (x *Query) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Query) GetStartTimestampMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_StartTimestampMs\n\t}\n\treturn 0\n}\n\nfunc (x *Query) GetEndTimestampMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_EndTimestampMs\n\t}\n\treturn 0\n}\n\nfunc (x *Query) GetMatchers() []*LabelMatcher {\n\tif x != nil {\n\t\tif x.xxx_hidden_Matchers != nil {\n\t\t\treturn *x.xxx_hidden_Matchers\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *Query) GetHints() *ReadHints {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Hints\n\t}\n\treturn nil\n}\n\nfunc (x *Query) SetStartTimestampMs(v int64) {\n\tx.xxx_hidden_StartTimestampMs = v\n}\n\nfunc (x *Query) SetEndTimestampMs(v int64) {\n\tx.xxx_hidden_EndTimestampMs = v\n}\n\nfunc (x *Query) SetMatchers(v []*LabelMatcher) {\n\tx.xxx_hidden_Matchers = &v\n}\n\nfunc (x *Query) SetHints(v *ReadHints) {\n\tx.xxx_hidden_Hints = v\n}\n\nfunc (x *Query) HasHints() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\treturn x.xxx_hidden_Hints != nil\n}\n\nfunc (x *Query) ClearHints() {\n\tx.xxx_hidden_Hints = nil\n}\n\ntype Query_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tStartTimestampMs int64\n\tEndTimestampMs   int64\n\tMatchers         []*LabelMatcher\n\tHints            *ReadHints\n}\n\nfunc (b0 Query_builder) Build() *Query {\n\tm0 := &Query{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_StartTimestampMs = b.StartTimestampMs\n\tx.xxx_hidden_EndTimestampMs = b.EndTimestampMs\n\tx.xxx_hidden_Matchers = &b.Matchers\n\tx.xxx_hidden_Hints = b.Hints\n\treturn m0\n}\n\ntype QueryResult struct {\n\tstate                 protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Timeseries *[]*TimeSeries         `protobuf:\"bytes,1,rep,name=timeseries,proto3\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *QueryResult) Reset() {\n\t*x = QueryResult{}\n\tmi := &file_remote_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *QueryResult) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*QueryResult) ProtoMessage() {}\n\nfunc (x *QueryResult) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *QueryResult) GetTimeseries() []*TimeSeries {\n\tif x != nil {\n\t\tif x.xxx_hidden_Timeseries != nil {\n\t\t\treturn *x.xxx_hidden_Timeseries\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *QueryResult) SetTimeseries(v []*TimeSeries) {\n\tx.xxx_hidden_Timeseries = &v\n}\n\ntype QueryResult_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Samples within a time series must be ordered by time.\n\tTimeseries []*TimeSeries\n}\n\nfunc (b0 QueryResult_builder) Build() *QueryResult {\n\tm0 := &QueryResult{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Timeseries = &b.Timeseries\n\treturn m0\n}\n\n// ChunkedReadResponse is a response when response_type equals STREAMED_XOR_CHUNKS.\n// We strictly stream full series after series, optionally split by time. This means that a single frame can contain\n// partition of the single series, but once a new series is started to be streamed it means that no more chunks will\n// be sent for previous one. Series are returned sorted in the same way TSDB block are internally.\ntype ChunkedReadResponse struct {\n\tstate                    protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_ChunkedSeries *[]*ChunkedSeries      `protobuf:\"bytes,1,rep,name=chunked_series,json=chunkedSeries,proto3\"`\n\txxx_hidden_QueryIndex    int64                  `protobuf:\"varint,2,opt,name=query_index,json=queryIndex,proto3\"`\n\tunknownFields            protoimpl.UnknownFields\n\tsizeCache                protoimpl.SizeCache\n}\n\nfunc (x *ChunkedReadResponse) Reset() {\n\t*x = ChunkedReadResponse{}\n\tmi := &file_remote_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ChunkedReadResponse) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ChunkedReadResponse) ProtoMessage() {}\n\nfunc (x *ChunkedReadResponse) ProtoReflect() protoreflect.Message {\n\tmi := &file_remote_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ChunkedReadResponse) GetChunkedSeries() []*ChunkedSeries {\n\tif x != nil {\n\t\tif x.xxx_hidden_ChunkedSeries != nil {\n\t\t\treturn *x.xxx_hidden_ChunkedSeries\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *ChunkedReadResponse) GetQueryIndex() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_QueryIndex\n\t}\n\treturn 0\n}\n\nfunc (x *ChunkedReadResponse) SetChunkedSeries(v []*ChunkedSeries) {\n\tx.xxx_hidden_ChunkedSeries = &v\n}\n\nfunc (x *ChunkedReadResponse) SetQueryIndex(v int64) {\n\tx.xxx_hidden_QueryIndex = v\n}\n\ntype ChunkedReadResponse_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tChunkedSeries []*ChunkedSeries\n\t// query_index represents an index of the query from ReadRequest.queries these chunks relates to.\n\tQueryIndex int64\n}\n\nfunc (b0 ChunkedReadResponse_builder) Build() *ChunkedReadResponse {\n\tm0 := &ChunkedReadResponse{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_ChunkedSeries = &b.ChunkedSeries\n\tx.xxx_hidden_QueryIndex = b.QueryIndex\n\treturn m0\n}\n\nvar File_remote_proto protoreflect.FileDescriptor\n\nconst file_remote_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\fremote.proto\\x12\\n\" +\n\t\"prometheus\\x1a\\vtypes.proto\\x1a\\x14gogoproto/gogo.proto\\\"\\x90\\x01\\n\" +\n\t\"\\fWriteRequest\\x12<\\n\" +\n\t\"\\n\" +\n\t\"timeseries\\x18\\x01 \\x03(\\v2\\x16.prometheus.TimeSeriesB\\x04\\xc8\\xde\\x1f\\x00R\\n\" +\n\t\"timeseries\\x12<\\n\" +\n\t\"\\bmetadata\\x18\\x03 \\x03(\\v2\\x1a.prometheus.MetricMetadataB\\x04\\xc8\\xde\\x1f\\x00R\\bmetadataJ\\x04\\b\\x02\\x10\\x03\\\"\\xce\\x01\\n\" +\n\t\"\\vReadRequest\\x12+\\n\" +\n\t\"\\aqueries\\x18\\x01 \\x03(\\v2\\x11.prometheus.QueryR\\aqueries\\x12\\\\\\n\" +\n\t\"\\x17accepted_response_types\\x18\\x02 \\x03(\\x0e2$.prometheus.ReadRequest.ResponseTypeR\\x15acceptedResponseTypes\\\"4\\n\" +\n\t\"\\fResponseType\\x12\\v\\n\" +\n\t\"\\aSAMPLES\\x10\\x00\\x12\\x17\\n\" +\n\t\"\\x13STREAMED_XOR_CHUNKS\\x10\\x01\\\"A\\n\" +\n\t\"\\fReadResponse\\x121\\n\" +\n\t\"\\aresults\\x18\\x01 \\x03(\\v2\\x17.prometheus.QueryResultR\\aresults\\\"\\xc2\\x01\\n\" +\n\t\"\\x05Query\\x12,\\n\" +\n\t\"\\x12start_timestamp_ms\\x18\\x01 \\x01(\\x03R\\x10startTimestampMs\\x12(\\n\" +\n\t\"\\x10end_timestamp_ms\\x18\\x02 \\x01(\\x03R\\x0eendTimestampMs\\x124\\n\" +\n\t\"\\bmatchers\\x18\\x03 \\x03(\\v2\\x18.prometheus.LabelMatcherR\\bmatchers\\x12+\\n\" +\n\t\"\\x05hints\\x18\\x04 \\x01(\\v2\\x15.prometheus.ReadHintsR\\x05hints\\\"E\\n\" +\n\t\"\\vQueryResult\\x126\\n\" +\n\t\"\\n\" +\n\t\"timeseries\\x18\\x01 \\x03(\\v2\\x16.prometheus.TimeSeriesR\\n\" +\n\t\"timeseries\\\"x\\n\" +\n\t\"\\x13ChunkedReadResponse\\x12@\\n\" +\n\t\"\\x0echunked_series\\x18\\x01 \\x03(\\v2\\x19.prometheus.ChunkedSeriesR\\rchunkedSeries\\x12\\x1f\\n\" +\n\t\"\\vquery_index\\x18\\x02 \\x01(\\x03R\\n\" +\n\t\"queryIndexB;Z9buf.build/gen/go/prometheus/prometheus/protocolbuffers/gob\\x06proto3\"\n\nvar file_remote_proto_enumTypes = make([]protoimpl.EnumInfo, 1)\nvar file_remote_proto_msgTypes = make([]protoimpl.MessageInfo, 6)\nvar file_remote_proto_goTypes = []any{\n\t(ReadRequest_ResponseType)(0), // 0: prometheus.ReadRequest.ResponseType\n\t(*WriteRequest)(nil),          // 1: prometheus.WriteRequest\n\t(*ReadRequest)(nil),           // 2: prometheus.ReadRequest\n\t(*ReadResponse)(nil),          // 3: prometheus.ReadResponse\n\t(*Query)(nil),                 // 4: prometheus.Query\n\t(*QueryResult)(nil),           // 5: prometheus.QueryResult\n\t(*ChunkedReadResponse)(nil),   // 6: prometheus.ChunkedReadResponse\n\t(*TimeSeries)(nil),            // 7: prometheus.TimeSeries\n\t(*MetricMetadata)(nil),        // 8: prometheus.MetricMetadata\n\t(*LabelMatcher)(nil),          // 9: prometheus.LabelMatcher\n\t(*ReadHints)(nil),             // 10: prometheus.ReadHints\n\t(*ChunkedSeries)(nil),         // 11: prometheus.ChunkedSeries\n}\nvar file_remote_proto_depIdxs = []int32{\n\t7,  // 0: prometheus.WriteRequest.timeseries:type_name -> prometheus.TimeSeries\n\t8,  // 1: prometheus.WriteRequest.metadata:type_name -> prometheus.MetricMetadata\n\t4,  // 2: prometheus.ReadRequest.queries:type_name -> prometheus.Query\n\t0,  // 3: prometheus.ReadRequest.accepted_response_types:type_name -> prometheus.ReadRequest.ResponseType\n\t5,  // 4: prometheus.ReadResponse.results:type_name -> prometheus.QueryResult\n\t9,  // 5: prometheus.Query.matchers:type_name -> prometheus.LabelMatcher\n\t10, // 6: prometheus.Query.hints:type_name -> prometheus.ReadHints\n\t7,  // 7: prometheus.QueryResult.timeseries:type_name -> prometheus.TimeSeries\n\t11, // 8: prometheus.ChunkedReadResponse.chunked_series:type_name -> prometheus.ChunkedSeries\n\t9,  // [9:9] is the sub-list for method output_type\n\t9,  // [9:9] is the sub-list for method input_type\n\t9,  // [9:9] is the sub-list for extension type_name\n\t9,  // [9:9] is the sub-list for extension extendee\n\t0,  // [0:9] is the sub-list for field type_name\n}\n\nfunc init() { file_remote_proto_init() }\nfunc file_remote_proto_init() {\n\tif File_remote_proto != nil {\n\t\treturn\n\t}\n\tfile_types_proto_init()\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_remote_proto_rawDesc), len(file_remote_proto_rawDesc)),\n\t\t\tNumEnums:      1,\n\t\t\tNumMessages:   6,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_remote_proto_goTypes,\n\t\tDependencyIndexes: file_remote_proto_depIdxs,\n\t\tEnumInfos:         file_remote_proto_enumTypes,\n\t\tMessageInfos:      file_remote_proto_msgTypes,\n\t}.Build()\n\tFile_remote_proto = out.File\n\tfile_remote_proto_goTypes = nil\n\tfile_remote_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "vendor/buf.build/gen/go/prometheus/prometheus/protocolbuffers/go/types.pb.go",
    "content": "// Copyright 2017 Prometheus Team\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11\n// \tprotoc        (unknown)\n// source: types.proto\n\n//go:build !protoopaque\n\npackage _go\n\nimport (\n\t_ \"buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tunsafe \"unsafe\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype MetricMetadata_MetricType int32\n\nconst (\n\tMetricMetadata_UNKNOWN        MetricMetadata_MetricType = 0\n\tMetricMetadata_COUNTER        MetricMetadata_MetricType = 1\n\tMetricMetadata_GAUGE          MetricMetadata_MetricType = 2\n\tMetricMetadata_HISTOGRAM      MetricMetadata_MetricType = 3\n\tMetricMetadata_GAUGEHISTOGRAM MetricMetadata_MetricType = 4\n\tMetricMetadata_SUMMARY        MetricMetadata_MetricType = 5\n\tMetricMetadata_INFO           MetricMetadata_MetricType = 6\n\tMetricMetadata_STATESET       MetricMetadata_MetricType = 7\n)\n\n// Enum value maps for MetricMetadata_MetricType.\nvar (\n\tMetricMetadata_MetricType_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"COUNTER\",\n\t\t2: \"GAUGE\",\n\t\t3: \"HISTOGRAM\",\n\t\t4: \"GAUGEHISTOGRAM\",\n\t\t5: \"SUMMARY\",\n\t\t6: \"INFO\",\n\t\t7: \"STATESET\",\n\t}\n\tMetricMetadata_MetricType_value = map[string]int32{\n\t\t\"UNKNOWN\":        0,\n\t\t\"COUNTER\":        1,\n\t\t\"GAUGE\":          2,\n\t\t\"HISTOGRAM\":      3,\n\t\t\"GAUGEHISTOGRAM\": 4,\n\t\t\"SUMMARY\":        5,\n\t\t\"INFO\":           6,\n\t\t\"STATESET\":       7,\n\t}\n)\n\nfunc (x MetricMetadata_MetricType) Enum() *MetricMetadata_MetricType {\n\tp := new(MetricMetadata_MetricType)\n\t*p = x\n\treturn p\n}\n\nfunc (x MetricMetadata_MetricType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (MetricMetadata_MetricType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[0].Descriptor()\n}\n\nfunc (MetricMetadata_MetricType) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[0]\n}\n\nfunc (x MetricMetadata_MetricType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype Histogram_ResetHint int32\n\nconst (\n\tHistogram_UNKNOWN Histogram_ResetHint = 0 // Need to test for a counter reset explicitly.\n\tHistogram_YES     Histogram_ResetHint = 1 // This is the 1st histogram after a counter reset.\n\tHistogram_NO      Histogram_ResetHint = 2 // There was no counter reset between this and the previous Histogram.\n\tHistogram_GAUGE   Histogram_ResetHint = 3 // This is a gauge histogram where counter resets don't happen.\n)\n\n// Enum value maps for Histogram_ResetHint.\nvar (\n\tHistogram_ResetHint_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"YES\",\n\t\t2: \"NO\",\n\t\t3: \"GAUGE\",\n\t}\n\tHistogram_ResetHint_value = map[string]int32{\n\t\t\"UNKNOWN\": 0,\n\t\t\"YES\":     1,\n\t\t\"NO\":      2,\n\t\t\"GAUGE\":   3,\n\t}\n)\n\nfunc (x Histogram_ResetHint) Enum() *Histogram_ResetHint {\n\tp := new(Histogram_ResetHint)\n\t*p = x\n\treturn p\n}\n\nfunc (x Histogram_ResetHint) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Histogram_ResetHint) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[1].Descriptor()\n}\n\nfunc (Histogram_ResetHint) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[1]\n}\n\nfunc (x Histogram_ResetHint) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype LabelMatcher_Type int32\n\nconst (\n\tLabelMatcher_EQ  LabelMatcher_Type = 0\n\tLabelMatcher_NEQ LabelMatcher_Type = 1\n\tLabelMatcher_RE  LabelMatcher_Type = 2\n\tLabelMatcher_NRE LabelMatcher_Type = 3\n)\n\n// Enum value maps for LabelMatcher_Type.\nvar (\n\tLabelMatcher_Type_name = map[int32]string{\n\t\t0: \"EQ\",\n\t\t1: \"NEQ\",\n\t\t2: \"RE\",\n\t\t3: \"NRE\",\n\t}\n\tLabelMatcher_Type_value = map[string]int32{\n\t\t\"EQ\":  0,\n\t\t\"NEQ\": 1,\n\t\t\"RE\":  2,\n\t\t\"NRE\": 3,\n\t}\n)\n\nfunc (x LabelMatcher_Type) Enum() *LabelMatcher_Type {\n\tp := new(LabelMatcher_Type)\n\t*p = x\n\treturn p\n}\n\nfunc (x LabelMatcher_Type) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (LabelMatcher_Type) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[2].Descriptor()\n}\n\nfunc (LabelMatcher_Type) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[2]\n}\n\nfunc (x LabelMatcher_Type) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// We require this to match chunkenc.Encoding.\ntype Chunk_Encoding int32\n\nconst (\n\tChunk_UNKNOWN         Chunk_Encoding = 0\n\tChunk_XOR             Chunk_Encoding = 1\n\tChunk_HISTOGRAM       Chunk_Encoding = 2\n\tChunk_FLOAT_HISTOGRAM Chunk_Encoding = 3\n)\n\n// Enum value maps for Chunk_Encoding.\nvar (\n\tChunk_Encoding_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"XOR\",\n\t\t2: \"HISTOGRAM\",\n\t\t3: \"FLOAT_HISTOGRAM\",\n\t}\n\tChunk_Encoding_value = map[string]int32{\n\t\t\"UNKNOWN\":         0,\n\t\t\"XOR\":             1,\n\t\t\"HISTOGRAM\":       2,\n\t\t\"FLOAT_HISTOGRAM\": 3,\n\t}\n)\n\nfunc (x Chunk_Encoding) Enum() *Chunk_Encoding {\n\tp := new(Chunk_Encoding)\n\t*p = x\n\treturn p\n}\n\nfunc (x Chunk_Encoding) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Chunk_Encoding) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[3].Descriptor()\n}\n\nfunc (Chunk_Encoding) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[3]\n}\n\nfunc (x Chunk_Encoding) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype MetricMetadata struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\t// Represents the metric type, these match the set from Prometheus.\n\t// Refer to github.com/prometheus/common/model/metadata.go for details.\n\tType             MetricMetadata_MetricType `protobuf:\"varint,1,opt,name=type,proto3,enum=prometheus.MetricMetadata_MetricType\" json:\"type,omitempty\"`\n\tMetricFamilyName string                    `protobuf:\"bytes,2,opt,name=metric_family_name,json=metricFamilyName,proto3\" json:\"metric_family_name,omitempty\"`\n\tHelp             string                    `protobuf:\"bytes,4,opt,name=help,proto3\" json:\"help,omitempty\"`\n\tUnit             string                    `protobuf:\"bytes,5,opt,name=unit,proto3\" json:\"unit,omitempty\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *MetricMetadata) Reset() {\n\t*x = MetricMetadata{}\n\tmi := &file_types_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetricMetadata) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetricMetadata) ProtoMessage() {}\n\nfunc (x *MetricMetadata) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *MetricMetadata) GetType() MetricMetadata_MetricType {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn MetricMetadata_UNKNOWN\n}\n\nfunc (x *MetricMetadata) GetMetricFamilyName() string {\n\tif x != nil {\n\t\treturn x.MetricFamilyName\n\t}\n\treturn \"\"\n}\n\nfunc (x *MetricMetadata) GetHelp() string {\n\tif x != nil {\n\t\treturn x.Help\n\t}\n\treturn \"\"\n}\n\nfunc (x *MetricMetadata) GetUnit() string {\n\tif x != nil {\n\t\treturn x.Unit\n\t}\n\treturn \"\"\n}\n\nfunc (x *MetricMetadata) SetType(v MetricMetadata_MetricType) {\n\tx.Type = v\n}\n\nfunc (x *MetricMetadata) SetMetricFamilyName(v string) {\n\tx.MetricFamilyName = v\n}\n\nfunc (x *MetricMetadata) SetHelp(v string) {\n\tx.Help = v\n}\n\nfunc (x *MetricMetadata) SetUnit(v string) {\n\tx.Unit = v\n}\n\ntype MetricMetadata_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Represents the metric type, these match the set from Prometheus.\n\t// Refer to github.com/prometheus/common/model/metadata.go for details.\n\tType             MetricMetadata_MetricType\n\tMetricFamilyName string\n\tHelp             string\n\tUnit             string\n}\n\nfunc (b0 MetricMetadata_builder) Build() *MetricMetadata {\n\tm0 := &MetricMetadata{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Type = b.Type\n\tx.MetricFamilyName = b.MetricFamilyName\n\tx.Help = b.Help\n\tx.Unit = b.Unit\n\treturn m0\n}\n\ntype Sample struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tValue float64                `protobuf:\"fixed64,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp     int64 `protobuf:\"varint,2,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Sample) Reset() {\n\t*x = Sample{}\n\tmi := &file_types_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Sample) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Sample) ProtoMessage() {}\n\nfunc (x *Sample) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Sample) GetValue() float64 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\nfunc (x *Sample) GetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (x *Sample) SetValue(v float64) {\n\tx.Value = v\n}\n\nfunc (x *Sample) SetTimestamp(v int64) {\n\tx.Timestamp = v\n}\n\ntype Sample_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tValue float64\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp int64\n}\n\nfunc (b0 Sample_builder) Build() *Sample {\n\tm0 := &Sample{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Value = b.Value\n\tx.Timestamp = b.Timestamp\n\treturn m0\n}\n\ntype Exemplar struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\t// Optional, can be empty.\n\tLabels []*Label `protobuf:\"bytes,1,rep,name=labels,proto3\" json:\"labels,omitempty\"`\n\tValue  float64  `protobuf:\"fixed64,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp     int64 `protobuf:\"varint,3,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Exemplar) Reset() {\n\t*x = Exemplar{}\n\tmi := &file_types_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Exemplar) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Exemplar) ProtoMessage() {}\n\nfunc (x *Exemplar) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Exemplar) GetLabels() []*Label {\n\tif x != nil {\n\t\treturn x.Labels\n\t}\n\treturn nil\n}\n\nfunc (x *Exemplar) GetValue() float64 {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn 0\n}\n\nfunc (x *Exemplar) GetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (x *Exemplar) SetLabels(v []*Label) {\n\tx.Labels = v\n}\n\nfunc (x *Exemplar) SetValue(v float64) {\n\tx.Value = v\n}\n\nfunc (x *Exemplar) SetTimestamp(v int64) {\n\tx.Timestamp = v\n}\n\ntype Exemplar_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Optional, can be empty.\n\tLabels []*Label\n\tValue  float64\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp int64\n}\n\nfunc (b0 Exemplar_builder) Build() *Exemplar {\n\tm0 := &Exemplar{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Labels = b.Labels\n\tx.Value = b.Value\n\tx.Timestamp = b.Timestamp\n\treturn m0\n}\n\n// A native histogram, also known as a sparse histogram.\n// Original design doc:\n// https://docs.google.com/document/d/1cLNv3aufPZb3fNfaJgdaRBZsInZKKIHo9E6HinJVbpM/edit\n// The appendix of this design doc also explains the concept of float\n// histograms. This Histogram message can represent both, the usual\n// integer histogram as well as a float histogram.\ntype Histogram struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\t// Types that are valid to be assigned to Count:\n\t//\n\t//\t*Histogram_CountInt\n\t//\t*Histogram_CountFloat\n\tCount isHistogram_Count `protobuf_oneof:\"count\"`\n\tSum   float64           `protobuf:\"fixed64,3,opt,name=sum,proto3\" json:\"sum,omitempty\"` // Sum of observations in the histogram.\n\t// The schema defines the bucket schema. Currently, valid numbers\n\t// are -4 <= n <= 8. They are all for base-2 bucket schemas, where 1\n\t// is a bucket boundary in each case, and then each power of two is\n\t// divided into 2^n logarithmic buckets. Or in other words, each\n\t// bucket boundary is the previous boundary times 2^(2^-n). In the\n\t// future, more bucket schemas may be added using numbers < -4 or >\n\t// 8.\n\tSchema        int32   `protobuf:\"zigzag32,4,opt,name=schema,proto3\" json:\"schema,omitempty\"`\n\tZeroThreshold float64 `protobuf:\"fixed64,5,opt,name=zero_threshold,json=zeroThreshold,proto3\" json:\"zero_threshold,omitempty\"` // Breadth of the zero bucket.\n\t// Types that are valid to be assigned to ZeroCount:\n\t//\n\t//\t*Histogram_ZeroCountInt\n\t//\t*Histogram_ZeroCountFloat\n\tZeroCount isHistogram_ZeroCount `protobuf_oneof:\"zero_count\"`\n\t// Negative Buckets.\n\tNegativeSpans []*BucketSpan `protobuf:\"bytes,8,rep,name=negative_spans,json=negativeSpans,proto3\" json:\"negative_spans,omitempty\"`\n\t// Use either \"negative_deltas\" or \"negative_counts\", the former for\n\t// regular histograms with integer counts, the latter for float\n\t// histograms.\n\tNegativeDeltas []int64   `protobuf:\"zigzag64,9,rep,packed,name=negative_deltas,json=negativeDeltas,proto3\" json:\"negative_deltas,omitempty\"` // Count delta of each bucket compared to previous one (or to zero for 1st bucket).\n\tNegativeCounts []float64 `protobuf:\"fixed64,10,rep,packed,name=negative_counts,json=negativeCounts,proto3\" json:\"negative_counts,omitempty\"` // Absolute count of each bucket.\n\t// Positive Buckets.\n\tPositiveSpans []*BucketSpan `protobuf:\"bytes,11,rep,name=positive_spans,json=positiveSpans,proto3\" json:\"positive_spans,omitempty\"`\n\t// Use either \"positive_deltas\" or \"positive_counts\", the former for\n\t// regular histograms with integer counts, the latter for float\n\t// histograms.\n\tPositiveDeltas []int64             `protobuf:\"zigzag64,12,rep,packed,name=positive_deltas,json=positiveDeltas,proto3\" json:\"positive_deltas,omitempty\"` // Count delta of each bucket compared to previous one (or to zero for 1st bucket).\n\tPositiveCounts []float64           `protobuf:\"fixed64,13,rep,packed,name=positive_counts,json=positiveCounts,proto3\" json:\"positive_counts,omitempty\"`  // Absolute count of each bucket.\n\tResetHint      Histogram_ResetHint `protobuf:\"varint,14,opt,name=reset_hint,json=resetHint,proto3,enum=prometheus.Histogram_ResetHint\" json:\"reset_hint,omitempty\"`\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp int64 `protobuf:\"varint,15,opt,name=timestamp,proto3\" json:\"timestamp,omitempty\"`\n\t// custom_values are not part of the specification, DO NOT use in remote write clients.\n\t// Used only for converting from OpenTelemetry to Prometheus internally.\n\tCustomValues  []float64 `protobuf:\"fixed64,16,rep,packed,name=custom_values,json=customValues,proto3\" json:\"custom_values,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Histogram) Reset() {\n\t*x = Histogram{}\n\tmi := &file_types_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Histogram) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Histogram) ProtoMessage() {}\n\nfunc (x *Histogram) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Histogram) GetCount() isHistogram_Count {\n\tif x != nil {\n\t\treturn x.Count\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetCountInt() uint64 {\n\tif x != nil {\n\t\tif x, ok := x.Count.(*Histogram_CountInt); ok {\n\t\t\treturn x.CountInt\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetCountFloat() float64 {\n\tif x != nil {\n\t\tif x, ok := x.Count.(*Histogram_CountFloat); ok {\n\t\t\treturn x.CountFloat\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetSum() float64 {\n\tif x != nil {\n\t\treturn x.Sum\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetSchema() int32 {\n\tif x != nil {\n\t\treturn x.Schema\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetZeroThreshold() float64 {\n\tif x != nil {\n\t\treturn x.ZeroThreshold\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetZeroCount() isHistogram_ZeroCount {\n\tif x != nil {\n\t\treturn x.ZeroCount\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetZeroCountInt() uint64 {\n\tif x != nil {\n\t\tif x, ok := x.ZeroCount.(*Histogram_ZeroCountInt); ok {\n\t\t\treturn x.ZeroCountInt\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetZeroCountFloat() float64 {\n\tif x != nil {\n\t\tif x, ok := x.ZeroCount.(*Histogram_ZeroCountFloat); ok {\n\t\t\treturn x.ZeroCountFloat\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetNegativeSpans() []*BucketSpan {\n\tif x != nil {\n\t\treturn x.NegativeSpans\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetNegativeDeltas() []int64 {\n\tif x != nil {\n\t\treturn x.NegativeDeltas\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetNegativeCounts() []float64 {\n\tif x != nil {\n\t\treturn x.NegativeCounts\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetPositiveSpans() []*BucketSpan {\n\tif x != nil {\n\t\treturn x.PositiveSpans\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetPositiveDeltas() []int64 {\n\tif x != nil {\n\t\treturn x.PositiveDeltas\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetPositiveCounts() []float64 {\n\tif x != nil {\n\t\treturn x.PositiveCounts\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetResetHint() Histogram_ResetHint {\n\tif x != nil {\n\t\treturn x.ResetHint\n\t}\n\treturn Histogram_UNKNOWN\n}\n\nfunc (x *Histogram) GetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.Timestamp\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetCustomValues() []float64 {\n\tif x != nil {\n\t\treturn x.CustomValues\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) SetCountInt(v uint64) {\n\tx.Count = &Histogram_CountInt{v}\n}\n\nfunc (x *Histogram) SetCountFloat(v float64) {\n\tx.Count = &Histogram_CountFloat{v}\n}\n\nfunc (x *Histogram) SetSum(v float64) {\n\tx.Sum = v\n}\n\nfunc (x *Histogram) SetSchema(v int32) {\n\tx.Schema = v\n}\n\nfunc (x *Histogram) SetZeroThreshold(v float64) {\n\tx.ZeroThreshold = v\n}\n\nfunc (x *Histogram) SetZeroCountInt(v uint64) {\n\tx.ZeroCount = &Histogram_ZeroCountInt{v}\n}\n\nfunc (x *Histogram) SetZeroCountFloat(v float64) {\n\tx.ZeroCount = &Histogram_ZeroCountFloat{v}\n}\n\nfunc (x *Histogram) SetNegativeSpans(v []*BucketSpan) {\n\tx.NegativeSpans = v\n}\n\nfunc (x *Histogram) SetNegativeDeltas(v []int64) {\n\tx.NegativeDeltas = v\n}\n\nfunc (x *Histogram) SetNegativeCounts(v []float64) {\n\tx.NegativeCounts = v\n}\n\nfunc (x *Histogram) SetPositiveSpans(v []*BucketSpan) {\n\tx.PositiveSpans = v\n}\n\nfunc (x *Histogram) SetPositiveDeltas(v []int64) {\n\tx.PositiveDeltas = v\n}\n\nfunc (x *Histogram) SetPositiveCounts(v []float64) {\n\tx.PositiveCounts = v\n}\n\nfunc (x *Histogram) SetResetHint(v Histogram_ResetHint) {\n\tx.ResetHint = v\n}\n\nfunc (x *Histogram) SetTimestamp(v int64) {\n\tx.Timestamp = v\n}\n\nfunc (x *Histogram) SetCustomValues(v []float64) {\n\tx.CustomValues = v\n}\n\nfunc (x *Histogram) HasCount() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\treturn x.Count != nil\n}\n\nfunc (x *Histogram) HasCountInt() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.Count.(*Histogram_CountInt)\n\treturn ok\n}\n\nfunc (x *Histogram) HasCountFloat() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.Count.(*Histogram_CountFloat)\n\treturn ok\n}\n\nfunc (x *Histogram) HasZeroCount() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\treturn x.ZeroCount != nil\n}\n\nfunc (x *Histogram) HasZeroCountInt() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.ZeroCount.(*Histogram_ZeroCountInt)\n\treturn ok\n}\n\nfunc (x *Histogram) HasZeroCountFloat() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.ZeroCount.(*Histogram_ZeroCountFloat)\n\treturn ok\n}\n\nfunc (x *Histogram) ClearCount() {\n\tx.Count = nil\n}\n\nfunc (x *Histogram) ClearCountInt() {\n\tif _, ok := x.Count.(*Histogram_CountInt); ok {\n\t\tx.Count = nil\n\t}\n}\n\nfunc (x *Histogram) ClearCountFloat() {\n\tif _, ok := x.Count.(*Histogram_CountFloat); ok {\n\t\tx.Count = nil\n\t}\n}\n\nfunc (x *Histogram) ClearZeroCount() {\n\tx.ZeroCount = nil\n}\n\nfunc (x *Histogram) ClearZeroCountInt() {\n\tif _, ok := x.ZeroCount.(*Histogram_ZeroCountInt); ok {\n\t\tx.ZeroCount = nil\n\t}\n}\n\nfunc (x *Histogram) ClearZeroCountFloat() {\n\tif _, ok := x.ZeroCount.(*Histogram_ZeroCountFloat); ok {\n\t\tx.ZeroCount = nil\n\t}\n}\n\nconst Histogram_Count_not_set_case case_Histogram_Count = 0\nconst Histogram_CountInt_case case_Histogram_Count = 1\nconst Histogram_CountFloat_case case_Histogram_Count = 2\n\nfunc (x *Histogram) WhichCount() case_Histogram_Count {\n\tif x == nil {\n\t\treturn Histogram_Count_not_set_case\n\t}\n\tswitch x.Count.(type) {\n\tcase *Histogram_CountInt:\n\t\treturn Histogram_CountInt_case\n\tcase *Histogram_CountFloat:\n\t\treturn Histogram_CountFloat_case\n\tdefault:\n\t\treturn Histogram_Count_not_set_case\n\t}\n}\n\nconst Histogram_ZeroCount_not_set_case case_Histogram_ZeroCount = 0\nconst Histogram_ZeroCountInt_case case_Histogram_ZeroCount = 6\nconst Histogram_ZeroCountFloat_case case_Histogram_ZeroCount = 7\n\nfunc (x *Histogram) WhichZeroCount() case_Histogram_ZeroCount {\n\tif x == nil {\n\t\treturn Histogram_ZeroCount_not_set_case\n\t}\n\tswitch x.ZeroCount.(type) {\n\tcase *Histogram_ZeroCountInt:\n\t\treturn Histogram_ZeroCountInt_case\n\tcase *Histogram_ZeroCountFloat:\n\t\treturn Histogram_ZeroCountFloat_case\n\tdefault:\n\t\treturn Histogram_ZeroCount_not_set_case\n\t}\n}\n\ntype Histogram_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Fields of oneof Count:\n\tCountInt   *uint64\n\tCountFloat *float64\n\t// -- end of Count\n\tSum float64\n\t// The schema defines the bucket schema. Currently, valid numbers\n\t// are -4 <= n <= 8. They are all for base-2 bucket schemas, where 1\n\t// is a bucket boundary in each case, and then each power of two is\n\t// divided into 2^n logarithmic buckets. Or in other words, each\n\t// bucket boundary is the previous boundary times 2^(2^-n). In the\n\t// future, more bucket schemas may be added using numbers < -4 or >\n\t// 8.\n\tSchema        int32\n\tZeroThreshold float64\n\t// Fields of oneof ZeroCount:\n\tZeroCountInt   *uint64\n\tZeroCountFloat *float64\n\t// -- end of ZeroCount\n\t// Negative Buckets.\n\tNegativeSpans []*BucketSpan\n\t// Use either \"negative_deltas\" or \"negative_counts\", the former for\n\t// regular histograms with integer counts, the latter for float\n\t// histograms.\n\tNegativeDeltas []int64\n\tNegativeCounts []float64\n\t// Positive Buckets.\n\tPositiveSpans []*BucketSpan\n\t// Use either \"positive_deltas\" or \"positive_counts\", the former for\n\t// regular histograms with integer counts, the latter for float\n\t// histograms.\n\tPositiveDeltas []int64\n\tPositiveCounts []float64\n\tResetHint      Histogram_ResetHint\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp int64\n\t// custom_values are not part of the specification, DO NOT use in remote write clients.\n\t// Used only for converting from OpenTelemetry to Prometheus internally.\n\tCustomValues []float64\n}\n\nfunc (b0 Histogram_builder) Build() *Histogram {\n\tm0 := &Histogram{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tif b.CountInt != nil {\n\t\tx.Count = &Histogram_CountInt{*b.CountInt}\n\t}\n\tif b.CountFloat != nil {\n\t\tx.Count = &Histogram_CountFloat{*b.CountFloat}\n\t}\n\tx.Sum = b.Sum\n\tx.Schema = b.Schema\n\tx.ZeroThreshold = b.ZeroThreshold\n\tif b.ZeroCountInt != nil {\n\t\tx.ZeroCount = &Histogram_ZeroCountInt{*b.ZeroCountInt}\n\t}\n\tif b.ZeroCountFloat != nil {\n\t\tx.ZeroCount = &Histogram_ZeroCountFloat{*b.ZeroCountFloat}\n\t}\n\tx.NegativeSpans = b.NegativeSpans\n\tx.NegativeDeltas = b.NegativeDeltas\n\tx.NegativeCounts = b.NegativeCounts\n\tx.PositiveSpans = b.PositiveSpans\n\tx.PositiveDeltas = b.PositiveDeltas\n\tx.PositiveCounts = b.PositiveCounts\n\tx.ResetHint = b.ResetHint\n\tx.Timestamp = b.Timestamp\n\tx.CustomValues = b.CustomValues\n\treturn m0\n}\n\ntype case_Histogram_Count protoreflect.FieldNumber\n\nfunc (x case_Histogram_Count) String() string {\n\tmd := file_types_proto_msgTypes[3].Descriptor()\n\tif x == 0 {\n\t\treturn \"not set\"\n\t}\n\treturn protoimpl.X.MessageFieldStringOf(md, protoreflect.FieldNumber(x))\n}\n\ntype case_Histogram_ZeroCount protoreflect.FieldNumber\n\nfunc (x case_Histogram_ZeroCount) String() string {\n\tmd := file_types_proto_msgTypes[3].Descriptor()\n\tif x == 0 {\n\t\treturn \"not set\"\n\t}\n\treturn protoimpl.X.MessageFieldStringOf(md, protoreflect.FieldNumber(x))\n}\n\ntype isHistogram_Count interface {\n\tisHistogram_Count()\n}\n\ntype Histogram_CountInt struct {\n\tCountInt uint64 `protobuf:\"varint,1,opt,name=count_int,json=countInt,proto3,oneof\"`\n}\n\ntype Histogram_CountFloat struct {\n\tCountFloat float64 `protobuf:\"fixed64,2,opt,name=count_float,json=countFloat,proto3,oneof\"`\n}\n\nfunc (*Histogram_CountInt) isHistogram_Count() {}\n\nfunc (*Histogram_CountFloat) isHistogram_Count() {}\n\ntype isHistogram_ZeroCount interface {\n\tisHistogram_ZeroCount()\n}\n\ntype Histogram_ZeroCountInt struct {\n\tZeroCountInt uint64 `protobuf:\"varint,6,opt,name=zero_count_int,json=zeroCountInt,proto3,oneof\"`\n}\n\ntype Histogram_ZeroCountFloat struct {\n\tZeroCountFloat float64 `protobuf:\"fixed64,7,opt,name=zero_count_float,json=zeroCountFloat,proto3,oneof\"`\n}\n\nfunc (*Histogram_ZeroCountInt) isHistogram_ZeroCount() {}\n\nfunc (*Histogram_ZeroCountFloat) isHistogram_ZeroCount() {}\n\n// A BucketSpan defines a number of consecutive buckets with their\n// offset. Logically, it would be more straightforward to include the\n// bucket counts in the Span. However, the protobuf representation is\n// more compact in the way the data is structured here (with all the\n// buckets in a single array separate from the Spans).\ntype BucketSpan struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tOffset        int32                  `protobuf:\"zigzag32,1,opt,name=offset,proto3\" json:\"offset,omitempty\"` // Gap to previous span, or starting point for 1st span (which can be negative).\n\tLength        uint32                 `protobuf:\"varint,2,opt,name=length,proto3\" json:\"length,omitempty\"`   // Length of consecutive buckets.\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *BucketSpan) Reset() {\n\t*x = BucketSpan{}\n\tmi := &file_types_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BucketSpan) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BucketSpan) ProtoMessage() {}\n\nfunc (x *BucketSpan) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *BucketSpan) GetOffset() int32 {\n\tif x != nil {\n\t\treturn x.Offset\n\t}\n\treturn 0\n}\n\nfunc (x *BucketSpan) GetLength() uint32 {\n\tif x != nil {\n\t\treturn x.Length\n\t}\n\treturn 0\n}\n\nfunc (x *BucketSpan) SetOffset(v int32) {\n\tx.Offset = v\n}\n\nfunc (x *BucketSpan) SetLength(v uint32) {\n\tx.Length = v\n}\n\ntype BucketSpan_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tOffset int32\n\tLength uint32\n}\n\nfunc (b0 BucketSpan_builder) Build() *BucketSpan {\n\tm0 := &BucketSpan{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Offset = b.Offset\n\tx.Length = b.Length\n\treturn m0\n}\n\n// TimeSeries represents samples and labels for a single time series.\ntype TimeSeries struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\t// For a timeseries to be valid, and for the samples and exemplars\n\t// to be ingested by the remote system properly, the labels field is required.\n\tLabels        []*Label     `protobuf:\"bytes,1,rep,name=labels,proto3\" json:\"labels,omitempty\"`\n\tSamples       []*Sample    `protobuf:\"bytes,2,rep,name=samples,proto3\" json:\"samples,omitempty\"`\n\tExemplars     []*Exemplar  `protobuf:\"bytes,3,rep,name=exemplars,proto3\" json:\"exemplars,omitempty\"`\n\tHistograms    []*Histogram `protobuf:\"bytes,4,rep,name=histograms,proto3\" json:\"histograms,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *TimeSeries) Reset() {\n\t*x = TimeSeries{}\n\tmi := &file_types_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TimeSeries) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TimeSeries) ProtoMessage() {}\n\nfunc (x *TimeSeries) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *TimeSeries) GetLabels() []*Label {\n\tif x != nil {\n\t\treturn x.Labels\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetSamples() []*Sample {\n\tif x != nil {\n\t\treturn x.Samples\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetExemplars() []*Exemplar {\n\tif x != nil {\n\t\treturn x.Exemplars\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetHistograms() []*Histogram {\n\tif x != nil {\n\t\treturn x.Histograms\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) SetLabels(v []*Label) {\n\tx.Labels = v\n}\n\nfunc (x *TimeSeries) SetSamples(v []*Sample) {\n\tx.Samples = v\n}\n\nfunc (x *TimeSeries) SetExemplars(v []*Exemplar) {\n\tx.Exemplars = v\n}\n\nfunc (x *TimeSeries) SetHistograms(v []*Histogram) {\n\tx.Histograms = v\n}\n\ntype TimeSeries_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// For a timeseries to be valid, and for the samples and exemplars\n\t// to be ingested by the remote system properly, the labels field is required.\n\tLabels     []*Label\n\tSamples    []*Sample\n\tExemplars  []*Exemplar\n\tHistograms []*Histogram\n}\n\nfunc (b0 TimeSeries_builder) Build() *TimeSeries {\n\tm0 := &TimeSeries{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Labels = b.Labels\n\tx.Samples = b.Samples\n\tx.Exemplars = b.Exemplars\n\tx.Histograms = b.Histograms\n\treturn m0\n}\n\ntype Label struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tName          string                 `protobuf:\"bytes,1,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tValue         string                 `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Label) Reset() {\n\t*x = Label{}\n\tmi := &file_types_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Label) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Label) ProtoMessage() {}\n\nfunc (x *Label) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Label) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Label) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\nfunc (x *Label) SetName(v string) {\n\tx.Name = v\n}\n\nfunc (x *Label) SetValue(v string) {\n\tx.Value = v\n}\n\ntype Label_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tName  string\n\tValue string\n}\n\nfunc (b0 Label_builder) Build() *Label {\n\tm0 := &Label{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Name = b.Name\n\tx.Value = b.Value\n\treturn m0\n}\n\ntype Labels struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tLabels        []*Label               `protobuf:\"bytes,1,rep,name=labels,proto3\" json:\"labels,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Labels) Reset() {\n\t*x = Labels{}\n\tmi := &file_types_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Labels) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Labels) ProtoMessage() {}\n\nfunc (x *Labels) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Labels) GetLabels() []*Label {\n\tif x != nil {\n\t\treturn x.Labels\n\t}\n\treturn nil\n}\n\nfunc (x *Labels) SetLabels(v []*Label) {\n\tx.Labels = v\n}\n\ntype Labels_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tLabels []*Label\n}\n\nfunc (b0 Labels_builder) Build() *Labels {\n\tm0 := &Labels{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Labels = b.Labels\n\treturn m0\n}\n\n// Matcher specifies a rule, which can match or set of labels or not.\ntype LabelMatcher struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tType          LabelMatcher_Type      `protobuf:\"varint,1,opt,name=type,proto3,enum=prometheus.LabelMatcher_Type\" json:\"type,omitempty\"`\n\tName          string                 `protobuf:\"bytes,2,opt,name=name,proto3\" json:\"name,omitempty\"`\n\tValue         string                 `protobuf:\"bytes,3,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *LabelMatcher) Reset() {\n\t*x = LabelMatcher{}\n\tmi := &file_types_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LabelMatcher) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LabelMatcher) ProtoMessage() {}\n\nfunc (x *LabelMatcher) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *LabelMatcher) GetType() LabelMatcher_Type {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn LabelMatcher_EQ\n}\n\nfunc (x *LabelMatcher) GetName() string {\n\tif x != nil {\n\t\treturn x.Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *LabelMatcher) GetValue() string {\n\tif x != nil {\n\t\treturn x.Value\n\t}\n\treturn \"\"\n}\n\nfunc (x *LabelMatcher) SetType(v LabelMatcher_Type) {\n\tx.Type = v\n}\n\nfunc (x *LabelMatcher) SetName(v string) {\n\tx.Name = v\n}\n\nfunc (x *LabelMatcher) SetValue(v string) {\n\tx.Value = v\n}\n\ntype LabelMatcher_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tType  LabelMatcher_Type\n\tName  string\n\tValue string\n}\n\nfunc (b0 LabelMatcher_builder) Build() *LabelMatcher {\n\tm0 := &LabelMatcher{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Type = b.Type\n\tx.Name = b.Name\n\tx.Value = b.Value\n\treturn m0\n}\n\ntype ReadHints struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tStepMs        int64                  `protobuf:\"varint,1,opt,name=step_ms,json=stepMs,proto3\" json:\"step_ms,omitempty\"`    // Query step size in milliseconds.\n\tFunc          string                 `protobuf:\"bytes,2,opt,name=func,proto3\" json:\"func,omitempty\"`                       // String representation of surrounding function or aggregation.\n\tStartMs       int64                  `protobuf:\"varint,3,opt,name=start_ms,json=startMs,proto3\" json:\"start_ms,omitempty\"` // Start time in milliseconds.\n\tEndMs         int64                  `protobuf:\"varint,4,opt,name=end_ms,json=endMs,proto3\" json:\"end_ms,omitempty\"`       // End time in milliseconds.\n\tGrouping      []string               `protobuf:\"bytes,5,rep,name=grouping,proto3\" json:\"grouping,omitempty\"`               // List of label names used in aggregation.\n\tBy            bool                   `protobuf:\"varint,6,opt,name=by,proto3\" json:\"by,omitempty\"`                          // Indicate whether it is without or by.\n\tRangeMs       int64                  `protobuf:\"varint,7,opt,name=range_ms,json=rangeMs,proto3\" json:\"range_ms,omitempty\"` // Range vector selector range in milliseconds.\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ReadHints) Reset() {\n\t*x = ReadHints{}\n\tmi := &file_types_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReadHints) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadHints) ProtoMessage() {}\n\nfunc (x *ReadHints) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ReadHints) GetStepMs() int64 {\n\tif x != nil {\n\t\treturn x.StepMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) GetFunc() string {\n\tif x != nil {\n\t\treturn x.Func\n\t}\n\treturn \"\"\n}\n\nfunc (x *ReadHints) GetStartMs() int64 {\n\tif x != nil {\n\t\treturn x.StartMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) GetEndMs() int64 {\n\tif x != nil {\n\t\treturn x.EndMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) GetGrouping() []string {\n\tif x != nil {\n\t\treturn x.Grouping\n\t}\n\treturn nil\n}\n\nfunc (x *ReadHints) GetBy() bool {\n\tif x != nil {\n\t\treturn x.By\n\t}\n\treturn false\n}\n\nfunc (x *ReadHints) GetRangeMs() int64 {\n\tif x != nil {\n\t\treturn x.RangeMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) SetStepMs(v int64) {\n\tx.StepMs = v\n}\n\nfunc (x *ReadHints) SetFunc(v string) {\n\tx.Func = v\n}\n\nfunc (x *ReadHints) SetStartMs(v int64) {\n\tx.StartMs = v\n}\n\nfunc (x *ReadHints) SetEndMs(v int64) {\n\tx.EndMs = v\n}\n\nfunc (x *ReadHints) SetGrouping(v []string) {\n\tx.Grouping = v\n}\n\nfunc (x *ReadHints) SetBy(v bool) {\n\tx.By = v\n}\n\nfunc (x *ReadHints) SetRangeMs(v int64) {\n\tx.RangeMs = v\n}\n\ntype ReadHints_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tStepMs   int64\n\tFunc     string\n\tStartMs  int64\n\tEndMs    int64\n\tGrouping []string\n\tBy       bool\n\tRangeMs  int64\n}\n\nfunc (b0 ReadHints_builder) Build() *ReadHints {\n\tm0 := &ReadHints{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.StepMs = b.StepMs\n\tx.Func = b.Func\n\tx.StartMs = b.StartMs\n\tx.EndMs = b.EndMs\n\tx.Grouping = b.Grouping\n\tx.By = b.By\n\tx.RangeMs = b.RangeMs\n\treturn m0\n}\n\n// Chunk represents a TSDB chunk.\n// Time range [min, max] is inclusive.\ntype Chunk struct {\n\tstate         protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\tMinTimeMs     int64                  `protobuf:\"varint,1,opt,name=min_time_ms,json=minTimeMs,proto3\" json:\"min_time_ms,omitempty\"`\n\tMaxTimeMs     int64                  `protobuf:\"varint,2,opt,name=max_time_ms,json=maxTimeMs,proto3\" json:\"max_time_ms,omitempty\"`\n\tType          Chunk_Encoding         `protobuf:\"varint,3,opt,name=type,proto3,enum=prometheus.Chunk_Encoding\" json:\"type,omitempty\"`\n\tData          []byte                 `protobuf:\"bytes,4,opt,name=data,proto3\" json:\"data,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *Chunk) Reset() {\n\t*x = Chunk{}\n\tmi := &file_types_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Chunk) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Chunk) ProtoMessage() {}\n\nfunc (x *Chunk) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Chunk) GetMinTimeMs() int64 {\n\tif x != nil {\n\t\treturn x.MinTimeMs\n\t}\n\treturn 0\n}\n\nfunc (x *Chunk) GetMaxTimeMs() int64 {\n\tif x != nil {\n\t\treturn x.MaxTimeMs\n\t}\n\treturn 0\n}\n\nfunc (x *Chunk) GetType() Chunk_Encoding {\n\tif x != nil {\n\t\treturn x.Type\n\t}\n\treturn Chunk_UNKNOWN\n}\n\nfunc (x *Chunk) GetData() []byte {\n\tif x != nil {\n\t\treturn x.Data\n\t}\n\treturn nil\n}\n\nfunc (x *Chunk) SetMinTimeMs(v int64) {\n\tx.MinTimeMs = v\n}\n\nfunc (x *Chunk) SetMaxTimeMs(v int64) {\n\tx.MaxTimeMs = v\n}\n\nfunc (x *Chunk) SetType(v Chunk_Encoding) {\n\tx.Type = v\n}\n\nfunc (x *Chunk) SetData(v []byte) {\n\tif v == nil {\n\t\tv = []byte{}\n\t}\n\tx.Data = v\n}\n\ntype Chunk_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tMinTimeMs int64\n\tMaxTimeMs int64\n\tType      Chunk_Encoding\n\tData      []byte\n}\n\nfunc (b0 Chunk_builder) Build() *Chunk {\n\tm0 := &Chunk{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.MinTimeMs = b.MinTimeMs\n\tx.MaxTimeMs = b.MaxTimeMs\n\tx.Type = b.Type\n\tx.Data = b.Data\n\treturn m0\n}\n\n// ChunkedSeries represents single, encoded time series.\ntype ChunkedSeries struct {\n\tstate protoimpl.MessageState `protogen:\"hybrid.v1\"`\n\t// Labels should be sorted.\n\tLabels []*Label `protobuf:\"bytes,1,rep,name=labels,proto3\" json:\"labels,omitempty\"`\n\t// Chunks will be in start time order and may overlap.\n\tChunks        []*Chunk `protobuf:\"bytes,2,rep,name=chunks,proto3\" json:\"chunks,omitempty\"`\n\tunknownFields protoimpl.UnknownFields\n\tsizeCache     protoimpl.SizeCache\n}\n\nfunc (x *ChunkedSeries) Reset() {\n\t*x = ChunkedSeries{}\n\tmi := &file_types_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ChunkedSeries) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ChunkedSeries) ProtoMessage() {}\n\nfunc (x *ChunkedSeries) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ChunkedSeries) GetLabels() []*Label {\n\tif x != nil {\n\t\treturn x.Labels\n\t}\n\treturn nil\n}\n\nfunc (x *ChunkedSeries) GetChunks() []*Chunk {\n\tif x != nil {\n\t\treturn x.Chunks\n\t}\n\treturn nil\n}\n\nfunc (x *ChunkedSeries) SetLabels(v []*Label) {\n\tx.Labels = v\n}\n\nfunc (x *ChunkedSeries) SetChunks(v []*Chunk) {\n\tx.Chunks = v\n}\n\ntype ChunkedSeries_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Labels should be sorted.\n\tLabels []*Label\n\t// Chunks will be in start time order and may overlap.\n\tChunks []*Chunk\n}\n\nfunc (b0 ChunkedSeries_builder) Build() *ChunkedSeries {\n\tm0 := &ChunkedSeries{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.Labels = b.Labels\n\tx.Chunks = b.Chunks\n\treturn m0\n}\n\nvar File_types_proto protoreflect.FileDescriptor\n\nconst file_types_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\vtypes.proto\\x12\\n\" +\n\t\"prometheus\\x1a\\x14gogoproto/gogo.proto\\\"\\x9c\\x02\\n\" +\n\t\"\\x0eMetricMetadata\\x129\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\x0e2%.prometheus.MetricMetadata.MetricTypeR\\x04type\\x12,\\n\" +\n\t\"\\x12metric_family_name\\x18\\x02 \\x01(\\tR\\x10metricFamilyName\\x12\\x12\\n\" +\n\t\"\\x04help\\x18\\x04 \\x01(\\tR\\x04help\\x12\\x12\\n\" +\n\t\"\\x04unit\\x18\\x05 \\x01(\\tR\\x04unit\\\"y\\n\" +\n\t\"\\n\" +\n\t\"MetricType\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\v\\n\" +\n\t\"\\aCOUNTER\\x10\\x01\\x12\\t\\n\" +\n\t\"\\x05GAUGE\\x10\\x02\\x12\\r\\n\" +\n\t\"\\tHISTOGRAM\\x10\\x03\\x12\\x12\\n\" +\n\t\"\\x0eGAUGEHISTOGRAM\\x10\\x04\\x12\\v\\n\" +\n\t\"\\aSUMMARY\\x10\\x05\\x12\\b\\n\" +\n\t\"\\x04INFO\\x10\\x06\\x12\\f\\n\" +\n\t\"\\bSTATESET\\x10\\a\\\"<\\n\" +\n\t\"\\x06Sample\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x01 \\x01(\\x01R\\x05value\\x12\\x1c\\n\" +\n\t\"\\ttimestamp\\x18\\x02 \\x01(\\x03R\\ttimestamp\\\"o\\n\" +\n\t\"\\bExemplar\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\x01R\\x05value\\x12\\x1c\\n\" +\n\t\"\\ttimestamp\\x18\\x03 \\x01(\\x03R\\ttimestamp\\\"\\xf0\\x05\\n\" +\n\t\"\\tHistogram\\x12\\x1d\\n\" +\n\t\"\\tcount_int\\x18\\x01 \\x01(\\x04H\\x00R\\bcountInt\\x12!\\n\" +\n\t\"\\vcount_float\\x18\\x02 \\x01(\\x01H\\x00R\\n\" +\n\t\"countFloat\\x12\\x10\\n\" +\n\t\"\\x03sum\\x18\\x03 \\x01(\\x01R\\x03sum\\x12\\x16\\n\" +\n\t\"\\x06schema\\x18\\x04 \\x01(\\x11R\\x06schema\\x12%\\n\" +\n\t\"\\x0ezero_threshold\\x18\\x05 \\x01(\\x01R\\rzeroThreshold\\x12&\\n\" +\n\t\"\\x0ezero_count_int\\x18\\x06 \\x01(\\x04H\\x01R\\fzeroCountInt\\x12*\\n\" +\n\t\"\\x10zero_count_float\\x18\\a \\x01(\\x01H\\x01R\\x0ezeroCountFloat\\x12C\\n\" +\n\t\"\\x0enegative_spans\\x18\\b \\x03(\\v2\\x16.prometheus.BucketSpanB\\x04\\xc8\\xde\\x1f\\x00R\\rnegativeSpans\\x12'\\n\" +\n\t\"\\x0fnegative_deltas\\x18\\t \\x03(\\x12R\\x0enegativeDeltas\\x12'\\n\" +\n\t\"\\x0fnegative_counts\\x18\\n\" +\n\t\" \\x03(\\x01R\\x0enegativeCounts\\x12C\\n\" +\n\t\"\\x0epositive_spans\\x18\\v \\x03(\\v2\\x16.prometheus.BucketSpanB\\x04\\xc8\\xde\\x1f\\x00R\\rpositiveSpans\\x12'\\n\" +\n\t\"\\x0fpositive_deltas\\x18\\f \\x03(\\x12R\\x0epositiveDeltas\\x12'\\n\" +\n\t\"\\x0fpositive_counts\\x18\\r \\x03(\\x01R\\x0epositiveCounts\\x12>\\n\" +\n\t\"\\n\" +\n\t\"reset_hint\\x18\\x0e \\x01(\\x0e2\\x1f.prometheus.Histogram.ResetHintR\\tresetHint\\x12\\x1c\\n\" +\n\t\"\\ttimestamp\\x18\\x0f \\x01(\\x03R\\ttimestamp\\x12#\\n\" +\n\t\"\\rcustom_values\\x18\\x10 \\x03(\\x01R\\fcustomValues\\\"4\\n\" +\n\t\"\\tResetHint\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03YES\\x10\\x01\\x12\\x06\\n\" +\n\t\"\\x02NO\\x10\\x02\\x12\\t\\n\" +\n\t\"\\x05GAUGE\\x10\\x03B\\a\\n\" +\n\t\"\\x05countB\\f\\n\" +\n\t\"\\n\" +\n\t\"zero_count\\\"<\\n\" +\n\t\"\\n\" +\n\t\"BucketSpan\\x12\\x16\\n\" +\n\t\"\\x06offset\\x18\\x01 \\x01(\\x11R\\x06offset\\x12\\x16\\n\" +\n\t\"\\x06length\\x18\\x02 \\x01(\\rR\\x06length\\\"\\xe8\\x01\\n\" +\n\t\"\\n\" +\n\t\"TimeSeries\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\x122\\n\" +\n\t\"\\asamples\\x18\\x02 \\x03(\\v2\\x12.prometheus.SampleB\\x04\\xc8\\xde\\x1f\\x00R\\asamples\\x128\\n\" +\n\t\"\\texemplars\\x18\\x03 \\x03(\\v2\\x14.prometheus.ExemplarB\\x04\\xc8\\xde\\x1f\\x00R\\texemplars\\x12;\\n\" +\n\t\"\\n\" +\n\t\"histograms\\x18\\x04 \\x03(\\v2\\x15.prometheus.HistogramB\\x04\\xc8\\xde\\x1f\\x00R\\n\" +\n\t\"histograms\\\"1\\n\" +\n\t\"\\x05Label\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value\\\"9\\n\" +\n\t\"\\x06Labels\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\\"\\x95\\x01\\n\" +\n\t\"\\fLabelMatcher\\x121\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\x0e2\\x1d.prometheus.LabelMatcher.TypeR\\x04type\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x03 \\x01(\\tR\\x05value\\\"(\\n\" +\n\t\"\\x04Type\\x12\\x06\\n\" +\n\t\"\\x02EQ\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03NEQ\\x10\\x01\\x12\\x06\\n\" +\n\t\"\\x02RE\\x10\\x02\\x12\\a\\n\" +\n\t\"\\x03NRE\\x10\\x03\\\"\\xb1\\x01\\n\" +\n\t\"\\tReadHints\\x12\\x17\\n\" +\n\t\"\\astep_ms\\x18\\x01 \\x01(\\x03R\\x06stepMs\\x12\\x12\\n\" +\n\t\"\\x04func\\x18\\x02 \\x01(\\tR\\x04func\\x12\\x19\\n\" +\n\t\"\\bstart_ms\\x18\\x03 \\x01(\\x03R\\astartMs\\x12\\x15\\n\" +\n\t\"\\x06end_ms\\x18\\x04 \\x01(\\x03R\\x05endMs\\x12\\x1a\\n\" +\n\t\"\\bgrouping\\x18\\x05 \\x03(\\tR\\bgrouping\\x12\\x0e\\n\" +\n\t\"\\x02by\\x18\\x06 \\x01(\\bR\\x02by\\x12\\x19\\n\" +\n\t\"\\brange_ms\\x18\\a \\x01(\\x03R\\arangeMs\\\"\\xd1\\x01\\n\" +\n\t\"\\x05Chunk\\x12\\x1e\\n\" +\n\t\"\\vmin_time_ms\\x18\\x01 \\x01(\\x03R\\tminTimeMs\\x12\\x1e\\n\" +\n\t\"\\vmax_time_ms\\x18\\x02 \\x01(\\x03R\\tmaxTimeMs\\x12.\\n\" +\n\t\"\\x04type\\x18\\x03 \\x01(\\x0e2\\x1a.prometheus.Chunk.EncodingR\\x04type\\x12\\x12\\n\" +\n\t\"\\x04data\\x18\\x04 \\x01(\\fR\\x04data\\\"D\\n\" +\n\t\"\\bEncoding\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03XOR\\x10\\x01\\x12\\r\\n\" +\n\t\"\\tHISTOGRAM\\x10\\x02\\x12\\x13\\n\" +\n\t\"\\x0fFLOAT_HISTOGRAM\\x10\\x03\\\"q\\n\" +\n\t\"\\rChunkedSeries\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\x12/\\n\" +\n\t\"\\x06chunks\\x18\\x02 \\x03(\\v2\\x11.prometheus.ChunkB\\x04\\xc8\\xde\\x1f\\x00R\\x06chunksB;Z9buf.build/gen/go/prometheus/prometheus/protocolbuffers/gob\\x06proto3\"\n\nvar file_types_proto_enumTypes = make([]protoimpl.EnumInfo, 4)\nvar file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 12)\nvar file_types_proto_goTypes = []any{\n\t(MetricMetadata_MetricType)(0), // 0: prometheus.MetricMetadata.MetricType\n\t(Histogram_ResetHint)(0),       // 1: prometheus.Histogram.ResetHint\n\t(LabelMatcher_Type)(0),         // 2: prometheus.LabelMatcher.Type\n\t(Chunk_Encoding)(0),            // 3: prometheus.Chunk.Encoding\n\t(*MetricMetadata)(nil),         // 4: prometheus.MetricMetadata\n\t(*Sample)(nil),                 // 5: prometheus.Sample\n\t(*Exemplar)(nil),               // 6: prometheus.Exemplar\n\t(*Histogram)(nil),              // 7: prometheus.Histogram\n\t(*BucketSpan)(nil),             // 8: prometheus.BucketSpan\n\t(*TimeSeries)(nil),             // 9: prometheus.TimeSeries\n\t(*Label)(nil),                  // 10: prometheus.Label\n\t(*Labels)(nil),                 // 11: prometheus.Labels\n\t(*LabelMatcher)(nil),           // 12: prometheus.LabelMatcher\n\t(*ReadHints)(nil),              // 13: prometheus.ReadHints\n\t(*Chunk)(nil),                  // 14: prometheus.Chunk\n\t(*ChunkedSeries)(nil),          // 15: prometheus.ChunkedSeries\n}\nvar file_types_proto_depIdxs = []int32{\n\t0,  // 0: prometheus.MetricMetadata.type:type_name -> prometheus.MetricMetadata.MetricType\n\t10, // 1: prometheus.Exemplar.labels:type_name -> prometheus.Label\n\t8,  // 2: prometheus.Histogram.negative_spans:type_name -> prometheus.BucketSpan\n\t8,  // 3: prometheus.Histogram.positive_spans:type_name -> prometheus.BucketSpan\n\t1,  // 4: prometheus.Histogram.reset_hint:type_name -> prometheus.Histogram.ResetHint\n\t10, // 5: prometheus.TimeSeries.labels:type_name -> prometheus.Label\n\t5,  // 6: prometheus.TimeSeries.samples:type_name -> prometheus.Sample\n\t6,  // 7: prometheus.TimeSeries.exemplars:type_name -> prometheus.Exemplar\n\t7,  // 8: prometheus.TimeSeries.histograms:type_name -> prometheus.Histogram\n\t10, // 9: prometheus.Labels.labels:type_name -> prometheus.Label\n\t2,  // 10: prometheus.LabelMatcher.type:type_name -> prometheus.LabelMatcher.Type\n\t3,  // 11: prometheus.Chunk.type:type_name -> prometheus.Chunk.Encoding\n\t10, // 12: prometheus.ChunkedSeries.labels:type_name -> prometheus.Label\n\t14, // 13: prometheus.ChunkedSeries.chunks:type_name -> prometheus.Chunk\n\t14, // [14:14] is the sub-list for method output_type\n\t14, // [14:14] is the sub-list for method input_type\n\t14, // [14:14] is the sub-list for extension type_name\n\t14, // [14:14] is the sub-list for extension extendee\n\t0,  // [0:14] is the sub-list for field type_name\n}\n\nfunc init() { file_types_proto_init() }\nfunc file_types_proto_init() {\n\tif File_types_proto != nil {\n\t\treturn\n\t}\n\tfile_types_proto_msgTypes[3].OneofWrappers = []any{\n\t\t(*Histogram_CountInt)(nil),\n\t\t(*Histogram_CountFloat)(nil),\n\t\t(*Histogram_ZeroCountInt)(nil),\n\t\t(*Histogram_ZeroCountFloat)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),\n\t\t\tNumEnums:      4,\n\t\t\tNumMessages:   12,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_types_proto_goTypes,\n\t\tDependencyIndexes: file_types_proto_depIdxs,\n\t\tEnumInfos:         file_types_proto_enumTypes,\n\t\tMessageInfos:      file_types_proto_msgTypes,\n\t}.Build()\n\tFile_types_proto = out.File\n\tfile_types_proto_goTypes = nil\n\tfile_types_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "vendor/buf.build/gen/go/prometheus/prometheus/protocolbuffers/go/types_protoopaque.pb.go",
    "content": "// Copyright 2017 Prometheus Team\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen-go v1.36.11\n// \tprotoc        (unknown)\n// source: types.proto\n\n//go:build protoopaque\n\npackage _go\n\nimport (\n\t_ \"buf.build/gen/go/gogo/protobuf/protocolbuffers/go/gogoproto\"\n\tprotoreflect \"google.golang.org/protobuf/reflect/protoreflect\"\n\tprotoimpl \"google.golang.org/protobuf/runtime/protoimpl\"\n\treflect \"reflect\"\n\tunsafe \"unsafe\"\n)\n\nconst (\n\t// Verify that this generated code is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)\n\t// Verify that runtime/protoimpl is sufficiently up-to-date.\n\t_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)\n)\n\ntype MetricMetadata_MetricType int32\n\nconst (\n\tMetricMetadata_UNKNOWN        MetricMetadata_MetricType = 0\n\tMetricMetadata_COUNTER        MetricMetadata_MetricType = 1\n\tMetricMetadata_GAUGE          MetricMetadata_MetricType = 2\n\tMetricMetadata_HISTOGRAM      MetricMetadata_MetricType = 3\n\tMetricMetadata_GAUGEHISTOGRAM MetricMetadata_MetricType = 4\n\tMetricMetadata_SUMMARY        MetricMetadata_MetricType = 5\n\tMetricMetadata_INFO           MetricMetadata_MetricType = 6\n\tMetricMetadata_STATESET       MetricMetadata_MetricType = 7\n)\n\n// Enum value maps for MetricMetadata_MetricType.\nvar (\n\tMetricMetadata_MetricType_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"COUNTER\",\n\t\t2: \"GAUGE\",\n\t\t3: \"HISTOGRAM\",\n\t\t4: \"GAUGEHISTOGRAM\",\n\t\t5: \"SUMMARY\",\n\t\t6: \"INFO\",\n\t\t7: \"STATESET\",\n\t}\n\tMetricMetadata_MetricType_value = map[string]int32{\n\t\t\"UNKNOWN\":        0,\n\t\t\"COUNTER\":        1,\n\t\t\"GAUGE\":          2,\n\t\t\"HISTOGRAM\":      3,\n\t\t\"GAUGEHISTOGRAM\": 4,\n\t\t\"SUMMARY\":        5,\n\t\t\"INFO\":           6,\n\t\t\"STATESET\":       7,\n\t}\n)\n\nfunc (x MetricMetadata_MetricType) Enum() *MetricMetadata_MetricType {\n\tp := new(MetricMetadata_MetricType)\n\t*p = x\n\treturn p\n}\n\nfunc (x MetricMetadata_MetricType) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (MetricMetadata_MetricType) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[0].Descriptor()\n}\n\nfunc (MetricMetadata_MetricType) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[0]\n}\n\nfunc (x MetricMetadata_MetricType) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype Histogram_ResetHint int32\n\nconst (\n\tHistogram_UNKNOWN Histogram_ResetHint = 0 // Need to test for a counter reset explicitly.\n\tHistogram_YES     Histogram_ResetHint = 1 // This is the 1st histogram after a counter reset.\n\tHistogram_NO      Histogram_ResetHint = 2 // There was no counter reset between this and the previous Histogram.\n\tHistogram_GAUGE   Histogram_ResetHint = 3 // This is a gauge histogram where counter resets don't happen.\n)\n\n// Enum value maps for Histogram_ResetHint.\nvar (\n\tHistogram_ResetHint_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"YES\",\n\t\t2: \"NO\",\n\t\t3: \"GAUGE\",\n\t}\n\tHistogram_ResetHint_value = map[string]int32{\n\t\t\"UNKNOWN\": 0,\n\t\t\"YES\":     1,\n\t\t\"NO\":      2,\n\t\t\"GAUGE\":   3,\n\t}\n)\n\nfunc (x Histogram_ResetHint) Enum() *Histogram_ResetHint {\n\tp := new(Histogram_ResetHint)\n\t*p = x\n\treturn p\n}\n\nfunc (x Histogram_ResetHint) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Histogram_ResetHint) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[1].Descriptor()\n}\n\nfunc (Histogram_ResetHint) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[1]\n}\n\nfunc (x Histogram_ResetHint) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype LabelMatcher_Type int32\n\nconst (\n\tLabelMatcher_EQ  LabelMatcher_Type = 0\n\tLabelMatcher_NEQ LabelMatcher_Type = 1\n\tLabelMatcher_RE  LabelMatcher_Type = 2\n\tLabelMatcher_NRE LabelMatcher_Type = 3\n)\n\n// Enum value maps for LabelMatcher_Type.\nvar (\n\tLabelMatcher_Type_name = map[int32]string{\n\t\t0: \"EQ\",\n\t\t1: \"NEQ\",\n\t\t2: \"RE\",\n\t\t3: \"NRE\",\n\t}\n\tLabelMatcher_Type_value = map[string]int32{\n\t\t\"EQ\":  0,\n\t\t\"NEQ\": 1,\n\t\t\"RE\":  2,\n\t\t\"NRE\": 3,\n\t}\n)\n\nfunc (x LabelMatcher_Type) Enum() *LabelMatcher_Type {\n\tp := new(LabelMatcher_Type)\n\t*p = x\n\treturn p\n}\n\nfunc (x LabelMatcher_Type) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (LabelMatcher_Type) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[2].Descriptor()\n}\n\nfunc (LabelMatcher_Type) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[2]\n}\n\nfunc (x LabelMatcher_Type) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\n// We require this to match chunkenc.Encoding.\ntype Chunk_Encoding int32\n\nconst (\n\tChunk_UNKNOWN         Chunk_Encoding = 0\n\tChunk_XOR             Chunk_Encoding = 1\n\tChunk_HISTOGRAM       Chunk_Encoding = 2\n\tChunk_FLOAT_HISTOGRAM Chunk_Encoding = 3\n)\n\n// Enum value maps for Chunk_Encoding.\nvar (\n\tChunk_Encoding_name = map[int32]string{\n\t\t0: \"UNKNOWN\",\n\t\t1: \"XOR\",\n\t\t2: \"HISTOGRAM\",\n\t\t3: \"FLOAT_HISTOGRAM\",\n\t}\n\tChunk_Encoding_value = map[string]int32{\n\t\t\"UNKNOWN\":         0,\n\t\t\"XOR\":             1,\n\t\t\"HISTOGRAM\":       2,\n\t\t\"FLOAT_HISTOGRAM\": 3,\n\t}\n)\n\nfunc (x Chunk_Encoding) Enum() *Chunk_Encoding {\n\tp := new(Chunk_Encoding)\n\t*p = x\n\treturn p\n}\n\nfunc (x Chunk_Encoding) String() string {\n\treturn protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))\n}\n\nfunc (Chunk_Encoding) Descriptor() protoreflect.EnumDescriptor {\n\treturn file_types_proto_enumTypes[3].Descriptor()\n}\n\nfunc (Chunk_Encoding) Type() protoreflect.EnumType {\n\treturn &file_types_proto_enumTypes[3]\n}\n\nfunc (x Chunk_Encoding) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(x)\n}\n\ntype MetricMetadata struct {\n\tstate                       protoimpl.MessageState    `protogen:\"opaque.v1\"`\n\txxx_hidden_Type             MetricMetadata_MetricType `protobuf:\"varint,1,opt,name=type,proto3,enum=prometheus.MetricMetadata_MetricType\"`\n\txxx_hidden_MetricFamilyName string                    `protobuf:\"bytes,2,opt,name=metric_family_name,json=metricFamilyName,proto3\"`\n\txxx_hidden_Help             string                    `protobuf:\"bytes,4,opt,name=help,proto3\"`\n\txxx_hidden_Unit             string                    `protobuf:\"bytes,5,opt,name=unit,proto3\"`\n\tunknownFields               protoimpl.UnknownFields\n\tsizeCache                   protoimpl.SizeCache\n}\n\nfunc (x *MetricMetadata) Reset() {\n\t*x = MetricMetadata{}\n\tmi := &file_types_proto_msgTypes[0]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *MetricMetadata) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*MetricMetadata) ProtoMessage() {}\n\nfunc (x *MetricMetadata) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[0]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *MetricMetadata) GetType() MetricMetadata_MetricType {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Type\n\t}\n\treturn MetricMetadata_UNKNOWN\n}\n\nfunc (x *MetricMetadata) GetMetricFamilyName() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_MetricFamilyName\n\t}\n\treturn \"\"\n}\n\nfunc (x *MetricMetadata) GetHelp() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Help\n\t}\n\treturn \"\"\n}\n\nfunc (x *MetricMetadata) GetUnit() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Unit\n\t}\n\treturn \"\"\n}\n\nfunc (x *MetricMetadata) SetType(v MetricMetadata_MetricType) {\n\tx.xxx_hidden_Type = v\n}\n\nfunc (x *MetricMetadata) SetMetricFamilyName(v string) {\n\tx.xxx_hidden_MetricFamilyName = v\n}\n\nfunc (x *MetricMetadata) SetHelp(v string) {\n\tx.xxx_hidden_Help = v\n}\n\nfunc (x *MetricMetadata) SetUnit(v string) {\n\tx.xxx_hidden_Unit = v\n}\n\ntype MetricMetadata_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Represents the metric type, these match the set from Prometheus.\n\t// Refer to github.com/prometheus/common/model/metadata.go for details.\n\tType             MetricMetadata_MetricType\n\tMetricFamilyName string\n\tHelp             string\n\tUnit             string\n}\n\nfunc (b0 MetricMetadata_builder) Build() *MetricMetadata {\n\tm0 := &MetricMetadata{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Type = b.Type\n\tx.xxx_hidden_MetricFamilyName = b.MetricFamilyName\n\tx.xxx_hidden_Help = b.Help\n\tx.xxx_hidden_Unit = b.Unit\n\treturn m0\n}\n\ntype Sample struct {\n\tstate                protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Value     float64                `protobuf:\"fixed64,1,opt,name=value,proto3\"`\n\txxx_hidden_Timestamp int64                  `protobuf:\"varint,2,opt,name=timestamp,proto3\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *Sample) Reset() {\n\t*x = Sample{}\n\tmi := &file_types_proto_msgTypes[1]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Sample) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Sample) ProtoMessage() {}\n\nfunc (x *Sample) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[1]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Sample) GetValue() float64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Value\n\t}\n\treturn 0\n}\n\nfunc (x *Sample) GetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Timestamp\n\t}\n\treturn 0\n}\n\nfunc (x *Sample) SetValue(v float64) {\n\tx.xxx_hidden_Value = v\n}\n\nfunc (x *Sample) SetTimestamp(v int64) {\n\tx.xxx_hidden_Timestamp = v\n}\n\ntype Sample_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tValue float64\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp int64\n}\n\nfunc (b0 Sample_builder) Build() *Sample {\n\tm0 := &Sample{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Value = b.Value\n\tx.xxx_hidden_Timestamp = b.Timestamp\n\treturn m0\n}\n\ntype Exemplar struct {\n\tstate                protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Labels    *[]*Label              `protobuf:\"bytes,1,rep,name=labels,proto3\"`\n\txxx_hidden_Value     float64                `protobuf:\"fixed64,2,opt,name=value,proto3\"`\n\txxx_hidden_Timestamp int64                  `protobuf:\"varint,3,opt,name=timestamp,proto3\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *Exemplar) Reset() {\n\t*x = Exemplar{}\n\tmi := &file_types_proto_msgTypes[2]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Exemplar) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Exemplar) ProtoMessage() {}\n\nfunc (x *Exemplar) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[2]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Exemplar) GetLabels() []*Label {\n\tif x != nil {\n\t\tif x.xxx_hidden_Labels != nil {\n\t\t\treturn *x.xxx_hidden_Labels\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *Exemplar) GetValue() float64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Value\n\t}\n\treturn 0\n}\n\nfunc (x *Exemplar) GetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Timestamp\n\t}\n\treturn 0\n}\n\nfunc (x *Exemplar) SetLabels(v []*Label) {\n\tx.xxx_hidden_Labels = &v\n}\n\nfunc (x *Exemplar) SetValue(v float64) {\n\tx.xxx_hidden_Value = v\n}\n\nfunc (x *Exemplar) SetTimestamp(v int64) {\n\tx.xxx_hidden_Timestamp = v\n}\n\ntype Exemplar_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Optional, can be empty.\n\tLabels []*Label\n\tValue  float64\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp int64\n}\n\nfunc (b0 Exemplar_builder) Build() *Exemplar {\n\tm0 := &Exemplar{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Labels = &b.Labels\n\tx.xxx_hidden_Value = b.Value\n\tx.xxx_hidden_Timestamp = b.Timestamp\n\treturn m0\n}\n\n// A native histogram, also known as a sparse histogram.\n// Original design doc:\n// https://docs.google.com/document/d/1cLNv3aufPZb3fNfaJgdaRBZsInZKKIHo9E6HinJVbpM/edit\n// The appendix of this design doc also explains the concept of float\n// histograms. This Histogram message can represent both, the usual\n// integer histogram as well as a float histogram.\ntype Histogram struct {\n\tstate                     protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Count          isHistogram_Count      `protobuf_oneof:\"count\"`\n\txxx_hidden_Sum            float64                `protobuf:\"fixed64,3,opt,name=sum,proto3\"`\n\txxx_hidden_Schema         int32                  `protobuf:\"zigzag32,4,opt,name=schema,proto3\"`\n\txxx_hidden_ZeroThreshold  float64                `protobuf:\"fixed64,5,opt,name=zero_threshold,json=zeroThreshold,proto3\"`\n\txxx_hidden_ZeroCount      isHistogram_ZeroCount  `protobuf_oneof:\"zero_count\"`\n\txxx_hidden_NegativeSpans  *[]*BucketSpan         `protobuf:\"bytes,8,rep,name=negative_spans,json=negativeSpans,proto3\"`\n\txxx_hidden_NegativeDeltas []int64                `protobuf:\"zigzag64,9,rep,packed,name=negative_deltas,json=negativeDeltas,proto3\"`\n\txxx_hidden_NegativeCounts []float64              `protobuf:\"fixed64,10,rep,packed,name=negative_counts,json=negativeCounts,proto3\"`\n\txxx_hidden_PositiveSpans  *[]*BucketSpan         `protobuf:\"bytes,11,rep,name=positive_spans,json=positiveSpans,proto3\"`\n\txxx_hidden_PositiveDeltas []int64                `protobuf:\"zigzag64,12,rep,packed,name=positive_deltas,json=positiveDeltas,proto3\"`\n\txxx_hidden_PositiveCounts []float64              `protobuf:\"fixed64,13,rep,packed,name=positive_counts,json=positiveCounts,proto3\"`\n\txxx_hidden_ResetHint      Histogram_ResetHint    `protobuf:\"varint,14,opt,name=reset_hint,json=resetHint,proto3,enum=prometheus.Histogram_ResetHint\"`\n\txxx_hidden_Timestamp      int64                  `protobuf:\"varint,15,opt,name=timestamp,proto3\"`\n\txxx_hidden_CustomValues   []float64              `protobuf:\"fixed64,16,rep,packed,name=custom_values,json=customValues,proto3\"`\n\tunknownFields             protoimpl.UnknownFields\n\tsizeCache                 protoimpl.SizeCache\n}\n\nfunc (x *Histogram) Reset() {\n\t*x = Histogram{}\n\tmi := &file_types_proto_msgTypes[3]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Histogram) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Histogram) ProtoMessage() {}\n\nfunc (x *Histogram) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[3]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Histogram) GetCountInt() uint64 {\n\tif x != nil {\n\t\tif x, ok := x.xxx_hidden_Count.(*histogram_CountInt); ok {\n\t\t\treturn x.CountInt\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetCountFloat() float64 {\n\tif x != nil {\n\t\tif x, ok := x.xxx_hidden_Count.(*histogram_CountFloat); ok {\n\t\t\treturn x.CountFloat\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetSum() float64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Sum\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetSchema() int32 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Schema\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetZeroThreshold() float64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_ZeroThreshold\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetZeroCountInt() uint64 {\n\tif x != nil {\n\t\tif x, ok := x.xxx_hidden_ZeroCount.(*histogram_ZeroCountInt); ok {\n\t\t\treturn x.ZeroCountInt\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetZeroCountFloat() float64 {\n\tif x != nil {\n\t\tif x, ok := x.xxx_hidden_ZeroCount.(*histogram_ZeroCountFloat); ok {\n\t\t\treturn x.ZeroCountFloat\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetNegativeSpans() []*BucketSpan {\n\tif x != nil {\n\t\tif x.xxx_hidden_NegativeSpans != nil {\n\t\t\treturn *x.xxx_hidden_NegativeSpans\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetNegativeDeltas() []int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_NegativeDeltas\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetNegativeCounts() []float64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_NegativeCounts\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetPositiveSpans() []*BucketSpan {\n\tif x != nil {\n\t\tif x.xxx_hidden_PositiveSpans != nil {\n\t\t\treturn *x.xxx_hidden_PositiveSpans\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetPositiveDeltas() []int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_PositiveDeltas\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetPositiveCounts() []float64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_PositiveCounts\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) GetResetHint() Histogram_ResetHint {\n\tif x != nil {\n\t\treturn x.xxx_hidden_ResetHint\n\t}\n\treturn Histogram_UNKNOWN\n}\n\nfunc (x *Histogram) GetTimestamp() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Timestamp\n\t}\n\treturn 0\n}\n\nfunc (x *Histogram) GetCustomValues() []float64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_CustomValues\n\t}\n\treturn nil\n}\n\nfunc (x *Histogram) SetCountInt(v uint64) {\n\tx.xxx_hidden_Count = &histogram_CountInt{v}\n}\n\nfunc (x *Histogram) SetCountFloat(v float64) {\n\tx.xxx_hidden_Count = &histogram_CountFloat{v}\n}\n\nfunc (x *Histogram) SetSum(v float64) {\n\tx.xxx_hidden_Sum = v\n}\n\nfunc (x *Histogram) SetSchema(v int32) {\n\tx.xxx_hidden_Schema = v\n}\n\nfunc (x *Histogram) SetZeroThreshold(v float64) {\n\tx.xxx_hidden_ZeroThreshold = v\n}\n\nfunc (x *Histogram) SetZeroCountInt(v uint64) {\n\tx.xxx_hidden_ZeroCount = &histogram_ZeroCountInt{v}\n}\n\nfunc (x *Histogram) SetZeroCountFloat(v float64) {\n\tx.xxx_hidden_ZeroCount = &histogram_ZeroCountFloat{v}\n}\n\nfunc (x *Histogram) SetNegativeSpans(v []*BucketSpan) {\n\tx.xxx_hidden_NegativeSpans = &v\n}\n\nfunc (x *Histogram) SetNegativeDeltas(v []int64) {\n\tx.xxx_hidden_NegativeDeltas = v\n}\n\nfunc (x *Histogram) SetNegativeCounts(v []float64) {\n\tx.xxx_hidden_NegativeCounts = v\n}\n\nfunc (x *Histogram) SetPositiveSpans(v []*BucketSpan) {\n\tx.xxx_hidden_PositiveSpans = &v\n}\n\nfunc (x *Histogram) SetPositiveDeltas(v []int64) {\n\tx.xxx_hidden_PositiveDeltas = v\n}\n\nfunc (x *Histogram) SetPositiveCounts(v []float64) {\n\tx.xxx_hidden_PositiveCounts = v\n}\n\nfunc (x *Histogram) SetResetHint(v Histogram_ResetHint) {\n\tx.xxx_hidden_ResetHint = v\n}\n\nfunc (x *Histogram) SetTimestamp(v int64) {\n\tx.xxx_hidden_Timestamp = v\n}\n\nfunc (x *Histogram) SetCustomValues(v []float64) {\n\tx.xxx_hidden_CustomValues = v\n}\n\nfunc (x *Histogram) HasCount() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\treturn x.xxx_hidden_Count != nil\n}\n\nfunc (x *Histogram) HasCountInt() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.xxx_hidden_Count.(*histogram_CountInt)\n\treturn ok\n}\n\nfunc (x *Histogram) HasCountFloat() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.xxx_hidden_Count.(*histogram_CountFloat)\n\treturn ok\n}\n\nfunc (x *Histogram) HasZeroCount() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\treturn x.xxx_hidden_ZeroCount != nil\n}\n\nfunc (x *Histogram) HasZeroCountInt() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.xxx_hidden_ZeroCount.(*histogram_ZeroCountInt)\n\treturn ok\n}\n\nfunc (x *Histogram) HasZeroCountFloat() bool {\n\tif x == nil {\n\t\treturn false\n\t}\n\t_, ok := x.xxx_hidden_ZeroCount.(*histogram_ZeroCountFloat)\n\treturn ok\n}\n\nfunc (x *Histogram) ClearCount() {\n\tx.xxx_hidden_Count = nil\n}\n\nfunc (x *Histogram) ClearCountInt() {\n\tif _, ok := x.xxx_hidden_Count.(*histogram_CountInt); ok {\n\t\tx.xxx_hidden_Count = nil\n\t}\n}\n\nfunc (x *Histogram) ClearCountFloat() {\n\tif _, ok := x.xxx_hidden_Count.(*histogram_CountFloat); ok {\n\t\tx.xxx_hidden_Count = nil\n\t}\n}\n\nfunc (x *Histogram) ClearZeroCount() {\n\tx.xxx_hidden_ZeroCount = nil\n}\n\nfunc (x *Histogram) ClearZeroCountInt() {\n\tif _, ok := x.xxx_hidden_ZeroCount.(*histogram_ZeroCountInt); ok {\n\t\tx.xxx_hidden_ZeroCount = nil\n\t}\n}\n\nfunc (x *Histogram) ClearZeroCountFloat() {\n\tif _, ok := x.xxx_hidden_ZeroCount.(*histogram_ZeroCountFloat); ok {\n\t\tx.xxx_hidden_ZeroCount = nil\n\t}\n}\n\nconst Histogram_Count_not_set_case case_Histogram_Count = 0\nconst Histogram_CountInt_case case_Histogram_Count = 1\nconst Histogram_CountFloat_case case_Histogram_Count = 2\n\nfunc (x *Histogram) WhichCount() case_Histogram_Count {\n\tif x == nil {\n\t\treturn Histogram_Count_not_set_case\n\t}\n\tswitch x.xxx_hidden_Count.(type) {\n\tcase *histogram_CountInt:\n\t\treturn Histogram_CountInt_case\n\tcase *histogram_CountFloat:\n\t\treturn Histogram_CountFloat_case\n\tdefault:\n\t\treturn Histogram_Count_not_set_case\n\t}\n}\n\nconst Histogram_ZeroCount_not_set_case case_Histogram_ZeroCount = 0\nconst Histogram_ZeroCountInt_case case_Histogram_ZeroCount = 6\nconst Histogram_ZeroCountFloat_case case_Histogram_ZeroCount = 7\n\nfunc (x *Histogram) WhichZeroCount() case_Histogram_ZeroCount {\n\tif x == nil {\n\t\treturn Histogram_ZeroCount_not_set_case\n\t}\n\tswitch x.xxx_hidden_ZeroCount.(type) {\n\tcase *histogram_ZeroCountInt:\n\t\treturn Histogram_ZeroCountInt_case\n\tcase *histogram_ZeroCountFloat:\n\t\treturn Histogram_ZeroCountFloat_case\n\tdefault:\n\t\treturn Histogram_ZeroCount_not_set_case\n\t}\n}\n\ntype Histogram_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Fields of oneof xxx_hidden_Count:\n\tCountInt   *uint64\n\tCountFloat *float64\n\t// -- end of xxx_hidden_Count\n\tSum float64\n\t// The schema defines the bucket schema. Currently, valid numbers\n\t// are -4 <= n <= 8. They are all for base-2 bucket schemas, where 1\n\t// is a bucket boundary in each case, and then each power of two is\n\t// divided into 2^n logarithmic buckets. Or in other words, each\n\t// bucket boundary is the previous boundary times 2^(2^-n). In the\n\t// future, more bucket schemas may be added using numbers < -4 or >\n\t// 8.\n\tSchema        int32\n\tZeroThreshold float64\n\t// Fields of oneof xxx_hidden_ZeroCount:\n\tZeroCountInt   *uint64\n\tZeroCountFloat *float64\n\t// -- end of xxx_hidden_ZeroCount\n\t// Negative Buckets.\n\tNegativeSpans []*BucketSpan\n\t// Use either \"negative_deltas\" or \"negative_counts\", the former for\n\t// regular histograms with integer counts, the latter for float\n\t// histograms.\n\tNegativeDeltas []int64\n\tNegativeCounts []float64\n\t// Positive Buckets.\n\tPositiveSpans []*BucketSpan\n\t// Use either \"positive_deltas\" or \"positive_counts\", the former for\n\t// regular histograms with integer counts, the latter for float\n\t// histograms.\n\tPositiveDeltas []int64\n\tPositiveCounts []float64\n\tResetHint      Histogram_ResetHint\n\t// timestamp is in ms format, see model/timestamp/timestamp.go for\n\t// conversion from time.Time to Prometheus timestamp.\n\tTimestamp int64\n\t// custom_values are not part of the specification, DO NOT use in remote write clients.\n\t// Used only for converting from OpenTelemetry to Prometheus internally.\n\tCustomValues []float64\n}\n\nfunc (b0 Histogram_builder) Build() *Histogram {\n\tm0 := &Histogram{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tif b.CountInt != nil {\n\t\tx.xxx_hidden_Count = &histogram_CountInt{*b.CountInt}\n\t}\n\tif b.CountFloat != nil {\n\t\tx.xxx_hidden_Count = &histogram_CountFloat{*b.CountFloat}\n\t}\n\tx.xxx_hidden_Sum = b.Sum\n\tx.xxx_hidden_Schema = b.Schema\n\tx.xxx_hidden_ZeroThreshold = b.ZeroThreshold\n\tif b.ZeroCountInt != nil {\n\t\tx.xxx_hidden_ZeroCount = &histogram_ZeroCountInt{*b.ZeroCountInt}\n\t}\n\tif b.ZeroCountFloat != nil {\n\t\tx.xxx_hidden_ZeroCount = &histogram_ZeroCountFloat{*b.ZeroCountFloat}\n\t}\n\tx.xxx_hidden_NegativeSpans = &b.NegativeSpans\n\tx.xxx_hidden_NegativeDeltas = b.NegativeDeltas\n\tx.xxx_hidden_NegativeCounts = b.NegativeCounts\n\tx.xxx_hidden_PositiveSpans = &b.PositiveSpans\n\tx.xxx_hidden_PositiveDeltas = b.PositiveDeltas\n\tx.xxx_hidden_PositiveCounts = b.PositiveCounts\n\tx.xxx_hidden_ResetHint = b.ResetHint\n\tx.xxx_hidden_Timestamp = b.Timestamp\n\tx.xxx_hidden_CustomValues = b.CustomValues\n\treturn m0\n}\n\ntype case_Histogram_Count protoreflect.FieldNumber\n\nfunc (x case_Histogram_Count) String() string {\n\tmd := file_types_proto_msgTypes[3].Descriptor()\n\tif x == 0 {\n\t\treturn \"not set\"\n\t}\n\treturn protoimpl.X.MessageFieldStringOf(md, protoreflect.FieldNumber(x))\n}\n\ntype case_Histogram_ZeroCount protoreflect.FieldNumber\n\nfunc (x case_Histogram_ZeroCount) String() string {\n\tmd := file_types_proto_msgTypes[3].Descriptor()\n\tif x == 0 {\n\t\treturn \"not set\"\n\t}\n\treturn protoimpl.X.MessageFieldStringOf(md, protoreflect.FieldNumber(x))\n}\n\ntype isHistogram_Count interface {\n\tisHistogram_Count()\n}\n\ntype histogram_CountInt struct {\n\tCountInt uint64 `protobuf:\"varint,1,opt,name=count_int,json=countInt,proto3,oneof\"`\n}\n\ntype histogram_CountFloat struct {\n\tCountFloat float64 `protobuf:\"fixed64,2,opt,name=count_float,json=countFloat,proto3,oneof\"`\n}\n\nfunc (*histogram_CountInt) isHistogram_Count() {}\n\nfunc (*histogram_CountFloat) isHistogram_Count() {}\n\ntype isHistogram_ZeroCount interface {\n\tisHistogram_ZeroCount()\n}\n\ntype histogram_ZeroCountInt struct {\n\tZeroCountInt uint64 `protobuf:\"varint,6,opt,name=zero_count_int,json=zeroCountInt,proto3,oneof\"`\n}\n\ntype histogram_ZeroCountFloat struct {\n\tZeroCountFloat float64 `protobuf:\"fixed64,7,opt,name=zero_count_float,json=zeroCountFloat,proto3,oneof\"`\n}\n\nfunc (*histogram_ZeroCountInt) isHistogram_ZeroCount() {}\n\nfunc (*histogram_ZeroCountFloat) isHistogram_ZeroCount() {}\n\n// A BucketSpan defines a number of consecutive buckets with their\n// offset. Logically, it would be more straightforward to include the\n// bucket counts in the Span. However, the protobuf representation is\n// more compact in the way the data is structured here (with all the\n// buckets in a single array separate from the Spans).\ntype BucketSpan struct {\n\tstate             protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Offset int32                  `protobuf:\"zigzag32,1,opt,name=offset,proto3\"`\n\txxx_hidden_Length uint32                 `protobuf:\"varint,2,opt,name=length,proto3\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *BucketSpan) Reset() {\n\t*x = BucketSpan{}\n\tmi := &file_types_proto_msgTypes[4]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *BucketSpan) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*BucketSpan) ProtoMessage() {}\n\nfunc (x *BucketSpan) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[4]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *BucketSpan) GetOffset() int32 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Offset\n\t}\n\treturn 0\n}\n\nfunc (x *BucketSpan) GetLength() uint32 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Length\n\t}\n\treturn 0\n}\n\nfunc (x *BucketSpan) SetOffset(v int32) {\n\tx.xxx_hidden_Offset = v\n}\n\nfunc (x *BucketSpan) SetLength(v uint32) {\n\tx.xxx_hidden_Length = v\n}\n\ntype BucketSpan_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tOffset int32\n\tLength uint32\n}\n\nfunc (b0 BucketSpan_builder) Build() *BucketSpan {\n\tm0 := &BucketSpan{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Offset = b.Offset\n\tx.xxx_hidden_Length = b.Length\n\treturn m0\n}\n\n// TimeSeries represents samples and labels for a single time series.\ntype TimeSeries struct {\n\tstate                 protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Labels     *[]*Label              `protobuf:\"bytes,1,rep,name=labels,proto3\"`\n\txxx_hidden_Samples    *[]*Sample             `protobuf:\"bytes,2,rep,name=samples,proto3\"`\n\txxx_hidden_Exemplars  *[]*Exemplar           `protobuf:\"bytes,3,rep,name=exemplars,proto3\"`\n\txxx_hidden_Histograms *[]*Histogram          `protobuf:\"bytes,4,rep,name=histograms,proto3\"`\n\tunknownFields         protoimpl.UnknownFields\n\tsizeCache             protoimpl.SizeCache\n}\n\nfunc (x *TimeSeries) Reset() {\n\t*x = TimeSeries{}\n\tmi := &file_types_proto_msgTypes[5]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *TimeSeries) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*TimeSeries) ProtoMessage() {}\n\nfunc (x *TimeSeries) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[5]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *TimeSeries) GetLabels() []*Label {\n\tif x != nil {\n\t\tif x.xxx_hidden_Labels != nil {\n\t\t\treturn *x.xxx_hidden_Labels\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetSamples() []*Sample {\n\tif x != nil {\n\t\tif x.xxx_hidden_Samples != nil {\n\t\t\treturn *x.xxx_hidden_Samples\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetExemplars() []*Exemplar {\n\tif x != nil {\n\t\tif x.xxx_hidden_Exemplars != nil {\n\t\t\treturn *x.xxx_hidden_Exemplars\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) GetHistograms() []*Histogram {\n\tif x != nil {\n\t\tif x.xxx_hidden_Histograms != nil {\n\t\t\treturn *x.xxx_hidden_Histograms\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *TimeSeries) SetLabels(v []*Label) {\n\tx.xxx_hidden_Labels = &v\n}\n\nfunc (x *TimeSeries) SetSamples(v []*Sample) {\n\tx.xxx_hidden_Samples = &v\n}\n\nfunc (x *TimeSeries) SetExemplars(v []*Exemplar) {\n\tx.xxx_hidden_Exemplars = &v\n}\n\nfunc (x *TimeSeries) SetHistograms(v []*Histogram) {\n\tx.xxx_hidden_Histograms = &v\n}\n\ntype TimeSeries_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// For a timeseries to be valid, and for the samples and exemplars\n\t// to be ingested by the remote system properly, the labels field is required.\n\tLabels     []*Label\n\tSamples    []*Sample\n\tExemplars  []*Exemplar\n\tHistograms []*Histogram\n}\n\nfunc (b0 TimeSeries_builder) Build() *TimeSeries {\n\tm0 := &TimeSeries{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Labels = &b.Labels\n\tx.xxx_hidden_Samples = &b.Samples\n\tx.xxx_hidden_Exemplars = &b.Exemplars\n\tx.xxx_hidden_Histograms = &b.Histograms\n\treturn m0\n}\n\ntype Label struct {\n\tstate            protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Name  string                 `protobuf:\"bytes,1,opt,name=name,proto3\"`\n\txxx_hidden_Value string                 `protobuf:\"bytes,2,opt,name=value,proto3\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *Label) Reset() {\n\t*x = Label{}\n\tmi := &file_types_proto_msgTypes[6]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Label) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Label) ProtoMessage() {}\n\nfunc (x *Label) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[6]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Label) GetName() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *Label) GetValue() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Value\n\t}\n\treturn \"\"\n}\n\nfunc (x *Label) SetName(v string) {\n\tx.xxx_hidden_Name = v\n}\n\nfunc (x *Label) SetValue(v string) {\n\tx.xxx_hidden_Value = v\n}\n\ntype Label_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tName  string\n\tValue string\n}\n\nfunc (b0 Label_builder) Build() *Label {\n\tm0 := &Label{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Name = b.Name\n\tx.xxx_hidden_Value = b.Value\n\treturn m0\n}\n\ntype Labels struct {\n\tstate             protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Labels *[]*Label              `protobuf:\"bytes,1,rep,name=labels,proto3\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *Labels) Reset() {\n\t*x = Labels{}\n\tmi := &file_types_proto_msgTypes[7]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Labels) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Labels) ProtoMessage() {}\n\nfunc (x *Labels) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[7]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Labels) GetLabels() []*Label {\n\tif x != nil {\n\t\tif x.xxx_hidden_Labels != nil {\n\t\t\treturn *x.xxx_hidden_Labels\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *Labels) SetLabels(v []*Label) {\n\tx.xxx_hidden_Labels = &v\n}\n\ntype Labels_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tLabels []*Label\n}\n\nfunc (b0 Labels_builder) Build() *Labels {\n\tm0 := &Labels{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Labels = &b.Labels\n\treturn m0\n}\n\n// Matcher specifies a rule, which can match or set of labels or not.\ntype LabelMatcher struct {\n\tstate            protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Type  LabelMatcher_Type      `protobuf:\"varint,1,opt,name=type,proto3,enum=prometheus.LabelMatcher_Type\"`\n\txxx_hidden_Name  string                 `protobuf:\"bytes,2,opt,name=name,proto3\"`\n\txxx_hidden_Value string                 `protobuf:\"bytes,3,opt,name=value,proto3\"`\n\tunknownFields    protoimpl.UnknownFields\n\tsizeCache        protoimpl.SizeCache\n}\n\nfunc (x *LabelMatcher) Reset() {\n\t*x = LabelMatcher{}\n\tmi := &file_types_proto_msgTypes[8]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *LabelMatcher) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*LabelMatcher) ProtoMessage() {}\n\nfunc (x *LabelMatcher) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[8]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *LabelMatcher) GetType() LabelMatcher_Type {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Type\n\t}\n\treturn LabelMatcher_EQ\n}\n\nfunc (x *LabelMatcher) GetName() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Name\n\t}\n\treturn \"\"\n}\n\nfunc (x *LabelMatcher) GetValue() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Value\n\t}\n\treturn \"\"\n}\n\nfunc (x *LabelMatcher) SetType(v LabelMatcher_Type) {\n\tx.xxx_hidden_Type = v\n}\n\nfunc (x *LabelMatcher) SetName(v string) {\n\tx.xxx_hidden_Name = v\n}\n\nfunc (x *LabelMatcher) SetValue(v string) {\n\tx.xxx_hidden_Value = v\n}\n\ntype LabelMatcher_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tType  LabelMatcher_Type\n\tName  string\n\tValue string\n}\n\nfunc (b0 LabelMatcher_builder) Build() *LabelMatcher {\n\tm0 := &LabelMatcher{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Type = b.Type\n\tx.xxx_hidden_Name = b.Name\n\tx.xxx_hidden_Value = b.Value\n\treturn m0\n}\n\ntype ReadHints struct {\n\tstate               protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_StepMs   int64                  `protobuf:\"varint,1,opt,name=step_ms,json=stepMs,proto3\"`\n\txxx_hidden_Func     string                 `protobuf:\"bytes,2,opt,name=func,proto3\"`\n\txxx_hidden_StartMs  int64                  `protobuf:\"varint,3,opt,name=start_ms,json=startMs,proto3\"`\n\txxx_hidden_EndMs    int64                  `protobuf:\"varint,4,opt,name=end_ms,json=endMs,proto3\"`\n\txxx_hidden_Grouping []string               `protobuf:\"bytes,5,rep,name=grouping,proto3\"`\n\txxx_hidden_By       bool                   `protobuf:\"varint,6,opt,name=by,proto3\"`\n\txxx_hidden_RangeMs  int64                  `protobuf:\"varint,7,opt,name=range_ms,json=rangeMs,proto3\"`\n\tunknownFields       protoimpl.UnknownFields\n\tsizeCache           protoimpl.SizeCache\n}\n\nfunc (x *ReadHints) Reset() {\n\t*x = ReadHints{}\n\tmi := &file_types_proto_msgTypes[9]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ReadHints) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ReadHints) ProtoMessage() {}\n\nfunc (x *ReadHints) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[9]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ReadHints) GetStepMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_StepMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) GetFunc() string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Func\n\t}\n\treturn \"\"\n}\n\nfunc (x *ReadHints) GetStartMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_StartMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) GetEndMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_EndMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) GetGrouping() []string {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Grouping\n\t}\n\treturn nil\n}\n\nfunc (x *ReadHints) GetBy() bool {\n\tif x != nil {\n\t\treturn x.xxx_hidden_By\n\t}\n\treturn false\n}\n\nfunc (x *ReadHints) GetRangeMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_RangeMs\n\t}\n\treturn 0\n}\n\nfunc (x *ReadHints) SetStepMs(v int64) {\n\tx.xxx_hidden_StepMs = v\n}\n\nfunc (x *ReadHints) SetFunc(v string) {\n\tx.xxx_hidden_Func = v\n}\n\nfunc (x *ReadHints) SetStartMs(v int64) {\n\tx.xxx_hidden_StartMs = v\n}\n\nfunc (x *ReadHints) SetEndMs(v int64) {\n\tx.xxx_hidden_EndMs = v\n}\n\nfunc (x *ReadHints) SetGrouping(v []string) {\n\tx.xxx_hidden_Grouping = v\n}\n\nfunc (x *ReadHints) SetBy(v bool) {\n\tx.xxx_hidden_By = v\n}\n\nfunc (x *ReadHints) SetRangeMs(v int64) {\n\tx.xxx_hidden_RangeMs = v\n}\n\ntype ReadHints_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tStepMs   int64\n\tFunc     string\n\tStartMs  int64\n\tEndMs    int64\n\tGrouping []string\n\tBy       bool\n\tRangeMs  int64\n}\n\nfunc (b0 ReadHints_builder) Build() *ReadHints {\n\tm0 := &ReadHints{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_StepMs = b.StepMs\n\tx.xxx_hidden_Func = b.Func\n\tx.xxx_hidden_StartMs = b.StartMs\n\tx.xxx_hidden_EndMs = b.EndMs\n\tx.xxx_hidden_Grouping = b.Grouping\n\tx.xxx_hidden_By = b.By\n\tx.xxx_hidden_RangeMs = b.RangeMs\n\treturn m0\n}\n\n// Chunk represents a TSDB chunk.\n// Time range [min, max] is inclusive.\ntype Chunk struct {\n\tstate                protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_MinTimeMs int64                  `protobuf:\"varint,1,opt,name=min_time_ms,json=minTimeMs,proto3\"`\n\txxx_hidden_MaxTimeMs int64                  `protobuf:\"varint,2,opt,name=max_time_ms,json=maxTimeMs,proto3\"`\n\txxx_hidden_Type      Chunk_Encoding         `protobuf:\"varint,3,opt,name=type,proto3,enum=prometheus.Chunk_Encoding\"`\n\txxx_hidden_Data      []byte                 `protobuf:\"bytes,4,opt,name=data,proto3\"`\n\tunknownFields        protoimpl.UnknownFields\n\tsizeCache            protoimpl.SizeCache\n}\n\nfunc (x *Chunk) Reset() {\n\t*x = Chunk{}\n\tmi := &file_types_proto_msgTypes[10]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *Chunk) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*Chunk) ProtoMessage() {}\n\nfunc (x *Chunk) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[10]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *Chunk) GetMinTimeMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_MinTimeMs\n\t}\n\treturn 0\n}\n\nfunc (x *Chunk) GetMaxTimeMs() int64 {\n\tif x != nil {\n\t\treturn x.xxx_hidden_MaxTimeMs\n\t}\n\treturn 0\n}\n\nfunc (x *Chunk) GetType() Chunk_Encoding {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Type\n\t}\n\treturn Chunk_UNKNOWN\n}\n\nfunc (x *Chunk) GetData() []byte {\n\tif x != nil {\n\t\treturn x.xxx_hidden_Data\n\t}\n\treturn nil\n}\n\nfunc (x *Chunk) SetMinTimeMs(v int64) {\n\tx.xxx_hidden_MinTimeMs = v\n}\n\nfunc (x *Chunk) SetMaxTimeMs(v int64) {\n\tx.xxx_hidden_MaxTimeMs = v\n}\n\nfunc (x *Chunk) SetType(v Chunk_Encoding) {\n\tx.xxx_hidden_Type = v\n}\n\nfunc (x *Chunk) SetData(v []byte) {\n\tif v == nil {\n\t\tv = []byte{}\n\t}\n\tx.xxx_hidden_Data = v\n}\n\ntype Chunk_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\tMinTimeMs int64\n\tMaxTimeMs int64\n\tType      Chunk_Encoding\n\tData      []byte\n}\n\nfunc (b0 Chunk_builder) Build() *Chunk {\n\tm0 := &Chunk{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_MinTimeMs = b.MinTimeMs\n\tx.xxx_hidden_MaxTimeMs = b.MaxTimeMs\n\tx.xxx_hidden_Type = b.Type\n\tx.xxx_hidden_Data = b.Data\n\treturn m0\n}\n\n// ChunkedSeries represents single, encoded time series.\ntype ChunkedSeries struct {\n\tstate             protoimpl.MessageState `protogen:\"opaque.v1\"`\n\txxx_hidden_Labels *[]*Label              `protobuf:\"bytes,1,rep,name=labels,proto3\"`\n\txxx_hidden_Chunks *[]*Chunk              `protobuf:\"bytes,2,rep,name=chunks,proto3\"`\n\tunknownFields     protoimpl.UnknownFields\n\tsizeCache         protoimpl.SizeCache\n}\n\nfunc (x *ChunkedSeries) Reset() {\n\t*x = ChunkedSeries{}\n\tmi := &file_types_proto_msgTypes[11]\n\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\tms.StoreMessageInfo(mi)\n}\n\nfunc (x *ChunkedSeries) String() string {\n\treturn protoimpl.X.MessageStringOf(x)\n}\n\nfunc (*ChunkedSeries) ProtoMessage() {}\n\nfunc (x *ChunkedSeries) ProtoReflect() protoreflect.Message {\n\tmi := &file_types_proto_msgTypes[11]\n\tif x != nil {\n\t\tms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))\n\t\tif ms.LoadMessageInfo() == nil {\n\t\t\tms.StoreMessageInfo(mi)\n\t\t}\n\t\treturn ms\n\t}\n\treturn mi.MessageOf(x)\n}\n\nfunc (x *ChunkedSeries) GetLabels() []*Label {\n\tif x != nil {\n\t\tif x.xxx_hidden_Labels != nil {\n\t\t\treturn *x.xxx_hidden_Labels\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *ChunkedSeries) GetChunks() []*Chunk {\n\tif x != nil {\n\t\tif x.xxx_hidden_Chunks != nil {\n\t\t\treturn *x.xxx_hidden_Chunks\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (x *ChunkedSeries) SetLabels(v []*Label) {\n\tx.xxx_hidden_Labels = &v\n}\n\nfunc (x *ChunkedSeries) SetChunks(v []*Chunk) {\n\tx.xxx_hidden_Chunks = &v\n}\n\ntype ChunkedSeries_builder struct {\n\t_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.\n\n\t// Labels should be sorted.\n\tLabels []*Label\n\t// Chunks will be in start time order and may overlap.\n\tChunks []*Chunk\n}\n\nfunc (b0 ChunkedSeries_builder) Build() *ChunkedSeries {\n\tm0 := &ChunkedSeries{}\n\tb, x := &b0, m0\n\t_, _ = b, x\n\tx.xxx_hidden_Labels = &b.Labels\n\tx.xxx_hidden_Chunks = &b.Chunks\n\treturn m0\n}\n\nvar File_types_proto protoreflect.FileDescriptor\n\nconst file_types_proto_rawDesc = \"\" +\n\t\"\\n\" +\n\t\"\\vtypes.proto\\x12\\n\" +\n\t\"prometheus\\x1a\\x14gogoproto/gogo.proto\\\"\\x9c\\x02\\n\" +\n\t\"\\x0eMetricMetadata\\x129\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\x0e2%.prometheus.MetricMetadata.MetricTypeR\\x04type\\x12,\\n\" +\n\t\"\\x12metric_family_name\\x18\\x02 \\x01(\\tR\\x10metricFamilyName\\x12\\x12\\n\" +\n\t\"\\x04help\\x18\\x04 \\x01(\\tR\\x04help\\x12\\x12\\n\" +\n\t\"\\x04unit\\x18\\x05 \\x01(\\tR\\x04unit\\\"y\\n\" +\n\t\"\\n\" +\n\t\"MetricType\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\v\\n\" +\n\t\"\\aCOUNTER\\x10\\x01\\x12\\t\\n\" +\n\t\"\\x05GAUGE\\x10\\x02\\x12\\r\\n\" +\n\t\"\\tHISTOGRAM\\x10\\x03\\x12\\x12\\n\" +\n\t\"\\x0eGAUGEHISTOGRAM\\x10\\x04\\x12\\v\\n\" +\n\t\"\\aSUMMARY\\x10\\x05\\x12\\b\\n\" +\n\t\"\\x04INFO\\x10\\x06\\x12\\f\\n\" +\n\t\"\\bSTATESET\\x10\\a\\\"<\\n\" +\n\t\"\\x06Sample\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x01 \\x01(\\x01R\\x05value\\x12\\x1c\\n\" +\n\t\"\\ttimestamp\\x18\\x02 \\x01(\\x03R\\ttimestamp\\\"o\\n\" +\n\t\"\\bExemplar\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\x01R\\x05value\\x12\\x1c\\n\" +\n\t\"\\ttimestamp\\x18\\x03 \\x01(\\x03R\\ttimestamp\\\"\\xf0\\x05\\n\" +\n\t\"\\tHistogram\\x12\\x1d\\n\" +\n\t\"\\tcount_int\\x18\\x01 \\x01(\\x04H\\x00R\\bcountInt\\x12!\\n\" +\n\t\"\\vcount_float\\x18\\x02 \\x01(\\x01H\\x00R\\n\" +\n\t\"countFloat\\x12\\x10\\n\" +\n\t\"\\x03sum\\x18\\x03 \\x01(\\x01R\\x03sum\\x12\\x16\\n\" +\n\t\"\\x06schema\\x18\\x04 \\x01(\\x11R\\x06schema\\x12%\\n\" +\n\t\"\\x0ezero_threshold\\x18\\x05 \\x01(\\x01R\\rzeroThreshold\\x12&\\n\" +\n\t\"\\x0ezero_count_int\\x18\\x06 \\x01(\\x04H\\x01R\\fzeroCountInt\\x12*\\n\" +\n\t\"\\x10zero_count_float\\x18\\a \\x01(\\x01H\\x01R\\x0ezeroCountFloat\\x12C\\n\" +\n\t\"\\x0enegative_spans\\x18\\b \\x03(\\v2\\x16.prometheus.BucketSpanB\\x04\\xc8\\xde\\x1f\\x00R\\rnegativeSpans\\x12'\\n\" +\n\t\"\\x0fnegative_deltas\\x18\\t \\x03(\\x12R\\x0enegativeDeltas\\x12'\\n\" +\n\t\"\\x0fnegative_counts\\x18\\n\" +\n\t\" \\x03(\\x01R\\x0enegativeCounts\\x12C\\n\" +\n\t\"\\x0epositive_spans\\x18\\v \\x03(\\v2\\x16.prometheus.BucketSpanB\\x04\\xc8\\xde\\x1f\\x00R\\rpositiveSpans\\x12'\\n\" +\n\t\"\\x0fpositive_deltas\\x18\\f \\x03(\\x12R\\x0epositiveDeltas\\x12'\\n\" +\n\t\"\\x0fpositive_counts\\x18\\r \\x03(\\x01R\\x0epositiveCounts\\x12>\\n\" +\n\t\"\\n\" +\n\t\"reset_hint\\x18\\x0e \\x01(\\x0e2\\x1f.prometheus.Histogram.ResetHintR\\tresetHint\\x12\\x1c\\n\" +\n\t\"\\ttimestamp\\x18\\x0f \\x01(\\x03R\\ttimestamp\\x12#\\n\" +\n\t\"\\rcustom_values\\x18\\x10 \\x03(\\x01R\\fcustomValues\\\"4\\n\" +\n\t\"\\tResetHint\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03YES\\x10\\x01\\x12\\x06\\n\" +\n\t\"\\x02NO\\x10\\x02\\x12\\t\\n\" +\n\t\"\\x05GAUGE\\x10\\x03B\\a\\n\" +\n\t\"\\x05countB\\f\\n\" +\n\t\"\\n\" +\n\t\"zero_count\\\"<\\n\" +\n\t\"\\n\" +\n\t\"BucketSpan\\x12\\x16\\n\" +\n\t\"\\x06offset\\x18\\x01 \\x01(\\x11R\\x06offset\\x12\\x16\\n\" +\n\t\"\\x06length\\x18\\x02 \\x01(\\rR\\x06length\\\"\\xe8\\x01\\n\" +\n\t\"\\n\" +\n\t\"TimeSeries\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\x122\\n\" +\n\t\"\\asamples\\x18\\x02 \\x03(\\v2\\x12.prometheus.SampleB\\x04\\xc8\\xde\\x1f\\x00R\\asamples\\x128\\n\" +\n\t\"\\texemplars\\x18\\x03 \\x03(\\v2\\x14.prometheus.ExemplarB\\x04\\xc8\\xde\\x1f\\x00R\\texemplars\\x12;\\n\" +\n\t\"\\n\" +\n\t\"histograms\\x18\\x04 \\x03(\\v2\\x15.prometheus.HistogramB\\x04\\xc8\\xde\\x1f\\x00R\\n\" +\n\t\"histograms\\\"1\\n\" +\n\t\"\\x05Label\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x01 \\x01(\\tR\\x04name\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x02 \\x01(\\tR\\x05value\\\"9\\n\" +\n\t\"\\x06Labels\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\\"\\x95\\x01\\n\" +\n\t\"\\fLabelMatcher\\x121\\n\" +\n\t\"\\x04type\\x18\\x01 \\x01(\\x0e2\\x1d.prometheus.LabelMatcher.TypeR\\x04type\\x12\\x12\\n\" +\n\t\"\\x04name\\x18\\x02 \\x01(\\tR\\x04name\\x12\\x14\\n\" +\n\t\"\\x05value\\x18\\x03 \\x01(\\tR\\x05value\\\"(\\n\" +\n\t\"\\x04Type\\x12\\x06\\n\" +\n\t\"\\x02EQ\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03NEQ\\x10\\x01\\x12\\x06\\n\" +\n\t\"\\x02RE\\x10\\x02\\x12\\a\\n\" +\n\t\"\\x03NRE\\x10\\x03\\\"\\xb1\\x01\\n\" +\n\t\"\\tReadHints\\x12\\x17\\n\" +\n\t\"\\astep_ms\\x18\\x01 \\x01(\\x03R\\x06stepMs\\x12\\x12\\n\" +\n\t\"\\x04func\\x18\\x02 \\x01(\\tR\\x04func\\x12\\x19\\n\" +\n\t\"\\bstart_ms\\x18\\x03 \\x01(\\x03R\\astartMs\\x12\\x15\\n\" +\n\t\"\\x06end_ms\\x18\\x04 \\x01(\\x03R\\x05endMs\\x12\\x1a\\n\" +\n\t\"\\bgrouping\\x18\\x05 \\x03(\\tR\\bgrouping\\x12\\x0e\\n\" +\n\t\"\\x02by\\x18\\x06 \\x01(\\bR\\x02by\\x12\\x19\\n\" +\n\t\"\\brange_ms\\x18\\a \\x01(\\x03R\\arangeMs\\\"\\xd1\\x01\\n\" +\n\t\"\\x05Chunk\\x12\\x1e\\n\" +\n\t\"\\vmin_time_ms\\x18\\x01 \\x01(\\x03R\\tminTimeMs\\x12\\x1e\\n\" +\n\t\"\\vmax_time_ms\\x18\\x02 \\x01(\\x03R\\tmaxTimeMs\\x12.\\n\" +\n\t\"\\x04type\\x18\\x03 \\x01(\\x0e2\\x1a.prometheus.Chunk.EncodingR\\x04type\\x12\\x12\\n\" +\n\t\"\\x04data\\x18\\x04 \\x01(\\fR\\x04data\\\"D\\n\" +\n\t\"\\bEncoding\\x12\\v\\n\" +\n\t\"\\aUNKNOWN\\x10\\x00\\x12\\a\\n\" +\n\t\"\\x03XOR\\x10\\x01\\x12\\r\\n\" +\n\t\"\\tHISTOGRAM\\x10\\x02\\x12\\x13\\n\" +\n\t\"\\x0fFLOAT_HISTOGRAM\\x10\\x03\\\"q\\n\" +\n\t\"\\rChunkedSeries\\x12/\\n\" +\n\t\"\\x06labels\\x18\\x01 \\x03(\\v2\\x11.prometheus.LabelB\\x04\\xc8\\xde\\x1f\\x00R\\x06labels\\x12/\\n\" +\n\t\"\\x06chunks\\x18\\x02 \\x03(\\v2\\x11.prometheus.ChunkB\\x04\\xc8\\xde\\x1f\\x00R\\x06chunksB;Z9buf.build/gen/go/prometheus/prometheus/protocolbuffers/gob\\x06proto3\"\n\nvar file_types_proto_enumTypes = make([]protoimpl.EnumInfo, 4)\nvar file_types_proto_msgTypes = make([]protoimpl.MessageInfo, 12)\nvar file_types_proto_goTypes = []any{\n\t(MetricMetadata_MetricType)(0), // 0: prometheus.MetricMetadata.MetricType\n\t(Histogram_ResetHint)(0),       // 1: prometheus.Histogram.ResetHint\n\t(LabelMatcher_Type)(0),         // 2: prometheus.LabelMatcher.Type\n\t(Chunk_Encoding)(0),            // 3: prometheus.Chunk.Encoding\n\t(*MetricMetadata)(nil),         // 4: prometheus.MetricMetadata\n\t(*Sample)(nil),                 // 5: prometheus.Sample\n\t(*Exemplar)(nil),               // 6: prometheus.Exemplar\n\t(*Histogram)(nil),              // 7: prometheus.Histogram\n\t(*BucketSpan)(nil),             // 8: prometheus.BucketSpan\n\t(*TimeSeries)(nil),             // 9: prometheus.TimeSeries\n\t(*Label)(nil),                  // 10: prometheus.Label\n\t(*Labels)(nil),                 // 11: prometheus.Labels\n\t(*LabelMatcher)(nil),           // 12: prometheus.LabelMatcher\n\t(*ReadHints)(nil),              // 13: prometheus.ReadHints\n\t(*Chunk)(nil),                  // 14: prometheus.Chunk\n\t(*ChunkedSeries)(nil),          // 15: prometheus.ChunkedSeries\n}\nvar file_types_proto_depIdxs = []int32{\n\t0,  // 0: prometheus.MetricMetadata.type:type_name -> prometheus.MetricMetadata.MetricType\n\t10, // 1: prometheus.Exemplar.labels:type_name -> prometheus.Label\n\t8,  // 2: prometheus.Histogram.negative_spans:type_name -> prometheus.BucketSpan\n\t8,  // 3: prometheus.Histogram.positive_spans:type_name -> prometheus.BucketSpan\n\t1,  // 4: prometheus.Histogram.reset_hint:type_name -> prometheus.Histogram.ResetHint\n\t10, // 5: prometheus.TimeSeries.labels:type_name -> prometheus.Label\n\t5,  // 6: prometheus.TimeSeries.samples:type_name -> prometheus.Sample\n\t6,  // 7: prometheus.TimeSeries.exemplars:type_name -> prometheus.Exemplar\n\t7,  // 8: prometheus.TimeSeries.histograms:type_name -> prometheus.Histogram\n\t10, // 9: prometheus.Labels.labels:type_name -> prometheus.Label\n\t2,  // 10: prometheus.LabelMatcher.type:type_name -> prometheus.LabelMatcher.Type\n\t3,  // 11: prometheus.Chunk.type:type_name -> prometheus.Chunk.Encoding\n\t10, // 12: prometheus.ChunkedSeries.labels:type_name -> prometheus.Label\n\t14, // 13: prometheus.ChunkedSeries.chunks:type_name -> prometheus.Chunk\n\t14, // [14:14] is the sub-list for method output_type\n\t14, // [14:14] is the sub-list for method input_type\n\t14, // [14:14] is the sub-list for extension type_name\n\t14, // [14:14] is the sub-list for extension extendee\n\t0,  // [0:14] is the sub-list for field type_name\n}\n\nfunc init() { file_types_proto_init() }\nfunc file_types_proto_init() {\n\tif File_types_proto != nil {\n\t\treturn\n\t}\n\tfile_types_proto_msgTypes[3].OneofWrappers = []any{\n\t\t(*histogram_CountInt)(nil),\n\t\t(*histogram_CountFloat)(nil),\n\t\t(*histogram_ZeroCountInt)(nil),\n\t\t(*histogram_ZeroCountFloat)(nil),\n\t}\n\ttype x struct{}\n\tout := protoimpl.TypeBuilder{\n\t\tFile: protoimpl.DescBuilder{\n\t\t\tGoPackagePath: reflect.TypeOf(x{}).PkgPath(),\n\t\t\tRawDescriptor: unsafe.Slice(unsafe.StringData(file_types_proto_rawDesc), len(file_types_proto_rawDesc)),\n\t\t\tNumEnums:      4,\n\t\t\tNumMessages:   12,\n\t\t\tNumExtensions: 0,\n\t\t\tNumServices:   0,\n\t\t},\n\t\tGoTypes:           file_types_proto_goTypes,\n\t\tDependencyIndexes: file_types_proto_depIdxs,\n\t\tEnumInfos:         file_types_proto_enumTypes,\n\t\tMessageInfos:      file_types_proto_msgTypes,\n\t}.Build()\n\tFile_types_proto = out.File\n\tfile_types_proto_goTypes = nil\n\tfile_types_proto_depIdxs = nil\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Microsoft\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/SECURITY.md",
    "content": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).\n\nIf you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.\n\n## Reporting Security Issues\n\n**Please do not report security vulnerabilities through public GitHub issues.**\n\nInstead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).\n\nIf you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).\n\nYou should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). \n\nPlease include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:\n\n  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)\n  * Full paths of source file(s) related to the manifestation of the issue\n  * The location of the affected source code (tag/branch/commit or direct URL)\n  * Any special configuration required to reproduce the issue\n  * Step-by-step instructions to reproduce the issue\n  * Proof-of-concept or exploit code (if possible)\n  * Impact of the issue, including how an attacker might exploit the issue\n\nThis information will help us triage your report more quickly.\n\nIf you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.\n\n## Preferred Languages\n\nWe prefer all communications to be in English.\n\n## Policy\n\nMicrosoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).\n\n<!-- END MICROSOFT SECURITY.MD BLOCK -->\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/authenticate_message.go",
    "content": "package ntlmssp\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype authenicateMessage struct {\n\tLmChallengeResponse []byte\n\tNtChallengeResponse []byte\n\n\tTargetName string\n\tUserName   string\n\n\t// only set if negotiateFlag_NTLMSSP_NEGOTIATE_KEY_EXCH\n\tEncryptedRandomSessionKey []byte\n\n\tNegotiateFlags negotiateFlags\n\n\tMIC []byte\n}\n\ntype authenticateMessageFields struct {\n\tmessageHeader\n\tLmChallengeResponse varField\n\tNtChallengeResponse varField\n\tTargetName          varField\n\tUserName            varField\n\tWorkstation         varField\n\t_                   [8]byte\n\tNegotiateFlags      negotiateFlags\n}\n\nfunc (m authenicateMessage) MarshalBinary() ([]byte, error) {\n\tif !m.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEUNICODE) {\n\t\treturn nil, errors.New(\"Only unicode is supported\")\n\t}\n\n\ttarget, user := toUnicode(m.TargetName), toUnicode(m.UserName)\n\tworkstation := toUnicode(\"\")\n\n\tptr := binary.Size(&authenticateMessageFields{})\n\tf := authenticateMessageFields{\n\t\tmessageHeader:       newMessageHeader(3),\n\t\tNegotiateFlags:      m.NegotiateFlags,\n\t\tLmChallengeResponse: newVarField(&ptr, len(m.LmChallengeResponse)),\n\t\tNtChallengeResponse: newVarField(&ptr, len(m.NtChallengeResponse)),\n\t\tTargetName:          newVarField(&ptr, len(target)),\n\t\tUserName:            newVarField(&ptr, len(user)),\n\t\tWorkstation:         newVarField(&ptr, len(workstation)),\n\t}\n\n\tf.NegotiateFlags.Unset(negotiateFlagNTLMSSPNEGOTIATEVERSION)\n\n\tb := bytes.Buffer{}\n\tif err := binary.Write(&b, binary.LittleEndian, &f); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := binary.Write(&b, binary.LittleEndian, &m.LmChallengeResponse); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := binary.Write(&b, binary.LittleEndian, &m.NtChallengeResponse); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := binary.Write(&b, binary.LittleEndian, &target); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := binary.Write(&b, binary.LittleEndian, &user); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := binary.Write(&b, binary.LittleEndian, &workstation); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn b.Bytes(), nil\n}\n\n//ProcessChallenge crafts an AUTHENTICATE message in response to the CHALLENGE message\n//that was received from the server\nfunc ProcessChallenge(challengeMessageData []byte, user, password string, domainNeeded bool) ([]byte, error) {\n\tif user == \"\" && password == \"\" {\n\t\treturn nil, errors.New(\"Anonymous authentication not supported\")\n\t}\n\n\tvar cm challengeMessage\n\tif err := cm.UnmarshalBinary(challengeMessageData); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {\n\t\treturn nil, errors.New(\"Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)\")\n\t}\n\tif cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {\n\t\treturn nil, errors.New(\"Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)\")\n\t}\n\t\n\tif !domainNeeded {\n\t\tcm.TargetName = \"\"\n\t}\n\n\tam := authenicateMessage{\n\t\tUserName:       user,\n\t\tTargetName:     cm.TargetName,\n\t\tNegotiateFlags: cm.NegotiateFlags,\n\t}\n\n\ttimestamp := cm.TargetInfo[avIDMsvAvTimestamp]\n\tif timestamp == nil { // no time sent, take current time\n\t\tft := uint64(time.Now().UnixNano()) / 100\n\t\tft += 116444736000000000 // add time between unix & windows offset\n\t\ttimestamp = make([]byte, 8)\n\t\tbinary.LittleEndian.PutUint64(timestamp, ft)\n\t}\n\n\tclientChallenge := make([]byte, 8)\n\trand.Reader.Read(clientChallenge)\n\n\tntlmV2Hash := getNtlmV2Hash(password, user, cm.TargetName)\n\n\tam.NtChallengeResponse = computeNtlmV2Response(ntlmV2Hash,\n\t\tcm.ServerChallenge[:], clientChallenge, timestamp, cm.TargetInfoRaw)\n\n\tif cm.TargetInfoRaw == nil {\n\t\tam.LmChallengeResponse = computeLmV2Response(ntlmV2Hash,\n\t\t\tcm.ServerChallenge[:], clientChallenge)\n\t}\n\treturn am.MarshalBinary()\n}\n\nfunc ProcessChallengeWithHash(challengeMessageData []byte, user, hash string) ([]byte, error) {\n\tif user == \"\" && hash == \"\" {\n\t\treturn nil, errors.New(\"Anonymous authentication not supported\")\n\t}\n\n\tvar cm challengeMessage\n\tif err := cm.UnmarshalBinary(challengeMessageData); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {\n\t\treturn nil, errors.New(\"Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)\")\n\t}\n\tif cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {\n\t\treturn nil, errors.New(\"Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)\")\n\t}\n\n\tam := authenicateMessage{\n\t\tUserName:       user,\n\t\tTargetName:     cm.TargetName,\n\t\tNegotiateFlags: cm.NegotiateFlags,\n\t}\n\n\ttimestamp := cm.TargetInfo[avIDMsvAvTimestamp]\n\tif timestamp == nil { // no time sent, take current time\n\t\tft := uint64(time.Now().UnixNano()) / 100\n\t\tft += 116444736000000000 // add time between unix & windows offset\n\t\ttimestamp = make([]byte, 8)\n\t\tbinary.LittleEndian.PutUint64(timestamp, ft)\n\t}\n\n\tclientChallenge := make([]byte, 8)\n\trand.Reader.Read(clientChallenge)\n\n\thashParts := strings.Split(hash, \":\")\n\tif len(hashParts) > 1 {\n\t\thash = hashParts[1]\n\t}\n\thashBytes, err := hex.DecodeString(hash)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tntlmV2Hash := hmacMd5(hashBytes, toUnicode(strings.ToUpper(user)+cm.TargetName))\n\n\tam.NtChallengeResponse = computeNtlmV2Response(ntlmV2Hash,\n\t\tcm.ServerChallenge[:], clientChallenge, timestamp, cm.TargetInfoRaw)\n\n\tif cm.TargetInfoRaw == nil {\n\t\tam.LmChallengeResponse = computeLmV2Response(ntlmV2Hash,\n\t\t\tcm.ServerChallenge[:], clientChallenge)\n\t}\n\treturn am.MarshalBinary()\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/authheader.go",
    "content": "package ntlmssp\n\nimport (\n\t\"encoding/base64\"\n\t\"strings\"\n)\n\ntype authheader []string\n\nfunc (h authheader) IsBasic() bool {\n\tfor _, s := range h {\n\t\tif strings.HasPrefix(string(s), \"Basic \") {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (h authheader) Basic() string {\n\tfor _, s := range h {\n\t\tif strings.HasPrefix(string(s), \"Basic \") {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn \"\"\n}\n\nfunc (h authheader) IsNegotiate() bool {\n\tfor _, s := range h {\n\t\tif strings.HasPrefix(string(s), \"Negotiate\") {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (h authheader) IsNTLM() bool {\n\tfor _, s := range h {\n\t\tif strings.HasPrefix(string(s), \"NTLM\") {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (h authheader) GetData() ([]byte, error) {\n\tfor _, s := range h {\n\t\tif strings.HasPrefix(string(s), \"NTLM\") || strings.HasPrefix(string(s), \"Negotiate\") || strings.HasPrefix(string(s), \"Basic \") {\n\t\t\tp := strings.Split(string(s), \" \")\n\t\t\tif len(p) < 2 {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t\treturn base64.StdEncoding.DecodeString(string(p[1]))\n\t\t}\n\t}\n\treturn nil, nil\n}\n\nfunc (h authheader) GetBasicCreds() (username, password string, err error) {\n\td, err := h.GetData()\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\tparts := strings.SplitN(string(d), \":\", 2)\n\treturn parts[0], parts[1], nil\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/avids.go",
    "content": "package ntlmssp\n\ntype avID uint16\n\nconst (\n\tavIDMsvAvEOL avID = iota\n\tavIDMsvAvNbComputerName\n\tavIDMsvAvNbDomainName\n\tavIDMsvAvDNSComputerName\n\tavIDMsvAvDNSDomainName\n\tavIDMsvAvDNSTreeName\n\tavIDMsvAvFlags\n\tavIDMsvAvTimestamp\n\tavIDMsvAvSingleHost\n\tavIDMsvAvTargetName\n\tavIDMsvChannelBindings\n)\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/challenge_message.go",
    "content": "package ntlmssp\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n)\n\ntype challengeMessageFields struct {\n\tmessageHeader\n\tTargetName      varField\n\tNegotiateFlags  negotiateFlags\n\tServerChallenge [8]byte\n\t_               [8]byte\n\tTargetInfo      varField\n}\n\nfunc (m challengeMessageFields) IsValid() bool {\n\treturn m.messageHeader.IsValid() && m.MessageType == 2\n}\n\ntype challengeMessage struct {\n\tchallengeMessageFields\n\tTargetName    string\n\tTargetInfo    map[avID][]byte\n\tTargetInfoRaw []byte\n}\n\nfunc (m *challengeMessage) UnmarshalBinary(data []byte) error {\n\tr := bytes.NewReader(data)\n\terr := binary.Read(r, binary.LittleEndian, &m.challengeMessageFields)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !m.challengeMessageFields.IsValid() {\n\t\treturn fmt.Errorf(\"Message is not a valid challenge message: %+v\", m.challengeMessageFields.messageHeader)\n\t}\n\n\tif m.challengeMessageFields.TargetName.Len > 0 {\n\t\tm.TargetName, err = m.challengeMessageFields.TargetName.ReadStringFrom(data, m.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEUNICODE))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m.challengeMessageFields.TargetInfo.Len > 0 {\n\t\td, err := m.challengeMessageFields.TargetInfo.ReadFrom(data)\n\t\tm.TargetInfoRaw = d\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tm.TargetInfo = make(map[avID][]byte)\n\t\tr := bytes.NewReader(d)\n\t\tfor {\n\t\t\tvar id avID\n\t\t\tvar l uint16\n\t\t\terr = binary.Read(r, binary.LittleEndian, &id)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif id == avIDMsvAvEOL {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\terr = binary.Read(r, binary.LittleEndian, &l)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tvalue := make([]byte, l)\n\t\t\tn, err := r.Read(value)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif n != int(l) {\n\t\t\t\treturn fmt.Errorf(\"Expected to read %d bytes, got only %d\", l, n)\n\t\t\t}\n\t\t\tm.TargetInfo[id] = value\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/messageheader.go",
    "content": "package ntlmssp\n\nimport (\n\t\"bytes\"\n)\n\nvar signature = [8]byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0}\n\ntype messageHeader struct {\n\tSignature   [8]byte\n\tMessageType uint32\n}\n\nfunc (h messageHeader) IsValid() bool {\n\treturn bytes.Equal(h.Signature[:], signature[:]) &&\n\t\th.MessageType > 0 && h.MessageType < 4\n}\n\nfunc newMessageHeader(messageType uint32) messageHeader {\n\treturn messageHeader{signature, messageType}\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/negotiate_flags.go",
    "content": "package ntlmssp\n\ntype negotiateFlags uint32\n\nconst (\n\t/*A*/ negotiateFlagNTLMSSPNEGOTIATEUNICODE negotiateFlags = 1 << 0\n\t/*B*/ negotiateFlagNTLMNEGOTIATEOEM = 1 << 1\n\t/*C*/ negotiateFlagNTLMSSPREQUESTTARGET = 1 << 2\n\n\t/*D*/\n\tnegotiateFlagNTLMSSPNEGOTIATESIGN = 1 << 4\n\t/*E*/ negotiateFlagNTLMSSPNEGOTIATESEAL = 1 << 5\n\t/*F*/ negotiateFlagNTLMSSPNEGOTIATEDATAGRAM = 1 << 6\n\t/*G*/ negotiateFlagNTLMSSPNEGOTIATELMKEY = 1 << 7\n\n\t/*H*/\n\tnegotiateFlagNTLMSSPNEGOTIATENTLM = 1 << 9\n\n\t/*J*/\n\tnegotiateFlagANONYMOUS = 1 << 11\n\t/*K*/ negotiateFlagNTLMSSPNEGOTIATEOEMDOMAINSUPPLIED = 1 << 12\n\t/*L*/ negotiateFlagNTLMSSPNEGOTIATEOEMWORKSTATIONSUPPLIED = 1 << 13\n\n\t/*M*/\n\tnegotiateFlagNTLMSSPNEGOTIATEALWAYSSIGN = 1 << 15\n\t/*N*/ negotiateFlagNTLMSSPTARGETTYPEDOMAIN = 1 << 16\n\t/*O*/ negotiateFlagNTLMSSPTARGETTYPESERVER = 1 << 17\n\n\t/*P*/\n\tnegotiateFlagNTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY = 1 << 19\n\t/*Q*/ negotiateFlagNTLMSSPNEGOTIATEIDENTIFY = 1 << 20\n\n\t/*R*/\n\tnegotiateFlagNTLMSSPREQUESTNONNTSESSIONKEY = 1 << 22\n\t/*S*/ negotiateFlagNTLMSSPNEGOTIATETARGETINFO = 1 << 23\n\n\t/*T*/\n\tnegotiateFlagNTLMSSPNEGOTIATEVERSION = 1 << 25\n\n\t/*U*/\n\tnegotiateFlagNTLMSSPNEGOTIATE128 = 1 << 29\n\t/*V*/ negotiateFlagNTLMSSPNEGOTIATEKEYEXCH = 1 << 30\n\t/*W*/ negotiateFlagNTLMSSPNEGOTIATE56 = 1 << 31\n)\n\nfunc (field negotiateFlags) Has(flags negotiateFlags) bool {\n\treturn field&flags == flags\n}\n\nfunc (field *negotiateFlags) Unset(flags negotiateFlags) {\n\t*field = *field ^ (*field & flags)\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/negotiate_message.go",
    "content": "package ntlmssp\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"strings\"\n)\n\nconst expMsgBodyLen = 40\n\ntype negotiateMessageFields struct {\n\tmessageHeader\n\tNegotiateFlags negotiateFlags\n\n\tDomain      varField\n\tWorkstation varField\n\n\tVersion\n}\n\nvar defaultFlags = negotiateFlagNTLMSSPNEGOTIATETARGETINFO |\n\tnegotiateFlagNTLMSSPNEGOTIATE56 |\n\tnegotiateFlagNTLMSSPNEGOTIATE128 |\n\tnegotiateFlagNTLMSSPNEGOTIATEUNICODE |\n\tnegotiateFlagNTLMSSPNEGOTIATEEXTENDEDSESSIONSECURITY\n\n//NewNegotiateMessage creates a new NEGOTIATE message with the\n//flags that this package supports.\nfunc NewNegotiateMessage(domainName, workstationName string) ([]byte, error) {\n\tpayloadOffset := expMsgBodyLen\n\tflags := defaultFlags\n\n\tif domainName != \"\" {\n\t\tflags |= negotiateFlagNTLMSSPNEGOTIATEOEMDOMAINSUPPLIED\n\t}\n\n\tif workstationName != \"\" {\n\t\tflags |= negotiateFlagNTLMSSPNEGOTIATEOEMWORKSTATIONSUPPLIED\n\t}\n\n\tmsg := negotiateMessageFields{\n\t\tmessageHeader:  newMessageHeader(1),\n\t\tNegotiateFlags: flags,\n\t\tDomain:         newVarField(&payloadOffset, len(domainName)),\n\t\tWorkstation:    newVarField(&payloadOffset, len(workstationName)),\n\t\tVersion:        DefaultVersion(),\n\t}\n\n\tb := bytes.Buffer{}\n\tif err := binary.Write(&b, binary.LittleEndian, &msg); err != nil {\n\t\treturn nil, err\n\t}\n\tif b.Len() != expMsgBodyLen {\n\t\treturn nil, errors.New(\"incorrect body length\")\n\t}\n\n\tpayload := strings.ToUpper(domainName + workstationName)\n\tif _, err := b.WriteString(payload); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn b.Bytes(), nil\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/negotiator.go",
    "content": "package ntlmssp\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strings\"\n)\n\n// GetDomain : parse domain name from based on slashes in the input\n// Need to check for upn as well\nfunc GetDomain(user string) (string, string, bool) {\n\tdomain := \"\"\n\tdomainNeeded := false\n\n\tif strings.Contains(user, \"\\\\\") {\n\t\tucomponents := strings.SplitN(user, \"\\\\\", 2)\n\t\tdomain = ucomponents[0]\n\t\tuser = ucomponents[1]\n\t\tdomainNeeded = true\n\t} else if strings.Contains(user, \"@\") {\n\t\tdomainNeeded = false\n\t} else {\n\t\tdomainNeeded = true\n\t}\n\treturn user, domain, domainNeeded\n}\n\n//Negotiator is a http.Roundtripper decorator that automatically\n//converts basic authentication to NTLM/Negotiate authentication when appropriate.\ntype Negotiator struct{ http.RoundTripper }\n\n//RoundTrip sends the request to the server, handling any authentication\n//re-sends as needed.\nfunc (l Negotiator) RoundTrip(req *http.Request) (res *http.Response, err error) {\n\t// Use default round tripper if not provided\n\trt := l.RoundTripper\n\tif rt == nil {\n\t\trt = http.DefaultTransport\n\t}\n\t// If it is not basic auth, just round trip the request as usual\n\treqauth := authheader(req.Header.Values(\"Authorization\"))\n\tif !reqauth.IsBasic() {\n\t\treturn rt.RoundTrip(req)\n\t}\n\treqauthBasic := reqauth.Basic()\n\t// Save request body\n\tbody := bytes.Buffer{}\n\tif req.Body != nil {\n\t\t_, err = body.ReadFrom(req.Body)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\treq.Body.Close()\n\t\treq.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))\n\t}\n\t// first try anonymous, in case the server still finds us\n\t// authenticated from previous traffic\n\treq.Header.Del(\"Authorization\")\n\tres, err = rt.RoundTrip(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif res.StatusCode != http.StatusUnauthorized {\n\t\treturn res, err\n\t}\n\tresauth := authheader(res.Header.Values(\"Www-Authenticate\"))\n\tif !resauth.IsNegotiate() && !resauth.IsNTLM() {\n\t\t// Unauthorized, Negotiate not requested, let's try with basic auth\n\t\treq.Header.Set(\"Authorization\", string(reqauthBasic))\n\t\tio.Copy(ioutil.Discard, res.Body)\n\t\tres.Body.Close()\n\t\treq.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))\n\n\t\tres, err = rt.RoundTrip(req)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif res.StatusCode != http.StatusUnauthorized {\n\t\t\treturn res, err\n\t\t}\n\t\tresauth = authheader(res.Header.Values(\"Www-Authenticate\"))\n\t}\n\n\tif resauth.IsNegotiate() || resauth.IsNTLM() {\n\t\t// 401 with request:Basic and response:Negotiate\n\t\tio.Copy(ioutil.Discard, res.Body)\n\t\tres.Body.Close()\n\n\t\t// recycle credentials\n\t\tu, p, err := reqauth.GetBasicCreds()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// get domain from username\n\t\tdomain := \"\"\n\t\tu, domain, domainNeeded := GetDomain(u)\n\n\t\t// send negotiate\n\t\tnegotiateMessage, err := NewNegotiateMessage(domain, \"\")\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif resauth.IsNTLM() {\n\t\t\treq.Header.Set(\"Authorization\", \"NTLM \"+base64.StdEncoding.EncodeToString(negotiateMessage))\n\t\t} else {\n\t\t\treq.Header.Set(\"Authorization\", \"Negotiate \"+base64.StdEncoding.EncodeToString(negotiateMessage))\n\t\t}\n\n\t\treq.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))\n\n\t\tres, err = rt.RoundTrip(req)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// receive challenge?\n\t\tresauth = authheader(res.Header.Values(\"Www-Authenticate\"))\n\t\tchallengeMessage, err := resauth.GetData()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !(resauth.IsNegotiate() || resauth.IsNTLM()) || len(challengeMessage) == 0 {\n\t\t\t// Negotiation failed, let client deal with response\n\t\t\treturn res, nil\n\t\t}\n\t\tio.Copy(ioutil.Discard, res.Body)\n\t\tres.Body.Close()\n\n\t\t// send authenticate\n\t\tauthenticateMessage, err := ProcessChallenge(challengeMessage, u, p, domainNeeded)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif resauth.IsNTLM() {\n\t\t\treq.Header.Set(\"Authorization\", \"NTLM \"+base64.StdEncoding.EncodeToString(authenticateMessage))\n\t\t} else {\n\t\t\treq.Header.Set(\"Authorization\", \"Negotiate \"+base64.StdEncoding.EncodeToString(authenticateMessage))\n\t\t}\n\n\t\treq.Body = ioutil.NopCloser(bytes.NewReader(body.Bytes()))\n\n\t\treturn rt.RoundTrip(req)\n\t}\n\n\treturn res, err\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/nlmp.go",
    "content": "// Package ntlmssp provides NTLM/Negotiate authentication over HTTP\n//\n// Protocol details from https://msdn.microsoft.com/en-us/library/cc236621.aspx,\n// implementation hints from http://davenport.sourceforge.net/ntlm.html .\n// This package only implements authentication, no key exchange or encryption. It\n// only supports Unicode (UTF16LE) encoding of protocol strings, no OEM encoding.\n// This package implements NTLMv2.\npackage ntlmssp\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/md5\"\n\t\"golang.org/x/crypto/md4\"\n\t\"strings\"\n)\n\nfunc getNtlmV2Hash(password, username, target string) []byte {\n\treturn hmacMd5(getNtlmHash(password), toUnicode(strings.ToUpper(username)+target))\n}\n\nfunc getNtlmHash(password string) []byte {\n\thash := md4.New()\n\thash.Write(toUnicode(password))\n\treturn hash.Sum(nil)\n}\n\nfunc computeNtlmV2Response(ntlmV2Hash, serverChallenge, clientChallenge,\n\ttimestamp, targetInfo []byte) []byte {\n\n\ttemp := []byte{1, 1, 0, 0, 0, 0, 0, 0}\n\ttemp = append(temp, timestamp...)\n\ttemp = append(temp, clientChallenge...)\n\ttemp = append(temp, 0, 0, 0, 0)\n\ttemp = append(temp, targetInfo...)\n\ttemp = append(temp, 0, 0, 0, 0)\n\n\tNTProofStr := hmacMd5(ntlmV2Hash, serverChallenge, temp)\n\treturn append(NTProofStr, temp...)\n}\n\nfunc computeLmV2Response(ntlmV2Hash, serverChallenge, clientChallenge []byte) []byte {\n\treturn append(hmacMd5(ntlmV2Hash, serverChallenge, clientChallenge), clientChallenge...)\n}\n\nfunc hmacMd5(key []byte, data ...[]byte) []byte {\n\tmac := hmac.New(md5.New, key)\n\tfor _, d := range data {\n\t\tmac.Write(d)\n\t}\n\treturn mac.Sum(nil)\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/unicode.go",
    "content": "package ntlmssp\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"unicode/utf16\"\n)\n\n// helper func's for dealing with Windows Unicode (UTF16LE)\n\nfunc fromUnicode(d []byte) (string, error) {\n\tif len(d)%2 > 0 {\n\t\treturn \"\", errors.New(\"Unicode (UTF 16 LE) specified, but uneven data length\")\n\t}\n\ts := make([]uint16, len(d)/2)\n\terr := binary.Read(bytes.NewReader(d), binary.LittleEndian, &s)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(utf16.Decode(s)), nil\n}\n\nfunc toUnicode(s string) []byte {\n\tuints := utf16.Encode([]rune(s))\n\tb := bytes.Buffer{}\n\tbinary.Write(&b, binary.LittleEndian, &uints)\n\treturn b.Bytes()\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/varfield.go",
    "content": "package ntlmssp\n\nimport (\n\t\"errors\"\n)\n\ntype varField struct {\n\tLen          uint16\n\tMaxLen       uint16\n\tBufferOffset uint32\n}\n\nfunc (f varField) ReadFrom(buffer []byte) ([]byte, error) {\n\tif len(buffer) < int(f.BufferOffset+uint32(f.Len)) {\n\t\treturn nil, errors.New(\"Error reading data, varField extends beyond buffer\")\n\t}\n\treturn buffer[f.BufferOffset : f.BufferOffset+uint32(f.Len)], nil\n}\n\nfunc (f varField) ReadStringFrom(buffer []byte, unicode bool) (string, error) {\n\td, err := f.ReadFrom(buffer)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif unicode { // UTF-16LE encoding scheme\n\t\treturn fromUnicode(d)\n\t}\n\t// OEM encoding, close enough to ASCII, since no code page is specified\n\treturn string(d), err\n}\n\nfunc newVarField(ptr *int, fieldsize int) varField {\n\tf := varField{\n\t\tLen:          uint16(fieldsize),\n\t\tMaxLen:       uint16(fieldsize),\n\t\tBufferOffset: uint32(*ptr),\n\t}\n\t*ptr += fieldsize\n\treturn f\n}\n"
  },
  {
    "path": "vendor/github.com/Azure/go-ntlmssp/version.go",
    "content": "package ntlmssp\n\n// Version is a struct representing https://msdn.microsoft.com/en-us/library/cc236654.aspx\ntype Version struct {\n\tProductMajorVersion uint8\n\tProductMinorVersion uint8\n\tProductBuild        uint16\n\t_                   [3]byte\n\tNTLMRevisionCurrent uint8\n}\n\n// DefaultVersion returns a Version with \"sensible\" defaults (Windows 7)\nfunc DefaultVersion() Version {\n\treturn Version{\n\t\tProductMajorVersion: 6,\n\t\tProductMinorVersion: 1,\n\t\tProductBuild:        7601,\n\t\tNTLMRevisionCurrent: 15,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/Masterminds/semver/v3/CHANGELOG.md",
    "content": "# Changelog\n\n## 3.4.0 (2025-06-27)\n\n### Added\n\n- #268: Added property to Constraints to include prereleases for Check and Validate\n\n### Changed\n\n- #263: Updated Go testing for 1.24, 1.23, and 1.22\n- #269: Updated the error message handling for message case and wrapping errors\n- #266: Restore the ability to have leading 0's when parsing with NewVersion.\n  Opt-out of this by setting CoerceNewVersion to false.\n\n### Fixed\n\n- #257: Fixed the CodeQL link (thanks @dmitris)\n- #262: Restored detailed errors when failed to parse with NewVersion. Opt-out\n  of this by setting DetailedNewVersionErrors to false for faster performance.\n- #267: Handle pre-releases for an \"and\" group if one constraint includes them\n\n## 3.3.1 (2024-11-19)\n\n### Fixed\n\n- #253: Fix for allowing some version that were invalid\n\n## 3.3.0 (2024-08-27)\n\n### Added\n\n- #238: Add LessThanEqual and GreaterThanEqual functions (thanks @grosser)\n- #213: nil version equality checking (thanks @KnutZuidema)\n\n### Changed\n\n- #241: Simplify StrictNewVersion parsing (thanks @grosser)\n- Testing support up through Go 1.23\n- Minimum version set to 1.21 as this is what's tested now\n- Fuzz testing now supports caching\n\n## 3.2.1 (2023-04-10)\n\n### Changed\n\n- #198: Improved testing around pre-release names\n- #200: Improved code scanning with addition of CodeQL\n- #201: Testing now includes Go 1.20. Go 1.17 has been dropped\n- #202: Migrated Fuzz testing to Go built-in Fuzzing. CI runs daily\n- #203: Docs updated for security details\n\n### Fixed\n\n- #199: Fixed issue with range transformations\n\n## 3.2.0 (2022-11-28)\n\n### Added\n\n- #190: Added text marshaling and unmarshaling\n- #167: Added JSON marshalling for constraints (thanks @SimonTheLeg)\n- #173: Implement encoding.TextMarshaler and encoding.TextUnmarshaler on Version (thanks @MarkRosemaker)\n- #179: Added New() version constructor (thanks @kazhuravlev)\n\n### Changed\n\n- #182/#183: Updated CI testing setup\n\n### Fixed\n\n- #186: Fixing issue where validation of constraint section gave false positives\n- #176: Fix constraints check with *-0 (thanks @mtt0)\n- #181: Fixed Caret operator (^) gives unexpected results when the minor version in constraint is 0 (thanks @arshchimni)\n- #161: Fixed godoc (thanks @afirth)\n\n## 3.1.1 (2020-11-23)\n\n### Fixed\n\n- #158: Fixed issue with generated regex operation order that could cause problem\n\n## 3.1.0 (2020-04-15)\n\n### Added\n\n- #131: Add support for serializing/deserializing SQL (thanks @ryancurrah)\n\n### Changed\n\n- #148: More accurate validation messages on constraints\n\n## 3.0.3 (2019-12-13)\n\n### Fixed\n\n- #141: Fixed issue with <= comparison\n\n## 3.0.2 (2019-11-14)\n\n### Fixed\n\n- #134: Fixed broken constraint checking with ^0.0 (thanks @krmichelos)\n\n## 3.0.1 (2019-09-13)\n\n### Fixed\n\n- #125: Fixes issue with module path for v3\n\n## 3.0.0 (2019-09-12)\n\nThis is a major release of the semver package which includes API changes. The Go\nAPI is compatible with ^1. The Go API was not changed because many people are using\n`go get` without Go modules for their applications and API breaking changes cause\nerrors which we have or would need to support.\n\nThe changes in this release are the handling based on the data passed into the\nfunctions. These are described in the added and changed sections below.\n\n### Added\n\n- StrictNewVersion function. This is similar to NewVersion but will return an\n  error if the version passed in is not a strict semantic version. For example,\n  1.2.3 would pass but v1.2.3 or 1.2 would fail because they are not strictly\n  speaking semantic versions. This function is faster, performs fewer operations,\n  and uses fewer allocations than NewVersion.\n- Fuzzing has been performed on NewVersion, StrictNewVersion, and NewConstraint.\n  The Makefile contains the operations used. For more information on you can start\n  on Wikipedia at https://en.wikipedia.org/wiki/Fuzzing\n- Now using Go modules\n\n### Changed\n\n- NewVersion has proper prerelease and metadata validation with error messages\n  to signal an issue with either of them\n- ^ now operates using a similar set of rules to npm/js and Rust/Cargo. If the\n  version is >=1 the ^ ranges works the same as v1. For major versions of 0 the\n  rules have changed. The minor version is treated as the stable version unless\n  a patch is specified and then it is equivalent to =. One difference from npm/js\n  is that prereleases there are only to a specific version (e.g. 1.2.3).\n  Prereleases here look over multiple versions and follow semantic version\n  ordering rules. This pattern now follows along with the expected and requested\n  handling of this packaged by numerous users.\n\n## 1.5.0 (2019-09-11)\n\n### Added\n\n- #103: Add basic fuzzing for `NewVersion()` (thanks @jesse-c)\n\n### Changed\n\n- #82: Clarify wildcard meaning in range constraints and update tests for it (thanks @greysteil)\n- #83: Clarify caret operator range for pre-1.0.0 dependencies (thanks @greysteil)\n- #72: Adding docs comment pointing to vert for a cli\n- #71: Update the docs on pre-release comparator handling\n- #89: Test with new go versions (thanks @thedevsaddam)\n- #87: Added $ to ValidPrerelease for better validation (thanks @jeremycarroll)\n\n### Fixed\n\n- #78: Fix unchecked error in example code (thanks @ravron)\n- #70: Fix the handling of pre-releases and the 0.0.0 release edge case\n- #97: Fixed copyright file for proper display on GitHub\n- #107: Fix handling prerelease when sorting alphanum and num\n- #109: Fixed where Validate sometimes returns wrong message on error\n\n## 1.4.2 (2018-04-10)\n\n### Changed\n\n- #72: Updated the docs to point to vert for a console appliaction\n- #71: Update the docs on pre-release comparator handling\n\n### Fixed\n\n- #70: Fix the handling of pre-releases and the 0.0.0 release edge case\n\n## 1.4.1 (2018-04-02)\n\n### Fixed\n\n- Fixed #64: Fix pre-release precedence issue (thanks @uudashr)\n\n## 1.4.0 (2017-10-04)\n\n### Changed\n\n- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill)\n\n## 1.3.1 (2017-07-10)\n\n### Fixed\n\n- Fixed #57: number comparisons in prerelease sometimes inaccurate\n\n## 1.3.0 (2017-05-02)\n\n### Added\n\n- #45: Added json (un)marshaling support (thanks @mh-cbon)\n- Stability marker. See https://masterminds.github.io/stability/\n\n### Fixed\n\n- #51: Fix handling of single digit tilde constraint (thanks @dgodd)\n\n### Changed\n\n- #55: The godoc icon moved from png to svg\n\n## 1.2.3 (2017-04-03)\n\n### Fixed\n\n- #46: Fixed 0.x.x and 0.0.x in constraints being treated as *\n\n## Release 1.2.2 (2016-12-13)\n\n### Fixed\n\n- #34: Fixed issue where hyphen range was not working with pre-release parsing.\n\n## Release 1.2.1 (2016-11-28)\n\n### Fixed\n\n- #24: Fixed edge case issue where constraint \"> 0\" does not handle \"0.0.1-alpha\"\n  properly.\n\n## Release 1.2.0 (2016-11-04)\n\n### Added\n\n- #20: Added MustParse function for versions (thanks @adamreese)\n- #15: Added increment methods on versions (thanks @mh-cbon)\n\n### Fixed\n\n- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and\n  might not satisfy the intended compatibility. The change here ignores pre-releases\n  on constraint checks (e.g., ~ or ^) when a pre-release is not part of the\n  constraint. For example, `^1.2.3` will ignore pre-releases while\n  `^1.2.3-alpha` will include them.\n\n## Release 1.1.1 (2016-06-30)\n\n### Changed\n\n- Issue #9: Speed up version comparison performance (thanks @sdboyer)\n- Issue #8: Added benchmarks (thanks @sdboyer)\n- Updated Go Report Card URL to new location\n- Updated Readme to add code snippet formatting (thanks @mh-cbon)\n- Updating tagging to v[SemVer] structure for compatibility with other tools.\n\n## Release 1.1.0 (2016-03-11)\n\n- Issue #2: Implemented validation to provide reasons a versions failed a\n  constraint.\n\n## Release 1.0.1 (2015-12-31)\n\n- Fixed #1: * constraint failing on valid versions.\n\n## Release 1.0.0 (2015-10-20)\n\n- Initial release\n"
  },
  {
    "path": "vendor/github.com/Masterminds/semver/v3/LICENSE.txt",
    "content": "Copyright (C) 2014-2019, Matt Butcher and Matt Farina\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/Masterminds/semver/v3/SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nThe following versions of semver are currently supported:\n\n| Version | Supported          |\n| ------- | ------------------ |\n| 3.x     | :white_check_mark: |\n| 2.x     | :x:                |\n| 1.x     | :x:                |\n\nFixes are only released for the latest minor version in the form of a patch release.\n\n## Reporting a Vulnerability\n\nYou can privately disclose a vulnerability through GitHubs\n[private vulnerability reporting](https://github.com/Masterminds/semver/security/advisories)\nmechanism.\n"
  },
  {
    "path": "vendor/github.com/Masterminds/semver/v3/collection.go",
    "content": "package semver\n\n// Collection is a collection of Version instances and implements the sort\n// interface. See the sort package for more details.\n// https://golang.org/pkg/sort/\ntype Collection []*Version\n\n// Len returns the length of a collection. The number of Version instances\n// on the slice.\nfunc (c Collection) Len() int {\n\treturn len(c)\n}\n\n// Less is needed for the sort interface to compare two Version objects on the\n// slice. If checks if one is less than the other.\nfunc (c Collection) Less(i, j int) bool {\n\treturn c[i].LessThan(c[j])\n}\n\n// Swap is needed for the sort interface to replace the Version objects\n// at two different positions in the slice.\nfunc (c Collection) Swap(i, j int) {\n\tc[i], c[j] = c[j], c[i]\n}\n"
  },
  {
    "path": "vendor/github.com/Masterminds/semver/v3/constraints.go",
    "content": "package semver\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n)\n\n// Constraints is one or more constraint that a semantic version can be\n// checked against.\ntype Constraints struct {\n\tconstraints [][]*constraint\n\tcontainsPre []bool\n\n\t// IncludePrerelease specifies if pre-releases should be included in\n\t// the results. Note, if a constraint range has a prerelease than\n\t// prereleases will be included for that AND group even if this is\n\t// set to false.\n\tIncludePrerelease bool\n}\n\n// NewConstraint returns a Constraints instance that a Version instance can\n// be checked against. If there is a parse error it will be returned.\nfunc NewConstraint(c string) (*Constraints, error) {\n\n\t// Rewrite - ranges into a comparison operation.\n\tc = rewriteRange(c)\n\n\tors := strings.Split(c, \"||\")\n\tlenors := len(ors)\n\tor := make([][]*constraint, lenors)\n\thasPre := make([]bool, lenors)\n\tfor k, v := range ors {\n\t\t// Validate the segment\n\t\tif !validConstraintRegex.MatchString(v) {\n\t\t\treturn nil, fmt.Errorf(\"improper constraint: %s\", v)\n\t\t}\n\n\t\tcs := findConstraintRegex.FindAllString(v, -1)\n\t\tif cs == nil {\n\t\t\tcs = append(cs, v)\n\t\t}\n\t\tresult := make([]*constraint, len(cs))\n\t\tfor i, s := range cs {\n\t\t\tpc, err := parseConstraint(s)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\t// If one of the constraints has a prerelease record this.\n\t\t\t// This information is used when checking all in an \"and\"\n\t\t\t// group to ensure they all check for prereleases.\n\t\t\tif pc.con.pre != \"\" {\n\t\t\t\thasPre[k] = true\n\t\t\t}\n\n\t\t\tresult[i] = pc\n\t\t}\n\t\tor[k] = result\n\t}\n\n\to := &Constraints{\n\t\tconstraints: or,\n\t\tcontainsPre: hasPre,\n\t}\n\treturn o, nil\n}\n\n// Check tests if a version satisfies the constraints.\nfunc (cs Constraints) Check(v *Version) bool {\n\t// TODO(mattfarina): For v4 of this library consolidate the Check and Validate\n\t// functions as the underlying functions make that possible now.\n\t// loop over the ORs and check the inner ANDs\n\tfor i, o := range cs.constraints {\n\t\tjoy := true\n\t\tfor _, c := range o {\n\t\t\tif check, _ := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); !check {\n\t\t\t\tjoy = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif joy {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// Validate checks if a version satisfies a constraint. If not a slice of\n// reasons for the failure are returned in addition to a bool.\nfunc (cs Constraints) Validate(v *Version) (bool, []error) {\n\t// loop over the ORs and check the inner ANDs\n\tvar e []error\n\n\t// Capture the prerelease message only once. When it happens the first time\n\t// this var is marked\n\tvar prerelesase bool\n\tfor i, o := range cs.constraints {\n\t\tjoy := true\n\t\tfor _, c := range o {\n\t\t\t// Before running the check handle the case there the version is\n\t\t\t// a prerelease and the check is not searching for prereleases.\n\t\t\tif !(cs.IncludePrerelease || cs.containsPre[i]) && v.pre != \"\" {\n\t\t\t\tif !prerelesase {\n\t\t\t\t\tem := fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t\t\t\t\te = append(e, em)\n\t\t\t\t\tprerelesase = true\n\t\t\t\t}\n\t\t\t\tjoy = false\n\n\t\t\t} else {\n\n\t\t\t\tif _, err := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); err != nil {\n\t\t\t\t\te = append(e, err)\n\t\t\t\t\tjoy = false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif joy {\n\t\t\treturn true, []error{}\n\t\t}\n\t}\n\n\treturn false, e\n}\n\nfunc (cs Constraints) String() string {\n\tbuf := make([]string, len(cs.constraints))\n\tvar tmp bytes.Buffer\n\n\tfor k, v := range cs.constraints {\n\t\ttmp.Reset()\n\t\tvlen := len(v)\n\t\tfor kk, c := range v {\n\t\t\ttmp.WriteString(c.string())\n\n\t\t\t// Space separate the AND conditions\n\t\t\tif vlen > 1 && kk < vlen-1 {\n\t\t\t\ttmp.WriteString(\" \")\n\t\t\t}\n\t\t}\n\t\tbuf[k] = tmp.String()\n\t}\n\n\treturn strings.Join(buf, \" || \")\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface.\nfunc (cs *Constraints) UnmarshalText(text []byte) error {\n\ttemp, err := NewConstraint(string(text))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*cs = *temp\n\n\treturn nil\n}\n\n// MarshalText implements the encoding.TextMarshaler interface.\nfunc (cs Constraints) MarshalText() ([]byte, error) {\n\treturn []byte(cs.String()), nil\n}\n\nvar constraintOps map[string]cfunc\nvar constraintRegex *regexp.Regexp\nvar constraintRangeRegex *regexp.Regexp\n\n// Used to find individual constraints within a multi-constraint string\nvar findConstraintRegex *regexp.Regexp\n\n// Used to validate an segment of ANDs is valid\nvar validConstraintRegex *regexp.Regexp\n\nconst cvRegex string = `v?([0-9|x|X|\\*]+)(\\.[0-9|x|X|\\*]+)?(\\.[0-9|x|X|\\*]+)?` +\n\t`(-([0-9A-Za-z\\-]+(\\.[0-9A-Za-z\\-]+)*))?` +\n\t`(\\+([0-9A-Za-z\\-]+(\\.[0-9A-Za-z\\-]+)*))?`\n\nfunc init() {\n\tconstraintOps = map[string]cfunc{\n\t\t\"\":   constraintTildeOrEqual,\n\t\t\"=\":  constraintTildeOrEqual,\n\t\t\"!=\": constraintNotEqual,\n\t\t\">\":  constraintGreaterThan,\n\t\t\"<\":  constraintLessThan,\n\t\t\">=\": constraintGreaterThanEqual,\n\t\t\"=>\": constraintGreaterThanEqual,\n\t\t\"<=\": constraintLessThanEqual,\n\t\t\"=<\": constraintLessThanEqual,\n\t\t\"~\":  constraintTilde,\n\t\t\"~>\": constraintTilde,\n\t\t\"^\":  constraintCaret,\n\t}\n\n\tops := `=||!=|>|<|>=|=>|<=|=<|~|~>|\\^`\n\n\tconstraintRegex = regexp.MustCompile(fmt.Sprintf(\n\t\t`^\\s*(%s)\\s*(%s)\\s*$`,\n\t\tops,\n\t\tcvRegex))\n\n\tconstraintRangeRegex = regexp.MustCompile(fmt.Sprintf(\n\t\t`\\s*(%s)\\s+-\\s+(%s)\\s*`,\n\t\tcvRegex, cvRegex))\n\n\tfindConstraintRegex = regexp.MustCompile(fmt.Sprintf(\n\t\t`(%s)\\s*(%s)`,\n\t\tops,\n\t\tcvRegex))\n\n\t// The first time a constraint shows up will look slightly different from\n\t// future times it shows up due to a leading space or comma in a given\n\t// string.\n\tvalidConstraintRegex = regexp.MustCompile(fmt.Sprintf(\n\t\t`^(\\s*(%s)\\s*(%s)\\s*)((?:\\s+|,\\s*)(%s)\\s*(%s)\\s*)*$`,\n\t\tops,\n\t\tcvRegex,\n\t\tops,\n\t\tcvRegex))\n}\n\n// An individual constraint\ntype constraint struct {\n\t// The version used in the constraint check. For example, if a constraint\n\t// is '<= 2.0.0' the con a version instance representing 2.0.0.\n\tcon *Version\n\n\t// The original parsed version (e.g., 4.x from != 4.x)\n\torig string\n\n\t// The original operator for the constraint\n\torigfunc string\n\n\t// When an x is used as part of the version (e.g., 1.x)\n\tminorDirty bool\n\tdirty      bool\n\tpatchDirty bool\n}\n\n// Check if a version meets the constraint\nfunc (c *constraint) check(v *Version, includePre bool) (bool, error) {\n\treturn constraintOps[c.origfunc](v, c, includePre)\n}\n\n// String prints an individual constraint into a string\nfunc (c *constraint) string() string {\n\treturn c.origfunc + c.orig\n}\n\ntype cfunc func(v *Version, c *constraint, includePre bool) (bool, error)\n\nfunc parseConstraint(c string) (*constraint, error) {\n\tif len(c) > 0 {\n\t\tm := constraintRegex.FindStringSubmatch(c)\n\t\tif m == nil {\n\t\t\treturn nil, fmt.Errorf(\"improper constraint: %s\", c)\n\t\t}\n\n\t\tcs := &constraint{\n\t\t\torig:     m[2],\n\t\t\torigfunc: m[1],\n\t\t}\n\n\t\tver := m[2]\n\t\tminorDirty := false\n\t\tpatchDirty := false\n\t\tdirty := false\n\t\tif isX(m[3]) || m[3] == \"\" {\n\t\t\tver = fmt.Sprintf(\"0.0.0%s\", m[6])\n\t\t\tdirty = true\n\t\t} else if isX(strings.TrimPrefix(m[4], \".\")) || m[4] == \"\" {\n\t\t\tminorDirty = true\n\t\t\tdirty = true\n\t\t\tver = fmt.Sprintf(\"%s.0.0%s\", m[3], m[6])\n\t\t} else if isX(strings.TrimPrefix(m[5], \".\")) || m[5] == \"\" {\n\t\t\tdirty = true\n\t\t\tpatchDirty = true\n\t\t\tver = fmt.Sprintf(\"%s%s.0%s\", m[3], m[4], m[6])\n\t\t}\n\n\t\tcon, err := NewVersion(ver)\n\t\tif err != nil {\n\n\t\t\t// The constraintRegex should catch any regex parsing errors. So,\n\t\t\t// we should never get here.\n\t\t\treturn nil, errors.New(\"constraint parser error\")\n\t\t}\n\n\t\tcs.con = con\n\t\tcs.minorDirty = minorDirty\n\t\tcs.patchDirty = patchDirty\n\t\tcs.dirty = dirty\n\n\t\treturn cs, nil\n\t}\n\n\t// The rest is the special case where an empty string was passed in which\n\t// is equivalent to * or >=0.0.0\n\tcon, err := StrictNewVersion(\"0.0.0\")\n\tif err != nil {\n\n\t\t// The constraintRegex should catch any regex parsing errors. So,\n\t\t// we should never get here.\n\t\treturn nil, errors.New(\"constraint parser error\")\n\t}\n\n\tcs := &constraint{\n\t\tcon:        con,\n\t\torig:       c,\n\t\torigfunc:   \"\",\n\t\tminorDirty: false,\n\t\tpatchDirty: false,\n\t\tdirty:      true,\n\t}\n\treturn cs, nil\n}\n\n// Constraint functions\nfunc constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error) {\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\tif c.dirty {\n\t\tif c.con.Major() != v.Major() {\n\t\t\treturn true, nil\n\t\t}\n\t\tif c.con.Minor() != v.Minor() && !c.minorDirty {\n\t\t\treturn true, nil\n\t\t} else if c.minorDirty {\n\t\t\treturn false, fmt.Errorf(\"%s is equal to %s\", v, c.orig)\n\t\t} else if c.con.Patch() != v.Patch() && !c.patchDirty {\n\t\t\treturn true, nil\n\t\t} else if c.patchDirty {\n\t\t\t// Need to handle prereleases if present\n\t\t\tif v.Prerelease() != \"\" || c.con.Prerelease() != \"\" {\n\t\t\t\teq := comparePrerelease(v.Prerelease(), c.con.Prerelease()) != 0\n\t\t\t\tif eq {\n\t\t\t\t\treturn true, nil\n\t\t\t\t}\n\t\t\t\treturn false, fmt.Errorf(\"%s is equal to %s\", v, c.orig)\n\t\t\t}\n\t\t\treturn false, fmt.Errorf(\"%s is equal to %s\", v, c.orig)\n\t\t}\n\t}\n\n\teq := v.Equal(c.con)\n\tif eq {\n\t\treturn false, fmt.Errorf(\"%s is equal to %s\", v, c.orig)\n\t}\n\n\treturn true, nil\n}\n\nfunc constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, error) {\n\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\tvar eq bool\n\n\tif !c.dirty {\n\t\teq = v.Compare(c.con) == 1\n\t\tif eq {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, fmt.Errorf(\"%s is less than or equal to %s\", v, c.orig)\n\t}\n\n\tif v.Major() > c.con.Major() {\n\t\treturn true, nil\n\t} else if v.Major() < c.con.Major() {\n\t\treturn false, fmt.Errorf(\"%s is less than or equal to %s\", v, c.orig)\n\t} else if c.minorDirty {\n\t\t// This is a range case such as >11. When the version is something like\n\t\t// 11.1.0 is it not > 11. For that we would need 12 or higher\n\t\treturn false, fmt.Errorf(\"%s is less than or equal to %s\", v, c.orig)\n\t} else if c.patchDirty {\n\t\t// This is for ranges such as >11.1. A version of 11.1.1 is not greater\n\t\t// which one of 11.2.1 is greater\n\t\teq = v.Minor() > c.con.Minor()\n\t\tif eq {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, fmt.Errorf(\"%s is less than or equal to %s\", v, c.orig)\n\t}\n\n\t// If we have gotten here we are not comparing pre-preleases and can use the\n\t// Compare function to accomplish that.\n\teq = v.Compare(c.con) == 1\n\tif eq {\n\t\treturn true, nil\n\t}\n\treturn false, fmt.Errorf(\"%s is less than or equal to %s\", v, c.orig)\n}\n\nfunc constraintLessThan(v *Version, c *constraint, includePre bool) (bool, error) {\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\teq := v.Compare(c.con) < 0\n\tif eq {\n\t\treturn true, nil\n\t}\n\treturn false, fmt.Errorf(\"%s is greater than or equal to %s\", v, c.orig)\n}\n\nfunc constraintGreaterThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {\n\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\teq := v.Compare(c.con) >= 0\n\tif eq {\n\t\treturn true, nil\n\t}\n\treturn false, fmt.Errorf(\"%s is less than %s\", v, c.orig)\n}\n\nfunc constraintLessThanEqual(v *Version, c *constraint, includePre bool) (bool, error) {\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\tvar eq bool\n\n\tif !c.dirty {\n\t\teq = v.Compare(c.con) <= 0\n\t\tif eq {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, fmt.Errorf(\"%s is greater than %s\", v, c.orig)\n\t}\n\n\tif v.Major() > c.con.Major() {\n\t\treturn false, fmt.Errorf(\"%s is greater than %s\", v, c.orig)\n\t} else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty {\n\t\treturn false, fmt.Errorf(\"%s is greater than %s\", v, c.orig)\n\t}\n\n\treturn true, nil\n}\n\n// ~*, ~>* --> >= 0.0.0 (any)\n// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0\n// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0\n// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0\n// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0\n// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0\nfunc constraintTilde(v *Version, c *constraint, includePre bool) (bool, error) {\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\tif v.LessThan(c.con) {\n\t\treturn false, fmt.Errorf(\"%s is less than %s\", v, c.orig)\n\t}\n\n\t// ~0.0.0 is a special case where all constraints are accepted. It's\n\t// equivalent to >= 0.0.0.\n\tif c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&\n\t\t!c.minorDirty && !c.patchDirty {\n\t\treturn true, nil\n\t}\n\n\tif v.Major() != c.con.Major() {\n\t\treturn false, fmt.Errorf(\"%s does not have same major version as %s\", v, c.orig)\n\t}\n\n\tif v.Minor() != c.con.Minor() && !c.minorDirty {\n\t\treturn false, fmt.Errorf(\"%s does not have same major and minor version as %s\", v, c.orig)\n\t}\n\n\treturn true, nil\n}\n\n// When there is a .x (dirty) status it automatically opts in to ~. Otherwise\n// it's a straight =\nfunc constraintTildeOrEqual(v *Version, c *constraint, includePre bool) (bool, error) {\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\tif c.dirty {\n\t\treturn constraintTilde(v, c, includePre)\n\t}\n\n\teq := v.Equal(c.con)\n\tif eq {\n\t\treturn true, nil\n\t}\n\n\treturn false, fmt.Errorf(\"%s is not equal to %s\", v, c.orig)\n}\n\n// ^*      -->  (any)\n// ^1.2.3  -->  >=1.2.3 <2.0.0\n// ^1.2    -->  >=1.2.0 <2.0.0\n// ^1      -->  >=1.0.0 <2.0.0\n// ^0.2.3  -->  >=0.2.3 <0.3.0\n// ^0.2    -->  >=0.2.0 <0.3.0\n// ^0.0.3  -->  >=0.0.3 <0.0.4\n// ^0.0    -->  >=0.0.0 <0.1.0\n// ^0      -->  >=0.0.0 <1.0.0\nfunc constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) {\n\t// The existence of prereleases is checked at the group level and passed in.\n\t// Exit early if the version has a prerelease but those are to be ignored.\n\tif v.Prerelease() != \"\" && !includePre {\n\t\treturn false, fmt.Errorf(\"%s is a prerelease version and the constraint is only looking for release versions\", v)\n\t}\n\n\t// This less than handles prereleases\n\tif v.LessThan(c.con) {\n\t\treturn false, fmt.Errorf(\"%s is less than %s\", v, c.orig)\n\t}\n\n\tvar eq bool\n\n\t// ^ when the major > 0 is >=x.y.z < x+1\n\tif c.con.Major() > 0 || c.minorDirty {\n\n\t\t// ^ has to be within a major range for > 0. Everything less than was\n\t\t// filtered out with the LessThan call above. This filters out those\n\t\t// that greater but not within the same major range.\n\t\teq = v.Major() == c.con.Major()\n\t\tif eq {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, fmt.Errorf(\"%s does not have same major version as %s\", v, c.orig)\n\t}\n\n\t// ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1\n\tif c.con.Major() == 0 && v.Major() > 0 {\n\t\treturn false, fmt.Errorf(\"%s does not have same major version as %s\", v, c.orig)\n\t}\n\t// If the con Minor is > 0 it is not dirty\n\tif c.con.Minor() > 0 || c.patchDirty {\n\t\teq = v.Minor() == c.con.Minor()\n\t\tif eq {\n\t\t\treturn true, nil\n\t\t}\n\t\treturn false, fmt.Errorf(\"%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0\", v, c.orig)\n\t}\n\t// ^ when the minor is 0 and minor > 0 is =0.0.z\n\tif c.con.Minor() == 0 && v.Minor() > 0 {\n\t\treturn false, fmt.Errorf(\"%s does not have same minor version as %s\", v, c.orig)\n\t}\n\n\t// At this point the major is 0 and the minor is 0 and not dirty. The patch\n\t// is not dirty so we need to check if they are equal. If they are not equal\n\teq = c.con.Patch() == v.Patch()\n\tif eq {\n\t\treturn true, nil\n\t}\n\treturn false, fmt.Errorf(\"%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0\", v, c.orig)\n}\n\nfunc isX(x string) bool {\n\tswitch x {\n\tcase \"x\", \"*\", \"X\":\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc rewriteRange(i string) string {\n\tm := constraintRangeRegex.FindAllStringSubmatch(i, -1)\n\tif m == nil {\n\t\treturn i\n\t}\n\to := i\n\tfor _, v := range m {\n\t\tt := fmt.Sprintf(\">= %s, <= %s \", v[1], v[11])\n\t\to = strings.Replace(o, v[0], t, 1)\n\t}\n\n\treturn o\n}\n"
  },
  {
    "path": "vendor/github.com/Masterminds/semver/v3/doc.go",
    "content": "/*\nPackage semver provides the ability to work with Semantic Versions (http://semver.org) in Go.\n\nSpecifically it provides the ability to:\n\n  - Parse semantic versions\n  - Sort semantic versions\n  - Check if a semantic version fits within a set of constraints\n  - Optionally work with a `v` prefix\n\n# Parsing Semantic Versions\n\nThere are two functions that can parse semantic versions. The `StrictNewVersion`\nfunction only parses valid version 2 semantic versions as outlined in the\nspecification. The `NewVersion` function attempts to coerce a version into a\nsemantic version and parse it. For example, if there is a leading v or a version\nlisted without all 3 parts (e.g. 1.2) it will attempt to coerce it into a valid\nsemantic version (e.g., 1.2.0). In both cases a `Version` object is returned\nthat can be sorted, compared, and used in constraints.\n\nWhen parsing a version an optional error can be returned if there is an issue\nparsing the version. For example,\n\n\tv, err := semver.NewVersion(\"1.2.3-beta.1+b345\")\n\nThe version object has methods to get the parts of the version, compare it to\nother versions, convert the version back into a string, and get the original\nstring. For more details please see the documentation\nat https://godoc.org/github.com/Masterminds/semver.\n\n# Sorting Semantic Versions\n\nA set of versions can be sorted using the `sort` package from the standard library.\nFor example,\n\n\t    raw := []string{\"1.2.3\", \"1.0\", \"1.3\", \"2\", \"0.4.2\",}\n\t    vs := make([]*semver.Version, len(raw))\n\t\tfor i, r := range raw {\n\t\t\tv, err := semver.NewVersion(r)\n\t\t\tif err != nil {\n\t\t\t\tt.Errorf(\"Error parsing version: %s\", err)\n\t\t\t}\n\n\t\t\tvs[i] = v\n\t\t}\n\n\t\tsort.Sort(semver.Collection(vs))\n\n# Checking Version Constraints and Comparing Versions\n\nThere are two methods for comparing versions. One uses comparison methods on\n`Version` instances and the other is using Constraints. There are some important\ndifferences to notes between these two methods of comparison.\n\n 1. When two versions are compared using functions such as `Compare`, `LessThan`,\n    and others it will follow the specification and always include prereleases\n    within the comparison. It will provide an answer valid with the comparison\n    spec section at https://semver.org/#spec-item-11\n 2. When constraint checking is used for checks or validation it will follow a\n    different set of rules that are common for ranges with tools like npm/js\n    and Rust/Cargo. This includes considering prereleases to be invalid if the\n    ranges does not include on. If you want to have it include pre-releases a\n    simple solution is to include `-0` in your range.\n 3. Constraint ranges can have some complex rules including the shorthard use of\n    ~ and ^. For more details on those see the options below.\n\nThere are differences between the two methods or checking versions because the\ncomparison methods on `Version` follow the specification while comparison ranges\nare not part of the specification. Different packages and tools have taken it\nupon themselves to come up with range rules. This has resulted in differences.\nFor example, npm/js and Cargo/Rust follow similar patterns which PHP has a\ndifferent pattern for ^. The comparison features in this package follow the\nnpm/js and Cargo/Rust lead because applications using it have followed similar\npatters with their versions.\n\nChecking a version against version constraints is one of the most featureful\nparts of the package.\n\n\tc, err := semver.NewConstraint(\">= 1.2.3\")\n\tif err != nil {\n\t    // Handle constraint not being parsable.\n\t}\n\n\tv, err := semver.NewVersion(\"1.3\")\n\tif err != nil {\n\t    // Handle version not being parsable.\n\t}\n\t// Check if the version meets the constraints. The a variable will be true.\n\ta := c.Check(v)\n\n# Basic Comparisons\n\nThere are two elements to the comparisons. First, a comparison string is a list\nof comma or space separated AND comparisons. These are then separated by || (OR)\ncomparisons. For example, `\">= 1.2 < 3.0.0 || >= 4.2.3\"` is looking for a\ncomparison that's greater than or equal to 1.2 and less than 3.0.0 or is\ngreater than or equal to 4.2.3. This can also be written as\n`\">= 1.2, < 3.0.0 || >= 4.2.3\"`\n\nThe basic comparisons are:\n\n  - `=`: equal (aliased to no operator)\n  - `!=`: not equal\n  - `>`: greater than\n  - `<`: less than\n  - `>=`: greater than or equal to\n  - `<=`: less than or equal to\n\n# Hyphen Range Comparisons\n\nThere are multiple methods to handle ranges and the first is hyphens ranges.\nThese look like:\n\n  - `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`\n  - `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5`\n\n# Wildcards In Comparisons\n\nThe `x`, `X`, and `*` characters can be used as a wildcard character. This works\nfor all comparison operators. When used on the `=` operator it falls\nback to the tilde operation. For example,\n\n  - `1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`\n  - `>= 1.2.x` is equivalent to `>= 1.2.0`\n  - `<= 2.x` is equivalent to `<= 3`\n  - `*` is equivalent to `>= 0.0.0`\n\nTilde Range Comparisons (Patch)\n\nThe tilde (`~`) comparison operator is for patch level ranges when a minor\nversion is specified and major level changes when the minor number is missing.\nFor example,\n\n  - `~1.2.3` is equivalent to `>= 1.2.3 < 1.3.0`\n  - `~1` is equivalent to `>= 1, < 2`\n  - `~2.3` is equivalent to `>= 2.3 < 2.4`\n  - `~1.2.x` is equivalent to `>= 1.2.0 < 1.3.0`\n  - `~1.x` is equivalent to `>= 1 < 2`\n\nCaret Range Comparisons (Major)\n\nThe caret (`^`) comparison operator is for major level changes once a stable\n(1.0.0) release has occurred. Prior to a 1.0.0 release the minor versions acts\nas the API stability level. This is useful when comparisons of API versions as a\nmajor change is API breaking. For example,\n\n  - `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`\n  - `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`\n  - `^2.3` is equivalent to `>= 2.3, < 3`\n  - `^2.x` is equivalent to `>= 2.0.0, < 3`\n  - `^0.2.3` is equivalent to `>=0.2.3 <0.3.0`\n  - `^0.2` is equivalent to `>=0.2.0 <0.3.0`\n  - `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`\n  - `^0.0` is equivalent to `>=0.0.0 <0.1.0`\n  - `^0` is equivalent to `>=0.0.0 <1.0.0`\n\n# Validation\n\nIn addition to testing a version against a constraint, a version can be validated\nagainst a constraint. When validation fails a slice of errors containing why a\nversion didn't meet the constraint is returned. For example,\n\n\tc, err := semver.NewConstraint(\"<= 1.2.3, >= 1.4\")\n\tif err != nil {\n\t    // Handle constraint not being parseable.\n\t}\n\n\tv, _ := semver.NewVersion(\"1.3\")\n\tif err != nil {\n\t    // Handle version not being parseable.\n\t}\n\n\t// Validate a version against a constraint.\n\ta, msgs := c.Validate(v)\n\t// a is false\n\tfor _, m := range msgs {\n\t    fmt.Println(m)\n\n\t    // Loops over the errors which would read\n\t    // \"1.3 is greater than 1.2.3\"\n\t    // \"1.3 is less than 1.4\"\n\t}\n*/\npackage semver\n"
  },
  {
    "path": "vendor/github.com/Masterminds/semver/v3/version.go",
    "content": "package semver\n\nimport (\n\t\"bytes\"\n\t\"database/sql/driver\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// The compiled version of the regex created at init() is cached here so it\n// only needs to be created once.\nvar versionRegex *regexp.Regexp\nvar looseVersionRegex *regexp.Regexp\n\n// CoerceNewVersion sets if leading 0's are allowd in the version part. Leading 0's are\n// not allowed in a valid semantic version. When set to true, NewVersion will coerce\n// leading 0's into a valid version.\nvar CoerceNewVersion = true\n\n// DetailedNewVersionErrors specifies if detailed errors are returned from the NewVersion\n// function. This is used when CoerceNewVersion is set to false. If set to false\n// ErrInvalidSemVer is returned for an invalid version. This does not apply to\n// StrictNewVersion. Setting this function to false returns errors more quickly.\nvar DetailedNewVersionErrors = true\n\nvar (\n\t// ErrInvalidSemVer is returned a version is found to be invalid when\n\t// being parsed.\n\tErrInvalidSemVer = errors.New(\"invalid semantic version\")\n\n\t// ErrEmptyString is returned when an empty string is passed in for parsing.\n\tErrEmptyString = errors.New(\"version string empty\")\n\n\t// ErrInvalidCharacters is returned when invalid characters are found as\n\t// part of a version\n\tErrInvalidCharacters = errors.New(\"invalid characters in version\")\n\n\t// ErrSegmentStartsZero is returned when a version segment starts with 0.\n\t// This is invalid in SemVer.\n\tErrSegmentStartsZero = errors.New(\"version segment starts with 0\")\n\n\t// ErrInvalidMetadata is returned when the metadata is an invalid format\n\tErrInvalidMetadata = errors.New(\"invalid metadata string\")\n\n\t// ErrInvalidPrerelease is returned when the pre-release is an invalid format\n\tErrInvalidPrerelease = errors.New(\"invalid prerelease string\")\n)\n\n// semVerRegex is the regular expression used to parse a semantic version.\n// This is not the official regex from the semver spec. It has been modified to allow for loose handling\n// where versions like 2.1 are detected.\nconst semVerRegex string = `v?(0|[1-9]\\d*)(?:\\.(0|[1-9]\\d*))?(?:\\.(0|[1-9]\\d*))?` +\n\t`(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?` +\n\t`(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?`\n\n// looseSemVerRegex is a regular expression that lets invalid semver expressions through\n// with enough detail that certain errors can be checked for.\nconst looseSemVerRegex string = `v?([0-9]+)(\\.[0-9]+)?(\\.[0-9]+)?` +\n\t`(-([0-9A-Za-z\\-]+(\\.[0-9A-Za-z\\-]+)*))?` +\n\t`(\\+([0-9A-Za-z\\-]+(\\.[0-9A-Za-z\\-]+)*))?`\n\n// Version represents a single semantic version.\ntype Version struct {\n\tmajor, minor, patch uint64\n\tpre                 string\n\tmetadata            string\n\toriginal            string\n}\n\nfunc init() {\n\tversionRegex = regexp.MustCompile(\"^\" + semVerRegex + \"$\")\n\tlooseVersionRegex = regexp.MustCompile(\"^\" + looseSemVerRegex + \"$\")\n}\n\nconst (\n\tnum     string = \"0123456789\"\n\tallowed string = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-\" + num\n)\n\n// StrictNewVersion parses a given version and returns an instance of Version or\n// an error if unable to parse the version. Only parses valid semantic versions.\n// Performs checking that can find errors within the version.\n// If you want to coerce a version such as 1 or 1.2 and parse it as the 1.x\n// releases of semver did, use the NewVersion() function.\nfunc StrictNewVersion(v string) (*Version, error) {\n\t// Parsing here does not use RegEx in order to increase performance and reduce\n\t// allocations.\n\n\tif len(v) == 0 {\n\t\treturn nil, ErrEmptyString\n\t}\n\n\t// Split the parts into [0]major, [1]minor, and [2]patch,prerelease,build\n\tparts := strings.SplitN(v, \".\", 3)\n\tif len(parts) != 3 {\n\t\treturn nil, ErrInvalidSemVer\n\t}\n\n\tsv := &Version{\n\t\toriginal: v,\n\t}\n\n\t// Extract build metadata\n\tif strings.Contains(parts[2], \"+\") {\n\t\textra := strings.SplitN(parts[2], \"+\", 2)\n\t\tsv.metadata = extra[1]\n\t\tparts[2] = extra[0]\n\t\tif err := validateMetadata(sv.metadata); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Extract build prerelease\n\tif strings.Contains(parts[2], \"-\") {\n\t\textra := strings.SplitN(parts[2], \"-\", 2)\n\t\tsv.pre = extra[1]\n\t\tparts[2] = extra[0]\n\t\tif err := validatePrerelease(sv.pre); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\t// Validate the number segments are valid. This includes only having positive\n\t// numbers and no leading 0's.\n\tfor _, p := range parts {\n\t\tif !containsOnly(p, num) {\n\t\t\treturn nil, ErrInvalidCharacters\n\t\t}\n\n\t\tif len(p) > 1 && p[0] == '0' {\n\t\t\treturn nil, ErrSegmentStartsZero\n\t\t}\n\t}\n\n\t// Extract major, minor, and patch\n\tvar err error\n\tsv.major, err = strconv.ParseUint(parts[0], 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsv.minor, err = strconv.ParseUint(parts[1], 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tsv.patch, err = strconv.ParseUint(parts[2], 10, 64)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn sv, nil\n}\n\n// NewVersion parses a given version and returns an instance of Version or\n// an error if unable to parse the version. If the version is SemVer-ish it\n// attempts to convert it to SemVer. If you want  to validate it was a strict\n// semantic version at parse time see StrictNewVersion().\nfunc NewVersion(v string) (*Version, error) {\n\tif CoerceNewVersion {\n\t\treturn coerceNewVersion(v)\n\t}\n\tm := versionRegex.FindStringSubmatch(v)\n\tif m == nil {\n\n\t\t// Disabling detailed errors is first so that it is in the fast path.\n\t\tif !DetailedNewVersionErrors {\n\t\t\treturn nil, ErrInvalidSemVer\n\t\t}\n\n\t\t// Check for specific errors with the semver string and return a more detailed\n\t\t// error.\n\t\tm = looseVersionRegex.FindStringSubmatch(v)\n\t\tif m == nil {\n\t\t\treturn nil, ErrInvalidSemVer\n\t\t}\n\t\terr := validateVersion(m)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, ErrInvalidSemVer\n\t}\n\n\tsv := &Version{\n\t\tmetadata: m[5],\n\t\tpre:      m[4],\n\t\toriginal: v,\n\t}\n\n\tvar err error\n\tsv.major, err = strconv.ParseUint(m[1], 10, 64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing version segment: %w\", err)\n\t}\n\n\tif m[2] != \"\" {\n\t\tsv.minor, err = strconv.ParseUint(m[2], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing version segment: %w\", err)\n\t\t}\n\t} else {\n\t\tsv.minor = 0\n\t}\n\n\tif m[3] != \"\" {\n\t\tsv.patch, err = strconv.ParseUint(m[3], 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing version segment: %w\", err)\n\t\t}\n\t} else {\n\t\tsv.patch = 0\n\t}\n\n\t// Perform some basic due diligence on the extra parts to ensure they are\n\t// valid.\n\n\tif sv.pre != \"\" {\n\t\tif err = validatePrerelease(sv.pre); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif sv.metadata != \"\" {\n\t\tif err = validateMetadata(sv.metadata); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn sv, nil\n}\n\nfunc coerceNewVersion(v string) (*Version, error) {\n\tm := looseVersionRegex.FindStringSubmatch(v)\n\tif m == nil {\n\t\treturn nil, ErrInvalidSemVer\n\t}\n\n\tsv := &Version{\n\t\tmetadata: m[8],\n\t\tpre:      m[5],\n\t\toriginal: v,\n\t}\n\n\tvar err error\n\tsv.major, err = strconv.ParseUint(m[1], 10, 64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing version segment: %w\", err)\n\t}\n\n\tif m[2] != \"\" {\n\t\tsv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], \".\"), 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing version segment: %w\", err)\n\t\t}\n\t} else {\n\t\tsv.minor = 0\n\t}\n\n\tif m[3] != \"\" {\n\t\tsv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], \".\"), 10, 64)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error parsing version segment: %w\", err)\n\t\t}\n\t} else {\n\t\tsv.patch = 0\n\t}\n\n\t// Perform some basic due diligence on the extra parts to ensure they are\n\t// valid.\n\n\tif sv.pre != \"\" {\n\t\tif err = validatePrerelease(sv.pre); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif sv.metadata != \"\" {\n\t\tif err = validateMetadata(sv.metadata); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn sv, nil\n}\n\n// New creates a new instance of Version with each of the parts passed in as\n// arguments instead of parsing a version string.\nfunc New(major, minor, patch uint64, pre, metadata string) *Version {\n\tv := Version{\n\t\tmajor:    major,\n\t\tminor:    minor,\n\t\tpatch:    patch,\n\t\tpre:      pre,\n\t\tmetadata: metadata,\n\t\toriginal: \"\",\n\t}\n\n\tv.original = v.String()\n\n\treturn &v\n}\n\n// MustParse parses a given version and panics on error.\nfunc MustParse(v string) *Version {\n\tsv, err := NewVersion(v)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn sv\n}\n\n// String converts a Version object to a string.\n// Note, if the original version contained a leading v this version will not.\n// See the Original() method to retrieve the original value. Semantic Versions\n// don't contain a leading v per the spec. Instead it's optional on\n// implementation.\nfunc (v Version) String() string {\n\tvar buf bytes.Buffer\n\n\tfmt.Fprintf(&buf, \"%d.%d.%d\", v.major, v.minor, v.patch)\n\tif v.pre != \"\" {\n\t\tfmt.Fprintf(&buf, \"-%s\", v.pre)\n\t}\n\tif v.metadata != \"\" {\n\t\tfmt.Fprintf(&buf, \"+%s\", v.metadata)\n\t}\n\n\treturn buf.String()\n}\n\n// Original returns the original value passed in to be parsed.\nfunc (v *Version) Original() string {\n\treturn v.original\n}\n\n// Major returns the major version.\nfunc (v Version) Major() uint64 {\n\treturn v.major\n}\n\n// Minor returns the minor version.\nfunc (v Version) Minor() uint64 {\n\treturn v.minor\n}\n\n// Patch returns the patch version.\nfunc (v Version) Patch() uint64 {\n\treturn v.patch\n}\n\n// Prerelease returns the pre-release version.\nfunc (v Version) Prerelease() string {\n\treturn v.pre\n}\n\n// Metadata returns the metadata on the version.\nfunc (v Version) Metadata() string {\n\treturn v.metadata\n}\n\n// originalVPrefix returns the original 'v' prefix if any.\nfunc (v Version) originalVPrefix() string {\n\t// Note, only lowercase v is supported as a prefix by the parser.\n\tif v.original != \"\" && v.original[:1] == \"v\" {\n\t\treturn v.original[:1]\n\t}\n\treturn \"\"\n}\n\n// IncPatch produces the next patch version.\n// If the current version does not have prerelease/metadata information,\n// it unsets metadata and prerelease values, increments patch number.\n// If the current version has any of prerelease or metadata information,\n// it unsets both values and keeps current patch value\nfunc (v Version) IncPatch() Version {\n\tvNext := v\n\t// according to http://semver.org/#spec-item-9\n\t// Pre-release versions have a lower precedence than the associated normal version.\n\t// according to http://semver.org/#spec-item-10\n\t// Build metadata SHOULD be ignored when determining version precedence.\n\tif v.pre != \"\" {\n\t\tvNext.metadata = \"\"\n\t\tvNext.pre = \"\"\n\t} else {\n\t\tvNext.metadata = \"\"\n\t\tvNext.pre = \"\"\n\t\tvNext.patch = v.patch + 1\n\t}\n\tvNext.original = v.originalVPrefix() + \"\" + vNext.String()\n\treturn vNext\n}\n\n// IncMinor produces the next minor version.\n// Sets patch to 0.\n// Increments minor number.\n// Unsets metadata.\n// Unsets prerelease status.\nfunc (v Version) IncMinor() Version {\n\tvNext := v\n\tvNext.metadata = \"\"\n\tvNext.pre = \"\"\n\tvNext.patch = 0\n\tvNext.minor = v.minor + 1\n\tvNext.original = v.originalVPrefix() + \"\" + vNext.String()\n\treturn vNext\n}\n\n// IncMajor produces the next major version.\n// Sets patch to 0.\n// Sets minor to 0.\n// Increments major number.\n// Unsets metadata.\n// Unsets prerelease status.\nfunc (v Version) IncMajor() Version {\n\tvNext := v\n\tvNext.metadata = \"\"\n\tvNext.pre = \"\"\n\tvNext.patch = 0\n\tvNext.minor = 0\n\tvNext.major = v.major + 1\n\tvNext.original = v.originalVPrefix() + \"\" + vNext.String()\n\treturn vNext\n}\n\n// SetPrerelease defines the prerelease value.\n// Value must not include the required 'hyphen' prefix.\nfunc (v Version) SetPrerelease(prerelease string) (Version, error) {\n\tvNext := v\n\tif len(prerelease) > 0 {\n\t\tif err := validatePrerelease(prerelease); err != nil {\n\t\t\treturn vNext, err\n\t\t}\n\t}\n\tvNext.pre = prerelease\n\tvNext.original = v.originalVPrefix() + \"\" + vNext.String()\n\treturn vNext, nil\n}\n\n// SetMetadata defines metadata value.\n// Value must not include the required 'plus' prefix.\nfunc (v Version) SetMetadata(metadata string) (Version, error) {\n\tvNext := v\n\tif len(metadata) > 0 {\n\t\tif err := validateMetadata(metadata); err != nil {\n\t\t\treturn vNext, err\n\t\t}\n\t}\n\tvNext.metadata = metadata\n\tvNext.original = v.originalVPrefix() + \"\" + vNext.String()\n\treturn vNext, nil\n}\n\n// LessThan tests if one version is less than another one.\nfunc (v *Version) LessThan(o *Version) bool {\n\treturn v.Compare(o) < 0\n}\n\n// LessThanEqual tests if one version is less or equal than another one.\nfunc (v *Version) LessThanEqual(o *Version) bool {\n\treturn v.Compare(o) <= 0\n}\n\n// GreaterThan tests if one version is greater than another one.\nfunc (v *Version) GreaterThan(o *Version) bool {\n\treturn v.Compare(o) > 0\n}\n\n// GreaterThanEqual tests if one version is greater or equal than another one.\nfunc (v *Version) GreaterThanEqual(o *Version) bool {\n\treturn v.Compare(o) >= 0\n}\n\n// Equal tests if two versions are equal to each other.\n// Note, versions can be equal with different metadata since metadata\n// is not considered part of the comparable version.\nfunc (v *Version) Equal(o *Version) bool {\n\tif v == o {\n\t\treturn true\n\t}\n\tif v == nil || o == nil {\n\t\treturn false\n\t}\n\treturn v.Compare(o) == 0\n}\n\n// Compare compares this version to another one. It returns -1, 0, or 1 if\n// the version smaller, equal, or larger than the other version.\n//\n// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is\n// lower than the version without a prerelease. Compare always takes into account\n// prereleases. If you want to work with ranges using typical range syntaxes that\n// skip prereleases if the range is not looking for them use constraints.\nfunc (v *Version) Compare(o *Version) int {\n\t// Compare the major, minor, and patch version for differences. If a\n\t// difference is found return the comparison.\n\tif d := compareSegment(v.Major(), o.Major()); d != 0 {\n\t\treturn d\n\t}\n\tif d := compareSegment(v.Minor(), o.Minor()); d != 0 {\n\t\treturn d\n\t}\n\tif d := compareSegment(v.Patch(), o.Patch()); d != 0 {\n\t\treturn d\n\t}\n\n\t// At this point the major, minor, and patch versions are the same.\n\tps := v.pre\n\tpo := o.Prerelease()\n\n\tif ps == \"\" && po == \"\" {\n\t\treturn 0\n\t}\n\tif ps == \"\" {\n\t\treturn 1\n\t}\n\tif po == \"\" {\n\t\treturn -1\n\t}\n\n\treturn comparePrerelease(ps, po)\n}\n\n// UnmarshalJSON implements JSON.Unmarshaler interface.\nfunc (v *Version) UnmarshalJSON(b []byte) error {\n\tvar s string\n\tif err := json.Unmarshal(b, &s); err != nil {\n\t\treturn err\n\t}\n\ttemp, err := NewVersion(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\tv.major = temp.major\n\tv.minor = temp.minor\n\tv.patch = temp.patch\n\tv.pre = temp.pre\n\tv.metadata = temp.metadata\n\tv.original = temp.original\n\treturn nil\n}\n\n// MarshalJSON implements JSON.Marshaler interface.\nfunc (v Version) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(v.String())\n}\n\n// UnmarshalText implements the encoding.TextUnmarshaler interface.\nfunc (v *Version) UnmarshalText(text []byte) error {\n\ttemp, err := NewVersion(string(text))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*v = *temp\n\n\treturn nil\n}\n\n// MarshalText implements the encoding.TextMarshaler interface.\nfunc (v Version) MarshalText() ([]byte, error) {\n\treturn []byte(v.String()), nil\n}\n\n// Scan implements the SQL.Scanner interface.\nfunc (v *Version) Scan(value interface{}) error {\n\tvar s string\n\ts, _ = value.(string)\n\ttemp, err := NewVersion(s)\n\tif err != nil {\n\t\treturn err\n\t}\n\tv.major = temp.major\n\tv.minor = temp.minor\n\tv.patch = temp.patch\n\tv.pre = temp.pre\n\tv.metadata = temp.metadata\n\tv.original = temp.original\n\treturn nil\n}\n\n// Value implements the Driver.Valuer interface.\nfunc (v Version) Value() (driver.Value, error) {\n\treturn v.String(), nil\n}\n\nfunc compareSegment(v, o uint64) int {\n\tif v < o {\n\t\treturn -1\n\t}\n\tif v > o {\n\t\treturn 1\n\t}\n\n\treturn 0\n}\n\nfunc comparePrerelease(v, o string) int {\n\t// split the prelease versions by their part. The separator, per the spec,\n\t// is a .\n\tsparts := strings.Split(v, \".\")\n\toparts := strings.Split(o, \".\")\n\n\t// Find the longer length of the parts to know how many loop iterations to\n\t// go through.\n\tslen := len(sparts)\n\tolen := len(oparts)\n\n\tl := slen\n\tif olen > slen {\n\t\tl = olen\n\t}\n\n\t// Iterate over each part of the prereleases to compare the differences.\n\tfor i := 0; i < l; i++ {\n\t\t// Since the lentgh of the parts can be different we need to create\n\t\t// a placeholder. This is to avoid out of bounds issues.\n\t\tstemp := \"\"\n\t\tif i < slen {\n\t\t\tstemp = sparts[i]\n\t\t}\n\n\t\totemp := \"\"\n\t\tif i < olen {\n\t\t\totemp = oparts[i]\n\t\t}\n\n\t\td := comparePrePart(stemp, otemp)\n\t\tif d != 0 {\n\t\t\treturn d\n\t\t}\n\t}\n\n\t// Reaching here means two versions are of equal value but have different\n\t// metadata (the part following a +). They are not identical in string form\n\t// but the version comparison finds them to be equal.\n\treturn 0\n}\n\nfunc comparePrePart(s, o string) int {\n\t// Fastpath if they are equal\n\tif s == o {\n\t\treturn 0\n\t}\n\n\t// When s or o are empty we can use the other in an attempt to determine\n\t// the response.\n\tif s == \"\" {\n\t\tif o != \"\" {\n\t\t\treturn -1\n\t\t}\n\t\treturn 1\n\t}\n\n\tif o == \"\" {\n\t\tif s != \"\" {\n\t\t\treturn 1\n\t\t}\n\t\treturn -1\n\t}\n\n\t// When comparing strings \"99\" is greater than \"103\". To handle\n\t// cases like this we need to detect numbers and compare them. According\n\t// to the semver spec, numbers are always positive. If there is a - at the\n\t// start like -99 this is to be evaluated as an alphanum. numbers always\n\t// have precedence over alphanum. Parsing as Uints because negative numbers\n\t// are ignored.\n\n\toi, n1 := strconv.ParseUint(o, 10, 64)\n\tsi, n2 := strconv.ParseUint(s, 10, 64)\n\n\t// The case where both are strings compare the strings\n\tif n1 != nil && n2 != nil {\n\t\tif s > o {\n\t\t\treturn 1\n\t\t}\n\t\treturn -1\n\t} else if n1 != nil {\n\t\t// o is a string and s is a number\n\t\treturn -1\n\t} else if n2 != nil {\n\t\t// s is a string and o is a number\n\t\treturn 1\n\t}\n\t// Both are numbers\n\tif si > oi {\n\t\treturn 1\n\t}\n\treturn -1\n}\n\n// Like strings.ContainsAny but does an only instead of any.\nfunc containsOnly(s string, comp string) bool {\n\treturn strings.IndexFunc(s, func(r rune) bool {\n\t\treturn !strings.ContainsRune(comp, r)\n\t}) == -1\n}\n\n// From the spec, \"Identifiers MUST comprise only\n// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.\n// Numeric identifiers MUST NOT include leading zeroes.\". These segments can\n// be dot separated.\nfunc validatePrerelease(p string) error {\n\teparts := strings.Split(p, \".\")\n\tfor _, p := range eparts {\n\t\tif p == \"\" {\n\t\t\treturn ErrInvalidPrerelease\n\t\t} else if containsOnly(p, num) {\n\t\t\tif len(p) > 1 && p[0] == '0' {\n\t\t\t\treturn ErrSegmentStartsZero\n\t\t\t}\n\t\t} else if !containsOnly(p, allowed) {\n\t\t\treturn ErrInvalidPrerelease\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// From the spec, \"Build metadata MAY be denoted by\n// appending a plus sign and a series of dot separated identifiers immediately\n// following the patch or pre-release version. Identifiers MUST comprise only\n// ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.\"\nfunc validateMetadata(m string) error {\n\teparts := strings.Split(m, \".\")\n\tfor _, p := range eparts {\n\t\tif p == \"\" {\n\t\t\treturn ErrInvalidMetadata\n\t\t} else if !containsOnly(p, allowed) {\n\t\t\treturn ErrInvalidMetadata\n\t\t}\n\t}\n\treturn nil\n}\n\n// validateVersion checks for common validation issues but may not catch all errors\nfunc validateVersion(m []string) error {\n\tvar err error\n\tvar v string\n\tif m[1] != \"\" {\n\t\tif len(m[1]) > 1 && m[1][0] == '0' {\n\t\t\treturn ErrSegmentStartsZero\n\t\t}\n\t\t_, err = strconv.ParseUint(m[1], 10, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing version segment: %w\", err)\n\t\t}\n\t}\n\n\tif m[2] != \"\" {\n\t\tv = strings.TrimPrefix(m[2], \".\")\n\t\tif len(v) > 1 && v[0] == '0' {\n\t\t\treturn ErrSegmentStartsZero\n\t\t}\n\t\t_, err = strconv.ParseUint(v, 10, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing version segment: %w\", err)\n\t\t}\n\t}\n\n\tif m[3] != \"\" {\n\t\tv = strings.TrimPrefix(m[3], \".\")\n\t\tif len(v) > 1 && v[0] == '0' {\n\t\t\treturn ErrSegmentStartsZero\n\t\t}\n\t\t_, err = strconv.ParseUint(v, 10, 64)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing version segment: %w\", err)\n\t\t}\n\t}\n\n\tif m[5] != \"\" {\n\t\tif err = validatePrerelease(m[5]); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif m[8] != \"\" {\n\t\tif err = validateMetadata(m[8]); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/.gitattributes",
    "content": "testdata/* linguist-vendored\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/LICENSE",
    "content": "Copyright (c) 2012-2021, Martin Angers & Contributors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\n* Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/array.go",
    "content": "package goquery\n\nimport (\n\t\"golang.org/x/net/html\"\n)\n\nconst (\n\tmaxUint = ^uint(0)\n\tmaxInt  = int(maxUint >> 1)\n\n\t// ToEnd is a special index value that can be used as end index in a call\n\t// to Slice so that all elements are selected until the end of the Selection.\n\t// It is equivalent to passing (*Selection).Length().\n\tToEnd = maxInt\n)\n\n// First reduces the set of matched elements to the first in the set.\n// It returns a new Selection object, and an empty Selection object if the\n// the selection is empty.\nfunc (s *Selection) First() *Selection {\n\treturn s.Eq(0)\n}\n\n// Last reduces the set of matched elements to the last in the set.\n// It returns a new Selection object, and an empty Selection object if\n// the selection is empty.\nfunc (s *Selection) Last() *Selection {\n\treturn s.Eq(-1)\n}\n\n// Eq reduces the set of matched elements to the one at the specified index.\n// If a negative index is given, it counts backwards starting at the end of the\n// set. It returns a new Selection object, and an empty Selection object if the\n// index is invalid.\nfunc (s *Selection) Eq(index int) *Selection {\n\tif index < 0 {\n\t\tindex += len(s.Nodes)\n\t}\n\n\tif index >= len(s.Nodes) || index < 0 {\n\t\treturn newEmptySelection(s.document)\n\t}\n\n\treturn s.Slice(index, index+1)\n}\n\n// Slice reduces the set of matched elements to a subset specified by a range\n// of indices. The start index is 0-based and indicates the index of the first\n// element to select. The end index is 0-based and indicates the index at which\n// the elements stop being selected (the end index is not selected).\n//\n// The indices may be negative, in which case they represent an offset from the\n// end of the selection.\n//\n// The special value ToEnd may be specified as end index, in which case all elements\n// until the end are selected. This works both for a positive and negative start\n// index.\nfunc (s *Selection) Slice(start, end int) *Selection {\n\tif start < 0 {\n\t\tstart += len(s.Nodes)\n\t}\n\tif end == ToEnd {\n\t\tend = len(s.Nodes)\n\t} else if end < 0 {\n\t\tend += len(s.Nodes)\n\t}\n\treturn pushStack(s, s.Nodes[start:end])\n}\n\n// Get retrieves the underlying node at the specified index.\n// Get without parameter is not implemented, since the node array is available\n// on the Selection object.\nfunc (s *Selection) Get(index int) *html.Node {\n\tif index < 0 {\n\t\tindex += len(s.Nodes) // Negative index gets from the end\n\t}\n\treturn s.Nodes[index]\n}\n\n// Index returns the position of the first element within the Selection object\n// relative to its sibling elements.\nfunc (s *Selection) Index() int {\n\tif len(s.Nodes) > 0 {\n\t\treturn newSingleSelection(s.Nodes[0], s.document).PrevAll().Length()\n\t}\n\treturn -1\n}\n\n// IndexSelector returns the position of the first element within the\n// Selection object relative to the elements matched by the selector, or -1 if\n// not found.\nfunc (s *Selection) IndexSelector(selector string) int {\n\tif len(s.Nodes) > 0 {\n\t\tsel := s.document.Find(selector)\n\t\treturn indexInSlice(sel.Nodes, s.Nodes[0])\n\t}\n\treturn -1\n}\n\n// IndexMatcher returns the position of the first element within the\n// Selection object relative to the elements matched by the matcher, or -1 if\n// not found.\nfunc (s *Selection) IndexMatcher(m Matcher) int {\n\tif len(s.Nodes) > 0 {\n\t\tsel := s.document.FindMatcher(m)\n\t\treturn indexInSlice(sel.Nodes, s.Nodes[0])\n\t}\n\treturn -1\n}\n\n// IndexOfNode returns the position of the specified node within the Selection\n// object, or -1 if not found.\nfunc (s *Selection) IndexOfNode(node *html.Node) int {\n\treturn indexInSlice(s.Nodes, node)\n}\n\n// IndexOfSelection returns the position of the first node in the specified\n// Selection object within this Selection object, or -1 if not found.\nfunc (s *Selection) IndexOfSelection(sel *Selection) int {\n\tif sel != nil && len(sel.Nodes) > 0 {\n\t\treturn indexInSlice(s.Nodes, sel.Nodes[0])\n\t}\n\treturn -1\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/doc.go",
    "content": "// Copyright (c) 2012-2016, Martin Angers & Contributors\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without modification,\n// are permitted provided that the following conditions are met:\n//\n// * Redistributions of source code must retain the above copyright notice,\n// this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above copyright notice,\n// this list of conditions and the following disclaimer in the documentation and/or\n// other materials provided with the distribution.\n// * Neither the name of the author nor the names of its contributors may be used to\n// endorse or promote products derived from this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS\n// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\n// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR\n// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY\n// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n/*\nPackage goquery implements features similar to jQuery, including the chainable\nsyntax, to manipulate and query an HTML document.\n\nIt brings a syntax and a set of features similar to jQuery to the Go language.\nIt is based on Go's net/html package and the CSS Selector library cascadia.\nSince the net/html parser returns nodes, and not a full-featured DOM\ntree, jQuery's stateful manipulation functions (like height(), css(), detach())\nhave been left off.\n\nAlso, because the net/html parser requires UTF-8 encoding, so does goquery: it is\nthe caller's responsibility to ensure that the source document provides UTF-8 encoded HTML.\nSee the repository's wiki for various options on how to do this.\n\nSyntax-wise, it is as close as possible to jQuery, with the same method names when\npossible, and that warm and fuzzy chainable interface. jQuery being the\nultra-popular library that it is, writing a similar HTML-manipulating\nlibrary was better to follow its API than to start anew (in the same spirit as\nGo's fmt package), even though some of its methods are less than intuitive (looking\nat you, index()...).\n\nIt is hosted on GitHub, along with additional documentation in the README.md\nfile: https://github.com/puerkitobio/goquery\n\nPlease note that because of the net/html dependency, goquery requires Go1.1+.\n\nThe various methods are split into files based on the category of behavior.\nThe three dots (...) indicate that various \"overloads\" are available.\n\n* array.go : array-like positional manipulation of the selection.\n    - Eq()\n    - First()\n    - Get()\n    - Index...()\n    - Last()\n    - Slice()\n\n* expand.go : methods that expand or augment the selection's set.\n    - Add...()\n    - AndSelf()\n    - Union(), which is an alias for AddSelection()\n\n* filter.go : filtering methods, that reduce the selection's set.\n    - End()\n    - Filter...()\n    - Has...()\n    - Intersection(), which is an alias of FilterSelection()\n    - Not...()\n\n* iteration.go : methods to loop over the selection's nodes.\n    - Each()\n    - EachWithBreak()\n    - Map()\n\n* manipulation.go : methods for modifying the document\n    - After...()\n    - Append...()\n    - Before...()\n    - Clone()\n    - Empty()\n    - Prepend...()\n    - Remove...()\n    - ReplaceWith...()\n    - Unwrap()\n    - Wrap...()\n    - WrapAll...()\n    - WrapInner...()\n\n* property.go : methods that inspect and get the node's properties values.\n    - Attr*(), RemoveAttr(), SetAttr()\n    - AddClass(), HasClass(), RemoveClass(), ToggleClass()\n    - Html()\n    - Length()\n    - Size(), which is an alias for Length()\n    - Text()\n\n* query.go : methods that query, or reflect, a node's identity.\n    - Contains()\n    - Is...()\n\n* traversal.go : methods to traverse the HTML document tree.\n    - Children...()\n    - Contents()\n    - Find...()\n    - Next...()\n    - Parent[s]...()\n    - Prev...()\n    - Siblings...()\n\n* type.go : definition of the types exposed by goquery.\n    - Document\n    - Selection\n    - Matcher\n\n* utilities.go : definition of helper functions (and not methods on a *Selection)\nthat are not part of jQuery, but are useful to goquery.\n    - NodeName\n    - OuterHtml\n*/\npackage goquery\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/expand.go",
    "content": "package goquery\n\nimport \"golang.org/x/net/html\"\n\n// Add adds the selector string's matching nodes to those in the current\n// selection and returns a new Selection object.\n// The selector string is run in the context of the document of the current\n// Selection object.\nfunc (s *Selection) Add(selector string) *Selection {\n\treturn s.AddNodes(findWithMatcher([]*html.Node{s.document.rootNode}, compileMatcher(selector))...)\n}\n\n// AddMatcher adds the matcher's matching nodes to those in the current\n// selection and returns a new Selection object.\n// The matcher is run in the context of the document of the current\n// Selection object.\nfunc (s *Selection) AddMatcher(m Matcher) *Selection {\n\treturn s.AddNodes(findWithMatcher([]*html.Node{s.document.rootNode}, m)...)\n}\n\n// AddSelection adds the specified Selection object's nodes to those in the\n// current selection and returns a new Selection object.\nfunc (s *Selection) AddSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.AddNodes()\n\t}\n\treturn s.AddNodes(sel.Nodes...)\n}\n\n// Union is an alias for AddSelection.\nfunc (s *Selection) Union(sel *Selection) *Selection {\n\treturn s.AddSelection(sel)\n}\n\n// AddNodes adds the specified nodes to those in the\n// current selection and returns a new Selection object.\nfunc (s *Selection) AddNodes(nodes ...*html.Node) *Selection {\n\treturn pushStack(s, appendWithoutDuplicates(s.Nodes, nodes, nil))\n}\n\n// AndSelf adds the previous set of elements on the stack to the current set.\n// It returns a new Selection object containing the current Selection combined\n// with the previous one.\n// Deprecated: This function has been deprecated and is now an alias for AddBack().\nfunc (s *Selection) AndSelf() *Selection {\n\treturn s.AddBack()\n}\n\n// AddBack adds the previous set of elements on the stack to the current set.\n// It returns a new Selection object containing the current Selection combined\n// with the previous one.\nfunc (s *Selection) AddBack() *Selection {\n\treturn s.AddSelection(s.prevSel)\n}\n\n// AddBackFiltered reduces the previous set of elements on the stack to those that\n// match the selector string, and adds them to the current set.\n// It returns a new Selection object containing the current Selection combined\n// with the filtered previous one\nfunc (s *Selection) AddBackFiltered(selector string) *Selection {\n\treturn s.AddSelection(s.prevSel.Filter(selector))\n}\n\n// AddBackMatcher reduces the previous set of elements on the stack to those that match\n// the matcher, and adds them to the current set.\n// It returns a new Selection object containing the current Selection combined\n// with the filtered previous one\nfunc (s *Selection) AddBackMatcher(m Matcher) *Selection {\n\treturn s.AddSelection(s.prevSel.FilterMatcher(m))\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/filter.go",
    "content": "package goquery\n\nimport \"golang.org/x/net/html\"\n\n// Filter reduces the set of matched elements to those that match the selector string.\n// It returns a new Selection object for this subset of matching elements.\nfunc (s *Selection) Filter(selector string) *Selection {\n\treturn s.FilterMatcher(compileMatcher(selector))\n}\n\n// FilterMatcher reduces the set of matched elements to those that match\n// the given matcher. It returns a new Selection object for this subset\n// of matching elements.\nfunc (s *Selection) FilterMatcher(m Matcher) *Selection {\n\treturn pushStack(s, winnow(s, m, true))\n}\n\n// Not removes elements from the Selection that match the selector string.\n// It returns a new Selection object with the matching elements removed.\nfunc (s *Selection) Not(selector string) *Selection {\n\treturn s.NotMatcher(compileMatcher(selector))\n}\n\n// NotMatcher removes elements from the Selection that match the given matcher.\n// It returns a new Selection object with the matching elements removed.\nfunc (s *Selection) NotMatcher(m Matcher) *Selection {\n\treturn pushStack(s, winnow(s, m, false))\n}\n\n// FilterFunction reduces the set of matched elements to those that pass the function's test.\n// It returns a new Selection object for this subset of elements.\nfunc (s *Selection) FilterFunction(f func(int, *Selection) bool) *Selection {\n\treturn pushStack(s, winnowFunction(s, f, true))\n}\n\n// NotFunction removes elements from the Selection that pass the function's test.\n// It returns a new Selection object with the matching elements removed.\nfunc (s *Selection) NotFunction(f func(int, *Selection) bool) *Selection {\n\treturn pushStack(s, winnowFunction(s, f, false))\n}\n\n// FilterNodes reduces the set of matched elements to those that match the specified nodes.\n// It returns a new Selection object for this subset of elements.\nfunc (s *Selection) FilterNodes(nodes ...*html.Node) *Selection {\n\treturn pushStack(s, winnowNodes(s, nodes, true))\n}\n\n// NotNodes removes elements from the Selection that match the specified nodes.\n// It returns a new Selection object with the matching elements removed.\nfunc (s *Selection) NotNodes(nodes ...*html.Node) *Selection {\n\treturn pushStack(s, winnowNodes(s, nodes, false))\n}\n\n// FilterSelection reduces the set of matched elements to those that match a\n// node in the specified Selection object.\n// It returns a new Selection object for this subset of elements.\nfunc (s *Selection) FilterSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn pushStack(s, winnowNodes(s, nil, true))\n\t}\n\treturn pushStack(s, winnowNodes(s, sel.Nodes, true))\n}\n\n// NotSelection removes elements from the Selection that match a node in the specified\n// Selection object. It returns a new Selection object with the matching elements removed.\nfunc (s *Selection) NotSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn pushStack(s, winnowNodes(s, nil, false))\n\t}\n\treturn pushStack(s, winnowNodes(s, sel.Nodes, false))\n}\n\n// Intersection is an alias for FilterSelection.\nfunc (s *Selection) Intersection(sel *Selection) *Selection {\n\treturn s.FilterSelection(sel)\n}\n\n// Has reduces the set of matched elements to those that have a descendant\n// that matches the selector.\n// It returns a new Selection object with the matching elements.\nfunc (s *Selection) Has(selector string) *Selection {\n\treturn s.HasSelection(s.document.Find(selector))\n}\n\n// HasMatcher reduces the set of matched elements to those that have a descendant\n// that matches the matcher.\n// It returns a new Selection object with the matching elements.\nfunc (s *Selection) HasMatcher(m Matcher) *Selection {\n\treturn s.HasSelection(s.document.FindMatcher(m))\n}\n\n// HasNodes reduces the set of matched elements to those that have a\n// descendant that matches one of the nodes.\n// It returns a new Selection object with the matching elements.\nfunc (s *Selection) HasNodes(nodes ...*html.Node) *Selection {\n\treturn s.FilterFunction(func(_ int, sel *Selection) bool {\n\t\t// Add all nodes that contain one of the specified nodes\n\t\tfor _, n := range nodes {\n\t\t\tif sel.Contains(n) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t\treturn false\n\t})\n}\n\n// HasSelection reduces the set of matched elements to those that have a\n// descendant that matches one of the nodes of the specified Selection object.\n// It returns a new Selection object with the matching elements.\nfunc (s *Selection) HasSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.HasNodes()\n\t}\n\treturn s.HasNodes(sel.Nodes...)\n}\n\n// End ends the most recent filtering operation in the current chain and\n// returns the set of matched elements to its previous state.\nfunc (s *Selection) End() *Selection {\n\tif s.prevSel != nil {\n\t\treturn s.prevSel\n\t}\n\treturn newEmptySelection(s.document)\n}\n\n// Filter based on the matcher, and the indicator to keep (Filter) or\n// to get rid of (Not) the matching elements.\nfunc winnow(sel *Selection, m Matcher, keep bool) []*html.Node {\n\t// Optimize if keep is requested\n\tif keep {\n\t\treturn m.Filter(sel.Nodes)\n\t}\n\t// Use grep\n\treturn grep(sel, func(i int, s *Selection) bool {\n\t\treturn !m.Match(s.Get(0))\n\t})\n}\n\n// Filter based on an array of nodes, and the indicator to keep (Filter) or\n// to get rid of (Not) the matching elements.\nfunc winnowNodes(sel *Selection, nodes []*html.Node, keep bool) []*html.Node {\n\tif len(nodes)+len(sel.Nodes) < minNodesForSet {\n\t\treturn grep(sel, func(i int, s *Selection) bool {\n\t\t\treturn isInSlice(nodes, s.Get(0)) == keep\n\t\t})\n\t}\n\n\tset := make(map[*html.Node]bool)\n\tfor _, n := range nodes {\n\t\tset[n] = true\n\t}\n\treturn grep(sel, func(i int, s *Selection) bool {\n\t\treturn set[s.Get(0)] == keep\n\t})\n}\n\n// Filter based on a function test, and the indicator to keep (Filter) or\n// to get rid of (Not) the matching elements.\nfunc winnowFunction(sel *Selection, f func(int, *Selection) bool, keep bool) []*html.Node {\n\treturn grep(sel, func(i int, s *Selection) bool {\n\t\treturn f(i, s) == keep\n\t})\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/iteration.go",
    "content": "package goquery\n\nimport \"iter\"\n\n// Each iterates over a Selection object, executing a function for each\n// matched element. It returns the current Selection object. The function\n// f is called for each element in the selection with the index of the\n// element in that selection starting at 0, and a *Selection that contains\n// only that element.\nfunc (s *Selection) Each(f func(int, *Selection)) *Selection {\n\tfor i, n := range s.Nodes {\n\t\tf(i, newSingleSelection(n, s.document))\n\t}\n\treturn s\n}\n\n// EachIter returns an iterator that yields the Selection object in order.\n// The implementation is similar to Each, but it returns an iterator instead.\nfunc (s *Selection) EachIter() iter.Seq2[int, *Selection] {\n\treturn func(yield func(int, *Selection) bool) {\n\t\tfor i, n := range s.Nodes {\n\t\t\tif !yield(i, newSingleSelection(n, s.document)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// EachWithBreak iterates over a Selection object, executing a function for each\n// matched element. It is identical to Each except that it is possible to break\n// out of the loop by returning false in the callback function. It returns the\n// current Selection object.\nfunc (s *Selection) EachWithBreak(f func(int, *Selection) bool) *Selection {\n\tfor i, n := range s.Nodes {\n\t\tif !f(i, newSingleSelection(n, s.document)) {\n\t\t\treturn s\n\t\t}\n\t}\n\treturn s\n}\n\n// Map passes each element in the current matched set through a function,\n// producing a slice of string holding the returned values. The function\n// f is called for each element in the selection with the index of the\n// element in that selection starting at 0, and a *Selection that contains\n// only that element.\nfunc (s *Selection) Map(f func(int, *Selection) string) (result []string) {\n\treturn Map(s, f)\n}\n\n// Map is the generic version of Selection.Map, allowing any type to be\n// returned.\nfunc Map[E any](s *Selection, f func(int, *Selection) E) (result []E) {\n\tresult = make([]E, len(s.Nodes))\n\n\tfor i, n := range s.Nodes {\n\t\tresult[i] = f(i, newSingleSelection(n, s.document))\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/manipulation.go",
    "content": "package goquery\n\nimport (\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// After applies the selector from the root document and inserts the matched elements\n// after the elements in the set of matched elements.\n//\n// If one of the matched elements in the selection is not currently in the\n// document, it's impossible to insert nodes after it, so it will be ignored.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) After(selector string) *Selection {\n\treturn s.AfterMatcher(compileMatcher(selector))\n}\n\n// AfterMatcher applies the matcher from the root document and inserts the matched elements\n// after the elements in the set of matched elements.\n//\n// If one of the matched elements in the selection is not currently in the\n// document, it's impossible to insert nodes after it, so it will be ignored.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) AfterMatcher(m Matcher) *Selection {\n\treturn s.AfterNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// AfterSelection inserts the elements in the selection after each element in the set of matched\n// elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) AfterSelection(sel *Selection) *Selection {\n\treturn s.AfterNodes(sel.Nodes...)\n}\n\n// AfterHtml parses the html and inserts it after the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) AfterHtml(htmlStr string) *Selection {\n\treturn s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {\n\t\tnextSibling := node.NextSibling\n\t\tfor _, n := range nodes {\n\t\t\tif node.Parent != nil {\n\t\t\t\tnode.Parent.InsertBefore(n, nextSibling)\n\t\t\t}\n\t\t}\n\t})\n}\n\n// AfterNodes inserts the nodes after each element in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) AfterNodes(ns ...*html.Node) *Selection {\n\treturn s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {\n\t\tif sn.Parent != nil {\n\t\t\tsn.Parent.InsertBefore(n, sn.NextSibling)\n\t\t}\n\t})\n}\n\n// Append appends the elements specified by the selector to the end of each element\n// in the set of matched elements, following those rules:\n//\n// 1) The selector is applied to the root document.\n//\n// 2) Elements that are part of the document will be moved to the new location.\n//\n// 3) If there are multiple locations to append to, cloned nodes will be\n// appended to all target locations except the last one, which will be moved\n// as noted in (2).\nfunc (s *Selection) Append(selector string) *Selection {\n\treturn s.AppendMatcher(compileMatcher(selector))\n}\n\n// AppendMatcher appends the elements specified by the matcher to the end of each element\n// in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) AppendMatcher(m Matcher) *Selection {\n\treturn s.AppendNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// AppendSelection appends the elements in the selection to the end of each element\n// in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) AppendSelection(sel *Selection) *Selection {\n\treturn s.AppendNodes(sel.Nodes...)\n}\n\n// AppendHtml parses the html and appends it to the set of matched elements.\nfunc (s *Selection) AppendHtml(htmlStr string) *Selection {\n\treturn s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {\n\t\tfor _, n := range nodes {\n\t\t\tnode.AppendChild(n)\n\t\t}\n\t})\n}\n\n// AppendNodes appends the specified nodes to each node in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) AppendNodes(ns ...*html.Node) *Selection {\n\treturn s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {\n\t\tsn.AppendChild(n)\n\t})\n}\n\n// Before inserts the matched elements before each element in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) Before(selector string) *Selection {\n\treturn s.BeforeMatcher(compileMatcher(selector))\n}\n\n// BeforeMatcher inserts the matched elements before each element in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) BeforeMatcher(m Matcher) *Selection {\n\treturn s.BeforeNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// BeforeSelection inserts the elements in the selection before each element in the set of matched\n// elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) BeforeSelection(sel *Selection) *Selection {\n\treturn s.BeforeNodes(sel.Nodes...)\n}\n\n// BeforeHtml parses the html and inserts it before the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) BeforeHtml(htmlStr string) *Selection {\n\treturn s.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {\n\t\tfor _, n := range nodes {\n\t\t\tif node.Parent != nil {\n\t\t\t\tnode.Parent.InsertBefore(n, node)\n\t\t\t}\n\t\t}\n\t})\n}\n\n// BeforeNodes inserts the nodes before each element in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) BeforeNodes(ns ...*html.Node) *Selection {\n\treturn s.manipulateNodes(ns, false, func(sn *html.Node, n *html.Node) {\n\t\tif sn.Parent != nil {\n\t\t\tsn.Parent.InsertBefore(n, sn)\n\t\t}\n\t})\n}\n\n// Clone creates a deep copy of the set of matched nodes. The new nodes will not be\n// attached to the document.\nfunc (s *Selection) Clone() *Selection {\n\tns := newEmptySelection(s.document)\n\tns.Nodes = cloneNodes(s.Nodes)\n\treturn ns\n}\n\n// Empty removes all children nodes from the set of matched elements.\n// It returns the children nodes in a new Selection.\nfunc (s *Selection) Empty() *Selection {\n\tvar nodes []*html.Node\n\n\tfor _, n := range s.Nodes {\n\t\tfor c := n.FirstChild; c != nil; c = n.FirstChild {\n\t\t\tn.RemoveChild(c)\n\t\t\tnodes = append(nodes, c)\n\t\t}\n\t}\n\n\treturn pushStack(s, nodes)\n}\n\n// Prepend prepends the elements specified by the selector to each element in\n// the set of matched elements, following the same rules as Append.\nfunc (s *Selection) Prepend(selector string) *Selection {\n\treturn s.PrependMatcher(compileMatcher(selector))\n}\n\n// PrependMatcher prepends the elements specified by the matcher to each\n// element in the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) PrependMatcher(m Matcher) *Selection {\n\treturn s.PrependNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// PrependSelection prepends the elements in the selection to each element in\n// the set of matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) PrependSelection(sel *Selection) *Selection {\n\treturn s.PrependNodes(sel.Nodes...)\n}\n\n// PrependHtml parses the html and prepends it to the set of matched elements.\nfunc (s *Selection) PrependHtml(htmlStr string) *Selection {\n\treturn s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {\n\t\tfirstChild := node.FirstChild\n\t\tfor _, n := range nodes {\n\t\t\tnode.InsertBefore(n, firstChild)\n\t\t}\n\t})\n}\n\n// PrependNodes prepends the specified nodes to each node in the set of\n// matched elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) PrependNodes(ns ...*html.Node) *Selection {\n\treturn s.manipulateNodes(ns, true, func(sn *html.Node, n *html.Node) {\n\t\t// sn.FirstChild may be nil, in which case this functions like\n\t\t// sn.AppendChild()\n\t\tsn.InsertBefore(n, sn.FirstChild)\n\t})\n}\n\n// Remove removes the set of matched elements from the document.\n// It returns the same selection, now consisting of nodes not in the document.\nfunc (s *Selection) Remove() *Selection {\n\tfor _, n := range s.Nodes {\n\t\tif n.Parent != nil {\n\t\t\tn.Parent.RemoveChild(n)\n\t\t}\n\t}\n\n\treturn s\n}\n\n// RemoveFiltered removes from the current set of matched elements those that\n// match the selector filter. It returns the Selection of removed nodes.\n//\n// For example if the selection s contains \"<h1>\", \"<h2>\" and \"<h3>\"\n// and s.RemoveFiltered(\"h2\") is called, only the \"<h2>\" node is removed\n// (and returned), while \"<h1>\" and \"<h3>\" are kept in the document.\nfunc (s *Selection) RemoveFiltered(selector string) *Selection {\n\treturn s.RemoveMatcher(compileMatcher(selector))\n}\n\n// RemoveMatcher removes from the current set of matched elements those that\n// match the Matcher filter. It returns the Selection of removed nodes.\n// See RemoveFiltered for additional information.\nfunc (s *Selection) RemoveMatcher(m Matcher) *Selection {\n\treturn s.FilterMatcher(m).Remove()\n}\n\n// ReplaceWith replaces each element in the set of matched elements with the\n// nodes matched by the given selector.\n// It returns the removed elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) ReplaceWith(selector string) *Selection {\n\treturn s.ReplaceWithMatcher(compileMatcher(selector))\n}\n\n// ReplaceWithMatcher replaces each element in the set of matched elements with\n// the nodes matched by the given Matcher.\n// It returns the removed elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) ReplaceWithMatcher(m Matcher) *Selection {\n\treturn s.ReplaceWithNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// ReplaceWithSelection replaces each element in the set of matched elements with\n// the nodes from the given Selection.\n// It returns the removed elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) ReplaceWithSelection(sel *Selection) *Selection {\n\treturn s.ReplaceWithNodes(sel.Nodes...)\n}\n\n// ReplaceWithHtml replaces each element in the set of matched elements with\n// the parsed HTML.\n// It returns the removed elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) ReplaceWithHtml(htmlStr string) *Selection {\n\ts.eachNodeHtml(htmlStr, true, func(node *html.Node, nodes []*html.Node) {\n\t\tnextSibling := node.NextSibling\n\t\tfor _, n := range nodes {\n\t\t\tif node.Parent != nil {\n\t\t\t\tnode.Parent.InsertBefore(n, nextSibling)\n\t\t\t}\n\t\t}\n\t})\n\treturn s.Remove()\n}\n\n// ReplaceWithNodes replaces each element in the set of matched elements with\n// the given nodes.\n// It returns the removed elements.\n//\n// This follows the same rules as Selection.Append.\nfunc (s *Selection) ReplaceWithNodes(ns ...*html.Node) *Selection {\n\ts.AfterNodes(ns...)\n\treturn s.Remove()\n}\n\n// SetHtml sets the html content of each element in the selection to\n// specified html string.\nfunc (s *Selection) SetHtml(htmlStr string) *Selection {\n\tfor _, context := range s.Nodes {\n\t\tfor c := context.FirstChild; c != nil; c = context.FirstChild {\n\t\t\tcontext.RemoveChild(c)\n\t\t}\n\t}\n\treturn s.eachNodeHtml(htmlStr, false, func(node *html.Node, nodes []*html.Node) {\n\t\tfor _, n := range nodes {\n\t\t\tnode.AppendChild(n)\n\t\t}\n\t})\n}\n\n// SetText sets the content of each element in the selection to specified content.\n// The provided text string is escaped.\nfunc (s *Selection) SetText(text string) *Selection {\n\treturn s.SetHtml(html.EscapeString(text))\n}\n\n// Unwrap removes the parents of the set of matched elements, leaving the matched\n// elements (and their siblings, if any) in their place.\n// It returns the original selection.\nfunc (s *Selection) Unwrap() *Selection {\n\ts.Parent().Each(func(i int, ss *Selection) {\n\t\t// For some reason, jquery allows unwrap to remove the <head> element, so\n\t\t// allowing it here too. Same for <html>. Why it allows those elements to\n\t\t// be unwrapped while not allowing body is a mystery to me.\n\t\tif ss.Nodes[0].Data != \"body\" {\n\t\t\tss.ReplaceWithSelection(ss.Contents())\n\t\t}\n\t})\n\n\treturn s\n}\n\n// Wrap wraps each element in the set of matched elements inside the first\n// element matched by the given selector. The matched child is cloned before\n// being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) Wrap(selector string) *Selection {\n\treturn s.WrapMatcher(compileMatcher(selector))\n}\n\n// WrapMatcher wraps each element in the set of matched elements inside the\n// first element matched by the given matcher. The matched child is cloned\n// before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapMatcher(m Matcher) *Selection {\n\treturn s.wrapNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// WrapSelection wraps each element in the set of matched elements inside the\n// first element in the given Selection. The element is cloned before being\n// inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapSelection(sel *Selection) *Selection {\n\treturn s.wrapNodes(sel.Nodes...)\n}\n\n// WrapHtml wraps each element in the set of matched elements inside the inner-\n// most child of the given HTML.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapHtml(htmlStr string) *Selection {\n\tnodesMap := make(map[string][]*html.Node)\n\tfor _, context := range s.Nodes {\n\t\tvar parent *html.Node\n\t\tif context.Parent != nil {\n\t\t\tparent = context.Parent\n\t\t} else {\n\t\t\tparent = &html.Node{Type: html.ElementNode}\n\t\t}\n\t\tnodes, found := nodesMap[nodeName(parent)]\n\t\tif !found {\n\t\t\tnodes = parseHtmlWithContext(htmlStr, parent)\n\t\t\tnodesMap[nodeName(parent)] = nodes\n\t\t}\n\t\tnewSingleSelection(context, s.document).wrapAllNodes(cloneNodes(nodes)...)\n\t}\n\treturn s\n}\n\n// WrapNode wraps each element in the set of matched elements inside the inner-\n// most child of the given node. The given node is copied before being inserted\n// into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapNode(n *html.Node) *Selection {\n\treturn s.wrapNodes(n)\n}\n\nfunc (s *Selection) wrapNodes(ns ...*html.Node) *Selection {\n\ts.Each(func(i int, ss *Selection) {\n\t\tss.wrapAllNodes(ns...)\n\t})\n\n\treturn s\n}\n\n// WrapAll wraps a single HTML structure, matched by the given selector, around\n// all elements in the set of matched elements. The matched child is cloned\n// before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapAll(selector string) *Selection {\n\treturn s.WrapAllMatcher(compileMatcher(selector))\n}\n\n// WrapAllMatcher wraps a single HTML structure, matched by the given Matcher,\n// around all elements in the set of matched elements. The matched child is\n// cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapAllMatcher(m Matcher) *Selection {\n\treturn s.wrapAllNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// WrapAllSelection wraps a single HTML structure, the first node of the given\n// Selection, around all elements in the set of matched elements. The matched\n// child is cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapAllSelection(sel *Selection) *Selection {\n\treturn s.wrapAllNodes(sel.Nodes...)\n}\n\n// WrapAllHtml wraps the given HTML structure around all elements in the set of\n// matched elements. The matched child is cloned before being inserted into the\n// document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapAllHtml(htmlStr string) *Selection {\n\tvar context *html.Node\n\tvar nodes []*html.Node\n\tif len(s.Nodes) > 0 {\n\t\tcontext = s.Nodes[0]\n\t\tif context.Parent != nil {\n\t\t\tnodes = parseHtmlWithContext(htmlStr, context)\n\t\t} else {\n\t\t\tnodes = parseHtml(htmlStr)\n\t\t}\n\t}\n\treturn s.wrapAllNodes(nodes...)\n}\n\nfunc (s *Selection) wrapAllNodes(ns ...*html.Node) *Selection {\n\tif len(ns) > 0 {\n\t\treturn s.WrapAllNode(ns[0])\n\t}\n\treturn s\n}\n\n// WrapAllNode wraps the given node around the first element in the Selection,\n// making all other nodes in the Selection children of the given node. The node\n// is cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapAllNode(n *html.Node) *Selection {\n\tif s.Size() == 0 {\n\t\treturn s\n\t}\n\n\twrap := cloneNode(n)\n\n\tfirst := s.Nodes[0]\n\tif first.Parent != nil {\n\t\tfirst.Parent.InsertBefore(wrap, first)\n\t\tfirst.Parent.RemoveChild(first)\n\t}\n\n\tfor c := getFirstChildEl(wrap); c != nil; c = getFirstChildEl(wrap) {\n\t\twrap = c\n\t}\n\n\tnewSingleSelection(wrap, s.document).AppendSelection(s)\n\n\treturn s\n}\n\n// WrapInner wraps an HTML structure, matched by the given selector, around the\n// content of element in the set of matched elements. The matched child is\n// cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapInner(selector string) *Selection {\n\treturn s.WrapInnerMatcher(compileMatcher(selector))\n}\n\n// WrapInnerMatcher wraps an HTML structure, matched by the given selector,\n// around the content of element in the set of matched elements. The matched\n// child is cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapInnerMatcher(m Matcher) *Selection {\n\treturn s.wrapInnerNodes(m.MatchAll(s.document.rootNode)...)\n}\n\n// WrapInnerSelection wraps an HTML structure, matched by the given selector,\n// around the content of element in the set of matched elements. The matched\n// child is cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapInnerSelection(sel *Selection) *Selection {\n\treturn s.wrapInnerNodes(sel.Nodes...)\n}\n\n// WrapInnerHtml wraps an HTML structure, matched by the given selector, around\n// the content of element in the set of matched elements. The matched child is\n// cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapInnerHtml(htmlStr string) *Selection {\n\tnodesMap := make(map[string][]*html.Node)\n\tfor _, context := range s.Nodes {\n\t\tnodes, found := nodesMap[nodeName(context)]\n\t\tif !found {\n\t\t\tnodes = parseHtmlWithContext(htmlStr, context)\n\t\t\tnodesMap[nodeName(context)] = nodes\n\t\t}\n\t\tnewSingleSelection(context, s.document).wrapInnerNodes(cloneNodes(nodes)...)\n\t}\n\treturn s\n}\n\n// WrapInnerNode wraps an HTML structure, matched by the given selector, around\n// the content of element in the set of matched elements. The matched child is\n// cloned before being inserted into the document.\n//\n// It returns the original set of elements.\nfunc (s *Selection) WrapInnerNode(n *html.Node) *Selection {\n\treturn s.wrapInnerNodes(n)\n}\n\nfunc (s *Selection) wrapInnerNodes(ns ...*html.Node) *Selection {\n\tif len(ns) == 0 {\n\t\treturn s\n\t}\n\n\ts.Each(func(i int, s *Selection) {\n\t\tcontents := s.Contents()\n\n\t\tif contents.Size() > 0 {\n\t\t\tcontents.wrapAllNodes(ns...)\n\t\t} else {\n\t\t\ts.AppendNodes(cloneNode(ns[0]))\n\t\t}\n\t})\n\n\treturn s\n}\n\nfunc parseHtml(h string) []*html.Node {\n\t// Errors are only returned when the io.Reader returns any error besides\n\t// EOF, but strings.Reader never will\n\tnodes, err := html.ParseFragment(strings.NewReader(h), &html.Node{Type: html.ElementNode})\n\tif err != nil {\n\t\tpanic(\"goquery: failed to parse HTML: \" + err.Error())\n\t}\n\treturn nodes\n}\n\nfunc parseHtmlWithContext(h string, context *html.Node) []*html.Node {\n\t// Errors are only returned when the io.Reader returns any error besides\n\t// EOF, but strings.Reader never will\n\tnodes, err := html.ParseFragment(strings.NewReader(h), context)\n\tif err != nil {\n\t\tpanic(\"goquery: failed to parse HTML: \" + err.Error())\n\t}\n\treturn nodes\n}\n\n// Get the first child that is an ElementNode\nfunc getFirstChildEl(n *html.Node) *html.Node {\n\tc := n.FirstChild\n\tfor c != nil && c.Type != html.ElementNode {\n\t\tc = c.NextSibling\n\t}\n\treturn c\n}\n\n// Deep copy a slice of nodes.\nfunc cloneNodes(ns []*html.Node) []*html.Node {\n\tcns := make([]*html.Node, 0, len(ns))\n\n\tfor _, n := range ns {\n\t\tcns = append(cns, cloneNode(n))\n\t}\n\n\treturn cns\n}\n\n// Deep copy a node. The new node has clones of all the original node's\n// children but none of its parents or siblings.\nfunc cloneNode(n *html.Node) *html.Node {\n\tnn := &html.Node{\n\t\tType:     n.Type,\n\t\tDataAtom: n.DataAtom,\n\t\tData:     n.Data,\n\t\tAttr:     make([]html.Attribute, len(n.Attr)),\n\t}\n\n\tcopy(nn.Attr, n.Attr)\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tnn.AppendChild(cloneNode(c))\n\t}\n\n\treturn nn\n}\n\nfunc (s *Selection) manipulateNodes(ns []*html.Node, reverse bool,\n\tf func(sn *html.Node, n *html.Node)) *Selection {\n\n\tlasti := s.Size() - 1\n\n\t// net.Html doesn't provide document fragments for insertion, so to get\n\t// things in the correct order with After() and Prepend(), the callback\n\t// needs to be called on the reverse of the nodes.\n\tif reverse {\n\t\tfor i, j := 0, len(ns)-1; i < j; i, j = i+1, j-1 {\n\t\t\tns[i], ns[j] = ns[j], ns[i]\n\t\t}\n\t}\n\n\tfor i, sn := range s.Nodes {\n\t\tfor _, n := range ns {\n\t\t\tif i != lasti {\n\t\t\t\tf(sn, cloneNode(n))\n\t\t\t} else {\n\t\t\t\tif n.Parent != nil {\n\t\t\t\t\tn.Parent.RemoveChild(n)\n\t\t\t\t}\n\t\t\t\tf(sn, n)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn s\n}\n\n// eachNodeHtml parses the given html string and inserts the resulting nodes in the dom with the mergeFn.\n// The parsed nodes are inserted for each element of the selection.\n// isParent can be used to indicate that the elements of the selection should be treated as the parent for the parsed html.\n// A cache is used to avoid parsing the html multiple times should the elements of the selection result in the same context.\nfunc (s *Selection) eachNodeHtml(htmlStr string, isParent bool, mergeFn func(n *html.Node, nodes []*html.Node)) *Selection {\n\t// cache to avoid parsing the html for the same context multiple times\n\tnodeCache := make(map[string][]*html.Node)\n\tvar context *html.Node\n\tfor _, n := range s.Nodes {\n\t\tif isParent {\n\t\t\tcontext = n.Parent\n\t\t} else {\n\t\t\tif n.Type != html.ElementNode {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcontext = n\n\t\t}\n\t\tif context != nil {\n\t\t\tnodes, found := nodeCache[nodeName(context)]\n\t\t\tif !found {\n\t\t\t\tnodes = parseHtmlWithContext(htmlStr, context)\n\t\t\t\tnodeCache[nodeName(context)] = nodes\n\t\t\t}\n\t\t\tmergeFn(n, cloneNodes(nodes))\n\t\t}\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/property.go",
    "content": "package goquery\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n)\n\nvar rxClassTrim = regexp.MustCompile(\"[\\t\\r\\n]\")\n\n// Attr gets the specified attribute's value for the first element in the\n// Selection. To get the value for each element individually, use a looping\n// construct such as Each or Map method.\nfunc (s *Selection) Attr(attrName string) (val string, exists bool) {\n\tif len(s.Nodes) == 0 {\n\t\treturn\n\t}\n\treturn getAttributeValue(attrName, s.Nodes[0])\n}\n\n// AttrOr works like Attr but returns default value if attribute is not present.\nfunc (s *Selection) AttrOr(attrName, defaultValue string) string {\n\tif len(s.Nodes) == 0 {\n\t\treturn defaultValue\n\t}\n\n\tval, exists := getAttributeValue(attrName, s.Nodes[0])\n\tif !exists {\n\t\treturn defaultValue\n\t}\n\n\treturn val\n}\n\n// RemoveAttr removes the named attribute from each element in the set of matched elements.\nfunc (s *Selection) RemoveAttr(attrName string) *Selection {\n\tfor _, n := range s.Nodes {\n\t\tremoveAttr(n, attrName)\n\t}\n\n\treturn s\n}\n\n// SetAttr sets the given attribute on each element in the set of matched elements.\nfunc (s *Selection) SetAttr(attrName, val string) *Selection {\n\tfor _, n := range s.Nodes {\n\t\tattr := getAttributePtr(attrName, n)\n\t\tif attr == nil {\n\t\t\tn.Attr = append(n.Attr, html.Attribute{Key: attrName, Val: val})\n\t\t} else {\n\t\t\tattr.Val = val\n\t\t}\n\t}\n\n\treturn s\n}\n\n// Text gets the combined text contents of each element in the set of matched\n// elements, including their descendants.\nfunc (s *Selection) Text() string {\n\tvar builder strings.Builder\n\n\t// Slightly optimized vs calling Each: no single selection object created\n\tvar f func(*html.Node)\n\tf = func(n *html.Node) {\n\t\tif n.Type == html.TextNode {\n\t\t\t// Keep newlines and spaces, like jQuery\n\t\t\tbuilder.WriteString(n.Data)\n\t\t}\n\t\tif n.FirstChild != nil {\n\t\t\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\t\t\tf(c)\n\t\t\t}\n\t\t}\n\t}\n\tfor _, n := range s.Nodes {\n\t\tf(n)\n\t}\n\n\treturn builder.String()\n}\n\n// Size is an alias for Length.\nfunc (s *Selection) Size() int {\n\treturn s.Length()\n}\n\n// Length returns the number of elements in the Selection object.\nfunc (s *Selection) Length() int {\n\treturn len(s.Nodes)\n}\n\n// Html gets the HTML contents of the first element in the set of matched\n// elements. It includes text and comment nodes.\nfunc (s *Selection) Html() (ret string, e error) {\n\t// Since there is no .innerHtml, the HTML content must be re-created from\n\t// the nodes using html.Render.\n\tvar builder strings.Builder\n\n\tif len(s.Nodes) > 0 {\n\t\tfor c := s.Nodes[0].FirstChild; c != nil; c = c.NextSibling {\n\t\t\te = html.Render(&builder, c)\n\t\t\tif e != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tret = builder.String()\n\t}\n\n\treturn\n}\n\n// AddClass adds the given class(es) to each element in the set of matched elements.\n// Multiple class names can be specified, separated by a space or via multiple arguments.\nfunc (s *Selection) AddClass(class ...string) *Selection {\n\tclassStr := strings.TrimSpace(strings.Join(class, \" \"))\n\n\tif classStr == \"\" {\n\t\treturn s\n\t}\n\n\ttcls := getClassesSlice(classStr)\n\tfor _, n := range s.Nodes {\n\t\tcurClasses, attr := getClassesAndAttr(n, true)\n\t\tfor _, newClass := range tcls {\n\t\t\tif !strings.Contains(curClasses, \" \"+newClass+\" \") {\n\t\t\t\tcurClasses += newClass + \" \"\n\t\t\t}\n\t\t}\n\n\t\tsetClasses(n, attr, curClasses)\n\t}\n\n\treturn s\n}\n\n// HasClass determines whether any of the matched elements are assigned the\n// given class.\nfunc (s *Selection) HasClass(class string) bool {\n\tclass = \" \" + class + \" \"\n\tfor _, n := range s.Nodes {\n\t\tclasses, _ := getClassesAndAttr(n, false)\n\t\tif strings.Contains(classes, class) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// RemoveClass removes the given class(es) from each element in the set of matched elements.\n// Multiple class names can be specified, separated by a space or via multiple arguments.\n// If no class name is provided, all classes are removed.\nfunc (s *Selection) RemoveClass(class ...string) *Selection {\n\tvar rclasses []string\n\n\tclassStr := strings.TrimSpace(strings.Join(class, \" \"))\n\tremove := classStr == \"\"\n\n\tif !remove {\n\t\trclasses = getClassesSlice(classStr)\n\t}\n\n\tfor _, n := range s.Nodes {\n\t\tif remove {\n\t\t\tremoveAttr(n, \"class\")\n\t\t} else {\n\t\t\tclasses, attr := getClassesAndAttr(n, true)\n\t\t\tfor _, rcl := range rclasses {\n\t\t\t\tclasses = strings.ReplaceAll(classes, \" \"+rcl+\" \", \" \")\n\t\t\t}\n\n\t\t\tsetClasses(n, attr, classes)\n\t\t}\n\t}\n\n\treturn s\n}\n\n// ToggleClass adds or removes the given class(es) for each element in the set of matched elements.\n// Multiple class names can be specified, separated by a space or via multiple arguments.\nfunc (s *Selection) ToggleClass(class ...string) *Selection {\n\tclassStr := strings.TrimSpace(strings.Join(class, \" \"))\n\n\tif classStr == \"\" {\n\t\treturn s\n\t}\n\n\ttcls := getClassesSlice(classStr)\n\n\tfor _, n := range s.Nodes {\n\t\tclasses, attr := getClassesAndAttr(n, true)\n\t\tfor _, tcl := range tcls {\n\t\t\tspaceAroundTcl := \" \" + tcl + \" \"\n\t\t\tif strings.Contains(classes, spaceAroundTcl) {\n\t\t\t\tclasses = strings.ReplaceAll(classes, spaceAroundTcl, \" \")\n\t\t\t} else {\n\t\t\t\tclasses += tcl + \" \"\n\t\t\t}\n\t\t}\n\n\t\tsetClasses(n, attr, classes)\n\t}\n\n\treturn s\n}\n\nfunc getAttributePtr(attrName string, n *html.Node) *html.Attribute {\n\tif n == nil {\n\t\treturn nil\n\t}\n\n\tfor i, a := range n.Attr {\n\t\tif a.Key == attrName {\n\t\t\treturn &n.Attr[i]\n\t\t}\n\t}\n\treturn nil\n}\n\n// Private function to get the specified attribute's value from a node.\nfunc getAttributeValue(attrName string, n *html.Node) (val string, exists bool) {\n\tif a := getAttributePtr(attrName, n); a != nil {\n\t\tval = a.Val\n\t\texists = true\n\t}\n\treturn\n}\n\n// Get and normalize the \"class\" attribute from the node.\nfunc getClassesAndAttr(n *html.Node, create bool) (classes string, attr *html.Attribute) {\n\t// Applies only to element nodes\n\tif n.Type == html.ElementNode {\n\t\tattr = getAttributePtr(\"class\", n)\n\t\tif attr == nil && create {\n\t\t\tn.Attr = append(n.Attr, html.Attribute{\n\t\t\t\tKey: \"class\",\n\t\t\t\tVal: \"\",\n\t\t\t})\n\t\t\tattr = &n.Attr[len(n.Attr)-1]\n\t\t}\n\t}\n\n\tif attr == nil {\n\t\tclasses = \" \"\n\t} else {\n\t\tclasses = rxClassTrim.ReplaceAllString(\" \"+attr.Val+\" \", \" \")\n\t}\n\n\treturn\n}\n\nfunc getClassesSlice(classes string) []string {\n\treturn strings.Split(rxClassTrim.ReplaceAllString(\" \"+classes+\" \", \" \"), \" \")\n}\n\nfunc removeAttr(n *html.Node, attrName string) {\n\tfor i, a := range n.Attr {\n\t\tif a.Key == attrName {\n\t\t\tn.Attr[i], n.Attr[len(n.Attr)-1], n.Attr =\n\t\t\t\tn.Attr[len(n.Attr)-1], html.Attribute{}, n.Attr[:len(n.Attr)-1]\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc setClasses(n *html.Node, attr *html.Attribute, classes string) {\n\tclasses = strings.TrimSpace(classes)\n\tif classes == \"\" {\n\t\tremoveAttr(n, \"class\")\n\t\treturn\n\t}\n\n\tattr.Val = classes\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/query.go",
    "content": "package goquery\n\nimport \"golang.org/x/net/html\"\n\n// Is checks the current matched set of elements against a selector and\n// returns true if at least one of these elements matches.\nfunc (s *Selection) Is(selector string) bool {\n\treturn s.IsMatcher(compileMatcher(selector))\n}\n\n// IsMatcher checks the current matched set of elements against a matcher and\n// returns true if at least one of these elements matches.\nfunc (s *Selection) IsMatcher(m Matcher) bool {\n\tif len(s.Nodes) > 0 {\n\t\tif len(s.Nodes) == 1 {\n\t\t\treturn m.Match(s.Nodes[0])\n\t\t}\n\t\treturn len(m.Filter(s.Nodes)) > 0\n\t}\n\n\treturn false\n}\n\n// IsFunction checks the current matched set of elements against a predicate and\n// returns true if at least one of these elements matches.\nfunc (s *Selection) IsFunction(f func(int, *Selection) bool) bool {\n\treturn s.FilterFunction(f).Length() > 0\n}\n\n// IsSelection checks the current matched set of elements against a Selection object\n// and returns true if at least one of these elements matches.\nfunc (s *Selection) IsSelection(sel *Selection) bool {\n\treturn s.FilterSelection(sel).Length() > 0\n}\n\n// IsNodes checks the current matched set of elements against the specified nodes\n// and returns true if at least one of these elements matches.\nfunc (s *Selection) IsNodes(nodes ...*html.Node) bool {\n\treturn s.FilterNodes(nodes...).Length() > 0\n}\n\n// Contains returns true if the specified Node is within,\n// at any depth, one of the nodes in the Selection object.\n// It is NOT inclusive, to behave like jQuery's implementation, and\n// unlike Javascript's .contains, so if the contained\n// node is itself in the selection, it returns false.\nfunc (s *Selection) Contains(n *html.Node) bool {\n\treturn sliceContains(s.Nodes, n)\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/traversal.go",
    "content": "package goquery\n\nimport \"golang.org/x/net/html\"\n\ntype siblingType int\n\n// Sibling type, used internally when iterating over children at the same\n// level (siblings) to specify which nodes are requested.\nconst (\n\tsiblingPrevUntil siblingType = iota - 3\n\tsiblingPrevAll\n\tsiblingPrev\n\tsiblingAll\n\tsiblingNext\n\tsiblingNextAll\n\tsiblingNextUntil\n\tsiblingAllIncludingNonElements\n)\n\n// Find gets the descendants of each element in the current set of matched\n// elements, filtered by a selector. It returns a new Selection object\n// containing these matched elements.\n//\n// Note that as for all methods accepting a selector string, the selector is\n// compiled and applied by the cascadia package and inherits its behavior and\n// constraints regarding supported selectors. See the note on cascadia in\n// the goquery documentation here:\n// https://github.com/PuerkitoBio/goquery?tab=readme-ov-file#api\nfunc (s *Selection) Find(selector string) *Selection {\n\treturn pushStack(s, findWithMatcher(s.Nodes, compileMatcher(selector)))\n}\n\n// FindMatcher gets the descendants of each element in the current set of matched\n// elements, filtered by the matcher. It returns a new Selection object\n// containing these matched elements.\nfunc (s *Selection) FindMatcher(m Matcher) *Selection {\n\treturn pushStack(s, findWithMatcher(s.Nodes, m))\n}\n\n// FindSelection gets the descendants of each element in the current\n// Selection, filtered by a Selection. It returns a new Selection object\n// containing these matched elements.\nfunc (s *Selection) FindSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn pushStack(s, nil)\n\t}\n\treturn s.FindNodes(sel.Nodes...)\n}\n\n// FindNodes gets the descendants of each element in the current\n// Selection, filtered by some nodes. It returns a new Selection object\n// containing these matched elements.\nfunc (s *Selection) FindNodes(nodes ...*html.Node) *Selection {\n\treturn pushStack(s, mapNodes(nodes, func(i int, n *html.Node) []*html.Node {\n\t\tif sliceContains(s.Nodes, n) {\n\t\t\treturn []*html.Node{n}\n\t\t}\n\t\treturn nil\n\t}))\n}\n\n// Contents gets the children of each element in the Selection,\n// including text and comment nodes. It returns a new Selection object\n// containing these elements.\nfunc (s *Selection) Contents() *Selection {\n\treturn pushStack(s, getChildrenNodes(s.Nodes, siblingAllIncludingNonElements))\n}\n\n// ContentsFiltered gets the children of each element in the Selection,\n// filtered by the specified selector. It returns a new Selection\n// object containing these elements. Since selectors only act on Element nodes,\n// this function is an alias to ChildrenFiltered unless the selector is empty,\n// in which case it is an alias to Contents.\nfunc (s *Selection) ContentsFiltered(selector string) *Selection {\n\tif selector != \"\" {\n\t\treturn s.ChildrenFiltered(selector)\n\t}\n\treturn s.Contents()\n}\n\n// ContentsMatcher gets the children of each element in the Selection,\n// filtered by the specified matcher. It returns a new Selection\n// object containing these elements. Since matchers only act on Element nodes,\n// this function is an alias to ChildrenMatcher.\nfunc (s *Selection) ContentsMatcher(m Matcher) *Selection {\n\treturn s.ChildrenMatcher(m)\n}\n\n// Children gets the child elements of each element in the Selection.\n// It returns a new Selection object containing these elements.\nfunc (s *Selection) Children() *Selection {\n\treturn pushStack(s, getChildrenNodes(s.Nodes, siblingAll))\n}\n\n// ChildrenFiltered gets the child elements of each element in the Selection,\n// filtered by the specified selector. It returns a new\n// Selection object containing these elements.\nfunc (s *Selection) ChildrenFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), compileMatcher(selector))\n}\n\n// ChildrenMatcher gets the child elements of each element in the Selection,\n// filtered by the specified matcher. It returns a new\n// Selection object containing these elements.\nfunc (s *Selection) ChildrenMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getChildrenNodes(s.Nodes, siblingAll), m)\n}\n\n// Parent gets the parent of each element in the Selection. It returns a\n// new Selection object containing the matched elements.\nfunc (s *Selection) Parent() *Selection {\n\treturn pushStack(s, getParentNodes(s.Nodes))\n}\n\n// ParentFiltered gets the parent of each element in the Selection filtered by a\n// selector. It returns a new Selection object containing the matched elements.\nfunc (s *Selection) ParentFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getParentNodes(s.Nodes), compileMatcher(selector))\n}\n\n// ParentMatcher gets the parent of each element in the Selection filtered by a\n// matcher. It returns a new Selection object containing the matched elements.\nfunc (s *Selection) ParentMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getParentNodes(s.Nodes), m)\n}\n\n// Closest gets the first element that matches the selector by testing the\n// element itself and traversing up through its ancestors in the DOM tree.\nfunc (s *Selection) Closest(selector string) *Selection {\n\tcs := compileMatcher(selector)\n\treturn s.ClosestMatcher(cs)\n}\n\n// ClosestMatcher gets the first element that matches the matcher by testing the\n// element itself and traversing up through its ancestors in the DOM tree.\nfunc (s *Selection) ClosestMatcher(m Matcher) *Selection {\n\treturn pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node {\n\t\t// For each node in the selection, test the node itself, then each parent\n\t\t// until a match is found.\n\t\tfor ; n != nil; n = n.Parent {\n\t\t\tif m.Match(n) {\n\t\t\t\treturn []*html.Node{n}\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}))\n}\n\n// ClosestNodes gets the first element that matches one of the nodes by testing the\n// element itself and traversing up through its ancestors in the DOM tree.\nfunc (s *Selection) ClosestNodes(nodes ...*html.Node) *Selection {\n\tset := make(map[*html.Node]bool)\n\tfor _, n := range nodes {\n\t\tset[n] = true\n\t}\n\treturn pushStack(s, mapNodes(s.Nodes, func(i int, n *html.Node) []*html.Node {\n\t\t// For each node in the selection, test the node itself, then each parent\n\t\t// until a match is found.\n\t\tfor ; n != nil; n = n.Parent {\n\t\t\tif set[n] {\n\t\t\t\treturn []*html.Node{n}\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}))\n}\n\n// ClosestSelection gets the first element that matches one of the nodes in the\n// Selection by testing the element itself and traversing up through its ancestors\n// in the DOM tree.\nfunc (s *Selection) ClosestSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn pushStack(s, nil)\n\t}\n\treturn s.ClosestNodes(sel.Nodes...)\n}\n\n// Parents gets the ancestors of each element in the current Selection. It\n// returns a new Selection object with the matched elements.\nfunc (s *Selection) Parents() *Selection {\n\treturn pushStack(s, getParentsNodes(s.Nodes, nil, nil))\n}\n\n// ParentsFiltered gets the ancestors of each element in the current\n// Selection. It returns a new Selection object with the matched elements.\nfunc (s *Selection) ParentsFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), compileMatcher(selector))\n}\n\n// ParentsMatcher gets the ancestors of each element in the current\n// Selection. It returns a new Selection object with the matched elements.\nfunc (s *Selection) ParentsMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getParentsNodes(s.Nodes, nil, nil), m)\n}\n\n// ParentsUntil gets the ancestors of each element in the Selection, up to but\n// not including the element matched by the selector. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) ParentsUntil(selector string) *Selection {\n\treturn pushStack(s, getParentsNodes(s.Nodes, compileMatcher(selector), nil))\n}\n\n// ParentsUntilMatcher gets the ancestors of each element in the Selection, up to but\n// not including the element matched by the matcher. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) ParentsUntilMatcher(m Matcher) *Selection {\n\treturn pushStack(s, getParentsNodes(s.Nodes, m, nil))\n}\n\n// ParentsUntilSelection gets the ancestors of each element in the Selection,\n// up to but not including the elements in the specified Selection. It returns a\n// new Selection object containing the matched elements.\nfunc (s *Selection) ParentsUntilSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.Parents()\n\t}\n\treturn s.ParentsUntilNodes(sel.Nodes...)\n}\n\n// ParentsUntilNodes gets the ancestors of each element in the Selection,\n// up to but not including the specified nodes. It returns a\n// new Selection object containing the matched elements.\nfunc (s *Selection) ParentsUntilNodes(nodes ...*html.Node) *Selection {\n\treturn pushStack(s, getParentsNodes(s.Nodes, nil, nodes))\n}\n\n// ParentsFilteredUntil is like ParentsUntil, with the option to filter the\n// results based on a selector string. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) ParentsFilteredUntil(filterSelector, untilSelector string) *Selection {\n\treturn filterAndPush(s, getParentsNodes(s.Nodes, compileMatcher(untilSelector), nil), compileMatcher(filterSelector))\n}\n\n// ParentsFilteredUntilMatcher is like ParentsUntilMatcher, with the option to filter the\n// results based on a matcher. It returns a new Selection object containing the matched elements.\nfunc (s *Selection) ParentsFilteredUntilMatcher(filter, until Matcher) *Selection {\n\treturn filterAndPush(s, getParentsNodes(s.Nodes, until, nil), filter)\n}\n\n// ParentsFilteredUntilSelection is like ParentsUntilSelection, with the\n// option to filter the results based on a selector string. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) ParentsFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {\n\treturn s.ParentsMatcherUntilSelection(compileMatcher(filterSelector), sel)\n}\n\n// ParentsMatcherUntilSelection is like ParentsUntilSelection, with the\n// option to filter the results based on a matcher. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) ParentsMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.ParentsMatcher(filter)\n\t}\n\treturn s.ParentsMatcherUntilNodes(filter, sel.Nodes...)\n}\n\n// ParentsFilteredUntilNodes is like ParentsUntilNodes, with the\n// option to filter the results based on a selector string. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) ParentsFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {\n\treturn filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), compileMatcher(filterSelector))\n}\n\n// ParentsMatcherUntilNodes is like ParentsUntilNodes, with the\n// option to filter the results based on a matcher. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) ParentsMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {\n\treturn filterAndPush(s, getParentsNodes(s.Nodes, nil, nodes), filter)\n}\n\n// Siblings gets the siblings of each element in the Selection. It returns\n// a new Selection object containing the matched elements.\nfunc (s *Selection) Siblings() *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil))\n}\n\n// SiblingsFiltered gets the siblings of each element in the Selection\n// filtered by a selector. It returns a new Selection object containing the\n// matched elements.\nfunc (s *Selection) SiblingsFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), compileMatcher(selector))\n}\n\n// SiblingsMatcher gets the siblings of each element in the Selection\n// filtered by a matcher. It returns a new Selection object containing the\n// matched elements.\nfunc (s *Selection) SiblingsMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingAll, nil, nil), m)\n}\n\n// Next gets the immediately following sibling of each element in the\n// Selection. It returns a new Selection object containing the matched elements.\nfunc (s *Selection) Next() *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil))\n}\n\n// NextFiltered gets the immediately following sibling of each element in the\n// Selection filtered by a selector. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) NextFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), compileMatcher(selector))\n}\n\n// NextMatcher gets the immediately following sibling of each element in the\n// Selection filtered by a matcher. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) NextMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNext, nil, nil), m)\n}\n\n// NextAll gets all the following siblings of each element in the\n// Selection. It returns a new Selection object containing the matched elements.\nfunc (s *Selection) NextAll() *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil))\n}\n\n// NextAllFiltered gets all the following siblings of each element in the\n// Selection filtered by a selector. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) NextAllFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), compileMatcher(selector))\n}\n\n// NextAllMatcher gets all the following siblings of each element in the\n// Selection filtered by a matcher. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) NextAllMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextAll, nil, nil), m)\n}\n\n// Prev gets the immediately preceding sibling of each element in the\n// Selection. It returns a new Selection object containing the matched elements.\nfunc (s *Selection) Prev() *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil))\n}\n\n// PrevFiltered gets the immediately preceding sibling of each element in the\n// Selection filtered by a selector. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) PrevFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), compileMatcher(selector))\n}\n\n// PrevMatcher gets the immediately preceding sibling of each element in the\n// Selection filtered by a matcher. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) PrevMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrev, nil, nil), m)\n}\n\n// PrevAll gets all the preceding siblings of each element in the\n// Selection. It returns a new Selection object containing the matched elements.\nfunc (s *Selection) PrevAll() *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil))\n}\n\n// PrevAllFiltered gets all the preceding siblings of each element in the\n// Selection filtered by a selector. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) PrevAllFiltered(selector string) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), compileMatcher(selector))\n}\n\n// PrevAllMatcher gets all the preceding siblings of each element in the\n// Selection filtered by a matcher. It returns a new Selection object\n// containing the matched elements.\nfunc (s *Selection) PrevAllMatcher(m Matcher) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevAll, nil, nil), m)\n}\n\n// NextUntil gets all following siblings of each element up to but not\n// including the element matched by the selector. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) NextUntil(selector string) *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,\n\t\tcompileMatcher(selector), nil))\n}\n\n// NextUntilMatcher gets all following siblings of each element up to but not\n// including the element matched by the matcher. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) NextUntilMatcher(m Matcher) *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,\n\t\tm, nil))\n}\n\n// NextUntilSelection gets all following siblings of each element up to but not\n// including the element matched by the Selection. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) NextUntilSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.NextAll()\n\t}\n\treturn s.NextUntilNodes(sel.Nodes...)\n}\n\n// NextUntilNodes gets all following siblings of each element up to but not\n// including the element matched by the nodes. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) NextUntilNodes(nodes ...*html.Node) *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingNextUntil,\n\t\tnil, nodes))\n}\n\n// PrevUntil gets all preceding siblings of each element up to but not\n// including the element matched by the selector. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) PrevUntil(selector string) *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,\n\t\tcompileMatcher(selector), nil))\n}\n\n// PrevUntilMatcher gets all preceding siblings of each element up to but not\n// including the element matched by the matcher. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) PrevUntilMatcher(m Matcher) *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,\n\t\tm, nil))\n}\n\n// PrevUntilSelection gets all preceding siblings of each element up to but not\n// including the element matched by the Selection. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) PrevUntilSelection(sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.PrevAll()\n\t}\n\treturn s.PrevUntilNodes(sel.Nodes...)\n}\n\n// PrevUntilNodes gets all preceding siblings of each element up to but not\n// including the element matched by the nodes. It returns a new Selection\n// object containing the matched elements.\nfunc (s *Selection) PrevUntilNodes(nodes ...*html.Node) *Selection {\n\treturn pushStack(s, getSiblingNodes(s.Nodes, siblingPrevUntil,\n\t\tnil, nodes))\n}\n\n// NextFilteredUntil is like NextUntil, with the option to filter\n// the results based on a selector string.\n// It returns a new Selection object containing the matched elements.\nfunc (s *Selection) NextFilteredUntil(filterSelector, untilSelector string) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,\n\t\tcompileMatcher(untilSelector), nil), compileMatcher(filterSelector))\n}\n\n// NextFilteredUntilMatcher is like NextUntilMatcher, with the option to filter\n// the results based on a matcher.\n// It returns a new Selection object containing the matched elements.\nfunc (s *Selection) NextFilteredUntilMatcher(filter, until Matcher) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,\n\t\tuntil, nil), filter)\n}\n\n// NextFilteredUntilSelection is like NextUntilSelection, with the\n// option to filter the results based on a selector string. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) NextFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {\n\treturn s.NextMatcherUntilSelection(compileMatcher(filterSelector), sel)\n}\n\n// NextMatcherUntilSelection is like NextUntilSelection, with the\n// option to filter the results based on a matcher. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) NextMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.NextMatcher(filter)\n\t}\n\treturn s.NextMatcherUntilNodes(filter, sel.Nodes...)\n}\n\n// NextFilteredUntilNodes is like NextUntilNodes, with the\n// option to filter the results based on a selector string. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) NextFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,\n\t\tnil, nodes), compileMatcher(filterSelector))\n}\n\n// NextMatcherUntilNodes is like NextUntilNodes, with the\n// option to filter the results based on a matcher. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) NextMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingNextUntil,\n\t\tnil, nodes), filter)\n}\n\n// PrevFilteredUntil is like PrevUntil, with the option to filter\n// the results based on a selector string.\n// It returns a new Selection object containing the matched elements.\nfunc (s *Selection) PrevFilteredUntil(filterSelector, untilSelector string) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,\n\t\tcompileMatcher(untilSelector), nil), compileMatcher(filterSelector))\n}\n\n// PrevFilteredUntilMatcher is like PrevUntilMatcher, with the option to filter\n// the results based on a matcher.\n// It returns a new Selection object containing the matched elements.\nfunc (s *Selection) PrevFilteredUntilMatcher(filter, until Matcher) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,\n\t\tuntil, nil), filter)\n}\n\n// PrevFilteredUntilSelection is like PrevUntilSelection, with the\n// option to filter the results based on a selector string. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) PrevFilteredUntilSelection(filterSelector string, sel *Selection) *Selection {\n\treturn s.PrevMatcherUntilSelection(compileMatcher(filterSelector), sel)\n}\n\n// PrevMatcherUntilSelection is like PrevUntilSelection, with the\n// option to filter the results based on a matcher. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) PrevMatcherUntilSelection(filter Matcher, sel *Selection) *Selection {\n\tif sel == nil {\n\t\treturn s.PrevMatcher(filter)\n\t}\n\treturn s.PrevMatcherUntilNodes(filter, sel.Nodes...)\n}\n\n// PrevFilteredUntilNodes is like PrevUntilNodes, with the\n// option to filter the results based on a selector string. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) PrevFilteredUntilNodes(filterSelector string, nodes ...*html.Node) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,\n\t\tnil, nodes), compileMatcher(filterSelector))\n}\n\n// PrevMatcherUntilNodes is like PrevUntilNodes, with the\n// option to filter the results based on a matcher. It returns a new\n// Selection object containing the matched elements.\nfunc (s *Selection) PrevMatcherUntilNodes(filter Matcher, nodes ...*html.Node) *Selection {\n\treturn filterAndPush(s, getSiblingNodes(s.Nodes, siblingPrevUntil,\n\t\tnil, nodes), filter)\n}\n\n// Filter and push filters the nodes based on a matcher, and pushes the results\n// on the stack, with the srcSel as previous selection.\nfunc filterAndPush(srcSel *Selection, nodes []*html.Node, m Matcher) *Selection {\n\t// Create a temporary Selection with the specified nodes to filter using winnow\n\tsel := &Selection{nodes, srcSel.document, nil}\n\t// Filter based on matcher and push on stack\n\treturn pushStack(srcSel, winnow(sel, m, true))\n}\n\n// Internal implementation of Find that return raw nodes.\nfunc findWithMatcher(nodes []*html.Node, m Matcher) []*html.Node {\n\t// Map nodes to find the matches within the children of each node\n\treturn mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {\n\t\t// Go down one level, becausejQuery's Find selects only within descendants\n\t\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\t\tif c.Type == html.ElementNode {\n\t\t\t\tresult = append(result, m.MatchAll(c)...)\n\t\t\t}\n\t\t}\n\t\treturn\n\t})\n}\n\n// Internal implementation to get all parent nodes, stopping at the specified\n// node (or nil if no stop).\nfunc getParentsNodes(nodes []*html.Node, stopm Matcher, stopNodes []*html.Node) []*html.Node {\n\treturn mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {\n\t\tfor p := n.Parent; p != nil; p = p.Parent {\n\t\t\tsel := newSingleSelection(p, nil)\n\t\t\tif stopm != nil {\n\t\t\t\tif sel.IsMatcher(stopm) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else if len(stopNodes) > 0 {\n\t\t\t\tif sel.IsNodes(stopNodes...) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif p.Type == html.ElementNode {\n\t\t\t\tresult = append(result, p)\n\t\t\t}\n\t\t}\n\t\treturn\n\t})\n}\n\n// Internal implementation of sibling nodes that return a raw slice of matches.\nfunc getSiblingNodes(nodes []*html.Node, st siblingType, untilm Matcher, untilNodes []*html.Node) []*html.Node {\n\tvar f func(*html.Node) bool\n\n\t// If the requested siblings are ...Until, create the test function to\n\t// determine if the until condition is reached (returns true if it is)\n\tif st == siblingNextUntil || st == siblingPrevUntil {\n\t\tf = func(n *html.Node) bool {\n\t\t\tif untilm != nil {\n\t\t\t\t// Matcher-based condition\n\t\t\t\tsel := newSingleSelection(n, nil)\n\t\t\t\treturn sel.IsMatcher(untilm)\n\t\t\t} else if len(untilNodes) > 0 {\n\t\t\t\t// Nodes-based condition\n\t\t\t\tsel := newSingleSelection(n, nil)\n\t\t\t\treturn sel.IsNodes(untilNodes...)\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn mapNodes(nodes, func(i int, n *html.Node) []*html.Node {\n\t\treturn getChildrenWithSiblingType(n.Parent, st, n, f)\n\t})\n}\n\n// Gets the children nodes of each node in the specified slice of nodes,\n// based on the sibling type request.\nfunc getChildrenNodes(nodes []*html.Node, st siblingType) []*html.Node {\n\treturn mapNodes(nodes, func(i int, n *html.Node) []*html.Node {\n\t\treturn getChildrenWithSiblingType(n, st, nil, nil)\n\t})\n}\n\n// Gets the children of the specified parent, based on the requested sibling\n// type, skipping a specified node if required.\nfunc getChildrenWithSiblingType(parent *html.Node, st siblingType, skipNode *html.Node,\n\tuntilFunc func(*html.Node) bool) (result []*html.Node) {\n\n\t// Create the iterator function\n\tvar iter = func(cur *html.Node) (ret *html.Node) {\n\t\t// Based on the sibling type requested, iterate the right way\n\t\tfor {\n\t\t\tswitch st {\n\t\t\tcase siblingAll, siblingAllIncludingNonElements:\n\t\t\t\tif cur == nil {\n\t\t\t\t\t// First iteration, start with first child of parent\n\t\t\t\t\t// Skip node if required\n\t\t\t\t\tif ret = parent.FirstChild; ret == skipNode && skipNode != nil {\n\t\t\t\t\t\tret = skipNode.NextSibling\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Skip node if required\n\t\t\t\t\tif ret = cur.NextSibling; ret == skipNode && skipNode != nil {\n\t\t\t\t\t\tret = skipNode.NextSibling\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase siblingPrev, siblingPrevAll, siblingPrevUntil:\n\t\t\t\tif cur == nil {\n\t\t\t\t\t// Start with previous sibling of the skip node\n\t\t\t\t\tret = skipNode.PrevSibling\n\t\t\t\t} else {\n\t\t\t\t\tret = cur.PrevSibling\n\t\t\t\t}\n\t\t\tcase siblingNext, siblingNextAll, siblingNextUntil:\n\t\t\t\tif cur == nil {\n\t\t\t\t\t// Start with next sibling of the skip node\n\t\t\t\t\tret = skipNode.NextSibling\n\t\t\t\t} else {\n\t\t\t\t\tret = cur.NextSibling\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tpanic(\"Invalid sibling type.\")\n\t\t\t}\n\t\t\tif ret == nil || ret.Type == html.ElementNode || st == siblingAllIncludingNonElements {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Not a valid node, try again from this one\n\t\t\tcur = ret\n\t\t}\n\t}\n\n\tfor c := iter(nil); c != nil; c = iter(c) {\n\t\t// If this is an ...Until case, test before append (returns true\n\t\t// if the until condition is reached)\n\t\tif st == siblingNextUntil || st == siblingPrevUntil {\n\t\t\tif untilFunc(c) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tresult = append(result, c)\n\t\tif st == siblingNext || st == siblingPrev {\n\t\t\t// Only one node was requested (immediate next or previous), so exit\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\n// Internal implementation of parent nodes that return a raw slice of Nodes.\nfunc getParentNodes(nodes []*html.Node) []*html.Node {\n\treturn mapNodes(nodes, func(i int, n *html.Node) []*html.Node {\n\t\tif n.Parent != nil && n.Parent.Type == html.ElementNode {\n\t\t\treturn []*html.Node{n.Parent}\n\t\t}\n\t\treturn nil\n\t})\n}\n\n// Internal map function used by many traversing methods. Takes the source nodes\n// to iterate on and the mapping function that returns an array of nodes.\n// Returns an array of nodes mapped by calling the callback function once for\n// each node in the source nodes.\nfunc mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) {\n\tset := make(map[*html.Node]bool)\n\tfor i, n := range nodes {\n\t\tif vals := f(i, n); len(vals) > 0 {\n\t\t\tresult = appendWithoutDuplicates(result, vals, set)\n\t\t}\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/type.go",
    "content": "package goquery\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\n\t\"github.com/andybalholm/cascadia\"\n\t\"golang.org/x/net/html\"\n)\n\n// Document represents an HTML document to be manipulated. Unlike jQuery, which\n// is loaded as part of a DOM document, and thus acts upon its containing\n// document, GoQuery doesn't know which HTML document to act upon. So it needs\n// to be told, and that's what the Document class is for. It holds the root\n// document node to manipulate, and can make selections on this document.\ntype Document struct {\n\t*Selection\n\tUrl      *url.URL\n\trootNode *html.Node\n}\n\n// NewDocumentFromNode is a Document constructor that takes a root html Node\n// as argument.\nfunc NewDocumentFromNode(root *html.Node) *Document {\n\treturn newDocument(root, nil)\n}\n\n// NewDocument is a Document constructor that takes a string URL as argument.\n// It loads the specified document, parses it, and stores the root Document\n// node, ready to be manipulated.\n//\n// Deprecated: Use the net/http standard library package to make the request\n// and validate the response before calling goquery.NewDocumentFromReader\n// with the response's body.\nfunc NewDocument(url string) (*Document, error) {\n\t// Load the URL\n\tres, e := http.Get(url)\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\treturn NewDocumentFromResponse(res)\n}\n\n// NewDocumentFromReader returns a Document from an io.Reader.\n// It returns an error as second value if the reader's data cannot be parsed\n// as html. It does not check if the reader is also an io.Closer, the\n// provided reader is never closed by this call. It is the responsibility\n// of the caller to close it if required.\nfunc NewDocumentFromReader(r io.Reader) (*Document, error) {\n\troot, e := html.Parse(r)\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\treturn newDocument(root, nil), nil\n}\n\n// NewDocumentFromResponse is another Document constructor that takes an http response as argument.\n// It loads the specified response's document, parses it, and stores the root Document\n// node, ready to be manipulated. The response's body is closed on return.\n//\n// Deprecated: Use goquery.NewDocumentFromReader with the response's body.\nfunc NewDocumentFromResponse(res *http.Response) (*Document, error) {\n\tif res == nil {\n\t\treturn nil, errors.New(\"Response is nil\")\n\t}\n\tdefer res.Body.Close()\n\tif res.Request == nil {\n\t\treturn nil, errors.New(\"Response.Request is nil\")\n\t}\n\n\t// Parse the HTML into nodes\n\troot, e := html.Parse(res.Body)\n\tif e != nil {\n\t\treturn nil, e\n\t}\n\n\t// Create and fill the document\n\treturn newDocument(root, res.Request.URL), nil\n}\n\n// CloneDocument creates a deep-clone of a document.\nfunc CloneDocument(doc *Document) *Document {\n\treturn newDocument(cloneNode(doc.rootNode), doc.Url)\n}\n\n// Private constructor, make sure all fields are correctly filled.\nfunc newDocument(root *html.Node, url *url.URL) *Document {\n\t// Create and fill the document\n\td := &Document{nil, url, root}\n\td.Selection = newSingleSelection(root, d)\n\treturn d\n}\n\n// Selection represents a collection of nodes matching some criteria. The\n// initial Selection can be created by using Document.Find, and then\n// manipulated using the jQuery-like chainable syntax and methods.\ntype Selection struct {\n\tNodes    []*html.Node\n\tdocument *Document\n\tprevSel  *Selection\n}\n\n// Helper constructor to create an empty selection\nfunc newEmptySelection(doc *Document) *Selection {\n\treturn &Selection{nil, doc, nil}\n}\n\n// Helper constructor to create a selection of only one node\nfunc newSingleSelection(node *html.Node, doc *Document) *Selection {\n\treturn &Selection{[]*html.Node{node}, doc, nil}\n}\n\n// Matcher is an interface that defines the methods to match\n// HTML nodes against a compiled selector string. Cascadia's\n// Selector implements this interface.\ntype Matcher interface {\n\tMatch(*html.Node) bool\n\tMatchAll(*html.Node) []*html.Node\n\tFilter([]*html.Node) []*html.Node\n}\n\n// Single compiles a selector string to a Matcher that stops after the first\n// match is found.\n//\n// By default, Selection.Find and other functions that accept a selector string\n// to select nodes will use all matches corresponding to that selector. By\n// using the Matcher returned by Single, at most the first match will be\n// selected.\n//\n// For example, those two statements are semantically equivalent:\n//\n//     sel1 := doc.Find(\"a\").First()\n//     sel2 := doc.FindMatcher(goquery.Single(\"a\"))\n//\n// The one using Single is optimized to be potentially much faster on large\n// documents.\n//\n// Only the behaviour of the MatchAll method of the Matcher interface is\n// altered compared to standard Matchers. This means that the single-selection\n// property of the Matcher only applies for Selection methods where the Matcher\n// is used to select nodes, not to filter or check if a node matches the\n// Matcher - in those cases, the behaviour of the Matcher is unchanged (e.g.\n// FilterMatcher(Single(\"div\")) will still result in a Selection with multiple\n// \"div\"s if there were many \"div\"s in the Selection to begin with).\nfunc Single(selector string) Matcher {\n\treturn singleMatcher{compileMatcher(selector)}\n}\n\n// SingleMatcher returns a Matcher matches the same nodes as m, but that stops\n// after the first match is found.\n//\n// See the documentation of function Single for more details.\nfunc SingleMatcher(m Matcher) Matcher {\n\tif _, ok := m.(singleMatcher); ok {\n\t\t// m is already a singleMatcher\n\t\treturn m\n\t}\n\treturn singleMatcher{m}\n}\n\n// compileMatcher compiles the selector string s and returns\n// the corresponding Matcher. If s is an invalid selector string,\n// it returns a Matcher that fails all matches.\nfunc compileMatcher(s string) Matcher {\n\tcs, err := cascadia.Compile(s)\n\tif err != nil {\n\t\treturn invalidMatcher{}\n\t}\n\treturn cs\n}\n\ntype singleMatcher struct {\n\tMatcher\n}\n\nfunc (m singleMatcher) MatchAll(n *html.Node) []*html.Node {\n\t// Optimized version - stops finding at the first match (cascadia-compiled\n\t// matchers all use this code path).\n\tif mm, ok := m.Matcher.(interface{ MatchFirst(*html.Node) *html.Node }); ok {\n\t\tnode := mm.MatchFirst(n)\n\t\tif node == nil {\n\t\t\treturn nil\n\t\t}\n\t\treturn []*html.Node{node}\n\t}\n\n\t// Fallback version, for e.g. test mocks that don't provide the MatchFirst\n\t// method.\n\tnodes := m.Matcher.MatchAll(n)\n\tif len(nodes) > 0 {\n\t\treturn nodes[:1:1]\n\t}\n\treturn nil\n}\n\n// invalidMatcher is a Matcher that always fails to match.\ntype invalidMatcher struct{}\n\nfunc (invalidMatcher) Match(n *html.Node) bool             { return false }\nfunc (invalidMatcher) MatchAll(n *html.Node) []*html.Node  { return nil }\nfunc (invalidMatcher) Filter(ns []*html.Node) []*html.Node { return nil }\n"
  },
  {
    "path": "vendor/github.com/PuerkitoBio/goquery/utilities.go",
    "content": "package goquery\n\nimport (\n\t\"io\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// used to determine if a set (map[*html.Node]bool) should be used\n// instead of iterating over a slice. The set uses more memory and\n// is slower than slice iteration for small N.\nconst minNodesForSet = 1000\n\nvar nodeNames = []string{\n\thtml.ErrorNode:    \"#error\",\n\thtml.TextNode:     \"#text\",\n\thtml.DocumentNode: \"#document\",\n\thtml.CommentNode:  \"#comment\",\n}\n\n// NodeName returns the node name of the first element in the selection.\n// It tries to behave in a similar way as the DOM's nodeName property\n// (https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeName).\n//\n// Go's net/html package defines the following node types, listed with\n// the corresponding returned value from this function:\n//\n//\tErrorNode : #error\n//\tTextNode : #text\n//\tDocumentNode : #document\n//\tElementNode : the element's tag name\n//\tCommentNode : #comment\n//\tDoctypeNode : the name of the document type\nfunc NodeName(s *Selection) string {\n\tif s.Length() == 0 {\n\t\treturn \"\"\n\t}\n\treturn nodeName(s.Get(0))\n}\n\n// nodeName returns the node name of the given html node.\n// See NodeName for additional details on behaviour.\nfunc nodeName(node *html.Node) string {\n\tif node == nil {\n\t\treturn \"\"\n\t}\n\n\tswitch node.Type {\n\tcase html.ElementNode, html.DoctypeNode:\n\t\treturn node.Data\n\tdefault:\n\t\tif int(node.Type) < len(nodeNames) {\n\t\t\treturn nodeNames[node.Type]\n\t\t}\n\t\treturn \"\"\n\t}\n}\n\n// Render renders the HTML of the first item in the selection and writes it to\n// the writer. It behaves the same as OuterHtml but writes to w instead of\n// returning the string.\nfunc Render(w io.Writer, s *Selection) error {\n\tif s.Length() == 0 {\n\t\treturn nil\n\t}\n\tn := s.Get(0)\n\treturn html.Render(w, n)\n}\n\n// OuterHtml returns the outer HTML rendering of the first item in\n// the selection - that is, the HTML including the first element's\n// tag and attributes.\n//\n// Unlike Html, this is a function and not a method on the Selection,\n// because this is not a jQuery method (in javascript-land, this is\n// a property provided by the DOM).\nfunc OuterHtml(s *Selection) (string, error) {\n\tvar builder strings.Builder\n\tif err := Render(&builder, s); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn builder.String(), nil\n}\n\n// Loop through all container nodes to search for the target node.\nfunc sliceContains(container []*html.Node, contained *html.Node) bool {\n\tfor _, n := range container {\n\t\tif nodeContains(n, contained) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// Checks if the contained node is within the container node.\nfunc nodeContains(container *html.Node, contained *html.Node) bool {\n\t// Check if the parent of the contained node is the container node, traversing\n\t// upward until the top is reached, or the container is found.\n\tfor contained = contained.Parent; contained != nil; contained = contained.Parent {\n\t\tif container == contained {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Checks if the target node is in the slice of nodes.\nfunc isInSlice(slice []*html.Node, node *html.Node) bool {\n\treturn indexInSlice(slice, node) > -1\n}\n\n// Returns the index of the target node in the slice, or -1.\nfunc indexInSlice(slice []*html.Node, node *html.Node) int {\n\tif node != nil {\n\t\tfor i, n := range slice {\n\t\t\tif n == node {\n\t\t\t\treturn i\n\t\t\t}\n\t\t}\n\t}\n\treturn -1\n}\n\n// Appends the new nodes to the target slice, making sure no duplicate is added.\n// There is no check to the original state of the target slice, so it may still\n// contain duplicates. The target slice is returned because append() may create\n// a new underlying array. If targetSet is nil, a local set is created with the\n// target if len(target) + len(nodes) is greater than minNodesForSet.\nfunc appendWithoutDuplicates(target []*html.Node, nodes []*html.Node, targetSet map[*html.Node]bool) []*html.Node {\n\t// if there are not that many nodes, don't use the map, faster to just use nested loops\n\t// (unless a non-nil targetSet is passed, in which case the caller knows better).\n\tif targetSet == nil && len(target)+len(nodes) < minNodesForSet {\n\t\tfor _, n := range nodes {\n\t\t\tif !isInSlice(target, n) {\n\t\t\t\ttarget = append(target, n)\n\t\t\t}\n\t\t}\n\t\treturn target\n\t}\n\n\t// if a targetSet is passed, then assume it is reliable, otherwise create one\n\t// and initialize it with the current target contents.\n\tif targetSet == nil {\n\t\ttargetSet = make(map[*html.Node]bool, len(target))\n\t\tfor _, n := range target {\n\t\t\ttargetSet[n] = true\n\t\t}\n\t}\n\tfor _, n := range nodes {\n\t\tif !targetSet[n] {\n\t\t\ttarget = append(target, n)\n\t\t\ttargetSet[n] = true\n\t\t}\n\t}\n\n\treturn target\n}\n\n// Loop through a selection, returning only those nodes that pass the predicate\n// function.\nfunc grep(sel *Selection, predicate func(i int, s *Selection) bool) (result []*html.Node) {\n\tfor i, n := range sel.Nodes {\n\t\tif predicate(i, newSingleSelection(n, sel.document)) {\n\t\t\tresult = append(result, n)\n\t\t}\n\t}\n\treturn result\n}\n\n// Creates a new Selection object based on the specified nodes, and keeps the\n// source Selection object on the stack (linked list).\nfunc pushStack(fromSel *Selection, nodes []*html.Node) *Selection {\n\tresult := &Selection{nodes, fromSel.document, fromSel}\n\treturn result\n}\n"
  },
  {
    "path": "vendor/github.com/Soontao/goHttpDigestClient/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Theo Sun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/Soontao/goHttpDigestClient/challenge.go",
    "content": "package goHttpDigestClient\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst (\n\tKEY_DIGEST           = \"Digest\"\n\tKEY_AUTH_SCHEMA      = \"auth_schema\"\n\tKEY_QOP              = \"qop\"\n\tKEY_NONCE            = \"nonce\"\n\tKEY_CNONCE           = \"cnonce\"\n\tKEY_USERNAME         = \"username\"\n\tKEY_NONCE_COUNT      = \"nc\"\n\tKEY_OPAQUE           = \"opaque\"\n\tKEY_RESPONSE         = \"response\"\n\tKEY_REALM            = \"realm\"\n\tKEY_AUTHORIZATION    = \"Authorization\"\n\tKEY_URI              = \"uri\"\n\tKEY_WWW_Authenticate = \"WWW-Authenticate\"\n)\n\n//The 401 (Unauthorized) response message is used by an origin server\n//to challenge the authorization of a user agent.\n//\n// And the CHALLENGE will include informations about auth\ntype Challenge map[string]string\n\nfunc NewChallenge(wwwAuthHeader string) Challenge {\n\tr := Challenge{}\n\twwwAuthArr := strings.Split(strings.Replace(wwwAuthHeader, \",\", \"\", -1), \" \")\n\twwwAuthArrLen := len(wwwAuthArr)\n\tif wwwAuthArrLen > 1 {\n\t\tr[KEY_AUTH_SCHEMA] = wwwAuthArr[0]\n\t\tfor i := 1; i < wwwAuthArrLen; i++ {\n\t\t\titemArr := strings.Split(wwwAuthArr[i], \"=\")\n\t\t\tr.SetChallengeItem(itemArr[0], itemArr[1])\n\t\t}\n\t}\n\treturn r\n}\n\nfunc (info Challenge) IsDigestAuth() bool {\n\treturn info[KEY_AUTH_SCHEMA] == KEY_DIGEST\n}\n\nfunc (info Challenge) SetChallengeItem(itemKey string, itemValue string) {\n\tinfo[itemKey] = itemValue\n}\n\nfunc (info Challenge) GetChallengeItemPure(itemKey string) string {\n\treturn strings.Replace(info[itemKey], `\"`, \"\", -1)\n}\n\n// some specific key, will add qutation mark\nfunc (info Challenge) GetChallengeItemFormat(itemKey string) string {\n\tr := info.GetChallengeItemPure(itemKey)\n\tswitch itemKey {\n\tcase KEY_QOP, KEY_NONCE_COUNT:\n\t\treturn r\n\tdefault:\n\t\treturn fmt.Sprintf(`\"%s\"`, r)\n\t}\n}\n\n// format challenge header to authorization header\n//\n// MAYBE you should computeResponseFirst()\nfunc (info Challenge) ToAuthorizationStr() string {\n\tauth_schema := KEY_DIGEST\n\tauthorization_content := \"\"\n\t// how to specify the sequence\n\tfor k, _ := range info {\n\t\tif k != KEY_AUTH_SCHEMA {\n\t\t\tauthorization_content += fmt.Sprintf(\", %s=%s\", k, info.GetChallengeItemFormat(k))\n\t\t}\n\t}\n\treturn auth_schema + strings.Replace(authorization_content, \",\", \"\", 1)\n}\n\n// base challenge to compute the response, and the response will be checking by server\nfunc (h Challenge) ComputeResponse(method, uri, entity, username, password string) Challenge {\n\tqop := h.GetChallengeItemPure(KEY_QOP)\n\trealm := h.GetChallengeItemPure(KEY_REALM)\n\tnonce := h.GetChallengeItemPure(KEY_NONCE)\n\tnonceCount := h.GetChallengeItemPure(KEY_NONCE_COUNT)\n\tcNonce := h.GetChallengeItemPure(KEY_CNONCE)\n\tresponse, cNonce, nonceCount := computeResponse(qop, realm, nonce, nonceCount, cNonce, method, uri, entity, username, password)\n\th.SetChallengeItem(KEY_USERNAME, username)\n\th.SetChallengeItem(KEY_URI, uri)\n\th.SetChallengeItem(KEY_CNONCE, cNonce)\n\th.SetChallengeItem(KEY_NONCE_COUNT, nonceCount)\n\th.SetChallengeItem(KEY_RESPONSE, response)\n\treturn h\n}\n"
  },
  {
    "path": "vendor/github.com/Soontao/goHttpDigestClient/client.go",
    "content": "package goHttpDigestClient\n\nimport (\n\t\"io\"\n\t\"io/ioutil\"\n\t\"net/http\"\n)\n\n// if option is set, get challenge at construct time\n// if option not set, ever digest auth will send 2 request\ntype Client struct {\n\tis_init bool\n\toption  ClientOption\n\thttp.Client\n}\n\ntype ClientOption struct {\n\tusername string\n\tpassword string\n}\n\n// create new Client instance\nfunc NewClient(username, password string) *Client {\n\topt := &ClientOption{username: username, password: password}\n\t// here need more attention\n\treturn &Client{option: *opt, is_init: false}\n}\n\nfunc GetChallengeFromHeader(h *http.Header) Challenge {\n\treturn NewChallenge(h.Get(KEY_WWW_Authenticate))\n}\n\nfunc (c *Client) Do(req *http.Request, opt *ClientOption) (*http.Response, error) {\n\tres, err := c.Client.Do(req)\n\tif res.StatusCode == http.StatusUnauthorized {\n\t\tchallenge := GetChallengeFromHeader(&res.Header)\n\t\tchallenge.ComputeResponse(req.Method, req.URL.RequestURI(), getStrFromIO(req.Body), opt.username, opt.password)\n\t\tauthorization := challenge.ToAuthorizationStr()\n\t\treq.Header.Set(KEY_AUTHORIZATION, authorization)\n\t\treturn c.Client.Do(req)\n\t} else {\n\t\treturn res, err\n\t}\n}\n\n// From ReadCloser to string\nfunc getStrFromIO(r io.ReadCloser) string {\n\tif r == nil {\n\t\treturn \"\"\n\t}\n\tif b, err := ioutil.ReadAll(r); err == nil {\n\t\treturn string(b)\n\t} else {\n\t\treturn \"\"\n\t}\n}\n\n// static Defualt Client\nvar DefaultClient = &Client{is_init: true}\n\n// Default Client Do　Request\nfunc Do(req *http.Request, opt *ClientOption) (*http.Response, error) {\n\treturn DefaultClient.Do(req, opt)\n}\n"
  },
  {
    "path": "vendor/github.com/Soontao/goHttpDigestClient/rfc2617.go",
    "content": "package goHttpDigestClient\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"github.com/nu7hatch/gouuid\"\n\t\"strings\"\n)\n\n// hash any string to md5 hex string\nfunc toMd5(s string) string {\n\tsByte := []byte(s)\n\treturn fmt.Sprintf(\"%x\", md5.Sum(sByte))\n}\n\n//In RFC 2617\n//\n//HA1 is equal to MD5(\"username:realm:password\")\nfunc computeHa1(username, realm, password string) string {\n\treturn toMd5(fmt.Sprintf(\"%s:%s:%s\", username, realm, password))\n}\n\nfunc computeHa2(qop, method, digestUri, entity string) string {\n\tswitch qop {\n\tcase \"auth-int\":\n\t\treturn toMd5(fmt.Sprintf(\"%s:%s:%s\", method, digestUri, toMd5(entity)))\n\tdefault:\n\t\treturn toMd5(fmt.Sprintf(\"%s:%s\", method, digestUri))\n\t}\n}\n\nfunc computeResponse(qop, realm, nonce, nonceCount, clientNonce, method, uri, entity, username, password string) (response, cNonce, nc string) {\n\tif clientNonce == \"\" {\n\t\tnewUUID, _ := uuid.NewV4()\n\t\tclientNonce = strings.Replace(newUUID.String(), \"-\", \"\", -1)\n\t}\n\tif nonceCount == \"\" {\n\t\tnonceCount = \"00000001\"\n\t}\n\tha1 := computeHa1(username, realm, password)\n\tha2 := computeHa2(qop, method, uri, entity)\n\tswitch qop {\n\tcase \"auth\", \"auth-int\":\n\t\treturn toMd5(fmt.Sprintf(\"%s:%s:%s:%s:%s:%s\", ha1, nonce, nonceCount, clientNonce, qop, ha2)), clientNonce, nonceCount\n\tdefault:\n\t\treturn toMd5(fmt.Sprintf(\"%s:%s:%s\", ha1, nonce, ha2)), clientNonce, nonceCount\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/LICENSE",
    "content": "Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/backward_references.go",
    "content": "package brotli\n\nimport (\n\t\"sync\"\n)\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Function to find backward reference copies. */\n\nfunc computeDistanceCode(distance uint, max_distance uint, dist_cache []int) uint {\n\tif distance <= max_distance {\n\t\tvar distance_plus_3 uint = distance + 3\n\t\tvar offset0 uint = distance_plus_3 - uint(dist_cache[0])\n\t\tvar offset1 uint = distance_plus_3 - uint(dist_cache[1])\n\t\tif distance == uint(dist_cache[0]) {\n\t\t\treturn 0\n\t\t} else if distance == uint(dist_cache[1]) {\n\t\t\treturn 1\n\t\t} else if offset0 < 7 {\n\t\t\treturn (0x9750468 >> (4 * offset0)) & 0xF\n\t\t} else if offset1 < 7 {\n\t\t\treturn (0xFDB1ACE >> (4 * offset1)) & 0xF\n\t\t} else if distance == uint(dist_cache[2]) {\n\t\t\treturn 2\n\t\t} else if distance == uint(dist_cache[3]) {\n\t\t\treturn 3\n\t\t}\n\t}\n\n\treturn distance + numDistanceShortCodes - 1\n}\n\nvar hasherSearchResultPool sync.Pool\n\nfunc createBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher hasherHandle, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {\n\tvar max_backward_limit uint = maxBackwardLimit(params.lgwin)\n\tvar insert_length uint = *last_insert_len\n\tvar pos_end uint = position + num_bytes\n\tvar store_end uint\n\tif num_bytes >= hasher.StoreLookahead() {\n\t\tstore_end = position + num_bytes - hasher.StoreLookahead() + 1\n\t} else {\n\t\tstore_end = position\n\t}\n\tvar random_heuristics_window_size uint = literalSpreeLengthForSparseSearch(params)\n\tvar apply_random_heuristics uint = position + random_heuristics_window_size\n\tvar gap uint = 0\n\t/* Set maximum distance, see section 9.1. of the spec. */\n\n\tconst kMinScore uint = scoreBase + 100\n\n\t/* For speed up heuristics for random data. */\n\n\t/* Minimum score to accept a backward reference. */\n\thasher.PrepareDistanceCache(dist_cache)\n\tsr2, _ := hasherSearchResultPool.Get().(*hasherSearchResult)\n\tif sr2 == nil {\n\t\tsr2 = &hasherSearchResult{}\n\t}\n\tsr, _ := hasherSearchResultPool.Get().(*hasherSearchResult)\n\tif sr == nil {\n\t\tsr = &hasherSearchResult{}\n\t}\n\n\tfor position+hasher.HashTypeLength() < pos_end {\n\t\tvar max_length uint = pos_end - position\n\t\tvar max_distance uint = brotli_min_size_t(position, max_backward_limit)\n\t\tsr.len = 0\n\t\tsr.len_code_delta = 0\n\t\tsr.distance = 0\n\t\tsr.score = kMinScore\n\t\thasher.FindLongestMatch(&params.dictionary, ringbuffer, ringbuffer_mask, dist_cache, position, max_length, max_distance, gap, params.dist.max_distance, sr)\n\t\tif sr.score > kMinScore {\n\t\t\t/* Found a match. Let's look for something even better ahead. */\n\t\t\tvar delayed_backward_references_in_row int = 0\n\t\t\tmax_length--\n\t\t\tfor ; ; max_length-- {\n\t\t\t\tvar cost_diff_lazy uint = 175\n\t\t\t\tif params.quality < minQualityForExtensiveReferenceSearch {\n\t\t\t\t\tsr2.len = brotli_min_size_t(sr.len-1, max_length)\n\t\t\t\t} else {\n\t\t\t\t\tsr2.len = 0\n\t\t\t\t}\n\t\t\t\tsr2.len_code_delta = 0\n\t\t\t\tsr2.distance = 0\n\t\t\t\tsr2.score = kMinScore\n\t\t\t\tmax_distance = brotli_min_size_t(position+1, max_backward_limit)\n\t\t\t\thasher.FindLongestMatch(&params.dictionary, ringbuffer, ringbuffer_mask, dist_cache, position+1, max_length, max_distance, gap, params.dist.max_distance, sr2)\n\t\t\t\tif sr2.score >= sr.score+cost_diff_lazy {\n\t\t\t\t\t/* Ok, let's just write one byte for now and start a match from the\n\t\t\t\t\t   next byte. */\n\t\t\t\t\tposition++\n\n\t\t\t\t\tinsert_length++\n\t\t\t\t\t*sr = *sr2\n\t\t\t\t\tdelayed_backward_references_in_row++\n\t\t\t\t\tif delayed_backward_references_in_row < 4 && position+hasher.HashTypeLength() < pos_end {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tapply_random_heuristics = position + 2*sr.len + random_heuristics_window_size\n\t\t\tmax_distance = brotli_min_size_t(position, max_backward_limit)\n\t\t\t{\n\t\t\t\t/* The first 16 codes are special short-codes,\n\t\t\t\t   and the minimum offset is 1. */\n\t\t\t\tvar distance_code uint = computeDistanceCode(sr.distance, max_distance+gap, dist_cache)\n\t\t\t\tif (sr.distance <= (max_distance + gap)) && distance_code > 0 {\n\t\t\t\t\tdist_cache[3] = dist_cache[2]\n\t\t\t\t\tdist_cache[2] = dist_cache[1]\n\t\t\t\t\tdist_cache[1] = dist_cache[0]\n\t\t\t\t\tdist_cache[0] = int(sr.distance)\n\t\t\t\t\thasher.PrepareDistanceCache(dist_cache)\n\t\t\t\t}\n\n\t\t\t\t*commands = append(*commands, makeCommand(&params.dist, insert_length, sr.len, sr.len_code_delta, distance_code))\n\t\t\t}\n\n\t\t\t*num_literals += insert_length\n\t\t\tinsert_length = 0\n\t\t\t/* Put the hash keys into the table, if there are enough bytes left.\n\t\t\t   Depending on the hasher implementation, it can push all positions\n\t\t\t   in the given range or only a subset of them.\n\t\t\t   Avoid hash poisoning with RLE data. */\n\t\t\t{\n\t\t\t\tvar range_start uint = position + 2\n\t\t\t\tvar range_end uint = brotli_min_size_t(position+sr.len, store_end)\n\t\t\t\tif sr.distance < sr.len>>2 {\n\t\t\t\t\trange_start = brotli_min_size_t(range_end, brotli_max_size_t(range_start, position+sr.len-(sr.distance<<2)))\n\t\t\t\t}\n\n\t\t\t\thasher.StoreRange(ringbuffer, ringbuffer_mask, range_start, range_end)\n\t\t\t}\n\n\t\t\tposition += sr.len\n\t\t} else {\n\t\t\tinsert_length++\n\t\t\tposition++\n\n\t\t\t/* If we have not seen matches for a long time, we can skip some\n\t\t\t   match lookups. Unsuccessful match lookups are very very expensive\n\t\t\t   and this kind of a heuristic speeds up compression quite\n\t\t\t   a lot. */\n\t\t\tif position > apply_random_heuristics {\n\t\t\t\t/* Going through uncompressible data, jump. */\n\t\t\t\tif position > apply_random_heuristics+4*random_heuristics_window_size {\n\t\t\t\t\tvar kMargin uint = brotli_max_size_t(hasher.StoreLookahead()-1, 4)\n\t\t\t\t\t/* It is quite a long time since we saw a copy, so we assume\n\t\t\t\t\t   that this data is not compressible, and store hashes less\n\t\t\t\t\t   often. Hashes of non compressible data are less likely to\n\t\t\t\t\t   turn out to be useful in the future, too, so we store less of\n\t\t\t\t\t   them to not to flood out the hash table of good compressible\n\t\t\t\t\t   data. */\n\n\t\t\t\t\tvar pos_jump uint = brotli_min_size_t(position+16, pos_end-kMargin)\n\t\t\t\t\tfor ; position < pos_jump; position += 4 {\n\t\t\t\t\t\thasher.Store(ringbuffer, ringbuffer_mask, position)\n\t\t\t\t\t\tinsert_length += 4\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tvar kMargin uint = brotli_max_size_t(hasher.StoreLookahead()-1, 2)\n\t\t\t\t\tvar pos_jump uint = brotli_min_size_t(position+8, pos_end-kMargin)\n\t\t\t\t\tfor ; position < pos_jump; position += 2 {\n\t\t\t\t\t\thasher.Store(ringbuffer, ringbuffer_mask, position)\n\t\t\t\t\t\tinsert_length += 2\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tinsert_length += pos_end - position\n\t*last_insert_len = insert_length\n\n\thasherSearchResultPool.Put(sr)\n\thasherSearchResultPool.Put(sr2)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/backward_references_hq.go",
    "content": "package brotli\n\nimport \"math\"\n\ntype zopfliNode struct {\n\tlength              uint32\n\tdistance            uint32\n\tdcode_insert_length uint32\n\tu                   struct {\n\t\tcost     float32\n\t\tnext     uint32\n\t\tshortcut uint32\n\t}\n}\n\nconst maxEffectiveDistanceAlphabetSize = 544\n\nconst kInfinity float32 = 1.7e38 /* ~= 2 ^ 127 */\n\nvar kDistanceCacheIndex = []uint32{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}\n\nvar kDistanceCacheOffset = []int{0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3}\n\nfunc initZopfliNodes(array []zopfliNode, length uint) {\n\tvar stub zopfliNode\n\tvar i uint\n\tstub.length = 1\n\tstub.distance = 0\n\tstub.dcode_insert_length = 0\n\tstub.u.cost = kInfinity\n\tfor i = 0; i < length; i++ {\n\t\tarray[i] = stub\n\t}\n}\n\nfunc zopfliNodeCopyLength(self *zopfliNode) uint32 {\n\treturn self.length & 0x1FFFFFF\n}\n\nfunc zopfliNodeLengthCode(self *zopfliNode) uint32 {\n\tvar modifier uint32 = self.length >> 25\n\treturn zopfliNodeCopyLength(self) + 9 - modifier\n}\n\nfunc zopfliNodeCopyDistance(self *zopfliNode) uint32 {\n\treturn self.distance\n}\n\nfunc zopfliNodeDistanceCode(self *zopfliNode) uint32 {\n\tvar short_code uint32 = self.dcode_insert_length >> 27\n\tif short_code == 0 {\n\t\treturn zopfliNodeCopyDistance(self) + numDistanceShortCodes - 1\n\t} else {\n\t\treturn short_code - 1\n\t}\n}\n\nfunc zopfliNodeCommandLength(self *zopfliNode) uint32 {\n\treturn zopfliNodeCopyLength(self) + (self.dcode_insert_length & 0x7FFFFFF)\n}\n\n/* Histogram based cost model for zopflification. */\ntype zopfliCostModel struct {\n\tcost_cmd_               [numCommandSymbols]float32\n\tcost_dist_              []float32\n\tdistance_histogram_size uint32\n\tliteral_costs_          []float32\n\tmin_cost_cmd_           float32\n\tnum_bytes_              uint\n}\n\nfunc initZopfliCostModel(self *zopfliCostModel, dist *distanceParams, num_bytes uint) {\n\tvar distance_histogram_size uint32 = dist.alphabet_size\n\tif distance_histogram_size > maxEffectiveDistanceAlphabetSize {\n\t\tdistance_histogram_size = maxEffectiveDistanceAlphabetSize\n\t}\n\n\tself.num_bytes_ = num_bytes\n\tself.literal_costs_ = make([]float32, (num_bytes + 2))\n\tself.cost_dist_ = make([]float32, (dist.alphabet_size))\n\tself.distance_histogram_size = distance_histogram_size\n}\n\nfunc cleanupZopfliCostModel(self *zopfliCostModel) {\n\tself.literal_costs_ = nil\n\tself.cost_dist_ = nil\n}\n\nfunc setCost(histogram []uint32, histogram_size uint, literal_histogram bool, cost []float32) {\n\tvar sum uint = 0\n\tvar missing_symbol_sum uint\n\tvar log2sum float32\n\tvar missing_symbol_cost float32\n\tvar i uint\n\tfor i = 0; i < histogram_size; i++ {\n\t\tsum += uint(histogram[i])\n\t}\n\n\tlog2sum = float32(fastLog2(sum))\n\tmissing_symbol_sum = sum\n\tif !literal_histogram {\n\t\tfor i = 0; i < histogram_size; i++ {\n\t\t\tif histogram[i] == 0 {\n\t\t\t\tmissing_symbol_sum++\n\t\t\t}\n\t\t}\n\t}\n\n\tmissing_symbol_cost = float32(fastLog2(missing_symbol_sum)) + 2\n\tfor i = 0; i < histogram_size; i++ {\n\t\tif histogram[i] == 0 {\n\t\t\tcost[i] = missing_symbol_cost\n\t\t\tcontinue\n\t\t}\n\n\t\t/* Shannon bits for this symbol. */\n\t\tcost[i] = log2sum - float32(fastLog2(uint(histogram[i])))\n\n\t\t/* Cannot be coded with less than 1 bit */\n\t\tif cost[i] < 1 {\n\t\t\tcost[i] = 1\n\t\t}\n\t}\n}\n\nfunc zopfliCostModelSetFromCommands(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint, commands []command, last_insert_len uint) {\n\tvar histogram_literal [numLiteralSymbols]uint32\n\tvar histogram_cmd [numCommandSymbols]uint32\n\tvar histogram_dist [maxEffectiveDistanceAlphabetSize]uint32\n\tvar cost_literal [numLiteralSymbols]float32\n\tvar pos uint = position - last_insert_len\n\tvar min_cost_cmd float32 = kInfinity\n\tvar cost_cmd []float32 = self.cost_cmd_[:]\n\tvar literal_costs []float32\n\n\thistogram_literal = [numLiteralSymbols]uint32{}\n\thistogram_cmd = [numCommandSymbols]uint32{}\n\thistogram_dist = [maxEffectiveDistanceAlphabetSize]uint32{}\n\n\tfor i := range commands {\n\t\tvar inslength uint = uint(commands[i].insert_len_)\n\t\tvar copylength uint = uint(commandCopyLen(&commands[i]))\n\t\tvar distcode uint = uint(commands[i].dist_prefix_) & 0x3FF\n\t\tvar cmdcode uint = uint(commands[i].cmd_prefix_)\n\t\tvar j uint\n\n\t\thistogram_cmd[cmdcode]++\n\t\tif cmdcode >= 128 {\n\t\t\thistogram_dist[distcode]++\n\t\t}\n\n\t\tfor j = 0; j < inslength; j++ {\n\t\t\thistogram_literal[ringbuffer[(pos+j)&ringbuffer_mask]]++\n\t\t}\n\n\t\tpos += inslength + copylength\n\t}\n\n\tsetCost(histogram_literal[:], numLiteralSymbols, true, cost_literal[:])\n\tsetCost(histogram_cmd[:], numCommandSymbols, false, cost_cmd)\n\tsetCost(histogram_dist[:], uint(self.distance_histogram_size), false, self.cost_dist_)\n\n\tfor i := 0; i < numCommandSymbols; i++ {\n\t\tmin_cost_cmd = brotli_min_float(min_cost_cmd, cost_cmd[i])\n\t}\n\n\tself.min_cost_cmd_ = min_cost_cmd\n\t{\n\t\tliteral_costs = self.literal_costs_\n\t\tvar literal_carry float32 = 0.0\n\t\tnum_bytes := int(self.num_bytes_)\n\t\tliteral_costs[0] = 0.0\n\t\tfor i := 0; i < num_bytes; i++ {\n\t\t\tliteral_carry += cost_literal[ringbuffer[(position+uint(i))&ringbuffer_mask]]\n\t\t\tliteral_costs[i+1] = literal_costs[i] + literal_carry\n\t\t\tliteral_carry -= literal_costs[i+1] - literal_costs[i]\n\t\t}\n\t}\n}\n\nfunc zopfliCostModelSetFromLiteralCosts(self *zopfliCostModel, position uint, ringbuffer []byte, ringbuffer_mask uint) {\n\tvar literal_costs []float32 = self.literal_costs_\n\tvar literal_carry float32 = 0.0\n\tvar cost_dist []float32 = self.cost_dist_\n\tvar cost_cmd []float32 = self.cost_cmd_[:]\n\tvar num_bytes uint = self.num_bytes_\n\tvar i uint\n\testimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask, ringbuffer, literal_costs[1:])\n\tliteral_costs[0] = 0.0\n\tfor i = 0; i < num_bytes; i++ {\n\t\tliteral_carry += literal_costs[i+1]\n\t\tliteral_costs[i+1] = literal_costs[i] + literal_carry\n\t\tliteral_carry -= literal_costs[i+1] - literal_costs[i]\n\t}\n\n\tfor i = 0; i < numCommandSymbols; i++ {\n\t\tcost_cmd[i] = float32(fastLog2(uint(11 + uint32(i))))\n\t}\n\n\tfor i = 0; uint32(i) < self.distance_histogram_size; i++ {\n\t\tcost_dist[i] = float32(fastLog2(uint(20 + uint32(i))))\n\t}\n\n\tself.min_cost_cmd_ = float32(fastLog2(11))\n}\n\nfunc zopfliCostModelGetCommandCost(self *zopfliCostModel, cmdcode uint16) float32 {\n\treturn self.cost_cmd_[cmdcode]\n}\n\nfunc zopfliCostModelGetDistanceCost(self *zopfliCostModel, distcode uint) float32 {\n\treturn self.cost_dist_[distcode]\n}\n\nfunc zopfliCostModelGetLiteralCosts(self *zopfliCostModel, from uint, to uint) float32 {\n\treturn self.literal_costs_[to] - self.literal_costs_[from]\n}\n\nfunc zopfliCostModelGetMinCostCmd(self *zopfliCostModel) float32 {\n\treturn self.min_cost_cmd_\n}\n\n/* REQUIRES: len >= 2, start_pos <= pos */\n/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */\n/* Maintains the \"ZopfliNode array invariant\". */\nfunc updateZopfliNode(nodes []zopfliNode, pos uint, start_pos uint, len uint, len_code uint, dist uint, short_code uint, cost float32) {\n\tvar next *zopfliNode = &nodes[pos+len]\n\tnext.length = uint32(len | (len+9-len_code)<<25)\n\tnext.distance = uint32(dist)\n\tnext.dcode_insert_length = uint32(short_code<<27 | (pos - start_pos))\n\tnext.u.cost = cost\n}\n\ntype posData struct {\n\tpos            uint\n\tdistance_cache [4]int\n\tcostdiff       float32\n\tcost           float32\n}\n\n/* Maintains the smallest 8 cost difference together with their positions */\ntype startPosQueue struct {\n\tq_   [8]posData\n\tidx_ uint\n}\n\nfunc initStartPosQueue(self *startPosQueue) {\n\tself.idx_ = 0\n}\n\nfunc startPosQueueSize(self *startPosQueue) uint {\n\treturn brotli_min_size_t(self.idx_, 8)\n}\n\nfunc startPosQueuePush(self *startPosQueue, posdata *posData) {\n\tvar offset uint = ^(self.idx_) & 7\n\tself.idx_++\n\tvar len uint = startPosQueueSize(self)\n\tvar i uint\n\tvar q []posData = self.q_[:]\n\tq[offset] = *posdata\n\n\t/* Restore the sorted order. In the list of |len| items at most |len - 1|\n\t   adjacent element comparisons / swaps are required. */\n\tfor i = 1; i < len; i++ {\n\t\tif q[offset&7].costdiff > q[(offset+1)&7].costdiff {\n\t\t\tvar tmp posData = q[offset&7]\n\t\t\tq[offset&7] = q[(offset+1)&7]\n\t\t\tq[(offset+1)&7] = tmp\n\t\t}\n\n\t\toffset++\n\t}\n}\n\nfunc startPosQueueAt(self *startPosQueue, k uint) *posData {\n\treturn &self.q_[(k-self.idx_)&7]\n}\n\n/* Returns the minimum possible copy length that can improve the cost of any */\n/* future position. */\nfunc computeMinimumCopyLength(start_cost float32, nodes []zopfliNode, num_bytes uint, pos uint) uint {\n\tvar min_cost float32 = start_cost\n\tvar len uint = 2\n\tvar next_len_bucket uint = 4\n\t/* Compute the minimum possible cost of reaching any future position. */\n\n\tvar next_len_offset uint = 10\n\tfor pos+len <= num_bytes && nodes[pos+len].u.cost <= min_cost {\n\t\t/* We already reached (pos + len) with no more cost than the minimum\n\t\t   possible cost of reaching anything from this pos, so there is no point in\n\t\t   looking for lengths <= len. */\n\t\tlen++\n\n\t\tif len == next_len_offset {\n\t\t\t/* We reached the next copy length code bucket, so we add one more\n\t\t\t   extra bit to the minimum cost. */\n\t\t\tmin_cost += 1.0\n\n\t\t\tnext_len_offset += next_len_bucket\n\t\t\tnext_len_bucket *= 2\n\t\t}\n\t}\n\n\treturn uint(len)\n}\n\n/* REQUIRES: nodes[pos].cost < kInfinity\n   REQUIRES: nodes[0..pos] satisfies that \"ZopfliNode array invariant\". */\nfunc computeDistanceShortcut(block_start uint, pos uint, max_backward_limit uint, gap uint, nodes []zopfliNode) uint32 {\n\tvar clen uint = uint(zopfliNodeCopyLength(&nodes[pos]))\n\tvar ilen uint = uint(nodes[pos].dcode_insert_length & 0x7FFFFFF)\n\tvar dist uint = uint(zopfliNodeCopyDistance(&nodes[pos]))\n\n\t/* Since |block_start + pos| is the end position of the command, the copy part\n\t   starts from |block_start + pos - clen|. Distances that are greater than\n\t   this or greater than |max_backward_limit| + |gap| are static dictionary\n\t   references, and do not update the last distances.\n\t   Also distance code 0 (last distance) does not update the last distances. */\n\tif pos == 0 {\n\t\treturn 0\n\t} else if dist+clen <= block_start+pos+gap && dist <= max_backward_limit+gap && zopfliNodeDistanceCode(&nodes[pos]) > 0 {\n\t\treturn uint32(pos)\n\t} else {\n\t\treturn nodes[pos-clen-ilen].u.shortcut\n\t}\n}\n\n/* Fills in dist_cache[0..3] with the last four distances (as defined by\n   Section 4. of the Spec) that would be used at (block_start + pos) if we\n   used the shortest path of commands from block_start, computed from\n   nodes[0..pos]. The last four distances at block_start are in\n   starting_dist_cache[0..3].\n   REQUIRES: nodes[pos].cost < kInfinity\n   REQUIRES: nodes[0..pos] satisfies that \"ZopfliNode array invariant\". */\nfunc computeDistanceCache(pos uint, starting_dist_cache []int, nodes []zopfliNode, dist_cache []int) {\n\tvar idx int = 0\n\tvar p uint = uint(nodes[pos].u.shortcut)\n\tfor idx < 4 && p > 0 {\n\t\tvar ilen uint = uint(nodes[p].dcode_insert_length & 0x7FFFFFF)\n\t\tvar clen uint = uint(zopfliNodeCopyLength(&nodes[p]))\n\t\tvar dist uint = uint(zopfliNodeCopyDistance(&nodes[p]))\n\t\tdist_cache[idx] = int(dist)\n\t\tidx++\n\n\t\t/* Because of prerequisite, p >= clen + ilen >= 2. */\n\t\tp = uint(nodes[p-clen-ilen].u.shortcut)\n\t}\n\n\tfor ; idx < 4; idx++ {\n\t\tdist_cache[idx] = starting_dist_cache[0]\n\t\tstarting_dist_cache = starting_dist_cache[1:]\n\t}\n}\n\n/* Maintains \"ZopfliNode array invariant\" and pushes node to the queue, if it\n   is eligible. */\nfunc evaluateNode(block_start uint, pos uint, max_backward_limit uint, gap uint, starting_dist_cache []int, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) {\n\t/* Save cost, because ComputeDistanceCache invalidates it. */\n\tvar node_cost float32 = nodes[pos].u.cost\n\tnodes[pos].u.shortcut = computeDistanceShortcut(block_start, pos, max_backward_limit, gap, nodes)\n\tif node_cost <= zopfliCostModelGetLiteralCosts(model, 0, pos) {\n\t\tvar posdata posData\n\t\tposdata.pos = pos\n\t\tposdata.cost = node_cost\n\t\tposdata.costdiff = node_cost - zopfliCostModelGetLiteralCosts(model, 0, pos)\n\t\tcomputeDistanceCache(pos, starting_dist_cache, nodes, posdata.distance_cache[:])\n\t\tstartPosQueuePush(queue, &posdata)\n\t}\n}\n\n/* Returns longest copy length. */\nfunc updateNodes(num_bytes uint, block_start uint, pos uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, max_backward_limit uint, starting_dist_cache []int, num_matches uint, matches []backwardMatch, model *zopfliCostModel, queue *startPosQueue, nodes []zopfliNode) uint {\n\tvar cur_ix uint = block_start + pos\n\tvar cur_ix_masked uint = cur_ix & ringbuffer_mask\n\tvar max_distance uint = brotli_min_size_t(cur_ix, max_backward_limit)\n\tvar max_len uint = num_bytes - pos\n\tvar max_zopfli_len uint = maxZopfliLen(params)\n\tvar max_iters uint = maxZopfliCandidates(params)\n\tvar min_len uint\n\tvar result uint = 0\n\tvar k uint\n\tvar gap uint = 0\n\n\tevaluateNode(block_start, pos, max_backward_limit, gap, starting_dist_cache, model, queue, nodes)\n\t{\n\t\tvar posdata *posData = startPosQueueAt(queue, 0)\n\t\tvar min_cost float32 = (posdata.cost + zopfliCostModelGetMinCostCmd(model) + zopfliCostModelGetLiteralCosts(model, posdata.pos, pos))\n\t\tmin_len = computeMinimumCopyLength(min_cost, nodes, num_bytes, pos)\n\t}\n\n\t/* Go over the command starting positions in order of increasing cost\n\t   difference. */\n\tfor k = 0; k < max_iters && k < startPosQueueSize(queue); k++ {\n\t\tvar posdata *posData = startPosQueueAt(queue, k)\n\t\tvar start uint = posdata.pos\n\t\tvar inscode uint16 = getInsertLengthCode(pos - start)\n\t\tvar start_costdiff float32 = posdata.costdiff\n\t\tvar base_cost float32 = start_costdiff + float32(getInsertExtra(inscode)) + zopfliCostModelGetLiteralCosts(model, 0, pos)\n\t\tvar best_len uint = min_len - 1\n\t\tvar j uint = 0\n\t\t/* Look for last distance matches using the distance cache from this\n\t\t   starting position. */\n\t\tfor ; j < numDistanceShortCodes && best_len < max_len; j++ {\n\t\t\tvar idx uint = uint(kDistanceCacheIndex[j])\n\t\t\tvar backward uint = uint(posdata.distance_cache[idx] + kDistanceCacheOffset[j])\n\t\t\tvar prev_ix uint = cur_ix - backward\n\t\t\tvar len uint = 0\n\t\t\tvar continuation byte = ringbuffer[cur_ix_masked+best_len]\n\t\t\tif cur_ix_masked+best_len > ringbuffer_mask {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif backward > max_distance+gap {\n\t\t\t\t/* Word dictionary -> ignore. */\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif backward <= max_distance {\n\t\t\t\t/* Regular backward reference. */\n\t\t\t\tif prev_ix >= cur_ix {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tprev_ix &= ringbuffer_mask\n\t\t\t\tif prev_ix+best_len > ringbuffer_mask || continuation != ringbuffer[prev_ix+best_len] {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tlen = findMatchLengthWithLimit(ringbuffer[prev_ix:], ringbuffer[cur_ix_masked:], max_len)\n\t\t\t} else {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t{\n\t\t\t\tvar dist_cost float32 = base_cost + zopfliCostModelGetDistanceCost(model, j)\n\t\t\t\tvar l uint\n\t\t\t\tfor l = best_len + 1; l <= len; l++ {\n\t\t\t\t\tvar copycode uint16 = getCopyLengthCode(l)\n\t\t\t\t\tvar cmdcode uint16 = combineLengthCodes(inscode, copycode, j == 0)\n\t\t\t\t\tvar tmp float32\n\t\t\t\t\tif cmdcode < 128 {\n\t\t\t\t\t\ttmp = base_cost\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = dist_cost\n\t\t\t\t\t}\n\t\t\t\t\tvar cost float32 = tmp + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)\n\t\t\t\t\tif cost < nodes[pos+l].u.cost {\n\t\t\t\t\t\tupdateZopfliNode(nodes, pos, start, l, l, backward, j+1, cost)\n\t\t\t\t\t\tresult = brotli_max_size_t(result, l)\n\t\t\t\t\t}\n\n\t\t\t\t\tbest_len = l\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* At higher iterations look only for new last distance matches, since\n\t\t   looking only for new command start positions with the same distances\n\t\t   does not help much. */\n\t\tif k >= 2 {\n\t\t\tcontinue\n\t\t}\n\t\t{\n\t\t\t/* Loop through all possible copy lengths at this position. */\n\t\t\tvar len uint = min_len\n\t\t\tfor j = 0; j < num_matches; j++ {\n\t\t\t\tvar match backwardMatch = matches[j]\n\t\t\t\tvar dist uint = uint(match.distance)\n\t\t\t\tvar is_dictionary_match bool = (dist > max_distance+gap)\n\t\t\t\tvar dist_code uint = dist + numDistanceShortCodes - 1\n\t\t\t\tvar dist_symbol uint16\n\t\t\t\tvar distextra uint32\n\t\t\t\tvar distnumextra uint32\n\t\t\t\tvar dist_cost float32\n\t\t\t\tvar max_match_len uint\n\t\t\t\t/* We already tried all possible last distance matches, so we can use\n\t\t\t\t   normal distance code here. */\n\t\t\t\tprefixEncodeCopyDistance(dist_code, uint(params.dist.num_direct_distance_codes), uint(params.dist.distance_postfix_bits), &dist_symbol, &distextra)\n\n\t\t\t\tdistnumextra = uint32(dist_symbol) >> 10\n\t\t\t\tdist_cost = base_cost + float32(distnumextra) + zopfliCostModelGetDistanceCost(model, uint(dist_symbol)&0x3FF)\n\n\t\t\t\t/* Try all copy lengths up until the maximum copy length corresponding\n\t\t\t\t   to this distance. If the distance refers to the static dictionary, or\n\t\t\t\t   the maximum length is long enough, try only one maximum length. */\n\t\t\t\tmax_match_len = backwardMatchLength(&match)\n\n\t\t\t\tif len < max_match_len && (is_dictionary_match || max_match_len > max_zopfli_len) {\n\t\t\t\t\tlen = max_match_len\n\t\t\t\t}\n\n\t\t\t\tfor ; len <= max_match_len; len++ {\n\t\t\t\t\tvar len_code uint\n\t\t\t\t\tif is_dictionary_match {\n\t\t\t\t\t\tlen_code = backwardMatchLengthCode(&match)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlen_code = len\n\t\t\t\t\t}\n\t\t\t\t\tvar copycode uint16 = getCopyLengthCode(len_code)\n\t\t\t\t\tvar cmdcode uint16 = combineLengthCodes(inscode, copycode, false)\n\t\t\t\t\tvar cost float32 = dist_cost + float32(getCopyExtra(copycode)) + zopfliCostModelGetCommandCost(model, cmdcode)\n\t\t\t\t\tif cost < nodes[pos+len].u.cost {\n\t\t\t\t\t\tupdateZopfliNode(nodes, pos, start, uint(len), len_code, dist, 0, cost)\n\t\t\t\t\t\tif len > result {\n\t\t\t\t\t\t\tresult = len\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunc computeShortestPathFromNodes(num_bytes uint, nodes []zopfliNode) uint {\n\tvar index uint = num_bytes\n\tvar num_commands uint = 0\n\tfor nodes[index].dcode_insert_length&0x7FFFFFF == 0 && nodes[index].length == 1 {\n\t\tindex--\n\t}\n\tnodes[index].u.next = math.MaxUint32\n\tfor index != 0 {\n\t\tvar len uint = uint(zopfliNodeCommandLength(&nodes[index]))\n\t\tindex -= uint(len)\n\t\tnodes[index].u.next = uint32(len)\n\t\tnum_commands++\n\t}\n\n\treturn num_commands\n}\n\n/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */\nfunc zopfliCreateCommands(num_bytes uint, block_start uint, nodes []zopfliNode, dist_cache []int, last_insert_len *uint, params *encoderParams, commands *[]command, num_literals *uint) {\n\tvar max_backward_limit uint = maxBackwardLimit(params.lgwin)\n\tvar pos uint = 0\n\tvar offset uint32 = nodes[0].u.next\n\tvar i uint\n\tvar gap uint = 0\n\tfor i = 0; offset != math.MaxUint32; i++ {\n\t\tvar next *zopfliNode = &nodes[uint32(pos)+offset]\n\t\tvar copy_length uint = uint(zopfliNodeCopyLength(next))\n\t\tvar insert_length uint = uint(next.dcode_insert_length & 0x7FFFFFF)\n\t\tpos += insert_length\n\t\toffset = next.u.next\n\t\tif i == 0 {\n\t\t\tinsert_length += *last_insert_len\n\t\t\t*last_insert_len = 0\n\t\t}\n\t\t{\n\t\t\tvar distance uint = uint(zopfliNodeCopyDistance(next))\n\t\t\tvar len_code uint = uint(zopfliNodeLengthCode(next))\n\t\t\tvar max_distance uint = brotli_min_size_t(block_start+pos, max_backward_limit)\n\t\t\tvar is_dictionary bool = (distance > max_distance+gap)\n\t\t\tvar dist_code uint = uint(zopfliNodeDistanceCode(next))\n\t\t\t*commands = append(*commands, makeCommand(&params.dist, insert_length, copy_length, int(len_code)-int(copy_length), dist_code))\n\n\t\t\tif !is_dictionary && dist_code > 0 {\n\t\t\t\tdist_cache[3] = dist_cache[2]\n\t\t\t\tdist_cache[2] = dist_cache[1]\n\t\t\t\tdist_cache[1] = dist_cache[0]\n\t\t\t\tdist_cache[0] = int(distance)\n\t\t\t}\n\t\t}\n\n\t\t*num_literals += insert_length\n\t\tpos += copy_length\n\t}\n\n\t*last_insert_len += num_bytes - pos\n}\n\nfunc zopfliIterate(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, gap uint, dist_cache []int, model *zopfliCostModel, num_matches []uint32, matches []backwardMatch, nodes []zopfliNode) uint {\n\tvar max_backward_limit uint = maxBackwardLimit(params.lgwin)\n\tvar max_zopfli_len uint = maxZopfliLen(params)\n\tvar queue startPosQueue\n\tvar cur_match_pos uint = 0\n\tvar i uint\n\tnodes[0].length = 0\n\tnodes[0].u.cost = 0\n\tinitStartPosQueue(&queue)\n\tfor i = 0; i+3 < num_bytes; i++ {\n\t\tvar skip uint = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, uint(num_matches[i]), matches[cur_match_pos:], model, &queue, nodes)\n\t\tif skip < longCopyQuickStep {\n\t\t\tskip = 0\n\t\t}\n\t\tcur_match_pos += uint(num_matches[i])\n\t\tif num_matches[i] == 1 && backwardMatchLength(&matches[cur_match_pos-1]) > max_zopfli_len {\n\t\t\tskip = brotli_max_size_t(backwardMatchLength(&matches[cur_match_pos-1]), skip)\n\t\t}\n\n\t\tif skip > 1 {\n\t\t\tskip--\n\t\t\tfor skip != 0 {\n\t\t\t\ti++\n\t\t\t\tif i+3 >= num_bytes {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tevaluateNode(position, i, max_backward_limit, gap, dist_cache, model, &queue, nodes)\n\t\t\t\tcur_match_pos += uint(num_matches[i])\n\t\t\t\tskip--\n\t\t\t}\n\t\t}\n\t}\n\n\treturn computeShortestPathFromNodes(num_bytes, nodes)\n}\n\n/* Computes the shortest path of commands from position to at most\n   position + num_bytes.\n\n   On return, path->size() is the number of commands found and path[i] is the\n   length of the i-th command (copy length plus insert length).\n   Note that the sum of the lengths of all commands can be less than num_bytes.\n\n   On return, the nodes[0..num_bytes] array will have the following\n   \"ZopfliNode array invariant\":\n   For each i in [1..num_bytes], if nodes[i].cost < kInfinity, then\n     (1) nodes[i].copy_length() >= 2\n     (2) nodes[i].command_length() <= i and\n     (3) nodes[i - nodes[i].command_length()].cost < kInfinity\n\n REQUIRES: nodes != nil and len(nodes) >= num_bytes + 1 */\nfunc zopfliComputeShortestPath(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, dist_cache []int, hasher *h10, nodes []zopfliNode) uint {\n\tvar max_backward_limit uint = maxBackwardLimit(params.lgwin)\n\tvar max_zopfli_len uint = maxZopfliLen(params)\n\tvar model zopfliCostModel\n\tvar queue startPosQueue\n\tvar matches [2 * (maxNumMatchesH10 + 64)]backwardMatch\n\tvar store_end uint\n\tif num_bytes >= hasher.StoreLookahead() {\n\t\tstore_end = position + num_bytes - hasher.StoreLookahead() + 1\n\t} else {\n\t\tstore_end = position\n\t}\n\tvar i uint\n\tvar gap uint = 0\n\tvar lz_matches_offset uint = 0\n\tnodes[0].length = 0\n\tnodes[0].u.cost = 0\n\tinitZopfliCostModel(&model, &params.dist, num_bytes)\n\tzopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)\n\tinitStartPosQueue(&queue)\n\tfor i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {\n\t\tvar pos uint = position + i\n\t\tvar max_distance uint = brotli_min_size_t(pos, max_backward_limit)\n\t\tvar skip uint\n\t\tvar num_matches uint\n\t\tnum_matches = findAllMatchesH10(hasher, &params.dictionary, ringbuffer, ringbuffer_mask, pos, num_bytes-i, max_distance, gap, params, matches[lz_matches_offset:])\n\t\tif num_matches > 0 && backwardMatchLength(&matches[num_matches-1]) > max_zopfli_len {\n\t\t\tmatches[0] = matches[num_matches-1]\n\t\t\tnum_matches = 1\n\t\t}\n\n\t\tskip = updateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, params, max_backward_limit, dist_cache, num_matches, matches[:], &model, &queue, nodes)\n\t\tif skip < longCopyQuickStep {\n\t\t\tskip = 0\n\t\t}\n\t\tif num_matches == 1 && backwardMatchLength(&matches[0]) > max_zopfli_len {\n\t\t\tskip = brotli_max_size_t(backwardMatchLength(&matches[0]), skip)\n\t\t}\n\n\t\tif skip > 1 {\n\t\t\t/* Add the tail of the copy to the hasher. */\n\t\t\thasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+skip, store_end))\n\n\t\t\tskip--\n\t\t\tfor skip != 0 {\n\t\t\t\ti++\n\t\t\t\tif i+hasher.HashTypeLength()-1 >= num_bytes {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tevaluateNode(position, i, max_backward_limit, gap, dist_cache, &model, &queue, nodes)\n\t\t\t\tskip--\n\t\t\t}\n\t\t}\n\t}\n\n\tcleanupZopfliCostModel(&model)\n\treturn computeShortestPathFromNodes(num_bytes, nodes)\n}\n\nfunc createZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher *h10, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {\n\tvar nodes []zopfliNode\n\tnodes = make([]zopfliNode, (num_bytes + 1))\n\tinitZopfliNodes(nodes, num_bytes+1)\n\tzopfliComputeShortestPath(num_bytes, position, ringbuffer, ringbuffer_mask, params, dist_cache, hasher, nodes)\n\tzopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)\n\tnodes = nil\n}\n\nfunc createHqZopfliBackwardReferences(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint, params *encoderParams, hasher hasherHandle, dist_cache []int, last_insert_len *uint, commands *[]command, num_literals *uint) {\n\tvar max_backward_limit uint = maxBackwardLimit(params.lgwin)\n\tvar num_matches []uint32 = make([]uint32, num_bytes)\n\tvar matches_size uint = 4 * num_bytes\n\tvar store_end uint\n\tif num_bytes >= hasher.StoreLookahead() {\n\t\tstore_end = position + num_bytes - hasher.StoreLookahead() + 1\n\t} else {\n\t\tstore_end = position\n\t}\n\tvar cur_match_pos uint = 0\n\tvar i uint\n\tvar orig_num_literals uint\n\tvar orig_last_insert_len uint\n\tvar orig_dist_cache [4]int\n\tvar orig_num_commands int\n\tvar model zopfliCostModel\n\tvar nodes []zopfliNode\n\tvar matches []backwardMatch = make([]backwardMatch, matches_size)\n\tvar gap uint = 0\n\tvar shadow_matches uint = 0\n\tvar new_array []backwardMatch\n\tfor i = 0; i+hasher.HashTypeLength()-1 < num_bytes; i++ {\n\t\tvar pos uint = position + i\n\t\tvar max_distance uint = brotli_min_size_t(pos, max_backward_limit)\n\t\tvar max_length uint = num_bytes - i\n\t\tvar num_found_matches uint\n\t\tvar cur_match_end uint\n\t\tvar j uint\n\n\t\t/* Ensure that we have enough free slots. */\n\t\tif matches_size < cur_match_pos+maxNumMatchesH10+shadow_matches {\n\t\t\tvar new_size uint = matches_size\n\t\t\tif new_size == 0 {\n\t\t\t\tnew_size = cur_match_pos + maxNumMatchesH10 + shadow_matches\n\t\t\t}\n\n\t\t\tfor new_size < cur_match_pos+maxNumMatchesH10+shadow_matches {\n\t\t\t\tnew_size *= 2\n\t\t\t}\n\n\t\t\tnew_array = make([]backwardMatch, new_size)\n\t\t\tif matches_size != 0 {\n\t\t\t\tcopy(new_array, matches[:matches_size])\n\t\t\t}\n\n\t\t\tmatches = new_array\n\t\t\tmatches_size = new_size\n\t\t}\n\n\t\tnum_found_matches = findAllMatchesH10(hasher.(*h10), &params.dictionary, ringbuffer, ringbuffer_mask, pos, max_length, max_distance, gap, params, matches[cur_match_pos+shadow_matches:])\n\t\tcur_match_end = cur_match_pos + num_found_matches\n\t\tfor j = cur_match_pos; j+1 < cur_match_end; j++ {\n\t\t\tassert(backwardMatchLength(&matches[j]) <= backwardMatchLength(&matches[j+1]))\n\t\t}\n\n\t\tnum_matches[i] = uint32(num_found_matches)\n\t\tif num_found_matches > 0 {\n\t\t\tvar match_len uint = backwardMatchLength(&matches[cur_match_end-1])\n\t\t\tif match_len > maxZopfliLenQuality11 {\n\t\t\t\tvar skip uint = match_len - 1\n\t\t\t\tmatches[cur_match_pos] = matches[cur_match_end-1]\n\t\t\t\tcur_match_pos++\n\t\t\t\tnum_matches[i] = 1\n\n\t\t\t\t/* Add the tail of the copy to the hasher. */\n\t\t\t\thasher.StoreRange(ringbuffer, ringbuffer_mask, pos+1, brotli_min_size_t(pos+match_len, store_end))\n\t\t\t\tvar pos uint = i\n\t\t\t\tfor i := 0; i < int(skip); i++ {\n\t\t\t\t\tnum_matches[pos+1:][i] = 0\n\t\t\t\t}\n\t\t\t\ti += skip\n\t\t\t} else {\n\t\t\t\tcur_match_pos = cur_match_end\n\t\t\t}\n\t\t}\n\t}\n\n\torig_num_literals = *num_literals\n\torig_last_insert_len = *last_insert_len\n\tcopy(orig_dist_cache[:], dist_cache[:4])\n\torig_num_commands = len(*commands)\n\tnodes = make([]zopfliNode, (num_bytes + 1))\n\tinitZopfliCostModel(&model, &params.dist, num_bytes)\n\tfor i = 0; i < 2; i++ {\n\t\tinitZopfliNodes(nodes, num_bytes+1)\n\t\tif i == 0 {\n\t\t\tzopfliCostModelSetFromLiteralCosts(&model, position, ringbuffer, ringbuffer_mask)\n\t\t} else {\n\t\t\tzopfliCostModelSetFromCommands(&model, position, ringbuffer, ringbuffer_mask, (*commands)[orig_num_commands:], orig_last_insert_len)\n\t\t}\n\n\t\t*commands = (*commands)[:orig_num_commands]\n\t\t*num_literals = orig_num_literals\n\t\t*last_insert_len = orig_last_insert_len\n\t\tcopy(dist_cache, orig_dist_cache[:4])\n\t\tzopfliIterate(num_bytes, position, ringbuffer, ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches, nodes)\n\t\tzopfliCreateCommands(num_bytes, position, nodes, dist_cache, last_insert_len, params, commands, num_literals)\n\t}\n\n\tcleanupZopfliCostModel(&model)\n\tnodes = nil\n\tmatches = nil\n\tnum_matches = nil\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/bit_cost.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Functions to estimate the bit cost of Huffman trees. */\nfunc shannonEntropy(population []uint32, size uint, total *uint) float64 {\n\tvar sum uint = 0\n\tvar retval float64 = 0\n\tvar population_end []uint32 = population[size:]\n\tvar p uint\n\tfor -cap(population) < -cap(population_end) {\n\t\tp = uint(population[0])\n\t\tpopulation = population[1:]\n\t\tsum += p\n\t\tretval -= float64(p) * fastLog2(p)\n\t}\n\n\tif sum != 0 {\n\t\tretval += float64(sum) * fastLog2(sum)\n\t}\n\t*total = sum\n\treturn retval\n}\n\nfunc bitsEntropy(population []uint32, size uint) float64 {\n\tvar sum uint\n\tvar retval float64 = shannonEntropy(population, size, &sum)\n\tif retval < float64(sum) {\n\t\t/* At least one bit per literal is needed. */\n\t\tretval = float64(sum)\n\t}\n\n\treturn retval\n}\n\nconst kOneSymbolHistogramCost float64 = 12\nconst kTwoSymbolHistogramCost float64 = 20\nconst kThreeSymbolHistogramCost float64 = 28\nconst kFourSymbolHistogramCost float64 = 37\n\nfunc populationCostLiteral(histogram *histogramLiteral) float64 {\n\tvar data_size uint = histogramDataSizeLiteral()\n\tvar count int = 0\n\tvar s [5]uint\n\tvar bits float64 = 0.0\n\tvar i uint\n\tif histogram.total_count_ == 0 {\n\t\treturn kOneSymbolHistogramCost\n\t}\n\n\tfor i = 0; i < data_size; i++ {\n\t\tif histogram.data_[i] > 0 {\n\t\t\ts[count] = i\n\t\t\tcount++\n\t\t\tif count > 4 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif count == 1 {\n\t\treturn kOneSymbolHistogramCost\n\t}\n\n\tif count == 2 {\n\t\treturn kTwoSymbolHistogramCost + float64(histogram.total_count_)\n\t}\n\n\tif count == 3 {\n\t\tvar histo0 uint32 = histogram.data_[s[0]]\n\t\tvar histo1 uint32 = histogram.data_[s[1]]\n\t\tvar histo2 uint32 = histogram.data_[s[2]]\n\t\tvar histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))\n\t\treturn kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)\n\t}\n\n\tif count == 4 {\n\t\tvar histo [4]uint32\n\t\tvar h23 uint32\n\t\tvar histomax uint32\n\t\tfor i = 0; i < 4; i++ {\n\t\t\thisto[i] = histogram.data_[s[i]]\n\t\t}\n\n\t\t/* Sort */\n\t\tfor i = 0; i < 4; i++ {\n\t\t\tvar j uint\n\t\t\tfor j = i + 1; j < 4; j++ {\n\t\t\t\tif histo[j] > histo[i] {\n\t\t\t\t\tvar tmp uint32 = histo[j]\n\t\t\t\t\thisto[j] = histo[i]\n\t\t\t\t\thisto[i] = tmp\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\th23 = histo[2] + histo[3]\n\t\thistomax = brotli_max_uint32_t(h23, histo[0])\n\t\treturn kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)\n\t}\n\t{\n\t\tvar max_depth uint = 1\n\t\tvar depth_histo = [codeLengthCodes]uint32{0}\n\t\t/* In this loop we compute the entropy of the histogram and simultaneously\n\t\t   build a simplified histogram of the code length codes where we use the\n\t\t   zero repeat code 17, but we don't use the non-zero repeat code 16. */\n\n\t\tvar log2total float64 = fastLog2(histogram.total_count_)\n\t\tfor i = 0; i < data_size; {\n\t\t\tif histogram.data_[i] > 0 {\n\t\t\t\tvar log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))\n\t\t\t\t/* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =\n\t\t\t\t   = log2(total_count) - log2(count(symbol)) */\n\n\t\t\t\tvar depth uint = uint(log2p + 0.5)\n\t\t\t\t/* Approximate the bit depth by round(-log2(P(symbol))) */\n\t\t\t\tbits += float64(histogram.data_[i]) * log2p\n\n\t\t\t\tif depth > 15 {\n\t\t\t\t\tdepth = 15\n\t\t\t\t}\n\n\t\t\t\tif depth > max_depth {\n\t\t\t\t\tmax_depth = depth\n\t\t\t\t}\n\n\t\t\t\tdepth_histo[depth]++\n\t\t\t\ti++\n\t\t\t} else {\n\t\t\t\tvar reps uint32 = 1\n\t\t\t\t/* Compute the run length of zeros and add the appropriate number of 0\n\t\t\t\t   and 17 code length codes to the code length code histogram. */\n\n\t\t\t\tvar k uint\n\t\t\t\tfor k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {\n\t\t\t\t\treps++\n\t\t\t\t}\n\n\t\t\t\ti += uint(reps)\n\t\t\t\tif i == data_size {\n\t\t\t\t\t/* Don't add any cost for the last zero run, since these are encoded\n\t\t\t\t\t   only implicitly. */\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif reps < 3 {\n\t\t\t\t\tdepth_histo[0] += reps\n\t\t\t\t} else {\n\t\t\t\t\treps -= 2\n\t\t\t\t\tfor reps > 0 {\n\t\t\t\t\t\tdepth_histo[repeatZeroCodeLength]++\n\n\t\t\t\t\t\t/* Add the 3 extra bits for the 17 code length code. */\n\t\t\t\t\t\tbits += 3\n\n\t\t\t\t\t\treps >>= 3\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* Add the estimated encoding cost of the code length code histogram. */\n\t\tbits += float64(18 + 2*max_depth)\n\n\t\t/* Add the entropy of the code length code histogram. */\n\t\tbits += bitsEntropy(depth_histo[:], codeLengthCodes)\n\t}\n\n\treturn bits\n}\n\nfunc populationCostCommand(histogram *histogramCommand) float64 {\n\tvar data_size uint = histogramDataSizeCommand()\n\tvar count int = 0\n\tvar s [5]uint\n\tvar bits float64 = 0.0\n\tvar i uint\n\tif histogram.total_count_ == 0 {\n\t\treturn kOneSymbolHistogramCost\n\t}\n\n\tfor i = 0; i < data_size; i++ {\n\t\tif histogram.data_[i] > 0 {\n\t\t\ts[count] = i\n\t\t\tcount++\n\t\t\tif count > 4 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif count == 1 {\n\t\treturn kOneSymbolHistogramCost\n\t}\n\n\tif count == 2 {\n\t\treturn kTwoSymbolHistogramCost + float64(histogram.total_count_)\n\t}\n\n\tif count == 3 {\n\t\tvar histo0 uint32 = histogram.data_[s[0]]\n\t\tvar histo1 uint32 = histogram.data_[s[1]]\n\t\tvar histo2 uint32 = histogram.data_[s[2]]\n\t\tvar histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))\n\t\treturn kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)\n\t}\n\n\tif count == 4 {\n\t\tvar histo [4]uint32\n\t\tvar h23 uint32\n\t\tvar histomax uint32\n\t\tfor i = 0; i < 4; i++ {\n\t\t\thisto[i] = histogram.data_[s[i]]\n\t\t}\n\n\t\t/* Sort */\n\t\tfor i = 0; i < 4; i++ {\n\t\t\tvar j uint\n\t\t\tfor j = i + 1; j < 4; j++ {\n\t\t\t\tif histo[j] > histo[i] {\n\t\t\t\t\tvar tmp uint32 = histo[j]\n\t\t\t\t\thisto[j] = histo[i]\n\t\t\t\t\thisto[i] = tmp\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\th23 = histo[2] + histo[3]\n\t\thistomax = brotli_max_uint32_t(h23, histo[0])\n\t\treturn kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)\n\t}\n\t{\n\t\tvar max_depth uint = 1\n\t\tvar depth_histo = [codeLengthCodes]uint32{0}\n\t\t/* In this loop we compute the entropy of the histogram and simultaneously\n\t\t   build a simplified histogram of the code length codes where we use the\n\t\t   zero repeat code 17, but we don't use the non-zero repeat code 16. */\n\n\t\tvar log2total float64 = fastLog2(histogram.total_count_)\n\t\tfor i = 0; i < data_size; {\n\t\t\tif histogram.data_[i] > 0 {\n\t\t\t\tvar log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))\n\t\t\t\t/* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =\n\t\t\t\t   = log2(total_count) - log2(count(symbol)) */\n\n\t\t\t\tvar depth uint = uint(log2p + 0.5)\n\t\t\t\t/* Approximate the bit depth by round(-log2(P(symbol))) */\n\t\t\t\tbits += float64(histogram.data_[i]) * log2p\n\n\t\t\t\tif depth > 15 {\n\t\t\t\t\tdepth = 15\n\t\t\t\t}\n\n\t\t\t\tif depth > max_depth {\n\t\t\t\t\tmax_depth = depth\n\t\t\t\t}\n\n\t\t\t\tdepth_histo[depth]++\n\t\t\t\ti++\n\t\t\t} else {\n\t\t\t\tvar reps uint32 = 1\n\t\t\t\t/* Compute the run length of zeros and add the appropriate number of 0\n\t\t\t\t   and 17 code length codes to the code length code histogram. */\n\n\t\t\t\tvar k uint\n\t\t\t\tfor k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {\n\t\t\t\t\treps++\n\t\t\t\t}\n\n\t\t\t\ti += uint(reps)\n\t\t\t\tif i == data_size {\n\t\t\t\t\t/* Don't add any cost for the last zero run, since these are encoded\n\t\t\t\t\t   only implicitly. */\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif reps < 3 {\n\t\t\t\t\tdepth_histo[0] += reps\n\t\t\t\t} else {\n\t\t\t\t\treps -= 2\n\t\t\t\t\tfor reps > 0 {\n\t\t\t\t\t\tdepth_histo[repeatZeroCodeLength]++\n\n\t\t\t\t\t\t/* Add the 3 extra bits for the 17 code length code. */\n\t\t\t\t\t\tbits += 3\n\n\t\t\t\t\t\treps >>= 3\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* Add the estimated encoding cost of the code length code histogram. */\n\t\tbits += float64(18 + 2*max_depth)\n\n\t\t/* Add the entropy of the code length code histogram. */\n\t\tbits += bitsEntropy(depth_histo[:], codeLengthCodes)\n\t}\n\n\treturn bits\n}\n\nfunc populationCostDistance(histogram *histogramDistance) float64 {\n\tvar data_size uint = histogramDataSizeDistance()\n\tvar count int = 0\n\tvar s [5]uint\n\tvar bits float64 = 0.0\n\tvar i uint\n\tif histogram.total_count_ == 0 {\n\t\treturn kOneSymbolHistogramCost\n\t}\n\n\tfor i = 0; i < data_size; i++ {\n\t\tif histogram.data_[i] > 0 {\n\t\t\ts[count] = i\n\t\t\tcount++\n\t\t\tif count > 4 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif count == 1 {\n\t\treturn kOneSymbolHistogramCost\n\t}\n\n\tif count == 2 {\n\t\treturn kTwoSymbolHistogramCost + float64(histogram.total_count_)\n\t}\n\n\tif count == 3 {\n\t\tvar histo0 uint32 = histogram.data_[s[0]]\n\t\tvar histo1 uint32 = histogram.data_[s[1]]\n\t\tvar histo2 uint32 = histogram.data_[s[2]]\n\t\tvar histomax uint32 = brotli_max_uint32_t(histo0, brotli_max_uint32_t(histo1, histo2))\n\t\treturn kThreeSymbolHistogramCost + 2*(float64(histo0)+float64(histo1)+float64(histo2)) - float64(histomax)\n\t}\n\n\tif count == 4 {\n\t\tvar histo [4]uint32\n\t\tvar h23 uint32\n\t\tvar histomax uint32\n\t\tfor i = 0; i < 4; i++ {\n\t\t\thisto[i] = histogram.data_[s[i]]\n\t\t}\n\n\t\t/* Sort */\n\t\tfor i = 0; i < 4; i++ {\n\t\t\tvar j uint\n\t\t\tfor j = i + 1; j < 4; j++ {\n\t\t\t\tif histo[j] > histo[i] {\n\t\t\t\t\tvar tmp uint32 = histo[j]\n\t\t\t\t\thisto[j] = histo[i]\n\t\t\t\t\thisto[i] = tmp\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\th23 = histo[2] + histo[3]\n\t\thistomax = brotli_max_uint32_t(h23, histo[0])\n\t\treturn kFourSymbolHistogramCost + 3*float64(h23) + 2*(float64(histo[0])+float64(histo[1])) - float64(histomax)\n\t}\n\t{\n\t\tvar max_depth uint = 1\n\t\tvar depth_histo = [codeLengthCodes]uint32{0}\n\t\t/* In this loop we compute the entropy of the histogram and simultaneously\n\t\t   build a simplified histogram of the code length codes where we use the\n\t\t   zero repeat code 17, but we don't use the non-zero repeat code 16. */\n\n\t\tvar log2total float64 = fastLog2(histogram.total_count_)\n\t\tfor i = 0; i < data_size; {\n\t\t\tif histogram.data_[i] > 0 {\n\t\t\t\tvar log2p float64 = log2total - fastLog2(uint(histogram.data_[i]))\n\t\t\t\t/* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =\n\t\t\t\t   = log2(total_count) - log2(count(symbol)) */\n\n\t\t\t\tvar depth uint = uint(log2p + 0.5)\n\t\t\t\t/* Approximate the bit depth by round(-log2(P(symbol))) */\n\t\t\t\tbits += float64(histogram.data_[i]) * log2p\n\n\t\t\t\tif depth > 15 {\n\t\t\t\t\tdepth = 15\n\t\t\t\t}\n\n\t\t\t\tif depth > max_depth {\n\t\t\t\t\tmax_depth = depth\n\t\t\t\t}\n\n\t\t\t\tdepth_histo[depth]++\n\t\t\t\ti++\n\t\t\t} else {\n\t\t\t\tvar reps uint32 = 1\n\t\t\t\t/* Compute the run length of zeros and add the appropriate number of 0\n\t\t\t\t   and 17 code length codes to the code length code histogram. */\n\n\t\t\t\tvar k uint\n\t\t\t\tfor k = i + 1; k < data_size && histogram.data_[k] == 0; k++ {\n\t\t\t\t\treps++\n\t\t\t\t}\n\n\t\t\t\ti += uint(reps)\n\t\t\t\tif i == data_size {\n\t\t\t\t\t/* Don't add any cost for the last zero run, since these are encoded\n\t\t\t\t\t   only implicitly. */\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif reps < 3 {\n\t\t\t\t\tdepth_histo[0] += reps\n\t\t\t\t} else {\n\t\t\t\t\treps -= 2\n\t\t\t\t\tfor reps > 0 {\n\t\t\t\t\t\tdepth_histo[repeatZeroCodeLength]++\n\n\t\t\t\t\t\t/* Add the 3 extra bits for the 17 code length code. */\n\t\t\t\t\t\tbits += 3\n\n\t\t\t\t\t\treps >>= 3\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* Add the estimated encoding cost of the code length code histogram. */\n\t\tbits += float64(18 + 2*max_depth)\n\n\t\t/* Add the entropy of the code length code histogram. */\n\t\tbits += bitsEntropy(depth_histo[:], codeLengthCodes)\n\t}\n\n\treturn bits\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/bit_reader.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Bit reading helpers */\n\nconst shortFillBitWindowRead = (8 >> 1)\n\nvar kBitMask = [33]uint32{\n\t0x00000000,\n\t0x00000001,\n\t0x00000003,\n\t0x00000007,\n\t0x0000000F,\n\t0x0000001F,\n\t0x0000003F,\n\t0x0000007F,\n\t0x000000FF,\n\t0x000001FF,\n\t0x000003FF,\n\t0x000007FF,\n\t0x00000FFF,\n\t0x00001FFF,\n\t0x00003FFF,\n\t0x00007FFF,\n\t0x0000FFFF,\n\t0x0001FFFF,\n\t0x0003FFFF,\n\t0x0007FFFF,\n\t0x000FFFFF,\n\t0x001FFFFF,\n\t0x003FFFFF,\n\t0x007FFFFF,\n\t0x00FFFFFF,\n\t0x01FFFFFF,\n\t0x03FFFFFF,\n\t0x07FFFFFF,\n\t0x0FFFFFFF,\n\t0x1FFFFFFF,\n\t0x3FFFFFFF,\n\t0x7FFFFFFF,\n\t0xFFFFFFFF,\n}\n\nfunc bitMask(n uint32) uint32 {\n\treturn kBitMask[n]\n}\n\ntype bitReader struct {\n\tval_      uint64\n\tbit_pos_  uint32\n\tinput     []byte\n\tinput_len uint\n\tbyte_pos  uint\n}\n\ntype bitReaderState struct {\n\tval_      uint64\n\tbit_pos_  uint32\n\tinput     []byte\n\tinput_len uint\n\tbyte_pos  uint\n}\n\n/* Initializes the BrotliBitReader fields. */\n\n/* Ensures that accumulator is not empty.\n   May consume up to sizeof(brotli_reg_t) - 1 bytes of input.\n   Returns false if data is required but there is no input available.\n   For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned\n   reading. */\nfunc bitReaderSaveState(from *bitReader, to *bitReaderState) {\n\tto.val_ = from.val_\n\tto.bit_pos_ = from.bit_pos_\n\tto.input = from.input\n\tto.input_len = from.input_len\n\tto.byte_pos = from.byte_pos\n}\n\nfunc bitReaderRestoreState(to *bitReader, from *bitReaderState) {\n\tto.val_ = from.val_\n\tto.bit_pos_ = from.bit_pos_\n\tto.input = from.input\n\tto.input_len = from.input_len\n\tto.byte_pos = from.byte_pos\n}\n\nfunc getAvailableBits(br *bitReader) uint32 {\n\treturn 64 - br.bit_pos_\n}\n\n/* Returns amount of unread bytes the bit reader still has buffered from the\n   BrotliInput, including whole bytes in br->val_. */\nfunc getRemainingBytes(br *bitReader) uint {\n\treturn uint(uint32(br.input_len-br.byte_pos) + (getAvailableBits(br) >> 3))\n}\n\n/* Checks if there is at least |num| bytes left in the input ring-buffer\n   (excluding the bits remaining in br->val_). */\nfunc checkInputAmount(br *bitReader, num uint) bool {\n\treturn br.input_len-br.byte_pos >= num\n}\n\n/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.\n   Precondition: accumulator contains at least 1 bit.\n   |n_bits| should be in the range [1..24] for regular build. For portable\n   non-64-bit little-endian build only 16 bits are safe to request. */\nfunc fillBitWindow(br *bitReader, n_bits uint32) {\n\tif br.bit_pos_ >= 32 {\n\t\tbr.val_ >>= 32\n\t\tbr.bit_pos_ ^= 32 /* here same as -= 32 because of the if condition */\n\t\tbr.val_ |= (uint64(binary.LittleEndian.Uint32(br.input[br.byte_pos:]))) << 32\n\t\tbr.byte_pos += 4\n\t}\n}\n\n/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no\n   more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */\nfunc fillBitWindow16(br *bitReader) {\n\tfillBitWindow(br, 17)\n}\n\n/* Tries to pull one byte of input to accumulator.\n   Returns false if there is no input available. */\nfunc pullByte(br *bitReader) bool {\n\tif br.byte_pos == br.input_len {\n\t\treturn false\n\t}\n\n\tbr.val_ >>= 8\n\tbr.val_ |= (uint64(br.input[br.byte_pos])) << 56\n\tbr.bit_pos_ -= 8\n\tbr.byte_pos++\n\treturn true\n}\n\n/* Returns currently available bits.\n   The number of valid bits could be calculated by BrotliGetAvailableBits. */\nfunc getBitsUnmasked(br *bitReader) uint64 {\n\treturn br.val_ >> br.bit_pos_\n}\n\n/* Like BrotliGetBits, but does not mask the result.\n   The result contains at least 16 valid bits. */\nfunc get16BitsUnmasked(br *bitReader) uint32 {\n\tfillBitWindow(br, 16)\n\treturn uint32(getBitsUnmasked(br))\n}\n\n/* Returns the specified number of bits from |br| without advancing bit\n   position. */\nfunc getBits(br *bitReader, n_bits uint32) uint32 {\n\tfillBitWindow(br, n_bits)\n\treturn uint32(getBitsUnmasked(br)) & bitMask(n_bits)\n}\n\n/* Tries to peek the specified amount of bits. Returns false, if there\n   is not enough input. */\nfunc safeGetBits(br *bitReader, n_bits uint32, val *uint32) bool {\n\tfor getAvailableBits(br) < n_bits {\n\t\tif !pullByte(br) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t*val = uint32(getBitsUnmasked(br)) & bitMask(n_bits)\n\treturn true\n}\n\n/* Advances the bit pos by |n_bits|. */\nfunc dropBits(br *bitReader, n_bits uint32) {\n\tbr.bit_pos_ += n_bits\n}\n\nfunc bitReaderUnload(br *bitReader) {\n\tvar unused_bytes uint32 = getAvailableBits(br) >> 3\n\tvar unused_bits uint32 = unused_bytes << 3\n\tbr.byte_pos -= uint(unused_bytes)\n\tif unused_bits == 64 {\n\t\tbr.val_ = 0\n\t} else {\n\t\tbr.val_ <<= unused_bits\n\t}\n\n\tbr.bit_pos_ += unused_bits\n}\n\n/* Reads the specified number of bits from |br| and advances the bit pos.\n   Precondition: accumulator MUST contain at least |n_bits|. */\nfunc takeBits(br *bitReader, n_bits uint32, val *uint32) {\n\t*val = uint32(getBitsUnmasked(br)) & bitMask(n_bits)\n\tdropBits(br, n_bits)\n}\n\n/* Reads the specified number of bits from |br| and advances the bit pos.\n   Assumes that there is enough input to perform BrotliFillBitWindow. */\nfunc readBits(br *bitReader, n_bits uint32) uint32 {\n\tvar val uint32\n\tfillBitWindow(br, n_bits)\n\ttakeBits(br, n_bits, &val)\n\treturn val\n}\n\n/* Tries to read the specified amount of bits. Returns false, if there\n   is not enough input. |n_bits| MUST be positive. */\nfunc safeReadBits(br *bitReader, n_bits uint32, val *uint32) bool {\n\tfor getAvailableBits(br) < n_bits {\n\t\tif !pullByte(br) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\ttakeBits(br, n_bits, val)\n\treturn true\n}\n\n/* Advances the bit reader position to the next byte boundary and verifies\n   that any skipped bits are set to zero. */\nfunc bitReaderJumpToByteBoundary(br *bitReader) bool {\n\tvar pad_bits_count uint32 = getAvailableBits(br) & 0x7\n\tvar pad_bits uint32 = 0\n\tif pad_bits_count != 0 {\n\t\ttakeBits(br, pad_bits_count, &pad_bits)\n\t}\n\n\treturn pad_bits == 0\n}\n\n/* Copies remaining input bytes stored in the bit reader to the output. Value\n   |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be\n   warmed up again after this. */\nfunc copyBytes(dest []byte, br *bitReader, num uint) {\n\tfor getAvailableBits(br) >= 8 && num > 0 {\n\t\tdest[0] = byte(getBitsUnmasked(br))\n\t\tdropBits(br, 8)\n\t\tdest = dest[1:]\n\t\tnum--\n\t}\n\n\tcopy(dest, br.input[br.byte_pos:][:num])\n\tbr.byte_pos += num\n}\n\nfunc initBitReader(br *bitReader) {\n\tbr.val_ = 0\n\tbr.bit_pos_ = 64\n}\n\nfunc warmupBitReader(br *bitReader) bool {\n\t/* Fixing alignment after unaligned BrotliFillWindow would result accumulator\n\t   overflow. If unalignment is caused by BrotliSafeReadBits, then there is\n\t   enough space in accumulator to fix alignment. */\n\tif getAvailableBits(br) == 0 {\n\t\tif !pullByte(br) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/bitwriter.go",
    "content": "package brotli\n\n/* Copyright 2010 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Write bits into a byte array. */\n\ntype bitWriter struct {\n\tdst []byte\n\n\t// Data waiting to be written is the low nbits of bits.\n\tbits  uint64\n\tnbits uint\n}\n\nfunc (w *bitWriter) writeBits(nb uint, b uint64) {\n\tw.bits |= b << w.nbits\n\tw.nbits += nb\n\tif w.nbits >= 32 {\n\t\tbits := w.bits\n\t\tw.bits >>= 32\n\t\tw.nbits -= 32\n\t\tw.dst = append(w.dst,\n\t\t\tbyte(bits),\n\t\t\tbyte(bits>>8),\n\t\t\tbyte(bits>>16),\n\t\t\tbyte(bits>>24),\n\t\t)\n\t}\n}\n\nfunc (w *bitWriter) writeSingleBit(bit bool) {\n\tif bit {\n\t\tw.writeBits(1, 1)\n\t} else {\n\t\tw.writeBits(1, 0)\n\t}\n}\n\nfunc (w *bitWriter) jumpToByteBoundary() {\n\tdst := w.dst\n\tfor w.nbits != 0 {\n\t\tdst = append(dst, byte(w.bits))\n\t\tw.bits >>= 8\n\t\tif w.nbits > 8 { // Avoid underflow\n\t\t\tw.nbits -= 8\n\t\t} else {\n\t\t\tw.nbits = 0\n\t\t}\n\t}\n\tw.bits = 0\n\tw.dst = dst\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/block_splitter.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Block split point selection utilities. */\n\ntype blockSplit struct {\n\tnum_types          uint\n\tnum_blocks         uint\n\ttypes              []byte\n\tlengths            []uint32\n\ttypes_alloc_size   uint\n\tlengths_alloc_size uint\n}\n\nconst (\n\tkMaxLiteralHistograms        uint    = 100\n\tkMaxCommandHistograms        uint    = 50\n\tkLiteralBlockSwitchCost      float64 = 28.1\n\tkCommandBlockSwitchCost      float64 = 13.5\n\tkDistanceBlockSwitchCost     float64 = 14.6\n\tkLiteralStrideLength         uint    = 70\n\tkCommandStrideLength         uint    = 40\n\tkSymbolsPerLiteralHistogram  uint    = 544\n\tkSymbolsPerCommandHistogram  uint    = 530\n\tkSymbolsPerDistanceHistogram uint    = 544\n\tkMinLengthForBlockSplitting  uint    = 128\n\tkIterMulForRefining          uint    = 2\n\tkMinItersForRefining         uint    = 100\n)\n\nfunc countLiterals(cmds []command) uint {\n\tvar total_length uint = 0\n\t/* Count how many we have. */\n\n\tfor i := range cmds {\n\t\ttotal_length += uint(cmds[i].insert_len_)\n\t}\n\n\treturn total_length\n}\n\nfunc copyLiteralsToByteArray(cmds []command, data []byte, offset uint, mask uint, literals []byte) {\n\tvar pos uint = 0\n\tvar from_pos uint = offset & mask\n\tfor i := range cmds {\n\t\tvar insert_len uint = uint(cmds[i].insert_len_)\n\t\tif from_pos+insert_len > mask {\n\t\t\tvar head_size uint = mask + 1 - from_pos\n\t\t\tcopy(literals[pos:], data[from_pos:][:head_size])\n\t\t\tfrom_pos = 0\n\t\t\tpos += head_size\n\t\t\tinsert_len -= head_size\n\t\t}\n\n\t\tif insert_len > 0 {\n\t\t\tcopy(literals[pos:], data[from_pos:][:insert_len])\n\t\t\tpos += insert_len\n\t\t}\n\n\t\tfrom_pos = uint((uint32(from_pos+insert_len) + commandCopyLen(&cmds[i])) & uint32(mask))\n\t}\n}\n\nfunc myRand(seed *uint32) uint32 {\n\t/* Initial seed should be 7. In this case, loop length is (1 << 29). */\n\t*seed *= 16807\n\n\treturn *seed\n}\n\nfunc bitCost(count uint) float64 {\n\tif count == 0 {\n\t\treturn -2.0\n\t} else {\n\t\treturn fastLog2(count)\n\t}\n}\n\nconst histogramsPerBatch = 64\n\nconst clustersPerBatch = 16\n\nfunc initBlockSplit(self *blockSplit) {\n\tself.num_types = 0\n\tself.num_blocks = 0\n\tself.types = self.types[:0]\n\tself.lengths = self.lengths[:0]\n\tself.types_alloc_size = 0\n\tself.lengths_alloc_size = 0\n}\n\nfunc splitBlock(cmds []command, data []byte, pos uint, mask uint, params *encoderParams, literal_split *blockSplit, insert_and_copy_split *blockSplit, dist_split *blockSplit) {\n\t{\n\t\tvar literals_count uint = countLiterals(cmds)\n\t\tvar literals []byte = make([]byte, literals_count)\n\n\t\t/* Create a continuous array of literals. */\n\t\tcopyLiteralsToByteArray(cmds, data, pos, mask, literals)\n\n\t\t/* Create the block split on the array of literals.\n\t\t   Literal histograms have alphabet size 256. */\n\t\tsplitByteVectorLiteral(literals, literals_count, kSymbolsPerLiteralHistogram, kMaxLiteralHistograms, kLiteralStrideLength, kLiteralBlockSwitchCost, params, literal_split)\n\n\t\tliterals = nil\n\t}\n\t{\n\t\tvar insert_and_copy_codes []uint16 = make([]uint16, len(cmds))\n\t\t/* Compute prefix codes for commands. */\n\n\t\tfor i := range cmds {\n\t\t\tinsert_and_copy_codes[i] = cmds[i].cmd_prefix_\n\t\t}\n\n\t\t/* Create the block split on the array of command prefixes. */\n\t\tsplitByteVectorCommand(insert_and_copy_codes, kSymbolsPerCommandHistogram, kMaxCommandHistograms, kCommandStrideLength, kCommandBlockSwitchCost, params, insert_and_copy_split)\n\n\t\t/* TODO: reuse for distances? */\n\n\t\tinsert_and_copy_codes = nil\n\t}\n\t{\n\t\tvar distance_prefixes []uint16 = make([]uint16, len(cmds))\n\t\tvar j uint = 0\n\t\t/* Create a continuous array of distance prefixes. */\n\n\t\tfor i := range cmds {\n\t\t\tvar cmd *command = &cmds[i]\n\t\t\tif commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {\n\t\t\t\tdistance_prefixes[j] = cmd.dist_prefix_ & 0x3FF\n\t\t\t\tj++\n\t\t\t}\n\t\t}\n\n\t\t/* Create the block split on the array of distance prefixes. */\n\t\tsplitByteVectorDistance(distance_prefixes, j, kSymbolsPerDistanceHistogram, kMaxCommandHistograms, kCommandStrideLength, kDistanceBlockSwitchCost, params, dist_split)\n\n\t\tdistance_prefixes = nil\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/block_splitter_command.go",
    "content": "package brotli\n\nimport \"math\"\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nfunc initialEntropyCodesCommand(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramCommand) {\n\tvar seed uint32 = 7\n\tvar block_length uint = length / num_histograms\n\tvar i uint\n\tclearHistogramsCommand(histograms, num_histograms)\n\tfor i = 0; i < num_histograms; i++ {\n\t\tvar pos uint = length * i / num_histograms\n\t\tif i != 0 {\n\t\t\tpos += uint(myRand(&seed) % uint32(block_length))\n\t\t}\n\n\t\tif pos+stride >= length {\n\t\t\tpos = length - stride - 1\n\t\t}\n\n\t\thistogramAddVectorCommand(&histograms[i], data[pos:], stride)\n\t}\n}\n\nfunc randomSampleCommand(seed *uint32, data []uint16, length uint, stride uint, sample *histogramCommand) {\n\tvar pos uint = 0\n\tif stride >= length {\n\t\tstride = length\n\t} else {\n\t\tpos = uint(myRand(seed) % uint32(length-stride+1))\n\t}\n\n\thistogramAddVectorCommand(sample, data[pos:], stride)\n}\n\nfunc refineEntropyCodesCommand(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramCommand) {\n\tvar iters uint = kIterMulForRefining*length/stride + kMinItersForRefining\n\tvar seed uint32 = 7\n\tvar iter uint\n\titers = ((iters + num_histograms - 1) / num_histograms) * num_histograms\n\tfor iter = 0; iter < iters; iter++ {\n\t\tvar sample histogramCommand\n\t\thistogramClearCommand(&sample)\n\t\trandomSampleCommand(&seed, data, length, stride, &sample)\n\t\thistogramAddHistogramCommand(&histograms[iter%num_histograms], &sample)\n\t}\n}\n\n/* Assigns a block id from the range [0, num_histograms) to each data element\n   in data[0..length) and fills in block_id[0..length) with the assigned values.\n   Returns the number of blocks, i.e. one plus the number of block switches. */\nfunc findBlocksCommand(data []uint16, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramCommand, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {\n\tvar data_size uint = histogramDataSizeCommand()\n\tvar bitmaplen uint = (num_histograms + 7) >> 3\n\tvar num_blocks uint = 1\n\tvar i uint\n\tvar j uint\n\tassert(num_histograms <= 256)\n\tif num_histograms <= 1 {\n\t\tfor i = 0; i < length; i++ {\n\t\t\tblock_id[i] = 0\n\t\t}\n\n\t\treturn 1\n\t}\n\n\tfor i := 0; i < int(data_size*num_histograms); i++ {\n\t\tinsert_cost[i] = 0\n\t}\n\tfor i = 0; i < num_histograms; i++ {\n\t\tinsert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))\n\t}\n\n\tfor i = data_size; i != 0; {\n\t\ti--\n\t\tfor j = 0; j < num_histograms; j++ {\n\t\t\tinsert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))\n\t\t}\n\t}\n\n\tfor i := 0; i < int(num_histograms); i++ {\n\t\tcost[i] = 0\n\t}\n\tfor i := 0; i < int(length*bitmaplen); i++ {\n\t\tswitch_signal[i] = 0\n\t}\n\n\t/* After each iteration of this loop, cost[k] will contain the difference\n\t   between the minimum cost of arriving at the current byte position using\n\t   entropy code k, and the minimum cost of arriving at the current byte\n\t   position. This difference is capped at the block switch cost, and if it\n\t   reaches block switch cost, it means that when we trace back from the last\n\t   position, we need to switch here. */\n\tfor i = 0; i < length; i++ {\n\t\tvar byte_ix uint = i\n\t\tvar ix uint = byte_ix * bitmaplen\n\t\tvar insert_cost_ix uint = uint(data[byte_ix]) * num_histograms\n\t\tvar min_cost float64 = 1e99\n\t\tvar block_switch_cost float64 = block_switch_bitcost\n\t\tvar k uint\n\t\tfor k = 0; k < num_histograms; k++ {\n\t\t\t/* We are coding the symbol in data[byte_ix] with entropy code k. */\n\t\t\tcost[k] += insert_cost[insert_cost_ix+k]\n\n\t\t\tif cost[k] < min_cost {\n\t\t\t\tmin_cost = cost[k]\n\t\t\t\tblock_id[byte_ix] = byte(k)\n\t\t\t}\n\t\t}\n\n\t\t/* More blocks for the beginning. */\n\t\tif byte_ix < 2000 {\n\t\t\tblock_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000\n\t\t}\n\n\t\tfor k = 0; k < num_histograms; k++ {\n\t\t\tcost[k] -= min_cost\n\t\t\tif cost[k] >= block_switch_cost {\n\t\t\t\tvar mask byte = byte(1 << (k & 7))\n\t\t\t\tcost[k] = block_switch_cost\n\t\t\t\tassert(k>>3 < bitmaplen)\n\t\t\t\tswitch_signal[ix+(k>>3)] |= mask\n\t\t\t\t/* Trace back from the last position and switch at the marked places. */\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tvar byte_ix uint = length - 1\n\t\tvar ix uint = byte_ix * bitmaplen\n\t\tvar cur_id byte = block_id[byte_ix]\n\t\tfor byte_ix > 0 {\n\t\t\tvar mask byte = byte(1 << (cur_id & 7))\n\t\t\tassert(uint(cur_id)>>3 < bitmaplen)\n\t\t\tbyte_ix--\n\t\t\tix -= bitmaplen\n\t\t\tif switch_signal[ix+uint(cur_id>>3)]&mask != 0 {\n\t\t\t\tif cur_id != block_id[byte_ix] {\n\t\t\t\t\tcur_id = block_id[byte_ix]\n\t\t\t\t\tnum_blocks++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tblock_id[byte_ix] = cur_id\n\t\t}\n\t}\n\n\treturn num_blocks\n}\n\nvar remapBlockIdsCommand_kInvalidId uint16 = 256\n\nfunc remapBlockIdsCommand(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {\n\tvar next_id uint16 = 0\n\tvar i uint\n\tfor i = 0; i < num_histograms; i++ {\n\t\tnew_id[i] = remapBlockIdsCommand_kInvalidId\n\t}\n\n\tfor i = 0; i < length; i++ {\n\t\tassert(uint(block_ids[i]) < num_histograms)\n\t\tif new_id[block_ids[i]] == remapBlockIdsCommand_kInvalidId {\n\t\t\tnew_id[block_ids[i]] = next_id\n\t\t\tnext_id++\n\t\t}\n\t}\n\n\tfor i = 0; i < length; i++ {\n\t\tblock_ids[i] = byte(new_id[block_ids[i]])\n\t\tassert(uint(block_ids[i]) < num_histograms)\n\t}\n\n\tassert(uint(next_id) <= num_histograms)\n\treturn uint(next_id)\n}\n\nfunc buildBlockHistogramsCommand(data []uint16, length uint, block_ids []byte, num_histograms uint, histograms []histogramCommand) {\n\tvar i uint\n\tclearHistogramsCommand(histograms, num_histograms)\n\tfor i = 0; i < length; i++ {\n\t\thistogramAddCommand(&histograms[block_ids[i]], uint(data[i]))\n\t}\n}\n\nvar clusterBlocksCommand_kInvalidIndex uint32 = math.MaxUint32\n\nfunc clusterBlocksCommand(data []uint16, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {\n\tvar histogram_symbols []uint32 = make([]uint32, num_blocks)\n\tvar block_lengths []uint32 = make([]uint32, num_blocks)\n\tvar expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch\n\tvar all_histograms_size uint = 0\n\tvar all_histograms_capacity uint = expected_num_clusters\n\tvar all_histograms []histogramCommand = make([]histogramCommand, all_histograms_capacity)\n\tvar cluster_size_size uint = 0\n\tvar cluster_size_capacity uint = expected_num_clusters\n\tvar cluster_size []uint32 = make([]uint32, cluster_size_capacity)\n\tvar num_clusters uint = 0\n\tvar histograms []histogramCommand = make([]histogramCommand, brotli_min_size_t(num_blocks, histogramsPerBatch))\n\tvar max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2\n\tvar pairs_capacity uint = max_num_pairs + 1\n\tvar pairs []histogramPair = make([]histogramPair, pairs_capacity)\n\tvar pos uint = 0\n\tvar clusters []uint32\n\tvar num_final_clusters uint\n\tvar new_index []uint32\n\tvar i uint\n\tvar sizes = [histogramsPerBatch]uint32{0}\n\tvar new_clusters = [histogramsPerBatch]uint32{0}\n\tvar symbols = [histogramsPerBatch]uint32{0}\n\tvar remap = [histogramsPerBatch]uint32{0}\n\n\tfor i := 0; i < int(num_blocks); i++ {\n\t\tblock_lengths[i] = 0\n\t}\n\t{\n\t\tvar block_idx uint = 0\n\t\tfor i = 0; i < length; i++ {\n\t\t\tassert(block_idx < num_blocks)\n\t\t\tblock_lengths[block_idx]++\n\t\t\tif i+1 == length || block_ids[i] != block_ids[i+1] {\n\t\t\t\tblock_idx++\n\t\t\t}\n\t\t}\n\n\t\tassert(block_idx == num_blocks)\n\t}\n\n\tfor i = 0; i < num_blocks; i += histogramsPerBatch {\n\t\tvar num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)\n\t\tvar num_new_clusters uint\n\t\tvar j uint\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\tvar k uint\n\t\t\thistogramClearCommand(&histograms[j])\n\t\t\tfor k = 0; uint32(k) < block_lengths[i+j]; k++ {\n\t\t\t\thistogramAddCommand(&histograms[j], uint(data[pos]))\n\t\t\t\tpos++\n\t\t\t}\n\n\t\t\thistograms[j].bit_cost_ = populationCostCommand(&histograms[j])\n\t\t\tnew_clusters[j] = uint32(j)\n\t\t\tsymbols[j] = uint32(j)\n\t\t\tsizes[j] = 1\n\t\t}\n\n\t\tnum_new_clusters = histogramCombineCommand(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)\n\t\tif all_histograms_capacity < (all_histograms_size + num_new_clusters) {\n\t\t\tvar _new_size uint\n\t\t\tif all_histograms_capacity == 0 {\n\t\t\t\t_new_size = all_histograms_size + num_new_clusters\n\t\t\t} else {\n\t\t\t\t_new_size = all_histograms_capacity\n\t\t\t}\n\t\t\tvar new_array []histogramCommand\n\t\t\tfor _new_size < (all_histograms_size + num_new_clusters) {\n\t\t\t\t_new_size *= 2\n\t\t\t}\n\t\t\tnew_array = make([]histogramCommand, _new_size)\n\t\t\tif all_histograms_capacity != 0 {\n\t\t\t\tcopy(new_array, all_histograms[:all_histograms_capacity])\n\t\t\t}\n\n\t\t\tall_histograms = new_array\n\t\t\tall_histograms_capacity = _new_size\n\t\t}\n\n\t\tbrotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)\n\t\tfor j = 0; j < num_new_clusters; j++ {\n\t\t\tall_histograms[all_histograms_size] = histograms[new_clusters[j]]\n\t\t\tall_histograms_size++\n\t\t\tcluster_size[cluster_size_size] = sizes[new_clusters[j]]\n\t\t\tcluster_size_size++\n\t\t\tremap[new_clusters[j]] = uint32(j)\n\t\t}\n\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\thistogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]\n\t\t}\n\n\t\tnum_clusters += num_new_clusters\n\t\tassert(num_clusters == cluster_size_size)\n\t\tassert(num_clusters == all_histograms_size)\n\t}\n\n\thistograms = nil\n\n\tmax_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)\n\tif pairs_capacity < max_num_pairs+1 {\n\t\tpairs = nil\n\t\tpairs = make([]histogramPair, (max_num_pairs + 1))\n\t}\n\n\tclusters = make([]uint32, num_clusters)\n\tfor i = 0; i < num_clusters; i++ {\n\t\tclusters[i] = uint32(i)\n\t}\n\n\tnum_final_clusters = histogramCombineCommand(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)\n\tpairs = nil\n\tcluster_size = nil\n\n\tnew_index = make([]uint32, num_clusters)\n\tfor i = 0; i < num_clusters; i++ {\n\t\tnew_index[i] = clusterBlocksCommand_kInvalidIndex\n\t}\n\tpos = 0\n\t{\n\t\tvar next_index uint32 = 0\n\t\tfor i = 0; i < num_blocks; i++ {\n\t\t\tvar histo histogramCommand\n\t\t\tvar j uint\n\t\t\tvar best_out uint32\n\t\t\tvar best_bits float64\n\t\t\thistogramClearCommand(&histo)\n\t\t\tfor j = 0; uint32(j) < block_lengths[i]; j++ {\n\t\t\t\thistogramAddCommand(&histo, uint(data[pos]))\n\t\t\t\tpos++\n\t\t\t}\n\n\t\t\tif i == 0 {\n\t\t\t\tbest_out = histogram_symbols[0]\n\t\t\t} else {\n\t\t\t\tbest_out = histogram_symbols[i-1]\n\t\t\t}\n\t\t\tbest_bits = histogramBitCostDistanceCommand(&histo, &all_histograms[best_out])\n\t\t\tfor j = 0; j < num_final_clusters; j++ {\n\t\t\t\tvar cur_bits float64 = histogramBitCostDistanceCommand(&histo, &all_histograms[clusters[j]])\n\t\t\t\tif cur_bits < best_bits {\n\t\t\t\t\tbest_bits = cur_bits\n\t\t\t\t\tbest_out = clusters[j]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\thistogram_symbols[i] = best_out\n\t\t\tif new_index[best_out] == clusterBlocksCommand_kInvalidIndex {\n\t\t\t\tnew_index[best_out] = next_index\n\t\t\t\tnext_index++\n\t\t\t}\n\t\t}\n\t}\n\n\tclusters = nil\n\tall_histograms = nil\n\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)\n\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)\n\t{\n\t\tvar cur_length uint32 = 0\n\t\tvar block_idx uint = 0\n\t\tvar max_type byte = 0\n\t\tfor i = 0; i < num_blocks; i++ {\n\t\t\tcur_length += block_lengths[i]\n\t\t\tif i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {\n\t\t\t\tvar id byte = byte(new_index[histogram_symbols[i]])\n\t\t\t\tsplit.types[block_idx] = id\n\t\t\t\tsplit.lengths[block_idx] = cur_length\n\t\t\t\tmax_type = brotli_max_uint8_t(max_type, id)\n\t\t\t\tcur_length = 0\n\t\t\t\tblock_idx++\n\t\t\t}\n\t\t}\n\n\t\tsplit.num_blocks = block_idx\n\t\tsplit.num_types = uint(max_type) + 1\n\t}\n\n\tnew_index = nil\n\tblock_lengths = nil\n\thistogram_symbols = nil\n}\n\nfunc splitByteVectorCommand(data []uint16, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {\n\tlength := uint(len(data))\n\tvar data_size uint = histogramDataSizeCommand()\n\tvar num_histograms uint = length/literals_per_histogram + 1\n\tvar histograms []histogramCommand\n\tif num_histograms > max_histograms {\n\t\tnum_histograms = max_histograms\n\t}\n\n\tif length == 0 {\n\t\tsplit.num_types = 1\n\t\treturn\n\t} else if length < kMinLengthForBlockSplitting {\n\t\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)\n\t\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)\n\t\tsplit.num_types = 1\n\t\tsplit.types[split.num_blocks] = 0\n\t\tsplit.lengths[split.num_blocks] = uint32(length)\n\t\tsplit.num_blocks++\n\t\treturn\n\t}\n\n\thistograms = make([]histogramCommand, num_histograms)\n\n\t/* Find good entropy codes. */\n\tinitialEntropyCodesCommand(data, length, sampling_stride_length, num_histograms, histograms)\n\n\trefineEntropyCodesCommand(data, length, sampling_stride_length, num_histograms, histograms)\n\t{\n\t\tvar block_ids []byte = make([]byte, length)\n\t\tvar num_blocks uint = 0\n\t\tvar bitmaplen uint = (num_histograms + 7) >> 3\n\t\tvar insert_cost []float64 = make([]float64, (data_size * num_histograms))\n\t\tvar cost []float64 = make([]float64, num_histograms)\n\t\tvar switch_signal []byte = make([]byte, (length * bitmaplen))\n\t\tvar new_id []uint16 = make([]uint16, num_histograms)\n\t\tvar iters uint\n\t\tif params.quality < hqZopflificationQuality {\n\t\t\titers = 3\n\t\t} else {\n\t\t\titers = 10\n\t\t}\n\t\t/* Find a good path through literals with the good entropy codes. */\n\n\t\tvar i uint\n\t\tfor i = 0; i < iters; i++ {\n\t\t\tnum_blocks = findBlocksCommand(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)\n\t\t\tnum_histograms = remapBlockIdsCommand(block_ids, length, new_id, num_histograms)\n\t\t\tbuildBlockHistogramsCommand(data, length, block_ids, num_histograms, histograms)\n\t\t}\n\n\t\tinsert_cost = nil\n\t\tcost = nil\n\t\tswitch_signal = nil\n\t\tnew_id = nil\n\t\thistograms = nil\n\t\tclusterBlocksCommand(data, length, num_blocks, block_ids, split)\n\t\tblock_ids = nil\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/block_splitter_distance.go",
    "content": "package brotli\n\nimport \"math\"\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nfunc initialEntropyCodesDistance(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramDistance) {\n\tvar seed uint32 = 7\n\tvar block_length uint = length / num_histograms\n\tvar i uint\n\tclearHistogramsDistance(histograms, num_histograms)\n\tfor i = 0; i < num_histograms; i++ {\n\t\tvar pos uint = length * i / num_histograms\n\t\tif i != 0 {\n\t\t\tpos += uint(myRand(&seed) % uint32(block_length))\n\t\t}\n\n\t\tif pos+stride >= length {\n\t\t\tpos = length - stride - 1\n\t\t}\n\n\t\thistogramAddVectorDistance(&histograms[i], data[pos:], stride)\n\t}\n}\n\nfunc randomSampleDistance(seed *uint32, data []uint16, length uint, stride uint, sample *histogramDistance) {\n\tvar pos uint = 0\n\tif stride >= length {\n\t\tstride = length\n\t} else {\n\t\tpos = uint(myRand(seed) % uint32(length-stride+1))\n\t}\n\n\thistogramAddVectorDistance(sample, data[pos:], stride)\n}\n\nfunc refineEntropyCodesDistance(data []uint16, length uint, stride uint, num_histograms uint, histograms []histogramDistance) {\n\tvar iters uint = kIterMulForRefining*length/stride + kMinItersForRefining\n\tvar seed uint32 = 7\n\tvar iter uint\n\titers = ((iters + num_histograms - 1) / num_histograms) * num_histograms\n\tfor iter = 0; iter < iters; iter++ {\n\t\tvar sample histogramDistance\n\t\thistogramClearDistance(&sample)\n\t\trandomSampleDistance(&seed, data, length, stride, &sample)\n\t\thistogramAddHistogramDistance(&histograms[iter%num_histograms], &sample)\n\t}\n}\n\n/* Assigns a block id from the range [0, num_histograms) to each data element\n   in data[0..length) and fills in block_id[0..length) with the assigned values.\n   Returns the number of blocks, i.e. one plus the number of block switches. */\nfunc findBlocksDistance(data []uint16, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramDistance, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {\n\tvar data_size uint = histogramDataSizeDistance()\n\tvar bitmaplen uint = (num_histograms + 7) >> 3\n\tvar num_blocks uint = 1\n\tvar i uint\n\tvar j uint\n\tassert(num_histograms <= 256)\n\tif num_histograms <= 1 {\n\t\tfor i = 0; i < length; i++ {\n\t\t\tblock_id[i] = 0\n\t\t}\n\n\t\treturn 1\n\t}\n\n\tfor i := 0; i < int(data_size*num_histograms); i++ {\n\t\tinsert_cost[i] = 0\n\t}\n\tfor i = 0; i < num_histograms; i++ {\n\t\tinsert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))\n\t}\n\n\tfor i = data_size; i != 0; {\n\t\ti--\n\t\tfor j = 0; j < num_histograms; j++ {\n\t\t\tinsert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))\n\t\t}\n\t}\n\n\tfor i := 0; i < int(num_histograms); i++ {\n\t\tcost[i] = 0\n\t}\n\tfor i := 0; i < int(length*bitmaplen); i++ {\n\t\tswitch_signal[i] = 0\n\t}\n\n\t/* After each iteration of this loop, cost[k] will contain the difference\n\t   between the minimum cost of arriving at the current byte position using\n\t   entropy code k, and the minimum cost of arriving at the current byte\n\t   position. This difference is capped at the block switch cost, and if it\n\t   reaches block switch cost, it means that when we trace back from the last\n\t   position, we need to switch here. */\n\tfor i = 0; i < length; i++ {\n\t\tvar byte_ix uint = i\n\t\tvar ix uint = byte_ix * bitmaplen\n\t\tvar insert_cost_ix uint = uint(data[byte_ix]) * num_histograms\n\t\tvar min_cost float64 = 1e99\n\t\tvar block_switch_cost float64 = block_switch_bitcost\n\t\tvar k uint\n\t\tfor k = 0; k < num_histograms; k++ {\n\t\t\t/* We are coding the symbol in data[byte_ix] with entropy code k. */\n\t\t\tcost[k] += insert_cost[insert_cost_ix+k]\n\n\t\t\tif cost[k] < min_cost {\n\t\t\t\tmin_cost = cost[k]\n\t\t\t\tblock_id[byte_ix] = byte(k)\n\t\t\t}\n\t\t}\n\n\t\t/* More blocks for the beginning. */\n\t\tif byte_ix < 2000 {\n\t\t\tblock_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000\n\t\t}\n\n\t\tfor k = 0; k < num_histograms; k++ {\n\t\t\tcost[k] -= min_cost\n\t\t\tif cost[k] >= block_switch_cost {\n\t\t\t\tvar mask byte = byte(1 << (k & 7))\n\t\t\t\tcost[k] = block_switch_cost\n\t\t\t\tassert(k>>3 < bitmaplen)\n\t\t\t\tswitch_signal[ix+(k>>3)] |= mask\n\t\t\t\t/* Trace back from the last position and switch at the marked places. */\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tvar byte_ix uint = length - 1\n\t\tvar ix uint = byte_ix * bitmaplen\n\t\tvar cur_id byte = block_id[byte_ix]\n\t\tfor byte_ix > 0 {\n\t\t\tvar mask byte = byte(1 << (cur_id & 7))\n\t\t\tassert(uint(cur_id)>>3 < bitmaplen)\n\t\t\tbyte_ix--\n\t\t\tix -= bitmaplen\n\t\t\tif switch_signal[ix+uint(cur_id>>3)]&mask != 0 {\n\t\t\t\tif cur_id != block_id[byte_ix] {\n\t\t\t\t\tcur_id = block_id[byte_ix]\n\t\t\t\t\tnum_blocks++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tblock_id[byte_ix] = cur_id\n\t\t}\n\t}\n\n\treturn num_blocks\n}\n\nvar remapBlockIdsDistance_kInvalidId uint16 = 256\n\nfunc remapBlockIdsDistance(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {\n\tvar next_id uint16 = 0\n\tvar i uint\n\tfor i = 0; i < num_histograms; i++ {\n\t\tnew_id[i] = remapBlockIdsDistance_kInvalidId\n\t}\n\n\tfor i = 0; i < length; i++ {\n\t\tassert(uint(block_ids[i]) < num_histograms)\n\t\tif new_id[block_ids[i]] == remapBlockIdsDistance_kInvalidId {\n\t\t\tnew_id[block_ids[i]] = next_id\n\t\t\tnext_id++\n\t\t}\n\t}\n\n\tfor i = 0; i < length; i++ {\n\t\tblock_ids[i] = byte(new_id[block_ids[i]])\n\t\tassert(uint(block_ids[i]) < num_histograms)\n\t}\n\n\tassert(uint(next_id) <= num_histograms)\n\treturn uint(next_id)\n}\n\nfunc buildBlockHistogramsDistance(data []uint16, length uint, block_ids []byte, num_histograms uint, histograms []histogramDistance) {\n\tvar i uint\n\tclearHistogramsDistance(histograms, num_histograms)\n\tfor i = 0; i < length; i++ {\n\t\thistogramAddDistance(&histograms[block_ids[i]], uint(data[i]))\n\t}\n}\n\nvar clusterBlocksDistance_kInvalidIndex uint32 = math.MaxUint32\n\nfunc clusterBlocksDistance(data []uint16, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {\n\tvar histogram_symbols []uint32 = make([]uint32, num_blocks)\n\tvar block_lengths []uint32 = make([]uint32, num_blocks)\n\tvar expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch\n\tvar all_histograms_size uint = 0\n\tvar all_histograms_capacity uint = expected_num_clusters\n\tvar all_histograms []histogramDistance = make([]histogramDistance, all_histograms_capacity)\n\tvar cluster_size_size uint = 0\n\tvar cluster_size_capacity uint = expected_num_clusters\n\tvar cluster_size []uint32 = make([]uint32, cluster_size_capacity)\n\tvar num_clusters uint = 0\n\tvar histograms []histogramDistance = make([]histogramDistance, brotli_min_size_t(num_blocks, histogramsPerBatch))\n\tvar max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2\n\tvar pairs_capacity uint = max_num_pairs + 1\n\tvar pairs []histogramPair = make([]histogramPair, pairs_capacity)\n\tvar pos uint = 0\n\tvar clusters []uint32\n\tvar num_final_clusters uint\n\tvar new_index []uint32\n\tvar i uint\n\tvar sizes = [histogramsPerBatch]uint32{0}\n\tvar new_clusters = [histogramsPerBatch]uint32{0}\n\tvar symbols = [histogramsPerBatch]uint32{0}\n\tvar remap = [histogramsPerBatch]uint32{0}\n\n\tfor i := 0; i < int(num_blocks); i++ {\n\t\tblock_lengths[i] = 0\n\t}\n\t{\n\t\tvar block_idx uint = 0\n\t\tfor i = 0; i < length; i++ {\n\t\t\tassert(block_idx < num_blocks)\n\t\t\tblock_lengths[block_idx]++\n\t\t\tif i+1 == length || block_ids[i] != block_ids[i+1] {\n\t\t\t\tblock_idx++\n\t\t\t}\n\t\t}\n\n\t\tassert(block_idx == num_blocks)\n\t}\n\n\tfor i = 0; i < num_blocks; i += histogramsPerBatch {\n\t\tvar num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)\n\t\tvar num_new_clusters uint\n\t\tvar j uint\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\tvar k uint\n\t\t\thistogramClearDistance(&histograms[j])\n\t\t\tfor k = 0; uint32(k) < block_lengths[i+j]; k++ {\n\t\t\t\thistogramAddDistance(&histograms[j], uint(data[pos]))\n\t\t\t\tpos++\n\t\t\t}\n\n\t\t\thistograms[j].bit_cost_ = populationCostDistance(&histograms[j])\n\t\t\tnew_clusters[j] = uint32(j)\n\t\t\tsymbols[j] = uint32(j)\n\t\t\tsizes[j] = 1\n\t\t}\n\n\t\tnum_new_clusters = histogramCombineDistance(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)\n\t\tif all_histograms_capacity < (all_histograms_size + num_new_clusters) {\n\t\t\tvar _new_size uint\n\t\t\tif all_histograms_capacity == 0 {\n\t\t\t\t_new_size = all_histograms_size + num_new_clusters\n\t\t\t} else {\n\t\t\t\t_new_size = all_histograms_capacity\n\t\t\t}\n\t\t\tvar new_array []histogramDistance\n\t\t\tfor _new_size < (all_histograms_size + num_new_clusters) {\n\t\t\t\t_new_size *= 2\n\t\t\t}\n\t\t\tnew_array = make([]histogramDistance, _new_size)\n\t\t\tif all_histograms_capacity != 0 {\n\t\t\t\tcopy(new_array, all_histograms[:all_histograms_capacity])\n\t\t\t}\n\n\t\t\tall_histograms = new_array\n\t\t\tall_histograms_capacity = _new_size\n\t\t}\n\n\t\tbrotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)\n\t\tfor j = 0; j < num_new_clusters; j++ {\n\t\t\tall_histograms[all_histograms_size] = histograms[new_clusters[j]]\n\t\t\tall_histograms_size++\n\t\t\tcluster_size[cluster_size_size] = sizes[new_clusters[j]]\n\t\t\tcluster_size_size++\n\t\t\tremap[new_clusters[j]] = uint32(j)\n\t\t}\n\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\thistogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]\n\t\t}\n\n\t\tnum_clusters += num_new_clusters\n\t\tassert(num_clusters == cluster_size_size)\n\t\tassert(num_clusters == all_histograms_size)\n\t}\n\n\thistograms = nil\n\n\tmax_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)\n\tif pairs_capacity < max_num_pairs+1 {\n\t\tpairs = nil\n\t\tpairs = make([]histogramPair, (max_num_pairs + 1))\n\t}\n\n\tclusters = make([]uint32, num_clusters)\n\tfor i = 0; i < num_clusters; i++ {\n\t\tclusters[i] = uint32(i)\n\t}\n\n\tnum_final_clusters = histogramCombineDistance(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)\n\tpairs = nil\n\tcluster_size = nil\n\n\tnew_index = make([]uint32, num_clusters)\n\tfor i = 0; i < num_clusters; i++ {\n\t\tnew_index[i] = clusterBlocksDistance_kInvalidIndex\n\t}\n\tpos = 0\n\t{\n\t\tvar next_index uint32 = 0\n\t\tfor i = 0; i < num_blocks; i++ {\n\t\t\tvar histo histogramDistance\n\t\t\tvar j uint\n\t\t\tvar best_out uint32\n\t\t\tvar best_bits float64\n\t\t\thistogramClearDistance(&histo)\n\t\t\tfor j = 0; uint32(j) < block_lengths[i]; j++ {\n\t\t\t\thistogramAddDistance(&histo, uint(data[pos]))\n\t\t\t\tpos++\n\t\t\t}\n\n\t\t\tif i == 0 {\n\t\t\t\tbest_out = histogram_symbols[0]\n\t\t\t} else {\n\t\t\t\tbest_out = histogram_symbols[i-1]\n\t\t\t}\n\t\t\tbest_bits = histogramBitCostDistanceDistance(&histo, &all_histograms[best_out])\n\t\t\tfor j = 0; j < num_final_clusters; j++ {\n\t\t\t\tvar cur_bits float64 = histogramBitCostDistanceDistance(&histo, &all_histograms[clusters[j]])\n\t\t\t\tif cur_bits < best_bits {\n\t\t\t\t\tbest_bits = cur_bits\n\t\t\t\t\tbest_out = clusters[j]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\thistogram_symbols[i] = best_out\n\t\t\tif new_index[best_out] == clusterBlocksDistance_kInvalidIndex {\n\t\t\t\tnew_index[best_out] = next_index\n\t\t\t\tnext_index++\n\t\t\t}\n\t\t}\n\t}\n\n\tclusters = nil\n\tall_histograms = nil\n\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)\n\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)\n\t{\n\t\tvar cur_length uint32 = 0\n\t\tvar block_idx uint = 0\n\t\tvar max_type byte = 0\n\t\tfor i = 0; i < num_blocks; i++ {\n\t\t\tcur_length += block_lengths[i]\n\t\t\tif i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {\n\t\t\t\tvar id byte = byte(new_index[histogram_symbols[i]])\n\t\t\t\tsplit.types[block_idx] = id\n\t\t\t\tsplit.lengths[block_idx] = cur_length\n\t\t\t\tmax_type = brotli_max_uint8_t(max_type, id)\n\t\t\t\tcur_length = 0\n\t\t\t\tblock_idx++\n\t\t\t}\n\t\t}\n\n\t\tsplit.num_blocks = block_idx\n\t\tsplit.num_types = uint(max_type) + 1\n\t}\n\n\tnew_index = nil\n\tblock_lengths = nil\n\thistogram_symbols = nil\n}\n\nfunc splitByteVectorDistance(data []uint16, length uint, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {\n\tvar data_size uint = histogramDataSizeDistance()\n\tvar num_histograms uint = length/literals_per_histogram + 1\n\tvar histograms []histogramDistance\n\tif num_histograms > max_histograms {\n\t\tnum_histograms = max_histograms\n\t}\n\n\tif length == 0 {\n\t\tsplit.num_types = 1\n\t\treturn\n\t} else if length < kMinLengthForBlockSplitting {\n\t\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)\n\t\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)\n\t\tsplit.num_types = 1\n\t\tsplit.types[split.num_blocks] = 0\n\t\tsplit.lengths[split.num_blocks] = uint32(length)\n\t\tsplit.num_blocks++\n\t\treturn\n\t}\n\n\thistograms = make([]histogramDistance, num_histograms)\n\n\t/* Find good entropy codes. */\n\tinitialEntropyCodesDistance(data, length, sampling_stride_length, num_histograms, histograms)\n\n\trefineEntropyCodesDistance(data, length, sampling_stride_length, num_histograms, histograms)\n\t{\n\t\tvar block_ids []byte = make([]byte, length)\n\t\tvar num_blocks uint = 0\n\t\tvar bitmaplen uint = (num_histograms + 7) >> 3\n\t\tvar insert_cost []float64 = make([]float64, (data_size * num_histograms))\n\t\tvar cost []float64 = make([]float64, num_histograms)\n\t\tvar switch_signal []byte = make([]byte, (length * bitmaplen))\n\t\tvar new_id []uint16 = make([]uint16, num_histograms)\n\t\tvar iters uint\n\t\tif params.quality < hqZopflificationQuality {\n\t\t\titers = 3\n\t\t} else {\n\t\t\titers = 10\n\t\t}\n\t\t/* Find a good path through literals with the good entropy codes. */\n\n\t\tvar i uint\n\t\tfor i = 0; i < iters; i++ {\n\t\t\tnum_blocks = findBlocksDistance(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)\n\t\t\tnum_histograms = remapBlockIdsDistance(block_ids, length, new_id, num_histograms)\n\t\t\tbuildBlockHistogramsDistance(data, length, block_ids, num_histograms, histograms)\n\t\t}\n\n\t\tinsert_cost = nil\n\t\tcost = nil\n\t\tswitch_signal = nil\n\t\tnew_id = nil\n\t\thistograms = nil\n\t\tclusterBlocksDistance(data, length, num_blocks, block_ids, split)\n\t\tblock_ids = nil\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/block_splitter_literal.go",
    "content": "package brotli\n\nimport \"math\"\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nfunc initialEntropyCodesLiteral(data []byte, length uint, stride uint, num_histograms uint, histograms []histogramLiteral) {\n\tvar seed uint32 = 7\n\tvar block_length uint = length / num_histograms\n\tvar i uint\n\tclearHistogramsLiteral(histograms, num_histograms)\n\tfor i = 0; i < num_histograms; i++ {\n\t\tvar pos uint = length * i / num_histograms\n\t\tif i != 0 {\n\t\t\tpos += uint(myRand(&seed) % uint32(block_length))\n\t\t}\n\n\t\tif pos+stride >= length {\n\t\t\tpos = length - stride - 1\n\t\t}\n\n\t\thistogramAddVectorLiteral(&histograms[i], data[pos:], stride)\n\t}\n}\n\nfunc randomSampleLiteral(seed *uint32, data []byte, length uint, stride uint, sample *histogramLiteral) {\n\tvar pos uint = 0\n\tif stride >= length {\n\t\tstride = length\n\t} else {\n\t\tpos = uint(myRand(seed) % uint32(length-stride+1))\n\t}\n\n\thistogramAddVectorLiteral(sample, data[pos:], stride)\n}\n\nfunc refineEntropyCodesLiteral(data []byte, length uint, stride uint, num_histograms uint, histograms []histogramLiteral) {\n\tvar iters uint = kIterMulForRefining*length/stride + kMinItersForRefining\n\tvar seed uint32 = 7\n\tvar iter uint\n\titers = ((iters + num_histograms - 1) / num_histograms) * num_histograms\n\tfor iter = 0; iter < iters; iter++ {\n\t\tvar sample histogramLiteral\n\t\thistogramClearLiteral(&sample)\n\t\trandomSampleLiteral(&seed, data, length, stride, &sample)\n\t\thistogramAddHistogramLiteral(&histograms[iter%num_histograms], &sample)\n\t}\n}\n\n/* Assigns a block id from the range [0, num_histograms) to each data element\n   in data[0..length) and fills in block_id[0..length) with the assigned values.\n   Returns the number of blocks, i.e. one plus the number of block switches. */\nfunc findBlocksLiteral(data []byte, length uint, block_switch_bitcost float64, num_histograms uint, histograms []histogramLiteral, insert_cost []float64, cost []float64, switch_signal []byte, block_id []byte) uint {\n\tvar data_size uint = histogramDataSizeLiteral()\n\tvar bitmaplen uint = (num_histograms + 7) >> 3\n\tvar num_blocks uint = 1\n\tvar i uint\n\tvar j uint\n\tassert(num_histograms <= 256)\n\tif num_histograms <= 1 {\n\t\tfor i = 0; i < length; i++ {\n\t\t\tblock_id[i] = 0\n\t\t}\n\n\t\treturn 1\n\t}\n\n\tfor i := 0; i < int(data_size*num_histograms); i++ {\n\t\tinsert_cost[i] = 0\n\t}\n\tfor i = 0; i < num_histograms; i++ {\n\t\tinsert_cost[i] = fastLog2(uint(uint32(histograms[i].total_count_)))\n\t}\n\n\tfor i = data_size; i != 0; {\n\t\ti--\n\t\tfor j = 0; j < num_histograms; j++ {\n\t\t\tinsert_cost[i*num_histograms+j] = insert_cost[j] - bitCost(uint(histograms[j].data_[i]))\n\t\t}\n\t}\n\n\tfor i := 0; i < int(num_histograms); i++ {\n\t\tcost[i] = 0\n\t}\n\tfor i := 0; i < int(length*bitmaplen); i++ {\n\t\tswitch_signal[i] = 0\n\t}\n\n\t/* After each iteration of this loop, cost[k] will contain the difference\n\t   between the minimum cost of arriving at the current byte position using\n\t   entropy code k, and the minimum cost of arriving at the current byte\n\t   position. This difference is capped at the block switch cost, and if it\n\t   reaches block switch cost, it means that when we trace back from the last\n\t   position, we need to switch here. */\n\tfor i = 0; i < length; i++ {\n\t\tvar byte_ix uint = i\n\t\tvar ix uint = byte_ix * bitmaplen\n\t\tvar insert_cost_ix uint = uint(data[byte_ix]) * num_histograms\n\t\tvar min_cost float64 = 1e99\n\t\tvar block_switch_cost float64 = block_switch_bitcost\n\t\tvar k uint\n\t\tfor k = 0; k < num_histograms; k++ {\n\t\t\t/* We are coding the symbol in data[byte_ix] with entropy code k. */\n\t\t\tcost[k] += insert_cost[insert_cost_ix+k]\n\n\t\t\tif cost[k] < min_cost {\n\t\t\t\tmin_cost = cost[k]\n\t\t\t\tblock_id[byte_ix] = byte(k)\n\t\t\t}\n\t\t}\n\n\t\t/* More blocks for the beginning. */\n\t\tif byte_ix < 2000 {\n\t\t\tblock_switch_cost *= 0.77 + 0.07*float64(byte_ix)/2000\n\t\t}\n\n\t\tfor k = 0; k < num_histograms; k++ {\n\t\t\tcost[k] -= min_cost\n\t\t\tif cost[k] >= block_switch_cost {\n\t\t\t\tvar mask byte = byte(1 << (k & 7))\n\t\t\t\tcost[k] = block_switch_cost\n\t\t\t\tassert(k>>3 < bitmaplen)\n\t\t\t\tswitch_signal[ix+(k>>3)] |= mask\n\t\t\t\t/* Trace back from the last position and switch at the marked places. */\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tvar byte_ix uint = length - 1\n\t\tvar ix uint = byte_ix * bitmaplen\n\t\tvar cur_id byte = block_id[byte_ix]\n\t\tfor byte_ix > 0 {\n\t\t\tvar mask byte = byte(1 << (cur_id & 7))\n\t\t\tassert(uint(cur_id)>>3 < bitmaplen)\n\t\t\tbyte_ix--\n\t\t\tix -= bitmaplen\n\t\t\tif switch_signal[ix+uint(cur_id>>3)]&mask != 0 {\n\t\t\t\tif cur_id != block_id[byte_ix] {\n\t\t\t\t\tcur_id = block_id[byte_ix]\n\t\t\t\t\tnum_blocks++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tblock_id[byte_ix] = cur_id\n\t\t}\n\t}\n\n\treturn num_blocks\n}\n\nvar remapBlockIdsLiteral_kInvalidId uint16 = 256\n\nfunc remapBlockIdsLiteral(block_ids []byte, length uint, new_id []uint16, num_histograms uint) uint {\n\tvar next_id uint16 = 0\n\tvar i uint\n\tfor i = 0; i < num_histograms; i++ {\n\t\tnew_id[i] = remapBlockIdsLiteral_kInvalidId\n\t}\n\n\tfor i = 0; i < length; i++ {\n\t\tassert(uint(block_ids[i]) < num_histograms)\n\t\tif new_id[block_ids[i]] == remapBlockIdsLiteral_kInvalidId {\n\t\t\tnew_id[block_ids[i]] = next_id\n\t\t\tnext_id++\n\t\t}\n\t}\n\n\tfor i = 0; i < length; i++ {\n\t\tblock_ids[i] = byte(new_id[block_ids[i]])\n\t\tassert(uint(block_ids[i]) < num_histograms)\n\t}\n\n\tassert(uint(next_id) <= num_histograms)\n\treturn uint(next_id)\n}\n\nfunc buildBlockHistogramsLiteral(data []byte, length uint, block_ids []byte, num_histograms uint, histograms []histogramLiteral) {\n\tvar i uint\n\tclearHistogramsLiteral(histograms, num_histograms)\n\tfor i = 0; i < length; i++ {\n\t\thistogramAddLiteral(&histograms[block_ids[i]], uint(data[i]))\n\t}\n}\n\nvar clusterBlocksLiteral_kInvalidIndex uint32 = math.MaxUint32\n\nfunc clusterBlocksLiteral(data []byte, length uint, num_blocks uint, block_ids []byte, split *blockSplit) {\n\tvar histogram_symbols []uint32 = make([]uint32, num_blocks)\n\tvar block_lengths []uint32 = make([]uint32, num_blocks)\n\tvar expected_num_clusters uint = clustersPerBatch * (num_blocks + histogramsPerBatch - 1) / histogramsPerBatch\n\tvar all_histograms_size uint = 0\n\tvar all_histograms_capacity uint = expected_num_clusters\n\tvar all_histograms []histogramLiteral = make([]histogramLiteral, all_histograms_capacity)\n\tvar cluster_size_size uint = 0\n\tvar cluster_size_capacity uint = expected_num_clusters\n\tvar cluster_size []uint32 = make([]uint32, cluster_size_capacity)\n\tvar num_clusters uint = 0\n\tvar histograms []histogramLiteral = make([]histogramLiteral, brotli_min_size_t(num_blocks, histogramsPerBatch))\n\tvar max_num_pairs uint = histogramsPerBatch * histogramsPerBatch / 2\n\tvar pairs_capacity uint = max_num_pairs + 1\n\tvar pairs []histogramPair = make([]histogramPair, pairs_capacity)\n\tvar pos uint = 0\n\tvar clusters []uint32\n\tvar num_final_clusters uint\n\tvar new_index []uint32\n\tvar i uint\n\tvar sizes = [histogramsPerBatch]uint32{0}\n\tvar new_clusters = [histogramsPerBatch]uint32{0}\n\tvar symbols = [histogramsPerBatch]uint32{0}\n\tvar remap = [histogramsPerBatch]uint32{0}\n\n\tfor i := 0; i < int(num_blocks); i++ {\n\t\tblock_lengths[i] = 0\n\t}\n\t{\n\t\tvar block_idx uint = 0\n\t\tfor i = 0; i < length; i++ {\n\t\t\tassert(block_idx < num_blocks)\n\t\t\tblock_lengths[block_idx]++\n\t\t\tif i+1 == length || block_ids[i] != block_ids[i+1] {\n\t\t\t\tblock_idx++\n\t\t\t}\n\t\t}\n\n\t\tassert(block_idx == num_blocks)\n\t}\n\n\tfor i = 0; i < num_blocks; i += histogramsPerBatch {\n\t\tvar num_to_combine uint = brotli_min_size_t(num_blocks-i, histogramsPerBatch)\n\t\tvar num_new_clusters uint\n\t\tvar j uint\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\tvar k uint\n\t\t\thistogramClearLiteral(&histograms[j])\n\t\t\tfor k = 0; uint32(k) < block_lengths[i+j]; k++ {\n\t\t\t\thistogramAddLiteral(&histograms[j], uint(data[pos]))\n\t\t\t\tpos++\n\t\t\t}\n\n\t\t\thistograms[j].bit_cost_ = populationCostLiteral(&histograms[j])\n\t\t\tnew_clusters[j] = uint32(j)\n\t\t\tsymbols[j] = uint32(j)\n\t\t\tsizes[j] = 1\n\t\t}\n\n\t\tnum_new_clusters = histogramCombineLiteral(histograms, sizes[:], symbols[:], new_clusters[:], []histogramPair(pairs), num_to_combine, num_to_combine, histogramsPerBatch, max_num_pairs)\n\t\tif all_histograms_capacity < (all_histograms_size + num_new_clusters) {\n\t\t\tvar _new_size uint\n\t\t\tif all_histograms_capacity == 0 {\n\t\t\t\t_new_size = all_histograms_size + num_new_clusters\n\t\t\t} else {\n\t\t\t\t_new_size = all_histograms_capacity\n\t\t\t}\n\t\t\tvar new_array []histogramLiteral\n\t\t\tfor _new_size < (all_histograms_size + num_new_clusters) {\n\t\t\t\t_new_size *= 2\n\t\t\t}\n\t\t\tnew_array = make([]histogramLiteral, _new_size)\n\t\t\tif all_histograms_capacity != 0 {\n\t\t\t\tcopy(new_array, all_histograms[:all_histograms_capacity])\n\t\t\t}\n\n\t\t\tall_histograms = new_array\n\t\t\tall_histograms_capacity = _new_size\n\t\t}\n\n\t\tbrotli_ensure_capacity_uint32_t(&cluster_size, &cluster_size_capacity, cluster_size_size+num_new_clusters)\n\t\tfor j = 0; j < num_new_clusters; j++ {\n\t\t\tall_histograms[all_histograms_size] = histograms[new_clusters[j]]\n\t\t\tall_histograms_size++\n\t\t\tcluster_size[cluster_size_size] = sizes[new_clusters[j]]\n\t\t\tcluster_size_size++\n\t\t\tremap[new_clusters[j]] = uint32(j)\n\t\t}\n\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\thistogram_symbols[i+j] = uint32(num_clusters) + remap[symbols[j]]\n\t\t}\n\n\t\tnum_clusters += num_new_clusters\n\t\tassert(num_clusters == cluster_size_size)\n\t\tassert(num_clusters == all_histograms_size)\n\t}\n\n\thistograms = nil\n\n\tmax_num_pairs = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)\n\tif pairs_capacity < max_num_pairs+1 {\n\t\tpairs = nil\n\t\tpairs = make([]histogramPair, (max_num_pairs + 1))\n\t}\n\n\tclusters = make([]uint32, num_clusters)\n\tfor i = 0; i < num_clusters; i++ {\n\t\tclusters[i] = uint32(i)\n\t}\n\n\tnum_final_clusters = histogramCombineLiteral(all_histograms, cluster_size, histogram_symbols, clusters, pairs, num_clusters, num_blocks, maxNumberOfBlockTypes, max_num_pairs)\n\tpairs = nil\n\tcluster_size = nil\n\n\tnew_index = make([]uint32, num_clusters)\n\tfor i = 0; i < num_clusters; i++ {\n\t\tnew_index[i] = clusterBlocksLiteral_kInvalidIndex\n\t}\n\tpos = 0\n\t{\n\t\tvar next_index uint32 = 0\n\t\tfor i = 0; i < num_blocks; i++ {\n\t\t\tvar histo histogramLiteral\n\t\t\tvar j uint\n\t\t\tvar best_out uint32\n\t\t\tvar best_bits float64\n\t\t\thistogramClearLiteral(&histo)\n\t\t\tfor j = 0; uint32(j) < block_lengths[i]; j++ {\n\t\t\t\thistogramAddLiteral(&histo, uint(data[pos]))\n\t\t\t\tpos++\n\t\t\t}\n\n\t\t\tif i == 0 {\n\t\t\t\tbest_out = histogram_symbols[0]\n\t\t\t} else {\n\t\t\t\tbest_out = histogram_symbols[i-1]\n\t\t\t}\n\t\t\tbest_bits = histogramBitCostDistanceLiteral(&histo, &all_histograms[best_out])\n\t\t\tfor j = 0; j < num_final_clusters; j++ {\n\t\t\t\tvar cur_bits float64 = histogramBitCostDistanceLiteral(&histo, &all_histograms[clusters[j]])\n\t\t\t\tif cur_bits < best_bits {\n\t\t\t\t\tbest_bits = cur_bits\n\t\t\t\t\tbest_out = clusters[j]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\thistogram_symbols[i] = best_out\n\t\t\tif new_index[best_out] == clusterBlocksLiteral_kInvalidIndex {\n\t\t\t\tnew_index[best_out] = next_index\n\t\t\t\tnext_index++\n\t\t\t}\n\t\t}\n\t}\n\n\tclusters = nil\n\tall_histograms = nil\n\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, num_blocks)\n\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, num_blocks)\n\t{\n\t\tvar cur_length uint32 = 0\n\t\tvar block_idx uint = 0\n\t\tvar max_type byte = 0\n\t\tfor i = 0; i < num_blocks; i++ {\n\t\t\tcur_length += block_lengths[i]\n\t\t\tif i+1 == num_blocks || histogram_symbols[i] != histogram_symbols[i+1] {\n\t\t\t\tvar id byte = byte(new_index[histogram_symbols[i]])\n\t\t\t\tsplit.types[block_idx] = id\n\t\t\t\tsplit.lengths[block_idx] = cur_length\n\t\t\t\tmax_type = brotli_max_uint8_t(max_type, id)\n\t\t\t\tcur_length = 0\n\t\t\t\tblock_idx++\n\t\t\t}\n\t\t}\n\n\t\tsplit.num_blocks = block_idx\n\t\tsplit.num_types = uint(max_type) + 1\n\t}\n\n\tnew_index = nil\n\tblock_lengths = nil\n\thistogram_symbols = nil\n}\n\nfunc splitByteVectorLiteral(data []byte, length uint, literals_per_histogram uint, max_histograms uint, sampling_stride_length uint, block_switch_cost float64, params *encoderParams, split *blockSplit) {\n\tvar data_size uint = histogramDataSizeLiteral()\n\tvar num_histograms uint = length/literals_per_histogram + 1\n\tvar histograms []histogramLiteral\n\tif num_histograms > max_histograms {\n\t\tnum_histograms = max_histograms\n\t}\n\n\tif length == 0 {\n\t\tsplit.num_types = 1\n\t\treturn\n\t} else if length < kMinLengthForBlockSplitting {\n\t\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, split.num_blocks+1)\n\t\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, split.num_blocks+1)\n\t\tsplit.num_types = 1\n\t\tsplit.types[split.num_blocks] = 0\n\t\tsplit.lengths[split.num_blocks] = uint32(length)\n\t\tsplit.num_blocks++\n\t\treturn\n\t}\n\n\thistograms = make([]histogramLiteral, num_histograms)\n\n\t/* Find good entropy codes. */\n\tinitialEntropyCodesLiteral(data, length, sampling_stride_length, num_histograms, histograms)\n\n\trefineEntropyCodesLiteral(data, length, sampling_stride_length, num_histograms, histograms)\n\t{\n\t\tvar block_ids []byte = make([]byte, length)\n\t\tvar num_blocks uint = 0\n\t\tvar bitmaplen uint = (num_histograms + 7) >> 3\n\t\tvar insert_cost []float64 = make([]float64, (data_size * num_histograms))\n\t\tvar cost []float64 = make([]float64, num_histograms)\n\t\tvar switch_signal []byte = make([]byte, (length * bitmaplen))\n\t\tvar new_id []uint16 = make([]uint16, num_histograms)\n\t\tvar iters uint\n\t\tif params.quality < hqZopflificationQuality {\n\t\t\titers = 3\n\t\t} else {\n\t\t\titers = 10\n\t\t}\n\t\t/* Find a good path through literals with the good entropy codes. */\n\n\t\tvar i uint\n\t\tfor i = 0; i < iters; i++ {\n\t\t\tnum_blocks = findBlocksLiteral(data, length, block_switch_cost, num_histograms, histograms, insert_cost, cost, switch_signal, block_ids)\n\t\t\tnum_histograms = remapBlockIdsLiteral(block_ids, length, new_id, num_histograms)\n\t\t\tbuildBlockHistogramsLiteral(data, length, block_ids, num_histograms, histograms)\n\t\t}\n\n\t\tinsert_cost = nil\n\t\tcost = nil\n\t\tswitch_signal = nil\n\t\tnew_id = nil\n\t\thistograms = nil\n\t\tclusterBlocksLiteral(data, length, num_blocks, block_ids, split)\n\t\tblock_ids = nil\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/brotli_bit_stream.go",
    "content": "package brotli\n\nimport (\n\t\"math\"\n\t\"sync\"\n)\n\nconst maxHuffmanTreeSize = (2*numCommandSymbols + 1)\n\n/*\nThe maximum size of Huffman dictionary for distances assuming that\n\n\tNPOSTFIX = 0 and NDIRECT = 0.\n*/\nconst maxSimpleDistanceAlphabetSize = 140\n\n/*\nRepresents the range of values belonging to a prefix code:\n\n\t[offset, offset + 2^nbits)\n*/\ntype prefixCodeRange struct {\n\toffset uint32\n\tnbits  uint32\n}\n\nvar kBlockLengthPrefixCode = [numBlockLenSymbols]prefixCodeRange{\n\tprefixCodeRange{1, 2},\n\tprefixCodeRange{5, 2},\n\tprefixCodeRange{9, 2},\n\tprefixCodeRange{13, 2},\n\tprefixCodeRange{17, 3},\n\tprefixCodeRange{25, 3},\n\tprefixCodeRange{33, 3},\n\tprefixCodeRange{41, 3},\n\tprefixCodeRange{49, 4},\n\tprefixCodeRange{65, 4},\n\tprefixCodeRange{81, 4},\n\tprefixCodeRange{97, 4},\n\tprefixCodeRange{113, 5},\n\tprefixCodeRange{145, 5},\n\tprefixCodeRange{177, 5},\n\tprefixCodeRange{209, 5},\n\tprefixCodeRange{241, 6},\n\tprefixCodeRange{305, 6},\n\tprefixCodeRange{369, 7},\n\tprefixCodeRange{497, 8},\n\tprefixCodeRange{753, 9},\n\tprefixCodeRange{1265, 10},\n\tprefixCodeRange{2289, 11},\n\tprefixCodeRange{4337, 12},\n\tprefixCodeRange{8433, 13},\n\tprefixCodeRange{16625, 24},\n}\n\nfunc blockLengthPrefixCode(len uint32) uint32 {\n\tvar code uint32\n\tif len >= 177 {\n\t\tif len >= 753 {\n\t\t\tcode = 20\n\t\t} else {\n\t\t\tcode = 14\n\t\t}\n\t} else if len >= 41 {\n\t\tcode = 7\n\t} else {\n\t\tcode = 0\n\t}\n\tfor code < (numBlockLenSymbols-1) && len >= kBlockLengthPrefixCode[code+1].offset {\n\t\tcode++\n\t}\n\treturn code\n}\n\nfunc getBlockLengthPrefixCode(len uint32, code *uint, n_extra *uint32, extra *uint32) {\n\t*code = uint(blockLengthPrefixCode(uint32(len)))\n\t*n_extra = kBlockLengthPrefixCode[*code].nbits\n\t*extra = len - kBlockLengthPrefixCode[*code].offset\n}\n\ntype blockTypeCodeCalculator struct {\n\tlast_type        uint\n\tsecond_last_type uint\n}\n\nfunc initBlockTypeCodeCalculator(self *blockTypeCodeCalculator) {\n\tself.last_type = 1\n\tself.second_last_type = 0\n}\n\nfunc nextBlockTypeCode(calculator *blockTypeCodeCalculator, type_ byte) uint {\n\tvar type_code uint\n\tif uint(type_) == calculator.last_type+1 {\n\t\ttype_code = 1\n\t} else if uint(type_) == calculator.second_last_type {\n\t\ttype_code = 0\n\t} else {\n\t\ttype_code = uint(type_) + 2\n\t}\n\tcalculator.second_last_type = calculator.last_type\n\tcalculator.last_type = uint(type_)\n\treturn type_code\n}\n\n/*\n|nibblesbits| represents the 2 bits to encode MNIBBLES (0-3)\n\n\tREQUIRES: length > 0\n\tREQUIRES: length <= (1 << 24)\n*/\nfunc encodeMlen(length uint, bits *uint64, numbits *uint, nibblesbits *uint64) {\n\tvar lg uint\n\tif length == 1 {\n\t\tlg = 1\n\t} else {\n\t\tlg = uint(log2FloorNonZero(uint(uint32(length-1)))) + 1\n\t}\n\tvar tmp uint\n\tif lg < 16 {\n\t\ttmp = 16\n\t} else {\n\t\ttmp = (lg + 3)\n\t}\n\tvar mnibbles uint = tmp / 4\n\tassert(length > 0)\n\tassert(length <= 1<<24)\n\tassert(lg <= 24)\n\t*nibblesbits = uint64(mnibbles) - 4\n\t*numbits = mnibbles * 4\n\t*bits = uint64(length) - 1\n}\n\nfunc storeCommandExtra(cmd *command, storage_ix *uint, storage []byte) {\n\tvar copylen_code uint32 = commandCopyLenCode(cmd)\n\tvar inscode uint16 = getInsertLengthCode(uint(cmd.insert_len_))\n\tvar copycode uint16 = getCopyLengthCode(uint(copylen_code))\n\tvar insnumextra uint32 = getInsertExtra(inscode)\n\tvar insextraval uint64 = uint64(cmd.insert_len_) - uint64(getInsertBase(inscode))\n\tvar copyextraval uint64 = uint64(copylen_code) - uint64(getCopyBase(copycode))\n\tvar bits uint64 = copyextraval<<insnumextra | insextraval\n\twriteBits(uint(insnumextra+getCopyExtra(copycode)), bits, storage_ix, storage)\n}\n\n/*\nData structure that stores almost everything that is needed to encode each\n\n\tblock switch command.\n*/\ntype blockSplitCode struct {\n\ttype_code_calculator blockTypeCodeCalculator\n\ttype_depths          [maxBlockTypeSymbols]byte\n\ttype_bits            [maxBlockTypeSymbols]uint16\n\tlength_depths        [numBlockLenSymbols]byte\n\tlength_bits          [numBlockLenSymbols]uint16\n}\n\n/* Stores a number between 0 and 255. */\nfunc storeVarLenUint8(n uint, storage_ix *uint, storage []byte) {\n\tif n == 0 {\n\t\twriteBits(1, 0, storage_ix, storage)\n\t} else {\n\t\tvar nbits uint = uint(log2FloorNonZero(n))\n\t\twriteBits(1, 1, storage_ix, storage)\n\t\twriteBits(3, uint64(nbits), storage_ix, storage)\n\t\twriteBits(nbits, uint64(n)-(uint64(uint(1))<<nbits), storage_ix, storage)\n\t}\n}\n\n/*\nStores the compressed meta-block header.\n\n\tREQUIRES: length > 0\n\tREQUIRES: length <= (1 << 24)\n*/\nfunc storeCompressedMetaBlockHeader(is_final_block bool, length uint, storage_ix *uint, storage []byte) {\n\tvar lenbits uint64\n\tvar nlenbits uint\n\tvar nibblesbits uint64\n\tvar is_final uint64\n\tif is_final_block {\n\t\tis_final = 1\n\t} else {\n\t\tis_final = 0\n\t}\n\n\t/* Write ISLAST bit. */\n\twriteBits(1, is_final, storage_ix, storage)\n\n\t/* Write ISEMPTY bit. */\n\tif is_final_block {\n\t\twriteBits(1, 0, storage_ix, storage)\n\t}\n\n\tencodeMlen(length, &lenbits, &nlenbits, &nibblesbits)\n\twriteBits(2, nibblesbits, storage_ix, storage)\n\twriteBits(nlenbits, lenbits, storage_ix, storage)\n\n\tif !is_final_block {\n\t\t/* Write ISUNCOMPRESSED bit. */\n\t\twriteBits(1, 0, storage_ix, storage)\n\t}\n}\n\n/*\nStores the uncompressed meta-block header.\n\n\tREQUIRES: length > 0\n\tREQUIRES: length <= (1 << 24)\n*/\nfunc storeUncompressedMetaBlockHeader(length uint, storage_ix *uint, storage []byte) {\n\tvar lenbits uint64\n\tvar nlenbits uint\n\tvar nibblesbits uint64\n\n\t/* Write ISLAST bit.\n\t   Uncompressed block cannot be the last one, so set to 0. */\n\twriteBits(1, 0, storage_ix, storage)\n\n\tencodeMlen(length, &lenbits, &nlenbits, &nibblesbits)\n\twriteBits(2, nibblesbits, storage_ix, storage)\n\twriteBits(nlenbits, lenbits, storage_ix, storage)\n\n\t/* Write ISUNCOMPRESSED bit. */\n\twriteBits(1, 1, storage_ix, storage)\n}\n\nvar storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder = [codeLengthCodes]byte{1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15}\n\nvar storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeSymbols = [6]byte{0, 7, 3, 2, 1, 15}\nvar storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeBitLengths = [6]byte{2, 4, 3, 2, 2, 4}\n\nfunc storeHuffmanTreeOfHuffmanTreeToBitMask(num_codes int, code_length_bitdepth []byte, storage_ix *uint, storage []byte) {\n\tvar skip_some uint = 0\n\tvar codes_to_store uint = codeLengthCodes\n\t/* The bit lengths of the Huffman code over the code length alphabet\n\t   are compressed with the following static Huffman code:\n\t     Symbol   Code\n\t     ------   ----\n\t     0          00\n\t     1        1110\n\t     2         110\n\t     3          01\n\t     4          10\n\t     5        1111 */\n\n\t/* Throw away trailing zeros: */\n\tif num_codes > 1 {\n\t\tfor ; codes_to_store > 0; codes_to_store-- {\n\t\t\tif code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[codes_to_store-1]] != 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[0]] == 0 && code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[1]] == 0 {\n\t\tskip_some = 2 /* skips two. */\n\t\tif code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[2]] == 0 {\n\t\t\tskip_some = 3 /* skips three. */\n\t\t}\n\t}\n\n\twriteBits(2, uint64(skip_some), storage_ix, storage)\n\t{\n\t\tvar i uint\n\t\tfor i = skip_some; i < codes_to_store; i++ {\n\t\t\tvar l uint = uint(code_length_bitdepth[storeHuffmanTreeOfHuffmanTreeToBitMask_kStorageOrder[i]])\n\t\t\twriteBits(uint(storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeBitLengths[l]), uint64(storeHuffmanTreeOfHuffmanTreeToBitMask_kHuffmanBitLengthHuffmanCodeSymbols[l]), storage_ix, storage)\n\t\t}\n\t}\n}\n\nfunc storeHuffmanTreeToBitMask(huffman_tree_size uint, huffman_tree []byte, huffman_tree_extra_bits []byte, code_length_bitdepth []byte, code_length_bitdepth_symbols []uint16, storage_ix *uint, storage []byte) {\n\tvar i uint\n\tfor i = 0; i < huffman_tree_size; i++ {\n\t\tvar ix uint = uint(huffman_tree[i])\n\t\twriteBits(uint(code_length_bitdepth[ix]), uint64(code_length_bitdepth_symbols[ix]), storage_ix, storage)\n\n\t\t/* Extra bits */\n\t\tswitch ix {\n\t\tcase repeatPreviousCodeLength:\n\t\t\twriteBits(2, uint64(huffman_tree_extra_bits[i]), storage_ix, storage)\n\n\t\tcase repeatZeroCodeLength:\n\t\t\twriteBits(3, uint64(huffman_tree_extra_bits[i]), storage_ix, storage)\n\t\t}\n\t}\n}\n\nfunc storeSimpleHuffmanTree(depths []byte, symbols []uint, num_symbols uint, max_bits uint, storage_ix *uint, storage []byte) {\n\t/* value of 1 indicates a simple Huffman code */\n\twriteBits(2, 1, storage_ix, storage)\n\n\twriteBits(2, uint64(num_symbols)-1, storage_ix, storage) /* NSYM - 1 */\n\t{\n\t\t/* Sort */\n\t\tvar i uint\n\t\tfor i = 0; i < num_symbols; i++ {\n\t\t\tvar j uint\n\t\t\tfor j = i + 1; j < num_symbols; j++ {\n\t\t\t\tif depths[symbols[j]] < depths[symbols[i]] {\n\t\t\t\t\tvar tmp uint = symbols[j]\n\t\t\t\t\tsymbols[j] = symbols[i]\n\t\t\t\t\tsymbols[i] = tmp\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif num_symbols == 2 {\n\t\twriteBits(max_bits, uint64(symbols[0]), storage_ix, storage)\n\t\twriteBits(max_bits, uint64(symbols[1]), storage_ix, storage)\n\t} else if num_symbols == 3 {\n\t\twriteBits(max_bits, uint64(symbols[0]), storage_ix, storage)\n\t\twriteBits(max_bits, uint64(symbols[1]), storage_ix, storage)\n\t\twriteBits(max_bits, uint64(symbols[2]), storage_ix, storage)\n\t} else {\n\t\twriteBits(max_bits, uint64(symbols[0]), storage_ix, storage)\n\t\twriteBits(max_bits, uint64(symbols[1]), storage_ix, storage)\n\t\twriteBits(max_bits, uint64(symbols[2]), storage_ix, storage)\n\t\twriteBits(max_bits, uint64(symbols[3]), storage_ix, storage)\n\n\t\t/* tree-select */\n\t\tvar tmp int\n\t\tif depths[symbols[0]] == 1 {\n\t\t\ttmp = 1\n\t\t} else {\n\t\t\ttmp = 0\n\t\t}\n\t\twriteBits(1, uint64(tmp), storage_ix, storage)\n\t}\n}\n\n/*\nnum = alphabet size\n\n\tdepths = symbol depths\n*/\nfunc storeHuffmanTree(depths []byte, num uint, tree []huffmanTree, storage_ix *uint, storage []byte) {\n\tvar huffman_tree [numCommandSymbols]byte\n\tvar huffman_tree_extra_bits [numCommandSymbols]byte\n\tvar huffman_tree_size uint = 0\n\tvar code_length_bitdepth = [codeLengthCodes]byte{0}\n\tvar code_length_bitdepth_symbols [codeLengthCodes]uint16\n\tvar huffman_tree_histogram = [codeLengthCodes]uint32{0}\n\tvar i uint\n\tvar num_codes int = 0\n\t/* Write the Huffman tree into the brotli-representation.\n\t   The command alphabet is the largest, so this allocation will fit all\n\t   alphabets. */\n\n\tvar code uint = 0\n\n\tassert(num <= numCommandSymbols)\n\n\twriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree[:], huffman_tree_extra_bits[:])\n\n\t/* Calculate the statistics of the Huffman tree in brotli-representation. */\n\tfor i = 0; i < huffman_tree_size; i++ {\n\t\thuffman_tree_histogram[huffman_tree[i]]++\n\t}\n\n\tfor i = 0; i < codeLengthCodes; i++ {\n\t\tif huffman_tree_histogram[i] != 0 {\n\t\t\tif num_codes == 0 {\n\t\t\t\tcode = i\n\t\t\t\tnum_codes = 1\n\t\t\t} else if num_codes == 1 {\n\t\t\t\tnum_codes = 2\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Calculate another Huffman tree to use for compressing both the\n\t   earlier Huffman tree with. */\n\tcreateHuffmanTree(huffman_tree_histogram[:], codeLengthCodes, 5, tree, code_length_bitdepth[:])\n\n\tconvertBitDepthsToSymbols(code_length_bitdepth[:], codeLengthCodes, code_length_bitdepth_symbols[:])\n\n\t/* Now, we have all the data, let's start storing it */\n\tstoreHuffmanTreeOfHuffmanTreeToBitMask(num_codes, code_length_bitdepth[:], storage_ix, storage)\n\n\tif num_codes == 1 {\n\t\tcode_length_bitdepth[code] = 0\n\t}\n\n\t/* Store the real Huffman tree now. */\n\tstoreHuffmanTreeToBitMask(huffman_tree_size, huffman_tree[:], huffman_tree_extra_bits[:], code_length_bitdepth[:], code_length_bitdepth_symbols[:], storage_ix, storage)\n}\n\n/*\nBuilds a Huffman tree from histogram[0:length] into depth[0:length] and\n\n\tbits[0:length] and stores the encoded tree to the bit stream.\n*/\nfunc buildAndStoreHuffmanTree(histogram []uint32, histogram_length uint, alphabet_size uint, tree []huffmanTree, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {\n\tvar count uint = 0\n\tvar s4 = [4]uint{0}\n\tvar i uint\n\tvar max_bits uint = 0\n\tfor i = 0; i < histogram_length; i++ {\n\t\tif histogram[i] != 0 {\n\t\t\tif count < 4 {\n\t\t\t\ts4[count] = i\n\t\t\t} else if count > 4 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcount++\n\t\t}\n\t}\n\t{\n\t\tvar max_bits_counter uint = alphabet_size - 1\n\t\tfor max_bits_counter != 0 {\n\t\t\tmax_bits_counter >>= 1\n\t\t\tmax_bits++\n\t\t}\n\t}\n\n\tif count <= 1 {\n\t\twriteBits(4, 1, storage_ix, storage)\n\t\twriteBits(max_bits, uint64(s4[0]), storage_ix, storage)\n\t\tdepth[s4[0]] = 0\n\t\tbits[s4[0]] = 0\n\t\treturn\n\t}\n\n\tfor i := 0; i < int(histogram_length); i++ {\n\t\tdepth[i] = 0\n\t}\n\tcreateHuffmanTree(histogram, histogram_length, 15, tree, depth)\n\tconvertBitDepthsToSymbols(depth, histogram_length, bits)\n\n\tif count <= 4 {\n\t\tstoreSimpleHuffmanTree(depth, s4[:], count, max_bits, storage_ix, storage)\n\t} else {\n\t\tstoreHuffmanTree(depth, histogram_length, tree, storage_ix, storage)\n\t}\n}\n\nfunc sortHuffmanTree1(v0 huffmanTree, v1 huffmanTree) bool {\n\treturn v0.total_count_ < v1.total_count_\n}\n\nvar huffmanTreePool sync.Pool\n\nfunc buildAndStoreHuffmanTreeFast(histogram []uint32, histogram_total uint, max_bits uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {\n\tvar count uint = 0\n\tvar symbols = [4]uint{0}\n\tvar length uint = 0\n\tvar total uint = histogram_total\n\tfor total != 0 {\n\t\tif histogram[length] != 0 {\n\t\t\tif count < 4 {\n\t\t\t\tsymbols[count] = length\n\t\t\t}\n\n\t\t\tcount++\n\t\t\ttotal -= uint(histogram[length])\n\t\t}\n\n\t\tlength++\n\t}\n\n\tif count <= 1 {\n\t\twriteBits(4, 1, storage_ix, storage)\n\t\twriteBits(max_bits, uint64(symbols[0]), storage_ix, storage)\n\t\tdepth[symbols[0]] = 0\n\t\tbits[symbols[0]] = 0\n\t\treturn\n\t}\n\n\tfor i := 0; i < int(length); i++ {\n\t\tdepth[i] = 0\n\t}\n\t{\n\t\tvar max_tree_size uint = 2*length + 1\n\t\ttree, _ := huffmanTreePool.Get().(*[]huffmanTree)\n\t\tif tree == nil || cap(*tree) < int(max_tree_size) {\n\t\t\ttmp := make([]huffmanTree, max_tree_size)\n\t\t\ttree = &tmp\n\t\t} else {\n\t\t\t*tree = (*tree)[:max_tree_size]\n\t\t}\n\t\tvar count_limit uint32\n\t\tfor count_limit = 1; ; count_limit *= 2 {\n\t\t\tvar node int = 0\n\t\t\tvar l uint\n\t\t\tfor l = length; l != 0; {\n\t\t\t\tl--\n\t\t\t\tif histogram[l] != 0 {\n\t\t\t\t\tif histogram[l] >= count_limit {\n\t\t\t\t\t\tinitHuffmanTree(&(*tree)[node:][0], histogram[l], -1, int16(l))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinitHuffmanTree(&(*tree)[node:][0], count_limit, -1, int16(l))\n\t\t\t\t\t}\n\n\t\t\t\t\tnode++\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tvar n int = node\n\t\t\t\t/* Points to the next leaf node. */ /* Points to the next non-leaf node. */\n\t\t\t\tvar sentinel huffmanTree\n\t\t\t\tvar i int = 0\n\t\t\t\tvar j int = n + 1\n\t\t\t\tvar k int\n\n\t\t\t\tsortHuffmanTreeItems(*tree, uint(n), huffmanTreeComparator(sortHuffmanTree1))\n\n\t\t\t\t/* The nodes are:\n\t\t\t\t   [0, n): the sorted leaf nodes that we start with.\n\t\t\t\t   [n]: we add a sentinel here.\n\t\t\t\t   [n + 1, 2n): new parent nodes are added here, starting from\n\t\t\t\t                (n+1). These are naturally in ascending order.\n\t\t\t\t   [2n]: we add a sentinel at the end as well.\n\t\t\t\t   There will be (2n+1) elements at the end. */\n\t\t\t\tinitHuffmanTree(&sentinel, math.MaxUint32, -1, -1)\n\n\t\t\t\t(*tree)[node] = sentinel\n\t\t\t\tnode++\n\t\t\t\t(*tree)[node] = sentinel\n\t\t\t\tnode++\n\n\t\t\t\tfor k = n - 1; k > 0; k-- {\n\t\t\t\t\tvar left int\n\t\t\t\t\tvar right int\n\t\t\t\t\tif (*tree)[i].total_count_ <= (*tree)[j].total_count_ {\n\t\t\t\t\t\tleft = i\n\t\t\t\t\t\ti++\n\t\t\t\t\t} else {\n\t\t\t\t\t\tleft = j\n\t\t\t\t\t\tj++\n\t\t\t\t\t}\n\n\t\t\t\t\tif (*tree)[i].total_count_ <= (*tree)[j].total_count_ {\n\t\t\t\t\t\tright = i\n\t\t\t\t\t\ti++\n\t\t\t\t\t} else {\n\t\t\t\t\t\tright = j\n\t\t\t\t\t\tj++\n\t\t\t\t\t}\n\n\t\t\t\t\t/* The sentinel node becomes the parent node. */\n\t\t\t\t\t(*tree)[node-1].total_count_ = (*tree)[left].total_count_ + (*tree)[right].total_count_\n\n\t\t\t\t\t(*tree)[node-1].index_left_ = int16(left)\n\t\t\t\t\t(*tree)[node-1].index_right_or_value_ = int16(right)\n\n\t\t\t\t\t/* Add back the last sentinel node. */\n\t\t\t\t\t(*tree)[node] = sentinel\n\t\t\t\t\tnode++\n\t\t\t\t}\n\n\t\t\t\tif setDepth(2*n-1, *tree, depth, 14) {\n\t\t\t\t\t/* We need to pack the Huffman tree in 14 bits. If this was not\n\t\t\t\t\t   successful, add fake entities to the lowest values and retry. */\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\thuffmanTreePool.Put(tree)\n\t}\n\n\tconvertBitDepthsToSymbols(depth, length, bits)\n\tif count <= 4 {\n\t\tvar i uint\n\n\t\t/* value of 1 indicates a simple Huffman code */\n\t\twriteBits(2, 1, storage_ix, storage)\n\n\t\twriteBits(2, uint64(count)-1, storage_ix, storage) /* NSYM - 1 */\n\n\t\t/* Sort */\n\t\tfor i = 0; i < count; i++ {\n\t\t\tvar j uint\n\t\t\tfor j = i + 1; j < count; j++ {\n\t\t\t\tif depth[symbols[j]] < depth[symbols[i]] {\n\t\t\t\t\tvar tmp uint = symbols[j]\n\t\t\t\t\tsymbols[j] = symbols[i]\n\t\t\t\t\tsymbols[i] = tmp\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif count == 2 {\n\t\t\twriteBits(max_bits, uint64(symbols[0]), storage_ix, storage)\n\t\t\twriteBits(max_bits, uint64(symbols[1]), storage_ix, storage)\n\t\t} else if count == 3 {\n\t\t\twriteBits(max_bits, uint64(symbols[0]), storage_ix, storage)\n\t\t\twriteBits(max_bits, uint64(symbols[1]), storage_ix, storage)\n\t\t\twriteBits(max_bits, uint64(symbols[2]), storage_ix, storage)\n\t\t} else {\n\t\t\twriteBits(max_bits, uint64(symbols[0]), storage_ix, storage)\n\t\t\twriteBits(max_bits, uint64(symbols[1]), storage_ix, storage)\n\t\t\twriteBits(max_bits, uint64(symbols[2]), storage_ix, storage)\n\t\t\twriteBits(max_bits, uint64(symbols[3]), storage_ix, storage)\n\n\t\t\t/* tree-select */\n\t\t\tvar tmp int\n\t\t\tif depth[symbols[0]] == 1 {\n\t\t\t\ttmp = 1\n\t\t\t} else {\n\t\t\t\ttmp = 0\n\t\t\t}\n\t\t\twriteBits(1, uint64(tmp), storage_ix, storage)\n\t\t}\n\t} else {\n\t\tvar previous_value byte = 8\n\t\tvar i uint\n\n\t\t/* Complex Huffman Tree */\n\t\tstoreStaticCodeLengthCode(storage_ix, storage)\n\n\t\t/* Actual RLE coding. */\n\t\tfor i = 0; i < length; {\n\t\t\tvar value byte = depth[i]\n\t\t\tvar reps uint = 1\n\t\t\tvar k uint\n\t\t\tfor k = i + 1; k < length && depth[k] == value; k++ {\n\t\t\t\treps++\n\t\t\t}\n\n\t\t\ti += reps\n\t\t\tif value == 0 {\n\t\t\t\twriteBits(uint(kZeroRepsDepth[reps]), kZeroRepsBits[reps], storage_ix, storage)\n\t\t\t} else {\n\t\t\t\tif previous_value != value {\n\t\t\t\t\twriteBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]), storage_ix, storage)\n\t\t\t\t\treps--\n\t\t\t\t}\n\n\t\t\t\tif reps < 3 {\n\t\t\t\t\tfor reps != 0 {\n\t\t\t\t\t\treps--\n\t\t\t\t\t\twriteBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]), storage_ix, storage)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treps -= 3\n\t\t\t\t\twriteBits(uint(kNonZeroRepsDepth[reps]), kNonZeroRepsBits[reps], storage_ix, storage)\n\t\t\t\t}\n\n\t\t\t\tprevious_value = value\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc buildAndStoreHuffmanTreeFastBW(histogram []uint32, histogram_total uint, max_bits uint, depth []byte, bits []uint16, bw *bitWriter) {\n\tvar count uint = 0\n\tvar symbols = [4]uint{0}\n\tvar length uint = 0\n\tvar total uint = histogram_total\n\tfor total != 0 {\n\t\tif histogram[length] != 0 {\n\t\t\tif count < 4 {\n\t\t\t\tsymbols[count] = length\n\t\t\t}\n\n\t\t\tcount++\n\t\t\ttotal -= uint(histogram[length])\n\t\t}\n\n\t\tlength++\n\t}\n\n\tif count <= 1 {\n\t\tbw.writeBits(4, 1)\n\t\tbw.writeBits(max_bits, uint64(symbols[0]))\n\t\tdepth[symbols[0]] = 0\n\t\tbits[symbols[0]] = 0\n\t\treturn\n\t}\n\n\tfor i := 0; i < int(length); i++ {\n\t\tdepth[i] = 0\n\t}\n\t{\n\t\tvar max_tree_size uint = 2*length + 1\n\t\ttree, _ := huffmanTreePool.Get().(*[]huffmanTree)\n\t\tif tree == nil || cap(*tree) < int(max_tree_size) {\n\t\t\ttmp := make([]huffmanTree, max_tree_size)\n\t\t\ttree = &tmp\n\t\t} else {\n\t\t\t*tree = (*tree)[:max_tree_size]\n\t\t}\n\t\tvar count_limit uint32\n\t\tfor count_limit = 1; ; count_limit *= 2 {\n\t\t\tvar node int = 0\n\t\t\tvar l uint\n\t\t\tfor l = length; l != 0; {\n\t\t\t\tl--\n\t\t\t\tif histogram[l] != 0 {\n\t\t\t\t\tif histogram[l] >= count_limit {\n\t\t\t\t\t\tinitHuffmanTree(&(*tree)[node:][0], histogram[l], -1, int16(l))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinitHuffmanTree(&(*tree)[node:][0], count_limit, -1, int16(l))\n\t\t\t\t\t}\n\n\t\t\t\t\tnode++\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tvar n int = node\n\t\t\t\t/* Points to the next leaf node. */ /* Points to the next non-leaf node. */\n\t\t\t\tvar sentinel huffmanTree\n\t\t\t\tvar i int = 0\n\t\t\t\tvar j int = n + 1\n\t\t\t\tvar k int\n\n\t\t\t\tsortHuffmanTreeItems(*tree, uint(n), huffmanTreeComparator(sortHuffmanTree1))\n\n\t\t\t\t/* The nodes are:\n\t\t\t\t   [0, n): the sorted leaf nodes that we start with.\n\t\t\t\t   [n]: we add a sentinel here.\n\t\t\t\t   [n + 1, 2n): new parent nodes are added here, starting from\n\t\t\t\t                (n+1). These are naturally in ascending order.\n\t\t\t\t   [2n]: we add a sentinel at the end as well.\n\t\t\t\t   There will be (2n+1) elements at the end. */\n\t\t\t\tinitHuffmanTree(&sentinel, math.MaxUint32, -1, -1)\n\n\t\t\t\t(*tree)[node] = sentinel\n\t\t\t\tnode++\n\t\t\t\t(*tree)[node] = sentinel\n\t\t\t\tnode++\n\n\t\t\t\tfor k = n - 1; k > 0; k-- {\n\t\t\t\t\tvar left int\n\t\t\t\t\tvar right int\n\t\t\t\t\tif (*tree)[i].total_count_ <= (*tree)[j].total_count_ {\n\t\t\t\t\t\tleft = i\n\t\t\t\t\t\ti++\n\t\t\t\t\t} else {\n\t\t\t\t\t\tleft = j\n\t\t\t\t\t\tj++\n\t\t\t\t\t}\n\n\t\t\t\t\tif (*tree)[i].total_count_ <= (*tree)[j].total_count_ {\n\t\t\t\t\t\tright = i\n\t\t\t\t\t\ti++\n\t\t\t\t\t} else {\n\t\t\t\t\t\tright = j\n\t\t\t\t\t\tj++\n\t\t\t\t\t}\n\n\t\t\t\t\t/* The sentinel node becomes the parent node. */\n\t\t\t\t\t(*tree)[node-1].total_count_ = (*tree)[left].total_count_ + (*tree)[right].total_count_\n\n\t\t\t\t\t(*tree)[node-1].index_left_ = int16(left)\n\t\t\t\t\t(*tree)[node-1].index_right_or_value_ = int16(right)\n\n\t\t\t\t\t/* Add back the last sentinel node. */\n\t\t\t\t\t(*tree)[node] = sentinel\n\t\t\t\t\tnode++\n\t\t\t\t}\n\n\t\t\t\tif setDepth(2*n-1, *tree, depth, 14) {\n\t\t\t\t\t/* We need to pack the Huffman tree in 14 bits. If this was not\n\t\t\t\t\t   successful, add fake entities to the lowest values and retry. */\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\thuffmanTreePool.Put(tree)\n\t}\n\n\tconvertBitDepthsToSymbols(depth, length, bits)\n\tif count <= 4 {\n\t\tvar i uint\n\n\t\t/* value of 1 indicates a simple Huffman code */\n\t\tbw.writeBits(2, 1)\n\n\t\tbw.writeBits(2, uint64(count)-1) /* NSYM - 1 */\n\n\t\t/* Sort */\n\t\tfor i = 0; i < count; i++ {\n\t\t\tvar j uint\n\t\t\tfor j = i + 1; j < count; j++ {\n\t\t\t\tif depth[symbols[j]] < depth[symbols[i]] {\n\t\t\t\t\tvar tmp uint = symbols[j]\n\t\t\t\t\tsymbols[j] = symbols[i]\n\t\t\t\t\tsymbols[i] = tmp\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif count == 2 {\n\t\t\tbw.writeBits(max_bits, uint64(symbols[0]))\n\t\t\tbw.writeBits(max_bits, uint64(symbols[1]))\n\t\t} else if count == 3 {\n\t\t\tbw.writeBits(max_bits, uint64(symbols[0]))\n\t\t\tbw.writeBits(max_bits, uint64(symbols[1]))\n\t\t\tbw.writeBits(max_bits, uint64(symbols[2]))\n\t\t} else {\n\t\t\tbw.writeBits(max_bits, uint64(symbols[0]))\n\t\t\tbw.writeBits(max_bits, uint64(symbols[1]))\n\t\t\tbw.writeBits(max_bits, uint64(symbols[2]))\n\t\t\tbw.writeBits(max_bits, uint64(symbols[3]))\n\n\t\t\t/* tree-select */\n\t\t\tbw.writeSingleBit(depth[symbols[0]] == 1)\n\t\t}\n\t} else {\n\t\tvar previous_value byte = 8\n\t\tvar i uint\n\n\t\t/* Complex Huffman Tree */\n\t\tstoreStaticCodeLengthCodeBW(bw)\n\n\t\t/* Actual RLE coding. */\n\t\tfor i = 0; i < length; {\n\t\t\tvar value byte = depth[i]\n\t\t\tvar reps uint = 1\n\t\t\tvar k uint\n\t\t\tfor k = i + 1; k < length && depth[k] == value; k++ {\n\t\t\t\treps++\n\t\t\t}\n\n\t\t\ti += reps\n\t\t\tif value == 0 {\n\t\t\t\tbw.writeBits(uint(kZeroRepsDepth[reps]), kZeroRepsBits[reps])\n\t\t\t} else {\n\t\t\t\tif previous_value != value {\n\t\t\t\t\tbw.writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]))\n\t\t\t\t\treps--\n\t\t\t\t}\n\n\t\t\t\tif reps < 3 {\n\t\t\t\t\tfor reps != 0 {\n\t\t\t\t\t\treps--\n\t\t\t\t\t\tbw.writeBits(uint(kCodeLengthDepth[value]), uint64(kCodeLengthBits[value]))\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treps -= 3\n\t\t\t\t\tbw.writeBits(uint(kNonZeroRepsDepth[reps]), kNonZeroRepsBits[reps])\n\t\t\t\t}\n\n\t\t\t\tprevious_value = value\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc indexOf(v []byte, v_size uint, value byte) uint {\n\tvar i uint = 0\n\tfor ; i < v_size; i++ {\n\t\tif v[i] == value {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn i\n}\n\nfunc moveToFront(v []byte, index uint) {\n\tvar value byte = v[index]\n\tvar i uint\n\tfor i = index; i != 0; i-- {\n\t\tv[i] = v[i-1]\n\t}\n\n\tv[0] = value\n}\n\nfunc moveToFrontTransform(v_in []uint32, v_size uint, v_out []uint32) {\n\tvar i uint\n\tvar mtf [256]byte\n\tvar max_value uint32\n\tif v_size == 0 {\n\t\treturn\n\t}\n\n\tmax_value = v_in[0]\n\tfor i = 1; i < v_size; i++ {\n\t\tif v_in[i] > max_value {\n\t\t\tmax_value = v_in[i]\n\t\t}\n\t}\n\n\tassert(max_value < 256)\n\tfor i = 0; uint32(i) <= max_value; i++ {\n\t\tmtf[i] = byte(i)\n\t}\n\t{\n\t\tvar mtf_size uint = uint(max_value + 1)\n\t\tfor i = 0; i < v_size; i++ {\n\t\t\tvar index uint = indexOf(mtf[:], mtf_size, byte(v_in[i]))\n\t\t\tassert(index < mtf_size)\n\t\t\tv_out[i] = uint32(index)\n\t\t\tmoveToFront(mtf[:], index)\n\t\t}\n\t}\n}\n\n/*\nFinds runs of zeros in v[0..in_size) and replaces them with a prefix code of\n\n\tthe run length plus extra bits (lower 9 bits is the prefix code and the rest\n\tare the extra bits). Non-zero values in v[] are shifted by\n\t*max_length_prefix. Will not create prefix codes bigger than the initial\n\tvalue of *max_run_length_prefix. The prefix code of run length L is simply\n\tLog2Floor(L) and the number of extra bits is the same as the prefix code.\n*/\nfunc runLengthCodeZeros(in_size uint, v []uint32, out_size *uint, max_run_length_prefix *uint32) {\n\tvar max_reps uint32 = 0\n\tvar i uint\n\tvar max_prefix uint32\n\tfor i = 0; i < in_size; {\n\t\tvar reps uint32 = 0\n\t\tfor ; i < in_size && v[i] != 0; i++ {\n\t\t}\n\t\tfor ; i < in_size && v[i] == 0; i++ {\n\t\t\treps++\n\t\t}\n\n\t\tmax_reps = brotli_max_uint32_t(reps, max_reps)\n\t}\n\n\tif max_reps > 0 {\n\t\tmax_prefix = log2FloorNonZero(uint(max_reps))\n\t} else {\n\t\tmax_prefix = 0\n\t}\n\tmax_prefix = brotli_min_uint32_t(max_prefix, *max_run_length_prefix)\n\t*max_run_length_prefix = max_prefix\n\t*out_size = 0\n\tfor i = 0; i < in_size; {\n\t\tassert(*out_size <= i)\n\t\tif v[i] != 0 {\n\t\t\tv[*out_size] = v[i] + *max_run_length_prefix\n\t\t\ti++\n\t\t\t(*out_size)++\n\t\t} else {\n\t\t\tvar reps uint32 = 1\n\t\t\tvar k uint\n\t\t\tfor k = i + 1; k < in_size && v[k] == 0; k++ {\n\t\t\t\treps++\n\t\t\t}\n\n\t\t\ti += uint(reps)\n\t\t\tfor reps != 0 {\n\t\t\t\tif reps < 2<<max_prefix {\n\t\t\t\t\tvar run_length_prefix uint32 = log2FloorNonZero(uint(reps))\n\t\t\t\t\tvar extra_bits uint32 = reps - (1 << run_length_prefix)\n\t\t\t\t\tv[*out_size] = run_length_prefix + (extra_bits << 9)\n\t\t\t\t\t(*out_size)++\n\t\t\t\t\tbreak\n\t\t\t\t} else {\n\t\t\t\t\tvar extra_bits uint32 = (1 << max_prefix) - 1\n\t\t\t\t\tv[*out_size] = max_prefix + (extra_bits << 9)\n\t\t\t\t\treps -= (2 << max_prefix) - 1\n\t\t\t\t\t(*out_size)++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst symbolBits = 9\n\nvar encodeContextMap_kSymbolMask uint32 = (1 << symbolBits) - 1\n\nfunc encodeContextMap(context_map []uint32, context_map_size uint, num_clusters uint, tree []huffmanTree, storage_ix *uint, storage []byte) {\n\tvar i uint\n\tvar rle_symbols []uint32\n\tvar max_run_length_prefix uint32 = 6\n\tvar num_rle_symbols uint = 0\n\tvar histogram [maxContextMapSymbols]uint32\n\tvar depths [maxContextMapSymbols]byte\n\tvar bits [maxContextMapSymbols]uint16\n\n\tstoreVarLenUint8(num_clusters-1, storage_ix, storage)\n\n\tif num_clusters == 1 {\n\t\treturn\n\t}\n\n\trle_symbols = make([]uint32, context_map_size)\n\tmoveToFrontTransform(context_map, context_map_size, rle_symbols)\n\trunLengthCodeZeros(context_map_size, rle_symbols, &num_rle_symbols, &max_run_length_prefix)\n\thistogram = [maxContextMapSymbols]uint32{}\n\tfor i = 0; i < num_rle_symbols; i++ {\n\t\thistogram[rle_symbols[i]&encodeContextMap_kSymbolMask]++\n\t}\n\t{\n\t\tvar use_rle bool = (max_run_length_prefix > 0)\n\t\twriteSingleBit(use_rle, storage_ix, storage)\n\t\tif use_rle {\n\t\t\twriteBits(4, uint64(max_run_length_prefix)-1, storage_ix, storage)\n\t\t}\n\t}\n\n\tbuildAndStoreHuffmanTree(histogram[:], uint(uint32(num_clusters)+max_run_length_prefix), uint(uint32(num_clusters)+max_run_length_prefix), tree, depths[:], bits[:], storage_ix, storage)\n\tfor i = 0; i < num_rle_symbols; i++ {\n\t\tvar rle_symbol uint32 = rle_symbols[i] & encodeContextMap_kSymbolMask\n\t\tvar extra_bits_val uint32 = rle_symbols[i] >> symbolBits\n\t\twriteBits(uint(depths[rle_symbol]), uint64(bits[rle_symbol]), storage_ix, storage)\n\t\tif rle_symbol > 0 && rle_symbol <= max_run_length_prefix {\n\t\t\twriteBits(uint(rle_symbol), uint64(extra_bits_val), storage_ix, storage)\n\t\t}\n\t}\n\n\twriteBits(1, 1, storage_ix, storage) /* use move-to-front */\n\trle_symbols = nil\n}\n\n/* Stores the block switch command with index block_ix to the bit stream. */\nfunc storeBlockSwitch(code *blockSplitCode, block_len uint32, block_type byte, is_first_block bool, storage_ix *uint, storage []byte) {\n\tvar typecode uint = nextBlockTypeCode(&code.type_code_calculator, block_type)\n\tvar lencode uint\n\tvar len_nextra uint32\n\tvar len_extra uint32\n\tif !is_first_block {\n\t\twriteBits(uint(code.type_depths[typecode]), uint64(code.type_bits[typecode]), storage_ix, storage)\n\t}\n\n\tgetBlockLengthPrefixCode(block_len, &lencode, &len_nextra, &len_extra)\n\n\twriteBits(uint(code.length_depths[lencode]), uint64(code.length_bits[lencode]), storage_ix, storage)\n\twriteBits(uint(len_nextra), uint64(len_extra), storage_ix, storage)\n}\n\n/*\nBuilds a BlockSplitCode data structure from the block split given by the\n\n\tvector of block types and block lengths and stores it to the bit stream.\n*/\nfunc buildAndStoreBlockSplitCode(types []byte, lengths []uint32, num_blocks uint, num_types uint, tree []huffmanTree, code *blockSplitCode, storage_ix *uint, storage []byte) {\n\tvar type_histo [maxBlockTypeSymbols]uint32\n\tvar length_histo [numBlockLenSymbols]uint32\n\tvar i uint\n\tvar type_code_calculator blockTypeCodeCalculator\n\tfor i := 0; i < int(num_types+2); i++ {\n\t\ttype_histo[i] = 0\n\t}\n\tlength_histo = [numBlockLenSymbols]uint32{}\n\tinitBlockTypeCodeCalculator(&type_code_calculator)\n\tfor i = 0; i < num_blocks; i++ {\n\t\tvar type_code uint = nextBlockTypeCode(&type_code_calculator, types[i])\n\t\tif i != 0 {\n\t\t\ttype_histo[type_code]++\n\t\t}\n\t\tlength_histo[blockLengthPrefixCode(lengths[i])]++\n\t}\n\n\tstoreVarLenUint8(num_types-1, storage_ix, storage)\n\tif num_types > 1 { /* TODO: else? could StoreBlockSwitch occur? */\n\t\tbuildAndStoreHuffmanTree(type_histo[0:], num_types+2, num_types+2, tree, code.type_depths[0:], code.type_bits[0:], storage_ix, storage)\n\t\tbuildAndStoreHuffmanTree(length_histo[0:], numBlockLenSymbols, numBlockLenSymbols, tree, code.length_depths[0:], code.length_bits[0:], storage_ix, storage)\n\t\tstoreBlockSwitch(code, lengths[0], types[0], true, storage_ix, storage)\n\t}\n}\n\n/* Stores a context map where the histogram type is always the block type. */\nfunc storeTrivialContextMap(num_types uint, context_bits uint, tree []huffmanTree, storage_ix *uint, storage []byte) {\n\tstoreVarLenUint8(num_types-1, storage_ix, storage)\n\tif num_types > 1 {\n\t\tvar repeat_code uint = context_bits - 1\n\t\tvar repeat_bits uint = (1 << repeat_code) - 1\n\t\tvar alphabet_size uint = num_types + repeat_code\n\t\tvar histogram [maxContextMapSymbols]uint32\n\t\tvar depths [maxContextMapSymbols]byte\n\t\tvar bits [maxContextMapSymbols]uint16\n\t\tvar i uint\n\t\tfor i := 0; i < int(alphabet_size); i++ {\n\t\t\thistogram[i] = 0\n\t\t}\n\n\t\t/* Write RLEMAX. */\n\t\twriteBits(1, 1, storage_ix, storage)\n\n\t\twriteBits(4, uint64(repeat_code)-1, storage_ix, storage)\n\t\thistogram[repeat_code] = uint32(num_types)\n\t\thistogram[0] = 1\n\t\tfor i = context_bits; i < alphabet_size; i++ {\n\t\t\thistogram[i] = 1\n\t\t}\n\n\t\tbuildAndStoreHuffmanTree(histogram[:], alphabet_size, alphabet_size, tree, depths[:], bits[:], storage_ix, storage)\n\t\tfor i = 0; i < num_types; i++ {\n\t\t\tvar tmp uint\n\t\t\tif i == 0 {\n\t\t\t\ttmp = 0\n\t\t\t} else {\n\t\t\t\ttmp = i + context_bits - 1\n\t\t\t}\n\t\t\tvar code uint = tmp\n\t\t\twriteBits(uint(depths[code]), uint64(bits[code]), storage_ix, storage)\n\t\t\twriteBits(uint(depths[repeat_code]), uint64(bits[repeat_code]), storage_ix, storage)\n\t\t\twriteBits(repeat_code, uint64(repeat_bits), storage_ix, storage)\n\t\t}\n\n\t\t/* Write IMTF (inverse-move-to-front) bit. */\n\t\twriteBits(1, 1, storage_ix, storage)\n\t}\n}\n\n/* Manages the encoding of one block category (literal, command or distance). */\ntype blockEncoder struct {\n\thistogram_length_ uint\n\tnum_block_types_  uint\n\tblock_types_      []byte\n\tblock_lengths_    []uint32\n\tnum_blocks_       uint\n\tblock_split_code_ blockSplitCode\n\tblock_ix_         uint\n\tblock_len_        uint\n\tentropy_ix_       uint\n\tdepths_           []byte\n\tbits_             []uint16\n}\n\nvar blockEncoderPool sync.Pool\n\nfunc getBlockEncoder(histogram_length uint, num_block_types uint, block_types []byte, block_lengths []uint32, num_blocks uint) *blockEncoder {\n\tself, _ := blockEncoderPool.Get().(*blockEncoder)\n\n\tif self != nil {\n\t\tself.block_ix_ = 0\n\t\tself.entropy_ix_ = 0\n\t\tself.depths_ = self.depths_[:0]\n\t\tself.bits_ = self.bits_[:0]\n\t} else {\n\t\tself = &blockEncoder{}\n\t}\n\n\tself.histogram_length_ = histogram_length\n\tself.num_block_types_ = num_block_types\n\tself.block_types_ = block_types\n\tself.block_lengths_ = block_lengths\n\tself.num_blocks_ = num_blocks\n\tinitBlockTypeCodeCalculator(&self.block_split_code_.type_code_calculator)\n\tif num_blocks == 0 {\n\t\tself.block_len_ = 0\n\t} else {\n\t\tself.block_len_ = uint(block_lengths[0])\n\t}\n\n\treturn self\n}\n\nfunc cleanupBlockEncoder(self *blockEncoder) {\n\tblockEncoderPool.Put(self)\n}\n\n/*\nCreates entropy codes of block lengths and block types and stores them\n\n\tto the bit stream.\n*/\nfunc buildAndStoreBlockSwitchEntropyCodes(self *blockEncoder, tree []huffmanTree, storage_ix *uint, storage []byte) {\n\tbuildAndStoreBlockSplitCode(self.block_types_, self.block_lengths_, self.num_blocks_, self.num_block_types_, tree, &self.block_split_code_, storage_ix, storage)\n}\n\n/*\nStores the next symbol with the entropy code of the current block type.\n\n\tUpdates the block type and block length at block boundaries.\n*/\nfunc storeSymbol(self *blockEncoder, symbol uint, storage_ix *uint, storage []byte) {\n\tif self.block_len_ == 0 {\n\t\tself.block_ix_++\n\t\tvar block_ix uint = self.block_ix_\n\t\tvar block_len uint32 = self.block_lengths_[block_ix]\n\t\tvar block_type byte = self.block_types_[block_ix]\n\t\tself.block_len_ = uint(block_len)\n\t\tself.entropy_ix_ = uint(block_type) * self.histogram_length_\n\t\tstoreBlockSwitch(&self.block_split_code_, block_len, block_type, false, storage_ix, storage)\n\t}\n\n\tself.block_len_--\n\t{\n\t\tvar ix uint = self.entropy_ix_ + symbol\n\t\twriteBits(uint(self.depths_[ix]), uint64(self.bits_[ix]), storage_ix, storage)\n\t}\n}\n\n/*\nStores the next symbol with the entropy code of the current block type and\n\n\tcontext value.\n\tUpdates the block type and block length at block boundaries.\n*/\nfunc storeSymbolWithContext(self *blockEncoder, symbol uint, context uint, context_map []uint32, storage_ix *uint, storage []byte, context_bits uint) {\n\tif self.block_len_ == 0 {\n\t\tself.block_ix_++\n\t\tvar block_ix uint = self.block_ix_\n\t\tvar block_len uint32 = self.block_lengths_[block_ix]\n\t\tvar block_type byte = self.block_types_[block_ix]\n\t\tself.block_len_ = uint(block_len)\n\t\tself.entropy_ix_ = uint(block_type) << context_bits\n\t\tstoreBlockSwitch(&self.block_split_code_, block_len, block_type, false, storage_ix, storage)\n\t}\n\n\tself.block_len_--\n\t{\n\t\tvar histo_ix uint = uint(context_map[self.entropy_ix_+context])\n\t\tvar ix uint = histo_ix*self.histogram_length_ + symbol\n\t\twriteBits(uint(self.depths_[ix]), uint64(self.bits_[ix]), storage_ix, storage)\n\t}\n}\n\nfunc buildAndStoreEntropyCodesLiteral(self *blockEncoder, histograms []histogramLiteral, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {\n\tvar table_size uint = histograms_size * self.histogram_length_\n\tif cap(self.depths_) < int(table_size) {\n\t\tself.depths_ = make([]byte, table_size)\n\t} else {\n\t\tself.depths_ = self.depths_[:table_size]\n\t}\n\tif cap(self.bits_) < int(table_size) {\n\t\tself.bits_ = make([]uint16, table_size)\n\t} else {\n\t\tself.bits_ = self.bits_[:table_size]\n\t}\n\t{\n\t\tvar i uint\n\t\tfor i = 0; i < histograms_size; i++ {\n\t\t\tvar ix uint = i * self.histogram_length_\n\t\t\tbuildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)\n\t\t}\n\t}\n}\n\nfunc buildAndStoreEntropyCodesCommand(self *blockEncoder, histograms []histogramCommand, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {\n\tvar table_size uint = histograms_size * self.histogram_length_\n\tif cap(self.depths_) < int(table_size) {\n\t\tself.depths_ = make([]byte, table_size)\n\t} else {\n\t\tself.depths_ = self.depths_[:table_size]\n\t}\n\tif cap(self.bits_) < int(table_size) {\n\t\tself.bits_ = make([]uint16, table_size)\n\t} else {\n\t\tself.bits_ = self.bits_[:table_size]\n\t}\n\t{\n\t\tvar i uint\n\t\tfor i = 0; i < histograms_size; i++ {\n\t\t\tvar ix uint = i * self.histogram_length_\n\t\t\tbuildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)\n\t\t}\n\t}\n}\n\nfunc buildAndStoreEntropyCodesDistance(self *blockEncoder, histograms []histogramDistance, histograms_size uint, alphabet_size uint, tree []huffmanTree, storage_ix *uint, storage []byte) {\n\tvar table_size uint = histograms_size * self.histogram_length_\n\tif cap(self.depths_) < int(table_size) {\n\t\tself.depths_ = make([]byte, table_size)\n\t} else {\n\t\tself.depths_ = self.depths_[:table_size]\n\t}\n\tif cap(self.bits_) < int(table_size) {\n\t\tself.bits_ = make([]uint16, table_size)\n\t} else {\n\t\tself.bits_ = self.bits_[:table_size]\n\t}\n\t{\n\t\tvar i uint\n\t\tfor i = 0; i < histograms_size; i++ {\n\t\t\tvar ix uint = i * self.histogram_length_\n\t\t\tbuildAndStoreHuffmanTree(histograms[i].data_[0:], self.histogram_length_, alphabet_size, tree, self.depths_[ix:], self.bits_[ix:], storage_ix, storage)\n\t\t}\n\t}\n}\n\nfunc jumpToByteBoundary(storage_ix *uint, storage []byte) {\n\t*storage_ix = (*storage_ix + 7) &^ 7\n\tstorage[*storage_ix>>3] = 0\n}\n\nfunc storeMetaBlock(input []byte, start_pos uint, length uint, mask uint, prev_byte byte, prev_byte2 byte, is_last bool, params *encoderParams, literal_context_mode int, commands []command, mb *metaBlockSplit, storage_ix *uint, storage []byte) {\n\tvar pos uint = start_pos\n\tvar i uint\n\tvar num_distance_symbols uint32 = params.dist.alphabet_size\n\tvar num_effective_distance_symbols uint32 = num_distance_symbols\n\tvar tree []huffmanTree\n\tvar literal_context_lut contextLUT = getContextLUT(literal_context_mode)\n\tvar dist *distanceParams = &params.dist\n\tif params.large_window && num_effective_distance_symbols > numHistogramDistanceSymbols {\n\t\tnum_effective_distance_symbols = numHistogramDistanceSymbols\n\t}\n\n\tstoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage)\n\n\ttree = make([]huffmanTree, maxHuffmanTreeSize)\n\tliteral_enc := getBlockEncoder(numLiteralSymbols, mb.literal_split.num_types, mb.literal_split.types, mb.literal_split.lengths, mb.literal_split.num_blocks)\n\tcommand_enc := getBlockEncoder(numCommandSymbols, mb.command_split.num_types, mb.command_split.types, mb.command_split.lengths, mb.command_split.num_blocks)\n\tdistance_enc := getBlockEncoder(uint(num_effective_distance_symbols), mb.distance_split.num_types, mb.distance_split.types, mb.distance_split.lengths, mb.distance_split.num_blocks)\n\n\tbuildAndStoreBlockSwitchEntropyCodes(literal_enc, tree, storage_ix, storage)\n\tbuildAndStoreBlockSwitchEntropyCodes(command_enc, tree, storage_ix, storage)\n\tbuildAndStoreBlockSwitchEntropyCodes(distance_enc, tree, storage_ix, storage)\n\n\twriteBits(2, uint64(dist.distance_postfix_bits), storage_ix, storage)\n\twriteBits(4, uint64(dist.num_direct_distance_codes)>>dist.distance_postfix_bits, storage_ix, storage)\n\tfor i = 0; i < mb.literal_split.num_types; i++ {\n\t\twriteBits(2, uint64(literal_context_mode), storage_ix, storage)\n\t}\n\n\tif mb.literal_context_map_size == 0 {\n\t\tstoreTrivialContextMap(mb.literal_histograms_size, literalContextBits, tree, storage_ix, storage)\n\t} else {\n\t\tencodeContextMap(mb.literal_context_map, mb.literal_context_map_size, mb.literal_histograms_size, tree, storage_ix, storage)\n\t}\n\n\tif mb.distance_context_map_size == 0 {\n\t\tstoreTrivialContextMap(mb.distance_histograms_size, distanceContextBits, tree, storage_ix, storage)\n\t} else {\n\t\tencodeContextMap(mb.distance_context_map, mb.distance_context_map_size, mb.distance_histograms_size, tree, storage_ix, storage)\n\t}\n\n\tbuildAndStoreEntropyCodesLiteral(literal_enc, mb.literal_histograms, mb.literal_histograms_size, numLiteralSymbols, tree, storage_ix, storage)\n\tbuildAndStoreEntropyCodesCommand(command_enc, mb.command_histograms, mb.command_histograms_size, numCommandSymbols, tree, storage_ix, storage)\n\tbuildAndStoreEntropyCodesDistance(distance_enc, mb.distance_histograms, mb.distance_histograms_size, uint(num_distance_symbols), tree, storage_ix, storage)\n\ttree = nil\n\n\tfor _, cmd := range commands {\n\t\tvar cmd_code uint = uint(cmd.cmd_prefix_)\n\t\tstoreSymbol(command_enc, cmd_code, storage_ix, storage)\n\t\tstoreCommandExtra(&cmd, storage_ix, storage)\n\t\tif mb.literal_context_map_size == 0 {\n\t\t\tvar j uint\n\t\t\tfor j = uint(cmd.insert_len_); j != 0; j-- {\n\t\t\t\tstoreSymbol(literal_enc, uint(input[pos&mask]), storage_ix, storage)\n\t\t\t\tpos++\n\t\t\t}\n\t\t} else {\n\t\t\tvar j uint\n\t\t\tfor j = uint(cmd.insert_len_); j != 0; j-- {\n\t\t\t\tvar context uint = uint(getContext(prev_byte, prev_byte2, literal_context_lut))\n\t\t\t\tvar literal byte = input[pos&mask]\n\t\t\t\tstoreSymbolWithContext(literal_enc, uint(literal), context, mb.literal_context_map, storage_ix, storage, literalContextBits)\n\t\t\t\tprev_byte2 = prev_byte\n\t\t\t\tprev_byte = literal\n\t\t\t\tpos++\n\t\t\t}\n\t\t}\n\n\t\tpos += uint(commandCopyLen(&cmd))\n\t\tif commandCopyLen(&cmd) != 0 {\n\t\t\tprev_byte2 = input[(pos-2)&mask]\n\t\t\tprev_byte = input[(pos-1)&mask]\n\t\t\tif cmd.cmd_prefix_ >= 128 {\n\t\t\t\tvar dist_code uint = uint(cmd.dist_prefix_) & 0x3FF\n\t\t\t\tvar distnumextra uint32 = uint32(cmd.dist_prefix_) >> 10\n\t\t\t\tvar distextra uint64 = uint64(cmd.dist_extra_)\n\t\t\t\tif mb.distance_context_map_size == 0 {\n\t\t\t\t\tstoreSymbol(distance_enc, dist_code, storage_ix, storage)\n\t\t\t\t} else {\n\t\t\t\t\tvar context uint = uint(commandDistanceContext(&cmd))\n\t\t\t\t\tstoreSymbolWithContext(distance_enc, dist_code, context, mb.distance_context_map, storage_ix, storage, distanceContextBits)\n\t\t\t\t}\n\n\t\t\t\twriteBits(uint(distnumextra), distextra, storage_ix, storage)\n\t\t\t}\n\t\t}\n\t}\n\n\tcleanupBlockEncoder(distance_enc)\n\tcleanupBlockEncoder(command_enc)\n\tcleanupBlockEncoder(literal_enc)\n\tif is_last {\n\t\tjumpToByteBoundary(storage_ix, storage)\n\t}\n}\n\nfunc buildHistograms(input []byte, start_pos uint, mask uint, commands []command, lit_histo *histogramLiteral, cmd_histo *histogramCommand, dist_histo *histogramDistance) {\n\tvar pos uint = start_pos\n\tfor _, cmd := range commands {\n\t\tvar j uint\n\t\thistogramAddCommand(cmd_histo, uint(cmd.cmd_prefix_))\n\t\tfor j = uint(cmd.insert_len_); j != 0; j-- {\n\t\t\thistogramAddLiteral(lit_histo, uint(input[pos&mask]))\n\t\t\tpos++\n\t\t}\n\n\t\tpos += uint(commandCopyLen(&cmd))\n\t\tif commandCopyLen(&cmd) != 0 && cmd.cmd_prefix_ >= 128 {\n\t\t\thistogramAddDistance(dist_histo, uint(cmd.dist_prefix_)&0x3FF)\n\t\t}\n\t}\n}\n\nfunc storeDataWithHuffmanCodes(input []byte, start_pos uint, mask uint, commands []command, lit_depth []byte, lit_bits []uint16, cmd_depth []byte, cmd_bits []uint16, dist_depth []byte, dist_bits []uint16, storage_ix *uint, storage []byte) {\n\tvar pos uint = start_pos\n\tfor _, cmd := range commands {\n\t\tvar cmd_code uint = uint(cmd.cmd_prefix_)\n\t\tvar j uint\n\t\twriteBits(uint(cmd_depth[cmd_code]), uint64(cmd_bits[cmd_code]), storage_ix, storage)\n\t\tstoreCommandExtra(&cmd, storage_ix, storage)\n\t\tfor j = uint(cmd.insert_len_); j != 0; j-- {\n\t\t\tvar literal byte = input[pos&mask]\n\t\t\twriteBits(uint(lit_depth[literal]), uint64(lit_bits[literal]), storage_ix, storage)\n\t\t\tpos++\n\t\t}\n\n\t\tpos += uint(commandCopyLen(&cmd))\n\t\tif commandCopyLen(&cmd) != 0 && cmd.cmd_prefix_ >= 128 {\n\t\t\tvar dist_code uint = uint(cmd.dist_prefix_) & 0x3FF\n\t\t\tvar distnumextra uint32 = uint32(cmd.dist_prefix_) >> 10\n\t\t\tvar distextra uint32 = cmd.dist_extra_\n\t\t\twriteBits(uint(dist_depth[dist_code]), uint64(dist_bits[dist_code]), storage_ix, storage)\n\t\t\twriteBits(uint(distnumextra), uint64(distextra), storage_ix, storage)\n\t\t}\n\t}\n}\n\nfunc storeMetaBlockTrivial(input []byte, start_pos uint, length uint, mask uint, is_last bool, params *encoderParams, commands []command, storage_ix *uint, storage []byte) {\n\tvar lit_histo histogramLiteral\n\tvar cmd_histo histogramCommand\n\tvar dist_histo histogramDistance\n\tvar lit_depth [numLiteralSymbols]byte\n\tvar lit_bits [numLiteralSymbols]uint16\n\tvar cmd_depth [numCommandSymbols]byte\n\tvar cmd_bits [numCommandSymbols]uint16\n\tvar dist_depth [maxSimpleDistanceAlphabetSize]byte\n\tvar dist_bits [maxSimpleDistanceAlphabetSize]uint16\n\tvar tree []huffmanTree\n\tvar num_distance_symbols uint32 = params.dist.alphabet_size\n\n\tstoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage)\n\n\thistogramClearLiteral(&lit_histo)\n\thistogramClearCommand(&cmd_histo)\n\thistogramClearDistance(&dist_histo)\n\n\tbuildHistograms(input, start_pos, mask, commands, &lit_histo, &cmd_histo, &dist_histo)\n\n\twriteBits(13, 0, storage_ix, storage)\n\n\ttree = make([]huffmanTree, maxHuffmanTreeSize)\n\tbuildAndStoreHuffmanTree(lit_histo.data_[:], numLiteralSymbols, numLiteralSymbols, tree, lit_depth[:], lit_bits[:], storage_ix, storage)\n\tbuildAndStoreHuffmanTree(cmd_histo.data_[:], numCommandSymbols, numCommandSymbols, tree, cmd_depth[:], cmd_bits[:], storage_ix, storage)\n\tbuildAndStoreHuffmanTree(dist_histo.data_[:], maxSimpleDistanceAlphabetSize, uint(num_distance_symbols), tree, dist_depth[:], dist_bits[:], storage_ix, storage)\n\ttree = nil\n\tstoreDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], cmd_depth[:], cmd_bits[:], dist_depth[:], dist_bits[:], storage_ix, storage)\n\tif is_last {\n\t\tjumpToByteBoundary(storage_ix, storage)\n\t}\n}\n\nfunc storeMetaBlockFast(input []byte, start_pos uint, length uint, mask uint, is_last bool, params *encoderParams, commands []command, storage_ix *uint, storage []byte) {\n\tvar num_distance_symbols uint32 = params.dist.alphabet_size\n\tvar distance_alphabet_bits uint32 = log2FloorNonZero(uint(num_distance_symbols-1)) + 1\n\n\tstoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage)\n\n\twriteBits(13, 0, storage_ix, storage)\n\n\tif len(commands) <= 128 {\n\t\tvar histogram = [numLiteralSymbols]uint32{0}\n\t\tvar pos uint = start_pos\n\t\tvar num_literals uint = 0\n\t\tvar lit_depth [numLiteralSymbols]byte\n\t\tvar lit_bits [numLiteralSymbols]uint16\n\t\tfor _, cmd := range commands {\n\t\t\tvar j uint\n\t\t\tfor j = uint(cmd.insert_len_); j != 0; j-- {\n\t\t\t\thistogram[input[pos&mask]]++\n\t\t\t\tpos++\n\t\t\t}\n\n\t\t\tnum_literals += uint(cmd.insert_len_)\n\t\t\tpos += uint(commandCopyLen(&cmd))\n\t\t}\n\n\t\tbuildAndStoreHuffmanTreeFast(histogram[:], num_literals, /* max_bits = */\n\t\t\t8, lit_depth[:], lit_bits[:], storage_ix, storage)\n\n\t\tstoreStaticCommandHuffmanTree(storage_ix, storage)\n\t\tstoreStaticDistanceHuffmanTree(storage_ix, storage)\n\t\tstoreDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], kStaticCommandCodeDepth[:], kStaticCommandCodeBits[:], kStaticDistanceCodeDepth[:], kStaticDistanceCodeBits[:], storage_ix, storage)\n\t} else {\n\t\tvar lit_histo histogramLiteral\n\t\tvar cmd_histo histogramCommand\n\t\tvar dist_histo histogramDistance\n\t\tvar lit_depth [numLiteralSymbols]byte\n\t\tvar lit_bits [numLiteralSymbols]uint16\n\t\tvar cmd_depth [numCommandSymbols]byte\n\t\tvar cmd_bits [numCommandSymbols]uint16\n\t\tvar dist_depth [maxSimpleDistanceAlphabetSize]byte\n\t\tvar dist_bits [maxSimpleDistanceAlphabetSize]uint16\n\t\thistogramClearLiteral(&lit_histo)\n\t\thistogramClearCommand(&cmd_histo)\n\t\thistogramClearDistance(&dist_histo)\n\t\tbuildHistograms(input, start_pos, mask, commands, &lit_histo, &cmd_histo, &dist_histo)\n\t\tbuildAndStoreHuffmanTreeFast(lit_histo.data_[:], lit_histo.total_count_, /* max_bits = */\n\t\t\t8, lit_depth[:], lit_bits[:], storage_ix, storage)\n\n\t\tbuildAndStoreHuffmanTreeFast(cmd_histo.data_[:], cmd_histo.total_count_, /* max_bits = */\n\t\t\t10, cmd_depth[:], cmd_bits[:], storage_ix, storage)\n\n\t\tbuildAndStoreHuffmanTreeFast(dist_histo.data_[:], dist_histo.total_count_, /* max_bits = */\n\t\t\tuint(distance_alphabet_bits), dist_depth[:], dist_bits[:], storage_ix, storage)\n\n\t\tstoreDataWithHuffmanCodes(input, start_pos, mask, commands, lit_depth[:], lit_bits[:], cmd_depth[:], cmd_bits[:], dist_depth[:], dist_bits[:], storage_ix, storage)\n\t}\n\n\tif is_last {\n\t\tjumpToByteBoundary(storage_ix, storage)\n\t}\n}\n\n/*\nThis is for storing uncompressed blocks (simple raw storage of\n\n\tbytes-as-bytes).\n*/\nfunc storeUncompressedMetaBlock(is_final_block bool, input []byte, position uint, mask uint, len uint, storage_ix *uint, storage []byte) {\n\tvar masked_pos uint = position & mask\n\tstoreUncompressedMetaBlockHeader(uint(len), storage_ix, storage)\n\tjumpToByteBoundary(storage_ix, storage)\n\n\tif masked_pos+len > mask+1 {\n\t\tvar len1 uint = mask + 1 - masked_pos\n\t\tcopy(storage[*storage_ix>>3:], input[masked_pos:][:len1])\n\t\t*storage_ix += len1 << 3\n\t\tlen -= len1\n\t\tmasked_pos = 0\n\t}\n\n\tcopy(storage[*storage_ix>>3:], input[masked_pos:][:len])\n\t*storage_ix += uint(len << 3)\n\n\t/* We need to clear the next 4 bytes to continue to be\n\t   compatible with BrotliWriteBits. */\n\twriteBitsPrepareStorage(*storage_ix, storage)\n\n\t/* Since the uncompressed block itself may not be the final block, add an\n\t   empty one after this. */\n\tif is_final_block {\n\t\twriteBits(1, 1, storage_ix, storage) /* islast */\n\t\twriteBits(1, 1, storage_ix, storage) /* isempty */\n\t\tjumpToByteBoundary(storage_ix, storage)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/cluster.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Functions for clustering similar histograms together. */\n\ntype histogramPair struct {\n\tidx1       uint32\n\tidx2       uint32\n\tcost_combo float64\n\tcost_diff  float64\n}\n\nfunc histogramPairIsLess(p1 *histogramPair, p2 *histogramPair) bool {\n\tif p1.cost_diff != p2.cost_diff {\n\t\treturn p1.cost_diff > p2.cost_diff\n\t}\n\n\treturn (p1.idx2 - p1.idx1) > (p2.idx2 - p2.idx1)\n}\n\n/* Returns entropy reduction of the context map when we combine two clusters. */\nfunc clusterCostDiff(size_a uint, size_b uint) float64 {\n\tvar size_c uint = size_a + size_b\n\treturn float64(size_a)*fastLog2(size_a) + float64(size_b)*fastLog2(size_b) - float64(size_c)*fastLog2(size_c)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/cluster_command.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if\n   it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */\nfunc compareAndPushToQueueCommand(out []histogramCommand, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {\n\tvar is_good_pair bool = false\n\tvar p histogramPair\n\tp.idx2 = 0\n\tp.idx1 = p.idx2\n\tp.cost_combo = 0\n\tp.cost_diff = p.cost_combo\n\tif idx1 == idx2 {\n\t\treturn\n\t}\n\n\tif idx2 < idx1 {\n\t\tvar t uint32 = idx2\n\t\tidx2 = idx1\n\t\tidx1 = t\n\t}\n\n\tp.idx1 = idx1\n\tp.idx2 = idx2\n\tp.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))\n\tp.cost_diff -= out[idx1].bit_cost_\n\tp.cost_diff -= out[idx2].bit_cost_\n\n\tif out[idx1].total_count_ == 0 {\n\t\tp.cost_combo = out[idx2].bit_cost_\n\t\tis_good_pair = true\n\t} else if out[idx2].total_count_ == 0 {\n\t\tp.cost_combo = out[idx1].bit_cost_\n\t\tis_good_pair = true\n\t} else {\n\t\tvar threshold float64\n\t\tif *num_pairs == 0 {\n\t\t\tthreshold = 1e99\n\t\t} else {\n\t\t\tthreshold = brotli_max_double(0.0, pairs[0].cost_diff)\n\t\t}\n\t\tvar combo histogramCommand = out[idx1]\n\t\tvar cost_combo float64\n\t\thistogramAddHistogramCommand(&combo, &out[idx2])\n\t\tcost_combo = populationCostCommand(&combo)\n\t\tif cost_combo < threshold-p.cost_diff {\n\t\t\tp.cost_combo = cost_combo\n\t\t\tis_good_pair = true\n\t\t}\n\t}\n\n\tif is_good_pair {\n\t\tp.cost_diff += p.cost_combo\n\t\tif *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {\n\t\t\t/* Replace the top of the queue if needed. */\n\t\t\tif *num_pairs < max_num_pairs {\n\t\t\t\tpairs[*num_pairs] = pairs[0]\n\t\t\t\t(*num_pairs)++\n\t\t\t}\n\n\t\t\tpairs[0] = p\n\t\t} else if *num_pairs < max_num_pairs {\n\t\t\tpairs[*num_pairs] = p\n\t\t\t(*num_pairs)++\n\t\t}\n\t}\n}\n\nfunc histogramCombineCommand(out []histogramCommand, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {\n\tvar cost_diff_threshold float64 = 0.0\n\tvar min_cluster_size uint = 1\n\tvar num_pairs uint = 0\n\t{\n\t\t/* We maintain a vector of histogram pairs, with the property that the pair\n\t\t   with the maximum bit cost reduction is the first. */\n\t\tvar idx1 uint\n\t\tfor idx1 = 0; idx1 < num_clusters; idx1++ {\n\t\t\tvar idx2 uint\n\t\t\tfor idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {\n\t\t\t\tcompareAndPushToQueueCommand(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor num_clusters > min_cluster_size {\n\t\tvar best_idx1 uint32\n\t\tvar best_idx2 uint32\n\t\tvar i uint\n\t\tif pairs[0].cost_diff >= cost_diff_threshold {\n\t\t\tcost_diff_threshold = 1e99\n\t\t\tmin_cluster_size = max_clusters\n\t\t\tcontinue\n\t\t}\n\n\t\t/* Take the best pair from the top of heap. */\n\t\tbest_idx1 = pairs[0].idx1\n\n\t\tbest_idx2 = pairs[0].idx2\n\t\thistogramAddHistogramCommand(&out[best_idx1], &out[best_idx2])\n\t\tout[best_idx1].bit_cost_ = pairs[0].cost_combo\n\t\tcluster_size[best_idx1] += cluster_size[best_idx2]\n\t\tfor i = 0; i < symbols_size; i++ {\n\t\t\tif symbols[i] == best_idx2 {\n\t\t\t\tsymbols[i] = best_idx1\n\t\t\t}\n\t\t}\n\n\t\tfor i = 0; i < num_clusters; i++ {\n\t\t\tif clusters[i] == best_idx2 {\n\t\t\t\tcopy(clusters[i:], clusters[i+1:][:num_clusters-i-1])\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tnum_clusters--\n\t\t{\n\t\t\t/* Remove pairs intersecting the just combined best pair. */\n\t\t\tvar copy_to_idx uint = 0\n\t\t\tfor i = 0; i < num_pairs; i++ {\n\t\t\t\tvar p *histogramPair = &pairs[i]\n\t\t\t\tif p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {\n\t\t\t\t\t/* Remove invalid pair from the queue. */\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif histogramPairIsLess(&pairs[0], p) {\n\t\t\t\t\t/* Replace the top of the queue if needed. */\n\t\t\t\t\tvar front histogramPair = pairs[0]\n\t\t\t\t\tpairs[0] = *p\n\t\t\t\t\tpairs[copy_to_idx] = front\n\t\t\t\t} else {\n\t\t\t\t\tpairs[copy_to_idx] = *p\n\t\t\t\t}\n\n\t\t\t\tcopy_to_idx++\n\t\t\t}\n\n\t\t\tnum_pairs = copy_to_idx\n\t\t}\n\n\t\t/* Push new pairs formed with the combined histogram to the heap. */\n\t\tfor i = 0; i < num_clusters; i++ {\n\t\t\tcompareAndPushToQueueCommand(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)\n\t\t}\n\t}\n\n\treturn num_clusters\n}\n\n/* What is the bit cost of moving histogram from cur_symbol to candidate. */\nfunc histogramBitCostDistanceCommand(histogram *histogramCommand, candidate *histogramCommand) float64 {\n\tif histogram.total_count_ == 0 {\n\t\treturn 0.0\n\t} else {\n\t\tvar tmp histogramCommand = *histogram\n\t\thistogramAddHistogramCommand(&tmp, candidate)\n\t\treturn populationCostCommand(&tmp) - candidate.bit_cost_\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/cluster_distance.go",
    "content": "package brotli\n\nimport \"math\"\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if\n   it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */\nfunc compareAndPushToQueueDistance(out []histogramDistance, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {\n\tvar is_good_pair bool = false\n\tvar p histogramPair\n\tp.idx2 = 0\n\tp.idx1 = p.idx2\n\tp.cost_combo = 0\n\tp.cost_diff = p.cost_combo\n\tif idx1 == idx2 {\n\t\treturn\n\t}\n\n\tif idx2 < idx1 {\n\t\tvar t uint32 = idx2\n\t\tidx2 = idx1\n\t\tidx1 = t\n\t}\n\n\tp.idx1 = idx1\n\tp.idx2 = idx2\n\tp.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))\n\tp.cost_diff -= out[idx1].bit_cost_\n\tp.cost_diff -= out[idx2].bit_cost_\n\n\tif out[idx1].total_count_ == 0 {\n\t\tp.cost_combo = out[idx2].bit_cost_\n\t\tis_good_pair = true\n\t} else if out[idx2].total_count_ == 0 {\n\t\tp.cost_combo = out[idx1].bit_cost_\n\t\tis_good_pair = true\n\t} else {\n\t\tvar threshold float64\n\t\tif *num_pairs == 0 {\n\t\t\tthreshold = 1e99\n\t\t} else {\n\t\t\tthreshold = brotli_max_double(0.0, pairs[0].cost_diff)\n\t\t}\n\t\tvar combo histogramDistance = out[idx1]\n\t\tvar cost_combo float64\n\t\thistogramAddHistogramDistance(&combo, &out[idx2])\n\t\tcost_combo = populationCostDistance(&combo)\n\t\tif cost_combo < threshold-p.cost_diff {\n\t\t\tp.cost_combo = cost_combo\n\t\t\tis_good_pair = true\n\t\t}\n\t}\n\n\tif is_good_pair {\n\t\tp.cost_diff += p.cost_combo\n\t\tif *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {\n\t\t\t/* Replace the top of the queue if needed. */\n\t\t\tif *num_pairs < max_num_pairs {\n\t\t\t\tpairs[*num_pairs] = pairs[0]\n\t\t\t\t(*num_pairs)++\n\t\t\t}\n\n\t\t\tpairs[0] = p\n\t\t} else if *num_pairs < max_num_pairs {\n\t\t\tpairs[*num_pairs] = p\n\t\t\t(*num_pairs)++\n\t\t}\n\t}\n}\n\nfunc histogramCombineDistance(out []histogramDistance, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {\n\tvar cost_diff_threshold float64 = 0.0\n\tvar min_cluster_size uint = 1\n\tvar num_pairs uint = 0\n\t{\n\t\t/* We maintain a vector of histogram pairs, with the property that the pair\n\t\t   with the maximum bit cost reduction is the first. */\n\t\tvar idx1 uint\n\t\tfor idx1 = 0; idx1 < num_clusters; idx1++ {\n\t\t\tvar idx2 uint\n\t\t\tfor idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {\n\t\t\t\tcompareAndPushToQueueDistance(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor num_clusters > min_cluster_size {\n\t\tvar best_idx1 uint32\n\t\tvar best_idx2 uint32\n\t\tvar i uint\n\t\tif pairs[0].cost_diff >= cost_diff_threshold {\n\t\t\tcost_diff_threshold = 1e99\n\t\t\tmin_cluster_size = max_clusters\n\t\t\tcontinue\n\t\t}\n\n\t\t/* Take the best pair from the top of heap. */\n\t\tbest_idx1 = pairs[0].idx1\n\n\t\tbest_idx2 = pairs[0].idx2\n\t\thistogramAddHistogramDistance(&out[best_idx1], &out[best_idx2])\n\t\tout[best_idx1].bit_cost_ = pairs[0].cost_combo\n\t\tcluster_size[best_idx1] += cluster_size[best_idx2]\n\t\tfor i = 0; i < symbols_size; i++ {\n\t\t\tif symbols[i] == best_idx2 {\n\t\t\t\tsymbols[i] = best_idx1\n\t\t\t}\n\t\t}\n\n\t\tfor i = 0; i < num_clusters; i++ {\n\t\t\tif clusters[i] == best_idx2 {\n\t\t\t\tcopy(clusters[i:], clusters[i+1:][:num_clusters-i-1])\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tnum_clusters--\n\t\t{\n\t\t\t/* Remove pairs intersecting the just combined best pair. */\n\t\t\tvar copy_to_idx uint = 0\n\t\t\tfor i = 0; i < num_pairs; i++ {\n\t\t\t\tvar p *histogramPair = &pairs[i]\n\t\t\t\tif p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {\n\t\t\t\t\t/* Remove invalid pair from the queue. */\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif histogramPairIsLess(&pairs[0], p) {\n\t\t\t\t\t/* Replace the top of the queue if needed. */\n\t\t\t\t\tvar front histogramPair = pairs[0]\n\t\t\t\t\tpairs[0] = *p\n\t\t\t\t\tpairs[copy_to_idx] = front\n\t\t\t\t} else {\n\t\t\t\t\tpairs[copy_to_idx] = *p\n\t\t\t\t}\n\n\t\t\t\tcopy_to_idx++\n\t\t\t}\n\n\t\t\tnum_pairs = copy_to_idx\n\t\t}\n\n\t\t/* Push new pairs formed with the combined histogram to the heap. */\n\t\tfor i = 0; i < num_clusters; i++ {\n\t\t\tcompareAndPushToQueueDistance(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)\n\t\t}\n\t}\n\n\treturn num_clusters\n}\n\n/* What is the bit cost of moving histogram from cur_symbol to candidate. */\nfunc histogramBitCostDistanceDistance(histogram *histogramDistance, candidate *histogramDistance) float64 {\n\tif histogram.total_count_ == 0 {\n\t\treturn 0.0\n\t} else {\n\t\tvar tmp histogramDistance = *histogram\n\t\thistogramAddHistogramDistance(&tmp, candidate)\n\t\treturn populationCostDistance(&tmp) - candidate.bit_cost_\n\t}\n}\n\n/* Find the best 'out' histogram for each of the 'in' histograms.\n   When called, clusters[0..num_clusters) contains the unique values from\n   symbols[0..in_size), but this property is not preserved in this function.\n   Note: we assume that out[]->bit_cost_ is already up-to-date. */\nfunc histogramRemapDistance(in []histogramDistance, in_size uint, clusters []uint32, num_clusters uint, out []histogramDistance, symbols []uint32) {\n\tvar i uint\n\tfor i = 0; i < in_size; i++ {\n\t\tvar best_out uint32\n\t\tif i == 0 {\n\t\t\tbest_out = symbols[0]\n\t\t} else {\n\t\t\tbest_out = symbols[i-1]\n\t\t}\n\t\tvar best_bits float64 = histogramBitCostDistanceDistance(&in[i], &out[best_out])\n\t\tvar j uint\n\t\tfor j = 0; j < num_clusters; j++ {\n\t\t\tvar cur_bits float64 = histogramBitCostDistanceDistance(&in[i], &out[clusters[j]])\n\t\t\tif cur_bits < best_bits {\n\t\t\t\tbest_bits = cur_bits\n\t\t\t\tbest_out = clusters[j]\n\t\t\t}\n\t\t}\n\n\t\tsymbols[i] = best_out\n\t}\n\n\t/* Recompute each out based on raw and symbols. */\n\tfor i = 0; i < num_clusters; i++ {\n\t\thistogramClearDistance(&out[clusters[i]])\n\t}\n\n\tfor i = 0; i < in_size; i++ {\n\t\thistogramAddHistogramDistance(&out[symbols[i]], &in[i])\n\t}\n}\n\n/* Reorders elements of the out[0..length) array and changes values in\n   symbols[0..length) array in the following way:\n     * when called, symbols[] contains indexes into out[], and has N unique\n       values (possibly N < length)\n     * on return, symbols'[i] = f(symbols[i]) and\n                  out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,\n       where f is a bijection between the range of symbols[] and [0..N), and\n       the first occurrences of values in symbols'[i] come in consecutive\n       increasing order.\n   Returns N, the number of unique values in symbols[]. */\n\nvar histogramReindexDistance_kInvalidIndex uint32 = math.MaxUint32\n\nfunc histogramReindexDistance(out []histogramDistance, symbols []uint32, length uint) uint {\n\tvar new_index []uint32 = make([]uint32, length)\n\tvar next_index uint32\n\tvar tmp []histogramDistance\n\tvar i uint\n\tfor i = 0; i < length; i++ {\n\t\tnew_index[i] = histogramReindexDistance_kInvalidIndex\n\t}\n\n\tnext_index = 0\n\tfor i = 0; i < length; i++ {\n\t\tif new_index[symbols[i]] == histogramReindexDistance_kInvalidIndex {\n\t\t\tnew_index[symbols[i]] = next_index\n\t\t\tnext_index++\n\t\t}\n\t}\n\n\t/* TODO: by using idea of \"cycle-sort\" we can avoid allocation of\n\t   tmp and reduce the number of copying by the factor of 2. */\n\ttmp = make([]histogramDistance, next_index)\n\n\tnext_index = 0\n\tfor i = 0; i < length; i++ {\n\t\tif new_index[symbols[i]] == next_index {\n\t\t\ttmp[next_index] = out[symbols[i]]\n\t\t\tnext_index++\n\t\t}\n\n\t\tsymbols[i] = new_index[symbols[i]]\n\t}\n\n\tnew_index = nil\n\tfor i = 0; uint32(i) < next_index; i++ {\n\t\tout[i] = tmp[i]\n\t}\n\n\ttmp = nil\n\treturn uint(next_index)\n}\n\nfunc clusterHistogramsDistance(in []histogramDistance, in_size uint, max_histograms uint, out []histogramDistance, out_size *uint, histogram_symbols []uint32) {\n\tvar cluster_size []uint32 = make([]uint32, in_size)\n\tvar clusters []uint32 = make([]uint32, in_size)\n\tvar num_clusters uint = 0\n\tvar max_input_histograms uint = 64\n\tvar pairs_capacity uint = max_input_histograms * max_input_histograms / 2\n\tvar pairs []histogramPair = make([]histogramPair, (pairs_capacity + 1))\n\tvar i uint\n\n\t/* For the first pass of clustering, we allow all pairs. */\n\tfor i = 0; i < in_size; i++ {\n\t\tcluster_size[i] = 1\n\t}\n\n\tfor i = 0; i < in_size; i++ {\n\t\tout[i] = in[i]\n\t\tout[i].bit_cost_ = populationCostDistance(&in[i])\n\t\thistogram_symbols[i] = uint32(i)\n\t}\n\n\tfor i = 0; i < in_size; i += max_input_histograms {\n\t\tvar num_to_combine uint = brotli_min_size_t(in_size-i, max_input_histograms)\n\t\tvar num_new_clusters uint\n\t\tvar j uint\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\tclusters[num_clusters+j] = uint32(i + j)\n\t\t}\n\n\t\tnum_new_clusters = histogramCombineDistance(out, cluster_size, histogram_symbols[i:], clusters[num_clusters:], pairs, num_to_combine, num_to_combine, max_histograms, pairs_capacity)\n\t\tnum_clusters += num_new_clusters\n\t}\n\t{\n\t\t/* For the second pass, we limit the total number of histogram pairs.\n\t\t   After this limit is reached, we only keep searching for the best pair. */\n\t\tvar max_num_pairs uint = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)\n\t\tif pairs_capacity < (max_num_pairs + 1) {\n\t\t\tvar _new_size uint\n\t\t\tif pairs_capacity == 0 {\n\t\t\t\t_new_size = max_num_pairs + 1\n\t\t\t} else {\n\t\t\t\t_new_size = pairs_capacity\n\t\t\t}\n\t\t\tvar new_array []histogramPair\n\t\t\tfor _new_size < (max_num_pairs + 1) {\n\t\t\t\t_new_size *= 2\n\t\t\t}\n\t\t\tnew_array = make([]histogramPair, _new_size)\n\t\t\tif pairs_capacity != 0 {\n\t\t\t\tcopy(new_array, pairs[:pairs_capacity])\n\t\t\t}\n\n\t\t\tpairs = new_array\n\t\t\tpairs_capacity = _new_size\n\t\t}\n\n\t\t/* Collapse similar histograms. */\n\t\tnum_clusters = histogramCombineDistance(out, cluster_size, histogram_symbols, clusters, pairs, num_clusters, in_size, max_histograms, max_num_pairs)\n\t}\n\n\tpairs = nil\n\tcluster_size = nil\n\n\t/* Find the optimal map from original histograms to the final ones. */\n\thistogramRemapDistance(in, in_size, clusters, num_clusters, out, histogram_symbols)\n\n\tclusters = nil\n\n\t/* Convert the context map to a canonical form. */\n\t*out_size = histogramReindexDistance(out, histogram_symbols, in_size)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/cluster_literal.go",
    "content": "package brotli\n\nimport \"math\"\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if\n   it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */\nfunc compareAndPushToQueueLiteral(out []histogramLiteral, cluster_size []uint32, idx1 uint32, idx2 uint32, max_num_pairs uint, pairs []histogramPair, num_pairs *uint) {\n\tvar is_good_pair bool = false\n\tvar p histogramPair\n\tp.idx2 = 0\n\tp.idx1 = p.idx2\n\tp.cost_combo = 0\n\tp.cost_diff = p.cost_combo\n\tif idx1 == idx2 {\n\t\treturn\n\t}\n\n\tif idx2 < idx1 {\n\t\tvar t uint32 = idx2\n\t\tidx2 = idx1\n\t\tidx1 = t\n\t}\n\n\tp.idx1 = idx1\n\tp.idx2 = idx2\n\tp.cost_diff = 0.5 * clusterCostDiff(uint(cluster_size[idx1]), uint(cluster_size[idx2]))\n\tp.cost_diff -= out[idx1].bit_cost_\n\tp.cost_diff -= out[idx2].bit_cost_\n\n\tif out[idx1].total_count_ == 0 {\n\t\tp.cost_combo = out[idx2].bit_cost_\n\t\tis_good_pair = true\n\t} else if out[idx2].total_count_ == 0 {\n\t\tp.cost_combo = out[idx1].bit_cost_\n\t\tis_good_pair = true\n\t} else {\n\t\tvar threshold float64\n\t\tif *num_pairs == 0 {\n\t\t\tthreshold = 1e99\n\t\t} else {\n\t\t\tthreshold = brotli_max_double(0.0, pairs[0].cost_diff)\n\t\t}\n\t\tvar combo histogramLiteral = out[idx1]\n\t\tvar cost_combo float64\n\t\thistogramAddHistogramLiteral(&combo, &out[idx2])\n\t\tcost_combo = populationCostLiteral(&combo)\n\t\tif cost_combo < threshold-p.cost_diff {\n\t\t\tp.cost_combo = cost_combo\n\t\t\tis_good_pair = true\n\t\t}\n\t}\n\n\tif is_good_pair {\n\t\tp.cost_diff += p.cost_combo\n\t\tif *num_pairs > 0 && histogramPairIsLess(&pairs[0], &p) {\n\t\t\t/* Replace the top of the queue if needed. */\n\t\t\tif *num_pairs < max_num_pairs {\n\t\t\t\tpairs[*num_pairs] = pairs[0]\n\t\t\t\t(*num_pairs)++\n\t\t\t}\n\n\t\t\tpairs[0] = p\n\t\t} else if *num_pairs < max_num_pairs {\n\t\t\tpairs[*num_pairs] = p\n\t\t\t(*num_pairs)++\n\t\t}\n\t}\n}\n\nfunc histogramCombineLiteral(out []histogramLiteral, cluster_size []uint32, symbols []uint32, clusters []uint32, pairs []histogramPair, num_clusters uint, symbols_size uint, max_clusters uint, max_num_pairs uint) uint {\n\tvar cost_diff_threshold float64 = 0.0\n\tvar min_cluster_size uint = 1\n\tvar num_pairs uint = 0\n\t{\n\t\t/* We maintain a vector of histogram pairs, with the property that the pair\n\t\t   with the maximum bit cost reduction is the first. */\n\t\tvar idx1 uint\n\t\tfor idx1 = 0; idx1 < num_clusters; idx1++ {\n\t\t\tvar idx2 uint\n\t\t\tfor idx2 = idx1 + 1; idx2 < num_clusters; idx2++ {\n\t\t\t\tcompareAndPushToQueueLiteral(out, cluster_size, clusters[idx1], clusters[idx2], max_num_pairs, pairs[0:], &num_pairs)\n\t\t\t}\n\t\t}\n\t}\n\n\tfor num_clusters > min_cluster_size {\n\t\tvar best_idx1 uint32\n\t\tvar best_idx2 uint32\n\t\tvar i uint\n\t\tif pairs[0].cost_diff >= cost_diff_threshold {\n\t\t\tcost_diff_threshold = 1e99\n\t\t\tmin_cluster_size = max_clusters\n\t\t\tcontinue\n\t\t}\n\n\t\t/* Take the best pair from the top of heap. */\n\t\tbest_idx1 = pairs[0].idx1\n\n\t\tbest_idx2 = pairs[0].idx2\n\t\thistogramAddHistogramLiteral(&out[best_idx1], &out[best_idx2])\n\t\tout[best_idx1].bit_cost_ = pairs[0].cost_combo\n\t\tcluster_size[best_idx1] += cluster_size[best_idx2]\n\t\tfor i = 0; i < symbols_size; i++ {\n\t\t\tif symbols[i] == best_idx2 {\n\t\t\t\tsymbols[i] = best_idx1\n\t\t\t}\n\t\t}\n\n\t\tfor i = 0; i < num_clusters; i++ {\n\t\t\tif clusters[i] == best_idx2 {\n\t\t\t\tcopy(clusters[i:], clusters[i+1:][:num_clusters-i-1])\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tnum_clusters--\n\t\t{\n\t\t\t/* Remove pairs intersecting the just combined best pair. */\n\t\t\tvar copy_to_idx uint = 0\n\t\t\tfor i = 0; i < num_pairs; i++ {\n\t\t\t\tvar p *histogramPair = &pairs[i]\n\t\t\t\tif p.idx1 == best_idx1 || p.idx2 == best_idx1 || p.idx1 == best_idx2 || p.idx2 == best_idx2 {\n\t\t\t\t\t/* Remove invalid pair from the queue. */\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif histogramPairIsLess(&pairs[0], p) {\n\t\t\t\t\t/* Replace the top of the queue if needed. */\n\t\t\t\t\tvar front histogramPair = pairs[0]\n\t\t\t\t\tpairs[0] = *p\n\t\t\t\t\tpairs[copy_to_idx] = front\n\t\t\t\t} else {\n\t\t\t\t\tpairs[copy_to_idx] = *p\n\t\t\t\t}\n\n\t\t\t\tcopy_to_idx++\n\t\t\t}\n\n\t\t\tnum_pairs = copy_to_idx\n\t\t}\n\n\t\t/* Push new pairs formed with the combined histogram to the heap. */\n\t\tfor i = 0; i < num_clusters; i++ {\n\t\t\tcompareAndPushToQueueLiteral(out, cluster_size, best_idx1, clusters[i], max_num_pairs, pairs[0:], &num_pairs)\n\t\t}\n\t}\n\n\treturn num_clusters\n}\n\n/* What is the bit cost of moving histogram from cur_symbol to candidate. */\nfunc histogramBitCostDistanceLiteral(histogram *histogramLiteral, candidate *histogramLiteral) float64 {\n\tif histogram.total_count_ == 0 {\n\t\treturn 0.0\n\t} else {\n\t\tvar tmp histogramLiteral = *histogram\n\t\thistogramAddHistogramLiteral(&tmp, candidate)\n\t\treturn populationCostLiteral(&tmp) - candidate.bit_cost_\n\t}\n}\n\n/* Find the best 'out' histogram for each of the 'in' histograms.\n   When called, clusters[0..num_clusters) contains the unique values from\n   symbols[0..in_size), but this property is not preserved in this function.\n   Note: we assume that out[]->bit_cost_ is already up-to-date. */\nfunc histogramRemapLiteral(in []histogramLiteral, in_size uint, clusters []uint32, num_clusters uint, out []histogramLiteral, symbols []uint32) {\n\tvar i uint\n\tfor i = 0; i < in_size; i++ {\n\t\tvar best_out uint32\n\t\tif i == 0 {\n\t\t\tbest_out = symbols[0]\n\t\t} else {\n\t\t\tbest_out = symbols[i-1]\n\t\t}\n\t\tvar best_bits float64 = histogramBitCostDistanceLiteral(&in[i], &out[best_out])\n\t\tvar j uint\n\t\tfor j = 0; j < num_clusters; j++ {\n\t\t\tvar cur_bits float64 = histogramBitCostDistanceLiteral(&in[i], &out[clusters[j]])\n\t\t\tif cur_bits < best_bits {\n\t\t\t\tbest_bits = cur_bits\n\t\t\t\tbest_out = clusters[j]\n\t\t\t}\n\t\t}\n\n\t\tsymbols[i] = best_out\n\t}\n\n\t/* Recompute each out based on raw and symbols. */\n\tfor i = 0; i < num_clusters; i++ {\n\t\thistogramClearLiteral(&out[clusters[i]])\n\t}\n\n\tfor i = 0; i < in_size; i++ {\n\t\thistogramAddHistogramLiteral(&out[symbols[i]], &in[i])\n\t}\n}\n\n/* Reorders elements of the out[0..length) array and changes values in\n   symbols[0..length) array in the following way:\n     * when called, symbols[] contains indexes into out[], and has N unique\n       values (possibly N < length)\n     * on return, symbols'[i] = f(symbols[i]) and\n                  out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,\n       where f is a bijection between the range of symbols[] and [0..N), and\n       the first occurrences of values in symbols'[i] come in consecutive\n       increasing order.\n   Returns N, the number of unique values in symbols[]. */\n\nvar histogramReindexLiteral_kInvalidIndex uint32 = math.MaxUint32\n\nfunc histogramReindexLiteral(out []histogramLiteral, symbols []uint32, length uint) uint {\n\tvar new_index []uint32 = make([]uint32, length)\n\tvar next_index uint32\n\tvar tmp []histogramLiteral\n\tvar i uint\n\tfor i = 0; i < length; i++ {\n\t\tnew_index[i] = histogramReindexLiteral_kInvalidIndex\n\t}\n\n\tnext_index = 0\n\tfor i = 0; i < length; i++ {\n\t\tif new_index[symbols[i]] == histogramReindexLiteral_kInvalidIndex {\n\t\t\tnew_index[symbols[i]] = next_index\n\t\t\tnext_index++\n\t\t}\n\t}\n\n\t/* TODO: by using idea of \"cycle-sort\" we can avoid allocation of\n\t   tmp and reduce the number of copying by the factor of 2. */\n\ttmp = make([]histogramLiteral, next_index)\n\n\tnext_index = 0\n\tfor i = 0; i < length; i++ {\n\t\tif new_index[symbols[i]] == next_index {\n\t\t\ttmp[next_index] = out[symbols[i]]\n\t\t\tnext_index++\n\t\t}\n\n\t\tsymbols[i] = new_index[symbols[i]]\n\t}\n\n\tnew_index = nil\n\tfor i = 0; uint32(i) < next_index; i++ {\n\t\tout[i] = tmp[i]\n\t}\n\n\ttmp = nil\n\treturn uint(next_index)\n}\n\nfunc clusterHistogramsLiteral(in []histogramLiteral, in_size uint, max_histograms uint, out []histogramLiteral, out_size *uint, histogram_symbols []uint32) {\n\tvar cluster_size []uint32 = make([]uint32, in_size)\n\tvar clusters []uint32 = make([]uint32, in_size)\n\tvar num_clusters uint = 0\n\tvar max_input_histograms uint = 64\n\tvar pairs_capacity uint = max_input_histograms * max_input_histograms / 2\n\tvar pairs []histogramPair = make([]histogramPair, (pairs_capacity + 1))\n\tvar i uint\n\n\t/* For the first pass of clustering, we allow all pairs. */\n\tfor i = 0; i < in_size; i++ {\n\t\tcluster_size[i] = 1\n\t}\n\n\tfor i = 0; i < in_size; i++ {\n\t\tout[i] = in[i]\n\t\tout[i].bit_cost_ = populationCostLiteral(&in[i])\n\t\thistogram_symbols[i] = uint32(i)\n\t}\n\n\tfor i = 0; i < in_size; i += max_input_histograms {\n\t\tvar num_to_combine uint = brotli_min_size_t(in_size-i, max_input_histograms)\n\t\tvar num_new_clusters uint\n\t\tvar j uint\n\t\tfor j = 0; j < num_to_combine; j++ {\n\t\t\tclusters[num_clusters+j] = uint32(i + j)\n\t\t}\n\n\t\tnum_new_clusters = histogramCombineLiteral(out, cluster_size, histogram_symbols[i:], clusters[num_clusters:], pairs, num_to_combine, num_to_combine, max_histograms, pairs_capacity)\n\t\tnum_clusters += num_new_clusters\n\t}\n\t{\n\t\t/* For the second pass, we limit the total number of histogram pairs.\n\t\t   After this limit is reached, we only keep searching for the best pair. */\n\t\tvar max_num_pairs uint = brotli_min_size_t(64*num_clusters, (num_clusters/2)*num_clusters)\n\t\tif pairs_capacity < (max_num_pairs + 1) {\n\t\t\tvar _new_size uint\n\t\t\tif pairs_capacity == 0 {\n\t\t\t\t_new_size = max_num_pairs + 1\n\t\t\t} else {\n\t\t\t\t_new_size = pairs_capacity\n\t\t\t}\n\t\t\tvar new_array []histogramPair\n\t\t\tfor _new_size < (max_num_pairs + 1) {\n\t\t\t\t_new_size *= 2\n\t\t\t}\n\t\t\tnew_array = make([]histogramPair, _new_size)\n\t\t\tif pairs_capacity != 0 {\n\t\t\t\tcopy(new_array, pairs[:pairs_capacity])\n\t\t\t}\n\n\t\t\tpairs = new_array\n\t\t\tpairs_capacity = _new_size\n\t\t}\n\n\t\t/* Collapse similar histograms. */\n\t\tnum_clusters = histogramCombineLiteral(out, cluster_size, histogram_symbols, clusters, pairs, num_clusters, in_size, max_histograms, max_num_pairs)\n\t}\n\n\tpairs = nil\n\tcluster_size = nil\n\n\t/* Find the optimal map from original histograms to the final ones. */\n\thistogramRemapLiteral(in, in_size, clusters, num_clusters, out, histogram_symbols)\n\n\tclusters = nil\n\n\t/* Convert the context map to a canonical form. */\n\t*out_size = histogramReindexLiteral(out, histogram_symbols, in_size)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/command.go",
    "content": "package brotli\n\nvar kInsBase = []uint32{\n\t0,\n\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t8,\n\t10,\n\t14,\n\t18,\n\t26,\n\t34,\n\t50,\n\t66,\n\t98,\n\t130,\n\t194,\n\t322,\n\t578,\n\t1090,\n\t2114,\n\t6210,\n\t22594,\n}\n\nvar kInsExtra = []uint32{\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t2,\n\t2,\n\t3,\n\t3,\n\t4,\n\t4,\n\t5,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t12,\n\t14,\n\t24,\n}\n\nvar kCopyBase = []uint32{\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t12,\n\t14,\n\t18,\n\t22,\n\t30,\n\t38,\n\t54,\n\t70,\n\t102,\n\t134,\n\t198,\n\t326,\n\t582,\n\t1094,\n\t2118,\n}\n\nvar kCopyExtra = []uint32{\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t2,\n\t2,\n\t3,\n\t3,\n\t4,\n\t4,\n\t5,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t24,\n}\n\nfunc getInsertLengthCode(insertlen uint) uint16 {\n\tif insertlen < 6 {\n\t\treturn uint16(insertlen)\n\t} else if insertlen < 130 {\n\t\tvar nbits uint32 = log2FloorNonZero(insertlen-2) - 1\n\t\treturn uint16((nbits << 1) + uint32((insertlen-2)>>nbits) + 2)\n\t} else if insertlen < 2114 {\n\t\treturn uint16(log2FloorNonZero(insertlen-66) + 10)\n\t} else if insertlen < 6210 {\n\t\treturn 21\n\t} else if insertlen < 22594 {\n\t\treturn 22\n\t} else {\n\t\treturn 23\n\t}\n}\n\nfunc getCopyLengthCode(copylen uint) uint16 {\n\tif copylen < 10 {\n\t\treturn uint16(copylen - 2)\n\t} else if copylen < 134 {\n\t\tvar nbits uint32 = log2FloorNonZero(copylen-6) - 1\n\t\treturn uint16((nbits << 1) + uint32((copylen-6)>>nbits) + 4)\n\t} else if copylen < 2118 {\n\t\treturn uint16(log2FloorNonZero(copylen-70) + 12)\n\t} else {\n\t\treturn 23\n\t}\n}\n\nfunc combineLengthCodes(inscode uint16, copycode uint16, use_last_distance bool) uint16 {\n\tvar bits64 uint16 = uint16(copycode&0x7 | (inscode&0x7)<<3)\n\tif use_last_distance && inscode < 8 && copycode < 16 {\n\t\tif copycode < 8 {\n\t\t\treturn bits64\n\t\t} else {\n\t\t\treturn bits64 | 64\n\t\t}\n\t} else {\n\t\t/* Specification: 5 Encoding of ... (last table) */\n\t\t/* offset = 2 * index, where index is in range [0..8] */\n\t\tvar offset uint32 = 2 * ((uint32(copycode) >> 3) + 3*(uint32(inscode)>>3))\n\n\t\t/* All values in specification are K * 64,\n\t\t   where   K = [2, 3, 6, 4, 5, 8, 7, 9, 10],\n\t\t       i + 1 = [1, 2, 3, 4, 5, 6, 7, 8,  9],\n\t\t   K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1,  2] = D.\n\t\t   All values in D require only 2 bits to encode.\n\t\t   Magic constant is shifted 6 bits left, to avoid final multiplication. */\n\t\toffset = (offset << 5) + 0x40 + ((0x520D40 >> offset) & 0xC0)\n\n\t\treturn uint16(offset | uint32(bits64))\n\t}\n}\n\nfunc getLengthCode(insertlen uint, copylen uint, use_last_distance bool, code *uint16) {\n\tvar inscode uint16 = getInsertLengthCode(insertlen)\n\tvar copycode uint16 = getCopyLengthCode(copylen)\n\t*code = combineLengthCodes(inscode, copycode, use_last_distance)\n}\n\nfunc getInsertBase(inscode uint16) uint32 {\n\treturn kInsBase[inscode]\n}\n\nfunc getInsertExtra(inscode uint16) uint32 {\n\treturn kInsExtra[inscode]\n}\n\nfunc getCopyBase(copycode uint16) uint32 {\n\treturn kCopyBase[copycode]\n}\n\nfunc getCopyExtra(copycode uint16) uint32 {\n\treturn kCopyExtra[copycode]\n}\n\ntype command struct {\n\tinsert_len_  uint32\n\tcopy_len_    uint32\n\tdist_extra_  uint32\n\tcmd_prefix_  uint16\n\tdist_prefix_ uint16\n}\n\n/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */\nfunc makeCommand(dist *distanceParams, insertlen uint, copylen uint, copylen_code_delta int, distance_code uint) (cmd command) {\n\t/* Don't rely on signed int representation, use honest casts. */\n\tvar delta uint32 = uint32(byte(int8(copylen_code_delta)))\n\tcmd.insert_len_ = uint32(insertlen)\n\tcmd.copy_len_ = uint32(uint32(copylen) | delta<<25)\n\n\t/* The distance prefix and extra bits are stored in this Command as if\n\t   npostfix and ndirect were 0, they are only recomputed later after the\n\t   clustering if needed. */\n\tprefixEncodeCopyDistance(distance_code, uint(dist.num_direct_distance_codes), uint(dist.distance_postfix_bits), &cmd.dist_prefix_, &cmd.dist_extra_)\n\tgetLengthCode(insertlen, uint(int(copylen)+copylen_code_delta), (cmd.dist_prefix_&0x3FF == 0), &cmd.cmd_prefix_)\n\n\treturn cmd\n}\n\nfunc makeInsertCommand(insertlen uint) (cmd command) {\n\tcmd.insert_len_ = uint32(insertlen)\n\tcmd.copy_len_ = 4 << 25\n\tcmd.dist_extra_ = 0\n\tcmd.dist_prefix_ = numDistanceShortCodes\n\tgetLengthCode(insertlen, 4, false, &cmd.cmd_prefix_)\n\treturn cmd\n}\n\nfunc commandRestoreDistanceCode(self *command, dist *distanceParams) uint32 {\n\tif uint32(self.dist_prefix_&0x3FF) < numDistanceShortCodes+dist.num_direct_distance_codes {\n\t\treturn uint32(self.dist_prefix_) & 0x3FF\n\t} else {\n\t\tvar dcode uint32 = uint32(self.dist_prefix_) & 0x3FF\n\t\tvar nbits uint32 = uint32(self.dist_prefix_) >> 10\n\t\tvar extra uint32 = self.dist_extra_\n\t\tvar postfix_mask uint32 = (1 << dist.distance_postfix_bits) - 1\n\t\tvar hcode uint32 = (dcode - dist.num_direct_distance_codes - numDistanceShortCodes) >> dist.distance_postfix_bits\n\t\tvar lcode uint32 = (dcode - dist.num_direct_distance_codes - numDistanceShortCodes) & postfix_mask\n\t\tvar offset uint32 = ((2 + (hcode & 1)) << nbits) - 4\n\t\treturn ((offset + extra) << dist.distance_postfix_bits) + lcode + dist.num_direct_distance_codes + numDistanceShortCodes\n\t}\n}\n\nfunc commandDistanceContext(self *command) uint32 {\n\tvar r uint32 = uint32(self.cmd_prefix_) >> 6\n\tvar c uint32 = uint32(self.cmd_prefix_) & 7\n\tif (r == 0 || r == 2 || r == 4 || r == 7) && (c <= 2) {\n\t\treturn c\n\t}\n\n\treturn 3\n}\n\nfunc commandCopyLen(self *command) uint32 {\n\treturn self.copy_len_ & 0x1FFFFFF\n}\n\nfunc commandCopyLenCode(self *command) uint32 {\n\tvar modifier uint32 = self.copy_len_ >> 25\n\tvar delta int32 = int32(int8(byte(modifier | (modifier&0x40)<<1)))\n\treturn uint32(int32(self.copy_len_&0x1FFFFFF) + delta)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/compress_fragment.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2015 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Function for fast encoding of an input fragment, independently from the input\n   history. This function uses one-pass processing: when we find a backward\n   match, we immediately emit the corresponding command and literal codes to\n   the bit stream.\n\n   Adapted from the CompressFragment() function in\n   https://github.com/google/snappy/blob/master/snappy.cc */\n\nconst maxDistance_compress_fragment = 262128\n\nfunc hash5(p []byte, shift uint) uint32 {\n\tvar h uint64 = (binary.LittleEndian.Uint64(p) << 24) * uint64(kHashMul32)\n\treturn uint32(h >> shift)\n}\n\nfunc hashBytesAtOffset5(v uint64, offset int, shift uint) uint32 {\n\tassert(offset >= 0)\n\tassert(offset <= 3)\n\t{\n\t\tvar h uint64 = ((v >> uint(8*offset)) << 24) * uint64(kHashMul32)\n\t\treturn uint32(h >> shift)\n\t}\n}\n\nfunc isMatch5(p1 []byte, p2 []byte) bool {\n\treturn binary.LittleEndian.Uint32(p1) == binary.LittleEndian.Uint32(p2) &&\n\t\tp1[4] == p2[4]\n}\n\n/* Builds a literal prefix code into \"depths\" and \"bits\" based on the statistics\n   of the \"input\" string and stores it into the bit stream.\n   Note that the prefix code here is built from the pre-LZ77 input, therefore\n   we can only approximate the statistics of the actual literal stream.\n   Moreover, for long inputs we build a histogram from a sample of the input\n   and thus have to assign a non-zero depth for each literal.\n   Returns estimated compression ratio millibytes/char for encoding given input\n   with generated code. */\nfunc buildAndStoreLiteralPrefixCode(input []byte, input_size uint, depths []byte, bits []uint16, storage_ix *uint, storage []byte) uint {\n\tvar histogram = [256]uint32{0}\n\tvar histogram_total uint\n\tvar i uint\n\tif input_size < 1<<15 {\n\t\tfor i = 0; i < input_size; i++ {\n\t\t\thistogram[input[i]]++\n\t\t}\n\n\t\thistogram_total = input_size\n\t\tfor i = 0; i < 256; i++ {\n\t\t\t/* We weigh the first 11 samples with weight 3 to account for the\n\t\t\t   balancing effect of the LZ77 phase on the histogram. */\n\t\t\tvar adjust uint32 = 2 * brotli_min_uint32_t(histogram[i], 11)\n\t\t\thistogram[i] += adjust\n\t\t\thistogram_total += uint(adjust)\n\t\t}\n\t} else {\n\t\tconst kSampleRate uint = 29\n\t\tfor i = 0; i < input_size; i += kSampleRate {\n\t\t\thistogram[input[i]]++\n\t\t}\n\n\t\thistogram_total = (input_size + kSampleRate - 1) / kSampleRate\n\t\tfor i = 0; i < 256; i++ {\n\t\t\t/* We add 1 to each population count to avoid 0 bit depths (since this is\n\t\t\t   only a sample and we don't know if the symbol appears or not), and we\n\t\t\t   weigh the first 11 samples with weight 3 to account for the balancing\n\t\t\t   effect of the LZ77 phase on the histogram (more frequent symbols are\n\t\t\t   more likely to be in backward references instead as literals). */\n\t\t\tvar adjust uint32 = 1 + 2*brotli_min_uint32_t(histogram[i], 11)\n\t\t\thistogram[i] += adjust\n\t\t\thistogram_total += uint(adjust)\n\t\t}\n\t}\n\n\tbuildAndStoreHuffmanTreeFast(histogram[:], histogram_total, /* max_bits = */\n\t\t8, depths, bits, storage_ix, storage)\n\t{\n\t\tvar literal_ratio uint = 0\n\t\tfor i = 0; i < 256; i++ {\n\t\t\tif histogram[i] != 0 {\n\t\t\t\tliteral_ratio += uint(histogram[i] * uint32(depths[i]))\n\t\t\t}\n\t\t}\n\n\t\t/* Estimated encoding ratio, millibytes per symbol. */\n\t\treturn (literal_ratio * 125) / histogram_total\n\t}\n}\n\n/* Builds a command and distance prefix code (each 64 symbols) into \"depth\" and\n   \"bits\" based on \"histogram\" and stores it into the bit stream. */\nfunc buildAndStoreCommandPrefixCode1(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {\n\tvar tree [129]huffmanTree\n\tvar cmd_depth = [numCommandSymbols]byte{0}\n\t/* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */\n\n\tvar cmd_bits [64]uint16\n\n\tcreateHuffmanTree(histogram, 64, 15, tree[:], depth)\n\tcreateHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:])\n\n\t/* We have to jump through a few hoops here in order to compute\n\t   the command bits because the symbols are in a different order than in\n\t   the full alphabet. This looks complicated, but having the symbols\n\t   in this order in the command bits saves a few branches in the Emit*\n\t   functions. */\n\tcopy(cmd_depth[:], depth[:24])\n\n\tcopy(cmd_depth[24:][:], depth[40:][:8])\n\tcopy(cmd_depth[32:][:], depth[24:][:8])\n\tcopy(cmd_depth[40:][:], depth[48:][:8])\n\tcopy(cmd_depth[48:][:], depth[32:][:8])\n\tcopy(cmd_depth[56:][:], depth[56:][:8])\n\tconvertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:])\n\tcopy(bits, cmd_bits[:24])\n\tcopy(bits[24:], cmd_bits[32:][:8])\n\tcopy(bits[32:], cmd_bits[48:][:8])\n\tcopy(bits[40:], cmd_bits[24:][:8])\n\tcopy(bits[48:], cmd_bits[40:][:8])\n\tcopy(bits[56:], cmd_bits[56:][:8])\n\tconvertBitDepthsToSymbols(depth[64:], 64, bits[64:])\n\t{\n\t\t/* Create the bit length array for the full command alphabet. */\n\t\tvar i uint\n\t\tfor i := 0; i < int(64); i++ {\n\t\t\tcmd_depth[i] = 0\n\t\t} /* only 64 first values were used */\n\t\tcopy(cmd_depth[:], depth[:8])\n\t\tcopy(cmd_depth[64:][:], depth[8:][:8])\n\t\tcopy(cmd_depth[128:][:], depth[16:][:8])\n\t\tcopy(cmd_depth[192:][:], depth[24:][:8])\n\t\tcopy(cmd_depth[384:][:], depth[32:][:8])\n\t\tfor i = 0; i < 8; i++ {\n\t\t\tcmd_depth[128+8*i] = depth[40+i]\n\t\t\tcmd_depth[256+8*i] = depth[48+i]\n\t\t\tcmd_depth[448+8*i] = depth[56+i]\n\t\t}\n\n\t\tstoreHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage)\n\t}\n\n\tstoreHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage)\n}\n\n/* REQUIRES: insertlen < 6210 */\nfunc emitInsertLen1(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {\n\tif insertlen < 6 {\n\t\tvar code uint = insertlen + 40\n\t\twriteBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)\n\t\thisto[code]++\n\t} else if insertlen < 130 {\n\t\tvar tail uint = insertlen - 2\n\t\tvar nbits uint32 = log2FloorNonZero(tail) - 1\n\t\tvar prefix uint = tail >> nbits\n\t\tvar inscode uint = uint((nbits << 1) + uint32(prefix) + 42)\n\t\twriteBits(uint(depth[inscode]), uint64(bits[inscode]), storage_ix, storage)\n\t\twriteBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage)\n\t\thisto[inscode]++\n\t} else if insertlen < 2114 {\n\t\tvar tail uint = insertlen - 66\n\t\tvar nbits uint32 = log2FloorNonZero(tail)\n\t\tvar code uint = uint(nbits + 50)\n\t\twriteBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)\n\t\twriteBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage)\n\t\thisto[code]++\n\t} else {\n\t\twriteBits(uint(depth[61]), uint64(bits[61]), storage_ix, storage)\n\t\twriteBits(12, uint64(insertlen)-2114, storage_ix, storage)\n\t\thisto[61]++\n\t}\n}\n\nfunc emitLongInsertLen(insertlen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {\n\tif insertlen < 22594 {\n\t\twriteBits(uint(depth[62]), uint64(bits[62]), storage_ix, storage)\n\t\twriteBits(14, uint64(insertlen)-6210, storage_ix, storage)\n\t\thisto[62]++\n\t} else {\n\t\twriteBits(uint(depth[63]), uint64(bits[63]), storage_ix, storage)\n\t\twriteBits(24, uint64(insertlen)-22594, storage_ix, storage)\n\t\thisto[63]++\n\t}\n}\n\nfunc emitCopyLen1(copylen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {\n\tif copylen < 10 {\n\t\twriteBits(uint(depth[copylen+14]), uint64(bits[copylen+14]), storage_ix, storage)\n\t\thisto[copylen+14]++\n\t} else if copylen < 134 {\n\t\tvar tail uint = copylen - 6\n\t\tvar nbits uint32 = log2FloorNonZero(tail) - 1\n\t\tvar prefix uint = tail >> nbits\n\t\tvar code uint = uint((nbits << 1) + uint32(prefix) + 20)\n\t\twriteBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)\n\t\twriteBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage)\n\t\thisto[code]++\n\t} else if copylen < 2118 {\n\t\tvar tail uint = copylen - 70\n\t\tvar nbits uint32 = log2FloorNonZero(tail)\n\t\tvar code uint = uint(nbits + 28)\n\t\twriteBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)\n\t\twriteBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage)\n\t\thisto[code]++\n\t} else {\n\t\twriteBits(uint(depth[39]), uint64(bits[39]), storage_ix, storage)\n\t\twriteBits(24, uint64(copylen)-2118, storage_ix, storage)\n\t\thisto[39]++\n\t}\n}\n\nfunc emitCopyLenLastDistance1(copylen uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {\n\tif copylen < 12 {\n\t\twriteBits(uint(depth[copylen-4]), uint64(bits[copylen-4]), storage_ix, storage)\n\t\thisto[copylen-4]++\n\t} else if copylen < 72 {\n\t\tvar tail uint = copylen - 8\n\t\tvar nbits uint32 = log2FloorNonZero(tail) - 1\n\t\tvar prefix uint = tail >> nbits\n\t\tvar code uint = uint((nbits << 1) + uint32(prefix) + 4)\n\t\twriteBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)\n\t\twriteBits(uint(nbits), uint64(tail)-(uint64(prefix)<<nbits), storage_ix, storage)\n\t\thisto[code]++\n\t} else if copylen < 136 {\n\t\tvar tail uint = copylen - 8\n\t\tvar code uint = (tail >> 5) + 30\n\t\twriteBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)\n\t\twriteBits(5, uint64(tail)&31, storage_ix, storage)\n\t\twriteBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)\n\t\thisto[code]++\n\t\thisto[64]++\n\t} else if copylen < 2120 {\n\t\tvar tail uint = copylen - 72\n\t\tvar nbits uint32 = log2FloorNonZero(tail)\n\t\tvar code uint = uint(nbits + 28)\n\t\twriteBits(uint(depth[code]), uint64(bits[code]), storage_ix, storage)\n\t\twriteBits(uint(nbits), uint64(tail)-(uint64(uint(1))<<nbits), storage_ix, storage)\n\t\twriteBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)\n\t\thisto[code]++\n\t\thisto[64]++\n\t} else {\n\t\twriteBits(uint(depth[39]), uint64(bits[39]), storage_ix, storage)\n\t\twriteBits(24, uint64(copylen)-2120, storage_ix, storage)\n\t\twriteBits(uint(depth[64]), uint64(bits[64]), storage_ix, storage)\n\t\thisto[39]++\n\t\thisto[64]++\n\t}\n}\n\nfunc emitDistance1(distance uint, depth []byte, bits []uint16, histo []uint32, storage_ix *uint, storage []byte) {\n\tvar d uint = distance + 3\n\tvar nbits uint32 = log2FloorNonZero(d) - 1\n\tvar prefix uint = (d >> nbits) & 1\n\tvar offset uint = (2 + prefix) << nbits\n\tvar distcode uint = uint(2*(nbits-1) + uint32(prefix) + 80)\n\twriteBits(uint(depth[distcode]), uint64(bits[distcode]), storage_ix, storage)\n\twriteBits(uint(nbits), uint64(d)-uint64(offset), storage_ix, storage)\n\thisto[distcode]++\n}\n\nfunc emitLiterals(input []byte, len uint, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {\n\tvar j uint\n\tfor j = 0; j < len; j++ {\n\t\tvar lit byte = input[j]\n\t\twriteBits(uint(depth[lit]), uint64(bits[lit]), storage_ix, storage)\n\t}\n}\n\n/* REQUIRES: len <= 1 << 24. */\nfunc storeMetaBlockHeader1(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) {\n\tvar nibbles uint = 6\n\n\t/* ISLAST */\n\twriteBits(1, 0, storage_ix, storage)\n\n\tif len <= 1<<16 {\n\t\tnibbles = 4\n\t} else if len <= 1<<20 {\n\t\tnibbles = 5\n\t}\n\n\twriteBits(2, uint64(nibbles)-4, storage_ix, storage)\n\twriteBits(nibbles*4, uint64(len)-1, storage_ix, storage)\n\n\t/* ISUNCOMPRESSED */\n\twriteSingleBit(is_uncompressed, storage_ix, storage)\n}\n\nfunc updateBits(n_bits uint, bits uint32, pos uint, array []byte) {\n\tfor n_bits > 0 {\n\t\tvar byte_pos uint = pos >> 3\n\t\tvar n_unchanged_bits uint = pos & 7\n\t\tvar n_changed_bits uint = brotli_min_size_t(n_bits, 8-n_unchanged_bits)\n\t\tvar total_bits uint = n_unchanged_bits + n_changed_bits\n\t\tvar mask uint32 = (^((1 << total_bits) - 1)) | ((1 << n_unchanged_bits) - 1)\n\t\tvar unchanged_bits uint32 = uint32(array[byte_pos]) & mask\n\t\tvar changed_bits uint32 = bits & ((1 << n_changed_bits) - 1)\n\t\tarray[byte_pos] = byte(changed_bits<<n_unchanged_bits | unchanged_bits)\n\t\tn_bits -= n_changed_bits\n\t\tbits >>= n_changed_bits\n\t\tpos += n_changed_bits\n\t}\n}\n\nfunc rewindBitPosition1(new_storage_ix uint, storage_ix *uint, storage []byte) {\n\tvar bitpos uint = new_storage_ix & 7\n\tvar mask uint = (1 << bitpos) - 1\n\tstorage[new_storage_ix>>3] &= byte(mask)\n\t*storage_ix = new_storage_ix\n}\n\nvar shouldMergeBlock_kSampleRate uint = 43\n\nfunc shouldMergeBlock(data []byte, len uint, depths []byte) bool {\n\tvar histo = [256]uint{0}\n\tvar i uint\n\tfor i = 0; i < len; i += shouldMergeBlock_kSampleRate {\n\t\thisto[data[i]]++\n\t}\n\t{\n\t\tvar total uint = (len + shouldMergeBlock_kSampleRate - 1) / shouldMergeBlock_kSampleRate\n\t\tvar r float64 = (fastLog2(total)+0.5)*float64(total) + 200\n\t\tfor i = 0; i < 256; i++ {\n\t\t\tr -= float64(histo[i]) * (float64(depths[i]) + fastLog2(histo[i]))\n\t\t}\n\n\t\treturn r >= 0.0\n\t}\n}\n\nfunc shouldUseUncompressedMode(metablock_start []byte, next_emit []byte, insertlen uint, literal_ratio uint) bool {\n\tvar compressed uint = uint(-cap(next_emit) + cap(metablock_start))\n\tif compressed*50 > insertlen {\n\t\treturn false\n\t} else {\n\t\treturn literal_ratio > 980\n\t}\n}\n\nfunc emitUncompressedMetaBlock1(begin []byte, end []byte, storage_ix_start uint, storage_ix *uint, storage []byte) {\n\tvar len uint = uint(-cap(end) + cap(begin))\n\trewindBitPosition1(storage_ix_start, storage_ix, storage)\n\tstoreMetaBlockHeader1(uint(len), true, storage_ix, storage)\n\t*storage_ix = (*storage_ix + 7) &^ 7\n\tcopy(storage[*storage_ix>>3:], begin[:len])\n\t*storage_ix += uint(len << 3)\n\tstorage[*storage_ix>>3] = 0\n}\n\nvar kCmdHistoSeed = [128]uint32{\n\t0,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t0,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t0,\n\t0,\n\t0,\n\t0,\n}\n\nvar compressFragmentFastImpl_kFirstBlockSize uint = 3 << 15\nvar compressFragmentFastImpl_kMergeBlockSize uint = 1 << 16\n\nfunc compressFragmentFastImpl(in []byte, input_size uint, is_last bool, table []int, table_bits uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {\n\tvar cmd_histo [128]uint32\n\tvar ip_end int\n\tvar next_emit int = 0\n\tvar base_ip int = 0\n\tvar input int = 0\n\tconst kInputMarginBytes uint = windowGap\n\tconst kMinMatchLen uint = 5\n\tvar metablock_start int = input\n\tvar block_size uint = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)\n\tvar total_block_size uint = block_size\n\tvar mlen_storage_ix uint = *storage_ix + 3\n\tvar lit_depth [256]byte\n\tvar lit_bits [256]uint16\n\tvar literal_ratio uint\n\tvar ip int\n\tvar last_distance int\n\tvar shift uint = 64 - table_bits\n\n\t/* \"next_emit\" is a pointer to the first byte that is not covered by a\n\t   previous copy. Bytes between \"next_emit\" and the start of the next copy or\n\t   the end of the input will be emitted as literal bytes. */\n\n\t/* Save the start of the first block for position and distance computations.\n\t */\n\n\t/* Save the bit position of the MLEN field of the meta-block header, so that\n\t   we can update it later if we decide to extend this meta-block. */\n\tstoreMetaBlockHeader1(block_size, false, storage_ix, storage)\n\n\t/* No block splits, no contexts. */\n\twriteBits(13, 0, storage_ix, storage)\n\n\tliteral_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)\n\t{\n\t\t/* Store the pre-compressed command and distance prefix codes. */\n\t\tvar i uint\n\t\tfor i = 0; i+7 < *cmd_code_numbits; i += 8 {\n\t\t\twriteBits(8, uint64(cmd_code[i>>3]), storage_ix, storage)\n\t\t}\n\t}\n\n\twriteBits(*cmd_code_numbits&7, uint64(cmd_code[*cmd_code_numbits>>3]), storage_ix, storage)\n\n\t/* Initialize the command and distance histograms. We will gather\n\t   statistics of command and distance codes during the processing\n\t   of this block and use it to update the command and distance\n\t   prefix codes for the next block. */\nemit_commands:\n\tcopy(cmd_histo[:], kCmdHistoSeed[:])\n\n\t/* \"ip\" is the input pointer. */\n\tip = input\n\n\tlast_distance = -1\n\tip_end = int(uint(input) + block_size)\n\n\tif block_size >= kInputMarginBytes {\n\t\tvar len_limit uint = brotli_min_size_t(block_size-kMinMatchLen, input_size-kInputMarginBytes)\n\t\tvar ip_limit int = int(uint(input) + len_limit)\n\t\t/* For the last block, we need to keep a 16 bytes margin so that we can be\n\t\t   sure that all distances are at most window size - 16.\n\t\t   For all other blocks, we only need to keep a margin of 5 bytes so that\n\t\t   we don't go over the block size with a copy. */\n\n\t\tvar next_hash uint32\n\t\tip++\n\t\tfor next_hash = hash5(in[ip:], shift); ; {\n\t\t\tvar skip uint32 = 32\n\t\t\tvar next_ip int = ip\n\t\t\t/* Step 1: Scan forward in the input looking for a 5-byte-long match.\n\t\t\t   If we get close to exhausting the input then goto emit_remainder.\n\n\t\t\t   Heuristic match skipping: If 32 bytes are scanned with no matches\n\t\t\t   found, start looking only at every other byte. If 32 more bytes are\n\t\t\t   scanned, look at every third byte, etc.. When a match is found,\n\t\t\t   immediately go back to looking at every byte. This is a small loss\n\t\t\t   (~5% performance, ~0.1% density) for compressible data due to more\n\t\t\t   bookkeeping, but for non-compressible data (such as JPEG) it's a huge\n\t\t\t   win since the compressor quickly \"realizes\" the data is incompressible\n\t\t\t   and doesn't bother looking for matches everywhere.\n\n\t\t\t   The \"skip\" variable keeps track of how many bytes there are since the\n\t\t\t   last match; dividing it by 32 (i.e. right-shifting by five) gives the\n\t\t\t   number of bytes to move ahead for each iteration. */\n\n\t\t\tvar candidate int\n\t\t\tassert(next_emit < ip)\n\n\t\ttrawl:\n\t\t\tfor {\n\t\t\t\tvar hash uint32 = next_hash\n\t\t\t\tvar bytes_between_hash_lookups uint32 = skip >> 5\n\t\t\t\tskip++\n\t\t\t\tassert(hash == hash5(in[next_ip:], shift))\n\t\t\t\tip = next_ip\n\t\t\t\tnext_ip = int(uint32(ip) + bytes_between_hash_lookups)\n\t\t\t\tif next_ip > ip_limit {\n\t\t\t\t\tgoto emit_remainder\n\t\t\t\t}\n\n\t\t\t\tnext_hash = hash5(in[next_ip:], shift)\n\t\t\t\tcandidate = ip - last_distance\n\t\t\t\tif isMatch5(in[ip:], in[candidate:]) {\n\t\t\t\t\tif candidate < ip {\n\t\t\t\t\t\ttable[hash] = int(ip - base_ip)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcandidate = base_ip + table[hash]\n\t\t\t\tassert(candidate >= base_ip)\n\t\t\t\tassert(candidate < ip)\n\n\t\t\t\ttable[hash] = int(ip - base_ip)\n\t\t\t\tif isMatch5(in[ip:], in[candidate:]) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Check copy distance. If candidate is not feasible, continue search.\n\t\t\t   Checking is done outside of hot loop to reduce overhead. */\n\t\t\tif ip-candidate > maxDistance_compress_fragment {\n\t\t\t\tgoto trawl\n\t\t\t}\n\n\t\t\t/* Step 2: Emit the found match together with the literal bytes from\n\t\t\t   \"next_emit\" to the bit stream, and then see if we can find a next match\n\t\t\t   immediately afterwards. Repeat until we find no match for the input\n\t\t\t   without emitting some literal bytes. */\n\t\t\t{\n\t\t\t\tvar base int = ip\n\t\t\t\t/* > 0 */\n\t\t\t\tvar matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)\n\t\t\t\tvar distance int = int(base - candidate)\n\t\t\t\t/* We have a 5-byte match at ip, and we need to emit bytes in\n\t\t\t\t   [next_emit, ip). */\n\n\t\t\t\tvar insert uint = uint(base - next_emit)\n\t\t\t\tip += int(matched)\n\t\t\t\tif insert < 6210 {\n\t\t\t\t\temitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\t\t\t\t} else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {\n\t\t\t\t\temitUncompressedMetaBlock1(in[metablock_start:], in[base:], mlen_storage_ix-3, storage_ix, storage)\n\t\t\t\t\tinput_size -= uint(base - input)\n\t\t\t\t\tinput = base\n\t\t\t\t\tnext_emit = input\n\t\t\t\t\tgoto next_block\n\t\t\t\t} else {\n\t\t\t\t\temitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\t\t\t\t}\n\n\t\t\t\temitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)\n\t\t\t\tif distance == last_distance {\n\t\t\t\t\twriteBits(uint(cmd_depth[64]), uint64(cmd_bits[64]), storage_ix, storage)\n\t\t\t\t\tcmd_histo[64]++\n\t\t\t\t} else {\n\t\t\t\t\temitDistance1(uint(distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\t\t\t\t\tlast_distance = distance\n\t\t\t\t}\n\n\t\t\t\temitCopyLenLastDistance1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\n\t\t\t\tnext_emit = ip\n\t\t\t\tif ip >= ip_limit {\n\t\t\t\t\tgoto emit_remainder\n\t\t\t\t}\n\n\t\t\t\t/* We could immediately start working at ip now, but to improve\n\t\t\t\t   compression we first update \"table\" with the hashes of some positions\n\t\t\t\t   within the last copy. */\n\t\t\t\t{\n\t\t\t\t\tvar input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])\n\t\t\t\t\tvar prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)\n\t\t\t\t\tvar cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)\n\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 3)\n\t\t\t\t\tprev_hash = hashBytesAtOffset5(input_bytes, 1, shift)\n\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 2)\n\t\t\t\t\tprev_hash = hashBytesAtOffset5(input_bytes, 2, shift)\n\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 1)\n\n\t\t\t\t\tcandidate = base_ip + table[cur_hash]\n\t\t\t\t\ttable[cur_hash] = int(ip - base_ip)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor isMatch5(in[ip:], in[candidate:]) {\n\t\t\t\tvar base int = ip\n\t\t\t\t/* We have a 5-byte match at ip, and no need to emit any literal bytes\n\t\t\t\t   prior to ip. */\n\n\t\t\t\tvar matched uint = 5 + findMatchLengthWithLimit(in[candidate+5:], in[ip+5:], uint(ip_end-ip)-5)\n\t\t\t\tif ip-candidate > maxDistance_compress_fragment {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tip += int(matched)\n\t\t\t\tlast_distance = int(base - candidate) /* > 0 */\n\t\t\t\temitCopyLen1(matched, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\t\t\t\temitDistance1(uint(last_distance), cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\n\t\t\t\tnext_emit = ip\n\t\t\t\tif ip >= ip_limit {\n\t\t\t\t\tgoto emit_remainder\n\t\t\t\t}\n\n\t\t\t\t/* We could immediately start working at ip now, but to improve\n\t\t\t\t   compression we first update \"table\" with the hashes of some positions\n\t\t\t\t   within the last copy. */\n\t\t\t\t{\n\t\t\t\t\tvar input_bytes uint64 = binary.LittleEndian.Uint64(in[ip-3:])\n\t\t\t\t\tvar prev_hash uint32 = hashBytesAtOffset5(input_bytes, 0, shift)\n\t\t\t\t\tvar cur_hash uint32 = hashBytesAtOffset5(input_bytes, 3, shift)\n\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 3)\n\t\t\t\t\tprev_hash = hashBytesAtOffset5(input_bytes, 1, shift)\n\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 2)\n\t\t\t\t\tprev_hash = hashBytesAtOffset5(input_bytes, 2, shift)\n\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 1)\n\n\t\t\t\t\tcandidate = base_ip + table[cur_hash]\n\t\t\t\t\ttable[cur_hash] = int(ip - base_ip)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tip++\n\t\t\tnext_hash = hash5(in[ip:], shift)\n\t\t}\n\t}\n\nemit_remainder:\n\tassert(next_emit <= ip_end)\n\tinput += int(block_size)\n\tinput_size -= block_size\n\tblock_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kMergeBlockSize)\n\n\t/* Decide if we want to continue this meta-block instead of emitting the\n\t   last insert-only command. */\n\tif input_size > 0 && total_block_size+block_size <= 1<<20 && shouldMergeBlock(in[input:], block_size, lit_depth[:]) {\n\t\tassert(total_block_size > 1<<16)\n\n\t\t/* Update the size of the current meta-block and continue emitting commands.\n\t\t   We can do this because the current size and the new size both have 5\n\t\t   nibbles. */\n\t\ttotal_block_size += block_size\n\n\t\tupdateBits(20, uint32(total_block_size-1), mlen_storage_ix, storage)\n\t\tgoto emit_commands\n\t}\n\n\t/* Emit the remaining bytes as literals. */\n\tif next_emit < ip_end {\n\t\tvar insert uint = uint(ip_end - next_emit)\n\t\tif insert < 6210 {\n\t\t\temitInsertLen1(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\t\t\temitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)\n\t\t} else if shouldUseUncompressedMode(in[metablock_start:], in[next_emit:], insert, literal_ratio) {\n\t\t\temitUncompressedMetaBlock1(in[metablock_start:], in[ip_end:], mlen_storage_ix-3, storage_ix, storage)\n\t\t} else {\n\t\t\temitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo[:], storage_ix, storage)\n\t\t\temitLiterals(in[next_emit:], insert, lit_depth[:], lit_bits[:], storage_ix, storage)\n\t\t}\n\t}\n\n\tnext_emit = ip_end\n\n\t/* If we have more data, write a new meta-block header and prefix codes and\n\t   then continue emitting commands. */\nnext_block:\n\tif input_size > 0 {\n\t\tmetablock_start = input\n\t\tblock_size = brotli_min_size_t(input_size, compressFragmentFastImpl_kFirstBlockSize)\n\t\ttotal_block_size = block_size\n\n\t\t/* Save the bit position of the MLEN field of the meta-block header, so that\n\t\t   we can update it later if we decide to extend this meta-block. */\n\t\tmlen_storage_ix = *storage_ix + 3\n\n\t\tstoreMetaBlockHeader1(block_size, false, storage_ix, storage)\n\n\t\t/* No block splits, no contexts. */\n\t\twriteBits(13, 0, storage_ix, storage)\n\n\t\tliteral_ratio = buildAndStoreLiteralPrefixCode(in[input:], block_size, lit_depth[:], lit_bits[:], storage_ix, storage)\n\t\tbuildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, storage_ix, storage)\n\t\tgoto emit_commands\n\t}\n\n\tif !is_last {\n\t\t/* If this is not the last block, update the command and distance prefix\n\t\t   codes for the next block and store the compressed forms. */\n\t\tcmd_code[0] = 0\n\n\t\t*cmd_code_numbits = 0\n\t\tbuildAndStoreCommandPrefixCode1(cmd_histo[:], cmd_depth, cmd_bits, cmd_code_numbits, cmd_code)\n\t}\n}\n\n/* Compresses \"input\" string to the \"*storage\" buffer as one or more complete\n   meta-blocks, and updates the \"*storage_ix\" bit position.\n\n   If \"is_last\" is 1, emits an additional empty last meta-block.\n\n   \"cmd_depth\" and \"cmd_bits\" contain the command and distance prefix codes\n   (see comment in encode.h) used for the encoding of this input fragment.\n   If \"is_last\" is 0, they are updated to reflect the statistics\n   of this input fragment, to be used for the encoding of the next fragment.\n\n   \"*cmd_code_numbits\" is the number of bits of the compressed representation\n   of the command and distance prefix codes, and \"cmd_code\" is an array of\n   at least \"(*cmd_code_numbits + 7) >> 3\" size that contains the compressed\n   command and distance prefix codes. If \"is_last\" is 0, these are also\n   updated to represent the updated \"cmd_depth\" and \"cmd_bits\".\n\n   REQUIRES: \"input_size\" is greater than zero, or \"is_last\" is 1.\n   REQUIRES: \"input_size\" is less or equal to maximal metablock size (1 << 24).\n   REQUIRES: All elements in \"table[0..table_size-1]\" are initialized to zero.\n   REQUIRES: \"table_size\" is an odd (9, 11, 13, 15) power of two\n   OUTPUT: maximal copy distance <= |input_size|\n   OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */\nfunc compressFragmentFast(input []byte, input_size uint, is_last bool, table []int, table_size uint, cmd_depth []byte, cmd_bits []uint16, cmd_code_numbits *uint, cmd_code []byte, storage_ix *uint, storage []byte) {\n\tvar initial_storage_ix uint = *storage_ix\n\tvar table_bits uint = uint(log2FloorNonZero(table_size))\n\n\tif input_size == 0 {\n\t\tassert(is_last)\n\t\twriteBits(1, 1, storage_ix, storage) /* islast */\n\t\twriteBits(1, 1, storage_ix, storage) /* isempty */\n\t\t*storage_ix = (*storage_ix + 7) &^ 7\n\t\treturn\n\t}\n\n\tcompressFragmentFastImpl(input, input_size, is_last, table, table_bits, cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage)\n\n\t/* If output is larger than single uncompressed block, rewrite it. */\n\tif *storage_ix-initial_storage_ix > 31+(input_size<<3) {\n\t\temitUncompressedMetaBlock1(input, input[input_size:], initial_storage_ix, storage_ix, storage)\n\t}\n\n\tif is_last {\n\t\twriteBits(1, 1, storage_ix, storage) /* islast */\n\t\twriteBits(1, 1, storage_ix, storage) /* isempty */\n\t\t*storage_ix = (*storage_ix + 7) &^ 7\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/compress_fragment_two_pass.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2015 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Function for fast encoding of an input fragment, independently from the input\n   history. This function uses two-pass processing: in the first pass we save\n   the found backward matches and literal bytes into a buffer, and in the\n   second pass we emit them into the bit stream using prefix codes built based\n   on the actual command and literal byte histograms. */\n\nconst kCompressFragmentTwoPassBlockSize uint = 1 << 17\n\nfunc hash1(p []byte, shift uint, length uint) uint32 {\n\tvar h uint64 = (binary.LittleEndian.Uint64(p) << ((8 - length) * 8)) * uint64(kHashMul32)\n\treturn uint32(h >> shift)\n}\n\nfunc hashBytesAtOffset(v uint64, offset uint, shift uint, length uint) uint32 {\n\tassert(offset <= 8-length)\n\t{\n\t\tvar h uint64 = ((v >> (8 * offset)) << ((8 - length) * 8)) * uint64(kHashMul32)\n\t\treturn uint32(h >> shift)\n\t}\n}\n\nfunc isMatch1(p1 []byte, p2 []byte, length uint) bool {\n\tif binary.LittleEndian.Uint32(p1) != binary.LittleEndian.Uint32(p2) {\n\t\treturn false\n\t}\n\tif length == 4 {\n\t\treturn true\n\t}\n\treturn p1[4] == p2[4] && p1[5] == p2[5]\n}\n\n/*\nBuilds a command and distance prefix code (each 64 symbols) into \"depth\" and\n\n\t\"bits\" based on \"histogram\" and stores it into the bit stream.\n*/\nfunc buildAndStoreCommandPrefixCode(histogram []uint32, depth []byte, bits []uint16, storage_ix *uint, storage []byte) {\n\tvar tree [129]huffmanTree\n\tvar cmd_depth = [numCommandSymbols]byte{0}\n\t/* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */\n\n\tvar cmd_bits [64]uint16\n\tcreateHuffmanTree(histogram, 64, 15, tree[:], depth)\n\tcreateHuffmanTree(histogram[64:], 64, 14, tree[:], depth[64:])\n\n\t/* We have to jump through a few hoops here in order to compute\n\t   the command bits because the symbols are in a different order than in\n\t   the full alphabet. This looks complicated, but having the symbols\n\t   in this order in the command bits saves a few branches in the Emit*\n\t   functions. */\n\tcopy(cmd_depth[:], depth[24:][:24])\n\n\tcopy(cmd_depth[24:][:], depth[:8])\n\tcopy(cmd_depth[32:][:], depth[48:][:8])\n\tcopy(cmd_depth[40:][:], depth[8:][:8])\n\tcopy(cmd_depth[48:][:], depth[56:][:8])\n\tcopy(cmd_depth[56:][:], depth[16:][:8])\n\tconvertBitDepthsToSymbols(cmd_depth[:], 64, cmd_bits[:])\n\tcopy(bits, cmd_bits[24:][:8])\n\tcopy(bits[8:], cmd_bits[40:][:8])\n\tcopy(bits[16:], cmd_bits[56:][:8])\n\tcopy(bits[24:], cmd_bits[:24])\n\tcopy(bits[48:], cmd_bits[32:][:8])\n\tcopy(bits[56:], cmd_bits[48:][:8])\n\tconvertBitDepthsToSymbols(depth[64:], 64, bits[64:])\n\t{\n\t\t/* Create the bit length array for the full command alphabet. */\n\t\tvar i uint\n\t\tfor i := 0; i < int(64); i++ {\n\t\t\tcmd_depth[i] = 0\n\t\t} /* only 64 first values were used */\n\t\tcopy(cmd_depth[:], depth[24:][:8])\n\t\tcopy(cmd_depth[64:][:], depth[32:][:8])\n\t\tcopy(cmd_depth[128:][:], depth[40:][:8])\n\t\tcopy(cmd_depth[192:][:], depth[48:][:8])\n\t\tcopy(cmd_depth[384:][:], depth[56:][:8])\n\t\tfor i = 0; i < 8; i++ {\n\t\t\tcmd_depth[128+8*i] = depth[i]\n\t\t\tcmd_depth[256+8*i] = depth[8+i]\n\t\t\tcmd_depth[448+8*i] = depth[16+i]\n\t\t}\n\n\t\tstoreHuffmanTree(cmd_depth[:], numCommandSymbols, tree[:], storage_ix, storage)\n\t}\n\n\tstoreHuffmanTree(depth[64:], 64, tree[:], storage_ix, storage)\n}\n\nfunc emitInsertLen(insertlen uint32, commands *[]uint32) {\n\tif insertlen < 6 {\n\t\t(*commands)[0] = insertlen\n\t} else if insertlen < 130 {\n\t\tvar tail uint32 = insertlen - 2\n\t\tvar nbits uint32 = log2FloorNonZero(uint(tail)) - 1\n\t\tvar prefix uint32 = tail >> nbits\n\t\tvar inscode uint32 = (nbits << 1) + prefix + 2\n\t\tvar extra uint32 = tail - (prefix << nbits)\n\t\t(*commands)[0] = inscode | extra<<8\n\t} else if insertlen < 2114 {\n\t\tvar tail uint32 = insertlen - 66\n\t\tvar nbits uint32 = log2FloorNonZero(uint(tail))\n\t\tvar code uint32 = nbits + 10\n\t\tvar extra uint32 = tail - (1 << nbits)\n\t\t(*commands)[0] = code | extra<<8\n\t} else if insertlen < 6210 {\n\t\tvar extra uint32 = insertlen - 2114\n\t\t(*commands)[0] = 21 | extra<<8\n\t} else if insertlen < 22594 {\n\t\tvar extra uint32 = insertlen - 6210\n\t\t(*commands)[0] = 22 | extra<<8\n\t} else {\n\t\tvar extra uint32 = insertlen - 22594\n\t\t(*commands)[0] = 23 | extra<<8\n\t}\n\n\t*commands = (*commands)[1:]\n}\n\nfunc emitCopyLen(copylen uint, commands *[]uint32) {\n\tif copylen < 10 {\n\t\t(*commands)[0] = uint32(copylen + 38)\n\t} else if copylen < 134 {\n\t\tvar tail uint = copylen - 6\n\t\tvar nbits uint = uint(log2FloorNonZero(tail) - 1)\n\t\tvar prefix uint = tail >> nbits\n\t\tvar code uint = (nbits << 1) + prefix + 44\n\t\tvar extra uint = tail - (prefix << nbits)\n\t\t(*commands)[0] = uint32(code | extra<<8)\n\t} else if copylen < 2118 {\n\t\tvar tail uint = copylen - 70\n\t\tvar nbits uint = uint(log2FloorNonZero(tail))\n\t\tvar code uint = nbits + 52\n\t\tvar extra uint = tail - (uint(1) << nbits)\n\t\t(*commands)[0] = uint32(code | extra<<8)\n\t} else {\n\t\tvar extra uint = copylen - 2118\n\t\t(*commands)[0] = uint32(63 | extra<<8)\n\t}\n\n\t*commands = (*commands)[1:]\n}\n\nfunc emitCopyLenLastDistance(copylen uint, commands *[]uint32) {\n\tif copylen < 12 {\n\t\t(*commands)[0] = uint32(copylen + 20)\n\t\t*commands = (*commands)[1:]\n\t} else if copylen < 72 {\n\t\tvar tail uint = copylen - 8\n\t\tvar nbits uint = uint(log2FloorNonZero(tail) - 1)\n\t\tvar prefix uint = tail >> nbits\n\t\tvar code uint = (nbits << 1) + prefix + 28\n\t\tvar extra uint = tail - (prefix << nbits)\n\t\t(*commands)[0] = uint32(code | extra<<8)\n\t\t*commands = (*commands)[1:]\n\t} else if copylen < 136 {\n\t\tvar tail uint = copylen - 8\n\t\tvar code uint = (tail >> 5) + 54\n\t\tvar extra uint = tail & 31\n\t\t(*commands)[0] = uint32(code | extra<<8)\n\t\t*commands = (*commands)[1:]\n\t\t(*commands)[0] = 64\n\t\t*commands = (*commands)[1:]\n\t} else if copylen < 2120 {\n\t\tvar tail uint = copylen - 72\n\t\tvar nbits uint = uint(log2FloorNonZero(tail))\n\t\tvar code uint = nbits + 52\n\t\tvar extra uint = tail - (uint(1) << nbits)\n\t\t(*commands)[0] = uint32(code | extra<<8)\n\t\t*commands = (*commands)[1:]\n\t\t(*commands)[0] = 64\n\t\t*commands = (*commands)[1:]\n\t} else {\n\t\tvar extra uint = copylen - 2120\n\t\t(*commands)[0] = uint32(63 | extra<<8)\n\t\t*commands = (*commands)[1:]\n\t\t(*commands)[0] = 64\n\t\t*commands = (*commands)[1:]\n\t}\n}\n\nfunc emitDistance(distance uint32, commands *[]uint32) {\n\tvar d uint32 = distance + 3\n\tvar nbits uint32 = log2FloorNonZero(uint(d)) - 1\n\tvar prefix uint32 = (d >> nbits) & 1\n\tvar offset uint32 = (2 + prefix) << nbits\n\tvar distcode uint32 = 2*(nbits-1) + prefix + 80\n\tvar extra uint32 = d - offset\n\t(*commands)[0] = distcode | extra<<8\n\t*commands = (*commands)[1:]\n}\n\n/* REQUIRES: len <= 1 << 24. */\nfunc storeMetaBlockHeader(len uint, is_uncompressed bool, storage_ix *uint, storage []byte) {\n\tvar nibbles uint = 6\n\n\t/* ISLAST */\n\twriteBits(1, 0, storage_ix, storage)\n\n\tif len <= 1<<16 {\n\t\tnibbles = 4\n\t} else if len <= 1<<20 {\n\t\tnibbles = 5\n\t}\n\n\twriteBits(2, uint64(nibbles)-4, storage_ix, storage)\n\twriteBits(nibbles*4, uint64(len)-1, storage_ix, storage)\n\n\t/* ISUNCOMPRESSED */\n\twriteSingleBit(is_uncompressed, storage_ix, storage)\n}\n\nfunc storeMetaBlockHeaderBW(len uint, is_uncompressed bool, bw *bitWriter) {\n\tvar nibbles uint = 6\n\n\t/* ISLAST */\n\tbw.writeBits(1, 0)\n\n\tif len <= 1<<16 {\n\t\tnibbles = 4\n\t} else if len <= 1<<20 {\n\t\tnibbles = 5\n\t} else if len > 1<<24 {\n\t\tpanic(\"metablock too long\")\n\t}\n\n\tbw.writeBits(2, uint64(nibbles)-4)\n\tbw.writeBits(nibbles*4, uint64(len)-1)\n\n\t/* ISUNCOMPRESSED */\n\tbw.writeSingleBit(is_uncompressed)\n}\n\nfunc createCommands(input []byte, block_size uint, input_size uint, base_ip_ptr []byte, table []int, table_bits uint, min_match uint, literals *[]byte, commands *[]uint32) {\n\tvar ip int = 0\n\tvar shift uint = 64 - table_bits\n\tvar ip_end int = int(block_size)\n\tvar base_ip int = -cap(base_ip_ptr) + cap(input)\n\tvar next_emit int = 0\n\tvar last_distance int = -1\n\t/* \"ip\" is the input pointer. */\n\n\tconst kInputMarginBytes uint = windowGap\n\n\t/* \"next_emit\" is a pointer to the first byte that is not covered by a\n\t   previous copy. Bytes between \"next_emit\" and the start of the next copy or\n\t   the end of the input will be emitted as literal bytes. */\n\tif block_size >= kInputMarginBytes {\n\t\tvar len_limit uint = brotli_min_size_t(block_size-min_match, input_size-kInputMarginBytes)\n\t\tvar ip_limit int = int(len_limit)\n\t\t/* For the last block, we need to keep a 16 bytes margin so that we can be\n\t\t   sure that all distances are at most window size - 16.\n\t\t   For all other blocks, we only need to keep a margin of 5 bytes so that\n\t\t   we don't go over the block size with a copy. */\n\n\t\tvar next_hash uint32\n\t\tip++\n\t\tfor next_hash = hash1(input[ip:], shift, min_match); ; {\n\t\t\tvar skip uint32 = 32\n\t\t\tvar next_ip int = ip\n\t\t\t/* Step 1: Scan forward in the input looking for a 6-byte-long match.\n\t\t\t   If we get close to exhausting the input then goto emit_remainder.\n\n\t\t\t   Heuristic match skipping: If 32 bytes are scanned with no matches\n\t\t\t   found, start looking only at every other byte. If 32 more bytes are\n\t\t\t   scanned, look at every third byte, etc.. When a match is found,\n\t\t\t   immediately go back to looking at every byte. This is a small loss\n\t\t\t   (~5% performance, ~0.1% density) for compressible data due to more\n\t\t\t   bookkeeping, but for non-compressible data (such as JPEG) it's a huge\n\t\t\t   win since the compressor quickly \"realizes\" the data is incompressible\n\t\t\t   and doesn't bother looking for matches everywhere.\n\n\t\t\t   The \"skip\" variable keeps track of how many bytes there are since the\n\t\t\t   last match; dividing it by 32 (ie. right-shifting by five) gives the\n\t\t\t   number of bytes to move ahead for each iteration. */\n\n\t\t\tvar candidate int\n\n\t\t\tassert(next_emit < ip)\n\n\t\ttrawl:\n\t\t\tfor {\n\t\t\t\tvar hash uint32 = next_hash\n\t\t\t\tvar bytes_between_hash_lookups uint32 = skip >> 5\n\t\t\t\tskip++\n\t\t\t\tip = next_ip\n\t\t\t\tassert(hash == hash1(input[ip:], shift, min_match))\n\t\t\t\tnext_ip = int(uint32(ip) + bytes_between_hash_lookups)\n\t\t\t\tif next_ip > ip_limit {\n\t\t\t\t\tgoto emit_remainder\n\t\t\t\t}\n\n\t\t\t\tnext_hash = hash1(input[next_ip:], shift, min_match)\n\t\t\t\tcandidate = ip - last_distance\n\t\t\t\tif isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {\n\t\t\t\t\tif candidate < ip {\n\t\t\t\t\t\ttable[hash] = int(ip - base_ip)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcandidate = base_ip + table[hash]\n\t\t\t\tassert(candidate >= base_ip)\n\t\t\t\tassert(candidate < ip)\n\n\t\t\t\ttable[hash] = int(ip - base_ip)\n\t\t\t\tif isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Check copy distance. If candidate is not feasible, continue search.\n\t\t\t   Checking is done outside of hot loop to reduce overhead. */\n\t\t\tif ip-candidate > maxDistance_compress_fragment {\n\t\t\t\tgoto trawl\n\t\t\t}\n\n\t\t\t/* Step 2: Emit the found match together with the literal bytes from\n\t\t\t   \"next_emit\", and then see if we can find a next match immediately\n\t\t\t   afterwards. Repeat until we find no match for the input\n\t\t\t   without emitting some literal bytes. */\n\t\t\t{\n\t\t\t\tvar base int = ip\n\t\t\t\t/* > 0 */\n\t\t\t\tvar matched uint = min_match + findMatchLengthWithLimit(base_ip_ptr[uint(candidate-base_ip)+min_match:], input[uint(ip)+min_match:], uint(ip_end-ip)-min_match)\n\t\t\t\tvar distance int = int(base - candidate)\n\t\t\t\t/* We have a 6-byte match at ip, and we need to emit bytes in\n\t\t\t\t   [next_emit, ip). */\n\n\t\t\t\tvar insert int = int(base - next_emit)\n\t\t\t\tip += int(matched)\n\t\t\t\temitInsertLen(uint32(insert), commands)\n\t\t\t\tcopy(*literals, input[next_emit:][:uint(insert)])\n\t\t\t\t*literals = (*literals)[insert:]\n\t\t\t\tif distance == last_distance {\n\t\t\t\t\t(*commands)[0] = 64\n\t\t\t\t\t*commands = (*commands)[1:]\n\t\t\t\t} else {\n\t\t\t\t\temitDistance(uint32(distance), commands)\n\t\t\t\t\tlast_distance = distance\n\t\t\t\t}\n\n\t\t\t\temitCopyLenLastDistance(matched, commands)\n\n\t\t\t\tnext_emit = ip\n\t\t\t\tif ip >= ip_limit {\n\t\t\t\t\tgoto emit_remainder\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tvar input_bytes uint64\n\t\t\t\t\tvar cur_hash uint32\n\t\t\t\t\t/* We could immediately start working at ip now, but to improve\n\t\t\t\t\t   compression we first update \"table\" with the hashes of some\n\t\t\t\t\t   positions within the last copy. */\n\n\t\t\t\t\tvar prev_hash uint32\n\t\t\t\t\tif min_match == 4 {\n\t\t\t\t\t\tinput_bytes = binary.LittleEndian.Uint64(input[ip-3:])\n\t\t\t\t\t\tcur_hash = hashBytesAtOffset(input_bytes, 3, shift, min_match)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 3)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 2)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 1)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinput_bytes = binary.LittleEndian.Uint64(input[ip-5:])\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 5)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 4)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 3)\n\t\t\t\t\t\tinput_bytes = binary.LittleEndian.Uint64(input[ip-2:])\n\t\t\t\t\t\tcur_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 2)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 1)\n\t\t\t\t\t}\n\n\t\t\t\t\tcandidate = base_ip + table[cur_hash]\n\t\t\t\t\ttable[cur_hash] = int(ip - base_ip)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ip-candidate <= maxDistance_compress_fragment && isMatch1(input[ip:], base_ip_ptr[candidate-base_ip:], min_match) {\n\t\t\t\tvar base int = ip\n\t\t\t\t/* We have a 6-byte match at ip, and no need to emit any\n\t\t\t\t   literal bytes prior to ip. */\n\n\t\t\t\tvar matched uint = min_match + findMatchLengthWithLimit(base_ip_ptr[uint(candidate-base_ip)+min_match:], input[uint(ip)+min_match:], uint(ip_end-ip)-min_match)\n\t\t\t\tip += int(matched)\n\t\t\t\tlast_distance = int(base - candidate) /* > 0 */\n\t\t\t\temitCopyLen(matched, commands)\n\t\t\t\temitDistance(uint32(last_distance), commands)\n\n\t\t\t\tnext_emit = ip\n\t\t\t\tif ip >= ip_limit {\n\t\t\t\t\tgoto emit_remainder\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tvar input_bytes uint64\n\t\t\t\t\tvar cur_hash uint32\n\t\t\t\t\t/* We could immediately start working at ip now, but to improve\n\t\t\t\t\t   compression we first update \"table\" with the hashes of some\n\t\t\t\t\t   positions within the last copy. */\n\n\t\t\t\t\tvar prev_hash uint32\n\t\t\t\t\tif min_match == 4 {\n\t\t\t\t\t\tinput_bytes = binary.LittleEndian.Uint64(input[ip-3:])\n\t\t\t\t\t\tcur_hash = hashBytesAtOffset(input_bytes, 3, shift, min_match)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 3)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 2)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 1)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tinput_bytes = binary.LittleEndian.Uint64(input[ip-5:])\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 5)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 4)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 3)\n\t\t\t\t\t\tinput_bytes = binary.LittleEndian.Uint64(input[ip-2:])\n\t\t\t\t\t\tcur_hash = hashBytesAtOffset(input_bytes, 2, shift, min_match)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 0, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 2)\n\t\t\t\t\t\tprev_hash = hashBytesAtOffset(input_bytes, 1, shift, min_match)\n\t\t\t\t\t\ttable[prev_hash] = int(ip - base_ip - 1)\n\t\t\t\t\t}\n\n\t\t\t\t\tcandidate = base_ip + table[cur_hash]\n\t\t\t\t\ttable[cur_hash] = int(ip - base_ip)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tip++\n\t\t\tnext_hash = hash1(input[ip:], shift, min_match)\n\t\t}\n\t}\n\nemit_remainder:\n\tassert(next_emit <= ip_end)\n\n\t/* Emit the remaining bytes as literals. */\n\tif next_emit < ip_end {\n\t\tvar insert uint32 = uint32(ip_end - next_emit)\n\t\temitInsertLen(insert, commands)\n\t\tcopy(*literals, input[next_emit:][:insert])\n\t\t*literals = (*literals)[insert:]\n\t}\n}\n\nvar storeCommands_kNumExtraBits = [128]uint32{\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t2,\n\t2,\n\t3,\n\t3,\n\t4,\n\t4,\n\t5,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t12,\n\t14,\n\t24,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t2,\n\t2,\n\t3,\n\t3,\n\t4,\n\t4,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t2,\n\t2,\n\t3,\n\t3,\n\t4,\n\t4,\n\t5,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t24,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t2,\n\t2,\n\t3,\n\t3,\n\t4,\n\t4,\n\t5,\n\t5,\n\t6,\n\t6,\n\t7,\n\t7,\n\t8,\n\t8,\n\t9,\n\t9,\n\t10,\n\t10,\n\t11,\n\t11,\n\t12,\n\t12,\n\t13,\n\t13,\n\t14,\n\t14,\n\t15,\n\t15,\n\t16,\n\t16,\n\t17,\n\t17,\n\t18,\n\t18,\n\t19,\n\t19,\n\t20,\n\t20,\n\t21,\n\t21,\n\t22,\n\t22,\n\t23,\n\t23,\n\t24,\n\t24,\n}\nvar storeCommands_kInsertOffset = [24]uint32{\n\t0,\n\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t8,\n\t10,\n\t14,\n\t18,\n\t26,\n\t34,\n\t50,\n\t66,\n\t98,\n\t130,\n\t194,\n\t322,\n\t578,\n\t1090,\n\t2114,\n\t6210,\n\t22594,\n}\n\nfunc storeCommands(literals []byte, num_literals uint, commands []uint32, num_commands uint, storage_ix *uint, storage []byte) {\n\tvar lit_depths [256]byte\n\tvar lit_bits [256]uint16\n\tvar lit_histo = [256]uint32{0}\n\tvar cmd_depths = [128]byte{0}\n\tvar cmd_bits = [128]uint16{0}\n\tvar cmd_histo = [128]uint32{0}\n\tvar i uint\n\tfor i = 0; i < num_literals; i++ {\n\t\tlit_histo[literals[i]]++\n\t}\n\n\tbuildAndStoreHuffmanTreeFast(lit_histo[:], num_literals, /* max_bits = */\n\t\t8, lit_depths[:], lit_bits[:], storage_ix, storage)\n\n\tfor i = 0; i < num_commands; i++ {\n\t\tvar code uint32 = commands[i] & 0xFF\n\t\tassert(code < 128)\n\t\tcmd_histo[code]++\n\t}\n\n\tcmd_histo[1] += 1\n\tcmd_histo[2] += 1\n\tcmd_histo[64] += 1\n\tcmd_histo[84] += 1\n\tbuildAndStoreCommandPrefixCode(cmd_histo[:], cmd_depths[:], cmd_bits[:], storage_ix, storage)\n\n\tfor i = 0; i < num_commands; i++ {\n\t\tvar cmd uint32 = commands[i]\n\t\tvar code uint32 = cmd & 0xFF\n\t\tvar extra uint32 = cmd >> 8\n\t\tassert(code < 128)\n\t\twriteBits(uint(cmd_depths[code]), uint64(cmd_bits[code]), storage_ix, storage)\n\t\twriteBits(uint(storeCommands_kNumExtraBits[code]), uint64(extra), storage_ix, storage)\n\t\tif code < 24 {\n\t\t\tvar insert uint32 = storeCommands_kInsertOffset[code] + extra\n\t\t\tvar j uint32\n\t\t\tfor j = 0; j < insert; j++ {\n\t\t\t\tvar lit byte = literals[0]\n\t\t\t\twriteBits(uint(lit_depths[lit]), uint64(lit_bits[lit]), storage_ix, storage)\n\t\t\t\tliterals = literals[1:]\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* Acceptable loss for uncompressible speedup is 2% */\nconst minRatio = 0.98\n\nconst sampleRate = 43\n\nfunc shouldCompress(input []byte, input_size uint, num_literals uint) bool {\n\tvar corpus_size float64 = float64(input_size)\n\tif float64(num_literals) < minRatio*corpus_size {\n\t\treturn true\n\t} else {\n\t\tvar literal_histo = [256]uint32{0}\n\t\tvar max_total_bit_cost float64 = corpus_size * 8 * minRatio / sampleRate\n\t\tvar i uint\n\t\tfor i = 0; i < input_size; i += sampleRate {\n\t\t\tliteral_histo[input[i]]++\n\t\t}\n\n\t\treturn bitsEntropy(literal_histo[:], 256) < max_total_bit_cost\n\t}\n}\n\nfunc rewindBitPosition(new_storage_ix uint, storage_ix *uint, storage []byte) {\n\tvar bitpos uint = new_storage_ix & 7\n\tvar mask uint = (1 << bitpos) - 1\n\tstorage[new_storage_ix>>3] &= byte(mask)\n\t*storage_ix = new_storage_ix\n}\n\nfunc emitUncompressedMetaBlock(input []byte, input_size uint, storage_ix *uint, storage []byte) {\n\tstoreMetaBlockHeader(input_size, true, storage_ix, storage)\n\t*storage_ix = (*storage_ix + 7) &^ 7\n\tcopy(storage[*storage_ix>>3:], input[:input_size])\n\t*storage_ix += input_size << 3\n\tstorage[*storage_ix>>3] = 0\n}\n\nfunc compressFragmentTwoPassImpl(input []byte, input_size uint, is_last bool, command_buf []uint32, literal_buf []byte, table []int, table_bits uint, min_match uint, storage_ix *uint, storage []byte) {\n\t/* Save the start of the first block for position and distance computations.\n\t */\n\tvar base_ip []byte = input\n\n\tfor input_size > 0 {\n\t\tvar block_size uint = brotli_min_size_t(input_size, kCompressFragmentTwoPassBlockSize)\n\t\tvar commands []uint32 = command_buf\n\t\tvar literals []byte = literal_buf\n\t\tvar num_literals uint\n\t\tcreateCommands(input, block_size, input_size, base_ip, table, table_bits, min_match, &literals, &commands)\n\t\tnum_literals = uint(-cap(literals) + cap(literal_buf))\n\t\tif shouldCompress(input, block_size, num_literals) {\n\t\t\tvar num_commands uint = uint(-cap(commands) + cap(command_buf))\n\t\t\tstoreMetaBlockHeader(block_size, false, storage_ix, storage)\n\n\t\t\t/* No block splits, no contexts. */\n\t\t\twriteBits(13, 0, storage_ix, storage)\n\n\t\t\tstoreCommands(literal_buf, num_literals, command_buf, num_commands, storage_ix, storage)\n\t\t} else {\n\t\t\t/* Since we did not find many backward references and the entropy of\n\t\t\t   the data is close to 8 bits, we can simply emit an uncompressed block.\n\t\t\t   This makes compression speed of uncompressible data about 3x faster. */\n\t\t\temitUncompressedMetaBlock(input, block_size, storage_ix, storage)\n\t\t}\n\n\t\tinput = input[block_size:]\n\t\tinput_size -= block_size\n\t}\n}\n\n/*\nCompresses \"input\" string to the \"*storage\" buffer as one or more complete\n\n\tmeta-blocks, and updates the \"*storage_ix\" bit position.\n\n\tIf \"is_last\" is 1, emits an additional empty last meta-block.\n\n\tREQUIRES: \"input_size\" is greater than zero, or \"is_last\" is 1.\n\tREQUIRES: \"input_size\" is less or equal to maximal metablock size (1 << 24).\n\tREQUIRES: \"command_buf\" and \"literal_buf\" point to at least\n\t           kCompressFragmentTwoPassBlockSize long arrays.\n\tREQUIRES: All elements in \"table[0..table_size-1]\" are initialized to zero.\n\tREQUIRES: \"table_size\" is a power of two\n\tOUTPUT: maximal copy distance <= |input_size|\n\tOUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18)\n*/\nfunc compressFragmentTwoPass(input []byte, input_size uint, is_last bool, command_buf []uint32, literal_buf []byte, table []int, table_size uint, storage_ix *uint, storage []byte) {\n\tvar initial_storage_ix uint = *storage_ix\n\tvar table_bits uint = uint(log2FloorNonZero(table_size))\n\tvar min_match uint\n\tif table_bits <= 15 {\n\t\tmin_match = 4\n\t} else {\n\t\tmin_match = 6\n\t}\n\tcompressFragmentTwoPassImpl(input, input_size, is_last, command_buf, literal_buf, table, table_bits, min_match, storage_ix, storage)\n\n\t/* If output is larger than single uncompressed block, rewrite it. */\n\tif *storage_ix-initial_storage_ix > 31+(input_size<<3) {\n\t\trewindBitPosition(initial_storage_ix, storage_ix, storage)\n\t\temitUncompressedMetaBlock(input, input_size, storage_ix, storage)\n\t}\n\n\tif is_last {\n\t\twriteBits(1, 1, storage_ix, storage) /* islast */\n\t\twriteBits(1, 1, storage_ix, storage) /* isempty */\n\t\t*storage_ix = (*storage_ix + 7) &^ 7\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/constants.go",
    "content": "package brotli\n\n/* Copyright 2016 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Specification: 7.3. Encoding of the context map */\nconst contextMapMaxRle = 16\n\n/* Specification: 2. Compressed representation overview */\nconst maxNumberOfBlockTypes = 256\n\n/* Specification: 3.3. Alphabet sizes: insert-and-copy length */\nconst numLiteralSymbols = 256\n\nconst numCommandSymbols = 704\n\nconst numBlockLenSymbols = 26\n\nconst maxContextMapSymbols = (maxNumberOfBlockTypes + contextMapMaxRle)\n\nconst maxBlockTypeSymbols = (maxNumberOfBlockTypes + 2)\n\n/* Specification: 3.5. Complex prefix codes */\nconst repeatPreviousCodeLength = 16\n\nconst repeatZeroCodeLength = 17\n\nconst codeLengthCodes = (repeatZeroCodeLength + 1)\n\n/* \"code length of 8 is repeated\" */\nconst initialRepeatedCodeLength = 8\n\n/* \"Large Window Brotli\" */\nconst largeMaxDistanceBits = 62\n\nconst largeMinWbits = 10\n\nconst largeMaxWbits = 30\n\n/* Specification: 4. Encoding of distances */\nconst numDistanceShortCodes = 16\n\nconst maxNpostfix = 3\n\nconst maxNdirect = 120\n\nconst maxDistanceBits = 24\n\nfunc distanceAlphabetSize(NPOSTFIX uint, NDIRECT uint, MAXNBITS uint) uint {\n\treturn numDistanceShortCodes + NDIRECT + uint(MAXNBITS<<(NPOSTFIX+1))\n}\n\n/* numDistanceSymbols == 1128 */\nconst numDistanceSymbols = 1128\n\nconst maxDistance = 0x3FFFFFC\n\nconst maxAllowedDistance = 0x7FFFFFFC\n\n/* 7.1. Context modes and context ID lookup for literals */\n/* \"context IDs for literals are in the range of 0..63\" */\nconst literalContextBits = 6\n\n/* 7.2. Context ID for distances */\nconst distanceContextBits = 2\n\n/* 9.1. Format of the Stream Header */\n/* Number of slack bytes for window size. Don't confuse\n   with BROTLI_NUM_DISTANCE_SHORT_CODES. */\nconst windowGap = 16\n\nfunc maxBackwardLimit(W uint) uint {\n\treturn (uint(1) << W) - windowGap\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/context.go",
    "content": "package brotli\n\n/* Lookup table to map the previous two bytes to a context id.\n\nThere are four different context modeling modes defined here:\n  contextLSB6: context id is the least significant 6 bits of the last byte,\n  contextMSB6: context id is the most significant 6 bits of the last byte,\n  contextUTF8: second-order context model tuned for UTF8-encoded text,\n  contextSigned: second-order context model tuned for signed integers.\n\nIf |p1| and |p2| are the previous two bytes, and |mode| is current context\nmode, we calculate the context as:\n\n  context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256].\n\nFor contextUTF8 mode, if the previous two bytes are ASCII characters\n(i.e. < 128), this will be equivalent to\n\n  context = 4 * context1(p1) + context2(p2),\n\nwhere context1 is based on the previous byte in the following way:\n\n  0  : non-ASCII control\n  1  : \\t, \\n, \\r\n  2  : space\n  3  : other punctuation\n  4  : \" '\n  5  : %\n  6  : ( < [ {\n  7  : ) > ] }\n  8  : , ; :\n  9  : .\n  10 : =\n  11 : number\n  12 : upper-case vowel\n  13 : upper-case consonant\n  14 : lower-case vowel\n  15 : lower-case consonant\n\nand context2 is based on the second last byte:\n\n  0 : control, space\n  1 : punctuation\n  2 : upper-case letter, number\n  3 : lower-case letter\n\nIf the last byte is ASCII, and the second last byte is not (in a valid UTF8\nstream it will be a continuation byte, value between 128 and 191), the\ncontext is the same as if the second last byte was an ASCII control or space.\n\nIf the last byte is a UTF8 lead byte (value >= 192), then the next byte will\nbe a continuation byte and the context id is 2 or 3 depending on the LSB of\nthe last byte and to a lesser extent on the second last byte if it is ASCII.\n\nIf the last byte is a UTF8 continuation byte, the second last byte can be:\n  - continuation byte: the next byte is probably ASCII or lead byte (assuming\n    4-byte UTF8 characters are rare) and the context id is 0 or 1.\n  - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1\n  - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3\n\nThe possible value combinations of the previous two bytes, the range of\ncontext ids and the type of the next byte is summarized in the table below:\n\n|--------\\-----------------------------------------------------------------|\n|         \\                         Last byte                              |\n| Second   \\---------------------------------------------------------------|\n| last byte \\    ASCII            |   cont. byte        |   lead byte      |\n|            \\   (0-127)          |   (128-191)         |   (192-)         |\n|=============|===================|=====================|==================|\n|  ASCII      | next: ASCII/lead  |  not valid          |  next: cont.     |\n|  (0-127)    | context: 4 - 63   |                     |  context: 2 - 3  |\n|-------------|-------------------|---------------------|------------------|\n|  cont. byte | next: ASCII/lead  |  next: ASCII/lead   |  next: cont.     |\n|  (128-191)  | context: 4 - 63   |  context: 0 - 1     |  context: 2 - 3  |\n|-------------|-------------------|---------------------|------------------|\n|  lead byte  | not valid         |  next: ASCII/lead   |  not valid       |\n|  (192-207)  |                   |  context: 0 - 1     |                  |\n|-------------|-------------------|---------------------|------------------|\n|  lead byte  | not valid         |  next: cont.        |  not valid       |\n|  (208-)     |                   |  context: 2 - 3     |                  |\n|-------------|-------------------|---------------------|------------------|\n*/\n\nconst (\n\tcontextLSB6   = 0\n\tcontextMSB6   = 1\n\tcontextUTF8   = 2\n\tcontextSigned = 3\n)\n\n/* Common context lookup table for all context modes. */\nvar kContextLookup = [2048]byte{\n\t/* CONTEXT_LSB6, last byte. */\n\t0,\n\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t11,\n\t12,\n\t13,\n\t14,\n\t15,\n\t16,\n\t17,\n\t18,\n\t19,\n\t20,\n\t21,\n\t22,\n\t23,\n\t24,\n\t25,\n\t26,\n\t27,\n\t28,\n\t29,\n\t30,\n\t31,\n\t32,\n\t33,\n\t34,\n\t35,\n\t36,\n\t37,\n\t38,\n\t39,\n\t40,\n\t41,\n\t42,\n\t43,\n\t44,\n\t45,\n\t46,\n\t47,\n\t48,\n\t49,\n\t50,\n\t51,\n\t52,\n\t53,\n\t54,\n\t55,\n\t56,\n\t57,\n\t58,\n\t59,\n\t60,\n\t61,\n\t62,\n\t63,\n\t0,\n\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t11,\n\t12,\n\t13,\n\t14,\n\t15,\n\t16,\n\t17,\n\t18,\n\t19,\n\t20,\n\t21,\n\t22,\n\t23,\n\t24,\n\t25,\n\t26,\n\t27,\n\t28,\n\t29,\n\t30,\n\t31,\n\t32,\n\t33,\n\t34,\n\t35,\n\t36,\n\t37,\n\t38,\n\t39,\n\t40,\n\t41,\n\t42,\n\t43,\n\t44,\n\t45,\n\t46,\n\t47,\n\t48,\n\t49,\n\t50,\n\t51,\n\t52,\n\t53,\n\t54,\n\t55,\n\t56,\n\t57,\n\t58,\n\t59,\n\t60,\n\t61,\n\t62,\n\t63,\n\t0,\n\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t11,\n\t12,\n\t13,\n\t14,\n\t15,\n\t16,\n\t17,\n\t18,\n\t19,\n\t20,\n\t21,\n\t22,\n\t23,\n\t24,\n\t25,\n\t26,\n\t27,\n\t28,\n\t29,\n\t30,\n\t31,\n\t32,\n\t33,\n\t34,\n\t35,\n\t36,\n\t37,\n\t38,\n\t39,\n\t40,\n\t41,\n\t42,\n\t43,\n\t44,\n\t45,\n\t46,\n\t47,\n\t48,\n\t49,\n\t50,\n\t51,\n\t52,\n\t53,\n\t54,\n\t55,\n\t56,\n\t57,\n\t58,\n\t59,\n\t60,\n\t61,\n\t62,\n\t63,\n\t0,\n\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t7,\n\t8,\n\t9,\n\t10,\n\t11,\n\t12,\n\t13,\n\t14,\n\t15,\n\t16,\n\t17,\n\t18,\n\t19,\n\t20,\n\t21,\n\t22,\n\t23,\n\t24,\n\t25,\n\t26,\n\t27,\n\t28,\n\t29,\n\t30,\n\t31,\n\t32,\n\t33,\n\t34,\n\t35,\n\t36,\n\t37,\n\t38,\n\t39,\n\t40,\n\t41,\n\t42,\n\t43,\n\t44,\n\t45,\n\t46,\n\t47,\n\t48,\n\t49,\n\t50,\n\t51,\n\t52,\n\t53,\n\t54,\n\t55,\n\t56,\n\t57,\n\t58,\n\t59,\n\t60,\n\t61,\n\t62,\n\t63,\n\n\t/* CONTEXT_LSB6, second last byte, */\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\n\t/* CONTEXT_MSB6, last byte. */\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t1,\n\t1,\n\t2,\n\t2,\n\t2,\n\t2,\n\t3,\n\t3,\n\t3,\n\t3,\n\t4,\n\t4,\n\t4,\n\t4,\n\t5,\n\t5,\n\t5,\n\t5,\n\t6,\n\t6,\n\t6,\n\t6,\n\t7,\n\t7,\n\t7,\n\t7,\n\t8,\n\t8,\n\t8,\n\t8,\n\t9,\n\t9,\n\t9,\n\t9,\n\t10,\n\t10,\n\t10,\n\t10,\n\t11,\n\t11,\n\t11,\n\t11,\n\t12,\n\t12,\n\t12,\n\t12,\n\t13,\n\t13,\n\t13,\n\t13,\n\t14,\n\t14,\n\t14,\n\t14,\n\t15,\n\t15,\n\t15,\n\t15,\n\t16,\n\t16,\n\t16,\n\t16,\n\t17,\n\t17,\n\t17,\n\t17,\n\t18,\n\t18,\n\t18,\n\t18,\n\t19,\n\t19,\n\t19,\n\t19,\n\t20,\n\t20,\n\t20,\n\t20,\n\t21,\n\t21,\n\t21,\n\t21,\n\t22,\n\t22,\n\t22,\n\t22,\n\t23,\n\t23,\n\t23,\n\t23,\n\t24,\n\t24,\n\t24,\n\t24,\n\t25,\n\t25,\n\t25,\n\t25,\n\t26,\n\t26,\n\t26,\n\t26,\n\t27,\n\t27,\n\t27,\n\t27,\n\t28,\n\t28,\n\t28,\n\t28,\n\t29,\n\t29,\n\t29,\n\t29,\n\t30,\n\t30,\n\t30,\n\t30,\n\t31,\n\t31,\n\t31,\n\t31,\n\t32,\n\t32,\n\t32,\n\t32,\n\t33,\n\t33,\n\t33,\n\t33,\n\t34,\n\t34,\n\t34,\n\t34,\n\t35,\n\t35,\n\t35,\n\t35,\n\t36,\n\t36,\n\t36,\n\t36,\n\t37,\n\t37,\n\t37,\n\t37,\n\t38,\n\t38,\n\t38,\n\t38,\n\t39,\n\t39,\n\t39,\n\t39,\n\t40,\n\t40,\n\t40,\n\t40,\n\t41,\n\t41,\n\t41,\n\t41,\n\t42,\n\t42,\n\t42,\n\t42,\n\t43,\n\t43,\n\t43,\n\t43,\n\t44,\n\t44,\n\t44,\n\t44,\n\t45,\n\t45,\n\t45,\n\t45,\n\t46,\n\t46,\n\t46,\n\t46,\n\t47,\n\t47,\n\t47,\n\t47,\n\t48,\n\t48,\n\t48,\n\t48,\n\t49,\n\t49,\n\t49,\n\t49,\n\t50,\n\t50,\n\t50,\n\t50,\n\t51,\n\t51,\n\t51,\n\t51,\n\t52,\n\t52,\n\t52,\n\t52,\n\t53,\n\t53,\n\t53,\n\t53,\n\t54,\n\t54,\n\t54,\n\t54,\n\t55,\n\t55,\n\t55,\n\t55,\n\t56,\n\t56,\n\t56,\n\t56,\n\t57,\n\t57,\n\t57,\n\t57,\n\t58,\n\t58,\n\t58,\n\t58,\n\t59,\n\t59,\n\t59,\n\t59,\n\t60,\n\t60,\n\t60,\n\t60,\n\t61,\n\t61,\n\t61,\n\t61,\n\t62,\n\t62,\n\t62,\n\t62,\n\t63,\n\t63,\n\t63,\n\t63,\n\n\t/* CONTEXT_MSB6, second last byte, */\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\n\t/* CONTEXT_UTF8, last byte. */\n\t/* ASCII range. */\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4,\n\t4,\n\t0,\n\t0,\n\t4,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8,\n\t12,\n\t16,\n\t12,\n\t12,\n\t20,\n\t12,\n\t16,\n\t24,\n\t28,\n\t12,\n\t12,\n\t32,\n\t12,\n\t36,\n\t12,\n\t44,\n\t44,\n\t44,\n\t44,\n\t44,\n\t44,\n\t44,\n\t44,\n\t44,\n\t44,\n\t32,\n\t32,\n\t24,\n\t40,\n\t28,\n\t12,\n\t12,\n\t48,\n\t52,\n\t52,\n\t52,\n\t48,\n\t52,\n\t52,\n\t52,\n\t48,\n\t52,\n\t52,\n\t52,\n\t52,\n\t52,\n\t48,\n\t52,\n\t52,\n\t52,\n\t52,\n\t52,\n\t48,\n\t52,\n\t52,\n\t52,\n\t52,\n\t52,\n\t24,\n\t12,\n\t28,\n\t12,\n\t12,\n\t12,\n\t56,\n\t60,\n\t60,\n\t60,\n\t56,\n\t60,\n\t60,\n\t60,\n\t56,\n\t60,\n\t60,\n\t60,\n\t60,\n\t60,\n\t56,\n\t60,\n\t60,\n\t60,\n\t60,\n\t60,\n\t56,\n\t60,\n\t60,\n\t60,\n\t60,\n\t60,\n\t24,\n\t12,\n\t28,\n\t12,\n\t0,\n\n\t/* UTF8 continuation byte range. */\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\n\t/* UTF8 lead byte range. */\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\t2,\n\t3,\n\n\t/* CONTEXT_UTF8 second last byte. */\n\t/* ASCII range. */\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t1,\n\t1,\n\t1,\n\t1,\n\t0,\n\n\t/* UTF8 continuation byte range. */\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\n\t/* UTF8 lead byte range. */\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\n\t/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */\n\t0,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t8,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t16,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t32,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t40,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t56,\n\n\t/* CONTEXT_SIGNED, second last byte. */\n\t0,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t1,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t2,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t3,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t4,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t5,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t7,\n}\n\ntype contextLUT []byte\n\nfunc getContextLUT(mode int) contextLUT {\n\treturn kContextLookup[mode<<9:]\n}\n\nfunc getContext(p1 byte, p2 byte, lut contextLUT) byte {\n\treturn lut[p1] | lut[256+int(p2)]\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/decode.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nconst (\n\tdecoderResultError           = 0\n\tdecoderResultSuccess         = 1\n\tdecoderResultNeedsMoreInput  = 2\n\tdecoderResultNeedsMoreOutput = 3\n)\n\n/**\n * Error code for detailed logging / production debugging.\n *\n * See ::BrotliDecoderGetErrorCode and ::BROTLI_LAST_ERROR_CODE.\n */\nconst (\n\tdecoderNoError                          = 0\n\tdecoderSuccess                          = 1\n\tdecoderNeedsMoreInput                   = 2\n\tdecoderNeedsMoreOutput                  = 3\n\tdecoderErrorFormatExuberantNibble       = -1\n\tdecoderErrorFormatReserved              = -2\n\tdecoderErrorFormatExuberantMetaNibble   = -3\n\tdecoderErrorFormatSimpleHuffmanAlphabet = -4\n\tdecoderErrorFormatSimpleHuffmanSame     = -5\n\tdecoderErrorFormatClSpace               = -6\n\tdecoderErrorFormatHuffmanSpace          = -7\n\tdecoderErrorFormatContextMapRepeat      = -8\n\tdecoderErrorFormatBlockLength1          = -9\n\tdecoderErrorFormatBlockLength2          = -10\n\tdecoderErrorFormatTransform             = -11\n\tdecoderErrorFormatDictionary            = -12\n\tdecoderErrorFormatWindowBits            = -13\n\tdecoderErrorFormatPadding1              = -14\n\tdecoderErrorFormatPadding2              = -15\n\tdecoderErrorFormatDistance              = -16\n\tdecoderErrorDictionaryNotSet            = -19\n\tdecoderErrorInvalidArguments            = -20\n\tdecoderErrorAllocContextModes           = -21\n\tdecoderErrorAllocTreeGroups             = -22\n\tdecoderErrorAllocContextMap             = -25\n\tdecoderErrorAllocRingBuffer1            = -26\n\tdecoderErrorAllocRingBuffer2            = -27\n\tdecoderErrorAllocBlockTypeTrees         = -30\n\tdecoderErrorUnreachable                 = -31\n)\n\nconst huffmanTableBits = 8\n\nconst huffmanTableMask = 0xFF\n\n/* We need the slack region for the following reasons:\n   - doing up to two 16-byte copies for fast backward copying\n   - inserting transformed dictionary word (5 prefix + 24 base + 8 suffix) */\nconst kRingBufferWriteAheadSlack uint32 = 42\n\nvar kCodeLengthCodeOrder = [codeLengthCodes]byte{1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15}\n\n/* Static prefix code for the complex code length code lengths. */\nvar kCodeLengthPrefixLength = [16]byte{2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 4}\n\nvar kCodeLengthPrefixValue = [16]byte{0, 4, 3, 2, 0, 4, 3, 1, 0, 4, 3, 2, 0, 4, 3, 5}\n\n/* Saves error code and converts it to BrotliDecoderResult. */\nfunc saveErrorCode(s *Reader, e int) int {\n\ts.error_code = int(e)\n\tswitch e {\n\tcase decoderSuccess:\n\t\treturn decoderResultSuccess\n\n\tcase decoderNeedsMoreInput:\n\t\treturn decoderResultNeedsMoreInput\n\n\tcase decoderNeedsMoreOutput:\n\t\treturn decoderResultNeedsMoreOutput\n\n\tdefault:\n\t\treturn decoderResultError\n\t}\n}\n\n/* Decodes WBITS by reading 1 - 7 bits, or 0x11 for \"Large Window Brotli\".\n   Precondition: bit-reader accumulator has at least 8 bits. */\nfunc decodeWindowBits(s *Reader, br *bitReader) int {\n\tvar n uint32\n\tvar large_window bool = s.large_window\n\ts.large_window = false\n\ttakeBits(br, 1, &n)\n\tif n == 0 {\n\t\ts.window_bits = 16\n\t\treturn decoderSuccess\n\t}\n\n\ttakeBits(br, 3, &n)\n\tif n != 0 {\n\t\ts.window_bits = 17 + n\n\t\treturn decoderSuccess\n\t}\n\n\ttakeBits(br, 3, &n)\n\tif n == 1 {\n\t\tif large_window {\n\t\t\ttakeBits(br, 1, &n)\n\t\t\tif n == 1 {\n\t\t\t\treturn decoderErrorFormatWindowBits\n\t\t\t}\n\n\t\t\ts.large_window = true\n\t\t\treturn decoderSuccess\n\t\t} else {\n\t\t\treturn decoderErrorFormatWindowBits\n\t\t}\n\t}\n\n\tif n != 0 {\n\t\ts.window_bits = 8 + n\n\t\treturn decoderSuccess\n\t}\n\n\ts.window_bits = 17\n\treturn decoderSuccess\n}\n\n/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */\nfunc decodeVarLenUint8(s *Reader, br *bitReader, value *uint32) int {\n\tvar bits uint32\n\tswitch s.substate_decode_uint8 {\n\tcase stateDecodeUint8None:\n\t\tif !safeReadBits(br, 1, &bits) {\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\n\t\tif bits == 0 {\n\t\t\t*value = 0\n\t\t\treturn decoderSuccess\n\t\t}\n\t\tfallthrough\n\n\t\t/* Fall through. */\n\tcase stateDecodeUint8Short:\n\t\tif !safeReadBits(br, 3, &bits) {\n\t\t\ts.substate_decode_uint8 = stateDecodeUint8Short\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\n\t\tif bits == 0 {\n\t\t\t*value = 1\n\t\t\ts.substate_decode_uint8 = stateDecodeUint8None\n\t\t\treturn decoderSuccess\n\t\t}\n\n\t\t/* Use output value as a temporary storage. It MUST be persisted. */\n\t\t*value = bits\n\t\tfallthrough\n\n\t\t/* Fall through. */\n\tcase stateDecodeUint8Long:\n\t\tif !safeReadBits(br, *value, &bits) {\n\t\t\ts.substate_decode_uint8 = stateDecodeUint8Long\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\n\t\t*value = (1 << *value) + bits\n\t\ts.substate_decode_uint8 = stateDecodeUint8None\n\t\treturn decoderSuccess\n\n\tdefault:\n\t\treturn decoderErrorUnreachable\n\t}\n}\n\n/* Decodes a metablock length and flags by reading 2 - 31 bits. */\nfunc decodeMetaBlockLength(s *Reader, br *bitReader) int {\n\tvar bits uint32\n\tvar i int\n\tfor {\n\t\tswitch s.substate_metablock_header {\n\t\tcase stateMetablockHeaderNone:\n\t\t\tif !safeReadBits(br, 1, &bits) {\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\tif bits != 0 {\n\t\t\t\ts.is_last_metablock = 1\n\t\t\t} else {\n\t\t\t\ts.is_last_metablock = 0\n\t\t\t}\n\t\t\ts.meta_block_remaining_len = 0\n\t\t\ts.is_uncompressed = 0\n\t\t\ts.is_metadata = 0\n\t\t\tif s.is_last_metablock == 0 {\n\t\t\t\ts.substate_metablock_header = stateMetablockHeaderNibbles\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.substate_metablock_header = stateMetablockHeaderEmpty\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockHeaderEmpty:\n\t\t\tif !safeReadBits(br, 1, &bits) {\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\tif bits != 0 {\n\t\t\t\ts.substate_metablock_header = stateMetablockHeaderNone\n\t\t\t\treturn decoderSuccess\n\t\t\t}\n\n\t\t\ts.substate_metablock_header = stateMetablockHeaderNibbles\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockHeaderNibbles:\n\t\t\tif !safeReadBits(br, 2, &bits) {\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\ts.size_nibbles = uint(byte(bits + 4))\n\t\t\ts.loop_counter = 0\n\t\t\tif bits == 3 {\n\t\t\t\ts.is_metadata = 1\n\t\t\t\ts.substate_metablock_header = stateMetablockHeaderReserved\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.substate_metablock_header = stateMetablockHeaderSize\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockHeaderSize:\n\t\t\ti = s.loop_counter\n\n\t\t\tfor ; i < int(s.size_nibbles); i++ {\n\t\t\t\tif !safeReadBits(br, 4, &bits) {\n\t\t\t\t\ts.loop_counter = i\n\t\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t\t}\n\n\t\t\t\tif uint(i+1) == s.size_nibbles && s.size_nibbles > 4 && bits == 0 {\n\t\t\t\t\treturn decoderErrorFormatExuberantNibble\n\t\t\t\t}\n\n\t\t\t\ts.meta_block_remaining_len |= int(bits << uint(i*4))\n\t\t\t}\n\n\t\t\ts.substate_metablock_header = stateMetablockHeaderUncompressed\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockHeaderUncompressed:\n\t\t\tif s.is_last_metablock == 0 {\n\t\t\t\tif !safeReadBits(br, 1, &bits) {\n\t\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t\t}\n\n\t\t\t\tif bits != 0 {\n\t\t\t\t\ts.is_uncompressed = 1\n\t\t\t\t} else {\n\t\t\t\t\ts.is_uncompressed = 0\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ts.meta_block_remaining_len++\n\t\t\ts.substate_metablock_header = stateMetablockHeaderNone\n\t\t\treturn decoderSuccess\n\n\t\tcase stateMetablockHeaderReserved:\n\t\t\tif !safeReadBits(br, 1, &bits) {\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\tif bits != 0 {\n\t\t\t\treturn decoderErrorFormatReserved\n\t\t\t}\n\n\t\t\ts.substate_metablock_header = stateMetablockHeaderBytes\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockHeaderBytes:\n\t\t\tif !safeReadBits(br, 2, &bits) {\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\tif bits == 0 {\n\t\t\t\ts.substate_metablock_header = stateMetablockHeaderNone\n\t\t\t\treturn decoderSuccess\n\t\t\t}\n\n\t\t\ts.size_nibbles = uint(byte(bits))\n\t\t\ts.substate_metablock_header = stateMetablockHeaderMetadata\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockHeaderMetadata:\n\t\t\ti = s.loop_counter\n\n\t\t\tfor ; i < int(s.size_nibbles); i++ {\n\t\t\t\tif !safeReadBits(br, 8, &bits) {\n\t\t\t\t\ts.loop_counter = i\n\t\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t\t}\n\n\t\t\t\tif uint(i+1) == s.size_nibbles && s.size_nibbles > 1 && bits == 0 {\n\t\t\t\t\treturn decoderErrorFormatExuberantMetaNibble\n\t\t\t\t}\n\n\t\t\t\ts.meta_block_remaining_len |= int(bits << uint(i*8))\n\t\t\t}\n\n\t\t\ts.meta_block_remaining_len++\n\t\t\ts.substate_metablock_header = stateMetablockHeaderNone\n\t\t\treturn decoderSuccess\n\n\t\tdefault:\n\t\t\treturn decoderErrorUnreachable\n\t\t}\n\t}\n}\n\n/* Decodes the Huffman code.\n   This method doesn't read data from the bit reader, BUT drops the amount of\n   bits that correspond to the decoded symbol.\n   bits MUST contain at least 15 (BROTLI_HUFFMAN_MAX_CODE_LENGTH) valid bits. */\nfunc decodeSymbol(bits uint32, table []huffmanCode, br *bitReader) uint32 {\n\ttable = table[bits&huffmanTableMask:]\n\tif table[0].bits > huffmanTableBits {\n\t\tvar nbits uint32 = uint32(table[0].bits) - huffmanTableBits\n\t\tdropBits(br, huffmanTableBits)\n\t\ttable = table[uint32(table[0].value)+((bits>>huffmanTableBits)&bitMask(nbits)):]\n\t}\n\n\tdropBits(br, uint32(table[0].bits))\n\treturn uint32(table[0].value)\n}\n\n/* Reads and decodes the next Huffman code from bit-stream.\n   This method peeks 16 bits of input and drops 0 - 15 of them. */\nfunc readSymbol(table []huffmanCode, br *bitReader) uint32 {\n\treturn decodeSymbol(get16BitsUnmasked(br), table, br)\n}\n\n/* Same as DecodeSymbol, but it is known that there is less than 15 bits of\n   input are currently available. */\nfunc safeDecodeSymbol(table []huffmanCode, br *bitReader, result *uint32) bool {\n\tvar val uint32\n\tvar available_bits uint32 = getAvailableBits(br)\n\tif available_bits == 0 {\n\t\tif table[0].bits == 0 {\n\t\t\t*result = uint32(table[0].value)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false /* No valid bits at all. */\n\t}\n\n\tval = uint32(getBitsUnmasked(br))\n\ttable = table[val&huffmanTableMask:]\n\tif table[0].bits <= huffmanTableBits {\n\t\tif uint32(table[0].bits) <= available_bits {\n\t\t\tdropBits(br, uint32(table[0].bits))\n\t\t\t*result = uint32(table[0].value)\n\t\t\treturn true\n\t\t} else {\n\t\t\treturn false /* Not enough bits for the first level. */\n\t\t}\n\t}\n\n\tif available_bits <= huffmanTableBits {\n\t\treturn false /* Not enough bits to move to the second level. */\n\t}\n\n\t/* Speculatively drop HUFFMAN_TABLE_BITS. */\n\tval = (val & bitMask(uint32(table[0].bits))) >> huffmanTableBits\n\n\tavailable_bits -= huffmanTableBits\n\ttable = table[uint32(table[0].value)+val:]\n\tif available_bits < uint32(table[0].bits) {\n\t\treturn false /* Not enough bits for the second level. */\n\t}\n\n\tdropBits(br, huffmanTableBits+uint32(table[0].bits))\n\t*result = uint32(table[0].value)\n\treturn true\n}\n\nfunc safeReadSymbol(table []huffmanCode, br *bitReader, result *uint32) bool {\n\tvar val uint32\n\tif safeGetBits(br, 15, &val) {\n\t\t*result = decodeSymbol(val, table, br)\n\t\treturn true\n\t}\n\n\treturn safeDecodeSymbol(table, br, result)\n}\n\n/* Makes a look-up in first level Huffman table. Peeks 8 bits. */\nfunc preloadSymbol(safe int, table []huffmanCode, br *bitReader, bits *uint32, value *uint32) {\n\tif safe != 0 {\n\t\treturn\n\t}\n\n\ttable = table[getBits(br, huffmanTableBits):]\n\t*bits = uint32(table[0].bits)\n\t*value = uint32(table[0].value)\n}\n\n/* Decodes the next Huffman code using data prepared by PreloadSymbol.\n   Reads 0 - 15 bits. Also peeks 8 following bits. */\nfunc readPreloadedSymbol(table []huffmanCode, br *bitReader, bits *uint32, value *uint32) uint32 {\n\tvar result uint32 = *value\n\tvar ext []huffmanCode\n\tif *bits > huffmanTableBits {\n\t\tvar val uint32 = get16BitsUnmasked(br)\n\t\text = table[val&huffmanTableMask:][*value:]\n\t\tvar mask uint32 = bitMask((*bits - huffmanTableBits))\n\t\tdropBits(br, huffmanTableBits)\n\t\text = ext[(val>>huffmanTableBits)&mask:]\n\t\tdropBits(br, uint32(ext[0].bits))\n\t\tresult = uint32(ext[0].value)\n\t} else {\n\t\tdropBits(br, *bits)\n\t}\n\n\tpreloadSymbol(0, table, br, bits, value)\n\treturn result\n}\n\nfunc log2Floor(x uint32) uint32 {\n\tvar result uint32 = 0\n\tfor x != 0 {\n\t\tx >>= 1\n\t\tresult++\n\t}\n\n\treturn result\n}\n\n/* Reads (s->symbol + 1) symbols.\n   Totally 1..4 symbols are read, 1..11 bits each.\n   The list of symbols MUST NOT contain duplicates. */\nfunc readSimpleHuffmanSymbols(alphabet_size uint32, max_symbol uint32, s *Reader) int {\n\tvar br *bitReader = &s.br\n\tvar max_bits uint32 = log2Floor(alphabet_size - 1)\n\tvar i uint32 = s.sub_loop_counter\n\t/* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */\n\n\tvar num_symbols uint32 = s.symbol\n\tfor i <= num_symbols {\n\t\tvar v uint32\n\t\tif !safeReadBits(br, max_bits, &v) {\n\t\t\ts.sub_loop_counter = i\n\t\t\ts.substate_huffman = stateHuffmanSimpleRead\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\n\t\tif v >= max_symbol {\n\t\t\treturn decoderErrorFormatSimpleHuffmanAlphabet\n\t\t}\n\n\t\ts.symbols_lists_array[i] = uint16(v)\n\t\ti++\n\t}\n\n\tfor i = 0; i < num_symbols; i++ {\n\t\tvar k uint32 = i + 1\n\t\tfor ; k <= num_symbols; k++ {\n\t\t\tif s.symbols_lists_array[i] == s.symbols_lists_array[k] {\n\t\t\t\treturn decoderErrorFormatSimpleHuffmanSame\n\t\t\t}\n\t\t}\n\t}\n\n\treturn decoderSuccess\n}\n\n/* Process single decoded symbol code length:\n   A) reset the repeat variable\n   B) remember code length (if it is not 0)\n   C) extend corresponding index-chain\n   D) reduce the Huffman space\n   E) update the histogram */\nfunc processSingleCodeLength(code_len uint32, symbol *uint32, repeat *uint32, space *uint32, prev_code_len *uint32, symbol_lists symbolList, code_length_histo []uint16, next_symbol []int) {\n\t*repeat = 0\n\tif code_len != 0 { /* code_len == 1..15 */\n\t\tsymbolListPut(symbol_lists, next_symbol[code_len], uint16(*symbol))\n\t\tnext_symbol[code_len] = int(*symbol)\n\t\t*prev_code_len = code_len\n\t\t*space -= 32768 >> code_len\n\t\tcode_length_histo[code_len]++\n\t}\n\n\t(*symbol)++\n}\n\n/* Process repeated symbol code length.\n    A) Check if it is the extension of previous repeat sequence; if the decoded\n       value is not BROTLI_REPEAT_PREVIOUS_CODE_LENGTH, then it is a new\n       symbol-skip\n    B) Update repeat variable\n    C) Check if operation is feasible (fits alphabet)\n    D) For each symbol do the same operations as in ProcessSingleCodeLength\n\n   PRECONDITION: code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH or\n                 code_len == BROTLI_REPEAT_ZERO_CODE_LENGTH */\nfunc processRepeatedCodeLength(code_len uint32, repeat_delta uint32, alphabet_size uint32, symbol *uint32, repeat *uint32, space *uint32, prev_code_len *uint32, repeat_code_len *uint32, symbol_lists symbolList, code_length_histo []uint16, next_symbol []int) {\n\tvar old_repeat uint32 /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */\n\tvar extra_bits uint32 = 3\n\tvar new_len uint32 = 0\n\tif code_len == repeatPreviousCodeLength {\n\t\tnew_len = *prev_code_len\n\t\textra_bits = 2\n\t}\n\n\tif *repeat_code_len != new_len {\n\t\t*repeat = 0\n\t\t*repeat_code_len = new_len\n\t}\n\n\told_repeat = *repeat\n\tif *repeat > 0 {\n\t\t*repeat -= 2\n\t\t*repeat <<= extra_bits\n\t}\n\n\t*repeat += repeat_delta + 3\n\trepeat_delta = *repeat - old_repeat\n\tif *symbol+repeat_delta > alphabet_size {\n\t\t*symbol = alphabet_size\n\t\t*space = 0xFFFFF\n\t\treturn\n\t}\n\n\tif *repeat_code_len != 0 {\n\t\tvar last uint = uint(*symbol + repeat_delta)\n\t\tvar next int = next_symbol[*repeat_code_len]\n\t\tfor {\n\t\t\tsymbolListPut(symbol_lists, next, uint16(*symbol))\n\t\t\tnext = int(*symbol)\n\t\t\t(*symbol)++\n\t\t\tif (*symbol) == uint32(last) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tnext_symbol[*repeat_code_len] = next\n\t\t*space -= repeat_delta << (15 - *repeat_code_len)\n\t\tcode_length_histo[*repeat_code_len] = uint16(uint32(code_length_histo[*repeat_code_len]) + repeat_delta)\n\t} else {\n\t\t*symbol += repeat_delta\n\t}\n}\n\n/* Reads and decodes symbol codelengths. */\nfunc readSymbolCodeLengths(alphabet_size uint32, s *Reader) int {\n\tvar br *bitReader = &s.br\n\tvar symbol uint32 = s.symbol\n\tvar repeat uint32 = s.repeat\n\tvar space uint32 = s.space\n\tvar prev_code_len uint32 = s.prev_code_len\n\tvar repeat_code_len uint32 = s.repeat_code_len\n\tvar symbol_lists symbolList = s.symbol_lists\n\tvar code_length_histo []uint16 = s.code_length_histo[:]\n\tvar next_symbol []int = s.next_symbol[:]\n\tif !warmupBitReader(br) {\n\t\treturn decoderNeedsMoreInput\n\t}\n\tvar p []huffmanCode\n\tfor symbol < alphabet_size && space > 0 {\n\t\tp = s.table[:]\n\t\tvar code_len uint32\n\t\tif !checkInputAmount(br, shortFillBitWindowRead) {\n\t\t\ts.symbol = symbol\n\t\t\ts.repeat = repeat\n\t\t\ts.prev_code_len = prev_code_len\n\t\t\ts.repeat_code_len = repeat_code_len\n\t\t\ts.space = space\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\n\t\tfillBitWindow16(br)\n\t\tp = p[getBitsUnmasked(br)&uint64(bitMask(huffmanMaxCodeLengthCodeLength)):]\n\t\tdropBits(br, uint32(p[0].bits)) /* Use 1..5 bits. */\n\t\tcode_len = uint32(p[0].value)   /* code_len == 0..17 */\n\t\tif code_len < repeatPreviousCodeLength {\n\t\t\tprocessSingleCodeLength(code_len, &symbol, &repeat, &space, &prev_code_len, symbol_lists, code_length_histo, next_symbol) /* code_len == 16..17, extra_bits == 2..3 */\n\t\t} else {\n\t\t\tvar extra_bits uint32\n\t\t\tif code_len == repeatPreviousCodeLength {\n\t\t\t\textra_bits = 2\n\t\t\t} else {\n\t\t\t\textra_bits = 3\n\t\t\t}\n\t\t\tvar repeat_delta uint32 = uint32(getBitsUnmasked(br)) & bitMask(extra_bits)\n\t\t\tdropBits(br, extra_bits)\n\t\t\tprocessRepeatedCodeLength(code_len, repeat_delta, alphabet_size, &symbol, &repeat, &space, &prev_code_len, &repeat_code_len, symbol_lists, code_length_histo, next_symbol)\n\t\t}\n\t}\n\n\ts.space = space\n\treturn decoderSuccess\n}\n\nfunc safeReadSymbolCodeLengths(alphabet_size uint32, s *Reader) int {\n\tvar br *bitReader = &s.br\n\tvar get_byte bool = false\n\tvar p []huffmanCode\n\tfor s.symbol < alphabet_size && s.space > 0 {\n\t\tp = s.table[:]\n\t\tvar code_len uint32\n\t\tvar available_bits uint32\n\t\tvar bits uint32 = 0\n\t\tif get_byte && !pullByte(br) {\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\t\tget_byte = false\n\t\tavailable_bits = getAvailableBits(br)\n\t\tif available_bits != 0 {\n\t\t\tbits = uint32(getBitsUnmasked(br))\n\t\t}\n\n\t\tp = p[bits&bitMask(huffmanMaxCodeLengthCodeLength):]\n\t\tif uint32(p[0].bits) > available_bits {\n\t\t\tget_byte = true\n\t\t\tcontinue\n\t\t}\n\n\t\tcode_len = uint32(p[0].value) /* code_len == 0..17 */\n\t\tif code_len < repeatPreviousCodeLength {\n\t\t\tdropBits(br, uint32(p[0].bits))\n\t\t\tprocessSingleCodeLength(code_len, &s.symbol, &s.repeat, &s.space, &s.prev_code_len, s.symbol_lists, s.code_length_histo[:], s.next_symbol[:]) /* code_len == 16..17, extra_bits == 2..3 */\n\t\t} else {\n\t\t\tvar extra_bits uint32 = code_len - 14\n\t\t\tvar repeat_delta uint32 = (bits >> p[0].bits) & bitMask(extra_bits)\n\t\t\tif available_bits < uint32(p[0].bits)+extra_bits {\n\t\t\t\tget_byte = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tdropBits(br, uint32(p[0].bits)+extra_bits)\n\t\t\tprocessRepeatedCodeLength(code_len, repeat_delta, alphabet_size, &s.symbol, &s.repeat, &s.space, &s.prev_code_len, &s.repeat_code_len, s.symbol_lists, s.code_length_histo[:], s.next_symbol[:])\n\t\t}\n\t}\n\n\treturn decoderSuccess\n}\n\n/* Reads and decodes 15..18 codes using static prefix code.\n   Each code is 2..4 bits long. In total 30..72 bits are used. */\nfunc readCodeLengthCodeLengths(s *Reader) int {\n\tvar br *bitReader = &s.br\n\tvar num_codes uint32 = s.repeat\n\tvar space uint32 = s.space\n\tvar i uint32 = s.sub_loop_counter\n\tfor ; i < codeLengthCodes; i++ {\n\t\tvar code_len_idx byte = kCodeLengthCodeOrder[i]\n\t\tvar ix uint32\n\t\tvar v uint32\n\t\tif !safeGetBits(br, 4, &ix) {\n\t\t\tvar available_bits uint32 = getAvailableBits(br)\n\t\t\tif available_bits != 0 {\n\t\t\t\tix = uint32(getBitsUnmasked(br) & 0xF)\n\t\t\t} else {\n\t\t\t\tix = 0\n\t\t\t}\n\n\t\t\tif uint32(kCodeLengthPrefixLength[ix]) > available_bits {\n\t\t\t\ts.sub_loop_counter = i\n\t\t\t\ts.repeat = num_codes\n\t\t\t\ts.space = space\n\t\t\t\ts.substate_huffman = stateHuffmanComplex\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\t\t}\n\n\t\tv = uint32(kCodeLengthPrefixValue[ix])\n\t\tdropBits(br, uint32(kCodeLengthPrefixLength[ix]))\n\t\ts.code_length_code_lengths[code_len_idx] = byte(v)\n\t\tif v != 0 {\n\t\t\tspace = space - (32 >> v)\n\t\t\tnum_codes++\n\t\t\ts.code_length_histo[v]++\n\t\t\tif space-1 >= 32 {\n\t\t\t\t/* space is 0 or wrapped around. */\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif num_codes != 1 && space != 0 {\n\t\treturn decoderErrorFormatClSpace\n\t}\n\n\treturn decoderSuccess\n}\n\n/* Decodes the Huffman tables.\n   There are 2 scenarios:\n    A) Huffman code contains only few symbols (1..4). Those symbols are read\n       directly; their code lengths are defined by the number of symbols.\n       For this scenario 4 - 49 bits will be read.\n\n    B) 2-phase decoding:\n    B.1) Small Huffman table is decoded; it is specified with code lengths\n         encoded with predefined entropy code. 32 - 74 bits are used.\n    B.2) Decoded table is used to decode code lengths of symbols in resulting\n         Huffman table. In worst case 3520 bits are read. */\nfunc readHuffmanCode(alphabet_size uint32, max_symbol uint32, table []huffmanCode, opt_table_size *uint32, s *Reader) int {\n\tvar br *bitReader = &s.br\n\n\t/* Unnecessary masking, but might be good for safety. */\n\talphabet_size &= 0x7FF\n\n\t/* State machine. */\n\tfor {\n\t\tswitch s.substate_huffman {\n\t\tcase stateHuffmanNone:\n\t\t\tif !safeReadBits(br, 2, &s.sub_loop_counter) {\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\t/* The value is used as follows:\n\t\t\t   1 for simple code;\n\t\t\t   0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */\n\t\t\tif s.sub_loop_counter != 1 {\n\t\t\t\ts.space = 32\n\t\t\t\ts.repeat = 0 /* num_codes */\n\t\t\t\tvar i int\n\t\t\t\tfor i = 0; i <= huffmanMaxCodeLengthCodeLength; i++ {\n\t\t\t\t\ts.code_length_histo[i] = 0\n\t\t\t\t}\n\n\t\t\t\tfor i = 0; i < codeLengthCodes; i++ {\n\t\t\t\t\ts.code_length_code_lengths[i] = 0\n\t\t\t\t}\n\n\t\t\t\ts.substate_huffman = stateHuffmanComplex\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfallthrough\n\n\t\t\t/* Read symbols, codes & code lengths directly. */\n\t\tcase stateHuffmanSimpleSize:\n\t\t\tif !safeReadBits(br, 2, &s.symbol) { /* num_symbols */\n\t\t\t\ts.substate_huffman = stateHuffmanSimpleSize\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\ts.sub_loop_counter = 0\n\t\t\tfallthrough\n\n\t\tcase stateHuffmanSimpleRead:\n\t\t\t{\n\t\t\t\tvar result int = readSimpleHuffmanSymbols(alphabet_size, max_symbol, s)\n\t\t\t\tif result != decoderSuccess {\n\t\t\t\t\treturn result\n\t\t\t\t}\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase stateHuffmanSimpleBuild:\n\t\t\tvar table_size uint32\n\t\t\tif s.symbol == 3 {\n\t\t\t\tvar bits uint32\n\t\t\t\tif !safeReadBits(br, 1, &bits) {\n\t\t\t\t\ts.substate_huffman = stateHuffmanSimpleBuild\n\t\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t\t}\n\n\t\t\t\ts.symbol += bits\n\t\t\t}\n\n\t\t\ttable_size = buildSimpleHuffmanTable(table, huffmanTableBits, s.symbols_lists_array[:], s.symbol)\n\t\t\tif opt_table_size != nil {\n\t\t\t\t*opt_table_size = table_size\n\t\t\t}\n\n\t\t\ts.substate_huffman = stateHuffmanNone\n\t\t\treturn decoderSuccess\n\n\t\t\t/* Decode Huffman-coded code lengths. */\n\t\tcase stateHuffmanComplex:\n\t\t\t{\n\t\t\t\tvar i uint32\n\t\t\t\tvar result int = readCodeLengthCodeLengths(s)\n\t\t\t\tif result != decoderSuccess {\n\t\t\t\t\treturn result\n\t\t\t\t}\n\n\t\t\t\tbuildCodeLengthsHuffmanTable(s.table[:], s.code_length_code_lengths[:], s.code_length_histo[:])\n\t\t\t\tfor i = 0; i < 16; i++ {\n\t\t\t\t\ts.code_length_histo[i] = 0\n\t\t\t\t}\n\n\t\t\t\tfor i = 0; i <= huffmanMaxCodeLength; i++ {\n\t\t\t\t\ts.next_symbol[i] = int(i) - (huffmanMaxCodeLength + 1)\n\t\t\t\t\tsymbolListPut(s.symbol_lists, s.next_symbol[i], 0xFFFF)\n\t\t\t\t}\n\n\t\t\t\ts.symbol = 0\n\t\t\t\ts.prev_code_len = initialRepeatedCodeLength\n\t\t\t\ts.repeat = 0\n\t\t\t\ts.repeat_code_len = 0\n\t\t\t\ts.space = 32768\n\t\t\t\ts.substate_huffman = stateHuffmanLengthSymbols\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase stateHuffmanLengthSymbols:\n\t\t\tvar table_size uint32\n\t\t\tvar result int = readSymbolCodeLengths(max_symbol, s)\n\t\t\tif result == decoderNeedsMoreInput {\n\t\t\t\tresult = safeReadSymbolCodeLengths(max_symbol, s)\n\t\t\t}\n\n\t\t\tif result != decoderSuccess {\n\t\t\t\treturn result\n\t\t\t}\n\n\t\t\tif s.space != 0 {\n\t\t\t\treturn decoderErrorFormatHuffmanSpace\n\t\t\t}\n\n\t\t\ttable_size = buildHuffmanTable(table, huffmanTableBits, s.symbol_lists, s.code_length_histo[:])\n\t\t\tif opt_table_size != nil {\n\t\t\t\t*opt_table_size = table_size\n\t\t\t}\n\n\t\t\ts.substate_huffman = stateHuffmanNone\n\t\t\treturn decoderSuccess\n\n\t\tdefault:\n\t\t\treturn decoderErrorUnreachable\n\t\t}\n\t}\n}\n\n/* Decodes a block length by reading 3..39 bits. */\nfunc readBlockLength(table []huffmanCode, br *bitReader) uint32 {\n\tvar code uint32\n\tvar nbits uint32\n\tcode = readSymbol(table, br)\n\tnbits = kBlockLengthPrefixCode[code].nbits /* nbits == 2..24 */\n\treturn kBlockLengthPrefixCode[code].offset + readBits(br, nbits)\n}\n\n/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then\n   reading can't be continued with ReadBlockLength. */\nfunc safeReadBlockLength(s *Reader, result *uint32, table []huffmanCode, br *bitReader) bool {\n\tvar index uint32\n\tif s.substate_read_block_length == stateReadBlockLengthNone {\n\t\tif !safeReadSymbol(table, br, &index) {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\tindex = s.block_length_index\n\t}\n\t{\n\t\tvar bits uint32 /* nbits == 2..24 */\n\t\tvar nbits uint32 = kBlockLengthPrefixCode[index].nbits\n\t\tif !safeReadBits(br, nbits, &bits) {\n\t\t\ts.block_length_index = index\n\t\t\ts.substate_read_block_length = stateReadBlockLengthSuffix\n\t\t\treturn false\n\t\t}\n\n\t\t*result = kBlockLengthPrefixCode[index].offset + bits\n\t\ts.substate_read_block_length = stateReadBlockLengthNone\n\t\treturn true\n\t}\n}\n\n/* Transform:\n    1) initialize list L with values 0, 1,... 255\n    2) For each input element X:\n    2.1) let Y = L[X]\n    2.2) remove X-th element from L\n    2.3) prepend Y to L\n    2.4) append Y to output\n\n   In most cases max(Y) <= 7, so most of L remains intact.\n   To reduce the cost of initialization, we reuse L, remember the upper bound\n   of Y values, and reinitialize only first elements in L.\n\n   Most of input values are 0 and 1. To reduce number of branches, we replace\n   inner for loop with do-while. */\nfunc inverseMoveToFrontTransform(v []byte, v_len uint32, state *Reader) {\n\tvar mtf [256]byte\n\tvar i int\n\tfor i = 1; i < 256; i++ {\n\t\tmtf[i] = byte(i)\n\t}\n\tvar mtf_1 byte\n\n\t/* Transform the input. */\n\tfor i = 0; uint32(i) < v_len; i++ {\n\t\tvar index int = int(v[i])\n\t\tvar value byte = mtf[index]\n\t\tv[i] = value\n\t\tmtf_1 = value\n\t\tfor index >= 1 {\n\t\t\tindex--\n\t\t\tmtf[index+1] = mtf[index]\n\t\t}\n\n\t\tmtf[0] = mtf_1\n\t}\n}\n\n/* Decodes a series of Huffman table using ReadHuffmanCode function. */\nfunc huffmanTreeGroupDecode(group *huffmanTreeGroup, s *Reader) int {\n\tif s.substate_tree_group != stateTreeGroupLoop {\n\t\ts.next = group.codes\n\t\ts.htree_index = 0\n\t\ts.substate_tree_group = stateTreeGroupLoop\n\t}\n\n\tfor s.htree_index < int(group.num_htrees) {\n\t\tvar table_size uint32\n\t\tvar result int = readHuffmanCode(uint32(group.alphabet_size), uint32(group.max_symbol), s.next, &table_size, s)\n\t\tif result != decoderSuccess {\n\t\t\treturn result\n\t\t}\n\t\tgroup.htrees[s.htree_index] = s.next\n\t\ts.next = s.next[table_size:]\n\t\ts.htree_index++\n\t}\n\n\ts.substate_tree_group = stateTreeGroupNone\n\treturn decoderSuccess\n}\n\n/* Decodes a context map.\n   Decoding is done in 4 phases:\n    1) Read auxiliary information (6..16 bits) and allocate memory.\n       In case of trivial context map, decoding is finished at this phase.\n    2) Decode Huffman table using ReadHuffmanCode function.\n       This table will be used for reading context map items.\n    3) Read context map items; \"0\" values could be run-length encoded.\n    4) Optionally, apply InverseMoveToFront transform to the resulting map. */\nfunc decodeContextMap(context_map_size uint32, num_htrees *uint32, context_map_arg *[]byte, s *Reader) int {\n\tvar br *bitReader = &s.br\n\tvar result int = decoderSuccess\n\n\tswitch int(s.substate_context_map) {\n\tcase stateContextMapNone:\n\t\tresult = decodeVarLenUint8(s, br, num_htrees)\n\t\tif result != decoderSuccess {\n\t\t\treturn result\n\t\t}\n\n\t\t(*num_htrees)++\n\t\ts.context_index = 0\n\t\t*context_map_arg = make([]byte, uint(context_map_size))\n\t\tif *context_map_arg == nil {\n\t\t\treturn decoderErrorAllocContextMap\n\t\t}\n\n\t\tif *num_htrees <= 1 {\n\t\t\tfor i := 0; i < int(context_map_size); i++ {\n\t\t\t\t(*context_map_arg)[i] = 0\n\t\t\t}\n\t\t\treturn decoderSuccess\n\t\t}\n\n\t\ts.substate_context_map = stateContextMapReadPrefix\n\t\tfallthrough\n\t/* Fall through. */\n\tcase stateContextMapReadPrefix:\n\t\t{\n\t\t\tvar bits uint32\n\n\t\t\t/* In next stage ReadHuffmanCode uses at least 4 bits, so it is safe\n\t\t\t   to peek 4 bits ahead. */\n\t\t\tif !safeGetBits(br, 5, &bits) {\n\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t}\n\n\t\t\tif bits&1 != 0 { /* Use RLE for zeros. */\n\t\t\t\ts.max_run_length_prefix = (bits >> 1) + 1\n\t\t\t\tdropBits(br, 5)\n\t\t\t} else {\n\t\t\t\ts.max_run_length_prefix = 0\n\t\t\t\tdropBits(br, 1)\n\t\t\t}\n\n\t\t\ts.substate_context_map = stateContextMapHuffman\n\t\t}\n\t\tfallthrough\n\n\t\t/* Fall through. */\n\tcase stateContextMapHuffman:\n\t\t{\n\t\t\tvar alphabet_size uint32 = *num_htrees + s.max_run_length_prefix\n\t\t\tresult = readHuffmanCode(alphabet_size, alphabet_size, s.context_map_table[:], nil, s)\n\t\t\tif result != decoderSuccess {\n\t\t\t\treturn result\n\t\t\t}\n\t\t\ts.code = 0xFFFF\n\t\t\ts.substate_context_map = stateContextMapDecode\n\t\t}\n\t\tfallthrough\n\n\t\t/* Fall through. */\n\tcase stateContextMapDecode:\n\t\t{\n\t\t\tvar context_index uint32 = s.context_index\n\t\t\tvar max_run_length_prefix uint32 = s.max_run_length_prefix\n\t\t\tvar context_map []byte = *context_map_arg\n\t\t\tvar code uint32 = s.code\n\t\t\tvar skip_preamble bool = (code != 0xFFFF)\n\t\t\tfor context_index < context_map_size || skip_preamble {\n\t\t\t\tif !skip_preamble {\n\t\t\t\t\tif !safeReadSymbol(s.context_map_table[:], br, &code) {\n\t\t\t\t\t\ts.code = 0xFFFF\n\t\t\t\t\t\ts.context_index = context_index\n\t\t\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t\t\t}\n\n\t\t\t\t\tif code == 0 {\n\t\t\t\t\t\tcontext_map[context_index] = 0\n\t\t\t\t\t\tcontext_index++\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\tif code > max_run_length_prefix {\n\t\t\t\t\t\tcontext_map[context_index] = byte(code - max_run_length_prefix)\n\t\t\t\t\t\tcontext_index++\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tskip_preamble = false\n\t\t\t\t}\n\n\t\t\t\t/* RLE sub-stage. */\n\t\t\t\t{\n\t\t\t\t\tvar reps uint32\n\t\t\t\t\tif !safeReadBits(br, code, &reps) {\n\t\t\t\t\t\ts.code = code\n\t\t\t\t\t\ts.context_index = context_index\n\t\t\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t\t\t}\n\n\t\t\t\t\treps += 1 << code\n\t\t\t\t\tif context_index+reps > context_map_size {\n\t\t\t\t\t\treturn decoderErrorFormatContextMapRepeat\n\t\t\t\t\t}\n\n\t\t\t\t\tfor {\n\t\t\t\t\t\tcontext_map[context_index] = 0\n\t\t\t\t\t\tcontext_index++\n\t\t\t\t\t\treps--\n\t\t\t\t\t\tif reps == 0 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfallthrough\n\n\tcase stateContextMapTransform:\n\t\tvar bits uint32\n\t\tif !safeReadBits(br, 1, &bits) {\n\t\t\ts.substate_context_map = stateContextMapTransform\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\n\t\tif bits != 0 {\n\t\t\tinverseMoveToFrontTransform(*context_map_arg, context_map_size, s)\n\t\t}\n\n\t\ts.substate_context_map = stateContextMapNone\n\t\treturn decoderSuccess\n\n\tdefault:\n\t\treturn decoderErrorUnreachable\n\t}\n}\n\n/* Decodes a command or literal and updates block type ring-buffer.\n   Reads 3..54 bits. */\nfunc decodeBlockTypeAndLength(safe int, s *Reader, tree_type int) bool {\n\tvar max_block_type uint32 = s.num_block_types[tree_type]\n\ttype_tree := s.block_type_trees[tree_type*huffmanMaxSize258:]\n\tlen_tree := s.block_len_trees[tree_type*huffmanMaxSize26:]\n\tvar br *bitReader = &s.br\n\tvar ringbuffer []uint32 = s.block_type_rb[tree_type*2:]\n\tvar block_type uint32\n\tif max_block_type <= 1 {\n\t\treturn false\n\t}\n\n\t/* Read 0..15 + 3..39 bits. */\n\tif safe == 0 {\n\t\tblock_type = readSymbol(type_tree, br)\n\t\ts.block_length[tree_type] = readBlockLength(len_tree, br)\n\t} else {\n\t\tvar memento bitReaderState\n\t\tbitReaderSaveState(br, &memento)\n\t\tif !safeReadSymbol(type_tree, br, &block_type) {\n\t\t\treturn false\n\t\t}\n\t\tif !safeReadBlockLength(s, &s.block_length[tree_type], len_tree, br) {\n\t\t\ts.substate_read_block_length = stateReadBlockLengthNone\n\t\t\tbitReaderRestoreState(br, &memento)\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif block_type == 1 {\n\t\tblock_type = ringbuffer[1] + 1\n\t} else if block_type == 0 {\n\t\tblock_type = ringbuffer[0]\n\t} else {\n\t\tblock_type -= 2\n\t}\n\n\tif block_type >= max_block_type {\n\t\tblock_type -= max_block_type\n\t}\n\n\tringbuffer[0] = ringbuffer[1]\n\tringbuffer[1] = block_type\n\treturn true\n}\n\nfunc detectTrivialLiteralBlockTypes(s *Reader) {\n\tvar i uint\n\tfor i = 0; i < 8; i++ {\n\t\ts.trivial_literal_contexts[i] = 0\n\t}\n\tfor i = 0; uint32(i) < s.num_block_types[0]; i++ {\n\t\tvar offset uint = i << literalContextBits\n\t\tvar error uint = 0\n\t\tvar sample uint = uint(s.context_map[offset])\n\t\tvar j uint\n\t\tfor j = 0; j < 1<<literalContextBits; {\n\t\t\tvar k int\n\t\t\tfor k = 0; k < 4; k++ {\n\t\t\t\terror |= uint(s.context_map[offset+j]) ^ sample\n\t\t\t\tj++\n\t\t\t}\n\t\t}\n\n\t\tif error == 0 {\n\t\t\ts.trivial_literal_contexts[i>>5] |= 1 << (i & 31)\n\t\t}\n\t}\n}\n\nfunc prepareLiteralDecoding(s *Reader) {\n\tvar context_mode byte\n\tvar trivial uint\n\tvar block_type uint32 = s.block_type_rb[1]\n\tvar context_offset uint32 = block_type << literalContextBits\n\ts.context_map_slice = s.context_map[context_offset:]\n\ttrivial = uint(s.trivial_literal_contexts[block_type>>5])\n\ts.trivial_literal_context = int((trivial >> (block_type & 31)) & 1)\n\ts.literal_htree = []huffmanCode(s.literal_hgroup.htrees[s.context_map_slice[0]])\n\tcontext_mode = s.context_modes[block_type] & 3\n\ts.context_lookup = getContextLUT(int(context_mode))\n}\n\n/* Decodes the block type and updates the state for literal context.\n   Reads 3..54 bits. */\nfunc decodeLiteralBlockSwitchInternal(safe int, s *Reader) bool {\n\tif !decodeBlockTypeAndLength(safe, s, 0) {\n\t\treturn false\n\t}\n\n\tprepareLiteralDecoding(s)\n\treturn true\n}\n\nfunc decodeLiteralBlockSwitch(s *Reader) {\n\tdecodeLiteralBlockSwitchInternal(0, s)\n}\n\nfunc safeDecodeLiteralBlockSwitch(s *Reader) bool {\n\treturn decodeLiteralBlockSwitchInternal(1, s)\n}\n\n/* Block switch for insert/copy length.\n   Reads 3..54 bits. */\nfunc decodeCommandBlockSwitchInternal(safe int, s *Reader) bool {\n\tif !decodeBlockTypeAndLength(safe, s, 1) {\n\t\treturn false\n\t}\n\n\ts.htree_command = []huffmanCode(s.insert_copy_hgroup.htrees[s.block_type_rb[3]])\n\treturn true\n}\n\nfunc decodeCommandBlockSwitch(s *Reader) {\n\tdecodeCommandBlockSwitchInternal(0, s)\n}\n\nfunc safeDecodeCommandBlockSwitch(s *Reader) bool {\n\treturn decodeCommandBlockSwitchInternal(1, s)\n}\n\n/* Block switch for distance codes.\n   Reads 3..54 bits. */\nfunc decodeDistanceBlockSwitchInternal(safe int, s *Reader) bool {\n\tif !decodeBlockTypeAndLength(safe, s, 2) {\n\t\treturn false\n\t}\n\n\ts.dist_context_map_slice = s.dist_context_map[s.block_type_rb[5]<<distanceContextBits:]\n\ts.dist_htree_index = s.dist_context_map_slice[s.distance_context]\n\treturn true\n}\n\nfunc decodeDistanceBlockSwitch(s *Reader) {\n\tdecodeDistanceBlockSwitchInternal(0, s)\n}\n\nfunc safeDecodeDistanceBlockSwitch(s *Reader) bool {\n\treturn decodeDistanceBlockSwitchInternal(1, s)\n}\n\nfunc unwrittenBytes(s *Reader, wrap bool) uint {\n\tvar pos uint\n\tif wrap && s.pos > s.ringbuffer_size {\n\t\tpos = uint(s.ringbuffer_size)\n\t} else {\n\t\tpos = uint(s.pos)\n\t}\n\tvar partial_pos_rb uint = (s.rb_roundtrips * uint(s.ringbuffer_size)) + pos\n\treturn partial_pos_rb - s.partial_pos_out\n}\n\n/* Dumps output.\n   Returns BROTLI_DECODER_NEEDS_MORE_OUTPUT only if there is more output to push\n   and either ring-buffer is as big as window size, or |force| is true. */\nfunc writeRingBuffer(s *Reader, available_out *uint, next_out *[]byte, total_out *uint, force bool) int {\n\tstart := s.ringbuffer[s.partial_pos_out&uint(s.ringbuffer_mask):]\n\tvar to_write uint = unwrittenBytes(s, true)\n\tvar num_written uint = *available_out\n\tif num_written > to_write {\n\t\tnum_written = to_write\n\t}\n\n\tif s.meta_block_remaining_len < 0 {\n\t\treturn decoderErrorFormatBlockLength1\n\t}\n\n\tif next_out != nil && *next_out == nil {\n\t\t*next_out = start\n\t} else {\n\t\tif next_out != nil {\n\t\t\tcopy(*next_out, start[:num_written])\n\t\t\t*next_out = (*next_out)[num_written:]\n\t\t}\n\t}\n\n\t*available_out -= num_written\n\ts.partial_pos_out += num_written\n\tif total_out != nil {\n\t\t*total_out = s.partial_pos_out\n\t}\n\n\tif num_written < to_write {\n\t\tif s.ringbuffer_size == 1<<s.window_bits || force {\n\t\t\treturn decoderNeedsMoreOutput\n\t\t} else {\n\t\t\treturn decoderSuccess\n\t\t}\n\t}\n\n\t/* Wrap ring buffer only if it has reached its maximal size. */\n\tif s.ringbuffer_size == 1<<s.window_bits && s.pos >= s.ringbuffer_size {\n\t\ts.pos -= s.ringbuffer_size\n\t\ts.rb_roundtrips++\n\t\tif uint(s.pos) != 0 {\n\t\t\ts.should_wrap_ringbuffer = 1\n\t\t} else {\n\t\t\ts.should_wrap_ringbuffer = 0\n\t\t}\n\t}\n\n\treturn decoderSuccess\n}\n\nfunc wrapRingBuffer(s *Reader) {\n\tif s.should_wrap_ringbuffer != 0 {\n\t\tcopy(s.ringbuffer, s.ringbuffer_end[:uint(s.pos)])\n\t\ts.should_wrap_ringbuffer = 0\n\t}\n}\n\n/* Allocates ring-buffer.\n\n   s->ringbuffer_size MUST be updated by BrotliCalculateRingBufferSize before\n   this function is called.\n\n   Last two bytes of ring-buffer are initialized to 0, so context calculation\n   could be done uniformly for the first two and all other positions. */\nfunc ensureRingBuffer(s *Reader) bool {\n\tvar old_ringbuffer []byte\n\tif s.ringbuffer_size == s.new_ringbuffer_size {\n\t\treturn true\n\t}\n\tspaceNeeded := int(s.new_ringbuffer_size) + int(kRingBufferWriteAheadSlack)\n\tif len(s.ringbuffer) < spaceNeeded {\n\t\told_ringbuffer = s.ringbuffer\n\t\ts.ringbuffer = make([]byte, spaceNeeded)\n\t}\n\n\ts.ringbuffer[s.new_ringbuffer_size-2] = 0\n\ts.ringbuffer[s.new_ringbuffer_size-1] = 0\n\n\tif old_ringbuffer != nil {\n\t\tcopy(s.ringbuffer, old_ringbuffer[:uint(s.pos)])\n\t}\n\n\ts.ringbuffer_size = s.new_ringbuffer_size\n\ts.ringbuffer_mask = s.new_ringbuffer_size - 1\n\ts.ringbuffer_end = s.ringbuffer[s.ringbuffer_size:]\n\n\treturn true\n}\n\nfunc copyUncompressedBlockToOutput(available_out *uint, next_out *[]byte, total_out *uint, s *Reader) int {\n\t/* TODO: avoid allocation for single uncompressed block. */\n\tif !ensureRingBuffer(s) {\n\t\treturn decoderErrorAllocRingBuffer1\n\t}\n\n\t/* State machine */\n\tfor {\n\t\tswitch s.substate_uncompressed {\n\t\tcase stateUncompressedNone:\n\t\t\t{\n\t\t\t\tvar nbytes int = int(getRemainingBytes(&s.br))\n\t\t\t\tif nbytes > s.meta_block_remaining_len {\n\t\t\t\t\tnbytes = s.meta_block_remaining_len\n\t\t\t\t}\n\n\t\t\t\tif s.pos+nbytes > s.ringbuffer_size {\n\t\t\t\t\tnbytes = s.ringbuffer_size - s.pos\n\t\t\t\t}\n\n\t\t\t\t/* Copy remaining bytes from s->br.buf_ to ring-buffer. */\n\t\t\t\tcopyBytes(s.ringbuffer[s.pos:], &s.br, uint(nbytes))\n\n\t\t\t\ts.pos += nbytes\n\t\t\t\ts.meta_block_remaining_len -= nbytes\n\t\t\t\tif s.pos < 1<<s.window_bits {\n\t\t\t\t\tif s.meta_block_remaining_len == 0 {\n\t\t\t\t\t\treturn decoderSuccess\n\t\t\t\t\t}\n\n\t\t\t\t\treturn decoderNeedsMoreInput\n\t\t\t\t}\n\n\t\t\t\ts.substate_uncompressed = stateUncompressedWrite\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase stateUncompressedWrite:\n\t\t\t{\n\t\t\t\tresult := writeRingBuffer(s, available_out, next_out, total_out, false)\n\t\t\t\tif result != decoderSuccess {\n\t\t\t\t\treturn result\n\t\t\t\t}\n\n\t\t\t\tif s.ringbuffer_size == 1<<s.window_bits {\n\t\t\t\t\ts.max_distance = s.max_backward_distance\n\t\t\t\t}\n\n\t\t\t\ts.substate_uncompressed = stateUncompressedNone\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* Calculates the smallest feasible ring buffer.\n\n   If we know the data size is small, do not allocate more ring buffer\n   size than needed to reduce memory usage.\n\n   When this method is called, metablock size and flags MUST be decoded. */\nfunc calculateRingBufferSize(s *Reader) {\n\tvar window_size int = 1 << s.window_bits\n\tvar new_ringbuffer_size int = window_size\n\tvar min_size int\n\t/* We need at least 2 bytes of ring buffer size to get the last two\n\t   bytes for context from there */\n\tif s.ringbuffer_size != 0 {\n\t\tmin_size = s.ringbuffer_size\n\t} else {\n\t\tmin_size = 1024\n\t}\n\tvar output_size int\n\n\t/* If maximum is already reached, no further extension is retired. */\n\tif s.ringbuffer_size == window_size {\n\t\treturn\n\t}\n\n\t/* Metadata blocks does not touch ring buffer. */\n\tif s.is_metadata != 0 {\n\t\treturn\n\t}\n\n\tif s.ringbuffer == nil {\n\t\toutput_size = 0\n\t} else {\n\t\toutput_size = s.pos\n\t}\n\n\toutput_size += s.meta_block_remaining_len\n\tif min_size < output_size {\n\t\tmin_size = output_size\n\t}\n\n\tif !(s.canny_ringbuffer_allocation == 0) {\n\t\t/* Reduce ring buffer size to save memory when server is unscrupulous.\n\t\t   In worst case memory usage might be 1.5x bigger for a short period of\n\t\t   ring buffer reallocation. */\n\t\tfor new_ringbuffer_size>>1 >= min_size {\n\t\t\tnew_ringbuffer_size >>= 1\n\t\t}\n\t}\n\n\ts.new_ringbuffer_size = new_ringbuffer_size\n}\n\n/* Reads 1..256 2-bit context modes. */\nfunc readContextModes(s *Reader) int {\n\tvar br *bitReader = &s.br\n\tvar i int = s.loop_counter\n\n\tfor i < int(s.num_block_types[0]) {\n\t\tvar bits uint32\n\t\tif !safeReadBits(br, 2, &bits) {\n\t\t\ts.loop_counter = i\n\t\t\treturn decoderNeedsMoreInput\n\t\t}\n\n\t\ts.context_modes[i] = byte(bits)\n\t\ti++\n\t}\n\n\treturn decoderSuccess\n}\n\nfunc takeDistanceFromRingBuffer(s *Reader) {\n\tif s.distance_code == 0 {\n\t\ts.dist_rb_idx--\n\t\ts.distance_code = s.dist_rb[s.dist_rb_idx&3]\n\n\t\t/* Compensate double distance-ring-buffer roll for dictionary items. */\n\t\ts.distance_context = 1\n\t} else {\n\t\tvar distance_code int = s.distance_code << 1\n\t\tconst kDistanceShortCodeIndexOffset uint32 = 0xAAAFFF1B\n\t\tconst kDistanceShortCodeValueOffset uint32 = 0xFA5FA500\n\t\tvar v int = (s.dist_rb_idx + int(kDistanceShortCodeIndexOffset>>uint(distance_code))) & 0x3\n\t\t/* kDistanceShortCodeIndexOffset has 2-bit values from LSB:\n\t\t   3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */\n\n\t\t/* kDistanceShortCodeValueOffset has 2-bit values from LSB:\n\t\t   -0, 0,-0, 0,-1, 1,-2, 2,-3, 3,-1, 1,-2, 2,-3, 3 */\n\t\ts.distance_code = s.dist_rb[v]\n\n\t\tv = int(kDistanceShortCodeValueOffset>>uint(distance_code)) & 0x3\n\t\tif distance_code&0x3 != 0 {\n\t\t\ts.distance_code += v\n\t\t} else {\n\t\t\ts.distance_code -= v\n\t\t\tif s.distance_code <= 0 {\n\t\t\t\t/* A huge distance will cause a () soon.\n\t\t\t\t   This is a little faster than failing here. */\n\t\t\t\ts.distance_code = 0x7FFFFFFF\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc safeReadBitsMaybeZero(br *bitReader, n_bits uint32, val *uint32) bool {\n\tif n_bits != 0 {\n\t\treturn safeReadBits(br, n_bits, val)\n\t} else {\n\t\t*val = 0\n\t\treturn true\n\t}\n}\n\n/* Precondition: s->distance_code < 0. */\nfunc readDistanceInternal(safe int, s *Reader, br *bitReader) bool {\n\tvar distval int\n\tvar memento bitReaderState\n\tvar distance_tree []huffmanCode = []huffmanCode(s.distance_hgroup.htrees[s.dist_htree_index])\n\tif safe == 0 {\n\t\ts.distance_code = int(readSymbol(distance_tree, br))\n\t} else {\n\t\tvar code uint32\n\t\tbitReaderSaveState(br, &memento)\n\t\tif !safeReadSymbol(distance_tree, br, &code) {\n\t\t\treturn false\n\t\t}\n\n\t\ts.distance_code = int(code)\n\t}\n\n\t/* Convert the distance code to the actual distance by possibly\n\t   looking up past distances from the s->ringbuffer. */\n\ts.distance_context = 0\n\n\tif s.distance_code&^0xF == 0 {\n\t\ttakeDistanceFromRingBuffer(s)\n\t\ts.block_length[2]--\n\t\treturn true\n\t}\n\n\tdistval = s.distance_code - int(s.num_direct_distance_codes)\n\tif distval >= 0 {\n\t\tvar nbits uint32\n\t\tvar postfix int\n\t\tvar offset int\n\t\tif safe == 0 && (s.distance_postfix_bits == 0) {\n\t\t\tnbits = (uint32(distval) >> 1) + 1\n\t\t\toffset = ((2 + (distval & 1)) << nbits) - 4\n\t\t\ts.distance_code = int(s.num_direct_distance_codes) + offset + int(readBits(br, nbits))\n\t\t} else {\n\t\t\t/* This branch also works well when s->distance_postfix_bits == 0. */\n\t\t\tvar bits uint32\n\t\t\tpostfix = distval & s.distance_postfix_mask\n\t\t\tdistval >>= s.distance_postfix_bits\n\t\t\tnbits = (uint32(distval) >> 1) + 1\n\t\t\tif safe != 0 {\n\t\t\t\tif !safeReadBitsMaybeZero(br, nbits, &bits) {\n\t\t\t\t\ts.distance_code = -1 /* Restore precondition. */\n\t\t\t\t\tbitReaderRestoreState(br, &memento)\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tbits = readBits(br, nbits)\n\t\t\t}\n\n\t\t\toffset = ((2 + (distval & 1)) << nbits) - 4\n\t\t\ts.distance_code = int(s.num_direct_distance_codes) + ((offset + int(bits)) << s.distance_postfix_bits) + postfix\n\t\t}\n\t}\n\n\ts.distance_code = s.distance_code - numDistanceShortCodes + 1\n\ts.block_length[2]--\n\treturn true\n}\n\nfunc readDistance(s *Reader, br *bitReader) {\n\treadDistanceInternal(0, s, br)\n}\n\nfunc safeReadDistance(s *Reader, br *bitReader) bool {\n\treturn readDistanceInternal(1, s, br)\n}\n\nfunc readCommandInternal(safe int, s *Reader, br *bitReader, insert_length *int) bool {\n\tvar cmd_code uint32\n\tvar insert_len_extra uint32 = 0\n\tvar copy_length uint32\n\tvar v cmdLutElement\n\tvar memento bitReaderState\n\tif safe == 0 {\n\t\tcmd_code = readSymbol(s.htree_command, br)\n\t} else {\n\t\tbitReaderSaveState(br, &memento)\n\t\tif !safeReadSymbol(s.htree_command, br, &cmd_code) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tv = kCmdLut[cmd_code]\n\ts.distance_code = int(v.distance_code)\n\ts.distance_context = int(v.context)\n\ts.dist_htree_index = s.dist_context_map_slice[s.distance_context]\n\t*insert_length = int(v.insert_len_offset)\n\tif safe == 0 {\n\t\tif v.insert_len_extra_bits != 0 {\n\t\t\tinsert_len_extra = readBits(br, uint32(v.insert_len_extra_bits))\n\t\t}\n\n\t\tcopy_length = readBits(br, uint32(v.copy_len_extra_bits))\n\t} else {\n\t\tif !safeReadBitsMaybeZero(br, uint32(v.insert_len_extra_bits), &insert_len_extra) || !safeReadBitsMaybeZero(br, uint32(v.copy_len_extra_bits), &copy_length) {\n\t\t\tbitReaderRestoreState(br, &memento)\n\t\t\treturn false\n\t\t}\n\t}\n\n\ts.copy_length = int(copy_length) + int(v.copy_len_offset)\n\ts.block_length[1]--\n\t*insert_length += int(insert_len_extra)\n\treturn true\n}\n\nfunc readCommand(s *Reader, br *bitReader, insert_length *int) {\n\treadCommandInternal(0, s, br, insert_length)\n}\n\nfunc safeReadCommand(s *Reader, br *bitReader, insert_length *int) bool {\n\treturn readCommandInternal(1, s, br, insert_length)\n}\n\nfunc checkInputAmountMaybeSafe(safe int, br *bitReader, num uint) bool {\n\tif safe != 0 {\n\t\treturn true\n\t}\n\n\treturn checkInputAmount(br, num)\n}\n\nfunc processCommandsInternal(safe int, s *Reader) int {\n\tvar pos int = s.pos\n\tvar i int = s.loop_counter\n\tvar result int = decoderSuccess\n\tvar br *bitReader = &s.br\n\tvar hc []huffmanCode\n\n\tif !checkInputAmountMaybeSafe(safe, br, 28) {\n\t\tresult = decoderNeedsMoreInput\n\t\tgoto saveStateAndReturn\n\t}\n\n\tif safe == 0 {\n\t\twarmupBitReader(br)\n\t}\n\n\t/* Jump into state machine. */\n\tif s.state == stateCommandBegin {\n\t\tgoto CommandBegin\n\t} else if s.state == stateCommandInner {\n\t\tgoto CommandInner\n\t} else if s.state == stateCommandPostDecodeLiterals {\n\t\tgoto CommandPostDecodeLiterals\n\t} else if s.state == stateCommandPostWrapCopy {\n\t\tgoto CommandPostWrapCopy\n\t} else {\n\t\treturn decoderErrorUnreachable\n\t}\n\nCommandBegin:\n\tif safe != 0 {\n\t\ts.state = stateCommandBegin\n\t}\n\n\tif !checkInputAmountMaybeSafe(safe, br, 28) { /* 156 bits + 7 bytes */\n\t\ts.state = stateCommandBegin\n\t\tresult = decoderNeedsMoreInput\n\t\tgoto saveStateAndReturn\n\t}\n\n\tif s.block_length[1] == 0 {\n\t\tif safe != 0 {\n\t\t\tif !safeDecodeCommandBlockSwitch(s) {\n\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\tgoto saveStateAndReturn\n\t\t\t}\n\t\t} else {\n\t\t\tdecodeCommandBlockSwitch(s)\n\t\t}\n\n\t\tgoto CommandBegin\n\t}\n\n\t/* Read the insert/copy length in the command. */\n\tif safe != 0 {\n\t\tif !safeReadCommand(s, br, &i) {\n\t\t\tresult = decoderNeedsMoreInput\n\t\t\tgoto saveStateAndReturn\n\t\t}\n\t} else {\n\t\treadCommand(s, br, &i)\n\t}\n\n\tif i == 0 {\n\t\tgoto CommandPostDecodeLiterals\n\t}\n\n\ts.meta_block_remaining_len -= i\n\nCommandInner:\n\tif safe != 0 {\n\t\ts.state = stateCommandInner\n\t}\n\n\t/* Read the literals in the command. */\n\tif s.trivial_literal_context != 0 {\n\t\tvar bits uint32\n\t\tvar value uint32\n\t\tpreloadSymbol(safe, s.literal_htree, br, &bits, &value)\n\t\tfor {\n\t\t\tif !checkInputAmountMaybeSafe(safe, br, 28) { /* 162 bits + 7 bytes */\n\t\t\t\ts.state = stateCommandInner\n\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\tgoto saveStateAndReturn\n\t\t\t}\n\n\t\t\tif s.block_length[0] == 0 {\n\t\t\t\tif safe != 0 {\n\t\t\t\t\tif !safeDecodeLiteralBlockSwitch(s) {\n\t\t\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\t\t\tgoto saveStateAndReturn\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tdecodeLiteralBlockSwitch(s)\n\t\t\t\t}\n\n\t\t\t\tpreloadSymbol(safe, s.literal_htree, br, &bits, &value)\n\t\t\t\tif s.trivial_literal_context == 0 {\n\t\t\t\t\tgoto CommandInner\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif safe == 0 {\n\t\t\t\ts.ringbuffer[pos] = byte(readPreloadedSymbol(s.literal_htree, br, &bits, &value))\n\t\t\t} else {\n\t\t\t\tvar literal uint32\n\t\t\t\tif !safeReadSymbol(s.literal_htree, br, &literal) {\n\t\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\t\tgoto saveStateAndReturn\n\t\t\t\t}\n\n\t\t\t\ts.ringbuffer[pos] = byte(literal)\n\t\t\t}\n\n\t\t\ts.block_length[0]--\n\t\t\tpos++\n\t\t\tif pos == s.ringbuffer_size {\n\t\t\t\ts.state = stateCommandInnerWrite\n\t\t\t\ti--\n\t\t\t\tgoto saveStateAndReturn\n\t\t\t}\n\t\t\ti--\n\t\t\tif i == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t} else {\n\t\tvar p1 byte = s.ringbuffer[(pos-1)&s.ringbuffer_mask]\n\t\tvar p2 byte = s.ringbuffer[(pos-2)&s.ringbuffer_mask]\n\t\tfor {\n\t\t\tvar context byte\n\t\t\tif !checkInputAmountMaybeSafe(safe, br, 28) { /* 162 bits + 7 bytes */\n\t\t\t\ts.state = stateCommandInner\n\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\tgoto saveStateAndReturn\n\t\t\t}\n\n\t\t\tif s.block_length[0] == 0 {\n\t\t\t\tif safe != 0 {\n\t\t\t\t\tif !safeDecodeLiteralBlockSwitch(s) {\n\t\t\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\t\t\tgoto saveStateAndReturn\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tdecodeLiteralBlockSwitch(s)\n\t\t\t\t}\n\n\t\t\t\tif s.trivial_literal_context != 0 {\n\t\t\t\t\tgoto CommandInner\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontext = getContext(p1, p2, s.context_lookup)\n\t\t\thc = []huffmanCode(s.literal_hgroup.htrees[s.context_map_slice[context]])\n\t\t\tp2 = p1\n\t\t\tif safe == 0 {\n\t\t\t\tp1 = byte(readSymbol(hc, br))\n\t\t\t} else {\n\t\t\t\tvar literal uint32\n\t\t\t\tif !safeReadSymbol(hc, br, &literal) {\n\t\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\t\tgoto saveStateAndReturn\n\t\t\t\t}\n\n\t\t\t\tp1 = byte(literal)\n\t\t\t}\n\n\t\t\ts.ringbuffer[pos] = p1\n\t\t\ts.block_length[0]--\n\t\t\tpos++\n\t\t\tif pos == s.ringbuffer_size {\n\t\t\t\ts.state = stateCommandInnerWrite\n\t\t\t\ti--\n\t\t\t\tgoto saveStateAndReturn\n\t\t\t}\n\t\t\ti--\n\t\t\tif i == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif s.meta_block_remaining_len <= 0 {\n\t\ts.state = stateMetablockDone\n\t\tgoto saveStateAndReturn\n\t}\n\nCommandPostDecodeLiterals:\n\tif safe != 0 {\n\t\ts.state = stateCommandPostDecodeLiterals\n\t}\n\n\tif s.distance_code >= 0 {\n\t\t/* Implicit distance case. */\n\t\tif s.distance_code != 0 {\n\t\t\ts.distance_context = 0\n\t\t} else {\n\t\t\ts.distance_context = 1\n\t\t}\n\n\t\ts.dist_rb_idx--\n\t\ts.distance_code = s.dist_rb[s.dist_rb_idx&3]\n\t} else {\n\t\t/* Read distance code in the command, unless it was implicitly zero. */\n\t\tif s.block_length[2] == 0 {\n\t\t\tif safe != 0 {\n\t\t\t\tif !safeDecodeDistanceBlockSwitch(s) {\n\t\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\t\tgoto saveStateAndReturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdecodeDistanceBlockSwitch(s)\n\t\t\t}\n\t\t}\n\n\t\tif safe != 0 {\n\t\t\tif !safeReadDistance(s, br) {\n\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\tgoto saveStateAndReturn\n\t\t\t}\n\t\t} else {\n\t\t\treadDistance(s, br)\n\t\t}\n\t}\n\n\tif s.max_distance != s.max_backward_distance {\n\t\tif pos < s.max_backward_distance {\n\t\t\ts.max_distance = pos\n\t\t} else {\n\t\t\ts.max_distance = s.max_backward_distance\n\t\t}\n\t}\n\n\ti = s.copy_length\n\n\t/* Apply copy of LZ77 back-reference, or static dictionary reference if\n\t   the distance is larger than the max LZ77 distance */\n\tif s.distance_code > s.max_distance {\n\t\t/* The maximum allowed distance is BROTLI_MAX_ALLOWED_DISTANCE = 0x7FFFFFFC.\n\t\t   With this choice, no signed overflow can occur after decoding\n\t\t   a special distance code (e.g., after adding 3 to the last distance). */\n\t\tif s.distance_code > maxAllowedDistance {\n\t\t\treturn decoderErrorFormatDistance\n\t\t}\n\n\t\tif i >= minDictionaryWordLength && i <= maxDictionaryWordLength {\n\t\t\tvar address int = s.distance_code - s.max_distance - 1\n\t\t\tvar words *dictionary = s.dictionary\n\t\t\tvar trans *transforms = s.transforms\n\t\t\tvar offset int = int(s.dictionary.offsets_by_length[i])\n\t\t\tvar shift uint32 = uint32(s.dictionary.size_bits_by_length[i])\n\t\t\tvar mask int = int(bitMask(shift))\n\t\t\tvar word_idx int = address & mask\n\t\t\tvar transform_idx int = address >> shift\n\n\t\t\t/* Compensate double distance-ring-buffer roll. */\n\t\t\ts.dist_rb_idx += s.distance_context\n\n\t\t\toffset += word_idx * i\n\t\t\tif words.data == nil {\n\t\t\t\treturn decoderErrorDictionaryNotSet\n\t\t\t}\n\n\t\t\tif transform_idx < int(trans.num_transforms) {\n\t\t\t\tword := words.data[offset:]\n\t\t\t\tvar len int = i\n\t\t\t\tif transform_idx == int(trans.cutOffTransforms[0]) {\n\t\t\t\t\tcopy(s.ringbuffer[pos:], word[:uint(len)])\n\t\t\t\t} else {\n\t\t\t\t\tlen = transformDictionaryWord(s.ringbuffer[pos:], word, int(len), trans, transform_idx)\n\t\t\t\t}\n\n\t\t\t\tpos += int(len)\n\t\t\t\ts.meta_block_remaining_len -= int(len)\n\t\t\t\tif pos >= s.ringbuffer_size {\n\t\t\t\t\ts.state = stateCommandPostWrite1\n\t\t\t\t\tgoto saveStateAndReturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn decoderErrorFormatTransform\n\t\t\t}\n\t\t} else {\n\t\t\treturn decoderErrorFormatDictionary\n\t\t}\n\t} else {\n\t\tvar src_start int = (pos - s.distance_code) & s.ringbuffer_mask\n\t\tcopy_dst := s.ringbuffer[pos:]\n\t\tcopy_src := s.ringbuffer[src_start:]\n\t\tvar dst_end int = pos + i\n\t\tvar src_end int = src_start + i\n\n\t\t/* Update the recent distances cache. */\n\t\ts.dist_rb[s.dist_rb_idx&3] = s.distance_code\n\n\t\ts.dist_rb_idx++\n\t\ts.meta_block_remaining_len -= i\n\n\t\t/* There are 32+ bytes of slack in the ring-buffer allocation.\n\t\t   Also, we have 16 short codes, that make these 16 bytes irrelevant\n\t\t   in the ring-buffer. Let's copy over them as a first guess. */\n\t\tcopy(copy_dst, copy_src[:16])\n\n\t\tif src_end > pos && dst_end > src_start {\n\t\t\t/* Regions intersect. */\n\t\t\tgoto CommandPostWrapCopy\n\t\t}\n\n\t\tif dst_end >= s.ringbuffer_size || src_end >= s.ringbuffer_size {\n\t\t\t/* At least one region wraps. */\n\t\t\tgoto CommandPostWrapCopy\n\t\t}\n\n\t\tpos += i\n\t\tif i > 16 {\n\t\t\tif i > 32 {\n\t\t\t\tcopy(copy_dst[16:], copy_src[16:][:uint(i-16)])\n\t\t\t} else {\n\t\t\t\t/* This branch covers about 45% cases.\n\t\t\t\t   Fixed size short copy allows more compiler optimizations. */\n\t\t\t\tcopy(copy_dst[16:], copy_src[16:][:16])\n\t\t\t}\n\t\t}\n\t}\n\n\tif s.meta_block_remaining_len <= 0 {\n\t\t/* Next metablock, if any. */\n\t\ts.state = stateMetablockDone\n\n\t\tgoto saveStateAndReturn\n\t} else {\n\t\tgoto CommandBegin\n\t}\nCommandPostWrapCopy:\n\t{\n\t\tvar wrap_guard int = s.ringbuffer_size - pos\n\t\tfor {\n\t\t\ti--\n\t\t\tif i < 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ts.ringbuffer[pos] = s.ringbuffer[(pos-s.distance_code)&s.ringbuffer_mask]\n\t\t\tpos++\n\t\t\twrap_guard--\n\t\t\tif wrap_guard == 0 {\n\t\t\t\ts.state = stateCommandPostWrite2\n\t\t\t\tgoto saveStateAndReturn\n\t\t\t}\n\t\t}\n\t}\n\n\tif s.meta_block_remaining_len <= 0 {\n\t\t/* Next metablock, if any. */\n\t\ts.state = stateMetablockDone\n\n\t\tgoto saveStateAndReturn\n\t} else {\n\t\tgoto CommandBegin\n\t}\n\nsaveStateAndReturn:\n\ts.pos = pos\n\ts.loop_counter = i\n\treturn result\n}\n\nfunc processCommands(s *Reader) int {\n\treturn processCommandsInternal(0, s)\n}\n\nfunc safeProcessCommands(s *Reader) int {\n\treturn processCommandsInternal(1, s)\n}\n\n/* Returns the maximum number of distance symbols which can only represent\n   distances not exceeding BROTLI_MAX_ALLOWED_DISTANCE. */\n\nvar maxDistanceSymbol_bound = [maxNpostfix + 1]uint32{0, 4, 12, 28}\nvar maxDistanceSymbol_diff = [maxNpostfix + 1]uint32{73, 126, 228, 424}\n\nfunc maxDistanceSymbol(ndirect uint32, npostfix uint32) uint32 {\n\tvar postfix uint32 = 1 << npostfix\n\tif ndirect < maxDistanceSymbol_bound[npostfix] {\n\t\treturn ndirect + maxDistanceSymbol_diff[npostfix] + postfix\n\t} else if ndirect > maxDistanceSymbol_bound[npostfix]+postfix {\n\t\treturn ndirect + maxDistanceSymbol_diff[npostfix]\n\t} else {\n\t\treturn maxDistanceSymbol_bound[npostfix] + maxDistanceSymbol_diff[npostfix] + postfix\n\t}\n}\n\n/* Invariant: input stream is never overconsumed:\n   - invalid input implies that the whole stream is invalid -> any amount of\n     input could be read and discarded\n   - when result is \"needs more input\", then at least one more byte is REQUIRED\n     to complete decoding; all input data MUST be consumed by decoder, so\n     client could swap the input buffer\n   - when result is \"needs more output\" decoder MUST ensure that it doesn't\n     hold more than 7 bits in bit reader; this saves client from swapping input\n     buffer ahead of time\n   - when result is \"success\" decoder MUST return all unused data back to input\n     buffer; this is possible because the invariant is held on enter */\nfunc decoderDecompressStream(s *Reader, available_in *uint, next_in *[]byte, available_out *uint, next_out *[]byte) int {\n\tvar result int = decoderSuccess\n\tvar br *bitReader = &s.br\n\n\t/* Do not try to process further in a case of unrecoverable error. */\n\tif int(s.error_code) < 0 {\n\t\treturn decoderResultError\n\t}\n\n\tif *available_out != 0 && (next_out == nil || *next_out == nil) {\n\t\treturn saveErrorCode(s, decoderErrorInvalidArguments)\n\t}\n\n\tif *available_out == 0 {\n\t\tnext_out = nil\n\t}\n\tif s.buffer_length == 0 { /* Just connect bit reader to input stream. */\n\t\tbr.input_len = *available_in\n\t\tbr.input = *next_in\n\t\tbr.byte_pos = 0\n\t} else {\n\t\t/* At least one byte of input is required. More than one byte of input may\n\t\t   be required to complete the transaction -> reading more data must be\n\t\t   done in a loop -> do it in a main loop. */\n\t\tresult = decoderNeedsMoreInput\n\n\t\tbr.input = s.buffer.u8[:]\n\t\tbr.byte_pos = 0\n\t}\n\n\t/* State machine */\n\tfor {\n\t\tif result != decoderSuccess {\n\t\t\t/* Error, needs more input/output. */\n\t\t\tif result == decoderNeedsMoreInput {\n\t\t\t\tif s.ringbuffer != nil { /* Pro-actively push output. */\n\t\t\t\t\tvar intermediate_result int = writeRingBuffer(s, available_out, next_out, nil, true)\n\n\t\t\t\t\t/* WriteRingBuffer checks s->meta_block_remaining_len validity. */\n\t\t\t\t\tif int(intermediate_result) < 0 {\n\t\t\t\t\t\tresult = intermediate_result\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif s.buffer_length != 0 { /* Used with internal buffer. */\n\t\t\t\t\tif br.byte_pos == br.input_len {\n\t\t\t\t\t\t/* Successfully finished read transaction.\n\t\t\t\t\t\t   Accumulator contains less than 8 bits, because internal buffer\n\t\t\t\t\t\t   is expanded byte-by-byte until it is enough to complete read. */\n\t\t\t\t\t\ts.buffer_length = 0\n\n\t\t\t\t\t\t/* Switch to input stream and restart. */\n\t\t\t\t\t\tresult = decoderSuccess\n\n\t\t\t\t\t\tbr.input_len = *available_in\n\t\t\t\t\t\tbr.input = *next_in\n\t\t\t\t\t\tbr.byte_pos = 0\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t} else if *available_in != 0 {\n\t\t\t\t\t\t/* Not enough data in buffer, but can take one more byte from\n\t\t\t\t\t\t   input stream. */\n\t\t\t\t\t\tresult = decoderSuccess\n\n\t\t\t\t\t\ts.buffer.u8[s.buffer_length] = (*next_in)[0]\n\t\t\t\t\t\ts.buffer_length++\n\t\t\t\t\t\tbr.input_len = uint(s.buffer_length)\n\t\t\t\t\t\t*next_in = (*next_in)[1:]\n\t\t\t\t\t\t(*available_in)--\n\n\t\t\t\t\t\t/* Retry with more data in buffer. */\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Can't finish reading and no more input. */\n\t\t\t\t\tbreak\n\t\t\t\t\t/* Input stream doesn't contain enough input. */\n\t\t\t\t} else {\n\t\t\t\t\t/* Copy tail to internal buffer and return. */\n\t\t\t\t\t*next_in = br.input[br.byte_pos:]\n\n\t\t\t\t\t*available_in = br.input_len - br.byte_pos\n\t\t\t\t\tfor *available_in != 0 {\n\t\t\t\t\t\ts.buffer.u8[s.buffer_length] = (*next_in)[0]\n\t\t\t\t\t\ts.buffer_length++\n\t\t\t\t\t\t*next_in = (*next_in)[1:]\n\t\t\t\t\t\t(*available_in)--\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Unreachable. */\n\n\t\t\t/* Fail or needs more output. */\n\t\t\tif s.buffer_length != 0 {\n\t\t\t\t/* Just consumed the buffered input and produced some output. Otherwise\n\t\t\t\t   it would result in \"needs more input\". Reset internal buffer. */\n\t\t\t\ts.buffer_length = 0\n\t\t\t} else {\n\t\t\t\t/* Using input stream in last iteration. When decoder switches to input\n\t\t\t\t   stream it has less than 8 bits in accumulator, so it is safe to\n\t\t\t\t   return unused accumulator bits there. */\n\t\t\t\tbitReaderUnload(br)\n\n\t\t\t\t*available_in = br.input_len - br.byte_pos\n\t\t\t\t*next_in = br.input[br.byte_pos:]\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\n\t\tswitch s.state {\n\t\t/* Prepare to the first read. */\n\t\tcase stateUninited:\n\t\t\tif !warmupBitReader(br) {\n\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t/* Decode window size. */\n\t\t\tresult = decodeWindowBits(s, br) /* Reads 1..8 bits. */\n\t\t\tif result != decoderSuccess {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif s.large_window {\n\t\t\t\ts.state = stateLargeWindowBits\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.state = stateInitialize\n\n\t\tcase stateLargeWindowBits:\n\t\t\tif !safeReadBits(br, 6, &s.window_bits) {\n\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif s.window_bits < largeMinWbits || s.window_bits > largeMaxWbits {\n\t\t\t\tresult = decoderErrorFormatWindowBits\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.state = stateInitialize\n\t\t\tfallthrough\n\n\t\t\t/* Maximum distance, see section 9.1. of the spec. */\n\t\t/* Fall through. */\n\t\tcase stateInitialize:\n\t\t\ts.max_backward_distance = (1 << s.window_bits) - windowGap\n\n\t\t\t/* Allocate memory for both block_type_trees and block_len_trees. */\n\t\t\ts.block_type_trees = make([]huffmanCode, (3 * (huffmanMaxSize258 + huffmanMaxSize26)))\n\n\t\t\tif s.block_type_trees == nil {\n\t\t\t\tresult = decoderErrorAllocBlockTypeTrees\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.block_len_trees = s.block_type_trees[3*huffmanMaxSize258:]\n\n\t\t\ts.state = stateMetablockBegin\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockBegin:\n\t\t\tdecoderStateMetablockBegin(s)\n\n\t\t\ts.state = stateMetablockHeader\n\t\t\tfallthrough\n\n\t\t\t/* Fall through. */\n\t\tcase stateMetablockHeader:\n\t\t\tresult = decodeMetaBlockLength(s, br)\n\t\t\t/* Reads 2 - 31 bits. */\n\t\t\tif result != decoderSuccess {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif s.is_metadata != 0 || s.is_uncompressed != 0 {\n\t\t\t\tif !bitReaderJumpToByteBoundary(br) {\n\t\t\t\t\tresult = decoderErrorFormatPadding1\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif s.is_metadata != 0 {\n\t\t\t\ts.state = stateMetadata\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif s.meta_block_remaining_len == 0 {\n\t\t\t\ts.state = stateMetablockDone\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcalculateRingBufferSize(s)\n\t\t\tif s.is_uncompressed != 0 {\n\t\t\t\ts.state = stateUncompressed\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.loop_counter = 0\n\t\t\ts.state = stateHuffmanCode0\n\n\t\tcase stateUncompressed:\n\t\t\tresult = copyUncompressedBlockToOutput(available_out, next_out, nil, s)\n\t\t\tif result == decoderSuccess {\n\t\t\t\ts.state = stateMetablockDone\n\t\t\t}\n\n\t\tcase stateMetadata:\n\t\t\tfor ; s.meta_block_remaining_len > 0; s.meta_block_remaining_len-- {\n\t\t\t\tvar bits uint32\n\n\t\t\t\t/* Read one byte and ignore it. */\n\t\t\t\tif !safeReadBits(br, 8, &bits) {\n\t\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif result == decoderSuccess {\n\t\t\t\ts.state = stateMetablockDone\n\t\t\t}\n\n\t\tcase stateHuffmanCode0:\n\t\t\tif s.loop_counter >= 3 {\n\t\t\t\ts.state = stateMetablockHeader2\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t/* Reads 1..11 bits. */\n\t\t\tresult = decodeVarLenUint8(s, br, &s.num_block_types[s.loop_counter])\n\n\t\t\tif result != decoderSuccess {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.num_block_types[s.loop_counter]++\n\t\t\tif s.num_block_types[s.loop_counter] < 2 {\n\t\t\t\ts.loop_counter++\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.state = stateHuffmanCode1\n\t\t\tfallthrough\n\n\t\tcase stateHuffmanCode1:\n\t\t\t{\n\t\t\t\tvar alphabet_size uint32 = s.num_block_types[s.loop_counter] + 2\n\t\t\t\tvar tree_offset int = s.loop_counter * huffmanMaxSize258\n\t\t\t\tresult = readHuffmanCode(alphabet_size, alphabet_size, s.block_type_trees[tree_offset:], nil, s)\n\t\t\t\tif result != decoderSuccess {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ts.state = stateHuffmanCode2\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase stateHuffmanCode2:\n\t\t\t{\n\t\t\t\tvar alphabet_size uint32 = numBlockLenSymbols\n\t\t\t\tvar tree_offset int = s.loop_counter * huffmanMaxSize26\n\t\t\t\tresult = readHuffmanCode(alphabet_size, alphabet_size, s.block_len_trees[tree_offset:], nil, s)\n\t\t\t\tif result != decoderSuccess {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ts.state = stateHuffmanCode3\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase stateHuffmanCode3:\n\t\t\tvar tree_offset int = s.loop_counter * huffmanMaxSize26\n\t\t\tif !safeReadBlockLength(s, &s.block_length[s.loop_counter], s.block_len_trees[tree_offset:], br) {\n\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.loop_counter++\n\t\t\ts.state = stateHuffmanCode0\n\n\t\tcase stateMetablockHeader2:\n\t\t\t{\n\t\t\t\tvar bits uint32\n\t\t\t\tif !safeReadBits(br, 6, &bits) {\n\t\t\t\t\tresult = decoderNeedsMoreInput\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\ts.distance_postfix_bits = bits & bitMask(2)\n\t\t\t\tbits >>= 2\n\t\t\t\ts.num_direct_distance_codes = numDistanceShortCodes + (bits << s.distance_postfix_bits)\n\t\t\t\ts.distance_postfix_mask = int(bitMask(s.distance_postfix_bits))\n\t\t\t\ts.context_modes = make([]byte, uint(s.num_block_types[0]))\n\t\t\t\tif s.context_modes == nil {\n\t\t\t\t\tresult = decoderErrorAllocContextModes\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\ts.loop_counter = 0\n\t\t\t\ts.state = stateContextModes\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase stateContextModes:\n\t\t\tresult = readContextModes(s)\n\n\t\t\tif result != decoderSuccess {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ts.state = stateContextMap1\n\t\t\tfallthrough\n\n\t\tcase stateContextMap1:\n\t\t\tresult = decodeContextMap(s.num_block_types[0]<<literalContextBits, &s.num_literal_htrees, &s.context_map, s)\n\n\t\t\tif result != decoderSuccess {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdetectTrivialLiteralBlockTypes(s)\n\t\t\ts.state = stateContextMap2\n\t\t\tfallthrough\n\n\t\tcase stateContextMap2:\n\t\t\t{\n\t\t\t\tvar num_direct_codes uint32 = s.num_direct_distance_codes - numDistanceShortCodes\n\t\t\t\tvar num_distance_codes uint32\n\t\t\t\tvar max_distance_symbol uint32\n\t\t\t\tif s.large_window {\n\t\t\t\t\tnum_distance_codes = uint32(distanceAlphabetSize(uint(s.distance_postfix_bits), uint(num_direct_codes), largeMaxDistanceBits))\n\t\t\t\t\tmax_distance_symbol = maxDistanceSymbol(num_direct_codes, s.distance_postfix_bits)\n\t\t\t\t} else {\n\t\t\t\t\tnum_distance_codes = uint32(distanceAlphabetSize(uint(s.distance_postfix_bits), uint(num_direct_codes), maxDistanceBits))\n\t\t\t\t\tmax_distance_symbol = num_distance_codes\n\t\t\t\t}\n\t\t\t\tvar allocation_success bool = true\n\t\t\t\tresult = decodeContextMap(s.num_block_types[2]<<distanceContextBits, &s.num_dist_htrees, &s.dist_context_map, s)\n\t\t\t\tif result != decoderSuccess {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif !decoderHuffmanTreeGroupInit(s, &s.literal_hgroup, numLiteralSymbols, numLiteralSymbols, s.num_literal_htrees) {\n\t\t\t\t\tallocation_success = false\n\t\t\t\t}\n\n\t\t\t\tif !decoderHuffmanTreeGroupInit(s, &s.insert_copy_hgroup, numCommandSymbols, numCommandSymbols, s.num_block_types[1]) {\n\t\t\t\t\tallocation_success = false\n\t\t\t\t}\n\n\t\t\t\tif !decoderHuffmanTreeGroupInit(s, &s.distance_hgroup, num_distance_codes, max_distance_symbol, s.num_dist_htrees) {\n\t\t\t\t\tallocation_success = false\n\t\t\t\t}\n\n\t\t\t\tif !allocation_success {\n\t\t\t\t\treturn saveErrorCode(s, decoderErrorAllocTreeGroups)\n\t\t\t\t}\n\n\t\t\t\ts.loop_counter = 0\n\t\t\t\ts.state = stateTreeGroup\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase stateTreeGroup:\n\t\t\tvar hgroup *huffmanTreeGroup = nil\n\t\t\tswitch s.loop_counter {\n\t\t\tcase 0:\n\t\t\t\thgroup = &s.literal_hgroup\n\t\t\tcase 1:\n\t\t\t\thgroup = &s.insert_copy_hgroup\n\t\t\tcase 2:\n\t\t\t\thgroup = &s.distance_hgroup\n\t\t\tdefault:\n\t\t\t\treturn saveErrorCode(s, decoderErrorUnreachable)\n\t\t\t}\n\n\t\t\tresult = huffmanTreeGroupDecode(hgroup, s)\n\t\t\tif result != decoderSuccess {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ts.loop_counter++\n\t\t\tif s.loop_counter >= 3 {\n\t\t\t\tprepareLiteralDecoding(s)\n\t\t\t\ts.dist_context_map_slice = s.dist_context_map\n\t\t\t\ts.htree_command = []huffmanCode(s.insert_copy_hgroup.htrees[0])\n\t\t\t\tif !ensureRingBuffer(s) {\n\t\t\t\t\tresult = decoderErrorAllocRingBuffer2\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\ts.state = stateCommandBegin\n\t\t\t}\n\n\t\tcase stateCommandBegin, stateCommandInner, stateCommandPostDecodeLiterals, stateCommandPostWrapCopy:\n\t\t\tresult = processCommands(s)\n\n\t\t\tif result == decoderNeedsMoreInput {\n\t\t\t\tresult = safeProcessCommands(s)\n\t\t\t}\n\n\t\tcase stateCommandInnerWrite, stateCommandPostWrite1, stateCommandPostWrite2:\n\t\t\tresult = writeRingBuffer(s, available_out, next_out, nil, false)\n\n\t\t\tif result != decoderSuccess {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\twrapRingBuffer(s)\n\t\t\tif s.ringbuffer_size == 1<<s.window_bits {\n\t\t\t\ts.max_distance = s.max_backward_distance\n\t\t\t}\n\n\t\t\tif s.state == stateCommandPostWrite1 {\n\t\t\t\tif s.meta_block_remaining_len == 0 {\n\t\t\t\t\t/* Next metablock, if any. */\n\t\t\t\t\ts.state = stateMetablockDone\n\t\t\t\t} else {\n\t\t\t\t\ts.state = stateCommandBegin\n\t\t\t\t}\n\t\t\t} else if s.state == stateCommandPostWrite2 {\n\t\t\t\ts.state = stateCommandPostWrapCopy /* BROTLI_STATE_COMMAND_INNER_WRITE */\n\t\t\t} else {\n\t\t\t\tif s.loop_counter == 0 {\n\t\t\t\t\tif s.meta_block_remaining_len == 0 {\n\t\t\t\t\t\ts.state = stateMetablockDone\n\t\t\t\t\t} else {\n\t\t\t\t\t\ts.state = stateCommandPostDecodeLiterals\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\ts.state = stateCommandInner\n\t\t\t}\n\n\t\tcase stateMetablockDone:\n\t\t\tif s.meta_block_remaining_len < 0 {\n\t\t\t\tresult = decoderErrorFormatBlockLength2\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tdecoderStateCleanupAfterMetablock(s)\n\t\t\tif s.is_last_metablock == 0 {\n\t\t\t\ts.state = stateMetablockBegin\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif !bitReaderJumpToByteBoundary(br) {\n\t\t\t\tresult = decoderErrorFormatPadding2\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif s.buffer_length == 0 {\n\t\t\t\tbitReaderUnload(br)\n\t\t\t\t*available_in = br.input_len - br.byte_pos\n\t\t\t\t*next_in = br.input[br.byte_pos:]\n\t\t\t}\n\n\t\t\ts.state = stateDone\n\t\t\tfallthrough\n\n\t\tcase stateDone:\n\t\t\tif s.ringbuffer != nil {\n\t\t\t\tresult = writeRingBuffer(s, available_out, next_out, nil, true)\n\t\t\t\tif result != decoderSuccess {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn saveErrorCode(s, result)\n\t\t}\n\t}\n\n\treturn saveErrorCode(s, result)\n}\n\nfunc decoderHasMoreOutput(s *Reader) bool {\n\t/* After unrecoverable error remaining output is considered nonsensical. */\n\tif int(s.error_code) < 0 {\n\t\treturn false\n\t}\n\n\treturn s.ringbuffer != nil && unwrittenBytes(s, false) != 0\n}\n\nfunc decoderGetErrorCode(s *Reader) int {\n\treturn int(s.error_code)\n}\n\nfunc decoderErrorString(c int) string {\n\tswitch c {\n\tcase decoderNoError:\n\t\treturn \"NO_ERROR\"\n\tcase decoderSuccess:\n\t\treturn \"SUCCESS\"\n\tcase decoderNeedsMoreInput:\n\t\treturn \"NEEDS_MORE_INPUT\"\n\tcase decoderNeedsMoreOutput:\n\t\treturn \"NEEDS_MORE_OUTPUT\"\n\tcase decoderErrorFormatExuberantNibble:\n\t\treturn \"EXUBERANT_NIBBLE\"\n\tcase decoderErrorFormatReserved:\n\t\treturn \"RESERVED\"\n\tcase decoderErrorFormatExuberantMetaNibble:\n\t\treturn \"EXUBERANT_META_NIBBLE\"\n\tcase decoderErrorFormatSimpleHuffmanAlphabet:\n\t\treturn \"SIMPLE_HUFFMAN_ALPHABET\"\n\tcase decoderErrorFormatSimpleHuffmanSame:\n\t\treturn \"SIMPLE_HUFFMAN_SAME\"\n\tcase decoderErrorFormatClSpace:\n\t\treturn \"CL_SPACE\"\n\tcase decoderErrorFormatHuffmanSpace:\n\t\treturn \"HUFFMAN_SPACE\"\n\tcase decoderErrorFormatContextMapRepeat:\n\t\treturn \"CONTEXT_MAP_REPEAT\"\n\tcase decoderErrorFormatBlockLength1:\n\t\treturn \"BLOCK_LENGTH_1\"\n\tcase decoderErrorFormatBlockLength2:\n\t\treturn \"BLOCK_LENGTH_2\"\n\tcase decoderErrorFormatTransform:\n\t\treturn \"TRANSFORM\"\n\tcase decoderErrorFormatDictionary:\n\t\treturn \"DICTIONARY\"\n\tcase decoderErrorFormatWindowBits:\n\t\treturn \"WINDOW_BITS\"\n\tcase decoderErrorFormatPadding1:\n\t\treturn \"PADDING_1\"\n\tcase decoderErrorFormatPadding2:\n\t\treturn \"PADDING_2\"\n\tcase decoderErrorFormatDistance:\n\t\treturn \"DISTANCE\"\n\tcase decoderErrorDictionaryNotSet:\n\t\treturn \"DICTIONARY_NOT_SET\"\n\tcase decoderErrorInvalidArguments:\n\t\treturn \"INVALID_ARGUMENTS\"\n\tcase decoderErrorAllocContextModes:\n\t\treturn \"CONTEXT_MODES\"\n\tcase decoderErrorAllocTreeGroups:\n\t\treturn \"TREE_GROUPS\"\n\tcase decoderErrorAllocContextMap:\n\t\treturn \"CONTEXT_MAP\"\n\tcase decoderErrorAllocRingBuffer1:\n\t\treturn \"RING_BUFFER_1\"\n\tcase decoderErrorAllocRingBuffer2:\n\t\treturn \"RING_BUFFER_2\"\n\tcase decoderErrorAllocBlockTypeTrees:\n\t\treturn \"BLOCK_TYPE_TREES\"\n\tcase decoderErrorUnreachable:\n\t\treturn \"UNREACHABLE\"\n\tdefault:\n\t\treturn \"INVALID\"\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/dictionary.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Collection of static dictionary words. */\ntype dictionary struct {\n\tsize_bits_by_length [32]byte\n\toffsets_by_length   [32]uint32\n\tdata_size           uint\n\tdata                []byte\n}\n\nconst minDictionaryWordLength = 4\n\nconst maxDictionaryWordLength = 24\n\nvar kBrotliDictionaryData = []byte{\n\t116,\n\t105,\n\t109,\n\t101,\n\t100,\n\t111,\n\t119,\n\t110,\n\t108,\n\t105,\n\t102,\n\t101,\n\t108,\n\t101,\n\t102,\n\t116,\n\t98,\n\t97,\n\t99,\n\t107,\n\t99,\n\t111,\n\t100,\n\t101,\n\t100,\n\t97,\n\t116,\n\t97,\n\t115,\n\t104,\n\t111,\n\t119,\n\t111,\n\t110,\n\t108,\n\t121,\n\t115,\n\t105,\n\t116,\n\t101,\n\t99,\n\t105,\n\t116,\n\t121,\n\t111,\n\t112,\n\t101,\n\t110,\n\t106,\n\t117,\n\t115,\n\t116,\n\t108,\n\t105,\n\t107,\n\t101,\n\t102,\n\t114,\n\t101,\n\t101,\n\t119,\n\t111,\n\t114,\n\t107,\n\t116,\n\t101,\n\t120,\n\t116,\n\t121,\n\t101,\n\t97,\n\t114,\n\t111,\n\t118,\n\t101,\n\t114,\n\t98,\n\t111,\n\t100,\n\t121,\n\t108,\n\t111,\n\t118,\n\t101,\n\t102,\n\t111,\n\t114,\n\t109,\n\t98,\n\t111,\n\t111,\n\t107,\n\t112,\n\t108,\n\t97,\n\t121,\n\t108,\n\t105,\n\t118,\n\t101,\n\t108,\n\t105,\n\t110,\n\t101,\n\t104,\n\t101,\n\t108,\n\t112,\n\t104,\n\t111,\n\t109,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t109,\n\t111,\n\t114,\n\t101,\n\t119,\n\t111,\n\t114,\n\t100,\n\t108,\n\t111,\n\t110,\n\t103,\n\t116,\n\t104,\n\t101,\n\t109,\n\t118,\n\t105,\n\t101,\n\t119,\n\t102,\n\t105,\n\t110,\n\t100,\n\t112,\n\t97,\n\t103,\n\t101,\n\t100,\n\t97,\n\t121,\n\t115,\n\t102,\n\t117,\n\t108,\n\t108,\n\t104,\n\t101,\n\t97,\n\t100,\n\t116,\n\t101,\n\t114,\n\t109,\n\t101,\n\t97,\n\t99,\n\t104,\n\t97,\n\t114,\n\t101,\n\t97,\n\t102,\n\t114,\n\t111,\n\t109,\n\t116,\n\t114,\n\t117,\n\t101,\n\t109,\n\t97,\n\t114,\n\t107,\n\t97,\n\t98,\n\t108,\n\t101,\n\t117,\n\t112,\n\t111,\n\t110,\n\t104,\n\t105,\n\t103,\n\t104,\n\t100,\n\t97,\n\t116,\n\t101,\n\t108,\n\t97,\n\t110,\n\t100,\n\t110,\n\t101,\n\t119,\n\t115,\n\t101,\n\t118,\n\t101,\n\t110,\n\t110,\n\t101,\n\t120,\n\t116,\n\t99,\n\t97,\n\t115,\n\t101,\n\t98,\n\t111,\n\t116,\n\t104,\n\t112,\n\t111,\n\t115,\n\t116,\n\t117,\n\t115,\n\t101,\n\t100,\n\t109,\n\t97,\n\t100,\n\t101,\n\t104,\n\t97,\n\t110,\n\t100,\n\t104,\n\t101,\n\t114,\n\t101,\n\t119,\n\t104,\n\t97,\n\t116,\n\t110,\n\t97,\n\t109,\n\t101,\n\t76,\n\t105,\n\t110,\n\t107,\n\t98,\n\t108,\n\t111,\n\t103,\n\t115,\n\t105,\n\t122,\n\t101,\n\t98,\n\t97,\n\t115,\n\t101,\n\t104,\n\t101,\n\t108,\n\t100,\n\t109,\n\t97,\n\t107,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t117,\n\t115,\n\t101,\n\t114,\n\t39,\n\t41,\n\t32,\n\t43,\n\t104,\n\t111,\n\t108,\n\t100,\n\t101,\n\t110,\n\t100,\n\t115,\n\t119,\n\t105,\n\t116,\n\t104,\n\t78,\n\t101,\n\t119,\n\t115,\n\t114,\n\t101,\n\t97,\n\t100,\n\t119,\n\t101,\n\t114,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t116,\n\t97,\n\t107,\n\t101,\n\t104,\n\t97,\n\t118,\n\t101,\n\t103,\n\t97,\n\t109,\n\t101,\n\t115,\n\t101,\n\t101,\n\t110,\n\t99,\n\t97,\n\t108,\n\t108,\n\t112,\n\t97,\n\t116,\n\t104,\n\t119,\n\t101,\n\t108,\n\t108,\n\t112,\n\t108,\n\t117,\n\t115,\n\t109,\n\t101,\n\t110,\n\t117,\n\t102,\n\t105,\n\t108,\n\t109,\n\t112,\n\t97,\n\t114,\n\t116,\n\t106,\n\t111,\n\t105,\n\t110,\n\t116,\n\t104,\n\t105,\n\t115,\n\t108,\n\t105,\n\t115,\n\t116,\n\t103,\n\t111,\n\t111,\n\t100,\n\t110,\n\t101,\n\t101,\n\t100,\n\t119,\n\t97,\n\t121,\n\t115,\n\t119,\n\t101,\n\t115,\n\t116,\n\t106,\n\t111,\n\t98,\n\t115,\n\t109,\n\t105,\n\t110,\n\t100,\n\t97,\n\t108,\n\t115,\n\t111,\n\t108,\n\t111,\n\t103,\n\t111,\n\t114,\n\t105,\n\t99,\n\t104,\n\t117,\n\t115,\n\t101,\n\t115,\n\t108,\n\t97,\n\t115,\n\t116,\n\t116,\n\t101,\n\t97,\n\t109,\n\t97,\n\t114,\n\t109,\n\t121,\n\t102,\n\t111,\n\t111,\n\t100,\n\t107,\n\t105,\n\t110,\n\t103,\n\t119,\n\t105,\n\t108,\n\t108,\n\t101,\n\t97,\n\t115,\n\t116,\n\t119,\n\t97,\n\t114,\n\t100,\n\t98,\n\t101,\n\t115,\n\t116,\n\t102,\n\t105,\n\t114,\n\t101,\n\t80,\n\t97,\n\t103,\n\t101,\n\t107,\n\t110,\n\t111,\n\t119,\n\t97,\n\t119,\n\t97,\n\t121,\n\t46,\n\t112,\n\t110,\n\t103,\n\t109,\n\t111,\n\t118,\n\t101,\n\t116,\n\t104,\n\t97,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t103,\n\t105,\n\t118,\n\t101,\n\t115,\n\t101,\n\t108,\n\t102,\n\t110,\n\t111,\n\t116,\n\t101,\n\t109,\n\t117,\n\t99,\n\t104,\n\t102,\n\t101,\n\t101,\n\t100,\n\t109,\n\t97,\n\t110,\n\t121,\n\t114,\n\t111,\n\t99,\n\t107,\n\t105,\n\t99,\n\t111,\n\t110,\n\t111,\n\t110,\n\t99,\n\t101,\n\t108,\n\t111,\n\t111,\n\t107,\n\t104,\n\t105,\n\t100,\n\t101,\n\t100,\n\t105,\n\t101,\n\t100,\n\t72,\n\t111,\n\t109,\n\t101,\n\t114,\n\t117,\n\t108,\n\t101,\n\t104,\n\t111,\n\t115,\n\t116,\n\t97,\n\t106,\n\t97,\n\t120,\n\t105,\n\t110,\n\t102,\n\t111,\n\t99,\n\t108,\n\t117,\n\t98,\n\t108,\n\t97,\n\t119,\n\t115,\n\t108,\n\t101,\n\t115,\n\t115,\n\t104,\n\t97,\n\t108,\n\t102,\n\t115,\n\t111,\n\t109,\n\t101,\n\t115,\n\t117,\n\t99,\n\t104,\n\t122,\n\t111,\n\t110,\n\t101,\n\t49,\n\t48,\n\t48,\n\t37,\n\t111,\n\t110,\n\t101,\n\t115,\n\t99,\n\t97,\n\t114,\n\t101,\n\t84,\n\t105,\n\t109,\n\t101,\n\t114,\n\t97,\n\t99,\n\t101,\n\t98,\n\t108,\n\t117,\n\t101,\n\t102,\n\t111,\n\t117,\n\t114,\n\t119,\n\t101,\n\t101,\n\t107,\n\t102,\n\t97,\n\t99,\n\t101,\n\t104,\n\t111,\n\t112,\n\t101,\n\t103,\n\t97,\n\t118,\n\t101,\n\t104,\n\t97,\n\t114,\n\t100,\n\t108,\n\t111,\n\t115,\n\t116,\n\t119,\n\t104,\n\t101,\n\t110,\n\t112,\n\t97,\n\t114,\n\t107,\n\t107,\n\t101,\n\t112,\n\t116,\n\t112,\n\t97,\n\t115,\n\t115,\n\t115,\n\t104,\n\t105,\n\t112,\n\t114,\n\t111,\n\t111,\n\t109,\n\t72,\n\t84,\n\t77,\n\t76,\n\t112,\n\t108,\n\t97,\n\t110,\n\t84,\n\t121,\n\t112,\n\t101,\n\t100,\n\t111,\n\t110,\n\t101,\n\t115,\n\t97,\n\t118,\n\t101,\n\t107,\n\t101,\n\t101,\n\t112,\n\t102,\n\t108,\n\t97,\n\t103,\n\t108,\n\t105,\n\t110,\n\t107,\n\t115,\n\t111,\n\t108,\n\t100,\n\t102,\n\t105,\n\t118,\n\t101,\n\t116,\n\t111,\n\t111,\n\t107,\n\t114,\n\t97,\n\t116,\n\t101,\n\t116,\n\t111,\n\t119,\n\t110,\n\t106,\n\t117,\n\t109,\n\t112,\n\t116,\n\t104,\n\t117,\n\t115,\n\t100,\n\t97,\n\t114,\n\t107,\n\t99,\n\t97,\n\t114,\n\t100,\n\t102,\n\t105,\n\t108,\n\t101,\n\t102,\n\t101,\n\t97,\n\t114,\n\t115,\n\t116,\n\t97,\n\t121,\n\t107,\n\t105,\n\t108,\n\t108,\n\t116,\n\t104,\n\t97,\n\t116,\n\t102,\n\t97,\n\t108,\n\t108,\n\t97,\n\t117,\n\t116,\n\t111,\n\t101,\n\t118,\n\t101,\n\t114,\n\t46,\n\t99,\n\t111,\n\t109,\n\t116,\n\t97,\n\t108,\n\t107,\n\t115,\n\t104,\n\t111,\n\t112,\n\t118,\n\t111,\n\t116,\n\t101,\n\t100,\n\t101,\n\t101,\n\t112,\n\t109,\n\t111,\n\t100,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t116,\n\t117,\n\t114,\n\t110,\n\t98,\n\t111,\n\t114,\n\t110,\n\t98,\n\t97,\n\t110,\n\t100,\n\t102,\n\t101,\n\t108,\n\t108,\n\t114,\n\t111,\n\t115,\n\t101,\n\t117,\n\t114,\n\t108,\n\t40,\n\t115,\n\t107,\n\t105,\n\t110,\n\t114,\n\t111,\n\t108,\n\t101,\n\t99,\n\t111,\n\t109,\n\t101,\n\t97,\n\t99,\n\t116,\n\t115,\n\t97,\n\t103,\n\t101,\n\t115,\n\t109,\n\t101,\n\t101,\n\t116,\n\t103,\n\t111,\n\t108,\n\t100,\n\t46,\n\t106,\n\t112,\n\t103,\n\t105,\n\t116,\n\t101,\n\t109,\n\t118,\n\t97,\n\t114,\n\t121,\n\t102,\n\t101,\n\t108,\n\t116,\n\t116,\n\t104,\n\t101,\n\t110,\n\t115,\n\t101,\n\t110,\n\t100,\n\t100,\n\t114,\n\t111,\n\t112,\n\t86,\n\t105,\n\t101,\n\t119,\n\t99,\n\t111,\n\t112,\n\t121,\n\t49,\n\t46,\n\t48,\n\t34,\n\t60,\n\t47,\n\t97,\n\t62,\n\t115,\n\t116,\n\t111,\n\t112,\n\t101,\n\t108,\n\t115,\n\t101,\n\t108,\n\t105,\n\t101,\n\t115,\n\t116,\n\t111,\n\t117,\n\t114,\n\t112,\n\t97,\n\t99,\n\t107,\n\t46,\n\t103,\n\t105,\n\t102,\n\t112,\n\t97,\n\t115,\n\t116,\n\t99,\n\t115,\n\t115,\n\t63,\n\t103,\n\t114,\n\t97,\n\t121,\n\t109,\n\t101,\n\t97,\n\t110,\n\t38,\n\t103,\n\t116,\n\t59,\n\t114,\n\t105,\n\t100,\n\t101,\n\t115,\n\t104,\n\t111,\n\t116,\n\t108,\n\t97,\n\t116,\n\t101,\n\t115,\n\t97,\n\t105,\n\t100,\n\t114,\n\t111,\n\t97,\n\t100,\n\t118,\n\t97,\n\t114,\n\t32,\n\t102,\n\t101,\n\t101,\n\t108,\n\t106,\n\t111,\n\t104,\n\t110,\n\t114,\n\t105,\n\t99,\n\t107,\n\t112,\n\t111,\n\t114,\n\t116,\n\t102,\n\t97,\n\t115,\n\t116,\n\t39,\n\t85,\n\t65,\n\t45,\n\t100,\n\t101,\n\t97,\n\t100,\n\t60,\n\t47,\n\t98,\n\t62,\n\t112,\n\t111,\n\t111,\n\t114,\n\t98,\n\t105,\n\t108,\n\t108,\n\t116,\n\t121,\n\t112,\n\t101,\n\t85,\n\t46,\n\t83,\n\t46,\n\t119,\n\t111,\n\t111,\n\t100,\n\t109,\n\t117,\n\t115,\n\t116,\n\t50,\n\t112,\n\t120,\n\t59,\n\t73,\n\t110,\n\t102,\n\t111,\n\t114,\n\t97,\n\t110,\n\t107,\n\t119,\n\t105,\n\t100,\n\t101,\n\t119,\n\t97,\n\t110,\n\t116,\n\t119,\n\t97,\n\t108,\n\t108,\n\t108,\n\t101,\n\t97,\n\t100,\n\t91,\n\t48,\n\t93,\n\t59,\n\t112,\n\t97,\n\t117,\n\t108,\n\t119,\n\t97,\n\t118,\n\t101,\n\t115,\n\t117,\n\t114,\n\t101,\n\t36,\n\t40,\n\t39,\n\t35,\n\t119,\n\t97,\n\t105,\n\t116,\n\t109,\n\t97,\n\t115,\n\t115,\n\t97,\n\t114,\n\t109,\n\t115,\n\t103,\n\t111,\n\t101,\n\t115,\n\t103,\n\t97,\n\t105,\n\t110,\n\t108,\n\t97,\n\t110,\n\t103,\n\t112,\n\t97,\n\t105,\n\t100,\n\t33,\n\t45,\n\t45,\n\t32,\n\t108,\n\t111,\n\t99,\n\t107,\n\t117,\n\t110,\n\t105,\n\t116,\n\t114,\n\t111,\n\t111,\n\t116,\n\t119,\n\t97,\n\t108,\n\t107,\n\t102,\n\t105,\n\t114,\n\t109,\n\t119,\n\t105,\n\t102,\n\t101,\n\t120,\n\t109,\n\t108,\n\t34,\n\t115,\n\t111,\n\t110,\n\t103,\n\t116,\n\t101,\n\t115,\n\t116,\n\t50,\n\t48,\n\t112,\n\t120,\n\t107,\n\t105,\n\t110,\n\t100,\n\t114,\n\t111,\n\t119,\n\t115,\n\t116,\n\t111,\n\t111,\n\t108,\n\t102,\n\t111,\n\t110,\n\t116,\n\t109,\n\t97,\n\t105,\n\t108,\n\t115,\n\t97,\n\t102,\n\t101,\n\t115,\n\t116,\n\t97,\n\t114,\n\t109,\n\t97,\n\t112,\n\t115,\n\t99,\n\t111,\n\t114,\n\t101,\n\t114,\n\t97,\n\t105,\n\t110,\n\t102,\n\t108,\n\t111,\n\t119,\n\t98,\n\t97,\n\t98,\n\t121,\n\t115,\n\t112,\n\t97,\n\t110,\n\t115,\n\t97,\n\t121,\n\t115,\n\t52,\n\t112,\n\t120,\n\t59,\n\t54,\n\t112,\n\t120,\n\t59,\n\t97,\n\t114,\n\t116,\n\t115,\n\t102,\n\t111,\n\t111,\n\t116,\n\t114,\n\t101,\n\t97,\n\t108,\n\t119,\n\t105,\n\t107,\n\t105,\n\t104,\n\t101,\n\t97,\n\t116,\n\t115,\n\t116,\n\t101,\n\t112,\n\t116,\n\t114,\n\t105,\n\t112,\n\t111,\n\t114,\n\t103,\n\t47,\n\t108,\n\t97,\n\t107,\n\t101,\n\t119,\n\t101,\n\t97,\n\t107,\n\t116,\n\t111,\n\t108,\n\t100,\n\t70,\n\t111,\n\t114,\n\t109,\n\t99,\n\t97,\n\t115,\n\t116,\n\t102,\n\t97,\n\t110,\n\t115,\n\t98,\n\t97,\n\t110,\n\t107,\n\t118,\n\t101,\n\t114,\n\t121,\n\t114,\n\t117,\n\t110,\n\t115,\n\t106,\n\t117,\n\t108,\n\t121,\n\t116,\n\t97,\n\t115,\n\t107,\n\t49,\n\t112,\n\t120,\n\t59,\n\t103,\n\t111,\n\t97,\n\t108,\n\t103,\n\t114,\n\t101,\n\t119,\n\t115,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t103,\n\t101,\n\t105,\n\t100,\n\t61,\n\t34,\n\t115,\n\t101,\n\t116,\n\t115,\n\t53,\n\t112,\n\t120,\n\t59,\n\t46,\n\t106,\n\t115,\n\t63,\n\t52,\n\t48,\n\t112,\n\t120,\n\t105,\n\t102,\n\t32,\n\t40,\n\t115,\n\t111,\n\t111,\n\t110,\n\t115,\n\t101,\n\t97,\n\t116,\n\t110,\n\t111,\n\t110,\n\t101,\n\t116,\n\t117,\n\t98,\n\t101,\n\t122,\n\t101,\n\t114,\n\t111,\n\t115,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t101,\n\t100,\n\t102,\n\t97,\n\t99,\n\t116,\n\t105,\n\t110,\n\t116,\n\t111,\n\t103,\n\t105,\n\t102,\n\t116,\n\t104,\n\t97,\n\t114,\n\t109,\n\t49,\n\t56,\n\t112,\n\t120,\n\t99,\n\t97,\n\t109,\n\t101,\n\t104,\n\t105,\n\t108,\n\t108,\n\t98,\n\t111,\n\t108,\n\t100,\n\t122,\n\t111,\n\t111,\n\t109,\n\t118,\n\t111,\n\t105,\n\t100,\n\t101,\n\t97,\n\t115,\n\t121,\n\t114,\n\t105,\n\t110,\n\t103,\n\t102,\n\t105,\n\t108,\n\t108,\n\t112,\n\t101,\n\t97,\n\t107,\n\t105,\n\t110,\n\t105,\n\t116,\n\t99,\n\t111,\n\t115,\n\t116,\n\t51,\n\t112,\n\t120,\n\t59,\n\t106,\n\t97,\n\t99,\n\t107,\n\t116,\n\t97,\n\t103,\n\t115,\n\t98,\n\t105,\n\t116,\n\t115,\n\t114,\n\t111,\n\t108,\n\t108,\n\t101,\n\t100,\n\t105,\n\t116,\n\t107,\n\t110,\n\t101,\n\t119,\n\t110,\n\t101,\n\t97,\n\t114,\n\t60,\n\t33,\n\t45,\n\t45,\n\t103,\n\t114,\n\t111,\n\t119,\n\t74,\n\t83,\n\t79,\n\t78,\n\t100,\n\t117,\n\t116,\n\t121,\n\t78,\n\t97,\n\t109,\n\t101,\n\t115,\n\t97,\n\t108,\n\t101,\n\t121,\n\t111,\n\t117,\n\t32,\n\t108,\n\t111,\n\t116,\n\t115,\n\t112,\n\t97,\n\t105,\n\t110,\n\t106,\n\t97,\n\t122,\n\t122,\n\t99,\n\t111,\n\t108,\n\t100,\n\t101,\n\t121,\n\t101,\n\t115,\n\t102,\n\t105,\n\t115,\n\t104,\n\t119,\n\t119,\n\t119,\n\t46,\n\t114,\n\t105,\n\t115,\n\t107,\n\t116,\n\t97,\n\t98,\n\t115,\n\t112,\n\t114,\n\t101,\n\t118,\n\t49,\n\t48,\n\t112,\n\t120,\n\t114,\n\t105,\n\t115,\n\t101,\n\t50,\n\t53,\n\t112,\n\t120,\n\t66,\n\t108,\n\t117,\n\t101,\n\t100,\n\t105,\n\t110,\n\t103,\n\t51,\n\t48,\n\t48,\n\t44,\n\t98,\n\t97,\n\t108,\n\t108,\n\t102,\n\t111,\n\t114,\n\t100,\n\t101,\n\t97,\n\t114,\n\t110,\n\t119,\n\t105,\n\t108,\n\t100,\n\t98,\n\t111,\n\t120,\n\t46,\n\t102,\n\t97,\n\t105,\n\t114,\n\t108,\n\t97,\n\t99,\n\t107,\n\t118,\n\t101,\n\t114,\n\t115,\n\t112,\n\t97,\n\t105,\n\t114,\n\t106,\n\t117,\n\t110,\n\t101,\n\t116,\n\t101,\n\t99,\n\t104,\n\t105,\n\t102,\n\t40,\n\t33,\n\t112,\n\t105,\n\t99,\n\t107,\n\t101,\n\t118,\n\t105,\n\t108,\n\t36,\n\t40,\n\t34,\n\t35,\n\t119,\n\t97,\n\t114,\n\t109,\n\t108,\n\t111,\n\t114,\n\t100,\n\t100,\n\t111,\n\t101,\n\t115,\n\t112,\n\t117,\n\t108,\n\t108,\n\t44,\n\t48,\n\t48,\n\t48,\n\t105,\n\t100,\n\t101,\n\t97,\n\t100,\n\t114,\n\t97,\n\t119,\n\t104,\n\t117,\n\t103,\n\t101,\n\t115,\n\t112,\n\t111,\n\t116,\n\t102,\n\t117,\n\t110,\n\t100,\n\t98,\n\t117,\n\t114,\n\t110,\n\t104,\n\t114,\n\t101,\n\t102,\n\t99,\n\t101,\n\t108,\n\t108,\n\t107,\n\t101,\n\t121,\n\t115,\n\t116,\n\t105,\n\t99,\n\t107,\n\t104,\n\t111,\n\t117,\n\t114,\n\t108,\n\t111,\n\t115,\n\t115,\n\t102,\n\t117,\n\t101,\n\t108,\n\t49,\n\t50,\n\t112,\n\t120,\n\t115,\n\t117,\n\t105,\n\t116,\n\t100,\n\t101,\n\t97,\n\t108,\n\t82,\n\t83,\n\t83,\n\t34,\n\t97,\n\t103,\n\t101,\n\t100,\n\t103,\n\t114,\n\t101,\n\t121,\n\t71,\n\t69,\n\t84,\n\t34,\n\t101,\n\t97,\n\t115,\n\t101,\n\t97,\n\t105,\n\t109,\n\t115,\n\t103,\n\t105,\n\t114,\n\t108,\n\t97,\n\t105,\n\t100,\n\t115,\n\t56,\n\t112,\n\t120,\n\t59,\n\t110,\n\t97,\n\t118,\n\t121,\n\t103,\n\t114,\n\t105,\n\t100,\n\t116,\n\t105,\n\t112,\n\t115,\n\t35,\n\t57,\n\t57,\n\t57,\n\t119,\n\t97,\n\t114,\n\t115,\n\t108,\n\t97,\n\t100,\n\t121,\n\t99,\n\t97,\n\t114,\n\t115,\n\t41,\n\t59,\n\t32,\n\t125,\n\t112,\n\t104,\n\t112,\n\t63,\n\t104,\n\t101,\n\t108,\n\t108,\n\t116,\n\t97,\n\t108,\n\t108,\n\t119,\n\t104,\n\t111,\n\t109,\n\t122,\n\t104,\n\t58,\n\t229,\n\t42,\n\t47,\n\t13,\n\t10,\n\t32,\n\t49,\n\t48,\n\t48,\n\t104,\n\t97,\n\t108,\n\t108,\n\t46,\n\t10,\n\t10,\n\t65,\n\t55,\n\t112,\n\t120,\n\t59,\n\t112,\n\t117,\n\t115,\n\t104,\n\t99,\n\t104,\n\t97,\n\t116,\n\t48,\n\t112,\n\t120,\n\t59,\n\t99,\n\t114,\n\t101,\n\t119,\n\t42,\n\t47,\n\t60,\n\t47,\n\t104,\n\t97,\n\t115,\n\t104,\n\t55,\n\t53,\n\t112,\n\t120,\n\t102,\n\t108,\n\t97,\n\t116,\n\t114,\n\t97,\n\t114,\n\t101,\n\t32,\n\t38,\n\t38,\n\t32,\n\t116,\n\t101,\n\t108,\n\t108,\n\t99,\n\t97,\n\t109,\n\t112,\n\t111,\n\t110,\n\t116,\n\t111,\n\t108,\n\t97,\n\t105,\n\t100,\n\t109,\n\t105,\n\t115,\n\t115,\n\t115,\n\t107,\n\t105,\n\t112,\n\t116,\n\t101,\n\t110,\n\t116,\n\t102,\n\t105,\n\t110,\n\t101,\n\t109,\n\t97,\n\t108,\n\t101,\n\t103,\n\t101,\n\t116,\n\t115,\n\t112,\n\t108,\n\t111,\n\t116,\n\t52,\n\t48,\n\t48,\n\t44,\n\t13,\n\t10,\n\t13,\n\t10,\n\t99,\n\t111,\n\t111,\n\t108,\n\t102,\n\t101,\n\t101,\n\t116,\n\t46,\n\t112,\n\t104,\n\t112,\n\t60,\n\t98,\n\t114,\n\t62,\n\t101,\n\t114,\n\t105,\n\t99,\n\t109,\n\t111,\n\t115,\n\t116,\n\t103,\n\t117,\n\t105,\n\t100,\n\t98,\n\t101,\n\t108,\n\t108,\n\t100,\n\t101,\n\t115,\n\t99,\n\t104,\n\t97,\n\t105,\n\t114,\n\t109,\n\t97,\n\t116,\n\t104,\n\t97,\n\t116,\n\t111,\n\t109,\n\t47,\n\t105,\n\t109,\n\t103,\n\t38,\n\t35,\n\t56,\n\t50,\n\t108,\n\t117,\n\t99,\n\t107,\n\t99,\n\t101,\n\t110,\n\t116,\n\t48,\n\t48,\n\t48,\n\t59,\n\t116,\n\t105,\n\t110,\n\t121,\n\t103,\n\t111,\n\t110,\n\t101,\n\t104,\n\t116,\n\t109,\n\t108,\n\t115,\n\t101,\n\t108,\n\t108,\n\t100,\n\t114,\n\t117,\n\t103,\n\t70,\n\t82,\n\t69,\n\t69,\n\t110,\n\t111,\n\t100,\n\t101,\n\t110,\n\t105,\n\t99,\n\t107,\n\t63,\n\t105,\n\t100,\n\t61,\n\t108,\n\t111,\n\t115,\n\t101,\n\t110,\n\t117,\n\t108,\n\t108,\n\t118,\n\t97,\n\t115,\n\t116,\n\t119,\n\t105,\n\t110,\n\t100,\n\t82,\n\t83,\n\t83,\n\t32,\n\t119,\n\t101,\n\t97,\n\t114,\n\t114,\n\t101,\n\t108,\n\t121,\n\t98,\n\t101,\n\t101,\n\t110,\n\t115,\n\t97,\n\t109,\n\t101,\n\t100,\n\t117,\n\t107,\n\t101,\n\t110,\n\t97,\n\t115,\n\t97,\n\t99,\n\t97,\n\t112,\n\t101,\n\t119,\n\t105,\n\t115,\n\t104,\n\t103,\n\t117,\n\t108,\n\t102,\n\t84,\n\t50,\n\t51,\n\t58,\n\t104,\n\t105,\n\t116,\n\t115,\n\t115,\n\t108,\n\t111,\n\t116,\n\t103,\n\t97,\n\t116,\n\t101,\n\t107,\n\t105,\n\t99,\n\t107,\n\t98,\n\t108,\n\t117,\n\t114,\n\t116,\n\t104,\n\t101,\n\t121,\n\t49,\n\t53,\n\t112,\n\t120,\n\t39,\n\t39,\n\t41,\n\t59,\n\t41,\n\t59,\n\t34,\n\t62,\n\t109,\n\t115,\n\t105,\n\t101,\n\t119,\n\t105,\n\t110,\n\t115,\n\t98,\n\t105,\n\t114,\n\t100,\n\t115,\n\t111,\n\t114,\n\t116,\n\t98,\n\t101,\n\t116,\n\t97,\n\t115,\n\t101,\n\t101,\n\t107,\n\t84,\n\t49,\n\t56,\n\t58,\n\t111,\n\t114,\n\t100,\n\t115,\n\t116,\n\t114,\n\t101,\n\t101,\n\t109,\n\t97,\n\t108,\n\t108,\n\t54,\n\t48,\n\t112,\n\t120,\n\t102,\n\t97,\n\t114,\n\t109,\n\t226,\n\t128,\n\t153,\n\t115,\n\t98,\n\t111,\n\t121,\n\t115,\n\t91,\n\t48,\n\t93,\n\t46,\n\t39,\n\t41,\n\t59,\n\t34,\n\t80,\n\t79,\n\t83,\n\t84,\n\t98,\n\t101,\n\t97,\n\t114,\n\t107,\n\t105,\n\t100,\n\t115,\n\t41,\n\t59,\n\t125,\n\t125,\n\t109,\n\t97,\n\t114,\n\t121,\n\t116,\n\t101,\n\t110,\n\t100,\n\t40,\n\t85,\n\t75,\n\t41,\n\t113,\n\t117,\n\t97,\n\t100,\n\t122,\n\t104,\n\t58,\n\t230,\n\t45,\n\t115,\n\t105,\n\t122,\n\t45,\n\t45,\n\t45,\n\t45,\n\t112,\n\t114,\n\t111,\n\t112,\n\t39,\n\t41,\n\t59,\n\t13,\n\t108,\n\t105,\n\t102,\n\t116,\n\t84,\n\t49,\n\t57,\n\t58,\n\t118,\n\t105,\n\t99,\n\t101,\n\t97,\n\t110,\n\t100,\n\t121,\n\t100,\n\t101,\n\t98,\n\t116,\n\t62,\n\t82,\n\t83,\n\t83,\n\t112,\n\t111,\n\t111,\n\t108,\n\t110,\n\t101,\n\t99,\n\t107,\n\t98,\n\t108,\n\t111,\n\t119,\n\t84,\n\t49,\n\t54,\n\t58,\n\t100,\n\t111,\n\t111,\n\t114,\n\t101,\n\t118,\n\t97,\n\t108,\n\t84,\n\t49,\n\t55,\n\t58,\n\t108,\n\t101,\n\t116,\n\t115,\n\t102,\n\t97,\n\t105,\n\t108,\n\t111,\n\t114,\n\t97,\n\t108,\n\t112,\n\t111,\n\t108,\n\t108,\n\t110,\n\t111,\n\t118,\n\t97,\n\t99,\n\t111,\n\t108,\n\t115,\n\t103,\n\t101,\n\t110,\n\t101,\n\t32,\n\t226,\n\t128,\n\t148,\n\t115,\n\t111,\n\t102,\n\t116,\n\t114,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t108,\n\t108,\n\t114,\n\t111,\n\t115,\n\t115,\n\t60,\n\t104,\n\t51,\n\t62,\n\t112,\n\t111,\n\t117,\n\t114,\n\t102,\n\t97,\n\t100,\n\t101,\n\t112,\n\t105,\n\t110,\n\t107,\n\t60,\n\t116,\n\t114,\n\t62,\n\t109,\n\t105,\n\t110,\n\t105,\n\t41,\n\t124,\n\t33,\n\t40,\n\t109,\n\t105,\n\t110,\n\t101,\n\t122,\n\t104,\n\t58,\n\t232,\n\t98,\n\t97,\n\t114,\n\t115,\n\t104,\n\t101,\n\t97,\n\t114,\n\t48,\n\t48,\n\t41,\n\t59,\n\t109,\n\t105,\n\t108,\n\t107,\n\t32,\n\t45,\n\t45,\n\t62,\n\t105,\n\t114,\n\t111,\n\t110,\n\t102,\n\t114,\n\t101,\n\t100,\n\t100,\n\t105,\n\t115,\n\t107,\n\t119,\n\t101,\n\t110,\n\t116,\n\t115,\n\t111,\n\t105,\n\t108,\n\t112,\n\t117,\n\t116,\n\t115,\n\t47,\n\t106,\n\t115,\n\t47,\n\t104,\n\t111,\n\t108,\n\t121,\n\t84,\n\t50,\n\t50,\n\t58,\n\t73,\n\t83,\n\t66,\n\t78,\n\t84,\n\t50,\n\t48,\n\t58,\n\t97,\n\t100,\n\t97,\n\t109,\n\t115,\n\t101,\n\t101,\n\t115,\n\t60,\n\t104,\n\t50,\n\t62,\n\t106,\n\t115,\n\t111,\n\t110,\n\t39,\n\t44,\n\t32,\n\t39,\n\t99,\n\t111,\n\t110,\n\t116,\n\t84,\n\t50,\n\t49,\n\t58,\n\t32,\n\t82,\n\t83,\n\t83,\n\t108,\n\t111,\n\t111,\n\t112,\n\t97,\n\t115,\n\t105,\n\t97,\n\t109,\n\t111,\n\t111,\n\t110,\n\t60,\n\t47,\n\t112,\n\t62,\n\t115,\n\t111,\n\t117,\n\t108,\n\t76,\n\t73,\n\t78,\n\t69,\n\t102,\n\t111,\n\t114,\n\t116,\n\t99,\n\t97,\n\t114,\n\t116,\n\t84,\n\t49,\n\t52,\n\t58,\n\t60,\n\t104,\n\t49,\n\t62,\n\t56,\n\t48,\n\t112,\n\t120,\n\t33,\n\t45,\n\t45,\n\t60,\n\t57,\n\t112,\n\t120,\n\t59,\n\t84,\n\t48,\n\t52,\n\t58,\n\t109,\n\t105,\n\t107,\n\t101,\n\t58,\n\t52,\n\t54,\n\t90,\n\t110,\n\t105,\n\t99,\n\t101,\n\t105,\n\t110,\n\t99,\n\t104,\n\t89,\n\t111,\n\t114,\n\t107,\n\t114,\n\t105,\n\t99,\n\t101,\n\t122,\n\t104,\n\t58,\n\t228,\n\t39,\n\t41,\n\t41,\n\t59,\n\t112,\n\t117,\n\t114,\n\t101,\n\t109,\n\t97,\n\t103,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t111,\n\t110,\n\t101,\n\t98,\n\t111,\n\t110,\n\t100,\n\t58,\n\t51,\n\t55,\n\t90,\n\t95,\n\t111,\n\t102,\n\t95,\n\t39,\n\t93,\n\t41,\n\t59,\n\t48,\n\t48,\n\t48,\n\t44,\n\t122,\n\t104,\n\t58,\n\t231,\n\t116,\n\t97,\n\t110,\n\t107,\n\t121,\n\t97,\n\t114,\n\t100,\n\t98,\n\t111,\n\t119,\n\t108,\n\t98,\n\t117,\n\t115,\n\t104,\n\t58,\n\t53,\n\t54,\n\t90,\n\t74,\n\t97,\n\t118,\n\t97,\n\t51,\n\t48,\n\t112,\n\t120,\n\t10,\n\t124,\n\t125,\n\t10,\n\t37,\n\t67,\n\t51,\n\t37,\n\t58,\n\t51,\n\t52,\n\t90,\n\t106,\n\t101,\n\t102,\n\t102,\n\t69,\n\t88,\n\t80,\n\t73,\n\t99,\n\t97,\n\t115,\n\t104,\n\t118,\n\t105,\n\t115,\n\t97,\n\t103,\n\t111,\n\t108,\n\t102,\n\t115,\n\t110,\n\t111,\n\t119,\n\t122,\n\t104,\n\t58,\n\t233,\n\t113,\n\t117,\n\t101,\n\t114,\n\t46,\n\t99,\n\t115,\n\t115,\n\t115,\n\t105,\n\t99,\n\t107,\n\t109,\n\t101,\n\t97,\n\t116,\n\t109,\n\t105,\n\t110,\n\t46,\n\t98,\n\t105,\n\t110,\n\t100,\n\t100,\n\t101,\n\t108,\n\t108,\n\t104,\n\t105,\n\t114,\n\t101,\n\t112,\n\t105,\n\t99,\n\t115,\n\t114,\n\t101,\n\t110,\n\t116,\n\t58,\n\t51,\n\t54,\n\t90,\n\t72,\n\t84,\n\t84,\n\t80,\n\t45,\n\t50,\n\t48,\n\t49,\n\t102,\n\t111,\n\t116,\n\t111,\n\t119,\n\t111,\n\t108,\n\t102,\n\t69,\n\t78,\n\t68,\n\t32,\n\t120,\n\t98,\n\t111,\n\t120,\n\t58,\n\t53,\n\t52,\n\t90,\n\t66,\n\t79,\n\t68,\n\t89,\n\t100,\n\t105,\n\t99,\n\t107,\n\t59,\n\t10,\n\t125,\n\t10,\n\t101,\n\t120,\n\t105,\n\t116,\n\t58,\n\t51,\n\t53,\n\t90,\n\t118,\n\t97,\n\t114,\n\t115,\n\t98,\n\t101,\n\t97,\n\t116,\n\t39,\n\t125,\n\t41,\n\t59,\n\t100,\n\t105,\n\t101,\n\t116,\n\t57,\n\t57,\n\t57,\n\t59,\n\t97,\n\t110,\n\t110,\n\t101,\n\t125,\n\t125,\n\t60,\n\t47,\n\t91,\n\t105,\n\t93,\n\t46,\n\t76,\n\t97,\n\t110,\n\t103,\n\t107,\n\t109,\n\t194,\n\t178,\n\t119,\n\t105,\n\t114,\n\t101,\n\t116,\n\t111,\n\t121,\n\t115,\n\t97,\n\t100,\n\t100,\n\t115,\n\t115,\n\t101,\n\t97,\n\t108,\n\t97,\n\t108,\n\t101,\n\t120,\n\t59,\n\t10,\n\t9,\n\t125,\n\t101,\n\t99,\n\t104,\n\t111,\n\t110,\n\t105,\n\t110,\n\t101,\n\t46,\n\t111,\n\t114,\n\t103,\n\t48,\n\t48,\n\t53,\n\t41,\n\t116,\n\t111,\n\t110,\n\t121,\n\t106,\n\t101,\n\t119,\n\t115,\n\t115,\n\t97,\n\t110,\n\t100,\n\t108,\n\t101,\n\t103,\n\t115,\n\t114,\n\t111,\n\t111,\n\t102,\n\t48,\n\t48,\n\t48,\n\t41,\n\t32,\n\t50,\n\t48,\n\t48,\n\t119,\n\t105,\n\t110,\n\t101,\n\t103,\n\t101,\n\t97,\n\t114,\n\t100,\n\t111,\n\t103,\n\t115,\n\t98,\n\t111,\n\t111,\n\t116,\n\t103,\n\t97,\n\t114,\n\t121,\n\t99,\n\t117,\n\t116,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t120,\n\t109,\n\t108,\n\t99,\n\t111,\n\t99,\n\t107,\n\t103,\n\t97,\n\t110,\n\t103,\n\t36,\n\t40,\n\t39,\n\t46,\n\t53,\n\t48,\n\t112,\n\t120,\n\t80,\n\t104,\n\t46,\n\t68,\n\t109,\n\t105,\n\t115,\n\t99,\n\t97,\n\t108,\n\t97,\n\t110,\n\t108,\n\t111,\n\t97,\n\t110,\n\t100,\n\t101,\n\t115,\n\t107,\n\t109,\n\t105,\n\t108,\n\t101,\n\t114,\n\t121,\n\t97,\n\t110,\n\t117,\n\t110,\n\t105,\n\t120,\n\t100,\n\t105,\n\t115,\n\t99,\n\t41,\n\t59,\n\t125,\n\t10,\n\t100,\n\t117,\n\t115,\n\t116,\n\t99,\n\t108,\n\t105,\n\t112,\n\t41,\n\t46,\n\t10,\n\t10,\n\t55,\n\t48,\n\t112,\n\t120,\n\t45,\n\t50,\n\t48,\n\t48,\n\t68,\n\t86,\n\t68,\n\t115,\n\t55,\n\t93,\n\t62,\n\t60,\n\t116,\n\t97,\n\t112,\n\t101,\n\t100,\n\t101,\n\t109,\n\t111,\n\t105,\n\t43,\n\t43,\n\t41,\n\t119,\n\t97,\n\t103,\n\t101,\n\t101,\n\t117,\n\t114,\n\t111,\n\t112,\n\t104,\n\t105,\n\t108,\n\t111,\n\t112,\n\t116,\n\t115,\n\t104,\n\t111,\n\t108,\n\t101,\n\t70,\n\t65,\n\t81,\n\t115,\n\t97,\n\t115,\n\t105,\n\t110,\n\t45,\n\t50,\n\t54,\n\t84,\n\t108,\n\t97,\n\t98,\n\t115,\n\t112,\n\t101,\n\t116,\n\t115,\n\t85,\n\t82,\n\t76,\n\t32,\n\t98,\n\t117,\n\t108,\n\t107,\n\t99,\n\t111,\n\t111,\n\t107,\n\t59,\n\t125,\n\t13,\n\t10,\n\t72,\n\t69,\n\t65,\n\t68,\n\t91,\n\t48,\n\t93,\n\t41,\n\t97,\n\t98,\n\t98,\n\t114,\n\t106,\n\t117,\n\t97,\n\t110,\n\t40,\n\t49,\n\t57,\n\t56,\n\t108,\n\t101,\n\t115,\n\t104,\n\t116,\n\t119,\n\t105,\n\t110,\n\t60,\n\t47,\n\t105,\n\t62,\n\t115,\n\t111,\n\t110,\n\t121,\n\t103,\n\t117,\n\t121,\n\t115,\n\t102,\n\t117,\n\t99,\n\t107,\n\t112,\n\t105,\n\t112,\n\t101,\n\t124,\n\t45,\n\t10,\n\t33,\n\t48,\n\t48,\n\t50,\n\t41,\n\t110,\n\t100,\n\t111,\n\t119,\n\t91,\n\t49,\n\t93,\n\t59,\n\t91,\n\t93,\n\t59,\n\t10,\n\t76,\n\t111,\n\t103,\n\t32,\n\t115,\n\t97,\n\t108,\n\t116,\n\t13,\n\t10,\n\t9,\n\t9,\n\t98,\n\t97,\n\t110,\n\t103,\n\t116,\n\t114,\n\t105,\n\t109,\n\t98,\n\t97,\n\t116,\n\t104,\n\t41,\n\t123,\n\t13,\n\t10,\n\t48,\n\t48,\n\t112,\n\t120,\n\t10,\n\t125,\n\t41,\n\t59,\n\t107,\n\t111,\n\t58,\n\t236,\n\t102,\n\t101,\n\t101,\n\t115,\n\t97,\n\t100,\n\t62,\n\t13,\n\t115,\n\t58,\n\t47,\n\t47,\n\t32,\n\t91,\n\t93,\n\t59,\n\t116,\n\t111,\n\t108,\n\t108,\n\t112,\n\t108,\n\t117,\n\t103,\n\t40,\n\t41,\n\t123,\n\t10,\n\t123,\n\t13,\n\t10,\n\t32,\n\t46,\n\t106,\n\t115,\n\t39,\n\t50,\n\t48,\n\t48,\n\t112,\n\t100,\n\t117,\n\t97,\n\t108,\n\t98,\n\t111,\n\t97,\n\t116,\n\t46,\n\t74,\n\t80,\n\t71,\n\t41,\n\t59,\n\t10,\n\t125,\n\t113,\n\t117,\n\t111,\n\t116,\n\t41,\n\t59,\n\t10,\n\t10,\n\t39,\n\t41,\n\t59,\n\t10,\n\t13,\n\t10,\n\t125,\n\t13,\n\t50,\n\t48,\n\t49,\n\t52,\n\t50,\n\t48,\n\t49,\n\t53,\n\t50,\n\t48,\n\t49,\n\t54,\n\t50,\n\t48,\n\t49,\n\t55,\n\t50,\n\t48,\n\t49,\n\t56,\n\t50,\n\t48,\n\t49,\n\t57,\n\t50,\n\t48,\n\t50,\n\t48,\n\t50,\n\t48,\n\t50,\n\t49,\n\t50,\n\t48,\n\t50,\n\t50,\n\t50,\n\t48,\n\t50,\n\t51,\n\t50,\n\t48,\n\t50,\n\t52,\n\t50,\n\t48,\n\t50,\n\t53,\n\t50,\n\t48,\n\t50,\n\t54,\n\t50,\n\t48,\n\t50,\n\t55,\n\t50,\n\t48,\n\t50,\n\t56,\n\t50,\n\t48,\n\t50,\n\t57,\n\t50,\n\t48,\n\t51,\n\t48,\n\t50,\n\t48,\n\t51,\n\t49,\n\t50,\n\t48,\n\t51,\n\t50,\n\t50,\n\t48,\n\t51,\n\t51,\n\t50,\n\t48,\n\t51,\n\t52,\n\t50,\n\t48,\n\t51,\n\t53,\n\t50,\n\t48,\n\t51,\n\t54,\n\t50,\n\t48,\n\t51,\n\t55,\n\t50,\n\t48,\n\t49,\n\t51,\n\t50,\n\t48,\n\t49,\n\t50,\n\t50,\n\t48,\n\t49,\n\t49,\n\t50,\n\t48,\n\t49,\n\t48,\n\t50,\n\t48,\n\t48,\n\t57,\n\t50,\n\t48,\n\t48,\n\t56,\n\t50,\n\t48,\n\t48,\n\t55,\n\t50,\n\t48,\n\t48,\n\t54,\n\t50,\n\t48,\n\t48,\n\t53,\n\t50,\n\t48,\n\t48,\n\t52,\n\t50,\n\t48,\n\t48,\n\t51,\n\t50,\n\t48,\n\t48,\n\t50,\n\t50,\n\t48,\n\t48,\n\t49,\n\t50,\n\t48,\n\t48,\n\t48,\n\t49,\n\t57,\n\t57,\n\t57,\n\t49,\n\t57,\n\t57,\n\t56,\n\t49,\n\t57,\n\t57,\n\t55,\n\t49,\n\t57,\n\t57,\n\t54,\n\t49,\n\t57,\n\t57,\n\t53,\n\t49,\n\t57,\n\t57,\n\t52,\n\t49,\n\t57,\n\t57,\n\t51,\n\t49,\n\t57,\n\t57,\n\t50,\n\t49,\n\t57,\n\t57,\n\t49,\n\t49,\n\t57,\n\t57,\n\t48,\n\t49,\n\t57,\n\t56,\n\t57,\n\t49,\n\t57,\n\t56,\n\t56,\n\t49,\n\t57,\n\t56,\n\t55,\n\t49,\n\t57,\n\t56,\n\t54,\n\t49,\n\t57,\n\t56,\n\t53,\n\t49,\n\t57,\n\t56,\n\t52,\n\t49,\n\t57,\n\t56,\n\t51,\n\t49,\n\t57,\n\t56,\n\t50,\n\t49,\n\t57,\n\t56,\n\t49,\n\t49,\n\t57,\n\t56,\n\t48,\n\t49,\n\t57,\n\t55,\n\t57,\n\t49,\n\t57,\n\t55,\n\t56,\n\t49,\n\t57,\n\t55,\n\t55,\n\t49,\n\t57,\n\t55,\n\t54,\n\t49,\n\t57,\n\t55,\n\t53,\n\t49,\n\t57,\n\t55,\n\t52,\n\t49,\n\t57,\n\t55,\n\t51,\n\t49,\n\t57,\n\t55,\n\t50,\n\t49,\n\t57,\n\t55,\n\t49,\n\t49,\n\t57,\n\t55,\n\t48,\n\t49,\n\t57,\n\t54,\n\t57,\n\t49,\n\t57,\n\t54,\n\t56,\n\t49,\n\t57,\n\t54,\n\t55,\n\t49,\n\t57,\n\t54,\n\t54,\n\t49,\n\t57,\n\t54,\n\t53,\n\t49,\n\t57,\n\t54,\n\t52,\n\t49,\n\t57,\n\t54,\n\t51,\n\t49,\n\t57,\n\t54,\n\t50,\n\t49,\n\t57,\n\t54,\n\t49,\n\t49,\n\t57,\n\t54,\n\t48,\n\t49,\n\t57,\n\t53,\n\t57,\n\t49,\n\t57,\n\t53,\n\t56,\n\t49,\n\t57,\n\t53,\n\t55,\n\t49,\n\t57,\n\t53,\n\t54,\n\t49,\n\t57,\n\t53,\n\t53,\n\t49,\n\t57,\n\t53,\n\t52,\n\t49,\n\t57,\n\t53,\n\t51,\n\t49,\n\t57,\n\t53,\n\t50,\n\t49,\n\t57,\n\t53,\n\t49,\n\t49,\n\t57,\n\t53,\n\t48,\n\t49,\n\t48,\n\t48,\n\t48,\n\t49,\n\t48,\n\t50,\n\t52,\n\t49,\n\t51,\n\t57,\n\t52,\n\t48,\n\t48,\n\t48,\n\t48,\n\t57,\n\t57,\n\t57,\n\t57,\n\t99,\n\t111,\n\t109,\n\t111,\n\t109,\n\t195,\n\t161,\n\t115,\n\t101,\n\t115,\n\t116,\n\t101,\n\t101,\n\t115,\n\t116,\n\t97,\n\t112,\n\t101,\n\t114,\n\t111,\n\t116,\n\t111,\n\t100,\n\t111,\n\t104,\n\t97,\n\t99,\n\t101,\n\t99,\n\t97,\n\t100,\n\t97,\n\t97,\n\t195,\n\t177,\n\t111,\n\t98,\n\t105,\n\t101,\n\t110,\n\t100,\n\t195,\n\t173,\n\t97,\n\t97,\n\t115,\n\t195,\n\t173,\n\t118,\n\t105,\n\t100,\n\t97,\n\t99,\n\t97,\n\t115,\n\t111,\n\t111,\n\t116,\n\t114,\n\t111,\n\t102,\n\t111,\n\t114,\n\t111,\n\t115,\n\t111,\n\t108,\n\t111,\n\t111,\n\t116,\n\t114,\n\t97,\n\t99,\n\t117,\n\t97,\n\t108,\n\t100,\n\t105,\n\t106,\n\t111,\n\t115,\n\t105,\n\t100,\n\t111,\n\t103,\n\t114,\n\t97,\n\t110,\n\t116,\n\t105,\n\t112,\n\t111,\n\t116,\n\t101,\n\t109,\n\t97,\n\t100,\n\t101,\n\t98,\n\t101,\n\t97,\n\t108,\n\t103,\n\t111,\n\t113,\n\t117,\n\t195,\n\t169,\n\t101,\n\t115,\n\t116,\n\t111,\n\t110,\n\t97,\n\t100,\n\t97,\n\t116,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t99,\n\t111,\n\t99,\n\t97,\n\t115,\n\t97,\n\t98,\n\t97,\n\t106,\n\t111,\n\t116,\n\t111,\n\t100,\n\t97,\n\t115,\n\t105,\n\t110,\n\t111,\n\t97,\n\t103,\n\t117,\n\t97,\n\t112,\n\t117,\n\t101,\n\t115,\n\t117,\n\t110,\n\t111,\n\t115,\n\t97,\n\t110,\n\t116,\n\t101,\n\t100,\n\t105,\n\t99,\n\t101,\n\t108,\n\t117,\n\t105,\n\t115,\n\t101,\n\t108,\n\t108,\n\t97,\n\t109,\n\t97,\n\t121,\n\t111,\n\t122,\n\t111,\n\t110,\n\t97,\n\t97,\n\t109,\n\t111,\n\t114,\n\t112,\n\t105,\n\t115,\n\t111,\n\t111,\n\t98,\n\t114,\n\t97,\n\t99,\n\t108,\n\t105,\n\t99,\n\t101,\n\t108,\n\t108,\n\t111,\n\t100,\n\t105,\n\t111,\n\t115,\n\t104,\n\t111,\n\t114,\n\t97,\n\t99,\n\t97,\n\t115,\n\t105,\n\t208,\n\t183,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t128,\n\t208,\n\t176,\n\t209,\n\t128,\n\t209,\n\t131,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t182,\n\t208,\n\t181,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t133,\n\t208,\n\t157,\n\t208,\n\t176,\n\t208,\n\t181,\n\t208,\n\t181,\n\t208,\n\t177,\n\t209,\n\t139,\n\t208,\n\t188,\n\t209,\n\t139,\n\t208,\n\t146,\n\t209,\n\t139,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t178,\n\t209,\n\t139,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t157,\n\t208,\n\t190,\n\t208,\n\t190,\n\t208,\n\t177,\n\t208,\n\t159,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t184,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t160,\n\t208,\n\t164,\n\t208,\n\t157,\n\t208,\n\t181,\n\t208,\n\t156,\n\t209,\n\t139,\n\t209,\n\t130,\n\t209,\n\t139,\n\t208,\n\t158,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t151,\n\t208,\n\t176,\n\t208,\n\t148,\n\t208,\n\t176,\n\t208,\n\t157,\n\t209,\n\t131,\n\t208,\n\t158,\n\t208,\n\t177,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t152,\n\t208,\n\t183,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t189,\n\t209,\n\t131,\n\t208,\n\t188,\n\t208,\n\t188,\n\t208,\n\t162,\n\t209,\n\t139,\n\t209,\n\t131,\n\t208,\n\t182,\n\t217,\n\t129,\n\t217,\n\t138,\n\t216,\n\t163,\n\t217,\n\t134,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t185,\n\t217,\n\t131,\n\t217,\n\t132,\n\t216,\n\t163,\n\t217,\n\t136,\n\t216,\n\t177,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t129,\n\t217,\n\t137,\n\t217,\n\t135,\n\t217,\n\t136,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t132,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t136,\n\t217,\n\t132,\n\t217,\n\t135,\n\t216,\n\t168,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t165,\n\t217,\n\t134,\n\t217,\n\t135,\n\t217,\n\t138,\n\t216,\n\t163,\n\t217,\n\t138,\n\t217,\n\t130,\n\t216,\n\t175,\n\t217,\n\t135,\n\t217,\n\t132,\n\t216,\n\t171,\n\t217,\n\t133,\n\t216,\n\t168,\n\t217,\n\t135,\n\t217,\n\t132,\n\t217,\n\t136,\n\t217,\n\t132,\n\t217,\n\t138,\n\t216,\n\t168,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t138,\n\t216,\n\t168,\n\t217,\n\t131,\n\t216,\n\t180,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t163,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t168,\n\t217,\n\t138,\n\t217,\n\t132,\n\t217,\n\t134,\n\t216,\n\t173,\n\t216,\n\t168,\n\t217,\n\t135,\n\t217,\n\t133,\n\t217,\n\t133,\n\t216,\n\t180,\n\t217,\n\t136,\n\t216,\n\t180,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t118,\n\t105,\n\t100,\n\t101,\n\t111,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t119,\n\t104,\n\t105,\n\t116,\n\t101,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t98,\n\t108,\n\t97,\n\t99,\n\t107,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t98,\n\t111,\n\t111,\n\t107,\n\t115,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t109,\n\t117,\n\t115,\n\t105,\n\t99,\n\t102,\n\t105,\n\t101,\n\t108,\n\t100,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t108,\n\t101,\n\t118,\n\t101,\n\t108,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t98,\n\t111,\n\t97,\n\t114,\n\t100,\n\t104,\n\t111,\n\t117,\n\t115,\n\t101,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t119,\n\t111,\n\t114,\n\t107,\n\t115,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t116,\n\t111,\n\t100,\n\t97,\n\t121,\n\t119,\n\t97,\n\t116,\n\t101,\n\t114,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t100,\n\t101,\n\t97,\n\t116,\n\t104,\n\t112,\n\t111,\n\t119,\n\t101,\n\t114,\n\t112,\n\t104,\n\t111,\n\t110,\n\t101,\n\t110,\n\t105,\n\t103,\n\t104,\n\t116,\n\t101,\n\t114,\n\t114,\n\t111,\n\t114,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t116,\n\t101,\n\t114,\n\t109,\n\t115,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t116,\n\t111,\n\t111,\n\t108,\n\t115,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t108,\n\t111,\n\t99,\n\t97,\n\t108,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t119,\n\t111,\n\t114,\n\t100,\n\t115,\n\t103,\n\t97,\n\t109,\n\t101,\n\t115,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t115,\n\t112,\n\t97,\n\t99,\n\t101,\n\t102,\n\t111,\n\t99,\n\t117,\n\t115,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t109,\n\t111,\n\t100,\n\t101,\n\t108,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t103,\n\t117,\n\t105,\n\t100,\n\t101,\n\t114,\n\t97,\n\t100,\n\t105,\n\t111,\n\t115,\n\t104,\n\t97,\n\t114,\n\t101,\n\t119,\n\t111,\n\t109,\n\t101,\n\t110,\n\t97,\n\t103,\n\t97,\n\t105,\n\t110,\n\t109,\n\t111,\n\t110,\n\t101,\n\t121,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t110,\n\t97,\n\t109,\n\t101,\n\t115,\n\t121,\n\t111,\n\t117,\n\t110,\n\t103,\n\t108,\n\t105,\n\t110,\n\t101,\n\t115,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t103,\n\t114,\n\t101,\n\t101,\n\t110,\n\t102,\n\t114,\n\t111,\n\t110,\n\t116,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t119,\n\t97,\n\t116,\n\t99,\n\t104,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t112,\n\t114,\n\t105,\n\t99,\n\t101,\n\t114,\n\t117,\n\t108,\n\t101,\n\t115,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t118,\n\t105,\n\t115,\n\t105,\n\t116,\n\t105,\n\t115,\n\t115,\n\t117,\n\t101,\n\t97,\n\t114,\n\t101,\n\t97,\n\t115,\n\t98,\n\t101,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t116,\n\t111,\n\t116,\n\t97,\n\t108,\n\t104,\n\t111,\n\t117,\n\t114,\n\t115,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t112,\n\t114,\n\t105,\n\t110,\n\t116,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t98,\n\t117,\n\t105,\n\t108,\n\t116,\n\t108,\n\t105,\n\t110,\n\t107,\n\t115,\n\t115,\n\t112,\n\t101,\n\t101,\n\t100,\n\t115,\n\t116,\n\t117,\n\t100,\n\t121,\n\t116,\n\t114,\n\t97,\n\t100,\n\t101,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t115,\n\t101,\n\t110,\n\t115,\n\t101,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t104,\n\t111,\n\t119,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t115,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t97,\n\t100,\n\t100,\n\t101,\n\t100,\n\t115,\n\t116,\n\t105,\n\t108,\n\t108,\n\t109,\n\t111,\n\t118,\n\t101,\n\t100,\n\t116,\n\t97,\n\t107,\n\t101,\n\t110,\n\t97,\n\t98,\n\t111,\n\t118,\n\t101,\n\t102,\n\t108,\n\t97,\n\t115,\n\t104,\n\t102,\n\t105,\n\t120,\n\t101,\n\t100,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t118,\n\t105,\n\t101,\n\t119,\n\t115,\n\t99,\n\t104,\n\t101,\n\t99,\n\t107,\n\t108,\n\t101,\n\t103,\n\t97,\n\t108,\n\t114,\n\t105,\n\t118,\n\t101,\n\t114,\n\t105,\n\t116,\n\t101,\n\t109,\n\t115,\n\t113,\n\t117,\n\t105,\n\t99,\n\t107,\n\t115,\n\t104,\n\t97,\n\t112,\n\t101,\n\t104,\n\t117,\n\t109,\n\t97,\n\t110,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t103,\n\t111,\n\t105,\n\t110,\n\t103,\n\t109,\n\t111,\n\t118,\n\t105,\n\t101,\n\t116,\n\t104,\n\t105,\n\t114,\n\t100,\n\t98,\n\t97,\n\t115,\n\t105,\n\t99,\n\t112,\n\t101,\n\t97,\n\t99,\n\t101,\n\t115,\n\t116,\n\t97,\n\t103,\n\t101,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t108,\n\t111,\n\t103,\n\t105,\n\t110,\n\t105,\n\t100,\n\t101,\n\t97,\n\t115,\n\t119,\n\t114,\n\t111,\n\t116,\n\t101,\n\t112,\n\t97,\n\t103,\n\t101,\n\t115,\n\t117,\n\t115,\n\t101,\n\t114,\n\t115,\n\t100,\n\t114,\n\t105,\n\t118,\n\t101,\n\t115,\n\t116,\n\t111,\n\t114,\n\t101,\n\t98,\n\t114,\n\t101,\n\t97,\n\t107,\n\t115,\n\t111,\n\t117,\n\t116,\n\t104,\n\t118,\n\t111,\n\t105,\n\t99,\n\t101,\n\t115,\n\t105,\n\t116,\n\t101,\n\t115,\n\t109,\n\t111,\n\t110,\n\t116,\n\t104,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t98,\n\t117,\n\t105,\n\t108,\n\t100,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t101,\n\t97,\n\t114,\n\t116,\n\t104,\n\t102,\n\t111,\n\t114,\n\t117,\n\t109,\n\t116,\n\t104,\n\t114,\n\t101,\n\t101,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t112,\n\t97,\n\t114,\n\t116,\n\t121,\n\t67,\n\t108,\n\t105,\n\t99,\n\t107,\n\t108,\n\t111,\n\t119,\n\t101,\n\t114,\n\t108,\n\t105,\n\t118,\n\t101,\n\t115,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t108,\n\t97,\n\t121,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t114,\n\t121,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t117,\n\t115,\n\t97,\n\t103,\n\t101,\n\t115,\n\t111,\n\t117,\n\t110,\n\t100,\n\t99,\n\t111,\n\t117,\n\t114,\n\t116,\n\t121,\n\t111,\n\t117,\n\t114,\n\t32,\n\t98,\n\t105,\n\t114,\n\t116,\n\t104,\n\t112,\n\t111,\n\t112,\n\t117,\n\t112,\n\t116,\n\t121,\n\t112,\n\t101,\n\t115,\n\t97,\n\t112,\n\t112,\n\t108,\n\t121,\n\t73,\n\t109,\n\t97,\n\t103,\n\t101,\n\t98,\n\t101,\n\t105,\n\t110,\n\t103,\n\t117,\n\t112,\n\t112,\n\t101,\n\t114,\n\t110,\n\t111,\n\t116,\n\t101,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t121,\n\t115,\n\t104,\n\t111,\n\t119,\n\t115,\n\t109,\n\t101,\n\t97,\n\t110,\n\t115,\n\t101,\n\t120,\n\t116,\n\t114,\n\t97,\n\t109,\n\t97,\n\t116,\n\t99,\n\t104,\n\t116,\n\t114,\n\t97,\n\t99,\n\t107,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t101,\n\t97,\n\t114,\n\t108,\n\t121,\n\t98,\n\t101,\n\t103,\n\t97,\n\t110,\n\t115,\n\t117,\n\t112,\n\t101,\n\t114,\n\t112,\n\t97,\n\t112,\n\t101,\n\t114,\n\t110,\n\t111,\n\t114,\n\t116,\n\t104,\n\t108,\n\t101,\n\t97,\n\t114,\n\t110,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t110,\n\t97,\n\t109,\n\t101,\n\t100,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t84,\n\t101,\n\t114,\n\t109,\n\t115,\n\t112,\n\t97,\n\t114,\n\t116,\n\t115,\n\t71,\n\t114,\n\t111,\n\t117,\n\t112,\n\t98,\n\t114,\n\t97,\n\t110,\n\t100,\n\t117,\n\t115,\n\t105,\n\t110,\n\t103,\n\t119,\n\t111,\n\t109,\n\t97,\n\t110,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t114,\n\t101,\n\t97,\n\t100,\n\t121,\n\t97,\n\t117,\n\t100,\n\t105,\n\t111,\n\t116,\n\t97,\n\t107,\n\t101,\n\t115,\n\t119,\n\t104,\n\t105,\n\t108,\n\t101,\n\t46,\n\t99,\n\t111,\n\t109,\n\t47,\n\t108,\n\t105,\n\t118,\n\t101,\n\t100,\n\t99,\n\t97,\n\t115,\n\t101,\n\t115,\n\t100,\n\t97,\n\t105,\n\t108,\n\t121,\n\t99,\n\t104,\n\t105,\n\t108,\n\t100,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t106,\n\t117,\n\t100,\n\t103,\n\t101,\n\t116,\n\t104,\n\t111,\n\t115,\n\t101,\n\t117,\n\t110,\n\t105,\n\t116,\n\t115,\n\t110,\n\t101,\n\t118,\n\t101,\n\t114,\n\t98,\n\t114,\n\t111,\n\t97,\n\t100,\n\t99,\n\t111,\n\t97,\n\t115,\n\t116,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t97,\n\t112,\n\t112,\n\t108,\n\t101,\n\t102,\n\t105,\n\t108,\n\t101,\n\t115,\n\t99,\n\t121,\n\t99,\n\t108,\n\t101,\n\t115,\n\t99,\n\t101,\n\t110,\n\t101,\n\t112,\n\t108,\n\t97,\n\t110,\n\t115,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t119,\n\t114,\n\t105,\n\t116,\n\t101,\n\t113,\n\t117,\n\t101,\n\t101,\n\t110,\n\t112,\n\t105,\n\t101,\n\t99,\n\t101,\n\t101,\n\t109,\n\t97,\n\t105,\n\t108,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t111,\n\t108,\n\t100,\n\t101,\n\t114,\n\t112,\n\t104,\n\t111,\n\t116,\n\t111,\n\t108,\n\t105,\n\t109,\n\t105,\n\t116,\n\t99,\n\t97,\n\t99,\n\t104,\n\t101,\n\t99,\n\t105,\n\t118,\n\t105,\n\t108,\n\t115,\n\t99,\n\t97,\n\t108,\n\t101,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t109,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t116,\n\t111,\n\t117,\n\t99,\n\t104,\n\t98,\n\t111,\n\t117,\n\t110,\n\t100,\n\t114,\n\t111,\n\t121,\n\t97,\n\t108,\n\t97,\n\t115,\n\t107,\n\t101,\n\t100,\n\t119,\n\t104,\n\t111,\n\t108,\n\t101,\n\t115,\n\t105,\n\t110,\n\t99,\n\t101,\n\t115,\n\t116,\n\t111,\n\t99,\n\t107,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t102,\n\t97,\n\t105,\n\t116,\n\t104,\n\t104,\n\t101,\n\t97,\n\t114,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t121,\n\t111,\n\t102,\n\t102,\n\t101,\n\t114,\n\t115,\n\t99,\n\t111,\n\t112,\n\t101,\n\t111,\n\t119,\n\t110,\n\t101,\n\t100,\n\t109,\n\t105,\n\t103,\n\t104,\n\t116,\n\t97,\n\t108,\n\t98,\n\t117,\n\t109,\n\t116,\n\t104,\n\t105,\n\t110,\n\t107,\n\t98,\n\t108,\n\t111,\n\t111,\n\t100,\n\t97,\n\t114,\n\t114,\n\t97,\n\t121,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t116,\n\t114,\n\t117,\n\t115,\n\t116,\n\t99,\n\t97,\n\t110,\n\t111,\n\t110,\n\t117,\n\t110,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t118,\n\t97,\n\t108,\n\t105,\n\t100,\n\t115,\n\t116,\n\t111,\n\t110,\n\t101,\n\t83,\n\t116,\n\t121,\n\t108,\n\t101,\n\t76,\n\t111,\n\t103,\n\t105,\n\t110,\n\t104,\n\t97,\n\t112,\n\t112,\n\t121,\n\t111,\n\t99,\n\t99,\n\t117,\n\t114,\n\t108,\n\t101,\n\t102,\n\t116,\n\t58,\n\t102,\n\t114,\n\t101,\n\t115,\n\t104,\n\t113,\n\t117,\n\t105,\n\t116,\n\t101,\n\t102,\n\t105,\n\t108,\n\t109,\n\t115,\n\t103,\n\t114,\n\t97,\n\t100,\n\t101,\n\t110,\n\t101,\n\t101,\n\t100,\n\t115,\n\t117,\n\t114,\n\t98,\n\t97,\n\t110,\n\t102,\n\t105,\n\t103,\n\t104,\n\t116,\n\t98,\n\t97,\n\t115,\n\t105,\n\t115,\n\t104,\n\t111,\n\t118,\n\t101,\n\t114,\n\t97,\n\t117,\n\t116,\n\t111,\n\t59,\n\t114,\n\t111,\n\t117,\n\t116,\n\t101,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t109,\n\t105,\n\t120,\n\t101,\n\t100,\n\t102,\n\t105,\n\t110,\n\t97,\n\t108,\n\t89,\n\t111,\n\t117,\n\t114,\n\t32,\n\t115,\n\t108,\n\t105,\n\t100,\n\t101,\n\t116,\n\t111,\n\t112,\n\t105,\n\t99,\n\t98,\n\t114,\n\t111,\n\t119,\n\t110,\n\t97,\n\t108,\n\t111,\n\t110,\n\t101,\n\t100,\n\t114,\n\t97,\n\t119,\n\t110,\n\t115,\n\t112,\n\t108,\n\t105,\n\t116,\n\t114,\n\t101,\n\t97,\n\t99,\n\t104,\n\t82,\n\t105,\n\t103,\n\t104,\n\t116,\n\t100,\n\t97,\n\t116,\n\t101,\n\t115,\n\t109,\n\t97,\n\t114,\n\t99,\n\t104,\n\t113,\n\t117,\n\t111,\n\t116,\n\t101,\n\t103,\n\t111,\n\t111,\n\t100,\n\t115,\n\t76,\n\t105,\n\t110,\n\t107,\n\t115,\n\t100,\n\t111,\n\t117,\n\t98,\n\t116,\n\t97,\n\t115,\n\t121,\n\t110,\n\t99,\n\t116,\n\t104,\n\t117,\n\t109,\n\t98,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t99,\n\t104,\n\t105,\n\t101,\n\t102,\n\t121,\n\t111,\n\t117,\n\t116,\n\t104,\n\t110,\n\t111,\n\t118,\n\t101,\n\t108,\n\t49,\n\t48,\n\t112,\n\t120,\n\t59,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t117,\n\t110,\n\t116,\n\t105,\n\t108,\n\t104,\n\t97,\n\t110,\n\t100,\n\t115,\n\t67,\n\t104,\n\t101,\n\t99,\n\t107,\n\t83,\n\t112,\n\t97,\n\t99,\n\t101,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t106,\n\t97,\n\t109,\n\t101,\n\t115,\n\t101,\n\t113,\n\t117,\n\t97,\n\t108,\n\t116,\n\t119,\n\t105,\n\t99,\n\t101,\n\t48,\n\t44,\n\t48,\n\t48,\n\t48,\n\t83,\n\t116,\n\t97,\n\t114,\n\t116,\n\t112,\n\t97,\n\t110,\n\t101,\n\t108,\n\t115,\n\t111,\n\t110,\n\t103,\n\t115,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t104,\n\t105,\n\t102,\n\t116,\n\t119,\n\t111,\n\t114,\n\t116,\n\t104,\n\t112,\n\t111,\n\t115,\n\t116,\n\t115,\n\t108,\n\t101,\n\t97,\n\t100,\n\t115,\n\t119,\n\t101,\n\t101,\n\t107,\n\t115,\n\t97,\n\t118,\n\t111,\n\t105,\n\t100,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t109,\n\t105,\n\t108,\n\t101,\n\t115,\n\t112,\n\t108,\n\t97,\n\t110,\n\t101,\n\t115,\n\t109,\n\t97,\n\t114,\n\t116,\n\t97,\n\t108,\n\t112,\n\t104,\n\t97,\n\t112,\n\t108,\n\t97,\n\t110,\n\t116,\n\t109,\n\t97,\n\t114,\n\t107,\n\t115,\n\t114,\n\t97,\n\t116,\n\t101,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t115,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t115,\n\t97,\n\t108,\n\t101,\n\t115,\n\t116,\n\t101,\n\t120,\n\t116,\n\t115,\n\t115,\n\t116,\n\t97,\n\t114,\n\t115,\n\t119,\n\t114,\n\t111,\n\t110,\n\t103,\n\t60,\n\t47,\n\t104,\n\t51,\n\t62,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t46,\n\t111,\n\t114,\n\t103,\n\t47,\n\t109,\n\t117,\n\t108,\n\t116,\n\t105,\n\t104,\n\t101,\n\t97,\n\t114,\n\t100,\n\t80,\n\t111,\n\t119,\n\t101,\n\t114,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t116,\n\t111,\n\t107,\n\t101,\n\t110,\n\t115,\n\t111,\n\t108,\n\t105,\n\t100,\n\t40,\n\t116,\n\t104,\n\t105,\n\t115,\n\t98,\n\t114,\n\t105,\n\t110,\n\t103,\n\t115,\n\t104,\n\t105,\n\t112,\n\t115,\n\t115,\n\t116,\n\t97,\n\t102,\n\t102,\n\t116,\n\t114,\n\t105,\n\t101,\n\t100,\n\t99,\n\t97,\n\t108,\n\t108,\n\t115,\n\t102,\n\t117,\n\t108,\n\t108,\n\t121,\n\t102,\n\t97,\n\t99,\n\t116,\n\t115,\n\t97,\n\t103,\n\t101,\n\t110,\n\t116,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t47,\n\t47,\n\t45,\n\t45,\n\t62,\n\t97,\n\t100,\n\t109,\n\t105,\n\t110,\n\t101,\n\t103,\n\t121,\n\t112,\n\t116,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t49,\n\t53,\n\t112,\n\t120,\n\t59,\n\t69,\n\t109,\n\t97,\n\t105,\n\t108,\n\t116,\n\t114,\n\t117,\n\t101,\n\t34,\n\t99,\n\t114,\n\t111,\n\t115,\n\t115,\n\t115,\n\t112,\n\t101,\n\t110,\n\t116,\n\t98,\n\t108,\n\t111,\n\t103,\n\t115,\n\t98,\n\t111,\n\t120,\n\t34,\n\t62,\n\t110,\n\t111,\n\t116,\n\t101,\n\t100,\n\t108,\n\t101,\n\t97,\n\t118,\n\t101,\n\t99,\n\t104,\n\t105,\n\t110,\n\t97,\n\t115,\n\t105,\n\t122,\n\t101,\n\t115,\n\t103,\n\t117,\n\t101,\n\t115,\n\t116,\n\t60,\n\t47,\n\t104,\n\t52,\n\t62,\n\t114,\n\t111,\n\t98,\n\t111,\n\t116,\n\t104,\n\t101,\n\t97,\n\t118,\n\t121,\n\t116,\n\t114,\n\t117,\n\t101,\n\t44,\n\t115,\n\t101,\n\t118,\n\t101,\n\t110,\n\t103,\n\t114,\n\t97,\n\t110,\n\t100,\n\t99,\n\t114,\n\t105,\n\t109,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t115,\n\t97,\n\t119,\n\t97,\n\t114,\n\t101,\n\t100,\n\t97,\n\t110,\n\t99,\n\t101,\n\t112,\n\t104,\n\t97,\n\t115,\n\t101,\n\t62,\n\t60,\n\t33,\n\t45,\n\t45,\n\t101,\n\t110,\n\t95,\n\t85,\n\t83,\n\t38,\n\t35,\n\t51,\n\t57,\n\t59,\n\t50,\n\t48,\n\t48,\n\t112,\n\t120,\n\t95,\n\t110,\n\t97,\n\t109,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t110,\n\t101,\n\t110,\n\t106,\n\t111,\n\t121,\n\t97,\n\t106,\n\t97,\n\t120,\n\t46,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t109,\n\t105,\n\t116,\n\t104,\n\t85,\n\t46,\n\t83,\n\t46,\n\t32,\n\t104,\n\t111,\n\t108,\n\t100,\n\t115,\n\t112,\n\t101,\n\t116,\n\t101,\n\t114,\n\t105,\n\t110,\n\t100,\n\t105,\n\t97,\n\t110,\n\t97,\n\t118,\n\t34,\n\t62,\n\t99,\n\t104,\n\t97,\n\t105,\n\t110,\n\t115,\n\t99,\n\t111,\n\t114,\n\t101,\n\t99,\n\t111,\n\t109,\n\t101,\n\t115,\n\t100,\n\t111,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t105,\n\t111,\n\t114,\n\t83,\n\t104,\n\t97,\n\t114,\n\t101,\n\t49,\n\t57,\n\t57,\n\t48,\n\t115,\n\t114,\n\t111,\n\t109,\n\t97,\n\t110,\n\t108,\n\t105,\n\t115,\n\t116,\n\t115,\n\t106,\n\t97,\n\t112,\n\t97,\n\t110,\n\t102,\n\t97,\n\t108,\n\t108,\n\t115,\n\t116,\n\t114,\n\t105,\n\t97,\n\t108,\n\t111,\n\t119,\n\t110,\n\t101,\n\t114,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t60,\n\t47,\n\t104,\n\t50,\n\t62,\n\t97,\n\t98,\n\t117,\n\t115,\n\t101,\n\t97,\n\t108,\n\t101,\n\t114,\n\t116,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t34,\n\t45,\n\t47,\n\t47,\n\t87,\n\t99,\n\t97,\n\t114,\n\t100,\n\t115,\n\t104,\n\t105,\n\t108,\n\t108,\n\t115,\n\t116,\n\t101,\n\t97,\n\t109,\n\t115,\n\t80,\n\t104,\n\t111,\n\t116,\n\t111,\n\t116,\n\t114,\n\t117,\n\t116,\n\t104,\n\t99,\n\t108,\n\t101,\n\t97,\n\t110,\n\t46,\n\t112,\n\t104,\n\t112,\n\t63,\n\t115,\n\t97,\n\t105,\n\t110,\n\t116,\n\t109,\n\t101,\n\t116,\n\t97,\n\t108,\n\t108,\n\t111,\n\t117,\n\t105,\n\t115,\n\t109,\n\t101,\n\t97,\n\t110,\n\t116,\n\t112,\n\t114,\n\t111,\n\t111,\n\t102,\n\t98,\n\t114,\n\t105,\n\t101,\n\t102,\n\t114,\n\t111,\n\t119,\n\t34,\n\t62,\n\t103,\n\t101,\n\t110,\n\t114,\n\t101,\n\t116,\n\t114,\n\t117,\n\t99,\n\t107,\n\t108,\n\t111,\n\t111,\n\t107,\n\t115,\n\t86,\n\t97,\n\t108,\n\t117,\n\t101,\n\t70,\n\t114,\n\t97,\n\t109,\n\t101,\n\t46,\n\t110,\n\t101,\n\t116,\n\t47,\n\t45,\n\t45,\n\t62,\n\t10,\n\t60,\n\t116,\n\t114,\n\t121,\n\t32,\n\t123,\n\t10,\n\t118,\n\t97,\n\t114,\n\t32,\n\t109,\n\t97,\n\t107,\n\t101,\n\t115,\n\t99,\n\t111,\n\t115,\n\t116,\n\t115,\n\t112,\n\t108,\n\t97,\n\t105,\n\t110,\n\t97,\n\t100,\n\t117,\n\t108,\n\t116,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t116,\n\t114,\n\t97,\n\t105,\n\t110,\n\t108,\n\t97,\n\t98,\n\t111,\n\t114,\n\t104,\n\t101,\n\t108,\n\t112,\n\t115,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t109,\n\t97,\n\t103,\n\t105,\n\t99,\n\t109,\n\t111,\n\t116,\n\t111,\n\t114,\n\t116,\n\t104,\n\t101,\n\t105,\n\t114,\n\t50,\n\t53,\n\t48,\n\t112,\n\t120,\n\t108,\n\t101,\n\t97,\n\t115,\n\t116,\n\t115,\n\t116,\n\t101,\n\t112,\n\t115,\n\t67,\n\t111,\n\t117,\n\t110,\n\t116,\n\t99,\n\t111,\n\t117,\n\t108,\n\t100,\n\t103,\n\t108,\n\t97,\n\t115,\n\t115,\n\t115,\n\t105,\n\t100,\n\t101,\n\t115,\n\t102,\n\t117,\n\t110,\n\t100,\n\t115,\n\t104,\n\t111,\n\t116,\n\t101,\n\t108,\n\t97,\n\t119,\n\t97,\n\t114,\n\t100,\n\t109,\n\t111,\n\t117,\n\t116,\n\t104,\n\t109,\n\t111,\n\t118,\n\t101,\n\t115,\n\t112,\n\t97,\n\t114,\n\t105,\n\t115,\n\t103,\n\t105,\n\t118,\n\t101,\n\t115,\n\t100,\n\t117,\n\t116,\n\t99,\n\t104,\n\t116,\n\t101,\n\t120,\n\t97,\n\t115,\n\t102,\n\t114,\n\t117,\n\t105,\n\t116,\n\t110,\n\t117,\n\t108,\n\t108,\n\t44,\n\t124,\n\t124,\n\t91,\n\t93,\n\t59,\n\t116,\n\t111,\n\t112,\n\t34,\n\t62,\n\t10,\n\t60,\n\t33,\n\t45,\n\t45,\n\t80,\n\t79,\n\t83,\n\t84,\n\t34,\n\t111,\n\t99,\n\t101,\n\t97,\n\t110,\n\t60,\n\t98,\n\t114,\n\t47,\n\t62,\n\t102,\n\t108,\n\t111,\n\t111,\n\t114,\n\t115,\n\t112,\n\t101,\n\t97,\n\t107,\n\t100,\n\t101,\n\t112,\n\t116,\n\t104,\n\t32,\n\t115,\n\t105,\n\t122,\n\t101,\n\t98,\n\t97,\n\t110,\n\t107,\n\t115,\n\t99,\n\t97,\n\t116,\n\t99,\n\t104,\n\t99,\n\t104,\n\t97,\n\t114,\n\t116,\n\t50,\n\t48,\n\t112,\n\t120,\n\t59,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t100,\n\t101,\n\t97,\n\t108,\n\t115,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t53,\n\t48,\n\t112,\n\t120,\n\t59,\n\t117,\n\t114,\n\t108,\n\t61,\n\t34,\n\t112,\n\t97,\n\t114,\n\t107,\n\t115,\n\t109,\n\t111,\n\t117,\n\t115,\n\t101,\n\t77,\n\t111,\n\t115,\n\t116,\n\t32,\n\t46,\n\t46,\n\t46,\n\t60,\n\t47,\n\t97,\n\t109,\n\t111,\n\t110,\n\t103,\n\t98,\n\t114,\n\t97,\n\t105,\n\t110,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t99,\n\t97,\n\t114,\n\t114,\n\t121,\n\t100,\n\t114,\n\t97,\n\t102,\n\t116,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t112,\n\t97,\n\t103,\n\t101,\n\t95,\n\t104,\n\t111,\n\t109,\n\t101,\n\t46,\n\t109,\n\t101,\n\t116,\n\t101,\n\t114,\n\t100,\n\t101,\n\t108,\n\t97,\n\t121,\n\t100,\n\t114,\n\t101,\n\t97,\n\t109,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t106,\n\t111,\n\t105,\n\t110,\n\t116,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t100,\n\t114,\n\t117,\n\t103,\n\t115,\n\t60,\n\t33,\n\t45,\n\t45,\n\t32,\n\t97,\n\t112,\n\t114,\n\t105,\n\t108,\n\t105,\n\t100,\n\t101,\n\t97,\n\t108,\n\t97,\n\t108,\n\t108,\n\t101,\n\t110,\n\t101,\n\t120,\n\t97,\n\t99,\n\t116,\n\t102,\n\t111,\n\t114,\n\t116,\n\t104,\n\t99,\n\t111,\n\t100,\n\t101,\n\t115,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t86,\n\t105,\n\t101,\n\t119,\n\t32,\n\t115,\n\t101,\n\t101,\n\t109,\n\t115,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t32,\n\t40,\n\t50,\n\t48,\n\t48,\n\t115,\n\t97,\n\t118,\n\t101,\n\t100,\n\t95,\n\t108,\n\t105,\n\t110,\n\t107,\n\t103,\n\t111,\n\t97,\n\t108,\n\t115,\n\t103,\n\t114,\n\t97,\n\t110,\n\t116,\n\t103,\n\t114,\n\t101,\n\t101,\n\t107,\n\t104,\n\t111,\n\t109,\n\t101,\n\t115,\n\t114,\n\t105,\n\t110,\n\t103,\n\t115,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t51,\n\t48,\n\t112,\n\t120,\n\t59,\n\t119,\n\t104,\n\t111,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t115,\n\t101,\n\t40,\n\t41,\n\t59,\n\t34,\n\t32,\n\t66,\n\t108,\n\t111,\n\t99,\n\t107,\n\t108,\n\t105,\n\t110,\n\t117,\n\t120,\n\t106,\n\t111,\n\t110,\n\t101,\n\t115,\n\t112,\n\t105,\n\t120,\n\t101,\n\t108,\n\t39,\n\t41,\n\t59,\n\t34,\n\t62,\n\t41,\n\t59,\n\t105,\n\t102,\n\t40,\n\t45,\n\t108,\n\t101,\n\t102,\n\t116,\n\t100,\n\t97,\n\t118,\n\t105,\n\t100,\n\t104,\n\t111,\n\t114,\n\t115,\n\t101,\n\t70,\n\t111,\n\t99,\n\t117,\n\t115,\n\t114,\n\t97,\n\t105,\n\t115,\n\t101,\n\t98,\n\t111,\n\t120,\n\t101,\n\t115,\n\t84,\n\t114,\n\t97,\n\t99,\n\t107,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t60,\n\t47,\n\t101,\n\t109,\n\t62,\n\t98,\n\t97,\n\t114,\n\t34,\n\t62,\n\t46,\n\t115,\n\t114,\n\t99,\n\t61,\n\t116,\n\t111,\n\t119,\n\t101,\n\t114,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t99,\n\t97,\n\t98,\n\t108,\n\t101,\n\t104,\n\t101,\n\t110,\n\t114,\n\t121,\n\t50,\n\t52,\n\t112,\n\t120,\n\t59,\n\t115,\n\t101,\n\t116,\n\t117,\n\t112,\n\t105,\n\t116,\n\t97,\n\t108,\n\t121,\n\t115,\n\t104,\n\t97,\n\t114,\n\t112,\n\t109,\n\t105,\n\t110,\n\t111,\n\t114,\n\t116,\n\t97,\n\t115,\n\t116,\n\t101,\n\t119,\n\t97,\n\t110,\n\t116,\n\t115,\n\t116,\n\t104,\n\t105,\n\t115,\n\t46,\n\t114,\n\t101,\n\t115,\n\t101,\n\t116,\n\t119,\n\t104,\n\t101,\n\t101,\n\t108,\n\t103,\n\t105,\n\t114,\n\t108,\n\t115,\n\t47,\n\t99,\n\t115,\n\t115,\n\t47,\n\t49,\n\t48,\n\t48,\n\t37,\n\t59,\n\t99,\n\t108,\n\t117,\n\t98,\n\t115,\n\t115,\n\t116,\n\t117,\n\t102,\n\t102,\n\t98,\n\t105,\n\t98,\n\t108,\n\t101,\n\t118,\n\t111,\n\t116,\n\t101,\n\t115,\n\t32,\n\t49,\n\t48,\n\t48,\n\t48,\n\t107,\n\t111,\n\t114,\n\t101,\n\t97,\n\t125,\n\t41,\n\t59,\n\t13,\n\t10,\n\t98,\n\t97,\n\t110,\n\t100,\n\t115,\n\t113,\n\t117,\n\t101,\n\t117,\n\t101,\n\t61,\n\t32,\n\t123,\n\t125,\n\t59,\n\t56,\n\t48,\n\t112,\n\t120,\n\t59,\n\t99,\n\t107,\n\t105,\n\t110,\n\t103,\n\t123,\n\t13,\n\t10,\n\t9,\n\t9,\n\t97,\n\t104,\n\t101,\n\t97,\n\t100,\n\t99,\n\t108,\n\t111,\n\t99,\n\t107,\n\t105,\n\t114,\n\t105,\n\t115,\n\t104,\n\t108,\n\t105,\n\t107,\n\t101,\n\t32,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t115,\n\t116,\n\t97,\n\t116,\n\t115,\n\t70,\n\t111,\n\t114,\n\t109,\n\t34,\n\t121,\n\t97,\n\t104,\n\t111,\n\t111,\n\t41,\n\t91,\n\t48,\n\t93,\n\t59,\n\t65,\n\t98,\n\t111,\n\t117,\n\t116,\n\t102,\n\t105,\n\t110,\n\t100,\n\t115,\n\t60,\n\t47,\n\t104,\n\t49,\n\t62,\n\t100,\n\t101,\n\t98,\n\t117,\n\t103,\n\t116,\n\t97,\n\t115,\n\t107,\n\t115,\n\t85,\n\t82,\n\t76,\n\t32,\n\t61,\n\t99,\n\t101,\n\t108,\n\t108,\n\t115,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t49,\n\t50,\n\t112,\n\t120,\n\t59,\n\t112,\n\t114,\n\t105,\n\t109,\n\t101,\n\t116,\n\t101,\n\t108,\n\t108,\n\t115,\n\t116,\n\t117,\n\t114,\n\t110,\n\t115,\n\t48,\n\t120,\n\t54,\n\t48,\n\t48,\n\t46,\n\t106,\n\t112,\n\t103,\n\t34,\n\t115,\n\t112,\n\t97,\n\t105,\n\t110,\n\t98,\n\t101,\n\t97,\n\t99,\n\t104,\n\t116,\n\t97,\n\t120,\n\t101,\n\t115,\n\t109,\n\t105,\n\t99,\n\t114,\n\t111,\n\t97,\n\t110,\n\t103,\n\t101,\n\t108,\n\t45,\n\t45,\n\t62,\n\t60,\n\t47,\n\t103,\n\t105,\n\t102,\n\t116,\n\t115,\n\t115,\n\t116,\n\t101,\n\t118,\n\t101,\n\t45,\n\t108,\n\t105,\n\t110,\n\t107,\n\t98,\n\t111,\n\t100,\n\t121,\n\t46,\n\t125,\n\t41,\n\t59,\n\t10,\n\t9,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t32,\n\t40,\n\t49,\n\t57,\n\t57,\n\t70,\n\t65,\n\t81,\n\t60,\n\t47,\n\t114,\n\t111,\n\t103,\n\t101,\n\t114,\n\t102,\n\t114,\n\t97,\n\t110,\n\t107,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t50,\n\t56,\n\t112,\n\t120,\n\t59,\n\t102,\n\t101,\n\t101,\n\t100,\n\t115,\n\t60,\n\t104,\n\t49,\n\t62,\n\t60,\n\t115,\n\t99,\n\t111,\n\t116,\n\t116,\n\t116,\n\t101,\n\t115,\n\t116,\n\t115,\n\t50,\n\t50,\n\t112,\n\t120,\n\t59,\n\t100,\n\t114,\n\t105,\n\t110,\n\t107,\n\t41,\n\t32,\n\t124,\n\t124,\n\t32,\n\t108,\n\t101,\n\t119,\n\t105,\n\t115,\n\t115,\n\t104,\n\t97,\n\t108,\n\t108,\n\t35,\n\t48,\n\t51,\n\t57,\n\t59,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t108,\n\t111,\n\t118,\n\t101,\n\t100,\n\t119,\n\t97,\n\t115,\n\t116,\n\t101,\n\t48,\n\t48,\n\t112,\n\t120,\n\t59,\n\t106,\n\t97,\n\t58,\n\t227,\n\t130,\n\t115,\n\t105,\n\t109,\n\t111,\n\t110,\n\t60,\n\t102,\n\t111,\n\t110,\n\t116,\n\t114,\n\t101,\n\t112,\n\t108,\n\t121,\n\t109,\n\t101,\n\t101,\n\t116,\n\t115,\n\t117,\n\t110,\n\t116,\n\t101,\n\t114,\n\t99,\n\t104,\n\t101,\n\t97,\n\t112,\n\t116,\n\t105,\n\t103,\n\t104,\n\t116,\n\t66,\n\t114,\n\t97,\n\t110,\n\t100,\n\t41,\n\t32,\n\t33,\n\t61,\n\t32,\n\t100,\n\t114,\n\t101,\n\t115,\n\t115,\n\t99,\n\t108,\n\t105,\n\t112,\n\t115,\n\t114,\n\t111,\n\t111,\n\t109,\n\t115,\n\t111,\n\t110,\n\t107,\n\t101,\n\t121,\n\t109,\n\t111,\n\t98,\n\t105,\n\t108,\n\t109,\n\t97,\n\t105,\n\t110,\n\t46,\n\t78,\n\t97,\n\t109,\n\t101,\n\t32,\n\t112,\n\t108,\n\t97,\n\t116,\n\t101,\n\t102,\n\t117,\n\t110,\n\t110,\n\t121,\n\t116,\n\t114,\n\t101,\n\t101,\n\t115,\n\t99,\n\t111,\n\t109,\n\t47,\n\t34,\n\t49,\n\t46,\n\t106,\n\t112,\n\t103,\n\t119,\n\t109,\n\t111,\n\t100,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t109,\n\t83,\n\t84,\n\t65,\n\t82,\n\t84,\n\t108,\n\t101,\n\t102,\n\t116,\n\t32,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t44,\n\t32,\n\t50,\n\t48,\n\t49,\n\t41,\n\t59,\n\t10,\n\t125,\n\t10,\n\t102,\n\t111,\n\t114,\n\t109,\n\t46,\n\t118,\n\t105,\n\t114,\n\t117,\n\t115,\n\t99,\n\t104,\n\t97,\n\t105,\n\t114,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t119,\n\t111,\n\t114,\n\t115,\n\t116,\n\t80,\n\t97,\n\t103,\n\t101,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t97,\n\t116,\n\t99,\n\t104,\n\t60,\n\t33,\n\t45,\n\t45,\n\t10,\n\t111,\n\t45,\n\t99,\n\t97,\n\t99,\n\t102,\n\t105,\n\t114,\n\t109,\n\t115,\n\t116,\n\t111,\n\t117,\n\t114,\n\t115,\n\t44,\n\t48,\n\t48,\n\t48,\n\t32,\n\t97,\n\t115,\n\t105,\n\t97,\n\t110,\n\t105,\n\t43,\n\t43,\n\t41,\n\t123,\n\t97,\n\t100,\n\t111,\n\t98,\n\t101,\n\t39,\n\t41,\n\t91,\n\t48,\n\t93,\n\t105,\n\t100,\n\t61,\n\t49,\n\t48,\n\t98,\n\t111,\n\t116,\n\t104,\n\t59,\n\t109,\n\t101,\n\t110,\n\t117,\n\t32,\n\t46,\n\t50,\n\t46,\n\t109,\n\t105,\n\t46,\n\t112,\n\t110,\n\t103,\n\t34,\n\t107,\n\t101,\n\t118,\n\t105,\n\t110,\n\t99,\n\t111,\n\t97,\n\t99,\n\t104,\n\t67,\n\t104,\n\t105,\n\t108,\n\t100,\n\t98,\n\t114,\n\t117,\n\t99,\n\t101,\n\t50,\n\t46,\n\t106,\n\t112,\n\t103,\n\t85,\n\t82,\n\t76,\n\t41,\n\t43,\n\t46,\n\t106,\n\t112,\n\t103,\n\t124,\n\t115,\n\t117,\n\t105,\n\t116,\n\t101,\n\t115,\n\t108,\n\t105,\n\t99,\n\t101,\n\t104,\n\t97,\n\t114,\n\t114,\n\t121,\n\t49,\n\t50,\n\t48,\n\t34,\n\t32,\n\t115,\n\t119,\n\t101,\n\t101,\n\t116,\n\t116,\n\t114,\n\t62,\n\t13,\n\t10,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t100,\n\t105,\n\t101,\n\t103,\n\t111,\n\t112,\n\t97,\n\t103,\n\t101,\n\t32,\n\t115,\n\t119,\n\t105,\n\t115,\n\t115,\n\t45,\n\t45,\n\t62,\n\t10,\n\t10,\n\t35,\n\t102,\n\t102,\n\t102,\n\t59,\n\t34,\n\t62,\n\t76,\n\t111,\n\t103,\n\t46,\n\t99,\n\t111,\n\t109,\n\t34,\n\t116,\n\t114,\n\t101,\n\t97,\n\t116,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t41,\n\t32,\n\t38,\n\t38,\n\t32,\n\t49,\n\t52,\n\t112,\n\t120,\n\t59,\n\t115,\n\t108,\n\t101,\n\t101,\n\t112,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t102,\n\t105,\n\t108,\n\t101,\n\t100,\n\t106,\n\t97,\n\t58,\n\t227,\n\t131,\n\t105,\n\t100,\n\t61,\n\t34,\n\t99,\n\t78,\n\t97,\n\t109,\n\t101,\n\t34,\n\t119,\n\t111,\n\t114,\n\t115,\n\t101,\n\t115,\n\t104,\n\t111,\n\t116,\n\t115,\n\t45,\n\t98,\n\t111,\n\t120,\n\t45,\n\t100,\n\t101,\n\t108,\n\t116,\n\t97,\n\t10,\n\t38,\n\t108,\n\t116,\n\t59,\n\t98,\n\t101,\n\t97,\n\t114,\n\t115,\n\t58,\n\t52,\n\t56,\n\t90,\n\t60,\n\t100,\n\t97,\n\t116,\n\t97,\n\t45,\n\t114,\n\t117,\n\t114,\n\t97,\n\t108,\n\t60,\n\t47,\n\t97,\n\t62,\n\t32,\n\t115,\n\t112,\n\t101,\n\t110,\n\t100,\n\t98,\n\t97,\n\t107,\n\t101,\n\t114,\n\t115,\n\t104,\n\t111,\n\t112,\n\t115,\n\t61,\n\t32,\n\t34,\n\t34,\n\t59,\n\t112,\n\t104,\n\t112,\n\t34,\n\t62,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t49,\n\t51,\n\t112,\n\t120,\n\t59,\n\t98,\n\t114,\n\t105,\n\t97,\n\t110,\n\t104,\n\t101,\n\t108,\n\t108,\n\t111,\n\t115,\n\t105,\n\t122,\n\t101,\n\t61,\n\t111,\n\t61,\n\t37,\n\t50,\n\t70,\n\t32,\n\t106,\n\t111,\n\t105,\n\t110,\n\t109,\n\t97,\n\t121,\n\t98,\n\t101,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t105,\n\t109,\n\t103,\n\t34,\n\t62,\n\t44,\n\t32,\n\t102,\n\t106,\n\t115,\n\t105,\n\t109,\n\t103,\n\t34,\n\t32,\n\t34,\n\t41,\n\t91,\n\t48,\n\t93,\n\t77,\n\t84,\n\t111,\n\t112,\n\t66,\n\t84,\n\t121,\n\t112,\n\t101,\n\t34,\n\t110,\n\t101,\n\t119,\n\t108,\n\t121,\n\t68,\n\t97,\n\t110,\n\t115,\n\t107,\n\t99,\n\t122,\n\t101,\n\t99,\n\t104,\n\t116,\n\t114,\n\t97,\n\t105,\n\t108,\n\t107,\n\t110,\n\t111,\n\t119,\n\t115,\n\t60,\n\t47,\n\t104,\n\t53,\n\t62,\n\t102,\n\t97,\n\t113,\n\t34,\n\t62,\n\t122,\n\t104,\n\t45,\n\t99,\n\t110,\n\t49,\n\t48,\n\t41,\n\t59,\n\t10,\n\t45,\n\t49,\n\t34,\n\t41,\n\t59,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t98,\n\t108,\n\t117,\n\t101,\n\t115,\n\t116,\n\t114,\n\t117,\n\t108,\n\t121,\n\t100,\n\t97,\n\t118,\n\t105,\n\t115,\n\t46,\n\t106,\n\t115,\n\t39,\n\t59,\n\t62,\n\t13,\n\t10,\n\t60,\n\t33,\n\t115,\n\t116,\n\t101,\n\t101,\n\t108,\n\t32,\n\t121,\n\t111,\n\t117,\n\t32,\n\t104,\n\t50,\n\t62,\n\t13,\n\t10,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t106,\n\t101,\n\t115,\n\t117,\n\t115,\n\t49,\n\t48,\n\t48,\n\t37,\n\t32,\n\t109,\n\t101,\n\t110,\n\t117,\n\t46,\n\t13,\n\t10,\n\t9,\n\t13,\n\t10,\n\t119,\n\t97,\n\t108,\n\t101,\n\t115,\n\t114,\n\t105,\n\t115,\n\t107,\n\t115,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t98,\n\t45,\n\t108,\n\t105,\n\t107,\n\t116,\n\t101,\n\t97,\n\t99,\n\t104,\n\t103,\n\t105,\n\t102,\n\t34,\n\t32,\n\t118,\n\t101,\n\t103,\n\t97,\n\t115,\n\t100,\n\t97,\n\t110,\n\t115,\n\t107,\n\t101,\n\t101,\n\t115,\n\t116,\n\t105,\n\t115,\n\t104,\n\t113,\n\t105,\n\t112,\n\t115,\n\t117,\n\t111,\n\t109,\n\t105,\n\t115,\n\t111,\n\t98,\n\t114,\n\t101,\n\t100,\n\t101,\n\t115,\n\t100,\n\t101,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t116,\n\t111,\n\t100,\n\t111,\n\t115,\n\t112,\n\t117,\n\t101,\n\t100,\n\t101,\n\t97,\n\t195,\n\t177,\n\t111,\n\t115,\n\t101,\n\t115,\n\t116,\n\t195,\n\t161,\n\t116,\n\t105,\n\t101,\n\t110,\n\t101,\n\t104,\n\t97,\n\t115,\n\t116,\n\t97,\n\t111,\n\t116,\n\t114,\n\t111,\n\t115,\n\t112,\n\t97,\n\t114,\n\t116,\n\t101,\n\t100,\n\t111,\n\t110,\n\t100,\n\t101,\n\t110,\n\t117,\n\t101,\n\t118,\n\t111,\n\t104,\n\t97,\n\t99,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t109,\n\t105,\n\t115,\n\t109,\n\t111,\n\t109,\n\t101,\n\t106,\n\t111,\n\t114,\n\t109,\n\t117,\n\t110,\n\t100,\n\t111,\n\t97,\n\t113,\n\t117,\n\t195,\n\t173,\n\t100,\n\t195,\n\t173,\n\t97,\n\t115,\n\t115,\n\t195,\n\t179,\n\t108,\n\t111,\n\t97,\n\t121,\n\t117,\n\t100,\n\t97,\n\t102,\n\t101,\n\t99,\n\t104,\n\t97,\n\t116,\n\t111,\n\t100,\n\t97,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t111,\n\t109,\n\t101,\n\t110,\n\t111,\n\t115,\n\t100,\n\t97,\n\t116,\n\t111,\n\t115,\n\t111,\n\t116,\n\t114,\n\t97,\n\t115,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t109,\n\t117,\n\t99,\n\t104,\n\t111,\n\t97,\n\t104,\n\t111,\n\t114,\n\t97,\n\t108,\n\t117,\n\t103,\n\t97,\n\t114,\n\t109,\n\t97,\n\t121,\n\t111,\n\t114,\n\t101,\n\t115,\n\t116,\n\t111,\n\t115,\n\t104,\n\t111,\n\t114,\n\t97,\n\t115,\n\t116,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t110,\n\t116,\n\t101,\n\t115,\n\t102,\n\t111,\n\t116,\n\t111,\n\t115,\n\t101,\n\t115,\n\t116,\n\t97,\n\t115,\n\t112,\n\t97,\n\t195,\n\t173,\n\t115,\n\t110,\n\t117,\n\t101,\n\t118,\n\t97,\n\t115,\n\t97,\n\t108,\n\t117,\n\t100,\n\t102,\n\t111,\n\t114,\n\t111,\n\t115,\n\t109,\n\t101,\n\t100,\n\t105,\n\t111,\n\t113,\n\t117,\n\t105,\n\t101,\n\t110,\n\t109,\n\t101,\n\t115,\n\t101,\n\t115,\n\t112,\n\t111,\n\t100,\n\t101,\n\t114,\n\t99,\n\t104,\n\t105,\n\t108,\n\t101,\n\t115,\n\t101,\n\t114,\n\t195,\n\t161,\n\t118,\n\t101,\n\t99,\n\t101,\n\t115,\n\t100,\n\t101,\n\t99,\n\t105,\n\t114,\n\t106,\n\t111,\n\t115,\n\t195,\n\t169,\n\t101,\n\t115,\n\t116,\n\t97,\n\t114,\n\t118,\n\t101,\n\t110,\n\t116,\n\t97,\n\t103,\n\t114,\n\t117,\n\t112,\n\t111,\n\t104,\n\t101,\n\t99,\n\t104,\n\t111,\n\t101,\n\t108,\n\t108,\n\t111,\n\t115,\n\t116,\n\t101,\n\t110,\n\t103,\n\t111,\n\t97,\n\t109,\n\t105,\n\t103,\n\t111,\n\t99,\n\t111,\n\t115,\n\t97,\n\t115,\n\t110,\n\t105,\n\t118,\n\t101,\n\t108,\n\t103,\n\t101,\n\t110,\n\t116,\n\t101,\n\t109,\n\t105,\n\t115,\n\t109,\n\t97,\n\t97,\n\t105,\n\t114,\n\t101,\n\t115,\n\t106,\n\t117,\n\t108,\n\t105,\n\t111,\n\t116,\n\t101,\n\t109,\n\t97,\n\t115,\n\t104,\n\t97,\n\t99,\n\t105,\n\t97,\n\t102,\n\t97,\n\t118,\n\t111,\n\t114,\n\t106,\n\t117,\n\t110,\n\t105,\n\t111,\n\t108,\n\t105,\n\t98,\n\t114,\n\t101,\n\t112,\n\t117,\n\t110,\n\t116,\n\t111,\n\t98,\n\t117,\n\t101,\n\t110,\n\t111,\n\t97,\n\t117,\n\t116,\n\t111,\n\t114,\n\t97,\n\t98,\n\t114,\n\t105,\n\t108,\n\t98,\n\t117,\n\t101,\n\t110,\n\t97,\n\t116,\n\t101,\n\t120,\n\t116,\n\t111,\n\t109,\n\t97,\n\t114,\n\t122,\n\t111,\n\t115,\n\t97,\n\t98,\n\t101,\n\t114,\n\t108,\n\t105,\n\t115,\n\t116,\n\t97,\n\t108,\n\t117,\n\t101,\n\t103,\n\t111,\n\t99,\n\t195,\n\t179,\n\t109,\n\t111,\n\t101,\n\t110,\n\t101,\n\t114,\n\t111,\n\t106,\n\t117,\n\t101,\n\t103,\n\t111,\n\t112,\n\t101,\n\t114,\n\t195,\n\t186,\n\t104,\n\t97,\n\t98,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t111,\n\t121,\n\t110,\n\t117,\n\t110,\n\t99,\n\t97,\n\t109,\n\t117,\n\t106,\n\t101,\n\t114,\n\t118,\n\t97,\n\t108,\n\t111,\n\t114,\n\t102,\n\t117,\n\t101,\n\t114,\n\t97,\n\t108,\n\t105,\n\t98,\n\t114,\n\t111,\n\t103,\n\t117,\n\t115,\n\t116,\n\t97,\n\t105,\n\t103,\n\t117,\n\t97,\n\t108,\n\t118,\n\t111,\n\t116,\n\t111,\n\t115,\n\t99,\n\t97,\n\t115,\n\t111,\n\t115,\n\t103,\n\t117,\n\t195,\n\t173,\n\t97,\n\t112,\n\t117,\n\t101,\n\t100,\n\t111,\n\t115,\n\t111,\n\t109,\n\t111,\n\t115,\n\t97,\n\t118,\n\t105,\n\t115,\n\t111,\n\t117,\n\t115,\n\t116,\n\t101,\n\t100,\n\t100,\n\t101,\n\t98,\n\t101,\n\t110,\n\t110,\n\t111,\n\t99,\n\t104,\n\t101,\n\t98,\n\t117,\n\t115,\n\t99,\n\t97,\n\t102,\n\t97,\n\t108,\n\t116,\n\t97,\n\t101,\n\t117,\n\t114,\n\t111,\n\t115,\n\t115,\n\t101,\n\t114,\n\t105,\n\t101,\n\t100,\n\t105,\n\t99,\n\t104,\n\t111,\n\t99,\n\t117,\n\t114,\n\t115,\n\t111,\n\t99,\n\t108,\n\t97,\n\t118,\n\t101,\n\t99,\n\t97,\n\t115,\n\t97,\n\t115,\n\t108,\n\t101,\n\t195,\n\t179,\n\t110,\n\t112,\n\t108,\n\t97,\n\t122,\n\t111,\n\t108,\n\t97,\n\t114,\n\t103,\n\t111,\n\t111,\n\t98,\n\t114,\n\t97,\n\t115,\n\t118,\n\t105,\n\t115,\n\t116,\n\t97,\n\t97,\n\t112,\n\t111,\n\t121,\n\t111,\n\t106,\n\t117,\n\t110,\n\t116,\n\t111,\n\t116,\n\t114,\n\t97,\n\t116,\n\t97,\n\t118,\n\t105,\n\t115,\n\t116,\n\t111,\n\t99,\n\t114,\n\t101,\n\t97,\n\t114,\n\t99,\n\t97,\n\t109,\n\t112,\n\t111,\n\t104,\n\t101,\n\t109,\n\t111,\n\t115,\n\t99,\n\t105,\n\t110,\n\t99,\n\t111,\n\t99,\n\t97,\n\t114,\n\t103,\n\t111,\n\t112,\n\t105,\n\t115,\n\t111,\n\t115,\n\t111,\n\t114,\n\t100,\n\t101,\n\t110,\n\t104,\n\t97,\n\t99,\n\t101,\n\t110,\n\t195,\n\t161,\n\t114,\n\t101,\n\t97,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t112,\n\t101,\n\t100,\n\t114,\n\t111,\n\t99,\n\t101,\n\t114,\n\t99,\n\t97,\n\t112,\n\t117,\n\t101,\n\t100,\n\t97,\n\t112,\n\t97,\n\t112,\n\t101,\n\t108,\n\t109,\n\t101,\n\t110,\n\t111,\n\t114,\n\t195,\n\t186,\n\t116,\n\t105,\n\t108,\n\t99,\n\t108,\n\t97,\n\t114,\n\t111,\n\t106,\n\t111,\n\t114,\n\t103,\n\t101,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t112,\n\t111,\n\t110,\n\t101,\n\t114,\n\t116,\n\t97,\n\t114,\n\t100,\n\t101,\n\t110,\n\t97,\n\t100,\n\t105,\n\t101,\n\t109,\n\t97,\n\t114,\n\t99,\n\t97,\n\t115,\n\t105,\n\t103,\n\t117,\n\t101,\n\t101,\n\t108,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t103,\n\t108,\n\t111,\n\t99,\n\t111,\n\t99,\n\t104,\n\t101,\n\t109,\n\t111,\n\t116,\n\t111,\n\t115,\n\t109,\n\t97,\n\t100,\n\t114,\n\t101,\n\t99,\n\t108,\n\t97,\n\t115,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t111,\n\t110,\n\t105,\n\t195,\n\t177,\n\t111,\n\t113,\n\t117,\n\t101,\n\t100,\n\t97,\n\t112,\n\t97,\n\t115,\n\t97,\n\t114,\n\t98,\n\t97,\n\t110,\n\t99,\n\t111,\n\t104,\n\t105,\n\t106,\n\t111,\n\t115,\n\t118,\n\t105,\n\t97,\n\t106,\n\t101,\n\t112,\n\t97,\n\t98,\n\t108,\n\t111,\n\t195,\n\t169,\n\t115,\n\t116,\n\t101,\n\t118,\n\t105,\n\t101,\n\t110,\n\t101,\n\t114,\n\t101,\n\t105,\n\t110,\n\t111,\n\t100,\n\t101,\n\t106,\n\t97,\n\t114,\n\t102,\n\t111,\n\t110,\n\t100,\n\t111,\n\t99,\n\t97,\n\t110,\n\t97,\n\t108,\n\t110,\n\t111,\n\t114,\n\t116,\n\t101,\n\t108,\n\t101,\n\t116,\n\t114,\n\t97,\n\t99,\n\t97,\n\t117,\n\t115,\n\t97,\n\t116,\n\t111,\n\t109,\n\t97,\n\t114,\n\t109,\n\t97,\n\t110,\n\t111,\n\t115,\n\t108,\n\t117,\n\t110,\n\t101,\n\t115,\n\t97,\n\t117,\n\t116,\n\t111,\n\t115,\n\t118,\n\t105,\n\t108,\n\t108,\n\t97,\n\t118,\n\t101,\n\t110,\n\t100,\n\t111,\n\t112,\n\t101,\n\t115,\n\t97,\n\t114,\n\t116,\n\t105,\n\t112,\n\t111,\n\t115,\n\t116,\n\t101,\n\t110,\n\t103,\n\t97,\n\t109,\n\t97,\n\t114,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t118,\n\t97,\n\t112,\n\t97,\n\t100,\n\t114,\n\t101,\n\t117,\n\t110,\n\t105,\n\t100,\n\t111,\n\t118,\n\t97,\n\t109,\n\t111,\n\t115,\n\t122,\n\t111,\n\t110,\n\t97,\n\t115,\n\t97,\n\t109,\n\t98,\n\t111,\n\t115,\n\t98,\n\t97,\n\t110,\n\t100,\n\t97,\n\t109,\n\t97,\n\t114,\n\t105,\n\t97,\n\t97,\n\t98,\n\t117,\n\t115,\n\t111,\n\t109,\n\t117,\n\t99,\n\t104,\n\t97,\n\t115,\n\t117,\n\t98,\n\t105,\n\t114,\n\t114,\n\t105,\n\t111,\n\t106,\n\t97,\n\t118,\n\t105,\n\t118,\n\t105,\n\t114,\n\t103,\n\t114,\n\t97,\n\t100,\n\t111,\n\t99,\n\t104,\n\t105,\n\t99,\n\t97,\n\t97,\n\t108,\n\t108,\n\t195,\n\t173,\n\t106,\n\t111,\n\t118,\n\t101,\n\t110,\n\t100,\n\t105,\n\t99,\n\t104,\n\t97,\n\t101,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t97,\n\t108,\n\t101,\n\t115,\n\t115,\n\t97,\n\t108,\n\t105,\n\t114,\n\t115,\n\t117,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t115,\n\t111,\n\t115,\n\t102,\n\t105,\n\t110,\n\t101,\n\t115,\n\t108,\n\t108,\n\t97,\n\t109,\n\t97,\n\t98,\n\t117,\n\t115,\n\t99,\n\t111,\n\t195,\n\t169,\n\t115,\n\t116,\n\t97,\n\t108,\n\t108,\n\t101,\n\t103,\n\t97,\n\t110,\n\t101,\n\t103,\n\t114,\n\t111,\n\t112,\n\t108,\n\t97,\n\t122,\n\t97,\n\t104,\n\t117,\n\t109,\n\t111,\n\t114,\n\t112,\n\t97,\n\t103,\n\t97,\n\t114,\n\t106,\n\t117,\n\t110,\n\t116,\n\t97,\n\t100,\n\t111,\n\t98,\n\t108,\n\t101,\n\t105,\n\t115,\n\t108,\n\t97,\n\t115,\n\t98,\n\t111,\n\t108,\n\t115,\n\t97,\n\t98,\n\t97,\n\t195,\n\t177,\n\t111,\n\t104,\n\t97,\n\t98,\n\t108,\n\t97,\n\t108,\n\t117,\n\t99,\n\t104,\n\t97,\n\t195,\n\t129,\n\t114,\n\t101,\n\t97,\n\t100,\n\t105,\n\t99,\n\t101,\n\t110,\n\t106,\n\t117,\n\t103,\n\t97,\n\t114,\n\t110,\n\t111,\n\t116,\n\t97,\n\t115,\n\t118,\n\t97,\n\t108,\n\t108,\n\t101,\n\t97,\n\t108,\n\t108,\n\t195,\n\t161,\n\t99,\n\t97,\n\t114,\n\t103,\n\t97,\n\t100,\n\t111,\n\t108,\n\t111,\n\t114,\n\t97,\n\t98,\n\t97,\n\t106,\n\t111,\n\t101,\n\t115,\n\t116,\n\t195,\n\t169,\n\t103,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t109,\n\t97,\n\t114,\n\t105,\n\t111,\n\t102,\n\t105,\n\t114,\n\t109,\n\t97,\n\t99,\n\t111,\n\t115,\n\t116,\n\t111,\n\t102,\n\t105,\n\t99,\n\t104,\n\t97,\n\t112,\n\t108,\n\t97,\n\t116,\n\t97,\n\t104,\n\t111,\n\t103,\n\t97,\n\t114,\n\t97,\n\t114,\n\t116,\n\t101,\n\t115,\n\t108,\n\t101,\n\t121,\n\t101,\n\t115,\n\t97,\n\t113,\n\t117,\n\t101,\n\t108,\n\t109,\n\t117,\n\t115,\n\t101,\n\t111,\n\t98,\n\t97,\n\t115,\n\t101,\n\t115,\n\t112,\n\t111,\n\t99,\n\t111,\n\t115,\n\t109,\n\t105,\n\t116,\n\t97,\n\t100,\n\t99,\n\t105,\n\t101,\n\t108,\n\t111,\n\t99,\n\t104,\n\t105,\n\t99,\n\t111,\n\t109,\n\t105,\n\t101,\n\t100,\n\t111,\n\t103,\n\t97,\n\t110,\n\t97,\n\t114,\n\t115,\n\t97,\n\t110,\n\t116,\n\t111,\n\t101,\n\t116,\n\t97,\n\t112,\n\t97,\n\t100,\n\t101,\n\t98,\n\t101,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t97,\n\t114,\n\t101,\n\t100,\n\t101,\n\t115,\n\t115,\n\t105,\n\t101,\n\t116,\n\t101,\n\t99,\n\t111,\n\t114,\n\t116,\n\t101,\n\t99,\n\t111,\n\t114,\n\t101,\n\t97,\n\t100,\n\t117,\n\t100,\n\t97,\n\t115,\n\t100,\n\t101,\n\t115,\n\t101,\n\t111,\n\t118,\n\t105,\n\t101,\n\t106,\n\t111,\n\t100,\n\t101,\n\t115,\n\t101,\n\t97,\n\t97,\n\t103,\n\t117,\n\t97,\n\t115,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t100,\n\t111,\n\t109,\n\t97,\n\t105,\n\t110,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t115,\n\t116,\n\t97,\n\t116,\n\t117,\n\t115,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t115,\n\t109,\n\t97,\n\t115,\n\t116,\n\t101,\n\t114,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t97,\n\t110,\n\t110,\n\t101,\n\t114,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t101,\n\t115,\n\t99,\n\t114,\n\t111,\n\t108,\n\t108,\n\t117,\n\t112,\n\t100,\n\t97,\n\t116,\n\t101,\n\t103,\n\t108,\n\t111,\n\t98,\n\t97,\n\t108,\n\t109,\n\t101,\n\t100,\n\t105,\n\t117,\n\t109,\n\t102,\n\t105,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t115,\n\t99,\n\t114,\n\t101,\n\t101,\n\t110,\n\t99,\n\t104,\n\t111,\n\t111,\n\t115,\n\t101,\n\t110,\n\t111,\n\t114,\n\t109,\n\t97,\n\t108,\n\t116,\n\t114,\n\t97,\n\t118,\n\t101,\n\t108,\n\t105,\n\t115,\n\t115,\n\t117,\n\t101,\n\t115,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t115,\n\t112,\n\t114,\n\t105,\n\t110,\n\t103,\n\t109,\n\t111,\n\t100,\n\t117,\n\t108,\n\t101,\n\t109,\n\t111,\n\t98,\n\t105,\n\t108,\n\t101,\n\t115,\n\t119,\n\t105,\n\t116,\n\t99,\n\t104,\n\t112,\n\t104,\n\t111,\n\t116,\n\t111,\n\t115,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t114,\n\t101,\n\t103,\n\t105,\n\t111,\n\t110,\n\t105,\n\t116,\n\t115,\n\t101,\n\t108,\n\t102,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t108,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t99,\n\t111,\n\t108,\n\t117,\n\t109,\n\t110,\n\t114,\n\t101,\n\t99,\n\t111,\n\t114,\n\t100,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t101,\n\t105,\n\t116,\n\t104,\n\t101,\n\t114,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t121,\n\t102,\n\t114,\n\t105,\n\t101,\n\t110,\n\t100,\n\t108,\n\t97,\n\t121,\n\t111,\n\t117,\n\t116,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t114,\n\t101,\n\t118,\n\t105,\n\t101,\n\t119,\n\t115,\n\t117,\n\t109,\n\t109,\n\t101,\n\t114,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t114,\n\t112,\n\t108,\n\t97,\n\t121,\n\t101,\n\t100,\n\t112,\n\t108,\n\t97,\n\t121,\n\t101,\n\t114,\n\t101,\n\t120,\n\t112,\n\t97,\n\t110,\n\t100,\n\t112,\n\t111,\n\t108,\n\t105,\n\t99,\n\t121,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t100,\n\t111,\n\t117,\n\t98,\n\t108,\n\t101,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t115,\n\t115,\n\t101,\n\t114,\n\t105,\n\t101,\n\t115,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t108,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t109,\n\t111,\n\t110,\n\t116,\n\t104,\n\t115,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t115,\n\t117,\n\t110,\n\t105,\n\t113,\n\t117,\n\t101,\n\t119,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t101,\n\t110,\n\t101,\n\t114,\n\t103,\n\t121,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t102,\n\t105,\n\t103,\n\t117,\n\t114,\n\t101,\n\t104,\n\t97,\n\t118,\n\t105,\n\t110,\n\t103,\n\t99,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t111,\n\t102,\n\t102,\n\t115,\n\t101,\n\t116,\n\t108,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t114,\n\t101,\n\t110,\n\t100,\n\t101,\n\t114,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t115,\n\t117,\n\t112,\n\t108,\n\t111,\n\t97,\n\t100,\n\t104,\n\t101,\n\t97,\n\t108,\n\t116,\n\t104,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t118,\n\t105,\n\t100,\n\t101,\n\t111,\n\t115,\n\t115,\n\t99,\n\t104,\n\t111,\n\t111,\n\t108,\n\t102,\n\t117,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t104,\n\t97,\n\t100,\n\t111,\n\t119,\n\t100,\n\t101,\n\t98,\n\t97,\n\t116,\n\t101,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t115,\n\t79,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t115,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t108,\n\t101,\n\t97,\n\t103,\n\t117,\n\t101,\n\t99,\n\t104,\n\t114,\n\t111,\n\t109,\n\t101,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t110,\n\t111,\n\t116,\n\t105,\n\t99,\n\t101,\n\t115,\n\t104,\n\t97,\n\t114,\n\t101,\n\t100,\n\t101,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t111,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t115,\n\t113,\n\t117,\n\t97,\n\t114,\n\t101,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t115,\n\t101,\n\t110,\n\t97,\n\t98,\n\t108,\n\t101,\n\t109,\n\t111,\n\t118,\n\t105,\n\t110,\n\t103,\n\t108,\n\t97,\n\t116,\n\t101,\n\t115,\n\t116,\n\t119,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t70,\n\t114,\n\t97,\n\t110,\n\t99,\n\t101,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t114,\n\t101,\n\t112,\n\t101,\n\t97,\n\t116,\n\t76,\n\t111,\n\t110,\n\t100,\n\t111,\n\t110,\n\t100,\n\t101,\n\t116,\n\t97,\n\t105,\n\t108,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t100,\n\t100,\n\t101,\n\t109,\n\t97,\n\t110,\n\t100,\n\t115,\n\t101,\n\t99,\n\t117,\n\t114,\n\t101,\n\t112,\n\t97,\n\t115,\n\t115,\n\t101,\n\t100,\n\t116,\n\t111,\n\t103,\n\t103,\n\t108,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t115,\n\t100,\n\t101,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t99,\n\t99,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t115,\n\t116,\n\t114,\n\t101,\n\t97,\n\t109,\n\t121,\n\t101,\n\t108,\n\t108,\n\t111,\n\t119,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t107,\n\t115,\n\t116,\n\t114,\n\t101,\n\t101,\n\t116,\n\t102,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t105,\n\t110,\n\t102,\n\t111,\n\t34,\n\t62,\n\t111,\n\t112,\n\t101,\n\t110,\n\t101,\n\t100,\n\t117,\n\t115,\n\t101,\n\t102,\n\t117,\n\t108,\n\t118,\n\t97,\n\t108,\n\t108,\n\t101,\n\t121,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t115,\n\t108,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t115,\n\t101,\n\t99,\n\t114,\n\t101,\n\t116,\n\t115,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t100,\n\t97,\n\t109,\n\t97,\n\t103,\n\t101,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t102,\n\t105,\n\t101,\n\t108,\n\t100,\n\t115,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t101,\n\t118,\n\t105,\n\t115,\n\t117,\n\t97,\n\t108,\n\t101,\n\t100,\n\t105,\n\t116,\n\t111,\n\t114,\n\t118,\n\t111,\n\t108,\n\t117,\n\t109,\n\t101,\n\t82,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t109,\n\t117,\n\t115,\n\t101,\n\t117,\n\t109,\n\t109,\n\t111,\n\t118,\n\t105,\n\t101,\n\t115,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t116,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t109,\n\t111,\n\t115,\n\t116,\n\t108,\n\t121,\n\t109,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t34,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t107,\n\t101,\n\t116,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t99,\n\t104,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t117,\n\t114,\n\t118,\n\t101,\n\t121,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t115,\n\t121,\n\t109,\n\t98,\n\t111,\n\t108,\n\t109,\n\t111,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t112,\n\t101,\n\t101,\n\t99,\n\t104,\n\t109,\n\t111,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t109,\n\t97,\n\t116,\n\t116,\n\t101,\n\t114,\n\t67,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t115,\n\t109,\n\t105,\n\t100,\n\t100,\n\t108,\n\t101,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t103,\n\t114,\n\t111,\n\t119,\n\t116,\n\t104,\n\t108,\n\t101,\n\t103,\n\t97,\n\t99,\n\t121,\n\t109,\n\t97,\n\t110,\n\t110,\n\t101,\n\t114,\n\t101,\n\t110,\n\t111,\n\t117,\n\t103,\n\t104,\n\t99,\n\t97,\n\t114,\n\t101,\n\t101,\n\t114,\n\t97,\n\t110,\n\t115,\n\t119,\n\t101,\n\t114,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t108,\n\t99,\n\t108,\n\t105,\n\t101,\n\t110,\n\t116,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t97,\n\t110,\n\t100,\n\t111,\n\t109,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t100,\n\t116,\n\t111,\n\t112,\n\t105,\n\t99,\n\t115,\n\t99,\n\t111,\n\t109,\n\t105,\n\t110,\n\t103,\n\t102,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t121,\n\t114,\n\t97,\n\t105,\n\t115,\n\t101,\n\t100,\n\t101,\n\t115,\n\t99,\n\t97,\n\t112,\n\t101,\n\t99,\n\t104,\n\t111,\n\t115,\n\t101,\n\t110,\n\t99,\n\t104,\n\t117,\n\t114,\n\t99,\n\t104,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t114,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t99,\n\t111,\n\t114,\n\t110,\n\t101,\n\t114,\n\t111,\n\t117,\n\t116,\n\t112,\n\t117,\n\t116,\n\t109,\n\t101,\n\t109,\n\t111,\n\t114,\n\t121,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t112,\n\t111,\n\t108,\n\t105,\n\t99,\n\t101,\n\t109,\n\t111,\n\t100,\n\t101,\n\t108,\n\t115,\n\t78,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t100,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t111,\n\t102,\n\t102,\n\t101,\n\t114,\n\t115,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t107,\n\t105,\n\t108,\n\t108,\n\t101,\n\t100,\n\t108,\n\t105,\n\t115,\n\t116,\n\t101,\n\t100,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t115,\n\t105,\n\t108,\n\t118,\n\t101,\n\t114,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t100,\n\t101,\n\t108,\n\t101,\n\t116,\n\t101,\n\t98,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t98,\n\t114,\n\t111,\n\t119,\n\t115,\n\t101,\n\t108,\n\t105,\n\t109,\n\t105,\n\t116,\n\t115,\n\t71,\n\t108,\n\t111,\n\t98,\n\t97,\n\t108,\n\t115,\n\t105,\n\t110,\n\t103,\n\t108,\n\t101,\n\t119,\n\t105,\n\t100,\n\t103,\n\t101,\n\t116,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t98,\n\t117,\n\t100,\n\t103,\n\t101,\n\t116,\n\t110,\n\t111,\n\t119,\n\t114,\n\t97,\n\t112,\n\t99,\n\t114,\n\t101,\n\t100,\n\t105,\n\t116,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t115,\n\t101,\n\t110,\n\t103,\n\t105,\n\t110,\n\t101,\n\t115,\n\t97,\n\t102,\n\t101,\n\t116,\n\t121,\n\t99,\n\t104,\n\t111,\n\t105,\n\t99,\n\t101,\n\t115,\n\t112,\n\t105,\n\t114,\n\t105,\n\t116,\n\t45,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t112,\n\t114,\n\t101,\n\t97,\n\t100,\n\t109,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t110,\n\t101,\n\t101,\n\t100,\n\t101,\n\t100,\n\t114,\n\t117,\n\t115,\n\t115,\n\t105,\n\t97,\n\t112,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t116,\n\t83,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t98,\n\t114,\n\t111,\n\t107,\n\t101,\n\t110,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t115,\n\t99,\n\t104,\n\t97,\n\t114,\n\t103,\n\t101,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t101,\n\t102,\n\t97,\n\t99,\n\t116,\n\t111,\n\t114,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t45,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t121,\n\t99,\n\t111,\n\t110,\n\t102,\n\t105,\n\t103,\n\t97,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t119,\n\t111,\n\t114,\n\t107,\n\t101,\n\t100,\n\t104,\n\t101,\n\t108,\n\t112,\n\t101,\n\t100,\n\t67,\n\t104,\n\t117,\n\t114,\n\t99,\n\t104,\n\t105,\n\t109,\n\t112,\n\t97,\n\t99,\n\t116,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t97,\n\t108,\n\t119,\n\t97,\n\t121,\n\t115,\n\t108,\n\t111,\n\t103,\n\t111,\n\t34,\n\t32,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t108,\n\t105,\n\t115,\n\t116,\n\t34,\n\t62,\n\t41,\n\t123,\n\t118,\n\t97,\n\t114,\n\t32,\n\t112,\n\t114,\n\t101,\n\t102,\n\t105,\n\t120,\n\t111,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t72,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t46,\n\t112,\n\t117,\n\t115,\n\t104,\n\t40,\n\t99,\n\t111,\n\t117,\n\t112,\n\t108,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t101,\n\t110,\n\t98,\n\t114,\n\t105,\n\t100,\n\t103,\n\t101,\n\t108,\n\t97,\n\t117,\n\t110,\n\t99,\n\t104,\n\t82,\n\t101,\n\t118,\n\t105,\n\t101,\n\t119,\n\t116,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t108,\n\t105,\n\t116,\n\t116,\n\t108,\n\t101,\n\t100,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t66,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t98,\n\t101,\n\t97,\n\t117,\n\t116,\n\t121,\n\t116,\n\t104,\n\t101,\n\t109,\n\t101,\n\t115,\n\t102,\n\t111,\n\t114,\n\t103,\n\t111,\n\t116,\n\t83,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t97,\n\t110,\n\t99,\n\t104,\n\t111,\n\t114,\n\t97,\n\t108,\n\t109,\n\t111,\n\t115,\n\t116,\n\t108,\n\t111,\n\t97,\n\t100,\n\t101,\n\t100,\n\t67,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t115,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t108,\n\t111,\n\t97,\n\t100,\n\t77,\n\t111,\n\t98,\n\t105,\n\t108,\n\t101,\n\t105,\n\t110,\n\t99,\n\t111,\n\t109,\n\t101,\n\t115,\n\t117,\n\t112,\n\t112,\n\t108,\n\t121,\n\t83,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t115,\n\t118,\n\t105,\n\t101,\n\t119,\n\t101,\n\t100,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t99,\n\t111,\n\t117,\n\t114,\n\t115,\n\t101,\n\t65,\n\t98,\n\t111,\n\t117,\n\t116,\n\t32,\n\t105,\n\t115,\n\t108,\n\t97,\n\t110,\n\t100,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t99,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t97,\n\t109,\n\t97,\n\t122,\n\t111,\n\t110,\n\t109,\n\t111,\n\t100,\n\t101,\n\t114,\n\t110,\n\t97,\n\t100,\n\t118,\n\t105,\n\t99,\n\t101,\n\t105,\n\t110,\n\t60,\n\t47,\n\t97,\n\t62,\n\t58,\n\t32,\n\t84,\n\t104,\n\t101,\n\t32,\n\t100,\n\t105,\n\t97,\n\t108,\n\t111,\n\t103,\n\t104,\n\t111,\n\t117,\n\t115,\n\t101,\n\t115,\n\t66,\n\t69,\n\t71,\n\t73,\n\t78,\n\t32,\n\t77,\n\t101,\n\t120,\n\t105,\n\t99,\n\t111,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t115,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t73,\n\t115,\n\t108,\n\t97,\n\t110,\n\t100,\n\t97,\n\t115,\n\t115,\n\t101,\n\t116,\n\t115,\n\t69,\n\t109,\n\t112,\n\t105,\n\t114,\n\t101,\n\t83,\n\t99,\n\t104,\n\t111,\n\t111,\n\t108,\n\t101,\n\t102,\n\t102,\n\t111,\n\t114,\n\t116,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t110,\n\t101,\n\t97,\n\t114,\n\t108,\n\t121,\n\t109,\n\t97,\n\t110,\n\t117,\n\t97,\n\t108,\n\t83,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t46,\n\t10,\n\t10,\n\t79,\n\t110,\n\t101,\n\t106,\n\t111,\n\t105,\n\t110,\n\t101,\n\t100,\n\t109,\n\t101,\n\t110,\n\t117,\n\t34,\n\t62,\n\t80,\n\t104,\n\t105,\n\t108,\n\t105,\n\t112,\n\t97,\n\t119,\n\t97,\n\t114,\n\t100,\n\t115,\n\t104,\n\t97,\n\t110,\n\t100,\n\t108,\n\t101,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t79,\n\t102,\n\t102,\n\t105,\n\t99,\n\t101,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t115,\n\t107,\n\t105,\n\t108,\n\t108,\n\t115,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t83,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t100,\n\t101,\n\t103,\n\t114,\n\t101,\n\t101,\n\t119,\n\t101,\n\t101,\n\t107,\n\t108,\n\t121,\n\t32,\n\t40,\n\t101,\n\t46,\n\t103,\n\t46,\n\t98,\n\t101,\n\t104,\n\t105,\n\t110,\n\t100,\n\t100,\n\t111,\n\t99,\n\t116,\n\t111,\n\t114,\n\t108,\n\t111,\n\t103,\n\t103,\n\t101,\n\t100,\n\t117,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t60,\n\t47,\n\t98,\n\t62,\n\t60,\n\t47,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t115,\n\t112,\n\t108,\n\t97,\n\t110,\n\t116,\n\t115,\n\t97,\n\t115,\n\t115,\n\t105,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t105,\n\t115,\n\t116,\n\t105,\n\t115,\n\t115,\n\t117,\n\t101,\n\t100,\n\t51,\n\t48,\n\t48,\n\t112,\n\t120,\n\t124,\n\t99,\n\t97,\n\t110,\n\t97,\n\t100,\n\t97,\n\t97,\n\t103,\n\t101,\n\t110,\n\t99,\n\t121,\n\t115,\n\t99,\n\t104,\n\t101,\n\t109,\n\t101,\n\t114,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t66,\n\t114,\n\t97,\n\t122,\n\t105,\n\t108,\n\t115,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t108,\n\t111,\n\t103,\n\t111,\n\t34,\n\t62,\n\t98,\n\t101,\n\t121,\n\t111,\n\t110,\n\t100,\n\t45,\n\t115,\n\t99,\n\t97,\n\t108,\n\t101,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t100,\n\t109,\n\t97,\n\t114,\n\t105,\n\t110,\n\t101,\n\t70,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t99,\n\t97,\n\t109,\n\t101,\n\t114,\n\t97,\n\t60,\n\t47,\n\t104,\n\t49,\n\t62,\n\t10,\n\t95,\n\t102,\n\t111,\n\t114,\n\t109,\n\t34,\n\t108,\n\t101,\n\t97,\n\t118,\n\t101,\n\t115,\n\t115,\n\t116,\n\t114,\n\t101,\n\t115,\n\t115,\n\t34,\n\t32,\n\t47,\n\t62,\n\t13,\n\t10,\n\t46,\n\t103,\n\t105,\n\t102,\n\t34,\n\t32,\n\t111,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t108,\n\t111,\n\t97,\n\t100,\n\t101,\n\t114,\n\t79,\n\t120,\n\t102,\n\t111,\n\t114,\n\t100,\n\t115,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t115,\n\t117,\n\t114,\n\t118,\n\t105,\n\t118,\n\t108,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t102,\n\t101,\n\t109,\n\t97,\n\t108,\n\t101,\n\t68,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t115,\n\t105,\n\t122,\n\t101,\n\t61,\n\t34,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t108,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t62,\n\t108,\n\t101,\n\t118,\n\t101,\n\t108,\n\t115,\n\t116,\n\t104,\n\t97,\n\t110,\n\t107,\n\t115,\n\t104,\n\t105,\n\t103,\n\t104,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t100,\n\t97,\n\t110,\n\t105,\n\t109,\n\t97,\n\t108,\n\t97,\n\t110,\n\t121,\n\t111,\n\t110,\n\t101,\n\t65,\n\t102,\n\t114,\n\t105,\n\t99,\n\t97,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t100,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t80,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t60,\n\t98,\n\t114,\n\t32,\n\t47,\n\t62,\n\t119,\n\t111,\n\t110,\n\t100,\n\t101,\n\t114,\n\t112,\n\t114,\n\t105,\n\t99,\n\t101,\n\t115,\n\t116,\n\t117,\n\t114,\n\t110,\n\t101,\n\t100,\n\t124,\n\t124,\n\t32,\n\t123,\n\t125,\n\t59,\n\t109,\n\t97,\n\t105,\n\t110,\n\t34,\n\t62,\n\t105,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t115,\n\t117,\n\t110,\n\t100,\n\t97,\n\t121,\n\t119,\n\t114,\n\t97,\n\t112,\n\t34,\n\t62,\n\t102,\n\t97,\n\t105,\n\t108,\n\t101,\n\t100,\n\t99,\n\t101,\n\t110,\n\t115,\n\t117,\n\t115,\n\t109,\n\t105,\n\t110,\n\t117,\n\t116,\n\t101,\n\t98,\n\t101,\n\t97,\n\t99,\n\t111,\n\t110,\n\t113,\n\t117,\n\t111,\n\t116,\n\t101,\n\t115,\n\t49,\n\t53,\n\t48,\n\t112,\n\t120,\n\t124,\n\t101,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t114,\n\t101,\n\t109,\n\t111,\n\t116,\n\t101,\n\t101,\n\t109,\n\t97,\n\t105,\n\t108,\n\t34,\n\t108,\n\t105,\n\t110,\n\t107,\n\t101,\n\t100,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t59,\n\t115,\n\t105,\n\t103,\n\t110,\n\t97,\n\t108,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t108,\n\t49,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t115,\n\t105,\n\t103,\n\t110,\n\t117,\n\t112,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t101,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t46,\n\t112,\n\t110,\n\t103,\n\t34,\n\t32,\n\t102,\n\t111,\n\t114,\n\t117,\n\t109,\n\t46,\n\t65,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t112,\n\t97,\n\t112,\n\t101,\n\t114,\n\t115,\n\t115,\n\t111,\n\t117,\n\t110,\n\t100,\n\t115,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t100,\n\t72,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t108,\n\t105,\n\t100,\n\t101,\n\t114,\n\t85,\n\t84,\n\t70,\n\t45,\n\t56,\n\t34,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t32,\n\t66,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t46,\n\t32,\n\t87,\n\t105,\n\t116,\n\t104,\n\t115,\n\t116,\n\t117,\n\t100,\n\t105,\n\t111,\n\t111,\n\t119,\n\t110,\n\t101,\n\t114,\n\t115,\n\t109,\n\t97,\n\t110,\n\t97,\n\t103,\n\t101,\n\t112,\n\t114,\n\t111,\n\t102,\n\t105,\n\t116,\n\t106,\n\t81,\n\t117,\n\t101,\n\t114,\n\t121,\n\t97,\n\t110,\n\t110,\n\t117,\n\t97,\n\t108,\n\t112,\n\t97,\n\t114,\n\t97,\n\t109,\n\t115,\n\t98,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t102,\n\t97,\n\t109,\n\t111,\n\t117,\n\t115,\n\t103,\n\t111,\n\t111,\n\t103,\n\t108,\n\t101,\n\t108,\n\t111,\n\t110,\n\t103,\n\t101,\n\t114,\n\t105,\n\t43,\n\t43,\n\t41,\n\t32,\n\t123,\n\t105,\n\t115,\n\t114,\n\t97,\n\t101,\n\t108,\n\t115,\n\t97,\n\t121,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t99,\n\t105,\n\t100,\n\t101,\n\t104,\n\t111,\n\t109,\n\t101,\n\t34,\n\t62,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t101,\n\t110,\n\t115,\n\t117,\n\t114,\n\t101,\n\t98,\n\t114,\n\t97,\n\t110,\n\t99,\n\t104,\n\t112,\n\t105,\n\t101,\n\t99,\n\t101,\n\t115,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t59,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t100,\n\t116,\n\t111,\n\t112,\n\t34,\n\t62,\n\t60,\n\t114,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t115,\n\t105,\n\t122,\n\t101,\n\t45,\n\t45,\n\t38,\n\t103,\n\t116,\n\t59,\n\t112,\n\t97,\n\t99,\n\t105,\n\t116,\n\t121,\n\t115,\n\t101,\n\t120,\n\t117,\n\t97,\n\t108,\n\t98,\n\t117,\n\t114,\n\t101,\n\t97,\n\t117,\n\t46,\n\t106,\n\t112,\n\t103,\n\t34,\n\t32,\n\t49,\n\t48,\n\t44,\n\t48,\n\t48,\n\t48,\n\t111,\n\t98,\n\t116,\n\t97,\n\t105,\n\t110,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t115,\n\t97,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t44,\n\t32,\n\t73,\n\t110,\n\t99,\n\t46,\n\t99,\n\t111,\n\t109,\n\t101,\n\t100,\n\t121,\n\t109,\n\t101,\n\t110,\n\t117,\n\t34,\n\t32,\n\t108,\n\t121,\n\t114,\n\t105,\n\t99,\n\t115,\n\t116,\n\t111,\n\t100,\n\t97,\n\t121,\n\t46,\n\t105,\n\t110,\n\t100,\n\t101,\n\t101,\n\t100,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t121,\n\t95,\n\t108,\n\t111,\n\t103,\n\t111,\n\t46,\n\t70,\n\t97,\n\t109,\n\t105,\n\t108,\n\t121,\n\t108,\n\t111,\n\t111,\n\t107,\n\t101,\n\t100,\n\t77,\n\t97,\n\t114,\n\t107,\n\t101,\n\t116,\n\t108,\n\t115,\n\t101,\n\t32,\n\t105,\n\t102,\n\t80,\n\t108,\n\t97,\n\t121,\n\t101,\n\t114,\n\t116,\n\t117,\n\t114,\n\t107,\n\t101,\n\t121,\n\t41,\n\t59,\n\t118,\n\t97,\n\t114,\n\t32,\n\t102,\n\t111,\n\t114,\n\t101,\n\t115,\n\t116,\n\t103,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t101,\n\t114,\n\t114,\n\t111,\n\t114,\n\t115,\n\t68,\n\t111,\n\t109,\n\t97,\n\t105,\n\t110,\n\t125,\n\t101,\n\t108,\n\t115,\n\t101,\n\t123,\n\t105,\n\t110,\n\t115,\n\t101,\n\t114,\n\t116,\n\t66,\n\t108,\n\t111,\n\t103,\n\t60,\n\t47,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t108,\n\t111,\n\t103,\n\t105,\n\t110,\n\t46,\n\t102,\n\t97,\n\t115,\n\t116,\n\t101,\n\t114,\n\t97,\n\t103,\n\t101,\n\t110,\n\t116,\n\t115,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t49,\n\t48,\n\t112,\n\t120,\n\t32,\n\t48,\n\t112,\n\t114,\n\t97,\n\t103,\n\t109,\n\t97,\n\t102,\n\t114,\n\t105,\n\t100,\n\t97,\n\t121,\n\t106,\n\t117,\n\t110,\n\t105,\n\t111,\n\t114,\n\t100,\n\t111,\n\t108,\n\t108,\n\t97,\n\t114,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t115,\n\t112,\n\t108,\n\t117,\n\t103,\n\t105,\n\t110,\n\t53,\n\t44,\n\t48,\n\t48,\n\t48,\n\t32,\n\t112,\n\t97,\n\t103,\n\t101,\n\t34,\n\t62,\n\t98,\n\t111,\n\t115,\n\t116,\n\t111,\n\t110,\n\t46,\n\t116,\n\t101,\n\t115,\n\t116,\n\t40,\n\t97,\n\t118,\n\t97,\n\t116,\n\t97,\n\t114,\n\t116,\n\t101,\n\t115,\n\t116,\n\t101,\n\t100,\n\t95,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t102,\n\t111,\n\t114,\n\t117,\n\t109,\n\t115,\n\t115,\n\t99,\n\t104,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t44,\n\t102,\n\t105,\n\t108,\n\t108,\n\t101,\n\t100,\n\t115,\n\t104,\n\t97,\n\t114,\n\t101,\n\t115,\n\t114,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t97,\n\t108,\n\t101,\n\t114,\n\t116,\n\t40,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t83,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t108,\n\t105,\n\t110,\n\t101,\n\t34,\n\t62,\n\t98,\n\t111,\n\t100,\n\t121,\n\t34,\n\t62,\n\t10,\n\t42,\n\t32,\n\t84,\n\t104,\n\t101,\n\t84,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t115,\n\t101,\n\t101,\n\t105,\n\t110,\n\t103,\n\t106,\n\t101,\n\t114,\n\t115,\n\t101,\n\t121,\n\t78,\n\t101,\n\t119,\n\t115,\n\t60,\n\t47,\n\t118,\n\t101,\n\t114,\n\t105,\n\t102,\n\t121,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t116,\n\t105,\n\t110,\n\t106,\n\t117,\n\t114,\n\t121,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t67,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t83,\n\t84,\n\t65,\n\t82,\n\t84,\n\t32,\n\t97,\n\t99,\n\t114,\n\t111,\n\t115,\n\t115,\n\t95,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t116,\n\t104,\n\t114,\n\t101,\n\t97,\n\t100,\n\t110,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t112,\n\t111,\n\t99,\n\t107,\n\t101,\n\t116,\n\t98,\n\t111,\n\t120,\n\t34,\n\t62,\n\t10,\n\t83,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t32,\n\t68,\n\t97,\n\t118,\n\t105,\n\t100,\n\t99,\n\t97,\n\t110,\n\t99,\n\t101,\n\t114,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t100,\n\t65,\n\t112,\n\t114,\n\t105,\n\t108,\n\t32,\n\t114,\n\t101,\n\t97,\n\t108,\n\t108,\n\t121,\n\t100,\n\t114,\n\t105,\n\t118,\n\t101,\n\t114,\n\t105,\n\t116,\n\t101,\n\t109,\n\t34,\n\t62,\n\t109,\n\t111,\n\t114,\n\t101,\n\t34,\n\t62,\n\t98,\n\t111,\n\t97,\n\t114,\n\t100,\n\t115,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t115,\n\t99,\n\t97,\n\t109,\n\t112,\n\t117,\n\t115,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t32,\n\t124,\n\t124,\n\t32,\n\t91,\n\t93,\n\t59,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t46,\n\t103,\n\t117,\n\t105,\n\t116,\n\t97,\n\t114,\n\t102,\n\t105,\n\t110,\n\t105,\n\t115,\n\t104,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t115,\n\t104,\n\t111,\n\t119,\n\t101,\n\t100,\n\t79,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t46,\n\t112,\n\t104,\n\t112,\n\t34,\n\t32,\n\t97,\n\t115,\n\t115,\n\t117,\n\t109,\n\t101,\n\t108,\n\t97,\n\t121,\n\t101,\n\t114,\n\t115,\n\t119,\n\t105,\n\t108,\n\t115,\n\t111,\n\t110,\n\t115,\n\t116,\n\t111,\n\t114,\n\t101,\n\t115,\n\t114,\n\t101,\n\t108,\n\t105,\n\t101,\n\t102,\n\t115,\n\t119,\n\t101,\n\t100,\n\t101,\n\t110,\n\t67,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t101,\n\t97,\n\t115,\n\t105,\n\t108,\n\t121,\n\t32,\n\t121,\n\t111,\n\t117,\n\t114,\n\t32,\n\t83,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t10,\n\t10,\n\t87,\n\t104,\n\t105,\n\t108,\n\t116,\n\t97,\n\t121,\n\t108,\n\t111,\n\t114,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t58,\n\t114,\n\t101,\n\t115,\n\t111,\n\t114,\n\t116,\n\t102,\n\t114,\n\t101,\n\t110,\n\t99,\n\t104,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t34,\n\t41,\n\t32,\n\t43,\n\t32,\n\t34,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t98,\n\t117,\n\t121,\n\t105,\n\t110,\n\t103,\n\t98,\n\t114,\n\t97,\n\t110,\n\t100,\n\t115,\n\t77,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t110,\n\t97,\n\t109,\n\t101,\n\t34,\n\t62,\n\t111,\n\t112,\n\t112,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t53,\n\t112,\n\t120,\n\t59,\n\t34,\n\t62,\n\t118,\n\t115,\n\t112,\n\t97,\n\t99,\n\t101,\n\t112,\n\t111,\n\t115,\n\t116,\n\t101,\n\t114,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t32,\n\t99,\n\t111,\n\t102,\n\t102,\n\t101,\n\t101,\n\t109,\n\t97,\n\t114,\n\t116,\n\t105,\n\t110,\n\t109,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t104,\n\t97,\n\t112,\n\t112,\n\t101,\n\t110,\n\t60,\n\t47,\n\t110,\n\t97,\n\t118,\n\t62,\n\t107,\n\t97,\n\t110,\n\t115,\n\t97,\n\t115,\n\t108,\n\t105,\n\t110,\n\t107,\n\t34,\n\t62,\n\t73,\n\t109,\n\t97,\n\t103,\n\t101,\n\t115,\n\t61,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t119,\n\t104,\n\t105,\n\t108,\n\t101,\n\t32,\n\t104,\n\t115,\n\t112,\n\t97,\n\t99,\n\t101,\n\t48,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t32,\n\t10,\n\t10,\n\t73,\n\t110,\n\t32,\n\t32,\n\t112,\n\t111,\n\t119,\n\t101,\n\t114,\n\t80,\n\t111,\n\t108,\n\t115,\n\t107,\n\t105,\n\t45,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t106,\n\t111,\n\t114,\n\t100,\n\t97,\n\t110,\n\t66,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t83,\n\t116,\n\t97,\n\t114,\n\t116,\n\t32,\n\t45,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t50,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t110,\n\t101,\n\t119,\n\t115,\n\t34,\n\t62,\n\t48,\n\t49,\n\t46,\n\t106,\n\t112,\n\t103,\n\t79,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t45,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t109,\n\t105,\n\t108,\n\t108,\n\t101,\n\t114,\n\t115,\n\t101,\n\t110,\n\t105,\n\t111,\n\t114,\n\t73,\n\t83,\n\t66,\n\t78,\n\t32,\n\t48,\n\t48,\n\t44,\n\t48,\n\t48,\n\t48,\n\t32,\n\t103,\n\t117,\n\t105,\n\t100,\n\t101,\n\t115,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t41,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t112,\n\t97,\n\t105,\n\t114,\n\t46,\n\t120,\n\t109,\n\t108,\n\t34,\n\t32,\n\t32,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t45,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t114,\n\t101,\n\t103,\n\t69,\n\t120,\n\t112,\n\t58,\n\t104,\n\t111,\n\t118,\n\t101,\n\t114,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t110,\n\t118,\n\t105,\n\t114,\n\t103,\n\t105,\n\t110,\n\t112,\n\t104,\n\t111,\n\t110,\n\t101,\n\t115,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t13,\n\t117,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t10,\n\t9,\n\t118,\n\t97,\n\t114,\n\t32,\n\t62,\n\t39,\n\t41,\n\t59,\n\t10,\n\t9,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t10,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t10,\n\t98,\n\t97,\n\t104,\n\t97,\n\t115,\n\t97,\n\t98,\n\t114,\n\t97,\n\t115,\n\t105,\n\t108,\n\t103,\n\t97,\n\t108,\n\t101,\n\t103,\n\t111,\n\t109,\n\t97,\n\t103,\n\t121,\n\t97,\n\t114,\n\t112,\n\t111,\n\t108,\n\t115,\n\t107,\n\t105,\n\t115,\n\t114,\n\t112,\n\t115,\n\t107,\n\t105,\n\t216,\n\t177,\n\t216,\n\t175,\n\t217,\n\t136,\n\t228,\n\t184,\n\t173,\n\t230,\n\t150,\n\t135,\n\t231,\n\t174,\n\t128,\n\t228,\n\t189,\n\t147,\n\t231,\n\t185,\n\t129,\n\t233,\n\t171,\n\t148,\n\t228,\n\t191,\n\t161,\n\t230,\n\t129,\n\t175,\n\t228,\n\t184,\n\t173,\n\t229,\n\t155,\n\t189,\n\t230,\n\t136,\n\t145,\n\t228,\n\t187,\n\t172,\n\t228,\n\t184,\n\t128,\n\t228,\n\t184,\n\t170,\n\t229,\n\t133,\n\t172,\n\t229,\n\t143,\n\t184,\n\t231,\n\t174,\n\t161,\n\t231,\n\t144,\n\t134,\n\t232,\n\t174,\n\t186,\n\t229,\n\t157,\n\t155,\n\t229,\n\t143,\n\t175,\n\t228,\n\t187,\n\t165,\n\t230,\n\t156,\n\t141,\n\t229,\n\t138,\n\t161,\n\t230,\n\t151,\n\t182,\n\t233,\n\t151,\n\t180,\n\t228,\n\t184,\n\t170,\n\t228,\n\t186,\n\t186,\n\t228,\n\t186,\n\t167,\n\t229,\n\t147,\n\t129,\n\t232,\n\t135,\n\t170,\n\t229,\n\t183,\n\t177,\n\t228,\n\t188,\n\t129,\n\t228,\n\t184,\n\t154,\n\t230,\n\t159,\n\t165,\n\t231,\n\t156,\n\t139,\n\t229,\n\t183,\n\t165,\n\t228,\n\t189,\n\t156,\n\t232,\n\t129,\n\t148,\n\t231,\n\t179,\n\t187,\n\t230,\n\t178,\n\t161,\n\t230,\n\t156,\n\t137,\n\t231,\n\t189,\n\t145,\n\t231,\n\t171,\n\t153,\n\t230,\n\t137,\n\t128,\n\t230,\n\t156,\n\t137,\n\t232,\n\t175,\n\t132,\n\t232,\n\t174,\n\t186,\n\t228,\n\t184,\n\t173,\n\t229,\n\t191,\n\t131,\n\t230,\n\t150,\n\t135,\n\t231,\n\t171,\n\t160,\n\t231,\n\t148,\n\t168,\n\t230,\n\t136,\n\t183,\n\t233,\n\t166,\n\t150,\n\t233,\n\t161,\n\t181,\n\t228,\n\t189,\n\t156,\n\t232,\n\t128,\n\t133,\n\t230,\n\t138,\n\t128,\n\t230,\n\t156,\n\t175,\n\t233,\n\t151,\n\t174,\n\t233,\n\t162,\n\t152,\n\t231,\n\t155,\n\t184,\n\t229,\n\t133,\n\t179,\n\t228,\n\t184,\n\t139,\n\t232,\n\t189,\n\t189,\n\t230,\n\t144,\n\t156,\n\t231,\n\t180,\n\t162,\n\t228,\n\t189,\n\t191,\n\t231,\n\t148,\n\t168,\n\t232,\n\t189,\n\t175,\n\t228,\n\t187,\n\t182,\n\t229,\n\t156,\n\t168,\n\t231,\n\t186,\n\t191,\n\t228,\n\t184,\n\t187,\n\t233,\n\t162,\n\t152,\n\t232,\n\t181,\n\t132,\n\t230,\n\t150,\n\t153,\n\t232,\n\t167,\n\t134,\n\t233,\n\t162,\n\t145,\n\t229,\n\t155,\n\t158,\n\t229,\n\t164,\n\t141,\n\t230,\n\t179,\n\t168,\n\t229,\n\t134,\n\t140,\n\t231,\n\t189,\n\t145,\n\t231,\n\t187,\n\t156,\n\t230,\n\t148,\n\t182,\n\t232,\n\t151,\n\t143,\n\t229,\n\t134,\n\t133,\n\t229,\n\t174,\n\t185,\n\t230,\n\t142,\n\t168,\n\t232,\n\t141,\n\t144,\n\t229,\n\t184,\n\t130,\n\t229,\n\t156,\n\t186,\n\t230,\n\t182,\n\t136,\n\t230,\n\t129,\n\t175,\n\t231,\n\t169,\n\t186,\n\t233,\n\t151,\n\t180,\n\t229,\n\t143,\n\t145,\n\t229,\n\t184,\n\t131,\n\t228,\n\t187,\n\t128,\n\t228,\n\t185,\n\t136,\n\t229,\n\t165,\n\t189,\n\t229,\n\t143,\n\t139,\n\t231,\n\t148,\n\t159,\n\t230,\n\t180,\n\t187,\n\t229,\n\t155,\n\t190,\n\t231,\n\t137,\n\t135,\n\t229,\n\t143,\n\t145,\n\t229,\n\t177,\n\t149,\n\t229,\n\t166,\n\t130,\n\t230,\n\t158,\n\t156,\n\t230,\n\t137,\n\t139,\n\t230,\n\t156,\n\t186,\n\t230,\n\t150,\n\t176,\n\t233,\n\t151,\n\t187,\n\t230,\n\t156,\n\t128,\n\t230,\n\t150,\n\t176,\n\t230,\n\t150,\n\t185,\n\t229,\n\t188,\n\t143,\n\t229,\n\t140,\n\t151,\n\t228,\n\t186,\n\t172,\n\t230,\n\t143,\n\t144,\n\t228,\n\t190,\n\t155,\n\t229,\n\t133,\n\t179,\n\t228,\n\t186,\n\t142,\n\t230,\n\t155,\n\t180,\n\t229,\n\t164,\n\t154,\n\t232,\n\t191,\n\t153,\n\t228,\n\t184,\n\t170,\n\t231,\n\t179,\n\t187,\n\t231,\n\t187,\n\t159,\n\t231,\n\t159,\n\t165,\n\t233,\n\t129,\n\t147,\n\t230,\n\t184,\n\t184,\n\t230,\n\t136,\n\t143,\n\t229,\n\t185,\n\t191,\n\t229,\n\t145,\n\t138,\n\t229,\n\t133,\n\t182,\n\t228,\n\t187,\n\t150,\n\t229,\n\t143,\n\t145,\n\t232,\n\t161,\n\t168,\n\t229,\n\t174,\n\t137,\n\t229,\n\t133,\n\t168,\n\t231,\n\t172,\n\t172,\n\t228,\n\t184,\n\t128,\n\t228,\n\t188,\n\t154,\n\t229,\n\t145,\n\t152,\n\t232,\n\t191,\n\t155,\n\t232,\n\t161,\n\t140,\n\t231,\n\t130,\n\t185,\n\t229,\n\t135,\n\t187,\n\t231,\n\t137,\n\t136,\n\t230,\n\t157,\n\t131,\n\t231,\n\t148,\n\t181,\n\t229,\n\t173,\n\t144,\n\t228,\n\t184,\n\t150,\n\t231,\n\t149,\n\t140,\n\t232,\n\t174,\n\t190,\n\t232,\n\t174,\n\t161,\n\t229,\n\t133,\n\t141,\n\t232,\n\t180,\n\t185,\n\t230,\n\t149,\n\t153,\n\t232,\n\t130,\n\t178,\n\t229,\n\t138,\n\t160,\n\t229,\n\t133,\n\t165,\n\t230,\n\t180,\n\t187,\n\t229,\n\t138,\n\t168,\n\t228,\n\t187,\n\t150,\n\t228,\n\t187,\n\t172,\n\t229,\n\t149,\n\t134,\n\t229,\n\t147,\n\t129,\n\t229,\n\t141,\n\t154,\n\t229,\n\t174,\n\t162,\n\t231,\n\t142,\n\t176,\n\t229,\n\t156,\n\t168,\n\t228,\n\t184,\n\t138,\n\t230,\n\t181,\n\t183,\n\t229,\n\t166,\n\t130,\n\t228,\n\t189,\n\t149,\n\t229,\n\t183,\n\t178,\n\t231,\n\t187,\n\t143,\n\t231,\n\t149,\n\t153,\n\t232,\n\t168,\n\t128,\n\t232,\n\t175,\n\t166,\n\t231,\n\t187,\n\t134,\n\t231,\n\t164,\n\t190,\n\t229,\n\t140,\n\t186,\n\t231,\n\t153,\n\t187,\n\t229,\n\t189,\n\t149,\n\t230,\n\t156,\n\t172,\n\t231,\n\t171,\n\t153,\n\t233,\n\t156,\n\t128,\n\t232,\n\t166,\n\t129,\n\t228,\n\t187,\n\t183,\n\t230,\n\t160,\n\t188,\n\t230,\n\t148,\n\t175,\n\t230,\n\t140,\n\t129,\n\t229,\n\t155,\n\t189,\n\t233,\n\t153,\n\t133,\n\t233,\n\t147,\n\t190,\n\t230,\n\t142,\n\t165,\n\t229,\n\t155,\n\t189,\n\t229,\n\t174,\n\t182,\n\t229,\n\t187,\n\t186,\n\t232,\n\t174,\n\t190,\n\t230,\n\t156,\n\t139,\n\t229,\n\t143,\n\t139,\n\t233,\n\t152,\n\t133,\n\t232,\n\t175,\n\t187,\n\t230,\n\t179,\n\t149,\n\t229,\n\t190,\n\t139,\n\t228,\n\t189,\n\t141,\n\t231,\n\t189,\n\t174,\n\t231,\n\t187,\n\t143,\n\t230,\n\t181,\n\t142,\n\t233,\n\t128,\n\t137,\n\t230,\n\t139,\n\t169,\n\t232,\n\t191,\n\t153,\n\t230,\n\t160,\n\t183,\n\t229,\n\t189,\n\t147,\n\t229,\n\t137,\n\t141,\n\t229,\n\t136,\n\t134,\n\t231,\n\t177,\n\t187,\n\t230,\n\t142,\n\t146,\n\t232,\n\t161,\n\t140,\n\t229,\n\t155,\n\t160,\n\t228,\n\t184,\n\t186,\n\t228,\n\t186,\n\t164,\n\t230,\n\t152,\n\t147,\n\t230,\n\t156,\n\t128,\n\t229,\n\t144,\n\t142,\n\t233,\n\t159,\n\t179,\n\t228,\n\t185,\n\t144,\n\t228,\n\t184,\n\t141,\n\t232,\n\t131,\n\t189,\n\t233,\n\t128,\n\t154,\n\t232,\n\t191,\n\t135,\n\t232,\n\t161,\n\t140,\n\t228,\n\t184,\n\t154,\n\t231,\n\t167,\n\t145,\n\t230,\n\t138,\n\t128,\n\t229,\n\t143,\n\t175,\n\t232,\n\t131,\n\t189,\n\t232,\n\t174,\n\t190,\n\t229,\n\t164,\n\t135,\n\t229,\n\t144,\n\t136,\n\t228,\n\t189,\n\t156,\n\t229,\n\t164,\n\t167,\n\t229,\n\t174,\n\t182,\n\t231,\n\t164,\n\t190,\n\t228,\n\t188,\n\t154,\n\t231,\n\t160,\n\t148,\n\t231,\n\t169,\n\t182,\n\t228,\n\t184,\n\t147,\n\t228,\n\t184,\n\t154,\n\t229,\n\t133,\n\t168,\n\t233,\n\t131,\n\t168,\n\t233,\n\t161,\n\t185,\n\t231,\n\t155,\n\t174,\n\t232,\n\t191,\n\t153,\n\t233,\n\t135,\n\t140,\n\t232,\n\t191,\n\t152,\n\t230,\n\t152,\n\t175,\n\t229,\n\t188,\n\t128,\n\t229,\n\t167,\n\t139,\n\t230,\n\t131,\n\t133,\n\t229,\n\t134,\n\t181,\n\t231,\n\t148,\n\t181,\n\t232,\n\t132,\n\t145,\n\t230,\n\t150,\n\t135,\n\t228,\n\t187,\n\t182,\n\t229,\n\t147,\n\t129,\n\t231,\n\t137,\n\t140,\n\t229,\n\t184,\n\t174,\n\t229,\n\t138,\n\t169,\n\t230,\n\t150,\n\t135,\n\t229,\n\t140,\n\t150,\n\t232,\n\t181,\n\t132,\n\t230,\n\t186,\n\t144,\n\t229,\n\t164,\n\t167,\n\t229,\n\t173,\n\t166,\n\t229,\n\t173,\n\t166,\n\t228,\n\t185,\n\t160,\n\t229,\n\t156,\n\t176,\n\t229,\n\t157,\n\t128,\n\t230,\n\t181,\n\t143,\n\t232,\n\t167,\n\t136,\n\t230,\n\t138,\n\t149,\n\t232,\n\t181,\n\t132,\n\t229,\n\t183,\n\t165,\n\t231,\n\t168,\n\t139,\n\t232,\n\t166,\n\t129,\n\t230,\n\t177,\n\t130,\n\t230,\n\t128,\n\t142,\n\t228,\n\t185,\n\t136,\n\t230,\n\t151,\n\t182,\n\t229,\n\t128,\n\t153,\n\t229,\n\t138,\n\t159,\n\t232,\n\t131,\n\t189,\n\t228,\n\t184,\n\t187,\n\t232,\n\t166,\n\t129,\n\t231,\n\t155,\n\t174,\n\t229,\n\t137,\n\t141,\n\t232,\n\t181,\n\t132,\n\t232,\n\t174,\n\t175,\n\t229,\n\t159,\n\t142,\n\t229,\n\t184,\n\t130,\n\t230,\n\t150,\n\t185,\n\t230,\n\t179,\n\t149,\n\t231,\n\t148,\n\t181,\n\t229,\n\t189,\n\t177,\n\t230,\n\t139,\n\t155,\n\t232,\n\t129,\n\t152,\n\t229,\n\t163,\n\t176,\n\t230,\n\t152,\n\t142,\n\t228,\n\t187,\n\t187,\n\t228,\n\t189,\n\t149,\n\t229,\n\t129,\n\t165,\n\t229,\n\t186,\n\t183,\n\t230,\n\t149,\n\t176,\n\t230,\n\t141,\n\t174,\n\t231,\n\t190,\n\t142,\n\t229,\n\t155,\n\t189,\n\t230,\n\t177,\n\t189,\n\t232,\n\t189,\n\t166,\n\t228,\n\t187,\n\t139,\n\t231,\n\t187,\n\t141,\n\t228,\n\t189,\n\t134,\n\t230,\n\t152,\n\t175,\n\t228,\n\t186,\n\t164,\n\t230,\n\t181,\n\t129,\n\t231,\n\t148,\n\t159,\n\t228,\n\t186,\n\t167,\n\t230,\n\t137,\n\t128,\n\t228,\n\t187,\n\t165,\n\t231,\n\t148,\n\t181,\n\t232,\n\t175,\n\t157,\n\t230,\n\t152,\n\t190,\n\t231,\n\t164,\n\t186,\n\t228,\n\t184,\n\t128,\n\t228,\n\t186,\n\t155,\n\t229,\n\t141,\n\t149,\n\t228,\n\t189,\n\t141,\n\t228,\n\t186,\n\t186,\n\t229,\n\t145,\n\t152,\n\t229,\n\t136,\n\t134,\n\t230,\n\t158,\n\t144,\n\t229,\n\t156,\n\t176,\n\t229,\n\t155,\n\t190,\n\t230,\n\t151,\n\t133,\n\t230,\n\t184,\n\t184,\n\t229,\n\t183,\n\t165,\n\t229,\n\t133,\n\t183,\n\t229,\n\t173,\n\t166,\n\t231,\n\t148,\n\t159,\n\t231,\n\t179,\n\t187,\n\t229,\n\t136,\n\t151,\n\t231,\n\t189,\n\t145,\n\t229,\n\t143,\n\t139,\n\t229,\n\t184,\n\t150,\n\t229,\n\t173,\n\t144,\n\t229,\n\t175,\n\t134,\n\t231,\n\t160,\n\t129,\n\t233,\n\t162,\n\t145,\n\t233,\n\t129,\n\t147,\n\t230,\n\t142,\n\t167,\n\t229,\n\t136,\n\t182,\n\t229,\n\t156,\n\t176,\n\t229,\n\t140,\n\t186,\n\t229,\n\t159,\n\t186,\n\t230,\n\t156,\n\t172,\n\t229,\n\t133,\n\t168,\n\t229,\n\t155,\n\t189,\n\t231,\n\t189,\n\t145,\n\t228,\n\t184,\n\t138,\n\t233,\n\t135,\n\t141,\n\t232,\n\t166,\n\t129,\n\t231,\n\t172,\n\t172,\n\t228,\n\t186,\n\t140,\n\t229,\n\t150,\n\t156,\n\t230,\n\t172,\n\t162,\n\t232,\n\t191,\n\t155,\n\t229,\n\t133,\n\t165,\n\t229,\n\t143,\n\t139,\n\t230,\n\t131,\n\t133,\n\t232,\n\t191,\n\t153,\n\t228,\n\t186,\n\t155,\n\t232,\n\t128,\n\t131,\n\t232,\n\t175,\n\t149,\n\t229,\n\t143,\n\t145,\n\t231,\n\t142,\n\t176,\n\t229,\n\t159,\n\t185,\n\t232,\n\t174,\n\t173,\n\t228,\n\t187,\n\t165,\n\t228,\n\t184,\n\t138,\n\t230,\n\t148,\n\t191,\n\t229,\n\t186,\n\t156,\n\t230,\n\t136,\n\t144,\n\t228,\n\t184,\n\t186,\n\t231,\n\t142,\n\t175,\n\t229,\n\t162,\n\t131,\n\t233,\n\t166,\n\t153,\n\t230,\n\t184,\n\t175,\n\t229,\n\t144,\n\t140,\n\t230,\n\t151,\n\t182,\n\t229,\n\t168,\n\t177,\n\t228,\n\t185,\n\t144,\n\t229,\n\t143,\n\t145,\n\t233,\n\t128,\n\t129,\n\t228,\n\t184,\n\t128,\n\t229,\n\t174,\n\t154,\n\t229,\n\t188,\n\t128,\n\t229,\n\t143,\n\t145,\n\t228,\n\t189,\n\t156,\n\t229,\n\t147,\n\t129,\n\t230,\n\t160,\n\t135,\n\t229,\n\t135,\n\t134,\n\t230,\n\t172,\n\t162,\n\t232,\n\t191,\n\t142,\n\t232,\n\t167,\n\t163,\n\t229,\n\t134,\n\t179,\n\t229,\n\t156,\n\t176,\n\t230,\n\t150,\n\t185,\n\t228,\n\t184,\n\t128,\n\t228,\n\t184,\n\t139,\n\t228,\n\t187,\n\t165,\n\t229,\n\t143,\n\t138,\n\t232,\n\t180,\n\t163,\n\t228,\n\t187,\n\t187,\n\t230,\n\t136,\n\t150,\n\t232,\n\t128,\n\t133,\n\t229,\n\t174,\n\t162,\n\t230,\n\t136,\n\t183,\n\t228,\n\t187,\n\t163,\n\t232,\n\t161,\n\t168,\n\t231,\n\t167,\n\t175,\n\t229,\n\t136,\n\t134,\n\t229,\n\t165,\n\t179,\n\t228,\n\t186,\n\t186,\n\t230,\n\t149,\n\t176,\n\t231,\n\t160,\n\t129,\n\t233,\n\t148,\n\t128,\n\t229,\n\t148,\n\t174,\n\t229,\n\t135,\n\t186,\n\t231,\n\t142,\n\t176,\n\t231,\n\t166,\n\t187,\n\t231,\n\t186,\n\t191,\n\t229,\n\t186,\n\t148,\n\t231,\n\t148,\n\t168,\n\t229,\n\t136,\n\t151,\n\t232,\n\t161,\n\t168,\n\t228,\n\t184,\n\t141,\n\t229,\n\t144,\n\t140,\n\t231,\n\t188,\n\t150,\n\t232,\n\t190,\n\t145,\n\t231,\n\t187,\n\t159,\n\t232,\n\t174,\n\t161,\n\t230,\n\t159,\n\t165,\n\t232,\n\t175,\n\t162,\n\t228,\n\t184,\n\t141,\n\t232,\n\t166,\n\t129,\n\t230,\n\t156,\n\t137,\n\t229,\n\t133,\n\t179,\n\t230,\n\t156,\n\t186,\n\t230,\n\t158,\n\t132,\n\t229,\n\t190,\n\t136,\n\t229,\n\t164,\n\t154,\n\t230,\n\t146,\n\t173,\n\t230,\n\t148,\n\t190,\n\t231,\n\t187,\n\t132,\n\t231,\n\t187,\n\t135,\n\t230,\n\t148,\n\t191,\n\t231,\n\t173,\n\t150,\n\t231,\n\t155,\n\t180,\n\t230,\n\t142,\n\t165,\n\t232,\n\t131,\n\t189,\n\t229,\n\t138,\n\t155,\n\t230,\n\t157,\n\t165,\n\t230,\n\t186,\n\t144,\n\t230,\n\t153,\n\t130,\n\t233,\n\t150,\n\t147,\n\t231,\n\t156,\n\t139,\n\t229,\n\t136,\n\t176,\n\t231,\n\t131,\n\t173,\n\t233,\n\t151,\n\t168,\n\t229,\n\t133,\n\t179,\n\t233,\n\t148,\n\t174,\n\t228,\n\t184,\n\t147,\n\t229,\n\t140,\n\t186,\n\t233,\n\t157,\n\t158,\n\t229,\n\t184,\n\t184,\n\t232,\n\t139,\n\t177,\n\t232,\n\t175,\n\t173,\n\t231,\n\t153,\n\t190,\n\t229,\n\t186,\n\t166,\n\t229,\n\t184,\n\t140,\n\t230,\n\t156,\n\t155,\n\t231,\n\t190,\n\t142,\n\t229,\n\t165,\n\t179,\n\t230,\n\t175,\n\t148,\n\t232,\n\t190,\n\t131,\n\t231,\n\t159,\n\t165,\n\t232,\n\t175,\n\t134,\n\t232,\n\t167,\n\t132,\n\t229,\n\t174,\n\t154,\n\t229,\n\t187,\n\t186,\n\t232,\n\t174,\n\t174,\n\t233,\n\t131,\n\t168,\n\t233,\n\t151,\n\t168,\n\t230,\n\t132,\n\t143,\n\t232,\n\t167,\n\t129,\n\t231,\n\t178,\n\t190,\n\t229,\n\t189,\n\t169,\n\t230,\n\t151,\n\t165,\n\t230,\n\t156,\n\t172,\n\t230,\n\t143,\n\t144,\n\t233,\n\t171,\n\t152,\n\t229,\n\t143,\n\t145,\n\t232,\n\t168,\n\t128,\n\t230,\n\t150,\n\t185,\n\t233,\n\t157,\n\t162,\n\t229,\n\t159,\n\t186,\n\t233,\n\t135,\n\t145,\n\t229,\n\t164,\n\t132,\n\t231,\n\t144,\n\t134,\n\t230,\n\t157,\n\t131,\n\t233,\n\t153,\n\t144,\n\t229,\n\t189,\n\t177,\n\t231,\n\t137,\n\t135,\n\t233,\n\t147,\n\t182,\n\t232,\n\t161,\n\t140,\n\t232,\n\t191,\n\t152,\n\t230,\n\t156,\n\t137,\n\t229,\n\t136,\n\t134,\n\t228,\n\t186,\n\t171,\n\t231,\n\t137,\n\t169,\n\t229,\n\t147,\n\t129,\n\t231,\n\t187,\n\t143,\n\t232,\n\t144,\n\t165,\n\t230,\n\t183,\n\t187,\n\t229,\n\t138,\n\t160,\n\t228,\n\t184,\n\t147,\n\t229,\n\t174,\n\t182,\n\t232,\n\t191,\n\t153,\n\t231,\n\t167,\n\t141,\n\t232,\n\t175,\n\t157,\n\t233,\n\t162,\n\t152,\n\t232,\n\t181,\n\t183,\n\t230,\n\t157,\n\t165,\n\t228,\n\t184,\n\t154,\n\t229,\n\t138,\n\t161,\n\t229,\n\t133,\n\t172,\n\t229,\n\t145,\n\t138,\n\t232,\n\t174,\n\t176,\n\t229,\n\t189,\n\t149,\n\t231,\n\t174,\n\t128,\n\t228,\n\t187,\n\t139,\n\t232,\n\t180,\n\t168,\n\t233,\n\t135,\n\t143,\n\t231,\n\t148,\n\t183,\n\t228,\n\t186,\n\t186,\n\t229,\n\t189,\n\t177,\n\t229,\n\t147,\n\t141,\n\t229,\n\t188,\n\t149,\n\t231,\n\t148,\n\t168,\n\t230,\n\t138,\n\t165,\n\t229,\n\t145,\n\t138,\n\t233,\n\t131,\n\t168,\n\t229,\n\t136,\n\t134,\n\t229,\n\t191,\n\t171,\n\t233,\n\t128,\n\t159,\n\t229,\n\t146,\n\t168,\n\t232,\n\t175,\n\t162,\n\t230,\n\t151,\n\t182,\n\t229,\n\t176,\n\t154,\n\t230,\n\t179,\n\t168,\n\t230,\n\t132,\n\t143,\n\t231,\n\t148,\n\t179,\n\t232,\n\t175,\n\t183,\n\t229,\n\t173,\n\t166,\n\t230,\n\t160,\n\t161,\n\t229,\n\t186,\n\t148,\n\t232,\n\t175,\n\t165,\n\t229,\n\t142,\n\t134,\n\t229,\n\t143,\n\t178,\n\t229,\n\t143,\n\t170,\n\t230,\n\t152,\n\t175,\n\t232,\n\t191,\n\t148,\n\t229,\n\t155,\n\t158,\n\t232,\n\t180,\n\t173,\n\t228,\n\t185,\n\t176,\n\t229,\n\t144,\n\t141,\n\t231,\n\t167,\n\t176,\n\t228,\n\t184,\n\t186,\n\t228,\n\t186,\n\t134,\n\t230,\n\t136,\n\t144,\n\t229,\n\t138,\n\t159,\n\t232,\n\t175,\n\t180,\n\t230,\n\t152,\n\t142,\n\t228,\n\t190,\n\t155,\n\t229,\n\t186,\n\t148,\n\t229,\n\t173,\n\t169,\n\t229,\n\t173,\n\t144,\n\t228,\n\t184,\n\t147,\n\t233,\n\t162,\n\t152,\n\t231,\n\t168,\n\t139,\n\t229,\n\t186,\n\t143,\n\t228,\n\t184,\n\t128,\n\t232,\n\t136,\n\t172,\n\t230,\n\t156,\n\t131,\n\t229,\n\t147,\n\t161,\n\t229,\n\t143,\n\t170,\n\t230,\n\t156,\n\t137,\n\t229,\n\t133,\n\t182,\n\t229,\n\t174,\n\t131,\n\t228,\n\t191,\n\t157,\n\t230,\n\t138,\n\t164,\n\t232,\n\t128,\n\t140,\n\t228,\n\t184,\n\t148,\n\t228,\n\t187,\n\t138,\n\t229,\n\t164,\n\t169,\n\t231,\n\t170,\n\t151,\n\t229,\n\t143,\n\t163,\n\t229,\n\t138,\n\t168,\n\t230,\n\t128,\n\t129,\n\t231,\n\t138,\n\t182,\n\t230,\n\t128,\n\t129,\n\t231,\n\t137,\n\t185,\n\t229,\n\t136,\n\t171,\n\t232,\n\t174,\n\t164,\n\t228,\n\t184,\n\t186,\n\t229,\n\t191,\n\t133,\n\t233,\n\t161,\n\t187,\n\t230,\n\t155,\n\t180,\n\t230,\n\t150,\n\t176,\n\t229,\n\t176,\n\t143,\n\t232,\n\t175,\n\t180,\n\t230,\n\t136,\n\t145,\n\t229,\n\t128,\n\t145,\n\t228,\n\t189,\n\t156,\n\t228,\n\t184,\n\t186,\n\t229,\n\t170,\n\t146,\n\t228,\n\t189,\n\t147,\n\t229,\n\t140,\n\t133,\n\t230,\n\t139,\n\t172,\n\t233,\n\t130,\n\t163,\n\t228,\n\t185,\n\t136,\n\t228,\n\t184,\n\t128,\n\t230,\n\t160,\n\t183,\n\t229,\n\t155,\n\t189,\n\t229,\n\t134,\n\t133,\n\t230,\n\t152,\n\t175,\n\t229,\n\t144,\n\t166,\n\t230,\n\t160,\n\t185,\n\t230,\n\t141,\n\t174,\n\t231,\n\t148,\n\t181,\n\t232,\n\t167,\n\t134,\n\t229,\n\t173,\n\t166,\n\t233,\n\t153,\n\t162,\n\t229,\n\t133,\n\t183,\n\t230,\n\t156,\n\t137,\n\t232,\n\t191,\n\t135,\n\t231,\n\t168,\n\t139,\n\t231,\n\t148,\n\t177,\n\t228,\n\t186,\n\t142,\n\t228,\n\t186,\n\t186,\n\t230,\n\t137,\n\t141,\n\t229,\n\t135,\n\t186,\n\t230,\n\t157,\n\t165,\n\t228,\n\t184,\n\t141,\n\t232,\n\t191,\n\t135,\n\t230,\n\t173,\n\t163,\n\t229,\n\t156,\n\t168,\n\t230,\n\t152,\n\t142,\n\t230,\n\t152,\n\t159,\n\t230,\n\t149,\n\t133,\n\t228,\n\t186,\n\t139,\n\t229,\n\t133,\n\t179,\n\t231,\n\t179,\n\t187,\n\t230,\n\t160,\n\t135,\n\t233,\n\t162,\n\t152,\n\t229,\n\t149,\n\t134,\n\t229,\n\t138,\n\t161,\n\t232,\n\t190,\n\t147,\n\t229,\n\t133,\n\t165,\n\t228,\n\t184,\n\t128,\n\t231,\n\t155,\n\t180,\n\t229,\n\t159,\n\t186,\n\t231,\n\t161,\n\t128,\n\t230,\n\t149,\n\t153,\n\t229,\n\t173,\n\t166,\n\t228,\n\t186,\n\t134,\n\t232,\n\t167,\n\t163,\n\t229,\n\t187,\n\t186,\n\t231,\n\t173,\n\t145,\n\t231,\n\t187,\n\t147,\n\t230,\n\t158,\n\t156,\n\t229,\n\t133,\n\t168,\n\t231,\n\t144,\n\t131,\n\t233,\n\t128,\n\t154,\n\t231,\n\t159,\n\t165,\n\t232,\n\t174,\n\t161,\n\t229,\n\t136,\n\t146,\n\t229,\n\t175,\n\t185,\n\t228,\n\t186,\n\t142,\n\t232,\n\t137,\n\t186,\n\t230,\n\t156,\n\t175,\n\t231,\n\t155,\n\t184,\n\t229,\n\t134,\n\t140,\n\t229,\n\t143,\n\t145,\n\t231,\n\t148,\n\t159,\n\t231,\n\t156,\n\t159,\n\t231,\n\t154,\n\t132,\n\t229,\n\t187,\n\t186,\n\t231,\n\t171,\n\t139,\n\t231,\n\t173,\n\t137,\n\t231,\n\t186,\n\t167,\n\t231,\n\t177,\n\t187,\n\t229,\n\t158,\n\t139,\n\t231,\n\t187,\n\t143,\n\t233,\n\t170,\n\t140,\n\t229,\n\t174,\n\t158,\n\t231,\n\t142,\n\t176,\n\t229,\n\t136,\n\t182,\n\t228,\n\t189,\n\t156,\n\t230,\n\t157,\n\t165,\n\t232,\n\t135,\n\t170,\n\t230,\n\t160,\n\t135,\n\t231,\n\t173,\n\t190,\n\t228,\n\t187,\n\t165,\n\t228,\n\t184,\n\t139,\n\t229,\n\t142,\n\t159,\n\t229,\n\t136,\n\t155,\n\t230,\n\t151,\n\t160,\n\t230,\n\t179,\n\t149,\n\t229,\n\t133,\n\t182,\n\t228,\n\t184,\n\t173,\n\t229,\n\t128,\n\t139,\n\t228,\n\t186,\n\t186,\n\t228,\n\t184,\n\t128,\n\t229,\n\t136,\n\t135,\n\t230,\n\t140,\n\t135,\n\t229,\n\t141,\n\t151,\n\t229,\n\t133,\n\t179,\n\t233,\n\t151,\n\t173,\n\t233,\n\t155,\n\t134,\n\t229,\n\t155,\n\t162,\n\t231,\n\t172,\n\t172,\n\t228,\n\t184,\n\t137,\n\t229,\n\t133,\n\t179,\n\t230,\n\t179,\n\t168,\n\t229,\n\t155,\n\t160,\n\t230,\n\t173,\n\t164,\n\t231,\n\t133,\n\t167,\n\t231,\n\t137,\n\t135,\n\t230,\n\t183,\n\t177,\n\t229,\n\t156,\n\t179,\n\t229,\n\t149,\n\t134,\n\t228,\n\t184,\n\t154,\n\t229,\n\t185,\n\t191,\n\t229,\n\t183,\n\t158,\n\t230,\n\t151,\n\t165,\n\t230,\n\t156,\n\t159,\n\t233,\n\t171,\n\t152,\n\t231,\n\t186,\n\t167,\n\t230,\n\t156,\n\t128,\n\t232,\n\t191,\n\t145,\n\t231,\n\t187,\n\t188,\n\t229,\n\t144,\n\t136,\n\t232,\n\t161,\n\t168,\n\t231,\n\t164,\n\t186,\n\t228,\n\t184,\n\t147,\n\t232,\n\t190,\n\t145,\n\t232,\n\t161,\n\t140,\n\t228,\n\t184,\n\t186,\n\t228,\n\t186,\n\t164,\n\t233,\n\t128,\n\t154,\n\t232,\n\t175,\n\t132,\n\t228,\n\t187,\n\t183,\n\t232,\n\t167,\n\t137,\n\t229,\n\t190,\n\t151,\n\t231,\n\t178,\n\t190,\n\t229,\n\t141,\n\t142,\n\t229,\n\t174,\n\t182,\n\t229,\n\t186,\n\t173,\n\t229,\n\t174,\n\t140,\n\t230,\n\t136,\n\t144,\n\t230,\n\t132,\n\t159,\n\t232,\n\t167,\n\t137,\n\t229,\n\t174,\n\t137,\n\t232,\n\t163,\n\t133,\n\t229,\n\t190,\n\t151,\n\t229,\n\t136,\n\t176,\n\t233,\n\t130,\n\t174,\n\t228,\n\t187,\n\t182,\n\t229,\n\t136,\n\t182,\n\t229,\n\t186,\n\t166,\n\t233,\n\t163,\n\t159,\n\t229,\n\t147,\n\t129,\n\t232,\n\t153,\n\t189,\n\t231,\n\t132,\n\t182,\n\t232,\n\t189,\n\t172,\n\t232,\n\t189,\n\t189,\n\t230,\n\t138,\n\t165,\n\t228,\n\t187,\n\t183,\n\t232,\n\t174,\n\t176,\n\t232,\n\t128,\n\t133,\n\t230,\n\t150,\n\t185,\n\t230,\n\t161,\n\t136,\n\t232,\n\t161,\n\t140,\n\t230,\n\t148,\n\t191,\n\t228,\n\t186,\n\t186,\n\t230,\n\t176,\n\t145,\n\t231,\n\t148,\n\t168,\n\t229,\n\t147,\n\t129,\n\t228,\n\t184,\n\t156,\n\t232,\n\t165,\n\t191,\n\t230,\n\t143,\n\t144,\n\t229,\n\t135,\n\t186,\n\t233,\n\t133,\n\t146,\n\t229,\n\t186,\n\t151,\n\t231,\n\t132,\n\t182,\n\t229,\n\t144,\n\t142,\n\t228,\n\t187,\n\t152,\n\t230,\n\t172,\n\t190,\n\t231,\n\t131,\n\t173,\n\t231,\n\t130,\n\t185,\n\t228,\n\t187,\n\t165,\n\t229,\n\t137,\n\t141,\n\t229,\n\t174,\n\t140,\n\t229,\n\t133,\n\t168,\n\t229,\n\t143,\n\t145,\n\t229,\n\t184,\n\t150,\n\t232,\n\t174,\n\t190,\n\t231,\n\t189,\n\t174,\n\t233,\n\t162,\n\t134,\n\t229,\n\t175,\n\t188,\n\t229,\n\t183,\n\t165,\n\t228,\n\t184,\n\t154,\n\t229,\n\t140,\n\t187,\n\t233,\n\t153,\n\t162,\n\t231,\n\t156,\n\t139,\n\t231,\n\t156,\n\t139,\n\t231,\n\t187,\n\t143,\n\t229,\n\t133,\n\t184,\n\t229,\n\t142,\n\t159,\n\t229,\n\t155,\n\t160,\n\t229,\n\t185,\n\t179,\n\t229,\n\t143,\n\t176,\n\t229,\n\t144,\n\t132,\n\t231,\n\t167,\n\t141,\n\t229,\n\t162,\n\t158,\n\t229,\n\t138,\n\t160,\n\t230,\n\t157,\n\t144,\n\t230,\n\t150,\n\t153,\n\t230,\n\t150,\n\t176,\n\t229,\n\t162,\n\t158,\n\t228,\n\t185,\n\t139,\n\t229,\n\t144,\n\t142,\n\t232,\n\t129,\n\t140,\n\t228,\n\t184,\n\t154,\n\t230,\n\t149,\n\t136,\n\t230,\n\t158,\n\t156,\n\t228,\n\t187,\n\t138,\n\t229,\n\t185,\n\t180,\n\t232,\n\t174,\n\t186,\n\t230,\n\t150,\n\t135,\n\t230,\n\t136,\n\t145,\n\t229,\n\t155,\n\t189,\n\t229,\n\t145,\n\t138,\n\t232,\n\t175,\n\t137,\n\t231,\n\t137,\n\t136,\n\t228,\n\t184,\n\t187,\n\t228,\n\t191,\n\t174,\n\t230,\n\t148,\n\t185,\n\t229,\n\t143,\n\t130,\n\t228,\n\t184,\n\t142,\n\t230,\n\t137,\n\t147,\n\t229,\n\t141,\n\t176,\n\t229,\n\t191,\n\t171,\n\t228,\n\t185,\n\t144,\n\t230,\n\t156,\n\t186,\n\t230,\n\t162,\n\t176,\n\t232,\n\t167,\n\t130,\n\t231,\n\t130,\n\t185,\n\t229,\n\t173,\n\t152,\n\t229,\n\t156,\n\t168,\n\t231,\n\t178,\n\t190,\n\t231,\n\t165,\n\t158,\n\t232,\n\t142,\n\t183,\n\t229,\n\t190,\n\t151,\n\t229,\n\t136,\n\t169,\n\t231,\n\t148,\n\t168,\n\t231,\n\t187,\n\t167,\n\t231,\n\t187,\n\t173,\n\t228,\n\t189,\n\t160,\n\t228,\n\t187,\n\t172,\n\t232,\n\t191,\n\t153,\n\t228,\n\t185,\n\t136,\n\t230,\n\t168,\n\t161,\n\t229,\n\t188,\n\t143,\n\t232,\n\t175,\n\t173,\n\t232,\n\t168,\n\t128,\n\t232,\n\t131,\n\t189,\n\t229,\n\t164,\n\t159,\n\t233,\n\t155,\n\t133,\n\t232,\n\t153,\n\t142,\n\t230,\n\t147,\n\t141,\n\t228,\n\t189,\n\t156,\n\t233,\n\t163,\n\t142,\n\t230,\n\t160,\n\t188,\n\t228,\n\t184,\n\t128,\n\t232,\n\t181,\n\t183,\n\t231,\n\t167,\n\t145,\n\t229,\n\t173,\n\t166,\n\t228,\n\t189,\n\t147,\n\t232,\n\t130,\n\t178,\n\t231,\n\t159,\n\t173,\n\t228,\n\t191,\n\t161,\n\t230,\n\t157,\n\t161,\n\t228,\n\t187,\n\t182,\n\t230,\n\t178,\n\t187,\n\t231,\n\t150,\n\t151,\n\t232,\n\t191,\n\t144,\n\t229,\n\t138,\n\t168,\n\t228,\n\t186,\n\t167,\n\t228,\n\t184,\n\t154,\n\t228,\n\t188,\n\t154,\n\t232,\n\t174,\n\t174,\n\t229,\n\t175,\n\t188,\n\t232,\n\t136,\n\t170,\n\t229,\n\t133,\n\t136,\n\t231,\n\t148,\n\t159,\n\t232,\n\t129,\n\t148,\n\t231,\n\t155,\n\t159,\n\t229,\n\t143,\n\t175,\n\t230,\n\t152,\n\t175,\n\t229,\n\t149,\n\t143,\n\t233,\n\t161,\n\t140,\n\t231,\n\t187,\n\t147,\n\t230,\n\t158,\n\t132,\n\t228,\n\t189,\n\t156,\n\t231,\n\t148,\n\t168,\n\t232,\n\t176,\n\t131,\n\t230,\n\t159,\n\t165,\n\t232,\n\t179,\n\t135,\n\t230,\n\t150,\n\t153,\n\t232,\n\t135,\n\t170,\n\t229,\n\t138,\n\t168,\n\t232,\n\t180,\n\t159,\n\t232,\n\t180,\n\t163,\n\t229,\n\t134,\n\t156,\n\t228,\n\t184,\n\t154,\n\t232,\n\t174,\n\t191,\n\t233,\n\t151,\n\t174,\n\t229,\n\t174,\n\t158,\n\t230,\n\t150,\n\t189,\n\t230,\n\t142,\n\t165,\n\t229,\n\t143,\n\t151,\n\t232,\n\t174,\n\t168,\n\t232,\n\t174,\n\t186,\n\t233,\n\t130,\n\t163,\n\t228,\n\t184,\n\t170,\n\t229,\n\t143,\n\t141,\n\t233,\n\t166,\n\t136,\n\t229,\n\t138,\n\t160,\n\t229,\n\t188,\n\t186,\n\t229,\n\t165,\n\t179,\n\t230,\n\t128,\n\t167,\n\t232,\n\t140,\n\t131,\n\t229,\n\t155,\n\t180,\n\t230,\n\t156,\n\t141,\n\t229,\n\t139,\n\t153,\n\t228,\n\t188,\n\t145,\n\t233,\n\t151,\n\t178,\n\t228,\n\t187,\n\t138,\n\t230,\n\t151,\n\t165,\n\t229,\n\t174,\n\t162,\n\t230,\n\t156,\n\t141,\n\t232,\n\t167,\n\t128,\n\t231,\n\t156,\n\t139,\n\t229,\n\t143,\n\t130,\n\t229,\n\t138,\n\t160,\n\t231,\n\t154,\n\t132,\n\t232,\n\t175,\n\t157,\n\t228,\n\t184,\n\t128,\n\t231,\n\t130,\n\t185,\n\t228,\n\t191,\n\t157,\n\t232,\n\t175,\n\t129,\n\t229,\n\t155,\n\t190,\n\t228,\n\t185,\n\t166,\n\t230,\n\t156,\n\t137,\n\t230,\n\t149,\n\t136,\n\t230,\n\t181,\n\t139,\n\t232,\n\t175,\n\t149,\n\t231,\n\t167,\n\t187,\n\t229,\n\t138,\n\t168,\n\t230,\n\t137,\n\t141,\n\t232,\n\t131,\n\t189,\n\t229,\n\t134,\n\t179,\n\t229,\n\t174,\n\t154,\n\t232,\n\t130,\n\t161,\n\t231,\n\t165,\n\t168,\n\t228,\n\t184,\n\t141,\n\t230,\n\t150,\n\t173,\n\t233,\n\t156,\n\t128,\n\t230,\n\t177,\n\t130,\n\t228,\n\t184,\n\t141,\n\t229,\n\t190,\n\t151,\n\t229,\n\t138,\n\t158,\n\t230,\n\t179,\n\t149,\n\t228,\n\t185,\n\t139,\n\t233,\n\t151,\n\t180,\n\t233,\n\t135,\n\t135,\n\t231,\n\t148,\n\t168,\n\t232,\n\t144,\n\t165,\n\t233,\n\t148,\n\t128,\n\t230,\n\t138,\n\t149,\n\t232,\n\t175,\n\t137,\n\t231,\n\t155,\n\t174,\n\t230,\n\t160,\n\t135,\n\t231,\n\t136,\n\t177,\n\t230,\n\t131,\n\t133,\n\t230,\n\t145,\n\t132,\n\t229,\n\t189,\n\t177,\n\t230,\n\t156,\n\t137,\n\t228,\n\t186,\n\t155,\n\t232,\n\t164,\n\t135,\n\t232,\n\t163,\n\t189,\n\t230,\n\t150,\n\t135,\n\t229,\n\t173,\n\t166,\n\t230,\n\t156,\n\t186,\n\t228,\n\t188,\n\t154,\n\t230,\n\t149,\n\t176,\n\t229,\n\t173,\n\t151,\n\t232,\n\t163,\n\t133,\n\t228,\n\t191,\n\t174,\n\t232,\n\t180,\n\t173,\n\t231,\n\t137,\n\t169,\n\t229,\n\t134,\n\t156,\n\t230,\n\t157,\n\t145,\n\t229,\n\t133,\n\t168,\n\t233,\n\t157,\n\t162,\n\t231,\n\t178,\n\t190,\n\t229,\n\t147,\n\t129,\n\t229,\n\t133,\n\t182,\n\t229,\n\t174,\n\t158,\n\t228,\n\t186,\n\t139,\n\t230,\n\t131,\n\t133,\n\t230,\n\t176,\n\t180,\n\t229,\n\t185,\n\t179,\n\t230,\n\t143,\n\t144,\n\t231,\n\t164,\n\t186,\n\t228,\n\t184,\n\t138,\n\t229,\n\t184,\n\t130,\n\t232,\n\t176,\n\t162,\n\t232,\n\t176,\n\t162,\n\t230,\n\t153,\n\t174,\n\t233,\n\t128,\n\t154,\n\t230,\n\t149,\n\t153,\n\t229,\n\t184,\n\t136,\n\t228,\n\t184,\n\t138,\n\t228,\n\t188,\n\t160,\n\t231,\n\t177,\n\t187,\n\t229,\n\t136,\n\t171,\n\t230,\n\t173,\n\t140,\n\t230,\n\t155,\n\t178,\n\t230,\n\t139,\n\t165,\n\t230,\n\t156,\n\t137,\n\t229,\n\t136,\n\t155,\n\t230,\n\t150,\n\t176,\n\t233,\n\t133,\n\t141,\n\t228,\n\t187,\n\t182,\n\t229,\n\t143,\n\t170,\n\t232,\n\t166,\n\t129,\n\t230,\n\t151,\n\t182,\n\t228,\n\t187,\n\t163,\n\t232,\n\t179,\n\t135,\n\t232,\n\t168,\n\t138,\n\t232,\n\t190,\n\t190,\n\t229,\n\t136,\n\t176,\n\t228,\n\t186,\n\t186,\n\t231,\n\t148,\n\t159,\n\t232,\n\t174,\n\t162,\n\t233,\n\t152,\n\t133,\n\t232,\n\t128,\n\t129,\n\t229,\n\t184,\n\t136,\n\t229,\n\t177,\n\t149,\n\t231,\n\t164,\n\t186,\n\t229,\n\t191,\n\t131,\n\t231,\n\t144,\n\t134,\n\t232,\n\t180,\n\t180,\n\t229,\n\t173,\n\t144,\n\t231,\n\t182,\n\t178,\n\t231,\n\t171,\n\t153,\n\t228,\n\t184,\n\t187,\n\t233,\n\t161,\n\t140,\n\t232,\n\t135,\n\t170,\n\t231,\n\t132,\n\t182,\n\t231,\n\t186,\n\t167,\n\t229,\n\t136,\n\t171,\n\t231,\n\t174,\n\t128,\n\t229,\n\t141,\n\t149,\n\t230,\n\t148,\n\t185,\n\t233,\n\t157,\n\t169,\n\t233,\n\t130,\n\t163,\n\t228,\n\t186,\n\t155,\n\t230,\n\t157,\n\t165,\n\t232,\n\t175,\n\t180,\n\t230,\n\t137,\n\t147,\n\t229,\n\t188,\n\t128,\n\t228,\n\t187,\n\t163,\n\t231,\n\t160,\n\t129,\n\t229,\n\t136,\n\t160,\n\t233,\n\t153,\n\t164,\n\t232,\n\t175,\n\t129,\n\t229,\n\t136,\n\t184,\n\t232,\n\t138,\n\t130,\n\t231,\n\t155,\n\t174,\n\t233,\n\t135,\n\t141,\n\t231,\n\t130,\n\t185,\n\t230,\n\t172,\n\t161,\n\t230,\n\t149,\n\t184,\n\t229,\n\t164,\n\t154,\n\t229,\n\t176,\n\t145,\n\t232,\n\t167,\n\t132,\n\t229,\n\t136,\n\t146,\n\t232,\n\t181,\n\t132,\n\t233,\n\t135,\n\t145,\n\t230,\n\t137,\n\t190,\n\t229,\n\t136,\n\t176,\n\t228,\n\t187,\n\t165,\n\t229,\n\t144,\n\t142,\n\t229,\n\t164,\n\t167,\n\t229,\n\t133,\n\t168,\n\t228,\n\t184,\n\t187,\n\t233,\n\t161,\n\t181,\n\t230,\n\t156,\n\t128,\n\t228,\n\t189,\n\t179,\n\t229,\n\t155,\n\t158,\n\t231,\n\t173,\n\t148,\n\t229,\n\t164,\n\t169,\n\t228,\n\t184,\n\t139,\n\t228,\n\t191,\n\t157,\n\t233,\n\t154,\n\t156,\n\t231,\n\t142,\n\t176,\n\t228,\n\t187,\n\t163,\n\t230,\n\t163,\n\t128,\n\t230,\n\t159,\n\t165,\n\t230,\n\t138,\n\t149,\n\t231,\n\t165,\n\t168,\n\t229,\n\t176,\n\t143,\n\t230,\n\t151,\n\t182,\n\t230,\n\t178,\n\t146,\n\t230,\n\t156,\n\t137,\n\t230,\n\t173,\n\t163,\n\t229,\n\t184,\n\t184,\n\t231,\n\t148,\n\t154,\n\t232,\n\t135,\n\t179,\n\t228,\n\t187,\n\t163,\n\t231,\n\t144,\n\t134,\n\t231,\n\t155,\n\t174,\n\t229,\n\t189,\n\t149,\n\t229,\n\t133,\n\t172,\n\t229,\n\t188,\n\t128,\n\t229,\n\t164,\n\t141,\n\t229,\n\t136,\n\t182,\n\t233,\n\t135,\n\t145,\n\t232,\n\t158,\n\t141,\n\t229,\n\t185,\n\t184,\n\t231,\n\t166,\n\t143,\n\t231,\n\t137,\n\t136,\n\t230,\n\t156,\n\t172,\n\t229,\n\t189,\n\t162,\n\t230,\n\t136,\n\t144,\n\t229,\n\t135,\n\t134,\n\t229,\n\t164,\n\t135,\n\t232,\n\t161,\n\t140,\n\t230,\n\t131,\n\t133,\n\t229,\n\t155,\n\t158,\n\t229,\n\t136,\n\t176,\n\t230,\n\t128,\n\t157,\n\t230,\n\t131,\n\t179,\n\t230,\n\t128,\n\t142,\n\t230,\n\t160,\n\t183,\n\t229,\n\t141,\n\t143,\n\t232,\n\t174,\n\t174,\n\t232,\n\t174,\n\t164,\n\t232,\n\t175,\n\t129,\n\t230,\n\t156,\n\t128,\n\t229,\n\t165,\n\t189,\n\t228,\n\t186,\n\t167,\n\t231,\n\t148,\n\t159,\n\t230,\n\t140,\n\t137,\n\t231,\n\t133,\n\t167,\n\t230,\n\t156,\n\t141,\n\t232,\n\t163,\n\t133,\n\t229,\n\t185,\n\t191,\n\t228,\n\t184,\n\t156,\n\t229,\n\t138,\n\t168,\n\t230,\n\t188,\n\t171,\n\t233,\n\t135,\n\t135,\n\t232,\n\t180,\n\t173,\n\t230,\n\t150,\n\t176,\n\t230,\n\t137,\n\t139,\n\t231,\n\t187,\n\t132,\n\t229,\n\t155,\n\t190,\n\t233,\n\t157,\n\t162,\n\t230,\n\t157,\n\t191,\n\t229,\n\t143,\n\t130,\n\t232,\n\t128,\n\t131,\n\t230,\n\t148,\n\t191,\n\t230,\n\t178,\n\t187,\n\t229,\n\t174,\n\t185,\n\t230,\n\t152,\n\t147,\n\t229,\n\t164,\n\t169,\n\t229,\n\t156,\n\t176,\n\t229,\n\t138,\n\t170,\n\t229,\n\t138,\n\t155,\n\t228,\n\t186,\n\t186,\n\t228,\n\t187,\n\t172,\n\t229,\n\t141,\n\t135,\n\t231,\n\t186,\n\t167,\n\t233,\n\t128,\n\t159,\n\t229,\n\t186,\n\t166,\n\t228,\n\t186,\n\t186,\n\t231,\n\t137,\n\t169,\n\t232,\n\t176,\n\t131,\n\t230,\n\t149,\n\t180,\n\t230,\n\t181,\n\t129,\n\t232,\n\t161,\n\t140,\n\t233,\n\t128,\n\t160,\n\t230,\n\t136,\n\t144,\n\t230,\n\t150,\n\t135,\n\t229,\n\t173,\n\t151,\n\t233,\n\t159,\n\t169,\n\t229,\n\t155,\n\t189,\n\t232,\n\t180,\n\t184,\n\t230,\n\t152,\n\t147,\n\t229,\n\t188,\n\t128,\n\t229,\n\t177,\n\t149,\n\t231,\n\t155,\n\t184,\n\t233,\n\t151,\n\t156,\n\t232,\n\t161,\n\t168,\n\t231,\n\t142,\n\t176,\n\t229,\n\t189,\n\t177,\n\t232,\n\t167,\n\t134,\n\t229,\n\t166,\n\t130,\n\t230,\n\t173,\n\t164,\n\t231,\n\t190,\n\t142,\n\t229,\n\t174,\n\t185,\n\t229,\n\t164,\n\t167,\n\t229,\n\t176,\n\t143,\n\t230,\n\t138,\n\t165,\n\t233,\n\t129,\n\t147,\n\t230,\n\t157,\n\t161,\n\t230,\n\t172,\n\t190,\n\t229,\n\t191,\n\t131,\n\t230,\n\t131,\n\t133,\n\t232,\n\t174,\n\t184,\n\t229,\n\t164,\n\t154,\n\t230,\n\t179,\n\t149,\n\t232,\n\t167,\n\t132,\n\t229,\n\t174,\n\t182,\n\t229,\n\t177,\n\t133,\n\t228,\n\t185,\n\t166,\n\t229,\n\t186,\n\t151,\n\t232,\n\t191,\n\t158,\n\t230,\n\t142,\n\t165,\n\t231,\n\t171,\n\t139,\n\t229,\n\t141,\n\t179,\n\t228,\n\t184,\n\t190,\n\t230,\n\t138,\n\t165,\n\t230,\n\t138,\n\t128,\n\t229,\n\t183,\n\t167,\n\t229,\n\t165,\n\t165,\n\t232,\n\t191,\n\t144,\n\t231,\n\t153,\n\t187,\n\t229,\n\t133,\n\t165,\n\t228,\n\t187,\n\t165,\n\t230,\n\t157,\n\t165,\n\t231,\n\t144,\n\t134,\n\t232,\n\t174,\n\t186,\n\t228,\n\t186,\n\t139,\n\t228,\n\t187,\n\t182,\n\t232,\n\t135,\n\t170,\n\t231,\n\t148,\n\t177,\n\t228,\n\t184,\n\t173,\n\t229,\n\t141,\n\t142,\n\t229,\n\t138,\n\t158,\n\t229,\n\t133,\n\t172,\n\t229,\n\t166,\n\t136,\n\t229,\n\t166,\n\t136,\n\t231,\n\t156,\n\t159,\n\t230,\n\t173,\n\t163,\n\t228,\n\t184,\n\t141,\n\t233,\n\t148,\n\t153,\n\t229,\n\t133,\n\t168,\n\t230,\n\t150,\n\t135,\n\t229,\n\t144,\n\t136,\n\t229,\n\t144,\n\t140,\n\t228,\n\t187,\n\t183,\n\t229,\n\t128,\n\t188,\n\t229,\n\t136,\n\t171,\n\t228,\n\t186,\n\t186,\n\t231,\n\t155,\n\t145,\n\t231,\n\t157,\n\t163,\n\t229,\n\t133,\n\t183,\n\t228,\n\t189,\n\t147,\n\t228,\n\t184,\n\t150,\n\t231,\n\t186,\n\t170,\n\t229,\n\t155,\n\t162,\n\t233,\n\t152,\n\t159,\n\t229,\n\t136,\n\t155,\n\t228,\n\t184,\n\t154,\n\t230,\n\t137,\n\t191,\n\t230,\n\t139,\n\t133,\n\t229,\n\t162,\n\t158,\n\t233,\n\t149,\n\t191,\n\t230,\n\t156,\n\t137,\n\t228,\n\t186,\n\t186,\n\t228,\n\t191,\n\t157,\n\t230,\n\t140,\n\t129,\n\t229,\n\t149,\n\t134,\n\t229,\n\t174,\n\t182,\n\t231,\n\t187,\n\t180,\n\t228,\n\t191,\n\t174,\n\t229,\n\t143,\n\t176,\n\t230,\n\t185,\n\t190,\n\t229,\n\t183,\n\t166,\n\t229,\n\t143,\n\t179,\n\t232,\n\t130,\n\t161,\n\t228,\n\t187,\n\t189,\n\t231,\n\t173,\n\t148,\n\t230,\n\t161,\n\t136,\n\t229,\n\t174,\n\t158,\n\t233,\n\t153,\n\t133,\n\t231,\n\t148,\n\t181,\n\t228,\n\t191,\n\t161,\n\t231,\n\t187,\n\t143,\n\t231,\n\t144,\n\t134,\n\t231,\n\t148,\n\t159,\n\t229,\n\t145,\n\t189,\n\t229,\n\t174,\n\t163,\n\t228,\n\t188,\n\t160,\n\t228,\n\t187,\n\t187,\n\t229,\n\t138,\n\t161,\n\t230,\n\t173,\n\t163,\n\t229,\n\t188,\n\t143,\n\t231,\n\t137,\n\t185,\n\t232,\n\t137,\n\t178,\n\t228,\n\t184,\n\t139,\n\t230,\n\t157,\n\t165,\n\t229,\n\t141,\n\t143,\n\t228,\n\t188,\n\t154,\n\t229,\n\t143,\n\t170,\n\t232,\n\t131,\n\t189,\n\t229,\n\t189,\n\t147,\n\t231,\n\t132,\n\t182,\n\t233,\n\t135,\n\t141,\n\t230,\n\t150,\n\t176,\n\t229,\n\t133,\n\t167,\n\t229,\n\t174,\n\t185,\n\t230,\n\t140,\n\t135,\n\t229,\n\t175,\n\t188,\n\t232,\n\t191,\n\t144,\n\t232,\n\t161,\n\t140,\n\t230,\n\t151,\n\t165,\n\t229,\n\t191,\n\t151,\n\t232,\n\t179,\n\t163,\n\t229,\n\t174,\n\t182,\n\t232,\n\t182,\n\t133,\n\t232,\n\t191,\n\t135,\n\t229,\n\t156,\n\t159,\n\t229,\n\t156,\n\t176,\n\t230,\n\t181,\n\t153,\n\t230,\n\t177,\n\t159,\n\t230,\n\t148,\n\t175,\n\t228,\n\t187,\n\t152,\n\t230,\n\t142,\n\t168,\n\t229,\n\t135,\n\t186,\n\t231,\n\t171,\n\t153,\n\t233,\n\t149,\n\t191,\n\t230,\n\t157,\n\t173,\n\t229,\n\t183,\n\t158,\n\t230,\n\t137,\n\t167,\n\t232,\n\t161,\n\t140,\n\t229,\n\t136,\n\t182,\n\t233,\n\t128,\n\t160,\n\t228,\n\t185,\n\t139,\n\t228,\n\t184,\n\t128,\n\t230,\n\t142,\n\t168,\n\t229,\n\t185,\n\t191,\n\t231,\n\t142,\n\t176,\n\t229,\n\t156,\n\t186,\n\t230,\n\t143,\n\t143,\n\t232,\n\t191,\n\t176,\n\t229,\n\t143,\n\t152,\n\t229,\n\t140,\n\t150,\n\t228,\n\t188,\n\t160,\n\t231,\n\t187,\n\t159,\n\t230,\n\t173,\n\t140,\n\t230,\n\t137,\n\t139,\n\t228,\n\t191,\n\t157,\n\t233,\n\t153,\n\t169,\n\t232,\n\t175,\n\t190,\n\t231,\n\t168,\n\t139,\n\t229,\n\t140,\n\t187,\n\t231,\n\t150,\n\t151,\n\t231,\n\t187,\n\t143,\n\t232,\n\t191,\n\t135,\n\t232,\n\t191,\n\t135,\n\t229,\n\t142,\n\t187,\n\t228,\n\t185,\n\t139,\n\t229,\n\t137,\n\t141,\n\t230,\n\t148,\n\t182,\n\t229,\n\t133,\n\t165,\n\t229,\n\t185,\n\t180,\n\t229,\n\t186,\n\t166,\n\t230,\n\t157,\n\t130,\n\t229,\n\t191,\n\t151,\n\t231,\n\t190,\n\t142,\n\t228,\n\t184,\n\t189,\n\t230,\n\t156,\n\t128,\n\t233,\n\t171,\n\t152,\n\t231,\n\t153,\n\t187,\n\t233,\n\t153,\n\t134,\n\t230,\n\t156,\n\t170,\n\t230,\n\t157,\n\t165,\n\t229,\n\t138,\n\t160,\n\t229,\n\t183,\n\t165,\n\t229,\n\t133,\n\t141,\n\t232,\n\t180,\n\t163,\n\t230,\n\t149,\n\t153,\n\t231,\n\t168,\n\t139,\n\t231,\n\t137,\n\t136,\n\t229,\n\t157,\n\t151,\n\t232,\n\t186,\n\t171,\n\t228,\n\t189,\n\t147,\n\t233,\n\t135,\n\t141,\n\t229,\n\t186,\n\t134,\n\t229,\n\t135,\n\t186,\n\t229,\n\t148,\n\t174,\n\t230,\n\t136,\n\t144,\n\t230,\n\t156,\n\t172,\n\t229,\n\t189,\n\t162,\n\t229,\n\t188,\n\t143,\n\t229,\n\t156,\n\t159,\n\t232,\n\t177,\n\t134,\n\t229,\n\t135,\n\t186,\n\t229,\n\t131,\n\t185,\n\t228,\n\t184,\n\t156,\n\t230,\n\t150,\n\t185,\n\t233,\n\t130,\n\t174,\n\t231,\n\t174,\n\t177,\n\t229,\n\t141,\n\t151,\n\t228,\n\t186,\n\t172,\n\t230,\n\t177,\n\t130,\n\t232,\n\t129,\n\t140,\n\t229,\n\t143,\n\t150,\n\t229,\n\t190,\n\t151,\n\t232,\n\t129,\n\t140,\n\t228,\n\t189,\n\t141,\n\t231,\n\t155,\n\t184,\n\t228,\n\t191,\n\t161,\n\t233,\n\t161,\n\t181,\n\t233,\n\t157,\n\t162,\n\t229,\n\t136,\n\t134,\n\t233,\n\t146,\n\t159,\n\t231,\n\t189,\n\t145,\n\t233,\n\t161,\n\t181,\n\t231,\n\t161,\n\t174,\n\t229,\n\t174,\n\t154,\n\t229,\n\t155,\n\t190,\n\t228,\n\t190,\n\t139,\n\t231,\n\t189,\n\t145,\n\t229,\n\t157,\n\t128,\n\t231,\n\t167,\n\t175,\n\t230,\n\t158,\n\t129,\n\t233,\n\t148,\n\t153,\n\t232,\n\t175,\n\t175,\n\t231,\n\t155,\n\t174,\n\t231,\n\t154,\n\t132,\n\t229,\n\t174,\n\t157,\n\t232,\n\t180,\n\t157,\n\t230,\n\t156,\n\t186,\n\t229,\n\t133,\n\t179,\n\t233,\n\t163,\n\t142,\n\t233,\n\t153,\n\t169,\n\t230,\n\t142,\n\t136,\n\t230,\n\t157,\n\t131,\n\t231,\n\t151,\n\t133,\n\t230,\n\t175,\n\t146,\n\t229,\n\t174,\n\t160,\n\t231,\n\t137,\n\t169,\n\t233,\n\t153,\n\t164,\n\t228,\n\t186,\n\t134,\n\t232,\n\t169,\n\t149,\n\t232,\n\t171,\n\t150,\n\t231,\n\t150,\n\t190,\n\t231,\n\t151,\n\t133,\n\t229,\n\t143,\n\t138,\n\t230,\n\t151,\n\t182,\n\t230,\n\t177,\n\t130,\n\t232,\n\t180,\n\t173,\n\t231,\n\t171,\n\t153,\n\t231,\n\t130,\n\t185,\n\t229,\n\t132,\n\t191,\n\t231,\n\t171,\n\t165,\n\t230,\n\t175,\n\t143,\n\t229,\n\t164,\n\t169,\n\t228,\n\t184,\n\t173,\n\t229,\n\t164,\n\t174,\n\t232,\n\t174,\n\t164,\n\t232,\n\t175,\n\t134,\n\t230,\n\t175,\n\t143,\n\t228,\n\t184,\n\t170,\n\t229,\n\t164,\n\t169,\n\t230,\n\t180,\n\t165,\n\t229,\n\t173,\n\t151,\n\t228,\n\t189,\n\t147,\n\t229,\n\t143,\n\t176,\n\t231,\n\t129,\n\t163,\n\t231,\n\t187,\n\t180,\n\t230,\n\t138,\n\t164,\n\t230,\n\t156,\n\t172,\n\t233,\n\t161,\n\t181,\n\t228,\n\t184,\n\t170,\n\t230,\n\t128,\n\t167,\n\t229,\n\t174,\n\t152,\n\t230,\n\t150,\n\t185,\n\t229,\n\t184,\n\t184,\n\t232,\n\t167,\n\t129,\n\t231,\n\t155,\n\t184,\n\t230,\n\t156,\n\t186,\n\t230,\n\t136,\n\t152,\n\t231,\n\t149,\n\t165,\n\t229,\n\t186,\n\t148,\n\t229,\n\t189,\n\t147,\n\t229,\n\t190,\n\t139,\n\t229,\n\t184,\n\t136,\n\t230,\n\t150,\n\t185,\n\t228,\n\t190,\n\t191,\n\t230,\n\t160,\n\t161,\n\t229,\n\t155,\n\t173,\n\t232,\n\t130,\n\t161,\n\t229,\n\t184,\n\t130,\n\t230,\n\t136,\n\t191,\n\t229,\n\t177,\n\t139,\n\t230,\n\t160,\n\t143,\n\t231,\n\t155,\n\t174,\n\t229,\n\t145,\n\t152,\n\t229,\n\t183,\n\t165,\n\t229,\n\t175,\n\t188,\n\t232,\n\t135,\n\t180,\n\t231,\n\t170,\n\t129,\n\t231,\n\t132,\n\t182,\n\t233,\n\t129,\n\t147,\n\t229,\n\t133,\n\t183,\n\t230,\n\t156,\n\t172,\n\t231,\n\t189,\n\t145,\n\t231,\n\t187,\n\t147,\n\t229,\n\t144,\n\t136,\n\t230,\n\t161,\n\t163,\n\t230,\n\t161,\n\t136,\n\t229,\n\t138,\n\t179,\n\t229,\n\t138,\n\t168,\n\t229,\n\t143,\n\t166,\n\t229,\n\t164,\n\t150,\n\t231,\n\t190,\n\t142,\n\t229,\n\t133,\n\t131,\n\t229,\n\t188,\n\t149,\n\t232,\n\t181,\n\t183,\n\t230,\n\t148,\n\t185,\n\t229,\n\t143,\n\t152,\n\t231,\n\t172,\n\t172,\n\t229,\n\t155,\n\t155,\n\t228,\n\t188,\n\t154,\n\t232,\n\t174,\n\t161,\n\t232,\n\t170,\n\t170,\n\t230,\n\t152,\n\t142,\n\t233,\n\t154,\n\t144,\n\t231,\n\t167,\n\t129,\n\t229,\n\t174,\n\t157,\n\t229,\n\t174,\n\t157,\n\t232,\n\t167,\n\t132,\n\t232,\n\t140,\n\t131,\n\t230,\n\t182,\n\t136,\n\t232,\n\t180,\n\t185,\n\t229,\n\t133,\n\t177,\n\t229,\n\t144,\n\t140,\n\t229,\n\t191,\n\t152,\n\t232,\n\t174,\n\t176,\n\t228,\n\t189,\n\t147,\n\t231,\n\t179,\n\t187,\n\t229,\n\t184,\n\t166,\n\t230,\n\t157,\n\t165,\n\t229,\n\t144,\n\t141,\n\t229,\n\t173,\n\t151,\n\t231,\n\t153,\n\t188,\n\t232,\n\t161,\n\t168,\n\t229,\n\t188,\n\t128,\n\t230,\n\t148,\n\t190,\n\t229,\n\t138,\n\t160,\n\t231,\n\t155,\n\t159,\n\t229,\n\t143,\n\t151,\n\t229,\n\t136,\n\t176,\n\t228,\n\t186,\n\t140,\n\t230,\n\t137,\n\t139,\n\t229,\n\t164,\n\t167,\n\t233,\n\t135,\n\t143,\n\t230,\n\t136,\n\t144,\n\t228,\n\t186,\n\t186,\n\t230,\n\t149,\n\t176,\n\t233,\n\t135,\n\t143,\n\t229,\n\t133,\n\t177,\n\t228,\n\t186,\n\t171,\n\t229,\n\t140,\n\t186,\n\t229,\n\t159,\n\t159,\n\t229,\n\t165,\n\t179,\n\t229,\n\t173,\n\t169,\n\t229,\n\t142,\n\t159,\n\t229,\n\t136,\n\t153,\n\t230,\n\t137,\n\t128,\n\t229,\n\t156,\n\t168,\n\t231,\n\t187,\n\t147,\n\t230,\n\t157,\n\t159,\n\t233,\n\t128,\n\t154,\n\t228,\n\t191,\n\t161,\n\t232,\n\t182,\n\t133,\n\t231,\n\t186,\n\t167,\n\t233,\n\t133,\n\t141,\n\t231,\n\t189,\n\t174,\n\t229,\n\t189,\n\t147,\n\t230,\n\t151,\n\t182,\n\t228,\n\t188,\n\t152,\n\t231,\n\t167,\n\t128,\n\t230,\n\t128,\n\t167,\n\t230,\n\t132,\n\t159,\n\t230,\n\t136,\n\t191,\n\t228,\n\t186,\n\t167,\n\t233,\n\t129,\n\t138,\n\t230,\n\t136,\n\t178,\n\t229,\n\t135,\n\t186,\n\t229,\n\t143,\n\t163,\n\t230,\n\t143,\n\t144,\n\t228,\n\t186,\n\t164,\n\t229,\n\t176,\n\t177,\n\t228,\n\t184,\n\t154,\n\t228,\n\t191,\n\t157,\n\t229,\n\t129,\n\t165,\n\t231,\n\t168,\n\t139,\n\t229,\n\t186,\n\t166,\n\t229,\n\t143,\n\t130,\n\t230,\n\t149,\n\t176,\n\t228,\n\t186,\n\t139,\n\t228,\n\t184,\n\t154,\n\t230,\n\t149,\n\t180,\n\t228,\n\t184,\n\t170,\n\t229,\n\t177,\n\t177,\n\t228,\n\t184,\n\t156,\n\t230,\n\t131,\n\t133,\n\t230,\n\t132,\n\t159,\n\t231,\n\t137,\n\t185,\n\t230,\n\t174,\n\t138,\n\t229,\n\t136,\n\t134,\n\t233,\n\t161,\n\t158,\n\t230,\n\t144,\n\t156,\n\t229,\n\t176,\n\t139,\n\t229,\n\t177,\n\t158,\n\t228,\n\t186,\n\t142,\n\t233,\n\t151,\n\t168,\n\t230,\n\t136,\n\t183,\n\t232,\n\t180,\n\t162,\n\t229,\n\t138,\n\t161,\n\t229,\n\t163,\n\t176,\n\t233,\n\t159,\n\t179,\n\t229,\n\t143,\n\t138,\n\t229,\n\t133,\n\t182,\n\t232,\n\t180,\n\t162,\n\t231,\n\t187,\n\t143,\n\t229,\n\t157,\n\t154,\n\t230,\n\t140,\n\t129,\n\t229,\n\t185,\n\t178,\n\t233,\n\t131,\n\t168,\n\t230,\n\t136,\n\t144,\n\t231,\n\t171,\n\t139,\n\t229,\n\t136,\n\t169,\n\t231,\n\t155,\n\t138,\n\t232,\n\t128,\n\t131,\n\t232,\n\t153,\n\t145,\n\t230,\n\t136,\n\t144,\n\t233,\n\t131,\n\t189,\n\t229,\n\t140,\n\t133,\n\t232,\n\t163,\n\t133,\n\t231,\n\t148,\n\t168,\n\t230,\n\t136,\n\t182,\n\t230,\n\t175,\n\t148,\n\t232,\n\t181,\n\t155,\n\t230,\n\t150,\n\t135,\n\t230,\n\t152,\n\t142,\n\t230,\n\t139,\n\t155,\n\t229,\n\t149,\n\t134,\n\t229,\n\t174,\n\t140,\n\t230,\n\t149,\n\t180,\n\t231,\n\t156,\n\t159,\n\t230,\n\t152,\n\t175,\n\t231,\n\t156,\n\t188,\n\t231,\n\t157,\n\t155,\n\t228,\n\t188,\n\t153,\n\t228,\n\t188,\n\t180,\n\t229,\n\t168,\n\t129,\n\t230,\n\t156,\n\t155,\n\t233,\n\t162,\n\t134,\n\t229,\n\t159,\n\t159,\n\t229,\n\t141,\n\t171,\n\t231,\n\t148,\n\t159,\n\t228,\n\t188,\n\t152,\n\t230,\n\t131,\n\t160,\n\t232,\n\t171,\n\t150,\n\t229,\n\t163,\n\t135,\n\t229,\n\t133,\n\t172,\n\t229,\n\t133,\n\t177,\n\t232,\n\t137,\n\t175,\n\t229,\n\t165,\n\t189,\n\t229,\n\t133,\n\t133,\n\t229,\n\t136,\n\t134,\n\t231,\n\t172,\n\t166,\n\t229,\n\t144,\n\t136,\n\t233,\n\t153,\n\t132,\n\t228,\n\t187,\n\t182,\n\t231,\n\t137,\n\t185,\n\t231,\n\t130,\n\t185,\n\t228,\n\t184,\n\t141,\n\t229,\n\t143,\n\t175,\n\t232,\n\t139,\n\t177,\n\t230,\n\t150,\n\t135,\n\t232,\n\t181,\n\t132,\n\t228,\n\t186,\n\t167,\n\t230,\n\t160,\n\t185,\n\t230,\n\t156,\n\t172,\n\t230,\n\t152,\n\t142,\n\t230,\n\t152,\n\t190,\n\t229,\n\t175,\n\t134,\n\t231,\n\t162,\n\t188,\n\t229,\n\t133,\n\t172,\n\t228,\n\t188,\n\t151,\n\t230,\n\t176,\n\t145,\n\t230,\n\t151,\n\t143,\n\t230,\n\t155,\n\t180,\n\t229,\n\t138,\n\t160,\n\t228,\n\t186,\n\t171,\n\t229,\n\t143,\n\t151,\n\t229,\n\t144,\n\t140,\n\t229,\n\t173,\n\t166,\n\t229,\n\t144,\n\t175,\n\t229,\n\t138,\n\t168,\n\t233,\n\t128,\n\t130,\n\t229,\n\t144,\n\t136,\n\t229,\n\t142,\n\t159,\n\t230,\n\t157,\n\t165,\n\t233,\n\t151,\n\t174,\n\t231,\n\t173,\n\t148,\n\t230,\n\t156,\n\t172,\n\t230,\n\t150,\n\t135,\n\t231,\n\t190,\n\t142,\n\t233,\n\t163,\n\t159,\n\t231,\n\t187,\n\t191,\n\t232,\n\t137,\n\t178,\n\t231,\n\t168,\n\t179,\n\t229,\n\t174,\n\t154,\n\t231,\n\t187,\n\t136,\n\t228,\n\t186,\n\t142,\n\t231,\n\t148,\n\t159,\n\t231,\n\t137,\n\t169,\n\t228,\n\t190,\n\t155,\n\t230,\n\t177,\n\t130,\n\t230,\n\t144,\n\t156,\n\t231,\n\t139,\n\t144,\n\t229,\n\t138,\n\t155,\n\t233,\n\t135,\n\t143,\n\t228,\n\t184,\n\t165,\n\t233,\n\t135,\n\t141,\n\t230,\n\t176,\n\t184,\n\t232,\n\t191,\n\t156,\n\t229,\n\t134,\n\t153,\n\t231,\n\t156,\n\t159,\n\t230,\n\t156,\n\t137,\n\t233,\n\t153,\n\t144,\n\t231,\n\t171,\n\t158,\n\t228,\n\t186,\n\t137,\n\t229,\n\t175,\n\t185,\n\t232,\n\t177,\n\t161,\n\t232,\n\t180,\n\t185,\n\t231,\n\t148,\n\t168,\n\t228,\n\t184,\n\t141,\n\t229,\n\t165,\n\t189,\n\t231,\n\t187,\n\t157,\n\t229,\n\t175,\n\t185,\n\t229,\n\t141,\n\t129,\n\t229,\n\t136,\n\t134,\n\t228,\n\t191,\n\t131,\n\t232,\n\t191,\n\t155,\n\t231,\n\t130,\n\t185,\n\t232,\n\t175,\n\t132,\n\t229,\n\t189,\n\t177,\n\t233,\n\t159,\n\t179,\n\t228,\n\t188,\n\t152,\n\t229,\n\t138,\n\t191,\n\t228,\n\t184,\n\t141,\n\t229,\n\t176,\n\t145,\n\t230,\n\t172,\n\t163,\n\t232,\n\t181,\n\t143,\n\t229,\n\t185,\n\t182,\n\t228,\n\t184,\n\t148,\n\t230,\n\t156,\n\t137,\n\t231,\n\t130,\n\t185,\n\t230,\n\t150,\n\t185,\n\t229,\n\t144,\n\t145,\n\t229,\n\t133,\n\t168,\n\t230,\n\t150,\n\t176,\n\t228,\n\t191,\n\t161,\n\t231,\n\t148,\n\t168,\n\t232,\n\t174,\n\t190,\n\t230,\n\t150,\n\t189,\n\t229,\n\t189,\n\t162,\n\t232,\n\t177,\n\t161,\n\t232,\n\t181,\n\t132,\n\t230,\n\t160,\n\t188,\n\t231,\n\t170,\n\t129,\n\t231,\n\t160,\n\t180,\n\t233,\n\t154,\n\t143,\n\t231,\n\t157,\n\t128,\n\t233,\n\t135,\n\t141,\n\t229,\n\t164,\n\t167,\n\t228,\n\t186,\n\t142,\n\t230,\n\t152,\n\t175,\n\t230,\n\t175,\n\t149,\n\t228,\n\t184,\n\t154,\n\t230,\n\t153,\n\t186,\n\t232,\n\t131,\n\t189,\n\t229,\n\t140,\n\t150,\n\t229,\n\t183,\n\t165,\n\t229,\n\t174,\n\t140,\n\t231,\n\t190,\n\t142,\n\t229,\n\t149,\n\t134,\n\t229,\n\t159,\n\t142,\n\t231,\n\t187,\n\t159,\n\t228,\n\t184,\n\t128,\n\t229,\n\t135,\n\t186,\n\t231,\n\t137,\n\t136,\n\t230,\n\t137,\n\t147,\n\t233,\n\t128,\n\t160,\n\t231,\n\t148,\n\t162,\n\t229,\n\t147,\n\t129,\n\t230,\n\t166,\n\t130,\n\t229,\n\t134,\n\t181,\n\t231,\n\t148,\n\t168,\n\t228,\n\t186,\n\t142,\n\t228,\n\t191,\n\t157,\n\t231,\n\t149,\n\t153,\n\t229,\n\t155,\n\t160,\n\t231,\n\t180,\n\t160,\n\t228,\n\t184,\n\t173,\n\t229,\n\t156,\n\t139,\n\t229,\n\t173,\n\t152,\n\t229,\n\t130,\n\t168,\n\t232,\n\t180,\n\t180,\n\t229,\n\t155,\n\t190,\n\t230,\n\t156,\n\t128,\n\t230,\n\t132,\n\t155,\n\t233,\n\t149,\n\t191,\n\t230,\n\t156,\n\t159,\n\t229,\n\t143,\n\t163,\n\t228,\n\t187,\n\t183,\n\t231,\n\t144,\n\t134,\n\t232,\n\t180,\n\t162,\n\t229,\n\t159,\n\t186,\n\t229,\n\t156,\n\t176,\n\t229,\n\t174,\n\t137,\n\t230,\n\t142,\n\t146,\n\t230,\n\t173,\n\t166,\n\t230,\n\t177,\n\t137,\n\t233,\n\t135,\n\t140,\n\t233,\n\t157,\n\t162,\n\t229,\n\t136,\n\t155,\n\t229,\n\t187,\n\t186,\n\t229,\n\t164,\n\t169,\n\t231,\n\t169,\n\t186,\n\t233,\n\t166,\n\t150,\n\t229,\n\t133,\n\t136,\n\t229,\n\t174,\n\t140,\n\t229,\n\t150,\n\t132,\n\t233,\n\t169,\n\t177,\n\t229,\n\t138,\n\t168,\n\t228,\n\t184,\n\t139,\n\t233,\n\t157,\n\t162,\n\t228,\n\t184,\n\t141,\n\t229,\n\t134,\n\t141,\n\t232,\n\t175,\n\t154,\n\t228,\n\t191,\n\t161,\n\t230,\n\t132,\n\t143,\n\t228,\n\t185,\n\t137,\n\t233,\n\t152,\n\t179,\n\t229,\n\t133,\n\t137,\n\t232,\n\t139,\n\t177,\n\t229,\n\t155,\n\t189,\n\t230,\n\t188,\n\t130,\n\t228,\n\t186,\n\t174,\n\t229,\n\t134,\n\t155,\n\t228,\n\t186,\n\t139,\n\t231,\n\t142,\n\t169,\n\t229,\n\t174,\n\t182,\n\t231,\n\t190,\n\t164,\n\t228,\n\t188,\n\t151,\n\t229,\n\t134,\n\t156,\n\t230,\n\t176,\n\t145,\n\t229,\n\t141,\n\t179,\n\t229,\n\t143,\n\t175,\n\t229,\n\t144,\n\t141,\n\t231,\n\t168,\n\t177,\n\t229,\n\t174,\n\t182,\n\t229,\n\t133,\n\t183,\n\t229,\n\t138,\n\t168,\n\t231,\n\t148,\n\t187,\n\t230,\n\t131,\n\t179,\n\t229,\n\t136,\n\t176,\n\t230,\n\t179,\n\t168,\n\t230,\n\t152,\n\t142,\n\t229,\n\t176,\n\t143,\n\t229,\n\t173,\n\t166,\n\t230,\n\t128,\n\t167,\n\t232,\n\t131,\n\t189,\n\t232,\n\t128,\n\t131,\n\t231,\n\t160,\n\t148,\n\t231,\n\t161,\n\t172,\n\t228,\n\t187,\n\t182,\n\t232,\n\t167,\n\t130,\n\t231,\n\t156,\n\t139,\n\t230,\n\t184,\n\t133,\n\t230,\n\t165,\n\t154,\n\t230,\n\t144,\n\t158,\n\t231,\n\t172,\n\t145,\n\t233,\n\t166,\n\t150,\n\t233,\n\t160,\n\t129,\n\t233,\n\t187,\n\t132,\n\t233,\n\t135,\n\t145,\n\t233,\n\t128,\n\t130,\n\t231,\n\t148,\n\t168,\n\t230,\n\t177,\n\t159,\n\t232,\n\t139,\n\t143,\n\t231,\n\t156,\n\t159,\n\t229,\n\t174,\n\t158,\n\t228,\n\t184,\n\t187,\n\t231,\n\t174,\n\t161,\n\t233,\n\t152,\n\t182,\n\t230,\n\t174,\n\t181,\n\t232,\n\t168,\n\t187,\n\t229,\n\t134,\n\t138,\n\t231,\n\t191,\n\t187,\n\t232,\n\t175,\n\t145,\n\t230,\n\t157,\n\t131,\n\t229,\n\t136,\n\t169,\n\t229,\n\t129,\n\t154,\n\t229,\n\t165,\n\t189,\n\t228,\n\t188,\n\t188,\n\t228,\n\t185,\n\t142,\n\t233,\n\t128,\n\t154,\n\t232,\n\t174,\n\t175,\n\t230,\n\t150,\n\t189,\n\t229,\n\t183,\n\t165,\n\t231,\n\t139,\n\t128,\n\t230,\n\t133,\n\t139,\n\t228,\n\t185,\n\t159,\n\t232,\n\t174,\n\t184,\n\t231,\n\t142,\n\t175,\n\t228,\n\t191,\n\t157,\n\t229,\n\t159,\n\t185,\n\t229,\n\t133,\n\t187,\n\t230,\n\t166,\n\t130,\n\t229,\n\t191,\n\t181,\n\t229,\n\t164,\n\t167,\n\t229,\n\t158,\n\t139,\n\t230,\n\t156,\n\t186,\n\t231,\n\t165,\n\t168,\n\t231,\n\t144,\n\t134,\n\t232,\n\t167,\n\t163,\n\t229,\n\t140,\n\t191,\n\t229,\n\t144,\n\t141,\n\t99,\n\t117,\n\t97,\n\t110,\n\t100,\n\t111,\n\t101,\n\t110,\n\t118,\n\t105,\n\t97,\n\t114,\n\t109,\n\t97,\n\t100,\n\t114,\n\t105,\n\t100,\n\t98,\n\t117,\n\t115,\n\t99,\n\t97,\n\t114,\n\t105,\n\t110,\n\t105,\n\t99,\n\t105,\n\t111,\n\t116,\n\t105,\n\t101,\n\t109,\n\t112,\n\t111,\n\t112,\n\t111,\n\t114,\n\t113,\n\t117,\n\t101,\n\t99,\n\t117,\n\t101,\n\t110,\n\t116,\n\t97,\n\t101,\n\t115,\n\t116,\n\t97,\n\t100,\n\t111,\n\t112,\n\t117,\n\t101,\n\t100,\n\t101,\n\t110,\n\t106,\n\t117,\n\t101,\n\t103,\n\t111,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t101,\n\t115,\n\t116,\n\t195,\n\t161,\n\t110,\n\t110,\n\t111,\n\t109,\n\t98,\n\t114,\n\t101,\n\t116,\n\t105,\n\t101,\n\t110,\n\t101,\n\t110,\n\t112,\n\t101,\n\t114,\n\t102,\n\t105,\n\t108,\n\t109,\n\t97,\n\t110,\n\t101,\n\t114,\n\t97,\n\t97,\n\t109,\n\t105,\n\t103,\n\t111,\n\t115,\n\t99,\n\t105,\n\t117,\n\t100,\n\t97,\n\t100,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t111,\n\t97,\n\t117,\n\t110,\n\t113,\n\t117,\n\t101,\n\t112,\n\t117,\n\t101,\n\t100,\n\t101,\n\t115,\n\t100,\n\t101,\n\t110,\n\t116,\n\t114,\n\t111,\n\t112,\n\t114,\n\t105,\n\t109,\n\t101,\n\t114,\n\t112,\n\t114,\n\t101,\n\t99,\n\t105,\n\t111,\n\t115,\n\t101,\n\t103,\n\t195,\n\t186,\n\t110,\n\t98,\n\t117,\n\t101,\n\t110,\n\t111,\n\t115,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t114,\n\t112,\n\t117,\n\t110,\n\t116,\n\t111,\n\t115,\n\t115,\n\t101,\n\t109,\n\t97,\n\t110,\n\t97,\n\t104,\n\t97,\n\t98,\n\t195,\n\t173,\n\t97,\n\t97,\n\t103,\n\t111,\n\t115,\n\t116,\n\t111,\n\t110,\n\t117,\n\t101,\n\t118,\n\t111,\n\t115,\n\t117,\n\t110,\n\t105,\n\t100,\n\t111,\n\t115,\n\t99,\n\t97,\n\t114,\n\t108,\n\t111,\n\t115,\n\t101,\n\t113,\n\t117,\n\t105,\n\t112,\n\t111,\n\t110,\n\t105,\n\t195,\n\t177,\n\t111,\n\t115,\n\t109,\n\t117,\n\t99,\n\t104,\n\t111,\n\t115,\n\t97,\n\t108,\n\t103,\n\t117,\n\t110,\n\t97,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t111,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t110,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t114,\n\t97,\n\t114,\n\t114,\n\t105,\n\t98,\n\t97,\n\t109,\n\t97,\n\t114,\n\t195,\n\t173,\n\t97,\n\t104,\n\t111,\n\t109,\n\t98,\n\t114,\n\t101,\n\t101,\n\t109,\n\t112,\n\t108,\n\t101,\n\t111,\n\t118,\n\t101,\n\t114,\n\t100,\n\t97,\n\t100,\n\t99,\n\t97,\n\t109,\n\t98,\n\t105,\n\t111,\n\t109,\n\t117,\n\t99,\n\t104,\n\t97,\n\t115,\n\t102,\n\t117,\n\t101,\n\t114,\n\t111,\n\t110,\n\t112,\n\t97,\n\t115,\n\t97,\n\t100,\n\t111,\n\t108,\n\t195,\n\t173,\n\t110,\n\t101,\n\t97,\n\t112,\n\t97,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t117,\n\t101,\n\t118,\n\t97,\n\t115,\n\t99,\n\t117,\n\t114,\n\t115,\n\t111,\n\t115,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t97,\n\t113,\n\t117,\n\t105,\n\t101,\n\t114,\n\t111,\n\t108,\n\t105,\n\t98,\n\t114,\n\t111,\n\t115,\n\t99,\n\t117,\n\t97,\n\t110,\n\t116,\n\t111,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t111,\n\t109,\n\t105,\n\t103,\n\t117,\n\t101,\n\t108,\n\t118,\n\t97,\n\t114,\n\t105,\n\t111,\n\t115,\n\t99,\n\t117,\n\t97,\n\t116,\n\t114,\n\t111,\n\t116,\n\t105,\n\t101,\n\t110,\n\t101,\n\t115,\n\t103,\n\t114,\n\t117,\n\t112,\n\t111,\n\t115,\n\t115,\n\t101,\n\t114,\n\t195,\n\t161,\n\t110,\n\t101,\n\t117,\n\t114,\n\t111,\n\t112,\n\t97,\n\t109,\n\t101,\n\t100,\n\t105,\n\t111,\n\t115,\n\t102,\n\t114,\n\t101,\n\t110,\n\t116,\n\t101,\n\t97,\n\t99,\n\t101,\n\t114,\n\t99,\n\t97,\n\t100,\n\t101,\n\t109,\n\t195,\n\t161,\n\t115,\n\t111,\n\t102,\n\t101,\n\t114,\n\t116,\n\t97,\n\t99,\n\t111,\n\t99,\n\t104,\n\t101,\n\t115,\n\t109,\n\t111,\n\t100,\n\t101,\n\t108,\n\t111,\n\t105,\n\t116,\n\t97,\n\t108,\n\t105,\n\t97,\n\t108,\n\t101,\n\t116,\n\t114,\n\t97,\n\t115,\n\t97,\n\t108,\n\t103,\n\t195,\n\t186,\n\t110,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t97,\n\t99,\n\t117,\n\t97,\n\t108,\n\t101,\n\t115,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t101,\n\t99,\n\t117,\n\t101,\n\t114,\n\t112,\n\t111,\n\t115,\n\t105,\n\t101,\n\t110,\n\t100,\n\t111,\n\t112,\n\t114,\n\t101,\n\t110,\n\t115,\n\t97,\n\t108,\n\t108,\n\t101,\n\t103,\n\t97,\n\t114,\n\t118,\n\t105,\n\t97,\n\t106,\n\t101,\n\t115,\n\t100,\n\t105,\n\t110,\n\t101,\n\t114,\n\t111,\n\t109,\n\t117,\n\t114,\n\t99,\n\t105,\n\t97,\n\t112,\n\t111,\n\t100,\n\t114,\n\t195,\n\t161,\n\t112,\n\t117,\n\t101,\n\t115,\n\t116,\n\t111,\n\t100,\n\t105,\n\t97,\n\t114,\n\t105,\n\t111,\n\t112,\n\t117,\n\t101,\n\t98,\n\t108,\n\t111,\n\t113,\n\t117,\n\t105,\n\t101,\n\t114,\n\t101,\n\t109,\n\t97,\n\t110,\n\t117,\n\t101,\n\t108,\n\t112,\n\t114,\n\t111,\n\t112,\n\t105,\n\t111,\n\t99,\n\t114,\n\t105,\n\t115,\n\t105,\n\t115,\n\t99,\n\t105,\n\t101,\n\t114,\n\t116,\n\t111,\n\t115,\n\t101,\n\t103,\n\t117,\n\t114,\n\t111,\n\t109,\n\t117,\n\t101,\n\t114,\n\t116,\n\t101,\n\t102,\n\t117,\n\t101,\n\t110,\n\t116,\n\t101,\n\t99,\n\t101,\n\t114,\n\t114,\n\t97,\n\t114,\n\t103,\n\t114,\n\t97,\n\t110,\n\t100,\n\t101,\n\t101,\n\t102,\n\t101,\n\t99,\n\t116,\n\t111,\n\t112,\n\t97,\n\t114,\n\t116,\n\t101,\n\t115,\n\t109,\n\t101,\n\t100,\n\t105,\n\t100,\n\t97,\n\t112,\n\t114,\n\t111,\n\t112,\n\t105,\n\t97,\n\t111,\n\t102,\n\t114,\n\t101,\n\t99,\n\t101,\n\t116,\n\t105,\n\t101,\n\t114,\n\t114,\n\t97,\n\t101,\n\t45,\n\t109,\n\t97,\n\t105,\n\t108,\n\t118,\n\t97,\n\t114,\n\t105,\n\t97,\n\t115,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t115,\n\t102,\n\t117,\n\t116,\n\t117,\n\t114,\n\t111,\n\t111,\n\t98,\n\t106,\n\t101,\n\t116,\n\t111,\n\t115,\n\t101,\n\t103,\n\t117,\n\t105,\n\t114,\n\t114,\n\t105,\n\t101,\n\t115,\n\t103,\n\t111,\n\t110,\n\t111,\n\t114,\n\t109,\n\t97,\n\t115,\n\t109,\n\t105,\n\t115,\n\t109,\n\t111,\n\t115,\n\t195,\n\t186,\n\t110,\n\t105,\n\t99,\n\t111,\n\t99,\n\t97,\n\t109,\n\t105,\n\t110,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t115,\n\t114,\n\t97,\n\t122,\n\t195,\n\t179,\n\t110,\n\t100,\n\t101,\n\t98,\n\t105,\n\t100,\n\t111,\n\t112,\n\t114,\n\t117,\n\t101,\n\t98,\n\t97,\n\t116,\n\t111,\n\t108,\n\t101,\n\t100,\n\t111,\n\t116,\n\t101,\n\t110,\n\t195,\n\t173,\n\t97,\n\t106,\n\t101,\n\t115,\n\t195,\n\t186,\n\t115,\n\t101,\n\t115,\n\t112,\n\t101,\n\t114,\n\t111,\n\t99,\n\t111,\n\t99,\n\t105,\n\t110,\n\t97,\n\t111,\n\t114,\n\t105,\n\t103,\n\t101,\n\t110,\n\t116,\n\t105,\n\t101,\n\t110,\n\t100,\n\t97,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t111,\n\t99,\n\t195,\n\t161,\n\t100,\n\t105,\n\t122,\n\t104,\n\t97,\n\t98,\n\t108,\n\t97,\n\t114,\n\t115,\n\t101,\n\t114,\n\t195,\n\t173,\n\t97,\n\t108,\n\t97,\n\t116,\n\t105,\n\t110,\n\t97,\n\t102,\n\t117,\n\t101,\n\t114,\n\t122,\n\t97,\n\t101,\n\t115,\n\t116,\n\t105,\n\t108,\n\t111,\n\t103,\n\t117,\n\t101,\n\t114,\n\t114,\n\t97,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t114,\n\t195,\n\t169,\n\t120,\n\t105,\n\t116,\n\t111,\n\t108,\n\t195,\n\t179,\n\t112,\n\t101,\n\t122,\n\t97,\n\t103,\n\t101,\n\t110,\n\t100,\n\t97,\n\t118,\n\t195,\n\t173,\n\t100,\n\t101,\n\t111,\n\t101,\n\t118,\n\t105,\n\t116,\n\t97,\n\t114,\n\t112,\n\t97,\n\t103,\n\t105,\n\t110,\n\t97,\n\t109,\n\t101,\n\t116,\n\t114,\n\t111,\n\t115,\n\t106,\n\t97,\n\t118,\n\t105,\n\t101,\n\t114,\n\t112,\n\t97,\n\t100,\n\t114,\n\t101,\n\t115,\n\t102,\n\t195,\n\t161,\n\t99,\n\t105,\n\t108,\n\t99,\n\t97,\n\t98,\n\t101,\n\t122,\n\t97,\n\t195,\n\t161,\n\t114,\n\t101,\n\t97,\n\t115,\n\t115,\n\t97,\n\t108,\n\t105,\n\t100,\n\t97,\n\t101,\n\t110,\n\t118,\n\t195,\n\t173,\n\t111,\n\t106,\n\t97,\n\t112,\n\t195,\n\t179,\n\t110,\n\t97,\n\t98,\n\t117,\n\t115,\n\t111,\n\t115,\n\t98,\n\t105,\n\t101,\n\t110,\n\t101,\n\t115,\n\t116,\n\t101,\n\t120,\n\t116,\n\t111,\n\t115,\n\t108,\n\t108,\n\t101,\n\t118,\n\t97,\n\t114,\n\t112,\n\t117,\n\t101,\n\t100,\n\t97,\n\t110,\n\t102,\n\t117,\n\t101,\n\t114,\n\t116,\n\t101,\n\t99,\n\t111,\n\t109,\n\t195,\n\t186,\n\t110,\n\t99,\n\t108,\n\t97,\n\t115,\n\t101,\n\t115,\n\t104,\n\t117,\n\t109,\n\t97,\n\t110,\n\t111,\n\t116,\n\t101,\n\t110,\n\t105,\n\t100,\n\t111,\n\t98,\n\t105,\n\t108,\n\t98,\n\t97,\n\t111,\n\t117,\n\t110,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t116,\n\t195,\n\t161,\n\t115,\n\t101,\n\t100,\n\t105,\n\t116,\n\t97,\n\t114,\n\t99,\n\t114,\n\t101,\n\t97,\n\t100,\n\t111,\n\t208,\n\t180,\n\t208,\n\t187,\n\t209,\n\t143,\n\t209,\n\t135,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t178,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t181,\n\t209,\n\t137,\n\t208,\n\t181,\n\t209,\n\t131,\n\t208,\n\t182,\n\t208,\n\t181,\n\t208,\n\t154,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t177,\n\t208,\n\t181,\n\t208,\n\t183,\n\t208,\n\t177,\n\t209,\n\t139,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t146,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t173,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t189,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t187,\n\t208,\n\t181,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t179,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t148,\n\t208,\n\t187,\n\t209,\n\t143,\n\t208,\n\t159,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t133,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t186,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t178,\n\t208,\n\t190,\n\t209,\n\t130,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t161,\n\t208,\n\t168,\n\t208,\n\t144,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t143,\n\t208,\n\t167,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t131,\n\t208,\n\t162,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t180,\n\t208,\n\t178,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t188,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t184,\n\t209,\n\t141,\n\t209,\n\t130,\n\t209,\n\t131,\n\t208,\n\t146,\n\t208,\n\t176,\n\t208,\n\t188,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t133,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t209,\n\t130,\n\t209,\n\t131,\n\t209,\n\t130,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t180,\n\t208,\n\t180,\n\t208,\n\t189,\n\t209,\n\t143,\n\t208,\n\t146,\n\t208,\n\t190,\n\t209,\n\t130,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t146,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t188,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t188,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t130,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t177,\n\t208,\n\t158,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t184,\n\t209,\n\t128,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t181,\n\t208,\n\t158,\n\t208,\n\t158,\n\t208,\n\t158,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t134,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t158,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t180,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t180,\n\t208,\n\t178,\n\t208,\n\t181,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t131,\n\t208,\n\t180,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t148,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t173,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t190,\n\t106,\n\t97,\n\t103,\n\t114,\n\t97,\n\t110,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t165,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t165,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t152,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t181,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t181,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t147,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t128,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t137,\n\t216,\n\t165,\n\t217,\n\t132,\n\t217,\n\t137,\n\t217,\n\t135,\n\t216,\n\t176,\n\t216,\n\t167,\n\t216,\n\t162,\n\t216,\n\t174,\n\t216,\n\t177,\n\t216,\n\t185,\n\t216,\n\t175,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t137,\n\t217,\n\t135,\n\t216,\n\t176,\n\t217,\n\t135,\n\t216,\n\t181,\n\t217,\n\t136,\n\t216,\n\t177,\n\t216,\n\t186,\n\t217,\n\t138,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t134,\n\t217,\n\t136,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t168,\n\t217,\n\t138,\n\t217,\n\t134,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t182,\n\t216,\n\t176,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t135,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t138,\n\t217,\n\t136,\n\t217,\n\t133,\n\t217,\n\t130,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t134,\n\t216,\n\t173,\n\t216,\n\t170,\n\t217,\n\t137,\n\t217,\n\t130,\n\t216,\n\t168,\n\t217,\n\t132,\n\t217,\n\t136,\n\t216,\n\t173,\n\t216,\n\t169,\n\t216,\n\t167,\n\t216,\n\t174,\n\t216,\n\t177,\n\t217,\n\t129,\n\t217,\n\t130,\n\t216,\n\t183,\n\t216,\n\t185,\n\t216,\n\t168,\n\t216,\n\t175,\n\t216,\n\t177,\n\t217,\n\t131,\n\t217,\n\t134,\n\t216,\n\t165,\n\t216,\n\t176,\n\t216,\n\t167,\n\t217,\n\t131,\n\t217,\n\t133,\n\t216,\n\t167,\n\t216,\n\t167,\n\t216,\n\t173,\n\t216,\n\t175,\n\t216,\n\t165,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t129,\n\t217,\n\t138,\n\t217,\n\t135,\n\t216,\n\t168,\n\t216,\n\t185,\n\t216,\n\t182,\n\t217,\n\t131,\n\t217,\n\t138,\n\t217,\n\t129,\n\t216,\n\t168,\n\t216,\n\t173,\n\t216,\n\t171,\n\t217,\n\t136,\n\t217,\n\t133,\n\t217,\n\t134,\n\t217,\n\t136,\n\t217,\n\t135,\n\t217,\n\t136,\n\t216,\n\t163,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t172,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t179,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t185,\n\t217,\n\t134,\n\t216,\n\t175,\n\t217,\n\t132,\n\t217,\n\t138,\n\t216,\n\t179,\n\t216,\n\t185,\n\t216,\n\t168,\n\t216,\n\t177,\n\t216,\n\t181,\n\t217,\n\t132,\n\t217,\n\t137,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t176,\n\t216,\n\t168,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t163,\n\t217,\n\t134,\n\t217,\n\t135,\n\t217,\n\t133,\n\t216,\n\t171,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t173,\n\t217,\n\t138,\n\t216,\n\t171,\n\t217,\n\t133,\n\t216,\n\t181,\n\t216,\n\t177,\n\t216,\n\t180,\n\t216,\n\t177,\n\t216,\n\t173,\n\t216,\n\t173,\n\t217,\n\t136,\n\t217,\n\t132,\n\t217,\n\t136,\n\t217,\n\t129,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t176,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t177,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t129,\n\t216,\n\t163,\n\t216,\n\t168,\n\t217,\n\t136,\n\t216,\n\t174,\n\t216,\n\t167,\n\t216,\n\t181,\n\t216,\n\t163,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t134,\n\t217,\n\t135,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t138,\n\t216,\n\t185,\n\t216,\n\t182,\n\t217,\n\t136,\n\t217,\n\t136,\n\t217,\n\t130,\n\t216,\n\t175,\n\t216,\n\t167,\n\t216,\n\t168,\n\t217,\n\t134,\n\t216,\n\t174,\n\t217,\n\t138,\n\t216,\n\t177,\n\t216,\n\t168,\n\t217,\n\t134,\n\t216,\n\t170,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t216,\n\t161,\n\t217,\n\t136,\n\t217,\n\t135,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t168,\n\t217,\n\t136,\n\t217,\n\t130,\n\t216,\n\t181,\n\t216,\n\t181,\n\t217,\n\t136,\n\t217,\n\t133,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t130,\n\t217,\n\t133,\n\t216,\n\t163,\n\t216,\n\t173,\n\t216,\n\t175,\n\t217,\n\t134,\n\t216,\n\t173,\n\t217,\n\t134,\n\t216,\n\t185,\n\t216,\n\t175,\n\t217,\n\t133,\n\t216,\n\t177,\n\t216,\n\t163,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t173,\n\t216,\n\t169,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t168,\n\t216,\n\t175,\n\t217,\n\t136,\n\t217,\n\t134,\n\t217,\n\t138,\n\t216,\n\t172,\n\t216,\n\t168,\n\t217,\n\t133,\n\t217,\n\t134,\n\t217,\n\t135,\n\t216,\n\t170,\n\t216,\n\t173,\n\t216,\n\t170,\n\t216,\n\t172,\n\t217,\n\t135,\n\t216,\n\t169,\n\t216,\n\t179,\n\t217,\n\t134,\n\t216,\n\t169,\n\t217,\n\t138,\n\t216,\n\t170,\n\t217,\n\t133,\n\t217,\n\t131,\n\t216,\n\t177,\n\t216,\n\t169,\n\t216,\n\t186,\n\t216,\n\t178,\n\t216,\n\t169,\n\t217,\n\t134,\n\t217,\n\t129,\n\t216,\n\t179,\n\t216,\n\t168,\n\t217,\n\t138,\n\t216,\n\t170,\n\t217,\n\t132,\n\t217,\n\t132,\n\t217,\n\t135,\n\t217,\n\t132,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t170,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t130,\n\t217,\n\t132,\n\t216,\n\t168,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t167,\n\t216,\n\t185,\n\t217,\n\t134,\n\t217,\n\t135,\n\t216,\n\t163,\n\t217,\n\t136,\n\t217,\n\t132,\n\t216,\n\t180,\n\t217,\n\t138,\n\t216,\n\t161,\n\t217,\n\t134,\n\t217,\n\t136,\n\t216,\n\t177,\n\t216,\n\t163,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t129,\n\t217,\n\t138,\n\t217,\n\t131,\n\t216,\n\t168,\n\t217,\n\t131,\n\t217,\n\t132,\n\t216,\n\t176,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t177,\n\t216,\n\t170,\n\t216,\n\t168,\n\t216,\n\t168,\n\t216,\n\t163,\n\t217,\n\t134,\n\t217,\n\t135,\n\t217,\n\t133,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t134,\n\t217,\n\t131,\n\t216,\n\t168,\n\t217,\n\t138,\n\t216,\n\t185,\n\t217,\n\t129,\n\t217,\n\t130,\n\t216,\n\t175,\n\t216,\n\t173,\n\t216,\n\t179,\n\t217,\n\t134,\n\t217,\n\t132,\n\t217,\n\t135,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t163,\n\t217,\n\t135,\n\t217,\n\t132,\n\t216,\n\t180,\n\t217,\n\t135,\n\t216,\n\t177,\n\t217,\n\t130,\n\t216,\n\t183,\n\t216,\n\t177,\n\t216,\n\t183,\n\t217,\n\t132,\n\t216,\n\t168,\n\t112,\n\t114,\n\t111,\n\t102,\n\t105,\n\t108,\n\t101,\n\t115,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t100,\n\t101,\n\t102,\n\t97,\n\t117,\n\t108,\n\t116,\n\t104,\n\t105,\n\t109,\n\t115,\n\t101,\n\t108,\n\t102,\n\t100,\n\t101,\n\t116,\n\t97,\n\t105,\n\t108,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t101,\n\t100,\n\t109,\n\t101,\n\t115,\n\t115,\n\t97,\n\t103,\n\t101,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t102,\n\t97,\n\t115,\n\t104,\n\t105,\n\t111,\n\t110,\n\t60,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t121,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t101,\n\t115,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t115,\n\t114,\n\t117,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t119,\n\t114,\n\t105,\n\t116,\n\t105,\n\t110,\n\t103,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t115,\n\t118,\n\t105,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t119,\n\t101,\n\t108,\n\t99,\n\t111,\n\t109,\n\t101,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t117,\n\t110,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t110,\n\t101,\n\t116,\n\t119,\n\t111,\n\t114,\n\t107,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t121,\n\t100,\n\t121,\n\t110,\n\t97,\n\t109,\n\t105,\n\t99,\n\t98,\n\t114,\n\t111,\n\t119,\n\t115,\n\t101,\n\t114,\n\t112,\n\t114,\n\t105,\n\t118,\n\t97,\n\t99,\n\t121,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t83,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t114,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t114,\n\t101,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t119,\n\t101,\n\t98,\n\t115,\n\t105,\n\t116,\n\t101,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t102,\n\t114,\n\t105,\n\t101,\n\t110,\n\t100,\n\t115,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t119,\n\t111,\n\t114,\n\t107,\n\t105,\n\t110,\n\t103,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t109,\n\t105,\n\t108,\n\t108,\n\t105,\n\t111,\n\t110,\n\t99,\n\t104,\n\t97,\n\t110,\n\t110,\n\t101,\n\t108,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t46,\n\t97,\n\t100,\n\t100,\n\t114,\n\t101,\n\t115,\n\t115,\n\t118,\n\t105,\n\t115,\n\t105,\n\t116,\n\t101,\n\t100,\n\t119,\n\t101,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t99,\n\t116,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t101,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t102,\n\t111,\n\t114,\n\t119,\n\t97,\n\t114,\n\t100,\n\t121,\n\t111,\n\t117,\n\t32,\n\t99,\n\t97,\n\t110,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t101,\n\t100,\n\t115,\n\t117,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t97,\n\t114,\n\t99,\n\t104,\n\t105,\n\t118,\n\t101,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t97,\n\t100,\n\t105,\n\t110,\n\t103,\n\t108,\n\t105,\n\t98,\n\t114,\n\t97,\n\t114,\n\t121,\n\t108,\n\t105,\n\t109,\n\t105,\n\t116,\n\t101,\n\t100,\n\t109,\n\t97,\n\t110,\n\t97,\n\t103,\n\t101,\n\t114,\n\t102,\n\t117,\n\t114,\n\t116,\n\t104,\n\t101,\n\t114,\n\t115,\n\t117,\n\t109,\n\t109,\n\t97,\n\t114,\n\t121,\n\t109,\n\t97,\n\t99,\n\t104,\n\t105,\n\t110,\n\t101,\n\t109,\n\t105,\n\t110,\n\t117,\n\t116,\n\t101,\n\t115,\n\t112,\n\t114,\n\t105,\n\t118,\n\t97,\n\t116,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t120,\n\t116,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t115,\n\t111,\n\t99,\n\t105,\n\t101,\n\t116,\n\t121,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t119,\n\t114,\n\t105,\n\t116,\n\t116,\n\t101,\n\t110,\n\t101,\n\t110,\n\t97,\n\t98,\n\t108,\n\t101,\n\t100,\n\t116,\n\t114,\n\t105,\n\t103,\n\t103,\n\t101,\n\t114,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t115,\n\t108,\n\t111,\n\t97,\n\t100,\n\t105,\n\t110,\n\t103,\n\t101,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t112,\n\t97,\n\t114,\n\t116,\n\t110,\n\t101,\n\t114,\n\t102,\n\t105,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t112,\n\t101,\n\t114,\n\t102,\n\t101,\n\t99,\n\t116,\n\t109,\n\t101,\n\t97,\n\t110,\n\t105,\n\t110,\n\t103,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t115,\n\t107,\n\t101,\n\t101,\n\t112,\n\t105,\n\t110,\n\t103,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t101,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t44,\n\t106,\n\t111,\n\t117,\n\t114,\n\t110,\n\t97,\n\t108,\n\t112,\n\t114,\n\t111,\n\t106,\n\t101,\n\t99,\n\t116,\n\t115,\n\t117,\n\t114,\n\t102,\n\t97,\n\t99,\n\t101,\n\t115,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t101,\n\t120,\n\t112,\n\t105,\n\t114,\n\t101,\n\t115,\n\t114,\n\t101,\n\t118,\n\t105,\n\t101,\n\t119,\n\t115,\n\t98,\n\t97,\n\t108,\n\t97,\n\t110,\n\t99,\n\t101,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t67,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t80,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t32,\n\t111,\n\t112,\n\t105,\n\t110,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t97,\n\t118,\n\t101,\n\t114,\n\t97,\n\t103,\n\t101,\n\t112,\n\t114,\n\t105,\n\t109,\n\t97,\n\t114,\n\t121,\n\t118,\n\t105,\n\t108,\n\t108,\n\t97,\n\t103,\n\t101,\n\t83,\n\t112,\n\t97,\n\t110,\n\t105,\n\t115,\n\t104,\n\t103,\n\t97,\n\t108,\n\t108,\n\t101,\n\t114,\n\t121,\n\t100,\n\t101,\n\t99,\n\t108,\n\t105,\n\t110,\n\t101,\n\t109,\n\t101,\n\t101,\n\t116,\n\t105,\n\t110,\n\t103,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t113,\n\t117,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t109,\n\t101,\n\t97,\n\t115,\n\t117,\n\t114,\n\t101,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t101,\n\t115,\n\t115,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t119,\n\t114,\n\t105,\n\t116,\n\t101,\n\t114,\n\t115,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t101,\n\t114,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t97,\n\t108,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t102,\n\t105,\n\t103,\n\t117,\n\t114,\n\t101,\n\t115,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t104,\n\t111,\n\t108,\n\t100,\n\t105,\n\t110,\n\t103,\n\t100,\n\t105,\n\t115,\n\t112,\n\t117,\n\t116,\n\t101,\n\t101,\n\t97,\n\t114,\n\t108,\n\t105,\n\t101,\n\t114,\n\t101,\n\t120,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t100,\n\t105,\n\t103,\n\t105,\n\t116,\n\t97,\n\t108,\n\t112,\n\t105,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t65,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t109,\n\t97,\n\t114,\n\t114,\n\t105,\n\t101,\n\t100,\n\t116,\n\t114,\n\t97,\n\t102,\n\t102,\n\t105,\n\t99,\n\t108,\n\t101,\n\t97,\n\t100,\n\t105,\n\t110,\n\t103,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t100,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t108,\n\t118,\n\t105,\n\t99,\n\t116,\n\t111,\n\t114,\n\t121,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t115,\n\t47,\n\t114,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t115,\n\t115,\n\t116,\n\t117,\n\t100,\n\t105,\n\t101,\n\t115,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t108,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t109,\n\t117,\n\t115,\n\t116,\n\t32,\n\t98,\n\t101,\n\t115,\n\t99,\n\t104,\n\t111,\n\t111,\n\t108,\n\t115,\n\t86,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t117,\n\t115,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t101,\n\t112,\n\t105,\n\t115,\n\t111,\n\t100,\n\t101,\n\t112,\n\t108,\n\t97,\n\t121,\n\t105,\n\t110,\n\t103,\n\t103,\n\t114,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t111,\n\t98,\n\t118,\n\t105,\n\t111,\n\t117,\n\t115,\n\t111,\n\t118,\n\t101,\n\t114,\n\t108,\n\t97,\n\t121,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t60,\n\t47,\n\t117,\n\t108,\n\t62,\n\t13,\n\t10,\n\t119,\n\t114,\n\t97,\n\t112,\n\t112,\n\t101,\n\t114,\n\t97,\n\t108,\n\t114,\n\t101,\n\t97,\n\t100,\n\t121,\n\t99,\n\t101,\n\t114,\n\t116,\n\t97,\n\t105,\n\t110,\n\t114,\n\t101,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t115,\n\t116,\n\t111,\n\t114,\n\t97,\n\t103,\n\t101,\n\t97,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t100,\n\t101,\n\t115,\n\t107,\n\t116,\n\t111,\n\t112,\n\t111,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t100,\n\t112,\n\t97,\n\t116,\n\t116,\n\t101,\n\t114,\n\t110,\n\t117,\n\t110,\n\t117,\n\t115,\n\t117,\n\t97,\n\t108,\n\t68,\n\t105,\n\t103,\n\t105,\n\t116,\n\t97,\n\t108,\n\t99,\n\t97,\n\t112,\n\t105,\n\t116,\n\t97,\n\t108,\n\t87,\n\t101,\n\t98,\n\t115,\n\t105,\n\t116,\n\t101,\n\t102,\n\t97,\n\t105,\n\t108,\n\t117,\n\t114,\n\t101,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t114,\n\t101,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t65,\n\t110,\n\t100,\n\t114,\n\t111,\n\t105,\n\t100,\n\t100,\n\t101,\n\t99,\n\t97,\n\t100,\n\t101,\n\t115,\n\t114,\n\t101,\n\t103,\n\t117,\n\t108,\n\t97,\n\t114,\n\t32,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t32,\n\t97,\n\t110,\n\t105,\n\t109,\n\t97,\n\t108,\n\t115,\n\t114,\n\t101,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t65,\n\t117,\n\t116,\n\t111,\n\t109,\n\t97,\n\t116,\n\t103,\n\t101,\n\t116,\n\t116,\n\t105,\n\t110,\n\t103,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t115,\n\t110,\n\t111,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t80,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t99,\n\t97,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t108,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t115,\n\t99,\n\t97,\n\t112,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t108,\n\t105,\n\t99,\n\t101,\n\t110,\n\t115,\n\t101,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t115,\n\t69,\n\t110,\n\t103,\n\t108,\n\t97,\n\t110,\n\t100,\n\t61,\n\t49,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t72,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t61,\n\t32,\n\t110,\n\t101,\n\t119,\n\t32,\n\t67,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t108,\n\t117,\n\t112,\n\t100,\n\t97,\n\t116,\n\t101,\n\t100,\n\t83,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t78,\n\t101,\n\t116,\n\t119,\n\t111,\n\t114,\n\t107,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t110,\n\t116,\n\t119,\n\t97,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t67,\n\t111,\n\t108,\n\t108,\n\t101,\n\t103,\n\t101,\n\t116,\n\t111,\n\t111,\n\t108,\n\t98,\n\t97,\n\t114,\n\t114,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t115,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t68,\n\t101,\n\t117,\n\t116,\n\t115,\n\t99,\n\t104,\n\t102,\n\t105,\n\t110,\n\t97,\n\t110,\n\t99,\n\t101,\n\t119,\n\t111,\n\t114,\n\t107,\n\t101,\n\t114,\n\t115,\n\t113,\n\t117,\n\t105,\n\t99,\n\t107,\n\t108,\n\t121,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t101,\n\t120,\n\t97,\n\t99,\n\t116,\n\t108,\n\t121,\n\t115,\n\t101,\n\t116,\n\t116,\n\t105,\n\t110,\n\t103,\n\t100,\n\t105,\n\t115,\n\t101,\n\t97,\n\t115,\n\t101,\n\t83,\n\t111,\n\t99,\n\t105,\n\t101,\n\t116,\n\t121,\n\t119,\n\t101,\n\t97,\n\t112,\n\t111,\n\t110,\n\t115,\n\t101,\n\t120,\n\t104,\n\t105,\n\t98,\n\t105,\n\t116,\n\t38,\n\t108,\n\t116,\n\t59,\n\t33,\n\t45,\n\t45,\n\t67,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t101,\n\t115,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t101,\n\t100,\n\t111,\n\t117,\n\t116,\n\t108,\n\t105,\n\t110,\n\t101,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t107,\n\t115,\n\t100,\n\t101,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t40,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t112,\n\t117,\n\t114,\n\t112,\n\t111,\n\t115,\n\t101,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t77,\n\t111,\n\t98,\n\t105,\n\t108,\n\t101,\n\t32,\n\t107,\n\t105,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t115,\n\t104,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t73,\n\t116,\n\t97,\n\t108,\n\t105,\n\t97,\n\t110,\n\t100,\n\t114,\n\t111,\n\t112,\n\t112,\n\t101,\n\t100,\n\t104,\n\t101,\n\t97,\n\t118,\n\t105,\n\t108,\n\t121,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t115,\n\t45,\n\t49,\n\t39,\n\t93,\n\t41,\n\t59,\n\t10,\n\t99,\n\t111,\n\t110,\n\t102,\n\t105,\n\t114,\n\t109,\n\t67,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t97,\n\t100,\n\t118,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t104,\n\t97,\n\t114,\n\t105,\n\t110,\n\t103,\n\t111,\n\t112,\n\t101,\n\t110,\n\t105,\n\t110,\n\t103,\n\t100,\n\t114,\n\t97,\n\t119,\n\t105,\n\t110,\n\t103,\n\t98,\n\t105,\n\t108,\n\t108,\n\t105,\n\t111,\n\t110,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t71,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t121,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t60,\n\t47,\n\t102,\n\t111,\n\t114,\n\t109,\n\t62,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t119,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t83,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t99,\n\t97,\n\t116,\n\t97,\n\t108,\n\t111,\n\t103,\n\t65,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t115,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t115,\n\t116,\n\t117,\n\t110,\n\t105,\n\t102,\n\t111,\n\t114,\n\t109,\n\t106,\n\t111,\n\t117,\n\t114,\n\t110,\n\t101,\n\t121,\n\t115,\n\t105,\n\t100,\n\t101,\n\t98,\n\t97,\n\t114,\n\t67,\n\t104,\n\t105,\n\t99,\n\t97,\n\t103,\n\t111,\n\t104,\n\t111,\n\t108,\n\t105,\n\t100,\n\t97,\n\t121,\n\t71,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t112,\n\t97,\n\t115,\n\t115,\n\t97,\n\t103,\n\t101,\n\t44,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t97,\n\t110,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t102,\n\t101,\n\t101,\n\t108,\n\t105,\n\t110,\n\t103,\n\t97,\n\t114,\n\t114,\n\t105,\n\t118,\n\t101,\n\t100,\n\t112,\n\t97,\n\t115,\n\t115,\n\t105,\n\t110,\n\t103,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t108,\n\t121,\n\t46,\n\t10,\n\t10,\n\t84,\n\t104,\n\t101,\n\t32,\n\t98,\n\t117,\n\t116,\n\t32,\n\t110,\n\t111,\n\t116,\n\t100,\n\t101,\n\t110,\n\t115,\n\t105,\n\t116,\n\t121,\n\t66,\n\t114,\n\t105,\n\t116,\n\t97,\n\t105,\n\t110,\n\t67,\n\t104,\n\t105,\n\t110,\n\t101,\n\t115,\n\t101,\n\t108,\n\t97,\n\t99,\n\t107,\n\t32,\n\t111,\n\t102,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t73,\n\t114,\n\t101,\n\t108,\n\t97,\n\t110,\n\t100,\n\t34,\n\t32,\n\t100,\n\t97,\n\t116,\n\t97,\n\t45,\n\t102,\n\t97,\n\t99,\n\t116,\n\t111,\n\t114,\n\t115,\n\t114,\n\t101,\n\t99,\n\t101,\n\t105,\n\t118,\n\t101,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t105,\n\t115,\n\t76,\n\t105,\n\t98,\n\t114,\n\t97,\n\t114,\n\t121,\n\t104,\n\t117,\n\t115,\n\t98,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t32,\n\t102,\n\t97,\n\t99,\n\t116,\n\t97,\n\t102,\n\t102,\n\t97,\n\t105,\n\t114,\n\t115,\n\t67,\n\t104,\n\t97,\n\t114,\n\t108,\n\t101,\n\t115,\n\t114,\n\t97,\n\t100,\n\t105,\n\t99,\n\t97,\n\t108,\n\t98,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t102,\n\t105,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t108,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t108,\n\t97,\n\t110,\n\t103,\n\t61,\n\t34,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t108,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t115,\n\t112,\n\t108,\n\t97,\n\t110,\n\t110,\n\t101,\n\t100,\n\t112,\n\t114,\n\t101,\n\t109,\n\t105,\n\t117,\n\t109,\n\t112,\n\t97,\n\t99,\n\t107,\n\t97,\n\t103,\n\t101,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t69,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t93,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t77,\n\t101,\n\t115,\n\t115,\n\t97,\n\t103,\n\t101,\n\t110,\n\t101,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t120,\n\t108,\n\t111,\n\t111,\n\t107,\n\t105,\n\t110,\n\t103,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t101,\n\t114,\n\t45,\n\t109,\n\t111,\n\t98,\n\t105,\n\t108,\n\t101,\n\t114,\n\t101,\n\t99,\n\t111,\n\t114,\n\t100,\n\t115,\n\t119,\n\t97,\n\t110,\n\t116,\n\t32,\n\t116,\n\t111,\n\t107,\n\t105,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t70,\n\t105,\n\t114,\n\t101,\n\t102,\n\t111,\n\t120,\n\t121,\n\t111,\n\t117,\n\t32,\n\t97,\n\t114,\n\t101,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t115,\n\t116,\n\t117,\n\t100,\n\t105,\n\t101,\n\t100,\n\t109,\n\t97,\n\t120,\n\t105,\n\t109,\n\t117,\n\t109,\n\t104,\n\t101,\n\t97,\n\t100,\n\t105,\n\t110,\n\t103,\n\t114,\n\t97,\n\t112,\n\t105,\n\t100,\n\t108,\n\t121,\n\t99,\n\t108,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t107,\n\t105,\n\t110,\n\t103,\n\t100,\n\t111,\n\t109,\n\t101,\n\t109,\n\t101,\n\t114,\n\t103,\n\t101,\n\t100,\n\t97,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t115,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t112,\n\t105,\n\t111,\n\t110,\n\t101,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t117,\n\t108,\n\t97,\n\t100,\n\t121,\n\t110,\n\t97,\n\t115,\n\t116,\n\t121,\n\t104,\n\t111,\n\t119,\n\t32,\n\t116,\n\t111,\n\t32,\n\t83,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t117,\n\t101,\n\t101,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t121,\n\t82,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t115,\n\t98,\n\t114,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t115,\n\t111,\n\t108,\n\t100,\n\t105,\n\t101,\n\t114,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t108,\n\t121,\n\t99,\n\t97,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t46,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t65,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t69,\n\t100,\n\t119,\n\t97,\n\t114,\n\t100,\n\t32,\n\t115,\n\t101,\n\t103,\n\t109,\n\t101,\n\t110,\n\t116,\n\t82,\n\t111,\n\t98,\n\t101,\n\t114,\n\t116,\n\t32,\n\t101,\n\t102,\n\t102,\n\t111,\n\t114,\n\t116,\n\t115,\n\t80,\n\t97,\n\t99,\n\t105,\n\t102,\n\t105,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t110,\n\t101,\n\t100,\n\t117,\n\t112,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t119,\n\t101,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t65,\n\t110,\n\t103,\n\t101,\n\t108,\n\t101,\n\t115,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t95,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t101,\n\t100,\n\t97,\n\t99,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t109,\n\t97,\n\t115,\n\t115,\n\t105,\n\t118,\n\t101,\n\t103,\n\t114,\n\t97,\n\t110,\n\t116,\n\t101,\n\t100,\n\t58,\n\t32,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t116,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t98,\n\t105,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t98,\n\t101,\n\t110,\n\t101,\n\t102,\n\t105,\n\t116,\n\t100,\n\t114,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t83,\n\t116,\n\t117,\n\t100,\n\t105,\n\t101,\n\t115,\n\t109,\n\t105,\n\t110,\n\t105,\n\t109,\n\t117,\n\t109,\n\t112,\n\t101,\n\t114,\n\t104,\n\t97,\n\t112,\n\t115,\n\t109,\n\t111,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t105,\n\t115,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t114,\n\t101,\n\t118,\n\t101,\n\t114,\n\t115,\n\t101,\n\t118,\n\t97,\n\t114,\n\t105,\n\t97,\n\t110,\n\t116,\n\t32,\n\t114,\n\t111,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t110,\n\t103,\n\t97,\n\t99,\n\t104,\n\t105,\n\t101,\n\t118,\n\t101,\n\t112,\n\t114,\n\t111,\n\t109,\n\t111,\n\t116,\n\t101,\n\t115,\n\t116,\n\t117,\n\t100,\n\t101,\n\t110,\n\t116,\n\t115,\n\t111,\n\t109,\n\t101,\n\t111,\n\t110,\n\t101,\n\t101,\n\t120,\n\t116,\n\t114,\n\t101,\n\t109,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t111,\n\t114,\n\t101,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t58,\n\t101,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t100,\n\t97,\n\t108,\n\t108,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t105,\n\t116,\n\t101,\n\t109,\n\t97,\n\t112,\n\t101,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t119,\n\t97,\n\t121,\n\t32,\n\t116,\n\t111,\n\t32,\n\t32,\n\t65,\n\t117,\n\t103,\n\t117,\n\t115,\n\t116,\n\t115,\n\t121,\n\t109,\n\t98,\n\t111,\n\t108,\n\t115,\n\t67,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t121,\n\t109,\n\t97,\n\t116,\n\t116,\n\t101,\n\t114,\n\t115,\n\t109,\n\t117,\n\t115,\n\t105,\n\t99,\n\t97,\n\t108,\n\t97,\n\t103,\n\t97,\n\t105,\n\t110,\n\t115,\n\t116,\n\t115,\n\t101,\n\t114,\n\t118,\n\t105,\n\t110,\n\t103,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t13,\n\t10,\n\t112,\n\t97,\n\t121,\n\t109,\n\t101,\n\t110,\n\t116,\n\t116,\n\t114,\n\t111,\n\t117,\n\t98,\n\t108,\n\t101,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t112,\n\t116,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t101,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t116,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t101,\n\t114,\n\t115,\n\t114,\n\t101,\n\t103,\n\t105,\n\t111,\n\t110,\n\t115,\n\t109,\n\t111,\n\t110,\n\t105,\n\t116,\n\t111,\n\t114,\n\t32,\n\t39,\n\t39,\n\t84,\n\t104,\n\t101,\n\t32,\n\t119,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t101,\n\t120,\n\t112,\n\t108,\n\t111,\n\t114,\n\t101,\n\t97,\n\t100,\n\t97,\n\t112,\n\t116,\n\t101,\n\t100,\n\t71,\n\t97,\n\t108,\n\t108,\n\t101,\n\t114,\n\t121,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t101,\n\t110,\n\t104,\n\t97,\n\t110,\n\t99,\n\t101,\n\t99,\n\t97,\n\t114,\n\t101,\n\t101,\n\t114,\n\t115,\n\t41,\n\t46,\n\t32,\n\t84,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t83,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t32,\n\t97,\n\t110,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t101,\n\t100,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t32,\n\t104,\n\t97,\n\t110,\n\t100,\n\t108,\n\t101,\n\t114,\n\t112,\n\t114,\n\t105,\n\t110,\n\t116,\n\t101,\n\t100,\n\t99,\n\t111,\n\t110,\n\t115,\n\t111,\n\t108,\n\t101,\n\t69,\n\t97,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t101,\n\t120,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t115,\n\t67,\n\t104,\n\t97,\n\t110,\n\t110,\n\t101,\n\t108,\n\t105,\n\t108,\n\t108,\n\t101,\n\t103,\n\t97,\n\t108,\n\t110,\n\t101,\n\t117,\n\t116,\n\t114,\n\t97,\n\t108,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t95,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t115,\n\t105,\n\t103,\n\t110,\n\t105,\n\t110,\n\t103,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t62,\n\t115,\n\t101,\n\t116,\n\t116,\n\t108,\n\t101,\n\t100,\n\t119,\n\t101,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t99,\n\t97,\n\t117,\n\t115,\n\t105,\n\t110,\n\t103,\n\t45,\n\t119,\n\t101,\n\t98,\n\t107,\n\t105,\n\t116,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t101,\n\t100,\n\t74,\n\t117,\n\t115,\n\t116,\n\t105,\n\t99,\n\t101,\n\t99,\n\t104,\n\t97,\n\t112,\n\t116,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t116,\n\t105,\n\t109,\n\t115,\n\t84,\n\t104,\n\t111,\n\t109,\n\t97,\n\t115,\n\t32,\n\t109,\n\t111,\n\t122,\n\t105,\n\t108,\n\t108,\n\t97,\n\t112,\n\t114,\n\t111,\n\t109,\n\t105,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t101,\n\t115,\n\t101,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t117,\n\t116,\n\t115,\n\t105,\n\t100,\n\t101,\n\t58,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t44,\n\t104,\n\t117,\n\t110,\n\t100,\n\t114,\n\t101,\n\t100,\n\t79,\n\t108,\n\t121,\n\t109,\n\t112,\n\t105,\n\t99,\n\t95,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t115,\n\t114,\n\t101,\n\t97,\n\t99,\n\t104,\n\t101,\n\t100,\n\t99,\n\t104,\n\t114,\n\t111,\n\t110,\n\t105,\n\t99,\n\t100,\n\t101,\n\t109,\n\t97,\n\t110,\n\t100,\n\t115,\n\t115,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t115,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t116,\n\t97,\n\t100,\n\t111,\n\t112,\n\t116,\n\t101,\n\t100,\n\t112,\n\t114,\n\t101,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t101,\n\t105,\n\t116,\n\t104,\n\t101,\n\t114,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t108,\n\t121,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t114,\n\t111,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t105,\n\t109,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t97,\n\t110,\n\t100,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t46,\n\t119,\n\t111,\n\t114,\n\t115,\n\t104,\n\t105,\n\t112,\n\t102,\n\t117,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t104,\n\t105,\n\t103,\n\t104,\n\t101,\n\t115,\n\t116,\n\t105,\n\t110,\n\t115,\n\t116,\n\t101,\n\t97,\n\t100,\n\t117,\n\t116,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t113,\n\t117,\n\t97,\n\t114,\n\t116,\n\t101,\n\t114,\n\t67,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t101,\n\t116,\n\t101,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t108,\n\t121,\n\t101,\n\t120,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t66,\n\t114,\n\t111,\n\t119,\n\t115,\n\t101,\n\t114,\n\t108,\n\t105,\n\t98,\n\t101,\n\t114,\n\t97,\n\t108,\n\t125,\n\t32,\n\t99,\n\t97,\n\t116,\n\t99,\n\t104,\n\t80,\n\t114,\n\t111,\n\t106,\n\t101,\n\t99,\n\t116,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t104,\n\t105,\n\t100,\n\t101,\n\t40,\n\t41,\n\t59,\n\t70,\n\t108,\n\t111,\n\t114,\n\t105,\n\t100,\n\t97,\n\t97,\n\t110,\n\t115,\n\t119,\n\t101,\n\t114,\n\t115,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t69,\n\t109,\n\t112,\n\t101,\n\t114,\n\t111,\n\t114,\n\t100,\n\t101,\n\t102,\n\t101,\n\t110,\n\t115,\n\t101,\n\t115,\n\t101,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t102,\n\t114,\n\t101,\n\t101,\n\t100,\n\t111,\n\t109,\n\t83,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t45,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t70,\n\t117,\n\t114,\n\t116,\n\t104,\n\t101,\n\t114,\n\t111,\n\t117,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t33,\n\t61,\n\t32,\n\t110,\n\t117,\n\t108,\n\t108,\n\t116,\n\t114,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t68,\n\t101,\n\t110,\n\t109,\n\t97,\n\t114,\n\t107,\n\t118,\n\t111,\n\t105,\n\t100,\n\t40,\n\t48,\n\t41,\n\t47,\n\t97,\n\t108,\n\t108,\n\t46,\n\t106,\n\t115,\n\t112,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t82,\n\t101,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t83,\n\t116,\n\t101,\n\t112,\n\t104,\n\t101,\n\t110,\n\t10,\n\t10,\n\t87,\n\t104,\n\t101,\n\t110,\n\t32,\n\t111,\n\t98,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t60,\n\t47,\n\t104,\n\t50,\n\t62,\n\t13,\n\t10,\n\t77,\n\t111,\n\t100,\n\t101,\n\t114,\n\t110,\n\t32,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t115,\n\t46,\n\t10,\n\t10,\n\t70,\n\t111,\n\t114,\n\t32,\n\t10,\n\t10,\n\t77,\n\t97,\n\t110,\n\t121,\n\t32,\n\t97,\n\t114,\n\t116,\n\t105,\n\t115,\n\t116,\n\t115,\n\t112,\n\t111,\n\t119,\n\t101,\n\t114,\n\t101,\n\t100,\n\t112,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t102,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t121,\n\t112,\n\t101,\n\t32,\n\t111,\n\t102,\n\t109,\n\t101,\n\t100,\n\t105,\n\t99,\n\t97,\n\t108,\n\t116,\n\t105,\n\t99,\n\t107,\n\t101,\n\t116,\n\t115,\n\t111,\n\t112,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t67,\n\t111,\n\t117,\n\t110,\n\t99,\n\t105,\n\t108,\n\t119,\n\t105,\n\t116,\n\t110,\n\t101,\n\t115,\n\t115,\n\t106,\n\t117,\n\t115,\n\t116,\n\t105,\n\t99,\n\t101,\n\t71,\n\t101,\n\t111,\n\t114,\n\t103,\n\t101,\n\t32,\n\t66,\n\t101,\n\t108,\n\t103,\n\t105,\n\t117,\n\t109,\n\t46,\n\t46,\n\t46,\n\t60,\n\t47,\n\t97,\n\t62,\n\t116,\n\t119,\n\t105,\n\t116,\n\t116,\n\t101,\n\t114,\n\t110,\n\t111,\n\t116,\n\t97,\n\t98,\n\t108,\n\t121,\n\t119,\n\t97,\n\t105,\n\t116,\n\t105,\n\t110,\n\t103,\n\t119,\n\t97,\n\t114,\n\t102,\n\t97,\n\t114,\n\t101,\n\t32,\n\t79,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t114,\n\t97,\n\t110,\n\t107,\n\t105,\n\t110,\n\t103,\n\t112,\n\t104,\n\t114,\n\t97,\n\t115,\n\t101,\n\t115,\n\t109,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t117,\n\t114,\n\t118,\n\t105,\n\t118,\n\t101,\n\t115,\n\t99,\n\t104,\n\t111,\n\t108,\n\t97,\n\t114,\n\t60,\n\t47,\n\t112,\n\t62,\n\t13,\n\t10,\n\t32,\n\t67,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t121,\n\t105,\n\t103,\n\t110,\n\t111,\n\t114,\n\t101,\n\t100,\n\t108,\n\t111,\n\t115,\n\t115,\n\t32,\n\t111,\n\t102,\n\t106,\n\t117,\n\t115,\n\t116,\n\t32,\n\t97,\n\t115,\n\t71,\n\t101,\n\t111,\n\t114,\n\t103,\n\t105,\n\t97,\n\t115,\n\t116,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t60,\n\t115,\n\t116,\n\t111,\n\t112,\n\t112,\n\t101,\n\t100,\n\t49,\n\t39,\n\t93,\n\t41,\n\t59,\n\t13,\n\t10,\n\t105,\n\t115,\n\t108,\n\t97,\n\t110,\n\t100,\n\t115,\n\t110,\n\t111,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t58,\n\t108,\n\t105,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t99,\n\t97,\n\t114,\n\t114,\n\t105,\n\t101,\n\t100,\n\t49,\n\t48,\n\t48,\n\t44,\n\t48,\n\t48,\n\t48,\n\t60,\n\t47,\n\t104,\n\t51,\n\t62,\n\t10,\n\t32,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t98,\n\t101,\n\t99,\n\t111,\n\t109,\n\t101,\n\t115,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t32,\n\t119,\n\t101,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t48,\n\t48,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t109,\n\t111,\n\t110,\n\t97,\n\t114,\n\t99,\n\t104,\n\t111,\n\t102,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t101,\n\t97,\n\t99,\n\t104,\n\t101,\n\t114,\n\t104,\n\t105,\n\t103,\n\t104,\n\t108,\n\t121,\n\t32,\n\t98,\n\t105,\n\t111,\n\t108,\n\t111,\n\t103,\n\t121,\n\t108,\n\t105,\n\t102,\n\t101,\n\t32,\n\t111,\n\t102,\n\t111,\n\t114,\n\t32,\n\t101,\n\t118,\n\t101,\n\t110,\n\t114,\n\t105,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t38,\n\t114,\n\t97,\n\t113,\n\t117,\n\t111,\n\t59,\n\t112,\n\t108,\n\t117,\n\t115,\n\t111,\n\t110,\n\t101,\n\t104,\n\t117,\n\t110,\n\t116,\n\t105,\n\t110,\n\t103,\n\t40,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t68,\n\t111,\n\t117,\n\t103,\n\t108,\n\t97,\n\t115,\n\t106,\n\t111,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t99,\n\t105,\n\t114,\n\t99,\n\t108,\n\t101,\n\t115,\n\t70,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t65,\n\t110,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t86,\n\t105,\n\t101,\n\t116,\n\t110,\n\t97,\n\t109,\n\t118,\n\t101,\n\t104,\n\t105,\n\t99,\n\t108,\n\t101,\n\t115,\n\t117,\n\t99,\n\t104,\n\t32,\n\t97,\n\t115,\n\t99,\n\t114,\n\t121,\n\t115,\n\t116,\n\t97,\n\t108,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t32,\n\t61,\n\t87,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t115,\n\t101,\n\t110,\n\t106,\n\t111,\n\t121,\n\t101,\n\t100,\n\t97,\n\t32,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t97,\n\t115,\n\t115,\n\t117,\n\t109,\n\t101,\n\t100,\n\t60,\n\t97,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t102,\n\t111,\n\t114,\n\t101,\n\t105,\n\t103,\n\t110,\n\t32,\n\t65,\n\t108,\n\t108,\n\t32,\n\t114,\n\t105,\n\t104,\n\t111,\n\t119,\n\t32,\n\t116,\n\t104,\n\t101,\n\t68,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t114,\n\t101,\n\t116,\n\t105,\n\t114,\n\t101,\n\t100,\n\t104,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t59,\n\t98,\n\t97,\n\t116,\n\t116,\n\t108,\n\t101,\n\t115,\n\t115,\n\t101,\n\t101,\n\t107,\n\t105,\n\t110,\n\t103,\n\t99,\n\t97,\n\t98,\n\t105,\n\t110,\n\t101,\n\t116,\n\t119,\n\t97,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t108,\n\t111,\n\t111,\n\t107,\n\t32,\n\t97,\n\t116,\n\t99,\n\t111,\n\t110,\n\t100,\n\t117,\n\t99,\n\t116,\n\t103,\n\t101,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t74,\n\t97,\n\t110,\n\t117,\n\t97,\n\t114,\n\t121,\n\t104,\n\t97,\n\t112,\n\t112,\n\t101,\n\t110,\n\t115,\n\t116,\n\t117,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t97,\n\t58,\n\t104,\n\t111,\n\t118,\n\t101,\n\t114,\n\t79,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t32,\n\t70,\n\t114,\n\t101,\n\t110,\n\t99,\n\t104,\n\t32,\n\t108,\n\t97,\n\t99,\n\t107,\n\t105,\n\t110,\n\t103,\n\t116,\n\t121,\n\t112,\n\t105,\n\t99,\n\t97,\n\t108,\n\t101,\n\t120,\n\t116,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t110,\n\t101,\n\t109,\n\t105,\n\t101,\n\t115,\n\t101,\n\t118,\n\t101,\n\t110,\n\t32,\n\t105,\n\t102,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t116,\n\t100,\n\t101,\n\t99,\n\t105,\n\t100,\n\t101,\n\t100,\n\t97,\n\t114,\n\t101,\n\t32,\n\t110,\n\t111,\n\t116,\n\t47,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t102,\n\t115,\n\t45,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t58,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t99,\n\t46,\n\t108,\n\t111,\n\t103,\n\t105,\n\t110,\n\t34,\n\t62,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t116,\n\t118,\n\t105,\n\t111,\n\t108,\n\t101,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t34,\n\t62,\n\t99,\n\t105,\n\t114,\n\t99,\n\t117,\n\t105,\n\t116,\n\t70,\n\t105,\n\t110,\n\t108,\n\t97,\n\t110,\n\t100,\n\t99,\n\t104,\n\t101,\n\t109,\n\t105,\n\t115,\n\t116,\n\t115,\n\t104,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t49,\n\t48,\n\t112,\n\t120,\n\t59,\n\t34,\n\t62,\n\t97,\n\t115,\n\t32,\n\t115,\n\t117,\n\t99,\n\t104,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t119,\n\t105,\n\t108,\n\t108,\n\t32,\n\t98,\n\t101,\n\t108,\n\t105,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t32,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t109,\n\t121,\n\t115,\n\t116,\n\t101,\n\t114,\n\t121,\n\t47,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t102,\n\t97,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t100,\n\t117,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t114,\n\t97,\n\t105,\n\t108,\n\t119,\n\t97,\n\t121,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t103,\n\t101,\n\t109,\n\t111,\n\t110,\n\t115,\n\t116,\n\t101,\n\t114,\n\t100,\n\t101,\n\t115,\n\t99,\n\t101,\n\t110,\n\t116,\n\t105,\n\t116,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t110,\n\t117,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t74,\n\t101,\n\t119,\n\t105,\n\t115,\n\t104,\n\t32,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t115,\n\t116,\n\t66,\n\t114,\n\t105,\n\t116,\n\t105,\n\t115,\n\t104,\n\t102,\n\t108,\n\t111,\n\t119,\n\t101,\n\t114,\n\t115,\n\t112,\n\t114,\n\t101,\n\t100,\n\t105,\n\t99,\n\t116,\n\t114,\n\t101,\n\t102,\n\t111,\n\t114,\n\t109,\n\t115,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t32,\n\t119,\n\t104,\n\t111,\n\t32,\n\t119,\n\t97,\n\t115,\n\t108,\n\t101,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t115,\n\t117,\n\t105,\n\t99,\n\t105,\n\t100,\n\t101,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t105,\n\t99,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t115,\n\t109,\n\t97,\n\t114,\n\t107,\n\t101,\n\t116,\n\t115,\n\t83,\n\t111,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t102,\n\t105,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t99,\n\t111,\n\t109,\n\t98,\n\t105,\n\t110,\n\t101,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t105,\n\t99,\n\t119,\n\t105,\n\t110,\n\t110,\n\t101,\n\t114,\n\t115,\n\t60,\n\t98,\n\t114,\n\t32,\n\t47,\n\t62,\n\t60,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t78,\n\t97,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t80,\n\t114,\n\t105,\n\t118,\n\t97,\n\t99,\n\t121,\n\t99,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t115,\n\t111,\n\t117,\n\t116,\n\t99,\n\t111,\n\t109,\n\t101,\n\t114,\n\t101,\n\t115,\n\t111,\n\t108,\n\t118,\n\t101,\n\t83,\n\t119,\n\t101,\n\t100,\n\t105,\n\t115,\n\t104,\n\t98,\n\t114,\n\t105,\n\t101,\n\t102,\n\t108,\n\t121,\n\t80,\n\t101,\n\t114,\n\t115,\n\t105,\n\t97,\n\t110,\n\t115,\n\t111,\n\t32,\n\t109,\n\t117,\n\t99,\n\t104,\n\t67,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t100,\n\t101,\n\t112,\n\t105,\n\t99,\n\t116,\n\t115,\n\t99,\n\t111,\n\t108,\n\t117,\n\t109,\n\t110,\n\t115,\n\t104,\n\t111,\n\t117,\n\t115,\n\t105,\n\t110,\n\t103,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t115,\n\t110,\n\t101,\n\t120,\n\t116,\n\t32,\n\t116,\n\t111,\n\t98,\n\t101,\n\t97,\n\t114,\n\t105,\n\t110,\n\t103,\n\t109,\n\t97,\n\t112,\n\t112,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t118,\n\t105,\n\t115,\n\t101,\n\t100,\n\t106,\n\t81,\n\t117,\n\t101,\n\t114,\n\t121,\n\t40,\n\t45,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t34,\n\t62,\n\t116,\n\t111,\n\t111,\n\t108,\n\t116,\n\t105,\n\t112,\n\t83,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t115,\n\t84,\n\t117,\n\t114,\n\t107,\n\t105,\n\t115,\n\t104,\n\t121,\n\t111,\n\t117,\n\t110,\n\t103,\n\t101,\n\t114,\n\t46,\n\t109,\n\t97,\n\t116,\n\t99,\n\t104,\n\t40,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t10,\n\t10,\n\t98,\n\t117,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t101,\n\t103,\n\t114,\n\t101,\n\t101,\n\t115,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t61,\n\t82,\n\t105,\n\t99,\n\t104,\n\t97,\n\t114,\n\t100,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t108,\n\t121,\n\t112,\n\t108,\n\t97,\n\t115,\n\t116,\n\t105,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t13,\n\t10,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t35,\n\t117,\n\t108,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t115,\n\t101,\n\t115,\n\t115,\n\t114,\n\t111,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t112,\n\t104,\n\t121,\n\t115,\n\t105,\n\t99,\n\t115,\n\t102,\n\t97,\n\t105,\n\t108,\n\t105,\n\t110,\n\t103,\n\t101,\n\t120,\n\t101,\n\t99,\n\t117,\n\t116,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t115,\n\t116,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t116,\n\t111,\n\t68,\n\t101,\n\t102,\n\t97,\n\t117,\n\t108,\n\t116,\n\t60,\n\t98,\n\t114,\n\t32,\n\t47,\n\t62,\n\t10,\n\t58,\n\t32,\n\t116,\n\t114,\n\t117,\n\t101,\n\t44,\n\t99,\n\t104,\n\t97,\n\t114,\n\t116,\n\t101,\n\t114,\n\t116,\n\t111,\n\t117,\n\t114,\n\t105,\n\t115,\n\t109,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t99,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t101,\n\t100,\n\t101,\n\t120,\n\t112,\n\t108,\n\t97,\n\t105,\n\t110,\n\t60,\n\t47,\n\t104,\n\t49,\n\t62,\n\t13,\n\t10,\n\t111,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t46,\n\t63,\n\t120,\n\t109,\n\t108,\n\t32,\n\t118,\n\t101,\n\t104,\n\t101,\n\t108,\n\t112,\n\t105,\n\t110,\n\t103,\n\t100,\n\t105,\n\t97,\n\t109,\n\t111,\n\t110,\n\t100,\n\t117,\n\t115,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t105,\n\t114,\n\t108,\n\t105,\n\t110,\n\t101,\n\t101,\n\t110,\n\t100,\n\t32,\n\t45,\n\t45,\n\t62,\n\t41,\n\t46,\n\t97,\n\t116,\n\t116,\n\t114,\n\t40,\n\t114,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t115,\n\t104,\n\t111,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t35,\n\t102,\n\t102,\n\t102,\n\t102,\n\t102,\n\t102,\n\t114,\n\t101,\n\t97,\n\t108,\n\t105,\n\t122,\n\t101,\n\t86,\n\t105,\n\t110,\n\t99,\n\t101,\n\t110,\n\t116,\n\t115,\n\t105,\n\t103,\n\t110,\n\t97,\n\t108,\n\t115,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t47,\n\t80,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t100,\n\t101,\n\t115,\n\t112,\n\t105,\n\t116,\n\t101,\n\t100,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t101,\n\t116,\n\t101,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t80,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t32,\n\t104,\n\t101,\n\t108,\n\t100,\n\t32,\n\t105,\n\t110,\n\t74,\n\t111,\n\t115,\n\t101,\n\t112,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t116,\n\t114,\n\t101,\n\t97,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t115,\n\t60,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t62,\n\t97,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t100,\n\t111,\n\t101,\n\t115,\n\t110,\n\t39,\n\t116,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t44,\n\t32,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t102,\n\t97,\n\t118,\n\t105,\n\t99,\n\t111,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t111,\n\t114,\n\t72,\n\t117,\n\t110,\n\t103,\n\t97,\n\t114,\n\t121,\n\t65,\n\t105,\n\t114,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t101,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t111,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t77,\n\t105,\n\t99,\n\t104,\n\t97,\n\t101,\n\t108,\n\t83,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t115,\n\t80,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t115,\n\t44,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t101,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t110,\n\t103,\n\t108,\n\t101,\n\t102,\n\t116,\n\t34,\n\t62,\n\t10,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t115,\n\t71,\n\t111,\n\t108,\n\t100,\n\t101,\n\t110,\n\t32,\n\t65,\n\t102,\n\t102,\n\t97,\n\t105,\n\t114,\n\t115,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t97,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t115,\n\t116,\n\t114,\n\t111,\n\t121,\n\t105,\n\t100,\n\t101,\n\t97,\n\t32,\n\t111,\n\t102,\n\t99,\n\t97,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t111,\n\t108,\n\t100,\n\t101,\n\t115,\n\t116,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t105,\n\t115,\n\t46,\n\t115,\n\t114,\n\t99,\n\t32,\n\t61,\n\t32,\n\t99,\n\t97,\n\t114,\n\t116,\n\t111,\n\t111,\n\t110,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t114,\n\t67,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t115,\n\t77,\n\t117,\n\t115,\n\t108,\n\t105,\n\t109,\n\t115,\n\t87,\n\t104,\n\t97,\n\t116,\n\t32,\n\t105,\n\t115,\n\t105,\n\t110,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t109,\n\t97,\n\t114,\n\t107,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t118,\n\t101,\n\t97,\n\t108,\n\t115,\n\t73,\n\t110,\n\t100,\n\t101,\n\t101,\n\t100,\n\t44,\n\t101,\n\t113,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t47,\n\t115,\n\t104,\n\t111,\n\t119,\n\t95,\n\t97,\n\t111,\n\t117,\n\t116,\n\t100,\n\t111,\n\t111,\n\t114,\n\t101,\n\t115,\n\t99,\n\t97,\n\t112,\n\t101,\n\t40,\n\t65,\n\t117,\n\t115,\n\t116,\n\t114,\n\t105,\n\t97,\n\t103,\n\t101,\n\t110,\n\t101,\n\t116,\n\t105,\n\t99,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t44,\n\t73,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t105,\n\t116,\n\t116,\n\t105,\n\t110,\n\t103,\n\t72,\n\t101,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t73,\n\t115,\n\t108,\n\t97,\n\t110,\n\t100,\n\t115,\n\t65,\n\t99,\n\t97,\n\t100,\n\t101,\n\t109,\n\t121,\n\t10,\n\t9,\n\t9,\n\t60,\n\t33,\n\t45,\n\t45,\n\t68,\n\t97,\n\t110,\n\t105,\n\t101,\n\t108,\n\t32,\n\t98,\n\t105,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t34,\n\t62,\n\t105,\n\t109,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t117,\n\t116,\n\t105,\n\t108,\n\t105,\n\t122,\n\t101,\n\t65,\n\t98,\n\t114,\n\t97,\n\t104,\n\t97,\n\t109,\n\t40,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t123,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t112,\n\t117,\n\t116,\n\t116,\n\t105,\n\t110,\n\t103,\n\t41,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t40,\n\t124,\n\t124,\n\t32,\n\t91,\n\t93,\n\t59,\n\t10,\n\t68,\n\t65,\n\t84,\n\t65,\n\t91,\n\t32,\n\t42,\n\t107,\n\t105,\n\t116,\n\t99,\n\t104,\n\t101,\n\t110,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t101,\n\t100,\n\t97,\n\t99,\n\t116,\n\t117,\n\t97,\n\t108,\n\t32,\n\t100,\n\t105,\n\t97,\n\t108,\n\t101,\n\t99,\n\t116,\n\t109,\n\t97,\n\t105,\n\t110,\n\t108,\n\t121,\n\t32,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t39,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t108,\n\t108,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t116,\n\t115,\n\t105,\n\t102,\n\t40,\n\t116,\n\t121,\n\t112,\n\t101,\n\t73,\n\t116,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t38,\n\t99,\n\t111,\n\t112,\n\t121,\n\t59,\n\t32,\n\t34,\n\t62,\n\t84,\n\t101,\n\t114,\n\t109,\n\t115,\n\t98,\n\t111,\n\t114,\n\t110,\n\t32,\n\t105,\n\t110,\n\t79,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t97,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t116,\n\t97,\n\t108,\n\t107,\n\t105,\n\t110,\n\t103,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t114,\n\t110,\n\t103,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t103,\n\t111,\n\t105,\n\t110,\n\t103,\n\t106,\n\t117,\n\t115,\n\t116,\n\t105,\n\t102,\n\t121,\n\t99,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t115,\n\t102,\n\t97,\n\t99,\n\t116,\n\t111,\n\t114,\n\t121,\n\t105,\n\t116,\n\t115,\n\t32,\n\t111,\n\t119,\n\t110,\n\t97,\n\t115,\n\t115,\n\t97,\n\t117,\n\t108,\n\t116,\n\t105,\n\t110,\n\t118,\n\t105,\n\t116,\n\t101,\n\t100,\n\t108,\n\t97,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t104,\n\t105,\n\t115,\n\t32,\n\t111,\n\t119,\n\t110,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t114,\n\t116,\n\t100,\n\t105,\n\t97,\n\t103,\n\t114,\n\t97,\n\t109,\n\t100,\n\t111,\n\t108,\n\t108,\n\t97,\n\t114,\n\t115,\n\t99,\n\t108,\n\t117,\n\t115,\n\t116,\n\t101,\n\t114,\n\t112,\n\t104,\n\t112,\n\t63,\n\t105,\n\t100,\n\t61,\n\t97,\n\t108,\n\t99,\n\t111,\n\t104,\n\t111,\n\t108,\n\t41,\n\t59,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t117,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t97,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t118,\n\t101,\n\t115,\n\t115,\n\t101,\n\t108,\n\t115,\n\t114,\n\t101,\n\t118,\n\t105,\n\t118,\n\t97,\n\t108,\n\t65,\n\t100,\n\t100,\n\t114,\n\t101,\n\t115,\n\t115,\n\t97,\n\t109,\n\t97,\n\t116,\n\t101,\n\t117,\n\t114,\n\t97,\n\t110,\n\t100,\n\t114,\n\t111,\n\t105,\n\t100,\n\t97,\n\t108,\n\t108,\n\t101,\n\t103,\n\t101,\n\t100,\n\t105,\n\t108,\n\t108,\n\t110,\n\t101,\n\t115,\n\t115,\n\t119,\n\t97,\n\t108,\n\t107,\n\t105,\n\t110,\n\t103,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t115,\n\t113,\n\t117,\n\t97,\n\t108,\n\t105,\n\t102,\n\t121,\n\t109,\n\t97,\n\t116,\n\t99,\n\t104,\n\t101,\n\t115,\n\t117,\n\t110,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t101,\n\t120,\n\t116,\n\t105,\n\t110,\n\t99,\n\t116,\n\t68,\n\t101,\n\t102,\n\t101,\n\t110,\n\t115,\n\t101,\n\t100,\n\t105,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t10,\n\t9,\n\t60,\n\t33,\n\t45,\n\t45,\n\t32,\n\t99,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t115,\n\t108,\n\t105,\n\t110,\n\t107,\n\t105,\n\t110,\n\t103,\n\t76,\n\t105,\n\t116,\n\t116,\n\t108,\n\t101,\n\t32,\n\t66,\n\t111,\n\t111,\n\t107,\n\t32,\n\t111,\n\t102,\n\t101,\n\t118,\n\t101,\n\t110,\n\t105,\n\t110,\n\t103,\n\t109,\n\t105,\n\t110,\n\t46,\n\t106,\n\t115,\n\t63,\n\t97,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t107,\n\t111,\n\t110,\n\t116,\n\t97,\n\t107,\n\t116,\n\t116,\n\t111,\n\t100,\n\t97,\n\t121,\n\t39,\n\t115,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t119,\n\t101,\n\t97,\n\t114,\n\t105,\n\t110,\n\t103,\n\t65,\n\t108,\n\t108,\n\t32,\n\t82,\n\t105,\n\t103,\n\t59,\n\t10,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t114,\n\t97,\n\t105,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t65,\n\t108,\n\t115,\n\t111,\n\t44,\n\t32,\n\t99,\n\t114,\n\t117,\n\t99,\n\t105,\n\t97,\n\t108,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t34,\n\t62,\n\t100,\n\t101,\n\t99,\n\t108,\n\t97,\n\t114,\n\t101,\n\t45,\n\t45,\n\t62,\n\t10,\n\t60,\n\t115,\n\t99,\n\t102,\n\t105,\n\t114,\n\t101,\n\t102,\n\t111,\n\t120,\n\t97,\n\t115,\n\t32,\n\t109,\n\t117,\n\t99,\n\t104,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t101,\n\t115,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t44,\n\t32,\n\t115,\n\t44,\n\t32,\n\t98,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t32,\n\t61,\n\t32,\n\t10,\n\t13,\n\t10,\n\t60,\n\t33,\n\t45,\n\t45,\n\t116,\n\t111,\n\t119,\n\t97,\n\t114,\n\t100,\n\t115,\n\t82,\n\t101,\n\t99,\n\t111,\n\t114,\n\t100,\n\t115,\n\t80,\n\t114,\n\t105,\n\t118,\n\t97,\n\t116,\n\t101,\n\t70,\n\t111,\n\t114,\n\t101,\n\t105,\n\t103,\n\t110,\n\t80,\n\t114,\n\t101,\n\t109,\n\t105,\n\t101,\n\t114,\n\t99,\n\t104,\n\t111,\n\t105,\n\t99,\n\t101,\n\t115,\n\t86,\n\t105,\n\t114,\n\t116,\n\t117,\n\t97,\n\t108,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t115,\n\t67,\n\t111,\n\t109,\n\t109,\n\t101,\n\t110,\n\t116,\n\t80,\n\t111,\n\t119,\n\t101,\n\t114,\n\t101,\n\t100,\n\t105,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t59,\n\t112,\n\t111,\n\t118,\n\t101,\n\t114,\n\t116,\n\t121,\n\t99,\n\t104,\n\t97,\n\t109,\n\t98,\n\t101,\n\t114,\n\t76,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t118,\n\t111,\n\t108,\n\t117,\n\t109,\n\t101,\n\t115,\n\t65,\n\t110,\n\t116,\n\t104,\n\t111,\n\t110,\n\t121,\n\t108,\n\t111,\n\t103,\n\t105,\n\t110,\n\t34,\n\t32,\n\t82,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t69,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t121,\n\t114,\n\t101,\n\t97,\n\t99,\n\t104,\n\t101,\n\t115,\n\t99,\n\t117,\n\t116,\n\t116,\n\t105,\n\t110,\n\t103,\n\t103,\n\t114,\n\t97,\n\t118,\n\t105,\n\t116,\n\t121,\n\t108,\n\t105,\n\t102,\n\t101,\n\t32,\n\t105,\n\t110,\n\t67,\n\t104,\n\t97,\n\t112,\n\t116,\n\t101,\n\t114,\n\t45,\n\t115,\n\t104,\n\t97,\n\t100,\n\t111,\n\t119,\n\t78,\n\t111,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t13,\n\t10,\n\t32,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t115,\n\t116,\n\t97,\n\t100,\n\t105,\n\t117,\n\t109,\n\t119,\n\t105,\n\t100,\n\t103,\n\t101,\n\t116,\n\t115,\n\t118,\n\t97,\n\t114,\n\t121,\n\t105,\n\t110,\n\t103,\n\t116,\n\t114,\n\t97,\n\t118,\n\t101,\n\t108,\n\t115,\n\t104,\n\t101,\n\t108,\n\t100,\n\t32,\n\t98,\n\t121,\n\t119,\n\t104,\n\t111,\n\t32,\n\t97,\n\t114,\n\t101,\n\t119,\n\t111,\n\t114,\n\t107,\n\t32,\n\t105,\n\t110,\n\t102,\n\t97,\n\t99,\n\t117,\n\t108,\n\t116,\n\t121,\n\t97,\n\t110,\n\t103,\n\t117,\n\t108,\n\t97,\n\t114,\n\t119,\n\t104,\n\t111,\n\t32,\n\t104,\n\t97,\n\t100,\n\t97,\n\t105,\n\t114,\n\t112,\n\t111,\n\t114,\n\t116,\n\t116,\n\t111,\n\t119,\n\t110,\n\t32,\n\t111,\n\t102,\n\t10,\n\t10,\n\t83,\n\t111,\n\t109,\n\t101,\n\t32,\n\t39,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t39,\n\t99,\n\t104,\n\t97,\n\t114,\n\t103,\n\t101,\n\t115,\n\t107,\n\t101,\n\t121,\n\t119,\n\t111,\n\t114,\n\t100,\n\t105,\n\t116,\n\t32,\n\t119,\n\t105,\n\t108,\n\t108,\n\t99,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t40,\n\t116,\n\t104,\n\t105,\n\t115,\n\t41,\n\t59,\n\t65,\n\t110,\n\t100,\n\t114,\n\t101,\n\t119,\n\t32,\n\t117,\n\t110,\n\t105,\n\t113,\n\t117,\n\t101,\n\t32,\n\t99,\n\t104,\n\t101,\n\t99,\n\t107,\n\t101,\n\t100,\n\t111,\n\t114,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t51,\n\t48,\n\t48,\n\t112,\n\t120,\n\t59,\n\t32,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t59,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t112,\n\t108,\n\t117,\n\t103,\n\t105,\n\t110,\n\t115,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t110,\n\t32,\n\t104,\n\t101,\n\t114,\n\t115,\n\t101,\n\t108,\n\t102,\n\t83,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t70,\n\t101,\n\t100,\n\t101,\n\t114,\n\t97,\n\t108,\n\t118,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t115,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t111,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t99,\n\t116,\n\t114,\n\t101,\n\t115,\n\t115,\n\t99,\n\t111,\n\t109,\n\t101,\n\t32,\n\t116,\n\t111,\n\t102,\n\t105,\n\t110,\n\t103,\n\t101,\n\t114,\n\t115,\n\t68,\n\t117,\n\t107,\n\t101,\n\t32,\n\t111,\n\t102,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t44,\n\t101,\n\t120,\n\t112,\n\t108,\n\t111,\n\t105,\n\t116,\n\t119,\n\t104,\n\t97,\n\t116,\n\t32,\n\t105,\n\t115,\n\t104,\n\t97,\n\t114,\n\t109,\n\t111,\n\t110,\n\t121,\n\t97,\n\t32,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t34,\n\t58,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t105,\n\t110,\n\t32,\n\t104,\n\t105,\n\t115,\n\t32,\n\t109,\n\t101,\n\t110,\n\t117,\n\t34,\n\t62,\n\t10,\n\t109,\n\t111,\n\t110,\n\t116,\n\t104,\n\t108,\n\t121,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t101,\n\t114,\n\t99,\n\t111,\n\t117,\n\t110,\n\t99,\n\t105,\n\t108,\n\t103,\n\t97,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t101,\n\t118,\n\t101,\n\t110,\n\t32,\n\t105,\n\t110,\n\t83,\n\t117,\n\t109,\n\t109,\n\t97,\n\t114,\n\t121,\n\t100,\n\t97,\n\t116,\n\t101,\n\t32,\n\t111,\n\t102,\n\t108,\n\t111,\n\t121,\n\t97,\n\t108,\n\t116,\n\t121,\n\t102,\n\t105,\n\t116,\n\t110,\n\t101,\n\t115,\n\t115,\n\t97,\n\t110,\n\t100,\n\t32,\n\t119,\n\t97,\n\t115,\n\t101,\n\t109,\n\t112,\n\t101,\n\t114,\n\t111,\n\t114,\n\t115,\n\t117,\n\t112,\n\t114,\n\t101,\n\t109,\n\t101,\n\t83,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t32,\n\t104,\n\t101,\n\t97,\n\t114,\n\t105,\n\t110,\n\t103,\n\t82,\n\t117,\n\t115,\n\t115,\n\t105,\n\t97,\n\t110,\n\t108,\n\t111,\n\t110,\n\t103,\n\t101,\n\t115,\n\t116,\n\t65,\n\t108,\n\t98,\n\t101,\n\t114,\n\t116,\n\t97,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t97,\n\t108,\n\t115,\n\t101,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t34,\n\t62,\n\t46,\n\t97,\n\t112,\n\t112,\n\t101,\n\t110,\n\t100,\n\t100,\n\t111,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t102,\n\t101,\n\t100,\n\t101,\n\t114,\n\t97,\n\t108,\n\t98,\n\t97,\n\t110,\n\t107,\n\t32,\n\t111,\n\t102,\n\t98,\n\t101,\n\t110,\n\t101,\n\t97,\n\t116,\n\t104,\n\t68,\n\t101,\n\t115,\n\t112,\n\t105,\n\t116,\n\t101,\n\t67,\n\t97,\n\t112,\n\t105,\n\t116,\n\t97,\n\t108,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t115,\n\t41,\n\t44,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t112,\n\t101,\n\t114,\n\t99,\n\t101,\n\t110,\n\t116,\n\t105,\n\t116,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t99,\n\t108,\n\t111,\n\t115,\n\t105,\n\t110,\n\t103,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t73,\n\t110,\n\t115,\n\t116,\n\t101,\n\t97,\n\t100,\n\t102,\n\t105,\n\t102,\n\t116,\n\t101,\n\t101,\n\t110,\n\t97,\n\t115,\n\t32,\n\t119,\n\t101,\n\t108,\n\t108,\n\t46,\n\t121,\n\t97,\n\t104,\n\t111,\n\t111,\n\t46,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t102,\n\t105,\n\t103,\n\t104,\n\t116,\n\t101,\n\t114,\n\t111,\n\t98,\n\t115,\n\t99,\n\t117,\n\t114,\n\t101,\n\t114,\n\t101,\n\t102,\n\t108,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t99,\n\t61,\n\t32,\n\t77,\n\t97,\n\t116,\n\t104,\n\t46,\n\t101,\n\t100,\n\t105,\n\t116,\n\t105,\n\t110,\n\t103,\n\t111,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t32,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t97,\n\t32,\n\t119,\n\t104,\n\t111,\n\t108,\n\t101,\n\t111,\n\t110,\n\t101,\n\t114,\n\t114,\n\t111,\n\t114,\n\t121,\n\t101,\n\t97,\n\t114,\n\t32,\n\t111,\n\t102,\n\t101,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t98,\n\t97,\n\t114,\n\t114,\n\t105,\n\t101,\n\t114,\n\t119,\n\t104,\n\t101,\n\t110,\n\t32,\n\t105,\n\t116,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t32,\n\t104,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t115,\n\t117,\n\t109,\n\t101,\n\t100,\n\t114,\n\t101,\n\t110,\n\t97,\n\t109,\n\t101,\n\t100,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t62,\n\t104,\n\t101,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t116,\n\t97,\n\t105,\n\t110,\n\t115,\n\t99,\n\t108,\n\t111,\n\t117,\n\t100,\n\t102,\n\t114,\n\t119,\n\t97,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t77,\n\t97,\n\t114,\n\t99,\n\t104,\n\t32,\n\t49,\n\t107,\n\t110,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t105,\n\t110,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t66,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t108,\n\t101,\n\t115,\n\t115,\n\t111,\n\t110,\n\t115,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t115,\n\t116,\n\t118,\n\t105,\n\t114,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t105,\n\t110,\n\t107,\n\t115,\n\t34,\n\t62,\n\t99,\n\t114,\n\t111,\n\t115,\n\t115,\n\t101,\n\t100,\n\t69,\n\t78,\n\t68,\n\t32,\n\t45,\n\t45,\n\t62,\n\t102,\n\t97,\n\t109,\n\t111,\n\t117,\n\t115,\n\t32,\n\t97,\n\t119,\n\t97,\n\t114,\n\t100,\n\t101,\n\t100,\n\t76,\n\t105,\n\t99,\n\t101,\n\t110,\n\t115,\n\t101,\n\t72,\n\t101,\n\t97,\n\t108,\n\t116,\n\t104,\n\t32,\n\t102,\n\t97,\n\t105,\n\t114,\n\t108,\n\t121,\n\t32,\n\t119,\n\t101,\n\t97,\n\t108,\n\t116,\n\t104,\n\t121,\n\t109,\n\t105,\n\t110,\n\t105,\n\t109,\n\t97,\n\t108,\n\t65,\n\t102,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t116,\n\t101,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t34,\n\t62,\n\t115,\n\t105,\n\t110,\n\t103,\n\t105,\n\t110,\n\t103,\n\t102,\n\t97,\n\t114,\n\t109,\n\t101,\n\t114,\n\t115,\n\t66,\n\t114,\n\t97,\n\t115,\n\t105,\n\t108,\n\t41,\n\t100,\n\t105,\n\t115,\n\t99,\n\t117,\n\t115,\n\t115,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t71,\n\t114,\n\t101,\n\t103,\n\t111,\n\t114,\n\t121,\n\t102,\n\t111,\n\t110,\n\t116,\n\t32,\n\t99,\n\t111,\n\t112,\n\t117,\n\t114,\n\t115,\n\t117,\n\t101,\n\t100,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t115,\n\t109,\n\t97,\n\t107,\n\t101,\n\t32,\n\t117,\n\t112,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t98,\n\t111,\n\t116,\n\t104,\n\t32,\n\t111,\n\t102,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t101,\n\t100,\n\t115,\n\t97,\n\t119,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t101,\n\t115,\n\t99,\n\t111,\n\t108,\n\t111,\n\t117,\n\t114,\n\t115,\n\t105,\n\t102,\n\t40,\n\t100,\n\t111,\n\t99,\n\t117,\n\t119,\n\t104,\n\t101,\n\t110,\n\t32,\n\t104,\n\t101,\n\t101,\n\t110,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t112,\n\t117,\n\t115,\n\t104,\n\t40,\n\t102,\n\t117,\n\t65,\n\t117,\n\t103,\n\t117,\n\t115,\n\t116,\n\t32,\n\t85,\n\t84,\n\t70,\n\t45,\n\t56,\n\t34,\n\t62,\n\t70,\n\t97,\n\t110,\n\t116,\n\t97,\n\t115,\n\t121,\n\t105,\n\t110,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t105,\n\t110,\n\t106,\n\t117,\n\t114,\n\t101,\n\t100,\n\t85,\n\t115,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t102,\n\t97,\n\t114,\n\t109,\n\t105,\n\t110,\n\t103,\n\t99,\n\t108,\n\t111,\n\t115,\n\t117,\n\t114,\n\t101,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t32,\n\t100,\n\t101,\n\t102,\n\t101,\n\t110,\n\t99,\n\t101,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t77,\n\t101,\n\t100,\n\t105,\n\t99,\n\t97,\n\t108,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t10,\n\t101,\n\t118,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t98,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t107,\n\t101,\n\t121,\n\t67,\n\t111,\n\t100,\n\t101,\n\t115,\n\t105,\n\t120,\n\t116,\n\t101,\n\t101,\n\t110,\n\t73,\n\t115,\n\t108,\n\t97,\n\t109,\n\t105,\n\t99,\n\t35,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t48,\n\t101,\n\t110,\n\t116,\n\t105,\n\t114,\n\t101,\n\t32,\n\t119,\n\t105,\n\t100,\n\t101,\n\t108,\n\t121,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t32,\n\t40,\n\t116,\n\t121,\n\t112,\n\t101,\n\t111,\n\t102,\n\t111,\n\t110,\n\t101,\n\t32,\n\t99,\n\t97,\n\t110,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t32,\n\t61,\n\t115,\n\t112,\n\t101,\n\t97,\n\t107,\n\t101,\n\t114,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t100,\n\t115,\n\t80,\n\t104,\n\t121,\n\t115,\n\t105,\n\t99,\n\t115,\n\t116,\n\t101,\n\t114,\n\t114,\n\t97,\n\t105,\n\t110,\n\t60,\n\t116,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t102,\n\t117,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t118,\n\t105,\n\t101,\n\t119,\n\t105,\n\t110,\n\t103,\n\t109,\n\t105,\n\t100,\n\t100,\n\t108,\n\t101,\n\t32,\n\t99,\n\t114,\n\t105,\n\t99,\n\t107,\n\t101,\n\t116,\n\t112,\n\t114,\n\t111,\n\t112,\n\t104,\n\t101,\n\t116,\n\t115,\n\t104,\n\t105,\n\t102,\n\t116,\n\t101,\n\t100,\n\t100,\n\t111,\n\t99,\n\t116,\n\t111,\n\t114,\n\t115,\n\t82,\n\t117,\n\t115,\n\t115,\n\t101,\n\t108,\n\t108,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t99,\n\t116,\n\t97,\n\t108,\n\t103,\n\t101,\n\t98,\n\t114,\n\t97,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t108,\n\t45,\n\t98,\n\t117,\n\t108,\n\t107,\n\t32,\n\t111,\n\t102,\n\t109,\n\t97,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t10,\n\t32,\n\t104,\n\t101,\n\t32,\n\t108,\n\t101,\n\t102,\n\t116,\n\t41,\n\t46,\n\t118,\n\t97,\n\t108,\n\t40,\n\t41,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t41,\n\t59,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t98,\n\t97,\n\t110,\n\t107,\n\t105,\n\t110,\n\t103,\n\t104,\n\t111,\n\t109,\n\t101,\n\t32,\n\t116,\n\t111,\n\t110,\n\t97,\n\t109,\n\t105,\n\t110,\n\t103,\n\t32,\n\t65,\n\t114,\n\t105,\n\t122,\n\t111,\n\t110,\n\t97,\n\t99,\n\t114,\n\t101,\n\t100,\n\t105,\n\t116,\n\t115,\n\t41,\n\t59,\n\t10,\n\t125,\n\t41,\n\t59,\n\t10,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t105,\n\t110,\n\t32,\n\t116,\n\t117,\n\t114,\n\t110,\n\t67,\n\t111,\n\t108,\n\t108,\n\t105,\n\t110,\n\t115,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t32,\n\t66,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t104,\n\t97,\n\t114,\n\t103,\n\t101,\n\t100,\n\t84,\n\t105,\n\t116,\n\t108,\n\t101,\n\t34,\n\t62,\n\t67,\n\t97,\n\t112,\n\t116,\n\t97,\n\t105,\n\t110,\n\t115,\n\t112,\n\t101,\n\t108,\n\t108,\n\t101,\n\t100,\n\t103,\n\t111,\n\t100,\n\t100,\n\t101,\n\t115,\n\t115,\n\t84,\n\t97,\n\t103,\n\t32,\n\t45,\n\t45,\n\t62,\n\t65,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t98,\n\t117,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t82,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t32,\n\t112,\n\t97,\n\t116,\n\t105,\n\t101,\n\t110,\n\t116,\n\t98,\n\t97,\n\t99,\n\t107,\n\t32,\n\t105,\n\t110,\n\t61,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t38,\n\t76,\n\t105,\n\t110,\n\t99,\n\t111,\n\t108,\n\t110,\n\t119,\n\t101,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t67,\n\t111,\n\t117,\n\t110,\n\t116,\n\t101,\n\t114,\n\t74,\n\t117,\n\t100,\n\t97,\n\t105,\n\t115,\n\t109,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t39,\n\t93,\n\t41,\n\t59,\n\t10,\n\t32,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t117,\n\t110,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t39,\n\t44,\n\t98,\n\t111,\n\t116,\n\t104,\n\t32,\n\t105,\n\t110,\n\t110,\n\t111,\n\t116,\n\t32,\n\t97,\n\t108,\n\t108,\n\t10,\n\t10,\n\t60,\n\t33,\n\t45,\n\t45,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t104,\n\t97,\n\t114,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t115,\n\t111,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t99,\n\t108,\n\t105,\n\t101,\n\t110,\n\t116,\n\t115,\n\t115,\n\t116,\n\t114,\n\t101,\n\t101,\n\t116,\n\t115,\n\t66,\n\t101,\n\t114,\n\t110,\n\t97,\n\t114,\n\t100,\n\t97,\n\t115,\n\t115,\n\t101,\n\t114,\n\t116,\n\t115,\n\t116,\n\t101,\n\t110,\n\t100,\n\t32,\n\t116,\n\t111,\n\t102,\n\t97,\n\t110,\n\t116,\n\t97,\n\t115,\n\t121,\n\t100,\n\t111,\n\t119,\n\t110,\n\t32,\n\t105,\n\t110,\n\t104,\n\t97,\n\t114,\n\t98,\n\t111,\n\t117,\n\t114,\n\t70,\n\t114,\n\t101,\n\t101,\n\t100,\n\t111,\n\t109,\n\t106,\n\t101,\n\t119,\n\t101,\n\t108,\n\t114,\n\t121,\n\t47,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t46,\n\t46,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t108,\n\t101,\n\t103,\n\t101,\n\t110,\n\t100,\n\t115,\n\t105,\n\t115,\n\t32,\n\t109,\n\t97,\n\t100,\n\t101,\n\t109,\n\t111,\n\t100,\n\t101,\n\t114,\n\t110,\n\t32,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t111,\n\t110,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t116,\n\t111,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t34,\n\t32,\n\t108,\n\t105,\n\t110,\n\t101,\n\t97,\n\t114,\n\t32,\n\t112,\n\t97,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t97,\n\t110,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t114,\n\t97,\n\t114,\n\t101,\n\t108,\n\t121,\n\t32,\n\t97,\n\t99,\n\t114,\n\t111,\n\t110,\n\t121,\n\t109,\n\t100,\n\t101,\n\t108,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t101,\n\t114,\n\t48,\n\t48,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t97,\n\t115,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t47,\n\t42,\n\t32,\n\t60,\n\t33,\n\t91,\n\t67,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t32,\n\t61,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t111,\n\t119,\n\t101,\n\t115,\n\t116,\n\t32,\n\t112,\n\t105,\n\t99,\n\t107,\n\t101,\n\t100,\n\t32,\n\t101,\n\t115,\n\t99,\n\t97,\n\t112,\n\t101,\n\t100,\n\t117,\n\t115,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t115,\n\t32,\n\t80,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t77,\n\t97,\n\t116,\n\t116,\n\t104,\n\t101,\n\t119,\n\t116,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t115,\n\t100,\n\t97,\n\t109,\n\t97,\n\t103,\n\t101,\n\t100,\n\t119,\n\t97,\n\t121,\n\t32,\n\t102,\n\t111,\n\t114,\n\t108,\n\t97,\n\t119,\n\t115,\n\t32,\n\t111,\n\t102,\n\t101,\n\t97,\n\t115,\n\t121,\n\t32,\n\t116,\n\t111,\n\t32,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t32,\n\t32,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t125,\n\t99,\n\t97,\n\t116,\n\t99,\n\t104,\n\t40,\n\t115,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t104,\n\t105,\n\t110,\n\t102,\n\t111,\n\t98,\n\t111,\n\t120,\n\t119,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t111,\n\t112,\n\t97,\n\t105,\n\t110,\n\t116,\n\t101,\n\t100,\n\t99,\n\t105,\n\t116,\n\t105,\n\t122,\n\t101,\n\t110,\n\t73,\n\t32,\n\t100,\n\t111,\n\t110,\n\t39,\n\t116,\n\t114,\n\t101,\n\t116,\n\t114,\n\t101,\n\t97,\n\t116,\n\t46,\n\t32,\n\t83,\n\t111,\n\t109,\n\t101,\n\t32,\n\t119,\n\t119,\n\t46,\n\t34,\n\t41,\n\t59,\n\t10,\n\t98,\n\t111,\n\t109,\n\t98,\n\t105,\n\t110,\n\t103,\n\t109,\n\t97,\n\t105,\n\t108,\n\t116,\n\t111,\n\t58,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t105,\n\t110,\n\t46,\n\t32,\n\t77,\n\t97,\n\t110,\n\t121,\n\t32,\n\t99,\n\t97,\n\t114,\n\t114,\n\t105,\n\t101,\n\t115,\n\t124,\n\t124,\n\t123,\n\t125,\n\t59,\n\t119,\n\t105,\n\t119,\n\t111,\n\t114,\n\t107,\n\t32,\n\t111,\n\t102,\n\t115,\n\t121,\n\t110,\n\t111,\n\t110,\n\t121,\n\t109,\n\t100,\n\t101,\n\t102,\n\t101,\n\t97,\n\t116,\n\t115,\n\t102,\n\t97,\n\t118,\n\t111,\n\t114,\n\t101,\n\t100,\n\t111,\n\t112,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t112,\n\t97,\n\t103,\n\t101,\n\t84,\n\t114,\n\t97,\n\t117,\n\t110,\n\t108,\n\t101,\n\t115,\n\t115,\n\t32,\n\t115,\n\t101,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t108,\n\t101,\n\t102,\n\t116,\n\t34,\n\t62,\n\t60,\n\t99,\n\t111,\n\t109,\n\t83,\n\t99,\n\t111,\n\t114,\n\t65,\n\t108,\n\t108,\n\t32,\n\t116,\n\t104,\n\t101,\n\t106,\n\t81,\n\t117,\n\t101,\n\t114,\n\t121,\n\t46,\n\t116,\n\t111,\n\t117,\n\t114,\n\t105,\n\t115,\n\t116,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t99,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t34,\n\t32,\n\t87,\n\t105,\n\t108,\n\t104,\n\t101,\n\t108,\n\t109,\n\t115,\n\t117,\n\t98,\n\t117,\n\t114,\n\t98,\n\t115,\n\t103,\n\t101,\n\t110,\n\t117,\n\t105,\n\t110,\n\t101,\n\t98,\n\t105,\n\t115,\n\t104,\n\t111,\n\t112,\n\t115,\n\t46,\n\t115,\n\t112,\n\t108,\n\t105,\n\t116,\n\t40,\n\t103,\n\t108,\n\t111,\n\t98,\n\t97,\n\t108,\n\t32,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t115,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t111,\n\t102,\n\t110,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t108,\n\t67,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t115,\n\t101,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t108,\n\t101,\n\t102,\n\t116,\n\t32,\n\t116,\n\t111,\n\t99,\n\t104,\n\t105,\n\t101,\n\t102,\n\t108,\n\t121,\n\t45,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t45,\n\t98,\n\t97,\n\t110,\n\t110,\n\t101,\n\t114,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t10,\n\t10,\n\t46,\n\t32,\n\t87,\n\t104,\n\t101,\n\t110,\n\t32,\n\t105,\n\t110,\n\t32,\n\t98,\n\t111,\n\t116,\n\t104,\n\t100,\n\t105,\n\t115,\n\t109,\n\t105,\n\t115,\n\t115,\n\t69,\n\t120,\n\t112,\n\t108,\n\t111,\n\t114,\n\t101,\n\t97,\n\t108,\n\t119,\n\t97,\n\t121,\n\t115,\n\t32,\n\t118,\n\t105,\n\t97,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t112,\n\t97,\n\t195,\n\t177,\n\t111,\n\t108,\n\t119,\n\t101,\n\t108,\n\t102,\n\t97,\n\t114,\n\t101,\n\t114,\n\t117,\n\t108,\n\t105,\n\t110,\n\t103,\n\t32,\n\t97,\n\t114,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t99,\n\t97,\n\t112,\n\t116,\n\t97,\n\t105,\n\t110,\n\t104,\n\t105,\n\t115,\n\t32,\n\t115,\n\t111,\n\t110,\n\t114,\n\t117,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t104,\n\t101,\n\t32,\n\t116,\n\t111,\n\t111,\n\t107,\n\t105,\n\t116,\n\t115,\n\t101,\n\t108,\n\t102,\n\t44,\n\t61,\n\t48,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t40,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t115,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t115,\n\t116,\n\t111,\n\t32,\n\t109,\n\t97,\n\t107,\n\t101,\n\t99,\n\t111,\n\t109,\n\t47,\n\t112,\n\t97,\n\t103,\n\t77,\n\t97,\n\t114,\n\t116,\n\t105,\n\t110,\n\t32,\n\t75,\n\t101,\n\t110,\n\t110,\n\t101,\n\t100,\n\t121,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t115,\n\t102,\n\t117,\n\t108,\n\t108,\n\t32,\n\t111,\n\t102,\n\t104,\n\t97,\n\t110,\n\t100,\n\t108,\n\t101,\n\t100,\n\t66,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t115,\n\t47,\n\t47,\n\t45,\n\t45,\n\t62,\n\t60,\n\t47,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t115,\n\t101,\n\t115,\n\t115,\n\t101,\n\t110,\n\t99,\n\t101,\n\t104,\n\t105,\n\t109,\n\t32,\n\t116,\n\t111,\n\t32,\n\t105,\n\t116,\n\t115,\n\t32,\n\t98,\n\t121,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t46,\n\t109,\n\t105,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t116,\n\t111,\n\t32,\n\t116,\n\t97,\n\t107,\n\t101,\n\t119,\n\t97,\n\t121,\n\t115,\n\t32,\n\t116,\n\t111,\n\t115,\n\t46,\n\t111,\n\t114,\n\t103,\n\t47,\n\t108,\n\t97,\n\t100,\n\t118,\n\t105,\n\t115,\n\t101,\n\t100,\n\t112,\n\t101,\n\t110,\n\t97,\n\t108,\n\t116,\n\t121,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t58,\n\t105,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t76,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t115,\n\t97,\n\t32,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t72,\n\t101,\n\t114,\n\t98,\n\t101,\n\t114,\n\t116,\n\t115,\n\t116,\n\t114,\n\t105,\n\t107,\n\t101,\n\t115,\n\t32,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t115,\n\t46,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t102,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t111,\n\t118,\n\t101,\n\t114,\n\t108,\n\t97,\n\t112,\n\t115,\n\t108,\n\t111,\n\t119,\n\t108,\n\t121,\n\t32,\n\t108,\n\t101,\n\t115,\n\t115,\n\t101,\n\t114,\n\t32,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t60,\n\t47,\n\t112,\n\t62,\n\t10,\n\t9,\n\t9,\n\t105,\n\t116,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t114,\n\t97,\n\t110,\n\t107,\n\t101,\n\t100,\n\t32,\n\t114,\n\t97,\n\t116,\n\t101,\n\t32,\n\t111,\n\t102,\n\t117,\n\t108,\n\t62,\n\t13,\n\t10,\n\t32,\n\t32,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t112,\n\t97,\n\t105,\n\t114,\n\t32,\n\t111,\n\t102,\n\t109,\n\t97,\n\t107,\n\t101,\n\t32,\n\t105,\n\t116,\n\t75,\n\t111,\n\t110,\n\t116,\n\t97,\n\t107,\n\t116,\n\t65,\n\t110,\n\t116,\n\t111,\n\t110,\n\t105,\n\t111,\n\t104,\n\t97,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t114,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t115,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t115,\n\t116,\n\t114,\n\t101,\n\t97,\n\t109,\n\t115,\n\t116,\n\t114,\n\t97,\n\t112,\n\t112,\n\t101,\n\t100,\n\t34,\n\t41,\n\t46,\n\t99,\n\t115,\n\t115,\n\t40,\n\t104,\n\t111,\n\t115,\n\t116,\n\t105,\n\t108,\n\t101,\n\t108,\n\t101,\n\t97,\n\t100,\n\t32,\n\t116,\n\t111,\n\t108,\n\t105,\n\t116,\n\t116,\n\t108,\n\t101,\n\t32,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t115,\n\t44,\n\t80,\n\t105,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t45,\n\t45,\n\t62,\n\t13,\n\t10,\n\t13,\n\t10,\n\t32,\n\t114,\n\t111,\n\t119,\n\t115,\n\t61,\n\t34,\n\t32,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t105,\n\t110,\n\t118,\n\t101,\n\t114,\n\t115,\n\t101,\n\t60,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t67,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t86,\n\t62,\n\t60,\n\t92,\n\t47,\n\t115,\n\t99,\n\t114,\n\t115,\n\t111,\n\t108,\n\t118,\n\t105,\n\t110,\n\t103,\n\t67,\n\t104,\n\t97,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t108,\n\t97,\n\t118,\n\t101,\n\t114,\n\t121,\n\t119,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t97,\n\t115,\n\t33,\n\t61,\n\t32,\n\t39,\n\t117,\n\t110,\n\t100,\n\t102,\n\t111,\n\t114,\n\t32,\n\t97,\n\t108,\n\t108,\n\t112,\n\t97,\n\t114,\n\t116,\n\t108,\n\t121,\n\t32,\n\t45,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t65,\n\t114,\n\t97,\n\t98,\n\t105,\n\t97,\n\t110,\n\t98,\n\t97,\n\t99,\n\t107,\n\t101,\n\t100,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t117,\n\t110,\n\t105,\n\t116,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t98,\n\t105,\n\t108,\n\t101,\n\t45,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t44,\n\t105,\n\t115,\n\t32,\n\t104,\n\t111,\n\t109,\n\t101,\n\t114,\n\t105,\n\t115,\n\t107,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t115,\n\t105,\n\t114,\n\t101,\n\t100,\n\t67,\n\t108,\n\t105,\n\t110,\n\t116,\n\t111,\n\t110,\n\t99,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t97,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t98,\n\t101,\n\t99,\n\t111,\n\t109,\n\t101,\n\t32,\n\t110,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t112,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t77,\n\t105,\n\t100,\n\t100,\n\t108,\n\t101,\n\t32,\n\t101,\n\t97,\n\t100,\n\t39,\n\t41,\n\t91,\n\t48,\n\t67,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t115,\n\t115,\n\t116,\n\t117,\n\t100,\n\t105,\n\t111,\n\t115,\n\t62,\n\t38,\n\t99,\n\t111,\n\t112,\n\t121,\n\t59,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t34,\n\t62,\n\t97,\n\t115,\n\t115,\n\t101,\n\t109,\n\t98,\n\t108,\n\t109,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t100,\n\t119,\n\t105,\n\t100,\n\t103,\n\t101,\n\t116,\n\t46,\n\t112,\n\t115,\n\t58,\n\t34,\n\t32,\n\t63,\n\t32,\n\t114,\n\t101,\n\t98,\n\t117,\n\t105,\n\t108,\n\t116,\n\t98,\n\t121,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t70,\n\t111,\n\t114,\n\t109,\n\t101,\n\t114,\n\t32,\n\t101,\n\t100,\n\t105,\n\t116,\n\t111,\n\t114,\n\t115,\n\t100,\n\t101,\n\t108,\n\t97,\n\t121,\n\t101,\n\t100,\n\t67,\n\t97,\n\t110,\n\t111,\n\t110,\n\t105,\n\t99,\n\t104,\n\t97,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t117,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t98,\n\t117,\n\t116,\n\t32,\n\t97,\n\t114,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t97,\n\t108,\n\t66,\n\t97,\n\t98,\n\t121,\n\t108,\n\t111,\n\t110,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t32,\n\t99,\n\t97,\n\t114,\n\t114,\n\t105,\n\t101,\n\t114,\n\t67,\n\t111,\n\t109,\n\t109,\n\t97,\n\t110,\n\t100,\n\t105,\n\t116,\n\t115,\n\t32,\n\t117,\n\t115,\n\t101,\n\t65,\n\t115,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t99,\n\t111,\n\t117,\n\t114,\n\t115,\n\t101,\n\t115,\n\t97,\n\t32,\n\t116,\n\t104,\n\t105,\n\t114,\n\t100,\n\t100,\n\t101,\n\t110,\n\t111,\n\t116,\n\t101,\n\t115,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t105,\n\t110,\n\t72,\n\t111,\n\t117,\n\t115,\n\t116,\n\t111,\n\t110,\n\t50,\n\t48,\n\t112,\n\t120,\n\t59,\n\t34,\n\t62,\n\t97,\n\t99,\n\t99,\n\t117,\n\t115,\n\t101,\n\t100,\n\t100,\n\t111,\n\t117,\n\t98,\n\t108,\n\t101,\n\t32,\n\t103,\n\t111,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t70,\n\t97,\n\t109,\n\t111,\n\t117,\n\t115,\n\t32,\n\t41,\n\t46,\n\t98,\n\t105,\n\t110,\n\t100,\n\t40,\n\t112,\n\t114,\n\t105,\n\t101,\n\t115,\n\t116,\n\t115,\n\t32,\n\t79,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t105,\n\t110,\n\t32,\n\t74,\n\t117,\n\t108,\n\t121,\n\t115,\n\t116,\n\t32,\n\t43,\n\t32,\n\t34,\n\t103,\n\t99,\n\t111,\n\t110,\n\t115,\n\t117,\n\t108,\n\t116,\n\t100,\n\t101,\n\t99,\n\t105,\n\t109,\n\t97,\n\t108,\n\t104,\n\t101,\n\t108,\n\t112,\n\t102,\n\t117,\n\t108,\n\t114,\n\t101,\n\t118,\n\t105,\n\t118,\n\t101,\n\t100,\n\t105,\n\t115,\n\t32,\n\t118,\n\t101,\n\t114,\n\t121,\n\t114,\n\t39,\n\t43,\n\t39,\n\t105,\n\t112,\n\t116,\n\t108,\n\t111,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t102,\n\t101,\n\t109,\n\t97,\n\t108,\n\t101,\n\t115,\n\t105,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t115,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t115,\n\t100,\n\t97,\n\t121,\n\t115,\n\t32,\n\t111,\n\t102,\n\t97,\n\t114,\n\t114,\n\t105,\n\t118,\n\t97,\n\t108,\n\t102,\n\t117,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t60,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t102,\n\t111,\n\t114,\n\t99,\n\t105,\n\t110,\n\t103,\n\t83,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t40,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t9,\n\t9,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t105,\n\t115,\n\t101,\n\t110,\n\t99,\n\t111,\n\t100,\n\t101,\n\t100,\n\t46,\n\t32,\n\t32,\n\t84,\n\t104,\n\t101,\n\t32,\n\t98,\n\t97,\n\t108,\n\t108,\n\t111,\n\t111,\n\t110,\n\t100,\n\t111,\n\t110,\n\t101,\n\t32,\n\t98,\n\t121,\n\t47,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t98,\n\t103,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t108,\n\t97,\n\t119,\n\t32,\n\t111,\n\t102,\n\t32,\n\t73,\n\t110,\n\t100,\n\t105,\n\t97,\n\t110,\n\t97,\n\t97,\n\t118,\n\t111,\n\t105,\n\t100,\n\t101,\n\t100,\n\t98,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t50,\n\t112,\n\t120,\n\t32,\n\t51,\n\t112,\n\t120,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t46,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t97,\n\t112,\n\t111,\n\t108,\n\t105,\n\t99,\n\t121,\n\t46,\n\t109,\n\t101,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t45,\n\t61,\n\t32,\n\t116,\n\t114,\n\t117,\n\t101,\n\t59,\n\t102,\n\t111,\n\t114,\n\t32,\n\t117,\n\t115,\n\t101,\n\t115,\n\t99,\n\t114,\n\t101,\n\t101,\n\t110,\n\t46,\n\t73,\n\t110,\n\t100,\n\t105,\n\t97,\n\t110,\n\t32,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t32,\n\t61,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t121,\n\t44,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t32,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t100,\n\t114,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t101,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t108,\n\t115,\n\t97,\n\t109,\n\t101,\n\t32,\n\t97,\n\t115,\n\t110,\n\t111,\n\t116,\n\t105,\n\t99,\n\t101,\n\t100,\n\t118,\n\t105,\n\t101,\n\t119,\n\t101,\n\t114,\n\t115,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t10,\n\t32,\n\t105,\n\t115,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t115,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t115,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t101,\n\t119,\n\t105,\n\t115,\n\t32,\n\t106,\n\t117,\n\t115,\n\t116,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t110,\n\t116,\n\t32,\n\t83,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t119,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t104,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t104,\n\t105,\n\t112,\n\t112,\n\t101,\n\t100,\n\t98,\n\t114,\n\t62,\n\t60,\n\t98,\n\t114,\n\t62,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t111,\n\t102,\n\t99,\n\t117,\n\t105,\n\t115,\n\t105,\n\t110,\n\t101,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t32,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t65,\n\t100,\n\t109,\n\t105,\n\t114,\n\t97,\n\t108,\n\t32,\n\t102,\n\t105,\n\t120,\n\t101,\n\t100,\n\t59,\n\t110,\n\t111,\n\t114,\n\t109,\n\t97,\n\t108,\n\t32,\n\t77,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t80,\n\t114,\n\t101,\n\t115,\n\t115,\n\t44,\n\t32,\n\t111,\n\t110,\n\t116,\n\t97,\n\t114,\n\t105,\n\t111,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t116,\n\t114,\n\t121,\n\t32,\n\t116,\n\t111,\n\t32,\n\t105,\n\t110,\n\t118,\n\t97,\n\t100,\n\t101,\n\t100,\n\t61,\n\t34,\n\t116,\n\t114,\n\t117,\n\t101,\n\t34,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t105,\n\t115,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t97,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t111,\n\t116,\n\t97,\n\t108,\n\t108,\n\t121,\n\t102,\n\t97,\n\t108,\n\t108,\n\t32,\n\t111,\n\t102,\n\t125,\n\t41,\n\t59,\n\t13,\n\t10,\n\t32,\n\t32,\n\t105,\n\t109,\n\t109,\n\t101,\n\t110,\n\t115,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t32,\n\t105,\n\t110,\n\t115,\n\t101,\n\t116,\n\t32,\n\t111,\n\t117,\n\t116,\n\t115,\n\t97,\n\t116,\n\t105,\n\t115,\n\t102,\n\t121,\n\t116,\n\t111,\n\t32,\n\t102,\n\t105,\n\t110,\n\t100,\n\t100,\n\t111,\n\t119,\n\t110,\n\t32,\n\t116,\n\t111,\n\t108,\n\t111,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t80,\n\t108,\n\t97,\n\t121,\n\t101,\n\t114,\n\t115,\n\t105,\n\t110,\n\t32,\n\t74,\n\t117,\n\t110,\n\t101,\n\t113,\n\t117,\n\t97,\n\t110,\n\t116,\n\t117,\n\t109,\n\t110,\n\t111,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t32,\n\t116,\n\t111,\n\t100,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t70,\n\t105,\n\t110,\n\t110,\n\t105,\n\t115,\n\t104,\n\t115,\n\t114,\n\t99,\n\t32,\n\t61,\n\t32,\n\t40,\n\t115,\n\t105,\n\t110,\n\t103,\n\t108,\n\t101,\n\t32,\n\t104,\n\t101,\n\t108,\n\t112,\n\t32,\n\t111,\n\t102,\n\t71,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t32,\n\t108,\n\t97,\n\t119,\n\t32,\n\t97,\n\t110,\n\t100,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t101,\n\t100,\n\t102,\n\t111,\n\t114,\n\t101,\n\t115,\n\t116,\n\t115,\n\t99,\n\t111,\n\t111,\n\t107,\n\t105,\n\t110,\n\t103,\n\t115,\n\t112,\n\t97,\n\t99,\n\t101,\n\t34,\n\t62,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t45,\n\t119,\n\t101,\n\t108,\n\t108,\n\t32,\n\t97,\n\t115,\n\t83,\n\t116,\n\t97,\n\t110,\n\t108,\n\t101,\n\t121,\n\t98,\n\t114,\n\t105,\n\t100,\n\t103,\n\t101,\n\t115,\n\t47,\n\t103,\n\t108,\n\t111,\n\t98,\n\t97,\n\t108,\n\t67,\n\t114,\n\t111,\n\t97,\n\t116,\n\t105,\n\t97,\n\t32,\n\t65,\n\t98,\n\t111,\n\t117,\n\t116,\n\t32,\n\t91,\n\t48,\n\t93,\n\t59,\n\t10,\n\t32,\n\t32,\n\t105,\n\t116,\n\t44,\n\t32,\n\t97,\n\t110,\n\t100,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t101,\n\t100,\n\t98,\n\t101,\n\t105,\n\t110,\n\t103,\n\t32,\n\t97,\n\t41,\n\t123,\n\t116,\n\t104,\n\t114,\n\t111,\n\t119,\n\t104,\n\t101,\n\t32,\n\t109,\n\t97,\n\t100,\n\t101,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t101,\n\t114,\n\t101,\n\t116,\n\t104,\n\t105,\n\t99,\n\t97,\n\t108,\n\t70,\n\t70,\n\t70,\n\t70,\n\t70,\n\t70,\n\t34,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t34,\n\t108,\n\t105,\n\t107,\n\t101,\n\t32,\n\t97,\n\t32,\n\t101,\n\t109,\n\t112,\n\t108,\n\t111,\n\t121,\n\t115,\n\t108,\n\t105,\n\t118,\n\t101,\n\t32,\n\t105,\n\t110,\n\t97,\n\t115,\n\t32,\n\t115,\n\t101,\n\t101,\n\t110,\n\t112,\n\t114,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t117,\n\t98,\n\t45,\n\t108,\n\t105,\n\t110,\n\t107,\n\t114,\n\t101,\n\t106,\n\t101,\n\t99,\n\t116,\n\t115,\n\t97,\n\t110,\n\t100,\n\t32,\n\t117,\n\t115,\n\t101,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t34,\n\t62,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t101,\n\t100,\n\t102,\n\t101,\n\t101,\n\t100,\n\t105,\n\t110,\n\t103,\n\t78,\n\t117,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t111,\n\t32,\n\t104,\n\t101,\n\t108,\n\t112,\n\t87,\n\t111,\n\t109,\n\t101,\n\t110,\n\t39,\n\t115,\n\t78,\n\t101,\n\t105,\n\t116,\n\t104,\n\t101,\n\t114,\n\t77,\n\t101,\n\t120,\n\t105,\n\t99,\n\t97,\n\t110,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t105,\n\t110,\n\t60,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t98,\n\t121,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t104,\n\t101,\n\t97,\n\t108,\n\t116,\n\t104,\n\t121,\n\t108,\n\t97,\n\t119,\n\t115,\n\t117,\n\t105,\n\t116,\n\t100,\n\t101,\n\t118,\n\t105,\n\t115,\n\t101,\n\t100,\n\t46,\n\t112,\n\t117,\n\t115,\n\t104,\n\t40,\n\t123,\n\t115,\n\t101,\n\t108,\n\t108,\n\t101,\n\t114,\n\t115,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t121,\n\t32,\n\t84,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t46,\n\t99,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t32,\n\t73,\n\t109,\n\t97,\n\t103,\n\t101,\n\t40,\n\t111,\n\t108,\n\t100,\n\t101,\n\t114,\n\t34,\n\t62,\n\t117,\n\t115,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t32,\n\t83,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t117,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t114,\n\t32,\n\t111,\n\t112,\n\t101,\n\t110,\n\t32,\n\t116,\n\t111,\n\t33,\n\t45,\n\t45,\n\t32,\n\t101,\n\t110,\n\t100,\n\t108,\n\t105,\n\t101,\n\t115,\n\t32,\n\t105,\n\t110,\n\t39,\n\t93,\n\t41,\n\t59,\n\t13,\n\t10,\n\t32,\n\t32,\n\t109,\n\t97,\n\t114,\n\t107,\n\t101,\n\t116,\n\t119,\n\t104,\n\t111,\n\t32,\n\t105,\n\t115,\n\t32,\n\t40,\n\t34,\n\t68,\n\t79,\n\t77,\n\t67,\n\t111,\n\t109,\n\t97,\n\t110,\n\t97,\n\t103,\n\t101,\n\t100,\n\t111,\n\t110,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t116,\n\t121,\n\t112,\n\t101,\n\t111,\n\t102,\n\t32,\n\t75,\n\t105,\n\t110,\n\t103,\n\t100,\n\t111,\n\t109,\n\t112,\n\t114,\n\t111,\n\t102,\n\t105,\n\t116,\n\t115,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t115,\n\t101,\n\t116,\n\t111,\n\t32,\n\t115,\n\t104,\n\t111,\n\t119,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t59,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t105,\n\t116,\n\t100,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t100,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t105,\n\t110,\n\t109,\n\t105,\n\t120,\n\t116,\n\t117,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t99,\n\t105,\n\t115,\n\t101,\n\t97,\n\t114,\n\t105,\n\t115,\n\t105,\n\t110,\n\t103,\n\t115,\n\t114,\n\t99,\n\t32,\n\t61,\n\t32,\n\t39,\n\t109,\n\t97,\n\t107,\n\t101,\n\t32,\n\t97,\n\t32,\n\t115,\n\t101,\n\t99,\n\t117,\n\t114,\n\t101,\n\t100,\n\t66,\n\t97,\n\t112,\n\t116,\n\t105,\n\t115,\n\t116,\n\t118,\n\t111,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t10,\n\t9,\n\t9,\n\t118,\n\t97,\n\t114,\n\t32,\n\t77,\n\t97,\n\t114,\n\t99,\n\t104,\n\t32,\n\t50,\n\t103,\n\t114,\n\t101,\n\t119,\n\t32,\n\t117,\n\t112,\n\t67,\n\t108,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t46,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t101,\n\t115,\n\t107,\n\t105,\n\t108,\n\t108,\n\t101,\n\t100,\n\t119,\n\t97,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t102,\n\t97,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t99,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t62,\n\t116,\n\t111,\n\t32,\n\t119,\n\t111,\n\t114,\n\t107,\n\t114,\n\t101,\n\t100,\n\t117,\n\t99,\n\t101,\n\t115,\n\t104,\n\t97,\n\t115,\n\t32,\n\t104,\n\t97,\n\t100,\n\t101,\n\t114,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t115,\n\t104,\n\t111,\n\t119,\n\t40,\n\t41,\n\t59,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t98,\n\t111,\n\t111,\n\t107,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t32,\n\t97,\n\t114,\n\t101,\n\t97,\n\t61,\n\t61,\n\t32,\n\t34,\n\t104,\n\t116,\n\t116,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t10,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t99,\n\t111,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t102,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t32,\n\t99,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t46,\n\t114,\n\t101,\n\t108,\n\t121,\n\t32,\n\t111,\n\t110,\n\t104,\n\t111,\n\t115,\n\t116,\n\t101,\n\t100,\n\t32,\n\t46,\n\t99,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t104,\n\t101,\n\t32,\n\t119,\n\t101,\n\t110,\n\t116,\n\t98,\n\t117,\n\t116,\n\t32,\n\t102,\n\t111,\n\t114,\n\t115,\n\t112,\n\t114,\n\t101,\n\t97,\n\t100,\n\t32,\n\t70,\n\t97,\n\t109,\n\t105,\n\t108,\n\t121,\n\t32,\n\t97,\n\t32,\n\t109,\n\t101,\n\t97,\n\t110,\n\t115,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t111,\n\t114,\n\t117,\n\t109,\n\t115,\n\t46,\n\t102,\n\t111,\n\t111,\n\t116,\n\t97,\n\t103,\n\t101,\n\t34,\n\t62,\n\t77,\n\t111,\n\t98,\n\t105,\n\t108,\n\t67,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t34,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t97,\n\t115,\n\t32,\n\t104,\n\t105,\n\t103,\n\t104,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t115,\n\t101,\n\t45,\n\t45,\n\t62,\n\t60,\n\t33,\n\t45,\n\t45,\n\t102,\n\t101,\n\t109,\n\t97,\n\t108,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t115,\n\t101,\n\t101,\n\t110,\n\t105,\n\t109,\n\t112,\n\t108,\n\t105,\n\t101,\n\t100,\n\t115,\n\t101,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t32,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t104,\n\t105,\n\t115,\n\t102,\n\t97,\n\t115,\n\t116,\n\t101,\n\t115,\n\t116,\n\t98,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t115,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t95,\n\t98,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t34,\n\t62,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t73,\n\t110,\n\t102,\n\t111,\n\t98,\n\t111,\n\t120,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t115,\n\t44,\n\t97,\n\t32,\n\t121,\n\t111,\n\t117,\n\t110,\n\t103,\n\t97,\n\t110,\n\t100,\n\t32,\n\t97,\n\t114,\n\t101,\n\t78,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t32,\n\t99,\n\t104,\n\t101,\n\t97,\n\t112,\n\t101,\n\t114,\n\t84,\n\t105,\n\t109,\n\t101,\n\t111,\n\t117,\n\t116,\n\t97,\n\t110,\n\t100,\n\t32,\n\t104,\n\t97,\n\t115,\n\t101,\n\t110,\n\t103,\n\t105,\n\t110,\n\t101,\n\t115,\n\t119,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t40,\n\t109,\n\t111,\n\t115,\n\t116,\n\t108,\n\t121,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t32,\n\t102,\n\t105,\n\t110,\n\t100,\n\t32,\n\t97,\n\t32,\n\t45,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t80,\n\t114,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t97,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t95,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t44,\n\t108,\n\t101,\n\t103,\n\t97,\n\t108,\n\t108,\n\t121,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t44,\n\t108,\n\t97,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t111,\n\t114,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t110,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t110,\n\t103,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t108,\n\t101,\n\t108,\n\t111,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t65,\n\t103,\n\t97,\n\t105,\n\t110,\n\t115,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t97,\n\t121,\n\t107,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t112,\n\t120,\n\t59,\n\t34,\n\t62,\n\t13,\n\t10,\n\t112,\n\t117,\n\t115,\n\t104,\n\t101,\n\t100,\n\t32,\n\t97,\n\t98,\n\t97,\n\t110,\n\t100,\n\t111,\n\t110,\n\t110,\n\t117,\n\t109,\n\t101,\n\t114,\n\t97,\n\t108,\n\t67,\n\t101,\n\t114,\n\t116,\n\t97,\n\t105,\n\t110,\n\t73,\n\t110,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t105,\n\t110,\n\t111,\n\t114,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t110,\n\t97,\n\t109,\n\t101,\n\t32,\n\t105,\n\t115,\n\t97,\n\t110,\n\t100,\n\t44,\n\t32,\n\t105,\n\t110,\n\t99,\n\t114,\n\t111,\n\t119,\n\t110,\n\t101,\n\t100,\n\t73,\n\t83,\n\t66,\n\t78,\n\t32,\n\t48,\n\t45,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t115,\n\t79,\n\t99,\n\t116,\n\t111,\n\t98,\n\t101,\n\t114,\n\t109,\n\t97,\n\t121,\n\t32,\n\t110,\n\t111,\n\t116,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t32,\n\t108,\n\t97,\n\t116,\n\t101,\n\t32,\n\t105,\n\t110,\n\t68,\n\t101,\n\t102,\n\t101,\n\t110,\n\t99,\n\t101,\n\t101,\n\t110,\n\t97,\n\t99,\n\t116,\n\t101,\n\t100,\n\t119,\n\t105,\n\t115,\n\t104,\n\t32,\n\t116,\n\t111,\n\t98,\n\t114,\n\t111,\n\t97,\n\t100,\n\t108,\n\t121,\n\t99,\n\t111,\n\t111,\n\t108,\n\t105,\n\t110,\n\t103,\n\t111,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t61,\n\t105,\n\t116,\n\t46,\n\t32,\n\t84,\n\t104,\n\t101,\n\t114,\n\t101,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t77,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t32,\n\t97,\n\t115,\n\t115,\n\t117,\n\t109,\n\t101,\n\t115,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t10,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t46,\n\t105,\n\t110,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t61,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t95,\n\t97,\n\t32,\n\t103,\n\t111,\n\t111,\n\t100,\n\t32,\n\t114,\n\t101,\n\t107,\n\t108,\n\t97,\n\t109,\n\t97,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t115,\n\t44,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t95,\n\t99,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t112,\n\t97,\n\t110,\n\t101,\n\t108,\n\t34,\n\t62,\n\t76,\n\t111,\n\t110,\n\t100,\n\t111,\n\t110,\n\t44,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t115,\n\t99,\n\t114,\n\t117,\n\t115,\n\t104,\n\t101,\n\t100,\n\t98,\n\t97,\n\t112,\n\t116,\n\t105,\n\t115,\n\t109,\n\t99,\n\t111,\n\t97,\n\t115,\n\t116,\n\t97,\n\t108,\n\t115,\n\t116,\n\t97,\n\t116,\n\t117,\n\t115,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t34,\n\t32,\n\t109,\n\t111,\n\t118,\n\t101,\n\t32,\n\t116,\n\t111,\n\t108,\n\t111,\n\t115,\n\t116,\n\t32,\n\t105,\n\t110,\n\t98,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t32,\n\t105,\n\t109,\n\t112,\n\t108,\n\t105,\n\t101,\n\t115,\n\t114,\n\t105,\n\t118,\n\t97,\n\t108,\n\t114,\n\t121,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t114,\n\t115,\n\t32,\n\t83,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t80,\n\t101,\n\t114,\n\t104,\n\t97,\n\t112,\n\t115,\n\t101,\n\t115,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t100,\n\t102,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t108,\n\t97,\n\t115,\n\t116,\n\t101,\n\t100,\n\t32,\n\t114,\n\t105,\n\t115,\n\t101,\n\t32,\n\t105,\n\t110,\n\t71,\n\t101,\n\t110,\n\t101,\n\t115,\n\t105,\n\t115,\n\t118,\n\t105,\n\t101,\n\t119,\n\t32,\n\t111,\n\t102,\n\t114,\n\t105,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t115,\n\t101,\n\t101,\n\t109,\n\t32,\n\t116,\n\t111,\n\t98,\n\t117,\n\t116,\n\t32,\n\t105,\n\t110,\n\t32,\n\t98,\n\t97,\n\t99,\n\t107,\n\t105,\n\t110,\n\t103,\n\t104,\n\t101,\n\t32,\n\t119,\n\t105,\n\t108,\n\t108,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t32,\n\t97,\n\t103,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t99,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t46,\n\t102,\n\t108,\n\t111,\n\t119,\n\t32,\n\t111,\n\t102,\n\t32,\n\t76,\n\t97,\n\t116,\n\t101,\n\t114,\n\t32,\n\t97,\n\t108,\n\t108,\n\t32,\n\t98,\n\t117,\n\t116,\n\t72,\n\t105,\n\t103,\n\t104,\n\t119,\n\t97,\n\t121,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t98,\n\t121,\n\t115,\n\t105,\n\t103,\n\t110,\n\t32,\n\t111,\n\t102,\n\t104,\n\t101,\n\t32,\n\t100,\n\t111,\n\t101,\n\t115,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t115,\n\t98,\n\t97,\n\t116,\n\t116,\n\t101,\n\t114,\n\t121,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t108,\n\t97,\n\t115,\n\t105,\n\t110,\n\t103,\n\t108,\n\t101,\n\t115,\n\t116,\n\t104,\n\t114,\n\t101,\n\t97,\n\t116,\n\t115,\n\t105,\n\t110,\n\t116,\n\t101,\n\t103,\n\t101,\n\t114,\n\t116,\n\t97,\n\t107,\n\t101,\n\t32,\n\t111,\n\t110,\n\t114,\n\t101,\n\t102,\n\t117,\n\t115,\n\t101,\n\t100,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t61,\n\t85,\n\t83,\n\t38,\n\t97,\n\t109,\n\t112,\n\t83,\n\t101,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t110,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t115,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t46,\n\t104,\n\t101,\n\t97,\n\t100,\n\t32,\n\t111,\n\t102,\n\t58,\n\t104,\n\t111,\n\t118,\n\t101,\n\t114,\n\t44,\n\t108,\n\t101,\n\t115,\n\t98,\n\t105,\n\t97,\n\t110,\n\t115,\n\t117,\n\t114,\n\t110,\n\t97,\n\t109,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t97,\n\t108,\n\t108,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t95,\n\t95,\n\t112,\n\t97,\n\t114,\n\t97,\n\t109,\n\t115,\n\t72,\n\t97,\n\t114,\n\t118,\n\t97,\n\t114,\n\t100,\n\t47,\n\t112,\n\t105,\n\t120,\n\t101,\n\t108,\n\t46,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t108,\n\t111,\n\t110,\n\t103,\n\t114,\n\t111,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t106,\n\t111,\n\t105,\n\t110,\n\t116,\n\t108,\n\t121,\n\t115,\n\t107,\n\t121,\n\t115,\n\t99,\n\t114,\n\t97,\n\t85,\n\t110,\n\t105,\n\t99,\n\t111,\n\t100,\n\t101,\n\t98,\n\t114,\n\t32,\n\t47,\n\t62,\n\t13,\n\t10,\n\t65,\n\t116,\n\t108,\n\t97,\n\t110,\n\t116,\n\t97,\n\t110,\n\t117,\n\t99,\n\t108,\n\t101,\n\t117,\n\t115,\n\t67,\n\t111,\n\t117,\n\t110,\n\t116,\n\t121,\n\t44,\n\t112,\n\t117,\n\t114,\n\t101,\n\t108,\n\t121,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t34,\n\t62,\n\t101,\n\t97,\n\t115,\n\t105,\n\t108,\n\t121,\n\t32,\n\t98,\n\t117,\n\t105,\n\t108,\n\t100,\n\t32,\n\t97,\n\t111,\n\t110,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t97,\n\t32,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t104,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t101,\n\t108,\n\t115,\n\t101,\n\t32,\n\t123,\n\t10,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t110,\n\t111,\n\t119,\n\t32,\n\t116,\n\t104,\n\t101,\n\t44,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t109,\n\t97,\n\t110,\n\t32,\n\t119,\n\t104,\n\t111,\n\t111,\n\t114,\n\t103,\n\t47,\n\t87,\n\t101,\n\t98,\n\t111,\n\t110,\n\t101,\n\t32,\n\t97,\n\t110,\n\t100,\n\t99,\n\t97,\n\t118,\n\t97,\n\t108,\n\t114,\n\t121,\n\t72,\n\t101,\n\t32,\n\t100,\n\t105,\n\t101,\n\t100,\n\t115,\n\t101,\n\t97,\n\t116,\n\t116,\n\t108,\n\t101,\n\t48,\n\t48,\n\t44,\n\t48,\n\t48,\n\t48,\n\t32,\n\t123,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t116,\n\t111,\n\t105,\n\t102,\n\t40,\n\t119,\n\t105,\n\t110,\n\t100,\n\t97,\n\t110,\n\t100,\n\t32,\n\t105,\n\t116,\n\t115,\n\t115,\n\t111,\n\t108,\n\t101,\n\t108,\n\t121,\n\t32,\n\t109,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t114,\n\t101,\n\t110,\n\t101,\n\t119,\n\t101,\n\t100,\n\t68,\n\t101,\n\t116,\n\t114,\n\t111,\n\t105,\n\t116,\n\t97,\n\t109,\n\t111,\n\t110,\n\t103,\n\t115,\n\t116,\n\t101,\n\t105,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t32,\n\t105,\n\t110,\n\t83,\n\t101,\n\t110,\n\t97,\n\t116,\n\t111,\n\t114,\n\t85,\n\t115,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t75,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t70,\n\t114,\n\t97,\n\t110,\n\t99,\n\t105,\n\t115,\n\t45,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t104,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t97,\n\t114,\n\t116,\n\t32,\n\t97,\n\t110,\n\t100,\n\t104,\n\t105,\n\t109,\n\t32,\n\t97,\n\t110,\n\t100,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t115,\n\t99,\n\t111,\n\t114,\n\t105,\n\t110,\n\t103,\n\t97,\n\t116,\n\t32,\n\t104,\n\t111,\n\t109,\n\t101,\n\t116,\n\t111,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t102,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t66,\n\t117,\n\t102,\n\t102,\n\t97,\n\t108,\n\t111,\n\t108,\n\t105,\n\t110,\n\t107,\n\t34,\n\t62,\n\t60,\n\t119,\n\t104,\n\t97,\n\t116,\n\t32,\n\t104,\n\t101,\n\t102,\n\t114,\n\t101,\n\t101,\n\t32,\n\t116,\n\t111,\n\t67,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t109,\n\t101,\n\t32,\n\t105,\n\t110,\n\t115,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t115,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t101,\n\t100,\n\t111,\n\t110,\n\t101,\n\t32,\n\t100,\n\t97,\n\t121,\n\t110,\n\t101,\n\t114,\n\t118,\n\t111,\n\t117,\n\t115,\n\t115,\n\t113,\n\t117,\n\t97,\n\t114,\n\t101,\n\t32,\n\t125,\n\t59,\n\t105,\n\t102,\n\t40,\n\t103,\n\t111,\n\t105,\n\t110,\n\t32,\n\t119,\n\t104,\n\t97,\n\t116,\n\t105,\n\t109,\n\t103,\n\t34,\n\t32,\n\t97,\n\t108,\n\t105,\n\t115,\n\t32,\n\t111,\n\t110,\n\t108,\n\t121,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t47,\n\t116,\n\t117,\n\t101,\n\t115,\n\t100,\n\t97,\n\t121,\n\t108,\n\t111,\n\t111,\n\t115,\n\t101,\n\t108,\n\t121,\n\t83,\n\t111,\n\t108,\n\t111,\n\t109,\n\t111,\n\t110,\n\t115,\n\t101,\n\t120,\n\t117,\n\t97,\n\t108,\n\t32,\n\t45,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t109,\n\t101,\n\t100,\n\t105,\n\t117,\n\t109,\n\t34,\n\t68,\n\t79,\n\t32,\n\t78,\n\t79,\n\t84,\n\t32,\n\t70,\n\t114,\n\t97,\n\t110,\n\t99,\n\t101,\n\t44,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t97,\n\t32,\n\t119,\n\t97,\n\t114,\n\t32,\n\t97,\n\t110,\n\t100,\n\t115,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t32,\n\t116,\n\t97,\n\t107,\n\t101,\n\t32,\n\t97,\n\t32,\n\t62,\n\t13,\n\t10,\n\t13,\n\t10,\n\t13,\n\t10,\n\t109,\n\t97,\n\t114,\n\t107,\n\t101,\n\t116,\n\t46,\n\t104,\n\t105,\n\t103,\n\t104,\n\t119,\n\t97,\n\t121,\n\t100,\n\t111,\n\t110,\n\t101,\n\t32,\n\t105,\n\t110,\n\t99,\n\t116,\n\t105,\n\t118,\n\t105,\n\t116,\n\t121,\n\t34,\n\t108,\n\t97,\n\t115,\n\t116,\n\t34,\n\t62,\n\t111,\n\t98,\n\t108,\n\t105,\n\t103,\n\t101,\n\t100,\n\t114,\n\t105,\n\t115,\n\t101,\n\t32,\n\t116,\n\t111,\n\t34,\n\t117,\n\t110,\n\t100,\n\t101,\n\t102,\n\t105,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t69,\n\t97,\n\t114,\n\t108,\n\t121,\n\t32,\n\t112,\n\t114,\n\t97,\n\t105,\n\t115,\n\t101,\n\t100,\n\t105,\n\t110,\n\t32,\n\t105,\n\t116,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t104,\n\t105,\n\t115,\n\t97,\n\t116,\n\t104,\n\t108,\n\t101,\n\t116,\n\t101,\n\t74,\n\t117,\n\t112,\n\t105,\n\t116,\n\t101,\n\t114,\n\t89,\n\t97,\n\t104,\n\t111,\n\t111,\n\t33,\n\t32,\n\t116,\n\t101,\n\t114,\n\t109,\n\t101,\n\t100,\n\t32,\n\t115,\n\t111,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t114,\n\t101,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t115,\n\t46,\n\t32,\n\t84,\n\t104,\n\t101,\n\t32,\n\t97,\n\t32,\n\t119,\n\t111,\n\t109,\n\t97,\n\t110,\n\t63,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t32,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t32,\n\t98,\n\t105,\n\t99,\n\t121,\n\t99,\n\t108,\n\t101,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t100,\n\t97,\n\t121,\n\t32,\n\t97,\n\t110,\n\t100,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t82,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t44,\n\t104,\n\t105,\n\t103,\n\t104,\n\t101,\n\t114,\n\t32,\n\t79,\n\t102,\n\t102,\n\t105,\n\t99,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t32,\n\t110,\n\t111,\n\t119,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t44,\n\t32,\n\t119,\n\t104,\n\t101,\n\t110,\n\t32,\n\t97,\n\t32,\n\t112,\n\t97,\n\t121,\n\t32,\n\t102,\n\t111,\n\t114,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t45,\n\t108,\n\t105,\n\t110,\n\t107,\n\t34,\n\t62,\n\t59,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t97,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t97,\n\t110,\n\t110,\n\t117,\n\t97,\n\t108,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t78,\n\t101,\n\t119,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t46,\n\t99,\n\t111,\n\t109,\n\t34,\n\t32,\n\t116,\n\t97,\n\t107,\n\t105,\n\t110,\n\t32,\n\t116,\n\t111,\n\t97,\n\t32,\n\t98,\n\t114,\n\t105,\n\t101,\n\t102,\n\t40,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t115,\n\t46,\n\t59,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t101,\n\t110,\n\t122,\n\t121,\n\t109,\n\t101,\n\t115,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t108,\n\t97,\n\t116,\n\t101,\n\t123,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t112,\n\t121,\n\t97,\n\t32,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t98,\n\t97,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t105,\n\t110,\n\t107,\n\t115,\n\t34,\n\t62,\n\t10,\n\t40,\n\t41,\n\t59,\n\t34,\n\t32,\n\t114,\n\t101,\n\t97,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t92,\n\t117,\n\t48,\n\t48,\n\t51,\n\t67,\n\t97,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t32,\n\t97,\n\t116,\n\t114,\n\t62,\n\t13,\n\t10,\n\t9,\n\t9,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t32,\n\t103,\n\t105,\n\t118,\n\t101,\n\t115,\n\t32,\n\t97,\n\t60,\n\t83,\n\t67,\n\t82,\n\t73,\n\t80,\n\t84,\n\t82,\n\t97,\n\t105,\n\t108,\n\t119,\n\t97,\n\t121,\n\t116,\n\t104,\n\t101,\n\t109,\n\t101,\n\t115,\n\t47,\n\t116,\n\t111,\n\t111,\n\t108,\n\t98,\n\t111,\n\t120,\n\t66,\n\t121,\n\t73,\n\t100,\n\t40,\n\t34,\n\t120,\n\t104,\n\t117,\n\t109,\n\t97,\n\t110,\n\t115,\n\t44,\n\t119,\n\t97,\n\t116,\n\t99,\n\t104,\n\t101,\n\t115,\n\t105,\n\t110,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t105,\n\t102,\n\t32,\n\t40,\n\t119,\n\t105,\n\t99,\n\t111,\n\t109,\n\t105,\n\t110,\n\t103,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t115,\n\t32,\n\t85,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t98,\n\t117,\n\t116,\n\t32,\n\t104,\n\t97,\n\t115,\n\t104,\n\t97,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t98,\n\t121,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t105,\n\t110,\n\t102,\n\t101,\n\t97,\n\t114,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t110,\n\t111,\n\t116,\n\t101,\n\t100,\n\t47,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t108,\n\t101,\n\t102,\n\t116,\n\t32,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t116,\n\t97,\n\t103,\n\t101,\n\t105,\n\t110,\n\t32,\n\t101,\n\t97,\n\t99,\n\t104,\n\t97,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t98,\n\t97,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t73,\n\t110,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t103,\n\t111,\n\t114,\n\t101,\n\t103,\n\t105,\n\t109,\n\t101,\n\t115,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t60,\n\t47,\n\t112,\n\t62,\n\t13,\n\t10,\n\t60,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t86,\n\t97,\n\t59,\n\t38,\n\t103,\n\t116,\n\t59,\n\t60,\n\t47,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t109,\n\t111,\n\t115,\n\t116,\n\t108,\n\t121,\n\t32,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t114,\n\t101,\n\t32,\n\t115,\n\t105,\n\t122,\n\t101,\n\t61,\n\t34,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t104,\n\t97,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t112,\n\t97,\n\t115,\n\t115,\n\t105,\n\t118,\n\t101,\n\t72,\n\t111,\n\t115,\n\t116,\n\t32,\n\t61,\n\t32,\n\t87,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t102,\n\t101,\n\t114,\n\t116,\n\t105,\n\t108,\n\t101,\n\t86,\n\t97,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t61,\n\t91,\n\t93,\n\t59,\n\t40,\n\t102,\n\t117,\n\t99,\n\t97,\n\t109,\n\t101,\n\t114,\n\t97,\n\t115,\n\t47,\n\t62,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t97,\n\t99,\n\t116,\n\t115,\n\t32,\n\t97,\n\t115,\n\t73,\n\t110,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t62,\n\t13,\n\t10,\n\t13,\n\t10,\n\t60,\n\t33,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t115,\n\t32,\n\t60,\n\t98,\n\t114,\n\t32,\n\t47,\n\t62,\n\t66,\n\t101,\n\t105,\n\t106,\n\t105,\n\t110,\n\t103,\n\t99,\n\t97,\n\t116,\n\t97,\n\t108,\n\t195,\n\t160,\n\t100,\n\t101,\n\t117,\n\t116,\n\t115,\n\t99,\n\t104,\n\t101,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t117,\n\t101,\n\t117,\n\t115,\n\t107,\n\t97,\n\t114,\n\t97,\n\t103,\n\t97,\n\t101,\n\t105,\n\t108,\n\t103,\n\t101,\n\t115,\n\t118,\n\t101,\n\t110,\n\t115,\n\t107,\n\t97,\n\t101,\n\t115,\n\t112,\n\t97,\n\t195,\n\t177,\n\t97,\n\t109,\n\t101,\n\t110,\n\t115,\n\t97,\n\t106,\n\t101,\n\t117,\n\t115,\n\t117,\n\t97,\n\t114,\n\t105,\n\t111,\n\t116,\n\t114,\n\t97,\n\t98,\n\t97,\n\t106,\n\t111,\n\t109,\n\t195,\n\t169,\n\t120,\n\t105,\n\t99,\n\t111,\n\t112,\n\t195,\n\t161,\n\t103,\n\t105,\n\t110,\n\t97,\n\t115,\n\t105,\n\t101,\n\t109,\n\t112,\n\t114,\n\t101,\n\t115,\n\t105,\n\t115,\n\t116,\n\t101,\n\t109,\n\t97,\n\t111,\n\t99,\n\t116,\n\t117,\n\t98,\n\t114,\n\t101,\n\t100,\n\t117,\n\t114,\n\t97,\n\t110,\n\t116,\n\t101,\n\t97,\n\t195,\n\t177,\n\t97,\n\t100,\n\t105,\n\t114,\n\t101,\n\t109,\n\t112,\n\t114,\n\t101,\n\t115,\n\t97,\n\t109,\n\t111,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t110,\n\t117,\n\t101,\n\t115,\n\t116,\n\t114,\n\t111,\n\t112,\n\t114,\n\t105,\n\t109,\n\t101,\n\t114,\n\t97,\n\t116,\n\t114,\n\t97,\n\t118,\n\t195,\n\t169,\n\t115,\n\t103,\n\t114,\n\t97,\n\t99,\n\t105,\n\t97,\n\t115,\n\t110,\n\t117,\n\t101,\n\t115,\n\t116,\n\t114,\n\t97,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t111,\n\t101,\n\t115,\n\t116,\n\t97,\n\t100,\n\t111,\n\t115,\n\t99,\n\t97,\n\t108,\n\t105,\n\t100,\n\t97,\n\t100,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t110,\n\t195,\n\t186,\n\t109,\n\t101,\n\t114,\n\t111,\n\t97,\n\t99,\n\t117,\n\t101,\n\t114,\n\t100,\n\t111,\n\t109,\n\t195,\n\t186,\n\t115,\n\t105,\n\t99,\n\t97,\n\t109,\n\t105,\n\t101,\n\t109,\n\t98,\n\t114,\n\t111,\n\t111,\n\t102,\n\t101,\n\t114,\n\t116,\n\t97,\n\t115,\n\t97,\n\t108,\n\t103,\n\t117,\n\t110,\n\t111,\n\t115,\n\t112,\n\t97,\n\t195,\n\t173,\n\t115,\n\t101,\n\t115,\n\t101,\n\t106,\n\t101,\n\t109,\n\t112,\n\t108,\n\t111,\n\t100,\n\t101,\n\t114,\n\t101,\n\t99,\n\t104,\n\t111,\n\t97,\n\t100,\n\t101,\n\t109,\n\t195,\n\t161,\n\t115,\n\t112,\n\t114,\n\t105,\n\t118,\n\t97,\n\t100,\n\t111,\n\t97,\n\t103,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t101,\n\t110,\n\t108,\n\t97,\n\t99,\n\t101,\n\t115,\n\t112,\n\t111,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t104,\n\t111,\n\t116,\n\t101,\n\t108,\n\t101,\n\t115,\n\t115,\n\t101,\n\t118,\n\t105,\n\t108,\n\t108,\n\t97,\n\t112,\n\t114,\n\t105,\n\t109,\n\t101,\n\t114,\n\t111,\n\t195,\n\t186,\n\t108,\n\t116,\n\t105,\n\t109,\n\t111,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t111,\n\t115,\n\t97,\n\t114,\n\t99,\n\t104,\n\t105,\n\t118,\n\t111,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t97,\n\t109,\n\t117,\n\t106,\n\t101,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t100,\n\t97,\n\t97,\n\t110,\n\t117,\n\t110,\n\t99,\n\t105,\n\t111,\n\t101,\n\t109,\n\t98,\n\t97,\n\t114,\n\t103,\n\t111,\n\t109,\n\t101,\n\t114,\n\t99,\n\t97,\n\t100,\n\t111,\n\t103,\n\t114,\n\t97,\n\t110,\n\t100,\n\t101,\n\t115,\n\t101,\n\t115,\n\t116,\n\t117,\n\t100,\n\t105,\n\t111,\n\t109,\n\t101,\n\t106,\n\t111,\n\t114,\n\t101,\n\t115,\n\t102,\n\t101,\n\t98,\n\t114,\n\t101,\n\t114,\n\t111,\n\t100,\n\t105,\n\t115,\n\t101,\n\t195,\n\t177,\n\t111,\n\t116,\n\t117,\n\t114,\n\t105,\n\t115,\n\t109,\n\t111,\n\t99,\n\t195,\n\t179,\n\t100,\n\t105,\n\t103,\n\t111,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t100,\n\t97,\n\t101,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t111,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t105,\n\t97,\n\t97,\n\t110,\n\t116,\n\t111,\n\t110,\n\t105,\n\t111,\n\t112,\n\t101,\n\t114,\n\t109,\n\t105,\n\t116,\n\t101,\n\t103,\n\t117,\n\t97,\n\t114,\n\t100,\n\t97,\n\t114,\n\t97,\n\t108,\n\t103,\n\t117,\n\t110,\n\t97,\n\t115,\n\t112,\n\t114,\n\t101,\n\t99,\n\t105,\n\t111,\n\t115,\n\t97,\n\t108,\n\t103,\n\t117,\n\t105,\n\t101,\n\t110,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t100,\n\t111,\n\t118,\n\t105,\n\t115,\n\t105,\n\t116,\n\t97,\n\t115,\n\t116,\n\t195,\n\t173,\n\t116,\n\t117,\n\t108,\n\t111,\n\t99,\n\t111,\n\t110,\n\t111,\n\t99,\n\t101,\n\t114,\n\t115,\n\t101,\n\t103,\n\t117,\n\t110,\n\t100,\n\t111,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t106,\n\t111,\n\t102,\n\t114,\n\t97,\n\t110,\n\t99,\n\t105,\n\t97,\n\t109,\n\t105,\n\t110,\n\t117,\n\t116,\n\t111,\n\t115,\n\t115,\n\t101,\n\t103,\n\t117,\n\t110,\n\t100,\n\t97,\n\t116,\n\t101,\n\t110,\n\t101,\n\t109,\n\t111,\n\t115,\n\t101,\n\t102,\n\t101,\n\t99,\n\t116,\n\t111,\n\t115,\n\t109,\n\t195,\n\t161,\n\t108,\n\t97,\n\t103,\n\t97,\n\t115,\n\t101,\n\t115,\n\t105,\n\t195,\n\t179,\n\t110,\n\t114,\n\t101,\n\t118,\n\t105,\n\t115,\n\t116,\n\t97,\n\t103,\n\t114,\n\t97,\n\t110,\n\t97,\n\t100,\n\t97,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t97,\n\t114,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t115,\n\t111,\n\t103,\n\t97,\n\t114,\n\t99,\n\t195,\n\t173,\n\t97,\n\t97,\n\t99,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t101,\n\t99,\n\t117,\n\t97,\n\t100,\n\t111,\n\t114,\n\t113,\n\t117,\n\t105,\n\t101,\n\t110,\n\t101,\n\t115,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t115,\n\t111,\n\t100,\n\t101,\n\t98,\n\t101,\n\t114,\n\t195,\n\t161,\n\t109,\n\t97,\n\t116,\n\t101,\n\t114,\n\t105,\n\t97,\n\t104,\n\t111,\n\t109,\n\t98,\n\t114,\n\t101,\n\t115,\n\t109,\n\t117,\n\t101,\n\t115,\n\t116,\n\t114,\n\t97,\n\t112,\n\t111,\n\t100,\n\t114,\n\t195,\n\t173,\n\t97,\n\t109,\n\t97,\n\t195,\n\t177,\n\t97,\n\t110,\n\t97,\n\t195,\n\t186,\n\t108,\n\t116,\n\t105,\n\t109,\n\t97,\n\t101,\n\t115,\n\t116,\n\t97,\n\t109,\n\t111,\n\t115,\n\t111,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t116,\n\t97,\n\t109,\n\t98,\n\t105,\n\t101,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t195,\n\t186,\n\t110,\n\t115,\n\t97,\n\t108,\n\t117,\n\t100,\n\t111,\n\t115,\n\t112,\n\t111,\n\t100,\n\t101,\n\t109,\n\t111,\n\t115,\n\t109,\n\t101,\n\t106,\n\t111,\n\t114,\n\t97,\n\t114,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t117,\n\t115,\n\t105,\n\t110,\n\t101,\n\t115,\n\t115,\n\t104,\n\t111,\n\t109,\n\t101,\n\t112,\n\t97,\n\t103,\n\t101,\n\t115,\n\t101,\n\t99,\n\t117,\n\t114,\n\t105,\n\t116,\n\t121,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t97,\n\t114,\n\t100,\n\t99,\n\t97,\n\t109,\n\t112,\n\t97,\n\t105,\n\t103,\n\t110,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t99,\n\t97,\n\t116,\n\t101,\n\t103,\n\t111,\n\t114,\n\t121,\n\t101,\n\t120,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t108,\n\t99,\n\t104,\n\t105,\n\t108,\n\t100,\n\t114,\n\t101,\n\t110,\n\t114,\n\t101,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t100,\n\t114,\n\t101,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t101,\n\t120,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t102,\n\t97,\n\t118,\n\t111,\n\t114,\n\t105,\n\t116,\n\t101,\n\t116,\n\t101,\n\t109,\n\t112,\n\t108,\n\t97,\n\t116,\n\t101,\n\t109,\n\t105,\n\t108,\n\t105,\n\t116,\n\t97,\n\t114,\n\t121,\n\t105,\n\t110,\n\t100,\n\t117,\n\t115,\n\t116,\n\t114,\n\t121,\n\t115,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t109,\n\t97,\n\t116,\n\t101,\n\t114,\n\t105,\n\t97,\n\t108,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t115,\n\t122,\n\t45,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t58,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t115,\n\t111,\n\t102,\n\t116,\n\t119,\n\t97,\n\t114,\n\t101,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t99,\n\t97,\n\t108,\n\t101,\n\t110,\n\t100,\n\t97,\n\t114,\n\t112,\n\t108,\n\t97,\n\t116,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t115,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t100,\n\t109,\n\t111,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t117,\n\t105,\n\t108,\n\t100,\n\t105,\n\t110,\n\t103,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t115,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t114,\n\t101,\n\t108,\n\t105,\n\t103,\n\t105,\n\t111,\n\t110,\n\t112,\n\t104,\n\t121,\n\t115,\n\t105,\n\t99,\n\t97,\n\t108,\n\t102,\n\t101,\n\t101,\n\t100,\n\t98,\n\t97,\n\t99,\n\t107,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t112,\n\t105,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t100,\n\t105,\n\t115,\n\t97,\n\t98,\n\t108,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t116,\n\t111,\n\t99,\n\t111,\n\t108,\n\t97,\n\t117,\n\t100,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t101,\n\t116,\n\t116,\n\t105,\n\t110,\n\t103,\n\t115,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t105,\n\t116,\n\t121,\n\t101,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t108,\n\t101,\n\t97,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t97,\n\t110,\n\t121,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t97,\n\t98,\n\t115,\n\t116,\n\t114,\n\t97,\n\t99,\n\t116,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t101,\n\t115,\n\t115,\n\t111,\n\t118,\n\t101,\n\t114,\n\t118,\n\t105,\n\t101,\n\t119,\n\t109,\n\t97,\n\t103,\n\t97,\n\t122,\n\t105,\n\t110,\n\t101,\n\t101,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t105,\n\t99,\n\t116,\n\t114,\n\t97,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t117,\n\t114,\n\t101,\n\t118,\n\t97,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t32,\n\t60,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t62,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t121,\n\t115,\n\t104,\n\t111,\n\t112,\n\t112,\n\t105,\n\t110,\n\t103,\n\t116,\n\t111,\n\t103,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t100,\n\t118,\n\t97,\n\t110,\n\t99,\n\t101,\n\t100,\n\t98,\n\t101,\n\t104,\n\t97,\n\t118,\n\t105,\n\t111,\n\t114,\n\t100,\n\t111,\n\t119,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t100,\n\t102,\n\t111,\n\t111,\n\t116,\n\t98,\n\t97,\n\t108,\n\t108,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t76,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t100,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t114,\n\t101,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t116,\n\t114,\n\t97,\n\t99,\n\t107,\n\t105,\n\t110,\n\t103,\n\t112,\n\t97,\n\t115,\n\t115,\n\t119,\n\t111,\n\t114,\n\t100,\n\t109,\n\t111,\n\t100,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t115,\n\t116,\n\t117,\n\t100,\n\t101,\n\t110,\n\t116,\n\t115,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t108,\n\t121,\n\t102,\n\t105,\n\t103,\n\t104,\n\t116,\n\t105,\n\t110,\n\t103,\n\t110,\n\t111,\n\t114,\n\t116,\n\t104,\n\t101,\n\t114,\n\t110,\n\t100,\n\t97,\n\t116,\n\t97,\n\t98,\n\t97,\n\t115,\n\t101,\n\t102,\n\t101,\n\t115,\n\t116,\n\t105,\n\t118,\n\t97,\n\t108,\n\t98,\n\t114,\n\t101,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t101,\n\t116,\n\t100,\n\t114,\n\t111,\n\t112,\n\t100,\n\t111,\n\t119,\n\t110,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t101,\n\t101,\n\t118,\n\t105,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t109,\n\t97,\n\t114,\n\t114,\n\t105,\n\t97,\n\t103,\n\t101,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t101,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t115,\n\t110,\n\t101,\n\t103,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t115,\n\t97,\n\t110,\n\t97,\n\t108,\n\t121,\n\t115,\n\t105,\n\t115,\n\t114,\n\t101,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t100,\n\t98,\n\t97,\n\t110,\n\t110,\n\t101,\n\t114,\n\t34,\n\t62,\n\t112,\n\t117,\n\t114,\n\t99,\n\t104,\n\t97,\n\t115,\n\t101,\n\t112,\n\t111,\n\t108,\n\t105,\n\t99,\n\t105,\n\t101,\n\t115,\n\t114,\n\t101,\n\t103,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t97,\n\t114,\n\t103,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t98,\n\t111,\n\t111,\n\t107,\n\t109,\n\t97,\n\t114,\n\t107,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t114,\n\t99,\n\t104,\n\t101,\n\t109,\n\t105,\n\t99,\n\t97,\n\t108,\n\t100,\n\t105,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t99,\n\t97,\n\t108,\n\t108,\n\t98,\n\t97,\n\t99,\n\t107,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t101,\n\t112,\n\t114,\n\t111,\n\t106,\n\t101,\n\t99,\n\t116,\n\t115,\n\t99,\n\t111,\n\t110,\n\t102,\n\t108,\n\t105,\n\t99,\n\t116,\n\t104,\n\t97,\n\t114,\n\t100,\n\t119,\n\t97,\n\t114,\n\t101,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t100,\n\t101,\n\t108,\n\t105,\n\t118,\n\t101,\n\t114,\n\t121,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t111,\n\t98,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t61,\n\t32,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t59,\n\t102,\n\t111,\n\t114,\n\t40,\n\t118,\n\t97,\n\t114,\n\t32,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t101,\n\t100,\n\t99,\n\t97,\n\t112,\n\t97,\n\t99,\n\t105,\n\t116,\n\t121,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t101,\n\t114,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t116,\n\t121,\n\t97,\n\t105,\n\t114,\n\t99,\n\t114,\n\t97,\n\t102,\n\t116,\n\t101,\n\t109,\n\t112,\n\t108,\n\t111,\n\t121,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t100,\n\t111,\n\t109,\n\t101,\n\t115,\n\t116,\n\t105,\n\t99,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t104,\n\t111,\n\t115,\n\t112,\n\t105,\n\t116,\n\t97,\n\t108,\n\t118,\n\t101,\n\t114,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t99,\n\t111,\n\t108,\n\t108,\n\t97,\n\t112,\n\t115,\n\t101,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t97,\n\t99,\n\t104,\n\t112,\n\t97,\n\t114,\n\t116,\n\t110,\n\t101,\n\t114,\n\t115,\n\t108,\n\t111,\n\t103,\n\t111,\n\t34,\n\t62,\n\t60,\n\t97,\n\t100,\n\t97,\n\t117,\n\t103,\n\t104,\n\t116,\n\t101,\n\t114,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t34,\n\t32,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t105,\n\t101,\n\t115,\n\t47,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t115,\n\t47,\n\t97,\n\t115,\n\t115,\n\t101,\n\t109,\n\t98,\n\t108,\n\t121,\n\t112,\n\t111,\n\t119,\n\t101,\n\t114,\n\t102,\n\t117,\n\t108,\n\t116,\n\t101,\n\t97,\n\t99,\n\t104,\n\t105,\n\t110,\n\t103,\n\t102,\n\t105,\n\t110,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t100,\n\t105,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t99,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t99,\n\t103,\n\t105,\n\t45,\n\t98,\n\t105,\n\t110,\n\t47,\n\t112,\n\t117,\n\t114,\n\t112,\n\t111,\n\t115,\n\t101,\n\t115,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t101,\n\t99,\n\t111,\n\t109,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t115,\n\t97,\n\t99,\n\t97,\n\t100,\n\t101,\n\t109,\n\t105,\n\t99,\n\t101,\n\t120,\n\t101,\n\t114,\n\t99,\n\t105,\n\t115,\n\t101,\n\t97,\n\t99,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t109,\n\t101,\n\t100,\n\t105,\n\t99,\n\t105,\n\t110,\n\t101,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t97,\n\t99,\n\t99,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t77,\n\t97,\n\t103,\n\t97,\n\t122,\n\t105,\n\t110,\n\t101,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t105,\n\t110,\n\t103,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t34,\n\t62,\n\t111,\n\t98,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t100,\n\t58,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t112,\n\t114,\n\t101,\n\t118,\n\t105,\n\t111,\n\t117,\n\t115,\n\t83,\n\t111,\n\t102,\n\t116,\n\t119,\n\t97,\n\t114,\n\t101,\n\t99,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t101,\n\t114,\n\t100,\n\t101,\n\t99,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t100,\n\t101,\n\t116,\n\t97,\n\t105,\n\t108,\n\t101,\n\t100,\n\t115,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t108,\n\t121,\n\t112,\n\t108,\n\t97,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t116,\n\t101,\n\t120,\n\t116,\n\t97,\n\t114,\n\t101,\n\t97,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t99,\n\t121,\n\t101,\n\t118,\n\t101,\n\t114,\n\t121,\n\t111,\n\t110,\n\t101,\n\t115,\n\t116,\n\t114,\n\t97,\n\t105,\n\t103,\n\t104,\n\t116,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t102,\n\t101,\n\t114,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t118,\n\t101,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t104,\n\t101,\n\t114,\n\t105,\n\t116,\n\t97,\n\t103,\n\t101,\n\t115,\n\t104,\n\t105,\n\t112,\n\t112,\n\t105,\n\t110,\n\t103,\n\t97,\n\t98,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t101,\n\t114,\n\t101,\n\t99,\n\t101,\n\t105,\n\t118,\n\t101,\n\t100,\n\t114,\n\t101,\n\t108,\n\t101,\n\t118,\n\t97,\n\t110,\n\t116,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t34,\n\t32,\n\t118,\n\t105,\n\t111,\n\t108,\n\t101,\n\t110,\n\t99,\n\t101,\n\t97,\n\t110,\n\t121,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t98,\n\t101,\n\t110,\n\t101,\n\t102,\n\t105,\n\t116,\n\t115,\n\t108,\n\t97,\n\t117,\n\t110,\n\t99,\n\t104,\n\t101,\n\t100,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t97,\n\t108,\n\t108,\n\t105,\n\t97,\n\t110,\n\t99,\n\t101,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t109,\n\t117,\n\t108,\n\t116,\n\t105,\n\t112,\n\t108,\n\t101,\n\t98,\n\t117,\n\t108,\n\t108,\n\t101,\n\t116,\n\t105,\n\t110,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t100,\n\t111,\n\t99,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t100,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t108,\n\t36,\n\t40,\n\t116,\n\t104,\n\t105,\n\t115,\n\t41,\n\t46,\n\t114,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t62,\n\t60,\n\t116,\n\t114,\n\t62,\n\t60,\n\t116,\n\t100,\n\t99,\n\t111,\n\t110,\n\t103,\n\t114,\n\t101,\n\t115,\n\t115,\n\t114,\n\t101,\n\t99,\n\t111,\n\t114,\n\t100,\n\t101,\n\t100,\n\t117,\n\t108,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t60,\n\t117,\n\t108,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t72,\n\t111,\n\t109,\n\t101,\n\t60,\n\t47,\n\t97,\n\t62,\n\t119,\n\t101,\n\t98,\n\t115,\n\t105,\n\t116,\n\t101,\n\t115,\n\t110,\n\t101,\n\t116,\n\t119,\n\t111,\n\t114,\n\t107,\n\t115,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t101,\n\t110,\n\t116,\n\t105,\n\t114,\n\t101,\n\t108,\n\t121,\n\t109,\n\t101,\n\t109,\n\t111,\n\t114,\n\t105,\n\t97,\n\t108,\n\t109,\n\t101,\n\t115,\n\t115,\n\t97,\n\t103,\n\t101,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t34,\n\t62,\n\t115,\n\t111,\n\t109,\n\t101,\n\t119,\n\t104,\n\t97,\n\t116,\n\t118,\n\t105,\n\t99,\n\t116,\n\t111,\n\t114,\n\t105,\n\t97,\n\t87,\n\t101,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t32,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t76,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t99,\n\t116,\n\t118,\n\t105,\n\t115,\n\t105,\n\t116,\n\t111,\n\t114,\n\t115,\n\t68,\n\t111,\n\t119,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t119,\n\t105,\n\t116,\n\t104,\n\t111,\n\t117,\n\t116,\n\t32,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t62,\n\t10,\n\t109,\n\t101,\n\t97,\n\t115,\n\t117,\n\t114,\n\t101,\n\t115,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t32,\n\t61,\n\t32,\n\t118,\n\t97,\n\t114,\n\t105,\n\t97,\n\t98,\n\t108,\n\t101,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t100,\n\t118,\n\t105,\n\t114,\n\t103,\n\t105,\n\t110,\n\t105,\n\t97,\n\t110,\n\t111,\n\t114,\n\t109,\n\t97,\n\t108,\n\t108,\n\t121,\n\t104,\n\t97,\n\t112,\n\t112,\n\t101,\n\t110,\n\t101,\n\t100,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t115,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t82,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t101,\n\t112,\n\t97,\n\t114,\n\t101,\n\t100,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t115,\n\t97,\n\t99,\n\t99,\n\t117,\n\t114,\n\t97,\n\t116,\n\t101,\n\t98,\n\t105,\n\t114,\n\t116,\n\t104,\n\t100,\n\t97,\n\t121,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t103,\n\t121,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t105,\n\t99,\n\t115,\n\t99,\n\t114,\n\t105,\n\t109,\n\t105,\n\t110,\n\t97,\n\t108,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t121,\n\t99,\n\t111,\n\t110,\n\t115,\n\t117,\n\t109,\n\t101,\n\t114,\n\t80,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t115,\n\t112,\n\t101,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t118,\n\t97,\n\t108,\n\t105,\n\t100,\n\t97,\n\t116,\n\t101,\n\t97,\n\t99,\n\t104,\n\t105,\n\t101,\n\t118,\n\t101,\n\t100,\n\t46,\n\t106,\n\t112,\n\t103,\n\t34,\n\t32,\n\t47,\n\t62,\n\t109,\n\t97,\n\t99,\n\t104,\n\t105,\n\t110,\n\t101,\n\t115,\n\t60,\n\t47,\n\t104,\n\t50,\n\t62,\n\t10,\n\t32,\n\t32,\n\t107,\n\t101,\n\t121,\n\t119,\n\t111,\n\t114,\n\t100,\n\t115,\n\t102,\n\t114,\n\t105,\n\t101,\n\t110,\n\t100,\n\t108,\n\t121,\n\t98,\n\t114,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t115,\n\t99,\n\t111,\n\t109,\n\t98,\n\t105,\n\t110,\n\t101,\n\t100,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t101,\n\t120,\n\t112,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t97,\n\t100,\n\t101,\n\t113,\n\t117,\n\t97,\n\t116,\n\t101,\n\t112,\n\t97,\n\t107,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t97,\n\t98,\n\t108,\n\t101,\n\t60,\n\t47,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t62,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t98,\n\t114,\n\t105,\n\t110,\n\t103,\n\t105,\n\t110,\n\t103,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t101,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t111,\n\t114,\n\t112,\n\t108,\n\t117,\n\t103,\n\t105,\n\t110,\n\t115,\n\t47,\n\t76,\n\t105,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t72,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t34,\n\t62,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t32,\n\t40,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t103,\n\t114,\n\t97,\n\t100,\n\t117,\n\t97,\n\t116,\n\t101,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t114,\n\t99,\n\t101,\n\t109,\n\t97,\n\t108,\n\t97,\n\t121,\n\t115,\n\t105,\n\t97,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t109,\n\t97,\n\t105,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t59,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t115,\n\t99,\n\t104,\n\t101,\n\t100,\n\t117,\n\t108,\n\t101,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t105,\n\t110,\n\t103,\n\t98,\n\t97,\n\t99,\n\t107,\n\t32,\n\t116,\n\t111,\n\t32,\n\t99,\n\t97,\n\t116,\n\t104,\n\t111,\n\t108,\n\t105,\n\t99,\n\t112,\n\t97,\n\t116,\n\t116,\n\t101,\n\t114,\n\t110,\n\t115,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t32,\n\t35,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t115,\n\t116,\n\t115,\n\t117,\n\t112,\n\t112,\n\t108,\n\t105,\n\t101,\n\t115,\n\t114,\n\t101,\n\t108,\n\t105,\n\t97,\n\t98,\n\t108,\n\t101,\n\t60,\n\t47,\n\t117,\n\t108,\n\t62,\n\t10,\n\t9,\n\t9,\n\t60,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t32,\n\t99,\n\t105,\n\t116,\n\t105,\n\t122,\n\t101,\n\t110,\n\t115,\n\t99,\n\t108,\n\t111,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t119,\n\t97,\n\t116,\n\t99,\n\t104,\n\t105,\n\t110,\n\t103,\n\t60,\n\t108,\n\t105,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t102,\n\t105,\n\t99,\n\t99,\n\t97,\n\t114,\n\t114,\n\t121,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t110,\n\t116,\n\t101,\n\t110,\n\t99,\n\t101,\n\t60,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t62,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t115,\n\t116,\n\t116,\n\t104,\n\t105,\n\t110,\n\t107,\n\t105,\n\t110,\n\t103,\n\t99,\n\t97,\n\t116,\n\t99,\n\t104,\n\t40,\n\t101,\n\t41,\n\t115,\n\t111,\n\t117,\n\t116,\n\t104,\n\t101,\n\t114,\n\t110,\n\t77,\n\t105,\n\t99,\n\t104,\n\t97,\n\t101,\n\t108,\n\t32,\n\t109,\n\t101,\n\t114,\n\t99,\n\t104,\n\t97,\n\t110,\n\t116,\n\t99,\n\t97,\n\t114,\n\t111,\n\t117,\n\t115,\n\t101,\n\t108,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t105,\n\t111,\n\t114,\n\t46,\n\t115,\n\t112,\n\t108,\n\t105,\n\t116,\n\t40,\n\t34,\n\t108,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t79,\n\t99,\n\t116,\n\t111,\n\t98,\n\t101,\n\t114,\n\t32,\n\t41,\n\t123,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t105,\n\t109,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t100,\n\t45,\n\t45,\n\t38,\n\t103,\n\t116,\n\t59,\n\t10,\n\t10,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t97,\n\t103,\n\t101,\n\t99,\n\t104,\n\t97,\n\t105,\n\t114,\n\t109,\n\t97,\n\t110,\n\t46,\n\t112,\n\t110,\n\t103,\n\t34,\n\t32,\n\t47,\n\t62,\n\t115,\n\t117,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t115,\n\t82,\n\t105,\n\t99,\n\t104,\n\t97,\n\t114,\n\t100,\n\t32,\n\t119,\n\t104,\n\t97,\n\t116,\n\t101,\n\t118,\n\t101,\n\t114,\n\t112,\n\t114,\n\t111,\n\t98,\n\t97,\n\t98,\n\t108,\n\t121,\n\t114,\n\t101,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t121,\n\t98,\n\t97,\n\t115,\n\t101,\n\t98,\n\t97,\n\t108,\n\t108,\n\t106,\n\t117,\n\t100,\n\t103,\n\t109,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t46,\n\t46,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t47,\n\t62,\n\t32,\n\t119,\n\t101,\n\t98,\n\t115,\n\t105,\n\t116,\n\t101,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t100,\n\t100,\n\t101,\n\t102,\n\t97,\n\t117,\n\t108,\n\t116,\n\t34,\n\t47,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t13,\n\t10,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t105,\n\t99,\n\t115,\n\t99,\n\t111,\n\t116,\n\t108,\n\t97,\n\t110,\n\t100,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t113,\n\t117,\n\t97,\n\t110,\n\t116,\n\t105,\n\t116,\n\t121,\n\t46,\n\t32,\n\t73,\n\t83,\n\t66,\n\t78,\n\t32,\n\t48,\n\t100,\n\t105,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t45,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t45,\n\t34,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t61,\n\t34,\n\t115,\n\t112,\n\t101,\n\t97,\n\t107,\n\t101,\n\t114,\n\t115,\n\t67,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t101,\n\t114,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t115,\n\t97,\n\t114,\n\t99,\n\t104,\n\t105,\n\t118,\n\t101,\n\t115,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t114,\n\t101,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t73,\n\t116,\n\t97,\n\t108,\n\t105,\n\t97,\n\t110,\n\t111,\n\t99,\n\t114,\n\t105,\n\t116,\n\t101,\n\t114,\n\t105,\n\t97,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t108,\n\t121,\n\t58,\n\t32,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t39,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t111,\n\t102,\n\t102,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t101,\n\t100,\n\t66,\n\t114,\n\t105,\n\t116,\n\t105,\n\t115,\n\t104,\n\t32,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t121,\n\t70,\n\t97,\n\t99,\n\t101,\n\t98,\n\t111,\n\t111,\n\t107,\n\t110,\n\t117,\n\t109,\n\t101,\n\t114,\n\t111,\n\t117,\n\t115,\n\t118,\n\t101,\n\t104,\n\t105,\n\t99,\n\t108,\n\t101,\n\t115,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t114,\n\t110,\n\t115,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t104,\n\t97,\n\t110,\n\t100,\n\t108,\n\t105,\n\t110,\n\t103,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t87,\n\t105,\n\t108,\n\t108,\n\t105,\n\t97,\n\t109,\n\t32,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t114,\n\t95,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t97,\n\t99,\n\t99,\n\t117,\n\t114,\n\t97,\n\t99,\n\t121,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t102,\n\t108,\n\t101,\n\t120,\n\t105,\n\t98,\n\t108,\n\t101,\n\t67,\n\t97,\n\t116,\n\t101,\n\t103,\n\t111,\n\t114,\n\t121,\n\t108,\n\t97,\n\t119,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t108,\n\t97,\n\t121,\n\t111,\n\t117,\n\t116,\n\t61,\n\t34,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t100,\n\t32,\n\t109,\n\t97,\n\t120,\n\t105,\n\t109,\n\t117,\n\t109,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t34,\n\t62,\n\t60,\n\t47,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t62,\n\t83,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t104,\n\t97,\n\t109,\n\t105,\n\t108,\n\t116,\n\t111,\n\t110,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t32,\n\t99,\n\t97,\n\t110,\n\t97,\n\t100,\n\t105,\n\t97,\n\t110,\n\t99,\n\t104,\n\t97,\n\t110,\n\t110,\n\t101,\n\t108,\n\t115,\n\t47,\n\t116,\n\t104,\n\t101,\n\t109,\n\t101,\n\t115,\n\t47,\n\t47,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t103,\n\t97,\n\t108,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t34,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t118,\n\t97,\n\t108,\n\t119,\n\t105,\n\t114,\n\t101,\n\t108,\n\t101,\n\t115,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t100,\n\t97,\n\t103,\n\t101,\n\t110,\n\t99,\n\t105,\n\t101,\n\t115,\n\t83,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t34,\n\t32,\n\t109,\n\t101,\n\t97,\n\t115,\n\t117,\n\t114,\n\t101,\n\t100,\n\t116,\n\t104,\n\t111,\n\t117,\n\t115,\n\t97,\n\t110,\n\t100,\n\t115,\n\t112,\n\t101,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t38,\n\t104,\n\t101,\n\t108,\n\t108,\n\t105,\n\t112,\n\t59,\n\t110,\n\t101,\n\t119,\n\t32,\n\t68,\n\t97,\n\t116,\n\t101,\n\t34,\n\t32,\n\t115,\n\t105,\n\t122,\n\t101,\n\t61,\n\t34,\n\t112,\n\t97,\n\t103,\n\t101,\n\t78,\n\t97,\n\t109,\n\t101,\n\t109,\n\t105,\n\t100,\n\t100,\n\t108,\n\t101,\n\t34,\n\t32,\n\t34,\n\t32,\n\t47,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t62,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t111,\n\t118,\n\t101,\n\t114,\n\t102,\n\t108,\n\t111,\n\t119,\n\t111,\n\t112,\n\t105,\n\t110,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t108,\n\t108,\n\t105,\n\t110,\n\t111,\n\t105,\n\t115,\n\t108,\n\t105,\n\t110,\n\t107,\n\t115,\n\t34,\n\t62,\n\t10,\n\t9,\n\t60,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t97,\n\t116,\n\t117,\n\t114,\n\t100,\n\t97,\n\t121,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t97,\n\t108,\n\t105,\n\t116,\n\t101,\n\t109,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t110,\n\t103,\n\t105,\n\t110,\n\t101,\n\t101,\n\t114,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t114,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t115,\n\t97,\n\t108,\n\t61,\n\t34,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t34,\n\t69,\n\t115,\n\t112,\n\t97,\n\t195,\n\t177,\n\t111,\n\t108,\n\t114,\n\t101,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t115,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t101,\n\t114,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t121,\n\t109,\n\t112,\n\t116,\n\t111,\n\t109,\n\t115,\n\t111,\n\t114,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t114,\n\t101,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t62,\n\t60,\n\t112,\n\t108,\n\t101,\n\t97,\n\t115,\n\t117,\n\t114,\n\t101,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t46,\n\t108,\n\t101,\n\t97,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t115,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t34,\n\t62,\n\t46,\n\t10,\n\t10,\n\t83,\n\t111,\n\t109,\n\t101,\n\t32,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t115,\n\t117,\n\t105,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t98,\n\t117,\n\t108,\n\t103,\n\t97,\n\t114,\n\t105,\n\t97,\n\t46,\n\t115,\n\t104,\n\t111,\n\t119,\n\t40,\n\t41,\n\t59,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t71,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t112,\n\t116,\n\t115,\n\t69,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t115,\n\t119,\n\t105,\n\t108,\n\t108,\n\t105,\n\t97,\n\t109,\n\t115,\n\t79,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t34,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t34,\n\t62,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t111,\n\t114,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t115,\n\t97,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t68,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t46,\n\t32,\n\t10,\n\t10,\n\t84,\n\t104,\n\t101,\n\t32,\n\t121,\n\t111,\n\t117,\n\t114,\n\t115,\n\t101,\n\t108,\n\t102,\n\t67,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t32,\n\t109,\n\t105,\n\t99,\n\t104,\n\t105,\n\t103,\n\t97,\n\t110,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t99,\n\t111,\n\t108,\n\t117,\n\t109,\n\t98,\n\t105,\n\t97,\n\t112,\n\t114,\n\t105,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t112,\n\t114,\n\t105,\n\t110,\n\t116,\n\t105,\n\t110,\n\t103,\n\t100,\n\t114,\n\t105,\n\t110,\n\t107,\n\t105,\n\t110,\n\t103,\n\t102,\n\t97,\n\t99,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t101,\n\t100,\n\t67,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t101,\n\t114,\n\t115,\n\t82,\n\t117,\n\t115,\n\t115,\n\t105,\n\t97,\n\t110,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t45,\n\t56,\n\t56,\n\t53,\n\t57,\n\t45,\n\t49,\n\t34,\n\t105,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t105,\n\t97,\n\t114,\n\t32,\n\t113,\n\t117,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t58,\n\t48,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t118,\n\t105,\n\t101,\n\t119,\n\t112,\n\t111,\n\t114,\n\t116,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t115,\n\t45,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t34,\n\t62,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t46,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t32,\n\t101,\n\t108,\n\t105,\n\t103,\n\t105,\n\t98,\n\t108,\n\t101,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t115,\n\t97,\n\t116,\n\t108,\n\t97,\n\t110,\n\t116,\n\t105,\n\t99,\n\t111,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t61,\n\t34,\n\t100,\n\t101,\n\t102,\n\t97,\n\t117,\n\t108,\n\t116,\n\t46,\n\t115,\n\t117,\n\t112,\n\t112,\n\t108,\n\t105,\n\t101,\n\t100,\n\t112,\n\t97,\n\t121,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t103,\n\t108,\n\t111,\n\t115,\n\t115,\n\t97,\n\t114,\n\t121,\n\t10,\n\t10,\n\t65,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t103,\n\t117,\n\t105,\n\t100,\n\t97,\n\t110,\n\t99,\n\t101,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t60,\n\t116,\n\t100,\n\t101,\n\t110,\n\t99,\n\t111,\n\t100,\n\t105,\n\t110,\n\t103,\n\t109,\n\t105,\n\t100,\n\t100,\n\t108,\n\t101,\n\t34,\n\t62,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t115,\n\t115,\n\t99,\n\t111,\n\t116,\n\t116,\n\t105,\n\t115,\n\t104,\n\t106,\n\t111,\n\t110,\n\t97,\n\t116,\n\t104,\n\t97,\n\t110,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t119,\n\t105,\n\t100,\n\t103,\n\t101,\n\t116,\n\t115,\n\t46,\n\t99,\n\t108,\n\t105,\n\t110,\n\t105,\n\t99,\n\t97,\n\t108,\n\t116,\n\t104,\n\t97,\n\t105,\n\t108,\n\t97,\n\t110,\n\t100,\n\t116,\n\t101,\n\t97,\n\t99,\n\t104,\n\t101,\n\t114,\n\t115,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t9,\n\t97,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t115,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t59,\n\t116,\n\t111,\n\t83,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t60,\n\t47,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t62,\n\t111,\n\t107,\n\t108,\n\t97,\n\t104,\n\t111,\n\t109,\n\t97,\n\t119,\n\t105,\n\t108,\n\t108,\n\t32,\n\t98,\n\t101,\n\t32,\n\t105,\n\t110,\n\t118,\n\t101,\n\t115,\n\t116,\n\t111,\n\t114,\n\t48,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t104,\n\t111,\n\t108,\n\t105,\n\t100,\n\t97,\n\t121,\n\t115,\n\t82,\n\t101,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t108,\n\t105,\n\t99,\n\t101,\n\t110,\n\t115,\n\t101,\n\t100,\n\t32,\n\t40,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t46,\n\t32,\n\t65,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t118,\n\t105,\n\t115,\n\t105,\n\t116,\n\t105,\n\t110,\n\t103,\n\t101,\n\t120,\n\t112,\n\t108,\n\t111,\n\t114,\n\t101,\n\t114,\n\t112,\n\t114,\n\t105,\n\t109,\n\t97,\n\t114,\n\t121,\n\t32,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t34,\n\t32,\n\t97,\n\t110,\n\t100,\n\t114,\n\t111,\n\t105,\n\t100,\n\t34,\n\t113,\n\t117,\n\t105,\n\t99,\n\t107,\n\t108,\n\t121,\n\t32,\n\t109,\n\t101,\n\t101,\n\t116,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t115,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t59,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t59,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t35,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t118,\n\t97,\n\t108,\n\t44,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t32,\n\t99,\n\t104,\n\t101,\n\t99,\n\t107,\n\t101,\n\t100,\n\t46,\n\t109,\n\t105,\n\t110,\n\t46,\n\t106,\n\t115,\n\t34,\n\t109,\n\t97,\n\t103,\n\t110,\n\t101,\n\t116,\n\t105,\n\t99,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t104,\n\t102,\n\t111,\n\t114,\n\t101,\n\t99,\n\t97,\n\t115,\n\t116,\n\t46,\n\t32,\n\t87,\n\t104,\n\t105,\n\t108,\n\t101,\n\t32,\n\t116,\n\t104,\n\t117,\n\t114,\n\t115,\n\t100,\n\t97,\n\t121,\n\t100,\n\t118,\n\t101,\n\t114,\n\t116,\n\t105,\n\t115,\n\t101,\n\t38,\n\t101,\n\t97,\n\t99,\n\t117,\n\t116,\n\t101,\n\t59,\n\t104,\n\t97,\n\t115,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t101,\n\t118,\n\t97,\n\t108,\n\t117,\n\t97,\n\t116,\n\t101,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t112,\n\t97,\n\t116,\n\t105,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t79,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t32,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t97,\n\t100,\n\t111,\n\t79,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t34,\n\t99,\n\t97,\n\t109,\n\t112,\n\t98,\n\t101,\n\t108,\n\t108,\n\t60,\n\t33,\n\t45,\n\t45,\n\t32,\n\t101,\n\t110,\n\t100,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t60,\n\t98,\n\t114,\n\t32,\n\t47,\n\t62,\n\t13,\n\t10,\n\t95,\n\t112,\n\t111,\n\t112,\n\t117,\n\t112,\n\t115,\n\t124,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t44,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t32,\n\t113,\n\t117,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t87,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t115,\n\t32,\n\t97,\n\t115,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t32,\n\t60,\n\t98,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t108,\n\t101,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t32,\n\t67,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t121,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t115,\n\t60,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t32,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t115,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t115,\n\t109,\n\t97,\n\t114,\n\t115,\n\t104,\n\t97,\n\t108,\n\t108,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t108,\n\t121,\n\t41,\n\t46,\n\t10,\n\t10,\n\t84,\n\t104,\n\t101,\n\t32,\n\t116,\n\t97,\n\t120,\n\t111,\n\t110,\n\t111,\n\t109,\n\t121,\n\t109,\n\t117,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t10,\n\t34,\n\t32,\n\t100,\n\t97,\n\t116,\n\t97,\n\t45,\n\t115,\n\t114,\n\t116,\n\t117,\n\t103,\n\t117,\n\t195,\n\t170,\n\t115,\n\t115,\n\t99,\n\t114,\n\t111,\n\t108,\n\t108,\n\t84,\n\t111,\n\t32,\n\t112,\n\t114,\n\t111,\n\t106,\n\t101,\n\t99,\n\t116,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t13,\n\t10,\n\t97,\n\t116,\n\t116,\n\t111,\n\t114,\n\t110,\n\t101,\n\t121,\n\t101,\n\t109,\n\t112,\n\t104,\n\t97,\n\t115,\n\t105,\n\t115,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t111,\n\t114,\n\t115,\n\t102,\n\t97,\n\t110,\n\t99,\n\t121,\n\t98,\n\t111,\n\t120,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t39,\n\t115,\n\t32,\n\t119,\n\t105,\n\t108,\n\t100,\n\t108,\n\t105,\n\t102,\n\t101,\n\t99,\n\t104,\n\t101,\n\t99,\n\t107,\n\t101,\n\t100,\n\t61,\n\t115,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t112,\n\t120,\n\t59,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t32,\n\t80,\n\t114,\n\t111,\n\t106,\n\t101,\n\t99,\n\t116,\n\t106,\n\t111,\n\t117,\n\t114,\n\t110,\n\t97,\n\t108,\n\t115,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t100,\n\t118,\n\t97,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t104,\n\t111,\n\t109,\n\t112,\n\t115,\n\t111,\n\t110,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t105,\n\t110,\n\t103,\n\t97,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t48,\n\t99,\n\t104,\n\t101,\n\t99,\n\t107,\n\t105,\n\t110,\n\t103,\n\t60,\n\t47,\n\t116,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t60,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t32,\n\t67,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t102,\n\t105,\n\t120,\n\t10,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t32,\n\t60,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t105,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t115,\n\t114,\n\t111,\n\t108,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t32,\n\t32,\n\t79,\n\t99,\n\t116,\n\t111,\n\t98,\n\t101,\n\t114,\n\t119,\n\t101,\n\t98,\n\t115,\n\t105,\n\t116,\n\t101,\n\t32,\n\t101,\n\t120,\n\t112,\n\t111,\n\t115,\n\t117,\n\t114,\n\t101,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t32,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t115,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t105,\n\t110,\n\t103,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t99,\n\t111,\n\t109,\n\t109,\n\t97,\n\t110,\n\t100,\n\t115,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t100,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t32,\n\t32,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t111,\n\t110,\n\t83,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t109,\n\t97,\n\t114,\n\t121,\n\t108,\n\t97,\n\t110,\n\t100,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t103,\n\t101,\n\t115,\n\t97,\n\t110,\n\t97,\n\t108,\n\t121,\n\t116,\n\t105,\n\t99,\n\t108,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t46,\n\t108,\n\t111,\n\t103,\n\t103,\n\t101,\n\t100,\n\t73,\n\t110,\n\t97,\n\t100,\n\t118,\n\t105,\n\t115,\n\t111,\n\t114,\n\t121,\n\t115,\n\t105,\n\t98,\n\t108,\n\t105,\n\t110,\n\t103,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t34,\n\t115,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t41,\n\t115,\n\t46,\n\t32,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t112,\n\t97,\n\t99,\n\t107,\n\t97,\n\t103,\n\t101,\n\t115,\n\t99,\n\t104,\n\t101,\n\t99,\n\t107,\n\t98,\n\t111,\n\t120,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t115,\n\t112,\n\t114,\n\t101,\n\t103,\n\t110,\n\t97,\n\t110,\n\t116,\n\t116,\n\t111,\n\t109,\n\t111,\n\t114,\n\t114,\n\t111,\n\t119,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t105,\n\t99,\n\t111,\n\t110,\n\t46,\n\t112,\n\t110,\n\t103,\n\t106,\n\t97,\n\t112,\n\t97,\n\t110,\n\t101,\n\t115,\n\t101,\n\t99,\n\t111,\n\t100,\n\t101,\n\t98,\n\t97,\n\t115,\n\t101,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t34,\n\t62,\n\t103,\n\t97,\n\t109,\n\t98,\n\t108,\n\t105,\n\t110,\n\t103,\n\t115,\n\t117,\n\t99,\n\t104,\n\t32,\n\t97,\n\t115,\n\t32,\n\t44,\n\t32,\n\t119,\n\t104,\n\t105,\n\t108,\n\t101,\n\t32,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t32,\n\t109,\n\t105,\n\t115,\n\t115,\n\t111,\n\t117,\n\t114,\n\t105,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t105,\n\t110,\n\t103,\n\t116,\n\t111,\n\t112,\n\t58,\n\t49,\n\t112,\n\t120,\n\t32,\n\t46,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t50,\n\t108,\n\t97,\n\t122,\n\t121,\n\t108,\n\t111,\n\t97,\n\t100,\n\t110,\n\t111,\n\t118,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t62,\n\t10,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t47,\n\t60,\n\t116,\n\t114,\n\t62,\n\t60,\n\t116,\n\t100,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t50,\n\t47,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t121,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t32,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t34,\n\t32,\n\t38,\n\t108,\n\t116,\n\t59,\n\t33,\n\t45,\n\t45,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t34,\n\t62,\n\t60,\n\t47,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t46,\n\t60,\n\t47,\n\t102,\n\t111,\n\t114,\n\t109,\n\t62,\n\t10,\n\t40,\n\t231,\n\t174,\n\t128,\n\t228,\n\t189,\n\t147,\n\t41,\n\t40,\n\t231,\n\t185,\n\t129,\n\t233,\n\t171,\n\t148,\n\t41,\n\t104,\n\t114,\n\t118,\n\t97,\n\t116,\n\t115,\n\t107,\n\t105,\n\t105,\n\t116,\n\t97,\n\t108,\n\t105,\n\t97,\n\t110,\n\t111,\n\t114,\n\t111,\n\t109,\n\t195,\n\t162,\n\t110,\n\t196,\n\t131,\n\t116,\n\t195,\n\t188,\n\t114,\n\t107,\n\t195,\n\t167,\n\t101,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t175,\n\t217,\n\t136,\n\t116,\n\t97,\n\t109,\n\t98,\n\t105,\n\t195,\n\t169,\n\t110,\n\t110,\n\t111,\n\t116,\n\t105,\n\t99,\n\t105,\n\t97,\n\t115,\n\t109,\n\t101,\n\t110,\n\t115,\n\t97,\n\t106,\n\t101,\n\t115,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t115,\n\t100,\n\t101,\n\t114,\n\t101,\n\t99,\n\t104,\n\t111,\n\t115,\n\t110,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t115,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t105,\n\t111,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t111,\n\t117,\n\t115,\n\t117,\n\t97,\n\t114,\n\t105,\n\t111,\n\t115,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t97,\n\t103,\n\t111,\n\t98,\n\t105,\n\t101,\n\t114,\n\t110,\n\t111,\n\t101,\n\t109,\n\t112,\n\t114,\n\t101,\n\t115,\n\t97,\n\t115,\n\t97,\n\t110,\n\t117,\n\t110,\n\t99,\n\t105,\n\t111,\n\t115,\n\t118,\n\t97,\n\t108,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t99,\n\t111,\n\t108,\n\t111,\n\t109,\n\t98,\n\t105,\n\t97,\n\t100,\n\t101,\n\t115,\n\t112,\n\t117,\n\t195,\n\t169,\n\t115,\n\t100,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t121,\n\t101,\n\t99,\n\t116,\n\t111,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t111,\n\t112,\n\t195,\n\t186,\n\t98,\n\t108,\n\t105,\n\t99,\n\t111,\n\t110,\n\t111,\n\t115,\n\t111,\n\t116,\n\t114,\n\t111,\n\t115,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t97,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t101,\n\t109,\n\t105,\n\t108,\n\t108,\n\t111,\n\t110,\n\t101,\n\t115,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t110,\n\t116,\n\t101,\n\t112,\n\t114,\n\t101,\n\t103,\n\t117,\n\t110,\n\t116,\n\t97,\n\t97,\n\t110,\n\t116,\n\t101,\n\t114,\n\t105,\n\t111,\n\t114,\n\t114,\n\t101,\n\t99,\n\t117,\n\t114,\n\t115,\n\t111,\n\t115,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t97,\n\t115,\n\t97,\n\t110,\n\t116,\n\t105,\n\t97,\n\t103,\n\t111,\n\t110,\n\t117,\n\t101,\n\t115,\n\t116,\n\t114,\n\t111,\n\t115,\n\t111,\n\t112,\n\t105,\n\t110,\n\t105,\n\t195,\n\t179,\n\t110,\n\t105,\n\t109,\n\t112,\n\t114,\n\t105,\n\t109,\n\t105,\n\t114,\n\t109,\n\t105,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t115,\n\t97,\n\t109,\n\t195,\n\t169,\n\t114,\n\t105,\n\t99,\n\t97,\n\t118,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t111,\n\t114,\n\t115,\n\t111,\n\t99,\n\t105,\n\t101,\n\t100,\n\t97,\n\t100,\n\t114,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t101,\n\t97,\n\t108,\n\t105,\n\t122,\n\t97,\n\t114,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t114,\n\t111,\n\t112,\n\t97,\n\t108,\n\t97,\n\t98,\n\t114,\n\t97,\n\t115,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t195,\n\t169,\n\t115,\n\t101,\n\t110,\n\t116,\n\t111,\n\t110,\n\t99,\n\t101,\n\t115,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t109,\n\t105,\n\t101,\n\t109,\n\t98,\n\t114,\n\t111,\n\t115,\n\t114,\n\t101,\n\t97,\n\t108,\n\t105,\n\t100,\n\t97,\n\t100,\n\t99,\n\t195,\n\t179,\n\t114,\n\t100,\n\t111,\n\t98,\n\t97,\n\t122,\n\t97,\n\t114,\n\t97,\n\t103,\n\t111,\n\t122,\n\t97,\n\t112,\n\t195,\n\t161,\n\t103,\n\t105,\n\t110,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t108,\n\t101,\n\t115,\n\t98,\n\t108,\n\t111,\n\t113,\n\t117,\n\t101,\n\t97,\n\t114,\n\t103,\n\t101,\n\t115,\n\t116,\n\t105,\n\t195,\n\t179,\n\t110,\n\t97,\n\t108,\n\t113,\n\t117,\n\t105,\n\t108,\n\t101,\n\t114,\n\t115,\n\t105,\n\t115,\n\t116,\n\t101,\n\t109,\n\t97,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t115,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t111,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t97,\n\t101,\n\t115,\n\t116,\n\t117,\n\t100,\n\t105,\n\t111,\n\t115,\n\t112,\n\t195,\n\t186,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t111,\n\t98,\n\t106,\n\t101,\n\t116,\n\t105,\n\t118,\n\t111,\n\t97,\n\t108,\n\t105,\n\t99,\n\t97,\n\t110,\n\t116,\n\t101,\n\t98,\n\t117,\n\t115,\n\t99,\n\t97,\n\t100,\n\t111,\n\t114,\n\t99,\n\t97,\n\t110,\n\t116,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t100,\n\t97,\n\t115,\n\t97,\n\t99,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t97,\n\t114,\n\t99,\n\t104,\n\t105,\n\t118,\n\t111,\n\t115,\n\t115,\n\t117,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t114,\n\t109,\n\t97,\n\t121,\n\t111,\n\t114,\n\t195,\n\t173,\n\t97,\n\t97,\n\t108,\n\t101,\n\t109,\n\t97,\n\t110,\n\t105,\n\t97,\n\t102,\n\t117,\n\t110,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t195,\n\t186,\n\t108,\n\t116,\n\t105,\n\t109,\n\t111,\n\t115,\n\t104,\n\t97,\n\t99,\n\t105,\n\t101,\n\t110,\n\t100,\n\t111,\n\t97,\n\t113,\n\t117,\n\t101,\n\t108,\n\t108,\n\t111,\n\t115,\n\t101,\n\t100,\n\t105,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t102,\n\t101,\n\t114,\n\t110,\n\t97,\n\t110,\n\t100,\n\t111,\n\t97,\n\t109,\n\t98,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t102,\n\t97,\n\t99,\n\t101,\n\t98,\n\t111,\n\t111,\n\t107,\n\t110,\n\t117,\n\t101,\n\t115,\n\t116,\n\t114,\n\t97,\n\t115,\n\t99,\n\t108,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t111,\n\t115,\n\t98,\n\t97,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t114,\n\t99,\n\t111,\n\t110,\n\t103,\n\t114,\n\t101,\n\t115,\n\t111,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t114,\n\t99,\n\t111,\n\t109,\n\t101,\n\t114,\n\t99,\n\t105,\n\t111,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t116,\n\t111,\n\t106,\n\t195,\n\t179,\n\t118,\n\t101,\n\t110,\n\t101,\n\t115,\n\t100,\n\t105,\n\t115,\n\t116,\n\t114,\n\t105,\n\t116,\n\t111,\n\t116,\n\t195,\n\t169,\n\t99,\n\t110,\n\t105,\n\t99,\n\t97,\n\t99,\n\t111,\n\t110,\n\t106,\n\t117,\n\t110,\n\t116,\n\t111,\n\t101,\n\t110,\n\t101,\n\t114,\n\t103,\n\t195,\n\t173,\n\t97,\n\t116,\n\t114,\n\t97,\n\t98,\n\t97,\n\t106,\n\t97,\n\t114,\n\t97,\n\t115,\n\t116,\n\t117,\n\t114,\n\t105,\n\t97,\n\t115,\n\t114,\n\t101,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t117,\n\t116,\n\t105,\n\t108,\n\t105,\n\t122,\n\t97,\n\t114,\n\t98,\n\t111,\n\t108,\n\t101,\n\t116,\n\t195,\n\t173,\n\t110,\n\t115,\n\t97,\n\t108,\n\t118,\n\t97,\n\t100,\n\t111,\n\t114,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t99,\n\t116,\n\t97,\n\t116,\n\t114,\n\t97,\n\t98,\n\t97,\n\t106,\n\t111,\n\t115,\n\t112,\n\t114,\n\t105,\n\t109,\n\t101,\n\t114,\n\t111,\n\t115,\n\t110,\n\t101,\n\t103,\n\t111,\n\t99,\n\t105,\n\t111,\n\t115,\n\t108,\n\t105,\n\t98,\n\t101,\n\t114,\n\t116,\n\t97,\n\t100,\n\t100,\n\t101,\n\t116,\n\t97,\n\t108,\n\t108,\n\t101,\n\t115,\n\t112,\n\t97,\n\t110,\n\t116,\n\t97,\n\t108,\n\t108,\n\t97,\n\t112,\n\t114,\n\t195,\n\t179,\n\t120,\n\t105,\n\t109,\n\t111,\n\t97,\n\t108,\n\t109,\n\t101,\n\t114,\n\t195,\n\t173,\n\t97,\n\t97,\n\t110,\n\t105,\n\t109,\n\t97,\n\t108,\n\t101,\n\t115,\n\t113,\n\t117,\n\t105,\n\t195,\n\t169,\n\t110,\n\t101,\n\t115,\n\t99,\n\t111,\n\t114,\n\t97,\n\t122,\n\t195,\n\t179,\n\t110,\n\t115,\n\t101,\n\t99,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t98,\n\t117,\n\t115,\n\t99,\n\t97,\n\t110,\n\t100,\n\t111,\n\t111,\n\t112,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t101,\n\t120,\n\t116,\n\t101,\n\t114,\n\t105,\n\t111,\n\t114,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t112,\n\t116,\n\t111,\n\t116,\n\t111,\n\t100,\n\t97,\n\t118,\n\t195,\n\t173,\n\t97,\n\t103,\n\t97,\n\t108,\n\t101,\n\t114,\n\t195,\n\t173,\n\t97,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t105,\n\t114,\n\t109,\n\t101,\n\t100,\n\t105,\n\t99,\n\t105,\n\t110,\n\t97,\n\t108,\n\t105,\n\t99,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t99,\n\t111,\n\t110,\n\t115,\n\t117,\n\t108,\n\t116,\n\t97,\n\t97,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t111,\n\t115,\n\t99,\n\t114,\n\t195,\n\t173,\n\t116,\n\t105,\n\t99,\n\t97,\n\t100,\n\t195,\n\t179,\n\t108,\n\t97,\n\t114,\n\t101,\n\t115,\n\t106,\n\t117,\n\t115,\n\t116,\n\t105,\n\t99,\n\t105,\n\t97,\n\t100,\n\t101,\n\t98,\n\t101,\n\t114,\n\t195,\n\t161,\n\t110,\n\t112,\n\t101,\n\t114,\n\t195,\n\t173,\n\t111,\n\t100,\n\t111,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t105,\n\t116,\n\t97,\n\t109,\n\t97,\n\t110,\n\t116,\n\t101,\n\t110,\n\t101,\n\t114,\n\t112,\n\t101,\n\t113,\n\t117,\n\t101,\n\t195,\n\t177,\n\t111,\n\t114,\n\t101,\n\t99,\n\t105,\n\t98,\n\t105,\n\t100,\n\t97,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t110,\n\t97,\n\t108,\n\t116,\n\t101,\n\t110,\n\t101,\n\t114,\n\t105,\n\t102,\n\t101,\n\t99,\n\t97,\n\t110,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t97,\n\t110,\n\t97,\n\t114,\n\t105,\n\t97,\n\t115,\n\t100,\n\t101,\n\t115,\n\t99,\n\t97,\n\t114,\n\t103,\n\t97,\n\t100,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t111,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t111,\n\t114,\n\t99,\n\t97,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t101,\n\t114,\n\t101,\n\t116,\n\t195,\n\t169,\n\t99,\n\t110,\n\t105,\n\t99,\n\t111,\n\t100,\n\t101,\n\t98,\n\t101,\n\t114,\n\t195,\n\t173,\n\t97,\n\t118,\n\t105,\n\t118,\n\t105,\n\t101,\n\t110,\n\t100,\n\t97,\n\t102,\n\t105,\n\t110,\n\t97,\n\t110,\n\t122,\n\t97,\n\t115,\n\t97,\n\t100,\n\t101,\n\t108,\n\t97,\n\t110,\n\t116,\n\t101,\n\t102,\n\t117,\n\t110,\n\t99,\n\t105,\n\t111,\n\t110,\n\t97,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t106,\n\t111,\n\t115,\n\t100,\n\t105,\n\t102,\n\t195,\n\t173,\n\t99,\n\t105,\n\t108,\n\t99,\n\t105,\n\t117,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t97,\n\t110,\n\t116,\n\t105,\n\t103,\n\t117,\n\t97,\n\t115,\n\t97,\n\t118,\n\t97,\n\t110,\n\t122,\n\t97,\n\t100,\n\t97,\n\t116,\n\t195,\n\t169,\n\t114,\n\t109,\n\t105,\n\t110,\n\t111,\n\t117,\n\t110,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t115,\n\t195,\n\t161,\n\t110,\n\t99,\n\t104,\n\t101,\n\t122,\n\t99,\n\t97,\n\t109,\n\t112,\n\t97,\n\t195,\n\t177,\n\t97,\n\t115,\n\t111,\n\t102,\n\t116,\n\t111,\n\t110,\n\t105,\n\t99,\n\t114,\n\t101,\n\t118,\n\t105,\n\t115,\n\t116,\n\t97,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t101,\n\t110,\n\t101,\n\t115,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t101,\n\t115,\n\t109,\n\t111,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t115,\n\t102,\n\t97,\n\t99,\n\t117,\n\t108,\n\t116,\n\t97,\n\t100,\n\t99,\n\t114,\n\t195,\n\t169,\n\t100,\n\t105,\n\t116,\n\t111,\n\t100,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t97,\n\t115,\n\t115,\n\t117,\n\t112,\n\t117,\n\t101,\n\t115,\n\t116,\n\t111,\n\t102,\n\t97,\n\t99,\n\t116,\n\t111,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t103,\n\t117,\n\t110,\n\t100,\n\t111,\n\t115,\n\t112,\n\t101,\n\t113,\n\t117,\n\t101,\n\t195,\n\t177,\n\t97,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t184,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t177,\n\t209,\n\t139,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t139,\n\t209,\n\t130,\n\t209,\n\t140,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t149,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t143,\n\t208,\n\t178,\n\t209,\n\t129,\n\t208,\n\t181,\n\t209,\n\t133,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t182,\n\t208,\n\t181,\n\t208,\n\t177,\n\t209,\n\t139,\n\t208,\n\t187,\n\t208,\n\t184,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t180,\n\t209,\n\t131,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t140,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t177,\n\t209,\n\t139,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t177,\n\t209,\n\t143,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t177,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t180,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t185,\n\t209,\n\t130,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t184,\n\t208,\n\t179,\n\t209,\n\t128,\n\t209,\n\t139,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t182,\n\t208,\n\t181,\n\t208,\n\t178,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t209,\n\t142,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t136,\n\t209,\n\t140,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t184,\n\t209,\n\t133,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t180,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t180,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t184,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t187,\n\t208,\n\t184,\n\t208,\n\t177,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t131,\n\t209,\n\t133,\n\t208,\n\t190,\n\t209,\n\t130,\n\t209,\n\t143,\n\t208,\n\t180,\n\t208,\n\t178,\n\t209,\n\t131,\n\t209,\n\t133,\n\t209,\n\t129,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t187,\n\t209,\n\t142,\n\t208,\n\t180,\n\t208,\n\t184,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t184,\n\t209,\n\t128,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t177,\n\t209,\n\t143,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t181,\n\t208,\n\t178,\n\t208,\n\t184,\n\t208,\n\t180,\n\t208,\n\t181,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t188,\n\t209,\n\t129,\n\t209,\n\t135,\n\t208,\n\t181,\n\t209,\n\t130,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t139,\n\t209,\n\t134,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t139,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t187,\n\t208,\n\t178,\n\t208,\n\t181,\n\t208,\n\t180,\n\t209,\n\t140,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t180,\n\t209,\n\t139,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t177,\n\t208,\n\t181,\n\t208,\n\t178,\n\t209,\n\t139,\n\t209,\n\t136,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t191,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t131,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t134,\n\t208,\n\t176,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t180,\n\t209,\n\t139,\n\t208,\n\t183,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t142,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t179,\n\t209,\n\t131,\n\t208,\n\t180,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t179,\n\t208,\n\t178,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t184,\n\t208,\n\t180,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t176,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t186,\n\t208,\n\t184,\n\t209,\n\t142,\n\t208,\n\t189,\n\t209,\n\t143,\n\t208,\n\t178,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t140,\n\t208,\n\t149,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t140,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t136,\n\t208,\n\t184,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t132,\n\t217,\n\t135,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t217,\n\t138,\n\t216,\n\t172,\n\t217,\n\t133,\n\t217,\n\t138,\n\t216,\n\t185,\n\t216,\n\t174,\n\t216,\n\t167,\n\t216,\n\t181,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t176,\n\t217,\n\t138,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t135,\n\t216,\n\t172,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t162,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t175,\n\t216,\n\t170,\n\t216,\n\t173,\n\t217,\n\t131,\n\t217,\n\t133,\n\t216,\n\t181,\n\t217,\n\t129,\n\t216,\n\t173,\n\t216,\n\t169,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t138,\n\t217,\n\t131,\n\t217,\n\t136,\n\t217,\n\t134,\n\t216,\n\t180,\n\t216,\n\t168,\n\t217,\n\t131,\n\t216,\n\t169,\n\t217,\n\t129,\n\t217,\n\t138,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t168,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t173,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t161,\n\t216,\n\t163,\n\t217,\n\t131,\n\t216,\n\t171,\n\t216,\n\t177,\n\t216,\n\t174,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t173,\n\t216,\n\t168,\n\t216,\n\t175,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t132,\n\t216,\n\t175,\n\t216,\n\t177,\n\t217,\n\t136,\n\t216,\n\t179,\n\t216,\n\t167,\n\t216,\n\t182,\n\t216,\n\t186,\n\t216,\n\t183,\n\t216,\n\t170,\n\t217,\n\t131,\n\t217,\n\t136,\n\t217,\n\t134,\n\t217,\n\t135,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t131,\n\t216,\n\t179,\n\t216,\n\t167,\n\t216,\n\t173,\n\t216,\n\t169,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t183,\n\t216,\n\t168,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t131,\n\t216,\n\t180,\n\t217,\n\t131,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t138,\n\t217,\n\t133,\n\t217,\n\t131,\n\t217,\n\t134,\n\t217,\n\t133,\n\t217,\n\t134,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t180,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t169,\n\t216,\n\t177,\n\t216,\n\t166,\n\t217,\n\t138,\n\t216,\n\t179,\n\t217,\n\t134,\n\t216,\n\t180,\n\t217,\n\t138,\n\t216,\n\t183,\n\t217,\n\t133,\n\t216,\n\t167,\n\t216,\n\t176,\n\t216,\n\t167,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t129,\n\t217,\n\t134,\n\t216,\n\t180,\n\t216,\n\t168,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t170,\n\t216,\n\t185,\n\t216,\n\t168,\n\t216,\n\t177,\n\t216,\n\t177,\n\t216,\n\t173,\n\t217,\n\t133,\n\t216,\n\t169,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t129,\n\t216,\n\t169,\n\t217,\n\t138,\n\t217,\n\t130,\n\t217,\n\t136,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t178,\n\t217,\n\t131,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t169,\n\t216,\n\t163,\n\t216,\n\t173,\n\t217,\n\t133,\n\t216,\n\t175,\n\t217,\n\t130,\n\t217,\n\t132,\n\t216,\n\t168,\n\t217,\n\t138,\n\t217,\n\t138,\n\t216,\n\t185,\n\t217,\n\t134,\n\t217,\n\t138,\n\t216,\n\t181,\n\t217,\n\t136,\n\t216,\n\t177,\n\t216,\n\t169,\n\t216,\n\t183,\n\t216,\n\t177,\n\t217,\n\t138,\n\t217,\n\t130,\n\t216,\n\t180,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t172,\n\t217,\n\t136,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t216,\n\t174,\n\t216,\n\t177,\n\t217,\n\t137,\n\t217,\n\t133,\n\t216,\n\t185,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t173,\n\t216,\n\t171,\n\t216,\n\t185,\n\t216,\n\t177,\n\t217,\n\t136,\n\t216,\n\t182,\n\t216,\n\t168,\n\t216,\n\t180,\n\t217,\n\t131,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t179,\n\t216,\n\t172,\n\t217,\n\t132,\n\t216,\n\t168,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t134,\n\t216,\n\t174,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t167,\n\t216,\n\t168,\n\t217,\n\t131,\n\t217,\n\t132,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t168,\n\t216,\n\t175,\n\t217,\n\t136,\n\t217,\n\t134,\n\t216,\n\t163,\n\t217,\n\t138,\n\t216,\n\t182,\n\t216,\n\t167,\n\t217,\n\t138,\n\t217,\n\t136,\n\t216,\n\t172,\n\t216,\n\t175,\n\t217,\n\t129,\n\t216,\n\t177,\n\t217,\n\t138,\n\t217,\n\t130,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t168,\n\t216,\n\t170,\n\t216,\n\t163,\n\t217,\n\t129,\n\t216,\n\t182,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t183,\n\t216,\n\t168,\n\t216,\n\t174,\n\t216,\n\t167,\n\t217,\n\t131,\n\t216,\n\t171,\n\t216,\n\t177,\n\t216,\n\t168,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t129,\n\t216,\n\t182,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t173,\n\t217,\n\t132,\n\t217,\n\t137,\n\t217,\n\t134,\n\t217,\n\t129,\n\t216,\n\t179,\n\t217,\n\t135,\n\t216,\n\t163,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t177,\n\t216,\n\t175,\n\t217,\n\t136,\n\t216,\n\t175,\n\t216,\n\t163,\n\t217,\n\t134,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t175,\n\t217,\n\t138,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t134,\n\t217,\n\t133,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t182,\n\t216,\n\t170,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t175,\n\t216,\n\t167,\n\t216,\n\t174,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t133,\n\t217,\n\t131,\n\t217,\n\t134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t1,\n\t0,\n\t2,\n\t0,\n\t2,\n\t0,\n\t2,\n\t0,\n\t2,\n\t0,\n\t4,\n\t0,\n\t4,\n\t0,\n\t4,\n\t0,\n\t4,\n\t0,\n\t0,\n\t1,\n\t2,\n\t3,\n\t4,\n\t5,\n\t6,\n\t7,\n\t7,\n\t6,\n\t5,\n\t4,\n\t3,\n\t2,\n\t1,\n\t0,\n\t8,\n\t9,\n\t10,\n\t11,\n\t12,\n\t13,\n\t14,\n\t15,\n\t15,\n\t14,\n\t13,\n\t12,\n\t11,\n\t10,\n\t9,\n\t8,\n\t16,\n\t17,\n\t18,\n\t19,\n\t20,\n\t21,\n\t22,\n\t23,\n\t23,\n\t22,\n\t21,\n\t20,\n\t19,\n\t18,\n\t17,\n\t16,\n\t24,\n\t25,\n\t26,\n\t27,\n\t28,\n\t29,\n\t30,\n\t31,\n\t31,\n\t30,\n\t29,\n\t28,\n\t27,\n\t26,\n\t25,\n\t24,\n\t255,\n\t255,\n\t255,\n\t255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t255,\n\t255,\n\t255,\n\t255,\n\t1,\n\t0,\n\t0,\n\t0,\n\t2,\n\t0,\n\t0,\n\t0,\n\t2,\n\t0,\n\t0,\n\t0,\n\t1,\n\t0,\n\t0,\n\t0,\n\t1,\n\t0,\n\t0,\n\t0,\n\t3,\n\t0,\n\t0,\n\t0,\n\t255,\n\t255,\n\t0,\n\t1,\n\t0,\n\t0,\n\t0,\n\t1,\n\t0,\n\t0,\n\t255,\n\t255,\n\t0,\n\t1,\n\t0,\n\t0,\n\t0,\n\t8,\n\t0,\n\t8,\n\t0,\n\t8,\n\t0,\n\t8,\n\t0,\n\t0,\n\t0,\n\t1,\n\t0,\n\t2,\n\t0,\n\t3,\n\t0,\n\t4,\n\t0,\n\t5,\n\t0,\n\t6,\n\t0,\n\t7,\n\t114,\n\t101,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t115,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t113,\n\t117,\n\t105,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t116,\n\t121,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t104,\n\t105,\n\t103,\n\t104,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t68,\n\t84,\n\t68,\n\t47,\n\t120,\n\t104,\n\t116,\n\t109,\n\t108,\n\t109,\n\t97,\n\t114,\n\t107,\n\t101,\n\t116,\n\t105,\n\t110,\n\t103,\n\t107,\n\t110,\n\t111,\n\t119,\n\t108,\n\t101,\n\t100,\n\t103,\n\t101,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t114,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t117,\n\t98,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t97,\n\t100,\n\t118,\n\t101,\n\t114,\n\t116,\n\t105,\n\t115,\n\t101,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t60,\n\t47,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t62,\n\t65,\n\t117,\n\t115,\n\t116,\n\t114,\n\t97,\n\t108,\n\t105,\n\t97,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t115,\n\t105,\n\t116,\n\t117,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t105,\n\t109,\n\t97,\n\t114,\n\t105,\n\t108,\n\t121,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t104,\n\t97,\n\t108,\n\t108,\n\t101,\n\t110,\n\t103,\n\t101,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t97,\n\t110,\n\t111,\n\t110,\n\t121,\n\t109,\n\t111,\n\t117,\n\t115,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t105,\n\t101,\n\t115,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t34,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t112,\n\t111,\n\t116,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t101,\n\t100,\n\t117,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t103,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t115,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t97,\n\t114,\n\t121,\n\t99,\n\t111,\n\t112,\n\t121,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t115,\n\t101,\n\t120,\n\t99,\n\t108,\n\t117,\n\t115,\n\t105,\n\t118,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t60,\n\t47,\n\t102,\n\t111,\n\t114,\n\t109,\n\t62,\n\t13,\n\t10,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t116,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t66,\n\t105,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t121,\n\t125,\n\t32,\n\t101,\n\t108,\n\t115,\n\t101,\n\t32,\n\t123,\n\t10,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t119,\n\t104,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t65,\n\t110,\n\t97,\n\t108,\n\t121,\n\t116,\n\t105,\n\t99,\n\t115,\n\t116,\n\t101,\n\t109,\n\t112,\n\t108,\n\t97,\n\t116,\n\t101,\n\t115,\n\t100,\n\t97,\n\t110,\n\t103,\n\t101,\n\t114,\n\t111,\n\t117,\n\t115,\n\t115,\n\t97,\n\t116,\n\t101,\n\t108,\n\t108,\n\t105,\n\t116,\n\t101,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t114,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t112,\n\t114,\n\t111,\n\t116,\n\t111,\n\t116,\n\t121,\n\t112,\n\t101,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t38,\n\t114,\n\t97,\n\t113,\n\t117,\n\t111,\n\t59,\n\t60,\n\t47,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t121,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t102,\n\t111,\n\t114,\n\t109,\n\t98,\n\t101,\n\t97,\n\t117,\n\t116,\n\t105,\n\t102,\n\t117,\n\t108,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t122,\n\t101,\n\t100,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t109,\n\t105,\n\t110,\n\t101,\n\t110,\n\t116,\n\t117,\n\t110,\n\t116,\n\t105,\n\t108,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t117,\n\t109,\n\t98,\n\t110,\n\t97,\n\t105,\n\t108,\n\t78,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t46,\n\t102,\n\t111,\n\t99,\n\t117,\n\t115,\n\t40,\n\t41,\n\t59,\n\t111,\n\t118,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t105,\n\t103,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t110,\n\t110,\n\t111,\n\t117,\n\t110,\n\t99,\n\t101,\n\t100,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t34,\n\t62,\n\t10,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t108,\n\t101,\n\t115,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t101,\n\t120,\n\t112,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t119,\n\t111,\n\t114,\n\t107,\n\t116,\n\t101,\n\t114,\n\t114,\n\t105,\n\t116,\n\t111,\n\t114,\n\t121,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t78,\n\t97,\n\t109,\n\t101,\n\t99,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t105,\n\t115,\n\t109,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t108,\n\t115,\n\t101,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t65,\n\t108,\n\t101,\n\t120,\n\t97,\n\t110,\n\t100,\n\t101,\n\t114,\n\t97,\n\t112,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t100,\n\t109,\n\t97,\n\t116,\n\t101,\n\t114,\n\t105,\n\t97,\n\t108,\n\t115,\n\t98,\n\t114,\n\t111,\n\t97,\n\t100,\n\t99,\n\t97,\n\t115,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t100,\n\t97,\n\t102,\n\t102,\n\t105,\n\t108,\n\t105,\n\t97,\n\t116,\n\t101,\n\t60,\n\t47,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t62,\n\t116,\n\t114,\n\t101,\n\t97,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t47,\n\t100,\n\t101,\n\t102,\n\t97,\n\t117,\n\t108,\n\t116,\n\t46,\n\t80,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t111,\n\t110,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t61,\n\t34,\n\t98,\n\t105,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t121,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t119,\n\t105,\n\t115,\n\t101,\n\t112,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t101,\n\t110,\n\t116,\n\t70,\n\t114,\n\t97,\n\t110,\n\t195,\n\t167,\n\t97,\n\t105,\n\t115,\n\t72,\n\t111,\n\t108,\n\t108,\n\t121,\n\t119,\n\t111,\n\t111,\n\t100,\n\t101,\n\t120,\n\t112,\n\t97,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t97,\n\t114,\n\t100,\n\t115,\n\t60,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t62,\n\t10,\n\t114,\n\t101,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t68,\n\t101,\n\t99,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t112,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t67,\n\t97,\n\t109,\n\t98,\n\t114,\n\t105,\n\t100,\n\t103,\n\t101,\n\t111,\n\t112,\n\t112,\n\t111,\n\t110,\n\t101,\n\t110,\n\t116,\n\t115,\n\t66,\n\t117,\n\t115,\n\t105,\n\t110,\n\t101,\n\t115,\n\t115,\n\t32,\n\t99,\n\t111,\n\t110,\n\t102,\n\t117,\n\t115,\n\t105,\n\t111,\n\t110,\n\t62,\n\t10,\n\t60,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t101,\n\t120,\n\t112,\n\t108,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t100,\n\t111,\n\t101,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t119,\n\t105,\n\t100,\n\t101,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t102,\n\t97,\n\t99,\n\t101,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t110,\n\t101,\n\t119,\n\t115,\n\t112,\n\t97,\n\t112,\n\t101,\n\t114,\n\t60,\n\t47,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t62,\n\t10,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t115,\n\t108,\n\t105,\n\t107,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t115,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t102,\n\t105,\n\t110,\n\t97,\n\t110,\n\t99,\n\t105,\n\t97,\n\t108,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t47,\n\t97,\n\t98,\n\t97,\n\t110,\n\t100,\n\t111,\n\t110,\n\t101,\n\t100,\n\t69,\n\t100,\n\t117,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t97,\n\t114,\n\t115,\n\t101,\n\t73,\n\t110,\n\t116,\n\t40,\n\t115,\n\t116,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t117,\n\t110,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t60,\n\t47,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t10,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t78,\n\t111,\n\t116,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t101,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t112,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t100,\n\t116,\n\t119,\n\t111,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t83,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t119,\n\t114,\n\t97,\n\t112,\n\t112,\n\t101,\n\t114,\n\t34,\n\t62,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t101,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t101,\n\t100,\n\t66,\n\t97,\n\t116,\n\t116,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t112,\n\t101,\n\t114,\n\t99,\n\t101,\n\t105,\n\t118,\n\t101,\n\t100,\n\t116,\n\t114,\n\t121,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t115,\n\t97,\n\t114,\n\t121,\n\t112,\n\t111,\n\t114,\n\t116,\n\t114,\n\t97,\n\t121,\n\t101,\n\t100,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t69,\n\t108,\n\t105,\n\t122,\n\t97,\n\t98,\n\t101,\n\t116,\n\t104,\n\t60,\n\t47,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t62,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t121,\n\t105,\n\t110,\n\t115,\n\t117,\n\t114,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t46,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t59,\n\t108,\n\t101,\n\t103,\n\t101,\n\t110,\n\t100,\n\t97,\n\t114,\n\t121,\n\t71,\n\t101,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t121,\n\t99,\n\t97,\n\t110,\n\t100,\n\t105,\n\t100,\n\t97,\n\t116,\n\t101,\n\t99,\n\t111,\n\t114,\n\t112,\n\t111,\n\t114,\n\t97,\n\t116,\n\t101,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t115,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t46,\n\t105,\n\t110,\n\t104,\n\t101,\n\t114,\n\t105,\n\t116,\n\t101,\n\t100,\n\t60,\n\t47,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t62,\n\t67,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t116,\n\t121,\n\t114,\n\t101,\n\t108,\n\t105,\n\t103,\n\t105,\n\t111,\n\t117,\n\t115,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t67,\n\t111,\n\t109,\n\t109,\n\t105,\n\t116,\n\t116,\n\t101,\n\t101,\n\t98,\n\t117,\n\t105,\n\t108,\n\t100,\n\t105,\n\t110,\n\t103,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t110,\n\t111,\n\t32,\n\t108,\n\t111,\n\t110,\n\t103,\n\t101,\n\t114,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t99,\n\t97,\n\t110,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t102,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t121,\n\t116,\n\t121,\n\t112,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t105,\n\t110,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t59,\n\t114,\n\t101,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t105,\n\t113,\n\t117,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t105,\n\t116,\n\t32,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t99,\n\t101,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t108,\n\t105,\n\t110,\n\t101,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t116,\n\t101,\n\t108,\n\t101,\n\t112,\n\t104,\n\t111,\n\t110,\n\t101,\n\t105,\n\t116,\n\t101,\n\t109,\n\t115,\n\t99,\n\t111,\n\t112,\n\t101,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t101,\n\t115,\n\t97,\n\t100,\n\t118,\n\t97,\n\t110,\n\t116,\n\t97,\n\t103,\n\t101,\n\t41,\n\t59,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t70,\n\t111,\n\t114,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t109,\n\t111,\n\t99,\n\t114,\n\t97,\n\t99,\n\t121,\n\t98,\n\t111,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t115,\n\t117,\n\t102,\n\t102,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t100,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t101,\n\t114,\n\t115,\n\t32,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t115,\n\t97,\n\t105,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t116,\n\t32,\n\t109,\n\t97,\n\t121,\n\t32,\n\t98,\n\t101,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t60,\n\t47,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t99,\n\t104,\n\t101,\n\t100,\n\t117,\n\t108,\n\t101,\n\t100,\n\t100,\n\t111,\n\t119,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t115,\n\t60,\n\t47,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t62,\n\t10,\n\t115,\n\t117,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t58,\n\t32,\n\t48,\n\t115,\n\t112,\n\t105,\n\t114,\n\t105,\n\t116,\n\t117,\n\t97,\n\t108,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t10,\n\t109,\n\t105,\n\t99,\n\t114,\n\t111,\n\t115,\n\t111,\n\t102,\n\t116,\n\t103,\n\t114,\n\t97,\n\t100,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t100,\n\t105,\n\t115,\n\t99,\n\t117,\n\t115,\n\t115,\n\t101,\n\t100,\n\t104,\n\t101,\n\t32,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t101,\n\t120,\n\t101,\n\t99,\n\t117,\n\t116,\n\t105,\n\t118,\n\t101,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t46,\n\t106,\n\t115,\n\t104,\n\t111,\n\t117,\n\t115,\n\t101,\n\t104,\n\t111,\n\t108,\n\t100,\n\t99,\n\t111,\n\t110,\n\t102,\n\t105,\n\t114,\n\t109,\n\t101,\n\t100,\n\t112,\n\t117,\n\t114,\n\t99,\n\t104,\n\t97,\n\t115,\n\t101,\n\t100,\n\t108,\n\t105,\n\t116,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t121,\n\t100,\n\t101,\n\t115,\n\t116,\n\t114,\n\t111,\n\t121,\n\t101,\n\t100,\n\t117,\n\t112,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t118,\n\t97,\n\t114,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t105,\n\t101,\n\t115,\n\t74,\n\t97,\n\t112,\n\t97,\n\t110,\n\t101,\n\t115,\n\t101,\n\t32,\n\t97,\n\t109,\n\t111,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t100,\n\t97,\n\t108,\n\t103,\n\t111,\n\t114,\n\t105,\n\t116,\n\t104,\n\t109,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t115,\n\t114,\n\t101,\n\t98,\n\t101,\n\t108,\n\t108,\n\t105,\n\t111,\n\t110,\n\t117,\n\t110,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t101,\n\t110,\n\t99,\n\t111,\n\t117,\n\t114,\n\t97,\n\t103,\n\t101,\n\t114,\n\t101,\n\t115,\n\t105,\n\t122,\n\t97,\n\t98,\n\t108,\n\t101,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t118,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t110,\n\t115,\n\t105,\n\t116,\n\t105,\n\t118,\n\t101,\n\t117,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t97,\n\t108,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t40,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t99,\n\t111,\n\t110,\n\t100,\n\t117,\n\t99,\n\t116,\n\t101,\n\t100,\n\t41,\n\t44,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t100,\n\t45,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t34,\n\t62,\n\t70,\n\t101,\n\t98,\n\t114,\n\t117,\n\t97,\n\t114,\n\t121,\n\t32,\n\t110,\n\t117,\n\t109,\n\t101,\n\t114,\n\t111,\n\t117,\n\t115,\n\t32,\n\t111,\n\t118,\n\t101,\n\t114,\n\t102,\n\t108,\n\t111,\n\t119,\n\t58,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t110,\n\t101,\n\t110,\n\t116,\n\t102,\n\t114,\n\t97,\n\t103,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t101,\n\t120,\n\t99,\n\t101,\n\t108,\n\t108,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t108,\n\t115,\n\t112,\n\t97,\n\t110,\n\t61,\n\t34,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t105,\n\t99,\n\t97,\n\t108,\n\t110,\n\t101,\n\t97,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t65,\n\t100,\n\t118,\n\t97,\n\t110,\n\t99,\n\t101,\n\t100,\n\t32,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t101,\n\t120,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t100,\n\t72,\n\t111,\n\t110,\n\t103,\n\t32,\n\t75,\n\t111,\n\t110,\n\t103,\n\t32,\n\t70,\n\t97,\n\t99,\n\t101,\n\t98,\n\t111,\n\t111,\n\t107,\n\t109,\n\t117,\n\t108,\n\t116,\n\t105,\n\t112,\n\t108,\n\t101,\n\t32,\n\t109,\n\t101,\n\t99,\n\t104,\n\t97,\n\t110,\n\t105,\n\t115,\n\t109,\n\t101,\n\t108,\n\t101,\n\t118,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t102,\n\t102,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t60,\n\t47,\n\t102,\n\t111,\n\t114,\n\t109,\n\t62,\n\t10,\n\t9,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t111,\n\t114,\n\t101,\n\t100,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t111,\n\t114,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t116,\n\t104,\n\t111,\n\t115,\n\t101,\n\t32,\n\t119,\n\t104,\n\t111,\n\t109,\n\t111,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t101,\n\t115,\n\t100,\n\t105,\n\t102,\n\t102,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t116,\n\t101,\n\t100,\n\t114,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t110,\n\t100,\n\t99,\n\t111,\n\t110,\n\t118,\n\t105,\n\t110,\n\t99,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t109,\n\t111,\n\t116,\n\t105,\n\t110,\n\t103,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t46,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t40,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t99,\n\t97,\n\t108,\n\t99,\n\t111,\n\t97,\n\t108,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t104,\n\t105,\n\t115,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t100,\n\t101,\n\t99,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t97,\n\t115,\n\t115,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t101,\n\t118,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t45,\n\t119,\n\t114,\n\t97,\n\t112,\n\t112,\n\t101,\n\t114,\n\t34,\n\t101,\n\t110,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t111,\n\t97,\n\t108,\n\t111,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t101,\n\t108,\n\t105,\n\t118,\n\t101,\n\t114,\n\t101,\n\t100,\n\t45,\n\t45,\n\t62,\n\t13,\n\t10,\n\t60,\n\t33,\n\t45,\n\t45,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t32,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t78,\n\t111,\n\t118,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t60,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t62,\n\t60,\n\t102,\n\t117,\n\t114,\n\t110,\n\t105,\n\t116,\n\t117,\n\t114,\n\t101,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t101,\n\t116,\n\t32,\n\t32,\n\t111,\n\t110,\n\t98,\n\t108,\n\t117,\n\t114,\n\t61,\n\t34,\n\t115,\n\t117,\n\t115,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t114,\n\t101,\n\t99,\n\t105,\n\t112,\n\t105,\n\t101,\n\t110,\n\t116,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t32,\n\t77,\n\t111,\n\t114,\n\t101,\n\t111,\n\t118,\n\t101,\n\t114,\n\t44,\n\t97,\n\t98,\n\t111,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t109,\n\t97,\n\t100,\n\t101,\n\t101,\n\t109,\n\t111,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t101,\n\t109,\n\t101,\n\t114,\n\t103,\n\t101,\n\t110,\n\t99,\n\t121,\n\t110,\n\t97,\n\t114,\n\t114,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t97,\n\t100,\n\t118,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t115,\n\t112,\n\t120,\n\t59,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t99,\n\t111,\n\t109,\n\t109,\n\t105,\n\t116,\n\t116,\n\t101,\n\t100,\n\t100,\n\t105,\n\t114,\n\t61,\n\t34,\n\t108,\n\t116,\n\t114,\n\t34,\n\t101,\n\t109,\n\t112,\n\t108,\n\t111,\n\t121,\n\t101,\n\t101,\n\t115,\n\t114,\n\t101,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t46,\n\t32,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t111,\n\t114,\n\t99,\n\t117,\n\t115,\n\t116,\n\t111,\n\t109,\n\t101,\n\t114,\n\t115,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t101,\n\t100,\n\t83,\n\t101,\n\t112,\n\t116,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t97,\n\t100,\n\t100,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t40,\n\t70,\n\t97,\n\t99,\n\t101,\n\t98,\n\t111,\n\t111,\n\t107,\n\t32,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t101,\n\t100,\n\t97,\n\t110,\n\t100,\n\t32,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t101,\n\t108,\n\t97,\n\t98,\n\t111,\n\t114,\n\t97,\n\t116,\n\t101,\n\t83,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t73,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t101,\n\t99,\n\t101,\n\t114,\n\t116,\n\t97,\n\t105,\n\t110,\n\t108,\n\t121,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t114,\n\t115,\n\t74,\n\t101,\n\t114,\n\t117,\n\t115,\n\t97,\n\t108,\n\t101,\n\t109,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t105,\n\t110,\n\t103,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t110,\n\t99,\n\t101,\n\t115,\n\t103,\n\t117,\n\t97,\n\t114,\n\t97,\n\t110,\n\t116,\n\t101,\n\t101,\n\t97,\n\t114,\n\t98,\n\t105,\n\t116,\n\t114,\n\t97,\n\t114,\n\t121,\n\t114,\n\t101,\n\t99,\n\t111,\n\t103,\n\t110,\n\t105,\n\t122,\n\t101,\n\t119,\n\t97,\n\t110,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t112,\n\t120,\n\t59,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t98,\n\t101,\n\t104,\n\t97,\n\t118,\n\t105,\n\t111,\n\t117,\n\t114,\n\t87,\n\t104,\n\t105,\n\t108,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t115,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t100,\n\t98,\n\t101,\n\t103,\n\t97,\n\t110,\n\t32,\n\t116,\n\t111,\n\t32,\n\t105,\n\t116,\n\t32,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t109,\n\t97,\n\t103,\n\t110,\n\t105,\n\t116,\n\t117,\n\t100,\n\t101,\n\t109,\n\t117,\n\t115,\n\t116,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t68,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t121,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t99,\n\t114,\n\t101,\n\t116,\n\t97,\n\t114,\n\t121,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t108,\n\t121,\n\t111,\n\t99,\n\t99,\n\t117,\n\t114,\n\t114,\n\t105,\n\t110,\n\t103,\n\t118,\n\t97,\n\t114,\n\t105,\n\t97,\n\t98,\n\t108,\n\t101,\n\t115,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t108,\n\t97,\n\t116,\n\t102,\n\t111,\n\t114,\n\t109,\n\t46,\n\t60,\n\t47,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t62,\n\t60,\n\t102,\n\t97,\n\t105,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t117,\n\t110,\n\t100,\n\t115,\n\t107,\n\t105,\n\t110,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t115,\n\t111,\n\t99,\n\t105,\n\t101,\n\t116,\n\t105,\n\t101,\n\t115,\n\t97,\n\t108,\n\t111,\n\t110,\n\t103,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t45,\n\t45,\n\t38,\n\t103,\n\t116,\n\t59,\n\t10,\n\t10,\n\t115,\n\t111,\n\t117,\n\t116,\n\t104,\n\t119,\n\t101,\n\t115,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t109,\n\t97,\n\t121,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t117,\n\t110,\n\t101,\n\t115,\n\t99,\n\t97,\n\t112,\n\t101,\n\t40,\n\t115,\n\t112,\n\t111,\n\t107,\n\t101,\n\t110,\n\t32,\n\t105,\n\t110,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t101,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t121,\n\t98,\n\t117,\n\t114,\n\t105,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t97,\n\t32,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t119,\n\t101,\n\t114,\n\t101,\n\t60,\n\t47,\n\t102,\n\t111,\n\t110,\n\t116,\n\t62,\n\t60,\n\t47,\n\t78,\n\t111,\n\t114,\n\t119,\n\t101,\n\t103,\n\t105,\n\t97,\n\t110,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t105,\n\t110,\n\t103,\n\t112,\n\t97,\n\t115,\n\t115,\n\t101,\n\t110,\n\t103,\n\t101,\n\t114,\n\t40,\n\t110,\n\t101,\n\t119,\n\t32,\n\t68,\n\t97,\n\t116,\n\t101,\n\t116,\n\t101,\n\t109,\n\t112,\n\t111,\n\t114,\n\t97,\n\t114,\n\t121,\n\t102,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t65,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t113,\n\t117,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t100,\n\t111,\n\t119,\n\t110,\n\t108,\n\t111,\n\t97,\n\t100,\n\t46,\n\t114,\n\t101,\n\t103,\n\t117,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t98,\n\t111,\n\t118,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t108,\n\t105,\n\t110,\n\t107,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t112,\n\t104,\n\t101,\n\t110,\n\t111,\n\t109,\n\t101,\n\t110,\n\t97,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t32,\n\t111,\n\t102,\n\t116,\n\t111,\n\t111,\n\t108,\n\t116,\n\t105,\n\t112,\n\t34,\n\t62,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t97,\n\t117,\n\t116,\n\t111,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t97,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t32,\n\t111,\n\t102,\n\t65,\n\t109,\n\t111,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t101,\n\t115,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t115,\n\t65,\n\t105,\n\t114,\n\t32,\n\t70,\n\t111,\n\t114,\n\t99,\n\t101,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t32,\n\t111,\n\t102,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t105,\n\t109,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t116,\n\t101,\n\t109,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t116,\n\t112,\n\t97,\n\t105,\n\t110,\n\t116,\n\t105,\n\t110,\n\t103,\n\t115,\n\t99,\n\t111,\n\t110,\n\t113,\n\t117,\n\t101,\n\t114,\n\t101,\n\t100,\n\t97,\n\t114,\n\t101,\n\t32,\n\t115,\n\t116,\n\t105,\n\t108,\n\t108,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t100,\n\t117,\n\t114,\n\t101,\n\t103,\n\t114,\n\t111,\n\t119,\n\t116,\n\t104,\n\t32,\n\t111,\n\t102,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t97,\n\t110,\n\t32,\n\t100,\n\t105,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t109,\n\t111,\n\t108,\n\t101,\n\t99,\n\t117,\n\t108,\n\t101,\n\t115,\n\t102,\n\t114,\n\t97,\n\t110,\n\t99,\n\t104,\n\t105,\n\t115,\n\t101,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t116,\n\t116,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t100,\n\t99,\n\t104,\n\t105,\n\t108,\n\t100,\n\t104,\n\t111,\n\t111,\n\t100,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t100,\n\t101,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t115,\n\t105,\n\t110,\n\t103,\n\t97,\n\t112,\n\t111,\n\t114,\n\t101,\n\t100,\n\t101,\n\t103,\n\t114,\n\t101,\n\t101,\n\t32,\n\t111,\n\t102,\n\t102,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t102,\n\t108,\n\t105,\n\t99,\n\t116,\n\t115,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t112,\n\t62,\n\t10,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t110,\n\t111,\n\t116,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t114,\n\t101,\n\t99,\n\t101,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t69,\n\t120,\n\t101,\n\t99,\n\t117,\n\t116,\n\t105,\n\t118,\n\t101,\n\t101,\n\t118,\n\t101,\n\t110,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t32,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t109,\n\t97,\n\t110,\n\t100,\n\t101,\n\t114,\n\t80,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t109,\n\t117,\n\t115,\n\t105,\n\t99,\n\t105,\n\t97,\n\t110,\n\t115,\n\t100,\n\t101,\n\t108,\n\t105,\n\t99,\n\t105,\n\t111,\n\t117,\n\t115,\n\t112,\n\t114,\n\t105,\n\t115,\n\t111,\n\t110,\n\t101,\n\t114,\n\t115,\n\t97,\n\t100,\n\t118,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t85,\n\t84,\n\t70,\n\t45,\n\t56,\n\t34,\n\t32,\n\t47,\n\t62,\n\t60,\n\t33,\n\t91,\n\t67,\n\t68,\n\t65,\n\t84,\n\t65,\n\t91,\n\t34,\n\t62,\n\t67,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t83,\n\t111,\n\t117,\n\t116,\n\t104,\n\t101,\n\t114,\n\t110,\n\t32,\n\t98,\n\t103,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t61,\n\t34,\n\t115,\n\t101,\n\t114,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t46,\n\t32,\n\t73,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t105,\n\t110,\n\t32,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t112,\n\t101,\n\t114,\n\t109,\n\t105,\n\t116,\n\t116,\n\t101,\n\t100,\n\t118,\n\t97,\n\t108,\n\t105,\n\t100,\n\t97,\n\t116,\n\t101,\n\t46,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t105,\n\t110,\n\t103,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t115,\n\t115,\n\t101,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t108,\n\t121,\n\t45,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t108,\n\t111,\n\t110,\n\t103,\n\t45,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t102,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t117,\n\t99,\n\t104,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t103,\n\t101,\n\t116,\n\t67,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t109,\n\t97,\n\t114,\n\t107,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t60,\n\t47,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t62,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t98,\n\t117,\n\t116,\n\t32,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t101,\n\t115,\n\t100,\n\t111,\n\t119,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t116,\n\t45,\n\t45,\n\t62,\n\t10,\n\t60,\n\t33,\n\t45,\n\t45,\n\t32,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t118,\n\t105,\n\t101,\n\t119,\n\t87,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t112,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t110,\n\t115,\n\t117,\n\t115,\n\t119,\n\t97,\n\t115,\n\t32,\n\t98,\n\t117,\n\t105,\n\t108,\n\t116,\n\t86,\n\t101,\n\t110,\n\t101,\n\t122,\n\t117,\n\t101,\n\t108,\n\t97,\n\t40,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t114,\n\t108,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t110,\n\t101,\n\t108,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t103,\n\t105,\n\t99,\n\t102,\n\t97,\n\t118,\n\t111,\n\t117,\n\t114,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t87,\n\t105,\n\t107,\n\t105,\n\t112,\n\t101,\n\t100,\n\t105,\n\t97,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t101,\n\t110,\n\t116,\n\t118,\n\t105,\n\t114,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t119,\n\t97,\n\t115,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t108,\n\t101,\n\t67,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t32,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t115,\n\t104,\n\t111,\n\t119,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t112,\n\t114,\n\t105,\n\t109,\n\t105,\n\t116,\n\t105,\n\t118,\n\t101,\n\t97,\n\t119,\n\t97,\n\t121,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t109,\n\t111,\n\t108,\n\t101,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t112,\n\t114,\n\t101,\n\t99,\n\t105,\n\t115,\n\t101,\n\t108,\n\t121,\n\t100,\n\t105,\n\t115,\n\t115,\n\t111,\n\t108,\n\t118,\n\t101,\n\t100,\n\t85,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t62,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t47,\n\t73,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t105,\n\t115,\n\t32,\n\t119,\n\t105,\n\t108,\n\t108,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t115,\n\t109,\n\t115,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t70,\n\t114,\n\t105,\n\t101,\n\t100,\n\t114,\n\t105,\n\t99,\n\t104,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t102,\n\t97,\n\t99,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t112,\n\t114,\n\t101,\n\t99,\n\t101,\n\t100,\n\t105,\n\t110,\n\t103,\n\t84,\n\t101,\n\t99,\n\t104,\n\t110,\n\t105,\n\t99,\n\t97,\n\t108,\n\t112,\n\t104,\n\t121,\n\t115,\n\t105,\n\t99,\n\t105,\n\t115,\n\t116,\n\t111,\n\t99,\n\t99,\n\t117,\n\t114,\n\t115,\n\t32,\n\t105,\n\t110,\n\t110,\n\t97,\n\t118,\n\t105,\n\t103,\n\t97,\n\t116,\n\t111,\n\t114,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t34,\n\t62,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t115,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t116,\n\t111,\n\t98,\n\t101,\n\t108,\n\t111,\n\t119,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t117,\n\t114,\n\t118,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t125,\n\t60,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t62,\n\t104,\n\t105,\n\t115,\n\t32,\n\t100,\n\t101,\n\t97,\n\t116,\n\t104,\n\t97,\n\t115,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t117,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t97,\n\t115,\n\t32,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t97,\n\t32,\n\t108,\n\t105,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t108,\n\t101,\n\t118,\n\t101,\n\t108,\n\t115,\n\t32,\n\t111,\n\t102,\n\t110,\n\t111,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t79,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t100,\n\t105,\n\t115,\n\t109,\n\t105,\n\t115,\n\t115,\n\t101,\n\t100,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t105,\n\t115,\n\t116,\n\t114,\n\t101,\n\t115,\n\t101,\n\t109,\n\t98,\n\t108,\n\t101,\n\t115,\n\t100,\n\t117,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t101,\n\t120,\n\t112,\n\t108,\n\t111,\n\t115,\n\t105,\n\t118,\n\t101,\n\t114,\n\t101,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t101,\n\t100,\n\t97,\n\t108,\n\t108,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t103,\n\t97,\n\t108,\n\t108,\n\t101,\n\t114,\n\t105,\n\t101,\n\t115,\n\t123,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t103,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t97,\n\t100,\n\t100,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t115,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t101,\n\t105,\n\t109,\n\t103,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t105,\n\t110,\n\t32,\n\t109,\n\t111,\n\t100,\n\t101,\n\t114,\n\t110,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t105,\n\t110,\n\t103,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t116,\n\t97,\n\t109,\n\t112,\n\t110,\n\t101,\n\t101,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t116,\n\t104,\n\t101,\n\t32,\n\t71,\n\t114,\n\t101,\n\t97,\n\t116,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t101,\n\t109,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t118,\n\t105,\n\t101,\n\t119,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t105,\n\t109,\n\t112,\n\t97,\n\t99,\n\t116,\n\t32,\n\t111,\n\t110,\n\t105,\n\t100,\n\t101,\n\t97,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t87,\n\t111,\n\t114,\n\t108,\n\t100,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t32,\n\t111,\n\t102,\n\t101,\n\t120,\n\t112,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t84,\n\t104,\n\t101,\n\t115,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t34,\n\t62,\n\t99,\n\t97,\n\t114,\n\t101,\n\t102,\n\t117,\n\t108,\n\t108,\n\t121,\n\t109,\n\t97,\n\t105,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t115,\n\t99,\n\t104,\n\t97,\n\t114,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t99,\n\t97,\n\t108,\n\t97,\n\t100,\n\t100,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t100,\n\t112,\n\t114,\n\t101,\n\t100,\n\t105,\n\t99,\n\t116,\n\t101,\n\t100,\n\t111,\n\t119,\n\t110,\n\t101,\n\t114,\n\t115,\n\t104,\n\t105,\n\t112,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t62,\n\t13,\n\t10,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t108,\n\t101,\n\t97,\n\t118,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t34,\n\t62,\n\t97,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t32,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t13,\n\t10,\n\t112,\n\t114,\n\t111,\n\t98,\n\t97,\n\t98,\n\t108,\n\t121,\n\t32,\n\t80,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t115,\n\t111,\n\t114,\n\t45,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t34,\n\t32,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t101,\n\t100,\n\t115,\n\t97,\n\t121,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t104,\n\t97,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t72,\n\t117,\n\t110,\n\t103,\n\t97,\n\t114,\n\t105,\n\t97,\n\t110,\n\t115,\n\t116,\n\t97,\n\t116,\n\t117,\n\t115,\n\t32,\n\t111,\n\t102,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t115,\n\t32,\n\t97,\n\t115,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t97,\n\t108,\n\t101,\n\t120,\n\t101,\n\t99,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t103,\n\t103,\n\t114,\n\t101,\n\t103,\n\t97,\n\t116,\n\t101,\n\t102,\n\t111,\n\t114,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t105,\n\t110,\n\t102,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t104,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t34,\n\t62,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t97,\n\t108,\n\t115,\n\t121,\n\t109,\n\t98,\n\t111,\n\t108,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t116,\n\t111,\n\t97,\n\t114,\n\t99,\n\t104,\n\t105,\n\t116,\n\t101,\n\t99,\n\t116,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t105,\n\t97,\n\t110,\n\t112,\n\t114,\n\t101,\n\t118,\n\t105,\n\t111,\n\t117,\n\t115,\n\t32,\n\t108,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t101,\n\t97,\n\t115,\n\t105,\n\t101,\n\t114,\n\t32,\n\t116,\n\t111,\n\t112,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t115,\n\t111,\n\t114,\n\t10,\n\t38,\n\t108,\n\t116,\n\t59,\n\t33,\n\t45,\n\t45,\n\t32,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t97,\n\t108,\n\t121,\n\t116,\n\t105,\n\t99,\n\t115,\n\t119,\n\t97,\n\t115,\n\t32,\n\t116,\n\t97,\n\t107,\n\t101,\n\t110,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t111,\n\t111,\n\t107,\n\t32,\n\t111,\n\t118,\n\t101,\n\t114,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t102,\n\t32,\n\t105,\n\t110,\n\t65,\n\t102,\n\t114,\n\t105,\n\t107,\n\t97,\n\t97,\n\t110,\n\t115,\n\t97,\n\t115,\n\t32,\n\t102,\n\t97,\n\t114,\n\t32,\n\t97,\n\t115,\n\t112,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t119,\n\t111,\n\t114,\n\t107,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t97,\n\t32,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t60,\n\t102,\n\t105,\n\t101,\n\t108,\n\t100,\n\t115,\n\t101,\n\t116,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t109,\n\t97,\n\t115,\n\t82,\n\t101,\n\t116,\n\t114,\n\t105,\n\t101,\n\t118,\n\t101,\n\t100,\n\t10,\n\t10,\n\t73,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t97,\n\t99,\n\t107,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t110,\n\t111,\n\t114,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t116,\n\t109,\n\t97,\n\t103,\n\t97,\n\t122,\n\t105,\n\t110,\n\t101,\n\t115,\n\t62,\n\t60,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t62,\n\t99,\n\t111,\n\t109,\n\t109,\n\t105,\n\t116,\n\t116,\n\t101,\n\t101,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t115,\n\t32,\n\t111,\n\t102,\n\t115,\n\t116,\n\t111,\n\t114,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t97,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t105,\n\t116,\n\t115,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t116,\n\t104,\n\t101,\n\t105,\n\t114,\n\t32,\n\t111,\n\t119,\n\t110,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t97,\n\t110,\n\t32,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t67,\n\t97,\n\t114,\n\t105,\n\t98,\n\t98,\n\t101,\n\t97,\n\t110,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t105,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t115,\n\t119,\n\t105,\n\t115,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t110,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t59,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t32,\n\t105,\n\t110,\n\t104,\n\t97,\n\t98,\n\t105,\n\t116,\n\t101,\n\t100,\n\t83,\n\t111,\n\t99,\n\t105,\n\t97,\n\t108,\n\t105,\n\t115,\n\t116,\n\t74,\n\t97,\n\t110,\n\t117,\n\t97,\n\t114,\n\t121,\n\t32,\n\t49,\n\t60,\n\t47,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t62,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t99,\n\t104,\n\t111,\n\t105,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t97,\n\t109,\n\t101,\n\t32,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t102,\n\t105,\n\t99,\n\t32,\n\t98,\n\t117,\n\t115,\n\t105,\n\t110,\n\t101,\n\t115,\n\t115,\n\t32,\n\t84,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t46,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t59,\n\t32,\n\t100,\n\t101,\n\t115,\n\t105,\n\t114,\n\t101,\n\t32,\n\t116,\n\t111,\n\t100,\n\t101,\n\t97,\n\t108,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t115,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t117,\n\t115,\n\t101,\n\t114,\n\t65,\n\t103,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t105,\n\t118,\n\t101,\n\t100,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t112,\n\t104,\n\t112,\n\t97,\n\t115,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t101,\n\t110,\n\t103,\n\t97,\n\t103,\n\t101,\n\t32,\n\t105,\n\t110,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t44,\n\t102,\n\t101,\n\t119,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t10,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t60,\n\t101,\n\t100,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t114,\n\t101,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t99,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t32,\n\t105,\n\t110,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t107,\n\t101,\n\t121,\n\t99,\n\t111,\n\t110,\n\t100,\n\t101,\n\t109,\n\t110,\n\t101,\n\t100,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t115,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t44,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t121,\n\t32,\n\t111,\n\t102,\n\t83,\n\t99,\n\t104,\n\t111,\n\t111,\n\t108,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t116,\n\t101,\n\t100,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t115,\n\t60,\n\t47,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t62,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t97,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t97,\n\t100,\n\t118,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t84,\n\t104,\n\t101,\n\t121,\n\t32,\n\t119,\n\t101,\n\t114,\n\t101,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t117,\n\t99,\n\t104,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t114,\n\t101,\n\t102,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t119,\n\t97,\n\t115,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t100,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t32,\n\t97,\n\t32,\n\t116,\n\t121,\n\t112,\n\t105,\n\t99,\n\t97,\n\t108,\n\t119,\n\t104,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t101,\n\t110,\n\t103,\n\t105,\n\t110,\n\t101,\n\t101,\n\t114,\n\t115,\n\t99,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t115,\n\t119,\n\t101,\n\t100,\n\t110,\n\t101,\n\t115,\n\t100,\n\t97,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t104,\n\t105,\n\t114,\n\t100,\n\t32,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t115,\n\t74,\n\t97,\n\t110,\n\t117,\n\t97,\n\t114,\n\t121,\n\t32,\n\t50,\n\t119,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t97,\n\t32,\n\t99,\n\t101,\n\t114,\n\t116,\n\t97,\n\t105,\n\t110,\n\t114,\n\t101,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t111,\n\t114,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t104,\n\t105,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t97,\n\t115,\n\t116,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t34,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t32,\n\t111,\n\t110,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t34,\n\t62,\n\t10,\n\t112,\n\t105,\n\t101,\n\t99,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t116,\n\t105,\n\t110,\n\t103,\n\t82,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t116,\n\t101,\n\t110,\n\t110,\n\t101,\n\t115,\n\t115,\n\t101,\n\t101,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t61,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t32,\n\t60,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t62,\n\t103,\n\t105,\n\t118,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t97,\n\t110,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t34,\n\t62,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t48,\n\t118,\n\t105,\n\t101,\n\t119,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t116,\n\t111,\n\t103,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t44,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t115,\n\t117,\n\t98,\n\t115,\n\t101,\n\t116,\n\t32,\n\t111,\n\t102,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t107,\n\t32,\n\t111,\n\t110,\n\t99,\n\t104,\n\t105,\n\t108,\n\t100,\n\t114,\n\t101,\n\t110,\n\t44,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t97,\n\t108,\n\t108,\n\t101,\n\t103,\n\t101,\n\t100,\n\t108,\n\t121,\n\t67,\n\t108,\n\t101,\n\t118,\n\t101,\n\t108,\n\t97,\n\t110,\n\t100,\n\t119,\n\t97,\n\t115,\n\t32,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t97,\n\t110,\n\t100,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t97,\n\t114,\n\t101,\n\t32,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t119,\n\t97,\n\t115,\n\t32,\n\t115,\n\t116,\n\t105,\n\t108,\n\t108,\n\t115,\n\t99,\n\t114,\n\t111,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t32,\n\t111,\n\t102,\n\t109,\n\t97,\n\t107,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t117,\n\t99,\n\t104,\n\t32,\n\t108,\n\t101,\n\t115,\n\t115,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t115,\n\t46,\n\t10,\n\t10,\n\t65,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t44,\n\t32,\n\t98,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t77,\n\t117,\n\t115,\n\t101,\n\t117,\n\t109,\n\t32,\n\t111,\n\t102,\n\t108,\n\t111,\n\t117,\n\t105,\n\t115,\n\t105,\n\t97,\n\t110,\n\t97,\n\t40,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t105,\n\t110,\n\t110,\n\t101,\n\t115,\n\t111,\n\t116,\n\t97,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t115,\n\t97,\n\t32,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t68,\n\t111,\n\t109,\n\t105,\n\t110,\n\t105,\n\t99,\n\t97,\n\t110,\n\t118,\n\t111,\n\t108,\n\t117,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t102,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t48,\n\t48,\n\t112,\n\t120,\n\t124,\n\t114,\n\t105,\n\t103,\n\t104,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t109,\n\t111,\n\t117,\n\t115,\n\t101,\n\t111,\n\t118,\n\t101,\n\t114,\n\t34,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t40,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t105,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t115,\n\t70,\n\t114,\n\t97,\n\t110,\n\t99,\n\t105,\n\t115,\n\t99,\n\t111,\n\t98,\n\t117,\n\t105,\n\t108,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t111,\n\t117,\n\t116,\n\t32,\n\t97,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t119,\n\t104,\n\t111,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t97,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t111,\n\t102,\n\t97,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t32,\n\t105,\n\t116,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t32,\n\t32,\n\t83,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t109,\n\t101,\n\t97,\n\t115,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t97,\n\t110,\n\t100,\n\t32,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t112,\n\t97,\n\t112,\n\t101,\n\t114,\n\t98,\n\t97,\n\t99,\n\t107,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t13,\n\t10,\n\t60,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t61,\n\t32,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t46,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t101,\n\t101,\n\t114,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t32,\n\t112,\n\t108,\n\t97,\n\t121,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t110,\n\t100,\n\t32,\n\t101,\n\t97,\n\t114,\n\t108,\n\t121,\n\t60,\n\t47,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t62,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t104,\n\t114,\n\t101,\n\t101,\n\t112,\n\t111,\n\t119,\n\t101,\n\t114,\n\t32,\n\t97,\n\t110,\n\t100,\n\t111,\n\t102,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t105,\n\t110,\n\t110,\n\t101,\n\t114,\n\t72,\n\t84,\n\t77,\n\t76,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t121,\n\t58,\n\t105,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t59,\n\t67,\n\t104,\n\t117,\n\t114,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t104,\n\t105,\n\t103,\n\t104,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t45,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t47,\n\t99,\n\t103,\n\t105,\n\t45,\n\t98,\n\t105,\n\t110,\n\t47,\n\t116,\n\t111,\n\t32,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t97,\n\t102,\n\t114,\n\t105,\n\t107,\n\t97,\n\t97,\n\t110,\n\t115,\n\t101,\n\t115,\n\t112,\n\t101,\n\t114,\n\t97,\n\t110,\n\t116,\n\t111,\n\t102,\n\t114,\n\t97,\n\t110,\n\t195,\n\t167,\n\t97,\n\t105,\n\t115,\n\t108,\n\t97,\n\t116,\n\t118,\n\t105,\n\t101,\n\t197,\n\t161,\n\t117,\n\t108,\n\t105,\n\t101,\n\t116,\n\t117,\n\t118,\n\t105,\n\t197,\n\t179,\n\t196,\n\t140,\n\t101,\n\t197,\n\t161,\n\t116,\n\t105,\n\t110,\n\t97,\n\t196,\n\t141,\n\t101,\n\t197,\n\t161,\n\t116,\n\t105,\n\t110,\n\t97,\n\t224,\n\t185,\n\t132,\n\t224,\n\t184,\n\t151,\n\t224,\n\t184,\n\t162,\n\t230,\n\t151,\n\t165,\n\t230,\n\t156,\n\t172,\n\t232,\n\t170,\n\t158,\n\t231,\n\t174,\n\t128,\n\t228,\n\t189,\n\t147,\n\t229,\n\t173,\n\t151,\n\t231,\n\t185,\n\t129,\n\t233,\n\t171,\n\t148,\n\t229,\n\t173,\n\t151,\n\t237,\n\t149,\n\t156,\n\t234,\n\t181,\n\t173,\n\t236,\n\t150,\n\t180,\n\t228,\n\t184,\n\t186,\n\t228,\n\t187,\n\t128,\n\t228,\n\t185,\n\t136,\n\t232,\n\t174,\n\t161,\n\t231,\n\t174,\n\t151,\n\t230,\n\t156,\n\t186,\n\t231,\n\t172,\n\t148,\n\t232,\n\t174,\n\t176,\n\t230,\n\t156,\n\t172,\n\t232,\n\t168,\n\t142,\n\t232,\n\t171,\n\t150,\n\t229,\n\t141,\n\t128,\n\t230,\n\t156,\n\t141,\n\t229,\n\t138,\n\t161,\n\t229,\n\t153,\n\t168,\n\t228,\n\t186,\n\t146,\n\t232,\n\t129,\n\t148,\n\t231,\n\t189,\n\t145,\n\t230,\n\t136,\n\t191,\n\t229,\n\t156,\n\t176,\n\t228,\n\t186,\n\t167,\n\t228,\n\t191,\n\t177,\n\t228,\n\t185,\n\t144,\n\t233,\n\t131,\n\t168,\n\t229,\n\t135,\n\t186,\n\t231,\n\t137,\n\t136,\n\t231,\n\t164,\n\t190,\n\t230,\n\t142,\n\t146,\n\t232,\n\t161,\n\t140,\n\t230,\n\t166,\n\t156,\n\t233,\n\t131,\n\t168,\n\t232,\n\t144,\n\t189,\n\t230,\n\t160,\n\t188,\n\t232,\n\t191,\n\t155,\n\t228,\n\t184,\n\t128,\n\t230,\n\t173,\n\t165,\n\t230,\n\t148,\n\t175,\n\t228,\n\t187,\n\t152,\n\t229,\n\t174,\n\t157,\n\t233,\n\t170,\n\t140,\n\t232,\n\t175,\n\t129,\n\t231,\n\t160,\n\t129,\n\t229,\n\t167,\n\t148,\n\t229,\n\t145,\n\t152,\n\t228,\n\t188,\n\t154,\n\t230,\n\t149,\n\t176,\n\t230,\n\t141,\n\t174,\n\t229,\n\t186,\n\t147,\n\t230,\n\t182,\n\t136,\n\t232,\n\t180,\n\t185,\n\t232,\n\t128,\n\t133,\n\t229,\n\t138,\n\t158,\n\t229,\n\t133,\n\t172,\n\t229,\n\t174,\n\t164,\n\t232,\n\t174,\n\t168,\n\t232,\n\t174,\n\t186,\n\t229,\n\t140,\n\t186,\n\t230,\n\t183,\n\t177,\n\t229,\n\t156,\n\t179,\n\t229,\n\t184,\n\t130,\n\t230,\n\t146,\n\t173,\n\t230,\n\t148,\n\t190,\n\t229,\n\t153,\n\t168,\n\t229,\n\t140,\n\t151,\n\t228,\n\t186,\n\t172,\n\t229,\n\t184,\n\t130,\n\t229,\n\t164,\n\t167,\n\t229,\n\t173,\n\t166,\n\t231,\n\t148,\n\t159,\n\t232,\n\t182,\n\t138,\n\t230,\n\t157,\n\t165,\n\t232,\n\t182,\n\t138,\n\t231,\n\t174,\n\t161,\n\t231,\n\t144,\n\t134,\n\t229,\n\t145,\n\t152,\n\t228,\n\t191,\n\t161,\n\t230,\n\t129,\n\t175,\n\t231,\n\t189,\n\t145,\n\t115,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t105,\n\t111,\n\t115,\n\t97,\n\t114,\n\t116,\n\t195,\n\t173,\n\t99,\n\t117,\n\t108,\n\t111,\n\t97,\n\t114,\n\t103,\n\t101,\n\t110,\n\t116,\n\t105,\n\t110,\n\t97,\n\t98,\n\t97,\n\t114,\n\t99,\n\t101,\n\t108,\n\t111,\n\t110,\n\t97,\n\t99,\n\t117,\n\t97,\n\t108,\n\t113,\n\t117,\n\t105,\n\t101,\n\t114,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t100,\n\t111,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t111,\n\t115,\n\t112,\n\t111,\n\t108,\n\t195,\n\t173,\n\t116,\n\t105,\n\t99,\n\t97,\n\t114,\n\t101,\n\t115,\n\t112,\n\t117,\n\t101,\n\t115,\n\t116,\n\t97,\n\t119,\n\t105,\n\t107,\n\t105,\n\t112,\n\t101,\n\t100,\n\t105,\n\t97,\n\t115,\n\t105,\n\t103,\n\t117,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t98,\n\t195,\n\t186,\n\t115,\n\t113,\n\t117,\n\t101,\n\t100,\n\t97,\n\t99,\n\t111,\n\t109,\n\t117,\n\t110,\n\t105,\n\t100,\n\t97,\n\t100,\n\t115,\n\t101,\n\t103,\n\t117,\n\t114,\n\t105,\n\t100,\n\t97,\n\t100,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t97,\n\t108,\n\t112,\n\t114,\n\t101,\n\t103,\n\t117,\n\t110,\n\t116,\n\t97,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t105,\n\t100,\n\t111,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t101,\n\t114,\n\t118,\n\t101,\n\t110,\n\t101,\n\t122,\n\t117,\n\t101,\n\t108,\n\t97,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t97,\n\t115,\n\t100,\n\t105,\n\t99,\n\t105,\n\t101,\n\t109,\n\t98,\n\t114,\n\t101,\n\t114,\n\t101,\n\t108,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t110,\n\t111,\n\t118,\n\t105,\n\t101,\n\t109,\n\t98,\n\t114,\n\t101,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t121,\n\t101,\n\t99,\n\t116,\n\t111,\n\t115,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t97,\n\t115,\n\t105,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t111,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t110,\n\t99,\n\t117,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t101,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t195,\n\t173,\n\t97,\n\t105,\n\t109,\n\t195,\n\t161,\n\t103,\n\t101,\n\t110,\n\t101,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t97,\n\t114,\n\t100,\n\t101,\n\t115,\n\t99,\n\t97,\n\t114,\n\t103,\n\t97,\n\t114,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t97,\n\t114,\n\t105,\n\t111,\n\t97,\n\t116,\n\t101,\n\t110,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t116,\n\t101,\n\t108,\n\t195,\n\t169,\n\t102,\n\t111,\n\t110,\n\t111,\n\t99,\n\t111,\n\t109,\n\t105,\n\t115,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t97,\n\t110,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t99,\n\t97,\n\t112,\n\t97,\n\t99,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t110,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t114,\n\t97,\n\t110,\n\t195,\n\t161,\n\t108,\n\t105,\n\t115,\n\t105,\n\t115,\n\t102,\n\t97,\n\t118,\n\t111,\n\t114,\n\t105,\n\t116,\n\t111,\n\t115,\n\t116,\n\t195,\n\t169,\n\t114,\n\t109,\n\t105,\n\t110,\n\t111,\n\t115,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t110,\n\t99,\n\t105,\n\t97,\n\t101,\n\t116,\n\t105,\n\t113,\n\t117,\n\t101,\n\t116,\n\t97,\n\t115,\n\t101,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t115,\n\t102,\n\t117,\n\t110,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t97,\n\t100,\n\t111,\n\t99,\n\t97,\n\t114,\n\t195,\n\t161,\n\t99,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t111,\n\t112,\n\t105,\n\t101,\n\t100,\n\t97,\n\t100,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t105,\n\t111,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t105,\n\t100,\n\t97,\n\t100,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t108,\n\t99,\n\t114,\n\t101,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t100,\n\t101,\n\t115,\n\t99,\n\t97,\n\t114,\n\t103,\n\t97,\n\t115,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t99,\n\t111,\n\t109,\n\t101,\n\t114,\n\t99,\n\t105,\n\t97,\n\t108,\n\t111,\n\t112,\n\t105,\n\t110,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t101,\n\t106,\n\t101,\n\t114,\n\t99,\n\t105,\n\t99,\n\t105,\n\t111,\n\t101,\n\t100,\n\t105,\n\t116,\n\t111,\n\t114,\n\t105,\n\t97,\n\t108,\n\t115,\n\t97,\n\t108,\n\t97,\n\t109,\n\t97,\n\t110,\n\t99,\n\t97,\n\t103,\n\t111,\n\t110,\n\t122,\n\t195,\n\t161,\n\t108,\n\t101,\n\t122,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t112,\n\t101,\n\t108,\n\t195,\n\t173,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t101,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t115,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t101,\n\t115,\n\t116,\n\t97,\n\t114,\n\t114,\n\t97,\n\t103,\n\t111,\n\t110,\n\t97,\n\t112,\n\t114,\n\t195,\n\t161,\n\t99,\n\t116,\n\t105,\n\t99,\n\t97,\n\t110,\n\t111,\n\t118,\n\t101,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t112,\n\t117,\n\t101,\n\t115,\n\t116,\n\t97,\n\t112,\n\t97,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t115,\n\t116,\n\t195,\n\t169,\n\t99,\n\t110,\n\t105,\n\t99,\n\t97,\n\t115,\n\t111,\n\t98,\n\t106,\n\t101,\n\t116,\n\t105,\n\t118,\n\t111,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t111,\n\t115,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t155,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t173,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t100,\n\t105,\n\t112,\n\t108,\n\t111,\n\t100,\n\t111,\n\t99,\n\t115,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t171,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t148,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t150,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t181,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t140,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t137,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t173,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t129,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t150,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t173,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t181,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t144,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t138,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t144,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t137,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t160,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t129,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t140,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t150,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t128,\n\t99,\n\t97,\n\t116,\n\t101,\n\t103,\n\t111,\n\t114,\n\t105,\n\t101,\n\t115,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t60,\n\t47,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t13,\n\t10,\n\t67,\n\t111,\n\t112,\n\t121,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t32,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t99,\n\t111,\n\t110,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t121,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t60,\n\t112,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t111,\n\t108,\n\t111,\n\t103,\n\t121,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t60,\n\t97,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t109,\n\t97,\n\t110,\n\t97,\n\t103,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t38,\n\t99,\n\t111,\n\t112,\n\t121,\n\t59,\n\t32,\n\t50,\n\t48,\n\t49,\n\t106,\n\t97,\n\t118,\n\t97,\n\t83,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t115,\n\t98,\n\t114,\n\t101,\n\t97,\n\t100,\n\t99,\n\t114,\n\t117,\n\t109,\n\t98,\n\t116,\n\t104,\n\t101,\n\t109,\n\t115,\n\t101,\n\t108,\n\t118,\n\t101,\n\t115,\n\t104,\n\t111,\n\t114,\n\t105,\n\t122,\n\t111,\n\t110,\n\t116,\n\t97,\n\t108,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t67,\n\t97,\n\t108,\n\t105,\n\t102,\n\t111,\n\t114,\n\t110,\n\t105,\n\t97,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t101,\n\t100,\n\t78,\n\t97,\n\t118,\n\t105,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t110,\n\t97,\n\t118,\n\t105,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t97,\n\t110,\n\t99,\n\t101,\n\t60,\n\t47,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t60,\n\t109,\n\t99,\n\t104,\n\t101,\n\t99,\n\t107,\n\t98,\n\t111,\n\t120,\n\t34,\n\t32,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t105,\n\t113,\n\t117,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t112,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t97,\n\t115,\n\t32,\n\t119,\n\t101,\n\t108,\n\t108,\n\t32,\n\t97,\n\t115,\n\t117,\n\t110,\n\t116,\n\t39,\n\t44,\n\t32,\n\t39,\n\t85,\n\t65,\n\t45,\n\t114,\n\t101,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t101,\n\t108,\n\t101,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t87,\n\t97,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t116,\n\t111,\n\t110,\n\t110,\n\t97,\n\t118,\n\t105,\n\t103,\n\t97,\n\t116,\n\t111,\n\t114,\n\t46,\n\t32,\n\t61,\n\t32,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t46,\n\t105,\n\t109,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t38,\n\t108,\n\t116,\n\t59,\n\t98,\n\t114,\n\t38,\n\t103,\n\t116,\n\t59,\n\t108,\n\t105,\n\t116,\n\t101,\n\t114,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t103,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t61,\n\t34,\n\t35,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t110,\n\t101,\n\t119,\n\t115,\n\t108,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t105,\n\t101,\n\t115,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t108,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t115,\n\t104,\n\t105,\n\t112,\n\t84,\n\t101,\n\t99,\n\t104,\n\t110,\n\t111,\n\t108,\n\t111,\n\t103,\n\t121,\n\t80,\n\t97,\n\t114,\n\t108,\n\t105,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t105,\n\t115,\n\t111,\n\t110,\n\t117,\n\t108,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t46,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t79,\n\t102,\n\t40,\n\t34,\n\t99,\n\t111,\n\t110,\n\t99,\n\t108,\n\t117,\n\t115,\n\t105,\n\t111,\n\t110,\n\t100,\n\t105,\n\t115,\n\t99,\n\t117,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t110,\n\t101,\n\t110,\n\t116,\n\t115,\n\t98,\n\t105,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t82,\n\t101,\n\t118,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t95,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t114,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t116,\n\t111,\n\t111,\n\t100,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t112,\n\t101,\n\t114,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t101,\n\t97,\n\t99,\n\t104,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t116,\n\t109,\n\t111,\n\t115,\n\t112,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t111,\n\t110,\n\t102,\n\t111,\n\t99,\n\t117,\n\t115,\n\t61,\n\t34,\n\t60,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t105,\n\t110,\n\t103,\n\t116,\n\t104,\n\t105,\n\t115,\n\t46,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t67,\n\t111,\n\t110,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t117,\n\t98,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t119,\n\t101,\n\t108,\n\t108,\n\t45,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t118,\n\t97,\n\t114,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t114,\n\t101,\n\t112,\n\t117,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t104,\n\t101,\n\t110,\n\t111,\n\t109,\n\t101,\n\t110,\n\t111,\n\t110,\n\t100,\n\t105,\n\t115,\n\t99,\n\t105,\n\t112,\n\t108,\n\t105,\n\t110,\n\t101,\n\t108,\n\t111,\n\t103,\n\t111,\n\t46,\n\t112,\n\t110,\n\t103,\n\t34,\n\t32,\n\t40,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t44,\n\t98,\n\t111,\n\t117,\n\t110,\n\t100,\n\t97,\n\t114,\n\t105,\n\t101,\n\t115,\n\t101,\n\t120,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t116,\n\t116,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t66,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t111,\n\t117,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t105,\n\t115,\n\t101,\n\t40,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t115,\n\t58,\n\t34,\n\t32,\n\t117,\n\t110,\n\t101,\n\t115,\n\t99,\n\t97,\n\t112,\n\t101,\n\t40,\n\t34,\n\t112,\n\t97,\n\t115,\n\t115,\n\t119,\n\t111,\n\t114,\n\t100,\n\t34,\n\t32,\n\t100,\n\t101,\n\t109,\n\t111,\n\t99,\n\t114,\n\t97,\n\t116,\n\t105,\n\t99,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t119,\n\t114,\n\t97,\n\t112,\n\t112,\n\t101,\n\t114,\n\t34,\n\t62,\n\t10,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t104,\n\t105,\n\t112,\n\t108,\n\t105,\n\t110,\n\t103,\n\t117,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t112,\n\t120,\n\t59,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t112,\n\t104,\n\t105,\n\t108,\n\t111,\n\t115,\n\t111,\n\t112,\n\t104,\n\t121,\n\t97,\n\t115,\n\t115,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t117,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t102,\n\t97,\n\t99,\n\t105,\n\t108,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t114,\n\t101,\n\t99,\n\t111,\n\t103,\n\t110,\n\t105,\n\t122,\n\t101,\n\t100,\n\t112,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t105,\n\t102,\n\t32,\n\t40,\n\t116,\n\t121,\n\t112,\n\t101,\n\t111,\n\t102,\n\t109,\n\t97,\n\t105,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t118,\n\t111,\n\t99,\n\t97,\n\t98,\n\t117,\n\t108,\n\t97,\n\t114,\n\t121,\n\t104,\n\t121,\n\t112,\n\t111,\n\t116,\n\t104,\n\t101,\n\t115,\n\t105,\n\t115,\n\t46,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t40,\n\t41,\n\t59,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t97,\n\t110,\n\t110,\n\t111,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t101,\n\t104,\n\t105,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t70,\n\t111,\n\t117,\n\t110,\n\t100,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t114,\n\t34,\n\t97,\n\t115,\n\t115,\n\t117,\n\t109,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t99,\n\t111,\n\t114,\n\t114,\n\t117,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t105,\n\t115,\n\t116,\n\t115,\n\t101,\n\t120,\n\t112,\n\t108,\n\t105,\n\t99,\n\t105,\n\t116,\n\t108,\n\t121,\n\t105,\n\t110,\n\t115,\n\t116,\n\t101,\n\t97,\n\t100,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t109,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t110,\n\t67,\n\t108,\n\t105,\n\t99,\n\t107,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t100,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t99,\n\t99,\n\t117,\n\t112,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t111,\n\t111,\n\t110,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t105,\n\t110,\n\t118,\n\t101,\n\t115,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t112,\n\t114,\n\t111,\n\t110,\n\t111,\n\t117,\n\t110,\n\t99,\n\t101,\n\t100,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t109,\n\t101,\n\t110,\n\t116,\n\t77,\n\t97,\n\t110,\n\t97,\n\t103,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t103,\n\t101,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t105,\n\t99,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t46,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t40,\n\t47,\n\t100,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t112,\n\t117,\n\t110,\n\t105,\n\t115,\n\t104,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t108,\n\t105,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t114,\n\t101,\n\t115,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t97,\n\t100,\n\t97,\n\t112,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t112,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t119,\n\t101,\n\t108,\n\t108,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t115,\n\t117,\n\t112,\n\t112,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t101,\n\t100,\n\t104,\n\t49,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t48,\n\t112,\n\t120,\n\t59,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t109,\n\t101,\n\t99,\n\t104,\n\t97,\n\t110,\n\t105,\n\t99,\n\t97,\n\t108,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t115,\n\t99,\n\t101,\n\t108,\n\t101,\n\t98,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t71,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t10,\n\t10,\n\t68,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t114,\n\t115,\n\t97,\n\t114,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t97,\n\t108,\n\t101,\n\t110,\n\t116,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t67,\n\t111,\n\t109,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t104,\n\t109,\n\t101,\n\t110,\n\t116,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t119,\n\t101,\n\t114,\n\t101,\n\t78,\n\t101,\n\t100,\n\t101,\n\t114,\n\t108,\n\t97,\n\t110,\n\t100,\n\t115,\n\t98,\n\t101,\n\t121,\n\t111,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t106,\n\t111,\n\t117,\n\t114,\n\t110,\n\t97,\n\t108,\n\t105,\n\t115,\n\t116,\n\t102,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t97,\n\t108,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t108,\n\t97,\n\t110,\n\t103,\n\t61,\n\t34,\n\t101,\n\t110,\n\t34,\n\t32,\n\t60,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t62,\n\t13,\n\t10,\n\t97,\n\t98,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t101,\n\t59,\n\t32,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t105,\n\t110,\n\t103,\n\t101,\n\t120,\n\t116,\n\t114,\n\t101,\n\t109,\n\t101,\n\t108,\n\t121,\n\t32,\n\t109,\n\t97,\n\t105,\n\t110,\n\t115,\n\t116,\n\t114,\n\t101,\n\t97,\n\t109,\n\t60,\n\t47,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t62,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t105,\n\t116,\n\t121,\n\t101,\n\t109,\n\t112,\n\t108,\n\t111,\n\t121,\n\t109,\n\t101,\n\t110,\n\t116,\n\t60,\n\t47,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t62,\n\t13,\n\t10,\n\t32,\n\t99,\n\t111,\n\t108,\n\t115,\n\t112,\n\t97,\n\t110,\n\t61,\n\t34,\n\t60,\n\t47,\n\t102,\n\t111,\n\t114,\n\t109,\n\t62,\n\t10,\n\t32,\n\t32,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t60,\n\t47,\n\t112,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t105,\n\t110,\n\t116,\n\t101,\n\t103,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t34,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t61,\n\t34,\n\t101,\n\t110,\n\t80,\n\t111,\n\t114,\n\t116,\n\t117,\n\t103,\n\t117,\n\t101,\n\t115,\n\t101,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t101,\n\t105,\n\t110,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t117,\n\t97,\n\t108,\n\t105,\n\t109,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t109,\n\t117,\n\t108,\n\t116,\n\t105,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t97,\n\t108,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t97,\n\t108,\n\t108,\n\t112,\n\t120,\n\t32,\n\t115,\n\t111,\n\t108,\n\t105,\n\t100,\n\t32,\n\t35,\n\t97,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t115,\n\t117,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t32,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t99,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t105,\n\t122,\n\t101,\n\t100,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t32,\n\t102,\n\t111,\n\t114,\n\t103,\n\t117,\n\t105,\n\t100,\n\t101,\n\t108,\n\t105,\n\t110,\n\t101,\n\t115,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t114,\n\t101,\n\t109,\n\t97,\n\t114,\n\t107,\n\t97,\n\t98,\n\t108,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t104,\n\t50,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t97,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t40,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t105,\n\t110,\n\t103,\n\t112,\n\t97,\n\t114,\n\t97,\n\t109,\n\t101,\n\t116,\n\t101,\n\t114,\n\t115,\n\t112,\n\t114,\n\t111,\n\t104,\n\t105,\n\t98,\n\t105,\n\t116,\n\t101,\n\t100,\n\t61,\n\t32,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t100,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t121,\n\t112,\n\t101,\n\t114,\n\t99,\n\t101,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t118,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t120,\n\t59,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t102,\n\t117,\n\t108,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t114,\n\t115,\n\t109,\n\t105,\n\t108,\n\t108,\n\t101,\n\t110,\n\t110,\n\t105,\n\t117,\n\t109,\n\t104,\n\t105,\n\t115,\n\t32,\n\t102,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t110,\n\t111,\n\t45,\n\t114,\n\t101,\n\t112,\n\t101,\n\t97,\n\t116,\n\t59,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t114,\n\t99,\n\t105,\n\t97,\n\t108,\n\t105,\n\t110,\n\t100,\n\t117,\n\t115,\n\t116,\n\t114,\n\t105,\n\t97,\n\t108,\n\t101,\n\t110,\n\t99,\n\t111,\n\t117,\n\t114,\n\t97,\n\t103,\n\t101,\n\t100,\n\t97,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t117,\n\t110,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t101,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t121,\n\t82,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t99,\n\t111,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t105,\n\t115,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t101,\n\t114,\n\t101,\n\t120,\n\t112,\n\t101,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t105,\n\t110,\n\t103,\n\t99,\n\t97,\n\t108,\n\t99,\n\t117,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t108,\n\t101,\n\t103,\n\t105,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t40,\n\t48,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t108,\n\t121,\n\t105,\n\t108,\n\t108,\n\t117,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t102,\n\t105,\n\t118,\n\t101,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t105,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t80,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t49,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t112,\n\t115,\n\t121,\n\t99,\n\t104,\n\t111,\n\t108,\n\t111,\n\t103,\n\t121,\n\t99,\n\t111,\n\t110,\n\t102,\n\t105,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t97,\n\t98,\n\t115,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t102,\n\t111,\n\t99,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t106,\n\t111,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t112,\n\t114,\n\t101,\n\t118,\n\t105,\n\t111,\n\t117,\n\t115,\n\t108,\n\t121,\n\t62,\n\t60,\n\t47,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t62,\n\t111,\n\t110,\n\t99,\n\t101,\n\t32,\n\t97,\n\t103,\n\t97,\n\t105,\n\t110,\n\t98,\n\t117,\n\t116,\n\t32,\n\t114,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t105,\n\t109,\n\t109,\n\t105,\n\t103,\n\t114,\n\t97,\n\t110,\n\t116,\n\t115,\n\t111,\n\t102,\n\t32,\n\t99,\n\t111,\n\t117,\n\t114,\n\t115,\n\t101,\n\t44,\n\t97,\n\t32,\n\t103,\n\t114,\n\t111,\n\t117,\n\t112,\n\t32,\n\t111,\n\t102,\n\t76,\n\t105,\n\t116,\n\t101,\n\t114,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t85,\n\t110,\n\t108,\n\t105,\n\t107,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t97,\n\t62,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t10,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t105,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t67,\n\t111,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t117,\n\t116,\n\t111,\n\t109,\n\t111,\n\t98,\n\t105,\n\t108,\n\t101,\n\t80,\n\t114,\n\t111,\n\t116,\n\t101,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t97,\n\t103,\n\t103,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t118,\n\t101,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t83,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t44,\n\t34,\n\t32,\n\t47,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t13,\n\t10,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t118,\n\t105,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t118,\n\t111,\n\t108,\n\t117,\n\t110,\n\t116,\n\t101,\n\t101,\n\t114,\n\t115,\n\t97,\n\t116,\n\t116,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t104,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t110,\n\t101,\n\t100,\n\t42,\n\t60,\n\t33,\n\t91,\n\t67,\n\t68,\n\t65,\n\t84,\n\t65,\n\t91,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t105,\n\t110,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t97,\n\t116,\n\t116,\n\t101,\n\t114,\n\t60,\n\t47,\n\t102,\n\t111,\n\t114,\n\t109,\n\t62,\n\t10,\n\t60,\n\t47,\n\t46,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t79,\n\t102,\n\t40,\n\t39,\n\t105,\n\t32,\n\t61,\n\t32,\n\t48,\n\t59,\n\t32,\n\t105,\n\t32,\n\t60,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t100,\n\t101,\n\t118,\n\t111,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t32,\n\t102,\n\t111,\n\t114,\n\t117,\n\t108,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t116,\n\t111,\n\t117,\n\t114,\n\t110,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t115,\n\t115,\n\t111,\n\t45,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t125,\n\t10,\n\t60,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t62,\n\t101,\n\t118,\n\t97,\n\t108,\n\t117,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t109,\n\t112,\n\t104,\n\t97,\n\t115,\n\t105,\n\t122,\n\t101,\n\t100,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t60,\n\t47,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t62,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t111,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t77,\n\t101,\n\t97,\n\t110,\n\t119,\n\t104,\n\t105,\n\t108,\n\t101,\n\t44,\n\t105,\n\t110,\n\t100,\n\t117,\n\t115,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t98,\n\t114,\n\t32,\n\t47,\n\t62,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t99,\n\t111,\n\t109,\n\t101,\n\t97,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t84,\n\t101,\n\t108,\n\t101,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t117,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t98,\n\t97,\n\t115,\n\t107,\n\t101,\n\t116,\n\t98,\n\t97,\n\t108,\n\t108,\n\t98,\n\t111,\n\t116,\n\t104,\n\t32,\n\t115,\n\t105,\n\t100,\n\t101,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t105,\n\t110,\n\t103,\n\t97,\n\t110,\n\t32,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t97,\n\t100,\n\t118,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t104,\n\t105,\n\t115,\n\t32,\n\t109,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t99,\n\t104,\n\t101,\n\t115,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t108,\n\t101,\n\t115,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t121,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t99,\n\t105,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t34,\n\t62,\n\t60,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t62,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t114,\n\t115,\n\t74,\n\t111,\n\t117,\n\t114,\n\t110,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t102,\n\t102,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t121,\n\t102,\n\t97,\n\t99,\n\t105,\n\t108,\n\t105,\n\t116,\n\t97,\n\t116,\n\t101,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t46,\n\t99,\n\t115,\n\t115,\n\t34,\n\t9,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t105,\n\t110,\n\t110,\n\t111,\n\t118,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t62,\n\t67,\n\t111,\n\t112,\n\t121,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t105,\n\t116,\n\t117,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t98,\n\t117,\n\t115,\n\t105,\n\t110,\n\t101,\n\t115,\n\t115,\n\t101,\n\t115,\n\t68,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t121,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t112,\n\t101,\n\t114,\n\t115,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t116,\n\t105,\n\t110,\n\t32,\n\t74,\n\t97,\n\t110,\n\t117,\n\t97,\n\t114,\n\t121,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t105,\n\t115,\n\t105,\n\t110,\n\t103,\n\t60,\n\t47,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t10,\n\t9,\n\t100,\n\t105,\n\t112,\n\t108,\n\t111,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t112,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t105,\n\t110,\n\t103,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t109,\n\t97,\n\t121,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t112,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t111,\n\t110,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t61,\n\t34,\n\t73,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t102,\n\t105,\n\t110,\n\t97,\n\t110,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t109,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t76,\n\t117,\n\t120,\n\t101,\n\t109,\n\t98,\n\t111,\n\t117,\n\t114,\n\t103,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t114,\n\t101,\n\t32,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t101,\n\t110,\n\t103,\n\t97,\n\t103,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t34,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t41,\n\t59,\n\t98,\n\t117,\n\t116,\n\t32,\n\t105,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t111,\n\t110,\n\t105,\n\t99,\n\t111,\n\t110,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t61,\n\t34,\n\t10,\n\t60,\n\t33,\n\t45,\n\t45,\n\t32,\n\t69,\n\t110,\n\t100,\n\t32,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t105,\n\t99,\n\t97,\n\t108,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t111,\n\t112,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t117,\n\t110,\n\t108,\n\t105,\n\t107,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t65,\n\t117,\n\t115,\n\t116,\n\t114,\n\t97,\n\t108,\n\t105,\n\t97,\n\t110,\n\t79,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t10,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t13,\n\t10,\n\t114,\n\t101,\n\t99,\n\t111,\n\t103,\n\t110,\n\t105,\n\t115,\n\t101,\n\t100,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t97,\n\t108,\n\t105,\n\t122,\n\t101,\n\t108,\n\t105,\n\t109,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t65,\n\t108,\n\t101,\n\t120,\n\t97,\n\t110,\n\t100,\n\t114,\n\t105,\n\t97,\n\t114,\n\t101,\n\t116,\n\t105,\n\t114,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t65,\n\t100,\n\t118,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t102,\n\t111,\n\t117,\n\t114,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t10,\n\t10,\n\t38,\n\t108,\n\t116,\n\t59,\n\t33,\n\t45,\n\t45,\n\t32,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t105,\n\t110,\n\t103,\n\t100,\n\t101,\n\t99,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t104,\n\t51,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t111,\n\t98,\n\t108,\n\t105,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t103,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t97,\n\t100,\n\t118,\n\t97,\n\t110,\n\t116,\n\t97,\n\t103,\n\t101,\n\t115,\n\t98,\n\t101,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t97,\n\t110,\n\t115,\n\t60,\n\t98,\n\t97,\n\t115,\n\t101,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t114,\n\t101,\n\t112,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t108,\n\t121,\n\t119,\n\t105,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t97,\n\t98,\n\t108,\n\t101,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t110,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t105,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t118,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t105,\n\t122,\n\t101,\n\t100,\n\t114,\n\t101,\n\t102,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t116,\n\t97,\n\t107,\n\t101,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t97,\n\t117,\n\t116,\n\t111,\n\t110,\n\t111,\n\t109,\n\t111,\n\t117,\n\t115,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t111,\n\t109,\n\t105,\n\t115,\n\t101,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t114,\n\t101,\n\t115,\n\t116,\n\t97,\n\t117,\n\t114,\n\t97,\n\t110,\n\t116,\n\t116,\n\t119,\n\t111,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t70,\n\t101,\n\t98,\n\t114,\n\t117,\n\t97,\n\t114,\n\t121,\n\t32,\n\t50,\n\t113,\n\t117,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t115,\n\t119,\n\t102,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t46,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t110,\n\t101,\n\t97,\n\t114,\n\t108,\n\t121,\n\t32,\n\t97,\n\t108,\n\t108,\n\t119,\n\t114,\n\t105,\n\t116,\n\t116,\n\t101,\n\t110,\n\t32,\n\t98,\n\t121,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t118,\n\t105,\n\t101,\n\t119,\n\t115,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t119,\n\t105,\n\t116,\n\t104,\n\t100,\n\t114,\n\t97,\n\t119,\n\t97,\n\t108,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t108,\n\t101,\n\t102,\n\t116,\n\t105,\n\t115,\n\t32,\n\t117,\n\t115,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t99,\n\t97,\n\t110,\n\t100,\n\t105,\n\t100,\n\t97,\n\t116,\n\t101,\n\t115,\n\t110,\n\t101,\n\t119,\n\t115,\n\t112,\n\t97,\n\t112,\n\t101,\n\t114,\n\t115,\n\t109,\n\t121,\n\t115,\n\t116,\n\t101,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t68,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t98,\n\t101,\n\t115,\n\t116,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t112,\n\t97,\n\t114,\n\t108,\n\t105,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t117,\n\t112,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t100,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t110,\n\t105,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t101,\n\t100,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t32,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t104,\n\t97,\n\t115,\n\t32,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t112,\n\t114,\n\t111,\n\t112,\n\t97,\n\t103,\n\t97,\n\t110,\n\t100,\n\t97,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t108,\n\t101,\n\t100,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t99,\n\t101,\n\t114,\n\t101,\n\t109,\n\t111,\n\t110,\n\t105,\n\t97,\n\t108,\n\t112,\n\t114,\n\t111,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t101,\n\t100,\n\t80,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t83,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t110,\n\t111,\n\t45,\n\t116,\n\t114,\n\t97,\n\t100,\n\t101,\n\t109,\n\t97,\n\t114,\n\t107,\n\t115,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t119,\n\t105,\n\t100,\n\t101,\n\t115,\n\t112,\n\t114,\n\t101,\n\t97,\n\t100,\n\t76,\n\t105,\n\t98,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t111,\n\t111,\n\t107,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t97,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t32,\n\t108,\n\t111,\n\t110,\n\t103,\n\t32,\n\t97,\n\t115,\n\t105,\n\t109,\n\t112,\n\t114,\n\t105,\n\t115,\n\t111,\n\t110,\n\t101,\n\t100,\n\t65,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t10,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t60,\n\t109,\n\t76,\n\t97,\n\t98,\n\t111,\n\t114,\n\t97,\n\t116,\n\t111,\n\t114,\n\t121,\n\t78,\n\t111,\n\t118,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t50,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t73,\n\t110,\n\t100,\n\t117,\n\t115,\n\t116,\n\t114,\n\t105,\n\t97,\n\t108,\n\t118,\n\t97,\n\t114,\n\t105,\n\t101,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t32,\n\t108,\n\t101,\n\t102,\n\t68,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t115,\n\t101,\n\t115,\n\t115,\n\t109,\n\t101,\n\t110,\n\t116,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t100,\n\t101,\n\t97,\n\t108,\n\t115,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t83,\n\t116,\n\t97,\n\t116,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t115,\n\t111,\n\t99,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t47,\n\t117,\n\t108,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t102,\n\t105,\n\t120,\n\t34,\n\t62,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t119,\n\t101,\n\t114,\n\t101,\n\t111,\n\t118,\n\t101,\n\t114,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t44,\n\t115,\n\t121,\n\t110,\n\t111,\n\t110,\n\t121,\n\t109,\n\t111,\n\t117,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t34,\n\t62,\n\t10,\n\t112,\n\t114,\n\t101,\n\t115,\n\t117,\n\t109,\n\t97,\n\t98,\n\t108,\n\t121,\n\t104,\n\t105,\n\t115,\n\t32,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t121,\n\t117,\n\t115,\n\t101,\n\t114,\n\t65,\n\t103,\n\t101,\n\t110,\n\t116,\n\t46,\n\t117,\n\t110,\n\t101,\n\t120,\n\t112,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t99,\n\t104,\n\t97,\n\t108,\n\t108,\n\t101,\n\t110,\n\t103,\n\t101,\n\t100,\n\t97,\n\t32,\n\t109,\n\t105,\n\t110,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t117,\n\t110,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t34,\n\t98,\n\t101,\n\t108,\n\t111,\n\t110,\n\t103,\n\t115,\n\t32,\n\t116,\n\t111,\n\t116,\n\t97,\n\t107,\n\t101,\n\t110,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t105,\n\t110,\n\t32,\n\t79,\n\t99,\n\t116,\n\t111,\n\t98,\n\t101,\n\t114,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t32,\n\t115,\n\t97,\n\t105,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t114,\n\t101,\n\t108,\n\t105,\n\t103,\n\t105,\n\t111,\n\t117,\n\t115,\n\t32,\n\t70,\n\t101,\n\t100,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t114,\n\t111,\n\t119,\n\t115,\n\t112,\n\t97,\n\t110,\n\t61,\n\t34,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t97,\n\t32,\n\t102,\n\t101,\n\t119,\n\t109,\n\t101,\n\t97,\n\t110,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t45,\n\t45,\n\t62,\n\t13,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t60,\n\t102,\n\t105,\n\t101,\n\t108,\n\t100,\n\t115,\n\t101,\n\t116,\n\t62,\n\t65,\n\t114,\n\t99,\n\t104,\n\t98,\n\t105,\n\t115,\n\t104,\n\t111,\n\t112,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t110,\n\t111,\n\t98,\n\t101,\n\t105,\n\t110,\n\t103,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t97,\n\t99,\n\t104,\n\t101,\n\t115,\n\t112,\n\t114,\n\t105,\n\t118,\n\t105,\n\t108,\n\t101,\n\t103,\n\t101,\n\t115,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t115,\n\t32,\n\t105,\n\t110,\n\t109,\n\t97,\n\t121,\n\t32,\n\t98,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t69,\n\t97,\n\t115,\n\t116,\n\t101,\n\t114,\n\t32,\n\t101,\n\t103,\n\t103,\n\t109,\n\t101,\n\t99,\n\t104,\n\t97,\n\t110,\n\t105,\n\t115,\n\t109,\n\t115,\n\t114,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t97,\n\t98,\n\t108,\n\t101,\n\t80,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t67,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t34,\n\t62,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t47,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t112,\n\t104,\n\t112,\n\t97,\n\t114,\n\t114,\n\t105,\n\t118,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t45,\n\t106,\n\t115,\n\t115,\n\t100,\n\t107,\n\t39,\n\t41,\n\t41,\n\t59,\n\t109,\n\t97,\n\t110,\n\t97,\n\t103,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t99,\n\t97,\n\t115,\n\t117,\n\t97,\n\t108,\n\t116,\n\t105,\n\t101,\n\t115,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t105,\n\t111,\n\t110,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t105,\n\t97,\n\t110,\n\t115,\n\t83,\n\t101,\n\t112,\n\t116,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t97,\n\t114,\n\t105,\n\t116,\n\t104,\n\t109,\n\t101,\n\t116,\n\t105,\n\t99,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t100,\n\t117,\n\t114,\n\t101,\n\t115,\n\t109,\n\t105,\n\t103,\n\t104,\n\t116,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t80,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t116,\n\t32,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t115,\n\t80,\n\t104,\n\t105,\n\t108,\n\t111,\n\t115,\n\t111,\n\t112,\n\t104,\n\t121,\n\t102,\n\t114,\n\t105,\n\t101,\n\t110,\n\t100,\n\t115,\n\t104,\n\t105,\n\t112,\n\t108,\n\t101,\n\t97,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t103,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t111,\n\t119,\n\t97,\n\t114,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t103,\n\t117,\n\t97,\n\t114,\n\t97,\n\t110,\n\t116,\n\t101,\n\t101,\n\t100,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t35,\n\t48,\n\t48,\n\t48,\n\t118,\n\t105,\n\t100,\n\t101,\n\t111,\n\t32,\n\t103,\n\t97,\n\t109,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t102,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t110,\n\t103,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t115,\n\t97,\n\t110,\n\t115,\n\t45,\n\t115,\n\t101,\n\t114,\n\t105,\n\t102,\n\t111,\n\t110,\n\t107,\n\t101,\n\t121,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t59,\n\t32,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t72,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t108,\n\t121,\n\t105,\n\t110,\n\t103,\n\t116,\n\t121,\n\t112,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t44,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t114,\n\t99,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t105,\n\t118,\n\t101,\n\t115,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t32,\n\t110,\n\t101,\n\t116,\n\t119,\n\t111,\n\t114,\n\t107,\n\t105,\n\t110,\n\t103,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t105,\n\t110,\n\t103,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t108,\n\t111,\n\t119,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t115,\n\t104,\n\t111,\n\t119,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t10,\n\t9,\n\t9,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t97,\n\t105,\n\t110,\n\t116,\n\t115,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t111,\n\t117,\n\t115,\n\t113,\n\t117,\n\t97,\n\t110,\n\t116,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t97,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t111,\n\t109,\n\t101,\n\t114,\n\t104,\n\t101,\n\t32,\n\t100,\n\t105,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t100,\n\t117,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t105,\n\t116,\n\t115,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t97,\n\t110,\n\t32,\n\t97,\n\t118,\n\t101,\n\t114,\n\t97,\n\t103,\n\t101,\n\t101,\n\t102,\n\t102,\n\t111,\n\t114,\n\t116,\n\t115,\n\t32,\n\t116,\n\t111,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t117,\n\t116,\n\t117,\n\t114,\n\t101,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t32,\n\t116,\n\t111,\n\t84,\n\t104,\n\t101,\n\t114,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t44,\n\t99,\n\t97,\n\t112,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t82,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t110,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t100,\n\t69,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t111,\n\t110,\n\t105,\n\t99,\n\t107,\n\t105,\n\t108,\n\t111,\n\t109,\n\t101,\n\t116,\n\t101,\n\t114,\n\t115,\n\t99,\n\t104,\n\t97,\n\t108,\n\t108,\n\t101,\n\t110,\n\t103,\n\t101,\n\t115,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t114,\n\t105,\n\t110,\n\t100,\n\t105,\n\t103,\n\t101,\n\t110,\n\t111,\n\t117,\n\t115,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t117,\n\t98,\n\t115,\n\t105,\n\t100,\n\t105,\n\t97,\n\t114,\n\t121,\n\t99,\n\t111,\n\t110,\n\t115,\n\t112,\n\t105,\n\t114,\n\t97,\n\t99,\n\t121,\n\t100,\n\t101,\n\t116,\n\t97,\n\t105,\n\t108,\n\t115,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t102,\n\t102,\n\t111,\n\t114,\n\t100,\n\t97,\n\t98,\n\t108,\n\t101,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t114,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t32,\n\t102,\n\t111,\n\t114,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t116,\n\t101,\n\t109,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t97,\n\t98,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t101,\n\t108,\n\t121,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t108,\n\t121,\n\t114,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t97,\n\t97,\n\t116,\n\t116,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t116,\n\t114,\n\t97,\n\t118,\n\t101,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t102,\n\t111,\n\t99,\n\t117,\n\t115,\n\t101,\n\t115,\n\t32,\n\t111,\n\t110,\n\t101,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t121,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t98,\n\t108,\n\t101,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t109,\n\t97,\n\t110,\n\t117,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t110,\n\t111,\n\t45,\n\t114,\n\t101,\n\t112,\n\t101,\n\t97,\n\t116,\n\t40,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t67,\n\t111,\n\t109,\n\t109,\n\t101,\n\t114,\n\t99,\n\t105,\n\t97,\n\t108,\n\t105,\n\t110,\n\t32,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t116,\n\t97,\n\t107,\n\t101,\n\t110,\n\t113,\n\t117,\n\t97,\n\t114,\n\t116,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t112,\n\t104,\n\t112,\n\t63,\n\t60,\n\t47,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t62,\n\t10,\n\t112,\n\t101,\n\t114,\n\t99,\n\t101,\n\t110,\n\t116,\n\t97,\n\t103,\n\t101,\n\t98,\n\t101,\n\t115,\n\t116,\n\t45,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t97,\n\t34,\n\t32,\n\t100,\n\t105,\n\t114,\n\t61,\n\t34,\n\t108,\n\t116,\n\t114,\n\t76,\n\t105,\n\t101,\n\t117,\n\t116,\n\t101,\n\t110,\n\t97,\n\t110,\n\t116,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t117,\n\t112,\n\t32,\n\t111,\n\t102,\n\t110,\n\t111,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t114,\n\t103,\n\t117,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t116,\n\t111,\n\t32,\n\t97,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t99,\n\t104,\n\t105,\n\t108,\n\t100,\n\t114,\n\t101,\n\t110,\n\t39,\n\t115,\n\t112,\n\t117,\n\t114,\n\t112,\n\t111,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t102,\n\t111,\n\t114,\n\t109,\n\t117,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t32,\n\t117,\n\t112,\n\t111,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t103,\n\t105,\n\t111,\n\t110,\n\t115,\n\t117,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t32,\n\t111,\n\t102,\n\t112,\n\t97,\n\t115,\n\t115,\n\t101,\n\t110,\n\t103,\n\t101,\n\t114,\n\t115,\n\t112,\n\t111,\n\t115,\n\t115,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t46,\n\t10,\n\t10,\n\t73,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t66,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t119,\n\t97,\n\t114,\n\t100,\n\t115,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t32,\n\t97,\n\t99,\n\t114,\n\t111,\n\t115,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t116,\n\t121,\n\t46,\n\t99,\n\t97,\n\t112,\n\t105,\n\t116,\n\t97,\n\t108,\n\t105,\n\t115,\n\t109,\n\t105,\n\t110,\n\t32,\n\t71,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t121,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t45,\n\t119,\n\t105,\n\t110,\n\t103,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t83,\n\t111,\n\t99,\n\t105,\n\t101,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t105,\n\t97,\n\t110,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t119,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t78,\n\t101,\n\t119,\n\t32,\n\t89,\n\t111,\n\t114,\n\t107,\n\t32,\n\t97,\n\t112,\n\t97,\n\t114,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t105,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t117,\n\t110,\n\t108,\n\t101,\n\t115,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t99,\n\t97,\n\t108,\n\t104,\n\t97,\n\t100,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t97,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t118,\n\t101,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t100,\n\t105,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t116,\n\t101,\n\t110,\n\t100,\n\t97,\n\t110,\n\t99,\n\t101,\n\t67,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t32,\n\t102,\n\t111,\n\t114,\n\t112,\n\t114,\n\t111,\n\t109,\n\t105,\n\t110,\n\t101,\n\t110,\n\t99,\n\t101,\n\t114,\n\t101,\n\t97,\n\t100,\n\t121,\n\t83,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t103,\n\t105,\n\t101,\n\t115,\n\t98,\n\t117,\n\t116,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t101,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t108,\n\t97,\n\t98,\n\t111,\n\t114,\n\t97,\n\t116,\n\t111,\n\t114,\n\t121,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t116,\n\t105,\n\t98,\n\t108,\n\t101,\n\t102,\n\t97,\n\t105,\n\t108,\n\t117,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t44,\n\t32,\n\t115,\n\t117,\n\t99,\n\t104,\n\t32,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t103,\n\t97,\n\t110,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t117,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t47,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t103,\n\t101,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t108,\n\t105,\n\t98,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t32,\n\t104,\n\t111,\n\t108,\n\t100,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t32,\n\t118,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t116,\n\t111,\n\t112,\n\t116,\n\t104,\n\t101,\n\t32,\n\t71,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t111,\n\t117,\n\t116,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t111,\n\t102,\n\t110,\n\t101,\n\t103,\n\t111,\n\t116,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t104,\n\t105,\n\t115,\n\t32,\n\t99,\n\t97,\n\t114,\n\t101,\n\t101,\n\t114,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t100,\n\t61,\n\t34,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t119,\n\t97,\n\t115,\n\t32,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t111,\n\t117,\n\t114,\n\t116,\n\t104,\n\t114,\n\t101,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t112,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t119,\n\t104,\n\t105,\n\t108,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t100,\n\t117,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t44,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t105,\n\t110,\n\t103,\n\t97,\n\t99,\n\t99,\n\t117,\n\t114,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t98,\n\t117,\n\t105,\n\t108,\n\t116,\n\t119,\n\t97,\n\t115,\n\t32,\n\t107,\n\t105,\n\t108,\n\t108,\n\t101,\n\t100,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t109,\n\t117,\n\t99,\n\t104,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t68,\n\t117,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t32,\n\t49,\n\t48,\n\t48,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t75,\n\t105,\n\t110,\n\t103,\n\t100,\n\t111,\n\t109,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t110,\n\t116,\n\t105,\n\t114,\n\t101,\n\t102,\n\t97,\n\t109,\n\t111,\n\t117,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t116,\n\t111,\n\t32,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t111,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t70,\n\t114,\n\t101,\n\t110,\n\t99,\n\t104,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t97,\n\t110,\n\t100,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t100,\n\t34,\n\t62,\n\t105,\n\t115,\n\t32,\n\t115,\n\t97,\n\t105,\n\t100,\n\t32,\n\t116,\n\t111,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t100,\n\t117,\n\t109,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t97,\n\t32,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t101,\n\t45,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t32,\n\t79,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t119,\n\t105,\n\t100,\n\t101,\n\t46,\n\t97,\n\t114,\n\t105,\n\t97,\n\t45,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t108,\n\t97,\n\t110,\n\t101,\n\t116,\n\t97,\n\t110,\n\t100,\n\t32,\n\t105,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t100,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t108,\n\t111,\n\t111,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t97,\n\t116,\n\t98,\n\t101,\n\t110,\n\t101,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t97,\n\t114,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t111,\n\t110,\n\t105,\n\t116,\n\t111,\n\t114,\n\t105,\n\t110,\n\t103,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t100,\n\t108,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t100,\n\t101,\n\t114,\n\t110,\n\t119,\n\t111,\n\t114,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t110,\n\t111,\n\t118,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t115,\n\t111,\n\t117,\n\t110,\n\t100,\n\t116,\n\t114,\n\t97,\n\t99,\n\t107,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t70,\n\t111,\n\t114,\n\t109,\n\t116,\n\t101,\n\t110,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t111,\n\t112,\n\t101,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t101,\n\t100,\n\t97,\n\t100,\n\t111,\n\t112,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t100,\n\t100,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t110,\n\t103,\n\t116,\n\t104,\n\t101,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t97,\n\t110,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t118,\n\t97,\n\t114,\n\t105,\n\t97,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t105,\n\t97,\n\t110,\n\t32,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t97,\n\t117,\n\t116,\n\t111,\n\t109,\n\t111,\n\t116,\n\t105,\n\t118,\n\t101,\n\t98,\n\t121,\n\t32,\n\t102,\n\t97,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t112,\n\t117,\n\t114,\n\t115,\n\t117,\n\t105,\n\t116,\n\t32,\n\t111,\n\t102,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t32,\n\t69,\n\t110,\n\t103,\n\t108,\n\t97,\n\t110,\n\t100,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t99,\n\t99,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t109,\n\t101,\n\t115,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t112,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t110,\n\t103,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t104,\n\t105,\n\t115,\n\t32,\n\t111,\n\t114,\n\t32,\n\t104,\n\t101,\n\t114,\n\t116,\n\t114,\n\t101,\n\t109,\n\t101,\n\t110,\n\t100,\n\t111,\n\t117,\n\t115,\n\t102,\n\t114,\n\t101,\n\t101,\n\t100,\n\t111,\n\t109,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t48,\n\t32,\n\t49,\n\t101,\n\t109,\n\t32,\n\t49,\n\t101,\n\t109,\n\t59,\n\t66,\n\t97,\n\t115,\n\t107,\n\t101,\n\t116,\n\t98,\n\t97,\n\t108,\n\t108,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t46,\n\t99,\n\t115,\n\t115,\n\t97,\n\t110,\n\t32,\n\t101,\n\t97,\n\t114,\n\t108,\n\t105,\n\t101,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t47,\n\t34,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t46,\n\t99,\n\t111,\n\t109,\n\t47,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t116,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t105,\n\t116,\n\t116,\n\t115,\n\t98,\n\t117,\n\t114,\n\t103,\n\t104,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t34,\n\t62,\n\t13,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t40,\n\t102,\n\t116,\n\t117,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t111,\n\t117,\n\t116,\n\t104,\n\t97,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t13,\n\t10,\n\t32,\n\t111,\n\t99,\n\t99,\n\t97,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t105,\n\t116,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t112,\n\t104,\n\t121,\n\t115,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t32,\n\t32,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t67,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t44,\n\t32,\n\t98,\n\t103,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t61,\n\t34,\n\t116,\n\t97,\n\t98,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t97,\n\t115,\n\t116,\n\t114,\n\t111,\n\t117,\n\t115,\n\t65,\n\t110,\n\t97,\n\t108,\n\t121,\n\t116,\n\t105,\n\t99,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t97,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t60,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t62,\n\t10,\n\t60,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t115,\n\t105,\n\t110,\n\t103,\n\t101,\n\t114,\n\t32,\n\t97,\n\t110,\n\t100,\n\t46,\n\t115,\n\t114,\n\t99,\n\t32,\n\t61,\n\t32,\n\t34,\n\t47,\n\t47,\n\t118,\n\t105,\n\t111,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t108,\n\t121,\n\t105,\n\t115,\n\t32,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t114,\n\t101,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t115,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t110,\n\t101,\n\t100,\n\t101,\n\t114,\n\t108,\n\t97,\n\t110,\n\t100,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t103,\n\t117,\n\t195,\n\t170,\n\t115,\n\t215,\n\t162,\n\t215,\n\t145,\n\t215,\n\t168,\n\t215,\n\t153,\n\t215,\n\t170,\n\t217,\n\t129,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t179,\n\t219,\n\t140,\n\t100,\n\t101,\n\t115,\n\t97,\n\t114,\n\t114,\n\t111,\n\t108,\n\t108,\n\t111,\n\t99,\n\t111,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t105,\n\t111,\n\t101,\n\t100,\n\t117,\n\t99,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t115,\n\t101,\n\t112,\n\t116,\n\t105,\n\t101,\n\t109,\n\t98,\n\t114,\n\t101,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t100,\n\t111,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t117,\n\t98,\n\t105,\n\t99,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t105,\n\t100,\n\t97,\n\t100,\n\t114,\n\t101,\n\t115,\n\t112,\n\t117,\n\t101,\n\t115,\n\t116,\n\t97,\n\t115,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t97,\n\t100,\n\t111,\n\t115,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t101,\n\t114,\n\t118,\n\t97,\n\t100,\n\t111,\n\t115,\n\t97,\n\t114,\n\t116,\n\t195,\n\t173,\n\t99,\n\t117,\n\t108,\n\t111,\n\t115,\n\t100,\n\t105,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t101,\n\t115,\n\t115,\n\t105,\n\t103,\n\t117,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t115,\n\t114,\n\t101,\n\t112,\n\t195,\n\t186,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t115,\n\t105,\n\t116,\n\t117,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t105,\n\t111,\n\t112,\n\t114,\n\t105,\n\t118,\n\t97,\n\t99,\n\t105,\n\t100,\n\t97,\n\t100,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t105,\n\t111,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t112,\n\t111,\n\t98,\n\t108,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t112,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t105,\n\t100,\n\t111,\n\t115,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t111,\n\t114,\n\t105,\n\t111,\n\t115,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t101,\n\t115,\n\t99,\n\t97,\n\t116,\n\t101,\n\t103,\n\t111,\n\t114,\n\t195,\n\t173,\n\t97,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t101,\n\t115,\n\t100,\n\t105,\n\t115,\n\t112,\n\t111,\n\t110,\n\t105,\n\t98,\n\t108,\n\t101,\n\t97,\n\t99,\n\t116,\n\t117,\n\t97,\n\t108,\n\t105,\n\t100,\n\t97,\n\t100,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t118,\n\t97,\n\t108,\n\t108,\n\t97,\n\t100,\n\t111,\n\t108,\n\t105,\n\t100,\n\t98,\n\t105,\n\t98,\n\t108,\n\t105,\n\t111,\n\t116,\n\t101,\n\t99,\n\t97,\n\t114,\n\t101,\n\t108,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t99,\n\t97,\n\t108,\n\t101,\n\t110,\n\t100,\n\t97,\n\t114,\n\t105,\n\t111,\n\t112,\n\t111,\n\t108,\n\t195,\n\t173,\n\t116,\n\t105,\n\t99,\n\t97,\n\t115,\n\t97,\n\t110,\n\t116,\n\t101,\n\t114,\n\t105,\n\t111,\n\t114,\n\t101,\n\t115,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t115,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t101,\n\t122,\n\t97,\n\t109,\n\t97,\n\t116,\n\t101,\n\t114,\n\t105,\n\t97,\n\t108,\n\t101,\n\t115,\n\t100,\n\t105,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t101,\n\t99,\n\t111,\n\t110,\n\t195,\n\t179,\n\t109,\n\t105,\n\t99,\n\t97,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t114,\n\t111,\n\t100,\n\t114,\n\t195,\n\t173,\n\t103,\n\t117,\n\t101,\n\t122,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t99,\n\t117,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t110,\n\t100,\n\t105,\n\t115,\n\t99,\n\t117,\n\t115,\n\t105,\n\t195,\n\t179,\n\t110,\n\t101,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t97,\n\t102,\n\t117,\n\t110,\n\t100,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t102,\n\t114,\n\t101,\n\t99,\n\t117,\n\t101,\n\t110,\n\t116,\n\t101,\n\t115,\n\t112,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t101,\n\t110,\n\t116,\n\t101,\n\t116,\n\t111,\n\t116,\n\t97,\n\t108,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t182,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t131,\n\t208,\n\t180,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t182,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t178,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t143,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t182,\n\t208,\n\t181,\n\t209,\n\t135,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t139,\n\t208,\n\t177,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t181,\n\t208,\n\t190,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t140,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t178,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t185,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t135,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t183,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t179,\n\t209,\n\t131,\n\t209,\n\t130,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t185,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t182,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t182,\n\t208,\n\t180,\n\t209,\n\t131,\n\t208,\n\t177,\n\t209,\n\t131,\n\t208,\n\t180,\n\t209,\n\t131,\n\t209,\n\t130,\n\t208,\n\t159,\n\t208,\n\t190,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t183,\n\t208,\n\t180,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t140,\n\t208,\n\t178,\n\t208,\n\t184,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t178,\n\t209,\n\t143,\n\t208,\n\t183,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t131,\n\t208,\n\t182,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t187,\n\t209,\n\t142,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t185,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t184,\n\t209,\n\t133,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t182,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t189,\n\t209,\n\t140,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t187,\n\t209,\n\t131,\n\t209,\n\t135,\n\t209,\n\t136,\n\t208,\n\t181,\n\t208,\n\t191,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t180,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t140,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t177,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t178,\n\t209,\n\t139,\n\t209,\n\t133,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t177,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t181,\n\t209,\n\t135,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t178,\n\t209,\n\t139,\n\t208,\n\t181,\n\t209,\n\t131,\n\t209,\n\t129,\n\t208,\n\t187,\n\t209,\n\t131,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t176,\n\t208,\n\t180,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t135,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t159,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t178,\n\t209,\n\t139,\n\t208,\n\t185,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t184,\n\t209,\n\t133,\n\t209,\n\t129,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t209,\n\t131,\n\t208,\n\t161,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t186,\n\t209,\n\t130,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t188,\n\t208,\n\t154,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t179,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t136,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t185,\n\t209,\n\t130,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t184,\n\t208,\n\t188,\n\t209,\n\t129,\n\t208,\n\t178,\n\t209,\n\t143,\n\t208,\n\t183,\n\t209,\n\t140,\n\t208,\n\t187,\n\t209,\n\t142,\n\t208,\n\t177,\n\t208,\n\t190,\n\t208,\n\t185,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t180,\n\t208,\n\t184,\n\t208,\n\t154,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t164,\n\t208,\n\t190,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t188,\n\t209,\n\t128,\n\t209,\n\t139,\n\t208,\n\t189,\n\t208,\n\t186,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t187,\n\t208,\n\t184,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t186,\n\t209,\n\t130,\n\t209,\n\t139,\n\t209,\n\t129,\n\t209,\n\t143,\n\t209,\n\t135,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t143,\n\t209,\n\t134,\n\t209,\n\t134,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t130,\n\t209,\n\t128,\n\t209,\n\t130,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t180,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t188,\n\t209,\n\t139,\n\t209,\n\t133,\n\t209,\n\t128,\n\t209,\n\t139,\n\t208,\n\t189,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t157,\n\t208,\n\t190,\n\t208,\n\t178,\n\t209,\n\t139,\n\t208,\n\t185,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t176,\n\t209,\n\t132,\n\t208,\n\t184,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t188,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t128,\n\t209,\n\t130,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t186,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t136,\n\t208,\n\t184,\n\t209,\n\t133,\n\t208,\n\t188,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t131,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t142,\n\t209,\n\t130,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t180,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t131,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t189,\n\t209,\n\t134,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t144,\n\t209,\n\t128,\n\t209,\n\t133,\n\t208,\n\t184,\n\t208,\n\t178,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t175,\n\t217,\n\t137,\n\t216,\n\t165,\n\t216,\n\t177,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t133,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t168,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t172,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t136,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t181,\n\t217,\n\t136,\n\t216,\n\t177,\n\t216,\n\t172,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t175,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t182,\n\t217,\n\t136,\n\t216,\n\t165,\n\t216,\n\t182,\n\t216,\n\t167,\n\t217,\n\t129,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t130,\n\t216,\n\t179,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t170,\n\t216,\n\t173,\n\t217,\n\t133,\n\t217,\n\t138,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t132,\n\t217,\n\t129,\n\t216,\n\t167,\n\t216,\n\t170,\n\t217,\n\t133,\n\t217,\n\t132,\n\t216,\n\t170,\n\t217,\n\t130,\n\t217,\n\t137,\n\t216,\n\t170,\n\t216,\n\t185,\n\t216,\n\t175,\n\t217,\n\t138,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t180,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t163,\n\t216,\n\t174,\n\t216,\n\t168,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t170,\n\t216,\n\t183,\n\t217,\n\t136,\n\t217,\n\t138,\n\t216,\n\t177,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t131,\n\t217,\n\t133,\n\t216,\n\t165,\n\t216,\n\t177,\n\t217,\n\t129,\n\t216,\n\t167,\n\t217,\n\t130,\n\t216,\n\t183,\n\t217,\n\t132,\n\t216,\n\t168,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t132,\n\t216,\n\t186,\n\t216,\n\t169,\n\t216,\n\t170,\n\t216,\n\t177,\n\t216,\n\t170,\n\t217,\n\t138,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t180,\n\t217,\n\t138,\n\t216,\n\t174,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t130,\n\t216,\n\t181,\n\t216,\n\t181,\n\t216,\n\t167,\n\t217,\n\t129,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t173,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t171,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t132,\n\t217,\n\t135,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t217,\n\t133,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t168,\n\t216,\n\t169,\n\t217,\n\t138,\n\t217,\n\t133,\n\t217,\n\t131,\n\t217,\n\t134,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t183,\n\t217,\n\t129,\n\t217,\n\t132,\n\t217,\n\t129,\n\t217,\n\t138,\n\t216,\n\t175,\n\t217,\n\t138,\n\t217,\n\t136,\n\t216,\n\t165,\n\t216,\n\t175,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t169,\n\t216,\n\t170,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t138,\n\t216,\n\t174,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t181,\n\t216,\n\t173,\n\t216,\n\t169,\n\t216,\n\t170,\n\t216,\n\t179,\n\t216,\n\t172,\n\t217,\n\t138,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t136,\n\t217,\n\t130,\n\t216,\n\t170,\n\t216,\n\t185,\n\t217,\n\t134,\n\t216,\n\t175,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t175,\n\t217,\n\t138,\n\t217,\n\t134,\n\t216,\n\t169,\n\t216,\n\t170,\n\t216,\n\t181,\n\t217,\n\t133,\n\t217,\n\t138,\n\t217,\n\t133,\n\t216,\n\t163,\n\t216,\n\t177,\n\t216,\n\t180,\n\t217,\n\t138,\n\t217,\n\t129,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t176,\n\t217,\n\t138,\n\t217,\n\t134,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t168,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t168,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t169,\n\t216,\n\t163,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t179,\n\t217,\n\t129,\n\t216,\n\t177,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t217,\n\t131,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t137,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t217,\n\t136,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t179,\n\t217,\n\t134,\n\t216,\n\t169,\n\t216,\n\t172,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t185,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t181,\n\t216,\n\t173,\n\t217,\n\t129,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t217,\n\t138,\n\t217,\n\t134,\n\t217,\n\t131,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t174,\n\t216,\n\t167,\n\t216,\n\t181,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t132,\n\t217,\n\t129,\n\t216,\n\t163,\n\t216,\n\t185,\n\t216,\n\t182,\n\t216,\n\t167,\n\t216,\n\t161,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t174,\n\t217,\n\t138,\n\t216,\n\t177,\n\t216,\n\t177,\n\t216,\n\t179,\n\t216,\n\t167,\n\t216,\n\t166,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t130,\n\t217,\n\t132,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t216,\n\t175,\n\t216,\n\t168,\n\t217,\n\t133,\n\t217,\n\t130,\n\t216,\n\t167,\n\t216,\n\t183,\n\t216,\n\t185,\n\t217,\n\t133,\n\t216,\n\t177,\n\t216,\n\t167,\n\t216,\n\t179,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t183,\n\t217,\n\t130,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t172,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t180,\n\t216,\n\t170,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t130,\n\t216,\n\t175,\n\t217,\n\t133,\n\t217,\n\t138,\n\t216,\n\t185,\n\t216,\n\t183,\n\t217,\n\t138,\n\t217,\n\t131,\n\t115,\n\t66,\n\t121,\n\t84,\n\t97,\n\t103,\n\t78,\n\t97,\n\t109,\n\t101,\n\t40,\n\t46,\n\t106,\n\t112,\n\t103,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t49,\n\t112,\n\t120,\n\t32,\n\t115,\n\t111,\n\t108,\n\t105,\n\t100,\n\t32,\n\t35,\n\t46,\n\t103,\n\t105,\n\t102,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t116,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t34,\n\t32,\n\t111,\n\t110,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t61,\n\t34,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t97,\n\t100,\n\t118,\n\t101,\n\t114,\n\t116,\n\t105,\n\t115,\n\t105,\n\t110,\n\t103,\n\t46,\n\t112,\n\t110,\n\t103,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t101,\n\t110,\n\t118,\n\t105,\n\t114,\n\t111,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t112,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t110,\n\t99,\n\t101,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t112,\n\t114,\n\t105,\n\t97,\n\t116,\n\t101,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t109,\n\t100,\n\t97,\n\t115,\n\t104,\n\t59,\n\t105,\n\t109,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t60,\n\t47,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t62,\n\t60,\n\t47,\n\t114,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t116,\n\t101,\n\t109,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t116,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t104,\n\t111,\n\t108,\n\t100,\n\t101,\n\t114,\n\t118,\n\t105,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t58,\n\t99,\n\t111,\n\t112,\n\t121,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t62,\n\t48,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t101,\n\t118,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t100,\n\t101,\n\t115,\n\t116,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t67,\n\t111,\n\t114,\n\t112,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t60,\n\t117,\n\t108,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t65,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t117,\n\t97,\n\t108,\n\t115,\n\t112,\n\t101,\n\t114,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t115,\n\t101,\n\t116,\n\t84,\n\t105,\n\t109,\n\t101,\n\t111,\n\t117,\n\t116,\n\t40,\n\t117,\n\t114,\n\t108,\n\t40,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t109,\n\t97,\n\t116,\n\t104,\n\t101,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t115,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t116,\n\t111,\n\t112,\n\t58,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t41,\n\t32,\n\t110,\n\t111,\n\t45,\n\t114,\n\t101,\n\t112,\n\t101,\n\t97,\n\t116,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t46,\n\t74,\n\t80,\n\t71,\n\t124,\n\t116,\n\t104,\n\t117,\n\t109,\n\t98,\n\t124,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t116,\n\t101,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t108,\n\t101,\n\t102,\n\t116,\n\t59,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t104,\n\t117,\n\t110,\n\t100,\n\t114,\n\t101,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t10,\n\t10,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t58,\n\t98,\n\t111,\n\t116,\n\t104,\n\t59,\n\t99,\n\t111,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t32,\n\t102,\n\t111,\n\t114,\n\t61,\n\t34,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t45,\n\t116,\n\t111,\n\t112,\n\t58,\n\t78,\n\t101,\n\t119,\n\t32,\n\t90,\n\t101,\n\t97,\n\t108,\n\t97,\n\t110,\n\t100,\n\t114,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t112,\n\t104,\n\t111,\n\t116,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t121,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t38,\n\t108,\n\t116,\n\t59,\n\t115,\n\t117,\n\t112,\n\t38,\n\t103,\n\t116,\n\t59,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t118,\n\t101,\n\t114,\n\t115,\n\t121,\n\t78,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t108,\n\t97,\n\t110,\n\t100,\n\t115,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t109,\n\t97,\n\t120,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t61,\n\t34,\n\t115,\n\t119,\n\t105,\n\t116,\n\t122,\n\t101,\n\t114,\n\t108,\n\t97,\n\t110,\n\t100,\n\t68,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t115,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t10,\n\t10,\n\t65,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t60,\n\t47,\n\t116,\n\t101,\n\t120,\n\t116,\n\t97,\n\t114,\n\t101,\n\t97,\n\t62,\n\t116,\n\t104,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t98,\n\t105,\n\t114,\n\t100,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t110,\n\t100,\n\t97,\n\t115,\n\t104,\n\t59,\n\t115,\n\t112,\n\t101,\n\t99,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t108,\n\t101,\n\t103,\n\t105,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t111,\n\t110,\n\t105,\n\t99,\n\t115,\n\t10,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t105,\n\t108,\n\t108,\n\t117,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t101,\n\t110,\n\t103,\n\t105,\n\t110,\n\t101,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t116,\n\t101,\n\t114,\n\t114,\n\t105,\n\t116,\n\t111,\n\t114,\n\t105,\n\t101,\n\t115,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t100,\n\t105,\n\t115,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t100,\n\t54,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t115,\n\t97,\n\t110,\n\t115,\n\t45,\n\t115,\n\t101,\n\t114,\n\t105,\n\t102,\n\t59,\n\t99,\n\t97,\n\t112,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t100,\n\t105,\n\t115,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t101,\n\t100,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t111,\n\t111,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t102,\n\t111,\n\t114,\n\t105,\n\t116,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t65,\n\t102,\n\t103,\n\t104,\n\t97,\n\t110,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t119,\n\t97,\n\t115,\n\t32,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t77,\n\t97,\n\t116,\n\t104,\n\t46,\n\t102,\n\t108,\n\t111,\n\t111,\n\t114,\n\t40,\n\t115,\n\t117,\n\t114,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t99,\n\t97,\n\t110,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t98,\n\t101,\n\t111,\n\t98,\n\t115,\n\t101,\n\t114,\n\t118,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t109,\n\t97,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t97,\n\t110,\n\t99,\n\t101,\n\t101,\n\t110,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t60,\n\t104,\n\t50,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t105,\n\t116,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t105,\n\t110,\n\t118,\n\t97,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t41,\n\t46,\n\t103,\n\t101,\n\t116,\n\t84,\n\t105,\n\t109,\n\t101,\n\t40,\n\t41,\n\t102,\n\t117,\n\t110,\n\t100,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t68,\n\t101,\n\t115,\n\t112,\n\t105,\n\t116,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t34,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t105,\n\t110,\n\t115,\n\t112,\n\t105,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t120,\n\t97,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t114,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t120,\n\t112,\n\t108,\n\t97,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t32,\n\t61,\n\t32,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t68,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t32,\n\t46,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t40,\n\t101,\n\t97,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t105,\n\t110,\n\t116,\n\t101,\n\t103,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t100,\n\t117,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t98,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t111,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t77,\n\t105,\n\t100,\n\t100,\n\t108,\n\t101,\n\t32,\n\t69,\n\t97,\n\t115,\n\t116,\n\t60,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t99,\n\t111,\n\t112,\n\t121,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t32,\n\t112,\n\t101,\n\t114,\n\t104,\n\t97,\n\t112,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t32,\n\t68,\n\t101,\n\t99,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t97,\n\t114,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t102,\n\t97,\n\t109,\n\t111,\n\t117,\n\t115,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t108,\n\t105,\n\t109,\n\t105,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t120,\n\t99,\n\t108,\n\t117,\n\t115,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t115,\n\t111,\n\t118,\n\t101,\n\t114,\n\t101,\n\t105,\n\t103,\n\t110,\n\t116,\n\t121,\n\t45,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t34,\n\t62,\n\t10,\n\t60,\n\t116,\n\t100,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t112,\n\t97,\n\t114,\n\t97,\n\t108,\n\t108,\n\t101,\n\t108,\n\t32,\n\t116,\n\t111,\n\t100,\n\t111,\n\t99,\n\t116,\n\t114,\n\t105,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t111,\n\t99,\n\t99,\n\t117,\n\t112,\n\t105,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t111,\n\t108,\n\t111,\n\t103,\n\t121,\n\t82,\n\t101,\n\t110,\n\t97,\n\t105,\n\t115,\n\t115,\n\t97,\n\t110,\n\t99,\n\t101,\n\t97,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t32,\n\t102,\n\t111,\n\t114,\n\t101,\n\t120,\n\t112,\n\t108,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t99,\n\t111,\n\t103,\n\t110,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t114,\n\t101,\n\t100,\n\t101,\n\t99,\n\t101,\n\t115,\n\t115,\n\t111,\n\t114,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t47,\n\t60,\n\t104,\n\t49,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t109,\n\t97,\n\t121,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t98,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t105,\n\t122,\n\t101,\n\t100,\n\t60,\n\t47,\n\t102,\n\t105,\n\t101,\n\t108,\n\t100,\n\t115,\n\t101,\n\t116,\n\t62,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t118,\n\t101,\n\t109,\n\t105,\n\t108,\n\t108,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t101,\n\t110,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t97,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t46,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t116,\n\t78,\n\t111,\n\t100,\n\t101,\n\t97,\n\t103,\n\t114,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t101,\n\t65,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t114,\n\t101,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t101,\n\t114,\n\t115,\n\t116,\n\t111,\n\t119,\n\t97,\n\t114,\n\t100,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t77,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t40,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t60,\n\t116,\n\t100,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t59,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t49,\n\t48,\n\t48,\n\t37,\n\t105,\n\t110,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t116,\n\t60,\n\t104,\n\t51,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t32,\n\t111,\n\t110,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t61,\n\t34,\n\t41,\n\t46,\n\t97,\n\t100,\n\t100,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t40,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t79,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t97,\n\t117,\n\t103,\n\t104,\n\t116,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t111,\n\t114,\n\t105,\n\t101,\n\t115,\n\t98,\n\t114,\n\t97,\n\t110,\n\t99,\n\t104,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t13,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t115,\n\t116,\n\t100,\n\t101,\n\t99,\n\t108,\n\t97,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t103,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t73,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t121,\n\t105,\n\t110,\n\t32,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t111,\n\t34,\n\t62,\n\t10,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t60,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t49,\n\t97,\n\t99,\n\t114,\n\t111,\n\t115,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t114,\n\t105,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t41,\n\t59,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t115,\n\t101,\n\t101,\n\t110,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t100,\n\t101,\n\t109,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t114,\n\t34,\n\t62,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t66,\n\t114,\n\t105,\n\t116,\n\t105,\n\t115,\n\t104,\n\t119,\n\t97,\n\t115,\n\t32,\n\t119,\n\t114,\n\t105,\n\t116,\n\t116,\n\t101,\n\t110,\n\t33,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t59,\n\t112,\n\t120,\n\t59,\n\t32,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t116,\n\t111,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t100,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t109,\n\t109,\n\t105,\n\t103,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t60,\n\t104,\n\t52,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t78,\n\t111,\n\t118,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t119,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t112,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t97,\n\t99,\n\t113,\n\t117,\n\t105,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t101,\n\t114,\n\t115,\n\t101,\n\t99,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t123,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t105,\n\t110,\n\t118,\n\t101,\n\t115,\n\t116,\n\t105,\n\t103,\n\t97,\n\t116,\n\t101,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t100,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t108,\n\t105,\n\t107,\n\t101,\n\t108,\n\t121,\n\t119,\n\t105,\n\t100,\n\t101,\n\t108,\n\t121,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t100,\n\t105,\n\t115,\n\t99,\n\t117,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t40,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t73,\n\t116,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t105,\n\t116,\n\t32,\n\t100,\n\t111,\n\t101,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t114,\n\t121,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t104,\n\t97,\n\t98,\n\t105,\n\t116,\n\t97,\n\t110,\n\t116,\n\t115,\n\t105,\n\t109,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t99,\n\t104,\n\t111,\n\t108,\n\t97,\n\t114,\n\t115,\n\t104,\n\t105,\n\t112,\n\t99,\n\t111,\n\t110,\n\t115,\n\t117,\n\t109,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t111,\n\t114,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t114,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t112,\n\t120,\n\t59,\n\t32,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t97,\n\t32,\n\t115,\n\t101,\n\t114,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t97,\n\t114,\n\t101,\n\t32,\n\t117,\n\t115,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t114,\n\t111,\n\t108,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t114,\n\t101,\n\t118,\n\t105,\n\t111,\n\t117,\n\t115,\n\t108,\n\t121,\n\t32,\n\t100,\n\t101,\n\t114,\n\t105,\n\t118,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t115,\n\t101,\n\t118,\n\t105,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t115,\n\t99,\n\t104,\n\t101,\n\t109,\n\t101,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t99,\n\t101,\n\t114,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t32,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t61,\n\t34,\n\t104,\n\t105,\n\t103,\n\t104,\n\t32,\n\t115,\n\t99,\n\t104,\n\t111,\n\t111,\n\t108,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t101,\n\t32,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t102,\n\t111,\n\t114,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t97,\n\t100,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t114,\n\t101,\n\t101,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t121,\n\t105,\n\t110,\n\t32,\n\t70,\n\t101,\n\t98,\n\t114,\n\t117,\n\t97,\n\t114,\n\t121,\n\t115,\n\t111,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t119,\n\t104,\n\t111,\n\t32,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t60,\n\t112,\n\t97,\n\t114,\n\t97,\n\t109,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t97,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t105,\n\t110,\n\t32,\n\t116,\n\t101,\n\t114,\n\t109,\n\t115,\n\t32,\n\t111,\n\t102,\n\t97,\n\t112,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t73,\n\t83,\n\t79,\n\t45,\n\t56,\n\t56,\n\t53,\n\t57,\n\t45,\n\t49,\n\t34,\n\t119,\n\t97,\n\t115,\n\t32,\n\t98,\n\t111,\n\t114,\n\t110,\n\t32,\n\t105,\n\t110,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t109,\n\t101,\n\t97,\n\t115,\n\t117,\n\t114,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t105,\n\t115,\n\t32,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t58,\n\t32,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t115,\n\t105,\n\t103,\n\t110,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t110,\n\t116,\n\t99,\n\t101,\n\t108,\n\t101,\n\t98,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t109,\n\t105,\n\t116,\n\t116,\n\t101,\n\t100,\n\t47,\n\t106,\n\t115,\n\t47,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t46,\n\t105,\n\t115,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t101,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t116,\n\t97,\n\t98,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t61,\n\t34,\n\t105,\n\t116,\n\t32,\n\t99,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t60,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t104,\n\t97,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t13,\n\t10,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t13,\n\t10,\n\t60,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t84,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t105,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t104,\n\t101,\n\t32,\n\t104,\n\t97,\n\t100,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t112,\n\t104,\n\t105,\n\t108,\n\t111,\n\t115,\n\t111,\n\t112,\n\t104,\n\t101,\n\t114,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t101,\n\t100,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t97,\n\t109,\n\t111,\n\t110,\n\t103,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t116,\n\t111,\n\t32,\n\t115,\n\t97,\n\t121,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t69,\n\t110,\n\t103,\n\t105,\n\t110,\n\t101,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t97,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t102,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t112,\n\t104,\n\t111,\n\t116,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t121,\n\t105,\n\t110,\n\t103,\n\t72,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t82,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t32,\n\t111,\n\t102,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t115,\n\t97,\n\t114,\n\t105,\n\t108,\n\t121,\n\t112,\n\t114,\n\t111,\n\t98,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t108,\n\t101,\n\t97,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t97,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t102,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t105,\n\t99,\n\t105,\n\t116,\n\t121,\n\t104,\n\t101,\n\t97,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t97,\n\t117,\n\t114,\n\t97,\n\t110,\n\t116,\n\t115,\n\t112,\n\t97,\n\t114,\n\t116,\n\t110,\n\t101,\n\t114,\n\t115,\n\t104,\n\t105,\n\t112,\n\t101,\n\t109,\n\t112,\n\t104,\n\t97,\n\t115,\n\t105,\n\t115,\n\t32,\n\t111,\n\t110,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t115,\n\t104,\n\t97,\n\t114,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t115,\n\t97,\n\t121,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t102,\n\t105,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t34,\n\t62,\n\t60,\n\t47,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t62,\n\t97,\n\t115,\n\t32,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t115,\n\t58,\n\t109,\n\t101,\n\t114,\n\t103,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t114,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t100,\n\t32,\n\t111,\n\t117,\n\t116,\n\t111,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t110,\n\t105,\n\t116,\n\t121,\n\t118,\n\t105,\n\t101,\n\t119,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t100,\n\t105,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t105,\n\t110,\n\t103,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t99,\n\t101,\n\t105,\n\t118,\n\t101,\n\t100,\n\t115,\n\t101,\n\t116,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t118,\n\t97,\n\t108,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t105,\n\t110,\n\t32,\n\t78,\n\t101,\n\t119,\n\t32,\n\t89,\n\t111,\n\t114,\n\t107,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t10,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t105,\n\t110,\n\t99,\n\t111,\n\t114,\n\t112,\n\t111,\n\t114,\n\t97,\n\t116,\n\t101,\n\t59,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t104,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t34,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t99,\n\t97,\n\t114,\n\t114,\n\t105,\n\t101,\n\t100,\n\t32,\n\t111,\n\t117,\n\t116,\n\t83,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t97,\n\t110,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t67,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t114,\n\t34,\n\t62,\n\t109,\n\t97,\n\t105,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t111,\n\t112,\n\t104,\n\t101,\n\t114,\n\t77,\n\t117,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t114,\n\t105,\n\t116,\n\t105,\n\t110,\n\t103,\n\t115,\n\t32,\n\t111,\n\t102,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t50,\n\t115,\n\t105,\n\t122,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t109,\n\t105,\n\t120,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t69,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t101,\n\t100,\n\t117,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t116,\n\t105,\n\t116,\n\t105,\n\t118,\n\t101,\n\t32,\n\t111,\n\t110,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t61,\n\t34,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t47,\n\t68,\n\t84,\n\t68,\n\t32,\n\t88,\n\t72,\n\t84,\n\t77,\n\t76,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t99,\n\t121,\n\t32,\n\t116,\n\t111,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t100,\n\t101,\n\t115,\n\t112,\n\t105,\n\t116,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t32,\n\t108,\n\t101,\n\t103,\n\t105,\n\t115,\n\t108,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t46,\n\t105,\n\t110,\n\t110,\n\t101,\n\t114,\n\t72,\n\t84,\n\t77,\n\t76,\n\t32,\n\t97,\n\t108,\n\t108,\n\t101,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t65,\n\t103,\n\t114,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t101,\n\t119,\n\t97,\n\t115,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t97,\n\t99,\n\t104,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t108,\n\t108,\n\t105,\n\t103,\n\t101,\n\t110,\n\t116,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t44,\n\t115,\n\t97,\n\t110,\n\t115,\n\t45,\n\t115,\n\t101,\n\t114,\n\t105,\n\t102,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t80,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t110,\n\t99,\n\t101,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t44,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t105,\n\t115,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t97,\n\t98,\n\t98,\n\t114,\n\t101,\n\t118,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t104,\n\t105,\n\t103,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t115,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t117,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t102,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t116,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t49,\n\t101,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t72,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t104,\n\t105,\n\t115,\n\t32,\n\t98,\n\t114,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t97,\n\t110,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t97,\n\t114,\n\t121,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t117,\n\t108,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t32,\n\t105,\n\t110,\n\t110,\n\t111,\n\t118,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t115,\n\t116,\n\t105,\n\t108,\n\t108,\n\t99,\n\t97,\n\t110,\n\t32,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t98,\n\t101,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t111,\n\t71,\n\t77,\n\t84,\n\t83,\n\t116,\n\t114,\n\t105,\n\t110,\n\t103,\n\t65,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t105,\n\t109,\n\t103,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t44,\n\t119,\n\t97,\n\t115,\n\t32,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t100,\n\t111,\n\t99,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t110,\n\t101,\n\t105,\n\t103,\n\t104,\n\t98,\n\t111,\n\t114,\n\t105,\n\t110,\n\t103,\n\t100,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t117,\n\t105,\n\t115,\n\t104,\n\t119,\n\t104,\n\t101,\n\t110,\n\t32,\n\t104,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t105,\n\t110,\n\t103,\n\t116,\n\t101,\n\t114,\n\t114,\n\t101,\n\t115,\n\t116,\n\t114,\n\t105,\n\t97,\n\t108,\n\t77,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t114,\n\t103,\n\t117,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t110,\n\t32,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t99,\n\t111,\n\t110,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t119,\n\t105,\n\t100,\n\t101,\n\t115,\n\t112,\n\t114,\n\t101,\n\t97,\n\t100,\n\t32,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t107,\n\t105,\n\t108,\n\t108,\n\t101,\n\t100,\n\t115,\n\t99,\n\t114,\n\t101,\n\t101,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t73,\n\t110,\n\t32,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t111,\n\t101,\n\t120,\n\t112,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t100,\n\t101,\n\t115,\n\t99,\n\t101,\n\t110,\n\t100,\n\t97,\n\t110,\n\t116,\n\t115,\n\t97,\n\t114,\n\t101,\n\t32,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t108,\n\t101,\n\t103,\n\t105,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t32,\n\t104,\n\t105,\n\t103,\n\t104,\n\t101,\n\t115,\n\t116,\n\t102,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t100,\n\t111,\n\t32,\n\t110,\n\t111,\n\t116,\n\t97,\n\t114,\n\t103,\n\t117,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t115,\n\t104,\n\t111,\n\t119,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t112,\n\t114,\n\t101,\n\t100,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t110,\n\t116,\n\t116,\n\t104,\n\t101,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t45,\n\t108,\n\t105,\n\t118,\n\t101,\n\t100,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t108,\n\t105,\n\t116,\n\t116,\n\t108,\n\t101,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t104,\n\t97,\n\t100,\n\t32,\n\t97,\n\t108,\n\t114,\n\t101,\n\t97,\n\t100,\n\t121,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t101,\n\t116,\n\t101,\n\t100,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t44,\n\t60,\n\t47,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t51,\n\t73,\n\t110,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t116,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t45,\n\t115,\n\t99,\n\t97,\n\t108,\n\t101,\n\t46,\n\t32,\n\t65,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t101,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t116,\n\t119,\n\t111,\n\t32,\n\t111,\n\t114,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t101,\n\t120,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t117,\n\t98,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t97,\n\t110,\n\t100,\n\t60,\n\t47,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t62,\n\t13,\n\t10,\n\t67,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t101,\n\t108,\n\t105,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t119,\n\t105,\n\t108,\n\t108,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t102,\n\t114,\n\t111,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t115,\n\t105,\n\t116,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t110,\n\t115,\n\t117,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t116,\n\t111,\n\t32,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t32,\n\t97,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t115,\n\t115,\n\t105,\n\t112,\n\t112,\n\t105,\n\t112,\n\t111,\n\t116,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t111,\n\t117,\n\t116,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t98,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t119,\n\t104,\n\t97,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t110,\n\t111,\n\t119,\n\t115,\n\t105,\n\t116,\n\t117,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t84,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t84,\n\t114,\n\t97,\n\t110,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t111,\n\t102,\n\t97,\n\t116,\n\t109,\n\t111,\n\t115,\n\t112,\n\t104,\n\t101,\n\t114,\n\t105,\n\t99,\n\t105,\n\t100,\n\t101,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t105,\n\t115,\n\t101,\n\t115,\n\t99,\n\t97,\n\t108,\n\t99,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t101,\n\t97,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t109,\n\t110,\n\t97,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t112,\n\t108,\n\t117,\n\t103,\n\t105,\n\t110,\n\t115,\n\t112,\n\t97,\n\t103,\n\t101,\n\t47,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t112,\n\t104,\n\t112,\n\t63,\n\t114,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t100,\n\t72,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t108,\n\t114,\n\t101,\n\t97,\n\t100,\n\t121,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t105,\n\t110,\n\t32,\n\t102,\n\t97,\n\t118,\n\t111,\n\t114,\n\t32,\n\t111,\n\t102,\n\t77,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t102,\n\t111,\n\t114,\n\t109,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t115,\n\t32,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t100,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t105,\n\t122,\n\t101,\n\t100,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t97,\n\t114,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t97,\n\t110,\n\t100,\n\t32,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t109,\n\t97,\n\t100,\n\t101,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t101,\n\t109,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t108,\n\t105,\n\t107,\n\t101,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t80,\n\t97,\n\t108,\n\t101,\n\t115,\n\t116,\n\t105,\n\t110,\n\t105,\n\t97,\n\t110,\n\t110,\n\t97,\n\t109,\n\t101,\n\t100,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t105,\n\t116,\n\t32,\n\t104,\n\t97,\n\t100,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t116,\n\t111,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t32,\n\t116,\n\t111,\n\t98,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t105,\n\t115,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t99,\n\t117,\n\t116,\n\t105,\n\t118,\n\t101,\n\t116,\n\t101,\n\t109,\n\t112,\n\t111,\n\t114,\n\t97,\n\t114,\n\t105,\n\t108,\n\t121,\n\t73,\n\t110,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t44,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t97,\n\t107,\n\t101,\n\t115,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t115,\n\t117,\n\t98,\n\t100,\n\t105,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t116,\n\t101,\n\t114,\n\t114,\n\t105,\n\t116,\n\t111,\n\t114,\n\t105,\n\t97,\n\t108,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t112,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t119,\n\t97,\n\t115,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t108,\n\t121,\n\t111,\n\t117,\n\t116,\n\t98,\n\t114,\n\t101,\n\t97,\n\t107,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t97,\n\t115,\n\t116,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t97,\n\t32,\n\t120,\n\t109,\n\t108,\n\t110,\n\t115,\n\t58,\n\t111,\n\t103,\n\t61,\n\t34,\n\t62,\n\t60,\n\t97,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t67,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t109,\n\t97,\n\t121,\n\t32,\n\t98,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t109,\n\t97,\n\t110,\n\t117,\n\t102,\n\t97,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t98,\n\t101,\n\t105,\n\t110,\n\t103,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t102,\n\t105,\n\t120,\n\t34,\n\t62,\n\t10,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t119,\n\t97,\n\t115,\n\t32,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t99,\n\t111,\n\t109,\n\t101,\n\t32,\n\t97,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t105,\n\t110,\n\t115,\n\t112,\n\t105,\n\t114,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t102,\n\t117,\n\t108,\n\t32,\n\t97,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t32,\n\t119,\n\t104,\n\t101,\n\t110,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t97,\n\t109,\n\t111,\n\t110,\n\t103,\n\t115,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t32,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t49,\n\t48,\n\t48,\n\t37,\n\t59,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t111,\n\t108,\n\t111,\n\t103,\n\t121,\n\t44,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t100,\n\t111,\n\t112,\n\t116,\n\t101,\n\t100,\n\t116,\n\t111,\n\t32,\n\t107,\n\t101,\n\t101,\n\t112,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t116,\n\t116,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t108,\n\t105,\n\t118,\n\t101,\n\t32,\n\t98,\n\t105,\n\t114,\n\t116,\n\t104,\n\t115,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t67,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t105,\n\t99,\n\t117,\n\t116,\n\t97,\n\t115,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t59,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t32,\n\t102,\n\t111,\n\t114,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t121,\n\t97,\n\t108,\n\t119,\n\t97,\n\t121,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t66,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t113,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t97,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t32,\n\t111,\n\t102,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t34,\n\t32,\n\t47,\n\t62,\n\t105,\n\t115,\n\t32,\n\t97,\n\t99,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t69,\n\t110,\n\t118,\n\t105,\n\t114,\n\t111,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t13,\n\t10,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t13,\n\t10,\n\t67,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t115,\n\t101,\n\t108,\n\t121,\n\t44,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t105,\n\t115,\n\t32,\n\t112,\n\t114,\n\t111,\n\t98,\n\t97,\n\t98,\n\t108,\n\t121,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t99,\n\t111,\n\t109,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t99,\n\t105,\n\t116,\n\t105,\n\t122,\n\t101,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t105,\n\t97,\n\t110,\n\t115,\n\t114,\n\t101,\n\t97,\n\t99,\n\t104,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t32,\n\t101,\n\t97,\n\t114,\n\t108,\n\t121,\n\t32,\n\t97,\n\t115,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t32,\n\t111,\n\t118,\n\t101,\n\t114,\n\t60,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t118,\n\t97,\n\t108,\n\t105,\n\t100,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t108,\n\t121,\n\t32,\n\t116,\n\t111,\n\t111,\n\t110,\n\t109,\n\t111,\n\t117,\n\t115,\n\t101,\n\t100,\n\t111,\n\t119,\n\t110,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t119,\n\t104,\n\t101,\n\t110,\n\t32,\n\t105,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t97,\n\t99,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t100,\n\t97,\n\t116,\n\t101,\n\t97,\n\t108,\n\t111,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t73,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t97,\n\t116,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t100,\n\t101,\n\t108,\n\t105,\n\t99,\n\t105,\n\t111,\n\t117,\n\t115,\n\t34,\n\t62,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t105,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t97,\n\t114,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t102,\n\t105,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t97,\n\t32,\n\t109,\n\t97,\n\t116,\n\t116,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t13,\n\t10,\n\t9,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t13,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t102,\n\t97,\n\t115,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t116,\n\t111,\n\t32,\n\t109,\n\t97,\n\t105,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t105,\n\t109,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t119,\n\t97,\n\t114,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t114,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t114,\n\t101,\n\t115,\n\t116,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t97,\n\t109,\n\t101,\n\t97,\n\t110,\n\t97,\n\t108,\n\t121,\n\t115,\n\t105,\n\t115,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t105,\n\t114,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t68,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t123,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t32,\n\t119,\n\t111,\n\t114,\n\t107,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t115,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t58,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t101,\n\t110,\n\t116,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t101,\n\t113,\n\t117,\n\t105,\n\t108,\n\t105,\n\t98,\n\t114,\n\t105,\n\t117,\n\t109,\n\t97,\n\t115,\n\t115,\n\t117,\n\t109,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t115,\n\t32,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t32,\n\t98,\n\t121,\n\t110,\n\t101,\n\t101,\n\t100,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t99,\n\t111,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t118,\n\t97,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t97,\n\t114,\n\t101,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t115,\n\t32,\n\t97,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t105,\n\t101,\n\t115,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t100,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t114,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t32,\n\t111,\n\t102,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t105,\n\t110,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t45,\n\t100,\n\t97,\n\t121,\n\t117,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t97,\n\t108,\n\t108,\n\t121,\n\t116,\n\t111,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t117,\n\t116,\n\t32,\n\t105,\n\t110,\n\t115,\n\t116,\n\t101,\n\t97,\n\t100,\n\t99,\n\t111,\n\t114,\n\t112,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t104,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t105,\n\t115,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t108,\n\t121,\n\t114,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t109,\n\t97,\n\t100,\n\t101,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t109,\n\t101,\n\t97,\n\t110,\n\t115,\n\t98,\n\t117,\n\t116,\n\t32,\n\t100,\n\t105,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t111,\n\t110,\n\t77,\n\t111,\n\t117,\n\t115,\n\t101,\n\t79,\n\t118,\n\t101,\n\t114,\n\t97,\n\t115,\n\t32,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t99,\n\t111,\n\t109,\n\t105,\n\t110,\n\t103,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t105,\n\t109,\n\t97,\n\t114,\n\t121,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t102,\n\t111,\n\t114,\n\t32,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t97,\n\t32,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t32,\n\t111,\n\t102,\n\t97,\n\t114,\n\t101,\n\t32,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t104,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t105,\n\t116,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t109,\n\t117,\n\t99,\n\t104,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t114,\n\t10,\n\t9,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t97,\n\t100,\n\t111,\n\t112,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t119,\n\t97,\n\t115,\n\t32,\n\t98,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t99,\n\t104,\n\t105,\n\t108,\n\t100,\n\t114,\n\t101,\n\t110,\n\t32,\n\t111,\n\t102,\n\t80,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t105,\n\t110,\n\t103,\n\t108,\n\t111,\n\t110,\n\t103,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t109,\n\t97,\n\t110,\n\t117,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t115,\n\t119,\n\t97,\n\t114,\n\t32,\n\t97,\n\t103,\n\t97,\n\t105,\n\t110,\n\t115,\n\t116,\n\t98,\n\t121,\n\t32,\n\t109,\n\t101,\n\t97,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t100,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t112,\n\t114,\n\t111,\n\t112,\n\t114,\n\t105,\n\t101,\n\t116,\n\t97,\n\t114,\n\t121,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t101,\n\t115,\n\t116,\n\t105,\n\t103,\n\t105,\n\t111,\n\t117,\n\t115,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t46,\n\t116,\n\t111,\n\t32,\n\t109,\n\t97,\n\t107,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t73,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t105,\n\t115,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t105,\n\t110,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t116,\n\t105,\n\t116,\n\t111,\n\t114,\n\t115,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t85,\n\t46,\n\t83,\n\t46,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t97,\n\t108,\n\t99,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t97,\n\t108,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t105,\n\t110,\n\t32,\n\t104,\n\t111,\n\t110,\n\t111,\n\t114,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t97,\n\t110,\n\t100,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t49,\n\t115,\n\t116,\n\t32,\n\t69,\n\t97,\n\t114,\n\t108,\n\t32,\n\t111,\n\t102,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t97,\n\t110,\n\t100,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t97,\n\t108,\n\t108,\n\t121,\n\t60,\n\t47,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t10,\n\t32,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t98,\n\t97,\n\t99,\n\t107,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t104,\n\t105,\n\t115,\n\t101,\n\t120,\n\t112,\n\t111,\n\t115,\n\t117,\n\t114,\n\t101,\n\t32,\n\t116,\n\t111,\n\t97,\n\t114,\n\t101,\n\t32,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t100,\n\t100,\n\t70,\n\t97,\n\t118,\n\t111,\n\t114,\n\t105,\n\t116,\n\t101,\n\t99,\n\t105,\n\t116,\n\t105,\n\t122,\n\t101,\n\t110,\n\t115,\n\t104,\n\t105,\n\t112,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t110,\n\t32,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t101,\n\t116,\n\t111,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t109,\n\t105,\n\t110,\n\t117,\n\t115,\n\t59,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t32,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t103,\n\t112,\n\t108,\n\t97,\n\t121,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t105,\n\t110,\n\t32,\n\t104,\n\t105,\n\t115,\n\t32,\n\t98,\n\t111,\n\t111,\n\t107,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t97,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t105,\n\t110,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t105,\n\t115,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t100,\n\t101,\n\t97,\n\t32,\n\t111,\n\t102,\n\t97,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t100,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t98,\n\t116,\n\t110,\n\t100,\n\t97,\n\t121,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t101,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t115,\n\t104,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t32,\n\t105,\n\t110,\n\t105,\n\t110,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t104,\n\t101,\n\t97,\n\t100,\n\t32,\n\t111,\n\t102,\n\t76,\n\t111,\n\t114,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t104,\n\t97,\n\t115,\n\t32,\n\t105,\n\t116,\n\t115,\n\t32,\n\t111,\n\t119,\n\t110,\n\t69,\n\t100,\n\t117,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t118,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t97,\n\t99,\n\t104,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t44,\n\t98,\n\t101,\n\t104,\n\t97,\n\t118,\n\t105,\n\t111,\n\t114,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t100,\n\t32,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t97,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t114,\n\t101,\n\t99,\n\t111,\n\t114,\n\t100,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t98,\n\t108,\n\t97,\n\t99,\n\t107,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t109,\n\t97,\n\t121,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t39,\n\t115,\n\t99,\n\t97,\n\t110,\n\t32,\n\t108,\n\t101,\n\t97,\n\t100,\n\t32,\n\t116,\n\t111,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t97,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t119,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t119,\n\t104,\n\t105,\n\t108,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t87,\n\t97,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t116,\n\t111,\n\t110,\n\t44,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t117,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t99,\n\t105,\n\t116,\n\t121,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t9,\n\t9,\n\t114,\n\t101,\n\t102,\n\t108,\n\t101,\n\t99,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t111,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t114,\n\t97,\n\t100,\n\t105,\n\t111,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t114,\n\t101,\n\t106,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t119,\n\t105,\n\t116,\n\t104,\n\t111,\n\t117,\n\t116,\n\t32,\n\t97,\n\t110,\n\t121,\n\t104,\n\t105,\n\t115,\n\t32,\n\t102,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t44,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t99,\n\t111,\n\t117,\n\t108,\n\t100,\n\t99,\n\t111,\n\t112,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t111,\n\t32,\n\t105,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t97,\n\t32,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t101,\n\t115,\n\t119,\n\t111,\n\t114,\n\t107,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t101,\n\t114,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t111,\n\t102,\n\t32,\n\t104,\n\t105,\n\t115,\n\t32,\n\t108,\n\t105,\n\t102,\n\t101,\n\t97,\n\t99,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t105,\n\t101,\n\t100,\n\t99,\n\t108,\n\t105,\n\t101,\n\t110,\n\t116,\n\t87,\n\t105,\n\t100,\n\t116,\n\t104,\n\t112,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t76,\n\t101,\n\t103,\n\t105,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t116,\n\t111,\n\t103,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t105,\n\t110,\n\t104,\n\t97,\n\t115,\n\t32,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t102,\n\t111,\n\t114,\n\t32,\n\t97,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t116,\n\t101,\n\t120,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t117,\n\t115,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t32,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t62,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t34,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t109,\n\t115,\n\t101,\n\t108,\n\t118,\n\t101,\n\t115,\n\t44,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t104,\n\t101,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t114,\n\t111,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t32,\n\t97,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t101,\n\t67,\n\t104,\n\t105,\n\t108,\n\t100,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t119,\n\t101,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t83,\n\t111,\n\t109,\n\t101,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t44,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t110,\n\t101,\n\t119,\n\t115,\n\t108,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t115,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t111,\n\t119,\n\t110,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t108,\n\t105,\n\t118,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t115,\n\t32,\n\t116,\n\t111,\n\t111,\n\t117,\n\t116,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t105,\n\t101,\n\t115,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t105,\n\t110,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t101,\n\t114,\n\t115,\n\t97,\n\t116,\n\t32,\n\t108,\n\t101,\n\t97,\n\t115,\n\t116,\n\t32,\n\t105,\n\t110,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t120,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t105,\n\t116,\n\t119,\n\t97,\n\t115,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t100,\n\t32,\n\t118,\n\t97,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t71,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t111,\n\t114,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t121,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t119,\n\t105,\n\t100,\n\t101,\n\t108,\n\t121,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t97,\n\t110,\n\t100,\n\t32,\n\t112,\n\t101,\n\t114,\n\t104,\n\t97,\n\t112,\n\t115,\n\t114,\n\t105,\n\t115,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t99,\n\t99,\n\t117,\n\t114,\n\t115,\n\t32,\n\t119,\n\t104,\n\t101,\n\t110,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t99,\n\t111,\n\t110,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t46,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t101,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t121,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t115,\n\t32,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t104,\n\t101,\n\t115,\n\t101,\n\t101,\n\t110,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t108,\n\t98,\n\t117,\n\t105,\n\t108,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t104,\n\t105,\n\t115,\n\t97,\n\t114,\n\t101,\n\t97,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t110,\n\t108,\n\t121,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t87,\n\t101,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t84,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t110,\n\t111,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t83,\n\t116,\n\t97,\n\t116,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t99,\n\t111,\n\t108,\n\t115,\n\t112,\n\t97,\n\t110,\n\t61,\n\t50,\n\t32,\n\t124,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t32,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t116,\n\t111,\n\t112,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t99,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t97,\n\t32,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t105,\n\t97,\n\t110,\n\t100,\n\t101,\n\t99,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t105,\n\t115,\n\t32,\n\t101,\n\t113,\n\t117,\n\t97,\n\t108,\n\t32,\n\t116,\n\t111,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t115,\n\t32,\n\t111,\n\t102,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t109,\n\t101,\n\t114,\n\t99,\n\t104,\n\t97,\n\t110,\n\t100,\n\t105,\n\t115,\n\t101,\n\t102,\n\t111,\n\t114,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t110,\n\t111,\n\t32,\n\t101,\n\t118,\n\t105,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t101,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t101,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t105,\n\t110,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t46,\n\t32,\n\t84,\n\t104,\n\t101,\n\t99,\n\t111,\n\t109,\n\t47,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t115,\n\t47,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t109,\n\t97,\n\t107,\n\t101,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t114,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t108,\n\t105,\n\t116,\n\t101,\n\t114,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t44,\n\t105,\n\t115,\n\t32,\n\t97,\n\t32,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t110,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t115,\n\t32,\n\t105,\n\t110,\n\t116,\n\t105,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t101,\n\t102,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t32,\n\t102,\n\t101,\n\t119,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t109,\n\t117,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t114,\n\t107,\n\t32,\n\t111,\n\t102,\n\t67,\n\t97,\n\t108,\n\t105,\n\t102,\n\t111,\n\t114,\n\t110,\n\t105,\n\t97,\n\t44,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t32,\n\t97,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t112,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t105,\n\t110,\n\t9,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t105,\n\t116,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t97,\n\t114,\n\t101,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t120,\n\t112,\n\t108,\n\t97,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t108,\n\t101,\n\t97,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t9,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t119,\n\t97,\n\t115,\n\t32,\n\t103,\n\t114,\n\t97,\n\t110,\n\t116,\n\t101,\n\t100,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t119,\n\t97,\n\t115,\n\t32,\n\t115,\n\t101,\n\t101,\n\t110,\n\t32,\n\t97,\n\t115,\n\t97,\n\t110,\n\t100,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t111,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t101,\n\t115,\n\t116,\n\t101,\n\t97,\n\t99,\n\t104,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t46,\n\t67,\n\t111,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t110,\n\t101,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t100,\n\t105,\n\t97,\n\t108,\n\t101,\n\t99,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t116,\n\t111,\n\t32,\n\t114,\n\t101,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t119,\n\t97,\n\t115,\n\t32,\n\t114,\n\t101,\n\t110,\n\t97,\n\t109,\n\t101,\n\t100,\n\t97,\n\t32,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t97,\n\t117,\n\t110,\n\t99,\n\t104,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t101,\n\t115,\n\t116,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t32,\n\t116,\n\t119,\n\t111,\n\t105,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t97,\n\t110,\n\t100,\n\t99,\n\t111,\n\t110,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t44,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t105,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t116,\n\t104,\n\t101,\n\t109,\n\t115,\n\t101,\n\t108,\n\t118,\n\t101,\n\t115,\n\t46,\n\t113,\n\t117,\n\t97,\n\t110,\n\t116,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t114,\n\t97,\n\t110,\n\t115,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t99,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t97,\n\t109,\n\t101,\n\t32,\n\t97,\n\t115,\n\t116,\n\t111,\n\t32,\n\t106,\n\t111,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t121,\n\t32,\n\t97,\n\t110,\n\t100,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t97,\n\t32,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t115,\n\t116,\n\t32,\n\t116,\n\t111,\n\t108,\n\t97,\n\t115,\n\t116,\n\t73,\n\t110,\n\t100,\n\t101,\n\t120,\n\t79,\n\t102,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t104,\n\t105,\n\t115,\n\t105,\n\t115,\n\t32,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t101,\n\t114,\n\t109,\n\t32,\n\t105,\n\t115,\n\t105,\n\t115,\n\t32,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t110,\n\t103,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t84,\n\t104,\n\t101,\n\t32,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t105,\n\t116,\n\t101,\n\t32,\n\t111,\n\t102,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t44,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t87,\n\t101,\n\t115,\n\t116,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t115,\n\t108,\n\t111,\n\t118,\n\t101,\n\t110,\n\t196,\n\t141,\n\t105,\n\t110,\n\t97,\n\t99,\n\t111,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t105,\n\t111,\n\t115,\n\t117,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t100,\n\t97,\n\t100,\n\t99,\n\t111,\n\t110,\n\t100,\n\t105,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t97,\n\t99,\n\t116,\n\t105,\n\t118,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t116,\n\t101,\n\t99,\n\t110,\n\t111,\n\t108,\n\t111,\n\t103,\n\t195,\n\t173,\n\t97,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t112,\n\t117,\n\t110,\n\t116,\n\t117,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t97,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t115,\n\t101,\n\t195,\n\t177,\n\t97,\n\t99,\n\t97,\n\t116,\n\t101,\n\t103,\n\t111,\n\t114,\n\t195,\n\t173,\n\t97,\n\t115,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t114,\n\t115,\n\t101,\n\t112,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t116,\n\t114,\n\t97,\n\t116,\n\t97,\n\t109,\n\t105,\n\t101,\n\t110,\n\t116,\n\t111,\n\t114,\n\t101,\n\t103,\n\t195,\n\t173,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t115,\n\t101,\n\t99,\n\t114,\n\t101,\n\t116,\n\t97,\n\t114,\n\t195,\n\t173,\n\t97,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t97,\n\t108,\n\t101,\n\t115,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t101,\n\t115,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t99,\n\t105,\n\t97,\n\t112,\n\t111,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t100,\n\t97,\n\t100,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t97,\n\t110,\n\t116,\n\t101,\n\t99,\n\t114,\n\t101,\n\t99,\n\t105,\n\t109,\n\t105,\n\t101,\n\t110,\n\t116,\n\t111,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t115,\n\t117,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t105,\n\t114,\n\t115,\n\t101,\n\t97,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t100,\n\t105,\n\t115,\n\t112,\n\t111,\n\t110,\n\t105,\n\t98,\n\t108,\n\t101,\n\t115,\n\t101,\n\t118,\n\t97,\n\t108,\n\t117,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t101,\n\t115,\n\t116,\n\t117,\n\t100,\n\t105,\n\t97,\n\t110,\n\t116,\n\t101,\n\t115,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t97,\n\t98,\n\t108,\n\t101,\n\t114,\n\t101,\n\t115,\n\t111,\n\t108,\n\t117,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t103,\n\t117,\n\t97,\n\t100,\n\t97,\n\t108,\n\t97,\n\t106,\n\t97,\n\t114,\n\t97,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t100,\n\t111,\n\t115,\n\t111,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t110,\n\t105,\n\t100,\n\t97,\n\t100,\n\t99,\n\t111,\n\t109,\n\t101,\n\t114,\n\t99,\n\t105,\n\t97,\n\t108,\n\t101,\n\t115,\n\t102,\n\t111,\n\t116,\n\t111,\n\t103,\n\t114,\n\t97,\n\t102,\n\t195,\n\t173,\n\t97,\n\t97,\n\t117,\n\t116,\n\t111,\n\t114,\n\t105,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t105,\n\t110,\n\t103,\n\t101,\n\t110,\n\t105,\n\t101,\n\t114,\n\t195,\n\t173,\n\t97,\n\t116,\n\t101,\n\t108,\n\t101,\n\t118,\n\t105,\n\t115,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t116,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t99,\n\t105,\n\t100,\n\t111,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t97,\n\t99,\n\t116,\n\t117,\n\t97,\n\t108,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t110,\n\t97,\n\t118,\n\t101,\n\t103,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t111,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t105,\n\t100,\n\t97,\n\t100,\n\t108,\n\t105,\n\t110,\n\t101,\n\t45,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t121,\n\t58,\n\t34,\n\t32,\n\t58,\n\t32,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t108,\n\t105,\n\t110,\n\t107,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t47,\n\t47,\n\t60,\n\t33,\n\t91,\n\t67,\n\t68,\n\t65,\n\t84,\n\t65,\n\t91,\n\t10,\n\t79,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t105,\n\t115,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t48,\n\t112,\n\t120,\n\t59,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t105,\n\t112,\n\t100,\n\t101,\n\t118,\n\t105,\n\t99,\n\t101,\n\t45,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t108,\n\t97,\n\t98,\n\t101,\n\t108,\n\t32,\n\t102,\n\t111,\n\t114,\n\t61,\n\t34,\n\t114,\n\t101,\n\t103,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t60,\n\t47,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t47,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t46,\n\t111,\n\t112,\n\t101,\n\t110,\n\t40,\n\t32,\n\t33,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t59,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t47,\n\t105,\n\t110,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t103,\n\t111,\n\t111,\n\t103,\n\t108,\n\t101,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t117,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t114,\n\t118,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t60,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t105,\n\t110,\n\t116,\n\t101,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t117,\n\t97,\n\t108,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t108,\n\t101,\n\t102,\n\t116,\n\t58,\n\t49,\n\t56,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t97,\n\t110,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t97,\n\t98,\n\t98,\n\t114,\n\t101,\n\t118,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t115,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t105,\n\t118,\n\t105,\n\t108,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t49,\n\t57,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t97,\n\t114,\n\t99,\n\t104,\n\t105,\n\t116,\n\t101,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t105,\n\t110,\n\t99,\n\t111,\n\t114,\n\t112,\n\t111,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t50,\n\t48,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t45,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t114,\n\t34,\n\t62,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t110,\n\t111,\n\t116,\n\t97,\n\t98,\n\t108,\n\t121,\n\t47,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t110,\n\t111,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t39,\n\t117,\n\t110,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t39,\n\t41,\n\t70,\n\t117,\n\t114,\n\t116,\n\t104,\n\t101,\n\t114,\n\t109,\n\t111,\n\t114,\n\t101,\n\t44,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t110,\n\t110,\n\t101,\n\t114,\n\t72,\n\t84,\n\t77,\n\t76,\n\t32,\n\t61,\n\t32,\n\t112,\n\t114,\n\t105,\n\t111,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t114,\n\t97,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t110,\n\t101,\n\t103,\n\t111,\n\t116,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t101,\n\t97,\n\t100,\n\t113,\n\t117,\n\t97,\n\t114,\n\t116,\n\t101,\n\t114,\n\t115,\n\t83,\n\t111,\n\t117,\n\t116,\n\t104,\n\t32,\n\t65,\n\t102,\n\t114,\n\t105,\n\t99,\n\t97,\n\t117,\n\t110,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t102,\n\t117,\n\t108,\n\t80,\n\t101,\n\t110,\n\t110,\n\t115,\n\t121,\n\t108,\n\t118,\n\t97,\n\t110,\n\t105,\n\t97,\n\t65,\n\t115,\n\t32,\n\t97,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t44,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t61,\n\t34,\n\t38,\n\t108,\n\t116,\n\t59,\n\t47,\n\t115,\n\t117,\n\t112,\n\t38,\n\t103,\n\t116,\n\t59,\n\t100,\n\t101,\n\t97,\n\t108,\n\t105,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t112,\n\t104,\n\t105,\n\t108,\n\t97,\n\t100,\n\t101,\n\t108,\n\t112,\n\t104,\n\t105,\n\t97,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t41,\n\t59,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t45,\n\t116,\n\t111,\n\t112,\n\t58,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t103,\n\t101,\n\t116,\n\t65,\n\t116,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t105,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t101,\n\t115,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t61,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t123,\n\t115,\n\t117,\n\t98,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t108,\n\t46,\n\t100,\n\t116,\n\t100,\n\t34,\n\t62,\n\t13,\n\t10,\n\t60,\n\t104,\n\t116,\n\t103,\n\t101,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t105,\n\t99,\n\t97,\n\t108,\n\t67,\n\t111,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t39,\n\t44,\n\t32,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t103,\n\t114,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t32,\n\t49,\n\t97,\n\t32,\n\t118,\n\t97,\n\t114,\n\t105,\n\t101,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t69,\n\t110,\n\t99,\n\t121,\n\t99,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t105,\n\t97,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t100,\n\t101,\n\t109,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t97,\n\t99,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t117,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t68,\n\t101,\n\t109,\n\t111,\n\t103,\n\t114,\n\t97,\n\t112,\n\t104,\n\t105,\n\t99,\n\t115,\n\t41,\n\t59,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t100,\n\t101,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t107,\n\t110,\n\t111,\n\t119,\n\t108,\n\t101,\n\t100,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t115,\n\t97,\n\t116,\n\t105,\n\t115,\n\t102,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t40,\n\t85,\n\t83,\n\t41,\n\t97,\n\t112,\n\t112,\n\t101,\n\t110,\n\t100,\n\t67,\n\t104,\n\t105,\n\t108,\n\t100,\n\t40,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t46,\n\t32,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t105,\n\t110,\n\t116,\n\t101,\n\t108,\n\t108,\n\t105,\n\t103,\n\t101,\n\t110,\n\t99,\n\t101,\n\t34,\n\t32,\n\t116,\n\t97,\n\t98,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t61,\n\t34,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t59,\n\t67,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t119,\n\t101,\n\t97,\n\t108,\n\t116,\n\t104,\n\t114,\n\t97,\n\t110,\n\t103,\n\t105,\n\t110,\n\t103,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t105,\n\t110,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t116,\n\t32,\n\t108,\n\t101,\n\t97,\n\t115,\n\t116,\n\t32,\n\t111,\n\t110,\n\t101,\n\t114,\n\t101,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t110,\n\t99,\n\t121,\n\t99,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t105,\n\t97,\n\t59,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t49,\n\t106,\n\t117,\n\t114,\n\t105,\n\t115,\n\t100,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t34,\n\t62,\n\t60,\n\t97,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t73,\n\t110,\n\t32,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t44,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t43,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t115,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t99,\n\t116,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t121,\n\t114,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t110,\n\t103,\n\t38,\n\t108,\n\t116,\n\t59,\n\t109,\n\t97,\n\t116,\n\t104,\n\t38,\n\t103,\n\t116,\n\t59,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t99,\n\t99,\n\t97,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t110,\n\t97,\n\t118,\n\t105,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t34,\n\t62,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t110,\n\t115,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t104,\n\t97,\n\t109,\n\t112,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t105,\n\t112,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t61,\n\t34,\n\t97,\n\t108,\n\t108,\n\t34,\n\t32,\n\t118,\n\t105,\n\t111,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t111,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t116,\n\t114,\n\t117,\n\t101,\n\t59,\n\t83,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t47,\n\t47,\n\t69,\n\t78,\n\t34,\n\t32,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t73,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t105,\n\t101,\n\t115,\n\t67,\n\t104,\n\t97,\n\t109,\n\t112,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t105,\n\t112,\n\t99,\n\t97,\n\t112,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t60,\n\t33,\n\t91,\n\t101,\n\t110,\n\t100,\n\t105,\n\t102,\n\t93,\n\t45,\n\t45,\n\t62,\n\t125,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t105,\n\t97,\n\t110,\n\t105,\n\t116,\n\t121,\n\t102,\n\t111,\n\t114,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t44,\n\t80,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t114,\n\t101,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t119,\n\t97,\n\t115,\n\t32,\n\t114,\n\t101,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t100,\n\t40,\n\t115,\n\t117,\n\t99,\n\t104,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t101,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t40,\n\t117,\n\t110,\n\t101,\n\t109,\n\t112,\n\t108,\n\t111,\n\t121,\n\t109,\n\t101,\n\t110,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t47,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t34,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t101,\n\t108,\n\t111,\n\t110,\n\t103,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t71,\n\t117,\n\t105,\n\t100,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t118,\n\t101,\n\t114,\n\t119,\n\t104,\n\t101,\n\t108,\n\t109,\n\t105,\n\t110,\n\t103,\n\t97,\n\t103,\n\t97,\n\t105,\n\t110,\n\t115,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t44,\n\t10,\n\t46,\n\t110,\n\t111,\n\t110,\n\t116,\n\t111,\n\t117,\n\t99,\n\t104,\n\t32,\n\t111,\n\t98,\n\t115,\n\t101,\n\t114,\n\t118,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t60,\n\t47,\n\t97,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t102,\n\t32,\n\t40,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t58,\n\t32,\n\t49,\n\t112,\n\t120,\n\t32,\n\t123,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t49,\n\t116,\n\t114,\n\t101,\n\t97,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t48,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t49,\n\t109,\n\t111,\n\t100,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t73,\n\t110,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t97,\n\t99,\n\t104,\n\t105,\n\t101,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t74,\n\t97,\n\t118,\n\t97,\n\t83,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t32,\n\t110,\n\t101,\n\t118,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t108,\n\t101,\n\t115,\n\t115,\n\t115,\n\t105,\n\t103,\n\t110,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t110,\n\t99,\n\t101,\n\t66,\n\t114,\n\t111,\n\t97,\n\t100,\n\t99,\n\t97,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t62,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t114,\n\t34,\n\t62,\n\t10,\n\t115,\n\t117,\n\t99,\n\t104,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t115,\n\t114,\n\t99,\n\t61,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t110,\n\t97,\n\t118,\n\t105,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t34,\n\t32,\n\t104,\n\t97,\n\t108,\n\t102,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t32,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t97,\n\t100,\n\t118,\n\t97,\n\t110,\n\t116,\n\t97,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t102,\n\t117,\n\t110,\n\t100,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t32,\n\t109,\n\t101,\n\t116,\n\t114,\n\t111,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t97,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t112,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t101,\n\t34,\n\t32,\n\t120,\n\t109,\n\t108,\n\t58,\n\t108,\n\t97,\n\t110,\n\t103,\n\t61,\n\t34,\n\t100,\n\t101,\n\t108,\n\t105,\n\t98,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t118,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t114,\n\t118,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t109,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t74,\n\t101,\n\t115,\n\t117,\n\t115,\n\t32,\n\t67,\n\t104,\n\t114,\n\t105,\n\t115,\n\t116,\n\t80,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t100,\n\t105,\n\t115,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t114,\n\t44,\n\t32,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t105,\n\t115,\n\t32,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t97,\n\t108,\n\t112,\n\t104,\n\t97,\n\t98,\n\t101,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t105,\n\t115,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t47,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t108,\n\t111,\n\t119,\n\t58,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t59,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t105,\n\t110,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t108,\n\t108,\n\t32,\n\t111,\n\t118,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t101,\n\t116,\n\t9,\n\t60,\n\t117,\n\t108,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t108,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t110,\n\t101,\n\t105,\n\t103,\n\t104,\n\t98,\n\t111,\n\t114,\n\t104,\n\t111,\n\t111,\n\t100,\n\t97,\n\t114,\n\t109,\n\t101,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t115,\n\t114,\n\t101,\n\t100,\n\t117,\n\t99,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t115,\n\t32,\n\t116,\n\t111,\n\t78,\n\t111,\n\t110,\n\t101,\n\t116,\n\t104,\n\t101,\n\t108,\n\t101,\n\t115,\n\t115,\n\t44,\n\t116,\n\t101,\n\t109,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t10,\n\t9,\n\t9,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t105,\n\t115,\n\t32,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t40,\n\t115,\n\t101,\n\t101,\n\t32,\n\t98,\n\t101,\n\t108,\n\t111,\n\t119,\n\t41,\n\t46,\n\t34,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t112,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t105,\n\t115,\n\t32,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t9,\n\t9,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t10,\n\t9,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t97,\n\t99,\n\t99,\n\t101,\n\t108,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t72,\n\t97,\n\t108,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t70,\n\t97,\n\t109,\n\t101,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t39,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t123,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t58,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t101,\n\t120,\n\t112,\n\t108,\n\t111,\n\t105,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t109,\n\t101,\n\t114,\n\t103,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t65,\n\t32,\n\t72,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t115,\n\t105,\n\t103,\n\t110,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t110,\n\t116,\n\t32,\n\t109,\n\t97,\n\t110,\n\t117,\n\t102,\n\t97,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t100,\n\t101,\n\t120,\n\t112,\n\t101,\n\t99,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t62,\n\t60,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t110,\n\t101,\n\t105,\n\t103,\n\t104,\n\t98,\n\t111,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t119,\n\t105,\n\t116,\n\t104,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t100,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t9,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t105,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t83,\n\t111,\n\t118,\n\t105,\n\t101,\n\t116,\n\t32,\n\t85,\n\t110,\n\t105,\n\t111,\n\t110,\n\t97,\n\t99,\n\t107,\n\t110,\n\t111,\n\t119,\n\t108,\n\t101,\n\t100,\n\t103,\n\t101,\n\t100,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t110,\n\t97,\n\t109,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t116,\n\t116,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t73,\n\t110,\n\t32,\n\t102,\n\t97,\n\t99,\n\t116,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t97,\n\t105,\n\t109,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t117,\n\t105,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t117,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t108,\n\t111,\n\t110,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t99,\n\t97,\n\t110,\n\t99,\n\t101,\n\t108,\n\t66,\n\t117,\n\t98,\n\t98,\n\t108,\n\t101,\n\t32,\n\t73,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t100,\n\t114,\n\t101,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t111,\n\t114,\n\t32,\n\t108,\n\t101,\n\t115,\n\t115,\n\t105,\n\t110,\n\t32,\n\t83,\n\t101,\n\t112,\n\t116,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t73,\n\t110,\n\t116,\n\t101,\n\t108,\n\t108,\n\t105,\n\t103,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t112,\n\t120,\n\t59,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t32,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t109,\n\t97,\n\t110,\n\t117,\n\t102,\n\t97,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t114,\n\t104,\n\t117,\n\t109,\n\t97,\n\t110,\n\t32,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t114,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t111,\n\t117,\n\t116,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t111,\n\t109,\n\t105,\n\t99,\n\t97,\n\t108,\n\t104,\n\t117,\n\t109,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t105,\n\t110,\n\t103,\n\t115,\n\t110,\n\t97,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t105,\n\t110,\n\t97,\n\t114,\n\t101,\n\t32,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t97,\n\t32,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t32,\n\t119,\n\t104,\n\t111,\n\t101,\n\t120,\n\t112,\n\t97,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t97,\n\t114,\n\t103,\n\t117,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t110,\n\t111,\n\t119,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t73,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t97,\n\t114,\n\t108,\n\t121,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t101,\n\t114,\n\t105,\n\t118,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t83,\n\t99,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t97,\n\t118,\n\t105,\n\t97,\n\t110,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t32,\n\t101,\n\t115,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t78,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t112,\n\t97,\n\t103,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t99,\n\t111,\n\t109,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t101,\n\t100,\n\t97,\n\t110,\n\t97,\n\t108,\n\t111,\n\t103,\n\t111,\n\t117,\n\t115,\n\t32,\n\t116,\n\t111,\n\t97,\n\t114,\n\t101,\n\t32,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t100,\n\t47,\n\t117,\n\t108,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t119,\n\t97,\n\t115,\n\t32,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t97,\n\t110,\n\t100,\n\t32,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t97,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t116,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t34,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t99,\n\t97,\n\t112,\n\t116,\n\t117,\n\t114,\n\t101,\n\t100,\n\t110,\n\t111,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t114,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t62,\n\t13,\n\t10,\n\t60,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t13,\n\t10,\n\t60,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t73,\n\t109,\n\t112,\n\t101,\n\t114,\n\t105,\n\t97,\n\t108,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t110,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t111,\n\t114,\n\t116,\n\t104,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t67,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t32,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t105,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t120,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t58,\n\t32,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t32,\n\t105,\n\t116,\n\t115,\n\t32,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t105,\n\t110,\n\t116,\n\t111,\n\t32,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t97,\n\t110,\n\t32,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t104,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t97,\n\t114,\n\t101,\n\t32,\n\t110,\n\t111,\n\t116,\n\t114,\n\t101,\n\t106,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t105,\n\t115,\n\t109,\n\t32,\n\t111,\n\t102,\n\t100,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t112,\n\t114,\n\t111,\n\t98,\n\t97,\n\t98,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t123,\n\t73,\n\t116,\n\t32,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t97,\n\t110,\n\t32,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t99,\n\t99,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t108,\n\t121,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t115,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t65,\n\t114,\n\t99,\n\t104,\n\t105,\n\t116,\n\t101,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t98,\n\t101,\n\t116,\n\t116,\n\t101,\n\t114,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t97,\n\t114,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t110,\n\t97,\n\t116,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t116,\n\t111,\n\t115,\n\t111,\n\t117,\n\t116,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t97,\n\t115,\n\t115,\n\t32,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t120,\n\t109,\n\t108,\n\t34,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t119,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t98,\n\t111,\n\t108,\n\t100,\n\t59,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t47,\n\t105,\n\t104,\n\t116,\n\t116,\n\t112,\n\t115,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t87,\n\t111,\n\t114,\n\t108,\n\t100,\n\t32,\n\t87,\n\t97,\n\t114,\n\t32,\n\t73,\n\t73,\n\t116,\n\t101,\n\t115,\n\t116,\n\t105,\n\t109,\n\t111,\n\t110,\n\t105,\n\t97,\n\t108,\n\t115,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t115,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t97,\n\t98,\n\t108,\n\t121,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t67,\n\t111,\n\t110,\n\t115,\n\t101,\n\t114,\n\t118,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t115,\n\t116,\n\t101,\n\t100,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t97,\n\t99,\n\t107,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t61,\n\t34,\n\t80,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t111,\n\t110,\n\t112,\n\t114,\n\t111,\n\t118,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t34,\n\t119,\n\t97,\n\t115,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t118,\n\t97,\n\t114,\n\t105,\n\t101,\n\t116,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t108,\n\t105,\n\t107,\n\t101,\n\t108,\n\t121,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t105,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t102,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t104,\n\t97,\n\t110,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t117,\n\t112,\n\t108,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t112,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t32,\n\t98,\n\t101,\n\t105,\n\t110,\n\t103,\n\t108,\n\t97,\n\t116,\n\t101,\n\t114,\n\t32,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t99,\n\t97,\n\t108,\n\t99,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t109,\n\t101,\n\t97,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t62,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t101,\n\t118,\n\t105,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t101,\n\t120,\n\t112,\n\t108,\n\t97,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t110,\n\t118,\n\t105,\n\t114,\n\t111,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t115,\n\t73,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t32,\n\t119,\n\t105,\n\t100,\n\t101,\n\t32,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t111,\n\t110,\n\t32,\n\t98,\n\t101,\n\t104,\n\t97,\n\t108,\n\t102,\n\t32,\n\t111,\n\t102,\n\t118,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t116,\n\t111,\n\t112,\n\t34,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t44,\n\t60,\n\t47,\n\t110,\n\t111,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t115,\n\t97,\n\t105,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t119,\n\t104,\n\t105,\n\t108,\n\t101,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t115,\n\t104,\n\t121,\n\t112,\n\t111,\n\t116,\n\t104,\n\t101,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t112,\n\t104,\n\t105,\n\t108,\n\t111,\n\t115,\n\t111,\n\t112,\n\t104,\n\t101,\n\t114,\n\t115,\n\t112,\n\t111,\n\t119,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t112,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t105,\n\t110,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t116,\n\t111,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t119,\n\t114,\n\t105,\n\t116,\n\t116,\n\t101,\n\t110,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t114,\n\t101,\n\t106,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t105,\n\t109,\n\t112,\n\t108,\n\t105,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t97,\n\t114,\n\t100,\n\t119,\n\t97,\n\t115,\n\t32,\n\t112,\n\t114,\n\t111,\n\t98,\n\t97,\n\t98,\n\t108,\n\t121,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t112,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t115,\n\t111,\n\t114,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t73,\n\t110,\n\t100,\n\t105,\n\t97,\n\t110,\n\t32,\n\t79,\n\t99,\n\t101,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t108,\n\t97,\n\t115,\n\t116,\n\t119,\n\t111,\n\t114,\n\t107,\n\t105,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t101,\n\t97,\n\t115,\n\t117,\n\t114,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t97,\n\t110,\n\t32,\n\t101,\n\t120,\n\t116,\n\t114,\n\t101,\n\t109,\n\t101,\n\t108,\n\t121,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t10,\n\t97,\n\t110,\n\t32,\n\t101,\n\t102,\n\t102,\n\t111,\n\t114,\n\t116,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t111,\n\t117,\n\t116,\n\t104,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t62,\n\t115,\n\t117,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t97,\n\t110,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t84,\n\t105,\n\t109,\n\t101,\n\t111,\n\t117,\n\t116,\n\t100,\n\t105,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t101,\n\t120,\n\t116,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t101,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t105,\n\t99,\n\t32,\n\t97,\n\t110,\n\t100,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t114,\n\t101,\n\t32,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t97,\n\t110,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t115,\n\t117,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t101,\n\t120,\n\t112,\n\t101,\n\t110,\n\t100,\n\t105,\n\t116,\n\t117,\n\t114,\n\t101,\n\t115,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t10,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t97,\n\t115,\n\t105,\n\t115,\n\t99,\n\t101,\n\t108,\n\t108,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t61,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t44,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t115,\n\t115,\n\t97,\n\t115,\n\t115,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t115,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t110,\n\t111,\n\t114,\n\t116,\n\t104,\n\t119,\n\t101,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t34,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t32,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t117,\n\t108,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t105,\n\t116,\n\t32,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t110,\n\t116,\n\t115,\n\t32,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t108,\n\t101,\n\t102,\n\t116,\n\t116,\n\t104,\n\t101,\n\t32,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t115,\n\t116,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t115,\n\t117,\n\t112,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t110,\n\t105,\n\t115,\n\t32,\n\t109,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t100,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t97,\n\t115,\n\t32,\n\t105,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t97,\n\t99,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t121,\n\t105,\n\t110,\n\t103,\n\t104,\n\t105,\n\t115,\n\t32,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t97,\n\t116,\n\t115,\n\t116,\n\t117,\n\t100,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t120,\n\t101,\n\t99,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t72,\n\t117,\n\t109,\n\t97,\n\t110,\n\t32,\n\t82,\n\t105,\n\t103,\n\t104,\n\t116,\n\t115,\n\t116,\n\t101,\n\t114,\n\t109,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t114,\n\t101,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t32,\n\t97,\n\t110,\n\t100,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t101,\n\t100,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t100,\n\t101,\n\t102,\n\t101,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t97,\n\t114,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t97,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t97,\n\t103,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t116,\n\t117,\n\t100,\n\t121,\n\t32,\n\t111,\n\t102,\n\t60,\n\t117,\n\t108,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t115,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t104,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t102,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t32,\n\t110,\n\t111,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t104,\n\t101,\n\t32,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t101,\n\t120,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t105,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t101,\n\t114,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t119,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t116,\n\t101,\n\t114,\n\t114,\n\t105,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t101,\n\t120,\n\t116,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t34,\n\t62,\n\t82,\n\t111,\n\t109,\n\t97,\n\t110,\n\t32,\n\t69,\n\t109,\n\t112,\n\t105,\n\t114,\n\t101,\n\t101,\n\t113,\n\t117,\n\t97,\n\t108,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t73,\n\t110,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t115,\n\t116,\n\t44,\n\t104,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t97,\n\t110,\n\t100,\n\t105,\n\t115,\n\t32,\n\t116,\n\t121,\n\t112,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t97,\n\t110,\n\t100,\n\t32,\n\t104,\n\t105,\n\t115,\n\t32,\n\t119,\n\t105,\n\t102,\n\t101,\n\t40,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t62,\n\t60,\n\t117,\n\t108,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t32,\n\t101,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t115,\n\t101,\n\t101,\n\t109,\n\t32,\n\t116,\n\t111,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t110,\n\t111,\n\t97,\n\t110,\n\t32,\n\t101,\n\t120,\n\t99,\n\t101,\n\t108,\n\t108,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t73,\n\t110,\n\t32,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t99,\n\t101,\n\t44,\n\t98,\n\t114,\n\t111,\n\t97,\n\t100,\n\t99,\n\t97,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t99,\n\t104,\n\t97,\n\t114,\n\t103,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t114,\n\t101,\n\t102,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t115,\n\t117,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t109,\n\t105,\n\t108,\n\t105,\n\t116,\n\t97,\n\t114,\n\t121,\n\t32,\n\t97,\n\t110,\n\t100,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t115,\n\t101,\n\t116,\n\t84,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t105,\n\t110,\n\t103,\n\t97,\n\t114,\n\t101,\n\t32,\n\t97,\n\t99,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t118,\n\t105,\n\t99,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t118,\n\t101,\n\t114,\n\t40,\n\t41,\n\t59,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t111,\n\t117,\n\t115,\n\t108,\n\t121,\n\t114,\n\t101,\n\t113,\n\t117,\n\t105,\n\t114,\n\t101,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t101,\n\t118,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t121,\n\t97,\n\t110,\n\t32,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t110,\n\t111,\n\t114,\n\t116,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t44,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t114,\n\t111,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t119,\n\t105,\n\t115,\n\t101,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t111,\n\t102,\n\t104,\n\t97,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t112,\n\t101,\n\t114,\n\t109,\n\t105,\n\t116,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t44,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t101,\n\t118,\n\t105,\n\t111,\n\t117,\n\t115,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t97,\n\t114,\n\t101,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t101,\n\t108,\n\t100,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t32,\n\t111,\n\t102,\n\t103,\n\t105,\n\t118,\n\t101,\n\t110,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t111,\n\t114,\n\t116,\n\t104,\n\t100,\n\t117,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t114,\n\t97,\n\t114,\n\t101,\n\t32,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t99,\n\t111,\n\t114,\n\t112,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t119,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t101,\n\t100,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t105,\n\t110,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t100,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t100,\n\t101,\n\t115,\n\t105,\n\t103,\n\t110,\n\t101,\n\t100,\n\t32,\n\t102,\n\t111,\n\t114,\n\t111,\n\t119,\n\t110,\n\t101,\n\t114,\n\t115,\n\t104,\n\t105,\n\t112,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t100,\n\t32,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t121,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t97,\n\t114,\n\t100,\n\t105,\n\t122,\n\t101,\n\t100,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t101,\n\t84,\n\t101,\n\t120,\n\t116,\n\t119,\n\t97,\n\t115,\n\t32,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t114,\n\t101,\n\t99,\n\t101,\n\t105,\n\t118,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t115,\n\t117,\n\t109,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t114,\n\t101,\n\t97,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t114,\n\t105,\n\t109,\n\t97,\n\t114,\n\t105,\n\t108,\n\t121,\n\t32,\n\t105,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t97,\n\t115,\n\t105,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t101,\n\t110,\n\t115,\n\t101,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t100,\n\t101,\n\t115,\n\t116,\n\t114,\n\t111,\n\t121,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t116,\n\t32,\n\t108,\n\t101,\n\t97,\n\t115,\n\t116,\n\t32,\n\t116,\n\t119,\n\t111,\n\t119,\n\t97,\n\t115,\n\t32,\n\t100,\n\t101,\n\t99,\n\t108,\n\t97,\n\t114,\n\t101,\n\t100,\n\t99,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t83,\n\t101,\n\t99,\n\t114,\n\t101,\n\t116,\n\t97,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t116,\n\t111,\n\t112,\n\t58,\n\t49,\n\t47,\n\t94,\n\t92,\n\t115,\n\t43,\n\t124,\n\t92,\n\t115,\n\t43,\n\t36,\n\t47,\n\t103,\n\t101,\n\t41,\n\t123,\n\t116,\n\t104,\n\t114,\n\t111,\n\t119,\n\t32,\n\t101,\n\t125,\n\t59,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t116,\n\t119,\n\t111,\n\t32,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t101,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t32,\n\t97,\n\t110,\n\t100,\n\t119,\n\t104,\n\t111,\n\t32,\n\t104,\n\t97,\n\t100,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t97,\n\t116,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t97,\n\t108,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t9,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t112,\n\t114,\n\t111,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t109,\n\t112,\n\t101,\n\t116,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t101,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t40,\n\t85,\n\t75,\n\t41,\n\t101,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t40,\n\t85,\n\t83,\n\t41,\n\t208,\n\t156,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t161,\n\t209,\n\t128,\n\t208,\n\t191,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t209,\n\t129,\n\t209,\n\t128,\n\t208,\n\t191,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t209,\n\t129,\n\t209,\n\t128,\n\t208,\n\t191,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t190,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t168,\n\t217,\n\t138,\n\t216,\n\t169,\n\t230,\n\t173,\n\t163,\n\t233,\n\t171,\n\t148,\n\t228,\n\t184,\n\t173,\n\t230,\n\t150,\n\t135,\n\t231,\n\t174,\n\t128,\n\t228,\n\t189,\n\t147,\n\t228,\n\t184,\n\t173,\n\t230,\n\t150,\n\t135,\n\t231,\n\t185,\n\t129,\n\t228,\n\t189,\n\t147,\n\t228,\n\t184,\n\t173,\n\t230,\n\t150,\n\t135,\n\t230,\n\t156,\n\t137,\n\t233,\n\t153,\n\t144,\n\t229,\n\t133,\n\t172,\n\t229,\n\t143,\n\t184,\n\t228,\n\t186,\n\t186,\n\t230,\n\t176,\n\t145,\n\t230,\n\t148,\n\t191,\n\t229,\n\t186,\n\t156,\n\t233,\n\t152,\n\t191,\n\t233,\n\t135,\n\t140,\n\t229,\n\t183,\n\t180,\n\t229,\n\t183,\n\t180,\n\t231,\n\t164,\n\t190,\n\t228,\n\t188,\n\t154,\n\t228,\n\t184,\n\t187,\n\t228,\n\t185,\n\t137,\n\t230,\n\t147,\n\t141,\n\t228,\n\t189,\n\t156,\n\t231,\n\t179,\n\t187,\n\t231,\n\t187,\n\t159,\n\t230,\n\t148,\n\t191,\n\t231,\n\t173,\n\t150,\n\t230,\n\t179,\n\t149,\n\t232,\n\t167,\n\t132,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t104,\n\t101,\n\t114,\n\t114,\n\t97,\n\t109,\n\t105,\n\t101,\n\t110,\n\t116,\n\t97,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t195,\n\t179,\n\t110,\n\t105,\n\t99,\n\t111,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t108,\n\t97,\n\t115,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t100,\n\t111,\n\t115,\n\t99,\n\t111,\n\t110,\n\t111,\n\t99,\n\t105,\n\t109,\n\t105,\n\t101,\n\t110,\n\t116,\n\t111,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t114,\n\t101,\n\t108,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t97,\n\t100,\n\t97,\n\t115,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t195,\n\t161,\n\t116,\n\t105,\n\t99,\n\t97,\n\t114,\n\t101,\n\t108,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t97,\n\t100,\n\t111,\n\t115,\n\t100,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t116,\n\t114,\n\t97,\n\t98,\n\t97,\n\t106,\n\t97,\n\t100,\n\t111,\n\t114,\n\t101,\n\t115,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t101,\n\t97,\n\t121,\n\t117,\n\t110,\n\t116,\n\t97,\n\t109,\n\t105,\n\t101,\n\t110,\n\t116,\n\t111,\n\t109,\n\t101,\n\t114,\n\t99,\n\t97,\n\t100,\n\t111,\n\t76,\n\t105,\n\t98,\n\t114,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t195,\n\t161,\n\t99,\n\t116,\n\t101,\n\t110,\n\t111,\n\t115,\n\t104,\n\t97,\n\t98,\n\t105,\n\t116,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t99,\n\t117,\n\t109,\n\t112,\n\t108,\n\t105,\n\t109,\n\t105,\n\t101,\n\t110,\n\t116,\n\t111,\n\t114,\n\t101,\n\t115,\n\t116,\n\t97,\n\t117,\n\t114,\n\t97,\n\t110,\n\t116,\n\t101,\n\t115,\n\t100,\n\t105,\n\t115,\n\t112,\n\t111,\n\t115,\n\t105,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t99,\n\t117,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t195,\n\t179,\n\t110,\n\t105,\n\t99,\n\t97,\n\t97,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t101,\n\t115,\n\t100,\n\t101,\n\t115,\n\t99,\n\t111,\n\t110,\n\t101,\n\t99,\n\t116,\n\t97,\n\t100,\n\t111,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t108,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t114,\n\t101,\n\t97,\n\t108,\n\t105,\n\t122,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t117,\n\t116,\n\t105,\n\t108,\n\t105,\n\t122,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t101,\n\t110,\n\t99,\n\t105,\n\t99,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t105,\n\t97,\n\t101,\n\t110,\n\t102,\n\t101,\n\t114,\n\t109,\n\t101,\n\t100,\n\t97,\n\t100,\n\t101,\n\t115,\n\t105,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t111,\n\t115,\n\t101,\n\t120,\n\t112,\n\t101,\n\t114,\n\t105,\n\t101,\n\t110,\n\t99,\n\t105,\n\t97,\n\t115,\n\t105,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t101,\n\t115,\n\t115,\n\t117,\n\t98,\n\t99,\n\t97,\n\t116,\n\t101,\n\t103,\n\t111,\n\t114,\n\t105,\n\t97,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t160,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t129,\n\t208,\n\t184,\n\t208,\n\t184,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t177,\n\t208,\n\t190,\n\t209,\n\t130,\n\t209,\n\t139,\n\t208,\n\t177,\n\t208,\n\t190,\n\t208,\n\t187,\n\t209,\n\t140,\n\t209,\n\t136,\n\t208,\n\t181,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t182,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t180,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t179,\n\t208,\n\t184,\n\t209,\n\t133,\n\t209,\n\t129,\n\t208,\n\t187,\n\t209,\n\t131,\n\t209,\n\t135,\n\t208,\n\t176,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t185,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t178,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t160,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t129,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t156,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t178,\n\t208,\n\t181,\n\t208,\n\t180,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t179,\n\t208,\n\t184,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t189,\n\t209,\n\t139,\n\t209,\n\t133,\n\t208,\n\t180,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t182,\n\t208,\n\t189,\n\t209,\n\t139,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t156,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t178,\n\t209,\n\t139,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t177,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t185,\n\t208,\n\t156,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t178,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t189,\n\t209,\n\t139,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t177,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t180,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t182,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t131,\n\t209,\n\t129,\n\t208,\n\t187,\n\t209,\n\t131,\n\t208,\n\t179,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t191,\n\t208,\n\t181,\n\t209,\n\t128,\n\t209,\n\t140,\n\t208,\n\t158,\n\t208,\n\t180,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t131,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t177,\n\t208,\n\t190,\n\t209,\n\t130,\n\t209,\n\t131,\n\t208,\n\t176,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t187,\n\t209,\n\t143,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t137,\n\t208,\n\t181,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t184,\n\t208,\n\t180,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t185,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t133,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t209,\n\t136,\n\t208,\n\t190,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t178,\n\t209,\n\t129,\n\t209,\n\t129,\n\t209,\n\t139,\n\t208,\n\t187,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t182,\n\t208,\n\t180,\n\t209,\n\t139,\n\t208,\n\t185,\n\t208,\n\t178,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t179,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t191,\n\t208,\n\t191,\n\t209,\n\t139,\n\t208,\n\t178,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t177,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t176,\n\t208,\n\t187,\n\t208,\n\t191,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t178,\n\t209,\n\t139,\n\t208,\n\t185,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t140,\n\t208,\n\t179,\n\t208,\n\t184,\n\t208,\n\t191,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t177,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t189,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t130,\n\t208,\n\t186,\n\t209,\n\t131,\n\t208,\n\t191,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t180,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t182,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t133,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t135,\n\t208,\n\t176,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t160,\n\t208,\n\t176,\n\t208,\n\t177,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t162,\n\t208,\n\t190,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t178,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t178,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t135,\n\t208,\n\t176,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t191,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t186,\n\t209,\n\t129,\n\t208,\n\t187,\n\t209,\n\t131,\n\t208,\n\t182,\n\t208,\n\t177,\n\t209,\n\t139,\n\t209,\n\t129,\n\t208,\n\t184,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t191,\n\t208,\n\t181,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t190,\n\t209,\n\t137,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t185,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t131,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t190,\n\t209,\n\t137,\n\t209,\n\t140,\n\t208,\n\t180,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t182,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t129,\n\t209,\n\t139,\n\t208,\n\t187,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t177,\n\t209,\n\t139,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t189,\n\t209,\n\t139,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t184,\n\t208,\n\t181,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t181,\n\t208,\n\t186,\n\t209,\n\t130,\n\t208,\n\t161,\n\t208,\n\t181,\n\t208,\n\t185,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t176,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t187,\n\t208,\n\t176,\n\t208,\n\t185,\n\t208,\n\t189,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t178,\n\t208,\n\t181,\n\t209,\n\t128,\n\t209,\n\t129,\n\t208,\n\t184,\n\t209,\n\t143,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t181,\n\t209,\n\t132,\n\t208,\n\t184,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t188,\n\t209,\n\t139,\n\t209,\n\t131,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t189,\n\t209,\n\t143,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t189,\n\t209,\n\t139,\n\t209,\n\t133,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t187,\n\t209,\n\t142,\n\t209,\n\t143,\n\t208,\n\t189,\n\t208,\n\t178,\n\t208,\n\t176,\n\t209,\n\t128,\n\t209,\n\t143,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t209,\n\t140,\n\t209,\n\t136,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t184,\n\t209,\n\t133,\n\t208,\n\t180,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t183,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t135,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t183,\n\t209,\n\t143,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t128,\n\t209,\n\t131,\n\t208,\n\t188,\n\t208,\n\t176,\n\t208,\n\t162,\n\t208,\n\t181,\n\t208,\n\t191,\n\t208,\n\t181,\n\t209,\n\t128,\n\t209,\n\t140,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t143,\n\t209,\n\t134,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t176,\n\t209,\n\t137,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t139,\n\t208,\n\t155,\n\t209,\n\t131,\n\t209,\n\t135,\n\t209,\n\t136,\n\t208,\n\t184,\n\t208,\n\t181,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t129,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t182,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t152,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t167,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t157,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t163,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t188,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t160,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t152,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t154,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t188,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t152,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t182,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t188,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t188,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t171,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t188,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t188,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t140,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t182,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t216,\n\t170,\n\t216,\n\t179,\n\t216,\n\t170,\n\t216,\n\t183,\n\t217,\n\t138,\n\t216,\n\t185,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t169,\n\t216,\n\t168,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t179,\n\t216,\n\t183,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t181,\n\t217,\n\t129,\n\t216,\n\t173,\n\t216,\n\t169,\n\t217,\n\t133,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t182,\n\t217,\n\t138,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t174,\n\t216,\n\t167,\n\t216,\n\t181,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t178,\n\t217,\n\t138,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t175,\n\t217,\n\t136,\n\t216,\n\t175,\n\t216,\n\t168,\n\t216,\n\t177,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t172,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t217,\n\t136,\n\t217,\n\t132,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t136,\n\t217,\n\t130,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t168,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t179,\n\t216,\n\t177,\n\t217,\n\t138,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t172,\n\t217,\n\t136,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t176,\n\t217,\n\t135,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t173,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t173,\n\t217,\n\t130,\n\t217,\n\t136,\n\t217,\n\t130,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t216,\n\t177,\n\t217,\n\t138,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t130,\n\t217,\n\t133,\n\t216,\n\t173,\n\t217,\n\t129,\n\t217,\n\t136,\n\t216,\n\t184,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t171,\n\t216,\n\t167,\n\t217,\n\t134,\n\t217,\n\t138,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t217,\n\t135,\n\t216,\n\t175,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t177,\n\t216,\n\t163,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t130,\n\t216,\n\t177,\n\t216,\n\t162,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t180,\n\t216,\n\t168,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t173,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t172,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t216,\n\t179,\n\t216,\n\t177,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t136,\n\t217,\n\t133,\n\t217,\n\t133,\n\t216,\n\t172,\n\t217,\n\t133,\n\t217,\n\t136,\n\t216,\n\t185,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t173,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t134,\n\t217,\n\t130,\n\t216,\n\t167,\n\t216,\n\t183,\n\t217,\n\t129,\n\t217,\n\t132,\n\t216,\n\t179,\n\t216,\n\t183,\n\t217,\n\t138,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t136,\n\t217,\n\t138,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t217,\n\t134,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t167,\n\t216,\n\t170,\n\t217,\n\t135,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t182,\n\t216,\n\t170,\n\t216,\n\t173,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t170,\n\t217,\n\t138,\n\t216,\n\t168,\n\t216,\n\t170,\n\t217,\n\t136,\n\t217,\n\t130,\n\t217,\n\t138,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t217,\n\t136,\n\t217,\n\t132,\n\t217,\n\t137,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t168,\n\t216,\n\t177,\n\t217,\n\t138,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t183,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t180,\n\t216,\n\t174,\n\t216,\n\t181,\n\t217,\n\t138,\n\t216,\n\t179,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t171,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t171,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t181,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t173,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t171,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t178,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t174,\n\t217,\n\t132,\n\t217,\n\t138,\n\t216,\n\t172,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t172,\n\t217,\n\t133,\n\t217,\n\t138,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t133,\n\t217,\n\t135,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t172,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t179,\n\t216,\n\t167,\n\t216,\n\t185,\n\t216,\n\t169,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t217,\n\t135,\n\t216,\n\t175,\n\t217,\n\t135,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t166,\n\t217,\n\t138,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t216,\n\t174,\n\t217,\n\t136,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t129,\n\t217,\n\t134,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t216,\n\t170,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t217,\n\t136,\n\t216,\n\t177,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t216,\n\t177,\n\t217,\n\t136,\n\t216,\n\t179,\n\t216,\n\t167,\n\t216,\n\t179,\n\t216,\n\t170,\n\t216,\n\t186,\n\t216,\n\t177,\n\t217,\n\t130,\n\t216,\n\t170,\n\t216,\n\t181,\n\t216,\n\t167,\n\t217,\n\t133,\n\t217,\n\t138,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t168,\n\t217,\n\t134,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t184,\n\t217,\n\t138,\n\t217,\n\t133,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t116,\n\t97,\n\t105,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t61,\n\t32,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t46,\n\t106,\n\t112,\n\t103,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t102,\n\t105,\n\t103,\n\t117,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t112,\n\t110,\n\t103,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t77,\n\t97,\n\t116,\n\t104,\n\t46,\n\t114,\n\t97,\n\t110,\n\t100,\n\t111,\n\t109,\n\t40,\n\t41,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t109,\n\t112,\n\t111,\n\t114,\n\t97,\n\t114,\n\t121,\n\t32,\n\t85,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t83,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t99,\n\t105,\n\t114,\n\t99,\n\t117,\n\t109,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t115,\n\t46,\n\t97,\n\t112,\n\t112,\n\t101,\n\t110,\n\t100,\n\t67,\n\t104,\n\t105,\n\t108,\n\t100,\n\t40,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t34,\n\t62,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t47,\n\t100,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t117,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t116,\n\t104,\n\t111,\n\t117,\n\t115,\n\t97,\n\t110,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t34,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t105,\n\t110,\n\t118,\n\t101,\n\t115,\n\t116,\n\t105,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t97,\n\t118,\n\t105,\n\t99,\n\t111,\n\t110,\n\t46,\n\t105,\n\t99,\n\t111,\n\t34,\n\t32,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t98,\n\t97,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t77,\n\t97,\n\t115,\n\t115,\n\t97,\n\t99,\n\t104,\n\t117,\n\t115,\n\t101,\n\t116,\n\t116,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t112,\n\t114,\n\t111,\n\t110,\n\t117,\n\t110,\n\t99,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t58,\n\t35,\n\t102,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t45,\n\t108,\n\t101,\n\t102,\n\t116,\n\t58,\n\t70,\n\t111,\n\t114,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t44,\n\t32,\n\t109,\n\t105,\n\t115,\n\t99,\n\t101,\n\t108,\n\t108,\n\t97,\n\t110,\n\t101,\n\t111,\n\t117,\n\t115,\n\t38,\n\t108,\n\t116,\n\t59,\n\t47,\n\t109,\n\t97,\n\t116,\n\t104,\n\t38,\n\t103,\n\t116,\n\t59,\n\t112,\n\t115,\n\t121,\n\t99,\n\t104,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t105,\n\t110,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t97,\n\t115,\n\t32,\n\t111,\n\t112,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t83,\n\t117,\n\t112,\n\t114,\n\t101,\n\t109,\n\t101,\n\t32,\n\t67,\n\t111,\n\t117,\n\t114,\n\t116,\n\t111,\n\t99,\n\t99,\n\t97,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t65,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t44,\n\t78,\n\t111,\n\t114,\n\t116,\n\t104,\n\t32,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t112,\n\t120,\n\t59,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t111,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t110,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t69,\n\t110,\n\t116,\n\t101,\n\t114,\n\t116,\n\t97,\n\t105,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t116,\n\t111,\n\t76,\n\t111,\n\t119,\n\t101,\n\t114,\n\t67,\n\t97,\n\t115,\n\t101,\n\t40,\n\t109,\n\t97,\n\t110,\n\t117,\n\t102,\n\t97,\n\t99,\n\t116,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t112,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t109,\n\t98,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t70,\n\t111,\n\t114,\n\t32,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t44,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t34,\n\t32,\n\t109,\n\t97,\n\t120,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t61,\n\t34,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t59,\n\t99,\n\t111,\n\t110,\n\t115,\n\t99,\n\t105,\n\t111,\n\t117,\n\t115,\n\t110,\n\t101,\n\t115,\n\t115,\n\t77,\n\t101,\n\t100,\n\t105,\n\t116,\n\t101,\n\t114,\n\t114,\n\t97,\n\t110,\n\t101,\n\t97,\n\t110,\n\t101,\n\t120,\n\t116,\n\t114,\n\t97,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t97,\n\t114,\n\t121,\n\t97,\n\t115,\n\t115,\n\t97,\n\t115,\n\t115,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t117,\n\t98,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t32,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t101,\n\t104,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t117,\n\t108,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t112,\n\t104,\n\t105,\n\t108,\n\t111,\n\t115,\n\t111,\n\t112,\n\t104,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t104,\n\t114,\n\t101,\n\t102,\n\t119,\n\t97,\n\t115,\n\t32,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t83,\n\t97,\n\t110,\n\t32,\n\t70,\n\t114,\n\t97,\n\t110,\n\t99,\n\t105,\n\t115,\n\t99,\n\t111,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t123,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t109,\n\t97,\n\t105,\n\t110,\n\t115,\n\t111,\n\t112,\n\t104,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t109,\n\t97,\n\t116,\n\t104,\n\t101,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t13,\n\t10,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t105,\n\t112,\n\t115,\n\t109,\n\t97,\n\t121,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t40,\n\t102,\n\t111,\n\t114,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t44,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t108,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t99,\n\t97,\n\t115,\n\t101,\n\t115,\n\t112,\n\t97,\n\t114,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t71,\n\t114,\n\t101,\n\t97,\n\t116,\n\t32,\n\t66,\n\t114,\n\t105,\n\t116,\n\t97,\n\t105,\n\t110,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t61,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t97,\n\t108,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t111,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t104,\n\t111,\n\t108,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t59,\n\t32,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t32,\n\t106,\n\t117,\n\t115,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t115,\n\t117,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t108,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t47,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t32,\n\t123,\n\t97,\n\t114,\n\t101,\n\t32,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t10,\n\t9,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t34,\n\t32,\n\t47,\n\t62,\n\t60,\n\t47,\n\t97,\n\t114,\n\t101,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t121,\n\t104,\n\t97,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t32,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t99,\n\t114,\n\t101,\n\t100,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t58,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t46,\n\t103,\n\t105,\n\t102,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t60,\n\t105,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t105,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t45,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t59,\n\t97,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t111,\n\t103,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t120,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t112,\n\t97,\n\t114,\n\t108,\n\t105,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t121,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t112,\n\t114,\n\t101,\n\t100,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t110,\n\t116,\n\t108,\n\t121,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t124,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t111,\n\t114,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t97,\n\t108,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t121,\n\t61,\n\t34,\n\t111,\n\t103,\n\t58,\n\t47,\n\t120,\n\t45,\n\t115,\n\t104,\n\t111,\n\t99,\n\t107,\n\t119,\n\t97,\n\t118,\n\t101,\n\t45,\n\t100,\n\t101,\n\t109,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t117,\n\t114,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t78,\n\t101,\n\t118,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t108,\n\t101,\n\t115,\n\t115,\n\t44,\n\t119,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t65,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t108,\n\t108,\n\t97,\n\t98,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t114,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t108,\n\t121,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t32,\n\t105,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t44,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t32,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t115,\n\t116,\n\t97,\n\t114,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t105,\n\t110,\n\t103,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t97,\n\t99,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t100,\n\t105,\n\t115,\n\t99,\n\t117,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t109,\n\t105,\n\t100,\n\t100,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t32,\n\t105,\n\t110,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t117,\n\t97,\n\t108,\n\t100,\n\t105,\n\t102,\n\t102,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t32,\n\t116,\n\t111,\n\t32,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t118,\n\t105,\n\t101,\n\t119,\n\t104,\n\t111,\n\t109,\n\t111,\n\t115,\n\t101,\n\t120,\n\t117,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t109,\n\t97,\n\t110,\n\t117,\n\t102,\n\t97,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t114,\n\t115,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t110,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t58,\n\t32,\n\t35,\n\t108,\n\t101,\n\t110,\n\t103,\n\t116,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t32,\n\t115,\n\t105,\n\t103,\n\t110,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t110,\n\t116,\n\t34,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t62,\n\t114,\n\t101,\n\t118,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t121,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t108,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t115,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t119,\n\t97,\n\t115,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t73,\n\t110,\n\t100,\n\t111,\n\t45,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t97,\n\t110,\n\t118,\n\t117,\n\t108,\n\t110,\n\t101,\n\t114,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t110,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t97,\n\t114,\n\t101,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t78,\n\t101,\n\t119,\n\t32,\n\t89,\n\t111,\n\t114,\n\t107,\n\t32,\n\t67,\n\t105,\n\t116,\n\t121,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t97,\n\t116,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t99,\n\t111,\n\t117,\n\t114,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t97,\n\t116,\n\t104,\n\t101,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t105,\n\t97,\n\t110,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t34,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t116,\n\t101,\n\t99,\n\t104,\n\t110,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t46,\n\t114,\n\t101,\n\t109,\n\t111,\n\t118,\n\t101,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t40,\n\t98,\n\t114,\n\t97,\n\t110,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t118,\n\t105,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t33,\n\t91,\n\t101,\n\t110,\n\t100,\n\t105,\n\t102,\n\t93,\n\t45,\n\t45,\n\t62,\n\t13,\n\t10,\n\t73,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t32,\n\t97,\n\t32,\n\t115,\n\t105,\n\t110,\n\t103,\n\t108,\n\t101,\n\t114,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t46,\n\t97,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t115,\n\t32,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t84,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t110,\n\t100,\n\t97,\n\t115,\n\t104,\n\t59,\n\t32,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t101,\n\t113,\n\t117,\n\t105,\n\t112,\n\t112,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t100,\n\t111,\n\t101,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t102,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t84,\n\t104,\n\t101,\n\t115,\n\t101,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t108,\n\t101,\n\t115,\n\t115,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t112,\n\t101,\n\t114,\n\t99,\n\t101,\n\t110,\n\t116,\n\t97,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t32,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t32,\n\t116,\n\t111,\n\t112,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t47,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t116,\n\t119,\n\t111,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t98,\n\t101,\n\t108,\n\t111,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t109,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t34,\n\t32,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t65,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t119,\n\t105,\n\t100,\n\t101,\n\t32,\n\t114,\n\t97,\n\t110,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t108,\n\t121,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t115,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t105,\n\t116,\n\t121,\n\t119,\n\t97,\n\t115,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t100,\n\t32,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t109,\n\t100,\n\t97,\n\t115,\n\t104,\n\t59,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t97,\n\t110,\n\t32,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t102,\n\t97,\n\t99,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t115,\n\t105,\n\t103,\n\t110,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t110,\n\t116,\n\t108,\n\t121,\n\t111,\n\t110,\n\t109,\n\t111,\n\t117,\n\t115,\n\t101,\n\t111,\n\t118,\n\t101,\n\t114,\n\t61,\n\t34,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t32,\n\t97,\n\t115,\n\t121,\n\t110,\n\t99,\n\t32,\n\t61,\n\t32,\n\t116,\n\t114,\n\t117,\n\t101,\n\t59,\n\t112,\n\t114,\n\t111,\n\t98,\n\t108,\n\t101,\n\t109,\n\t115,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t115,\n\t101,\n\t101,\n\t109,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t105,\n\t97,\n\t114,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t112,\n\t111,\n\t115,\n\t115,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t40,\n\t41,\n\t32,\n\t123,\n\t116,\n\t111,\n\t111,\n\t107,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t32,\n\t105,\n\t110,\n\t97,\n\t110,\n\t100,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t105,\n\t115,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t105,\n\t110,\n\t32,\n\t97,\n\t110,\n\t32,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t103,\n\t114,\n\t101,\n\t97,\n\t116,\n\t32,\n\t100,\n\t101,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t69,\n\t110,\n\t118,\n\t105,\n\t114,\n\t111,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t102,\n\t117,\n\t108,\n\t108,\n\t121,\n\t32,\n\t118,\n\t105,\n\t114,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t97,\n\t108,\n\t108,\n\t50,\n\t48,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t44,\n\t112,\n\t114,\n\t111,\n\t102,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t115,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t115,\n\t97,\n\t114,\n\t121,\n\t32,\n\t116,\n\t111,\n\t32,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t116,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t68,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t100,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t84,\n\t104,\n\t101,\n\t32,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t109,\n\t97,\n\t121,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t32,\n\t116,\n\t111,\n\t58,\n\t67,\n\t111,\n\t110,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t44,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t98,\n\t101,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t39,\n\t115,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t40,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t108,\n\t101,\n\t102,\n\t116,\n\t34,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t108,\n\t121,\n\t98,\n\t97,\n\t115,\n\t105,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t111,\n\t32,\n\t114,\n\t101,\n\t100,\n\t117,\n\t99,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t106,\n\t117,\n\t114,\n\t105,\n\t115,\n\t100,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t120,\n\t105,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t110,\n\t109,\n\t111,\n\t117,\n\t115,\n\t101,\n\t111,\n\t117,\n\t116,\n\t61,\n\t34,\n\t78,\n\t101,\n\t119,\n\t32,\n\t84,\n\t101,\n\t115,\n\t116,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t85,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t102,\n\t105,\n\t108,\n\t109,\n\t32,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t45,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t46,\n\t100,\n\t116,\n\t100,\n\t34,\n\t62,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t98,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t117,\n\t110,\n\t112,\n\t114,\n\t101,\n\t99,\n\t101,\n\t100,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t105,\n\t115,\n\t32,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t105,\n\t110,\n\t119,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t32,\n\t98,\n\t111,\n\t108,\n\t100,\n\t59,\n\t105,\n\t115,\n\t32,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t105,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t114,\n\t101,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t9,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t97,\n\t114,\n\t101,\n\t32,\n\t116,\n\t121,\n\t112,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t99,\n\t111,\n\t110,\n\t102,\n\t108,\n\t105,\n\t99,\n\t116,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t65,\n\t110,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t113,\n\t117,\n\t97,\n\t110,\n\t116,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t114,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t97,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t101,\n\t108,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t115,\n\t97,\n\t114,\n\t121,\n\t32,\n\t102,\n\t111,\n\t114,\n\t114,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t97,\n\t110,\n\t100,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t32,\n\t116,\n\t111,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t97,\n\t109,\n\t101,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t71,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t99,\n\t111,\n\t109,\n\t109,\n\t105,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t111,\n\t9,\n\t9,\n\t60,\n\t117,\n\t108,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t118,\n\t105,\n\t115,\n\t117,\n\t97,\n\t108,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t49,\n\t57,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t44,\n\t112,\n\t114,\n\t97,\n\t99,\n\t116,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t101,\n\t114,\n\t115,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t97,\n\t110,\n\t100,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t101,\n\t100,\n\t111,\n\t99,\n\t99,\n\t117,\n\t112,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t105,\n\t115,\n\t32,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t109,\n\t111,\n\t117,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t97,\n\t108,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t116,\n\t101,\n\t98,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t108,\n\t101,\n\t102,\n\t116,\n\t58,\n\t32,\n\t97,\n\t117,\n\t116,\n\t111,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t97,\n\t115,\n\t83,\n\t111,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t100,\n\t117,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t114,\n\t101,\n\t112,\n\t117,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t97,\n\t115,\n\t10,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t97,\n\t99,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t100,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t73,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t111,\n\t45,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t97,\n\t103,\n\t97,\n\t105,\n\t110,\n\t115,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t73,\n\t110,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t99,\n\t97,\n\t115,\n\t101,\n\t44,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t112,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t100,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t68,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t109,\n\t97,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t32,\n\t100,\n\t101,\n\t97,\n\t108,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t97,\n\t108,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t97,\n\t108,\n\t119,\n\t97,\n\t121,\n\t115,\n\t97,\n\t114,\n\t101,\n\t32,\n\t99,\n\t117,\n\t114,\n\t114,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t101,\n\t120,\n\t112,\n\t114,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t112,\n\t104,\n\t105,\n\t108,\n\t111,\n\t115,\n\t111,\n\t112,\n\t104,\n\t121,\n\t32,\n\t111,\n\t102,\n\t102,\n\t111,\n\t114,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t99,\n\t105,\n\t118,\n\t105,\n\t108,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t115,\n\t108,\n\t97,\n\t110,\n\t100,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t73,\n\t110,\n\t100,\n\t101,\n\t120,\n\t99,\n\t97,\n\t110,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t32,\n\t105,\n\t110,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t34,\n\t32,\n\t47,\n\t62,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t47,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t77,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t85,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t109,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t116,\n\t114,\n\t97,\n\t99,\n\t101,\n\t100,\n\t105,\n\t115,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t105,\n\t115,\n\t32,\n\t102,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t108,\n\t105,\n\t118,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t101,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t70,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t82,\n\t101,\n\t118,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t121,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t105,\n\t110,\n\t105,\n\t115,\n\t32,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t115,\n\t117,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t111,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t34,\n\t62,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t32,\n\t115,\n\t116,\n\t111,\n\t114,\n\t105,\n\t101,\n\t115,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t97,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t119,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t105,\n\t116,\n\t115,\n\t119,\n\t97,\n\t115,\n\t32,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t105,\n\t115,\n\t32,\n\t97,\n\t110,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t105,\n\t110,\n\t99,\n\t105,\n\t112,\n\t97,\n\t108,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t115,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t97,\n\t114,\n\t101,\n\t99,\n\t111,\n\t103,\n\t110,\n\t105,\n\t122,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t97,\n\t32,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t114,\n\t101,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t101,\n\t100,\n\t104,\n\t101,\n\t97,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t103,\n\t114,\n\t97,\n\t100,\n\t117,\n\t97,\n\t116,\n\t101,\n\t84,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t32,\n\t116,\n\t119,\n\t111,\n\t103,\n\t114,\n\t97,\n\t118,\n\t105,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t114,\n\t101,\n\t32,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t100,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t115,\n\t101,\n\t114,\n\t118,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t111,\n\t112,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t102,\n\t117,\n\t110,\n\t100,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t108,\n\t121,\n\t100,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t105,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t99,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t114,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t44,\n\t97,\n\t110,\n\t100,\n\t32,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t105,\n\t110,\n\t32,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t50,\n\t48,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t46,\n\t97,\n\t110,\n\t100,\n\t32,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t108,\n\t111,\n\t97,\n\t100,\n\t67,\n\t104,\n\t97,\n\t114,\n\t116,\n\t98,\n\t101,\n\t97,\n\t116,\n\t116,\n\t111,\n\t32,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t101,\n\t110,\n\t118,\n\t105,\n\t114,\n\t111,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t32,\n\t104,\n\t97,\n\t108,\n\t102,\n\t32,\n\t111,\n\t102,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t32,\n\t97,\n\t110,\n\t100,\n\t97,\n\t114,\n\t99,\n\t104,\n\t105,\n\t116,\n\t101,\n\t99,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t98,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t105,\n\t122,\n\t101,\n\t100,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t118,\n\t97,\n\t108,\n\t97,\n\t117,\n\t116,\n\t104,\n\t111,\n\t114,\n\t105,\n\t116,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t70,\n\t101,\n\t100,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t119,\n\t97,\n\t115,\n\t32,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t101,\n\t100,\n\t101,\n\t100,\n\t97,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t97,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t80,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t100,\n\t102,\n\t114,\n\t101,\n\t101,\n\t32,\n\t115,\n\t111,\n\t102,\n\t116,\n\t119,\n\t97,\n\t114,\n\t101,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t97,\n\t115,\n\t32,\n\t100,\n\t101,\n\t115,\n\t116,\n\t114,\n\t111,\n\t121,\n\t101,\n\t100,\n\t97,\n\t119,\n\t97,\n\t121,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t59,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t97,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t112,\n\t111,\n\t119,\n\t101,\n\t114,\n\t102,\n\t117,\n\t108,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t97,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t116,\n\t32,\n\t116,\n\t111,\n\t117,\n\t110,\n\t116,\n\t105,\n\t108,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t110,\n\t100,\n\t119,\n\t97,\n\t115,\n\t32,\n\t97,\n\t110,\n\t110,\n\t111,\n\t117,\n\t110,\n\t99,\n\t101,\n\t100,\n\t97,\n\t114,\n\t101,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t115,\n\t62,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t68,\n\t79,\n\t32,\n\t78,\n\t79,\n\t84,\n\t32,\n\t65,\n\t76,\n\t84,\n\t69,\n\t82,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t109,\n\t101,\n\t115,\n\t47,\n\t63,\n\t115,\n\t111,\n\t114,\n\t116,\n\t61,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t104,\n\t97,\n\t100,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t97,\n\t115,\n\t105,\n\t115,\n\t32,\n\t102,\n\t111,\n\t114,\n\t104,\n\t97,\n\t115,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t117,\n\t109,\n\t109,\n\t101,\n\t114,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t117,\n\t99,\n\t104,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t111,\n\t115,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t105,\n\t110,\n\t103,\n\t105,\n\t115,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t118,\n\t97,\n\t114,\n\t105,\n\t111,\n\t117,\n\t115,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t83,\n\t111,\n\t117,\n\t116,\n\t104,\n\t32,\n\t65,\n\t102,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t97,\n\t109,\n\t101,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t110,\n\t101,\n\t115,\n\t115,\n\t105,\n\t110,\n\t32,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t99,\n\t97,\n\t115,\n\t101,\n\t59,\n\t32,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t97,\n\t110,\n\t100,\n\t59,\n\t32,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t58,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t115,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t97,\n\t104,\n\t97,\n\t115,\n\t97,\n\t32,\n\t77,\n\t101,\n\t108,\n\t97,\n\t121,\n\t117,\n\t110,\n\t111,\n\t114,\n\t115,\n\t107,\n\t32,\n\t98,\n\t111,\n\t107,\n\t109,\n\t195,\n\t165,\n\t108,\n\t110,\n\t111,\n\t114,\n\t115,\n\t107,\n\t32,\n\t110,\n\t121,\n\t110,\n\t111,\n\t114,\n\t115,\n\t107,\n\t115,\n\t108,\n\t111,\n\t118,\n\t101,\n\t110,\n\t197,\n\t161,\n\t196,\n\t141,\n\t105,\n\t110,\n\t97,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t99,\n\t97,\n\t108,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t111,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t34,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t97,\n\t109,\n\t98,\n\t105,\n\t103,\n\t117,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t68,\n\t111,\n\t109,\n\t97,\n\t105,\n\t110,\n\t78,\n\t97,\n\t109,\n\t101,\n\t39,\n\t44,\n\t32,\n\t39,\n\t97,\n\t100,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t109,\n\t117,\n\t108,\n\t116,\n\t97,\n\t110,\n\t101,\n\t111,\n\t117,\n\t115,\n\t108,\n\t121,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t58,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t60,\n\t33,\n\t91,\n\t101,\n\t110,\n\t100,\n\t105,\n\t102,\n\t93,\n\t45,\n\t45,\n\t62,\n\t10,\n\t60,\n\t47,\n\t62,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t102,\n\t114,\n\t97,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t45,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t58,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t61,\n\t104,\n\t116,\n\t116,\n\t112,\n\t37,\n\t51,\n\t65,\n\t37,\n\t50,\n\t70,\n\t37,\n\t50,\n\t70,\n\t60,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t116,\n\t34,\n\t32,\n\t47,\n\t102,\n\t97,\n\t118,\n\t105,\n\t99,\n\t111,\n\t110,\n\t46,\n\t105,\n\t99,\n\t111,\n\t34,\n\t32,\n\t125,\n\t41,\n\t59,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t46,\n\t115,\n\t101,\n\t116,\n\t65,\n\t116,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t40,\n\t65,\n\t100,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t32,\n\t110,\n\t101,\n\t119,\n\t32,\n\t65,\n\t114,\n\t114,\n\t97,\n\t121,\n\t40,\n\t41,\n\t59,\n\t60,\n\t33,\n\t91,\n\t101,\n\t110,\n\t100,\n\t105,\n\t102,\n\t93,\n\t45,\n\t45,\n\t62,\n\t13,\n\t10,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t59,\n\t85,\n\t110,\n\t102,\n\t111,\n\t114,\n\t116,\n\t117,\n\t110,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t44,\n\t34,\n\t62,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t47,\n\t102,\n\t97,\n\t118,\n\t105,\n\t99,\n\t111,\n\t110,\n\t46,\n\t105,\n\t99,\n\t111,\n\t34,\n\t62,\n\t61,\n\t39,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t39,\n\t32,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t44,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t44,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t97,\n\t110,\n\t32,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t97,\n\t115,\n\t32,\n\t97,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t32,\n\t111,\n\t102,\n\t112,\n\t116,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t10,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t32,\n\t123,\n\t114,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t101,\n\t110,\n\t100,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t47,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t46,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t32,\n\t65,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t97,\n\t108,\n\t111,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t98,\n\t111,\n\t100,\n\t121,\n\t46,\n\t97,\n\t112,\n\t112,\n\t114,\n\t111,\n\t120,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t32,\n\t67,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t112,\n\t111,\n\t115,\n\t116,\n\t34,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t109,\n\t101,\n\t97,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t45,\n\t45,\n\t60,\n\t33,\n\t91,\n\t101,\n\t110,\n\t100,\n\t105,\n\t102,\n\t93,\n\t45,\n\t45,\n\t62,\n\t80,\n\t114,\n\t105,\n\t109,\n\t101,\n\t32,\n\t77,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t60,\n\t47,\n\t97,\n\t62,\n\t32,\n\t60,\n\t97,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t116,\n\t104,\n\t101,\n\t32,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t111,\n\t110,\n\t109,\n\t111,\n\t117,\n\t115,\n\t101,\n\t111,\n\t118,\n\t101,\n\t114,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t115,\n\t58,\n\t47,\n\t47,\n\t119,\n\t97,\n\t115,\n\t32,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t119,\n\t97,\n\t115,\n\t32,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t97,\n\t114,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t60,\n\t33,\n\t91,\n\t101,\n\t110,\n\t100,\n\t105,\n\t102,\n\t93,\n\t45,\n\t45,\n\t62,\n\t10,\n\t10,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t115,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t105,\n\t110,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t97,\n\t115,\n\t116,\n\t32,\n\t116,\n\t111,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t104,\n\t111,\n\t108,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t97,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t105,\n\t116,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t45,\n\t58,\n\t32,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t32,\n\t123,\n\t66,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t45,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t46,\n\t100,\n\t116,\n\t100,\n\t34,\n\t62,\n\t10,\n\t60,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t97,\n\t99,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t110,\n\t105,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t99,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t47,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t105,\n\t110,\n\t32,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t115,\n\t41,\n\t59,\n\t32,\n\t106,\n\t115,\n\t46,\n\t105,\n\t100,\n\t32,\n\t61,\n\t32,\n\t105,\n\t100,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t48,\n\t48,\n\t37,\n\t34,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t82,\n\t111,\n\t109,\n\t97,\n\t110,\n\t32,\n\t67,\n\t97,\n\t116,\n\t104,\n\t111,\n\t108,\n\t105,\n\t99,\n\t97,\n\t110,\n\t32,\n\t105,\n\t110,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t101,\n\t110,\n\t116,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t46,\n\t103,\n\t105,\n\t102,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t100,\n\t105,\n\t115,\n\t99,\n\t114,\n\t105,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t114,\n\t99,\n\t104,\n\t97,\n\t101,\n\t111,\n\t108,\n\t111,\n\t103,\n\t105,\n\t99,\n\t97,\n\t108,\n\t112,\n\t114,\n\t105,\n\t109,\n\t101,\n\t32,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t99,\n\t111,\n\t109,\n\t98,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t40,\n\t119,\n\t46,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t104,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t40,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t115,\n\t58,\n\t47,\n\t47,\n\t97,\n\t73,\n\t110,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t44,\n\t32,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t108,\n\t101,\n\t102,\n\t116,\n\t34,\n\t32,\n\t67,\n\t122,\n\t101,\n\t99,\n\t104,\n\t32,\n\t82,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t85,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t75,\n\t105,\n\t110,\n\t103,\n\t100,\n\t111,\n\t109,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t101,\n\t110,\n\t99,\n\t101,\n\t99,\n\t111,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t46,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t40,\n\t41,\n\t32,\n\t123,\n\t99,\n\t111,\n\t109,\n\t101,\n\t115,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t115,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t40,\n\t39,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t60,\n\t47,\n\t97,\n\t62,\n\t10,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t10,\n\t60,\n\t108,\n\t105,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t40,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t9,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t62,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t97,\n\t115,\n\t32,\n\t118,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t116,\n\t111,\n\t112,\n\t34,\n\t62,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t116,\n\t116,\n\t101,\n\t109,\n\t112,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t99,\n\t97,\n\t114,\n\t98,\n\t111,\n\t110,\n\t32,\n\t100,\n\t105,\n\t111,\n\t120,\n\t105,\n\t100,\n\t101,\n\t10,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t45,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t111,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t110,\n\t105,\n\t116,\n\t121,\n\t32,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t13,\n\t10,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t84,\n\t105,\n\t225,\n\t186,\n\t191,\n\t110,\n\t103,\n\t32,\n\t86,\n\t105,\n\t225,\n\t187,\n\t135,\n\t116,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t115,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t45,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t35,\n\t48,\n\t34,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t119,\n\t97,\n\t115,\n\t32,\n\t100,\n\t105,\n\t115,\n\t99,\n\t111,\n\t118,\n\t101,\n\t114,\n\t101,\n\t100,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t41,\n\t59,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t10,\n\t68,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t101,\n\t99,\n\t99,\n\t108,\n\t101,\n\t115,\n\t105,\n\t97,\n\t115,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t60,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t104,\n\t97,\n\t115,\n\t32,\n\t110,\n\t101,\n\t118,\n\t101,\n\t114,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t105,\n\t110,\n\t32,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t101,\n\t32,\n\t116,\n\t111,\n\t97,\n\t117,\n\t116,\n\t111,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t119,\n\t97,\n\t115,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t112,\n\t101,\n\t114,\n\t99,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t34,\n\t32,\n\t47,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t100,\n\t101,\n\t115,\n\t99,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t115,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t45,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t102,\n\t117,\n\t115,\n\t101,\n\t100,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t45,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t101,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t111,\n\t114,\n\t32,\n\t110,\n\t111,\n\t116,\n\t84,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t97,\n\t32,\n\t115,\n\t109,\n\t97,\n\t108,\n\t108,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t109,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t46,\n\t32,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t110,\n\t100,\n\t32,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t65,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t105,\n\t116,\n\t115,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t32,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t116,\n\t34,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t108,\n\t105,\n\t107,\n\t101,\n\t108,\n\t121,\n\t32,\n\t116,\n\t111,\n\t97,\n\t110,\n\t32,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t101,\n\t32,\n\t105,\n\t110,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t115,\n\t32,\n\t116,\n\t111,\n\t97,\n\t110,\n\t110,\n\t111,\n\t117,\n\t110,\n\t99,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t62,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t102,\n\t111,\n\t114,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t101,\n\t97,\n\t114,\n\t108,\n\t105,\n\t101,\n\t115,\n\t116,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t105,\n\t116,\n\t32,\n\t119,\n\t97,\n\t115,\n\t112,\n\t116,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t32,\n\t118,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t116,\n\t111,\n\t112,\n\t34,\n\t32,\n\t105,\n\t110,\n\t104,\n\t97,\n\t98,\n\t105,\n\t116,\n\t97,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t13,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t109,\n\t105,\n\t108,\n\t108,\n\t105,\n\t111,\n\t110,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t114,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t114,\n\t103,\n\t117,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t97,\n\t110,\n\t100,\n\t97,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t111,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t98,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t98,\n\t101,\n\t115,\n\t116,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t102,\n\t111,\n\t114,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t109,\n\t117,\n\t108,\n\t116,\n\t105,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t114,\n\t101,\n\t99,\n\t111,\n\t103,\n\t110,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t67,\n\t111,\n\t117,\n\t110,\n\t99,\n\t105,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t32,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t69,\n\t110,\n\t116,\n\t101,\n\t114,\n\t116,\n\t97,\n\t105,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t97,\n\t119,\n\t97,\n\t121,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t59,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t118,\n\t101,\n\t115,\n\t116,\n\t105,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t99,\n\t111,\n\t110,\n\t110,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t97,\n\t110,\n\t100,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t108,\n\t116,\n\t104,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t100,\n\t101,\n\t115,\n\t99,\n\t101,\n\t110,\n\t100,\n\t97,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t105,\n\t32,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t34,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t32,\n\t97,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t97,\n\t115,\n\t32,\n\t115,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t97,\n\t110,\n\t32,\n\t85,\n\t110,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t99,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t105,\n\t99,\n\t117,\n\t108,\n\t116,\n\t86,\n\t105,\n\t99,\n\t101,\n\t32,\n\t80,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t112,\n\t97,\n\t115,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t49,\n\t49,\n\t112,\n\t120,\n\t101,\n\t120,\n\t112,\n\t108,\n\t97,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t112,\n\t116,\n\t32,\n\t111,\n\t102,\n\t119,\n\t114,\n\t105,\n\t116,\n\t116,\n\t101,\n\t110,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t9,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t105,\n\t115,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t115,\n\t101,\n\t109,\n\t98,\n\t108,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t111,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t115,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t115,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t109,\n\t101,\n\t97,\n\t110,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t117,\n\t116,\n\t115,\n\t105,\n\t100,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t116,\n\t40,\n\t77,\n\t97,\n\t116,\n\t104,\n\t46,\n\t114,\n\t97,\n\t110,\n\t100,\n\t111,\n\t109,\n\t40,\n\t41,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t112,\n\t114,\n\t111,\n\t109,\n\t105,\n\t110,\n\t101,\n\t110,\n\t116,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t67,\n\t111,\n\t110,\n\t115,\n\t116,\n\t97,\n\t110,\n\t116,\n\t105,\n\t110,\n\t111,\n\t112,\n\t108,\n\t101,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t115,\n\t101,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t49,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t49,\n\t34,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t115,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t104,\n\t97,\n\t100,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t100,\n\t101,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t10,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t116,\n\t101,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t58,\n\t98,\n\t13,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t60,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t118,\n\t105,\n\t101,\n\t119,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t95,\n\t105,\n\t100,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t99,\n\t97,\n\t112,\n\t105,\n\t116,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t13,\n\t10,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t114,\n\t101,\n\t108,\n\t101,\n\t97,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t32,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t120,\n\t77,\n\t76,\n\t72,\n\t116,\n\t116,\n\t112,\n\t82,\n\t101,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t32,\n\t115,\n\t117,\n\t98,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t115,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t115,\n\t116,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t117,\n\t114,\n\t102,\n\t97,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t105,\n\t103,\n\t110,\n\t32,\n\t112,\n\t111,\n\t108,\n\t105,\n\t99,\n\t121,\n\t95,\n\t115,\n\t101,\n\t116,\n\t68,\n\t111,\n\t109,\n\t97,\n\t105,\n\t110,\n\t78,\n\t97,\n\t109,\n\t101,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t105,\n\t115,\n\t32,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t73,\n\t110,\n\t32,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t109,\n\t101,\n\t97,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t115,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t100,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t116,\n\t111,\n\t32,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t115,\n\t32,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t68,\n\t101,\n\t99,\n\t108,\n\t97,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t101,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t67,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t115,\n\t32,\n\t111,\n\t102,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t112,\n\t101,\n\t114,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t32,\n\t123,\n\t13,\n\t105,\n\t102,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t105,\n\t102,\n\t114,\n\t101,\n\t103,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t108,\n\t101,\n\t97,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t85,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t78,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t121,\n\t112,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t65,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t10,\n\t60,\n\t47,\n\t104,\n\t101,\n\t97,\n\t100,\n\t62,\n\t10,\n\t60,\n\t98,\n\t111,\n\t100,\n\t121,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t115,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t40,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t110,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t117,\n\t97,\n\t108,\n\t97,\n\t109,\n\t111,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t97,\n\t110,\n\t121,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t47,\n\t62,\n\t10,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t32,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t59,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t117,\n\t114,\n\t112,\n\t111,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t116,\n\t111,\n\t59,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t35,\n\t102,\n\t102,\n\t102,\n\t125,\n\t10,\n\t46,\n\t10,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t117,\n\t98,\n\t106,\n\t101,\n\t99,\n\t116,\n\t32,\n\t111,\n\t102,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t62,\n\t13,\n\t10,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t60,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t99,\n\t101,\n\t108,\n\t101,\n\t98,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t70,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t100,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t117,\n\t105,\n\t115,\n\t104,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t98,\n\t116,\n\t97,\n\t107,\n\t101,\n\t115,\n\t32,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t32,\n\t105,\n\t110,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t110,\n\t111,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t62,\n\t60,\n\t33,\n\t91,\n\t101,\n\t110,\n\t100,\n\t105,\n\t102,\n\t93,\n\t45,\n\t45,\n\t62,\n\t10,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t105,\n\t110,\n\t115,\n\t116,\n\t101,\n\t97,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t32,\n\t105,\n\t110,\n\t101,\n\t115,\n\t116,\n\t105,\n\t109,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t119,\n\t97,\n\t115,\n\t32,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t111,\n\t117,\n\t116,\n\t32,\n\t104,\n\t105,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t115,\n\t105,\n\t103,\n\t110,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t110,\n\t116,\n\t108,\n\t121,\n\t32,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t13,\n\t10,\n\t101,\n\t110,\n\t118,\n\t105,\n\t114,\n\t111,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t97,\n\t108,\n\t32,\n\t116,\n\t111,\n\t32,\n\t112,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t102,\n\t111,\n\t114,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t115,\n\t32,\n\t101,\n\t115,\n\t115,\n\t101,\n\t110,\n\t116,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t115,\n\t116,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t109,\n\t97,\n\t100,\n\t101,\n\t34,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t101,\n\t116,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t115,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t32,\n\t104,\n\t97,\n\t108,\n\t102,\n\t32,\n\t111,\n\t102,\n\t99,\n\t114,\n\t111,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t110,\n\t111,\n\t34,\n\t32,\n\t105,\n\t115,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t32,\n\t111,\n\t102,\n\t73,\n\t73,\n\t44,\n\t32,\n\t72,\n\t111,\n\t108,\n\t121,\n\t32,\n\t82,\n\t111,\n\t109,\n\t97,\n\t110,\n\t105,\n\t115,\n\t32,\n\t101,\n\t120,\n\t112,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t114,\n\t32,\n\t111,\n\t119,\n\t110,\n\t100,\n\t101,\n\t102,\n\t105,\n\t110,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t116,\n\t111,\n\t32,\n\t101,\n\t110,\n\t115,\n\t117,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t103,\n\t114,\n\t101,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t99,\n\t111,\n\t110,\n\t116,\n\t97,\n\t105,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t114,\n\t101,\n\t32,\n\t102,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t110,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t32,\n\t105,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t32,\n\t97,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t60,\n\t47,\n\t117,\n\t108,\n\t62,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t97,\n\t110,\n\t100,\n\t32,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t98,\n\t117,\n\t116,\n\t116,\n\t111,\n\t110,\n\t34,\n\t32,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t100,\n\t62,\n\t10,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t97,\n\t114,\n\t114,\n\t105,\n\t101,\n\t100,\n\t32,\n\t111,\n\t117,\n\t116,\n\t32,\n\t98,\n\t121,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t97,\n\t112,\n\t105,\n\t116,\n\t97,\n\t108,\n\t32,\n\t111,\n\t102,\n\t119,\n\t97,\n\t115,\n\t32,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t119,\n\t104,\n\t105,\n\t99,\n\t104,\n\t32,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t116,\n\t104,\n\t101,\n\t32,\n\t72,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t32,\n\t116,\n\t111,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t116,\n\t111,\n\t32,\n\t115,\n\t117,\n\t112,\n\t112,\n\t111,\n\t114,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t111,\n\t99,\n\t101,\n\t115,\n\t115,\n\t32,\n\t32,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t104,\n\t105,\n\t115,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t116,\n\t104,\n\t101,\n\t32,\n\t117,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t111,\n\t112,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t120,\n\t116,\n\t32,\n\t111,\n\t102,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t112,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t113,\n\t34,\n\t9,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t99,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t109,\n\t97,\n\t116,\n\t104,\n\t101,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t105,\n\t97,\n\t110,\n\t115,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t105,\n\t110,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t44,\n\t99,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t41,\n\t59,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t112,\n\t104,\n\t105,\n\t108,\n\t111,\n\t115,\n\t111,\n\t112,\n\t104,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t115,\n\t114,\n\t112,\n\t115,\n\t107,\n\t111,\n\t104,\n\t114,\n\t118,\n\t97,\n\t116,\n\t115,\n\t107,\n\t105,\n\t116,\n\t105,\n\t225,\n\t186,\n\t191,\n\t110,\n\t103,\n\t32,\n\t86,\n\t105,\n\t225,\n\t187,\n\t135,\n\t116,\n\t208,\n\t160,\n\t209,\n\t131,\n\t209,\n\t129,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t185,\n\t209,\n\t128,\n\t209,\n\t131,\n\t209,\n\t129,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t185,\n\t105,\n\t110,\n\t118,\n\t101,\n\t115,\n\t116,\n\t105,\n\t103,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t209,\n\t139,\n\t208,\n\t181,\n\t208,\n\t190,\n\t208,\n\t177,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t209,\n\t139,\n\t208,\n\t185,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t181,\n\t208,\n\t186,\n\t209,\n\t129,\n\t208,\n\t184,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t139,\n\t208,\n\t157,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t209,\n\t139,\n\t209,\n\t133,\n\t208,\n\t190,\n\t208,\n\t177,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t178,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t176,\n\t209,\n\t143,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t189,\n\t209,\n\t143,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t163,\n\t208,\n\t186,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t139,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t139,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t185,\n\t209,\n\t129,\n\t208,\n\t180,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t190,\n\t209,\n\t137,\n\t209,\n\t140,\n\t209,\n\t142,\n\t209,\n\t129,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t180,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t189,\n\t209,\n\t139,\n\t209,\n\t131,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t181,\n\t208,\n\t147,\n\t208,\n\t187,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t143,\n\t208,\n\t184,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t184,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t128,\n\t208,\n\t181,\n\t209,\n\t136,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t161,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t135,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t141,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t188,\n\t209,\n\t131,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t180,\n\t209,\n\t131,\n\t208,\n\t181,\n\t209,\n\t130,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t140,\n\t209,\n\t130,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t176,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t189,\n\t208,\n\t181,\n\t209,\n\t135,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t181,\n\t209,\n\t136,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t181,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t181,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t179,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t160,\n\t208,\n\t181,\n\t208,\n\t186,\n\t208,\n\t187,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t176,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t175,\n\t217,\n\t137,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t136,\n\t216,\n\t182,\n\t217,\n\t136,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t168,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t172,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t136,\n\t216,\n\t167,\n\t217,\n\t130,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t179,\n\t216,\n\t167,\n\t216,\n\t166,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t216,\n\t185,\n\t216,\n\t182,\n\t216,\n\t167,\n\t216,\n\t161,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t182,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t181,\n\t217,\n\t133,\n\t217,\n\t138,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t185,\n\t216,\n\t182,\n\t216,\n\t167,\n\t216,\n\t161,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t167,\n\t216,\n\t166,\n\t216,\n\t172,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t179,\n\t216,\n\t172,\n\t217,\n\t138,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t217,\n\t130,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t182,\n\t216,\n\t186,\n\t216,\n\t183,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t129,\n\t217,\n\t138,\n\t216,\n\t175,\n\t217,\n\t138,\n\t217,\n\t136,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t177,\n\t216,\n\t173,\n\t217,\n\t138,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t172,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t175,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t138,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t216,\n\t174,\n\t216,\n\t168,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t129,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t217,\n\t129,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t138,\n\t216,\n\t174,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t217,\n\t130,\n\t217,\n\t134,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t174,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t183,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t172,\n\t216,\n\t170,\n\t217,\n\t133,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t175,\n\t217,\n\t138,\n\t217,\n\t131,\n\t217,\n\t136,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t179,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t173,\n\t216,\n\t169,\n\t216,\n\t185,\n\t216,\n\t168,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t132,\n\t217,\n\t135,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t177,\n\t216,\n\t168,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t168,\n\t216,\n\t183,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t163,\n\t216,\n\t175,\n\t216,\n\t168,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t174,\n\t216,\n\t168,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t170,\n\t216,\n\t173,\n\t216,\n\t175,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t186,\n\t216,\n\t167,\n\t217,\n\t134,\n\t217,\n\t138,\n\t99,\n\t117,\n\t114,\n\t115,\n\t111,\n\t114,\n\t58,\n\t112,\n\t111,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t59,\n\t60,\n\t47,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t62,\n\t10,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t34,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t46,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t118,\n\t101,\n\t114,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t47,\n\t97,\n\t62,\n\t32,\n\t124,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t60,\n\t33,\n\t100,\n\t111,\n\t99,\n\t116,\n\t121,\n\t112,\n\t101,\n\t32,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t61,\n\t34,\n\t115,\n\t99,\n\t114,\n\t101,\n\t101,\n\t110,\n\t34,\n\t32,\n\t60,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t102,\n\t97,\n\t118,\n\t105,\n\t99,\n\t111,\n\t110,\n\t46,\n\t105,\n\t99,\n\t111,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t9,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t105,\n\t115,\n\t116,\n\t105,\n\t99,\n\t115,\n\t34,\n\t32,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t103,\n\t101,\n\t116,\n\t34,\n\t32,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t10,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t99,\n\t117,\n\t116,\n\t32,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t119,\n\t114,\n\t105,\n\t116,\n\t101,\n\t40,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t45,\n\t98,\n\t111,\n\t116,\n\t116,\n\t111,\n\t109,\n\t58,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t115,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t34,\n\t32,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t102,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t10,\n\t32,\n\t32,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t118,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t116,\n\t111,\n\t112,\n\t34,\n\t62,\n\t60,\n\t119,\n\t97,\n\t115,\n\t32,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t41,\n\t59,\n\t13,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t59,\n\t34,\n\t62,\n\t41,\n\t46,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t46,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t98,\n\t101,\n\t99,\n\t97,\n\t117,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t99,\n\t111,\n\t111,\n\t107,\n\t105,\n\t101,\n\t60,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t47,\n\t125,\n\t98,\n\t111,\n\t100,\n\t121,\n\t123,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t58,\n\t48,\n\t59,\n\t69,\n\t110,\n\t99,\n\t121,\n\t99,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t105,\n\t97,\n\t32,\n\t111,\n\t102,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t46,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t40,\n\t110,\n\t97,\n\t109,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t10,\n\t97,\n\t100,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t32,\n\t60,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t104,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t34,\n\t62,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t112,\n\t111,\n\t114,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t115,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t34,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t73,\n\t110,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t119,\n\t111,\n\t114,\n\t100,\n\t115,\n\t44,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t32,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t59,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t47,\n\t62,\n\t10,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t97,\n\t115,\n\t32,\n\t119,\n\t101,\n\t108,\n\t108,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t13,\n\t10,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t9,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t105,\n\t110,\n\t115,\n\t112,\n\t105,\n\t114,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t110,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t116,\n\t105,\n\t98,\n\t108,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t58,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t32,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t71,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t35,\n\t67,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t115,\n\t116,\n\t32,\n\t80,\n\t97,\n\t114,\n\t116,\n\t121,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t116,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t32,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t34,\n\t32,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t97,\n\t110,\n\t121,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t32,\n\t79,\n\t114,\n\t116,\n\t104,\n\t111,\n\t100,\n\t111,\n\t120,\n\t32,\n\t67,\n\t104,\n\t117,\n\t114,\n\t99,\n\t104,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t47,\n\t62,\n\t10,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t119,\n\t97,\n\t115,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t117,\n\t110,\n\t116,\n\t105,\n\t108,\n\t32,\n\t104,\n\t105,\n\t115,\n\t32,\n\t100,\n\t101,\n\t97,\n\t116,\n\t104,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t115,\n\t99,\n\t111,\n\t109,\n\t112,\n\t97,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t111,\n\t114,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t78,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t108,\n\t97,\n\t110,\n\t100,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t58,\n\t117,\n\t114,\n\t108,\n\t40,\n\t97,\n\t114,\n\t103,\n\t117,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t99,\n\t114,\n\t111,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t110,\n\t111,\n\t34,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t78,\n\t111,\n\t114,\n\t116,\n\t104,\n\t32,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t101,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t102,\n\t114,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t97,\n\t32,\n\t99,\n\t111,\n\t108,\n\t108,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t118,\n\t101,\n\t114,\n\t121,\n\t32,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t115,\n\t117,\n\t114,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t34,\n\t62,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t95,\n\t99,\n\t97,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t61,\n\t97,\n\t116,\n\t116,\n\t97,\n\t99,\n\t104,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t111,\n\t102,\n\t32,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t115,\n\t32,\n\t100,\n\t101,\n\t114,\n\t105,\n\t118,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t110,\n\t97,\n\t109,\n\t101,\n\t100,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t73,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t114,\n\t101,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t110,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t32,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t32,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t97,\n\t110,\n\t100,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t108,\n\t108,\n\t97,\n\t112,\n\t115,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t84,\n\t104,\n\t105,\n\t115,\n\t32,\n\t109,\n\t101,\n\t97,\n\t110,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t101,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t97,\n\t115,\n\t32,\n\t114,\n\t101,\n\t112,\n\t108,\n\t97,\n\t99,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t97,\n\t110,\n\t97,\n\t108,\n\t121,\n\t115,\n\t105,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t115,\n\t112,\n\t105,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t102,\n\t111,\n\t114,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t115,\n\t117,\n\t99,\n\t99,\n\t101,\n\t115,\n\t115,\n\t102,\n\t117,\n\t108,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t97,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t114,\n\t101,\n\t104,\n\t101,\n\t110,\n\t115,\n\t105,\n\t118,\n\t101,\n\t72,\n\t105,\n\t115,\n\t116,\n\t111,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t101,\n\t114,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t114,\n\t101,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t85,\n\t110,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t100,\n\t32,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t62,\n\t10,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t115,\n\t116,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t111,\n\t112,\n\t80,\n\t114,\n\t111,\n\t112,\n\t97,\n\t103,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t116,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t101,\n\t108,\n\t101,\n\t99,\n\t116,\n\t114,\n\t111,\n\t109,\n\t97,\n\t103,\n\t110,\n\t101,\n\t116,\n\t105,\n\t99,\n\t101,\n\t110,\n\t97,\n\t98,\n\t108,\n\t101,\n\t83,\n\t101,\n\t114,\n\t118,\n\t105,\n\t99,\n\t101,\n\t115,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t73,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t123,\n\t118,\n\t97,\n\t114,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t115,\n\t32,\n\t97,\n\t32,\n\t114,\n\t101,\n\t115,\n\t117,\n\t108,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t70,\n\t111,\n\t114,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t44,\n\t32,\n\t105,\n\t110,\n\t32,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t116,\n\t34,\n\t32,\n\t119,\n\t97,\n\t115,\n\t32,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t109,\n\t100,\n\t97,\n\t115,\n\t104,\n\t59,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t117,\n\t108,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t101,\n\t97,\n\t116,\n\t104,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t114,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t116,\n\t32,\n\t116,\n\t111,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t105,\n\t115,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t105,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t59,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t105,\n\t115,\n\t32,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t228,\n\t184,\n\t173,\n\t230,\n\t150,\n\t135,\n\t32,\n\t40,\n\t231,\n\t174,\n\t128,\n\t228,\n\t189,\n\t147,\n\t41,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t100,\n\t97,\n\t100,\n\t97,\n\t100,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t114,\n\t97,\n\t99,\n\t105,\n\t195,\n\t179,\n\t110,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t99,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t101,\n\t115,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t105,\n\t101,\n\t110,\n\t116,\n\t101,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t150,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t173,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t163,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t137,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t131,\n\t224,\n\t164,\n\t183,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t160,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t162,\n\t224,\n\t164,\n\t188,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t171,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t140,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t129,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t155,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t182,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t163,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t162,\n\t224,\n\t164,\n\t188,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t171,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t150,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t154,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t155,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t155,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t152,\n\t224,\n\t164,\n\t163,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t167,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t182,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t188,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t131,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t152,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t150,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t130,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t114,\n\t115,\n\t115,\n\t43,\n\t120,\n\t109,\n\t108,\n\t34,\n\t32,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t61,\n\t34,\n\t45,\n\t116,\n\t121,\n\t112,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t116,\n\t105,\n\t116,\n\t108,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t115,\n\t97,\n\t109,\n\t101,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t34,\n\t32,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t116,\n\t34,\n\t32,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t118,\n\t101,\n\t114,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t116,\n\t47,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t46,\n\t109,\n\t105,\n\t110,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t46,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t45,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t41,\n\t59,\n\t32,\n\t114,\n\t101,\n\t116,\n\t117,\n\t114,\n\t110,\n\t32,\n\t102,\n\t97,\n\t108,\n\t115,\n\t101,\n\t59,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t100,\n\t101,\n\t99,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t32,\n\t115,\n\t99,\n\t114,\n\t111,\n\t108,\n\t108,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t110,\n\t111,\n\t34,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t45,\n\t99,\n\t111,\n\t108,\n\t108,\n\t97,\n\t112,\n\t115,\n\t101,\n\t58,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t66,\n\t97,\n\t104,\n\t97,\n\t115,\n\t97,\n\t32,\n\t73,\n\t110,\n\t100,\n\t111,\n\t110,\n\t101,\n\t115,\n\t105,\n\t97,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t60,\n\t116,\n\t101,\n\t120,\n\t116,\n\t32,\n\t120,\n\t109,\n\t108,\n\t58,\n\t115,\n\t112,\n\t97,\n\t99,\n\t101,\n\t61,\n\t46,\n\t103,\n\t105,\n\t102,\n\t34,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t60,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t10,\n\t111,\n\t118,\n\t101,\n\t114,\n\t102,\n\t108,\n\t111,\n\t119,\n\t58,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t59,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t97,\n\t100,\n\t100,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t76,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t101,\n\t114,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t115,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t47,\n\t102,\n\t97,\n\t118,\n\t105,\n\t99,\n\t111,\n\t110,\n\t46,\n\t105,\n\t99,\n\t111,\n\t34,\n\t32,\n\t47,\n\t62,\n\t111,\n\t112,\n\t101,\n\t114,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t115,\n\t121,\n\t115,\n\t116,\n\t101,\n\t109,\n\t34,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t49,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t62,\n\t83,\n\t116,\n\t97,\n\t116,\n\t101,\n\t32,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t108,\n\t101,\n\t102,\n\t116,\n\t59,\n\t10,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t119,\n\t114,\n\t105,\n\t116,\n\t101,\n\t40,\n\t44,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t41,\n\t59,\n\t13,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t60,\n\t34,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t59,\n\t111,\n\t118,\n\t101,\n\t114,\n\t102,\n\t108,\n\t111,\n\t119,\n\t58,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t110,\n\t32,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t32,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t9,\n\t9,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t32,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t34,\n\t62,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t10,\n\t32,\n\t32,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t32,\n\t123,\n\t116,\n\t104,\n\t101,\n\t32,\n\t49,\n\t53,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t46,\n\t112,\n\t114,\n\t101,\n\t118,\n\t101,\n\t110,\n\t116,\n\t68,\n\t101,\n\t102,\n\t97,\n\t117,\n\t108,\n\t116,\n\t40,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t66,\n\t121,\n\t122,\n\t97,\n\t110,\n\t116,\n\t105,\n\t110,\n\t101,\n\t32,\n\t69,\n\t109,\n\t112,\n\t105,\n\t114,\n\t101,\n\t46,\n\t106,\n\t112,\n\t103,\n\t124,\n\t116,\n\t104,\n\t117,\n\t109,\n\t98,\n\t124,\n\t108,\n\t101,\n\t102,\n\t116,\n\t124,\n\t118,\n\t97,\n\t115,\n\t116,\n\t32,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t109,\n\t97,\n\t106,\n\t111,\n\t114,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t32,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t61,\n\t34,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t34,\n\t62,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t32,\n\t80,\n\t114,\n\t101,\n\t115,\n\t115,\n\t100,\n\t111,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t83,\n\t101,\n\t99,\n\t111,\n\t110,\n\t100,\n\t32,\n\t87,\n\t111,\n\t114,\n\t108,\n\t100,\n\t32,\n\t87,\n\t97,\n\t114,\n\t100,\n\t105,\n\t115,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t115,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t105,\n\t122,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t110,\n\t111,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t34,\n\t62,\n\t100,\n\t101,\n\t114,\n\t105,\n\t118,\n\t101,\n\t115,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t97,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t97,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t32,\n\t99,\n\t111,\n\t109,\n\t98,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t58,\n\t49,\n\t48,\n\t48,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t45,\n\t115,\n\t112,\n\t101,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t101,\n\t114,\n\t32,\n\t115,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t120,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t68,\n\t101,\n\t109,\n\t111,\n\t99,\n\t114,\n\t97,\n\t116,\n\t105,\n\t99,\n\t32,\n\t80,\n\t97,\n\t114,\n\t116,\n\t121,\n\t34,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t70,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t114,\n\t101,\n\t97,\n\t115,\n\t111,\n\t110,\n\t44,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t9,\n\t115,\n\t66,\n\t121,\n\t84,\n\t97,\n\t103,\n\t78,\n\t97,\n\t109,\n\t101,\n\t40,\n\t115,\n\t41,\n\t91,\n\t48,\n\t93,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t60,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t39,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t39,\n\t39,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t39,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t47,\n\t112,\n\t97,\n\t103,\n\t101,\n\t62,\n\t10,\n\t32,\n\t32,\n\t60,\n\t112,\n\t97,\n\t103,\n\t101,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t116,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t98,\n\t97,\n\t104,\n\t97,\n\t115,\n\t97,\n\t32,\n\t73,\n\t110,\n\t100,\n\t111,\n\t110,\n\t101,\n\t115,\n\t105,\n\t97,\n\t101,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t40,\n\t115,\n\t105,\n\t109,\n\t112,\n\t108,\n\t101,\n\t41,\n\t206,\n\t149,\n\t206,\n\t187,\n\t206,\n\t187,\n\t206,\n\t183,\n\t206,\n\t189,\n\t206,\n\t185,\n\t206,\n\t186,\n\t206,\n\t172,\n\t209,\n\t133,\n\t209,\n\t128,\n\t208,\n\t178,\n\t208,\n\t176,\n\t209,\n\t130,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t191,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t178,\n\t208,\n\t187,\n\t209,\n\t143,\n\t208,\n\t181,\n\t209,\n\t130,\n\t209,\n\t129,\n\t209,\n\t143,\n\t208,\n\t148,\n\t208,\n\t190,\n\t208,\n\t177,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t140,\n\t209,\n\t135,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t181,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t178,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t152,\n\t208,\n\t189,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t189,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t158,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t189,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t134,\n\t209,\n\t139,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t135,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t181,\n\t209,\n\t131,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t184,\n\t209,\n\t143,\n\t209,\n\t133,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t177,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t188,\n\t209,\n\t139,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t187,\n\t209,\n\t131,\n\t209,\n\t135,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t140,\n\t209,\n\t143,\n\t208,\n\t178,\n\t208,\n\t187,\n\t209,\n\t143,\n\t209,\n\t142,\n\t209,\n\t130,\n\t209,\n\t129,\n\t209,\n\t143,\n\t208,\n\t189,\n\t208,\n\t176,\n\t208,\n\t184,\n\t208,\n\t177,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t181,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t191,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t178,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t180,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t176,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t182,\n\t217,\n\t138,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t166,\n\t217,\n\t138,\n\t216,\n\t179,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t134,\n\t216,\n\t170,\n\t217,\n\t130,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t167,\n\t216,\n\t170,\n\t217,\n\t131,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t179,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t131,\n\t216,\n\t170,\n\t217,\n\t136,\n\t216,\n\t168,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t179,\n\t216,\n\t185,\n\t217,\n\t136,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t216,\n\t173,\n\t216,\n\t181,\n\t216,\n\t167,\n\t216,\n\t166,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t185,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t181,\n\t217,\n\t136,\n\t216,\n\t170,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t177,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t170,\n\t216,\n\t181,\n\t216,\n\t167,\n\t217,\n\t133,\n\t217,\n\t138,\n\t217,\n\t133,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t165,\n\t216,\n\t179,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t133,\n\t217,\n\t138,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t177,\n\t216,\n\t166,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t170,\n\t114,\n\t111,\n\t98,\n\t111,\n\t116,\n\t115,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t34,\n\t62,\n\t116,\n\t104,\n\t101,\n\t32,\n\t85,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t83,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t46,\n\t106,\n\t112,\n\t103,\n\t124,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t124,\n\t116,\n\t104,\n\t117,\n\t109,\n\t98,\n\t124,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t60,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t112,\n\t114,\n\t111,\n\t116,\n\t111,\n\t99,\n\t111,\n\t108,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t115,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t119,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t98,\n\t111,\n\t108,\n\t100,\n\t59,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t58,\n\t48,\n\t59,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t58,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t110,\n\t111,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t34,\n\t32,\n\t80,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t119,\n\t101,\n\t110,\n\t116,\n\t105,\n\t101,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t101,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t62,\n\t10,\n\t32,\n\t32,\n\t60,\n\t47,\n\t112,\n\t97,\n\t103,\n\t101,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t101,\n\t116,\n\t32,\n\t69,\n\t120,\n\t112,\n\t108,\n\t111,\n\t114,\n\t101,\n\t114,\n\t97,\n\t46,\n\t97,\n\t115,\n\t121,\n\t110,\n\t99,\n\t32,\n\t61,\n\t32,\n\t116,\n\t114,\n\t117,\n\t101,\n\t59,\n\t13,\n\t10,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t34,\n\t62,\n\t34,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t115,\n\t58,\n\t47,\n\t47,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t34,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t60,\n\t100,\n\t101,\n\t114,\n\t105,\n\t118,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t97,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t10,\n\t60,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t10,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t61,\n\t34,\n\t65,\n\t114,\n\t105,\n\t97,\n\t108,\n\t44,\n\t32,\n\t72,\n\t101,\n\t108,\n\t118,\n\t101,\n\t116,\n\t105,\n\t99,\n\t97,\n\t44,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t101,\n\t115,\n\t116,\n\t100,\n\t62,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t60,\n\t47,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t62,\n\t60,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t112,\n\t114,\n\t101,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t119,\n\t114,\n\t105,\n\t116,\n\t101,\n\t40,\n\t39,\n\t60,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t34,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t62,\n\t10,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t114,\n\t101,\n\t118,\n\t101,\n\t97,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t101,\n\t108,\n\t101,\n\t118,\n\t105,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t115,\n\t101,\n\t114,\n\t105,\n\t101,\n\t115,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t110,\n\t111,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t34,\n\t62,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t62,\n\t99,\n\t108,\n\t97,\n\t105,\n\t109,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t116,\n\t116,\n\t112,\n\t37,\n\t51,\n\t65,\n\t37,\n\t50,\n\t70,\n\t37,\n\t50,\n\t70,\n\t119,\n\t119,\n\t119,\n\t46,\n\t109,\n\t97,\n\t110,\n\t105,\n\t102,\n\t101,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t80,\n\t114,\n\t105,\n\t109,\n\t101,\n\t32,\n\t77,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t102,\n\t105,\n\t120,\n\t34,\n\t62,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t13,\n\t10,\n\t116,\n\t104,\n\t114,\n\t101,\n\t101,\n\t45,\n\t100,\n\t105,\n\t109,\n\t101,\n\t110,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t67,\n\t104,\n\t117,\n\t114,\n\t99,\n\t104,\n\t32,\n\t111,\n\t102,\n\t32,\n\t69,\n\t110,\n\t103,\n\t108,\n\t97,\n\t110,\n\t100,\n\t111,\n\t102,\n\t32,\n\t78,\n\t111,\n\t114,\n\t116,\n\t104,\n\t32,\n\t67,\n\t97,\n\t114,\n\t111,\n\t108,\n\t105,\n\t110,\n\t97,\n\t115,\n\t113,\n\t117,\n\t97,\n\t114,\n\t101,\n\t32,\n\t107,\n\t105,\n\t108,\n\t111,\n\t109,\n\t101,\n\t116,\n\t114,\n\t101,\n\t115,\n\t46,\n\t97,\n\t100,\n\t100,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t76,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t101,\n\t114,\n\t100,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t99,\n\t116,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t108,\n\t121,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t80,\n\t104,\n\t111,\n\t110,\n\t101,\n\t116,\n\t105,\n\t99,\n\t32,\n\t65,\n\t108,\n\t112,\n\t104,\n\t97,\n\t98,\n\t101,\n\t116,\n\t100,\n\t101,\n\t99,\n\t108,\n\t97,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t66,\n\t101,\n\t110,\n\t106,\n\t97,\n\t109,\n\t105,\n\t110,\n\t32,\n\t70,\n\t114,\n\t97,\n\t110,\n\t107,\n\t108,\n\t105,\n\t110,\n\t114,\n\t111,\n\t108,\n\t101,\n\t45,\n\t112,\n\t108,\n\t97,\n\t121,\n\t105,\n\t110,\n\t103,\n\t32,\n\t103,\n\t97,\n\t109,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t87,\n\t101,\n\t115,\n\t116,\n\t101,\n\t114,\n\t110,\n\t32,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t112,\n\t101,\n\t114,\n\t115,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t101,\n\t114,\n\t80,\n\t114,\n\t111,\n\t106,\n\t101,\n\t99,\n\t116,\n\t32,\n\t71,\n\t117,\n\t116,\n\t101,\n\t110,\n\t98,\n\t101,\n\t114,\n\t103,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t108,\n\t101,\n\t115,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t112,\n\t114,\n\t111,\n\t112,\n\t111,\n\t115,\n\t101,\n\t100,\n\t116,\n\t111,\n\t103,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t105,\n\t110,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t109,\n\t105,\n\t110,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t115,\n\t47,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t110,\n\t97,\n\t116,\n\t117,\n\t114,\n\t97,\n\t108,\n\t32,\n\t114,\n\t101,\n\t115,\n\t111,\n\t117,\n\t114,\n\t99,\n\t101,\n\t115,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t105,\n\t102,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t99,\n\t97,\n\t110,\n\t32,\n\t98,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t113,\n\t117,\n\t97,\n\t110,\n\t116,\n\t117,\n\t109,\n\t32,\n\t109,\n\t101,\n\t99,\n\t104,\n\t97,\n\t110,\n\t105,\n\t99,\n\t115,\n\t78,\n\t101,\n\t118,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t108,\n\t101,\n\t115,\n\t115,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t105,\n\t108,\n\t108,\n\t105,\n\t111,\n\t110,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t32,\n\t97,\n\t103,\n\t111,\n\t60,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t13,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t13,\n\t206,\n\t149,\n\t206,\n\t187,\n\t206,\n\t187,\n\t206,\n\t183,\n\t206,\n\t189,\n\t206,\n\t185,\n\t206,\n\t186,\n\t206,\n\t172,\n\t10,\n\t116,\n\t97,\n\t107,\n\t101,\n\t32,\n\t97,\n\t100,\n\t118,\n\t97,\n\t110,\n\t116,\n\t97,\n\t103,\n\t101,\n\t32,\n\t111,\n\t102,\n\t97,\n\t110,\n\t100,\n\t44,\n\t32,\n\t97,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t97,\n\t116,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t77,\n\t105,\n\t99,\n\t114,\n\t111,\n\t115,\n\t111,\n\t102,\n\t116,\n\t32,\n\t87,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t115,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t111,\n\t108,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t108,\n\t121,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t110,\n\t111,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t111,\n\t117,\n\t115,\n\t97,\n\t110,\n\t100,\n\t115,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t97,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t46,\n\t114,\n\t101,\n\t97,\n\t99,\n\t104,\n\t105,\n\t110,\n\t103,\n\t32,\n\t109,\n\t105,\n\t108,\n\t105,\n\t116,\n\t97,\n\t114,\n\t121,\n\t105,\n\t115,\n\t111,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t112,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t79,\n\t108,\n\t100,\n\t32,\n\t84,\n\t101,\n\t115,\n\t116,\n\t97,\n\t109,\n\t101,\n\t110,\n\t116,\n\t65,\n\t102,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t32,\n\t65,\n\t109,\n\t101,\n\t114,\n\t105,\n\t99,\n\t97,\n\t110,\n\t115,\n\t105,\n\t110,\n\t115,\n\t101,\n\t114,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t101,\n\t112,\n\t97,\n\t114,\n\t97,\n\t116,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t109,\n\t101,\n\t116,\n\t114,\n\t111,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t97,\n\t110,\n\t32,\n\t97,\n\t114,\n\t101,\n\t97,\n\t109,\n\t97,\n\t107,\n\t101,\n\t115,\n\t32,\n\t105,\n\t116,\n\t32,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t97,\n\t99,\n\t107,\n\t110,\n\t111,\n\t119,\n\t108,\n\t101,\n\t100,\n\t103,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t114,\n\t103,\n\t117,\n\t97,\n\t98,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t62,\n\t10,\n\t116,\n\t104,\n\t101,\n\t32,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t65,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t99,\n\t111,\n\t105,\n\t110,\n\t99,\n\t105,\n\t100,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t119,\n\t111,\n\t45,\n\t116,\n\t104,\n\t105,\n\t114,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t68,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t44,\n\t100,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t97,\n\t110,\n\t110,\n\t111,\n\t117,\n\t110,\n\t99,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t97,\n\t110,\n\t100,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t108,\n\t121,\n\t98,\n\t101,\n\t108,\n\t105,\n\t101,\n\t118,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t115,\n\t99,\n\t105,\n\t111,\n\t117,\n\t115,\n\t110,\n\t101,\n\t115,\n\t115,\n\t32,\n\t97,\n\t110,\n\t100,\n\t102,\n\t111,\n\t114,\n\t109,\n\t101,\n\t114,\n\t108,\n\t121,\n\t32,\n\t107,\n\t110,\n\t111,\n\t119,\n\t110,\n\t32,\n\t97,\n\t115,\n\t115,\n\t117,\n\t114,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t32,\n\t97,\n\t112,\n\t112,\n\t101,\n\t97,\n\t114,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t111,\n\t99,\n\t99,\n\t97,\n\t115,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t117,\n\t115,\n\t101,\n\t100,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t97,\n\t98,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t101,\n\t59,\n\t34,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t32,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t118,\n\t101,\n\t59,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t59,\n\t106,\n\t97,\n\t120,\n\t47,\n\t108,\n\t105,\n\t98,\n\t115,\n\t47,\n\t106,\n\t113,\n\t117,\n\t101,\n\t114,\n\t121,\n\t47,\n\t49,\n\t46,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t45,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t35,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t47,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t61,\n\t34,\n\t80,\n\t114,\n\t105,\n\t118,\n\t97,\n\t99,\n\t121,\n\t32,\n\t80,\n\t111,\n\t108,\n\t105,\n\t99,\n\t121,\n\t60,\n\t47,\n\t97,\n\t62,\n\t101,\n\t40,\n\t34,\n\t37,\n\t51,\n\t67,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t39,\n\t34,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t62,\n\t79,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t104,\n\t97,\n\t110,\n\t100,\n\t44,\n\t46,\n\t106,\n\t112,\n\t103,\n\t124,\n\t116,\n\t104,\n\t117,\n\t109,\n\t98,\n\t124,\n\t114,\n\t105,\n\t103,\n\t104,\n\t116,\n\t124,\n\t50,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t110,\n\t105,\n\t110,\n\t101,\n\t116,\n\t101,\n\t101,\n\t110,\n\t116,\n\t104,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t117,\n\t114,\n\t121,\n\t60,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t13,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t13,\n\t10,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t115,\n\t59,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t119,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t32,\n\t98,\n\t111,\n\t108,\n\t100,\n\t59,\n\t32,\n\t65,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t34,\n\t32,\n\t102,\n\t114,\n\t97,\n\t109,\n\t101,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t34,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t52,\n\t47,\n\t108,\n\t111,\n\t111,\n\t115,\n\t101,\n\t46,\n\t100,\n\t116,\n\t100,\n\t34,\n\t62,\n\t10,\n\t100,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t105,\n\t115,\n\t32,\n\t112,\n\t101,\n\t114,\n\t105,\n\t111,\n\t100,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t60,\n\t47,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t62,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t108,\n\t121,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t32,\n\t116,\n\t105,\n\t109,\n\t101,\n\t59,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t119,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t98,\n\t111,\n\t108,\n\t100,\n\t59,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t111,\n\t110,\n\t114,\n\t101,\n\t97,\n\t100,\n\t121,\n\t115,\n\t116,\n\t97,\n\t116,\n\t101,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t9,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t32,\n\t70,\n\t111,\n\t114,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t32,\n\t119,\n\t105,\n\t100,\n\t101,\n\t32,\n\t118,\n\t97,\n\t114,\n\t105,\n\t101,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t60,\n\t33,\n\t68,\n\t79,\n\t67,\n\t84,\n\t89,\n\t80,\n\t69,\n\t32,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t13,\n\t10,\n\t60,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t34,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t108,\n\t101,\n\t102,\n\t116,\n\t59,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t114,\n\t110,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t61,\n\t104,\n\t116,\n\t116,\n\t112,\n\t37,\n\t51,\n\t65,\n\t37,\n\t50,\n\t70,\n\t37,\n\t50,\n\t70,\n\t119,\n\t119,\n\t119,\n\t46,\n\t105,\n\t110,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t114,\n\t32,\n\t99,\n\t117,\n\t108,\n\t116,\n\t117,\n\t114,\n\t101,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t47,\n\t62,\n\t105,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t32,\n\t116,\n\t111,\n\t32,\n\t72,\n\t97,\n\t114,\n\t118,\n\t97,\n\t114,\n\t100,\n\t32,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t97,\n\t105,\n\t110,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t79,\n\t120,\n\t102,\n\t111,\n\t114,\n\t100,\n\t32,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t32,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t107,\n\t101,\n\t121,\n\t119,\n\t111,\n\t114,\n\t100,\n\t115,\n\t34,\n\t32,\n\t99,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t116,\n\t104,\n\t101,\n\t32,\n\t85,\n\t110,\n\t105,\n\t116,\n\t101,\n\t100,\n\t32,\n\t75,\n\t105,\n\t110,\n\t103,\n\t100,\n\t111,\n\t109,\n\t102,\n\t101,\n\t100,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t103,\n\t111,\n\t118,\n\t101,\n\t114,\n\t110,\n\t109,\n\t101,\n\t110,\n\t116,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t32,\n\t100,\n\t101,\n\t112,\n\t101,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t104,\n\t101,\n\t97,\n\t100,\n\t101,\n\t114,\n\t46,\n\t109,\n\t105,\n\t110,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t100,\n\t101,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t108,\n\t105,\n\t103,\n\t104,\n\t116,\n\t108,\n\t121,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t105,\n\t110,\n\t32,\n\t97,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t116,\n\t101,\n\t108,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t105,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t108,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t101,\n\t115,\n\t112,\n\t101,\n\t99,\n\t105,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t97,\n\t110,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t115,\n\t116,\n\t97,\n\t116,\n\t105,\n\t99,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t34,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t97,\n\t32,\n\t108,\n\t97,\n\t114,\n\t103,\n\t101,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t84,\n\t101,\n\t108,\n\t101,\n\t99,\n\t111,\n\t109,\n\t109,\n\t117,\n\t110,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t110,\n\t111,\n\t102,\n\t111,\n\t108,\n\t108,\n\t111,\n\t119,\n\t34,\n\t32,\n\t116,\n\t72,\n\t111,\n\t108,\n\t121,\n\t32,\n\t82,\n\t111,\n\t109,\n\t97,\n\t110,\n\t32,\n\t69,\n\t109,\n\t112,\n\t101,\n\t114,\n\t111,\n\t114,\n\t97,\n\t108,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t101,\n\t120,\n\t99,\n\t108,\n\t117,\n\t115,\n\t105,\n\t118,\n\t101,\n\t108,\n\t121,\n\t34,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t97,\n\t108,\n\t116,\n\t61,\n\t34,\n\t83,\n\t101,\n\t99,\n\t114,\n\t101,\n\t116,\n\t97,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t83,\n\t116,\n\t97,\n\t116,\n\t101,\n\t99,\n\t117,\n\t108,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t67,\n\t73,\n\t65,\n\t32,\n\t87,\n\t111,\n\t114,\n\t108,\n\t100,\n\t32,\n\t70,\n\t97,\n\t99,\n\t116,\n\t98,\n\t111,\n\t111,\n\t107,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t97,\n\t110,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t97,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t45,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t101,\n\t109,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t116,\n\t104,\n\t101,\n\t32,\n\t65,\n\t116,\n\t108,\n\t97,\n\t110,\n\t116,\n\t105,\n\t99,\n\t32,\n\t79,\n\t99,\n\t101,\n\t97,\n\t110,\n\t115,\n\t116,\n\t114,\n\t105,\n\t99,\n\t116,\n\t108,\n\t121,\n\t32,\n\t115,\n\t112,\n\t101,\n\t97,\n\t107,\n\t105,\n\t110,\n\t103,\n\t44,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t108,\n\t121,\n\t32,\n\t98,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t116,\n\t104,\n\t101,\n\t32,\n\t79,\n\t116,\n\t116,\n\t111,\n\t109,\n\t97,\n\t110,\n\t32,\n\t69,\n\t109,\n\t112,\n\t105,\n\t114,\n\t101,\n\t62,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t65,\n\t110,\n\t32,\n\t73,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t99,\n\t111,\n\t110,\n\t115,\n\t101,\n\t113,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t117,\n\t114,\n\t101,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t67,\n\t111,\n\t110,\n\t102,\n\t101,\n\t100,\n\t101,\n\t114,\n\t97,\n\t116,\n\t101,\n\t32,\n\t83,\n\t116,\n\t97,\n\t116,\n\t101,\n\t115,\n\t105,\n\t110,\n\t100,\n\t105,\n\t103,\n\t101,\n\t110,\n\t111,\n\t117,\n\t115,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t115,\n\t80,\n\t114,\n\t111,\n\t99,\n\t101,\n\t101,\n\t100,\n\t105,\n\t110,\n\t103,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t105,\n\t101,\n\t115,\n\t32,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t105,\n\t110,\n\t118,\n\t111,\n\t108,\n\t118,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t105,\n\t118,\n\t105,\n\t100,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t114,\n\t101,\n\t101,\n\t97,\n\t100,\n\t106,\n\t97,\n\t99,\n\t101,\n\t110,\n\t116,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t105,\n\t115,\n\t32,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t100,\n\t105,\n\t115,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t108,\n\t108,\n\t97,\n\t98,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t119,\n\t105,\n\t100,\n\t101,\n\t108,\n\t121,\n\t32,\n\t114,\n\t101,\n\t103,\n\t97,\n\t114,\n\t100,\n\t101,\n\t100,\n\t32,\n\t97,\n\t115,\n\t104,\n\t105,\n\t115,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t109,\n\t112,\n\t111,\n\t114,\n\t97,\n\t114,\n\t105,\n\t101,\n\t115,\n\t102,\n\t111,\n\t117,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t109,\n\t101,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t68,\n\t111,\n\t109,\n\t105,\n\t110,\n\t105,\n\t99,\n\t97,\n\t110,\n\t32,\n\t82,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t97,\n\t99,\n\t99,\n\t101,\n\t112,\n\t116,\n\t101,\n\t100,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t111,\n\t115,\n\t115,\n\t105,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t121,\n\t32,\n\t111,\n\t102,\n\t97,\n\t114,\n\t101,\n\t32,\n\t97,\n\t108,\n\t115,\n\t111,\n\t32,\n\t97,\n\t118,\n\t97,\n\t105,\n\t108,\n\t97,\n\t98,\n\t108,\n\t101,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t114,\n\t101,\n\t115,\n\t116,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t105,\n\t115,\n\t32,\n\t97,\n\t108,\n\t109,\n\t111,\n\t115,\n\t116,\n\t32,\n\t101,\n\t110,\n\t116,\n\t105,\n\t114,\n\t101,\n\t108,\n\t121,\n\t112,\n\t97,\n\t115,\n\t115,\n\t101,\n\t115,\n\t32,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t101,\n\t100,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t101,\n\t114,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t118,\n\t105,\n\t100,\n\t101,\n\t111,\n\t71,\n\t101,\n\t114,\n\t109,\n\t97,\n\t110,\n\t105,\n\t99,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t115,\n\t32,\n\t97,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t108,\n\t121,\n\t32,\n\t97,\n\t102,\n\t116,\n\t101,\n\t114,\n\t119,\n\t97,\n\t114,\n\t100,\n\t115,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t115,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t114,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t66,\n\t111,\n\t97,\n\t114,\n\t100,\n\t32,\n\t111,\n\t102,\n\t32,\n\t68,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t111,\n\t114,\n\t115,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t115,\n\t101,\n\t97,\n\t114,\n\t99,\n\t104,\n\t124,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t73,\n\t110,\n\t32,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t77,\n\t117,\n\t108,\n\t116,\n\t105,\n\t112,\n\t108,\n\t101,\n\t32,\n\t102,\n\t111,\n\t111,\n\t116,\n\t110,\n\t111,\n\t116,\n\t101,\n\t115,\n\t111,\n\t114,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t115,\n\t117,\n\t98,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t116,\n\t104,\n\t111,\n\t117,\n\t115,\n\t97,\n\t110,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t121,\n\t101,\n\t97,\n\t114,\n\t115,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t13,\n\t10,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t105,\n\t110,\n\t100,\n\t101,\n\t120,\n\t46,\n\t112,\n\t104,\n\t112,\n\t119,\n\t97,\n\t115,\n\t32,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t109,\n\t105,\n\t110,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t116,\n\t101,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t32,\n\t115,\n\t116,\n\t114,\n\t111,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t116,\n\t111,\n\t112,\n\t58,\n\t114,\n\t101,\n\t112,\n\t114,\n\t101,\n\t115,\n\t101,\n\t110,\n\t116,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t103,\n\t114,\n\t97,\n\t100,\n\t117,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t32,\n\t116,\n\t104,\n\t101,\n\t84,\n\t114,\n\t97,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t40,\n\t34,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t41,\n\t59,\n\t72,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t115,\n\t105,\n\t110,\n\t99,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t108,\n\t101,\n\t102,\n\t116,\n\t59,\n\t32,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t108,\n\t101,\n\t102,\n\t116,\n\t58,\n\t112,\n\t114,\n\t111,\n\t116,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t97,\n\t103,\n\t97,\n\t105,\n\t110,\n\t115,\n\t116,\n\t48,\n\t59,\n\t32,\n\t118,\n\t101,\n\t114,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t85,\n\t110,\n\t102,\n\t111,\n\t114,\n\t116,\n\t117,\n\t110,\n\t97,\n\t116,\n\t101,\n\t108,\n\t121,\n\t44,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t47,\n\t120,\n\t45,\n\t105,\n\t99,\n\t111,\n\t110,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t108,\n\t101,\n\t97,\n\t114,\n\t102,\n\t105,\n\t120,\n\t34,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t102,\n\t111,\n\t111,\n\t116,\n\t101,\n\t114,\n\t9,\n\t9,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t9,\n\t9,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t116,\n\t104,\n\t101,\n\t32,\n\t109,\n\t111,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t112,\n\t105,\n\t99,\n\t116,\n\t117,\n\t114,\n\t101,\n\t208,\n\t145,\n\t209,\n\t138,\n\t208,\n\t187,\n\t208,\n\t179,\n\t208,\n\t176,\n\t209,\n\t128,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t177,\n\t209,\n\t138,\n\t208,\n\t187,\n\t208,\n\t179,\n\t208,\n\t176,\n\t209,\n\t128,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t164,\n\t208,\n\t181,\n\t208,\n\t180,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t176,\n\t209,\n\t134,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t189,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t186,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t137,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t137,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t179,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t188,\n\t209,\n\t139,\n\t208,\n\t158,\n\t209,\n\t130,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t177,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t191,\n\t208,\n\t187,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t176,\n\t208,\n\t187,\n\t209,\n\t139,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t183,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t187,\n\t209,\n\t143,\n\t208,\n\t181,\n\t209,\n\t130,\n\t208,\n\t191,\n\t208,\n\t190,\n\t209,\n\t129,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t180,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t135,\n\t208,\n\t189,\n\t209,\n\t139,\n\t209,\n\t133,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t180,\n\t209,\n\t131,\n\t208,\n\t186,\n\t209,\n\t134,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t179,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t188,\n\t208,\n\t188,\n\t208,\n\t176,\n\t208,\n\t191,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t140,\n\t209,\n\t142,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t133,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t184,\n\t209,\n\t130,\n\t209,\n\t129,\n\t209,\n\t143,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t177,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t189,\n\t208,\n\t190,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t181,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t188,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t144,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t186,\n\t209,\n\t129,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t180,\n\t209,\n\t128,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t167,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t181,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t160,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t145,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t171,\n\t224,\n\t164,\n\t188,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t136,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t160,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t188,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t182,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t163,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t163,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t154,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t154,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t167,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t166,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t167,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t185,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t172,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t143,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t150,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t167,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t188,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t181,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t150,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t182,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t134,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t216,\n\t177,\n\t217,\n\t131,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t217,\n\t134,\n\t216,\n\t170,\n\t216,\n\t175,\n\t217,\n\t138,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t131,\n\t217,\n\t133,\n\t216,\n\t168,\n\t217,\n\t138,\n\t217,\n\t136,\n\t216,\n\t170,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t180,\n\t216,\n\t167,\n\t217,\n\t135,\n\t216,\n\t175,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t185,\n\t216,\n\t175,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t178,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t177,\n\t216,\n\t185,\n\t216,\n\t175,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t177,\n\t216,\n\t175,\n\t217,\n\t136,\n\t216,\n\t175,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t165,\n\t216,\n\t179,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t133,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t129,\n\t217,\n\t136,\n\t216,\n\t170,\n\t217,\n\t136,\n\t216,\n\t180,\n\t217,\n\t136,\n\t216,\n\t168,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t179,\n\t216,\n\t167,\n\t216,\n\t168,\n\t217,\n\t130,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t185,\n\t217,\n\t132,\n\t217,\n\t136,\n\t217,\n\t133,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t179,\n\t217,\n\t132,\n\t216,\n\t179,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t172,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t129,\n\t217,\n\t138,\n\t217,\n\t131,\n\t216,\n\t179,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t179,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t133,\n\t217,\n\t138,\n\t216,\n\t169,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t181,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t170,\n\t107,\n\t101,\n\t121,\n\t119,\n\t111,\n\t114,\n\t100,\n\t115,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t119,\n\t51,\n\t46,\n\t111,\n\t114,\n\t103,\n\t47,\n\t49,\n\t57,\n\t57,\n\t57,\n\t47,\n\t120,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t62,\n\t60,\n\t97,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t32,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t59,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t34,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t62,\n\t60,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t97,\n\t117,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t61,\n\t34,\n\t111,\n\t102,\n\t102,\n\t34,\n\t32,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t32,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t59,\n\t116,\n\t111,\n\t32,\n\t108,\n\t97,\n\t115,\n\t116,\n\t32,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t111,\n\t110,\n\t32,\n\t98,\n\t121,\n\t32,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t45,\n\t99,\n\t111,\n\t108,\n\t111,\n\t114,\n\t58,\n\t32,\n\t35,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t105,\n\t100,\n\t61,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t35,\n\t34,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t34,\n\t62,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t61,\n\t34,\n\t47,\n\t47,\n\t69,\n\t78,\n\t34,\n\t32,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t119,\n\t101,\n\t110,\n\t99,\n\t111,\n\t100,\n\t101,\n\t85,\n\t82,\n\t73,\n\t67,\n\t111,\n\t109,\n\t112,\n\t111,\n\t110,\n\t101,\n\t110,\n\t116,\n\t40,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t58,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t119,\n\t114,\n\t105,\n\t116,\n\t101,\n\t40,\n\t39,\n\t60,\n\t115,\n\t99,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t32,\n\t97,\n\t98,\n\t115,\n\t111,\n\t108,\n\t117,\n\t116,\n\t101,\n\t59,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t45,\n\t116,\n\t111,\n\t112,\n\t58,\n\t46,\n\t109,\n\t105,\n\t110,\n\t46,\n\t106,\n\t115,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t119,\n\t51,\n\t46,\n\t111,\n\t114,\n\t103,\n\t47,\n\t49,\n\t57,\n\t57,\n\t57,\n\t47,\n\t120,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t32,\n\t10,\n\t13,\n\t10,\n\t60,\n\t47,\n\t98,\n\t111,\n\t100,\n\t121,\n\t62,\n\t13,\n\t10,\n\t60,\n\t47,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t100,\n\t105,\n\t115,\n\t116,\n\t105,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t47,\n\t34,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t62,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t101,\n\t110,\n\t99,\n\t111,\n\t100,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t63,\n\t62,\n\t10,\n\t119,\n\t46,\n\t97,\n\t100,\n\t100,\n\t69,\n\t118,\n\t101,\n\t110,\n\t116,\n\t76,\n\t105,\n\t115,\n\t116,\n\t101,\n\t110,\n\t101,\n\t114,\n\t63,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t58,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t121,\n\t61,\n\t34,\n\t111,\n\t103,\n\t58,\n\t116,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t97,\n\t108,\n\t105,\n\t103,\n\t110,\n\t58,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t104,\n\t116,\n\t109,\n\t108,\n\t59,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t105,\n\t115,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t98,\n\t101,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t48,\n\t48,\n\t37,\n\t34,\n\t32,\n\t73,\n\t110,\n\t32,\n\t97,\n\t100,\n\t100,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t73,\n\t116,\n\t32,\n\t105,\n\t115,\n\t32,\n\t105,\n\t109,\n\t112,\n\t111,\n\t114,\n\t116,\n\t97,\n\t110,\n\t116,\n\t32,\n\t116,\n\t111,\n\t32,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t102,\n\t111,\n\t110,\n\t116,\n\t45,\n\t115,\n\t105,\n\t122,\n\t101,\n\t58,\n\t49,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t105,\n\t100,\n\t61,\n\t103,\n\t98,\n\t76,\n\t105,\n\t98,\n\t114,\n\t97,\n\t114,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t67,\n\t111,\n\t110,\n\t103,\n\t114,\n\t101,\n\t115,\n\t115,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t105,\n\t109,\n\t69,\n\t110,\n\t103,\n\t108,\n\t105,\n\t115,\n\t104,\n\t32,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t65,\n\t99,\n\t97,\n\t100,\n\t101,\n\t109,\n\t121,\n\t32,\n\t111,\n\t102,\n\t32,\n\t83,\n\t99,\n\t105,\n\t101,\n\t110,\n\t99,\n\t101,\n\t115,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t99,\n\t111,\n\t110,\n\t115,\n\t116,\n\t114,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t66,\n\t121,\n\t73,\n\t100,\n\t40,\n\t105,\n\t100,\n\t41,\n\t105,\n\t110,\n\t32,\n\t99,\n\t111,\n\t110,\n\t106,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t40,\n\t39,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t41,\n\t59,\n\t32,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t121,\n\t61,\n\t34,\n\t111,\n\t103,\n\t58,\n\t208,\n\t145,\n\t209,\n\t138,\n\t208,\n\t187,\n\t208,\n\t179,\n\t208,\n\t176,\n\t209,\n\t128,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t184,\n\t10,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t62,\n\t80,\n\t114,\n\t105,\n\t118,\n\t97,\n\t99,\n\t121,\n\t32,\n\t80,\n\t111,\n\t108,\n\t105,\n\t99,\n\t121,\n\t60,\n\t47,\n\t97,\n\t62,\n\t97,\n\t100,\n\t109,\n\t105,\n\t110,\n\t105,\n\t115,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t98,\n\t121,\n\t32,\n\t116,\n\t104,\n\t101,\n\t101,\n\t110,\n\t97,\n\t98,\n\t108,\n\t101,\n\t83,\n\t105,\n\t110,\n\t103,\n\t108,\n\t101,\n\t82,\n\t101,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t109,\n\t97,\n\t114,\n\t103,\n\t105,\n\t110,\n\t58,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t62,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t105,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t38,\n\t113,\n\t117,\n\t111,\n\t116,\n\t59,\n\t102,\n\t108,\n\t111,\n\t97,\n\t116,\n\t58,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t97,\n\t115,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t111,\n\t116,\n\t97,\n\t108,\n\t32,\n\t112,\n\t111,\n\t112,\n\t117,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t105,\n\t110,\n\t32,\n\t87,\n\t97,\n\t115,\n\t104,\n\t105,\n\t110,\n\t103,\n\t116,\n\t111,\n\t110,\n\t44,\n\t32,\n\t68,\n\t46,\n\t67,\n\t46,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t45,\n\t97,\n\t109,\n\t111,\n\t110,\n\t103,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t105,\n\t110,\n\t103,\n\t115,\n\t44,\n\t111,\n\t114,\n\t103,\n\t97,\n\t110,\n\t105,\n\t122,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t116,\n\t114,\n\t111,\n\t100,\n\t117,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t105,\n\t100,\n\t101,\n\t110,\n\t116,\n\t105,\n\t102,\n\t105,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t105,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t97,\n\t99,\n\t116,\n\t101,\n\t114,\n\t32,\n\t79,\n\t120,\n\t102,\n\t111,\n\t114,\n\t100,\n\t32,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t32,\n\t109,\n\t105,\n\t115,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t115,\n\t116,\n\t97,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t84,\n\t104,\n\t101,\n\t114,\n\t101,\n\t32,\n\t97,\n\t114,\n\t101,\n\t44,\n\t32,\n\t104,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t47,\n\t67,\n\t111,\n\t108,\n\t117,\n\t109,\n\t98,\n\t105,\n\t97,\n\t32,\n\t85,\n\t110,\n\t105,\n\t118,\n\t101,\n\t114,\n\t115,\n\t105,\n\t116,\n\t121,\n\t101,\n\t120,\n\t112,\n\t97,\n\t110,\n\t100,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t117,\n\t115,\n\t117,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t105,\n\t110,\n\t100,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t115,\n\t117,\n\t103,\n\t103,\n\t101,\n\t115,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t97,\n\t102,\n\t102,\n\t105,\n\t108,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t32,\n\t111,\n\t102,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t62,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t60,\n\t47,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t62,\n\t82,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t32,\n\t111,\n\t102,\n\t32,\n\t73,\n\t114,\n\t101,\n\t108,\n\t97,\n\t110,\n\t100,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t105,\n\t110,\n\t102,\n\t108,\n\t117,\n\t101,\n\t110,\n\t99,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t79,\n\t102,\n\t102,\n\t105,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t119,\n\t101,\n\t98,\n\t115,\n\t105,\n\t116,\n\t101,\n\t32,\n\t111,\n\t102,\n\t104,\n\t101,\n\t97,\n\t100,\n\t113,\n\t117,\n\t97,\n\t114,\n\t116,\n\t101,\n\t114,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t101,\n\t110,\n\t116,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t97,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t105,\n\t109,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t70,\n\t101,\n\t100,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t82,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t32,\n\t111,\n\t102,\n\t98,\n\t101,\n\t99,\n\t97,\n\t109,\n\t101,\n\t32,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t105,\n\t110,\n\t103,\n\t108,\n\t121,\n\t99,\n\t111,\n\t110,\n\t116,\n\t105,\n\t110,\n\t117,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t78,\n\t111,\n\t116,\n\t101,\n\t44,\n\t32,\n\t104,\n\t111,\n\t119,\n\t101,\n\t118,\n\t101,\n\t114,\n\t44,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t115,\n\t105,\n\t109,\n\t105,\n\t108,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t99,\n\t97,\n\t112,\n\t97,\n\t98,\n\t105,\n\t108,\n\t105,\n\t116,\n\t105,\n\t101,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t97,\n\t99,\n\t99,\n\t111,\n\t114,\n\t100,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t110,\n\t116,\n\t115,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t117,\n\t114,\n\t116,\n\t104,\n\t101,\n\t114,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t105,\n\t115,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t104,\n\t105,\n\t115,\n\t32,\n\t121,\n\t111,\n\t117,\n\t110,\n\t103,\n\t101,\n\t114,\n\t32,\n\t98,\n\t114,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t60,\n\t47,\n\t116,\n\t100,\n\t62,\n\t60,\n\t47,\n\t116,\n\t114,\n\t62,\n\t60,\n\t47,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t61,\n\t34,\n\t88,\n\t45,\n\t85,\n\t65,\n\t45,\n\t112,\n\t104,\n\t121,\n\t115,\n\t105,\n\t99,\n\t97,\n\t108,\n\t32,\n\t112,\n\t114,\n\t111,\n\t112,\n\t101,\n\t114,\n\t116,\n\t105,\n\t101,\n\t115,\n\t111,\n\t102,\n\t32,\n\t66,\n\t114,\n\t105,\n\t116,\n\t105,\n\t115,\n\t104,\n\t32,\n\t67,\n\t111,\n\t108,\n\t117,\n\t109,\n\t98,\n\t105,\n\t97,\n\t104,\n\t97,\n\t115,\n\t32,\n\t98,\n\t101,\n\t101,\n\t110,\n\t32,\n\t99,\n\t114,\n\t105,\n\t116,\n\t105,\n\t99,\n\t105,\n\t122,\n\t101,\n\t100,\n\t40,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t113,\n\t117,\n\t101,\n\t115,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t97,\n\t98,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t112,\n\t97,\n\t115,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t48,\n\t34,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t116,\n\t104,\n\t111,\n\t117,\n\t115,\n\t97,\n\t110,\n\t100,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t112,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t114,\n\t101,\n\t100,\n\t105,\n\t114,\n\t101,\n\t99,\n\t116,\n\t115,\n\t32,\n\t104,\n\t101,\n\t114,\n\t101,\n\t46,\n\t32,\n\t70,\n\t111,\n\t114,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t99,\n\t104,\n\t105,\n\t108,\n\t100,\n\t114,\n\t101,\n\t110,\n\t32,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t37,\n\t51,\n\t69,\n\t37,\n\t51,\n\t67,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t37,\n\t51,\n\t69,\n\t34,\n\t41,\n\t41,\n\t59,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t115,\n\t105,\n\t116,\n\t101,\n\t95,\n\t110,\n\t97,\n\t109,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t100,\n\t101,\n\t99,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t32,\n\t110,\n\t111,\n\t110,\n\t101,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t61,\n\t34,\n\t88,\n\t45,\n\t110,\n\t101,\n\t119,\n\t32,\n\t68,\n\t97,\n\t116,\n\t101,\n\t40,\n\t41,\n\t46,\n\t103,\n\t101,\n\t116,\n\t84,\n\t105,\n\t109,\n\t101,\n\t40,\n\t41,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t47,\n\t120,\n\t45,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t61,\n\t34,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t119,\n\t105,\n\t110,\n\t100,\n\t111,\n\t119,\n\t46,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t104,\n\t114,\n\t101,\n\t102,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t58,\n\t45,\n\t45,\n\t62,\n\t13,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t39,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t104,\n\t111,\n\t114,\n\t116,\n\t99,\n\t117,\n\t116,\n\t32,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t13,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t116,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t47,\n\t97,\n\t62,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t32,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t84,\n\t114,\n\t97,\n\t110,\n\t115,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t99,\n\t121,\n\t61,\n\t34,\n\t88,\n\t45,\n\t85,\n\t65,\n\t45,\n\t67,\n\t111,\n\t109,\n\t112,\n\t97,\n\t116,\n\t105,\n\t98,\n\t108,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t104,\n\t105,\n\t112,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t60,\n\t47,\n\t117,\n\t108,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t105,\n\t110,\n\t103,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t113,\n\t34,\n\t60,\n\t116,\n\t97,\n\t98,\n\t108,\n\t101,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t48,\n\t48,\n\t37,\n\t34,\n\t32,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t45,\n\t112,\n\t111,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t34,\n\t32,\n\t98,\n\t111,\n\t114,\n\t100,\n\t101,\n\t114,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t99,\n\t117,\n\t116,\n\t32,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t104,\n\t54,\n\t62,\n\t60,\n\t117,\n\t108,\n\t62,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t32,\n\t32,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t61,\n\t34,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t61,\n\t34,\n\t115,\n\t99,\n\t114,\n\t101,\n\t101,\n\t110,\n\t34,\n\t32,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t115,\n\t105,\n\t98,\n\t108,\n\t101,\n\t32,\n\t102,\n\t111,\n\t114,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t47,\n\t34,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t45,\n\t104,\n\t116,\n\t109,\n\t108,\n\t59,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t32,\n\t97,\n\t108,\n\t108,\n\t111,\n\t119,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t99,\n\t121,\n\t61,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t13,\n\t10,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t61,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t112,\n\t97,\n\t110,\n\t62,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t62,\n\t59,\n\t10,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t115,\n\t111,\n\t109,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t115,\n\t32,\n\t99,\n\t97,\n\t108,\n\t108,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t100,\n\t111,\n\t101,\n\t115,\n\t32,\n\t110,\n\t111,\n\t116,\n\t32,\n\t110,\n\t101,\n\t99,\n\t101,\n\t115,\n\t115,\n\t97,\n\t114,\n\t105,\n\t108,\n\t121,\n\t70,\n\t111,\n\t114,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t32,\n\t60,\n\t33,\n\t68,\n\t79,\n\t67,\n\t84,\n\t89,\n\t80,\n\t69,\n\t32,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t108,\n\t121,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t58,\n\t118,\n\t111,\n\t105,\n\t100,\n\t40,\n\t48,\n\t41,\n\t59,\n\t34,\n\t101,\n\t102,\n\t102,\n\t101,\n\t99,\n\t116,\n\t105,\n\t118,\n\t101,\n\t110,\n\t101,\n\t115,\n\t115,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t97,\n\t117,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t61,\n\t34,\n\t111,\n\t102,\n\t102,\n\t34,\n\t32,\n\t103,\n\t101,\n\t110,\n\t101,\n\t114,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t62,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t34,\n\t62,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t13,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t116,\n\t104,\n\t114,\n\t111,\n\t117,\n\t103,\n\t104,\n\t111,\n\t117,\n\t116,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t119,\n\t111,\n\t114,\n\t108,\n\t100,\n\t99,\n\t111,\n\t109,\n\t109,\n\t111,\n\t110,\n\t32,\n\t109,\n\t105,\n\t115,\n\t99,\n\t111,\n\t110,\n\t99,\n\t101,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t115,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t100,\n\t117,\n\t114,\n\t105,\n\t110,\n\t103,\n\t32,\n\t104,\n\t105,\n\t115,\n\t32,\n\t108,\n\t105,\n\t102,\n\t101,\n\t116,\n\t105,\n\t109,\n\t101,\n\t44,\n\t99,\n\t111,\n\t114,\n\t114,\n\t101,\n\t115,\n\t112,\n\t111,\n\t110,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t47,\n\t120,\n\t45,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t97,\n\t110,\n\t32,\n\t105,\n\t110,\n\t99,\n\t114,\n\t101,\n\t97,\n\t115,\n\t105,\n\t110,\n\t103,\n\t32,\n\t110,\n\t117,\n\t109,\n\t98,\n\t101,\n\t114,\n\t100,\n\t105,\n\t112,\n\t108,\n\t111,\n\t109,\n\t97,\n\t116,\n\t105,\n\t99,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t97,\n\t114,\n\t101,\n\t32,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t34,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t32,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t101,\n\t120,\n\t97,\n\t109,\n\t112,\n\t108,\n\t101,\n\t115,\n\t32,\n\t105,\n\t110,\n\t99,\n\t108,\n\t117,\n\t100,\n\t101,\n\t32,\n\t116,\n\t104,\n\t101,\n\t34,\n\t62,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t105,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t38,\n\t97,\n\t109,\n\t112,\n\t59,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t116,\n\t111,\n\t32,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t101,\n\t32,\n\t119,\n\t104,\n\t101,\n\t116,\n\t104,\n\t101,\n\t114,\n\t113,\n\t117,\n\t105,\n\t116,\n\t101,\n\t32,\n\t100,\n\t105,\n\t102,\n\t102,\n\t101,\n\t114,\n\t101,\n\t110,\n\t116,\n\t32,\n\t102,\n\t114,\n\t111,\n\t109,\n\t109,\n\t97,\n\t114,\n\t107,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t100,\n\t105,\n\t115,\n\t116,\n\t97,\n\t110,\n\t99,\n\t101,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t116,\n\t114,\n\t105,\n\t98,\n\t117,\n\t116,\n\t105,\n\t111,\n\t110,\n\t115,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t99,\n\t111,\n\t110,\n\t102,\n\t108,\n\t105,\n\t99,\n\t116,\n\t32,\n\t98,\n\t101,\n\t116,\n\t119,\n\t101,\n\t101,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t119,\n\t105,\n\t100,\n\t101,\n\t108,\n\t121,\n\t32,\n\t99,\n\t111,\n\t110,\n\t115,\n\t105,\n\t100,\n\t101,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t119,\n\t97,\n\t115,\n\t32,\n\t111,\n\t110,\n\t101,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t102,\n\t105,\n\t114,\n\t115,\n\t116,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t118,\n\t97,\n\t114,\n\t121,\n\t105,\n\t110,\n\t103,\n\t32,\n\t100,\n\t101,\n\t103,\n\t114,\n\t101,\n\t101,\n\t115,\n\t104,\n\t97,\n\t118,\n\t101,\n\t32,\n\t115,\n\t112,\n\t101,\n\t99,\n\t117,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t32,\n\t116,\n\t104,\n\t97,\n\t116,\n\t40,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t112,\n\t97,\n\t114,\n\t116,\n\t105,\n\t99,\n\t105,\n\t112,\n\t97,\n\t116,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t32,\n\t116,\n\t104,\n\t101,\n\t111,\n\t114,\n\t105,\n\t103,\n\t105,\n\t110,\n\t97,\n\t108,\n\t108,\n\t121,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t101,\n\t100,\n\t101,\n\t116,\n\t97,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t34,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t62,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t105,\n\t110,\n\t116,\n\t101,\n\t114,\n\t99,\n\t104,\n\t97,\n\t110,\n\t103,\n\t101,\n\t97,\n\t98,\n\t108,\n\t121,\n\t32,\n\t119,\n\t105,\n\t116,\n\t104,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t99,\n\t108,\n\t111,\n\t115,\n\t101,\n\t108,\n\t121,\n\t32,\n\t114,\n\t101,\n\t108,\n\t97,\n\t116,\n\t101,\n\t100,\n\t115,\n\t111,\n\t99,\n\t105,\n\t97,\n\t108,\n\t32,\n\t97,\n\t110,\n\t100,\n\t32,\n\t112,\n\t111,\n\t108,\n\t105,\n\t116,\n\t105,\n\t99,\n\t97,\n\t108,\n\t116,\n\t104,\n\t97,\n\t116,\n\t32,\n\t119,\n\t111,\n\t117,\n\t108,\n\t100,\n\t32,\n\t111,\n\t116,\n\t104,\n\t101,\n\t114,\n\t119,\n\t105,\n\t115,\n\t101,\n\t112,\n\t101,\n\t114,\n\t112,\n\t101,\n\t110,\n\t100,\n\t105,\n\t99,\n\t117,\n\t108,\n\t97,\n\t114,\n\t32,\n\t116,\n\t111,\n\t32,\n\t116,\n\t104,\n\t101,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t102,\n\t97,\n\t109,\n\t105,\n\t108,\n\t105,\n\t101,\n\t115,\n\t32,\n\t114,\n\t101,\n\t115,\n\t105,\n\t100,\n\t105,\n\t110,\n\t103,\n\t32,\n\t105,\n\t110,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t105,\n\t110,\n\t103,\n\t32,\n\t99,\n\t111,\n\t117,\n\t110,\n\t116,\n\t114,\n\t105,\n\t101,\n\t115,\n\t99,\n\t111,\n\t109,\n\t112,\n\t117,\n\t116,\n\t101,\n\t114,\n\t32,\n\t112,\n\t114,\n\t111,\n\t103,\n\t114,\n\t97,\n\t109,\n\t109,\n\t105,\n\t110,\n\t103,\n\t101,\n\t99,\n\t111,\n\t110,\n\t111,\n\t109,\n\t105,\n\t99,\n\t32,\n\t100,\n\t101,\n\t118,\n\t101,\n\t108,\n\t111,\n\t112,\n\t109,\n\t101,\n\t110,\n\t116,\n\t100,\n\t101,\n\t116,\n\t101,\n\t114,\n\t109,\n\t105,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t102,\n\t111,\n\t114,\n\t32,\n\t109,\n\t111,\n\t114,\n\t101,\n\t32,\n\t105,\n\t110,\n\t102,\n\t111,\n\t114,\n\t109,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t111,\n\t110,\n\t32,\n\t115,\n\t101,\n\t118,\n\t101,\n\t114,\n\t97,\n\t108,\n\t32,\n\t111,\n\t99,\n\t99,\n\t97,\n\t115,\n\t105,\n\t111,\n\t110,\n\t115,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t103,\n\t117,\n\t195,\n\t170,\n\t115,\n\t32,\n\t40,\n\t69,\n\t117,\n\t114,\n\t111,\n\t112,\n\t101,\n\t117,\n\t41,\n\t208,\n\t163,\n\t208,\n\t186,\n\t209,\n\t128,\n\t208,\n\t176,\n\t209,\n\t151,\n\t208,\n\t189,\n\t209,\n\t129,\n\t209,\n\t140,\n\t208,\n\t186,\n\t208,\n\t176,\n\t209,\n\t131,\n\t208,\n\t186,\n\t209,\n\t128,\n\t208,\n\t176,\n\t209,\n\t151,\n\t208,\n\t189,\n\t209,\n\t129,\n\t209,\n\t140,\n\t208,\n\t186,\n\t208,\n\t176,\n\t208,\n\t160,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t129,\n\t208,\n\t184,\n\t208,\n\t185,\n\t209,\n\t129,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t185,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t176,\n\t208,\n\t187,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t134,\n\t208,\n\t184,\n\t208,\n\t184,\n\t209,\n\t131,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t178,\n\t208,\n\t187,\n\t208,\n\t181,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t189,\n\t208,\n\t181,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t133,\n\t208,\n\t190,\n\t208,\n\t180,\n\t208,\n\t184,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t134,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t152,\n\t208,\n\t189,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t134,\n\t208,\n\t184,\n\t209,\n\t143,\n\t208,\n\t160,\n\t208,\n\t181,\n\t209,\n\t129,\n\t208,\n\t191,\n\t209,\n\t131,\n\t208,\n\t177,\n\t208,\n\t187,\n\t208,\n\t184,\n\t208,\n\t186,\n\t208,\n\t184,\n\t208,\n\t186,\n\t208,\n\t190,\n\t208,\n\t187,\n\t208,\n\t184,\n\t209,\n\t135,\n\t208,\n\t181,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t184,\n\t208,\n\t189,\n\t209,\n\t132,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t188,\n\t208,\n\t176,\n\t209,\n\t134,\n\t208,\n\t184,\n\t209,\n\t142,\n\t209,\n\t130,\n\t208,\n\t181,\n\t209,\n\t128,\n\t209,\n\t128,\n\t208,\n\t184,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t180,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t190,\n\t209,\n\t135,\n\t208,\n\t189,\n\t208,\n\t190,\n\t216,\n\t167,\n\t217,\n\t132,\n\t217,\n\t133,\n\t216,\n\t170,\n\t217,\n\t136,\n\t216,\n\t167,\n\t216,\n\t172,\n\t216,\n\t175,\n\t217,\n\t136,\n\t217,\n\t134,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t216,\n\t180,\n\t216,\n\t170,\n\t216,\n\t177,\n\t216,\n\t167,\n\t217,\n\t131,\n\t216,\n\t167,\n\t216,\n\t170,\n\t216,\n\t167,\n\t217,\n\t132,\n\t216,\n\t167,\n\t217,\n\t130,\n\t216,\n\t170,\n\t216,\n\t177,\n\t216,\n\t167,\n\t216,\n\t173,\n\t216,\n\t167,\n\t216,\n\t170,\n\t104,\n\t116,\n\t109,\n\t108,\n\t59,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t85,\n\t84,\n\t70,\n\t45,\n\t56,\n\t34,\n\t32,\n\t115,\n\t101,\n\t116,\n\t84,\n\t105,\n\t109,\n\t101,\n\t111,\n\t117,\n\t116,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t105,\n\t110,\n\t108,\n\t105,\n\t110,\n\t101,\n\t45,\n\t98,\n\t108,\n\t111,\n\t99,\n\t107,\n\t59,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t115,\n\t117,\n\t98,\n\t109,\n\t105,\n\t116,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t32,\n\t61,\n\t32,\n\t39,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t60,\n\t105,\n\t109,\n\t103,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t34,\n\t32,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t119,\n\t51,\n\t46,\n\t111,\n\t114,\n\t103,\n\t47,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t99,\n\t117,\n\t116,\n\t32,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t34,\n\t32,\n\t97,\n\t117,\n\t116,\n\t111,\n\t99,\n\t111,\n\t109,\n\t112,\n\t108,\n\t101,\n\t116,\n\t101,\n\t61,\n\t34,\n\t111,\n\t102,\n\t102,\n\t34,\n\t32,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t10,\n\t60,\n\t108,\n\t105,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t34,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t60,\n\t102,\n\t111,\n\t114,\n\t109,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t101,\n\t34,\n\t32,\n\t13,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t32,\n\t111,\n\t110,\n\t99,\n\t108,\n\t105,\n\t99,\n\t107,\n\t61,\n\t34,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t58,\n\t40,\n\t110,\n\t101,\n\t119,\n\t32,\n\t68,\n\t97,\n\t116,\n\t101,\n\t41,\n\t46,\n\t103,\n\t101,\n\t116,\n\t84,\n\t105,\n\t109,\n\t101,\n\t40,\n\t41,\n\t125,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t49,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t34,\n\t32,\n\t80,\n\t101,\n\t111,\n\t112,\n\t108,\n\t101,\n\t39,\n\t115,\n\t32,\n\t82,\n\t101,\n\t112,\n\t117,\n\t98,\n\t108,\n\t105,\n\t99,\n\t32,\n\t111,\n\t102,\n\t32,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t116,\n\t101,\n\t120,\n\t116,\n\t45,\n\t100,\n\t101,\n\t99,\n\t111,\n\t114,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t58,\n\t117,\n\t110,\n\t100,\n\t101,\n\t114,\n\t116,\n\t104,\n\t101,\n\t32,\n\t98,\n\t101,\n\t103,\n\t105,\n\t110,\n\t110,\n\t105,\n\t110,\n\t103,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t10,\n\t101,\n\t115,\n\t116,\n\t97,\n\t98,\n\t108,\n\t105,\n\t115,\n\t104,\n\t109,\n\t101,\n\t110,\n\t116,\n\t32,\n\t111,\n\t102,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t35,\n\t118,\n\t105,\n\t101,\n\t119,\n\t112,\n\t111,\n\t114,\n\t116,\n\t123,\n\t109,\n\t105,\n\t110,\n\t45,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t58,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t115,\n\t114,\n\t99,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t62,\n\t60,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t111,\n\t102,\n\t116,\n\t101,\n\t110,\n\t32,\n\t114,\n\t101,\n\t102,\n\t101,\n\t114,\n\t114,\n\t101,\n\t100,\n\t32,\n\t116,\n\t111,\n\t32,\n\t97,\n\t115,\n\t32,\n\t47,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t62,\n\t10,\n\t60,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t60,\n\t33,\n\t68,\n\t79,\n\t67,\n\t84,\n\t89,\n\t80,\n\t69,\n\t32,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t10,\n\t60,\n\t33,\n\t45,\n\t45,\n\t91,\n\t73,\n\t110,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t32,\n\t65,\n\t105,\n\t114,\n\t112,\n\t111,\n\t114,\n\t116,\n\t62,\n\t10,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t224,\n\t184,\n\t160,\n\t224,\n\t184,\n\t178,\n\t224,\n\t184,\n\t169,\n\t224,\n\t184,\n\t178,\n\t224,\n\t185,\n\t132,\n\t224,\n\t184,\n\t151,\n\t224,\n\t184,\n\t162,\n\t225,\n\t131,\n\t165,\n\t225,\n\t131,\n\t144,\n\t225,\n\t131,\n\t160,\n\t225,\n\t131,\n\t151,\n\t225,\n\t131,\n\t163,\n\t225,\n\t131,\n\t154,\n\t225,\n\t131,\n\t152,\n\t230,\n\t173,\n\t163,\n\t233,\n\t171,\n\t148,\n\t228,\n\t184,\n\t173,\n\t230,\n\t150,\n\t135,\n\t32,\n\t40,\n\t231,\n\t185,\n\t129,\n\t233,\n\t171,\n\t148,\n\t41,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t166,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t182,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t178,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t183,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t156,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t167,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t165,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t181,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t163,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t160,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t158,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t133,\n\t224,\n\t164,\n\t174,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t161,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t129,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t175,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t129,\n\t224,\n\t164,\n\t154,\n\t224,\n\t164,\n\t164,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t172,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t167,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t163,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t171,\n\t224,\n\t164,\n\t188,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t163,\n\t224,\n\t164,\n\t178,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t174,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t159,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t161,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t108,\n\t111,\n\t99,\n\t97,\n\t116,\n\t105,\n\t111,\n\t110,\n\t46,\n\t112,\n\t114,\n\t111,\n\t116,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t66,\n\t121,\n\t84,\n\t97,\n\t103,\n\t78,\n\t97,\n\t109,\n\t101,\n\t40,\n\t60,\n\t33,\n\t68,\n\t79,\n\t67,\n\t84,\n\t89,\n\t80,\n\t69,\n\t32,\n\t104,\n\t116,\n\t109,\n\t108,\n\t62,\n\t10,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t34,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t62,\n\t58,\n\t117,\n\t114,\n\t108,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t46,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t62,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t119,\n\t51,\n\t46,\n\t111,\n\t114,\n\t103,\n\t47,\n\t49,\n\t57,\n\t57,\n\t57,\n\t47,\n\t120,\n\t104,\n\t116,\n\t109,\n\t108,\n\t34,\n\t32,\n\t120,\n\t109,\n\t108,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t32,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t103,\n\t101,\n\t116,\n\t34,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t32,\n\t61,\n\t32,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t47,\n\t120,\n\t45,\n\t105,\n\t99,\n\t111,\n\t110,\n\t34,\n\t32,\n\t47,\n\t62,\n\t99,\n\t101,\n\t108,\n\t108,\n\t112,\n\t97,\n\t100,\n\t100,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t115,\n\t112,\n\t46,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t60,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t34,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t49,\n\t34,\n\t34,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t34,\n\t62,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t101,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t97,\n\t112,\n\t112,\n\t108,\n\t105,\n\t45,\n\t47,\n\t47,\n\t87,\n\t51,\n\t67,\n\t47,\n\t47,\n\t68,\n\t84,\n\t68,\n\t32,\n\t88,\n\t72,\n\t84,\n\t77,\n\t76,\n\t32,\n\t49,\n\t46,\n\t48,\n\t32,\n\t101,\n\t108,\n\t108,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t112,\n\t97,\n\t100,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t61,\n\t34,\n\t47,\n\t97,\n\t62,\n\t38,\n\t110,\n\t98,\n\t115,\n\t112,\n\t59,\n\t60,\n\t115,\n\t112,\n\t97,\n\t110,\n\t32,\n\t114,\n\t111,\n\t108,\n\t101,\n\t61,\n\t34,\n\t115,\n\t10,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t32,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t61,\n\t34,\n\t74,\n\t97,\n\t118,\n\t97,\n\t83,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t32,\n\t32,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t66,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t109,\n\t101,\n\t100,\n\t105,\n\t97,\n\t61,\n\t34,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t39,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t119,\n\t105,\n\t116,\n\t104,\n\t32,\n\t116,\n\t104,\n\t101,\n\t32,\n\t101,\n\t120,\n\t99,\n\t101,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t111,\n\t102,\n\t32,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t116,\n\t32,\n\t104,\n\t101,\n\t105,\n\t103,\n\t104,\n\t116,\n\t61,\n\t34,\n\t49,\n\t34,\n\t32,\n\t119,\n\t105,\n\t100,\n\t116,\n\t104,\n\t61,\n\t34,\n\t49,\n\t34,\n\t32,\n\t61,\n\t39,\n\t43,\n\t101,\n\t110,\n\t99,\n\t111,\n\t100,\n\t101,\n\t85,\n\t82,\n\t73,\n\t67,\n\t111,\n\t109,\n\t112,\n\t111,\n\t110,\n\t101,\n\t110,\n\t116,\n\t40,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t97,\n\t108,\n\t116,\n\t101,\n\t114,\n\t110,\n\t97,\n\t116,\n\t101,\n\t34,\n\t32,\n\t10,\n\t98,\n\t111,\n\t100,\n\t121,\n\t44,\n\t32,\n\t116,\n\t114,\n\t44,\n\t32,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t44,\n\t32,\n\t116,\n\t101,\n\t120,\n\t116,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t114,\n\t111,\n\t98,\n\t111,\n\t116,\n\t115,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t109,\n\t101,\n\t116,\n\t104,\n\t111,\n\t100,\n\t61,\n\t34,\n\t112,\n\t111,\n\t115,\n\t116,\n\t34,\n\t32,\n\t97,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t61,\n\t34,\n\t62,\n\t10,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t99,\n\t115,\n\t115,\n\t34,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t61,\n\t34,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t62,\n\t97,\n\t114,\n\t105,\n\t97,\n\t45,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t61,\n\t34,\n\t116,\n\t114,\n\t117,\n\t101,\n\t34,\n\t62,\n\t194,\n\t183,\n\t60,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t108,\n\t61,\n\t48,\n\t59,\n\t125,\n\t41,\n\t40,\n\t41,\n\t59,\n\t10,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t111,\n\t110,\n\t40,\n\t41,\n\t123,\n\t98,\n\t97,\n\t99,\n\t107,\n\t103,\n\t114,\n\t111,\n\t117,\n\t110,\n\t100,\n\t45,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t58,\n\t32,\n\t117,\n\t114,\n\t108,\n\t40,\n\t47,\n\t97,\n\t62,\n\t60,\n\t47,\n\t108,\n\t105,\n\t62,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t9,\n\t9,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t97,\n\t116,\n\t111,\n\t114,\n\t34,\n\t32,\n\t97,\n\t114,\n\t105,\n\t97,\n\t45,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t61,\n\t34,\n\t116,\n\t114,\n\t117,\n\t62,\n\t32,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t108,\n\t97,\n\t110,\n\t103,\n\t117,\n\t97,\n\t103,\n\t101,\n\t61,\n\t34,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t34,\n\t32,\n\t47,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t62,\n\t10,\n\t60,\n\t111,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t32,\n\t118,\n\t97,\n\t108,\n\t117,\n\t101,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t47,\n\t100,\n\t105,\n\t118,\n\t62,\n\t60,\n\t100,\n\t105,\n\t118,\n\t32,\n\t99,\n\t108,\n\t97,\n\t115,\n\t115,\n\t61,\n\t114,\n\t97,\n\t116,\n\t111,\n\t114,\n\t34,\n\t32,\n\t97,\n\t114,\n\t105,\n\t97,\n\t45,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t61,\n\t34,\n\t116,\n\t114,\n\t101,\n\t61,\n\t40,\n\t110,\n\t101,\n\t119,\n\t32,\n\t68,\n\t97,\n\t116,\n\t101,\n\t41,\n\t46,\n\t103,\n\t101,\n\t116,\n\t84,\n\t105,\n\t109,\n\t101,\n\t40,\n\t41,\n\t112,\n\t111,\n\t114,\n\t116,\n\t117,\n\t103,\n\t117,\n\t195,\n\t170,\n\t115,\n\t32,\n\t40,\n\t100,\n\t111,\n\t32,\n\t66,\n\t114,\n\t97,\n\t115,\n\t105,\n\t108,\n\t41,\n\t208,\n\t190,\n\t209,\n\t128,\n\t208,\n\t179,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t176,\n\t209,\n\t134,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t183,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t182,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t140,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t128,\n\t208,\n\t176,\n\t208,\n\t183,\n\t208,\n\t190,\n\t208,\n\t178,\n\t208,\n\t176,\n\t208,\n\t189,\n\t208,\n\t184,\n\t209,\n\t143,\n\t209,\n\t128,\n\t208,\n\t181,\n\t208,\n\t179,\n\t208,\n\t184,\n\t209,\n\t129,\n\t209,\n\t130,\n\t209,\n\t128,\n\t208,\n\t176,\n\t209,\n\t134,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t183,\n\t208,\n\t188,\n\t208,\n\t190,\n\t208,\n\t182,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t208,\n\t190,\n\t208,\n\t177,\n\t209,\n\t143,\n\t208,\n\t183,\n\t208,\n\t176,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t189,\n\t208,\n\t176,\n\t60,\n\t33,\n\t68,\n\t79,\n\t67,\n\t84,\n\t89,\n\t80,\n\t69,\n\t32,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t80,\n\t85,\n\t66,\n\t76,\n\t73,\n\t67,\n\t32,\n\t34,\n\t110,\n\t116,\n\t45,\n\t84,\n\t121,\n\t112,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t61,\n\t34,\n\t67,\n\t111,\n\t110,\n\t116,\n\t101,\n\t114,\n\t97,\n\t110,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t47,\n\t47,\n\t69,\n\t78,\n\t34,\n\t32,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t120,\n\t109,\n\t108,\n\t110,\n\t115,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t45,\n\t47,\n\t47,\n\t87,\n\t51,\n\t67,\n\t47,\n\t47,\n\t68,\n\t84,\n\t68,\n\t32,\n\t88,\n\t72,\n\t84,\n\t77,\n\t76,\n\t32,\n\t49,\n\t46,\n\t48,\n\t32,\n\t84,\n\t68,\n\t84,\n\t68,\n\t47,\n\t120,\n\t104,\n\t116,\n\t109,\n\t108,\n\t49,\n\t45,\n\t116,\n\t114,\n\t97,\n\t110,\n\t115,\n\t105,\n\t116,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t119,\n\t51,\n\t46,\n\t111,\n\t114,\n\t103,\n\t47,\n\t84,\n\t82,\n\t47,\n\t120,\n\t104,\n\t116,\n\t109,\n\t108,\n\t49,\n\t47,\n\t112,\n\t101,\n\t32,\n\t61,\n\t32,\n\t39,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t59,\n\t60,\n\t109,\n\t101,\n\t116,\n\t97,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t100,\n\t101,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t105,\n\t111,\n\t110,\n\t112,\n\t97,\n\t114,\n\t101,\n\t110,\n\t116,\n\t78,\n\t111,\n\t100,\n\t101,\n\t46,\n\t105,\n\t110,\n\t115,\n\t101,\n\t114,\n\t116,\n\t66,\n\t101,\n\t102,\n\t111,\n\t114,\n\t101,\n\t60,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t32,\n\t110,\n\t97,\n\t106,\n\t115,\n\t34,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t40,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t41,\n\t46,\n\t114,\n\t101,\n\t97,\n\t100,\n\t121,\n\t40,\n\t102,\n\t117,\n\t110,\n\t99,\n\t116,\n\t105,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t105,\n\t109,\n\t97,\n\t103,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t85,\n\t65,\n\t45,\n\t67,\n\t111,\n\t109,\n\t112,\n\t97,\n\t116,\n\t105,\n\t98,\n\t108,\n\t101,\n\t34,\n\t32,\n\t99,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t61,\n\t116,\n\t109,\n\t108,\n\t59,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t104,\n\t111,\n\t114,\n\t116,\n\t99,\n\t117,\n\t116,\n\t32,\n\t105,\n\t99,\n\t111,\n\t110,\n\t60,\n\t108,\n\t105,\n\t110,\n\t107,\n\t32,\n\t114,\n\t101,\n\t108,\n\t61,\n\t34,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t115,\n\t104,\n\t101,\n\t101,\n\t116,\n\t34,\n\t32,\n\t60,\n\t47,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t62,\n\t10,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t61,\n\t32,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t60,\n\t97,\n\t32,\n\t116,\n\t97,\n\t114,\n\t103,\n\t101,\n\t116,\n\t61,\n\t34,\n\t95,\n\t98,\n\t108,\n\t97,\n\t110,\n\t107,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t32,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t66,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t97,\n\t46,\n\t116,\n\t121,\n\t112,\n\t101,\n\t32,\n\t61,\n\t32,\n\t39,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t104,\n\t116,\n\t109,\n\t108,\n\t59,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t32,\n\t47,\n\t62,\n\t100,\n\t116,\n\t100,\n\t34,\n\t62,\n\t10,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t120,\n\t109,\n\t108,\n\t110,\n\t115,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t47,\n\t47,\n\t87,\n\t51,\n\t67,\n\t47,\n\t47,\n\t68,\n\t84,\n\t68,\n\t32,\n\t72,\n\t84,\n\t77,\n\t76,\n\t32,\n\t52,\n\t46,\n\t48,\n\t49,\n\t32,\n\t84,\n\t101,\n\t110,\n\t116,\n\t115,\n\t66,\n\t121,\n\t84,\n\t97,\n\t103,\n\t78,\n\t97,\n\t109,\n\t101,\n\t40,\n\t39,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t41,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t104,\n\t105,\n\t100,\n\t100,\n\t101,\n\t110,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t60,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t34,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t34,\n\t62,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t66,\n\t121,\n\t73,\n\t100,\n\t40,\n\t61,\n\t100,\n\t111,\n\t99,\n\t117,\n\t109,\n\t101,\n\t110,\n\t116,\n\t46,\n\t99,\n\t114,\n\t101,\n\t97,\n\t116,\n\t101,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t40,\n\t39,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t39,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t105,\n\t110,\n\t112,\n\t117,\n\t116,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t34,\n\t32,\n\t110,\n\t97,\n\t109,\n\t101,\n\t61,\n\t34,\n\t100,\n\t46,\n\t103,\n\t101,\n\t116,\n\t69,\n\t108,\n\t101,\n\t109,\n\t101,\n\t110,\n\t116,\n\t115,\n\t66,\n\t121,\n\t84,\n\t97,\n\t103,\n\t78,\n\t97,\n\t109,\n\t101,\n\t40,\n\t115,\n\t110,\n\t105,\n\t99,\n\t97,\n\t108,\n\t34,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t67,\n\t47,\n\t47,\n\t68,\n\t84,\n\t68,\n\t32,\n\t72,\n\t84,\n\t77,\n\t76,\n\t32,\n\t52,\n\t46,\n\t48,\n\t49,\n\t32,\n\t84,\n\t114,\n\t97,\n\t110,\n\t115,\n\t105,\n\t116,\n\t60,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t62,\n\t10,\n\t10,\n\t60,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t34,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t99,\n\t115,\n\t115,\n\t34,\n\t62,\n\t105,\n\t111,\n\t110,\n\t97,\n\t108,\n\t46,\n\t100,\n\t116,\n\t100,\n\t34,\n\t62,\n\t10,\n\t60,\n\t104,\n\t116,\n\t109,\n\t108,\n\t32,\n\t120,\n\t109,\n\t108,\n\t110,\n\t115,\n\t61,\n\t104,\n\t116,\n\t116,\n\t112,\n\t45,\n\t101,\n\t113,\n\t117,\n\t105,\n\t118,\n\t61,\n\t34,\n\t67,\n\t111,\n\t110,\n\t116,\n\t101,\n\t110,\n\t116,\n\t45,\n\t84,\n\t121,\n\t112,\n\t101,\n\t100,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t32,\n\t99,\n\t101,\n\t108,\n\t108,\n\t115,\n\t112,\n\t97,\n\t99,\n\t105,\n\t110,\n\t103,\n\t61,\n\t34,\n\t48,\n\t34,\n\t104,\n\t116,\n\t109,\n\t108,\n\t59,\n\t32,\n\t99,\n\t104,\n\t97,\n\t114,\n\t115,\n\t101,\n\t116,\n\t61,\n\t117,\n\t116,\n\t102,\n\t45,\n\t56,\n\t34,\n\t32,\n\t47,\n\t62,\n\t10,\n\t32,\n\t115,\n\t116,\n\t121,\n\t108,\n\t101,\n\t61,\n\t34,\n\t100,\n\t105,\n\t115,\n\t112,\n\t108,\n\t97,\n\t121,\n\t58,\n\t110,\n\t111,\n\t110,\n\t101,\n\t59,\n\t34,\n\t62,\n\t60,\n\t60,\n\t108,\n\t105,\n\t62,\n\t60,\n\t97,\n\t32,\n\t104,\n\t114,\n\t101,\n\t102,\n\t61,\n\t34,\n\t104,\n\t116,\n\t116,\n\t112,\n\t58,\n\t47,\n\t47,\n\t119,\n\t119,\n\t119,\n\t46,\n\t32,\n\t116,\n\t121,\n\t112,\n\t101,\n\t61,\n\t39,\n\t116,\n\t101,\n\t120,\n\t116,\n\t47,\n\t106,\n\t97,\n\t118,\n\t97,\n\t115,\n\t99,\n\t114,\n\t105,\n\t112,\n\t116,\n\t39,\n\t62,\n\t208,\n\t180,\n\t208,\n\t181,\n\t209,\n\t143,\n\t209,\n\t130,\n\t208,\n\t181,\n\t208,\n\t187,\n\t209,\n\t140,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t209,\n\t129,\n\t208,\n\t190,\n\t208,\n\t190,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t181,\n\t209,\n\t130,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t184,\n\t208,\n\t184,\n\t208,\n\t191,\n\t209,\n\t128,\n\t208,\n\t190,\n\t208,\n\t184,\n\t208,\n\t183,\n\t208,\n\t178,\n\t208,\n\t190,\n\t208,\n\t180,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t178,\n\t208,\n\t176,\n\t208,\n\t177,\n\t208,\n\t181,\n\t208,\n\t183,\n\t208,\n\t190,\n\t208,\n\t191,\n\t208,\n\t176,\n\t209,\n\t129,\n\t208,\n\t189,\n\t208,\n\t190,\n\t209,\n\t129,\n\t209,\n\t130,\n\t208,\n\t184,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t151,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t137,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t185,\n\t224,\n\t165,\n\t139,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t168,\n\t224,\n\t165,\n\t135,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t167,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t173,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t171,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t130,\n\t224,\n\t164,\n\t151,\n\t224,\n\t164,\n\t184,\n\t224,\n\t165,\n\t129,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t183,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t137,\n\t224,\n\t164,\n\t170,\n\t224,\n\t165,\n\t128,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t135,\n\t224,\n\t164,\n\t159,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t156,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t158,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t170,\n\t224,\n\t164,\n\t168,\n\t224,\n\t164,\n\t149,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t176,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t181,\n\t224,\n\t164,\n\t190,\n\t224,\n\t164,\n\t136,\n\t224,\n\t164,\n\t184,\n\t224,\n\t164,\n\t149,\n\t224,\n\t165,\n\t141,\n\t224,\n\t164,\n\t176,\n\t224,\n\t164,\n\t191,\n\t224,\n\t164,\n\t175,\n\t224,\n\t164,\n\t164,\n\t224,\n\t164,\n\t190,\n}\n\nvar kBrotliDictionary = dictionary{\n\t/* size_bits_by_length */\n\t[32]byte{\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t10,\n\t\t10,\n\t\t11,\n\t\t11,\n\t\t10,\n\t\t10,\n\t\t10,\n\t\t10,\n\t\t10,\n\t\t9,\n\t\t9,\n\t\t8,\n\t\t7,\n\t\t7,\n\t\t8,\n\t\t7,\n\t\t7,\n\t\t6,\n\t\t6,\n\t\t5,\n\t\t5,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t},\n\n\t/* offsets_by_length */\n\t[32]uint32{\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t0,\n\t\t4096,\n\t\t9216,\n\t\t21504,\n\t\t35840,\n\t\t44032,\n\t\t53248,\n\t\t63488,\n\t\t74752,\n\t\t87040,\n\t\t93696,\n\t\t100864,\n\t\t104704,\n\t\t106752,\n\t\t108928,\n\t\t113536,\n\t\t115968,\n\t\t118528,\n\t\t119872,\n\t\t121280,\n\t\t122016,\n\t\t122784,\n\t\t122784,\n\t\t122784,\n\t\t122784,\n\t\t122784,\n\t\t122784,\n\t\t122784,\n\t},\n\n\t/* data_size ==  sizeof(kBrotliDictionaryData) */\n\t122784,\n\n\t/* data */\n\tkBrotliDictionaryData,\n}\n\nfunc getDictionary() *dictionary {\n\treturn &kBrotliDictionary\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/dictionary_hash.go",
    "content": "package brotli\n\n/* Copyright 2015 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Hash table on the 4-byte prefixes of static dictionary words. */\nvar kStaticDictionaryHash = [32768]uint16{\n\t32072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21860,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45798,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4964,\n\t278,\n\t23717,\n\t0,\n\t19972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2126,\n\t16102,\n\t0,\n\t0,\n\t0,\n\t14437,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26727,\n\t2253,\n\t0,\n\t0,\n\t17252,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22984,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16647,\n\t0,\n\t34247,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2511,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19532,\n\t0,\n\t0,\n\t24004,\n\t0,\n\t0,\n\t0,\n\t9828,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30853,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20650,\n\t2404,\n\t0,\n\t20773,\n\t1677,\n\t9031,\n\t0,\n\t6404,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51879,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6761,\n\t7206,\n\t0,\n\t0,\n\t21992,\n\t22983,\n\t0,\n\t0,\n\t3529,\n\t0,\n\t1864,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11046,\n\t0,\n\t0,\n\t9641,\n\t0,\n\t0,\n\t0,\n\t6507,\n\t0,\n\t0,\n\t36934,\n\t21576,\n\t62375,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8294,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40807,\n\t0,\n\t0,\n\t0,\n\t39398,\n\t8136,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8875,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7941,\n\t0,\n\t0,\n\t25609,\n\t0,\n\t0,\n\t0,\n\t936,\n\t3716,\n\t3213,\n\t15687,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52519,\n\t0,\n\t17381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1320,\n\t5797,\n\t0,\n\t21029,\n\t0,\n\t0,\n\t6472,\n\t807,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13545,\n\t0,\n\t0,\n\t0,\n\t3624,\n\t0,\n\t0,\n\t0,\n\t29674,\n\t30820,\n\t0,\n\t31237,\n\t0,\n\t6596,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22278,\n\t0,\n\t37446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7240,\n\t423,\n\t0,\n\t24612,\n\t21705,\n\t17636,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1833,\n\t0,\n\t0,\n\t0,\n\t328,\n\t6021,\n\t0,\n\t0,\n\t0,\n\t19974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62119,\n\t4178,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12100,\n\t8617,\n\t0,\n\t0,\n\t16900,\n\t0,\n\t36678,\n\t0,\n\t0,\n\t0,\n\t35366,\n\t0,\n\t51718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20998,\n\t0,\n\t62086,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5542,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14629,\n\t10952,\n\t25927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19849,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30952,\n\t3046,\n\t14314,\n\t12998,\n\t0,\n\t0,\n\t0,\n\t15268,\n\t0,\n\t40582,\n\t30216,\n\t62118,\n\t0,\n\t0,\n\t0,\n\t20132,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12005,\n\t0,\n\t0,\n\t0,\n\t52358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24778,\n\t0,\n\t44,\n\t33095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3781,\n\t0,\n\t0,\n\t17928,\n\t9479,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32297,\n\t28613,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47174,\n\t11723,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2536,\n\t55143,\n\t0,\n\t0,\n\t6410,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56294,\n\t11914,\n\t0,\n\t529,\n\t0,\n\t30184,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8261,\n\t0,\n\t0,\n\t28808,\n\t58854,\n\t22633,\n\t965,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64135,\n\t0,\n\t0,\n\t331,\n\t3684,\n\t0,\n\t1605,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16650,\n\t37,\n\t0,\n\t23622,\n\t3144,\n\t15429,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22443,\n\t69,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17832,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11113,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18309,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26630,\n\t0,\n\t0,\n\t25512,\n\t25895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16901,\n\t0,\n\t0,\n\t0,\n\t27558,\n\t0,\n\t0,\n\t9418,\n\t0,\n\t0,\n\t0,\n\t3508,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37990,\n\t9289,\n\t8517,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1578,\n\t1604,\n\t23944,\n\t0,\n\t0,\n\t14916,\n\t12781,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12105,\n\t0,\n\t16617,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21348,\n\t11240,\n\t28870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5772,\n\t0,\n\t0,\n\t27812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8324,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16748,\n\t1157,\n\t0,\n\t0,\n\t18794,\n\t16324,\n\t25898,\n\t935,\n\t8333,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18246,\n\t0,\n\t18086,\n\t0,\n\t46854,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t339,\n\t0,\n\t0,\n\t25188,\n\t12780,\n\t12166,\n\t6409,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16516,\n\t0,\n\t27012,\n\t28395,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1420,\n\t0,\n\t0,\n\t0,\n\t9768,\n\t52967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25163,\n\t324,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64998,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21893,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47366,\n\t0,\n\t0,\n\t0,\n\t870,\n\t0,\n\t0,\n\t0,\n\t12646,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26020,\n\t16360,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1809,\n\t0,\n\t0,\n\t0,\n\t6601,\n\t15878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29092,\n\t0,\n\t28516,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21988,\n\t0,\n\t0,\n\t0,\n\t42950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5133,\n\t1318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54982,\n\t24904,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51526,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3685,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10062,\n\t9412,\n\t0,\n\t0,\n\t0,\n\t31460,\n\t5708,\n\t6181,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27144,\n\t57478,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7084,\n\t0,\n\t21993,\n\t53126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8397,\n\t0,\n\t0,\n\t5733,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2116,\n\t0,\n\t24742,\n\t0,\n\t11271,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1133,\n\t0,\n\t4873,\n\t0,\n\t0,\n\t38310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17932,\n\t0,\n\t0,\n\t18053,\n\t0,\n\t0,\n\t0,\n\t25510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17798,\n\t0,\n\t26214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23016,\n\t17415,\n\t20392,\n\t164,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3239,\n\t0,\n\t46119,\n\t0,\n\t0,\n\t0,\n\t28580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7621,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41478,\n\t0,\n\t0,\n\t31016,\n\t55334,\n\t10056,\n\t1924,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36614,\n\t0,\n\t36711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13994,\n\t59303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26501,\n\t0,\n\t5639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13897,\n\t1253,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5095,\n\t0,\n\t0,\n\t0,\n\t28869,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8646,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25641,\n\t17796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13316,\n\t620,\n\t6309,\n\t11819,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t904,\n\t1095,\n\t0,\n\t24229,\n\t0,\n\t0,\n\t28744,\n\t49703,\n\t0,\n\t23077,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32392,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35271,\n\t0,\n\t28740,\n\t5866,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4361,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7917,\n\t8869,\n\t0,\n\t0,\n\t0,\n\t13924,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6766,\n\t13989,\n\t0,\n\t0,\n\t0,\n\t903,\n\t0,\n\t0,\n\t24010,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64390,\n\t0,\n\t22468,\n\t0,\n\t25861,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23656,\n\t5317,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23017,\n\t5445,\n\t16009,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48006,\n\t10473,\n\t0,\n\t0,\n\t14404,\n\t0,\n\t0,\n\t0,\n\t42183,\n\t0,\n\t0,\n\t0,\n\t51270,\n\t0,\n\t0,\n\t10602,\n\t24132,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43782,\n\t0,\n\t0,\n\t17834,\n\t0,\n\t0,\n\t0,\n\t25576,\n\t27205,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29066,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t626,\n\t1988,\n\t14700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44710,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3848,\n\t7623,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19272,\n\t6436,\n\t0,\n\t0,\n\t5256,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19685,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39783,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30984,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28230,\n\t0,\n\t0,\n\t0,\n\t29028,\n\t10538,\n\t3205,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5636,\n\t840,\n\t295,\n\t0,\n\t0,\n\t8488,\n\t8198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4074,\n\t19526,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31144,\n\t64038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16716,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17706,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50630,\n\t0,\n\t50503,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25446,\n\t0,\n\t0,\n\t0,\n\t13831,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2696,\n\t4039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25288,\n\t0,\n\t12076,\n\t2054,\n\t0,\n\t48934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16969,\n\t59431,\n\t17259,\n\t35335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31275,\n\t0,\n\t0,\n\t0,\n\t1097,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t776,\n\t839,\n\t0,\n\t0,\n\t29386,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5864,\n\t12134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25349,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61447,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24678,\n\t0,\n\t0,\n\t0,\n\t63335,\n\t0,\n\t28836,\n\t8142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14088,\n\t1188,\n\t0,\n\t16260,\n\t0,\n\t0,\n\t0,\n\t16421,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t276,\n\t0,\n\t0,\n\t17060,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24076,\n\t29445,\n\t0,\n\t33543,\n\t0,\n\t4901,\n\t0,\n\t0,\n\t12522,\n\t0,\n\t0,\n\t62471,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20486,\n\t0,\n\t15460,\n\t2217,\n\t51719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23495,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15370,\n\t0,\n\t15849,\n\t0,\n\t15113,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27972,\n\t7337,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32299,\n\t23940,\n\t0,\n\t17766,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6184,\n\t0,\n\t20904,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31492,\n\t0,\n\t0,\n\t0,\n\t5509,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2669,\n\t50182,\n\t0,\n\t0,\n\t12299,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5257,\n\t28167,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11750,\n\t3890,\n\t0,\n\t0,\n\t26500,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10981,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17961,\n\t1831,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26473,\n\t0,\n\t6216,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28683,\n\t39975,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51654,\n\t0,\n\t0,\n\t0,\n\t27527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30859,\n\t3268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28772,\n\t0,\n\t18212,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25448,\n\t65446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3337,\n\t1670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24936,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1043,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15814,\n\t0,\n\t21670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16263,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32454,\n\t0,\n\t30630,\n\t0,\n\t0,\n\t20170,\n\t9926,\n\t0,\n\t0,\n\t0,\n\t18247,\n\t0,\n\t0,\n\t14376,\n\t0,\n\t2056,\n\t17191,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22474,\n\t52806,\n\t1588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28677,\n\t0,\n\t0,\n\t5714,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25865,\n\t22246,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17256,\n\t35751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8236,\n\t0,\n\t32108,\n\t0,\n\t0,\n\t0,\n\t43,\n\t14342,\n\t0,\n\t16517,\n\t0,\n\t0,\n\t30732,\n\t0,\n\t4012,\n\t133,\n\t0,\n\t40583,\n\t971,\n\t23942,\n\t0,\n\t0,\n\t27275,\n\t0,\n\t0,\n\t0,\n\t204,\n\t0,\n\t0,\n\t27140,\n\t7564,\n\t44327,\n\t27592,\n\t57958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22344,\n\t25701,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19524,\n\t31755,\n\t0,\n\t0,\n\t28102,\n\t0,\n\t59111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12261,\n\t0,\n\t44934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31560,\n\t0,\n\t11114,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18953,\n\t18311,\n\t0,\n\t45159,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2059,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19399,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22411,\n\t23943,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11690,\n\t0,\n\t0,\n\t4069,\n\t0,\n\t0,\n\t2668,\n\t6342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27658,\n\t1766,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23240,\n\t56070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34119,\n\t0,\n\t24453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21867,\n\t0,\n\t17610,\n\t9894,\n\t0,\n\t0,\n\t27976,\n\t38790,\n\t0,\n\t0,\n\t0,\n\t43654,\n\t0,\n\t31559,\n\t12202,\n\t23142,\n\t0,\n\t0,\n\t0,\n\t50343,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15786,\n\t4263,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4746,\n\t3814,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17192,\n\t453,\n\t17323,\n\t0,\n\t20328,\n\t4036,\n\t0,\n\t0,\n\t0,\n\t15844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27561,\n\t31940,\n\t32296,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11499,\n\t11782,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9738,\n\t50471,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35430,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29734,\n\t0,\n\t0,\n\t0,\n\t36551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9257,\n\t5606,\n\t0,\n\t13829,\n\t0,\n\t7015,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25127,\n\t0,\n\t0,\n\t19051,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2572,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29797,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9293,\n\t0,\n\t17896,\n\t56038,\n\t4077,\n\t0,\n\t0,\n\t0,\n\t29899,\n\t37351,\n\t0,\n\t30823,\n\t0,\n\t8326,\n\t0,\n\t0,\n\t0,\n\t18342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18569,\n\t54054,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37254,\n\t0,\n\t0,\n\t31433,\n\t61510,\n\t0,\n\t2022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2149,\n\t25289,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12516,\n\t14185,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10889,\n\t9607,\n\t0,\n\t28711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28490,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26181,\n\t10283,\n\t1701,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14980,\n\t0,\n\t7783,\n\t0,\n\t27846,\n\t0,\n\t0,\n\t0,\n\t56486,\n\t3892,\n\t0,\n\t0,\n\t0,\n\t5770,\n\t16583,\n\t0,\n\t26309,\n\t13422,\n\t20292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14536,\n\t1158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25801,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42438,\n\t0,\n\t3332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8327,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17353,\n\t1447,\n\t0,\n\t0,\n\t8427,\n\t48518,\n\t1359,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14986,\n\t0,\n\t32168,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9230,\n\t2791,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16073,\n\t31623,\n\t4269,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4519,\n\t0,\n\t0,\n\t27912,\n\t58950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8361,\n\t19812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6056,\n\t7877,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21701,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9128,\n\t1125,\n\t0,\n\t16548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17292,\n\t6854,\n\t21352,\n\t0,\n\t2380,\n\t0,\n\t0,\n\t4007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24357,\n\t4202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10664,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42823,\n\t3022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14373,\n\t0,\n\t20677,\n\t3304,\n\t2759,\n\t20522,\n\t64903,\n\t0,\n\t0,\n\t0,\n\t38,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27814,\n\t2802,\n\t8870,\n\t3758,\n\t1255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30027,\n\t9510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17864,\n\t14855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23404,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45734,\n\t0,\n\t0,\n\t23467,\n\t32327,\n\t0,\n\t0,\n\t10826,\n\t52999,\n\t0,\n\t0,\n\t0,\n\t33222,\n\t31336,\n\t64326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32166,\n\t0,\n\t0,\n\t3891,\n\t0,\n\t0,\n\t0,\n\t7017,\n\t645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27915,\n\t46087,\n\t0,\n\t0,\n\t0,\n\t21863,\n\t0,\n\t34246,\n\t0,\n\t0,\n\t16715,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14052,\n\t21416,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38982,\n\t0,\n\t0,\n\t17512,\n\t7460,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15428,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25445,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11879,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19911,\n\t0,\n\t20007,\n\t0,\n\t0,\n\t0,\n\t10855,\n\t943,\n\t0,\n\t0,\n\t10821,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4170,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9836,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t65415,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9865,\n\t24646,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40519,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12804,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22091,\n\t23655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31686,\n\t0,\n\t0,\n\t0,\n\t58599,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19620,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24421,\n\t0,\n\t28100,\n\t0,\n\t0,\n\t0,\n\t31268,\n\t0,\n\t3204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14822,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19947,\n\t10182,\n\t0,\n\t0,\n\t9480,\n\t14821,\n\t4398,\n\t0,\n\t0,\n\t14532,\n\t0,\n\t0,\n\t0,\n\t48871,\n\t1873,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t589,\n\t1541,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23333,\n\t0,\n\t0,\n\t0,\n\t14149,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1296,\n\t14374,\n\t0,\n\t27300,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5164,\n\t1765,\n\t0,\n\t14405,\n\t0,\n\t37574,\n\t1994,\n\t0,\n\t6636,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27815,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2568,\n\t6820,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11336,\n\t26247,\n\t0,\n\t0,\n\t23912,\n\t0,\n\t0,\n\t0,\n\t30536,\n\t0,\n\t0,\n\t34342,\n\t0,\n\t17799,\n\t0,\n\t0,\n\t0,\n\t22149,\n\t0,\n\t6118,\n\t0,\n\t25732,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26600,\n\t5190,\n\t0,\n\t0,\n\t1142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4786,\n\t0,\n\t0,\n\t0,\n\t28873,\n\t6532,\n\t0,\n\t0,\n\t26664,\n\t0,\n\t9193,\n\t11719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31752,\n\t64646,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11397,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25094,\n\t0,\n\t0,\n\t18153,\n\t20167,\n\t0,\n\t0,\n\t0,\n\t17254,\n\t0,\n\t0,\n\t878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24166,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26059,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31592,\n\t0,\n\t0,\n\t8167,\n\t24362,\n\t6212,\n\t0,\n\t34758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32520,\n\t0,\n\t0,\n\t44679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17989,\n\t8681,\n\t29222,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10251,\n\t4902,\n\t1452,\n\t15207,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22822,\n\t0,\n\t10469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19337,\n\t17670,\n\t107,\n\t11494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27305,\n\t2565,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64518,\n\t200,\n\t28389,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31208,\n\t0,\n\t30762,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29321,\n\t60518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3209,\n\t3237,\n\t12490,\n\t22663,\n\t0,\n\t0,\n\t0,\n\t18789,\n\t31464,\n\t16391,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20646,\n\t0,\n\t0,\n\t0,\n\t27238,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15940,\n\t4488,\n\t6951,\n\t0,\n\t0,\n\t0,\n\t46342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28965,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20584,\n\t3367,\n\t0,\n\t25350,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1814,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17125,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55943,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24133,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2929,\n\t0,\n\t0,\n\t50086,\n\t0,\n\t2918,\n\t25356,\n\t30052,\n\t115,\n\t11846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3056,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17639,\n\t239,\n\t19815,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21479,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28420,\n\t11786,\n\t4772,\n\t0,\n\t0,\n\t3368,\n\t36295,\n\t0,\n\t31463,\n\t0,\n\t0,\n\t14665,\n\t996,\n\t0,\n\t20582,\n\t0,\n\t0,\n\t0,\n\t9988,\n\t0,\n\t23685,\n\t0,\n\t0,\n\t0,\n\t52551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7556,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1895,\n\t2186,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27755,\n\t25447,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31052,\n\t63270,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36742,\n\t0,\n\t24804,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31048,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21290,\n\t2276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26475,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3176,\n\t19431,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62726,\n\t0,\n\t0,\n\t0,\n\t25380,\n\t0,\n\t0,\n\t27883,\n\t1316,\n\t0,\n\t0,\n\t7724,\n\t3015,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6697,\n\t0,\n\t0,\n\t47910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3141,\n\t0,\n\t0,\n\t0,\n\t14820,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31493,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6569,\n\t1348,\n\t0,\n\t25638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20324,\n\t0,\n\t0,\n\t17067,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11876,\n\t0,\n\t41030,\n\t0,\n\t0,\n\t0,\n\t26405,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11431,\n\t28137,\n\t14950,\n\t0,\n\t10151,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27176,\n\t57446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28650,\n\t57574,\n\t1387,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58247,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16805,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3526,\n\t0,\n\t15781,\n\t0,\n\t5572,\n\t13352,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18665,\n\t23463,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15405,\n\t6885,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15272,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9861,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9512,\n\t4037,\n\t0,\n\t0,\n\t11563,\n\t49639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27880,\n\t57830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41831,\n\t0,\n\t21924,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25509,\n\t0,\n\t27462,\n\t0,\n\t18085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13898,\n\t8068,\n\t26441,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25316,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16298,\n\t7397,\n\t5706,\n\t19239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1392,\n\t50919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1451,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35847,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17801,\n\t15813,\n\t0,\n\t12740,\n\t0,\n\t0,\n\t0,\n\t32967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5389,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31143,\n\t0,\n\t20548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51686,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12109,\n\t19015,\n\t0,\n\t34983,\n\t0,\n\t21732,\n\t3600,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47750,\n\t17288,\n\t43975,\n\t22857,\n\t47559,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26408,\n\t48358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30470,\n\t0,\n\t0,\n\t23560,\n\t4581,\n\t0,\n\t22404,\n\t0,\n\t49286,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49831,\n\t0,\n\t0,\n\t0,\n\t27525,\n\t31691,\n\t7,\n\t0,\n\t0,\n\t25835,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4201,\n\t16485,\n\t0,\n\t20676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3753,\n\t23303,\n\t16264,\n\t3878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11434,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22820,\n\t11146,\n\t49158,\n\t0,\n\t23623,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13893,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11722,\n\t60071,\n\t1258,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18564,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27945,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5479,\n\t0,\n\t20006,\n\t17608,\n\t3431,\n\t10988,\n\t30180,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24581,\n\t14,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25572,\n\t0,\n\t0,\n\t0,\n\t28612,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8710,\n\t0,\n\t14116,\n\t0,\n\t0,\n\t116,\n\t292,\n\t0,\n\t0,\n\t0,\n\t37831,\n\t0,\n\t43078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21832,\n\t0,\n\t0,\n\t32134,\n\t783,\n\t0,\n\t0,\n\t30982,\n\t0,\n\t0,\n\t0,\n\t68,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5932,\n\t0,\n\t0,\n\t0,\n\t18505,\n\t15175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3630,\n\t16965,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17797,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t520,\n\t42150,\n\t0,\n\t0,\n\t3122,\n\t0,\n\t0,\n\t0,\n\t22506,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28550,\n\t0,\n\t0,\n\t0,\n\t50278,\n\t0,\n\t0,\n\t13641,\n\t5958,\n\t0,\n\t35238,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29993,\n\t18724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20619,\n\t9319,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23977,\n\t0,\n\t5193,\n\t0,\n\t0,\n\t12196,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20105,\n\t677,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29419,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20266,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10631,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26628,\n\t12744,\n\t0,\n\t20648,\n\t0,\n\t0,\n\t0,\n\t432,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t646,\n\t0,\n\t25604,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63782,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24616,\n\t0,\n\t0,\n\t0,\n\t21291,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1931,\n\t0,\n\t0,\n\t0,\n\t20521,\n\t59975,\n\t0,\n\t20614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56231,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29991,\n\t0,\n\t52871,\n\t0,\n\t20934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16871,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47558,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43046,\n\t0,\n\t0,\n\t2930,\n\t0,\n\t12936,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31141,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37639,\n\t0,\n\t17572,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31240,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t688,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1648,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t146,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6345,\n\t199,\n\t0,\n\t34982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48902,\n\t0,\n\t13412,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2441,\n\t4420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20428,\n\t933,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45383,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17036,\n\t741,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27589,\n\t0,\n\t0,\n\t30282,\n\t18950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2248,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25993,\n\t0,\n\t0,\n\t0,\n\t2443,\n\t0,\n\t0,\n\t31622,\n\t0,\n\t14150,\n\t0,\n\t0,\n\t0,\n\t28679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54694,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3827,\n\t0,\n\t0,\n\t0,\n\t3756,\n\t0,\n\t9897,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19082,\n\t31239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27625,\n\t0,\n\t0,\n\t0,\n\t784,\n\t4647,\n\t32652,\n\t0,\n\t0,\n\t63494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3404,\n\t58470,\n\t0,\n\t32325,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18634,\n\t2789,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8548,\n\t0,\n\t0,\n\t0,\n\t22501,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15881,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35879,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7978,\n\t17956,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24324,\n\t0,\n\t0,\n\t4937,\n\t0,\n\t0,\n\t0,\n\t8168,\n\t0,\n\t13420,\n\t10340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16712,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17640,\n\t17991,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2953,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9100,\n\t16806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30667,\n\t0,\n\t0,\n\t19013,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t205,\n\t15334,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1969,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26248,\n\t52518,\n\t0,\n\t49798,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4742,\n\t0,\n\t0,\n\t21641,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5707,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3018,\n\t12454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2920,\n\t262,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3593,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55879,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t775,\n\t0,\n\t43270,\n\t5066,\n\t48967,\n\t0,\n\t0,\n\t22986,\n\t4165,\n\t8971,\n\t44838,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62279,\n\t272,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51430,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28234,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13349,\n\t0,\n\t0,\n\t0,\n\t51111,\n\t20265,\n\t13861,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t585,\n\t7494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21768,\n\t62407,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7979,\n\t166,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38918,\n\t0,\n\t56742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16296,\n\t5767,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32068,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23916,\n\t30183,\n\t0,\n\t58791,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8969,\n\t0,\n\t0,\n\t0,\n\t183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2314,\n\t17445,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23748,\n\t0,\n\t0,\n\t8139,\n\t4839,\n\t27914,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29478,\n\t0,\n\t0,\n\t16552,\n\t26663,\n\t0,\n\t53767,\n\t0,\n\t0,\n\t13960,\n\t8039,\n\t18696,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t782,\n\t16005,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6258,\n\t56806,\n\t16456,\n\t12455,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9355,\n\t0,\n\t0,\n\t0,\n\t7273,\n\t41063,\n\t24780,\n\t57766,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3820,\n\t2597,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29225,\n\t61126,\n\t0,\n\t0,\n\t0,\n\t58439,\n\t15691,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37190,\n\t22408,\n\t967,\n\t0,\n\t0,\n\t0,\n\t23078,\n\t26858,\n\t0,\n\t0,\n\t0,\n\t19753,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5416,\n\t13702,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52742,\n\t20394,\n\t38567,\n\t0,\n\t0,\n\t0,\n\t51079,\n\t0,\n\t0,\n\t136,\n\t8516,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t531,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8936,\n\t5031,\n\t12520,\n\t19334,\n\t0,\n\t0,\n\t22827,\n\t30247,\n\t28074,\n\t31140,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27497,\n\t18148,\n\t20104,\n\t59079,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24389,\n\t0,\n\t0,\n\t6125,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9541,\n\t0,\n\t0,\n\t24553,\n\t29095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25444,\n\t0,\n\t0,\n\t9643,\n\t0,\n\t0,\n\t63047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39558,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20620,\n\t11815,\n\t499,\n\t0,\n\t5128,\n\t2278,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23530,\n\t40166,\n\t2440,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26922,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51911,\n\t0,\n\t0,\n\t23532,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51238,\n\t25737,\n\t44486,\n\t12622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3078,\n\t0,\n\t9253,\n\t0,\n\t0,\n\t1128,\n\t22023,\n\t0,\n\t0,\n\t0,\n\t21350,\n\t0,\n\t16420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t65094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22532,\n\t0,\n\t48774,\n\t0,\n\t34503,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9797,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13797,\n\t0,\n\t38279,\n\t0,\n\t0,\n\t1738,\n\t0,\n\t489,\n\t46343,\n\t0,\n\t45382,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6220,\n\t56550,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26885,\n\t0,\n\t28806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20553,\n\t49927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3019,\n\t12358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26571,\n\t13319,\n\t0,\n\t0,\n\t653,\n\t23399,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22316,\n\t0,\n\t0,\n\t21188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27556,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27878,\n\t21483,\n\t27653,\n\t0,\n\t29701,\n\t237,\n\t0,\n\t10632,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33766,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31563,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1416,\n\t2439,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9611,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5611,\n\t16581,\n\t26601,\n\t35462,\n\t0,\n\t0,\n\t0,\n\t26756,\n\t0,\n\t59271,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26984,\n\t57734,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7882,\n\t0,\n\t0,\n\t0,\n\t19528,\n\t6469,\n\t0,\n\t0,\n\t1161,\n\t0,\n\t0,\n\t0,\n\t7688,\n\t20935,\n\t425,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12519,\n\t0,\n\t12902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2411,\n\t0,\n\t11725,\n\t26086,\n\t0,\n\t0,\n\t20201,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11045,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30471,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21541,\n\t1141,\n\t21190,\n\t0,\n\t9188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t184,\n\t1093,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4842,\n\t0,\n\t13672,\n\t0,\n\t0,\n\t12230,\n\t0,\n\t0,\n\t0,\n\t10532,\n\t0,\n\t0,\n\t8937,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28996,\n\t0,\n\t0,\n\t11720,\n\t26982,\n\t0,\n\t46182,\n\t0,\n\t43911,\n\t31754,\n\t0,\n\t1160,\n\t3940,\n\t0,\n\t20772,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24549,\n\t0,\n\t32582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2310,\n\t11788,\n\t0,\n\t0,\n\t43047,\n\t0,\n\t0,\n\t0,\n\t18853,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63622,\n\t0,\n\t0,\n\t7048,\n\t17318,\n\t0,\n\t0,\n\t0,\n\t21957,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1039,\n\t6279,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12197,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46470,\n\t0,\n\t0,\n\t24,\n\t19719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21353,\n\t3846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9382,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29926,\n\t0,\n\t33606,\n\t0,\n\t4708,\n\t2828,\n\t0,\n\t0,\n\t29543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29893,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3663,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10920,\n\t7111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9384,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37094,\n\t0,\n\t0,\n\t0,\n\t27110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21865,\n\t0,\n\t27753,\n\t30214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12648,\n\t5446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19784,\n\t17124,\n\t0,\n\t52007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24900,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1476,\n\t0,\n\t65031,\n\t0,\n\t0,\n\t1205,\n\t46663,\n\t0,\n\t30023,\n\t11625,\n\t1094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10058,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28455,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14788,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16808,\n\t0,\n\t0,\n\t742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21636,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15944,\n\t23207,\n\t0,\n\t0,\n\t0,\n\t0,\n\t247,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24743,\n\t0,\n\t0,\n\t0,\n\t5252,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29961,\n\t18660,\n\t21099,\n\t46791,\n\t0,\n\t7045,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25707,\n\t0,\n\t0,\n\t17412,\n\t3828,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5803,\n\t5637,\n\t0,\n\t38151,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t60103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t853,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30215,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8741,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t171,\n\t4070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24073,\n\t7366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2184,\n\t5189,\n\t0,\n\t20932,\n\t1545,\n\t4996,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6313,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30826,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27463,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21640,\n\t63303,\n\t0,\n\t0,\n\t3275,\n\t31111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11556,\n\t0,\n\t14756,\n\t0,\n\t0,\n\t0,\n\t15108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23914,\n\t28966,\n\t0,\n\t0,\n\t0,\n\t4965,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10216,\n\t5223,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27142,\n\t0,\n\t0,\n\t1173,\n\t20198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4612,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11822,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17769,\n\t7910,\n\t0,\n\t0,\n\t31880,\n\t0,\n\t0,\n\t6055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8970,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16840,\n\t23879,\n\t0,\n\t0,\n\t11051,\n\t0,\n\t0,\n\t0,\n\t32552,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20842,\n\t13701,\n\t0,\n\t0,\n\t0,\n\t37191,\n\t7373,\n\t10471,\n\t17482,\n\t25348,\n\t0,\n\t0,\n\t0,\n\t38502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21509,\n\t6058,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3173,\n\t0,\n\t0,\n\t0,\n\t9543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17768,\n\t12708,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12748,\n\t48743,\n\t0,\n\t11718,\n\t0,\n\t0,\n\t25194,\n\t0,\n\t0,\n\t0,\n\t9033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5028,\n\t0,\n\t30118,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42759,\n\t0,\n\t0,\n\t3720,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5450,\n\t5125,\n\t0,\n\t58086,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27716,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22052,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26249,\n\t0,\n\t15947,\n\t3460,\n\t0,\n\t0,\n\t0,\n\t35814,\n\t0,\n\t0,\n\t0,\n\t7813,\n\t19500,\n\t32167,\n\t0,\n\t18597,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28644,\n\t0,\n\t0,\n\t0,\n\t60743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29636,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17220,\n\t15885,\n\t9414,\n\t9642,\n\t0,\n\t0,\n\t0,\n\t593,\n\t0,\n\t0,\n\t24228,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40422,\n\t0,\n\t26244,\n\t0,\n\t23109,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3979,\n\t60007,\n\t0,\n\t0,\n\t0,\n\t28199,\n\t0,\n\t0,\n\t0,\n\t43142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29158,\n\t0,\n\t30532,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13256,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16549,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26116,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1065,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18985,\n\t4805,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17702,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3468,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13447,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56871,\n\t0,\n\t0,\n\t1776,\n\t15780,\n\t0,\n\t0,\n\t2603,\n\t0,\n\t10280,\n\t31366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11592,\n\t3591,\n\t0,\n\t2372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20004,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12072,\n\t518,\n\t0,\n\t0,\n\t1960,\n\t8999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7178,\n\t32999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1641,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6764,\n\t9893,\n\t490,\n\t4005,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25258,\n\t5541,\n\t0,\n\t14053,\n\t306,\n\t20743,\n\t0,\n\t0,\n\t9422,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11977,\n\t260,\n\t0,\n\t35175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18405,\n\t0,\n\t0,\n\t0,\n\t16582,\n\t0,\n\t0,\n\t0,\n\t22470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2792,\n\t0,\n\t0,\n\t0,\n\t14026,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14858,\n\t3909,\n\t0,\n\t0,\n\t0,\n\t57671,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15979,\n\t0,\n\t0,\n\t0,\n\t2794,\n\t15239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26884,\n\t9070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19499,\n\t37127,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19205,\n\t10350,\n\t11910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15083,\n\t23108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t169,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15274,\n\t41735,\n\t0,\n\t56774,\n\t0,\n\t0,\n\t2825,\n\t0,\n\t14025,\n\t389,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21482,\n\t31910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20456,\n\t710,\n\t0,\n\t0,\n\t25032,\n\t21797,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32427,\n\t21252,\n\t0,\n\t30150,\n\t0,\n\t43174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11403,\n\t0,\n\t0,\n\t1029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6892,\n\t9252,\n\t0,\n\t63206,\n\t3496,\n\t14406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22568,\n\t0,\n\t0,\n\t21253,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39623,\n\t0,\n\t0,\n\t10189,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30729,\n\t59910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3305,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7660,\n\t24871,\n\t0,\n\t838,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12013,\n\t13252,\n\t0,\n\t551,\n\t0,\n\t0,\n\t0,\n\t43207,\n\t0,\n\t30567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28394,\n\t30724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22665,\n\t22725,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16074,\n\t8966,\n\t245,\n\t1445,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24872,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13124,\n\t0,\n\t35527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13259,\n\t10917,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25191,\n\t0,\n\t0,\n\t0,\n\t13956,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54631,\n\t19625,\n\t12070,\n\t3083,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14436,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21766,\n\t0,\n\t15463,\n\t29322,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23653,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2643,\n\t0,\n\t0,\n\t21223,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4114,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34790,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t297,\n\t3620,\n\t3338,\n\t10372,\n\t0,\n\t14727,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29924,\n\t22473,\n\t13895,\n\t15529,\n\t32455,\n\t30378,\n\t13540,\n\t0,\n\t28807,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64582,\n\t18380,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32710,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4590,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64935,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16744,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20005,\n\t0,\n\t0,\n\t13608,\n\t1191,\n\t0,\n\t0,\n\t0,\n\t62183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17643,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5380,\n\t0,\n\t0,\n\t32328,\n\t0,\n\t0,\n\t63814,\n\t0,\n\t0,\n\t0,\n\t2919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17034,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t60295,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7690,\n\t486,\n\t0,\n\t0,\n\t0,\n\t39270,\n\t0,\n\t49094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12555,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20967,\n\t17993,\n\t12647,\n\t0,\n\t0,\n\t0,\n\t16036,\n\t32616,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16294,\n\t8555,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30346,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14797,\n\t3652,\n\t0,\n\t0,\n\t8268,\n\t12934,\n\t0,\n\t54950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2632,\n\t33959,\n\t0,\n\t23175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36262,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32684,\n\t26918,\n\t0,\n\t32676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15625,\n\t11943,\n\t1206,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18052,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16422,\n\t0,\n\t0,\n\t0,\n\t26404,\n\t0,\n\t0,\n\t28777,\n\t0,\n\t0,\n\t24902,\n\t0,\n\t0,\n\t408,\n\t45351,\n\t0,\n\t35719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3658,\n\t17446,\n\t0,\n\t165,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6151,\n\t0,\n\t0,\n\t24424,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24170,\n\t24293,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11847,\n\t0,\n\t39591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9549,\n\t2788,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1010,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26055,\n\t31724,\n\t0,\n\t24233,\n\t1828,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17284,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32452,\n\t0,\n\t0,\n\t0,\n\t28871,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17704,\n\t53383,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17892,\n\t1938,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16362,\n\t0,\n\t0,\n\t21605,\n\t0,\n\t0,\n\t5003,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22693,\n\t0,\n\t22342,\n\t0,\n\t0,\n\t0,\n\t55846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22853,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6600,\n\t263,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24836,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5386,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17740,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25093,\n\t29064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12680,\n\t11462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t84,\n\t7303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27044,\n\t457,\n\t0,\n\t22924,\n\t58246,\n\t19016,\n\t0,\n\t2606,\n\t45703,\n\t0,\n\t5157,\n\t0,\n\t25028,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2065,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31946,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33382,\n\t0,\n\t47878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25004,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26153,\n\t35654,\n\t0,\n\t58055,\n\t30668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25988,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4456,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7560,\n\t20583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42822,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1733,\n\t0,\n\t0,\n\t0,\n\t8196,\n\t0,\n\t0,\n\t11241,\n\t0,\n\t30572,\n\t60326,\n\t0,\n\t15013,\n\t0,\n\t0,\n\t0,\n\t40646,\n\t0,\n\t23812,\n\t0,\n\t10022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12874,\n\t31015,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1608,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27114,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7944,\n\t1382,\n\t0,\n\t11813,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24517,\n\t0,\n\t11621,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21702,\n\t0,\n\t0,\n\t13100,\n\t8262,\n\t2644,\n\t7973,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1033,\n\t12581,\n\t0,\n\t25221,\n\t0,\n\t0,\n\t0,\n\t40998,\n\t16301,\n\t62983,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1263,\n\t9318,\n\t0,\n\t0,\n\t0,\n\t18854,\n\t0,\n\t0,\n\t1741,\n\t33895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26377,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32165,\n\t0,\n\t51143,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29412,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1674,\n\t4230,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5545,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2099,\n\t45158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14157,\n\t0,\n\t26955,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17096,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27050,\n\t6726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28554,\n\t0,\n\t0,\n\t7142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16936,\n\t0,\n\t0,\n\t0,\n\t25833,\n\t0,\n\t4399,\n\t6980,\n\t0,\n\t46214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10630,\n\t21164,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2446,\n\t48551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15400,\n\t12135,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4774,\n\t586,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23751,\n\t9736,\n\t4548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25577,\n\t29607,\n\t6250,\n\t1637,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22024,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37414,\n\t24044,\n\t0,\n\t0,\n\t0,\n\t14474,\n\t29735,\n\t0,\n\t7077,\n\t0,\n\t45990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30568,\n\t40039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6150,\n\t0,\n\t4228,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27687,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24548,\n\t21513,\n\t1350,\n\t0,\n\t0,\n\t0,\n\t33607,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11784,\n\t1414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18244,\n\t940,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7270,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16709,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48935,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23660,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53350,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4236,\n\t16358,\n\t0,\n\t4422,\n\t6665,\n\t32644,\n\t0,\n\t0,\n\t744,\n\t18084,\n\t0,\n\t11014,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29508,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7686,\n\t0,\n\t0,\n\t13289,\n\t5478,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12872,\n\t0,\n\t0,\n\t24134,\n\t1005,\n\t22916,\n\t0,\n\t31429,\n\t23400,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28424,\n\t0,\n\t0,\n\t0,\n\t25706,\n\t27109,\n\t0,\n\t0,\n\t26345,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25126,\n\t0,\n\t0,\n\t88,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17032,\n\t0,\n\t0,\n\t21799,\n\t0,\n\t0,\n\t10060,\n\t0,\n\t12296,\n\t21892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20777,\n\t14311,\n\t0,\n\t58182,\n\t32232,\n\t0,\n\t10282,\n\t0,\n\t2121,\n\t11527,\n\t0,\n\t0,\n\t0,\n\t12325,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28804,\n\t2344,\n\t8133,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21864,\n\t62695,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2771,\n\t0,\n\t0,\n\t23204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6278,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26597,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23144,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31816,\n\t20070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24456,\n\t2118,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6570,\n\t1156,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30406,\n\t0,\n\t0,\n\t0,\n\t28388,\n\t3572,\n\t0,\n\t0,\n\t26599,\n\t12426,\n\t5286,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24970,\n\t24167,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28745,\n\t4678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1444,\n\t236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19428,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2092,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2827,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19881,\n\t19204,\n\t0,\n\t11749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17958,\n\t0,\n\t17894,\n\t0,\n\t18726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21510,\n\t5033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14598,\n\t0,\n\t29605,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t617,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3627,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2225,\n\t14823,\n\t0,\n\t0,\n\t2637,\n\t6182,\n\t78,\n\t15078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20264,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36743,\n\t4140,\n\t44551,\n\t17352,\n\t25703,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14024,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28004,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2087,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18028,\n\t0,\n\t0,\n\t0,\n\t300,\n\t14212,\n\t0,\n\t0,\n\t1386,\n\t40327,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31082,\n\t0,\n\t0,\n\t22374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26532,\n\t7756,\n\t0,\n\t0,\n\t18982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6440,\n\t1159,\n\t7180,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45766,\n\t0,\n\t57798,\n\t0,\n\t16740,\n\t0,\n\t0,\n\t6802,\n\t60454,\n\t0,\n\t0,\n\t0,\n\t26470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t65382,\n\t4362,\n\t7750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9096,\n\t4743,\n\t334,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39974,\n\t0,\n\t0,\n\t0,\n\t25828,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3027,\n\t0,\n\t0,\n\t0,\n\t15816,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48327,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16168,\n\t41799,\n\t0,\n\t0,\n\t24458,\n\t8581,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54503,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5097,\n\t30852,\n\t18664,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16484,\n\t0,\n\t0,\n\t27337,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57030,\n\t0,\n\t0,\n\t1417,\n\t41191,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23429,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10024,\n\t21735,\n\t0,\n\t0,\n\t10126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24105,\n\t4710,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4394,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13253,\n\t0,\n\t56391,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55974,\n\t0,\n\t0,\n\t0,\n\t52070,\n\t0,\n\t15620,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2660,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21644,\n\t0,\n\t0,\n\t52455,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3116,\n\t0,\n\t464,\n\t34726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25003,\n\t12423,\n\t0,\n\t27172,\n\t1896,\n\t7335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35686,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3472,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45254,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21124,\n\t23594,\n\t33127,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16684,\n\t22087,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8714,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55814,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4109,\n\t23460,\n\t0,\n\t0,\n\t8874,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t147,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29960,\n\t63398,\n\t1302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9799,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31333,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19557,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5701,\n\t0,\n\t0,\n\t0,\n\t63014,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21254,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12484,\n\t0,\n\t0,\n\t0,\n\t48326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15783,\n\t0,\n\t0,\n\t1202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3086,\n\t49191,\n\t0,\n\t0,\n\t5387,\n\t15141,\n\t0,\n\t0,\n\t0,\n\t3365,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20076,\n\t14021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t376,\n\t40198,\n\t0,\n\t0,\n\t0,\n\t52039,\n\t0,\n\t24932,\n\t0,\n\t0,\n\t0,\n\t0,\n\t808,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9860,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23719,\n\t0,\n\t21476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20776,\n\t4807,\n\t0,\n\t0,\n\t3177,\n\t16678,\n\t0,\n\t0,\n\t110,\n\t10853,\n\t0,\n\t0,\n\t0,\n\t17382,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7500,\n\t4966,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52102,\n\t0,\n\t24516,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26535,\n\t0,\n\t0,\n\t0,\n\t46247,\n\t0,\n\t0,\n\t0,\n\t15557,\n\t0,\n\t0,\n\t0,\n\t0,\n\t76,\n\t52327,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17866,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19173,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2985,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14310,\n\t0,\n\t0,\n\t2125,\n\t45831,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9838,\n\t0,\n\t13227,\n\t19492,\n\t0,\n\t0,\n\t0,\n\t29764,\n\t0,\n\t0,\n\t0,\n\t0,\n\t686,\n\t30053,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30789,\n\t139,\n\t20837,\n\t0,\n\t0,\n\t0,\n\t0,\n\t502,\n\t18533,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31396,\n\t0,\n\t0,\n\t0,\n\t17444,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49862,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25610,\n\t550,\n\t0,\n\t0,\n\t561,\n\t0,\n\t29034,\n\t0,\n\t0,\n\t0,\n\t3528,\n\t0,\n\t0,\n\t0,\n\t1715,\n\t14661,\n\t18,\n\t63463,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14186,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29578,\n\t59014,\n\t0,\n\t39430,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2250,\n\t16612,\n\t0,\n\t31780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t462,\n\t16967,\n\t0,\n\t29029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1768,\n\t0,\n\t6025,\n\t16998,\n\t1804,\n\t0,\n\t0,\n\t54182,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14124,\n\t0,\n\t6154,\n\t29702,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7716,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48807,\n\t0,\n\t8292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16389,\n\t5933,\n\t0,\n\t14857,\n\t51303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35623,\n\t9097,\n\t23047,\n\t0,\n\t0,\n\t23112,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t151,\n\t9254,\n\t1390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54215,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6187,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9866,\n\t0,\n\t0,\n\t59622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25286,\n\t0,\n\t0,\n\t23848,\n\t32069,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9255,\n\t2187,\n\t15270,\n\t437,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19493,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11748,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22212,\n\t1865,\n\t17543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21996,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55975,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32138,\n\t21156,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14249,\n\t0,\n\t0,\n\t0,\n\t2388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6823,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26694,\n\t0,\n\t0,\n\t6059,\n\t53511,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49542,\n\t6159,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1036,\n\t24036,\n\t0,\n\t2501,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17419,\n\t51271,\n\t3377,\n\t15142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5007,\n\t62374,\n\t0,\n\t56935,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24422,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28263,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15622,\n\t0,\n\t19749,\n\t0,\n\t0,\n\t1611,\n\t0,\n\t22219,\n\t48583,\n\t25129,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t721,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32518,\n\t0,\n\t0,\n\t0,\n\t18469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5896,\n\t29927,\n\t3657,\n\t23046,\n\t0,\n\t0,\n\t3214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t112,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3048,\n\t455,\n\t0,\n\t31012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23270,\n\t0,\n\t32677,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38086,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4900,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25541,\n\t0,\n\t18788,\n\t0,\n\t0,\n\t22248,\n\t1351,\n\t0,\n\t61734,\n\t4524,\n\t30629,\n\t0,\n\t14887,\n\t242,\n\t29063,\n\t0,\n\t0,\n\t14408,\n\t4741,\n\t0,\n\t0,\n\t0,\n\t37318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8106,\n\t0,\n\t32107,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1481,\n\t0,\n\t0,\n\t28132,\n\t0,\n\t25798,\n\t0,\n\t59783,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t59078,\n\t0,\n\t0,\n\t0,\n\t23366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30887,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16200,\n\t0,\n\t0,\n\t0,\n\t335,\n\t0,\n\t0,\n\t0,\n\t714,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30730,\n\t9478,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18790,\n\t0,\n\t0,\n\t0,\n\t0,\n\t663,\n\t0,\n\t0,\n\t0,\n\t1034,\n\t31431,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30120,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13925,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2280,\n\t13414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22028,\n\t23687,\n\t3017,\n\t11047,\n\t0,\n\t0,\n\t21738,\n\t18630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30246,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17257,\n\t0,\n\t21896,\n\t63783,\n\t0,\n\t0,\n\t0,\n\t21094,\n\t0,\n\t18662,\n\t0,\n\t25700,\n\t0,\n\t22533,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6341,\n\t5800,\n\t11111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15399,\n\t12970,\n\t6501,\n\t0,\n\t0,\n\t3179,\n\t26438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15750,\n\t0,\n\t13062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21284,\n\t11177,\n\t4391,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19595,\n\t40647,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11877,\n\t0,\n\t0,\n\t0,\n\t26439,\n\t0,\n\t0,\n\t0,\n\t0,\n\t695,\n\t49126,\n\t27467,\n\t11972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9961,\n\t0,\n\t0,\n\t0,\n\t31722,\n\t62982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15817,\n\t52710,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20550,\n\t0,\n\t0,\n\t5034,\n\t3942,\n\t0,\n\t0,\n\t0,\n\t45927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45606,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3405,\n\t12582,\n\t15563,\n\t54087,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24202,\n\t5893,\n\t0,\n\t0,\n\t0,\n\t44230,\n\t0,\n\t0,\n\t0,\n\t5605,\n\t0,\n\t47782,\n\t0,\n\t32230,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7014,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16488,\n\t3175,\n\t0,\n\t27237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32004,\n\t31434,\n\t0,\n\t24392,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29130,\n\t58214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29002,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37926,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1290,\n\t0,\n\t0,\n\t0,\n\t4713,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1803,\n\t966,\n\t0,\n\t17700,\n\t0,\n\t0,\n\t654,\n\t19109,\n\t0,\n\t51655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10470,\n\t1584,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2506,\n\t0,\n\t0,\n\t25159,\n\t4303,\n\t0,\n\t0,\n\t0,\n\t395,\n\t15879,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1352,\n\t6535,\n\t0,\n\t19652,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4722,\n\t7909,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30152,\n\t0,\n\t0,\n\t64742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2153,\n\t9125,\n\t0,\n\t0,\n\t279,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1328,\n\t17030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54151,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1775,\n\t54535,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31624,\n\t0,\n\t0,\n\t0,\n\t7150,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1840,\n\t35943,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56455,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64486,\n\t0,\n\t0,\n\t0,\n\t51174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17092,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12,\n\t16134,\n\t19883,\n\t39943,\n\t10281,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14125,\n\t2407,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26921,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22188,\n\t0,\n\t20810,\n\t10053,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29220,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28170,\n\t0,\n\t15208,\n\t0,\n\t0,\n\t32517,\n\t5736,\n\t19271,\n\t3562,\n\t10534,\n\t0,\n\t0,\n\t0,\n\t59655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27084,\n\t60422,\n\t0,\n\t0,\n\t24969,\n\t0,\n\t0,\n\t0,\n\t2636,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30596,\n\t3594,\n\t0,\n\t0,\n\t0,\n\t8362,\n\t14565,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10793,\n\t12326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5906,\n\t59686,\n\t0,\n\t0,\n\t23081,\n\t517,\n\t0,\n\t15556,\n\t0,\n\t0,\n\t0,\n\t8486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19877,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7497,\n\t0,\n\t0,\n\t26085,\n\t0,\n\t0,\n\t23784,\n\t63591,\n\t6568,\n\t6310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10054,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7018,\n\t14470,\n\t18858,\n\t0,\n\t5641,\n\t10660,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35526,\n\t1515,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27656,\n\t0,\n\t0,\n\t9606,\n\t0,\n\t39590,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53926,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t232,\n\t4327,\n\t12649,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20199,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26730,\n\t0,\n\t0,\n\t0,\n\t19400,\n\t14695,\n\t0,\n\t31334,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5064,\n\t11908,\n\t0,\n\t27333,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47751,\n\t0,\n\t0,\n\t0,\n\t26662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6245,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23368,\n\t63911,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8520,\n\t24037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26279,\n\t0,\n\t0,\n\t0,\n\t22886,\n\t0,\n\t0,\n\t0,\n\t27782,\n\t0,\n\t30694,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33703,\n\t0,\n\t0,\n\t0,\n\t30405,\n\t0,\n\t34598,\n\t0,\n\t51047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1908,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1511,\n\t21897,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51398,\n\t0,\n\t24870,\n\t0,\n\t32647,\n\t0,\n\t0,\n\t0,\n\t35015,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7758,\n\t57991,\n\t0,\n\t0,\n\t0,\n\t30949,\n\t0,\n\t0,\n\t22,\n\t15140,\n\t9162,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25540,\n\t20136,\n\t7108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16427,\n\t10789,\n\t9805,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4680,\n\t0,\n\t0,\n\t52679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14884,\n\t0,\n\t0,\n\t0,\n\t16804,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9578,\n\t5287,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34054,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19076,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7627,\n\t55719,\n\t0,\n\t39463,\n\t14446,\n\t58374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23465,\n\t15845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38534,\n\t0,\n\t0,\n\t0,\n\t17893,\n\t10922,\n\t0,\n\t7176,\n\t678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3113,\n\t46279,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23334,\n\t0,\n\t0,\n\t18088,\n\t23268,\n\t0,\n\t62342,\n\t0,\n\t0,\n\t0,\n\t16613,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38182,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10344,\n\t71,\n\t6446,\n\t0,\n\t0,\n\t1893,\n\t0,\n\t0,\n\t1106,\n\t0,\n\t28680,\n\t30756,\n\t0,\n\t41126,\n\t0,\n\t0,\n\t1492,\n\t0,\n\t15341,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17575,\n\t0,\n\t21220,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25060,\n\t2088,\n\t21828,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16708,\n\t0,\n\t0,\n\t0,\n\t1668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12260,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12713,\n\t6215,\n\t0,\n\t0,\n\t20329,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3732,\n\t0,\n\t1646,\n\t0,\n\t0,\n\t27460,\n\t0,\n\t34406,\n\t17128,\n\t14341,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6120,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8551,\n\t21546,\n\t10212,\n\t3020,\n\t2951,\n\t0,\n\t17638,\n\t0,\n\t0,\n\t6985,\n\t44999,\n\t2218,\n\t8197,\n\t0,\n\t0,\n\t30472,\n\t63366,\n\t0,\n\t26660,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1265,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2610,\n\t0,\n\t0,\n\t0,\n\t11278,\n\t20295,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2353,\n\t10852,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5421,\n\t24292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34407,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15432,\n\t20774,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12360,\n\t10757,\n\t0,\n\t0,\n\t0,\n\t33126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29573,\n\t0,\n\t2343,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63079,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43015,\n\t0,\n\t16038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1480,\n\t25573,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5063,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t823,\n\t0,\n\t0,\n\t64039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15300,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2924,\n\t46759,\n\t6760,\n\t19268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34182,\n\t0,\n\t0,\n\t3977,\n\t18149,\n\t0,\n\t0,\n\t0,\n\t32199,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23524,\n\t25994,\n\t0,\n\t0,\n\t10343,\n\t0,\n\t0,\n\t0,\n\t9733,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4740,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16741,\n\t0,\n\t0,\n\t4626,\n\t23367,\n\t0,\n\t0,\n\t31400,\n\t0,\n\t0,\n\t3557,\n\t0,\n\t0,\n\t4234,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14213,\n\t0,\n\t57191,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t240,\n\t0,\n\t0,\n\t0,\n\t0,\n\t65318,\n\t29832,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29989,\n\t0,\n\t31846,\n\t0,\n\t0,\n\t8170,\n\t0,\n\t0,\n\t4421,\n\t27626,\n\t30884,\n\t0,\n\t0,\n\t20204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44614,\n\t534,\n\t20868,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28710,\n\t0,\n\t10277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29511,\n\t0,\n\t19813,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27020,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53094,\n\t0,\n\t35207,\n\t0,\n\t0,\n\t0,\n\t37542,\n\t0,\n\t61766,\n\t8584,\n\t8037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12488,\n\t22757,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23814,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19973,\n\t0,\n\t0,\n\t0,\n\t63943,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36006,\n\t0,\n\t0,\n\t0,\n\t19012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t80,\n\t1254,\n\t0,\n\t0,\n\t0,\n\t42630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16262,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2124,\n\t25479,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16873,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3142,\n\t0,\n\t0,\n\t18443,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3917,\n\t0,\n\t8841,\n\t1190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9284,\n\t0,\n\t0,\n\t24394,\n\t41351,\n\t0,\n\t0,\n\t0,\n\t42087,\n\t0,\n\t62566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6728,\n\t4199,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25515,\n\t0,\n\t1231,\n\t0,\n\t374,\n\t15623,\n\t0,\n\t29956,\n\t0,\n\t14118,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20900,\n\t0,\n\t16743,\n\t0,\n\t0,\n\t0,\n\t28902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2578,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13838,\n\t0,\n\t0,\n\t10052,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7432,\n\t43783,\n\t17097,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t873,\n\t0,\n\t0,\n\t0,\n\t398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8459,\n\t23559,\n\t0,\n\t53030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35750,\n\t0,\n\t4071,\n\t0,\n\t0,\n\t0,\n\t38662,\n\t0,\n\t41414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11656,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4011,\n\t42695,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25353,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27177,\n\t22372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30980,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46278,\n\t3976,\n\t12711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20517,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4072,\n\t11078,\n\t0,\n\t0,\n\t16553,\n\t2405,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32998,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47046,\n\t0,\n\t30533,\n\t0,\n\t0,\n\t11050,\n\t9734,\n\t13129,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58310,\n\t0,\n\t0,\n\t0,\n\t57543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5163,\n\t59687,\n\t2220,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17316,\n\t0,\n\t20069,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5319,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22949,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19208,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20933,\n\t0,\n\t0,\n\t6026,\n\t8742,\n\t0,\n\t0,\n\t0,\n\t17380,\n\t0,\n\t13127,\n\t2797,\n\t0,\n\t0,\n\t30116,\n\t0,\n\t0,\n\t5963,\n\t8004,\n\t0,\n\t57126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42854,\n\t14792,\n\t30759,\n\t0,\n\t24964,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16933,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15176,\n\t40839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t788,\n\t30341,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21036,\n\t24102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30123,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22597,\n\t31531,\n\t26789,\n\t0,\n\t59559,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9352,\n\t29863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20516,\n\t0,\n\t0,\n\t0,\n\t39462,\n\t3665,\n\t0,\n\t28265,\n\t0,\n\t8778,\n\t64262,\n\t0,\n\t57414,\n\t9132,\n\t0,\n\t0,\n\t18276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26344,\n\t30725,\n\t524,\n\t19751,\n\t0,\n\t13796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18155,\n\t0,\n\t12841,\n\t0,\n\t74,\n\t24998,\n\t13579,\n\t1061,\n\t0,\n\t64199,\n\t0,\n\t0,\n\t8776,\n\t0,\n\t0,\n\t60231,\n\t0,\n\t25412,\n\t0,\n\t0,\n\t0,\n\t59143,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14344,\n\t1510,\n\t0,\n\t0,\n\t0,\n\t38374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13353,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32613,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14859,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14154,\n\t0,\n\t29770,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16520,\n\t2182,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36102,\n\t3340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25189,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15720,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22758,\n\t0,\n\t0,\n\t304,\n\t0,\n\t3243,\n\t14117,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5130,\n\t12679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21733,\n\t10441,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23590,\n\t0,\n\t57479,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10824,\n\t18372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35078,\n\t15722,\n\t12967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34599,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53639,\n\t0,\n\t38630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31017,\n\t11333,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19144,\n\t0,\n\t9513,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56711,\n\t24042,\n\t0,\n\t1197,\n\t0,\n\t0,\n\t58502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8230,\n\t6121,\n\t18628,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25290,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1514,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14378,\n\t9798,\n\t32363,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9577,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26788,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t330,\n\t10533,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42246,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5074,\n\t21028,\n\t0,\n\t38119,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t248,\n\t0,\n\t31176,\n\t62054,\n\t0,\n\t53287,\n\t0,\n\t0,\n\t0,\n\t0,\n\t271,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9224,\n\t2117,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15818,\n\t5607,\n\t0,\n\t52582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18248,\n\t24005,\n\t23018,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t427,\n\t0,\n\t0,\n\t39910,\n\t0,\n\t0,\n\t7080,\n\t11399,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22220,\n\t57894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13156,\n\t0,\n\t1413,\n\t1007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21415,\n\t0,\n\t21543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41702,\n\t22538,\n\t9573,\n\t0,\n\t0,\n\t0,\n\t8806,\n\t0,\n\t0,\n\t6920,\n\t56359,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42215,\n\t0,\n\t0,\n\t13708,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1582,\n\t1764,\n\t3282,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11653,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12139,\n\t0,\n\t29482,\n\t31076,\n\t1673,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40262,\n\t0,\n\t0,\n\t0,\n\t33862,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20996,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4615,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43943,\n\t333,\n\t19367,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26821,\n\t0,\n\t32389,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4936,\n\t11687,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10885,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25926,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15851,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8360,\n\t0,\n\t17130,\n\t7942,\n\t0,\n\t11460,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18150,\n\t14248,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22310,\n\t0,\n\t0,\n\t0,\n\t42758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29354,\n\t5574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31109,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9156,\n\t0,\n\t0,\n\t1801,\n\t14023,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23620,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31018,\n\t65510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26182,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27717,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31108,\n\t0,\n\t11366,\n\t0,\n\t0,\n\t0,\n\t3717,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8552,\n\t6054,\n\t3339,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28358,\n\t0,\n\t2756,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1462,\n\t0,\n\t0,\n\t27622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62502,\n\t14410,\n\t56743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12206,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36550,\n\t0,\n\t38054,\n\t0,\n\t0,\n\t0,\n\t21221,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27077,\n\t0,\n\t0,\n\t16906,\n\t0,\n\t12587,\n\t12101,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10414,\n\t28775,\n\t21769,\n\t60167,\n\t0,\n\t56646,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20740,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5931,\n\t5351,\n\t0,\n\t65478,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7977,\n\t52647,\n\t0,\n\t4868,\n\t0,\n\t0,\n\t0,\n\t55463,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32197,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13445,\n\t0,\n\t0,\n\t0,\n\t26631,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t209,\n\t1285,\n\t0,\n\t0,\n\t1928,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43334,\n\t23849,\n\t23172,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24712,\n\t62439,\n\t8811,\n\t3463,\n\t20457,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16008,\n\t56263,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t60358,\n\t22761,\n\t6565,\n\t0,\n\t0,\n\t30888,\n\t27686,\n\t0,\n\t0,\n\t0,\n\t17093,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22121,\n\t0,\n\t0,\n\t0,\n\t7593,\n\t14182,\n\t0,\n\t28103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18500,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26308,\n\t0,\n\t29541,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29572,\n\t0,\n\t0,\n\t0,\n\t21285,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t60839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30407,\n\t15949,\n\t2981,\n\t0,\n\t0,\n\t0,\n\t46439,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23911,\n\t26505,\n\t25222,\n\t12811,\n\t5895,\n\t0,\n\t6343,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31815,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19688,\n\t10245,\n\t0,\n\t0,\n\t0,\n\t31301,\n\t26985,\n\t28964,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27208,\n\t31172,\n\t0,\n\t0,\n\t0,\n\t0,\n\t216,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6438,\n\t0,\n\t0,\n\t0,\n\t33319,\n\t0,\n\t0,\n\t0,\n\t33286,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22181,\n\t7499,\n\t24774,\n\t0,\n\t10756,\n\t0,\n\t44775,\n\t724,\n\t0,\n\t25768,\n\t25669,\n\t24873,\n\t5349,\n\t25257,\n\t0,\n\t0,\n\t54566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t327,\n\t439,\n\t357,\n\t0,\n\t0,\n\t6536,\n\t8452,\n\t0,\n\t0,\n\t1802,\n\t0,\n\t0,\n\t61350,\n\t0,\n\t15045,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38343,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32491,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22885,\n\t0,\n\t0,\n\t32073,\n\t0,\n\t0,\n\t0,\n\t9546,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27748,\n\t0,\n\t0,\n\t23176,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34118,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2158,\n\t0,\n\t5586,\n\t30340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24452,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2409,\n\t4390,\n\t0,\n\t24196,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32264,\n\t26948,\n\t20587,\n\t0,\n\t0,\n\t0,\n\t2155,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4328,\n\t26276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23564,\n\t0,\n\t12458,\n\t11367,\n\t0,\n\t0,\n\t25162,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t65414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32966,\n\t0,\n\t0,\n\t0,\n\t34662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39238,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11400,\n\t10214,\n\t266,\n\t12452,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15173,\n\t0,\n\t0,\n\t0,\n\t13668,\n\t0,\n\t13222,\n\t0,\n\t23364,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11941,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25575,\n\t0,\n\t0,\n\t0,\n\t57383,\n\t0,\n\t0,\n\t0,\n\t10308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2865,\n\t9287,\n\t75,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21508,\n\t22380,\n\t59526,\n\t0,\n\t0,\n\t0,\n\t23589,\n\t0,\n\t0,\n\t0,\n\t51590,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4645,\n\t3980,\n\t28295,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21734,\n\t0,\n\t17607,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41767,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18436,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21958,\n\t0,\n\t19430,\n\t0,\n\t0,\n\t1204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3240,\n\t55239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30660,\n\t0,\n\t0,\n\t0,\n\t28901,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4716,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11754,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22086,\n\t0,\n\t22564,\n\t8749,\n\t0,\n\t0,\n\t28391,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2886,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40358,\n\t0,\n\t0,\n\t15916,\n\t39526,\n\t0,\n\t13735,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28938,\n\t0,\n\t407,\n\t4006,\n\t0,\n\t0,\n\t0,\n\t26916,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27526,\n\t30280,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24586,\n\t0,\n\t24649,\n\t5126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23019,\n\t0,\n\t22377,\n\t18599,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27593,\n\t9735,\n\t0,\n\t20196,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28168,\n\t48423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31399,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17606,\n\t0,\n\t0,\n\t15242,\n\t29767,\n\t26378,\n\t17701,\n\t0,\n\t0,\n\t14472,\n\t0,\n\t4840,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24708,\n\t0,\n\t9349,\n\t4330,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16137,\n\t0,\n\t0,\n\t34854,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25063,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6603,\n\t12583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7433,\n\t29188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31270,\n\t0,\n\t0,\n\t22920,\n\t3143,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t618,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21381,\n\t0,\n\t11524,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21004,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t312,\n\t23239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2313,\n\t0,\n\t0,\n\t40614,\n\t0,\n\t0,\n\t14825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46535,\n\t0,\n\t41190,\n\t7853,\n\t0,\n\t31656,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3433,\n\t5255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t72,\n\t15493,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29828,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18822,\n\t20008,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2438,\n\t2952,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24420,\n\t0,\n\t19908,\n\t0,\n\t0,\n\t0,\n\t8101,\n\t0,\n\t17479,\n\t0,\n\t0,\n\t3530,\n\t0,\n\t8202,\n\t29319,\n\t0,\n\t0,\n\t1132,\n\t6789,\n\t0,\n\t0,\n\t23881,\n\t0,\n\t0,\n\t0,\n\t4810,\n\t0,\n\t0,\n\t46918,\n\t0,\n\t0,\n\t0,\n\t41574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39334,\n\t0,\n\t0,\n\t0,\n\t26117,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5100,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23496,\n\t27813,\n\t4045,\n\t54918,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6473,\n\t7428,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6792,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3560,\n\t32103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54790,\n\t0,\n\t0,\n\t6926,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1841,\n\t3174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9612,\n\t18374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32744,\n\t0,\n\t0,\n\t9671,\n\t0,\n\t59879,\n\t0,\n\t23300,\n\t8073,\n\t0,\n\t0,\n\t14758,\n\t0,\n\t0,\n\t0,\n\t10342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24808,\n\t14759,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5515,\n\t0,\n\t0,\n\t14852,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2354,\n\t23271,\n\t0,\n\t32740,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18472,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8972,\n\t21669,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5096,\n\t0,\n\t14283,\n\t55367,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12644,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4651,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t661,\n\t0,\n\t0,\n\t13638,\n\t19466,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31273,\n\t0,\n\t8010,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3211,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63430,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19018,\n\t2437,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14312,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16836,\n\t0,\n\t0,\n\t471,\n\t35975,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6023,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11593,\n\t9639,\n\t0,\n\t0,\n\t0,\n\t55783,\n\t0,\n\t5700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27908,\n\t0,\n\t26598,\n\t0,\n\t0,\n\t6667,\n\t6470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16522,\n\t27911,\n\t0,\n\t0,\n\t10025,\n\t7172,\n\t0,\n\t0,\n\t779,\n\t0,\n\t360,\n\t17477,\n\t0,\n\t0,\n\t0,\n\t61991,\n\t7752,\n\t7717,\n\t1494,\n\t0,\n\t0,\n\t0,\n\t26569,\n\t40742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26406,\n\t10474,\n\t32196,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50567,\n\t16521,\n\t11716,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55558,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61926,\n\t0,\n\t26436,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4459,\n\t10598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9223,\n\t0,\n\t29318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t60423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47078,\n\t0,\n\t50246,\n\t0,\n\t12612,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61799,\n\t0,\n\t55015,\n\t0,\n\t21060,\n\t7309,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11976,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10347,\n\t15942,\n\t0,\n\t34023,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4969,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28997,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3466,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19716,\n\t28872,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22152,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26342,\n\t0,\n\t0,\n\t0,\n\t9764,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21798,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13,\n\t6853,\n\t32136,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t750,\n\t0,\n\t0,\n\t54502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46183,\n\t0,\n\t0,\n\t625,\n\t22854,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2061,\n\t23588,\n\t0,\n\t0,\n\t11049,\n\t56262,\n\t0,\n\t0,\n\t18538,\n\t1509,\n\t0,\n\t0,\n\t17258,\n\t4453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12429,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8074,\n\t0,\n\t23852,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16136,\n\t3428,\n\t0,\n\t27876,\n\t0,\n\t0,\n\t0,\n\t7332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28900,\n\t0,\n\t0,\n\t2284,\n\t0,\n\t0,\n\t17573,\n\t201,\n\t1508,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31365,\n\t27688,\n\t22565,\n\t0,\n\t0,\n\t0,\n\t5159,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4584,\n\t42599,\n\t0,\n\t0,\n\t0,\n\t44422,\n\t1068,\n\t23173,\n\t0,\n\t0,\n\t0,\n\t613,\n\t0,\n\t0,\n\t0,\n\t12645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27076,\n\t6732,\n\t0,\n\t0,\n\t0,\n\t3913,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22244,\n\t29992,\n\t15911,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5161,\n\t1574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19108,\n\t0,\n\t0,\n\t0,\n\t35014,\n\t0,\n\t0,\n\t0,\n\t25956,\n\t29067,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47079,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1356,\n\t61927,\n\t0,\n\t0,\n\t0,\n\t64455,\n\t2122,\n\t64231,\n\t0,\n\t0,\n\t18763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t907,\n\t34471,\n\t0,\n\t0,\n\t0,\n\t39078,\n\t0,\n\t0,\n\t1995,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t822,\n\t0,\n\t15978,\n\t44423,\n\t0,\n\t0,\n\t3112,\n\t325,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15397,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1193,\n\t4294,\n\t4968,\n\t15559,\n\t0,\n\t46150,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18917,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9928,\n\t37543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13097,\n\t36999,\n\t0,\n\t0,\n\t0,\n\t15430,\n\t0,\n\t0,\n\t8424,\n\t29639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25734,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40487,\n\t0,\n\t13284,\n\t0,\n\t11141,\n\t0,\n\t0,\n\t0,\n\t32388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5298,\n\t57702,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13060,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8233,\n\t42278,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36422,\n\t0,\n\t0,\n\t0,\n\t7972,\n\t0,\n\t0,\n\t0,\n\t18437,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7406,\n\t0,\n\t0,\n\t0,\n\t9225,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13865,\n\t47591,\n\t18220,\n\t53703,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24940,\n\t17223,\n\t0,\n\t0,\n\t0,\n\t13221,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15848,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6122,\n\t1735,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16968,\n\t18151,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26089,\n\t19494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28809,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42727,\n\t0,\n\t55174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20485,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15172,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35302,\n\t0,\n\t48135,\n\t20972,\n\t33094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9765,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39559,\n\t0,\n\t0,\n\t13736,\n\t6950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23658,\n\t8903,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58886,\n\t7468,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64550,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47622,\n\t0,\n\t0,\n\t0,\n\t50886,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57606,\n\t912,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1449,\n\t0,\n\t1169,\n\t0,\n\t718,\n\t46151,\n\t12104,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48230,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1259,\n\t0,\n\t0,\n\t33734,\n\t23208,\n\t62567,\n\t0,\n\t65158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28684,\n\t59878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25769,\n\t0,\n\t0,\n\t0,\n\t0,\n\t65479,\n\t0,\n\t0,\n\t0,\n\t0,\n\t555,\n\t22789,\n\t0,\n\t19748,\n\t1769,\n\t10246,\n\t8680,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14250,\n\t0,\n\t5899,\n\t3303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21097,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10795,\n\t0,\n\t0,\n\t0,\n\t16204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26986,\n\t2469,\n\t0,\n\t14660,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45447,\n\t12234,\n\t3494,\n\t4555,\n\t10566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2801,\n\t0,\n\t0,\n\t0,\n\t15755,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39654,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33574,\n\t0,\n\t10279,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63527,\n\t0,\n\t0,\n\t3912,\n\t0,\n\t0,\n\t7492,\n\t0,\n\t0,\n\t0,\n\t35142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17576,\n\t8103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16713,\n\t4198,\n\t0,\n\t0,\n\t4782,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16228,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25961,\n\t20166,\n\t0,\n\t0,\n\t0,\n\t10980,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14340,\n\t18922,\n\t14567,\n\t0,\n\t44199,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37606,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20902,\n\t0,\n\t0,\n\t0,\n\t56358,\n\t0,\n\t38342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9514,\n\t36071,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21700,\n\t0,\n\t0,\n\t5266,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1134,\n\t0,\n\t1453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3882,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4004,\n\t0,\n\t0,\n\t0,\n\t51910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23076,\n\t4648,\n\t0,\n\t0,\n\t0,\n\t31051,\n\t25351,\n\t0,\n\t0,\n\t0,\n\t22884,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63975,\n\t0,\n\t0,\n\t2376,\n\t16997,\n\t0,\n\t0,\n\t2096,\n\t0,\n\t0,\n\t0,\n\t3373,\n\t7046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20,\n\t0,\n\t13707,\n\t614,\n\t0,\n\t0,\n\t12840,\n\t3079,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51046,\n\t3729,\n\t0,\n\t32680,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24008,\n\t62759,\n\t0,\n\t0,\n\t4745,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2414,\n\t0,\n\t0,\n\t44262,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24937,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19140,\n\t0,\n\t13575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39110,\n\t0,\n\t0,\n\t0,\n\t28036,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4261,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5992,\n\t0,\n\t264,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13739,\n\t0,\n\t21928,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4232,\n\t15110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30022,\n\t0,\n\t0,\n\t27977,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24776,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2962,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26564,\n\t22441,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13640,\n\t11205,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19305,\n\t1894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9389,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14119,\n\t5224,\n\t135,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63815,\n\t0,\n\t55654,\n\t0,\n\t0,\n\t12584,\n\t0,\n\t1524,\n\t33223,\n\t0,\n\t0,\n\t0,\n\t9895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11624,\n\t0,\n\t0,\n\t0,\n\t5614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21320,\n\t0,\n\t0,\n\t53607,\n\t0,\n\t51206,\n\t0,\n\t0,\n\t0,\n\t25863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8964,\n\t1740,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7975,\n\t0,\n\t0,\n\t3306,\n\t8134,\n\t0,\n\t8389,\n\t48,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25766,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52166,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21477,\n\t31112,\n\t31652,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28452,\n\t0,\n\t0,\n\t0,\n\t44231,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24805,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12428,\n\t6471,\n\t0,\n\t0,\n\t0,\n\t0,\n\t525,\n\t17926,\n\t0,\n\t0,\n\t0,\n\t26919,\n\t0,\n\t0,\n\t18120,\n\t0,\n\t0,\n\t0,\n\t30024,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29189,\n\t0,\n\t0,\n\t0,\n\t43559,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19787,\n\t7557,\n\t0,\n\t59334,\n\t0,\n\t0,\n\t10184,\n\t6085,\n\t0,\n\t44039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30440,\n\t63110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11017,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t622,\n\t0,\n\t5226,\n\t2727,\n\t0,\n\t15588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4650,\n\t0,\n\t2675,\n\t0,\n\t0,\n\t32420,\n\t0,\n\t0,\n\t0,\n\t61511,\n\t0,\n\t0,\n\t5419,\n\t17829,\n\t2123,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38183,\n\t2640,\n\t0,\n\t11274,\n\t14533,\n\t1842,\n\t0,\n\t0,\n\t42663,\n\t12681,\n\t3430,\n\t0,\n\t11845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6533,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t54598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12616,\n\t38535,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32229,\n\t0,\n\t0,\n\t0,\n\t54279,\n\t0,\n\t48614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31401,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34310,\n\t0,\n\t0,\n\t0,\n\t22788,\n\t0,\n\t52134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40678,\n\t0,\n\t0,\n\t0,\n\t51463,\n\t535,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15525,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4904,\n\t869,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t63718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1678,\n\t0,\n\t692,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26216,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29355,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14538,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27273,\n\t55014,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27271,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30468,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18186,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14345,\n\t0,\n\t0,\n\t0,\n\t2152,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58438,\n\t21034,\n\t0,\n\t23339,\n\t21318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21412,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12869,\n\t0,\n\t0,\n\t4875,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29191,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1640,\n\t10247,\n\t0,\n\t14244,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9867,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12363,\n\t0,\n\t0,\n\t7653,\n\t0,\n\t0,\n\t4168,\n\t2663,\n\t0,\n\t4580,\n\t0,\n\t11143,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13764,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t234,\n\t6821,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29958,\n\t0,\n\t3461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28324,\n\t18795,\n\t7013,\n\t12746,\n\t11655,\n\t0,\n\t37287,\n\t0,\n\t0,\n\t10953,\n\t7718,\n\t9705,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8137,\n\t17988,\n\t0,\n\t25156,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41415,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15784,\n\t6918,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7019,\n\t10919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4171,\n\t55495,\n\t4940,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22440,\n\t19333,\n\t0,\n\t0,\n\t28136,\n\t0,\n\t6249,\n\t21317,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53414,\n\t0,\n\t0,\n\t0,\n\t57318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19940,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2698,\n\t3911,\n\t0,\n\t0,\n\t0,\n\t26790,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32424,\n\t0,\n\t0,\n\t18470,\n\t0,\n\t0,\n\t0,\n\t14726,\n\t29834,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1000,\n\t4197,\n\t0,\n\t0,\n\t0,\n\t19366,\n\t0,\n\t0,\n\t0,\n\t39878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2185,\n\t8901,\n\t5288,\n\t9829,\n\t25000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35622,\n\t0,\n\t0,\n\t23048,\n\t62503,\n\t6506,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13609,\n\t10438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7723,\n\t42119,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13317,\n\t0,\n\t0,\n\t0,\n\t41606,\n\t0,\n\t27111,\n\t0,\n\t0,\n\t21194,\n\t11461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26856,\n\t58342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20940,\n\t48710,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5227,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10061,\n\t31300,\n\t0,\n\t0,\n\t0,\n\t19236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30277,\n\t13896,\n\t0,\n\t0,\n\t0,\n\t12876,\n\t13159,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t428,\n\t46951,\n\t13134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2249,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3465,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24868,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23909,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16164,\n\t0,\n\t10437,\n\t0,\n\t0,\n\t5263,\n\t20102,\n\t20938,\n\t0,\n\t0,\n\t0,\n\t1192,\n\t1030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21385,\n\t4870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18596,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1422,\n\t4038,\n\t2858,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48998,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6508,\n\t37350,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17001,\n\t39431,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30182,\n\t0,\n\t21445,\n\t7403,\n\t28164,\n\t0,\n\t51750,\n\t0,\n\t0,\n\t0,\n\t62631,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31206,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13477,\n\t0,\n\t0,\n\t456,\n\t26693,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14890,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26697,\n\t22022,\n\t13225,\n\t27364,\n\t0,\n\t0,\n\t0,\n\t18884,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3659,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1448,\n\t5413,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6340,\n\t0,\n\t0,\n\t18091,\n\t18725,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22118,\n\t0,\n\t0,\n\t0,\n\t18981,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29223,\n\t3724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43526,\n\t0,\n\t0,\n\t0,\n\t25668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21545,\n\t9862,\n\t0,\n\t22692,\n\t32201,\n\t60646,\n\t0,\n\t7300,\n\t0,\n\t0,\n\t0,\n\t58887,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19460,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50342,\n\t0,\n\t65255,\n\t4360,\n\t17286,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28708,\n\t0,\n\t0,\n\t30025,\n\t60102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47014,\n\t0,\n\t31973,\n\t0,\n\t9572,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18501,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14597,\n\t0,\n\t0,\n\t0,\n\t53735,\n\t5228,\n\t22183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1554,\n\t24164,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10827,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34918,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22252,\n\t0,\n\t0,\n\t46855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31207,\n\t0,\n\t0,\n\t10733,\n\t0,\n\t0,\n\t63334,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8616,\n\t50119,\n\t20169,\n\t12678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58087,\n\t20298,\n\t5,\n\t0,\n\t0,\n\t30920,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t296,\n\t13190,\n\t0,\n\t30663,\n\t0,\n\t0,\n\t18536,\n\t12228,\n\t0,\n\t6788,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30890,\n\t21796,\n\t0,\n\t0,\n\t526,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20965,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2161,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13544,\n\t7398,\n\t0,\n\t0,\n\t32522,\n\t9605,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3208,\n\t7590,\n\t0,\n\t0,\n\t0,\n\t43846,\n\t0,\n\t0,\n\t0,\n\t38663,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39014,\n\t4142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6373,\n\t0,\n\t0,\n\t13676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30374,\n\t21288,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22791,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9452,\n\t9990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4841,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18820,\n\t152,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13260,\n\t3334,\n\t0,\n\t0,\n\t24234,\n\t8422,\n\t0,\n\t17957,\n\t0,\n\t0,\n\t0,\n\t10244,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1201,\n\t26151,\n\t0,\n\t31173,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64838,\n\t4203,\n\t7525,\n\t521,\n\t0,\n\t18888,\n\t37031,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7082,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4490,\n\t12487,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36615,\n\t0,\n\t0,\n\t0,\n\t14854,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6539,\n\t13029,\n\t9704,\n\t38983,\n\t0,\n\t0,\n\t0,\n\t0,\n\t168,\n\t10405,\n\t0,\n\t0,\n\t0,\n\t0,\n\t394,\n\t25607,\n\t0,\n\t57063,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16141,\n\t19878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29446,\n\t0,\n\t12036,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6982,\n\t18572,\n\t0,\n\t24584,\n\t14535,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16,\n\t0,\n\t21642,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5254,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3853,\n\t9126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7241,\n\t10982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t950,\n\t0,\n\t0,\n\t57990,\n\t0,\n\t0,\n\t277,\n\t0,\n\t0,\n\t0,\n\t694,\n\t36007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18409,\n\t51142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28646,\n\t0,\n\t0,\n\t0,\n\t30693,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56295,\n\t5544,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8518,\n\t8366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45670,\n\t0,\n\t0,\n\t9608,\n\t33062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18694,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1672,\n\t23493,\n\t0,\n\t0,\n\t6955,\n\t7655,\n\t0,\n\t36134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23432,\n\t647,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13382,\n\t0,\n\t0,\n\t0,\n\t19621,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20228,\n\t0,\n\t0,\n\t2728,\n\t31495,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29096,\n\t22213,\n\t235,\n\t35495,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8968,\n\t1989,\n\t0,\n\t0,\n\t1066,\n\t0,\n\t0,\n\t11492,\n\t5965,\n\t31367,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18727,\n\t0,\n\t0,\n\t0,\n\t6757,\n\t0,\n\t0,\n\t10765,\n\t4646,\n\t0,\n\t36166,\n\t0,\n\t27943,\n\t0,\n\t0,\n\t26888,\n\t8420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29316,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4975,\n\t0,\n\t0,\n\t0,\n\t14762,\n\t3111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43399,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18980,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44550,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4051,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37734,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24486,\n\t0,\n\t5989,\n\t0,\n\t41159,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20326,\n\t0,\n\t0,\n\t747,\n\t6884,\n\t0,\n\t0,\n\t0,\n\t41798,\n\t0,\n\t0,\n\t3117,\n\t22919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21032,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21068,\n\t34630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64071,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26667,\n\t7943,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52934,\n\t0,\n\t0,\n\t17002,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20294,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27301,\n\t18347,\n\t7974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16874,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t648,\n\t1575,\n\t0,\n\t0,\n\t0,\n\t31749,\n\t0,\n\t0,\n\t0,\n\t23301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15912,\n\t50535,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1993,\n\t8582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15850,\n\t6183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3402,\n\t0,\n\t0,\n\t27494,\n\t0,\n\t0,\n\t749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26025,\n\t29606,\n\t0,\n\t0,\n\t7144,\n\t19622,\n\t30504,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21316,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21444,\n\t0,\n\t0,\n\t1289,\n\t6919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8299,\n\t0,\n\t0,\n\t0,\n\t14090,\n\t35655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2377,\n\t15206,\n\t0,\n\t0,\n\t6028,\n\t4452,\n\t0,\n\t25508,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1269,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51014,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9286,\n\t0,\n\t7429,\n\t0,\n\t0,\n\t28393,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16680,\n\t452,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23718,\n\t0,\n\t0,\n\t0,\n\t31750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3568,\n\t0,\n\t0,\n\t13604,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25255,\n\t0,\n\t0,\n\t0,\n\t50982,\n\t0,\n\t56582,\n\t0,\n\t0,\n\t7467,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30181,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30564,\n\t7208,\n\t7845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62182,\n\t0,\n\t0,\n\t0,\n\t41094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22695,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17736,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50054,\n\t0,\n\t0,\n\t0,\n\t14180,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23332,\n\t0,\n\t0,\n\t0,\n\t11140,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24262,\n\t27145,\n\t9540,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26537,\n\t45510,\n\t6062,\n\t3879,\n\t0,\n\t0,\n\t20233,\n\t25991,\n\t0,\n\t0,\n\t17803,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13962,\n\t5508,\n\t16971,\n\t27013,\n\t7437,\n\t31494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4714,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17189,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27492,\n\t0,\n\t0,\n\t26953,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41319,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47430,\n\t19596,\n\t12549,\n\t0,\n\t0,\n\t0,\n\t8390,\n\t1006,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24100,\n\t17577,\n\t4,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26692,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29477,\n\t0,\n\t0,\n\t0,\n\t21573,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9864,\n\t14214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25771,\n\t5766,\n\t0,\n\t0,\n\t8909,\n\t8679,\n\t0,\n\t0,\n\t6861,\n\t16166,\n\t0,\n\t38887,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12392,\n\t8678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52646,\n\t1354,\n\t2950,\n\t0,\n\t14692,\n\t0,\n\t0,\n\t10572,\n\t49830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3626,\n\t582,\n\t0,\n\t0,\n\t0,\n\t55750,\n\t0,\n\t0,\n\t0,\n\t30885,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5830,\n\t0,\n\t0,\n\t2090,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10503,\n\t0,\n\t0,\n\t18825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57158,\n\t0,\n\t0,\n\t30792,\n\t63526,\n\t0,\n\t0,\n\t0,\n\t9863,\n\t16267,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18824,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19653,\n\t25388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25480,\n\t23015,\n\t0,\n\t0,\n\t10440,\n\t6725,\n\t0,\n\t0,\n\t0,\n\t22436,\n\t24265,\n\t15109,\n\t0,\n\t0,\n\t0,\n\t62311,\n\t8906,\n\t34534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15913,\n\t1319,\n\t0,\n\t0,\n\t20296,\n\t1477,\n\t30760,\n\t0,\n\t25928,\n\t16772,\n\t0,\n\t0,\n\t1069,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17029,\n\t0,\n\t31909,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41542,\n\t0,\n\t21478,\n\t0,\n\t0,\n\t0,\n\t9796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22187,\n\t58343,\n\t0,\n\t0,\n\t0,\n\t24295,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61831,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2833,\n\t5829,\n\t0,\n\t0,\n\t0,\n\t62855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13577,\n\t27431,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21480,\n\t10501,\n\t0,\n\t16932,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22918,\n\t0,\n\t48294,\n\t2574,\n\t2150,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1897,\n\t4518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10990,\n\t13767,\n\t25705,\n\t37863,\n\t21672,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43430,\n\t1712,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18886,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10535,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14734,\n\t0,\n\t0,\n\t55782,\n\t0,\n\t0,\n\t30824,\n\t10886,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51302,\n\t0,\n\t0,\n\t8012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20680,\n\t6981,\n\t0,\n\t57415,\n\t11,\n\t0,\n\t0,\n\t18277,\n\t0,\n\t14564,\n\t0,\n\t0,\n\t0,\n\t32390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19113,\n\t5158,\n\t0,\n\t11172,\n\t0,\n\t16774,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10315,\n\t13830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10410,\n\t7141,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18116,\n\t0,\n\t0,\n\t0,\n\t44615,\n\t15403,\n\t13958,\n\t0,\n\t1540,\n\t14632,\n\t19525,\n\t24201,\n\t19781,\n\t0,\n\t0,\n\t0,\n\t24165,\n\t0,\n\t38951,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17416,\n\t15749,\n\t3438,\n\t13255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32228,\n\t0,\n\t0,\n\t0,\n\t0,\n\t176,\n\t0,\n\t0,\n\t50566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21540,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5284,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25897,\n\t28326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15945,\n\t0,\n\t0,\n\t0,\n\t9804,\n\t293,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13988,\n\t23082,\n\t4677,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6405,\n\t0,\n\t30692,\n\t0,\n\t0,\n\t0,\n\t61702,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45926,\n\t0,\n\t15398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4554,\n\t2692,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32485,\n\t0,\n\t0,\n\t0,\n\t10084,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24297,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22790,\n\t0,\n\t0,\n\t0,\n\t55110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7112,\n\t0,\n\t31530,\n\t45255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40743,\n\t17226,\n\t22599,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3695,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13799,\n\t3114,\n\t21287,\n\t1353,\n\t7591,\n\t0,\n\t0,\n\t0,\n\t8455,\n\t0,\n\t0,\n\t6824,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14569,\n\t0,\n\t0,\n\t0,\n\t29000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19979,\n\t0,\n\t18376,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11332,\n\t0,\n\t0,\n\t0,\n\t49863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2191,\n\t7527,\n\t23148,\n\t58022,\n\t0,\n\t0,\n\t0,\n\t30631,\n\t0,\n\t26565,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t754,\n\t0,\n\t0,\n\t15877,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17510,\n\t7657,\n\t2821,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2569,\n\t34439,\n\t0,\n\t0,\n\t3790,\n\t0,\n\t0,\n\t0,\n\t15339,\n\t8775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15908,\n\t0,\n\t0,\n\t21419,\n\t8359,\n\t0,\n\t0,\n\t0,\n\t0,\n\t424,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25318,\n\t8008,\n\t20551,\n\t0,\n\t0,\n\t0,\n\t45735,\n\t30058,\n\t30372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26180,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31432,\n\t10567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17450,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30310,\n\t0,\n\t38022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28932,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22180,\n\t12075,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22247,\n\t0,\n\t0,\n\t22826,\n\t12359,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4105,\n\t50407,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13581,\n\t28583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28936,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17673,\n\t10310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t905,\n\t57862,\n\t1580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13479,\n\t0,\n\t0,\n\t14153,\n\t13286,\n\t0,\n\t0,\n\t9259,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6606,\n\t3524,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t631,\n\t49255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42886,\n\t0,\n\t38215,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10213,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3604,\n\t37767,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62087,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23528,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28715,\n\t4229,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1226,\n\t26820,\n\t0,\n\t0,\n\t0,\n\t12133,\n\t6984,\n\t261,\n\t21130,\n\t32548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3565,\n\t12390,\n\t20713,\n\t28071,\n\t0,\n\t0,\n\t1706,\n\t25287,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30534,\n\t0,\n\t0,\n\t0,\n\t12615,\n\t0,\n\t43750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28228,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1224,\n\t3975,\n\t10954,\n\t6375,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23180,\n\t20100,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25736,\n\t8519,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6663,\n\t0,\n\t2534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23720,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19398,\n\t0,\n\t47814,\n\t26281,\n\t49702,\n\t0,\n\t0,\n\t4332,\n\t12965,\n\t0,\n\t0,\n\t5704,\n\t3206,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15396,\n\t0,\n\t0,\n\t0,\n\t44102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25317,\n\t1064,\n\t39271,\n\t27433,\n\t0,\n\t14952,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2763,\n\t4100,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18792,\n\t0,\n\t0,\n\t0,\n\t22154,\n\t32583,\n\t0,\n\t6244,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49478,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21894,\n\t0,\n\t0,\n\t11048,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11685,\n\t0,\n\t53862,\n\t0,\n\t0,\n\t15114,\n\t0,\n\t13870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t919,\n\t0,\n\t0,\n\t0,\n\t31916,\n\t0,\n\t22570,\n\t101,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7333,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3272,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27718,\n\t32712,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1782,\n\t0,\n\t3688,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29862,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55302,\n\t850,\n\t15492,\n\t0,\n\t0,\n\t0,\n\t5927,\n\t19786,\n\t13350,\n\t0,\n\t25702,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20260,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15335,\n\t8394,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t843,\n\t2245,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6959,\n\t0,\n\t20488,\n\t1638,\n\t0,\n\t0,\n\t11533,\n\t50759,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20871,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24519,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9544,\n\t23591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20969,\n\t7109,\n\t29001,\n\t0,\n\t0,\n\t32422,\n\t31720,\n\t64294,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16106,\n\t0,\n\t0,\n\t0,\n\t6930,\n\t4933,\n\t0,\n\t0,\n\t0,\n\t22917,\n\t0,\n\t27015,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19880,\n\t8070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23945,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3310,\n\t0,\n\t87,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18439,\n\t0,\n\t0,\n\t0,\n\t20742,\n\t0,\n\t0,\n\t0,\n\t10597,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20236,\n\t0,\n\t0,\n\t0,\n\t16584,\n\t3429,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27241,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16132,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t244,\n\t28261,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29509,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2921,\n\t31781,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6408,\n\t4196,\n\t344,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11689,\n\t45863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t906,\n\t3301,\n\t0,\n\t0,\n\t25544,\n\t32421,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1260,\n\t61607,\n\t0,\n\t27302,\n\t0,\n\t0,\n\t8682,\n\t16614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10830,\n\t0,\n\t0,\n\t9604,\n\t15049,\n\t13413,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26761,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12580,\n\t0,\n\t0,\n\t11432,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22507,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12389,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2408,\n\t22661,\n\t14507,\n\t43239,\n\t0,\n\t9700,\n\t0,\n\t0,\n\t24714,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34086,\n\t0,\n\t0,\n\t22955,\n\t7238,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28485,\n\t13806,\n\t20038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22602,\n\t0,\n\t0,\n\t0,\n\t1645,\n\t22340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26502,\n\t0,\n\t0,\n\t554,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61735,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2694,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t883,\n\t27879,\n\t15948,\n\t0,\n\t3242,\n\t57382,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13930,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30922,\n\t0,\n\t4137,\n\t52615,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31911,\n\t16072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26340,\n\t0,\n\t61671,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3145,\n\t56199,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t280,\n\t0,\n\t5131,\n\t33479,\n\t0,\n\t15751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4136,\n\t1446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11304,\n\t17863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25125,\n\t0,\n\t0,\n\t0,\n\t36646,\n\t6057,\n\t0,\n\t0,\n\t0,\n\t855,\n\t11301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64774,\n\t0,\n\t0,\n\t0,\n\t19397,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1040,\n\t27367,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64358,\n\t0,\n\t0,\n\t178,\n\t132,\n\t0,\n\t0,\n\t14763,\n\t24455,\n\t0,\n\t0,\n\t0,\n\t46374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46246,\n\t0,\n\t0,\n\t0,\n\t37382,\n\t0,\n\t0,\n\t0,\n\t7462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8166,\n\t0,\n\t0,\n\t6921,\n\t0,\n\t0,\n\t0,\n\t9163,\n\t0,\n\t0,\n\t0,\n\t119,\n\t0,\n\t0,\n\t0,\n\t23146,\n\t17156,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9127,\n\t0,\n\t0,\n\t0,\n\t17927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22084,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39879,\n\t0,\n\t0,\n\t2035,\n\t0,\n\t1067,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16652,\n\t59591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20171,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17733,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42022,\n\t0,\n\t0,\n\t26793,\n\t20358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8907,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32330,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39399,\n\t0,\n\t9732,\n\t0,\n\t16199,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t854,\n\t0,\n\t2984,\n\t45063,\n\t25418,\n\t26980,\n\t22539,\n\t0,\n\t9133,\n\t3653,\n\t15528,\n\t28743,\n\t4649,\n\t0,\n\t616,\n\t65127,\n\t0,\n\t0,\n\t0,\n\t61863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23880,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31848,\n\t62854,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49606,\n\t0,\n\t27974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32580,\n\t0,\n\t0,\n\t0,\n\t26052,\n\t4043,\n\t0,\n\t0,\n\t40454,\n\t0,\n\t0,\n\t26056,\n\t30565,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29288,\n\t1797,\n\t0,\n\t0,\n\t3220,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20427,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23621,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24261,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35591,\n\t0,\n\t0,\n\t6862,\n\t0,\n\t0,\n\t0,\n\t4265,\n\t0,\n\t6285,\n\t5383,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36870,\n\t0,\n\t39847,\n\t0,\n\t0,\n\t17224,\n\t5414,\n\t27882,\n\t58118,\n\t0,\n\t0,\n\t13224,\n\t4262,\n\t0,\n\t0,\n\t0,\n\t31302,\n\t0,\n\t0,\n\t1388,\n\t2982,\n\t11881,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16837,\n\t809,\n\t0,\n\t24140,\n\t10724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5835,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1256,\n\t19237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5796,\n\t11848,\n\t0,\n\t0,\n\t52870,\n\t11464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5645,\n\t9158,\n\t0,\n\t25223,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39142,\n\t24968,\n\t8135,\n\t32104,\n\t28678,\n\t0,\n\t0,\n\t0,\n\t46311,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23820,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4050,\n\t0,\n\t1323,\n\t25220,\n\t0,\n\t0,\n\t0,\n\t20133,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13444,\n\t1198,\n\t60806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17356,\n\t50247,\n\t30632,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11944,\n\t999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4010,\n\t10404,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10346,\n\t0,\n\t0,\n\t49510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6351,\n\t60966,\n\t20137,\n\t487,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t655,\n\t2406,\n\t17387,\n\t43303,\n\t0,\n\t0,\n\t0,\n\t17063,\n\t0,\n\t0,\n\t213,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17221,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10820,\n\t0,\n\t0,\n\t0,\n\t0,\n\t369,\n\t6,\n\t0,\n\t0,\n\t9098,\n\t21093,\n\t0,\n\t31653,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27143,\n\t0,\n\t0,\n\t16234,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6020,\n\t31723,\n\t28293,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1936,\n\t30695,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52902,\n\t0,\n\t0,\n\t29512,\n\t10791,\n\t0,\n\t20420,\n\t0,\n\t0,\n\t16010,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5324,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13383,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24328,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24648,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7786,\n\t2852,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44678,\n\t0,\n\t17925,\n\t0,\n\t0,\n\t105,\n\t53062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18762,\n\t0,\n\t0,\n\t40679,\n\t0,\n\t0,\n\t0,\n\t16165,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62310,\n\t1322,\n\t14247,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1832,\n\t6052,\n\t0,\n\t0,\n\t11882,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17668,\n\t0,\n\t28262,\n\t0,\n\t29542,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28007,\n\t0,\n\t0,\n\t0,\n\t57223,\n\t1585,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21162,\n\t0,\n\t0,\n\t62247,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36326,\n\t0,\n\t0,\n\t0,\n\t23845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2693,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13125,\n\t0,\n\t31236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5994,\n\t10309,\n\t0,\n\t0,\n\t0,\n\t7269,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17929,\n\t0,\n\t1011,\n\t44647,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20586,\n\t5350,\n\t0,\n\t0,\n\t0,\n\t45702,\n\t0,\n\t13189,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35782,\n\t17992,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8203,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38087,\n\t4233,\n\t0,\n\t2127,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10148,\n\t0,\n\t0,\n\t0,\n\t2021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47206,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9220,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19465,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t39206,\n\t0,\n\t38055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22054,\n\t3850,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55,\n\t0,\n\t10542,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t59367,\n\t0,\n\t0,\n\t14761,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43079,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2726,\n\t0,\n\t0,\n\t9582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t37478,\n\t0,\n\t0,\n\t0,\n\t31364,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20393,\n\t8933,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9380,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16905,\n\t549,\n\t0,\n\t0,\n\t0,\n\t0,\n\t182,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1558,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19242,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24933,\n\t0,\n\t6276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42310,\n\t23595,\n\t24068,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13191,\n\t6158,\n\t2567,\n\t0,\n\t0,\n\t268,\n\t47047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27940,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8200,\n\t1222,\n\t31562,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2922,\n\t8231,\n\t8904,\n\t29157,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23976,\n\t4836,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31658,\n\t0,\n\t0,\n\t31685,\n\t0,\n\t0,\n\t2889,\n\t6213,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13605,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24772,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20684,\n\t26468,\n\t24075,\n\t0,\n\t0,\n\t0,\n\t21193,\n\t0,\n\t715,\n\t679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3050,\n\t7654,\n\t0,\n\t0,\n\t0,\n\t13798,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15,\n\t27973,\n\t0,\n\t0,\n\t8491,\n\t2086,\n\t0,\n\t0,\n\t0,\n\t43206,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t60391,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25892,\n\t0,\n\t22276,\n\t0,\n\t34374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20165,\n\t0,\n\t0,\n\t25672,\n\t0,\n\t0,\n\t0,\n\t1811,\n\t24839,\n\t0,\n\t31044,\n\t0,\n\t0,\n\t25513,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12810,\n\t0,\n\t0,\n\t62438,\n\t0,\n\t0,\n\t1325,\n\t0,\n\t364,\n\t3782,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8042,\n\t19687,\n\t0,\n\t0,\n\t0,\n\t33415,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7205,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3341,\n\t1543,\n\t6698,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29766,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41158,\n\t0,\n\t24294,\n\t0,\n\t3844,\n\t12329,\n\t0,\n\t0,\n\t0,\n\t13738,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26245,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6378,\n\t0,\n\t343,\n\t4838,\n\t0,\n\t0,\n\t0,\n\t24358,\n\t11688,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1489,\n\t34759,\n\t0,\n\t0,\n\t0,\n\t0,\n\t363,\n\t51974,\n\t1878,\n\t11013,\n\t0,\n\t0,\n\t32265,\n\t59782,\n\t0,\n\t0,\n\t0,\n\t28421,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22756,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14089,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29257,\n\t61222,\n\t0,\n\t30661,\n\t0,\n\t28327,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27108,\n\t8843,\n\t0,\n\t9673,\n\t2084,\n\t0,\n\t0,\n\t0,\n\t16327,\n\t0,\n\t48455,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4876,\n\t9316,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9035,\n\t18852,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4164,\n\t0,\n\t0,\n\t14827,\n\t1349,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11909,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21765,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31272,\n\t63910,\n\t0,\n\t0,\n\t0,\n\t25924,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44487,\n\t0,\n\t0,\n\t0,\n\t20612,\n\t0,\n\t0,\n\t27754,\n\t31428,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17287,\n\t0,\n\t3943,\n\t0,\n\t0,\n\t0,\n\t63302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25256,\n\t19942,\n\t0,\n\t55142,\n\t0,\n\t39046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15367,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28422,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9576,\n\t63847,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25226,\n\t5734,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13801,\n\t4997,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43942,\n\t1270,\n\t2566,\n\t6284,\n\t0,\n\t0,\n\t16230,\n\t0,\n\t0,\n\t0,\n\t20678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29643,\n\t0,\n\t0,\n\t0,\n\t41,\n\t3655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15686,\n\t0,\n\t0,\n\t0,\n\t15718,\n\t0,\n\t50694,\n\t0,\n\t0,\n\t16232,\n\t8007,\n\t0,\n\t0,\n\t0,\n\t5060,\n\t329,\n\t11591,\n\t51,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13065,\n\t7302,\n\t27530,\n\t15366,\n\t0,\n\t24934,\n\t0,\n\t0,\n\t0,\n\t17828,\n\t0,\n\t0,\n\t4552,\n\t6311,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47686,\n\t368,\n\t12103,\n\t10122,\n\t33830,\n\t0,\n\t0,\n\t599,\n\t18534,\n\t9579,\n\t49479,\n\t0,\n\t5668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13157,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23274,\n\t14055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48903,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1871,\n\t0,\n\t15434,\n\t0,\n\t0,\n\t0,\n\t16174,\n\t62470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30501,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25675,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9285,\n\t0,\n\t0,\n\t25323,\n\t1669,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32902,\n\t0,\n\t0,\n\t4426,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57959,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29898,\n\t58278,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11880,\n\t1220,\n\t0,\n\t0,\n\t0,\n\t41479,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23141,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40167,\n\t9484,\n\t3493,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8649,\n\t18918,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34886,\n\t2601,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7976,\n\t10311,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16842,\n\t20229,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7528,\n\t4614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30086,\n\t0,\n\t0,\n\t0,\n\t1671,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9896,\n\t6277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61191,\n\t0,\n\t41287,\n\t0,\n\t21956,\n\t0,\n\t0,\n\t20010,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13195,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t365,\n\t30951,\n\t24268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7044,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27944,\n\t359,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28487,\n\t0,\n\t0,\n\t77,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t56775,\n\t12586,\n\t8421,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26185,\n\t14599,\n\t0,\n\t0,\n\t8040,\n\t5702,\n\t12585,\n\t3109,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21574,\n\t5388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5106,\n\t52454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1907,\n\t29895,\n\t0,\n\t6116,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11081,\n\t5285,\n\t0,\n\t28069,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4104,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41511,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5262,\n\t0,\n\t0,\n\t0,\n\t503,\n\t4231,\n\t7720,\n\t34343,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7304,\n\t10374,\n\t1718,\n\t0,\n\t0,\n\t29127,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23497,\n\t22567,\n\t6952,\n\t2340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20360,\n\t12453,\n\t0,\n\t45094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t680,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23084,\n\t0,\n\t0,\n\t0,\n\t30696,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45862,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5580,\n\t6053,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t712,\n\t70,\n\t0,\n\t0,\n\t26091,\n\t11335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13612,\n\t0,\n\t13160,\n\t1926,\n\t435,\n\t51559,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47302,\n\t19083,\n\t0,\n\t0,\n\t12742,\n\t0,\n\t1607,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6155,\n\t37095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18948,\n\t7146,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7848,\n\t2055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8910,\n\t0,\n\t19336,\n\t0,\n\t0,\n\t48070,\n\t8490,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9932,\n\t56423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4133,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16173,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32011,\n\t0,\n\t0,\n\t30918,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26854,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20389,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18889,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8965,\n\t0,\n\t0,\n\t0,\n\t44358,\n\t0,\n\t0,\n\t0,\n\t8997,\n\t0,\n\t34055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29350,\n\t0,\n\t0,\n\t501,\n\t17767,\n\t0,\n\t0,\n\t32457,\n\t60262,\n\t0,\n\t0,\n\t0,\n\t30886,\n\t0,\n\t0,\n\t3757,\n\t1063,\n\t0,\n\t0,\n\t0,\n\t25637,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28068,\n\t0,\n\t26374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24779,\n\t229,\n\t0,\n\t13766,\n\t0,\n\t0,\n\t7402,\n\t11525,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26313,\n\t23686,\n\t0,\n\t0,\n\t29736,\n\t47527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t553,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1135,\n\t26596,\n\t0,\n\t0,\n\t12300,\n\t14631,\n\t0,\n\t0,\n\t0,\n\t43238,\n\t0,\n\t871,\n\t0,\n\t0,\n\t31496,\n\t0,\n\t8457,\n\t17669,\n\t0,\n\t12836,\n\t0,\n\t0,\n\t0,\n\t22726,\n\t0,\n\t38758,\n\t0,\n\t0,\n\t375,\n\t6564,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t170,\n\t18535,\n\t0,\n\t22948,\n\t0,\n\t0,\n\t32360,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25764,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15652,\n\t0,\n\t0,\n\t0,\n\t32774,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15145,\n\t0,\n\t0,\n\t0,\n\t21100,\n\t27654,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4874,\n\t26215,\n\t0,\n\t1639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4169,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7336,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21572,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24644,\n\t1675,\n\t2533,\n\t0,\n\t0,\n\t0,\n\t53318,\n\t0,\n\t13094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6246,\n\t0,\n\t22020,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28453,\n\t5576,\n\t5124,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27910,\n\t0,\n\t29382,\n\t18216,\n\t8583,\n\t0,\n\t0,\n\t0,\n\t39174,\n\t0,\n\t43558,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11973,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23397,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6091,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6474,\n\t16197,\n\t14217,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26728,\n\t0,\n\t567,\n\t48839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15271,\n\t0,\n\t0,\n\t31818,\n\t43974,\n\t2450,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11368,\n\t9191,\n\t0,\n\t44454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14568,\n\t12293,\n\t0,\n\t0,\n\t0,\n\t8453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32040,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t902,\n\t0,\n\t0,\n\t0,\n\t27236,\n\t5612,\n\t11495,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9194,\n\t23684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27430,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26217,\n\t44870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5581,\n\t7173,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20968,\n\t18340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4107,\n\t11239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48806,\n\t0,\n\t0,\n\t0,\n\t32292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10884,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27562,\n\t0,\n\t5643,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3089,\n\t31525,\n\t0,\n\t19684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61415,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7908,\n\t0,\n\t0,\n\t0,\n\t0,\n\t872,\n\t743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1229,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34822,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7274,\n\t0,\n\t0,\n\t0,\n\t15304,\n\t11526,\n\t0,\n\t0,\n\t0,\n\t3047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22376,\n\t0,\n\t0,\n\t0,\n\t846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35815,\n\t0,\n\t0,\n\t0,\n\t23652,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23721,\n\t2148,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14856,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1358,\n\t0,\n\t3082,\n\t0,\n\t0,\n\t0,\n\t848,\n\t10949,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6504,\n\t0,\n\t0,\n\t14372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8201,\n\t9958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24266,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18604,\n\t2053,\n\t0,\n\t33511,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9222,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44006,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12044,\n\t390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4935,\n\t0,\n\t48646,\n\t0,\n\t56102,\n\t3052,\n\t16070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8612,\n\t9320,\n\t38311,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t500,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42918,\n\t0,\n\t32550,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27434,\n\t57926,\n\t17064,\n\t0,\n\t0,\n\t46502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26760,\n\t6756,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t624,\n\t0,\n\t5000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32293,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26246,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23,\n\t7301,\n\t0,\n\t0,\n\t0,\n\t36199,\n\t0,\n\t40838,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27178,\n\t57350,\n\t0,\n\t0,\n\t12457,\n\t9317,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16810,\n\t0,\n\t0,\n\t0,\n\t14510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21319,\n\t0,\n\t0,\n\t0,\n\t13508,\n\t17,\n\t11365,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5291,\n\t0,\n\t8329,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27685,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t52006,\n\t0,\n\t0,\n\t0,\n\t7493,\n\t0,\n\t44263,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9800,\n\t0,\n\t0,\n\t0,\n\t25676,\n\t61478,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5773,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41991,\n\t26057,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22629,\n\t0,\n\t0,\n\t0,\n\t47783,\n\t362,\n\t1959,\n\t23468,\n\t0,\n\t0,\n\t0,\n\t10921,\n\t0,\n\t0,\n\t0,\n\t3150,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32456,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4559,\n\t3270,\n\t0,\n\t0,\n\t983,\n\t0,\n\t0,\n\t26343,\n\t0,\n\t33446,\n\t0,\n\t0,\n\t0,\n\t61767,\n\t0,\n\t48390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2790,\n\t0,\n\t39782,\n\t7849,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1544,\n\t2183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4040,\n\t2471,\n\t20009,\n\t30020,\n\t0,\n\t0,\n\t11242,\n\t0,\n\t0,\n\t0,\n\t5578,\n\t53382,\n\t0,\n\t22631,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12901,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t215,\n\t0,\n\t0,\n\t9030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t265,\n\t1412,\n\t0,\n\t0,\n\t11626,\n\t3687,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17449,\n\t24359,\n\t0,\n\t0,\n\t26729,\n\t40134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29768,\n\t61958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20908,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11016,\n\t0,\n\t0,\n\t47462,\n\t21547,\n\t5926,\n\t0,\n\t0,\n\t14728,\n\t2983,\n\t24104,\n\t15301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3300,\n\t0,\n\t0,\n\t0,\n\t15972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6634,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3076,\n\t0,\n\t30983,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t106,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7177,\n\t18022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27560,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30278,\n\t10668,\n\t23877,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29124,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t44582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6442,\n\t0,\n\t16330,\n\t22951,\n\t0,\n\t0,\n\t16904,\n\t0,\n\t0,\n\t0,\n\t0,\n\t644,\n\t0,\n\t0,\n\t0,\n\t40038,\n\t0,\n\t0,\n\t0,\n\t37222,\n\t0,\n\t0,\n\t0,\n\t9830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13733,\n\t0,\n\t0,\n\t0,\n\t28196,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19876,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23558,\n\t0,\n\t11142,\n\t0,\n\t27781,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13864,\n\t0,\n\t0,\n\t0,\n\t24682,\n\t47847,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6890,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3981,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1772,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3603,\n\t1991,\n\t0,\n\t27396,\n\t8652,\n\t0,\n\t18312,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30054,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11270,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20708,\n\t0,\n\t0,\n\t0,\n\t0,\n\t338,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7050,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14862,\n\t0,\n\t0,\n\t3492,\n\t0,\n\t0,\n\t0,\n\t55878,\n\t0,\n\t0,\n\t0,\n\t16486,\n\t0,\n\t0,\n\t0,\n\t18119,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2154,\n\t1284,\n\t0,\n\t0,\n\t23113,\n\t31751,\n\t0,\n\t0,\n\t29547,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36647,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7913,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20644,\n\t0,\n\t0,\n\t10508,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40966,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t246,\n\t901,\n\t11529,\n\t5191,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24454,\n\t0,\n\t0,\n\t26665,\n\t27590,\n\t0,\n\t27397,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23562,\n\t2949,\n\t0,\n\t0,\n\t30344,\n\t62214,\n\t0,\n\t47334,\n\t2026,\n\t18885,\n\t0,\n\t0,\n\t0,\n\t48678,\n\t0,\n\t0,\n\t0,\n\t22694,\n\t0,\n\t0,\n\t1972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15465,\n\t0,\n\t0,\n\t0,\n\t0,\n\t38822,\n\t0,\n\t0,\n\t0,\n\t0,\n\t945,\n\t32708,\n\t0,\n\t54791,\n\t0,\n\t14918,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23396,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7722,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30856,\n\t64166,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35206,\n\t0,\n\t0,\n\t0,\n\t30535,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62663,\n\t0,\n\t0,\n\t1096,\n\t17574,\n\t31820,\n\t0,\n\t0,\n\t14375,\n\t4402,\n\t27207,\n\t0,\n\t0,\n\t21448,\n\t4676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16585,\n\t5094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4845,\n\t0,\n\t0,\n\t32870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31466,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31783,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4522,\n\t16039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7464,\n\t4773,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18636,\n\t0,\n\t0,\n\t0,\n\t25640,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2244,\n\t0,\n\t0,\n\t11818,\n\t0,\n\t1168,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6540,\n\t23079,\n\t13770,\n\t7719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58150,\n\t528,\n\t34502,\n\t32682,\n\t0,\n\t0,\n\t12997,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58567,\n\t0,\n\t0,\n\t0,\n\t26375,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26437,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26121,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32005,\n\t22952,\n\t59047,\n\t0,\n\t13543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16328,\n\t0,\n\t0,\n\t33542,\n\t0,\n\t0,\n\t0,\n\t19782,\n\t0,\n\t0,\n\t0,\n\t16644,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31688,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36327,\n\t0,\n\t0,\n\t29480,\n\t0,\n\t0,\n\t0,\n\t777,\n\t12709,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27398,\n\t0,\n\t0,\n\t0,\n\t4455,\n\t9037,\n\t31397,\n\t0,\n\t9221,\n\t0,\n\t0,\n\t0,\n\t60487,\n\t20840,\n\t1796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8364,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19752,\n\t44902,\n\t0,\n\t38566,\n\t0,\n\t0,\n\t18027,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19910,\n\t0,\n\t0,\n\t0,\n\t45030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19978,\n\t5127,\n\t0,\n\t11620,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19817,\n\t0,\n\t5579,\n\t9350,\n\t0,\n\t0,\n\t21002,\n\t19718,\n\t0,\n\t0,\n\t0,\n\t21926,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20711,\n\t0,\n\t0,\n\t0,\n\t20197,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40550,\n\t0,\n\t0,\n\t0,\n\t57510,\n\t0,\n\t0,\n\t0,\n\t53895,\n\t0,\n\t0,\n\t15017,\n\t0,\n\t17000,\n\t39367,\n\t2347,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3273,\n\t17862,\n\t3498,\n\t2085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19048,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11978,\n\t58631,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t523,\n\t0,\n\t12969,\n\t198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28197,\n\t0,\n\t47846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4549,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t687,\n\t14917,\n\t748,\n\t8229,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2476,\n\t12935,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22792,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27528,\n\t59142,\n\t0,\n\t0,\n\t20876,\n\t20134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t440,\n\t12068,\n\t0,\n\t58951,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48038,\n\t0,\n\t0,\n\t0,\n\t60999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15716,\n\t7498,\n\t5476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20202,\n\t37959,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29801,\n\t0,\n\t5451,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50790,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24485,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13573,\n\t0,\n\t0,\n\t22856,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9130,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13732,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2282,\n\t583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3726,\n\t26503,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9258,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21604,\n\t0,\n\t0,\n\t0,\n\t45574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20710,\n\t0,\n\t0,\n\t0,\n\t42694,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1163,\n\t6694,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10948,\n\t0,\n\t0,\n\t0,\n\t29700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58823,\n\t3796,\n\t27399,\n\t20939,\n\t10180,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19,\n\t29287,\n\t28649,\n\t14534,\n\t0,\n\t0,\n\t16428,\n\t45607,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25322,\n\t0,\n\t4908,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25476,\n\t29097,\n\t14246,\n\t11053,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18502,\n\t0,\n\t0,\n\t0,\n\t44390,\n\t0,\n\t0,\n\t0,\n\t17765,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24520,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17319,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28166,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48198,\n\t0,\n\t0,\n\t31467,\n\t0,\n\t24585,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18692,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23596,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7236,\n\t968,\n\t13637,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14791,\n\t0,\n\t0,\n\t0,\n\t12324,\n\t0,\n\t12741,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4009,\n\t40295,\n\t20616,\n\t4357,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15015,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t43751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23013,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45542,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17480,\n\t20647,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8876,\n\t0,\n\t0,\n\t40806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14502,\n\t17160,\n\t17764,\n\t0,\n\t0,\n\t31594,\n\t35431,\n\t0,\n\t0,\n\t2890,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27524,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8228,\n\t0,\n\t56583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t34278,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2662,\n\t0,\n\t26724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22281,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3049,\n\t54983,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t837,\n\t0,\n\t17604,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28838,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26312,\n\t0,\n\t0,\n\t3910,\n\t0,\n\t0,\n\t0,\n\t25830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8391,\n\t0,\n\t19845,\n\t19240,\n\t1092,\n\t0,\n\t0,\n\t5449,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10629,\n\t0,\n\t0,\n\t6671,\n\t61094,\n\t5832,\n\t8358,\n\t0,\n\t0,\n\t0,\n\t55078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29860,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51494,\n\t0,\n\t28647,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25989,\n\t0,\n\t0,\n\t30153,\n\t61318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24903,\n\t0,\n\t0,\n\t0,\n\t4388,\n\t0,\n\t42054,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t53158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50918,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26251,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5929,\n\t2853,\n\t0,\n\t37126,\n\t7372,\n\t197,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2027,\n\t934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55686,\n\t0,\n\t0,\n\t5672,\n\t5447,\n\t0,\n\t62758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2923,\n\t0,\n\t556,\n\t1415,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8645,\n\t0,\n\t9477,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t48742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24235,\n\t228,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16970,\n\t18823,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18567,\n\t20072,\n\t2823,\n\t14313,\n\t1830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27048,\n\t23526,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t997,\n\t492,\n\t0,\n\t14730,\n\t16677,\n\t396,\n\t13574,\n\t0,\n\t0,\n\t0,\n\t41671,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19045,\n\t0,\n\t0,\n\t0,\n\t421,\n\t17545,\n\t3110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t47111,\n\t14475,\n\t56551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3697,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49382,\n\t0,\n\t35559,\n\t0,\n\t0,\n\t0,\n\t0,\n\t40,\n\t0,\n\t11496,\n\t15621,\n\t0,\n\t8550,\n\t0,\n\t0,\n\t0,\n\t63462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t36966,\n\t0,\n\t50406,\n\t0,\n\t46022,\n\t1001,\n\t0,\n\t0,\n\t12069,\n\t3249,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15241,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t64743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t58759,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1136,\n\t26981,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17732,\n\t0,\n\t0,\n\t0,\n\t17157,\n\t20011,\n\t6629,\n\t0,\n\t43879,\n\t0,\n\t0,\n\t0,\n\t13572,\n\t25128,\n\t10759,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t875,\n\t24007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7628,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19300,\n\t23210,\n\t356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49670,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21764,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13931,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t45799,\n\t0,\n\t0,\n\t436,\n\t3589,\n\t0,\n\t0,\n\t11402,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t62822,\n\t0,\n\t0,\n\t0,\n\t39814,\n\t588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1609,\n\t22660,\n\t2346,\n\t18951,\n\t0,\n\t16068,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5162,\n\t11110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15048,\n\t1060,\n\t0,\n\t7879,\n\t18280,\n\t326,\n\t0,\n\t14886,\n\t19656,\n\t0,\n\t7594,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t781,\n\t581,\n\t0,\n\t16198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1078,\n\t9892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4489,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33798,\n\t0,\n\t0,\n\t0,\n\t54534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t33158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t42086,\n\t13834,\n\t2757,\n\t8456,\n\t16773,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3434,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3946,\n\t29668,\n\t0,\n\t0,\n\t30634,\n\t36775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24901,\n\t0,\n\t16069,\n\t6280,\n\t0,\n\t0,\n\t0,\n\t0,\n\t41990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27365,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1450,\n\t44807,\n\t0,\n\t0,\n\t0,\n\t32100,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t35110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17448,\n\t19591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1739,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5511,\n\t0,\n\t0,\n\t0,\n\t32934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18180,\n\t0,\n\t0,\n\t0,\n\t23428,\n\t19754,\n\t0,\n\t0,\n\t31174,\n\t3021,\n\t31655,\n\t23464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t57255,\n\t0,\n\t0,\n\t21292,\n\t64487,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25802,\n\t9189,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t49254,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5837,\n\t50023,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15495,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t51942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28104,\n\t58662,\n\t0,\n\t50214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2988,\n\t0,\n\t22888,\n\t31812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2020,\n\t0,\n\t18916,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23973,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17516,\n\t11717,\n\t0,\n\t0,\n\t0,\n\t55911,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46822,\n\t0,\n\t24710,\n\t28586,\n\t0,\n\t0,\n\t0,\n\t1556,\n\t0,\n\t0,\n\t30117,\n\t0,\n\t0,\n\t22090,\n\t57127,\n\t3403,\n\t14087,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1041,\n\t0,\n\t10633,\n\t6916,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27269,\n\t0,\n\t0,\n\t13322,\n\t18055,\n\t0,\n\t29380,\n\t0,\n\t56454,\n\t0,\n\t0,\n\t120,\n\t0,\n\t0,\n\t8773,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16040,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27242,\n\t23781,\n\t0,\n\t1572,\n\t0,\n\t28134,\n\t0,\n\t0,\n\t1512,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27684,\n\t0,\n\t38470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1513,\n\t8709,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28521,\n\t61159,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13028,\n\t0,\n\t5863,\n\t0,\n\t0,\n\t15693,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1131,\n\t23398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26212,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18404,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1457,\n\t26183,\n\t0,\n\t0,\n\t2475,\n\t7110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27180,\n\t60166,\n\t0,\n\t0,\n\t0,\n\t20262,\n\t0,\n\t41862,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2762,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26148,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28229,\n\t0,\n\t0,\n\t0,\n\t29254,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27690,\n\t0,\n\t0,\n\t13636,\n\t12776,\n\t1862,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17225,\n\t3271,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4457,\n\t18117,\n\t0,\n\t2023,\n\t402,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t104,\n\t3654,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18440,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29861,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22150,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24074,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12004,\n\t0,\n\t32358,\n\t0,\n\t0,\n\t3081,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10792,\n\t1799,\n\t21322,\n\t0,\n\t7880,\n\t12613,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13993,\n\t0,\n\t0,\n\t0,\n\t16202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32102,\n\t0,\n\t37223,\n\t0,\n\t10500,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t32008,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23816,\n\t3236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23237,\n\t0,\n\t0,\n\t5642,\n\t0,\n\t4684,\n\t294,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26852,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7148,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7890,\n\t61798,\n\t939,\n\t0,\n\t0,\n\t56679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27078,\n\t202,\n\t5029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28005,\n\t0,\n\t0,\n\t15273,\n\t24741,\n\t5676,\n\t20452,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5069,\n\t27942,\n\t0,\n\t21092,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12517,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21384,\n\t28260,\n\t0,\n\t2502,\n\t20108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t46726,\n\t0,\n\t30790,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14725,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1099,\n\t6372,\n\t0,\n\t0,\n\t0,\n\t12422,\n\t15182,\n\t0,\n\t8683,\n\t0,\n\t10665,\n\t19462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1590,\n\t0,\n\t31628,\n\t0,\n\t22632,\n\t19750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t50662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9131,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11015,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16490,\n\t54695,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12937,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16004,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2181,\n\t6923,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15624,\n\t11302,\n\t0,\n\t0,\n\t5673,\n\t7559,\n\t0,\n\t0,\n\t14668,\n\t15684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24204,\n\t48134,\n\t0,\n\t24230,\n\t0,\n\t55527,\n\t0,\n\t0,\n\t3464,\n\t19141,\n\t0,\n\t0,\n\t0,\n\t0,\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/encode.go",
    "content": "package brotli\n\nimport (\n\t\"io\"\n\t\"math\"\n)\n\n/* Copyright 2016 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/** Minimal value for ::BROTLI_PARAM_LGWIN parameter. */\nconst minWindowBits = 10\n\n/**\n * Maximal value for ::BROTLI_PARAM_LGWIN parameter.\n *\n * @note equal to @c BROTLI_MAX_DISTANCE_BITS constant.\n */\nconst maxWindowBits = 24\n\n/**\n * Maximal value for ::BROTLI_PARAM_LGWIN parameter\n * in \"Large Window Brotli\" (32-bit).\n */\nconst largeMaxWindowBits = 30\n\n/** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */\nconst minInputBlockBits = 16\n\n/** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */\nconst maxInputBlockBits = 24\n\n/** Minimal value for ::BROTLI_PARAM_QUALITY parameter. */\nconst minQuality = 0\n\n/** Maximal value for ::BROTLI_PARAM_QUALITY parameter. */\nconst maxQuality = 11\n\n/** Options for ::BROTLI_PARAM_MODE parameter. */\nconst (\n\tmodeGeneric = 0\n\tmodeText    = 1\n\tmodeFont    = 2\n)\n\n/** Default value for ::BROTLI_PARAM_QUALITY parameter. */\nconst defaultQuality = 11\n\n/** Default value for ::BROTLI_PARAM_LGWIN parameter. */\nconst defaultWindow = 22\n\n/** Default value for ::BROTLI_PARAM_MODE parameter. */\nconst defaultMode = modeGeneric\n\n/** Operations that can be performed by streaming encoder. */\nconst (\n\toperationProcess      = 0\n\toperationFlush        = 1\n\toperationFinish       = 2\n\toperationEmitMetadata = 3\n)\n\nconst (\n\tstreamProcessing     = 0\n\tstreamFlushRequested = 1\n\tstreamFinished       = 2\n\tstreamMetadataHead   = 3\n\tstreamMetadataBody   = 4\n)\n\ntype Writer struct {\n\tdst     io.Writer\n\toptions WriterOptions\n\terr     error\n\n\tparams              encoderParams\n\thasher_             hasherHandle\n\tinput_pos_          uint64\n\tringbuffer_         ringBuffer\n\tcommands            []command\n\tnum_literals_       uint\n\tlast_insert_len_    uint\n\tlast_flush_pos_     uint64\n\tlast_processed_pos_ uint64\n\tdist_cache_         [numDistanceShortCodes]int\n\tsaved_dist_cache_   [4]int\n\tlast_bytes_         uint16\n\tlast_bytes_bits_    byte\n\tprev_byte_          byte\n\tprev_byte2_         byte\n\tstorage             []byte\n\tsmall_table_        [1 << 10]int\n\tlarge_table_        []int\n\tlarge_table_size_   uint\n\tcmd_depths_         [128]byte\n\tcmd_bits_           [128]uint16\n\tcmd_code_           [512]byte\n\tcmd_code_numbits_   uint\n\tcommand_buf_        []uint32\n\tliteral_buf_        []byte\n\ttiny_buf_           struct {\n\t\tu64 [2]uint64\n\t\tu8  [16]byte\n\t}\n\tremaining_metadata_bytes_ uint32\n\tstream_state_             int\n\tis_last_block_emitted_    bool\n\tis_initialized_           bool\n}\n\nfunc inputBlockSize(s *Writer) uint {\n\treturn uint(1) << uint(s.params.lgblock)\n}\n\nfunc unprocessedInputSize(s *Writer) uint64 {\n\treturn s.input_pos_ - s.last_processed_pos_\n}\n\nfunc remainingInputBlockSize(s *Writer) uint {\n\tvar delta uint64 = unprocessedInputSize(s)\n\tvar block_size uint = inputBlockSize(s)\n\tif delta >= uint64(block_size) {\n\t\treturn 0\n\t}\n\treturn block_size - uint(delta)\n}\n\n/* Wraps 64-bit input position to 32-bit ring-buffer position preserving\n   \"not-a-first-lap\" feature. */\nfunc wrapPosition(position uint64) uint32 {\n\tvar result uint32 = uint32(position)\n\tvar gb uint64 = position >> 30\n\tif gb > 2 {\n\t\t/* Wrap every 2GiB; The first 3GB are continuous. */\n\t\tresult = result&((1<<30)-1) | (uint32((gb-1)&1)+1)<<30\n\t}\n\n\treturn result\n}\n\nfunc (s *Writer) getStorage(size int) []byte {\n\tif len(s.storage) < size {\n\t\ts.storage = make([]byte, size)\n\t}\n\n\treturn s.storage\n}\n\nfunc hashTableSize(max_table_size uint, input_size uint) uint {\n\tvar htsize uint = 256\n\tfor htsize < max_table_size && htsize < input_size {\n\t\thtsize <<= 1\n\t}\n\n\treturn htsize\n}\n\nfunc getHashTable(s *Writer, quality int, input_size uint, table_size *uint) []int {\n\tvar max_table_size uint = maxHashTableSize(quality)\n\tvar htsize uint = hashTableSize(max_table_size, input_size)\n\t/* Use smaller hash table when input.size() is smaller, since we\n\t   fill the table, incurring O(hash table size) overhead for\n\t   compression, and if the input is short, we won't need that\n\t   many hash table entries anyway. */\n\n\tvar table []int\n\tassert(max_table_size >= 256)\n\tif quality == fastOnePassCompressionQuality {\n\t\t/* Only odd shifts are supported by fast-one-pass. */\n\t\tif htsize&0xAAAAA == 0 {\n\t\t\thtsize <<= 1\n\t\t}\n\t}\n\n\tif htsize <= uint(len(s.small_table_)) {\n\t\ttable = s.small_table_[:]\n\t} else {\n\t\tif htsize > s.large_table_size_ {\n\t\t\ts.large_table_size_ = htsize\n\t\t\ts.large_table_ = nil\n\t\t\ts.large_table_ = make([]int, htsize)\n\t\t}\n\n\t\ttable = s.large_table_\n\t}\n\n\t*table_size = htsize\n\tfor i := 0; i < int(htsize); i++ {\n\t\ttable[i] = 0\n\t}\n\treturn table\n}\n\nfunc encodeWindowBits(lgwin int, large_window bool, last_bytes *uint16, last_bytes_bits *byte) {\n\tif large_window {\n\t\t*last_bytes = uint16((lgwin&0x3F)<<8 | 0x11)\n\t\t*last_bytes_bits = 14\n\t} else {\n\t\tif lgwin == 16 {\n\t\t\t*last_bytes = 0\n\t\t\t*last_bytes_bits = 1\n\t\t} else if lgwin == 17 {\n\t\t\t*last_bytes = 1\n\t\t\t*last_bytes_bits = 7\n\t\t} else if lgwin > 17 {\n\t\t\t*last_bytes = uint16((lgwin-17)<<1 | 0x01)\n\t\t\t*last_bytes_bits = 4\n\t\t} else {\n\t\t\t*last_bytes = uint16((lgwin-8)<<4 | 0x01)\n\t\t\t*last_bytes_bits = 7\n\t\t}\n\t}\n}\n\n/* Decide about the context map based on the ability of the prediction\n   ability of the previous byte UTF8-prefix on the next byte. The\n   prediction ability is calculated as Shannon entropy. Here we need\n   Shannon entropy instead of 'BitsEntropy' since the prefix will be\n   encoded with the remaining 6 bits of the following byte, and\n   BitsEntropy will assume that symbol to be stored alone using Huffman\n   coding. */\n\nvar kStaticContextMapContinuation = [64]uint32{\n\t1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n}\nvar kStaticContextMapSimpleUTF8 = [64]uint32{\n\t0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n}\n\nfunc chooseContextMap(quality int, bigram_histo []uint32, num_literal_contexts *uint, literal_context_map *[]uint32) {\n\tvar monogram_histo = [3]uint32{0}\n\tvar two_prefix_histo = [6]uint32{0}\n\tvar total uint\n\tvar i uint\n\tvar dummy uint\n\tvar entropy [4]float64\n\tfor i = 0; i < 9; i++ {\n\t\tmonogram_histo[i%3] += bigram_histo[i]\n\t\ttwo_prefix_histo[i%6] += bigram_histo[i]\n\t}\n\n\tentropy[1] = shannonEntropy(monogram_histo[:], 3, &dummy)\n\tentropy[2] = (shannonEntropy(two_prefix_histo[:], 3, &dummy) + shannonEntropy(two_prefix_histo[3:], 3, &dummy))\n\tentropy[3] = 0\n\tfor i = 0; i < 3; i++ {\n\t\tentropy[3] += shannonEntropy(bigram_histo[3*i:], 3, &dummy)\n\t}\n\n\ttotal = uint(monogram_histo[0] + monogram_histo[1] + monogram_histo[2])\n\tassert(total != 0)\n\tentropy[0] = 1.0 / float64(total)\n\tentropy[1] *= entropy[0]\n\tentropy[2] *= entropy[0]\n\tentropy[3] *= entropy[0]\n\n\tif quality < minQualityForHqContextModeling {\n\t\t/* 3 context models is a bit slower, don't use it at lower qualities. */\n\t\tentropy[3] = entropy[1] * 10\n\t}\n\n\t/* If expected savings by symbol are less than 0.2 bits, skip the\n\t   context modeling -- in exchange for faster decoding speed. */\n\tif entropy[1]-entropy[2] < 0.2 && entropy[1]-entropy[3] < 0.2 {\n\t\t*num_literal_contexts = 1\n\t} else if entropy[2]-entropy[3] < 0.02 {\n\t\t*num_literal_contexts = 2\n\t\t*literal_context_map = kStaticContextMapSimpleUTF8[:]\n\t} else {\n\t\t*num_literal_contexts = 3\n\t\t*literal_context_map = kStaticContextMapContinuation[:]\n\t}\n}\n\n/* Decide if we want to use a more complex static context map containing 13\n   context values, based on the entropy reduction of histograms over the\n   first 5 bits of literals. */\n\nvar kStaticContextMapComplexUTF8 = [64]uint32{\n\t11, 11, 12, 12, /* 0 special */\n\t0, 0, 0, 0, /* 4 lf */\n\t1, 1, 9, 9, /* 8 space */\n\t2, 2, 2, 2, /* !, first after space/lf and after something else. */\n\t1, 1, 1, 1, /* \" */\n\t8, 3, 3, 3, /* % */\n\t1, 1, 1, 1, /* ({[ */\n\t2, 2, 2, 2, /* }]) */\n\t8, 4, 4, 4, /* :; */\n\t8, 7, 4, 4, /* . */\n\t8, 0, 0, 0, /* > */\n\t3, 3, 3, 3, /* [0..9] */\n\t5, 5, 10, 5, /* [A-Z] */\n\t5, 5, 10, 5,\n\t6, 6, 6, 6, /* [a-z] */\n\t6, 6, 6, 6,\n}\n\nfunc shouldUseComplexStaticContextMap(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) bool {\n\t/* Try the more complex static context map only for long data. */\n\tif size_hint < 1<<20 {\n\t\treturn false\n\t} else {\n\t\tvar end_pos uint = start_pos + length\n\t\tvar combined_histo = [32]uint32{0}\n\t\tvar context_histo = [13][32]uint32{[32]uint32{0}}\n\t\tvar total uint32 = 0\n\t\tvar entropy [3]float64\n\t\tvar dummy uint\n\t\tvar i uint\n\t\tvar utf8_lut contextLUT = getContextLUT(contextUTF8)\n\t\t/* To make entropy calculations faster and to fit on the stack, we collect\n\t\t   histograms over the 5 most significant bits of literals. One histogram\n\t\t   without context and 13 additional histograms for each context value. */\n\t\tfor ; start_pos+64 <= end_pos; start_pos += 4096 {\n\t\t\tvar stride_end_pos uint = start_pos + 64\n\t\t\tvar prev2 byte = input[start_pos&mask]\n\t\t\tvar prev1 byte = input[(start_pos+1)&mask]\n\t\t\tvar pos uint\n\n\t\t\t/* To make the analysis of the data faster we only examine 64 byte long\n\t\t\t   strides at every 4kB intervals. */\n\t\t\tfor pos = start_pos + 2; pos < stride_end_pos; pos++ {\n\t\t\t\tvar literal byte = input[pos&mask]\n\t\t\t\tvar context byte = byte(kStaticContextMapComplexUTF8[getContext(prev1, prev2, utf8_lut)])\n\t\t\t\ttotal++\n\t\t\t\tcombined_histo[literal>>3]++\n\t\t\t\tcontext_histo[context][literal>>3]++\n\t\t\t\tprev2 = prev1\n\t\t\t\tprev1 = literal\n\t\t\t}\n\t\t}\n\n\t\tentropy[1] = shannonEntropy(combined_histo[:], 32, &dummy)\n\t\tentropy[2] = 0\n\t\tfor i = 0; i < 13; i++ {\n\t\t\tentropy[2] += shannonEntropy(context_histo[i][0:], 32, &dummy)\n\t\t}\n\n\t\tentropy[0] = 1.0 / float64(total)\n\t\tentropy[1] *= entropy[0]\n\t\tentropy[2] *= entropy[0]\n\n\t\t/* The triggering heuristics below were tuned by compressing the individual\n\t\t   files of the silesia corpus. If we skip this kind of context modeling\n\t\t   for not very well compressible input (i.e. entropy using context modeling\n\t\t   is 60% of maximal entropy) or if expected savings by symbol are less\n\t\t   than 0.2 bits, then in every case when it triggers, the final compression\n\t\t   ratio is improved. Note however that this heuristics might be too strict\n\t\t   for some cases and could be tuned further. */\n\t\tif entropy[2] > 3.0 || entropy[1]-entropy[2] < 0.2 {\n\t\t\treturn false\n\t\t} else {\n\t\t\t*num_literal_contexts = 13\n\t\t\t*literal_context_map = kStaticContextMapComplexUTF8[:]\n\t\t\treturn true\n\t\t}\n\t}\n}\n\nfunc decideOverLiteralContextModeling(input []byte, start_pos uint, length uint, mask uint, quality int, size_hint uint, num_literal_contexts *uint, literal_context_map *[]uint32) {\n\tif quality < minQualityForContextModeling || length < 64 {\n\t\treturn\n\t} else if shouldUseComplexStaticContextMap(input, start_pos, length, mask, quality, size_hint, num_literal_contexts, literal_context_map) {\n\t} else /* Context map was already set, nothing else to do. */\n\t{\n\t\tvar end_pos uint = start_pos + length\n\t\t/* Gather bi-gram data of the UTF8 byte prefixes. To make the analysis of\n\t\t   UTF8 data faster we only examine 64 byte long strides at every 4kB\n\t\t   intervals. */\n\n\t\tvar bigram_prefix_histo = [9]uint32{0}\n\t\tfor ; start_pos+64 <= end_pos; start_pos += 4096 {\n\t\t\tvar lut = [4]int{0, 0, 1, 2}\n\t\t\tvar stride_end_pos uint = start_pos + 64\n\t\t\tvar prev int = lut[input[start_pos&mask]>>6] * 3\n\t\t\tvar pos uint\n\t\t\tfor pos = start_pos + 1; pos < stride_end_pos; pos++ {\n\t\t\t\tvar literal byte = input[pos&mask]\n\t\t\t\tbigram_prefix_histo[prev+lut[literal>>6]]++\n\t\t\t\tprev = lut[literal>>6] * 3\n\t\t\t}\n\t\t}\n\n\t\tchooseContextMap(quality, bigram_prefix_histo[0:], num_literal_contexts, literal_context_map)\n\t}\n}\n\nfunc shouldCompress_encode(data []byte, mask uint, last_flush_pos uint64, bytes uint, num_literals uint, num_commands uint) bool {\n\t/* TODO: find more precise minimal block overhead. */\n\tif bytes <= 2 {\n\t\treturn false\n\t}\n\tif num_commands < (bytes>>8)+2 {\n\t\tif float64(num_literals) > 0.99*float64(bytes) {\n\t\t\tvar literal_histo = [256]uint32{0}\n\t\t\tconst kSampleRate uint32 = 13\n\t\t\tconst kMinEntropy float64 = 7.92\n\t\t\tvar bit_cost_threshold float64 = float64(bytes) * kMinEntropy / float64(kSampleRate)\n\t\t\tvar t uint = uint((uint32(bytes) + kSampleRate - 1) / kSampleRate)\n\t\t\tvar pos uint32 = uint32(last_flush_pos)\n\t\t\tvar i uint\n\t\t\tfor i = 0; i < t; i++ {\n\t\t\t\tliteral_histo[data[pos&uint32(mask)]]++\n\t\t\t\tpos += kSampleRate\n\t\t\t}\n\n\t\t\tif bitsEntropy(literal_histo[:], 256) > bit_cost_threshold {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\n/* Chooses the literal context mode for a metablock */\nfunc chooseContextMode(params *encoderParams, data []byte, pos uint, mask uint, length uint) int {\n\t/* We only do the computation for the option of something else than\n\t   CONTEXT_UTF8 for the highest qualities */\n\tif params.quality >= minQualityForHqBlockSplitting && !isMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio) {\n\t\treturn contextSigned\n\t}\n\n\treturn contextUTF8\n}\n\nfunc writeMetaBlockInternal(data []byte, mask uint, last_flush_pos uint64, bytes uint, is_last bool, literal_context_mode int, params *encoderParams, prev_byte byte, prev_byte2 byte, num_literals uint, commands []command, saved_dist_cache []int, dist_cache []int, storage_ix *uint, storage []byte) {\n\tvar wrapped_last_flush_pos uint32 = wrapPosition(last_flush_pos)\n\tvar last_bytes uint16\n\tvar last_bytes_bits byte\n\tvar literal_context_lut contextLUT = getContextLUT(literal_context_mode)\n\tvar block_params encoderParams = *params\n\n\tif bytes == 0 {\n\t\t/* Write the ISLAST and ISEMPTY bits. */\n\t\twriteBits(2, 3, storage_ix, storage)\n\n\t\t*storage_ix = (*storage_ix + 7) &^ 7\n\t\treturn\n\t}\n\n\tif !shouldCompress_encode(data, mask, last_flush_pos, bytes, num_literals, uint(len(commands))) {\n\t\t/* Restore the distance cache, as its last update by\n\t\t   CreateBackwardReferences is now unused. */\n\t\tcopy(dist_cache, saved_dist_cache[:4])\n\n\t\tstoreUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage)\n\t\treturn\n\t}\n\n\tassert(*storage_ix <= 14)\n\tlast_bytes = uint16(storage[1])<<8 | uint16(storage[0])\n\tlast_bytes_bits = byte(*storage_ix)\n\tif params.quality <= maxQualityForStaticEntropyCodes {\n\t\tstoreMetaBlockFast(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage)\n\t} else if params.quality < minQualityForBlockSplit {\n\t\tstoreMetaBlockTrivial(data, uint(wrapped_last_flush_pos), bytes, mask, is_last, params, commands, storage_ix, storage)\n\t} else {\n\t\tmb := getMetaBlockSplit()\n\t\tif params.quality < minQualityForHqBlockSplitting {\n\t\t\tvar num_literal_contexts uint = 1\n\t\t\tvar literal_context_map []uint32 = nil\n\t\t\tif !params.disable_literal_context_modeling {\n\t\t\t\tdecideOverLiteralContextModeling(data, uint(wrapped_last_flush_pos), bytes, mask, params.quality, params.size_hint, &num_literal_contexts, &literal_context_map)\n\t\t\t}\n\n\t\t\tbuildMetaBlockGreedy(data, uint(wrapped_last_flush_pos), mask, prev_byte, prev_byte2, literal_context_lut, num_literal_contexts, literal_context_map, commands, mb)\n\t\t} else {\n\t\t\tbuildMetaBlock(data, uint(wrapped_last_flush_pos), mask, &block_params, prev_byte, prev_byte2, commands, literal_context_mode, mb)\n\t\t}\n\n\t\tif params.quality >= minQualityForOptimizeHistograms {\n\t\t\t/* The number of distance symbols effectively used for distance\n\t\t\t   histograms. It might be less than distance alphabet size\n\t\t\t   for \"Large Window Brotli\" (32-bit). */\n\t\t\tvar num_effective_dist_codes uint32 = block_params.dist.alphabet_size\n\t\t\tif num_effective_dist_codes > numHistogramDistanceSymbols {\n\t\t\t\tnum_effective_dist_codes = numHistogramDistanceSymbols\n\t\t\t}\n\n\t\t\toptimizeHistograms(num_effective_dist_codes, mb)\n\t\t}\n\n\t\tstoreMetaBlock(data, uint(wrapped_last_flush_pos), bytes, mask, prev_byte, prev_byte2, is_last, &block_params, literal_context_mode, commands, mb, storage_ix, storage)\n\t\tfreeMetaBlockSplit(mb)\n\t}\n\n\tif bytes+4 < *storage_ix>>3 {\n\t\t/* Restore the distance cache and last byte. */\n\t\tcopy(dist_cache, saved_dist_cache[:4])\n\n\t\tstorage[0] = byte(last_bytes)\n\t\tstorage[1] = byte(last_bytes >> 8)\n\t\t*storage_ix = uint(last_bytes_bits)\n\t\tstoreUncompressedMetaBlock(is_last, data, uint(wrapped_last_flush_pos), mask, bytes, storage_ix, storage)\n\t}\n}\n\nfunc chooseDistanceParams(params *encoderParams) {\n\tvar distance_postfix_bits uint32 = 0\n\tvar num_direct_distance_codes uint32 = 0\n\n\tif params.quality >= minQualityForNonzeroDistanceParams {\n\t\tvar ndirect_msb uint32\n\t\tif params.mode == modeFont {\n\t\t\tdistance_postfix_bits = 1\n\t\t\tnum_direct_distance_codes = 12\n\t\t} else {\n\t\t\tdistance_postfix_bits = params.dist.distance_postfix_bits\n\t\t\tnum_direct_distance_codes = params.dist.num_direct_distance_codes\n\t\t}\n\n\t\tndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F\n\t\tif distance_postfix_bits > maxNpostfix || num_direct_distance_codes > maxNdirect || ndirect_msb<<distance_postfix_bits != num_direct_distance_codes {\n\t\t\tdistance_postfix_bits = 0\n\t\t\tnum_direct_distance_codes = 0\n\t\t}\n\t}\n\n\tinitDistanceParams(params, distance_postfix_bits, num_direct_distance_codes)\n}\n\nfunc ensureInitialized(s *Writer) bool {\n\tif s.is_initialized_ {\n\t\treturn true\n\t}\n\n\ts.last_bytes_bits_ = 0\n\ts.last_bytes_ = 0\n\ts.remaining_metadata_bytes_ = math.MaxUint32\n\n\tsanitizeParams(&s.params)\n\ts.params.lgblock = computeLgBlock(&s.params)\n\tchooseDistanceParams(&s.params)\n\n\tringBufferSetup(&s.params, &s.ringbuffer_)\n\n\t/* Initialize last byte with stream header. */\n\t{\n\t\tvar lgwin int = int(s.params.lgwin)\n\t\tif s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality {\n\t\t\tlgwin = brotli_max_int(lgwin, 18)\n\t\t}\n\n\t\tencodeWindowBits(lgwin, s.params.large_window, &s.last_bytes_, &s.last_bytes_bits_)\n\t}\n\n\tif s.params.quality == fastOnePassCompressionQuality {\n\t\ts.cmd_depths_ = [128]byte{\n\t\t\t0, 4, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8,\n\t\t\t0, 0, 0, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7,\n\t\t\t7, 7, 10, 10, 10, 10, 10, 10, 0, 4, 4, 5, 5, 5, 6, 6,\n\t\t\t7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n\t\t\t5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t\t6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,\n\t\t\t4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 10,\n\t\t\t12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,\n\t\t}\n\t\ts.cmd_bits_ = [128]uint16{\n\t\t\t0, 0, 8, 9, 3, 35, 7, 71,\n\t\t\t39, 103, 23, 47, 175, 111, 239, 31,\n\t\t\t0, 0, 0, 4, 12, 2, 10, 6,\n\t\t\t13, 29, 11, 43, 27, 59, 87, 55,\n\t\t\t15, 79, 319, 831, 191, 703, 447, 959,\n\t\t\t0, 14, 1, 25, 5, 21, 19, 51,\n\t\t\t119, 159, 95, 223, 479, 991, 63, 575,\n\t\t\t127, 639, 383, 895, 255, 767, 511, 1023,\n\t\t\t14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t\t\t27, 59, 7, 39, 23, 55, 30, 1, 17, 9, 25, 5, 0, 8, 4, 12,\n\t\t\t2, 10, 6, 21, 13, 29, 3, 19, 11, 15, 47, 31, 95, 63, 127, 255,\n\t\t\t767, 2815, 1791, 3839, 511, 2559, 1535, 3583, 1023, 3071, 2047, 4095,\n\t\t}\n\t\ts.cmd_code_ = [512]byte{\n\t\t\t0xff, 0x77, 0xd5, 0xbf, 0xe7, 0xde, 0xea, 0x9e, 0x51, 0x5d, 0xde, 0xc6,\n\t\t\t0x70, 0x57, 0xbc, 0x58, 0x58, 0x58, 0xd8, 0xd8, 0x58, 0xd5, 0xcb, 0x8c,\n\t\t\t0xea, 0xe0, 0xc3, 0x87, 0x1f, 0x83, 0xc1, 0x60, 0x1c, 0x67, 0xb2, 0xaa,\n\t\t\t0x06, 0x83, 0xc1, 0x60, 0x30, 0x18, 0xcc, 0xa1, 0xce, 0x88, 0x54, 0x94,\n\t\t\t0x46, 0xe1, 0xb0, 0xd0, 0x4e, 0xb2, 0xf7, 0x04, 0x00,\n\t\t}\n\t\ts.cmd_code_numbits_ = 448\n\t}\n\n\ts.is_initialized_ = true\n\treturn true\n}\n\nfunc encoderInitParams(params *encoderParams) {\n\tparams.mode = defaultMode\n\tparams.large_window = false\n\tparams.quality = defaultQuality\n\tparams.lgwin = defaultWindow\n\tparams.lgblock = 0\n\tparams.size_hint = 0\n\tparams.disable_literal_context_modeling = false\n\tinitEncoderDictionary(&params.dictionary)\n\tparams.dist.distance_postfix_bits = 0\n\tparams.dist.num_direct_distance_codes = 0\n\tparams.dist.alphabet_size = uint32(distanceAlphabetSize(0, 0, maxDistanceBits))\n\tparams.dist.max_distance = maxDistance\n}\n\nfunc encoderInitState(s *Writer) {\n\tencoderInitParams(&s.params)\n\ts.input_pos_ = 0\n\ts.commands = s.commands[:0]\n\ts.num_literals_ = 0\n\ts.last_insert_len_ = 0\n\ts.last_flush_pos_ = 0\n\ts.last_processed_pos_ = 0\n\ts.prev_byte_ = 0\n\ts.prev_byte2_ = 0\n\tif s.hasher_ != nil {\n\t\ts.hasher_.Common().is_prepared_ = false\n\t}\n\ts.cmd_code_numbits_ = 0\n\ts.stream_state_ = streamProcessing\n\ts.is_last_block_emitted_ = false\n\ts.is_initialized_ = false\n\n\tringBufferInit(&s.ringbuffer_)\n\n\t/* Initialize distance cache. */\n\ts.dist_cache_[0] = 4\n\n\ts.dist_cache_[1] = 11\n\ts.dist_cache_[2] = 15\n\ts.dist_cache_[3] = 16\n\n\t/* Save the state of the distance cache in case we need to restore it for\n\t   emitting an uncompressed block. */\n\tcopy(s.saved_dist_cache_[:], s.dist_cache_[:])\n}\n\n/*\n   Copies the given input data to the internal ring buffer of the compressor.\n   No processing of the data occurs at this time and this function can be\n   called multiple times before calling WriteBrotliData() to process the\n   accumulated input. At most input_block_size() bytes of input data can be\n   copied to the ring buffer, otherwise the next WriteBrotliData() will fail.\n*/\nfunc copyInputToRingBuffer(s *Writer, input_size uint, input_buffer []byte) {\n\tvar ringbuffer_ *ringBuffer = &s.ringbuffer_\n\tringBufferWrite(input_buffer, input_size, ringbuffer_)\n\ts.input_pos_ += uint64(input_size)\n\n\t/* TL;DR: If needed, initialize 7 more bytes in the ring buffer to make the\n\t   hashing not depend on uninitialized data. This makes compression\n\t   deterministic and it prevents uninitialized memory warnings in Valgrind.\n\t   Even without erasing, the output would be valid (but nondeterministic).\n\n\t   Background information: The compressor stores short (at most 8 bytes)\n\t   substrings of the input already read in a hash table, and detects\n\t   repetitions by looking up such substrings in the hash table. If it\n\t   can find a substring, it checks whether the substring is really there\n\t   in the ring buffer (or it's just a hash collision). Should the hash\n\t   table become corrupt, this check makes sure that the output is\n\t   still valid, albeit the compression ratio would be bad.\n\n\t   The compressor populates the hash table from the ring buffer as it's\n\t   reading new bytes from the input. However, at the last few indexes of\n\t   the ring buffer, there are not enough bytes to build full-length\n\t   substrings from. Since the hash table always contains full-length\n\t   substrings, we erase with dummy zeros here to make sure that those\n\t   substrings will contain zeros at the end instead of uninitialized\n\t   data.\n\n\t   Please note that erasing is not necessary (because the\n\t   memory region is already initialized since he ring buffer\n\t   has a `tail' that holds a copy of the beginning,) so we\n\t   skip erasing if we have already gone around at least once in\n\t   the ring buffer.\n\n\t   Only clear during the first round of ring-buffer writes. On\n\t   subsequent rounds data in the ring-buffer would be affected. */\n\tif ringbuffer_.pos_ <= ringbuffer_.mask_ {\n\t\t/* This is the first time when the ring buffer is being written.\n\t\t   We clear 7 bytes just after the bytes that have been copied from\n\t\t   the input buffer.\n\n\t\t   The ring-buffer has a \"tail\" that holds a copy of the beginning,\n\t\t   but only once the ring buffer has been fully written once, i.e.,\n\t\t   pos <= mask. For the first time, we need to write values\n\t\t   in this tail (where index may be larger than mask), so that\n\t\t   we have exactly defined behavior and don't read uninitialized\n\t\t   memory. Due to performance reasons, hashing reads data using a\n\t\t   LOAD64, which can go 7 bytes beyond the bytes written in the\n\t\t   ring-buffer. */\n\t\tfor i := 0; i < int(7); i++ {\n\t\t\tringbuffer_.buffer_[ringbuffer_.pos_:][i] = 0\n\t\t}\n\t}\n}\n\n/* Marks all input as processed.\n   Returns true if position wrapping occurs. */\nfunc updateLastProcessedPos(s *Writer) bool {\n\tvar wrapped_last_processed_pos uint32 = wrapPosition(s.last_processed_pos_)\n\tvar wrapped_input_pos uint32 = wrapPosition(s.input_pos_)\n\ts.last_processed_pos_ = s.input_pos_\n\treturn wrapped_input_pos < wrapped_last_processed_pos\n}\n\nfunc extendLastCommand(s *Writer, bytes *uint32, wrapped_last_processed_pos *uint32) {\n\tvar last_command *command = &s.commands[len(s.commands)-1]\n\tvar data []byte = s.ringbuffer_.buffer_\n\tvar mask uint32 = s.ringbuffer_.mask_\n\tvar max_backward_distance uint64 = ((uint64(1)) << s.params.lgwin) - windowGap\n\tvar last_copy_len uint64 = uint64(last_command.copy_len_) & 0x1FFFFFF\n\tvar last_processed_pos uint64 = s.last_processed_pos_ - last_copy_len\n\tvar max_distance uint64\n\tif last_processed_pos < max_backward_distance {\n\t\tmax_distance = last_processed_pos\n\t} else {\n\t\tmax_distance = max_backward_distance\n\t}\n\tvar cmd_dist uint64 = uint64(s.dist_cache_[0])\n\tvar distance_code uint32 = commandRestoreDistanceCode(last_command, &s.params.dist)\n\tif distance_code < numDistanceShortCodes || uint64(distance_code-(numDistanceShortCodes-1)) == cmd_dist {\n\t\tif cmd_dist <= max_distance {\n\t\t\tfor *bytes != 0 && data[*wrapped_last_processed_pos&mask] == data[(uint64(*wrapped_last_processed_pos)-cmd_dist)&uint64(mask)] {\n\t\t\t\tlast_command.copy_len_++\n\t\t\t\t(*bytes)--\n\t\t\t\t(*wrapped_last_processed_pos)++\n\t\t\t}\n\t\t}\n\n\t\t/* The copy length is at most the metablock size, and thus expressible. */\n\t\tgetLengthCode(uint(last_command.insert_len_), uint(int(last_command.copy_len_&0x1FFFFFF)+int(last_command.copy_len_>>25)), (last_command.dist_prefix_&0x3FF == 0), &last_command.cmd_prefix_)\n\t}\n}\n\n/*\n   Processes the accumulated input data and writes\n   the new output meta-block to s.dest, if one has been\n   created (otherwise the processed input data is buffered internally).\n   If |is_last| or |force_flush| is true, an output meta-block is\n   always created. However, until |is_last| is true encoder may retain up\n   to 7 bits of the last byte of output. To force encoder to dump the remaining\n   bits use WriteMetadata() to append an empty meta-data block.\n   Returns false if the size of the input data is larger than\n   input_block_size().\n*/\nfunc encodeData(s *Writer, is_last bool, force_flush bool) bool {\n\tvar delta uint64 = unprocessedInputSize(s)\n\tvar bytes uint32 = uint32(delta)\n\tvar wrapped_last_processed_pos uint32 = wrapPosition(s.last_processed_pos_)\n\tvar data []byte\n\tvar mask uint32\n\tvar literal_context_mode int\n\n\tdata = s.ringbuffer_.buffer_\n\tmask = s.ringbuffer_.mask_\n\n\t/* Adding more blocks after \"last\" block is forbidden. */\n\tif s.is_last_block_emitted_ {\n\t\treturn false\n\t}\n\tif is_last {\n\t\ts.is_last_block_emitted_ = true\n\t}\n\n\tif delta > uint64(inputBlockSize(s)) {\n\t\treturn false\n\t}\n\n\tif s.params.quality == fastTwoPassCompressionQuality {\n\t\tif s.command_buf_ == nil || cap(s.command_buf_) < int(kCompressFragmentTwoPassBlockSize) {\n\t\t\ts.command_buf_ = make([]uint32, kCompressFragmentTwoPassBlockSize)\n\t\t\ts.literal_buf_ = make([]byte, kCompressFragmentTwoPassBlockSize)\n\t\t} else {\n\t\t\ts.command_buf_ = s.command_buf_[:kCompressFragmentTwoPassBlockSize]\n\t\t\ts.literal_buf_ = s.literal_buf_[:kCompressFragmentTwoPassBlockSize]\n\t\t}\n\t}\n\n\tif s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality {\n\t\tvar storage []byte\n\t\tvar storage_ix uint = uint(s.last_bytes_bits_)\n\t\tvar table_size uint\n\t\tvar table []int\n\n\t\tif delta == 0 && !is_last {\n\t\t\t/* We have no new input data and we don't have to finish the stream, so\n\t\t\t   nothing to do. */\n\t\t\treturn true\n\t\t}\n\n\t\tstorage = s.getStorage(int(2*bytes + 503))\n\t\tstorage[0] = byte(s.last_bytes_)\n\t\tstorage[1] = byte(s.last_bytes_ >> 8)\n\t\ttable = getHashTable(s, s.params.quality, uint(bytes), &table_size)\n\t\tif s.params.quality == fastOnePassCompressionQuality {\n\t\t\tcompressFragmentFast(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage)\n\t\t} else {\n\t\t\tcompressFragmentTwoPass(data[wrapped_last_processed_pos&mask:], uint(bytes), is_last, s.command_buf_, s.literal_buf_, table, table_size, &storage_ix, storage)\n\t\t}\n\n\t\ts.last_bytes_ = uint16(storage[storage_ix>>3])\n\t\ts.last_bytes_bits_ = byte(storage_ix & 7)\n\t\tupdateLastProcessedPos(s)\n\t\ts.writeOutput(storage[:storage_ix>>3])\n\t\treturn true\n\t}\n\t{\n\t\t/* Theoretical max number of commands is 1 per 2 bytes. */\n\t\tnewsize := len(s.commands) + int(bytes)/2 + 1\n\t\tif newsize > cap(s.commands) {\n\t\t\t/* Reserve a bit more memory to allow merging with a next block\n\t\t\t   without reallocation: that would impact speed. */\n\t\t\tnewsize += int(bytes/4) + 16\n\n\t\t\tnew_commands := make([]command, len(s.commands), newsize)\n\t\t\tif s.commands != nil {\n\t\t\t\tcopy(new_commands, s.commands)\n\t\t\t}\n\n\t\t\ts.commands = new_commands\n\t\t}\n\t}\n\n\tinitOrStitchToPreviousBlock(&s.hasher_, data, uint(mask), &s.params, uint(wrapped_last_processed_pos), uint(bytes), is_last)\n\n\tliteral_context_mode = chooseContextMode(&s.params, data, uint(wrapPosition(s.last_flush_pos_)), uint(mask), uint(s.input_pos_-s.last_flush_pos_))\n\n\tif len(s.commands) != 0 && s.last_insert_len_ == 0 {\n\t\textendLastCommand(s, &bytes, &wrapped_last_processed_pos)\n\t}\n\n\tif s.params.quality == zopflificationQuality {\n\t\tassert(s.params.hasher.type_ == 10)\n\t\tcreateZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_.(*h10), s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)\n\t} else if s.params.quality == hqZopflificationQuality {\n\t\tassert(s.params.hasher.type_ == 10)\n\t\tcreateHqZopfliBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)\n\t} else {\n\t\tcreateBackwardReferences(uint(bytes), uint(wrapped_last_processed_pos), data, uint(mask), &s.params, s.hasher_, s.dist_cache_[:], &s.last_insert_len_, &s.commands, &s.num_literals_)\n\t}\n\t{\n\t\tvar max_length uint = maxMetablockSize(&s.params)\n\t\tvar max_literals uint = max_length / 8\n\t\tmax_commands := int(max_length / 8)\n\t\tvar processed_bytes uint = uint(s.input_pos_ - s.last_flush_pos_)\n\t\tvar next_input_fits_metablock bool = (processed_bytes+inputBlockSize(s) <= max_length)\n\t\tvar should_flush bool = (s.params.quality < minQualityForBlockSplit && s.num_literals_+uint(len(s.commands)) >= maxNumDelayedSymbols)\n\t\t/* If maximal possible additional block doesn't fit metablock, flush now. */\n\t\t/* TODO: Postpone decision until next block arrives? */\n\n\t\t/* If block splitting is not used, then flush as soon as there is some\n\t\t   amount of commands / literals produced. */\n\t\tif !is_last && !force_flush && !should_flush && next_input_fits_metablock && s.num_literals_ < max_literals && len(s.commands) < max_commands {\n\t\t\t/* Merge with next input block. Everything will happen later. */\n\t\t\tif updateLastProcessedPos(s) {\n\t\t\t\thasherReset(s.hasher_)\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t}\n\n\t/* Create the last insert-only command. */\n\tif s.last_insert_len_ > 0 {\n\t\ts.commands = append(s.commands, makeInsertCommand(s.last_insert_len_))\n\t\ts.num_literals_ += s.last_insert_len_\n\t\ts.last_insert_len_ = 0\n\t}\n\n\tif !is_last && s.input_pos_ == s.last_flush_pos_ {\n\t\t/* We have no new input data and we don't have to finish the stream, so\n\t\t   nothing to do. */\n\t\treturn true\n\t}\n\n\tassert(s.input_pos_ >= s.last_flush_pos_)\n\tassert(s.input_pos_ > s.last_flush_pos_ || is_last)\n\tassert(s.input_pos_-s.last_flush_pos_ <= 1<<24)\n\t{\n\t\tvar metablock_size uint32 = uint32(s.input_pos_ - s.last_flush_pos_)\n\t\tvar storage []byte = s.getStorage(int(2*metablock_size + 503))\n\t\tvar storage_ix uint = uint(s.last_bytes_bits_)\n\t\tstorage[0] = byte(s.last_bytes_)\n\t\tstorage[1] = byte(s.last_bytes_ >> 8)\n\t\twriteMetaBlockInternal(data, uint(mask), s.last_flush_pos_, uint(metablock_size), is_last, literal_context_mode, &s.params, s.prev_byte_, s.prev_byte2_, s.num_literals_, s.commands, s.saved_dist_cache_[:], s.dist_cache_[:], &storage_ix, storage)\n\t\ts.last_bytes_ = uint16(storage[storage_ix>>3])\n\t\ts.last_bytes_bits_ = byte(storage_ix & 7)\n\t\ts.last_flush_pos_ = s.input_pos_\n\t\tif updateLastProcessedPos(s) {\n\t\t\thasherReset(s.hasher_)\n\t\t}\n\n\t\tif s.last_flush_pos_ > 0 {\n\t\t\ts.prev_byte_ = data[(uint32(s.last_flush_pos_)-1)&mask]\n\t\t}\n\n\t\tif s.last_flush_pos_ > 1 {\n\t\t\ts.prev_byte2_ = data[uint32(s.last_flush_pos_-2)&mask]\n\t\t}\n\n\t\ts.commands = s.commands[:0]\n\t\ts.num_literals_ = 0\n\n\t\t/* Save the state of the distance cache in case we need to restore it for\n\t\t   emitting an uncompressed block. */\n\t\tcopy(s.saved_dist_cache_[:], s.dist_cache_[:])\n\n\t\ts.writeOutput(storage[:storage_ix>>3])\n\t\treturn true\n\t}\n}\n\n/* Dumps remaining output bits and metadata header to |header|.\n   Returns number of produced bytes.\n   REQUIRED: |header| should be 8-byte aligned and at least 16 bytes long.\n   REQUIRED: |block_size| <= (1 << 24). */\nfunc writeMetadataHeader(s *Writer, block_size uint, header []byte) uint {\n\tstorage_ix := uint(s.last_bytes_bits_)\n\theader[0] = byte(s.last_bytes_)\n\theader[1] = byte(s.last_bytes_ >> 8)\n\ts.last_bytes_ = 0\n\ts.last_bytes_bits_ = 0\n\n\twriteBits(1, 0, &storage_ix, header)\n\twriteBits(2, 3, &storage_ix, header)\n\twriteBits(1, 0, &storage_ix, header)\n\tif block_size == 0 {\n\t\twriteBits(2, 0, &storage_ix, header)\n\t} else {\n\t\tvar nbits uint32\n\t\tif block_size == 1 {\n\t\t\tnbits = 0\n\t\t} else {\n\t\t\tnbits = log2FloorNonZero(uint(uint32(block_size)-1)) + 1\n\t\t}\n\t\tvar nbytes uint32 = (nbits + 7) / 8\n\t\twriteBits(2, uint64(nbytes), &storage_ix, header)\n\t\twriteBits(uint(8*nbytes), uint64(block_size)-1, &storage_ix, header)\n\t}\n\n\treturn (storage_ix + 7) >> 3\n}\n\nfunc injectBytePaddingBlock(s *Writer) {\n\tvar seal uint32 = uint32(s.last_bytes_)\n\tvar seal_bits uint = uint(s.last_bytes_bits_)\n\ts.last_bytes_ = 0\n\ts.last_bytes_bits_ = 0\n\n\t/* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */\n\tseal |= 0x6 << seal_bits\n\n\tseal_bits += 6\n\n\tdestination := s.tiny_buf_.u8[:]\n\n\tdestination[0] = byte(seal)\n\tif seal_bits > 8 {\n\t\tdestination[1] = byte(seal >> 8)\n\t}\n\tif seal_bits > 16 {\n\t\tdestination[2] = byte(seal >> 16)\n\t}\n\ts.writeOutput(destination[:(seal_bits+7)>>3])\n}\n\nfunc checkFlushComplete(s *Writer) {\n\tif s.stream_state_ == streamFlushRequested && s.err == nil {\n\t\ts.stream_state_ = streamProcessing\n\t}\n}\n\nfunc encoderCompressStreamFast(s *Writer, op int, available_in *uint, next_in *[]byte) bool {\n\tvar block_size_limit uint = uint(1) << s.params.lgwin\n\tvar buf_size uint = brotli_min_size_t(kCompressFragmentTwoPassBlockSize, brotli_min_size_t(*available_in, block_size_limit))\n\tvar command_buf []uint32 = nil\n\tvar literal_buf []byte = nil\n\tif s.params.quality != fastOnePassCompressionQuality && s.params.quality != fastTwoPassCompressionQuality {\n\t\treturn false\n\t}\n\n\tif s.params.quality == fastTwoPassCompressionQuality {\n\t\tif s.command_buf_ == nil || cap(s.command_buf_) < int(buf_size) {\n\t\t\ts.command_buf_ = make([]uint32, buf_size)\n\t\t\ts.literal_buf_ = make([]byte, buf_size)\n\t\t} else {\n\t\t\ts.command_buf_ = s.command_buf_[:buf_size]\n\t\t\ts.literal_buf_ = s.literal_buf_[:buf_size]\n\t\t}\n\n\t\tcommand_buf = s.command_buf_\n\t\tliteral_buf = s.literal_buf_\n\t}\n\n\tfor {\n\t\tif s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {\n\t\t\tinjectBytePaddingBlock(s)\n\t\t\tcontinue\n\t\t}\n\n\t\t/* Compress block only when stream is not\n\t\t   finished, there is no pending flush request, and there is either\n\t\t   additional input or pending operation. */\n\t\tif s.stream_state_ == streamProcessing && (*available_in != 0 || op != int(operationProcess)) {\n\t\t\tvar block_size uint = brotli_min_size_t(block_size_limit, *available_in)\n\t\t\tvar is_last bool = (*available_in == block_size) && (op == int(operationFinish))\n\t\t\tvar force_flush bool = (*available_in == block_size) && (op == int(operationFlush))\n\t\t\tvar max_out_size uint = 2*block_size + 503\n\t\t\tvar storage []byte = nil\n\t\t\tvar storage_ix uint = uint(s.last_bytes_bits_)\n\t\t\tvar table_size uint\n\t\t\tvar table []int\n\n\t\t\tif force_flush && block_size == 0 {\n\t\t\t\ts.stream_state_ = streamFlushRequested\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tstorage = s.getStorage(int(max_out_size))\n\n\t\t\tstorage[0] = byte(s.last_bytes_)\n\t\t\tstorage[1] = byte(s.last_bytes_ >> 8)\n\t\t\ttable = getHashTable(s, s.params.quality, block_size, &table_size)\n\n\t\t\tif s.params.quality == fastOnePassCompressionQuality {\n\t\t\t\tcompressFragmentFast(*next_in, block_size, is_last, table, table_size, s.cmd_depths_[:], s.cmd_bits_[:], &s.cmd_code_numbits_, s.cmd_code_[:], &storage_ix, storage)\n\t\t\t} else {\n\t\t\t\tcompressFragmentTwoPass(*next_in, block_size, is_last, command_buf, literal_buf, table, table_size, &storage_ix, storage)\n\t\t\t}\n\n\t\t\t*next_in = (*next_in)[block_size:]\n\t\t\t*available_in -= block_size\n\t\t\tvar out_bytes uint = storage_ix >> 3\n\t\t\ts.writeOutput(storage[:out_bytes])\n\n\t\t\ts.last_bytes_ = uint16(storage[storage_ix>>3])\n\t\t\ts.last_bytes_bits_ = byte(storage_ix & 7)\n\n\t\t\tif force_flush {\n\t\t\t\ts.stream_state_ = streamFlushRequested\n\t\t\t}\n\t\t\tif is_last {\n\t\t\t\ts.stream_state_ = streamFinished\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tbreak\n\t}\n\n\tcheckFlushComplete(s)\n\treturn true\n}\n\nfunc processMetadata(s *Writer, available_in *uint, next_in *[]byte) bool {\n\tif *available_in > 1<<24 {\n\t\treturn false\n\t}\n\n\t/* Switch to metadata block workflow, if required. */\n\tif s.stream_state_ == streamProcessing {\n\t\ts.remaining_metadata_bytes_ = uint32(*available_in)\n\t\ts.stream_state_ = streamMetadataHead\n\t}\n\n\tif s.stream_state_ != streamMetadataHead && s.stream_state_ != streamMetadataBody {\n\t\treturn false\n\t}\n\n\tfor {\n\t\tif s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {\n\t\t\tinjectBytePaddingBlock(s)\n\t\t\tcontinue\n\t\t}\n\n\t\tif s.input_pos_ != s.last_flush_pos_ {\n\t\t\tvar result bool = encodeData(s, false, true)\n\t\t\tif !result {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif s.stream_state_ == streamMetadataHead {\n\t\t\tn := writeMetadataHeader(s, uint(s.remaining_metadata_bytes_), s.tiny_buf_.u8[:])\n\t\t\ts.writeOutput(s.tiny_buf_.u8[:n])\n\t\t\ts.stream_state_ = streamMetadataBody\n\t\t\tcontinue\n\t\t} else {\n\t\t\t/* Exit workflow only when there is no more input and no more output.\n\t\t\t   Otherwise client may continue producing empty metadata blocks. */\n\t\t\tif s.remaining_metadata_bytes_ == 0 {\n\t\t\t\ts.remaining_metadata_bytes_ = math.MaxUint32\n\t\t\t\ts.stream_state_ = streamProcessing\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t/* This guarantees progress in \"TakeOutput\" workflow. */\n\t\t\tvar c uint32 = brotli_min_uint32_t(s.remaining_metadata_bytes_, 16)\n\t\t\tcopy(s.tiny_buf_.u8[:], (*next_in)[:c])\n\t\t\t*next_in = (*next_in)[c:]\n\t\t\t*available_in -= uint(c)\n\t\t\ts.remaining_metadata_bytes_ -= c\n\t\t\ts.writeOutput(s.tiny_buf_.u8[:c])\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc updateSizeHint(s *Writer, available_in uint) {\n\tif s.params.size_hint == 0 {\n\t\tvar delta uint64 = unprocessedInputSize(s)\n\t\tvar tail uint64 = uint64(available_in)\n\t\tvar limit uint32 = 1 << 30\n\t\tvar total uint32\n\t\tif (delta >= uint64(limit)) || (tail >= uint64(limit)) || ((delta + tail) >= uint64(limit)) {\n\t\t\ttotal = limit\n\t\t} else {\n\t\t\ttotal = uint32(delta + tail)\n\t\t}\n\n\t\ts.params.size_hint = uint(total)\n\t}\n}\n\nfunc encoderCompressStream(s *Writer, op int, available_in *uint, next_in *[]byte) bool {\n\tif !ensureInitialized(s) {\n\t\treturn false\n\t}\n\n\t/* Unfinished metadata block; check requirements. */\n\tif s.remaining_metadata_bytes_ != math.MaxUint32 {\n\t\tif uint32(*available_in) != s.remaining_metadata_bytes_ {\n\t\t\treturn false\n\t\t}\n\t\tif op != int(operationEmitMetadata) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tif op == int(operationEmitMetadata) {\n\t\tupdateSizeHint(s, 0) /* First data metablock might be emitted here. */\n\t\treturn processMetadata(s, available_in, next_in)\n\t}\n\n\tif s.stream_state_ == streamMetadataHead || s.stream_state_ == streamMetadataBody {\n\t\treturn false\n\t}\n\n\tif s.stream_state_ != streamProcessing && *available_in != 0 {\n\t\treturn false\n\t}\n\n\tif s.params.quality == fastOnePassCompressionQuality || s.params.quality == fastTwoPassCompressionQuality {\n\t\treturn encoderCompressStreamFast(s, op, available_in, next_in)\n\t}\n\n\tfor {\n\t\tvar remaining_block_size uint = remainingInputBlockSize(s)\n\n\t\tif remaining_block_size != 0 && *available_in != 0 {\n\t\t\tvar copy_input_size uint = brotli_min_size_t(remaining_block_size, *available_in)\n\t\t\tcopyInputToRingBuffer(s, copy_input_size, *next_in)\n\t\t\t*next_in = (*next_in)[copy_input_size:]\n\t\t\t*available_in -= copy_input_size\n\t\t\tcontinue\n\t\t}\n\n\t\tif s.stream_state_ == streamFlushRequested && s.last_bytes_bits_ != 0 {\n\t\t\tinjectBytePaddingBlock(s)\n\t\t\tcontinue\n\t\t}\n\n\t\t/* Compress data only when stream is not\n\t\t   finished and there is no pending flush request. */\n\t\tif s.stream_state_ == streamProcessing {\n\t\t\tif remaining_block_size == 0 || op != int(operationProcess) {\n\t\t\t\tvar is_last bool = ((*available_in == 0) && op == int(operationFinish))\n\t\t\t\tvar force_flush bool = ((*available_in == 0) && op == int(operationFlush))\n\t\t\t\tvar result bool\n\t\t\t\tupdateSizeHint(s, *available_in)\n\t\t\t\tresult = encodeData(s, is_last, force_flush)\n\t\t\t\tif !result {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tif force_flush {\n\t\t\t\t\ts.stream_state_ = streamFlushRequested\n\t\t\t\t}\n\t\t\t\tif is_last {\n\t\t\t\t\ts.stream_state_ = streamFinished\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tbreak\n\t}\n\n\tcheckFlushComplete(s)\n\treturn true\n}\n\nfunc (w *Writer) writeOutput(data []byte) {\n\tif w.err != nil {\n\t\treturn\n\t}\n\n\t_, w.err = w.dst.Write(data)\n\tif w.err == nil {\n\t\tcheckFlushComplete(w)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/encoder.go",
    "content": "package brotli\n\nimport \"github.com/andybalholm/brotli/matchfinder\"\n\n// An Encoder implements the matchfinder.Encoder interface, writing in Brotli format.\ntype Encoder struct {\n\twroteHeader bool\n\tbw          bitWriter\n\tdistCache   []distanceCode\n}\n\nfunc (e *Encoder) Reset() {\n\te.wroteHeader = false\n\te.bw = bitWriter{}\n}\n\nfunc (e *Encoder) Encode(dst []byte, src []byte, matches []matchfinder.Match, lastBlock bool) []byte {\n\te.bw.dst = dst\n\tif !e.wroteHeader {\n\t\te.bw.writeBits(4, 15)\n\t\te.wroteHeader = true\n\t}\n\n\tif len(src) == 0 {\n\t\tif lastBlock {\n\t\t\te.bw.writeBits(2, 3) // islast + isempty\n\t\t\te.bw.jumpToByteBoundary()\n\t\t\treturn e.bw.dst\n\t\t}\n\t\treturn dst\n\t}\n\n\tvar literalHisto [256]uint32\n\tvar commandHisto [704]uint32\n\tvar distanceHisto [64]uint32\n\tliteralCount := 0\n\tcommandCount := 0\n\tdistanceCount := 0\n\n\tif len(e.distCache) < len(matches) {\n\t\te.distCache = make([]distanceCode, len(matches))\n\t}\n\n\t// first pass: build the histograms\n\tpos := 0\n\n\t// d is the ring buffer of the last 4 distances.\n\td := [4]int{-10, -10, -10, -10}\n\tfor i, m := range matches {\n\t\tif m.Unmatched > 0 {\n\t\t\tfor _, c := range src[pos : pos+m.Unmatched] {\n\t\t\t\tliteralHisto[c]++\n\t\t\t}\n\t\t\tliteralCount += m.Unmatched\n\t\t}\n\n\t\tinsertCode := getInsertLengthCode(uint(m.Unmatched))\n\t\tcopyCode := getCopyLengthCode(uint(m.Length))\n\t\tif m.Length == 0 {\n\t\t\t// If the stream ends with unmatched bytes, we need a dummy copy length.\n\t\t\tcopyCode = 2\n\t\t}\n\t\tcommand := combineLengthCodes(insertCode, copyCode, false)\n\t\tcommandHisto[command]++\n\t\tcommandCount++\n\n\t\tif command >= 128 && m.Length != 0 {\n\t\t\tvar distCode distanceCode\n\t\t\tswitch m.Distance {\n\t\t\tcase d[3]:\n\t\t\t\tdistCode.code = 0\n\t\t\tcase d[2]:\n\t\t\t\tdistCode.code = 1\n\t\t\tcase d[1]:\n\t\t\t\tdistCode.code = 2\n\t\t\tcase d[0]:\n\t\t\t\tdistCode.code = 3\n\t\t\tcase d[3] - 1:\n\t\t\t\tdistCode.code = 4\n\t\t\tcase d[3] + 1:\n\t\t\t\tdistCode.code = 5\n\t\t\tcase d[3] - 2:\n\t\t\t\tdistCode.code = 6\n\t\t\tcase d[3] + 2:\n\t\t\t\tdistCode.code = 7\n\t\t\tcase d[3] - 3:\n\t\t\t\tdistCode.code = 8\n\t\t\tcase d[3] + 3:\n\t\t\t\tdistCode.code = 9\n\n\t\t\t\t// In my testing, codes 10–15 actually reduced the compression ratio.\n\n\t\t\tdefault:\n\t\t\t\tdistCode = getDistanceCode(m.Distance)\n\t\t\t}\n\t\t\te.distCache[i] = distCode\n\t\t\tdistanceHisto[distCode.code]++\n\t\t\tdistanceCount++\n\t\t\tif distCode.code != 0 {\n\t\t\t\td[0], d[1], d[2], d[3] = d[1], d[2], d[3], m.Distance\n\t\t\t}\n\t\t}\n\n\t\tpos += m.Unmatched + m.Length\n\t}\n\n\tstoreMetaBlockHeaderBW(uint(len(src)), false, &e.bw)\n\te.bw.writeBits(13, 0)\n\n\tvar literalDepths [256]byte\n\tvar literalBits [256]uint16\n\tbuildAndStoreHuffmanTreeFastBW(literalHisto[:], uint(literalCount), 8, literalDepths[:], literalBits[:], &e.bw)\n\n\tvar commandDepths [704]byte\n\tvar commandBits [704]uint16\n\tbuildAndStoreHuffmanTreeFastBW(commandHisto[:], uint(commandCount), 10, commandDepths[:], commandBits[:], &e.bw)\n\n\tvar distanceDepths [64]byte\n\tvar distanceBits [64]uint16\n\tbuildAndStoreHuffmanTreeFastBW(distanceHisto[:], uint(distanceCount), 6, distanceDepths[:], distanceBits[:], &e.bw)\n\n\tpos = 0\n\tfor i, m := range matches {\n\t\tinsertCode := getInsertLengthCode(uint(m.Unmatched))\n\t\tcopyCode := getCopyLengthCode(uint(m.Length))\n\t\tif m.Length == 0 {\n\t\t\t// If the stream ends with unmatched bytes, we need a dummy copy length.\n\t\t\tcopyCode = 2\n\t\t}\n\t\tcommand := combineLengthCodes(insertCode, copyCode, false)\n\t\te.bw.writeBits(uint(commandDepths[command]), uint64(commandBits[command]))\n\t\tif kInsExtra[insertCode] > 0 {\n\t\t\te.bw.writeBits(uint(kInsExtra[insertCode]), uint64(m.Unmatched)-uint64(kInsBase[insertCode]))\n\t\t}\n\t\tif kCopyExtra[copyCode] > 0 {\n\t\t\te.bw.writeBits(uint(kCopyExtra[copyCode]), uint64(m.Length)-uint64(kCopyBase[copyCode]))\n\t\t}\n\n\t\tif m.Unmatched > 0 {\n\t\t\tfor _, c := range src[pos : pos+m.Unmatched] {\n\t\t\t\te.bw.writeBits(uint(literalDepths[c]), uint64(literalBits[c]))\n\t\t\t}\n\t\t}\n\n\t\tif command >= 128 && m.Length != 0 {\n\t\t\tdistCode := e.distCache[i]\n\t\t\te.bw.writeBits(uint(distanceDepths[distCode.code]), uint64(distanceBits[distCode.code]))\n\t\t\tif distCode.nExtra > 0 {\n\t\t\t\te.bw.writeBits(distCode.nExtra, distCode.extraBits)\n\t\t\t}\n\t\t}\n\n\t\tpos += m.Unmatched + m.Length\n\t}\n\n\tif lastBlock {\n\t\te.bw.writeBits(2, 3) // islast + isempty\n\t\te.bw.jumpToByteBoundary()\n\t}\n\treturn e.bw.dst\n}\n\ntype distanceCode struct {\n\tcode      int\n\tnExtra    uint\n\textraBits uint64\n}\n\nfunc getDistanceCode(distance int) distanceCode {\n\td := distance + 3\n\tnbits := log2FloorNonZero(uint(d)) - 1\n\tprefix := (d >> nbits) & 1\n\toffset := (2 + prefix) << nbits\n\tdistcode := int(2*(nbits-1)) + prefix + 16\n\textra := d - offset\n\treturn distanceCode{distcode, uint(nbits), uint64(extra)}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/encoder_dict.go",
    "content": "package brotli\n\n/* Dictionary data (words and transforms) for 1 possible context */\ntype encoderDictionary struct {\n\twords                 *dictionary\n\tcutoffTransformsCount uint32\n\tcutoffTransforms      uint64\n\thash_table            []uint16\n\tbuckets               []uint16\n\tdict_words            []dictWord\n}\n\nfunc initEncoderDictionary(dict *encoderDictionary) {\n\tdict.words = getDictionary()\n\n\tdict.hash_table = kStaticDictionaryHash[:]\n\tdict.buckets = kStaticDictionaryBuckets[:]\n\tdict.dict_words = kStaticDictionaryWords[:]\n\n\tdict.cutoffTransformsCount = kCutoffTransformsCount\n\tdict.cutoffTransforms = kCutoffTransforms\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/entropy_encode.go",
    "content": "package brotli\n\nimport \"math\"\n\n/* Copyright 2010 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Entropy encoding (Huffman) utilities. */\n\n/* A node of a Huffman tree. */\ntype huffmanTree struct {\n\ttotal_count_          uint32\n\tindex_left_           int16\n\tindex_right_or_value_ int16\n}\n\nfunc initHuffmanTree(self *huffmanTree, count uint32, left int16, right int16) {\n\tself.total_count_ = count\n\tself.index_left_ = left\n\tself.index_right_or_value_ = right\n}\n\n/* Input size optimized Shell sort. */\ntype huffmanTreeComparator func(huffmanTree, huffmanTree) bool\n\nvar sortHuffmanTreeItems_gaps = []uint{132, 57, 23, 10, 4, 1}\n\nfunc sortHuffmanTreeItems(items []huffmanTree, n uint, comparator huffmanTreeComparator) {\n\tif n < 13 {\n\t\t/* Insertion sort. */\n\t\tvar i uint\n\t\tfor i = 1; i < n; i++ {\n\t\t\tvar tmp huffmanTree = items[i]\n\t\t\tvar k uint = i\n\t\t\tvar j uint = i - 1\n\t\t\tfor comparator(tmp, items[j]) {\n\t\t\t\titems[k] = items[j]\n\t\t\t\tk = j\n\t\t\t\tif j == 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tj--\n\t\t\t}\n\n\t\t\titems[k] = tmp\n\t\t}\n\n\t\treturn\n\t} else {\n\t\tvar g int\n\t\tif n < 57 {\n\t\t\tg = 2\n\t\t} else {\n\t\t\tg = 0\n\t\t}\n\t\tfor ; g < 6; g++ {\n\t\t\tvar gap uint = sortHuffmanTreeItems_gaps[g]\n\t\t\tvar i uint\n\t\t\tfor i = gap; i < n; i++ {\n\t\t\t\tvar j uint = i\n\t\t\t\tvar tmp huffmanTree = items[i]\n\t\t\t\tfor ; j >= gap && comparator(tmp, items[j-gap]); j -= gap {\n\t\t\t\t\titems[j] = items[j-gap]\n\t\t\t\t}\n\n\t\t\t\titems[j] = tmp\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* Returns 1 if assignment of depths succeeded, otherwise 0. */\nfunc setDepth(p0 int, pool []huffmanTree, depth []byte, max_depth int) bool {\n\tvar stack [16]int\n\tvar level int = 0\n\tvar p int = p0\n\tassert(max_depth <= 15)\n\tstack[0] = -1\n\tfor {\n\t\tif pool[p].index_left_ >= 0 {\n\t\t\tlevel++\n\t\t\tif level > max_depth {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tstack[level] = int(pool[p].index_right_or_value_)\n\t\t\tp = int(pool[p].index_left_)\n\t\t\tcontinue\n\t\t} else {\n\t\t\tdepth[pool[p].index_right_or_value_] = byte(level)\n\t\t}\n\n\t\tfor level >= 0 && stack[level] == -1 {\n\t\t\tlevel--\n\t\t}\n\t\tif level < 0 {\n\t\t\treturn true\n\t\t}\n\t\tp = stack[level]\n\t\tstack[level] = -1\n\t}\n}\n\n/* Sort the root nodes, least popular first. */\nfunc sortHuffmanTree(v0 huffmanTree, v1 huffmanTree) bool {\n\tif v0.total_count_ != v1.total_count_ {\n\t\treturn v0.total_count_ < v1.total_count_\n\t}\n\n\treturn v0.index_right_or_value_ > v1.index_right_or_value_\n}\n\n/* This function will create a Huffman tree.\n\n   The catch here is that the tree cannot be arbitrarily deep.\n   Brotli specifies a maximum depth of 15 bits for \"code trees\"\n   and 7 bits for \"code length code trees.\"\n\n   count_limit is the value that is to be faked as the minimum value\n   and this minimum value is raised until the tree matches the\n   maximum length requirement.\n\n   This algorithm is not of excellent performance for very long data blocks,\n   especially when population counts are longer than 2**tree_limit, but\n   we are not planning to use this with extremely long blocks.\n\n   See http://en.wikipedia.org/wiki/Huffman_coding */\nfunc createHuffmanTree(data []uint32, length uint, tree_limit int, tree []huffmanTree, depth []byte) {\n\tvar count_limit uint32\n\tvar sentinel huffmanTree\n\tinitHuffmanTree(&sentinel, math.MaxUint32, -1, -1)\n\n\t/* For block sizes below 64 kB, we never need to do a second iteration\n\t   of this loop. Probably all of our block sizes will be smaller than\n\t   that, so this loop is mostly of academic interest. If we actually\n\t   would need this, we would be better off with the Katajainen algorithm. */\n\tfor count_limit = 1; ; count_limit *= 2 {\n\t\tvar n uint = 0\n\t\tvar i uint\n\t\tvar j uint\n\t\tvar k uint\n\t\tfor i = length; i != 0; {\n\t\t\ti--\n\t\t\tif data[i] != 0 {\n\t\t\t\tvar count uint32 = brotli_max_uint32_t(data[i], count_limit)\n\t\t\t\tinitHuffmanTree(&tree[n], count, -1, int16(i))\n\t\t\t\tn++\n\t\t\t}\n\t\t}\n\n\t\tif n == 1 {\n\t\t\tdepth[tree[0].index_right_or_value_] = 1 /* Only one element. */\n\t\t\tbreak\n\t\t}\n\n\t\tsortHuffmanTreeItems(tree, n, huffmanTreeComparator(sortHuffmanTree))\n\n\t\t/* The nodes are:\n\t\t   [0, n): the sorted leaf nodes that we start with.\n\t\t   [n]: we add a sentinel here.\n\t\t   [n + 1, 2n): new parent nodes are added here, starting from\n\t\t                (n+1). These are naturally in ascending order.\n\t\t   [2n]: we add a sentinel at the end as well.\n\t\t   There will be (2n+1) elements at the end. */\n\t\ttree[n] = sentinel\n\n\t\ttree[n+1] = sentinel\n\n\t\ti = 0     /* Points to the next leaf node. */\n\t\tj = n + 1 /* Points to the next non-leaf node. */\n\t\tfor k = n - 1; k != 0; k-- {\n\t\t\tvar left uint\n\t\t\tvar right uint\n\t\t\tif tree[i].total_count_ <= tree[j].total_count_ {\n\t\t\t\tleft = i\n\t\t\t\ti++\n\t\t\t} else {\n\t\t\t\tleft = j\n\t\t\t\tj++\n\t\t\t}\n\n\t\t\tif tree[i].total_count_ <= tree[j].total_count_ {\n\t\t\t\tright = i\n\t\t\t\ti++\n\t\t\t} else {\n\t\t\t\tright = j\n\t\t\t\tj++\n\t\t\t}\n\t\t\t{\n\t\t\t\t/* The sentinel node becomes the parent node. */\n\t\t\t\tvar j_end uint = 2*n - k\n\t\t\t\ttree[j_end].total_count_ = tree[left].total_count_ + tree[right].total_count_\n\t\t\t\ttree[j_end].index_left_ = int16(left)\n\t\t\t\ttree[j_end].index_right_or_value_ = int16(right)\n\n\t\t\t\t/* Add back the last sentinel node. */\n\t\t\t\ttree[j_end+1] = sentinel\n\t\t\t}\n\t\t}\n\n\t\tif setDepth(int(2*n-1), tree[0:], depth, tree_limit) {\n\t\t\t/* We need to pack the Huffman tree in tree_limit bits. If this was not\n\t\t\t   successful, add fake entities to the lowest values and retry. */\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc reverse(v []byte, start uint, end uint) {\n\tend--\n\tfor start < end {\n\t\tvar tmp byte = v[start]\n\t\tv[start] = v[end]\n\t\tv[end] = tmp\n\t\tstart++\n\t\tend--\n\t}\n}\n\nfunc writeHuffmanTreeRepetitions(previous_value byte, value byte, repetitions uint, tree_size *uint, tree []byte, extra_bits_data []byte) {\n\tassert(repetitions > 0)\n\tif previous_value != value {\n\t\ttree[*tree_size] = value\n\t\textra_bits_data[*tree_size] = 0\n\t\t(*tree_size)++\n\t\trepetitions--\n\t}\n\n\tif repetitions == 7 {\n\t\ttree[*tree_size] = value\n\t\textra_bits_data[*tree_size] = 0\n\t\t(*tree_size)++\n\t\trepetitions--\n\t}\n\n\tif repetitions < 3 {\n\t\tvar i uint\n\t\tfor i = 0; i < repetitions; i++ {\n\t\t\ttree[*tree_size] = value\n\t\t\textra_bits_data[*tree_size] = 0\n\t\t\t(*tree_size)++\n\t\t}\n\t} else {\n\t\tvar start uint = *tree_size\n\t\trepetitions -= 3\n\t\tfor {\n\t\t\ttree[*tree_size] = repeatPreviousCodeLength\n\t\t\textra_bits_data[*tree_size] = byte(repetitions & 0x3)\n\t\t\t(*tree_size)++\n\t\t\trepetitions >>= 2\n\t\t\tif repetitions == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\trepetitions--\n\t\t}\n\n\t\treverse(tree, start, *tree_size)\n\t\treverse(extra_bits_data, start, *tree_size)\n\t}\n}\n\nfunc writeHuffmanTreeRepetitionsZeros(repetitions uint, tree_size *uint, tree []byte, extra_bits_data []byte) {\n\tif repetitions == 11 {\n\t\ttree[*tree_size] = 0\n\t\textra_bits_data[*tree_size] = 0\n\t\t(*tree_size)++\n\t\trepetitions--\n\t}\n\n\tif repetitions < 3 {\n\t\tvar i uint\n\t\tfor i = 0; i < repetitions; i++ {\n\t\t\ttree[*tree_size] = 0\n\t\t\textra_bits_data[*tree_size] = 0\n\t\t\t(*tree_size)++\n\t\t}\n\t} else {\n\t\tvar start uint = *tree_size\n\t\trepetitions -= 3\n\t\tfor {\n\t\t\ttree[*tree_size] = repeatZeroCodeLength\n\t\t\textra_bits_data[*tree_size] = byte(repetitions & 0x7)\n\t\t\t(*tree_size)++\n\t\t\trepetitions >>= 3\n\t\t\tif repetitions == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\trepetitions--\n\t\t}\n\n\t\treverse(tree, start, *tree_size)\n\t\treverse(extra_bits_data, start, *tree_size)\n\t}\n}\n\n/* Change the population counts in a way that the consequent\n   Huffman tree compression, especially its RLE-part will be more\n   likely to compress this data more efficiently.\n\n   length contains the size of the histogram.\n   counts contains the population counts.\n   good_for_rle is a buffer of at least length size */\nfunc optimizeHuffmanCountsForRLE(length uint, counts []uint32, good_for_rle []byte) {\n\tvar nonzero_count uint = 0\n\tvar stride uint\n\tvar limit uint\n\tvar sum uint\n\tvar streak_limit uint = 1240\n\tvar i uint\n\t/* Let's make the Huffman code more compatible with RLE encoding. */\n\tfor i = 0; i < length; i++ {\n\t\tif counts[i] != 0 {\n\t\t\tnonzero_count++\n\t\t}\n\t}\n\n\tif nonzero_count < 16 {\n\t\treturn\n\t}\n\n\tfor length != 0 && counts[length-1] == 0 {\n\t\tlength--\n\t}\n\n\tif length == 0 {\n\t\treturn /* All zeros. */\n\t}\n\n\t/* Now counts[0..length - 1] does not have trailing zeros. */\n\t{\n\t\tvar nonzeros uint = 0\n\t\tvar smallest_nonzero uint32 = 1 << 30\n\t\tfor i = 0; i < length; i++ {\n\t\t\tif counts[i] != 0 {\n\t\t\t\tnonzeros++\n\t\t\t\tif smallest_nonzero > counts[i] {\n\t\t\t\t\tsmallest_nonzero = counts[i]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif nonzeros < 5 {\n\t\t\t/* Small histogram will model it well. */\n\t\t\treturn\n\t\t}\n\n\t\tif smallest_nonzero < 4 {\n\t\t\tvar zeros uint = length - nonzeros\n\t\t\tif zeros < 6 {\n\t\t\t\tfor i = 1; i < length-1; i++ {\n\t\t\t\t\tif counts[i-1] != 0 && counts[i] == 0 && counts[i+1] != 0 {\n\t\t\t\t\t\tcounts[i] = 1\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif nonzeros < 28 {\n\t\t\treturn\n\t\t}\n\t}\n\n\t/* 2) Let's mark all population counts that already can be encoded\n\t   with an RLE code. */\n\tfor i := 0; i < int(length); i++ {\n\t\tgood_for_rle[i] = 0\n\t}\n\t{\n\t\tvar symbol uint32 = counts[0]\n\t\t/* Let's not spoil any of the existing good RLE codes.\n\t\t   Mark any seq of 0's that is longer as 5 as a good_for_rle.\n\t\t   Mark any seq of non-0's that is longer as 7 as a good_for_rle. */\n\n\t\tvar step uint = 0\n\t\tfor i = 0; i <= length; i++ {\n\t\t\tif i == length || counts[i] != symbol {\n\t\t\t\tif (symbol == 0 && step >= 5) || (symbol != 0 && step >= 7) {\n\t\t\t\t\tvar k uint\n\t\t\t\t\tfor k = 0; k < step; k++ {\n\t\t\t\t\t\tgood_for_rle[i-k-1] = 1\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tstep = 1\n\t\t\t\tif i != length {\n\t\t\t\t\tsymbol = counts[i]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstep++\n\t\t\t}\n\t\t}\n\t}\n\n\t/* 3) Let's replace those population counts that lead to more RLE codes.\n\t   Math here is in 24.8 fixed point representation. */\n\tstride = 0\n\n\tlimit = uint(256*(counts[0]+counts[1]+counts[2])/3 + 420)\n\tsum = 0\n\tfor i = 0; i <= length; i++ {\n\t\tif i == length || good_for_rle[i] != 0 || (i != 0 && good_for_rle[i-1] != 0) || (256*counts[i]-uint32(limit)+uint32(streak_limit)) >= uint32(2*streak_limit) {\n\t\t\tif stride >= 4 || (stride >= 3 && sum == 0) {\n\t\t\t\tvar k uint\n\t\t\t\tvar count uint = (sum + stride/2) / stride\n\t\t\t\t/* The stride must end, collapse what we have, if we have enough (4). */\n\t\t\t\tif count == 0 {\n\t\t\t\t\tcount = 1\n\t\t\t\t}\n\n\t\t\t\tif sum == 0 {\n\t\t\t\t\t/* Don't make an all zeros stride to be upgraded to ones. */\n\t\t\t\t\tcount = 0\n\t\t\t\t}\n\n\t\t\t\tfor k = 0; k < stride; k++ {\n\t\t\t\t\t/* We don't want to change value at counts[i],\n\t\t\t\t\t   that is already belonging to the next stride. Thus - 1. */\n\t\t\t\t\tcounts[i-k-1] = uint32(count)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstride = 0\n\t\t\tsum = 0\n\t\t\tif i < length-2 {\n\t\t\t\t/* All interesting strides have a count of at least 4, */\n\t\t\t\t/* at least when non-zeros. */\n\t\t\t\tlimit = uint(256*(counts[i]+counts[i+1]+counts[i+2])/3 + 420)\n\t\t\t} else if i < length {\n\t\t\t\tlimit = uint(256 * counts[i])\n\t\t\t} else {\n\t\t\t\tlimit = 0\n\t\t\t}\n\t\t}\n\n\t\tstride++\n\t\tif i != length {\n\t\t\tsum += uint(counts[i])\n\t\t\tif stride >= 4 {\n\t\t\t\tlimit = (256*sum + stride/2) / stride\n\t\t\t}\n\n\t\t\tif stride == 4 {\n\t\t\t\tlimit += 120\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc decideOverRLEUse(depth []byte, length uint, use_rle_for_non_zero *bool, use_rle_for_zero *bool) {\n\tvar total_reps_zero uint = 0\n\tvar total_reps_non_zero uint = 0\n\tvar count_reps_zero uint = 1\n\tvar count_reps_non_zero uint = 1\n\tvar i uint\n\tfor i = 0; i < length; {\n\t\tvar value byte = depth[i]\n\t\tvar reps uint = 1\n\t\tvar k uint\n\t\tfor k = i + 1; k < length && depth[k] == value; k++ {\n\t\t\treps++\n\t\t}\n\n\t\tif reps >= 3 && value == 0 {\n\t\t\ttotal_reps_zero += reps\n\t\t\tcount_reps_zero++\n\t\t}\n\n\t\tif reps >= 4 && value != 0 {\n\t\t\ttotal_reps_non_zero += reps\n\t\t\tcount_reps_non_zero++\n\t\t}\n\n\t\ti += reps\n\t}\n\n\t*use_rle_for_non_zero = total_reps_non_zero > count_reps_non_zero*2\n\t*use_rle_for_zero = total_reps_zero > count_reps_zero*2\n}\n\n/* Write a Huffman tree from bit depths into the bit-stream representation\n   of a Huffman tree. The generated Huffman tree is to be compressed once\n   more using a Huffman tree */\nfunc writeHuffmanTree(depth []byte, length uint, tree_size *uint, tree []byte, extra_bits_data []byte) {\n\tvar previous_value byte = initialRepeatedCodeLength\n\tvar i uint\n\tvar use_rle_for_non_zero bool = false\n\tvar use_rle_for_zero bool = false\n\tvar new_length uint = length\n\t/* Throw away trailing zeros. */\n\tfor i = 0; i < length; i++ {\n\t\tif depth[length-i-1] == 0 {\n\t\t\tnew_length--\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t/* First gather statistics on if it is a good idea to do RLE. */\n\tif length > 50 {\n\t\t/* Find RLE coding for longer codes.\n\t\t   Shorter codes seem not to benefit from RLE. */\n\t\tdecideOverRLEUse(depth, new_length, &use_rle_for_non_zero, &use_rle_for_zero)\n\t}\n\n\t/* Actual RLE coding. */\n\tfor i = 0; i < new_length; {\n\t\tvar value byte = depth[i]\n\t\tvar reps uint = 1\n\t\tif (value != 0 && use_rle_for_non_zero) || (value == 0 && use_rle_for_zero) {\n\t\t\tvar k uint\n\t\t\tfor k = i + 1; k < new_length && depth[k] == value; k++ {\n\t\t\t\treps++\n\t\t\t}\n\t\t}\n\n\t\tif value == 0 {\n\t\t\twriteHuffmanTreeRepetitionsZeros(reps, tree_size, tree, extra_bits_data)\n\t\t} else {\n\t\t\twriteHuffmanTreeRepetitions(previous_value, value, reps, tree_size, tree, extra_bits_data)\n\t\t\tprevious_value = value\n\t\t}\n\n\t\ti += reps\n\t}\n}\n\nvar reverseBits_kLut = [16]uint{\n\t0x00,\n\t0x08,\n\t0x04,\n\t0x0C,\n\t0x02,\n\t0x0A,\n\t0x06,\n\t0x0E,\n\t0x01,\n\t0x09,\n\t0x05,\n\t0x0D,\n\t0x03,\n\t0x0B,\n\t0x07,\n\t0x0F,\n}\n\nfunc reverseBits(num_bits uint, bits uint16) uint16 {\n\tvar retval uint = reverseBits_kLut[bits&0x0F]\n\tvar i uint\n\tfor i = 4; i < num_bits; i += 4 {\n\t\tretval <<= 4\n\t\tbits = uint16(bits >> 4)\n\t\tretval |= reverseBits_kLut[bits&0x0F]\n\t}\n\n\tretval >>= ((0 - num_bits) & 0x03)\n\treturn uint16(retval)\n}\n\n/* 0..15 are values for bits */\nconst maxHuffmanBits = 16\n\n/* Get the actual bit values for a tree of bit depths. */\nfunc convertBitDepthsToSymbols(depth []byte, len uint, bits []uint16) {\n\tvar bl_count = [maxHuffmanBits]uint16{0}\n\tvar next_code [maxHuffmanBits]uint16\n\tvar i uint\n\t/* In Brotli, all bit depths are [1..15]\n\t   0 bit depth means that the symbol does not exist. */\n\n\tvar code int = 0\n\tfor i = 0; i < len; i++ {\n\t\tbl_count[depth[i]]++\n\t}\n\n\tbl_count[0] = 0\n\tnext_code[0] = 0\n\tfor i = 1; i < maxHuffmanBits; i++ {\n\t\tcode = (code + int(bl_count[i-1])) << 1\n\t\tnext_code[i] = uint16(code)\n\t}\n\n\tfor i = 0; i < len; i++ {\n\t\tif depth[i] != 0 {\n\t\t\tbits[i] = reverseBits(uint(depth[i]), next_code[depth[i]])\n\t\t\tnext_code[depth[i]]++\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/entropy_encode_static.go",
    "content": "package brotli\n\nvar kCodeLengthDepth = [18]byte{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4}\n\nvar kStaticCommandCodeDepth = [numCommandSymbols]byte{\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t9,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n\t11,\n}\n\nvar kStaticDistanceCodeDepth = [64]byte{\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n\t6,\n}\n\nvar kCodeLengthBits = [18]uint32{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7}\n\nfunc storeStaticCodeLengthCode(storage_ix *uint, storage []byte) {\n\twriteBits(40, 0x0000FF55555554, storage_ix, storage)\n}\n\nfunc storeStaticCodeLengthCodeBW(bw *bitWriter) {\n\tbw.writeBits(32, 0x55555554)\n\tbw.writeBits(8, 0xFF)\n}\n\nvar kZeroRepsBits = [numCommandSymbols]uint64{\n\t0x00000000,\n\t0x00000000,\n\t0x00000000,\n\t0x00000007,\n\t0x00000017,\n\t0x00000027,\n\t0x00000037,\n\t0x00000047,\n\t0x00000057,\n\t0x00000067,\n\t0x00000077,\n\t0x00000770,\n\t0x00000b87,\n\t0x00001387,\n\t0x00001b87,\n\t0x00002387,\n\t0x00002b87,\n\t0x00003387,\n\t0x00003b87,\n\t0x00000397,\n\t0x00000b97,\n\t0x00001397,\n\t0x00001b97,\n\t0x00002397,\n\t0x00002b97,\n\t0x00003397,\n\t0x00003b97,\n\t0x000003a7,\n\t0x00000ba7,\n\t0x000013a7,\n\t0x00001ba7,\n\t0x000023a7,\n\t0x00002ba7,\n\t0x000033a7,\n\t0x00003ba7,\n\t0x000003b7,\n\t0x00000bb7,\n\t0x000013b7,\n\t0x00001bb7,\n\t0x000023b7,\n\t0x00002bb7,\n\t0x000033b7,\n\t0x00003bb7,\n\t0x000003c7,\n\t0x00000bc7,\n\t0x000013c7,\n\t0x00001bc7,\n\t0x000023c7,\n\t0x00002bc7,\n\t0x000033c7,\n\t0x00003bc7,\n\t0x000003d7,\n\t0x00000bd7,\n\t0x000013d7,\n\t0x00001bd7,\n\t0x000023d7,\n\t0x00002bd7,\n\t0x000033d7,\n\t0x00003bd7,\n\t0x000003e7,\n\t0x00000be7,\n\t0x000013e7,\n\t0x00001be7,\n\t0x000023e7,\n\t0x00002be7,\n\t0x000033e7,\n\t0x00003be7,\n\t0x000003f7,\n\t0x00000bf7,\n\t0x000013f7,\n\t0x00001bf7,\n\t0x000023f7,\n\t0x00002bf7,\n\t0x000033f7,\n\t0x00003bf7,\n\t0x0001c387,\n\t0x0005c387,\n\t0x0009c387,\n\t0x000dc387,\n\t0x0011c387,\n\t0x0015c387,\n\t0x0019c387,\n\t0x001dc387,\n\t0x0001cb87,\n\t0x0005cb87,\n\t0x0009cb87,\n\t0x000dcb87,\n\t0x0011cb87,\n\t0x0015cb87,\n\t0x0019cb87,\n\t0x001dcb87,\n\t0x0001d387,\n\t0x0005d387,\n\t0x0009d387,\n\t0x000dd387,\n\t0x0011d387,\n\t0x0015d387,\n\t0x0019d387,\n\t0x001dd387,\n\t0x0001db87,\n\t0x0005db87,\n\t0x0009db87,\n\t0x000ddb87,\n\t0x0011db87,\n\t0x0015db87,\n\t0x0019db87,\n\t0x001ddb87,\n\t0x0001e387,\n\t0x0005e387,\n\t0x0009e387,\n\t0x000de387,\n\t0x0011e387,\n\t0x0015e387,\n\t0x0019e387,\n\t0x001de387,\n\t0x0001eb87,\n\t0x0005eb87,\n\t0x0009eb87,\n\t0x000deb87,\n\t0x0011eb87,\n\t0x0015eb87,\n\t0x0019eb87,\n\t0x001deb87,\n\t0x0001f387,\n\t0x0005f387,\n\t0x0009f387,\n\t0x000df387,\n\t0x0011f387,\n\t0x0015f387,\n\t0x0019f387,\n\t0x001df387,\n\t0x0001fb87,\n\t0x0005fb87,\n\t0x0009fb87,\n\t0x000dfb87,\n\t0x0011fb87,\n\t0x0015fb87,\n\t0x0019fb87,\n\t0x001dfb87,\n\t0x0001c397,\n\t0x0005c397,\n\t0x0009c397,\n\t0x000dc397,\n\t0x0011c397,\n\t0x0015c397,\n\t0x0019c397,\n\t0x001dc397,\n\t0x0001cb97,\n\t0x0005cb97,\n\t0x0009cb97,\n\t0x000dcb97,\n\t0x0011cb97,\n\t0x0015cb97,\n\t0x0019cb97,\n\t0x001dcb97,\n\t0x0001d397,\n\t0x0005d397,\n\t0x0009d397,\n\t0x000dd397,\n\t0x0011d397,\n\t0x0015d397,\n\t0x0019d397,\n\t0x001dd397,\n\t0x0001db97,\n\t0x0005db97,\n\t0x0009db97,\n\t0x000ddb97,\n\t0x0011db97,\n\t0x0015db97,\n\t0x0019db97,\n\t0x001ddb97,\n\t0x0001e397,\n\t0x0005e397,\n\t0x0009e397,\n\t0x000de397,\n\t0x0011e397,\n\t0x0015e397,\n\t0x0019e397,\n\t0x001de397,\n\t0x0001eb97,\n\t0x0005eb97,\n\t0x0009eb97,\n\t0x000deb97,\n\t0x0011eb97,\n\t0x0015eb97,\n\t0x0019eb97,\n\t0x001deb97,\n\t0x0001f397,\n\t0x0005f397,\n\t0x0009f397,\n\t0x000df397,\n\t0x0011f397,\n\t0x0015f397,\n\t0x0019f397,\n\t0x001df397,\n\t0x0001fb97,\n\t0x0005fb97,\n\t0x0009fb97,\n\t0x000dfb97,\n\t0x0011fb97,\n\t0x0015fb97,\n\t0x0019fb97,\n\t0x001dfb97,\n\t0x0001c3a7,\n\t0x0005c3a7,\n\t0x0009c3a7,\n\t0x000dc3a7,\n\t0x0011c3a7,\n\t0x0015c3a7,\n\t0x0019c3a7,\n\t0x001dc3a7,\n\t0x0001cba7,\n\t0x0005cba7,\n\t0x0009cba7,\n\t0x000dcba7,\n\t0x0011cba7,\n\t0x0015cba7,\n\t0x0019cba7,\n\t0x001dcba7,\n\t0x0001d3a7,\n\t0x0005d3a7,\n\t0x0009d3a7,\n\t0x000dd3a7,\n\t0x0011d3a7,\n\t0x0015d3a7,\n\t0x0019d3a7,\n\t0x001dd3a7,\n\t0x0001dba7,\n\t0x0005dba7,\n\t0x0009dba7,\n\t0x000ddba7,\n\t0x0011dba7,\n\t0x0015dba7,\n\t0x0019dba7,\n\t0x001ddba7,\n\t0x0001e3a7,\n\t0x0005e3a7,\n\t0x0009e3a7,\n\t0x000de3a7,\n\t0x0011e3a7,\n\t0x0015e3a7,\n\t0x0019e3a7,\n\t0x001de3a7,\n\t0x0001eba7,\n\t0x0005eba7,\n\t0x0009eba7,\n\t0x000deba7,\n\t0x0011eba7,\n\t0x0015eba7,\n\t0x0019eba7,\n\t0x001deba7,\n\t0x0001f3a7,\n\t0x0005f3a7,\n\t0x0009f3a7,\n\t0x000df3a7,\n\t0x0011f3a7,\n\t0x0015f3a7,\n\t0x0019f3a7,\n\t0x001df3a7,\n\t0x0001fba7,\n\t0x0005fba7,\n\t0x0009fba7,\n\t0x000dfba7,\n\t0x0011fba7,\n\t0x0015fba7,\n\t0x0019fba7,\n\t0x001dfba7,\n\t0x0001c3b7,\n\t0x0005c3b7,\n\t0x0009c3b7,\n\t0x000dc3b7,\n\t0x0011c3b7,\n\t0x0015c3b7,\n\t0x0019c3b7,\n\t0x001dc3b7,\n\t0x0001cbb7,\n\t0x0005cbb7,\n\t0x0009cbb7,\n\t0x000dcbb7,\n\t0x0011cbb7,\n\t0x0015cbb7,\n\t0x0019cbb7,\n\t0x001dcbb7,\n\t0x0001d3b7,\n\t0x0005d3b7,\n\t0x0009d3b7,\n\t0x000dd3b7,\n\t0x0011d3b7,\n\t0x0015d3b7,\n\t0x0019d3b7,\n\t0x001dd3b7,\n\t0x0001dbb7,\n\t0x0005dbb7,\n\t0x0009dbb7,\n\t0x000ddbb7,\n\t0x0011dbb7,\n\t0x0015dbb7,\n\t0x0019dbb7,\n\t0x001ddbb7,\n\t0x0001e3b7,\n\t0x0005e3b7,\n\t0x0009e3b7,\n\t0x000de3b7,\n\t0x0011e3b7,\n\t0x0015e3b7,\n\t0x0019e3b7,\n\t0x001de3b7,\n\t0x0001ebb7,\n\t0x0005ebb7,\n\t0x0009ebb7,\n\t0x000debb7,\n\t0x0011ebb7,\n\t0x0015ebb7,\n\t0x0019ebb7,\n\t0x001debb7,\n\t0x0001f3b7,\n\t0x0005f3b7,\n\t0x0009f3b7,\n\t0x000df3b7,\n\t0x0011f3b7,\n\t0x0015f3b7,\n\t0x0019f3b7,\n\t0x001df3b7,\n\t0x0001fbb7,\n\t0x0005fbb7,\n\t0x0009fbb7,\n\t0x000dfbb7,\n\t0x0011fbb7,\n\t0x0015fbb7,\n\t0x0019fbb7,\n\t0x001dfbb7,\n\t0x0001c3c7,\n\t0x0005c3c7,\n\t0x0009c3c7,\n\t0x000dc3c7,\n\t0x0011c3c7,\n\t0x0015c3c7,\n\t0x0019c3c7,\n\t0x001dc3c7,\n\t0x0001cbc7,\n\t0x0005cbc7,\n\t0x0009cbc7,\n\t0x000dcbc7,\n\t0x0011cbc7,\n\t0x0015cbc7,\n\t0x0019cbc7,\n\t0x001dcbc7,\n\t0x0001d3c7,\n\t0x0005d3c7,\n\t0x0009d3c7,\n\t0x000dd3c7,\n\t0x0011d3c7,\n\t0x0015d3c7,\n\t0x0019d3c7,\n\t0x001dd3c7,\n\t0x0001dbc7,\n\t0x0005dbc7,\n\t0x0009dbc7,\n\t0x000ddbc7,\n\t0x0011dbc7,\n\t0x0015dbc7,\n\t0x0019dbc7,\n\t0x001ddbc7,\n\t0x0001e3c7,\n\t0x0005e3c7,\n\t0x0009e3c7,\n\t0x000de3c7,\n\t0x0011e3c7,\n\t0x0015e3c7,\n\t0x0019e3c7,\n\t0x001de3c7,\n\t0x0001ebc7,\n\t0x0005ebc7,\n\t0x0009ebc7,\n\t0x000debc7,\n\t0x0011ebc7,\n\t0x0015ebc7,\n\t0x0019ebc7,\n\t0x001debc7,\n\t0x0001f3c7,\n\t0x0005f3c7,\n\t0x0009f3c7,\n\t0x000df3c7,\n\t0x0011f3c7,\n\t0x0015f3c7,\n\t0x0019f3c7,\n\t0x001df3c7,\n\t0x0001fbc7,\n\t0x0005fbc7,\n\t0x0009fbc7,\n\t0x000dfbc7,\n\t0x0011fbc7,\n\t0x0015fbc7,\n\t0x0019fbc7,\n\t0x001dfbc7,\n\t0x0001c3d7,\n\t0x0005c3d7,\n\t0x0009c3d7,\n\t0x000dc3d7,\n\t0x0011c3d7,\n\t0x0015c3d7,\n\t0x0019c3d7,\n\t0x001dc3d7,\n\t0x0001cbd7,\n\t0x0005cbd7,\n\t0x0009cbd7,\n\t0x000dcbd7,\n\t0x0011cbd7,\n\t0x0015cbd7,\n\t0x0019cbd7,\n\t0x001dcbd7,\n\t0x0001d3d7,\n\t0x0005d3d7,\n\t0x0009d3d7,\n\t0x000dd3d7,\n\t0x0011d3d7,\n\t0x0015d3d7,\n\t0x0019d3d7,\n\t0x001dd3d7,\n\t0x0001dbd7,\n\t0x0005dbd7,\n\t0x0009dbd7,\n\t0x000ddbd7,\n\t0x0011dbd7,\n\t0x0015dbd7,\n\t0x0019dbd7,\n\t0x001ddbd7,\n\t0x0001e3d7,\n\t0x0005e3d7,\n\t0x0009e3d7,\n\t0x000de3d7,\n\t0x0011e3d7,\n\t0x0015e3d7,\n\t0x0019e3d7,\n\t0x001de3d7,\n\t0x0001ebd7,\n\t0x0005ebd7,\n\t0x0009ebd7,\n\t0x000debd7,\n\t0x0011ebd7,\n\t0x0015ebd7,\n\t0x0019ebd7,\n\t0x001debd7,\n\t0x0001f3d7,\n\t0x0005f3d7,\n\t0x0009f3d7,\n\t0x000df3d7,\n\t0x0011f3d7,\n\t0x0015f3d7,\n\t0x0019f3d7,\n\t0x001df3d7,\n\t0x0001fbd7,\n\t0x0005fbd7,\n\t0x0009fbd7,\n\t0x000dfbd7,\n\t0x0011fbd7,\n\t0x0015fbd7,\n\t0x0019fbd7,\n\t0x001dfbd7,\n\t0x0001c3e7,\n\t0x0005c3e7,\n\t0x0009c3e7,\n\t0x000dc3e7,\n\t0x0011c3e7,\n\t0x0015c3e7,\n\t0x0019c3e7,\n\t0x001dc3e7,\n\t0x0001cbe7,\n\t0x0005cbe7,\n\t0x0009cbe7,\n\t0x000dcbe7,\n\t0x0011cbe7,\n\t0x0015cbe7,\n\t0x0019cbe7,\n\t0x001dcbe7,\n\t0x0001d3e7,\n\t0x0005d3e7,\n\t0x0009d3e7,\n\t0x000dd3e7,\n\t0x0011d3e7,\n\t0x0015d3e7,\n\t0x0019d3e7,\n\t0x001dd3e7,\n\t0x0001dbe7,\n\t0x0005dbe7,\n\t0x0009dbe7,\n\t0x000ddbe7,\n\t0x0011dbe7,\n\t0x0015dbe7,\n\t0x0019dbe7,\n\t0x001ddbe7,\n\t0x0001e3e7,\n\t0x0005e3e7,\n\t0x0009e3e7,\n\t0x000de3e7,\n\t0x0011e3e7,\n\t0x0015e3e7,\n\t0x0019e3e7,\n\t0x001de3e7,\n\t0x0001ebe7,\n\t0x0005ebe7,\n\t0x0009ebe7,\n\t0x000debe7,\n\t0x0011ebe7,\n\t0x0015ebe7,\n\t0x0019ebe7,\n\t0x001debe7,\n\t0x0001f3e7,\n\t0x0005f3e7,\n\t0x0009f3e7,\n\t0x000df3e7,\n\t0x0011f3e7,\n\t0x0015f3e7,\n\t0x0019f3e7,\n\t0x001df3e7,\n\t0x0001fbe7,\n\t0x0005fbe7,\n\t0x0009fbe7,\n\t0x000dfbe7,\n\t0x0011fbe7,\n\t0x0015fbe7,\n\t0x0019fbe7,\n\t0x001dfbe7,\n\t0x0001c3f7,\n\t0x0005c3f7,\n\t0x0009c3f7,\n\t0x000dc3f7,\n\t0x0011c3f7,\n\t0x0015c3f7,\n\t0x0019c3f7,\n\t0x001dc3f7,\n\t0x0001cbf7,\n\t0x0005cbf7,\n\t0x0009cbf7,\n\t0x000dcbf7,\n\t0x0011cbf7,\n\t0x0015cbf7,\n\t0x0019cbf7,\n\t0x001dcbf7,\n\t0x0001d3f7,\n\t0x0005d3f7,\n\t0x0009d3f7,\n\t0x000dd3f7,\n\t0x0011d3f7,\n\t0x0015d3f7,\n\t0x0019d3f7,\n\t0x001dd3f7,\n\t0x0001dbf7,\n\t0x0005dbf7,\n\t0x0009dbf7,\n\t0x000ddbf7,\n\t0x0011dbf7,\n\t0x0015dbf7,\n\t0x0019dbf7,\n\t0x001ddbf7,\n\t0x0001e3f7,\n\t0x0005e3f7,\n\t0x0009e3f7,\n\t0x000de3f7,\n\t0x0011e3f7,\n\t0x0015e3f7,\n\t0x0019e3f7,\n\t0x001de3f7,\n\t0x0001ebf7,\n\t0x0005ebf7,\n\t0x0009ebf7,\n\t0x000debf7,\n\t0x0011ebf7,\n\t0x0015ebf7,\n\t0x0019ebf7,\n\t0x001debf7,\n\t0x0001f3f7,\n\t0x0005f3f7,\n\t0x0009f3f7,\n\t0x000df3f7,\n\t0x0011f3f7,\n\t0x0015f3f7,\n\t0x0019f3f7,\n\t0x001df3f7,\n\t0x0001fbf7,\n\t0x0005fbf7,\n\t0x0009fbf7,\n\t0x000dfbf7,\n\t0x0011fbf7,\n\t0x0015fbf7,\n\t0x0019fbf7,\n\t0x001dfbf7,\n\t0x00e1c387,\n\t0x02e1c387,\n\t0x04e1c387,\n\t0x06e1c387,\n\t0x08e1c387,\n\t0x0ae1c387,\n\t0x0ce1c387,\n\t0x0ee1c387,\n\t0x00e5c387,\n\t0x02e5c387,\n\t0x04e5c387,\n\t0x06e5c387,\n\t0x08e5c387,\n\t0x0ae5c387,\n\t0x0ce5c387,\n\t0x0ee5c387,\n\t0x00e9c387,\n\t0x02e9c387,\n\t0x04e9c387,\n\t0x06e9c387,\n\t0x08e9c387,\n\t0x0ae9c387,\n\t0x0ce9c387,\n\t0x0ee9c387,\n\t0x00edc387,\n\t0x02edc387,\n\t0x04edc387,\n\t0x06edc387,\n\t0x08edc387,\n\t0x0aedc387,\n\t0x0cedc387,\n\t0x0eedc387,\n\t0x00f1c387,\n\t0x02f1c387,\n\t0x04f1c387,\n\t0x06f1c387,\n\t0x08f1c387,\n\t0x0af1c387,\n\t0x0cf1c387,\n\t0x0ef1c387,\n\t0x00f5c387,\n\t0x02f5c387,\n\t0x04f5c387,\n\t0x06f5c387,\n\t0x08f5c387,\n\t0x0af5c387,\n\t0x0cf5c387,\n\t0x0ef5c387,\n\t0x00f9c387,\n\t0x02f9c387,\n\t0x04f9c387,\n\t0x06f9c387,\n\t0x08f9c387,\n\t0x0af9c387,\n\t0x0cf9c387,\n\t0x0ef9c387,\n\t0x00fdc387,\n\t0x02fdc387,\n\t0x04fdc387,\n\t0x06fdc387,\n\t0x08fdc387,\n\t0x0afdc387,\n\t0x0cfdc387,\n\t0x0efdc387,\n\t0x00e1cb87,\n\t0x02e1cb87,\n\t0x04e1cb87,\n\t0x06e1cb87,\n\t0x08e1cb87,\n\t0x0ae1cb87,\n\t0x0ce1cb87,\n\t0x0ee1cb87,\n\t0x00e5cb87,\n\t0x02e5cb87,\n\t0x04e5cb87,\n\t0x06e5cb87,\n\t0x08e5cb87,\n\t0x0ae5cb87,\n\t0x0ce5cb87,\n\t0x0ee5cb87,\n\t0x00e9cb87,\n\t0x02e9cb87,\n\t0x04e9cb87,\n\t0x06e9cb87,\n\t0x08e9cb87,\n\t0x0ae9cb87,\n\t0x0ce9cb87,\n\t0x0ee9cb87,\n\t0x00edcb87,\n\t0x02edcb87,\n\t0x04edcb87,\n\t0x06edcb87,\n\t0x08edcb87,\n\t0x0aedcb87,\n\t0x0cedcb87,\n\t0x0eedcb87,\n\t0x00f1cb87,\n\t0x02f1cb87,\n\t0x04f1cb87,\n\t0x06f1cb87,\n\t0x08f1cb87,\n\t0x0af1cb87,\n\t0x0cf1cb87,\n\t0x0ef1cb87,\n\t0x00f5cb87,\n\t0x02f5cb87,\n\t0x04f5cb87,\n\t0x06f5cb87,\n\t0x08f5cb87,\n\t0x0af5cb87,\n\t0x0cf5cb87,\n\t0x0ef5cb87,\n\t0x00f9cb87,\n\t0x02f9cb87,\n\t0x04f9cb87,\n\t0x06f9cb87,\n\t0x08f9cb87,\n}\n\nvar kZeroRepsDepth = [numCommandSymbols]uint32{\n\t0,\n\t4,\n\t8,\n\t7,\n\t7,\n\t7,\n\t7,\n\t7,\n\t7,\n\t7,\n\t7,\n\t11,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t14,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t21,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n\t28,\n}\n\nvar kNonZeroRepsBits = [numCommandSymbols]uint64{\n\t0x0000000b,\n\t0x0000001b,\n\t0x0000002b,\n\t0x0000003b,\n\t0x000002cb,\n\t0x000006cb,\n\t0x00000acb,\n\t0x00000ecb,\n\t0x000002db,\n\t0x000006db,\n\t0x00000adb,\n\t0x00000edb,\n\t0x000002eb,\n\t0x000006eb,\n\t0x00000aeb,\n\t0x00000eeb,\n\t0x000002fb,\n\t0x000006fb,\n\t0x00000afb,\n\t0x00000efb,\n\t0x0000b2cb,\n\t0x0001b2cb,\n\t0x0002b2cb,\n\t0x0003b2cb,\n\t0x0000b6cb,\n\t0x0001b6cb,\n\t0x0002b6cb,\n\t0x0003b6cb,\n\t0x0000bacb,\n\t0x0001bacb,\n\t0x0002bacb,\n\t0x0003bacb,\n\t0x0000becb,\n\t0x0001becb,\n\t0x0002becb,\n\t0x0003becb,\n\t0x0000b2db,\n\t0x0001b2db,\n\t0x0002b2db,\n\t0x0003b2db,\n\t0x0000b6db,\n\t0x0001b6db,\n\t0x0002b6db,\n\t0x0003b6db,\n\t0x0000badb,\n\t0x0001badb,\n\t0x0002badb,\n\t0x0003badb,\n\t0x0000bedb,\n\t0x0001bedb,\n\t0x0002bedb,\n\t0x0003bedb,\n\t0x0000b2eb,\n\t0x0001b2eb,\n\t0x0002b2eb,\n\t0x0003b2eb,\n\t0x0000b6eb,\n\t0x0001b6eb,\n\t0x0002b6eb,\n\t0x0003b6eb,\n\t0x0000baeb,\n\t0x0001baeb,\n\t0x0002baeb,\n\t0x0003baeb,\n\t0x0000beeb,\n\t0x0001beeb,\n\t0x0002beeb,\n\t0x0003beeb,\n\t0x0000b2fb,\n\t0x0001b2fb,\n\t0x0002b2fb,\n\t0x0003b2fb,\n\t0x0000b6fb,\n\t0x0001b6fb,\n\t0x0002b6fb,\n\t0x0003b6fb,\n\t0x0000bafb,\n\t0x0001bafb,\n\t0x0002bafb,\n\t0x0003bafb,\n\t0x0000befb,\n\t0x0001befb,\n\t0x0002befb,\n\t0x0003befb,\n\t0x002cb2cb,\n\t0x006cb2cb,\n\t0x00acb2cb,\n\t0x00ecb2cb,\n\t0x002db2cb,\n\t0x006db2cb,\n\t0x00adb2cb,\n\t0x00edb2cb,\n\t0x002eb2cb,\n\t0x006eb2cb,\n\t0x00aeb2cb,\n\t0x00eeb2cb,\n\t0x002fb2cb,\n\t0x006fb2cb,\n\t0x00afb2cb,\n\t0x00efb2cb,\n\t0x002cb6cb,\n\t0x006cb6cb,\n\t0x00acb6cb,\n\t0x00ecb6cb,\n\t0x002db6cb,\n\t0x006db6cb,\n\t0x00adb6cb,\n\t0x00edb6cb,\n\t0x002eb6cb,\n\t0x006eb6cb,\n\t0x00aeb6cb,\n\t0x00eeb6cb,\n\t0x002fb6cb,\n\t0x006fb6cb,\n\t0x00afb6cb,\n\t0x00efb6cb,\n\t0x002cbacb,\n\t0x006cbacb,\n\t0x00acbacb,\n\t0x00ecbacb,\n\t0x002dbacb,\n\t0x006dbacb,\n\t0x00adbacb,\n\t0x00edbacb,\n\t0x002ebacb,\n\t0x006ebacb,\n\t0x00aebacb,\n\t0x00eebacb,\n\t0x002fbacb,\n\t0x006fbacb,\n\t0x00afbacb,\n\t0x00efbacb,\n\t0x002cbecb,\n\t0x006cbecb,\n\t0x00acbecb,\n\t0x00ecbecb,\n\t0x002dbecb,\n\t0x006dbecb,\n\t0x00adbecb,\n\t0x00edbecb,\n\t0x002ebecb,\n\t0x006ebecb,\n\t0x00aebecb,\n\t0x00eebecb,\n\t0x002fbecb,\n\t0x006fbecb,\n\t0x00afbecb,\n\t0x00efbecb,\n\t0x002cb2db,\n\t0x006cb2db,\n\t0x00acb2db,\n\t0x00ecb2db,\n\t0x002db2db,\n\t0x006db2db,\n\t0x00adb2db,\n\t0x00edb2db,\n\t0x002eb2db,\n\t0x006eb2db,\n\t0x00aeb2db,\n\t0x00eeb2db,\n\t0x002fb2db,\n\t0x006fb2db,\n\t0x00afb2db,\n\t0x00efb2db,\n\t0x002cb6db,\n\t0x006cb6db,\n\t0x00acb6db,\n\t0x00ecb6db,\n\t0x002db6db,\n\t0x006db6db,\n\t0x00adb6db,\n\t0x00edb6db,\n\t0x002eb6db,\n\t0x006eb6db,\n\t0x00aeb6db,\n\t0x00eeb6db,\n\t0x002fb6db,\n\t0x006fb6db,\n\t0x00afb6db,\n\t0x00efb6db,\n\t0x002cbadb,\n\t0x006cbadb,\n\t0x00acbadb,\n\t0x00ecbadb,\n\t0x002dbadb,\n\t0x006dbadb,\n\t0x00adbadb,\n\t0x00edbadb,\n\t0x002ebadb,\n\t0x006ebadb,\n\t0x00aebadb,\n\t0x00eebadb,\n\t0x002fbadb,\n\t0x006fbadb,\n\t0x00afbadb,\n\t0x00efbadb,\n\t0x002cbedb,\n\t0x006cbedb,\n\t0x00acbedb,\n\t0x00ecbedb,\n\t0x002dbedb,\n\t0x006dbedb,\n\t0x00adbedb,\n\t0x00edbedb,\n\t0x002ebedb,\n\t0x006ebedb,\n\t0x00aebedb,\n\t0x00eebedb,\n\t0x002fbedb,\n\t0x006fbedb,\n\t0x00afbedb,\n\t0x00efbedb,\n\t0x002cb2eb,\n\t0x006cb2eb,\n\t0x00acb2eb,\n\t0x00ecb2eb,\n\t0x002db2eb,\n\t0x006db2eb,\n\t0x00adb2eb,\n\t0x00edb2eb,\n\t0x002eb2eb,\n\t0x006eb2eb,\n\t0x00aeb2eb,\n\t0x00eeb2eb,\n\t0x002fb2eb,\n\t0x006fb2eb,\n\t0x00afb2eb,\n\t0x00efb2eb,\n\t0x002cb6eb,\n\t0x006cb6eb,\n\t0x00acb6eb,\n\t0x00ecb6eb,\n\t0x002db6eb,\n\t0x006db6eb,\n\t0x00adb6eb,\n\t0x00edb6eb,\n\t0x002eb6eb,\n\t0x006eb6eb,\n\t0x00aeb6eb,\n\t0x00eeb6eb,\n\t0x002fb6eb,\n\t0x006fb6eb,\n\t0x00afb6eb,\n\t0x00efb6eb,\n\t0x002cbaeb,\n\t0x006cbaeb,\n\t0x00acbaeb,\n\t0x00ecbaeb,\n\t0x002dbaeb,\n\t0x006dbaeb,\n\t0x00adbaeb,\n\t0x00edbaeb,\n\t0x002ebaeb,\n\t0x006ebaeb,\n\t0x00aebaeb,\n\t0x00eebaeb,\n\t0x002fbaeb,\n\t0x006fbaeb,\n\t0x00afbaeb,\n\t0x00efbaeb,\n\t0x002cbeeb,\n\t0x006cbeeb,\n\t0x00acbeeb,\n\t0x00ecbeeb,\n\t0x002dbeeb,\n\t0x006dbeeb,\n\t0x00adbeeb,\n\t0x00edbeeb,\n\t0x002ebeeb,\n\t0x006ebeeb,\n\t0x00aebeeb,\n\t0x00eebeeb,\n\t0x002fbeeb,\n\t0x006fbeeb,\n\t0x00afbeeb,\n\t0x00efbeeb,\n\t0x002cb2fb,\n\t0x006cb2fb,\n\t0x00acb2fb,\n\t0x00ecb2fb,\n\t0x002db2fb,\n\t0x006db2fb,\n\t0x00adb2fb,\n\t0x00edb2fb,\n\t0x002eb2fb,\n\t0x006eb2fb,\n\t0x00aeb2fb,\n\t0x00eeb2fb,\n\t0x002fb2fb,\n\t0x006fb2fb,\n\t0x00afb2fb,\n\t0x00efb2fb,\n\t0x002cb6fb,\n\t0x006cb6fb,\n\t0x00acb6fb,\n\t0x00ecb6fb,\n\t0x002db6fb,\n\t0x006db6fb,\n\t0x00adb6fb,\n\t0x00edb6fb,\n\t0x002eb6fb,\n\t0x006eb6fb,\n\t0x00aeb6fb,\n\t0x00eeb6fb,\n\t0x002fb6fb,\n\t0x006fb6fb,\n\t0x00afb6fb,\n\t0x00efb6fb,\n\t0x002cbafb,\n\t0x006cbafb,\n\t0x00acbafb,\n\t0x00ecbafb,\n\t0x002dbafb,\n\t0x006dbafb,\n\t0x00adbafb,\n\t0x00edbafb,\n\t0x002ebafb,\n\t0x006ebafb,\n\t0x00aebafb,\n\t0x00eebafb,\n\t0x002fbafb,\n\t0x006fbafb,\n\t0x00afbafb,\n\t0x00efbafb,\n\t0x002cbefb,\n\t0x006cbefb,\n\t0x00acbefb,\n\t0x00ecbefb,\n\t0x002dbefb,\n\t0x006dbefb,\n\t0x00adbefb,\n\t0x00edbefb,\n\t0x002ebefb,\n\t0x006ebefb,\n\t0x00aebefb,\n\t0x00eebefb,\n\t0x002fbefb,\n\t0x006fbefb,\n\t0x00afbefb,\n\t0x00efbefb,\n\t0x0b2cb2cb,\n\t0x1b2cb2cb,\n\t0x2b2cb2cb,\n\t0x3b2cb2cb,\n\t0x0b6cb2cb,\n\t0x1b6cb2cb,\n\t0x2b6cb2cb,\n\t0x3b6cb2cb,\n\t0x0bacb2cb,\n\t0x1bacb2cb,\n\t0x2bacb2cb,\n\t0x3bacb2cb,\n\t0x0becb2cb,\n\t0x1becb2cb,\n\t0x2becb2cb,\n\t0x3becb2cb,\n\t0x0b2db2cb,\n\t0x1b2db2cb,\n\t0x2b2db2cb,\n\t0x3b2db2cb,\n\t0x0b6db2cb,\n\t0x1b6db2cb,\n\t0x2b6db2cb,\n\t0x3b6db2cb,\n\t0x0badb2cb,\n\t0x1badb2cb,\n\t0x2badb2cb,\n\t0x3badb2cb,\n\t0x0bedb2cb,\n\t0x1bedb2cb,\n\t0x2bedb2cb,\n\t0x3bedb2cb,\n\t0x0b2eb2cb,\n\t0x1b2eb2cb,\n\t0x2b2eb2cb,\n\t0x3b2eb2cb,\n\t0x0b6eb2cb,\n\t0x1b6eb2cb,\n\t0x2b6eb2cb,\n\t0x3b6eb2cb,\n\t0x0baeb2cb,\n\t0x1baeb2cb,\n\t0x2baeb2cb,\n\t0x3baeb2cb,\n\t0x0beeb2cb,\n\t0x1beeb2cb,\n\t0x2beeb2cb,\n\t0x3beeb2cb,\n\t0x0b2fb2cb,\n\t0x1b2fb2cb,\n\t0x2b2fb2cb,\n\t0x3b2fb2cb,\n\t0x0b6fb2cb,\n\t0x1b6fb2cb,\n\t0x2b6fb2cb,\n\t0x3b6fb2cb,\n\t0x0bafb2cb,\n\t0x1bafb2cb,\n\t0x2bafb2cb,\n\t0x3bafb2cb,\n\t0x0befb2cb,\n\t0x1befb2cb,\n\t0x2befb2cb,\n\t0x3befb2cb,\n\t0x0b2cb6cb,\n\t0x1b2cb6cb,\n\t0x2b2cb6cb,\n\t0x3b2cb6cb,\n\t0x0b6cb6cb,\n\t0x1b6cb6cb,\n\t0x2b6cb6cb,\n\t0x3b6cb6cb,\n\t0x0bacb6cb,\n\t0x1bacb6cb,\n\t0x2bacb6cb,\n\t0x3bacb6cb,\n\t0x0becb6cb,\n\t0x1becb6cb,\n\t0x2becb6cb,\n\t0x3becb6cb,\n\t0x0b2db6cb,\n\t0x1b2db6cb,\n\t0x2b2db6cb,\n\t0x3b2db6cb,\n\t0x0b6db6cb,\n\t0x1b6db6cb,\n\t0x2b6db6cb,\n\t0x3b6db6cb,\n\t0x0badb6cb,\n\t0x1badb6cb,\n\t0x2badb6cb,\n\t0x3badb6cb,\n\t0x0bedb6cb,\n\t0x1bedb6cb,\n\t0x2bedb6cb,\n\t0x3bedb6cb,\n\t0x0b2eb6cb,\n\t0x1b2eb6cb,\n\t0x2b2eb6cb,\n\t0x3b2eb6cb,\n\t0x0b6eb6cb,\n\t0x1b6eb6cb,\n\t0x2b6eb6cb,\n\t0x3b6eb6cb,\n\t0x0baeb6cb,\n\t0x1baeb6cb,\n\t0x2baeb6cb,\n\t0x3baeb6cb,\n\t0x0beeb6cb,\n\t0x1beeb6cb,\n\t0x2beeb6cb,\n\t0x3beeb6cb,\n\t0x0b2fb6cb,\n\t0x1b2fb6cb,\n\t0x2b2fb6cb,\n\t0x3b2fb6cb,\n\t0x0b6fb6cb,\n\t0x1b6fb6cb,\n\t0x2b6fb6cb,\n\t0x3b6fb6cb,\n\t0x0bafb6cb,\n\t0x1bafb6cb,\n\t0x2bafb6cb,\n\t0x3bafb6cb,\n\t0x0befb6cb,\n\t0x1befb6cb,\n\t0x2befb6cb,\n\t0x3befb6cb,\n\t0x0b2cbacb,\n\t0x1b2cbacb,\n\t0x2b2cbacb,\n\t0x3b2cbacb,\n\t0x0b6cbacb,\n\t0x1b6cbacb,\n\t0x2b6cbacb,\n\t0x3b6cbacb,\n\t0x0bacbacb,\n\t0x1bacbacb,\n\t0x2bacbacb,\n\t0x3bacbacb,\n\t0x0becbacb,\n\t0x1becbacb,\n\t0x2becbacb,\n\t0x3becbacb,\n\t0x0b2dbacb,\n\t0x1b2dbacb,\n\t0x2b2dbacb,\n\t0x3b2dbacb,\n\t0x0b6dbacb,\n\t0x1b6dbacb,\n\t0x2b6dbacb,\n\t0x3b6dbacb,\n\t0x0badbacb,\n\t0x1badbacb,\n\t0x2badbacb,\n\t0x3badbacb,\n\t0x0bedbacb,\n\t0x1bedbacb,\n\t0x2bedbacb,\n\t0x3bedbacb,\n\t0x0b2ebacb,\n\t0x1b2ebacb,\n\t0x2b2ebacb,\n\t0x3b2ebacb,\n\t0x0b6ebacb,\n\t0x1b6ebacb,\n\t0x2b6ebacb,\n\t0x3b6ebacb,\n\t0x0baebacb,\n\t0x1baebacb,\n\t0x2baebacb,\n\t0x3baebacb,\n\t0x0beebacb,\n\t0x1beebacb,\n\t0x2beebacb,\n\t0x3beebacb,\n\t0x0b2fbacb,\n\t0x1b2fbacb,\n\t0x2b2fbacb,\n\t0x3b2fbacb,\n\t0x0b6fbacb,\n\t0x1b6fbacb,\n\t0x2b6fbacb,\n\t0x3b6fbacb,\n\t0x0bafbacb,\n\t0x1bafbacb,\n\t0x2bafbacb,\n\t0x3bafbacb,\n\t0x0befbacb,\n\t0x1befbacb,\n\t0x2befbacb,\n\t0x3befbacb,\n\t0x0b2cbecb,\n\t0x1b2cbecb,\n\t0x2b2cbecb,\n\t0x3b2cbecb,\n\t0x0b6cbecb,\n\t0x1b6cbecb,\n\t0x2b6cbecb,\n\t0x3b6cbecb,\n\t0x0bacbecb,\n\t0x1bacbecb,\n\t0x2bacbecb,\n\t0x3bacbecb,\n\t0x0becbecb,\n\t0x1becbecb,\n\t0x2becbecb,\n\t0x3becbecb,\n\t0x0b2dbecb,\n\t0x1b2dbecb,\n\t0x2b2dbecb,\n\t0x3b2dbecb,\n\t0x0b6dbecb,\n\t0x1b6dbecb,\n\t0x2b6dbecb,\n\t0x3b6dbecb,\n\t0x0badbecb,\n\t0x1badbecb,\n\t0x2badbecb,\n\t0x3badbecb,\n\t0x0bedbecb,\n\t0x1bedbecb,\n\t0x2bedbecb,\n\t0x3bedbecb,\n\t0x0b2ebecb,\n\t0x1b2ebecb,\n\t0x2b2ebecb,\n\t0x3b2ebecb,\n\t0x0b6ebecb,\n\t0x1b6ebecb,\n\t0x2b6ebecb,\n\t0x3b6ebecb,\n\t0x0baebecb,\n\t0x1baebecb,\n\t0x2baebecb,\n\t0x3baebecb,\n\t0x0beebecb,\n\t0x1beebecb,\n\t0x2beebecb,\n\t0x3beebecb,\n\t0x0b2fbecb,\n\t0x1b2fbecb,\n\t0x2b2fbecb,\n\t0x3b2fbecb,\n\t0x0b6fbecb,\n\t0x1b6fbecb,\n\t0x2b6fbecb,\n\t0x3b6fbecb,\n\t0x0bafbecb,\n\t0x1bafbecb,\n\t0x2bafbecb,\n\t0x3bafbecb,\n\t0x0befbecb,\n\t0x1befbecb,\n\t0x2befbecb,\n\t0x3befbecb,\n\t0x0b2cb2db,\n\t0x1b2cb2db,\n\t0x2b2cb2db,\n\t0x3b2cb2db,\n\t0x0b6cb2db,\n\t0x1b6cb2db,\n\t0x2b6cb2db,\n\t0x3b6cb2db,\n\t0x0bacb2db,\n\t0x1bacb2db,\n\t0x2bacb2db,\n\t0x3bacb2db,\n\t0x0becb2db,\n\t0x1becb2db,\n\t0x2becb2db,\n\t0x3becb2db,\n\t0x0b2db2db,\n\t0x1b2db2db,\n\t0x2b2db2db,\n\t0x3b2db2db,\n\t0x0b6db2db,\n\t0x1b6db2db,\n\t0x2b6db2db,\n\t0x3b6db2db,\n\t0x0badb2db,\n\t0x1badb2db,\n\t0x2badb2db,\n\t0x3badb2db,\n\t0x0bedb2db,\n\t0x1bedb2db,\n\t0x2bedb2db,\n\t0x3bedb2db,\n\t0x0b2eb2db,\n\t0x1b2eb2db,\n\t0x2b2eb2db,\n\t0x3b2eb2db,\n\t0x0b6eb2db,\n\t0x1b6eb2db,\n\t0x2b6eb2db,\n\t0x3b6eb2db,\n\t0x0baeb2db,\n\t0x1baeb2db,\n\t0x2baeb2db,\n\t0x3baeb2db,\n\t0x0beeb2db,\n\t0x1beeb2db,\n\t0x2beeb2db,\n\t0x3beeb2db,\n\t0x0b2fb2db,\n\t0x1b2fb2db,\n\t0x2b2fb2db,\n\t0x3b2fb2db,\n\t0x0b6fb2db,\n\t0x1b6fb2db,\n\t0x2b6fb2db,\n\t0x3b6fb2db,\n\t0x0bafb2db,\n\t0x1bafb2db,\n\t0x2bafb2db,\n\t0x3bafb2db,\n\t0x0befb2db,\n\t0x1befb2db,\n\t0x2befb2db,\n\t0x3befb2db,\n\t0x0b2cb6db,\n\t0x1b2cb6db,\n\t0x2b2cb6db,\n\t0x3b2cb6db,\n\t0x0b6cb6db,\n\t0x1b6cb6db,\n\t0x2b6cb6db,\n\t0x3b6cb6db,\n\t0x0bacb6db,\n\t0x1bacb6db,\n\t0x2bacb6db,\n\t0x3bacb6db,\n\t0x0becb6db,\n\t0x1becb6db,\n\t0x2becb6db,\n\t0x3becb6db,\n\t0x0b2db6db,\n\t0x1b2db6db,\n\t0x2b2db6db,\n\t0x3b2db6db,\n\t0x0b6db6db,\n\t0x1b6db6db,\n\t0x2b6db6db,\n\t0x3b6db6db,\n\t0x0badb6db,\n\t0x1badb6db,\n\t0x2badb6db,\n\t0x3badb6db,\n\t0x0bedb6db,\n\t0x1bedb6db,\n\t0x2bedb6db,\n\t0x3bedb6db,\n\t0x0b2eb6db,\n\t0x1b2eb6db,\n\t0x2b2eb6db,\n\t0x3b2eb6db,\n\t0x0b6eb6db,\n\t0x1b6eb6db,\n\t0x2b6eb6db,\n\t0x3b6eb6db,\n\t0x0baeb6db,\n\t0x1baeb6db,\n\t0x2baeb6db,\n\t0x3baeb6db,\n}\n\nvar kNonZeroRepsDepth = [numCommandSymbols]uint32{\n\t6,\n\t6,\n\t6,\n\t6,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t12,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t18,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t24,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n\t30,\n}\n\nvar kStaticCommandCodeBits = [numCommandSymbols]uint16{\n\t0,\n\t256,\n\t128,\n\t384,\n\t64,\n\t320,\n\t192,\n\t448,\n\t32,\n\t288,\n\t160,\n\t416,\n\t96,\n\t352,\n\t224,\n\t480,\n\t16,\n\t272,\n\t144,\n\t400,\n\t80,\n\t336,\n\t208,\n\t464,\n\t48,\n\t304,\n\t176,\n\t432,\n\t112,\n\t368,\n\t240,\n\t496,\n\t8,\n\t264,\n\t136,\n\t392,\n\t72,\n\t328,\n\t200,\n\t456,\n\t40,\n\t296,\n\t168,\n\t424,\n\t104,\n\t360,\n\t232,\n\t488,\n\t24,\n\t280,\n\t152,\n\t408,\n\t88,\n\t344,\n\t216,\n\t472,\n\t56,\n\t312,\n\t184,\n\t440,\n\t120,\n\t376,\n\t248,\n\t504,\n\t4,\n\t260,\n\t132,\n\t388,\n\t68,\n\t324,\n\t196,\n\t452,\n\t36,\n\t292,\n\t164,\n\t420,\n\t100,\n\t356,\n\t228,\n\t484,\n\t20,\n\t276,\n\t148,\n\t404,\n\t84,\n\t340,\n\t212,\n\t468,\n\t52,\n\t308,\n\t180,\n\t436,\n\t116,\n\t372,\n\t244,\n\t500,\n\t12,\n\t268,\n\t140,\n\t396,\n\t76,\n\t332,\n\t204,\n\t460,\n\t44,\n\t300,\n\t172,\n\t428,\n\t108,\n\t364,\n\t236,\n\t492,\n\t28,\n\t284,\n\t156,\n\t412,\n\t92,\n\t348,\n\t220,\n\t476,\n\t60,\n\t316,\n\t188,\n\t444,\n\t124,\n\t380,\n\t252,\n\t508,\n\t2,\n\t258,\n\t130,\n\t386,\n\t66,\n\t322,\n\t194,\n\t450,\n\t34,\n\t290,\n\t162,\n\t418,\n\t98,\n\t354,\n\t226,\n\t482,\n\t18,\n\t274,\n\t146,\n\t402,\n\t82,\n\t338,\n\t210,\n\t466,\n\t50,\n\t306,\n\t178,\n\t434,\n\t114,\n\t370,\n\t242,\n\t498,\n\t10,\n\t266,\n\t138,\n\t394,\n\t74,\n\t330,\n\t202,\n\t458,\n\t42,\n\t298,\n\t170,\n\t426,\n\t106,\n\t362,\n\t234,\n\t490,\n\t26,\n\t282,\n\t154,\n\t410,\n\t90,\n\t346,\n\t218,\n\t474,\n\t58,\n\t314,\n\t186,\n\t442,\n\t122,\n\t378,\n\t250,\n\t506,\n\t6,\n\t262,\n\t134,\n\t390,\n\t70,\n\t326,\n\t198,\n\t454,\n\t38,\n\t294,\n\t166,\n\t422,\n\t102,\n\t358,\n\t230,\n\t486,\n\t22,\n\t278,\n\t150,\n\t406,\n\t86,\n\t342,\n\t214,\n\t470,\n\t54,\n\t310,\n\t182,\n\t438,\n\t118,\n\t374,\n\t246,\n\t502,\n\t14,\n\t270,\n\t142,\n\t398,\n\t78,\n\t334,\n\t206,\n\t462,\n\t46,\n\t302,\n\t174,\n\t430,\n\t110,\n\t366,\n\t238,\n\t494,\n\t30,\n\t286,\n\t158,\n\t414,\n\t94,\n\t350,\n\t222,\n\t478,\n\t62,\n\t318,\n\t190,\n\t446,\n\t126,\n\t382,\n\t254,\n\t510,\n\t1,\n\t257,\n\t129,\n\t385,\n\t65,\n\t321,\n\t193,\n\t449,\n\t33,\n\t289,\n\t161,\n\t417,\n\t97,\n\t353,\n\t225,\n\t481,\n\t17,\n\t273,\n\t145,\n\t401,\n\t81,\n\t337,\n\t209,\n\t465,\n\t49,\n\t305,\n\t177,\n\t433,\n\t113,\n\t369,\n\t241,\n\t497,\n\t9,\n\t265,\n\t137,\n\t393,\n\t73,\n\t329,\n\t201,\n\t457,\n\t41,\n\t297,\n\t169,\n\t425,\n\t105,\n\t361,\n\t233,\n\t489,\n\t25,\n\t281,\n\t153,\n\t409,\n\t89,\n\t345,\n\t217,\n\t473,\n\t57,\n\t313,\n\t185,\n\t441,\n\t121,\n\t377,\n\t249,\n\t505,\n\t5,\n\t261,\n\t133,\n\t389,\n\t69,\n\t325,\n\t197,\n\t453,\n\t37,\n\t293,\n\t165,\n\t421,\n\t101,\n\t357,\n\t229,\n\t485,\n\t21,\n\t277,\n\t149,\n\t405,\n\t85,\n\t341,\n\t213,\n\t469,\n\t53,\n\t309,\n\t181,\n\t437,\n\t117,\n\t373,\n\t245,\n\t501,\n\t13,\n\t269,\n\t141,\n\t397,\n\t77,\n\t333,\n\t205,\n\t461,\n\t45,\n\t301,\n\t173,\n\t429,\n\t109,\n\t365,\n\t237,\n\t493,\n\t29,\n\t285,\n\t157,\n\t413,\n\t93,\n\t349,\n\t221,\n\t477,\n\t61,\n\t317,\n\t189,\n\t445,\n\t125,\n\t381,\n\t253,\n\t509,\n\t3,\n\t259,\n\t131,\n\t387,\n\t67,\n\t323,\n\t195,\n\t451,\n\t35,\n\t291,\n\t163,\n\t419,\n\t99,\n\t355,\n\t227,\n\t483,\n\t19,\n\t275,\n\t147,\n\t403,\n\t83,\n\t339,\n\t211,\n\t467,\n\t51,\n\t307,\n\t179,\n\t435,\n\t115,\n\t371,\n\t243,\n\t499,\n\t11,\n\t267,\n\t139,\n\t395,\n\t75,\n\t331,\n\t203,\n\t459,\n\t43,\n\t299,\n\t171,\n\t427,\n\t107,\n\t363,\n\t235,\n\t491,\n\t27,\n\t283,\n\t155,\n\t411,\n\t91,\n\t347,\n\t219,\n\t475,\n\t59,\n\t315,\n\t187,\n\t443,\n\t123,\n\t379,\n\t251,\n\t507,\n\t7,\n\t1031,\n\t519,\n\t1543,\n\t263,\n\t1287,\n\t775,\n\t1799,\n\t135,\n\t1159,\n\t647,\n\t1671,\n\t391,\n\t1415,\n\t903,\n\t1927,\n\t71,\n\t1095,\n\t583,\n\t1607,\n\t327,\n\t1351,\n\t839,\n\t1863,\n\t199,\n\t1223,\n\t711,\n\t1735,\n\t455,\n\t1479,\n\t967,\n\t1991,\n\t39,\n\t1063,\n\t551,\n\t1575,\n\t295,\n\t1319,\n\t807,\n\t1831,\n\t167,\n\t1191,\n\t679,\n\t1703,\n\t423,\n\t1447,\n\t935,\n\t1959,\n\t103,\n\t1127,\n\t615,\n\t1639,\n\t359,\n\t1383,\n\t871,\n\t1895,\n\t231,\n\t1255,\n\t743,\n\t1767,\n\t487,\n\t1511,\n\t999,\n\t2023,\n\t23,\n\t1047,\n\t535,\n\t1559,\n\t279,\n\t1303,\n\t791,\n\t1815,\n\t151,\n\t1175,\n\t663,\n\t1687,\n\t407,\n\t1431,\n\t919,\n\t1943,\n\t87,\n\t1111,\n\t599,\n\t1623,\n\t343,\n\t1367,\n\t855,\n\t1879,\n\t215,\n\t1239,\n\t727,\n\t1751,\n\t471,\n\t1495,\n\t983,\n\t2007,\n\t55,\n\t1079,\n\t567,\n\t1591,\n\t311,\n\t1335,\n\t823,\n\t1847,\n\t183,\n\t1207,\n\t695,\n\t1719,\n\t439,\n\t1463,\n\t951,\n\t1975,\n\t119,\n\t1143,\n\t631,\n\t1655,\n\t375,\n\t1399,\n\t887,\n\t1911,\n\t247,\n\t1271,\n\t759,\n\t1783,\n\t503,\n\t1527,\n\t1015,\n\t2039,\n\t15,\n\t1039,\n\t527,\n\t1551,\n\t271,\n\t1295,\n\t783,\n\t1807,\n\t143,\n\t1167,\n\t655,\n\t1679,\n\t399,\n\t1423,\n\t911,\n\t1935,\n\t79,\n\t1103,\n\t591,\n\t1615,\n\t335,\n\t1359,\n\t847,\n\t1871,\n\t207,\n\t1231,\n\t719,\n\t1743,\n\t463,\n\t1487,\n\t975,\n\t1999,\n\t47,\n\t1071,\n\t559,\n\t1583,\n\t303,\n\t1327,\n\t815,\n\t1839,\n\t175,\n\t1199,\n\t687,\n\t1711,\n\t431,\n\t1455,\n\t943,\n\t1967,\n\t111,\n\t1135,\n\t623,\n\t1647,\n\t367,\n\t1391,\n\t879,\n\t1903,\n\t239,\n\t1263,\n\t751,\n\t1775,\n\t495,\n\t1519,\n\t1007,\n\t2031,\n\t31,\n\t1055,\n\t543,\n\t1567,\n\t287,\n\t1311,\n\t799,\n\t1823,\n\t159,\n\t1183,\n\t671,\n\t1695,\n\t415,\n\t1439,\n\t927,\n\t1951,\n\t95,\n\t1119,\n\t607,\n\t1631,\n\t351,\n\t1375,\n\t863,\n\t1887,\n\t223,\n\t1247,\n\t735,\n\t1759,\n\t479,\n\t1503,\n\t991,\n\t2015,\n\t63,\n\t1087,\n\t575,\n\t1599,\n\t319,\n\t1343,\n\t831,\n\t1855,\n\t191,\n\t1215,\n\t703,\n\t1727,\n\t447,\n\t1471,\n\t959,\n\t1983,\n\t127,\n\t1151,\n\t639,\n\t1663,\n\t383,\n\t1407,\n\t895,\n\t1919,\n\t255,\n\t1279,\n\t767,\n\t1791,\n\t511,\n\t1535,\n\t1023,\n\t2047,\n}\n\nfunc storeStaticCommandHuffmanTree(storage_ix *uint, storage []byte) {\n\twriteBits(56, 0x92624416307003, storage_ix, storage)\n\twriteBits(3, 0x00000000, storage_ix, storage)\n}\n\nvar kStaticDistanceCodeBits = [64]uint16{\n\t0,\n\t32,\n\t16,\n\t48,\n\t8,\n\t40,\n\t24,\n\t56,\n\t4,\n\t36,\n\t20,\n\t52,\n\t12,\n\t44,\n\t28,\n\t60,\n\t2,\n\t34,\n\t18,\n\t50,\n\t10,\n\t42,\n\t26,\n\t58,\n\t6,\n\t38,\n\t22,\n\t54,\n\t14,\n\t46,\n\t30,\n\t62,\n\t1,\n\t33,\n\t17,\n\t49,\n\t9,\n\t41,\n\t25,\n\t57,\n\t5,\n\t37,\n\t21,\n\t53,\n\t13,\n\t45,\n\t29,\n\t61,\n\t3,\n\t35,\n\t19,\n\t51,\n\t11,\n\t43,\n\t27,\n\t59,\n\t7,\n\t39,\n\t23,\n\t55,\n\t15,\n\t47,\n\t31,\n\t63,\n}\n\nfunc storeStaticDistanceHuffmanTree(storage_ix *uint, storage []byte) {\n\twriteBits(28, 0x0369DC03, storage_ix, storage)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/fast_log.go",
    "content": "package brotli\n\nimport (\n\t\"math\"\n\t\"math/bits\"\n)\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Utilities for fast computation of logarithms. */\n\nfunc log2FloorNonZero(n uint) uint32 {\n\treturn uint32(bits.Len(n)) - 1\n}\n\n/* A lookup table for small values of log2(int) to be used in entropy\n   computation.\n\n   \", \".join([\"%.16ff\" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */\nvar kLog2Table = []float32{\n\t0.0000000000000000,\n\t0.0000000000000000,\n\t1.0000000000000000,\n\t1.5849625007211563,\n\t2.0000000000000000,\n\t2.3219280948873622,\n\t2.5849625007211561,\n\t2.8073549220576042,\n\t3.0000000000000000,\n\t3.1699250014423126,\n\t3.3219280948873626,\n\t3.4594316186372978,\n\t3.5849625007211565,\n\t3.7004397181410922,\n\t3.8073549220576037,\n\t3.9068905956085187,\n\t4.0000000000000000,\n\t4.0874628412503400,\n\t4.1699250014423122,\n\t4.2479275134435852,\n\t4.3219280948873626,\n\t4.3923174227787607,\n\t4.4594316186372973,\n\t4.5235619560570131,\n\t4.5849625007211570,\n\t4.6438561897747244,\n\t4.7004397181410926,\n\t4.7548875021634691,\n\t4.8073549220576037,\n\t4.8579809951275728,\n\t4.9068905956085187,\n\t4.9541963103868758,\n\t5.0000000000000000,\n\t5.0443941193584534,\n\t5.0874628412503400,\n\t5.1292830169449664,\n\t5.1699250014423122,\n\t5.2094533656289501,\n\t5.2479275134435852,\n\t5.2854022188622487,\n\t5.3219280948873626,\n\t5.3575520046180838,\n\t5.3923174227787607,\n\t5.4262647547020979,\n\t5.4594316186372973,\n\t5.4918530963296748,\n\t5.5235619560570131,\n\t5.5545888516776376,\n\t5.5849625007211570,\n\t5.6147098441152083,\n\t5.6438561897747244,\n\t5.6724253419714961,\n\t5.7004397181410926,\n\t5.7279204545631996,\n\t5.7548875021634691,\n\t5.7813597135246599,\n\t5.8073549220576046,\n\t5.8328900141647422,\n\t5.8579809951275719,\n\t5.8826430493618416,\n\t5.9068905956085187,\n\t5.9307373375628867,\n\t5.9541963103868758,\n\t5.9772799234999168,\n\t6.0000000000000000,\n\t6.0223678130284544,\n\t6.0443941193584534,\n\t6.0660891904577721,\n\t6.0874628412503400,\n\t6.1085244567781700,\n\t6.1292830169449672,\n\t6.1497471195046822,\n\t6.1699250014423122,\n\t6.1898245588800176,\n\t6.2094533656289510,\n\t6.2288186904958804,\n\t6.2479275134435861,\n\t6.2667865406949019,\n\t6.2854022188622487,\n\t6.3037807481771031,\n\t6.3219280948873617,\n\t6.3398500028846252,\n\t6.3575520046180847,\n\t6.3750394313469254,\n\t6.3923174227787598,\n\t6.4093909361377026,\n\t6.4262647547020979,\n\t6.4429434958487288,\n\t6.4594316186372982,\n\t6.4757334309663976,\n\t6.4918530963296748,\n\t6.5077946401986964,\n\t6.5235619560570131,\n\t6.5391588111080319,\n\t6.5545888516776376,\n\t6.5698556083309478,\n\t6.5849625007211561,\n\t6.5999128421871278,\n\t6.6147098441152092,\n\t6.6293566200796095,\n\t6.6438561897747253,\n\t6.6582114827517955,\n\t6.6724253419714952,\n\t6.6865005271832185,\n\t6.7004397181410917,\n\t6.7142455176661224,\n\t6.7279204545631988,\n\t6.7414669864011465,\n\t6.7548875021634691,\n\t6.7681843247769260,\n\t6.7813597135246599,\n\t6.7944158663501062,\n\t6.8073549220576037,\n\t6.8201789624151887,\n\t6.8328900141647422,\n\t6.8454900509443757,\n\t6.8579809951275719,\n\t6.8703647195834048,\n\t6.8826430493618416,\n\t6.8948177633079437,\n\t6.9068905956085187,\n\t6.9188632372745955,\n\t6.9307373375628867,\n\t6.9425145053392399,\n\t6.9541963103868758,\n\t6.9657842846620879,\n\t6.9772799234999168,\n\t6.9886846867721664,\n\t7.0000000000000000,\n\t7.0112272554232540,\n\t7.0223678130284544,\n\t7.0334230015374501,\n\t7.0443941193584534,\n\t7.0552824355011898,\n\t7.0660891904577721,\n\t7.0768155970508317,\n\t7.0874628412503400,\n\t7.0980320829605272,\n\t7.1085244567781700,\n\t7.1189410727235076,\n\t7.1292830169449664,\n\t7.1395513523987937,\n\t7.1497471195046822,\n\t7.1598713367783891,\n\t7.1699250014423130,\n\t7.1799090900149345,\n\t7.1898245588800176,\n\t7.1996723448363644,\n\t7.2094533656289492,\n\t7.2191685204621621,\n\t7.2288186904958804,\n\t7.2384047393250794,\n\t7.2479275134435861,\n\t7.2573878426926521,\n\t7.2667865406949019,\n\t7.2761244052742384,\n\t7.2854022188622487,\n\t7.2946207488916270,\n\t7.3037807481771031,\n\t7.3128829552843557,\n\t7.3219280948873617,\n\t7.3309168781146177,\n\t7.3398500028846243,\n\t7.3487281542310781,\n\t7.3575520046180847,\n\t7.3663222142458151,\n\t7.3750394313469254,\n\t7.3837042924740528,\n\t7.3923174227787607,\n\t7.4008794362821844,\n\t7.4093909361377026,\n\t7.4178525148858991,\n\t7.4262647547020979,\n\t7.4346282276367255,\n\t7.4429434958487288,\n\t7.4512111118323299,\n\t7.4594316186372973,\n\t7.4676055500829976,\n\t7.4757334309663976,\n\t7.4838157772642564,\n\t7.4918530963296748,\n\t7.4998458870832057,\n\t7.5077946401986964,\n\t7.5156998382840436,\n\t7.5235619560570131,\n\t7.5313814605163119,\n\t7.5391588111080319,\n\t7.5468944598876373,\n\t7.5545888516776376,\n\t7.5622424242210728,\n\t7.5698556083309478,\n\t7.5774288280357487,\n\t7.5849625007211561,\n\t7.5924570372680806,\n\t7.5999128421871278,\n\t7.6073303137496113,\n\t7.6147098441152075,\n\t7.6220518194563764,\n\t7.6293566200796095,\n\t7.6366246205436488,\n\t7.6438561897747244,\n\t7.6510516911789290,\n\t7.6582114827517955,\n\t7.6653359171851765,\n\t7.6724253419714952,\n\t7.6794800995054464,\n\t7.6865005271832185,\n\t7.6934869574993252,\n\t7.7004397181410926,\n\t7.7073591320808825,\n\t7.7142455176661224,\n\t7.7210991887071856,\n\t7.7279204545631996,\n\t7.7347096202258392,\n\t7.7414669864011465,\n\t7.7481928495894596,\n\t7.7548875021634691,\n\t7.7615512324444795,\n\t7.7681843247769260,\n\t7.7747870596011737,\n\t7.7813597135246608,\n\t7.7879025593914317,\n\t7.7944158663501062,\n\t7.8008998999203047,\n\t7.8073549220576037,\n\t7.8137811912170374,\n\t7.8201789624151887,\n\t7.8265484872909159,\n\t7.8328900141647422,\n\t7.8392037880969445,\n\t7.8454900509443757,\n\t7.8517490414160571,\n\t7.8579809951275719,\n\t7.8641861446542798,\n\t7.8703647195834048,\n\t7.8765169465650002,\n\t7.8826430493618425,\n\t7.8887432488982601,\n\t7.8948177633079446,\n\t7.9008668079807496,\n\t7.9068905956085187,\n\t7.9128893362299619,\n\t7.9188632372745955,\n\t7.9248125036057813,\n\t7.9307373375628867,\n\t7.9366379390025719,\n\t7.9425145053392399,\n\t7.9483672315846778,\n\t7.9541963103868758,\n\t7.9600019320680806,\n\t7.9657842846620870,\n\t7.9715435539507720,\n\t7.9772799234999168,\n\t7.9829935746943104,\n\t7.9886846867721664,\n\t7.9943534368588578,\n}\n\n/* Faster logarithm for small integers, with the property of log2(0) == 0. */\nfunc fastLog2(v uint) float64 {\n\tif v < uint(len(kLog2Table)) {\n\t\treturn float64(kLog2Table[v])\n\t}\n\n\treturn math.Log2(float64(v))\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/find_match_length.go",
    "content": "package brotli\n\nimport (\n\t\"encoding/binary\"\n\t\"math/bits\"\n\t\"runtime\"\n)\n\n/* Copyright 2010 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Function to find maximal matching prefixes of strings. */\nfunc findMatchLengthWithLimit(s1 []byte, s2 []byte, limit uint) uint {\n\tvar matched uint = 0\n\t_, _ = s1[limit-1], s2[limit-1] // bounds check\n\tswitch runtime.GOARCH {\n\tcase \"amd64\", \"arm64\":\n\t\t// Compare 8 bytes at at time.\n\t\tfor matched+8 <= limit {\n\t\t\tw1 := binary.LittleEndian.Uint64(s1[matched:])\n\t\t\tw2 := binary.LittleEndian.Uint64(s2[matched:])\n\t\t\tif w1 != w2 {\n\t\t\t\treturn matched + uint(bits.TrailingZeros64(w1^w2)>>3)\n\t\t\t}\n\t\t\tmatched += 8\n\t\t}\n\tcase \"386\":\n\t\t// Compare 4 bytes at at time.\n\t\tfor matched+4 <= limit {\n\t\t\tw1 := binary.LittleEndian.Uint32(s1[matched:])\n\t\t\tw2 := binary.LittleEndian.Uint32(s2[matched:])\n\t\t\tif w1 != w2 {\n\t\t\t\treturn matched + uint(bits.TrailingZeros32(w1^w2)>>3)\n\t\t\t}\n\t\t\tmatched += 4\n\t\t}\n\t}\n\tfor matched < limit && s1[matched] == s2[matched] {\n\t\tmatched++\n\t}\n\treturn matched\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/h10.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2016 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nfunc (*h10) HashTypeLength() uint {\n\treturn 4\n}\n\nfunc (*h10) StoreLookahead() uint {\n\treturn 128\n}\n\nfunc hashBytesH10(data []byte) uint32 {\n\tvar h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32\n\n\t/* The higher bits contain more mixture from the multiplication,\n\t   so we take our results from there. */\n\treturn h >> (32 - 17)\n}\n\n/* A (forgetful) hash table where each hash bucket contains a binary tree of\n   sequences whose first 4 bytes share the same hash code.\n   Each sequence is 128 long and is identified by its starting\n   position in the input data. The binary tree is sorted by the lexicographic\n   order of the sequences, and it is also a max-heap with respect to the\n   starting positions. */\ntype h10 struct {\n\thasherCommon\n\twindow_mask_ uint\n\tbuckets_     [1 << 17]uint32\n\tinvalid_pos_ uint32\n\tforest       []uint32\n}\n\nfunc (h *h10) Initialize(params *encoderParams) {\n\th.window_mask_ = (1 << params.lgwin) - 1\n\th.invalid_pos_ = uint32(0 - h.window_mask_)\n\tvar num_nodes uint = uint(1) << params.lgwin\n\th.forest = make([]uint32, 2*num_nodes)\n}\n\nfunc (h *h10) Prepare(one_shot bool, input_size uint, data []byte) {\n\tvar invalid_pos uint32 = h.invalid_pos_\n\tvar i uint32\n\tfor i = 0; i < 1<<17; i++ {\n\t\th.buckets_[i] = invalid_pos\n\t}\n}\n\nfunc leftChildIndexH10(self *h10, pos uint) uint {\n\treturn 2 * (pos & self.window_mask_)\n}\n\nfunc rightChildIndexH10(self *h10, pos uint) uint {\n\treturn 2*(pos&self.window_mask_) + 1\n}\n\n/* Stores the hash of the next 4 bytes and in a single tree-traversal, the\n   hash bucket's binary tree is searched for matches and is re-rooted at the\n   current position.\n\n   If less than 128 data is available, the hash bucket of the\n   current position is searched for matches, but the state of the hash table\n   is not changed, since we can not know the final sorting order of the\n   current (incomplete) sequence.\n\n   This function must be called with increasing cur_ix positions. */\nfunc storeAndFindMatchesH10(self *h10, data []byte, cur_ix uint, ring_buffer_mask uint, max_length uint, max_backward uint, best_len *uint, matches []backwardMatch) []backwardMatch {\n\tvar cur_ix_masked uint = cur_ix & ring_buffer_mask\n\tvar max_comp_len uint = brotli_min_size_t(max_length, 128)\n\tvar should_reroot_tree bool = (max_length >= 128)\n\tvar key uint32 = hashBytesH10(data[cur_ix_masked:])\n\tvar forest []uint32 = self.forest\n\tvar prev_ix uint = uint(self.buckets_[key])\n\tvar node_left uint = leftChildIndexH10(self, cur_ix)\n\tvar node_right uint = rightChildIndexH10(self, cur_ix)\n\tvar best_len_left uint = 0\n\tvar best_len_right uint = 0\n\tvar depth_remaining uint\n\t/* The forest index of the rightmost node of the left subtree of the new\n\t   root, updated as we traverse and re-root the tree of the hash bucket. */\n\n\t/* The forest index of the leftmost node of the right subtree of the new\n\t   root, updated as we traverse and re-root the tree of the hash bucket. */\n\n\t/* The match length of the rightmost node of the left subtree of the new\n\t   root, updated as we traverse and re-root the tree of the hash bucket. */\n\n\t/* The match length of the leftmost node of the right subtree of the new\n\t   root, updated as we traverse and re-root the tree of the hash bucket. */\n\tif should_reroot_tree {\n\t\tself.buckets_[key] = uint32(cur_ix)\n\t}\n\n\tfor depth_remaining = 64; ; depth_remaining-- {\n\t\tvar backward uint = cur_ix - prev_ix\n\t\tvar prev_ix_masked uint = prev_ix & ring_buffer_mask\n\t\tif backward == 0 || backward > max_backward || depth_remaining == 0 {\n\t\t\tif should_reroot_tree {\n\t\t\t\tforest[node_left] = self.invalid_pos_\n\t\t\t\tforest[node_right] = self.invalid_pos_\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t\t{\n\t\t\tvar cur_len uint = brotli_min_size_t(best_len_left, best_len_right)\n\t\t\tvar len uint\n\t\t\tassert(cur_len <= 128)\n\t\t\tlen = cur_len + findMatchLengthWithLimit(data[cur_ix_masked+cur_len:], data[prev_ix_masked+cur_len:], max_length-cur_len)\n\t\t\tif matches != nil && len > *best_len {\n\t\t\t\t*best_len = uint(len)\n\t\t\t\tinitBackwardMatch(&matches[0], backward, uint(len))\n\t\t\t\tmatches = matches[1:]\n\t\t\t}\n\n\t\t\tif len >= max_comp_len {\n\t\t\t\tif should_reroot_tree {\n\t\t\t\t\tforest[node_left] = forest[leftChildIndexH10(self, prev_ix)]\n\t\t\t\t\tforest[node_right] = forest[rightChildIndexH10(self, prev_ix)]\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif data[cur_ix_masked+len] > data[prev_ix_masked+len] {\n\t\t\t\tbest_len_left = uint(len)\n\t\t\t\tif should_reroot_tree {\n\t\t\t\t\tforest[node_left] = uint32(prev_ix)\n\t\t\t\t}\n\n\t\t\t\tnode_left = rightChildIndexH10(self, prev_ix)\n\t\t\t\tprev_ix = uint(forest[node_left])\n\t\t\t} else {\n\t\t\t\tbest_len_right = uint(len)\n\t\t\t\tif should_reroot_tree {\n\t\t\t\t\tforest[node_right] = uint32(prev_ix)\n\t\t\t\t}\n\n\t\t\t\tnode_right = leftChildIndexH10(self, prev_ix)\n\t\t\t\tprev_ix = uint(forest[node_right])\n\t\t\t}\n\t\t}\n\t}\n\n\treturn matches\n}\n\n/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the\n   length of max_length and stores the position cur_ix in the hash table.\n\n   Sets *num_matches to the number of matches found, and stores the found\n   matches in matches[0] to matches[*num_matches - 1]. The matches will be\n   sorted by strictly increasing length and (non-strictly) increasing\n   distance. */\nfunc findAllMatchesH10(handle *h10, dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, cur_ix uint, max_length uint, max_backward uint, gap uint, params *encoderParams, matches []backwardMatch) uint {\n\tvar orig_matches []backwardMatch = matches\n\tvar cur_ix_masked uint = cur_ix & ring_buffer_mask\n\tvar best_len uint = 1\n\tvar short_match_max_backward uint\n\tif params.quality != hqZopflificationQuality {\n\t\tshort_match_max_backward = 16\n\t} else {\n\t\tshort_match_max_backward = 64\n\t}\n\tvar stop uint = cur_ix - short_match_max_backward\n\tvar dict_matches [maxStaticDictionaryMatchLen + 1]uint32\n\tvar i uint\n\tif cur_ix < short_match_max_backward {\n\t\tstop = 0\n\t}\n\tfor i = cur_ix - 1; i > stop && best_len <= 2; i-- {\n\t\tvar prev_ix uint = i\n\t\tvar backward uint = cur_ix - prev_ix\n\t\tif backward > max_backward {\n\t\t\tbreak\n\t\t}\n\n\t\tprev_ix &= ring_buffer_mask\n\t\tif data[cur_ix_masked] != data[prev_ix] || data[cur_ix_masked+1] != data[prev_ix+1] {\n\t\t\tcontinue\n\t\t}\n\t\t{\n\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\tif len > best_len {\n\t\t\t\tbest_len = uint(len)\n\t\t\t\tinitBackwardMatch(&matches[0], backward, uint(len))\n\t\t\t\tmatches = matches[1:]\n\t\t\t}\n\t\t}\n\t}\n\n\tif best_len < max_length {\n\t\tmatches = storeAndFindMatchesH10(handle, data, cur_ix, ring_buffer_mask, max_length, max_backward, &best_len, matches)\n\t}\n\n\tfor i = 0; i <= maxStaticDictionaryMatchLen; i++ {\n\t\tdict_matches[i] = kInvalidMatch\n\t}\n\t{\n\t\tvar minlen uint = brotli_max_size_t(4, best_len+1)\n\t\tif findAllStaticDictionaryMatches(dictionary, data[cur_ix_masked:], minlen, max_length, dict_matches[0:]) {\n\t\t\tvar maxlen uint = brotli_min_size_t(maxStaticDictionaryMatchLen, max_length)\n\t\t\tvar l uint\n\t\t\tfor l = minlen; l <= maxlen; l++ {\n\t\t\t\tvar dict_id uint32 = dict_matches[l]\n\t\t\t\tif dict_id < kInvalidMatch {\n\t\t\t\t\tvar distance uint = max_backward + gap + uint(dict_id>>5) + 1\n\t\t\t\t\tif distance <= params.dist.max_distance {\n\t\t\t\t\t\tinitDictionaryBackwardMatch(&matches[0], distance, l, uint(dict_id&31))\n\t\t\t\t\t\tmatches = matches[1:]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn uint(-cap(matches) + cap(orig_matches))\n}\n\n/* Stores the hash of the next 4 bytes and re-roots the binary tree at the\n   current sequence, without returning any matches.\n   REQUIRES: ix + 128 <= end-of-current-block */\nfunc (h *h10) Store(data []byte, mask uint, ix uint) {\n\tvar max_backward uint = h.window_mask_ - windowGap + 1\n\t/* Maximum distance is window size - 16, see section 9.1. of the spec. */\n\tstoreAndFindMatchesH10(h, data, ix, mask, 128, max_backward, nil, nil)\n}\n\nfunc (h *h10) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {\n\tvar i uint = ix_start\n\tvar j uint = ix_start\n\tif ix_start+63 <= ix_end {\n\t\ti = ix_end - 63\n\t}\n\n\tif ix_start+512 <= i {\n\t\tfor ; j < i; j += 8 {\n\t\t\th.Store(data, mask, j)\n\t\t}\n\t}\n\n\tfor ; i < ix_end; i++ {\n\t\th.Store(data, mask, i)\n\t}\n}\n\nfunc (h *h10) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {\n\tif num_bytes >= h.HashTypeLength()-1 && position >= 128 {\n\t\tvar i_start uint = position - 128 + 1\n\t\tvar i_end uint = brotli_min_size_t(position, i_start+num_bytes)\n\t\t/* Store the last `128 - 1` positions in the hasher.\n\t\t   These could not be calculated before, since they require knowledge\n\t\t   of both the previous and the current block. */\n\n\t\tvar i uint\n\t\tfor i = i_start; i < i_end; i++ {\n\t\t\t/* Maximum distance is window size - 16, see section 9.1. of the spec.\n\t\t\t   Furthermore, we have to make sure that we don't look further back\n\t\t\t   from the start of the next block than the window size, otherwise we\n\t\t\t   could access already overwritten areas of the ring-buffer. */\n\t\t\tvar max_backward uint = h.window_mask_ - brotli_max_size_t(windowGap-1, position-i)\n\n\t\t\t/* We know that i + 128 <= position + num_bytes, i.e. the\n\t\t\t   end of the current block and that we have at least\n\t\t\t   128 tail in the ring-buffer. */\n\t\t\tstoreAndFindMatchesH10(h, ringbuffer, i, ringbuffer_mask, 128, max_backward, nil, nil)\n\t\t}\n\t}\n}\n\n/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */\nconst maxNumMatchesH10 = 128\n\nfunc (*h10) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {\n\tpanic(\"unimplemented\")\n}\n\nfunc (*h10) PrepareDistanceCache(distance_cache []int) {\n\tpanic(\"unimplemented\")\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/h5.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2010 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* A (forgetful) hash table to the data seen by the compressor, to\n   help create backward references to previous data.\n\n   This is a hash map of fixed size (bucket_size_) to a ring buffer of\n   fixed size (block_size_). The ring buffer contains the last block_size_\n   index positions of the given hash key in the compressed data. */\nfunc (*h5) HashTypeLength() uint {\n\treturn 4\n}\n\nfunc (*h5) StoreLookahead() uint {\n\treturn 4\n}\n\n/* HashBytes is the function that chooses the bucket to place the address in. */\nfunc hashBytesH5(data []byte, shift int) uint32 {\n\tvar h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32\n\n\t/* The higher bits contain more mixture from the multiplication,\n\t   so we take our results from there. */\n\treturn uint32(h >> uint(shift))\n}\n\ntype h5 struct {\n\thasherCommon\n\tbucket_size_ uint\n\tblock_size_  uint\n\thash_shift_  int\n\tblock_mask_  uint32\n\tnum          []uint16\n\tbuckets      []uint32\n}\n\nfunc (h *h5) Initialize(params *encoderParams) {\n\th.hash_shift_ = 32 - h.params.bucket_bits\n\th.bucket_size_ = uint(1) << uint(h.params.bucket_bits)\n\th.block_size_ = uint(1) << uint(h.params.block_bits)\n\th.block_mask_ = uint32(h.block_size_ - 1)\n\th.num = make([]uint16, h.bucket_size_)\n\th.buckets = make([]uint32, h.block_size_*h.bucket_size_)\n}\n\nfunc (h *h5) Prepare(one_shot bool, input_size uint, data []byte) {\n\tvar num []uint16 = h.num\n\tvar partial_prepare_threshold uint = h.bucket_size_ >> 6\n\t/* Partial preparation is 100 times slower (per socket). */\n\tif one_shot && input_size <= partial_prepare_threshold {\n\t\tvar i uint\n\t\tfor i = 0; i < input_size; i++ {\n\t\t\tvar key uint32 = hashBytesH5(data[i:], h.hash_shift_)\n\t\t\tnum[key] = 0\n\t\t}\n\t} else {\n\t\tfor i := 0; i < int(h.bucket_size_); i++ {\n\t\t\tnum[i] = 0\n\t\t}\n\t}\n}\n\n/* Look at 4 bytes at &data[ix & mask].\n   Compute a hash from these, and store the value of ix at that position. */\nfunc (h *h5) Store(data []byte, mask uint, ix uint) {\n\tvar num []uint16 = h.num\n\tvar key uint32 = hashBytesH5(data[ix&mask:], h.hash_shift_)\n\tvar minor_ix uint = uint(num[key]) & uint(h.block_mask_)\n\tvar offset uint = minor_ix + uint(key<<uint(h.params.block_bits))\n\th.buckets[offset] = uint32(ix)\n\tnum[key]++\n}\n\nfunc (h *h5) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {\n\tvar i uint\n\tfor i = ix_start; i < ix_end; i++ {\n\t\th.Store(data, mask, i)\n\t}\n}\n\nfunc (h *h5) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {\n\tif num_bytes >= h.HashTypeLength()-1 && position >= 3 {\n\t\t/* Prepare the hashes for three last bytes of the last write.\n\t\t   These could not be calculated before, since they require knowledge\n\t\t   of both the previous and the current block. */\n\t\th.Store(ringbuffer, ringbuffer_mask, position-3)\n\t\th.Store(ringbuffer, ringbuffer_mask, position-2)\n\t\th.Store(ringbuffer, ringbuffer_mask, position-1)\n\t}\n}\n\nfunc (h *h5) PrepareDistanceCache(distance_cache []int) {\n\tprepareDistanceCache(distance_cache, h.params.num_last_distances_to_check)\n}\n\n/* Find a longest backward match of &data[cur_ix] up to the length of\n   max_length and stores the position cur_ix in the hash table.\n\n   REQUIRES: PrepareDistanceCacheH5 must be invoked for current distance cache\n             values; if this method is invoked repeatedly with the same distance\n             cache values, it is enough to invoke PrepareDistanceCacheH5 once.\n\n   Does not look for matches longer than max_length.\n   Does not look for matches further away than max_backward.\n   Writes the best match into |out|.\n   |out|->score is updated only if a better match is found. */\nfunc (h *h5) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {\n\tvar num []uint16 = h.num\n\tvar buckets []uint32 = h.buckets\n\tvar cur_ix_masked uint = cur_ix & ring_buffer_mask\n\tvar min_score uint = out.score\n\tvar best_score uint = out.score\n\tvar best_len uint = out.len\n\tvar i uint\n\tvar bucket []uint32\n\t/* Don't accept a short copy from far away. */\n\tout.len = 0\n\n\tout.len_code_delta = 0\n\n\t/* Try last distance first. */\n\tfor i = 0; i < uint(h.params.num_last_distances_to_check); i++ {\n\t\tvar backward uint = uint(distance_cache[i])\n\t\tvar prev_ix uint = uint(cur_ix - backward)\n\t\tif prev_ix >= cur_ix {\n\t\t\tcontinue\n\t\t}\n\n\t\tif backward > max_backward {\n\t\t\tcontinue\n\t\t}\n\n\t\tprev_ix &= ring_buffer_mask\n\n\t\tif cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {\n\t\t\tcontinue\n\t\t}\n\t\t{\n\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\tif len >= 3 || (len == 2 && i < 2) {\n\t\t\t\t/* Comparing for >= 2 does not change the semantics, but just saves for\n\t\t\t\t   a few unnecessary binary logarithms in backward reference score,\n\t\t\t\t   since we are not interested in such short matches. */\n\t\t\t\tvar score uint = backwardReferenceScoreUsingLastDistance(uint(len))\n\t\t\t\tif best_score < score {\n\t\t\t\t\tif i != 0 {\n\t\t\t\t\t\tscore -= backwardReferencePenaltyUsingLastDistance(i)\n\t\t\t\t\t}\n\t\t\t\t\tif best_score < score {\n\t\t\t\t\t\tbest_score = score\n\t\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\t\tout.len = best_len\n\t\t\t\t\t\tout.distance = backward\n\t\t\t\t\t\tout.score = best_score\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tvar key uint32 = hashBytesH5(data[cur_ix_masked:], h.hash_shift_)\n\t\tbucket = buckets[key<<uint(h.params.block_bits):]\n\t\tvar down uint\n\t\tif uint(num[key]) > h.block_size_ {\n\t\t\tdown = uint(num[key]) - h.block_size_\n\t\t} else {\n\t\t\tdown = 0\n\t\t}\n\t\tfor i = uint(num[key]); i > down; {\n\t\t\tvar prev_ix uint\n\t\t\ti--\n\t\t\tprev_ix = uint(bucket[uint32(i)&h.block_mask_])\n\t\t\tvar backward uint = cur_ix - prev_ix\n\t\t\tif backward > max_backward {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tprev_ix &= ring_buffer_mask\n\t\t\tif cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t{\n\t\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\t\tif len >= 4 {\n\t\t\t\t\t/* Comparing for >= 3 does not change the semantics, but just saves\n\t\t\t\t\t   for a few unnecessary binary logarithms in backward reference\n\t\t\t\t\t   score, since we are not interested in such short matches. */\n\t\t\t\t\tvar score uint = backwardReferenceScore(uint(len), backward)\n\t\t\t\t\tif best_score < score {\n\t\t\t\t\t\tbest_score = score\n\t\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\t\tout.len = best_len\n\t\t\t\t\t\tout.distance = backward\n\t\t\t\t\t\tout.score = best_score\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbucket[uint32(num[key])&h.block_mask_] = uint32(cur_ix)\n\t\tnum[key]++\n\t}\n\n\tif min_score == out.score {\n\t\tsearchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/h6.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2010 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* A (forgetful) hash table to the data seen by the compressor, to\n   help create backward references to previous data.\n\n   This is a hash map of fixed size (bucket_size_) to a ring buffer of\n   fixed size (block_size_). The ring buffer contains the last block_size_\n   index positions of the given hash key in the compressed data. */\nfunc (*h6) HashTypeLength() uint {\n\treturn 8\n}\n\nfunc (*h6) StoreLookahead() uint {\n\treturn 8\n}\n\n/* HashBytes is the function that chooses the bucket to place the address in. */\nfunc hashBytesH6(data []byte, mask uint64, shift int) uint32 {\n\tvar h uint64 = (binary.LittleEndian.Uint64(data) & mask) * kHashMul64Long\n\n\t/* The higher bits contain more mixture from the multiplication,\n\t   so we take our results from there. */\n\treturn uint32(h >> uint(shift))\n}\n\ntype h6 struct {\n\thasherCommon\n\tbucket_size_ uint\n\tblock_size_  uint\n\thash_shift_  int\n\thash_mask_   uint64\n\tblock_mask_  uint32\n\tnum          []uint16\n\tbuckets      []uint32\n}\n\nfunc (h *h6) Initialize(params *encoderParams) {\n\th.hash_shift_ = 64 - h.params.bucket_bits\n\th.hash_mask_ = (^(uint64(0))) >> uint(64-8*h.params.hash_len)\n\th.bucket_size_ = uint(1) << uint(h.params.bucket_bits)\n\th.block_size_ = uint(1) << uint(h.params.block_bits)\n\th.block_mask_ = uint32(h.block_size_ - 1)\n\th.num = make([]uint16, h.bucket_size_)\n\th.buckets = make([]uint32, h.block_size_*h.bucket_size_)\n}\n\nfunc (h *h6) Prepare(one_shot bool, input_size uint, data []byte) {\n\tvar num []uint16 = h.num\n\tvar partial_prepare_threshold uint = h.bucket_size_ >> 6\n\t/* Partial preparation is 100 times slower (per socket). */\n\tif one_shot && input_size <= partial_prepare_threshold {\n\t\tvar i uint\n\t\tfor i = 0; i < input_size; i++ {\n\t\t\tvar key uint32 = hashBytesH6(data[i:], h.hash_mask_, h.hash_shift_)\n\t\t\tnum[key] = 0\n\t\t}\n\t} else {\n\t\tfor i := 0; i < int(h.bucket_size_); i++ {\n\t\t\tnum[i] = 0\n\t\t}\n\t}\n}\n\n/* Look at 4 bytes at &data[ix & mask].\n   Compute a hash from these, and store the value of ix at that position. */\nfunc (h *h6) Store(data []byte, mask uint, ix uint) {\n\tvar num []uint16 = h.num\n\tvar key uint32 = hashBytesH6(data[ix&mask:], h.hash_mask_, h.hash_shift_)\n\tvar minor_ix uint = uint(num[key]) & uint(h.block_mask_)\n\tvar offset uint = minor_ix + uint(key<<uint(h.params.block_bits))\n\th.buckets[offset] = uint32(ix)\n\tnum[key]++\n}\n\nfunc (h *h6) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {\n\tvar i uint\n\tfor i = ix_start; i < ix_end; i++ {\n\t\th.Store(data, mask, i)\n\t}\n}\n\nfunc (h *h6) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {\n\tif num_bytes >= h.HashTypeLength()-1 && position >= 3 {\n\t\t/* Prepare the hashes for three last bytes of the last write.\n\t\t   These could not be calculated before, since they require knowledge\n\t\t   of both the previous and the current block. */\n\t\th.Store(ringbuffer, ringbuffer_mask, position-3)\n\t\th.Store(ringbuffer, ringbuffer_mask, position-2)\n\t\th.Store(ringbuffer, ringbuffer_mask, position-1)\n\t}\n}\n\nfunc (h *h6) PrepareDistanceCache(distance_cache []int) {\n\tprepareDistanceCache(distance_cache, h.params.num_last_distances_to_check)\n}\n\n/* Find a longest backward match of &data[cur_ix] up to the length of\n   max_length and stores the position cur_ix in the hash table.\n\n   REQUIRES: PrepareDistanceCacheH6 must be invoked for current distance cache\n             values; if this method is invoked repeatedly with the same distance\n             cache values, it is enough to invoke PrepareDistanceCacheH6 once.\n\n   Does not look for matches longer than max_length.\n   Does not look for matches further away than max_backward.\n   Writes the best match into |out|.\n   |out|->score is updated only if a better match is found. */\nfunc (h *h6) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {\n\tvar num []uint16 = h.num\n\tvar buckets []uint32 = h.buckets\n\tvar cur_ix_masked uint = cur_ix & ring_buffer_mask\n\tvar min_score uint = out.score\n\tvar best_score uint = out.score\n\tvar best_len uint = out.len\n\tvar i uint\n\tvar bucket []uint32\n\t/* Don't accept a short copy from far away. */\n\tout.len = 0\n\n\tout.len_code_delta = 0\n\n\t/* Try last distance first. */\n\tfor i = 0; i < uint(h.params.num_last_distances_to_check); i++ {\n\t\tvar backward uint = uint(distance_cache[i])\n\t\tvar prev_ix uint = uint(cur_ix - backward)\n\t\tif prev_ix >= cur_ix {\n\t\t\tcontinue\n\t\t}\n\n\t\tif backward > max_backward {\n\t\t\tcontinue\n\t\t}\n\n\t\tprev_ix &= ring_buffer_mask\n\n\t\tif cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {\n\t\t\tcontinue\n\t\t}\n\t\t{\n\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\tif len >= 3 || (len == 2 && i < 2) {\n\t\t\t\t/* Comparing for >= 2 does not change the semantics, but just saves for\n\t\t\t\t   a few unnecessary binary logarithms in backward reference score,\n\t\t\t\t   since we are not interested in such short matches. */\n\t\t\t\tvar score uint = backwardReferenceScoreUsingLastDistance(uint(len))\n\t\t\t\tif best_score < score {\n\t\t\t\t\tif i != 0 {\n\t\t\t\t\t\tscore -= backwardReferencePenaltyUsingLastDistance(i)\n\t\t\t\t\t}\n\t\t\t\t\tif best_score < score {\n\t\t\t\t\t\tbest_score = score\n\t\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\t\tout.len = best_len\n\t\t\t\t\t\tout.distance = backward\n\t\t\t\t\t\tout.score = best_score\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tvar key uint32 = hashBytesH6(data[cur_ix_masked:], h.hash_mask_, h.hash_shift_)\n\t\tbucket = buckets[key<<uint(h.params.block_bits):]\n\t\tvar down uint\n\t\tif uint(num[key]) > h.block_size_ {\n\t\t\tdown = uint(num[key]) - h.block_size_\n\t\t} else {\n\t\t\tdown = 0\n\t\t}\n\t\tfor i = uint(num[key]); i > down; {\n\t\t\tvar prev_ix uint\n\t\t\ti--\n\t\t\tprev_ix = uint(bucket[uint32(i)&h.block_mask_])\n\t\t\tvar backward uint = cur_ix - prev_ix\n\t\t\tif backward > max_backward {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tprev_ix &= ring_buffer_mask\n\t\t\tif cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t{\n\t\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\t\tif len >= 4 {\n\t\t\t\t\t/* Comparing for >= 3 does not change the semantics, but just saves\n\t\t\t\t\t   for a few unnecessary binary logarithms in backward reference\n\t\t\t\t\t   score, since we are not interested in such short matches. */\n\t\t\t\t\tvar score uint = backwardReferenceScore(uint(len), backward)\n\t\t\t\t\tif best_score < score {\n\t\t\t\t\t\tbest_score = score\n\t\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\t\tout.len = best_len\n\t\t\t\t\t\tout.distance = backward\n\t\t\t\t\t\tout.score = best_score\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbucket[uint32(num[key])&h.block_mask_] = uint32(cur_ix)\n\t\tnum[key]++\n\t}\n\n\tif min_score == out.score {\n\t\tsearchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/hash.go",
    "content": "package brotli\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n)\n\ntype hasherCommon struct {\n\tparams           hasherParams\n\tis_prepared_     bool\n\tdict_num_lookups uint\n\tdict_num_matches uint\n}\n\nfunc (h *hasherCommon) Common() *hasherCommon {\n\treturn h\n}\n\ntype hasherHandle interface {\n\tCommon() *hasherCommon\n\tInitialize(params *encoderParams)\n\tPrepare(one_shot bool, input_size uint, data []byte)\n\tStitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint)\n\tHashTypeLength() uint\n\tStoreLookahead() uint\n\tPrepareDistanceCache(distance_cache []int)\n\tFindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult)\n\tStoreRange(data []byte, mask uint, ix_start uint, ix_end uint)\n\tStore(data []byte, mask uint, ix uint)\n}\n\nconst kCutoffTransformsCount uint32 = 10\n\n/*   0,  12,   27,    23,    42,    63,    56,    48,    59,    64 */\n/* 0+0, 4+8, 8+19, 12+11, 16+26, 20+43, 24+32, 28+20, 32+27, 36+28 */\nconst kCutoffTransforms uint64 = 0x071B520ADA2D3200\n\ntype hasherSearchResult struct {\n\tlen            uint\n\tdistance       uint\n\tscore          uint\n\tlen_code_delta int\n}\n\n/* kHashMul32 multiplier has these properties:\n   * The multiplier must be odd. Otherwise we may lose the highest bit.\n   * No long streaks of ones or zeros.\n   * There is no effort to ensure that it is a prime, the oddity is enough\n     for this use.\n   * The number has been tuned heuristically against compression benchmarks. */\nconst kHashMul32 uint32 = 0x1E35A7BD\n\nconst kHashMul64 uint64 = 0x1E35A7BD1E35A7BD\n\nconst kHashMul64Long uint64 = 0x1FE35A7BD3579BD3\n\nfunc hash14(data []byte) uint32 {\n\tvar h uint32 = binary.LittleEndian.Uint32(data) * kHashMul32\n\n\t/* The higher bits contain more mixture from the multiplication,\n\t   so we take our results from there. */\n\treturn h >> (32 - 14)\n}\n\nfunc prepareDistanceCache(distance_cache []int, num_distances int) {\n\tif num_distances > 4 {\n\t\tvar last_distance int = distance_cache[0]\n\t\tdistance_cache[4] = last_distance - 1\n\t\tdistance_cache[5] = last_distance + 1\n\t\tdistance_cache[6] = last_distance - 2\n\t\tdistance_cache[7] = last_distance + 2\n\t\tdistance_cache[8] = last_distance - 3\n\t\tdistance_cache[9] = last_distance + 3\n\t\tif num_distances > 10 {\n\t\t\tvar next_last_distance int = distance_cache[1]\n\t\t\tdistance_cache[10] = next_last_distance - 1\n\t\t\tdistance_cache[11] = next_last_distance + 1\n\t\t\tdistance_cache[12] = next_last_distance - 2\n\t\t\tdistance_cache[13] = next_last_distance + 2\n\t\t\tdistance_cache[14] = next_last_distance - 3\n\t\t\tdistance_cache[15] = next_last_distance + 3\n\t\t}\n\t}\n}\n\nconst literalByteScore = 135\n\nconst distanceBitPenalty = 30\n\n/* Score must be positive after applying maximal penalty. */\nconst scoreBase = (distanceBitPenalty * 8 * 8)\n\n/* Usually, we always choose the longest backward reference. This function\n   allows for the exception of that rule.\n\n   If we choose a backward reference that is further away, it will\n   usually be coded with more bits. We approximate this by assuming\n   log2(distance). If the distance can be expressed in terms of the\n   last four distances, we use some heuristic constants to estimate\n   the bits cost. For the first up to four literals we use the bit\n   cost of the literals from the literal cost model, after that we\n   use the average bit cost of the cost model.\n\n   This function is used to sometimes discard a longer backward reference\n   when it is not much longer and the bit cost for encoding it is more\n   than the saved literals.\n\n   backward_reference_offset MUST be positive. */\nfunc backwardReferenceScore(copy_length uint, backward_reference_offset uint) uint {\n\treturn scoreBase + literalByteScore*uint(copy_length) - distanceBitPenalty*uint(log2FloorNonZero(backward_reference_offset))\n}\n\nfunc backwardReferenceScoreUsingLastDistance(copy_length uint) uint {\n\treturn literalByteScore*uint(copy_length) + scoreBase + 15\n}\n\nfunc backwardReferencePenaltyUsingLastDistance(distance_short_code uint) uint {\n\treturn uint(39) + ((0x1CA10 >> (distance_short_code & 0xE)) & 0xE)\n}\n\nfunc testStaticDictionaryItem(dictionary *encoderDictionary, item uint, data []byte, max_length uint, max_backward uint, max_distance uint, out *hasherSearchResult) bool {\n\tvar len uint\n\tvar word_idx uint\n\tvar offset uint\n\tvar matchlen uint\n\tvar backward uint\n\tvar score uint\n\tlen = item & 0x1F\n\tword_idx = item >> 5\n\toffset = uint(dictionary.words.offsets_by_length[len]) + len*word_idx\n\tif len > max_length {\n\t\treturn false\n\t}\n\n\tmatchlen = findMatchLengthWithLimit(data, dictionary.words.data[offset:], uint(len))\n\tif matchlen+uint(dictionary.cutoffTransformsCount) <= len || matchlen == 0 {\n\t\treturn false\n\t}\n\t{\n\t\tvar cut uint = len - matchlen\n\t\tvar transform_id uint = (cut << 2) + uint((dictionary.cutoffTransforms>>(cut*6))&0x3F)\n\t\tbackward = max_backward + 1 + word_idx + (transform_id << dictionary.words.size_bits_by_length[len])\n\t}\n\n\tif backward > max_distance {\n\t\treturn false\n\t}\n\n\tscore = backwardReferenceScore(matchlen, backward)\n\tif score < out.score {\n\t\treturn false\n\t}\n\n\tout.len = matchlen\n\tout.len_code_delta = int(len) - int(matchlen)\n\tout.distance = backward\n\tout.score = score\n\treturn true\n}\n\nfunc searchInStaticDictionary(dictionary *encoderDictionary, handle hasherHandle, data []byte, max_length uint, max_backward uint, max_distance uint, out *hasherSearchResult, shallow bool) {\n\tvar key uint\n\tvar i uint\n\tvar self *hasherCommon = handle.Common()\n\tif self.dict_num_matches < self.dict_num_lookups>>7 {\n\t\treturn\n\t}\n\n\tkey = uint(hash14(data) << 1)\n\tfor i = 0; ; (func() { i++; key++ })() {\n\t\tvar tmp uint\n\t\tif shallow {\n\t\t\ttmp = 1\n\t\t} else {\n\t\t\ttmp = 2\n\t\t}\n\t\tif i >= tmp {\n\t\t\tbreak\n\t\t}\n\t\tvar item uint = uint(dictionary.hash_table[key])\n\t\tself.dict_num_lookups++\n\t\tif item != 0 {\n\t\t\tvar item_matches bool = testStaticDictionaryItem(dictionary, item, data, max_length, max_backward, max_distance, out)\n\t\t\tif item_matches {\n\t\t\t\tself.dict_num_matches++\n\t\t\t}\n\t\t}\n\t}\n}\n\ntype backwardMatch struct {\n\tdistance        uint32\n\tlength_and_code uint32\n}\n\nfunc initBackwardMatch(self *backwardMatch, dist uint, len uint) {\n\tself.distance = uint32(dist)\n\tself.length_and_code = uint32(len << 5)\n}\n\nfunc initDictionaryBackwardMatch(self *backwardMatch, dist uint, len uint, len_code uint) {\n\tself.distance = uint32(dist)\n\tvar tmp uint\n\tif len == len_code {\n\t\ttmp = 0\n\t} else {\n\t\ttmp = len_code\n\t}\n\tself.length_and_code = uint32(len<<5 | tmp)\n}\n\nfunc backwardMatchLength(self *backwardMatch) uint {\n\treturn uint(self.length_and_code >> 5)\n}\n\nfunc backwardMatchLengthCode(self *backwardMatch) uint {\n\tvar code uint = uint(self.length_and_code) & 31\n\tif code != 0 {\n\t\treturn code\n\t} else {\n\t\treturn backwardMatchLength(self)\n\t}\n}\n\nfunc hasherReset(handle hasherHandle) {\n\tif handle == nil {\n\t\treturn\n\t}\n\thandle.Common().is_prepared_ = false\n}\n\nfunc newHasher(typ int) hasherHandle {\n\tswitch typ {\n\tcase 2:\n\t\treturn &hashLongestMatchQuickly{\n\t\t\tbucketBits:    16,\n\t\t\tbucketSweep:   1,\n\t\t\thashLen:       5,\n\t\t\tuseDictionary: true,\n\t\t}\n\tcase 3:\n\t\treturn &hashLongestMatchQuickly{\n\t\t\tbucketBits:    16,\n\t\t\tbucketSweep:   2,\n\t\t\thashLen:       5,\n\t\t\tuseDictionary: false,\n\t\t}\n\tcase 4:\n\t\treturn &hashLongestMatchQuickly{\n\t\t\tbucketBits:    17,\n\t\t\tbucketSweep:   4,\n\t\t\thashLen:       5,\n\t\t\tuseDictionary: true,\n\t\t}\n\tcase 5:\n\t\treturn new(h5)\n\tcase 6:\n\t\treturn new(h6)\n\tcase 10:\n\t\treturn new(h10)\n\tcase 35:\n\t\treturn &hashComposite{\n\t\t\tha: newHasher(3),\n\t\t\thb: &hashRolling{jump: 4},\n\t\t}\n\tcase 40:\n\t\treturn &hashForgetfulChain{\n\t\t\tbucketBits:              15,\n\t\t\tnumBanks:                1,\n\t\t\tbankBits:                16,\n\t\t\tnumLastDistancesToCheck: 4,\n\t\t}\n\tcase 41:\n\t\treturn &hashForgetfulChain{\n\t\t\tbucketBits:              15,\n\t\t\tnumBanks:                1,\n\t\t\tbankBits:                16,\n\t\t\tnumLastDistancesToCheck: 10,\n\t\t}\n\tcase 42:\n\t\treturn &hashForgetfulChain{\n\t\t\tbucketBits:              15,\n\t\t\tnumBanks:                512,\n\t\t\tbankBits:                9,\n\t\t\tnumLastDistancesToCheck: 16,\n\t\t}\n\tcase 54:\n\t\treturn &hashLongestMatchQuickly{\n\t\t\tbucketBits:    20,\n\t\t\tbucketSweep:   4,\n\t\t\thashLen:       7,\n\t\t\tuseDictionary: false,\n\t\t}\n\tcase 55:\n\t\treturn &hashComposite{\n\t\t\tha: newHasher(54),\n\t\t\thb: &hashRolling{jump: 4},\n\t\t}\n\tcase 65:\n\t\treturn &hashComposite{\n\t\t\tha: newHasher(6),\n\t\t\thb: &hashRolling{jump: 1},\n\t\t}\n\t}\n\n\tpanic(fmt.Sprintf(\"unknown hasher type: %d\", typ))\n}\n\nfunc hasherSetup(handle *hasherHandle, params *encoderParams, data []byte, position uint, input_size uint, is_last bool) {\n\tvar self hasherHandle = nil\n\tvar common *hasherCommon = nil\n\tvar one_shot bool = (position == 0 && is_last)\n\tif *handle == nil {\n\t\tchooseHasher(params, &params.hasher)\n\t\tself = newHasher(params.hasher.type_)\n\n\t\t*handle = self\n\t\tcommon = self.Common()\n\t\tcommon.params = params.hasher\n\t\tself.Initialize(params)\n\t}\n\n\tself = *handle\n\tcommon = self.Common()\n\tif !common.is_prepared_ {\n\t\tself.Prepare(one_shot, input_size, data)\n\n\t\tif position == 0 {\n\t\t\tcommon.dict_num_lookups = 0\n\t\t\tcommon.dict_num_matches = 0\n\t\t}\n\n\t\tcommon.is_prepared_ = true\n\t}\n}\n\nfunc initOrStitchToPreviousBlock(handle *hasherHandle, data []byte, mask uint, params *encoderParams, position uint, input_size uint, is_last bool) {\n\tvar self hasherHandle\n\thasherSetup(handle, params, data, position, input_size, is_last)\n\tself = *handle\n\tself.StitchToPreviousBlock(input_size, position, data, mask)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/hash_composite.go",
    "content": "package brotli\n\n/* Copyright 2018 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nfunc (h *hashComposite) HashTypeLength() uint {\n\tvar a uint = h.ha.HashTypeLength()\n\tvar b uint = h.hb.HashTypeLength()\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc (h *hashComposite) StoreLookahead() uint {\n\tvar a uint = h.ha.StoreLookahead()\n\tvar b uint = h.hb.StoreLookahead()\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\n/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A\n   and HASHER_B. */\ntype hashComposite struct {\n\thasherCommon\n\tha     hasherHandle\n\thb     hasherHandle\n\tparams *encoderParams\n}\n\nfunc (h *hashComposite) Initialize(params *encoderParams) {\n\th.params = params\n}\n\n/* TODO: Initialize of the hashers is defered to Prepare (and params\n   remembered here) because we don't get the one_shot and input_size params\n   here that are needed to know the memory size of them. Instead provide\n   those params to all hashers InitializehashComposite */\nfunc (h *hashComposite) Prepare(one_shot bool, input_size uint, data []byte) {\n\tif h.ha == nil {\n\t\tvar common_a *hasherCommon\n\t\tvar common_b *hasherCommon\n\n\t\tcommon_a = h.ha.Common()\n\t\tcommon_a.params = h.params.hasher\n\t\tcommon_a.is_prepared_ = false\n\t\tcommon_a.dict_num_lookups = 0\n\t\tcommon_a.dict_num_matches = 0\n\t\th.ha.Initialize(h.params)\n\n\t\tcommon_b = h.hb.Common()\n\t\tcommon_b.params = h.params.hasher\n\t\tcommon_b.is_prepared_ = false\n\t\tcommon_b.dict_num_lookups = 0\n\t\tcommon_b.dict_num_matches = 0\n\t\th.hb.Initialize(h.params)\n\t}\n\n\th.ha.Prepare(one_shot, input_size, data)\n\th.hb.Prepare(one_shot, input_size, data)\n}\n\nfunc (h *hashComposite) Store(data []byte, mask uint, ix uint) {\n\th.ha.Store(data, mask, ix)\n\th.hb.Store(data, mask, ix)\n}\n\nfunc (h *hashComposite) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {\n\th.ha.StoreRange(data, mask, ix_start, ix_end)\n\th.hb.StoreRange(data, mask, ix_start, ix_end)\n}\n\nfunc (h *hashComposite) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {\n\th.ha.StitchToPreviousBlock(num_bytes, position, ringbuffer, ring_buffer_mask)\n\th.hb.StitchToPreviousBlock(num_bytes, position, ringbuffer, ring_buffer_mask)\n}\n\nfunc (h *hashComposite) PrepareDistanceCache(distance_cache []int) {\n\th.ha.PrepareDistanceCache(distance_cache)\n\th.hb.PrepareDistanceCache(distance_cache)\n}\n\nfunc (h *hashComposite) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {\n\th.ha.FindLongestMatch(dictionary, data, ring_buffer_mask, distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out)\n\th.hb.FindLongestMatch(dictionary, data, ring_buffer_mask, distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/hash_forgetful_chain.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2016 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nfunc (*hashForgetfulChain) HashTypeLength() uint {\n\treturn 4\n}\n\nfunc (*hashForgetfulChain) StoreLookahead() uint {\n\treturn 4\n}\n\n/* HashBytes is the function that chooses the bucket to place the address in.*/\nfunc (h *hashForgetfulChain) HashBytes(data []byte) uint {\n\tvar hash uint32 = binary.LittleEndian.Uint32(data) * kHashMul32\n\n\t/* The higher bits contain more mixture from the multiplication,\n\t   so we take our results from there. */\n\treturn uint(hash >> (32 - h.bucketBits))\n}\n\ntype slot struct {\n\tdelta uint16\n\tnext  uint16\n}\n\n/* A (forgetful) hash table to the data seen by the compressor, to\n   help create backward references to previous data.\n\n   Hashes are stored in chains which are bucketed to groups. Group of chains\n   share a storage \"bank\". When more than \"bank size\" chain nodes are added,\n   oldest nodes are replaced; this way several chains may share a tail. */\ntype hashForgetfulChain struct {\n\thasherCommon\n\n\tbucketBits              uint\n\tnumBanks                uint\n\tbankBits                uint\n\tnumLastDistancesToCheck int\n\n\taddr          []uint32\n\thead          []uint16\n\ttiny_hash     [65536]byte\n\tbanks         [][]slot\n\tfree_slot_idx []uint16\n\tmax_hops      uint\n}\n\nfunc (h *hashForgetfulChain) Initialize(params *encoderParams) {\n\tvar q uint\n\tif params.quality > 6 {\n\t\tq = 7\n\t} else {\n\t\tq = 8\n\t}\n\th.max_hops = q << uint(params.quality-4)\n\n\tbankSize := 1 << h.bankBits\n\tbucketSize := 1 << h.bucketBits\n\n\th.addr = make([]uint32, bucketSize)\n\th.head = make([]uint16, bucketSize)\n\th.banks = make([][]slot, h.numBanks)\n\tfor i := range h.banks {\n\t\th.banks[i] = make([]slot, bankSize)\n\t}\n\th.free_slot_idx = make([]uint16, h.numBanks)\n}\n\nfunc (h *hashForgetfulChain) Prepare(one_shot bool, input_size uint, data []byte) {\n\tvar partial_prepare_threshold uint = (1 << h.bucketBits) >> 6\n\t/* Partial preparation is 100 times slower (per socket). */\n\tif one_shot && input_size <= partial_prepare_threshold {\n\t\tvar i uint\n\t\tfor i = 0; i < input_size; i++ {\n\t\t\tvar bucket uint = h.HashBytes(data[i:])\n\n\t\t\t/* See InitEmpty comment. */\n\t\t\th.addr[bucket] = 0xCCCCCCCC\n\n\t\t\th.head[bucket] = 0xCCCC\n\t\t}\n\t} else {\n\t\t/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position\n\t\t   processed by hasher never reaches 3GB + 64M; this makes all new chains\n\t\t   to be terminated after the first node. */\n\t\tfor i := range h.addr {\n\t\t\th.addr[i] = 0xCCCCCCCC\n\t\t}\n\n\t\tfor i := range h.head {\n\t\t\th.head[i] = 0\n\t\t}\n\t}\n\n\th.tiny_hash = [65536]byte{}\n\tfor i := range h.free_slot_idx {\n\t\th.free_slot_idx[i] = 0\n\t}\n}\n\n/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend\n   node to corresponding chain; also update tiny_hash for current position. */\nfunc (h *hashForgetfulChain) Store(data []byte, mask uint, ix uint) {\n\tvar key uint = h.HashBytes(data[ix&mask:])\n\tvar bank uint = key & (h.numBanks - 1)\n\tidx := uint(h.free_slot_idx[bank]) & ((1 << h.bankBits) - 1)\n\th.free_slot_idx[bank]++\n\tvar delta uint = ix - uint(h.addr[key])\n\th.tiny_hash[uint16(ix)] = byte(key)\n\tif delta > 0xFFFF {\n\t\tdelta = 0xFFFF\n\t}\n\th.banks[bank][idx].delta = uint16(delta)\n\th.banks[bank][idx].next = h.head[key]\n\th.addr[key] = uint32(ix)\n\th.head[key] = uint16(idx)\n}\n\nfunc (h *hashForgetfulChain) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {\n\tvar i uint\n\tfor i = ix_start; i < ix_end; i++ {\n\t\th.Store(data, mask, i)\n\t}\n}\n\nfunc (h *hashForgetfulChain) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {\n\tif num_bytes >= h.HashTypeLength()-1 && position >= 3 {\n\t\t/* Prepare the hashes for three last bytes of the last write.\n\t\t   These could not be calculated before, since they require knowledge\n\t\t   of both the previous and the current block. */\n\t\th.Store(ringbuffer, ring_buffer_mask, position-3)\n\t\th.Store(ringbuffer, ring_buffer_mask, position-2)\n\t\th.Store(ringbuffer, ring_buffer_mask, position-1)\n\t}\n}\n\nfunc (h *hashForgetfulChain) PrepareDistanceCache(distance_cache []int) {\n\tprepareDistanceCache(distance_cache, h.numLastDistancesToCheck)\n}\n\n/* Find a longest backward match of &data[cur_ix] up to the length of\n   max_length and stores the position cur_ix in the hash table.\n\n   REQUIRES: PrepareDistanceCachehashForgetfulChain must be invoked for current distance cache\n             values; if this method is invoked repeatedly with the same distance\n             cache values, it is enough to invoke PrepareDistanceCachehashForgetfulChain once.\n\n   Does not look for matches longer than max_length.\n   Does not look for matches further away than max_backward.\n   Writes the best match into |out|.\n   |out|->score is updated only if a better match is found. */\nfunc (h *hashForgetfulChain) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {\n\tvar cur_ix_masked uint = cur_ix & ring_buffer_mask\n\tvar min_score uint = out.score\n\tvar best_score uint = out.score\n\tvar best_len uint = out.len\n\tvar key uint = h.HashBytes(data[cur_ix_masked:])\n\tvar tiny_hash byte = byte(key)\n\t/* Don't accept a short copy from far away. */\n\tout.len = 0\n\n\tout.len_code_delta = 0\n\n\t/* Try last distance first. */\n\tfor i := 0; i < h.numLastDistancesToCheck; i++ {\n\t\tvar backward uint = uint(distance_cache[i])\n\t\tvar prev_ix uint = (cur_ix - backward)\n\n\t\t/* For distance code 0 we want to consider 2-byte matches. */\n\t\tif i > 0 && h.tiny_hash[uint16(prev_ix)] != tiny_hash {\n\t\t\tcontinue\n\t\t}\n\t\tif prev_ix >= cur_ix || backward > max_backward {\n\t\t\tcontinue\n\t\t}\n\n\t\tprev_ix &= ring_buffer_mask\n\t\t{\n\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\tif len >= 2 {\n\t\t\t\tvar score uint = backwardReferenceScoreUsingLastDistance(uint(len))\n\t\t\t\tif best_score < score {\n\t\t\t\t\tif i != 0 {\n\t\t\t\t\t\tscore -= backwardReferencePenaltyUsingLastDistance(uint(i))\n\t\t\t\t\t}\n\t\t\t\t\tif best_score < score {\n\t\t\t\t\t\tbest_score = score\n\t\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\t\tout.len = best_len\n\t\t\t\t\t\tout.distance = backward\n\t\t\t\t\t\tout.score = best_score\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tvar bank uint = key & (h.numBanks - 1)\n\t\tvar backward uint = 0\n\t\tvar hops uint = h.max_hops\n\t\tvar delta uint = cur_ix - uint(h.addr[key])\n\t\tvar slot uint = uint(h.head[key])\n\t\tfor {\n\t\t\ttmp6 := hops\n\t\t\thops--\n\t\t\tif tmp6 == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tvar prev_ix uint\n\t\t\tvar last uint = slot\n\t\t\tbackward += delta\n\t\t\tif backward > max_backward {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tprev_ix = (cur_ix - backward) & ring_buffer_mask\n\t\t\tslot = uint(h.banks[bank][last].next)\n\t\t\tdelta = uint(h.banks[bank][last].delta)\n\t\t\tif cur_ix_masked+best_len > ring_buffer_mask || prev_ix+best_len > ring_buffer_mask || data[cur_ix_masked+best_len] != data[prev_ix+best_len] {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t{\n\t\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\t\tif len >= 4 {\n\t\t\t\t\t/* Comparing for >= 3 does not change the semantics, but just saves\n\t\t\t\t\t   for a few unnecessary binary logarithms in backward reference\n\t\t\t\t\t   score, since we are not interested in such short matches. */\n\t\t\t\t\tvar score uint = backwardReferenceScore(uint(len), backward)\n\t\t\t\t\tif best_score < score {\n\t\t\t\t\t\tbest_score = score\n\t\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\t\tout.len = best_len\n\t\t\t\t\t\tout.distance = backward\n\t\t\t\t\t\tout.score = best_score\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\th.Store(data, ring_buffer_mask, cur_ix)\n\t}\n\n\tif out.score == min_score {\n\t\tsearchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, false)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/hash_longest_match_quickly.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2010 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression\n   a little faster (0.5% - 1%) and it compresses 0.15% better on small text\n   and HTML inputs. */\n\nfunc (*hashLongestMatchQuickly) HashTypeLength() uint {\n\treturn 8\n}\n\nfunc (*hashLongestMatchQuickly) StoreLookahead() uint {\n\treturn 8\n}\n\n/* HashBytes is the function that chooses the bucket to place\n   the address in. The HashLongestMatch and hashLongestMatchQuickly\n   classes have separate, different implementations of hashing. */\nfunc (h *hashLongestMatchQuickly) HashBytes(data []byte) uint32 {\n\tvar hash uint64 = ((binary.LittleEndian.Uint64(data) << (64 - 8*h.hashLen)) * kHashMul64)\n\n\t/* The higher bits contain more mixture from the multiplication,\n\t   so we take our results from there. */\n\treturn uint32(hash >> (64 - h.bucketBits))\n}\n\n/* A (forgetful) hash table to the data seen by the compressor, to\n   help create backward references to previous data.\n\n   This is a hash map of fixed size (1 << 16). Starting from the\n   given index, 1 buckets are used to store values of a key. */\ntype hashLongestMatchQuickly struct {\n\thasherCommon\n\n\tbucketBits    uint\n\tbucketSweep   int\n\thashLen       uint\n\tuseDictionary bool\n\n\tbuckets []uint32\n}\n\nfunc (h *hashLongestMatchQuickly) Initialize(params *encoderParams) {\n\th.buckets = make([]uint32, 1<<h.bucketBits+h.bucketSweep)\n}\n\nfunc (h *hashLongestMatchQuickly) Prepare(one_shot bool, input_size uint, data []byte) {\n\tvar partial_prepare_threshold uint = (4 << h.bucketBits) >> 7\n\t/* Partial preparation is 100 times slower (per socket). */\n\tif one_shot && input_size <= partial_prepare_threshold {\n\t\tvar i uint\n\t\tfor i = 0; i < input_size; i++ {\n\t\t\tvar key uint32 = h.HashBytes(data[i:])\n\t\t\tfor j := 0; j < h.bucketSweep; j++ {\n\t\t\t\th.buckets[key+uint32(j)] = 0\n\t\t\t}\n\t\t}\n\t} else {\n\t\t/* It is not strictly necessary to fill this buffer here, but\n\t\t   not filling will make the results of the compression stochastic\n\t\t   (but correct). This is because random data would cause the\n\t\t   system to find accidentally good backward references here and there. */\n\t\tfor i := range h.buckets {\n\t\t\th.buckets[i] = 0\n\t\t}\n\t}\n}\n\n/* Look at 5 bytes at &data[ix & mask].\n   Compute a hash from these, and store the value somewhere within\n   [ix .. ix+3]. */\nfunc (h *hashLongestMatchQuickly) Store(data []byte, mask uint, ix uint) {\n\tvar key uint32 = h.HashBytes(data[ix&mask:])\n\tvar off uint32 = uint32(ix>>3) % uint32(h.bucketSweep)\n\t/* Wiggle the value with the bucket sweep range. */\n\th.buckets[key+off] = uint32(ix)\n}\n\nfunc (h *hashLongestMatchQuickly) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {\n\tvar i uint\n\tfor i = ix_start; i < ix_end; i++ {\n\t\th.Store(data, mask, i)\n\t}\n}\n\nfunc (h *hashLongestMatchQuickly) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ringbuffer_mask uint) {\n\tif num_bytes >= h.HashTypeLength()-1 && position >= 3 {\n\t\t/* Prepare the hashes for three last bytes of the last write.\n\t\t   These could not be calculated before, since they require knowledge\n\t\t   of both the previous and the current block. */\n\t\th.Store(ringbuffer, ringbuffer_mask, position-3)\n\t\th.Store(ringbuffer, ringbuffer_mask, position-2)\n\t\th.Store(ringbuffer, ringbuffer_mask, position-1)\n\t}\n}\n\nfunc (*hashLongestMatchQuickly) PrepareDistanceCache(distance_cache []int) {\n}\n\n/* Find a longest backward match of &data[cur_ix & ring_buffer_mask]\n   up to the length of max_length and stores the position cur_ix in the\n   hash table.\n\n   Does not look for matches longer than max_length.\n   Does not look for matches further away than max_backward.\n   Writes the best match into |out|.\n   |out|->score is updated only if a better match is found. */\nfunc (h *hashLongestMatchQuickly) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {\n\tvar best_len_in uint = out.len\n\tvar cur_ix_masked uint = cur_ix & ring_buffer_mask\n\tvar key uint32 = h.HashBytes(data[cur_ix_masked:])\n\tvar compare_char int = int(data[cur_ix_masked+best_len_in])\n\tvar min_score uint = out.score\n\tvar best_score uint = out.score\n\tvar best_len uint = best_len_in\n\tvar cached_backward uint = uint(distance_cache[0])\n\tvar prev_ix uint = cur_ix - cached_backward\n\tvar bucket []uint32\n\tout.len_code_delta = 0\n\tif prev_ix < cur_ix {\n\t\tprev_ix &= uint(uint32(ring_buffer_mask))\n\t\tif compare_char == int(data[prev_ix+best_len]) {\n\t\t\tvar len uint = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\tif len >= 4 {\n\t\t\t\tvar score uint = backwardReferenceScoreUsingLastDistance(uint(len))\n\t\t\t\tif best_score < score {\n\t\t\t\t\tbest_score = score\n\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\tout.len = uint(len)\n\t\t\t\t\tout.distance = cached_backward\n\t\t\t\t\tout.score = best_score\n\t\t\t\t\tcompare_char = int(data[cur_ix_masked+best_len])\n\t\t\t\t\tif h.bucketSweep == 1 {\n\t\t\t\t\t\th.buckets[key] = uint32(cur_ix)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif h.bucketSweep == 1 {\n\t\tvar backward uint\n\t\tvar len uint\n\n\t\t/* Only one to look for, don't bother to prepare for a loop. */\n\t\tprev_ix = uint(h.buckets[key])\n\n\t\th.buckets[key] = uint32(cur_ix)\n\t\tbackward = cur_ix - prev_ix\n\t\tprev_ix &= uint(uint32(ring_buffer_mask))\n\t\tif compare_char != int(data[prev_ix+best_len_in]) {\n\t\t\treturn\n\t\t}\n\n\t\tif backward == 0 || backward > max_backward {\n\t\t\treturn\n\t\t}\n\n\t\tlen = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\tif len >= 4 {\n\t\t\tvar score uint = backwardReferenceScore(uint(len), backward)\n\t\t\tif best_score < score {\n\t\t\t\tout.len = uint(len)\n\t\t\t\tout.distance = backward\n\t\t\t\tout.score = score\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t} else {\n\t\tbucket = h.buckets[key:]\n\t\tvar i int\n\t\tprev_ix = uint(bucket[0])\n\t\tbucket = bucket[1:]\n\t\tfor i = 0; i < h.bucketSweep; (func() { i++; tmp3 := bucket; bucket = bucket[1:]; prev_ix = uint(tmp3[0]) })() {\n\t\t\tvar backward uint = cur_ix - prev_ix\n\t\t\tvar len uint\n\t\t\tprev_ix &= uint(uint32(ring_buffer_mask))\n\t\t\tif compare_char != int(data[prev_ix+best_len]) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif backward == 0 || backward > max_backward {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tlen = findMatchLengthWithLimit(data[prev_ix:], data[cur_ix_masked:], max_length)\n\t\t\tif len >= 4 {\n\t\t\t\tvar score uint = backwardReferenceScore(uint(len), backward)\n\t\t\t\tif best_score < score {\n\t\t\t\t\tbest_score = score\n\t\t\t\t\tbest_len = uint(len)\n\t\t\t\t\tout.len = best_len\n\t\t\t\t\tout.distance = backward\n\t\t\t\t\tout.score = score\n\t\t\t\t\tcompare_char = int(data[cur_ix_masked+best_len])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif h.useDictionary && min_score == out.score {\n\t\tsearchInStaticDictionary(dictionary, h, data[cur_ix_masked:], max_length, max_backward+gap, max_distance, out, true)\n\t}\n\n\th.buckets[key+uint32((cur_ix>>3)%uint(h.bucketSweep))] = uint32(cur_ix)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/hash_rolling.go",
    "content": "package brotli\n\n/* Copyright 2018 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* NOTE: this hasher does not search in the dictionary. It is used as\n   backup-hasher, the main hasher already searches in it. */\n\nconst kRollingHashMul32 uint32 = 69069\n\nconst kInvalidPosHashRolling uint32 = 0xffffffff\n\n/* This hasher uses a longer forward length, but returning a higher value here\n   will hurt compression by the main hasher when combined with a composite\n   hasher. The hasher tests for forward itself instead. */\nfunc (*hashRolling) HashTypeLength() uint {\n\treturn 4\n}\n\nfunc (*hashRolling) StoreLookahead() uint {\n\treturn 4\n}\n\n/* Computes a code from a single byte. A lookup table of 256 values could be\n   used, but simply adding 1 works about as good. */\nfunc (*hashRolling) HashByte(b byte) uint32 {\n\treturn uint32(b) + 1\n}\n\nfunc (h *hashRolling) HashRollingFunctionInitial(state uint32, add byte, factor uint32) uint32 {\n\treturn uint32(factor*state + h.HashByte(add))\n}\n\nfunc (h *hashRolling) HashRollingFunction(state uint32, add byte, rem byte, factor uint32, factor_remove uint32) uint32 {\n\treturn uint32(factor*state + h.HashByte(add) - factor_remove*h.HashByte(rem))\n}\n\n/* Rolling hash for long distance long string matches. Stores one position\n   per bucket, bucket key is computed over a long region. */\ntype hashRolling struct {\n\thasherCommon\n\n\tjump int\n\n\tstate         uint32\n\ttable         []uint32\n\tnext_ix       uint\n\tfactor        uint32\n\tfactor_remove uint32\n}\n\nfunc (h *hashRolling) Initialize(params *encoderParams) {\n\th.state = 0\n\th.next_ix = 0\n\n\th.factor = kRollingHashMul32\n\n\t/* Compute the factor of the oldest byte to remove: factor**steps modulo\n\t   0xffffffff (the multiplications rely on 32-bit overflow) */\n\th.factor_remove = 1\n\n\tfor i := 0; i < 32; i += h.jump {\n\t\th.factor_remove *= h.factor\n\t}\n\n\th.table = make([]uint32, 16777216)\n\tfor i := 0; i < 16777216; i++ {\n\t\th.table[i] = kInvalidPosHashRolling\n\t}\n}\n\nfunc (h *hashRolling) Prepare(one_shot bool, input_size uint, data []byte) {\n\t/* Too small size, cannot use this hasher. */\n\tif input_size < 32 {\n\t\treturn\n\t}\n\th.state = 0\n\tfor i := 0; i < 32; i += h.jump {\n\t\th.state = h.HashRollingFunctionInitial(h.state, data[i], h.factor)\n\t}\n}\n\nfunc (*hashRolling) Store(data []byte, mask uint, ix uint) {\n}\n\nfunc (*hashRolling) StoreRange(data []byte, mask uint, ix_start uint, ix_end uint) {\n}\n\nfunc (h *hashRolling) StitchToPreviousBlock(num_bytes uint, position uint, ringbuffer []byte, ring_buffer_mask uint) {\n\tvar position_masked uint\n\t/* In this case we must re-initialize the hasher from scratch from the\n\t   current position. */\n\n\tvar available uint = num_bytes\n\tif position&uint(h.jump-1) != 0 {\n\t\tvar diff uint = uint(h.jump) - (position & uint(h.jump-1))\n\t\tif diff > available {\n\t\t\tavailable = 0\n\t\t} else {\n\t\t\tavailable = available - diff\n\t\t}\n\t\tposition += diff\n\t}\n\n\tposition_masked = position & ring_buffer_mask\n\n\t/* wrapping around ringbuffer not handled. */\n\tif available > ring_buffer_mask-position_masked {\n\t\tavailable = ring_buffer_mask - position_masked\n\t}\n\n\th.Prepare(false, available, ringbuffer[position&ring_buffer_mask:])\n\th.next_ix = position\n}\n\nfunc (*hashRolling) PrepareDistanceCache(distance_cache []int) {\n}\n\nfunc (h *hashRolling) FindLongestMatch(dictionary *encoderDictionary, data []byte, ring_buffer_mask uint, distance_cache []int, cur_ix uint, max_length uint, max_backward uint, gap uint, max_distance uint, out *hasherSearchResult) {\n\tvar cur_ix_masked uint = cur_ix & ring_buffer_mask\n\tvar pos uint = h.next_ix\n\n\tif cur_ix&uint(h.jump-1) != 0 {\n\t\treturn\n\t}\n\n\t/* Not enough lookahead */\n\tif max_length < 32 {\n\t\treturn\n\t}\n\n\tfor pos = h.next_ix; pos <= cur_ix; pos += uint(h.jump) {\n\t\tvar code uint32 = h.state & ((16777216 * 64) - 1)\n\t\tvar rem byte = data[pos&ring_buffer_mask]\n\t\tvar add byte = data[(pos+32)&ring_buffer_mask]\n\t\tvar found_ix uint = uint(kInvalidPosHashRolling)\n\n\t\th.state = h.HashRollingFunction(h.state, add, rem, h.factor, h.factor_remove)\n\n\t\tif code < 16777216 {\n\t\t\tfound_ix = uint(h.table[code])\n\t\t\th.table[code] = uint32(pos)\n\t\t\tif pos == cur_ix && uint32(found_ix) != kInvalidPosHashRolling {\n\t\t\t\t/* The cast to 32-bit makes backward distances up to 4GB work even\n\t\t\t\t   if cur_ix is above 4GB, despite using 32-bit values in the table. */\n\t\t\t\tvar backward uint = uint(uint32(cur_ix - found_ix))\n\t\t\t\tif backward <= max_backward {\n\t\t\t\t\tvar found_ix_masked uint = found_ix & ring_buffer_mask\n\t\t\t\t\tvar len uint = findMatchLengthWithLimit(data[found_ix_masked:], data[cur_ix_masked:], max_length)\n\t\t\t\t\tif len >= 4 && len > out.len {\n\t\t\t\t\t\tvar score uint = backwardReferenceScore(uint(len), backward)\n\t\t\t\t\t\tif score > out.score {\n\t\t\t\t\t\t\tout.len = uint(len)\n\t\t\t\t\t\t\tout.distance = backward\n\t\t\t\t\t\t\tout.score = score\n\t\t\t\t\t\t\tout.len_code_delta = 0\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\th.next_ix = cur_ix + uint(h.jump)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/histogram.go",
    "content": "package brotli\n\nimport \"math\"\n\n/* The distance symbols effectively used by \"Large Window Brotli\" (32-bit). */\nconst numHistogramDistanceSymbols = 544\n\ntype histogramLiteral struct {\n\tdata_        [numLiteralSymbols]uint32\n\ttotal_count_ uint\n\tbit_cost_    float64\n}\n\nfunc histogramClearLiteral(self *histogramLiteral) {\n\tself.data_ = [numLiteralSymbols]uint32{}\n\tself.total_count_ = 0\n\tself.bit_cost_ = math.MaxFloat64\n}\n\nfunc clearHistogramsLiteral(array []histogramLiteral, length uint) {\n\tvar i uint\n\tfor i = 0; i < length; i++ {\n\t\thistogramClearLiteral(&array[i:][0])\n\t}\n}\n\nfunc histogramAddLiteral(self *histogramLiteral, val uint) {\n\tself.data_[val]++\n\tself.total_count_++\n}\n\nfunc histogramAddVectorLiteral(self *histogramLiteral, p []byte, n uint) {\n\tself.total_count_ += n\n\tn += 1\n\tfor {\n\t\tn--\n\t\tif n == 0 {\n\t\t\tbreak\n\t\t}\n\t\tself.data_[p[0]]++\n\t\tp = p[1:]\n\t}\n}\n\nfunc histogramAddHistogramLiteral(self *histogramLiteral, v *histogramLiteral) {\n\tvar i uint\n\tself.total_count_ += v.total_count_\n\tfor i = 0; i < numLiteralSymbols; i++ {\n\t\tself.data_[i] += v.data_[i]\n\t}\n}\n\nfunc histogramDataSizeLiteral() uint {\n\treturn numLiteralSymbols\n}\n\ntype histogramCommand struct {\n\tdata_        [numCommandSymbols]uint32\n\ttotal_count_ uint\n\tbit_cost_    float64\n}\n\nfunc histogramClearCommand(self *histogramCommand) {\n\tself.data_ = [numCommandSymbols]uint32{}\n\tself.total_count_ = 0\n\tself.bit_cost_ = math.MaxFloat64\n}\n\nfunc clearHistogramsCommand(array []histogramCommand, length uint) {\n\tvar i uint\n\tfor i = 0; i < length; i++ {\n\t\thistogramClearCommand(&array[i:][0])\n\t}\n}\n\nfunc histogramAddCommand(self *histogramCommand, val uint) {\n\tself.data_[val]++\n\tself.total_count_++\n}\n\nfunc histogramAddVectorCommand(self *histogramCommand, p []uint16, n uint) {\n\tself.total_count_ += n\n\tn += 1\n\tfor {\n\t\tn--\n\t\tif n == 0 {\n\t\t\tbreak\n\t\t}\n\t\tself.data_[p[0]]++\n\t\tp = p[1:]\n\t}\n}\n\nfunc histogramAddHistogramCommand(self *histogramCommand, v *histogramCommand) {\n\tvar i uint\n\tself.total_count_ += v.total_count_\n\tfor i = 0; i < numCommandSymbols; i++ {\n\t\tself.data_[i] += v.data_[i]\n\t}\n}\n\nfunc histogramDataSizeCommand() uint {\n\treturn numCommandSymbols\n}\n\ntype histogramDistance struct {\n\tdata_        [numDistanceSymbols]uint32\n\ttotal_count_ uint\n\tbit_cost_    float64\n}\n\nfunc histogramClearDistance(self *histogramDistance) {\n\tself.data_ = [numDistanceSymbols]uint32{}\n\tself.total_count_ = 0\n\tself.bit_cost_ = math.MaxFloat64\n}\n\nfunc clearHistogramsDistance(array []histogramDistance, length uint) {\n\tvar i uint\n\tfor i = 0; i < length; i++ {\n\t\thistogramClearDistance(&array[i:][0])\n\t}\n}\n\nfunc histogramAddDistance(self *histogramDistance, val uint) {\n\tself.data_[val]++\n\tself.total_count_++\n}\n\nfunc histogramAddVectorDistance(self *histogramDistance, p []uint16, n uint) {\n\tself.total_count_ += n\n\tn += 1\n\tfor {\n\t\tn--\n\t\tif n == 0 {\n\t\t\tbreak\n\t\t}\n\t\tself.data_[p[0]]++\n\t\tp = p[1:]\n\t}\n}\n\nfunc histogramAddHistogramDistance(self *histogramDistance, v *histogramDistance) {\n\tvar i uint\n\tself.total_count_ += v.total_count_\n\tfor i = 0; i < numDistanceSymbols; i++ {\n\t\tself.data_[i] += v.data_[i]\n\t}\n}\n\nfunc histogramDataSizeDistance() uint {\n\treturn numDistanceSymbols\n}\n\ntype blockSplitIterator struct {\n\tsplit_  *blockSplit\n\tidx_    uint\n\ttype_   uint\n\tlength_ uint\n}\n\nfunc initBlockSplitIterator(self *blockSplitIterator, split *blockSplit) {\n\tself.split_ = split\n\tself.idx_ = 0\n\tself.type_ = 0\n\tif len(split.lengths) > 0 {\n\t\tself.length_ = uint(split.lengths[0])\n\t} else {\n\t\tself.length_ = 0\n\t}\n}\n\nfunc blockSplitIteratorNext(self *blockSplitIterator) {\n\tif self.length_ == 0 {\n\t\tself.idx_++\n\t\tself.type_ = uint(self.split_.types[self.idx_])\n\t\tself.length_ = uint(self.split_.lengths[self.idx_])\n\t}\n\n\tself.length_--\n}\n\nfunc buildHistogramsWithContext(cmds []command, literal_split *blockSplit, insert_and_copy_split *blockSplit, dist_split *blockSplit, ringbuffer []byte, start_pos uint, mask uint, prev_byte byte, prev_byte2 byte, context_modes []int, literal_histograms []histogramLiteral, insert_and_copy_histograms []histogramCommand, copy_dist_histograms []histogramDistance) {\n\tvar pos uint = start_pos\n\tvar literal_it blockSplitIterator\n\tvar insert_and_copy_it blockSplitIterator\n\tvar dist_it blockSplitIterator\n\n\tinitBlockSplitIterator(&literal_it, literal_split)\n\tinitBlockSplitIterator(&insert_and_copy_it, insert_and_copy_split)\n\tinitBlockSplitIterator(&dist_it, dist_split)\n\tfor i := range cmds {\n\t\tvar cmd *command = &cmds[i]\n\t\tvar j uint\n\t\tblockSplitIteratorNext(&insert_and_copy_it)\n\t\thistogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_], uint(cmd.cmd_prefix_))\n\n\t\t/* TODO: unwrap iterator blocks. */\n\t\tfor j = uint(cmd.insert_len_); j != 0; j-- {\n\t\t\tvar context uint\n\t\t\tblockSplitIteratorNext(&literal_it)\n\t\t\tcontext = literal_it.type_\n\t\t\tif context_modes != nil {\n\t\t\t\tvar lut contextLUT = getContextLUT(context_modes[context])\n\t\t\t\tcontext = (context << literalContextBits) + uint(getContext(prev_byte, prev_byte2, lut))\n\t\t\t}\n\n\t\t\thistogramAddLiteral(&literal_histograms[context], uint(ringbuffer[pos&mask]))\n\t\t\tprev_byte2 = prev_byte\n\t\t\tprev_byte = ringbuffer[pos&mask]\n\t\t\tpos++\n\t\t}\n\n\t\tpos += uint(commandCopyLen(cmd))\n\t\tif commandCopyLen(cmd) != 0 {\n\t\t\tprev_byte2 = ringbuffer[(pos-2)&mask]\n\t\t\tprev_byte = ringbuffer[(pos-1)&mask]\n\t\t\tif cmd.cmd_prefix_ >= 128 {\n\t\t\t\tvar context uint\n\t\t\t\tblockSplitIteratorNext(&dist_it)\n\t\t\t\tcontext = uint(uint32(dist_it.type_<<distanceContextBits) + commandDistanceContext(cmd))\n\t\t\t\thistogramAddDistance(&copy_dist_histograms[context], uint(cmd.dist_prefix_)&0x3FF)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/http.go",
    "content": "package brotli\n\nimport (\n\t\"compress/gzip\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\n// HTTPCompressor chooses a compression method (brotli, gzip, or none) based on\n// the Accept-Encoding header, sets the Content-Encoding header, and returns a\n// WriteCloser that implements that compression. The Close method must be called\n// before the current HTTP handler returns.\nfunc HTTPCompressor(w http.ResponseWriter, r *http.Request) io.WriteCloser {\n\tif w.Header().Get(\"Vary\") == \"\" {\n\t\tw.Header().Set(\"Vary\", \"Accept-Encoding\")\n\t}\n\n\tencoding := negotiateContentEncoding(r, []string{\"br\", \"gzip\"})\n\tswitch encoding {\n\tcase \"br\":\n\t\tw.Header().Set(\"Content-Encoding\", \"br\")\n\t\treturn NewWriterV2(w, DefaultCompression)\n\tcase \"gzip\":\n\t\tw.Header().Set(\"Content-Encoding\", \"gzip\")\n\t\treturn gzip.NewWriter(w)\n\t}\n\treturn nopCloser{w}\n}\n\n// negotiateContentEncoding returns the best offered content encoding for the\n// request's Accept-Encoding header. If two offers match with equal weight and\n// then the offer earlier in the list is preferred. If no offers are\n// acceptable, then \"\" is returned.\nfunc negotiateContentEncoding(r *http.Request, offers []string) string {\n\tbestOffer := \"identity\"\n\tbestQ := -1.0\n\tspecs := parseAccept(r.Header, \"Accept-Encoding\")\n\tfor _, offer := range offers {\n\t\tfor _, spec := range specs {\n\t\t\tif spec.Q > bestQ &&\n\t\t\t\t(spec.Value == \"*\" || spec.Value == offer) {\n\t\t\t\tbestQ = spec.Q\n\t\t\t\tbestOffer = offer\n\t\t\t}\n\t\t}\n\t}\n\tif bestQ == 0 {\n\t\tbestOffer = \"\"\n\t}\n\treturn bestOffer\n}\n\n// acceptSpec describes an Accept* header.\ntype acceptSpec struct {\n\tValue string\n\tQ     float64\n}\n\n// parseAccept parses Accept* headers.\nfunc parseAccept(header http.Header, key string) (specs []acceptSpec) {\nloop:\n\tfor _, s := range header[key] {\n\t\tfor {\n\t\t\tvar spec acceptSpec\n\t\t\tspec.Value, s = expectTokenSlash(s)\n\t\t\tif spec.Value == \"\" {\n\t\t\t\tcontinue loop\n\t\t\t}\n\t\t\tspec.Q = 1.0\n\t\t\ts = skipSpace(s)\n\t\t\tif strings.HasPrefix(s, \";\") {\n\t\t\t\ts = skipSpace(s[1:])\n\t\t\t\tif !strings.HasPrefix(s, \"q=\") {\n\t\t\t\t\tcontinue loop\n\t\t\t\t}\n\t\t\t\tspec.Q, s = expectQuality(s[2:])\n\t\t\t\tif spec.Q < 0.0 {\n\t\t\t\t\tcontinue loop\n\t\t\t\t}\n\t\t\t}\n\t\t\tspecs = append(specs, spec)\n\t\t\ts = skipSpace(s)\n\t\t\tif !strings.HasPrefix(s, \",\") {\n\t\t\t\tcontinue loop\n\t\t\t}\n\t\t\ts = skipSpace(s[1:])\n\t\t}\n\t}\n\treturn\n}\n\nfunc skipSpace(s string) (rest string) {\n\ti := 0\n\tfor ; i < len(s); i++ {\n\t\tif octetTypes[s[i]]&isSpace == 0 {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn s[i:]\n}\n\nfunc expectTokenSlash(s string) (token, rest string) {\n\ti := 0\n\tfor ; i < len(s); i++ {\n\t\tb := s[i]\n\t\tif (octetTypes[b]&isToken == 0) && b != '/' {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn s[:i], s[i:]\n}\n\nfunc expectQuality(s string) (q float64, rest string) {\n\tswitch {\n\tcase len(s) == 0:\n\t\treturn -1, \"\"\n\tcase s[0] == '0':\n\t\tq = 0\n\tcase s[0] == '1':\n\t\tq = 1\n\tdefault:\n\t\treturn -1, \"\"\n\t}\n\ts = s[1:]\n\tif !strings.HasPrefix(s, \".\") {\n\t\treturn q, s\n\t}\n\ts = s[1:]\n\ti := 0\n\tn := 0\n\td := 1\n\tfor ; i < len(s); i++ {\n\t\tb := s[i]\n\t\tif b < '0' || b > '9' {\n\t\t\tbreak\n\t\t}\n\t\tn = n*10 + int(b) - '0'\n\t\td *= 10\n\t}\n\treturn q + float64(n)/float64(d), s[i:]\n}\n\n// Octet types from RFC 2616.\nvar octetTypes [256]octetType\n\ntype octetType byte\n\nconst (\n\tisToken octetType = 1 << iota\n\tisSpace\n)\n\nfunc init() {\n\t// OCTET      = <any 8-bit sequence of data>\n\t// CHAR       = <any US-ASCII character (octets 0 - 127)>\n\t// CTL        = <any US-ASCII control character (octets 0 - 31) and DEL (127)>\n\t// CR         = <US-ASCII CR, carriage return (13)>\n\t// LF         = <US-ASCII LF, linefeed (10)>\n\t// SP         = <US-ASCII SP, space (32)>\n\t// HT         = <US-ASCII HT, horizontal-tab (9)>\n\t// <\">        = <US-ASCII double-quote mark (34)>\n\t// CRLF       = CR LF\n\t// LWS        = [CRLF] 1*( SP | HT )\n\t// TEXT       = <any OCTET except CTLs, but including LWS>\n\t// separators = \"(\" | \")\" | \"<\" | \">\" | \"@\" | \",\" | \";\" | \":\" | \"\\\" | <\">\n\t//              | \"/\" | \"[\" | \"]\" | \"?\" | \"=\" | \"{\" | \"}\" | SP | HT\n\t// token      = 1*<any CHAR except CTLs or separators>\n\t// qdtext     = <any TEXT except <\">>\n\n\tfor c := 0; c < 256; c++ {\n\t\tvar t octetType\n\t\tisCtl := c <= 31 || c == 127\n\t\tisChar := 0 <= c && c <= 127\n\t\tisSeparator := strings.ContainsRune(\" \\t\\\"(),/:;<=>?@[]\\\\{}\", rune(c))\n\t\tif strings.ContainsRune(\" \\t\\r\\n\", rune(c)) {\n\t\t\tt |= isSpace\n\t\t}\n\t\tif isChar && !isCtl && !isSeparator {\n\t\t\tt |= isToken\n\t\t}\n\t\toctetTypes[c] = t\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/huffman.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Utilities for building Huffman decoding tables. */\n\nconst huffmanMaxCodeLength = 15\n\n/* Maximum possible Huffman table size for an alphabet size of (index * 32),\n   max code length 15 and root table bits 8. */\nvar kMaxHuffmanTableSize = []uint16{\n\t256,\n\t402,\n\t436,\n\t468,\n\t500,\n\t534,\n\t566,\n\t598,\n\t630,\n\t662,\n\t694,\n\t726,\n\t758,\n\t790,\n\t822,\n\t854,\n\t886,\n\t920,\n\t952,\n\t984,\n\t1016,\n\t1048,\n\t1080,\n\t1112,\n\t1144,\n\t1176,\n\t1208,\n\t1240,\n\t1272,\n\t1304,\n\t1336,\n\t1368,\n\t1400,\n\t1432,\n\t1464,\n\t1496,\n\t1528,\n}\n\n/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */\nconst huffmanMaxSize26 = 396\n\n/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */\nconst huffmanMaxSize258 = 632\n\n/* BROTLI_MAX_CONTEXT_MAP_SYMBOLS == 272 */\nconst huffmanMaxSize272 = 646\n\nconst huffmanMaxCodeLengthCodeLength = 5\n\n/* Do not create this struct directly - use the ConstructHuffmanCode\n * constructor below! */\ntype huffmanCode struct {\n\tbits  byte\n\tvalue uint16\n}\n\nfunc constructHuffmanCode(bits byte, value uint16) huffmanCode {\n\tvar h huffmanCode\n\th.bits = bits\n\th.value = value\n\treturn h\n}\n\n/* Builds Huffman lookup table assuming code lengths are in symbol order. */\n\n/* Builds Huffman lookup table assuming code lengths are in symbol order.\n   Returns size of resulting table. */\n\n/* Builds a simple Huffman table. The |num_symbols| parameter is to be\n   interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,\n   2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2],\n   4 means 4 symbols with lengths [1, 2, 3, 3]. */\n\n/* Contains a collection of Huffman trees with the same alphabet size. */\n/* max_symbol is needed due to simple codes since log2(alphabet_size) could be\n   greater than log2(max_symbol). */\ntype huffmanTreeGroup struct {\n\thtrees        [][]huffmanCode\n\tcodes         []huffmanCode\n\talphabet_size uint16\n\tmax_symbol    uint16\n\tnum_htrees    uint16\n}\n\nconst reverseBitsMax = 8\n\nconst reverseBitsBase = 0\n\nvar kReverseBits = [1 << reverseBitsMax]byte{\n\t0x00,\n\t0x80,\n\t0x40,\n\t0xC0,\n\t0x20,\n\t0xA0,\n\t0x60,\n\t0xE0,\n\t0x10,\n\t0x90,\n\t0x50,\n\t0xD0,\n\t0x30,\n\t0xB0,\n\t0x70,\n\t0xF0,\n\t0x08,\n\t0x88,\n\t0x48,\n\t0xC8,\n\t0x28,\n\t0xA8,\n\t0x68,\n\t0xE8,\n\t0x18,\n\t0x98,\n\t0x58,\n\t0xD8,\n\t0x38,\n\t0xB8,\n\t0x78,\n\t0xF8,\n\t0x04,\n\t0x84,\n\t0x44,\n\t0xC4,\n\t0x24,\n\t0xA4,\n\t0x64,\n\t0xE4,\n\t0x14,\n\t0x94,\n\t0x54,\n\t0xD4,\n\t0x34,\n\t0xB4,\n\t0x74,\n\t0xF4,\n\t0x0C,\n\t0x8C,\n\t0x4C,\n\t0xCC,\n\t0x2C,\n\t0xAC,\n\t0x6C,\n\t0xEC,\n\t0x1C,\n\t0x9C,\n\t0x5C,\n\t0xDC,\n\t0x3C,\n\t0xBC,\n\t0x7C,\n\t0xFC,\n\t0x02,\n\t0x82,\n\t0x42,\n\t0xC2,\n\t0x22,\n\t0xA2,\n\t0x62,\n\t0xE2,\n\t0x12,\n\t0x92,\n\t0x52,\n\t0xD2,\n\t0x32,\n\t0xB2,\n\t0x72,\n\t0xF2,\n\t0x0A,\n\t0x8A,\n\t0x4A,\n\t0xCA,\n\t0x2A,\n\t0xAA,\n\t0x6A,\n\t0xEA,\n\t0x1A,\n\t0x9A,\n\t0x5A,\n\t0xDA,\n\t0x3A,\n\t0xBA,\n\t0x7A,\n\t0xFA,\n\t0x06,\n\t0x86,\n\t0x46,\n\t0xC6,\n\t0x26,\n\t0xA6,\n\t0x66,\n\t0xE6,\n\t0x16,\n\t0x96,\n\t0x56,\n\t0xD6,\n\t0x36,\n\t0xB6,\n\t0x76,\n\t0xF6,\n\t0x0E,\n\t0x8E,\n\t0x4E,\n\t0xCE,\n\t0x2E,\n\t0xAE,\n\t0x6E,\n\t0xEE,\n\t0x1E,\n\t0x9E,\n\t0x5E,\n\t0xDE,\n\t0x3E,\n\t0xBE,\n\t0x7E,\n\t0xFE,\n\t0x01,\n\t0x81,\n\t0x41,\n\t0xC1,\n\t0x21,\n\t0xA1,\n\t0x61,\n\t0xE1,\n\t0x11,\n\t0x91,\n\t0x51,\n\t0xD1,\n\t0x31,\n\t0xB1,\n\t0x71,\n\t0xF1,\n\t0x09,\n\t0x89,\n\t0x49,\n\t0xC9,\n\t0x29,\n\t0xA9,\n\t0x69,\n\t0xE9,\n\t0x19,\n\t0x99,\n\t0x59,\n\t0xD9,\n\t0x39,\n\t0xB9,\n\t0x79,\n\t0xF9,\n\t0x05,\n\t0x85,\n\t0x45,\n\t0xC5,\n\t0x25,\n\t0xA5,\n\t0x65,\n\t0xE5,\n\t0x15,\n\t0x95,\n\t0x55,\n\t0xD5,\n\t0x35,\n\t0xB5,\n\t0x75,\n\t0xF5,\n\t0x0D,\n\t0x8D,\n\t0x4D,\n\t0xCD,\n\t0x2D,\n\t0xAD,\n\t0x6D,\n\t0xED,\n\t0x1D,\n\t0x9D,\n\t0x5D,\n\t0xDD,\n\t0x3D,\n\t0xBD,\n\t0x7D,\n\t0xFD,\n\t0x03,\n\t0x83,\n\t0x43,\n\t0xC3,\n\t0x23,\n\t0xA3,\n\t0x63,\n\t0xE3,\n\t0x13,\n\t0x93,\n\t0x53,\n\t0xD3,\n\t0x33,\n\t0xB3,\n\t0x73,\n\t0xF3,\n\t0x0B,\n\t0x8B,\n\t0x4B,\n\t0xCB,\n\t0x2B,\n\t0xAB,\n\t0x6B,\n\t0xEB,\n\t0x1B,\n\t0x9B,\n\t0x5B,\n\t0xDB,\n\t0x3B,\n\t0xBB,\n\t0x7B,\n\t0xFB,\n\t0x07,\n\t0x87,\n\t0x47,\n\t0xC7,\n\t0x27,\n\t0xA7,\n\t0x67,\n\t0xE7,\n\t0x17,\n\t0x97,\n\t0x57,\n\t0xD7,\n\t0x37,\n\t0xB7,\n\t0x77,\n\t0xF7,\n\t0x0F,\n\t0x8F,\n\t0x4F,\n\t0xCF,\n\t0x2F,\n\t0xAF,\n\t0x6F,\n\t0xEF,\n\t0x1F,\n\t0x9F,\n\t0x5F,\n\t0xDF,\n\t0x3F,\n\t0xBF,\n\t0x7F,\n\t0xFF,\n}\n\nconst reverseBitsLowest = (uint64(1) << (reverseBitsMax - 1 + reverseBitsBase))\n\n/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX),\n   where reverse(value, len) is the bit-wise reversal of the len least\n   significant bits of value. */\nfunc reverseBits8(num uint64) uint64 {\n\treturn uint64(kReverseBits[num])\n}\n\n/* Stores code in table[0], table[step], table[2*step], ..., table[end] */\n/* Assumes that end is an integer multiple of step */\nfunc replicateValue(table []huffmanCode, step int, end int, code huffmanCode) {\n\tfor {\n\t\tend -= step\n\t\ttable[end] = code\n\t\tif end <= 0 {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n/* Returns the table width of the next 2nd level table. |count| is the histogram\n   of bit lengths for the remaining symbols, |len| is the code length of the\n   next processed symbol. */\nfunc nextTableBitSize(count []uint16, len int, root_bits int) int {\n\tvar left int = 1 << uint(len-root_bits)\n\tfor len < huffmanMaxCodeLength {\n\t\tleft -= int(count[len])\n\t\tif left <= 0 {\n\t\t\tbreak\n\t\t}\n\t\tlen++\n\t\tleft <<= 1\n\t}\n\n\treturn len - root_bits\n}\n\nfunc buildCodeLengthsHuffmanTable(table []huffmanCode, code_lengths []byte, count []uint16) {\n\tvar code huffmanCode /* current table entry */ /* symbol index in original or sorted table */ /* prefix code */ /* prefix code addend */ /* step size to replicate values in current table */ /* size of current table */ /* symbols sorted by code length */\n\tvar symbol int\n\tvar key uint64\n\tvar key_step uint64\n\tvar step int\n\tvar table_size int\n\tvar sorted [codeLengthCodes]int\n\tvar offset [huffmanMaxCodeLengthCodeLength + 1]int\n\tvar bits int\n\tvar bits_count int\n\t/* offsets in sorted table for each length */\n\tassert(huffmanMaxCodeLengthCodeLength <= reverseBitsMax)\n\n\t/* Generate offsets into sorted symbol table by code length. */\n\tsymbol = -1\n\n\tbits = 1\n\tvar i int\n\tfor i = 0; i < huffmanMaxCodeLengthCodeLength; i++ {\n\t\tsymbol += int(count[bits])\n\t\toffset[bits] = symbol\n\t\tbits++\n\t}\n\n\t/* Symbols with code length 0 are placed after all other symbols. */\n\toffset[0] = codeLengthCodes - 1\n\n\t/* Sort symbols by length, by symbol order within each length. */\n\tsymbol = codeLengthCodes\n\n\tfor {\n\t\tvar i int\n\t\tfor i = 0; i < 6; i++ {\n\t\t\tsymbol--\n\t\t\tsorted[offset[code_lengths[symbol]]] = symbol\n\t\t\toffset[code_lengths[symbol]]--\n\t\t}\n\t\tif symbol == 0 {\n\t\t\tbreak\n\t\t}\n\t}\n\n\ttable_size = 1 << huffmanMaxCodeLengthCodeLength\n\n\t/* Special case: all symbols but one have 0 code length. */\n\tif offset[0] == 0 {\n\t\tcode = constructHuffmanCode(0, uint16(sorted[0]))\n\t\tfor key = 0; key < uint64(table_size); key++ {\n\t\t\ttable[key] = code\n\t\t}\n\n\t\treturn\n\t}\n\n\t/* Fill in table. */\n\tkey = 0\n\n\tkey_step = reverseBitsLowest\n\tsymbol = 0\n\tbits = 1\n\tstep = 2\n\tfor {\n\t\tfor bits_count = int(count[bits]); bits_count != 0; bits_count-- {\n\t\t\tcode = constructHuffmanCode(byte(bits), uint16(sorted[symbol]))\n\t\t\tsymbol++\n\t\t\treplicateValue(table[reverseBits8(key):], step, table_size, code)\n\t\t\tkey += key_step\n\t\t}\n\n\t\tstep <<= 1\n\t\tkey_step >>= 1\n\t\tbits++\n\t\tif bits > huffmanMaxCodeLengthCodeLength {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc buildHuffmanTable(root_table []huffmanCode, root_bits int, symbol_lists symbolList, count []uint16) uint32 {\n\tvar code huffmanCode /* current table entry */ /* next available space in table */ /* current code length */ /* symbol index in original or sorted table */ /* prefix code */ /* prefix code addend */ /* 2nd level table prefix code */ /* 2nd level table prefix code addend */ /* step size to replicate values in current table */ /* key length of current table */ /* size of current table */ /* sum of root table size and 2nd level table sizes */\n\tvar table []huffmanCode\n\tvar len int\n\tvar symbol int\n\tvar key uint64\n\tvar key_step uint64\n\tvar sub_key uint64\n\tvar sub_key_step uint64\n\tvar step int\n\tvar table_bits int\n\tvar table_size int\n\tvar total_size int\n\tvar max_length int = -1\n\tvar bits int\n\tvar bits_count int\n\n\tassert(root_bits <= reverseBitsMax)\n\tassert(huffmanMaxCodeLength-root_bits <= reverseBitsMax)\n\n\tfor symbolListGet(symbol_lists, max_length) == 0xFFFF {\n\t\tmax_length--\n\t}\n\tmax_length += huffmanMaxCodeLength + 1\n\n\ttable = root_table\n\ttable_bits = root_bits\n\ttable_size = 1 << uint(table_bits)\n\ttotal_size = table_size\n\n\t/* Fill in the root table. Reduce the table size to if possible,\n\t   and create the repetitions by memcpy. */\n\tif table_bits > max_length {\n\t\ttable_bits = max_length\n\t\ttable_size = 1 << uint(table_bits)\n\t}\n\n\tkey = 0\n\tkey_step = reverseBitsLowest\n\tbits = 1\n\tstep = 2\n\tfor {\n\t\tsymbol = bits - (huffmanMaxCodeLength + 1)\n\t\tfor bits_count = int(count[bits]); bits_count != 0; bits_count-- {\n\t\t\tsymbol = int(symbolListGet(symbol_lists, symbol))\n\t\t\tcode = constructHuffmanCode(byte(bits), uint16(symbol))\n\t\t\treplicateValue(table[reverseBits8(key):], step, table_size, code)\n\t\t\tkey += key_step\n\t\t}\n\n\t\tstep <<= 1\n\t\tkey_step >>= 1\n\t\tbits++\n\t\tif bits > table_bits {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t/* If root_bits != table_bits then replicate to fill the remaining slots. */\n\tfor total_size != table_size {\n\t\tcopy(table[table_size:], table[:uint(table_size)])\n\t\ttable_size <<= 1\n\t}\n\n\t/* Fill in 2nd level tables and add pointers to root table. */\n\tkey_step = reverseBitsLowest >> uint(root_bits-1)\n\n\tsub_key = reverseBitsLowest << 1\n\tsub_key_step = reverseBitsLowest\n\tlen = root_bits + 1\n\tstep = 2\n\tfor ; len <= max_length; len++ {\n\t\tsymbol = len - (huffmanMaxCodeLength + 1)\n\t\tfor ; count[len] != 0; count[len]-- {\n\t\t\tif sub_key == reverseBitsLowest<<1 {\n\t\t\t\ttable = table[table_size:]\n\t\t\t\ttable_bits = nextTableBitSize(count, int(len), root_bits)\n\t\t\t\ttable_size = 1 << uint(table_bits)\n\t\t\t\ttotal_size += table_size\n\t\t\t\tsub_key = reverseBits8(key)\n\t\t\t\tkey += key_step\n\t\t\t\troot_table[sub_key] = constructHuffmanCode(byte(table_bits+root_bits), uint16(uint64(uint(-cap(table)+cap(root_table)))-sub_key))\n\t\t\t\tsub_key = 0\n\t\t\t}\n\n\t\t\tsymbol = int(symbolListGet(symbol_lists, symbol))\n\t\t\tcode = constructHuffmanCode(byte(len-root_bits), uint16(symbol))\n\t\t\treplicateValue(table[reverseBits8(sub_key):], step, table_size, code)\n\t\t\tsub_key += sub_key_step\n\t\t}\n\n\t\tstep <<= 1\n\t\tsub_key_step >>= 1\n\t}\n\n\treturn uint32(total_size)\n}\n\nfunc buildSimpleHuffmanTable(table []huffmanCode, root_bits int, val []uint16, num_symbols uint32) uint32 {\n\tvar table_size uint32 = 1\n\tvar goal_size uint32 = 1 << uint(root_bits)\n\tswitch num_symbols {\n\tcase 0:\n\t\ttable[0] = constructHuffmanCode(0, val[0])\n\n\tcase 1:\n\t\tif val[1] > val[0] {\n\t\t\ttable[0] = constructHuffmanCode(1, val[0])\n\t\t\ttable[1] = constructHuffmanCode(1, val[1])\n\t\t} else {\n\t\t\ttable[0] = constructHuffmanCode(1, val[1])\n\t\t\ttable[1] = constructHuffmanCode(1, val[0])\n\t\t}\n\n\t\ttable_size = 2\n\n\tcase 2:\n\t\ttable[0] = constructHuffmanCode(1, val[0])\n\t\ttable[2] = constructHuffmanCode(1, val[0])\n\t\tif val[2] > val[1] {\n\t\t\ttable[1] = constructHuffmanCode(2, val[1])\n\t\t\ttable[3] = constructHuffmanCode(2, val[2])\n\t\t} else {\n\t\t\ttable[1] = constructHuffmanCode(2, val[2])\n\t\t\ttable[3] = constructHuffmanCode(2, val[1])\n\t\t}\n\n\t\ttable_size = 4\n\n\tcase 3:\n\t\tvar i int\n\t\tvar k int\n\t\tfor i = 0; i < 3; i++ {\n\t\t\tfor k = i + 1; k < 4; k++ {\n\t\t\t\tif val[k] < val[i] {\n\t\t\t\t\tvar t uint16 = val[k]\n\t\t\t\t\tval[k] = val[i]\n\t\t\t\t\tval[i] = t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttable[0] = constructHuffmanCode(2, val[0])\n\t\ttable[2] = constructHuffmanCode(2, val[1])\n\t\ttable[1] = constructHuffmanCode(2, val[2])\n\t\ttable[3] = constructHuffmanCode(2, val[3])\n\t\ttable_size = 4\n\n\tcase 4:\n\t\tif val[3] < val[2] {\n\t\t\tvar t uint16 = val[3]\n\t\t\tval[3] = val[2]\n\t\t\tval[2] = t\n\t\t}\n\n\t\ttable[0] = constructHuffmanCode(1, val[0])\n\t\ttable[1] = constructHuffmanCode(2, val[1])\n\t\ttable[2] = constructHuffmanCode(1, val[0])\n\t\ttable[3] = constructHuffmanCode(3, val[2])\n\t\ttable[4] = constructHuffmanCode(1, val[0])\n\t\ttable[5] = constructHuffmanCode(2, val[1])\n\t\ttable[6] = constructHuffmanCode(1, val[0])\n\t\ttable[7] = constructHuffmanCode(3, val[3])\n\t\ttable_size = 8\n\t}\n\n\tfor table_size != goal_size {\n\t\tcopy(table[table_size:], table[:uint(table_size)])\n\t\ttable_size <<= 1\n\t}\n\n\treturn goal_size\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/literal_cost.go",
    "content": "package brotli\n\nfunc utf8Position(last uint, c uint, clamp uint) uint {\n\tif c < 128 {\n\t\treturn 0 /* Next one is the 'Byte 1' again. */\n\t} else if c >= 192 { /* Next one is the 'Byte 2' of utf-8 encoding. */\n\t\treturn brotli_min_size_t(1, clamp)\n\t} else {\n\t\t/* Let's decide over the last byte if this ends the sequence. */\n\t\tif last < 0xE0 {\n\t\t\treturn 0 /* Completed two or three byte coding. */ /* Next one is the 'Byte 3' of utf-8 encoding. */\n\t\t} else {\n\t\t\treturn brotli_min_size_t(2, clamp)\n\t\t}\n\t}\n}\n\nfunc decideMultiByteStatsLevel(pos uint, len uint, mask uint, data []byte) uint {\n\tvar counts = [3]uint{0} /* should be 2, but 1 compresses better. */\n\tvar max_utf8 uint = 1\n\tvar last_c uint = 0\n\tvar i uint\n\tfor i = 0; i < len; i++ {\n\t\tvar c uint = uint(data[(pos+i)&mask])\n\t\tcounts[utf8Position(last_c, c, 2)]++\n\t\tlast_c = c\n\t}\n\n\tif counts[2] < 500 {\n\t\tmax_utf8 = 1\n\t}\n\n\tif counts[1]+counts[2] < 25 {\n\t\tmax_utf8 = 0\n\t}\n\n\treturn max_utf8\n}\n\nfunc estimateBitCostsForLiteralsUTF8(pos uint, len uint, mask uint, data []byte, cost []float32) {\n\tvar max_utf8 uint = decideMultiByteStatsLevel(pos, uint(len), mask, data)\n\t/* Bootstrap histograms. */\n\tvar histogram = [3][256]uint{[256]uint{0}}\n\tvar window_half uint = 495\n\tvar in_window uint = brotli_min_size_t(window_half, uint(len))\n\tvar in_window_utf8 = [3]uint{0}\n\t/* max_utf8 is 0 (normal ASCII single byte modeling),\n\t   1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */\n\n\tvar i uint\n\t{\n\t\tvar last_c uint = 0\n\t\tvar utf8_pos uint = 0\n\t\tfor i = 0; i < in_window; i++ {\n\t\t\tvar c uint = uint(data[(pos+i)&mask])\n\t\t\thistogram[utf8_pos][c]++\n\t\t\tin_window_utf8[utf8_pos]++\n\t\t\tutf8_pos = utf8Position(last_c, c, max_utf8)\n\t\t\tlast_c = c\n\t\t}\n\t}\n\n\t/* Compute bit costs with sliding window. */\n\tfor i = 0; i < len; i++ {\n\t\tif i >= window_half {\n\t\t\tvar c uint\n\t\t\tvar last_c uint\n\t\t\tif i < window_half+1 {\n\t\t\t\tc = 0\n\t\t\t} else {\n\t\t\t\tc = uint(data[(pos+i-window_half-1)&mask])\n\t\t\t}\n\t\t\tif i < window_half+2 {\n\t\t\t\tlast_c = 0\n\t\t\t} else {\n\t\t\t\tlast_c = uint(data[(pos+i-window_half-2)&mask])\n\t\t\t}\n\t\t\t/* Remove a byte in the past. */\n\n\t\t\tvar utf8_pos2 uint = utf8Position(last_c, c, max_utf8)\n\t\t\thistogram[utf8_pos2][data[(pos+i-window_half)&mask]]--\n\t\t\tin_window_utf8[utf8_pos2]--\n\t\t}\n\n\t\tif i+window_half < len {\n\t\t\tvar c uint = uint(data[(pos+i+window_half-1)&mask])\n\t\t\tvar last_c uint = uint(data[(pos+i+window_half-2)&mask])\n\t\t\t/* Add a byte in the future. */\n\n\t\t\tvar utf8_pos2 uint = utf8Position(last_c, c, max_utf8)\n\t\t\thistogram[utf8_pos2][data[(pos+i+window_half)&mask]]++\n\t\t\tin_window_utf8[utf8_pos2]++\n\t\t}\n\t\t{\n\t\t\tvar c uint\n\t\t\tvar last_c uint\n\t\t\tif i < 1 {\n\t\t\t\tc = 0\n\t\t\t} else {\n\t\t\t\tc = uint(data[(pos+i-1)&mask])\n\t\t\t}\n\t\t\tif i < 2 {\n\t\t\t\tlast_c = 0\n\t\t\t} else {\n\t\t\t\tlast_c = uint(data[(pos+i-2)&mask])\n\t\t\t}\n\t\t\tvar utf8_pos uint = utf8Position(last_c, c, max_utf8)\n\t\t\tvar masked_pos uint = (pos + i) & mask\n\t\t\tvar histo uint = histogram[utf8_pos][data[masked_pos]]\n\t\t\tvar lit_cost float64\n\t\t\tif histo == 0 {\n\t\t\t\thisto = 1\n\t\t\t}\n\n\t\t\tlit_cost = fastLog2(in_window_utf8[utf8_pos]) - fastLog2(histo)\n\t\t\tlit_cost += 0.02905\n\t\t\tif lit_cost < 1.0 {\n\t\t\t\tlit_cost *= 0.5\n\t\t\t\tlit_cost += 0.5\n\t\t\t}\n\n\t\t\t/* Make the first bytes more expensive -- seems to help, not sure why.\n\t\t\t   Perhaps because the entropy source is changing its properties\n\t\t\t   rapidly in the beginning of the file, perhaps because the beginning\n\t\t\t   of the data is a statistical \"anomaly\". */\n\t\t\tif i < 2000 {\n\t\t\t\tlit_cost += 0.7 - (float64(2000-i) / 2000.0 * 0.35)\n\t\t\t}\n\n\t\t\tcost[i] = float32(lit_cost)\n\t\t}\n\t}\n}\n\nfunc estimateBitCostsForLiterals(pos uint, len uint, mask uint, data []byte, cost []float32) {\n\tif isMostlyUTF8(data, pos, mask, uint(len), kMinUTF8Ratio) {\n\t\testimateBitCostsForLiteralsUTF8(pos, uint(len), mask, data, cost)\n\t\treturn\n\t} else {\n\t\tvar histogram = [256]uint{0}\n\t\tvar window_half uint = 2000\n\t\tvar in_window uint = brotli_min_size_t(window_half, uint(len))\n\t\tvar i uint\n\t\t/* Bootstrap histogram. */\n\t\tfor i = 0; i < in_window; i++ {\n\t\t\thistogram[data[(pos+i)&mask]]++\n\t\t}\n\n\t\t/* Compute bit costs with sliding window. */\n\t\tfor i = 0; i < len; i++ {\n\t\t\tvar histo uint\n\t\t\tif i >= window_half {\n\t\t\t\t/* Remove a byte in the past. */\n\t\t\t\thistogram[data[(pos+i-window_half)&mask]]--\n\n\t\t\t\tin_window--\n\t\t\t}\n\n\t\t\tif i+window_half < len {\n\t\t\t\t/* Add a byte in the future. */\n\t\t\t\thistogram[data[(pos+i+window_half)&mask]]++\n\n\t\t\t\tin_window++\n\t\t\t}\n\n\t\t\thisto = histogram[data[(pos+i)&mask]]\n\t\t\tif histo == 0 {\n\t\t\t\thisto = 1\n\t\t\t}\n\t\t\t{\n\t\t\t\tvar lit_cost float64 = fastLog2(in_window) - fastLog2(histo)\n\t\t\t\tlit_cost += 0.029\n\t\t\t\tif lit_cost < 1.0 {\n\t\t\t\t\tlit_cost *= 0.5\n\t\t\t\t\tlit_cost += 0.5\n\t\t\t\t}\n\n\t\t\t\tcost[i] = float32(lit_cost)\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/matchfinder/emitter.go",
    "content": "package matchfinder\n\n// An absoluteMatch is like a Match, but it stores indexes into the byte\n// stream instead of lengths.\ntype absoluteMatch struct {\n\t// Start is the index of the first byte.\n\tStart int\n\n\t// End is the index of the byte after the last byte\n\t// (so that End - Start = Length).\n\tEnd int\n\n\t// Match is the index of the previous data that matches\n\t// (Start - Match = Distance).\n\tMatch int\n}\n\n// A matchEmitter manages the output of matches for a MatchFinder.\ntype matchEmitter struct {\n\t// Dst is the destination slice that Matches are added to.\n\tDst []Match\n\n\t// NextEmit is the index of the next byte to emit.\n\tNextEmit int\n}\n\nfunc (e *matchEmitter) emit(m absoluteMatch) {\n\te.Dst = append(e.Dst, Match{\n\t\tUnmatched: m.Start - e.NextEmit,\n\t\tLength:    m.End - m.Start,\n\t\tDistance:  m.Start - m.Match,\n\t})\n\te.NextEmit = m.End\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/matchfinder/m0.go",
    "content": "package matchfinder\n\nimport (\n\t\"encoding/binary\"\n)\n\n// M0 is an implementation of the MatchFinder interface based\n// on the algorithm used by snappy, but modified to be more like the algorithm\n// used by compression level 0 of the brotli reference implementation.\n//\n// It has a maximum block size of 65536 bytes.\ntype M0 struct {\n\t// Lazy turns on \"lazy matching,\" for higher compression but less speed.\n\tLazy bool\n\n\tMaxDistance int\n\tMaxLength   int\n}\n\nfunc (M0) Reset() {}\n\nconst (\n\tm0HashLen = 5\n\n\tm0TableBits = 14\n\tm0TableSize = 1 << m0TableBits\n\tm0Shift     = 32 - m0TableBits\n\t// m0TableMask is redundant, but helps the compiler eliminate bounds\n\t// checks.\n\tm0TableMask = m0TableSize - 1\n)\n\nfunc (m M0) hash(data uint64) uint64 {\n\thash := (data << (64 - 8*m0HashLen)) * hashMul64\n\treturn hash >> (64 - m0TableBits)\n}\n\n// FindMatches looks for matches in src, appends them to dst, and returns dst.\n// src must not be longer than 65536 bytes.\nfunc (m M0) FindMatches(dst []Match, src []byte) []Match {\n\tconst inputMargin = 16 - 1\n\tconst minNonLiteralBlockSize = 1 + 1 + inputMargin\n\n\tif len(src) < minNonLiteralBlockSize {\n\t\tdst = append(dst, Match{\n\t\t\tUnmatched: len(src),\n\t\t})\n\t\treturn dst\n\t}\n\tif len(src) > 65536 {\n\t\tpanic(\"block too long\")\n\t}\n\n\tvar table [m0TableSize]uint16\n\n\t// sLimit is when to stop looking for offset/length copies. The inputMargin\n\t// lets us use a fast path for emitLiteral in the main loop, while we are\n\t// looking for copies.\n\tsLimit := len(src) - inputMargin\n\n\t// nextEmit is where in src the next emitLiteral should start from.\n\tnextEmit := 0\n\n\t// The encoded form must start with a literal, as there are no previous\n\t// bytes to copy, so we start looking for hash matches at s == 1.\n\ts := 1\n\tnextHash := m.hash(binary.LittleEndian.Uint64(src[s:]))\n\n\tfor {\n\t\t// Copied from the C++ snappy implementation:\n\t\t//\n\t\t// Heuristic match skipping: If 32 bytes are scanned with no matches\n\t\t// found, start looking only at every other byte. If 32 more bytes are\n\t\t// scanned (or skipped), look at every third byte, etc.. When a match\n\t\t// is found, immediately go back to looking at every byte. This is a\n\t\t// small loss (~5% performance, ~0.1% density) for compressible data\n\t\t// due to more bookkeeping, but for non-compressible data (such as\n\t\t// JPEG) it's a huge win since the compressor quickly \"realizes\" the\n\t\t// data is incompressible and doesn't bother looking for matches\n\t\t// everywhere.\n\t\t//\n\t\t// The \"skip\" variable keeps track of how many bytes there are since\n\t\t// the last match; dividing it by 32 (ie. right-shifting by five) gives\n\t\t// the number of bytes to move ahead for each iteration.\n\t\tskip := 32\n\n\t\tnextS := s\n\t\tcandidate := 0\n\t\tfor {\n\t\t\ts = nextS\n\t\t\tbytesBetweenHashLookups := skip >> 5\n\t\t\tnextS = s + bytesBetweenHashLookups\n\t\t\tskip += bytesBetweenHashLookups\n\t\t\tif nextS > sLimit {\n\t\t\t\tgoto emitRemainder\n\t\t\t}\n\t\t\tcandidate = int(table[nextHash&m0TableMask])\n\t\t\ttable[nextHash&m0TableMask] = uint16(s)\n\t\t\tnextHash = m.hash(binary.LittleEndian.Uint64(src[nextS:]))\n\t\t\tif m.MaxDistance != 0 && s-candidate > m.MaxDistance {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif binary.LittleEndian.Uint32(src[s:]) == binary.LittleEndian.Uint32(src[candidate:]) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// Invariant: we have a 4-byte match at s.\n\t\tbase := s\n\t\ts = extendMatch(src, candidate+4, s+4)\n\n\t\torigBase := base\n\t\tif m.Lazy && base+1 < sLimit {\n\t\t\tnewBase := base + 1\n\t\t\th := m.hash(binary.LittleEndian.Uint64(src[newBase:]))\n\t\t\tnewCandidate := int(table[h&m0TableMask])\n\t\t\ttable[h&m0TableMask] = uint16(newBase)\n\t\t\tokDistance := true\n\t\t\tif m.MaxDistance != 0 && newBase-newCandidate > m.MaxDistance {\n\t\t\t\tokDistance = false\n\t\t\t}\n\t\t\tif okDistance && binary.LittleEndian.Uint32(src[newBase:]) == binary.LittleEndian.Uint32(src[newCandidate:]) {\n\t\t\t\tnewS := extendMatch(src, newCandidate+4, newBase+4)\n\t\t\t\tif newS-newBase > s-base+1 {\n\t\t\t\t\ts = newS\n\t\t\t\t\tbase = newBase\n\t\t\t\t\tcandidate = newCandidate\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif m.MaxLength != 0 && s-base > m.MaxLength {\n\t\t\ts = base + m.MaxLength\n\t\t}\n\t\tdst = append(dst, Match{\n\t\t\tUnmatched: base - nextEmit,\n\t\t\tLength:    s - base,\n\t\t\tDistance:  base - candidate,\n\t\t})\n\t\tnextEmit = s\n\t\tif s >= sLimit {\n\t\t\tgoto emitRemainder\n\t\t}\n\n\t\tif m.Lazy {\n\t\t\t// If lazy matching is enabled, we update the hash table for\n\t\t\t// every byte in the match.\n\t\t\tfor i := origBase + 2; i < s-1; i++ {\n\t\t\t\tx := binary.LittleEndian.Uint64(src[i:])\n\t\t\t\ttable[m.hash(x)&m0TableMask] = uint16(i)\n\t\t\t}\n\t\t}\n\n\t\t// We could immediately start working at s now, but to improve\n\t\t// compression we first update the hash table at s-1 and at s.\n\t\tx := binary.LittleEndian.Uint64(src[s-1:])\n\t\tprevHash := m.hash(x >> 0)\n\t\ttable[prevHash&m0TableMask] = uint16(s - 1)\n\t\tnextHash = m.hash(x >> 8)\n\t}\n\nemitRemainder:\n\tif nextEmit < len(src) {\n\t\tdst = append(dst, Match{\n\t\t\tUnmatched: len(src) - nextEmit,\n\t\t})\n\t}\n\treturn dst\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/matchfinder/m4.go",
    "content": "package matchfinder\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"math/bits\"\n\t\"runtime\"\n)\n\n// M4 is an implementation of the MatchFinder\n// interface that uses a hash table to find matches,\n// optional match chains,\n// and the advanced parsing technique from\n// https://fastcompression.blogspot.com/2011/12/advanced-parsing-strategies.html.\ntype M4 struct {\n\t// MaxDistance is the maximum distance (in bytes) to look back for\n\t// a match. The default is 65535.\n\tMaxDistance int\n\n\t// MinLength is the length of the shortest match to return.\n\t// The default is 4.\n\tMinLength int\n\n\t// HashLen is the number of bytes to use to calculate the hashes.\n\t// The maximum is 8 and the default is 6.\n\tHashLen int\n\n\t// TableBits is the number of bits in the hash table indexes.\n\t// The default is 17 (128K entries).\n\tTableBits int\n\n\t// ChainLength is how many entries to search on the \"match chain\" of older\n\t// locations with the same hash as the current location.\n\tChainLength int\n\n\t// DistanceBitCost is used when comparing two matches to see\n\t// which is better. The comparison is primarily based on the length\n\t// of the matches, but it can also take the distance into account,\n\t// in terms of the number of bits needed to represent the distance.\n\t// One byte of length is given a score of 256, so 32 (256/8) would\n\t// be a reasonable first guess for the value of one bit.\n\t// (The default is 0, which bases the comparison solely on length.)\n\tDistanceBitCost int\n\n\ttable []uint32\n\tchain []uint32\n\n\thistory []byte\n}\n\nfunc (q *M4) Reset() {\n\tfor i := range q.table {\n\t\tq.table[i] = 0\n\t}\n\tq.history = q.history[:0]\n\tq.chain = q.chain[:0]\n}\n\nfunc (q *M4) score(m absoluteMatch) int {\n\treturn (m.End-m.Start)*256 + (bits.LeadingZeros32(uint32(m.Start-m.Match))-32)*q.DistanceBitCost\n}\n\nfunc (q *M4) FindMatches(dst []Match, src []byte) []Match {\n\tif q.MaxDistance == 0 {\n\t\tq.MaxDistance = 65535\n\t}\n\tif q.MinLength == 0 {\n\t\tq.MinLength = 4\n\t}\n\tif q.HashLen == 0 {\n\t\tq.HashLen = 6\n\t}\n\tif q.TableBits == 0 {\n\t\tq.TableBits = 17\n\t}\n\tif len(q.table) < 1<<q.TableBits {\n\t\tq.table = make([]uint32, 1<<q.TableBits)\n\t}\n\n\te := matchEmitter{Dst: dst}\n\n\tif len(q.history) > q.MaxDistance*2 {\n\t\t// Trim down the history buffer.\n\t\tdelta := len(q.history) - q.MaxDistance\n\t\tcopy(q.history, q.history[delta:])\n\t\tq.history = q.history[:q.MaxDistance]\n\t\tif q.ChainLength > 0 {\n\t\t\tq.chain = q.chain[:q.MaxDistance]\n\t\t}\n\n\t\tfor i, v := range q.table {\n\t\t\tnewV := int(v) - delta\n\t\t\tif newV < 0 {\n\t\t\t\tnewV = 0\n\t\t\t}\n\t\t\tq.table[i] = uint32(newV)\n\t\t}\n\t}\n\n\t// Append src to the history buffer.\n\te.NextEmit = len(q.history)\n\tq.history = append(q.history, src...)\n\tif q.ChainLength > 0 {\n\t\tq.chain = append(q.chain, make([]uint32, len(src))...)\n\t}\n\tsrc = q.history\n\n\t// matches stores the matches that have been found but not emitted,\n\t// in reverse order. (matches[0] is the most recent one.)\n\tvar matches [3]absoluteMatch\n\tfor i := e.NextEmit; i < len(src)-7; i++ {\n\t\tif matches[0] != (absoluteMatch{}) && i >= matches[0].End {\n\t\t\t// We have found some matches, and we're far enough along that we probably\n\t\t\t// won't find overlapping matches, so we might as well emit them.\n\t\t\tif matches[1] != (absoluteMatch{}) {\n\t\t\t\tif matches[1].End > matches[0].Start {\n\t\t\t\t\tmatches[1].End = matches[0].Start\n\t\t\t\t}\n\t\t\t\tif matches[1].End-matches[1].Start >= q.MinLength && q.score(matches[1]) > 0 {\n\t\t\t\t\te.emit(matches[1])\n\t\t\t\t}\n\t\t\t}\n\t\t\te.emit(matches[0])\n\t\t\tmatches = [3]absoluteMatch{}\n\t\t}\n\n\t\t// Look for a repeat match one byte after the current position.\n\t\tif matches[0] == (absoluteMatch{}) && len(e.Dst) > 0 {\n\t\t\tprevDistance := e.Dst[len(e.Dst)-1].Distance\n\t\t\tif binary.LittleEndian.Uint32(src[i+1:]) == binary.LittleEndian.Uint32(src[i+1-prevDistance:]) {\n\t\t\t\t// We have a 4-byte match.\n\t\t\t\tm := extendMatch2(src, i+1, i+1-prevDistance, e.NextEmit+1)\n\t\t\t\tif m.End-m.Start >= q.MinLength {\n\t\t\t\t\tmatches[0] = m\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Calculate and store the hash.\n\t\th := ((binary.LittleEndian.Uint64(src[i:]) & (1<<(8*q.HashLen) - 1)) * hashMul64) >> (64 - q.TableBits)\n\t\tcandidate := int(q.table[h])\n\t\tq.table[h] = uint32(i)\n\t\tif q.ChainLength > 0 && candidate != 0 {\n\t\t\tdelta := i - candidate\n\t\t\tq.chain[i] = uint32(delta)\n\t\t}\n\n\t\tif i < matches[0].End && i != matches[0].End+2-q.HashLen {\n\t\t\tcontinue\n\t\t}\n\t\tif candidate == 0 || i-candidate > q.MaxDistance {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Look for a match.\n\t\tvar currentMatch absoluteMatch\n\n\t\tif binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {\n\t\t\tm := extendMatch2(src, i, candidate, e.NextEmit)\n\t\t\tif m.End-m.Start > q.MinLength && q.score(m) > 0 {\n\t\t\t\tcurrentMatch = m\n\t\t\t}\n\t\t}\n\n\t\tfor j := 0; j < q.ChainLength; j++ {\n\t\t\tdelta := q.chain[candidate]\n\t\t\tif delta == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcandidate -= int(delta)\n\t\t\tif candidate <= 0 || i-candidate > q.MaxDistance {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {\n\t\t\t\tm := extendMatch2(src, i, candidate, e.NextEmit)\n\t\t\t\tif m.End-m.Start > q.MinLength && q.score(m) > q.score(currentMatch) {\n\t\t\t\t\tcurrentMatch = m\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif currentMatch.End-currentMatch.Start < q.MinLength {\n\t\t\tcontinue\n\t\t}\n\n\t\toverlapPenalty := 0\n\t\tif matches[0] != (absoluteMatch{}) {\n\t\t\toverlapPenalty = 275\n\t\t\tif currentMatch.Start <= matches[1].End {\n\t\t\t\t// This match would completely replace the previous match,\n\t\t\t\t// so there is no penalty for overlap.\n\t\t\t\toverlapPenalty = 0\n\t\t\t}\n\t\t}\n\n\t\tif q.score(currentMatch) <= q.score(matches[0])+overlapPenalty {\n\t\t\tcontinue\n\t\t}\n\n\t\tmatches = [3]absoluteMatch{\n\t\t\tcurrentMatch,\n\t\t\tmatches[0],\n\t\t\tmatches[1],\n\t\t}\n\n\t\tif matches[2] == (absoluteMatch{}) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// We have three matches, so it's time to emit one and/or eliminate one.\n\t\tswitch {\n\t\tcase matches[0].Start < matches[2].End:\n\t\t\t// The first and third matches overlap; discard the one in between.\n\t\t\tmatches = [3]absoluteMatch{\n\t\t\t\tmatches[0],\n\t\t\t\tmatches[2],\n\t\t\t\tabsoluteMatch{},\n\t\t\t}\n\n\t\tcase matches[0].Start < matches[2].End+q.MinLength:\n\t\t\t// The first and third matches don't overlap, but there's no room for\n\t\t\t// another match between them. Emit the first match and discard the second.\n\t\t\te.emit(matches[2])\n\t\t\tmatches = [3]absoluteMatch{\n\t\t\t\tmatches[0],\n\t\t\t\tabsoluteMatch{},\n\t\t\t\tabsoluteMatch{},\n\t\t\t}\n\n\t\tdefault:\n\t\t\t// Emit the first match, shortening it if necessary to avoid overlap with the second.\n\t\t\tif matches[2].End > matches[1].Start {\n\t\t\t\tmatches[2].End = matches[1].Start\n\t\t\t\tif q.ChainLength > 0 && matches[2].End-matches[2].Start >= q.MinLength {\n\t\t\t\t\t// Since the match length was trimmed, we may be able to find a closer match\n\t\t\t\t\t// to replace it.\n\t\t\t\t\tpos := matches[2].Start\n\t\t\t\t\tfor {\n\t\t\t\t\t\tdelta := int(q.chain[pos])\n\t\t\t\t\t\tif delta == 0 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpos -= delta\n\t\t\t\t\t\tif pos <= matches[2].Match {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif bytes.Equal(src[matches[2].Start:matches[2].End], src[pos:pos+matches[2].End-matches[2].Start]) {\n\t\t\t\t\t\t\tmatches[2].Match = pos\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif matches[2].End-matches[2].Start >= q.MinLength && q.score(matches[2]) > 0 {\n\t\t\t\te.emit(matches[2])\n\t\t\t}\n\t\t\tmatches[2] = absoluteMatch{}\n\t\t}\n\t}\n\n\t// We've found all the matches now; emit the remaining ones.\n\tif matches[1] != (absoluteMatch{}) {\n\t\tif matches[1].End > matches[0].Start {\n\t\t\tmatches[1].End = matches[0].Start\n\t\t}\n\t\tif matches[1].End-matches[1].Start >= q.MinLength && q.score(matches[1]) > 0 {\n\t\t\te.emit(matches[1])\n\t\t}\n\t}\n\tif matches[0] != (absoluteMatch{}) {\n\t\te.emit(matches[0])\n\t}\n\n\tdst = e.Dst\n\tif e.NextEmit < len(src) {\n\t\tdst = append(dst, Match{\n\t\t\tUnmatched: len(src) - e.NextEmit,\n\t\t})\n\t}\n\n\treturn dst\n}\n\nconst hashMul64 = 0x1E35A7BD1E35A7BD\n\n// extendMatch returns the largest k such that k <= len(src) and that\n// src[i:i+k-j] and src[j:k] have the same contents.\n//\n// It assumes that:\n//\n//\t0 <= i && i < j && j <= len(src)\nfunc extendMatch(src []byte, i, j int) int {\n\tswitch runtime.GOARCH {\n\tcase \"amd64\", \"arm64\":\n\t\t// As long as we are 8 or more bytes before the end of src, we can load and\n\t\t// compare 8 bytes at a time. If those 8 bytes are equal, repeat.\n\t\tfor j+8 < len(src) {\n\t\t\tiBytes := binary.LittleEndian.Uint64(src[i:])\n\t\t\tjBytes := binary.LittleEndian.Uint64(src[j:])\n\t\t\tif iBytes != jBytes {\n\t\t\t\t// If those 8 bytes were not equal, XOR the two 8 byte values, and return\n\t\t\t\t// the index of the first byte that differs. The BSF instruction finds the\n\t\t\t\t// least significant 1 bit, the amd64 architecture is little-endian, and\n\t\t\t\t// the shift by 3 converts a bit index to a byte index.\n\t\t\t\treturn j + bits.TrailingZeros64(iBytes^jBytes)>>3\n\t\t\t}\n\t\t\ti, j = i+8, j+8\n\t\t}\n\tcase \"386\":\n\t\t// On a 32-bit CPU, we do it 4 bytes at a time.\n\t\tfor j+4 < len(src) {\n\t\t\tiBytes := binary.LittleEndian.Uint32(src[i:])\n\t\t\tjBytes := binary.LittleEndian.Uint32(src[j:])\n\t\t\tif iBytes != jBytes {\n\t\t\t\treturn j + bits.TrailingZeros32(iBytes^jBytes)>>3\n\t\t\t}\n\t\t\ti, j = i+4, j+4\n\t\t}\n\t}\n\tfor ; j < len(src) && src[i] == src[j]; i, j = i+1, j+1 {\n\t}\n\treturn j\n}\n\n// Given a 4-byte match at src[start] and src[candidate], extendMatch2 extends it\n// upward as far as possible, and downward no farther than to min.\nfunc extendMatch2(src []byte, start, candidate, min int) absoluteMatch {\n\tend := extendMatch(src, candidate+4, start+4)\n\tfor start > min && candidate > 0 && src[start-1] == src[candidate-1] {\n\t\tstart--\n\t\tcandidate--\n\t}\n\treturn absoluteMatch{\n\t\tStart: start,\n\t\tEnd:   end,\n\t\tMatch: candidate,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/matchfinder/matchfinder.go",
    "content": "// The matchfinder package defines reusable components for data compression.\n//\n// Many compression libraries have two main parts:\n//   - Something that looks for repeated sequences of bytes\n//   - An encoder for the compressed data format (often an entropy coder)\n//\n// Although these are logically two separate steps, the implementations are\n// usually closely tied together. You can't use flate's matcher with snappy's\n// encoder, for example. This package defines interfaces and an intermediate\n// representation to allow mixing and matching compression components.\npackage matchfinder\n\nimport \"io\"\n\n// A Match is the basic unit of LZ77 compression.\ntype Match struct {\n\tUnmatched int // the number of unmatched bytes since the previous match\n\tLength    int // the number of bytes in the matched string; it may be 0 at the end of the input\n\tDistance  int // how far back in the stream to copy from\n}\n\n// A MatchFinder performs the LZ77 stage of compression, looking for matches.\ntype MatchFinder interface {\n\t// FindMatches looks for matches in src, appends them to dst, and returns dst.\n\tFindMatches(dst []Match, src []byte) []Match\n\n\t// Reset clears any internal state, preparing the MatchFinder to be used with\n\t// a new stream.\n\tReset()\n}\n\n// An Encoder encodes the data in its final format.\ntype Encoder interface {\n\t// Encode appends the encoded format of src to dst, using the match\n\t// information from matches.\n\tEncode(dst []byte, src []byte, matches []Match, lastBlock bool) []byte\n\n\t// Reset clears any internal state, preparing the Encoder to be used with\n\t// a new stream.\n\tReset()\n}\n\n// A Writer uses MatchFinder and Encoder to write compressed data to Dest.\ntype Writer struct {\n\tDest        io.Writer\n\tMatchFinder MatchFinder\n\tEncoder     Encoder\n\n\t// BlockSize is the number of bytes to compress at a time. If it is zero,\n\t// each Write operation will be treated as one block.\n\tBlockSize int\n\n\terr     error\n\tinBuf   []byte\n\toutBuf  []byte\n\tmatches []Match\n}\n\nfunc (w *Writer) Write(p []byte) (n int, err error) {\n\tif w.err != nil {\n\t\treturn 0, w.err\n\t}\n\n\tif w.BlockSize == 0 {\n\t\treturn w.writeBlock(p, false)\n\t}\n\n\tw.inBuf = append(w.inBuf, p...)\n\tvar pos int\n\tfor pos = 0; pos+w.BlockSize <= len(w.inBuf) && w.err == nil; pos += w.BlockSize {\n\t\tw.writeBlock(w.inBuf[pos:pos+w.BlockSize], false)\n\t}\n\tif pos > 0 {\n\t\tn := copy(w.inBuf, w.inBuf[pos:])\n\t\tw.inBuf = w.inBuf[:n]\n\t}\n\n\treturn len(p), w.err\n}\n\nfunc (w *Writer) writeBlock(p []byte, lastBlock bool) (n int, err error) {\n\tw.outBuf = w.outBuf[:0]\n\tw.matches = w.MatchFinder.FindMatches(w.matches[:0], p)\n\tw.outBuf = w.Encoder.Encode(w.outBuf, p, w.matches, lastBlock)\n\t_, w.err = w.Dest.Write(w.outBuf)\n\treturn len(p), w.err\n}\n\nfunc (w *Writer) Close() error {\n\tw.writeBlock(w.inBuf, true)\n\tw.inBuf = w.inBuf[:0]\n\treturn w.err\n}\n\nfunc (w *Writer) Reset(newDest io.Writer) {\n\tw.MatchFinder.Reset()\n\tw.Encoder.Reset()\n\tw.err = nil\n\tw.inBuf = w.inBuf[:0]\n\tw.outBuf = w.outBuf[:0]\n\tw.matches = w.matches[:0]\n\tw.Dest = newDest\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/matchfinder/pathfinder.go",
    "content": "package matchfinder\n\nimport (\n\t\"encoding/binary\"\n\t\"math\"\n\t\"math/bits\"\n\t\"slices\"\n)\n\n// Pathfinder is a MatchFinder that uses hash chains to find matches, and a\n// shortest-path optimizer to choose which matches to use.\ntype Pathfinder struct {\n\t// MaxDistance is the maximum distance (in bytes) to look back for\n\t// a match. The default is 65535.\n\tMaxDistance int\n\n\t// MinLength is the length of the shortest match to return.\n\t// The default is 4.\n\tMinLength int\n\n\t// HashLen is the number of bytes to use to calculate the hashes.\n\t// The maximum is 8 and the default is 6.\n\tHashLen int\n\n\t// TableBits is the number of bits in the hash table indexes.\n\t// The default is 17 (128K entries).\n\tTableBits int\n\n\t// ChainLength is how many entries to search on the \"match chain\" of older\n\t// locations with the same hash as the current location.\n\tChainLength int\n\n\ttable []uint32\n\tchain []uint32\n\n\thistory []byte\n\n\t// holding onto buffers to reduce allocations:\n\n\tarrivals     []arrival\n\tfoundMatches []absoluteMatch\n\tmatches      []Match\n}\n\nfunc (q *Pathfinder) Reset() {\n\tfor i := range q.table {\n\t\tq.table[i] = 0\n\t}\n\tq.history = q.history[:0]\n\tq.chain = q.chain[:0]\n}\n\n// An arrival represents how we got to a certain byte position.\n// The cost is the total cost to get there from the beginning of the block.\n// If distance > 0, the arrival is with a match.\n// If distance == 0, the arrival is with a run of literals.\ntype arrival struct {\n\tlength   uint32\n\tdistance uint32\n\tcost     float32\n}\n\nconst (\n\tbaseMatchCost float32 = 4\n)\n\nfunc (q *Pathfinder) FindMatches(dst []Match, src []byte) []Match {\n\tif q.MaxDistance == 0 {\n\t\tq.MaxDistance = 65535\n\t}\n\tif q.MinLength == 0 {\n\t\tq.MinLength = 4\n\t}\n\tif q.HashLen == 0 {\n\t\tq.HashLen = 6\n\t}\n\tif q.TableBits == 0 {\n\t\tq.TableBits = 17\n\t}\n\tif len(q.table) < 1<<q.TableBits {\n\t\tq.table = make([]uint32, 1<<q.TableBits)\n\t}\n\n\tvar histogram [256]uint32\n\tfor _, b := range src {\n\t\thistogram[b]++\n\t}\n\tvar byteCost [256]float32\n\tfor b, n := range histogram {\n\t\tcost := max(math.Log2(float64(len(src))/float64(n)), 1)\n\t\tbyteCost[b] = float32(cost)\n\t}\n\n\t// Each element in arrivals corresponds to the position just after\n\t// the corresponding byte in src.\n\tarrivals := q.arrivals\n\tif len(arrivals) < len(src) {\n\t\tarrivals = make([]arrival, len(src))\n\t\tq.arrivals = arrivals\n\t} else {\n\t\tarrivals = arrivals[:len(src)]\n\t\tfor i := range arrivals {\n\t\t\tarrivals[i] = arrival{}\n\t\t}\n\t}\n\n\tif len(q.history) > q.MaxDistance*2 {\n\t\t// Trim down the history buffer.\n\t\tdelta := len(q.history) - q.MaxDistance\n\t\tcopy(q.history, q.history[delta:])\n\t\tq.history = q.history[:q.MaxDistance]\n\t\tq.chain = q.chain[:q.MaxDistance]\n\n\t\tfor i, v := range q.table {\n\t\t\tnewV := max(int(v)-delta, 0)\n\t\t\tq.table[i] = uint32(newV)\n\t\t}\n\t}\n\n\t// Append src to the history buffer.\n\thistoryLen := len(q.history)\n\tq.history = append(q.history, src...)\n\tq.chain = append(q.chain, make([]uint32, len(src))...)\n\tsrc = q.history\n\n\t// Calculate hashes and build the chain.\n\tfor i := historyLen; i < len(src)-7; i++ {\n\t\th := ((binary.LittleEndian.Uint64(src[i:]) & (1<<(8*q.HashLen) - 1)) * hashMul64) >> (64 - q.TableBits)\n\t\tcandidate := int(q.table[h])\n\t\tq.table[h] = uint32(i)\n\t\tif candidate != 0 {\n\t\t\tdelta := i - candidate\n\t\t\tq.chain[i] = uint32(delta)\n\t\t}\n\t}\n\n\t// Look for matches, and collect them in foundMatches. Later we'll figure out\n\t// which ones to actually use.\n\tfoundMatches := q.foundMatches[:0]\n\tvar prevMatch absoluteMatch\n\ti := historyLen\n\tfor i < len(src)-7 {\n\t\tdelta := q.chain[i]\n\t\tif delta == 0 {\n\t\t\ti++\n\t\t\tcontinue\n\t\t}\n\t\tcandidate := i - int(delta)\n\t\tif candidate <= 0 || i-candidate > q.MaxDistance {\n\t\t\ti++\n\t\t\tcontinue\n\t\t}\n\n\t\tvar currentMatch absoluteMatch\n\n\t\tif i >= prevMatch.End && prevMatch != (absoluteMatch{}) {\n\t\t\t// Look for a repeat match at i+1.\n\t\t\tprevDistance := prevMatch.Start - prevMatch.Match\n\t\t\tif binary.LittleEndian.Uint32(src[i+1:]) == binary.LittleEndian.Uint32(src[i+1-prevDistance:]) {\n\t\t\t\tm := extendMatch2(src, i+1, i+1-prevDistance, i+1)\n\t\t\t\tif m.End-m.Start > q.MinLength {\n\t\t\t\t\tcurrentMatch = m\n\t\t\t\t\tfoundMatches = append(foundMatches, m)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {\n\t\t\tm := extendMatch2(src, i, candidate, max(historyLen, prevMatch.Start))\n\t\t\tif m.End-m.Start > q.MinLength {\n\t\t\t\tcurrentMatch = m\n\t\t\t\tfoundMatches = append(foundMatches, m)\n\t\t\t}\n\t\t}\n\n\t\tfor range q.ChainLength {\n\t\t\tdelta := q.chain[candidate]\n\t\t\tif delta == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcandidate -= int(delta)\n\t\t\tif candidate <= 0 || i-candidate > q.MaxDistance {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif binary.LittleEndian.Uint32(src[candidate:]) == binary.LittleEndian.Uint32(src[i:]) {\n\t\t\t\tm := extendMatch2(src, i, candidate, max(historyLen, prevMatch.Start))\n\t\t\t\tif m.End-m.Start > q.MinLength && m.End-m.Start > currentMatch.End-currentMatch.Start {\n\t\t\t\t\tcurrentMatch = m\n\t\t\t\t\tfoundMatches = append(foundMatches, m)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif i < prevMatch.End && currentMatch.End-currentMatch.Start <= prevMatch.End-prevMatch.Start {\n\t\t\t// We were looking for an overlapping match, but we didn't find one longer\n\t\t\t// than the previous match. So we'll go back to sequential search,\n\t\t\t// starting right after the previous match.\n\t\t\ti = prevMatch.End\n\t\t\tcontinue\n\t\t}\n\n\t\tif currentMatch == (absoluteMatch{}) {\n\t\t\t// No match found. Continue with sequential search.\n\t\t\ti++\n\t\t\tcontinue\n\t\t}\n\n\t\t// We've found a match; now look for matches overlapping the end of it.\n\t\tprevMatch = currentMatch\n\t\ti = currentMatch.End + 2 - q.HashLen\n\t}\n\n\tq.foundMatches = foundMatches\n\n\tslices.SortFunc(foundMatches, func(a, b absoluteMatch) int { return a.Start - b.Start })\n\tmatchIndex := 0\n\tvar pending absoluteMatch\n\n\tfor i := historyLen; i < len(src); i++ {\n\t\tvar arrivedHere arrival\n\t\tif i > historyLen {\n\t\t\tarrivedHere = arrivals[i-historyLen-1]\n\t\t}\n\n\t\tunmatched := 0\n\t\tif arrivedHere.distance == 0 {\n\t\t\tunmatched = int(arrivedHere.length)\n\t\t}\n\t\tprevDistance := 0\n\t\tif i-unmatched > historyLen {\n\t\t\tprevDistance = int(arrivals[i-historyLen-1-unmatched].distance)\n\t\t}\n\n\t\tliteralCost := byteCost[src[i]]\n\t\tnextArrival := &arrivals[i-historyLen]\n\t\tif nextArrival.cost == 0 || arrivedHere.cost+literalCost < nextArrival.cost {\n\t\t\t*nextArrival = arrival{\n\t\t\t\tcost:   arrivedHere.cost + literalCost,\n\t\t\t\tlength: uint32(unmatched + 1),\n\t\t\t}\n\t\t}\n\n\t\tfor matchIndex < len(foundMatches) && foundMatches[matchIndex].Start == i {\n\t\t\tm := foundMatches[matchIndex]\n\t\t\tmatchIndex++\n\t\t\tif m.End > pending.End {\n\t\t\t\tpending = m\n\t\t\t}\n\t\t\tmatchCost := baseMatchCost + float32(bits.Len(uint(unmatched)))\n\t\t\tif m.Start-m.Match != prevDistance {\n\t\t\t\tmatchCost += float32(bits.Len(uint(m.Start - m.Match)))\n\t\t\t}\n\t\t\tfor j := m.Start + q.MinLength; j <= m.End; j++ {\n\t\t\t\tadjustedCost := matchCost\n\t\t\t\tif j-m.Start < 6 {\n\t\t\t\t\t// Matches shorter than 6 are comparatively rare, and therefore\n\t\t\t\t\t// have longer codes.\n\t\t\t\t\tadjustedCost += float32(6-(j-m.Start)) * 2\n\t\t\t\t}\n\t\t\t\ta := &arrivals[j-historyLen-1]\n\t\t\t\tif a.cost == 0 || arrivedHere.cost+adjustedCost < a.cost {\n\t\t\t\t\t*a = arrival{\n\t\t\t\t\t\tlength:   uint32(j - m.Start),\n\t\t\t\t\t\tdistance: uint32(m.Start - m.Match),\n\t\t\t\t\t\tcost:     arrivedHere.cost + adjustedCost,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If a match from an earlier position extends far enough past the current\n\t\t// position, try using the tail of it, starting from here.\n\t\tif unmatched == 0 && pending.Start != i && pending.End >= i+q.MinLength &&\n\t\t\t!(arrivedHere.length != 0 && arrivedHere.distance == uint32(pending.Start-pending.Match)) {\n\t\t\tmatchCost := baseMatchCost + float32(bits.Len(uint(pending.Start-pending.Match)))\n\t\t\tfor j := i + q.MinLength; j <= pending.End; j++ {\n\t\t\t\tadjustedCost := matchCost\n\t\t\t\tif j-i < 6 {\n\t\t\t\t\t// Matches shorter than 6 are comparatively rare, and therefore\n\t\t\t\t\t// have longer codes.\n\t\t\t\t\tadjustedCost += float32(6-(j-i)) * 2\n\t\t\t\t}\n\t\t\t\ta := &arrivals[j-historyLen-1]\n\t\t\t\tif a.cost == 0 || arrivedHere.cost+adjustedCost < a.cost {\n\t\t\t\t\t*a = arrival{\n\t\t\t\t\t\tlength:   uint32(j - i),\n\t\t\t\t\t\tdistance: uint32(pending.Start - pending.Match),\n\t\t\t\t\t\tcost:     arrivedHere.cost + adjustedCost,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdelta := q.chain[i]\n\t\tif delta == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tcandidate := i - int(delta)\n\t\tif candidate <= 0 || i-candidate > q.MaxDistance {\n\t\t\tcontinue\n\t\t}\n\t}\n\n\t// We've found the shortest path; now walk it backward and store the matches.\n\tmatches := q.matches[:0]\n\ti = len(arrivals) - 1\n\tfor i >= 0 {\n\t\ta := arrivals[i]\n\t\tif a.distance > 0 {\n\t\t\tmatches = append(matches, Match{\n\t\t\t\tLength:   int(a.length),\n\t\t\t\tDistance: int(a.distance),\n\t\t\t})\n\t\t\ti -= int(a.length)\n\t\t} else {\n\t\t\tif len(matches) == 0 {\n\t\t\t\tmatches = append(matches, Match{})\n\t\t\t}\n\t\t\tmatches[len(matches)-1].Unmatched = int(a.length)\n\t\t\ti -= int(a.length)\n\t\t}\n\t}\n\tq.matches = matches\n\n\tslices.Reverse(matches)\n\n\treturn append(dst, matches...)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/matchfinder/textencoder.go",
    "content": "package matchfinder\n\nimport \"fmt\"\n\n// A TextEncoder is an Encoder that produces a human-readable representation of\n// the LZ77 compression. Matches are replaced with <Length,Distance> symbols.\ntype TextEncoder struct{}\n\nfunc (t TextEncoder) Reset() {}\n\nfunc (t TextEncoder) Encode(dst []byte, src []byte, matches []Match, lastBlock bool) []byte {\n\tpos := 0\n\tfor _, m := range matches {\n\t\tif m.Unmatched > 0 {\n\t\t\tdst = append(dst, src[pos:pos+m.Unmatched]...)\n\t\t\tpos += m.Unmatched\n\t\t}\n\t\tif m.Length > 0 {\n\t\t\tdst = append(dst, []byte(fmt.Sprintf(\"<%d,%d>\", m.Length, m.Distance))...)\n\t\t\tpos += m.Length\n\t\t}\n\t}\n\tif pos < len(src) {\n\t\tdst = append(dst, src[pos:]...)\n\t}\n\treturn dst\n}\n\n// A NoMatchFinder implements MatchFinder, but doesn't find any matches.\n// It can be used to implement the equivalent of the standard library flate package's\n// HuffmanOnly setting.\ntype NoMatchFinder struct{}\n\nfunc (n NoMatchFinder) Reset() {}\n\nfunc (n NoMatchFinder) FindMatches(dst []Match, src []byte) []Match {\n\treturn append(dst, Match{\n\t\tUnmatched: len(src),\n\t})\n}\n\n// AutoReset wraps a MatchFinder that can return references to data in previous\n// blocks, and calls Reset before each block. It is useful for (e.g.) using a\n// snappy Encoder with a MatchFinder designed for flate. (Snappy doesn't\n// support references between blocks.)\ntype AutoReset struct {\n\tMatchFinder\n}\n\nfunc (a AutoReset) FindMatches(dst []Match, src []byte) []Match {\n\ta.Reset()\n\treturn a.MatchFinder.FindMatches(dst, src)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/memory.go",
    "content": "package brotli\n\n/* Copyright 2016 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/*\nDynamically grows array capacity to at least the requested size\nT: data type\nA: array\nC: capacity\nR: requested size\n*/\nfunc brotli_ensure_capacity_uint8_t(a *[]byte, c *uint, r uint) {\n\tif *c < r {\n\t\tvar new_size uint = *c\n\t\tif new_size == 0 {\n\t\t\tnew_size = r\n\t\t}\n\n\t\tfor new_size < r {\n\t\t\tnew_size *= 2\n\t\t}\n\n\t\tif cap(*a) < int(new_size) {\n\t\t\tvar new_array []byte = make([]byte, new_size)\n\t\t\tif *c != 0 {\n\t\t\t\tcopy(new_array, (*a)[:*c])\n\t\t\t}\n\n\t\t\t*a = new_array\n\t\t} else {\n\t\t\t*a = (*a)[:new_size]\n\t\t}\n\n\t\t*c = new_size\n\t}\n}\n\nfunc brotli_ensure_capacity_uint32_t(a *[]uint32, c *uint, r uint) {\n\tvar new_array []uint32\n\tif *c < r {\n\t\tvar new_size uint = *c\n\t\tif new_size == 0 {\n\t\t\tnew_size = r\n\t\t}\n\n\t\tfor new_size < r {\n\t\t\tnew_size *= 2\n\t\t}\n\n\t\tif cap(*a) < int(new_size) {\n\t\t\tnew_array = make([]uint32, new_size)\n\t\t\tif *c != 0 {\n\t\t\t\tcopy(new_array, (*a)[:*c])\n\t\t\t}\n\n\t\t\t*a = new_array\n\t\t} else {\n\t\t\t*a = (*a)[:new_size]\n\t\t}\n\t\t*c = new_size\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/metablock.go",
    "content": "package brotli\n\nimport (\n\t\"sync\"\n)\n\n/* Copyright 2014 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Algorithms for distributing the literals and commands of a metablock between\n   block types and contexts. */\n\ntype metaBlockSplit struct {\n\tliteral_split             blockSplit\n\tcommand_split             blockSplit\n\tdistance_split            blockSplit\n\tliteral_context_map       []uint32\n\tliteral_context_map_size  uint\n\tdistance_context_map      []uint32\n\tdistance_context_map_size uint\n\tliteral_histograms        []histogramLiteral\n\tliteral_histograms_size   uint\n\tcommand_histograms        []histogramCommand\n\tcommand_histograms_size   uint\n\tdistance_histograms       []histogramDistance\n\tdistance_histograms_size  uint\n}\n\nvar metaBlockPool sync.Pool\n\nfunc getMetaBlockSplit() *metaBlockSplit {\n\tmb, _ := metaBlockPool.Get().(*metaBlockSplit)\n\n\tif mb == nil {\n\t\tmb = &metaBlockSplit{}\n\t} else {\n\t\tinitBlockSplit(&mb.literal_split)\n\t\tinitBlockSplit(&mb.command_split)\n\t\tinitBlockSplit(&mb.distance_split)\n\t\tmb.literal_context_map = mb.literal_context_map[:0]\n\t\tmb.literal_context_map_size = 0\n\t\tmb.distance_context_map = mb.distance_context_map[:0]\n\t\tmb.distance_context_map_size = 0\n\t\tmb.literal_histograms = mb.literal_histograms[:0]\n\t\tmb.command_histograms = mb.command_histograms[:0]\n\t\tmb.distance_histograms = mb.distance_histograms[:0]\n\t}\n\treturn mb\n}\n\nfunc freeMetaBlockSplit(mb *metaBlockSplit) {\n\tmetaBlockPool.Put(mb)\n}\n\nfunc initDistanceParams(params *encoderParams, npostfix uint32, ndirect uint32) {\n\tvar dist_params *distanceParams = &params.dist\n\tvar alphabet_size uint32\n\tvar max_distance uint32\n\n\tdist_params.distance_postfix_bits = npostfix\n\tdist_params.num_direct_distance_codes = ndirect\n\n\talphabet_size = uint32(distanceAlphabetSize(uint(npostfix), uint(ndirect), maxDistanceBits))\n\tmax_distance = ndirect + (1 << (maxDistanceBits + npostfix + 2)) - (1 << (npostfix + 2))\n\n\tif params.large_window {\n\t\tvar bound = [maxNpostfix + 1]uint32{0, 4, 12, 28}\n\t\tvar postfix uint32 = 1 << npostfix\n\t\talphabet_size = uint32(distanceAlphabetSize(uint(npostfix), uint(ndirect), largeMaxDistanceBits))\n\n\t\t/* The maximum distance is set so that no distance symbol used can encode\n\t\t   a distance larger than BROTLI_MAX_ALLOWED_DISTANCE with all\n\t\t   its extra bits set. */\n\t\tif ndirect < bound[npostfix] {\n\t\t\tmax_distance = maxAllowedDistance - (bound[npostfix] - ndirect)\n\t\t} else if ndirect >= bound[npostfix]+postfix {\n\t\t\tmax_distance = (3 << 29) - 4 + (ndirect - bound[npostfix])\n\t\t} else {\n\t\t\tmax_distance = maxAllowedDistance\n\t\t}\n\t}\n\n\tdist_params.alphabet_size = alphabet_size\n\tdist_params.max_distance = uint(max_distance)\n}\n\nfunc recomputeDistancePrefixes(cmds []command, orig_params *distanceParams, new_params *distanceParams) {\n\tif orig_params.distance_postfix_bits == new_params.distance_postfix_bits && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes {\n\t\treturn\n\t}\n\n\tfor i := range cmds {\n\t\tvar cmd *command = &cmds[i]\n\t\tif commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {\n\t\t\tprefixEncodeCopyDistance(uint(commandRestoreDistanceCode(cmd, orig_params)), uint(new_params.num_direct_distance_codes), uint(new_params.distance_postfix_bits), &cmd.dist_prefix_, &cmd.dist_extra_)\n\t\t}\n\t}\n}\n\nfunc computeDistanceCost(cmds []command, orig_params *distanceParams, new_params *distanceParams, cost *float64) bool {\n\tvar equal_params bool = false\n\tvar dist_prefix uint16\n\tvar dist_extra uint32\n\tvar extra_bits float64 = 0.0\n\tvar histo histogramDistance\n\thistogramClearDistance(&histo)\n\n\tif orig_params.distance_postfix_bits == new_params.distance_postfix_bits && orig_params.num_direct_distance_codes == new_params.num_direct_distance_codes {\n\t\tequal_params = true\n\t}\n\n\tfor i := range cmds {\n\t\tcmd := &cmds[i]\n\t\tif commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {\n\t\t\tif equal_params {\n\t\t\t\tdist_prefix = cmd.dist_prefix_\n\t\t\t} else {\n\t\t\t\tvar distance uint32 = commandRestoreDistanceCode(cmd, orig_params)\n\t\t\t\tif distance > uint32(new_params.max_distance) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\tprefixEncodeCopyDistance(uint(distance), uint(new_params.num_direct_distance_codes), uint(new_params.distance_postfix_bits), &dist_prefix, &dist_extra)\n\t\t\t}\n\n\t\t\thistogramAddDistance(&histo, uint(dist_prefix)&0x3FF)\n\t\t\textra_bits += float64(dist_prefix >> 10)\n\t\t}\n\t}\n\n\t*cost = populationCostDistance(&histo) + extra_bits\n\treturn true\n}\n\nvar buildMetaBlock_kMaxNumberOfHistograms uint = 256\n\nfunc buildMetaBlock(ringbuffer []byte, pos uint, mask uint, params *encoderParams, prev_byte byte, prev_byte2 byte, cmds []command, literal_context_mode int, mb *metaBlockSplit) {\n\tvar distance_histograms []histogramDistance\n\tvar literal_histograms []histogramLiteral\n\tvar literal_context_modes []int = nil\n\tvar literal_histograms_size uint\n\tvar distance_histograms_size uint\n\tvar i uint\n\tvar literal_context_multiplier uint = 1\n\tvar npostfix uint32\n\tvar ndirect_msb uint32 = 0\n\tvar check_orig bool = true\n\tvar best_dist_cost float64 = 1e99\n\tvar orig_params encoderParams = *params\n\t/* Histogram ids need to fit in one byte. */\n\n\tvar new_params encoderParams = *params\n\n\tfor npostfix = 0; npostfix <= maxNpostfix; npostfix++ {\n\t\tfor ; ndirect_msb < 16; ndirect_msb++ {\n\t\t\tvar ndirect uint32 = ndirect_msb << npostfix\n\t\t\tvar skip bool\n\t\t\tvar dist_cost float64\n\t\t\tinitDistanceParams(&new_params, npostfix, ndirect)\n\t\t\tif npostfix == orig_params.dist.distance_postfix_bits && ndirect == orig_params.dist.num_direct_distance_codes {\n\t\t\t\tcheck_orig = false\n\t\t\t}\n\n\t\t\tskip = !computeDistanceCost(cmds, &orig_params.dist, &new_params.dist, &dist_cost)\n\t\t\tif skip || (dist_cost > best_dist_cost) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tbest_dist_cost = dist_cost\n\t\t\tparams.dist = new_params.dist\n\t\t}\n\n\t\tif ndirect_msb > 0 {\n\t\t\tndirect_msb--\n\t\t}\n\t\tndirect_msb /= 2\n\t}\n\n\tif check_orig {\n\t\tvar dist_cost float64\n\t\tcomputeDistanceCost(cmds, &orig_params.dist, &orig_params.dist, &dist_cost)\n\t\tif dist_cost < best_dist_cost {\n\t\t\t/* NB: currently unused; uncomment when more param tuning is added. */\n\t\t\t/* best_dist_cost = dist_cost; */\n\t\t\tparams.dist = orig_params.dist\n\t\t}\n\t}\n\n\trecomputeDistancePrefixes(cmds, &orig_params.dist, &params.dist)\n\n\tsplitBlock(cmds, ringbuffer, pos, mask, params, &mb.literal_split, &mb.command_split, &mb.distance_split)\n\n\tif !params.disable_literal_context_modeling {\n\t\tliteral_context_multiplier = 1 << literalContextBits\n\t\tliteral_context_modes = make([]int, (mb.literal_split.num_types))\n\t\tfor i = 0; i < mb.literal_split.num_types; i++ {\n\t\t\tliteral_context_modes[i] = literal_context_mode\n\t\t}\n\t}\n\n\tliteral_histograms_size = mb.literal_split.num_types * literal_context_multiplier\n\tliteral_histograms = make([]histogramLiteral, literal_histograms_size)\n\tclearHistogramsLiteral(literal_histograms, literal_histograms_size)\n\n\tdistance_histograms_size = mb.distance_split.num_types << distanceContextBits\n\tdistance_histograms = make([]histogramDistance, distance_histograms_size)\n\tclearHistogramsDistance(distance_histograms, distance_histograms_size)\n\n\tmb.command_histograms_size = mb.command_split.num_types\n\tif cap(mb.command_histograms) < int(mb.command_histograms_size) {\n\t\tmb.command_histograms = make([]histogramCommand, (mb.command_histograms_size))\n\t} else {\n\t\tmb.command_histograms = mb.command_histograms[:mb.command_histograms_size]\n\t}\n\tclearHistogramsCommand(mb.command_histograms, mb.command_histograms_size)\n\n\tbuildHistogramsWithContext(cmds, &mb.literal_split, &mb.command_split, &mb.distance_split, ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes, literal_histograms, mb.command_histograms, distance_histograms)\n\tliteral_context_modes = nil\n\n\tmb.literal_context_map_size = mb.literal_split.num_types << literalContextBits\n\tif cap(mb.literal_context_map) < int(mb.literal_context_map_size) {\n\t\tmb.literal_context_map = make([]uint32, (mb.literal_context_map_size))\n\t} else {\n\t\tmb.literal_context_map = mb.literal_context_map[:mb.literal_context_map_size]\n\t}\n\n\tmb.literal_histograms_size = mb.literal_context_map_size\n\tif cap(mb.literal_histograms) < int(mb.literal_histograms_size) {\n\t\tmb.literal_histograms = make([]histogramLiteral, (mb.literal_histograms_size))\n\t} else {\n\t\tmb.literal_histograms = mb.literal_histograms[:mb.literal_histograms_size]\n\t}\n\n\tclusterHistogramsLiteral(literal_histograms, literal_histograms_size, buildMetaBlock_kMaxNumberOfHistograms, mb.literal_histograms, &mb.literal_histograms_size, mb.literal_context_map)\n\tliteral_histograms = nil\n\n\tif params.disable_literal_context_modeling {\n\t\t/* Distribute assignment to all contexts. */\n\t\tfor i = mb.literal_split.num_types; i != 0; {\n\t\t\tvar j uint = 0\n\t\t\ti--\n\t\t\tfor ; j < 1<<literalContextBits; j++ {\n\t\t\t\tmb.literal_context_map[(i<<literalContextBits)+j] = mb.literal_context_map[i]\n\t\t\t}\n\t\t}\n\t}\n\n\tmb.distance_context_map_size = mb.distance_split.num_types << distanceContextBits\n\tif cap(mb.distance_context_map) < int(mb.distance_context_map_size) {\n\t\tmb.distance_context_map = make([]uint32, (mb.distance_context_map_size))\n\t} else {\n\t\tmb.distance_context_map = mb.distance_context_map[:mb.distance_context_map_size]\n\t}\n\n\tmb.distance_histograms_size = mb.distance_context_map_size\n\tif cap(mb.distance_histograms) < int(mb.distance_histograms_size) {\n\t\tmb.distance_histograms = make([]histogramDistance, (mb.distance_histograms_size))\n\t} else {\n\t\tmb.distance_histograms = mb.distance_histograms[:mb.distance_histograms_size]\n\t}\n\n\tclusterHistogramsDistance(distance_histograms, mb.distance_context_map_size, buildMetaBlock_kMaxNumberOfHistograms, mb.distance_histograms, &mb.distance_histograms_size, mb.distance_context_map)\n\tdistance_histograms = nil\n}\n\nconst maxStaticContexts = 13\n\n/* Greedy block splitter for one block category (literal, command or distance).\n   Gathers histograms for all context buckets. */\ntype contextBlockSplitter struct {\n\talphabet_size_     uint\n\tnum_contexts_      uint\n\tmax_block_types_   uint\n\tmin_block_size_    uint\n\tsplit_threshold_   float64\n\tnum_blocks_        uint\n\tsplit_             *blockSplit\n\thistograms_        []histogramLiteral\n\thistograms_size_   *uint\n\ttarget_block_size_ uint\n\tblock_size_        uint\n\tcurr_histogram_ix_ uint\n\tlast_histogram_ix_ [2]uint\n\tlast_entropy_      [2 * maxStaticContexts]float64\n\tmerge_last_count_  uint\n}\n\nfunc initContextBlockSplitter(self *contextBlockSplitter, alphabet_size uint, num_contexts uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramLiteral, histograms_size *uint) {\n\tvar max_num_blocks uint = num_symbols/min_block_size + 1\n\tvar max_num_types uint\n\tassert(num_contexts <= maxStaticContexts)\n\n\tself.alphabet_size_ = alphabet_size\n\tself.num_contexts_ = num_contexts\n\tself.max_block_types_ = maxNumberOfBlockTypes / num_contexts\n\tself.min_block_size_ = min_block_size\n\tself.split_threshold_ = split_threshold\n\tself.num_blocks_ = 0\n\tself.split_ = split\n\tself.histograms_size_ = histograms_size\n\tself.target_block_size_ = min_block_size\n\tself.block_size_ = 0\n\tself.curr_histogram_ix_ = 0\n\tself.merge_last_count_ = 0\n\n\t/* We have to allocate one more histogram than the maximum number of block\n\t   types for the current histogram when the meta-block is too big. */\n\tmax_num_types = brotli_min_size_t(max_num_blocks, self.max_block_types_+1)\n\n\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)\n\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)\n\tsplit.num_blocks = max_num_blocks\n\t*histograms_size = max_num_types * num_contexts\n\tif histograms == nil || cap(*histograms) < int(*histograms_size) {\n\t\t*histograms = make([]histogramLiteral, (*histograms_size))\n\t} else {\n\t\t*histograms = (*histograms)[:*histograms_size]\n\t}\n\tself.histograms_ = *histograms\n\n\t/* Clear only current histogram. */\n\tclearHistogramsLiteral(self.histograms_[0:], num_contexts)\n\n\tself.last_histogram_ix_[1] = 0\n\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n}\n\n/* Does either of three things:\n   (1) emits the current block with a new block type;\n   (2) emits the current block with the type of the second last block;\n   (3) merges the current block with the last block. */\nfunc contextBlockSplitterFinishBlock(self *contextBlockSplitter, is_final bool) {\n\tvar split *blockSplit = self.split_\n\tvar num_contexts uint = self.num_contexts_\n\tvar last_entropy []float64 = self.last_entropy_[:]\n\tvar histograms []histogramLiteral = self.histograms_\n\n\tif self.block_size_ < self.min_block_size_ {\n\t\tself.block_size_ = self.min_block_size_\n\t}\n\n\tif self.num_blocks_ == 0 {\n\t\tvar i uint\n\n\t\t/* Create first block. */\n\t\tsplit.lengths[0] = uint32(self.block_size_)\n\n\t\tsplit.types[0] = 0\n\n\t\tfor i = 0; i < num_contexts; i++ {\n\t\t\tlast_entropy[i] = bitsEntropy(histograms[i].data_[:], self.alphabet_size_)\n\t\t\tlast_entropy[num_contexts+i] = last_entropy[i]\n\t\t}\n\n\t\tself.num_blocks_++\n\t\tsplit.num_types++\n\t\tself.curr_histogram_ix_ += num_contexts\n\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\tclearHistogramsLiteral(self.histograms_[self.curr_histogram_ix_:], self.num_contexts_)\n\t\t}\n\n\t\tself.block_size_ = 0\n\t} else if self.block_size_ > 0 {\n\t\tvar entropy [maxStaticContexts]float64\n\t\tvar combined_histo []histogramLiteral = make([]histogramLiteral, (2 * num_contexts))\n\t\tvar combined_entropy [2 * maxStaticContexts]float64\n\t\tvar diff = [2]float64{0.0}\n\t\t/* Try merging the set of histograms for the current block type with the\n\t\t   respective set of histograms for the last and second last block types.\n\t\t   Decide over the split based on the total reduction of entropy across\n\t\t   all contexts. */\n\n\t\tvar i uint\n\t\tfor i = 0; i < num_contexts; i++ {\n\t\t\tvar curr_histo_ix uint = self.curr_histogram_ix_ + i\n\t\t\tvar j uint\n\t\t\tentropy[i] = bitsEntropy(histograms[curr_histo_ix].data_[:], self.alphabet_size_)\n\t\t\tfor j = 0; j < 2; j++ {\n\t\t\t\tvar jx uint = j*num_contexts + i\n\t\t\t\tvar last_histogram_ix uint = self.last_histogram_ix_[j] + i\n\t\t\t\tcombined_histo[jx] = histograms[curr_histo_ix]\n\t\t\t\thistogramAddHistogramLiteral(&combined_histo[jx], &histograms[last_histogram_ix])\n\t\t\t\tcombined_entropy[jx] = bitsEntropy(combined_histo[jx].data_[0:], self.alphabet_size_)\n\t\t\t\tdiff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx]\n\t\t\t}\n\t\t}\n\n\t\tif split.num_types < self.max_block_types_ && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {\n\t\t\t/* Create new block. */\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\n\t\t\tsplit.types[self.num_blocks_] = byte(split.num_types)\n\t\t\tself.last_histogram_ix_[1] = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = split.num_types * num_contexts\n\t\t\tfor i = 0; i < num_contexts; i++ {\n\t\t\t\tlast_entropy[num_contexts+i] = last_entropy[i]\n\t\t\t\tlast_entropy[i] = entropy[i]\n\t\t\t}\n\n\t\t\tself.num_blocks_++\n\t\t\tsplit.num_types++\n\t\t\tself.curr_histogram_ix_ += num_contexts\n\t\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\t\tclearHistogramsLiteral(self.histograms_[self.curr_histogram_ix_:], self.num_contexts_)\n\t\t\t}\n\n\t\t\tself.block_size_ = 0\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else if diff[1] < diff[0]-20.0 {\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\t\t\tsplit.types[self.num_blocks_] = split.types[self.num_blocks_-2]\n\t\t\t/* Combine this block with second last block. */\n\n\t\t\tvar tmp uint = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n\t\t\tself.last_histogram_ix_[1] = tmp\n\t\t\tfor i = 0; i < num_contexts; i++ {\n\t\t\t\thistograms[self.last_histogram_ix_[0]+i] = combined_histo[num_contexts+i]\n\t\t\t\tlast_entropy[num_contexts+i] = last_entropy[i]\n\t\t\t\tlast_entropy[i] = combined_entropy[num_contexts+i]\n\t\t\t\thistogramClearLiteral(&histograms[self.curr_histogram_ix_+i])\n\t\t\t}\n\n\t\t\tself.num_blocks_++\n\t\t\tself.block_size_ = 0\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else {\n\t\t\t/* Combine this block with last block. */\n\t\t\tsplit.lengths[self.num_blocks_-1] += uint32(self.block_size_)\n\n\t\t\tfor i = 0; i < num_contexts; i++ {\n\t\t\t\thistograms[self.last_histogram_ix_[0]+i] = combined_histo[i]\n\t\t\t\tlast_entropy[i] = combined_entropy[i]\n\t\t\t\tif split.num_types == 1 {\n\t\t\t\t\tlast_entropy[num_contexts+i] = last_entropy[i]\n\t\t\t\t}\n\n\t\t\t\thistogramClearLiteral(&histograms[self.curr_histogram_ix_+i])\n\t\t\t}\n\n\t\t\tself.block_size_ = 0\n\t\t\tself.merge_last_count_++\n\t\t\tif self.merge_last_count_ > 1 {\n\t\t\t\tself.target_block_size_ += self.min_block_size_\n\t\t\t}\n\t\t}\n\n\t\tcombined_histo = nil\n\t}\n\n\tif is_final {\n\t\t*self.histograms_size_ = split.num_types * num_contexts\n\t\tsplit.num_blocks = self.num_blocks_\n\t}\n}\n\n/* Adds the next symbol to the current block type and context. When the\n   current block reaches the target size, decides on merging the block. */\nfunc contextBlockSplitterAddSymbol(self *contextBlockSplitter, symbol uint, context uint) {\n\thistogramAddLiteral(&self.histograms_[self.curr_histogram_ix_+context], symbol)\n\tself.block_size_++\n\tif self.block_size_ == self.target_block_size_ {\n\t\tcontextBlockSplitterFinishBlock(self, false) /* is_final = */\n\t}\n}\n\nfunc mapStaticContexts(num_contexts uint, static_context_map []uint32, mb *metaBlockSplit) {\n\tvar i uint\n\tmb.literal_context_map_size = mb.literal_split.num_types << literalContextBits\n\tif cap(mb.literal_context_map) < int(mb.literal_context_map_size) {\n\t\tmb.literal_context_map = make([]uint32, (mb.literal_context_map_size))\n\t} else {\n\t\tmb.literal_context_map = mb.literal_context_map[:mb.literal_context_map_size]\n\t}\n\n\tfor i = 0; i < mb.literal_split.num_types; i++ {\n\t\tvar offset uint32 = uint32(i * num_contexts)\n\t\tvar j uint\n\t\tfor j = 0; j < 1<<literalContextBits; j++ {\n\t\t\tmb.literal_context_map[(i<<literalContextBits)+j] = offset + static_context_map[j]\n\t\t}\n\t}\n}\n\nfunc buildMetaBlockGreedyInternal(ringbuffer []byte, pos uint, mask uint, prev_byte byte, prev_byte2 byte, literal_context_lut contextLUT, num_contexts uint, static_context_map []uint32, commands []command, mb *metaBlockSplit) {\n\tvar lit_blocks struct {\n\t\tplain blockSplitterLiteral\n\t\tctx   contextBlockSplitter\n\t}\n\tvar cmd_blocks blockSplitterCommand\n\tvar dist_blocks blockSplitterDistance\n\tvar num_literals uint = 0\n\tfor i := range commands {\n\t\tnum_literals += uint(commands[i].insert_len_)\n\t}\n\n\tif num_contexts == 1 {\n\t\tinitBlockSplitterLiteral(&lit_blocks.plain, 256, 512, 400.0, num_literals, &mb.literal_split, &mb.literal_histograms, &mb.literal_histograms_size)\n\t} else {\n\t\tinitContextBlockSplitter(&lit_blocks.ctx, 256, num_contexts, 512, 400.0, num_literals, &mb.literal_split, &mb.literal_histograms, &mb.literal_histograms_size)\n\t}\n\n\tinitBlockSplitterCommand(&cmd_blocks, numCommandSymbols, 1024, 500.0, uint(len(commands)), &mb.command_split, &mb.command_histograms, &mb.command_histograms_size)\n\tinitBlockSplitterDistance(&dist_blocks, 64, 512, 100.0, uint(len(commands)), &mb.distance_split, &mb.distance_histograms, &mb.distance_histograms_size)\n\n\tfor _, cmd := range commands {\n\t\tvar j uint\n\t\tblockSplitterAddSymbolCommand(&cmd_blocks, uint(cmd.cmd_prefix_))\n\t\tfor j = uint(cmd.insert_len_); j != 0; j-- {\n\t\t\tvar literal byte = ringbuffer[pos&mask]\n\t\t\tif num_contexts == 1 {\n\t\t\t\tblockSplitterAddSymbolLiteral(&lit_blocks.plain, uint(literal))\n\t\t\t} else {\n\t\t\t\tvar context uint = uint(getContext(prev_byte, prev_byte2, literal_context_lut))\n\t\t\t\tcontextBlockSplitterAddSymbol(&lit_blocks.ctx, uint(literal), uint(static_context_map[context]))\n\t\t\t}\n\n\t\t\tprev_byte2 = prev_byte\n\t\t\tprev_byte = literal\n\t\t\tpos++\n\t\t}\n\n\t\tpos += uint(commandCopyLen(&cmd))\n\t\tif commandCopyLen(&cmd) != 0 {\n\t\t\tprev_byte2 = ringbuffer[(pos-2)&mask]\n\t\t\tprev_byte = ringbuffer[(pos-1)&mask]\n\t\t\tif cmd.cmd_prefix_ >= 128 {\n\t\t\t\tblockSplitterAddSymbolDistance(&dist_blocks, uint(cmd.dist_prefix_)&0x3FF)\n\t\t\t}\n\t\t}\n\t}\n\n\tif num_contexts == 1 {\n\t\tblockSplitterFinishBlockLiteral(&lit_blocks.plain, true) /* is_final = */\n\t} else {\n\t\tcontextBlockSplitterFinishBlock(&lit_blocks.ctx, true) /* is_final = */\n\t}\n\n\tblockSplitterFinishBlockCommand(&cmd_blocks, true)   /* is_final = */\n\tblockSplitterFinishBlockDistance(&dist_blocks, true) /* is_final = */\n\n\tif num_contexts > 1 {\n\t\tmapStaticContexts(num_contexts, static_context_map, mb)\n\t}\n}\n\nfunc buildMetaBlockGreedy(ringbuffer []byte, pos uint, mask uint, prev_byte byte, prev_byte2 byte, literal_context_lut contextLUT, num_contexts uint, static_context_map []uint32, commands []command, mb *metaBlockSplit) {\n\tif num_contexts == 1 {\n\t\tbuildMetaBlockGreedyInternal(ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_lut, 1, nil, commands, mb)\n\t} else {\n\t\tbuildMetaBlockGreedyInternal(ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_lut, num_contexts, static_context_map, commands, mb)\n\t}\n}\n\nfunc optimizeHistograms(num_distance_codes uint32, mb *metaBlockSplit) {\n\tvar good_for_rle [numCommandSymbols]byte\n\tvar i uint\n\tfor i = 0; i < mb.literal_histograms_size; i++ {\n\t\toptimizeHuffmanCountsForRLE(256, mb.literal_histograms[i].data_[:], good_for_rle[:])\n\t}\n\n\tfor i = 0; i < mb.command_histograms_size; i++ {\n\t\toptimizeHuffmanCountsForRLE(numCommandSymbols, mb.command_histograms[i].data_[:], good_for_rle[:])\n\t}\n\n\tfor i = 0; i < mb.distance_histograms_size; i++ {\n\t\toptimizeHuffmanCountsForRLE(uint(num_distance_codes), mb.distance_histograms[i].data_[:], good_for_rle[:])\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/metablock_command.go",
    "content": "package brotli\n\n/* Copyright 2015 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Greedy block splitter for one block category (literal, command or distance).\n */\ntype blockSplitterCommand struct {\n\talphabet_size_     uint\n\tmin_block_size_    uint\n\tsplit_threshold_   float64\n\tnum_blocks_        uint\n\tsplit_             *blockSplit\n\thistograms_        []histogramCommand\n\thistograms_size_   *uint\n\ttarget_block_size_ uint\n\tblock_size_        uint\n\tcurr_histogram_ix_ uint\n\tlast_histogram_ix_ [2]uint\n\tlast_entropy_      [2]float64\n\tmerge_last_count_  uint\n}\n\nfunc initBlockSplitterCommand(self *blockSplitterCommand, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramCommand, histograms_size *uint) {\n\tvar max_num_blocks uint = num_symbols/min_block_size + 1\n\tvar max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)\n\t/* We have to allocate one more histogram than the maximum number of block\n\t   types for the current histogram when the meta-block is too big. */\n\tself.alphabet_size_ = alphabet_size\n\n\tself.min_block_size_ = min_block_size\n\tself.split_threshold_ = split_threshold\n\tself.num_blocks_ = 0\n\tself.split_ = split\n\tself.histograms_size_ = histograms_size\n\tself.target_block_size_ = min_block_size\n\tself.block_size_ = 0\n\tself.curr_histogram_ix_ = 0\n\tself.merge_last_count_ = 0\n\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)\n\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)\n\tself.split_.num_blocks = max_num_blocks\n\t*histograms_size = max_num_types\n\tif histograms == nil || cap(*histograms) < int(*histograms_size) {\n\t\t*histograms = make([]histogramCommand, (*histograms_size))\n\t} else {\n\t\t*histograms = (*histograms)[:*histograms_size]\n\t}\n\tself.histograms_ = *histograms\n\n\t/* Clear only current histogram. */\n\thistogramClearCommand(&self.histograms_[0])\n\n\tself.last_histogram_ix_[1] = 0\n\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n}\n\n/* Does either of three things:\n   (1) emits the current block with a new block type;\n   (2) emits the current block with the type of the second last block;\n   (3) merges the current block with the last block. */\nfunc blockSplitterFinishBlockCommand(self *blockSplitterCommand, is_final bool) {\n\tvar split *blockSplit = self.split_\n\tvar last_entropy []float64 = self.last_entropy_[:]\n\tvar histograms []histogramCommand = self.histograms_\n\tself.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)\n\tif self.num_blocks_ == 0 {\n\t\t/* Create first block. */\n\t\tsplit.lengths[0] = uint32(self.block_size_)\n\n\t\tsplit.types[0] = 0\n\t\tlast_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)\n\t\tlast_entropy[1] = last_entropy[0]\n\t\tself.num_blocks_++\n\t\tsplit.num_types++\n\t\tself.curr_histogram_ix_++\n\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\thistogramClearCommand(&histograms[self.curr_histogram_ix_])\n\t\t}\n\t\tself.block_size_ = 0\n\t} else if self.block_size_ > 0 {\n\t\tvar entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)\n\t\tvar combined_histo [2]histogramCommand\n\t\tvar combined_entropy [2]float64\n\t\tvar diff [2]float64\n\t\tvar j uint\n\t\tfor j = 0; j < 2; j++ {\n\t\t\tvar last_histogram_ix uint = self.last_histogram_ix_[j]\n\t\t\tcombined_histo[j] = histograms[self.curr_histogram_ix_]\n\t\t\thistogramAddHistogramCommand(&combined_histo[j], &histograms[last_histogram_ix])\n\t\t\tcombined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)\n\t\t\tdiff[j] = combined_entropy[j] - entropy - last_entropy[j]\n\t\t}\n\n\t\tif split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {\n\t\t\t/* Create new block. */\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\n\t\t\tsplit.types[self.num_blocks_] = byte(split.num_types)\n\t\t\tself.last_histogram_ix_[1] = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = uint(byte(split.num_types))\n\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\tlast_entropy[0] = entropy\n\t\t\tself.num_blocks_++\n\t\t\tsplit.num_types++\n\t\t\tself.curr_histogram_ix_++\n\t\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\t\thistogramClearCommand(&histograms[self.curr_histogram_ix_])\n\t\t\t}\n\t\t\tself.block_size_ = 0\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else if diff[1] < diff[0]-20.0 {\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\t\t\tsplit.types[self.num_blocks_] = split.types[self.num_blocks_-2]\n\t\t\t/* Combine this block with second last block. */\n\n\t\t\tvar tmp uint = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n\t\t\tself.last_histogram_ix_[1] = tmp\n\t\t\thistograms[self.last_histogram_ix_[0]] = combined_histo[1]\n\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\tlast_entropy[0] = combined_entropy[1]\n\t\t\tself.num_blocks_++\n\t\t\tself.block_size_ = 0\n\t\t\thistogramClearCommand(&histograms[self.curr_histogram_ix_])\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else {\n\t\t\t/* Combine this block with last block. */\n\t\t\tsplit.lengths[self.num_blocks_-1] += uint32(self.block_size_)\n\n\t\t\thistograms[self.last_histogram_ix_[0]] = combined_histo[0]\n\t\t\tlast_entropy[0] = combined_entropy[0]\n\t\t\tif split.num_types == 1 {\n\t\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\t}\n\n\t\t\tself.block_size_ = 0\n\t\t\thistogramClearCommand(&histograms[self.curr_histogram_ix_])\n\t\t\tself.merge_last_count_++\n\t\t\tif self.merge_last_count_ > 1 {\n\t\t\t\tself.target_block_size_ += self.min_block_size_\n\t\t\t}\n\t\t}\n\t}\n\n\tif is_final {\n\t\t*self.histograms_size_ = split.num_types\n\t\tsplit.num_blocks = self.num_blocks_\n\t}\n}\n\n/* Adds the next symbol to the current histogram. When the current histogram\n   reaches the target size, decides on merging the block. */\nfunc blockSplitterAddSymbolCommand(self *blockSplitterCommand, symbol uint) {\n\thistogramAddCommand(&self.histograms_[self.curr_histogram_ix_], symbol)\n\tself.block_size_++\n\tif self.block_size_ == self.target_block_size_ {\n\t\tblockSplitterFinishBlockCommand(self, false) /* is_final = */\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/metablock_distance.go",
    "content": "package brotli\n\n/* Copyright 2015 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Greedy block splitter for one block category (literal, command or distance).\n */\ntype blockSplitterDistance struct {\n\talphabet_size_     uint\n\tmin_block_size_    uint\n\tsplit_threshold_   float64\n\tnum_blocks_        uint\n\tsplit_             *blockSplit\n\thistograms_        []histogramDistance\n\thistograms_size_   *uint\n\ttarget_block_size_ uint\n\tblock_size_        uint\n\tcurr_histogram_ix_ uint\n\tlast_histogram_ix_ [2]uint\n\tlast_entropy_      [2]float64\n\tmerge_last_count_  uint\n}\n\nfunc initBlockSplitterDistance(self *blockSplitterDistance, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramDistance, histograms_size *uint) {\n\tvar max_num_blocks uint = num_symbols/min_block_size + 1\n\tvar max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)\n\t/* We have to allocate one more histogram than the maximum number of block\n\t   types for the current histogram when the meta-block is too big. */\n\tself.alphabet_size_ = alphabet_size\n\n\tself.min_block_size_ = min_block_size\n\tself.split_threshold_ = split_threshold\n\tself.num_blocks_ = 0\n\tself.split_ = split\n\tself.histograms_size_ = histograms_size\n\tself.target_block_size_ = min_block_size\n\tself.block_size_ = 0\n\tself.curr_histogram_ix_ = 0\n\tself.merge_last_count_ = 0\n\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)\n\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)\n\tself.split_.num_blocks = max_num_blocks\n\t*histograms_size = max_num_types\n\tif histograms == nil || cap(*histograms) < int(*histograms_size) {\n\t\t*histograms = make([]histogramDistance, *histograms_size)\n\t} else {\n\t\t*histograms = (*histograms)[:*histograms_size]\n\t}\n\tself.histograms_ = *histograms\n\n\t/* Clear only current histogram. */\n\thistogramClearDistance(&self.histograms_[0])\n\n\tself.last_histogram_ix_[1] = 0\n\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n}\n\n/* Does either of three things:\n   (1) emits the current block with a new block type;\n   (2) emits the current block with the type of the second last block;\n   (3) merges the current block with the last block. */\nfunc blockSplitterFinishBlockDistance(self *blockSplitterDistance, is_final bool) {\n\tvar split *blockSplit = self.split_\n\tvar last_entropy []float64 = self.last_entropy_[:]\n\tvar histograms []histogramDistance = self.histograms_\n\tself.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)\n\tif self.num_blocks_ == 0 {\n\t\t/* Create first block. */\n\t\tsplit.lengths[0] = uint32(self.block_size_)\n\n\t\tsplit.types[0] = 0\n\t\tlast_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)\n\t\tlast_entropy[1] = last_entropy[0]\n\t\tself.num_blocks_++\n\t\tsplit.num_types++\n\t\tself.curr_histogram_ix_++\n\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\thistogramClearDistance(&histograms[self.curr_histogram_ix_])\n\t\t}\n\t\tself.block_size_ = 0\n\t} else if self.block_size_ > 0 {\n\t\tvar entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)\n\t\tvar combined_histo [2]histogramDistance\n\t\tvar combined_entropy [2]float64\n\t\tvar diff [2]float64\n\t\tvar j uint\n\t\tfor j = 0; j < 2; j++ {\n\t\t\tvar last_histogram_ix uint = self.last_histogram_ix_[j]\n\t\t\tcombined_histo[j] = histograms[self.curr_histogram_ix_]\n\t\t\thistogramAddHistogramDistance(&combined_histo[j], &histograms[last_histogram_ix])\n\t\t\tcombined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)\n\t\t\tdiff[j] = combined_entropy[j] - entropy - last_entropy[j]\n\t\t}\n\n\t\tif split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {\n\t\t\t/* Create new block. */\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\n\t\t\tsplit.types[self.num_blocks_] = byte(split.num_types)\n\t\t\tself.last_histogram_ix_[1] = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = uint(byte(split.num_types))\n\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\tlast_entropy[0] = entropy\n\t\t\tself.num_blocks_++\n\t\t\tsplit.num_types++\n\t\t\tself.curr_histogram_ix_++\n\t\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\t\thistogramClearDistance(&histograms[self.curr_histogram_ix_])\n\t\t\t}\n\t\t\tself.block_size_ = 0\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else if diff[1] < diff[0]-20.0 {\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\t\t\tsplit.types[self.num_blocks_] = split.types[self.num_blocks_-2]\n\t\t\t/* Combine this block with second last block. */\n\n\t\t\tvar tmp uint = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n\t\t\tself.last_histogram_ix_[1] = tmp\n\t\t\thistograms[self.last_histogram_ix_[0]] = combined_histo[1]\n\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\tlast_entropy[0] = combined_entropy[1]\n\t\t\tself.num_blocks_++\n\t\t\tself.block_size_ = 0\n\t\t\thistogramClearDistance(&histograms[self.curr_histogram_ix_])\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else {\n\t\t\t/* Combine this block with last block. */\n\t\t\tsplit.lengths[self.num_blocks_-1] += uint32(self.block_size_)\n\n\t\t\thistograms[self.last_histogram_ix_[0]] = combined_histo[0]\n\t\t\tlast_entropy[0] = combined_entropy[0]\n\t\t\tif split.num_types == 1 {\n\t\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\t}\n\n\t\t\tself.block_size_ = 0\n\t\t\thistogramClearDistance(&histograms[self.curr_histogram_ix_])\n\t\t\tself.merge_last_count_++\n\t\t\tif self.merge_last_count_ > 1 {\n\t\t\t\tself.target_block_size_ += self.min_block_size_\n\t\t\t}\n\t\t}\n\t}\n\n\tif is_final {\n\t\t*self.histograms_size_ = split.num_types\n\t\tsplit.num_blocks = self.num_blocks_\n\t}\n}\n\n/* Adds the next symbol to the current histogram. When the current histogram\n   reaches the target size, decides on merging the block. */\nfunc blockSplitterAddSymbolDistance(self *blockSplitterDistance, symbol uint) {\n\thistogramAddDistance(&self.histograms_[self.curr_histogram_ix_], symbol)\n\tself.block_size_++\n\tif self.block_size_ == self.target_block_size_ {\n\t\tblockSplitterFinishBlockDistance(self, false) /* is_final = */\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/metablock_literal.go",
    "content": "package brotli\n\n/* Copyright 2015 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Greedy block splitter for one block category (literal, command or distance).\n */\ntype blockSplitterLiteral struct {\n\talphabet_size_     uint\n\tmin_block_size_    uint\n\tsplit_threshold_   float64\n\tnum_blocks_        uint\n\tsplit_             *blockSplit\n\thistograms_        []histogramLiteral\n\thistograms_size_   *uint\n\ttarget_block_size_ uint\n\tblock_size_        uint\n\tcurr_histogram_ix_ uint\n\tlast_histogram_ix_ [2]uint\n\tlast_entropy_      [2]float64\n\tmerge_last_count_  uint\n}\n\nfunc initBlockSplitterLiteral(self *blockSplitterLiteral, alphabet_size uint, min_block_size uint, split_threshold float64, num_symbols uint, split *blockSplit, histograms *[]histogramLiteral, histograms_size *uint) {\n\tvar max_num_blocks uint = num_symbols/min_block_size + 1\n\tvar max_num_types uint = brotli_min_size_t(max_num_blocks, maxNumberOfBlockTypes+1)\n\t/* We have to allocate one more histogram than the maximum number of block\n\t   types for the current histogram when the meta-block is too big. */\n\tself.alphabet_size_ = alphabet_size\n\n\tself.min_block_size_ = min_block_size\n\tself.split_threshold_ = split_threshold\n\tself.num_blocks_ = 0\n\tself.split_ = split\n\tself.histograms_size_ = histograms_size\n\tself.target_block_size_ = min_block_size\n\tself.block_size_ = 0\n\tself.curr_histogram_ix_ = 0\n\tself.merge_last_count_ = 0\n\tbrotli_ensure_capacity_uint8_t(&split.types, &split.types_alloc_size, max_num_blocks)\n\tbrotli_ensure_capacity_uint32_t(&split.lengths, &split.lengths_alloc_size, max_num_blocks)\n\tself.split_.num_blocks = max_num_blocks\n\t*histograms_size = max_num_types\n\tif histograms == nil || cap(*histograms) < int(*histograms_size) {\n\t\t*histograms = make([]histogramLiteral, *histograms_size)\n\t} else {\n\t\t*histograms = (*histograms)[:*histograms_size]\n\t}\n\tself.histograms_ = *histograms\n\n\t/* Clear only current histogram. */\n\thistogramClearLiteral(&self.histograms_[0])\n\n\tself.last_histogram_ix_[1] = 0\n\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n}\n\n/* Does either of three things:\n   (1) emits the current block with a new block type;\n   (2) emits the current block with the type of the second last block;\n   (3) merges the current block with the last block. */\nfunc blockSplitterFinishBlockLiteral(self *blockSplitterLiteral, is_final bool) {\n\tvar split *blockSplit = self.split_\n\tvar last_entropy []float64 = self.last_entropy_[:]\n\tvar histograms []histogramLiteral = self.histograms_\n\tself.block_size_ = brotli_max_size_t(self.block_size_, self.min_block_size_)\n\tif self.num_blocks_ == 0 {\n\t\t/* Create first block. */\n\t\tsplit.lengths[0] = uint32(self.block_size_)\n\n\t\tsplit.types[0] = 0\n\t\tlast_entropy[0] = bitsEntropy(histograms[0].data_[:], self.alphabet_size_)\n\t\tlast_entropy[1] = last_entropy[0]\n\t\tself.num_blocks_++\n\t\tsplit.num_types++\n\t\tself.curr_histogram_ix_++\n\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\thistogramClearLiteral(&histograms[self.curr_histogram_ix_])\n\t\t}\n\t\tself.block_size_ = 0\n\t} else if self.block_size_ > 0 {\n\t\tvar entropy float64 = bitsEntropy(histograms[self.curr_histogram_ix_].data_[:], self.alphabet_size_)\n\t\tvar combined_histo [2]histogramLiteral\n\t\tvar combined_entropy [2]float64\n\t\tvar diff [2]float64\n\t\tvar j uint\n\t\tfor j = 0; j < 2; j++ {\n\t\t\tvar last_histogram_ix uint = self.last_histogram_ix_[j]\n\t\t\tcombined_histo[j] = histograms[self.curr_histogram_ix_]\n\t\t\thistogramAddHistogramLiteral(&combined_histo[j], &histograms[last_histogram_ix])\n\t\t\tcombined_entropy[j] = bitsEntropy(combined_histo[j].data_[0:], self.alphabet_size_)\n\t\t\tdiff[j] = combined_entropy[j] - entropy - last_entropy[j]\n\t\t}\n\n\t\tif split.num_types < maxNumberOfBlockTypes && diff[0] > self.split_threshold_ && diff[1] > self.split_threshold_ {\n\t\t\t/* Create new block. */\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\n\t\t\tsplit.types[self.num_blocks_] = byte(split.num_types)\n\t\t\tself.last_histogram_ix_[1] = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = uint(byte(split.num_types))\n\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\tlast_entropy[0] = entropy\n\t\t\tself.num_blocks_++\n\t\t\tsplit.num_types++\n\t\t\tself.curr_histogram_ix_++\n\t\t\tif self.curr_histogram_ix_ < *self.histograms_size_ {\n\t\t\t\thistogramClearLiteral(&histograms[self.curr_histogram_ix_])\n\t\t\t}\n\t\t\tself.block_size_ = 0\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else if diff[1] < diff[0]-20.0 {\n\t\t\tsplit.lengths[self.num_blocks_] = uint32(self.block_size_)\n\t\t\tsplit.types[self.num_blocks_] = split.types[self.num_blocks_-2]\n\t\t\t/* Combine this block with second last block. */\n\n\t\t\tvar tmp uint = self.last_histogram_ix_[0]\n\t\t\tself.last_histogram_ix_[0] = self.last_histogram_ix_[1]\n\t\t\tself.last_histogram_ix_[1] = tmp\n\t\t\thistograms[self.last_histogram_ix_[0]] = combined_histo[1]\n\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\tlast_entropy[0] = combined_entropy[1]\n\t\t\tself.num_blocks_++\n\t\t\tself.block_size_ = 0\n\t\t\thistogramClearLiteral(&histograms[self.curr_histogram_ix_])\n\t\t\tself.merge_last_count_ = 0\n\t\t\tself.target_block_size_ = self.min_block_size_\n\t\t} else {\n\t\t\t/* Combine this block with last block. */\n\t\t\tsplit.lengths[self.num_blocks_-1] += uint32(self.block_size_)\n\n\t\t\thistograms[self.last_histogram_ix_[0]] = combined_histo[0]\n\t\t\tlast_entropy[0] = combined_entropy[0]\n\t\t\tif split.num_types == 1 {\n\t\t\t\tlast_entropy[1] = last_entropy[0]\n\t\t\t}\n\n\t\t\tself.block_size_ = 0\n\t\t\thistogramClearLiteral(&histograms[self.curr_histogram_ix_])\n\t\t\tself.merge_last_count_++\n\t\t\tif self.merge_last_count_ > 1 {\n\t\t\t\tself.target_block_size_ += self.min_block_size_\n\t\t\t}\n\t\t}\n\t}\n\n\tif is_final {\n\t\t*self.histograms_size_ = split.num_types\n\t\tsplit.num_blocks = self.num_blocks_\n\t}\n}\n\n/* Adds the next symbol to the current histogram. When the current histogram\n   reaches the target size, decides on merging the block. */\nfunc blockSplitterAddSymbolLiteral(self *blockSplitterLiteral, symbol uint) {\n\thistogramAddLiteral(&self.histograms_[self.curr_histogram_ix_], symbol)\n\tself.block_size_++\n\tif self.block_size_ == self.target_block_size_ {\n\t\tblockSplitterFinishBlockLiteral(self, false) /* is_final = */\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/params.go",
    "content": "package brotli\n\n/* Copyright 2017 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Parameters for the Brotli encoder with chosen quality levels. */\ntype hasherParams struct {\n\ttype_                       int\n\tbucket_bits                 int\n\tblock_bits                  int\n\thash_len                    int\n\tnum_last_distances_to_check int\n}\n\ntype distanceParams struct {\n\tdistance_postfix_bits     uint32\n\tnum_direct_distance_codes uint32\n\talphabet_size             uint32\n\tmax_distance              uint\n}\n\n/* Encoding parameters */\ntype encoderParams struct {\n\tmode                             int\n\tquality                          int\n\tlgwin                            uint\n\tlgblock                          int\n\tsize_hint                        uint\n\tdisable_literal_context_modeling bool\n\tlarge_window                     bool\n\thasher                           hasherParams\n\tdist                             distanceParams\n\tdictionary                       encoderDictionary\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/platform.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\nfunc brotli_min_double(a float64, b float64) float64 {\n\tif a < b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_max_double(a float64, b float64) float64 {\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_min_float(a float32, b float32) float32 {\n\tif a < b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_max_float(a float32, b float32) float32 {\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_min_int(a int, b int) int {\n\tif a < b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_max_int(a int, b int) int {\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_min_size_t(a uint, b uint) uint {\n\tif a < b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_max_size_t(a uint, b uint) uint {\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_min_uint32_t(a uint32, b uint32) uint32 {\n\tif a < b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_max_uint32_t(a uint32, b uint32) uint32 {\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_min_uint8_t(a byte, b byte) byte {\n\tif a < b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n\nfunc brotli_max_uint8_t(a byte, b byte) byte {\n\tif a > b {\n\t\treturn a\n\t} else {\n\t\treturn b\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/prefix.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Functions for encoding of integers into prefix codes the amount of extra\n   bits, and the actual values of the extra bits. */\n\n/* Here distance_code is an intermediate code, i.e. one of the special codes or\n   the actual distance increased by BROTLI_NUM_DISTANCE_SHORT_CODES - 1. */\nfunc prefixEncodeCopyDistance(distance_code uint, num_direct_codes uint, postfix_bits uint, code *uint16, extra_bits *uint32) {\n\tif distance_code < numDistanceShortCodes+num_direct_codes {\n\t\t*code = uint16(distance_code)\n\t\t*extra_bits = 0\n\t\treturn\n\t} else {\n\t\tvar dist uint = (uint(1) << (postfix_bits + 2)) + (distance_code - numDistanceShortCodes - num_direct_codes)\n\t\tvar bucket uint = uint(log2FloorNonZero(dist) - 1)\n\t\tvar postfix_mask uint = (1 << postfix_bits) - 1\n\t\tvar postfix uint = dist & postfix_mask\n\t\tvar prefix uint = (dist >> bucket) & 1\n\t\tvar offset uint = (2 + prefix) << bucket\n\t\tvar nbits uint = bucket - postfix_bits\n\t\t*code = uint16(nbits<<10 | (numDistanceShortCodes + num_direct_codes + ((2*(nbits-1) + prefix) << postfix_bits) + postfix))\n\t\t*extra_bits = uint32((dist - offset) >> postfix_bits)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/prefix_dec.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\ntype cmdLutElement struct {\n\tinsert_len_extra_bits byte\n\tcopy_len_extra_bits   byte\n\tdistance_code         int8\n\tcontext               byte\n\tinsert_len_offset     uint16\n\tcopy_len_offset       uint16\n}\n\nvar kCmdLut = [numCommandSymbols]cmdLutElement{\n\tcmdLutElement{0x00, 0x00, 0, 0x00, 0x0000, 0x0002},\n\tcmdLutElement{0x00, 0x00, 0, 0x01, 0x0000, 0x0003},\n\tcmdLutElement{0x00, 0x00, 0, 0x02, 0x0000, 0x0004},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0005},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0006},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0007},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0008},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0000, 0x0009},\n\tcmdLutElement{0x00, 0x00, 0, 0x00, 0x0001, 0x0002},\n\tcmdLutElement{0x00, 0x00, 0, 0x01, 0x0001, 0x0003},\n\tcmdLutElement{0x00, 0x00, 0, 0x02, 0x0001, 0x0004},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0005},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0006},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0007},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0008},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0001, 0x0009},\n\tcmdLutElement{0x00, 0x00, 0, 0x00, 0x0002, 0x0002},\n\tcmdLutElement{0x00, 0x00, 0, 0x01, 0x0002, 0x0003},\n\tcmdLutElement{0x00, 0x00, 0, 0x02, 0x0002, 0x0004},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0005},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0006},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0007},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0008},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0002, 0x0009},\n\tcmdLutElement{0x00, 0x00, 0, 0x00, 0x0003, 0x0002},\n\tcmdLutElement{0x00, 0x00, 0, 0x01, 0x0003, 0x0003},\n\tcmdLutElement{0x00, 0x00, 0, 0x02, 0x0003, 0x0004},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0005},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0006},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0007},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0008},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0003, 0x0009},\n\tcmdLutElement{0x00, 0x00, 0, 0x00, 0x0004, 0x0002},\n\tcmdLutElement{0x00, 0x00, 0, 0x01, 0x0004, 0x0003},\n\tcmdLutElement{0x00, 0x00, 0, 0x02, 0x0004, 0x0004},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0005},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0006},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0007},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0008},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0004, 0x0009},\n\tcmdLutElement{0x00, 0x00, 0, 0x00, 0x0005, 0x0002},\n\tcmdLutElement{0x00, 0x00, 0, 0x01, 0x0005, 0x0003},\n\tcmdLutElement{0x00, 0x00, 0, 0x02, 0x0005, 0x0004},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0005},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0006},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0007},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0008},\n\tcmdLutElement{0x00, 0x00, 0, 0x03, 0x0005, 0x0009},\n\tcmdLutElement{0x01, 0x00, 0, 0x00, 0x0006, 0x0002},\n\tcmdLutElement{0x01, 0x00, 0, 0x01, 0x0006, 0x0003},\n\tcmdLutElement{0x01, 0x00, 0, 0x02, 0x0006, 0x0004},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0005},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0006},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0007},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0008},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0006, 0x0009},\n\tcmdLutElement{0x01, 0x00, 0, 0x00, 0x0008, 0x0002},\n\tcmdLutElement{0x01, 0x00, 0, 0x01, 0x0008, 0x0003},\n\tcmdLutElement{0x01, 0x00, 0, 0x02, 0x0008, 0x0004},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0005},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0006},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0007},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0008},\n\tcmdLutElement{0x01, 0x00, 0, 0x03, 0x0008, 0x0009},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0000, 0x000a},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0000, 0x000c},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0000, 0x000e},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0000, 0x0012},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0000, 0x0016},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0000, 0x001e},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0000, 0x0026},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0000, 0x0036},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0001, 0x000a},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0001, 0x000c},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0001, 0x000e},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0001, 0x0012},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0001, 0x0016},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0001, 0x001e},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0001, 0x0026},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0001, 0x0036},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0002, 0x000a},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0002, 0x000c},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0002, 0x000e},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0002, 0x0012},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0002, 0x0016},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0002, 0x001e},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0002, 0x0026},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0002, 0x0036},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0003, 0x000a},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0003, 0x000c},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0003, 0x000e},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0003, 0x0012},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0003, 0x0016},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0003, 0x001e},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0003, 0x0026},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0003, 0x0036},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0004, 0x000a},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0004, 0x000c},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0004, 0x000e},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0004, 0x0012},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0004, 0x0016},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0004, 0x001e},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0004, 0x0026},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0004, 0x0036},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0005, 0x000a},\n\tcmdLutElement{0x00, 0x01, 0, 0x03, 0x0005, 0x000c},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0005, 0x000e},\n\tcmdLutElement{0x00, 0x02, 0, 0x03, 0x0005, 0x0012},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0005, 0x0016},\n\tcmdLutElement{0x00, 0x03, 0, 0x03, 0x0005, 0x001e},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0005, 0x0026},\n\tcmdLutElement{0x00, 0x04, 0, 0x03, 0x0005, 0x0036},\n\tcmdLutElement{0x01, 0x01, 0, 0x03, 0x0006, 0x000a},\n\tcmdLutElement{0x01, 0x01, 0, 0x03, 0x0006, 0x000c},\n\tcmdLutElement{0x01, 0x02, 0, 0x03, 0x0006, 0x000e},\n\tcmdLutElement{0x01, 0x02, 0, 0x03, 0x0006, 0x0012},\n\tcmdLutElement{0x01, 0x03, 0, 0x03, 0x0006, 0x0016},\n\tcmdLutElement{0x01, 0x03, 0, 0x03, 0x0006, 0x001e},\n\tcmdLutElement{0x01, 0x04, 0, 0x03, 0x0006, 0x0026},\n\tcmdLutElement{0x01, 0x04, 0, 0x03, 0x0006, 0x0036},\n\tcmdLutElement{0x01, 0x01, 0, 0x03, 0x0008, 0x000a},\n\tcmdLutElement{0x01, 0x01, 0, 0x03, 0x0008, 0x000c},\n\tcmdLutElement{0x01, 0x02, 0, 0x03, 0x0008, 0x000e},\n\tcmdLutElement{0x01, 0x02, 0, 0x03, 0x0008, 0x0012},\n\tcmdLutElement{0x01, 0x03, 0, 0x03, 0x0008, 0x0016},\n\tcmdLutElement{0x01, 0x03, 0, 0x03, 0x0008, 0x001e},\n\tcmdLutElement{0x01, 0x04, 0, 0x03, 0x0008, 0x0026},\n\tcmdLutElement{0x01, 0x04, 0, 0x03, 0x0008, 0x0036},\n\tcmdLutElement{0x00, 0x00, -1, 0x00, 0x0000, 0x0002},\n\tcmdLutElement{0x00, 0x00, -1, 0x01, 0x0000, 0x0003},\n\tcmdLutElement{0x00, 0x00, -1, 0x02, 0x0000, 0x0004},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0005},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0006},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0007},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0008},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0000, 0x0009},\n\tcmdLutElement{0x00, 0x00, -1, 0x00, 0x0001, 0x0002},\n\tcmdLutElement{0x00, 0x00, -1, 0x01, 0x0001, 0x0003},\n\tcmdLutElement{0x00, 0x00, -1, 0x02, 0x0001, 0x0004},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0005},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0006},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0007},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0008},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0001, 0x0009},\n\tcmdLutElement{0x00, 0x00, -1, 0x00, 0x0002, 0x0002},\n\tcmdLutElement{0x00, 0x00, -1, 0x01, 0x0002, 0x0003},\n\tcmdLutElement{0x00, 0x00, -1, 0x02, 0x0002, 0x0004},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0005},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0006},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0007},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0008},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0002, 0x0009},\n\tcmdLutElement{0x00, 0x00, -1, 0x00, 0x0003, 0x0002},\n\tcmdLutElement{0x00, 0x00, -1, 0x01, 0x0003, 0x0003},\n\tcmdLutElement{0x00, 0x00, -1, 0x02, 0x0003, 0x0004},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0005},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0006},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0007},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0008},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0003, 0x0009},\n\tcmdLutElement{0x00, 0x00, -1, 0x00, 0x0004, 0x0002},\n\tcmdLutElement{0x00, 0x00, -1, 0x01, 0x0004, 0x0003},\n\tcmdLutElement{0x00, 0x00, -1, 0x02, 0x0004, 0x0004},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0005},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0006},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0007},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0008},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0004, 0x0009},\n\tcmdLutElement{0x00, 0x00, -1, 0x00, 0x0005, 0x0002},\n\tcmdLutElement{0x00, 0x00, -1, 0x01, 0x0005, 0x0003},\n\tcmdLutElement{0x00, 0x00, -1, 0x02, 0x0005, 0x0004},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0005},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0006},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0007},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0008},\n\tcmdLutElement{0x00, 0x00, -1, 0x03, 0x0005, 0x0009},\n\tcmdLutElement{0x01, 0x00, -1, 0x00, 0x0006, 0x0002},\n\tcmdLutElement{0x01, 0x00, -1, 0x01, 0x0006, 0x0003},\n\tcmdLutElement{0x01, 0x00, -1, 0x02, 0x0006, 0x0004},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0005},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0006},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0007},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0008},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0006, 0x0009},\n\tcmdLutElement{0x01, 0x00, -1, 0x00, 0x0008, 0x0002},\n\tcmdLutElement{0x01, 0x00, -1, 0x01, 0x0008, 0x0003},\n\tcmdLutElement{0x01, 0x00, -1, 0x02, 0x0008, 0x0004},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0005},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0006},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0007},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0008},\n\tcmdLutElement{0x01, 0x00, -1, 0x03, 0x0008, 0x0009},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0000, 0x000a},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0000, 0x000c},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0000, 0x000e},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0000, 0x0012},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0000, 0x0016},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0000, 0x001e},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0000, 0x0026},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0000, 0x0036},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0001, 0x000a},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0001, 0x000c},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0001, 0x000e},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0001, 0x0012},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0001, 0x0016},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0001, 0x001e},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0001, 0x0026},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0001, 0x0036},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0002, 0x000a},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0002, 0x000c},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0002, 0x000e},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0002, 0x0012},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0002, 0x0016},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0002, 0x001e},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0002, 0x0026},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0002, 0x0036},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0003, 0x000a},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0003, 0x000c},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0003, 0x000e},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0003, 0x0012},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0003, 0x0016},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0003, 0x001e},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0003, 0x0026},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0003, 0x0036},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0004, 0x000a},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0004, 0x000c},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0004, 0x000e},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0004, 0x0012},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0004, 0x0016},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0004, 0x001e},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0004, 0x0026},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0004, 0x0036},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0005, 0x000a},\n\tcmdLutElement{0x00, 0x01, -1, 0x03, 0x0005, 0x000c},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0005, 0x000e},\n\tcmdLutElement{0x00, 0x02, -1, 0x03, 0x0005, 0x0012},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0005, 0x0016},\n\tcmdLutElement{0x00, 0x03, -1, 0x03, 0x0005, 0x001e},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0005, 0x0026},\n\tcmdLutElement{0x00, 0x04, -1, 0x03, 0x0005, 0x0036},\n\tcmdLutElement{0x01, 0x01, -1, 0x03, 0x0006, 0x000a},\n\tcmdLutElement{0x01, 0x01, -1, 0x03, 0x0006, 0x000c},\n\tcmdLutElement{0x01, 0x02, -1, 0x03, 0x0006, 0x000e},\n\tcmdLutElement{0x01, 0x02, -1, 0x03, 0x0006, 0x0012},\n\tcmdLutElement{0x01, 0x03, -1, 0x03, 0x0006, 0x0016},\n\tcmdLutElement{0x01, 0x03, -1, 0x03, 0x0006, 0x001e},\n\tcmdLutElement{0x01, 0x04, -1, 0x03, 0x0006, 0x0026},\n\tcmdLutElement{0x01, 0x04, -1, 0x03, 0x0006, 0x0036},\n\tcmdLutElement{0x01, 0x01, -1, 0x03, 0x0008, 0x000a},\n\tcmdLutElement{0x01, 0x01, -1, 0x03, 0x0008, 0x000c},\n\tcmdLutElement{0x01, 0x02, -1, 0x03, 0x0008, 0x000e},\n\tcmdLutElement{0x01, 0x02, -1, 0x03, 0x0008, 0x0012},\n\tcmdLutElement{0x01, 0x03, -1, 0x03, 0x0008, 0x0016},\n\tcmdLutElement{0x01, 0x03, -1, 0x03, 0x0008, 0x001e},\n\tcmdLutElement{0x01, 0x04, -1, 0x03, 0x0008, 0x0026},\n\tcmdLutElement{0x01, 0x04, -1, 0x03, 0x0008, 0x0036},\n\tcmdLutElement{0x02, 0x00, -1, 0x00, 0x000a, 0x0002},\n\tcmdLutElement{0x02, 0x00, -1, 0x01, 0x000a, 0x0003},\n\tcmdLutElement{0x02, 0x00, -1, 0x02, 0x000a, 0x0004},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0005},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0006},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0007},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0008},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000a, 0x0009},\n\tcmdLutElement{0x02, 0x00, -1, 0x00, 0x000e, 0x0002},\n\tcmdLutElement{0x02, 0x00, -1, 0x01, 0x000e, 0x0003},\n\tcmdLutElement{0x02, 0x00, -1, 0x02, 0x000e, 0x0004},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0005},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0006},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0007},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0008},\n\tcmdLutElement{0x02, 0x00, -1, 0x03, 0x000e, 0x0009},\n\tcmdLutElement{0x03, 0x00, -1, 0x00, 0x0012, 0x0002},\n\tcmdLutElement{0x03, 0x00, -1, 0x01, 0x0012, 0x0003},\n\tcmdLutElement{0x03, 0x00, -1, 0x02, 0x0012, 0x0004},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0005},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0006},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0007},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0008},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x0012, 0x0009},\n\tcmdLutElement{0x03, 0x00, -1, 0x00, 0x001a, 0x0002},\n\tcmdLutElement{0x03, 0x00, -1, 0x01, 0x001a, 0x0003},\n\tcmdLutElement{0x03, 0x00, -1, 0x02, 0x001a, 0x0004},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0005},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0006},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0007},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0008},\n\tcmdLutElement{0x03, 0x00, -1, 0x03, 0x001a, 0x0009},\n\tcmdLutElement{0x04, 0x00, -1, 0x00, 0x0022, 0x0002},\n\tcmdLutElement{0x04, 0x00, -1, 0x01, 0x0022, 0x0003},\n\tcmdLutElement{0x04, 0x00, -1, 0x02, 0x0022, 0x0004},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0005},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0006},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0007},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0008},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0022, 0x0009},\n\tcmdLutElement{0x04, 0x00, -1, 0x00, 0x0032, 0x0002},\n\tcmdLutElement{0x04, 0x00, -1, 0x01, 0x0032, 0x0003},\n\tcmdLutElement{0x04, 0x00, -1, 0x02, 0x0032, 0x0004},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0005},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0006},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0007},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0008},\n\tcmdLutElement{0x04, 0x00, -1, 0x03, 0x0032, 0x0009},\n\tcmdLutElement{0x05, 0x00, -1, 0x00, 0x0042, 0x0002},\n\tcmdLutElement{0x05, 0x00, -1, 0x01, 0x0042, 0x0003},\n\tcmdLutElement{0x05, 0x00, -1, 0x02, 0x0042, 0x0004},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0005},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0006},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0007},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0008},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0042, 0x0009},\n\tcmdLutElement{0x05, 0x00, -1, 0x00, 0x0062, 0x0002},\n\tcmdLutElement{0x05, 0x00, -1, 0x01, 0x0062, 0x0003},\n\tcmdLutElement{0x05, 0x00, -1, 0x02, 0x0062, 0x0004},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0005},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0006},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0007},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0008},\n\tcmdLutElement{0x05, 0x00, -1, 0x03, 0x0062, 0x0009},\n\tcmdLutElement{0x02, 0x01, -1, 0x03, 0x000a, 0x000a},\n\tcmdLutElement{0x02, 0x01, -1, 0x03, 0x000a, 0x000c},\n\tcmdLutElement{0x02, 0x02, -1, 0x03, 0x000a, 0x000e},\n\tcmdLutElement{0x02, 0x02, -1, 0x03, 0x000a, 0x0012},\n\tcmdLutElement{0x02, 0x03, -1, 0x03, 0x000a, 0x0016},\n\tcmdLutElement{0x02, 0x03, -1, 0x03, 0x000a, 0x001e},\n\tcmdLutElement{0x02, 0x04, -1, 0x03, 0x000a, 0x0026},\n\tcmdLutElement{0x02, 0x04, -1, 0x03, 0x000a, 0x0036},\n\tcmdLutElement{0x02, 0x01, -1, 0x03, 0x000e, 0x000a},\n\tcmdLutElement{0x02, 0x01, -1, 0x03, 0x000e, 0x000c},\n\tcmdLutElement{0x02, 0x02, -1, 0x03, 0x000e, 0x000e},\n\tcmdLutElement{0x02, 0x02, -1, 0x03, 0x000e, 0x0012},\n\tcmdLutElement{0x02, 0x03, -1, 0x03, 0x000e, 0x0016},\n\tcmdLutElement{0x02, 0x03, -1, 0x03, 0x000e, 0x001e},\n\tcmdLutElement{0x02, 0x04, -1, 0x03, 0x000e, 0x0026},\n\tcmdLutElement{0x02, 0x04, -1, 0x03, 0x000e, 0x0036},\n\tcmdLutElement{0x03, 0x01, -1, 0x03, 0x0012, 0x000a},\n\tcmdLutElement{0x03, 0x01, -1, 0x03, 0x0012, 0x000c},\n\tcmdLutElement{0x03, 0x02, -1, 0x03, 0x0012, 0x000e},\n\tcmdLutElement{0x03, 0x02, -1, 0x03, 0x0012, 0x0012},\n\tcmdLutElement{0x03, 0x03, -1, 0x03, 0x0012, 0x0016},\n\tcmdLutElement{0x03, 0x03, -1, 0x03, 0x0012, 0x001e},\n\tcmdLutElement{0x03, 0x04, -1, 0x03, 0x0012, 0x0026},\n\tcmdLutElement{0x03, 0x04, -1, 0x03, 0x0012, 0x0036},\n\tcmdLutElement{0x03, 0x01, -1, 0x03, 0x001a, 0x000a},\n\tcmdLutElement{0x03, 0x01, -1, 0x03, 0x001a, 0x000c},\n\tcmdLutElement{0x03, 0x02, -1, 0x03, 0x001a, 0x000e},\n\tcmdLutElement{0x03, 0x02, -1, 0x03, 0x001a, 0x0012},\n\tcmdLutElement{0x03, 0x03, -1, 0x03, 0x001a, 0x0016},\n\tcmdLutElement{0x03, 0x03, -1, 0x03, 0x001a, 0x001e},\n\tcmdLutElement{0x03, 0x04, -1, 0x03, 0x001a, 0x0026},\n\tcmdLutElement{0x03, 0x04, -1, 0x03, 0x001a, 0x0036},\n\tcmdLutElement{0x04, 0x01, -1, 0x03, 0x0022, 0x000a},\n\tcmdLutElement{0x04, 0x01, -1, 0x03, 0x0022, 0x000c},\n\tcmdLutElement{0x04, 0x02, -1, 0x03, 0x0022, 0x000e},\n\tcmdLutElement{0x04, 0x02, -1, 0x03, 0x0022, 0x0012},\n\tcmdLutElement{0x04, 0x03, -1, 0x03, 0x0022, 0x0016},\n\tcmdLutElement{0x04, 0x03, -1, 0x03, 0x0022, 0x001e},\n\tcmdLutElement{0x04, 0x04, -1, 0x03, 0x0022, 0x0026},\n\tcmdLutElement{0x04, 0x04, -1, 0x03, 0x0022, 0x0036},\n\tcmdLutElement{0x04, 0x01, -1, 0x03, 0x0032, 0x000a},\n\tcmdLutElement{0x04, 0x01, -1, 0x03, 0x0032, 0x000c},\n\tcmdLutElement{0x04, 0x02, -1, 0x03, 0x0032, 0x000e},\n\tcmdLutElement{0x04, 0x02, -1, 0x03, 0x0032, 0x0012},\n\tcmdLutElement{0x04, 0x03, -1, 0x03, 0x0032, 0x0016},\n\tcmdLutElement{0x04, 0x03, -1, 0x03, 0x0032, 0x001e},\n\tcmdLutElement{0x04, 0x04, -1, 0x03, 0x0032, 0x0026},\n\tcmdLutElement{0x04, 0x04, -1, 0x03, 0x0032, 0x0036},\n\tcmdLutElement{0x05, 0x01, -1, 0x03, 0x0042, 0x000a},\n\tcmdLutElement{0x05, 0x01, -1, 0x03, 0x0042, 0x000c},\n\tcmdLutElement{0x05, 0x02, -1, 0x03, 0x0042, 0x000e},\n\tcmdLutElement{0x05, 0x02, -1, 0x03, 0x0042, 0x0012},\n\tcmdLutElement{0x05, 0x03, -1, 0x03, 0x0042, 0x0016},\n\tcmdLutElement{0x05, 0x03, -1, 0x03, 0x0042, 0x001e},\n\tcmdLutElement{0x05, 0x04, -1, 0x03, 0x0042, 0x0026},\n\tcmdLutElement{0x05, 0x04, -1, 0x03, 0x0042, 0x0036},\n\tcmdLutElement{0x05, 0x01, -1, 0x03, 0x0062, 0x000a},\n\tcmdLutElement{0x05, 0x01, -1, 0x03, 0x0062, 0x000c},\n\tcmdLutElement{0x05, 0x02, -1, 0x03, 0x0062, 0x000e},\n\tcmdLutElement{0x05, 0x02, -1, 0x03, 0x0062, 0x0012},\n\tcmdLutElement{0x05, 0x03, -1, 0x03, 0x0062, 0x0016},\n\tcmdLutElement{0x05, 0x03, -1, 0x03, 0x0062, 0x001e},\n\tcmdLutElement{0x05, 0x04, -1, 0x03, 0x0062, 0x0026},\n\tcmdLutElement{0x05, 0x04, -1, 0x03, 0x0062, 0x0036},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0000, 0x0046},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0000, 0x0066},\n\tcmdLutElement{0x00, 0x06, -1, 0x03, 0x0000, 0x0086},\n\tcmdLutElement{0x00, 0x07, -1, 0x03, 0x0000, 0x00c6},\n\tcmdLutElement{0x00, 0x08, -1, 0x03, 0x0000, 0x0146},\n\tcmdLutElement{0x00, 0x09, -1, 0x03, 0x0000, 0x0246},\n\tcmdLutElement{0x00, 0x0a, -1, 0x03, 0x0000, 0x0446},\n\tcmdLutElement{0x00, 0x18, -1, 0x03, 0x0000, 0x0846},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0001, 0x0046},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0001, 0x0066},\n\tcmdLutElement{0x00, 0x06, -1, 0x03, 0x0001, 0x0086},\n\tcmdLutElement{0x00, 0x07, -1, 0x03, 0x0001, 0x00c6},\n\tcmdLutElement{0x00, 0x08, -1, 0x03, 0x0001, 0x0146},\n\tcmdLutElement{0x00, 0x09, -1, 0x03, 0x0001, 0x0246},\n\tcmdLutElement{0x00, 0x0a, -1, 0x03, 0x0001, 0x0446},\n\tcmdLutElement{0x00, 0x18, -1, 0x03, 0x0001, 0x0846},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0002, 0x0046},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0002, 0x0066},\n\tcmdLutElement{0x00, 0x06, -1, 0x03, 0x0002, 0x0086},\n\tcmdLutElement{0x00, 0x07, -1, 0x03, 0x0002, 0x00c6},\n\tcmdLutElement{0x00, 0x08, -1, 0x03, 0x0002, 0x0146},\n\tcmdLutElement{0x00, 0x09, -1, 0x03, 0x0002, 0x0246},\n\tcmdLutElement{0x00, 0x0a, -1, 0x03, 0x0002, 0x0446},\n\tcmdLutElement{0x00, 0x18, -1, 0x03, 0x0002, 0x0846},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0003, 0x0046},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0003, 0x0066},\n\tcmdLutElement{0x00, 0x06, -1, 0x03, 0x0003, 0x0086},\n\tcmdLutElement{0x00, 0x07, -1, 0x03, 0x0003, 0x00c6},\n\tcmdLutElement{0x00, 0x08, -1, 0x03, 0x0003, 0x0146},\n\tcmdLutElement{0x00, 0x09, -1, 0x03, 0x0003, 0x0246},\n\tcmdLutElement{0x00, 0x0a, -1, 0x03, 0x0003, 0x0446},\n\tcmdLutElement{0x00, 0x18, -1, 0x03, 0x0003, 0x0846},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0004, 0x0046},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0004, 0x0066},\n\tcmdLutElement{0x00, 0x06, -1, 0x03, 0x0004, 0x0086},\n\tcmdLutElement{0x00, 0x07, -1, 0x03, 0x0004, 0x00c6},\n\tcmdLutElement{0x00, 0x08, -1, 0x03, 0x0004, 0x0146},\n\tcmdLutElement{0x00, 0x09, -1, 0x03, 0x0004, 0x0246},\n\tcmdLutElement{0x00, 0x0a, -1, 0x03, 0x0004, 0x0446},\n\tcmdLutElement{0x00, 0x18, -1, 0x03, 0x0004, 0x0846},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0005, 0x0046},\n\tcmdLutElement{0x00, 0x05, -1, 0x03, 0x0005, 0x0066},\n\tcmdLutElement{0x00, 0x06, -1, 0x03, 0x0005, 0x0086},\n\tcmdLutElement{0x00, 0x07, -1, 0x03, 0x0005, 0x00c6},\n\tcmdLutElement{0x00, 0x08, -1, 0x03, 0x0005, 0x0146},\n\tcmdLutElement{0x00, 0x09, -1, 0x03, 0x0005, 0x0246},\n\tcmdLutElement{0x00, 0x0a, -1, 0x03, 0x0005, 0x0446},\n\tcmdLutElement{0x00, 0x18, -1, 0x03, 0x0005, 0x0846},\n\tcmdLutElement{0x01, 0x05, -1, 0x03, 0x0006, 0x0046},\n\tcmdLutElement{0x01, 0x05, -1, 0x03, 0x0006, 0x0066},\n\tcmdLutElement{0x01, 0x06, -1, 0x03, 0x0006, 0x0086},\n\tcmdLutElement{0x01, 0x07, -1, 0x03, 0x0006, 0x00c6},\n\tcmdLutElement{0x01, 0x08, -1, 0x03, 0x0006, 0x0146},\n\tcmdLutElement{0x01, 0x09, -1, 0x03, 0x0006, 0x0246},\n\tcmdLutElement{0x01, 0x0a, -1, 0x03, 0x0006, 0x0446},\n\tcmdLutElement{0x01, 0x18, -1, 0x03, 0x0006, 0x0846},\n\tcmdLutElement{0x01, 0x05, -1, 0x03, 0x0008, 0x0046},\n\tcmdLutElement{0x01, 0x05, -1, 0x03, 0x0008, 0x0066},\n\tcmdLutElement{0x01, 0x06, -1, 0x03, 0x0008, 0x0086},\n\tcmdLutElement{0x01, 0x07, -1, 0x03, 0x0008, 0x00c6},\n\tcmdLutElement{0x01, 0x08, -1, 0x03, 0x0008, 0x0146},\n\tcmdLutElement{0x01, 0x09, -1, 0x03, 0x0008, 0x0246},\n\tcmdLutElement{0x01, 0x0a, -1, 0x03, 0x0008, 0x0446},\n\tcmdLutElement{0x01, 0x18, -1, 0x03, 0x0008, 0x0846},\n\tcmdLutElement{0x06, 0x00, -1, 0x00, 0x0082, 0x0002},\n\tcmdLutElement{0x06, 0x00, -1, 0x01, 0x0082, 0x0003},\n\tcmdLutElement{0x06, 0x00, -1, 0x02, 0x0082, 0x0004},\n\tcmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0005},\n\tcmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0006},\n\tcmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0007},\n\tcmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0008},\n\tcmdLutElement{0x06, 0x00, -1, 0x03, 0x0082, 0x0009},\n\tcmdLutElement{0x07, 0x00, -1, 0x00, 0x00c2, 0x0002},\n\tcmdLutElement{0x07, 0x00, -1, 0x01, 0x00c2, 0x0003},\n\tcmdLutElement{0x07, 0x00, -1, 0x02, 0x00c2, 0x0004},\n\tcmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0005},\n\tcmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0006},\n\tcmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0007},\n\tcmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0008},\n\tcmdLutElement{0x07, 0x00, -1, 0x03, 0x00c2, 0x0009},\n\tcmdLutElement{0x08, 0x00, -1, 0x00, 0x0142, 0x0002},\n\tcmdLutElement{0x08, 0x00, -1, 0x01, 0x0142, 0x0003},\n\tcmdLutElement{0x08, 0x00, -1, 0x02, 0x0142, 0x0004},\n\tcmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0005},\n\tcmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0006},\n\tcmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0007},\n\tcmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0008},\n\tcmdLutElement{0x08, 0x00, -1, 0x03, 0x0142, 0x0009},\n\tcmdLutElement{0x09, 0x00, -1, 0x00, 0x0242, 0x0002},\n\tcmdLutElement{0x09, 0x00, -1, 0x01, 0x0242, 0x0003},\n\tcmdLutElement{0x09, 0x00, -1, 0x02, 0x0242, 0x0004},\n\tcmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0005},\n\tcmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0006},\n\tcmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0007},\n\tcmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0008},\n\tcmdLutElement{0x09, 0x00, -1, 0x03, 0x0242, 0x0009},\n\tcmdLutElement{0x0a, 0x00, -1, 0x00, 0x0442, 0x0002},\n\tcmdLutElement{0x0a, 0x00, -1, 0x01, 0x0442, 0x0003},\n\tcmdLutElement{0x0a, 0x00, -1, 0x02, 0x0442, 0x0004},\n\tcmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0005},\n\tcmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0006},\n\tcmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0007},\n\tcmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0008},\n\tcmdLutElement{0x0a, 0x00, -1, 0x03, 0x0442, 0x0009},\n\tcmdLutElement{0x0c, 0x00, -1, 0x00, 0x0842, 0x0002},\n\tcmdLutElement{0x0c, 0x00, -1, 0x01, 0x0842, 0x0003},\n\tcmdLutElement{0x0c, 0x00, -1, 0x02, 0x0842, 0x0004},\n\tcmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0005},\n\tcmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0006},\n\tcmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0007},\n\tcmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0008},\n\tcmdLutElement{0x0c, 0x00, -1, 0x03, 0x0842, 0x0009},\n\tcmdLutElement{0x0e, 0x00, -1, 0x00, 0x1842, 0x0002},\n\tcmdLutElement{0x0e, 0x00, -1, 0x01, 0x1842, 0x0003},\n\tcmdLutElement{0x0e, 0x00, -1, 0x02, 0x1842, 0x0004},\n\tcmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0005},\n\tcmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0006},\n\tcmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0007},\n\tcmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0008},\n\tcmdLutElement{0x0e, 0x00, -1, 0x03, 0x1842, 0x0009},\n\tcmdLutElement{0x18, 0x00, -1, 0x00, 0x5842, 0x0002},\n\tcmdLutElement{0x18, 0x00, -1, 0x01, 0x5842, 0x0003},\n\tcmdLutElement{0x18, 0x00, -1, 0x02, 0x5842, 0x0004},\n\tcmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0005},\n\tcmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0006},\n\tcmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0007},\n\tcmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0008},\n\tcmdLutElement{0x18, 0x00, -1, 0x03, 0x5842, 0x0009},\n\tcmdLutElement{0x02, 0x05, -1, 0x03, 0x000a, 0x0046},\n\tcmdLutElement{0x02, 0x05, -1, 0x03, 0x000a, 0x0066},\n\tcmdLutElement{0x02, 0x06, -1, 0x03, 0x000a, 0x0086},\n\tcmdLutElement{0x02, 0x07, -1, 0x03, 0x000a, 0x00c6},\n\tcmdLutElement{0x02, 0x08, -1, 0x03, 0x000a, 0x0146},\n\tcmdLutElement{0x02, 0x09, -1, 0x03, 0x000a, 0x0246},\n\tcmdLutElement{0x02, 0x0a, -1, 0x03, 0x000a, 0x0446},\n\tcmdLutElement{0x02, 0x18, -1, 0x03, 0x000a, 0x0846},\n\tcmdLutElement{0x02, 0x05, -1, 0x03, 0x000e, 0x0046},\n\tcmdLutElement{0x02, 0x05, -1, 0x03, 0x000e, 0x0066},\n\tcmdLutElement{0x02, 0x06, -1, 0x03, 0x000e, 0x0086},\n\tcmdLutElement{0x02, 0x07, -1, 0x03, 0x000e, 0x00c6},\n\tcmdLutElement{0x02, 0x08, -1, 0x03, 0x000e, 0x0146},\n\tcmdLutElement{0x02, 0x09, -1, 0x03, 0x000e, 0x0246},\n\tcmdLutElement{0x02, 0x0a, -1, 0x03, 0x000e, 0x0446},\n\tcmdLutElement{0x02, 0x18, -1, 0x03, 0x000e, 0x0846},\n\tcmdLutElement{0x03, 0x05, -1, 0x03, 0x0012, 0x0046},\n\tcmdLutElement{0x03, 0x05, -1, 0x03, 0x0012, 0x0066},\n\tcmdLutElement{0x03, 0x06, -1, 0x03, 0x0012, 0x0086},\n\tcmdLutElement{0x03, 0x07, -1, 0x03, 0x0012, 0x00c6},\n\tcmdLutElement{0x03, 0x08, -1, 0x03, 0x0012, 0x0146},\n\tcmdLutElement{0x03, 0x09, -1, 0x03, 0x0012, 0x0246},\n\tcmdLutElement{0x03, 0x0a, -1, 0x03, 0x0012, 0x0446},\n\tcmdLutElement{0x03, 0x18, -1, 0x03, 0x0012, 0x0846},\n\tcmdLutElement{0x03, 0x05, -1, 0x03, 0x001a, 0x0046},\n\tcmdLutElement{0x03, 0x05, -1, 0x03, 0x001a, 0x0066},\n\tcmdLutElement{0x03, 0x06, -1, 0x03, 0x001a, 0x0086},\n\tcmdLutElement{0x03, 0x07, -1, 0x03, 0x001a, 0x00c6},\n\tcmdLutElement{0x03, 0x08, -1, 0x03, 0x001a, 0x0146},\n\tcmdLutElement{0x03, 0x09, -1, 0x03, 0x001a, 0x0246},\n\tcmdLutElement{0x03, 0x0a, -1, 0x03, 0x001a, 0x0446},\n\tcmdLutElement{0x03, 0x18, -1, 0x03, 0x001a, 0x0846},\n\tcmdLutElement{0x04, 0x05, -1, 0x03, 0x0022, 0x0046},\n\tcmdLutElement{0x04, 0x05, -1, 0x03, 0x0022, 0x0066},\n\tcmdLutElement{0x04, 0x06, -1, 0x03, 0x0022, 0x0086},\n\tcmdLutElement{0x04, 0x07, -1, 0x03, 0x0022, 0x00c6},\n\tcmdLutElement{0x04, 0x08, -1, 0x03, 0x0022, 0x0146},\n\tcmdLutElement{0x04, 0x09, -1, 0x03, 0x0022, 0x0246},\n\tcmdLutElement{0x04, 0x0a, -1, 0x03, 0x0022, 0x0446},\n\tcmdLutElement{0x04, 0x18, -1, 0x03, 0x0022, 0x0846},\n\tcmdLutElement{0x04, 0x05, -1, 0x03, 0x0032, 0x0046},\n\tcmdLutElement{0x04, 0x05, -1, 0x03, 0x0032, 0x0066},\n\tcmdLutElement{0x04, 0x06, -1, 0x03, 0x0032, 0x0086},\n\tcmdLutElement{0x04, 0x07, -1, 0x03, 0x0032, 0x00c6},\n\tcmdLutElement{0x04, 0x08, -1, 0x03, 0x0032, 0x0146},\n\tcmdLutElement{0x04, 0x09, -1, 0x03, 0x0032, 0x0246},\n\tcmdLutElement{0x04, 0x0a, -1, 0x03, 0x0032, 0x0446},\n\tcmdLutElement{0x04, 0x18, -1, 0x03, 0x0032, 0x0846},\n\tcmdLutElement{0x05, 0x05, -1, 0x03, 0x0042, 0x0046},\n\tcmdLutElement{0x05, 0x05, -1, 0x03, 0x0042, 0x0066},\n\tcmdLutElement{0x05, 0x06, -1, 0x03, 0x0042, 0x0086},\n\tcmdLutElement{0x05, 0x07, -1, 0x03, 0x0042, 0x00c6},\n\tcmdLutElement{0x05, 0x08, -1, 0x03, 0x0042, 0x0146},\n\tcmdLutElement{0x05, 0x09, -1, 0x03, 0x0042, 0x0246},\n\tcmdLutElement{0x05, 0x0a, -1, 0x03, 0x0042, 0x0446},\n\tcmdLutElement{0x05, 0x18, -1, 0x03, 0x0042, 0x0846},\n\tcmdLutElement{0x05, 0x05, -1, 0x03, 0x0062, 0x0046},\n\tcmdLutElement{0x05, 0x05, -1, 0x03, 0x0062, 0x0066},\n\tcmdLutElement{0x05, 0x06, -1, 0x03, 0x0062, 0x0086},\n\tcmdLutElement{0x05, 0x07, -1, 0x03, 0x0062, 0x00c6},\n\tcmdLutElement{0x05, 0x08, -1, 0x03, 0x0062, 0x0146},\n\tcmdLutElement{0x05, 0x09, -1, 0x03, 0x0062, 0x0246},\n\tcmdLutElement{0x05, 0x0a, -1, 0x03, 0x0062, 0x0446},\n\tcmdLutElement{0x05, 0x18, -1, 0x03, 0x0062, 0x0846},\n\tcmdLutElement{0x06, 0x01, -1, 0x03, 0x0082, 0x000a},\n\tcmdLutElement{0x06, 0x01, -1, 0x03, 0x0082, 0x000c},\n\tcmdLutElement{0x06, 0x02, -1, 0x03, 0x0082, 0x000e},\n\tcmdLutElement{0x06, 0x02, -1, 0x03, 0x0082, 0x0012},\n\tcmdLutElement{0x06, 0x03, -1, 0x03, 0x0082, 0x0016},\n\tcmdLutElement{0x06, 0x03, -1, 0x03, 0x0082, 0x001e},\n\tcmdLutElement{0x06, 0x04, -1, 0x03, 0x0082, 0x0026},\n\tcmdLutElement{0x06, 0x04, -1, 0x03, 0x0082, 0x0036},\n\tcmdLutElement{0x07, 0x01, -1, 0x03, 0x00c2, 0x000a},\n\tcmdLutElement{0x07, 0x01, -1, 0x03, 0x00c2, 0x000c},\n\tcmdLutElement{0x07, 0x02, -1, 0x03, 0x00c2, 0x000e},\n\tcmdLutElement{0x07, 0x02, -1, 0x03, 0x00c2, 0x0012},\n\tcmdLutElement{0x07, 0x03, -1, 0x03, 0x00c2, 0x0016},\n\tcmdLutElement{0x07, 0x03, -1, 0x03, 0x00c2, 0x001e},\n\tcmdLutElement{0x07, 0x04, -1, 0x03, 0x00c2, 0x0026},\n\tcmdLutElement{0x07, 0x04, -1, 0x03, 0x00c2, 0x0036},\n\tcmdLutElement{0x08, 0x01, -1, 0x03, 0x0142, 0x000a},\n\tcmdLutElement{0x08, 0x01, -1, 0x03, 0x0142, 0x000c},\n\tcmdLutElement{0x08, 0x02, -1, 0x03, 0x0142, 0x000e},\n\tcmdLutElement{0x08, 0x02, -1, 0x03, 0x0142, 0x0012},\n\tcmdLutElement{0x08, 0x03, -1, 0x03, 0x0142, 0x0016},\n\tcmdLutElement{0x08, 0x03, -1, 0x03, 0x0142, 0x001e},\n\tcmdLutElement{0x08, 0x04, -1, 0x03, 0x0142, 0x0026},\n\tcmdLutElement{0x08, 0x04, -1, 0x03, 0x0142, 0x0036},\n\tcmdLutElement{0x09, 0x01, -1, 0x03, 0x0242, 0x000a},\n\tcmdLutElement{0x09, 0x01, -1, 0x03, 0x0242, 0x000c},\n\tcmdLutElement{0x09, 0x02, -1, 0x03, 0x0242, 0x000e},\n\tcmdLutElement{0x09, 0x02, -1, 0x03, 0x0242, 0x0012},\n\tcmdLutElement{0x09, 0x03, -1, 0x03, 0x0242, 0x0016},\n\tcmdLutElement{0x09, 0x03, -1, 0x03, 0x0242, 0x001e},\n\tcmdLutElement{0x09, 0x04, -1, 0x03, 0x0242, 0x0026},\n\tcmdLutElement{0x09, 0x04, -1, 0x03, 0x0242, 0x0036},\n\tcmdLutElement{0x0a, 0x01, -1, 0x03, 0x0442, 0x000a},\n\tcmdLutElement{0x0a, 0x01, -1, 0x03, 0x0442, 0x000c},\n\tcmdLutElement{0x0a, 0x02, -1, 0x03, 0x0442, 0x000e},\n\tcmdLutElement{0x0a, 0x02, -1, 0x03, 0x0442, 0x0012},\n\tcmdLutElement{0x0a, 0x03, -1, 0x03, 0x0442, 0x0016},\n\tcmdLutElement{0x0a, 0x03, -1, 0x03, 0x0442, 0x001e},\n\tcmdLutElement{0x0a, 0x04, -1, 0x03, 0x0442, 0x0026},\n\tcmdLutElement{0x0a, 0x04, -1, 0x03, 0x0442, 0x0036},\n\tcmdLutElement{0x0c, 0x01, -1, 0x03, 0x0842, 0x000a},\n\tcmdLutElement{0x0c, 0x01, -1, 0x03, 0x0842, 0x000c},\n\tcmdLutElement{0x0c, 0x02, -1, 0x03, 0x0842, 0x000e},\n\tcmdLutElement{0x0c, 0x02, -1, 0x03, 0x0842, 0x0012},\n\tcmdLutElement{0x0c, 0x03, -1, 0x03, 0x0842, 0x0016},\n\tcmdLutElement{0x0c, 0x03, -1, 0x03, 0x0842, 0x001e},\n\tcmdLutElement{0x0c, 0x04, -1, 0x03, 0x0842, 0x0026},\n\tcmdLutElement{0x0c, 0x04, -1, 0x03, 0x0842, 0x0036},\n\tcmdLutElement{0x0e, 0x01, -1, 0x03, 0x1842, 0x000a},\n\tcmdLutElement{0x0e, 0x01, -1, 0x03, 0x1842, 0x000c},\n\tcmdLutElement{0x0e, 0x02, -1, 0x03, 0x1842, 0x000e},\n\tcmdLutElement{0x0e, 0x02, -1, 0x03, 0x1842, 0x0012},\n\tcmdLutElement{0x0e, 0x03, -1, 0x03, 0x1842, 0x0016},\n\tcmdLutElement{0x0e, 0x03, -1, 0x03, 0x1842, 0x001e},\n\tcmdLutElement{0x0e, 0x04, -1, 0x03, 0x1842, 0x0026},\n\tcmdLutElement{0x0e, 0x04, -1, 0x03, 0x1842, 0x0036},\n\tcmdLutElement{0x18, 0x01, -1, 0x03, 0x5842, 0x000a},\n\tcmdLutElement{0x18, 0x01, -1, 0x03, 0x5842, 0x000c},\n\tcmdLutElement{0x18, 0x02, -1, 0x03, 0x5842, 0x000e},\n\tcmdLutElement{0x18, 0x02, -1, 0x03, 0x5842, 0x0012},\n\tcmdLutElement{0x18, 0x03, -1, 0x03, 0x5842, 0x0016},\n\tcmdLutElement{0x18, 0x03, -1, 0x03, 0x5842, 0x001e},\n\tcmdLutElement{0x18, 0x04, -1, 0x03, 0x5842, 0x0026},\n\tcmdLutElement{0x18, 0x04, -1, 0x03, 0x5842, 0x0036},\n\tcmdLutElement{0x06, 0x05, -1, 0x03, 0x0082, 0x0046},\n\tcmdLutElement{0x06, 0x05, -1, 0x03, 0x0082, 0x0066},\n\tcmdLutElement{0x06, 0x06, -1, 0x03, 0x0082, 0x0086},\n\tcmdLutElement{0x06, 0x07, -1, 0x03, 0x0082, 0x00c6},\n\tcmdLutElement{0x06, 0x08, -1, 0x03, 0x0082, 0x0146},\n\tcmdLutElement{0x06, 0x09, -1, 0x03, 0x0082, 0x0246},\n\tcmdLutElement{0x06, 0x0a, -1, 0x03, 0x0082, 0x0446},\n\tcmdLutElement{0x06, 0x18, -1, 0x03, 0x0082, 0x0846},\n\tcmdLutElement{0x07, 0x05, -1, 0x03, 0x00c2, 0x0046},\n\tcmdLutElement{0x07, 0x05, -1, 0x03, 0x00c2, 0x0066},\n\tcmdLutElement{0x07, 0x06, -1, 0x03, 0x00c2, 0x0086},\n\tcmdLutElement{0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6},\n\tcmdLutElement{0x07, 0x08, -1, 0x03, 0x00c2, 0x0146},\n\tcmdLutElement{0x07, 0x09, -1, 0x03, 0x00c2, 0x0246},\n\tcmdLutElement{0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446},\n\tcmdLutElement{0x07, 0x18, -1, 0x03, 0x00c2, 0x0846},\n\tcmdLutElement{0x08, 0x05, -1, 0x03, 0x0142, 0x0046},\n\tcmdLutElement{0x08, 0x05, -1, 0x03, 0x0142, 0x0066},\n\tcmdLutElement{0x08, 0x06, -1, 0x03, 0x0142, 0x0086},\n\tcmdLutElement{0x08, 0x07, -1, 0x03, 0x0142, 0x00c6},\n\tcmdLutElement{0x08, 0x08, -1, 0x03, 0x0142, 0x0146},\n\tcmdLutElement{0x08, 0x09, -1, 0x03, 0x0142, 0x0246},\n\tcmdLutElement{0x08, 0x0a, -1, 0x03, 0x0142, 0x0446},\n\tcmdLutElement{0x08, 0x18, -1, 0x03, 0x0142, 0x0846},\n\tcmdLutElement{0x09, 0x05, -1, 0x03, 0x0242, 0x0046},\n\tcmdLutElement{0x09, 0x05, -1, 0x03, 0x0242, 0x0066},\n\tcmdLutElement{0x09, 0x06, -1, 0x03, 0x0242, 0x0086},\n\tcmdLutElement{0x09, 0x07, -1, 0x03, 0x0242, 0x00c6},\n\tcmdLutElement{0x09, 0x08, -1, 0x03, 0x0242, 0x0146},\n\tcmdLutElement{0x09, 0x09, -1, 0x03, 0x0242, 0x0246},\n\tcmdLutElement{0x09, 0x0a, -1, 0x03, 0x0242, 0x0446},\n\tcmdLutElement{0x09, 0x18, -1, 0x03, 0x0242, 0x0846},\n\tcmdLutElement{0x0a, 0x05, -1, 0x03, 0x0442, 0x0046},\n\tcmdLutElement{0x0a, 0x05, -1, 0x03, 0x0442, 0x0066},\n\tcmdLutElement{0x0a, 0x06, -1, 0x03, 0x0442, 0x0086},\n\tcmdLutElement{0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6},\n\tcmdLutElement{0x0a, 0x08, -1, 0x03, 0x0442, 0x0146},\n\tcmdLutElement{0x0a, 0x09, -1, 0x03, 0x0442, 0x0246},\n\tcmdLutElement{0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446},\n\tcmdLutElement{0x0a, 0x18, -1, 0x03, 0x0442, 0x0846},\n\tcmdLutElement{0x0c, 0x05, -1, 0x03, 0x0842, 0x0046},\n\tcmdLutElement{0x0c, 0x05, -1, 0x03, 0x0842, 0x0066},\n\tcmdLutElement{0x0c, 0x06, -1, 0x03, 0x0842, 0x0086},\n\tcmdLutElement{0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6},\n\tcmdLutElement{0x0c, 0x08, -1, 0x03, 0x0842, 0x0146},\n\tcmdLutElement{0x0c, 0x09, -1, 0x03, 0x0842, 0x0246},\n\tcmdLutElement{0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446},\n\tcmdLutElement{0x0c, 0x18, -1, 0x03, 0x0842, 0x0846},\n\tcmdLutElement{0x0e, 0x05, -1, 0x03, 0x1842, 0x0046},\n\tcmdLutElement{0x0e, 0x05, -1, 0x03, 0x1842, 0x0066},\n\tcmdLutElement{0x0e, 0x06, -1, 0x03, 0x1842, 0x0086},\n\tcmdLutElement{0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6},\n\tcmdLutElement{0x0e, 0x08, -1, 0x03, 0x1842, 0x0146},\n\tcmdLutElement{0x0e, 0x09, -1, 0x03, 0x1842, 0x0246},\n\tcmdLutElement{0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446},\n\tcmdLutElement{0x0e, 0x18, -1, 0x03, 0x1842, 0x0846},\n\tcmdLutElement{0x18, 0x05, -1, 0x03, 0x5842, 0x0046},\n\tcmdLutElement{0x18, 0x05, -1, 0x03, 0x5842, 0x0066},\n\tcmdLutElement{0x18, 0x06, -1, 0x03, 0x5842, 0x0086},\n\tcmdLutElement{0x18, 0x07, -1, 0x03, 0x5842, 0x00c6},\n\tcmdLutElement{0x18, 0x08, -1, 0x03, 0x5842, 0x0146},\n\tcmdLutElement{0x18, 0x09, -1, 0x03, 0x5842, 0x0246},\n\tcmdLutElement{0x18, 0x0a, -1, 0x03, 0x5842, 0x0446},\n\tcmdLutElement{0x18, 0x18, -1, 0x03, 0x5842, 0x0846},\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/quality.go",
    "content": "package brotli\n\nconst fastOnePassCompressionQuality = 0\n\nconst fastTwoPassCompressionQuality = 1\n\nconst zopflificationQuality = 10\n\nconst hqZopflificationQuality = 11\n\nconst maxQualityForStaticEntropyCodes = 2\n\nconst minQualityForBlockSplit = 4\n\nconst minQualityForNonzeroDistanceParams = 4\n\nconst minQualityForOptimizeHistograms = 4\n\nconst minQualityForExtensiveReferenceSearch = 5\n\nconst minQualityForContextModeling = 5\n\nconst minQualityForHqContextModeling = 7\n\nconst minQualityForHqBlockSplitting = 10\n\n/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,\n   so we buffer at most this much literals and commands. */\nconst maxNumDelayedSymbols = 0x2FFF\n\n/* Returns hash-table size for quality levels 0 and 1. */\nfunc maxHashTableSize(quality int) uint {\n\tif quality == fastOnePassCompressionQuality {\n\t\treturn 1 << 15\n\t} else {\n\t\treturn 1 << 17\n\t}\n}\n\n/* The maximum length for which the zopflification uses distinct distances. */\nconst maxZopfliLenQuality10 = 150\n\nconst maxZopfliLenQuality11 = 325\n\n/* Do not thoroughly search when a long copy is found. */\nconst longCopyQuickStep = 16384\n\nfunc maxZopfliLen(params *encoderParams) uint {\n\tif params.quality <= 10 {\n\t\treturn maxZopfliLenQuality10\n\t} else {\n\t\treturn maxZopfliLenQuality11\n\t}\n}\n\n/* Number of best candidates to evaluate to expand Zopfli chain. */\nfunc maxZopfliCandidates(params *encoderParams) uint {\n\tif params.quality <= 10 {\n\t\treturn 1\n\t} else {\n\t\treturn 5\n\t}\n}\n\nfunc sanitizeParams(params *encoderParams) {\n\tparams.quality = brotli_min_int(maxQuality, brotli_max_int(minQuality, params.quality))\n\tif params.quality <= maxQualityForStaticEntropyCodes {\n\t\tparams.large_window = false\n\t}\n\n\tif params.lgwin < minWindowBits {\n\t\tparams.lgwin = minWindowBits\n\t} else {\n\t\tvar max_lgwin int\n\t\tif params.large_window {\n\t\t\tmax_lgwin = largeMaxWindowBits\n\t\t} else {\n\t\t\tmax_lgwin = maxWindowBits\n\t\t}\n\t\tif params.lgwin > uint(max_lgwin) {\n\t\t\tparams.lgwin = uint(max_lgwin)\n\t\t}\n\t}\n}\n\n/* Returns optimized lg_block value. */\nfunc computeLgBlock(params *encoderParams) int {\n\tvar lgblock int = params.lgblock\n\tif params.quality == fastOnePassCompressionQuality || params.quality == fastTwoPassCompressionQuality {\n\t\tlgblock = int(params.lgwin)\n\t} else if params.quality < minQualityForBlockSplit {\n\t\tlgblock = 14\n\t} else if lgblock == 0 {\n\t\tlgblock = 16\n\t\tif params.quality >= 9 && params.lgwin > uint(lgblock) {\n\t\t\tlgblock = brotli_min_int(18, int(params.lgwin))\n\t\t}\n\t} else {\n\t\tlgblock = brotli_min_int(maxInputBlockBits, brotli_max_int(minInputBlockBits, lgblock))\n\t}\n\n\treturn lgblock\n}\n\n/* Returns log2 of the size of main ring buffer area.\n   Allocate at least lgwin + 1 bits for the ring buffer so that the newly\n   added block fits there completely and we still get lgwin bits and at least\n   read_block_size_bits + 1 bits because the copy tail length needs to be\n   smaller than ring-buffer size. */\nfunc computeRbBits(params *encoderParams) int {\n\treturn 1 + brotli_max_int(int(params.lgwin), params.lgblock)\n}\n\nfunc maxMetablockSize(params *encoderParams) uint {\n\tvar bits int = brotli_min_int(computeRbBits(params), maxInputBlockBits)\n\treturn uint(1) << uint(bits)\n}\n\n/* When searching for backward references and have not seen matches for a long\n   time, we can skip some match lookups. Unsuccessful match lookups are very\n   expensive and this kind of a heuristic speeds up compression quite a lot.\n   At first 8 byte strides are taken and every second byte is put to hasher.\n   After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.\n   Applied only to qualities 2 to 9. */\nfunc literalSpreeLengthForSparseSearch(params *encoderParams) uint {\n\tif params.quality < 9 {\n\t\treturn 64\n\t} else {\n\t\treturn 512\n\t}\n}\n\nfunc chooseHasher(params *encoderParams, hparams *hasherParams) {\n\tif params.quality > 9 {\n\t\thparams.type_ = 10\n\t} else if params.quality == 4 && params.size_hint >= 1<<20 {\n\t\thparams.type_ = 54\n\t} else if params.quality < 5 {\n\t\thparams.type_ = params.quality\n\t} else if params.lgwin <= 16 {\n\t\tif params.quality < 7 {\n\t\t\thparams.type_ = 40\n\t\t} else if params.quality < 9 {\n\t\t\thparams.type_ = 41\n\t\t} else {\n\t\t\thparams.type_ = 42\n\t\t}\n\t} else if params.size_hint >= 1<<20 && params.lgwin >= 19 {\n\t\thparams.type_ = 6\n\t\thparams.block_bits = params.quality - 1\n\t\thparams.bucket_bits = 15\n\t\thparams.hash_len = 5\n\t\tif params.quality < 7 {\n\t\t\thparams.num_last_distances_to_check = 4\n\t\t} else if params.quality < 9 {\n\t\t\thparams.num_last_distances_to_check = 10\n\t\t} else {\n\t\t\thparams.num_last_distances_to_check = 16\n\t\t}\n\t} else {\n\t\thparams.type_ = 5\n\t\thparams.block_bits = params.quality - 1\n\t\tif params.quality < 7 {\n\t\t\thparams.bucket_bits = 14\n\t\t} else {\n\t\t\thparams.bucket_bits = 15\n\t\t}\n\t\tif params.quality < 7 {\n\t\t\thparams.num_last_distances_to_check = 4\n\t\t} else if params.quality < 9 {\n\t\t\thparams.num_last_distances_to_check = 10\n\t\t} else {\n\t\t\thparams.num_last_distances_to_check = 16\n\t\t}\n\t}\n\n\tif params.lgwin > 24 {\n\t\t/* Different hashers for large window brotli: not for qualities <= 2,\n\t\t   these are too fast for large window. Not for qualities >= 10: their\n\t\t   hasher already works well with large window. So the changes are:\n\t\t   H3 --> H35: for quality 3.\n\t\t   H54 --> H55: for quality 4 with size hint > 1MB\n\t\t   H6 --> H65: for qualities 5, 6, 7, 8, 9. */\n\t\tif hparams.type_ == 3 {\n\t\t\thparams.type_ = 35\n\t\t}\n\n\t\tif hparams.type_ == 54 {\n\t\t\thparams.type_ = 55\n\t\t}\n\n\t\tif hparams.type_ == 6 {\n\t\t\thparams.type_ = 65\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/reader.go",
    "content": "package brotli\n\nimport (\n\t\"errors\"\n\t\"io\"\n)\n\ntype decodeError int\n\nfunc (err decodeError) Error() string {\n\treturn \"brotli: \" + string(decoderErrorString(int(err)))\n}\n\nvar errExcessiveInput = errors.New(\"brotli: excessive input\")\nvar errInvalidState = errors.New(\"brotli: invalid state\")\n\n// readBufSize is a \"good\" buffer size that avoids excessive round-trips\n// between C and Go but doesn't waste too much memory on buffering.\n// It is arbitrarily chosen to be equal to the constant used in io.Copy.\nconst readBufSize = 32 * 1024\n\n// NewReader creates a new Reader reading the given reader.\nfunc NewReader(src io.Reader) *Reader {\n\tr := new(Reader)\n\tr.Reset(src)\n\treturn r\n}\n\n// Reset discards the Reader's state and makes it equivalent to the result of\n// its original state from NewReader, but reading from src instead.\n// This permits reusing a Reader rather than allocating a new one.\n// Error is always nil\nfunc (r *Reader) Reset(src io.Reader) error {\n\tif r.error_code < 0 {\n\t\t// There was an unrecoverable error, leaving the Reader's state\n\t\t// undefined. Clear out everything but the buffer.\n\t\t*r = Reader{buf: r.buf}\n\t}\n\n\tdecoderStateInit(r)\n\tr.src = src\n\tif r.buf == nil {\n\t\tr.buf = make([]byte, readBufSize)\n\t}\n\treturn nil\n}\n\nfunc (r *Reader) Read(p []byte) (n int, err error) {\n\tif !decoderHasMoreOutput(r) && len(r.in) == 0 {\n\t\tm, readErr := r.src.Read(r.buf)\n\t\tif m == 0 {\n\t\t\tif readErr == io.EOF && r.state != stateDone {\n\t\t\t\treadErr = io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\t// If readErr is `nil`, we just proxy underlying stream behavior.\n\t\t\treturn 0, readErr\n\t\t}\n\t\tr.in = r.buf[:m]\n\t}\n\n\tif len(p) == 0 {\n\t\treturn 0, nil\n\t}\n\n\tfor {\n\t\tvar written uint\n\t\tin_len := uint(len(r.in))\n\t\tout_len := uint(len(p))\n\t\tin_remaining := in_len\n\t\tout_remaining := out_len\n\t\tresult := decoderDecompressStream(r, &in_remaining, &r.in, &out_remaining, &p)\n\t\twritten = out_len - out_remaining\n\t\tn = int(written)\n\n\t\tswitch result {\n\t\tcase decoderResultSuccess:\n\t\t\tif len(r.in) > 0 {\n\t\t\t\treturn n, errExcessiveInput\n\t\t\t}\n\t\t\treturn n, nil\n\t\tcase decoderResultError:\n\t\t\treturn n, decodeError(decoderGetErrorCode(r))\n\t\tcase decoderResultNeedsMoreOutput:\n\t\t\tif n == 0 {\n\t\t\t\treturn 0, io.ErrShortBuffer\n\t\t\t}\n\t\t\treturn n, nil\n\t\tcase decoderNeedsMoreInput:\n\t\t}\n\n\t\tif len(r.in) != 0 {\n\t\t\treturn 0, errInvalidState\n\t\t}\n\n\t\t// Calling r.src.Read may block. Don't block if we have data to return.\n\t\tif n > 0 {\n\t\t\treturn n, nil\n\t\t}\n\n\t\t// Top off the buffer.\n\t\tencN, err := r.src.Read(r.buf)\n\t\tif encN == 0 {\n\t\t\t// Not enough data to complete decoding.\n\t\t\tif err == io.EOF {\n\t\t\t\treturn 0, io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\treturn 0, err\n\t\t}\n\t\tr.in = r.buf[:encN]\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/ringbuffer.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* A ringBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of\n   data in a circular manner: writing a byte writes it to:\n     `position() % (1 << window_bits)'.\n   For convenience, the ringBuffer array contains another copy of the\n   first `1 << tail_bits' bytes:\n     buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits),\n   and another copy of the last two bytes:\n     buffer_[-1] == buffer_[(1 << window_bits) - 1] and\n     buffer_[-2] == buffer_[(1 << window_bits) - 2]. */\ntype ringBuffer struct {\n\tsize_       uint32\n\tmask_       uint32\n\ttail_size_  uint32\n\ttotal_size_ uint32\n\tcur_size_   uint32\n\tpos_        uint32\n\tdata_       []byte\n\tbuffer_     []byte\n}\n\nfunc ringBufferInit(rb *ringBuffer) {\n\trb.pos_ = 0\n}\n\nfunc ringBufferSetup(params *encoderParams, rb *ringBuffer) {\n\tvar window_bits int = computeRbBits(params)\n\tvar tail_bits int = params.lgblock\n\t*(*uint32)(&rb.size_) = 1 << uint(window_bits)\n\t*(*uint32)(&rb.mask_) = (1 << uint(window_bits)) - 1\n\t*(*uint32)(&rb.tail_size_) = 1 << uint(tail_bits)\n\t*(*uint32)(&rb.total_size_) = rb.size_ + rb.tail_size_\n}\n\nconst kSlackForEightByteHashingEverywhere uint = 7\n\n/* Allocates or re-allocates data_ to the given length + plus some slack\n   region before and after. Fills the slack regions with zeros. */\nfunc ringBufferInitBuffer(buflen uint32, rb *ringBuffer) {\n\tvar new_data []byte\n\tvar i uint\n\tsize := 2 + int(buflen) + int(kSlackForEightByteHashingEverywhere)\n\tif cap(rb.data_) < size {\n\t\tnew_data = make([]byte, size)\n\t} else {\n\t\tnew_data = rb.data_[:size]\n\t}\n\tif rb.data_ != nil {\n\t\tcopy(new_data, rb.data_[:2+rb.cur_size_+uint32(kSlackForEightByteHashingEverywhere)])\n\t}\n\n\trb.data_ = new_data\n\trb.cur_size_ = buflen\n\trb.buffer_ = rb.data_[2:]\n\trb.data_[1] = 0\n\trb.data_[0] = rb.data_[1]\n\tfor i = 0; i < kSlackForEightByteHashingEverywhere; i++ {\n\t\trb.buffer_[rb.cur_size_+uint32(i)] = 0\n\t}\n}\n\nfunc ringBufferWriteTail(bytes []byte, n uint, rb *ringBuffer) {\n\tvar masked_pos uint = uint(rb.pos_ & rb.mask_)\n\tif uint32(masked_pos) < rb.tail_size_ {\n\t\t/* Just fill the tail buffer with the beginning data. */\n\t\tvar p uint = uint(rb.size_ + uint32(masked_pos))\n\t\tcopy(rb.buffer_[p:], bytes[:brotli_min_size_t(n, uint(rb.tail_size_-uint32(masked_pos)))])\n\t}\n}\n\n/* Push bytes into the ring buffer. */\nfunc ringBufferWrite(bytes []byte, n uint, rb *ringBuffer) {\n\tif rb.pos_ == 0 && uint32(n) < rb.tail_size_ {\n\t\t/* Special case for the first write: to process the first block, we don't\n\t\t   need to allocate the whole ring-buffer and we don't need the tail\n\t\t   either. However, we do this memory usage optimization only if the\n\t\t   first write is less than the tail size, which is also the input block\n\t\t   size, otherwise it is likely that other blocks will follow and we\n\t\t   will need to reallocate to the full size anyway. */\n\t\trb.pos_ = uint32(n)\n\n\t\tringBufferInitBuffer(rb.pos_, rb)\n\t\tcopy(rb.buffer_, bytes[:n])\n\t\treturn\n\t}\n\n\tif rb.cur_size_ < rb.total_size_ {\n\t\t/* Lazily allocate the full buffer. */\n\t\tringBufferInitBuffer(rb.total_size_, rb)\n\n\t\t/* Initialize the last two bytes to zero, so that we don't have to worry\n\t\t   later when we copy the last two bytes to the first two positions. */\n\t\trb.buffer_[rb.size_-2] = 0\n\n\t\trb.buffer_[rb.size_-1] = 0\n\t}\n\t{\n\t\tvar masked_pos uint = uint(rb.pos_ & rb.mask_)\n\n\t\t/* The length of the writes is limited so that we do not need to worry\n\t\t   about a write */\n\t\tringBufferWriteTail(bytes, n, rb)\n\n\t\tif uint32(masked_pos+n) <= rb.size_ {\n\t\t\t/* A single write fits. */\n\t\t\tcopy(rb.buffer_[masked_pos:], bytes[:n])\n\t\t} else {\n\t\t\t/* Split into two writes.\n\t\t\t   Copy into the end of the buffer, including the tail buffer. */\n\t\t\tcopy(rb.buffer_[masked_pos:], bytes[:brotli_min_size_t(n, uint(rb.total_size_-uint32(masked_pos)))])\n\n\t\t\t/* Copy into the beginning of the buffer */\n\t\t\tcopy(rb.buffer_, bytes[rb.size_-uint32(masked_pos):][:uint32(n)-(rb.size_-uint32(masked_pos))])\n\t\t}\n\t}\n\t{\n\t\tvar not_first_lap bool = rb.pos_&(1<<31) != 0\n\t\tvar rb_pos_mask uint32 = (1 << 31) - 1\n\t\trb.data_[0] = rb.buffer_[rb.size_-2]\n\t\trb.data_[1] = rb.buffer_[rb.size_-1]\n\t\trb.pos_ = (rb.pos_ & rb_pos_mask) + uint32(uint32(n)&rb_pos_mask)\n\t\tif not_first_lap {\n\t\t\t/* Wrap, but preserve not-a-first-lap feature. */\n\t\t\trb.pos_ |= 1 << 31\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/state.go",
    "content": "package brotli\n\nimport \"io\"\n\n/* Copyright 2015 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Brotli state for partial streaming decoding. */\nconst (\n\tstateUninited = iota\n\tstateLargeWindowBits\n\tstateInitialize\n\tstateMetablockBegin\n\tstateMetablockHeader\n\tstateMetablockHeader2\n\tstateContextModes\n\tstateCommandBegin\n\tstateCommandInner\n\tstateCommandPostDecodeLiterals\n\tstateCommandPostWrapCopy\n\tstateUncompressed\n\tstateMetadata\n\tstateCommandInnerWrite\n\tstateMetablockDone\n\tstateCommandPostWrite1\n\tstateCommandPostWrite2\n\tstateHuffmanCode0\n\tstateHuffmanCode1\n\tstateHuffmanCode2\n\tstateHuffmanCode3\n\tstateContextMap1\n\tstateContextMap2\n\tstateTreeGroup\n\tstateDone\n)\n\nconst (\n\tstateMetablockHeaderNone = iota\n\tstateMetablockHeaderEmpty\n\tstateMetablockHeaderNibbles\n\tstateMetablockHeaderSize\n\tstateMetablockHeaderUncompressed\n\tstateMetablockHeaderReserved\n\tstateMetablockHeaderBytes\n\tstateMetablockHeaderMetadata\n)\n\nconst (\n\tstateUncompressedNone = iota\n\tstateUncompressedWrite\n)\n\nconst (\n\tstateTreeGroupNone = iota\n\tstateTreeGroupLoop\n)\n\nconst (\n\tstateContextMapNone = iota\n\tstateContextMapReadPrefix\n\tstateContextMapHuffman\n\tstateContextMapDecode\n\tstateContextMapTransform\n)\n\nconst (\n\tstateHuffmanNone = iota\n\tstateHuffmanSimpleSize\n\tstateHuffmanSimpleRead\n\tstateHuffmanSimpleBuild\n\tstateHuffmanComplex\n\tstateHuffmanLengthSymbols\n)\n\nconst (\n\tstateDecodeUint8None = iota\n\tstateDecodeUint8Short\n\tstateDecodeUint8Long\n)\n\nconst (\n\tstateReadBlockLengthNone = iota\n\tstateReadBlockLengthSuffix\n)\n\ntype Reader struct {\n\tsrc io.Reader\n\tbuf []byte // scratch space for reading from src\n\tin  []byte // current chunk to decode; usually aliases buf\n\n\tstate        int\n\tloop_counter int\n\tbr           bitReader\n\tbuffer       struct {\n\t\tu64 uint64\n\t\tu8  [8]byte\n\t}\n\tbuffer_length               uint32\n\tpos                         int\n\tmax_backward_distance       int\n\tmax_distance                int\n\tringbuffer_size             int\n\tringbuffer_mask             int\n\tdist_rb_idx                 int\n\tdist_rb                     [4]int\n\terror_code                  int\n\tsub_loop_counter            uint32\n\tringbuffer                  []byte\n\tringbuffer_end              []byte\n\thtree_command               []huffmanCode\n\tcontext_lookup              []byte\n\tcontext_map_slice           []byte\n\tdist_context_map_slice      []byte\n\tliteral_hgroup              huffmanTreeGroup\n\tinsert_copy_hgroup          huffmanTreeGroup\n\tdistance_hgroup             huffmanTreeGroup\n\tblock_type_trees            []huffmanCode\n\tblock_len_trees             []huffmanCode\n\ttrivial_literal_context     int\n\tdistance_context            int\n\tmeta_block_remaining_len    int\n\tblock_length_index          uint32\n\tblock_length                [3]uint32\n\tnum_block_types             [3]uint32\n\tblock_type_rb               [6]uint32\n\tdistance_postfix_bits       uint32\n\tnum_direct_distance_codes   uint32\n\tdistance_postfix_mask       int\n\tnum_dist_htrees             uint32\n\tdist_context_map            []byte\n\tliteral_htree               []huffmanCode\n\tdist_htree_index            byte\n\trepeat_code_len             uint32\n\tprev_code_len               uint32\n\tcopy_length                 int\n\tdistance_code               int\n\trb_roundtrips               uint\n\tpartial_pos_out             uint\n\tsymbol                      uint32\n\trepeat                      uint32\n\tspace                       uint32\n\ttable                       [32]huffmanCode\n\tsymbol_lists                symbolList\n\tsymbols_lists_array         [huffmanMaxCodeLength + 1 + numCommandSymbols]uint16\n\tnext_symbol                 [32]int\n\tcode_length_code_lengths    [codeLengthCodes]byte\n\tcode_length_histo           [16]uint16\n\thtree_index                 int\n\tnext                        []huffmanCode\n\tcontext_index               uint32\n\tmax_run_length_prefix       uint32\n\tcode                        uint32\n\tcontext_map_table           [huffmanMaxSize272]huffmanCode\n\tsubstate_metablock_header   int\n\tsubstate_tree_group         int\n\tsubstate_context_map        int\n\tsubstate_uncompressed       int\n\tsubstate_huffman            int\n\tsubstate_decode_uint8       int\n\tsubstate_read_block_length  int\n\tis_last_metablock           uint\n\tis_uncompressed             uint\n\tis_metadata                 uint\n\tshould_wrap_ringbuffer      uint\n\tcanny_ringbuffer_allocation uint\n\tlarge_window                bool\n\tsize_nibbles                uint\n\twindow_bits                 uint32\n\tnew_ringbuffer_size         int\n\tnum_literal_htrees          uint32\n\tcontext_map                 []byte\n\tcontext_modes               []byte\n\tdictionary                  *dictionary\n\ttransforms                  *transforms\n\ttrivial_literal_contexts    [8]uint32\n}\n\nfunc decoderStateInit(s *Reader) bool {\n\ts.error_code = 0 /* BROTLI_DECODER_NO_ERROR */\n\n\tinitBitReader(&s.br)\n\ts.state = stateUninited\n\ts.large_window = false\n\ts.substate_metablock_header = stateMetablockHeaderNone\n\ts.substate_tree_group = stateTreeGroupNone\n\ts.substate_context_map = stateContextMapNone\n\ts.substate_uncompressed = stateUncompressedNone\n\ts.substate_huffman = stateHuffmanNone\n\ts.substate_decode_uint8 = stateDecodeUint8None\n\ts.substate_read_block_length = stateReadBlockLengthNone\n\n\ts.buffer_length = 0\n\ts.loop_counter = 0\n\ts.pos = 0\n\ts.rb_roundtrips = 0\n\ts.partial_pos_out = 0\n\n\ts.block_type_trees = nil\n\ts.block_len_trees = nil\n\ts.ringbuffer_size = 0\n\ts.new_ringbuffer_size = 0\n\ts.ringbuffer_mask = 0\n\n\ts.context_map = nil\n\ts.context_modes = nil\n\ts.dist_context_map = nil\n\ts.context_map_slice = nil\n\ts.dist_context_map_slice = nil\n\n\ts.sub_loop_counter = 0\n\n\ts.literal_hgroup.codes = nil\n\ts.literal_hgroup.htrees = nil\n\ts.insert_copy_hgroup.codes = nil\n\ts.insert_copy_hgroup.htrees = nil\n\ts.distance_hgroup.codes = nil\n\ts.distance_hgroup.htrees = nil\n\n\ts.is_last_metablock = 0\n\ts.is_uncompressed = 0\n\ts.is_metadata = 0\n\ts.should_wrap_ringbuffer = 0\n\ts.canny_ringbuffer_allocation = 1\n\n\ts.window_bits = 0\n\ts.max_distance = 0\n\ts.dist_rb[0] = 16\n\ts.dist_rb[1] = 15\n\ts.dist_rb[2] = 11\n\ts.dist_rb[3] = 4\n\ts.dist_rb_idx = 0\n\ts.block_type_trees = nil\n\ts.block_len_trees = nil\n\n\ts.symbol_lists.storage = s.symbols_lists_array[:]\n\ts.symbol_lists.offset = huffmanMaxCodeLength + 1\n\n\ts.dictionary = getDictionary()\n\ts.transforms = getTransforms()\n\n\treturn true\n}\n\nfunc decoderStateMetablockBegin(s *Reader) {\n\ts.meta_block_remaining_len = 0\n\ts.block_length[0] = 1 << 24\n\ts.block_length[1] = 1 << 24\n\ts.block_length[2] = 1 << 24\n\ts.num_block_types[0] = 1\n\ts.num_block_types[1] = 1\n\ts.num_block_types[2] = 1\n\ts.block_type_rb[0] = 1\n\ts.block_type_rb[1] = 0\n\ts.block_type_rb[2] = 1\n\ts.block_type_rb[3] = 0\n\ts.block_type_rb[4] = 1\n\ts.block_type_rb[5] = 0\n\ts.context_map = nil\n\ts.context_modes = nil\n\ts.dist_context_map = nil\n\ts.context_map_slice = nil\n\ts.literal_htree = nil\n\ts.dist_context_map_slice = nil\n\ts.dist_htree_index = 0\n\ts.context_lookup = nil\n\ts.literal_hgroup.codes = nil\n\ts.literal_hgroup.htrees = nil\n\ts.insert_copy_hgroup.codes = nil\n\ts.insert_copy_hgroup.htrees = nil\n\ts.distance_hgroup.codes = nil\n\ts.distance_hgroup.htrees = nil\n}\n\nfunc decoderStateCleanupAfterMetablock(s *Reader) {\n\ts.context_modes = nil\n\ts.context_map = nil\n\ts.dist_context_map = nil\n\ts.literal_hgroup.htrees = nil\n\ts.insert_copy_hgroup.htrees = nil\n\ts.distance_hgroup.htrees = nil\n}\n\nfunc decoderHuffmanTreeGroupInit(s *Reader, group *huffmanTreeGroup, alphabet_size uint32, max_symbol uint32, ntrees uint32) bool {\n\tvar max_table_size uint = uint(kMaxHuffmanTableSize[(alphabet_size+31)>>5])\n\tgroup.alphabet_size = uint16(alphabet_size)\n\tgroup.max_symbol = uint16(max_symbol)\n\tgroup.num_htrees = uint16(ntrees)\n\tgroup.htrees = make([][]huffmanCode, ntrees)\n\tgroup.codes = make([]huffmanCode, (uint(ntrees) * max_table_size))\n\treturn !(group.codes == nil)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/static_dict.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Class to model the static dictionary. */\n\nconst maxStaticDictionaryMatchLen = 37\n\nconst kInvalidMatch uint32 = 0xFFFFFFF\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\nfunc hash(data []byte) uint32 {\n\tvar h uint32 = binary.LittleEndian.Uint32(data) * kDictHashMul32\n\n\t/* The higher bits contain more mixture from the multiplication,\n\t   so we take our results from there. */\n\treturn h >> uint(32-kDictNumBits)\n}\n\nfunc addMatch(distance uint, len uint, len_code uint, matches []uint32) {\n\tvar match uint32 = uint32((distance << 5) + len_code)\n\tmatches[len] = brotli_min_uint32_t(matches[len], match)\n}\n\nfunc dictMatchLength(dict *dictionary, data []byte, id uint, len uint, maxlen uint) uint {\n\tvar offset uint = uint(dict.offsets_by_length[len]) + len*id\n\treturn findMatchLengthWithLimit(dict.data[offset:], data, brotli_min_size_t(uint(len), maxlen))\n}\n\nfunc isMatch(d *dictionary, w dictWord, data []byte, max_length uint) bool {\n\tif uint(w.len) > max_length {\n\t\treturn false\n\t} else {\n\t\tvar offset uint = uint(d.offsets_by_length[w.len]) + uint(w.len)*uint(w.idx)\n\t\tvar dict []byte = d.data[offset:]\n\t\tif w.transform == 0 {\n\t\t\t/* Match against base dictionary word. */\n\t\t\treturn findMatchLengthWithLimit(dict, data, uint(w.len)) == uint(w.len)\n\t\t} else if w.transform == 10 {\n\t\t\t/* Match against uppercase first transform.\n\t\t\t   Note that there are only ASCII uppercase words in the lookup table. */\n\t\t\treturn dict[0] >= 'a' && dict[0] <= 'z' && (dict[0]^32) == data[0] && findMatchLengthWithLimit(dict[1:], data[1:], uint(w.len)-1) == uint(w.len-1)\n\t\t} else {\n\t\t\t/* Match against uppercase all transform.\n\t\t\t   Note that there are only ASCII uppercase words in the lookup table. */\n\t\t\tvar i uint\n\t\t\tfor i = 0; i < uint(w.len); i++ {\n\t\t\t\tif dict[i] >= 'a' && dict[i] <= 'z' {\n\t\t\t\t\tif (dict[i] ^ 32) != data[i] {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif dict[i] != data[i] {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t}\n}\n\nfunc findAllStaticDictionaryMatches(dict *encoderDictionary, data []byte, min_length uint, max_length uint, matches []uint32) bool {\n\tvar has_found_match bool = false\n\t{\n\t\tvar offset uint = uint(dict.buckets[hash(data)])\n\t\tvar end bool = offset == 0\n\t\tfor !end {\n\t\t\tw := dict.dict_words[offset]\n\t\t\toffset++\n\t\t\tvar l uint = uint(w.len) & 0x1F\n\t\t\tvar n uint = uint(1) << dict.words.size_bits_by_length[l]\n\t\t\tvar id uint = uint(w.idx)\n\t\t\tend = !(w.len&0x80 == 0)\n\t\t\tw.len = byte(l)\n\t\t\tif w.transform == 0 {\n\t\t\t\tvar matchlen uint = dictMatchLength(dict.words, data, id, l, max_length)\n\t\t\t\tvar s []byte\n\t\t\t\tvar minlen uint\n\t\t\t\tvar maxlen uint\n\t\t\t\tvar len uint\n\n\t\t\t\t/* Transform \"\" + BROTLI_TRANSFORM_IDENTITY + \"\" */\n\t\t\t\tif matchlen == l {\n\t\t\t\t\taddMatch(id, l, l, matches)\n\t\t\t\t\thas_found_match = true\n\t\t\t\t}\n\n\t\t\t\t/* Transforms \"\" + BROTLI_TRANSFORM_OMIT_LAST_1 + \"\" and\n\t\t\t\t   \"\" + BROTLI_TRANSFORM_OMIT_LAST_1 + \"ing \" */\n\t\t\t\tif matchlen >= l-1 {\n\t\t\t\t\taddMatch(id+12*n, l-1, l, matches)\n\t\t\t\t\tif l+2 < max_length && data[l-1] == 'i' && data[l] == 'n' && data[l+1] == 'g' && data[l+2] == ' ' {\n\t\t\t\t\t\taddMatch(id+49*n, l+3, l, matches)\n\t\t\t\t\t}\n\n\t\t\t\t\thas_found_match = true\n\t\t\t\t}\n\n\t\t\t\t/* Transform \"\" + BROTLI_TRANSFORM_OMIT_LAST_# + \"\" (# = 2 .. 9) */\n\t\t\t\tminlen = min_length\n\n\t\t\t\tif l > 9 {\n\t\t\t\t\tminlen = brotli_max_size_t(minlen, l-9)\n\t\t\t\t}\n\t\t\t\tmaxlen = brotli_min_size_t(matchlen, l-2)\n\t\t\t\tfor len = minlen; len <= maxlen; len++ {\n\t\t\t\t\tvar cut uint = l - len\n\t\t\t\t\tvar transform_id uint = (cut << 2) + uint((dict.cutoffTransforms>>(cut*6))&0x3F)\n\t\t\t\t\taddMatch(id+transform_id*n, uint(len), l, matches)\n\t\t\t\t\thas_found_match = true\n\t\t\t\t}\n\n\t\t\t\tif matchlen < l || l+6 >= max_length {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\ts = data[l:]\n\n\t\t\t\t/* Transforms \"\" + BROTLI_TRANSFORM_IDENTITY + <suffix> */\n\t\t\t\tif s[0] == ' ' {\n\t\t\t\t\taddMatch(id+n, l+1, l, matches)\n\t\t\t\t\tif s[1] == 'a' {\n\t\t\t\t\t\tif s[2] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+28*n, l+3, l, matches)\n\t\t\t\t\t\t} else if s[2] == 's' {\n\t\t\t\t\t\t\tif s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+46*n, l+4, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if s[2] == 't' {\n\t\t\t\t\t\t\tif s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+60*n, l+4, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if s[2] == 'n' {\n\t\t\t\t\t\t\tif s[3] == 'd' && s[4] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+10*n, l+5, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'b' {\n\t\t\t\t\t\tif s[2] == 'y' && s[3] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+38*n, l+4, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'i' {\n\t\t\t\t\t\tif s[2] == 'n' {\n\t\t\t\t\t\t\tif s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+16*n, l+4, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if s[2] == 's' {\n\t\t\t\t\t\t\tif s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+47*n, l+4, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'f' {\n\t\t\t\t\t\tif s[2] == 'o' {\n\t\t\t\t\t\t\tif s[3] == 'r' && s[4] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+25*n, l+5, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if s[2] == 'r' {\n\t\t\t\t\t\t\tif s[3] == 'o' && s[4] == 'm' && s[5] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+37*n, l+6, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'o' {\n\t\t\t\t\t\tif s[2] == 'f' {\n\t\t\t\t\t\t\tif s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+8*n, l+4, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if s[2] == 'n' {\n\t\t\t\t\t\t\tif s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+45*n, l+4, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'n' {\n\t\t\t\t\t\tif s[2] == 'o' && s[3] == 't' && s[4] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+80*n, l+5, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 't' {\n\t\t\t\t\t\tif s[2] == 'h' {\n\t\t\t\t\t\t\tif s[3] == 'e' {\n\t\t\t\t\t\t\t\tif s[4] == ' ' {\n\t\t\t\t\t\t\t\t\taddMatch(id+5*n, l+5, l, matches)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if s[3] == 'a' {\n\t\t\t\t\t\t\t\tif s[4] == 't' && s[5] == ' ' {\n\t\t\t\t\t\t\t\t\taddMatch(id+29*n, l+6, l, matches)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if s[2] == 'o' {\n\t\t\t\t\t\t\tif s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+17*n, l+4, l, matches)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'w' {\n\t\t\t\t\t\tif s[2] == 'i' && s[3] == 't' && s[4] == 'h' && s[5] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+35*n, l+6, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == '\"' {\n\t\t\t\t\taddMatch(id+19*n, l+1, l, matches)\n\t\t\t\t\tif s[1] == '>' {\n\t\t\t\t\t\taddMatch(id+21*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == '.' {\n\t\t\t\t\taddMatch(id+20*n, l+1, l, matches)\n\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\taddMatch(id+31*n, l+2, l, matches)\n\t\t\t\t\t\tif s[2] == 'T' && s[3] == 'h' {\n\t\t\t\t\t\t\tif s[4] == 'e' {\n\t\t\t\t\t\t\t\tif s[5] == ' ' {\n\t\t\t\t\t\t\t\t\taddMatch(id+43*n, l+6, l, matches)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if s[4] == 'i' {\n\t\t\t\t\t\t\t\tif s[5] == 's' && s[6] == ' ' {\n\t\t\t\t\t\t\t\t\taddMatch(id+75*n, l+7, l, matches)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == ',' {\n\t\t\t\t\taddMatch(id+76*n, l+1, l, matches)\n\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\taddMatch(id+14*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == '\\n' {\n\t\t\t\t\taddMatch(id+22*n, l+1, l, matches)\n\t\t\t\t\tif s[1] == '\\t' {\n\t\t\t\t\t\taddMatch(id+50*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == ']' {\n\t\t\t\t\taddMatch(id+24*n, l+1, l, matches)\n\t\t\t\t} else if s[0] == '\\'' {\n\t\t\t\t\taddMatch(id+36*n, l+1, l, matches)\n\t\t\t\t} else if s[0] == ':' {\n\t\t\t\t\taddMatch(id+51*n, l+1, l, matches)\n\t\t\t\t} else if s[0] == '(' {\n\t\t\t\t\taddMatch(id+57*n, l+1, l, matches)\n\t\t\t\t} else if s[0] == '=' {\n\t\t\t\t\tif s[1] == '\"' {\n\t\t\t\t\t\taddMatch(id+70*n, l+2, l, matches)\n\t\t\t\t\t} else if s[1] == '\\'' {\n\t\t\t\t\t\taddMatch(id+86*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == 'a' {\n\t\t\t\t\tif s[1] == 'l' && s[2] == ' ' {\n\t\t\t\t\t\taddMatch(id+84*n, l+3, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == 'e' {\n\t\t\t\t\tif s[1] == 'd' {\n\t\t\t\t\t\tif s[2] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+53*n, l+3, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'r' {\n\t\t\t\t\t\tif s[2] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+82*n, l+3, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 's' {\n\t\t\t\t\t\tif s[2] == 't' && s[3] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+95*n, l+4, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == 'f' {\n\t\t\t\t\tif s[1] == 'u' && s[2] == 'l' && s[3] == ' ' {\n\t\t\t\t\t\taddMatch(id+90*n, l+4, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == 'i' {\n\t\t\t\t\tif s[1] == 'v' {\n\t\t\t\t\t\tif s[2] == 'e' && s[3] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+92*n, l+4, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'z' {\n\t\t\t\t\t\tif s[2] == 'e' && s[3] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+100*n, l+4, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == 'l' {\n\t\t\t\t\tif s[1] == 'e' {\n\t\t\t\t\t\tif s[2] == 's' && s[3] == 's' && s[4] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+93*n, l+5, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[1] == 'y' {\n\t\t\t\t\t\tif s[2] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+61*n, l+3, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == 'o' {\n\t\t\t\t\tif s[1] == 'u' && s[2] == 's' && s[3] == ' ' {\n\t\t\t\t\t\taddMatch(id+106*n, l+4, l, matches)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar is_all_caps bool = (w.transform != transformUppercaseFirst)\n\t\t\t\t/* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and\n\t\t\t\t    is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)\n\t\t\t\ttransform. */\n\n\t\t\t\tvar s []byte\n\t\t\t\tif !isMatch(dict.words, w, data, max_length) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t/* Transform \"\" + kUppercase{First,All} + \"\" */\n\t\t\t\tvar tmp int\n\t\t\t\tif is_all_caps {\n\t\t\t\t\ttmp = 44\n\t\t\t\t} else {\n\t\t\t\t\ttmp = 9\n\t\t\t\t}\n\t\t\t\taddMatch(id+uint(tmp)*n, l, l, matches)\n\n\t\t\t\thas_found_match = true\n\t\t\t\tif l+1 >= max_length {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t/* Transforms \"\" + kUppercase{First,All} + <suffix> */\n\t\t\t\ts = data[l:]\n\n\t\t\t\tif s[0] == ' ' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 68\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 4\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\t\t\t\t} else if s[0] == '\"' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 87\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 66\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\t\t\t\t\tif s[1] == '>' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 97\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 69\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == '.' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 101\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 79\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 114\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 88\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == ',' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 112\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 99\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 107\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 58\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == '\\'' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 94\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 74\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\t\t\t\t} else if s[0] == '(' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 113\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 78\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\t\t\t\t} else if s[0] == '=' {\n\t\t\t\t\tif s[1] == '\"' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 105\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 104\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t\t} else if s[1] == '\\'' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 116\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 108\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Transforms with prefixes \" \" and \".\" */\n\tif max_length >= 5 && (data[0] == ' ' || data[0] == '.') {\n\t\tvar is_space bool = (data[0] == ' ')\n\t\tvar offset uint = uint(dict.buckets[hash(data[1:])])\n\t\tvar end bool = offset == 0\n\t\tfor !end {\n\t\t\tw := dict.dict_words[offset]\n\t\t\toffset++\n\t\t\tvar l uint = uint(w.len) & 0x1F\n\t\t\tvar n uint = uint(1) << dict.words.size_bits_by_length[l]\n\t\t\tvar id uint = uint(w.idx)\n\t\t\tend = !(w.len&0x80 == 0)\n\t\t\tw.len = byte(l)\n\t\t\tif w.transform == 0 {\n\t\t\t\tvar s []byte\n\t\t\t\tif !isMatch(dict.words, w, data[1:], max_length-1) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t/* Transforms \" \" + BROTLI_TRANSFORM_IDENTITY + \"\" and\n\t\t\t\t   \".\" + BROTLI_TRANSFORM_IDENTITY + \"\" */\n\t\t\t\tvar tmp int\n\t\t\t\tif is_space {\n\t\t\t\t\ttmp = 6\n\t\t\t\t} else {\n\t\t\t\t\ttmp = 32\n\t\t\t\t}\n\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\n\t\t\t\thas_found_match = true\n\t\t\t\tif l+2 >= max_length {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t/* Transforms \" \" + BROTLI_TRANSFORM_IDENTITY + <suffix> and\n\t\t\t\t   \".\" + BROTLI_TRANSFORM_IDENTITY + <suffix>\n\t\t\t\t*/\n\t\t\t\ts = data[l+1:]\n\n\t\t\t\tif s[0] == ' ' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_space {\n\t\t\t\t\t\ttmp = 2\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 77\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t} else if s[0] == '(' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_space {\n\t\t\t\t\t\ttmp = 89\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 67\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t} else if is_space {\n\t\t\t\t\tif s[0] == ',' {\n\t\t\t\t\t\taddMatch(id+103*n, l+2, l, matches)\n\t\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+33*n, l+3, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[0] == '.' {\n\t\t\t\t\t\taddMatch(id+71*n, l+2, l, matches)\n\t\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\t\taddMatch(id+52*n, l+3, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if s[0] == '=' {\n\t\t\t\t\t\tif s[1] == '\"' {\n\t\t\t\t\t\t\taddMatch(id+81*n, l+3, l, matches)\n\t\t\t\t\t\t} else if s[1] == '\\'' {\n\t\t\t\t\t\t\taddMatch(id+98*n, l+3, l, matches)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if is_space {\n\t\t\t\tvar is_all_caps bool = (w.transform != transformUppercaseFirst)\n\t\t\t\t/* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and\n\t\t\t\t    is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL)\n\t\t\t\ttransform. */\n\n\t\t\t\tvar s []byte\n\t\t\t\tif !isMatch(dict.words, w, data[1:], max_length-1) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t/* Transforms \" \" + kUppercase{First,All} + \"\" */\n\t\t\t\tvar tmp int\n\t\t\t\tif is_all_caps {\n\t\t\t\t\ttmp = 85\n\t\t\t\t} else {\n\t\t\t\t\ttmp = 30\n\t\t\t\t}\n\t\t\t\taddMatch(id+uint(tmp)*n, l+1, l, matches)\n\n\t\t\t\thas_found_match = true\n\t\t\t\tif l+2 >= max_length {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t/* Transforms \" \" + kUppercase{First,All} + <suffix> */\n\t\t\t\ts = data[l+1:]\n\n\t\t\t\tif s[0] == ' ' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 83\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 15\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t} else if s[0] == ',' {\n\t\t\t\t\tif !is_all_caps {\n\t\t\t\t\t\taddMatch(id+109*n, l+2, l, matches)\n\t\t\t\t\t}\n\n\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 111\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 65\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+3, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == '.' {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\ttmp = 115\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 96\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+2, l, matches)\n\t\t\t\t\tif s[1] == ' ' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 117\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 91\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+3, l, matches)\n\t\t\t\t\t}\n\t\t\t\t} else if s[0] == '=' {\n\t\t\t\t\tif s[1] == '\"' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 110\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 118\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+3, l, matches)\n\t\t\t\t\t} else if s[1] == '\\'' {\n\t\t\t\t\t\tvar tmp int\n\t\t\t\t\t\tif is_all_caps {\n\t\t\t\t\t\t\ttmp = 119\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttmp = 120\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+uint(tmp)*n, l+3, l, matches)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif max_length >= 6 {\n\t\t/* Transforms with prefixes \"e \", \"s \", \", \" and \"\\xC2\\xA0\" */\n\t\tif (data[1] == ' ' && (data[0] == 'e' || data[0] == 's' || data[0] == ',')) || (data[0] == 0xC2 && data[1] == 0xA0) {\n\t\t\tvar offset uint = uint(dict.buckets[hash(data[2:])])\n\t\t\tvar end bool = offset == 0\n\t\t\tfor !end {\n\t\t\t\tw := dict.dict_words[offset]\n\t\t\t\toffset++\n\t\t\t\tvar l uint = uint(w.len) & 0x1F\n\t\t\t\tvar n uint = uint(1) << dict.words.size_bits_by_length[l]\n\t\t\t\tvar id uint = uint(w.idx)\n\t\t\t\tend = !(w.len&0x80 == 0)\n\t\t\t\tw.len = byte(l)\n\t\t\t\tif w.transform == 0 && isMatch(dict.words, w, data[2:], max_length-2) {\n\t\t\t\t\tif data[0] == 0xC2 {\n\t\t\t\t\t\taddMatch(id+102*n, l+2, l, matches)\n\t\t\t\t\t\thas_found_match = true\n\t\t\t\t\t} else if l+2 < max_length && data[l+2] == ' ' {\n\t\t\t\t\t\tvar t uint = 13\n\t\t\t\t\t\tif data[0] == 'e' {\n\t\t\t\t\t\t\tt = 18\n\t\t\t\t\t\t} else if data[0] == 's' {\n\t\t\t\t\t\t\tt = 7\n\t\t\t\t\t\t}\n\t\t\t\t\t\taddMatch(id+t*n, l+3, l, matches)\n\t\t\t\t\t\thas_found_match = true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif max_length >= 9 {\n\t\t/* Transforms with prefixes \" the \" and \".com/\" */\n\t\tif (data[0] == ' ' && data[1] == 't' && data[2] == 'h' && data[3] == 'e' && data[4] == ' ') || (data[0] == '.' && data[1] == 'c' && data[2] == 'o' && data[3] == 'm' && data[4] == '/') {\n\t\t\tvar offset uint = uint(dict.buckets[hash(data[5:])])\n\t\t\tvar end bool = offset == 0\n\t\t\tfor !end {\n\t\t\t\tw := dict.dict_words[offset]\n\t\t\t\toffset++\n\t\t\t\tvar l uint = uint(w.len) & 0x1F\n\t\t\t\tvar n uint = uint(1) << dict.words.size_bits_by_length[l]\n\t\t\t\tvar id uint = uint(w.idx)\n\t\t\t\tend = !(w.len&0x80 == 0)\n\t\t\t\tw.len = byte(l)\n\t\t\t\tif w.transform == 0 && isMatch(dict.words, w, data[5:], max_length-5) {\n\t\t\t\t\tvar tmp int\n\t\t\t\t\tif data[0] == ' ' {\n\t\t\t\t\t\ttmp = 41\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttmp = 72\n\t\t\t\t\t}\n\t\t\t\t\taddMatch(id+uint(tmp)*n, l+5, l, matches)\n\t\t\t\t\thas_found_match = true\n\t\t\t\t\tif l+5 < max_length {\n\t\t\t\t\t\tvar s []byte = data[l+5:]\n\t\t\t\t\t\tif data[0] == ' ' {\n\t\t\t\t\t\t\tif l+8 < max_length && s[0] == ' ' && s[1] == 'o' && s[2] == 'f' && s[3] == ' ' {\n\t\t\t\t\t\t\t\taddMatch(id+62*n, l+9, l, matches)\n\t\t\t\t\t\t\t\tif l+12 < max_length && s[4] == 't' && s[5] == 'h' && s[6] == 'e' && s[7] == ' ' {\n\t\t\t\t\t\t\t\t\taddMatch(id+73*n, l+13, l, matches)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn has_found_match\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/static_dict_lut.go",
    "content": "package brotli\n\n/* Copyright 2017 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Lookup table for static dictionary and transforms. */\n\ntype dictWord struct {\n\tlen       byte\n\ttransform byte\n\tidx       uint16\n}\n\nconst kDictNumBits int = 15\n\nconst kDictHashMul32 uint32 = 0x1E35A7BD\n\nvar kStaticDictionaryBuckets = [32768]uint16{\n\t1,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3,\n\t6,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20,\n\t0,\n\t0,\n\t0,\n\t21,\n\t0,\n\t22,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23,\n\t0,\n\t0,\n\t25,\n\t0,\n\t29,\n\t0,\n\t53,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t55,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t61,\n\t76,\n\t0,\n\t0,\n\t0,\n\t94,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t96,\n\t0,\n\t97,\n\t0,\n\t98,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t99,\n\t101,\n\t106,\n\t108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t110,\n\t0,\n\t111,\n\t112,\n\t0,\n\t113,\n\t118,\n\t124,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t125,\n\t128,\n\t0,\n\t0,\n\t0,\n\t0,\n\t129,\n\t0,\n\t0,\n\t131,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t132,\n\t0,\n\t0,\n\t135,\n\t0,\n\t0,\n\t0,\n\t137,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t138,\n\t139,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t142,\n\t143,\n\t144,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t145,\n\t0,\n\t0,\n\t0,\n\t146,\n\t149,\n\t151,\n\t152,\n\t0,\n\t0,\n\t153,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t154,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t155,\n\t0,\n\t0,\n\t0,\n\t0,\n\t160,\n\t182,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t183,\n\t0,\n\t0,\n\t0,\n\t188,\n\t189,\n\t0,\n\t0,\n\t192,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t194,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t197,\n\t202,\n\t209,\n\t0,\n\t0,\n\t210,\n\t0,\n\t224,\n\t0,\n\t0,\n\t0,\n\t225,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t231,\n\t0,\n\t0,\n\t0,\n\t232,\n\t0,\n\t240,\n\t0,\n\t0,\n\t242,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t244,\n\t0,\n\t0,\n\t0,\n\t246,\n\t0,\n\t0,\n\t249,\n\t251,\n\t253,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t258,\n\t0,\n\t0,\n\t261,\n\t263,\n\t0,\n\t0,\n\t0,\n\t267,\n\t0,\n\t0,\n\t268,\n\t0,\n\t269,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t271,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t272,\n\t0,\n\t273,\n\t0,\n\t277,\n\t0,\n\t278,\n\t286,\n\t0,\n\t0,\n\t0,\n\t0,\n\t287,\n\t0,\n\t289,\n\t290,\n\t291,\n\t0,\n\t0,\n\t0,\n\t295,\n\t0,\n\t0,\n\t296,\n\t297,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t298,\n\t0,\n\t0,\n\t0,\n\t299,\n\t0,\n\t0,\n\t305,\n\t0,\n\t324,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t327,\n\t0,\n\t328,\n\t329,\n\t0,\n\t0,\n\t0,\n\t0,\n\t336,\n\t0,\n\t0,\n\t340,\n\t0,\n\t341,\n\t342,\n\t343,\n\t0,\n\t0,\n\t346,\n\t0,\n\t348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t349,\n\t351,\n\t0,\n\t0,\n\t355,\n\t0,\n\t363,\n\t0,\n\t364,\n\t0,\n\t368,\n\t369,\n\t0,\n\t370,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t373,\n\t0,\n\t375,\n\t0,\n\t0,\n\t0,\n\t0,\n\t376,\n\t377,\n\t0,\n\t0,\n\t394,\n\t395,\n\t396,\n\t0,\n\t0,\n\t398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t400,\n\t0,\n\t0,\n\t408,\n\t0,\n\t0,\n\t0,\n\t0,\n\t420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t421,\n\t0,\n\t0,\n\t422,\n\t423,\n\t0,\n\t0,\n\t429,\n\t435,\n\t436,\n\t442,\n\t0,\n\t0,\n\t443,\n\t0,\n\t444,\n\t445,\n\t453,\n\t456,\n\t0,\n\t457,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t458,\n\t0,\n\t0,\n\t0,\n\t459,\n\t0,\n\t0,\n\t0,\n\t460,\n\t0,\n\t462,\n\t463,\n\t465,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t466,\n\t469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t470,\n\t0,\n\t0,\n\t0,\n\t474,\n\t0,\n\t476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t483,\n\t0,\n\t485,\n\t0,\n\t0,\n\t0,\n\t486,\n\t0,\n\t0,\n\t488,\n\t491,\n\t492,\n\t0,\n\t0,\n\t497,\n\t499,\n\t500,\n\t0,\n\t501,\n\t0,\n\t0,\n\t0,\n\t505,\n\t0,\n\t0,\n\t506,\n\t0,\n\t0,\n\t0,\n\t507,\n\t0,\n\t0,\n\t0,\n\t509,\n\t0,\n\t0,\n\t0,\n\t0,\n\t511,\n\t512,\n\t519,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t529,\n\t530,\n\t0,\n\t0,\n\t0,\n\t534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t553,\n\t0,\n\t0,\n\t0,\n\t0,\n\t557,\n\t560,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t561,\n\t0,\n\t564,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t565,\n\t566,\n\t0,\n\t575,\n\t0,\n\t619,\n\t0,\n\t620,\n\t0,\n\t0,\n\t623,\n\t624,\n\t0,\n\t0,\n\t0,\n\t625,\n\t0,\n\t0,\n\t626,\n\t627,\n\t0,\n\t0,\n\t628,\n\t0,\n\t0,\n\t0,\n\t0,\n\t630,\n\t0,\n\t631,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t641,\n\t0,\n\t0,\n\t0,\n\t0,\n\t643,\n\t656,\n\t668,\n\t0,\n\t0,\n\t0,\n\t673,\n\t0,\n\t0,\n\t0,\n\t674,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t682,\n\t0,\n\t687,\n\t0,\n\t690,\n\t0,\n\t693,\n\t699,\n\t700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t704,\n\t705,\n\t0,\n\t0,\n\t0,\n\t0,\n\t707,\n\t710,\n\t0,\n\t711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t726,\n\t0,\n\t0,\n\t729,\n\t0,\n\t0,\n\t0,\n\t730,\n\t731,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t752,\n\t0,\n\t0,\n\t0,\n\t762,\n\t0,\n\t763,\n\t0,\n\t0,\n\t767,\n\t0,\n\t0,\n\t0,\n\t770,\n\t774,\n\t0,\n\t0,\n\t775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t776,\n\t0,\n\t0,\n\t0,\n\t777,\n\t783,\n\t0,\n\t0,\n\t0,\n\t785,\n\t788,\n\t0,\n\t0,\n\t0,\n\t0,\n\t790,\n\t0,\n\t0,\n\t0,\n\t793,\n\t0,\n\t0,\n\t0,\n\t0,\n\t794,\n\t0,\n\t0,\n\t804,\n\t819,\n\t821,\n\t0,\n\t827,\n\t0,\n\t0,\n\t0,\n\t834,\n\t0,\n\t0,\n\t835,\n\t0,\n\t0,\n\t0,\n\t841,\n\t0,\n\t844,\n\t0,\n\t850,\n\t851,\n\t859,\n\t0,\n\t860,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t874,\n\t0,\n\t876,\n\t0,\n\t877,\n\t890,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t893,\n\t894,\n\t898,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t899,\n\t0,\n\t0,\n\t0,\n\t900,\n\t904,\n\t906,\n\t0,\n\t0,\n\t0,\n\t907,\n\t0,\n\t908,\n\t909,\n\t0,\n\t910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t911,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t916,\n\t0,\n\t0,\n\t0,\n\t922,\n\t925,\n\t0,\n\t930,\n\t0,\n\t934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t943,\n\t0,\n\t0,\n\t944,\n\t0,\n\t953,\n\t954,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t955,\n\t0,\n\t962,\n\t963,\n\t0,\n\t0,\n\t976,\n\t0,\n\t0,\n\t977,\n\t978,\n\t979,\n\t980,\n\t0,\n\t981,\n\t0,\n\t0,\n\t0,\n\t0,\n\t984,\n\t0,\n\t0,\n\t985,\n\t0,\n\t0,\n\t987,\n\t989,\n\t991,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t992,\n\t0,\n\t0,\n\t0,\n\t993,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t996,\n\t0,\n\t0,\n\t0,\n\t1000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1002,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1005,\n\t1007,\n\t0,\n\t0,\n\t0,\n\t1009,\n\t0,\n\t0,\n\t0,\n\t1010,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1011,\n\t0,\n\t1012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1014,\n\t1016,\n\t0,\n\t0,\n\t0,\n\t1020,\n\t0,\n\t1021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1022,\n\t0,\n\t0,\n\t0,\n\t1024,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1025,\n\t0,\n\t0,\n\t1026,\n\t1027,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1031,\n\t0,\n\t1033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1034,\n\t0,\n\t0,\n\t0,\n\t1037,\n\t1040,\n\t0,\n\t0,\n\t0,\n\t1042,\n\t1043,\n\t0,\n\t0,\n\t1053,\n\t0,\n\t1054,\n\t0,\n\t0,\n\t1057,\n\t0,\n\t0,\n\t0,\n\t1058,\n\t0,\n\t0,\n\t1060,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1061,\n\t0,\n\t0,\n\t1062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1063,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1065,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1066,\n\t1067,\n\t0,\n\t0,\n\t0,\n\t1069,\n\t1070,\n\t1072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1073,\n\t0,\n\t1075,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1080,\n\t1084,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1088,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1094,\n\t0,\n\t1095,\n\t0,\n\t1107,\n\t0,\n\t0,\n\t0,\n\t1112,\n\t1114,\n\t0,\n\t1119,\n\t0,\n\t1122,\n\t0,\n\t0,\n\t1126,\n\t0,\n\t1129,\n\t0,\n\t1130,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1132,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1144,\n\t0,\n\t0,\n\t1145,\n\t1146,\n\t0,\n\t1148,\n\t1149,\n\t0,\n\t0,\n\t1150,\n\t1151,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1152,\n\t0,\n\t1153,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1154,\n\t0,\n\t1163,\n\t0,\n\t0,\n\t0,\n\t1164,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1165,\n\t0,\n\t1167,\n\t0,\n\t1170,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1171,\n\t1172,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1173,\n\t1175,\n\t1177,\n\t0,\n\t1186,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1195,\n\t0,\n\t0,\n\t1221,\n\t0,\n\t0,\n\t1224,\n\t0,\n\t0,\n\t1227,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1228,\n\t1229,\n\t0,\n\t0,\n\t1230,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1231,\n\t0,\n\t0,\n\t0,\n\t1233,\n\t0,\n\t0,\n\t1243,\n\t1244,\n\t1246,\n\t1248,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1254,\n\t1255,\n\t1258,\n\t1259,\n\t0,\n\t0,\n\t0,\n\t1260,\n\t0,\n\t0,\n\t1261,\n\t0,\n\t0,\n\t0,\n\t1262,\n\t1264,\n\t0,\n\t0,\n\t1265,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1266,\n\t0,\n\t1267,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1273,\n\t1274,\n\t1276,\n\t1289,\n\t0,\n\t0,\n\t1291,\n\t1292,\n\t1293,\n\t0,\n\t0,\n\t1294,\n\t1295,\n\t1296,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1302,\n\t0,\n\t1304,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1311,\n\t1312,\n\t0,\n\t1314,\n\t0,\n\t1316,\n\t1320,\n\t1321,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1322,\n\t1323,\n\t1324,\n\t0,\n\t1335,\n\t0,\n\t1336,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1341,\n\t1342,\n\t0,\n\t1346,\n\t0,\n\t1357,\n\t0,\n\t0,\n\t0,\n\t1358,\n\t1360,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1361,\n\t0,\n\t0,\n\t0,\n\t1362,\n\t1365,\n\t0,\n\t1366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1379,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1386,\n\t0,\n\t1388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1395,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1403,\n\t0,\n\t1405,\n\t0,\n\t0,\n\t1407,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1408,\n\t1409,\n\t0,\n\t1410,\n\t0,\n\t0,\n\t0,\n\t1412,\n\t1413,\n\t1416,\n\t0,\n\t0,\n\t1429,\n\t1451,\n\t0,\n\t0,\n\t1454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1455,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1456,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1459,\n\t1460,\n\t1461,\n\t1475,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1477,\n\t0,\n\t1480,\n\t0,\n\t1481,\n\t0,\n\t0,\n\t1486,\n\t0,\n\t0,\n\t1495,\n\t0,\n\t0,\n\t0,\n\t1496,\n\t0,\n\t0,\n\t1498,\n\t1499,\n\t1501,\n\t1520,\n\t1521,\n\t0,\n\t0,\n\t0,\n\t1526,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1528,\n\t1529,\n\t0,\n\t1533,\n\t1536,\n\t0,\n\t0,\n\t0,\n\t1537,\n\t1538,\n\t1549,\n\t0,\n\t1550,\n\t1558,\n\t1559,\n\t1572,\n\t0,\n\t1573,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1579,\n\t0,\n\t1599,\n\t0,\n\t1603,\n\t0,\n\t1604,\n\t0,\n\t1605,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1608,\n\t1610,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1611,\n\t0,\n\t1615,\n\t0,\n\t1616,\n\t1618,\n\t0,\n\t1619,\n\t0,\n\t0,\n\t1622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1634,\n\t0,\n\t0,\n\t0,\n\t1635,\n\t0,\n\t0,\n\t0,\n\t1641,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1643,\n\t0,\n\t0,\n\t0,\n\t1650,\n\t0,\n\t0,\n\t1652,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1653,\n\t0,\n\t0,\n\t0,\n\t1654,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1655,\n\t0,\n\t1662,\n\t0,\n\t0,\n\t1663,\n\t1664,\n\t0,\n\t0,\n\t1668,\n\t0,\n\t0,\n\t1669,\n\t1670,\n\t0,\n\t1672,\n\t1673,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1674,\n\t0,\n\t0,\n\t0,\n\t1675,\n\t1676,\n\t1680,\n\t0,\n\t1682,\n\t0,\n\t0,\n\t1687,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1704,\n\t0,\n\t0,\n\t1705,\n\t0,\n\t0,\n\t1721,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1734,\n\t1735,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1737,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1739,\n\t0,\n\t0,\n\t1740,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1741,\n\t1743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1745,\n\t0,\n\t0,\n\t0,\n\t1749,\n\t0,\n\t0,\n\t0,\n\t1751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1765,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1784,\n\t0,\n\t1785,\n\t1787,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1788,\n\t1789,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1790,\n\t1791,\n\t1793,\n\t0,\n\t1798,\n\t1799,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1801,\n\t0,\n\t1803,\n\t1805,\n\t0,\n\t0,\n\t0,\n\t1806,\n\t1811,\n\t0,\n\t1812,\n\t1814,\n\t0,\n\t1821,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1822,\n\t1833,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1848,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1857,\n\t0,\n\t0,\n\t0,\n\t1859,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1861,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1866,\n\t0,\n\t1921,\n\t1925,\n\t0,\n\t0,\n\t0,\n\t1929,\n\t1930,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1931,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1932,\n\t0,\n\t0,\n\t0,\n\t1934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1946,\n\t0,\n\t0,\n\t1948,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1950,\n\t0,\n\t1957,\n\t0,\n\t1958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1965,\n\t1967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1968,\n\t0,\n\t1969,\n\t0,\n\t1971,\n\t1972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1973,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1975,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1976,\n\t1979,\n\t0,\n\t1982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1984,\n\t1988,\n\t0,\n\t0,\n\t0,\n\t0,\n\t1990,\n\t2004,\n\t2008,\n\t0,\n\t0,\n\t0,\n\t2012,\n\t2013,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2015,\n\t0,\n\t2016,\n\t2017,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2021,\n\t0,\n\t0,\n\t2025,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2029,\n\t2036,\n\t2040,\n\t0,\n\t2042,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2043,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2045,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2046,\n\t2047,\n\t0,\n\t2048,\n\t2049,\n\t0,\n\t2059,\n\t0,\n\t0,\n\t2063,\n\t0,\n\t2064,\n\t2065,\n\t0,\n\t0,\n\t2066,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2069,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2070,\n\t0,\n\t2071,\n\t0,\n\t2072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2080,\n\t2082,\n\t2083,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2085,\n\t0,\n\t2086,\n\t2088,\n\t2089,\n\t2105,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2107,\n\t0,\n\t0,\n\t2116,\n\t2117,\n\t0,\n\t2120,\n\t0,\n\t0,\n\t2122,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2123,\n\t0,\n\t0,\n\t2125,\n\t2127,\n\t2128,\n\t0,\n\t0,\n\t0,\n\t2130,\n\t0,\n\t0,\n\t0,\n\t2137,\n\t2139,\n\t2140,\n\t2141,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2144,\n\t2145,\n\t0,\n\t0,\n\t2146,\n\t2149,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2150,\n\t0,\n\t0,\n\t2151,\n\t2158,\n\t0,\n\t2159,\n\t0,\n\t2160,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2161,\n\t2162,\n\t0,\n\t0,\n\t2194,\n\t2202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2205,\n\t2217,\n\t0,\n\t2220,\n\t0,\n\t2221,\n\t0,\n\t2222,\n\t2224,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2238,\n\t0,\n\t2239,\n\t2241,\n\t0,\n\t0,\n\t2242,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2243,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2252,\n\t0,\n\t0,\n\t2253,\n\t0,\n\t0,\n\t0,\n\t2257,\n\t2258,\n\t0,\n\t0,\n\t0,\n\t2260,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2262,\n\t0,\n\t2264,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2269,\n\t2270,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2271,\n\t0,\n\t2273,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2278,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2279,\n\t0,\n\t2280,\n\t0,\n\t2283,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2287,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2289,\n\t2290,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2291,\n\t0,\n\t2292,\n\t0,\n\t0,\n\t0,\n\t2293,\n\t2295,\n\t2296,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2298,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2303,\n\t0,\n\t2305,\n\t0,\n\t0,\n\t2306,\n\t0,\n\t2307,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2313,\n\t2314,\n\t2315,\n\t2316,\n\t0,\n\t0,\n\t2318,\n\t0,\n\t2319,\n\t0,\n\t2322,\n\t0,\n\t0,\n\t2323,\n\t0,\n\t2324,\n\t0,\n\t2326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2335,\n\t0,\n\t2336,\n\t2338,\n\t2339,\n\t0,\n\t2340,\n\t0,\n\t0,\n\t0,\n\t2355,\n\t0,\n\t2375,\n\t0,\n\t2382,\n\t2386,\n\t0,\n\t2387,\n\t0,\n\t0,\n\t2394,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2395,\n\t0,\n\t2397,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2399,\n\t2402,\n\t2404,\n\t2408,\n\t2411,\n\t0,\n\t0,\n\t0,\n\t2413,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2415,\n\t0,\n\t0,\n\t2416,\n\t2417,\n\t2419,\n\t0,\n\t2420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2425,\n\t0,\n\t0,\n\t0,\n\t2426,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2427,\n\t2428,\n\t0,\n\t2429,\n\t0,\n\t0,\n\t2430,\n\t2434,\n\t0,\n\t2436,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2441,\n\t2442,\n\t0,\n\t2445,\n\t0,\n\t0,\n\t2446,\n\t2457,\n\t0,\n\t2459,\n\t0,\n\t0,\n\t2462,\n\t0,\n\t2464,\n\t0,\n\t2477,\n\t0,\n\t2478,\n\t2486,\n\t0,\n\t0,\n\t0,\n\t2491,\n\t0,\n\t0,\n\t2493,\n\t0,\n\t0,\n\t2494,\n\t0,\n\t2495,\n\t0,\n\t2513,\n\t2523,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2524,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2528,\n\t2529,\n\t2530,\n\t0,\n\t0,\n\t2531,\n\t0,\n\t2533,\n\t0,\n\t0,\n\t2534,\n\t2535,\n\t0,\n\t2536,\n\t2537,\n\t0,\n\t2538,\n\t0,\n\t2539,\n\t2540,\n\t0,\n\t0,\n\t0,\n\t2545,\n\t2546,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2548,\n\t0,\n\t0,\n\t2549,\n\t0,\n\t2550,\n\t2555,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2557,\n\t0,\n\t2560,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2561,\n\t0,\n\t2576,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2577,\n\t2578,\n\t0,\n\t0,\n\t0,\n\t2579,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2581,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2583,\n\t0,\n\t2584,\n\t0,\n\t2588,\n\t2590,\n\t0,\n\t0,\n\t0,\n\t2591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2593,\n\t2594,\n\t0,\n\t2595,\n\t0,\n\t2601,\n\t2602,\n\t0,\n\t0,\n\t2603,\n\t0,\n\t2605,\n\t0,\n\t0,\n\t0,\n\t2606,\n\t2607,\n\t2611,\n\t0,\n\t2615,\n\t0,\n\t0,\n\t0,\n\t2617,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2619,\n\t0,\n\t0,\n\t2620,\n\t0,\n\t0,\n\t0,\n\t2621,\n\t0,\n\t2623,\n\t0,\n\t2625,\n\t0,\n\t0,\n\t2628,\n\t2629,\n\t0,\n\t0,\n\t2635,\n\t2636,\n\t2637,\n\t0,\n\t0,\n\t2639,\n\t0,\n\t0,\n\t0,\n\t2642,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2643,\n\t0,\n\t2644,\n\t0,\n\t2649,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2655,\n\t2656,\n\t0,\n\t0,\n\t2657,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2658,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2659,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2664,\n\t2685,\n\t0,\n\t2687,\n\t0,\n\t2688,\n\t0,\n\t0,\n\t2689,\n\t0,\n\t0,\n\t2694,\n\t0,\n\t2695,\n\t0,\n\t0,\n\t2698,\n\t0,\n\t2701,\n\t2706,\n\t0,\n\t0,\n\t0,\n\t2707,\n\t0,\n\t2709,\n\t2710,\n\t2711,\n\t0,\n\t0,\n\t0,\n\t2720,\n\t2730,\n\t2735,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2738,\n\t2740,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2747,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2748,\n\t0,\n\t0,\n\t2749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2750,\n\t0,\n\t0,\n\t2752,\n\t2754,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2762,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2764,\n\t2767,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2768,\n\t0,\n\t0,\n\t2770,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2771,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2772,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2773,\n\t2776,\n\t0,\n\t0,\n\t2783,\n\t0,\n\t0,\n\t2784,\n\t0,\n\t2789,\n\t0,\n\t2790,\n\t0,\n\t0,\n\t0,\n\t2792,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2793,\n\t2795,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2797,\n\t2799,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2803,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2806,\n\t0,\n\t2807,\n\t2808,\n\t2817,\n\t2819,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2821,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2822,\n\t2823,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2824,\n\t0,\n\t0,\n\t2828,\n\t0,\n\t2834,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2836,\n\t0,\n\t2838,\n\t0,\n\t0,\n\t2839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2841,\n\t0,\n\t0,\n\t0,\n\t2842,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2843,\n\t2844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2846,\n\t0,\n\t0,\n\t2847,\n\t0,\n\t2849,\n\t0,\n\t2853,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2857,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2858,\n\t0,\n\t2859,\n\t0,\n\t0,\n\t2860,\n\t0,\n\t2862,\n\t2868,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2875,\n\t0,\n\t2876,\n\t0,\n\t0,\n\t2877,\n\t2878,\n\t2884,\n\t2889,\n\t2890,\n\t0,\n\t0,\n\t2891,\n\t0,\n\t0,\n\t2892,\n\t0,\n\t0,\n\t0,\n\t2906,\n\t2912,\n\t0,\n\t2913,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2916,\n\t0,\n\t2934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2935,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2939,\n\t0,\n\t2940,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2941,\n\t0,\n\t0,\n\t0,\n\t2946,\n\t0,\n\t2949,\n\t0,\n\t0,\n\t2950,\n\t2954,\n\t2955,\n\t0,\n\t0,\n\t0,\n\t2959,\n\t2961,\n\t0,\n\t0,\n\t2962,\n\t0,\n\t2963,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2964,\n\t2965,\n\t2966,\n\t2967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2969,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2970,\n\t2975,\n\t0,\n\t2982,\n\t2983,\n\t2984,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2989,\n\t0,\n\t0,\n\t2990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2991,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t2998,\n\t0,\n\t3000,\n\t3001,\n\t0,\n\t0,\n\t3002,\n\t0,\n\t0,\n\t0,\n\t3003,\n\t0,\n\t0,\n\t3012,\n\t0,\n\t0,\n\t3022,\n\t0,\n\t0,\n\t3024,\n\t0,\n\t0,\n\t3025,\n\t3027,\n\t0,\n\t0,\n\t0,\n\t3030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3034,\n\t3035,\n\t0,\n\t0,\n\t3036,\n\t0,\n\t3039,\n\t0,\n\t3049,\n\t0,\n\t0,\n\t3050,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3051,\n\t0,\n\t3053,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3057,\n\t0,\n\t3058,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3063,\n\t0,\n\t0,\n\t3073,\n\t3074,\n\t3078,\n\t3079,\n\t0,\n\t3080,\n\t3086,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3087,\n\t0,\n\t3092,\n\t0,\n\t3095,\n\t0,\n\t3099,\n\t0,\n\t0,\n\t0,\n\t3100,\n\t0,\n\t3101,\n\t3102,\n\t0,\n\t3122,\n\t0,\n\t0,\n\t0,\n\t3124,\n\t0,\n\t3125,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3132,\n\t3134,\n\t0,\n\t0,\n\t3136,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3147,\n\t0,\n\t0,\n\t3149,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3150,\n\t3151,\n\t3152,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3158,\n\t0,\n\t0,\n\t3160,\n\t0,\n\t0,\n\t3161,\n\t0,\n\t0,\n\t3162,\n\t0,\n\t3163,\n\t3166,\n\t3168,\n\t0,\n\t0,\n\t3169,\n\t3170,\n\t0,\n\t0,\n\t3171,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3182,\n\t0,\n\t3184,\n\t0,\n\t0,\n\t3188,\n\t0,\n\t0,\n\t3194,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3209,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3216,\n\t3217,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3219,\n\t0,\n\t0,\n\t3220,\n\t3222,\n\t0,\n\t3223,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3224,\n\t0,\n\t3225,\n\t3226,\n\t0,\n\t3228,\n\t3233,\n\t0,\n\t3239,\n\t3241,\n\t3242,\n\t0,\n\t0,\n\t3251,\n\t3252,\n\t3253,\n\t3255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3260,\n\t0,\n\t0,\n\t3261,\n\t0,\n\t0,\n\t0,\n\t3267,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3271,\n\t0,\n\t0,\n\t0,\n\t3278,\n\t0,\n\t3282,\n\t0,\n\t0,\n\t0,\n\t3284,\n\t0,\n\t0,\n\t0,\n\t3285,\n\t3286,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3287,\n\t3292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3294,\n\t3296,\n\t0,\n\t0,\n\t3299,\n\t3300,\n\t3301,\n\t0,\n\t3302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3304,\n\t3306,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3311,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3312,\n\t3314,\n\t3315,\n\t0,\n\t3318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3319,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3321,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3322,\n\t0,\n\t0,\n\t3324,\n\t3325,\n\t0,\n\t0,\n\t3326,\n\t0,\n\t0,\n\t3328,\n\t3329,\n\t3331,\n\t0,\n\t0,\n\t3335,\n\t0,\n\t0,\n\t3337,\n\t0,\n\t3338,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3343,\n\t3347,\n\t0,\n\t0,\n\t0,\n\t3348,\n\t0,\n\t0,\n\t3351,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3354,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3355,\n\t0,\n\t0,\n\t3365,\n\t3366,\n\t3367,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3368,\n\t3369,\n\t0,\n\t3370,\n\t0,\n\t0,\n\t3373,\n\t0,\n\t0,\n\t3376,\n\t0,\n\t0,\n\t3377,\n\t0,\n\t3379,\n\t3387,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3402,\n\t0,\n\t3403,\n\t3436,\n\t3437,\n\t3439,\n\t0,\n\t0,\n\t3441,\n\t0,\n\t0,\n\t0,\n\t3442,\n\t0,\n\t0,\n\t3449,\n\t0,\n\t0,\n\t0,\n\t3450,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3451,\n\t0,\n\t0,\n\t3452,\n\t0,\n\t3453,\n\t3456,\n\t0,\n\t3457,\n\t0,\n\t0,\n\t3458,\n\t0,\n\t3459,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3460,\n\t0,\n\t0,\n\t3469,\n\t3470,\n\t0,\n\t0,\n\t3475,\n\t0,\n\t0,\n\t0,\n\t3480,\n\t3487,\n\t3489,\n\t0,\n\t3490,\n\t0,\n\t0,\n\t3491,\n\t3499,\n\t0,\n\t3500,\n\t0,\n\t0,\n\t3501,\n\t0,\n\t0,\n\t0,\n\t3502,\n\t0,\n\t3514,\n\t0,\n\t0,\n\t0,\n\t3516,\n\t3517,\n\t0,\n\t0,\n\t0,\n\t3518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3520,\n\t3521,\n\t3522,\n\t0,\n\t0,\n\t3526,\n\t3530,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3531,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3536,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3539,\n\t3541,\n\t0,\n\t0,\n\t3542,\n\t3544,\n\t0,\n\t3547,\n\t3548,\n\t0,\n\t0,\n\t3550,\n\t0,\n\t3553,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3554,\n\t0,\n\t3555,\n\t0,\n\t3558,\n\t0,\n\t3559,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3563,\n\t0,\n\t3581,\n\t0,\n\t0,\n\t0,\n\t3599,\n\t0,\n\t0,\n\t0,\n\t3600,\n\t0,\n\t3601,\n\t0,\n\t3602,\n\t3603,\n\t0,\n\t0,\n\t3606,\n\t3608,\n\t0,\n\t3610,\n\t3611,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3612,\n\t3616,\n\t3619,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3624,\n\t3628,\n\t0,\n\t3629,\n\t3634,\n\t3635,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3636,\n\t0,\n\t3637,\n\t0,\n\t0,\n\t3638,\n\t3651,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3652,\n\t3653,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3656,\n\t3657,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3658,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3659,\n\t0,\n\t3661,\n\t3663,\n\t3664,\n\t0,\n\t3665,\n\t0,\n\t3692,\n\t0,\n\t0,\n\t0,\n\t3694,\n\t3696,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3698,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3700,\n\t0,\n\t0,\n\t3701,\n\t0,\n\t0,\n\t0,\n\t3708,\n\t3709,\n\t0,\n\t0,\n\t0,\n\t3711,\n\t3712,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3723,\n\t0,\n\t3724,\n\t3725,\n\t0,\n\t0,\n\t3726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3728,\n\t3729,\n\t0,\n\t3734,\n\t3735,\n\t3737,\n\t0,\n\t0,\n\t0,\n\t3743,\n\t0,\n\t3745,\n\t0,\n\t0,\n\t3746,\n\t0,\n\t0,\n\t3747,\n\t3748,\n\t0,\n\t3757,\n\t0,\n\t3759,\n\t3766,\n\t3767,\n\t0,\n\t3768,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3769,\n\t0,\n\t0,\n\t3771,\n\t0,\n\t3774,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3776,\n\t0,\n\t3777,\n\t3786,\n\t0,\n\t3788,\n\t3789,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3791,\n\t0,\n\t3811,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3814,\n\t3815,\n\t3816,\n\t3820,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3821,\n\t0,\n\t0,\n\t3825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3835,\n\t0,\n\t0,\n\t3848,\n\t3849,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3850,\n\t3851,\n\t3853,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3859,\n\t0,\n\t3860,\n\t3862,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3873,\n\t0,\n\t3874,\n\t0,\n\t3875,\n\t3886,\n\t0,\n\t3887,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3892,\n\t3913,\n\t0,\n\t3914,\n\t0,\n\t0,\n\t0,\n\t3925,\n\t3931,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3934,\n\t3941,\n\t3942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3943,\n\t0,\n\t0,\n\t0,\n\t3944,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3945,\n\t0,\n\t3947,\n\t0,\n\t0,\n\t0,\n\t3956,\n\t3957,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3958,\n\t0,\n\t3959,\n\t3965,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3966,\n\t0,\n\t0,\n\t0,\n\t3967,\n\t0,\n\t0,\n\t0,\n\t3968,\n\t3974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3975,\n\t3977,\n\t3978,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3980,\n\t0,\n\t3985,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t3986,\n\t4011,\n\t0,\n\t0,\n\t4017,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4018,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4019,\n\t0,\n\t4023,\n\t0,\n\t0,\n\t0,\n\t4027,\n\t4028,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4031,\n\t4034,\n\t0,\n\t0,\n\t4035,\n\t4037,\n\t4039,\n\t4040,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4059,\n\t0,\n\t4060,\n\t4061,\n\t0,\n\t4062,\n\t4063,\n\t4066,\n\t0,\n\t0,\n\t4072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4088,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4091,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4094,\n\t4095,\n\t0,\n\t0,\n\t4096,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4098,\n\t4099,\n\t0,\n\t0,\n\t0,\n\t4101,\n\t0,\n\t4104,\n\t0,\n\t0,\n\t0,\n\t4105,\n\t4108,\n\t0,\n\t4113,\n\t0,\n\t0,\n\t4115,\n\t4116,\n\t0,\n\t4126,\n\t0,\n\t0,\n\t4127,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4128,\n\t4132,\n\t4133,\n\t0,\n\t4134,\n\t0,\n\t0,\n\t0,\n\t4137,\n\t0,\n\t0,\n\t4141,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4144,\n\t4146,\n\t4147,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4148,\n\t0,\n\t0,\n\t4311,\n\t0,\n\t0,\n\t0,\n\t4314,\n\t4329,\n\t0,\n\t4331,\n\t4332,\n\t0,\n\t4333,\n\t0,\n\t4334,\n\t0,\n\t0,\n\t0,\n\t4335,\n\t0,\n\t4336,\n\t0,\n\t0,\n\t0,\n\t4337,\n\t0,\n\t0,\n\t0,\n\t4342,\n\t4345,\n\t4346,\n\t4350,\n\t0,\n\t4351,\n\t4352,\n\t0,\n\t4354,\n\t4355,\n\t0,\n\t0,\n\t4364,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4369,\n\t0,\n\t0,\n\t0,\n\t4373,\n\t0,\n\t4374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4377,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4378,\n\t0,\n\t0,\n\t0,\n\t4380,\n\t0,\n\t0,\n\t0,\n\t4381,\n\t4382,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4384,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4385,\n\t0,\n\t0,\n\t0,\n\t4386,\n\t0,\n\t0,\n\t0,\n\t4391,\n\t4398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4407,\n\t4409,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4410,\n\t0,\n\t0,\n\t4411,\n\t0,\n\t4414,\n\t4415,\n\t4418,\n\t0,\n\t4427,\n\t4428,\n\t4430,\n\t0,\n\t4431,\n\t0,\n\t4448,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4449,\n\t0,\n\t0,\n\t0,\n\t4451,\n\t4452,\n\t0,\n\t4453,\n\t4454,\n\t0,\n\t4456,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4459,\n\t0,\n\t4463,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4466,\n\t0,\n\t4467,\n\t0,\n\t4469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4470,\n\t4471,\n\t0,\n\t4473,\n\t0,\n\t0,\n\t4475,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4477,\n\t4478,\n\t0,\n\t0,\n\t0,\n\t4479,\n\t4481,\n\t0,\n\t4482,\n\t0,\n\t4484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4486,\n\t0,\n\t0,\n\t4488,\n\t0,\n\t0,\n\t4497,\n\t0,\n\t4508,\n\t0,\n\t0,\n\t4510,\n\t4511,\n\t0,\n\t4520,\n\t4523,\n\t0,\n\t4524,\n\t0,\n\t4525,\n\t0,\n\t4527,\n\t0,\n\t0,\n\t4528,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4530,\n\t0,\n\t4531,\n\t0,\n\t0,\n\t4532,\n\t0,\n\t0,\n\t0,\n\t4533,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4535,\n\t0,\n\t0,\n\t0,\n\t4536,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4541,\n\t4543,\n\t4544,\n\t4545,\n\t4547,\n\t0,\n\t4548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4550,\n\t4551,\n\t0,\n\t4553,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4562,\n\t0,\n\t0,\n\t4571,\n\t0,\n\t0,\n\t0,\n\t4574,\n\t0,\n\t0,\n\t0,\n\t4575,\n\t0,\n\t4576,\n\t0,\n\t4577,\n\t0,\n\t0,\n\t0,\n\t4581,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4582,\n\t0,\n\t0,\n\t4586,\n\t0,\n\t0,\n\t0,\n\t4588,\n\t0,\n\t0,\n\t4597,\n\t0,\n\t4598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4616,\n\t4617,\n\t0,\n\t4618,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4619,\n\t0,\n\t4620,\n\t0,\n\t0,\n\t4621,\n\t0,\n\t4624,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4625,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4657,\n\t0,\n\t4659,\n\t0,\n\t4667,\n\t0,\n\t0,\n\t0,\n\t4668,\n\t4670,\n\t0,\n\t4672,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4673,\n\t4676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4687,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4697,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4699,\n\t0,\n\t4701,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4702,\n\t0,\n\t0,\n\t4706,\n\t0,\n\t0,\n\t4713,\n\t0,\n\t0,\n\t0,\n\t4714,\n\t4715,\n\t4716,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4717,\n\t0,\n\t0,\n\t4720,\n\t0,\n\t4721,\n\t4729,\n\t4735,\n\t0,\n\t0,\n\t0,\n\t4737,\n\t0,\n\t0,\n\t0,\n\t4739,\n\t0,\n\t0,\n\t0,\n\t4740,\n\t0,\n\t0,\n\t0,\n\t4741,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4742,\n\t0,\n\t4745,\n\t4746,\n\t4747,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4748,\n\t0,\n\t0,\n\t0,\n\t4749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4751,\n\t4786,\n\t0,\n\t4787,\n\t0,\n\t4788,\n\t4796,\n\t0,\n\t0,\n\t4797,\n\t4798,\n\t0,\n\t4799,\n\t4806,\n\t4807,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4809,\n\t4810,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4811,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4812,\n\t0,\n\t4813,\n\t0,\n\t0,\n\t4815,\n\t0,\n\t4821,\n\t4822,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4823,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4824,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4826,\n\t0,\n\t0,\n\t0,\n\t4828,\n\t0,\n\t4829,\n\t0,\n\t0,\n\t0,\n\t4843,\n\t0,\n\t0,\n\t4847,\n\t0,\n\t4853,\n\t4855,\n\t4858,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4859,\n\t0,\n\t4864,\n\t0,\n\t0,\n\t4879,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4880,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4881,\n\t0,\n\t4882,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4883,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4884,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4886,\n\t4887,\n\t4888,\n\t4894,\n\t4896,\n\t0,\n\t4902,\n\t0,\n\t0,\n\t4905,\n\t0,\n\t0,\n\t4915,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4916,\n\t4917,\n\t4919,\n\t4921,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4926,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t4929,\n\t0,\n\t4930,\n\t4931,\n\t0,\n\t4938,\n\t0,\n\t4952,\n\t0,\n\t4953,\n\t4957,\n\t4960,\n\t4964,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5019,\n\t5020,\n\t5022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5023,\n\t0,\n\t0,\n\t0,\n\t5024,\n\t0,\n\t0,\n\t0,\n\t5025,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5028,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5029,\n\t5030,\n\t5031,\n\t0,\n\t5033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5034,\n\t5035,\n\t0,\n\t5036,\n\t0,\n\t0,\n\t5037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5038,\n\t0,\n\t0,\n\t5039,\n\t0,\n\t0,\n\t0,\n\t5041,\n\t5042,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5044,\n\t5049,\n\t5054,\n\t0,\n\t5055,\n\t0,\n\t5057,\n\t0,\n\t0,\n\t0,\n\t5060,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5063,\n\t0,\n\t5064,\n\t5065,\n\t0,\n\t5067,\n\t0,\n\t0,\n\t0,\n\t5068,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5076,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5077,\n\t0,\n\t0,\n\t5078,\n\t5080,\n\t0,\n\t0,\n\t5083,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5098,\n\t5099,\n\t5101,\n\t5105,\n\t5107,\n\t0,\n\t5108,\n\t0,\n\t5109,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5117,\n\t5118,\n\t0,\n\t5121,\n\t0,\n\t5122,\n\t0,\n\t0,\n\t5130,\n\t0,\n\t0,\n\t0,\n\t5137,\n\t0,\n\t0,\n\t0,\n\t5148,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5151,\n\t5154,\n\t0,\n\t0,\n\t0,\n\t5155,\n\t0,\n\t0,\n\t5156,\n\t5159,\n\t5161,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5162,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5163,\n\t5164,\n\t0,\n\t5166,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5167,\n\t0,\n\t0,\n\t0,\n\t5172,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5178,\n\t5179,\n\t0,\n\t0,\n\t5190,\n\t0,\n\t0,\n\t5191,\n\t5192,\n\t5194,\n\t0,\n\t0,\n\t5198,\n\t5201,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5203,\n\t0,\n\t5206,\n\t5209,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5213,\n\t0,\n\t5214,\n\t5216,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5217,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5218,\n\t5219,\n\t0,\n\t5231,\n\t0,\n\t0,\n\t5244,\n\t5249,\n\t0,\n\t5254,\n\t0,\n\t5255,\n\t0,\n\t0,\n\t5257,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5258,\n\t0,\n\t5260,\n\t5270,\n\t0,\n\t5277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5280,\n\t5281,\n\t5282,\n\t5283,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5284,\n\t0,\n\t5285,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5287,\n\t5288,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5289,\n\t5291,\n\t0,\n\t0,\n\t5294,\n\t0,\n\t0,\n\t5295,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5304,\n\t0,\n\t0,\n\t5306,\n\t5307,\n\t5308,\n\t0,\n\t5309,\n\t0,\n\t0,\n\t5310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5311,\n\t5312,\n\t0,\n\t5313,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5316,\n\t0,\n\t0,\n\t0,\n\t5317,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5325,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5326,\n\t0,\n\t5327,\n\t5329,\n\t0,\n\t5332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5338,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5340,\n\t0,\n\t0,\n\t5341,\n\t0,\n\t0,\n\t0,\n\t5342,\n\t0,\n\t5343,\n\t5344,\n\t0,\n\t0,\n\t5345,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5347,\n\t5348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5349,\n\t0,\n\t5350,\n\t0,\n\t5354,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5358,\n\t0,\n\t0,\n\t5359,\n\t0,\n\t0,\n\t5361,\n\t0,\n\t0,\n\t5365,\n\t0,\n\t5367,\n\t0,\n\t5373,\n\t0,\n\t0,\n\t0,\n\t5379,\n\t0,\n\t0,\n\t0,\n\t5380,\n\t0,\n\t0,\n\t0,\n\t5382,\n\t0,\n\t5384,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5385,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5387,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5388,\n\t5390,\n\t5393,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5396,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5397,\n\t5402,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5403,\n\t0,\n\t0,\n\t0,\n\t5404,\n\t5405,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5410,\n\t0,\n\t0,\n\t5411,\n\t0,\n\t5415,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5416,\n\t5434,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5438,\n\t0,\n\t5440,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5441,\n\t5442,\n\t0,\n\t0,\n\t0,\n\t5443,\n\t5444,\n\t5447,\n\t0,\n\t0,\n\t5448,\n\t5449,\n\t5451,\n\t0,\n\t0,\n\t0,\n\t5456,\n\t5457,\n\t0,\n\t0,\n\t0,\n\t5459,\n\t0,\n\t0,\n\t0,\n\t5461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5464,\n\t0,\n\t5466,\n\t0,\n\t0,\n\t5467,\n\t0,\n\t5470,\n\t0,\n\t0,\n\t5473,\n\t0,\n\t0,\n\t5474,\n\t0,\n\t0,\n\t5476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5477,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5484,\n\t0,\n\t0,\n\t5485,\n\t5486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5488,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5489,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5507,\n\t0,\n\t0,\n\t0,\n\t5510,\n\t0,\n\t5511,\n\t0,\n\t0,\n\t5512,\n\t0,\n\t0,\n\t0,\n\t5513,\n\t0,\n\t5515,\n\t0,\n\t0,\n\t5516,\n\t5517,\n\t0,\n\t5518,\n\t0,\n\t0,\n\t5522,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5534,\n\t5535,\n\t0,\n\t0,\n\t5536,\n\t0,\n\t5538,\n\t0,\n\t0,\n\t5543,\n\t0,\n\t5544,\n\t0,\n\t0,\n\t5545,\n\t0,\n\t5547,\n\t0,\n\t5557,\n\t0,\n\t0,\n\t5558,\n\t0,\n\t5560,\n\t5567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5568,\n\t0,\n\t0,\n\t0,\n\t5571,\n\t5573,\n\t0,\n\t5574,\n\t0,\n\t5575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5577,\n\t0,\n\t0,\n\t5598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5600,\n\t5609,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5610,\n\t0,\n\t0,\n\t5612,\n\t0,\n\t5624,\n\t0,\n\t5625,\n\t0,\n\t0,\n\t0,\n\t5629,\n\t0,\n\t5641,\n\t0,\n\t5642,\n\t5643,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5651,\n\t0,\n\t0,\n\t0,\n\t5652,\n\t5653,\n\t0,\n\t5661,\n\t5662,\n\t5678,\n\t0,\n\t5679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5685,\n\t5686,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5690,\n\t5692,\n\t0,\n\t5703,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5706,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5707,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5708,\n\t0,\n\t0,\n\t5709,\n\t0,\n\t5710,\n\t0,\n\t0,\n\t0,\n\t5712,\n\t0,\n\t5733,\n\t0,\n\t5734,\n\t5735,\n\t0,\n\t0,\n\t5744,\n\t5751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5752,\n\t0,\n\t5754,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5757,\n\t5758,\n\t0,\n\t5760,\n\t5761,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5763,\n\t5764,\n\t5765,\n\t0,\n\t5766,\n\t0,\n\t5767,\n\t5768,\n\t0,\n\t5770,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5776,\n\t5780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5782,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5784,\n\t0,\n\t0,\n\t5788,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5797,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5799,\n\t0,\n\t0,\n\t5801,\n\t0,\n\t0,\n\t0,\n\t5811,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5816,\n\t0,\n\t0,\n\t5827,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5830,\n\t5831,\n\t0,\n\t0,\n\t5832,\n\t0,\n\t0,\n\t5833,\n\t0,\n\t5835,\n\t5844,\n\t5845,\n\t0,\n\t5846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5850,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5852,\n\t0,\n\t5855,\n\t5857,\n\t0,\n\t0,\n\t5859,\n\t0,\n\t5861,\n\t0,\n\t0,\n\t5863,\n\t0,\n\t5865,\n\t0,\n\t0,\n\t0,\n\t5873,\n\t5875,\n\t0,\n\t0,\n\t0,\n\t5877,\n\t0,\n\t5879,\n\t0,\n\t0,\n\t0,\n\t5888,\n\t0,\n\t0,\n\t5889,\n\t5891,\n\t0,\n\t5894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5895,\n\t0,\n\t5897,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5907,\n\t0,\n\t5911,\n\t0,\n\t0,\n\t5912,\n\t0,\n\t5913,\n\t5922,\n\t5924,\n\t0,\n\t5927,\n\t5928,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5929,\n\t5930,\n\t0,\n\t5933,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5949,\n\t0,\n\t0,\n\t5951,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5953,\n\t0,\n\t0,\n\t5954,\n\t0,\n\t5959,\n\t5960,\n\t5961,\n\t0,\n\t5964,\n\t0,\n\t0,\n\t0,\n\t5976,\n\t5978,\n\t5987,\n\t5990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t5991,\n\t0,\n\t5992,\n\t0,\n\t0,\n\t0,\n\t5994,\n\t5995,\n\t0,\n\t0,\n\t5996,\n\t0,\n\t0,\n\t6001,\n\t6003,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6008,\n\t0,\n\t0,\n\t6009,\n\t0,\n\t6010,\n\t0,\n\t0,\n\t0,\n\t6011,\n\t6015,\n\t0,\n\t6017,\n\t0,\n\t6019,\n\t0,\n\t6023,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6025,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6026,\n\t0,\n\t6030,\n\t0,\n\t0,\n\t6032,\n\t0,\n\t0,\n\t0,\n\t6033,\n\t6038,\n\t6040,\n\t0,\n\t0,\n\t0,\n\t6041,\n\t6045,\n\t0,\n\t0,\n\t6046,\n\t0,\n\t0,\n\t6053,\n\t0,\n\t0,\n\t6054,\n\t0,\n\t6055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6057,\n\t0,\n\t6063,\n\t0,\n\t0,\n\t0,\n\t6064,\n\t0,\n\t6066,\n\t6071,\n\t6072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6075,\n\t6076,\n\t0,\n\t0,\n\t6077,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6078,\n\t6079,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6080,\n\t0,\n\t6083,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6084,\n\t0,\n\t0,\n\t6088,\n\t0,\n\t6089,\n\t0,\n\t0,\n\t6093,\n\t6105,\n\t0,\n\t0,\n\t6107,\n\t0,\n\t6110,\n\t0,\n\t0,\n\t0,\n\t6111,\n\t6125,\n\t6126,\n\t0,\n\t0,\n\t0,\n\t6129,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6130,\n\t0,\n\t0,\n\t0,\n\t6131,\n\t6134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6144,\n\t0,\n\t0,\n\t6146,\n\t6151,\n\t6153,\n\t0,\n\t6156,\n\t0,\n\t6163,\n\t0,\n\t6180,\n\t6181,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6182,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6184,\n\t6195,\n\t0,\n\t0,\n\t6206,\n\t0,\n\t6208,\n\t0,\n\t0,\n\t6212,\n\t6213,\n\t6214,\n\t0,\n\t6215,\n\t0,\n\t0,\n\t0,\n\t6228,\n\t0,\n\t0,\n\t0,\n\t6234,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6235,\n\t6240,\n\t0,\n\t6242,\n\t6243,\n\t6244,\n\t0,\n\t6250,\n\t6255,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6257,\n\t0,\n\t0,\n\t0,\n\t6258,\n\t6278,\n\t0,\n\t6284,\n\t0,\n\t0,\n\t0,\n\t6285,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6286,\n\t0,\n\t0,\n\t0,\n\t6320,\n\t0,\n\t0,\n\t6322,\n\t6332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6334,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6335,\n\t0,\n\t0,\n\t6337,\n\t0,\n\t6338,\n\t0,\n\t6339,\n\t6340,\n\t0,\n\t0,\n\t6356,\n\t6357,\n\t6369,\n\t0,\n\t0,\n\t0,\n\t6370,\n\t6371,\n\t6372,\n\t0,\n\t6373,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6376,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6382,\n\t6383,\n\t6384,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6386,\n\t0,\n\t6389,\n\t6397,\n\t6400,\n\t6411,\n\t0,\n\t6414,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6415,\n\t6416,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6417,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6418,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6420,\n\t0,\n\t6421,\n\t6423,\n\t6425,\n\t0,\n\t6429,\n\t6430,\n\t0,\n\t6433,\n\t6438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6439,\n\t6440,\n\t0,\n\t0,\n\t6441,\n\t0,\n\t0,\n\t6444,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6447,\n\t6448,\n\t0,\n\t0,\n\t6450,\n\t0,\n\t0,\n\t0,\n\t6454,\n\t0,\n\t0,\n\t6455,\n\t0,\n\t6461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6462,\n\t0,\n\t0,\n\t6463,\n\t0,\n\t6464,\n\t0,\n\t6465,\n\t6467,\n\t0,\n\t0,\n\t0,\n\t6468,\n\t0,\n\t6479,\n\t6480,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6481,\n\t0,\n\t0,\n\t6485,\n\t6487,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6493,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6494,\n\t6495,\n\t6496,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6498,\n\t0,\n\t0,\n\t0,\n\t6507,\n\t6508,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6511,\n\t6512,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6513,\n\t0,\n\t0,\n\t0,\n\t6514,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6516,\n\t0,\n\t0,\n\t6517,\n\t6518,\n\t0,\n\t0,\n\t0,\n\t6519,\n\t6520,\n\t6521,\n\t0,\n\t6523,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6524,\n\t6528,\n\t0,\n\t6530,\n\t0,\n\t0,\n\t6532,\n\t0,\n\t6578,\n\t0,\n\t0,\n\t0,\n\t6583,\n\t0,\n\t6584,\n\t0,\n\t0,\n\t0,\n\t6587,\n\t0,\n\t0,\n\t0,\n\t6590,\n\t0,\n\t6591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6592,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6593,\n\t6594,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6599,\n\t6600,\n\t0,\n\t0,\n\t6601,\n\t6602,\n\t6604,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6608,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6610,\n\t6611,\n\t0,\n\t6615,\n\t0,\n\t6616,\n\t6618,\n\t6620,\n\t0,\n\t6637,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6641,\n\t0,\n\t6642,\n\t0,\n\t0,\n\t0,\n\t6647,\n\t0,\n\t6660,\n\t6663,\n\t0,\n\t6664,\n\t0,\n\t6666,\n\t6669,\n\t0,\n\t6675,\n\t6676,\n\t6677,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6678,\n\t0,\n\t0,\n\t0,\n\t6679,\n\t0,\n\t6680,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6693,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6704,\n\t6705,\n\t6706,\n\t0,\n\t0,\n\t6711,\n\t6713,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6716,\n\t0,\n\t0,\n\t0,\n\t6717,\n\t0,\n\t6719,\n\t6724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6725,\n\t6726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6728,\n\t6729,\n\t6735,\n\t0,\n\t6737,\n\t6742,\n\t0,\n\t0,\n\t6743,\n\t6750,\n\t0,\n\t6751,\n\t0,\n\t0,\n\t6752,\n\t6753,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6754,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6756,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6763,\n\t0,\n\t0,\n\t6764,\n\t6765,\n\t0,\n\t0,\n\t0,\n\t6770,\n\t0,\n\t0,\n\t0,\n\t6776,\n\t6780,\n\t0,\n\t6781,\n\t0,\n\t0,\n\t0,\n\t6783,\n\t0,\n\t6784,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6785,\n\t0,\n\t0,\n\t0,\n\t6792,\n\t0,\n\t0,\n\t0,\n\t6793,\n\t0,\n\t0,\n\t6802,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6803,\n\t0,\n\t0,\n\t0,\n\t6804,\n\t0,\n\t0,\n\t0,\n\t6812,\n\t0,\n\t0,\n\t6823,\n\t0,\n\t6824,\n\t6839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6852,\n\t0,\n\t0,\n\t6854,\n\t0,\n\t6856,\n\t6857,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6867,\n\t0,\n\t6868,\n\t6870,\n\t6872,\n\t0,\n\t0,\n\t0,\n\t6873,\n\t6874,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6875,\n\t0,\n\t0,\n\t6877,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6878,\n\t0,\n\t0,\n\t0,\n\t6879,\n\t0,\n\t6880,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6887,\n\t0,\n\t6888,\n\t6891,\n\t6893,\n\t0,\n\t6895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6899,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6901,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6910,\n\t0,\n\t6911,\n\t0,\n\t0,\n\t6912,\n\t0,\n\t0,\n\t6913,\n\t6914,\n\t0,\n\t0,\n\t0,\n\t6915,\n\t0,\n\t0,\n\t0,\n\t6916,\n\t6919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6924,\n\t0,\n\t6925,\n\t0,\n\t0,\n\t0,\n\t6926,\n\t6927,\n\t6928,\n\t0,\n\t6929,\n\t0,\n\t6930,\n\t0,\n\t0,\n\t6931,\n\t6935,\n\t0,\n\t6936,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6939,\n\t6940,\n\t6941,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6942,\n\t6948,\n\t6949,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6952,\n\t6954,\n\t6963,\n\t6965,\n\t6966,\n\t0,\n\t0,\n\t6967,\n\t6968,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6969,\n\t0,\n\t0,\n\t6970,\n\t6979,\n\t0,\n\t0,\n\t6980,\n\t0,\n\t0,\n\t6983,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6984,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6988,\n\t6990,\n\t6992,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t6995,\n\t0,\n\t0,\n\t0,\n\t7012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7019,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7021,\n\t0,\n\t0,\n\t7022,\n\t7023,\n\t7028,\n\t0,\n\t7030,\n\t7033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7046,\n\t0,\n\t7047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7048,\n\t7052,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7054,\n\t0,\n\t7060,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7061,\n\t0,\n\t7065,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7067,\n\t7069,\n\t0,\n\t7070,\n\t7071,\n\t7072,\n\t0,\n\t0,\n\t7078,\n\t0,\n\t7080,\n\t7081,\n\t0,\n\t7083,\n\t0,\n\t0,\n\t0,\n\t7084,\n\t7087,\n\t7088,\n\t0,\n\t0,\n\t7090,\n\t0,\n\t7093,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7107,\n\t0,\n\t0,\n\t7108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7110,\n\t0,\n\t7114,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7115,\n\t0,\n\t7116,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7117,\n\t0,\n\t0,\n\t7118,\n\t0,\n\t0,\n\t7124,\n\t0,\n\t7125,\n\t0,\n\t0,\n\t7126,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7128,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7129,\n\t0,\n\t7130,\n\t0,\n\t7132,\n\t7133,\n\t0,\n\t0,\n\t7134,\n\t0,\n\t0,\n\t7139,\n\t0,\n\t7148,\n\t7150,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7152,\n\t0,\n\t0,\n\t0,\n\t7153,\n\t7156,\n\t7157,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7163,\n\t7165,\n\t7169,\n\t0,\n\t7171,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7172,\n\t0,\n\t7173,\n\t7181,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7182,\n\t7185,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7187,\n\t0,\n\t7201,\n\t7204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7206,\n\t7207,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7211,\n\t7216,\n\t0,\n\t7218,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7226,\n\t7228,\n\t7230,\n\t7232,\n\t7233,\n\t7235,\n\t7237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7238,\n\t7241,\n\t0,\n\t7242,\n\t0,\n\t0,\n\t7247,\n\t0,\n\t0,\n\t0,\n\t7266,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7289,\n\t0,\n\t0,\n\t7290,\n\t7291,\n\t0,\n\t0,\n\t7292,\n\t0,\n\t7297,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7300,\n\t0,\n\t7301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7305,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7307,\n\t0,\n\t7308,\n\t0,\n\t7310,\n\t0,\n\t7335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7337,\n\t0,\n\t7343,\n\t7347,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7348,\n\t0,\n\t7349,\n\t7350,\n\t7352,\n\t7354,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7357,\n\t0,\n\t7358,\n\t7366,\n\t0,\n\t7367,\n\t7368,\n\t0,\n\t0,\n\t7373,\n\t0,\n\t0,\n\t0,\n\t7374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7376,\n\t0,\n\t0,\n\t0,\n\t7377,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7378,\n\t0,\n\t7379,\n\t7380,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7383,\n\t0,\n\t0,\n\t7386,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7398,\n\t0,\n\t0,\n\t0,\n\t7399,\n\t7400,\n\t0,\n\t7401,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7402,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7405,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7421,\n\t7427,\n\t7429,\n\t0,\n\t0,\n\t0,\n\t7435,\n\t0,\n\t0,\n\t7436,\n\t0,\n\t0,\n\t0,\n\t7437,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7438,\n\t7443,\n\t0,\n\t7446,\n\t0,\n\t7448,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7456,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7457,\n\t0,\n\t0,\n\t7461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7462,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7463,\n\t7466,\n\t7472,\n\t0,\n\t7476,\n\t0,\n\t0,\n\t7490,\n\t0,\n\t7491,\n\t0,\n\t0,\n\t7493,\n\t0,\n\t0,\n\t0,\n\t7498,\n\t7499,\n\t0,\n\t0,\n\t7508,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7512,\n\t0,\n\t0,\n\t0,\n\t7513,\n\t7514,\n\t7516,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7518,\n\t0,\n\t0,\n\t7519,\n\t7521,\n\t7522,\n\t0,\n\t0,\n\t0,\n\t7526,\n\t0,\n\t0,\n\t7529,\n\t0,\n\t0,\n\t7531,\n\t0,\n\t7536,\n\t0,\n\t7538,\n\t0,\n\t7539,\n\t0,\n\t0,\n\t7541,\n\t7542,\n\t7546,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7547,\n\t0,\n\t7548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7550,\n\t0,\n\t0,\n\t7552,\n\t7553,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7554,\n\t7563,\n\t0,\n\t7573,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7574,\n\t7576,\n\t0,\n\t7578,\n\t7581,\n\t7583,\n\t0,\n\t0,\n\t0,\n\t7584,\n\t0,\n\t7587,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7589,\n\t0,\n\t0,\n\t0,\n\t7594,\n\t0,\n\t0,\n\t7595,\n\t0,\n\t0,\n\t7600,\n\t7602,\n\t7610,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7612,\n\t0,\n\t7613,\n\t7614,\n\t0,\n\t0,\n\t7615,\n\t0,\n\t0,\n\t7616,\n\t0,\n\t7620,\n\t0,\n\t7621,\n\t7622,\n\t0,\n\t7623,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7626,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7627,\n\t7629,\n\t7631,\n\t0,\n\t0,\n\t7633,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7639,\n\t0,\n\t7640,\n\t7642,\n\t0,\n\t0,\n\t7643,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7644,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7661,\n\t7662,\n\t7663,\n\t7665,\n\t0,\n\t7666,\n\t0,\n\t7667,\n\t0,\n\t7684,\n\t7688,\n\t7690,\n\t0,\n\t7691,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7692,\n\t0,\n\t0,\n\t7700,\n\t0,\n\t7707,\n\t0,\n\t7708,\n\t0,\n\t7709,\n\t0,\n\t7721,\n\t0,\n\t0,\n\t0,\n\t7722,\n\t0,\n\t7724,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7729,\n\t7731,\n\t0,\n\t7732,\n\t0,\n\t7733,\n\t7735,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7739,\n\t0,\n\t0,\n\t7741,\n\t7745,\n\t0,\n\t7748,\n\t0,\n\t0,\n\t0,\n\t7751,\n\t0,\n\t0,\n\t0,\n\t7752,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7753,\n\t0,\n\t0,\n\t7756,\n\t0,\n\t7757,\n\t0,\n\t7759,\n\t0,\n\t7760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7761,\n\t7768,\n\t0,\n\t0,\n\t7769,\n\t0,\n\t0,\n\t7770,\n\t0,\n\t0,\n\t7771,\n\t0,\n\t0,\n\t7772,\n\t0,\n\t0,\n\t7773,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7778,\n\t7783,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7784,\n\t7785,\n\t0,\n\t7790,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7792,\n\t0,\n\t7798,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7799,\n\t0,\n\t7810,\n\t0,\n\t0,\n\t7813,\n\t0,\n\t7814,\n\t0,\n\t7816,\n\t0,\n\t7818,\n\t7824,\n\t7825,\n\t7826,\n\t0,\n\t7828,\n\t7830,\n\t0,\n\t0,\n\t0,\n\t7840,\n\t0,\n\t7842,\n\t0,\n\t7843,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7856,\n\t7857,\n\t7858,\n\t7862,\n\t0,\n\t7865,\n\t0,\n\t0,\n\t7866,\n\t0,\n\t0,\n\t7913,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7914,\n\t0,\n\t0,\n\t7915,\n\t7917,\n\t7918,\n\t7919,\n\t0,\n\t7920,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7921,\n\t7922,\n\t0,\n\t7924,\n\t0,\n\t0,\n\t7925,\n\t0,\n\t0,\n\t7927,\n\t0,\n\t7930,\n\t7935,\n\t0,\n\t0,\n\t7937,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7939,\n\t0,\n\t7940,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7941,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7945,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7949,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7950,\n\t0,\n\t7953,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7968,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7969,\n\t7972,\n\t7992,\n\t0,\n\t7993,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t7994,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8007,\n\t8008,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8010,\n\t0,\n\t0,\n\t0,\n\t8012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8018,\n\t0,\n\t8028,\n\t8029,\n\t0,\n\t0,\n\t8030,\n\t0,\n\t0,\n\t8032,\n\t8033,\n\t0,\n\t0,\n\t8034,\n\t8036,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8037,\n\t0,\n\t0,\n\t0,\n\t8043,\n\t8052,\n\t8059,\n\t8060,\n\t0,\n\t0,\n\t8061,\n\t0,\n\t0,\n\t0,\n\t8062,\n\t0,\n\t8063,\n\t0,\n\t8064,\n\t0,\n\t8066,\n\t8068,\n\t0,\n\t0,\n\t0,\n\t8080,\n\t8081,\n\t0,\n\t8089,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8092,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8093,\n\t8110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8112,\n\t8115,\n\t0,\n\t8117,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8120,\n\t8121,\n\t8122,\n\t8128,\n\t8129,\n\t8130,\n\t8131,\n\t0,\n\t0,\n\t8139,\n\t0,\n\t0,\n\t8144,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8145,\n\t8146,\n\t8153,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8154,\n\t0,\n\t8157,\n\t8160,\n\t8162,\n\t0,\n\t8164,\n\t8165,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8166,\n\t8167,\n\t0,\n\t0,\n\t8179,\n\t0,\n\t0,\n\t0,\n\t8185,\n\t0,\n\t0,\n\t0,\n\t8186,\n\t0,\n\t0,\n\t8187,\n\t0,\n\t0,\n\t0,\n\t8188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8210,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8213,\n\t0,\n\t8214,\n\t0,\n\t0,\n\t8215,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8218,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8219,\n\t0,\n\t8221,\n\t0,\n\t0,\n\t8222,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8225,\n\t0,\n\t0,\n\t0,\n\t8233,\n\t0,\n\t0,\n\t8242,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8247,\n\t0,\n\t8248,\n\t8252,\n\t0,\n\t8256,\n\t8257,\n\t0,\n\t0,\n\t8261,\n\t0,\n\t8264,\n\t8265,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8267,\n\t0,\n\t0,\n\t0,\n\t8269,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8270,\n\t0,\n\t0,\n\t0,\n\t8278,\n\t0,\n\t8279,\n\t8283,\n\t0,\n\t0,\n\t8285,\n\t8286,\n\t8289,\n\t8292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8293,\n\t8295,\n\t8299,\n\t8300,\n\t8301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8304,\n\t8307,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8321,\n\t0,\n\t0,\n\t0,\n\t8322,\n\t8323,\n\t8325,\n\t8326,\n\t8327,\n\t0,\n\t0,\n\t8332,\n\t8338,\n\t0,\n\t0,\n\t8340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8350,\n\t0,\n\t0,\n\t8351,\n\t0,\n\t8354,\n\t8355,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8360,\n\t8372,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8377,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8380,\n\t0,\n\t0,\n\t0,\n\t8383,\n\t0,\n\t8384,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8386,\n\t8392,\n\t0,\n\t0,\n\t8394,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8396,\n\t8397,\n\t0,\n\t8398,\n\t0,\n\t8399,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8400,\n\t0,\n\t8401,\n\t8410,\n\t8411,\n\t0,\n\t8412,\n\t8413,\n\t8422,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8424,\n\t0,\n\t0,\n\t8425,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8441,\n\t8442,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8443,\n\t0,\n\t0,\n\t8444,\n\t0,\n\t8447,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8451,\n\t0,\n\t8458,\n\t0,\n\t8462,\n\t0,\n\t0,\n\t8468,\n\t0,\n\t8469,\n\t0,\n\t0,\n\t0,\n\t8470,\n\t0,\n\t8473,\n\t8479,\n\t8480,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8481,\n\t8483,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8484,\n\t0,\n\t0,\n\t8490,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8491,\n\t8493,\n\t8494,\n\t0,\n\t8528,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8530,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8534,\n\t8538,\n\t8540,\n\t0,\n\t0,\n\t8541,\n\t0,\n\t0,\n\t8545,\n\t0,\n\t8557,\n\t0,\n\t0,\n\t8569,\n\t8570,\n\t0,\n\t0,\n\t8571,\n\t8574,\n\t8575,\n\t8579,\n\t0,\n\t8583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8606,\n\t0,\n\t8607,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8608,\n\t0,\n\t0,\n\t8609,\n\t0,\n\t0,\n\t0,\n\t8610,\n\t0,\n\t0,\n\t0,\n\t8611,\n\t0,\n\t0,\n\t8613,\n\t8617,\n\t8621,\n\t0,\n\t0,\n\t8622,\n\t0,\n\t8623,\n\t0,\n\t8624,\n\t8625,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8637,\n\t8638,\n\t8639,\n\t8650,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8652,\n\t8654,\n\t8655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8656,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8657,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8658,\n\t0,\n\t0,\n\t8659,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8660,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8661,\n\t8663,\n\t8664,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8665,\n\t0,\n\t8669,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8671,\n\t8674,\n\t0,\n\t8684,\n\t0,\n\t8686,\n\t0,\n\t0,\n\t0,\n\t8689,\n\t0,\n\t0,\n\t0,\n\t8690,\n\t0,\n\t8706,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8710,\n\t0,\n\t8711,\n\t8713,\n\t8714,\n\t8724,\n\t8727,\n\t8728,\n\t8733,\n\t8736,\n\t0,\n\t8737,\n\t8739,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8742,\n\t8743,\n\t8745,\n\t8754,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8756,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8757,\n\t8760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8762,\n\t8763,\n\t8764,\n\t0,\n\t8766,\n\t8769,\n\t8770,\n\t8773,\n\t0,\n\t8774,\n\t0,\n\t8779,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8780,\n\t0,\n\t0,\n\t8781,\n\t0,\n\t0,\n\t8783,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8784,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8785,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8786,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8788,\n\t8790,\n\t0,\n\t0,\n\t0,\n\t8803,\n\t0,\n\t8813,\n\t8814,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8815,\n\t8816,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8818,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8822,\n\t8828,\n\t8829,\n\t0,\n\t8831,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8833,\n\t0,\n\t0,\n\t0,\n\t8834,\n\t0,\n\t0,\n\t0,\n\t8835,\n\t0,\n\t8836,\n\t0,\n\t0,\n\t0,\n\t8837,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8838,\n\t8839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8840,\n\t0,\n\t0,\n\t0,\n\t8841,\n\t0,\n\t8842,\n\t0,\n\t0,\n\t0,\n\t8846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8847,\n\t0,\n\t8848,\n\t0,\n\t0,\n\t8864,\n\t0,\n\t0,\n\t8866,\n\t0,\n\t0,\n\t8870,\n\t8872,\n\t0,\n\t0,\n\t8873,\n\t8874,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8875,\n\t0,\n\t8876,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8896,\n\t8900,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8901,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8904,\n\t0,\n\t8907,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8911,\n\t8912,\n\t8913,\n\t0,\n\t0,\n\t0,\n\t8914,\n\t0,\n\t8915,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8916,\n\t0,\n\t0,\n\t0,\n\t8929,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8930,\n\t0,\n\t8932,\n\t0,\n\t8943,\n\t0,\n\t0,\n\t0,\n\t8945,\n\t8947,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8949,\n\t0,\n\t8950,\n\t0,\n\t8954,\n\t8957,\n\t0,\n\t0,\n\t8970,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8971,\n\t0,\n\t8996,\n\t0,\n\t0,\n\t0,\n\t0,\n\t8997,\n\t9000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9001,\n\t9002,\n\t0,\n\t9004,\n\t9009,\n\t9024,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9027,\n\t9082,\n\t0,\n\t0,\n\t9083,\n\t9089,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9090,\n\t0,\n\t0,\n\t0,\n\t9092,\n\t0,\n\t0,\n\t9093,\n\t0,\n\t9095,\n\t0,\n\t0,\n\t9096,\n\t9097,\n\t9101,\n\t9102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9112,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9114,\n\t0,\n\t0,\n\t9120,\n\t0,\n\t9121,\n\t9122,\n\t0,\n\t0,\n\t0,\n\t9123,\n\t9124,\n\t0,\n\t0,\n\t9125,\n\t0,\n\t0,\n\t9126,\n\t0,\n\t9127,\n\t0,\n\t0,\n\t9129,\n\t9131,\n\t0,\n\t0,\n\t0,\n\t9132,\n\t0,\n\t0,\n\t9136,\n\t0,\n\t9144,\n\t0,\n\t0,\n\t9148,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9149,\n\t0,\n\t9152,\n\t9163,\n\t0,\n\t0,\n\t9165,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9166,\n\t0,\n\t9169,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9170,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9172,\n\t0,\n\t9174,\n\t9175,\n\t9176,\n\t0,\n\t9177,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9186,\n\t0,\n\t9187,\n\t0,\n\t0,\n\t0,\n\t9188,\n\t9189,\n\t0,\n\t0,\n\t9190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9191,\n\t0,\n\t0,\n\t0,\n\t9193,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9197,\n\t9198,\n\t0,\n\t0,\n\t0,\n\t9208,\n\t9211,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9216,\n\t9217,\n\t0,\n\t9220,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9221,\n\t9222,\n\t9223,\n\t0,\n\t9224,\n\t9225,\n\t0,\n\t0,\n\t9227,\n\t0,\n\t9228,\n\t9229,\n\t0,\n\t0,\n\t9230,\n\t0,\n\t9232,\n\t0,\n\t9233,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9234,\n\t9235,\n\t0,\n\t0,\n\t9237,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9238,\n\t9240,\n\t0,\n\t0,\n\t9241,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9244,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9247,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9248,\n\t0,\n\t0,\n\t0,\n\t9249,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9250,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9251,\n\t0,\n\t0,\n\t9252,\n\t9255,\n\t0,\n\t0,\n\t0,\n\t9256,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9257,\n\t0,\n\t0,\n\t9258,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9259,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9262,\n\t9263,\n\t0,\n\t0,\n\t9265,\n\t9266,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9268,\n\t9271,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9273,\n\t0,\n\t0,\n\t0,\n\t9276,\n\t9277,\n\t9279,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9280,\n\t0,\n\t0,\n\t9293,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9297,\n\t9301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9308,\n\t9309,\n\t9313,\n\t9321,\n\t9322,\n\t0,\n\t9326,\n\t9327,\n\t0,\n\t0,\n\t9477,\n\t0,\n\t9479,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9482,\n\t0,\n\t0,\n\t0,\n\t9483,\n\t0,\n\t9484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9485,\n\t0,\n\t0,\n\t9486,\n\t0,\n\t0,\n\t0,\n\t9489,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9490,\n\t9491,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9493,\n\t0,\n\t9495,\n\t9496,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9500,\n\t0,\n\t9502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9504,\n\t9507,\n\t0,\n\t9509,\n\t0,\n\t9511,\n\t0,\n\t0,\n\t9513,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9515,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9516,\n\t9517,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9532,\n\t0,\n\t0,\n\t9533,\n\t0,\n\t0,\n\t9538,\n\t0,\n\t9539,\n\t9540,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9541,\n\t0,\n\t0,\n\t0,\n\t9542,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9544,\n\t9545,\n\t0,\n\t9546,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9547,\n\t9548,\n\t0,\n\t0,\n\t0,\n\t9550,\n\t0,\n\t9557,\n\t0,\n\t9558,\n\t0,\n\t9561,\n\t0,\n\t9563,\n\t9570,\n\t0,\n\t9572,\n\t9574,\n\t9575,\n\t0,\n\t0,\n\t0,\n\t9577,\n\t9592,\n\t0,\n\t0,\n\t9596,\n\t0,\n\t0,\n\t0,\n\t9598,\n\t0,\n\t9600,\n\t0,\n\t9601,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9608,\n\t0,\n\t9638,\n\t9639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9641,\n\t0,\n\t0,\n\t9643,\n\t9644,\n\t9645,\n\t9646,\n\t0,\n\t0,\n\t0,\n\t9648,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9650,\n\t9654,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9655,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9656,\n\t0,\n\t9657,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9658,\n\t0,\n\t0,\n\t9659,\n\t0,\n\t0,\n\t9664,\n\t0,\n\t0,\n\t9665,\n\t0,\n\t9667,\n\t9669,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9671,\n\t0,\n\t9673,\n\t9681,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9682,\n\t9683,\n\t9684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9686,\n\t9698,\n\t0,\n\t0,\n\t9700,\n\t9701,\n\t9702,\n\t0,\n\t9703,\n\t9717,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9718,\n\t0,\n\t9726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9727,\n\t0,\n\t0,\n\t0,\n\t9728,\n\t0,\n\t9742,\n\t0,\n\t9744,\n\t0,\n\t0,\n\t0,\n\t9750,\n\t0,\n\t9754,\n\t9755,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9756,\n\t0,\n\t9757,\n\t9768,\n\t0,\n\t9769,\n\t0,\n\t0,\n\t0,\n\t9770,\n\t9771,\n\t0,\n\t9773,\n\t0,\n\t9774,\n\t0,\n\t9775,\n\t0,\n\t0,\n\t0,\n\t9776,\n\t9777,\n\t9784,\n\t0,\n\t0,\n\t0,\n\t9786,\n\t0,\n\t9789,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9793,\n\t9794,\n\t0,\n\t0,\n\t0,\n\t9808,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9811,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9812,\n\t0,\n\t9820,\n\t0,\n\t9823,\n\t0,\n\t9828,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9830,\n\t0,\n\t0,\n\t9833,\n\t9836,\n\t0,\n\t0,\n\t0,\n\t9840,\n\t0,\n\t0,\n\t0,\n\t9841,\n\t0,\n\t0,\n\t9842,\n\t0,\n\t9845,\n\t0,\n\t0,\n\t0,\n\t9847,\n\t9848,\n\t0,\n\t0,\n\t9855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9856,\n\t9863,\n\t9865,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9866,\n\t9867,\n\t9868,\n\t9873,\n\t9875,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9880,\n\t0,\n\t9886,\n\t0,\n\t0,\n\t0,\n\t9887,\n\t0,\n\t0,\n\t9891,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9906,\n\t9907,\n\t9908,\n\t0,\n\t0,\n\t0,\n\t9909,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9913,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9914,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9922,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9923,\n\t9925,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9930,\n\t0,\n\t0,\n\t0,\n\t9931,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9932,\n\t0,\n\t9939,\n\t0,\n\t0,\n\t9940,\n\t9962,\n\t9966,\n\t0,\n\t9969,\n\t9970,\n\t0,\n\t0,\n\t9974,\n\t0,\n\t9979,\n\t9981,\n\t9982,\n\t0,\n\t0,\n\t0,\n\t9985,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9987,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t9988,\n\t9993,\n\t0,\n\t0,\n\t9994,\n\t0,\n\t0,\n\t0,\n\t9997,\n\t0,\n\t10004,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10007,\n\t10019,\n\t10020,\n\t10022,\n\t0,\n\t0,\n\t0,\n\t10031,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10032,\n\t0,\n\t0,\n\t10034,\n\t0,\n\t10036,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10038,\n\t0,\n\t10039,\n\t10040,\n\t10041,\n\t10042,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10043,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10045,\n\t10054,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10055,\n\t0,\n\t0,\n\t10057,\n\t10058,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10059,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10060,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10063,\n\t0,\n\t10066,\n\t0,\n\t0,\n\t0,\n\t10070,\n\t0,\n\t10072,\n\t0,\n\t0,\n\t10076,\n\t10077,\n\t0,\n\t0,\n\t10084,\n\t0,\n\t10087,\n\t10090,\n\t10091,\n\t0,\n\t0,\n\t0,\n\t10094,\n\t10097,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10098,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10103,\n\t0,\n\t10104,\n\t0,\n\t10108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10120,\n\t0,\n\t0,\n\t0,\n\t10122,\n\t0,\n\t0,\n\t10125,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10127,\n\t10128,\n\t0,\n\t0,\n\t10134,\n\t0,\n\t10135,\n\t10136,\n\t0,\n\t10137,\n\t0,\n\t0,\n\t10147,\n\t0,\n\t10149,\n\t10150,\n\t0,\n\t0,\n\t10156,\n\t0,\n\t10158,\n\t10159,\n\t10160,\n\t10168,\n\t0,\n\t0,\n\t10171,\n\t0,\n\t10173,\n\t0,\n\t0,\n\t0,\n\t10176,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10177,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10178,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10194,\n\t0,\n\t10202,\n\t0,\n\t0,\n\t10203,\n\t10204,\n\t0,\n\t10205,\n\t10206,\n\t0,\n\t10207,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10209,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10213,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10217,\n\t0,\n\t10229,\n\t0,\n\t10230,\n\t10231,\n\t0,\n\t0,\n\t10232,\n\t0,\n\t0,\n\t10237,\n\t10238,\n\t10244,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10250,\n\t0,\n\t10252,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10255,\n\t0,\n\t0,\n\t10257,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10258,\n\t0,\n\t10259,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10260,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10284,\n\t10288,\n\t10289,\n\t0,\n\t0,\n\t0,\n\t10290,\n\t0,\n\t10296,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10297,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10298,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10299,\n\t10303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10306,\n\t0,\n\t0,\n\t0,\n\t10307,\n\t0,\n\t10308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10311,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10315,\n\t10317,\n\t0,\n\t0,\n\t0,\n\t10318,\n\t10319,\n\t0,\n\t10321,\n\t0,\n\t10326,\n\t0,\n\t10328,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10329,\n\t0,\n\t0,\n\t10331,\n\t0,\n\t10332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10334,\n\t0,\n\t0,\n\t10335,\n\t10338,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10339,\n\t10349,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10351,\n\t0,\n\t10353,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10362,\n\t0,\n\t10368,\n\t0,\n\t10369,\n\t0,\n\t0,\n\t0,\n\t10372,\n\t10373,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10374,\n\t0,\n\t0,\n\t0,\n\t10375,\n\t0,\n\t10376,\n\t0,\n\t0,\n\t10386,\n\t10388,\n\t10390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10391,\n\t0,\n\t0,\n\t10392,\n\t10394,\n\t0,\n\t0,\n\t10396,\n\t0,\n\t10397,\n\t0,\n\t10403,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10404,\n\t0,\n\t10405,\n\t10410,\n\t0,\n\t0,\n\t10411,\n\t0,\n\t10412,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10421,\n\t10422,\n\t10423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10425,\n\t0,\n\t0,\n\t10427,\n\t0,\n\t0,\n\t10430,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10432,\n\t0,\n\t10433,\n\t10434,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10436,\n\t10437,\n\t0,\n\t10438,\n\t0,\n\t10439,\n\t0,\n\t10444,\n\t10446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10448,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10449,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10451,\n\t0,\n\t10453,\n\t0,\n\t0,\n\t0,\n\t10454,\n\t10457,\n\t0,\n\t0,\n\t10459,\n\t0,\n\t10469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10472,\n\t10481,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10482,\n\t10483,\n\t0,\n\t10492,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10499,\n\t0,\n\t0,\n\t0,\n\t10502,\n\t0,\n\t0,\n\t10510,\n\t0,\n\t10521,\n\t10524,\n\t0,\n\t0,\n\t10525,\n\t10526,\n\t10528,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10530,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10533,\n\t0,\n\t10534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10535,\n\t10536,\n\t0,\n\t0,\n\t10544,\n\t0,\n\t10553,\n\t10556,\n\t0,\n\t10557,\n\t10559,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10562,\n\t10563,\n\t10564,\n\t0,\n\t10565,\n\t0,\n\t0,\n\t0,\n\t10566,\n\t0,\n\t10567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10575,\n\t0,\n\t0,\n\t10576,\n\t0,\n\t10578,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10585,\n\t10586,\n\t10587,\n\t10589,\n\t0,\n\t10590,\n\t0,\n\t0,\n\t10594,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10598,\n\t0,\n\t0,\n\t10601,\n\t0,\n\t0,\n\t0,\n\t10602,\n\t0,\n\t10603,\n\t0,\n\t10604,\n\t0,\n\t10605,\n\t0,\n\t0,\n\t10607,\n\t0,\n\t10626,\n\t0,\n\t10627,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10629,\n\t10630,\n\t10631,\n\t0,\n\t0,\n\t0,\n\t10646,\n\t0,\n\t0,\n\t0,\n\t10647,\n\t0,\n\t10650,\n\t0,\n\t10651,\n\t0,\n\t0,\n\t0,\n\t10652,\n\t10653,\n\t10655,\n\t0,\n\t10658,\n\t0,\n\t0,\n\t10659,\n\t0,\n\t10667,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10669,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10670,\n\t0,\n\t0,\n\t0,\n\t10671,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10672,\n\t10673,\n\t0,\n\t10674,\n\t0,\n\t0,\n\t0,\n\t10676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10678,\n\t0,\n\t10682,\n\t0,\n\t0,\n\t10692,\n\t0,\n\t10697,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10698,\n\t0,\n\t0,\n\t0,\n\t10700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10703,\n\t0,\n\t10704,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10705,\n\t0,\n\t10715,\n\t10718,\n\t10720,\n\t0,\n\t0,\n\t10722,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10723,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10727,\n\t10730,\n\t10743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10744,\n\t0,\n\t0,\n\t10745,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10748,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10750,\n\t0,\n\t0,\n\t10752,\n\t10753,\n\t0,\n\t0,\n\t0,\n\t10756,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10758,\n\t0,\n\t0,\n\t0,\n\t10759,\n\t0,\n\t10769,\n\t0,\n\t0,\n\t10772,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10773,\n\t0,\n\t0,\n\t0,\n\t10777,\n\t0,\n\t0,\n\t10779,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10780,\n\t10784,\n\t0,\n\t0,\n\t0,\n\t10789,\n\t0,\n\t0,\n\t0,\n\t10791,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10795,\n\t0,\n\t0,\n\t10796,\n\t0,\n\t10808,\n\t0,\n\t10809,\n\t0,\n\t0,\n\t0,\n\t10810,\n\t0,\n\t0,\n\t0,\n\t10812,\n\t0,\n\t0,\n\t10814,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10815,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10816,\n\t10817,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10819,\n\t0,\n\t10820,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10821,\n\t10822,\n\t10823,\n\t0,\n\t10826,\n\t10849,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10850,\n\t0,\n\t0,\n\t10852,\n\t0,\n\t10853,\n\t0,\n\t0,\n\t10856,\n\t0,\n\t0,\n\t10857,\n\t10858,\n\t10859,\n\t10860,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10863,\n\t0,\n\t10866,\n\t10867,\n\t10872,\n\t10890,\n\t0,\n\t0,\n\t10891,\n\t10892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10893,\n\t0,\n\t0,\n\t0,\n\t10896,\n\t10899,\n\t0,\n\t0,\n\t10900,\n\t10902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10903,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10905,\n\t0,\n\t10906,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10908,\n\t10911,\n\t0,\n\t10912,\n\t0,\n\t0,\n\t10916,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10917,\n\t0,\n\t10918,\n\t0,\n\t0,\n\t0,\n\t10923,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10924,\n\t0,\n\t0,\n\t10928,\n\t10929,\n\t0,\n\t0,\n\t10930,\n\t0,\n\t0,\n\t0,\n\t10932,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10939,\n\t0,\n\t0,\n\t10945,\n\t0,\n\t0,\n\t0,\n\t10947,\n\t0,\n\t0,\n\t10948,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10958,\n\t0,\n\t10960,\n\t10962,\n\t0,\n\t0,\n\t10964,\n\t0,\n\t0,\n\t0,\n\t10966,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10967,\n\t0,\n\t0,\n\t0,\n\t10968,\n\t0,\n\t0,\n\t0,\n\t10973,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10975,\n\t0,\n\t0,\n\t0,\n\t10976,\n\t10978,\n\t0,\n\t0,\n\t10982,\n\t10984,\n\t10987,\n\t0,\n\t0,\n\t10988,\n\t0,\n\t10989,\n\t0,\n\t0,\n\t10991,\n\t0,\n\t0,\n\t0,\n\t0,\n\t10992,\n\t0,\n\t0,\n\t0,\n\t10993,\n\t0,\n\t10995,\n\t0,\n\t0,\n\t0,\n\t10996,\n\t10997,\n\t0,\n\t0,\n\t0,\n\t10998,\n\t0,\n\t10999,\n\t0,\n\t11001,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11010,\n\t11012,\n\t0,\n\t11013,\n\t11016,\n\t11017,\n\t0,\n\t0,\n\t11019,\n\t11020,\n\t11021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11022,\n\t0,\n\t0,\n\t11023,\n\t11029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11031,\n\t0,\n\t0,\n\t0,\n\t11034,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11056,\n\t11060,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11061,\n\t0,\n\t0,\n\t11064,\n\t11065,\n\t0,\n\t11066,\n\t0,\n\t11069,\n\t0,\n\t11085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11086,\n\t0,\n\t0,\n\t0,\n\t11088,\n\t0,\n\t0,\n\t0,\n\t11094,\n\t0,\n\t0,\n\t0,\n\t11095,\n\t11096,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11097,\n\t11098,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11099,\n\t0,\n\t0,\n\t11102,\n\t11108,\n\t0,\n\t0,\n\t0,\n\t11109,\n\t0,\n\t11114,\n\t11119,\n\t0,\n\t11131,\n\t0,\n\t0,\n\t0,\n\t11142,\n\t0,\n\t0,\n\t11143,\n\t0,\n\t11146,\n\t0,\n\t11147,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11148,\n\t0,\n\t11149,\n\t11152,\n\t11153,\n\t11154,\n\t0,\n\t11156,\n\t0,\n\t11157,\n\t0,\n\t0,\n\t0,\n\t11158,\n\t0,\n\t0,\n\t11159,\n\t11160,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11163,\n\t0,\n\t0,\n\t11164,\n\t11166,\n\t0,\n\t0,\n\t0,\n\t11172,\n\t11174,\n\t0,\n\t0,\n\t0,\n\t11176,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11182,\n\t11183,\n\t0,\n\t0,\n\t0,\n\t11184,\n\t11187,\n\t0,\n\t0,\n\t11188,\n\t11189,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11194,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11200,\n\t11202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11203,\n\t0,\n\t11204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11205,\n\t0,\n\t0,\n\t0,\n\t11206,\n\t0,\n\t11207,\n\t0,\n\t0,\n\t11209,\n\t0,\n\t11211,\n\t0,\n\t11214,\n\t0,\n\t0,\n\t11231,\n\t0,\n\t0,\n\t0,\n\t11293,\n\t11295,\n\t0,\n\t0,\n\t11296,\n\t11297,\n\t11302,\n\t0,\n\t0,\n\t0,\n\t11307,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11309,\n\t11310,\n\t0,\n\t11311,\n\t0,\n\t0,\n\t0,\n\t11313,\n\t0,\n\t11314,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11334,\n\t0,\n\t11338,\n\t0,\n\t0,\n\t0,\n\t11339,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11340,\n\t0,\n\t11341,\n\t11342,\n\t0,\n\t11344,\n\t0,\n\t11345,\n\t0,\n\t0,\n\t0,\n\t11348,\n\t11349,\n\t0,\n\t0,\n\t11350,\n\t0,\n\t0,\n\t0,\n\t11355,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11356,\n\t0,\n\t11357,\n\t11370,\n\t0,\n\t0,\n\t11371,\n\t0,\n\t11374,\n\t11376,\n\t0,\n\t0,\n\t0,\n\t11377,\n\t0,\n\t0,\n\t11378,\n\t11383,\n\t0,\n\t11386,\n\t11399,\n\t0,\n\t11400,\n\t11406,\n\t0,\n\t0,\n\t0,\n\t11408,\n\t0,\n\t0,\n\t11409,\n\t11412,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11417,\n\t0,\n\t0,\n\t0,\n\t11418,\n\t0,\n\t11421,\n\t0,\n\t11426,\n\t11429,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11430,\n\t0,\n\t11437,\n\t0,\n\t11438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11440,\n\t11453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11455,\n\t0,\n\t0,\n\t11456,\n\t11460,\n\t11461,\n\t11463,\n\t0,\n\t11469,\n\t0,\n\t11473,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11474,\n\t0,\n\t0,\n\t0,\n\t11475,\n\t0,\n\t11476,\n\t11477,\n\t11480,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11481,\n\t0,\n\t0,\n\t11484,\n\t0,\n\t0,\n\t11487,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11497,\n\t0,\n\t0,\n\t11502,\n\t0,\n\t11509,\n\t0,\n\t0,\n\t11510,\n\t11511,\n\t11513,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11515,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11516,\n\t0,\n\t11520,\n\t11521,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11529,\n\t11530,\n\t11531,\n\t11534,\n\t0,\n\t0,\n\t11543,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11547,\n\t0,\n\t11548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11552,\n\t11556,\n\t0,\n\t11557,\n\t0,\n\t0,\n\t11559,\n\t0,\n\t11560,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11561,\n\t0,\n\t0,\n\t11563,\n\t11564,\n\t0,\n\t11565,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11567,\n\t0,\n\t0,\n\t0,\n\t11569,\n\t0,\n\t11574,\n\t0,\n\t11575,\n\t0,\n\t0,\n\t0,\n\t11577,\n\t0,\n\t11578,\n\t0,\n\t0,\n\t0,\n\t11580,\n\t11581,\n\t0,\n\t0,\n\t0,\n\t11582,\n\t11584,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11587,\n\t0,\n\t11588,\n\t11591,\n\t0,\n\t11595,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11596,\n\t0,\n\t11597,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11598,\n\t11601,\n\t0,\n\t0,\n\t0,\n\t11602,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11603,\n\t11604,\n\t0,\n\t11606,\n\t0,\n\t0,\n\t11608,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11610,\n\t0,\n\t0,\n\t11611,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11613,\n\t0,\n\t11622,\n\t0,\n\t0,\n\t0,\n\t11623,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11625,\n\t0,\n\t0,\n\t11626,\n\t11627,\n\t11628,\n\t11630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11639,\n\t0,\n\t0,\n\t11646,\n\t0,\n\t11648,\n\t11649,\n\t0,\n\t11650,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11651,\n\t0,\n\t0,\n\t11652,\n\t11653,\n\t11656,\n\t0,\n\t0,\n\t11677,\n\t11679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11680,\n\t0,\n\t0,\n\t11681,\n\t0,\n\t11685,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11688,\n\t0,\n\t0,\n\t0,\n\t11716,\n\t0,\n\t11719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11721,\n\t0,\n\t0,\n\t11724,\n\t11743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11745,\n\t11748,\n\t11750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11751,\n\t0,\n\t0,\n\t0,\n\t11752,\n\t11754,\n\t0,\n\t11755,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11759,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11760,\n\t0,\n\t0,\n\t0,\n\t11761,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11766,\n\t11767,\n\t0,\n\t11772,\n\t11773,\n\t0,\n\t11774,\n\t0,\n\t0,\n\t11775,\n\t0,\n\t11777,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11778,\n\t11780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11783,\n\t0,\n\t11784,\n\t0,\n\t0,\n\t0,\n\t11785,\n\t0,\n\t0,\n\t0,\n\t11786,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11788,\n\t0,\n\t0,\n\t11789,\n\t11791,\n\t11792,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11795,\n\t11834,\n\t11835,\n\t11836,\n\t0,\n\t0,\n\t11837,\n\t0,\n\t0,\n\t0,\n\t11838,\n\t0,\n\t0,\n\t11846,\n\t11851,\n\t0,\n\t11852,\n\t0,\n\t11869,\n\t0,\n\t0,\n\t0,\n\t11871,\n\t0,\n\t0,\n\t0,\n\t11872,\n\t11874,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11875,\n\t0,\n\t11876,\n\t11877,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11883,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11884,\n\t0,\n\t11885,\n\t0,\n\t11886,\n\t0,\n\t0,\n\t11887,\n\t0,\n\t11894,\n\t11895,\n\t11897,\n\t11909,\n\t11910,\n\t0,\n\t11912,\n\t11918,\n\t0,\n\t0,\n\t11920,\n\t0,\n\t11922,\n\t11924,\n\t11927,\n\t11928,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11929,\n\t0,\n\t11934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11941,\n\t11943,\n\t11944,\n\t0,\n\t11945,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11948,\n\t11949,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11953,\n\t0,\n\t11954,\n\t0,\n\t11955,\n\t0,\n\t11956,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11957,\n\t0,\n\t0,\n\t11959,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11961,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11978,\n\t0,\n\t0,\n\t0,\n\t11979,\n\t11980,\n\t11986,\n\t11987,\n\t0,\n\t11992,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t11993,\n\t0,\n\t0,\n\t0,\n\t11994,\n\t0,\n\t11999,\n\t12004,\n\t12005,\n\t12006,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12011,\n\t0,\n\t0,\n\t12012,\n\t12014,\n\t0,\n\t0,\n\t12015,\n\t0,\n\t0,\n\t12019,\n\t12028,\n\t0,\n\t0,\n\t12029,\n\t0,\n\t0,\n\t12032,\n\t12033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12034,\n\t0,\n\t12041,\n\t12043,\n\t0,\n\t0,\n\t12044,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12054,\n\t12055,\n\t0,\n\t12056,\n\t0,\n\t0,\n\t0,\n\t12060,\n\t12064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12065,\n\t12067,\n\t12068,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12074,\n\t0,\n\t0,\n\t0,\n\t12075,\n\t12076,\n\t0,\n\t0,\n\t0,\n\t12079,\n\t0,\n\t12081,\n\t12086,\n\t12087,\n\t0,\n\t0,\n\t12088,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12089,\n\t0,\n\t12092,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12097,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12098,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12102,\n\t12103,\n\t12104,\n\t12111,\n\t0,\n\t0,\n\t12114,\n\t12116,\n\t0,\n\t0,\n\t0,\n\t12118,\n\t0,\n\t0,\n\t0,\n\t12119,\n\t12120,\n\t12128,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12130,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12131,\n\t0,\n\t0,\n\t0,\n\t12132,\n\t12134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12137,\n\t0,\n\t12139,\n\t0,\n\t12141,\n\t0,\n\t0,\n\t12142,\n\t0,\n\t0,\n\t0,\n\t12144,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12145,\n\t0,\n\t12148,\n\t0,\n\t12153,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12154,\n\t12171,\n\t12173,\n\t0,\n\t0,\n\t0,\n\t12175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12178,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12184,\n\t0,\n\t0,\n\t0,\n\t12186,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12187,\n\t12188,\n\t0,\n\t0,\n\t12189,\n\t0,\n\t12196,\n\t0,\n\t12197,\n\t0,\n\t0,\n\t12198,\n\t0,\n\t12201,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12203,\n\t0,\n\t12209,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12210,\n\t12211,\n\t12212,\n\t12213,\n\t0,\n\t12217,\n\t12218,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12222,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12223,\n\t0,\n\t0,\n\t12229,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12233,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12234,\n\t0,\n\t0,\n\t12236,\n\t12242,\n\t0,\n\t0,\n\t0,\n\t12243,\n\t0,\n\t0,\n\t0,\n\t12244,\n\t12253,\n\t0,\n\t12254,\n\t12256,\n\t0,\n\t12257,\n\t0,\n\t0,\n\t12275,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12278,\n\t0,\n\t12289,\n\t0,\n\t0,\n\t12290,\n\t0,\n\t12292,\n\t12293,\n\t0,\n\t0,\n\t12294,\n\t0,\n\t12295,\n\t0,\n\t0,\n\t12296,\n\t0,\n\t12297,\n\t0,\n\t12298,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12309,\n\t0,\n\t12338,\n\t12340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12341,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12342,\n\t12343,\n\t0,\n\t12344,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12345,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12346,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12350,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12351,\n\t0,\n\t12355,\n\t12356,\n\t12357,\n\t0,\n\t0,\n\t12367,\n\t12370,\n\t12371,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12372,\n\t12376,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12379,\n\t0,\n\t12382,\n\t0,\n\t12383,\n\t0,\n\t0,\n\t12384,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12393,\n\t0,\n\t0,\n\t12394,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12398,\n\t12403,\n\t0,\n\t0,\n\t12404,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12410,\n\t0,\n\t0,\n\t0,\n\t12411,\n\t0,\n\t0,\n\t0,\n\t12412,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12420,\n\t0,\n\t12421,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12423,\n\t0,\n\t12425,\n\t12429,\n\t0,\n\t0,\n\t0,\n\t12431,\n\t12432,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12434,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12435,\n\t12436,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12437,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12445,\n\t0,\n\t0,\n\t0,\n\t12450,\n\t12451,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12452,\n\t12475,\n\t0,\n\t0,\n\t12493,\n\t12494,\n\t0,\n\t0,\n\t0,\n\t12495,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12496,\n\t12502,\n\t12509,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12510,\n\t0,\n\t12512,\n\t12513,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12514,\n\t0,\n\t0,\n\t0,\n\t12515,\n\t0,\n\t12520,\n\t0,\n\t0,\n\t0,\n\t12524,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12527,\n\t0,\n\t0,\n\t0,\n\t12528,\n\t0,\n\t0,\n\t0,\n\t12529,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12530,\n\t0,\n\t12535,\n\t0,\n\t0,\n\t12536,\n\t0,\n\t12538,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12540,\n\t0,\n\t12548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12550,\n\t0,\n\t0,\n\t0,\n\t12551,\n\t12552,\n\t0,\n\t0,\n\t0,\n\t12554,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12555,\n\t0,\n\t0,\n\t12562,\n\t0,\n\t12565,\n\t0,\n\t12566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12569,\n\t0,\n\t0,\n\t0,\n\t12571,\n\t12574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12577,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12578,\n\t12579,\n\t12603,\n\t0,\n\t12608,\n\t0,\n\t0,\n\t12611,\n\t0,\n\t12612,\n\t0,\n\t12615,\n\t0,\n\t12625,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12627,\n\t12646,\n\t0,\n\t12648,\n\t0,\n\t0,\n\t12657,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12670,\n\t0,\n\t0,\n\t12671,\n\t0,\n\t12673,\n\t12677,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12679,\n\t0,\n\t12681,\n\t0,\n\t12682,\n\t12693,\n\t0,\n\t12694,\n\t0,\n\t12697,\n\t0,\n\t12701,\n\t0,\n\t0,\n\t0,\n\t12703,\n\t12704,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12707,\n\t12737,\n\t0,\n\t0,\n\t12739,\n\t0,\n\t0,\n\t12740,\n\t0,\n\t0,\n\t12742,\n\t12743,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12745,\n\t0,\n\t12746,\n\t12747,\n\t0,\n\t12748,\n\t0,\n\t0,\n\t12759,\n\t12767,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12773,\n\t0,\n\t12774,\n\t12778,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12779,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12780,\n\t12793,\n\t0,\n\t12824,\n\t0,\n\t12825,\n\t0,\n\t12836,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12839,\n\t0,\n\t12842,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12843,\n\t12845,\n\t0,\n\t12846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12847,\n\t0,\n\t0,\n\t12850,\n\t12852,\n\t12853,\n\t0,\n\t0,\n\t0,\n\t12854,\n\t0,\n\t0,\n\t0,\n\t12855,\n\t0,\n\t12856,\n\t0,\n\t12858,\n\t0,\n\t0,\n\t12859,\n\t0,\n\t12862,\n\t0,\n\t12863,\n\t0,\n\t0,\n\t12866,\n\t0,\n\t12869,\n\t12872,\n\t12873,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12875,\n\t0,\n\t12877,\n\t0,\n\t0,\n\t12878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12884,\n\t12885,\n\t12888,\n\t0,\n\t12889,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12893,\n\t0,\n\t0,\n\t0,\n\t12895,\n\t12896,\n\t12898,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12902,\n\t0,\n\t12909,\n\t12910,\n\t0,\n\t12926,\n\t0,\n\t12928,\n\t0,\n\t0,\n\t0,\n\t12929,\n\t0,\n\t12930,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12931,\n\t0,\n\t12932,\n\t12933,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12934,\n\t0,\n\t12942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12944,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12946,\n\t0,\n\t0,\n\t12948,\n\t0,\n\t0,\n\t12949,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12951,\n\t0,\n\t12952,\n\t0,\n\t12953,\n\t0,\n\t0,\n\t0,\n\t12954,\n\t12958,\n\t12959,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12960,\n\t12964,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12966,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12970,\n\t0,\n\t12971,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t12972,\n\t0,\n\t0,\n\t12982,\n\t0,\n\t0,\n\t0,\n\t12984,\n\t12985,\n\t0,\n\t12986,\n\t12996,\n\t12997,\n\t13001,\n\t13002,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13004,\n\t0,\n\t0,\n\t13005,\n\t0,\n\t0,\n\t13007,\n\t13009,\n\t0,\n\t13017,\n\t0,\n\t0,\n\t0,\n\t13020,\n\t0,\n\t13021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13024,\n\t13027,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13028,\n\t0,\n\t0,\n\t13029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13032,\n\t0,\n\t13037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13040,\n\t0,\n\t0,\n\t13041,\n\t0,\n\t0,\n\t0,\n\t13043,\n\t13044,\n\t13046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13049,\n\t13054,\n\t0,\n\t13056,\n\t0,\n\t0,\n\t13060,\n\t13061,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13067,\n\t0,\n\t0,\n\t13068,\n\t0,\n\t13071,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13077,\n\t13078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13079,\n\t13080,\n\t13081,\n\t0,\n\t13082,\n\t0,\n\t0,\n\t0,\n\t13085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13086,\n\t0,\n\t13087,\n\t13088,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13094,\n\t0,\n\t13099,\n\t0,\n\t13100,\n\t0,\n\t0,\n\t0,\n\t13101,\n\t0,\n\t13125,\n\t13126,\n\t13128,\n\t13129,\n\t0,\n\t0,\n\t13130,\n\t0,\n\t13131,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13150,\n\t0,\n\t13168,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13169,\n\t0,\n\t0,\n\t13170,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13174,\n\t0,\n\t0,\n\t0,\n\t13176,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13177,\n\t0,\n\t13178,\n\t13183,\n\t13187,\n\t0,\n\t0,\n\t0,\n\t13189,\n\t0,\n\t0,\n\t13190,\n\t0,\n\t0,\n\t13191,\n\t0,\n\t0,\n\t13206,\n\t0,\n\t0,\n\t0,\n\t13207,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13212,\n\t0,\n\t0,\n\t13219,\n\t13232,\n\t0,\n\t0,\n\t0,\n\t13241,\n\t0,\n\t13249,\n\t13253,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13255,\n\t13259,\n\t0,\n\t13260,\n\t13261,\n\t0,\n\t13262,\n\t0,\n\t13272,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13277,\n\t13299,\n\t0,\n\t0,\n\t13301,\n\t13302,\n\t0,\n\t0,\n\t13303,\n\t0,\n\t0,\n\t13305,\n\t0,\n\t13310,\n\t0,\n\t0,\n\t0,\n\t13311,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13325,\n\t0,\n\t13328,\n\t0,\n\t0,\n\t0,\n\t13329,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13330,\n\t0,\n\t0,\n\t13331,\n\t0,\n\t13335,\n\t0,\n\t0,\n\t13342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13343,\n\t0,\n\t13354,\n\t0,\n\t13362,\n\t0,\n\t13366,\n\t13367,\n\t13369,\n\t0,\n\t0,\n\t13371,\n\t13372,\n\t0,\n\t13373,\n\t13374,\n\t0,\n\t13376,\n\t0,\n\t13380,\n\t13381,\n\t13386,\n\t0,\n\t13387,\n\t13388,\n\t0,\n\t13389,\n\t13391,\n\t13395,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13401,\n\t13409,\n\t0,\n\t13410,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13422,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13425,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13427,\n\t0,\n\t0,\n\t0,\n\t13428,\n\t0,\n\t0,\n\t13430,\n\t13438,\n\t0,\n\t13439,\n\t0,\n\t13445,\n\t0,\n\t13448,\n\t13449,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13451,\n\t0,\n\t13457,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13458,\n\t13459,\n\t0,\n\t13460,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13464,\n\t13465,\n\t13466,\n\t13470,\n\t0,\n\t13471,\n\t13472,\n\t13474,\n\t13475,\n\t0,\n\t13476,\n\t0,\n\t0,\n\t13478,\n\t13479,\n\t0,\n\t13481,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13487,\n\t0,\n\t13490,\n\t0,\n\t13493,\n\t0,\n\t0,\n\t13494,\n\t0,\n\t0,\n\t13495,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13496,\n\t13497,\n\t0,\n\t13500,\n\t0,\n\t0,\n\t13516,\n\t13522,\n\t0,\n\t0,\n\t13525,\n\t13528,\n\t0,\n\t0,\n\t0,\n\t13530,\n\t13535,\n\t0,\n\t13537,\n\t13539,\n\t0,\n\t13540,\n\t0,\n\t13543,\n\t0,\n\t13544,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13545,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13547,\n\t0,\n\t0,\n\t0,\n\t13549,\n\t13555,\n\t0,\n\t0,\n\t0,\n\t13556,\n\t13557,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13558,\n\t0,\n\t13563,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13564,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13569,\n\t0,\n\t0,\n\t13571,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13573,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13578,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13581,\n\t0,\n\t13586,\n\t0,\n\t13595,\n\t0,\n\t13600,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13601,\n\t13603,\n\t0,\n\t13604,\n\t13605,\n\t13606,\n\t13607,\n\t0,\n\t0,\n\t13617,\n\t13618,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13623,\n\t0,\n\t13625,\n\t13627,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13629,\n\t0,\n\t0,\n\t0,\n\t13634,\n\t0,\n\t0,\n\t0,\n\t13638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13654,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13656,\n\t0,\n\t13659,\n\t0,\n\t0,\n\t13660,\n\t0,\n\t0,\n\t13662,\n\t0,\n\t0,\n\t0,\n\t13663,\n\t0,\n\t13664,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13668,\n\t0,\n\t13669,\n\t13671,\n\t0,\n\t0,\n\t13672,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13675,\n\t13685,\n\t0,\n\t13686,\n\t0,\n\t0,\n\t0,\n\t13687,\n\t0,\n\t0,\n\t0,\n\t13692,\n\t13694,\n\t13697,\n\t0,\n\t0,\n\t0,\n\t13702,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13705,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13707,\n\t0,\n\t0,\n\t0,\n\t13714,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13715,\n\t0,\n\t13716,\n\t13717,\n\t0,\n\t0,\n\t13719,\n\t13724,\n\t13730,\n\t13731,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13732,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13734,\n\t0,\n\t13736,\n\t0,\n\t0,\n\t13737,\n\t13738,\n\t13747,\n\t0,\n\t13751,\n\t0,\n\t0,\n\t13752,\n\t0,\n\t0,\n\t0,\n\t13753,\n\t0,\n\t13757,\n\t0,\n\t0,\n\t13762,\n\t13763,\n\t0,\n\t13764,\n\t13765,\n\t0,\n\t13766,\n\t0,\n\t0,\n\t13767,\n\t0,\n\t0,\n\t0,\n\t13768,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13769,\n\t0,\n\t0,\n\t13772,\n\t0,\n\t13775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13776,\n\t13778,\n\t13787,\n\t0,\n\t0,\n\t0,\n\t13797,\n\t0,\n\t13798,\n\t0,\n\t13801,\n\t0,\n\t13804,\n\t13806,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13816,\n\t13817,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13834,\n\t0,\n\t13836,\n\t0,\n\t0,\n\t13838,\n\t0,\n\t0,\n\t13839,\n\t0,\n\t13840,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13842,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13843,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13858,\n\t0,\n\t0,\n\t13860,\n\t0,\n\t0,\n\t13861,\n\t0,\n\t0,\n\t13862,\n\t13863,\n\t0,\n\t13868,\n\t0,\n\t13869,\n\t13870,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13872,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13873,\n\t13878,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13886,\n\t0,\n\t13888,\n\t13889,\n\t13890,\n\t0,\n\t0,\n\t13891,\n\t13894,\n\t0,\n\t13897,\n\t13899,\n\t13900,\n\t13904,\n\t0,\n\t0,\n\t13906,\n\t0,\n\t0,\n\t0,\n\t13909,\n\t0,\n\t0,\n\t0,\n\t13910,\n\t0,\n\t0,\n\t0,\n\t13911,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13912,\n\t13917,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13918,\n\t0,\n\t13919,\n\t0,\n\t0,\n\t13920,\n\t0,\n\t0,\n\t0,\n\t13921,\n\t0,\n\t0,\n\t13922,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13924,\n\t0,\n\t13927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13932,\n\t0,\n\t13933,\n\t0,\n\t13934,\n\t0,\n\t0,\n\t13935,\n\t0,\n\t13944,\n\t0,\n\t0,\n\t0,\n\t13954,\n\t0,\n\t0,\n\t13955,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13956,\n\t0,\n\t13957,\n\t0,\n\t13967,\n\t13969,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13970,\n\t13990,\n\t0,\n\t13991,\n\t13994,\n\t0,\n\t13995,\n\t0,\n\t0,\n\t0,\n\t0,\n\t13996,\n\t0,\n\t0,\n\t13999,\n\t0,\n\t0,\n\t0,\n\t14018,\n\t0,\n\t14019,\n\t0,\n\t14021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14041,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14043,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14046,\n\t0,\n\t0,\n\t0,\n\t14048,\n\t14049,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14051,\n\t0,\n\t0,\n\t14052,\n\t14056,\n\t0,\n\t14063,\n\t0,\n\t14064,\n\t14066,\n\t0,\n\t0,\n\t14067,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14068,\n\t0,\n\t0,\n\t0,\n\t14072,\n\t0,\n\t14074,\n\t14075,\n\t0,\n\t14076,\n\t14079,\n\t14085,\n\t14086,\n\t14087,\n\t14093,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14096,\n\t14097,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14098,\n\t0,\n\t14102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14103,\n\t0,\n\t0,\n\t0,\n\t14104,\n\t0,\n\t0,\n\t14105,\n\t0,\n\t0,\n\t0,\n\t14107,\n\t14108,\n\t0,\n\t0,\n\t14109,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14117,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14118,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14119,\n\t0,\n\t0,\n\t14120,\n\t0,\n\t0,\n\t14121,\n\t0,\n\t14122,\n\t14127,\n\t0,\n\t14128,\n\t14136,\n\t0,\n\t0,\n\t14138,\n\t0,\n\t14140,\n\t0,\n\t0,\n\t0,\n\t14141,\n\t14142,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14146,\n\t0,\n\t0,\n\t14149,\n\t0,\n\t14151,\n\t0,\n\t0,\n\t0,\n\t14152,\n\t0,\n\t0,\n\t14153,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14154,\n\t0,\n\t14156,\n\t14157,\n\t0,\n\t0,\n\t14159,\n\t0,\n\t14161,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14162,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14163,\n\t0,\n\t0,\n\t14173,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14174,\n\t0,\n\t0,\n\t14176,\n\t0,\n\t0,\n\t14178,\n\t0,\n\t0,\n\t14179,\n\t14181,\n\t0,\n\t0,\n\t14182,\n\t14185,\n\t14187,\n\t0,\n\t14190,\n\t0,\n\t0,\n\t14197,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14199,\n\t14200,\n\t0,\n\t0,\n\t0,\n\t14204,\n\t0,\n\t0,\n\t14208,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14231,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14234,\n\t0,\n\t0,\n\t14235,\n\t0,\n\t0,\n\t0,\n\t14240,\n\t14241,\n\t0,\n\t0,\n\t0,\n\t14246,\n\t0,\n\t0,\n\t0,\n\t14247,\n\t0,\n\t14250,\n\t0,\n\t0,\n\t14251,\n\t0,\n\t0,\n\t14254,\n\t0,\n\t0,\n\t14256,\n\t0,\n\t0,\n\t0,\n\t14260,\n\t0,\n\t14261,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14262,\n\t14267,\n\t14269,\n\t0,\n\t0,\n\t14277,\n\t0,\n\t0,\n\t14278,\n\t0,\n\t14279,\n\t14282,\n\t0,\n\t0,\n\t0,\n\t14283,\n\t0,\n\t0,\n\t0,\n\t14284,\n\t14285,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14286,\n\t0,\n\t0,\n\t0,\n\t14288,\n\t0,\n\t0,\n\t0,\n\t14289,\n\t0,\n\t14290,\n\t0,\n\t14293,\n\t14301,\n\t14302,\n\t14304,\n\t14305,\n\t0,\n\t14307,\n\t0,\n\t14308,\n\t14309,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14311,\n\t14312,\n\t0,\n\t0,\n\t14317,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14320,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14321,\n\t14322,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14326,\n\t14329,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14330,\n\t14331,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14332,\n\t0,\n\t0,\n\t0,\n\t14333,\n\t0,\n\t0,\n\t14337,\n\t14340,\n\t0,\n\t14341,\n\t0,\n\t0,\n\t14342,\n\t0,\n\t14345,\n\t14346,\n\t0,\n\t0,\n\t14347,\n\t0,\n\t14362,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14364,\n\t14365,\n\t14371,\n\t0,\n\t14373,\n\t0,\n\t0,\n\t14374,\n\t0,\n\t14379,\n\t0,\n\t14400,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14401,\n\t0,\n\t0,\n\t14405,\n\t0,\n\t14406,\n\t0,\n\t14408,\n\t14409,\n\t0,\n\t0,\n\t0,\n\t14417,\n\t0,\n\t0,\n\t14424,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14430,\n\t0,\n\t0,\n\t0,\n\t14431,\n\t0,\n\t0,\n\t14435,\n\t0,\n\t14440,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14442,\n\t0,\n\t0,\n\t14443,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14454,\n\t0,\n\t14457,\n\t0,\n\t14460,\n\t0,\n\t0,\n\t14466,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14467,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14469,\n\t0,\n\t14477,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14478,\n\t14482,\n\t0,\n\t0,\n\t0,\n\t14483,\n\t0,\n\t0,\n\t0,\n\t14485,\n\t14486,\n\t0,\n\t0,\n\t0,\n\t14487,\n\t14488,\n\t14489,\n\t14492,\n\t14493,\n\t14494,\n\t14495,\n\t14496,\n\t14497,\n\t0,\n\t14499,\n\t0,\n\t14501,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14502,\n\t0,\n\t14507,\n\t14512,\n\t14513,\n\t14514,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14515,\n\t14526,\n\t14530,\n\t0,\n\t14537,\n\t0,\n\t14544,\n\t0,\n\t14547,\n\t0,\n\t0,\n\t14548,\n\t14550,\n\t14551,\n\t0,\n\t0,\n\t14552,\n\t0,\n\t0,\n\t0,\n\t14553,\n\t0,\n\t14554,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14556,\n\t14564,\n\t0,\n\t0,\n\t14565,\n\t14566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14568,\n\t0,\n\t0,\n\t14569,\n\t0,\n\t0,\n\t0,\n\t14571,\n\t14576,\n\t0,\n\t0,\n\t14577,\n\t14578,\n\t14579,\n\t0,\n\t0,\n\t14580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14587,\n\t0,\n\t14588,\n\t0,\n\t0,\n\t14600,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14601,\n\t0,\n\t0,\n\t14604,\n\t14605,\n\t14611,\n\t0,\n\t14613,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14615,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14627,\n\t0,\n\t14628,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14631,\n\t0,\n\t14633,\n\t14634,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14635,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14636,\n\t0,\n\t0,\n\t14639,\n\t14642,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14644,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14645,\n\t14646,\n\t0,\n\t14653,\n\t0,\n\t0,\n\t14654,\n\t0,\n\t14658,\n\t0,\n\t14661,\n\t0,\n\t0,\n\t0,\n\t14665,\n\t0,\n\t0,\n\t0,\n\t14668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14669,\n\t0,\n\t0,\n\t14670,\n\t0,\n\t0,\n\t0,\n\t14680,\n\t0,\n\t0,\n\t14681,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14682,\n\t14683,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14686,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14687,\n\t14697,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14699,\n\t14705,\n\t14711,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14712,\n\t0,\n\t0,\n\t0,\n\t14713,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14719,\n\t0,\n\t14720,\n\t14721,\n\t14726,\n\t0,\n\t0,\n\t0,\n\t14728,\n\t14729,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14731,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14733,\n\t14736,\n\t14737,\n\t0,\n\t0,\n\t14740,\n\t14742,\n\t0,\n\t0,\n\t0,\n\t14744,\n\t14753,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14755,\n\t14758,\n\t14760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14761,\n\t14762,\n\t14765,\n\t14771,\n\t0,\n\t14772,\n\t0,\n\t14773,\n\t14774,\n\t0,\n\t0,\n\t14775,\n\t0,\n\t0,\n\t14776,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14777,\n\t0,\n\t14779,\n\t0,\n\t0,\n\t14782,\n\t0,\n\t0,\n\t14785,\n\t14786,\n\t14788,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14795,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14798,\n\t0,\n\t14803,\n\t14804,\n\t14806,\n\t0,\n\t0,\n\t0,\n\t14809,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14810,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14811,\n\t0,\n\t14812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14815,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14816,\n\t0,\n\t14818,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14819,\n\t0,\n\t14820,\n\t0,\n\t14823,\n\t0,\n\t0,\n\t0,\n\t14824,\n\t0,\n\t0,\n\t14826,\n\t14827,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14833,\n\t0,\n\t14845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14846,\n\t0,\n\t0,\n\t14847,\n\t14871,\n\t0,\n\t14873,\n\t0,\n\t14876,\n\t0,\n\t14877,\n\t14878,\n\t14880,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14881,\n\t0,\n\t14882,\n\t14894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14895,\n\t0,\n\t14907,\n\t0,\n\t14908,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14911,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14920,\n\t0,\n\t0,\n\t14931,\n\t0,\n\t14932,\n\t14934,\n\t14935,\n\t0,\n\t0,\n\t14936,\n\t0,\n\t14945,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14947,\n\t0,\n\t0,\n\t14948,\n\t14949,\n\t14951,\n\t0,\n\t0,\n\t14952,\n\t0,\n\t0,\n\t0,\n\t14964,\n\t14973,\n\t0,\n\t0,\n\t14990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t14995,\n\t0,\n\t0,\n\t14998,\n\t15001,\n\t0,\n\t0,\n\t15002,\n\t15020,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15021,\n\t0,\n\t15022,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15023,\n\t0,\n\t0,\n\t15025,\n\t15029,\n\t15033,\n\t0,\n\t0,\n\t0,\n\t15034,\n\t0,\n\t0,\n\t0,\n\t15035,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15043,\n\t15044,\n\t0,\n\t0,\n\t0,\n\t15045,\n\t15046,\n\t15048,\n\t15050,\n\t0,\n\t15065,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15066,\n\t0,\n\t0,\n\t15075,\n\t15082,\n\t15084,\n\t0,\n\t0,\n\t15085,\n\t15086,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15088,\n\t0,\n\t0,\n\t0,\n\t15089,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15094,\n\t0,\n\t15096,\n\t0,\n\t15097,\n\t0,\n\t15100,\n\t0,\n\t0,\n\t15102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15105,\n\t0,\n\t0,\n\t15106,\n\t0,\n\t15109,\n\t15113,\n\t0,\n\t0,\n\t0,\n\t15115,\n\t0,\n\t15118,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15119,\n\t0,\n\t0,\n\t15120,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15123,\n\t15129,\n\t0,\n\t0,\n\t0,\n\t15130,\n\t0,\n\t15131,\n\t0,\n\t0,\n\t15134,\n\t0,\n\t15135,\n\t0,\n\t0,\n\t0,\n\t15137,\n\t15138,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15139,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15140,\n\t0,\n\t0,\n\t15154,\n\t15162,\n\t0,\n\t15169,\n\t15170,\n\t0,\n\t15175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15177,\n\t0,\n\t15178,\n\t15179,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15183,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15185,\n\t15187,\n\t0,\n\t15194,\n\t15195,\n\t15196,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15206,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15207,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15213,\n\t0,\n\t15214,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15232,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15234,\n\t0,\n\t15238,\n\t15240,\n\t0,\n\t15248,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15250,\n\t15251,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15252,\n\t0,\n\t0,\n\t0,\n\t15255,\n\t15262,\n\t15266,\n\t0,\n\t0,\n\t0,\n\t15267,\n\t0,\n\t0,\n\t0,\n\t15277,\n\t15279,\n\t0,\n\t0,\n\t0,\n\t15280,\n\t15281,\n\t15282,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15285,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15289,\n\t0,\n\t0,\n\t15291,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15296,\n\t15297,\n\t0,\n\t0,\n\t15304,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15306,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15307,\n\t15308,\n\t0,\n\t15309,\n\t0,\n\t0,\n\t15311,\n\t0,\n\t0,\n\t15312,\n\t15313,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15314,\n\t15317,\n\t0,\n\t0,\n\t0,\n\t15318,\n\t15319,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15320,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15321,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15324,\n\t0,\n\t15325,\n\t15326,\n\t0,\n\t15330,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15334,\n\t0,\n\t15335,\n\t0,\n\t15341,\n\t0,\n\t0,\n\t15342,\n\t0,\n\t0,\n\t15343,\n\t15344,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15345,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15347,\n\t0,\n\t0,\n\t15348,\n\t15349,\n\t15350,\n\t0,\n\t15356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15357,\n\t0,\n\t15358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15359,\n\t15360,\n\t15364,\n\t0,\n\t15380,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15392,\n\t0,\n\t0,\n\t15393,\n\t0,\n\t15395,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15396,\n\t0,\n\t0,\n\t15397,\n\t15398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15399,\n\t0,\n\t15400,\n\t0,\n\t0,\n\t0,\n\t15402,\n\t0,\n\t15405,\n\t15410,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15411,\n\t0,\n\t0,\n\t0,\n\t15412,\n\t0,\n\t15416,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15428,\n\t0,\n\t15435,\n\t0,\n\t0,\n\t15438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15439,\n\t0,\n\t0,\n\t0,\n\t15440,\n\t0,\n\t0,\n\t0,\n\t15441,\n\t15449,\n\t15451,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15452,\n\t0,\n\t0,\n\t15455,\n\t0,\n\t0,\n\t0,\n\t15456,\n\t0,\n\t0,\n\t15458,\n\t0,\n\t15460,\n\t15461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15462,\n\t15464,\n\t0,\n\t15465,\n\t0,\n\t0,\n\t15466,\n\t0,\n\t0,\n\t15467,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15468,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15481,\n\t0,\n\t0,\n\t15484,\n\t0,\n\t15485,\n\t15486,\n\t0,\n\t0,\n\t0,\n\t15487,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15488,\n\t0,\n\t15492,\n\t15498,\n\t0,\n\t0,\n\t0,\n\t15499,\n\t0,\n\t0,\n\t0,\n\t15500,\n\t0,\n\t15501,\n\t0,\n\t0,\n\t15512,\n\t0,\n\t15522,\n\t0,\n\t0,\n\t0,\n\t15524,\n\t0,\n\t15525,\n\t15526,\n\t0,\n\t0,\n\t15527,\n\t0,\n\t0,\n\t15545,\n\t15546,\n\t0,\n\t15548,\n\t15552,\n\t0,\n\t15553,\n\t0,\n\t0,\n\t0,\n\t15554,\n\t0,\n\t15555,\n\t0,\n\t15557,\n\t15565,\n\t15573,\n\t15577,\n\t15578,\n\t0,\n\t15582,\n\t0,\n\t15583,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15586,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15593,\n\t15594,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15595,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15596,\n\t0,\n\t0,\n\t0,\n\t15597,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15600,\n\t0,\n\t0,\n\t15601,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15602,\n\t15603,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15604,\n\t0,\n\t15609,\n\t0,\n\t0,\n\t15612,\n\t0,\n\t0,\n\t15613,\n\t0,\n\t0,\n\t15615,\n\t15617,\n\t15618,\n\t0,\n\t0,\n\t15620,\n\t0,\n\t15636,\n\t15637,\n\t0,\n\t0,\n\t15649,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15650,\n\t0,\n\t0,\n\t15651,\n\t0,\n\t0,\n\t0,\n\t15656,\n\t0,\n\t15658,\n\t0,\n\t0,\n\t0,\n\t15664,\n\t0,\n\t0,\n\t15665,\n\t0,\n\t0,\n\t15668,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15669,\n\t0,\n\t0,\n\t15674,\n\t0,\n\t0,\n\t15675,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15677,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15679,\n\t0,\n\t0,\n\t15681,\n\t0,\n\t15686,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15687,\n\t0,\n\t15688,\n\t0,\n\t0,\n\t15690,\n\t0,\n\t0,\n\t0,\n\t15697,\n\t0,\n\t15699,\n\t15700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15701,\n\t0,\n\t15702,\n\t15703,\n\t0,\n\t15704,\n\t0,\n\t15705,\n\t0,\n\t15707,\n\t0,\n\t15709,\n\t0,\n\t15712,\n\t15716,\n\t0,\n\t15717,\n\t0,\n\t15718,\n\t15720,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15724,\n\t0,\n\t0,\n\t0,\n\t15725,\n\t0,\n\t15726,\n\t0,\n\t0,\n\t0,\n\t15740,\n\t0,\n\t15745,\n\t15746,\n\t0,\n\t0,\n\t15747,\n\t0,\n\t15748,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15749,\n\t0,\n\t0,\n\t0,\n\t15752,\n\t0,\n\t15753,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15759,\n\t0,\n\t0,\n\t0,\n\t15765,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15767,\n\t0,\n\t0,\n\t0,\n\t15771,\n\t0,\n\t0,\n\t15784,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15785,\n\t15790,\n\t15791,\n\t0,\n\t0,\n\t15792,\n\t0,\n\t0,\n\t0,\n\t15807,\n\t0,\n\t15811,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15818,\n\t0,\n\t0,\n\t0,\n\t15819,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15821,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15822,\n\t15824,\n\t0,\n\t0,\n\t15827,\n\t0,\n\t0,\n\t15829,\n\t15831,\n\t0,\n\t15832,\n\t0,\n\t0,\n\t15833,\n\t0,\n\t15835,\n\t15838,\n\t15839,\n\t15843,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15845,\n\t15851,\n\t15856,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15858,\n\t15860,\n\t0,\n\t15861,\n\t0,\n\t0,\n\t0,\n\t15864,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15865,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15866,\n\t0,\n\t15872,\n\t0,\n\t0,\n\t15876,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15877,\n\t15878,\n\t15883,\n\t15885,\n\t0,\n\t0,\n\t15888,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15889,\n\t15890,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15893,\n\t0,\n\t0,\n\t15894,\n\t0,\n\t0,\n\t0,\n\t15895,\n\t0,\n\t15896,\n\t15897,\n\t0,\n\t15898,\n\t15901,\n\t15902,\n\t0,\n\t15911,\n\t15915,\n\t0,\n\t15916,\n\t0,\n\t15924,\n\t15935,\n\t0,\n\t15937,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15958,\n\t0,\n\t0,\n\t0,\n\t15961,\n\t0,\n\t0,\n\t15966,\n\t0,\n\t15967,\n\t0,\n\t0,\n\t15977,\n\t0,\n\t0,\n\t15978,\n\t0,\n\t0,\n\t15981,\n\t15982,\n\t15983,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t15986,\n\t0,\n\t0,\n\t0,\n\t15990,\n\t0,\n\t15991,\n\t15995,\n\t15998,\n\t0,\n\t15999,\n\t0,\n\t16000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16008,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16009,\n\t16011,\n\t0,\n\t16013,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16014,\n\t0,\n\t0,\n\t16015,\n\t16023,\n\t16024,\n\t16025,\n\t0,\n\t0,\n\t16026,\n\t0,\n\t16030,\n\t0,\n\t16032,\n\t0,\n\t16033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16035,\n\t16036,\n\t16037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16041,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16043,\n\t16044,\n\t0,\n\t0,\n\t16047,\n\t0,\n\t0,\n\t0,\n\t16048,\n\t0,\n\t0,\n\t16049,\n\t16050,\n\t16052,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16056,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16058,\n\t16060,\n\t16061,\n\t0,\n\t0,\n\t16063,\n\t0,\n\t0,\n\t16064,\n\t0,\n\t0,\n\t0,\n\t16067,\n\t16068,\n\t0,\n\t0,\n\t16069,\n\t16078,\n\t0,\n\t0,\n\t0,\n\t16079,\n\t0,\n\t0,\n\t0,\n\t16080,\n\t0,\n\t16081,\n\t0,\n\t0,\n\t0,\n\t16088,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16089,\n\t16093,\n\t0,\n\t16097,\n\t0,\n\t16103,\n\t0,\n\t16104,\n\t16105,\n\t0,\n\t0,\n\t16256,\n\t0,\n\t0,\n\t16259,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16260,\n\t16261,\n\t0,\n\t0,\n\t16262,\n\t0,\n\t0,\n\t16263,\n\t0,\n\t16268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16269,\n\t0,\n\t0,\n\t16270,\n\t16273,\n\t0,\n\t16274,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16275,\n\t16276,\n\t16277,\n\t16280,\n\t0,\n\t0,\n\t0,\n\t16281,\n\t16284,\n\t0,\n\t0,\n\t0,\n\t16286,\n\t0,\n\t16289,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16290,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16291,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16293,\n\t16295,\n\t16297,\n\t0,\n\t16302,\n\t0,\n\t16304,\n\t0,\n\t16305,\n\t0,\n\t16306,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16307,\n\t16308,\n\t16312,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16313,\n\t16315,\n\t0,\n\t16318,\n\t0,\n\t0,\n\t0,\n\t16321,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16326,\n\t16333,\n\t16336,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16337,\n\t16340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16345,\n\t0,\n\t0,\n\t16346,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16347,\n\t0,\n\t0,\n\t16348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16349,\n\t0,\n\t0,\n\t0,\n\t16350,\n\t0,\n\t16357,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16359,\n\t16360,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16362,\n\t16363,\n\t16364,\n\t16365,\n\t0,\n\t0,\n\t16366,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16367,\n\t16368,\n\t0,\n\t16369,\n\t16374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16376,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16378,\n\t16379,\n\t0,\n\t16380,\n\t0,\n\t0,\n\t0,\n\t16381,\n\t16383,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16390,\n\t0,\n\t0,\n\t0,\n\t16399,\n\t0,\n\t16402,\n\t16404,\n\t16406,\n\t16407,\n\t0,\n\t0,\n\t0,\n\t16409,\n\t16411,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16412,\n\t0,\n\t16413,\n\t16415,\n\t16423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16424,\n\t0,\n\t0,\n\t0,\n\t16428,\n\t16434,\n\t16435,\n\t16449,\n\t0,\n\t16450,\n\t16451,\n\t0,\n\t0,\n\t0,\n\t16453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16454,\n\t0,\n\t0,\n\t16456,\n\t16458,\n\t0,\n\t0,\n\t16459,\n\t0,\n\t0,\n\t16460,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16462,\n\t0,\n\t16463,\n\t0,\n\t0,\n\t16466,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16479,\n\t0,\n\t0,\n\t16480,\n\t0,\n\t16481,\n\t16484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16485,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16489,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16491,\n\t0,\n\t0,\n\t16498,\n\t0,\n\t0,\n\t16503,\n\t0,\n\t16505,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16506,\n\t0,\n\t0,\n\t0,\n\t16508,\n\t16509,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16511,\n\t16513,\n\t0,\n\t0,\n\t0,\n\t16516,\n\t0,\n\t16517,\n\t0,\n\t16519,\n\t0,\n\t16529,\n\t0,\n\t0,\n\t16531,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16534,\n\t0,\n\t0,\n\t16541,\n\t16542,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16543,\n\t16547,\n\t16548,\n\t0,\n\t0,\n\t0,\n\t16551,\n\t0,\n\t16552,\n\t0,\n\t0,\n\t0,\n\t16553,\n\t0,\n\t0,\n\t16558,\n\t0,\n\t0,\n\t16562,\n\t16565,\n\t0,\n\t0,\n\t0,\n\t16570,\n\t0,\n\t0,\n\t0,\n\t16573,\n\t16585,\n\t0,\n\t0,\n\t0,\n\t16586,\n\t16587,\n\t16595,\n\t0,\n\t16596,\n\t0,\n\t16598,\n\t0,\n\t0,\n\t0,\n\t16600,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16601,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16603,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16604,\n\t16612,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16613,\n\t0,\n\t16618,\n\t0,\n\t0,\n\t0,\n\t16640,\n\t0,\n\t0,\n\t16641,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16646,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16651,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16653,\n\t16654,\n\t0,\n\t0,\n\t0,\n\t16655,\n\t0,\n\t0,\n\t16656,\n\t16667,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16671,\n\t0,\n\t16672,\n\t0,\n\t0,\n\t0,\n\t16673,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16676,\n\t0,\n\t16686,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16689,\n\t0,\n\t16690,\n\t0,\n\t16692,\n\t0,\n\t16693,\n\t0,\n\t16694,\n\t0,\n\t16696,\n\t0,\n\t0,\n\t0,\n\t16705,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16707,\n\t0,\n\t0,\n\t0,\n\t16709,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16711,\n\t0,\n\t16712,\n\t16713,\n\t0,\n\t0,\n\t0,\n\t16715,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16716,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16718,\n\t16724,\n\t0,\n\t0,\n\t16726,\n\t16727,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16728,\n\t0,\n\t16729,\n\t0,\n\t0,\n\t16730,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16731,\n\t0,\n\t0,\n\t0,\n\t16732,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16734,\n\t16738,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16743,\n\t0,\n\t0,\n\t16745,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16749,\n\t0,\n\t16752,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16756,\n\t0,\n\t0,\n\t16758,\n\t0,\n\t16759,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16762,\n\t0,\n\t16769,\n\t0,\n\t16770,\n\t0,\n\t16772,\n\t0,\n\t0,\n\t0,\n\t16777,\n\t16780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16781,\n\t0,\n\t0,\n\t16782,\n\t0,\n\t16784,\n\t0,\n\t0,\n\t16785,\n\t16787,\n\t16792,\n\t0,\n\t0,\n\t16794,\n\t0,\n\t0,\n\t0,\n\t16798,\n\t0,\n\t0,\n\t16809,\n\t0,\n\t0,\n\t16814,\n\t16816,\n\t16817,\n\t0,\n\t16819,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16820,\n\t0,\n\t0,\n\t16836,\n\t16839,\n\t0,\n\t0,\n\t16841,\n\t16851,\n\t16857,\n\t0,\n\t0,\n\t16858,\n\t16859,\n\t0,\n\t0,\n\t16860,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16862,\n\t0,\n\t16863,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16864,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16876,\n\t0,\n\t16881,\n\t16882,\n\t0,\n\t16885,\n\t16886,\n\t0,\n\t16887,\n\t0,\n\t0,\n\t0,\n\t16889,\n\t16891,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16894,\n\t16895,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16897,\n\t0,\n\t16898,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16913,\n\t0,\n\t0,\n\t16924,\n\t16925,\n\t16926,\n\t0,\n\t0,\n\t16927,\n\t0,\n\t0,\n\t0,\n\t16937,\n\t16938,\n\t0,\n\t0,\n\t0,\n\t16940,\n\t16941,\n\t0,\n\t0,\n\t0,\n\t16942,\n\t16945,\n\t0,\n\t16946,\n\t16949,\n\t16950,\n\t0,\n\t0,\n\t0,\n\t16952,\n\t16955,\n\t0,\n\t0,\n\t0,\n\t16965,\n\t0,\n\t16969,\n\t0,\n\t0,\n\t16975,\n\t0,\n\t0,\n\t16976,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16978,\n\t0,\n\t0,\n\t16981,\n\t0,\n\t16983,\n\t16989,\n\t0,\n\t0,\n\t0,\n\t0,\n\t16990,\n\t0,\n\t0,\n\t16991,\n\t0,\n\t0,\n\t0,\n\t16993,\n\t0,\n\t16994,\n\t16996,\n\t17000,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17002,\n\t17004,\n\t0,\n\t17006,\n\t0,\n\t0,\n\t17007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17008,\n\t17013,\n\t17014,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17021,\n\t0,\n\t17031,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17033,\n\t17036,\n\t0,\n\t17038,\n\t0,\n\t0,\n\t17039,\n\t0,\n\t17045,\n\t0,\n\t0,\n\t17046,\n\t17047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17048,\n\t0,\n\t17049,\n\t17050,\n\t0,\n\t17051,\n\t17053,\n\t0,\n\t17054,\n\t0,\n\t17055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17063,\n\t0,\n\t0,\n\t17064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17065,\n\t0,\n\t0,\n\t17068,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17073,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17074,\n\t0,\n\t17080,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17081,\n\t17083,\n\t17084,\n\t0,\n\t0,\n\t0,\n\t17085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17092,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17093,\n\t0,\n\t17095,\n\t17102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17103,\n\t0,\n\t0,\n\t17105,\n\t0,\n\t17107,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17114,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17115,\n\t17125,\n\t17127,\n\t0,\n\t0,\n\t17128,\n\t0,\n\t0,\n\t0,\n\t17129,\n\t17130,\n\t0,\n\t17131,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17132,\n\t17135,\n\t17145,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17146,\n\t0,\n\t17147,\n\t0,\n\t17148,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17149,\n\t17150,\n\t0,\n\t17151,\n\t17153,\n\t0,\n\t17155,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17163,\n\t17171,\n\t0,\n\t17174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17179,\n\t0,\n\t0,\n\t17182,\n\t17185,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17186,\n\t0,\n\t0,\n\t17188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17189,\n\t17191,\n\t0,\n\t17194,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17195,\n\t17196,\n\t17203,\n\t17204,\n\t0,\n\t0,\n\t17205,\n\t17217,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17218,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17219,\n\t0,\n\t17220,\n\t0,\n\t17221,\n\t0,\n\t0,\n\t17230,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17236,\n\t0,\n\t17238,\n\t17239,\n\t0,\n\t0,\n\t0,\n\t17241,\n\t17244,\n\t0,\n\t0,\n\t17245,\n\t0,\n\t17248,\n\t0,\n\t0,\n\t17251,\n\t0,\n\t17252,\n\t0,\n\t0,\n\t17264,\n\t0,\n\t17266,\n\t0,\n\t0,\n\t0,\n\t17268,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17271,\n\t17272,\n\t0,\n\t17273,\n\t0,\n\t17295,\n\t0,\n\t17302,\n\t0,\n\t17305,\n\t0,\n\t0,\n\t0,\n\t17306,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17309,\n\t0,\n\t17310,\n\t17313,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17314,\n\t17315,\n\t0,\n\t17317,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17318,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17320,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17334,\n\t0,\n\t17344,\n\t17348,\n\t0,\n\t0,\n\t0,\n\t17350,\n\t17351,\n\t0,\n\t0,\n\t17353,\n\t0,\n\t0,\n\t17354,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17355,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17356,\n\t17357,\n\t0,\n\t0,\n\t17359,\n\t0,\n\t0,\n\t0,\n\t17371,\n\t0,\n\t17372,\n\t0,\n\t0,\n\t0,\n\t17393,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17394,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17395,\n\t0,\n\t0,\n\t17399,\n\t0,\n\t0,\n\t0,\n\t17401,\n\t17417,\n\t0,\n\t17418,\n\t0,\n\t17419,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17422,\n\t17423,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17424,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17428,\n\t17429,\n\t17433,\n\t0,\n\t0,\n\t0,\n\t17437,\n\t0,\n\t0,\n\t17441,\n\t0,\n\t0,\n\t17442,\n\t0,\n\t0,\n\t17453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17454,\n\t17456,\n\t17462,\n\t0,\n\t0,\n\t17466,\n\t0,\n\t0,\n\t17468,\n\t0,\n\t0,\n\t17469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17470,\n\t0,\n\t17475,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17479,\n\t0,\n\t0,\n\t0,\n\t17483,\n\t17484,\n\t0,\n\t17485,\n\t0,\n\t17486,\n\t0,\n\t17491,\n\t17492,\n\t0,\n\t0,\n\t17493,\n\t0,\n\t17494,\n\t17495,\n\t0,\n\t0,\n\t0,\n\t17496,\n\t0,\n\t0,\n\t0,\n\t17497,\n\t0,\n\t0,\n\t0,\n\t17502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17503,\n\t0,\n\t17505,\n\t0,\n\t17507,\n\t0,\n\t0,\n\t0,\n\t17512,\n\t17513,\n\t17514,\n\t0,\n\t0,\n\t17515,\n\t0,\n\t0,\n\t0,\n\t17519,\n\t0,\n\t0,\n\t0,\n\t17522,\n\t0,\n\t0,\n\t17523,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17527,\n\t0,\n\t0,\n\t0,\n\t17528,\n\t0,\n\t0,\n\t0,\n\t17534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17536,\n\t0,\n\t0,\n\t0,\n\t17539,\n\t0,\n\t17540,\n\t17543,\n\t17549,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17556,\n\t0,\n\t0,\n\t17558,\n\t0,\n\t17559,\n\t0,\n\t0,\n\t17560,\n\t0,\n\t0,\n\t0,\n\t17563,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17564,\n\t0,\n\t0,\n\t17565,\n\t17566,\n\t0,\n\t17567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17569,\n\t17570,\n\t0,\n\t17575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17581,\n\t0,\n\t0,\n\t0,\n\t17582,\n\t17583,\n\t0,\n\t17586,\n\t0,\n\t0,\n\t17587,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17596,\n\t17597,\n\t0,\n\t0,\n\t17598,\n\t17600,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17601,\n\t0,\n\t0,\n\t0,\n\t17604,\n\t0,\n\t0,\n\t17605,\n\t0,\n\t0,\n\t17607,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17612,\n\t0,\n\t0,\n\t17618,\n\t0,\n\t17621,\n\t17622,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17623,\n\t0,\n\t0,\n\t17624,\n\t0,\n\t0,\n\t17630,\n\t0,\n\t0,\n\t17631,\n\t17633,\n\t17634,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17635,\n\t0,\n\t0,\n\t17636,\n\t0,\n\t0,\n\t17637,\n\t0,\n\t17638,\n\t0,\n\t17640,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17641,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17643,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17645,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17646,\n\t17662,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17663,\n\t17664,\n\t0,\n\t17665,\n\t17666,\n\t0,\n\t0,\n\t0,\n\t17669,\n\t17671,\n\t17673,\n\t0,\n\t17679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17684,\n\t0,\n\t0,\n\t0,\n\t17686,\n\t0,\n\t17714,\n\t0,\n\t0,\n\t17720,\n\t17722,\n\t17726,\n\t0,\n\t0,\n\t17728,\n\t0,\n\t0,\n\t17729,\n\t0,\n\t0,\n\t0,\n\t17732,\n\t0,\n\t17733,\n\t0,\n\t17734,\n\t0,\n\t0,\n\t0,\n\t17735,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17737,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17739,\n\t0,\n\t0,\n\t0,\n\t17741,\n\t17742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17743,\n\t17744,\n\t17745,\n\t0,\n\t0,\n\t0,\n\t17749,\n\t0,\n\t17750,\n\t17751,\n\t17752,\n\t17754,\n\t17761,\n\t17762,\n\t0,\n\t17763,\n\t0,\n\t17766,\n\t0,\n\t17772,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17776,\n\t0,\n\t0,\n\t17777,\n\t0,\n\t0,\n\t17778,\n\t17779,\n\t0,\n\t17782,\n\t17783,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17784,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17821,\n\t0,\n\t0,\n\t0,\n\t17822,\n\t0,\n\t0,\n\t0,\n\t17823,\n\t17825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17826,\n\t17831,\n\t17832,\n\t17833,\n\t0,\n\t0,\n\t17845,\n\t0,\n\t0,\n\t0,\n\t17846,\n\t0,\n\t0,\n\t0,\n\t17848,\n\t17850,\n\t17854,\n\t0,\n\t17855,\n\t0,\n\t0,\n\t17859,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17860,\n\t17861,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17870,\n\t17871,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17872,\n\t0,\n\t0,\n\t0,\n\t17879,\n\t0,\n\t0,\n\t0,\n\t17881,\n\t17883,\n\t0,\n\t17884,\n\t0,\n\t17885,\n\t0,\n\t0,\n\t17886,\n\t0,\n\t0,\n\t17887,\n\t17891,\n\t17953,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17954,\n\t0,\n\t0,\n\t17955,\n\t0,\n\t17968,\n\t0,\n\t0,\n\t17972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t17976,\n\t17978,\n\t0,\n\t0,\n\t17983,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18003,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18007,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18009,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18010,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18012,\n\t0,\n\t0,\n\t18014,\n\t0,\n\t0,\n\t0,\n\t18015,\n\t0,\n\t0,\n\t0,\n\t18016,\n\t0,\n\t18017,\n\t0,\n\t0,\n\t0,\n\t18030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18031,\n\t0,\n\t0,\n\t18036,\n\t18037,\n\t18038,\n\t0,\n\t0,\n\t18049,\n\t18056,\n\t0,\n\t18057,\n\t18058,\n\t0,\n\t18059,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18062,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18067,\n\t0,\n\t0,\n\t0,\n\t18068,\n\t0,\n\t0,\n\t18075,\n\t0,\n\t0,\n\t18078,\n\t18093,\n\t18094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18097,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18098,\n\t18100,\n\t0,\n\t0,\n\t0,\n\t18108,\n\t0,\n\t18111,\n\t0,\n\t0,\n\t18112,\n\t0,\n\t18113,\n\t0,\n\t0,\n\t18115,\n\t18116,\n\t0,\n\t18118,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18121,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18123,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18124,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18125,\n\t18126,\n\t0,\n\t18127,\n\t0,\n\t0,\n\t18128,\n\t18135,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18150,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18151,\n\t18152,\n\t0,\n\t0,\n\t18156,\n\t18164,\n\t0,\n\t18166,\n\t18171,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18172,\n\t18183,\n\t0,\n\t18184,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18185,\n\t0,\n\t18187,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18189,\n\t0,\n\t0,\n\t18190,\n\t0,\n\t0,\n\t18191,\n\t18192,\n\t0,\n\t0,\n\t18194,\n\t18195,\n\t18196,\n\t0,\n\t0,\n\t0,\n\t18197,\n\t0,\n\t18203,\n\t0,\n\t18204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18205,\n\t0,\n\t0,\n\t0,\n\t18207,\n\t18208,\n\t0,\n\t0,\n\t18214,\n\t0,\n\t0,\n\t0,\n\t18215,\n\t18216,\n\t0,\n\t0,\n\t0,\n\t18220,\n\t0,\n\t0,\n\t18222,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18223,\n\t0,\n\t18225,\n\t18231,\n\t0,\n\t18234,\n\t0,\n\t18235,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18240,\n\t0,\n\t0,\n\t18241,\n\t18242,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18243,\n\t18251,\n\t0,\n\t18253,\n\t0,\n\t18254,\n\t0,\n\t0,\n\t0,\n\t18266,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18269,\n\t18270,\n\t18271,\n\t18273,\n\t18281,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18282,\n\t0,\n\t18283,\n\t0,\n\t18284,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18285,\n\t0,\n\t18287,\n\t18289,\n\t0,\n\t0,\n\t18290,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18308,\n\t0,\n\t0,\n\t0,\n\t18310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18311,\n\t0,\n\t18312,\n\t18313,\n\t0,\n\t18315,\n\t0,\n\t0,\n\t18316,\n\t18320,\n\t0,\n\t18331,\n\t0,\n\t18332,\n\t0,\n\t18336,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18337,\n\t0,\n\t18340,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18341,\n\t0,\n\t18344,\n\t18345,\n\t0,\n\t18346,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18348,\n\t0,\n\t18351,\n\t0,\n\t0,\n\t18356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18357,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18367,\n\t0,\n\t0,\n\t0,\n\t18368,\n\t0,\n\t18369,\n\t0,\n\t18370,\n\t18371,\n\t0,\n\t0,\n\t0,\n\t18437,\n\t18444,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18445,\n\t18450,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18451,\n\t0,\n\t18452,\n\t0,\n\t0,\n\t0,\n\t18453,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18455,\n\t0,\n\t0,\n\t0,\n\t18456,\n\t0,\n\t18457,\n\t0,\n\t18460,\n\t0,\n\t0,\n\t18461,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18466,\n\t0,\n\t0,\n\t18467,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18473,\n\t0,\n\t0,\n\t0,\n\t18476,\n\t0,\n\t18477,\n\t0,\n\t0,\n\t0,\n\t18478,\n\t18479,\n\t18480,\n\t0,\n\t0,\n\t0,\n\t18485,\n\t0,\n\t0,\n\t0,\n\t18486,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18488,\n\t18490,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18491,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18495,\n\t0,\n\t0,\n\t18496,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18505,\n\t0,\n\t18521,\n\t0,\n\t18522,\n\t18523,\n\t0,\n\t0,\n\t0,\n\t18525,\n\t18526,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18532,\n\t18533,\n\t0,\n\t18534,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18535,\n\t18537,\n\t0,\n\t18538,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18540,\n\t18541,\n\t18542,\n\t18543,\n\t0,\n\t18546,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18553,\n\t18556,\n\t0,\n\t0,\n\t18558,\n\t0,\n\t0,\n\t18569,\n\t18571,\n\t0,\n\t0,\n\t0,\n\t18572,\n\t0,\n\t18574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18586,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18588,\n\t0,\n\t0,\n\t18589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18590,\n\t0,\n\t18592,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18594,\n\t0,\n\t0,\n\t0,\n\t18596,\n\t0,\n\t0,\n\t18597,\n\t18598,\n\t0,\n\t0,\n\t18601,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18602,\n\t0,\n\t0,\n\t0,\n\t18603,\n\t18604,\n\t0,\n\t18605,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18608,\n\t0,\n\t0,\n\t18611,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18612,\n\t0,\n\t18616,\n\t0,\n\t0,\n\t18617,\n\t18619,\n\t0,\n\t0,\n\t0,\n\t18628,\n\t0,\n\t0,\n\t0,\n\t18629,\n\t0,\n\t0,\n\t18630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18631,\n\t0,\n\t18632,\n\t0,\n\t0,\n\t18635,\n\t18637,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18641,\n\t18643,\n\t18648,\n\t0,\n\t18652,\n\t0,\n\t0,\n\t18653,\n\t0,\n\t18655,\n\t18656,\n\t0,\n\t0,\n\t0,\n\t18657,\n\t0,\n\t0,\n\t18666,\n\t18674,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18677,\n\t18684,\n\t18685,\n\t0,\n\t0,\n\t18686,\n\t0,\n\t0,\n\t18690,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18695,\n\t18696,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18697,\n\t0,\n\t0,\n\t18700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18702,\n\t0,\n\t18708,\n\t0,\n\t0,\n\t18709,\n\t0,\n\t18710,\n\t0,\n\t0,\n\t18711,\n\t0,\n\t18714,\n\t0,\n\t0,\n\t18718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18719,\n\t0,\n\t0,\n\t18722,\n\t0,\n\t18726,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18731,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18739,\n\t18741,\n\t0,\n\t0,\n\t18742,\n\t0,\n\t18743,\n\t18744,\n\t18746,\n\t18748,\n\t0,\n\t18752,\n\t18753,\n\t0,\n\t0,\n\t18754,\n\t18763,\n\t0,\n\t18765,\n\t0,\n\t0,\n\t0,\n\t18766,\n\t0,\n\t0,\n\t0,\n\t18769,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18773,\n\t18778,\n\t18779,\n\t18781,\n\t0,\n\t0,\n\t18784,\n\t18787,\n\t0,\n\t18788,\n\t0,\n\t18793,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18795,\n\t0,\n\t0,\n\t18800,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18801,\n\t18804,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18806,\n\t0,\n\t0,\n\t0,\n\t18811,\n\t18815,\n\t18816,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18825,\n\t0,\n\t0,\n\t18827,\n\t18829,\n\t0,\n\t0,\n\t18830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18831,\n\t0,\n\t0,\n\t18832,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18833,\n\t0,\n\t18840,\n\t0,\n\t18841,\n\t0,\n\t18842,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18843,\n\t0,\n\t18844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18845,\n\t18846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18848,\n\t0,\n\t0,\n\t0,\n\t18853,\n\t18860,\n\t0,\n\t0,\n\t18862,\n\t18866,\n\t0,\n\t0,\n\t18867,\n\t18869,\n\t0,\n\t0,\n\t18874,\n\t18881,\n\t18891,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18895,\n\t0,\n\t18896,\n\t0,\n\t0,\n\t0,\n\t18900,\n\t0,\n\t0,\n\t0,\n\t18901,\n\t0,\n\t18902,\n\t18915,\n\t18916,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18920,\n\t0,\n\t0,\n\t0,\n\t18921,\n\t18929,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18930,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18932,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18934,\n\t18942,\n\t0,\n\t0,\n\t0,\n\t18951,\n\t18957,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18959,\n\t18960,\n\t0,\n\t0,\n\t18961,\n\t0,\n\t0,\n\t18962,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18963,\n\t18964,\n\t0,\n\t0,\n\t0,\n\t18965,\n\t0,\n\t18967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18968,\n\t0,\n\t18969,\n\t0,\n\t18970,\n\t18973,\n\t18976,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18977,\n\t0,\n\t0,\n\t0,\n\t18981,\n\t0,\n\t0,\n\t0,\n\t18990,\n\t0,\n\t18998,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t18999,\n\t19003,\n\t0,\n\t0,\n\t19005,\n\t0,\n\t0,\n\t0,\n\t19006,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19008,\n\t19011,\n\t0,\n\t0,\n\t19018,\n\t0,\n\t0,\n\t19019,\n\t0,\n\t19024,\n\t0,\n\t19031,\n\t19032,\n\t0,\n\t19039,\n\t0,\n\t19041,\n\t19050,\n\t0,\n\t0,\n\t0,\n\t19051,\n\t19055,\n\t19056,\n\t0,\n\t19059,\n\t19063,\n\t19064,\n\t0,\n\t0,\n\t19088,\n\t0,\n\t0,\n\t0,\n\t19093,\n\t19094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19095,\n\t0,\n\t19096,\n\t0,\n\t0,\n\t0,\n\t19097,\n\t0,\n\t0,\n\t19098,\n\t0,\n\t19099,\n\t19100,\n\t0,\n\t0,\n\t19103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19111,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19112,\n\t0,\n\t0,\n\t0,\n\t19116,\n\t19117,\n\t0,\n\t19121,\n\t19122,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19123,\n\t19124,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19125,\n\t19126,\n\t0,\n\t19128,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19129,\n\t19130,\n\t19131,\n\t19132,\n\t0,\n\t0,\n\t19146,\n\t0,\n\t0,\n\t19147,\n\t19156,\n\t19158,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19182,\n\t19185,\n\t0,\n\t0,\n\t19187,\n\t0,\n\t0,\n\t0,\n\t19193,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19194,\n\t0,\n\t19197,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19203,\n\t0,\n\t19205,\n\t19210,\n\t0,\n\t0,\n\t0,\n\t19213,\n\t0,\n\t19218,\n\t0,\n\t0,\n\t0,\n\t19223,\n\t19229,\n\t0,\n\t0,\n\t19230,\n\t0,\n\t0,\n\t19231,\n\t19232,\n\t19233,\n\t19239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19240,\n\t0,\n\t19248,\n\t19249,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19254,\n\t0,\n\t19256,\n\t19258,\n\t19259,\n\t0,\n\t0,\n\t19261,\n\t0,\n\t19266,\n\t0,\n\t0,\n\t0,\n\t19272,\n\t0,\n\t19278,\n\t19281,\n\t19282,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19283,\n\t0,\n\t0,\n\t19284,\n\t0,\n\t0,\n\t19285,\n\t19287,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19288,\n\t19291,\n\t0,\n\t19292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19297,\n\t0,\n\t19298,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19302,\n\t19303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19304,\n\t19305,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19314,\n\t0,\n\t0,\n\t19315,\n\t0,\n\t0,\n\t19321,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19322,\n\t0,\n\t19333,\n\t0,\n\t19334,\n\t19335,\n\t0,\n\t19336,\n\t19337,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19346,\n\t0,\n\t0,\n\t19353,\n\t0,\n\t19354,\n\t19362,\n\t0,\n\t19366,\n\t19367,\n\t0,\n\t0,\n\t19369,\n\t0,\n\t19375,\n\t0,\n\t19377,\n\t19380,\n\t19388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19389,\n\t19390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19392,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19402,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19412,\n\t0,\n\t0,\n\t19413,\n\t19422,\n\t0,\n\t19424,\n\t0,\n\t0,\n\t0,\n\t19425,\n\t0,\n\t0,\n\t0,\n\t19428,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19431,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19432,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19448,\n\t19459,\n\t0,\n\t0,\n\t19461,\n\t0,\n\t19462,\n\t19463,\n\t0,\n\t19467,\n\t19474,\n\t19482,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19501,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19502,\n\t19504,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19505,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19506,\n\t19507,\n\t0,\n\t0,\n\t0,\n\t19508,\n\t0,\n\t0,\n\t19511,\n\t0,\n\t0,\n\t19514,\n\t0,\n\t19515,\n\t0,\n\t19516,\n\t0,\n\t19518,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19530,\n\t0,\n\t19537,\n\t19538,\n\t0,\n\t19543,\n\t19546,\n\t0,\n\t19547,\n\t19551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19552,\n\t19553,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19555,\n\t0,\n\t0,\n\t19556,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19560,\n\t19561,\n\t0,\n\t0,\n\t19562,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19565,\n\t19567,\n\t0,\n\t19568,\n\t0,\n\t0,\n\t0,\n\t19569,\n\t19570,\n\t0,\n\t19578,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19580,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19581,\n\t19584,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19585,\n\t19586,\n\t0,\n\t0,\n\t0,\n\t19587,\n\t19588,\n\t0,\n\t19589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19592,\n\t19593,\n\t19599,\n\t0,\n\t19600,\n\t0,\n\t0,\n\t19604,\n\t0,\n\t0,\n\t19605,\n\t0,\n\t19606,\n\t19608,\n\t19610,\n\t0,\n\t19613,\n\t19614,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19616,\n\t19617,\n\t0,\n\t0,\n\t19618,\n\t0,\n\t0,\n\t19619,\n\t0,\n\t0,\n\t0,\n\t19620,\n\t19621,\n\t19631,\n\t0,\n\t0,\n\t19632,\n\t19634,\n\t19636,\n\t0,\n\t19643,\n\t0,\n\t0,\n\t19644,\n\t19658,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19659,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19675,\n\t19677,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19679,\n\t0,\n\t19683,\n\t0,\n\t19684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19687,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19688,\n\t19689,\n\t19692,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19695,\n\t19697,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19698,\n\t19699,\n\t0,\n\t0,\n\t19700,\n\t0,\n\t19702,\n\t0,\n\t0,\n\t19703,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19704,\n\t19708,\n\t0,\n\t19710,\n\t0,\n\t19713,\n\t0,\n\t0,\n\t0,\n\t19715,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19718,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19720,\n\t0,\n\t19722,\n\t0,\n\t0,\n\t19725,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19730,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19731,\n\t0,\n\t19734,\n\t19735,\n\t19739,\n\t0,\n\t0,\n\t19740,\n\t0,\n\t19741,\n\t0,\n\t0,\n\t0,\n\t19746,\n\t0,\n\t0,\n\t19747,\n\t0,\n\t19771,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19772,\n\t19775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19778,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19779,\n\t0,\n\t0,\n\t19780,\n\t19790,\n\t0,\n\t19791,\n\t0,\n\t0,\n\t19792,\n\t0,\n\t0,\n\t0,\n\t19793,\n\t0,\n\t0,\n\t19796,\n\t19797,\n\t0,\n\t0,\n\t0,\n\t19799,\n\t0,\n\t0,\n\t0,\n\t19801,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19803,\n\t0,\n\t19804,\n\t0,\n\t19805,\n\t0,\n\t0,\n\t19807,\n\t0,\n\t0,\n\t0,\n\t19808,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19809,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19816,\n\t0,\n\t19821,\n\t0,\n\t19822,\n\t19830,\n\t19831,\n\t0,\n\t0,\n\t0,\n\t19833,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19838,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19839,\n\t0,\n\t0,\n\t19843,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19847,\n\t0,\n\t0,\n\t19848,\n\t0,\n\t19849,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19851,\n\t0,\n\t0,\n\t0,\n\t19854,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19864,\n\t0,\n\t19865,\n\t0,\n\t19866,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19868,\n\t0,\n\t0,\n\t19870,\n\t0,\n\t0,\n\t19871,\n\t0,\n\t0,\n\t19872,\n\t19873,\n\t19875,\n\t0,\n\t19880,\n\t19882,\n\t19884,\n\t0,\n\t0,\n\t19885,\n\t19886,\n\t19888,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19890,\n\t19892,\n\t19893,\n\t0,\n\t0,\n\t19894,\n\t0,\n\t0,\n\t0,\n\t19895,\n\t0,\n\t19896,\n\t19902,\n\t0,\n\t0,\n\t19903,\n\t0,\n\t0,\n\t19905,\n\t0,\n\t0,\n\t0,\n\t19906,\n\t0,\n\t19908,\n\t0,\n\t19909,\n\t19911,\n\t0,\n\t0,\n\t0,\n\t19913,\n\t19920,\n\t0,\n\t19938,\n\t19939,\n\t19940,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19942,\n\t0,\n\t19943,\n\t0,\n\t19945,\n\t0,\n\t0,\n\t0,\n\t19951,\n\t19952,\n\t19954,\n\t19960,\n\t0,\n\t19965,\n\t0,\n\t19971,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t19975,\n\t0,\n\t19976,\n\t0,\n\t19990,\n\t0,\n\t0,\n\t19991,\n\t0,\n\t19993,\n\t0,\n\t19995,\n\t0,\n\t0,\n\t0,\n\t19998,\n\t19999,\n\t20001,\n\t0,\n\t20003,\n\t20005,\n\t0,\n\t20011,\n\t20012,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20014,\n\t0,\n\t20020,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20023,\n\t20024,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20025,\n\t0,\n\t0,\n\t20027,\n\t0,\n\t0,\n\t20029,\n\t0,\n\t0,\n\t20032,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20044,\n\t20045,\n\t0,\n\t20048,\n\t20049,\n\t0,\n\t0,\n\t20050,\n\t0,\n\t20052,\n\t0,\n\t0,\n\t20054,\n\t20057,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20059,\n\t0,\n\t0,\n\t20061,\n\t0,\n\t20062,\n\t0,\n\t20064,\n\t0,\n\t0,\n\t20066,\n\t0,\n\t0,\n\t20067,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20069,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20070,\n\t20071,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20072,\n\t0,\n\t0,\n\t20073,\n\t20074,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20075,\n\t0,\n\t20078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20080,\n\t0,\n\t20081,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20095,\n\t0,\n\t20098,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20107,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20112,\n\t0,\n\t0,\n\t0,\n\t20113,\n\t20114,\n\t0,\n\t0,\n\t0,\n\t20115,\n\t20123,\n\t20124,\n\t0,\n\t0,\n\t0,\n\t20131,\n\t20133,\n\t20134,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20136,\n\t0,\n\t0,\n\t20137,\n\t20138,\n\t20150,\n\t0,\n\t20152,\n\t0,\n\t0,\n\t0,\n\t20153,\n\t0,\n\t0,\n\t20154,\n\t0,\n\t0,\n\t0,\n\t20158,\n\t0,\n\t20163,\n\t0,\n\t0,\n\t20164,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20166,\n\t0,\n\t20168,\n\t0,\n\t20170,\n\t0,\n\t20175,\n\t0,\n\t0,\n\t20178,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20223,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20224,\n\t0,\n\t20226,\n\t0,\n\t0,\n\t20230,\n\t0,\n\t20231,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20232,\n\t0,\n\t0,\n\t20233,\n\t20234,\n\t0,\n\t20244,\n\t0,\n\t20247,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20249,\n\t0,\n\t0,\n\t0,\n\t20250,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20251,\n\t0,\n\t20253,\n\t0,\n\t20254,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20256,\n\t0,\n\t0,\n\t20264,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20266,\n\t0,\n\t0,\n\t0,\n\t20278,\n\t0,\n\t0,\n\t20279,\n\t20282,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20283,\n\t0,\n\t20284,\n\t0,\n\t20285,\n\t0,\n\t20287,\n\t20290,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20293,\n\t20297,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20299,\n\t0,\n\t20300,\n\t20303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20307,\n\t0,\n\t0,\n\t20308,\n\t0,\n\t20309,\n\t0,\n\t20310,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20312,\n\t0,\n\t0,\n\t0,\n\t20314,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20315,\n\t20316,\n\t0,\n\t20322,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20339,\n\t0,\n\t0,\n\t0,\n\t20342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20352,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20362,\n\t0,\n\t0,\n\t20365,\n\t0,\n\t20375,\n\t20377,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20378,\n\t20379,\n\t0,\n\t20380,\n\t0,\n\t0,\n\t20381,\n\t0,\n\t20382,\n\t0,\n\t20383,\n\t0,\n\t20388,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20390,\n\t20392,\n\t20393,\n\t0,\n\t0,\n\t20395,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20396,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20398,\n\t20415,\n\t0,\n\t0,\n\t0,\n\t20417,\n\t0,\n\t0,\n\t20420,\n\t0,\n\t0,\n\t20426,\n\t20428,\n\t0,\n\t20431,\n\t0,\n\t0,\n\t20432,\n\t0,\n\t20433,\n\t20434,\n\t20435,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20440,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20442,\n\t0,\n\t20443,\n\t0,\n\t20446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20448,\n\t0,\n\t20451,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20452,\n\t20453,\n\t0,\n\t0,\n\t20454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20457,\n\t0,\n\t20458,\n\t0,\n\t0,\n\t0,\n\t20465,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20469,\n\t0,\n\t0,\n\t0,\n\t20473,\n\t0,\n\t20476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20477,\n\t0,\n\t0,\n\t20485,\n\t0,\n\t0,\n\t20486,\n\t0,\n\t0,\n\t20487,\n\t0,\n\t20496,\n\t0,\n\t20497,\n\t0,\n\t0,\n\t20498,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20499,\n\t20500,\n\t0,\n\t20501,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20520,\n\t20527,\n\t0,\n\t20529,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20539,\n\t0,\n\t0,\n\t20540,\n\t0,\n\t0,\n\t0,\n\t20543,\n\t0,\n\t0,\n\t0,\n\t20546,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20548,\n\t0,\n\t0,\n\t20563,\n\t0,\n\t0,\n\t20564,\n\t0,\n\t20566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20590,\n\t0,\n\t0,\n\t20593,\n\t20594,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20595,\n\t0,\n\t20597,\n\t20598,\n\t0,\n\t0,\n\t0,\n\t20618,\n\t20620,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20621,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20627,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20628,\n\t0,\n\t0,\n\t0,\n\t20629,\n\t0,\n\t20630,\n\t0,\n\t0,\n\t20639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20707,\n\t0,\n\t0,\n\t20709,\n\t0,\n\t0,\n\t0,\n\t20713,\n\t20714,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20724,\n\t20725,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20726,\n\t20728,\n\t20729,\n\t0,\n\t20733,\n\t0,\n\t20734,\n\t0,\n\t20735,\n\t20736,\n\t0,\n\t20737,\n\t0,\n\t0,\n\t20744,\n\t0,\n\t20745,\n\t0,\n\t20748,\n\t0,\n\t0,\n\t20749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20754,\n\t0,\n\t0,\n\t0,\n\t20761,\n\t0,\n\t0,\n\t20763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20766,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20767,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20768,\n\t0,\n\t20769,\n\t20777,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20785,\n\t0,\n\t0,\n\t0,\n\t20786,\n\t20795,\n\t20801,\n\t0,\n\t20802,\n\t0,\n\t20807,\n\t0,\n\t0,\n\t20808,\n\t0,\n\t0,\n\t20810,\n\t0,\n\t0,\n\t20811,\n\t0,\n\t20812,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20813,\n\t0,\n\t0,\n\t20818,\n\t20820,\n\t20821,\n\t0,\n\t0,\n\t0,\n\t20822,\n\t0,\n\t20823,\n\t0,\n\t0,\n\t0,\n\t20826,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20829,\n\t20830,\n\t20831,\n\t0,\n\t20832,\n\t20836,\n\t0,\n\t0,\n\t20839,\n\t0,\n\t0,\n\t20840,\n\t20842,\n\t0,\n\t20843,\n\t0,\n\t20844,\n\t0,\n\t20854,\n\t0,\n\t0,\n\t0,\n\t20855,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20856,\n\t0,\n\t0,\n\t0,\n\t20869,\n\t0,\n\t0,\n\t20871,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20873,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20876,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20880,\n\t0,\n\t0,\n\t20882,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20883,\n\t20884,\n\t0,\n\t0,\n\t20890,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20891,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20905,\n\t0,\n\t20906,\n\t20910,\n\t0,\n\t0,\n\t20912,\n\t20915,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20916,\n\t0,\n\t20917,\n\t0,\n\t20919,\n\t20920,\n\t20922,\n\t0,\n\t20927,\n\t0,\n\t20928,\n\t20929,\n\t20930,\n\t0,\n\t0,\n\t20935,\n\t0,\n\t0,\n\t20939,\n\t0,\n\t0,\n\t20941,\n\t0,\n\t0,\n\t0,\n\t20943,\n\t0,\n\t0,\n\t0,\n\t20946,\n\t20947,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20950,\n\t0,\n\t20954,\n\t0,\n\t0,\n\t20955,\n\t20964,\n\t0,\n\t0,\n\t20967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20973,\n\t20975,\n\t0,\n\t0,\n\t0,\n\t20984,\n\t0,\n\t20987,\n\t20988,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t20989,\n\t0,\n\t0,\n\t0,\n\t20995,\n\t0,\n\t20998,\n\t0,\n\t20999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21000,\n\t21001,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21008,\n\t0,\n\t21010,\n\t0,\n\t21016,\n\t0,\n\t0,\n\t0,\n\t21017,\n\t21018,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21021,\n\t21026,\n\t21027,\n\t21028,\n\t0,\n\t0,\n\t21029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21031,\n\t21032,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21037,\n\t0,\n\t0,\n\t21038,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21039,\n\t0,\n\t21041,\n\t0,\n\t21046,\n\t21047,\n\t0,\n\t0,\n\t0,\n\t21049,\n\t21053,\n\t0,\n\t0,\n\t21057,\n\t21064,\n\t21065,\n\t0,\n\t0,\n\t21066,\n\t21067,\n\t0,\n\t0,\n\t0,\n\t21069,\n\t0,\n\t0,\n\t0,\n\t21071,\n\t21072,\n\t0,\n\t0,\n\t21073,\n\t0,\n\t21074,\n\t0,\n\t0,\n\t21078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21079,\n\t0,\n\t0,\n\t21080,\n\t21081,\n\t0,\n\t0,\n\t21086,\n\t21087,\n\t0,\n\t21089,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21091,\n\t0,\n\t21093,\n\t0,\n\t21094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21096,\n\t0,\n\t21098,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21099,\n\t0,\n\t0,\n\t21100,\n\t21101,\n\t21102,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21103,\n\t0,\n\t21104,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21105,\n\t21108,\n\t21109,\n\t0,\n\t0,\n\t21112,\n\t21113,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21115,\n\t21122,\n\t21123,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21125,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21129,\n\t21131,\n\t0,\n\t0,\n\t21134,\n\t0,\n\t0,\n\t0,\n\t21137,\n\t21142,\n\t0,\n\t21143,\n\t0,\n\t0,\n\t21144,\n\t0,\n\t21145,\n\t21146,\n\t0,\n\t21152,\n\t21154,\n\t21155,\n\t21156,\n\t0,\n\t0,\n\t0,\n\t21160,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21161,\n\t0,\n\t21164,\n\t0,\n\t21166,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21170,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21171,\n\t0,\n\t0,\n\t21172,\n\t0,\n\t21174,\n\t0,\n\t21175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21176,\n\t21179,\n\t21188,\n\t0,\n\t0,\n\t0,\n\t21189,\n\t0,\n\t0,\n\t21190,\n\t0,\n\t0,\n\t0,\n\t21192,\n\t0,\n\t0,\n\t21193,\n\t0,\n\t0,\n\t0,\n\t21198,\n\t0,\n\t21212,\n\t0,\n\t0,\n\t21213,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21215,\n\t21216,\n\t0,\n\t0,\n\t21223,\n\t21225,\n\t0,\n\t21226,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21227,\n\t21228,\n\t0,\n\t0,\n\t21229,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21230,\n\t21236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21237,\n\t0,\n\t0,\n\t21238,\n\t21239,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21256,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21257,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21259,\n\t0,\n\t0,\n\t0,\n\t21263,\n\t0,\n\t21272,\n\t0,\n\t21274,\n\t0,\n\t21282,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21283,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21294,\n\t0,\n\t0,\n\t21297,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21298,\n\t0,\n\t0,\n\t0,\n\t21299,\n\t0,\n\t21300,\n\t21302,\n\t0,\n\t21316,\n\t0,\n\t21318,\n\t21322,\n\t21323,\n\t0,\n\t21324,\n\t0,\n\t21326,\n\t0,\n\t0,\n\t0,\n\t21327,\n\t21328,\n\t0,\n\t0,\n\t0,\n\t21352,\n\t0,\n\t0,\n\t21354,\n\t21361,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21362,\n\t0,\n\t0,\n\t0,\n\t21363,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21366,\n\t0,\n\t0,\n\t21367,\n\t21372,\n\t21374,\n\t0,\n\t0,\n\t0,\n\t21375,\n\t21377,\n\t0,\n\t21378,\n\t0,\n\t0,\n\t0,\n\t21380,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21382,\n\t0,\n\t21383,\n\t0,\n\t0,\n\t21384,\n\t0,\n\t0,\n\t21385,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21389,\n\t21390,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21397,\n\t21398,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21399,\n\t0,\n\t21400,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21402,\n\t0,\n\t0,\n\t0,\n\t21403,\n\t21404,\n\t0,\n\t21405,\n\t21406,\n\t0,\n\t0,\n\t0,\n\t21407,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21408,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21409,\n\t0,\n\t21421,\n\t0,\n\t21422,\n\t0,\n\t0,\n\t0,\n\t21425,\n\t21428,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21429,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21433,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21434,\n\t0,\n\t21443,\n\t0,\n\t21444,\n\t21449,\n\t0,\n\t21452,\n\t0,\n\t21453,\n\t21454,\n\t0,\n\t0,\n\t0,\n\t21457,\n\t0,\n\t0,\n\t21458,\n\t0,\n\t0,\n\t0,\n\t21460,\n\t21461,\n\t0,\n\t0,\n\t21464,\n\t0,\n\t0,\n\t0,\n\t21473,\n\t21478,\n\t0,\n\t0,\n\t21479,\n\t0,\n\t0,\n\t21481,\n\t21483,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21484,\n\t0,\n\t0,\n\t21485,\n\t21486,\n\t0,\n\t0,\n\t21488,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21523,\n\t0,\n\t0,\n\t21525,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21526,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21529,\n\t21530,\n\t0,\n\t0,\n\t21531,\n\t0,\n\t0,\n\t21533,\n\t0,\n\t0,\n\t21539,\n\t21564,\n\t0,\n\t21567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21577,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21591,\n\t0,\n\t0,\n\t21604,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21605,\n\t0,\n\t21606,\n\t0,\n\t0,\n\t21617,\n\t21618,\n\t21619,\n\t21620,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21623,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21631,\n\t0,\n\t21635,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21639,\n\t21646,\n\t21653,\n\t21662,\n\t0,\n\t0,\n\t21663,\n\t21664,\n\t0,\n\t21666,\n\t0,\n\t0,\n\t21667,\n\t0,\n\t21670,\n\t21672,\n\t21673,\n\t0,\n\t21674,\n\t21683,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21684,\n\t0,\n\t21694,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21695,\n\t21700,\n\t0,\n\t21703,\n\t0,\n\t21704,\n\t0,\n\t0,\n\t21709,\n\t0,\n\t0,\n\t0,\n\t21710,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21711,\n\t0,\n\t0,\n\t0,\n\t21712,\n\t0,\n\t21717,\n\t0,\n\t21730,\n\t0,\n\t0,\n\t0,\n\t21731,\n\t21733,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21737,\n\t21741,\n\t21742,\n\t0,\n\t21747,\n\t0,\n\t0,\n\t0,\n\t21749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21752,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21753,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21755,\n\t21756,\n\t0,\n\t21757,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21760,\n\t0,\n\t0,\n\t21763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21764,\n\t0,\n\t0,\n\t21766,\n\t0,\n\t0,\n\t21767,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21773,\n\t0,\n\t21774,\n\t0,\n\t0,\n\t21775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21776,\n\t0,\n\t0,\n\t21777,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21780,\n\t21787,\n\t21788,\n\t21791,\n\t0,\n\t0,\n\t0,\n\t21797,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21805,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21806,\n\t0,\n\t21807,\n\t21809,\n\t0,\n\t21810,\n\t21811,\n\t0,\n\t21817,\n\t21819,\n\t21820,\n\t0,\n\t21823,\n\t0,\n\t21824,\n\t0,\n\t0,\n\t21825,\n\t0,\n\t0,\n\t21826,\n\t21832,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21833,\n\t21848,\n\t21849,\n\t0,\n\t0,\n\t21867,\n\t21870,\n\t21871,\n\t21873,\n\t0,\n\t0,\n\t0,\n\t21874,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21875,\n\t0,\n\t21878,\n\t0,\n\t0,\n\t0,\n\t21879,\n\t0,\n\t21881,\n\t21886,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21887,\n\t0,\n\t0,\n\t21888,\n\t21894,\n\t21895,\n\t21897,\n\t0,\n\t21901,\n\t0,\n\t21904,\n\t0,\n\t0,\n\t21906,\n\t0,\n\t0,\n\t0,\n\t21909,\n\t21910,\n\t21911,\n\t0,\n\t0,\n\t21912,\n\t0,\n\t0,\n\t21913,\n\t21914,\n\t21915,\n\t0,\n\t21919,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21921,\n\t0,\n\t0,\n\t21922,\n\t21933,\n\t21939,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21944,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21945,\n\t0,\n\t21947,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21949,\n\t0,\n\t0,\n\t0,\n\t21950,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21951,\n\t0,\n\t21952,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21954,\n\t21957,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21958,\n\t0,\n\t21959,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21962,\n\t21963,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21964,\n\t21965,\n\t0,\n\t0,\n\t21969,\n\t21970,\n\t0,\n\t0,\n\t0,\n\t21974,\n\t0,\n\t0,\n\t21980,\n\t21981,\n\t0,\n\t21982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t21985,\n\t0,\n\t21988,\n\t0,\n\t21992,\n\t0,\n\t21999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22001,\n\t0,\n\t22002,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22003,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22004,\n\t0,\n\t0,\n\t0,\n\t22008,\n\t0,\n\t22009,\n\t22015,\n\t0,\n\t0,\n\t22016,\n\t0,\n\t0,\n\t0,\n\t22017,\n\t22019,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22020,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22021,\n\t22037,\n\t0,\n\t22039,\n\t0,\n\t0,\n\t0,\n\t22040,\n\t0,\n\t0,\n\t0,\n\t22048,\n\t22049,\n\t0,\n\t0,\n\t22053,\n\t22055,\n\t22056,\n\t22059,\n\t0,\n\t0,\n\t22060,\n\t22061,\n\t0,\n\t0,\n\t22064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22066,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22073,\n\t0,\n\t0,\n\t0,\n\t22074,\n\t22075,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22076,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22077,\n\t22084,\n\t22099,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22104,\n\t0,\n\t0,\n\t22107,\n\t0,\n\t22108,\n\t0,\n\t22109,\n\t0,\n\t22110,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22111,\n\t22119,\n\t0,\n\t22120,\n\t22122,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22125,\n\t0,\n\t0,\n\t0,\n\t22128,\n\t22129,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22141,\n\t0,\n\t0,\n\t0,\n\t22142,\n\t0,\n\t0,\n\t22144,\n\t22146,\n\t0,\n\t22148,\n\t22149,\n\t22151,\n\t22154,\n\t0,\n\t0,\n\t0,\n\t22162,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22164,\n\t22177,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22179,\n\t0,\n\t22182,\n\t22183,\n\t0,\n\t0,\n\t22184,\n\t22188,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22190,\n\t0,\n\t22194,\n\t22201,\n\t0,\n\t0,\n\t22208,\n\t0,\n\t22209,\n\t0,\n\t22212,\n\t0,\n\t0,\n\t22215,\n\t0,\n\t22223,\n\t22231,\n\t0,\n\t0,\n\t22232,\n\t0,\n\t22234,\n\t0,\n\t0,\n\t22235,\n\t22236,\n\t0,\n\t22237,\n\t0,\n\t22240,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22241,\n\t0,\n\t0,\n\t0,\n\t22242,\n\t22246,\n\t22247,\n\t0,\n\t0,\n\t0,\n\t22259,\n\t22268,\n\t0,\n\t22269,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22270,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22271,\n\t0,\n\t22272,\n\t0,\n\t22277,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22278,\n\t22280,\n\t22283,\n\t22286,\n\t0,\n\t0,\n\t22287,\n\t22289,\n\t0,\n\t0,\n\t22290,\n\t0,\n\t22293,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22295,\n\t0,\n\t22301,\n\t22302,\n\t0,\n\t0,\n\t0,\n\t22305,\n\t0,\n\t22308,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22315,\n\t0,\n\t0,\n\t0,\n\t22317,\n\t0,\n\t22334,\n\t0,\n\t0,\n\t0,\n\t22335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22336,\n\t0,\n\t22338,\n\t22344,\n\t0,\n\t22347,\n\t22349,\n\t0,\n\t22350,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22357,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22358,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22359,\n\t22360,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22361,\n\t22366,\n\t0,\n\t0,\n\t22369,\n\t0,\n\t22370,\n\t22373,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22375,\n\t0,\n\t22377,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22378,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22382,\n\t0,\n\t22383,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22391,\n\t0,\n\t0,\n\t22392,\n\t22395,\n\t22396,\n\t22402,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22405,\n\t0,\n\t0,\n\t22406,\n\t0,\n\t0,\n\t22408,\n\t0,\n\t0,\n\t22409,\n\t22410,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22424,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22426,\n\t0,\n\t0,\n\t0,\n\t22427,\n\t0,\n\t22428,\n\t0,\n\t22432,\n\t0,\n\t22435,\n\t22442,\n\t22443,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22444,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22446,\n\t0,\n\t22454,\n\t0,\n\t22455,\n\t0,\n\t0,\n\t0,\n\t22465,\n\t0,\n\t22470,\n\t0,\n\t22471,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22472,\n\t22473,\n\t0,\n\t22487,\n\t0,\n\t0,\n\t0,\n\t22488,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22489,\n\t0,\n\t0,\n\t22499,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22514,\n\t0,\n\t0,\n\t22515,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22516,\n\t0,\n\t0,\n\t0,\n\t22517,\n\t22520,\n\t0,\n\t0,\n\t0,\n\t22534,\n\t0,\n\t0,\n\t22535,\n\t0,\n\t0,\n\t22536,\n\t0,\n\t22540,\n\t22553,\n\t0,\n\t22555,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22561,\n\t0,\n\t0,\n\t22562,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22567,\n\t22568,\n\t0,\n\t0,\n\t22575,\n\t0,\n\t22579,\n\t0,\n\t22582,\n\t22583,\n\t22585,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22586,\n\t0,\n\t0,\n\t22587,\n\t0,\n\t0,\n\t22590,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22591,\n\t0,\n\t22592,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22593,\n\t0,\n\t22602,\n\t0,\n\t0,\n\t22604,\n\t0,\n\t0,\n\t22609,\n\t0,\n\t0,\n\t22618,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22619,\n\t0,\n\t22624,\n\t22625,\n\t0,\n\t0,\n\t22638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22639,\n\t0,\n\t0,\n\t22640,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22644,\n\t0,\n\t22645,\n\t22647,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22652,\n\t22653,\n\t0,\n\t0,\n\t0,\n\t22654,\n\t0,\n\t22655,\n\t0,\n\t0,\n\t0,\n\t22656,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22673,\n\t22675,\n\t22676,\n\t0,\n\t0,\n\t22678,\n\t22679,\n\t0,\n\t22691,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22693,\n\t0,\n\t0,\n\t22696,\n\t0,\n\t22699,\n\t22707,\n\t22708,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22718,\n\t0,\n\t22719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22723,\n\t0,\n\t0,\n\t0,\n\t22724,\n\t22725,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22726,\n\t22728,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22729,\n\t0,\n\t0,\n\t22731,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22732,\n\t22735,\n\t22736,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22739,\n\t0,\n\t22749,\n\t0,\n\t0,\n\t22751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22764,\n\t22765,\n\t22766,\n\t0,\n\t22768,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22769,\n\t22770,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22771,\n\t0,\n\t0,\n\t22772,\n\t22775,\n\t0,\n\t22776,\n\t22777,\n\t22780,\n\t0,\n\t0,\n\t22782,\n\t22784,\n\t0,\n\t22787,\n\t0,\n\t22789,\n\t22796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22798,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22802,\n\t0,\n\t22803,\n\t22804,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22805,\n\t0,\n\t0,\n\t22810,\n\t22811,\n\t22814,\n\t22816,\n\t0,\n\t22825,\n\t22826,\n\t0,\n\t22831,\n\t22833,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22834,\n\t0,\n\t22836,\n\t22838,\n\t0,\n\t22839,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22840,\n\t0,\n\t22847,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22856,\n\t22857,\n\t0,\n\t22858,\n\t22859,\n\t0,\n\t0,\n\t22862,\n\t0,\n\t0,\n\t22864,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22865,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22866,\n\t0,\n\t22867,\n\t22868,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22869,\n\t0,\n\t22871,\n\t0,\n\t22872,\n\t0,\n\t22873,\n\t22881,\n\t22882,\n\t22884,\n\t22885,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22886,\n\t22887,\n\t0,\n\t22894,\n\t0,\n\t22895,\n\t0,\n\t0,\n\t0,\n\t22900,\n\t0,\n\t22901,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22904,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22905,\n\t22907,\n\t0,\n\t0,\n\t0,\n\t22915,\n\t22917,\n\t0,\n\t0,\n\t22918,\n\t0,\n\t0,\n\t0,\n\t22920,\n\t0,\n\t0,\n\t0,\n\t22929,\n\t22930,\n\t0,\n\t0,\n\t0,\n\t22941,\n\t22942,\n\t0,\n\t0,\n\t0,\n\t22943,\n\t0,\n\t0,\n\t0,\n\t22944,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22946,\n\t0,\n\t22947,\n\t0,\n\t0,\n\t22954,\n\t0,\n\t22956,\n\t0,\n\t0,\n\t22962,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22963,\n\t0,\n\t0,\n\t22964,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22965,\n\t0,\n\t22968,\n\t0,\n\t0,\n\t0,\n\t22969,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22970,\n\t0,\n\t22971,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22978,\n\t0,\n\t0,\n\t22979,\n\t0,\n\t22987,\n\t0,\n\t0,\n\t22989,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t22990,\n\t0,\n\t23005,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23006,\n\t23007,\n\t23008,\n\t0,\n\t0,\n\t23023,\n\t23024,\n\t23029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23032,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23035,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23038,\n\t0,\n\t0,\n\t0,\n\t23048,\n\t0,\n\t23049,\n\t23052,\n\t23053,\n\t23060,\n\t23061,\n\t0,\n\t23063,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23067,\n\t23068,\n\t0,\n\t0,\n\t0,\n\t23069,\n\t23073,\n\t0,\n\t0,\n\t0,\n\t23127,\n\t0,\n\t23128,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23129,\n\t0,\n\t23138,\n\t23141,\n\t0,\n\t23149,\n\t0,\n\t0,\n\t23150,\n\t0,\n\t0,\n\t0,\n\t23152,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23154,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23157,\n\t23159,\n\t23160,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23180,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23181,\n\t0,\n\t0,\n\t23188,\n\t0,\n\t23189,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23195,\n\t0,\n\t0,\n\t23196,\n\t23199,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23202,\n\t0,\n\t23204,\n\t0,\n\t23207,\n\t0,\n\t23209,\n\t23210,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23227,\n\t23229,\n\t0,\n\t0,\n\t23230,\n\t23234,\n\t23238,\n\t0,\n\t0,\n\t0,\n\t23245,\n\t23246,\n\t23248,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23249,\n\t23254,\n\t0,\n\t0,\n\t0,\n\t23265,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23268,\n\t0,\n\t23276,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23277,\n\t0,\n\t23297,\n\t0,\n\t23298,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23299,\n\t0,\n\t23302,\n\t0,\n\t0,\n\t23303,\n\t23312,\n\t0,\n\t0,\n\t23314,\n\t0,\n\t23320,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23324,\n\t0,\n\t23325,\n\t0,\n\t23328,\n\t0,\n\t23334,\n\t0,\n\t0,\n\t0,\n\t23337,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23343,\n\t23344,\n\t23346,\n\t0,\n\t23348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23353,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23355,\n\t0,\n\t23356,\n\t23358,\n\t0,\n\t0,\n\t0,\n\t23359,\n\t23360,\n\t0,\n\t23361,\n\t0,\n\t23367,\n\t0,\n\t23369,\n\t0,\n\t0,\n\t23373,\n\t0,\n\t23378,\n\t23379,\n\t0,\n\t23382,\n\t23383,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23387,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23388,\n\t23390,\n\t0,\n\t0,\n\t23393,\n\t23398,\n\t0,\n\t0,\n\t0,\n\t23399,\n\t0,\n\t0,\n\t0,\n\t23400,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23401,\n\t0,\n\t0,\n\t0,\n\t23415,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23416,\n\t0,\n\t23422,\n\t0,\n\t23443,\n\t23444,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23448,\n\t0,\n\t23454,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23456,\n\t0,\n\t0,\n\t23458,\n\t23464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23465,\n\t0,\n\t0,\n\t0,\n\t23470,\n\t23471,\n\t0,\n\t0,\n\t23472,\n\t0,\n\t0,\n\t0,\n\t23473,\n\t23496,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23497,\n\t0,\n\t23499,\n\t0,\n\t0,\n\t23502,\n\t0,\n\t0,\n\t23503,\n\t0,\n\t0,\n\t23513,\n\t0,\n\t0,\n\t23515,\n\t0,\n\t0,\n\t0,\n\t23517,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23518,\n\t23519,\n\t23521,\n\t23524,\n\t0,\n\t23525,\n\t23528,\n\t23539,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23541,\n\t0,\n\t0,\n\t23544,\n\t0,\n\t0,\n\t23556,\n\t0,\n\t0,\n\t23557,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23559,\n\t0,\n\t23560,\n\t0,\n\t0,\n\t23561,\n\t0,\n\t0,\n\t23566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23568,\n\t23569,\n\t23570,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23571,\n\t0,\n\t23574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23575,\n\t0,\n\t23579,\n\t0,\n\t0,\n\t23581,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23587,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23596,\n\t23598,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23602,\n\t23606,\n\t0,\n\t0,\n\t23607,\n\t0,\n\t23608,\n\t0,\n\t0,\n\t0,\n\t23614,\n\t23616,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23618,\n\t0,\n\t0,\n\t23619,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23621,\n\t23626,\n\t0,\n\t23627,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23629,\n\t0,\n\t23630,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23634,\n\t0,\n\t23636,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23640,\n\t23667,\n\t0,\n\t23669,\n\t0,\n\t0,\n\t0,\n\t23681,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23682,\n\t0,\n\t23683,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23684,\n\t0,\n\t0,\n\t0,\n\t23685,\n\t23689,\n\t0,\n\t23693,\n\t23694,\n\t23700,\n\t0,\n\t23702,\n\t0,\n\t23709,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23712,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23714,\n\t0,\n\t0,\n\t23715,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23718,\n\t0,\n\t0,\n\t23720,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23722,\n\t0,\n\t0,\n\t0,\n\t23726,\n\t23729,\n\t0,\n\t23741,\n\t23746,\n\t0,\n\t23748,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23749,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23750,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23751,\n\t0,\n\t23753,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23757,\n\t23765,\n\t0,\n\t0,\n\t0,\n\t23770,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23771,\n\t0,\n\t23772,\n\t23781,\n\t0,\n\t0,\n\t23796,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23798,\n\t0,\n\t23799,\n\t0,\n\t0,\n\t0,\n\t23802,\n\t0,\n\t0,\n\t23806,\n\t0,\n\t23807,\n\t0,\n\t0,\n\t23808,\n\t0,\n\t23809,\n\t0,\n\t23819,\n\t0,\n\t0,\n\t0,\n\t23821,\n\t0,\n\t23827,\n\t0,\n\t0,\n\t0,\n\t23829,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23830,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23832,\n\t23833,\n\t23834,\n\t23835,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23837,\n\t23838,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23846,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23847,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23879,\n\t23881,\n\t0,\n\t0,\n\t23882,\n\t23883,\n\t23895,\n\t0,\n\t23899,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23901,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23903,\n\t23905,\n\t0,\n\t23906,\n\t0,\n\t23907,\n\t23918,\n\t23919,\n\t23920,\n\t0,\n\t23922,\n\t0,\n\t23924,\n\t0,\n\t23927,\n\t0,\n\t23934,\n\t0,\n\t23937,\n\t23941,\n\t0,\n\t23942,\n\t23946,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23955,\n\t23956,\n\t23958,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23959,\n\t0,\n\t23962,\n\t23965,\n\t0,\n\t23966,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23967,\n\t23968,\n\t0,\n\t0,\n\t23973,\n\t0,\n\t0,\n\t23974,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23975,\n\t0,\n\t23976,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23977,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23980,\n\t0,\n\t0,\n\t23984,\n\t0,\n\t23985,\n\t0,\n\t0,\n\t23987,\n\t0,\n\t0,\n\t23988,\n\t23990,\n\t23991,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23992,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23994,\n\t0,\n\t0,\n\t0,\n\t23998,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t23999,\n\t0,\n\t0,\n\t24003,\n\t0,\n\t24004,\n\t0,\n\t24006,\n\t0,\n\t0,\n\t0,\n\t24007,\n\t0,\n\t0,\n\t24008,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24009,\n\t0,\n\t0,\n\t24010,\n\t0,\n\t0,\n\t24011,\n\t0,\n\t0,\n\t24013,\n\t24014,\n\t0,\n\t0,\n\t24015,\n\t24016,\n\t24027,\n\t0,\n\t24028,\n\t24029,\n\t0,\n\t24030,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24033,\n\t24034,\n\t0,\n\t24035,\n\t0,\n\t0,\n\t24036,\n\t0,\n\t0,\n\t24044,\n\t0,\n\t24048,\n\t24049,\n\t24063,\n\t24067,\n\t0,\n\t24068,\n\t24070,\n\t0,\n\t0,\n\t24071,\n\t24078,\n\t24087,\n\t0,\n\t24090,\n\t0,\n\t0,\n\t0,\n\t24095,\n\t0,\n\t24098,\n\t24101,\n\t24104,\n\t24106,\n\t0,\n\t24107,\n\t0,\n\t0,\n\t0,\n\t24108,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24110,\n\t24111,\n\t0,\n\t24113,\n\t0,\n\t0,\n\t24115,\n\t24120,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24124,\n\t0,\n\t24125,\n\t0,\n\t24126,\n\t0,\n\t24127,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24135,\n\t0,\n\t0,\n\t24136,\n\t0,\n\t24137,\n\t24142,\n\t0,\n\t0,\n\t0,\n\t24146,\n\t0,\n\t0,\n\t24147,\n\t24149,\n\t24154,\n\t0,\n\t24163,\n\t0,\n\t0,\n\t0,\n\t24165,\n\t24166,\n\t24167,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24169,\n\t24170,\n\t24175,\n\t0,\n\t0,\n\t0,\n\t24178,\n\t0,\n\t0,\n\t24179,\n\t0,\n\t0,\n\t24181,\n\t0,\n\t24184,\n\t24197,\n\t0,\n\t24201,\n\t24204,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24206,\n\t24212,\n\t24220,\n\t0,\n\t0,\n\t0,\n\t24224,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24226,\n\t0,\n\t24234,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24235,\n\t0,\n\t24236,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24239,\n\t24240,\n\t24241,\n\t0,\n\t0,\n\t24248,\n\t0,\n\t0,\n\t24249,\n\t0,\n\t24251,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24253,\n\t0,\n\t24268,\n\t0,\n\t0,\n\t0,\n\t24269,\n\t0,\n\t24271,\n\t24272,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24273,\n\t0,\n\t0,\n\t24274,\n\t0,\n\t0,\n\t24279,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24280,\n\t0,\n\t24293,\n\t24294,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24296,\n\t0,\n\t0,\n\t24323,\n\t0,\n\t0,\n\t0,\n\t24329,\n\t24330,\n\t24331,\n\t24339,\n\t0,\n\t24351,\n\t0,\n\t0,\n\t24369,\n\t24370,\n\t0,\n\t0,\n\t0,\n\t24371,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24372,\n\t24373,\n\t24374,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24378,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24379,\n\t0,\n\t24381,\n\t0,\n\t24383,\n\t24389,\n\t0,\n\t24390,\n\t0,\n\t0,\n\t24394,\n\t24395,\n\t24400,\n\t0,\n\t0,\n\t0,\n\t24401,\n\t24402,\n\t0,\n\t24406,\n\t0,\n\t0,\n\t0,\n\t24411,\n\t0,\n\t0,\n\t0,\n\t24415,\n\t0,\n\t24416,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24417,\n\t0,\n\t24419,\n\t0,\n\t24422,\n\t0,\n\t24423,\n\t24428,\n\t0,\n\t24435,\n\t0,\n\t0,\n\t0,\n\t24439,\n\t0,\n\t0,\n\t0,\n\t24440,\n\t24442,\n\t24446,\n\t0,\n\t0,\n\t0,\n\t24447,\n\t24448,\n\t24449,\n\t24452,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24453,\n\t24457,\n\t0,\n\t0,\n\t24458,\n\t24459,\n\t24460,\n\t0,\n\t24465,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24471,\n\t0,\n\t24473,\n\t24474,\n\t24475,\n\t24476,\n\t0,\n\t24478,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24480,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24481,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24482,\n\t24485,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24486,\n\t0,\n\t0,\n\t0,\n\t24488,\n\t0,\n\t0,\n\t0,\n\t24494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24497,\n\t0,\n\t0,\n\t24498,\n\t0,\n\t0,\n\t0,\n\t24499,\n\t24506,\n\t0,\n\t0,\n\t0,\n\t24507,\n\t0,\n\t0,\n\t24511,\n\t0,\n\t0,\n\t24513,\n\t24514,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24517,\n\t0,\n\t24518,\n\t0,\n\t24520,\n\t0,\n\t24521,\n\t24524,\n\t24525,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24527,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24528,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24537,\n\t24539,\n\t0,\n\t24540,\n\t0,\n\t0,\n\t0,\n\t24548,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24549,\n\t24550,\n\t0,\n\t0,\n\t0,\n\t24553,\n\t24554,\n\t0,\n\t24555,\n\t0,\n\t24556,\n\t0,\n\t24558,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24560,\n\t0,\n\t0,\n\t0,\n\t24561,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24562,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24567,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24569,\n\t0,\n\t0,\n\t0,\n\t24574,\n\t0,\n\t24575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24577,\n\t24581,\n\t0,\n\t24584,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24585,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24586,\n\t0,\n\t0,\n\t24587,\n\t0,\n\t24588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24590,\n\t24591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24592,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24594,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24596,\n\t24597,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24602,\n\t24603,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24604,\n\t0,\n\t0,\n\t24605,\n\t0,\n\t24610,\n\t0,\n\t0,\n\t24611,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24612,\n\t24615,\n\t24616,\n\t24624,\n\t0,\n\t0,\n\t0,\n\t24627,\n\t0,\n\t24638,\n\t24639,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24640,\n\t0,\n\t0,\n\t0,\n\t24655,\n\t24656,\n\t24657,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24662,\n\t0,\n\t24663,\n\t24664,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24665,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24667,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24668,\n\t24669,\n\t0,\n\t24670,\n\t24674,\n\t0,\n\t0,\n\t0,\n\t24675,\n\t0,\n\t24678,\n\t0,\n\t0,\n\t24679,\n\t0,\n\t0,\n\t0,\n\t24681,\n\t0,\n\t24683,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24684,\n\t0,\n\t24685,\n\t0,\n\t0,\n\t24686,\n\t0,\n\t0,\n\t24688,\n\t24689,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24690,\n\t24691,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24697,\n\t0,\n\t24698,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24709,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24710,\n\t0,\n\t24712,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24713,\n\t24714,\n\t0,\n\t24715,\n\t0,\n\t24716,\n\t24718,\n\t0,\n\t24719,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24720,\n\t0,\n\t0,\n\t24725,\n\t0,\n\t0,\n\t24738,\n\t0,\n\t24749,\n\t24750,\n\t0,\n\t0,\n\t0,\n\t24752,\n\t0,\n\t0,\n\t0,\n\t24753,\n\t0,\n\t0,\n\t0,\n\t24758,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24762,\n\t0,\n\t24763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24764,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24765,\n\t24767,\n\t24768,\n\t0,\n\t24772,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24773,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24777,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24785,\n\t0,\n\t24786,\n\t24788,\n\t0,\n\t0,\n\t0,\n\t24789,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24794,\n\t24798,\n\t0,\n\t24799,\n\t24800,\n\t0,\n\t0,\n\t0,\n\t24803,\n\t0,\n\t24804,\n\t24806,\n\t0,\n\t24807,\n\t0,\n\t0,\n\t0,\n\t24810,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24827,\n\t24828,\n\t0,\n\t24835,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24836,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24839,\n\t0,\n\t24843,\n\t24844,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24847,\n\t0,\n\t0,\n\t24848,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24849,\n\t0,\n\t24850,\n\t24851,\n\t0,\n\t0,\n\t0,\n\t24852,\n\t0,\n\t24853,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24854,\n\t0,\n\t24855,\n\t0,\n\t0,\n\t24868,\n\t0,\n\t0,\n\t0,\n\t24883,\n\t0,\n\t0,\n\t0,\n\t24884,\n\t0,\n\t24895,\n\t24897,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24899,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24900,\n\t0,\n\t24913,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24914,\n\t0,\n\t0,\n\t24917,\n\t24930,\n\t24931,\n\t0,\n\t0,\n\t0,\n\t24932,\n\t0,\n\t0,\n\t24939,\n\t0,\n\t0,\n\t24942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24945,\n\t24950,\n\t0,\n\t24951,\n\t0,\n\t0,\n\t24953,\n\t0,\n\t0,\n\t0,\n\t24954,\n\t0,\n\t24959,\n\t0,\n\t0,\n\t0,\n\t24961,\n\t0,\n\t0,\n\t24962,\n\t0,\n\t24964,\n\t24968,\n\t24970,\n\t24972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t24976,\n\t0,\n\t0,\n\t0,\n\t24977,\n\t0,\n\t24982,\n\t0,\n\t0,\n\t24983,\n\t0,\n\t0,\n\t24984,\n\t0,\n\t0,\n\t0,\n\t24993,\n\t0,\n\t0,\n\t0,\n\t24994,\n\t0,\n\t0,\n\t25001,\n\t0,\n\t0,\n\t0,\n\t25003,\n\t0,\n\t0,\n\t25018,\n\t0,\n\t0,\n\t25023,\n\t0,\n\t0,\n\t0,\n\t25034,\n\t0,\n\t0,\n\t25035,\n\t25036,\n\t0,\n\t25037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25039,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25040,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25042,\n\t0,\n\t0,\n\t25043,\n\t25045,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25049,\n\t0,\n\t0,\n\t25051,\n\t0,\n\t25052,\n\t25053,\n\t0,\n\t0,\n\t25054,\n\t0,\n\t0,\n\t0,\n\t25055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25057,\n\t25059,\n\t0,\n\t0,\n\t25060,\n\t25064,\n\t0,\n\t25065,\n\t25069,\n\t25070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25072,\n\t0,\n\t25073,\n\t0,\n\t25090,\n\t0,\n\t0,\n\t25092,\n\t25093,\n\t25101,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25105,\n\t25108,\n\t0,\n\t0,\n\t25113,\n\t0,\n\t0,\n\t25115,\n\t25116,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25117,\n\t0,\n\t0,\n\t0,\n\t25120,\n\t25121,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25125,\n\t0,\n\t0,\n\t0,\n\t25126,\n\t0,\n\t25130,\n\t25134,\n\t0,\n\t25139,\n\t0,\n\t25143,\n\t0,\n\t0,\n\t0,\n\t25151,\n\t0,\n\t25161,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25163,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25174,\n\t0,\n\t25175,\n\t0,\n\t25207,\n\t0,\n\t0,\n\t0,\n\t25209,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25213,\n\t0,\n\t25219,\n\t0,\n\t25223,\n\t0,\n\t25225,\n\t0,\n\t0,\n\t0,\n\t25227,\n\t0,\n\t0,\n\t0,\n\t25228,\n\t0,\n\t0,\n\t0,\n\t25229,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25231,\n\t25233,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25237,\n\t25239,\n\t0,\n\t0,\n\t0,\n\t25243,\n\t0,\n\t0,\n\t0,\n\t25252,\n\t0,\n\t25257,\n\t25258,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25260,\n\t25265,\n\t0,\n\t25268,\n\t0,\n\t0,\n\t25273,\n\t25324,\n\t0,\n\t25325,\n\t0,\n\t25326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25327,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25328,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25332,\n\t0,\n\t0,\n\t0,\n\t25333,\n\t0,\n\t0,\n\t0,\n\t25336,\n\t25337,\n\t25338,\n\t0,\n\t0,\n\t25343,\n\t0,\n\t25350,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25352,\n\t0,\n\t25354,\n\t0,\n\t25375,\n\t0,\n\t25379,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25384,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25386,\n\t0,\n\t25388,\n\t0,\n\t25390,\n\t0,\n\t0,\n\t25399,\n\t0,\n\t0,\n\t25401,\n\t0,\n\t0,\n\t0,\n\t25402,\n\t0,\n\t0,\n\t0,\n\t25407,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25413,\n\t25415,\n\t0,\n\t0,\n\t25417,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25419,\n\t0,\n\t0,\n\t0,\n\t25421,\n\t0,\n\t0,\n\t0,\n\t25424,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25433,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25435,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25436,\n\t0,\n\t0,\n\t0,\n\t25437,\n\t0,\n\t0,\n\t25440,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25442,\n\t0,\n\t0,\n\t25443,\n\t0,\n\t25446,\n\t0,\n\t0,\n\t25449,\n\t0,\n\t0,\n\t0,\n\t25450,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25452,\n\t0,\n\t25453,\n\t25454,\n\t25455,\n\t0,\n\t0,\n\t0,\n\t25456,\n\t0,\n\t25457,\n\t0,\n\t0,\n\t0,\n\t25459,\n\t0,\n\t25461,\n\t0,\n\t25468,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25471,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25474,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25475,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25477,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25483,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25485,\n\t0,\n\t25497,\n\t0,\n\t0,\n\t25498,\n\t0,\n\t25504,\n\t0,\n\t25510,\n\t0,\n\t25512,\n\t0,\n\t0,\n\t25513,\n\t25514,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25517,\n\t25518,\n\t25519,\n\t0,\n\t25520,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25521,\n\t0,\n\t25522,\n\t25527,\n\t25534,\n\t0,\n\t25536,\n\t0,\n\t25537,\n\t0,\n\t0,\n\t25548,\n\t25550,\n\t0,\n\t0,\n\t25551,\n\t0,\n\t25552,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25554,\n\t0,\n\t25555,\n\t0,\n\t25556,\n\t25557,\n\t25568,\n\t0,\n\t0,\n\t0,\n\t25570,\n\t25571,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25574,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25579,\n\t0,\n\t0,\n\t0,\n\t25581,\n\t0,\n\t0,\n\t0,\n\t25582,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25588,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25590,\n\t0,\n\t25591,\n\t25592,\n\t25593,\n\t0,\n\t25594,\n\t0,\n\t0,\n\t0,\n\t25596,\n\t0,\n\t25597,\n\t25615,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25618,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25619,\n\t25623,\n\t0,\n\t0,\n\t25629,\n\t0,\n\t0,\n\t25631,\n\t0,\n\t0,\n\t0,\n\t25635,\n\t25636,\n\t0,\n\t0,\n\t25649,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25654,\n\t0,\n\t0,\n\t0,\n\t25661,\n\t25663,\n\t0,\n\t0,\n\t25671,\n\t0,\n\t0,\n\t25678,\n\t25698,\n\t0,\n\t25699,\n\t25702,\n\t25703,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25704,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25706,\n\t0,\n\t0,\n\t25710,\n\t0,\n\t25711,\n\t0,\n\t25712,\n\t0,\n\t25715,\n\t25716,\n\t25717,\n\t0,\n\t0,\n\t25718,\n\t25728,\n\t25732,\n\t0,\n\t0,\n\t0,\n\t25734,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25737,\n\t0,\n\t0,\n\t25739,\n\t0,\n\t0,\n\t0,\n\t25740,\n\t0,\n\t25741,\n\t25745,\n\t0,\n\t25746,\n\t0,\n\t25748,\n\t25772,\n\t25778,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25780,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25781,\n\t0,\n\t25782,\n\t25784,\n\t25785,\n\t0,\n\t0,\n\t0,\n\t25789,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25797,\n\t25801,\n\t0,\n\t0,\n\t0,\n\t25808,\n\t25809,\n\t0,\n\t0,\n\t25811,\n\t25814,\n\t25815,\n\t0,\n\t0,\n\t25817,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25820,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25832,\n\t25833,\n\t0,\n\t0,\n\t0,\n\t25846,\n\t0,\n\t0,\n\t0,\n\t25847,\n\t25848,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25849,\n\t25850,\n\t0,\n\t0,\n\t25851,\n\t0,\n\t0,\n\t25852,\n\t0,\n\t25862,\n\t0,\n\t0,\n\t0,\n\t25863,\n\t25865,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25867,\n\t25868,\n\t0,\n\t25869,\n\t25874,\n\t0,\n\t25875,\n\t0,\n\t25876,\n\t25877,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25878,\n\t25902,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25903,\n\t25904,\n\t25905,\n\t0,\n\t0,\n\t0,\n\t25908,\n\t25909,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25910,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25912,\n\t0,\n\t25913,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25914,\n\t0,\n\t0,\n\t25916,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25917,\n\t25927,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25928,\n\t0,\n\t0,\n\t25930,\n\t0,\n\t0,\n\t0,\n\t25933,\n\t0,\n\t0,\n\t25938,\n\t25942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25945,\n\t0,\n\t25950,\n\t0,\n\t25956,\n\t0,\n\t0,\n\t25961,\n\t25962,\n\t0,\n\t0,\n\t25963,\n\t0,\n\t25964,\n\t25965,\n\t25966,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25968,\n\t0,\n\t0,\n\t0,\n\t25969,\n\t25971,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25973,\n\t25975,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25978,\n\t0,\n\t25981,\n\t0,\n\t0,\n\t0,\n\t25982,\n\t0,\n\t0,\n\t0,\n\t25984,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t25993,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26002,\n\t0,\n\t0,\n\t0,\n\t26005,\n\t0,\n\t0,\n\t0,\n\t26006,\n\t26007,\n\t0,\n\t0,\n\t26014,\n\t26015,\n\t26016,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26017,\n\t26018,\n\t26020,\n\t0,\n\t26022,\n\t26023,\n\t0,\n\t0,\n\t0,\n\t26024,\n\t26028,\n\t0,\n\t26029,\n\t26033,\n\t26034,\n\t26044,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26046,\n\t0,\n\t0,\n\t26047,\n\t0,\n\t0,\n\t26049,\n\t0,\n\t26050,\n\t0,\n\t26051,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26053,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26054,\n\t26059,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26060,\n\t0,\n\t26066,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26067,\n\t0,\n\t26069,\n\t0,\n\t0,\n\t26071,\n\t0,\n\t0,\n\t0,\n\t26073,\n\t0,\n\t26074,\n\t26077,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26078,\n\t0,\n\t0,\n\t0,\n\t26079,\n\t0,\n\t26090,\n\t0,\n\t0,\n\t26094,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26095,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26096,\n\t26101,\n\t0,\n\t26107,\n\t26122,\n\t0,\n\t26124,\n\t0,\n\t0,\n\t26125,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26136,\n\t26141,\n\t26155,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26164,\n\t26166,\n\t0,\n\t0,\n\t0,\n\t26167,\n\t0,\n\t26170,\n\t26171,\n\t0,\n\t0,\n\t26172,\n\t0,\n\t0,\n\t26174,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26175,\n\t0,\n\t0,\n\t0,\n\t26176,\n\t26177,\n\t0,\n\t26321,\n\t26322,\n\t0,\n\t26323,\n\t0,\n\t0,\n\t26324,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26325,\n\t0,\n\t26331,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26335,\n\t0,\n\t0,\n\t0,\n\t26350,\n\t0,\n\t0,\n\t0,\n\t26379,\n\t0,\n\t0,\n\t26382,\n\t26383,\n\t26385,\n\t0,\n\t0,\n\t26392,\n\t26406,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26411,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26412,\n\t0,\n\t0,\n\t26420,\n\t0,\n\t0,\n\t26423,\n\t0,\n\t26424,\n\t26426,\n\t26432,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26435,\n\t0,\n\t26436,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26441,\n\t0,\n\t26444,\n\t0,\n\t0,\n\t0,\n\t26446,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26447,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26449,\n\t0,\n\t26450,\n\t26452,\n\t0,\n\t26453,\n\t26454,\n\t0,\n\t0,\n\t0,\n\t26455,\n\t0,\n\t0,\n\t0,\n\t26456,\n\t0,\n\t0,\n\t26458,\n\t0,\n\t0,\n\t26460,\n\t0,\n\t26463,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26464,\n\t26470,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26473,\n\t0,\n\t0,\n\t26474,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26475,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26477,\n\t0,\n\t26485,\n\t0,\n\t0,\n\t26486,\n\t0,\n\t26487,\n\t0,\n\t0,\n\t26488,\n\t26493,\n\t26494,\n\t0,\n\t0,\n\t26495,\n\t0,\n\t26497,\n\t26504,\n\t26506,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26507,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26509,\n\t0,\n\t0,\n\t26510,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26512,\n\t0,\n\t26513,\n\t26515,\n\t0,\n\t0,\n\t0,\n\t26518,\n\t0,\n\t0,\n\t0,\n\t26519,\n\t0,\n\t26524,\n\t26526,\n\t0,\n\t0,\n\t0,\n\t26527,\n\t0,\n\t26532,\n\t0,\n\t26533,\n\t26537,\n\t26558,\n\t0,\n\t0,\n\t0,\n\t26559,\n\t0,\n\t0,\n\t0,\n\t26571,\n\t0,\n\t0,\n\t26573,\n\t0,\n\t26588,\n\t0,\n\t26593,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26603,\n\t0,\n\t26604,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26606,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26607,\n\t26609,\n\t26611,\n\t26614,\n\t0,\n\t0,\n\t0,\n\t26616,\n\t26620,\n\t0,\n\t26621,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26627,\n\t0,\n\t26629,\n\t0,\n\t0,\n\t26630,\n\t0,\n\t0,\n\t26632,\n\t26643,\n\t0,\n\t0,\n\t0,\n\t26644,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26646,\n\t26647,\n\t0,\n\t0,\n\t0,\n\t26650,\n\t0,\n\t0,\n\t26656,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26663,\n\t26670,\n\t26671,\n\t0,\n\t0,\n\t0,\n\t26685,\n\t26686,\n\t26687,\n\t0,\n\t26689,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26744,\n\t0,\n\t26745,\n\t0,\n\t26747,\n\t26748,\n\t0,\n\t26749,\n\t26750,\n\t26751,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26752,\n\t26755,\n\t0,\n\t0,\n\t0,\n\t26756,\n\t26769,\n\t0,\n\t0,\n\t0,\n\t26774,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26775,\n\t0,\n\t26777,\n\t26778,\n\t0,\n\t26786,\n\t0,\n\t0,\n\t0,\n\t26787,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26788,\n\t0,\n\t0,\n\t26789,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26791,\n\t0,\n\t26792,\n\t26793,\n\t0,\n\t0,\n\t0,\n\t26794,\n\t0,\n\t26797,\n\t26798,\n\t0,\n\t0,\n\t0,\n\t26800,\n\t0,\n\t0,\n\t26803,\n\t0,\n\t26804,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26805,\n\t0,\n\t0,\n\t26808,\n\t0,\n\t0,\n\t26809,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26812,\n\t0,\n\t26825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26826,\n\t0,\n\t0,\n\t26827,\n\t26829,\n\t26834,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26835,\n\t0,\n\t0,\n\t26849,\n\t0,\n\t26851,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26852,\n\t0,\n\t26853,\n\t26857,\n\t0,\n\t26858,\n\t0,\n\t26859,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26876,\n\t0,\n\t26878,\n\t26882,\n\t26883,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26890,\n\t26894,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26895,\n\t26896,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26900,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26911,\n\t26913,\n\t26914,\n\t26915,\n\t26916,\n\t26919,\n\t0,\n\t0,\n\t0,\n\t26921,\n\t26922,\n\t0,\n\t0,\n\t26925,\n\t0,\n\t0,\n\t0,\n\t26928,\n\t0,\n\t0,\n\t26929,\n\t26930,\n\t0,\n\t0,\n\t0,\n\t26931,\n\t0,\n\t26932,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26933,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26937,\n\t0,\n\t0,\n\t26943,\n\t0,\n\t0,\n\t26944,\n\t0,\n\t0,\n\t0,\n\t26946,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26956,\n\t0,\n\t26958,\n\t0,\n\t0,\n\t26963,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26965,\n\t0,\n\t26969,\n\t26970,\n\t26972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26973,\n\t0,\n\t26974,\n\t0,\n\t26978,\n\t0,\n\t26980,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t26982,\n\t0,\n\t26986,\n\t26987,\n\t0,\n\t26990,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27003,\n\t27006,\n\t0,\n\t0,\n\t27007,\n\t27010,\n\t27012,\n\t27013,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27014,\n\t27015,\n\t27018,\n\t0,\n\t27019,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27025,\n\t0,\n\t0,\n\t0,\n\t27026,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27029,\n\t27030,\n\t27031,\n\t27034,\n\t0,\n\t0,\n\t27036,\n\t27037,\n\t0,\n\t0,\n\t0,\n\t27038,\n\t27042,\n\t0,\n\t0,\n\t0,\n\t27044,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27045,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27046,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27047,\n\t27049,\n\t0,\n\t27050,\n\t0,\n\t0,\n\t0,\n\t27051,\n\t27052,\n\t0,\n\t27055,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27056,\n\t27058,\n\t27059,\n\t0,\n\t27061,\n\t0,\n\t27064,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27069,\n\t0,\n\t0,\n\t27070,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27072,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27076,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27078,\n\t0,\n\t27079,\n\t0,\n\t0,\n\t0,\n\t27081,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27082,\n\t0,\n\t27083,\n\t27086,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27087,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27088,\n\t27090,\n\t0,\n\t27094,\n\t0,\n\t0,\n\t27095,\n\t0,\n\t27099,\n\t27102,\n\t0,\n\t0,\n\t0,\n\t27103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27105,\n\t0,\n\t0,\n\t0,\n\t27106,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27107,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27108,\n\t27117,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27118,\n\t0,\n\t0,\n\t27124,\n\t0,\n\t27126,\n\t0,\n\t0,\n\t27130,\n\t27131,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27147,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27148,\n\t27149,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27150,\n\t27151,\n\t0,\n\t27152,\n\t0,\n\t27159,\n\t0,\n\t0,\n\t0,\n\t27164,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27175,\n\t0,\n\t27189,\n\t0,\n\t0,\n\t27191,\n\t0,\n\t27193,\n\t0,\n\t27195,\n\t0,\n\t27198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27200,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27203,\n\t0,\n\t0,\n\t27204,\n\t0,\n\t0,\n\t27206,\n\t0,\n\t27207,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27209,\n\t0,\n\t0,\n\t0,\n\t27213,\n\t0,\n\t0,\n\t27216,\n\t27219,\n\t27220,\n\t27222,\n\t27223,\n\t0,\n\t27224,\n\t0,\n\t27225,\n\t27226,\n\t0,\n\t0,\n\t27233,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27235,\n\t0,\n\t27237,\n\t0,\n\t27238,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27239,\n\t0,\n\t27242,\n\t27243,\n\t0,\n\t27250,\n\t0,\n\t0,\n\t0,\n\t27251,\n\t0,\n\t27253,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27254,\n\t27255,\n\t27258,\n\t0,\n\t0,\n\t0,\n\t27259,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27267,\n\t0,\n\t27276,\n\t27278,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27296,\n\t27297,\n\t27301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27312,\n\t27313,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27318,\n\t0,\n\t27320,\n\t0,\n\t27329,\n\t0,\n\t27330,\n\t27331,\n\t0,\n\t27332,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27340,\n\t0,\n\t0,\n\t0,\n\t27348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27350,\n\t0,\n\t27351,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27355,\n\t0,\n\t0,\n\t27358,\n\t27359,\n\t27361,\n\t0,\n\t0,\n\t0,\n\t27365,\n\t0,\n\t27367,\n\t0,\n\t27376,\n\t27378,\n\t0,\n\t0,\n\t27379,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27396,\n\t0,\n\t27397,\n\t27404,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27408,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27453,\n\t0,\n\t0,\n\t0,\n\t27456,\n\t0,\n\t0,\n\t0,\n\t27458,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27459,\n\t0,\n\t0,\n\t0,\n\t27460,\n\t0,\n\t0,\n\t27461,\n\t0,\n\t27465,\n\t27467,\n\t0,\n\t0,\n\t27469,\n\t0,\n\t27470,\n\t0,\n\t27471,\n\t0,\n\t27477,\n\t27482,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27485,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27493,\n\t0,\n\t27494,\n\t27502,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27511,\n\t27532,\n\t0,\n\t0,\n\t0,\n\t27533,\n\t27545,\n\t0,\n\t0,\n\t0,\n\t27546,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27547,\n\t0,\n\t0,\n\t27549,\n\t27550,\n\t0,\n\t27551,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27555,\n\t0,\n\t0,\n\t27571,\n\t0,\n\t27573,\n\t27574,\n\t27575,\n\t27577,\n\t0,\n\t27578,\n\t0,\n\t0,\n\t27579,\n\t27585,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27586,\n\t0,\n\t0,\n\t27588,\n\t27589,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27596,\n\t0,\n\t0,\n\t27600,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27608,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27610,\n\t0,\n\t0,\n\t0,\n\t27618,\n\t0,\n\t0,\n\t27620,\n\t0,\n\t0,\n\t0,\n\t27631,\n\t0,\n\t0,\n\t27632,\n\t27634,\n\t0,\n\t27636,\n\t27638,\n\t0,\n\t0,\n\t0,\n\t27643,\n\t0,\n\t27644,\n\t27649,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27651,\n\t27660,\n\t0,\n\t27661,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27662,\n\t0,\n\t0,\n\t27664,\n\t0,\n\t27665,\n\t0,\n\t0,\n\t0,\n\t27669,\n\t0,\n\t27671,\n\t0,\n\t0,\n\t0,\n\t27673,\n\t27674,\n\t0,\n\t0,\n\t0,\n\t27682,\n\t0,\n\t0,\n\t0,\n\t27711,\n\t0,\n\t27712,\n\t27713,\n\t27719,\n\t27720,\n\t0,\n\t0,\n\t27728,\n\t0,\n\t27729,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27731,\n\t0,\n\t0,\n\t27732,\n\t0,\n\t27733,\n\t0,\n\t27738,\n\t0,\n\t0,\n\t0,\n\t27742,\n\t0,\n\t0,\n\t0,\n\t27743,\n\t27744,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27745,\n\t27746,\n\t0,\n\t0,\n\t0,\n\t27747,\n\t27748,\n\t27751,\n\t27752,\n\t0,\n\t0,\n\t0,\n\t27768,\n\t27770,\n\t0,\n\t0,\n\t0,\n\t27774,\n\t27775,\n\t0,\n\t27776,\n\t27777,\n\t0,\n\t0,\n\t27781,\n\t0,\n\t27784,\n\t0,\n\t27786,\n\t0,\n\t0,\n\t27791,\n\t0,\n\t27792,\n\t27793,\n\t27804,\n\t0,\n\t27812,\n\t27813,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27814,\n\t0,\n\t27825,\n\t0,\n\t27827,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27828,\n\t27861,\n\t27862,\n\t0,\n\t0,\n\t0,\n\t27864,\n\t0,\n\t0,\n\t0,\n\t27865,\n\t27884,\n\t0,\n\t27889,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27890,\n\t0,\n\t27891,\n\t0,\n\t0,\n\t0,\n\t27892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27897,\n\t27898,\n\t0,\n\t0,\n\t27899,\n\t0,\n\t0,\n\t0,\n\t27901,\n\t27905,\n\t0,\n\t0,\n\t27920,\n\t0,\n\t0,\n\t27921,\n\t0,\n\t27922,\n\t0,\n\t0,\n\t0,\n\t27931,\n\t27934,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27941,\n\t0,\n\t27942,\n\t0,\n\t27945,\n\t0,\n\t27947,\n\t27954,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27960,\n\t27963,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t27964,\n\t27965,\n\t0,\n\t0,\n\t0,\n\t27967,\n\t0,\n\t27969,\n\t27975,\n\t0,\n\t27976,\n\t27977,\n\t0,\n\t27981,\n\t0,\n\t27983,\n\t28051,\n\t28052,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28056,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28058,\n\t28059,\n\t0,\n\t0,\n\t28061,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28063,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28066,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28069,\n\t28070,\n\t28072,\n\t0,\n\t28073,\n\t0,\n\t0,\n\t28074,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28075,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28078,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28085,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28086,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28088,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28090,\n\t0,\n\t28097,\n\t28114,\n\t28115,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28116,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28118,\n\t0,\n\t28129,\n\t0,\n\t28131,\n\t0,\n\t0,\n\t28135,\n\t0,\n\t0,\n\t0,\n\t28140,\n\t28141,\n\t0,\n\t0,\n\t0,\n\t28146,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28152,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28155,\n\t28157,\n\t28161,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28166,\n\t0,\n\t28167,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28172,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28173,\n\t0,\n\t0,\n\t28175,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28178,\n\t28188,\n\t0,\n\t28190,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28191,\n\t0,\n\t28193,\n\t28206,\n\t0,\n\t0,\n\t28207,\n\t28209,\n\t0,\n\t28211,\n\t0,\n\t28213,\n\t0,\n\t0,\n\t0,\n\t28215,\n\t28216,\n\t28217,\n\t0,\n\t28222,\n\t0,\n\t28223,\n\t28225,\n\t0,\n\t0,\n\t0,\n\t28226,\n\t0,\n\t28227,\n\t28229,\n\t28232,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28235,\n\t0,\n\t28241,\n\t0,\n\t0,\n\t28242,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28243,\n\t0,\n\t0,\n\t0,\n\t28245,\n\t0,\n\t0,\n\t0,\n\t28248,\n\t28250,\n\t0,\n\t28251,\n\t28252,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28253,\n\t0,\n\t0,\n\t28254,\n\t28255,\n\t0,\n\t0,\n\t28256,\n\t0,\n\t0,\n\t28258,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28259,\n\t0,\n\t0,\n\t28260,\n\t0,\n\t0,\n\t28261,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28262,\n\t28263,\n\t0,\n\t0,\n\t28264,\n\t0,\n\t0,\n\t0,\n\t28266,\n\t0,\n\t28268,\n\t28269,\n\t0,\n\t28270,\n\t28272,\n\t28274,\n\t0,\n\t28277,\n\t28278,\n\t0,\n\t0,\n\t0,\n\t28279,\n\t0,\n\t28280,\n\t28281,\n\t28283,\n\t0,\n\t28292,\n\t0,\n\t28294,\n\t0,\n\t28297,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28299,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28300,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28301,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28302,\n\t28303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28304,\n\t0,\n\t0,\n\t28305,\n\t0,\n\t28312,\n\t0,\n\t28313,\n\t28314,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28315,\n\t0,\n\t0,\n\t0,\n\t28320,\n\t28321,\n\t0,\n\t0,\n\t28328,\n\t0,\n\t0,\n\t0,\n\t28329,\n\t28338,\n\t0,\n\t28339,\n\t0,\n\t0,\n\t28344,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28347,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28348,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28411,\n\t0,\n\t28412,\n\t28413,\n\t0,\n\t28416,\n\t0,\n\t0,\n\t0,\n\t28420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28421,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28423,\n\t0,\n\t0,\n\t0,\n\t28424,\n\t0,\n\t0,\n\t28428,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28429,\n\t0,\n\t0,\n\t0,\n\t28431,\n\t28434,\n\t0,\n\t28458,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28465,\n\t0,\n\t28467,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28471,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28474,\n\t0,\n\t28480,\n\t0,\n\t28481,\n\t0,\n\t0,\n\t28485,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28486,\n\t28488,\n\t0,\n\t0,\n\t28489,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28492,\n\t0,\n\t0,\n\t0,\n\t28495,\n\t0,\n\t28497,\n\t0,\n\t28499,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28500,\n\t0,\n\t0,\n\t28502,\n\t28503,\n\t0,\n\t0,\n\t0,\n\t28508,\n\t0,\n\t0,\n\t0,\n\t28510,\n\t0,\n\t0,\n\t28512,\n\t28513,\n\t28514,\n\t28521,\n\t0,\n\t28526,\n\t0,\n\t28527,\n\t28528,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28529,\n\t0,\n\t0,\n\t28532,\n\t0,\n\t0,\n\t28537,\n\t28538,\n\t0,\n\t0,\n\t0,\n\t28539,\n\t0,\n\t28548,\n\t0,\n\t28553,\n\t28554,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28560,\n\t28563,\n\t0,\n\t0,\n\t28564,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28565,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28566,\n\t28568,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28569,\n\t0,\n\t0,\n\t0,\n\t28570,\n\t0,\n\t28572,\n\t28573,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28575,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28576,\n\t28581,\n\t28588,\n\t0,\n\t0,\n\t28589,\n\t0,\n\t0,\n\t0,\n\t28590,\n\t28595,\n\t0,\n\t28598,\n\t0,\n\t0,\n\t28601,\n\t0,\n\t0,\n\t28605,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28614,\n\t28615,\n\t28619,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28620,\n\t0,\n\t28626,\n\t0,\n\t0,\n\t28628,\n\t0,\n\t28631,\n\t0,\n\t28632,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28635,\n\t0,\n\t0,\n\t0,\n\t28637,\n\t28638,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28639,\n\t0,\n\t28643,\n\t0,\n\t0,\n\t28652,\n\t0,\n\t0,\n\t0,\n\t28662,\n\t0,\n\t28670,\n\t28671,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28672,\n\t28673,\n\t28675,\n\t28676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28691,\n\t0,\n\t0,\n\t0,\n\t28695,\n\t0,\n\t0,\n\t0,\n\t28696,\n\t0,\n\t28697,\n\t28698,\n\t0,\n\t28705,\n\t0,\n\t28707,\n\t28708,\n\t28710,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28711,\n\t28728,\n\t0,\n\t0,\n\t0,\n\t28736,\n\t0,\n\t0,\n\t0,\n\t28737,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28738,\n\t0,\n\t28739,\n\t0,\n\t28741,\n\t0,\n\t0,\n\t28742,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28745,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28749,\n\t28750,\n\t28752,\n\t28754,\n\t28756,\n\t0,\n\t28757,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28759,\n\t28760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28762,\n\t0,\n\t0,\n\t0,\n\t28764,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28766,\n\t0,\n\t28767,\n\t28768,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28769,\n\t28770,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28771,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28772,\n\t0,\n\t28773,\n\t0,\n\t28782,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28784,\n\t0,\n\t28785,\n\t0,\n\t28786,\n\t0,\n\t0,\n\t0,\n\t28787,\n\t0,\n\t0,\n\t0,\n\t28797,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28799,\n\t0,\n\t0,\n\t28801,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28802,\n\t0,\n\t28805,\n\t0,\n\t0,\n\t28806,\n\t0,\n\t0,\n\t28807,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28808,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28810,\n\t28812,\n\t0,\n\t0,\n\t28816,\n\t28819,\n\t0,\n\t0,\n\t28821,\n\t0,\n\t28826,\n\t0,\n\t0,\n\t0,\n\t28842,\n\t28852,\n\t0,\n\t0,\n\t28853,\n\t0,\n\t28854,\n\t28855,\n\t0,\n\t0,\n\t0,\n\t28857,\n\t0,\n\t0,\n\t0,\n\t28858,\n\t0,\n\t28867,\n\t28868,\n\t28869,\n\t0,\n\t0,\n\t0,\n\t28874,\n\t28880,\n\t28882,\n\t28890,\n\t28892,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28895,\n\t0,\n\t0,\n\t0,\n\t28898,\n\t28899,\n\t0,\n\t0,\n\t0,\n\t28900,\n\t0,\n\t0,\n\t28904,\n\t0,\n\t28906,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28907,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28908,\n\t0,\n\t0,\n\t0,\n\t28910,\n\t0,\n\t28914,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28915,\n\t28916,\n\t28919,\n\t0,\n\t0,\n\t28920,\n\t0,\n\t28921,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28924,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28926,\n\t28929,\n\t0,\n\t0,\n\t0,\n\t28930,\n\t0,\n\t28936,\n\t0,\n\t28939,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28956,\n\t0,\n\t0,\n\t0,\n\t28966,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28967,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28968,\n\t0,\n\t28971,\n\t0,\n\t28975,\n\t28976,\n\t0,\n\t28982,\n\t28983,\n\t0,\n\t0,\n\t28984,\n\t28989,\n\t28996,\n\t28997,\n\t28998,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t28999,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29000,\n\t0,\n\t29001,\n\t0,\n\t0,\n\t0,\n\t29009,\n\t0,\n\t0,\n\t29011,\n\t0,\n\t0,\n\t29021,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29024,\n\t0,\n\t29025,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29026,\n\t0,\n\t0,\n\t0,\n\t29036,\n\t0,\n\t0,\n\t0,\n\t29037,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29038,\n\t0,\n\t29045,\n\t0,\n\t29047,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29051,\n\t0,\n\t0,\n\t0,\n\t29054,\n\t29056,\n\t29062,\n\t0,\n\t29070,\n\t29082,\n\t0,\n\t0,\n\t0,\n\t29083,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29084,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29085,\n\t29088,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29090,\n\t29097,\n\t0,\n\t0,\n\t0,\n\t29103,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29105,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29107,\n\t0,\n\t29109,\n\t0,\n\t0,\n\t0,\n\t29115,\n\t0,\n\t0,\n\t29120,\n\t0,\n\t0,\n\t29138,\n\t29140,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29152,\n\t0,\n\t29160,\n\t29174,\n\t0,\n\t29176,\n\t0,\n\t0,\n\t29180,\n\t0,\n\t29181,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29228,\n\t0,\n\t0,\n\t29229,\n\t0,\n\t0,\n\t29230,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29234,\n\t0,\n\t0,\n\t0,\n\t29241,\n\t0,\n\t29245,\n\t0,\n\t29248,\n\t0,\n\t29250,\n\t29256,\n\t29280,\n\t0,\n\t29282,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29285,\n\t0,\n\t0,\n\t29286,\n\t29291,\n\t29292,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29294,\n\t0,\n\t29295,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29296,\n\t29297,\n\t29298,\n\t29300,\n\t0,\n\t29302,\n\t0,\n\t0,\n\t29304,\n\t29307,\n\t0,\n\t29312,\n\t0,\n\t0,\n\t0,\n\t29322,\n\t0,\n\t0,\n\t29323,\n\t0,\n\t0,\n\t29324,\n\t29326,\n\t29328,\n\t0,\n\t29335,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29338,\n\t29339,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29341,\n\t29343,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29344,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29345,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29346,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29347,\n\t29348,\n\t29349,\n\t0,\n\t0,\n\t29354,\n\t0,\n\t0,\n\t29355,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29357,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29364,\n\t0,\n\t29365,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29366,\n\t0,\n\t0,\n\t29368,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29378,\n\t0,\n\t29381,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29386,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29389,\n\t0,\n\t0,\n\t0,\n\t29390,\n\t0,\n\t0,\n\t29391,\n\t29397,\n\t0,\n\t29398,\n\t29412,\n\t29414,\n\t29418,\n\t29419,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29420,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29423,\n\t0,\n\t0,\n\t0,\n\t29435,\n\t0,\n\t0,\n\t0,\n\t29437,\n\t0,\n\t0,\n\t29439,\n\t0,\n\t29441,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29443,\n\t0,\n\t29446,\n\t29450,\n\t29452,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29456,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29461,\n\t0,\n\t0,\n\t0,\n\t29464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29468,\n\t0,\n\t29473,\n\t0,\n\t0,\n\t0,\n\t29486,\n\t0,\n\t0,\n\t0,\n\t29490,\n\t0,\n\t0,\n\t0,\n\t29491,\n\t29492,\n\t0,\n\t0,\n\t29497,\n\t0,\n\t0,\n\t0,\n\t29498,\n\t0,\n\t29499,\n\t0,\n\t29502,\n\t29505,\n\t0,\n\t29509,\n\t0,\n\t0,\n\t0,\n\t29510,\n\t0,\n\t0,\n\t0,\n\t29512,\n\t0,\n\t0,\n\t0,\n\t29516,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29518,\n\t0,\n\t29519,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29520,\n\t29521,\n\t29529,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29530,\n\t0,\n\t0,\n\t29531,\n\t29538,\n\t0,\n\t29540,\n\t0,\n\t0,\n\t0,\n\t29542,\n\t0,\n\t29543,\n\t29544,\n\t29547,\n\t0,\n\t0,\n\t29548,\n\t0,\n\t0,\n\t0,\n\t29549,\n\t0,\n\t0,\n\t0,\n\t29550,\n\t0,\n\t0,\n\t29552,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29558,\n\t29561,\n\t0,\n\t29562,\n\t29564,\n\t0,\n\t0,\n\t29565,\n\t0,\n\t0,\n\t29566,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29578,\n\t29584,\n\t29586,\n\t29591,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29593,\n\t29594,\n\t0,\n\t0,\n\t29597,\n\t0,\n\t0,\n\t29613,\n\t0,\n\t29614,\n\t0,\n\t29615,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29616,\n\t29617,\n\t0,\n\t0,\n\t29625,\n\t0,\n\t0,\n\t0,\n\t29632,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29633,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29634,\n\t29635,\n\t29637,\n\t0,\n\t29638,\n\t0,\n\t29641,\n\t29643,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29644,\n\t0,\n\t29645,\n\t0,\n\t29649,\n\t0,\n\t0,\n\t0,\n\t29650,\n\t0,\n\t29653,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29656,\n\t29659,\n\t0,\n\t0,\n\t29660,\n\t0,\n\t0,\n\t0,\n\t29661,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29664,\n\t0,\n\t0,\n\t0,\n\t29671,\n\t29673,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29675,\n\t0,\n\t29677,\n\t29679,\n\t0,\n\t0,\n\t29684,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29685,\n\t0,\n\t0,\n\t0,\n\t29687,\n\t0,\n\t0,\n\t0,\n\t29688,\n\t0,\n\t29689,\n\t29690,\n\t29700,\n\t0,\n\t29701,\n\t0,\n\t0,\n\t0,\n\t29702,\n\t0,\n\t29706,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29720,\n\t0,\n\t29721,\n\t0,\n\t29727,\n\t0,\n\t29733,\n\t29734,\n\t0,\n\t29750,\n\t29761,\n\t0,\n\t29763,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29764,\n\t0,\n\t0,\n\t29765,\n\t0,\n\t0,\n\t0,\n\t29771,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29772,\n\t0,\n\t0,\n\t0,\n\t29773,\n\t29774,\n\t29775,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29822,\n\t0,\n\t0,\n\t0,\n\t29824,\n\t0,\n\t29825,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29827,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29829,\n\t0,\n\t29832,\n\t29834,\n\t0,\n\t0,\n\t29835,\n\t0,\n\t0,\n\t29837,\n\t29838,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29843,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29844,\n\t29845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29849,\n\t0,\n\t0,\n\t29869,\n\t29872,\n\t29890,\n\t29905,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29907,\n\t29921,\n\t0,\n\t29922,\n\t0,\n\t0,\n\t29923,\n\t29926,\n\t29944,\n\t29946,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29947,\n\t29948,\n\t0,\n\t0,\n\t0,\n\t29951,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29953,\n\t0,\n\t0,\n\t29956,\n\t0,\n\t29957,\n\t0,\n\t0,\n\t29962,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29971,\n\t0,\n\t0,\n\t0,\n\t29972,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t29978,\n\t0,\n\t29979,\n\t29992,\n\t30007,\n\t30008,\n\t30010,\n\t0,\n\t0,\n\t0,\n\t30013,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30014,\n\t30016,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30017,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30023,\n\t30031,\n\t0,\n\t0,\n\t30033,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30034,\n\t0,\n\t30038,\n\t0,\n\t30039,\n\t0,\n\t30040,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30067,\n\t30068,\n\t0,\n\t0,\n\t0,\n\t30069,\n\t0,\n\t30072,\n\t0,\n\t0,\n\t0,\n\t30073,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30075,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30079,\n\t0,\n\t0,\n\t30080,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30082,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30084,\n\t30090,\n\t0,\n\t0,\n\t30091,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30098,\n\t30118,\n\t0,\n\t30119,\n\t0,\n\t30121,\n\t30130,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30131,\n\t30132,\n\t30133,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30135,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30136,\n\t0,\n\t0,\n\t30137,\n\t30138,\n\t0,\n\t0,\n\t0,\n\t30139,\n\t30146,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30147,\n\t0,\n\t0,\n\t30148,\n\t30151,\n\t0,\n\t0,\n\t0,\n\t30168,\n\t0,\n\t30172,\n\t30173,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30180,\n\t30181,\n\t0,\n\t30192,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30194,\n\t30196,\n\t0,\n\t0,\n\t30199,\n\t0,\n\t0,\n\t30202,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30203,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30213,\n\t0,\n\t0,\n\t0,\n\t30216,\n\t0,\n\t0,\n\t30217,\n\t0,\n\t0,\n\t0,\n\t30218,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30219,\n\t0,\n\t30220,\n\t0,\n\t30222,\n\t30227,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30231,\n\t0,\n\t0,\n\t30233,\n\t30235,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30238,\n\t0,\n\t30240,\n\t30243,\n\t30245,\n\t0,\n\t30250,\n\t30252,\n\t0,\n\t0,\n\t0,\n\t30269,\n\t0,\n\t0,\n\t30271,\n\t30272,\n\t0,\n\t0,\n\t0,\n\t30278,\n\t30280,\n\t0,\n\t0,\n\t30282,\n\t0,\n\t30284,\n\t0,\n\t30294,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30295,\n\t30296,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30298,\n\t30299,\n\t30302,\n\t30304,\n\t30306,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30316,\n\t30317,\n\t0,\n\t0,\n\t0,\n\t30318,\n\t0,\n\t0,\n\t0,\n\t30319,\n\t0,\n\t30320,\n\t30322,\n\t30326,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30327,\n\t0,\n\t30332,\n\t30348,\n\t30349,\n\t0,\n\t0,\n\t30356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30357,\n\t0,\n\t30358,\n\t0,\n\t30359,\n\t30360,\n\t0,\n\t0,\n\t30365,\n\t30366,\n\t30378,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30379,\n\t0,\n\t0,\n\t30381,\n\t0,\n\t30385,\n\t0,\n\t30388,\n\t30397,\n\t0,\n\t0,\n\t0,\n\t30401,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30403,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30404,\n\t0,\n\t0,\n\t30405,\n\t0,\n\t30406,\n\t30408,\n\t0,\n\t30409,\n\t0,\n\t30410,\n\t0,\n\t0,\n\t0,\n\t30417,\n\t0,\n\t0,\n\t30418,\n\t30419,\n\t0,\n\t30420,\n\t0,\n\t30424,\n\t0,\n\t0,\n\t0,\n\t30427,\n\t30430,\n\t30432,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30433,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30436,\n\t0,\n\t30437,\n\t30438,\n\t0,\n\t30441,\n\t30442,\n\t0,\n\t0,\n\t0,\n\t30445,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30452,\n\t30456,\n\t30457,\n\t0,\n\t0,\n\t0,\n\t30458,\n\t0,\n\t30464,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30467,\n\t0,\n\t30469,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30477,\n\t0,\n\t0,\n\t30484,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30485,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30486,\n\t30487,\n\t30497,\n\t30498,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30505,\n\t0,\n\t30508,\n\t0,\n\t0,\n\t0,\n\t30509,\n\t30510,\n\t0,\n\t30514,\n\t30516,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30523,\n\t0,\n\t30524,\n\t0,\n\t30525,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30537,\n\t0,\n\t0,\n\t30538,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30553,\n\t0,\n\t0,\n\t30555,\n\t30556,\n\t30558,\n\t30559,\n\t30560,\n\t0,\n\t0,\n\t30561,\n\t0,\n\t30562,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30563,\n\t30570,\n\t30571,\n\t0,\n\t30586,\n\t30587,\n\t0,\n\t0,\n\t30590,\n\t0,\n\t0,\n\t30594,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30611,\n\t30612,\n\t30623,\n\t30634,\n\t0,\n\t0,\n\t30636,\n\t30640,\n\t30655,\n\t30656,\n\t0,\n\t30657,\n\t0,\n\t0,\n\t30658,\n\t30669,\n\t0,\n\t30670,\n\t0,\n\t30676,\n\t30678,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30679,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30695,\n\t0,\n\t0,\n\t30698,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30700,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30701,\n\t0,\n\t30702,\n\t30703,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30707,\n\t0,\n\t0,\n\t0,\n\t30709,\n\t0,\n\t0,\n\t30710,\n\t30719,\n\t30729,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30731,\n\t0,\n\t0,\n\t30733,\n\t0,\n\t0,\n\t0,\n\t30734,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30736,\n\t30737,\n\t0,\n\t0,\n\t0,\n\t30740,\n\t0,\n\t0,\n\t0,\n\t30743,\n\t0,\n\t30746,\n\t0,\n\t30747,\n\t30748,\n\t0,\n\t0,\n\t30751,\n\t30752,\n\t30753,\n\t0,\n\t0,\n\t0,\n\t30754,\n\t0,\n\t0,\n\t30760,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30763,\n\t0,\n\t30764,\n\t0,\n\t0,\n\t30766,\n\t0,\n\t30769,\n\t30770,\n\t30771,\n\t30774,\n\t30777,\n\t0,\n\t0,\n\t30779,\n\t30780,\n\t30781,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30790,\n\t0,\n\t0,\n\t0,\n\t30792,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30810,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30812,\n\t30819,\n\t0,\n\t0,\n\t30823,\n\t30824,\n\t0,\n\t30825,\n\t0,\n\t30827,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30828,\n\t0,\n\t0,\n\t30830,\n\t0,\n\t0,\n\t0,\n\t30834,\n\t0,\n\t30835,\n\t0,\n\t30837,\n\t30838,\n\t0,\n\t30845,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30846,\n\t30847,\n\t0,\n\t0,\n\t30849,\n\t0,\n\t30851,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30852,\n\t30858,\n\t0,\n\t0,\n\t30859,\n\t0,\n\t30865,\n\t0,\n\t0,\n\t30866,\n\t0,\n\t0,\n\t30868,\n\t0,\n\t0,\n\t30869,\n\t0,\n\t0,\n\t0,\n\t30881,\n\t30883,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30889,\n\t0,\n\t30891,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30894,\n\t0,\n\t30895,\n\t0,\n\t30897,\n\t0,\n\t30898,\n\t0,\n\t0,\n\t0,\n\t30904,\n\t30906,\n\t0,\n\t30909,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30910,\n\t0,\n\t0,\n\t0,\n\t30915,\n\t30933,\n\t30942,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30943,\n\t0,\n\t0,\n\t30945,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30946,\n\t0,\n\t0,\n\t30947,\n\t0,\n\t0,\n\t30955,\n\t30956,\n\t0,\n\t0,\n\t30960,\n\t0,\n\t0,\n\t30961,\n\t30962,\n\t30966,\n\t0,\n\t0,\n\t30969,\n\t30974,\n\t0,\n\t0,\n\t0,\n\t30976,\n\t0,\n\t0,\n\t30977,\n\t0,\n\t30978,\n\t30982,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t30994,\n\t30995,\n\t30998,\n\t0,\n\t31000,\n\t0,\n\t0,\n\t31001,\n\t0,\n\t0,\n\t31003,\n\t31005,\n\t0,\n\t0,\n\t31006,\n\t31011,\n\t0,\n\t0,\n\t31014,\n\t0,\n\t31016,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31018,\n\t0,\n\t0,\n\t31020,\n\t31023,\n\t31024,\n\t31025,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31027,\n\t31028,\n\t31029,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31032,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31036,\n\t31037,\n\t31038,\n\t0,\n\t0,\n\t0,\n\t31041,\n\t31043,\n\t31045,\n\t0,\n\t31047,\n\t0,\n\t0,\n\t0,\n\t31048,\n\t0,\n\t31049,\n\t0,\n\t0,\n\t0,\n\t31053,\n\t31054,\n\t31055,\n\t0,\n\t0,\n\t31063,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31066,\n\t0,\n\t31068,\n\t31071,\n\t0,\n\t0,\n\t0,\n\t31072,\n\t31073,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31075,\n\t0,\n\t0,\n\t31076,\n\t0,\n\t0,\n\t0,\n\t31077,\n\t31079,\n\t0,\n\t31080,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31087,\n\t0,\n\t31142,\n\t0,\n\t31144,\n\t0,\n\t0,\n\t31145,\n\t31146,\n\t31147,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31149,\n\t0,\n\t31151,\n\t31152,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31162,\n\t31171,\n\t31174,\n\t31175,\n\t0,\n\t0,\n\t0,\n\t31176,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31179,\n\t0,\n\t0,\n\t0,\n\t31186,\n\t0,\n\t0,\n\t0,\n\t31192,\n\t31195,\n\t0,\n\t0,\n\t31196,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31198,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31199,\n\t0,\n\t0,\n\t0,\n\t31205,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31211,\n\t31215,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31231,\n\t0,\n\t31232,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31233,\n\t31236,\n\t31253,\n\t0,\n\t31254,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31255,\n\t0,\n\t0,\n\t31257,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31258,\n\t31259,\n\t0,\n\t0,\n\t31260,\n\t0,\n\t31261,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31262,\n\t31263,\n\t0,\n\t0,\n\t31264,\n\t0,\n\t31266,\n\t0,\n\t31267,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31281,\n\t0,\n\t31282,\n\t0,\n\t31284,\n\t0,\n\t0,\n\t31285,\n\t31287,\n\t31288,\n\t0,\n\t0,\n\t31290,\n\t0,\n\t0,\n\t0,\n\t31292,\n\t31295,\n\t0,\n\t31299,\n\t0,\n\t31300,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31302,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31303,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31304,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31305,\n\t31308,\n\t31309,\n\t31315,\n\t0,\n\t31317,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31323,\n\t0,\n\t31324,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31325,\n\t31327,\n\t0,\n\t0,\n\t31331,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31333,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31336,\n\t0,\n\t0,\n\t31337,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31338,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31339,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31342,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31345,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31347,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31348,\n\t0,\n\t0,\n\t31350,\n\t31351,\n\t0,\n\t31352,\n\t0,\n\t0,\n\t31354,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31355,\n\t0,\n\t0,\n\t31356,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31363,\n\t0,\n\t31372,\n\t0,\n\t0,\n\t31373,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31376,\n\t0,\n\t31388,\n\t0,\n\t31389,\n\t0,\n\t31392,\n\t0,\n\t31401,\n\t0,\n\t31405,\n\t31407,\n\t31408,\n\t0,\n\t31409,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31413,\n\t31415,\n\t0,\n\t0,\n\t0,\n\t31416,\n\t31418,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31422,\n\t31423,\n\t0,\n\t0,\n\t31424,\n\t0,\n\t31425,\n\t31432,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31433,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31434,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31435,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31438,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31442,\n\t0,\n\t31444,\n\t0,\n\t31448,\n\t0,\n\t0,\n\t31451,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31452,\n\t0,\n\t31461,\n\t31465,\n\t0,\n\t0,\n\t31466,\n\t0,\n\t0,\n\t31467,\n\t0,\n\t0,\n\t31468,\n\t0,\n\t0,\n\t0,\n\t31469,\n\t31473,\n\t0,\n\t31476,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31489,\n\t31490,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31492,\n\t31493,\n\t31494,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31501,\n\t31504,\n\t31505,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31509,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31510,\n\t0,\n\t0,\n\t31511,\n\t0,\n\t0,\n\t31513,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31514,\n\t0,\n\t31522,\n\t31536,\n\t31539,\n\t31540,\n\t0,\n\t31541,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31546,\n\t31553,\n\t31559,\n\t0,\n\t0,\n\t0,\n\t31560,\n\t31561,\n\t31562,\n\t0,\n\t0,\n\t31564,\n\t31567,\n\t0,\n\t31569,\n\t0,\n\t0,\n\t0,\n\t31570,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31571,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31572,\n\t31574,\n\t31580,\n\t31581,\n\t0,\n\t0,\n\t31582,\n\t31584,\n\t31585,\n\t31586,\n\t31595,\n\t0,\n\t31596,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31597,\n\t0,\n\t31599,\n\t0,\n\t31600,\n\t31601,\n\t0,\n\t0,\n\t31603,\n\t31604,\n\t0,\n\t0,\n\t31608,\n\t31610,\n\t0,\n\t0,\n\t0,\n\t31611,\n\t0,\n\t31615,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31616,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31617,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31618,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31621,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31622,\n\t31625,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31627,\n\t0,\n\t31641,\n\t0,\n\t0,\n\t31642,\n\t0,\n\t0,\n\t31643,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31644,\n\t0,\n\t31646,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31648,\n\t0,\n\t0,\n\t0,\n\t31652,\n\t0,\n\t0,\n\t0,\n\t31657,\n\t0,\n\t0,\n\t31676,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t0,\n\t31689,\n\t31691,\n\t31692,\n\t0,\n\t31694,\n\t0,\n\t0,\n\t0,\n\t31696,\n\t0,\n\t31702,\n\t0,\n\t31703,\n\t0,\n}\n\nvar kStaticDictionaryWords = [31705]dictWord{\n\tdictWord{0, 0, 0},\n\tdictWord{8, 0, 1002},\n\tdictWord{136, 0, 1015},\n\tdictWord{4, 0, 683},\n\tdictWord{4, 10, 325},\n\tdictWord{138, 10, 125},\n\tdictWord{7, 11, 572},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t592,\n\t},\n\tdictWord{11, 11, 680},\n\tdictWord{11, 11, 842},\n\tdictWord{11, 11, 924},\n\tdictWord{12, 11, 356},\n\tdictWord{12, 11, 550},\n\tdictWord{13, 11, 317},\n\tdictWord{13, 11, 370},\n\tdictWord{13, 11, 469},\n\tdictWord{13, 11, 471},\n\tdictWord{14, 11, 397},\n\tdictWord{18, 11, 69},\n\tdictWord{146, 11, 145},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1265,\n\t},\n\tdictWord{136, 11, 534},\n\tdictWord{134, 0, 1431},\n\tdictWord{11, 0, 138},\n\tdictWord{140, 0, 40},\n\tdictWord{4, 0, 155},\n\tdictWord{7, 0, 1689},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t718,\n\t},\n\tdictWord{135, 10, 1216},\n\tdictWord{4, 0, 245},\n\tdictWord{5, 0, 151},\n\tdictWord{5, 0, 741},\n\tdictWord{6, 0, 1147},\n\tdictWord{7, 0, 498},\n\tdictWord{7, 0, 870},\n\tdictWord{7, 0, 1542},\n\tdictWord{12, 0, 213},\n\tdictWord{14, 0, 36},\n\tdictWord{14, 0, 391},\n\tdictWord{17, 0, 111},\n\tdictWord{18, 0, 6},\n\tdictWord{18, 0, 46},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t151,\n\t},\n\tdictWord{19, 0, 36},\n\tdictWord{20, 0, 32},\n\tdictWord{20, 0, 56},\n\tdictWord{20, 0, 69},\n\tdictWord{20, 0, 102},\n\tdictWord{21, 0, 4},\n\tdictWord{22, 0, 8},\n\tdictWord{\n\t\t22,\n\t\t0,\n\t\t10,\n\t},\n\tdictWord{22, 0, 14},\n\tdictWord{150, 0, 31},\n\tdictWord{4, 0, 624},\n\tdictWord{135, 0, 1752},\n\tdictWord{5, 10, 124},\n\tdictWord{5, 10, 144},\n\tdictWord{6, 10, 548},\n\tdictWord{7, 10, 15},\n\tdictWord{7, 10, 153},\n\tdictWord{137, 10, 629},\n\tdictWord{6, 0, 503},\n\tdictWord{9, 0, 586},\n\tdictWord{13, 0, 468},\n\tdictWord{14, 0, 66},\n\tdictWord{\n\t\t16,\n\t\t0,\n\t\t58,\n\t},\n\tdictWord{7, 10, 1531},\n\tdictWord{8, 10, 416},\n\tdictWord{9, 10, 275},\n\tdictWord{10, 10, 100},\n\tdictWord{11, 10, 658},\n\tdictWord{11, 10, 979},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t86,\n\t},\n\tdictWord{14, 10, 207},\n\tdictWord{15, 10, 20},\n\tdictWord{143, 10, 25},\n\tdictWord{5, 0, 603},\n\tdictWord{7, 0, 1212},\n\tdictWord{9, 0, 565},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t301,\n\t},\n\tdictWord{5, 10, 915},\n\tdictWord{6, 10, 1783},\n\tdictWord{7, 10, 211},\n\tdictWord{7, 10, 1353},\n\tdictWord{9, 10, 83},\n\tdictWord{10, 10, 376},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t431,\n\t},\n\tdictWord{11, 10, 543},\n\tdictWord{12, 10, 664},\n\tdictWord{13, 10, 280},\n\tdictWord{13, 10, 428},\n\tdictWord{14, 10, 128},\n\tdictWord{17, 10, 52},\n\tdictWord{\n\t\t145,\n\t\t10,\n\t\t81,\n\t},\n\tdictWord{4, 0, 492},\n\tdictWord{133, 0, 451},\n\tdictWord{135, 0, 835},\n\tdictWord{141, 0, 70},\n\tdictWord{132, 0, 539},\n\tdictWord{7, 11, 748},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t700,\n\t},\n\tdictWord{7, 11, 1517},\n\tdictWord{11, 11, 597},\n\tdictWord{14, 11, 76},\n\tdictWord{14, 11, 335},\n\tdictWord{148, 11, 33},\n\tdictWord{6, 0, 113},\n\tdictWord{135, 0, 436},\n\tdictWord{4, 10, 338},\n\tdictWord{133, 10, 400},\n\tdictWord{136, 0, 718},\n\tdictWord{133, 11, 127},\n\tdictWord{133, 11, 418},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1505,\n\t},\n\tdictWord{7, 0, 520},\n\tdictWord{6, 11, 198},\n\tdictWord{11, 10, 892},\n\tdictWord{140, 11, 83},\n\tdictWord{4, 10, 221},\n\tdictWord{5, 10, 659},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t989,\n\t},\n\tdictWord{7, 10, 697},\n\tdictWord{7, 10, 1211},\n\tdictWord{138, 10, 284},\n\tdictWord{135, 0, 1070},\n\tdictWord{5, 11, 276},\n\tdictWord{6, 11, 55},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1369,\n\t},\n\tdictWord{134, 0, 1515},\n\tdictWord{6, 11, 1752},\n\tdictWord{136, 11, 726},\n\tdictWord{138, 10, 507},\n\tdictWord{15, 0, 78},\n\tdictWord{4, 10, 188},\n\tdictWord{135, 10, 805},\n\tdictWord{5, 10, 884},\n\tdictWord{139, 10, 991},\n\tdictWord{133, 11, 764},\n\tdictWord{134, 10, 1653},\n\tdictWord{6, 11, 309},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t331,\n\t},\n\tdictWord{138, 11, 550},\n\tdictWord{135, 11, 1861},\n\tdictWord{132, 11, 348},\n\tdictWord{135, 11, 986},\n\tdictWord{135, 11, 1573},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t610,\n\t},\n\tdictWord{13, 0, 431},\n\tdictWord{144, 0, 59},\n\tdictWord{9, 11, 799},\n\tdictWord{140, 10, 166},\n\tdictWord{134, 0, 1530},\n\tdictWord{132, 0, 750},\n\tdictWord{132, 0, 307},\n\tdictWord{133, 0, 964},\n\tdictWord{6, 11, 194},\n\tdictWord{7, 11, 133},\n\tdictWord{10, 11, 493},\n\tdictWord{10, 11, 570},\n\tdictWord{139, 11, 664},\n\tdictWord{5, 11, 24},\n\tdictWord{5, 11, 569},\n\tdictWord{6, 11, 3},\n\tdictWord{6, 11, 119},\n\tdictWord{6, 11, 143},\n\tdictWord{6, 11, 440},\n\tdictWord{7, 11, 295},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t599,\n\t},\n\tdictWord{7, 11, 1686},\n\tdictWord{7, 11, 1854},\n\tdictWord{8, 11, 424},\n\tdictWord{9, 11, 43},\n\tdictWord{9, 11, 584},\n\tdictWord{9, 11, 760},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t148,\n\t},\n\tdictWord{10, 11, 328},\n\tdictWord{11, 11, 159},\n\tdictWord{11, 11, 253},\n\tdictWord{11, 11, 506},\n\tdictWord{12, 11, 487},\n\tdictWord{12, 11, 531},\n\tdictWord{144, 11, 33},\n\tdictWord{136, 10, 760},\n\tdictWord{5, 11, 14},\n\tdictWord{5, 11, 892},\n\tdictWord{6, 11, 283},\n\tdictWord{7, 11, 234},\n\tdictWord{136, 11, 537},\n\tdictWord{135, 11, 1251},\n\tdictWord{4, 11, 126},\n\tdictWord{8, 11, 635},\n\tdictWord{147, 11, 34},\n\tdictWord{4, 11, 316},\n\tdictWord{135, 11, 1561},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t999,\n\t},\n\tdictWord{6, 0, 1310},\n\tdictWord{137, 11, 861},\n\tdictWord{4, 11, 64},\n\tdictWord{5, 11, 352},\n\tdictWord{5, 11, 720},\n\tdictWord{6, 11, 368},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t359,\n\t},\n\tdictWord{4, 0, 75},\n\tdictWord{5, 0, 180},\n\tdictWord{6, 0, 500},\n\tdictWord{7, 0, 58},\n\tdictWord{7, 0, 710},\n\tdictWord{10, 0, 645},\n\tdictWord{136, 10, 770},\n\tdictWord{133, 0, 649},\n\tdictWord{6, 0, 276},\n\tdictWord{7, 0, 282},\n\tdictWord{7, 0, 879},\n\tdictWord{7, 0, 924},\n\tdictWord{8, 0, 459},\n\tdictWord{9, 0, 599},\n\tdictWord{9, 0, 754},\n\tdictWord{11, 0, 574},\n\tdictWord{12, 0, 128},\n\tdictWord{12, 0, 494},\n\tdictWord{13, 0, 52},\n\tdictWord{13, 0, 301},\n\tdictWord{15, 0, 30},\n\tdictWord{143, 0, 132},\n\tdictWord{132, 0, 200},\n\tdictWord{4, 10, 89},\n\tdictWord{5, 10, 489},\n\tdictWord{6, 10, 315},\n\tdictWord{7, 10, 553},\n\tdictWord{7, 10, 1745},\n\tdictWord{138, 10, 243},\n\tdictWord{135, 11, 1050},\n\tdictWord{7, 0, 1621},\n\tdictWord{6, 10, 1658},\n\tdictWord{9, 10, 3},\n\tdictWord{10, 10, 154},\n\tdictWord{11, 10, 641},\n\tdictWord{13, 10, 85},\n\tdictWord{13, 10, 201},\n\tdictWord{141, 10, 346},\n\tdictWord{6, 11, 175},\n\tdictWord{137, 11, 289},\n\tdictWord{5, 11, 432},\n\tdictWord{133, 11, 913},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t225,\n\t},\n\tdictWord{137, 0, 211},\n\tdictWord{7, 0, 718},\n\tdictWord{8, 0, 687},\n\tdictWord{139, 0, 374},\n\tdictWord{4, 10, 166},\n\tdictWord{133, 10, 505},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t110,\n\t},\n\tdictWord{134, 10, 1670},\n\tdictWord{8, 0, 58},\n\tdictWord{9, 0, 724},\n\tdictWord{11, 0, 809},\n\tdictWord{13, 0, 113},\n\tdictWord{145, 0, 72},\n\tdictWord{6, 0, 345},\n\tdictWord{7, 0, 1247},\n\tdictWord{144, 11, 82},\n\tdictWord{5, 11, 931},\n\tdictWord{134, 11, 1698},\n\tdictWord{8, 0, 767},\n\tdictWord{8, 0, 803},\n\tdictWord{9, 0, 301},\n\tdictWord{137, 0, 903},\n\tdictWord{139, 0, 203},\n\tdictWord{134, 0, 1154},\n\tdictWord{7, 0, 1949},\n\tdictWord{136, 0, 674},\n\tdictWord{134, 0, 259},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1275,\n\t},\n\tdictWord{5, 11, 774},\n\tdictWord{6, 11, 1637},\n\tdictWord{6, 11, 1686},\n\tdictWord{134, 11, 1751},\n\tdictWord{134, 0, 1231},\n\tdictWord{7, 10, 445},\n\tdictWord{8, 10, 307},\n\tdictWord{8, 10, 704},\n\tdictWord{10, 10, 41},\n\tdictWord{10, 10, 439},\n\tdictWord{11, 10, 237},\n\tdictWord{11, 10, 622},\n\tdictWord{140, 10, 201},\n\tdictWord{136, 0, 254},\n\tdictWord{6, 11, 260},\n\tdictWord{135, 11, 1484},\n\tdictWord{139, 0, 277},\n\tdictWord{135, 10, 1977},\n\tdictWord{4, 10, 189},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t713,\n\t},\n\tdictWord{6, 11, 573},\n\tdictWord{136, 10, 57},\n\tdictWord{138, 10, 371},\n\tdictWord{132, 10, 552},\n\tdictWord{134, 11, 344},\n\tdictWord{133, 0, 248},\n\tdictWord{9, 0, 800},\n\tdictWord{10, 0, 693},\n\tdictWord{11, 0, 482},\n\tdictWord{11, 0, 734},\n\tdictWord{11, 0, 789},\n\tdictWord{134, 11, 240},\n\tdictWord{4, 0, 116},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t95,\n\t},\n\tdictWord{5, 0, 445},\n\tdictWord{7, 0, 1688},\n\tdictWord{8, 0, 29},\n\tdictWord{9, 0, 272},\n\tdictWord{11, 0, 509},\n\tdictWord{11, 0, 915},\n\tdictWord{4, 11, 292},\n\tdictWord{4, 11, 736},\n\tdictWord{5, 11, 871},\n\tdictWord{6, 11, 171},\n\tdictWord{6, 11, 1689},\n\tdictWord{7, 11, 1324},\n\tdictWord{7, 11, 1944},\n\tdictWord{9, 11, 415},\n\tdictWord{9, 11, 580},\n\tdictWord{14, 11, 230},\n\tdictWord{146, 11, 68},\n\tdictWord{7, 0, 490},\n\tdictWord{13, 0, 100},\n\tdictWord{143, 0, 75},\n\tdictWord{135, 0, 1641},\n\tdictWord{133, 0, 543},\n\tdictWord{7, 11, 209},\n\tdictWord{8, 11, 661},\n\tdictWord{10, 11, 42},\n\tdictWord{11, 11, 58},\n\tdictWord{12, 11, 58},\n\tdictWord{12, 11, 118},\n\tdictWord{141, 11, 32},\n\tdictWord{5, 0, 181},\n\tdictWord{8, 0, 41},\n\tdictWord{6, 11, 63},\n\tdictWord{135, 11, 920},\n\tdictWord{133, 0, 657},\n\tdictWord{133, 11, 793},\n\tdictWord{138, 0, 709},\n\tdictWord{7, 0, 25},\n\tdictWord{8, 0, 202},\n\tdictWord{138, 0, 536},\n\tdictWord{5, 11, 665},\n\tdictWord{135, 10, 1788},\n\tdictWord{145, 10, 49},\n\tdictWord{9, 0, 423},\n\tdictWord{140, 0, 89},\n\tdictWord{5, 11, 67},\n\tdictWord{6, 11, 62},\n\tdictWord{6, 11, 374},\n\tdictWord{135, 11, 1391},\n\tdictWord{8, 0, 113},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t877,\n\t},\n\tdictWord{10, 0, 554},\n\tdictWord{11, 0, 83},\n\tdictWord{12, 0, 136},\n\tdictWord{19, 0, 109},\n\tdictWord{9, 11, 790},\n\tdictWord{140, 11, 47},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t661,\n\t},\n\tdictWord{4, 0, 963},\n\tdictWord{10, 0, 927},\n\tdictWord{14, 0, 442},\n\tdictWord{135, 10, 1945},\n\tdictWord{133, 0, 976},\n\tdictWord{132, 0, 206},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t391,\n\t},\n\tdictWord{135, 11, 1169},\n\tdictWord{134, 0, 2002},\n\tdictWord{6, 0, 696},\n\tdictWord{134, 0, 1008},\n\tdictWord{134, 0, 1170},\n\tdictWord{132, 11, 271},\n\tdictWord{7, 0, 13},\n\tdictWord{8, 0, 226},\n\tdictWord{10, 0, 537},\n\tdictWord{11, 0, 570},\n\tdictWord{11, 0, 605},\n\tdictWord{11, 0, 799},\n\tdictWord{11, 0, 804},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t85,\n\t},\n\tdictWord{12, 0, 516},\n\tdictWord{12, 0, 623},\n\tdictWord{13, 0, 112},\n\tdictWord{13, 0, 361},\n\tdictWord{14, 0, 77},\n\tdictWord{14, 0, 78},\n\tdictWord{17, 0, 28},\n\tdictWord{19, 0, 110},\n\tdictWord{140, 11, 314},\n\tdictWord{132, 0, 769},\n\tdictWord{134, 0, 1544},\n\tdictWord{4, 0, 551},\n\tdictWord{137, 0, 678},\n\tdictWord{5, 10, 84},\n\tdictWord{134, 10, 163},\n\tdictWord{9, 0, 57},\n\tdictWord{9, 0, 459},\n\tdictWord{10, 0, 425},\n\tdictWord{11, 0, 119},\n\tdictWord{12, 0, 184},\n\tdictWord{12, 0, 371},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t358,\n\t},\n\tdictWord{145, 0, 51},\n\tdictWord{5, 0, 188},\n\tdictWord{5, 0, 814},\n\tdictWord{8, 0, 10},\n\tdictWord{9, 0, 421},\n\tdictWord{9, 0, 729},\n\tdictWord{10, 0, 609},\n\tdictWord{11, 0, 689},\n\tdictWord{4, 11, 253},\n\tdictWord{5, 10, 410},\n\tdictWord{5, 11, 544},\n\tdictWord{7, 11, 300},\n\tdictWord{137, 11, 340},\n\tdictWord{134, 0, 624},\n\tdictWord{138, 11, 321},\n\tdictWord{135, 0, 1941},\n\tdictWord{18, 0, 130},\n\tdictWord{5, 10, 322},\n\tdictWord{8, 10, 186},\n\tdictWord{9, 10, 262},\n\tdictWord{10, 10, 187},\n\tdictWord{142, 10, 208},\n\tdictWord{5, 11, 53},\n\tdictWord{5, 11, 541},\n\tdictWord{6, 11, 94},\n\tdictWord{6, 11, 499},\n\tdictWord{7, 11, 230},\n\tdictWord{139, 11, 321},\n\tdictWord{133, 10, 227},\n\tdictWord{4, 0, 378},\n\tdictWord{4, 11, 920},\n\tdictWord{5, 11, 25},\n\tdictWord{5, 11, 790},\n\tdictWord{6, 11, 457},\n\tdictWord{135, 11, 853},\n\tdictWord{137, 0, 269},\n\tdictWord{132, 0, 528},\n\tdictWord{134, 0, 1146},\n\tdictWord{7, 10, 1395},\n\tdictWord{8, 10, 486},\n\tdictWord{9, 10, 236},\n\tdictWord{9, 10, 878},\n\tdictWord{10, 10, 218},\n\tdictWord{11, 10, 95},\n\tdictWord{19, 10, 17},\n\tdictWord{147, 10, 31},\n\tdictWord{7, 10, 2043},\n\tdictWord{8, 10, 672},\n\tdictWord{\n\t\t141,\n\t\t10,\n\t\t448,\n\t},\n\tdictWord{134, 0, 1105},\n\tdictWord{134, 0, 1616},\n\tdictWord{134, 11, 1765},\n\tdictWord{140, 11, 163},\n\tdictWord{5, 10, 412},\n\tdictWord{133, 11, 822},\n\tdictWord{132, 11, 634},\n\tdictWord{6, 0, 656},\n\tdictWord{134, 11, 1730},\n\tdictWord{134, 0, 1940},\n\tdictWord{5, 0, 104},\n\tdictWord{6, 0, 173},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1631,\n\t},\n\tdictWord{136, 10, 562},\n\tdictWord{6, 11, 36},\n\tdictWord{7, 11, 658},\n\tdictWord{8, 11, 454},\n\tdictWord{147, 11, 86},\n\tdictWord{5, 0, 457},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1771,\n\t},\n\tdictWord{7, 0, 810},\n\tdictWord{8, 0, 138},\n\tdictWord{8, 0, 342},\n\tdictWord{9, 0, 84},\n\tdictWord{10, 0, 193},\n\tdictWord{11, 0, 883},\n\tdictWord{140, 0, 359},\n\tdictWord{9, 0, 620},\n\tdictWord{135, 10, 1190},\n\tdictWord{137, 10, 132},\n\tdictWord{7, 11, 975},\n\tdictWord{137, 11, 789},\n\tdictWord{6, 0, 95},\n\tdictWord{6, 0, 1934},\n\tdictWord{136, 0, 967},\n\tdictWord{141, 11, 335},\n\tdictWord{6, 0, 406},\n\tdictWord{10, 0, 409},\n\tdictWord{10, 0, 447},\n\tdictWord{11, 0, 44},\n\tdictWord{140, 0, 100},\n\tdictWord{4, 10, 317},\n\tdictWord{135, 10, 1279},\n\tdictWord{132, 0, 477},\n\tdictWord{134, 0, 1268},\n\tdictWord{6, 0, 1941},\n\tdictWord{8, 0, 944},\n\tdictWord{5, 10, 63},\n\tdictWord{133, 10, 509},\n\tdictWord{132, 0, 629},\n\tdictWord{132, 11, 104},\n\tdictWord{4, 0, 246},\n\tdictWord{133, 0, 375},\n\tdictWord{6, 0, 1636},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t288,\n\t},\n\tdictWord{135, 11, 1614},\n\tdictWord{9, 0, 49},\n\tdictWord{10, 0, 774},\n\tdictWord{8, 10, 89},\n\tdictWord{8, 10, 620},\n\tdictWord{11, 10, 628},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t322,\n\t},\n\tdictWord{143, 10, 124},\n\tdictWord{4, 0, 282},\n\tdictWord{7, 0, 1034},\n\tdictWord{11, 0, 398},\n\tdictWord{11, 0, 634},\n\tdictWord{12, 0, 1},\n\tdictWord{12, 0, 79},\n\tdictWord{12, 0, 544},\n\tdictWord{14, 0, 237},\n\tdictWord{17, 0, 10},\n\tdictWord{146, 0, 20},\n\tdictWord{132, 0, 824},\n\tdictWord{7, 11, 45},\n\tdictWord{9, 11, 542},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t566,\n\t},\n\tdictWord{138, 11, 728},\n\tdictWord{5, 0, 118},\n\tdictWord{5, 0, 499},\n\tdictWord{6, 0, 476},\n\tdictWord{6, 0, 665},\n\tdictWord{6, 0, 1176},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1196,\n\t},\n\tdictWord{7, 0, 600},\n\tdictWord{7, 0, 888},\n\tdictWord{135, 0, 1096},\n\tdictWord{7, 0, 296},\n\tdictWord{7, 0, 596},\n\tdictWord{8, 0, 560},\n\tdictWord{8, 0, 586},\n\tdictWord{9, 0, 612},\n\tdictWord{11, 0, 304},\n\tdictWord{12, 0, 46},\n\tdictWord{13, 0, 89},\n\tdictWord{14, 0, 112},\n\tdictWord{145, 0, 122},\n\tdictWord{5, 0, 894},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1772,\n\t},\n\tdictWord{9, 0, 1009},\n\tdictWord{138, 10, 120},\n\tdictWord{5, 11, 533},\n\tdictWord{7, 11, 755},\n\tdictWord{138, 11, 780},\n\tdictWord{151, 10, 1},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1474,\n\t},\n\tdictWord{7, 11, 87},\n\tdictWord{142, 11, 288},\n\tdictWord{139, 0, 366},\n\tdictWord{137, 10, 461},\n\tdictWord{7, 11, 988},\n\tdictWord{7, 11, 1939},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t64,\n\t},\n\tdictWord{9, 11, 502},\n\tdictWord{12, 11, 7},\n\tdictWord{12, 11, 34},\n\tdictWord{13, 11, 12},\n\tdictWord{13, 11, 234},\n\tdictWord{147, 11, 77},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1599,\n\t},\n\tdictWord{7, 0, 1723},\n\tdictWord{8, 0, 79},\n\tdictWord{8, 0, 106},\n\tdictWord{8, 0, 190},\n\tdictWord{8, 0, 302},\n\tdictWord{8, 0, 383},\n\tdictWord{8, 0, 713},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t119,\n\t},\n\tdictWord{9, 0, 233},\n\tdictWord{9, 0, 419},\n\tdictWord{9, 0, 471},\n\tdictWord{10, 0, 181},\n\tdictWord{10, 0, 406},\n\tdictWord{11, 0, 57},\n\tdictWord{11, 0, 85},\n\tdictWord{11, 0, 120},\n\tdictWord{11, 0, 177},\n\tdictWord{11, 0, 296},\n\tdictWord{11, 0, 382},\n\tdictWord{11, 0, 454},\n\tdictWord{11, 0, 758},\n\tdictWord{11, 0, 999},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t27,\n\t},\n\tdictWord{12, 0, 98},\n\tdictWord{12, 0, 131},\n\tdictWord{12, 0, 245},\n\tdictWord{12, 0, 312},\n\tdictWord{12, 0, 446},\n\tdictWord{12, 0, 454},\n\tdictWord{13, 0, 25},\n\tdictWord{13, 0, 98},\n\tdictWord{13, 0, 426},\n\tdictWord{13, 0, 508},\n\tdictWord{14, 0, 70},\n\tdictWord{14, 0, 163},\n\tdictWord{14, 0, 272},\n\tdictWord{14, 0, 277},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t370,\n\t},\n\tdictWord{15, 0, 95},\n\tdictWord{15, 0, 138},\n\tdictWord{15, 0, 167},\n\tdictWord{17, 0, 38},\n\tdictWord{148, 0, 96},\n\tdictWord{135, 10, 1346},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t200,\n\t},\n\tdictWord{19, 0, 2},\n\tdictWord{151, 0, 22},\n\tdictWord{135, 11, 141},\n\tdictWord{134, 10, 85},\n\tdictWord{134, 0, 1759},\n\tdictWord{138, 0, 372},\n\tdictWord{\n\t\t145,\n\t\t0,\n\t\t16,\n\t},\n\tdictWord{8, 0, 943},\n\tdictWord{132, 11, 619},\n\tdictWord{139, 11, 88},\n\tdictWord{5, 11, 246},\n\tdictWord{8, 11, 189},\n\tdictWord{9, 11, 355},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t512,\n\t},\n\tdictWord{10, 11, 124},\n\tdictWord{10, 11, 453},\n\tdictWord{11, 11, 143},\n\tdictWord{11, 11, 416},\n\tdictWord{11, 11, 859},\n\tdictWord{141, 11, 341},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t258,\n\t},\n\tdictWord{134, 0, 719},\n\tdictWord{6, 0, 1798},\n\tdictWord{6, 0, 1839},\n\tdictWord{8, 0, 900},\n\tdictWord{10, 0, 874},\n\tdictWord{10, 0, 886},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t698,\n\t},\n\tdictWord{12, 0, 732},\n\tdictWord{12, 0, 770},\n\tdictWord{16, 0, 106},\n\tdictWord{18, 0, 163},\n\tdictWord{18, 0, 170},\n\tdictWord{18, 0, 171},\n\tdictWord{152, 0, 20},\n\tdictWord{9, 0, 707},\n\tdictWord{11, 0, 326},\n\tdictWord{11, 0, 339},\n\tdictWord{12, 0, 423},\n\tdictWord{12, 0, 502},\n\tdictWord{20, 0, 62},\n\tdictWord{9, 11, 707},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t326,\n\t},\n\tdictWord{11, 11, 339},\n\tdictWord{12, 11, 423},\n\tdictWord{12, 11, 502},\n\tdictWord{148, 11, 62},\n\tdictWord{5, 0, 30},\n\tdictWord{7, 0, 495},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t134,\n\t},\n\tdictWord{9, 0, 788},\n\tdictWord{140, 0, 438},\n\tdictWord{133, 11, 678},\n\tdictWord{5, 10, 279},\n\tdictWord{6, 10, 235},\n\tdictWord{7, 10, 468},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t446,\n\t},\n\tdictWord{9, 10, 637},\n\tdictWord{10, 10, 717},\n\tdictWord{11, 10, 738},\n\tdictWord{140, 10, 514},\n\tdictWord{5, 11, 35},\n\tdictWord{6, 11, 287},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t862,\n\t},\n\tdictWord{7, 11, 1886},\n\tdictWord{138, 11, 179},\n\tdictWord{7, 0, 1948},\n\tdictWord{7, 0, 2004},\n\tdictWord{132, 11, 517},\n\tdictWord{5, 10, 17},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t371,\n\t},\n\tdictWord{137, 10, 528},\n\tdictWord{4, 0, 115},\n\tdictWord{5, 0, 669},\n\tdictWord{6, 0, 407},\n\tdictWord{8, 0, 311},\n\tdictWord{11, 0, 10},\n\tdictWord{141, 0, 5},\n\tdictWord{137, 0, 381},\n\tdictWord{5, 0, 50},\n\tdictWord{6, 0, 439},\n\tdictWord{7, 0, 780},\n\tdictWord{135, 0, 1040},\n\tdictWord{136, 11, 667},\n\tdictWord{11, 11, 403},\n\tdictWord{146, 11, 83},\n\tdictWord{5, 0, 1},\n\tdictWord{6, 0, 81},\n\tdictWord{138, 0, 520},\n\tdictWord{134, 0, 738},\n\tdictWord{5, 0, 482},\n\tdictWord{8, 0, 98},\n\tdictWord{9, 0, 172},\n\tdictWord{10, 0, 360},\n\tdictWord{10, 0, 700},\n\tdictWord{10, 0, 822},\n\tdictWord{11, 0, 302},\n\tdictWord{11, 0, 778},\n\tdictWord{12, 0, 50},\n\tdictWord{12, 0, 127},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t396,\n\t},\n\tdictWord{13, 0, 62},\n\tdictWord{13, 0, 328},\n\tdictWord{14, 0, 122},\n\tdictWord{147, 0, 72},\n\tdictWord{9, 11, 157},\n\tdictWord{10, 11, 131},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t72,\n\t},\n\tdictWord{135, 11, 714},\n\tdictWord{135, 11, 539},\n\tdictWord{5, 0, 2},\n\tdictWord{6, 0, 512},\n\tdictWord{7, 0, 797},\n\tdictWord{7, 0, 1494},\n\tdictWord{8, 0, 253},\n\tdictWord{8, 0, 589},\n\tdictWord{9, 0, 77},\n\tdictWord{10, 0, 1},\n\tdictWord{10, 0, 129},\n\tdictWord{10, 0, 225},\n\tdictWord{11, 0, 118},\n\tdictWord{11, 0, 226},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t251,\n\t},\n\tdictWord{11, 0, 430},\n\tdictWord{11, 0, 701},\n\tdictWord{11, 0, 974},\n\tdictWord{11, 0, 982},\n\tdictWord{12, 0, 64},\n\tdictWord{12, 0, 260},\n\tdictWord{12, 0, 488},\n\tdictWord{140, 0, 690},\n\tdictWord{5, 11, 394},\n\tdictWord{7, 11, 367},\n\tdictWord{7, 11, 487},\n\tdictWord{7, 11, 857},\n\tdictWord{7, 11, 1713},\n\tdictWord{8, 11, 246},\n\tdictWord{9, 11, 537},\n\tdictWord{10, 11, 165},\n\tdictWord{12, 11, 219},\n\tdictWord{140, 11, 561},\n\tdictWord{136, 0, 557},\n\tdictWord{5, 10, 779},\n\tdictWord{5, 10, 807},\n\tdictWord{6, 10, 1655},\n\tdictWord{134, 10, 1676},\n\tdictWord{4, 10, 196},\n\tdictWord{5, 10, 558},\n\tdictWord{133, 10, 949},\n\tdictWord{11, 11, 827},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t56,\n\t},\n\tdictWord{14, 11, 34},\n\tdictWord{143, 11, 148},\n\tdictWord{137, 0, 347},\n\tdictWord{133, 0, 572},\n\tdictWord{134, 0, 832},\n\tdictWord{4, 0, 12},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t504,\n\t},\n\tdictWord{7, 0, 522},\n\tdictWord{7, 0, 809},\n\tdictWord{8, 0, 797},\n\tdictWord{141, 0, 88},\n\tdictWord{4, 10, 752},\n\tdictWord{133, 11, 449},\n\tdictWord{7, 11, 86},\n\tdictWord{8, 11, 103},\n\tdictWord{145, 11, 69},\n\tdictWord{7, 11, 2028},\n\tdictWord{138, 11, 641},\n\tdictWord{5, 0, 528},\n\tdictWord{6, 11, 1},\n\tdictWord{142, 11, 2},\n\tdictWord{134, 0, 861},\n\tdictWord{10, 0, 294},\n\tdictWord{4, 10, 227},\n\tdictWord{5, 10, 159},\n\tdictWord{5, 10, 409},\n\tdictWord{7, 10, 80},\n\tdictWord{10, 10, 479},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t418,\n\t},\n\tdictWord{14, 10, 50},\n\tdictWord{14, 10, 249},\n\tdictWord{142, 10, 295},\n\tdictWord{7, 10, 1470},\n\tdictWord{8, 10, 66},\n\tdictWord{8, 10, 137},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t761,\n\t},\n\tdictWord{9, 10, 638},\n\tdictWord{11, 10, 80},\n\tdictWord{11, 10, 212},\n\tdictWord{11, 10, 368},\n\tdictWord{11, 10, 418},\n\tdictWord{12, 10, 8},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t15,\n\t},\n\tdictWord{16, 10, 61},\n\tdictWord{17, 10, 59},\n\tdictWord{19, 10, 28},\n\tdictWord{148, 10, 84},\n\tdictWord{20, 0, 109},\n\tdictWord{135, 11, 1148},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t277,\n\t},\n\tdictWord{7, 11, 1274},\n\tdictWord{7, 11, 1386},\n\tdictWord{7, 11, 1392},\n\tdictWord{12, 11, 129},\n\tdictWord{146, 11, 87},\n\tdictWord{6, 11, 187},\n\tdictWord{7, 11, 39},\n\tdictWord{7, 11, 1203},\n\tdictWord{8, 11, 380},\n\tdictWord{8, 11, 542},\n\tdictWord{14, 11, 117},\n\tdictWord{149, 11, 28},\n\tdictWord{134, 0, 1187},\n\tdictWord{5, 0, 266},\n\tdictWord{9, 0, 290},\n\tdictWord{9, 0, 364},\n\tdictWord{10, 0, 293},\n\tdictWord{11, 0, 606},\n\tdictWord{142, 0, 45},\n\tdictWord{6, 11, 297},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t793,\n\t},\n\tdictWord{139, 11, 938},\n\tdictWord{4, 0, 50},\n\tdictWord{6, 0, 594},\n\tdictWord{9, 0, 121},\n\tdictWord{10, 0, 49},\n\tdictWord{10, 0, 412},\n\tdictWord{139, 0, 834},\n\tdictWord{136, 0, 748},\n\tdictWord{7, 11, 464},\n\tdictWord{8, 11, 438},\n\tdictWord{11, 11, 105},\n\tdictWord{11, 11, 363},\n\tdictWord{12, 11, 231},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t386,\n\t},\n\tdictWord{15, 11, 102},\n\tdictWord{148, 11, 75},\n\tdictWord{132, 0, 466},\n\tdictWord{13, 0, 399},\n\tdictWord{14, 0, 337},\n\tdictWord{6, 10, 38},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1220,\n\t},\n\tdictWord{8, 10, 185},\n\tdictWord{8, 10, 256},\n\tdictWord{9, 10, 22},\n\tdictWord{9, 10, 331},\n\tdictWord{10, 10, 738},\n\tdictWord{11, 10, 205},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t540,\n\t},\n\tdictWord{11, 10, 746},\n\tdictWord{13, 10, 465},\n\tdictWord{142, 10, 194},\n\tdictWord{9, 0, 378},\n\tdictWord{141, 0, 162},\n\tdictWord{137, 0, 519},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t159,\n\t},\n\tdictWord{6, 10, 115},\n\tdictWord{7, 10, 252},\n\tdictWord{7, 10, 257},\n\tdictWord{7, 10, 1928},\n\tdictWord{8, 10, 69},\n\tdictWord{9, 10, 384},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t91,\n\t},\n\tdictWord{10, 10, 615},\n\tdictWord{12, 10, 375},\n\tdictWord{14, 10, 235},\n\tdictWord{18, 10, 117},\n\tdictWord{147, 10, 123},\n\tdictWord{5, 11, 604},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t911,\n\t},\n\tdictWord{136, 10, 278},\n\tdictWord{132, 0, 667},\n\tdictWord{8, 0, 351},\n\tdictWord{9, 0, 322},\n\tdictWord{4, 10, 151},\n\tdictWord{135, 10, 1567},\n\tdictWord{134, 0, 902},\n\tdictWord{133, 10, 990},\n\tdictWord{12, 0, 180},\n\tdictWord{5, 10, 194},\n\tdictWord{7, 10, 1662},\n\tdictWord{137, 10, 90},\n\tdictWord{4, 0, 869},\n\tdictWord{134, 0, 1996},\n\tdictWord{134, 0, 813},\n\tdictWord{133, 10, 425},\n\tdictWord{137, 11, 761},\n\tdictWord{132, 0, 260},\n\tdictWord{133, 10, 971},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t20,\n\t},\n\tdictWord{6, 11, 298},\n\tdictWord{7, 11, 659},\n\tdictWord{7, 11, 1366},\n\tdictWord{137, 11, 219},\n\tdictWord{4, 0, 39},\n\tdictWord{5, 0, 36},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1843,\n\t},\n\tdictWord{8, 0, 407},\n\tdictWord{11, 0, 144},\n\tdictWord{140, 0, 523},\n\tdictWord{4, 0, 510},\n\tdictWord{10, 0, 587},\n\tdictWord{139, 10, 752},\n\tdictWord{7, 0, 29},\n\tdictWord{7, 0, 66},\n\tdictWord{7, 0, 1980},\n\tdictWord{10, 0, 487},\n\tdictWord{138, 0, 809},\n\tdictWord{13, 0, 260},\n\tdictWord{14, 0, 82},\n\tdictWord{18, 0, 63},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t662,\n\t},\n\tdictWord{5, 10, 72},\n\tdictWord{6, 10, 264},\n\tdictWord{7, 10, 21},\n\tdictWord{7, 10, 46},\n\tdictWord{7, 10, 2013},\n\tdictWord{8, 10, 215},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t513,\n\t},\n\tdictWord{10, 10, 266},\n\tdictWord{139, 10, 22},\n\tdictWord{134, 0, 570},\n\tdictWord{6, 0, 565},\n\tdictWord{7, 0, 1667},\n\tdictWord{4, 11, 439},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t95,\n\t},\n\tdictWord{11, 10, 603},\n\tdictWord{12, 11, 242},\n\tdictWord{13, 10, 443},\n\tdictWord{14, 10, 160},\n\tdictWord{143, 10, 4},\n\tdictWord{134, 0, 1464},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t431,\n\t},\n\tdictWord{9, 0, 372},\n\tdictWord{15, 0, 2},\n\tdictWord{19, 0, 10},\n\tdictWord{19, 0, 18},\n\tdictWord{5, 10, 874},\n\tdictWord{6, 10, 1677},\n\tdictWord{143, 10, 0},\n\tdictWord{132, 0, 787},\n\tdictWord{6, 0, 380},\n\tdictWord{12, 0, 399},\n\tdictWord{21, 0, 19},\n\tdictWord{7, 10, 939},\n\tdictWord{7, 10, 1172},\n\tdictWord{7, 10, 1671},\n\tdictWord{9, 10, 540},\n\tdictWord{10, 10, 696},\n\tdictWord{11, 10, 265},\n\tdictWord{11, 10, 732},\n\tdictWord{11, 10, 928},\n\tdictWord{11, 10, 937},\n\tdictWord{\n\t\t141,\n\t\t10,\n\t\t438,\n\t},\n\tdictWord{137, 0, 200},\n\tdictWord{132, 11, 233},\n\tdictWord{132, 0, 516},\n\tdictWord{134, 11, 577},\n\tdictWord{132, 0, 844},\n\tdictWord{11, 0, 887},\n\tdictWord{14, 0, 365},\n\tdictWord{142, 0, 375},\n\tdictWord{132, 11, 482},\n\tdictWord{8, 0, 821},\n\tdictWord{140, 0, 44},\n\tdictWord{7, 0, 1655},\n\tdictWord{136, 0, 305},\n\tdictWord{5, 10, 682},\n\tdictWord{135, 10, 1887},\n\tdictWord{135, 11, 346},\n\tdictWord{132, 10, 696},\n\tdictWord{4, 0, 10},\n\tdictWord{7, 0, 917},\n\tdictWord{139, 0, 786},\n\tdictWord{5, 11, 795},\n\tdictWord{6, 11, 1741},\n\tdictWord{8, 11, 417},\n\tdictWord{137, 11, 782},\n\tdictWord{4, 0, 1016},\n\tdictWord{134, 0, 2031},\n\tdictWord{5, 0, 684},\n\tdictWord{4, 10, 726},\n\tdictWord{133, 10, 630},\n\tdictWord{6, 0, 1021},\n\tdictWord{134, 0, 1480},\n\tdictWord{8, 10, 802},\n\tdictWord{136, 10, 838},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t27,\n\t},\n\tdictWord{134, 0, 395},\n\tdictWord{135, 11, 622},\n\tdictWord{7, 11, 625},\n\tdictWord{135, 11, 1750},\n\tdictWord{4, 11, 203},\n\tdictWord{135, 11, 1936},\n\tdictWord{6, 10, 118},\n\tdictWord{7, 10, 215},\n\tdictWord{7, 10, 1521},\n\tdictWord{140, 10, 11},\n\tdictWord{132, 0, 813},\n\tdictWord{136, 0, 511},\n\tdictWord{7, 10, 615},\n\tdictWord{138, 10, 251},\n\tdictWord{135, 10, 1044},\n\tdictWord{145, 0, 56},\n\tdictWord{133, 10, 225},\n\tdictWord{6, 0, 342},\n\tdictWord{6, 0, 496},\n\tdictWord{8, 0, 275},\n\tdictWord{137, 0, 206},\n\tdictWord{4, 0, 909},\n\tdictWord{133, 0, 940},\n\tdictWord{132, 0, 891},\n\tdictWord{7, 11, 311},\n\tdictWord{9, 11, 308},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t255,\n\t},\n\tdictWord{4, 10, 370},\n\tdictWord{5, 10, 756},\n\tdictWord{135, 10, 1326},\n\tdictWord{4, 0, 687},\n\tdictWord{134, 0, 1596},\n\tdictWord{134, 0, 1342},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1662,\n\t},\n\tdictWord{7, 10, 48},\n\tdictWord{8, 10, 771},\n\tdictWord{10, 10, 116},\n\tdictWord{13, 10, 104},\n\tdictWord{14, 10, 105},\n\tdictWord{14, 10, 184},\n\tdictWord{15, 10, 168},\n\tdictWord{19, 10, 92},\n\tdictWord{148, 10, 68},\n\tdictWord{138, 10, 209},\n\tdictWord{4, 11, 400},\n\tdictWord{5, 11, 267},\n\tdictWord{135, 11, 232},\n\tdictWord{151, 11, 12},\n\tdictWord{6, 0, 41},\n\tdictWord{141, 0, 160},\n\tdictWord{141, 11, 314},\n\tdictWord{134, 0, 1718},\n\tdictWord{136, 0, 778},\n\tdictWord{\n\t\t142,\n\t\t11,\n\t\t261,\n\t},\n\tdictWord{134, 0, 1610},\n\tdictWord{133, 0, 115},\n\tdictWord{132, 0, 294},\n\tdictWord{14, 0, 314},\n\tdictWord{132, 10, 120},\n\tdictWord{132, 0, 983},\n\tdictWord{5, 0, 193},\n\tdictWord{140, 0, 178},\n\tdictWord{138, 10, 429},\n\tdictWord{5, 10, 820},\n\tdictWord{135, 10, 931},\n\tdictWord{6, 0, 994},\n\tdictWord{6, 0, 1051},\n\tdictWord{6, 0, 1439},\n\tdictWord{7, 0, 174},\n\tdictWord{133, 11, 732},\n\tdictWord{4, 11, 100},\n\tdictWord{7, 11, 679},\n\tdictWord{8, 11, 313},\n\tdictWord{138, 10, 199},\n\tdictWord{6, 10, 151},\n\tdictWord{6, 10, 1675},\n\tdictWord{7, 10, 383},\n\tdictWord{151, 10, 10},\n\tdictWord{6, 0, 1796},\n\tdictWord{8, 0, 848},\n\tdictWord{8, 0, 867},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t907,\n\t},\n\tdictWord{10, 0, 855},\n\tdictWord{140, 0, 703},\n\tdictWord{140, 0, 221},\n\tdictWord{4, 0, 122},\n\tdictWord{5, 0, 796},\n\tdictWord{5, 0, 952},\n\tdictWord{6, 0, 1660},\n\tdictWord{6, 0, 1671},\n\tdictWord{8, 0, 567},\n\tdictWord{9, 0, 687},\n\tdictWord{9, 0, 742},\n\tdictWord{10, 0, 686},\n\tdictWord{11, 0, 682},\n\tdictWord{11, 0, 909},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t281,\n\t},\n\tdictWord{5, 11, 362},\n\tdictWord{5, 11, 443},\n\tdictWord{6, 11, 318},\n\tdictWord{7, 11, 1019},\n\tdictWord{139, 11, 623},\n\tdictWord{5, 11, 463},\n\tdictWord{136, 11, 296},\n\tdictWord{11, 0, 583},\n\tdictWord{13, 0, 262},\n\tdictWord{6, 10, 1624},\n\tdictWord{12, 10, 422},\n\tdictWord{142, 10, 360},\n\tdictWord{5, 0, 179},\n\tdictWord{7, 0, 1095},\n\tdictWord{135, 0, 1213},\n\tdictWord{4, 10, 43},\n\tdictWord{4, 11, 454},\n\tdictWord{5, 10, 344},\n\tdictWord{133, 10, 357},\n\tdictWord{4, 0, 66},\n\tdictWord{7, 0, 722},\n\tdictWord{135, 0, 904},\n\tdictWord{134, 0, 773},\n\tdictWord{7, 0, 352},\n\tdictWord{133, 10, 888},\n\tdictWord{5, 11, 48},\n\tdictWord{5, 11, 404},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t557,\n\t},\n\tdictWord{7, 11, 458},\n\tdictWord{8, 11, 597},\n\tdictWord{10, 11, 455},\n\tdictWord{10, 11, 606},\n\tdictWord{11, 11, 49},\n\tdictWord{11, 11, 548},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t476,\n\t},\n\tdictWord{13, 11, 18},\n\tdictWord{141, 11, 450},\n\tdictWord{134, 11, 418},\n\tdictWord{132, 10, 711},\n\tdictWord{5, 11, 442},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1984,\n\t},\n\tdictWord{141, 0, 35},\n\tdictWord{137, 0, 152},\n\tdictWord{134, 0, 1197},\n\tdictWord{135, 11, 1093},\n\tdictWord{137, 11, 203},\n\tdictWord{137, 10, 440},\n\tdictWord{10, 0, 592},\n\tdictWord{10, 0, 753},\n\tdictWord{12, 0, 317},\n\tdictWord{12, 0, 355},\n\tdictWord{12, 0, 465},\n\tdictWord{12, 0, 469},\n\tdictWord{12, 0, 560},\n\tdictWord{12, 0, 578},\n\tdictWord{141, 0, 243},\n\tdictWord{133, 0, 564},\n\tdictWord{134, 0, 797},\n\tdictWord{5, 10, 958},\n\tdictWord{133, 10, 987},\n\tdictWord{5, 11, 55},\n\tdictWord{7, 11, 376},\n\tdictWord{140, 11, 161},\n\tdictWord{133, 11, 450},\n\tdictWord{134, 0, 556},\n\tdictWord{134, 0, 819},\n\tdictWord{11, 10, 276},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t293,\n\t},\n\tdictWord{7, 0, 544},\n\tdictWord{138, 0, 61},\n\tdictWord{8, 0, 719},\n\tdictWord{4, 10, 65},\n\tdictWord{5, 10, 479},\n\tdictWord{5, 10, 1004},\n\tdictWord{7, 10, 1913},\n\tdictWord{8, 10, 317},\n\tdictWord{9, 10, 302},\n\tdictWord{10, 10, 612},\n\tdictWord{141, 10, 22},\n\tdictWord{4, 0, 5},\n\tdictWord{5, 0, 498},\n\tdictWord{8, 0, 637},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t521,\n\t},\n\tdictWord{4, 11, 213},\n\tdictWord{4, 10, 261},\n\tdictWord{7, 11, 223},\n\tdictWord{7, 10, 510},\n\tdictWord{136, 11, 80},\n\tdictWord{5, 0, 927},\n\tdictWord{7, 0, 101},\n\tdictWord{4, 10, 291},\n\tdictWord{7, 11, 381},\n\tdictWord{7, 11, 806},\n\tdictWord{7, 11, 820},\n\tdictWord{8, 11, 354},\n\tdictWord{8, 11, 437},\n\tdictWord{8, 11, 787},\n\tdictWord{9, 10, 515},\n\tdictWord{9, 11, 657},\n\tdictWord{10, 11, 58},\n\tdictWord{10, 11, 339},\n\tdictWord{10, 11, 749},\n\tdictWord{11, 11, 914},\n\tdictWord{12, 10, 152},\n\tdictWord{12, 11, 162},\n\tdictWord{12, 10, 443},\n\tdictWord{13, 11, 75},\n\tdictWord{13, 10, 392},\n\tdictWord{14, 11, 106},\n\tdictWord{14, 11, 198},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t320,\n\t},\n\tdictWord{14, 10, 357},\n\tdictWord{14, 11, 413},\n\tdictWord{146, 11, 43},\n\tdictWord{6, 0, 1153},\n\tdictWord{7, 0, 1441},\n\tdictWord{136, 11, 747},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t893,\n\t},\n\tdictWord{5, 0, 780},\n\tdictWord{133, 0, 893},\n\tdictWord{138, 11, 654},\n\tdictWord{133, 11, 692},\n\tdictWord{133, 0, 238},\n\tdictWord{134, 11, 191},\n\tdictWord{4, 10, 130},\n\tdictWord{135, 10, 843},\n\tdictWord{6, 0, 1296},\n\tdictWord{5, 10, 42},\n\tdictWord{5, 10, 879},\n\tdictWord{7, 10, 245},\n\tdictWord{7, 10, 324},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1532,\n\t},\n\tdictWord{11, 10, 463},\n\tdictWord{11, 10, 472},\n\tdictWord{13, 10, 363},\n\tdictWord{144, 10, 52},\n\tdictWord{134, 0, 1729},\n\tdictWord{6, 0, 1999},\n\tdictWord{136, 0, 969},\n\tdictWord{4, 10, 134},\n\tdictWord{133, 10, 372},\n\tdictWord{4, 0, 60},\n\tdictWord{7, 0, 941},\n\tdictWord{7, 0, 1800},\n\tdictWord{8, 0, 314},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t700,\n\t},\n\tdictWord{139, 0, 487},\n\tdictWord{134, 0, 1144},\n\tdictWord{6, 11, 162},\n\tdictWord{7, 11, 1960},\n\tdictWord{136, 11, 831},\n\tdictWord{132, 11, 706},\n\tdictWord{135, 0, 1147},\n\tdictWord{138, 11, 426},\n\tdictWord{138, 11, 89},\n\tdictWord{7, 0, 1853},\n\tdictWord{138, 0, 437},\n\tdictWord{136, 0, 419},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1634,\n\t},\n\tdictWord{133, 0, 828},\n\tdictWord{5, 0, 806},\n\tdictWord{7, 0, 176},\n\tdictWord{7, 0, 178},\n\tdictWord{7, 0, 1240},\n\tdictWord{7, 0, 1976},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t644,\n\t},\n\tdictWord{135, 11, 1877},\n\tdictWord{5, 11, 420},\n\tdictWord{135, 11, 1449},\n\tdictWord{4, 0, 51},\n\tdictWord{5, 0, 39},\n\tdictWord{6, 0, 4},\n\tdictWord{7, 0, 591},\n\tdictWord{7, 0, 849},\n\tdictWord{7, 0, 951},\n\tdictWord{7, 0, 1613},\n\tdictWord{7, 0, 1760},\n\tdictWord{7, 0, 1988},\n\tdictWord{9, 0, 434},\n\tdictWord{10, 0, 754},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t25,\n\t},\n\tdictWord{139, 0, 37},\n\tdictWord{10, 11, 57},\n\tdictWord{138, 11, 277},\n\tdictWord{135, 10, 540},\n\tdictWord{132, 11, 204},\n\tdictWord{135, 0, 159},\n\tdictWord{139, 11, 231},\n\tdictWord{133, 0, 902},\n\tdictWord{7, 0, 928},\n\tdictWord{7, 11, 366},\n\tdictWord{9, 11, 287},\n\tdictWord{12, 11, 199},\n\tdictWord{12, 11, 556},\n\tdictWord{140, 11, 577},\n\tdictWord{6, 10, 623},\n\tdictWord{136, 10, 789},\n\tdictWord{4, 10, 908},\n\tdictWord{5, 10, 359},\n\tdictWord{5, 10, 508},\n\tdictWord{6, 10, 1723},\n\tdictWord{7, 10, 343},\n\tdictWord{7, 10, 1996},\n\tdictWord{135, 10, 2026},\n\tdictWord{134, 0, 270},\n\tdictWord{4, 10, 341},\n\tdictWord{135, 10, 480},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t356,\n\t},\n\tdictWord{135, 11, 224},\n\tdictWord{11, 11, 588},\n\tdictWord{11, 11, 864},\n\tdictWord{11, 11, 968},\n\tdictWord{143, 11, 160},\n\tdictWord{132, 0, 556},\n\tdictWord{137, 0, 801},\n\tdictWord{132, 0, 416},\n\tdictWord{142, 0, 372},\n\tdictWord{5, 0, 152},\n\tdictWord{5, 0, 197},\n\tdictWord{7, 0, 340},\n\tdictWord{7, 0, 867},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t548,\n\t},\n\tdictWord{10, 0, 581},\n\tdictWord{11, 0, 6},\n\tdictWord{12, 0, 3},\n\tdictWord{12, 0, 19},\n\tdictWord{14, 0, 110},\n\tdictWord{142, 0, 289},\n\tdictWord{139, 0, 369},\n\tdictWord{7, 11, 630},\n\tdictWord{9, 11, 567},\n\tdictWord{11, 11, 150},\n\tdictWord{11, 11, 444},\n\tdictWord{141, 11, 119},\n\tdictWord{134, 11, 539},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1995,\n\t},\n\tdictWord{8, 10, 299},\n\tdictWord{11, 10, 890},\n\tdictWord{140, 10, 674},\n\tdictWord{7, 0, 34},\n\tdictWord{7, 0, 190},\n\tdictWord{8, 0, 28},\n\tdictWord{8, 0, 141},\n\tdictWord{8, 0, 444},\n\tdictWord{8, 0, 811},\n\tdictWord{9, 0, 468},\n\tdictWord{11, 0, 334},\n\tdictWord{12, 0, 24},\n\tdictWord{12, 0, 386},\n\tdictWord{140, 0, 576},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t757,\n\t},\n\tdictWord{7, 0, 1553},\n\tdictWord{136, 0, 898},\n\tdictWord{133, 0, 721},\n\tdictWord{136, 0, 1012},\n\tdictWord{4, 0, 789},\n\tdictWord{5, 0, 647},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1102,\n\t},\n\tdictWord{132, 0, 898},\n\tdictWord{10, 0, 183},\n\tdictWord{4, 10, 238},\n\tdictWord{5, 10, 503},\n\tdictWord{6, 10, 179},\n\tdictWord{7, 10, 2003},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t381,\n\t},\n\tdictWord{8, 10, 473},\n\tdictWord{9, 10, 149},\n\tdictWord{10, 10, 788},\n\tdictWord{15, 10, 45},\n\tdictWord{15, 10, 86},\n\tdictWord{20, 10, 110},\n\tdictWord{\n\t\t150,\n\t\t10,\n\t\t57,\n\t},\n\tdictWord{9, 0, 136},\n\tdictWord{19, 0, 107},\n\tdictWord{4, 10, 121},\n\tdictWord{5, 10, 156},\n\tdictWord{5, 10, 349},\n\tdictWord{10, 10, 605},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t342,\n\t},\n\tdictWord{4, 11, 235},\n\tdictWord{135, 11, 255},\n\tdictWord{4, 11, 194},\n\tdictWord{5, 11, 584},\n\tdictWord{6, 11, 384},\n\tdictWord{7, 11, 583},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t761,\n\t},\n\tdictWord{11, 11, 760},\n\tdictWord{139, 11, 851},\n\tdictWord{6, 10, 80},\n\tdictWord{6, 10, 1694},\n\tdictWord{7, 10, 173},\n\tdictWord{7, 10, 1974},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t547,\n\t},\n\tdictWord{10, 10, 730},\n\tdictWord{14, 10, 18},\n\tdictWord{150, 10, 39},\n\tdictWord{4, 10, 923},\n\tdictWord{134, 10, 1711},\n\tdictWord{5, 0, 277},\n\tdictWord{141, 0, 247},\n\tdictWord{132, 0, 435},\n\tdictWord{133, 11, 562},\n\tdictWord{134, 0, 1311},\n\tdictWord{5, 11, 191},\n\tdictWord{137, 11, 271},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t595,\n\t},\n\tdictWord{7, 11, 1537},\n\tdictWord{14, 11, 96},\n\tdictWord{143, 11, 73},\n\tdictWord{5, 0, 437},\n\tdictWord{7, 0, 502},\n\tdictWord{7, 0, 519},\n\tdictWord{7, 0, 1122},\n\tdictWord{7, 0, 1751},\n\tdictWord{14, 0, 211},\n\tdictWord{6, 10, 459},\n\tdictWord{7, 10, 1753},\n\tdictWord{7, 10, 1805},\n\tdictWord{8, 10, 658},\n\tdictWord{9, 10, 1},\n\tdictWord{11, 10, 959},\n\tdictWord{141, 10, 446},\n\tdictWord{6, 0, 814},\n\tdictWord{4, 11, 470},\n\tdictWord{5, 11, 473},\n\tdictWord{6, 11, 153},\n\tdictWord{7, 11, 1503},\n\tdictWord{7, 11, 1923},\n\tdictWord{10, 11, 701},\n\tdictWord{11, 11, 132},\n\tdictWord{11, 11, 168},\n\tdictWord{11, 11, 227},\n\tdictWord{11, 11, 320},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t436,\n\t},\n\tdictWord{11, 11, 525},\n\tdictWord{11, 11, 855},\n\tdictWord{12, 11, 41},\n\tdictWord{12, 11, 286},\n\tdictWord{13, 11, 103},\n\tdictWord{13, 11, 284},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t255,\n\t},\n\tdictWord{14, 11, 262},\n\tdictWord{15, 11, 117},\n\tdictWord{143, 11, 127},\n\tdictWord{5, 0, 265},\n\tdictWord{6, 0, 212},\n\tdictWord{135, 0, 28},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t750,\n\t},\n\tdictWord{133, 11, 327},\n\tdictWord{6, 11, 552},\n\tdictWord{7, 11, 1754},\n\tdictWord{137, 11, 604},\n\tdictWord{134, 0, 2012},\n\tdictWord{132, 0, 702},\n\tdictWord{5, 11, 80},\n\tdictWord{6, 11, 405},\n\tdictWord{7, 11, 403},\n\tdictWord{7, 11, 1502},\n\tdictWord{7, 11, 1626},\n\tdictWord{8, 11, 456},\n\tdictWord{9, 11, 487},\n\tdictWord{9, 11, 853},\n\tdictWord{9, 11, 889},\n\tdictWord{10, 11, 309},\n\tdictWord{11, 11, 721},\n\tdictWord{11, 11, 994},\n\tdictWord{12, 11, 430},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t165,\n\t},\n\tdictWord{5, 0, 808},\n\tdictWord{135, 0, 2045},\n\tdictWord{5, 0, 166},\n\tdictWord{8, 0, 739},\n\tdictWord{140, 0, 511},\n\tdictWord{134, 10, 490},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t453,\n\t},\n\tdictWord{5, 11, 887},\n\tdictWord{6, 11, 535},\n\tdictWord{8, 11, 6},\n\tdictWord{136, 11, 543},\n\tdictWord{4, 0, 119},\n\tdictWord{5, 0, 170},\n\tdictWord{5, 0, 447},\n\tdictWord{7, 0, 1708},\n\tdictWord{7, 0, 1889},\n\tdictWord{9, 0, 357},\n\tdictWord{9, 0, 719},\n\tdictWord{12, 0, 486},\n\tdictWord{140, 0, 596},\n\tdictWord{137, 0, 500},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t250,\n\t},\n\tdictWord{136, 10, 507},\n\tdictWord{132, 10, 158},\n\tdictWord{6, 0, 809},\n\tdictWord{134, 0, 1500},\n\tdictWord{9, 0, 327},\n\tdictWord{11, 0, 350},\n\tdictWord{11, 0, 831},\n\tdictWord{13, 0, 352},\n\tdictWord{4, 10, 140},\n\tdictWord{7, 10, 362},\n\tdictWord{8, 10, 209},\n\tdictWord{9, 10, 10},\n\tdictWord{9, 10, 503},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t614,\n\t},\n\tdictWord{10, 10, 689},\n\tdictWord{11, 10, 327},\n\tdictWord{11, 10, 725},\n\tdictWord{12, 10, 252},\n\tdictWord{12, 10, 583},\n\tdictWord{13, 10, 192},\n\tdictWord{14, 10, 269},\n\tdictWord{14, 10, 356},\n\tdictWord{148, 10, 50},\n\tdictWord{135, 11, 741},\n\tdictWord{4, 0, 450},\n\tdictWord{7, 0, 1158},\n\tdictWord{19, 10, 1},\n\tdictWord{19, 10, 26},\n\tdictWord{150, 10, 9},\n\tdictWord{6, 0, 597},\n\tdictWord{135, 0, 1318},\n\tdictWord{134, 0, 1602},\n\tdictWord{6, 10, 228},\n\tdictWord{7, 10, 1341},\n\tdictWord{9, 10, 408},\n\tdictWord{138, 10, 343},\n\tdictWord{7, 0, 1375},\n\tdictWord{7, 0, 1466},\n\tdictWord{138, 0, 331},\n\tdictWord{132, 0, 754},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t557,\n\t},\n\tdictWord{5, 11, 101},\n\tdictWord{6, 11, 88},\n\tdictWord{6, 11, 543},\n\tdictWord{7, 11, 1677},\n\tdictWord{9, 11, 100},\n\tdictWord{10, 11, 677},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t169,\n\t},\n\tdictWord{14, 11, 302},\n\tdictWord{14, 11, 313},\n\tdictWord{15, 11, 48},\n\tdictWord{143, 11, 84},\n\tdictWord{134, 0, 1368},\n\tdictWord{4, 11, 310},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t795,\n\t},\n\tdictWord{10, 11, 733},\n\tdictWord{11, 11, 451},\n\tdictWord{12, 11, 249},\n\tdictWord{14, 11, 115},\n\tdictWord{14, 11, 286},\n\tdictWord{143, 11, 100},\n\tdictWord{132, 10, 548},\n\tdictWord{10, 0, 557},\n\tdictWord{7, 10, 197},\n\tdictWord{8, 10, 142},\n\tdictWord{8, 10, 325},\n\tdictWord{9, 10, 150},\n\tdictWord{9, 10, 596},\n\tdictWord{10, 10, 353},\n\tdictWord{11, 10, 74},\n\tdictWord{11, 10, 315},\n\tdictWord{12, 10, 662},\n\tdictWord{12, 10, 681},\n\tdictWord{14, 10, 423},\n\tdictWord{\n\t\t143,\n\t\t10,\n\t\t141,\n\t},\n\tdictWord{133, 11, 587},\n\tdictWord{5, 0, 850},\n\tdictWord{136, 0, 799},\n\tdictWord{10, 0, 908},\n\tdictWord{12, 0, 701},\n\tdictWord{12, 0, 757},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t466,\n\t},\n\tdictWord{4, 0, 62},\n\tdictWord{5, 0, 275},\n\tdictWord{18, 0, 19},\n\tdictWord{6, 10, 399},\n\tdictWord{6, 10, 579},\n\tdictWord{7, 10, 692},\n\tdictWord{7, 10, 846},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1015,\n\t},\n\tdictWord{7, 10, 1799},\n\tdictWord{8, 10, 403},\n\tdictWord{9, 10, 394},\n\tdictWord{10, 10, 133},\n\tdictWord{12, 10, 4},\n\tdictWord{12, 10, 297},\n\tdictWord{12, 10, 452},\n\tdictWord{16, 10, 81},\n\tdictWord{18, 10, 25},\n\tdictWord{21, 10, 14},\n\tdictWord{22, 10, 12},\n\tdictWord{151, 10, 18},\n\tdictWord{12, 0, 459},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1546,\n\t},\n\tdictWord{11, 10, 299},\n\tdictWord{142, 10, 407},\n\tdictWord{132, 10, 177},\n\tdictWord{132, 11, 498},\n\tdictWord{7, 11, 217},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t140,\n\t},\n\tdictWord{138, 11, 610},\n\tdictWord{5, 10, 411},\n\tdictWord{135, 10, 653},\n\tdictWord{134, 0, 1802},\n\tdictWord{7, 10, 439},\n\tdictWord{10, 10, 727},\n\tdictWord{11, 10, 260},\n\tdictWord{139, 10, 684},\n\tdictWord{133, 11, 905},\n\tdictWord{11, 11, 580},\n\tdictWord{142, 11, 201},\n\tdictWord{134, 0, 1397},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t208,\n\t},\n\tdictWord{7, 10, 753},\n\tdictWord{135, 10, 1528},\n\tdictWord{7, 0, 238},\n\tdictWord{7, 0, 2033},\n\tdictWord{8, 0, 120},\n\tdictWord{8, 0, 188},\n\tdictWord{8, 0, 659},\n\tdictWord{9, 0, 598},\n\tdictWord{10, 0, 466},\n\tdictWord{12, 0, 342},\n\tdictWord{12, 0, 588},\n\tdictWord{13, 0, 503},\n\tdictWord{14, 0, 246},\n\tdictWord{143, 0, 92},\n\tdictWord{135, 11, 1041},\n\tdictWord{4, 11, 456},\n\tdictWord{7, 11, 105},\n\tdictWord{7, 11, 358},\n\tdictWord{7, 11, 1637},\n\tdictWord{8, 11, 643},\n\tdictWord{139, 11, 483},\n\tdictWord{6, 0, 1318},\n\tdictWord{134, 0, 1324},\n\tdictWord{4, 0, 201},\n\tdictWord{7, 0, 1744},\n\tdictWord{8, 0, 602},\n\tdictWord{11, 0, 247},\n\tdictWord{11, 0, 826},\n\tdictWord{17, 0, 65},\n\tdictWord{133, 10, 242},\n\tdictWord{8, 0, 164},\n\tdictWord{146, 0, 62},\n\tdictWord{133, 10, 953},\n\tdictWord{139, 10, 802},\n\tdictWord{133, 0, 615},\n\tdictWord{7, 11, 1566},\n\tdictWord{8, 11, 269},\n\tdictWord{9, 11, 212},\n\tdictWord{9, 11, 718},\n\tdictWord{14, 11, 15},\n\tdictWord{14, 11, 132},\n\tdictWord{142, 11, 227},\n\tdictWord{133, 10, 290},\n\tdictWord{132, 10, 380},\n\tdictWord{5, 10, 52},\n\tdictWord{7, 10, 277},\n\tdictWord{9, 10, 368},\n\tdictWord{139, 10, 791},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1243,\n\t},\n\tdictWord{133, 11, 539},\n\tdictWord{11, 11, 919},\n\tdictWord{141, 11, 409},\n\tdictWord{136, 0, 968},\n\tdictWord{133, 11, 470},\n\tdictWord{134, 0, 882},\n\tdictWord{132, 0, 907},\n\tdictWord{5, 0, 100},\n\tdictWord{10, 0, 329},\n\tdictWord{12, 0, 416},\n\tdictWord{149, 0, 29},\n\tdictWord{10, 10, 138},\n\tdictWord{139, 10, 476},\n\tdictWord{5, 10, 725},\n\tdictWord{5, 10, 727},\n\tdictWord{6, 11, 91},\n\tdictWord{7, 11, 435},\n\tdictWord{135, 10, 1811},\n\tdictWord{4, 11, 16},\n\tdictWord{5, 11, 316},\n\tdictWord{5, 11, 842},\n\tdictWord{6, 11, 370},\n\tdictWord{6, 11, 1778},\n\tdictWord{8, 11, 166},\n\tdictWord{11, 11, 812},\n\tdictWord{12, 11, 206},\n\tdictWord{12, 11, 351},\n\tdictWord{14, 11, 418},\n\tdictWord{16, 11, 15},\n\tdictWord{16, 11, 34},\n\tdictWord{18, 11, 3},\n\tdictWord{19, 11, 3},\n\tdictWord{19, 11, 7},\n\tdictWord{20, 11, 4},\n\tdictWord{\n\t\t149,\n\t\t11,\n\t\t21,\n\t},\n\tdictWord{132, 0, 176},\n\tdictWord{5, 0, 636},\n\tdictWord{5, 0, 998},\n\tdictWord{7, 0, 9},\n\tdictWord{7, 0, 1508},\n\tdictWord{8, 0, 26},\n\tdictWord{9, 0, 317},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t358,\n\t},\n\tdictWord{10, 0, 210},\n\tdictWord{10, 0, 292},\n\tdictWord{10, 0, 533},\n\tdictWord{11, 0, 555},\n\tdictWord{12, 0, 526},\n\tdictWord{12, 0, 607},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t263,\n\t},\n\tdictWord{13, 0, 459},\n\tdictWord{142, 0, 271},\n\tdictWord{6, 0, 256},\n\tdictWord{8, 0, 265},\n\tdictWord{4, 10, 38},\n\tdictWord{7, 10, 307},\n\tdictWord{7, 10, 999},\n\tdictWord{7, 10, 1481},\n\tdictWord{7, 10, 1732},\n\tdictWord{7, 10, 1738},\n\tdictWord{9, 10, 414},\n\tdictWord{11, 10, 316},\n\tdictWord{12, 10, 52},\n\tdictWord{13, 10, 420},\n\tdictWord{147, 10, 100},\n\tdictWord{135, 10, 1296},\n\tdictWord{4, 11, 611},\n\tdictWord{133, 11, 606},\n\tdictWord{4, 0, 643},\n\tdictWord{142, 11, 21},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t715,\n\t},\n\tdictWord{133, 10, 723},\n\tdictWord{6, 0, 610},\n\tdictWord{135, 11, 597},\n\tdictWord{10, 0, 127},\n\tdictWord{141, 0, 27},\n\tdictWord{6, 0, 1995},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t2001,\n\t},\n\tdictWord{8, 0, 119},\n\tdictWord{136, 0, 973},\n\tdictWord{4, 11, 149},\n\tdictWord{138, 11, 368},\n\tdictWord{12, 0, 522},\n\tdictWord{4, 11, 154},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t109,\n\t},\n\tdictWord{6, 10, 1784},\n\tdictWord{7, 11, 1134},\n\tdictWord{7, 10, 1895},\n\tdictWord{8, 11, 105},\n\tdictWord{12, 10, 296},\n\tdictWord{140, 10, 302},\n\tdictWord{4, 11, 31},\n\tdictWord{6, 11, 429},\n\tdictWord{7, 11, 962},\n\tdictWord{9, 11, 458},\n\tdictWord{139, 11, 691},\n\tdictWord{10, 0, 553},\n\tdictWord{11, 0, 876},\n\tdictWord{13, 0, 193},\n\tdictWord{13, 0, 423},\n\tdictWord{14, 0, 166},\n\tdictWord{19, 0, 84},\n\tdictWord{4, 11, 312},\n\tdictWord{5, 10, 216},\n\tdictWord{7, 10, 1879},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t141,\n\t},\n\tdictWord{9, 10, 270},\n\tdictWord{9, 10, 679},\n\tdictWord{10, 10, 159},\n\tdictWord{11, 10, 197},\n\tdictWord{12, 10, 538},\n\tdictWord{12, 10, 559},\n\tdictWord{14, 10, 144},\n\tdictWord{14, 10, 167},\n\tdictWord{143, 10, 67},\n\tdictWord{134, 0, 1582},\n\tdictWord{7, 0, 1578},\n\tdictWord{135, 11, 1578},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t81,\n\t},\n\tdictWord{132, 11, 236},\n\tdictWord{134, 10, 391},\n\tdictWord{134, 0, 795},\n\tdictWord{7, 10, 322},\n\tdictWord{136, 10, 249},\n\tdictWord{5, 11, 836},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t857,\n\t},\n\tdictWord{6, 11, 1680},\n\tdictWord{7, 11, 59},\n\tdictWord{147, 11, 53},\n\tdictWord{135, 0, 432},\n\tdictWord{10, 11, 68},\n\tdictWord{139, 11, 494},\n\tdictWord{4, 11, 81},\n\tdictWord{139, 11, 867},\n\tdictWord{7, 0, 126},\n\tdictWord{136, 0, 84},\n\tdictWord{142, 11, 280},\n\tdictWord{5, 11, 282},\n\tdictWord{8, 11, 650},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t295,\n\t},\n\tdictWord{9, 11, 907},\n\tdictWord{138, 11, 443},\n\tdictWord{136, 0, 790},\n\tdictWord{5, 10, 632},\n\tdictWord{138, 10, 526},\n\tdictWord{6, 0, 64},\n\tdictWord{12, 0, 377},\n\tdictWord{13, 0, 309},\n\tdictWord{14, 0, 141},\n\tdictWord{14, 0, 429},\n\tdictWord{14, 11, 141},\n\tdictWord{142, 11, 429},\n\tdictWord{134, 0, 1529},\n\tdictWord{6, 0, 321},\n\tdictWord{7, 0, 1857},\n\tdictWord{9, 0, 530},\n\tdictWord{19, 0, 99},\n\tdictWord{7, 10, 948},\n\tdictWord{7, 10, 1042},\n\tdictWord{8, 10, 235},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t461,\n\t},\n\tdictWord{9, 10, 453},\n\tdictWord{10, 10, 354},\n\tdictWord{145, 10, 77},\n\tdictWord{7, 0, 1104},\n\tdictWord{11, 0, 269},\n\tdictWord{11, 0, 539},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t627,\n\t},\n\tdictWord{11, 0, 706},\n\tdictWord{11, 0, 975},\n\tdictWord{12, 0, 248},\n\tdictWord{12, 0, 434},\n\tdictWord{12, 0, 600},\n\tdictWord{12, 0, 622},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t297,\n\t},\n\tdictWord{13, 0, 485},\n\tdictWord{14, 0, 69},\n\tdictWord{14, 0, 409},\n\tdictWord{143, 0, 108},\n\tdictWord{4, 10, 362},\n\tdictWord{7, 10, 52},\n\tdictWord{7, 10, 303},\n\tdictWord{10, 11, 70},\n\tdictWord{12, 11, 26},\n\tdictWord{14, 11, 17},\n\tdictWord{14, 11, 178},\n\tdictWord{15, 11, 34},\n\tdictWord{149, 11, 12},\n\tdictWord{11, 0, 977},\n\tdictWord{141, 0, 507},\n\tdictWord{9, 0, 34},\n\tdictWord{139, 0, 484},\n\tdictWord{5, 10, 196},\n\tdictWord{6, 10, 486},\n\tdictWord{7, 10, 212},\n\tdictWord{8, 10, 309},\n\tdictWord{136, 10, 346},\n\tdictWord{6, 0, 1700},\n\tdictWord{7, 0, 26},\n\tdictWord{7, 0, 293},\n\tdictWord{7, 0, 382},\n\tdictWord{7, 0, 1026},\n\tdictWord{7, 0, 1087},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t2027,\n\t},\n\tdictWord{8, 0, 24},\n\tdictWord{8, 0, 114},\n\tdictWord{8, 0, 252},\n\tdictWord{8, 0, 727},\n\tdictWord{8, 0, 729},\n\tdictWord{9, 0, 30},\n\tdictWord{9, 0, 199},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t231,\n\t},\n\tdictWord{9, 0, 251},\n\tdictWord{9, 0, 334},\n\tdictWord{9, 0, 361},\n\tdictWord{9, 0, 712},\n\tdictWord{10, 0, 55},\n\tdictWord{10, 0, 60},\n\tdictWord{10, 0, 232},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t332,\n\t},\n\tdictWord{10, 0, 384},\n\tdictWord{10, 0, 396},\n\tdictWord{10, 0, 504},\n\tdictWord{10, 0, 542},\n\tdictWord{10, 0, 652},\n\tdictWord{11, 0, 20},\n\tdictWord{11, 0, 48},\n\tdictWord{11, 0, 207},\n\tdictWord{11, 0, 291},\n\tdictWord{11, 0, 298},\n\tdictWord{11, 0, 342},\n\tdictWord{11, 0, 365},\n\tdictWord{11, 0, 394},\n\tdictWord{11, 0, 620},\n\tdictWord{11, 0, 705},\n\tdictWord{11, 0, 1017},\n\tdictWord{12, 0, 123},\n\tdictWord{12, 0, 340},\n\tdictWord{12, 0, 406},\n\tdictWord{12, 0, 643},\n\tdictWord{13, 0, 61},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t269,\n\t},\n\tdictWord{13, 0, 311},\n\tdictWord{13, 0, 319},\n\tdictWord{13, 0, 486},\n\tdictWord{14, 0, 234},\n\tdictWord{15, 0, 62},\n\tdictWord{15, 0, 85},\n\tdictWord{16, 0, 71},\n\tdictWord{18, 0, 119},\n\tdictWord{20, 0, 105},\n\tdictWord{135, 10, 1912},\n\tdictWord{4, 11, 71},\n\tdictWord{5, 11, 376},\n\tdictWord{7, 11, 119},\n\tdictWord{138, 11, 665},\n\tdictWord{10, 0, 918},\n\tdictWord{10, 0, 926},\n\tdictWord{4, 10, 686},\n\tdictWord{136, 11, 55},\n\tdictWord{138, 10, 625},\n\tdictWord{136, 10, 706},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t479,\n\t},\n\tdictWord{4, 10, 30},\n\tdictWord{133, 10, 43},\n\tdictWord{6, 0, 379},\n\tdictWord{7, 0, 270},\n\tdictWord{8, 0, 176},\n\tdictWord{8, 0, 183},\n\tdictWord{9, 0, 432},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t661,\n\t},\n\tdictWord{12, 0, 247},\n\tdictWord{12, 0, 617},\n\tdictWord{18, 0, 125},\n\tdictWord{7, 11, 607},\n\tdictWord{8, 11, 99},\n\tdictWord{152, 11, 4},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t792,\n\t},\n\tdictWord{133, 0, 900},\n\tdictWord{4, 11, 612},\n\tdictWord{133, 11, 561},\n\tdictWord{4, 11, 41},\n\tdictWord{4, 10, 220},\n\tdictWord{5, 11, 74},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1535,\n\t},\n\tdictWord{7, 11, 1627},\n\tdictWord{11, 11, 871},\n\tdictWord{140, 11, 619},\n\tdictWord{135, 0, 1920},\n\tdictWord{7, 11, 94},\n\tdictWord{11, 11, 329},\n\tdictWord{11, 11, 965},\n\tdictWord{12, 11, 241},\n\tdictWord{14, 11, 354},\n\tdictWord{15, 11, 22},\n\tdictWord{148, 11, 63},\n\tdictWord{9, 11, 209},\n\tdictWord{137, 11, 300},\n\tdictWord{134, 0, 771},\n\tdictWord{135, 0, 1979},\n\tdictWord{4, 0, 901},\n\tdictWord{133, 0, 776},\n\tdictWord{142, 0, 254},\n\tdictWord{133, 11, 98},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t16,\n\t},\n\tdictWord{141, 11, 386},\n\tdictWord{133, 11, 984},\n\tdictWord{4, 11, 182},\n\tdictWord{6, 11, 205},\n\tdictWord{135, 11, 220},\n\tdictWord{7, 10, 1725},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1774,\n\t},\n\tdictWord{138, 10, 393},\n\tdictWord{5, 10, 263},\n\tdictWord{134, 10, 414},\n\tdictWord{4, 11, 42},\n\tdictWord{9, 11, 205},\n\tdictWord{9, 11, 786},\n\tdictWord{138, 11, 659},\n\tdictWord{14, 0, 140},\n\tdictWord{148, 0, 41},\n\tdictWord{8, 0, 440},\n\tdictWord{10, 0, 359},\n\tdictWord{6, 10, 178},\n\tdictWord{6, 11, 289},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1750,\n\t},\n\tdictWord{7, 11, 1670},\n\tdictWord{9, 10, 690},\n\tdictWord{10, 10, 155},\n\tdictWord{10, 10, 373},\n\tdictWord{11, 10, 698},\n\tdictWord{12, 11, 57},\n\tdictWord{13, 10, 155},\n\tdictWord{20, 10, 93},\n\tdictWord{151, 11, 4},\n\tdictWord{4, 0, 37},\n\tdictWord{5, 0, 334},\n\tdictWord{7, 0, 1253},\n\tdictWord{151, 11, 25},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t508,\n\t},\n\tdictWord{4, 11, 635},\n\tdictWord{5, 10, 97},\n\tdictWord{137, 10, 393},\n\tdictWord{139, 11, 533},\n\tdictWord{4, 0, 640},\n\tdictWord{133, 0, 513},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1639,\n\t},\n\tdictWord{132, 11, 371},\n\tdictWord{4, 11, 272},\n\tdictWord{7, 11, 836},\n\tdictWord{7, 11, 1651},\n\tdictWord{145, 11, 89},\n\tdictWord{5, 11, 825},\n\tdictWord{6, 11, 444},\n\tdictWord{6, 11, 1640},\n\tdictWord{136, 11, 308},\n\tdictWord{4, 10, 191},\n\tdictWord{7, 10, 934},\n\tdictWord{8, 10, 647},\n\tdictWord{145, 10, 97},\n\tdictWord{12, 0, 246},\n\tdictWord{15, 0, 162},\n\tdictWord{19, 0, 64},\n\tdictWord{20, 0, 8},\n\tdictWord{20, 0, 95},\n\tdictWord{22, 0, 24},\n\tdictWord{152, 0, 17},\n\tdictWord{4, 0, 533},\n\tdictWord{5, 10, 165},\n\tdictWord{9, 10, 346},\n\tdictWord{138, 10, 655},\n\tdictWord{5, 11, 737},\n\tdictWord{139, 10, 885},\n\tdictWord{133, 10, 877},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t128,\n\t},\n\tdictWord{139, 10, 179},\n\tdictWord{137, 11, 307},\n\tdictWord{140, 0, 752},\n\tdictWord{133, 0, 920},\n\tdictWord{135, 0, 1048},\n\tdictWord{5, 0, 153},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t580,\n\t},\n\tdictWord{6, 10, 1663},\n\tdictWord{7, 10, 132},\n\tdictWord{7, 10, 1154},\n\tdictWord{7, 10, 1415},\n\tdictWord{7, 10, 1507},\n\tdictWord{12, 10, 493},\n\tdictWord{15, 10, 105},\n\tdictWord{151, 10, 15},\n\tdictWord{5, 10, 459},\n\tdictWord{7, 10, 1073},\n\tdictWord{8, 10, 241},\n\tdictWord{136, 10, 334},\n\tdictWord{138, 0, 391},\n\tdictWord{135, 0, 1952},\n\tdictWord{133, 11, 525},\n\tdictWord{8, 11, 641},\n\tdictWord{11, 11, 388},\n\tdictWord{140, 11, 580},\n\tdictWord{142, 0, 126},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t640,\n\t},\n\tdictWord{132, 0, 483},\n\tdictWord{7, 0, 1616},\n\tdictWord{9, 0, 69},\n\tdictWord{6, 10, 324},\n\tdictWord{6, 10, 520},\n\tdictWord{7, 10, 338},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1729,\n\t},\n\tdictWord{8, 10, 228},\n\tdictWord{139, 10, 750},\n\tdictWord{5, 11, 493},\n\tdictWord{134, 11, 528},\n\tdictWord{135, 0, 734},\n\tdictWord{4, 11, 174},\n\tdictWord{135, 11, 911},\n\tdictWord{138, 0, 480},\n\tdictWord{9, 0, 495},\n\tdictWord{146, 0, 104},\n\tdictWord{135, 10, 705},\n\tdictWord{9, 0, 472},\n\tdictWord{4, 10, 73},\n\tdictWord{6, 10, 612},\n\tdictWord{7, 10, 927},\n\tdictWord{7, 10, 1330},\n\tdictWord{7, 10, 1822},\n\tdictWord{8, 10, 217},\n\tdictWord{9, 10, 765},\n\tdictWord{9, 10, 766},\n\tdictWord{10, 10, 408},\n\tdictWord{11, 10, 51},\n\tdictWord{11, 10, 793},\n\tdictWord{12, 10, 266},\n\tdictWord{15, 10, 158},\n\tdictWord{20, 10, 89},\n\tdictWord{150, 10, 32},\n\tdictWord{7, 11, 548},\n\tdictWord{137, 11, 58},\n\tdictWord{4, 11, 32},\n\tdictWord{5, 11, 215},\n\tdictWord{6, 11, 269},\n\tdictWord{7, 11, 1782},\n\tdictWord{7, 11, 1892},\n\tdictWord{10, 11, 16},\n\tdictWord{11, 11, 822},\n\tdictWord{11, 11, 954},\n\tdictWord{141, 11, 481},\n\tdictWord{132, 0, 874},\n\tdictWord{9, 0, 229},\n\tdictWord{5, 10, 389},\n\tdictWord{136, 10, 636},\n\tdictWord{7, 11, 1749},\n\tdictWord{136, 11, 477},\n\tdictWord{134, 0, 948},\n\tdictWord{5, 11, 308},\n\tdictWord{135, 11, 1088},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t748,\n\t},\n\tdictWord{139, 0, 1009},\n\tdictWord{136, 10, 21},\n\tdictWord{6, 0, 555},\n\tdictWord{135, 0, 485},\n\tdictWord{5, 11, 126},\n\tdictWord{8, 11, 297},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t366,\n\t},\n\tdictWord{9, 11, 445},\n\tdictWord{12, 11, 53},\n\tdictWord{12, 11, 374},\n\tdictWord{141, 11, 492},\n\tdictWord{7, 11, 1551},\n\tdictWord{139, 11, 361},\n\tdictWord{136, 0, 193},\n\tdictWord{136, 0, 472},\n\tdictWord{8, 0, 653},\n\tdictWord{13, 0, 93},\n\tdictWord{147, 0, 14},\n\tdictWord{132, 0, 984},\n\tdictWord{132, 11, 175},\n\tdictWord{5, 0, 172},\n\tdictWord{6, 0, 1971},\n\tdictWord{132, 11, 685},\n\tdictWord{149, 11, 8},\n\tdictWord{133, 11, 797},\n\tdictWord{13, 0, 83},\n\tdictWord{5, 10, 189},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t442,\n\t},\n\tdictWord{7, 10, 443},\n\tdictWord{8, 10, 281},\n\tdictWord{12, 10, 174},\n\tdictWord{141, 10, 261},\n\tdictWord{134, 0, 1568},\n\tdictWord{133, 11, 565},\n\tdictWord{139, 0, 384},\n\tdictWord{133, 0, 260},\n\tdictWord{7, 0, 758},\n\tdictWord{7, 0, 880},\n\tdictWord{7, 0, 1359},\n\tdictWord{9, 0, 164},\n\tdictWord{9, 0, 167},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t156,\n\t},\n\tdictWord{10, 0, 588},\n\tdictWord{12, 0, 101},\n\tdictWord{14, 0, 48},\n\tdictWord{15, 0, 70},\n\tdictWord{6, 10, 2},\n\tdictWord{7, 10, 1262},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1737,\n\t},\n\tdictWord{8, 10, 22},\n\tdictWord{8, 10, 270},\n\tdictWord{8, 10, 612},\n\tdictWord{9, 10, 312},\n\tdictWord{9, 10, 436},\n\tdictWord{10, 10, 311},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t623,\n\t},\n\tdictWord{11, 10, 72},\n\tdictWord{11, 10, 330},\n\tdictWord{11, 10, 455},\n\tdictWord{12, 10, 321},\n\tdictWord{12, 10, 504},\n\tdictWord{12, 10, 530},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t543,\n\t},\n\tdictWord{13, 10, 17},\n\tdictWord{13, 10, 156},\n\tdictWord{13, 10, 334},\n\tdictWord{17, 10, 60},\n\tdictWord{148, 10, 64},\n\tdictWord{4, 11, 252},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1068,\n\t},\n\tdictWord{10, 11, 434},\n\tdictWord{11, 11, 228},\n\tdictWord{11, 11, 426},\n\tdictWord{13, 11, 231},\n\tdictWord{18, 11, 106},\n\tdictWord{148, 11, 87},\n\tdictWord{7, 10, 354},\n\tdictWord{10, 10, 410},\n\tdictWord{139, 10, 815},\n\tdictWord{6, 0, 367},\n\tdictWord{7, 10, 670},\n\tdictWord{7, 10, 1327},\n\tdictWord{8, 10, 411},\n\tdictWord{8, 10, 435},\n\tdictWord{9, 10, 653},\n\tdictWord{9, 10, 740},\n\tdictWord{10, 10, 385},\n\tdictWord{11, 10, 222},\n\tdictWord{11, 10, 324},\n\tdictWord{11, 10, 829},\n\tdictWord{140, 10, 611},\n\tdictWord{7, 0, 1174},\n\tdictWord{6, 10, 166},\n\tdictWord{135, 10, 374},\n\tdictWord{146, 0, 121},\n\tdictWord{132, 0, 828},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t231,\n\t},\n\tdictWord{138, 11, 509},\n\tdictWord{7, 11, 601},\n\tdictWord{9, 11, 277},\n\tdictWord{9, 11, 674},\n\tdictWord{10, 11, 178},\n\tdictWord{10, 11, 257},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t418,\n\t},\n\tdictWord{11, 11, 531},\n\tdictWord{11, 11, 544},\n\tdictWord{11, 11, 585},\n\tdictWord{12, 11, 113},\n\tdictWord{12, 11, 475},\n\tdictWord{13, 11, 99},\n\tdictWord{142, 11, 428},\n\tdictWord{134, 0, 1541},\n\tdictWord{135, 11, 1779},\n\tdictWord{5, 0, 343},\n\tdictWord{134, 10, 398},\n\tdictWord{135, 10, 50},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1683,\n\t},\n\tdictWord{4, 0, 440},\n\tdictWord{7, 0, 57},\n\tdictWord{8, 0, 167},\n\tdictWord{8, 0, 375},\n\tdictWord{9, 0, 82},\n\tdictWord{9, 0, 561},\n\tdictWord{9, 0, 744},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t620,\n\t},\n\tdictWord{137, 11, 744},\n\tdictWord{134, 0, 926},\n\tdictWord{6, 10, 517},\n\tdictWord{7, 10, 1159},\n\tdictWord{10, 10, 621},\n\tdictWord{139, 10, 192},\n\tdictWord{137, 0, 827},\n\tdictWord{8, 0, 194},\n\tdictWord{136, 0, 756},\n\tdictWord{10, 10, 223},\n\tdictWord{139, 10, 645},\n\tdictWord{7, 10, 64},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t245,\n\t},\n\tdictWord{4, 11, 399},\n\tdictWord{5, 11, 119},\n\tdictWord{5, 11, 494},\n\tdictWord{7, 11, 751},\n\tdictWord{137, 11, 556},\n\tdictWord{132, 0, 808},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t22,\n\t},\n\tdictWord{7, 10, 1763},\n\tdictWord{140, 10, 310},\n\tdictWord{5, 0, 639},\n\tdictWord{7, 0, 1249},\n\tdictWord{11, 0, 896},\n\tdictWord{134, 11, 584},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1614,\n\t},\n\tdictWord{135, 0, 860},\n\tdictWord{135, 11, 1121},\n\tdictWord{5, 10, 129},\n\tdictWord{6, 10, 61},\n\tdictWord{135, 10, 947},\n\tdictWord{4, 0, 102},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t815,\n\t},\n\tdictWord{7, 0, 1699},\n\tdictWord{139, 0, 964},\n\tdictWord{13, 10, 505},\n\tdictWord{141, 10, 506},\n\tdictWord{139, 10, 1000},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t679,\n\t},\n\tdictWord{132, 0, 899},\n\tdictWord{132, 0, 569},\n\tdictWord{5, 11, 694},\n\tdictWord{137, 11, 714},\n\tdictWord{136, 0, 795},\n\tdictWord{6, 0, 2045},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t7,\n\t},\n\tdictWord{6, 0, 52},\n\tdictWord{9, 0, 104},\n\tdictWord{9, 0, 559},\n\tdictWord{12, 0, 308},\n\tdictWord{147, 0, 87},\n\tdictWord{4, 0, 301},\n\tdictWord{132, 0, 604},\n\tdictWord{133, 10, 637},\n\tdictWord{136, 0, 779},\n\tdictWord{5, 11, 143},\n\tdictWord{5, 11, 769},\n\tdictWord{6, 11, 1760},\n\tdictWord{7, 11, 682},\n\tdictWord{7, 11, 1992},\n\tdictWord{136, 11, 736},\n\tdictWord{137, 10, 590},\n\tdictWord{147, 0, 32},\n\tdictWord{137, 11, 527},\n\tdictWord{5, 10, 280},\n\tdictWord{135, 10, 1226},\n\tdictWord{134, 0, 494},\n\tdictWord{6, 0, 677},\n\tdictWord{6, 0, 682},\n\tdictWord{134, 0, 1044},\n\tdictWord{133, 10, 281},\n\tdictWord{135, 10, 1064},\n\tdictWord{7, 0, 508},\n\tdictWord{133, 11, 860},\n\tdictWord{6, 11, 422},\n\tdictWord{7, 11, 0},\n\tdictWord{7, 11, 1544},\n\tdictWord{9, 11, 577},\n\tdictWord{11, 11, 990},\n\tdictWord{12, 11, 141},\n\tdictWord{12, 11, 453},\n\tdictWord{13, 11, 47},\n\tdictWord{141, 11, 266},\n\tdictWord{134, 0, 1014},\n\tdictWord{5, 11, 515},\n\tdictWord{137, 11, 131},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t957,\n\t},\n\tdictWord{132, 11, 646},\n\tdictWord{6, 0, 310},\n\tdictWord{7, 0, 1849},\n\tdictWord{8, 0, 72},\n\tdictWord{8, 0, 272},\n\tdictWord{8, 0, 431},\n\tdictWord{9, 0, 12},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t376,\n\t},\n\tdictWord{10, 0, 563},\n\tdictWord{10, 0, 630},\n\tdictWord{10, 0, 796},\n\tdictWord{10, 0, 810},\n\tdictWord{11, 0, 367},\n\tdictWord{11, 0, 599},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t686,\n\t},\n\tdictWord{140, 0, 672},\n\tdictWord{7, 0, 570},\n\tdictWord{4, 11, 396},\n\tdictWord{7, 10, 120},\n\tdictWord{7, 11, 728},\n\tdictWord{8, 10, 489},\n\tdictWord{9, 11, 117},\n\tdictWord{9, 10, 319},\n\tdictWord{10, 10, 820},\n\tdictWord{11, 10, 1004},\n\tdictWord{12, 10, 379},\n\tdictWord{12, 10, 679},\n\tdictWord{13, 10, 117},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t202,\n\t},\n\tdictWord{13, 10, 412},\n\tdictWord{14, 10, 25},\n\tdictWord{15, 10, 52},\n\tdictWord{15, 10, 161},\n\tdictWord{16, 10, 47},\n\tdictWord{20, 11, 51},\n\tdictWord{\n\t\t149,\n\t\t10,\n\t\t2,\n\t},\n\tdictWord{6, 11, 121},\n\tdictWord{6, 11, 124},\n\tdictWord{6, 11, 357},\n\tdictWord{7, 11, 1138},\n\tdictWord{7, 11, 1295},\n\tdictWord{8, 11, 162},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t655,\n\t},\n\tdictWord{8, 0, 449},\n\tdictWord{4, 10, 937},\n\tdictWord{5, 10, 801},\n\tdictWord{136, 11, 449},\n\tdictWord{139, 11, 958},\n\tdictWord{6, 0, 181},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t537,\n\t},\n\tdictWord{8, 0, 64},\n\tdictWord{9, 0, 127},\n\tdictWord{10, 0, 496},\n\tdictWord{12, 0, 510},\n\tdictWord{141, 0, 384},\n\tdictWord{138, 11, 253},\n\tdictWord{4, 0, 244},\n\tdictWord{135, 0, 233},\n\tdictWord{133, 11, 237},\n\tdictWord{132, 10, 365},\n\tdictWord{6, 0, 1650},\n\tdictWord{10, 0, 702},\n\tdictWord{139, 0, 245},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t7,\n\t},\n\tdictWord{139, 10, 774},\n\tdictWord{13, 0, 463},\n\tdictWord{20, 0, 49},\n\tdictWord{13, 11, 463},\n\tdictWord{148, 11, 49},\n\tdictWord{4, 10, 734},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t662,\n\t},\n\tdictWord{134, 10, 430},\n\tdictWord{4, 10, 746},\n\tdictWord{135, 10, 1090},\n\tdictWord{5, 10, 360},\n\tdictWord{136, 10, 237},\n\tdictWord{137, 0, 338},\n\tdictWord{143, 11, 10},\n\tdictWord{7, 11, 571},\n\tdictWord{138, 11, 366},\n\tdictWord{134, 0, 1279},\n\tdictWord{9, 11, 513},\n\tdictWord{10, 11, 22},\n\tdictWord{10, 11, 39},\n\tdictWord{12, 11, 122},\n\tdictWord{140, 11, 187},\n\tdictWord{133, 0, 896},\n\tdictWord{146, 0, 178},\n\tdictWord{134, 0, 695},\n\tdictWord{137, 0, 808},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t587,\n\t},\n\tdictWord{7, 11, 107},\n\tdictWord{7, 11, 838},\n\tdictWord{8, 11, 550},\n\tdictWord{138, 11, 401},\n\tdictWord{7, 0, 1117},\n\tdictWord{136, 0, 539},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t277,\n\t},\n\tdictWord{5, 10, 608},\n\tdictWord{6, 10, 493},\n\tdictWord{7, 10, 457},\n\tdictWord{140, 10, 384},\n\tdictWord{133, 11, 768},\n\tdictWord{12, 0, 257},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t27,\n\t},\n\tdictWord{135, 10, 316},\n\tdictWord{140, 0, 1003},\n\tdictWord{4, 0, 207},\n\tdictWord{5, 0, 586},\n\tdictWord{5, 0, 676},\n\tdictWord{6, 0, 448},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t244,\n\t},\n\tdictWord{11, 0, 1},\n\tdictWord{13, 0, 3},\n\tdictWord{16, 0, 54},\n\tdictWord{17, 0, 4},\n\tdictWord{18, 0, 13},\n\tdictWord{133, 10, 552},\n\tdictWord{4, 10, 401},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t264,\n\t},\n\tdictWord{5, 0, 516},\n\tdictWord{7, 0, 1883},\n\tdictWord{135, 11, 1883},\n\tdictWord{12, 0, 960},\n\tdictWord{132, 11, 894},\n\tdictWord{5, 0, 4},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t810,\n\t},\n\tdictWord{6, 0, 13},\n\tdictWord{6, 0, 538},\n\tdictWord{6, 0, 1690},\n\tdictWord{6, 0, 1726},\n\tdictWord{7, 0, 499},\n\tdictWord{7, 0, 1819},\n\tdictWord{8, 0, 148},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t696,\n\t},\n\tdictWord{8, 0, 791},\n\tdictWord{12, 0, 125},\n\tdictWord{143, 0, 9},\n\tdictWord{135, 0, 1268},\n\tdictWord{11, 0, 30},\n\tdictWord{14, 0, 315},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t543,\n\t},\n\tdictWord{10, 10, 524},\n\tdictWord{12, 10, 524},\n\tdictWord{16, 10, 18},\n\tdictWord{20, 10, 26},\n\tdictWord{148, 10, 65},\n\tdictWord{6, 0, 748},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t205,\n\t},\n\tdictWord{5, 10, 623},\n\tdictWord{7, 10, 104},\n\tdictWord{136, 10, 519},\n\tdictWord{11, 0, 542},\n\tdictWord{139, 0, 852},\n\tdictWord{140, 0, 6},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t848,\n\t},\n\tdictWord{7, 0, 1385},\n\tdictWord{11, 0, 582},\n\tdictWord{11, 0, 650},\n\tdictWord{11, 0, 901},\n\tdictWord{11, 0, 949},\n\tdictWord{12, 0, 232},\n\tdictWord{12, 0, 236},\n\tdictWord{13, 0, 413},\n\tdictWord{13, 0, 501},\n\tdictWord{18, 0, 116},\n\tdictWord{7, 10, 579},\n\tdictWord{9, 10, 41},\n\tdictWord{9, 10, 244},\n\tdictWord{9, 10, 669},\n\tdictWord{10, 10, 5},\n\tdictWord{11, 10, 861},\n\tdictWord{11, 10, 951},\n\tdictWord{139, 10, 980},\n\tdictWord{4, 0, 945},\n\tdictWord{6, 0, 1811},\n\tdictWord{6, 0, 1845},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1853,\n\t},\n\tdictWord{6, 0, 1858},\n\tdictWord{8, 0, 862},\n\tdictWord{12, 0, 782},\n\tdictWord{12, 0, 788},\n\tdictWord{18, 0, 160},\n\tdictWord{148, 0, 117},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t717,\n\t},\n\tdictWord{4, 0, 925},\n\tdictWord{5, 0, 803},\n\tdictWord{8, 0, 698},\n\tdictWord{138, 0, 828},\n\tdictWord{134, 0, 1416},\n\tdictWord{132, 0, 610},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t992,\n\t},\n\tdictWord{6, 0, 878},\n\tdictWord{134, 0, 1477},\n\tdictWord{135, 0, 1847},\n\tdictWord{138, 11, 531},\n\tdictWord{137, 11, 539},\n\tdictWord{134, 11, 272},\n\tdictWord{133, 0, 383},\n\tdictWord{134, 0, 1404},\n\tdictWord{132, 10, 489},\n\tdictWord{4, 11, 9},\n\tdictWord{5, 11, 128},\n\tdictWord{7, 11, 368},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t480,\n\t},\n\tdictWord{148, 11, 3},\n\tdictWord{136, 0, 986},\n\tdictWord{9, 0, 660},\n\tdictWord{138, 0, 347},\n\tdictWord{135, 10, 892},\n\tdictWord{136, 11, 682},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t572,\n\t},\n\tdictWord{9, 0, 592},\n\tdictWord{11, 0, 680},\n\tdictWord{12, 0, 356},\n\tdictWord{140, 0, 550},\n\tdictWord{7, 0, 1411},\n\tdictWord{138, 11, 527},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t2,\n\t},\n\tdictWord{7, 11, 545},\n\tdictWord{135, 11, 894},\n\tdictWord{137, 10, 473},\n\tdictWord{11, 0, 64},\n\tdictWord{7, 11, 481},\n\tdictWord{7, 10, 819},\n\tdictWord{9, 10, 26},\n\tdictWord{9, 10, 392},\n\tdictWord{9, 11, 792},\n\tdictWord{10, 10, 152},\n\tdictWord{10, 10, 226},\n\tdictWord{12, 10, 276},\n\tdictWord{12, 10, 426},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t589,\n\t},\n\tdictWord{13, 10, 460},\n\tdictWord{15, 10, 97},\n\tdictWord{19, 10, 48},\n\tdictWord{148, 10, 104},\n\tdictWord{135, 10, 51},\n\tdictWord{136, 11, 445},\n\tdictWord{136, 11, 646},\n\tdictWord{135, 0, 606},\n\tdictWord{132, 10, 674},\n\tdictWord{6, 0, 1829},\n\tdictWord{134, 0, 1830},\n\tdictWord{132, 10, 770},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t79,\n\t},\n\tdictWord{7, 10, 1027},\n\tdictWord{7, 10, 1477},\n\tdictWord{139, 10, 52},\n\tdictWord{5, 11, 530},\n\tdictWord{142, 11, 113},\n\tdictWord{134, 10, 1666},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t748,\n\t},\n\tdictWord{139, 0, 700},\n\tdictWord{134, 10, 195},\n\tdictWord{133, 10, 789},\n\tdictWord{9, 0, 87},\n\tdictWord{10, 0, 365},\n\tdictWord{4, 10, 251},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t688,\n\t},\n\tdictWord{7, 10, 513},\n\tdictWord{135, 10, 1284},\n\tdictWord{136, 11, 111},\n\tdictWord{133, 0, 127},\n\tdictWord{6, 0, 198},\n\tdictWord{140, 0, 83},\n\tdictWord{133, 11, 556},\n\tdictWord{133, 10, 889},\n\tdictWord{4, 10, 160},\n\tdictWord{5, 10, 330},\n\tdictWord{7, 10, 1434},\n\tdictWord{136, 10, 174},\n\tdictWord{5, 0, 276},\n\tdictWord{6, 0, 55},\n\tdictWord{7, 0, 1369},\n\tdictWord{138, 0, 864},\n\tdictWord{8, 11, 16},\n\tdictWord{140, 11, 568},\n\tdictWord{6, 0, 1752},\n\tdictWord{136, 0, 726},\n\tdictWord{135, 0, 1066},\n\tdictWord{133, 0, 764},\n\tdictWord{6, 11, 186},\n\tdictWord{137, 11, 426},\n\tdictWord{11, 0, 683},\n\tdictWord{139, 11, 683},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t309,\n\t},\n\tdictWord{7, 0, 331},\n\tdictWord{138, 0, 550},\n\tdictWord{133, 10, 374},\n\tdictWord{6, 0, 1212},\n\tdictWord{6, 0, 1852},\n\tdictWord{7, 0, 1062},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t874,\n\t},\n\tdictWord{8, 0, 882},\n\tdictWord{138, 0, 936},\n\tdictWord{132, 11, 585},\n\tdictWord{134, 0, 1364},\n\tdictWord{7, 0, 986},\n\tdictWord{133, 10, 731},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t723,\n\t},\n\tdictWord{6, 0, 1408},\n\tdictWord{138, 0, 381},\n\tdictWord{135, 0, 1573},\n\tdictWord{134, 0, 1025},\n\tdictWord{4, 10, 626},\n\tdictWord{5, 10, 642},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t425,\n\t},\n\tdictWord{10, 10, 202},\n\tdictWord{139, 10, 141},\n\tdictWord{4, 11, 93},\n\tdictWord{5, 11, 252},\n\tdictWord{6, 11, 229},\n\tdictWord{7, 11, 291},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t550,\n\t},\n\tdictWord{139, 11, 644},\n\tdictWord{137, 11, 749},\n\tdictWord{137, 11, 162},\n\tdictWord{132, 11, 381},\n\tdictWord{135, 0, 1559},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t194,\n\t},\n\tdictWord{7, 0, 133},\n\tdictWord{10, 0, 493},\n\tdictWord{10, 0, 570},\n\tdictWord{139, 0, 664},\n\tdictWord{5, 0, 24},\n\tdictWord{5, 0, 569},\n\tdictWord{6, 0, 3},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t119,\n\t},\n\tdictWord{6, 0, 143},\n\tdictWord{6, 0, 440},\n\tdictWord{7, 0, 295},\n\tdictWord{7, 0, 599},\n\tdictWord{7, 0, 1686},\n\tdictWord{7, 0, 1854},\n\tdictWord{8, 0, 424},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t43,\n\t},\n\tdictWord{9, 0, 584},\n\tdictWord{9, 0, 760},\n\tdictWord{10, 0, 148},\n\tdictWord{10, 0, 328},\n\tdictWord{11, 0, 159},\n\tdictWord{11, 0, 253},\n\tdictWord{11, 0, 506},\n\tdictWord{12, 0, 487},\n\tdictWord{140, 0, 531},\n\tdictWord{6, 0, 661},\n\tdictWord{134, 0, 1517},\n\tdictWord{136, 10, 835},\n\tdictWord{151, 10, 17},\n\tdictWord{5, 0, 14},\n\tdictWord{5, 0, 892},\n\tdictWord{6, 0, 283},\n\tdictWord{7, 0, 234},\n\tdictWord{136, 0, 537},\n\tdictWord{139, 0, 541},\n\tdictWord{4, 0, 126},\n\tdictWord{8, 0, 635},\n\tdictWord{\n\t\t147,\n\t\t0,\n\t\t34,\n\t},\n\tdictWord{4, 0, 316},\n\tdictWord{4, 0, 495},\n\tdictWord{135, 0, 1561},\n\tdictWord{4, 11, 187},\n\tdictWord{5, 11, 184},\n\tdictWord{5, 11, 690},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1869,\n\t},\n\tdictWord{138, 11, 756},\n\tdictWord{139, 11, 783},\n\tdictWord{4, 0, 998},\n\tdictWord{137, 0, 861},\n\tdictWord{136, 0, 1009},\n\tdictWord{139, 11, 292},\n\tdictWord{5, 11, 21},\n\tdictWord{6, 11, 77},\n\tdictWord{6, 11, 157},\n\tdictWord{7, 11, 974},\n\tdictWord{7, 11, 1301},\n\tdictWord{7, 11, 1339},\n\tdictWord{7, 11, 1490},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1873,\n\t},\n\tdictWord{137, 11, 628},\n\tdictWord{7, 11, 1283},\n\tdictWord{9, 11, 227},\n\tdictWord{9, 11, 499},\n\tdictWord{10, 11, 341},\n\tdictWord{11, 11, 325},\n\tdictWord{11, 11, 408},\n\tdictWord{14, 11, 180},\n\tdictWord{15, 11, 144},\n\tdictWord{18, 11, 47},\n\tdictWord{147, 11, 49},\n\tdictWord{4, 0, 64},\n\tdictWord{5, 0, 352},\n\tdictWord{5, 0, 720},\n\tdictWord{6, 0, 368},\n\tdictWord{139, 0, 359},\n\tdictWord{5, 10, 384},\n\tdictWord{8, 10, 455},\n\tdictWord{140, 10, 48},\n\tdictWord{5, 10, 264},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t184,\n\t},\n\tdictWord{7, 0, 1577},\n\tdictWord{10, 0, 304},\n\tdictWord{10, 0, 549},\n\tdictWord{12, 0, 365},\n\tdictWord{13, 0, 220},\n\tdictWord{13, 0, 240},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t33,\n\t},\n\tdictWord{134, 0, 1107},\n\tdictWord{134, 0, 929},\n\tdictWord{135, 0, 1142},\n\tdictWord{6, 0, 175},\n\tdictWord{137, 0, 289},\n\tdictWord{5, 0, 432},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t913,\n\t},\n\tdictWord{6, 0, 279},\n\tdictWord{7, 0, 219},\n\tdictWord{5, 10, 633},\n\tdictWord{135, 10, 1323},\n\tdictWord{7, 0, 785},\n\tdictWord{7, 10, 359},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t243,\n\t},\n\tdictWord{140, 10, 175},\n\tdictWord{139, 0, 595},\n\tdictWord{132, 10, 105},\n\tdictWord{8, 11, 398},\n\tdictWord{9, 11, 681},\n\tdictWord{139, 11, 632},\n\tdictWord{140, 0, 80},\n\tdictWord{5, 0, 931},\n\tdictWord{134, 0, 1698},\n\tdictWord{142, 11, 241},\n\tdictWord{134, 11, 20},\n\tdictWord{134, 0, 1323},\n\tdictWord{11, 0, 526},\n\tdictWord{11, 0, 939},\n\tdictWord{141, 0, 290},\n\tdictWord{5, 0, 774},\n\tdictWord{6, 0, 780},\n\tdictWord{6, 0, 1637},\n\tdictWord{6, 0, 1686},\n\tdictWord{6, 0, 1751},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t559,\n\t},\n\tdictWord{141, 0, 109},\n\tdictWord{141, 0, 127},\n\tdictWord{7, 0, 1167},\n\tdictWord{11, 0, 934},\n\tdictWord{13, 0, 391},\n\tdictWord{17, 0, 76},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t709,\n\t},\n\tdictWord{135, 0, 963},\n\tdictWord{6, 0, 260},\n\tdictWord{135, 0, 1484},\n\tdictWord{134, 0, 573},\n\tdictWord{4, 10, 758},\n\tdictWord{139, 11, 941},\n\tdictWord{135, 10, 1649},\n\tdictWord{145, 11, 36},\n\tdictWord{4, 0, 292},\n\tdictWord{137, 0, 580},\n\tdictWord{4, 0, 736},\n\tdictWord{5, 0, 871},\n\tdictWord{6, 0, 1689},\n\tdictWord{135, 0, 1944},\n\tdictWord{7, 11, 945},\n\tdictWord{11, 11, 713},\n\tdictWord{139, 11, 744},\n\tdictWord{134, 0, 1164},\n\tdictWord{135, 11, 937},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1922,\n\t},\n\tdictWord{9, 0, 982},\n\tdictWord{15, 0, 173},\n\tdictWord{15, 0, 178},\n\tdictWord{15, 0, 200},\n\tdictWord{18, 0, 189},\n\tdictWord{18, 0, 207},\n\tdictWord{21, 0, 47},\n\tdictWord{135, 11, 1652},\n\tdictWord{7, 0, 1695},\n\tdictWord{139, 10, 128},\n\tdictWord{6, 0, 63},\n\tdictWord{135, 0, 920},\n\tdictWord{133, 0, 793},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t134,\n\t},\n\tdictWord{133, 10, 918},\n\tdictWord{5, 0, 67},\n\tdictWord{6, 0, 62},\n\tdictWord{6, 0, 374},\n\tdictWord{135, 0, 1391},\n\tdictWord{9, 0, 790},\n\tdictWord{12, 0, 47},\n\tdictWord{4, 11, 579},\n\tdictWord{5, 11, 226},\n\tdictWord{5, 11, 323},\n\tdictWord{135, 11, 960},\n\tdictWord{10, 11, 784},\n\tdictWord{141, 11, 191},\n\tdictWord{4, 0, 391},\n\tdictWord{135, 0, 1169},\n\tdictWord{137, 0, 443},\n\tdictWord{13, 11, 232},\n\tdictWord{146, 11, 35},\n\tdictWord{132, 10, 340},\n\tdictWord{132, 0, 271},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t313,\n\t},\n\tdictWord{5, 11, 973},\n\tdictWord{137, 11, 659},\n\tdictWord{134, 0, 1140},\n\tdictWord{6, 11, 135},\n\tdictWord{135, 11, 1176},\n\tdictWord{4, 0, 253},\n\tdictWord{5, 0, 544},\n\tdictWord{7, 0, 300},\n\tdictWord{137, 0, 340},\n\tdictWord{7, 0, 897},\n\tdictWord{5, 10, 985},\n\tdictWord{7, 10, 509},\n\tdictWord{145, 10, 96},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t735,\n\t},\n\tdictWord{135, 10, 1919},\n\tdictWord{138, 0, 890},\n\tdictWord{5, 0, 818},\n\tdictWord{134, 0, 1122},\n\tdictWord{5, 0, 53},\n\tdictWord{5, 0, 541},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t94,\n\t},\n\tdictWord{6, 0, 499},\n\tdictWord{7, 0, 230},\n\tdictWord{139, 0, 321},\n\tdictWord{4, 0, 920},\n\tdictWord{5, 0, 25},\n\tdictWord{5, 0, 790},\n\tdictWord{6, 0, 457},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t853,\n\t},\n\tdictWord{8, 0, 788},\n\tdictWord{142, 11, 31},\n\tdictWord{132, 10, 247},\n\tdictWord{135, 11, 314},\n\tdictWord{132, 0, 468},\n\tdictWord{7, 0, 243},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t337,\n\t},\n\tdictWord{7, 10, 494},\n\tdictWord{8, 10, 27},\n\tdictWord{8, 10, 599},\n\tdictWord{138, 10, 153},\n\tdictWord{4, 10, 184},\n\tdictWord{5, 10, 390},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t618,\n\t},\n\tdictWord{7, 10, 1456},\n\tdictWord{139, 10, 710},\n\tdictWord{134, 0, 870},\n\tdictWord{134, 0, 1238},\n\tdictWord{134, 0, 1765},\n\tdictWord{10, 0, 853},\n\tdictWord{10, 0, 943},\n\tdictWord{14, 0, 437},\n\tdictWord{14, 0, 439},\n\tdictWord{14, 0, 443},\n\tdictWord{14, 0, 446},\n\tdictWord{14, 0, 452},\n\tdictWord{14, 0, 469},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t471,\n\t},\n\tdictWord{14, 0, 473},\n\tdictWord{16, 0, 93},\n\tdictWord{16, 0, 102},\n\tdictWord{16, 0, 110},\n\tdictWord{148, 0, 121},\n\tdictWord{4, 0, 605},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t518,\n\t},\n\tdictWord{7, 0, 1282},\n\tdictWord{7, 0, 1918},\n\tdictWord{10, 0, 180},\n\tdictWord{139, 0, 218},\n\tdictWord{133, 0, 822},\n\tdictWord{4, 0, 634},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t916,\n\t},\n\tdictWord{142, 0, 419},\n\tdictWord{6, 11, 281},\n\tdictWord{7, 11, 6},\n\tdictWord{8, 11, 282},\n\tdictWord{8, 11, 480},\n\tdictWord{8, 11, 499},\n\tdictWord{9, 11, 198},\n\tdictWord{10, 11, 143},\n\tdictWord{10, 11, 169},\n\tdictWord{10, 11, 211},\n\tdictWord{10, 11, 417},\n\tdictWord{10, 11, 574},\n\tdictWord{11, 11, 147},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t395,\n\t},\n\tdictWord{12, 11, 75},\n\tdictWord{12, 11, 407},\n\tdictWord{12, 11, 608},\n\tdictWord{13, 11, 500},\n\tdictWord{142, 11, 251},\n\tdictWord{134, 0, 898},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t36,\n\t},\n\tdictWord{7, 0, 658},\n\tdictWord{8, 0, 454},\n\tdictWord{150, 11, 48},\n\tdictWord{133, 11, 674},\n\tdictWord{135, 11, 1776},\n\tdictWord{4, 11, 419},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t227,\n\t},\n\tdictWord{11, 10, 497},\n\tdictWord{11, 10, 709},\n\tdictWord{140, 10, 415},\n\tdictWord{6, 10, 360},\n\tdictWord{7, 10, 1664},\n\tdictWord{136, 10, 478},\n\tdictWord{137, 0, 806},\n\tdictWord{12, 11, 508},\n\tdictWord{14, 11, 102},\n\tdictWord{14, 11, 226},\n\tdictWord{144, 11, 57},\n\tdictWord{135, 11, 1123},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t138,\n\t},\n\tdictWord{7, 11, 1012},\n\tdictWord{7, 11, 1280},\n\tdictWord{137, 11, 76},\n\tdictWord{5, 11, 29},\n\tdictWord{140, 11, 638},\n\tdictWord{136, 10, 699},\n\tdictWord{134, 0, 1326},\n\tdictWord{132, 0, 104},\n\tdictWord{135, 11, 735},\n\tdictWord{132, 10, 739},\n\tdictWord{134, 0, 1331},\n\tdictWord{7, 0, 260},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t260,\n\t},\n\tdictWord{135, 11, 1063},\n\tdictWord{7, 0, 45},\n\tdictWord{9, 0, 542},\n\tdictWord{9, 0, 566},\n\tdictWord{10, 0, 728},\n\tdictWord{137, 10, 869},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t67,\n\t},\n\tdictWord{5, 10, 422},\n\tdictWord{7, 10, 1037},\n\tdictWord{7, 10, 1289},\n\tdictWord{7, 10, 1555},\n\tdictWord{9, 10, 741},\n\tdictWord{145, 10, 108},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t263,\n\t},\n\tdictWord{134, 0, 1516},\n\tdictWord{14, 0, 146},\n\tdictWord{15, 0, 42},\n\tdictWord{16, 0, 23},\n\tdictWord{17, 0, 86},\n\tdictWord{146, 0, 17},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t468,\n\t},\n\tdictWord{136, 0, 1005},\n\tdictWord{4, 11, 17},\n\tdictWord{5, 11, 23},\n\tdictWord{7, 11, 995},\n\tdictWord{11, 11, 383},\n\tdictWord{11, 11, 437},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t460,\n\t},\n\tdictWord{140, 11, 532},\n\tdictWord{7, 0, 87},\n\tdictWord{142, 0, 288},\n\tdictWord{138, 10, 96},\n\tdictWord{135, 11, 626},\n\tdictWord{144, 10, 26},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t988,\n\t},\n\tdictWord{7, 0, 1939},\n\tdictWord{9, 0, 64},\n\tdictWord{9, 0, 502},\n\tdictWord{12, 0, 22},\n\tdictWord{12, 0, 34},\n\tdictWord{13, 0, 12},\n\tdictWord{13, 0, 234},\n\tdictWord{147, 0, 77},\n\tdictWord{13, 0, 133},\n\tdictWord{8, 10, 203},\n\tdictWord{11, 10, 823},\n\tdictWord{11, 10, 846},\n\tdictWord{12, 10, 482},\n\tdictWord{13, 10, 277},\n\tdictWord{13, 10, 302},\n\tdictWord{13, 10, 464},\n\tdictWord{14, 10, 205},\n\tdictWord{142, 10, 221},\n\tdictWord{4, 10, 449},\n\tdictWord{133, 10, 718},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t141,\n\t},\n\tdictWord{6, 0, 1842},\n\tdictWord{136, 0, 872},\n\tdictWord{8, 11, 70},\n\tdictWord{12, 11, 171},\n\tdictWord{141, 11, 272},\n\tdictWord{4, 10, 355},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t311,\n\t},\n\tdictWord{9, 10, 256},\n\tdictWord{138, 10, 404},\n\tdictWord{132, 0, 619},\n\tdictWord{137, 0, 261},\n\tdictWord{10, 11, 233},\n\tdictWord{10, 10, 758},\n\tdictWord{139, 11, 76},\n\tdictWord{5, 0, 246},\n\tdictWord{8, 0, 189},\n\tdictWord{9, 0, 355},\n\tdictWord{9, 0, 512},\n\tdictWord{10, 0, 124},\n\tdictWord{10, 0, 453},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t143,\n\t},\n\tdictWord{11, 0, 416},\n\tdictWord{11, 0, 859},\n\tdictWord{141, 0, 341},\n\tdictWord{134, 11, 442},\n\tdictWord{133, 10, 827},\n\tdictWord{5, 10, 64},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t581,\n\t},\n\tdictWord{4, 10, 442},\n\tdictWord{7, 10, 1047},\n\tdictWord{7, 10, 1352},\n\tdictWord{135, 10, 1643},\n\tdictWord{134, 11, 1709},\n\tdictWord{5, 0, 678},\n\tdictWord{6, 0, 305},\n\tdictWord{7, 0, 775},\n\tdictWord{7, 0, 1065},\n\tdictWord{133, 10, 977},\n\tdictWord{11, 11, 69},\n\tdictWord{12, 11, 105},\n\tdictWord{12, 11, 117},\n\tdictWord{13, 11, 213},\n\tdictWord{14, 11, 13},\n\tdictWord{14, 11, 62},\n\tdictWord{14, 11, 177},\n\tdictWord{14, 11, 421},\n\tdictWord{15, 11, 19},\n\tdictWord{146, 11, 141},\n\tdictWord{137, 11, 309},\n\tdictWord{5, 0, 35},\n\tdictWord{7, 0, 862},\n\tdictWord{7, 0, 1886},\n\tdictWord{138, 0, 179},\n\tdictWord{136, 0, 285},\n\tdictWord{132, 0, 517},\n\tdictWord{7, 11, 976},\n\tdictWord{9, 11, 146},\n\tdictWord{10, 11, 206},\n\tdictWord{10, 11, 596},\n\tdictWord{13, 11, 218},\n\tdictWord{142, 11, 153},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t254,\n\t},\n\tdictWord{6, 0, 214},\n\tdictWord{12, 0, 540},\n\tdictWord{4, 10, 275},\n\tdictWord{7, 10, 1219},\n\tdictWord{140, 10, 376},\n\tdictWord{8, 0, 667},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t403,\n\t},\n\tdictWord{146, 0, 83},\n\tdictWord{12, 0, 74},\n\tdictWord{10, 11, 648},\n\tdictWord{11, 11, 671},\n\tdictWord{143, 11, 46},\n\tdictWord{135, 0, 125},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1753,\n\t},\n\tdictWord{133, 0, 761},\n\tdictWord{6, 0, 912},\n\tdictWord{4, 11, 518},\n\tdictWord{6, 10, 369},\n\tdictWord{6, 10, 502},\n\tdictWord{7, 10, 1036},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1136,\n\t},\n\tdictWord{8, 10, 348},\n\tdictWord{9, 10, 452},\n\tdictWord{10, 10, 26},\n\tdictWord{11, 10, 224},\n\tdictWord{11, 10, 387},\n\tdictWord{11, 10, 772},\n\tdictWord{12, 10, 95},\n\tdictWord{12, 10, 629},\n\tdictWord{13, 10, 195},\n\tdictWord{13, 10, 207},\n\tdictWord{13, 10, 241},\n\tdictWord{14, 10, 260},\n\tdictWord{14, 10, 270},\n\tdictWord{143, 10, 140},\n\tdictWord{10, 0, 131},\n\tdictWord{140, 0, 72},\n\tdictWord{132, 10, 269},\n\tdictWord{5, 10, 480},\n\tdictWord{7, 10, 532},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1197,\n\t},\n\tdictWord{7, 10, 1358},\n\tdictWord{8, 10, 291},\n\tdictWord{11, 10, 349},\n\tdictWord{142, 10, 396},\n\tdictWord{8, 11, 689},\n\tdictWord{137, 11, 863},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t333,\n\t},\n\tdictWord{138, 0, 182},\n\tdictWord{4, 11, 18},\n\tdictWord{7, 11, 145},\n\tdictWord{7, 11, 444},\n\tdictWord{7, 11, 1278},\n\tdictWord{8, 11, 49},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t400,\n\t},\n\tdictWord{9, 11, 71},\n\tdictWord{9, 11, 250},\n\tdictWord{10, 11, 459},\n\tdictWord{12, 11, 160},\n\tdictWord{144, 11, 24},\n\tdictWord{14, 11, 35},\n\tdictWord{\n\t\t142,\n\t\t11,\n\t\t191,\n\t},\n\tdictWord{135, 11, 1864},\n\tdictWord{135, 0, 1338},\n\tdictWord{148, 10, 15},\n\tdictWord{14, 0, 94},\n\tdictWord{15, 0, 65},\n\tdictWord{16, 0, 4},\n\tdictWord{\n\t\t16,\n\t\t0,\n\t\t77,\n\t},\n\tdictWord{16, 0, 80},\n\tdictWord{145, 0, 5},\n\tdictWord{12, 11, 82},\n\tdictWord{143, 11, 36},\n\tdictWord{133, 11, 1010},\n\tdictWord{133, 0, 449},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t646,\n\t},\n\tdictWord{7, 0, 86},\n\tdictWord{8, 0, 103},\n\tdictWord{135, 10, 657},\n\tdictWord{7, 0, 2028},\n\tdictWord{138, 0, 641},\n\tdictWord{136, 10, 533},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1,\n\t},\n\tdictWord{139, 11, 970},\n\tdictWord{5, 11, 87},\n\tdictWord{7, 11, 313},\n\tdictWord{7, 11, 1103},\n\tdictWord{10, 11, 112},\n\tdictWord{10, 11, 582},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t389,\n\t},\n\tdictWord{11, 11, 813},\n\tdictWord{12, 11, 385},\n\tdictWord{13, 11, 286},\n\tdictWord{14, 11, 124},\n\tdictWord{146, 11, 108},\n\tdictWord{6, 0, 869},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t267,\n\t},\n\tdictWord{6, 0, 277},\n\tdictWord{7, 0, 1274},\n\tdictWord{7, 0, 1386},\n\tdictWord{146, 0, 87},\n\tdictWord{6, 0, 187},\n\tdictWord{7, 0, 39},\n\tdictWord{7, 0, 1203},\n\tdictWord{8, 0, 380},\n\tdictWord{14, 0, 117},\n\tdictWord{149, 0, 28},\n\tdictWord{4, 10, 211},\n\tdictWord{4, 10, 332},\n\tdictWord{5, 10, 335},\n\tdictWord{6, 10, 238},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t269,\n\t},\n\tdictWord{7, 10, 811},\n\tdictWord{7, 10, 1797},\n\tdictWord{8, 10, 836},\n\tdictWord{9, 10, 507},\n\tdictWord{141, 10, 242},\n\tdictWord{4, 0, 785},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t368,\n\t},\n\tdictWord{6, 0, 297},\n\tdictWord{7, 0, 793},\n\tdictWord{139, 0, 938},\n\tdictWord{7, 0, 464},\n\tdictWord{8, 0, 558},\n\tdictWord{11, 0, 105},\n\tdictWord{12, 0, 231},\n\tdictWord{14, 0, 386},\n\tdictWord{15, 0, 102},\n\tdictWord{148, 0, 75},\n\tdictWord{133, 10, 1009},\n\tdictWord{8, 0, 877},\n\tdictWord{140, 0, 731},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t289,\n\t},\n\tdictWord{10, 11, 249},\n\tdictWord{139, 11, 209},\n\tdictWord{132, 11, 561},\n\tdictWord{134, 0, 1608},\n\tdictWord{132, 11, 760},\n\tdictWord{134, 0, 1429},\n\tdictWord{9, 11, 154},\n\tdictWord{140, 11, 485},\n\tdictWord{5, 10, 228},\n\tdictWord{6, 10, 203},\n\tdictWord{7, 10, 156},\n\tdictWord{8, 10, 347},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t265,\n\t},\n\tdictWord{7, 0, 1010},\n\tdictWord{11, 0, 733},\n\tdictWord{11, 0, 759},\n\tdictWord{13, 0, 34},\n\tdictWord{14, 0, 427},\n\tdictWord{146, 0, 45},\n\tdictWord{7, 10, 1131},\n\tdictWord{135, 10, 1468},\n\tdictWord{136, 11, 255},\n\tdictWord{7, 0, 1656},\n\tdictWord{9, 0, 369},\n\tdictWord{10, 0, 338},\n\tdictWord{10, 0, 490},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t154,\n\t},\n\tdictWord{11, 0, 545},\n\tdictWord{11, 0, 775},\n\tdictWord{13, 0, 77},\n\tdictWord{141, 0, 274},\n\tdictWord{133, 11, 621},\n\tdictWord{134, 0, 1038},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t368,\n\t},\n\tdictWord{135, 11, 641},\n\tdictWord{6, 0, 2010},\n\tdictWord{8, 0, 979},\n\tdictWord{8, 0, 985},\n\tdictWord{10, 0, 951},\n\tdictWord{138, 0, 1011},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1005,\n\t},\n\tdictWord{19, 0, 121},\n\tdictWord{5, 10, 291},\n\tdictWord{5, 10, 318},\n\tdictWord{7, 10, 765},\n\tdictWord{9, 10, 389},\n\tdictWord{140, 10, 548},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t20,\n\t},\n\tdictWord{6, 0, 298},\n\tdictWord{7, 0, 659},\n\tdictWord{137, 0, 219},\n\tdictWord{7, 0, 1440},\n\tdictWord{11, 0, 854},\n\tdictWord{11, 0, 872},\n\tdictWord{11, 0, 921},\n\tdictWord{12, 0, 551},\n\tdictWord{13, 0, 472},\n\tdictWord{142, 0, 367},\n\tdictWord{5, 0, 490},\n\tdictWord{6, 0, 615},\n\tdictWord{6, 0, 620},\n\tdictWord{135, 0, 683},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1070,\n\t},\n\tdictWord{134, 0, 1597},\n\tdictWord{139, 0, 522},\n\tdictWord{132, 0, 439},\n\tdictWord{136, 0, 669},\n\tdictWord{6, 0, 766},\n\tdictWord{6, 0, 1143},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1245,\n\t},\n\tdictWord{10, 10, 525},\n\tdictWord{139, 10, 82},\n\tdictWord{9, 11, 92},\n\tdictWord{147, 11, 91},\n\tdictWord{6, 0, 668},\n\tdictWord{134, 0, 1218},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t525,\n\t},\n\tdictWord{9, 11, 876},\n\tdictWord{140, 11, 284},\n\tdictWord{132, 0, 233},\n\tdictWord{136, 0, 547},\n\tdictWord{132, 10, 422},\n\tdictWord{5, 10, 355},\n\tdictWord{145, 10, 0},\n\tdictWord{6, 11, 300},\n\tdictWord{135, 11, 1515},\n\tdictWord{4, 0, 482},\n\tdictWord{137, 10, 905},\n\tdictWord{4, 0, 886},\n\tdictWord{7, 0, 346},\n\tdictWord{133, 11, 594},\n\tdictWord{133, 10, 865},\n\tdictWord{5, 10, 914},\n\tdictWord{134, 10, 1625},\n\tdictWord{135, 0, 334},\n\tdictWord{5, 0, 795},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1741,\n\t},\n\tdictWord{133, 10, 234},\n\tdictWord{135, 10, 1383},\n\tdictWord{6, 11, 1641},\n\tdictWord{136, 11, 820},\n\tdictWord{135, 0, 371},\n\tdictWord{7, 11, 1313},\n\tdictWord{138, 11, 660},\n\tdictWord{135, 10, 1312},\n\tdictWord{135, 0, 622},\n\tdictWord{7, 0, 625},\n\tdictWord{135, 0, 1750},\n\tdictWord{135, 0, 339},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t203,\n\t},\n\tdictWord{135, 0, 1936},\n\tdictWord{15, 0, 29},\n\tdictWord{16, 0, 38},\n\tdictWord{15, 11, 29},\n\tdictWord{144, 11, 38},\n\tdictWord{5, 0, 338},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1256,\n\t},\n\tdictWord{135, 10, 1493},\n\tdictWord{10, 0, 130},\n\tdictWord{6, 10, 421},\n\tdictWord{7, 10, 61},\n\tdictWord{7, 10, 1540},\n\tdictWord{138, 10, 501},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t389,\n\t},\n\tdictWord{7, 11, 149},\n\tdictWord{9, 11, 142},\n\tdictWord{138, 11, 94},\n\tdictWord{137, 10, 341},\n\tdictWord{11, 0, 678},\n\tdictWord{12, 0, 307},\n\tdictWord{142, 10, 98},\n\tdictWord{6, 11, 8},\n\tdictWord{7, 11, 1881},\n\tdictWord{136, 11, 91},\n\tdictWord{135, 0, 2044},\n\tdictWord{6, 0, 770},\n\tdictWord{6, 0, 802},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t812,\n\t},\n\tdictWord{7, 0, 311},\n\tdictWord{9, 0, 308},\n\tdictWord{12, 0, 255},\n\tdictWord{6, 10, 102},\n\tdictWord{7, 10, 72},\n\tdictWord{15, 10, 142},\n\tdictWord{\n\t\t147,\n\t\t10,\n\t\t67,\n\t},\n\tdictWord{151, 10, 30},\n\tdictWord{135, 10, 823},\n\tdictWord{135, 0, 1266},\n\tdictWord{135, 11, 1746},\n\tdictWord{135, 10, 1870},\n\tdictWord{4, 0, 400},\n\tdictWord{5, 0, 267},\n\tdictWord{135, 0, 232},\n\tdictWord{7, 11, 24},\n\tdictWord{11, 11, 542},\n\tdictWord{139, 11, 852},\n\tdictWord{135, 11, 1739},\n\tdictWord{4, 11, 503},\n\tdictWord{135, 11, 1661},\n\tdictWord{5, 11, 130},\n\tdictWord{7, 11, 1314},\n\tdictWord{9, 11, 610},\n\tdictWord{10, 11, 718},\n\tdictWord{11, 11, 601},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t819,\n\t},\n\tdictWord{11, 11, 946},\n\tdictWord{140, 11, 536},\n\tdictWord{10, 11, 149},\n\tdictWord{11, 11, 280},\n\tdictWord{142, 11, 336},\n\tdictWord{7, 0, 739},\n\tdictWord{11, 0, 690},\n\tdictWord{7, 11, 1946},\n\tdictWord{8, 10, 48},\n\tdictWord{8, 10, 88},\n\tdictWord{8, 10, 582},\n\tdictWord{8, 10, 681},\n\tdictWord{9, 10, 373},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t864,\n\t},\n\tdictWord{11, 10, 157},\n\tdictWord{11, 10, 843},\n\tdictWord{148, 10, 27},\n\tdictWord{134, 0, 990},\n\tdictWord{4, 10, 88},\n\tdictWord{5, 10, 137},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t174,\n\t},\n\tdictWord{5, 10, 777},\n\tdictWord{6, 10, 1664},\n\tdictWord{6, 10, 1725},\n\tdictWord{7, 10, 77},\n\tdictWord{7, 10, 426},\n\tdictWord{7, 10, 1317},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1355,\n\t},\n\tdictWord{8, 10, 126},\n\tdictWord{8, 10, 563},\n\tdictWord{9, 10, 523},\n\tdictWord{9, 10, 750},\n\tdictWord{10, 10, 310},\n\tdictWord{10, 10, 836},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t42,\n\t},\n\tdictWord{11, 10, 318},\n\tdictWord{11, 10, 731},\n\tdictWord{12, 10, 68},\n\tdictWord{12, 10, 92},\n\tdictWord{12, 10, 507},\n\tdictWord{12, 10, 692},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t81,\n\t},\n\tdictWord{13, 10, 238},\n\tdictWord{13, 10, 374},\n\tdictWord{14, 10, 436},\n\tdictWord{18, 10, 138},\n\tdictWord{19, 10, 78},\n\tdictWord{19, 10, 111},\n\tdictWord{20, 10, 55},\n\tdictWord{20, 10, 77},\n\tdictWord{148, 10, 92},\n\tdictWord{141, 10, 418},\n\tdictWord{7, 0, 1831},\n\tdictWord{132, 10, 938},\n\tdictWord{6, 0, 776},\n\tdictWord{134, 0, 915},\n\tdictWord{138, 10, 351},\n\tdictWord{5, 11, 348},\n\tdictWord{6, 11, 522},\n\tdictWord{6, 10, 1668},\n\tdictWord{7, 10, 1499},\n\tdictWord{8, 10, 117},\n\tdictWord{9, 10, 314},\n\tdictWord{138, 10, 174},\n\tdictWord{135, 10, 707},\n\tdictWord{132, 0, 613},\n\tdictWord{133, 10, 403},\n\tdictWord{132, 11, 392},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t433,\n\t},\n\tdictWord{9, 11, 633},\n\tdictWord{139, 11, 629},\n\tdictWord{133, 0, 763},\n\tdictWord{132, 0, 878},\n\tdictWord{132, 0, 977},\n\tdictWord{132, 0, 100},\n\tdictWord{6, 0, 463},\n\tdictWord{4, 10, 44},\n\tdictWord{5, 10, 311},\n\tdictWord{7, 10, 639},\n\tdictWord{7, 10, 762},\n\tdictWord{7, 10, 1827},\n\tdictWord{9, 10, 8},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t462,\n\t},\n\tdictWord{148, 10, 83},\n\tdictWord{134, 11, 234},\n\tdictWord{4, 10, 346},\n\tdictWord{7, 10, 115},\n\tdictWord{9, 10, 180},\n\tdictWord{9, 10, 456},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t363,\n\t},\n\tdictWord{5, 0, 362},\n\tdictWord{5, 0, 443},\n\tdictWord{6, 0, 318},\n\tdictWord{7, 0, 1019},\n\tdictWord{139, 0, 623},\n\tdictWord{5, 0, 463},\n\tdictWord{8, 0, 296},\n\tdictWord{7, 11, 140},\n\tdictWord{7, 11, 1950},\n\tdictWord{8, 11, 680},\n\tdictWord{11, 11, 817},\n\tdictWord{147, 11, 88},\n\tdictWord{7, 11, 1222},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t386,\n\t},\n\tdictWord{142, 0, 137},\n\tdictWord{132, 0, 454},\n\tdictWord{7, 0, 1914},\n\tdictWord{6, 11, 5},\n\tdictWord{7, 10, 1051},\n\tdictWord{9, 10, 545},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t249,\n\t},\n\tdictWord{12, 11, 313},\n\tdictWord{16, 11, 66},\n\tdictWord{145, 11, 26},\n\tdictWord{135, 0, 1527},\n\tdictWord{145, 0, 58},\n\tdictWord{148, 11, 59},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t48,\n\t},\n\tdictWord{5, 0, 404},\n\tdictWord{6, 0, 557},\n\tdictWord{7, 0, 458},\n\tdictWord{8, 0, 597},\n\tdictWord{10, 0, 455},\n\tdictWord{10, 0, 606},\n\tdictWord{11, 0, 49},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t548,\n\t},\n\tdictWord{12, 0, 476},\n\tdictWord{13, 0, 18},\n\tdictWord{141, 0, 450},\n\tdictWord{5, 11, 963},\n\tdictWord{134, 11, 1773},\n\tdictWord{133, 0, 729},\n\tdictWord{138, 11, 586},\n\tdictWord{5, 0, 442},\n\tdictWord{135, 0, 1984},\n\tdictWord{134, 0, 449},\n\tdictWord{144, 0, 40},\n\tdictWord{4, 0, 853},\n\tdictWord{7, 11, 180},\n\tdictWord{8, 11, 509},\n\tdictWord{136, 11, 792},\n\tdictWord{6, 10, 185},\n\tdictWord{7, 10, 1899},\n\tdictWord{9, 10, 875},\n\tdictWord{139, 10, 673},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t524,\n\t},\n\tdictWord{12, 0, 227},\n\tdictWord{4, 10, 327},\n\tdictWord{5, 10, 478},\n\tdictWord{7, 10, 1332},\n\tdictWord{136, 10, 753},\n\tdictWord{6, 0, 1491},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t1020,\n\t},\n\tdictWord{133, 10, 1022},\n\tdictWord{4, 10, 103},\n\tdictWord{133, 10, 401},\n\tdictWord{132, 11, 931},\n\tdictWord{4, 10, 499},\n\tdictWord{135, 10, 1421},\n\tdictWord{5, 0, 55},\n\tdictWord{7, 0, 376},\n\tdictWord{140, 0, 161},\n\tdictWord{133, 0, 450},\n\tdictWord{6, 0, 1174},\n\tdictWord{134, 0, 1562},\n\tdictWord{10, 0, 62},\n\tdictWord{13, 0, 400},\n\tdictWord{135, 11, 1837},\n\tdictWord{140, 0, 207},\n\tdictWord{135, 0, 869},\n\tdictWord{4, 11, 773},\n\tdictWord{5, 11, 618},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t756,\n\t},\n\tdictWord{132, 10, 96},\n\tdictWord{4, 0, 213},\n\tdictWord{7, 0, 223},\n\tdictWord{8, 0, 80},\n\tdictWord{135, 10, 968},\n\tdictWord{4, 11, 90},\n\tdictWord{5, 11, 337},\n\tdictWord{5, 11, 545},\n\tdictWord{7, 11, 754},\n\tdictWord{9, 11, 186},\n\tdictWord{10, 11, 72},\n\tdictWord{10, 11, 782},\n\tdictWord{11, 11, 513},\n\tdictWord{11, 11, 577},\n\tdictWord{11, 11, 610},\n\tdictWord{11, 11, 889},\n\tdictWord{11, 11, 961},\n\tdictWord{12, 11, 354},\n\tdictWord{12, 11, 362},\n\tdictWord{12, 11, 461},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t595,\n\t},\n\tdictWord{13, 11, 79},\n\tdictWord{143, 11, 121},\n\tdictWord{7, 0, 381},\n\tdictWord{7, 0, 806},\n\tdictWord{7, 0, 820},\n\tdictWord{8, 0, 354},\n\tdictWord{8, 0, 437},\n\tdictWord{8, 0, 787},\n\tdictWord{9, 0, 657},\n\tdictWord{10, 0, 58},\n\tdictWord{10, 0, 339},\n\tdictWord{10, 0, 749},\n\tdictWord{11, 0, 914},\n\tdictWord{12, 0, 162},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t75,\n\t},\n\tdictWord{14, 0, 106},\n\tdictWord{14, 0, 198},\n\tdictWord{14, 0, 320},\n\tdictWord{14, 0, 413},\n\tdictWord{146, 0, 43},\n\tdictWord{136, 0, 747},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t954,\n\t},\n\tdictWord{134, 0, 1073},\n\tdictWord{135, 0, 556},\n\tdictWord{7, 11, 151},\n\tdictWord{9, 11, 329},\n\tdictWord{139, 11, 254},\n\tdictWord{5, 0, 692},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1395,\n\t},\n\tdictWord{6, 10, 563},\n\tdictWord{137, 10, 224},\n\tdictWord{134, 0, 191},\n\tdictWord{132, 0, 804},\n\tdictWord{9, 11, 187},\n\tdictWord{10, 11, 36},\n\tdictWord{17, 11, 44},\n\tdictWord{146, 11, 64},\n\tdictWord{7, 11, 165},\n\tdictWord{7, 11, 919},\n\tdictWord{136, 11, 517},\n\tdictWord{4, 11, 506},\n\tdictWord{5, 11, 295},\n\tdictWord{7, 11, 1680},\n\tdictWord{15, 11, 14},\n\tdictWord{144, 11, 5},\n\tdictWord{4, 0, 706},\n\tdictWord{6, 0, 162},\n\tdictWord{7, 0, 1960},\n\tdictWord{136, 0, 831},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1376,\n\t},\n\tdictWord{7, 11, 987},\n\tdictWord{9, 11, 688},\n\tdictWord{10, 11, 522},\n\tdictWord{11, 11, 788},\n\tdictWord{140, 11, 566},\n\tdictWord{150, 0, 35},\n\tdictWord{138, 0, 426},\n\tdictWord{135, 0, 1235},\n\tdictWord{135, 11, 1741},\n\tdictWord{7, 11, 389},\n\tdictWord{7, 11, 700},\n\tdictWord{7, 11, 940},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t514,\n\t},\n\tdictWord{9, 11, 116},\n\tdictWord{9, 11, 535},\n\tdictWord{10, 11, 118},\n\tdictWord{11, 11, 107},\n\tdictWord{11, 11, 148},\n\tdictWord{11, 11, 922},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t254,\n\t},\n\tdictWord{12, 11, 421},\n\tdictWord{142, 11, 238},\n\tdictWord{134, 0, 1234},\n\tdictWord{132, 11, 743},\n\tdictWord{4, 10, 910},\n\tdictWord{5, 10, 832},\n\tdictWord{135, 11, 1335},\n\tdictWord{141, 0, 96},\n\tdictWord{135, 11, 185},\n\tdictWord{146, 0, 149},\n\tdictWord{4, 0, 204},\n\tdictWord{137, 0, 902},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t784,\n\t},\n\tdictWord{133, 11, 745},\n\tdictWord{136, 0, 833},\n\tdictWord{136, 0, 949},\n\tdictWord{7, 0, 366},\n\tdictWord{9, 0, 287},\n\tdictWord{12, 0, 199},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t556,\n\t},\n\tdictWord{12, 0, 577},\n\tdictWord{5, 11, 81},\n\tdictWord{7, 11, 146},\n\tdictWord{7, 11, 1342},\n\tdictWord{7, 11, 1446},\n\tdictWord{8, 11, 53},\n\tdictWord{8, 11, 561},\n\tdictWord{8, 11, 694},\n\tdictWord{8, 11, 754},\n\tdictWord{9, 11, 97},\n\tdictWord{9, 11, 115},\n\tdictWord{9, 11, 894},\n\tdictWord{10, 11, 462},\n\tdictWord{10, 11, 813},\n\tdictWord{11, 11, 230},\n\tdictWord{11, 11, 657},\n\tdictWord{11, 11, 699},\n\tdictWord{11, 11, 748},\n\tdictWord{12, 11, 119},\n\tdictWord{12, 11, 200},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t283,\n\t},\n\tdictWord{14, 11, 273},\n\tdictWord{145, 11, 15},\n\tdictWord{5, 11, 408},\n\tdictWord{137, 11, 747},\n\tdictWord{9, 11, 498},\n\tdictWord{140, 11, 181},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t2020,\n\t},\n\tdictWord{136, 0, 992},\n\tdictWord{5, 0, 356},\n\tdictWord{135, 0, 224},\n\tdictWord{134, 0, 784},\n\tdictWord{7, 0, 630},\n\tdictWord{9, 0, 567},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t150,\n\t},\n\tdictWord{11, 0, 444},\n\tdictWord{13, 0, 119},\n\tdictWord{8, 10, 528},\n\tdictWord{137, 10, 348},\n\tdictWord{134, 0, 539},\n\tdictWord{4, 10, 20},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t616,\n\t},\n\tdictWord{142, 0, 27},\n\tdictWord{7, 11, 30},\n\tdictWord{8, 11, 86},\n\tdictWord{8, 11, 315},\n\tdictWord{8, 11, 700},\n\tdictWord{9, 11, 576},\n\tdictWord{9, 11, 858},\n\tdictWord{11, 11, 310},\n\tdictWord{11, 11, 888},\n\tdictWord{11, 11, 904},\n\tdictWord{12, 11, 361},\n\tdictWord{141, 11, 248},\n\tdictWord{138, 11, 839},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t755,\n\t},\n\tdictWord{134, 0, 1063},\n\tdictWord{7, 10, 1091},\n\tdictWord{135, 10, 1765},\n\tdictWord{134, 11, 428},\n\tdictWord{7, 11, 524},\n\tdictWord{8, 11, 169},\n\tdictWord{8, 11, 234},\n\tdictWord{9, 11, 480},\n\tdictWord{138, 11, 646},\n\tdictWord{139, 0, 814},\n\tdictWord{7, 11, 1462},\n\tdictWord{139, 11, 659},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t26,\n\t},\n\tdictWord{5, 10, 429},\n\tdictWord{6, 10, 245},\n\tdictWord{7, 10, 704},\n\tdictWord{7, 10, 1379},\n\tdictWord{135, 10, 1474},\n\tdictWord{7, 11, 1205},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t637,\n\t},\n\tdictWord{139, 11, 803},\n\tdictWord{132, 10, 621},\n\tdictWord{136, 0, 987},\n\tdictWord{4, 11, 266},\n\tdictWord{8, 11, 4},\n\tdictWord{9, 11, 39},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t166,\n\t},\n\tdictWord{11, 11, 918},\n\tdictWord{12, 11, 635},\n\tdictWord{20, 11, 10},\n\tdictWord{22, 11, 27},\n\tdictWord{150, 11, 43},\n\tdictWord{4, 0, 235},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t255,\n\t},\n\tdictWord{4, 0, 194},\n\tdictWord{5, 0, 584},\n\tdictWord{6, 0, 384},\n\tdictWord{7, 0, 583},\n\tdictWord{10, 0, 761},\n\tdictWord{11, 0, 760},\n\tdictWord{139, 0, 851},\n\tdictWord{133, 10, 542},\n\tdictWord{134, 0, 1086},\n\tdictWord{133, 10, 868},\n\tdictWord{8, 0, 1016},\n\tdictWord{136, 0, 1018},\n\tdictWord{7, 0, 1396},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1396,\n\t},\n\tdictWord{136, 10, 433},\n\tdictWord{135, 10, 1495},\n\tdictWord{138, 10, 215},\n\tdictWord{141, 10, 124},\n\tdictWord{7, 11, 157},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t279,\n\t},\n\tdictWord{9, 11, 759},\n\tdictWord{16, 11, 31},\n\tdictWord{16, 11, 39},\n\tdictWord{16, 11, 75},\n\tdictWord{18, 11, 24},\n\tdictWord{20, 11, 42},\n\tdictWord{152, 11, 1},\n\tdictWord{5, 0, 562},\n\tdictWord{134, 11, 604},\n\tdictWord{134, 0, 913},\n\tdictWord{5, 0, 191},\n\tdictWord{137, 0, 271},\n\tdictWord{4, 0, 470},\n\tdictWord{6, 0, 153},\n\tdictWord{7, 0, 1503},\n\tdictWord{7, 0, 1923},\n\tdictWord{10, 0, 701},\n\tdictWord{11, 0, 132},\n\tdictWord{11, 0, 227},\n\tdictWord{11, 0, 320},\n\tdictWord{11, 0, 436},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t525,\n\t},\n\tdictWord{11, 0, 855},\n\tdictWord{11, 0, 873},\n\tdictWord{12, 0, 41},\n\tdictWord{12, 0, 286},\n\tdictWord{13, 0, 103},\n\tdictWord{13, 0, 284},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t255,\n\t},\n\tdictWord{14, 0, 262},\n\tdictWord{15, 0, 117},\n\tdictWord{143, 0, 127},\n\tdictWord{7, 0, 475},\n\tdictWord{12, 0, 45},\n\tdictWord{147, 10, 112},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t567,\n\t},\n\tdictWord{137, 11, 859},\n\tdictWord{6, 0, 713},\n\tdictWord{6, 0, 969},\n\tdictWord{6, 0, 1290},\n\tdictWord{134, 0, 1551},\n\tdictWord{133, 0, 327},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t552,\n\t},\n\tdictWord{6, 0, 1292},\n\tdictWord{7, 0, 1754},\n\tdictWord{137, 0, 604},\n\tdictWord{4, 0, 223},\n\tdictWord{6, 0, 359},\n\tdictWord{11, 0, 3},\n\tdictWord{13, 0, 108},\n\tdictWord{14, 0, 89},\n\tdictWord{16, 0, 22},\n\tdictWord{5, 11, 762},\n\tdictWord{7, 11, 1880},\n\tdictWord{9, 11, 680},\n\tdictWord{139, 11, 798},\n\tdictWord{5, 0, 80},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t405,\n\t},\n\tdictWord{7, 0, 403},\n\tdictWord{7, 0, 1502},\n\tdictWord{8, 0, 456},\n\tdictWord{9, 0, 487},\n\tdictWord{9, 0, 853},\n\tdictWord{9, 0, 889},\n\tdictWord{10, 0, 309},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t721,\n\t},\n\tdictWord{11, 0, 994},\n\tdictWord{12, 0, 430},\n\tdictWord{141, 0, 165},\n\tdictWord{133, 11, 298},\n\tdictWord{132, 10, 647},\n\tdictWord{134, 0, 2016},\n\tdictWord{18, 10, 10},\n\tdictWord{146, 11, 10},\n\tdictWord{4, 0, 453},\n\tdictWord{5, 0, 887},\n\tdictWord{6, 0, 535},\n\tdictWord{8, 0, 6},\n\tdictWord{8, 0, 543},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t826,\n\t},\n\tdictWord{136, 0, 975},\n\tdictWord{10, 0, 961},\n\tdictWord{138, 0, 962},\n\tdictWord{138, 10, 220},\n\tdictWord{6, 0, 1891},\n\tdictWord{6, 0, 1893},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t916,\n\t},\n\tdictWord{9, 0, 965},\n\tdictWord{9, 0, 972},\n\tdictWord{12, 0, 801},\n\tdictWord{12, 0, 859},\n\tdictWord{12, 0, 883},\n\tdictWord{15, 0, 226},\n\tdictWord{149, 0, 51},\n\tdictWord{132, 10, 109},\n\tdictWord{135, 11, 267},\n\tdictWord{7, 11, 92},\n\tdictWord{7, 11, 182},\n\tdictWord{8, 11, 453},\n\tdictWord{9, 11, 204},\n\tdictWord{11, 11, 950},\n\tdictWord{12, 11, 94},\n\tdictWord{12, 11, 644},\n\tdictWord{16, 11, 20},\n\tdictWord{16, 11, 70},\n\tdictWord{16, 11, 90},\n\tdictWord{147, 11, 55},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1746,\n\t},\n\tdictWord{6, 11, 71},\n\tdictWord{7, 11, 845},\n\tdictWord{7, 11, 1308},\n\tdictWord{8, 11, 160},\n\tdictWord{137, 11, 318},\n\tdictWord{5, 0, 101},\n\tdictWord{6, 0, 88},\n\tdictWord{7, 0, 263},\n\tdictWord{7, 0, 628},\n\tdictWord{7, 0, 1677},\n\tdictWord{8, 0, 349},\n\tdictWord{9, 0, 100},\n\tdictWord{10, 0, 677},\n\tdictWord{14, 0, 169},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t302,\n\t},\n\tdictWord{14, 0, 313},\n\tdictWord{15, 0, 48},\n\tdictWord{15, 0, 84},\n\tdictWord{7, 11, 237},\n\tdictWord{8, 11, 664},\n\tdictWord{9, 11, 42},\n\tdictWord{9, 11, 266},\n\tdictWord{9, 11, 380},\n\tdictWord{9, 11, 645},\n\tdictWord{10, 11, 177},\n\tdictWord{138, 11, 276},\n\tdictWord{138, 11, 69},\n\tdictWord{4, 0, 310},\n\tdictWord{7, 0, 708},\n\tdictWord{7, 0, 996},\n\tdictWord{9, 0, 795},\n\tdictWord{10, 0, 390},\n\tdictWord{10, 0, 733},\n\tdictWord{11, 0, 451},\n\tdictWord{12, 0, 249},\n\tdictWord{14, 0, 115},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t286,\n\t},\n\tdictWord{143, 0, 100},\n\tdictWord{5, 0, 587},\n\tdictWord{4, 10, 40},\n\tdictWord{10, 10, 67},\n\tdictWord{11, 10, 117},\n\tdictWord{11, 10, 768},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t935,\n\t},\n\tdictWord{6, 0, 1942},\n\tdictWord{7, 0, 512},\n\tdictWord{136, 0, 983},\n\tdictWord{7, 10, 992},\n\tdictWord{8, 10, 301},\n\tdictWord{9, 10, 722},\n\tdictWord{12, 10, 63},\n\tdictWord{13, 10, 29},\n\tdictWord{14, 10, 161},\n\tdictWord{143, 10, 18},\n\tdictWord{136, 11, 76},\n\tdictWord{139, 10, 923},\n\tdictWord{134, 0, 645},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t851,\n\t},\n\tdictWord{4, 0, 498},\n\tdictWord{132, 11, 293},\n\tdictWord{7, 0, 217},\n\tdictWord{8, 0, 140},\n\tdictWord{10, 0, 610},\n\tdictWord{14, 11, 352},\n\tdictWord{\n\t\t17,\n\t\t11,\n\t\t53,\n\t},\n\tdictWord{18, 11, 146},\n\tdictWord{18, 11, 152},\n\tdictWord{19, 11, 11},\n\tdictWord{150, 11, 54},\n\tdictWord{134, 0, 1448},\n\tdictWord{138, 11, 841},\n\tdictWord{133, 0, 905},\n\tdictWord{4, 11, 605},\n\tdictWord{7, 11, 518},\n\tdictWord{7, 11, 1282},\n\tdictWord{7, 11, 1918},\n\tdictWord{10, 11, 180},\n\tdictWord{139, 11, 218},\n\tdictWord{139, 11, 917},\n\tdictWord{135, 10, 825},\n\tdictWord{140, 10, 328},\n\tdictWord{4, 0, 456},\n\tdictWord{7, 0, 105},\n\tdictWord{7, 0, 358},\n\tdictWord{7, 0, 1637},\n\tdictWord{8, 0, 643},\n\tdictWord{139, 0, 483},\n\tdictWord{134, 0, 792},\n\tdictWord{6, 11, 96},\n\tdictWord{135, 11, 1426},\n\tdictWord{137, 11, 691},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t651,\n\t},\n\tdictWord{133, 11, 289},\n\tdictWord{7, 11, 688},\n\tdictWord{8, 11, 35},\n\tdictWord{9, 11, 511},\n\tdictWord{10, 11, 767},\n\tdictWord{147, 11, 118},\n\tdictWord{\n\t\t150,\n\t\t0,\n\t\t56,\n\t},\n\tdictWord{5, 0, 243},\n\tdictWord{5, 0, 535},\n\tdictWord{6, 10, 204},\n\tdictWord{10, 10, 320},\n\tdictWord{10, 10, 583},\n\tdictWord{13, 10, 502},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t72,\n\t},\n\tdictWord{14, 10, 274},\n\tdictWord{14, 10, 312},\n\tdictWord{14, 10, 344},\n\tdictWord{15, 10, 159},\n\tdictWord{16, 10, 62},\n\tdictWord{16, 10, 69},\n\tdictWord{\n\t\t17,\n\t\t10,\n\t\t30,\n\t},\n\tdictWord{18, 10, 42},\n\tdictWord{18, 10, 53},\n\tdictWord{18, 10, 84},\n\tdictWord{18, 10, 140},\n\tdictWord{19, 10, 68},\n\tdictWord{19, 10, 85},\n\tdictWord{20, 10, 5},\n\tdictWord{20, 10, 45},\n\tdictWord{20, 10, 101},\n\tdictWord{22, 10, 7},\n\tdictWord{150, 10, 20},\n\tdictWord{4, 10, 558},\n\tdictWord{6, 10, 390},\n\tdictWord{7, 10, 162},\n\tdictWord{7, 10, 689},\n\tdictWord{9, 10, 360},\n\tdictWord{138, 10, 653},\n\tdictWord{146, 11, 23},\n\tdictWord{135, 0, 1748},\n\tdictWord{5, 10, 856},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1672,\n\t},\n\tdictWord{6, 10, 1757},\n\tdictWord{134, 10, 1781},\n\tdictWord{5, 0, 539},\n\tdictWord{5, 0, 754},\n\tdictWord{6, 0, 876},\n\tdictWord{132, 11, 704},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1078,\n\t},\n\tdictWord{5, 10, 92},\n\tdictWord{10, 10, 736},\n\tdictWord{140, 10, 102},\n\tdictWord{17, 0, 91},\n\tdictWord{5, 10, 590},\n\tdictWord{137, 10, 213},\n\tdictWord{134, 0, 1565},\n\tdictWord{6, 0, 91},\n\tdictWord{135, 0, 435},\n\tdictWord{4, 0, 939},\n\tdictWord{140, 0, 792},\n\tdictWord{134, 0, 1399},\n\tdictWord{4, 0, 16},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t316,\n\t},\n\tdictWord{5, 0, 842},\n\tdictWord{6, 0, 370},\n\tdictWord{6, 0, 1778},\n\tdictWord{8, 0, 166},\n\tdictWord{11, 0, 812},\n\tdictWord{12, 0, 206},\n\tdictWord{12, 0, 351},\n\tdictWord{14, 0, 418},\n\tdictWord{16, 0, 15},\n\tdictWord{16, 0, 34},\n\tdictWord{18, 0, 3},\n\tdictWord{19, 0, 3},\n\tdictWord{19, 0, 7},\n\tdictWord{20, 0, 4},\n\tdictWord{21, 0, 21},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t720,\n\t},\n\tdictWord{133, 11, 306},\n\tdictWord{144, 0, 95},\n\tdictWord{133, 11, 431},\n\tdictWord{132, 11, 234},\n\tdictWord{135, 0, 551},\n\tdictWord{4, 0, 999},\n\tdictWord{6, 0, 1966},\n\tdictWord{134, 0, 2042},\n\tdictWord{7, 0, 619},\n\tdictWord{10, 0, 547},\n\tdictWord{11, 0, 122},\n\tdictWord{12, 0, 601},\n\tdictWord{15, 0, 7},\n\tdictWord{148, 0, 20},\n\tdictWord{5, 11, 464},\n\tdictWord{6, 11, 236},\n\tdictWord{7, 11, 276},\n\tdictWord{7, 11, 696},\n\tdictWord{7, 11, 914},\n\tdictWord{7, 11, 1108},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1448,\n\t},\n\tdictWord{9, 11, 15},\n\tdictWord{9, 11, 564},\n\tdictWord{10, 11, 14},\n\tdictWord{12, 11, 565},\n\tdictWord{13, 11, 449},\n\tdictWord{14, 11, 53},\n\tdictWord{\n\t\t15,\n\t\t11,\n\t\t13,\n\t},\n\tdictWord{16, 11, 64},\n\tdictWord{145, 11, 41},\n\tdictWord{6, 0, 884},\n\tdictWord{6, 0, 1019},\n\tdictWord{134, 0, 1150},\n\tdictWord{6, 11, 1767},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t194,\n\t},\n\tdictWord{145, 11, 107},\n\tdictWord{136, 10, 503},\n\tdictWord{133, 11, 840},\n\tdictWord{7, 0, 671},\n\tdictWord{134, 10, 466},\n\tdictWord{132, 0, 888},\n\tdictWord{4, 0, 149},\n\tdictWord{138, 0, 368},\n\tdictWord{4, 0, 154},\n\tdictWord{7, 0, 1134},\n\tdictWord{136, 0, 105},\n\tdictWord{135, 0, 983},\n\tdictWord{9, 11, 642},\n\tdictWord{11, 11, 236},\n\tdictWord{142, 11, 193},\n\tdictWord{4, 0, 31},\n\tdictWord{6, 0, 429},\n\tdictWord{7, 0, 962},\n\tdictWord{9, 0, 458},\n\tdictWord{139, 0, 691},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t643,\n\t},\n\tdictWord{134, 0, 1102},\n\tdictWord{132, 0, 312},\n\tdictWord{4, 11, 68},\n\tdictWord{5, 11, 634},\n\tdictWord{6, 11, 386},\n\tdictWord{7, 11, 794},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t273,\n\t},\n\tdictWord{9, 11, 563},\n\tdictWord{10, 11, 105},\n\tdictWord{10, 11, 171},\n\tdictWord{11, 11, 94},\n\tdictWord{139, 11, 354},\n\tdictWord{133, 0, 740},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1642,\n\t},\n\tdictWord{4, 11, 95},\n\tdictWord{7, 11, 416},\n\tdictWord{8, 11, 211},\n\tdictWord{139, 11, 830},\n\tdictWord{132, 0, 236},\n\tdictWord{138, 10, 241},\n\tdictWord{7, 11, 731},\n\tdictWord{13, 11, 20},\n\tdictWord{143, 11, 11},\n\tdictWord{5, 0, 836},\n\tdictWord{5, 0, 857},\n\tdictWord{6, 0, 1680},\n\tdictWord{135, 0, 59},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t68,\n\t},\n\tdictWord{11, 0, 494},\n\tdictWord{152, 11, 6},\n\tdictWord{4, 0, 81},\n\tdictWord{139, 0, 867},\n\tdictWord{135, 0, 795},\n\tdictWord{133, 11, 689},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t1001,\n\t},\n\tdictWord{5, 0, 282},\n\tdictWord{6, 0, 1932},\n\tdictWord{6, 0, 1977},\n\tdictWord{6, 0, 1987},\n\tdictWord{6, 0, 1992},\n\tdictWord{8, 0, 650},\n\tdictWord{8, 0, 919},\n\tdictWord{8, 0, 920},\n\tdictWord{8, 0, 923},\n\tdictWord{8, 0, 926},\n\tdictWord{8, 0, 927},\n\tdictWord{8, 0, 931},\n\tdictWord{8, 0, 939},\n\tdictWord{8, 0, 947},\n\tdictWord{8, 0, 956},\n\tdictWord{8, 0, 997},\n\tdictWord{9, 0, 907},\n\tdictWord{10, 0, 950},\n\tdictWord{10, 0, 953},\n\tdictWord{10, 0, 954},\n\tdictWord{10, 0, 956},\n\tdictWord{10, 0, 958},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t959,\n\t},\n\tdictWord{10, 0, 964},\n\tdictWord{10, 0, 970},\n\tdictWord{10, 0, 972},\n\tdictWord{10, 0, 973},\n\tdictWord{10, 0, 975},\n\tdictWord{10, 0, 976},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t980,\n\t},\n\tdictWord{10, 0, 981},\n\tdictWord{10, 0, 984},\n\tdictWord{10, 0, 988},\n\tdictWord{10, 0, 990},\n\tdictWord{10, 0, 995},\n\tdictWord{10, 0, 999},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t1002,\n\t},\n\tdictWord{10, 0, 1003},\n\tdictWord{10, 0, 1005},\n\tdictWord{10, 0, 1006},\n\tdictWord{10, 0, 1008},\n\tdictWord{10, 0, 1009},\n\tdictWord{10, 0, 1012},\n\tdictWord{10, 0, 1014},\n\tdictWord{10, 0, 1015},\n\tdictWord{10, 0, 1019},\n\tdictWord{10, 0, 1020},\n\tdictWord{10, 0, 1022},\n\tdictWord{12, 0, 959},\n\tdictWord{12, 0, 961},\n\tdictWord{12, 0, 962},\n\tdictWord{12, 0, 963},\n\tdictWord{12, 0, 964},\n\tdictWord{12, 0, 965},\n\tdictWord{12, 0, 967},\n\tdictWord{12, 0, 968},\n\tdictWord{12, 0, 969},\n\tdictWord{12, 0, 970},\n\tdictWord{12, 0, 971},\n\tdictWord{12, 0, 972},\n\tdictWord{12, 0, 973},\n\tdictWord{12, 0, 974},\n\tdictWord{12, 0, 975},\n\tdictWord{12, 0, 976},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t977,\n\t},\n\tdictWord{12, 0, 979},\n\tdictWord{12, 0, 981},\n\tdictWord{12, 0, 982},\n\tdictWord{12, 0, 983},\n\tdictWord{12, 0, 984},\n\tdictWord{12, 0, 985},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t986,\n\t},\n\tdictWord{12, 0, 987},\n\tdictWord{12, 0, 989},\n\tdictWord{12, 0, 990},\n\tdictWord{12, 0, 992},\n\tdictWord{12, 0, 993},\n\tdictWord{12, 0, 995},\n\tdictWord{12, 0, 998},\n\tdictWord{12, 0, 999},\n\tdictWord{12, 0, 1000},\n\tdictWord{12, 0, 1001},\n\tdictWord{12, 0, 1002},\n\tdictWord{12, 0, 1004},\n\tdictWord{12, 0, 1005},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t1006,\n\t},\n\tdictWord{12, 0, 1007},\n\tdictWord{12, 0, 1008},\n\tdictWord{12, 0, 1009},\n\tdictWord{12, 0, 1010},\n\tdictWord{12, 0, 1011},\n\tdictWord{12, 0, 1012},\n\tdictWord{12, 0, 1014},\n\tdictWord{12, 0, 1015},\n\tdictWord{12, 0, 1016},\n\tdictWord{12, 0, 1017},\n\tdictWord{12, 0, 1018},\n\tdictWord{12, 0, 1019},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t1022,\n\t},\n\tdictWord{12, 0, 1023},\n\tdictWord{14, 0, 475},\n\tdictWord{14, 0, 477},\n\tdictWord{14, 0, 478},\n\tdictWord{14, 0, 479},\n\tdictWord{14, 0, 480},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t482,\n\t},\n\tdictWord{14, 0, 483},\n\tdictWord{14, 0, 484},\n\tdictWord{14, 0, 485},\n\tdictWord{14, 0, 486},\n\tdictWord{14, 0, 487},\n\tdictWord{14, 0, 488},\n\tdictWord{14, 0, 489},\n\tdictWord{14, 0, 490},\n\tdictWord{14, 0, 491},\n\tdictWord{14, 0, 492},\n\tdictWord{14, 0, 493},\n\tdictWord{14, 0, 494},\n\tdictWord{14, 0, 495},\n\tdictWord{14, 0, 496},\n\tdictWord{14, 0, 497},\n\tdictWord{14, 0, 498},\n\tdictWord{14, 0, 499},\n\tdictWord{14, 0, 500},\n\tdictWord{14, 0, 501},\n\tdictWord{14, 0, 502},\n\tdictWord{14, 0, 503},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t504,\n\t},\n\tdictWord{14, 0, 506},\n\tdictWord{14, 0, 507},\n\tdictWord{14, 0, 508},\n\tdictWord{14, 0, 509},\n\tdictWord{14, 0, 510},\n\tdictWord{14, 0, 511},\n\tdictWord{\n\t\t16,\n\t\t0,\n\t\t113,\n\t},\n\tdictWord{16, 0, 114},\n\tdictWord{16, 0, 115},\n\tdictWord{16, 0, 117},\n\tdictWord{16, 0, 118},\n\tdictWord{16, 0, 119},\n\tdictWord{16, 0, 121},\n\tdictWord{16, 0, 122},\n\tdictWord{16, 0, 123},\n\tdictWord{16, 0, 124},\n\tdictWord{16, 0, 125},\n\tdictWord{16, 0, 126},\n\tdictWord{16, 0, 127},\n\tdictWord{18, 0, 242},\n\tdictWord{18, 0, 243},\n\tdictWord{18, 0, 244},\n\tdictWord{18, 0, 245},\n\tdictWord{18, 0, 248},\n\tdictWord{18, 0, 249},\n\tdictWord{18, 0, 250},\n\tdictWord{18, 0, 251},\n\tdictWord{18, 0, 252},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t253,\n\t},\n\tdictWord{18, 0, 254},\n\tdictWord{18, 0, 255},\n\tdictWord{20, 0, 125},\n\tdictWord{20, 0, 126},\n\tdictWord{148, 0, 127},\n\tdictWord{7, 11, 1717},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1769,\n\t},\n\tdictWord{138, 11, 546},\n\tdictWord{7, 11, 1127},\n\tdictWord{7, 11, 1572},\n\tdictWord{10, 11, 297},\n\tdictWord{10, 11, 422},\n\tdictWord{11, 11, 764},\n\tdictWord{11, 11, 810},\n\tdictWord{12, 11, 264},\n\tdictWord{13, 11, 102},\n\tdictWord{13, 11, 300},\n\tdictWord{13, 11, 484},\n\tdictWord{14, 11, 147},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t229,\n\t},\n\tdictWord{17, 11, 71},\n\tdictWord{18, 11, 118},\n\tdictWord{147, 11, 120},\n\tdictWord{6, 0, 1148},\n\tdictWord{134, 0, 1586},\n\tdictWord{132, 0, 775},\n\tdictWord{135, 10, 954},\n\tdictWord{133, 11, 864},\n\tdictWord{133, 11, 928},\n\tdictWord{138, 11, 189},\n\tdictWord{135, 10, 1958},\n\tdictWord{6, 10, 549},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t34,\n\t},\n\tdictWord{8, 10, 283},\n\tdictWord{9, 10, 165},\n\tdictWord{138, 10, 475},\n\tdictWord{5, 10, 652},\n\tdictWord{5, 10, 701},\n\tdictWord{135, 10, 449},\n\tdictWord{135, 11, 695},\n\tdictWord{4, 10, 655},\n\tdictWord{7, 10, 850},\n\tdictWord{17, 10, 75},\n\tdictWord{146, 10, 137},\n\tdictWord{140, 11, 682},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t523,\n\t},\n\tdictWord{8, 0, 970},\n\tdictWord{136, 10, 670},\n\tdictWord{136, 11, 555},\n\tdictWord{7, 11, 76},\n\tdictWord{8, 11, 44},\n\tdictWord{9, 11, 884},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t580,\n\t},\n\tdictWord{11, 11, 399},\n\tdictWord{11, 11, 894},\n\tdictWord{15, 11, 122},\n\tdictWord{18, 11, 144},\n\tdictWord{147, 11, 61},\n\tdictWord{6, 10, 159},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t364,\n\t},\n\tdictWord{7, 10, 516},\n\tdictWord{7, 10, 1439},\n\tdictWord{137, 10, 518},\n\tdictWord{4, 0, 71},\n\tdictWord{5, 0, 376},\n\tdictWord{7, 0, 119},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t665,\n\t},\n\tdictWord{141, 10, 151},\n\tdictWord{11, 0, 827},\n\tdictWord{14, 0, 34},\n\tdictWord{143, 0, 148},\n\tdictWord{133, 11, 518},\n\tdictWord{4, 0, 479},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1787,\n\t},\n\tdictWord{135, 11, 1852},\n\tdictWord{135, 10, 993},\n\tdictWord{7, 0, 607},\n\tdictWord{136, 0, 99},\n\tdictWord{134, 0, 1960},\n\tdictWord{132, 0, 793},\n\tdictWord{4, 0, 41},\n\tdictWord{5, 0, 74},\n\tdictWord{7, 0, 1627},\n\tdictWord{11, 0, 871},\n\tdictWord{140, 0, 619},\n\tdictWord{7, 0, 94},\n\tdictWord{11, 0, 329},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t965,\n\t},\n\tdictWord{12, 0, 241},\n\tdictWord{14, 0, 354},\n\tdictWord{15, 0, 22},\n\tdictWord{148, 0, 63},\n\tdictWord{7, 10, 501},\n\tdictWord{9, 10, 111},\n\tdictWord{10, 10, 141},\n\tdictWord{11, 10, 332},\n\tdictWord{13, 10, 43},\n\tdictWord{13, 10, 429},\n\tdictWord{14, 10, 130},\n\tdictWord{14, 10, 415},\n\tdictWord{145, 10, 102},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t209,\n\t},\n\tdictWord{137, 0, 300},\n\tdictWord{134, 0, 1497},\n\tdictWord{138, 11, 255},\n\tdictWord{4, 11, 934},\n\tdictWord{5, 11, 138},\n\tdictWord{136, 11, 610},\n\tdictWord{133, 0, 98},\n\tdictWord{6, 0, 1316},\n\tdictWord{10, 11, 804},\n\tdictWord{138, 11, 832},\n\tdictWord{8, 11, 96},\n\tdictWord{9, 11, 36},\n\tdictWord{10, 11, 607},\n\tdictWord{11, 11, 423},\n\tdictWord{11, 11, 442},\n\tdictWord{12, 11, 309},\n\tdictWord{14, 11, 199},\n\tdictWord{15, 11, 90},\n\tdictWord{145, 11, 110},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t463,\n\t},\n\tdictWord{5, 10, 149},\n\tdictWord{136, 10, 233},\n\tdictWord{133, 10, 935},\n\tdictWord{4, 11, 652},\n\tdictWord{8, 11, 320},\n\tdictWord{9, 11, 13},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t398,\n\t},\n\tdictWord{9, 11, 727},\n\tdictWord{10, 11, 75},\n\tdictWord{10, 11, 184},\n\tdictWord{10, 11, 230},\n\tdictWord{10, 11, 564},\n\tdictWord{10, 11, 569},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t973,\n\t},\n\tdictWord{12, 11, 70},\n\tdictWord{12, 11, 189},\n\tdictWord{13, 11, 57},\n\tdictWord{13, 11, 257},\n\tdictWord{22, 11, 6},\n\tdictWord{150, 11, 16},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t291,\n\t},\n\tdictWord{12, 10, 582},\n\tdictWord{146, 10, 131},\n\tdictWord{136, 10, 801},\n\tdictWord{133, 0, 984},\n\tdictWord{145, 11, 116},\n\tdictWord{4, 11, 692},\n\tdictWord{133, 11, 321},\n\tdictWord{4, 0, 182},\n\tdictWord{6, 0, 205},\n\tdictWord{135, 0, 220},\n\tdictWord{4, 0, 42},\n\tdictWord{9, 0, 205},\n\tdictWord{9, 0, 786},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t659,\n\t},\n\tdictWord{6, 0, 801},\n\tdictWord{11, 11, 130},\n\tdictWord{140, 11, 609},\n\tdictWord{132, 0, 635},\n\tdictWord{5, 11, 345},\n\tdictWord{135, 11, 1016},\n\tdictWord{139, 0, 533},\n\tdictWord{132, 0, 371},\n\tdictWord{4, 0, 272},\n\tdictWord{135, 0, 836},\n\tdictWord{6, 0, 1282},\n\tdictWord{135, 11, 1100},\n\tdictWord{5, 0, 825},\n\tdictWord{134, 0, 1640},\n\tdictWord{135, 11, 1325},\n\tdictWord{133, 11, 673},\n\tdictWord{4, 11, 287},\n\tdictWord{133, 11, 1018},\n\tdictWord{135, 0, 357},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t467,\n\t},\n\tdictWord{137, 0, 879},\n\tdictWord{7, 0, 317},\n\tdictWord{135, 0, 569},\n\tdictWord{6, 0, 924},\n\tdictWord{134, 0, 1588},\n\tdictWord{5, 11, 34},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t406,\n\t},\n\tdictWord{10, 11, 724},\n\tdictWord{12, 11, 444},\n\tdictWord{13, 11, 354},\n\tdictWord{18, 11, 32},\n\tdictWord{23, 11, 24},\n\tdictWord{23, 11, 31},\n\tdictWord{\n\t\t152,\n\t\t11,\n\t\t5,\n\t},\n\tdictWord{6, 0, 1795},\n\tdictWord{6, 0, 1835},\n\tdictWord{6, 0, 1836},\n\tdictWord{6, 0, 1856},\n\tdictWord{8, 0, 844},\n\tdictWord{8, 0, 849},\n\tdictWord{8, 0, 854},\n\tdictWord{8, 0, 870},\n\tdictWord{8, 0, 887},\n\tdictWord{10, 0, 852},\n\tdictWord{138, 0, 942},\n\tdictWord{6, 10, 69},\n\tdictWord{135, 10, 117},\n\tdictWord{137, 0, 307},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t944,\n\t},\n\tdictWord{6, 0, 1799},\n\tdictWord{6, 0, 1825},\n\tdictWord{10, 0, 848},\n\tdictWord{10, 0, 875},\n\tdictWord{10, 0, 895},\n\tdictWord{10, 0, 899},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t902,\n\t},\n\tdictWord{140, 0, 773},\n\tdictWord{11, 0, 43},\n\tdictWord{13, 0, 72},\n\tdictWord{141, 0, 142},\n\tdictWord{135, 10, 1830},\n\tdictWord{134, 11, 382},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t432,\n\t},\n\tdictWord{135, 10, 824},\n\tdictWord{132, 11, 329},\n\tdictWord{7, 0, 1820},\n\tdictWord{139, 11, 124},\n\tdictWord{133, 10, 826},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t525,\n\t},\n\tdictWord{132, 11, 906},\n\tdictWord{7, 11, 1940},\n\tdictWord{136, 11, 366},\n\tdictWord{138, 11, 10},\n\tdictWord{4, 11, 123},\n\tdictWord{4, 11, 649},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t605,\n\t},\n\tdictWord{7, 11, 1509},\n\tdictWord{136, 11, 36},\n\tdictWord{6, 0, 110},\n\tdictWord{135, 0, 1681},\n\tdictWord{133, 0, 493},\n\tdictWord{133, 11, 767},\n\tdictWord{4, 0, 174},\n\tdictWord{135, 0, 911},\n\tdictWord{138, 11, 786},\n\tdictWord{8, 0, 417},\n\tdictWord{137, 0, 782},\n\tdictWord{133, 10, 1000},\n\tdictWord{7, 0, 733},\n\tdictWord{137, 0, 583},\n\tdictWord{4, 10, 297},\n\tdictWord{6, 10, 529},\n\tdictWord{7, 10, 152},\n\tdictWord{7, 10, 713},\n\tdictWord{7, 10, 1845},\n\tdictWord{8, 10, 710},\n\tdictWord{8, 10, 717},\n\tdictWord{12, 10, 639},\n\tdictWord{140, 10, 685},\n\tdictWord{4, 0, 32},\n\tdictWord{5, 0, 215},\n\tdictWord{6, 0, 269},\n\tdictWord{7, 0, 1782},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1892,\n\t},\n\tdictWord{10, 0, 16},\n\tdictWord{11, 0, 822},\n\tdictWord{11, 0, 954},\n\tdictWord{141, 0, 481},\n\tdictWord{4, 11, 273},\n\tdictWord{5, 11, 658},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t995,\n\t},\n\tdictWord{136, 0, 477},\n\tdictWord{134, 11, 72},\n\tdictWord{135, 11, 1345},\n\tdictWord{5, 0, 308},\n\tdictWord{7, 0, 1088},\n\tdictWord{4, 10, 520},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t575,\n\t},\n\tdictWord{133, 11, 589},\n\tdictWord{5, 0, 126},\n\tdictWord{8, 0, 297},\n\tdictWord{9, 0, 366},\n\tdictWord{140, 0, 374},\n\tdictWord{7, 0, 1551},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t361,\n\t},\n\tdictWord{5, 11, 117},\n\tdictWord{6, 11, 514},\n\tdictWord{6, 11, 541},\n\tdictWord{7, 11, 1164},\n\tdictWord{7, 11, 1436},\n\tdictWord{8, 11, 220},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t648,\n\t},\n\tdictWord{10, 11, 688},\n\tdictWord{139, 11, 560},\n\tdictWord{133, 11, 686},\n\tdictWord{4, 0, 946},\n\tdictWord{6, 0, 1807},\n\tdictWord{8, 0, 871},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t854,\n\t},\n\tdictWord{10, 0, 870},\n\tdictWord{10, 0, 888},\n\tdictWord{10, 0, 897},\n\tdictWord{10, 0, 920},\n\tdictWord{12, 0, 722},\n\tdictWord{12, 0, 761},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t763,\n\t},\n\tdictWord{12, 0, 764},\n\tdictWord{14, 0, 454},\n\tdictWord{14, 0, 465},\n\tdictWord{16, 0, 107},\n\tdictWord{18, 0, 167},\n\tdictWord{18, 0, 168},\n\tdictWord{\n\t\t146,\n\t\t0,\n\t\t172,\n\t},\n\tdictWord{132, 0, 175},\n\tdictWord{135, 0, 1307},\n\tdictWord{132, 0, 685},\n\tdictWord{135, 11, 1834},\n\tdictWord{133, 0, 797},\n\tdictWord{6, 0, 745},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t858,\n\t},\n\tdictWord{134, 0, 963},\n\tdictWord{133, 0, 565},\n\tdictWord{5, 10, 397},\n\tdictWord{6, 10, 154},\n\tdictWord{7, 11, 196},\n\tdictWord{7, 10, 676},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t443,\n\t},\n\tdictWord{8, 10, 609},\n\tdictWord{9, 10, 24},\n\tdictWord{9, 10, 325},\n\tdictWord{10, 10, 35},\n\tdictWord{10, 11, 765},\n\tdictWord{11, 11, 347},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t535,\n\t},\n\tdictWord{11, 11, 552},\n\tdictWord{11, 11, 576},\n\tdictWord{11, 10, 672},\n\tdictWord{11, 11, 790},\n\tdictWord{11, 10, 1018},\n\tdictWord{12, 11, 263},\n\tdictWord{12, 10, 637},\n\tdictWord{13, 11, 246},\n\tdictWord{13, 11, 270},\n\tdictWord{13, 11, 395},\n\tdictWord{14, 11, 74},\n\tdictWord{14, 11, 176},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t190,\n\t},\n\tdictWord{14, 11, 398},\n\tdictWord{14, 11, 412},\n\tdictWord{15, 11, 32},\n\tdictWord{15, 11, 63},\n\tdictWord{16, 10, 30},\n\tdictWord{16, 11, 88},\n\tdictWord{\n\t\t147,\n\t\t11,\n\t\t105,\n\t},\n\tdictWord{13, 11, 84},\n\tdictWord{141, 11, 122},\n\tdictWord{4, 0, 252},\n\tdictWord{7, 0, 1068},\n\tdictWord{10, 0, 434},\n\tdictWord{11, 0, 228},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t426,\n\t},\n\tdictWord{13, 0, 231},\n\tdictWord{18, 0, 106},\n\tdictWord{148, 0, 87},\n\tdictWord{137, 0, 826},\n\tdictWord{4, 11, 589},\n\tdictWord{139, 11, 282},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t381,\n\t},\n\tdictWord{135, 11, 1792},\n\tdictWord{132, 0, 791},\n\tdictWord{5, 0, 231},\n\tdictWord{10, 0, 509},\n\tdictWord{133, 10, 981},\n\tdictWord{7, 0, 601},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t277,\n\t},\n\tdictWord{9, 0, 674},\n\tdictWord{10, 0, 178},\n\tdictWord{10, 0, 418},\n\tdictWord{10, 0, 571},\n\tdictWord{11, 0, 531},\n\tdictWord{12, 0, 113},\n\tdictWord{12, 0, 475},\n\tdictWord{13, 0, 99},\n\tdictWord{142, 0, 428},\n\tdictWord{4, 10, 56},\n\tdictWord{7, 11, 616},\n\tdictWord{7, 10, 1791},\n\tdictWord{8, 10, 607},\n\tdictWord{8, 10, 651},\n\tdictWord{10, 11, 413},\n\tdictWord{11, 10, 465},\n\tdictWord{11, 10, 835},\n\tdictWord{12, 10, 337},\n\tdictWord{141, 10, 480},\n\tdictWord{7, 0, 1591},\n\tdictWord{144, 0, 43},\n\tdictWord{9, 10, 158},\n\tdictWord{138, 10, 411},\n\tdictWord{135, 0, 1683},\n\tdictWord{8, 0, 289},\n\tdictWord{11, 0, 45},\n\tdictWord{12, 0, 278},\n\tdictWord{140, 0, 537},\n\tdictWord{6, 11, 120},\n\tdictWord{7, 11, 1188},\n\tdictWord{7, 11, 1710},\n\tdictWord{8, 11, 286},\n\tdictWord{9, 11, 667},\n\tdictWord{11, 11, 592},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t730,\n\t},\n\tdictWord{136, 10, 617},\n\tdictWord{135, 0, 1120},\n\tdictWord{135, 11, 1146},\n\tdictWord{139, 10, 563},\n\tdictWord{4, 11, 352},\n\tdictWord{4, 10, 369},\n\tdictWord{135, 11, 687},\n\tdictWord{143, 11, 38},\n\tdictWord{4, 0, 399},\n\tdictWord{5, 0, 119},\n\tdictWord{5, 0, 494},\n\tdictWord{7, 0, 751},\n\tdictWord{9, 0, 556},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t179,\n\t},\n\tdictWord{15, 11, 151},\n\tdictWord{150, 11, 11},\n\tdictWord{4, 11, 192},\n\tdictWord{5, 11, 49},\n\tdictWord{6, 11, 200},\n\tdictWord{6, 11, 293},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t1696,\n\t},\n\tdictWord{135, 11, 488},\n\tdictWord{4, 0, 398},\n\tdictWord{133, 0, 660},\n\tdictWord{7, 0, 1030},\n\tdictWord{134, 10, 622},\n\tdictWord{135, 11, 595},\n\tdictWord{141, 0, 168},\n\tdictWord{132, 11, 147},\n\tdictWord{7, 0, 973},\n\tdictWord{10, 10, 624},\n\tdictWord{142, 10, 279},\n\tdictWord{132, 10, 363},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t642,\n\t},\n\tdictWord{133, 11, 934},\n\tdictWord{134, 0, 1615},\n\tdictWord{7, 11, 505},\n\tdictWord{135, 11, 523},\n\tdictWord{7, 0, 594},\n\tdictWord{7, 0, 851},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1858,\n\t},\n\tdictWord{9, 0, 411},\n\tdictWord{9, 0, 574},\n\tdictWord{9, 0, 666},\n\tdictWord{9, 0, 737},\n\tdictWord{10, 0, 346},\n\tdictWord{10, 0, 712},\n\tdictWord{11, 0, 246},\n\tdictWord{11, 0, 432},\n\tdictWord{11, 0, 517},\n\tdictWord{11, 0, 647},\n\tdictWord{11, 0, 679},\n\tdictWord{11, 0, 727},\n\tdictWord{12, 0, 304},\n\tdictWord{12, 0, 305},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t323,\n\t},\n\tdictWord{12, 0, 483},\n\tdictWord{12, 0, 572},\n\tdictWord{12, 0, 593},\n\tdictWord{12, 0, 602},\n\tdictWord{13, 0, 95},\n\tdictWord{13, 0, 101},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t171,\n\t},\n\tdictWord{13, 0, 315},\n\tdictWord{13, 0, 378},\n\tdictWord{13, 0, 425},\n\tdictWord{13, 0, 475},\n\tdictWord{14, 0, 63},\n\tdictWord{14, 0, 380},\n\tdictWord{14, 0, 384},\n\tdictWord{15, 0, 133},\n\tdictWord{18, 0, 112},\n\tdictWord{148, 0, 72},\n\tdictWord{135, 0, 1093},\n\tdictWord{132, 0, 679},\n\tdictWord{8, 0, 913},\n\tdictWord{10, 0, 903},\n\tdictWord{10, 0, 915},\n\tdictWord{12, 0, 648},\n\tdictWord{12, 0, 649},\n\tdictWord{14, 0, 455},\n\tdictWord{16, 0, 112},\n\tdictWord{138, 11, 438},\n\tdictWord{137, 0, 203},\n\tdictWord{134, 10, 292},\n\tdictWord{134, 0, 1492},\n\tdictWord{7, 0, 1374},\n\tdictWord{8, 0, 540},\n\tdictWord{5, 10, 177},\n\tdictWord{6, 10, 616},\n\tdictWord{7, 10, 827},\n\tdictWord{9, 10, 525},\n\tdictWord{138, 10, 656},\n\tdictWord{135, 0, 1486},\n\tdictWord{9, 0, 714},\n\tdictWord{138, 10, 31},\n\tdictWord{136, 0, 825},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1511,\n\t},\n\tdictWord{132, 11, 637},\n\tdictWord{134, 0, 952},\n\tdictWord{4, 10, 161},\n\tdictWord{133, 10, 631},\n\tdictWord{5, 0, 143},\n\tdictWord{5, 0, 769},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1760,\n\t},\n\tdictWord{7, 0, 682},\n\tdictWord{7, 0, 1992},\n\tdictWord{136, 0, 736},\n\tdictWord{132, 0, 700},\n\tdictWord{134, 0, 1540},\n\tdictWord{132, 11, 777},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t867,\n\t},\n\tdictWord{138, 11, 837},\n\tdictWord{7, 0, 1557},\n\tdictWord{135, 10, 1684},\n\tdictWord{133, 0, 860},\n\tdictWord{6, 0, 422},\n\tdictWord{7, 0, 0},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1544,\n\t},\n\tdictWord{9, 0, 605},\n\tdictWord{11, 0, 990},\n\tdictWord{12, 0, 235},\n\tdictWord{12, 0, 453},\n\tdictWord{13, 0, 47},\n\tdictWord{13, 0, 266},\n\tdictWord{9, 10, 469},\n\tdictWord{9, 10, 709},\n\tdictWord{12, 10, 512},\n\tdictWord{14, 10, 65},\n\tdictWord{145, 10, 12},\n\tdictWord{11, 0, 807},\n\tdictWord{10, 10, 229},\n\tdictWord{11, 10, 73},\n\tdictWord{139, 10, 376},\n\tdictWord{6, 11, 170},\n\tdictWord{7, 11, 1080},\n\tdictWord{8, 11, 395},\n\tdictWord{8, 11, 487},\n\tdictWord{11, 11, 125},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t147,\n\t},\n\tdictWord{5, 0, 515},\n\tdictWord{137, 0, 131},\n\tdictWord{7, 0, 1605},\n\tdictWord{11, 0, 962},\n\tdictWord{146, 0, 139},\n\tdictWord{132, 0, 646},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t396,\n\t},\n\tdictWord{7, 0, 728},\n\tdictWord{9, 0, 117},\n\tdictWord{13, 0, 202},\n\tdictWord{148, 0, 51},\n\tdictWord{6, 0, 121},\n\tdictWord{6, 0, 124},\n\tdictWord{6, 0, 357},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1138,\n\t},\n\tdictWord{7, 0, 1295},\n\tdictWord{8, 0, 162},\n\tdictWord{8, 0, 508},\n\tdictWord{11, 0, 655},\n\tdictWord{4, 11, 535},\n\tdictWord{6, 10, 558},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t651,\n\t},\n\tdictWord{8, 11, 618},\n\tdictWord{9, 10, 0},\n\tdictWord{10, 10, 34},\n\tdictWord{139, 10, 1008},\n\tdictWord{135, 11, 1245},\n\tdictWord{138, 0, 357},\n\tdictWord{\n\t\t150,\n\t\t11,\n\t\t23,\n\t},\n\tdictWord{133, 0, 237},\n\tdictWord{135, 0, 1784},\n\tdictWord{7, 10, 1832},\n\tdictWord{138, 10, 374},\n\tdictWord{132, 0, 713},\n\tdictWord{132, 11, 46},\n\tdictWord{6, 0, 1536},\n\tdictWord{10, 0, 348},\n\tdictWord{5, 11, 811},\n\tdictWord{6, 11, 1679},\n\tdictWord{6, 11, 1714},\n\tdictWord{135, 11, 2032},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t182,\n\t},\n\tdictWord{142, 11, 195},\n\tdictWord{6, 0, 523},\n\tdictWord{7, 0, 738},\n\tdictWord{7, 10, 771},\n\tdictWord{7, 10, 1731},\n\tdictWord{9, 10, 405},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t421,\n\t},\n\tdictWord{7, 11, 1458},\n\tdictWord{9, 11, 407},\n\tdictWord{139, 11, 15},\n\tdictWord{6, 11, 34},\n\tdictWord{7, 11, 69},\n\tdictWord{7, 11, 640},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1089,\n\t},\n\tdictWord{8, 11, 708},\n\tdictWord{8, 11, 721},\n\tdictWord{9, 11, 363},\n\tdictWord{9, 11, 643},\n\tdictWord{10, 11, 628},\n\tdictWord{148, 11, 98},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t434,\n\t},\n\tdictWord{135, 0, 1877},\n\tdictWord{7, 0, 571},\n\tdictWord{138, 0, 366},\n\tdictWord{5, 10, 881},\n\tdictWord{133, 10, 885},\n\tdictWord{9, 0, 513},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t25,\n\t},\n\tdictWord{10, 0, 39},\n\tdictWord{12, 0, 122},\n\tdictWord{140, 0, 187},\n\tdictWord{132, 0, 580},\n\tdictWord{5, 10, 142},\n\tdictWord{134, 10, 546},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t462,\n\t},\n\tdictWord{137, 0, 873},\n\tdictWord{5, 10, 466},\n\tdictWord{11, 10, 571},\n\tdictWord{12, 10, 198},\n\tdictWord{13, 10, 283},\n\tdictWord{14, 10, 186},\n\tdictWord{15, 10, 21},\n\tdictWord{143, 10, 103},\n\tdictWord{7, 0, 171},\n\tdictWord{4, 10, 185},\n\tdictWord{5, 10, 257},\n\tdictWord{5, 10, 839},\n\tdictWord{5, 10, 936},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t399,\n\t},\n\tdictWord{10, 10, 258},\n\tdictWord{10, 10, 395},\n\tdictWord{10, 10, 734},\n\tdictWord{11, 10, 1014},\n\tdictWord{12, 10, 23},\n\tdictWord{13, 10, 350},\n\tdictWord{14, 10, 150},\n\tdictWord{147, 10, 6},\n\tdictWord{134, 0, 625},\n\tdictWord{7, 0, 107},\n\tdictWord{7, 0, 838},\n\tdictWord{8, 0, 550},\n\tdictWord{138, 0, 401},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t73,\n\t},\n\tdictWord{6, 11, 23},\n\tdictWord{134, 11, 338},\n\tdictWord{4, 0, 943},\n\tdictWord{6, 0, 1850},\n\tdictWord{12, 0, 713},\n\tdictWord{142, 0, 434},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t588,\n\t},\n\tdictWord{11, 0, 864},\n\tdictWord{11, 0, 936},\n\tdictWord{11, 0, 968},\n\tdictWord{12, 0, 73},\n\tdictWord{12, 0, 343},\n\tdictWord{12, 0, 394},\n\tdictWord{13, 0, 275},\n\tdictWord{14, 0, 257},\n\tdictWord{15, 0, 160},\n\tdictWord{7, 10, 404},\n\tdictWord{7, 10, 1377},\n\tdictWord{7, 10, 1430},\n\tdictWord{7, 10, 2017},\n\tdictWord{8, 10, 149},\n\tdictWord{8, 10, 239},\n\tdictWord{8, 10, 512},\n\tdictWord{8, 10, 793},\n\tdictWord{8, 10, 818},\n\tdictWord{9, 10, 474},\n\tdictWord{9, 10, 595},\n\tdictWord{10, 10, 122},\n\tdictWord{10, 10, 565},\n\tdictWord{10, 10, 649},\n\tdictWord{10, 10, 783},\n\tdictWord{11, 10, 239},\n\tdictWord{11, 10, 295},\n\tdictWord{11, 10, 447},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t528,\n\t},\n\tdictWord{11, 10, 639},\n\tdictWord{11, 10, 800},\n\tdictWord{12, 10, 25},\n\tdictWord{12, 10, 157},\n\tdictWord{12, 10, 316},\n\tdictWord{12, 10, 390},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t391,\n\t},\n\tdictWord{12, 10, 395},\n\tdictWord{12, 10, 478},\n\tdictWord{12, 10, 503},\n\tdictWord{12, 10, 592},\n\tdictWord{12, 10, 680},\n\tdictWord{13, 10, 50},\n\tdictWord{13, 10, 53},\n\tdictWord{13, 10, 132},\n\tdictWord{13, 10, 198},\n\tdictWord{13, 10, 322},\n\tdictWord{13, 10, 415},\n\tdictWord{13, 10, 511},\n\tdictWord{14, 10, 71},\n\tdictWord{14, 10, 395},\n\tdictWord{15, 10, 71},\n\tdictWord{15, 10, 136},\n\tdictWord{17, 10, 123},\n\tdictWord{18, 10, 93},\n\tdictWord{147, 10, 58},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t768,\n\t},\n\tdictWord{11, 0, 103},\n\tdictWord{142, 0, 0},\n\tdictWord{136, 10, 712},\n\tdictWord{132, 0, 799},\n\tdictWord{132, 0, 894},\n\tdictWord{7, 11, 725},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t498,\n\t},\n\tdictWord{139, 11, 268},\n\tdictWord{135, 11, 1798},\n\tdictWord{135, 11, 773},\n\tdictWord{141, 11, 360},\n\tdictWord{4, 10, 377},\n\tdictWord{152, 10, 13},\n\tdictWord{135, 0, 1673},\n\tdictWord{132, 11, 583},\n\tdictWord{134, 0, 1052},\n\tdictWord{133, 11, 220},\n\tdictWord{140, 11, 69},\n\tdictWord{132, 11, 544},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t180,\n\t},\n\tdictWord{135, 10, 1906},\n\tdictWord{134, 0, 272},\n\tdictWord{4, 0, 441},\n\tdictWord{134, 0, 1421},\n\tdictWord{4, 0, 9},\n\tdictWord{5, 0, 128},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t368,\n\t},\n\tdictWord{11, 0, 480},\n\tdictWord{148, 0, 3},\n\tdictWord{5, 11, 176},\n\tdictWord{6, 11, 437},\n\tdictWord{6, 11, 564},\n\tdictWord{11, 11, 181},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t183,\n\t},\n\tdictWord{132, 10, 491},\n\tdictWord{7, 0, 1182},\n\tdictWord{141, 11, 67},\n\tdictWord{6, 0, 1346},\n\tdictWord{4, 10, 171},\n\tdictWord{138, 10, 234},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t586,\n\t},\n\tdictWord{7, 10, 1186},\n\tdictWord{138, 10, 631},\n\tdictWord{136, 0, 682},\n\tdictWord{134, 0, 1004},\n\tdictWord{15, 0, 24},\n\tdictWord{143, 11, 24},\n\tdictWord{134, 0, 968},\n\tdictWord{4, 0, 2},\n\tdictWord{6, 0, 742},\n\tdictWord{6, 0, 793},\n\tdictWord{7, 0, 545},\n\tdictWord{7, 0, 894},\n\tdictWord{9, 10, 931},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t334,\n\t},\n\tdictWord{148, 10, 71},\n\tdictWord{136, 11, 600},\n\tdictWord{133, 10, 765},\n\tdictWord{9, 0, 769},\n\tdictWord{140, 0, 185},\n\tdictWord{4, 11, 790},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t273,\n\t},\n\tdictWord{134, 11, 394},\n\tdictWord{7, 0, 474},\n\tdictWord{137, 0, 578},\n\tdictWord{4, 11, 135},\n\tdictWord{6, 11, 127},\n\tdictWord{7, 11, 1185},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1511,\n\t},\n\tdictWord{8, 11, 613},\n\tdictWord{11, 11, 5},\n\tdictWord{12, 11, 133},\n\tdictWord{12, 11, 495},\n\tdictWord{12, 11, 586},\n\tdictWord{14, 11, 385},\n\tdictWord{15, 11, 118},\n\tdictWord{17, 11, 20},\n\tdictWord{146, 11, 98},\n\tdictWord{133, 10, 424},\n\tdictWord{5, 0, 530},\n\tdictWord{142, 0, 113},\n\tdictWord{6, 11, 230},\n\tdictWord{7, 11, 961},\n\tdictWord{7, 11, 1085},\n\tdictWord{136, 11, 462},\n\tdictWord{7, 11, 1954},\n\tdictWord{137, 11, 636},\n\tdictWord{136, 10, 714},\n\tdictWord{\n\t\t149,\n\t\t11,\n\t\t6,\n\t},\n\tdictWord{135, 10, 685},\n\tdictWord{9, 10, 420},\n\tdictWord{10, 10, 269},\n\tdictWord{10, 10, 285},\n\tdictWord{10, 10, 576},\n\tdictWord{11, 10, 397},\n\tdictWord{13, 10, 175},\n\tdictWord{145, 10, 90},\n\tdictWord{132, 10, 429},\n\tdictWord{5, 0, 556},\n\tdictWord{5, 11, 162},\n\tdictWord{136, 11, 68},\n\tdictWord{132, 11, 654},\n\tdictWord{4, 11, 156},\n\tdictWord{7, 11, 998},\n\tdictWord{7, 11, 1045},\n\tdictWord{7, 11, 1860},\n\tdictWord{9, 11, 48},\n\tdictWord{9, 11, 692},\n\tdictWord{11, 11, 419},\n\tdictWord{139, 11, 602},\n\tdictWord{6, 0, 1317},\n\tdictWord{8, 0, 16},\n\tdictWord{9, 0, 825},\n\tdictWord{12, 0, 568},\n\tdictWord{7, 11, 1276},\n\tdictWord{8, 11, 474},\n\tdictWord{137, 11, 652},\n\tdictWord{18, 0, 97},\n\tdictWord{7, 10, 18},\n\tdictWord{7, 10, 699},\n\tdictWord{7, 10, 1966},\n\tdictWord{8, 10, 752},\n\tdictWord{9, 10, 273},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t412,\n\t},\n\tdictWord{9, 10, 703},\n\tdictWord{10, 10, 71},\n\tdictWord{10, 10, 427},\n\tdictWord{138, 10, 508},\n\tdictWord{10, 0, 703},\n\tdictWord{7, 11, 1454},\n\tdictWord{138, 11, 703},\n\tdictWord{4, 10, 53},\n\tdictWord{5, 10, 186},\n\tdictWord{135, 10, 752},\n\tdictWord{134, 0, 892},\n\tdictWord{134, 0, 1571},\n\tdictWord{8, 10, 575},\n\tdictWord{10, 10, 289},\n\tdictWord{139, 10, 319},\n\tdictWord{6, 0, 186},\n\tdictWord{137, 0, 426},\n\tdictWord{134, 0, 1101},\n\tdictWord{132, 10, 675},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t585,\n\t},\n\tdictWord{6, 0, 1870},\n\tdictWord{137, 0, 937},\n\tdictWord{152, 11, 10},\n\tdictWord{9, 11, 197},\n\tdictWord{10, 11, 300},\n\tdictWord{12, 11, 473},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t90,\n\t},\n\tdictWord{141, 11, 405},\n\tdictWord{4, 0, 93},\n\tdictWord{5, 0, 252},\n\tdictWord{6, 0, 229},\n\tdictWord{7, 0, 291},\n\tdictWord{9, 0, 550},\n\tdictWord{139, 0, 644},\n\tdictWord{137, 0, 749},\n\tdictWord{9, 0, 162},\n\tdictWord{6, 10, 209},\n\tdictWord{8, 10, 468},\n\tdictWord{9, 10, 210},\n\tdictWord{11, 10, 36},\n\tdictWord{12, 10, 28},\n\tdictWord{12, 10, 630},\n\tdictWord{13, 10, 21},\n\tdictWord{13, 10, 349},\n\tdictWord{14, 10, 7},\n\tdictWord{145, 10, 13},\n\tdictWord{132, 0, 381},\n\tdictWord{132, 11, 606},\n\tdictWord{4, 10, 342},\n\tdictWord{135, 10, 1179},\n\tdictWord{7, 11, 1587},\n\tdictWord{7, 11, 1707},\n\tdictWord{10, 11, 528},\n\tdictWord{139, 11, 504},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t39,\n\t},\n\tdictWord{13, 11, 265},\n\tdictWord{141, 11, 439},\n\tdictWord{4, 10, 928},\n\tdictWord{133, 10, 910},\n\tdictWord{7, 10, 1838},\n\tdictWord{7, 11, 1978},\n\tdictWord{136, 11, 676},\n\tdictWord{6, 0, 762},\n\tdictWord{6, 0, 796},\n\tdictWord{134, 0, 956},\n\tdictWord{4, 10, 318},\n\tdictWord{4, 10, 496},\n\tdictWord{7, 10, 856},\n\tdictWord{139, 10, 654},\n\tdictWord{137, 11, 242},\n\tdictWord{4, 11, 361},\n\tdictWord{133, 11, 315},\n\tdictWord{132, 11, 461},\n\tdictWord{132, 11, 472},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t857,\n\t},\n\tdictWord{5, 0, 21},\n\tdictWord{6, 0, 77},\n\tdictWord{6, 0, 157},\n\tdictWord{7, 0, 974},\n\tdictWord{7, 0, 1301},\n\tdictWord{7, 0, 1339},\n\tdictWord{7, 0, 1490},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1873,\n\t},\n\tdictWord{9, 0, 628},\n\tdictWord{7, 10, 915},\n\tdictWord{8, 10, 247},\n\tdictWord{147, 10, 0},\n\tdictWord{4, 10, 202},\n\tdictWord{5, 10, 382},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t454,\n\t},\n\tdictWord{7, 10, 936},\n\tdictWord{7, 10, 1803},\n\tdictWord{8, 10, 758},\n\tdictWord{9, 10, 375},\n\tdictWord{9, 10, 895},\n\tdictWord{10, 10, 743},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t792,\n\t},\n\tdictWord{11, 10, 978},\n\tdictWord{11, 10, 1012},\n\tdictWord{142, 10, 109},\n\tdictWord{7, 11, 617},\n\tdictWord{10, 11, 498},\n\tdictWord{11, 11, 501},\n\tdictWord{12, 11, 16},\n\tdictWord{140, 11, 150},\n\tdictWord{7, 10, 1150},\n\tdictWord{7, 10, 1425},\n\tdictWord{7, 10, 1453},\n\tdictWord{10, 11, 747},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t513,\n\t},\n\tdictWord{133, 11, 155},\n\tdictWord{11, 0, 919},\n\tdictWord{141, 0, 409},\n\tdictWord{138, 10, 791},\n\tdictWord{10, 0, 633},\n\tdictWord{139, 11, 729},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t163,\n\t},\n\tdictWord{8, 11, 319},\n\tdictWord{9, 11, 402},\n\tdictWord{10, 11, 24},\n\tdictWord{10, 11, 681},\n\tdictWord{11, 11, 200},\n\tdictWord{11, 11, 567},\n\tdictWord{12, 11, 253},\n\tdictWord{12, 11, 410},\n\tdictWord{142, 11, 219},\n\tdictWord{5, 11, 475},\n\tdictWord{7, 11, 1780},\n\tdictWord{9, 11, 230},\n\tdictWord{11, 11, 297},\n\tdictWord{11, 11, 558},\n\tdictWord{14, 11, 322},\n\tdictWord{147, 11, 76},\n\tdictWord{7, 0, 332},\n\tdictWord{6, 10, 445},\n\tdictWord{137, 10, 909},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1956,\n\t},\n\tdictWord{136, 11, 274},\n\tdictWord{134, 10, 578},\n\tdictWord{135, 0, 1489},\n\tdictWord{135, 11, 1848},\n\tdictWord{5, 11, 944},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t1769,\n\t},\n\tdictWord{132, 11, 144},\n\tdictWord{136, 10, 766},\n\tdictWord{4, 0, 832},\n\tdictWord{135, 10, 541},\n\tdictWord{8, 0, 398},\n\tdictWord{9, 0, 681},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t632,\n\t},\n\tdictWord{136, 0, 645},\n\tdictWord{9, 0, 791},\n\tdictWord{10, 0, 93},\n\tdictWord{16, 0, 13},\n\tdictWord{17, 0, 23},\n\tdictWord{18, 0, 135},\n\tdictWord{19, 0, 12},\n\tdictWord{20, 0, 1},\n\tdictWord{20, 0, 12},\n\tdictWord{148, 0, 14},\n\tdictWord{6, 11, 247},\n\tdictWord{137, 11, 555},\n\tdictWord{134, 0, 20},\n\tdictWord{132, 0, 800},\n\tdictWord{135, 0, 1841},\n\tdictWord{139, 10, 983},\n\tdictWord{137, 10, 768},\n\tdictWord{132, 10, 584},\n\tdictWord{141, 11, 51},\n\tdictWord{6, 0, 1993},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t620,\n\t},\n\tdictWord{138, 11, 280},\n\tdictWord{136, 0, 769},\n\tdictWord{11, 0, 290},\n\tdictWord{11, 0, 665},\n\tdictWord{7, 11, 1810},\n\tdictWord{11, 11, 866},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t103,\n\t},\n\tdictWord{13, 11, 495},\n\tdictWord{17, 11, 67},\n\tdictWord{147, 11, 74},\n\tdictWord{134, 0, 1426},\n\tdictWord{139, 0, 60},\n\tdictWord{4, 10, 326},\n\tdictWord{135, 10, 1770},\n\tdictWord{7, 0, 1874},\n\tdictWord{9, 0, 641},\n\tdictWord{132, 10, 226},\n\tdictWord{6, 0, 644},\n\tdictWord{5, 10, 426},\n\tdictWord{8, 10, 30},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t2,\n\t},\n\tdictWord{11, 10, 549},\n\tdictWord{147, 10, 122},\n\tdictWord{5, 11, 428},\n\tdictWord{138, 11, 442},\n\tdictWord{135, 11, 1871},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1757,\n\t},\n\tdictWord{147, 10, 117},\n\tdictWord{135, 0, 937},\n\tdictWord{135, 0, 1652},\n\tdictWord{6, 0, 654},\n\tdictWord{134, 0, 1476},\n\tdictWord{133, 11, 99},\n\tdictWord{135, 0, 527},\n\tdictWord{132, 10, 345},\n\tdictWord{4, 10, 385},\n\tdictWord{4, 11, 397},\n\tdictWord{7, 10, 265},\n\tdictWord{135, 10, 587},\n\tdictWord{4, 0, 579},\n\tdictWord{5, 0, 226},\n\tdictWord{5, 0, 323},\n\tdictWord{135, 0, 960},\n\tdictWord{134, 0, 1486},\n\tdictWord{8, 11, 502},\n\tdictWord{144, 11, 9},\n\tdictWord{4, 10, 347},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t423,\n\t},\n\tdictWord{5, 10, 996},\n\tdictWord{135, 10, 1329},\n\tdictWord{7, 11, 727},\n\tdictWord{146, 11, 73},\n\tdictWord{4, 11, 485},\n\tdictWord{7, 11, 353},\n\tdictWord{7, 10, 1259},\n\tdictWord{7, 11, 1523},\n\tdictWord{9, 10, 125},\n\tdictWord{139, 10, 65},\n\tdictWord{6, 0, 325},\n\tdictWord{5, 10, 136},\n\tdictWord{6, 11, 366},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1384,\n\t},\n\tdictWord{7, 11, 1601},\n\tdictWord{136, 10, 644},\n\tdictWord{138, 11, 160},\n\tdictWord{6, 0, 1345},\n\tdictWord{137, 11, 282},\n\tdictWord{18, 0, 91},\n\tdictWord{147, 0, 70},\n\tdictWord{136, 0, 404},\n\tdictWord{4, 11, 157},\n\tdictWord{133, 11, 471},\n\tdictWord{133, 0, 973},\n\tdictWord{6, 0, 135},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1176,\n\t},\n\tdictWord{8, 11, 116},\n\tdictWord{11, 11, 551},\n\tdictWord{142, 11, 159},\n\tdictWord{4, 0, 549},\n\tdictWord{4, 10, 433},\n\tdictWord{133, 10, 719},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t976,\n\t},\n\tdictWord{5, 11, 160},\n\tdictWord{7, 11, 363},\n\tdictWord{7, 11, 589},\n\tdictWord{10, 11, 170},\n\tdictWord{141, 11, 55},\n\tdictWord{144, 0, 21},\n\tdictWord{\n\t\t144,\n\t\t0,\n\t\t51,\n\t},\n\tdictWord{135, 0, 314},\n\tdictWord{135, 10, 1363},\n\tdictWord{4, 11, 108},\n\tdictWord{7, 11, 405},\n\tdictWord{10, 11, 491},\n\tdictWord{139, 11, 498},\n\tdictWord{146, 0, 4},\n\tdictWord{4, 10, 555},\n\tdictWord{8, 10, 536},\n\tdictWord{10, 10, 288},\n\tdictWord{139, 10, 1005},\n\tdictWord{135, 11, 1005},\n\tdictWord{6, 0, 281},\n\tdictWord{7, 0, 6},\n\tdictWord{8, 0, 282},\n\tdictWord{8, 0, 480},\n\tdictWord{8, 0, 499},\n\tdictWord{9, 0, 198},\n\tdictWord{10, 0, 143},\n\tdictWord{10, 0, 169},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t211,\n\t},\n\tdictWord{10, 0, 417},\n\tdictWord{10, 0, 574},\n\tdictWord{11, 0, 147},\n\tdictWord{11, 0, 395},\n\tdictWord{12, 0, 75},\n\tdictWord{12, 0, 407},\n\tdictWord{12, 0, 608},\n\tdictWord{13, 0, 500},\n\tdictWord{142, 0, 251},\n\tdictWord{6, 0, 1093},\n\tdictWord{6, 0, 1405},\n\tdictWord{9, 10, 370},\n\tdictWord{138, 10, 90},\n\tdictWord{4, 11, 926},\n\tdictWord{133, 11, 983},\n\tdictWord{135, 0, 1776},\n\tdictWord{134, 0, 1528},\n\tdictWord{132, 0, 419},\n\tdictWord{132, 11, 538},\n\tdictWord{6, 11, 294},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1267,\n\t},\n\tdictWord{136, 11, 624},\n\tdictWord{135, 11, 1772},\n\tdictWord{138, 11, 301},\n\tdictWord{4, 10, 257},\n\tdictWord{135, 10, 2031},\n\tdictWord{4, 0, 138},\n\tdictWord{7, 0, 1012},\n\tdictWord{7, 0, 1280},\n\tdictWord{9, 0, 76},\n\tdictWord{135, 10, 1768},\n\tdictWord{132, 11, 757},\n\tdictWord{5, 0, 29},\n\tdictWord{140, 0, 638},\n\tdictWord{7, 11, 655},\n\tdictWord{135, 11, 1844},\n\tdictWord{7, 0, 1418},\n\tdictWord{6, 11, 257},\n\tdictWord{135, 11, 1522},\n\tdictWord{8, 11, 469},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t47,\n\t},\n\tdictWord{142, 11, 278},\n\tdictWord{6, 10, 83},\n\tdictWord{6, 10, 1733},\n\tdictWord{135, 10, 1389},\n\tdictWord{11, 11, 204},\n\tdictWord{11, 11, 243},\n\tdictWord{140, 11, 293},\n\tdictWord{135, 11, 1875},\n\tdictWord{6, 0, 1710},\n\tdictWord{135, 0, 2038},\n\tdictWord{137, 11, 299},\n\tdictWord{4, 0, 17},\n\tdictWord{5, 0, 23},\n\tdictWord{7, 0, 995},\n\tdictWord{11, 0, 383},\n\tdictWord{11, 0, 437},\n\tdictWord{12, 0, 460},\n\tdictWord{140, 0, 532},\n\tdictWord{133, 0, 862},\n\tdictWord{137, 10, 696},\n\tdictWord{6, 0, 592},\n\tdictWord{138, 0, 946},\n\tdictWord{138, 11, 599},\n\tdictWord{7, 10, 1718},\n\tdictWord{9, 10, 95},\n\tdictWord{9, 10, 274},\n\tdictWord{10, 10, 279},\n\tdictWord{10, 10, 317},\n\tdictWord{10, 10, 420},\n\tdictWord{11, 10, 303},\n\tdictWord{11, 10, 808},\n\tdictWord{12, 10, 134},\n\tdictWord{12, 10, 367},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t149,\n\t},\n\tdictWord{13, 10, 347},\n\tdictWord{14, 10, 349},\n\tdictWord{14, 10, 406},\n\tdictWord{18, 10, 22},\n\tdictWord{18, 10, 89},\n\tdictWord{18, 10, 122},\n\tdictWord{\n\t\t147,\n\t\t10,\n\t\t47,\n\t},\n\tdictWord{8, 0, 70},\n\tdictWord{12, 0, 171},\n\tdictWord{141, 0, 272},\n\tdictWord{133, 10, 26},\n\tdictWord{132, 10, 550},\n\tdictWord{137, 0, 812},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t233,\n\t},\n\tdictWord{139, 0, 76},\n\tdictWord{134, 0, 988},\n\tdictWord{134, 0, 442},\n\tdictWord{136, 10, 822},\n\tdictWord{7, 0, 896},\n\tdictWord{4, 10, 902},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t809,\n\t},\n\tdictWord{134, 10, 122},\n\tdictWord{5, 11, 150},\n\tdictWord{7, 11, 106},\n\tdictWord{8, 11, 603},\n\tdictWord{9, 11, 593},\n\tdictWord{9, 11, 634},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t44,\n\t},\n\tdictWord{10, 11, 173},\n\tdictWord{11, 11, 462},\n\tdictWord{11, 11, 515},\n\tdictWord{13, 11, 216},\n\tdictWord{13, 11, 288},\n\tdictWord{142, 11, 400},\n\tdictWord{136, 0, 483},\n\tdictWord{135, 10, 262},\n\tdictWord{6, 0, 1709},\n\tdictWord{133, 10, 620},\n\tdictWord{4, 10, 34},\n\tdictWord{5, 10, 574},\n\tdictWord{7, 10, 279},\n\tdictWord{7, 10, 1624},\n\tdictWord{136, 10, 601},\n\tdictWord{137, 10, 170},\n\tdictWord{147, 0, 119},\n\tdictWord{12, 11, 108},\n\tdictWord{141, 11, 291},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t69,\n\t},\n\tdictWord{12, 0, 105},\n\tdictWord{12, 0, 117},\n\tdictWord{13, 0, 213},\n\tdictWord{14, 0, 13},\n\tdictWord{14, 0, 62},\n\tdictWord{14, 0, 177},\n\tdictWord{14, 0, 421},\n\tdictWord{15, 0, 19},\n\tdictWord{146, 0, 141},\n\tdictWord{137, 0, 309},\n\tdictWord{11, 11, 278},\n\tdictWord{142, 11, 73},\n\tdictWord{7, 0, 608},\n\tdictWord{7, 0, 976},\n\tdictWord{9, 0, 146},\n\tdictWord{10, 0, 206},\n\tdictWord{10, 0, 596},\n\tdictWord{13, 0, 218},\n\tdictWord{142, 0, 153},\n\tdictWord{133, 10, 332},\n\tdictWord{6, 10, 261},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t182,\n\t},\n\tdictWord{139, 10, 943},\n\tdictWord{4, 11, 493},\n\tdictWord{144, 11, 55},\n\tdictWord{134, 10, 1721},\n\tdictWord{132, 0, 768},\n\tdictWord{4, 10, 933},\n\tdictWord{133, 10, 880},\n\tdictWord{7, 11, 555},\n\tdictWord{7, 11, 1316},\n\tdictWord{7, 11, 1412},\n\tdictWord{7, 11, 1839},\n\tdictWord{9, 11, 192},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t589,\n\t},\n\tdictWord{11, 11, 241},\n\tdictWord{11, 11, 676},\n\tdictWord{11, 11, 811},\n\tdictWord{11, 11, 891},\n\tdictWord{12, 11, 140},\n\tdictWord{12, 11, 346},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t479,\n\t},\n\tdictWord{13, 11, 30},\n\tdictWord{13, 11, 49},\n\tdictWord{13, 11, 381},\n\tdictWord{14, 11, 188},\n\tdictWord{15, 11, 150},\n\tdictWord{16, 11, 76},\n\tdictWord{18, 11, 30},\n\tdictWord{148, 11, 52},\n\tdictWord{4, 0, 518},\n\tdictWord{135, 0, 1136},\n\tdictWord{6, 11, 568},\n\tdictWord{7, 11, 112},\n\tdictWord{7, 11, 1804},\n\tdictWord{8, 11, 362},\n\tdictWord{8, 11, 410},\n\tdictWord{8, 11, 830},\n\tdictWord{9, 11, 514},\n\tdictWord{11, 11, 649},\n\tdictWord{142, 11, 157},\n\tdictWord{135, 11, 673},\n\tdictWord{8, 0, 689},\n\tdictWord{137, 0, 863},\n\tdictWord{4, 0, 18},\n\tdictWord{7, 0, 145},\n\tdictWord{7, 0, 444},\n\tdictWord{7, 0, 1278},\n\tdictWord{8, 0, 49},\n\tdictWord{8, 0, 400},\n\tdictWord{9, 0, 71},\n\tdictWord{9, 0, 250},\n\tdictWord{10, 0, 459},\n\tdictWord{12, 0, 160},\n\tdictWord{16, 0, 24},\n\tdictWord{132, 11, 625},\n\tdictWord{140, 0, 1020},\n\tdictWord{4, 0, 997},\n\tdictWord{6, 0, 1946},\n\tdictWord{6, 0, 1984},\n\tdictWord{134, 0, 1998},\n\tdictWord{6, 11, 16},\n\tdictWord{6, 11, 158},\n\tdictWord{7, 11, 43},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t129,\n\t},\n\tdictWord{7, 11, 181},\n\tdictWord{8, 11, 276},\n\tdictWord{8, 11, 377},\n\tdictWord{10, 11, 523},\n\tdictWord{11, 11, 816},\n\tdictWord{12, 11, 455},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t303,\n\t},\n\tdictWord{142, 11, 135},\n\tdictWord{133, 10, 812},\n\tdictWord{134, 0, 658},\n\tdictWord{4, 11, 1},\n\tdictWord{7, 11, 1143},\n\tdictWord{7, 11, 1463},\n\tdictWord{8, 11, 61},\n\tdictWord{9, 11, 207},\n\tdictWord{9, 11, 390},\n\tdictWord{9, 11, 467},\n\tdictWord{139, 11, 836},\n\tdictWord{150, 11, 26},\n\tdictWord{140, 0, 106},\n\tdictWord{6, 0, 1827},\n\tdictWord{10, 0, 931},\n\tdictWord{18, 0, 166},\n\tdictWord{20, 0, 114},\n\tdictWord{4, 10, 137},\n\tdictWord{7, 10, 1178},\n\tdictWord{7, 11, 1319},\n\tdictWord{135, 10, 1520},\n\tdictWord{133, 0, 1010},\n\tdictWord{4, 11, 723},\n\tdictWord{5, 11, 895},\n\tdictWord{7, 11, 1031},\n\tdictWord{8, 11, 199},\n\tdictWord{8, 11, 340},\n\tdictWord{9, 11, 153},\n\tdictWord{9, 11, 215},\n\tdictWord{10, 11, 21},\n\tdictWord{10, 11, 59},\n\tdictWord{10, 11, 80},\n\tdictWord{10, 11, 224},\n\tdictWord{11, 11, 229},\n\tdictWord{11, 11, 652},\n\tdictWord{12, 11, 192},\n\tdictWord{13, 11, 146},\n\tdictWord{142, 11, 91},\n\tdictWord{132, 11, 295},\n\tdictWord{6, 11, 619},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t898,\n\t},\n\tdictWord{7, 11, 1092},\n\tdictWord{8, 11, 485},\n\tdictWord{18, 11, 28},\n\tdictWord{147, 11, 116},\n\tdictWord{137, 11, 51},\n\tdictWord{6, 10, 1661},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1975,\n\t},\n\tdictWord{7, 10, 2009},\n\tdictWord{135, 10, 2011},\n\tdictWord{5, 11, 309},\n\tdictWord{140, 11, 211},\n\tdictWord{5, 0, 87},\n\tdictWord{7, 0, 313},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1103,\n\t},\n\tdictWord{10, 0, 208},\n\tdictWord{10, 0, 582},\n\tdictWord{11, 0, 389},\n\tdictWord{11, 0, 813},\n\tdictWord{12, 0, 385},\n\tdictWord{13, 0, 286},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t124,\n\t},\n\tdictWord{146, 0, 108},\n\tdictWord{5, 11, 125},\n\tdictWord{8, 11, 77},\n\tdictWord{138, 11, 15},\n\tdictWord{132, 0, 267},\n\tdictWord{133, 0, 703},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t155,\n\t},\n\tdictWord{133, 11, 439},\n\tdictWord{11, 11, 164},\n\tdictWord{140, 11, 76},\n\tdictWord{9, 0, 496},\n\tdictWord{5, 10, 89},\n\tdictWord{7, 10, 1915},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t185,\n\t},\n\tdictWord{9, 10, 235},\n\tdictWord{10, 10, 64},\n\tdictWord{10, 10, 270},\n\tdictWord{10, 10, 403},\n\tdictWord{10, 10, 469},\n\tdictWord{10, 10, 529},\n\tdictWord{10, 10, 590},\n\tdictWord{11, 10, 140},\n\tdictWord{11, 10, 860},\n\tdictWord{13, 10, 1},\n\tdictWord{13, 10, 422},\n\tdictWord{14, 10, 341},\n\tdictWord{14, 10, 364},\n\tdictWord{17, 10, 93},\n\tdictWord{18, 10, 113},\n\tdictWord{19, 10, 97},\n\tdictWord{147, 10, 113},\n\tdictWord{133, 10, 695},\n\tdictWord{135, 0, 1121},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t6,\n\t},\n\tdictWord{6, 10, 183},\n\tdictWord{7, 10, 680},\n\tdictWord{7, 10, 978},\n\tdictWord{7, 10, 1013},\n\tdictWord{7, 10, 1055},\n\tdictWord{12, 10, 230},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t172,\n\t},\n\tdictWord{146, 10, 29},\n\tdictWord{4, 11, 8},\n\tdictWord{7, 11, 1152},\n\tdictWord{7, 11, 1153},\n\tdictWord{7, 11, 1715},\n\tdictWord{9, 11, 374},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t478,\n\t},\n\tdictWord{139, 11, 648},\n\tdictWord{135, 11, 1099},\n\tdictWord{6, 10, 29},\n\tdictWord{139, 10, 63},\n\tdictWord{4, 0, 561},\n\tdictWord{10, 0, 249},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t209,\n\t},\n\tdictWord{132, 0, 760},\n\tdictWord{7, 11, 799},\n\tdictWord{138, 11, 511},\n\tdictWord{136, 11, 87},\n\tdictWord{9, 0, 154},\n\tdictWord{140, 0, 485},\n\tdictWord{136, 0, 255},\n\tdictWord{132, 0, 323},\n\tdictWord{140, 0, 419},\n\tdictWord{132, 10, 311},\n\tdictWord{134, 10, 1740},\n\tdictWord{4, 0, 368},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t641,\n\t},\n\tdictWord{7, 10, 170},\n\tdictWord{8, 10, 90},\n\tdictWord{8, 10, 177},\n\tdictWord{8, 10, 415},\n\tdictWord{11, 10, 714},\n\tdictWord{142, 10, 281},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t69,\n\t},\n\tdictWord{5, 11, 122},\n\tdictWord{9, 11, 656},\n\tdictWord{138, 11, 464},\n\tdictWord{5, 11, 849},\n\tdictWord{134, 11, 1633},\n\tdictWord{8, 0, 522},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t328,\n\t},\n\tdictWord{11, 10, 91},\n\tdictWord{13, 10, 129},\n\tdictWord{15, 10, 101},\n\tdictWord{145, 10, 125},\n\tdictWord{7, 0, 562},\n\tdictWord{8, 0, 551},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t494,\n\t},\n\tdictWord{6, 10, 74},\n\tdictWord{7, 10, 44},\n\tdictWord{11, 11, 499},\n\tdictWord{12, 10, 17},\n\tdictWord{15, 10, 5},\n\tdictWord{148, 10, 11},\n\tdictWord{4, 10, 276},\n\tdictWord{133, 10, 296},\n\tdictWord{9, 0, 92},\n\tdictWord{147, 0, 91},\n\tdictWord{4, 10, 7},\n\tdictWord{5, 10, 90},\n\tdictWord{5, 10, 158},\n\tdictWord{6, 10, 542},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t221,\n\t},\n\tdictWord{7, 10, 1574},\n\tdictWord{9, 10, 490},\n\tdictWord{10, 10, 540},\n\tdictWord{11, 10, 443},\n\tdictWord{139, 10, 757},\n\tdictWord{6, 0, 525},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1976,\n\t},\n\tdictWord{8, 0, 806},\n\tdictWord{9, 0, 876},\n\tdictWord{140, 0, 284},\n\tdictWord{5, 11, 859},\n\tdictWord{7, 10, 588},\n\tdictWord{7, 11, 1160},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t107,\n\t},\n\tdictWord{9, 10, 175},\n\tdictWord{9, 11, 291},\n\tdictWord{9, 11, 439},\n\tdictWord{10, 10, 530},\n\tdictWord{10, 11, 663},\n\tdictWord{11, 11, 609},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t197,\n\t},\n\tdictWord{7, 11, 168},\n\tdictWord{13, 11, 196},\n\tdictWord{141, 11, 237},\n\tdictWord{139, 0, 958},\n\tdictWord{133, 0, 594},\n\tdictWord{135, 10, 580},\n\tdictWord{7, 10, 88},\n\tdictWord{136, 10, 627},\n\tdictWord{6, 0, 479},\n\tdictWord{6, 0, 562},\n\tdictWord{7, 0, 1060},\n\tdictWord{13, 0, 6},\n\tdictWord{5, 10, 872},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t57,\n\t},\n\tdictWord{7, 10, 471},\n\tdictWord{9, 10, 447},\n\tdictWord{137, 10, 454},\n\tdictWord{136, 11, 413},\n\tdictWord{145, 11, 19},\n\tdictWord{4, 11, 117},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t372,\n\t},\n\tdictWord{7, 11, 1905},\n\tdictWord{142, 11, 323},\n\tdictWord{4, 11, 722},\n\tdictWord{139, 11, 471},\n\tdictWord{17, 0, 61},\n\tdictWord{5, 10, 31},\n\tdictWord{134, 10, 614},\n\tdictWord{8, 10, 330},\n\tdictWord{140, 10, 477},\n\tdictWord{7, 10, 1200},\n\tdictWord{138, 10, 460},\n\tdictWord{6, 10, 424},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1866,\n\t},\n\tdictWord{6, 0, 1641},\n\tdictWord{136, 0, 820},\n\tdictWord{6, 0, 1556},\n\tdictWord{134, 0, 1618},\n\tdictWord{9, 11, 5},\n\tdictWord{12, 11, 216},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t294,\n\t},\n\tdictWord{12, 11, 298},\n\tdictWord{12, 11, 400},\n\tdictWord{12, 11, 518},\n\tdictWord{13, 11, 229},\n\tdictWord{143, 11, 139},\n\tdictWord{15, 11, 155},\n\tdictWord{144, 11, 79},\n\tdictWord{4, 0, 302},\n\tdictWord{135, 0, 1766},\n\tdictWord{5, 10, 13},\n\tdictWord{134, 10, 142},\n\tdictWord{6, 0, 148},\n\tdictWord{7, 0, 1313},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t116,\n\t},\n\tdictWord{8, 10, 322},\n\tdictWord{8, 10, 755},\n\tdictWord{9, 10, 548},\n\tdictWord{10, 10, 714},\n\tdictWord{11, 10, 884},\n\tdictWord{141, 10, 324},\n\tdictWord{137, 0, 676},\n\tdictWord{9, 11, 88},\n\tdictWord{139, 11, 270},\n\tdictWord{5, 11, 12},\n\tdictWord{7, 11, 375},\n\tdictWord{137, 11, 438},\n\tdictWord{134, 0, 1674},\n\tdictWord{7, 10, 1472},\n\tdictWord{135, 10, 1554},\n\tdictWord{11, 0, 178},\n\tdictWord{7, 10, 1071},\n\tdictWord{7, 10, 1541},\n\tdictWord{7, 10, 1767},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1806,\n\t},\n\tdictWord{11, 10, 162},\n\tdictWord{11, 10, 242},\n\tdictWord{12, 10, 605},\n\tdictWord{15, 10, 26},\n\tdictWord{144, 10, 44},\n\tdictWord{6, 0, 389},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t149,\n\t},\n\tdictWord{9, 0, 142},\n\tdictWord{138, 0, 94},\n\tdictWord{140, 11, 71},\n\tdictWord{145, 10, 115},\n\tdictWord{6, 0, 8},\n\tdictWord{7, 0, 1881},\n\tdictWord{8, 0, 91},\n\tdictWord{11, 11, 966},\n\tdictWord{12, 11, 287},\n\tdictWord{13, 11, 342},\n\tdictWord{13, 11, 402},\n\tdictWord{15, 11, 110},\n\tdictWord{143, 11, 163},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t258,\n\t},\n\tdictWord{136, 11, 639},\n\tdictWord{6, 11, 22},\n\tdictWord{7, 11, 903},\n\tdictWord{138, 11, 577},\n\tdictWord{133, 11, 681},\n\tdictWord{135, 10, 1111},\n\tdictWord{135, 11, 1286},\n\tdictWord{9, 0, 112},\n\tdictWord{8, 10, 1},\n\tdictWord{138, 10, 326},\n\tdictWord{5, 10, 488},\n\tdictWord{6, 10, 527},\n\tdictWord{7, 10, 489},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1636,\n\t},\n\tdictWord{8, 10, 121},\n\tdictWord{8, 10, 144},\n\tdictWord{8, 10, 359},\n\tdictWord{9, 10, 193},\n\tdictWord{9, 10, 241},\n\tdictWord{9, 10, 336},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t882,\n\t},\n\tdictWord{11, 10, 266},\n\tdictWord{11, 10, 372},\n\tdictWord{11, 10, 944},\n\tdictWord{12, 10, 401},\n\tdictWord{140, 10, 641},\n\tdictWord{4, 11, 664},\n\tdictWord{133, 11, 804},\n\tdictWord{6, 0, 747},\n\tdictWord{134, 0, 1015},\n\tdictWord{135, 0, 1746},\n\tdictWord{9, 10, 31},\n\tdictWord{10, 10, 244},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t699,\n\t},\n\tdictWord{12, 10, 149},\n\tdictWord{141, 10, 497},\n\tdictWord{133, 10, 377},\n\tdictWord{135, 0, 24},\n\tdictWord{6, 0, 1352},\n\tdictWord{5, 11, 32},\n\tdictWord{\n\t\t145,\n\t\t10,\n\t\t101,\n\t},\n\tdictWord{7, 0, 1530},\n\tdictWord{10, 0, 158},\n\tdictWord{13, 0, 13},\n\tdictWord{13, 0, 137},\n\tdictWord{13, 0, 258},\n\tdictWord{14, 0, 111},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t225,\n\t},\n\tdictWord{14, 0, 253},\n\tdictWord{14, 0, 304},\n\tdictWord{14, 0, 339},\n\tdictWord{14, 0, 417},\n\tdictWord{146, 0, 33},\n\tdictWord{4, 0, 503},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1661,\n\t},\n\tdictWord{5, 0, 130},\n\tdictWord{6, 0, 845},\n\tdictWord{7, 0, 1314},\n\tdictWord{9, 0, 610},\n\tdictWord{10, 0, 718},\n\tdictWord{11, 0, 601},\n\tdictWord{11, 0, 819},\n\tdictWord{11, 0, 946},\n\tdictWord{140, 0, 536},\n\tdictWord{10, 0, 149},\n\tdictWord{11, 0, 280},\n\tdictWord{142, 0, 336},\n\tdictWord{134, 0, 1401},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1946,\n\t},\n\tdictWord{8, 0, 663},\n\tdictWord{144, 0, 8},\n\tdictWord{134, 0, 1607},\n\tdictWord{135, 10, 2023},\n\tdictWord{4, 11, 289},\n\tdictWord{7, 11, 629},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1698,\n\t},\n\tdictWord{7, 11, 1711},\n\tdictWord{140, 11, 215},\n\tdictWord{6, 11, 450},\n\tdictWord{136, 11, 109},\n\tdictWord{10, 0, 882},\n\tdictWord{10, 0, 883},\n\tdictWord{10, 0, 914},\n\tdictWord{138, 0, 928},\n\tdictWord{133, 10, 843},\n\tdictWord{136, 11, 705},\n\tdictWord{132, 10, 554},\n\tdictWord{133, 10, 536},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t417,\n\t},\n\tdictWord{9, 10, 79},\n\tdictWord{11, 10, 625},\n\tdictWord{145, 10, 7},\n\tdictWord{7, 11, 1238},\n\tdictWord{142, 11, 37},\n\tdictWord{4, 0, 392},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1597,\n\t},\n\tdictWord{5, 0, 433},\n\tdictWord{9, 0, 633},\n\tdictWord{11, 0, 629},\n\tdictWord{132, 10, 424},\n\tdictWord{7, 10, 336},\n\tdictWord{136, 10, 785},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t355,\n\t},\n\tdictWord{6, 0, 234},\n\tdictWord{7, 0, 769},\n\tdictWord{9, 0, 18},\n\tdictWord{138, 0, 358},\n\tdictWord{4, 10, 896},\n\tdictWord{134, 10, 1777},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t323,\n\t},\n\tdictWord{7, 0, 140},\n\tdictWord{7, 0, 1950},\n\tdictWord{8, 0, 680},\n\tdictWord{11, 0, 817},\n\tdictWord{147, 0, 88},\n\tdictWord{7, 0, 1222},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t386,\n\t},\n\tdictWord{139, 11, 908},\n\tdictWord{11, 0, 249},\n\tdictWord{12, 0, 313},\n\tdictWord{16, 0, 66},\n\tdictWord{145, 0, 26},\n\tdictWord{134, 0, 5},\n\tdictWord{7, 10, 750},\n\tdictWord{9, 10, 223},\n\tdictWord{11, 10, 27},\n\tdictWord{11, 10, 466},\n\tdictWord{12, 10, 624},\n\tdictWord{14, 10, 265},\n\tdictWord{146, 10, 61},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t26,\n\t},\n\tdictWord{134, 0, 1216},\n\tdictWord{5, 0, 963},\n\tdictWord{134, 0, 1773},\n\tdictWord{4, 11, 414},\n\tdictWord{5, 11, 467},\n\tdictWord{9, 11, 654},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t451,\n\t},\n\tdictWord{12, 11, 59},\n\tdictWord{141, 11, 375},\n\tdictWord{135, 11, 17},\n\tdictWord{4, 10, 603},\n\tdictWord{133, 10, 661},\n\tdictWord{4, 10, 11},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t128,\n\t},\n\tdictWord{7, 10, 231},\n\tdictWord{7, 10, 1533},\n\tdictWord{138, 10, 725},\n\tdictWord{135, 11, 955},\n\tdictWord{7, 0, 180},\n\tdictWord{8, 0, 509},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t792,\n\t},\n\tdictWord{132, 10, 476},\n\tdictWord{132, 0, 1002},\n\tdictWord{133, 11, 538},\n\tdictWord{135, 10, 1807},\n\tdictWord{132, 0, 931},\n\tdictWord{7, 0, 943},\n\tdictWord{11, 0, 614},\n\tdictWord{140, 0, 747},\n\tdictWord{135, 0, 1837},\n\tdictWord{9, 10, 20},\n\tdictWord{10, 10, 324},\n\tdictWord{10, 10, 807},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t488,\n\t},\n\tdictWord{134, 0, 641},\n\tdictWord{6, 11, 280},\n\tdictWord{10, 11, 502},\n\tdictWord{11, 11, 344},\n\tdictWord{140, 11, 38},\n\tdictWord{5, 11, 45},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1161,\n\t},\n\tdictWord{11, 11, 448},\n\tdictWord{11, 11, 880},\n\tdictWord{13, 11, 139},\n\tdictWord{13, 11, 407},\n\tdictWord{15, 11, 16},\n\tdictWord{17, 11, 95},\n\tdictWord{\n\t\t18,\n\t\t11,\n\t\t66,\n\t},\n\tdictWord{18, 11, 88},\n\tdictWord{18, 11, 123},\n\tdictWord{149, 11, 7},\n\tdictWord{9, 0, 280},\n\tdictWord{138, 0, 134},\n\tdictWord{22, 0, 22},\n\tdictWord{23, 0, 5},\n\tdictWord{151, 0, 29},\n\tdictWord{136, 11, 777},\n\tdictWord{4, 0, 90},\n\tdictWord{5, 0, 545},\n\tdictWord{7, 0, 754},\n\tdictWord{9, 0, 186},\n\tdictWord{10, 0, 72},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t782,\n\t},\n\tdictWord{11, 0, 577},\n\tdictWord{11, 0, 610},\n\tdictWord{11, 0, 960},\n\tdictWord{12, 0, 354},\n\tdictWord{12, 0, 362},\n\tdictWord{12, 0, 595},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t410,\n\t},\n\tdictWord{135, 11, 521},\n\tdictWord{135, 11, 1778},\n\tdictWord{5, 10, 112},\n\tdictWord{6, 10, 103},\n\tdictWord{134, 10, 150},\n\tdictWord{138, 10, 356},\n\tdictWord{132, 0, 742},\n\tdictWord{7, 0, 151},\n\tdictWord{9, 0, 329},\n\tdictWord{139, 0, 254},\n\tdictWord{8, 0, 853},\n\tdictWord{8, 0, 881},\n\tdictWord{8, 0, 911},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t912,\n\t},\n\tdictWord{10, 0, 872},\n\tdictWord{12, 0, 741},\n\tdictWord{12, 0, 742},\n\tdictWord{152, 0, 18},\n\tdictWord{4, 11, 573},\n\tdictWord{136, 11, 655},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t921,\n\t},\n\tdictWord{134, 0, 934},\n\tdictWord{9, 0, 187},\n\tdictWord{10, 0, 36},\n\tdictWord{11, 0, 1016},\n\tdictWord{17, 0, 44},\n\tdictWord{146, 0, 64},\n\tdictWord{7, 0, 833},\n\tdictWord{136, 0, 517},\n\tdictWord{4, 0, 506},\n\tdictWord{5, 0, 295},\n\tdictWord{135, 0, 1680},\n\tdictWord{4, 10, 708},\n\tdictWord{8, 10, 15},\n\tdictWord{9, 10, 50},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t386,\n\t},\n\tdictWord{11, 10, 18},\n\tdictWord{11, 10, 529},\n\tdictWord{140, 10, 228},\n\tdictWord{7, 0, 251},\n\tdictWord{7, 0, 1701},\n\tdictWord{8, 0, 436},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t563,\n\t},\n\tdictWord{7, 10, 592},\n\tdictWord{7, 10, 637},\n\tdictWord{7, 10, 770},\n\tdictWord{8, 10, 463},\n\tdictWord{9, 10, 60},\n\tdictWord{9, 10, 335},\n\tdictWord{9, 10, 904},\n\tdictWord{10, 10, 73},\n\tdictWord{11, 10, 434},\n\tdictWord{12, 10, 585},\n\tdictWord{13, 10, 331},\n\tdictWord{18, 10, 110},\n\tdictWord{148, 10, 60},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t502,\n\t},\n\tdictWord{136, 0, 584},\n\tdictWord{6, 10, 347},\n\tdictWord{138, 10, 161},\n\tdictWord{7, 0, 987},\n\tdictWord{9, 0, 688},\n\tdictWord{10, 0, 522},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t788,\n\t},\n\tdictWord{12, 0, 137},\n\tdictWord{12, 0, 566},\n\tdictWord{14, 0, 9},\n\tdictWord{14, 0, 24},\n\tdictWord{14, 0, 64},\n\tdictWord{7, 11, 899},\n\tdictWord{142, 11, 325},\n\tdictWord{4, 0, 214},\n\tdictWord{5, 0, 500},\n\tdictWord{5, 10, 102},\n\tdictWord{6, 10, 284},\n\tdictWord{7, 10, 1079},\n\tdictWord{7, 10, 1423},\n\tdictWord{7, 10, 1702},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t470,\n\t},\n\tdictWord{9, 10, 554},\n\tdictWord{9, 10, 723},\n\tdictWord{139, 10, 333},\n\tdictWord{7, 10, 246},\n\tdictWord{135, 10, 840},\n\tdictWord{6, 10, 10},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t571,\n\t},\n\tdictWord{9, 10, 739},\n\tdictWord{143, 10, 91},\n\tdictWord{133, 10, 626},\n\tdictWord{146, 0, 195},\n\tdictWord{134, 0, 1775},\n\tdictWord{7, 0, 389},\n\tdictWord{7, 0, 700},\n\tdictWord{7, 0, 940},\n\tdictWord{8, 0, 514},\n\tdictWord{9, 0, 116},\n\tdictWord{9, 0, 535},\n\tdictWord{10, 0, 118},\n\tdictWord{11, 0, 107},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t148,\n\t},\n\tdictWord{11, 0, 922},\n\tdictWord{12, 0, 254},\n\tdictWord{12, 0, 421},\n\tdictWord{142, 0, 238},\n\tdictWord{5, 10, 18},\n\tdictWord{6, 10, 526},\n\tdictWord{13, 10, 24},\n\tdictWord{13, 10, 110},\n\tdictWord{19, 10, 5},\n\tdictWord{147, 10, 44},\n\tdictWord{132, 0, 743},\n\tdictWord{11, 0, 292},\n\tdictWord{4, 10, 309},\n\tdictWord{5, 10, 462},\n\tdictWord{7, 10, 970},\n\tdictWord{135, 10, 1097},\n\tdictWord{22, 10, 30},\n\tdictWord{150, 10, 33},\n\tdictWord{139, 11, 338},\n\tdictWord{135, 11, 1598},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1283,\n\t},\n\tdictWord{9, 0, 227},\n\tdictWord{11, 0, 325},\n\tdictWord{11, 0, 408},\n\tdictWord{14, 0, 180},\n\tdictWord{146, 0, 47},\n\tdictWord{4, 0, 953},\n\tdictWord{6, 0, 1805},\n\tdictWord{6, 0, 1814},\n\tdictWord{6, 0, 1862},\n\tdictWord{140, 0, 774},\n\tdictWord{6, 11, 611},\n\tdictWord{135, 11, 1733},\n\tdictWord{135, 11, 1464},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t81,\n\t},\n\tdictWord{7, 0, 146},\n\tdictWord{7, 0, 1342},\n\tdictWord{8, 0, 53},\n\tdictWord{8, 0, 561},\n\tdictWord{8, 0, 694},\n\tdictWord{8, 0, 754},\n\tdictWord{9, 0, 115},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t179,\n\t},\n\tdictWord{9, 0, 894},\n\tdictWord{10, 0, 462},\n\tdictWord{10, 0, 813},\n\tdictWord{11, 0, 230},\n\tdictWord{11, 0, 657},\n\tdictWord{11, 0, 699},\n\tdictWord{11, 0, 748},\n\tdictWord{12, 0, 119},\n\tdictWord{12, 0, 200},\n\tdictWord{12, 0, 283},\n\tdictWord{142, 0, 273},\n\tdictWord{5, 0, 408},\n\tdictWord{6, 0, 789},\n\tdictWord{6, 0, 877},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1253,\n\t},\n\tdictWord{6, 0, 1413},\n\tdictWord{137, 0, 747},\n\tdictWord{134, 10, 1704},\n\tdictWord{135, 11, 663},\n\tdictWord{6, 0, 1910},\n\tdictWord{6, 0, 1915},\n\tdictWord{6, 0, 1923},\n\tdictWord{9, 0, 913},\n\tdictWord{9, 0, 928},\n\tdictWord{9, 0, 950},\n\tdictWord{9, 0, 954},\n\tdictWord{9, 0, 978},\n\tdictWord{9, 0, 993},\n\tdictWord{12, 0, 812},\n\tdictWord{12, 0, 819},\n\tdictWord{12, 0, 831},\n\tdictWord{12, 0, 833},\n\tdictWord{12, 0, 838},\n\tdictWord{12, 0, 909},\n\tdictWord{12, 0, 928},\n\tdictWord{12, 0, 931},\n\tdictWord{12, 0, 950},\n\tdictWord{15, 0, 186},\n\tdictWord{15, 0, 187},\n\tdictWord{15, 0, 195},\n\tdictWord{15, 0, 196},\n\tdictWord{15, 0, 209},\n\tdictWord{15, 0, 215},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t236,\n\t},\n\tdictWord{15, 0, 241},\n\tdictWord{15, 0, 249},\n\tdictWord{15, 0, 253},\n\tdictWord{18, 0, 180},\n\tdictWord{18, 0, 221},\n\tdictWord{18, 0, 224},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t227,\n\t},\n\tdictWord{18, 0, 229},\n\tdictWord{149, 0, 60},\n\tdictWord{7, 0, 1826},\n\tdictWord{135, 0, 1938},\n\tdictWord{11, 0, 490},\n\tdictWord{18, 0, 143},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t86,\n\t},\n\tdictWord{7, 10, 743},\n\tdictWord{9, 10, 85},\n\tdictWord{10, 10, 281},\n\tdictWord{10, 10, 432},\n\tdictWord{12, 10, 251},\n\tdictWord{13, 10, 118},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t378,\n\t},\n\tdictWord{5, 10, 524},\n\tdictWord{133, 10, 744},\n\tdictWord{141, 11, 442},\n\tdictWord{10, 10, 107},\n\tdictWord{140, 10, 436},\n\tdictWord{135, 11, 503},\n\tdictWord{134, 0, 1162},\n\tdictWord{132, 10, 927},\n\tdictWord{7, 0, 30},\n\tdictWord{8, 0, 86},\n\tdictWord{8, 0, 315},\n\tdictWord{8, 0, 700},\n\tdictWord{9, 0, 576},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t858,\n\t},\n\tdictWord{10, 0, 414},\n\tdictWord{11, 0, 310},\n\tdictWord{11, 0, 888},\n\tdictWord{11, 0, 904},\n\tdictWord{12, 0, 361},\n\tdictWord{13, 0, 248},\n\tdictWord{13, 0, 371},\n\tdictWord{14, 0, 142},\n\tdictWord{12, 10, 670},\n\tdictWord{146, 10, 94},\n\tdictWord{134, 0, 721},\n\tdictWord{4, 11, 113},\n\tdictWord{5, 11, 163},\n\tdictWord{5, 11, 735},\n\tdictWord{7, 11, 1009},\n\tdictWord{7, 10, 1149},\n\tdictWord{9, 11, 9},\n\tdictWord{9, 10, 156},\n\tdictWord{9, 11, 771},\n\tdictWord{12, 11, 90},\n\tdictWord{13, 11, 138},\n\tdictWord{13, 11, 410},\n\tdictWord{143, 11, 128},\n\tdictWord{138, 0, 839},\n\tdictWord{133, 10, 778},\n\tdictWord{137, 0, 617},\n\tdictWord{133, 10, 502},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t196,\n\t},\n\tdictWord{10, 10, 283},\n\tdictWord{139, 10, 406},\n\tdictWord{6, 0, 428},\n\tdictWord{7, 0, 524},\n\tdictWord{8, 0, 169},\n\tdictWord{8, 0, 234},\n\tdictWord{9, 0, 480},\n\tdictWord{138, 0, 646},\n\tdictWord{133, 10, 855},\n\tdictWord{134, 0, 1648},\n\tdictWord{7, 0, 1205},\n\tdictWord{138, 0, 637},\n\tdictWord{7, 0, 1596},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t935,\n\t},\n\tdictWord{133, 11, 823},\n\tdictWord{5, 11, 269},\n\tdictWord{7, 11, 434},\n\tdictWord{7, 11, 891},\n\tdictWord{8, 11, 339},\n\tdictWord{9, 11, 702},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t594,\n\t},\n\tdictWord{11, 11, 718},\n\tdictWord{145, 11, 100},\n\tdictWord{7, 11, 878},\n\tdictWord{9, 11, 485},\n\tdictWord{141, 11, 264},\n\tdictWord{4, 0, 266},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t4,\n\t},\n\tdictWord{9, 0, 39},\n\tdictWord{10, 0, 166},\n\tdictWord{11, 0, 918},\n\tdictWord{12, 0, 635},\n\tdictWord{20, 0, 10},\n\tdictWord{22, 0, 27},\n\tdictWord{22, 0, 43},\n\tdictWord{\n\t\t22,\n\t\t0,\n\t\t52,\n\t},\n\tdictWord{134, 11, 1713},\n\tdictWord{7, 10, 1400},\n\tdictWord{9, 10, 446},\n\tdictWord{138, 10, 45},\n\tdictWord{135, 11, 900},\n\tdictWord{132, 0, 862},\n\tdictWord{134, 0, 1554},\n\tdictWord{135, 11, 1033},\n\tdictWord{19, 0, 16},\n\tdictWord{147, 11, 16},\n\tdictWord{135, 11, 1208},\n\tdictWord{7, 0, 157},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t279,\n\t},\n\tdictWord{6, 0, 604},\n\tdictWord{136, 0, 391},\n\tdictWord{13, 10, 455},\n\tdictWord{15, 10, 99},\n\tdictWord{15, 10, 129},\n\tdictWord{144, 10, 68},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t172,\n\t},\n\tdictWord{7, 0, 945},\n\tdictWord{11, 0, 713},\n\tdictWord{139, 0, 744},\n\tdictWord{4, 0, 973},\n\tdictWord{10, 0, 877},\n\tdictWord{10, 0, 937},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t938,\n\t},\n\tdictWord{140, 0, 711},\n\tdictWord{139, 0, 1022},\n\tdictWord{132, 10, 568},\n\tdictWord{142, 11, 143},\n\tdictWord{4, 0, 567},\n\tdictWord{9, 0, 859},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t732,\n\t},\n\tdictWord{7, 0, 1846},\n\tdictWord{136, 0, 628},\n\tdictWord{136, 10, 733},\n\tdictWord{133, 0, 762},\n\tdictWord{4, 10, 428},\n\tdictWord{135, 10, 1789},\n\tdictWord{10, 0, 784},\n\tdictWord{13, 0, 191},\n\tdictWord{7, 10, 2015},\n\tdictWord{140, 10, 665},\n\tdictWord{133, 0, 298},\n\tdictWord{7, 0, 633},\n\tdictWord{7, 0, 905},\n\tdictWord{7, 0, 909},\n\tdictWord{7, 0, 1538},\n\tdictWord{9, 0, 767},\n\tdictWord{140, 0, 636},\n\tdictWord{138, 10, 806},\n\tdictWord{132, 0, 795},\n\tdictWord{139, 0, 301},\n\tdictWord{135, 0, 1970},\n\tdictWord{5, 11, 625},\n\tdictWord{135, 11, 1617},\n\tdictWord{135, 11, 275},\n\tdictWord{7, 11, 37},\n\tdictWord{8, 11, 425},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t693,\n\t},\n\tdictWord{9, 11, 720},\n\tdictWord{10, 11, 380},\n\tdictWord{10, 11, 638},\n\tdictWord{11, 11, 273},\n\tdictWord{11, 11, 307},\n\tdictWord{11, 11, 473},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t61,\n\t},\n\tdictWord{143, 11, 43},\n\tdictWord{135, 11, 198},\n\tdictWord{134, 0, 1236},\n\tdictWord{7, 0, 369},\n\tdictWord{12, 0, 644},\n\tdictWord{12, 0, 645},\n\tdictWord{144, 0, 90},\n\tdictWord{19, 0, 15},\n\tdictWord{149, 0, 27},\n\tdictWord{6, 0, 71},\n\tdictWord{7, 0, 845},\n\tdictWord{8, 0, 160},\n\tdictWord{9, 0, 318},\n\tdictWord{6, 10, 1623},\n\tdictWord{134, 10, 1681},\n\tdictWord{134, 0, 1447},\n\tdictWord{134, 0, 1255},\n\tdictWord{138, 0, 735},\n\tdictWord{8, 0, 76},\n\tdictWord{132, 11, 168},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1748,\n\t},\n\tdictWord{8, 10, 715},\n\tdictWord{9, 10, 802},\n\tdictWord{10, 10, 46},\n\tdictWord{10, 10, 819},\n\tdictWord{13, 10, 308},\n\tdictWord{14, 10, 351},\n\tdictWord{14, 10, 363},\n\tdictWord{146, 10, 67},\n\tdictWord{135, 11, 91},\n\tdictWord{6, 0, 474},\n\tdictWord{4, 10, 63},\n\tdictWord{133, 10, 347},\n\tdictWord{133, 10, 749},\n\tdictWord{138, 0, 841},\n\tdictWord{133, 10, 366},\n\tdictWord{6, 0, 836},\n\tdictWord{132, 11, 225},\n\tdictWord{135, 0, 1622},\n\tdictWord{135, 10, 89},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t735,\n\t},\n\tdictWord{134, 0, 1601},\n\tdictWord{138, 11, 145},\n\tdictWord{6, 0, 1390},\n\tdictWord{137, 0, 804},\n\tdictWord{142, 0, 394},\n\tdictWord{6, 11, 15},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t70,\n\t},\n\tdictWord{10, 11, 240},\n\tdictWord{147, 11, 93},\n\tdictWord{6, 0, 96},\n\tdictWord{135, 0, 1426},\n\tdictWord{4, 0, 651},\n\tdictWord{133, 0, 289},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t956,\n\t},\n\tdictWord{7, 10, 977},\n\tdictWord{7, 11, 1157},\n\tdictWord{7, 11, 1506},\n\tdictWord{7, 11, 1606},\n\tdictWord{7, 11, 1615},\n\tdictWord{7, 11, 1619},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1736,\n\t},\n\tdictWord{7, 11, 1775},\n\tdictWord{8, 11, 590},\n\tdictWord{9, 11, 324},\n\tdictWord{9, 11, 736},\n\tdictWord{9, 11, 774},\n\tdictWord{9, 11, 776},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t784,\n\t},\n\tdictWord{10, 11, 567},\n\tdictWord{10, 11, 708},\n\tdictWord{11, 11, 518},\n\tdictWord{11, 11, 613},\n\tdictWord{11, 11, 695},\n\tdictWord{11, 11, 716},\n\tdictWord{11, 11, 739},\n\tdictWord{11, 11, 770},\n\tdictWord{11, 11, 771},\n\tdictWord{11, 11, 848},\n\tdictWord{11, 11, 857},\n\tdictWord{11, 11, 931},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t947,\n\t},\n\tdictWord{12, 11, 326},\n\tdictWord{12, 11, 387},\n\tdictWord{12, 11, 484},\n\tdictWord{12, 11, 528},\n\tdictWord{12, 11, 552},\n\tdictWord{12, 11, 613},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t189,\n\t},\n\tdictWord{13, 11, 256},\n\tdictWord{13, 11, 340},\n\tdictWord{13, 11, 432},\n\tdictWord{13, 11, 436},\n\tdictWord{13, 11, 440},\n\tdictWord{13, 11, 454},\n\tdictWord{14, 11, 174},\n\tdictWord{14, 11, 220},\n\tdictWord{14, 11, 284},\n\tdictWord{14, 11, 390},\n\tdictWord{145, 11, 121},\n\tdictWord{7, 0, 688},\n\tdictWord{8, 0, 35},\n\tdictWord{9, 0, 511},\n\tdictWord{10, 0, 767},\n\tdictWord{147, 0, 118},\n\tdictWord{134, 0, 667},\n\tdictWord{4, 0, 513},\n\tdictWord{5, 10, 824},\n\tdictWord{133, 10, 941},\n\tdictWord{7, 10, 440},\n\tdictWord{8, 10, 230},\n\tdictWord{139, 10, 106},\n\tdictWord{134, 0, 2034},\n\tdictWord{135, 11, 1399},\n\tdictWord{143, 11, 66},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1529,\n\t},\n\tdictWord{4, 11, 145},\n\tdictWord{6, 11, 176},\n\tdictWord{7, 11, 395},\n\tdictWord{9, 11, 562},\n\tdictWord{144, 11, 28},\n\tdictWord{132, 11, 501},\n\tdictWord{132, 0, 704},\n\tdictWord{134, 0, 1524},\n\tdictWord{7, 0, 1078},\n\tdictWord{134, 11, 464},\n\tdictWord{6, 11, 509},\n\tdictWord{10, 11, 82},\n\tdictWord{20, 11, 91},\n\tdictWord{151, 11, 13},\n\tdictWord{4, 0, 720},\n\tdictWord{133, 0, 306},\n\tdictWord{133, 0, 431},\n\tdictWord{7, 0, 1196},\n\tdictWord{4, 10, 914},\n\tdictWord{5, 10, 800},\n\tdictWord{133, 10, 852},\n\tdictWord{135, 11, 1189},\n\tdictWord{10, 0, 54},\n\tdictWord{141, 10, 115},\n\tdictWord{7, 10, 564},\n\tdictWord{142, 10, 168},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t464,\n\t},\n\tdictWord{6, 0, 236},\n\tdictWord{7, 0, 696},\n\tdictWord{7, 0, 914},\n\tdictWord{7, 0, 1108},\n\tdictWord{7, 0, 1448},\n\tdictWord{9, 0, 15},\n\tdictWord{9, 0, 564},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t14,\n\t},\n\tdictWord{12, 0, 565},\n\tdictWord{13, 0, 449},\n\tdictWord{14, 0, 53},\n\tdictWord{15, 0, 13},\n\tdictWord{16, 0, 64},\n\tdictWord{17, 0, 41},\n\tdictWord{4, 10, 918},\n\tdictWord{133, 10, 876},\n\tdictWord{6, 0, 1418},\n\tdictWord{134, 10, 1764},\n\tdictWord{4, 10, 92},\n\tdictWord{133, 10, 274},\n\tdictWord{134, 0, 907},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t114,\n\t},\n\tdictWord{8, 10, 501},\n\tdictWord{9, 11, 492},\n\tdictWord{13, 11, 462},\n\tdictWord{142, 11, 215},\n\tdictWord{4, 11, 77},\n\tdictWord{5, 11, 361},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t139,\n\t},\n\tdictWord{6, 11, 401},\n\tdictWord{6, 11, 404},\n\tdictWord{7, 11, 413},\n\tdictWord{7, 11, 715},\n\tdictWord{7, 11, 1716},\n\tdictWord{11, 11, 279},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t179,\n\t},\n\tdictWord{12, 11, 258},\n\tdictWord{13, 11, 244},\n\tdictWord{142, 11, 358},\n\tdictWord{6, 0, 1767},\n\tdictWord{12, 0, 194},\n\tdictWord{145, 0, 107},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t1717,\n\t},\n\tdictWord{5, 10, 743},\n\tdictWord{142, 11, 329},\n\tdictWord{4, 10, 49},\n\tdictWord{7, 10, 280},\n\tdictWord{135, 10, 1633},\n\tdictWord{5, 0, 840},\n\tdictWord{7, 11, 1061},\n\tdictWord{8, 11, 82},\n\tdictWord{11, 11, 250},\n\tdictWord{12, 11, 420},\n\tdictWord{141, 11, 184},\n\tdictWord{135, 11, 724},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t900,\n\t},\n\tdictWord{136, 10, 47},\n\tdictWord{134, 0, 1436},\n\tdictWord{144, 11, 0},\n\tdictWord{6, 0, 675},\n\tdictWord{7, 0, 1008},\n\tdictWord{7, 0, 1560},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t642,\n\t},\n\tdictWord{11, 0, 236},\n\tdictWord{14, 0, 193},\n\tdictWord{5, 10, 272},\n\tdictWord{5, 10, 908},\n\tdictWord{5, 10, 942},\n\tdictWord{8, 10, 197},\n\tdictWord{9, 10, 47},\n\tdictWord{11, 10, 538},\n\tdictWord{139, 10, 742},\n\tdictWord{4, 0, 68},\n\tdictWord{5, 0, 628},\n\tdictWord{5, 0, 634},\n\tdictWord{6, 0, 386},\n\tdictWord{7, 0, 794},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t273,\n\t},\n\tdictWord{9, 0, 563},\n\tdictWord{10, 0, 105},\n\tdictWord{10, 0, 171},\n\tdictWord{11, 0, 94},\n\tdictWord{139, 0, 354},\n\tdictWord{135, 10, 1911},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t891,\n\t},\n\tdictWord{4, 0, 95},\n\tdictWord{6, 0, 1297},\n\tdictWord{6, 0, 1604},\n\tdictWord{7, 0, 416},\n\tdictWord{139, 0, 830},\n\tdictWord{6, 11, 513},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1052,\n\t},\n\tdictWord{7, 0, 731},\n\tdictWord{13, 0, 20},\n\tdictWord{143, 0, 11},\n\tdictWord{137, 11, 899},\n\tdictWord{10, 0, 850},\n\tdictWord{140, 0, 697},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t662,\n\t},\n\tdictWord{7, 11, 1417},\n\tdictWord{12, 11, 382},\n\tdictWord{17, 11, 48},\n\tdictWord{152, 11, 12},\n\tdictWord{133, 0, 736},\n\tdictWord{132, 0, 861},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t407,\n\t},\n\tdictWord{132, 10, 560},\n\tdictWord{141, 10, 490},\n\tdictWord{6, 11, 545},\n\tdictWord{7, 11, 565},\n\tdictWord{7, 11, 1669},\n\tdictWord{10, 11, 114},\n\tdictWord{11, 11, 642},\n\tdictWord{140, 11, 618},\n\tdictWord{6, 0, 871},\n\tdictWord{134, 0, 1000},\n\tdictWord{5, 0, 864},\n\tdictWord{10, 0, 648},\n\tdictWord{11, 0, 671},\n\tdictWord{15, 0, 46},\n\tdictWord{133, 11, 5},\n\tdictWord{133, 0, 928},\n\tdictWord{11, 0, 90},\n\tdictWord{13, 0, 7},\n\tdictWord{4, 10, 475},\n\tdictWord{11, 10, 35},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t71,\n\t},\n\tdictWord{13, 10, 177},\n\tdictWord{142, 10, 422},\n\tdictWord{136, 0, 332},\n\tdictWord{135, 11, 192},\n\tdictWord{134, 0, 1055},\n\tdictWord{136, 11, 763},\n\tdictWord{11, 0, 986},\n\tdictWord{140, 0, 682},\n\tdictWord{7, 0, 76},\n\tdictWord{8, 0, 44},\n\tdictWord{9, 0, 884},\n\tdictWord{10, 0, 580},\n\tdictWord{11, 0, 399},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t894,\n\t},\n\tdictWord{143, 0, 122},\n\tdictWord{135, 11, 1237},\n\tdictWord{135, 10, 636},\n\tdictWord{11, 0, 300},\n\tdictWord{6, 10, 222},\n\tdictWord{7, 10, 1620},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t409,\n\t},\n\tdictWord{137, 10, 693},\n\tdictWord{4, 11, 87},\n\tdictWord{5, 11, 250},\n\tdictWord{10, 11, 601},\n\tdictWord{13, 11, 298},\n\tdictWord{13, 11, 353},\n\tdictWord{141, 11, 376},\n\tdictWord{5, 0, 518},\n\tdictWord{10, 0, 340},\n\tdictWord{11, 0, 175},\n\tdictWord{149, 0, 16},\n\tdictWord{140, 0, 771},\n\tdictWord{6, 0, 1108},\n\tdictWord{137, 0, 831},\n\tdictWord{132, 0, 836},\n\tdictWord{135, 0, 1852},\n\tdictWord{4, 0, 957},\n\tdictWord{6, 0, 1804},\n\tdictWord{8, 0, 842},\n\tdictWord{8, 0, 843},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t851,\n\t},\n\tdictWord{8, 0, 855},\n\tdictWord{140, 0, 767},\n\tdictWord{135, 11, 814},\n\tdictWord{4, 11, 57},\n\tdictWord{7, 11, 1195},\n\tdictWord{7, 11, 1438},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1548,\n\t},\n\tdictWord{7, 11, 1835},\n\tdictWord{7, 11, 1904},\n\tdictWord{9, 11, 757},\n\tdictWord{10, 11, 604},\n\tdictWord{139, 11, 519},\n\tdictWord{133, 10, 882},\n\tdictWord{138, 0, 246},\n\tdictWord{4, 0, 934},\n\tdictWord{5, 0, 202},\n\tdictWord{8, 0, 610},\n\tdictWord{7, 11, 1897},\n\tdictWord{12, 11, 290},\n\tdictWord{13, 11, 80},\n\tdictWord{13, 11, 437},\n\tdictWord{145, 11, 74},\n\tdictWord{8, 0, 96},\n\tdictWord{9, 0, 36},\n\tdictWord{10, 0, 607},\n\tdictWord{10, 0, 804},\n\tdictWord{10, 0, 832},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t423,\n\t},\n\tdictWord{11, 0, 442},\n\tdictWord{12, 0, 309},\n\tdictWord{14, 0, 199},\n\tdictWord{15, 0, 90},\n\tdictWord{145, 0, 110},\n\tdictWord{132, 10, 426},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t654,\n\t},\n\tdictWord{8, 0, 240},\n\tdictWord{6, 10, 58},\n\tdictWord{7, 10, 745},\n\tdictWord{7, 10, 1969},\n\tdictWord{8, 10, 675},\n\tdictWord{9, 10, 479},\n\tdictWord{9, 10, 731},\n\tdictWord{10, 10, 330},\n\tdictWord{10, 10, 593},\n\tdictWord{10, 10, 817},\n\tdictWord{11, 10, 32},\n\tdictWord{11, 10, 133},\n\tdictWord{11, 10, 221},\n\tdictWord{\n\t\t145,\n\t\t10,\n\t\t68,\n\t},\n\tdictWord{9, 0, 13},\n\tdictWord{9, 0, 398},\n\tdictWord{9, 0, 727},\n\tdictWord{10, 0, 75},\n\tdictWord{10, 0, 184},\n\tdictWord{10, 0, 230},\n\tdictWord{10, 0, 564},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t569,\n\t},\n\tdictWord{11, 0, 973},\n\tdictWord{12, 0, 70},\n\tdictWord{12, 0, 189},\n\tdictWord{13, 0, 57},\n\tdictWord{141, 0, 257},\n\tdictWord{4, 11, 209},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t902,\n\t},\n\tdictWord{7, 0, 391},\n\tdictWord{137, 10, 538},\n\tdictWord{134, 0, 403},\n\tdictWord{6, 11, 303},\n\tdictWord{7, 11, 335},\n\tdictWord{7, 11, 1437},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1668,\n\t},\n\tdictWord{8, 11, 553},\n\tdictWord{8, 11, 652},\n\tdictWord{8, 11, 656},\n\tdictWord{9, 11, 558},\n\tdictWord{11, 11, 743},\n\tdictWord{149, 11, 18},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t559,\n\t},\n\tdictWord{11, 0, 75},\n\tdictWord{142, 0, 267},\n\tdictWord{6, 0, 815},\n\tdictWord{141, 11, 2},\n\tdictWord{141, 0, 366},\n\tdictWord{137, 0, 631},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t1017,\n\t},\n\tdictWord{5, 0, 345},\n\tdictWord{135, 0, 1016},\n\tdictWord{133, 11, 709},\n\tdictWord{134, 11, 1745},\n\tdictWord{133, 10, 566},\n\tdictWord{7, 0, 952},\n\tdictWord{6, 10, 48},\n\tdictWord{9, 10, 139},\n\tdictWord{10, 10, 399},\n\tdictWord{11, 10, 469},\n\tdictWord{12, 10, 634},\n\tdictWord{141, 10, 223},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t673,\n\t},\n\tdictWord{9, 0, 850},\n\tdictWord{7, 11, 8},\n\tdictWord{136, 11, 206},\n\tdictWord{6, 0, 662},\n\tdictWord{149, 0, 35},\n\tdictWord{4, 0, 287},\n\tdictWord{133, 0, 1018},\n\tdictWord{6, 10, 114},\n\tdictWord{7, 10, 1224},\n\tdictWord{7, 10, 1556},\n\tdictWord{136, 10, 3},\n\tdictWord{8, 10, 576},\n\tdictWord{137, 10, 267},\n\tdictWord{4, 0, 884},\n\tdictWord{5, 0, 34},\n\tdictWord{10, 0, 724},\n\tdictWord{12, 0, 444},\n\tdictWord{13, 0, 354},\n\tdictWord{18, 0, 32},\n\tdictWord{23, 0, 24},\n\tdictWord{23, 0, 31},\n\tdictWord{\n\t\t152,\n\t\t0,\n\t\t5,\n\t},\n\tdictWord{133, 10, 933},\n\tdictWord{132, 11, 776},\n\tdictWord{138, 0, 151},\n\tdictWord{136, 0, 427},\n\tdictWord{134, 0, 382},\n\tdictWord{132, 0, 329},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t846,\n\t},\n\tdictWord{10, 0, 827},\n\tdictWord{138, 11, 33},\n\tdictWord{9, 0, 279},\n\tdictWord{10, 0, 407},\n\tdictWord{14, 0, 84},\n\tdictWord{22, 0, 18},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1297,\n\t},\n\tdictWord{136, 11, 406},\n\tdictWord{132, 0, 906},\n\tdictWord{136, 0, 366},\n\tdictWord{134, 0, 843},\n\tdictWord{134, 0, 1443},\n\tdictWord{135, 0, 1372},\n\tdictWord{138, 0, 992},\n\tdictWord{4, 0, 123},\n\tdictWord{5, 0, 605},\n\tdictWord{7, 0, 1509},\n\tdictWord{136, 0, 36},\n\tdictWord{132, 0, 649},\n\tdictWord{8, 11, 175},\n\tdictWord{10, 11, 168},\n\tdictWord{138, 11, 573},\n\tdictWord{133, 0, 767},\n\tdictWord{134, 0, 1018},\n\tdictWord{135, 11, 1305},\n\tdictWord{12, 10, 30},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t148,\n\t},\n\tdictWord{14, 10, 87},\n\tdictWord{14, 10, 182},\n\tdictWord{16, 10, 42},\n\tdictWord{148, 10, 70},\n\tdictWord{134, 11, 607},\n\tdictWord{4, 0, 273},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t658,\n\t},\n\tdictWord{133, 0, 995},\n\tdictWord{6, 0, 72},\n\tdictWord{139, 11, 174},\n\tdictWord{10, 0, 483},\n\tdictWord{12, 0, 368},\n\tdictWord{7, 10, 56},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1989,\n\t},\n\tdictWord{8, 10, 337},\n\tdictWord{8, 10, 738},\n\tdictWord{9, 10, 600},\n\tdictWord{13, 10, 447},\n\tdictWord{142, 10, 92},\n\tdictWord{5, 11, 784},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t666,\n\t},\n\tdictWord{135, 0, 1345},\n\tdictWord{139, 11, 882},\n\tdictWord{134, 0, 1293},\n\tdictWord{133, 0, 589},\n\tdictWord{134, 0, 1988},\n\tdictWord{5, 0, 117},\n\tdictWord{6, 0, 514},\n\tdictWord{6, 0, 541},\n\tdictWord{7, 0, 1164},\n\tdictWord{7, 0, 1436},\n\tdictWord{8, 0, 220},\n\tdictWord{8, 0, 648},\n\tdictWord{10, 0, 688},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t560,\n\t},\n\tdictWord{136, 0, 379},\n\tdictWord{5, 0, 686},\n\tdictWord{7, 10, 866},\n\tdictWord{135, 10, 1163},\n\tdictWord{132, 10, 328},\n\tdictWord{9, 11, 14},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t441,\n\t},\n\tdictWord{10, 11, 306},\n\tdictWord{139, 11, 9},\n\tdictWord{4, 10, 101},\n\tdictWord{135, 10, 1171},\n\tdictWord{5, 10, 833},\n\tdictWord{136, 10, 744},\n\tdictWord{5, 11, 161},\n\tdictWord{7, 11, 839},\n\tdictWord{135, 11, 887},\n\tdictWord{7, 0, 196},\n\tdictWord{10, 0, 765},\n\tdictWord{11, 0, 347},\n\tdictWord{11, 0, 552},\n\tdictWord{11, 0, 790},\n\tdictWord{12, 0, 263},\n\tdictWord{13, 0, 246},\n\tdictWord{13, 0, 270},\n\tdictWord{13, 0, 395},\n\tdictWord{14, 0, 176},\n\tdictWord{14, 0, 190},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t398,\n\t},\n\tdictWord{14, 0, 412},\n\tdictWord{15, 0, 32},\n\tdictWord{15, 0, 63},\n\tdictWord{16, 0, 88},\n\tdictWord{147, 0, 105},\n\tdictWord{6, 10, 9},\n\tdictWord{6, 10, 397},\n\tdictWord{7, 10, 53},\n\tdictWord{7, 10, 1742},\n\tdictWord{10, 10, 632},\n\tdictWord{11, 10, 828},\n\tdictWord{140, 10, 146},\n\tdictWord{5, 0, 381},\n\tdictWord{135, 0, 1792},\n\tdictWord{134, 0, 1452},\n\tdictWord{135, 11, 429},\n\tdictWord{8, 0, 367},\n\tdictWord{10, 0, 760},\n\tdictWord{14, 0, 79},\n\tdictWord{20, 0, 17},\n\tdictWord{152, 0, 0},\n\tdictWord{7, 0, 616},\n\tdictWord{138, 0, 413},\n\tdictWord{11, 10, 417},\n\tdictWord{12, 10, 223},\n\tdictWord{140, 10, 265},\n\tdictWord{7, 11, 1611},\n\tdictWord{13, 11, 14},\n\tdictWord{15, 11, 44},\n\tdictWord{19, 11, 13},\n\tdictWord{148, 11, 76},\n\tdictWord{135, 0, 1229},\n\tdictWord{6, 0, 120},\n\tdictWord{7, 0, 1188},\n\tdictWord{7, 0, 1710},\n\tdictWord{8, 0, 286},\n\tdictWord{9, 0, 667},\n\tdictWord{11, 0, 592},\n\tdictWord{139, 0, 730},\n\tdictWord{135, 11, 1814},\n\tdictWord{135, 0, 1146},\n\tdictWord{4, 10, 186},\n\tdictWord{5, 10, 157},\n\tdictWord{8, 10, 168},\n\tdictWord{138, 10, 6},\n\tdictWord{4, 0, 352},\n\tdictWord{135, 0, 687},\n\tdictWord{4, 0, 192},\n\tdictWord{5, 0, 49},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t200,\n\t},\n\tdictWord{6, 0, 293},\n\tdictWord{6, 0, 1696},\n\tdictWord{135, 0, 1151},\n\tdictWord{133, 10, 875},\n\tdictWord{5, 10, 773},\n\tdictWord{5, 10, 991},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1635,\n\t},\n\tdictWord{134, 10, 1788},\n\tdictWord{7, 10, 111},\n\tdictWord{136, 10, 581},\n\tdictWord{6, 0, 935},\n\tdictWord{134, 0, 1151},\n\tdictWord{134, 0, 1050},\n\tdictWord{132, 0, 650},\n\tdictWord{132, 0, 147},\n\tdictWord{11, 0, 194},\n\tdictWord{12, 0, 62},\n\tdictWord{12, 0, 88},\n\tdictWord{11, 11, 194},\n\tdictWord{12, 11, 62},\n\tdictWord{140, 11, 88},\n\tdictWord{6, 0, 339},\n\tdictWord{135, 0, 923},\n\tdictWord{134, 10, 1747},\n\tdictWord{7, 11, 643},\n\tdictWord{136, 11, 236},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t934,\n\t},\n\tdictWord{7, 10, 1364},\n\tdictWord{7, 10, 1907},\n\tdictWord{141, 10, 158},\n\tdictWord{132, 10, 659},\n\tdictWord{4, 10, 404},\n\tdictWord{135, 10, 675},\n\tdictWord{7, 11, 581},\n\tdictWord{9, 11, 644},\n\tdictWord{137, 11, 699},\n\tdictWord{13, 0, 211},\n\tdictWord{14, 0, 133},\n\tdictWord{14, 0, 204},\n\tdictWord{15, 0, 64},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t69,\n\t},\n\tdictWord{15, 0, 114},\n\tdictWord{16, 0, 10},\n\tdictWord{19, 0, 23},\n\tdictWord{19, 0, 35},\n\tdictWord{19, 0, 39},\n\tdictWord{19, 0, 51},\n\tdictWord{19, 0, 71},\n\tdictWord{19, 0, 75},\n\tdictWord{152, 0, 15},\n\tdictWord{133, 10, 391},\n\tdictWord{5, 11, 54},\n\tdictWord{135, 11, 1513},\n\tdictWord{7, 0, 222},\n\tdictWord{8, 0, 341},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t540,\n\t},\n\tdictWord{134, 10, 1697},\n\tdictWord{134, 10, 78},\n\tdictWord{132, 11, 744},\n\tdictWord{136, 0, 293},\n\tdictWord{137, 11, 701},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t930,\n\t},\n\tdictWord{10, 11, 402},\n\tdictWord{10, 11, 476},\n\tdictWord{13, 11, 452},\n\tdictWord{18, 11, 55},\n\tdictWord{147, 11, 104},\n\tdictWord{132, 0, 637},\n\tdictWord{133, 10, 460},\n\tdictWord{8, 11, 50},\n\tdictWord{137, 11, 624},\n\tdictWord{132, 11, 572},\n\tdictWord{134, 0, 1159},\n\tdictWord{4, 10, 199},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t34,\n\t},\n\tdictWord{134, 0, 847},\n\tdictWord{134, 10, 388},\n\tdictWord{6, 11, 43},\n\tdictWord{7, 11, 38},\n\tdictWord{8, 11, 248},\n\tdictWord{9, 11, 504},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t513,\n\t},\n\tdictWord{9, 0, 683},\n\tdictWord{4, 10, 511},\n\tdictWord{6, 10, 608},\n\tdictWord{9, 10, 333},\n\tdictWord{10, 10, 602},\n\tdictWord{11, 10, 441},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t723,\n\t},\n\tdictWord{11, 10, 976},\n\tdictWord{140, 10, 357},\n\tdictWord{9, 0, 867},\n\tdictWord{138, 0, 837},\n\tdictWord{6, 0, 944},\n\tdictWord{135, 11, 326},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1809,\n\t},\n\tdictWord{5, 10, 938},\n\tdictWord{7, 11, 783},\n\tdictWord{136, 10, 707},\n\tdictWord{133, 11, 766},\n\tdictWord{133, 11, 363},\n\tdictWord{6, 0, 170},\n\tdictWord{7, 0, 1080},\n\tdictWord{8, 0, 395},\n\tdictWord{8, 0, 487},\n\tdictWord{141, 0, 147},\n\tdictWord{6, 11, 258},\n\tdictWord{140, 11, 409},\n\tdictWord{4, 0, 535},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t618,\n\t},\n\tdictWord{5, 11, 249},\n\tdictWord{148, 11, 82},\n\tdictWord{6, 0, 1379},\n\tdictWord{149, 11, 15},\n\tdictWord{135, 0, 1625},\n\tdictWord{150, 0, 23},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t393,\n\t},\n\tdictWord{6, 11, 378},\n\tdictWord{7, 11, 1981},\n\tdictWord{9, 11, 32},\n\tdictWord{9, 11, 591},\n\tdictWord{10, 11, 685},\n\tdictWord{10, 11, 741},\n\tdictWord{\n\t\t142,\n\t\t11,\n\t\t382,\n\t},\n\tdictWord{133, 11, 788},\n\tdictWord{7, 11, 1968},\n\tdictWord{10, 11, 19},\n\tdictWord{139, 11, 911},\n\tdictWord{7, 11, 1401},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1476,\n\t},\n\tdictWord{4, 11, 61},\n\tdictWord{5, 11, 58},\n\tdictWord{5, 11, 171},\n\tdictWord{5, 11, 635},\n\tdictWord{5, 11, 683},\n\tdictWord{5, 11, 700},\n\tdictWord{6, 11, 291},\n\tdictWord{6, 11, 566},\n\tdictWord{7, 11, 1650},\n\tdictWord{11, 11, 523},\n\tdictWord{12, 11, 273},\n\tdictWord{12, 11, 303},\n\tdictWord{15, 11, 39},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t111,\n\t},\n\tdictWord{6, 10, 469},\n\tdictWord{7, 10, 1709},\n\tdictWord{138, 10, 515},\n\tdictWord{4, 0, 778},\n\tdictWord{134, 11, 589},\n\tdictWord{132, 0, 46},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t811,\n\t},\n\tdictWord{6, 0, 1679},\n\tdictWord{6, 0, 1714},\n\tdictWord{135, 0, 2032},\n\tdictWord{7, 0, 1458},\n\tdictWord{9, 0, 407},\n\tdictWord{11, 0, 15},\n\tdictWord{12, 0, 651},\n\tdictWord{149, 0, 37},\n\tdictWord{7, 0, 938},\n\tdictWord{132, 10, 500},\n\tdictWord{6, 0, 34},\n\tdictWord{7, 0, 69},\n\tdictWord{7, 0, 1089},\n\tdictWord{7, 0, 1281},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t708,\n\t},\n\tdictWord{8, 0, 721},\n\tdictWord{9, 0, 363},\n\tdictWord{148, 0, 98},\n\tdictWord{10, 11, 231},\n\tdictWord{147, 11, 124},\n\tdictWord{7, 11, 726},\n\tdictWord{\n\t\t152,\n\t\t11,\n\t\t9,\n\t},\n\tdictWord{5, 10, 68},\n\tdictWord{134, 10, 383},\n\tdictWord{136, 11, 583},\n\tdictWord{4, 11, 917},\n\tdictWord{133, 11, 1005},\n\tdictWord{11, 10, 216},\n\tdictWord{139, 10, 340},\n\tdictWord{135, 11, 1675},\n\tdictWord{8, 0, 441},\n\tdictWord{10, 0, 314},\n\tdictWord{143, 0, 3},\n\tdictWord{132, 11, 919},\n\tdictWord{4, 10, 337},\n\tdictWord{6, 10, 353},\n\tdictWord{7, 10, 1934},\n\tdictWord{8, 10, 488},\n\tdictWord{137, 10, 429},\n\tdictWord{7, 0, 889},\n\tdictWord{7, 10, 1795},\n\tdictWord{8, 10, 259},\n\tdictWord{9, 10, 135},\n\tdictWord{9, 10, 177},\n\tdictWord{9, 10, 860},\n\tdictWord{10, 10, 825},\n\tdictWord{11, 10, 115},\n\tdictWord{11, 10, 370},\n\tdictWord{11, 10, 405},\n\tdictWord{11, 10, 604},\n\tdictWord{12, 10, 10},\n\tdictWord{12, 10, 667},\n\tdictWord{12, 10, 669},\n\tdictWord{13, 10, 76},\n\tdictWord{14, 10, 310},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t76,\n\t},\n\tdictWord{15, 10, 147},\n\tdictWord{148, 10, 23},\n\tdictWord{4, 10, 15},\n\tdictWord{4, 11, 255},\n\tdictWord{5, 10, 22},\n\tdictWord{5, 11, 302},\n\tdictWord{6, 11, 132},\n\tdictWord{6, 10, 244},\n\tdictWord{7, 10, 40},\n\tdictWord{7, 11, 128},\n\tdictWord{7, 10, 200},\n\tdictWord{7, 11, 283},\n\tdictWord{7, 10, 906},\n\tdictWord{7, 10, 1199},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1299,\n\t},\n\tdictWord{9, 10, 616},\n\tdictWord{10, 11, 52},\n\tdictWord{10, 11, 514},\n\tdictWord{10, 10, 716},\n\tdictWord{11, 10, 635},\n\tdictWord{11, 10, 801},\n\tdictWord{11, 11, 925},\n\tdictWord{12, 10, 458},\n\tdictWord{13, 11, 92},\n\tdictWord{142, 11, 309},\n\tdictWord{132, 0, 462},\n\tdictWord{137, 11, 173},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1735,\n\t},\n\tdictWord{8, 0, 525},\n\tdictWord{5, 10, 598},\n\tdictWord{7, 10, 791},\n\tdictWord{8, 10, 108},\n\tdictWord{137, 10, 123},\n\tdictWord{5, 0, 73},\n\tdictWord{6, 0, 23},\n\tdictWord{134, 0, 338},\n\tdictWord{132, 0, 676},\n\tdictWord{132, 10, 683},\n\tdictWord{7, 0, 725},\n\tdictWord{8, 0, 498},\n\tdictWord{139, 0, 268},\n\tdictWord{12, 0, 21},\n\tdictWord{151, 0, 7},\n\tdictWord{135, 0, 773},\n\tdictWord{4, 10, 155},\n\tdictWord{135, 10, 1689},\n\tdictWord{4, 0, 164},\n\tdictWord{5, 0, 730},\n\tdictWord{5, 10, 151},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t741,\n\t},\n\tdictWord{6, 11, 210},\n\tdictWord{7, 10, 498},\n\tdictWord{7, 10, 870},\n\tdictWord{7, 10, 1542},\n\tdictWord{12, 10, 213},\n\tdictWord{14, 10, 36},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t391,\n\t},\n\tdictWord{17, 10, 111},\n\tdictWord{18, 10, 6},\n\tdictWord{18, 10, 46},\n\tdictWord{18, 10, 151},\n\tdictWord{19, 10, 36},\n\tdictWord{20, 10, 32},\n\tdictWord{\n\t\t20,\n\t\t10,\n\t\t56,\n\t},\n\tdictWord{20, 10, 69},\n\tdictWord{20, 10, 102},\n\tdictWord{21, 10, 4},\n\tdictWord{22, 10, 8},\n\tdictWord{22, 10, 10},\n\tdictWord{22, 10, 14},\n\tdictWord{\n\t\t150,\n\t\t10,\n\t\t31,\n\t},\n\tdictWord{4, 10, 624},\n\tdictWord{135, 10, 1752},\n\tdictWord{4, 0, 583},\n\tdictWord{9, 0, 936},\n\tdictWord{15, 0, 214},\n\tdictWord{18, 0, 199},\n\tdictWord{24, 0, 26},\n\tdictWord{134, 11, 588},\n\tdictWord{7, 0, 1462},\n\tdictWord{11, 0, 659},\n\tdictWord{4, 11, 284},\n\tdictWord{134, 11, 223},\n\tdictWord{133, 0, 220},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t803,\n\t},\n\tdictWord{132, 0, 544},\n\tdictWord{4, 10, 492},\n\tdictWord{133, 10, 451},\n\tdictWord{16, 0, 98},\n\tdictWord{148, 0, 119},\n\tdictWord{4, 11, 218},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t526,\n\t},\n\tdictWord{143, 11, 137},\n\tdictWord{135, 10, 835},\n\tdictWord{4, 11, 270},\n\tdictWord{5, 11, 192},\n\tdictWord{6, 11, 332},\n\tdictWord{7, 11, 1322},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t9,\n\t},\n\tdictWord{13, 10, 70},\n\tdictWord{14, 11, 104},\n\tdictWord{142, 11, 311},\n\tdictWord{132, 10, 539},\n\tdictWord{140, 11, 661},\n\tdictWord{5, 0, 176},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t437,\n\t},\n\tdictWord{6, 0, 564},\n\tdictWord{11, 0, 181},\n\tdictWord{141, 0, 183},\n\tdictWord{135, 0, 1192},\n\tdictWord{6, 10, 113},\n\tdictWord{135, 10, 436},\n\tdictWord{136, 10, 718},\n\tdictWord{135, 10, 520},\n\tdictWord{135, 0, 1878},\n\tdictWord{140, 11, 196},\n\tdictWord{7, 11, 379},\n\tdictWord{8, 11, 481},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t377,\n\t},\n\tdictWord{5, 11, 1003},\n\tdictWord{6, 11, 149},\n\tdictWord{137, 11, 746},\n\tdictWord{8, 11, 262},\n\tdictWord{9, 11, 627},\n\tdictWord{10, 11, 18},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t214,\n\t},\n\tdictWord{11, 11, 404},\n\tdictWord{11, 11, 457},\n\tdictWord{11, 11, 780},\n\tdictWord{11, 11, 849},\n\tdictWord{11, 11, 913},\n\tdictWord{13, 11, 330},\n\tdictWord{13, 11, 401},\n\tdictWord{142, 11, 200},\n\tdictWord{149, 0, 26},\n\tdictWord{136, 11, 304},\n\tdictWord{132, 11, 142},\n\tdictWord{135, 0, 944},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t790,\n\t},\n\tdictWord{5, 0, 273},\n\tdictWord{134, 0, 394},\n\tdictWord{134, 0, 855},\n\tdictWord{4, 0, 135},\n\tdictWord{6, 0, 127},\n\tdictWord{7, 0, 1185},\n\tdictWord{7, 0, 1511},\n\tdictWord{8, 0, 613},\n\tdictWord{11, 0, 5},\n\tdictWord{12, 0, 336},\n\tdictWord{12, 0, 495},\n\tdictWord{12, 0, 586},\n\tdictWord{12, 0, 660},\n\tdictWord{12, 0, 668},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t385,\n\t},\n\tdictWord{15, 0, 118},\n\tdictWord{17, 0, 20},\n\tdictWord{146, 0, 98},\n\tdictWord{6, 0, 230},\n\tdictWord{9, 0, 752},\n\tdictWord{18, 0, 109},\n\tdictWord{12, 10, 610},\n\tdictWord{13, 10, 431},\n\tdictWord{144, 10, 59},\n\tdictWord{7, 0, 1954},\n\tdictWord{135, 11, 925},\n\tdictWord{4, 11, 471},\n\tdictWord{5, 11, 51},\n\tdictWord{6, 11, 602},\n\tdictWord{8, 11, 484},\n\tdictWord{10, 11, 195},\n\tdictWord{140, 11, 159},\n\tdictWord{132, 10, 307},\n\tdictWord{136, 11, 688},\n\tdictWord{132, 11, 697},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t812,\n\t},\n\tdictWord{7, 11, 1261},\n\tdictWord{7, 11, 1360},\n\tdictWord{9, 11, 632},\n\tdictWord{140, 11, 352},\n\tdictWord{5, 0, 162},\n\tdictWord{8, 0, 68},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t964,\n\t},\n\tdictWord{4, 0, 654},\n\tdictWord{136, 11, 212},\n\tdictWord{4, 0, 156},\n\tdictWord{7, 0, 998},\n\tdictWord{7, 0, 1045},\n\tdictWord{7, 0, 1860},\n\tdictWord{9, 0, 48},\n\tdictWord{9, 0, 692},\n\tdictWord{11, 0, 419},\n\tdictWord{139, 0, 602},\n\tdictWord{133, 11, 221},\n\tdictWord{4, 11, 373},\n\tdictWord{5, 11, 283},\n\tdictWord{6, 11, 480},\n\tdictWord{135, 11, 609},\n\tdictWord{142, 11, 216},\n\tdictWord{132, 0, 240},\n\tdictWord{6, 11, 192},\n\tdictWord{9, 11, 793},\n\tdictWord{145, 11, 55},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t75,\n\t},\n\tdictWord{5, 10, 180},\n\tdictWord{6, 10, 500},\n\tdictWord{7, 10, 58},\n\tdictWord{7, 10, 710},\n\tdictWord{138, 10, 645},\n\tdictWord{4, 11, 132},\n\tdictWord{5, 11, 69},\n\tdictWord{5, 10, 649},\n\tdictWord{135, 11, 1242},\n\tdictWord{6, 10, 276},\n\tdictWord{7, 10, 282},\n\tdictWord{7, 10, 879},\n\tdictWord{7, 10, 924},\n\tdictWord{8, 10, 459},\n\tdictWord{9, 10, 599},\n\tdictWord{9, 10, 754},\n\tdictWord{11, 10, 574},\n\tdictWord{12, 10, 128},\n\tdictWord{12, 10, 494},\n\tdictWord{13, 10, 52},\n\tdictWord{13, 10, 301},\n\tdictWord{15, 10, 30},\n\tdictWord{143, 10, 132},\n\tdictWord{132, 10, 200},\n\tdictWord{4, 11, 111},\n\tdictWord{135, 11, 302},\n\tdictWord{9, 0, 197},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t300,\n\t},\n\tdictWord{12, 0, 473},\n\tdictWord{13, 0, 90},\n\tdictWord{141, 0, 405},\n\tdictWord{132, 11, 767},\n\tdictWord{6, 11, 42},\n\tdictWord{7, 11, 1416},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1590,\n\t},\n\tdictWord{7, 11, 2005},\n\tdictWord{8, 11, 131},\n\tdictWord{8, 11, 466},\n\tdictWord{9, 11, 672},\n\tdictWord{13, 11, 252},\n\tdictWord{148, 11, 103},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t958,\n\t},\n\tdictWord{8, 0, 999},\n\tdictWord{10, 0, 963},\n\tdictWord{138, 0, 1001},\n\tdictWord{135, 10, 1621},\n\tdictWord{135, 0, 858},\n\tdictWord{4, 0, 606},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t444,\n\t},\n\tdictWord{6, 11, 44},\n\tdictWord{136, 11, 368},\n\tdictWord{139, 11, 172},\n\tdictWord{4, 11, 570},\n\tdictWord{133, 11, 120},\n\tdictWord{139, 11, 624},\n\tdictWord{7, 0, 1978},\n\tdictWord{8, 0, 676},\n\tdictWord{6, 10, 225},\n\tdictWord{137, 10, 211},\n\tdictWord{7, 0, 972},\n\tdictWord{11, 0, 102},\n\tdictWord{136, 10, 687},\n\tdictWord{6, 11, 227},\n\tdictWord{135, 11, 1589},\n\tdictWord{8, 10, 58},\n\tdictWord{9, 10, 724},\n\tdictWord{11, 10, 809},\n\tdictWord{13, 10, 113},\n\tdictWord{\n\t\t145,\n\t\t10,\n\t\t72,\n\t},\n\tdictWord{4, 0, 361},\n\tdictWord{133, 0, 315},\n\tdictWord{132, 0, 461},\n\tdictWord{6, 10, 345},\n\tdictWord{135, 10, 1247},\n\tdictWord{132, 0, 472},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t767,\n\t},\n\tdictWord{8, 10, 803},\n\tdictWord{9, 10, 301},\n\tdictWord{137, 10, 903},\n\tdictWord{135, 11, 1333},\n\tdictWord{135, 11, 477},\n\tdictWord{7, 10, 1949},\n\tdictWord{136, 10, 674},\n\tdictWord{6, 0, 905},\n\tdictWord{138, 0, 747},\n\tdictWord{133, 0, 155},\n\tdictWord{134, 10, 259},\n\tdictWord{7, 0, 163},\n\tdictWord{8, 0, 319},\n\tdictWord{9, 0, 402},\n\tdictWord{10, 0, 24},\n\tdictWord{10, 0, 681},\n\tdictWord{11, 0, 200},\n\tdictWord{12, 0, 253},\n\tdictWord{12, 0, 410},\n\tdictWord{142, 0, 219},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t475,\n\t},\n\tdictWord{7, 0, 1780},\n\tdictWord{9, 0, 230},\n\tdictWord{11, 0, 297},\n\tdictWord{11, 0, 558},\n\tdictWord{14, 0, 322},\n\tdictWord{19, 0, 76},\n\tdictWord{6, 11, 1667},\n\tdictWord{7, 11, 2036},\n\tdictWord{138, 11, 600},\n\tdictWord{136, 10, 254},\n\tdictWord{6, 0, 848},\n\tdictWord{135, 0, 1956},\n\tdictWord{6, 11, 511},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t132,\n\t},\n\tdictWord{5, 11, 568},\n\tdictWord{6, 11, 138},\n\tdictWord{135, 11, 1293},\n\tdictWord{6, 0, 631},\n\tdictWord{137, 0, 838},\n\tdictWord{149, 0, 36},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t565,\n\t},\n\tdictWord{8, 11, 23},\n\tdictWord{136, 11, 827},\n\tdictWord{5, 0, 944},\n\tdictWord{134, 0, 1769},\n\tdictWord{4, 0, 144},\n\tdictWord{6, 0, 842},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1400,\n\t},\n\tdictWord{4, 11, 922},\n\tdictWord{133, 11, 1023},\n\tdictWord{133, 10, 248},\n\tdictWord{9, 10, 800},\n\tdictWord{10, 10, 693},\n\tdictWord{11, 10, 482},\n\tdictWord{11, 10, 734},\n\tdictWord{139, 10, 789},\n\tdictWord{7, 11, 1002},\n\tdictWord{139, 11, 145},\n\tdictWord{4, 10, 116},\n\tdictWord{5, 10, 95},\n\tdictWord{5, 10, 445},\n\tdictWord{7, 10, 1688},\n\tdictWord{8, 10, 29},\n\tdictWord{9, 10, 272},\n\tdictWord{11, 10, 509},\n\tdictWord{139, 10, 915},\n\tdictWord{14, 0, 369},\n\tdictWord{146, 0, 72},\n\tdictWord{135, 10, 1641},\n\tdictWord{132, 11, 740},\n\tdictWord{133, 10, 543},\n\tdictWord{140, 11, 116},\n\tdictWord{6, 0, 247},\n\tdictWord{9, 0, 555},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t181,\n\t},\n\tdictWord{136, 10, 41},\n\tdictWord{133, 10, 657},\n\tdictWord{136, 0, 996},\n\tdictWord{138, 10, 709},\n\tdictWord{7, 0, 189},\n\tdictWord{8, 10, 202},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t536,\n\t},\n\tdictWord{136, 11, 402},\n\tdictWord{4, 11, 716},\n\tdictWord{141, 11, 31},\n\tdictWord{10, 0, 280},\n\tdictWord{138, 0, 797},\n\tdictWord{9, 10, 423},\n\tdictWord{140, 10, 89},\n\tdictWord{8, 10, 113},\n\tdictWord{9, 10, 877},\n\tdictWord{10, 10, 554},\n\tdictWord{11, 10, 83},\n\tdictWord{12, 10, 136},\n\tdictWord{147, 10, 109},\n\tdictWord{133, 10, 976},\n\tdictWord{7, 0, 746},\n\tdictWord{132, 10, 206},\n\tdictWord{136, 0, 526},\n\tdictWord{139, 0, 345},\n\tdictWord{136, 0, 1017},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t152,\n\t},\n\tdictWord{9, 11, 53},\n\tdictWord{9, 11, 268},\n\tdictWord{9, 11, 901},\n\tdictWord{10, 11, 518},\n\tdictWord{10, 11, 829},\n\tdictWord{11, 11, 188},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t74,\n\t},\n\tdictWord{14, 11, 46},\n\tdictWord{15, 11, 17},\n\tdictWord{15, 11, 33},\n\tdictWord{17, 11, 40},\n\tdictWord{18, 11, 36},\n\tdictWord{19, 11, 20},\n\tdictWord{22, 11, 1},\n\tdictWord{152, 11, 2},\n\tdictWord{133, 11, 736},\n\tdictWord{136, 11, 532},\n\tdictWord{5, 0, 428},\n\tdictWord{138, 0, 651},\n\tdictWord{135, 11, 681},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1162,\n\t},\n\tdictWord{7, 0, 327},\n\tdictWord{13, 0, 230},\n\tdictWord{17, 0, 113},\n\tdictWord{8, 10, 226},\n\tdictWord{10, 10, 537},\n\tdictWord{11, 10, 570},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t605,\n\t},\n\tdictWord{11, 10, 799},\n\tdictWord{11, 10, 804},\n\tdictWord{12, 10, 85},\n\tdictWord{12, 10, 516},\n\tdictWord{12, 10, 623},\n\tdictWord{12, 11, 677},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t361,\n\t},\n\tdictWord{14, 10, 77},\n\tdictWord{14, 10, 78},\n\tdictWord{147, 10, 110},\n\tdictWord{4, 0, 792},\n\tdictWord{7, 0, 1717},\n\tdictWord{10, 0, 546},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t769,\n\t},\n\tdictWord{4, 11, 684},\n\tdictWord{136, 11, 384},\n\tdictWord{132, 10, 551},\n\tdictWord{134, 0, 1203},\n\tdictWord{9, 10, 57},\n\tdictWord{9, 10, 459},\n\tdictWord{10, 10, 425},\n\tdictWord{11, 10, 119},\n\tdictWord{12, 10, 184},\n\tdictWord{12, 10, 371},\n\tdictWord{13, 10, 358},\n\tdictWord{145, 10, 51},\n\tdictWord{5, 0, 672},\n\tdictWord{5, 10, 814},\n\tdictWord{8, 10, 10},\n\tdictWord{9, 10, 421},\n\tdictWord{9, 10, 729},\n\tdictWord{10, 10, 609},\n\tdictWord{139, 10, 689},\n\tdictWord{138, 0, 189},\n\tdictWord{134, 10, 624},\n\tdictWord{7, 11, 110},\n\tdictWord{7, 11, 188},\n\tdictWord{8, 11, 290},\n\tdictWord{8, 11, 591},\n\tdictWord{9, 11, 382},\n\tdictWord{9, 11, 649},\n\tdictWord{11, 11, 71},\n\tdictWord{11, 11, 155},\n\tdictWord{11, 11, 313},\n\tdictWord{12, 11, 5},\n\tdictWord{13, 11, 325},\n\tdictWord{142, 11, 287},\n\tdictWord{133, 0, 99},\n\tdictWord{6, 0, 1053},\n\tdictWord{135, 0, 298},\n\tdictWord{7, 11, 360},\n\tdictWord{7, 11, 425},\n\tdictWord{9, 11, 66},\n\tdictWord{9, 11, 278},\n\tdictWord{138, 11, 644},\n\tdictWord{4, 0, 397},\n\tdictWord{136, 0, 555},\n\tdictWord{137, 10, 269},\n\tdictWord{132, 10, 528},\n\tdictWord{4, 11, 900},\n\tdictWord{133, 11, 861},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1157,\n\t},\n\tdictWord{5, 11, 254},\n\tdictWord{7, 11, 985},\n\tdictWord{136, 11, 73},\n\tdictWord{7, 11, 1959},\n\tdictWord{136, 11, 683},\n\tdictWord{12, 0, 398},\n\tdictWord{\n\t\t20,\n\t\t0,\n\t\t39,\n\t},\n\tdictWord{21, 0, 11},\n\tdictWord{150, 0, 41},\n\tdictWord{4, 0, 485},\n\tdictWord{7, 0, 353},\n\tdictWord{135, 0, 1523},\n\tdictWord{6, 0, 366},\n\tdictWord{7, 0, 1384},\n\tdictWord{135, 0, 1601},\n\tdictWord{138, 0, 787},\n\tdictWord{137, 0, 282},\n\tdictWord{5, 10, 104},\n\tdictWord{6, 10, 173},\n\tdictWord{135, 10, 1631},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t146,\n\t},\n\tdictWord{4, 0, 157},\n\tdictWord{133, 0, 471},\n\tdictWord{134, 0, 941},\n\tdictWord{132, 11, 725},\n\tdictWord{7, 0, 1336},\n\tdictWord{8, 10, 138},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t342,\n\t},\n\tdictWord{9, 10, 84},\n\tdictWord{10, 10, 193},\n\tdictWord{11, 10, 883},\n\tdictWord{140, 10, 359},\n\tdictWord{134, 11, 196},\n\tdictWord{136, 0, 116},\n\tdictWord{133, 11, 831},\n\tdictWord{134, 0, 787},\n\tdictWord{134, 10, 95},\n\tdictWord{6, 10, 406},\n\tdictWord{10, 10, 409},\n\tdictWord{10, 10, 447},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t44,\n\t},\n\tdictWord{140, 10, 100},\n\tdictWord{5, 0, 160},\n\tdictWord{7, 0, 363},\n\tdictWord{7, 0, 589},\n\tdictWord{10, 0, 170},\n\tdictWord{141, 0, 55},\n\tdictWord{134, 0, 1815},\n\tdictWord{132, 0, 866},\n\tdictWord{6, 0, 889},\n\tdictWord{6, 0, 1067},\n\tdictWord{6, 0, 1183},\n\tdictWord{4, 11, 321},\n\tdictWord{134, 11, 569},\n\tdictWord{5, 11, 848},\n\tdictWord{134, 11, 66},\n\tdictWord{4, 11, 36},\n\tdictWord{6, 10, 1636},\n\tdictWord{7, 11, 1387},\n\tdictWord{10, 11, 205},\n\tdictWord{11, 11, 755},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t271,\n\t},\n\tdictWord{132, 0, 689},\n\tdictWord{9, 0, 820},\n\tdictWord{4, 10, 282},\n\tdictWord{7, 10, 1034},\n\tdictWord{11, 10, 398},\n\tdictWord{11, 10, 634},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t1,\n\t},\n\tdictWord{12, 10, 79},\n\tdictWord{12, 10, 544},\n\tdictWord{14, 10, 237},\n\tdictWord{17, 10, 10},\n\tdictWord{146, 10, 20},\n\tdictWord{4, 0, 108},\n\tdictWord{7, 0, 804},\n\tdictWord{139, 0, 498},\n\tdictWord{132, 11, 887},\n\tdictWord{6, 0, 1119},\n\tdictWord{135, 11, 620},\n\tdictWord{6, 11, 165},\n\tdictWord{138, 11, 388},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t244,\n\t},\n\tdictWord{5, 10, 499},\n\tdictWord{6, 10, 476},\n\tdictWord{7, 10, 600},\n\tdictWord{7, 10, 888},\n\tdictWord{135, 10, 1096},\n\tdictWord{140, 0, 609},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1005,\n\t},\n\tdictWord{4, 0, 412},\n\tdictWord{133, 0, 581},\n\tdictWord{4, 11, 719},\n\tdictWord{135, 11, 155},\n\tdictWord{7, 10, 296},\n\tdictWord{7, 10, 596},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t560,\n\t},\n\tdictWord{8, 10, 586},\n\tdictWord{9, 10, 612},\n\tdictWord{11, 10, 304},\n\tdictWord{12, 10, 46},\n\tdictWord{13, 10, 89},\n\tdictWord{14, 10, 112},\n\tdictWord{\n\t\t145,\n\t\t10,\n\t\t122,\n\t},\n\tdictWord{4, 0, 895},\n\tdictWord{133, 0, 772},\n\tdictWord{142, 11, 307},\n\tdictWord{135, 0, 1898},\n\tdictWord{4, 0, 926},\n\tdictWord{133, 0, 983},\n\tdictWord{4, 11, 353},\n\tdictWord{6, 11, 146},\n\tdictWord{6, 11, 1789},\n\tdictWord{7, 11, 288},\n\tdictWord{7, 11, 990},\n\tdictWord{7, 11, 1348},\n\tdictWord{9, 11, 665},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t898,\n\t},\n\tdictWord{11, 11, 893},\n\tdictWord{142, 11, 212},\n\tdictWord{132, 0, 538},\n\tdictWord{133, 11, 532},\n\tdictWord{6, 0, 294},\n\tdictWord{7, 0, 1267},\n\tdictWord{8, 0, 624},\n\tdictWord{141, 0, 496},\n\tdictWord{7, 0, 1325},\n\tdictWord{4, 11, 45},\n\tdictWord{135, 11, 1257},\n\tdictWord{138, 0, 301},\n\tdictWord{9, 0, 298},\n\tdictWord{12, 0, 291},\n\tdictWord{13, 0, 276},\n\tdictWord{14, 0, 6},\n\tdictWord{17, 0, 18},\n\tdictWord{21, 0, 32},\n\tdictWord{7, 10, 1599},\n\tdictWord{7, 10, 1723},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t79,\n\t},\n\tdictWord{8, 10, 106},\n\tdictWord{8, 10, 190},\n\tdictWord{8, 10, 302},\n\tdictWord{8, 10, 383},\n\tdictWord{8, 10, 713},\n\tdictWord{9, 10, 119},\n\tdictWord{9, 10, 233},\n\tdictWord{9, 10, 419},\n\tdictWord{9, 10, 471},\n\tdictWord{10, 10, 181},\n\tdictWord{10, 10, 406},\n\tdictWord{11, 10, 57},\n\tdictWord{11, 10, 85},\n\tdictWord{11, 10, 120},\n\tdictWord{11, 10, 177},\n\tdictWord{11, 10, 296},\n\tdictWord{11, 10, 382},\n\tdictWord{11, 10, 454},\n\tdictWord{11, 10, 758},\n\tdictWord{11, 10, 999},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t27,\n\t},\n\tdictWord{12, 10, 131},\n\tdictWord{12, 10, 245},\n\tdictWord{12, 10, 312},\n\tdictWord{12, 10, 446},\n\tdictWord{12, 10, 454},\n\tdictWord{13, 10, 98},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t426,\n\t},\n\tdictWord{13, 10, 508},\n\tdictWord{14, 10, 163},\n\tdictWord{14, 10, 272},\n\tdictWord{14, 10, 277},\n\tdictWord{14, 10, 370},\n\tdictWord{15, 10, 95},\n\tdictWord{15, 10, 138},\n\tdictWord{15, 10, 167},\n\tdictWord{17, 10, 38},\n\tdictWord{148, 10, 96},\n\tdictWord{132, 0, 757},\n\tdictWord{134, 0, 1263},\n\tdictWord{4, 0, 820},\n\tdictWord{134, 10, 1759},\n\tdictWord{133, 0, 722},\n\tdictWord{136, 11, 816},\n\tdictWord{138, 10, 372},\n\tdictWord{145, 10, 16},\n\tdictWord{134, 0, 1039},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t991,\n\t},\n\tdictWord{134, 0, 2028},\n\tdictWord{133, 10, 258},\n\tdictWord{7, 0, 1875},\n\tdictWord{139, 0, 124},\n\tdictWord{6, 11, 559},\n\tdictWord{6, 11, 1691},\n\tdictWord{135, 11, 586},\n\tdictWord{5, 0, 324},\n\tdictWord{7, 0, 881},\n\tdictWord{8, 10, 134},\n\tdictWord{9, 10, 788},\n\tdictWord{140, 10, 438},\n\tdictWord{7, 11, 1823},\n\tdictWord{139, 11, 693},\n\tdictWord{6, 0, 1348},\n\tdictWord{134, 0, 1545},\n\tdictWord{134, 0, 911},\n\tdictWord{132, 0, 954},\n\tdictWord{8, 0, 329},\n\tdictWord{8, 0, 414},\n\tdictWord{7, 10, 1948},\n\tdictWord{135, 10, 2004},\n\tdictWord{5, 0, 517},\n\tdictWord{6, 10, 439},\n\tdictWord{7, 10, 780},\n\tdictWord{135, 10, 1040},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t816,\n\t},\n\tdictWord{5, 10, 1},\n\tdictWord{6, 10, 81},\n\tdictWord{138, 10, 520},\n\tdictWord{9, 0, 713},\n\tdictWord{10, 0, 222},\n\tdictWord{5, 10, 482},\n\tdictWord{8, 10, 98},\n\tdictWord{10, 10, 700},\n\tdictWord{10, 10, 822},\n\tdictWord{11, 10, 302},\n\tdictWord{11, 10, 778},\n\tdictWord{12, 10, 50},\n\tdictWord{12, 10, 127},\n\tdictWord{12, 10, 396},\n\tdictWord{13, 10, 62},\n\tdictWord{13, 10, 328},\n\tdictWord{14, 10, 122},\n\tdictWord{147, 10, 72},\n\tdictWord{137, 0, 33},\n\tdictWord{5, 10, 2},\n\tdictWord{7, 10, 1494},\n\tdictWord{136, 10, 589},\n\tdictWord{6, 10, 512},\n\tdictWord{7, 10, 797},\n\tdictWord{8, 10, 253},\n\tdictWord{9, 10, 77},\n\tdictWord{10, 10, 1},\n\tdictWord{10, 11, 108},\n\tdictWord{10, 10, 129},\n\tdictWord{10, 10, 225},\n\tdictWord{11, 11, 116},\n\tdictWord{11, 10, 118},\n\tdictWord{11, 10, 226},\n\tdictWord{11, 10, 251},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t430,\n\t},\n\tdictWord{11, 10, 701},\n\tdictWord{11, 10, 974},\n\tdictWord{11, 10, 982},\n\tdictWord{12, 10, 64},\n\tdictWord{12, 10, 260},\n\tdictWord{12, 10, 488},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t690,\n\t},\n\tdictWord{134, 11, 456},\n\tdictWord{133, 11, 925},\n\tdictWord{5, 0, 150},\n\tdictWord{7, 0, 106},\n\tdictWord{7, 0, 774},\n\tdictWord{8, 0, 603},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t593,\n\t},\n\tdictWord{9, 0, 634},\n\tdictWord{10, 0, 44},\n\tdictWord{10, 0, 173},\n\tdictWord{11, 0, 462},\n\tdictWord{11, 0, 515},\n\tdictWord{13, 0, 216},\n\tdictWord{13, 0, 288},\n\tdictWord{142, 0, 400},\n\tdictWord{137, 10, 347},\n\tdictWord{5, 0, 748},\n\tdictWord{134, 0, 553},\n\tdictWord{12, 0, 108},\n\tdictWord{141, 0, 291},\n\tdictWord{7, 0, 420},\n\tdictWord{4, 10, 12},\n\tdictWord{7, 10, 522},\n\tdictWord{7, 10, 809},\n\tdictWord{8, 10, 797},\n\tdictWord{141, 10, 88},\n\tdictWord{6, 11, 193},\n\tdictWord{7, 11, 240},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1682,\n\t},\n\tdictWord{10, 11, 51},\n\tdictWord{10, 11, 640},\n\tdictWord{11, 11, 410},\n\tdictWord{13, 11, 82},\n\tdictWord{14, 11, 247},\n\tdictWord{14, 11, 331},\n\tdictWord{142, 11, 377},\n\tdictWord{133, 10, 528},\n\tdictWord{135, 0, 1777},\n\tdictWord{4, 0, 493},\n\tdictWord{144, 0, 55},\n\tdictWord{136, 11, 633},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t81,\n\t},\n\tdictWord{6, 0, 980},\n\tdictWord{136, 0, 321},\n\tdictWord{148, 10, 109},\n\tdictWord{5, 10, 266},\n\tdictWord{9, 10, 290},\n\tdictWord{9, 10, 364},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t293,\n\t},\n\tdictWord{11, 10, 606},\n\tdictWord{142, 10, 45},\n\tdictWord{6, 0, 568},\n\tdictWord{7, 0, 112},\n\tdictWord{7, 0, 1804},\n\tdictWord{8, 0, 362},\n\tdictWord{8, 0, 410},\n\tdictWord{8, 0, 830},\n\tdictWord{9, 0, 514},\n\tdictWord{11, 0, 649},\n\tdictWord{142, 0, 157},\n\tdictWord{4, 0, 74},\n\tdictWord{6, 0, 510},\n\tdictWord{6, 10, 594},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t121,\n\t},\n\tdictWord{10, 10, 49},\n\tdictWord{10, 10, 412},\n\tdictWord{139, 10, 834},\n\tdictWord{134, 0, 838},\n\tdictWord{136, 10, 748},\n\tdictWord{132, 10, 466},\n\tdictWord{132, 0, 625},\n\tdictWord{135, 11, 1443},\n\tdictWord{4, 11, 237},\n\tdictWord{135, 11, 514},\n\tdictWord{9, 10, 378},\n\tdictWord{141, 10, 162},\n\tdictWord{6, 0, 16},\n\tdictWord{6, 0, 158},\n\tdictWord{7, 0, 43},\n\tdictWord{7, 0, 129},\n\tdictWord{7, 0, 181},\n\tdictWord{8, 0, 276},\n\tdictWord{8, 0, 377},\n\tdictWord{10, 0, 523},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t816,\n\t},\n\tdictWord{12, 0, 455},\n\tdictWord{13, 0, 303},\n\tdictWord{142, 0, 135},\n\tdictWord{135, 0, 281},\n\tdictWord{4, 0, 1},\n\tdictWord{7, 0, 1143},\n\tdictWord{7, 0, 1463},\n\tdictWord{8, 0, 61},\n\tdictWord{9, 0, 207},\n\tdictWord{9, 0, 390},\n\tdictWord{9, 0, 467},\n\tdictWord{139, 0, 836},\n\tdictWord{6, 11, 392},\n\tdictWord{7, 11, 65},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t2019,\n\t},\n\tdictWord{132, 10, 667},\n\tdictWord{4, 0, 723},\n\tdictWord{5, 0, 895},\n\tdictWord{7, 0, 1031},\n\tdictWord{8, 0, 199},\n\tdictWord{8, 0, 340},\n\tdictWord{9, 0, 153},\n\tdictWord{9, 0, 215},\n\tdictWord{10, 0, 21},\n\tdictWord{10, 0, 59},\n\tdictWord{10, 0, 80},\n\tdictWord{10, 0, 224},\n\tdictWord{10, 0, 838},\n\tdictWord{11, 0, 229},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t652,\n\t},\n\tdictWord{12, 0, 192},\n\tdictWord{13, 0, 146},\n\tdictWord{142, 0, 91},\n\tdictWord{132, 0, 295},\n\tdictWord{137, 0, 51},\n\tdictWord{9, 11, 222},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t43,\n\t},\n\tdictWord{139, 11, 900},\n\tdictWord{5, 0, 309},\n\tdictWord{140, 0, 211},\n\tdictWord{5, 0, 125},\n\tdictWord{8, 0, 77},\n\tdictWord{138, 0, 15},\n\tdictWord{136, 11, 604},\n\tdictWord{138, 0, 789},\n\tdictWord{5, 0, 173},\n\tdictWord{4, 10, 39},\n\tdictWord{7, 10, 1843},\n\tdictWord{8, 10, 407},\n\tdictWord{11, 10, 144},\n\tdictWord{140, 10, 523},\n\tdictWord{138, 11, 265},\n\tdictWord{133, 0, 439},\n\tdictWord{132, 10, 510},\n\tdictWord{7, 0, 648},\n\tdictWord{7, 0, 874},\n\tdictWord{11, 0, 164},\n\tdictWord{12, 0, 76},\n\tdictWord{18, 0, 9},\n\tdictWord{7, 10, 1980},\n\tdictWord{10, 10, 487},\n\tdictWord{138, 10, 809},\n\tdictWord{12, 0, 111},\n\tdictWord{14, 0, 294},\n\tdictWord{19, 0, 45},\n\tdictWord{13, 10, 260},\n\tdictWord{146, 10, 63},\n\tdictWord{133, 11, 549},\n\tdictWord{134, 10, 570},\n\tdictWord{4, 0, 8},\n\tdictWord{7, 0, 1152},\n\tdictWord{7, 0, 1153},\n\tdictWord{7, 0, 1715},\n\tdictWord{9, 0, 374},\n\tdictWord{10, 0, 478},\n\tdictWord{139, 0, 648},\n\tdictWord{135, 0, 1099},\n\tdictWord{5, 0, 575},\n\tdictWord{6, 0, 354},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t701,\n\t},\n\tdictWord{7, 11, 36},\n\tdictWord{8, 11, 201},\n\tdictWord{136, 11, 605},\n\tdictWord{4, 10, 787},\n\tdictWord{136, 11, 156},\n\tdictWord{6, 0, 518},\n\tdictWord{\n\t\t149,\n\t\t11,\n\t\t13,\n\t},\n\tdictWord{140, 11, 224},\n\tdictWord{134, 0, 702},\n\tdictWord{132, 10, 516},\n\tdictWord{5, 11, 724},\n\tdictWord{10, 11, 305},\n\tdictWord{11, 11, 151},\n\tdictWord{12, 11, 33},\n\tdictWord{12, 11, 121},\n\tdictWord{12, 11, 381},\n\tdictWord{17, 11, 3},\n\tdictWord{17, 11, 27},\n\tdictWord{17, 11, 78},\n\tdictWord{18, 11, 18},\n\tdictWord{19, 11, 54},\n\tdictWord{149, 11, 5},\n\tdictWord{8, 0, 87},\n\tdictWord{4, 11, 523},\n\tdictWord{5, 11, 638},\n\tdictWord{11, 10, 887},\n\tdictWord{14, 10, 365},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t375,\n\t},\n\tdictWord{138, 0, 438},\n\tdictWord{136, 10, 821},\n\tdictWord{135, 11, 1908},\n\tdictWord{6, 11, 242},\n\tdictWord{7, 11, 227},\n\tdictWord{7, 11, 1581},\n\tdictWord{8, 11, 104},\n\tdictWord{9, 11, 113},\n\tdictWord{9, 11, 220},\n\tdictWord{9, 11, 427},\n\tdictWord{10, 11, 74},\n\tdictWord{10, 11, 239},\n\tdictWord{11, 11, 579},\n\tdictWord{11, 11, 1023},\n\tdictWord{13, 11, 4},\n\tdictWord{13, 11, 204},\n\tdictWord{13, 11, 316},\n\tdictWord{18, 11, 95},\n\tdictWord{148, 11, 86},\n\tdictWord{4, 0, 69},\n\tdictWord{5, 0, 122},\n\tdictWord{5, 0, 849},\n\tdictWord{6, 0, 1633},\n\tdictWord{9, 0, 656},\n\tdictWord{138, 0, 464},\n\tdictWord{7, 0, 1802},\n\tdictWord{4, 10, 10},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t786,\n\t},\n\tdictWord{135, 11, 861},\n\tdictWord{139, 0, 499},\n\tdictWord{7, 0, 476},\n\tdictWord{7, 0, 1592},\n\tdictWord{138, 0, 87},\n\tdictWord{133, 10, 684},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t840,\n\t},\n\tdictWord{134, 10, 27},\n\tdictWord{142, 0, 283},\n\tdictWord{6, 0, 1620},\n\tdictWord{7, 11, 1328},\n\tdictWord{136, 11, 494},\n\tdictWord{5, 0, 859},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1160,\n\t},\n\tdictWord{8, 0, 107},\n\tdictWord{9, 0, 291},\n\tdictWord{9, 0, 439},\n\tdictWord{10, 0, 663},\n\tdictWord{11, 0, 609},\n\tdictWord{140, 0, 197},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1306,\n\t},\n\tdictWord{8, 11, 505},\n\tdictWord{9, 11, 482},\n\tdictWord{10, 11, 126},\n\tdictWord{11, 11, 225},\n\tdictWord{12, 11, 347},\n\tdictWord{12, 11, 449},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t19,\n\t},\n\tdictWord{142, 11, 218},\n\tdictWord{5, 11, 268},\n\tdictWord{10, 11, 764},\n\tdictWord{12, 11, 120},\n\tdictWord{13, 11, 39},\n\tdictWord{145, 11, 127},\n\tdictWord{145, 10, 56},\n\tdictWord{7, 11, 1672},\n\tdictWord{10, 11, 472},\n\tdictWord{11, 11, 189},\n\tdictWord{143, 11, 51},\n\tdictWord{6, 10, 342},\n\tdictWord{6, 10, 496},\n\tdictWord{8, 10, 275},\n\tdictWord{137, 10, 206},\n\tdictWord{133, 0, 600},\n\tdictWord{4, 0, 117},\n\tdictWord{6, 0, 372},\n\tdictWord{7, 0, 1905},\n\tdictWord{142, 0, 323},\n\tdictWord{4, 10, 909},\n\tdictWord{5, 10, 940},\n\tdictWord{135, 11, 1471},\n\tdictWord{132, 10, 891},\n\tdictWord{4, 0, 722},\n\tdictWord{139, 0, 471},\n\tdictWord{4, 11, 384},\n\tdictWord{135, 11, 1022},\n\tdictWord{132, 10, 687},\n\tdictWord{9, 0, 5},\n\tdictWord{12, 0, 216},\n\tdictWord{12, 0, 294},\n\tdictWord{12, 0, 298},\n\tdictWord{12, 0, 400},\n\tdictWord{12, 0, 518},\n\tdictWord{13, 0, 229},\n\tdictWord{143, 0, 139},\n\tdictWord{135, 11, 1703},\n\tdictWord{7, 11, 1602},\n\tdictWord{10, 11, 698},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t212,\n\t},\n\tdictWord{141, 11, 307},\n\tdictWord{6, 10, 41},\n\tdictWord{141, 10, 160},\n\tdictWord{135, 11, 1077},\n\tdictWord{9, 11, 159},\n\tdictWord{11, 11, 28},\n\tdictWord{140, 11, 603},\n\tdictWord{4, 0, 514},\n\tdictWord{7, 0, 1304},\n\tdictWord{138, 0, 477},\n\tdictWord{134, 0, 1774},\n\tdictWord{9, 0, 88},\n\tdictWord{139, 0, 270},\n\tdictWord{5, 0, 12},\n\tdictWord{7, 0, 375},\n\tdictWord{9, 0, 438},\n\tdictWord{134, 10, 1718},\n\tdictWord{132, 11, 515},\n\tdictWord{136, 10, 778},\n\tdictWord{8, 11, 632},\n\tdictWord{8, 11, 697},\n\tdictWord{137, 11, 854},\n\tdictWord{6, 0, 362},\n\tdictWord{6, 0, 997},\n\tdictWord{146, 0, 51},\n\tdictWord{7, 0, 816},\n\tdictWord{7, 0, 1241},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t283,\n\t},\n\tdictWord{9, 0, 520},\n\tdictWord{10, 0, 213},\n\tdictWord{10, 0, 307},\n\tdictWord{10, 0, 463},\n\tdictWord{10, 0, 671},\n\tdictWord{10, 0, 746},\n\tdictWord{11, 0, 401},\n\tdictWord{11, 0, 794},\n\tdictWord{12, 0, 517},\n\tdictWord{18, 0, 107},\n\tdictWord{147, 0, 115},\n\tdictWord{133, 10, 115},\n\tdictWord{150, 11, 28},\n\tdictWord{4, 11, 136},\n\tdictWord{133, 11, 551},\n\tdictWord{142, 10, 314},\n\tdictWord{132, 0, 258},\n\tdictWord{6, 0, 22},\n\tdictWord{7, 0, 903},\n\tdictWord{7, 0, 1963},\n\tdictWord{8, 0, 639},\n\tdictWord{138, 0, 577},\n\tdictWord{5, 0, 681},\n\tdictWord{8, 0, 782},\n\tdictWord{13, 0, 130},\n\tdictWord{17, 0, 84},\n\tdictWord{5, 10, 193},\n\tdictWord{140, 10, 178},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t17,\n\t},\n\tdictWord{138, 11, 291},\n\tdictWord{7, 11, 1287},\n\tdictWord{9, 11, 44},\n\tdictWord{10, 11, 552},\n\tdictWord{10, 11, 642},\n\tdictWord{11, 11, 839},\n\tdictWord{12, 11, 274},\n\tdictWord{12, 11, 275},\n\tdictWord{12, 11, 372},\n\tdictWord{13, 11, 91},\n\tdictWord{142, 11, 125},\n\tdictWord{135, 10, 174},\n\tdictWord{4, 0, 664},\n\tdictWord{5, 0, 804},\n\tdictWord{139, 0, 1013},\n\tdictWord{134, 0, 942},\n\tdictWord{6, 0, 1349},\n\tdictWord{6, 0, 1353},\n\tdictWord{6, 0, 1450},\n\tdictWord{7, 11, 1518},\n\tdictWord{139, 11, 694},\n\tdictWord{11, 0, 356},\n\tdictWord{4, 10, 122},\n\tdictWord{5, 10, 796},\n\tdictWord{5, 10, 952},\n\tdictWord{6, 10, 1660},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1671,\n\t},\n\tdictWord{8, 10, 567},\n\tdictWord{9, 10, 687},\n\tdictWord{9, 10, 742},\n\tdictWord{10, 10, 686},\n\tdictWord{11, 10, 682},\n\tdictWord{140, 10, 281},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t32,\n\t},\n\tdictWord{6, 11, 147},\n\tdictWord{7, 11, 886},\n\tdictWord{9, 11, 753},\n\tdictWord{138, 11, 268},\n\tdictWord{5, 10, 179},\n\tdictWord{7, 10, 1095},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1213,\n\t},\n\tdictWord{4, 10, 66},\n\tdictWord{7, 10, 722},\n\tdictWord{135, 10, 904},\n\tdictWord{135, 10, 352},\n\tdictWord{9, 11, 245},\n\tdictWord{138, 11, 137},\n\tdictWord{4, 0, 289},\n\tdictWord{7, 0, 629},\n\tdictWord{7, 0, 1698},\n\tdictWord{7, 0, 1711},\n\tdictWord{12, 0, 215},\n\tdictWord{133, 11, 414},\n\tdictWord{6, 0, 1975},\n\tdictWord{135, 11, 1762},\n\tdictWord{6, 0, 450},\n\tdictWord{136, 0, 109},\n\tdictWord{141, 10, 35},\n\tdictWord{134, 11, 599},\n\tdictWord{136, 0, 705},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t664,\n\t},\n\tdictWord{134, 11, 1749},\n\tdictWord{11, 11, 402},\n\tdictWord{12, 11, 109},\n\tdictWord{12, 11, 431},\n\tdictWord{13, 11, 179},\n\tdictWord{13, 11, 206},\n\tdictWord{14, 11, 175},\n\tdictWord{14, 11, 217},\n\tdictWord{16, 11, 3},\n\tdictWord{148, 11, 53},\n\tdictWord{135, 0, 1238},\n\tdictWord{134, 11, 1627},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t488,\n\t},\n\tdictWord{13, 0, 318},\n\tdictWord{10, 10, 592},\n\tdictWord{10, 10, 753},\n\tdictWord{12, 10, 317},\n\tdictWord{12, 10, 355},\n\tdictWord{12, 10, 465},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t469,\n\t},\n\tdictWord{12, 10, 560},\n\tdictWord{140, 10, 578},\n\tdictWord{133, 10, 564},\n\tdictWord{132, 11, 83},\n\tdictWord{140, 11, 676},\n\tdictWord{6, 0, 1872},\n\tdictWord{6, 0, 1906},\n\tdictWord{6, 0, 1907},\n\tdictWord{9, 0, 934},\n\tdictWord{9, 0, 956},\n\tdictWord{9, 0, 960},\n\tdictWord{9, 0, 996},\n\tdictWord{12, 0, 794},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t876,\n\t},\n\tdictWord{12, 0, 880},\n\tdictWord{12, 0, 918},\n\tdictWord{15, 0, 230},\n\tdictWord{18, 0, 234},\n\tdictWord{18, 0, 238},\n\tdictWord{21, 0, 38},\n\tdictWord{149, 0, 62},\n\tdictWord{134, 10, 556},\n\tdictWord{134, 11, 278},\n\tdictWord{137, 0, 103},\n\tdictWord{7, 10, 544},\n\tdictWord{8, 10, 719},\n\tdictWord{138, 10, 61},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t5,\n\t},\n\tdictWord{5, 10, 498},\n\tdictWord{8, 10, 637},\n\tdictWord{137, 10, 521},\n\tdictWord{7, 0, 777},\n\tdictWord{12, 0, 229},\n\tdictWord{12, 0, 239},\n\tdictWord{15, 0, 12},\n\tdictWord{12, 11, 229},\n\tdictWord{12, 11, 239},\n\tdictWord{143, 11, 12},\n\tdictWord{6, 0, 26},\n\tdictWord{7, 11, 388},\n\tdictWord{7, 11, 644},\n\tdictWord{139, 11, 781},\n\tdictWord{7, 11, 229},\n\tdictWord{8, 11, 59},\n\tdictWord{9, 11, 190},\n\tdictWord{9, 11, 257},\n\tdictWord{10, 11, 378},\n\tdictWord{140, 11, 191},\n\tdictWord{133, 10, 927},\n\tdictWord{135, 10, 1441},\n\tdictWord{4, 10, 893},\n\tdictWord{5, 10, 780},\n\tdictWord{133, 10, 893},\n\tdictWord{4, 0, 414},\n\tdictWord{5, 0, 467},\n\tdictWord{9, 0, 654},\n\tdictWord{10, 0, 451},\n\tdictWord{12, 0, 59},\n\tdictWord{141, 0, 375},\n\tdictWord{142, 0, 173},\n\tdictWord{135, 0, 17},\n\tdictWord{7, 0, 1350},\n\tdictWord{133, 10, 238},\n\tdictWord{135, 0, 955},\n\tdictWord{4, 0, 960},\n\tdictWord{10, 0, 887},\n\tdictWord{12, 0, 753},\n\tdictWord{18, 0, 161},\n\tdictWord{18, 0, 162},\n\tdictWord{152, 0, 19},\n\tdictWord{136, 11, 344},\n\tdictWord{6, 10, 1729},\n\tdictWord{137, 11, 288},\n\tdictWord{132, 11, 660},\n\tdictWord{4, 0, 217},\n\tdictWord{5, 0, 710},\n\tdictWord{7, 0, 760},\n\tdictWord{7, 0, 1926},\n\tdictWord{9, 0, 428},\n\tdictWord{9, 0, 708},\n\tdictWord{10, 0, 254},\n\tdictWord{10, 0, 296},\n\tdictWord{10, 0, 720},\n\tdictWord{11, 0, 109},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t255,\n\t},\n\tdictWord{12, 0, 165},\n\tdictWord{12, 0, 315},\n\tdictWord{13, 0, 107},\n\tdictWord{13, 0, 203},\n\tdictWord{14, 0, 54},\n\tdictWord{14, 0, 99},\n\tdictWord{14, 0, 114},\n\tdictWord{14, 0, 388},\n\tdictWord{16, 0, 85},\n\tdictWord{17, 0, 9},\n\tdictWord{17, 0, 33},\n\tdictWord{20, 0, 25},\n\tdictWord{20, 0, 28},\n\tdictWord{20, 0, 29},\n\tdictWord{21, 0, 9},\n\tdictWord{21, 0, 10},\n\tdictWord{21, 0, 34},\n\tdictWord{22, 0, 17},\n\tdictWord{4, 10, 60},\n\tdictWord{7, 10, 1800},\n\tdictWord{8, 10, 314},\n\tdictWord{9, 10, 700},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t487,\n\t},\n\tdictWord{7, 11, 1035},\n\tdictWord{138, 11, 737},\n\tdictWord{7, 11, 690},\n\tdictWord{9, 11, 217},\n\tdictWord{9, 11, 587},\n\tdictWord{140, 11, 521},\n\tdictWord{6, 0, 919},\n\tdictWord{7, 11, 706},\n\tdictWord{7, 11, 1058},\n\tdictWord{138, 11, 538},\n\tdictWord{7, 10, 1853},\n\tdictWord{138, 10, 437},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t419,\n\t},\n\tdictWord{6, 0, 280},\n\tdictWord{10, 0, 502},\n\tdictWord{11, 0, 344},\n\tdictWord{140, 0, 38},\n\tdictWord{5, 0, 45},\n\tdictWord{7, 0, 1161},\n\tdictWord{11, 0, 448},\n\tdictWord{11, 0, 880},\n\tdictWord{13, 0, 139},\n\tdictWord{13, 0, 407},\n\tdictWord{15, 0, 16},\n\tdictWord{17, 0, 95},\n\tdictWord{18, 0, 66},\n\tdictWord{18, 0, 88},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t123,\n\t},\n\tdictWord{149, 0, 7},\n\tdictWord{11, 11, 92},\n\tdictWord{11, 11, 196},\n\tdictWord{11, 11, 409},\n\tdictWord{11, 11, 450},\n\tdictWord{11, 11, 666},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t777,\n\t},\n\tdictWord{12, 11, 262},\n\tdictWord{13, 11, 385},\n\tdictWord{13, 11, 393},\n\tdictWord{15, 11, 115},\n\tdictWord{16, 11, 45},\n\tdictWord{145, 11, 82},\n\tdictWord{136, 0, 777},\n\tdictWord{134, 11, 1744},\n\tdictWord{4, 0, 410},\n\tdictWord{7, 0, 521},\n\tdictWord{133, 10, 828},\n\tdictWord{134, 0, 673},\n\tdictWord{7, 0, 1110},\n\tdictWord{7, 0, 1778},\n\tdictWord{7, 10, 176},\n\tdictWord{135, 10, 178},\n\tdictWord{5, 10, 806},\n\tdictWord{7, 11, 268},\n\tdictWord{7, 10, 1976},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t569,\n\t},\n\tdictWord{4, 11, 733},\n\tdictWord{9, 11, 194},\n\tdictWord{10, 11, 92},\n\tdictWord{11, 11, 198},\n\tdictWord{12, 11, 84},\n\tdictWord{12, 11, 87},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t128,\n\t},\n\tdictWord{144, 11, 74},\n\tdictWord{5, 0, 341},\n\tdictWord{7, 0, 1129},\n\tdictWord{11, 0, 414},\n\tdictWord{4, 10, 51},\n\tdictWord{6, 10, 4},\n\tdictWord{7, 10, 591},\n\tdictWord{7, 10, 849},\n\tdictWord{7, 10, 951},\n\tdictWord{7, 10, 1613},\n\tdictWord{7, 10, 1760},\n\tdictWord{7, 10, 1988},\n\tdictWord{9, 10, 434},\n\tdictWord{10, 10, 754},\n\tdictWord{11, 10, 25},\n\tdictWord{139, 10, 37},\n\tdictWord{133, 10, 902},\n\tdictWord{135, 10, 928},\n\tdictWord{135, 0, 787},\n\tdictWord{132, 0, 436},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t270,\n\t},\n\tdictWord{7, 0, 1587},\n\tdictWord{135, 0, 1707},\n\tdictWord{6, 0, 377},\n\tdictWord{7, 0, 1025},\n\tdictWord{9, 0, 613},\n\tdictWord{145, 0, 104},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t982,\n\t},\n\tdictWord{7, 11, 1361},\n\tdictWord{10, 11, 32},\n\tdictWord{143, 11, 56},\n\tdictWord{139, 0, 96},\n\tdictWord{132, 0, 451},\n\tdictWord{132, 10, 416},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t372,\n\t},\n\tdictWord{5, 10, 152},\n\tdictWord{5, 10, 197},\n\tdictWord{7, 11, 306},\n\tdictWord{7, 10, 340},\n\tdictWord{7, 10, 867},\n\tdictWord{10, 10, 548},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t581,\n\t},\n\tdictWord{11, 10, 6},\n\tdictWord{12, 10, 3},\n\tdictWord{12, 10, 19},\n\tdictWord{14, 10, 110},\n\tdictWord{142, 10, 289},\n\tdictWord{134, 0, 680},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t609,\n\t},\n\tdictWord{7, 0, 483},\n\tdictWord{7, 10, 190},\n\tdictWord{8, 10, 28},\n\tdictWord{8, 10, 141},\n\tdictWord{8, 10, 444},\n\tdictWord{8, 10, 811},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t468,\n\t},\n\tdictWord{11, 10, 334},\n\tdictWord{12, 10, 24},\n\tdictWord{12, 10, 386},\n\tdictWord{140, 10, 576},\n\tdictWord{10, 0, 916},\n\tdictWord{133, 10, 757},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t721,\n\t},\n\tdictWord{135, 10, 1553},\n\tdictWord{133, 11, 178},\n\tdictWord{134, 0, 937},\n\tdictWord{132, 10, 898},\n\tdictWord{133, 0, 739},\n\tdictWord{\n\t\t147,\n\t\t0,\n\t\t82,\n\t},\n\tdictWord{135, 0, 663},\n\tdictWord{146, 0, 128},\n\tdictWord{5, 10, 277},\n\tdictWord{141, 10, 247},\n\tdictWord{134, 0, 1087},\n\tdictWord{132, 10, 435},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t381,\n\t},\n\tdictWord{7, 11, 645},\n\tdictWord{7, 11, 694},\n\tdictWord{136, 11, 546},\n\tdictWord{7, 0, 503},\n\tdictWord{135, 0, 1885},\n\tdictWord{6, 0, 1965},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t925,\n\t},\n\tdictWord{138, 0, 955},\n\tdictWord{4, 0, 113},\n\tdictWord{5, 0, 163},\n\tdictWord{5, 0, 735},\n\tdictWord{7, 0, 1009},\n\tdictWord{9, 0, 9},\n\tdictWord{9, 0, 771},\n\tdictWord{12, 0, 90},\n\tdictWord{13, 0, 138},\n\tdictWord{13, 0, 410},\n\tdictWord{143, 0, 128},\n\tdictWord{4, 0, 324},\n\tdictWord{138, 0, 104},\n\tdictWord{7, 0, 460},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t265,\n\t},\n\tdictWord{134, 10, 212},\n\tdictWord{133, 11, 105},\n\tdictWord{7, 11, 261},\n\tdictWord{7, 11, 1107},\n\tdictWord{7, 11, 1115},\n\tdictWord{7, 11, 1354},\n\tdictWord{7, 11, 1588},\n\tdictWord{7, 11, 1705},\n\tdictWord{7, 11, 1902},\n\tdictWord{9, 11, 465},\n\tdictWord{10, 11, 248},\n\tdictWord{10, 11, 349},\n\tdictWord{10, 11, 647},\n\tdictWord{11, 11, 527},\n\tdictWord{11, 11, 660},\n\tdictWord{11, 11, 669},\n\tdictWord{12, 11, 529},\n\tdictWord{141, 11, 305},\n\tdictWord{5, 11, 438},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t694,\n\t},\n\tdictWord{12, 11, 627},\n\tdictWord{141, 11, 210},\n\tdictWord{152, 11, 11},\n\tdictWord{4, 0, 935},\n\tdictWord{133, 0, 823},\n\tdictWord{132, 10, 702},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t269,\n\t},\n\tdictWord{7, 0, 434},\n\tdictWord{7, 0, 891},\n\tdictWord{8, 0, 339},\n\tdictWord{9, 0, 702},\n\tdictWord{11, 0, 594},\n\tdictWord{11, 0, 718},\n\tdictWord{17, 0, 100},\n\tdictWord{5, 10, 808},\n\tdictWord{135, 10, 2045},\n\tdictWord{7, 0, 1014},\n\tdictWord{9, 0, 485},\n\tdictWord{141, 0, 264},\n\tdictWord{134, 0, 1713},\n\tdictWord{7, 0, 1810},\n\tdictWord{11, 0, 866},\n\tdictWord{12, 0, 103},\n\tdictWord{13, 0, 495},\n\tdictWord{140, 11, 233},\n\tdictWord{4, 0, 423},\n\tdictWord{10, 0, 949},\n\tdictWord{138, 0, 1013},\n\tdictWord{135, 0, 900},\n\tdictWord{8, 11, 25},\n\tdictWord{138, 11, 826},\n\tdictWord{5, 10, 166},\n\tdictWord{8, 10, 739},\n\tdictWord{140, 10, 511},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t2018,\n\t},\n\tdictWord{7, 11, 1270},\n\tdictWord{139, 11, 612},\n\tdictWord{4, 10, 119},\n\tdictWord{5, 10, 170},\n\tdictWord{5, 10, 447},\n\tdictWord{7, 10, 1708},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1889,\n\t},\n\tdictWord{9, 10, 357},\n\tdictWord{9, 10, 719},\n\tdictWord{12, 10, 486},\n\tdictWord{140, 10, 596},\n\tdictWord{12, 0, 574},\n\tdictWord{140, 11, 574},\n\tdictWord{132, 11, 308},\n\tdictWord{6, 0, 964},\n\tdictWord{6, 0, 1206},\n\tdictWord{134, 0, 1302},\n\tdictWord{4, 10, 450},\n\tdictWord{135, 10, 1158},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t150,\n\t},\n\tdictWord{136, 11, 649},\n\tdictWord{14, 0, 213},\n\tdictWord{148, 0, 38},\n\tdictWord{9, 11, 45},\n\tdictWord{9, 11, 311},\n\tdictWord{141, 11, 42},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t521,\n\t},\n\tdictWord{7, 10, 1375},\n\tdictWord{7, 10, 1466},\n\tdictWord{138, 10, 331},\n\tdictWord{132, 10, 754},\n\tdictWord{5, 11, 339},\n\tdictWord{7, 11, 1442},\n\tdictWord{14, 11, 3},\n\tdictWord{15, 11, 41},\n\tdictWord{147, 11, 66},\n\tdictWord{136, 11, 378},\n\tdictWord{134, 0, 1022},\n\tdictWord{5, 10, 850},\n\tdictWord{136, 10, 799},\n\tdictWord{142, 0, 143},\n\tdictWord{135, 0, 2029},\n\tdictWord{134, 11, 1628},\n\tdictWord{8, 0, 523},\n\tdictWord{150, 0, 34},\n\tdictWord{5, 0, 625},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1617,\n\t},\n\tdictWord{7, 0, 275},\n\tdictWord{7, 10, 238},\n\tdictWord{7, 10, 2033},\n\tdictWord{8, 10, 120},\n\tdictWord{8, 10, 188},\n\tdictWord{8, 10, 659},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t598,\n\t},\n\tdictWord{10, 10, 466},\n\tdictWord{12, 10, 342},\n\tdictWord{12, 10, 588},\n\tdictWord{13, 10, 503},\n\tdictWord{14, 10, 246},\n\tdictWord{143, 10, 92},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t37,\n\t},\n\tdictWord{8, 0, 425},\n\tdictWord{8, 0, 693},\n\tdictWord{9, 0, 720},\n\tdictWord{10, 0, 380},\n\tdictWord{10, 0, 638},\n\tdictWord{11, 0, 273},\n\tdictWord{11, 0, 473},\n\tdictWord{12, 0, 61},\n\tdictWord{143, 0, 43},\n\tdictWord{135, 11, 829},\n\tdictWord{135, 0, 1943},\n\tdictWord{132, 0, 765},\n\tdictWord{5, 11, 486},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1349,\n\t},\n\tdictWord{7, 11, 1635},\n\tdictWord{8, 11, 17},\n\tdictWord{10, 11, 217},\n\tdictWord{138, 11, 295},\n\tdictWord{4, 10, 201},\n\tdictWord{7, 10, 1744},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t602,\n\t},\n\tdictWord{11, 10, 247},\n\tdictWord{11, 10, 826},\n\tdictWord{145, 10, 65},\n\tdictWord{138, 11, 558},\n\tdictWord{11, 0, 551},\n\tdictWord{142, 0, 159},\n\tdictWord{8, 10, 164},\n\tdictWord{146, 10, 62},\n\tdictWord{139, 11, 176},\n\tdictWord{132, 0, 168},\n\tdictWord{136, 0, 1010},\n\tdictWord{134, 0, 1994},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t91,\n\t},\n\tdictWord{138, 0, 532},\n\tdictWord{135, 10, 1243},\n\tdictWord{135, 0, 1884},\n\tdictWord{132, 10, 907},\n\tdictWord{5, 10, 100},\n\tdictWord{10, 10, 329},\n\tdictWord{12, 10, 416},\n\tdictWord{149, 10, 29},\n\tdictWord{134, 11, 447},\n\tdictWord{132, 10, 176},\n\tdictWord{5, 10, 636},\n\tdictWord{5, 10, 998},\n\tdictWord{7, 10, 9},\n\tdictWord{7, 10, 1508},\n\tdictWord{8, 10, 26},\n\tdictWord{9, 10, 317},\n\tdictWord{9, 10, 358},\n\tdictWord{10, 10, 210},\n\tdictWord{10, 10, 292},\n\tdictWord{10, 10, 533},\n\tdictWord{11, 10, 555},\n\tdictWord{12, 10, 526},\n\tdictWord{12, 10, 607},\n\tdictWord{13, 10, 263},\n\tdictWord{13, 10, 459},\n\tdictWord{142, 10, 271},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t609,\n\t},\n\tdictWord{135, 11, 756},\n\tdictWord{6, 0, 15},\n\tdictWord{7, 0, 70},\n\tdictWord{10, 0, 240},\n\tdictWord{147, 0, 93},\n\tdictWord{4, 11, 930},\n\tdictWord{133, 11, 947},\n\tdictWord{134, 0, 1227},\n\tdictWord{134, 0, 1534},\n\tdictWord{133, 11, 939},\n\tdictWord{133, 11, 962},\n\tdictWord{5, 11, 651},\n\tdictWord{8, 11, 170},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t61,\n\t},\n\tdictWord{9, 11, 63},\n\tdictWord{10, 11, 23},\n\tdictWord{10, 11, 37},\n\tdictWord{10, 11, 834},\n\tdictWord{11, 11, 4},\n\tdictWord{11, 11, 187},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t281,\n\t},\n\tdictWord{11, 11, 503},\n\tdictWord{11, 11, 677},\n\tdictWord{12, 11, 96},\n\tdictWord{12, 11, 130},\n\tdictWord{12, 11, 244},\n\tdictWord{14, 11, 5},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t40,\n\t},\n\tdictWord{14, 11, 162},\n\tdictWord{14, 11, 202},\n\tdictWord{146, 11, 133},\n\tdictWord{4, 11, 406},\n\tdictWord{5, 11, 579},\n\tdictWord{12, 11, 492},\n\tdictWord{\n\t\t150,\n\t\t11,\n\t\t15,\n\t},\n\tdictWord{139, 0, 392},\n\tdictWord{6, 10, 610},\n\tdictWord{10, 10, 127},\n\tdictWord{141, 10, 27},\n\tdictWord{7, 0, 655},\n\tdictWord{7, 0, 1844},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t119,\n\t},\n\tdictWord{4, 0, 145},\n\tdictWord{6, 0, 176},\n\tdictWord{7, 0, 395},\n\tdictWord{137, 0, 562},\n\tdictWord{132, 0, 501},\n\tdictWord{140, 11, 145},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t1019,\n\t},\n\tdictWord{134, 0, 509},\n\tdictWord{139, 0, 267},\n\tdictWord{6, 11, 17},\n\tdictWord{7, 11, 16},\n\tdictWord{7, 11, 1001},\n\tdictWord{7, 11, 1982},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t886,\n\t},\n\tdictWord{10, 11, 489},\n\tdictWord{10, 11, 800},\n\tdictWord{11, 11, 782},\n\tdictWord{12, 11, 320},\n\tdictWord{13, 11, 467},\n\tdictWord{14, 11, 145},\n\tdictWord{14, 11, 387},\n\tdictWord{143, 11, 119},\n\tdictWord{145, 11, 17},\n\tdictWord{6, 0, 1099},\n\tdictWord{133, 11, 458},\n\tdictWord{7, 11, 1983},\n\tdictWord{8, 11, 0},\n\tdictWord{8, 11, 171},\n\tdictWord{9, 11, 120},\n\tdictWord{9, 11, 732},\n\tdictWord{10, 11, 473},\n\tdictWord{11, 11, 656},\n\tdictWord{11, 11, 998},\n\tdictWord{18, 11, 0},\n\tdictWord{18, 11, 2},\n\tdictWord{147, 11, 21},\n\tdictWord{12, 11, 427},\n\tdictWord{146, 11, 38},\n\tdictWord{10, 0, 948},\n\tdictWord{138, 0, 968},\n\tdictWord{7, 10, 126},\n\tdictWord{136, 10, 84},\n\tdictWord{136, 10, 790},\n\tdictWord{4, 0, 114},\n\tdictWord{9, 0, 492},\n\tdictWord{13, 0, 462},\n\tdictWord{142, 0, 215},\n\tdictWord{6, 10, 64},\n\tdictWord{12, 10, 377},\n\tdictWord{141, 10, 309},\n\tdictWord{4, 0, 77},\n\tdictWord{5, 0, 361},\n\tdictWord{6, 0, 139},\n\tdictWord{6, 0, 401},\n\tdictWord{6, 0, 404},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t413,\n\t},\n\tdictWord{7, 0, 715},\n\tdictWord{7, 0, 1716},\n\tdictWord{11, 0, 279},\n\tdictWord{12, 0, 179},\n\tdictWord{12, 0, 258},\n\tdictWord{13, 0, 244},\n\tdictWord{142, 0, 358},\n\tdictWord{134, 0, 1717},\n\tdictWord{7, 0, 772},\n\tdictWord{7, 0, 1061},\n\tdictWord{7, 0, 1647},\n\tdictWord{8, 0, 82},\n\tdictWord{11, 0, 250},\n\tdictWord{11, 0, 607},\n\tdictWord{12, 0, 311},\n\tdictWord{12, 0, 420},\n\tdictWord{13, 0, 184},\n\tdictWord{13, 0, 367},\n\tdictWord{7, 10, 1104},\n\tdictWord{11, 10, 269},\n\tdictWord{11, 10, 539},\n\tdictWord{11, 10, 627},\n\tdictWord{11, 10, 706},\n\tdictWord{11, 10, 975},\n\tdictWord{12, 10, 248},\n\tdictWord{12, 10, 434},\n\tdictWord{12, 10, 600},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t622,\n\t},\n\tdictWord{13, 10, 297},\n\tdictWord{13, 10, 485},\n\tdictWord{14, 10, 69},\n\tdictWord{14, 10, 409},\n\tdictWord{143, 10, 108},\n\tdictWord{135, 0, 724},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t512,\n\t},\n\tdictWord{4, 11, 519},\n\tdictWord{133, 11, 342},\n\tdictWord{134, 0, 1133},\n\tdictWord{145, 11, 29},\n\tdictWord{11, 10, 977},\n\tdictWord{141, 10, 507},\n\tdictWord{6, 0, 841},\n\tdictWord{6, 0, 1042},\n\tdictWord{6, 0, 1194},\n\tdictWord{10, 0, 993},\n\tdictWord{140, 0, 1021},\n\tdictWord{6, 11, 31},\n\tdictWord{7, 11, 491},\n\tdictWord{7, 11, 530},\n\tdictWord{8, 11, 592},\n\tdictWord{9, 10, 34},\n\tdictWord{11, 11, 53},\n\tdictWord{11, 10, 484},\n\tdictWord{11, 11, 779},\n\tdictWord{12, 11, 167},\n\tdictWord{12, 11, 411},\n\tdictWord{14, 11, 14},\n\tdictWord{14, 11, 136},\n\tdictWord{15, 11, 72},\n\tdictWord{16, 11, 17},\n\tdictWord{144, 11, 72},\n\tdictWord{4, 0, 1021},\n\tdictWord{6, 0, 2037},\n\tdictWord{133, 11, 907},\n\tdictWord{7, 0, 373},\n\tdictWord{8, 0, 335},\n\tdictWord{8, 0, 596},\n\tdictWord{9, 0, 488},\n\tdictWord{6, 10, 1700},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t293,\n\t},\n\tdictWord{7, 10, 382},\n\tdictWord{7, 10, 1026},\n\tdictWord{7, 10, 1087},\n\tdictWord{7, 10, 2027},\n\tdictWord{8, 10, 252},\n\tdictWord{8, 10, 727},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t729,\n\t},\n\tdictWord{9, 10, 30},\n\tdictWord{9, 10, 199},\n\tdictWord{9, 10, 231},\n\tdictWord{9, 10, 251},\n\tdictWord{9, 10, 334},\n\tdictWord{9, 10, 361},\n\tdictWord{9, 10, 712},\n\tdictWord{10, 10, 55},\n\tdictWord{10, 10, 60},\n\tdictWord{10, 10, 232},\n\tdictWord{10, 10, 332},\n\tdictWord{10, 10, 384},\n\tdictWord{10, 10, 396},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t504,\n\t},\n\tdictWord{10, 10, 542},\n\tdictWord{10, 10, 652},\n\tdictWord{11, 10, 20},\n\tdictWord{11, 10, 48},\n\tdictWord{11, 10, 207},\n\tdictWord{11, 10, 291},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t298,\n\t},\n\tdictWord{11, 10, 342},\n\tdictWord{11, 10, 365},\n\tdictWord{11, 10, 394},\n\tdictWord{11, 10, 620},\n\tdictWord{11, 10, 705},\n\tdictWord{11, 10, 1017},\n\tdictWord{12, 10, 123},\n\tdictWord{12, 10, 340},\n\tdictWord{12, 10, 406},\n\tdictWord{12, 10, 643},\n\tdictWord{13, 10, 61},\n\tdictWord{13, 10, 269},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t311,\n\t},\n\tdictWord{13, 10, 319},\n\tdictWord{13, 10, 486},\n\tdictWord{14, 10, 234},\n\tdictWord{15, 10, 62},\n\tdictWord{15, 10, 85},\n\tdictWord{16, 10, 71},\n\tdictWord{\n\t\t18,\n\t\t10,\n\t\t119,\n\t},\n\tdictWord{148, 10, 105},\n\tdictWord{150, 0, 37},\n\tdictWord{4, 11, 208},\n\tdictWord{5, 11, 106},\n\tdictWord{6, 11, 531},\n\tdictWord{8, 11, 408},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t188,\n\t},\n\tdictWord{138, 11, 572},\n\tdictWord{132, 0, 564},\n\tdictWord{6, 0, 513},\n\tdictWord{135, 0, 1052},\n\tdictWord{132, 0, 825},\n\tdictWord{9, 0, 899},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t441,\n\t},\n\tdictWord{134, 0, 778},\n\tdictWord{133, 11, 379},\n\tdictWord{7, 0, 1417},\n\tdictWord{12, 0, 382},\n\tdictWord{17, 0, 48},\n\tdictWord{152, 0, 12},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t241,\n\t},\n\tdictWord{7, 0, 1116},\n\tdictWord{6, 10, 379},\n\tdictWord{7, 10, 270},\n\tdictWord{8, 10, 176},\n\tdictWord{8, 10, 183},\n\tdictWord{9, 10, 432},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t661,\n\t},\n\tdictWord{12, 10, 247},\n\tdictWord{12, 10, 617},\n\tdictWord{146, 10, 125},\n\tdictWord{5, 10, 792},\n\tdictWord{133, 10, 900},\n\tdictWord{6, 0, 545},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t565,\n\t},\n\tdictWord{7, 0, 1669},\n\tdictWord{10, 0, 114},\n\tdictWord{11, 0, 642},\n\tdictWord{140, 0, 618},\n\tdictWord{133, 0, 5},\n\tdictWord{138, 11, 7},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t259,\n\t},\n\tdictWord{135, 0, 192},\n\tdictWord{134, 0, 701},\n\tdictWord{136, 0, 763},\n\tdictWord{135, 10, 1979},\n\tdictWord{4, 10, 901},\n\tdictWord{133, 10, 776},\n\tdictWord{10, 0, 755},\n\tdictWord{147, 0, 29},\n\tdictWord{133, 0, 759},\n\tdictWord{4, 11, 173},\n\tdictWord{5, 11, 312},\n\tdictWord{5, 11, 512},\n\tdictWord{135, 11, 1285},\n\tdictWord{7, 11, 1603},\n\tdictWord{7, 11, 1691},\n\tdictWord{9, 11, 464},\n\tdictWord{11, 11, 195},\n\tdictWord{12, 11, 279},\n\tdictWord{12, 11, 448},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t11,\n\t},\n\tdictWord{147, 11, 102},\n\tdictWord{7, 0, 370},\n\tdictWord{7, 0, 1007},\n\tdictWord{7, 0, 1177},\n\tdictWord{135, 0, 1565},\n\tdictWord{135, 0, 1237},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t87,\n\t},\n\tdictWord{5, 0, 250},\n\tdictWord{141, 0, 298},\n\tdictWord{4, 11, 452},\n\tdictWord{5, 11, 583},\n\tdictWord{5, 11, 817},\n\tdictWord{6, 11, 433},\n\tdictWord{7, 11, 593},\n\tdictWord{7, 11, 720},\n\tdictWord{7, 11, 1378},\n\tdictWord{8, 11, 161},\n\tdictWord{9, 11, 284},\n\tdictWord{10, 11, 313},\n\tdictWord{139, 11, 886},\n\tdictWord{4, 11, 547},\n\tdictWord{135, 11, 1409},\n\tdictWord{136, 11, 722},\n\tdictWord{4, 10, 37},\n\tdictWord{5, 10, 334},\n\tdictWord{135, 10, 1253},\n\tdictWord{132, 10, 508},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t107,\n\t},\n\tdictWord{146, 0, 31},\n\tdictWord{8, 11, 420},\n\tdictWord{139, 11, 193},\n\tdictWord{135, 0, 814},\n\tdictWord{135, 11, 409},\n\tdictWord{140, 0, 991},\n\tdictWord{4, 0, 57},\n\tdictWord{7, 0, 1195},\n\tdictWord{7, 0, 1438},\n\tdictWord{7, 0, 1548},\n\tdictWord{7, 0, 1835},\n\tdictWord{7, 0, 1904},\n\tdictWord{9, 0, 757},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t604,\n\t},\n\tdictWord{139, 0, 519},\n\tdictWord{132, 0, 540},\n\tdictWord{138, 11, 308},\n\tdictWord{132, 10, 533},\n\tdictWord{136, 0, 608},\n\tdictWord{144, 11, 65},\n\tdictWord{4, 0, 1014},\n\tdictWord{134, 0, 2029},\n\tdictWord{4, 0, 209},\n\tdictWord{7, 0, 902},\n\tdictWord{5, 11, 1002},\n\tdictWord{136, 11, 745},\n\tdictWord{134, 0, 2030},\n\tdictWord{6, 0, 303},\n\tdictWord{7, 0, 335},\n\tdictWord{7, 0, 1437},\n\tdictWord{7, 0, 1668},\n\tdictWord{8, 0, 553},\n\tdictWord{8, 0, 652},\n\tdictWord{8, 0, 656},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t558,\n\t},\n\tdictWord{11, 0, 743},\n\tdictWord{149, 0, 18},\n\tdictWord{5, 11, 575},\n\tdictWord{6, 11, 354},\n\tdictWord{135, 11, 701},\n\tdictWord{4, 11, 239},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t477,\n\t},\n\tdictWord{7, 11, 1607},\n\tdictWord{11, 11, 68},\n\tdictWord{139, 11, 617},\n\tdictWord{132, 0, 559},\n\tdictWord{8, 0, 527},\n\tdictWord{18, 0, 60},\n\tdictWord{\n\t\t147,\n\t\t0,\n\t\t24,\n\t},\n\tdictWord{133, 10, 920},\n\tdictWord{138, 0, 511},\n\tdictWord{133, 0, 1017},\n\tdictWord{133, 0, 675},\n\tdictWord{138, 10, 391},\n\tdictWord{11, 0, 156},\n\tdictWord{135, 10, 1952},\n\tdictWord{138, 11, 369},\n\tdictWord{132, 11, 367},\n\tdictWord{133, 0, 709},\n\tdictWord{6, 0, 698},\n\tdictWord{134, 0, 887},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t126,\n\t},\n\tdictWord{134, 0, 1745},\n\tdictWord{132, 10, 483},\n\tdictWord{13, 11, 299},\n\tdictWord{142, 11, 75},\n\tdictWord{133, 0, 714},\n\tdictWord{7, 0, 8},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t206,\n\t},\n\tdictWord{138, 10, 480},\n\tdictWord{4, 11, 694},\n\tdictWord{9, 10, 495},\n\tdictWord{146, 10, 104},\n\tdictWord{7, 11, 1248},\n\tdictWord{11, 11, 621},\n\tdictWord{139, 11, 702},\n\tdictWord{140, 11, 687},\n\tdictWord{132, 0, 776},\n\tdictWord{139, 10, 1009},\n\tdictWord{135, 0, 1272},\n\tdictWord{134, 0, 1059},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t653,\n\t},\n\tdictWord{13, 10, 93},\n\tdictWord{147, 10, 14},\n\tdictWord{135, 11, 213},\n\tdictWord{136, 0, 406},\n\tdictWord{133, 10, 172},\n\tdictWord{132, 0, 947},\n\tdictWord{8, 0, 175},\n\tdictWord{10, 0, 168},\n\tdictWord{138, 0, 573},\n\tdictWord{132, 0, 870},\n\tdictWord{6, 0, 1567},\n\tdictWord{151, 11, 28},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t472,\n\t},\n\tdictWord{5, 10, 260},\n\tdictWord{136, 11, 132},\n\tdictWord{4, 11, 751},\n\tdictWord{11, 11, 390},\n\tdictWord{140, 11, 32},\n\tdictWord{4, 11, 409},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t78,\n\t},\n\tdictWord{12, 0, 554},\n\tdictWord{6, 11, 473},\n\tdictWord{145, 11, 105},\n\tdictWord{133, 0, 784},\n\tdictWord{8, 0, 908},\n\tdictWord{136, 11, 306},\n\tdictWord{139, 0, 882},\n\tdictWord{6, 0, 358},\n\tdictWord{7, 0, 1393},\n\tdictWord{8, 0, 396},\n\tdictWord{10, 0, 263},\n\tdictWord{14, 0, 154},\n\tdictWord{16, 0, 48},\n\tdictWord{\n\t\t17,\n\t\t0,\n\t\t8,\n\t},\n\tdictWord{7, 11, 1759},\n\tdictWord{8, 11, 396},\n\tdictWord{10, 11, 263},\n\tdictWord{14, 11, 154},\n\tdictWord{16, 11, 48},\n\tdictWord{145, 11, 8},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t163,\n\t},\n\tdictWord{13, 11, 180},\n\tdictWord{18, 11, 78},\n\tdictWord{148, 11, 35},\n\tdictWord{14, 0, 32},\n\tdictWord{18, 0, 85},\n\tdictWord{20, 0, 2},\n\tdictWord{152, 0, 16},\n\tdictWord{7, 0, 228},\n\tdictWord{10, 0, 770},\n\tdictWord{8, 10, 167},\n\tdictWord{8, 10, 375},\n\tdictWord{9, 10, 82},\n\tdictWord{9, 10, 561},\n\tdictWord{138, 10, 620},\n\tdictWord{132, 0, 845},\n\tdictWord{9, 0, 14},\n\tdictWord{9, 0, 441},\n\tdictWord{10, 0, 306},\n\tdictWord{139, 0, 9},\n\tdictWord{11, 0, 966},\n\tdictWord{12, 0, 287},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t342,\n\t},\n\tdictWord{13, 0, 402},\n\tdictWord{15, 0, 110},\n\tdictWord{15, 0, 163},\n\tdictWord{8, 10, 194},\n\tdictWord{136, 10, 756},\n\tdictWord{134, 0, 1578},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t967,\n\t},\n\tdictWord{6, 0, 1820},\n\tdictWord{6, 0, 1847},\n\tdictWord{140, 0, 716},\n\tdictWord{136, 0, 594},\n\tdictWord{7, 0, 1428},\n\tdictWord{7, 0, 1640},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1867,\n\t},\n\tdictWord{9, 0, 169},\n\tdictWord{9, 0, 182},\n\tdictWord{9, 0, 367},\n\tdictWord{9, 0, 478},\n\tdictWord{9, 0, 506},\n\tdictWord{9, 0, 551},\n\tdictWord{9, 0, 557},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t648,\n\t},\n\tdictWord{9, 0, 697},\n\tdictWord{9, 0, 705},\n\tdictWord{9, 0, 725},\n\tdictWord{9, 0, 787},\n\tdictWord{9, 0, 794},\n\tdictWord{10, 0, 198},\n\tdictWord{10, 0, 214},\n\tdictWord{10, 0, 267},\n\tdictWord{10, 0, 275},\n\tdictWord{10, 0, 456},\n\tdictWord{10, 0, 551},\n\tdictWord{10, 0, 561},\n\tdictWord{10, 0, 613},\n\tdictWord{10, 0, 627},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t668,\n\t},\n\tdictWord{10, 0, 675},\n\tdictWord{10, 0, 691},\n\tdictWord{10, 0, 695},\n\tdictWord{10, 0, 707},\n\tdictWord{10, 0, 715},\n\tdictWord{11, 0, 183},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t201,\n\t},\n\tdictWord{11, 0, 244},\n\tdictWord{11, 0, 262},\n\tdictWord{11, 0, 352},\n\tdictWord{11, 0, 439},\n\tdictWord{11, 0, 493},\n\tdictWord{11, 0, 572},\n\tdictWord{11, 0, 591},\n\tdictWord{11, 0, 608},\n\tdictWord{11, 0, 611},\n\tdictWord{11, 0, 646},\n\tdictWord{11, 0, 674},\n\tdictWord{11, 0, 711},\n\tdictWord{11, 0, 751},\n\tdictWord{11, 0, 761},\n\tdictWord{11, 0, 776},\n\tdictWord{11, 0, 785},\n\tdictWord{11, 0, 850},\n\tdictWord{11, 0, 853},\n\tdictWord{11, 0, 862},\n\tdictWord{11, 0, 865},\n\tdictWord{11, 0, 868},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t875,\n\t},\n\tdictWord{11, 0, 898},\n\tdictWord{11, 0, 902},\n\tdictWord{11, 0, 903},\n\tdictWord{11, 0, 910},\n\tdictWord{11, 0, 932},\n\tdictWord{11, 0, 942},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t957,\n\t},\n\tdictWord{11, 0, 967},\n\tdictWord{11, 0, 972},\n\tdictWord{12, 0, 148},\n\tdictWord{12, 0, 195},\n\tdictWord{12, 0, 220},\n\tdictWord{12, 0, 237},\n\tdictWord{12, 0, 318},\n\tdictWord{12, 0, 339},\n\tdictWord{12, 0, 393},\n\tdictWord{12, 0, 445},\n\tdictWord{12, 0, 450},\n\tdictWord{12, 0, 474},\n\tdictWord{12, 0, 505},\n\tdictWord{12, 0, 509},\n\tdictWord{12, 0, 533},\n\tdictWord{12, 0, 591},\n\tdictWord{12, 0, 594},\n\tdictWord{12, 0, 597},\n\tdictWord{12, 0, 621},\n\tdictWord{12, 0, 633},\n\tdictWord{12, 0, 642},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t59,\n\t},\n\tdictWord{13, 0, 60},\n\tdictWord{13, 0, 145},\n\tdictWord{13, 0, 239},\n\tdictWord{13, 0, 250},\n\tdictWord{13, 0, 329},\n\tdictWord{13, 0, 344},\n\tdictWord{13, 0, 365},\n\tdictWord{13, 0, 372},\n\tdictWord{13, 0, 387},\n\tdictWord{13, 0, 403},\n\tdictWord{13, 0, 414},\n\tdictWord{13, 0, 456},\n\tdictWord{13, 0, 470},\n\tdictWord{13, 0, 478},\n\tdictWord{13, 0, 483},\n\tdictWord{13, 0, 489},\n\tdictWord{14, 0, 55},\n\tdictWord{14, 0, 57},\n\tdictWord{14, 0, 81},\n\tdictWord{14, 0, 90},\n\tdictWord{14, 0, 148},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t239,\n\t},\n\tdictWord{14, 0, 266},\n\tdictWord{14, 0, 321},\n\tdictWord{14, 0, 326},\n\tdictWord{14, 0, 327},\n\tdictWord{14, 0, 330},\n\tdictWord{14, 0, 347},\n\tdictWord{14, 0, 355},\n\tdictWord{14, 0, 401},\n\tdictWord{14, 0, 404},\n\tdictWord{14, 0, 411},\n\tdictWord{14, 0, 414},\n\tdictWord{14, 0, 416},\n\tdictWord{14, 0, 420},\n\tdictWord{15, 0, 61},\n\tdictWord{15, 0, 74},\n\tdictWord{15, 0, 87},\n\tdictWord{15, 0, 88},\n\tdictWord{15, 0, 94},\n\tdictWord{15, 0, 96},\n\tdictWord{15, 0, 116},\n\tdictWord{15, 0, 149},\n\tdictWord{15, 0, 154},\n\tdictWord{16, 0, 50},\n\tdictWord{16, 0, 63},\n\tdictWord{16, 0, 73},\n\tdictWord{17, 0, 2},\n\tdictWord{17, 0, 66},\n\tdictWord{17, 0, 92},\n\tdictWord{17, 0, 103},\n\tdictWord{\n\t\t17,\n\t\t0,\n\t\t112,\n\t},\n\tdictWord{17, 0, 120},\n\tdictWord{18, 0, 50},\n\tdictWord{18, 0, 54},\n\tdictWord{18, 0, 82},\n\tdictWord{18, 0, 86},\n\tdictWord{18, 0, 90},\n\tdictWord{18, 0, 111},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t115,\n\t},\n\tdictWord{18, 0, 156},\n\tdictWord{19, 0, 40},\n\tdictWord{19, 0, 79},\n\tdictWord{20, 0, 78},\n\tdictWord{21, 0, 22},\n\tdictWord{135, 11, 883},\n\tdictWord{5, 0, 161},\n\tdictWord{135, 0, 839},\n\tdictWord{4, 0, 782},\n\tdictWord{13, 11, 293},\n\tdictWord{142, 11, 56},\n\tdictWord{133, 11, 617},\n\tdictWord{139, 11, 50},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t22,\n\t},\n\tdictWord{145, 0, 64},\n\tdictWord{5, 10, 639},\n\tdictWord{7, 10, 1249},\n\tdictWord{139, 10, 896},\n\tdictWord{138, 0, 998},\n\tdictWord{135, 11, 2042},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t546,\n\t},\n\tdictWord{142, 11, 233},\n\tdictWord{6, 0, 1043},\n\tdictWord{134, 0, 1574},\n\tdictWord{134, 0, 1496},\n\tdictWord{4, 10, 102},\n\tdictWord{7, 10, 815},\n\tdictWord{7, 10, 1699},\n\tdictWord{139, 10, 964},\n\tdictWord{12, 0, 781},\n\tdictWord{142, 0, 461},\n\tdictWord{4, 11, 313},\n\tdictWord{133, 11, 577},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t639,\n\t},\n\tdictWord{6, 0, 1114},\n\tdictWord{137, 0, 817},\n\tdictWord{8, 11, 184},\n\tdictWord{141, 11, 433},\n\tdictWord{7, 0, 1814},\n\tdictWord{135, 11, 935},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t997,\n\t},\n\tdictWord{140, 0, 958},\n\tdictWord{4, 0, 812},\n\tdictWord{137, 11, 625},\n\tdictWord{132, 10, 899},\n\tdictWord{136, 10, 795},\n\tdictWord{5, 11, 886},\n\tdictWord{6, 11, 46},\n\tdictWord{6, 11, 1790},\n\tdictWord{7, 11, 14},\n\tdictWord{7, 11, 732},\n\tdictWord{7, 11, 1654},\n\tdictWord{8, 11, 95},\n\tdictWord{8, 11, 327},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t616,\n\t},\n\tdictWord{10, 11, 598},\n\tdictWord{10, 11, 769},\n\tdictWord{11, 11, 134},\n\tdictWord{11, 11, 747},\n\tdictWord{12, 11, 378},\n\tdictWord{142, 11, 97},\n\tdictWord{136, 0, 139},\n\tdictWord{6, 10, 52},\n\tdictWord{9, 10, 104},\n\tdictWord{9, 10, 559},\n\tdictWord{12, 10, 308},\n\tdictWord{147, 10, 87},\n\tdictWord{133, 11, 1021},\n\tdictWord{132, 10, 604},\n\tdictWord{132, 10, 301},\n\tdictWord{136, 10, 779},\n\tdictWord{7, 0, 643},\n\tdictWord{136, 0, 236},\n\tdictWord{132, 11, 153},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1172,\n\t},\n\tdictWord{147, 10, 32},\n\tdictWord{133, 11, 798},\n\tdictWord{6, 0, 1338},\n\tdictWord{132, 11, 587},\n\tdictWord{6, 11, 598},\n\tdictWord{7, 11, 42},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t695,\n\t},\n\tdictWord{10, 11, 212},\n\tdictWord{11, 11, 158},\n\tdictWord{14, 11, 196},\n\tdictWord{145, 11, 85},\n\tdictWord{135, 10, 508},\n\tdictWord{5, 11, 957},\n\tdictWord{5, 11, 1008},\n\tdictWord{135, 11, 249},\n\tdictWord{4, 11, 129},\n\tdictWord{135, 11, 465},\n\tdictWord{5, 0, 54},\n\tdictWord{7, 11, 470},\n\tdictWord{7, 11, 1057},\n\tdictWord{7, 11, 1201},\n\tdictWord{9, 11, 755},\n\tdictWord{11, 11, 906},\n\tdictWord{140, 11, 527},\n\tdictWord{7, 11, 908},\n\tdictWord{146, 11, 7},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t148,\n\t},\n\tdictWord{136, 11, 450},\n\tdictWord{144, 11, 1},\n\tdictWord{4, 0, 256},\n\tdictWord{135, 0, 1488},\n\tdictWord{9, 0, 351},\n\tdictWord{6, 10, 310},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1849,\n\t},\n\tdictWord{8, 10, 72},\n\tdictWord{8, 10, 272},\n\tdictWord{8, 10, 431},\n\tdictWord{9, 10, 12},\n\tdictWord{10, 10, 563},\n\tdictWord{10, 10, 630},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t796,\n\t},\n\tdictWord{10, 10, 810},\n\tdictWord{11, 10, 367},\n\tdictWord{11, 10, 599},\n\tdictWord{11, 10, 686},\n\tdictWord{140, 10, 672},\n\tdictWord{6, 0, 1885},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1898,\n\t},\n\tdictWord{6, 0, 1899},\n\tdictWord{140, 0, 955},\n\tdictWord{4, 0, 714},\n\tdictWord{133, 0, 469},\n\tdictWord{6, 0, 1270},\n\tdictWord{134, 0, 1456},\n\tdictWord{132, 0, 744},\n\tdictWord{6, 0, 313},\n\tdictWord{7, 10, 537},\n\tdictWord{8, 10, 64},\n\tdictWord{9, 10, 127},\n\tdictWord{10, 10, 496},\n\tdictWord{12, 10, 510},\n\tdictWord{141, 10, 384},\n\tdictWord{4, 11, 217},\n\tdictWord{4, 10, 244},\n\tdictWord{5, 11, 710},\n\tdictWord{7, 10, 233},\n\tdictWord{7, 11, 1926},\n\tdictWord{9, 11, 428},\n\tdictWord{9, 11, 708},\n\tdictWord{10, 11, 254},\n\tdictWord{10, 11, 296},\n\tdictWord{10, 11, 720},\n\tdictWord{11, 11, 109},\n\tdictWord{11, 11, 255},\n\tdictWord{12, 11, 165},\n\tdictWord{12, 11, 315},\n\tdictWord{13, 11, 107},\n\tdictWord{13, 11, 203},\n\tdictWord{14, 11, 54},\n\tdictWord{14, 11, 99},\n\tdictWord{14, 11, 114},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t388,\n\t},\n\tdictWord{16, 11, 85},\n\tdictWord{17, 11, 9},\n\tdictWord{17, 11, 33},\n\tdictWord{20, 11, 25},\n\tdictWord{20, 11, 28},\n\tdictWord{20, 11, 29},\n\tdictWord{21, 11, 9},\n\tdictWord{21, 11, 10},\n\tdictWord{21, 11, 34},\n\tdictWord{150, 11, 17},\n\tdictWord{138, 0, 402},\n\tdictWord{7, 0, 969},\n\tdictWord{146, 0, 55},\n\tdictWord{8, 0, 50},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t624,\n\t},\n\tdictWord{134, 0, 1355},\n\tdictWord{132, 0, 572},\n\tdictWord{134, 10, 1650},\n\tdictWord{10, 10, 702},\n\tdictWord{139, 10, 245},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t847,\n\t},\n\tdictWord{142, 0, 445},\n\tdictWord{6, 0, 43},\n\tdictWord{7, 0, 38},\n\tdictWord{8, 0, 248},\n\tdictWord{138, 0, 513},\n\tdictWord{133, 0, 369},\n\tdictWord{137, 10, 338},\n\tdictWord{133, 0, 766},\n\tdictWord{133, 0, 363},\n\tdictWord{133, 10, 896},\n\tdictWord{8, 11, 392},\n\tdictWord{11, 11, 54},\n\tdictWord{13, 11, 173},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t294,\n\t},\n\tdictWord{148, 11, 7},\n\tdictWord{134, 0, 678},\n\tdictWord{7, 11, 1230},\n\tdictWord{136, 11, 531},\n\tdictWord{6, 0, 258},\n\tdictWord{140, 0, 409},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t249,\n\t},\n\tdictWord{148, 0, 82},\n\tdictWord{7, 10, 1117},\n\tdictWord{136, 10, 539},\n\tdictWord{5, 0, 393},\n\tdictWord{6, 0, 378},\n\tdictWord{7, 0, 1981},\n\tdictWord{9, 0, 32},\n\tdictWord{9, 0, 591},\n\tdictWord{10, 0, 685},\n\tdictWord{10, 0, 741},\n\tdictWord{142, 0, 382},\n\tdictWord{133, 0, 788},\n\tdictWord{134, 0, 1281},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1295,\n\t},\n\tdictWord{7, 0, 1968},\n\tdictWord{141, 0, 509},\n\tdictWord{4, 0, 61},\n\tdictWord{5, 0, 58},\n\tdictWord{5, 0, 171},\n\tdictWord{5, 0, 683},\n\tdictWord{6, 0, 291},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t566,\n\t},\n\tdictWord{7, 0, 1650},\n\tdictWord{11, 0, 523},\n\tdictWord{12, 0, 273},\n\tdictWord{12, 0, 303},\n\tdictWord{15, 0, 39},\n\tdictWord{143, 0, 111},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t706,\n\t},\n\tdictWord{134, 0, 1283},\n\tdictWord{134, 0, 589},\n\tdictWord{135, 11, 1433},\n\tdictWord{133, 11, 435},\n\tdictWord{7, 0, 1059},\n\tdictWord{13, 0, 54},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t4,\n\t},\n\tdictWord{5, 10, 810},\n\tdictWord{6, 10, 13},\n\tdictWord{6, 10, 538},\n\tdictWord{6, 10, 1690},\n\tdictWord{6, 10, 1726},\n\tdictWord{7, 10, 1819},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t148,\n\t},\n\tdictWord{8, 10, 696},\n\tdictWord{8, 10, 791},\n\tdictWord{12, 10, 125},\n\tdictWord{143, 10, 9},\n\tdictWord{135, 10, 1268},\n\tdictWord{5, 11, 85},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t419,\n\t},\n\tdictWord{7, 11, 134},\n\tdictWord{7, 11, 305},\n\tdictWord{7, 11, 361},\n\tdictWord{7, 11, 1337},\n\tdictWord{8, 11, 71},\n\tdictWord{140, 11, 519},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t824,\n\t},\n\tdictWord{140, 11, 688},\n\tdictWord{5, 11, 691},\n\tdictWord{7, 11, 345},\n\tdictWord{7, 10, 1385},\n\tdictWord{9, 11, 94},\n\tdictWord{11, 10, 582},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t650,\n\t},\n\tdictWord{11, 10, 901},\n\tdictWord{11, 10, 949},\n\tdictWord{12, 11, 169},\n\tdictWord{12, 10, 232},\n\tdictWord{12, 10, 236},\n\tdictWord{13, 10, 413},\n\tdictWord{13, 10, 501},\n\tdictWord{146, 10, 116},\n\tdictWord{4, 0, 917},\n\tdictWord{133, 0, 1005},\n\tdictWord{7, 0, 1598},\n\tdictWord{5, 11, 183},\n\tdictWord{6, 11, 582},\n\tdictWord{9, 11, 344},\n\tdictWord{10, 11, 679},\n\tdictWord{140, 11, 435},\n\tdictWord{4, 10, 925},\n\tdictWord{5, 10, 803},\n\tdictWord{8, 10, 698},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t828,\n\t},\n\tdictWord{132, 0, 919},\n\tdictWord{135, 11, 511},\n\tdictWord{139, 10, 992},\n\tdictWord{4, 0, 255},\n\tdictWord{5, 0, 302},\n\tdictWord{6, 0, 132},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t128,\n\t},\n\tdictWord{7, 0, 283},\n\tdictWord{7, 0, 1299},\n\tdictWord{10, 0, 52},\n\tdictWord{10, 0, 514},\n\tdictWord{11, 0, 925},\n\tdictWord{13, 0, 92},\n\tdictWord{142, 0, 309},\n\tdictWord{134, 0, 1369},\n\tdictWord{135, 10, 1847},\n\tdictWord{134, 0, 328},\n\tdictWord{7, 11, 1993},\n\tdictWord{136, 11, 684},\n\tdictWord{133, 10, 383},\n\tdictWord{137, 0, 173},\n\tdictWord{134, 11, 583},\n\tdictWord{134, 0, 1411},\n\tdictWord{19, 0, 65},\n\tdictWord{5, 11, 704},\n\tdictWord{8, 11, 357},\n\tdictWord{10, 11, 745},\n\tdictWord{14, 11, 426},\n\tdictWord{17, 11, 94},\n\tdictWord{147, 11, 57},\n\tdictWord{9, 10, 660},\n\tdictWord{138, 10, 347},\n\tdictWord{4, 11, 179},\n\tdictWord{5, 11, 198},\n\tdictWord{133, 11, 697},\n\tdictWord{7, 11, 347},\n\tdictWord{7, 11, 971},\n\tdictWord{8, 11, 181},\n\tdictWord{138, 11, 711},\n\tdictWord{141, 0, 442},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t842,\n\t},\n\tdictWord{11, 0, 924},\n\tdictWord{13, 0, 317},\n\tdictWord{13, 0, 370},\n\tdictWord{13, 0, 469},\n\tdictWord{13, 0, 471},\n\tdictWord{14, 0, 397},\n\tdictWord{18, 0, 69},\n\tdictWord{18, 0, 145},\n\tdictWord{7, 10, 572},\n\tdictWord{9, 10, 592},\n\tdictWord{11, 10, 680},\n\tdictWord{12, 10, 356},\n\tdictWord{140, 10, 550},\n\tdictWord{14, 11, 19},\n\tdictWord{14, 11, 28},\n\tdictWord{144, 11, 29},\n\tdictWord{136, 0, 534},\n\tdictWord{4, 11, 243},\n\tdictWord{5, 11, 203},\n\tdictWord{7, 11, 19},\n\tdictWord{7, 11, 71},\n\tdictWord{7, 11, 113},\n\tdictWord{10, 11, 405},\n\tdictWord{11, 11, 357},\n\tdictWord{142, 11, 240},\n\tdictWord{6, 0, 210},\n\tdictWord{10, 0, 845},\n\tdictWord{138, 0, 862},\n\tdictWord{7, 11, 1351},\n\tdictWord{9, 11, 581},\n\tdictWord{10, 11, 639},\n\tdictWord{11, 11, 453},\n\tdictWord{140, 11, 584},\n\tdictWord{7, 11, 1450},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t99,\n\t},\n\tdictWord{10, 0, 892},\n\tdictWord{12, 0, 719},\n\tdictWord{144, 0, 105},\n\tdictWord{4, 0, 284},\n\tdictWord{6, 0, 223},\n\tdictWord{134, 11, 492},\n\tdictWord{5, 11, 134},\n\tdictWord{6, 11, 408},\n\tdictWord{6, 11, 495},\n\tdictWord{135, 11, 1593},\n\tdictWord{136, 0, 529},\n\tdictWord{137, 0, 807},\n\tdictWord{4, 0, 218},\n\tdictWord{7, 0, 526},\n\tdictWord{143, 0, 137},\n\tdictWord{6, 0, 1444},\n\tdictWord{142, 11, 4},\n\tdictWord{132, 11, 665},\n\tdictWord{4, 0, 270},\n\tdictWord{5, 0, 192},\n\tdictWord{6, 0, 332},\n\tdictWord{7, 0, 1322},\n\tdictWord{4, 11, 248},\n\tdictWord{7, 11, 137},\n\tdictWord{137, 11, 349},\n\tdictWord{140, 0, 661},\n\tdictWord{7, 0, 1517},\n\tdictWord{11, 0, 597},\n\tdictWord{14, 0, 76},\n\tdictWord{14, 0, 335},\n\tdictWord{20, 0, 33},\n\tdictWord{7, 10, 748},\n\tdictWord{139, 10, 700},\n\tdictWord{5, 11, 371},\n\tdictWord{135, 11, 563},\n\tdictWord{146, 11, 57},\n\tdictWord{133, 10, 127},\n\tdictWord{133, 0, 418},\n\tdictWord{4, 11, 374},\n\tdictWord{7, 11, 547},\n\tdictWord{7, 11, 1700},\n\tdictWord{7, 11, 1833},\n\tdictWord{139, 11, 858},\n\tdictWord{6, 10, 198},\n\tdictWord{140, 10, 83},\n\tdictWord{7, 11, 1812},\n\tdictWord{13, 11, 259},\n\tdictWord{13, 11, 356},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t242,\n\t},\n\tdictWord{147, 11, 114},\n\tdictWord{7, 0, 379},\n\tdictWord{8, 0, 481},\n\tdictWord{9, 0, 377},\n\tdictWord{5, 10, 276},\n\tdictWord{6, 10, 55},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1369,\n\t},\n\tdictWord{138, 11, 286},\n\tdictWord{5, 0, 1003},\n\tdictWord{6, 0, 149},\n\tdictWord{6, 10, 1752},\n\tdictWord{136, 10, 726},\n\tdictWord{8, 0, 262},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t627,\n\t},\n\tdictWord{10, 0, 18},\n\tdictWord{11, 0, 214},\n\tdictWord{11, 0, 404},\n\tdictWord{11, 0, 457},\n\tdictWord{11, 0, 780},\n\tdictWord{11, 0, 913},\n\tdictWord{13, 0, 401},\n\tdictWord{14, 0, 200},\n\tdictWord{6, 11, 1647},\n\tdictWord{7, 11, 1552},\n\tdictWord{7, 11, 2010},\n\tdictWord{9, 11, 494},\n\tdictWord{137, 11, 509},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t742,\n\t},\n\tdictWord{136, 0, 304},\n\tdictWord{132, 0, 142},\n\tdictWord{133, 10, 764},\n\tdictWord{6, 10, 309},\n\tdictWord{7, 10, 331},\n\tdictWord{138, 10, 550},\n\tdictWord{135, 10, 1062},\n\tdictWord{6, 11, 123},\n\tdictWord{7, 11, 214},\n\tdictWord{7, 10, 986},\n\tdictWord{9, 11, 728},\n\tdictWord{10, 11, 157},\n\tdictWord{11, 11, 346},\n\tdictWord{11, 11, 662},\n\tdictWord{143, 11, 106},\n\tdictWord{135, 10, 1573},\n\tdictWord{7, 0, 925},\n\tdictWord{137, 0, 799},\n\tdictWord{4, 0, 471},\n\tdictWord{5, 0, 51},\n\tdictWord{6, 0, 602},\n\tdictWord{8, 0, 484},\n\tdictWord{138, 0, 195},\n\tdictWord{136, 0, 688},\n\tdictWord{132, 0, 697},\n\tdictWord{6, 0, 1169},\n\tdictWord{6, 0, 1241},\n\tdictWord{6, 10, 194},\n\tdictWord{7, 10, 133},\n\tdictWord{10, 10, 493},\n\tdictWord{10, 10, 570},\n\tdictWord{139, 10, 664},\n\tdictWord{140, 0, 751},\n\tdictWord{7, 0, 929},\n\tdictWord{10, 0, 452},\n\tdictWord{11, 0, 878},\n\tdictWord{16, 0, 33},\n\tdictWord{5, 10, 24},\n\tdictWord{5, 10, 569},\n\tdictWord{6, 10, 3},\n\tdictWord{6, 10, 119},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t143,\n\t},\n\tdictWord{6, 10, 440},\n\tdictWord{7, 10, 599},\n\tdictWord{7, 10, 1686},\n\tdictWord{7, 10, 1854},\n\tdictWord{8, 10, 424},\n\tdictWord{9, 10, 43},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t584,\n\t},\n\tdictWord{9, 10, 760},\n\tdictWord{10, 10, 328},\n\tdictWord{11, 10, 159},\n\tdictWord{11, 10, 253},\n\tdictWord{12, 10, 487},\n\tdictWord{140, 10, 531},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t707,\n\t},\n\tdictWord{13, 11, 106},\n\tdictWord{18, 11, 49},\n\tdictWord{147, 11, 41},\n\tdictWord{5, 0, 221},\n\tdictWord{5, 11, 588},\n\tdictWord{134, 11, 393},\n\tdictWord{134, 0, 1437},\n\tdictWord{6, 11, 211},\n\tdictWord{7, 11, 1690},\n\tdictWord{11, 11, 486},\n\tdictWord{140, 11, 369},\n\tdictWord{5, 10, 14},\n\tdictWord{5, 10, 892},\n\tdictWord{6, 10, 283},\n\tdictWord{7, 10, 234},\n\tdictWord{136, 10, 537},\n\tdictWord{4, 0, 988},\n\tdictWord{136, 0, 955},\n\tdictWord{135, 0, 1251},\n\tdictWord{4, 10, 126},\n\tdictWord{8, 10, 635},\n\tdictWord{147, 10, 34},\n\tdictWord{4, 10, 316},\n\tdictWord{135, 10, 1561},\n\tdictWord{137, 10, 861},\n\tdictWord{4, 10, 64},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t352,\n\t},\n\tdictWord{5, 10, 720},\n\tdictWord{6, 10, 368},\n\tdictWord{139, 10, 359},\n\tdictWord{134, 0, 192},\n\tdictWord{4, 0, 132},\n\tdictWord{5, 0, 69},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1242,\n\t},\n\tdictWord{7, 10, 1577},\n\tdictWord{10, 10, 304},\n\tdictWord{10, 10, 549},\n\tdictWord{12, 10, 365},\n\tdictWord{13, 10, 220},\n\tdictWord{13, 10, 240},\n\tdictWord{142, 10, 33},\n\tdictWord{4, 0, 111},\n\tdictWord{7, 0, 865},\n\tdictWord{134, 11, 219},\n\tdictWord{5, 11, 582},\n\tdictWord{6, 11, 1646},\n\tdictWord{7, 11, 99},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1962,\n\t},\n\tdictWord{7, 11, 1986},\n\tdictWord{8, 11, 515},\n\tdictWord{8, 11, 773},\n\tdictWord{9, 11, 23},\n\tdictWord{9, 11, 491},\n\tdictWord{12, 11, 620},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t52,\n\t},\n\tdictWord{145, 11, 50},\n\tdictWord{132, 0, 767},\n\tdictWord{7, 11, 568},\n\tdictWord{148, 11, 21},\n\tdictWord{6, 0, 42},\n\tdictWord{7, 0, 1416},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t2005,\n\t},\n\tdictWord{8, 0, 131},\n\tdictWord{8, 0, 466},\n\tdictWord{9, 0, 672},\n\tdictWord{13, 0, 252},\n\tdictWord{20, 0, 103},\n\tdictWord{133, 11, 851},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1050,\n\t},\n\tdictWord{6, 10, 175},\n\tdictWord{137, 10, 289},\n\tdictWord{5, 10, 432},\n\tdictWord{133, 10, 913},\n\tdictWord{6, 0, 44},\n\tdictWord{136, 0, 368},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t784,\n\t},\n\tdictWord{132, 0, 570},\n\tdictWord{133, 0, 120},\n\tdictWord{139, 10, 595},\n\tdictWord{140, 0, 29},\n\tdictWord{6, 0, 227},\n\tdictWord{135, 0, 1589},\n\tdictWord{4, 11, 98},\n\tdictWord{7, 11, 1365},\n\tdictWord{9, 11, 422},\n\tdictWord{9, 11, 670},\n\tdictWord{10, 11, 775},\n\tdictWord{11, 11, 210},\n\tdictWord{13, 11, 26},\n\tdictWord{13, 11, 457},\n\tdictWord{141, 11, 476},\n\tdictWord{140, 10, 80},\n\tdictWord{5, 10, 931},\n\tdictWord{134, 10, 1698},\n\tdictWord{133, 0, 522},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1120,\n\t},\n\tdictWord{135, 0, 1529},\n\tdictWord{12, 0, 739},\n\tdictWord{14, 0, 448},\n\tdictWord{142, 0, 467},\n\tdictWord{11, 10, 526},\n\tdictWord{11, 10, 939},\n\tdictWord{141, 10, 290},\n\tdictWord{5, 10, 774},\n\tdictWord{6, 10, 1637},\n\tdictWord{6, 10, 1686},\n\tdictWord{134, 10, 1751},\n\tdictWord{6, 0, 1667},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t2036,\n\t},\n\tdictWord{7, 10, 1167},\n\tdictWord{11, 10, 934},\n\tdictWord{13, 10, 391},\n\tdictWord{145, 10, 76},\n\tdictWord{137, 11, 147},\n\tdictWord{6, 10, 260},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1484,\n\t},\n\tdictWord{11, 11, 821},\n\tdictWord{12, 11, 110},\n\tdictWord{12, 11, 153},\n\tdictWord{18, 11, 41},\n\tdictWord{150, 11, 19},\n\tdictWord{6, 0, 511},\n\tdictWord{12, 0, 132},\n\tdictWord{134, 10, 573},\n\tdictWord{5, 0, 568},\n\tdictWord{6, 0, 138},\n\tdictWord{135, 0, 1293},\n\tdictWord{132, 0, 1020},\n\tdictWord{8, 0, 258},\n\tdictWord{9, 0, 208},\n\tdictWord{137, 0, 359},\n\tdictWord{4, 0, 565},\n\tdictWord{8, 0, 23},\n\tdictWord{136, 0, 827},\n\tdictWord{134, 0, 344},\n\tdictWord{4, 0, 922},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t1023,\n\t},\n\tdictWord{13, 11, 477},\n\tdictWord{14, 11, 120},\n\tdictWord{148, 11, 61},\n\tdictWord{134, 0, 240},\n\tdictWord{5, 11, 209},\n\tdictWord{6, 11, 30},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t56,\n\t},\n\tdictWord{139, 11, 305},\n\tdictWord{6, 0, 171},\n\tdictWord{7, 0, 1002},\n\tdictWord{7, 0, 1324},\n\tdictWord{9, 0, 415},\n\tdictWord{14, 0, 230},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t68,\n\t},\n\tdictWord{4, 10, 292},\n\tdictWord{4, 10, 736},\n\tdictWord{5, 10, 871},\n\tdictWord{6, 10, 1689},\n\tdictWord{7, 10, 1944},\n\tdictWord{137, 10, 580},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t635,\n\t},\n\tdictWord{139, 11, 559},\n\tdictWord{4, 11, 150},\n\tdictWord{5, 11, 303},\n\tdictWord{134, 11, 327},\n\tdictWord{6, 10, 63},\n\tdictWord{135, 10, 920},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t793,\n\t},\n\tdictWord{8, 11, 192},\n\tdictWord{10, 11, 78},\n\tdictWord{10, 11, 555},\n\tdictWord{11, 11, 308},\n\tdictWord{13, 11, 359},\n\tdictWord{147, 11, 95},\n\tdictWord{135, 11, 786},\n\tdictWord{135, 11, 1712},\n\tdictWord{136, 0, 402},\n\tdictWord{6, 0, 754},\n\tdictWord{6, 11, 1638},\n\tdictWord{7, 11, 79},\n\tdictWord{7, 11, 496},\n\tdictWord{9, 11, 138},\n\tdictWord{10, 11, 336},\n\tdictWord{11, 11, 12},\n\tdictWord{12, 11, 412},\n\tdictWord{12, 11, 440},\n\tdictWord{142, 11, 305},\n\tdictWord{4, 0, 716},\n\tdictWord{141, 0, 31},\n\tdictWord{133, 0, 982},\n\tdictWord{8, 0, 691},\n\tdictWord{8, 0, 731},\n\tdictWord{5, 10, 67},\n\tdictWord{6, 10, 62},\n\tdictWord{6, 10, 374},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1391,\n\t},\n\tdictWord{9, 10, 790},\n\tdictWord{140, 10, 47},\n\tdictWord{139, 11, 556},\n\tdictWord{151, 11, 1},\n\tdictWord{7, 11, 204},\n\tdictWord{7, 11, 415},\n\tdictWord{8, 11, 42},\n\tdictWord{10, 11, 85},\n\tdictWord{11, 11, 33},\n\tdictWord{11, 11, 564},\n\tdictWord{12, 11, 571},\n\tdictWord{149, 11, 1},\n\tdictWord{8, 0, 888},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t610,\n\t},\n\tdictWord{135, 11, 1501},\n\tdictWord{4, 10, 391},\n\tdictWord{135, 10, 1169},\n\tdictWord{5, 0, 847},\n\tdictWord{9, 0, 840},\n\tdictWord{138, 0, 803},\n\tdictWord{137, 0, 823},\n\tdictWord{134, 0, 785},\n\tdictWord{8, 0, 152},\n\tdictWord{9, 0, 53},\n\tdictWord{9, 0, 268},\n\tdictWord{9, 0, 901},\n\tdictWord{10, 0, 518},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t829,\n\t},\n\tdictWord{11, 0, 188},\n\tdictWord{13, 0, 74},\n\tdictWord{14, 0, 46},\n\tdictWord{15, 0, 17},\n\tdictWord{15, 0, 33},\n\tdictWord{17, 0, 40},\n\tdictWord{18, 0, 36},\n\tdictWord{\n\t\t19,\n\t\t0,\n\t\t20,\n\t},\n\tdictWord{22, 0, 1},\n\tdictWord{152, 0, 2},\n\tdictWord{4, 11, 3},\n\tdictWord{5, 11, 247},\n\tdictWord{5, 11, 644},\n\tdictWord{7, 11, 744},\n\tdictWord{7, 11, 1207},\n\tdictWord{7, 11, 1225},\n\tdictWord{7, 11, 1909},\n\tdictWord{146, 11, 147},\n\tdictWord{136, 0, 532},\n\tdictWord{135, 0, 681},\n\tdictWord{132, 10, 271},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t314,\n\t},\n\tdictWord{140, 0, 677},\n\tdictWord{4, 0, 684},\n\tdictWord{136, 0, 384},\n\tdictWord{5, 11, 285},\n\tdictWord{9, 11, 67},\n\tdictWord{13, 11, 473},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t82,\n\t},\n\tdictWord{4, 10, 253},\n\tdictWord{5, 10, 544},\n\tdictWord{7, 10, 300},\n\tdictWord{137, 10, 340},\n\tdictWord{7, 0, 110},\n\tdictWord{7, 0, 447},\n\tdictWord{8, 0, 290},\n\tdictWord{8, 0, 591},\n\tdictWord{9, 0, 382},\n\tdictWord{9, 0, 649},\n\tdictWord{11, 0, 71},\n\tdictWord{11, 0, 155},\n\tdictWord{11, 0, 313},\n\tdictWord{12, 0, 5},\n\tdictWord{13, 0, 325},\n\tdictWord{142, 0, 287},\n\tdictWord{134, 0, 1818},\n\tdictWord{136, 0, 1007},\n\tdictWord{138, 0, 321},\n\tdictWord{7, 0, 360},\n\tdictWord{7, 0, 425},\n\tdictWord{9, 0, 66},\n\tdictWord{9, 0, 278},\n\tdictWord{138, 0, 644},\n\tdictWord{133, 10, 818},\n\tdictWord{5, 0, 385},\n\tdictWord{5, 10, 541},\n\tdictWord{6, 10, 94},\n\tdictWord{6, 10, 499},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t230,\n\t},\n\tdictWord{139, 10, 321},\n\tdictWord{4, 10, 920},\n\tdictWord{5, 10, 25},\n\tdictWord{5, 10, 790},\n\tdictWord{6, 10, 457},\n\tdictWord{7, 10, 853},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t788,\n\t},\n\tdictWord{4, 0, 900},\n\tdictWord{133, 0, 861},\n\tdictWord{5, 0, 254},\n\tdictWord{7, 0, 985},\n\tdictWord{136, 0, 73},\n\tdictWord{7, 0, 1959},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t683,\n\t},\n\tdictWord{134, 10, 1765},\n\tdictWord{133, 10, 822},\n\tdictWord{132, 10, 634},\n\tdictWord{4, 11, 29},\n\tdictWord{6, 11, 532},\n\tdictWord{7, 11, 1628},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1648,\n\t},\n\tdictWord{9, 11, 303},\n\tdictWord{9, 11, 350},\n\tdictWord{10, 11, 433},\n\tdictWord{11, 11, 97},\n\tdictWord{11, 11, 557},\n\tdictWord{11, 11, 745},\n\tdictWord{12, 11, 289},\n\tdictWord{12, 11, 335},\n\tdictWord{12, 11, 348},\n\tdictWord{12, 11, 606},\n\tdictWord{13, 11, 116},\n\tdictWord{13, 11, 233},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t466,\n\t},\n\tdictWord{14, 11, 181},\n\tdictWord{14, 11, 209},\n\tdictWord{14, 11, 232},\n\tdictWord{14, 11, 236},\n\tdictWord{14, 11, 300},\n\tdictWord{16, 11, 41},\n\tdictWord{\n\t\t148,\n\t\t11,\n\t\t97,\n\t},\n\tdictWord{19, 0, 86},\n\tdictWord{6, 10, 36},\n\tdictWord{7, 10, 658},\n\tdictWord{136, 10, 454},\n\tdictWord{135, 11, 1692},\n\tdictWord{132, 0, 725},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t501,\n\t},\n\tdictWord{7, 11, 1704},\n\tdictWord{9, 11, 553},\n\tdictWord{11, 11, 520},\n\tdictWord{12, 11, 557},\n\tdictWord{141, 11, 249},\n\tdictWord{134, 0, 196},\n\tdictWord{133, 0, 831},\n\tdictWord{136, 0, 723},\n\tdictWord{7, 0, 1897},\n\tdictWord{13, 0, 80},\n\tdictWord{13, 0, 437},\n\tdictWord{145, 0, 74},\n\tdictWord{4, 0, 992},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t627,\n\t},\n\tdictWord{136, 0, 994},\n\tdictWord{135, 11, 1294},\n\tdictWord{132, 10, 104},\n\tdictWord{5, 0, 848},\n\tdictWord{6, 0, 66},\n\tdictWord{136, 0, 764},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t36,\n\t},\n\tdictWord{7, 0, 1387},\n\tdictWord{10, 0, 205},\n\tdictWord{139, 0, 755},\n\tdictWord{6, 0, 1046},\n\tdictWord{134, 0, 1485},\n\tdictWord{134, 0, 950},\n\tdictWord{132, 0, 887},\n\tdictWord{14, 0, 450},\n\tdictWord{148, 0, 111},\n\tdictWord{7, 0, 620},\n\tdictWord{7, 0, 831},\n\tdictWord{9, 10, 542},\n\tdictWord{9, 10, 566},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t728,\n\t},\n\tdictWord{6, 0, 165},\n\tdictWord{138, 0, 388},\n\tdictWord{139, 10, 263},\n\tdictWord{4, 0, 719},\n\tdictWord{135, 0, 155},\n\tdictWord{138, 10, 468},\n\tdictWord{6, 11, 453},\n\tdictWord{144, 11, 36},\n\tdictWord{134, 11, 129},\n\tdictWord{5, 0, 533},\n\tdictWord{7, 0, 755},\n\tdictWord{138, 0, 780},\n\tdictWord{134, 0, 1465},\n\tdictWord{4, 0, 353},\n\tdictWord{6, 0, 146},\n\tdictWord{6, 0, 1789},\n\tdictWord{7, 0, 427},\n\tdictWord{7, 0, 990},\n\tdictWord{7, 0, 1348},\n\tdictWord{9, 0, 665},\n\tdictWord{9, 0, 898},\n\tdictWord{11, 0, 893},\n\tdictWord{142, 0, 212},\n\tdictWord{7, 10, 87},\n\tdictWord{142, 10, 288},\n\tdictWord{4, 0, 45},\n\tdictWord{135, 0, 1257},\n\tdictWord{12, 0, 7},\n\tdictWord{7, 10, 988},\n\tdictWord{7, 10, 1939},\n\tdictWord{9, 10, 64},\n\tdictWord{9, 10, 502},\n\tdictWord{12, 10, 34},\n\tdictWord{13, 10, 12},\n\tdictWord{13, 10, 234},\n\tdictWord{147, 10, 77},\n\tdictWord{4, 0, 607},\n\tdictWord{5, 11, 60},\n\tdictWord{6, 11, 504},\n\tdictWord{7, 11, 614},\n\tdictWord{7, 11, 1155},\n\tdictWord{140, 11, 0},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t141,\n\t},\n\tdictWord{8, 11, 198},\n\tdictWord{11, 11, 29},\n\tdictWord{140, 11, 534},\n\tdictWord{140, 0, 65},\n\tdictWord{136, 0, 816},\n\tdictWord{132, 10, 619},\n\tdictWord{139, 0, 88},\n\tdictWord{5, 10, 246},\n\tdictWord{8, 10, 189},\n\tdictWord{9, 10, 355},\n\tdictWord{9, 10, 512},\n\tdictWord{10, 10, 124},\n\tdictWord{10, 10, 453},\n\tdictWord{11, 10, 143},\n\tdictWord{11, 10, 416},\n\tdictWord{11, 10, 859},\n\tdictWord{141, 10, 341},\n\tdictWord{4, 11, 379},\n\tdictWord{135, 11, 1397},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t600,\n\t},\n\tdictWord{137, 0, 621},\n\tdictWord{133, 0, 367},\n\tdictWord{134, 0, 561},\n\tdictWord{6, 0, 559},\n\tdictWord{134, 0, 1691},\n\tdictWord{6, 0, 585},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t585,\n\t},\n\tdictWord{135, 11, 1228},\n\tdictWord{4, 11, 118},\n\tdictWord{5, 10, 678},\n\tdictWord{6, 11, 274},\n\tdictWord{6, 11, 361},\n\tdictWord{7, 11, 75},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t441,\n\t},\n\tdictWord{135, 11, 1818},\n\tdictWord{137, 11, 841},\n\tdictWord{5, 0, 573},\n\tdictWord{6, 0, 287},\n\tdictWord{7, 10, 862},\n\tdictWord{7, 10, 1886},\n\tdictWord{138, 10, 179},\n\tdictWord{132, 10, 517},\n\tdictWord{140, 11, 693},\n\tdictWord{5, 11, 314},\n\tdictWord{6, 11, 221},\n\tdictWord{7, 11, 419},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t650,\n\t},\n\tdictWord{11, 11, 396},\n\tdictWord{12, 11, 156},\n\tdictWord{13, 11, 369},\n\tdictWord{14, 11, 333},\n\tdictWord{145, 11, 47},\n\tdictWord{140, 10, 540},\n\tdictWord{136, 10, 667},\n\tdictWord{11, 10, 403},\n\tdictWord{146, 10, 83},\n\tdictWord{6, 0, 672},\n\tdictWord{133, 10, 761},\n\tdictWord{9, 0, 157},\n\tdictWord{10, 10, 131},\n\tdictWord{140, 10, 72},\n\tdictWord{7, 0, 714},\n\tdictWord{134, 11, 460},\n\tdictWord{134, 0, 456},\n\tdictWord{133, 0, 925},\n\tdictWord{5, 11, 682},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1887,\n\t},\n\tdictWord{136, 11, 510},\n\tdictWord{136, 11, 475},\n\tdictWord{133, 11, 1016},\n\tdictWord{9, 0, 19},\n\tdictWord{7, 11, 602},\n\tdictWord{8, 11, 179},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t781,\n\t},\n\tdictWord{140, 11, 126},\n\tdictWord{6, 11, 329},\n\tdictWord{138, 11, 111},\n\tdictWord{6, 0, 822},\n\tdictWord{134, 0, 1473},\n\tdictWord{144, 11, 86},\n\tdictWord{11, 0, 113},\n\tdictWord{139, 11, 113},\n\tdictWord{5, 11, 821},\n\tdictWord{134, 11, 1687},\n\tdictWord{133, 10, 449},\n\tdictWord{7, 0, 463},\n\tdictWord{\n\t\t17,\n\t\t0,\n\t\t69,\n\t},\n\tdictWord{136, 10, 103},\n\tdictWord{7, 10, 2028},\n\tdictWord{138, 10, 641},\n\tdictWord{6, 0, 193},\n\tdictWord{7, 0, 240},\n\tdictWord{7, 0, 1682},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t51,\n\t},\n\tdictWord{10, 0, 640},\n\tdictWord{11, 0, 410},\n\tdictWord{13, 0, 82},\n\tdictWord{14, 0, 247},\n\tdictWord{14, 0, 331},\n\tdictWord{142, 0, 377},\n\tdictWord{6, 0, 471},\n\tdictWord{11, 0, 411},\n\tdictWord{142, 0, 2},\n\tdictWord{5, 11, 71},\n\tdictWord{7, 11, 1407},\n\tdictWord{9, 11, 388},\n\tdictWord{9, 11, 704},\n\tdictWord{10, 11, 261},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t619,\n\t},\n\tdictWord{11, 11, 547},\n\tdictWord{11, 11, 619},\n\tdictWord{143, 11, 157},\n\tdictWord{136, 0, 633},\n\tdictWord{135, 0, 1148},\n\tdictWord{6, 0, 554},\n\tdictWord{7, 0, 1392},\n\tdictWord{12, 0, 129},\n\tdictWord{7, 10, 1274},\n\tdictWord{7, 10, 1386},\n\tdictWord{7, 11, 2008},\n\tdictWord{9, 11, 337},\n\tdictWord{10, 11, 517},\n\tdictWord{146, 10, 87},\n\tdictWord{7, 0, 803},\n\tdictWord{8, 0, 542},\n\tdictWord{6, 10, 187},\n\tdictWord{7, 10, 1203},\n\tdictWord{8, 10, 380},\n\tdictWord{14, 10, 117},\n\tdictWord{149, 10, 28},\n\tdictWord{6, 10, 297},\n\tdictWord{7, 10, 793},\n\tdictWord{139, 10, 938},\n\tdictWord{8, 0, 438},\n\tdictWord{11, 0, 363},\n\tdictWord{7, 10, 464},\n\tdictWord{11, 10, 105},\n\tdictWord{12, 10, 231},\n\tdictWord{14, 10, 386},\n\tdictWord{15, 10, 102},\n\tdictWord{148, 10, 75},\n\tdictWord{5, 11, 16},\n\tdictWord{6, 11, 86},\n\tdictWord{6, 11, 603},\n\tdictWord{7, 11, 292},\n\tdictWord{7, 11, 561},\n\tdictWord{8, 11, 257},\n\tdictWord{8, 11, 382},\n\tdictWord{9, 11, 721},\n\tdictWord{9, 11, 778},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t581,\n\t},\n\tdictWord{140, 11, 466},\n\tdictWord{6, 0, 717},\n\tdictWord{4, 11, 486},\n\tdictWord{133, 11, 491},\n\tdictWord{132, 0, 875},\n\tdictWord{132, 11, 72},\n\tdictWord{6, 11, 265},\n\tdictWord{135, 11, 847},\n\tdictWord{4, 0, 237},\n\tdictWord{135, 0, 514},\n\tdictWord{6, 0, 392},\n\tdictWord{7, 0, 65},\n\tdictWord{135, 0, 2019},\n\tdictWord{140, 11, 261},\n\tdictWord{135, 11, 922},\n\tdictWord{137, 11, 404},\n\tdictWord{12, 0, 563},\n\tdictWord{14, 0, 101},\n\tdictWord{18, 0, 129},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1010,\n\t},\n\tdictWord{11, 10, 733},\n\tdictWord{11, 10, 759},\n\tdictWord{13, 10, 34},\n\tdictWord{146, 10, 45},\n\tdictWord{7, 10, 1656},\n\tdictWord{9, 10, 369},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t338,\n\t},\n\tdictWord{10, 10, 490},\n\tdictWord{11, 10, 154},\n\tdictWord{11, 10, 545},\n\tdictWord{11, 10, 775},\n\tdictWord{13, 10, 77},\n\tdictWord{141, 10, 274},\n\tdictWord{4, 0, 444},\n\tdictWord{10, 0, 146},\n\tdictWord{140, 0, 9},\n\tdictWord{139, 11, 163},\n\tdictWord{7, 0, 1260},\n\tdictWord{135, 0, 1790},\n\tdictWord{9, 0, 222},\n\tdictWord{10, 0, 43},\n\tdictWord{139, 0, 900},\n\tdictWord{137, 11, 234},\n\tdictWord{138, 0, 971},\n\tdictWord{137, 0, 761},\n\tdictWord{134, 0, 699},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t434,\n\t},\n\tdictWord{6, 0, 1116},\n\tdictWord{7, 0, 1366},\n\tdictWord{5, 10, 20},\n\tdictWord{6, 11, 197},\n\tdictWord{6, 10, 298},\n\tdictWord{7, 10, 659},\n\tdictWord{8, 11, 205},\n\tdictWord{137, 10, 219},\n\tdictWord{132, 11, 490},\n\tdictWord{11, 11, 820},\n\tdictWord{150, 11, 51},\n\tdictWord{7, 10, 1440},\n\tdictWord{11, 10, 854},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t872,\n\t},\n\tdictWord{11, 10, 921},\n\tdictWord{12, 10, 551},\n\tdictWord{13, 10, 472},\n\tdictWord{142, 10, 367},\n\tdictWord{140, 11, 13},\n\tdictWord{132, 0, 829},\n\tdictWord{12, 0, 242},\n\tdictWord{132, 10, 439},\n\tdictWord{136, 10, 669},\n\tdictWord{6, 0, 593},\n\tdictWord{6, 11, 452},\n\tdictWord{7, 11, 312},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t219,\n\t},\n\tdictWord{4, 11, 333},\n\tdictWord{9, 11, 176},\n\tdictWord{12, 11, 353},\n\tdictWord{141, 11, 187},\n\tdictWord{7, 0, 36},\n\tdictWord{8, 0, 201},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t605,\n\t},\n\tdictWord{140, 0, 224},\n\tdictWord{132, 10, 233},\n\tdictWord{134, 0, 1430},\n\tdictWord{134, 0, 1806},\n\tdictWord{4, 0, 523},\n\tdictWord{133, 0, 638},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1889,\n\t},\n\tdictWord{9, 0, 958},\n\tdictWord{9, 0, 971},\n\tdictWord{9, 0, 976},\n\tdictWord{12, 0, 796},\n\tdictWord{12, 0, 799},\n\tdictWord{12, 0, 808},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t835,\n\t},\n\tdictWord{12, 0, 836},\n\tdictWord{12, 0, 914},\n\tdictWord{12, 0, 946},\n\tdictWord{15, 0, 216},\n\tdictWord{15, 0, 232},\n\tdictWord{18, 0, 183},\n\tdictWord{18, 0, 187},\n\tdictWord{18, 0, 194},\n\tdictWord{18, 0, 212},\n\tdictWord{18, 0, 232},\n\tdictWord{149, 0, 49},\n\tdictWord{132, 10, 482},\n\tdictWord{6, 0, 827},\n\tdictWord{134, 0, 1434},\n\tdictWord{135, 10, 346},\n\tdictWord{134, 0, 2043},\n\tdictWord{6, 0, 242},\n\tdictWord{7, 0, 227},\n\tdictWord{7, 0, 1581},\n\tdictWord{8, 0, 104},\n\tdictWord{9, 0, 113},\n\tdictWord{9, 0, 220},\n\tdictWord{9, 0, 427},\n\tdictWord{10, 0, 136},\n\tdictWord{10, 0, 239},\n\tdictWord{11, 0, 579},\n\tdictWord{11, 0, 1023},\n\tdictWord{13, 0, 4},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t204,\n\t},\n\tdictWord{13, 0, 316},\n\tdictWord{148, 0, 86},\n\tdictWord{134, 11, 1685},\n\tdictWord{7, 0, 148},\n\tdictWord{8, 0, 284},\n\tdictWord{141, 0, 63},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t10,\n\t},\n\tdictWord{135, 11, 584},\n\tdictWord{134, 0, 1249},\n\tdictWord{7, 0, 861},\n\tdictWord{135, 10, 334},\n\tdictWord{5, 10, 795},\n\tdictWord{6, 10, 1741},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t70,\n\t},\n\tdictWord{132, 0, 807},\n\tdictWord{7, 11, 135},\n\tdictWord{8, 11, 7},\n\tdictWord{8, 11, 62},\n\tdictWord{9, 11, 243},\n\tdictWord{10, 11, 658},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t697,\n\t},\n\tdictWord{11, 11, 456},\n\tdictWord{139, 11, 756},\n\tdictWord{9, 11, 395},\n\tdictWord{138, 11, 79},\n\tdictWord{137, 11, 108},\n\tdictWord{147, 0, 94},\n\tdictWord{136, 0, 494},\n\tdictWord{135, 11, 631},\n\tdictWord{135, 10, 622},\n\tdictWord{7, 0, 1510},\n\tdictWord{135, 10, 1750},\n\tdictWord{4, 10, 203},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1936,\n\t},\n\tdictWord{7, 11, 406},\n\tdictWord{7, 11, 459},\n\tdictWord{8, 11, 606},\n\tdictWord{139, 11, 726},\n\tdictWord{7, 0, 1306},\n\tdictWord{8, 0, 505},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t482,\n\t},\n\tdictWord{10, 0, 126},\n\tdictWord{11, 0, 225},\n\tdictWord{12, 0, 347},\n\tdictWord{12, 0, 449},\n\tdictWord{13, 0, 19},\n\tdictWord{14, 0, 218},\n\tdictWord{142, 0, 435},\n\tdictWord{5, 0, 268},\n\tdictWord{10, 0, 764},\n\tdictWord{12, 0, 120},\n\tdictWord{13, 0, 39},\n\tdictWord{145, 0, 127},\n\tdictWord{142, 11, 68},\n\tdictWord{11, 10, 678},\n\tdictWord{140, 10, 307},\n\tdictWord{12, 11, 268},\n\tdictWord{12, 11, 640},\n\tdictWord{142, 11, 119},\n\tdictWord{135, 10, 2044},\n\tdictWord{133, 11, 612},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t372,\n\t},\n\tdictWord{7, 11, 482},\n\tdictWord{8, 11, 158},\n\tdictWord{9, 11, 602},\n\tdictWord{9, 11, 615},\n\tdictWord{10, 11, 245},\n\tdictWord{10, 11, 678},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t744,\n\t},\n\tdictWord{11, 11, 248},\n\tdictWord{139, 11, 806},\n\tdictWord{7, 10, 311},\n\tdictWord{9, 10, 308},\n\tdictWord{140, 10, 255},\n\tdictWord{4, 0, 384},\n\tdictWord{135, 0, 1022},\n\tdictWord{5, 11, 854},\n\tdictWord{135, 11, 1991},\n\tdictWord{135, 10, 1266},\n\tdictWord{4, 10, 400},\n\tdictWord{5, 10, 267},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t232,\n\t},\n\tdictWord{135, 0, 1703},\n\tdictWord{9, 0, 159},\n\tdictWord{11, 0, 661},\n\tdictWord{140, 0, 603},\n\tdictWord{4, 0, 964},\n\tdictWord{14, 0, 438},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t444,\n\t},\n\tdictWord{14, 0, 456},\n\tdictWord{22, 0, 60},\n\tdictWord{22, 0, 63},\n\tdictWord{9, 11, 106},\n\tdictWord{9, 11, 163},\n\tdictWord{9, 11, 296},\n\tdictWord{10, 11, 167},\n\tdictWord{10, 11, 172},\n\tdictWord{10, 11, 777},\n\tdictWord{139, 11, 16},\n\tdictWord{136, 0, 583},\n\tdictWord{132, 0, 515},\n\tdictWord{8, 0, 632},\n\tdictWord{8, 0, 697},\n\tdictWord{137, 0, 854},\n\tdictWord{5, 11, 195},\n\tdictWord{135, 11, 1685},\n\tdictWord{6, 0, 1123},\n\tdictWord{134, 0, 1365},\n\tdictWord{134, 11, 328},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1997,\n\t},\n\tdictWord{8, 11, 730},\n\tdictWord{139, 11, 1006},\n\tdictWord{4, 0, 136},\n\tdictWord{133, 0, 551},\n\tdictWord{134, 0, 1782},\n\tdictWord{7, 0, 1287},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t44,\n\t},\n\tdictWord{10, 0, 552},\n\tdictWord{10, 0, 642},\n\tdictWord{11, 0, 839},\n\tdictWord{12, 0, 274},\n\tdictWord{12, 0, 275},\n\tdictWord{12, 0, 372},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t91,\n\t},\n\tdictWord{142, 0, 125},\n\tdictWord{5, 11, 751},\n\tdictWord{11, 11, 797},\n\tdictWord{140, 11, 203},\n\tdictWord{133, 0, 732},\n\tdictWord{7, 0, 679},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t313,\n\t},\n\tdictWord{4, 10, 100},\n\tdictWord{135, 11, 821},\n\tdictWord{10, 0, 361},\n\tdictWord{142, 0, 316},\n\tdictWord{134, 0, 595},\n\tdictWord{6, 0, 147},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t886,\n\t},\n\tdictWord{9, 0, 753},\n\tdictWord{138, 0, 268},\n\tdictWord{5, 10, 362},\n\tdictWord{5, 10, 443},\n\tdictWord{6, 10, 318},\n\tdictWord{7, 10, 1019},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t623,\n\t},\n\tdictWord{5, 10, 463},\n\tdictWord{136, 10, 296},\n\tdictWord{4, 10, 454},\n\tdictWord{5, 11, 950},\n\tdictWord{5, 11, 994},\n\tdictWord{134, 11, 351},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t137,\n\t},\n\tdictWord{5, 10, 48},\n\tdictWord{5, 10, 404},\n\tdictWord{6, 10, 557},\n\tdictWord{7, 10, 458},\n\tdictWord{8, 10, 597},\n\tdictWord{10, 10, 455},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t606,\n\t},\n\tdictWord{11, 10, 49},\n\tdictWord{11, 10, 548},\n\tdictWord{12, 10, 476},\n\tdictWord{13, 10, 18},\n\tdictWord{141, 10, 450},\n\tdictWord{133, 0, 414},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1762,\n\t},\n\tdictWord{5, 11, 421},\n\tdictWord{135, 11, 47},\n\tdictWord{5, 10, 442},\n\tdictWord{135, 10, 1984},\n\tdictWord{134, 0, 599},\n\tdictWord{134, 0, 1749},\n\tdictWord{134, 0, 1627},\n\tdictWord{4, 0, 488},\n\tdictWord{132, 11, 350},\n\tdictWord{137, 11, 751},\n\tdictWord{132, 0, 83},\n\tdictWord{140, 0, 676},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t967,\n\t},\n\tdictWord{7, 0, 1639},\n\tdictWord{5, 10, 55},\n\tdictWord{140, 10, 161},\n\tdictWord{4, 11, 473},\n\tdictWord{7, 11, 623},\n\tdictWord{8, 11, 808},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t871,\n\t},\n\tdictWord{9, 11, 893},\n\tdictWord{11, 11, 38},\n\tdictWord{11, 11, 431},\n\tdictWord{12, 11, 112},\n\tdictWord{12, 11, 217},\n\tdictWord{12, 11, 243},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t562,\n\t},\n\tdictWord{12, 11, 683},\n\tdictWord{13, 11, 141},\n\tdictWord{13, 11, 197},\n\tdictWord{13, 11, 227},\n\tdictWord{13, 11, 406},\n\tdictWord{13, 11, 487},\n\tdictWord{14, 11, 156},\n\tdictWord{14, 11, 203},\n\tdictWord{14, 11, 224},\n\tdictWord{14, 11, 256},\n\tdictWord{18, 11, 58},\n\tdictWord{150, 11, 0},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t450,\n\t},\n\tdictWord{7, 11, 736},\n\tdictWord{139, 11, 264},\n\tdictWord{134, 0, 278},\n\tdictWord{4, 11, 222},\n\tdictWord{7, 11, 286},\n\tdictWord{136, 11, 629},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t869,\n\t},\n\tdictWord{140, 0, 97},\n\tdictWord{144, 0, 14},\n\tdictWord{134, 0, 1085},\n\tdictWord{4, 10, 213},\n\tdictWord{7, 10, 223},\n\tdictWord{136, 10, 80},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t388,\n\t},\n\tdictWord{7, 0, 644},\n\tdictWord{139, 0, 781},\n\tdictWord{132, 0, 849},\n\tdictWord{7, 0, 229},\n\tdictWord{8, 0, 59},\n\tdictWord{9, 0, 190},\n\tdictWord{10, 0, 378},\n\tdictWord{140, 0, 191},\n\tdictWord{7, 10, 381},\n\tdictWord{7, 10, 806},\n\tdictWord{7, 10, 820},\n\tdictWord{8, 10, 354},\n\tdictWord{8, 10, 437},\n\tdictWord{8, 10, 787},\n\tdictWord{9, 10, 657},\n\tdictWord{10, 10, 58},\n\tdictWord{10, 10, 339},\n\tdictWord{10, 10, 749},\n\tdictWord{11, 10, 914},\n\tdictWord{12, 10, 162},\n\tdictWord{13, 10, 75},\n\tdictWord{14, 10, 106},\n\tdictWord{14, 10, 198},\n\tdictWord{14, 10, 320},\n\tdictWord{14, 10, 413},\n\tdictWord{146, 10, 43},\n\tdictWord{141, 11, 306},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t747,\n\t},\n\tdictWord{134, 0, 1115},\n\tdictWord{16, 0, 94},\n\tdictWord{16, 0, 108},\n\tdictWord{136, 11, 146},\n\tdictWord{6, 0, 700},\n\tdictWord{6, 0, 817},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1002,\n\t},\n\tdictWord{133, 10, 692},\n\tdictWord{4, 11, 465},\n\tdictWord{135, 11, 1663},\n\tdictWord{134, 10, 191},\n\tdictWord{6, 0, 1414},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t913,\n\t},\n\tdictWord{132, 0, 660},\n\tdictWord{7, 0, 1035},\n\tdictWord{138, 0, 737},\n\tdictWord{6, 10, 162},\n\tdictWord{7, 10, 1960},\n\tdictWord{136, 10, 831},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t706,\n\t},\n\tdictWord{7, 0, 690},\n\tdictWord{9, 0, 217},\n\tdictWord{9, 0, 587},\n\tdictWord{140, 0, 521},\n\tdictWord{138, 10, 426},\n\tdictWord{135, 10, 1235},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t82,\n\t},\n\tdictWord{7, 11, 138},\n\tdictWord{7, 11, 517},\n\tdictWord{9, 11, 673},\n\tdictWord{139, 11, 238},\n\tdictWord{138, 0, 272},\n\tdictWord{5, 11, 495},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t834,\n\t},\n\tdictWord{9, 11, 733},\n\tdictWord{139, 11, 378},\n\tdictWord{134, 0, 1744},\n\tdictWord{132, 0, 1011},\n\tdictWord{7, 11, 828},\n\tdictWord{142, 11, 116},\n\tdictWord{4, 0, 733},\n\tdictWord{9, 0, 194},\n\tdictWord{10, 0, 92},\n\tdictWord{11, 0, 198},\n\tdictWord{12, 0, 84},\n\tdictWord{13, 0, 128},\n\tdictWord{133, 11, 559},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t57,\n\t},\n\tdictWord{10, 0, 277},\n\tdictWord{6, 11, 21},\n\tdictWord{6, 11, 1737},\n\tdictWord{7, 11, 1444},\n\tdictWord{136, 11, 224},\n\tdictWord{4, 10, 204},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t902,\n\t},\n\tdictWord{136, 10, 833},\n\tdictWord{11, 0, 348},\n\tdictWord{12, 0, 99},\n\tdictWord{18, 0, 1},\n\tdictWord{18, 0, 11},\n\tdictWord{19, 0, 4},\n\tdictWord{7, 10, 366},\n\tdictWord{9, 10, 287},\n\tdictWord{12, 10, 199},\n\tdictWord{12, 10, 556},\n\tdictWord{140, 10, 577},\n\tdictWord{6, 0, 1981},\n\tdictWord{136, 0, 936},\n\tdictWord{\n\t\t21,\n\t\t0,\n\t\t33,\n\t},\n\tdictWord{150, 0, 40},\n\tdictWord{5, 11, 519},\n\tdictWord{138, 11, 204},\n\tdictWord{5, 10, 356},\n\tdictWord{135, 10, 224},\n\tdictWord{134, 0, 775},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t306,\n\t},\n\tdictWord{7, 10, 630},\n\tdictWord{9, 10, 567},\n\tdictWord{11, 10, 150},\n\tdictWord{11, 10, 444},\n\tdictWord{141, 10, 119},\n\tdictWord{5, 0, 979},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t539,\n\t},\n\tdictWord{133, 0, 611},\n\tdictWord{4, 11, 402},\n\tdictWord{135, 11, 1679},\n\tdictWord{5, 0, 178},\n\tdictWord{7, 11, 2},\n\tdictWord{8, 11, 323},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t479,\n\t},\n\tdictWord{5, 11, 59},\n\tdictWord{135, 11, 672},\n\tdictWord{4, 0, 1010},\n\tdictWord{6, 0, 1969},\n\tdictWord{138, 11, 237},\n\tdictWord{133, 11, 412},\n\tdictWord{146, 11, 34},\n\tdictWord{7, 11, 1740},\n\tdictWord{146, 11, 48},\n\tdictWord{134, 0, 664},\n\tdictWord{139, 10, 814},\n\tdictWord{4, 11, 85},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t549,\n\t},\n\tdictWord{133, 11, 94},\n\tdictWord{133, 11, 457},\n\tdictWord{132, 0, 390},\n\tdictWord{134, 0, 1510},\n\tdictWord{4, 10, 235},\n\tdictWord{135, 10, 255},\n\tdictWord{4, 10, 194},\n\tdictWord{5, 10, 584},\n\tdictWord{6, 11, 11},\n\tdictWord{6, 10, 384},\n\tdictWord{7, 11, 187},\n\tdictWord{7, 10, 583},\n\tdictWord{10, 10, 761},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t760,\n\t},\n\tdictWord{139, 10, 851},\n\tdictWord{4, 11, 522},\n\tdictWord{139, 11, 802},\n\tdictWord{135, 0, 493},\n\tdictWord{10, 11, 776},\n\tdictWord{13, 11, 345},\n\tdictWord{142, 11, 425},\n\tdictWord{146, 0, 37},\n\tdictWord{4, 11, 52},\n\tdictWord{135, 11, 661},\n\tdictWord{134, 0, 724},\n\tdictWord{134, 0, 829},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t520,\n\t},\n\tdictWord{133, 10, 562},\n\tdictWord{4, 11, 281},\n\tdictWord{5, 11, 38},\n\tdictWord{7, 11, 194},\n\tdictWord{7, 11, 668},\n\tdictWord{7, 11, 1893},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t397,\n\t},\n\tdictWord{5, 10, 191},\n\tdictWord{137, 10, 271},\n\tdictWord{7, 0, 1537},\n\tdictWord{14, 0, 96},\n\tdictWord{143, 0, 73},\n\tdictWord{5, 0, 473},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t168,\n\t},\n\tdictWord{4, 10, 470},\n\tdictWord{6, 10, 153},\n\tdictWord{7, 10, 1503},\n\tdictWord{7, 10, 1923},\n\tdictWord{10, 10, 701},\n\tdictWord{11, 10, 132},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t227,\n\t},\n\tdictWord{11, 10, 320},\n\tdictWord{11, 10, 436},\n\tdictWord{11, 10, 525},\n\tdictWord{11, 10, 855},\n\tdictWord{12, 10, 41},\n\tdictWord{12, 10, 286},\n\tdictWord{13, 10, 103},\n\tdictWord{13, 10, 284},\n\tdictWord{14, 10, 255},\n\tdictWord{14, 10, 262},\n\tdictWord{15, 10, 117},\n\tdictWord{143, 10, 127},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t105,\n\t},\n\tdictWord{5, 0, 438},\n\tdictWord{9, 0, 694},\n\tdictWord{12, 0, 627},\n\tdictWord{141, 0, 210},\n\tdictWord{133, 10, 327},\n\tdictWord{6, 10, 552},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1754,\n\t},\n\tdictWord{137, 10, 604},\n\tdictWord{134, 0, 1256},\n\tdictWord{152, 0, 11},\n\tdictWord{5, 11, 448},\n\tdictWord{11, 11, 98},\n\tdictWord{139, 11, 524},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1626,\n\t},\n\tdictWord{5, 10, 80},\n\tdictWord{6, 10, 405},\n\tdictWord{7, 10, 403},\n\tdictWord{7, 10, 1502},\n\tdictWord{8, 10, 456},\n\tdictWord{9, 10, 487},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t853,\n\t},\n\tdictWord{9, 10, 889},\n\tdictWord{10, 10, 309},\n\tdictWord{11, 10, 721},\n\tdictWord{11, 10, 994},\n\tdictWord{12, 10, 430},\n\tdictWord{13, 10, 165},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t16,\n\t},\n\tdictWord{146, 11, 44},\n\tdictWord{132, 0, 779},\n\tdictWord{8, 0, 25},\n\tdictWord{138, 0, 826},\n\tdictWord{4, 10, 453},\n\tdictWord{5, 10, 887},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t535,\n\t},\n\tdictWord{8, 10, 6},\n\tdictWord{8, 10, 543},\n\tdictWord{136, 10, 826},\n\tdictWord{137, 11, 461},\n\tdictWord{140, 11, 632},\n\tdictWord{132, 0, 308},\n\tdictWord{135, 0, 741},\n\tdictWord{132, 0, 671},\n\tdictWord{7, 0, 150},\n\tdictWord{8, 0, 649},\n\tdictWord{136, 0, 1020},\n\tdictWord{9, 0, 99},\n\tdictWord{6, 11, 336},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t552,\n\t},\n\tdictWord{9, 11, 285},\n\tdictWord{10, 11, 99},\n\tdictWord{139, 11, 568},\n\tdictWord{134, 0, 521},\n\tdictWord{5, 0, 339},\n\tdictWord{14, 0, 3},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t41,\n\t},\n\tdictWord{15, 0, 166},\n\tdictWord{147, 0, 66},\n\tdictWord{6, 11, 423},\n\tdictWord{7, 11, 665},\n\tdictWord{7, 11, 1210},\n\tdictWord{9, 11, 218},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t222,\n\t},\n\tdictWord{6, 0, 543},\n\tdictWord{5, 10, 101},\n\tdictWord{5, 11, 256},\n\tdictWord{6, 10, 88},\n\tdictWord{7, 10, 1677},\n\tdictWord{9, 10, 100},\n\tdictWord{10, 10, 677},\n\tdictWord{14, 10, 169},\n\tdictWord{14, 10, 302},\n\tdictWord{14, 10, 313},\n\tdictWord{15, 10, 48},\n\tdictWord{143, 10, 84},\n\tdictWord{4, 10, 310},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t708,\n\t},\n\tdictWord{7, 10, 996},\n\tdictWord{9, 10, 795},\n\tdictWord{10, 10, 390},\n\tdictWord{10, 10, 733},\n\tdictWord{11, 10, 451},\n\tdictWord{12, 10, 249},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t115,\n\t},\n\tdictWord{14, 10, 286},\n\tdictWord{143, 10, 100},\n\tdictWord{133, 10, 587},\n\tdictWord{13, 11, 417},\n\tdictWord{14, 11, 129},\n\tdictWord{143, 11, 15},\n\tdictWord{134, 0, 1358},\n\tdictWord{136, 11, 554},\n\tdictWord{132, 10, 498},\n\tdictWord{7, 10, 217},\n\tdictWord{8, 10, 140},\n\tdictWord{138, 10, 610},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t989,\n\t},\n\tdictWord{135, 11, 634},\n\tdictWord{6, 0, 155},\n\tdictWord{140, 0, 234},\n\tdictWord{135, 11, 462},\n\tdictWord{132, 11, 618},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1628,\n\t},\n\tdictWord{132, 0, 766},\n\tdictWord{4, 11, 339},\n\tdictWord{5, 10, 905},\n\tdictWord{135, 11, 259},\n\tdictWord{135, 0, 829},\n\tdictWord{4, 11, 759},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t169,\n\t},\n\tdictWord{7, 0, 1445},\n\tdictWord{4, 10, 456},\n\tdictWord{7, 10, 358},\n\tdictWord{7, 10, 1637},\n\tdictWord{8, 10, 643},\n\tdictWord{139, 10, 483},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t486,\n\t},\n\tdictWord{135, 0, 1349},\n\tdictWord{5, 11, 688},\n\tdictWord{135, 11, 712},\n\tdictWord{7, 0, 1635},\n\tdictWord{8, 0, 17},\n\tdictWord{10, 0, 217},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t295,\n\t},\n\tdictWord{12, 0, 2},\n\tdictWord{140, 11, 2},\n\tdictWord{138, 0, 558},\n\tdictWord{150, 10, 56},\n\tdictWord{4, 11, 278},\n\tdictWord{5, 11, 465},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1367,\n\t},\n\tdictWord{136, 11, 482},\n\tdictWord{133, 10, 535},\n\tdictWord{6, 0, 1362},\n\tdictWord{6, 0, 1461},\n\tdictWord{10, 11, 274},\n\tdictWord{10, 11, 625},\n\tdictWord{139, 11, 530},\n\tdictWord{5, 0, 599},\n\tdictWord{5, 11, 336},\n\tdictWord{6, 11, 341},\n\tdictWord{6, 11, 478},\n\tdictWord{6, 11, 1763},\n\tdictWord{136, 11, 386},\n\tdictWord{7, 10, 1748},\n\tdictWord{137, 11, 151},\n\tdictWord{134, 0, 1376},\n\tdictWord{133, 10, 539},\n\tdictWord{135, 11, 73},\n\tdictWord{135, 11, 1971},\n\tdictWord{139, 11, 283},\n\tdictWord{9, 0, 93},\n\tdictWord{139, 0, 474},\n\tdictWord{6, 10, 91},\n\tdictWord{135, 10, 435},\n\tdictWord{6, 0, 447},\n\tdictWord{5, 11, 396},\n\tdictWord{134, 11, 501},\n\tdictWord{4, 10, 16},\n\tdictWord{5, 10, 316},\n\tdictWord{5, 10, 842},\n\tdictWord{6, 10, 370},\n\tdictWord{6, 10, 1778},\n\tdictWord{8, 10, 166},\n\tdictWord{11, 10, 812},\n\tdictWord{12, 10, 206},\n\tdictWord{12, 10, 351},\n\tdictWord{14, 10, 418},\n\tdictWord{16, 10, 15},\n\tdictWord{16, 10, 34},\n\tdictWord{18, 10, 3},\n\tdictWord{19, 10, 3},\n\tdictWord{19, 10, 7},\n\tdictWord{20, 10, 4},\n\tdictWord{149, 10, 21},\n\tdictWord{7, 0, 577},\n\tdictWord{7, 0, 1432},\n\tdictWord{9, 0, 475},\n\tdictWord{9, 0, 505},\n\tdictWord{9, 0, 526},\n\tdictWord{9, 0, 609},\n\tdictWord{9, 0, 689},\n\tdictWord{9, 0, 726},\n\tdictWord{9, 0, 735},\n\tdictWord{9, 0, 738},\n\tdictWord{10, 0, 556},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t674,\n\t},\n\tdictWord{10, 0, 684},\n\tdictWord{11, 0, 89},\n\tdictWord{11, 0, 202},\n\tdictWord{11, 0, 272},\n\tdictWord{11, 0, 380},\n\tdictWord{11, 0, 415},\n\tdictWord{11, 0, 505},\n\tdictWord{11, 0, 537},\n\tdictWord{11, 0, 550},\n\tdictWord{11, 0, 562},\n\tdictWord{11, 0, 640},\n\tdictWord{11, 0, 667},\n\tdictWord{11, 0, 688},\n\tdictWord{11, 0, 847},\n\tdictWord{11, 0, 927},\n\tdictWord{11, 0, 930},\n\tdictWord{11, 0, 940},\n\tdictWord{12, 0, 144},\n\tdictWord{12, 0, 325},\n\tdictWord{12, 0, 329},\n\tdictWord{12, 0, 389},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t403,\n\t},\n\tdictWord{12, 0, 451},\n\tdictWord{12, 0, 515},\n\tdictWord{12, 0, 604},\n\tdictWord{12, 0, 616},\n\tdictWord{12, 0, 626},\n\tdictWord{13, 0, 66},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t131,\n\t},\n\tdictWord{13, 0, 167},\n\tdictWord{13, 0, 236},\n\tdictWord{13, 0, 368},\n\tdictWord{13, 0, 411},\n\tdictWord{13, 0, 434},\n\tdictWord{13, 0, 453},\n\tdictWord{13, 0, 461},\n\tdictWord{13, 0, 474},\n\tdictWord{14, 0, 59},\n\tdictWord{14, 0, 60},\n\tdictWord{14, 0, 139},\n\tdictWord{14, 0, 152},\n\tdictWord{14, 0, 276},\n\tdictWord{14, 0, 353},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t402,\n\t},\n\tdictWord{15, 0, 28},\n\tdictWord{15, 0, 81},\n\tdictWord{15, 0, 123},\n\tdictWord{15, 0, 152},\n\tdictWord{18, 0, 136},\n\tdictWord{148, 0, 88},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t929,\n\t},\n\tdictWord{133, 11, 799},\n\tdictWord{136, 11, 46},\n\tdictWord{142, 0, 307},\n\tdictWord{4, 0, 609},\n\tdictWord{7, 0, 756},\n\tdictWord{9, 0, 544},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t413,\n\t},\n\tdictWord{144, 0, 25},\n\tdictWord{10, 0, 687},\n\tdictWord{7, 10, 619},\n\tdictWord{10, 10, 547},\n\tdictWord{11, 10, 122},\n\tdictWord{140, 10, 601},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t930,\n\t},\n\tdictWord{133, 0, 947},\n\tdictWord{133, 0, 939},\n\tdictWord{142, 0, 21},\n\tdictWord{4, 11, 892},\n\tdictWord{133, 11, 770},\n\tdictWord{133, 0, 962},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t651,\n\t},\n\tdictWord{8, 0, 170},\n\tdictWord{9, 0, 61},\n\tdictWord{9, 0, 63},\n\tdictWord{10, 0, 23},\n\tdictWord{10, 0, 37},\n\tdictWord{10, 0, 834},\n\tdictWord{11, 0, 4},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t187,\n\t},\n\tdictWord{11, 0, 281},\n\tdictWord{11, 0, 503},\n\tdictWord{11, 0, 677},\n\tdictWord{12, 0, 96},\n\tdictWord{12, 0, 130},\n\tdictWord{12, 0, 244},\n\tdictWord{14, 0, 5},\n\tdictWord{14, 0, 40},\n\tdictWord{14, 0, 162},\n\tdictWord{14, 0, 202},\n\tdictWord{146, 0, 133},\n\tdictWord{4, 0, 406},\n\tdictWord{5, 0, 579},\n\tdictWord{12, 0, 492},\n\tdictWord{\n\t\t150,\n\t\t0,\n\t\t15,\n\t},\n\tdictWord{135, 11, 158},\n\tdictWord{135, 0, 597},\n\tdictWord{132, 0, 981},\n\tdictWord{132, 10, 888},\n\tdictWord{4, 10, 149},\n\tdictWord{138, 10, 368},\n\tdictWord{132, 0, 545},\n\tdictWord{4, 10, 154},\n\tdictWord{7, 10, 1134},\n\tdictWord{136, 10, 105},\n\tdictWord{135, 11, 2001},\n\tdictWord{134, 0, 1558},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t31,\n\t},\n\tdictWord{6, 10, 429},\n\tdictWord{7, 10, 962},\n\tdictWord{9, 10, 458},\n\tdictWord{139, 10, 691},\n\tdictWord{132, 10, 312},\n\tdictWord{135, 10, 1642},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t17,\n\t},\n\tdictWord{6, 0, 1304},\n\tdictWord{7, 0, 16},\n\tdictWord{7, 0, 1001},\n\tdictWord{9, 0, 886},\n\tdictWord{10, 0, 489},\n\tdictWord{10, 0, 800},\n\tdictWord{11, 0, 782},\n\tdictWord{12, 0, 320},\n\tdictWord{13, 0, 467},\n\tdictWord{14, 0, 145},\n\tdictWord{14, 0, 387},\n\tdictWord{143, 0, 119},\n\tdictWord{135, 0, 1982},\n\tdictWord{17, 0, 17},\n\tdictWord{7, 11, 1461},\n\tdictWord{140, 11, 91},\n\tdictWord{4, 10, 236},\n\tdictWord{132, 11, 602},\n\tdictWord{138, 0, 907},\n\tdictWord{136, 0, 110},\n\tdictWord{7, 0, 272},\n\tdictWord{19, 0, 53},\n\tdictWord{5, 10, 836},\n\tdictWord{5, 10, 857},\n\tdictWord{134, 10, 1680},\n\tdictWord{5, 0, 458},\n\tdictWord{7, 11, 1218},\n\tdictWord{136, 11, 303},\n\tdictWord{7, 0, 1983},\n\tdictWord{8, 0, 0},\n\tdictWord{8, 0, 171},\n\tdictWord{9, 0, 120},\n\tdictWord{9, 0, 732},\n\tdictWord{10, 0, 473},\n\tdictWord{11, 0, 656},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t998,\n\t},\n\tdictWord{18, 0, 0},\n\tdictWord{18, 0, 2},\n\tdictWord{19, 0, 21},\n\tdictWord{10, 10, 68},\n\tdictWord{139, 10, 494},\n\tdictWord{137, 11, 662},\n\tdictWord{4, 11, 13},\n\tdictWord{5, 11, 567},\n\tdictWord{7, 11, 1498},\n\tdictWord{9, 11, 124},\n\tdictWord{11, 11, 521},\n\tdictWord{140, 11, 405},\n\tdictWord{4, 10, 81},\n\tdictWord{139, 10, 867},\n\tdictWord{135, 11, 1006},\n\tdictWord{7, 11, 800},\n\tdictWord{7, 11, 1783},\n\tdictWord{138, 11, 12},\n\tdictWord{9, 0, 295},\n\tdictWord{10, 0, 443},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t282,\n\t},\n\tdictWord{8, 10, 650},\n\tdictWord{137, 10, 907},\n\tdictWord{132, 11, 735},\n\tdictWord{4, 11, 170},\n\tdictWord{4, 10, 775},\n\tdictWord{135, 11, 323},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1844,\n\t},\n\tdictWord{10, 0, 924},\n\tdictWord{11, 11, 844},\n\tdictWord{12, 11, 104},\n\tdictWord{140, 11, 625},\n\tdictWord{5, 11, 304},\n\tdictWord{7, 11, 1403},\n\tdictWord{140, 11, 498},\n\tdictWord{134, 0, 1232},\n\tdictWord{4, 0, 519},\n\tdictWord{10, 0, 70},\n\tdictWord{12, 0, 26},\n\tdictWord{14, 0, 17},\n\tdictWord{14, 0, 178},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t34,\n\t},\n\tdictWord{149, 0, 12},\n\tdictWord{132, 0, 993},\n\tdictWord{4, 11, 148},\n\tdictWord{133, 11, 742},\n\tdictWord{6, 0, 31},\n\tdictWord{7, 0, 491},\n\tdictWord{7, 0, 530},\n\tdictWord{8, 0, 592},\n\tdictWord{11, 0, 53},\n\tdictWord{11, 0, 779},\n\tdictWord{12, 0, 167},\n\tdictWord{12, 0, 411},\n\tdictWord{14, 0, 14},\n\tdictWord{14, 0, 136},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t72,\n\t},\n\tdictWord{16, 0, 17},\n\tdictWord{144, 0, 72},\n\tdictWord{133, 0, 907},\n\tdictWord{134, 0, 733},\n\tdictWord{133, 11, 111},\n\tdictWord{4, 10, 71},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t376,\n\t},\n\tdictWord{7, 10, 119},\n\tdictWord{138, 10, 665},\n\tdictWord{136, 0, 55},\n\tdictWord{8, 0, 430},\n\tdictWord{136, 11, 430},\n\tdictWord{4, 0, 208},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t106,\n\t},\n\tdictWord{6, 0, 531},\n\tdictWord{8, 0, 408},\n\tdictWord{9, 0, 188},\n\tdictWord{138, 0, 572},\n\tdictWord{12, 0, 56},\n\tdictWord{11, 10, 827},\n\tdictWord{14, 10, 34},\n\tdictWord{143, 10, 148},\n\tdictWord{134, 0, 1693},\n\tdictWord{133, 11, 444},\n\tdictWord{132, 10, 479},\n\tdictWord{140, 0, 441},\n\tdictWord{9, 0, 449},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t192,\n\t},\n\tdictWord{138, 0, 740},\n\tdictWord{134, 0, 928},\n\tdictWord{4, 0, 241},\n\tdictWord{7, 10, 607},\n\tdictWord{136, 10, 99},\n\tdictWord{8, 11, 123},\n\tdictWord{\n\t\t15,\n\t\t11,\n\t\t6,\n\t},\n\tdictWord{144, 11, 7},\n\tdictWord{6, 11, 285},\n\tdictWord{8, 11, 654},\n\tdictWord{11, 11, 749},\n\tdictWord{12, 11, 190},\n\tdictWord{12, 11, 327},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t120,\n\t},\n\tdictWord{13, 11, 121},\n\tdictWord{13, 11, 327},\n\tdictWord{15, 11, 47},\n\tdictWord{146, 11, 40},\n\tdictWord{4, 10, 41},\n\tdictWord{5, 10, 74},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1627,\n\t},\n\tdictWord{11, 10, 871},\n\tdictWord{140, 10, 619},\n\tdictWord{7, 0, 1525},\n\tdictWord{11, 10, 329},\n\tdictWord{11, 10, 965},\n\tdictWord{12, 10, 241},\n\tdictWord{14, 10, 354},\n\tdictWord{15, 10, 22},\n\tdictWord{148, 10, 63},\n\tdictWord{132, 0, 259},\n\tdictWord{135, 11, 183},\n\tdictWord{9, 10, 209},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t300,\n\t},\n\tdictWord{5, 11, 937},\n\tdictWord{135, 11, 100},\n\tdictWord{133, 10, 98},\n\tdictWord{4, 0, 173},\n\tdictWord{5, 0, 312},\n\tdictWord{5, 0, 512},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1285,\n\t},\n\tdictWord{141, 0, 185},\n\tdictWord{7, 0, 1603},\n\tdictWord{7, 0, 1691},\n\tdictWord{9, 0, 464},\n\tdictWord{11, 0, 195},\n\tdictWord{12, 0, 279},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t448,\n\t},\n\tdictWord{14, 0, 11},\n\tdictWord{147, 0, 102},\n\tdictWord{135, 0, 1113},\n\tdictWord{133, 10, 984},\n\tdictWord{4, 0, 452},\n\tdictWord{5, 0, 583},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t720,\n\t},\n\tdictWord{4, 0, 547},\n\tdictWord{5, 0, 817},\n\tdictWord{6, 0, 433},\n\tdictWord{7, 0, 593},\n\tdictWord{7, 0, 1378},\n\tdictWord{8, 0, 161},\n\tdictWord{9, 0, 284},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t313,\n\t},\n\tdictWord{139, 0, 886},\n\tdictWord{8, 0, 722},\n\tdictWord{4, 10, 182},\n\tdictWord{6, 10, 205},\n\tdictWord{135, 10, 220},\n\tdictWord{150, 0, 13},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t42,\n\t},\n\tdictWord{9, 10, 205},\n\tdictWord{9, 10, 786},\n\tdictWord{138, 10, 659},\n\tdictWord{6, 0, 289},\n\tdictWord{7, 0, 1670},\n\tdictWord{12, 0, 57},\n\tdictWord{151, 0, 4},\n\tdictWord{132, 10, 635},\n\tdictWord{14, 0, 43},\n\tdictWord{146, 0, 21},\n\tdictWord{139, 10, 533},\n\tdictWord{135, 0, 1694},\n\tdictWord{8, 0, 420},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t193,\n\t},\n\tdictWord{135, 0, 409},\n\tdictWord{132, 10, 371},\n\tdictWord{4, 10, 272},\n\tdictWord{135, 10, 836},\n\tdictWord{5, 10, 825},\n\tdictWord{134, 10, 1640},\n\tdictWord{5, 11, 251},\n\tdictWord{5, 11, 956},\n\tdictWord{8, 11, 268},\n\tdictWord{9, 11, 214},\n\tdictWord{146, 11, 142},\n\tdictWord{138, 0, 308},\n\tdictWord{6, 0, 1863},\n\tdictWord{141, 11, 37},\n\tdictWord{137, 10, 879},\n\tdictWord{7, 10, 317},\n\tdictWord{135, 10, 569},\n\tdictWord{132, 11, 294},\n\tdictWord{134, 0, 790},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t1002,\n\t},\n\tdictWord{136, 0, 745},\n\tdictWord{5, 11, 346},\n\tdictWord{5, 11, 711},\n\tdictWord{136, 11, 390},\n\tdictWord{135, 0, 289},\n\tdictWord{5, 0, 504},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t68,\n\t},\n\tdictWord{137, 10, 307},\n\tdictWord{4, 0, 239},\n\tdictWord{6, 0, 477},\n\tdictWord{7, 0, 1607},\n\tdictWord{139, 0, 617},\n\tdictWord{149, 0, 13},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t609,\n\t},\n\tdictWord{133, 11, 624},\n\tdictWord{5, 11, 783},\n\tdictWord{7, 11, 1998},\n\tdictWord{135, 11, 2047},\n\tdictWord{133, 10, 525},\n\tdictWord{132, 0, 367},\n\tdictWord{132, 11, 594},\n\tdictWord{6, 0, 528},\n\tdictWord{133, 10, 493},\n\tdictWord{4, 10, 174},\n\tdictWord{135, 10, 911},\n\tdictWord{8, 10, 417},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t782,\n\t},\n\tdictWord{132, 0, 694},\n\tdictWord{7, 0, 548},\n\tdictWord{137, 0, 58},\n\tdictWord{4, 10, 32},\n\tdictWord{5, 10, 215},\n\tdictWord{6, 10, 269},\n\tdictWord{7, 10, 1782},\n\tdictWord{7, 10, 1892},\n\tdictWord{10, 10, 16},\n\tdictWord{11, 10, 822},\n\tdictWord{11, 10, 954},\n\tdictWord{141, 10, 481},\n\tdictWord{140, 0, 687},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1749,\n\t},\n\tdictWord{136, 10, 477},\n\tdictWord{132, 11, 569},\n\tdictWord{133, 10, 308},\n\tdictWord{135, 10, 1088},\n\tdictWord{4, 0, 661},\n\tdictWord{138, 0, 1004},\n\tdictWord{5, 11, 37},\n\tdictWord{6, 11, 39},\n\tdictWord{6, 11, 451},\n\tdictWord{7, 11, 218},\n\tdictWord{7, 11, 667},\n\tdictWord{7, 11, 1166},\n\tdictWord{7, 11, 1687},\n\tdictWord{8, 11, 662},\n\tdictWord{144, 11, 2},\n\tdictWord{9, 0, 445},\n\tdictWord{12, 0, 53},\n\tdictWord{13, 0, 492},\n\tdictWord{5, 10, 126},\n\tdictWord{8, 10, 297},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t366,\n\t},\n\tdictWord{140, 10, 374},\n\tdictWord{7, 10, 1551},\n\tdictWord{139, 10, 361},\n\tdictWord{148, 0, 74},\n\tdictWord{134, 11, 508},\n\tdictWord{135, 0, 213},\n\tdictWord{132, 10, 175},\n\tdictWord{132, 10, 685},\n\tdictWord{6, 0, 760},\n\tdictWord{6, 0, 834},\n\tdictWord{134, 0, 1248},\n\tdictWord{7, 11, 453},\n\tdictWord{7, 11, 635},\n\tdictWord{7, 11, 796},\n\tdictWord{8, 11, 331},\n\tdictWord{9, 11, 328},\n\tdictWord{9, 11, 330},\n\tdictWord{9, 11, 865},\n\tdictWord{10, 11, 119},\n\tdictWord{10, 11, 235},\n\tdictWord{11, 11, 111},\n\tdictWord{11, 11, 129},\n\tdictWord{11, 11, 240},\n\tdictWord{12, 11, 31},\n\tdictWord{12, 11, 66},\n\tdictWord{12, 11, 222},\n\tdictWord{12, 11, 269},\n\tdictWord{12, 11, 599},\n\tdictWord{12, 11, 689},\n\tdictWord{13, 11, 186},\n\tdictWord{13, 11, 364},\n\tdictWord{142, 11, 345},\n\tdictWord{7, 0, 1672},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t189,\n\t},\n\tdictWord{133, 10, 797},\n\tdictWord{133, 10, 565},\n\tdictWord{6, 0, 1548},\n\tdictWord{6, 11, 98},\n\tdictWord{7, 11, 585},\n\tdictWord{135, 11, 702},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t968,\n\t},\n\tdictWord{15, 0, 192},\n\tdictWord{149, 0, 56},\n\tdictWord{4, 10, 252},\n\tdictWord{6, 11, 37},\n\tdictWord{7, 11, 299},\n\tdictWord{7, 10, 1068},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1666,\n\t},\n\tdictWord{8, 11, 195},\n\tdictWord{8, 11, 316},\n\tdictWord{9, 11, 178},\n\tdictWord{9, 11, 276},\n\tdictWord{9, 11, 339},\n\tdictWord{9, 11, 536},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t102,\n\t},\n\tdictWord{10, 11, 362},\n\tdictWord{10, 10, 434},\n\tdictWord{10, 11, 785},\n\tdictWord{11, 11, 55},\n\tdictWord{11, 11, 149},\n\tdictWord{11, 10, 228},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t426,\n\t},\n\tdictWord{11, 11, 773},\n\tdictWord{13, 10, 231},\n\tdictWord{13, 11, 416},\n\tdictWord{13, 11, 419},\n\tdictWord{14, 11, 38},\n\tdictWord{14, 11, 41},\n\tdictWord{14, 11, 210},\n\tdictWord{18, 10, 106},\n\tdictWord{148, 10, 87},\n\tdictWord{4, 0, 751},\n\tdictWord{11, 0, 390},\n\tdictWord{140, 0, 32},\n\tdictWord{4, 0, 409},\n\tdictWord{133, 0, 78},\n\tdictWord{11, 11, 458},\n\tdictWord{12, 11, 15},\n\tdictWord{140, 11, 432},\n\tdictWord{7, 0, 1602},\n\tdictWord{10, 0, 257},\n\tdictWord{10, 0, 698},\n\tdictWord{11, 0, 544},\n\tdictWord{11, 0, 585},\n\tdictWord{12, 0, 212},\n\tdictWord{13, 0, 307},\n\tdictWord{5, 10, 231},\n\tdictWord{7, 10, 601},\n\tdictWord{9, 10, 277},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t674,\n\t},\n\tdictWord{10, 10, 178},\n\tdictWord{10, 10, 418},\n\tdictWord{10, 10, 509},\n\tdictWord{11, 10, 531},\n\tdictWord{12, 10, 113},\n\tdictWord{12, 10, 475},\n\tdictWord{13, 10, 99},\n\tdictWord{142, 10, 428},\n\tdictWord{6, 0, 473},\n\tdictWord{145, 0, 105},\n\tdictWord{6, 0, 1949},\n\tdictWord{15, 0, 156},\n\tdictWord{133, 11, 645},\n\tdictWord{7, 10, 1591},\n\tdictWord{144, 10, 43},\n\tdictWord{135, 0, 1779},\n\tdictWord{135, 10, 1683},\n\tdictWord{4, 11, 290},\n\tdictWord{135, 11, 1356},\n\tdictWord{134, 0, 763},\n\tdictWord{6, 11, 70},\n\tdictWord{7, 11, 1292},\n\tdictWord{10, 11, 762},\n\tdictWord{139, 11, 288},\n\tdictWord{142, 0, 29},\n\tdictWord{140, 11, 428},\n\tdictWord{7, 0, 883},\n\tdictWord{7, 11, 131},\n\tdictWord{7, 11, 422},\n\tdictWord{8, 11, 210},\n\tdictWord{140, 11, 573},\n\tdictWord{134, 0, 488},\n\tdictWord{4, 10, 399},\n\tdictWord{5, 10, 119},\n\tdictWord{5, 10, 494},\n\tdictWord{7, 10, 751},\n\tdictWord{137, 10, 556},\n\tdictWord{133, 0, 617},\n\tdictWord{132, 11, 936},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t50,\n\t},\n\tdictWord{7, 0, 1518},\n\tdictWord{139, 0, 694},\n\tdictWord{137, 0, 785},\n\tdictWord{4, 0, 546},\n\tdictWord{135, 0, 2042},\n\tdictWord{7, 11, 716},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t97,\n\t},\n\tdictWord{141, 11, 251},\n\tdictWord{132, 11, 653},\n\tdictWord{145, 0, 22},\n\tdictWord{134, 0, 1016},\n\tdictWord{4, 0, 313},\n\tdictWord{133, 0, 577},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t657,\n\t},\n\tdictWord{8, 0, 184},\n\tdictWord{141, 0, 433},\n\tdictWord{135, 0, 935},\n\tdictWord{6, 0, 720},\n\tdictWord{9, 0, 114},\n\tdictWord{146, 11, 80},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t186,\n\t},\n\tdictWord{12, 0, 292},\n\tdictWord{14, 0, 100},\n\tdictWord{18, 0, 70},\n\tdictWord{7, 10, 594},\n\tdictWord{7, 10, 851},\n\tdictWord{7, 10, 1858},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t411,\n\t},\n\tdictWord{9, 10, 574},\n\tdictWord{9, 10, 666},\n\tdictWord{9, 10, 737},\n\tdictWord{10, 10, 346},\n\tdictWord{10, 10, 712},\n\tdictWord{11, 10, 246},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t432,\n\t},\n\tdictWord{11, 10, 517},\n\tdictWord{11, 10, 647},\n\tdictWord{11, 10, 679},\n\tdictWord{11, 10, 727},\n\tdictWord{12, 10, 304},\n\tdictWord{12, 10, 305},\n\tdictWord{12, 10, 323},\n\tdictWord{12, 10, 483},\n\tdictWord{12, 10, 572},\n\tdictWord{12, 10, 593},\n\tdictWord{12, 10, 602},\n\tdictWord{13, 10, 95},\n\tdictWord{13, 10, 101},\n\tdictWord{13, 10, 171},\n\tdictWord{13, 10, 315},\n\tdictWord{13, 10, 378},\n\tdictWord{13, 10, 425},\n\tdictWord{13, 10, 475},\n\tdictWord{14, 10, 63},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t380,\n\t},\n\tdictWord{14, 10, 384},\n\tdictWord{15, 10, 133},\n\tdictWord{18, 10, 112},\n\tdictWord{148, 10, 72},\n\tdictWord{135, 10, 1093},\n\tdictWord{135, 11, 1836},\n\tdictWord{132, 10, 679},\n\tdictWord{137, 10, 203},\n\tdictWord{11, 0, 402},\n\tdictWord{12, 0, 109},\n\tdictWord{12, 0, 431},\n\tdictWord{13, 0, 179},\n\tdictWord{13, 0, 206},\n\tdictWord{14, 0, 217},\n\tdictWord{16, 0, 3},\n\tdictWord{148, 0, 53},\n\tdictWord{7, 11, 1368},\n\tdictWord{8, 11, 232},\n\tdictWord{8, 11, 361},\n\tdictWord{10, 11, 682},\n\tdictWord{138, 11, 742},\n\tdictWord{137, 10, 714},\n\tdictWord{5, 0, 886},\n\tdictWord{6, 0, 46},\n\tdictWord{6, 0, 1790},\n\tdictWord{7, 0, 14},\n\tdictWord{7, 0, 732},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1654,\n\t},\n\tdictWord{8, 0, 95},\n\tdictWord{8, 0, 327},\n\tdictWord{8, 0, 616},\n\tdictWord{9, 0, 892},\n\tdictWord{10, 0, 598},\n\tdictWord{10, 0, 769},\n\tdictWord{11, 0, 134},\n\tdictWord{11, 0, 747},\n\tdictWord{12, 0, 378},\n\tdictWord{14, 0, 97},\n\tdictWord{137, 11, 534},\n\tdictWord{4, 0, 969},\n\tdictWord{136, 10, 825},\n\tdictWord{137, 11, 27},\n\tdictWord{6, 0, 727},\n\tdictWord{142, 11, 12},\n\tdictWord{133, 0, 1021},\n\tdictWord{134, 0, 1190},\n\tdictWord{134, 11, 1657},\n\tdictWord{5, 10, 143},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t769,\n\t},\n\tdictWord{6, 10, 1760},\n\tdictWord{7, 10, 682},\n\tdictWord{7, 10, 1992},\n\tdictWord{136, 10, 736},\n\tdictWord{132, 0, 153},\n\tdictWord{135, 11, 127},\n\tdictWord{133, 0, 798},\n\tdictWord{132, 0, 587},\n\tdictWord{6, 0, 598},\n\tdictWord{7, 0, 42},\n\tdictWord{8, 0, 695},\n\tdictWord{10, 0, 212},\n\tdictWord{11, 0, 158},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t196,\n\t},\n\tdictWord{145, 0, 85},\n\tdictWord{133, 10, 860},\n\tdictWord{6, 0, 1929},\n\tdictWord{134, 0, 1933},\n\tdictWord{5, 0, 957},\n\tdictWord{5, 0, 1008},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t577,\n\t},\n\tdictWord{12, 0, 141},\n\tdictWord{6, 10, 422},\n\tdictWord{7, 10, 0},\n\tdictWord{7, 10, 1544},\n\tdictWord{8, 11, 364},\n\tdictWord{11, 10, 990},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t453,\n\t},\n\tdictWord{13, 10, 47},\n\tdictWord{141, 10, 266},\n\tdictWord{134, 0, 1319},\n\tdictWord{4, 0, 129},\n\tdictWord{135, 0, 465},\n\tdictWord{7, 0, 470},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1057,\n\t},\n\tdictWord{7, 0, 1201},\n\tdictWord{9, 0, 755},\n\tdictWord{11, 0, 906},\n\tdictWord{140, 0, 527},\n\tdictWord{7, 0, 908},\n\tdictWord{146, 0, 7},\n\tdictWord{5, 0, 148},\n\tdictWord{136, 0, 450},\n\tdictWord{5, 10, 515},\n\tdictWord{137, 10, 131},\n\tdictWord{7, 10, 1605},\n\tdictWord{11, 10, 962},\n\tdictWord{146, 10, 139},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t646,\n\t},\n\tdictWord{134, 0, 1166},\n\tdictWord{4, 10, 396},\n\tdictWord{7, 10, 728},\n\tdictWord{9, 10, 117},\n\tdictWord{13, 10, 202},\n\tdictWord{148, 10, 51},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t121,\n\t},\n\tdictWord{6, 10, 124},\n\tdictWord{6, 10, 357},\n\tdictWord{7, 10, 1138},\n\tdictWord{7, 10, 1295},\n\tdictWord{8, 10, 162},\n\tdictWord{139, 10, 655},\n\tdictWord{14, 0, 374},\n\tdictWord{142, 11, 374},\n\tdictWord{138, 0, 253},\n\tdictWord{139, 0, 1003},\n\tdictWord{5, 11, 909},\n\tdictWord{9, 11, 849},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t805,\n\t},\n\tdictWord{133, 10, 237},\n\tdictWord{7, 11, 525},\n\tdictWord{7, 11, 1579},\n\tdictWord{8, 11, 497},\n\tdictWord{136, 11, 573},\n\tdictWord{137, 0, 46},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t879,\n\t},\n\tdictWord{134, 0, 806},\n\tdictWord{135, 0, 1868},\n\tdictWord{6, 0, 1837},\n\tdictWord{134, 0, 1846},\n\tdictWord{6, 0, 730},\n\tdictWord{134, 0, 881},\n\tdictWord{7, 0, 965},\n\tdictWord{7, 0, 1460},\n\tdictWord{7, 0, 1604},\n\tdictWord{7, 11, 193},\n\tdictWord{7, 11, 397},\n\tdictWord{7, 11, 1105},\n\tdictWord{8, 11, 124},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t619,\n\t},\n\tdictWord{9, 11, 305},\n\tdictWord{10, 11, 264},\n\tdictWord{11, 11, 40},\n\tdictWord{12, 11, 349},\n\tdictWord{13, 11, 134},\n\tdictWord{13, 11, 295},\n\tdictWord{14, 11, 155},\n\tdictWord{15, 11, 120},\n\tdictWord{146, 11, 105},\n\tdictWord{136, 0, 506},\n\tdictWord{143, 0, 10},\n\tdictWord{4, 11, 262},\n\tdictWord{7, 11, 342},\n\tdictWord{7, 10, 571},\n\tdictWord{7, 10, 1877},\n\tdictWord{10, 10, 366},\n\tdictWord{141, 11, 23},\n\tdictWord{133, 11, 641},\n\tdictWord{10, 0, 22},\n\tdictWord{9, 10, 513},\n\tdictWord{10, 10, 39},\n\tdictWord{12, 10, 122},\n\tdictWord{140, 10, 187},\n\tdictWord{135, 11, 1431},\n\tdictWord{150, 11, 49},\n\tdictWord{4, 11, 99},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t250,\n\t},\n\tdictWord{6, 11, 346},\n\tdictWord{8, 11, 127},\n\tdictWord{138, 11, 81},\n\tdictWord{6, 0, 2014},\n\tdictWord{8, 0, 928},\n\tdictWord{10, 0, 960},\n\tdictWord{10, 0, 979},\n\tdictWord{140, 0, 996},\n\tdictWord{134, 0, 296},\n\tdictWord{132, 11, 915},\n\tdictWord{5, 11, 75},\n\tdictWord{9, 11, 517},\n\tdictWord{10, 11, 470},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t155,\n\t},\n\tdictWord{141, 11, 224},\n\tdictWord{137, 10, 873},\n\tdictWord{4, 0, 854},\n\tdictWord{140, 11, 18},\n\tdictWord{134, 0, 587},\n\tdictWord{7, 10, 107},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t838,\n\t},\n\tdictWord{8, 10, 550},\n\tdictWord{138, 10, 401},\n\tdictWord{11, 0, 636},\n\tdictWord{15, 0, 145},\n\tdictWord{17, 0, 34},\n\tdictWord{19, 0, 50},\n\tdictWord{\n\t\t23,\n\t\t0,\n\t\t20,\n\t},\n\tdictWord{11, 10, 588},\n\tdictWord{11, 10, 864},\n\tdictWord{11, 10, 968},\n\tdictWord{143, 10, 160},\n\tdictWord{135, 11, 216},\n\tdictWord{7, 0, 982},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t32,\n\t},\n\tdictWord{143, 0, 56},\n\tdictWord{133, 10, 768},\n\tdictWord{133, 11, 954},\n\tdictWord{6, 11, 304},\n\tdictWord{7, 11, 1114},\n\tdictWord{8, 11, 418},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t345,\n\t},\n\tdictWord{11, 11, 341},\n\tdictWord{11, 11, 675},\n\tdictWord{141, 11, 40},\n\tdictWord{9, 11, 410},\n\tdictWord{139, 11, 425},\n\tdictWord{136, 0, 941},\n\tdictWord{5, 0, 435},\n\tdictWord{132, 10, 894},\n\tdictWord{5, 0, 85},\n\tdictWord{6, 0, 419},\n\tdictWord{7, 0, 134},\n\tdictWord{7, 0, 305},\n\tdictWord{7, 0, 361},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1337,\n\t},\n\tdictWord{8, 0, 71},\n\tdictWord{140, 0, 519},\n\tdictWord{140, 0, 688},\n\tdictWord{135, 0, 740},\n\tdictWord{5, 0, 691},\n\tdictWord{7, 0, 345},\n\tdictWord{9, 0, 94},\n\tdictWord{140, 0, 169},\n\tdictWord{5, 0, 183},\n\tdictWord{6, 0, 582},\n\tdictWord{10, 0, 679},\n\tdictWord{140, 0, 435},\n\tdictWord{134, 11, 14},\n\tdictWord{6, 0, 945},\n\tdictWord{135, 0, 511},\n\tdictWord{134, 11, 1708},\n\tdictWord{5, 11, 113},\n\tdictWord{6, 11, 243},\n\tdictWord{7, 11, 1865},\n\tdictWord{11, 11, 161},\n\tdictWord{16, 11, 37},\n\tdictWord{145, 11, 99},\n\tdictWord{132, 11, 274},\n\tdictWord{137, 0, 539},\n\tdictWord{7, 0, 1993},\n\tdictWord{8, 0, 684},\n\tdictWord{134, 10, 272},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t659,\n\t},\n\tdictWord{134, 0, 982},\n\tdictWord{4, 10, 9},\n\tdictWord{5, 10, 128},\n\tdictWord{7, 10, 368},\n\tdictWord{11, 10, 480},\n\tdictWord{148, 10, 3},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t583,\n\t},\n\tdictWord{132, 0, 803},\n\tdictWord{133, 0, 704},\n\tdictWord{4, 0, 179},\n\tdictWord{5, 0, 198},\n\tdictWord{133, 0, 697},\n\tdictWord{7, 0, 347},\n\tdictWord{7, 0, 971},\n\tdictWord{8, 0, 181},\n\tdictWord{10, 0, 711},\n\tdictWord{135, 11, 166},\n\tdictWord{136, 10, 682},\n\tdictWord{4, 10, 2},\n\tdictWord{7, 10, 545},\n\tdictWord{7, 10, 894},\n\tdictWord{136, 11, 521},\n\tdictWord{135, 0, 481},\n\tdictWord{132, 0, 243},\n\tdictWord{5, 0, 203},\n\tdictWord{7, 0, 19},\n\tdictWord{7, 0, 71},\n\tdictWord{7, 0, 113},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t405,\n\t},\n\tdictWord{11, 0, 357},\n\tdictWord{142, 0, 240},\n\tdictWord{5, 11, 725},\n\tdictWord{5, 11, 727},\n\tdictWord{135, 11, 1811},\n\tdictWord{6, 0, 826},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t304,\n\t},\n\tdictWord{7, 0, 1450},\n\tdictWord{139, 0, 99},\n\tdictWord{133, 11, 654},\n\tdictWord{134, 0, 492},\n\tdictWord{5, 0, 134},\n\tdictWord{6, 0, 408},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t495,\n\t},\n\tdictWord{7, 0, 1593},\n\tdictWord{6, 11, 273},\n\tdictWord{10, 11, 188},\n\tdictWord{13, 11, 377},\n\tdictWord{146, 11, 77},\n\tdictWord{9, 10, 769},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t185,\n\t},\n\tdictWord{135, 11, 410},\n\tdictWord{142, 0, 4},\n\tdictWord{4, 0, 665},\n\tdictWord{134, 11, 1785},\n\tdictWord{4, 0, 248},\n\tdictWord{7, 0, 137},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t349,\n\t},\n\tdictWord{5, 10, 530},\n\tdictWord{142, 10, 113},\n\tdictWord{7, 0, 1270},\n\tdictWord{139, 0, 612},\n\tdictWord{132, 11, 780},\n\tdictWord{5, 0, 371},\n\tdictWord{135, 0, 563},\n\tdictWord{135, 0, 826},\n\tdictWord{6, 0, 1535},\n\tdictWord{23, 0, 21},\n\tdictWord{151, 0, 23},\n\tdictWord{4, 0, 374},\n\tdictWord{7, 0, 547},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1700,\n\t},\n\tdictWord{7, 0, 1833},\n\tdictWord{139, 0, 858},\n\tdictWord{133, 10, 556},\n\tdictWord{7, 11, 612},\n\tdictWord{8, 11, 545},\n\tdictWord{8, 11, 568},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t642,\n\t},\n\tdictWord{9, 11, 717},\n\tdictWord{10, 11, 541},\n\tdictWord{10, 11, 763},\n\tdictWord{11, 11, 449},\n\tdictWord{12, 11, 489},\n\tdictWord{13, 11, 153},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t296,\n\t},\n\tdictWord{14, 11, 138},\n\tdictWord{14, 11, 392},\n\tdictWord{15, 11, 50},\n\tdictWord{16, 11, 6},\n\tdictWord{16, 11, 12},\n\tdictWord{148, 11, 9},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t311,\n\t},\n\tdictWord{141, 0, 42},\n\tdictWord{8, 10, 16},\n\tdictWord{140, 10, 568},\n\tdictWord{6, 0, 1968},\n\tdictWord{6, 0, 2027},\n\tdictWord{138, 0, 991},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1647,\n\t},\n\tdictWord{7, 0, 1552},\n\tdictWord{7, 0, 2010},\n\tdictWord{9, 0, 494},\n\tdictWord{137, 0, 509},\n\tdictWord{133, 11, 948},\n\tdictWord{6, 10, 186},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t426,\n\t},\n\tdictWord{134, 0, 769},\n\tdictWord{134, 0, 642},\n\tdictWord{132, 10, 585},\n\tdictWord{6, 0, 123},\n\tdictWord{7, 0, 214},\n\tdictWord{9, 0, 728},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t157,\n\t},\n\tdictWord{11, 0, 346},\n\tdictWord{11, 0, 662},\n\tdictWord{143, 0, 106},\n\tdictWord{142, 11, 381},\n\tdictWord{135, 0, 1435},\n\tdictWord{4, 11, 532},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t706,\n\t},\n\tdictWord{135, 11, 662},\n\tdictWord{5, 11, 837},\n\tdictWord{134, 11, 1651},\n\tdictWord{4, 10, 93},\n\tdictWord{5, 10, 252},\n\tdictWord{6, 10, 229},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t291,\n\t},\n\tdictWord{9, 10, 550},\n\tdictWord{139, 10, 644},\n\tdictWord{148, 0, 79},\n\tdictWord{137, 10, 749},\n\tdictWord{134, 0, 1425},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t162,\n\t},\n\tdictWord{4, 11, 362},\n\tdictWord{7, 11, 52},\n\tdictWord{7, 11, 303},\n\tdictWord{140, 11, 166},\n\tdictWord{132, 10, 381},\n\tdictWord{4, 11, 330},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t933,\n\t},\n\tdictWord{7, 11, 2012},\n\tdictWord{136, 11, 292},\n\tdictWord{135, 11, 767},\n\tdictWord{4, 0, 707},\n\tdictWord{5, 0, 588},\n\tdictWord{6, 0, 393},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t106,\n\t},\n\tdictWord{18, 0, 49},\n\tdictWord{147, 0, 41},\n\tdictWord{6, 0, 211},\n\tdictWord{7, 0, 1690},\n\tdictWord{11, 0, 486},\n\tdictWord{140, 0, 369},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t883,\n\t},\n\tdictWord{4, 11, 703},\n\tdictWord{135, 11, 207},\n\tdictWord{4, 0, 187},\n\tdictWord{5, 0, 184},\n\tdictWord{5, 0, 690},\n\tdictWord{7, 0, 1869},\n\tdictWord{10, 0, 756},\n\tdictWord{139, 0, 783},\n\tdictWord{132, 11, 571},\n\tdictWord{134, 0, 1382},\n\tdictWord{5, 0, 175},\n\tdictWord{6, 10, 77},\n\tdictWord{6, 10, 157},\n\tdictWord{7, 10, 974},\n\tdictWord{7, 10, 1301},\n\tdictWord{7, 10, 1339},\n\tdictWord{7, 10, 1490},\n\tdictWord{7, 10, 1873},\n\tdictWord{137, 10, 628},\n\tdictWord{134, 0, 1493},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t873,\n\t},\n\tdictWord{133, 11, 960},\n\tdictWord{134, 0, 1007},\n\tdictWord{12, 11, 93},\n\tdictWord{12, 11, 501},\n\tdictWord{13, 11, 362},\n\tdictWord{14, 11, 151},\n\tdictWord{15, 11, 40},\n\tdictWord{15, 11, 59},\n\tdictWord{16, 11, 46},\n\tdictWord{17, 11, 25},\n\tdictWord{18, 11, 14},\n\tdictWord{18, 11, 134},\n\tdictWord{19, 11, 25},\n\tdictWord{\n\t\t19,\n\t\t11,\n\t\t69,\n\t},\n\tdictWord{20, 11, 16},\n\tdictWord{20, 11, 19},\n\tdictWord{20, 11, 66},\n\tdictWord{21, 11, 23},\n\tdictWord{21, 11, 25},\n\tdictWord{150, 11, 42},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t919,\n\t},\n\tdictWord{141, 10, 409},\n\tdictWord{134, 0, 219},\n\tdictWord{5, 0, 582},\n\tdictWord{6, 0, 1646},\n\tdictWord{7, 0, 99},\n\tdictWord{7, 0, 1962},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1986,\n\t},\n\tdictWord{8, 0, 515},\n\tdictWord{8, 0, 773},\n\tdictWord{9, 0, 23},\n\tdictWord{9, 0, 491},\n\tdictWord{12, 0, 620},\n\tdictWord{142, 0, 93},\n\tdictWord{133, 0, 851},\n\tdictWord{5, 11, 33},\n\tdictWord{134, 11, 470},\n\tdictWord{135, 11, 1291},\n\tdictWord{134, 0, 1278},\n\tdictWord{135, 11, 1882},\n\tdictWord{135, 10, 1489},\n\tdictWord{132, 0, 1000},\n\tdictWord{138, 0, 982},\n\tdictWord{8, 0, 762},\n\tdictWord{8, 0, 812},\n\tdictWord{137, 0, 910},\n\tdictWord{6, 11, 47},\n\tdictWord{7, 11, 90},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t664,\n\t},\n\tdictWord{7, 11, 830},\n\tdictWord{7, 11, 1380},\n\tdictWord{7, 11, 2025},\n\tdictWord{8, 11, 448},\n\tdictWord{136, 11, 828},\n\tdictWord{4, 0, 98},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t940,\n\t},\n\tdictWord{6, 0, 1819},\n\tdictWord{6, 0, 1834},\n\tdictWord{6, 0, 1841},\n\tdictWord{7, 0, 1365},\n\tdictWord{8, 0, 859},\n\tdictWord{8, 0, 897},\n\tdictWord{8, 0, 918},\n\tdictWord{9, 0, 422},\n\tdictWord{9, 0, 670},\n\tdictWord{10, 0, 775},\n\tdictWord{10, 0, 894},\n\tdictWord{10, 0, 909},\n\tdictWord{10, 0, 910},\n\tdictWord{10, 0, 935},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t210,\n\t},\n\tdictWord{12, 0, 750},\n\tdictWord{12, 0, 755},\n\tdictWord{13, 0, 26},\n\tdictWord{13, 0, 457},\n\tdictWord{13, 0, 476},\n\tdictWord{16, 0, 100},\n\tdictWord{16, 0, 109},\n\tdictWord{18, 0, 173},\n\tdictWord{18, 0, 175},\n\tdictWord{8, 10, 398},\n\tdictWord{9, 10, 681},\n\tdictWord{139, 10, 632},\n\tdictWord{9, 11, 417},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t493,\n\t},\n\tdictWord{136, 10, 645},\n\tdictWord{138, 0, 906},\n\tdictWord{134, 0, 1730},\n\tdictWord{134, 10, 20},\n\tdictWord{133, 11, 1019},\n\tdictWord{134, 0, 1185},\n\tdictWord{10, 0, 40},\n\tdictWord{136, 10, 769},\n\tdictWord{9, 0, 147},\n\tdictWord{134, 11, 208},\n\tdictWord{140, 0, 650},\n\tdictWord{5, 0, 209},\n\tdictWord{6, 0, 30},\n\tdictWord{11, 0, 56},\n\tdictWord{139, 0, 305},\n\tdictWord{132, 0, 553},\n\tdictWord{138, 11, 344},\n\tdictWord{6, 11, 68},\n\tdictWord{7, 11, 398},\n\tdictWord{7, 11, 448},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1629,\n\t},\n\tdictWord{7, 11, 1813},\n\tdictWord{8, 11, 387},\n\tdictWord{8, 11, 442},\n\tdictWord{9, 11, 710},\n\tdictWord{10, 11, 282},\n\tdictWord{138, 11, 722},\n\tdictWord{5, 0, 597},\n\tdictWord{14, 0, 20},\n\tdictWord{142, 11, 20},\n\tdictWord{135, 0, 1614},\n\tdictWord{135, 10, 1757},\n\tdictWord{4, 0, 150},\n\tdictWord{5, 0, 303},\n\tdictWord{6, 0, 327},\n\tdictWord{135, 10, 937},\n\tdictWord{16, 0, 49},\n\tdictWord{7, 10, 1652},\n\tdictWord{144, 11, 49},\n\tdictWord{8, 0, 192},\n\tdictWord{10, 0, 78},\n\tdictWord{\n\t\t141,\n\t\t0,\n\t\t359,\n\t},\n\tdictWord{135, 0, 786},\n\tdictWord{143, 0, 134},\n\tdictWord{6, 0, 1638},\n\tdictWord{7, 0, 79},\n\tdictWord{7, 0, 496},\n\tdictWord{9, 0, 138},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t336,\n\t},\n\tdictWord{11, 0, 12},\n\tdictWord{12, 0, 412},\n\tdictWord{12, 0, 440},\n\tdictWord{142, 0, 305},\n\tdictWord{136, 11, 491},\n\tdictWord{4, 10, 579},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t226,\n\t},\n\tdictWord{5, 10, 323},\n\tdictWord{135, 10, 960},\n\tdictWord{7, 0, 204},\n\tdictWord{7, 0, 415},\n\tdictWord{8, 0, 42},\n\tdictWord{10, 0, 85},\n\tdictWord{139, 0, 564},\n\tdictWord{132, 0, 614},\n\tdictWord{4, 11, 403},\n\tdictWord{5, 11, 441},\n\tdictWord{7, 11, 450},\n\tdictWord{11, 11, 101},\n\tdictWord{12, 11, 193},\n\tdictWord{141, 11, 430},\n\tdictWord{135, 11, 1927},\n\tdictWord{135, 11, 1330},\n\tdictWord{4, 0, 3},\n\tdictWord{5, 0, 247},\n\tdictWord{5, 0, 644},\n\tdictWord{7, 0, 744},\n\tdictWord{7, 0, 1207},\n\tdictWord{7, 0, 1225},\n\tdictWord{7, 0, 1909},\n\tdictWord{146, 0, 147},\n\tdictWord{136, 0, 942},\n\tdictWord{4, 0, 1019},\n\tdictWord{134, 0, 2023},\n\tdictWord{5, 11, 679},\n\tdictWord{133, 10, 973},\n\tdictWord{5, 0, 285},\n\tdictWord{9, 0, 67},\n\tdictWord{13, 0, 473},\n\tdictWord{143, 0, 82},\n\tdictWord{7, 11, 328},\n\tdictWord{137, 11, 326},\n\tdictWord{151, 0, 8},\n\tdictWord{6, 10, 135},\n\tdictWord{135, 10, 1176},\n\tdictWord{135, 11, 1128},\n\tdictWord{134, 0, 1309},\n\tdictWord{135, 11, 1796},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t314,\n\t},\n\tdictWord{4, 11, 574},\n\tdictWord{7, 11, 350},\n\tdictWord{7, 11, 1024},\n\tdictWord{8, 11, 338},\n\tdictWord{9, 11, 677},\n\tdictWord{10, 11, 808},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t508,\n\t},\n\tdictWord{7, 11, 818},\n\tdictWord{17, 11, 14},\n\tdictWord{17, 11, 45},\n\tdictWord{18, 11, 75},\n\tdictWord{148, 11, 18},\n\tdictWord{146, 10, 4},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1081,\n\t},\n\tdictWord{4, 0, 29},\n\tdictWord{6, 0, 532},\n\tdictWord{7, 0, 1628},\n\tdictWord{7, 0, 1648},\n\tdictWord{9, 0, 350},\n\tdictWord{10, 0, 433},\n\tdictWord{11, 0, 97},\n\tdictWord{11, 0, 557},\n\tdictWord{11, 0, 745},\n\tdictWord{12, 0, 289},\n\tdictWord{12, 0, 335},\n\tdictWord{12, 0, 348},\n\tdictWord{12, 0, 606},\n\tdictWord{13, 0, 116},\n\tdictWord{13, 0, 233},\n\tdictWord{13, 0, 466},\n\tdictWord{14, 0, 181},\n\tdictWord{14, 0, 209},\n\tdictWord{14, 0, 232},\n\tdictWord{14, 0, 236},\n\tdictWord{14, 0, 300},\n\tdictWord{\n\t\t16,\n\t\t0,\n\t\t41,\n\t},\n\tdictWord{148, 0, 97},\n\tdictWord{7, 0, 318},\n\tdictWord{6, 10, 281},\n\tdictWord{8, 10, 282},\n\tdictWord{8, 10, 480},\n\tdictWord{8, 10, 499},\n\tdictWord{9, 10, 198},\n\tdictWord{10, 10, 143},\n\tdictWord{10, 10, 169},\n\tdictWord{10, 10, 211},\n\tdictWord{10, 10, 417},\n\tdictWord{10, 10, 574},\n\tdictWord{11, 10, 147},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t395,\n\t},\n\tdictWord{12, 10, 75},\n\tdictWord{12, 10, 407},\n\tdictWord{12, 10, 608},\n\tdictWord{13, 10, 500},\n\tdictWord{142, 10, 251},\n\tdictWord{135, 11, 1676},\n\tdictWord{135, 11, 2037},\n\tdictWord{135, 0, 1692},\n\tdictWord{5, 0, 501},\n\tdictWord{7, 0, 1704},\n\tdictWord{9, 0, 553},\n\tdictWord{11, 0, 520},\n\tdictWord{12, 0, 557},\n\tdictWord{141, 0, 249},\n\tdictWord{6, 0, 1527},\n\tdictWord{14, 0, 324},\n\tdictWord{15, 0, 55},\n\tdictWord{15, 0, 80},\n\tdictWord{14, 11, 324},\n\tdictWord{15, 11, 55},\n\tdictWord{143, 11, 80},\n\tdictWord{135, 10, 1776},\n\tdictWord{8, 0, 988},\n\tdictWord{137, 11, 297},\n\tdictWord{132, 10, 419},\n\tdictWord{142, 0, 223},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t234,\n\t},\n\tdictWord{7, 0, 1123},\n\tdictWord{12, 0, 508},\n\tdictWord{14, 0, 102},\n\tdictWord{14, 0, 226},\n\tdictWord{144, 0, 57},\n\tdictWord{4, 10, 138},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1012,\n\t},\n\tdictWord{7, 10, 1280},\n\tdictWord{137, 10, 76},\n\tdictWord{7, 0, 1764},\n\tdictWord{5, 10, 29},\n\tdictWord{140, 10, 638},\n\tdictWord{134, 0, 2015},\n\tdictWord{134, 0, 1599},\n\tdictWord{138, 11, 56},\n\tdictWord{6, 11, 306},\n\tdictWord{7, 11, 1140},\n\tdictWord{7, 11, 1340},\n\tdictWord{8, 11, 133},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t449,\n\t},\n\tdictWord{139, 11, 1011},\n\tdictWord{6, 10, 1710},\n\tdictWord{135, 10, 2038},\n\tdictWord{7, 11, 1763},\n\tdictWord{140, 11, 310},\n\tdictWord{6, 0, 129},\n\tdictWord{4, 10, 17},\n\tdictWord{5, 10, 23},\n\tdictWord{7, 10, 995},\n\tdictWord{11, 10, 383},\n\tdictWord{11, 10, 437},\n\tdictWord{12, 10, 460},\n\tdictWord{140, 10, 532},\n\tdictWord{5, 11, 329},\n\tdictWord{136, 11, 260},\n\tdictWord{133, 10, 862},\n\tdictWord{132, 0, 534},\n\tdictWord{6, 0, 811},\n\tdictWord{135, 0, 626},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t657,\n\t},\n\tdictWord{4, 0, 25},\n\tdictWord{5, 0, 60},\n\tdictWord{6, 0, 504},\n\tdictWord{7, 0, 614},\n\tdictWord{7, 0, 1155},\n\tdictWord{12, 0, 0},\n\tdictWord{152, 11, 7},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1248,\n\t},\n\tdictWord{11, 0, 621},\n\tdictWord{139, 0, 702},\n\tdictWord{137, 0, 321},\n\tdictWord{8, 10, 70},\n\tdictWord{12, 10, 171},\n\tdictWord{141, 10, 272},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t233,\n\t},\n\tdictWord{139, 10, 76},\n\tdictWord{4, 0, 379},\n\tdictWord{7, 0, 1397},\n\tdictWord{134, 10, 442},\n\tdictWord{5, 11, 66},\n\tdictWord{7, 11, 1896},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t288,\n\t},\n\tdictWord{134, 11, 1643},\n\tdictWord{134, 10, 1709},\n\tdictWord{4, 11, 21},\n\tdictWord{5, 11, 91},\n\tdictWord{5, 11, 570},\n\tdictWord{5, 11, 648},\n\tdictWord{5, 11, 750},\n\tdictWord{5, 11, 781},\n\tdictWord{6, 11, 54},\n\tdictWord{6, 11, 112},\n\tdictWord{6, 11, 402},\n\tdictWord{6, 11, 1732},\n\tdictWord{7, 11, 315},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t749,\n\t},\n\tdictWord{7, 11, 1347},\n\tdictWord{7, 11, 1900},\n\tdictWord{9, 11, 78},\n\tdictWord{9, 11, 508},\n\tdictWord{10, 11, 611},\n\tdictWord{11, 11, 510},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t728,\n\t},\n\tdictWord{13, 11, 36},\n\tdictWord{14, 11, 39},\n\tdictWord{16, 11, 83},\n\tdictWord{17, 11, 124},\n\tdictWord{148, 11, 30},\n\tdictWord{4, 0, 118},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t274,\n\t},\n\tdictWord{6, 0, 361},\n\tdictWord{7, 0, 75},\n\tdictWord{141, 0, 441},\n\tdictWord{10, 11, 322},\n\tdictWord{10, 11, 719},\n\tdictWord{139, 11, 407},\n\tdictWord{\n\t\t147,\n\t\t10,\n\t\t119,\n\t},\n\tdictWord{12, 11, 549},\n\tdictWord{14, 11, 67},\n\tdictWord{147, 11, 60},\n\tdictWord{11, 10, 69},\n\tdictWord{12, 10, 105},\n\tdictWord{12, 10, 117},\n\tdictWord{13, 10, 213},\n\tdictWord{14, 10, 13},\n\tdictWord{14, 10, 62},\n\tdictWord{14, 10, 177},\n\tdictWord{14, 10, 421},\n\tdictWord{15, 10, 19},\n\tdictWord{146, 10, 141},\n\tdictWord{9, 0, 841},\n\tdictWord{137, 10, 309},\n\tdictWord{7, 10, 608},\n\tdictWord{7, 10, 976},\n\tdictWord{8, 11, 125},\n\tdictWord{8, 11, 369},\n\tdictWord{8, 11, 524},\n\tdictWord{9, 10, 146},\n\tdictWord{10, 10, 206},\n\tdictWord{10, 11, 486},\n\tdictWord{10, 10, 596},\n\tdictWord{11, 11, 13},\n\tdictWord{11, 11, 381},\n\tdictWord{11, 11, 736},\n\tdictWord{11, 11, 766},\n\tdictWord{11, 11, 845},\n\tdictWord{13, 11, 114},\n\tdictWord{13, 10, 218},\n\tdictWord{13, 11, 292},\n\tdictWord{14, 11, 47},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t153,\n\t},\n\tdictWord{12, 0, 693},\n\tdictWord{135, 11, 759},\n\tdictWord{5, 0, 314},\n\tdictWord{6, 0, 221},\n\tdictWord{7, 0, 419},\n\tdictWord{10, 0, 650},\n\tdictWord{11, 0, 396},\n\tdictWord{12, 0, 156},\n\tdictWord{13, 0, 369},\n\tdictWord{14, 0, 333},\n\tdictWord{145, 0, 47},\n\tdictWord{6, 11, 1684},\n\tdictWord{6, 11, 1731},\n\tdictWord{7, 11, 356},\n\tdictWord{7, 11, 1932},\n\tdictWord{8, 11, 54},\n\tdictWord{8, 11, 221},\n\tdictWord{9, 11, 225},\n\tdictWord{9, 11, 356},\n\tdictWord{10, 11, 77},\n\tdictWord{10, 11, 446},\n\tdictWord{10, 11, 731},\n\tdictWord{12, 11, 404},\n\tdictWord{141, 11, 491},\n\tdictWord{132, 11, 375},\n\tdictWord{4, 10, 518},\n\tdictWord{135, 10, 1136},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t913,\n\t},\n\tdictWord{4, 11, 411},\n\tdictWord{11, 11, 643},\n\tdictWord{140, 11, 115},\n\tdictWord{4, 11, 80},\n\tdictWord{133, 11, 44},\n\tdictWord{8, 10, 689},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t863,\n\t},\n\tdictWord{138, 0, 880},\n\tdictWord{4, 10, 18},\n\tdictWord{7, 10, 145},\n\tdictWord{7, 10, 444},\n\tdictWord{7, 10, 1278},\n\tdictWord{8, 10, 49},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t400,\n\t},\n\tdictWord{9, 10, 71},\n\tdictWord{9, 10, 250},\n\tdictWord{10, 10, 459},\n\tdictWord{12, 10, 160},\n\tdictWord{144, 10, 24},\n\tdictWord{136, 0, 475},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t1016,\n\t},\n\tdictWord{5, 11, 299},\n\tdictWord{135, 11, 1083},\n\tdictWord{7, 0, 602},\n\tdictWord{8, 0, 179},\n\tdictWord{10, 0, 781},\n\tdictWord{140, 0, 126},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t329,\n\t},\n\tdictWord{138, 0, 111},\n\tdictWord{135, 0, 1864},\n\tdictWord{4, 11, 219},\n\tdictWord{7, 11, 1761},\n\tdictWord{137, 11, 86},\n\tdictWord{6, 0, 1888},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1892,\n\t},\n\tdictWord{6, 0, 1901},\n\tdictWord{6, 0, 1904},\n\tdictWord{9, 0, 953},\n\tdictWord{9, 0, 985},\n\tdictWord{9, 0, 991},\n\tdictWord{9, 0, 1001},\n\tdictWord{12, 0, 818},\n\tdictWord{12, 0, 846},\n\tdictWord{12, 0, 847},\n\tdictWord{12, 0, 861},\n\tdictWord{12, 0, 862},\n\tdictWord{12, 0, 873},\n\tdictWord{12, 0, 875},\n\tdictWord{12, 0, 877},\n\tdictWord{12, 0, 879},\n\tdictWord{12, 0, 881},\n\tdictWord{12, 0, 884},\n\tdictWord{12, 0, 903},\n\tdictWord{12, 0, 915},\n\tdictWord{12, 0, 926},\n\tdictWord{12, 0, 939},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t182,\n\t},\n\tdictWord{15, 0, 219},\n\tdictWord{15, 0, 255},\n\tdictWord{18, 0, 191},\n\tdictWord{18, 0, 209},\n\tdictWord{18, 0, 211},\n\tdictWord{149, 0, 41},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t328,\n\t},\n\tdictWord{135, 11, 918},\n\tdictWord{137, 0, 780},\n\tdictWord{12, 0, 82},\n\tdictWord{143, 0, 36},\n\tdictWord{133, 10, 1010},\n\tdictWord{5, 0, 821},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1687,\n\t},\n\tdictWord{133, 11, 514},\n\tdictWord{132, 0, 956},\n\tdictWord{134, 0, 1180},\n\tdictWord{10, 0, 112},\n\tdictWord{5, 10, 87},\n\tdictWord{7, 10, 313},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1103,\n\t},\n\tdictWord{10, 10, 582},\n\tdictWord{11, 10, 389},\n\tdictWord{11, 10, 813},\n\tdictWord{12, 10, 385},\n\tdictWord{13, 10, 286},\n\tdictWord{14, 10, 124},\n\tdictWord{146, 10, 108},\n\tdictWord{5, 0, 71},\n\tdictWord{7, 0, 1407},\n\tdictWord{9, 0, 704},\n\tdictWord{10, 0, 261},\n\tdictWord{10, 0, 619},\n\tdictWord{11, 0, 547},\n\tdictWord{11, 0, 619},\n\tdictWord{143, 0, 157},\n\tdictWord{4, 0, 531},\n\tdictWord{5, 0, 455},\n\tdictWord{5, 11, 301},\n\tdictWord{6, 11, 571},\n\tdictWord{14, 11, 49},\n\tdictWord{\n\t\t146,\n\t\t11,\n\t\t102,\n\t},\n\tdictWord{132, 10, 267},\n\tdictWord{6, 0, 385},\n\tdictWord{7, 0, 2008},\n\tdictWord{9, 0, 337},\n\tdictWord{138, 0, 517},\n\tdictWord{133, 11, 726},\n\tdictWord{133, 11, 364},\n\tdictWord{4, 11, 76},\n\tdictWord{7, 11, 1550},\n\tdictWord{9, 11, 306},\n\tdictWord{9, 11, 430},\n\tdictWord{9, 11, 663},\n\tdictWord{10, 11, 683},\n\tdictWord{11, 11, 427},\n\tdictWord{11, 11, 753},\n\tdictWord{12, 11, 334},\n\tdictWord{12, 11, 442},\n\tdictWord{14, 11, 258},\n\tdictWord{14, 11, 366},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t131,\n\t},\n\tdictWord{6, 0, 1865},\n\tdictWord{6, 0, 1879},\n\tdictWord{6, 0, 1881},\n\tdictWord{6, 0, 1894},\n\tdictWord{6, 0, 1908},\n\tdictWord{9, 0, 915},\n\tdictWord{9, 0, 926},\n\tdictWord{9, 0, 940},\n\tdictWord{9, 0, 943},\n\tdictWord{9, 0, 966},\n\tdictWord{9, 0, 980},\n\tdictWord{9, 0, 989},\n\tdictWord{9, 0, 1005},\n\tdictWord{9, 0, 1010},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t813,\n\t},\n\tdictWord{12, 0, 817},\n\tdictWord{12, 0, 840},\n\tdictWord{12, 0, 843},\n\tdictWord{12, 0, 855},\n\tdictWord{12, 0, 864},\n\tdictWord{12, 0, 871},\n\tdictWord{12, 0, 872},\n\tdictWord{12, 0, 899},\n\tdictWord{12, 0, 905},\n\tdictWord{12, 0, 924},\n\tdictWord{15, 0, 171},\n\tdictWord{15, 0, 181},\n\tdictWord{15, 0, 224},\n\tdictWord{15, 0, 235},\n\tdictWord{15, 0, 251},\n\tdictWord{146, 0, 184},\n\tdictWord{137, 11, 52},\n\tdictWord{5, 0, 16},\n\tdictWord{6, 0, 86},\n\tdictWord{6, 0, 603},\n\tdictWord{7, 0, 292},\n\tdictWord{7, 0, 561},\n\tdictWord{8, 0, 257},\n\tdictWord{8, 0, 382},\n\tdictWord{9, 0, 721},\n\tdictWord{9, 0, 778},\n\tdictWord{11, 0, 581},\n\tdictWord{140, 0, 466},\n\tdictWord{4, 0, 486},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t491,\n\t},\n\tdictWord{135, 10, 1121},\n\tdictWord{4, 0, 72},\n\tdictWord{6, 0, 265},\n\tdictWord{135, 0, 1300},\n\tdictWord{135, 11, 1183},\n\tdictWord{10, 10, 249},\n\tdictWord{139, 10, 209},\n\tdictWord{132, 10, 561},\n\tdictWord{137, 11, 519},\n\tdictWord{4, 11, 656},\n\tdictWord{4, 10, 760},\n\tdictWord{135, 11, 779},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t154,\n\t},\n\tdictWord{140, 10, 485},\n\tdictWord{135, 11, 1793},\n\tdictWord{135, 11, 144},\n\tdictWord{136, 10, 255},\n\tdictWord{133, 0, 621},\n\tdictWord{4, 10, 368},\n\tdictWord{135, 10, 641},\n\tdictWord{135, 11, 1373},\n\tdictWord{7, 11, 554},\n\tdictWord{7, 11, 605},\n\tdictWord{141, 11, 10},\n\tdictWord{137, 0, 234},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t815,\n\t},\n\tdictWord{6, 0, 1688},\n\tdictWord{134, 0, 1755},\n\tdictWord{5, 11, 838},\n\tdictWord{5, 11, 841},\n\tdictWord{134, 11, 1649},\n\tdictWord{7, 0, 1987},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t2040,\n\t},\n\tdictWord{136, 0, 743},\n\tdictWord{133, 11, 1012},\n\tdictWord{6, 0, 197},\n\tdictWord{136, 0, 205},\n\tdictWord{6, 0, 314},\n\tdictWord{134, 11, 314},\n\tdictWord{144, 11, 53},\n\tdictWord{6, 11, 251},\n\tdictWord{7, 11, 365},\n\tdictWord{7, 11, 1357},\n\tdictWord{7, 11, 1497},\n\tdictWord{8, 11, 154},\n\tdictWord{141, 11, 281},\n\tdictWord{133, 11, 340},\n\tdictWord{6, 0, 452},\n\tdictWord{7, 0, 312},\n\tdictWord{138, 0, 219},\n\tdictWord{138, 0, 589},\n\tdictWord{4, 0, 333},\n\tdictWord{9, 0, 176},\n\tdictWord{12, 0, 353},\n\tdictWord{141, 0, 187},\n\tdictWord{9, 10, 92},\n\tdictWord{147, 10, 91},\n\tdictWord{134, 0, 1110},\n\tdictWord{11, 0, 47},\n\tdictWord{139, 11, 495},\n\tdictWord{6, 10, 525},\n\tdictWord{8, 10, 806},\n\tdictWord{9, 10, 876},\n\tdictWord{140, 10, 284},\n\tdictWord{8, 11, 261},\n\tdictWord{9, 11, 144},\n\tdictWord{9, 11, 466},\n\tdictWord{10, 11, 370},\n\tdictWord{12, 11, 470},\n\tdictWord{13, 11, 144},\n\tdictWord{142, 11, 348},\n\tdictWord{137, 11, 897},\n\tdictWord{8, 0, 863},\n\tdictWord{8, 0, 864},\n\tdictWord{8, 0, 868},\n\tdictWord{8, 0, 884},\n\tdictWord{10, 0, 866},\n\tdictWord{10, 0, 868},\n\tdictWord{10, 0, 873},\n\tdictWord{10, 0, 911},\n\tdictWord{10, 0, 912},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t944,\n\t},\n\tdictWord{12, 0, 727},\n\tdictWord{6, 11, 248},\n\tdictWord{9, 11, 546},\n\tdictWord{10, 11, 535},\n\tdictWord{11, 11, 681},\n\tdictWord{141, 11, 135},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t300,\n\t},\n\tdictWord{135, 0, 1515},\n\tdictWord{134, 0, 1237},\n\tdictWord{139, 10, 958},\n\tdictWord{133, 10, 594},\n\tdictWord{140, 11, 250},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1685,\n\t},\n\tdictWord{134, 11, 567},\n\tdictWord{7, 0, 135},\n\tdictWord{8, 0, 7},\n\tdictWord{8, 0, 62},\n\tdictWord{9, 0, 243},\n\tdictWord{10, 0, 658},\n\tdictWord{10, 0, 697},\n\tdictWord{11, 0, 456},\n\tdictWord{139, 0, 756},\n\tdictWord{9, 0, 395},\n\tdictWord{138, 0, 79},\n\tdictWord{6, 10, 1641},\n\tdictWord{136, 10, 820},\n\tdictWord{4, 10, 302},\n\tdictWord{135, 10, 1766},\n\tdictWord{134, 11, 174},\n\tdictWord{135, 10, 1313},\n\tdictWord{135, 0, 631},\n\tdictWord{134, 10, 1674},\n\tdictWord{134, 11, 395},\n\tdictWord{138, 0, 835},\n\tdictWord{7, 0, 406},\n\tdictWord{7, 0, 459},\n\tdictWord{8, 0, 606},\n\tdictWord{139, 0, 726},\n\tdictWord{134, 11, 617},\n\tdictWord{134, 0, 979},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t389,\n\t},\n\tdictWord{7, 10, 149},\n\tdictWord{9, 10, 142},\n\tdictWord{138, 10, 94},\n\tdictWord{5, 11, 878},\n\tdictWord{133, 11, 972},\n\tdictWord{6, 10, 8},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1881,\n\t},\n\tdictWord{8, 10, 91},\n\tdictWord{136, 11, 511},\n\tdictWord{133, 0, 612},\n\tdictWord{132, 11, 351},\n\tdictWord{4, 0, 372},\n\tdictWord{7, 0, 482},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t158,\n\t},\n\tdictWord{9, 0, 602},\n\tdictWord{9, 0, 615},\n\tdictWord{10, 0, 245},\n\tdictWord{10, 0, 678},\n\tdictWord{10, 0, 744},\n\tdictWord{11, 0, 248},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t806,\n\t},\n\tdictWord{5, 0, 854},\n\tdictWord{135, 0, 1991},\n\tdictWord{132, 11, 286},\n\tdictWord{135, 11, 344},\n\tdictWord{7, 11, 438},\n\tdictWord{7, 11, 627},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1516,\n\t},\n\tdictWord{8, 11, 40},\n\tdictWord{9, 11, 56},\n\tdictWord{9, 11, 294},\n\tdictWord{10, 11, 30},\n\tdictWord{10, 11, 259},\n\tdictWord{11, 11, 969},\n\tdictWord{\n\t\t146,\n\t\t11,\n\t\t148,\n\t},\n\tdictWord{135, 0, 1492},\n\tdictWord{5, 11, 259},\n\tdictWord{7, 11, 414},\n\tdictWord{7, 11, 854},\n\tdictWord{142, 11, 107},\n\tdictWord{135, 10, 1746},\n\tdictWord{6, 0, 833},\n\tdictWord{134, 0, 998},\n\tdictWord{135, 10, 24},\n\tdictWord{6, 0, 750},\n\tdictWord{135, 0, 1739},\n\tdictWord{4, 10, 503},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1661,\n\t},\n\tdictWord{5, 10, 130},\n\tdictWord{7, 10, 1314},\n\tdictWord{9, 10, 610},\n\tdictWord{10, 10, 718},\n\tdictWord{11, 10, 601},\n\tdictWord{11, 10, 819},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t946,\n\t},\n\tdictWord{140, 10, 536},\n\tdictWord{10, 10, 149},\n\tdictWord{11, 10, 280},\n\tdictWord{142, 10, 336},\n\tdictWord{132, 11, 738},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1946,\n\t},\n\tdictWord{5, 0, 195},\n\tdictWord{135, 0, 1685},\n\tdictWord{7, 0, 1997},\n\tdictWord{8, 0, 730},\n\tdictWord{139, 0, 1006},\n\tdictWord{151, 11, 17},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t866,\n\t},\n\tdictWord{14, 0, 463},\n\tdictWord{14, 0, 470},\n\tdictWord{150, 0, 61},\n\tdictWord{5, 0, 751},\n\tdictWord{8, 0, 266},\n\tdictWord{11, 0, 578},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t392,\n\t},\n\tdictWord{135, 10, 1597},\n\tdictWord{5, 10, 433},\n\tdictWord{9, 10, 633},\n\tdictWord{139, 10, 629},\n\tdictWord{135, 0, 821},\n\tdictWord{6, 0, 715},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1325,\n\t},\n\tdictWord{133, 11, 116},\n\tdictWord{6, 0, 868},\n\tdictWord{132, 11, 457},\n\tdictWord{134, 0, 959},\n\tdictWord{6, 10, 234},\n\tdictWord{138, 11, 199},\n\tdictWord{7, 0, 1053},\n\tdictWord{7, 10, 1950},\n\tdictWord{8, 10, 680},\n\tdictWord{11, 10, 817},\n\tdictWord{147, 10, 88},\n\tdictWord{7, 10, 1222},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t386,\n\t},\n\tdictWord{5, 0, 950},\n\tdictWord{5, 0, 994},\n\tdictWord{6, 0, 351},\n\tdictWord{134, 0, 1124},\n\tdictWord{134, 0, 1081},\n\tdictWord{7, 0, 1595},\n\tdictWord{6, 10, 5},\n\tdictWord{11, 10, 249},\n\tdictWord{12, 10, 313},\n\tdictWord{16, 10, 66},\n\tdictWord{145, 10, 26},\n\tdictWord{148, 0, 59},\n\tdictWord{5, 11, 527},\n\tdictWord{6, 11, 189},\n\tdictWord{135, 11, 859},\n\tdictWord{5, 10, 963},\n\tdictWord{6, 10, 1773},\n\tdictWord{11, 11, 104},\n\tdictWord{11, 11, 554},\n\tdictWord{15, 11, 60},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t125,\n\t},\n\tdictWord{135, 0, 47},\n\tdictWord{137, 0, 684},\n\tdictWord{134, 11, 116},\n\tdictWord{134, 0, 1606},\n\tdictWord{134, 0, 777},\n\tdictWord{7, 0, 1020},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t509,\n\t},\n\tdictWord{136, 10, 792},\n\tdictWord{135, 0, 1094},\n\tdictWord{132, 0, 350},\n\tdictWord{133, 11, 487},\n\tdictWord{4, 11, 86},\n\tdictWord{5, 11, 667},\n\tdictWord{5, 11, 753},\n\tdictWord{6, 11, 316},\n\tdictWord{6, 11, 455},\n\tdictWord{135, 11, 946},\n\tdictWord{7, 0, 1812},\n\tdictWord{13, 0, 259},\n\tdictWord{13, 0, 356},\n\tdictWord{14, 0, 242},\n\tdictWord{147, 0, 114},\n\tdictWord{132, 10, 931},\n\tdictWord{133, 0, 967},\n\tdictWord{4, 0, 473},\n\tdictWord{7, 0, 623},\n\tdictWord{8, 0, 808},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t871,\n\t},\n\tdictWord{9, 0, 893},\n\tdictWord{11, 0, 38},\n\tdictWord{11, 0, 431},\n\tdictWord{12, 0, 112},\n\tdictWord{12, 0, 217},\n\tdictWord{12, 0, 243},\n\tdictWord{12, 0, 562},\n\tdictWord{12, 0, 663},\n\tdictWord{12, 0, 683},\n\tdictWord{13, 0, 141},\n\tdictWord{13, 0, 197},\n\tdictWord{13, 0, 227},\n\tdictWord{13, 0, 406},\n\tdictWord{13, 0, 487},\n\tdictWord{14, 0, 156},\n\tdictWord{14, 0, 203},\n\tdictWord{14, 0, 224},\n\tdictWord{14, 0, 256},\n\tdictWord{18, 0, 58},\n\tdictWord{150, 0, 0},\n\tdictWord{138, 0, 286},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t943,\n\t},\n\tdictWord{139, 10, 614},\n\tdictWord{135, 10, 1837},\n\tdictWord{150, 11, 45},\n\tdictWord{132, 0, 798},\n\tdictWord{4, 0, 222},\n\tdictWord{7, 0, 286},\n\tdictWord{136, 0, 629},\n\tdictWord{4, 11, 79},\n\tdictWord{7, 11, 1773},\n\tdictWord{10, 11, 450},\n\tdictWord{11, 11, 589},\n\tdictWord{13, 11, 332},\n\tdictWord{13, 11, 493},\n\tdictWord{14, 11, 183},\n\tdictWord{14, 11, 334},\n\tdictWord{14, 11, 362},\n\tdictWord{14, 11, 368},\n\tdictWord{14, 11, 376},\n\tdictWord{14, 11, 379},\n\tdictWord{\n\t\t19,\n\t\t11,\n\t\t90,\n\t},\n\tdictWord{19, 11, 103},\n\tdictWord{19, 11, 127},\n\tdictWord{148, 11, 90},\n\tdictWord{5, 0, 337},\n\tdictWord{11, 0, 513},\n\tdictWord{11, 0, 889},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t961,\n\t},\n\tdictWord{12, 0, 461},\n\tdictWord{13, 0, 79},\n\tdictWord{15, 0, 121},\n\tdictWord{4, 10, 90},\n\tdictWord{5, 10, 545},\n\tdictWord{7, 10, 754},\n\tdictWord{9, 10, 186},\n\tdictWord{10, 10, 72},\n\tdictWord{10, 10, 782},\n\tdictWord{11, 10, 577},\n\tdictWord{11, 10, 610},\n\tdictWord{12, 10, 354},\n\tdictWord{12, 10, 362},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t595,\n\t},\n\tdictWord{141, 0, 306},\n\tdictWord{136, 0, 146},\n\tdictWord{7, 0, 1646},\n\tdictWord{9, 10, 329},\n\tdictWord{11, 10, 254},\n\tdictWord{141, 11, 124},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t465,\n\t},\n\tdictWord{135, 0, 1663},\n\tdictWord{132, 0, 525},\n\tdictWord{133, 11, 663},\n\tdictWord{10, 0, 299},\n\tdictWord{18, 0, 74},\n\tdictWord{9, 10, 187},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t1016,\n\t},\n\tdictWord{145, 10, 44},\n\tdictWord{7, 0, 165},\n\tdictWord{7, 0, 919},\n\tdictWord{4, 10, 506},\n\tdictWord{136, 10, 517},\n\tdictWord{5, 10, 295},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1680,\n\t},\n\tdictWord{133, 11, 846},\n\tdictWord{134, 0, 1064},\n\tdictWord{5, 11, 378},\n\tdictWord{7, 11, 1402},\n\tdictWord{7, 11, 1414},\n\tdictWord{8, 11, 465},\n\tdictWord{9, 11, 286},\n\tdictWord{10, 11, 185},\n\tdictWord{10, 11, 562},\n\tdictWord{10, 11, 635},\n\tdictWord{11, 11, 31},\n\tdictWord{11, 11, 393},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t456,\n\t},\n\tdictWord{13, 11, 312},\n\tdictWord{18, 11, 65},\n\tdictWord{18, 11, 96},\n\tdictWord{147, 11, 89},\n\tdictWord{132, 0, 596},\n\tdictWord{7, 10, 987},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t688,\n\t},\n\tdictWord{10, 10, 522},\n\tdictWord{11, 10, 788},\n\tdictWord{140, 10, 566},\n\tdictWord{6, 0, 82},\n\tdictWord{7, 0, 138},\n\tdictWord{7, 0, 517},\n\tdictWord{7, 0, 1741},\n\tdictWord{11, 0, 238},\n\tdictWord{4, 11, 648},\n\tdictWord{134, 10, 1775},\n\tdictWord{7, 0, 1233},\n\tdictWord{7, 10, 700},\n\tdictWord{7, 10, 940},\n\tdictWord{8, 10, 514},\n\tdictWord{9, 10, 116},\n\tdictWord{9, 10, 535},\n\tdictWord{10, 10, 118},\n\tdictWord{11, 10, 107},\n\tdictWord{11, 10, 148},\n\tdictWord{11, 10, 922},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t254,\n\t},\n\tdictWord{12, 10, 421},\n\tdictWord{142, 10, 238},\n\tdictWord{4, 0, 962},\n\tdictWord{6, 0, 1824},\n\tdictWord{8, 0, 894},\n\tdictWord{12, 0, 708},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t725,\n\t},\n\tdictWord{14, 0, 451},\n\tdictWord{20, 0, 94},\n\tdictWord{22, 0, 59},\n\tdictWord{150, 0, 62},\n\tdictWord{5, 11, 945},\n\tdictWord{6, 11, 1656},\n\tdictWord{6, 11, 1787},\n\tdictWord{7, 11, 167},\n\tdictWord{8, 11, 824},\n\tdictWord{9, 11, 391},\n\tdictWord{10, 11, 375},\n\tdictWord{139, 11, 185},\n\tdictWord{5, 0, 495},\n\tdictWord{7, 0, 834},\n\tdictWord{9, 0, 733},\n\tdictWord{139, 0, 378},\n\tdictWord{4, 10, 743},\n\tdictWord{135, 11, 1273},\n\tdictWord{6, 0, 1204},\n\tdictWord{7, 11, 1645},\n\tdictWord{8, 11, 352},\n\tdictWord{137, 11, 249},\n\tdictWord{139, 10, 292},\n\tdictWord{133, 0, 559},\n\tdictWord{132, 11, 152},\n\tdictWord{9, 0, 499},\n\tdictWord{10, 0, 341},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t144,\n\t},\n\tdictWord{19, 0, 49},\n\tdictWord{7, 10, 1283},\n\tdictWord{9, 10, 227},\n\tdictWord{11, 10, 325},\n\tdictWord{11, 10, 408},\n\tdictWord{14, 10, 180},\n\tdictWord{\n\t\t146,\n\t\t10,\n\t\t47,\n\t},\n\tdictWord{6, 0, 21},\n\tdictWord{6, 0, 1737},\n\tdictWord{7, 0, 1444},\n\tdictWord{136, 0, 224},\n\tdictWord{133, 11, 1006},\n\tdictWord{7, 0, 1446},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t97,\n\t},\n\tdictWord{17, 0, 15},\n\tdictWord{5, 10, 81},\n\tdictWord{7, 10, 146},\n\tdictWord{7, 10, 1342},\n\tdictWord{8, 10, 53},\n\tdictWord{8, 10, 561},\n\tdictWord{8, 10, 694},\n\tdictWord{8, 10, 754},\n\tdictWord{9, 10, 115},\n\tdictWord{9, 10, 894},\n\tdictWord{10, 10, 462},\n\tdictWord{10, 10, 813},\n\tdictWord{11, 10, 230},\n\tdictWord{11, 10, 657},\n\tdictWord{11, 10, 699},\n\tdictWord{11, 10, 748},\n\tdictWord{12, 10, 119},\n\tdictWord{12, 10, 200},\n\tdictWord{12, 10, 283},\n\tdictWord{142, 10, 273},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t408,\n\t},\n\tdictWord{137, 10, 747},\n\tdictWord{135, 11, 431},\n\tdictWord{135, 11, 832},\n\tdictWord{6, 0, 729},\n\tdictWord{134, 0, 953},\n\tdictWord{4, 0, 727},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t565,\n\t},\n\tdictWord{5, 11, 351},\n\tdictWord{7, 11, 264},\n\tdictWord{136, 11, 565},\n\tdictWord{134, 0, 1948},\n\tdictWord{5, 0, 519},\n\tdictWord{5, 11, 40},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t598,\n\t},\n\tdictWord{7, 11, 1638},\n\tdictWord{8, 11, 78},\n\tdictWord{9, 11, 166},\n\tdictWord{9, 11, 640},\n\tdictWord{9, 11, 685},\n\tdictWord{9, 11, 773},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t215,\n\t},\n\tdictWord{13, 11, 65},\n\tdictWord{14, 11, 172},\n\tdictWord{14, 11, 317},\n\tdictWord{145, 11, 6},\n\tdictWord{8, 11, 60},\n\tdictWord{9, 11, 343},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t769,\n\t},\n\tdictWord{137, 11, 455},\n\tdictWord{134, 0, 1193},\n\tdictWord{140, 0, 790},\n\tdictWord{7, 11, 1951},\n\tdictWord{8, 11, 765},\n\tdictWord{8, 11, 772},\n\tdictWord{140, 11, 671},\n\tdictWord{7, 11, 108},\n\tdictWord{8, 11, 219},\n\tdictWord{8, 11, 388},\n\tdictWord{9, 11, 639},\n\tdictWord{9, 11, 775},\n\tdictWord{11, 11, 275},\n\tdictWord{140, 11, 464},\n\tdictWord{132, 11, 468},\n\tdictWord{7, 10, 30},\n\tdictWord{8, 10, 86},\n\tdictWord{8, 10, 315},\n\tdictWord{8, 10, 700},\n\tdictWord{9, 10, 576},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t858,\n\t},\n\tdictWord{11, 10, 310},\n\tdictWord{11, 10, 888},\n\tdictWord{11, 10, 904},\n\tdictWord{12, 10, 361},\n\tdictWord{141, 10, 248},\n\tdictWord{5, 11, 15},\n\tdictWord{6, 11, 56},\n\tdictWord{7, 11, 1758},\n\tdictWord{8, 11, 500},\n\tdictWord{9, 11, 730},\n\tdictWord{11, 11, 331},\n\tdictWord{13, 11, 150},\n\tdictWord{142, 11, 282},\n\tdictWord{4, 0, 402},\n\tdictWord{7, 0, 2},\n\tdictWord{8, 0, 323},\n\tdictWord{136, 0, 479},\n\tdictWord{138, 10, 839},\n\tdictWord{11, 0, 580},\n\tdictWord{142, 0, 201},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t59,\n\t},\n\tdictWord{135, 0, 672},\n\tdictWord{137, 10, 617},\n\tdictWord{146, 0, 34},\n\tdictWord{134, 11, 1886},\n\tdictWord{4, 0, 961},\n\tdictWord{136, 0, 896},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1285,\n\t},\n\tdictWord{5, 11, 205},\n\tdictWord{6, 11, 438},\n\tdictWord{137, 11, 711},\n\tdictWord{134, 10, 428},\n\tdictWord{7, 10, 524},\n\tdictWord{8, 10, 169},\n\tdictWord{8, 10, 234},\n\tdictWord{9, 10, 480},\n\tdictWord{138, 10, 646},\n\tdictWord{148, 0, 46},\n\tdictWord{141, 0, 479},\n\tdictWord{133, 11, 534},\n\tdictWord{6, 0, 2019},\n\tdictWord{134, 10, 1648},\n\tdictWord{4, 0, 85},\n\tdictWord{7, 0, 549},\n\tdictWord{7, 10, 1205},\n\tdictWord{138, 10, 637},\n\tdictWord{4, 0, 663},\n\tdictWord{5, 0, 94},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t235,\n\t},\n\tdictWord{7, 11, 1475},\n\tdictWord{15, 11, 68},\n\tdictWord{146, 11, 120},\n\tdictWord{6, 11, 443},\n\tdictWord{9, 11, 237},\n\tdictWord{9, 11, 571},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t695,\n\t},\n\tdictWord{10, 11, 139},\n\tdictWord{11, 11, 715},\n\tdictWord{12, 11, 417},\n\tdictWord{141, 11, 421},\n\tdictWord{132, 0, 783},\n\tdictWord{4, 0, 682},\n\tdictWord{8, 0, 65},\n\tdictWord{9, 10, 39},\n\tdictWord{10, 10, 166},\n\tdictWord{11, 10, 918},\n\tdictWord{12, 10, 635},\n\tdictWord{20, 10, 10},\n\tdictWord{22, 10, 27},\n\tdictWord{\n\t\t22,\n\t\t10,\n\t\t43,\n\t},\n\tdictWord{150, 10, 52},\n\tdictWord{6, 0, 11},\n\tdictWord{135, 0, 187},\n\tdictWord{132, 0, 522},\n\tdictWord{4, 0, 52},\n\tdictWord{135, 0, 661},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t383,\n\t},\n\tdictWord{133, 0, 520},\n\tdictWord{135, 11, 546},\n\tdictWord{11, 0, 343},\n\tdictWord{142, 0, 127},\n\tdictWord{4, 11, 578},\n\tdictWord{7, 10, 157},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t624,\n\t},\n\tdictWord{7, 11, 916},\n\tdictWord{8, 10, 279},\n\tdictWord{10, 11, 256},\n\tdictWord{11, 11, 87},\n\tdictWord{139, 11, 703},\n\tdictWord{134, 10, 604},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t281,\n\t},\n\tdictWord{5, 0, 38},\n\tdictWord{7, 0, 194},\n\tdictWord{7, 0, 668},\n\tdictWord{7, 0, 1893},\n\tdictWord{137, 0, 397},\n\tdictWord{7, 10, 945},\n\tdictWord{11, 10, 713},\n\tdictWord{139, 10, 744},\n\tdictWord{139, 10, 1022},\n\tdictWord{9, 0, 635},\n\tdictWord{139, 0, 559},\n\tdictWord{5, 11, 923},\n\tdictWord{7, 11, 490},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t553,\n\t},\n\tdictWord{13, 11, 100},\n\tdictWord{14, 11, 118},\n\tdictWord{143, 11, 75},\n\tdictWord{132, 0, 975},\n\tdictWord{132, 10, 567},\n\tdictWord{137, 10, 859},\n\tdictWord{7, 10, 1846},\n\tdictWord{7, 11, 1846},\n\tdictWord{8, 10, 628},\n\tdictWord{136, 11, 628},\n\tdictWord{148, 0, 116},\n\tdictWord{138, 11, 750},\n\tdictWord{14, 0, 51},\n\tdictWord{14, 11, 51},\n\tdictWord{15, 11, 7},\n\tdictWord{148, 11, 20},\n\tdictWord{132, 0, 858},\n\tdictWord{134, 0, 1075},\n\tdictWord{4, 11, 924},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t762,\n\t},\n\tdictWord{136, 0, 535},\n\tdictWord{133, 0, 448},\n\tdictWord{10, 10, 784},\n\tdictWord{141, 10, 191},\n\tdictWord{133, 10, 298},\n\tdictWord{7, 0, 610},\n\tdictWord{135, 0, 1501},\n\tdictWord{7, 10, 633},\n\tdictWord{7, 10, 905},\n\tdictWord{7, 10, 909},\n\tdictWord{7, 10, 1538},\n\tdictWord{9, 10, 767},\n\tdictWord{140, 10, 636},\n\tdictWord{4, 11, 265},\n\tdictWord{7, 11, 807},\n\tdictWord{135, 11, 950},\n\tdictWord{5, 11, 93},\n\tdictWord{12, 11, 267},\n\tdictWord{144, 11, 26},\n\tdictWord{136, 0, 191},\n\tdictWord{139, 10, 301},\n\tdictWord{135, 10, 1970},\n\tdictWord{135, 0, 267},\n\tdictWord{4, 0, 319},\n\tdictWord{5, 0, 699},\n\tdictWord{138, 0, 673},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t336,\n\t},\n\tdictWord{7, 0, 92},\n\tdictWord{7, 0, 182},\n\tdictWord{8, 0, 453},\n\tdictWord{8, 0, 552},\n\tdictWord{9, 0, 204},\n\tdictWord{9, 0, 285},\n\tdictWord{10, 0, 99},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t568,\n\t},\n\tdictWord{11, 0, 950},\n\tdictWord{12, 0, 94},\n\tdictWord{16, 0, 20},\n\tdictWord{16, 0, 70},\n\tdictWord{19, 0, 55},\n\tdictWord{12, 10, 644},\n\tdictWord{144, 10, 90},\n\tdictWord{6, 0, 551},\n\tdictWord{7, 0, 1308},\n\tdictWord{7, 10, 845},\n\tdictWord{7, 11, 994},\n\tdictWord{8, 10, 160},\n\tdictWord{137, 10, 318},\n\tdictWord{19, 11, 1},\n\tdictWord{\n\t\t19,\n\t\t11,\n\t\t26,\n\t},\n\tdictWord{150, 11, 9},\n\tdictWord{7, 0, 1406},\n\tdictWord{9, 0, 218},\n\tdictWord{141, 0, 222},\n\tdictWord{5, 0, 256},\n\tdictWord{138, 0, 69},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t233,\n\t},\n\tdictWord{5, 11, 320},\n\tdictWord{6, 11, 140},\n\tdictWord{7, 11, 330},\n\tdictWord{136, 11, 295},\n\tdictWord{6, 0, 1980},\n\tdictWord{136, 0, 952},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t833,\n\t},\n\tdictWord{137, 11, 678},\n\tdictWord{133, 11, 978},\n\tdictWord{4, 11, 905},\n\tdictWord{6, 11, 1701},\n\tdictWord{137, 11, 843},\n\tdictWord{138, 10, 735},\n\tdictWord{136, 10, 76},\n\tdictWord{17, 0, 39},\n\tdictWord{148, 0, 36},\n\tdictWord{18, 0, 81},\n\tdictWord{146, 11, 81},\n\tdictWord{14, 0, 352},\n\tdictWord{17, 0, 53},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t146,\n\t},\n\tdictWord{18, 0, 152},\n\tdictWord{19, 0, 11},\n\tdictWord{150, 0, 54},\n\tdictWord{135, 0, 634},\n\tdictWord{138, 10, 841},\n\tdictWord{132, 0, 618},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t339,\n\t},\n\tdictWord{7, 0, 259},\n\tdictWord{17, 0, 73},\n\tdictWord{4, 11, 275},\n\tdictWord{140, 11, 376},\n\tdictWord{132, 11, 509},\n\tdictWord{7, 11, 273},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t377,\n\t},\n\tdictWord{4, 0, 759},\n\tdictWord{13, 0, 169},\n\tdictWord{137, 10, 804},\n\tdictWord{6, 10, 96},\n\tdictWord{135, 10, 1426},\n\tdictWord{4, 10, 651},\n\tdictWord{133, 10, 289},\n\tdictWord{7, 0, 1075},\n\tdictWord{8, 10, 35},\n\tdictWord{9, 10, 511},\n\tdictWord{10, 10, 767},\n\tdictWord{147, 10, 118},\n\tdictWord{6, 0, 649},\n\tdictWord{6, 0, 670},\n\tdictWord{136, 0, 482},\n\tdictWord{5, 0, 336},\n\tdictWord{6, 0, 341},\n\tdictWord{6, 0, 478},\n\tdictWord{6, 0, 1763},\n\tdictWord{136, 0, 386},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t802,\n\t},\n\tdictWord{7, 11, 2021},\n\tdictWord{8, 11, 805},\n\tdictWord{14, 11, 94},\n\tdictWord{15, 11, 65},\n\tdictWord{16, 11, 4},\n\tdictWord{16, 11, 77},\n\tdictWord{16, 11, 80},\n\tdictWord{145, 11, 5},\n\tdictWord{6, 0, 1035},\n\tdictWord{5, 11, 167},\n\tdictWord{5, 11, 899},\n\tdictWord{6, 11, 410},\n\tdictWord{137, 11, 777},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t1705,\n\t},\n\tdictWord{5, 0, 924},\n\tdictWord{133, 0, 969},\n\tdictWord{132, 10, 704},\n\tdictWord{135, 0, 73},\n\tdictWord{135, 11, 10},\n\tdictWord{135, 10, 1078},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t11,\n\t},\n\tdictWord{6, 11, 117},\n\tdictWord{6, 11, 485},\n\tdictWord{7, 11, 1133},\n\tdictWord{9, 11, 582},\n\tdictWord{9, 11, 594},\n\tdictWord{11, 11, 21},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t818,\n\t},\n\tdictWord{12, 11, 535},\n\tdictWord{141, 11, 86},\n\tdictWord{135, 0, 1971},\n\tdictWord{4, 11, 264},\n\tdictWord{7, 11, 1067},\n\tdictWord{8, 11, 204},\n\tdictWord{8, 11, 385},\n\tdictWord{139, 11, 953},\n\tdictWord{6, 0, 1458},\n\tdictWord{135, 0, 1344},\n\tdictWord{5, 0, 396},\n\tdictWord{134, 0, 501},\n\tdictWord{4, 10, 720},\n\tdictWord{133, 10, 306},\n\tdictWord{4, 0, 929},\n\tdictWord{5, 0, 799},\n\tdictWord{8, 0, 46},\n\tdictWord{8, 0, 740},\n\tdictWord{133, 10, 431},\n\tdictWord{7, 11, 646},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1730,\n\t},\n\tdictWord{11, 11, 446},\n\tdictWord{141, 11, 178},\n\tdictWord{7, 0, 276},\n\tdictWord{5, 10, 464},\n\tdictWord{6, 10, 236},\n\tdictWord{7, 10, 696},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t914,\n\t},\n\tdictWord{7, 10, 1108},\n\tdictWord{7, 10, 1448},\n\tdictWord{9, 10, 15},\n\tdictWord{9, 10, 564},\n\tdictWord{10, 10, 14},\n\tdictWord{12, 10, 565},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t449,\n\t},\n\tdictWord{14, 10, 53},\n\tdictWord{15, 10, 13},\n\tdictWord{16, 10, 64},\n\tdictWord{145, 10, 41},\n\tdictWord{4, 0, 892},\n\tdictWord{133, 0, 770},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1767,\n\t},\n\tdictWord{12, 10, 194},\n\tdictWord{145, 10, 107},\n\tdictWord{135, 0, 158},\n\tdictWord{5, 10, 840},\n\tdictWord{138, 11, 608},\n\tdictWord{134, 0, 1432},\n\tdictWord{138, 11, 250},\n\tdictWord{8, 11, 794},\n\tdictWord{9, 11, 400},\n\tdictWord{10, 11, 298},\n\tdictWord{142, 11, 228},\n\tdictWord{151, 0, 25},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1131,\n\t},\n\tdictWord{135, 11, 1468},\n\tdictWord{135, 0, 2001},\n\tdictWord{9, 10, 642},\n\tdictWord{11, 10, 236},\n\tdictWord{142, 10, 193},\n\tdictWord{4, 10, 68},\n\tdictWord{5, 10, 634},\n\tdictWord{6, 10, 386},\n\tdictWord{7, 10, 794},\n\tdictWord{8, 10, 273},\n\tdictWord{9, 10, 563},\n\tdictWord{10, 10, 105},\n\tdictWord{10, 10, 171},\n\tdictWord{11, 10, 94},\n\tdictWord{139, 10, 354},\n\tdictWord{136, 11, 724},\n\tdictWord{132, 0, 478},\n\tdictWord{11, 11, 512},\n\tdictWord{13, 11, 205},\n\tdictWord{\n\t\t19,\n\t\t11,\n\t\t30,\n\t},\n\tdictWord{22, 11, 36},\n\tdictWord{151, 11, 19},\n\tdictWord{7, 0, 1461},\n\tdictWord{140, 0, 91},\n\tdictWord{6, 11, 190},\n\tdictWord{7, 11, 768},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1170,\n\t},\n\tdictWord{4, 0, 602},\n\tdictWord{8, 0, 211},\n\tdictWord{4, 10, 95},\n\tdictWord{7, 10, 416},\n\tdictWord{139, 10, 830},\n\tdictWord{7, 10, 731},\n\tdictWord{13, 10, 20},\n\tdictWord{143, 10, 11},\n\tdictWord{6, 0, 1068},\n\tdictWord{135, 0, 1872},\n\tdictWord{4, 0, 13},\n\tdictWord{5, 0, 567},\n\tdictWord{7, 0, 1498},\n\tdictWord{9, 0, 124},\n\tdictWord{11, 0, 521},\n\tdictWord{12, 0, 405},\n\tdictWord{135, 11, 1023},\n\tdictWord{135, 0, 1006},\n\tdictWord{132, 0, 735},\n\tdictWord{138, 0, 812},\n\tdictWord{4, 0, 170},\n\tdictWord{135, 0, 323},\n\tdictWord{6, 11, 137},\n\tdictWord{9, 11, 75},\n\tdictWord{9, 11, 253},\n\tdictWord{10, 11, 194},\n\tdictWord{138, 11, 444},\n\tdictWord{5, 0, 304},\n\tdictWord{7, 0, 1403},\n\tdictWord{5, 10, 864},\n\tdictWord{10, 10, 648},\n\tdictWord{11, 10, 671},\n\tdictWord{143, 10, 46},\n\tdictWord{135, 11, 1180},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t928,\n\t},\n\tdictWord{4, 0, 148},\n\tdictWord{133, 0, 742},\n\tdictWord{11, 10, 986},\n\tdictWord{140, 10, 682},\n\tdictWord{133, 0, 523},\n\tdictWord{135, 11, 1743},\n\tdictWord{7, 0, 730},\n\tdictWord{18, 0, 144},\n\tdictWord{19, 0, 61},\n\tdictWord{8, 10, 44},\n\tdictWord{9, 10, 884},\n\tdictWord{10, 10, 580},\n\tdictWord{11, 10, 399},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t894,\n\t},\n\tdictWord{143, 10, 122},\n\tdictWord{5, 11, 760},\n\tdictWord{7, 11, 542},\n\tdictWord{8, 11, 135},\n\tdictWord{136, 11, 496},\n\tdictWord{136, 0, 981},\n\tdictWord{133, 0, 111},\n\tdictWord{10, 0, 132},\n\tdictWord{11, 0, 191},\n\tdictWord{11, 0, 358},\n\tdictWord{139, 0, 460},\n\tdictWord{7, 11, 319},\n\tdictWord{7, 11, 355},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t763,\n\t},\n\tdictWord{10, 11, 389},\n\tdictWord{145, 11, 43},\n\tdictWord{134, 0, 890},\n\tdictWord{134, 0, 1420},\n\tdictWord{136, 11, 557},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t518,\n\t},\n\tdictWord{133, 0, 444},\n\tdictWord{135, 0, 1787},\n\tdictWord{135, 10, 1852},\n\tdictWord{8, 0, 123},\n\tdictWord{15, 0, 6},\n\tdictWord{144, 0, 7},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t2041,\n\t},\n\tdictWord{10, 11, 38},\n\tdictWord{139, 11, 784},\n\tdictWord{136, 0, 932},\n\tdictWord{5, 0, 937},\n\tdictWord{135, 0, 100},\n\tdictWord{6, 0, 995},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t58,\n\t},\n\tdictWord{5, 11, 286},\n\tdictWord{6, 11, 319},\n\tdictWord{7, 11, 402},\n\tdictWord{7, 11, 1254},\n\tdictWord{7, 11, 1903},\n\tdictWord{8, 11, 356},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t408,\n\t},\n\tdictWord{4, 11, 389},\n\tdictWord{9, 11, 181},\n\tdictWord{9, 11, 255},\n\tdictWord{10, 11, 8},\n\tdictWord{10, 11, 29},\n\tdictWord{10, 11, 816},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t311,\n\t},\n\tdictWord{11, 11, 561},\n\tdictWord{12, 11, 67},\n\tdictWord{141, 11, 181},\n\tdictWord{138, 0, 255},\n\tdictWord{5, 0, 138},\n\tdictWord{4, 10, 934},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t610,\n\t},\n\tdictWord{4, 0, 965},\n\tdictWord{10, 0, 863},\n\tdictWord{138, 0, 898},\n\tdictWord{10, 10, 804},\n\tdictWord{138, 10, 832},\n\tdictWord{12, 0, 631},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t96,\n\t},\n\tdictWord{9, 10, 36},\n\tdictWord{10, 10, 607},\n\tdictWord{11, 10, 423},\n\tdictWord{11, 10, 442},\n\tdictWord{12, 10, 309},\n\tdictWord{14, 10, 199},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t90,\n\t},\n\tdictWord{145, 10, 110},\n\tdictWord{134, 0, 1394},\n\tdictWord{4, 0, 652},\n\tdictWord{8, 0, 320},\n\tdictWord{22, 0, 6},\n\tdictWord{22, 0, 16},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t13,\n\t},\n\tdictWord{9, 10, 398},\n\tdictWord{9, 10, 727},\n\tdictWord{10, 10, 75},\n\tdictWord{10, 10, 184},\n\tdictWord{10, 10, 230},\n\tdictWord{10, 10, 564},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t569,\n\t},\n\tdictWord{11, 10, 973},\n\tdictWord{12, 10, 70},\n\tdictWord{12, 10, 189},\n\tdictWord{13, 10, 57},\n\tdictWord{141, 10, 257},\n\tdictWord{6, 0, 897},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1333,\n\t},\n\tdictWord{4, 0, 692},\n\tdictWord{133, 0, 321},\n\tdictWord{133, 11, 373},\n\tdictWord{135, 0, 922},\n\tdictWord{5, 0, 619},\n\tdictWord{133, 0, 698},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t631,\n\t},\n\tdictWord{5, 10, 345},\n\tdictWord{135, 10, 1016},\n\tdictWord{9, 0, 957},\n\tdictWord{9, 0, 1018},\n\tdictWord{12, 0, 828},\n\tdictWord{12, 0, 844},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t897,\n\t},\n\tdictWord{12, 0, 901},\n\tdictWord{12, 0, 943},\n\tdictWord{15, 0, 180},\n\tdictWord{18, 0, 197},\n\tdictWord{18, 0, 200},\n\tdictWord{18, 0, 213},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t214,\n\t},\n\tdictWord{146, 0, 226},\n\tdictWord{5, 0, 917},\n\tdictWord{134, 0, 1659},\n\tdictWord{135, 0, 1100},\n\tdictWord{134, 0, 1173},\n\tdictWord{134, 0, 1930},\n\tdictWord{5, 0, 251},\n\tdictWord{5, 0, 956},\n\tdictWord{8, 0, 268},\n\tdictWord{9, 0, 214},\n\tdictWord{146, 0, 142},\n\tdictWord{133, 10, 673},\n\tdictWord{137, 10, 850},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t287,\n\t},\n\tdictWord{133, 10, 1018},\n\tdictWord{132, 11, 672},\n\tdictWord{5, 0, 346},\n\tdictWord{5, 0, 711},\n\tdictWord{8, 0, 390},\n\tdictWord{11, 11, 752},\n\tdictWord{139, 11, 885},\n\tdictWord{5, 10, 34},\n\tdictWord{10, 10, 724},\n\tdictWord{12, 10, 444},\n\tdictWord{13, 10, 354},\n\tdictWord{18, 10, 32},\n\tdictWord{23, 10, 24},\n\tdictWord{23, 10, 31},\n\tdictWord{152, 10, 5},\n\tdictWord{4, 11, 710},\n\tdictWord{134, 11, 606},\n\tdictWord{134, 0, 744},\n\tdictWord{134, 10, 382},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t145,\n\t},\n\tdictWord{4, 10, 329},\n\tdictWord{7, 11, 884},\n\tdictWord{140, 11, 124},\n\tdictWord{4, 11, 467},\n\tdictWord{5, 11, 405},\n\tdictWord{134, 11, 544},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t846,\n\t},\n\tdictWord{138, 10, 827},\n\tdictWord{133, 0, 624},\n\tdictWord{9, 11, 372},\n\tdictWord{15, 11, 2},\n\tdictWord{19, 11, 10},\n\tdictWord{147, 11, 18},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t387,\n\t},\n\tdictWord{135, 11, 1288},\n\tdictWord{5, 0, 783},\n\tdictWord{7, 0, 1998},\n\tdictWord{135, 0, 2047},\n\tdictWord{132, 10, 906},\n\tdictWord{136, 10, 366},\n\tdictWord{135, 11, 550},\n\tdictWord{4, 10, 123},\n\tdictWord{4, 10, 649},\n\tdictWord{5, 10, 605},\n\tdictWord{7, 10, 1509},\n\tdictWord{136, 10, 36},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1125,\n\t},\n\tdictWord{132, 0, 594},\n\tdictWord{133, 10, 767},\n\tdictWord{135, 11, 1227},\n\tdictWord{136, 11, 467},\n\tdictWord{4, 11, 576},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1263,\n\t},\n\tdictWord{4, 0, 268},\n\tdictWord{7, 0, 1534},\n\tdictWord{135, 11, 1534},\n\tdictWord{4, 10, 273},\n\tdictWord{5, 10, 658},\n\tdictWord{5, 11, 919},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t995,\n\t},\n\tdictWord{134, 11, 1673},\n\tdictWord{133, 0, 563},\n\tdictWord{134, 10, 72},\n\tdictWord{135, 10, 1345},\n\tdictWord{4, 11, 82},\n\tdictWord{5, 11, 333},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t904,\n\t},\n\tdictWord{6, 11, 207},\n\tdictWord{7, 11, 325},\n\tdictWord{7, 11, 1726},\n\tdictWord{8, 11, 101},\n\tdictWord{10, 11, 778},\n\tdictWord{139, 11, 220},\n\tdictWord{5, 0, 37},\n\tdictWord{6, 0, 39},\n\tdictWord{6, 0, 451},\n\tdictWord{7, 0, 218},\n\tdictWord{7, 0, 667},\n\tdictWord{7, 0, 1166},\n\tdictWord{7, 0, 1687},\n\tdictWord{8, 0, 662},\n\tdictWord{16, 0, 2},\n\tdictWord{133, 10, 589},\n\tdictWord{134, 0, 1332},\n\tdictWord{133, 11, 903},\n\tdictWord{134, 0, 508},\n\tdictWord{5, 10, 117},\n\tdictWord{6, 10, 514},\n\tdictWord{6, 10, 541},\n\tdictWord{7, 10, 1164},\n\tdictWord{7, 10, 1436},\n\tdictWord{8, 10, 220},\n\tdictWord{8, 10, 648},\n\tdictWord{10, 10, 688},\n\tdictWord{11, 10, 560},\n\tdictWord{140, 11, 147},\n\tdictWord{6, 11, 555},\n\tdictWord{135, 11, 485},\n\tdictWord{133, 10, 686},\n\tdictWord{7, 0, 453},\n\tdictWord{7, 0, 635},\n\tdictWord{7, 0, 796},\n\tdictWord{8, 0, 331},\n\tdictWord{9, 0, 330},\n\tdictWord{9, 0, 865},\n\tdictWord{10, 0, 119},\n\tdictWord{10, 0, 235},\n\tdictWord{11, 0, 111},\n\tdictWord{11, 0, 129},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t240,\n\t},\n\tdictWord{12, 0, 31},\n\tdictWord{12, 0, 66},\n\tdictWord{12, 0, 222},\n\tdictWord{12, 0, 269},\n\tdictWord{12, 0, 599},\n\tdictWord{12, 0, 684},\n\tdictWord{12, 0, 689},\n\tdictWord{12, 0, 691},\n\tdictWord{142, 0, 345},\n\tdictWord{135, 0, 1834},\n\tdictWord{4, 11, 705},\n\tdictWord{7, 11, 615},\n\tdictWord{138, 11, 251},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t345,\n\t},\n\tdictWord{137, 0, 527},\n\tdictWord{6, 0, 98},\n\tdictWord{7, 0, 702},\n\tdictWord{135, 0, 991},\n\tdictWord{11, 0, 576},\n\tdictWord{14, 0, 74},\n\tdictWord{7, 10, 196},\n\tdictWord{10, 10, 765},\n\tdictWord{11, 10, 347},\n\tdictWord{11, 10, 552},\n\tdictWord{11, 10, 790},\n\tdictWord{12, 10, 263},\n\tdictWord{13, 10, 246},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t270,\n\t},\n\tdictWord{13, 10, 395},\n\tdictWord{14, 10, 176},\n\tdictWord{14, 10, 190},\n\tdictWord{14, 10, 398},\n\tdictWord{14, 10, 412},\n\tdictWord{15, 10, 32},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t63,\n\t},\n\tdictWord{16, 10, 88},\n\tdictWord{147, 10, 105},\n\tdictWord{134, 11, 90},\n\tdictWord{13, 0, 84},\n\tdictWord{141, 0, 122},\n\tdictWord{6, 0, 37},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t299,\n\t},\n\tdictWord{7, 0, 1666},\n\tdictWord{8, 0, 195},\n\tdictWord{8, 0, 316},\n\tdictWord{9, 0, 178},\n\tdictWord{9, 0, 276},\n\tdictWord{9, 0, 339},\n\tdictWord{9, 0, 536},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t102,\n\t},\n\tdictWord{10, 0, 362},\n\tdictWord{10, 0, 785},\n\tdictWord{11, 0, 55},\n\tdictWord{11, 0, 149},\n\tdictWord{11, 0, 773},\n\tdictWord{13, 0, 416},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t419,\n\t},\n\tdictWord{14, 0, 38},\n\tdictWord{14, 0, 41},\n\tdictWord{142, 0, 210},\n\tdictWord{5, 10, 381},\n\tdictWord{135, 10, 1792},\n\tdictWord{7, 11, 813},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t497,\n\t},\n\tdictWord{141, 11, 56},\n\tdictWord{7, 10, 616},\n\tdictWord{138, 10, 413},\n\tdictWord{133, 0, 645},\n\tdictWord{6, 11, 125},\n\tdictWord{135, 11, 1277},\n\tdictWord{132, 0, 290},\n\tdictWord{6, 0, 70},\n\tdictWord{7, 0, 1292},\n\tdictWord{10, 0, 762},\n\tdictWord{139, 0, 288},\n\tdictWord{6, 10, 120},\n\tdictWord{7, 10, 1188},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1710,\n\t},\n\tdictWord{8, 10, 286},\n\tdictWord{9, 10, 667},\n\tdictWord{11, 10, 592},\n\tdictWord{139, 10, 730},\n\tdictWord{135, 11, 1784},\n\tdictWord{7, 0, 1315},\n\tdictWord{135, 11, 1315},\n\tdictWord{134, 0, 1955},\n\tdictWord{135, 10, 1146},\n\tdictWord{7, 0, 131},\n\tdictWord{7, 0, 422},\n\tdictWord{8, 0, 210},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t573,\n\t},\n\tdictWord{4, 10, 352},\n\tdictWord{135, 10, 687},\n\tdictWord{139, 0, 797},\n\tdictWord{143, 0, 38},\n\tdictWord{14, 0, 179},\n\tdictWord{15, 0, 151},\n\tdictWord{\n\t\t150,\n\t\t0,\n\t\t11,\n\t},\n\tdictWord{7, 0, 488},\n\tdictWord{4, 10, 192},\n\tdictWord{5, 10, 49},\n\tdictWord{6, 10, 200},\n\tdictWord{6, 10, 293},\n\tdictWord{134, 10, 1696},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t936,\n\t},\n\tdictWord{135, 11, 703},\n\tdictWord{6, 11, 160},\n\tdictWord{7, 11, 1106},\n\tdictWord{9, 11, 770},\n\tdictWord{10, 11, 618},\n\tdictWord{11, 11, 112},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t413,\n\t},\n\tdictWord{5, 0, 453},\n\tdictWord{134, 0, 441},\n\tdictWord{135, 0, 595},\n\tdictWord{132, 10, 650},\n\tdictWord{132, 10, 147},\n\tdictWord{6, 0, 991},\n\tdictWord{6, 0, 1182},\n\tdictWord{12, 11, 271},\n\tdictWord{145, 11, 109},\n\tdictWord{133, 10, 934},\n\tdictWord{140, 11, 221},\n\tdictWord{132, 0, 653},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t505,\n\t},\n\tdictWord{135, 0, 523},\n\tdictWord{134, 0, 903},\n\tdictWord{135, 11, 479},\n\tdictWord{7, 11, 304},\n\tdictWord{9, 11, 646},\n\tdictWord{9, 11, 862},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t262,\n\t},\n\tdictWord{11, 11, 696},\n\tdictWord{12, 11, 208},\n\tdictWord{15, 11, 79},\n\tdictWord{147, 11, 108},\n\tdictWord{146, 0, 80},\n\tdictWord{135, 11, 981},\n\tdictWord{142, 0, 432},\n\tdictWord{132, 0, 314},\n\tdictWord{137, 11, 152},\n\tdictWord{7, 0, 1368},\n\tdictWord{8, 0, 232},\n\tdictWord{8, 0, 361},\n\tdictWord{10, 0, 682},\n\tdictWord{138, 0, 742},\n\tdictWord{135, 11, 1586},\n\tdictWord{9, 0, 534},\n\tdictWord{4, 11, 434},\n\tdictWord{11, 11, 663},\n\tdictWord{12, 11, 210},\n\tdictWord{13, 11, 166},\n\tdictWord{13, 11, 310},\n\tdictWord{14, 11, 373},\n\tdictWord{147, 11, 43},\n\tdictWord{7, 11, 1091},\n\tdictWord{135, 11, 1765},\n\tdictWord{6, 11, 550},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t652,\n\t},\n\tdictWord{137, 0, 27},\n\tdictWord{142, 0, 12},\n\tdictWord{4, 10, 637},\n\tdictWord{5, 11, 553},\n\tdictWord{7, 11, 766},\n\tdictWord{138, 11, 824},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t737,\n\t},\n\tdictWord{8, 11, 298},\n\tdictWord{136, 11, 452},\n\tdictWord{7, 0, 736},\n\tdictWord{139, 0, 264},\n\tdictWord{134, 0, 1657},\n\tdictWord{133, 11, 292},\n\tdictWord{138, 11, 135},\n\tdictWord{6, 0, 844},\n\tdictWord{134, 0, 1117},\n\tdictWord{135, 0, 127},\n\tdictWord{9, 10, 867},\n\tdictWord{138, 10, 837},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1184,\n\t},\n\tdictWord{134, 0, 1208},\n\tdictWord{134, 0, 1294},\n\tdictWord{136, 0, 364},\n\tdictWord{6, 0, 1415},\n\tdictWord{7, 0, 1334},\n\tdictWord{11, 0, 125},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t170,\n\t},\n\tdictWord{7, 11, 393},\n\tdictWord{8, 10, 395},\n\tdictWord{8, 10, 487},\n\tdictWord{10, 11, 603},\n\tdictWord{11, 11, 206},\n\tdictWord{141, 10, 147},\n\tdictWord{137, 11, 748},\n\tdictWord{4, 11, 912},\n\tdictWord{137, 11, 232},\n\tdictWord{4, 10, 535},\n\tdictWord{136, 10, 618},\n\tdictWord{137, 0, 792},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1973,\n\t},\n\tdictWord{136, 11, 716},\n\tdictWord{135, 11, 98},\n\tdictWord{5, 0, 909},\n\tdictWord{9, 0, 849},\n\tdictWord{138, 0, 805},\n\tdictWord{4, 0, 630},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t699,\n\t},\n\tdictWord{5, 11, 733},\n\tdictWord{14, 11, 103},\n\tdictWord{150, 10, 23},\n\tdictWord{12, 11, 158},\n\tdictWord{18, 11, 8},\n\tdictWord{19, 11, 62},\n\tdictWord{\n\t\t20,\n\t\t11,\n\t\t6,\n\t},\n\tdictWord{22, 11, 4},\n\tdictWord{23, 11, 2},\n\tdictWord{151, 11, 9},\n\tdictWord{132, 0, 968},\n\tdictWord{132, 10, 778},\n\tdictWord{132, 10, 46},\n\tdictWord{5, 10, 811},\n\tdictWord{6, 10, 1679},\n\tdictWord{6, 10, 1714},\n\tdictWord{135, 10, 2032},\n\tdictWord{6, 0, 1446},\n\tdictWord{7, 10, 1458},\n\tdictWord{9, 10, 407},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t15,\n\t},\n\tdictWord{7, 0, 206},\n\tdictWord{7, 0, 397},\n\tdictWord{7, 0, 621},\n\tdictWord{7, 0, 640},\n\tdictWord{8, 0, 124},\n\tdictWord{8, 0, 619},\n\tdictWord{9, 0, 305},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t643,\n\t},\n\tdictWord{10, 0, 264},\n\tdictWord{10, 0, 628},\n\tdictWord{11, 0, 40},\n\tdictWord{12, 0, 349},\n\tdictWord{13, 0, 134},\n\tdictWord{13, 0, 295},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t155,\n\t},\n\tdictWord{15, 0, 120},\n\tdictWord{18, 0, 105},\n\tdictWord{6, 10, 34},\n\tdictWord{7, 10, 1089},\n\tdictWord{8, 10, 708},\n\tdictWord{8, 10, 721},\n\tdictWord{9, 10, 363},\n\tdictWord{148, 10, 98},\n\tdictWord{4, 0, 262},\n\tdictWord{5, 0, 641},\n\tdictWord{135, 0, 342},\n\tdictWord{137, 11, 72},\n\tdictWord{4, 0, 99},\n\tdictWord{6, 0, 250},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t346,\n\t},\n\tdictWord{8, 0, 127},\n\tdictWord{138, 0, 81},\n\tdictWord{132, 0, 915},\n\tdictWord{5, 0, 75},\n\tdictWord{9, 0, 517},\n\tdictWord{10, 0, 470},\n\tdictWord{12, 0, 155},\n\tdictWord{141, 0, 224},\n\tdictWord{132, 10, 462},\n\tdictWord{11, 11, 600},\n\tdictWord{11, 11, 670},\n\tdictWord{141, 11, 245},\n\tdictWord{142, 0, 83},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t73,\n\t},\n\tdictWord{6, 10, 23},\n\tdictWord{134, 10, 338},\n\tdictWord{6, 0, 1031},\n\tdictWord{139, 11, 923},\n\tdictWord{7, 11, 164},\n\tdictWord{7, 11, 1571},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t107,\n\t},\n\tdictWord{140, 11, 225},\n\tdictWord{134, 0, 1470},\n\tdictWord{133, 0, 954},\n\tdictWord{6, 0, 304},\n\tdictWord{8, 0, 418},\n\tdictWord{10, 0, 345},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t341,\n\t},\n\tdictWord{139, 0, 675},\n\tdictWord{9, 0, 410},\n\tdictWord{139, 0, 425},\n\tdictWord{4, 11, 27},\n\tdictWord{5, 11, 484},\n\tdictWord{5, 11, 510},\n\tdictWord{6, 11, 434},\n\tdictWord{7, 11, 1000},\n\tdictWord{7, 11, 1098},\n\tdictWord{8, 11, 2},\n\tdictWord{136, 11, 200},\n\tdictWord{134, 0, 734},\n\tdictWord{140, 11, 257},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t725,\n\t},\n\tdictWord{8, 10, 498},\n\tdictWord{139, 10, 268},\n\tdictWord{134, 0, 1822},\n\tdictWord{135, 0, 1798},\n\tdictWord{135, 10, 773},\n\tdictWord{132, 11, 460},\n\tdictWord{4, 11, 932},\n\tdictWord{133, 11, 891},\n\tdictWord{134, 0, 14},\n\tdictWord{132, 10, 583},\n\tdictWord{7, 10, 1462},\n\tdictWord{8, 11, 625},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t659,\n\t},\n\tdictWord{5, 0, 113},\n\tdictWord{6, 0, 243},\n\tdictWord{6, 0, 1708},\n\tdictWord{7, 0, 1865},\n\tdictWord{11, 0, 161},\n\tdictWord{16, 0, 37},\n\tdictWord{17, 0, 99},\n\tdictWord{133, 10, 220},\n\tdictWord{134, 11, 76},\n\tdictWord{5, 11, 461},\n\tdictWord{135, 11, 1925},\n\tdictWord{140, 0, 69},\n\tdictWord{8, 11, 92},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t221,\n\t},\n\tdictWord{139, 10, 803},\n\tdictWord{132, 10, 544},\n\tdictWord{4, 0, 274},\n\tdictWord{134, 0, 922},\n\tdictWord{132, 0, 541},\n\tdictWord{5, 0, 627},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t437,\n\t},\n\tdictWord{6, 10, 564},\n\tdictWord{11, 10, 181},\n\tdictWord{141, 10, 183},\n\tdictWord{135, 10, 1192},\n\tdictWord{7, 0, 166},\n\tdictWord{132, 11, 763},\n\tdictWord{133, 11, 253},\n\tdictWord{134, 0, 849},\n\tdictWord{9, 11, 73},\n\tdictWord{10, 11, 110},\n\tdictWord{14, 11, 185},\n\tdictWord{145, 11, 119},\n\tdictWord{5, 11, 212},\n\tdictWord{12, 11, 35},\n\tdictWord{141, 11, 382},\n\tdictWord{133, 0, 717},\n\tdictWord{137, 0, 304},\n\tdictWord{136, 0, 600},\n\tdictWord{133, 0, 654},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t273,\n\t},\n\tdictWord{10, 0, 188},\n\tdictWord{13, 0, 377},\n\tdictWord{146, 0, 77},\n\tdictWord{4, 10, 790},\n\tdictWord{5, 10, 273},\n\tdictWord{134, 10, 394},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t543,\n\t},\n\tdictWord{135, 0, 410},\n\tdictWord{11, 0, 98},\n\tdictWord{11, 0, 524},\n\tdictWord{141, 0, 87},\n\tdictWord{132, 0, 941},\n\tdictWord{135, 11, 1175},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t250,\n\t},\n\tdictWord{7, 0, 1612},\n\tdictWord{11, 0, 186},\n\tdictWord{12, 0, 133},\n\tdictWord{6, 10, 127},\n\tdictWord{7, 10, 1511},\n\tdictWord{8, 10, 613},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t495,\n\t},\n\tdictWord{12, 10, 586},\n\tdictWord{12, 10, 660},\n\tdictWord{12, 10, 668},\n\tdictWord{14, 10, 385},\n\tdictWord{15, 10, 118},\n\tdictWord{17, 10, 20},\n\tdictWord{\n\t\t146,\n\t\t10,\n\t\t98,\n\t},\n\tdictWord{6, 0, 1785},\n\tdictWord{133, 11, 816},\n\tdictWord{134, 0, 1339},\n\tdictWord{7, 0, 961},\n\tdictWord{7, 0, 1085},\n\tdictWord{7, 0, 1727},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t462,\n\t},\n\tdictWord{6, 10, 230},\n\tdictWord{135, 11, 1727},\n\tdictWord{9, 0, 636},\n\tdictWord{135, 10, 1954},\n\tdictWord{132, 0, 780},\n\tdictWord{5, 11, 869},\n\tdictWord{5, 11, 968},\n\tdictWord{6, 11, 1626},\n\tdictWord{8, 11, 734},\n\tdictWord{136, 11, 784},\n\tdictWord{4, 11, 542},\n\tdictWord{6, 11, 1716},\n\tdictWord{6, 11, 1727},\n\tdictWord{7, 11, 1082},\n\tdictWord{7, 11, 1545},\n\tdictWord{8, 11, 56},\n\tdictWord{8, 11, 118},\n\tdictWord{8, 11, 412},\n\tdictWord{8, 11, 564},\n\tdictWord{9, 11, 888},\n\tdictWord{9, 11, 908},\n\tdictWord{10, 11, 50},\n\tdictWord{10, 11, 423},\n\tdictWord{11, 11, 685},\n\tdictWord{11, 11, 697},\n\tdictWord{11, 11, 933},\n\tdictWord{12, 11, 299},\n\tdictWord{13, 11, 126},\n\tdictWord{13, 11, 136},\n\tdictWord{13, 11, 170},\n\tdictWord{141, 11, 190},\n\tdictWord{134, 11, 226},\n\tdictWord{4, 11, 232},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t202,\n\t},\n\tdictWord{10, 11, 474},\n\tdictWord{140, 11, 433},\n\tdictWord{137, 11, 500},\n\tdictWord{5, 0, 529},\n\tdictWord{136, 10, 68},\n\tdictWord{132, 10, 654},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t156,\n\t},\n\tdictWord{7, 10, 998},\n\tdictWord{7, 10, 1045},\n\tdictWord{7, 10, 1860},\n\tdictWord{9, 10, 48},\n\tdictWord{9, 10, 692},\n\tdictWord{11, 10, 419},\n\tdictWord{139, 10, 602},\n\tdictWord{7, 0, 1276},\n\tdictWord{8, 0, 474},\n\tdictWord{9, 0, 652},\n\tdictWord{6, 11, 108},\n\tdictWord{7, 11, 1003},\n\tdictWord{7, 11, 1181},\n\tdictWord{136, 11, 343},\n\tdictWord{7, 11, 1264},\n\tdictWord{7, 11, 1678},\n\tdictWord{11, 11, 945},\n\tdictWord{12, 11, 341},\n\tdictWord{12, 11, 471},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t569,\n\t},\n\tdictWord{134, 11, 1712},\n\tdictWord{5, 0, 948},\n\tdictWord{12, 0, 468},\n\tdictWord{19, 0, 96},\n\tdictWord{148, 0, 24},\n\tdictWord{4, 11, 133},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t711,\n\t},\n\tdictWord{7, 11, 1298},\n\tdictWord{7, 11, 1585},\n\tdictWord{135, 11, 1929},\n\tdictWord{6, 0, 753},\n\tdictWord{140, 0, 657},\n\tdictWord{139, 0, 941},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t99,\n\t},\n\tdictWord{7, 11, 1808},\n\tdictWord{145, 11, 57},\n\tdictWord{6, 11, 574},\n\tdictWord{7, 11, 428},\n\tdictWord{7, 11, 1250},\n\tdictWord{10, 11, 669},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t485,\n\t},\n\tdictWord{11, 11, 840},\n\tdictWord{12, 11, 300},\n\tdictWord{142, 11, 250},\n\tdictWord{4, 0, 532},\n\tdictWord{5, 0, 706},\n\tdictWord{135, 0, 662},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t837,\n\t},\n\tdictWord{6, 0, 1651},\n\tdictWord{139, 0, 985},\n\tdictWord{7, 0, 1861},\n\tdictWord{9, 10, 197},\n\tdictWord{10, 10, 300},\n\tdictWord{12, 10, 473},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t90,\n\t},\n\tdictWord{141, 10, 405},\n\tdictWord{137, 11, 252},\n\tdictWord{6, 11, 323},\n\tdictWord{135, 11, 1564},\n\tdictWord{4, 0, 330},\n\tdictWord{4, 0, 863},\n\tdictWord{7, 0, 933},\n\tdictWord{7, 0, 2012},\n\tdictWord{8, 0, 292},\n\tdictWord{7, 11, 461},\n\tdictWord{8, 11, 775},\n\tdictWord{138, 11, 435},\n\tdictWord{132, 10, 606},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t655,\n\t},\n\tdictWord{7, 11, 850},\n\tdictWord{17, 11, 75},\n\tdictWord{146, 11, 137},\n\tdictWord{135, 0, 767},\n\tdictWord{7, 10, 1978},\n\tdictWord{136, 10, 676},\n\tdictWord{132, 0, 641},\n\tdictWord{135, 11, 1559},\n\tdictWord{134, 0, 1233},\n\tdictWord{137, 0, 242},\n\tdictWord{17, 0, 114},\n\tdictWord{4, 10, 361},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t315,\n\t},\n\tdictWord{137, 0, 883},\n\tdictWord{132, 10, 461},\n\tdictWord{138, 0, 274},\n\tdictWord{134, 0, 2008},\n\tdictWord{134, 0, 1794},\n\tdictWord{4, 0, 703},\n\tdictWord{135, 0, 207},\n\tdictWord{12, 0, 285},\n\tdictWord{132, 10, 472},\n\tdictWord{132, 0, 571},\n\tdictWord{5, 0, 873},\n\tdictWord{5, 0, 960},\n\tdictWord{8, 0, 823},\n\tdictWord{9, 0, 881},\n\tdictWord{136, 11, 577},\n\tdictWord{7, 0, 617},\n\tdictWord{10, 0, 498},\n\tdictWord{11, 0, 501},\n\tdictWord{12, 0, 16},\n\tdictWord{140, 0, 150},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t747,\n\t},\n\tdictWord{132, 0, 431},\n\tdictWord{133, 10, 155},\n\tdictWord{11, 0, 283},\n\tdictWord{11, 0, 567},\n\tdictWord{7, 10, 163},\n\tdictWord{8, 10, 319},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t402,\n\t},\n\tdictWord{10, 10, 24},\n\tdictWord{10, 10, 681},\n\tdictWord{11, 10, 200},\n\tdictWord{12, 10, 253},\n\tdictWord{12, 10, 410},\n\tdictWord{142, 10, 219},\n\tdictWord{4, 11, 413},\n\tdictWord{5, 11, 677},\n\tdictWord{8, 11, 432},\n\tdictWord{140, 11, 280},\n\tdictWord{9, 0, 401},\n\tdictWord{5, 10, 475},\n\tdictWord{7, 10, 1780},\n\tdictWord{11, 10, 297},\n\tdictWord{11, 10, 558},\n\tdictWord{14, 10, 322},\n\tdictWord{147, 10, 76},\n\tdictWord{6, 0, 781},\n\tdictWord{9, 0, 134},\n\tdictWord{10, 0, 2},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t27,\n\t},\n\tdictWord{10, 0, 333},\n\tdictWord{11, 0, 722},\n\tdictWord{143, 0, 1},\n\tdictWord{5, 0, 33},\n\tdictWord{6, 0, 470},\n\tdictWord{139, 0, 424},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t2006,\n\t},\n\tdictWord{12, 0, 783},\n\tdictWord{135, 10, 1956},\n\tdictWord{136, 0, 274},\n\tdictWord{135, 0, 1882},\n\tdictWord{132, 0, 794},\n\tdictWord{135, 0, 1848},\n\tdictWord{5, 10, 944},\n\tdictWord{134, 10, 1769},\n\tdictWord{6, 0, 47},\n\tdictWord{7, 0, 90},\n\tdictWord{7, 0, 664},\n\tdictWord{7, 0, 830},\n\tdictWord{7, 0, 1380},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t2025,\n\t},\n\tdictWord{8, 0, 448},\n\tdictWord{136, 0, 828},\n\tdictWord{132, 10, 144},\n\tdictWord{134, 0, 1199},\n\tdictWord{4, 11, 395},\n\tdictWord{139, 11, 762},\n\tdictWord{135, 11, 1504},\n\tdictWord{9, 0, 417},\n\tdictWord{137, 0, 493},\n\tdictWord{9, 11, 174},\n\tdictWord{10, 11, 164},\n\tdictWord{11, 11, 440},\n\tdictWord{11, 11, 841},\n\tdictWord{143, 11, 98},\n\tdictWord{134, 11, 426},\n\tdictWord{139, 11, 1002},\n\tdictWord{134, 0, 295},\n\tdictWord{134, 0, 816},\n\tdictWord{6, 10, 247},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t555,\n\t},\n\tdictWord{133, 0, 1019},\n\tdictWord{4, 0, 620},\n\tdictWord{5, 11, 476},\n\tdictWord{10, 10, 280},\n\tdictWord{138, 10, 797},\n\tdictWord{139, 0, 464},\n\tdictWord{5, 11, 76},\n\tdictWord{6, 11, 458},\n\tdictWord{6, 11, 497},\n\tdictWord{7, 11, 764},\n\tdictWord{7, 11, 868},\n\tdictWord{9, 11, 658},\n\tdictWord{10, 11, 594},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t173,\n\t},\n\tdictWord{11, 11, 566},\n\tdictWord{12, 11, 20},\n\tdictWord{12, 11, 338},\n\tdictWord{141, 11, 200},\n\tdictWord{134, 0, 208},\n\tdictWord{4, 11, 526},\n\tdictWord{7, 11, 1029},\n\tdictWord{135, 11, 1054},\n\tdictWord{132, 11, 636},\n\tdictWord{6, 11, 233},\n\tdictWord{7, 11, 660},\n\tdictWord{7, 11, 1124},\n\tdictWord{\n\t\t17,\n\t\t11,\n\t\t31,\n\t},\n\tdictWord{19, 11, 22},\n\tdictWord{151, 11, 14},\n\tdictWord{10, 0, 442},\n\tdictWord{133, 10, 428},\n\tdictWord{10, 0, 930},\n\tdictWord{140, 0, 778},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t68,\n\t},\n\tdictWord{7, 0, 448},\n\tdictWord{7, 0, 1629},\n\tdictWord{7, 0, 1769},\n\tdictWord{7, 0, 1813},\n\tdictWord{8, 0, 442},\n\tdictWord{8, 0, 516},\n\tdictWord{9, 0, 710},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t282,\n\t},\n\tdictWord{10, 0, 722},\n\tdictWord{7, 10, 1717},\n\tdictWord{138, 10, 546},\n\tdictWord{134, 0, 1128},\n\tdictWord{11, 0, 844},\n\tdictWord{12, 0, 104},\n\tdictWord{140, 0, 625},\n\tdictWord{4, 11, 432},\n\tdictWord{135, 11, 824},\n\tdictWord{138, 10, 189},\n\tdictWord{133, 0, 787},\n\tdictWord{133, 10, 99},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t279,\n\t},\n\tdictWord{7, 11, 301},\n\tdictWord{137, 11, 362},\n\tdictWord{8, 0, 491},\n\tdictWord{4, 10, 397},\n\tdictWord{136, 10, 555},\n\tdictWord{4, 11, 178},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t399,\n\t},\n\tdictWord{134, 0, 711},\n\tdictWord{144, 0, 9},\n\tdictWord{4, 0, 403},\n\tdictWord{5, 0, 441},\n\tdictWord{7, 0, 450},\n\tdictWord{10, 0, 840},\n\tdictWord{11, 0, 101},\n\tdictWord{12, 0, 193},\n\tdictWord{141, 0, 430},\n\tdictWord{135, 11, 1246},\n\tdictWord{12, 10, 398},\n\tdictWord{20, 10, 39},\n\tdictWord{21, 10, 11},\n\tdictWord{\n\t\t150,\n\t\t10,\n\t\t41,\n\t},\n\tdictWord{4, 10, 485},\n\tdictWord{7, 10, 353},\n\tdictWord{135, 10, 1523},\n\tdictWord{6, 10, 366},\n\tdictWord{7, 10, 1384},\n\tdictWord{7, 10, 1601},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1912,\n\t},\n\tdictWord{7, 0, 396},\n\tdictWord{10, 0, 160},\n\tdictWord{135, 11, 396},\n\tdictWord{137, 10, 282},\n\tdictWord{134, 11, 1692},\n\tdictWord{4, 10, 157},\n\tdictWord{5, 10, 471},\n\tdictWord{6, 11, 202},\n\tdictWord{10, 11, 448},\n\tdictWord{11, 11, 208},\n\tdictWord{12, 11, 360},\n\tdictWord{17, 11, 117},\n\tdictWord{\n\t\t17,\n\t\t11,\n\t\t118,\n\t},\n\tdictWord{18, 11, 27},\n\tdictWord{148, 11, 67},\n\tdictWord{133, 0, 679},\n\tdictWord{137, 0, 326},\n\tdictWord{136, 10, 116},\n\tdictWord{7, 11, 872},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t516,\n\t},\n\tdictWord{139, 11, 167},\n\tdictWord{132, 11, 224},\n\tdictWord{5, 11, 546},\n\tdictWord{7, 11, 35},\n\tdictWord{8, 11, 11},\n\tdictWord{8, 11, 12},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t315,\n\t},\n\tdictWord{9, 11, 533},\n\tdictWord{10, 11, 802},\n\tdictWord{11, 11, 166},\n\tdictWord{12, 11, 525},\n\tdictWord{142, 11, 243},\n\tdictWord{7, 0, 1128},\n\tdictWord{135, 11, 1920},\n\tdictWord{5, 11, 241},\n\tdictWord{8, 11, 242},\n\tdictWord{9, 11, 451},\n\tdictWord{10, 11, 667},\n\tdictWord{11, 11, 598},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t429,\n\t},\n\tdictWord{6, 0, 737},\n\tdictWord{5, 10, 160},\n\tdictWord{7, 10, 363},\n\tdictWord{7, 10, 589},\n\tdictWord{10, 10, 170},\n\tdictWord{141, 10, 55},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1796,\n\t},\n\tdictWord{142, 11, 254},\n\tdictWord{4, 0, 574},\n\tdictWord{7, 0, 350},\n\tdictWord{7, 0, 1024},\n\tdictWord{8, 0, 338},\n\tdictWord{9, 0, 677},\n\tdictWord{138, 0, 808},\n\tdictWord{134, 0, 1096},\n\tdictWord{137, 11, 516},\n\tdictWord{7, 0, 405},\n\tdictWord{10, 0, 491},\n\tdictWord{4, 10, 108},\n\tdictWord{4, 11, 366},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t498,\n\t},\n\tdictWord{11, 11, 337},\n\tdictWord{142, 11, 303},\n\tdictWord{134, 11, 1736},\n\tdictWord{7, 0, 1081},\n\tdictWord{140, 11, 364},\n\tdictWord{7, 10, 1005},\n\tdictWord{140, 10, 609},\n\tdictWord{7, 0, 1676},\n\tdictWord{4, 10, 895},\n\tdictWord{133, 10, 772},\n\tdictWord{135, 0, 2037},\n\tdictWord{6, 0, 1207},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t916,\n\t},\n\tdictWord{142, 11, 419},\n\tdictWord{14, 11, 140},\n\tdictWord{148, 11, 41},\n\tdictWord{6, 11, 331},\n\tdictWord{136, 11, 623},\n\tdictWord{9, 0, 944},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t969,\n\t},\n\tdictWord{9, 0, 1022},\n\tdictWord{12, 0, 913},\n\tdictWord{12, 0, 936},\n\tdictWord{15, 0, 177},\n\tdictWord{15, 0, 193},\n\tdictWord{4, 10, 926},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t983,\n\t},\n\tdictWord{5, 0, 354},\n\tdictWord{135, 11, 506},\n\tdictWord{8, 0, 598},\n\tdictWord{9, 0, 664},\n\tdictWord{138, 0, 441},\n\tdictWord{4, 11, 640},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t513,\n\t},\n\tdictWord{137, 0, 297},\n\tdictWord{132, 10, 538},\n\tdictWord{6, 10, 294},\n\tdictWord{7, 10, 1267},\n\tdictWord{136, 10, 624},\n\tdictWord{7, 0, 1772},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1888,\n\t},\n\tdictWord{8, 11, 289},\n\tdictWord{11, 11, 45},\n\tdictWord{12, 11, 278},\n\tdictWord{140, 11, 537},\n\tdictWord{135, 10, 1325},\n\tdictWord{138, 0, 751},\n\tdictWord{141, 0, 37},\n\tdictWord{134, 0, 1828},\n\tdictWord{132, 10, 757},\n\tdictWord{132, 11, 394},\n\tdictWord{6, 0, 257},\n\tdictWord{135, 0, 1522},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t582,\n\t},\n\tdictWord{9, 0, 191},\n\tdictWord{135, 11, 1931},\n\tdictWord{7, 11, 574},\n\tdictWord{7, 11, 1719},\n\tdictWord{137, 11, 145},\n\tdictWord{132, 11, 658},\n\tdictWord{10, 0, 790},\n\tdictWord{132, 11, 369},\n\tdictWord{9, 11, 781},\n\tdictWord{10, 11, 144},\n\tdictWord{11, 11, 385},\n\tdictWord{13, 11, 161},\n\tdictWord{13, 11, 228},\n\tdictWord{13, 11, 268},\n\tdictWord{148, 11, 107},\n\tdictWord{8, 0, 469},\n\tdictWord{10, 0, 47},\n\tdictWord{136, 11, 374},\n\tdictWord{6, 0, 306},\n\tdictWord{7, 0, 1140},\n\tdictWord{7, 0, 1340},\n\tdictWord{8, 0, 133},\n\tdictWord{138, 0, 449},\n\tdictWord{139, 0, 1011},\n\tdictWord{7, 10, 1875},\n\tdictWord{139, 10, 124},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t344,\n\t},\n\tdictWord{6, 11, 498},\n\tdictWord{139, 11, 323},\n\tdictWord{137, 0, 299},\n\tdictWord{132, 0, 837},\n\tdictWord{133, 11, 906},\n\tdictWord{5, 0, 329},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t260,\n\t},\n\tdictWord{138, 0, 10},\n\tdictWord{134, 0, 1320},\n\tdictWord{4, 0, 657},\n\tdictWord{146, 0, 158},\n\tdictWord{135, 0, 1191},\n\tdictWord{152, 0, 7},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1939,\n\t},\n\tdictWord{8, 0, 974},\n\tdictWord{138, 0, 996},\n\tdictWord{135, 0, 1665},\n\tdictWord{11, 11, 126},\n\tdictWord{139, 11, 287},\n\tdictWord{143, 0, 8},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t149,\n\t},\n\tdictWord{14, 11, 399},\n\tdictWord{143, 11, 57},\n\tdictWord{5, 0, 66},\n\tdictWord{7, 0, 1896},\n\tdictWord{136, 0, 288},\n\tdictWord{7, 0, 175},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t494,\n\t},\n\tdictWord{5, 10, 150},\n\tdictWord{8, 10, 603},\n\tdictWord{9, 10, 593},\n\tdictWord{9, 10, 634},\n\tdictWord{10, 10, 173},\n\tdictWord{11, 10, 462},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t515,\n\t},\n\tdictWord{13, 10, 216},\n\tdictWord{13, 10, 288},\n\tdictWord{142, 10, 400},\n\tdictWord{134, 0, 1643},\n\tdictWord{136, 11, 21},\n\tdictWord{4, 0, 21},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t91,\n\t},\n\tdictWord{5, 0, 648},\n\tdictWord{5, 0, 750},\n\tdictWord{5, 0, 781},\n\tdictWord{6, 0, 54},\n\tdictWord{6, 0, 112},\n\tdictWord{6, 0, 402},\n\tdictWord{6, 0, 1732},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t315,\n\t},\n\tdictWord{7, 0, 749},\n\tdictWord{7, 0, 1427},\n\tdictWord{7, 0, 1900},\n\tdictWord{9, 0, 78},\n\tdictWord{9, 0, 508},\n\tdictWord{10, 0, 611},\n\tdictWord{10, 0, 811},\n\tdictWord{11, 0, 510},\n\tdictWord{11, 0, 728},\n\tdictWord{13, 0, 36},\n\tdictWord{14, 0, 39},\n\tdictWord{16, 0, 83},\n\tdictWord{17, 0, 124},\n\tdictWord{148, 0, 30},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t668,\n\t},\n\tdictWord{136, 0, 570},\n\tdictWord{10, 0, 322},\n\tdictWord{10, 0, 719},\n\tdictWord{139, 0, 407},\n\tdictWord{135, 11, 1381},\n\tdictWord{136, 11, 193},\n\tdictWord{12, 10, 108},\n\tdictWord{141, 10, 291},\n\tdictWord{132, 11, 616},\n\tdictWord{136, 11, 692},\n\tdictWord{8, 0, 125},\n\tdictWord{8, 0, 369},\n\tdictWord{8, 0, 524},\n\tdictWord{10, 0, 486},\n\tdictWord{11, 0, 13},\n\tdictWord{11, 0, 381},\n\tdictWord{11, 0, 736},\n\tdictWord{11, 0, 766},\n\tdictWord{11, 0, 845},\n\tdictWord{13, 0, 114},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t292,\n\t},\n\tdictWord{142, 0, 47},\n\tdictWord{134, 0, 1247},\n\tdictWord{6, 0, 1684},\n\tdictWord{6, 0, 1731},\n\tdictWord{7, 0, 356},\n\tdictWord{8, 0, 54},\n\tdictWord{8, 0, 221},\n\tdictWord{9, 0, 225},\n\tdictWord{9, 0, 356},\n\tdictWord{10, 0, 77},\n\tdictWord{10, 0, 446},\n\tdictWord{10, 0, 731},\n\tdictWord{12, 0, 404},\n\tdictWord{141, 0, 491},\n\tdictWord{135, 10, 1777},\n\tdictWord{4, 11, 305},\n\tdictWord{4, 10, 493},\n\tdictWord{144, 10, 55},\n\tdictWord{4, 0, 951},\n\tdictWord{6, 0, 1809},\n\tdictWord{6, 0, 1849},\n\tdictWord{8, 0, 846},\n\tdictWord{8, 0, 866},\n\tdictWord{8, 0, 899},\n\tdictWord{10, 0, 896},\n\tdictWord{12, 0, 694},\n\tdictWord{142, 0, 468},\n\tdictWord{5, 11, 214},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t603,\n\t},\n\tdictWord{8, 11, 611},\n\tdictWord{9, 11, 686},\n\tdictWord{10, 11, 88},\n\tdictWord{11, 11, 459},\n\tdictWord{11, 11, 496},\n\tdictWord{12, 11, 463},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t590,\n\t},\n\tdictWord{13, 11, 0},\n\tdictWord{142, 11, 214},\n\tdictWord{132, 0, 411},\n\tdictWord{4, 0, 80},\n\tdictWord{133, 0, 44},\n\tdictWord{140, 11, 74},\n\tdictWord{\n\t\t143,\n\t\t0,\n\t\t31,\n\t},\n\tdictWord{7, 0, 669},\n\tdictWord{6, 10, 568},\n\tdictWord{7, 10, 1804},\n\tdictWord{8, 10, 362},\n\tdictWord{8, 10, 410},\n\tdictWord{8, 10, 830},\n\tdictWord{9, 10, 514},\n\tdictWord{11, 10, 649},\n\tdictWord{142, 10, 157},\n\tdictWord{7, 0, 673},\n\tdictWord{134, 11, 1703},\n\tdictWord{132, 10, 625},\n\tdictWord{134, 0, 1303},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t299,\n\t},\n\tdictWord{135, 0, 1083},\n\tdictWord{138, 0, 704},\n\tdictWord{6, 0, 275},\n\tdictWord{7, 0, 408},\n\tdictWord{6, 10, 158},\n\tdictWord{7, 10, 129},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t181,\n\t},\n\tdictWord{8, 10, 276},\n\tdictWord{8, 10, 377},\n\tdictWord{10, 10, 523},\n\tdictWord{11, 10, 816},\n\tdictWord{12, 10, 455},\n\tdictWord{13, 10, 303},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t135,\n\t},\n\tdictWord{4, 0, 219},\n\tdictWord{7, 0, 367},\n\tdictWord{7, 0, 1713},\n\tdictWord{7, 0, 1761},\n\tdictWord{9, 0, 86},\n\tdictWord{9, 0, 537},\n\tdictWord{10, 0, 165},\n\tdictWord{12, 0, 219},\n\tdictWord{140, 0, 561},\n\tdictWord{8, 0, 216},\n\tdictWord{4, 10, 1},\n\tdictWord{4, 11, 737},\n\tdictWord{6, 11, 317},\n\tdictWord{7, 10, 1143},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1463,\n\t},\n\tdictWord{9, 10, 207},\n\tdictWord{9, 10, 390},\n\tdictWord{9, 10, 467},\n\tdictWord{10, 11, 98},\n\tdictWord{11, 11, 294},\n\tdictWord{11, 10, 836},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t60,\n\t},\n\tdictWord{12, 11, 437},\n\tdictWord{13, 11, 64},\n\tdictWord{13, 11, 380},\n\tdictWord{142, 11, 430},\n\tdictWord{6, 11, 1758},\n\tdictWord{8, 11, 520},\n\tdictWord{9, 11, 345},\n\tdictWord{9, 11, 403},\n\tdictWord{142, 11, 350},\n\tdictWord{5, 11, 47},\n\tdictWord{10, 11, 242},\n\tdictWord{138, 11, 579},\n\tdictWord{5, 11, 139},\n\tdictWord{7, 11, 1168},\n\tdictWord{138, 11, 539},\n\tdictWord{135, 0, 1319},\n\tdictWord{4, 10, 295},\n\tdictWord{4, 10, 723},\n\tdictWord{5, 10, 895},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1031,\n\t},\n\tdictWord{8, 10, 199},\n\tdictWord{8, 10, 340},\n\tdictWord{9, 10, 153},\n\tdictWord{9, 10, 215},\n\tdictWord{10, 10, 21},\n\tdictWord{10, 10, 59},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t80,\n\t},\n\tdictWord{10, 10, 224},\n\tdictWord{10, 10, 838},\n\tdictWord{11, 10, 229},\n\tdictWord{11, 10, 652},\n\tdictWord{12, 10, 192},\n\tdictWord{13, 10, 146},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t91,\n\t},\n\tdictWord{140, 0, 428},\n\tdictWord{137, 10, 51},\n\tdictWord{133, 0, 514},\n\tdictWord{5, 10, 309},\n\tdictWord{140, 10, 211},\n\tdictWord{6, 0, 1010},\n\tdictWord{5, 10, 125},\n\tdictWord{8, 10, 77},\n\tdictWord{138, 10, 15},\n\tdictWord{4, 0, 55},\n\tdictWord{5, 0, 301},\n\tdictWord{6, 0, 571},\n\tdictWord{142, 0, 49},\n\tdictWord{\n\t\t146,\n\t\t0,\n\t\t102,\n\t},\n\tdictWord{136, 11, 370},\n\tdictWord{4, 11, 107},\n\tdictWord{7, 11, 613},\n\tdictWord{8, 11, 358},\n\tdictWord{8, 11, 439},\n\tdictWord{8, 11, 504},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t501,\n\t},\n\tdictWord{10, 11, 383},\n\tdictWord{139, 11, 477},\n\tdictWord{132, 11, 229},\n\tdictWord{133, 0, 364},\n\tdictWord{133, 10, 439},\n\tdictWord{4, 11, 903},\n\tdictWord{135, 11, 1816},\n\tdictWord{11, 0, 379},\n\tdictWord{140, 10, 76},\n\tdictWord{4, 0, 76},\n\tdictWord{4, 0, 971},\n\tdictWord{7, 0, 1550},\n\tdictWord{9, 0, 306},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t430,\n\t},\n\tdictWord{9, 0, 663},\n\tdictWord{10, 0, 683},\n\tdictWord{10, 0, 921},\n\tdictWord{11, 0, 427},\n\tdictWord{11, 0, 753},\n\tdictWord{12, 0, 334},\n\tdictWord{12, 0, 442},\n\tdictWord{14, 0, 258},\n\tdictWord{14, 0, 366},\n\tdictWord{143, 0, 131},\n\tdictWord{137, 0, 52},\n\tdictWord{4, 11, 47},\n\tdictWord{6, 11, 373},\n\tdictWord{7, 11, 452},\n\tdictWord{7, 11, 543},\n\tdictWord{7, 11, 1714},\n\tdictWord{7, 11, 1856},\n\tdictWord{9, 11, 6},\n\tdictWord{11, 11, 257},\n\tdictWord{139, 11, 391},\n\tdictWord{4, 10, 8},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1152,\n\t},\n\tdictWord{7, 10, 1153},\n\tdictWord{7, 10, 1715},\n\tdictWord{9, 10, 374},\n\tdictWord{10, 10, 478},\n\tdictWord{139, 10, 648},\n\tdictWord{4, 11, 785},\n\tdictWord{133, 11, 368},\n\tdictWord{135, 10, 1099},\n\tdictWord{135, 11, 860},\n\tdictWord{5, 11, 980},\n\tdictWord{134, 11, 1754},\n\tdictWord{134, 0, 1258},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1058,\n\t},\n\tdictWord{6, 0, 1359},\n\tdictWord{7, 11, 536},\n\tdictWord{7, 11, 1331},\n\tdictWord{136, 11, 143},\n\tdictWord{4, 0, 656},\n\tdictWord{135, 0, 779},\n\tdictWord{136, 10, 87},\n\tdictWord{5, 11, 19},\n\tdictWord{6, 11, 533},\n\tdictWord{146, 11, 126},\n\tdictWord{7, 0, 144},\n\tdictWord{138, 10, 438},\n\tdictWord{5, 11, 395},\n\tdictWord{5, 11, 951},\n\tdictWord{134, 11, 1776},\n\tdictWord{135, 0, 1373},\n\tdictWord{7, 0, 554},\n\tdictWord{7, 0, 605},\n\tdictWord{141, 0, 10},\n\tdictWord{4, 10, 69},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t122,\n\t},\n\tdictWord{9, 10, 656},\n\tdictWord{138, 10, 464},\n\tdictWord{5, 10, 849},\n\tdictWord{134, 10, 1633},\n\tdictWord{5, 0, 838},\n\tdictWord{5, 0, 841},\n\tdictWord{134, 0, 1649},\n\tdictWord{133, 0, 1012},\n\tdictWord{139, 10, 499},\n\tdictWord{7, 10, 476},\n\tdictWord{7, 10, 1592},\n\tdictWord{138, 10, 87},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t251,\n\t},\n\tdictWord{7, 0, 365},\n\tdictWord{7, 0, 1357},\n\tdictWord{7, 0, 1497},\n\tdictWord{8, 0, 154},\n\tdictWord{141, 0, 281},\n\tdictWord{132, 11, 441},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t695,\n\t},\n\tdictWord{7, 11, 497},\n\tdictWord{9, 11, 387},\n\tdictWord{147, 11, 81},\n\tdictWord{133, 0, 340},\n\tdictWord{14, 10, 283},\n\tdictWord{142, 11, 283},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t810,\n\t},\n\tdictWord{135, 11, 1894},\n\tdictWord{139, 0, 495},\n\tdictWord{5, 11, 284},\n\tdictWord{6, 11, 49},\n\tdictWord{6, 11, 350},\n\tdictWord{7, 11, 1},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t377,\n\t},\n\tdictWord{7, 11, 1693},\n\tdictWord{8, 11, 18},\n\tdictWord{8, 11, 678},\n\tdictWord{9, 11, 161},\n\tdictWord{9, 11, 585},\n\tdictWord{9, 11, 671},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t839,\n\t},\n\tdictWord{11, 11, 912},\n\tdictWord{141, 11, 427},\n\tdictWord{5, 10, 859},\n\tdictWord{7, 10, 1160},\n\tdictWord{8, 10, 107},\n\tdictWord{9, 10, 291},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t439,\n\t},\n\tdictWord{10, 10, 663},\n\tdictWord{11, 10, 609},\n\tdictWord{140, 10, 197},\n\tdictWord{8, 0, 261},\n\tdictWord{9, 0, 144},\n\tdictWord{9, 0, 466},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t370,\n\t},\n\tdictWord{12, 0, 470},\n\tdictWord{13, 0, 144},\n\tdictWord{142, 0, 348},\n\tdictWord{137, 0, 897},\n\tdictWord{6, 0, 248},\n\tdictWord{9, 0, 546},\n\tdictWord{10, 0, 535},\n\tdictWord{11, 0, 681},\n\tdictWord{141, 0, 135},\n\tdictWord{4, 0, 358},\n\tdictWord{135, 0, 1496},\n\tdictWord{134, 0, 567},\n\tdictWord{136, 0, 445},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t117,\n\t},\n\tdictWord{6, 10, 372},\n\tdictWord{7, 10, 1905},\n\tdictWord{142, 10, 323},\n\tdictWord{4, 10, 722},\n\tdictWord{139, 10, 471},\n\tdictWord{6, 0, 697},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t996,\n\t},\n\tdictWord{7, 11, 2007},\n\tdictWord{9, 11, 101},\n\tdictWord{9, 11, 450},\n\tdictWord{10, 11, 66},\n\tdictWord{10, 11, 842},\n\tdictWord{11, 11, 536},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t587,\n\t},\n\tdictWord{132, 0, 577},\n\tdictWord{134, 0, 1336},\n\tdictWord{9, 10, 5},\n\tdictWord{12, 10, 216},\n\tdictWord{12, 10, 294},\n\tdictWord{12, 10, 298},\n\tdictWord{12, 10, 400},\n\tdictWord{12, 10, 518},\n\tdictWord{13, 10, 229},\n\tdictWord{143, 10, 139},\n\tdictWord{6, 0, 174},\n\tdictWord{138, 0, 917},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1774,\n\t},\n\tdictWord{5, 10, 12},\n\tdictWord{7, 10, 375},\n\tdictWord{9, 10, 88},\n\tdictWord{9, 10, 438},\n\tdictWord{11, 11, 62},\n\tdictWord{139, 10, 270},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t1766,\n\t},\n\tdictWord{6, 11, 0},\n\tdictWord{7, 11, 84},\n\tdictWord{7, 10, 816},\n\tdictWord{7, 10, 1241},\n\tdictWord{9, 10, 283},\n\tdictWord{9, 10, 520},\n\tdictWord{10, 10, 213},\n\tdictWord{10, 10, 307},\n\tdictWord{10, 10, 463},\n\tdictWord{10, 10, 671},\n\tdictWord{10, 10, 746},\n\tdictWord{11, 10, 401},\n\tdictWord{11, 10, 794},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t895,\n\t},\n\tdictWord{12, 10, 517},\n\tdictWord{17, 11, 11},\n\tdictWord{18, 10, 107},\n\tdictWord{147, 10, 115},\n\tdictWord{5, 0, 878},\n\tdictWord{133, 0, 972},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t1665,\n\t},\n\tdictWord{7, 11, 256},\n\tdictWord{7, 11, 1388},\n\tdictWord{138, 11, 499},\n\tdictWord{4, 10, 258},\n\tdictWord{136, 10, 639},\n\tdictWord{4, 11, 22},\n\tdictWord{5, 11, 10},\n\tdictWord{6, 10, 22},\n\tdictWord{7, 11, 848},\n\tdictWord{7, 10, 903},\n\tdictWord{7, 10, 1963},\n\tdictWord{8, 11, 97},\n\tdictWord{138, 10, 577},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t681,\n\t},\n\tdictWord{136, 10, 782},\n\tdictWord{133, 11, 481},\n\tdictWord{132, 0, 351},\n\tdictWord{4, 10, 664},\n\tdictWord{5, 10, 804},\n\tdictWord{139, 10, 1013},\n\tdictWord{6, 11, 134},\n\tdictWord{7, 11, 437},\n\tdictWord{7, 11, 959},\n\tdictWord{9, 11, 37},\n\tdictWord{14, 11, 285},\n\tdictWord{14, 11, 371},\n\tdictWord{144, 11, 60},\n\tdictWord{7, 11, 486},\n\tdictWord{8, 11, 155},\n\tdictWord{11, 11, 93},\n\tdictWord{140, 11, 164},\n\tdictWord{132, 0, 286},\n\tdictWord{7, 0, 438},\n\tdictWord{7, 0, 627},\n\tdictWord{7, 0, 1516},\n\tdictWord{8, 0, 40},\n\tdictWord{9, 0, 56},\n\tdictWord{9, 0, 294},\n\tdictWord{10, 0, 30},\n\tdictWord{11, 0, 969},\n\tdictWord{11, 0, 995},\n\tdictWord{146, 0, 148},\n\tdictWord{5, 11, 591},\n\tdictWord{135, 11, 337},\n\tdictWord{134, 0, 1950},\n\tdictWord{133, 10, 32},\n\tdictWord{138, 11, 500},\n\tdictWord{5, 11, 380},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t650,\n\t},\n\tdictWord{136, 11, 310},\n\tdictWord{4, 11, 364},\n\tdictWord{7, 11, 1156},\n\tdictWord{7, 11, 1187},\n\tdictWord{137, 11, 409},\n\tdictWord{4, 0, 738},\n\tdictWord{134, 11, 482},\n\tdictWord{4, 11, 781},\n\tdictWord{6, 11, 487},\n\tdictWord{7, 11, 926},\n\tdictWord{8, 11, 263},\n\tdictWord{139, 11, 500},\n\tdictWord{135, 11, 418},\n\tdictWord{6, 0, 2047},\n\tdictWord{10, 0, 969},\n\tdictWord{4, 10, 289},\n\tdictWord{7, 10, 629},\n\tdictWord{7, 10, 1698},\n\tdictWord{7, 10, 1711},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t215,\n\t},\n\tdictWord{6, 10, 450},\n\tdictWord{136, 10, 109},\n\tdictWord{134, 0, 818},\n\tdictWord{136, 10, 705},\n\tdictWord{133, 0, 866},\n\tdictWord{4, 11, 94},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1265,\n\t},\n\tdictWord{132, 11, 417},\n\tdictWord{134, 0, 1467},\n\tdictWord{135, 10, 1238},\n\tdictWord{4, 0, 972},\n\tdictWord{6, 0, 1851},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1857,\n\t},\n\tdictWord{134, 0, 355},\n\tdictWord{133, 0, 116},\n\tdictWord{132, 0, 457},\n\tdictWord{135, 11, 1411},\n\tdictWord{4, 11, 408},\n\tdictWord{4, 11, 741},\n\tdictWord{135, 11, 500},\n\tdictWord{134, 10, 26},\n\tdictWord{142, 11, 137},\n\tdictWord{5, 0, 527},\n\tdictWord{6, 0, 189},\n\tdictWord{7, 0, 859},\n\tdictWord{136, 0, 267},\n\tdictWord{11, 0, 104},\n\tdictWord{11, 0, 554},\n\tdictWord{15, 0, 60},\n\tdictWord{143, 0, 125},\n\tdictWord{134, 0, 1613},\n\tdictWord{4, 10, 414},\n\tdictWord{5, 10, 467},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t654,\n\t},\n\tdictWord{10, 10, 451},\n\tdictWord{12, 10, 59},\n\tdictWord{141, 10, 375},\n\tdictWord{135, 10, 17},\n\tdictWord{134, 0, 116},\n\tdictWord{135, 11, 541},\n\tdictWord{135, 10, 955},\n\tdictWord{6, 11, 73},\n\tdictWord{135, 11, 177},\n\tdictWord{133, 11, 576},\n\tdictWord{134, 0, 886},\n\tdictWord{133, 0, 487},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t86,\n\t},\n\tdictWord{5, 0, 667},\n\tdictWord{5, 0, 753},\n\tdictWord{6, 0, 316},\n\tdictWord{6, 0, 455},\n\tdictWord{135, 0, 946},\n\tdictWord{142, 11, 231},\n\tdictWord{150, 0, 45},\n\tdictWord{134, 0, 863},\n\tdictWord{134, 0, 1953},\n\tdictWord{6, 10, 280},\n\tdictWord{10, 10, 502},\n\tdictWord{11, 10, 344},\n\tdictWord{140, 10, 38},\n\tdictWord{4, 0, 79},\n\tdictWord{7, 0, 1773},\n\tdictWord{10, 0, 450},\n\tdictWord{11, 0, 589},\n\tdictWord{13, 0, 332},\n\tdictWord{13, 0, 493},\n\tdictWord{14, 0, 183},\n\tdictWord{14, 0, 334},\n\tdictWord{14, 0, 362},\n\tdictWord{14, 0, 368},\n\tdictWord{14, 0, 376},\n\tdictWord{14, 0, 379},\n\tdictWord{19, 0, 90},\n\tdictWord{19, 0, 103},\n\tdictWord{19, 0, 127},\n\tdictWord{\n\t\t148,\n\t\t0,\n\t\t90,\n\t},\n\tdictWord{5, 10, 45},\n\tdictWord{7, 10, 1161},\n\tdictWord{11, 10, 448},\n\tdictWord{11, 10, 880},\n\tdictWord{13, 10, 139},\n\tdictWord{13, 10, 407},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t16,\n\t},\n\tdictWord{17, 10, 95},\n\tdictWord{18, 10, 66},\n\tdictWord{18, 10, 88},\n\tdictWord{18, 10, 123},\n\tdictWord{149, 10, 7},\n\tdictWord{136, 10, 777},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t410,\n\t},\n\tdictWord{135, 10, 521},\n\tdictWord{135, 10, 1778},\n\tdictWord{135, 11, 538},\n\tdictWord{142, 0, 381},\n\tdictWord{133, 11, 413},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1142,\n\t},\n\tdictWord{6, 0, 1189},\n\tdictWord{136, 11, 495},\n\tdictWord{5, 0, 663},\n\tdictWord{6, 0, 1962},\n\tdictWord{134, 0, 2003},\n\tdictWord{7, 11, 54},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t312,\n\t},\n\tdictWord{10, 11, 191},\n\tdictWord{10, 11, 614},\n\tdictWord{140, 11, 567},\n\tdictWord{132, 10, 436},\n\tdictWord{133, 0, 846},\n\tdictWord{10, 0, 528},\n\tdictWord{11, 0, 504},\n\tdictWord{7, 10, 1587},\n\tdictWord{135, 10, 1707},\n\tdictWord{5, 0, 378},\n\tdictWord{8, 0, 465},\n\tdictWord{9, 0, 286},\n\tdictWord{10, 0, 185},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t562,\n\t},\n\tdictWord{10, 0, 635},\n\tdictWord{11, 0, 31},\n\tdictWord{11, 0, 393},\n\tdictWord{13, 0, 312},\n\tdictWord{18, 0, 65},\n\tdictWord{18, 0, 96},\n\tdictWord{147, 0, 89},\n\tdictWord{7, 0, 899},\n\tdictWord{14, 0, 325},\n\tdictWord{6, 11, 468},\n\tdictWord{7, 11, 567},\n\tdictWord{7, 11, 1478},\n\tdictWord{8, 11, 530},\n\tdictWord{142, 11, 290},\n\tdictWord{7, 0, 1880},\n\tdictWord{9, 0, 680},\n\tdictWord{139, 0, 798},\n\tdictWord{134, 0, 1770},\n\tdictWord{132, 0, 648},\n\tdictWord{150, 11, 35},\n\tdictWord{5, 0, 945},\n\tdictWord{6, 0, 1656},\n\tdictWord{6, 0, 1787},\n\tdictWord{7, 0, 167},\n\tdictWord{8, 0, 824},\n\tdictWord{9, 0, 391},\n\tdictWord{10, 0, 375},\n\tdictWord{139, 0, 185},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t484,\n\t},\n\tdictWord{135, 11, 822},\n\tdictWord{134, 0, 2046},\n\tdictWord{7, 0, 1645},\n\tdictWord{8, 0, 352},\n\tdictWord{137, 0, 249},\n\tdictWord{132, 0, 152},\n\tdictWord{6, 0, 611},\n\tdictWord{135, 0, 1733},\n\tdictWord{6, 11, 1724},\n\tdictWord{135, 11, 2022},\n\tdictWord{133, 0, 1006},\n\tdictWord{141, 11, 96},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t420,\n\t},\n\tdictWord{135, 0, 1449},\n\tdictWord{146, 11, 149},\n\tdictWord{135, 0, 832},\n\tdictWord{135, 10, 663},\n\tdictWord{133, 0, 351},\n\tdictWord{5, 0, 40},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t598,\n\t},\n\tdictWord{7, 0, 1638},\n\tdictWord{8, 0, 78},\n\tdictWord{9, 0, 166},\n\tdictWord{9, 0, 640},\n\tdictWord{9, 0, 685},\n\tdictWord{9, 0, 773},\n\tdictWord{11, 0, 215},\n\tdictWord{13, 0, 65},\n\tdictWord{14, 0, 172},\n\tdictWord{14, 0, 317},\n\tdictWord{145, 0, 6},\n\tdictWord{8, 0, 60},\n\tdictWord{9, 0, 343},\n\tdictWord{139, 0, 769},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1354,\n\t},\n\tdictWord{132, 0, 724},\n\tdictWord{137, 0, 745},\n\tdictWord{132, 11, 474},\n\tdictWord{7, 0, 1951},\n\tdictWord{8, 0, 765},\n\tdictWord{8, 0, 772},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t671,\n\t},\n\tdictWord{7, 0, 108},\n\tdictWord{8, 0, 219},\n\tdictWord{8, 0, 388},\n\tdictWord{9, 0, 775},\n\tdictWord{11, 0, 275},\n\tdictWord{140, 0, 464},\n\tdictWord{137, 0, 639},\n\tdictWord{135, 10, 503},\n\tdictWord{133, 11, 366},\n\tdictWord{5, 0, 15},\n\tdictWord{6, 0, 56},\n\tdictWord{7, 0, 1758},\n\tdictWord{8, 0, 500},\n\tdictWord{9, 0, 730},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t331,\n\t},\n\tdictWord{13, 0, 150},\n\tdictWord{14, 0, 282},\n\tdictWord{5, 11, 305},\n\tdictWord{9, 11, 560},\n\tdictWord{141, 11, 208},\n\tdictWord{4, 10, 113},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t163,\n\t},\n\tdictWord{5, 10, 735},\n\tdictWord{7, 10, 1009},\n\tdictWord{9, 10, 9},\n\tdictWord{9, 10, 771},\n\tdictWord{12, 10, 90},\n\tdictWord{13, 10, 138},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t410,\n\t},\n\tdictWord{143, 10, 128},\n\tdictWord{4, 10, 324},\n\tdictWord{138, 10, 104},\n\tdictWord{135, 11, 466},\n\tdictWord{142, 11, 27},\n\tdictWord{134, 0, 1886},\n\tdictWord{5, 0, 205},\n\tdictWord{6, 0, 438},\n\tdictWord{9, 0, 711},\n\tdictWord{4, 11, 480},\n\tdictWord{6, 11, 167},\n\tdictWord{6, 11, 302},\n\tdictWord{6, 11, 1642},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t130,\n\t},\n\tdictWord{7, 11, 656},\n\tdictWord{7, 11, 837},\n\tdictWord{7, 11, 1547},\n\tdictWord{7, 11, 1657},\n\tdictWord{8, 11, 429},\n\tdictWord{9, 11, 228},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t643,\n\t},\n\tdictWord{13, 11, 289},\n\tdictWord{13, 11, 343},\n\tdictWord{147, 11, 101},\n\tdictWord{134, 0, 865},\n\tdictWord{6, 0, 2025},\n\tdictWord{136, 0, 965},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t278,\n\t},\n\tdictWord{10, 11, 739},\n\tdictWord{11, 11, 708},\n\tdictWord{141, 11, 348},\n\tdictWord{133, 0, 534},\n\tdictWord{135, 11, 1922},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t691,\n\t},\n\tdictWord{4, 10, 935},\n\tdictWord{133, 10, 823},\n\tdictWord{6, 0, 443},\n\tdictWord{9, 0, 237},\n\tdictWord{9, 0, 571},\n\tdictWord{9, 0, 695},\n\tdictWord{10, 0, 139},\n\tdictWord{11, 0, 715},\n\tdictWord{12, 0, 417},\n\tdictWord{141, 0, 421},\n\tdictWord{5, 10, 269},\n\tdictWord{7, 10, 434},\n\tdictWord{7, 10, 891},\n\tdictWord{8, 10, 339},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t702,\n\t},\n\tdictWord{11, 10, 594},\n\tdictWord{11, 10, 718},\n\tdictWord{145, 10, 100},\n\tdictWord{6, 0, 1555},\n\tdictWord{7, 0, 878},\n\tdictWord{9, 10, 485},\n\tdictWord{141, 10, 264},\n\tdictWord{134, 10, 1713},\n\tdictWord{7, 10, 1810},\n\tdictWord{11, 10, 866},\n\tdictWord{12, 10, 103},\n\tdictWord{141, 10, 495},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t900,\n\t},\n\tdictWord{6, 0, 1410},\n\tdictWord{9, 11, 316},\n\tdictWord{139, 11, 256},\n\tdictWord{4, 0, 995},\n\tdictWord{135, 0, 1033},\n\tdictWord{132, 0, 578},\n\tdictWord{10, 0, 881},\n\tdictWord{12, 0, 740},\n\tdictWord{12, 0, 743},\n\tdictWord{140, 0, 759},\n\tdictWord{132, 0, 822},\n\tdictWord{133, 0, 923},\n\tdictWord{142, 10, 143},\n\tdictWord{135, 11, 1696},\n\tdictWord{6, 11, 363},\n\tdictWord{7, 11, 1955},\n\tdictWord{136, 11, 725},\n\tdictWord{132, 0, 924},\n\tdictWord{133, 0, 665},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t2029,\n\t},\n\tdictWord{135, 0, 1901},\n\tdictWord{4, 0, 265},\n\tdictWord{6, 0, 1092},\n\tdictWord{6, 0, 1417},\n\tdictWord{7, 0, 807},\n\tdictWord{135, 0, 950},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t93,\n\t},\n\tdictWord{12, 0, 267},\n\tdictWord{141, 0, 498},\n\tdictWord{135, 0, 1451},\n\tdictWord{5, 11, 813},\n\tdictWord{135, 11, 2046},\n\tdictWord{5, 10, 625},\n\tdictWord{135, 10, 1617},\n\tdictWord{135, 0, 747},\n\tdictWord{6, 0, 788},\n\tdictWord{137, 0, 828},\n\tdictWord{7, 0, 184},\n\tdictWord{11, 0, 307},\n\tdictWord{11, 0, 400},\n\tdictWord{15, 0, 130},\n\tdictWord{5, 11, 712},\n\tdictWord{7, 11, 1855},\n\tdictWord{8, 10, 425},\n\tdictWord{8, 10, 693},\n\tdictWord{9, 10, 720},\n\tdictWord{10, 10, 380},\n\tdictWord{10, 10, 638},\n\tdictWord{11, 11, 17},\n\tdictWord{11, 10, 473},\n\tdictWord{12, 10, 61},\n\tdictWord{13, 11, 321},\n\tdictWord{144, 11, 67},\n\tdictWord{135, 0, 198},\n\tdictWord{6, 11, 320},\n\tdictWord{7, 11, 781},\n\tdictWord{7, 11, 1921},\n\tdictWord{9, 11, 55},\n\tdictWord{10, 11, 186},\n\tdictWord{10, 11, 273},\n\tdictWord{10, 11, 664},\n\tdictWord{10, 11, 801},\n\tdictWord{11, 11, 996},\n\tdictWord{11, 11, 997},\n\tdictWord{13, 11, 157},\n\tdictWord{142, 11, 170},\n\tdictWord{136, 11, 271},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t994,\n\t},\n\tdictWord{7, 11, 103},\n\tdictWord{7, 11, 863},\n\tdictWord{11, 11, 184},\n\tdictWord{14, 11, 299},\n\tdictWord{145, 11, 62},\n\tdictWord{11, 10, 551},\n\tdictWord{142, 10, 159},\n\tdictWord{5, 0, 233},\n\tdictWord{5, 0, 320},\n\tdictWord{6, 0, 140},\n\tdictWord{8, 0, 295},\n\tdictWord{8, 0, 615},\n\tdictWord{136, 11, 615},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t978,\n\t},\n\tdictWord{4, 0, 905},\n\tdictWord{6, 0, 1701},\n\tdictWord{137, 0, 843},\n\tdictWord{132, 10, 168},\n\tdictWord{4, 0, 974},\n\tdictWord{8, 0, 850},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t709,\n\t},\n\tdictWord{12, 0, 768},\n\tdictWord{140, 0, 786},\n\tdictWord{135, 10, 91},\n\tdictWord{152, 0, 6},\n\tdictWord{138, 10, 532},\n\tdictWord{135, 10, 1884},\n\tdictWord{132, 0, 509},\n\tdictWord{6, 0, 1307},\n\tdictWord{135, 0, 273},\n\tdictWord{5, 11, 77},\n\tdictWord{7, 11, 1455},\n\tdictWord{10, 11, 843},\n\tdictWord{19, 11, 73},\n\tdictWord{150, 11, 5},\n\tdictWord{132, 11, 458},\n\tdictWord{135, 11, 1420},\n\tdictWord{6, 11, 109},\n\tdictWord{138, 11, 382},\n\tdictWord{6, 0, 201},\n\tdictWord{6, 11, 330},\n\tdictWord{7, 10, 70},\n\tdictWord{7, 11, 1084},\n\tdictWord{10, 10, 240},\n\tdictWord{11, 11, 142},\n\tdictWord{147, 10, 93},\n\tdictWord{7, 0, 1041},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t328,\n\t},\n\tdictWord{133, 11, 354},\n\tdictWord{134, 0, 1040},\n\tdictWord{133, 0, 693},\n\tdictWord{134, 0, 774},\n\tdictWord{139, 0, 234},\n\tdictWord{132, 0, 336},\n\tdictWord{7, 0, 1399},\n\tdictWord{139, 10, 392},\n\tdictWord{20, 0, 22},\n\tdictWord{148, 11, 22},\n\tdictWord{5, 0, 802},\n\tdictWord{7, 0, 2021},\n\tdictWord{136, 0, 805},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t167,\n\t},\n\tdictWord{5, 0, 899},\n\tdictWord{6, 0, 410},\n\tdictWord{137, 0, 777},\n\tdictWord{137, 0, 789},\n\tdictWord{134, 0, 1705},\n\tdictWord{7, 10, 655},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1844,\n\t},\n\tdictWord{4, 10, 145},\n\tdictWord{6, 10, 176},\n\tdictWord{7, 10, 395},\n\tdictWord{137, 10, 562},\n\tdictWord{132, 10, 501},\n\tdictWord{135, 0, 10},\n\tdictWord{5, 0, 11},\n\tdictWord{6, 0, 117},\n\tdictWord{6, 0, 485},\n\tdictWord{7, 0, 1133},\n\tdictWord{9, 0, 582},\n\tdictWord{9, 0, 594},\n\tdictWord{10, 0, 82},\n\tdictWord{11, 0, 21},\n\tdictWord{11, 0, 818},\n\tdictWord{12, 0, 535},\n\tdictWord{13, 0, 86},\n\tdictWord{20, 0, 91},\n\tdictWord{23, 0, 13},\n\tdictWord{134, 10, 509},\n\tdictWord{4, 0, 264},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1067,\n\t},\n\tdictWord{8, 0, 204},\n\tdictWord{8, 0, 385},\n\tdictWord{139, 0, 953},\n\tdictWord{139, 11, 737},\n\tdictWord{138, 0, 56},\n\tdictWord{134, 0, 1917},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t470,\n\t},\n\tdictWord{10, 11, 657},\n\tdictWord{14, 11, 297},\n\tdictWord{142, 11, 361},\n\tdictWord{135, 11, 412},\n\tdictWord{7, 0, 1198},\n\tdictWord{7, 11, 1198},\n\tdictWord{8, 11, 556},\n\tdictWord{14, 11, 123},\n\tdictWord{14, 11, 192},\n\tdictWord{143, 11, 27},\n\tdictWord{7, 11, 1985},\n\tdictWord{14, 11, 146},\n\tdictWord{15, 11, 42},\n\tdictWord{16, 11, 23},\n\tdictWord{17, 11, 86},\n\tdictWord{146, 11, 17},\n\tdictWord{11, 0, 1015},\n\tdictWord{136, 11, 122},\n\tdictWord{4, 10, 114},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t492,\n\t},\n\tdictWord{13, 10, 462},\n\tdictWord{142, 10, 215},\n\tdictWord{4, 10, 77},\n\tdictWord{5, 10, 361},\n\tdictWord{6, 10, 139},\n\tdictWord{6, 10, 401},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t404,\n\t},\n\tdictWord{7, 10, 413},\n\tdictWord{7, 10, 715},\n\tdictWord{7, 10, 1716},\n\tdictWord{11, 10, 279},\n\tdictWord{12, 10, 179},\n\tdictWord{12, 10, 258},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t244,\n\t},\n\tdictWord{142, 10, 358},\n\tdictWord{134, 10, 1717},\n\tdictWord{7, 10, 1061},\n\tdictWord{8, 10, 82},\n\tdictWord{11, 10, 250},\n\tdictWord{12, 10, 420},\n\tdictWord{141, 10, 184},\n\tdictWord{133, 0, 715},\n\tdictWord{135, 10, 724},\n\tdictWord{9, 0, 919},\n\tdictWord{9, 0, 922},\n\tdictWord{9, 0, 927},\n\tdictWord{9, 0, 933},\n\tdictWord{9, 0, 962},\n\tdictWord{9, 0, 1000},\n\tdictWord{9, 0, 1002},\n\tdictWord{9, 0, 1021},\n\tdictWord{12, 0, 890},\n\tdictWord{12, 0, 907},\n\tdictWord{12, 0, 930},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t207,\n\t},\n\tdictWord{15, 0, 228},\n\tdictWord{15, 0, 238},\n\tdictWord{149, 0, 61},\n\tdictWord{8, 0, 794},\n\tdictWord{9, 0, 400},\n\tdictWord{10, 0, 298},\n\tdictWord{142, 0, 228},\n\tdictWord{5, 11, 430},\n\tdictWord{5, 11, 932},\n\tdictWord{6, 11, 131},\n\tdictWord{7, 11, 417},\n\tdictWord{9, 11, 522},\n\tdictWord{11, 11, 314},\n\tdictWord{141, 11, 390},\n\tdictWord{132, 0, 867},\n\tdictWord{8, 0, 724},\n\tdictWord{132, 11, 507},\n\tdictWord{137, 11, 261},\n\tdictWord{4, 11, 343},\n\tdictWord{133, 11, 511},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t190,\n\t},\n\tdictWord{7, 0, 768},\n\tdictWord{135, 0, 1170},\n\tdictWord{6, 10, 513},\n\tdictWord{135, 10, 1052},\n\tdictWord{7, 11, 455},\n\tdictWord{138, 11, 591},\n\tdictWord{134, 0, 1066},\n\tdictWord{137, 10, 899},\n\tdictWord{14, 0, 67},\n\tdictWord{147, 0, 60},\n\tdictWord{4, 0, 948},\n\tdictWord{18, 0, 174},\n\tdictWord{146, 0, 176},\n\tdictWord{135, 0, 1023},\n\tdictWord{7, 10, 1417},\n\tdictWord{12, 10, 382},\n\tdictWord{17, 10, 48},\n\tdictWord{152, 10, 12},\n\tdictWord{134, 11, 575},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t764,\n\t},\n\tdictWord{6, 10, 545},\n\tdictWord{7, 10, 565},\n\tdictWord{7, 10, 1669},\n\tdictWord{10, 10, 114},\n\tdictWord{11, 10, 642},\n\tdictWord{140, 10, 618},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t137,\n\t},\n\tdictWord{9, 0, 75},\n\tdictWord{9, 0, 253},\n\tdictWord{10, 0, 194},\n\tdictWord{138, 0, 444},\n\tdictWord{4, 0, 756},\n\tdictWord{133, 10, 5},\n\tdictWord{8, 0, 1008},\n\tdictWord{135, 10, 192},\n\tdictWord{132, 0, 842},\n\tdictWord{11, 0, 643},\n\tdictWord{12, 0, 115},\n\tdictWord{136, 10, 763},\n\tdictWord{139, 0, 67},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t759,\n\t},\n\tdictWord{4, 0, 821},\n\tdictWord{5, 0, 760},\n\tdictWord{7, 0, 542},\n\tdictWord{8, 0, 135},\n\tdictWord{8, 0, 496},\n\tdictWord{135, 11, 580},\n\tdictWord{7, 10, 370},\n\tdictWord{7, 10, 1007},\n\tdictWord{7, 10, 1177},\n\tdictWord{135, 10, 1565},\n\tdictWord{135, 10, 1237},\n\tdictWord{140, 0, 736},\n\tdictWord{7, 0, 319},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t355,\n\t},\n\tdictWord{7, 0, 763},\n\tdictWord{10, 0, 389},\n\tdictWord{145, 0, 43},\n\tdictWord{8, 11, 333},\n\tdictWord{138, 11, 182},\n\tdictWord{4, 10, 87},\n\tdictWord{5, 10, 250},\n\tdictWord{141, 10, 298},\n\tdictWord{138, 0, 786},\n\tdictWord{134, 0, 2044},\n\tdictWord{8, 11, 330},\n\tdictWord{140, 11, 477},\n\tdictWord{135, 11, 1338},\n\tdictWord{132, 11, 125},\n\tdictWord{134, 0, 1030},\n\tdictWord{134, 0, 1083},\n\tdictWord{132, 11, 721},\n\tdictWord{135, 10, 814},\n\tdictWord{7, 11, 776},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t145,\n\t},\n\tdictWord{147, 11, 56},\n\tdictWord{134, 0, 1226},\n\tdictWord{4, 10, 57},\n\tdictWord{7, 10, 1195},\n\tdictWord{7, 10, 1438},\n\tdictWord{7, 10, 1548},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1835,\n\t},\n\tdictWord{7, 10, 1904},\n\tdictWord{9, 10, 757},\n\tdictWord{10, 10, 604},\n\tdictWord{139, 10, 519},\n\tdictWord{7, 11, 792},\n\tdictWord{8, 11, 147},\n\tdictWord{10, 11, 821},\n\tdictWord{139, 11, 1021},\n\tdictWord{137, 11, 797},\n\tdictWord{4, 0, 58},\n\tdictWord{5, 0, 286},\n\tdictWord{6, 0, 319},\n\tdictWord{7, 0, 402},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1254,\n\t},\n\tdictWord{7, 0, 1903},\n\tdictWord{8, 0, 356},\n\tdictWord{140, 0, 408},\n\tdictWord{4, 0, 389},\n\tdictWord{4, 0, 815},\n\tdictWord{9, 0, 181},\n\tdictWord{9, 0, 255},\n\tdictWord{10, 0, 8},\n\tdictWord{10, 0, 29},\n\tdictWord{10, 0, 816},\n\tdictWord{11, 0, 311},\n\tdictWord{11, 0, 561},\n\tdictWord{12, 0, 67},\n\tdictWord{141, 0, 181},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1472,\n\t},\n\tdictWord{135, 11, 1554},\n\tdictWord{7, 11, 1071},\n\tdictWord{7, 11, 1541},\n\tdictWord{7, 11, 1767},\n\tdictWord{7, 11, 1806},\n\tdictWord{7, 11, 1999},\n\tdictWord{9, 11, 248},\n\tdictWord{10, 11, 400},\n\tdictWord{11, 11, 162},\n\tdictWord{11, 11, 178},\n\tdictWord{11, 11, 242},\n\tdictWord{12, 11, 605},\n\tdictWord{\n\t\t15,\n\t\t11,\n\t\t26,\n\t},\n\tdictWord{144, 11, 44},\n\tdictWord{5, 11, 168},\n\tdictWord{5, 11, 930},\n\tdictWord{8, 11, 74},\n\tdictWord{9, 11, 623},\n\tdictWord{12, 11, 500},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t579,\n\t},\n\tdictWord{13, 11, 41},\n\tdictWord{143, 11, 93},\n\tdictWord{6, 11, 220},\n\tdictWord{7, 11, 1101},\n\tdictWord{141, 11, 105},\n\tdictWord{5, 0, 474},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t507,\n\t},\n\tdictWord{4, 10, 209},\n\tdictWord{7, 11, 507},\n\tdictWord{135, 10, 902},\n\tdictWord{132, 0, 427},\n\tdictWord{6, 0, 413},\n\tdictWord{7, 10, 335},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1437,\n\t},\n\tdictWord{7, 10, 1668},\n\tdictWord{8, 10, 553},\n\tdictWord{8, 10, 652},\n\tdictWord{8, 10, 656},\n\tdictWord{9, 10, 558},\n\tdictWord{11, 10, 743},\n\tdictWord{\n\t\t149,\n\t\t10,\n\t\t18,\n\t},\n\tdictWord{132, 0, 730},\n\tdictWord{6, 11, 19},\n\tdictWord{7, 11, 1413},\n\tdictWord{139, 11, 428},\n\tdictWord{133, 0, 373},\n\tdictWord{132, 10, 559},\n\tdictWord{7, 11, 96},\n\tdictWord{8, 11, 401},\n\tdictWord{137, 11, 896},\n\tdictWord{7, 0, 799},\n\tdictWord{7, 0, 1972},\n\tdictWord{5, 10, 1017},\n\tdictWord{138, 10, 511},\n\tdictWord{135, 0, 1793},\n\tdictWord{7, 11, 1961},\n\tdictWord{7, 11, 1965},\n\tdictWord{8, 11, 702},\n\tdictWord{136, 11, 750},\n\tdictWord{8, 11, 150},\n\tdictWord{8, 11, 737},\n\tdictWord{140, 11, 366},\n\tdictWord{132, 0, 322},\n\tdictWord{133, 10, 709},\n\tdictWord{8, 11, 800},\n\tdictWord{9, 11, 148},\n\tdictWord{9, 11, 872},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t890,\n\t},\n\tdictWord{11, 11, 309},\n\tdictWord{11, 11, 1001},\n\tdictWord{13, 11, 267},\n\tdictWord{141, 11, 323},\n\tdictWord{134, 10, 1745},\n\tdictWord{7, 0, 290},\n\tdictWord{136, 10, 206},\n\tdictWord{7, 0, 1651},\n\tdictWord{145, 0, 89},\n\tdictWord{139, 0, 2},\n\tdictWord{132, 0, 672},\n\tdictWord{6, 0, 1860},\n\tdictWord{8, 0, 905},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t844,\n\t},\n\tdictWord{10, 0, 846},\n\tdictWord{10, 0, 858},\n\tdictWord{12, 0, 699},\n\tdictWord{12, 0, 746},\n\tdictWord{140, 0, 772},\n\tdictWord{135, 11, 424},\n\tdictWord{133, 11, 547},\n\tdictWord{133, 0, 737},\n\tdictWord{5, 11, 490},\n\tdictWord{6, 11, 615},\n\tdictWord{6, 11, 620},\n\tdictWord{135, 11, 683},\n\tdictWord{6, 0, 746},\n\tdictWord{134, 0, 1612},\n\tdictWord{132, 10, 776},\n\tdictWord{9, 11, 385},\n\tdictWord{149, 11, 17},\n\tdictWord{133, 0, 145},\n\tdictWord{135, 10, 1272},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t884,\n\t},\n\tdictWord{140, 0, 124},\n\tdictWord{4, 0, 387},\n\tdictWord{135, 0, 1288},\n\tdictWord{5, 11, 133},\n\tdictWord{136, 10, 406},\n\tdictWord{136, 11, 187},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t679,\n\t},\n\tdictWord{8, 11, 8},\n\tdictWord{138, 11, 0},\n\tdictWord{135, 0, 550},\n\tdictWord{135, 11, 798},\n\tdictWord{136, 11, 685},\n\tdictWord{7, 11, 1086},\n\tdictWord{145, 11, 46},\n\tdictWord{8, 10, 175},\n\tdictWord{10, 10, 168},\n\tdictWord{138, 10, 573},\n\tdictWord{135, 0, 1305},\n\tdictWord{4, 0, 576},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1263,\n\t},\n\tdictWord{6, 0, 686},\n\tdictWord{134, 0, 1563},\n\tdictWord{134, 0, 607},\n\tdictWord{5, 0, 919},\n\tdictWord{134, 0, 1673},\n\tdictWord{148, 0, 37},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t774,\n\t},\n\tdictWord{10, 11, 670},\n\tdictWord{140, 11, 51},\n\tdictWord{133, 10, 784},\n\tdictWord{139, 10, 882},\n\tdictWord{4, 0, 82},\n\tdictWord{5, 0, 333},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t904,\n\t},\n\tdictWord{6, 0, 207},\n\tdictWord{7, 0, 325},\n\tdictWord{7, 0, 1726},\n\tdictWord{8, 0, 101},\n\tdictWord{10, 0, 778},\n\tdictWord{139, 0, 220},\n\tdictWord{135, 11, 371},\n\tdictWord{132, 0, 958},\n\tdictWord{133, 0, 903},\n\tdictWord{4, 11, 127},\n\tdictWord{5, 11, 350},\n\tdictWord{6, 11, 356},\n\tdictWord{8, 11, 426},\n\tdictWord{9, 11, 572},\n\tdictWord{10, 11, 247},\n\tdictWord{139, 11, 312},\n\tdictWord{140, 0, 147},\n\tdictWord{6, 11, 59},\n\tdictWord{7, 11, 885},\n\tdictWord{9, 11, 603},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t397,\n\t},\n\tdictWord{10, 0, 367},\n\tdictWord{9, 10, 14},\n\tdictWord{9, 10, 441},\n\tdictWord{139, 10, 9},\n\tdictWord{11, 10, 966},\n\tdictWord{12, 10, 287},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t342,\n\t},\n\tdictWord{13, 10, 402},\n\tdictWord{15, 10, 110},\n\tdictWord{143, 10, 163},\n\tdictWord{134, 0, 690},\n\tdictWord{132, 0, 705},\n\tdictWord{9, 0, 651},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t971,\n\t},\n\tdictWord{13, 0, 273},\n\tdictWord{7, 10, 1428},\n\tdictWord{7, 10, 1640},\n\tdictWord{7, 10, 1867},\n\tdictWord{9, 10, 169},\n\tdictWord{9, 10, 182},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t367,\n\t},\n\tdictWord{9, 10, 478},\n\tdictWord{9, 10, 506},\n\tdictWord{9, 10, 551},\n\tdictWord{9, 10, 557},\n\tdictWord{9, 10, 648},\n\tdictWord{9, 10, 697},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t705,\n\t},\n\tdictWord{9, 10, 725},\n\tdictWord{9, 10, 787},\n\tdictWord{9, 10, 794},\n\tdictWord{10, 10, 198},\n\tdictWord{10, 10, 214},\n\tdictWord{10, 10, 267},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t275,\n\t},\n\tdictWord{10, 10, 456},\n\tdictWord{10, 10, 551},\n\tdictWord{10, 10, 561},\n\tdictWord{10, 10, 613},\n\tdictWord{10, 10, 627},\n\tdictWord{10, 10, 668},\n\tdictWord{10, 10, 675},\n\tdictWord{10, 10, 691},\n\tdictWord{10, 10, 695},\n\tdictWord{10, 10, 707},\n\tdictWord{10, 10, 715},\n\tdictWord{11, 10, 183},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t201,\n\t},\n\tdictWord{11, 10, 262},\n\tdictWord{11, 10, 352},\n\tdictWord{11, 10, 439},\n\tdictWord{11, 10, 493},\n\tdictWord{11, 10, 572},\n\tdictWord{11, 10, 591},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t608,\n\t},\n\tdictWord{11, 10, 611},\n\tdictWord{11, 10, 646},\n\tdictWord{11, 10, 674},\n\tdictWord{11, 10, 711},\n\tdictWord{11, 10, 751},\n\tdictWord{11, 10, 761},\n\tdictWord{11, 10, 776},\n\tdictWord{11, 10, 785},\n\tdictWord{11, 10, 850},\n\tdictWord{11, 10, 853},\n\tdictWord{11, 10, 862},\n\tdictWord{11, 10, 865},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t868,\n\t},\n\tdictWord{11, 10, 875},\n\tdictWord{11, 10, 898},\n\tdictWord{11, 10, 902},\n\tdictWord{11, 10, 903},\n\tdictWord{11, 10, 910},\n\tdictWord{11, 10, 932},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t942,\n\t},\n\tdictWord{11, 10, 957},\n\tdictWord{11, 10, 967},\n\tdictWord{11, 10, 972},\n\tdictWord{12, 10, 148},\n\tdictWord{12, 10, 195},\n\tdictWord{12, 10, 220},\n\tdictWord{12, 10, 237},\n\tdictWord{12, 10, 318},\n\tdictWord{12, 10, 339},\n\tdictWord{12, 10, 393},\n\tdictWord{12, 10, 445},\n\tdictWord{12, 10, 450},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t474,\n\t},\n\tdictWord{12, 10, 505},\n\tdictWord{12, 10, 509},\n\tdictWord{12, 10, 533},\n\tdictWord{12, 10, 591},\n\tdictWord{12, 10, 594},\n\tdictWord{12, 10, 597},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t621,\n\t},\n\tdictWord{12, 10, 633},\n\tdictWord{12, 10, 642},\n\tdictWord{13, 10, 59},\n\tdictWord{13, 10, 60},\n\tdictWord{13, 10, 145},\n\tdictWord{13, 10, 239},\n\tdictWord{13, 10, 250},\n\tdictWord{13, 10, 329},\n\tdictWord{13, 10, 344},\n\tdictWord{13, 10, 365},\n\tdictWord{13, 10, 372},\n\tdictWord{13, 10, 387},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t403,\n\t},\n\tdictWord{13, 10, 414},\n\tdictWord{13, 10, 456},\n\tdictWord{13, 10, 470},\n\tdictWord{13, 10, 478},\n\tdictWord{13, 10, 483},\n\tdictWord{13, 10, 489},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t55,\n\t},\n\tdictWord{14, 10, 57},\n\tdictWord{14, 10, 81},\n\tdictWord{14, 10, 90},\n\tdictWord{14, 10, 148},\n\tdictWord{14, 10, 239},\n\tdictWord{14, 10, 266},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t321,\n\t},\n\tdictWord{14, 10, 326},\n\tdictWord{14, 10, 327},\n\tdictWord{14, 10, 330},\n\tdictWord{14, 10, 347},\n\tdictWord{14, 10, 355},\n\tdictWord{14, 10, 401},\n\tdictWord{14, 10, 404},\n\tdictWord{14, 10, 411},\n\tdictWord{14, 10, 414},\n\tdictWord{14, 10, 416},\n\tdictWord{14, 10, 420},\n\tdictWord{15, 10, 61},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t74,\n\t},\n\tdictWord{15, 10, 87},\n\tdictWord{15, 10, 88},\n\tdictWord{15, 10, 94},\n\tdictWord{15, 10, 96},\n\tdictWord{15, 10, 116},\n\tdictWord{15, 10, 149},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t154,\n\t},\n\tdictWord{16, 10, 50},\n\tdictWord{16, 10, 63},\n\tdictWord{16, 10, 73},\n\tdictWord{17, 10, 2},\n\tdictWord{17, 10, 66},\n\tdictWord{17, 10, 92},\n\tdictWord{17, 10, 103},\n\tdictWord{17, 10, 112},\n\tdictWord{17, 10, 120},\n\tdictWord{18, 10, 50},\n\tdictWord{18, 10, 54},\n\tdictWord{18, 10, 82},\n\tdictWord{18, 10, 86},\n\tdictWord{18, 10, 90},\n\tdictWord{18, 10, 111},\n\tdictWord{18, 10, 115},\n\tdictWord{18, 10, 156},\n\tdictWord{19, 10, 40},\n\tdictWord{19, 10, 79},\n\tdictWord{20, 10, 78},\n\tdictWord{149, 10, 22},\n\tdictWord{7, 0, 887},\n\tdictWord{5, 10, 161},\n\tdictWord{135, 10, 839},\n\tdictWord{142, 11, 98},\n\tdictWord{134, 0, 90},\n\tdictWord{138, 11, 356},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t441,\n\t},\n\tdictWord{6, 11, 111},\n\tdictWord{7, 11, 4},\n\tdictWord{8, 11, 163},\n\tdictWord{8, 11, 776},\n\tdictWord{138, 11, 566},\n\tdictWord{134, 0, 908},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1261,\n\t},\n\tdictWord{7, 0, 813},\n\tdictWord{12, 0, 497},\n\tdictWord{141, 0, 56},\n\tdictWord{134, 0, 1235},\n\tdictWord{135, 0, 429},\n\tdictWord{135, 11, 1994},\n\tdictWord{138, 0, 904},\n\tdictWord{6, 0, 125},\n\tdictWord{7, 0, 1277},\n\tdictWord{137, 0, 772},\n\tdictWord{151, 0, 12},\n\tdictWord{4, 0, 841},\n\tdictWord{5, 0, 386},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t386,\n\t},\n\tdictWord{5, 11, 297},\n\tdictWord{135, 11, 1038},\n\tdictWord{6, 0, 860},\n\tdictWord{6, 0, 1069},\n\tdictWord{135, 11, 309},\n\tdictWord{136, 0, 946},\n\tdictWord{135, 10, 1814},\n\tdictWord{141, 11, 418},\n\tdictWord{136, 11, 363},\n\tdictWord{10, 0, 768},\n\tdictWord{139, 0, 787},\n\tdictWord{22, 11, 30},\n\tdictWord{\n\t\t150,\n\t\t11,\n\t\t33,\n\t},\n\tdictWord{6, 0, 160},\n\tdictWord{7, 0, 1106},\n\tdictWord{9, 0, 770},\n\tdictWord{11, 0, 112},\n\tdictWord{140, 0, 413},\n\tdictWord{11, 11, 216},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t340,\n\t},\n\tdictWord{136, 10, 139},\n\tdictWord{135, 11, 1390},\n\tdictWord{135, 11, 808},\n\tdictWord{132, 11, 280},\n\tdictWord{12, 0, 271},\n\tdictWord{17, 0, 109},\n\tdictWord{7, 10, 643},\n\tdictWord{136, 10, 236},\n\tdictWord{140, 11, 54},\n\tdictWord{4, 11, 421},\n\tdictWord{133, 11, 548},\n\tdictWord{11, 0, 719},\n\tdictWord{12, 0, 36},\n\tdictWord{141, 0, 337},\n\tdictWord{7, 0, 581},\n\tdictWord{9, 0, 644},\n\tdictWord{137, 0, 699},\n\tdictWord{11, 11, 511},\n\tdictWord{13, 11, 394},\n\tdictWord{14, 11, 298},\n\tdictWord{14, 11, 318},\n\tdictWord{146, 11, 103},\n\tdictWord{7, 0, 304},\n\tdictWord{9, 0, 646},\n\tdictWord{9, 0, 862},\n\tdictWord{11, 0, 696},\n\tdictWord{12, 0, 208},\n\tdictWord{15, 0, 79},\n\tdictWord{147, 0, 108},\n\tdictWord{4, 0, 631},\n\tdictWord{7, 0, 1126},\n\tdictWord{135, 0, 1536},\n\tdictWord{135, 11, 1527},\n\tdictWord{8, 0, 880},\n\tdictWord{10, 0, 869},\n\tdictWord{138, 0, 913},\n\tdictWord{7, 0, 1513},\n\tdictWord{5, 10, 54},\n\tdictWord{6, 11, 254},\n\tdictWord{9, 11, 109},\n\tdictWord{138, 11, 103},\n\tdictWord{135, 0, 981},\n\tdictWord{133, 11, 729},\n\tdictWord{132, 10, 744},\n\tdictWord{132, 0, 434},\n\tdictWord{134, 0, 550},\n\tdictWord{7, 0, 930},\n\tdictWord{10, 0, 476},\n\tdictWord{13, 0, 452},\n\tdictWord{19, 0, 104},\n\tdictWord{6, 11, 1630},\n\tdictWord{10, 10, 402},\n\tdictWord{146, 10, 55},\n\tdictWord{5, 0, 553},\n\tdictWord{138, 0, 824},\n\tdictWord{136, 0, 452},\n\tdictWord{8, 0, 151},\n\tdictWord{137, 10, 624},\n\tdictWord{132, 10, 572},\n\tdictWord{132, 0, 772},\n\tdictWord{133, 11, 671},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t292,\n\t},\n\tdictWord{138, 0, 135},\n\tdictWord{132, 11, 889},\n\tdictWord{140, 11, 207},\n\tdictWord{9, 0, 504},\n\tdictWord{6, 10, 43},\n\tdictWord{7, 10, 38},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t248,\n\t},\n\tdictWord{138, 10, 513},\n\tdictWord{6, 0, 1089},\n\tdictWord{135, 11, 1910},\n\tdictWord{4, 11, 627},\n\tdictWord{133, 11, 775},\n\tdictWord{135, 0, 783},\n\tdictWord{133, 10, 766},\n\tdictWord{133, 10, 363},\n\tdictWord{7, 0, 387},\n\tdictWord{135, 11, 387},\n\tdictWord{7, 0, 393},\n\tdictWord{10, 0, 603},\n\tdictWord{11, 0, 206},\n\tdictWord{7, 11, 202},\n\tdictWord{11, 11, 362},\n\tdictWord{11, 11, 948},\n\tdictWord{140, 11, 388},\n\tdictWord{6, 11, 507},\n\tdictWord{7, 11, 451},\n\tdictWord{8, 11, 389},\n\tdictWord{12, 11, 490},\n\tdictWord{13, 11, 16},\n\tdictWord{13, 11, 215},\n\tdictWord{13, 11, 351},\n\tdictWord{18, 11, 132},\n\tdictWord{147, 11, 125},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t912,\n\t},\n\tdictWord{9, 0, 232},\n\tdictWord{135, 11, 841},\n\tdictWord{6, 10, 258},\n\tdictWord{140, 10, 409},\n\tdictWord{5, 10, 249},\n\tdictWord{148, 10, 82},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t566,\n\t},\n\tdictWord{6, 0, 977},\n\tdictWord{135, 11, 1214},\n\tdictWord{7, 0, 1973},\n\tdictWord{136, 0, 716},\n\tdictWord{135, 0, 98},\n\tdictWord{133, 0, 733},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t912,\n\t},\n\tdictWord{134, 11, 1695},\n\tdictWord{5, 10, 393},\n\tdictWord{6, 10, 378},\n\tdictWord{7, 10, 1981},\n\tdictWord{9, 10, 32},\n\tdictWord{9, 10, 591},\n\tdictWord{10, 10, 685},\n\tdictWord{10, 10, 741},\n\tdictWord{142, 10, 382},\n\tdictWord{133, 10, 788},\n\tdictWord{10, 0, 19},\n\tdictWord{11, 0, 911},\n\tdictWord{7, 10, 1968},\n\tdictWord{141, 10, 509},\n\tdictWord{5, 0, 668},\n\tdictWord{5, 11, 236},\n\tdictWord{6, 11, 572},\n\tdictWord{8, 11, 492},\n\tdictWord{11, 11, 618},\n\tdictWord{144, 11, 56},\n\tdictWord{135, 11, 1789},\n\tdictWord{4, 0, 360},\n\tdictWord{5, 0, 635},\n\tdictWord{5, 0, 700},\n\tdictWord{5, 10, 58},\n\tdictWord{5, 10, 171},\n\tdictWord{5, 10, 683},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t291,\n\t},\n\tdictWord{6, 10, 566},\n\tdictWord{7, 10, 1650},\n\tdictWord{11, 10, 523},\n\tdictWord{12, 10, 273},\n\tdictWord{12, 10, 303},\n\tdictWord{15, 10, 39},\n\tdictWord{143, 10, 111},\n\tdictWord{133, 0, 901},\n\tdictWord{134, 10, 589},\n\tdictWord{5, 11, 190},\n\tdictWord{136, 11, 318},\n\tdictWord{140, 0, 656},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t726,\n\t},\n\tdictWord{152, 0, 9},\n\tdictWord{4, 10, 917},\n\tdictWord{133, 10, 1005},\n\tdictWord{135, 10, 1598},\n\tdictWord{134, 11, 491},\n\tdictWord{4, 10, 919},\n\tdictWord{133, 11, 434},\n\tdictWord{137, 0, 72},\n\tdictWord{6, 0, 1269},\n\tdictWord{6, 0, 1566},\n\tdictWord{134, 0, 1621},\n\tdictWord{9, 0, 463},\n\tdictWord{10, 0, 595},\n\tdictWord{4, 10, 255},\n\tdictWord{5, 10, 302},\n\tdictWord{6, 10, 132},\n\tdictWord{7, 10, 128},\n\tdictWord{7, 10, 283},\n\tdictWord{7, 10, 1299},\n\tdictWord{10, 10, 52},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t514,\n\t},\n\tdictWord{11, 10, 925},\n\tdictWord{13, 10, 92},\n\tdictWord{142, 10, 309},\n\tdictWord{135, 0, 1454},\n\tdictWord{134, 0, 1287},\n\tdictWord{11, 0, 600},\n\tdictWord{13, 0, 245},\n\tdictWord{137, 10, 173},\n\tdictWord{136, 0, 989},\n\tdictWord{7, 0, 164},\n\tdictWord{7, 0, 1571},\n\tdictWord{9, 0, 107},\n\tdictWord{140, 0, 225},\n\tdictWord{6, 0, 1061},\n\tdictWord{141, 10, 442},\n\tdictWord{4, 0, 27},\n\tdictWord{5, 0, 484},\n\tdictWord{5, 0, 510},\n\tdictWord{6, 0, 434},\n\tdictWord{7, 0, 1000},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1098,\n\t},\n\tdictWord{136, 0, 2},\n\tdictWord{7, 11, 85},\n\tdictWord{7, 11, 247},\n\tdictWord{8, 11, 585},\n\tdictWord{10, 11, 163},\n\tdictWord{138, 11, 316},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t103,\n\t},\n\tdictWord{142, 11, 0},\n\tdictWord{134, 0, 1127},\n\tdictWord{4, 0, 460},\n\tdictWord{134, 0, 852},\n\tdictWord{134, 10, 210},\n\tdictWord{4, 0, 932},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t891,\n\t},\n\tdictWord{6, 0, 588},\n\tdictWord{147, 11, 83},\n\tdictWord{8, 0, 625},\n\tdictWord{4, 10, 284},\n\tdictWord{134, 10, 223},\n\tdictWord{134, 0, 76},\n\tdictWord{8, 0, 92},\n\tdictWord{137, 0, 221},\n\tdictWord{4, 11, 124},\n\tdictWord{10, 11, 457},\n\tdictWord{11, 11, 121},\n\tdictWord{11, 11, 169},\n\tdictWord{11, 11, 422},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t870,\n\t},\n\tdictWord{12, 11, 214},\n\tdictWord{13, 11, 389},\n\tdictWord{14, 11, 187},\n\tdictWord{143, 11, 77},\n\tdictWord{9, 11, 618},\n\tdictWord{138, 11, 482},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t218,\n\t},\n\tdictWord{7, 10, 526},\n\tdictWord{143, 10, 137},\n\tdictWord{13, 0, 9},\n\tdictWord{14, 0, 104},\n\tdictWord{14, 0, 311},\n\tdictWord{4, 10, 270},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t192,\n\t},\n\tdictWord{6, 10, 332},\n\tdictWord{135, 10, 1322},\n\tdictWord{140, 10, 661},\n\tdictWord{135, 11, 1193},\n\tdictWord{6, 11, 107},\n\tdictWord{7, 11, 638},\n\tdictWord{7, 11, 1632},\n\tdictWord{137, 11, 396},\n\tdictWord{132, 0, 763},\n\tdictWord{4, 0, 622},\n\tdictWord{5, 11, 370},\n\tdictWord{134, 11, 1756},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t253,\n\t},\n\tdictWord{135, 0, 546},\n\tdictWord{9, 0, 73},\n\tdictWord{10, 0, 110},\n\tdictWord{14, 0, 185},\n\tdictWord{17, 0, 119},\n\tdictWord{133, 11, 204},\n\tdictWord{7, 0, 624},\n\tdictWord{7, 0, 916},\n\tdictWord{10, 0, 256},\n\tdictWord{139, 0, 87},\n\tdictWord{7, 10, 379},\n\tdictWord{8, 10, 481},\n\tdictWord{137, 10, 377},\n\tdictWord{5, 0, 212},\n\tdictWord{12, 0, 35},\n\tdictWord{13, 0, 382},\n\tdictWord{5, 11, 970},\n\tdictWord{134, 11, 1706},\n\tdictWord{9, 0, 746},\n\tdictWord{5, 10, 1003},\n\tdictWord{134, 10, 149},\n\tdictWord{10, 0, 150},\n\tdictWord{11, 0, 849},\n\tdictWord{13, 0, 330},\n\tdictWord{8, 10, 262},\n\tdictWord{9, 10, 627},\n\tdictWord{11, 10, 214},\n\tdictWord{11, 10, 404},\n\tdictWord{11, 10, 457},\n\tdictWord{11, 10, 780},\n\tdictWord{11, 10, 913},\n\tdictWord{13, 10, 401},\n\tdictWord{142, 10, 200},\n\tdictWord{134, 0, 1466},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t3,\n\t},\n\tdictWord{6, 0, 1299},\n\tdictWord{4, 11, 35},\n\tdictWord{5, 11, 121},\n\tdictWord{5, 11, 483},\n\tdictWord{5, 11, 685},\n\tdictWord{6, 11, 489},\n\tdictWord{7, 11, 1204},\n\tdictWord{136, 11, 394},\n\tdictWord{135, 10, 742},\n\tdictWord{4, 10, 142},\n\tdictWord{136, 10, 304},\n\tdictWord{4, 11, 921},\n\tdictWord{133, 11, 1007},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1518,\n\t},\n\tdictWord{6, 0, 1229},\n\tdictWord{135, 0, 1175},\n\tdictWord{133, 0, 816},\n\tdictWord{12, 0, 159},\n\tdictWord{4, 10, 471},\n\tdictWord{4, 11, 712},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t51,\n\t},\n\tdictWord{6, 10, 602},\n\tdictWord{7, 10, 925},\n\tdictWord{8, 10, 484},\n\tdictWord{138, 10, 195},\n\tdictWord{134, 11, 1629},\n\tdictWord{5, 0, 869},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t968,\n\t},\n\tdictWord{6, 0, 1626},\n\tdictWord{8, 0, 734},\n\tdictWord{136, 0, 784},\n\tdictWord{4, 0, 542},\n\tdictWord{6, 0, 1716},\n\tdictWord{6, 0, 1727},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1082,\n\t},\n\tdictWord{7, 0, 1545},\n\tdictWord{8, 0, 56},\n\tdictWord{8, 0, 118},\n\tdictWord{8, 0, 412},\n\tdictWord{8, 0, 564},\n\tdictWord{9, 0, 888},\n\tdictWord{9, 0, 908},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t50,\n\t},\n\tdictWord{10, 0, 423},\n\tdictWord{11, 0, 685},\n\tdictWord{11, 0, 697},\n\tdictWord{11, 0, 933},\n\tdictWord{12, 0, 299},\n\tdictWord{13, 0, 126},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t136,\n\t},\n\tdictWord{13, 0, 170},\n\tdictWord{13, 0, 190},\n\tdictWord{136, 10, 688},\n\tdictWord{132, 10, 697},\n\tdictWord{4, 0, 232},\n\tdictWord{9, 0, 202},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t474,\n\t},\n\tdictWord{140, 0, 433},\n\tdictWord{136, 0, 212},\n\tdictWord{6, 0, 108},\n\tdictWord{7, 0, 1003},\n\tdictWord{7, 0, 1181},\n\tdictWord{8, 0, 111},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t343,\n\t},\n\tdictWord{5, 10, 221},\n\tdictWord{135, 11, 1255},\n\tdictWord{133, 11, 485},\n\tdictWord{134, 0, 1712},\n\tdictWord{142, 0, 216},\n\tdictWord{5, 0, 643},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t516,\n\t},\n\tdictWord{4, 11, 285},\n\tdictWord{5, 11, 317},\n\tdictWord{6, 11, 301},\n\tdictWord{7, 11, 7},\n\tdictWord{8, 11, 153},\n\tdictWord{10, 11, 766},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t468,\n\t},\n\tdictWord{12, 11, 467},\n\tdictWord{141, 11, 143},\n\tdictWord{4, 0, 133},\n\tdictWord{7, 0, 711},\n\tdictWord{7, 0, 1298},\n\tdictWord{135, 0, 1585},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t650,\n\t},\n\tdictWord{135, 11, 512},\n\tdictWord{6, 0, 99},\n\tdictWord{7, 0, 1808},\n\tdictWord{145, 0, 57},\n\tdictWord{6, 0, 246},\n\tdictWord{6, 0, 574},\n\tdictWord{7, 0, 428},\n\tdictWord{9, 0, 793},\n\tdictWord{10, 0, 669},\n\tdictWord{11, 0, 485},\n\tdictWord{11, 0, 840},\n\tdictWord{12, 0, 300},\n\tdictWord{14, 0, 250},\n\tdictWord{145, 0, 55},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t132,\n\t},\n\tdictWord{5, 10, 69},\n\tdictWord{135, 10, 1242},\n\tdictWord{136, 0, 1023},\n\tdictWord{7, 0, 302},\n\tdictWord{132, 10, 111},\n\tdictWord{135, 0, 1871},\n\tdictWord{132, 0, 728},\n\tdictWord{9, 0, 252},\n\tdictWord{132, 10, 767},\n\tdictWord{6, 0, 461},\n\tdictWord{7, 0, 1590},\n\tdictWord{7, 10, 1416},\n\tdictWord{7, 10, 2005},\n\tdictWord{8, 10, 131},\n\tdictWord{8, 10, 466},\n\tdictWord{9, 10, 672},\n\tdictWord{13, 10, 252},\n\tdictWord{148, 10, 103},\n\tdictWord{6, 0, 323},\n\tdictWord{135, 0, 1564},\n\tdictWord{7, 0, 461},\n\tdictWord{136, 0, 775},\n\tdictWord{6, 10, 44},\n\tdictWord{136, 10, 368},\n\tdictWord{139, 0, 172},\n\tdictWord{132, 0, 464},\n\tdictWord{4, 10, 570},\n\tdictWord{133, 10, 120},\n\tdictWord{137, 11, 269},\n\tdictWord{6, 10, 227},\n\tdictWord{135, 10, 1589},\n\tdictWord{6, 11, 1719},\n\tdictWord{6, 11, 1735},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t2016,\n\t},\n\tdictWord{7, 11, 2020},\n\tdictWord{8, 11, 837},\n\tdictWord{137, 11, 852},\n\tdictWord{7, 0, 727},\n\tdictWord{146, 0, 73},\n\tdictWord{132, 0, 1023},\n\tdictWord{135, 11, 852},\n\tdictWord{135, 10, 1529},\n\tdictWord{136, 0, 577},\n\tdictWord{138, 11, 568},\n\tdictWord{134, 0, 1037},\n\tdictWord{8, 11, 67},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t419,\n\t},\n\tdictWord{4, 0, 413},\n\tdictWord{5, 0, 677},\n\tdictWord{8, 0, 432},\n\tdictWord{140, 0, 280},\n\tdictWord{10, 0, 600},\n\tdictWord{6, 10, 1667},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t967,\n\t},\n\tdictWord{7, 10, 2036},\n\tdictWord{141, 11, 11},\n\tdictWord{6, 10, 511},\n\tdictWord{140, 10, 132},\n\tdictWord{6, 0, 799},\n\tdictWord{5, 10, 568},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t138,\n\t},\n\tdictWord{135, 10, 1293},\n\tdictWord{8, 0, 159},\n\tdictWord{4, 10, 565},\n\tdictWord{136, 10, 827},\n\tdictWord{7, 0, 646},\n\tdictWord{7, 0, 1730},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t446,\n\t},\n\tdictWord{141, 0, 178},\n\tdictWord{4, 10, 922},\n\tdictWord{133, 10, 1023},\n\tdictWord{135, 11, 11},\n\tdictWord{132, 0, 395},\n\tdictWord{11, 0, 145},\n\tdictWord{135, 10, 1002},\n\tdictWord{9, 0, 174},\n\tdictWord{10, 0, 164},\n\tdictWord{11, 0, 440},\n\tdictWord{11, 0, 514},\n\tdictWord{11, 0, 841},\n\tdictWord{15, 0, 98},\n\tdictWord{149, 0, 20},\n\tdictWord{134, 0, 426},\n\tdictWord{10, 0, 608},\n\tdictWord{139, 0, 1002},\n\tdictWord{7, 11, 320},\n\tdictWord{8, 11, 51},\n\tdictWord{12, 11, 481},\n\tdictWord{12, 11, 570},\n\tdictWord{148, 11, 106},\n\tdictWord{9, 0, 977},\n\tdictWord{9, 0, 983},\n\tdictWord{132, 11, 445},\n\tdictWord{138, 0, 250},\n\tdictWord{139, 0, 100},\n\tdictWord{6, 0, 1982},\n\tdictWord{136, 10, 402},\n\tdictWord{133, 11, 239},\n\tdictWord{4, 10, 716},\n\tdictWord{141, 10, 31},\n\tdictWord{5, 0, 476},\n\tdictWord{7, 11, 83},\n\tdictWord{7, 11, 1990},\n\tdictWord{8, 11, 130},\n\tdictWord{139, 11, 720},\n\tdictWord{8, 10, 691},\n\tdictWord{136, 10, 731},\n\tdictWord{5, 11, 123},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t530,\n\t},\n\tdictWord{7, 11, 348},\n\tdictWord{135, 11, 1419},\n\tdictWord{5, 0, 76},\n\tdictWord{6, 0, 458},\n\tdictWord{6, 0, 497},\n\tdictWord{7, 0, 868},\n\tdictWord{9, 0, 658},\n\tdictWord{10, 0, 594},\n\tdictWord{11, 0, 173},\n\tdictWord{11, 0, 566},\n\tdictWord{12, 0, 20},\n\tdictWord{12, 0, 338},\n\tdictWord{141, 0, 200},\n\tdictWord{9, 11, 139},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t399,\n\t},\n\tdictWord{11, 11, 469},\n\tdictWord{12, 11, 634},\n\tdictWord{141, 11, 223},\n\tdictWord{9, 10, 840},\n\tdictWord{138, 10, 803},\n\tdictWord{133, 10, 847},\n\tdictWord{11, 11, 223},\n\tdictWord{140, 11, 168},\n\tdictWord{132, 11, 210},\n\tdictWord{8, 0, 447},\n\tdictWord{9, 10, 53},\n\tdictWord{9, 10, 268},\n\tdictWord{9, 10, 901},\n\tdictWord{10, 10, 518},\n\tdictWord{10, 10, 829},\n\tdictWord{11, 10, 188},\n\tdictWord{13, 10, 74},\n\tdictWord{14, 10, 46},\n\tdictWord{15, 10, 17},\n\tdictWord{15, 10, 33},\n\tdictWord{17, 10, 40},\n\tdictWord{18, 10, 36},\n\tdictWord{19, 10, 20},\n\tdictWord{22, 10, 1},\n\tdictWord{152, 10, 2},\n\tdictWord{4, 0, 526},\n\tdictWord{7, 0, 1029},\n\tdictWord{135, 0, 1054},\n\tdictWord{19, 11, 59},\n\tdictWord{150, 11, 2},\n\tdictWord{4, 0, 636},\n\tdictWord{6, 0, 1875},\n\tdictWord{6, 0, 1920},\n\tdictWord{9, 0, 999},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t807,\n\t},\n\tdictWord{12, 0, 825},\n\tdictWord{15, 0, 179},\n\tdictWord{15, 0, 190},\n\tdictWord{18, 0, 182},\n\tdictWord{136, 10, 532},\n\tdictWord{6, 0, 1699},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t660,\n\t},\n\tdictWord{7, 0, 1124},\n\tdictWord{17, 0, 31},\n\tdictWord{19, 0, 22},\n\tdictWord{151, 0, 14},\n\tdictWord{135, 10, 681},\n\tdictWord{132, 11, 430},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t677,\n\t},\n\tdictWord{4, 10, 684},\n\tdictWord{136, 10, 384},\n\tdictWord{132, 11, 756},\n\tdictWord{133, 11, 213},\n\tdictWord{7, 0, 188},\n\tdictWord{7, 10, 110},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t290,\n\t},\n\tdictWord{8, 10, 591},\n\tdictWord{9, 10, 382},\n\tdictWord{9, 10, 649},\n\tdictWord{11, 10, 71},\n\tdictWord{11, 10, 155},\n\tdictWord{11, 10, 313},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t5,\n\t},\n\tdictWord{13, 10, 325},\n\tdictWord{142, 10, 287},\n\tdictWord{7, 10, 360},\n\tdictWord{7, 10, 425},\n\tdictWord{9, 10, 66},\n\tdictWord{9, 10, 278},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t644,\n\t},\n\tdictWord{142, 11, 164},\n\tdictWord{4, 0, 279},\n\tdictWord{7, 0, 301},\n\tdictWord{137, 0, 362},\n\tdictWord{134, 11, 586},\n\tdictWord{135, 0, 1743},\n\tdictWord{4, 0, 178},\n\tdictWord{133, 0, 399},\n\tdictWord{4, 10, 900},\n\tdictWord{133, 10, 861},\n\tdictWord{5, 10, 254},\n\tdictWord{7, 10, 985},\n\tdictWord{136, 10, 73},\n\tdictWord{133, 11, 108},\n\tdictWord{7, 10, 1959},\n\tdictWord{136, 10, 683},\n\tdictWord{133, 11, 219},\n\tdictWord{4, 11, 193},\n\tdictWord{5, 11, 916},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t364,\n\t},\n\tdictWord{10, 11, 398},\n\tdictWord{10, 11, 726},\n\tdictWord{11, 11, 317},\n\tdictWord{11, 11, 626},\n\tdictWord{12, 11, 142},\n\tdictWord{12, 11, 288},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t678,\n\t},\n\tdictWord{13, 11, 313},\n\tdictWord{15, 11, 113},\n\tdictWord{18, 11, 114},\n\tdictWord{21, 11, 30},\n\tdictWord{150, 11, 53},\n\tdictWord{6, 11, 241},\n\tdictWord{7, 11, 907},\n\tdictWord{8, 11, 832},\n\tdictWord{9, 11, 342},\n\tdictWord{10, 11, 729},\n\tdictWord{11, 11, 284},\n\tdictWord{11, 11, 445},\n\tdictWord{11, 11, 651},\n\tdictWord{11, 11, 863},\n\tdictWord{13, 11, 398},\n\tdictWord{146, 11, 99},\n\tdictWord{132, 0, 872},\n\tdictWord{134, 0, 831},\n\tdictWord{134, 0, 1692},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t202,\n\t},\n\tdictWord{6, 0, 1006},\n\tdictWord{9, 0, 832},\n\tdictWord{10, 0, 636},\n\tdictWord{11, 0, 208},\n\tdictWord{12, 0, 360},\n\tdictWord{17, 0, 118},\n\tdictWord{18, 0, 27},\n\tdictWord{20, 0, 67},\n\tdictWord{137, 11, 734},\n\tdictWord{132, 10, 725},\n\tdictWord{7, 11, 993},\n\tdictWord{138, 11, 666},\n\tdictWord{134, 0, 1954},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t196,\n\t},\n\tdictWord{7, 0, 872},\n\tdictWord{10, 0, 516},\n\tdictWord{139, 0, 167},\n\tdictWord{133, 10, 831},\n\tdictWord{4, 11, 562},\n\tdictWord{9, 11, 254},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t879,\n\t},\n\tdictWord{137, 0, 313},\n\tdictWord{4, 0, 224},\n\tdictWord{132, 11, 786},\n\tdictWord{11, 0, 24},\n\tdictWord{12, 0, 170},\n\tdictWord{136, 10, 723},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t546,\n\t},\n\tdictWord{7, 0, 35},\n\tdictWord{8, 0, 11},\n\tdictWord{8, 0, 12},\n\tdictWord{9, 0, 315},\n\tdictWord{9, 0, 533},\n\tdictWord{10, 0, 802},\n\tdictWord{11, 0, 166},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t525,\n\t},\n\tdictWord{142, 0, 243},\n\tdictWord{7, 0, 1937},\n\tdictWord{13, 10, 80},\n\tdictWord{13, 10, 437},\n\tdictWord{145, 10, 74},\n\tdictWord{5, 0, 241},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t242,\n\t},\n\tdictWord{9, 0, 451},\n\tdictWord{10, 0, 667},\n\tdictWord{11, 0, 598},\n\tdictWord{140, 0, 429},\n\tdictWord{150, 0, 46},\n\tdictWord{6, 0, 1273},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t830,\n\t},\n\tdictWord{5, 10, 848},\n\tdictWord{6, 10, 66},\n\tdictWord{136, 10, 764},\n\tdictWord{6, 0, 825},\n\tdictWord{134, 0, 993},\n\tdictWord{4, 0, 1006},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t327,\n\t},\n\tdictWord{13, 0, 271},\n\tdictWord{4, 10, 36},\n\tdictWord{7, 10, 1387},\n\tdictWord{139, 10, 755},\n\tdictWord{134, 0, 1023},\n\tdictWord{135, 0, 1580},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t366,\n\t},\n\tdictWord{137, 0, 516},\n\tdictWord{132, 10, 887},\n\tdictWord{6, 0, 1736},\n\tdictWord{135, 0, 1891},\n\tdictWord{6, 11, 216},\n\tdictWord{7, 11, 901},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1343,\n\t},\n\tdictWord{136, 11, 493},\n\tdictWord{6, 10, 165},\n\tdictWord{138, 10, 388},\n\tdictWord{7, 11, 341},\n\tdictWord{139, 11, 219},\n\tdictWord{4, 10, 719},\n\tdictWord{135, 10, 155},\n\tdictWord{134, 0, 1935},\n\tdictWord{132, 0, 826},\n\tdictWord{6, 0, 331},\n\tdictWord{6, 0, 1605},\n\tdictWord{8, 0, 623},\n\tdictWord{11, 0, 139},\n\tdictWord{139, 0, 171},\n\tdictWord{135, 11, 1734},\n\tdictWord{10, 11, 115},\n\tdictWord{11, 11, 420},\n\tdictWord{12, 11, 154},\n\tdictWord{13, 11, 404},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t346,\n\t},\n\tdictWord{15, 11, 54},\n\tdictWord{143, 11, 112},\n\tdictWord{7, 0, 288},\n\tdictWord{4, 10, 353},\n\tdictWord{6, 10, 146},\n\tdictWord{6, 10, 1789},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t990,\n\t},\n\tdictWord{7, 10, 1348},\n\tdictWord{9, 10, 665},\n\tdictWord{9, 10, 898},\n\tdictWord{11, 10, 893},\n\tdictWord{142, 10, 212},\n\tdictWord{6, 0, 916},\n\tdictWord{134, 0, 1592},\n\tdictWord{7, 0, 1888},\n\tdictWord{4, 10, 45},\n\tdictWord{135, 10, 1257},\n\tdictWord{5, 11, 1011},\n\tdictWord{136, 11, 701},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t596,\n\t},\n\tdictWord{4, 11, 54},\n\tdictWord{5, 11, 666},\n\tdictWord{7, 11, 1039},\n\tdictWord{7, 11, 1130},\n\tdictWord{9, 11, 195},\n\tdictWord{138, 11, 302},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1471,\n\t},\n\tdictWord{134, 0, 1570},\n\tdictWord{132, 0, 394},\n\tdictWord{140, 10, 65},\n\tdictWord{136, 10, 816},\n\tdictWord{135, 0, 1931},\n\tdictWord{7, 0, 574},\n\tdictWord{135, 0, 1719},\n\tdictWord{134, 11, 467},\n\tdictWord{132, 0, 658},\n\tdictWord{9, 0, 781},\n\tdictWord{10, 0, 144},\n\tdictWord{11, 0, 385},\n\tdictWord{13, 0, 161},\n\tdictWord{13, 0, 228},\n\tdictWord{13, 0, 268},\n\tdictWord{20, 0, 107},\n\tdictWord{134, 11, 1669},\n\tdictWord{136, 0, 374},\n\tdictWord{135, 0, 735},\n\tdictWord{4, 0, 344},\n\tdictWord{6, 0, 498},\n\tdictWord{139, 0, 323},\n\tdictWord{7, 0, 586},\n\tdictWord{7, 0, 1063},\n\tdictWord{6, 10, 559},\n\tdictWord{134, 10, 1691},\n\tdictWord{137, 0, 155},\n\tdictWord{133, 0, 906},\n\tdictWord{7, 11, 122},\n\tdictWord{9, 11, 259},\n\tdictWord{10, 11, 84},\n\tdictWord{11, 11, 470},\n\tdictWord{12, 11, 541},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t379,\n\t},\n\tdictWord{134, 0, 1139},\n\tdictWord{10, 0, 108},\n\tdictWord{139, 0, 116},\n\tdictWord{134, 10, 456},\n\tdictWord{133, 10, 925},\n\tdictWord{5, 11, 82},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t131,\n\t},\n\tdictWord{7, 11, 1755},\n\tdictWord{8, 11, 31},\n\tdictWord{9, 11, 168},\n\tdictWord{9, 11, 764},\n\tdictWord{139, 11, 869},\n\tdictWord{134, 11, 605},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t278,\n\t},\n\tdictWord{137, 11, 68},\n\tdictWord{4, 11, 163},\n\tdictWord{5, 11, 201},\n\tdictWord{5, 11, 307},\n\tdictWord{5, 11, 310},\n\tdictWord{6, 11, 335},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t284,\n\t},\n\tdictWord{136, 11, 165},\n\tdictWord{135, 11, 1660},\n\tdictWord{6, 11, 33},\n\tdictWord{135, 11, 1244},\n\tdictWord{4, 0, 616},\n\tdictWord{136, 11, 483},\n\tdictWord{8, 0, 857},\n\tdictWord{8, 0, 902},\n\tdictWord{8, 0, 910},\n\tdictWord{10, 0, 879},\n\tdictWord{12, 0, 726},\n\tdictWord{4, 11, 199},\n\tdictWord{139, 11, 34},\n\tdictWord{136, 0, 692},\n\tdictWord{6, 10, 193},\n\tdictWord{7, 10, 240},\n\tdictWord{7, 10, 1682},\n\tdictWord{10, 10, 51},\n\tdictWord{10, 10, 640},\n\tdictWord{11, 10, 410},\n\tdictWord{13, 10, 82},\n\tdictWord{14, 10, 247},\n\tdictWord{14, 10, 331},\n\tdictWord{142, 10, 377},\n\tdictWord{6, 0, 823},\n\tdictWord{134, 0, 983},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t411,\n\t},\n\tdictWord{132, 0, 305},\n\tdictWord{136, 10, 633},\n\tdictWord{138, 11, 203},\n\tdictWord{134, 0, 681},\n\tdictWord{6, 11, 326},\n\tdictWord{7, 11, 677},\n\tdictWord{137, 11, 425},\n\tdictWord{5, 0, 214},\n\tdictWord{7, 0, 603},\n\tdictWord{8, 0, 611},\n\tdictWord{9, 0, 686},\n\tdictWord{10, 0, 88},\n\tdictWord{11, 0, 459},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t496,\n\t},\n\tdictWord{12, 0, 463},\n\tdictWord{12, 0, 590},\n\tdictWord{141, 0, 0},\n\tdictWord{136, 0, 1004},\n\tdictWord{142, 0, 23},\n\tdictWord{134, 0, 1703},\n\tdictWord{\n\t\t147,\n\t\t11,\n\t\t8,\n\t},\n\tdictWord{145, 11, 56},\n\tdictWord{135, 0, 1443},\n\tdictWord{4, 10, 237},\n\tdictWord{135, 10, 514},\n\tdictWord{6, 0, 714},\n\tdictWord{145, 0, 19},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t358,\n\t},\n\tdictWord{7, 11, 473},\n\tdictWord{7, 11, 1184},\n\tdictWord{10, 11, 662},\n\tdictWord{13, 11, 212},\n\tdictWord{13, 11, 304},\n\tdictWord{13, 11, 333},\n\tdictWord{145, 11, 98},\n\tdictWord{4, 0, 737},\n\tdictWord{10, 0, 98},\n\tdictWord{11, 0, 294},\n\tdictWord{12, 0, 60},\n\tdictWord{12, 0, 437},\n\tdictWord{13, 0, 64},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t380,\n\t},\n\tdictWord{142, 0, 430},\n\tdictWord{6, 10, 392},\n\tdictWord{7, 10, 65},\n\tdictWord{135, 10, 2019},\n\tdictWord{6, 0, 1758},\n\tdictWord{8, 0, 520},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t345,\n\t},\n\tdictWord{9, 0, 403},\n\tdictWord{142, 0, 350},\n\tdictWord{5, 0, 47},\n\tdictWord{10, 0, 242},\n\tdictWord{138, 0, 579},\n\tdictWord{5, 0, 139},\n\tdictWord{7, 0, 1168},\n\tdictWord{138, 0, 539},\n\tdictWord{134, 0, 1459},\n\tdictWord{13, 0, 388},\n\tdictWord{141, 11, 388},\n\tdictWord{134, 0, 253},\n\tdictWord{7, 10, 1260},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1790,\n\t},\n\tdictWord{10, 0, 252},\n\tdictWord{9, 10, 222},\n\tdictWord{139, 10, 900},\n\tdictWord{140, 0, 745},\n\tdictWord{133, 11, 946},\n\tdictWord{4, 0, 107},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t613,\n\t},\n\tdictWord{8, 0, 439},\n\tdictWord{8, 0, 504},\n\tdictWord{9, 0, 501},\n\tdictWord{10, 0, 383},\n\tdictWord{139, 0, 477},\n\tdictWord{135, 11, 1485},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t871,\n\t},\n\tdictWord{7, 11, 411},\n\tdictWord{7, 11, 590},\n\tdictWord{8, 11, 631},\n\tdictWord{9, 11, 323},\n\tdictWord{10, 11, 355},\n\tdictWord{11, 11, 491},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t143,\n\t},\n\tdictWord{12, 11, 402},\n\tdictWord{13, 11, 73},\n\tdictWord{14, 11, 408},\n\tdictWord{15, 11, 107},\n\tdictWord{146, 11, 71},\n\tdictWord{132, 0, 229},\n\tdictWord{132, 0, 903},\n\tdictWord{140, 0, 71},\n\tdictWord{133, 0, 549},\n\tdictWord{4, 0, 47},\n\tdictWord{6, 0, 373},\n\tdictWord{7, 0, 452},\n\tdictWord{7, 0, 543},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1828,\n\t},\n\tdictWord{7, 0, 1856},\n\tdictWord{9, 0, 6},\n\tdictWord{11, 0, 257},\n\tdictWord{139, 0, 391},\n\tdictWord{7, 11, 1467},\n\tdictWord{8, 11, 328},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t544,\n\t},\n\tdictWord{11, 11, 955},\n\tdictWord{13, 11, 320},\n\tdictWord{145, 11, 83},\n\tdictWord{5, 0, 980},\n\tdictWord{134, 0, 1754},\n\tdictWord{136, 0, 865},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t705,\n\t},\n\tdictWord{137, 0, 606},\n\tdictWord{7, 0, 161},\n\tdictWord{8, 10, 201},\n\tdictWord{136, 10, 605},\n\tdictWord{143, 11, 35},\n\tdictWord{5, 11, 835},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t483,\n\t},\n\tdictWord{140, 10, 224},\n\tdictWord{7, 0, 536},\n\tdictWord{7, 0, 1331},\n\tdictWord{136, 0, 143},\n\tdictWord{134, 0, 1388},\n\tdictWord{5, 0, 724},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t305,\n\t},\n\tdictWord{11, 0, 151},\n\tdictWord{12, 0, 33},\n\tdictWord{12, 0, 121},\n\tdictWord{12, 0, 381},\n\tdictWord{17, 0, 3},\n\tdictWord{17, 0, 27},\n\tdictWord{17, 0, 78},\n\tdictWord{18, 0, 18},\n\tdictWord{19, 0, 54},\n\tdictWord{149, 0, 5},\n\tdictWord{4, 10, 523},\n\tdictWord{133, 10, 638},\n\tdictWord{5, 0, 19},\n\tdictWord{134, 0, 533},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t395,\n\t},\n\tdictWord{5, 0, 951},\n\tdictWord{134, 0, 1776},\n\tdictWord{135, 0, 1908},\n\tdictWord{132, 0, 846},\n\tdictWord{10, 0, 74},\n\tdictWord{11, 0, 663},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t210,\n\t},\n\tdictWord{13, 0, 166},\n\tdictWord{13, 0, 310},\n\tdictWord{14, 0, 373},\n\tdictWord{18, 0, 95},\n\tdictWord{19, 0, 43},\n\tdictWord{6, 10, 242},\n\tdictWord{7, 10, 227},\n\tdictWord{7, 10, 1581},\n\tdictWord{8, 10, 104},\n\tdictWord{9, 10, 113},\n\tdictWord{9, 10, 220},\n\tdictWord{9, 10, 427},\n\tdictWord{10, 10, 239},\n\tdictWord{11, 10, 579},\n\tdictWord{11, 10, 1023},\n\tdictWord{13, 10, 4},\n\tdictWord{13, 10, 204},\n\tdictWord{13, 10, 316},\n\tdictWord{148, 10, 86},\n\tdictWord{9, 11, 716},\n\tdictWord{11, 11, 108},\n\tdictWord{13, 11, 123},\n\tdictWord{14, 11, 252},\n\tdictWord{19, 11, 38},\n\tdictWord{21, 11, 3},\n\tdictWord{151, 11, 11},\n\tdictWord{8, 0, 372},\n\tdictWord{9, 0, 122},\n\tdictWord{138, 0, 175},\n\tdictWord{132, 11, 677},\n\tdictWord{7, 11, 1374},\n\tdictWord{136, 11, 540},\n\tdictWord{135, 10, 861},\n\tdictWord{132, 0, 695},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t497,\n\t},\n\tdictWord{9, 0, 387},\n\tdictWord{147, 0, 81},\n\tdictWord{136, 0, 937},\n\tdictWord{134, 0, 718},\n\tdictWord{7, 0, 1328},\n\tdictWord{136, 10, 494},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t331,\n\t},\n\tdictWord{6, 0, 1581},\n\tdictWord{133, 11, 747},\n\tdictWord{5, 0, 284},\n\tdictWord{6, 0, 49},\n\tdictWord{6, 0, 350},\n\tdictWord{7, 0, 1},\n\tdictWord{7, 0, 377},\n\tdictWord{7, 0, 1693},\n\tdictWord{8, 0, 18},\n\tdictWord{8, 0, 678},\n\tdictWord{9, 0, 161},\n\tdictWord{9, 0, 585},\n\tdictWord{9, 0, 671},\n\tdictWord{9, 0, 839},\n\tdictWord{11, 0, 912},\n\tdictWord{141, 0, 427},\n\tdictWord{7, 10, 1306},\n\tdictWord{8, 10, 505},\n\tdictWord{9, 10, 482},\n\tdictWord{10, 10, 126},\n\tdictWord{11, 10, 225},\n\tdictWord{12, 10, 347},\n\tdictWord{12, 10, 449},\n\tdictWord{13, 10, 19},\n\tdictWord{14, 10, 218},\n\tdictWord{142, 10, 435},\n\tdictWord{10, 10, 764},\n\tdictWord{12, 10, 120},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t39,\n\t},\n\tdictWord{145, 10, 127},\n\tdictWord{4, 0, 597},\n\tdictWord{133, 10, 268},\n\tdictWord{134, 0, 1094},\n\tdictWord{4, 0, 1008},\n\tdictWord{134, 0, 1973},\n\tdictWord{132, 0, 811},\n\tdictWord{139, 0, 908},\n\tdictWord{135, 0, 1471},\n\tdictWord{133, 11, 326},\n\tdictWord{4, 10, 384},\n\tdictWord{135, 10, 1022},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1935,\n\t},\n\tdictWord{8, 0, 324},\n\tdictWord{12, 0, 42},\n\tdictWord{4, 11, 691},\n\tdictWord{7, 11, 1935},\n\tdictWord{8, 11, 324},\n\tdictWord{9, 11, 35},\n\tdictWord{10, 11, 680},\n\tdictWord{11, 11, 364},\n\tdictWord{12, 11, 42},\n\tdictWord{13, 11, 357},\n\tdictWord{146, 11, 16},\n\tdictWord{135, 0, 2014},\n\tdictWord{7, 0, 2007},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t101,\n\t},\n\tdictWord{9, 0, 450},\n\tdictWord{10, 0, 66},\n\tdictWord{10, 0, 842},\n\tdictWord{11, 0, 536},\n\tdictWord{12, 0, 587},\n\tdictWord{6, 11, 32},\n\tdictWord{7, 11, 385},\n\tdictWord{7, 11, 757},\n\tdictWord{7, 11, 1916},\n\tdictWord{8, 11, 37},\n\tdictWord{8, 11, 94},\n\tdictWord{8, 11, 711},\n\tdictWord{9, 11, 541},\n\tdictWord{10, 11, 162},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t795,\n\t},\n\tdictWord{11, 11, 989},\n\tdictWord{11, 11, 1010},\n\tdictWord{12, 11, 14},\n\tdictWord{142, 11, 308},\n\tdictWord{139, 0, 586},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1703,\n\t},\n\tdictWord{7, 0, 1077},\n\tdictWord{11, 0, 28},\n\tdictWord{9, 10, 159},\n\tdictWord{140, 10, 603},\n\tdictWord{6, 0, 1221},\n\tdictWord{136, 10, 583},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t152,\n\t},\n\tdictWord{6, 11, 349},\n\tdictWord{6, 11, 1682},\n\tdictWord{7, 11, 1252},\n\tdictWord{8, 11, 112},\n\tdictWord{9, 11, 435},\n\tdictWord{9, 11, 668},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t290,\n\t},\n\tdictWord{10, 11, 319},\n\tdictWord{10, 11, 815},\n\tdictWord{11, 11, 180},\n\tdictWord{11, 11, 837},\n\tdictWord{12, 11, 240},\n\tdictWord{13, 11, 152},\n\tdictWord{13, 11, 219},\n\tdictWord{142, 11, 158},\n\tdictWord{139, 0, 62},\n\tdictWord{132, 10, 515},\n\tdictWord{8, 10, 632},\n\tdictWord{8, 10, 697},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t854,\n\t},\n\tdictWord{134, 0, 1766},\n\tdictWord{132, 11, 581},\n\tdictWord{6, 11, 126},\n\tdictWord{7, 11, 573},\n\tdictWord{8, 11, 397},\n\tdictWord{142, 11, 44},\n\tdictWord{\n\t\t150,\n\t\t0,\n\t\t28,\n\t},\n\tdictWord{11, 0, 670},\n\tdictWord{22, 0, 25},\n\tdictWord{4, 10, 136},\n\tdictWord{133, 10, 551},\n\tdictWord{6, 0, 1665},\n\tdictWord{7, 0, 256},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1388,\n\t},\n\tdictWord{138, 0, 499},\n\tdictWord{4, 0, 22},\n\tdictWord{5, 0, 10},\n\tdictWord{7, 0, 1576},\n\tdictWord{136, 0, 97},\n\tdictWord{134, 10, 1782},\n\tdictWord{5, 0, 481},\n\tdictWord{7, 10, 1287},\n\tdictWord{9, 10, 44},\n\tdictWord{10, 10, 552},\n\tdictWord{10, 10, 642},\n\tdictWord{11, 10, 839},\n\tdictWord{12, 10, 274},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t275,\n\t},\n\tdictWord{12, 10, 372},\n\tdictWord{13, 10, 91},\n\tdictWord{142, 10, 125},\n\tdictWord{133, 11, 926},\n\tdictWord{7, 11, 1232},\n\tdictWord{137, 11, 531},\n\tdictWord{6, 0, 134},\n\tdictWord{7, 0, 437},\n\tdictWord{7, 0, 1824},\n\tdictWord{9, 0, 37},\n\tdictWord{14, 0, 285},\n\tdictWord{142, 0, 371},\n\tdictWord{7, 0, 486},\n\tdictWord{8, 0, 155},\n\tdictWord{11, 0, 93},\n\tdictWord{140, 0, 164},\n\tdictWord{6, 0, 1391},\n\tdictWord{134, 0, 1442},\n\tdictWord{133, 11, 670},\n\tdictWord{133, 0, 591},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t147,\n\t},\n\tdictWord{7, 10, 886},\n\tdictWord{7, 11, 1957},\n\tdictWord{9, 10, 753},\n\tdictWord{138, 10, 268},\n\tdictWord{5, 0, 380},\n\tdictWord{5, 0, 650},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1173,\n\t},\n\tdictWord{136, 0, 310},\n\tdictWord{4, 0, 364},\n\tdictWord{7, 0, 1156},\n\tdictWord{7, 0, 1187},\n\tdictWord{137, 0, 409},\n\tdictWord{135, 11, 1621},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t482,\n\t},\n\tdictWord{133, 11, 506},\n\tdictWord{4, 0, 781},\n\tdictWord{6, 0, 487},\n\tdictWord{7, 0, 926},\n\tdictWord{8, 0, 263},\n\tdictWord{139, 0, 500},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t137,\n\t},\n\tdictWord{135, 11, 242},\n\tdictWord{139, 11, 96},\n\tdictWord{133, 10, 414},\n\tdictWord{135, 10, 1762},\n\tdictWord{134, 0, 804},\n\tdictWord{5, 11, 834},\n\tdictWord{7, 11, 1202},\n\tdictWord{8, 11, 14},\n\tdictWord{9, 11, 481},\n\tdictWord{137, 11, 880},\n\tdictWord{134, 10, 599},\n\tdictWord{4, 0, 94},\n\tdictWord{135, 0, 1265},\n\tdictWord{4, 0, 415},\n\tdictWord{132, 0, 417},\n\tdictWord{5, 0, 348},\n\tdictWord{6, 0, 522},\n\tdictWord{6, 10, 1749},\n\tdictWord{7, 11, 1526},\n\tdictWord{138, 11, 465},\n\tdictWord{134, 10, 1627},\n\tdictWord{132, 0, 1012},\n\tdictWord{132, 10, 488},\n\tdictWord{4, 11, 357},\n\tdictWord{6, 11, 172},\n\tdictWord{7, 11, 143},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t413,\n\t},\n\tdictWord{4, 10, 83},\n\tdictWord{4, 11, 590},\n\tdictWord{146, 11, 76},\n\tdictWord{140, 10, 676},\n\tdictWord{7, 11, 287},\n\tdictWord{8, 11, 355},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t293,\n\t},\n\tdictWord{137, 11, 743},\n\tdictWord{134, 10, 278},\n\tdictWord{6, 0, 1803},\n\tdictWord{18, 0, 165},\n\tdictWord{24, 0, 21},\n\tdictWord{5, 11, 169},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t333,\n\t},\n\tdictWord{136, 11, 45},\n\tdictWord{12, 10, 97},\n\tdictWord{140, 11, 97},\n\tdictWord{4, 0, 408},\n\tdictWord{4, 0, 741},\n\tdictWord{135, 0, 500},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t198,\n\t},\n\tdictWord{7, 10, 388},\n\tdictWord{7, 10, 644},\n\tdictWord{139, 10, 781},\n\tdictWord{4, 11, 24},\n\tdictWord{5, 11, 140},\n\tdictWord{5, 11, 185},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1500,\n\t},\n\tdictWord{11, 11, 565},\n\tdictWord{139, 11, 838},\n\tdictWord{6, 0, 1321},\n\tdictWord{9, 0, 257},\n\tdictWord{7, 10, 229},\n\tdictWord{8, 10, 59},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t190,\n\t},\n\tdictWord{10, 10, 378},\n\tdictWord{140, 10, 191},\n\tdictWord{4, 11, 334},\n\tdictWord{133, 11, 593},\n\tdictWord{135, 11, 1885},\n\tdictWord{134, 0, 1138},\n\tdictWord{4, 0, 249},\n\tdictWord{6, 0, 73},\n\tdictWord{135, 0, 177},\n\tdictWord{133, 0, 576},\n\tdictWord{142, 0, 231},\n\tdictWord{137, 0, 288},\n\tdictWord{132, 10, 660},\n\tdictWord{7, 10, 1035},\n\tdictWord{138, 10, 737},\n\tdictWord{135, 0, 1487},\n\tdictWord{6, 0, 989},\n\tdictWord{9, 0, 433},\n\tdictWord{7, 10, 690},\n\tdictWord{9, 10, 587},\n\tdictWord{140, 10, 521},\n\tdictWord{7, 0, 1264},\n\tdictWord{7, 0, 1678},\n\tdictWord{11, 0, 945},\n\tdictWord{12, 0, 341},\n\tdictWord{12, 0, 471},\n\tdictWord{140, 0, 569},\n\tdictWord{132, 11, 709},\n\tdictWord{133, 11, 897},\n\tdictWord{5, 11, 224},\n\tdictWord{13, 11, 174},\n\tdictWord{146, 11, 52},\n\tdictWord{135, 11, 1840},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1744,\n\t},\n\tdictWord{12, 0, 87},\n\tdictWord{16, 0, 74},\n\tdictWord{4, 10, 733},\n\tdictWord{9, 10, 194},\n\tdictWord{10, 10, 92},\n\tdictWord{11, 10, 198},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t84,\n\t},\n\tdictWord{141, 10, 128},\n\tdictWord{140, 0, 779},\n\tdictWord{135, 0, 538},\n\tdictWord{4, 11, 608},\n\tdictWord{133, 11, 497},\n\tdictWord{133, 0, 413},\n\tdictWord{7, 11, 1375},\n\tdictWord{7, 11, 1466},\n\tdictWord{138, 11, 331},\n\tdictWord{136, 0, 495},\n\tdictWord{6, 11, 540},\n\tdictWord{136, 11, 136},\n\tdictWord{7, 0, 54},\n\tdictWord{8, 0, 312},\n\tdictWord{10, 0, 191},\n\tdictWord{10, 0, 614},\n\tdictWord{140, 0, 567},\n\tdictWord{6, 0, 468},\n\tdictWord{7, 0, 567},\n\tdictWord{7, 0, 1478},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t530,\n\t},\n\tdictWord{14, 0, 290},\n\tdictWord{133, 11, 999},\n\tdictWord{4, 11, 299},\n\tdictWord{7, 10, 306},\n\tdictWord{135, 11, 1004},\n\tdictWord{142, 11, 296},\n\tdictWord{134, 0, 1484},\n\tdictWord{133, 10, 979},\n\tdictWord{6, 0, 609},\n\tdictWord{9, 0, 815},\n\tdictWord{12, 11, 137},\n\tdictWord{14, 11, 9},\n\tdictWord{14, 11, 24},\n\tdictWord{142, 11, 64},\n\tdictWord{133, 11, 456},\n\tdictWord{6, 0, 484},\n\tdictWord{135, 0, 822},\n\tdictWord{133, 10, 178},\n\tdictWord{136, 11, 180},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t755,\n\t},\n\tdictWord{137, 0, 900},\n\tdictWord{135, 0, 1335},\n\tdictWord{6, 0, 1724},\n\tdictWord{135, 0, 2022},\n\tdictWord{135, 11, 1139},\n\tdictWord{5, 0, 640},\n\tdictWord{132, 10, 390},\n\tdictWord{6, 0, 1831},\n\tdictWord{138, 11, 633},\n\tdictWord{135, 11, 566},\n\tdictWord{4, 11, 890},\n\tdictWord{5, 11, 805},\n\tdictWord{5, 11, 819},\n\tdictWord{5, 11, 961},\n\tdictWord{6, 11, 396},\n\tdictWord{6, 11, 1631},\n\tdictWord{6, 11, 1678},\n\tdictWord{7, 11, 1967},\n\tdictWord{7, 11, 2041},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t630,\n\t},\n\tdictWord{11, 11, 8},\n\tdictWord{11, 11, 1019},\n\tdictWord{12, 11, 176},\n\tdictWord{13, 11, 225},\n\tdictWord{14, 11, 292},\n\tdictWord{149, 11, 24},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t474,\n\t},\n\tdictWord{134, 0, 1103},\n\tdictWord{135, 0, 1504},\n\tdictWord{134, 0, 1576},\n\tdictWord{6, 0, 961},\n\tdictWord{6, 0, 1034},\n\tdictWord{140, 0, 655},\n\tdictWord{11, 11, 514},\n\tdictWord{149, 11, 20},\n\tdictWord{5, 0, 305},\n\tdictWord{135, 11, 1815},\n\tdictWord{7, 11, 1505},\n\tdictWord{10, 11, 190},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t634,\n\t},\n\tdictWord{11, 11, 792},\n\tdictWord{12, 11, 358},\n\tdictWord{140, 11, 447},\n\tdictWord{5, 11, 0},\n\tdictWord{6, 11, 536},\n\tdictWord{7, 11, 604},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t445,\n\t},\n\tdictWord{145, 11, 126},\n\tdictWord{7, 0, 1236},\n\tdictWord{133, 10, 105},\n\tdictWord{4, 0, 480},\n\tdictWord{6, 0, 217},\n\tdictWord{6, 0, 302},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1642,\n\t},\n\tdictWord{7, 0, 130},\n\tdictWord{7, 0, 837},\n\tdictWord{7, 0, 1321},\n\tdictWord{7, 0, 1547},\n\tdictWord{7, 0, 1657},\n\tdictWord{8, 0, 429},\n\tdictWord{9, 0, 228},\n\tdictWord{13, 0, 289},\n\tdictWord{13, 0, 343},\n\tdictWord{19, 0, 101},\n\tdictWord{6, 11, 232},\n\tdictWord{6, 11, 412},\n\tdictWord{7, 11, 1074},\n\tdictWord{8, 11, 9},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t157,\n\t},\n\tdictWord{8, 11, 786},\n\tdictWord{9, 11, 196},\n\tdictWord{9, 11, 352},\n\tdictWord{9, 11, 457},\n\tdictWord{10, 11, 337},\n\tdictWord{11, 11, 232},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t877,\n\t},\n\tdictWord{12, 11, 480},\n\tdictWord{140, 11, 546},\n\tdictWord{5, 10, 438},\n\tdictWord{7, 11, 958},\n\tdictWord{9, 10, 694},\n\tdictWord{12, 10, 627},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t38,\n\t},\n\tdictWord{141, 10, 210},\n\tdictWord{4, 11, 382},\n\tdictWord{136, 11, 579},\n\tdictWord{7, 0, 278},\n\tdictWord{10, 0, 739},\n\tdictWord{11, 0, 708},\n\tdictWord{\n\t\t141,\n\t\t0,\n\t\t348,\n\t},\n\tdictWord{4, 11, 212},\n\tdictWord{135, 11, 1206},\n\tdictWord{135, 11, 1898},\n\tdictWord{6, 0, 708},\n\tdictWord{6, 0, 1344},\n\tdictWord{152, 10, 11},\n\tdictWord{137, 11, 768},\n\tdictWord{134, 0, 1840},\n\tdictWord{140, 0, 233},\n\tdictWord{8, 10, 25},\n\tdictWord{138, 10, 826},\n\tdictWord{6, 0, 2017},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t655,\n\t},\n\tdictWord{6, 0, 1488},\n\tdictWord{139, 11, 290},\n\tdictWord{132, 10, 308},\n\tdictWord{134, 0, 1590},\n\tdictWord{134, 0, 1800},\n\tdictWord{134, 0, 1259},\n\tdictWord{16, 0, 28},\n\tdictWord{6, 11, 231},\n\tdictWord{7, 11, 95},\n\tdictWord{136, 11, 423},\n\tdictWord{133, 11, 300},\n\tdictWord{135, 10, 150},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t649,\n\t},\n\tdictWord{7, 11, 1874},\n\tdictWord{137, 11, 641},\n\tdictWord{6, 11, 237},\n\tdictWord{7, 11, 611},\n\tdictWord{8, 11, 100},\n\tdictWord{9, 11, 416},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t335,\n\t},\n\tdictWord{12, 11, 173},\n\tdictWord{146, 11, 101},\n\tdictWord{137, 0, 45},\n\tdictWord{134, 10, 521},\n\tdictWord{17, 0, 36},\n\tdictWord{14, 11, 26},\n\tdictWord{\n\t\t146,\n\t\t11,\n\t\t150,\n\t},\n\tdictWord{7, 0, 1442},\n\tdictWord{14, 0, 22},\n\tdictWord{5, 10, 339},\n\tdictWord{15, 10, 41},\n\tdictWord{15, 10, 166},\n\tdictWord{147, 10, 66},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t378,\n\t},\n\tdictWord{6, 11, 581},\n\tdictWord{135, 11, 1119},\n\tdictWord{134, 0, 1507},\n\tdictWord{147, 11, 117},\n\tdictWord{139, 0, 39},\n\tdictWord{134, 0, 1054},\n\tdictWord{6, 0, 363},\n\tdictWord{7, 0, 1955},\n\tdictWord{136, 0, 725},\n\tdictWord{134, 0, 2036},\n\tdictWord{133, 11, 199},\n\tdictWord{6, 0, 1871},\n\tdictWord{9, 0, 935},\n\tdictWord{9, 0, 961},\n\tdictWord{9, 0, 1004},\n\tdictWord{9, 0, 1016},\n\tdictWord{12, 0, 805},\n\tdictWord{12, 0, 852},\n\tdictWord{12, 0, 853},\n\tdictWord{12, 0, 869},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t882,\n\t},\n\tdictWord{12, 0, 896},\n\tdictWord{12, 0, 906},\n\tdictWord{12, 0, 917},\n\tdictWord{12, 0, 940},\n\tdictWord{15, 0, 170},\n\tdictWord{15, 0, 176},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t188,\n\t},\n\tdictWord{15, 0, 201},\n\tdictWord{15, 0, 205},\n\tdictWord{15, 0, 212},\n\tdictWord{15, 0, 234},\n\tdictWord{15, 0, 244},\n\tdictWord{18, 0, 181},\n\tdictWord{18, 0, 193},\n\tdictWord{18, 0, 196},\n\tdictWord{18, 0, 201},\n\tdictWord{18, 0, 202},\n\tdictWord{18, 0, 210},\n\tdictWord{18, 0, 217},\n\tdictWord{18, 0, 235},\n\tdictWord{18, 0, 236},\n\tdictWord{18, 0, 237},\n\tdictWord{21, 0, 54},\n\tdictWord{21, 0, 55},\n\tdictWord{21, 0, 58},\n\tdictWord{21, 0, 59},\n\tdictWord{152, 0, 22},\n\tdictWord{134, 10, 1628},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t805,\n\t},\n\tdictWord{5, 0, 813},\n\tdictWord{135, 0, 2046},\n\tdictWord{142, 11, 42},\n\tdictWord{5, 0, 712},\n\tdictWord{6, 0, 1240},\n\tdictWord{11, 0, 17},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t321,\n\t},\n\tdictWord{144, 0, 67},\n\tdictWord{132, 0, 617},\n\tdictWord{135, 10, 829},\n\tdictWord{6, 0, 320},\n\tdictWord{7, 0, 781},\n\tdictWord{7, 0, 1921},\n\tdictWord{9, 0, 55},\n\tdictWord{10, 0, 186},\n\tdictWord{10, 0, 273},\n\tdictWord{10, 0, 664},\n\tdictWord{10, 0, 801},\n\tdictWord{11, 0, 996},\n\tdictWord{11, 0, 997},\n\tdictWord{13, 0, 157},\n\tdictWord{142, 0, 170},\n\tdictWord{136, 0, 271},\n\tdictWord{5, 10, 486},\n\tdictWord{135, 10, 1349},\n\tdictWord{18, 11, 91},\n\tdictWord{147, 11, 70},\n\tdictWord{10, 0, 445},\n\tdictWord{7, 10, 1635},\n\tdictWord{8, 10, 17},\n\tdictWord{138, 10, 295},\n\tdictWord{136, 11, 404},\n\tdictWord{7, 0, 103},\n\tdictWord{7, 0, 863},\n\tdictWord{11, 0, 184},\n\tdictWord{145, 0, 62},\n\tdictWord{138, 10, 558},\n\tdictWord{137, 0, 659},\n\tdictWord{6, 11, 312},\n\tdictWord{6, 11, 1715},\n\tdictWord{10, 11, 584},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t546,\n\t},\n\tdictWord{11, 11, 692},\n\tdictWord{12, 11, 259},\n\tdictWord{12, 11, 295},\n\tdictWord{13, 11, 46},\n\tdictWord{141, 11, 154},\n\tdictWord{134, 0, 676},\n\tdictWord{132, 11, 588},\n\tdictWord{4, 11, 231},\n\tdictWord{5, 11, 61},\n\tdictWord{6, 11, 104},\n\tdictWord{7, 11, 729},\n\tdictWord{7, 11, 964},\n\tdictWord{7, 11, 1658},\n\tdictWord{140, 11, 414},\n\tdictWord{6, 11, 263},\n\tdictWord{138, 11, 757},\n\tdictWord{11, 0, 337},\n\tdictWord{142, 0, 303},\n\tdictWord{135, 11, 1363},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t320,\n\t},\n\tdictWord{140, 0, 506},\n\tdictWord{134, 10, 447},\n\tdictWord{5, 0, 77},\n\tdictWord{7, 0, 1455},\n\tdictWord{10, 0, 843},\n\tdictWord{147, 0, 73},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t577,\n\t},\n\tdictWord{7, 10, 1432},\n\tdictWord{9, 10, 475},\n\tdictWord{9, 10, 505},\n\tdictWord{9, 10, 526},\n\tdictWord{9, 10, 609},\n\tdictWord{9, 10, 689},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t726,\n\t},\n\tdictWord{9, 10, 735},\n\tdictWord{9, 10, 738},\n\tdictWord{10, 10, 556},\n\tdictWord{10, 10, 674},\n\tdictWord{10, 10, 684},\n\tdictWord{11, 10, 89},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t202,\n\t},\n\tdictWord{11, 10, 272},\n\tdictWord{11, 10, 380},\n\tdictWord{11, 10, 415},\n\tdictWord{11, 10, 505},\n\tdictWord{11, 10, 537},\n\tdictWord{11, 10, 550},\n\tdictWord{11, 10, 562},\n\tdictWord{11, 10, 640},\n\tdictWord{11, 10, 667},\n\tdictWord{11, 10, 688},\n\tdictWord{11, 10, 847},\n\tdictWord{11, 10, 927},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t930,\n\t},\n\tdictWord{11, 10, 940},\n\tdictWord{12, 10, 144},\n\tdictWord{12, 10, 325},\n\tdictWord{12, 10, 329},\n\tdictWord{12, 10, 389},\n\tdictWord{12, 10, 403},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t451,\n\t},\n\tdictWord{12, 10, 515},\n\tdictWord{12, 10, 604},\n\tdictWord{12, 10, 616},\n\tdictWord{12, 10, 626},\n\tdictWord{13, 10, 66},\n\tdictWord{13, 10, 131},\n\tdictWord{13, 10, 167},\n\tdictWord{13, 10, 236},\n\tdictWord{13, 10, 368},\n\tdictWord{13, 10, 411},\n\tdictWord{13, 10, 434},\n\tdictWord{13, 10, 453},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t461,\n\t},\n\tdictWord{13, 10, 474},\n\tdictWord{14, 10, 59},\n\tdictWord{14, 10, 60},\n\tdictWord{14, 10, 139},\n\tdictWord{14, 10, 152},\n\tdictWord{14, 10, 276},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t353,\n\t},\n\tdictWord{14, 10, 402},\n\tdictWord{15, 10, 28},\n\tdictWord{15, 10, 81},\n\tdictWord{15, 10, 123},\n\tdictWord{15, 10, 152},\n\tdictWord{18, 10, 136},\n\tdictWord{148, 10, 88},\n\tdictWord{132, 0, 458},\n\tdictWord{135, 0, 1420},\n\tdictWord{6, 0, 109},\n\tdictWord{10, 0, 382},\n\tdictWord{4, 11, 405},\n\tdictWord{4, 10, 609},\n\tdictWord{7, 10, 756},\n\tdictWord{7, 11, 817},\n\tdictWord{9, 10, 544},\n\tdictWord{11, 10, 413},\n\tdictWord{14, 11, 58},\n\tdictWord{14, 10, 307},\n\tdictWord{16, 10, 25},\n\tdictWord{17, 11, 37},\n\tdictWord{146, 11, 124},\n\tdictWord{6, 0, 330},\n\tdictWord{7, 0, 1084},\n\tdictWord{11, 0, 142},\n\tdictWord{133, 11, 974},\n\tdictWord{4, 10, 930},\n\tdictWord{133, 10, 947},\n\tdictWord{5, 10, 939},\n\tdictWord{142, 11, 394},\n\tdictWord{16, 0, 91},\n\tdictWord{145, 0, 87},\n\tdictWord{5, 11, 235},\n\tdictWord{5, 10, 962},\n\tdictWord{7, 11, 1239},\n\tdictWord{11, 11, 131},\n\tdictWord{140, 11, 370},\n\tdictWord{11, 0, 492},\n\tdictWord{5, 10, 651},\n\tdictWord{8, 10, 170},\n\tdictWord{9, 10, 61},\n\tdictWord{9, 10, 63},\n\tdictWord{10, 10, 23},\n\tdictWord{10, 10, 37},\n\tdictWord{10, 10, 834},\n\tdictWord{11, 10, 4},\n\tdictWord{11, 10, 281},\n\tdictWord{11, 10, 503},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t677,\n\t},\n\tdictWord{12, 10, 96},\n\tdictWord{12, 10, 130},\n\tdictWord{12, 10, 244},\n\tdictWord{14, 10, 5},\n\tdictWord{14, 10, 40},\n\tdictWord{14, 10, 162},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t202,\n\t},\n\tdictWord{146, 10, 133},\n\tdictWord{4, 10, 406},\n\tdictWord{5, 10, 579},\n\tdictWord{12, 10, 492},\n\tdictWord{150, 10, 15},\n\tdictWord{9, 11, 137},\n\tdictWord{138, 11, 221},\n\tdictWord{134, 0, 1239},\n\tdictWord{11, 0, 211},\n\tdictWord{140, 0, 145},\n\tdictWord{7, 11, 390},\n\tdictWord{138, 11, 140},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1418,\n\t},\n\tdictWord{135, 11, 1144},\n\tdictWord{134, 0, 1049},\n\tdictWord{7, 0, 321},\n\tdictWord{6, 10, 17},\n\tdictWord{7, 10, 1001},\n\tdictWord{7, 10, 1982},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t886,\n\t},\n\tdictWord{10, 10, 489},\n\tdictWord{10, 10, 800},\n\tdictWord{11, 10, 782},\n\tdictWord{12, 10, 320},\n\tdictWord{13, 10, 467},\n\tdictWord{14, 10, 145},\n\tdictWord{14, 10, 387},\n\tdictWord{143, 10, 119},\n\tdictWord{145, 10, 17},\n\tdictWord{5, 11, 407},\n\tdictWord{11, 11, 489},\n\tdictWord{19, 11, 37},\n\tdictWord{20, 11, 73},\n\tdictWord{150, 11, 38},\n\tdictWord{133, 10, 458},\n\tdictWord{135, 0, 1985},\n\tdictWord{7, 10, 1983},\n\tdictWord{8, 10, 0},\n\tdictWord{8, 10, 171},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t120,\n\t},\n\tdictWord{9, 10, 732},\n\tdictWord{10, 10, 473},\n\tdictWord{11, 10, 656},\n\tdictWord{11, 10, 998},\n\tdictWord{18, 10, 0},\n\tdictWord{18, 10, 2},\n\tdictWord{\n\t\t147,\n\t\t10,\n\t\t21,\n\t},\n\tdictWord{5, 11, 325},\n\tdictWord{7, 11, 1483},\n\tdictWord{8, 11, 5},\n\tdictWord{8, 11, 227},\n\tdictWord{9, 11, 105},\n\tdictWord{10, 11, 585},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t614,\n\t},\n\tdictWord{136, 0, 122},\n\tdictWord{132, 0, 234},\n\tdictWord{135, 11, 1196},\n\tdictWord{6, 0, 976},\n\tdictWord{6, 0, 1098},\n\tdictWord{134, 0, 1441},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t253,\n\t},\n\tdictWord{136, 0, 549},\n\tdictWord{6, 11, 621},\n\tdictWord{13, 11, 504},\n\tdictWord{144, 11, 19},\n\tdictWord{132, 10, 519},\n\tdictWord{5, 0, 430},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t932,\n\t},\n\tdictWord{6, 0, 131},\n\tdictWord{7, 0, 417},\n\tdictWord{9, 0, 522},\n\tdictWord{11, 0, 314},\n\tdictWord{141, 0, 390},\n\tdictWord{14, 0, 149},\n\tdictWord{14, 0, 399},\n\tdictWord{143, 0, 57},\n\tdictWord{5, 10, 907},\n\tdictWord{6, 10, 31},\n\tdictWord{6, 11, 218},\n\tdictWord{7, 10, 491},\n\tdictWord{7, 10, 530},\n\tdictWord{8, 10, 592},\n\tdictWord{11, 10, 53},\n\tdictWord{11, 10, 779},\n\tdictWord{12, 10, 167},\n\tdictWord{12, 10, 411},\n\tdictWord{14, 10, 14},\n\tdictWord{14, 10, 136},\n\tdictWord{15, 10, 72},\n\tdictWord{16, 10, 17},\n\tdictWord{144, 10, 72},\n\tdictWord{140, 11, 330},\n\tdictWord{7, 11, 454},\n\tdictWord{7, 11, 782},\n\tdictWord{136, 11, 768},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t507,\n\t},\n\tdictWord{10, 11, 676},\n\tdictWord{140, 11, 462},\n\tdictWord{6, 0, 630},\n\tdictWord{9, 0, 811},\n\tdictWord{4, 10, 208},\n\tdictWord{5, 10, 106},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t531,\n\t},\n\tdictWord{8, 10, 408},\n\tdictWord{9, 10, 188},\n\tdictWord{138, 10, 572},\n\tdictWord{4, 0, 343},\n\tdictWord{5, 0, 511},\n\tdictWord{134, 10, 1693},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t164,\n\t},\n\tdictWord{132, 0, 448},\n\tdictWord{7, 0, 455},\n\tdictWord{138, 0, 591},\n\tdictWord{135, 0, 1381},\n\tdictWord{12, 10, 441},\n\tdictWord{150, 11, 50},\n\tdictWord{9, 10, 449},\n\tdictWord{10, 10, 192},\n\tdictWord{138, 10, 740},\n\tdictWord{6, 0, 575},\n\tdictWord{132, 10, 241},\n\tdictWord{134, 0, 1175},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t653,\n\t},\n\tdictWord{134, 0, 1761},\n\tdictWord{134, 0, 1198},\n\tdictWord{132, 10, 259},\n\tdictWord{6, 11, 343},\n\tdictWord{7, 11, 195},\n\tdictWord{9, 11, 226},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t197,\n\t},\n\tdictWord{10, 11, 575},\n\tdictWord{11, 11, 502},\n\tdictWord{139, 11, 899},\n\tdictWord{7, 0, 1127},\n\tdictWord{7, 0, 1572},\n\tdictWord{10, 0, 297},\n\tdictWord{10, 0, 422},\n\tdictWord{11, 0, 764},\n\tdictWord{11, 0, 810},\n\tdictWord{12, 0, 264},\n\tdictWord{13, 0, 102},\n\tdictWord{13, 0, 300},\n\tdictWord{13, 0, 484},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t147,\n\t},\n\tdictWord{14, 0, 229},\n\tdictWord{17, 0, 71},\n\tdictWord{18, 0, 118},\n\tdictWord{147, 0, 120},\n\tdictWord{135, 11, 666},\n\tdictWord{132, 0, 678},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t173,\n\t},\n\tdictWord{5, 10, 312},\n\tdictWord{5, 10, 512},\n\tdictWord{135, 10, 1285},\n\tdictWord{7, 10, 1603},\n\tdictWord{7, 10, 1691},\n\tdictWord{9, 10, 464},\n\tdictWord{11, 10, 195},\n\tdictWord{12, 10, 279},\n\tdictWord{12, 10, 448},\n\tdictWord{14, 10, 11},\n\tdictWord{147, 10, 102},\n\tdictWord{16, 0, 99},\n\tdictWord{146, 0, 164},\n\tdictWord{7, 11, 1125},\n\tdictWord{9, 11, 143},\n\tdictWord{11, 11, 61},\n\tdictWord{14, 11, 405},\n\tdictWord{150, 11, 21},\n\tdictWord{137, 11, 260},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t452,\n\t},\n\tdictWord{5, 10, 583},\n\tdictWord{5, 10, 817},\n\tdictWord{6, 10, 433},\n\tdictWord{7, 10, 593},\n\tdictWord{7, 10, 720},\n\tdictWord{7, 10, 1378},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t161,\n\t},\n\tdictWord{9, 10, 284},\n\tdictWord{10, 10, 313},\n\tdictWord{139, 10, 886},\n\tdictWord{132, 10, 547},\n\tdictWord{136, 10, 722},\n\tdictWord{14, 0, 35},\n\tdictWord{142, 0, 191},\n\tdictWord{141, 0, 45},\n\tdictWord{138, 0, 121},\n\tdictWord{132, 0, 125},\n\tdictWord{134, 0, 1622},\n\tdictWord{133, 11, 959},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t420,\n\t},\n\tdictWord{139, 10, 193},\n\tdictWord{132, 0, 721},\n\tdictWord{135, 10, 409},\n\tdictWord{136, 0, 145},\n\tdictWord{7, 0, 792},\n\tdictWord{8, 0, 147},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t821,\n\t},\n\tdictWord{11, 0, 970},\n\tdictWord{11, 0, 1021},\n\tdictWord{136, 11, 173},\n\tdictWord{134, 11, 266},\n\tdictWord{132, 0, 715},\n\tdictWord{7, 0, 1999},\n\tdictWord{138, 10, 308},\n\tdictWord{133, 0, 531},\n\tdictWord{5, 0, 168},\n\tdictWord{5, 0, 930},\n\tdictWord{8, 0, 74},\n\tdictWord{9, 0, 623},\n\tdictWord{12, 0, 500},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t579,\n\t},\n\tdictWord{144, 0, 65},\n\tdictWord{138, 11, 246},\n\tdictWord{6, 0, 220},\n\tdictWord{7, 0, 1101},\n\tdictWord{13, 0, 105},\n\tdictWord{142, 11, 314},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t1002,\n\t},\n\tdictWord{136, 10, 745},\n\tdictWord{134, 0, 960},\n\tdictWord{20, 0, 0},\n\tdictWord{148, 11, 0},\n\tdictWord{4, 0, 1005},\n\tdictWord{4, 10, 239},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t477,\n\t},\n\tdictWord{7, 10, 1607},\n\tdictWord{11, 10, 68},\n\tdictWord{139, 10, 617},\n\tdictWord{6, 0, 19},\n\tdictWord{7, 0, 1413},\n\tdictWord{139, 0, 428},\n\tdictWord{\n\t\t149,\n\t\t10,\n\t\t13,\n\t},\n\tdictWord{7, 0, 96},\n\tdictWord{8, 0, 401},\n\tdictWord{8, 0, 703},\n\tdictWord{9, 0, 896},\n\tdictWord{136, 11, 300},\n\tdictWord{134, 0, 1595},\n\tdictWord{145, 0, 116},\n\tdictWord{136, 0, 1021},\n\tdictWord{7, 0, 1961},\n\tdictWord{7, 0, 1965},\n\tdictWord{7, 0, 2030},\n\tdictWord{8, 0, 150},\n\tdictWord{8, 0, 702},\n\tdictWord{8, 0, 737},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t750,\n\t},\n\tdictWord{140, 0, 366},\n\tdictWord{11, 11, 75},\n\tdictWord{142, 11, 267},\n\tdictWord{132, 10, 367},\n\tdictWord{8, 0, 800},\n\tdictWord{9, 0, 148},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t872,\n\t},\n\tdictWord{9, 0, 890},\n\tdictWord{11, 0, 309},\n\tdictWord{11, 0, 1001},\n\tdictWord{13, 0, 267},\n\tdictWord{13, 0, 323},\n\tdictWord{5, 11, 427},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t734,\n\t},\n\tdictWord{7, 11, 478},\n\tdictWord{136, 11, 52},\n\tdictWord{7, 11, 239},\n\tdictWord{11, 11, 217},\n\tdictWord{142, 11, 165},\n\tdictWord{132, 11, 323},\n\tdictWord{140, 11, 419},\n\tdictWord{13, 0, 299},\n\tdictWord{142, 0, 75},\n\tdictWord{6, 11, 87},\n\tdictWord{6, 11, 1734},\n\tdictWord{7, 11, 20},\n\tdictWord{7, 11, 1056},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t732,\n\t},\n\tdictWord{9, 11, 406},\n\tdictWord{9, 11, 911},\n\tdictWord{138, 11, 694},\n\tdictWord{134, 0, 1383},\n\tdictWord{132, 10, 694},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t613,\n\t},\n\tdictWord{137, 0, 779},\n\tdictWord{4, 0, 598},\n\tdictWord{140, 10, 687},\n\tdictWord{6, 0, 970},\n\tdictWord{135, 0, 424},\n\tdictWord{133, 0, 547},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t32,\n\t},\n\tdictWord{7, 11, 984},\n\tdictWord{8, 11, 85},\n\tdictWord{8, 11, 709},\n\tdictWord{9, 11, 579},\n\tdictWord{9, 11, 847},\n\tdictWord{9, 11, 856},\n\tdictWord{10, 11, 799},\n\tdictWord{11, 11, 258},\n\tdictWord{11, 11, 1007},\n\tdictWord{12, 11, 331},\n\tdictWord{12, 11, 615},\n\tdictWord{13, 11, 188},\n\tdictWord{13, 11, 435},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t8,\n\t},\n\tdictWord{15, 11, 165},\n\tdictWord{16, 11, 27},\n\tdictWord{148, 11, 40},\n\tdictWord{6, 0, 1222},\n\tdictWord{134, 0, 1385},\n\tdictWord{132, 0, 876},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t151,\n\t},\n\tdictWord{135, 10, 213},\n\tdictWord{4, 11, 167},\n\tdictWord{135, 11, 82},\n\tdictWord{133, 0, 133},\n\tdictWord{6, 11, 24},\n\tdictWord{7, 11, 74},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t678,\n\t},\n\tdictWord{137, 11, 258},\n\tdictWord{5, 11, 62},\n\tdictWord{6, 11, 534},\n\tdictWord{7, 11, 684},\n\tdictWord{7, 11, 1043},\n\tdictWord{7, 11, 1072},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t280,\n\t},\n\tdictWord{8, 11, 541},\n\tdictWord{8, 11, 686},\n\tdictWord{10, 11, 519},\n\tdictWord{11, 11, 252},\n\tdictWord{140, 11, 282},\n\tdictWord{136, 0, 187},\n\tdictWord{8, 0, 8},\n\tdictWord{10, 0, 0},\n\tdictWord{10, 0, 818},\n\tdictWord{139, 0, 988},\n\tdictWord{132, 11, 359},\n\tdictWord{11, 0, 429},\n\tdictWord{15, 0, 51},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1672,\n\t},\n\tdictWord{136, 0, 685},\n\tdictWord{5, 11, 211},\n\tdictWord{7, 11, 88},\n\tdictWord{136, 11, 627},\n\tdictWord{134, 0, 472},\n\tdictWord{136, 0, 132},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t145,\n\t},\n\tdictWord{141, 11, 336},\n\tdictWord{4, 10, 751},\n\tdictWord{11, 10, 390},\n\tdictWord{140, 10, 32},\n\tdictWord{6, 0, 938},\n\tdictWord{6, 0, 1060},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t263,\n\t},\n\tdictWord{4, 10, 409},\n\tdictWord{133, 10, 78},\n\tdictWord{137, 0, 874},\n\tdictWord{8, 0, 774},\n\tdictWord{10, 0, 670},\n\tdictWord{12, 0, 51},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t916,\n\t},\n\tdictWord{6, 10, 473},\n\tdictWord{7, 10, 1602},\n\tdictWord{10, 10, 698},\n\tdictWord{12, 10, 212},\n\tdictWord{13, 10, 307},\n\tdictWord{145, 10, 105},\n\tdictWord{146, 0, 92},\n\tdictWord{143, 10, 156},\n\tdictWord{132, 0, 830},\n\tdictWord{137, 0, 701},\n\tdictWord{4, 11, 599},\n\tdictWord{6, 11, 1634},\n\tdictWord{7, 11, 5},\n\tdictWord{7, 11, 55},\n\tdictWord{7, 11, 67},\n\tdictWord{7, 11, 97},\n\tdictWord{7, 11, 691},\n\tdictWord{7, 11, 979},\n\tdictWord{7, 11, 1697},\n\tdictWord{8, 11, 207},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t214,\n\t},\n\tdictWord{8, 11, 231},\n\tdictWord{8, 11, 294},\n\tdictWord{8, 11, 336},\n\tdictWord{8, 11, 428},\n\tdictWord{8, 11, 451},\n\tdictWord{8, 11, 460},\n\tdictWord{8, 11, 471},\n\tdictWord{8, 11, 622},\n\tdictWord{8, 11, 626},\n\tdictWord{8, 11, 679},\n\tdictWord{8, 11, 759},\n\tdictWord{8, 11, 829},\n\tdictWord{9, 11, 11},\n\tdictWord{9, 11, 246},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t484,\n\t},\n\tdictWord{9, 11, 573},\n\tdictWord{9, 11, 706},\n\tdictWord{9, 11, 762},\n\tdictWord{9, 11, 798},\n\tdictWord{9, 11, 855},\n\tdictWord{9, 11, 870},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t912,\n\t},\n\tdictWord{10, 11, 303},\n\tdictWord{10, 11, 335},\n\tdictWord{10, 11, 424},\n\tdictWord{10, 11, 461},\n\tdictWord{10, 11, 543},\n\tdictWord{10, 11, 759},\n\tdictWord{10, 11, 814},\n\tdictWord{11, 11, 59},\n\tdictWord{11, 11, 199},\n\tdictWord{11, 11, 235},\n\tdictWord{11, 11, 475},\n\tdictWord{11, 11, 590},\n\tdictWord{11, 11, 929},\n\tdictWord{11, 11, 963},\n\tdictWord{12, 11, 114},\n\tdictWord{12, 11, 182},\n\tdictWord{12, 11, 226},\n\tdictWord{12, 11, 332},\n\tdictWord{12, 11, 439},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t575,\n\t},\n\tdictWord{12, 11, 598},\n\tdictWord{13, 11, 8},\n\tdictWord{13, 11, 125},\n\tdictWord{13, 11, 194},\n\tdictWord{13, 11, 287},\n\tdictWord{14, 11, 197},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t383,\n\t},\n\tdictWord{15, 11, 53},\n\tdictWord{17, 11, 63},\n\tdictWord{19, 11, 46},\n\tdictWord{19, 11, 98},\n\tdictWord{19, 11, 106},\n\tdictWord{148, 11, 85},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t127,\n\t},\n\tdictWord{5, 0, 350},\n\tdictWord{6, 0, 356},\n\tdictWord{8, 0, 426},\n\tdictWord{9, 0, 572},\n\tdictWord{10, 0, 247},\n\tdictWord{139, 0, 312},\n\tdictWord{134, 0, 1215},\n\tdictWord{6, 0, 59},\n\tdictWord{9, 0, 603},\n\tdictWord{13, 0, 397},\n\tdictWord{7, 11, 1853},\n\tdictWord{138, 11, 437},\n\tdictWord{134, 0, 1762},\n\tdictWord{\n\t\t147,\n\t\t11,\n\t\t126,\n\t},\n\tdictWord{135, 10, 883},\n\tdictWord{13, 0, 293},\n\tdictWord{142, 0, 56},\n\tdictWord{133, 10, 617},\n\tdictWord{139, 10, 50},\n\tdictWord{5, 11, 187},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1518,\n\t},\n\tdictWord{139, 10, 694},\n\tdictWord{135, 0, 441},\n\tdictWord{6, 0, 111},\n\tdictWord{7, 0, 4},\n\tdictWord{8, 0, 163},\n\tdictWord{8, 0, 776},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t566,\n\t},\n\tdictWord{132, 0, 806},\n\tdictWord{4, 11, 215},\n\tdictWord{9, 11, 38},\n\tdictWord{10, 11, 3},\n\tdictWord{11, 11, 23},\n\tdictWord{11, 11, 127},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t796,\n\t},\n\tdictWord{14, 0, 233},\n\tdictWord{4, 10, 546},\n\tdictWord{135, 10, 2042},\n\tdictWord{135, 0, 1994},\n\tdictWord{134, 0, 1739},\n\tdictWord{135, 11, 1530},\n\tdictWord{136, 0, 393},\n\tdictWord{5, 0, 297},\n\tdictWord{7, 0, 1038},\n\tdictWord{14, 0, 359},\n\tdictWord{19, 0, 52},\n\tdictWord{148, 0, 47},\n\tdictWord{135, 0, 309},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t313,\n\t},\n\tdictWord{133, 10, 577},\n\tdictWord{8, 10, 184},\n\tdictWord{141, 10, 433},\n\tdictWord{135, 10, 935},\n\tdictWord{12, 10, 186},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t292,\n\t},\n\tdictWord{14, 10, 100},\n\tdictWord{146, 10, 70},\n\tdictWord{136, 0, 363},\n\tdictWord{14, 0, 175},\n\tdictWord{11, 10, 402},\n\tdictWord{12, 10, 109},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t431,\n\t},\n\tdictWord{13, 10, 179},\n\tdictWord{13, 10, 206},\n\tdictWord{14, 10, 217},\n\tdictWord{16, 10, 3},\n\tdictWord{148, 10, 53},\n\tdictWord{5, 10, 886},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t46,\n\t},\n\tdictWord{6, 10, 1790},\n\tdictWord{7, 10, 14},\n\tdictWord{7, 10, 732},\n\tdictWord{7, 10, 1654},\n\tdictWord{8, 10, 95},\n\tdictWord{8, 10, 327},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t616,\n\t},\n\tdictWord{9, 10, 892},\n\tdictWord{10, 10, 598},\n\tdictWord{10, 10, 769},\n\tdictWord{11, 10, 134},\n\tdictWord{11, 10, 747},\n\tdictWord{12, 10, 378},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t97,\n\t},\n\tdictWord{136, 0, 666},\n\tdictWord{135, 0, 1675},\n\tdictWord{6, 0, 655},\n\tdictWord{134, 0, 1600},\n\tdictWord{135, 0, 808},\n\tdictWord{133, 10, 1021},\n\tdictWord{4, 11, 28},\n\tdictWord{5, 11, 440},\n\tdictWord{7, 11, 248},\n\tdictWord{11, 11, 833},\n\tdictWord{140, 11, 344},\n\tdictWord{134, 11, 1654},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t280,\n\t},\n\tdictWord{140, 0, 54},\n\tdictWord{4, 0, 421},\n\tdictWord{133, 0, 548},\n\tdictWord{132, 10, 153},\n\tdictWord{6, 11, 339},\n\tdictWord{135, 11, 923},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t853,\n\t},\n\tdictWord{133, 10, 798},\n\tdictWord{132, 10, 587},\n\tdictWord{6, 11, 249},\n\tdictWord{7, 11, 1234},\n\tdictWord{139, 11, 573},\n\tdictWord{6, 10, 598},\n\tdictWord{7, 10, 42},\n\tdictWord{8, 10, 695},\n\tdictWord{10, 10, 212},\n\tdictWord{11, 10, 158},\n\tdictWord{14, 10, 196},\n\tdictWord{145, 10, 85},\n\tdictWord{7, 0, 249},\n\tdictWord{5, 10, 957},\n\tdictWord{133, 10, 1008},\n\tdictWord{4, 10, 129},\n\tdictWord{135, 10, 465},\n\tdictWord{6, 0, 254},\n\tdictWord{7, 0, 842},\n\tdictWord{7, 0, 1659},\n\tdictWord{9, 0, 109},\n\tdictWord{10, 0, 103},\n\tdictWord{7, 10, 908},\n\tdictWord{7, 10, 1201},\n\tdictWord{9, 10, 755},\n\tdictWord{11, 10, 906},\n\tdictWord{12, 10, 527},\n\tdictWord{146, 10, 7},\n\tdictWord{5, 0, 262},\n\tdictWord{136, 10, 450},\n\tdictWord{144, 0, 1},\n\tdictWord{10, 11, 201},\n\tdictWord{142, 11, 319},\n\tdictWord{7, 11, 49},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t392,\n\t},\n\tdictWord{8, 11, 20},\n\tdictWord{8, 11, 172},\n\tdictWord{8, 11, 690},\n\tdictWord{9, 11, 383},\n\tdictWord{9, 11, 845},\n\tdictWord{10, 11, 48},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t293,\n\t},\n\tdictWord{11, 11, 832},\n\tdictWord{11, 11, 920},\n\tdictWord{141, 11, 221},\n\tdictWord{5, 11, 858},\n\tdictWord{133, 11, 992},\n\tdictWord{134, 0, 805},\n\tdictWord{139, 10, 1003},\n\tdictWord{6, 0, 1630},\n\tdictWord{134, 11, 307},\n\tdictWord{7, 11, 1512},\n\tdictWord{135, 11, 1794},\n\tdictWord{6, 11, 268},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t62,\n\t},\n\tdictWord{135, 10, 1868},\n\tdictWord{133, 0, 671},\n\tdictWord{4, 0, 989},\n\tdictWord{8, 0, 972},\n\tdictWord{136, 0, 998},\n\tdictWord{132, 11, 423},\n\tdictWord{132, 0, 889},\n\tdictWord{135, 0, 1382},\n\tdictWord{135, 0, 1910},\n\tdictWord{7, 10, 965},\n\tdictWord{7, 10, 1460},\n\tdictWord{135, 10, 1604},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t627,\n\t},\n\tdictWord{5, 0, 775},\n\tdictWord{138, 11, 106},\n\tdictWord{134, 11, 348},\n\tdictWord{7, 0, 202},\n\tdictWord{11, 0, 362},\n\tdictWord{11, 0, 948},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t388,\n\t},\n\tdictWord{138, 11, 771},\n\tdictWord{6, 11, 613},\n\tdictWord{136, 11, 223},\n\tdictWord{6, 0, 560},\n\tdictWord{7, 0, 451},\n\tdictWord{8, 0, 389},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t490,\n\t},\n\tdictWord{13, 0, 16},\n\tdictWord{13, 0, 215},\n\tdictWord{13, 0, 351},\n\tdictWord{18, 0, 132},\n\tdictWord{147, 0, 125},\n\tdictWord{135, 0, 841},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t566,\n\t},\n\tdictWord{136, 0, 938},\n\tdictWord{132, 11, 670},\n\tdictWord{5, 0, 912},\n\tdictWord{6, 0, 1695},\n\tdictWord{140, 11, 55},\n\tdictWord{9, 11, 40},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t136,\n\t},\n\tdictWord{7, 0, 1361},\n\tdictWord{7, 10, 982},\n\tdictWord{10, 10, 32},\n\tdictWord{143, 10, 56},\n\tdictWord{11, 11, 259},\n\tdictWord{140, 11, 270},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t236,\n\t},\n\tdictWord{6, 0, 572},\n\tdictWord{8, 0, 492},\n\tdictWord{11, 0, 618},\n\tdictWord{144, 0, 56},\n\tdictWord{8, 11, 572},\n\tdictWord{9, 11, 310},\n\tdictWord{9, 11, 682},\n\tdictWord{137, 11, 698},\n\tdictWord{134, 0, 1854},\n\tdictWord{5, 0, 190},\n\tdictWord{136, 0, 318},\n\tdictWord{133, 10, 435},\n\tdictWord{135, 0, 1376},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t296,\n\t},\n\tdictWord{6, 11, 352},\n\tdictWord{7, 11, 401},\n\tdictWord{7, 11, 1410},\n\tdictWord{7, 11, 1594},\n\tdictWord{7, 11, 1674},\n\tdictWord{8, 11, 63},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t660,\n\t},\n\tdictWord{137, 11, 74},\n\tdictWord{7, 0, 349},\n\tdictWord{5, 10, 85},\n\tdictWord{6, 10, 419},\n\tdictWord{7, 10, 305},\n\tdictWord{7, 10, 361},\n\tdictWord{7, 10, 1337},\n\tdictWord{8, 10, 71},\n\tdictWord{140, 10, 519},\n\tdictWord{4, 11, 139},\n\tdictWord{4, 11, 388},\n\tdictWord{140, 11, 188},\n\tdictWord{6, 0, 1972},\n\tdictWord{6, 0, 2013},\n\tdictWord{8, 0, 951},\n\tdictWord{10, 0, 947},\n\tdictWord{10, 0, 974},\n\tdictWord{10, 0, 1018},\n\tdictWord{142, 0, 476},\n\tdictWord{140, 10, 688},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t740,\n\t},\n\tdictWord{5, 10, 691},\n\tdictWord{7, 10, 345},\n\tdictWord{9, 10, 94},\n\tdictWord{140, 10, 169},\n\tdictWord{9, 0, 344},\n\tdictWord{5, 10, 183},\n\tdictWord{6, 10, 582},\n\tdictWord{10, 10, 679},\n\tdictWord{140, 10, 435},\n\tdictWord{135, 10, 511},\n\tdictWord{132, 0, 850},\n\tdictWord{8, 11, 441},\n\tdictWord{10, 11, 314},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t3,\n\t},\n\tdictWord{7, 10, 1993},\n\tdictWord{136, 10, 684},\n\tdictWord{4, 11, 747},\n\tdictWord{6, 11, 290},\n\tdictWord{6, 10, 583},\n\tdictWord{7, 11, 649},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1479,\n\t},\n\tdictWord{135, 11, 1583},\n\tdictWord{133, 11, 232},\n\tdictWord{133, 10, 704},\n\tdictWord{134, 0, 910},\n\tdictWord{4, 10, 179},\n\tdictWord{5, 10, 198},\n\tdictWord{133, 10, 697},\n\tdictWord{7, 10, 347},\n\tdictWord{7, 10, 971},\n\tdictWord{8, 10, 181},\n\tdictWord{138, 10, 711},\n\tdictWord{136, 11, 525},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t19,\n\t},\n\tdictWord{14, 0, 28},\n\tdictWord{144, 0, 29},\n\tdictWord{7, 0, 85},\n\tdictWord{7, 0, 247},\n\tdictWord{8, 0, 585},\n\tdictWord{138, 0, 163},\n\tdictWord{4, 0, 487},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t472,\n\t},\n\tdictWord{7, 11, 1801},\n\tdictWord{10, 11, 748},\n\tdictWord{141, 11, 458},\n\tdictWord{4, 10, 243},\n\tdictWord{5, 10, 203},\n\tdictWord{7, 10, 19},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t71,\n\t},\n\tdictWord{7, 10, 113},\n\tdictWord{10, 10, 405},\n\tdictWord{11, 10, 357},\n\tdictWord{142, 10, 240},\n\tdictWord{7, 10, 1450},\n\tdictWord{139, 10, 99},\n\tdictWord{132, 11, 425},\n\tdictWord{138, 0, 145},\n\tdictWord{147, 0, 83},\n\tdictWord{6, 10, 492},\n\tdictWord{137, 11, 247},\n\tdictWord{4, 0, 1013},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t2033,\n\t},\n\tdictWord{5, 10, 134},\n\tdictWord{6, 10, 408},\n\tdictWord{6, 10, 495},\n\tdictWord{135, 10, 1593},\n\tdictWord{135, 0, 1922},\n\tdictWord{134, 11, 1768},\n\tdictWord{4, 0, 124},\n\tdictWord{10, 0, 457},\n\tdictWord{11, 0, 121},\n\tdictWord{11, 0, 169},\n\tdictWord{11, 0, 870},\n\tdictWord{11, 0, 874},\n\tdictWord{12, 0, 214},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t187,\n\t},\n\tdictWord{143, 0, 77},\n\tdictWord{5, 0, 557},\n\tdictWord{135, 0, 1457},\n\tdictWord{139, 0, 66},\n\tdictWord{5, 11, 943},\n\tdictWord{6, 11, 1779},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t4,\n\t},\n\tdictWord{4, 10, 248},\n\tdictWord{4, 10, 665},\n\tdictWord{7, 10, 137},\n\tdictWord{137, 10, 349},\n\tdictWord{7, 0, 1193},\n\tdictWord{5, 11, 245},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t576,\n\t},\n\tdictWord{7, 11, 582},\n\tdictWord{136, 11, 225},\n\tdictWord{144, 0, 82},\n\tdictWord{7, 10, 1270},\n\tdictWord{139, 10, 612},\n\tdictWord{5, 0, 454},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t352,\n\t},\n\tdictWord{138, 11, 352},\n\tdictWord{18, 0, 57},\n\tdictWord{5, 10, 371},\n\tdictWord{135, 10, 563},\n\tdictWord{135, 0, 1333},\n\tdictWord{6, 0, 107},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t638,\n\t},\n\tdictWord{7, 0, 1632},\n\tdictWord{9, 0, 396},\n\tdictWord{134, 11, 610},\n\tdictWord{5, 0, 370},\n\tdictWord{134, 0, 1756},\n\tdictWord{4, 10, 374},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t547,\n\t},\n\tdictWord{7, 10, 1700},\n\tdictWord{7, 10, 1833},\n\tdictWord{139, 10, 858},\n\tdictWord{133, 0, 204},\n\tdictWord{6, 0, 1305},\n\tdictWord{9, 10, 311},\n\tdictWord{\n\t\t141,\n\t\t10,\n\t\t42,\n\t},\n\tdictWord{5, 0, 970},\n\tdictWord{134, 0, 1706},\n\tdictWord{6, 10, 1647},\n\tdictWord{7, 10, 1552},\n\tdictWord{7, 10, 2010},\n\tdictWord{9, 10, 494},\n\tdictWord{137, 10, 509},\n\tdictWord{13, 11, 455},\n\tdictWord{15, 11, 99},\n\tdictWord{15, 11, 129},\n\tdictWord{144, 11, 68},\n\tdictWord{135, 0, 3},\n\tdictWord{4, 0, 35},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t121,\n\t},\n\tdictWord{5, 0, 483},\n\tdictWord{5, 0, 685},\n\tdictWord{6, 0, 489},\n\tdictWord{6, 0, 782},\n\tdictWord{6, 0, 1032},\n\tdictWord{7, 0, 1204},\n\tdictWord{136, 0, 394},\n\tdictWord{4, 0, 921},\n\tdictWord{133, 0, 1007},\n\tdictWord{8, 11, 360},\n\tdictWord{138, 11, 63},\n\tdictWord{135, 0, 1696},\n\tdictWord{134, 0, 1519},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t443,\n\t},\n\tdictWord{135, 11, 944},\n\tdictWord{6, 10, 123},\n\tdictWord{7, 10, 214},\n\tdictWord{9, 10, 728},\n\tdictWord{10, 10, 157},\n\tdictWord{11, 10, 346},\n\tdictWord{11, 10, 662},\n\tdictWord{143, 10, 106},\n\tdictWord{137, 0, 981},\n\tdictWord{135, 10, 1435},\n\tdictWord{134, 0, 1072},\n\tdictWord{132, 0, 712},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1629,\n\t},\n\tdictWord{134, 0, 728},\n\tdictWord{4, 11, 298},\n\tdictWord{137, 11, 483},\n\tdictWord{6, 0, 1177},\n\tdictWord{6, 0, 1271},\n\tdictWord{5, 11, 164},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t121,\n\t},\n\tdictWord{142, 11, 189},\n\tdictWord{7, 0, 1608},\n\tdictWord{4, 10, 707},\n\tdictWord{5, 10, 588},\n\tdictWord{6, 10, 393},\n\tdictWord{13, 10, 106},\n\tdictWord{\n\t\t18,\n\t\t10,\n\t\t49,\n\t},\n\tdictWord{147, 10, 41},\n\tdictWord{23, 0, 16},\n\tdictWord{151, 11, 16},\n\tdictWord{6, 10, 211},\n\tdictWord{7, 10, 1690},\n\tdictWord{11, 10, 486},\n\tdictWord{140, 10, 369},\n\tdictWord{133, 0, 485},\n\tdictWord{19, 11, 15},\n\tdictWord{149, 11, 27},\n\tdictWord{4, 11, 172},\n\tdictWord{9, 11, 611},\n\tdictWord{10, 11, 436},\n\tdictWord{12, 11, 673},\n\tdictWord{141, 11, 255},\n\tdictWord{5, 11, 844},\n\tdictWord{10, 11, 484},\n\tdictWord{11, 11, 754},\n\tdictWord{12, 11, 457},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t171,\n\t},\n\tdictWord{14, 11, 389},\n\tdictWord{146, 11, 153},\n\tdictWord{4, 0, 285},\n\tdictWord{5, 0, 27},\n\tdictWord{5, 0, 317},\n\tdictWord{6, 0, 301},\n\tdictWord{7, 0, 7},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t153,\n\t},\n\tdictWord{10, 0, 766},\n\tdictWord{11, 0, 468},\n\tdictWord{12, 0, 467},\n\tdictWord{141, 0, 143},\n\tdictWord{134, 0, 1462},\n\tdictWord{9, 11, 263},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t147,\n\t},\n\tdictWord{138, 11, 492},\n\tdictWord{133, 11, 537},\n\tdictWord{6, 0, 1945},\n\tdictWord{6, 0, 1986},\n\tdictWord{6, 0, 1991},\n\tdictWord{134, 0, 2038},\n\tdictWord{134, 10, 219},\n\tdictWord{137, 11, 842},\n\tdictWord{14, 0, 52},\n\tdictWord{17, 0, 50},\n\tdictWord{5, 10, 582},\n\tdictWord{6, 10, 1646},\n\tdictWord{7, 10, 99},\n\tdictWord{7, 10, 1962},\n\tdictWord{7, 10, 1986},\n\tdictWord{8, 10, 515},\n\tdictWord{8, 10, 773},\n\tdictWord{9, 10, 23},\n\tdictWord{9, 10, 491},\n\tdictWord{12, 10, 620},\n\tdictWord{142, 10, 93},\n\tdictWord{138, 11, 97},\n\tdictWord{20, 0, 21},\n\tdictWord{20, 0, 44},\n\tdictWord{133, 10, 851},\n\tdictWord{136, 0, 819},\n\tdictWord{139, 0, 917},\n\tdictWord{5, 11, 230},\n\tdictWord{5, 11, 392},\n\tdictWord{6, 11, 420},\n\tdictWord{8, 10, 762},\n\tdictWord{8, 10, 812},\n\tdictWord{9, 11, 568},\n\tdictWord{9, 10, 910},\n\tdictWord{140, 11, 612},\n\tdictWord{135, 0, 784},\n\tdictWord{15, 0, 135},\n\tdictWord{143, 11, 135},\n\tdictWord{10, 0, 454},\n\tdictWord{140, 0, 324},\n\tdictWord{4, 11, 0},\n\tdictWord{5, 11, 41},\n\tdictWord{7, 11, 1459},\n\tdictWord{7, 11, 1469},\n\tdictWord{7, 11, 1618},\n\tdictWord{7, 11, 1859},\n\tdictWord{9, 11, 549},\n\tdictWord{139, 11, 905},\n\tdictWord{4, 10, 98},\n\tdictWord{7, 10, 1365},\n\tdictWord{9, 10, 422},\n\tdictWord{9, 10, 670},\n\tdictWord{10, 10, 775},\n\tdictWord{11, 10, 210},\n\tdictWord{13, 10, 26},\n\tdictWord{13, 10, 457},\n\tdictWord{141, 10, 476},\n\tdictWord{6, 0, 1719},\n\tdictWord{6, 0, 1735},\n\tdictWord{7, 0, 2016},\n\tdictWord{7, 0, 2020},\n\tdictWord{8, 0, 837},\n\tdictWord{137, 0, 852},\n\tdictWord{133, 11, 696},\n\tdictWord{135, 0, 852},\n\tdictWord{132, 0, 952},\n\tdictWord{134, 10, 1730},\n\tdictWord{132, 11, 771},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t568,\n\t},\n\tdictWord{137, 0, 448},\n\tdictWord{139, 0, 146},\n\tdictWord{8, 0, 67},\n\tdictWord{138, 0, 419},\n\tdictWord{133, 11, 921},\n\tdictWord{137, 10, 147},\n\tdictWord{134, 0, 1826},\n\tdictWord{10, 0, 657},\n\tdictWord{14, 0, 297},\n\tdictWord{142, 0, 361},\n\tdictWord{6, 0, 666},\n\tdictWord{6, 0, 767},\n\tdictWord{134, 0, 1542},\n\tdictWord{139, 0, 729},\n\tdictWord{6, 11, 180},\n\tdictWord{7, 11, 1137},\n\tdictWord{8, 11, 751},\n\tdictWord{139, 11, 805},\n\tdictWord{4, 11, 183},\n\tdictWord{7, 11, 271},\n\tdictWord{11, 11, 824},\n\tdictWord{11, 11, 952},\n\tdictWord{13, 11, 278},\n\tdictWord{13, 11, 339},\n\tdictWord{13, 11, 482},\n\tdictWord{14, 11, 424},\n\tdictWord{\n\t\t148,\n\t\t11,\n\t\t99,\n\t},\n\tdictWord{4, 0, 669},\n\tdictWord{5, 11, 477},\n\tdictWord{5, 11, 596},\n\tdictWord{6, 11, 505},\n\tdictWord{7, 11, 1221},\n\tdictWord{11, 11, 907},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t209,\n\t},\n\tdictWord{141, 11, 214},\n\tdictWord{135, 11, 1215},\n\tdictWord{5, 0, 402},\n\tdictWord{6, 10, 30},\n\tdictWord{11, 10, 56},\n\tdictWord{139, 10, 305},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t564,\n\t},\n\tdictWord{142, 11, 168},\n\tdictWord{139, 0, 152},\n\tdictWord{7, 0, 912},\n\tdictWord{135, 10, 1614},\n\tdictWord{4, 10, 150},\n\tdictWord{5, 10, 303},\n\tdictWord{134, 10, 327},\n\tdictWord{7, 0, 320},\n\tdictWord{8, 0, 51},\n\tdictWord{9, 0, 868},\n\tdictWord{10, 0, 833},\n\tdictWord{12, 0, 481},\n\tdictWord{12, 0, 570},\n\tdictWord{\n\t\t148,\n\t\t0,\n\t\t106,\n\t},\n\tdictWord{132, 0, 445},\n\tdictWord{7, 11, 274},\n\tdictWord{11, 11, 263},\n\tdictWord{11, 11, 479},\n\tdictWord{11, 11, 507},\n\tdictWord{140, 11, 277},\n\tdictWord{10, 0, 555},\n\tdictWord{11, 0, 308},\n\tdictWord{19, 0, 95},\n\tdictWord{6, 11, 1645},\n\tdictWord{8, 10, 192},\n\tdictWord{10, 10, 78},\n\tdictWord{141, 10, 359},\n\tdictWord{135, 10, 786},\n\tdictWord{6, 11, 92},\n\tdictWord{6, 11, 188},\n\tdictWord{7, 11, 1269},\n\tdictWord{7, 11, 1524},\n\tdictWord{7, 11, 1876},\n\tdictWord{10, 11, 228},\n\tdictWord{139, 11, 1020},\n\tdictWord{4, 11, 459},\n\tdictWord{133, 11, 966},\n\tdictWord{11, 0, 386},\n\tdictWord{6, 10, 1638},\n\tdictWord{7, 10, 79},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t496,\n\t},\n\tdictWord{9, 10, 138},\n\tdictWord{10, 10, 336},\n\tdictWord{12, 10, 412},\n\tdictWord{12, 10, 440},\n\tdictWord{142, 10, 305},\n\tdictWord{133, 0, 239},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t83,\n\t},\n\tdictWord{7, 0, 1990},\n\tdictWord{8, 0, 130},\n\tdictWord{139, 0, 720},\n\tdictWord{138, 11, 709},\n\tdictWord{4, 0, 143},\n\tdictWord{5, 0, 550},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t752,\n\t},\n\tdictWord{5, 0, 123},\n\tdictWord{6, 0, 530},\n\tdictWord{7, 0, 348},\n\tdictWord{135, 0, 1419},\n\tdictWord{135, 0, 2024},\n\tdictWord{6, 11, 18},\n\tdictWord{7, 11, 179},\n\tdictWord{7, 11, 721},\n\tdictWord{7, 11, 932},\n\tdictWord{8, 11, 548},\n\tdictWord{8, 11, 757},\n\tdictWord{9, 11, 54},\n\tdictWord{9, 11, 65},\n\tdictWord{9, 11, 532},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t844,\n\t},\n\tdictWord{10, 11, 113},\n\tdictWord{10, 11, 117},\n\tdictWord{10, 11, 236},\n\tdictWord{10, 11, 315},\n\tdictWord{10, 11, 430},\n\tdictWord{10, 11, 798},\n\tdictWord{11, 11, 153},\n\tdictWord{11, 11, 351},\n\tdictWord{11, 11, 375},\n\tdictWord{12, 11, 78},\n\tdictWord{12, 11, 151},\n\tdictWord{12, 11, 392},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t248,\n\t},\n\tdictWord{143, 11, 23},\n\tdictWord{7, 10, 204},\n\tdictWord{7, 10, 415},\n\tdictWord{8, 10, 42},\n\tdictWord{10, 10, 85},\n\tdictWord{139, 10, 564},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t958,\n\t},\n\tdictWord{133, 11, 965},\n\tdictWord{132, 0, 210},\n\tdictWord{135, 11, 1429},\n\tdictWord{138, 11, 480},\n\tdictWord{134, 11, 182},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t345,\n\t},\n\tdictWord{10, 11, 65},\n\tdictWord{10, 11, 488},\n\tdictWord{138, 11, 497},\n\tdictWord{4, 10, 3},\n\tdictWord{5, 10, 247},\n\tdictWord{5, 10, 644},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t744,\n\t},\n\tdictWord{7, 10, 1207},\n\tdictWord{7, 10, 1225},\n\tdictWord{7, 10, 1909},\n\tdictWord{146, 10, 147},\n\tdictWord{132, 0, 430},\n\tdictWord{5, 10, 285},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t67,\n\t},\n\tdictWord{13, 10, 473},\n\tdictWord{143, 10, 82},\n\tdictWord{144, 11, 16},\n\tdictWord{7, 11, 1162},\n\tdictWord{9, 11, 588},\n\tdictWord{10, 11, 260},\n\tdictWord{151, 10, 8},\n\tdictWord{133, 0, 213},\n\tdictWord{138, 0, 7},\n\tdictWord{135, 0, 801},\n\tdictWord{134, 11, 1786},\n\tdictWord{135, 11, 308},\n\tdictWord{6, 0, 936},\n\tdictWord{134, 0, 1289},\n\tdictWord{133, 0, 108},\n\tdictWord{132, 0, 885},\n\tdictWord{133, 0, 219},\n\tdictWord{139, 0, 587},\n\tdictWord{4, 0, 193},\n\tdictWord{5, 0, 916},\n\tdictWord{6, 0, 1041},\n\tdictWord{7, 0, 364},\n\tdictWord{10, 0, 398},\n\tdictWord{10, 0, 726},\n\tdictWord{11, 0, 317},\n\tdictWord{11, 0, 626},\n\tdictWord{12, 0, 142},\n\tdictWord{12, 0, 288},\n\tdictWord{12, 0, 678},\n\tdictWord{13, 0, 313},\n\tdictWord{15, 0, 113},\n\tdictWord{146, 0, 114},\n\tdictWord{135, 0, 1165},\n\tdictWord{6, 0, 241},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t342,\n\t},\n\tdictWord{10, 0, 729},\n\tdictWord{11, 0, 284},\n\tdictWord{11, 0, 445},\n\tdictWord{11, 0, 651},\n\tdictWord{11, 0, 863},\n\tdictWord{13, 0, 398},\n\tdictWord{\n\t\t146,\n\t\t0,\n\t\t99,\n\t},\n\tdictWord{7, 0, 907},\n\tdictWord{136, 0, 832},\n\tdictWord{9, 0, 303},\n\tdictWord{4, 10, 29},\n\tdictWord{6, 10, 532},\n\tdictWord{7, 10, 1628},\n\tdictWord{7, 10, 1648},\n\tdictWord{9, 10, 350},\n\tdictWord{10, 10, 433},\n\tdictWord{11, 10, 97},\n\tdictWord{11, 10, 557},\n\tdictWord{11, 10, 745},\n\tdictWord{12, 10, 289},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t335,\n\t},\n\tdictWord{12, 10, 348},\n\tdictWord{12, 10, 606},\n\tdictWord{13, 10, 116},\n\tdictWord{13, 10, 233},\n\tdictWord{13, 10, 466},\n\tdictWord{14, 10, 181},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t209,\n\t},\n\tdictWord{14, 10, 232},\n\tdictWord{14, 10, 236},\n\tdictWord{14, 10, 300},\n\tdictWord{16, 10, 41},\n\tdictWord{148, 10, 97},\n\tdictWord{7, 11, 423},\n\tdictWord{7, 10, 1692},\n\tdictWord{136, 11, 588},\n\tdictWord{6, 0, 931},\n\tdictWord{134, 0, 1454},\n\tdictWord{5, 10, 501},\n\tdictWord{7, 10, 1704},\n\tdictWord{9, 10, 553},\n\tdictWord{11, 10, 520},\n\tdictWord{12, 10, 557},\n\tdictWord{141, 10, 249},\n\tdictWord{136, 11, 287},\n\tdictWord{4, 0, 562},\n\tdictWord{9, 0, 254},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t879,\n\t},\n\tdictWord{132, 0, 786},\n\tdictWord{14, 11, 32},\n\tdictWord{18, 11, 85},\n\tdictWord{20, 11, 2},\n\tdictWord{152, 11, 16},\n\tdictWord{135, 0, 1294},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t723,\n\t},\n\tdictWord{135, 11, 1135},\n\tdictWord{6, 0, 216},\n\tdictWord{7, 0, 901},\n\tdictWord{7, 0, 1343},\n\tdictWord{8, 0, 493},\n\tdictWord{134, 11, 403},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t719,\n\t},\n\tdictWord{8, 11, 809},\n\tdictWord{136, 11, 834},\n\tdictWord{5, 11, 210},\n\tdictWord{6, 11, 213},\n\tdictWord{7, 11, 60},\n\tdictWord{10, 11, 364},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t135,\n\t},\n\tdictWord{7, 0, 341},\n\tdictWord{11, 0, 219},\n\tdictWord{5, 11, 607},\n\tdictWord{8, 11, 326},\n\tdictWord{136, 11, 490},\n\tdictWord{4, 11, 701},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t472,\n\t},\n\tdictWord{5, 11, 639},\n\tdictWord{7, 11, 1249},\n\tdictWord{9, 11, 758},\n\tdictWord{139, 11, 896},\n\tdictWord{135, 11, 380},\n\tdictWord{135, 11, 1947},\n\tdictWord{139, 0, 130},\n\tdictWord{135, 0, 1734},\n\tdictWord{10, 0, 115},\n\tdictWord{11, 0, 420},\n\tdictWord{12, 0, 154},\n\tdictWord{13, 0, 404},\n\tdictWord{14, 0, 346},\n\tdictWord{143, 0, 54},\n\tdictWord{134, 10, 129},\n\tdictWord{4, 11, 386},\n\tdictWord{7, 11, 41},\n\tdictWord{8, 11, 405},\n\tdictWord{9, 11, 497},\n\tdictWord{11, 11, 110},\n\tdictWord{11, 11, 360},\n\tdictWord{15, 11, 37},\n\tdictWord{144, 11, 84},\n\tdictWord{141, 11, 282},\n\tdictWord{5, 11, 46},\n\tdictWord{7, 11, 1452},\n\tdictWord{7, 11, 1480},\n\tdictWord{8, 11, 634},\n\tdictWord{140, 11, 472},\n\tdictWord{4, 11, 524},\n\tdictWord{136, 11, 810},\n\tdictWord{10, 11, 238},\n\tdictWord{141, 11, 33},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t604,\n\t},\n\tdictWord{5, 0, 1011},\n\tdictWord{136, 0, 701},\n\tdictWord{8, 0, 856},\n\tdictWord{8, 0, 858},\n\tdictWord{8, 0, 879},\n\tdictWord{12, 0, 702},\n\tdictWord{142, 0, 447},\n\tdictWord{4, 0, 54},\n\tdictWord{5, 0, 666},\n\tdictWord{7, 0, 1039},\n\tdictWord{7, 0, 1130},\n\tdictWord{9, 0, 195},\n\tdictWord{138, 0, 302},\n\tdictWord{4, 10, 25},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t60,\n\t},\n\tdictWord{6, 10, 504},\n\tdictWord{7, 10, 614},\n\tdictWord{7, 10, 1155},\n\tdictWord{140, 10, 0},\n\tdictWord{7, 10, 1248},\n\tdictWord{11, 10, 621},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t702,\n\t},\n\tdictWord{133, 11, 997},\n\tdictWord{137, 10, 321},\n\tdictWord{134, 0, 1669},\n\tdictWord{134, 0, 1791},\n\tdictWord{4, 10, 379},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1397,\n\t},\n\tdictWord{138, 11, 372},\n\tdictWord{5, 11, 782},\n\tdictWord{5, 11, 829},\n\tdictWord{134, 11, 1738},\n\tdictWord{135, 0, 1228},\n\tdictWord{4, 10, 118},\n\tdictWord{6, 10, 274},\n\tdictWord{6, 10, 361},\n\tdictWord{7, 10, 75},\n\tdictWord{141, 10, 441},\n\tdictWord{132, 0, 623},\n\tdictWord{9, 11, 279},\n\tdictWord{10, 11, 407},\n\tdictWord{14, 11, 84},\n\tdictWord{150, 11, 18},\n\tdictWord{137, 10, 841},\n\tdictWord{135, 0, 798},\n\tdictWord{140, 10, 693},\n\tdictWord{5, 10, 314},\n\tdictWord{6, 10, 221},\n\tdictWord{7, 10, 419},\n\tdictWord{10, 10, 650},\n\tdictWord{11, 10, 396},\n\tdictWord{12, 10, 156},\n\tdictWord{13, 10, 369},\n\tdictWord{14, 10, 333},\n\tdictWord{\n\t\t145,\n\t\t10,\n\t\t47,\n\t},\n\tdictWord{135, 11, 1372},\n\tdictWord{7, 0, 122},\n\tdictWord{9, 0, 259},\n\tdictWord{10, 0, 84},\n\tdictWord{11, 0, 470},\n\tdictWord{12, 0, 541},\n\tdictWord{\n\t\t141,\n\t\t0,\n\t\t379,\n\t},\n\tdictWord{134, 0, 837},\n\tdictWord{8, 0, 1013},\n\tdictWord{4, 11, 78},\n\tdictWord{5, 11, 96},\n\tdictWord{5, 11, 182},\n\tdictWord{7, 11, 1724},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1825,\n\t},\n\tdictWord{10, 11, 394},\n\tdictWord{10, 11, 471},\n\tdictWord{11, 11, 532},\n\tdictWord{14, 11, 340},\n\tdictWord{145, 11, 88},\n\tdictWord{134, 0, 577},\n\tdictWord{135, 11, 1964},\n\tdictWord{132, 10, 913},\n\tdictWord{134, 0, 460},\n\tdictWord{8, 0, 891},\n\tdictWord{10, 0, 901},\n\tdictWord{10, 0, 919},\n\tdictWord{10, 0, 932},\n\tdictWord{12, 0, 715},\n\tdictWord{12, 0, 728},\n\tdictWord{12, 0, 777},\n\tdictWord{14, 0, 457},\n\tdictWord{144, 0, 103},\n\tdictWord{5, 0, 82},\n\tdictWord{5, 0, 131},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1755,\n\t},\n\tdictWord{8, 0, 31},\n\tdictWord{9, 0, 168},\n\tdictWord{9, 0, 764},\n\tdictWord{139, 0, 869},\n\tdictWord{136, 10, 475},\n\tdictWord{6, 0, 605},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t1016,\n\t},\n\tdictWord{9, 11, 601},\n\tdictWord{9, 11, 619},\n\tdictWord{10, 11, 505},\n\tdictWord{10, 11, 732},\n\tdictWord{11, 11, 355},\n\tdictWord{140, 11, 139},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t602,\n\t},\n\tdictWord{8, 10, 179},\n\tdictWord{10, 10, 781},\n\tdictWord{140, 10, 126},\n\tdictWord{134, 0, 1246},\n\tdictWord{6, 10, 329},\n\tdictWord{138, 10, 111},\n\tdictWord{6, 11, 215},\n\tdictWord{7, 11, 1028},\n\tdictWord{7, 11, 1473},\n\tdictWord{7, 11, 1721},\n\tdictWord{9, 11, 424},\n\tdictWord{138, 11, 779},\n\tdictWord{5, 0, 278},\n\tdictWord{137, 0, 68},\n\tdictWord{6, 0, 932},\n\tdictWord{6, 0, 1084},\n\tdictWord{144, 0, 86},\n\tdictWord{4, 0, 163},\n\tdictWord{5, 0, 201},\n\tdictWord{5, 0, 307},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t310,\n\t},\n\tdictWord{6, 0, 335},\n\tdictWord{7, 0, 284},\n\tdictWord{7, 0, 1660},\n\tdictWord{136, 0, 165},\n\tdictWord{136, 0, 781},\n\tdictWord{134, 0, 707},\n\tdictWord{6, 0, 33},\n\tdictWord{135, 0, 1244},\n\tdictWord{5, 10, 821},\n\tdictWord{6, 11, 67},\n\tdictWord{6, 10, 1687},\n\tdictWord{7, 11, 258},\n\tdictWord{7, 11, 1630},\n\tdictWord{9, 11, 354},\n\tdictWord{9, 11, 675},\n\tdictWord{10, 11, 830},\n\tdictWord{14, 11, 80},\n\tdictWord{145, 11, 80},\n\tdictWord{6, 11, 141},\n\tdictWord{7, 11, 225},\n\tdictWord{9, 11, 59},\n\tdictWord{9, 11, 607},\n\tdictWord{10, 11, 312},\n\tdictWord{11, 11, 687},\n\tdictWord{12, 11, 555},\n\tdictWord{13, 11, 373},\n\tdictWord{13, 11, 494},\n\tdictWord{148, 11, 58},\n\tdictWord{134, 0, 1113},\n\tdictWord{9, 0, 388},\n\tdictWord{5, 10, 71},\n\tdictWord{7, 10, 1407},\n\tdictWord{9, 10, 704},\n\tdictWord{10, 10, 261},\n\tdictWord{10, 10, 619},\n\tdictWord{11, 10, 547},\n\tdictWord{11, 10, 619},\n\tdictWord{143, 10, 157},\n\tdictWord{7, 0, 1953},\n\tdictWord{136, 0, 720},\n\tdictWord{138, 0, 203},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t2008,\n\t},\n\tdictWord{9, 10, 337},\n\tdictWord{138, 10, 517},\n\tdictWord{6, 0, 326},\n\tdictWord{7, 0, 677},\n\tdictWord{137, 0, 425},\n\tdictWord{139, 11, 81},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1316,\n\t},\n\tdictWord{7, 0, 1412},\n\tdictWord{7, 0, 1839},\n\tdictWord{9, 0, 589},\n\tdictWord{11, 0, 241},\n\tdictWord{11, 0, 676},\n\tdictWord{11, 0, 811},\n\tdictWord{11, 0, 891},\n\tdictWord{12, 0, 140},\n\tdictWord{12, 0, 346},\n\tdictWord{12, 0, 479},\n\tdictWord{13, 0, 140},\n\tdictWord{13, 0, 381},\n\tdictWord{14, 0, 188},\n\tdictWord{18, 0, 30},\n\tdictWord{148, 0, 108},\n\tdictWord{5, 0, 416},\n\tdictWord{6, 10, 86},\n\tdictWord{6, 10, 603},\n\tdictWord{7, 10, 292},\n\tdictWord{7, 10, 561},\n\tdictWord{8, 10, 257},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t382,\n\t},\n\tdictWord{9, 10, 721},\n\tdictWord{9, 10, 778},\n\tdictWord{11, 10, 581},\n\tdictWord{140, 10, 466},\n\tdictWord{4, 10, 486},\n\tdictWord{133, 10, 491},\n\tdictWord{134, 0, 1300},\n\tdictWord{132, 10, 72},\n\tdictWord{7, 0, 847},\n\tdictWord{6, 10, 265},\n\tdictWord{7, 11, 430},\n\tdictWord{139, 11, 46},\n\tdictWord{5, 11, 602},\n\tdictWord{6, 11, 106},\n\tdictWord{7, 11, 1786},\n\tdictWord{7, 11, 1821},\n\tdictWord{7, 11, 2018},\n\tdictWord{9, 11, 418},\n\tdictWord{137, 11, 763},\n\tdictWord{5, 0, 358},\n\tdictWord{7, 0, 535},\n\tdictWord{7, 0, 1184},\n\tdictWord{10, 0, 662},\n\tdictWord{13, 0, 212},\n\tdictWord{13, 0, 304},\n\tdictWord{13, 0, 333},\n\tdictWord{145, 0, 98},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t65,\n\t},\n\tdictWord{6, 11, 416},\n\tdictWord{7, 11, 1720},\n\tdictWord{7, 11, 1924},\n\tdictWord{8, 11, 677},\n\tdictWord{10, 11, 109},\n\tdictWord{11, 11, 14},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t70,\n\t},\n\tdictWord{11, 11, 569},\n\tdictWord{11, 11, 735},\n\tdictWord{15, 11, 153},\n\tdictWord{148, 11, 80},\n\tdictWord{6, 0, 1823},\n\tdictWord{8, 0, 839},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t852,\n\t},\n\tdictWord{8, 0, 903},\n\tdictWord{10, 0, 940},\n\tdictWord{12, 0, 707},\n\tdictWord{140, 0, 775},\n\tdictWord{135, 11, 1229},\n\tdictWord{6, 0, 1522},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t654,\n\t},\n\tdictWord{136, 11, 595},\n\tdictWord{139, 0, 163},\n\tdictWord{141, 0, 314},\n\tdictWord{132, 0, 978},\n\tdictWord{4, 0, 601},\n\tdictWord{6, 0, 2035},\n\tdictWord{137, 10, 234},\n\tdictWord{5, 10, 815},\n\tdictWord{6, 10, 1688},\n\tdictWord{134, 10, 1755},\n\tdictWord{133, 0, 946},\n\tdictWord{136, 0, 434},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t197,\n\t},\n\tdictWord{136, 10, 205},\n\tdictWord{7, 0, 411},\n\tdictWord{7, 0, 590},\n\tdictWord{8, 0, 631},\n\tdictWord{9, 0, 323},\n\tdictWord{10, 0, 355},\n\tdictWord{11, 0, 491},\n\tdictWord{12, 0, 143},\n\tdictWord{12, 0, 402},\n\tdictWord{13, 0, 73},\n\tdictWord{14, 0, 408},\n\tdictWord{15, 0, 107},\n\tdictWord{146, 0, 71},\n\tdictWord{7, 0, 1467},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t328,\n\t},\n\tdictWord{10, 0, 544},\n\tdictWord{11, 0, 955},\n\tdictWord{12, 0, 13},\n\tdictWord{13, 0, 320},\n\tdictWord{145, 0, 83},\n\tdictWord{142, 0, 410},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t511,\n\t},\n\tdictWord{13, 0, 394},\n\tdictWord{14, 0, 298},\n\tdictWord{14, 0, 318},\n\tdictWord{146, 0, 103},\n\tdictWord{6, 10, 452},\n\tdictWord{7, 10, 312},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t219,\n\t},\n\tdictWord{138, 10, 589},\n\tdictWord{4, 10, 333},\n\tdictWord{9, 10, 176},\n\tdictWord{12, 10, 353},\n\tdictWord{141, 10, 187},\n\tdictWord{135, 11, 329},\n\tdictWord{132, 11, 469},\n\tdictWord{5, 0, 835},\n\tdictWord{134, 0, 483},\n\tdictWord{134, 11, 1743},\n\tdictWord{5, 11, 929},\n\tdictWord{6, 11, 340},\n\tdictWord{8, 11, 376},\n\tdictWord{136, 11, 807},\n\tdictWord{134, 10, 1685},\n\tdictWord{132, 0, 677},\n\tdictWord{5, 11, 218},\n\tdictWord{7, 11, 1610},\n\tdictWord{138, 11, 83},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t571,\n\t},\n\tdictWord{135, 11, 1842},\n\tdictWord{132, 11, 455},\n\tdictWord{137, 0, 70},\n\tdictWord{135, 0, 1405},\n\tdictWord{7, 10, 135},\n\tdictWord{8, 10, 7},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t62,\n\t},\n\tdictWord{9, 10, 243},\n\tdictWord{10, 10, 658},\n\tdictWord{10, 10, 697},\n\tdictWord{11, 10, 456},\n\tdictWord{139, 10, 756},\n\tdictWord{9, 10, 395},\n\tdictWord{138, 10, 79},\n\tdictWord{137, 0, 108},\n\tdictWord{6, 11, 161},\n\tdictWord{7, 11, 372},\n\tdictWord{137, 11, 597},\n\tdictWord{132, 11, 349},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t777,\n\t},\n\tdictWord{132, 0, 331},\n\tdictWord{135, 10, 631},\n\tdictWord{133, 0, 747},\n\tdictWord{6, 11, 432},\n\tdictWord{6, 11, 608},\n\tdictWord{139, 11, 322},\n\tdictWord{138, 10, 835},\n\tdictWord{5, 11, 468},\n\tdictWord{7, 11, 1809},\n\tdictWord{10, 11, 325},\n\tdictWord{11, 11, 856},\n\tdictWord{12, 11, 345},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t104,\n\t},\n\tdictWord{133, 11, 223},\n\tdictWord{7, 10, 406},\n\tdictWord{7, 10, 459},\n\tdictWord{8, 10, 606},\n\tdictWord{139, 10, 726},\n\tdictWord{132, 11, 566},\n\tdictWord{142, 0, 68},\n\tdictWord{4, 11, 59},\n\tdictWord{135, 11, 1394},\n\tdictWord{6, 11, 436},\n\tdictWord{139, 11, 481},\n\tdictWord{4, 11, 48},\n\tdictWord{5, 11, 271},\n\tdictWord{135, 11, 953},\n\tdictWord{139, 11, 170},\n\tdictWord{5, 11, 610},\n\tdictWord{136, 11, 457},\n\tdictWord{133, 11, 755},\n\tdictWord{135, 11, 1217},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t612,\n\t},\n\tdictWord{132, 11, 197},\n\tdictWord{132, 0, 505},\n\tdictWord{4, 10, 372},\n\tdictWord{7, 10, 482},\n\tdictWord{8, 10, 158},\n\tdictWord{9, 10, 602},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t615,\n\t},\n\tdictWord{10, 10, 245},\n\tdictWord{10, 10, 678},\n\tdictWord{10, 10, 744},\n\tdictWord{11, 10, 248},\n\tdictWord{139, 10, 806},\n\tdictWord{133, 0, 326},\n\tdictWord{5, 10, 854},\n\tdictWord{135, 10, 1991},\n\tdictWord{4, 0, 691},\n\tdictWord{146, 0, 16},\n\tdictWord{6, 0, 628},\n\tdictWord{9, 0, 35},\n\tdictWord{10, 0, 680},\n\tdictWord{10, 0, 793},\n\tdictWord{11, 0, 364},\n\tdictWord{13, 0, 357},\n\tdictWord{143, 0, 164},\n\tdictWord{138, 0, 654},\n\tdictWord{6, 0, 32},\n\tdictWord{7, 0, 385},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t757,\n\t},\n\tdictWord{7, 0, 1916},\n\tdictWord{8, 0, 37},\n\tdictWord{8, 0, 94},\n\tdictWord{8, 0, 711},\n\tdictWord{9, 0, 541},\n\tdictWord{10, 0, 162},\n\tdictWord{10, 0, 795},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t989,\n\t},\n\tdictWord{11, 0, 1010},\n\tdictWord{12, 0, 14},\n\tdictWord{142, 0, 308},\n\tdictWord{133, 11, 217},\n\tdictWord{6, 0, 152},\n\tdictWord{6, 0, 349},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1682,\n\t},\n\tdictWord{7, 0, 1252},\n\tdictWord{8, 0, 112},\n\tdictWord{9, 0, 435},\n\tdictWord{9, 0, 668},\n\tdictWord{10, 0, 290},\n\tdictWord{10, 0, 319},\n\tdictWord{10, 0, 815},\n\tdictWord{11, 0, 180},\n\tdictWord{11, 0, 837},\n\tdictWord{12, 0, 240},\n\tdictWord{13, 0, 152},\n\tdictWord{13, 0, 219},\n\tdictWord{142, 0, 158},\n\tdictWord{4, 0, 581},\n\tdictWord{134, 0, 726},\n\tdictWord{5, 10, 195},\n\tdictWord{135, 10, 1685},\n\tdictWord{6, 0, 126},\n\tdictWord{7, 0, 573},\n\tdictWord{8, 0, 397},\n\tdictWord{142, 0, 44},\n\tdictWord{138, 0, 89},\n\tdictWord{7, 10, 1997},\n\tdictWord{8, 10, 730},\n\tdictWord{139, 10, 1006},\n\tdictWord{134, 0, 1531},\n\tdictWord{134, 0, 1167},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t926,\n\t},\n\tdictWord{12, 0, 203},\n\tdictWord{133, 10, 751},\n\tdictWord{4, 11, 165},\n\tdictWord{7, 11, 1398},\n\tdictWord{135, 11, 1829},\n\tdictWord{7, 0, 1232},\n\tdictWord{137, 0, 531},\n\tdictWord{135, 10, 821},\n\tdictWord{134, 0, 943},\n\tdictWord{133, 0, 670},\n\tdictWord{4, 0, 880},\n\tdictWord{139, 0, 231},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1617,\n\t},\n\tdictWord{135, 0, 1957},\n\tdictWord{5, 11, 9},\n\tdictWord{7, 11, 297},\n\tdictWord{7, 11, 966},\n\tdictWord{140, 11, 306},\n\tdictWord{6, 0, 975},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t985,\n\t},\n\tdictWord{5, 10, 950},\n\tdictWord{5, 10, 994},\n\tdictWord{134, 10, 351},\n\tdictWord{12, 11, 21},\n\tdictWord{151, 11, 7},\n\tdictWord{5, 11, 146},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t411,\n\t},\n\tdictWord{138, 11, 721},\n\tdictWord{7, 0, 242},\n\tdictWord{135, 0, 1942},\n\tdictWord{6, 11, 177},\n\tdictWord{135, 11, 467},\n\tdictWord{5, 0, 421},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t47,\n\t},\n\tdictWord{137, 10, 684},\n\tdictWord{5, 0, 834},\n\tdictWord{7, 0, 1202},\n\tdictWord{8, 0, 14},\n\tdictWord{9, 0, 481},\n\tdictWord{137, 0, 880},\n\tdictWord{138, 0, 465},\n\tdictWord{6, 0, 688},\n\tdictWord{9, 0, 834},\n\tdictWord{132, 10, 350},\n\tdictWord{132, 0, 855},\n\tdictWord{4, 0, 357},\n\tdictWord{6, 0, 172},\n\tdictWord{7, 0, 143},\n\tdictWord{137, 0, 413},\n\tdictWord{133, 11, 200},\n\tdictWord{132, 0, 590},\n\tdictWord{7, 10, 1812},\n\tdictWord{13, 10, 259},\n\tdictWord{13, 10, 356},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t242,\n\t},\n\tdictWord{147, 10, 114},\n\tdictWord{133, 10, 967},\n\tdictWord{11, 0, 114},\n\tdictWord{4, 10, 473},\n\tdictWord{7, 10, 623},\n\tdictWord{8, 10, 808},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t871,\n\t},\n\tdictWord{9, 10, 893},\n\tdictWord{11, 10, 431},\n\tdictWord{12, 10, 112},\n\tdictWord{12, 10, 217},\n\tdictWord{12, 10, 243},\n\tdictWord{12, 10, 562},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t663,\n\t},\n\tdictWord{12, 10, 683},\n\tdictWord{13, 10, 141},\n\tdictWord{13, 10, 197},\n\tdictWord{13, 10, 227},\n\tdictWord{13, 10, 406},\n\tdictWord{13, 10, 487},\n\tdictWord{14, 10, 156},\n\tdictWord{14, 10, 203},\n\tdictWord{14, 10, 224},\n\tdictWord{14, 10, 256},\n\tdictWord{18, 10, 58},\n\tdictWord{150, 10, 0},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t286,\n\t},\n\tdictWord{4, 10, 222},\n\tdictWord{7, 10, 286},\n\tdictWord{136, 10, 629},\n\tdictWord{5, 0, 169},\n\tdictWord{7, 0, 333},\n\tdictWord{136, 0, 45},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t481,\n\t},\n\tdictWord{132, 0, 198},\n\tdictWord{4, 0, 24},\n\tdictWord{5, 0, 140},\n\tdictWord{5, 0, 185},\n\tdictWord{7, 0, 1500},\n\tdictWord{11, 0, 565},\n\tdictWord{11, 0, 838},\n\tdictWord{4, 11, 84},\n\tdictWord{7, 11, 1482},\n\tdictWord{10, 11, 76},\n\tdictWord{138, 11, 142},\n\tdictWord{133, 0, 585},\n\tdictWord{141, 10, 306},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t1015,\n\t},\n\tdictWord{4, 11, 315},\n\tdictWord{5, 11, 507},\n\tdictWord{135, 11, 1370},\n\tdictWord{136, 10, 146},\n\tdictWord{6, 0, 691},\n\tdictWord{134, 0, 1503},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t334,\n\t},\n\tdictWord{133, 0, 593},\n\tdictWord{4, 10, 465},\n\tdictWord{135, 10, 1663},\n\tdictWord{142, 11, 173},\n\tdictWord{135, 0, 913},\n\tdictWord{12, 0, 116},\n\tdictWord{134, 11, 1722},\n\tdictWord{134, 0, 1360},\n\tdictWord{132, 0, 802},\n\tdictWord{8, 11, 222},\n\tdictWord{8, 11, 476},\n\tdictWord{9, 11, 238},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t516,\n\t},\n\tdictWord{11, 11, 575},\n\tdictWord{15, 11, 109},\n\tdictWord{146, 11, 100},\n\tdictWord{6, 0, 308},\n\tdictWord{9, 0, 673},\n\tdictWord{7, 10, 138},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t517,\n\t},\n\tdictWord{139, 10, 238},\n\tdictWord{132, 0, 709},\n\tdictWord{6, 0, 1876},\n\tdictWord{6, 0, 1895},\n\tdictWord{9, 0, 994},\n\tdictWord{9, 0, 1006},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t829,\n\t},\n\tdictWord{12, 0, 888},\n\tdictWord{12, 0, 891},\n\tdictWord{146, 0, 185},\n\tdictWord{148, 10, 94},\n\tdictWord{4, 0, 228},\n\tdictWord{133, 0, 897},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1840,\n\t},\n\tdictWord{5, 10, 495},\n\tdictWord{7, 10, 834},\n\tdictWord{9, 10, 733},\n\tdictWord{139, 10, 378},\n\tdictWord{133, 10, 559},\n\tdictWord{6, 10, 21},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1737,\n\t},\n\tdictWord{7, 10, 1444},\n\tdictWord{136, 10, 224},\n\tdictWord{4, 0, 608},\n\tdictWord{133, 0, 497},\n\tdictWord{6, 11, 40},\n\tdictWord{135, 11, 1781},\n\tdictWord{134, 0, 1573},\n\tdictWord{135, 0, 2039},\n\tdictWord{6, 0, 540},\n\tdictWord{136, 0, 136},\n\tdictWord{4, 0, 897},\n\tdictWord{5, 0, 786},\n\tdictWord{133, 10, 519},\n\tdictWord{6, 0, 1878},\n\tdictWord{6, 0, 1884},\n\tdictWord{9, 0, 938},\n\tdictWord{9, 0, 948},\n\tdictWord{9, 0, 955},\n\tdictWord{9, 0, 973},\n\tdictWord{9, 0, 1012},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t895,\n\t},\n\tdictWord{12, 0, 927},\n\tdictWord{143, 0, 254},\n\tdictWord{134, 0, 1469},\n\tdictWord{133, 0, 999},\n\tdictWord{4, 0, 299},\n\tdictWord{135, 0, 1004},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t745,\n\t},\n\tdictWord{133, 0, 578},\n\tdictWord{136, 11, 574},\n\tdictWord{133, 0, 456},\n\tdictWord{134, 0, 1457},\n\tdictWord{7, 0, 1679},\n\tdictWord{132, 10, 402},\n\tdictWord{7, 0, 693},\n\tdictWord{8, 0, 180},\n\tdictWord{12, 0, 163},\n\tdictWord{8, 10, 323},\n\tdictWord{136, 10, 479},\n\tdictWord{11, 10, 580},\n\tdictWord{142, 10, 201},\n\tdictWord{5, 10, 59},\n\tdictWord{135, 10, 672},\n\tdictWord{132, 11, 354},\n\tdictWord{146, 10, 34},\n\tdictWord{4, 0, 755},\n\tdictWord{135, 11, 1558},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1740,\n\t},\n\tdictWord{146, 0, 48},\n\tdictWord{4, 10, 85},\n\tdictWord{135, 10, 549},\n\tdictWord{139, 0, 338},\n\tdictWord{133, 10, 94},\n\tdictWord{134, 0, 1091},\n\tdictWord{135, 11, 469},\n\tdictWord{12, 0, 695},\n\tdictWord{12, 0, 704},\n\tdictWord{20, 0, 113},\n\tdictWord{5, 11, 830},\n\tdictWord{14, 11, 338},\n\tdictWord{148, 11, 81},\n\tdictWord{135, 0, 1464},\n\tdictWord{6, 10, 11},\n\tdictWord{135, 10, 187},\n\tdictWord{135, 0, 975},\n\tdictWord{13, 0, 335},\n\tdictWord{132, 10, 522},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1979,\n\t},\n\tdictWord{5, 11, 496},\n\tdictWord{135, 11, 203},\n\tdictWord{4, 10, 52},\n\tdictWord{135, 10, 661},\n\tdictWord{7, 0, 1566},\n\tdictWord{8, 0, 269},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t212,\n\t},\n\tdictWord{9, 0, 718},\n\tdictWord{14, 0, 15},\n\tdictWord{14, 0, 132},\n\tdictWord{142, 0, 227},\n\tdictWord{4, 0, 890},\n\tdictWord{5, 0, 805},\n\tdictWord{5, 0, 819},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t961,\n\t},\n\tdictWord{6, 0, 396},\n\tdictWord{6, 0, 1631},\n\tdictWord{6, 0, 1678},\n\tdictWord{7, 0, 1967},\n\tdictWord{7, 0, 2041},\n\tdictWord{9, 0, 630},\n\tdictWord{11, 0, 8},\n\tdictWord{11, 0, 1019},\n\tdictWord{12, 0, 176},\n\tdictWord{13, 0, 225},\n\tdictWord{14, 0, 292},\n\tdictWord{21, 0, 24},\n\tdictWord{4, 10, 383},\n\tdictWord{133, 10, 520},\n\tdictWord{134, 11, 547},\n\tdictWord{135, 11, 1748},\n\tdictWord{5, 11, 88},\n\tdictWord{137, 11, 239},\n\tdictWord{146, 11, 128},\n\tdictWord{7, 11, 650},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1310,\n\t},\n\tdictWord{4, 10, 281},\n\tdictWord{5, 10, 38},\n\tdictWord{7, 10, 194},\n\tdictWord{7, 10, 668},\n\tdictWord{7, 10, 1893},\n\tdictWord{137, 10, 397},\n\tdictWord{135, 0, 1815},\n\tdictWord{9, 10, 635},\n\tdictWord{139, 10, 559},\n\tdictWord{7, 0, 1505},\n\tdictWord{10, 0, 190},\n\tdictWord{10, 0, 634},\n\tdictWord{11, 0, 792},\n\tdictWord{12, 0, 358},\n\tdictWord{140, 0, 447},\n\tdictWord{5, 0, 0},\n\tdictWord{6, 0, 536},\n\tdictWord{7, 0, 604},\n\tdictWord{13, 0, 445},\n\tdictWord{145, 0, 126},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1076,\n\t},\n\tdictWord{9, 11, 80},\n\tdictWord{11, 11, 78},\n\tdictWord{11, 11, 421},\n\tdictWord{11, 11, 534},\n\tdictWord{140, 11, 545},\n\tdictWord{8, 0, 966},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t1023,\n\t},\n\tdictWord{14, 11, 369},\n\tdictWord{146, 11, 72},\n\tdictWord{135, 11, 1641},\n\tdictWord{6, 0, 232},\n\tdictWord{6, 0, 412},\n\tdictWord{7, 0, 1074},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t9,\n\t},\n\tdictWord{8, 0, 157},\n\tdictWord{8, 0, 786},\n\tdictWord{9, 0, 196},\n\tdictWord{9, 0, 352},\n\tdictWord{9, 0, 457},\n\tdictWord{10, 0, 337},\n\tdictWord{11, 0, 232},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t877,\n\t},\n\tdictWord{12, 0, 480},\n\tdictWord{140, 0, 546},\n\tdictWord{135, 0, 958},\n\tdictWord{4, 0, 382},\n\tdictWord{136, 0, 579},\n\tdictWord{4, 0, 212},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1206,\n\t},\n\tdictWord{4, 11, 497},\n\tdictWord{5, 11, 657},\n\tdictWord{135, 11, 1584},\n\tdictWord{132, 0, 681},\n\tdictWord{8, 0, 971},\n\tdictWord{138, 0, 965},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t448,\n\t},\n\tdictWord{136, 10, 535},\n\tdictWord{14, 0, 16},\n\tdictWord{146, 0, 44},\n\tdictWord{11, 0, 584},\n\tdictWord{11, 0, 616},\n\tdictWord{14, 0, 275},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t584,\n\t},\n\tdictWord{11, 11, 616},\n\tdictWord{142, 11, 275},\n\tdictWord{136, 11, 13},\n\tdictWord{7, 10, 610},\n\tdictWord{135, 10, 1501},\n\tdictWord{7, 11, 642},\n\tdictWord{8, 11, 250},\n\tdictWord{11, 11, 123},\n\tdictWord{11, 11, 137},\n\tdictWord{13, 11, 48},\n\tdictWord{142, 11, 95},\n\tdictWord{133, 0, 655},\n\tdictWord{17, 0, 67},\n\tdictWord{147, 0, 74},\n\tdictWord{134, 0, 751},\n\tdictWord{134, 0, 1967},\n\tdictWord{6, 0, 231},\n\tdictWord{136, 0, 423},\n\tdictWord{5, 0, 300},\n\tdictWord{138, 0, 1016},\n\tdictWord{4, 10, 319},\n\tdictWord{5, 10, 699},\n\tdictWord{138, 10, 673},\n\tdictWord{6, 0, 237},\n\tdictWord{7, 0, 611},\n\tdictWord{8, 0, 100},\n\tdictWord{9, 0, 416},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t335,\n\t},\n\tdictWord{12, 0, 173},\n\tdictWord{18, 0, 101},\n\tdictWord{6, 10, 336},\n\tdictWord{8, 10, 552},\n\tdictWord{9, 10, 285},\n\tdictWord{10, 10, 99},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t568,\n\t},\n\tdictWord{134, 0, 1370},\n\tdictWord{7, 10, 1406},\n\tdictWord{9, 10, 218},\n\tdictWord{141, 10, 222},\n\tdictWord{133, 10, 256},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1208,\n\t},\n\tdictWord{14, 11, 213},\n\tdictWord{148, 11, 38},\n\tdictWord{6, 0, 1219},\n\tdictWord{135, 11, 1642},\n\tdictWord{13, 0, 417},\n\tdictWord{14, 0, 129},\n\tdictWord{143, 0, 15},\n\tdictWord{10, 11, 545},\n\tdictWord{140, 11, 301},\n\tdictWord{17, 10, 39},\n\tdictWord{148, 10, 36},\n\tdictWord{133, 0, 199},\n\tdictWord{4, 11, 904},\n\tdictWord{133, 11, 794},\n\tdictWord{12, 0, 427},\n\tdictWord{146, 0, 38},\n\tdictWord{134, 0, 949},\n\tdictWord{8, 0, 665},\n\tdictWord{135, 10, 634},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t618,\n\t},\n\tdictWord{135, 10, 259},\n\tdictWord{132, 10, 339},\n\tdictWord{133, 11, 761},\n\tdictWord{141, 10, 169},\n\tdictWord{132, 10, 759},\n\tdictWord{5, 0, 688},\n\tdictWord{7, 0, 539},\n\tdictWord{135, 0, 712},\n\tdictWord{7, 11, 386},\n\tdictWord{138, 11, 713},\n\tdictWord{134, 0, 1186},\n\tdictWord{6, 11, 7},\n\tdictWord{6, 11, 35},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t147,\n\t},\n\tdictWord{7, 11, 1069},\n\tdictWord{7, 11, 1568},\n\tdictWord{7, 11, 1575},\n\tdictWord{7, 11, 1917},\n\tdictWord{8, 11, 43},\n\tdictWord{8, 11, 208},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t128,\n\t},\n\tdictWord{9, 11, 866},\n\tdictWord{10, 11, 20},\n\tdictWord{11, 11, 981},\n\tdictWord{147, 11, 33},\n\tdictWord{7, 11, 893},\n\tdictWord{8, 10, 482},\n\tdictWord{141, 11, 424},\n\tdictWord{6, 0, 312},\n\tdictWord{6, 0, 1715},\n\tdictWord{10, 0, 584},\n\tdictWord{11, 0, 546},\n\tdictWord{11, 0, 692},\n\tdictWord{12, 0, 259},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t295,\n\t},\n\tdictWord{13, 0, 46},\n\tdictWord{141, 0, 154},\n\tdictWord{5, 10, 336},\n\tdictWord{6, 10, 341},\n\tdictWord{6, 10, 478},\n\tdictWord{6, 10, 1763},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t386,\n\t},\n\tdictWord{137, 0, 151},\n\tdictWord{132, 0, 588},\n\tdictWord{152, 0, 4},\n\tdictWord{6, 11, 322},\n\tdictWord{9, 11, 552},\n\tdictWord{11, 11, 274},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t209,\n\t},\n\tdictWord{13, 11, 499},\n\tdictWord{14, 11, 85},\n\tdictWord{15, 11, 126},\n\tdictWord{145, 11, 70},\n\tdictWord{135, 10, 73},\n\tdictWord{4, 0, 231},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t61,\n\t},\n\tdictWord{6, 0, 104},\n\tdictWord{7, 0, 729},\n\tdictWord{7, 0, 964},\n\tdictWord{7, 0, 1658},\n\tdictWord{140, 0, 414},\n\tdictWord{6, 0, 263},\n\tdictWord{138, 0, 757},\n\tdictWord{135, 10, 1971},\n\tdictWord{4, 0, 612},\n\tdictWord{133, 0, 561},\n\tdictWord{132, 0, 320},\n\tdictWord{135, 10, 1344},\n\tdictWord{8, 11, 83},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t817,\n\t},\n\tdictWord{9, 11, 28},\n\tdictWord{9, 11, 29},\n\tdictWord{9, 11, 885},\n\tdictWord{10, 11, 387},\n\tdictWord{11, 11, 633},\n\tdictWord{11, 11, 740},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t235,\n\t},\n\tdictWord{13, 11, 254},\n\tdictWord{15, 11, 143},\n\tdictWord{143, 11, 146},\n\tdictWord{5, 10, 396},\n\tdictWord{134, 10, 501},\n\tdictWord{140, 11, 49},\n\tdictWord{132, 0, 225},\n\tdictWord{4, 10, 929},\n\tdictWord{5, 10, 799},\n\tdictWord{8, 10, 46},\n\tdictWord{136, 10, 740},\n\tdictWord{4, 0, 405},\n\tdictWord{7, 0, 817},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t58,\n\t},\n\tdictWord{17, 0, 37},\n\tdictWord{146, 0, 124},\n\tdictWord{133, 0, 974},\n\tdictWord{4, 11, 412},\n\tdictWord{133, 11, 581},\n\tdictWord{4, 10, 892},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t770,\n\t},\n\tdictWord{4, 0, 996},\n\tdictWord{134, 0, 2026},\n\tdictWord{4, 0, 527},\n\tdictWord{5, 0, 235},\n\tdictWord{7, 0, 1239},\n\tdictWord{11, 0, 131},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t370,\n\t},\n\tdictWord{9, 0, 16},\n\tdictWord{13, 0, 386},\n\tdictWord{135, 11, 421},\n\tdictWord{7, 0, 956},\n\tdictWord{7, 0, 1157},\n\tdictWord{7, 0, 1506},\n\tdictWord{7, 0, 1606},\n\tdictWord{7, 0, 1615},\n\tdictWord{7, 0, 1619},\n\tdictWord{7, 0, 1736},\n\tdictWord{7, 0, 1775},\n\tdictWord{8, 0, 590},\n\tdictWord{9, 0, 324},\n\tdictWord{9, 0, 736},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t774,\n\t},\n\tdictWord{9, 0, 776},\n\tdictWord{9, 0, 784},\n\tdictWord{10, 0, 567},\n\tdictWord{10, 0, 708},\n\tdictWord{11, 0, 518},\n\tdictWord{11, 0, 613},\n\tdictWord{11, 0, 695},\n\tdictWord{11, 0, 716},\n\tdictWord{11, 0, 739},\n\tdictWord{11, 0, 770},\n\tdictWord{11, 0, 771},\n\tdictWord{11, 0, 848},\n\tdictWord{11, 0, 857},\n\tdictWord{11, 0, 931},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t947,\n\t},\n\tdictWord{12, 0, 326},\n\tdictWord{12, 0, 387},\n\tdictWord{12, 0, 484},\n\tdictWord{12, 0, 528},\n\tdictWord{12, 0, 552},\n\tdictWord{12, 0, 613},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t189,\n\t},\n\tdictWord{13, 0, 256},\n\tdictWord{13, 0, 340},\n\tdictWord{13, 0, 432},\n\tdictWord{13, 0, 436},\n\tdictWord{13, 0, 440},\n\tdictWord{13, 0, 454},\n\tdictWord{14, 0, 174},\n\tdictWord{14, 0, 220},\n\tdictWord{14, 0, 284},\n\tdictWord{14, 0, 390},\n\tdictWord{145, 0, 121},\n\tdictWord{135, 10, 158},\n\tdictWord{9, 0, 137},\n\tdictWord{138, 0, 221},\n\tdictWord{4, 11, 110},\n\tdictWord{10, 11, 415},\n\tdictWord{10, 11, 597},\n\tdictWord{142, 11, 206},\n\tdictWord{141, 11, 496},\n\tdictWord{135, 11, 205},\n\tdictWord{\n\t\t151,\n\t\t10,\n\t\t25,\n\t},\n\tdictWord{135, 11, 778},\n\tdictWord{7, 11, 1656},\n\tdictWord{7, 10, 2001},\n\tdictWord{9, 11, 369},\n\tdictWord{10, 11, 338},\n\tdictWord{10, 11, 490},\n\tdictWord{11, 11, 154},\n\tdictWord{11, 11, 545},\n\tdictWord{11, 11, 775},\n\tdictWord{13, 11, 77},\n\tdictWord{141, 11, 274},\n\tdictWord{4, 11, 444},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t146,\n\t},\n\tdictWord{140, 11, 9},\n\tdictWord{7, 0, 390},\n\tdictWord{138, 0, 140},\n\tdictWord{135, 0, 1144},\n\tdictWord{134, 0, 464},\n\tdictWord{7, 10, 1461},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t91,\n\t},\n\tdictWord{132, 10, 602},\n\tdictWord{4, 11, 283},\n\tdictWord{135, 11, 1194},\n\tdictWord{5, 0, 407},\n\tdictWord{11, 0, 204},\n\tdictWord{11, 0, 243},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t489,\n\t},\n\tdictWord{12, 0, 293},\n\tdictWord{19, 0, 37},\n\tdictWord{20, 0, 73},\n\tdictWord{150, 0, 38},\n\tdictWord{7, 0, 1218},\n\tdictWord{136, 0, 303},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t325,\n\t},\n\tdictWord{8, 0, 5},\n\tdictWord{8, 0, 227},\n\tdictWord{9, 0, 105},\n\tdictWord{10, 0, 585},\n\tdictWord{12, 0, 614},\n\tdictWord{4, 10, 13},\n\tdictWord{5, 10, 567},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1498,\n\t},\n\tdictWord{9, 10, 124},\n\tdictWord{11, 10, 521},\n\tdictWord{140, 10, 405},\n\tdictWord{135, 10, 1006},\n\tdictWord{7, 0, 800},\n\tdictWord{10, 0, 12},\n\tdictWord{134, 11, 1720},\n\tdictWord{135, 0, 1783},\n\tdictWord{132, 10, 735},\n\tdictWord{138, 10, 812},\n\tdictWord{4, 10, 170},\n\tdictWord{135, 10, 323},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t621,\n\t},\n\tdictWord{13, 0, 504},\n\tdictWord{144, 0, 89},\n\tdictWord{5, 10, 304},\n\tdictWord{135, 10, 1403},\n\tdictWord{137, 11, 216},\n\tdictWord{6, 0, 920},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1104,\n\t},\n\tdictWord{9, 11, 183},\n\tdictWord{139, 11, 286},\n\tdictWord{4, 0, 376},\n\tdictWord{133, 10, 742},\n\tdictWord{134, 0, 218},\n\tdictWord{8, 0, 641},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t388,\n\t},\n\tdictWord{140, 0, 580},\n\tdictWord{7, 0, 454},\n\tdictWord{7, 0, 782},\n\tdictWord{8, 0, 768},\n\tdictWord{140, 0, 686},\n\tdictWord{137, 11, 33},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t111,\n\t},\n\tdictWord{144, 0, 0},\n\tdictWord{10, 0, 676},\n\tdictWord{140, 0, 462},\n\tdictWord{6, 0, 164},\n\tdictWord{136, 11, 735},\n\tdictWord{133, 10, 444},\n\tdictWord{\n\t\t150,\n\t\t0,\n\t\t50,\n\t},\n\tdictWord{7, 11, 1862},\n\tdictWord{12, 11, 491},\n\tdictWord{12, 11, 520},\n\tdictWord{13, 11, 383},\n\tdictWord{14, 11, 244},\n\tdictWord{146, 11, 12},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t132,\n\t},\n\tdictWord{9, 11, 486},\n\tdictWord{9, 11, 715},\n\tdictWord{10, 11, 458},\n\tdictWord{11, 11, 373},\n\tdictWord{11, 11, 668},\n\tdictWord{11, 11, 795},\n\tdictWord{11, 11, 897},\n\tdictWord{12, 11, 272},\n\tdictWord{12, 11, 424},\n\tdictWord{12, 11, 539},\n\tdictWord{12, 11, 558},\n\tdictWord{14, 11, 245},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t263,\n\t},\n\tdictWord{14, 11, 264},\n\tdictWord{14, 11, 393},\n\tdictWord{142, 11, 403},\n\tdictWord{8, 10, 123},\n\tdictWord{15, 10, 6},\n\tdictWord{144, 10, 7},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t285,\n\t},\n\tdictWord{8, 0, 654},\n\tdictWord{11, 0, 749},\n\tdictWord{12, 0, 190},\n\tdictWord{12, 0, 327},\n\tdictWord{13, 0, 120},\n\tdictWord{13, 0, 121},\n\tdictWord{13, 0, 327},\n\tdictWord{15, 0, 47},\n\tdictWord{146, 0, 40},\n\tdictWord{5, 11, 8},\n\tdictWord{6, 11, 89},\n\tdictWord{6, 11, 400},\n\tdictWord{7, 11, 1569},\n\tdictWord{7, 11, 1623},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1850,\n\t},\n\tdictWord{8, 11, 218},\n\tdictWord{8, 11, 422},\n\tdictWord{9, 11, 570},\n\tdictWord{138, 11, 626},\n\tdictWord{6, 11, 387},\n\tdictWord{7, 11, 882},\n\tdictWord{141, 11, 111},\n\tdictWord{6, 0, 343},\n\tdictWord{7, 0, 195},\n\tdictWord{9, 0, 226},\n\tdictWord{10, 0, 197},\n\tdictWord{10, 0, 575},\n\tdictWord{11, 0, 502},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t899,\n\t},\n\tdictWord{6, 11, 224},\n\tdictWord{7, 11, 877},\n\tdictWord{137, 11, 647},\n\tdictWord{5, 10, 937},\n\tdictWord{135, 10, 100},\n\tdictWord{135, 11, 790},\n\tdictWord{150, 0, 29},\n\tdictWord{147, 0, 8},\n\tdictWord{134, 0, 1812},\n\tdictWord{149, 0, 8},\n\tdictWord{135, 11, 394},\n\tdictWord{7, 0, 1125},\n\tdictWord{9, 0, 143},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t61,\n\t},\n\tdictWord{14, 0, 405},\n\tdictWord{150, 0, 21},\n\tdictWord{10, 11, 755},\n\tdictWord{147, 11, 29},\n\tdictWord{9, 11, 378},\n\tdictWord{141, 11, 162},\n\tdictWord{135, 10, 922},\n\tdictWord{5, 10, 619},\n\tdictWord{133, 10, 698},\n\tdictWord{134, 0, 1327},\n\tdictWord{6, 0, 1598},\n\tdictWord{137, 0, 575},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t569,\n\t},\n\tdictWord{12, 11, 12},\n\tdictWord{12, 11, 81},\n\tdictWord{12, 11, 319},\n\tdictWord{13, 11, 69},\n\tdictWord{14, 11, 259},\n\tdictWord{16, 11, 87},\n\tdictWord{\n\t\t17,\n\t\t11,\n\t\t1,\n\t},\n\tdictWord{17, 11, 21},\n\tdictWord{17, 11, 24},\n\tdictWord{18, 11, 15},\n\tdictWord{18, 11, 56},\n\tdictWord{18, 11, 59},\n\tdictWord{18, 11, 127},\n\tdictWord{18, 11, 154},\n\tdictWord{19, 11, 19},\n\tdictWord{148, 11, 31},\n\tdictWord{6, 0, 895},\n\tdictWord{135, 11, 1231},\n\tdictWord{5, 0, 959},\n\tdictWord{7, 11, 124},\n\tdictWord{136, 11, 38},\n\tdictWord{5, 11, 261},\n\tdictWord{7, 11, 78},\n\tdictWord{7, 11, 199},\n\tdictWord{8, 11, 815},\n\tdictWord{9, 11, 126},\n\tdictWord{138, 11, 342},\n\tdictWord{5, 10, 917},\n\tdictWord{134, 10, 1659},\n\tdictWord{7, 0, 1759},\n\tdictWord{5, 11, 595},\n\tdictWord{135, 11, 1863},\n\tdictWord{136, 0, 173},\n\tdictWord{134, 0, 266},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t261,\n\t},\n\tdictWord{132, 11, 628},\n\tdictWord{5, 10, 251},\n\tdictWord{5, 10, 956},\n\tdictWord{8, 10, 268},\n\tdictWord{9, 10, 214},\n\tdictWord{146, 10, 142},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t266,\n\t},\n\tdictWord{136, 11, 804},\n\tdictWord{135, 11, 208},\n\tdictWord{6, 11, 79},\n\tdictWord{7, 11, 1021},\n\tdictWord{135, 11, 1519},\n\tdictWord{11, 11, 704},\n\tdictWord{141, 11, 396},\n\tdictWord{5, 10, 346},\n\tdictWord{5, 10, 711},\n\tdictWord{136, 10, 390},\n\tdictWord{136, 11, 741},\n\tdictWord{134, 11, 376},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1427,\n\t},\n\tdictWord{6, 0, 1033},\n\tdictWord{6, 0, 1217},\n\tdictWord{136, 0, 300},\n\tdictWord{133, 10, 624},\n\tdictWord{6, 11, 100},\n\tdictWord{7, 11, 244},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t632,\n\t},\n\tdictWord{7, 11, 1609},\n\tdictWord{8, 11, 178},\n\tdictWord{8, 11, 638},\n\tdictWord{141, 11, 58},\n\tdictWord{6, 0, 584},\n\tdictWord{5, 10, 783},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1998,\n\t},\n\tdictWord{135, 10, 2047},\n\tdictWord{5, 0, 427},\n\tdictWord{5, 0, 734},\n\tdictWord{7, 0, 478},\n\tdictWord{136, 0, 52},\n\tdictWord{7, 0, 239},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t217,\n\t},\n\tdictWord{142, 0, 165},\n\tdictWord{134, 0, 1129},\n\tdictWord{6, 0, 168},\n\tdictWord{6, 0, 1734},\n\tdictWord{7, 0, 20},\n\tdictWord{7, 0, 1056},\n\tdictWord{8, 0, 732},\n\tdictWord{9, 0, 406},\n\tdictWord{9, 0, 911},\n\tdictWord{138, 0, 694},\n\tdictWord{132, 10, 594},\n\tdictWord{133, 11, 791},\n\tdictWord{7, 11, 686},\n\tdictWord{8, 11, 33},\n\tdictWord{8, 11, 238},\n\tdictWord{10, 11, 616},\n\tdictWord{11, 11, 467},\n\tdictWord{11, 11, 881},\n\tdictWord{13, 11, 217},\n\tdictWord{13, 11, 253},\n\tdictWord{\n\t\t142,\n\t\t11,\n\t\t268,\n\t},\n\tdictWord{137, 11, 476},\n\tdictWord{134, 0, 418},\n\tdictWord{133, 0, 613},\n\tdictWord{132, 0, 632},\n\tdictWord{132, 11, 447},\n\tdictWord{7, 0, 32},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t984,\n\t},\n\tdictWord{8, 0, 85},\n\tdictWord{8, 0, 709},\n\tdictWord{9, 0, 579},\n\tdictWord{9, 0, 847},\n\tdictWord{9, 0, 856},\n\tdictWord{10, 0, 799},\n\tdictWord{11, 0, 258},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t1007,\n\t},\n\tdictWord{12, 0, 331},\n\tdictWord{12, 0, 615},\n\tdictWord{13, 0, 188},\n\tdictWord{13, 0, 435},\n\tdictWord{14, 0, 8},\n\tdictWord{15, 0, 165},\n\tdictWord{\n\t\t16,\n\t\t0,\n\t\t27,\n\t},\n\tdictWord{20, 0, 40},\n\tdictWord{144, 11, 35},\n\tdictWord{4, 11, 128},\n\tdictWord{5, 11, 415},\n\tdictWord{6, 11, 462},\n\tdictWord{7, 11, 294},\n\tdictWord{7, 11, 578},\n\tdictWord{10, 11, 710},\n\tdictWord{139, 11, 86},\n\tdictWord{5, 0, 694},\n\tdictWord{136, 0, 909},\n\tdictWord{7, 0, 1109},\n\tdictWord{11, 0, 7},\n\tdictWord{5, 10, 37},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t39,\n\t},\n\tdictWord{6, 10, 451},\n\tdictWord{7, 10, 218},\n\tdictWord{7, 10, 1166},\n\tdictWord{7, 10, 1687},\n\tdictWord{8, 10, 662},\n\tdictWord{144, 10, 2},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t587,\n\t},\n\tdictWord{6, 11, 427},\n\tdictWord{7, 11, 1018},\n\tdictWord{138, 11, 692},\n\tdictWord{4, 11, 195},\n\tdictWord{6, 10, 508},\n\tdictWord{135, 11, 802},\n\tdictWord{4, 0, 167},\n\tdictWord{135, 0, 82},\n\tdictWord{5, 0, 62},\n\tdictWord{6, 0, 24},\n\tdictWord{6, 0, 534},\n\tdictWord{7, 0, 74},\n\tdictWord{7, 0, 678},\n\tdictWord{7, 0, 684},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1043,\n\t},\n\tdictWord{7, 0, 1072},\n\tdictWord{8, 0, 280},\n\tdictWord{8, 0, 541},\n\tdictWord{8, 0, 686},\n\tdictWord{9, 0, 258},\n\tdictWord{10, 0, 519},\n\tdictWord{11, 0, 252},\n\tdictWord{140, 0, 282},\n\tdictWord{138, 0, 33},\n\tdictWord{4, 0, 359},\n\tdictWord{133, 11, 738},\n\tdictWord{7, 0, 980},\n\tdictWord{9, 0, 328},\n\tdictWord{13, 0, 186},\n\tdictWord{13, 0, 364},\n\tdictWord{7, 10, 635},\n\tdictWord{7, 10, 796},\n\tdictWord{8, 10, 331},\n\tdictWord{9, 10, 330},\n\tdictWord{9, 10, 865},\n\tdictWord{10, 10, 119},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t235,\n\t},\n\tdictWord{11, 10, 111},\n\tdictWord{11, 10, 129},\n\tdictWord{11, 10, 240},\n\tdictWord{12, 10, 31},\n\tdictWord{12, 10, 66},\n\tdictWord{12, 10, 222},\n\tdictWord{12, 10, 269},\n\tdictWord{12, 10, 599},\n\tdictWord{12, 10, 684},\n\tdictWord{12, 10, 689},\n\tdictWord{12, 10, 691},\n\tdictWord{142, 10, 345},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t527,\n\t},\n\tdictWord{6, 0, 596},\n\tdictWord{7, 0, 585},\n\tdictWord{135, 10, 702},\n\tdictWord{134, 11, 1683},\n\tdictWord{133, 0, 211},\n\tdictWord{6, 0, 145},\n\tdictWord{\n\t\t141,\n\t\t0,\n\t\t336,\n\t},\n\tdictWord{134, 0, 1130},\n\tdictWord{7, 0, 873},\n\tdictWord{6, 10, 37},\n\tdictWord{7, 10, 1666},\n\tdictWord{8, 10, 195},\n\tdictWord{8, 10, 316},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t178,\n\t},\n\tdictWord{9, 10, 276},\n\tdictWord{9, 10, 339},\n\tdictWord{9, 10, 536},\n\tdictWord{10, 10, 102},\n\tdictWord{10, 10, 362},\n\tdictWord{10, 10, 785},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t55,\n\t},\n\tdictWord{11, 10, 149},\n\tdictWord{11, 10, 773},\n\tdictWord{13, 10, 416},\n\tdictWord{13, 10, 419},\n\tdictWord{14, 10, 38},\n\tdictWord{14, 10, 41},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t210,\n\t},\n\tdictWord{8, 0, 840},\n\tdictWord{136, 0, 841},\n\tdictWord{132, 0, 263},\n\tdictWord{5, 11, 3},\n\tdictWord{8, 11, 578},\n\tdictWord{9, 11, 118},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t705,\n\t},\n\tdictWord{12, 11, 383},\n\tdictWord{141, 11, 279},\n\tdictWord{132, 0, 916},\n\tdictWord{133, 11, 229},\n\tdictWord{133, 10, 645},\n\tdictWord{15, 0, 155},\n\tdictWord{16, 0, 79},\n\tdictWord{8, 11, 102},\n\tdictWord{10, 11, 578},\n\tdictWord{10, 11, 672},\n\tdictWord{12, 11, 496},\n\tdictWord{13, 11, 408},\n\tdictWord{14, 11, 121},\n\tdictWord{145, 11, 106},\n\tdictWord{4, 0, 599},\n\tdictWord{5, 0, 592},\n\tdictWord{6, 0, 1634},\n\tdictWord{7, 0, 5},\n\tdictWord{7, 0, 55},\n\tdictWord{7, 0, 67},\n\tdictWord{7, 0, 97},\n\tdictWord{7, 0, 691},\n\tdictWord{7, 0, 979},\n\tdictWord{7, 0, 1600},\n\tdictWord{7, 0, 1697},\n\tdictWord{8, 0, 207},\n\tdictWord{8, 0, 214},\n\tdictWord{8, 0, 231},\n\tdictWord{8, 0, 294},\n\tdictWord{8, 0, 336},\n\tdictWord{8, 0, 428},\n\tdictWord{8, 0, 471},\n\tdictWord{8, 0, 622},\n\tdictWord{8, 0, 626},\n\tdictWord{8, 0, 679},\n\tdictWord{8, 0, 759},\n\tdictWord{8, 0, 829},\n\tdictWord{9, 0, 11},\n\tdictWord{9, 0, 246},\n\tdictWord{9, 0, 484},\n\tdictWord{9, 0, 573},\n\tdictWord{9, 0, 706},\n\tdictWord{9, 0, 762},\n\tdictWord{9, 0, 798},\n\tdictWord{9, 0, 855},\n\tdictWord{9, 0, 870},\n\tdictWord{9, 0, 912},\n\tdictWord{10, 0, 303},\n\tdictWord{10, 0, 335},\n\tdictWord{10, 0, 424},\n\tdictWord{10, 0, 461},\n\tdictWord{10, 0, 543},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t759,\n\t},\n\tdictWord{10, 0, 814},\n\tdictWord{11, 0, 59},\n\tdictWord{11, 0, 199},\n\tdictWord{11, 0, 235},\n\tdictWord{11, 0, 590},\n\tdictWord{11, 0, 631},\n\tdictWord{11, 0, 929},\n\tdictWord{11, 0, 963},\n\tdictWord{11, 0, 987},\n\tdictWord{12, 0, 114},\n\tdictWord{12, 0, 182},\n\tdictWord{12, 0, 226},\n\tdictWord{12, 0, 332},\n\tdictWord{12, 0, 439},\n\tdictWord{12, 0, 575},\n\tdictWord{12, 0, 598},\n\tdictWord{12, 0, 675},\n\tdictWord{13, 0, 8},\n\tdictWord{13, 0, 125},\n\tdictWord{13, 0, 194},\n\tdictWord{13, 0, 287},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t197,\n\t},\n\tdictWord{14, 0, 383},\n\tdictWord{15, 0, 53},\n\tdictWord{17, 0, 63},\n\tdictWord{19, 0, 46},\n\tdictWord{19, 0, 98},\n\tdictWord{19, 0, 106},\n\tdictWord{148, 0, 85},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1356,\n\t},\n\tdictWord{132, 10, 290},\n\tdictWord{6, 10, 70},\n\tdictWord{7, 10, 1292},\n\tdictWord{10, 10, 762},\n\tdictWord{139, 10, 288},\n\tdictWord{150, 11, 55},\n\tdictWord{4, 0, 593},\n\tdictWord{8, 11, 115},\n\tdictWord{8, 11, 350},\n\tdictWord{9, 11, 489},\n\tdictWord{10, 11, 128},\n\tdictWord{11, 11, 306},\n\tdictWord{12, 11, 373},\n\tdictWord{14, 11, 30},\n\tdictWord{17, 11, 79},\n\tdictWord{147, 11, 80},\n\tdictWord{135, 11, 1235},\n\tdictWord{134, 0, 1392},\n\tdictWord{4, 11, 230},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t702,\n\t},\n\tdictWord{147, 0, 126},\n\tdictWord{7, 10, 131},\n\tdictWord{7, 10, 422},\n\tdictWord{8, 10, 210},\n\tdictWord{140, 10, 573},\n\tdictWord{134, 0, 1179},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t435,\n\t},\n\tdictWord{139, 10, 797},\n\tdictWord{134, 11, 1728},\n\tdictWord{4, 0, 162},\n\tdictWord{18, 11, 26},\n\tdictWord{19, 11, 42},\n\tdictWord{20, 11, 43},\n\tdictWord{21, 11, 0},\n\tdictWord{23, 11, 27},\n\tdictWord{152, 11, 14},\n\tdictWord{132, 10, 936},\n\tdictWord{6, 0, 765},\n\tdictWord{5, 10, 453},\n\tdictWord{134, 10, 441},\n\tdictWord{133, 0, 187},\n\tdictWord{135, 0, 1286},\n\tdictWord{6, 0, 635},\n\tdictWord{6, 0, 904},\n\tdictWord{6, 0, 1210},\n\tdictWord{134, 0, 1489},\n\tdictWord{4, 0, 215},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t890,\n\t},\n\tdictWord{9, 0, 38},\n\tdictWord{10, 0, 923},\n\tdictWord{11, 0, 23},\n\tdictWord{11, 0, 127},\n\tdictWord{139, 0, 796},\n\tdictWord{6, 0, 1165},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1306,\n\t},\n\tdictWord{7, 0, 716},\n\tdictWord{13, 0, 97},\n\tdictWord{141, 0, 251},\n\tdictWord{132, 10, 653},\n\tdictWord{136, 0, 657},\n\tdictWord{146, 10, 80},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t622,\n\t},\n\tdictWord{7, 11, 1032},\n\tdictWord{11, 11, 26},\n\tdictWord{11, 11, 213},\n\tdictWord{11, 11, 707},\n\tdictWord{12, 11, 380},\n\tdictWord{13, 11, 226},\n\tdictWord{141, 11, 355},\n\tdictWord{6, 0, 299},\n\tdictWord{5, 11, 70},\n\tdictWord{6, 11, 334},\n\tdictWord{9, 11, 171},\n\tdictWord{11, 11, 637},\n\tdictWord{12, 11, 202},\n\tdictWord{14, 11, 222},\n\tdictWord{145, 11, 42},\n\tdictWord{142, 0, 134},\n\tdictWord{4, 11, 23},\n\tdictWord{5, 11, 313},\n\tdictWord{5, 11, 1014},\n\tdictWord{6, 11, 50},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t51,\n\t},\n\tdictWord{7, 11, 142},\n\tdictWord{7, 11, 384},\n\tdictWord{9, 11, 783},\n\tdictWord{139, 11, 741},\n\tdictWord{4, 11, 141},\n\tdictWord{7, 11, 559},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t640,\n\t},\n\tdictWord{9, 11, 460},\n\tdictWord{12, 11, 183},\n\tdictWord{141, 11, 488},\n\tdictWord{136, 11, 614},\n\tdictWord{7, 10, 1368},\n\tdictWord{8, 10, 232},\n\tdictWord{8, 10, 361},\n\tdictWord{10, 10, 682},\n\tdictWord{138, 10, 742},\n\tdictWord{137, 10, 534},\n\tdictWord{6, 0, 1082},\n\tdictWord{140, 0, 658},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t27,\n\t},\n\tdictWord{135, 0, 2002},\n\tdictWord{142, 10, 12},\n\tdictWord{4, 0, 28},\n\tdictWord{5, 0, 440},\n\tdictWord{7, 0, 248},\n\tdictWord{11, 0, 833},\n\tdictWord{140, 0, 344},\n\tdictWord{7, 10, 736},\n\tdictWord{139, 10, 264},\n\tdictWord{134, 10, 1657},\n\tdictWord{134, 0, 1654},\n\tdictWord{138, 0, 531},\n\tdictWord{5, 11, 222},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t140,\n\t},\n\tdictWord{138, 11, 534},\n\tdictWord{6, 0, 634},\n\tdictWord{6, 0, 798},\n\tdictWord{134, 0, 840},\n\tdictWord{138, 11, 503},\n\tdictWord{135, 10, 127},\n\tdictWord{133, 0, 853},\n\tdictWord{5, 11, 154},\n\tdictWord{7, 11, 1491},\n\tdictWord{10, 11, 379},\n\tdictWord{138, 11, 485},\n\tdictWord{6, 0, 249},\n\tdictWord{7, 0, 1234},\n\tdictWord{139, 0, 573},\n\tdictWord{133, 11, 716},\n\tdictWord{7, 11, 1570},\n\tdictWord{140, 11, 542},\n\tdictWord{136, 10, 364},\n\tdictWord{138, 0, 527},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t91,\n\t},\n\tdictWord{5, 11, 388},\n\tdictWord{5, 11, 845},\n\tdictWord{6, 11, 206},\n\tdictWord{6, 11, 252},\n\tdictWord{6, 11, 365},\n\tdictWord{7, 11, 136},\n\tdictWord{7, 11, 531},\n\tdictWord{8, 11, 264},\n\tdictWord{136, 11, 621},\n\tdictWord{134, 0, 1419},\n\tdictWord{135, 11, 1441},\n\tdictWord{7, 0, 49},\n\tdictWord{7, 0, 392},\n\tdictWord{8, 0, 20},\n\tdictWord{8, 0, 172},\n\tdictWord{8, 0, 690},\n\tdictWord{9, 0, 383},\n\tdictWord{9, 0, 845},\n\tdictWord{10, 0, 48},\n\tdictWord{11, 0, 293},\n\tdictWord{11, 0, 832},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t920,\n\t},\n\tdictWord{11, 0, 984},\n\tdictWord{141, 0, 221},\n\tdictWord{5, 0, 858},\n\tdictWord{133, 0, 992},\n\tdictWord{5, 0, 728},\n\tdictWord{137, 10, 792},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t909,\n\t},\n\tdictWord{9, 10, 849},\n\tdictWord{138, 10, 805},\n\tdictWord{7, 0, 525},\n\tdictWord{7, 0, 1579},\n\tdictWord{8, 0, 497},\n\tdictWord{136, 0, 573},\n\tdictWord{6, 0, 268},\n\tdictWord{137, 0, 62},\n\tdictWord{135, 11, 576},\n\tdictWord{134, 0, 1201},\n\tdictWord{5, 11, 771},\n\tdictWord{5, 11, 863},\n\tdictWord{5, 11, 898},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t1632,\n\t},\n\tdictWord{6, 11, 1644},\n\tdictWord{134, 11, 1780},\n\tdictWord{133, 11, 331},\n\tdictWord{7, 0, 193},\n\tdictWord{7, 0, 1105},\n\tdictWord{10, 0, 495},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t397,\n\t},\n\tdictWord{8, 10, 124},\n\tdictWord{8, 10, 619},\n\tdictWord{9, 10, 305},\n\tdictWord{11, 10, 40},\n\tdictWord{12, 10, 349},\n\tdictWord{13, 10, 134},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t295,\n\t},\n\tdictWord{14, 10, 155},\n\tdictWord{15, 10, 120},\n\tdictWord{146, 10, 105},\n\tdictWord{138, 0, 106},\n\tdictWord{6, 0, 859},\n\tdictWord{5, 11, 107},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t201,\n\t},\n\tdictWord{136, 11, 518},\n\tdictWord{6, 11, 446},\n\tdictWord{135, 11, 1817},\n\tdictWord{13, 0, 23},\n\tdictWord{4, 10, 262},\n\tdictWord{135, 10, 342},\n\tdictWord{133, 10, 641},\n\tdictWord{137, 11, 851},\n\tdictWord{6, 0, 925},\n\tdictWord{137, 0, 813},\n\tdictWord{132, 11, 504},\n\tdictWord{6, 0, 613},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t223,\n\t},\n\tdictWord{4, 10, 99},\n\tdictWord{6, 10, 250},\n\tdictWord{6, 10, 346},\n\tdictWord{8, 10, 127},\n\tdictWord{138, 10, 81},\n\tdictWord{136, 0, 953},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t915,\n\t},\n\tdictWord{139, 11, 892},\n\tdictWord{5, 10, 75},\n\tdictWord{9, 10, 517},\n\tdictWord{10, 10, 470},\n\tdictWord{12, 10, 155},\n\tdictWord{141, 10, 224},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t666,\n\t},\n\tdictWord{7, 0, 1017},\n\tdictWord{7, 11, 996},\n\tdictWord{138, 11, 390},\n\tdictWord{5, 11, 883},\n\tdictWord{133, 11, 975},\n\tdictWord{14, 10, 83},\n\tdictWord{\n\t\t142,\n\t\t11,\n\t\t83,\n\t},\n\tdictWord{4, 0, 670},\n\tdictWord{5, 11, 922},\n\tdictWord{134, 11, 1707},\n\tdictWord{135, 0, 216},\n\tdictWord{9, 0, 40},\n\tdictWord{11, 0, 136},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t787,\n\t},\n\tdictWord{5, 10, 954},\n\tdictWord{5, 11, 993},\n\tdictWord{7, 11, 515},\n\tdictWord{137, 11, 91},\n\tdictWord{139, 0, 259},\n\tdictWord{7, 0, 1114},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t310,\n\t},\n\tdictWord{9, 0, 682},\n\tdictWord{10, 0, 440},\n\tdictWord{13, 0, 40},\n\tdictWord{6, 10, 304},\n\tdictWord{8, 10, 418},\n\tdictWord{11, 10, 341},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t675,\n\t},\n\tdictWord{14, 0, 296},\n\tdictWord{9, 10, 410},\n\tdictWord{139, 10, 425},\n\tdictWord{10, 11, 377},\n\tdictWord{12, 11, 363},\n\tdictWord{13, 11, 68},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t94,\n\t},\n\tdictWord{14, 11, 108},\n\tdictWord{142, 11, 306},\n\tdictWord{7, 0, 1401},\n\tdictWord{135, 0, 1476},\n\tdictWord{4, 0, 296},\n\tdictWord{6, 0, 475},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t401,\n\t},\n\tdictWord{7, 0, 1410},\n\tdictWord{7, 0, 1594},\n\tdictWord{7, 0, 1674},\n\tdictWord{8, 0, 63},\n\tdictWord{8, 0, 660},\n\tdictWord{137, 0, 74},\n\tdictWord{4, 0, 139},\n\tdictWord{4, 0, 388},\n\tdictWord{140, 0, 188},\n\tdictWord{132, 0, 797},\n\tdictWord{132, 11, 766},\n\tdictWord{5, 11, 103},\n\tdictWord{7, 11, 921},\n\tdictWord{8, 11, 580},\n\tdictWord{8, 11, 593},\n\tdictWord{8, 11, 630},\n\tdictWord{138, 11, 28},\n\tdictWord{4, 11, 911},\n\tdictWord{5, 11, 867},\n\tdictWord{133, 11, 1013},\n\tdictWord{134, 10, 14},\n\tdictWord{134, 0, 1572},\n\tdictWord{134, 10, 1708},\n\tdictWord{21, 0, 39},\n\tdictWord{5, 10, 113},\n\tdictWord{6, 10, 243},\n\tdictWord{7, 10, 1865},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t161,\n\t},\n\tdictWord{16, 10, 37},\n\tdictWord{145, 10, 99},\n\tdictWord{7, 11, 1563},\n\tdictWord{141, 11, 182},\n\tdictWord{5, 11, 135},\n\tdictWord{6, 11, 519},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1722,\n\t},\n\tdictWord{10, 11, 271},\n\tdictWord{11, 11, 261},\n\tdictWord{145, 11, 54},\n\tdictWord{132, 10, 274},\n\tdictWord{134, 0, 1594},\n\tdictWord{4, 11, 300},\n\tdictWord{5, 11, 436},\n\tdictWord{135, 11, 484},\n\tdictWord{4, 0, 747},\n\tdictWord{6, 0, 290},\n\tdictWord{7, 0, 649},\n\tdictWord{7, 0, 1479},\n\tdictWord{135, 0, 1583},\n\tdictWord{133, 11, 535},\n\tdictWord{147, 11, 82},\n\tdictWord{133, 0, 232},\n\tdictWord{137, 0, 887},\n\tdictWord{135, 10, 166},\n\tdictWord{136, 0, 521},\n\tdictWord{4, 0, 14},\n\tdictWord{7, 0, 472},\n\tdictWord{7, 0, 1801},\n\tdictWord{10, 0, 748},\n\tdictWord{141, 0, 458},\n\tdictWord{134, 0, 741},\n\tdictWord{134, 0, 992},\n\tdictWord{16, 0, 111},\n\tdictWord{137, 10, 304},\n\tdictWord{4, 0, 425},\n\tdictWord{5, 11, 387},\n\tdictWord{7, 11, 557},\n\tdictWord{12, 11, 547},\n\tdictWord{142, 11, 86},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1747,\n\t},\n\tdictWord{5, 10, 654},\n\tdictWord{135, 11, 1489},\n\tdictWord{7, 0, 789},\n\tdictWord{4, 11, 6},\n\tdictWord{5, 11, 708},\n\tdictWord{136, 11, 75},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t273,\n\t},\n\tdictWord{10, 10, 188},\n\tdictWord{13, 10, 377},\n\tdictWord{146, 10, 77},\n\tdictWord{6, 0, 1593},\n\tdictWord{4, 11, 303},\n\tdictWord{7, 11, 619},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t547,\n\t},\n\tdictWord{10, 11, 687},\n\tdictWord{11, 11, 122},\n\tdictWord{140, 11, 601},\n\tdictWord{134, 0, 1768},\n\tdictWord{135, 10, 410},\n\tdictWord{138, 11, 772},\n\tdictWord{11, 0, 233},\n\tdictWord{139, 10, 524},\n\tdictWord{5, 0, 943},\n\tdictWord{134, 0, 1779},\n\tdictWord{134, 10, 1785},\n\tdictWord{136, 11, 529},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t955,\n\t},\n\tdictWord{5, 0, 245},\n\tdictWord{6, 0, 576},\n\tdictWord{7, 0, 582},\n\tdictWord{136, 0, 225},\n\tdictWord{132, 10, 780},\n\tdictWord{142, 0, 241},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1943,\n\t},\n\tdictWord{4, 11, 106},\n\tdictWord{7, 11, 310},\n\tdictWord{7, 11, 1785},\n\tdictWord{10, 11, 690},\n\tdictWord{139, 11, 717},\n\tdictWord{134, 0, 1284},\n\tdictWord{5, 11, 890},\n\tdictWord{133, 11, 988},\n\tdictWord{6, 11, 626},\n\tdictWord{142, 11, 431},\n\tdictWord{10, 11, 706},\n\tdictWord{145, 11, 32},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t332,\n\t},\n\tdictWord{132, 11, 698},\n\tdictWord{135, 0, 709},\n\tdictWord{5, 10, 948},\n\tdictWord{138, 11, 17},\n\tdictWord{136, 0, 554},\n\tdictWord{134, 0, 1564},\n\tdictWord{139, 10, 941},\n\tdictWord{132, 0, 443},\n\tdictWord{134, 0, 909},\n\tdictWord{134, 11, 84},\n\tdictWord{142, 0, 280},\n\tdictWord{4, 10, 532},\n\tdictWord{5, 10, 706},\n\tdictWord{135, 10, 662},\n\tdictWord{132, 0, 729},\n\tdictWord{5, 10, 837},\n\tdictWord{6, 10, 1651},\n\tdictWord{139, 10, 985},\n\tdictWord{135, 10, 1861},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t348,\n\t},\n\tdictWord{152, 11, 3},\n\tdictWord{5, 11, 986},\n\tdictWord{6, 11, 130},\n\tdictWord{7, 11, 1582},\n\tdictWord{8, 11, 458},\n\tdictWord{10, 11, 101},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t318,\n\t},\n\tdictWord{138, 11, 823},\n\tdictWord{134, 0, 758},\n\tdictWord{4, 0, 298},\n\tdictWord{137, 0, 848},\n\tdictWord{4, 10, 330},\n\tdictWord{7, 10, 933},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t2012,\n\t},\n\tdictWord{136, 10, 292},\n\tdictWord{7, 11, 1644},\n\tdictWord{137, 11, 129},\n\tdictWord{6, 0, 1422},\n\tdictWord{9, 0, 829},\n\tdictWord{135, 10, 767},\n\tdictWord{5, 0, 164},\n\tdictWord{7, 0, 121},\n\tdictWord{142, 0, 189},\n\tdictWord{7, 0, 812},\n\tdictWord{7, 0, 1261},\n\tdictWord{7, 0, 1360},\n\tdictWord{9, 0, 632},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t352,\n\t},\n\tdictWord{135, 11, 1788},\n\tdictWord{139, 0, 556},\n\tdictWord{135, 11, 997},\n\tdictWord{145, 10, 114},\n\tdictWord{4, 0, 172},\n\tdictWord{9, 0, 611},\n\tdictWord{10, 0, 436},\n\tdictWord{12, 0, 673},\n\tdictWord{13, 0, 255},\n\tdictWord{137, 10, 883},\n\tdictWord{11, 0, 530},\n\tdictWord{138, 10, 274},\n\tdictWord{133, 0, 844},\n\tdictWord{134, 0, 984},\n\tdictWord{13, 0, 232},\n\tdictWord{18, 0, 35},\n\tdictWord{4, 10, 703},\n\tdictWord{135, 10, 207},\n\tdictWord{132, 10, 571},\n\tdictWord{9, 0, 263},\n\tdictWord{10, 0, 147},\n\tdictWord{138, 0, 492},\n\tdictWord{7, 11, 1756},\n\tdictWord{137, 11, 98},\n\tdictWord{5, 10, 873},\n\tdictWord{5, 10, 960},\n\tdictWord{8, 10, 823},\n\tdictWord{137, 10, 881},\n\tdictWord{133, 0, 537},\n\tdictWord{132, 0, 859},\n\tdictWord{7, 11, 1046},\n\tdictWord{139, 11, 160},\n\tdictWord{137, 0, 842},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t283,\n\t},\n\tdictWord{5, 10, 33},\n\tdictWord{6, 10, 470},\n\tdictWord{139, 10, 424},\n\tdictWord{6, 11, 45},\n\tdictWord{7, 11, 433},\n\tdictWord{8, 11, 129},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t21,\n\t},\n\tdictWord{10, 11, 392},\n\tdictWord{11, 11, 79},\n\tdictWord{12, 11, 499},\n\tdictWord{13, 11, 199},\n\tdictWord{141, 11, 451},\n\tdictWord{135, 0, 1291},\n\tdictWord{135, 10, 1882},\n\tdictWord{7, 11, 558},\n\tdictWord{136, 11, 353},\n\tdictWord{134, 0, 1482},\n\tdictWord{5, 0, 230},\n\tdictWord{5, 0, 392},\n\tdictWord{6, 0, 420},\n\tdictWord{9, 0, 568},\n\tdictWord{140, 0, 612},\n\tdictWord{6, 0, 262},\n\tdictWord{7, 10, 90},\n\tdictWord{7, 10, 664},\n\tdictWord{7, 10, 830},\n\tdictWord{7, 10, 1380},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t2025,\n\t},\n\tdictWord{8, 11, 81},\n\tdictWord{8, 10, 448},\n\tdictWord{8, 10, 828},\n\tdictWord{9, 11, 189},\n\tdictWord{9, 11, 201},\n\tdictWord{11, 11, 478},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t712,\n\t},\n\tdictWord{141, 11, 338},\n\tdictWord{142, 0, 31},\n\tdictWord{5, 11, 353},\n\tdictWord{151, 11, 26},\n\tdictWord{132, 0, 753},\n\tdictWord{4, 0, 0},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t41,\n\t},\n\tdictWord{7, 0, 1459},\n\tdictWord{7, 0, 1469},\n\tdictWord{7, 0, 1859},\n\tdictWord{9, 0, 549},\n\tdictWord{139, 0, 905},\n\tdictWord{9, 10, 417},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t493,\n\t},\n\tdictWord{135, 11, 1113},\n\tdictWord{133, 0, 696},\n\tdictWord{141, 11, 448},\n\tdictWord{134, 10, 295},\n\tdictWord{132, 0, 834},\n\tdictWord{4, 0, 771},\n\tdictWord{5, 10, 1019},\n\tdictWord{6, 11, 25},\n\tdictWord{7, 11, 855},\n\tdictWord{7, 11, 1258},\n\tdictWord{144, 11, 32},\n\tdictWord{134, 0, 1076},\n\tdictWord{133, 0, 921},\n\tdictWord{133, 0, 674},\n\tdictWord{4, 11, 4},\n\tdictWord{7, 11, 1118},\n\tdictWord{7, 11, 1320},\n\tdictWord{7, 11, 1706},\n\tdictWord{8, 11, 277},\n\tdictWord{9, 11, 622},\n\tdictWord{10, 11, 9},\n\tdictWord{11, 11, 724},\n\tdictWord{12, 11, 350},\n\tdictWord{12, 11, 397},\n\tdictWord{13, 11, 28},\n\tdictWord{13, 11, 159},\n\tdictWord{15, 11, 89},\n\tdictWord{18, 11, 5},\n\tdictWord{19, 11, 9},\n\tdictWord{20, 11, 34},\n\tdictWord{150, 11, 47},\n\tdictWord{134, 10, 208},\n\tdictWord{6, 0, 444},\n\tdictWord{136, 0, 308},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t180,\n\t},\n\tdictWord{7, 0, 1137},\n\tdictWord{8, 0, 751},\n\tdictWord{139, 0, 805},\n\tdictWord{4, 0, 183},\n\tdictWord{7, 0, 271},\n\tdictWord{11, 0, 824},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t952,\n\t},\n\tdictWord{13, 0, 278},\n\tdictWord{13, 0, 339},\n\tdictWord{13, 0, 482},\n\tdictWord{14, 0, 424},\n\tdictWord{148, 0, 99},\n\tdictWord{7, 11, 317},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t569,\n\t},\n\tdictWord{4, 0, 19},\n\tdictWord{5, 0, 477},\n\tdictWord{5, 0, 596},\n\tdictWord{6, 0, 505},\n\tdictWord{7, 0, 1221},\n\tdictWord{11, 0, 907},\n\tdictWord{12, 0, 209},\n\tdictWord{141, 0, 214},\n\tdictWord{135, 0, 1215},\n\tdictWord{6, 0, 271},\n\tdictWord{7, 0, 398},\n\tdictWord{8, 0, 387},\n\tdictWord{10, 0, 344},\n\tdictWord{7, 10, 448},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1629,\n\t},\n\tdictWord{7, 10, 1813},\n\tdictWord{8, 10, 442},\n\tdictWord{9, 10, 710},\n\tdictWord{10, 10, 282},\n\tdictWord{138, 10, 722},\n\tdictWord{11, 10, 844},\n\tdictWord{12, 10, 104},\n\tdictWord{140, 10, 625},\n\tdictWord{134, 11, 255},\n\tdictWord{133, 10, 787},\n\tdictWord{134, 0, 1645},\n\tdictWord{11, 11, 956},\n\tdictWord{\n\t\t151,\n\t\t11,\n\t\t3,\n\t},\n\tdictWord{6, 0, 92},\n\tdictWord{6, 0, 188},\n\tdictWord{7, 0, 209},\n\tdictWord{7, 0, 1269},\n\tdictWord{7, 0, 1524},\n\tdictWord{7, 0, 1876},\n\tdictWord{8, 0, 661},\n\tdictWord{10, 0, 42},\n\tdictWord{10, 0, 228},\n\tdictWord{11, 0, 58},\n\tdictWord{11, 0, 1020},\n\tdictWord{12, 0, 58},\n\tdictWord{12, 0, 118},\n\tdictWord{141, 0, 32},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t459,\n\t},\n\tdictWord{133, 0, 966},\n\tdictWord{4, 11, 536},\n\tdictWord{7, 11, 1141},\n\tdictWord{10, 11, 723},\n\tdictWord{139, 11, 371},\n\tdictWord{140, 0, 330},\n\tdictWord{134, 0, 1557},\n\tdictWord{7, 11, 285},\n\tdictWord{135, 11, 876},\n\tdictWord{136, 10, 491},\n\tdictWord{135, 11, 560},\n\tdictWord{6, 0, 18},\n\tdictWord{7, 0, 179},\n\tdictWord{7, 0, 932},\n\tdictWord{8, 0, 548},\n\tdictWord{8, 0, 757},\n\tdictWord{9, 0, 54},\n\tdictWord{9, 0, 65},\n\tdictWord{9, 0, 532},\n\tdictWord{9, 0, 844},\n\tdictWord{10, 0, 113},\n\tdictWord{10, 0, 117},\n\tdictWord{10, 0, 315},\n\tdictWord{10, 0, 560},\n\tdictWord{10, 0, 622},\n\tdictWord{10, 0, 798},\n\tdictWord{11, 0, 153},\n\tdictWord{11, 0, 351},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t375,\n\t},\n\tdictWord{12, 0, 78},\n\tdictWord{12, 0, 151},\n\tdictWord{12, 0, 392},\n\tdictWord{12, 0, 666},\n\tdictWord{14, 0, 248},\n\tdictWord{143, 0, 23},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1742,\n\t},\n\tdictWord{132, 11, 690},\n\tdictWord{4, 10, 403},\n\tdictWord{5, 10, 441},\n\tdictWord{7, 10, 450},\n\tdictWord{10, 10, 840},\n\tdictWord{11, 10, 101},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t193,\n\t},\n\tdictWord{141, 10, 430},\n\tdictWord{133, 0, 965},\n\tdictWord{134, 0, 182},\n\tdictWord{10, 0, 65},\n\tdictWord{10, 0, 488},\n\tdictWord{138, 0, 497},\n\tdictWord{135, 11, 1346},\n\tdictWord{6, 0, 973},\n\tdictWord{6, 0, 1158},\n\tdictWord{10, 11, 200},\n\tdictWord{19, 11, 2},\n\tdictWord{151, 11, 22},\n\tdictWord{4, 11, 190},\n\tdictWord{133, 11, 554},\n\tdictWord{133, 10, 679},\n\tdictWord{7, 0, 328},\n\tdictWord{137, 10, 326},\n\tdictWord{133, 11, 1001},\n\tdictWord{9, 0, 588},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t260,\n\t},\n\tdictWord{133, 11, 446},\n\tdictWord{135, 10, 1128},\n\tdictWord{135, 10, 1796},\n\tdictWord{147, 11, 119},\n\tdictWord{134, 0, 1786},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1328,\n\t},\n\tdictWord{6, 0, 1985},\n\tdictWord{8, 0, 962},\n\tdictWord{138, 0, 1017},\n\tdictWord{135, 0, 308},\n\tdictWord{11, 0, 508},\n\tdictWord{4, 10, 574},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t350,\n\t},\n\tdictWord{7, 10, 1024},\n\tdictWord{8, 10, 338},\n\tdictWord{9, 10, 677},\n\tdictWord{138, 10, 808},\n\tdictWord{138, 11, 752},\n\tdictWord{135, 10, 1081},\n\tdictWord{137, 11, 96},\n\tdictWord{7, 10, 1676},\n\tdictWord{135, 10, 2037},\n\tdictWord{136, 0, 588},\n\tdictWord{132, 11, 304},\n\tdictWord{133, 0, 614},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t793,\n\t},\n\tdictWord{136, 0, 287},\n\tdictWord{137, 10, 297},\n\tdictWord{141, 10, 37},\n\tdictWord{6, 11, 53},\n\tdictWord{6, 11, 199},\n\tdictWord{7, 11, 1408},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t32,\n\t},\n\tdictWord{8, 11, 93},\n\tdictWord{9, 11, 437},\n\tdictWord{10, 11, 397},\n\tdictWord{10, 11, 629},\n\tdictWord{11, 11, 593},\n\tdictWord{11, 11, 763},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t326,\n\t},\n\tdictWord{145, 11, 35},\n\tdictWord{134, 11, 105},\n\tdictWord{9, 11, 320},\n\tdictWord{10, 11, 506},\n\tdictWord{138, 11, 794},\n\tdictWord{5, 11, 114},\n\tdictWord{5, 11, 255},\n\tdictWord{141, 11, 285},\n\tdictWord{140, 0, 290},\n\tdictWord{7, 11, 2035},\n\tdictWord{8, 11, 19},\n\tdictWord{9, 11, 89},\n\tdictWord{138, 11, 831},\n\tdictWord{134, 0, 1136},\n\tdictWord{7, 0, 719},\n\tdictWord{8, 0, 796},\n\tdictWord{8, 0, 809},\n\tdictWord{8, 0, 834},\n\tdictWord{6, 10, 306},\n\tdictWord{7, 10, 1140},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1340,\n\t},\n\tdictWord{8, 10, 133},\n\tdictWord{138, 10, 449},\n\tdictWord{139, 10, 1011},\n\tdictWord{5, 0, 210},\n\tdictWord{6, 0, 213},\n\tdictWord{7, 0, 60},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t364,\n\t},\n\tdictWord{139, 0, 135},\n\tdictWord{5, 0, 607},\n\tdictWord{8, 0, 326},\n\tdictWord{136, 0, 490},\n\tdictWord{138, 11, 176},\n\tdictWord{132, 0, 701},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t472,\n\t},\n\tdictWord{7, 0, 380},\n\tdictWord{137, 0, 758},\n\tdictWord{135, 0, 1947},\n\tdictWord{6, 0, 1079},\n\tdictWord{138, 0, 278},\n\tdictWord{138, 11, 391},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t329,\n\t},\n\tdictWord{8, 10, 260},\n\tdictWord{139, 11, 156},\n\tdictWord{4, 0, 386},\n\tdictWord{7, 0, 41},\n\tdictWord{8, 0, 405},\n\tdictWord{8, 0, 728},\n\tdictWord{9, 0, 497},\n\tdictWord{11, 0, 110},\n\tdictWord{11, 0, 360},\n\tdictWord{15, 0, 37},\n\tdictWord{144, 0, 84},\n\tdictWord{5, 0, 46},\n\tdictWord{7, 0, 1452},\n\tdictWord{7, 0, 1480},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t634,\n\t},\n\tdictWord{140, 0, 472},\n\tdictWord{136, 0, 961},\n\tdictWord{4, 0, 524},\n\tdictWord{136, 0, 810},\n\tdictWord{10, 0, 238},\n\tdictWord{141, 0, 33},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t657,\n\t},\n\tdictWord{152, 10, 7},\n\tdictWord{133, 0, 532},\n\tdictWord{5, 0, 997},\n\tdictWord{135, 10, 1665},\n\tdictWord{7, 11, 594},\n\tdictWord{7, 11, 851},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1858,\n\t},\n\tdictWord{9, 11, 411},\n\tdictWord{9, 11, 574},\n\tdictWord{9, 11, 666},\n\tdictWord{9, 11, 737},\n\tdictWord{10, 11, 346},\n\tdictWord{10, 11, 712},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t246,\n\t},\n\tdictWord{11, 11, 432},\n\tdictWord{11, 11, 517},\n\tdictWord{11, 11, 647},\n\tdictWord{11, 11, 679},\n\tdictWord{11, 11, 727},\n\tdictWord{12, 11, 304},\n\tdictWord{12, 11, 305},\n\tdictWord{12, 11, 323},\n\tdictWord{12, 11, 483},\n\tdictWord{12, 11, 572},\n\tdictWord{12, 11, 593},\n\tdictWord{12, 11, 602},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t95,\n\t},\n\tdictWord{13, 11, 101},\n\tdictWord{13, 11, 171},\n\tdictWord{13, 11, 315},\n\tdictWord{13, 11, 378},\n\tdictWord{13, 11, 425},\n\tdictWord{13, 11, 475},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t63,\n\t},\n\tdictWord{14, 11, 380},\n\tdictWord{14, 11, 384},\n\tdictWord{15, 11, 133},\n\tdictWord{18, 11, 112},\n\tdictWord{148, 11, 72},\n\tdictWord{5, 11, 955},\n\tdictWord{136, 11, 814},\n\tdictWord{134, 0, 1301},\n\tdictWord{5, 10, 66},\n\tdictWord{7, 10, 1896},\n\tdictWord{136, 10, 288},\n\tdictWord{133, 11, 56},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1643,\n\t},\n\tdictWord{6, 0, 1298},\n\tdictWord{148, 11, 100},\n\tdictWord{5, 0, 782},\n\tdictWord{5, 0, 829},\n\tdictWord{6, 0, 671},\n\tdictWord{6, 0, 1156},\n\tdictWord{6, 0, 1738},\n\tdictWord{137, 11, 621},\n\tdictWord{4, 0, 306},\n\tdictWord{5, 0, 570},\n\tdictWord{7, 0, 1347},\n\tdictWord{5, 10, 91},\n\tdictWord{5, 10, 648},\n\tdictWord{5, 10, 750},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t781,\n\t},\n\tdictWord{6, 10, 54},\n\tdictWord{6, 10, 112},\n\tdictWord{6, 10, 402},\n\tdictWord{6, 10, 1732},\n\tdictWord{7, 10, 315},\n\tdictWord{7, 10, 749},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1900,\n\t},\n\tdictWord{9, 10, 78},\n\tdictWord{9, 10, 508},\n\tdictWord{10, 10, 611},\n\tdictWord{10, 10, 811},\n\tdictWord{11, 10, 510},\n\tdictWord{11, 10, 728},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t36,\n\t},\n\tdictWord{14, 10, 39},\n\tdictWord{16, 10, 83},\n\tdictWord{17, 10, 124},\n\tdictWord{148, 10, 30},\n\tdictWord{8, 10, 570},\n\tdictWord{9, 11, 477},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t78,\n\t},\n\tdictWord{4, 11, 639},\n\tdictWord{10, 11, 4},\n\tdictWord{10, 10, 322},\n\tdictWord{10, 10, 719},\n\tdictWord{11, 10, 407},\n\tdictWord{11, 11, 638},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t177,\n\t},\n\tdictWord{148, 11, 57},\n\tdictWord{7, 0, 1823},\n\tdictWord{139, 0, 693},\n\tdictWord{7, 0, 759},\n\tdictWord{5, 11, 758},\n\tdictWord{8, 10, 125},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t369,\n\t},\n\tdictWord{8, 10, 524},\n\tdictWord{10, 10, 486},\n\tdictWord{11, 10, 13},\n\tdictWord{11, 10, 381},\n\tdictWord{11, 10, 736},\n\tdictWord{11, 10, 766},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t845,\n\t},\n\tdictWord{13, 10, 114},\n\tdictWord{13, 10, 292},\n\tdictWord{142, 10, 47},\n\tdictWord{7, 0, 1932},\n\tdictWord{6, 10, 1684},\n\tdictWord{6, 10, 1731},\n\tdictWord{7, 10, 356},\n\tdictWord{8, 10, 54},\n\tdictWord{8, 10, 221},\n\tdictWord{9, 10, 225},\n\tdictWord{9, 10, 356},\n\tdictWord{10, 10, 77},\n\tdictWord{10, 10, 446},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t731,\n\t},\n\tdictWord{12, 10, 404},\n\tdictWord{141, 10, 491},\n\tdictWord{135, 11, 552},\n\tdictWord{135, 11, 1112},\n\tdictWord{4, 0, 78},\n\tdictWord{5, 0, 96},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t182,\n\t},\n\tdictWord{6, 0, 1257},\n\tdictWord{7, 0, 1724},\n\tdictWord{7, 0, 1825},\n\tdictWord{10, 0, 394},\n\tdictWord{10, 0, 471},\n\tdictWord{11, 0, 532},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t340,\n\t},\n\tdictWord{145, 0, 88},\n\tdictWord{139, 11, 328},\n\tdictWord{135, 0, 1964},\n\tdictWord{132, 10, 411},\n\tdictWord{4, 10, 80},\n\tdictWord{5, 10, 44},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t133,\n\t},\n\tdictWord{5, 11, 110},\n\tdictWord{6, 11, 169},\n\tdictWord{6, 11, 1702},\n\tdictWord{7, 11, 400},\n\tdictWord{8, 11, 538},\n\tdictWord{9, 11, 184},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t524,\n\t},\n\tdictWord{140, 11, 218},\n\tdictWord{4, 0, 521},\n\tdictWord{5, 10, 299},\n\tdictWord{7, 10, 1083},\n\tdictWord{140, 11, 554},\n\tdictWord{6, 11, 133},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t353,\n\t},\n\tdictWord{12, 11, 628},\n\tdictWord{146, 11, 79},\n\tdictWord{6, 0, 215},\n\tdictWord{7, 0, 584},\n\tdictWord{7, 0, 1028},\n\tdictWord{7, 0, 1473},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1721,\n\t},\n\tdictWord{9, 0, 424},\n\tdictWord{138, 0, 779},\n\tdictWord{7, 0, 857},\n\tdictWord{7, 0, 1209},\n\tdictWord{7, 10, 1713},\n\tdictWord{9, 10, 537},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t165,\n\t},\n\tdictWord{12, 10, 219},\n\tdictWord{140, 10, 561},\n\tdictWord{4, 10, 219},\n\tdictWord{6, 11, 93},\n\tdictWord{7, 11, 1422},\n\tdictWord{7, 10, 1761},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1851,\n\t},\n\tdictWord{8, 11, 673},\n\tdictWord{9, 10, 86},\n\tdictWord{9, 11, 529},\n\tdictWord{140, 11, 43},\n\tdictWord{137, 11, 371},\n\tdictWord{136, 0, 671},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t328,\n\t},\n\tdictWord{135, 0, 918},\n\tdictWord{132, 0, 529},\n\tdictWord{9, 11, 25},\n\tdictWord{10, 11, 467},\n\tdictWord{138, 11, 559},\n\tdictWord{4, 11, 335},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t942,\n\t},\n\tdictWord{134, 0, 716},\n\tdictWord{134, 0, 1509},\n\tdictWord{6, 0, 67},\n\tdictWord{7, 0, 258},\n\tdictWord{7, 0, 1630},\n\tdictWord{9, 0, 354},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t675,\n\t},\n\tdictWord{10, 0, 830},\n\tdictWord{14, 0, 80},\n\tdictWord{17, 0, 80},\n\tdictWord{140, 10, 428},\n\tdictWord{134, 0, 1112},\n\tdictWord{6, 0, 141},\n\tdictWord{7, 0, 225},\n\tdictWord{9, 0, 59},\n\tdictWord{9, 0, 607},\n\tdictWord{10, 0, 312},\n\tdictWord{11, 0, 687},\n\tdictWord{12, 0, 555},\n\tdictWord{13, 0, 373},\n\tdictWord{13, 0, 494},\n\tdictWord{\n\t\t148,\n\t\t0,\n\t\t58,\n\t},\n\tdictWord{133, 10, 514},\n\tdictWord{8, 11, 39},\n\tdictWord{10, 11, 773},\n\tdictWord{11, 11, 84},\n\tdictWord{12, 11, 205},\n\tdictWord{142, 11, 1},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t783,\n\t},\n\tdictWord{5, 11, 601},\n\tdictWord{133, 11, 870},\n\tdictWord{136, 11, 594},\n\tdictWord{4, 10, 55},\n\tdictWord{5, 10, 301},\n\tdictWord{6, 10, 571},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t49,\n\t},\n\tdictWord{146, 10, 102},\n\tdictWord{132, 11, 181},\n\tdictWord{134, 11, 1652},\n\tdictWord{133, 10, 364},\n\tdictWord{4, 11, 97},\n\tdictWord{5, 11, 147},\n\tdictWord{6, 11, 286},\n\tdictWord{7, 11, 1362},\n\tdictWord{141, 11, 176},\n\tdictWord{4, 10, 76},\n\tdictWord{7, 10, 1550},\n\tdictWord{9, 10, 306},\n\tdictWord{9, 10, 430},\n\tdictWord{9, 10, 663},\n\tdictWord{10, 10, 683},\n\tdictWord{11, 10, 427},\n\tdictWord{11, 10, 753},\n\tdictWord{12, 10, 334},\n\tdictWord{12, 10, 442},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t258,\n\t},\n\tdictWord{14, 10, 366},\n\tdictWord{143, 10, 131},\n\tdictWord{137, 10, 52},\n\tdictWord{6, 0, 955},\n\tdictWord{134, 0, 1498},\n\tdictWord{6, 11, 375},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t169,\n\t},\n\tdictWord{7, 11, 254},\n\tdictWord{136, 11, 780},\n\tdictWord{7, 0, 430},\n\tdictWord{11, 0, 46},\n\tdictWord{14, 0, 343},\n\tdictWord{142, 11, 343},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1183,\n\t},\n\tdictWord{5, 0, 602},\n\tdictWord{7, 0, 2018},\n\tdictWord{9, 0, 418},\n\tdictWord{9, 0, 803},\n\tdictWord{135, 11, 1447},\n\tdictWord{8, 0, 677},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1044,\n\t},\n\tdictWord{139, 11, 285},\n\tdictWord{4, 10, 656},\n\tdictWord{135, 10, 779},\n\tdictWord{135, 10, 144},\n\tdictWord{5, 11, 629},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1549,\n\t},\n\tdictWord{135, 10, 1373},\n\tdictWord{138, 11, 209},\n\tdictWord{7, 10, 554},\n\tdictWord{7, 10, 605},\n\tdictWord{141, 10, 10},\n\tdictWord{5, 10, 838},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t841,\n\t},\n\tdictWord{134, 10, 1649},\n\tdictWord{133, 10, 1012},\n\tdictWord{6, 0, 1357},\n\tdictWord{134, 0, 1380},\n\tdictWord{144, 0, 53},\n\tdictWord{6, 0, 590},\n\tdictWord{7, 10, 365},\n\tdictWord{7, 10, 1357},\n\tdictWord{7, 10, 1497},\n\tdictWord{8, 10, 154},\n\tdictWord{141, 10, 281},\n\tdictWord{133, 10, 340},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t420,\n\t},\n\tdictWord{135, 0, 329},\n\tdictWord{147, 11, 32},\n\tdictWord{4, 0, 469},\n\tdictWord{10, 11, 429},\n\tdictWord{139, 10, 495},\n\tdictWord{8, 10, 261},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t144,\n\t},\n\tdictWord{9, 10, 466},\n\tdictWord{10, 10, 370},\n\tdictWord{12, 10, 470},\n\tdictWord{13, 10, 144},\n\tdictWord{142, 10, 348},\n\tdictWord{142, 0, 460},\n\tdictWord{4, 11, 325},\n\tdictWord{9, 10, 897},\n\tdictWord{138, 11, 125},\n\tdictWord{6, 0, 1743},\n\tdictWord{6, 10, 248},\n\tdictWord{9, 10, 546},\n\tdictWord{10, 10, 535},\n\tdictWord{11, 10, 681},\n\tdictWord{141, 10, 135},\n\tdictWord{4, 0, 990},\n\tdictWord{5, 0, 929},\n\tdictWord{6, 0, 340},\n\tdictWord{8, 0, 376},\n\tdictWord{8, 0, 807},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t963,\n\t},\n\tdictWord{8, 0, 980},\n\tdictWord{138, 0, 1007},\n\tdictWord{134, 0, 1603},\n\tdictWord{140, 0, 250},\n\tdictWord{4, 11, 714},\n\tdictWord{133, 11, 469},\n\tdictWord{134, 10, 567},\n\tdictWord{136, 10, 445},\n\tdictWord{5, 0, 218},\n\tdictWord{7, 0, 1610},\n\tdictWord{8, 0, 646},\n\tdictWord{10, 0, 83},\n\tdictWord{11, 11, 138},\n\tdictWord{140, 11, 40},\n\tdictWord{7, 0, 1512},\n\tdictWord{135, 0, 1794},\n\tdictWord{135, 11, 1216},\n\tdictWord{11, 0, 0},\n\tdictWord{16, 0, 78},\n\tdictWord{132, 11, 718},\n\tdictWord{133, 0, 571},\n\tdictWord{132, 0, 455},\n\tdictWord{134, 0, 1012},\n\tdictWord{5, 11, 124},\n\tdictWord{5, 11, 144},\n\tdictWord{6, 11, 548},\n\tdictWord{7, 11, 15},\n\tdictWord{7, 11, 153},\n\tdictWord{137, 11, 629},\n\tdictWord{142, 11, 10},\n\tdictWord{6, 11, 75},\n\tdictWord{7, 11, 1531},\n\tdictWord{8, 11, 416},\n\tdictWord{9, 11, 240},\n\tdictWord{9, 11, 275},\n\tdictWord{10, 11, 100},\n\tdictWord{11, 11, 658},\n\tdictWord{11, 11, 979},\n\tdictWord{12, 11, 86},\n\tdictWord{13, 11, 468},\n\tdictWord{14, 11, 66},\n\tdictWord{14, 11, 207},\n\tdictWord{15, 11, 20},\n\tdictWord{15, 11, 25},\n\tdictWord{144, 11, 58},\n\tdictWord{132, 10, 577},\n\tdictWord{5, 11, 141},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t915,\n\t},\n\tdictWord{6, 11, 1783},\n\tdictWord{7, 11, 211},\n\tdictWord{7, 11, 698},\n\tdictWord{7, 11, 1353},\n\tdictWord{9, 11, 83},\n\tdictWord{9, 11, 281},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t376,\n\t},\n\tdictWord{10, 11, 431},\n\tdictWord{11, 11, 543},\n\tdictWord{12, 11, 664},\n\tdictWord{13, 11, 280},\n\tdictWord{13, 11, 428},\n\tdictWord{14, 11, 61},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t128,\n\t},\n\tdictWord{17, 11, 52},\n\tdictWord{145, 11, 81},\n\tdictWord{6, 0, 161},\n\tdictWord{7, 0, 372},\n\tdictWord{137, 0, 597},\n\tdictWord{132, 0, 349},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t702,\n\t},\n\tdictWord{139, 11, 245},\n\tdictWord{134, 0, 524},\n\tdictWord{134, 10, 174},\n\tdictWord{6, 0, 432},\n\tdictWord{9, 0, 751},\n\tdictWord{139, 0, 322},\n\tdictWord{147, 11, 94},\n\tdictWord{4, 11, 338},\n\tdictWord{133, 11, 400},\n\tdictWord{5, 0, 468},\n\tdictWord{10, 0, 325},\n\tdictWord{11, 0, 856},\n\tdictWord{12, 0, 345},\n\tdictWord{143, 0, 104},\n\tdictWord{133, 0, 223},\n\tdictWord{132, 0, 566},\n\tdictWord{4, 11, 221},\n\tdictWord{5, 11, 659},\n\tdictWord{5, 11, 989},\n\tdictWord{7, 11, 697},\n\tdictWord{7, 11, 1211},\n\tdictWord{138, 11, 284},\n\tdictWord{135, 11, 1070},\n\tdictWord{4, 0, 59},\n\tdictWord{135, 0, 1394},\n\tdictWord{6, 0, 436},\n\tdictWord{11, 0, 481},\n\tdictWord{5, 10, 878},\n\tdictWord{133, 10, 972},\n\tdictWord{4, 0, 48},\n\tdictWord{5, 0, 271},\n\tdictWord{135, 0, 953},\n\tdictWord{5, 0, 610},\n\tdictWord{136, 0, 457},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t773,\n\t},\n\tdictWord{5, 0, 618},\n\tdictWord{137, 0, 756},\n\tdictWord{133, 0, 755},\n\tdictWord{135, 0, 1217},\n\tdictWord{138, 11, 507},\n\tdictWord{132, 10, 351},\n\tdictWord{132, 0, 197},\n\tdictWord{143, 11, 78},\n\tdictWord{4, 11, 188},\n\tdictWord{7, 11, 805},\n\tdictWord{11, 11, 276},\n\tdictWord{142, 11, 293},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t884,\n\t},\n\tdictWord{139, 11, 991},\n\tdictWord{132, 10, 286},\n\tdictWord{10, 0, 259},\n\tdictWord{10, 0, 428},\n\tdictWord{7, 10, 438},\n\tdictWord{7, 10, 627},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1516,\n\t},\n\tdictWord{8, 10, 40},\n\tdictWord{9, 10, 56},\n\tdictWord{9, 10, 294},\n\tdictWord{11, 10, 969},\n\tdictWord{11, 10, 995},\n\tdictWord{146, 10, 148},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t356,\n\t},\n\tdictWord{5, 0, 217},\n\tdictWord{5, 0, 492},\n\tdictWord{5, 0, 656},\n\tdictWord{8, 0, 544},\n\tdictWord{136, 11, 544},\n\tdictWord{5, 0, 259},\n\tdictWord{6, 0, 1230},\n\tdictWord{7, 0, 414},\n\tdictWord{7, 0, 854},\n\tdictWord{142, 0, 107},\n\tdictWord{132, 0, 1007},\n\tdictWord{15, 0, 14},\n\tdictWord{144, 0, 5},\n\tdictWord{6, 0, 1580},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t738,\n\t},\n\tdictWord{132, 11, 596},\n\tdictWord{132, 0, 673},\n\tdictWord{133, 10, 866},\n\tdictWord{6, 0, 1843},\n\tdictWord{135, 11, 1847},\n\tdictWord{4, 0, 165},\n\tdictWord{7, 0, 1398},\n\tdictWord{135, 0, 1829},\n\tdictWord{135, 11, 1634},\n\tdictWord{147, 11, 65},\n\tdictWord{6, 0, 885},\n\tdictWord{6, 0, 1009},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t809,\n\t},\n\tdictWord{133, 10, 116},\n\tdictWord{132, 10, 457},\n\tdictWord{136, 11, 770},\n\tdictWord{9, 0, 498},\n\tdictWord{12, 0, 181},\n\tdictWord{10, 11, 361},\n\tdictWord{142, 11, 316},\n\tdictWord{134, 11, 595},\n\tdictWord{5, 0, 9},\n\tdictWord{7, 0, 297},\n\tdictWord{7, 0, 966},\n\tdictWord{140, 0, 306},\n\tdictWord{4, 11, 89},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t489,\n\t},\n\tdictWord{6, 11, 315},\n\tdictWord{7, 11, 553},\n\tdictWord{7, 11, 1745},\n\tdictWord{138, 11, 243},\n\tdictWord{134, 0, 1487},\n\tdictWord{132, 0, 437},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t146,\n\t},\n\tdictWord{6, 0, 411},\n\tdictWord{138, 0, 721},\n\tdictWord{5, 10, 527},\n\tdictWord{6, 10, 189},\n\tdictWord{135, 10, 859},\n\tdictWord{11, 10, 104},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t554,\n\t},\n\tdictWord{15, 10, 60},\n\tdictWord{143, 10, 125},\n\tdictWord{6, 11, 1658},\n\tdictWord{9, 11, 3},\n\tdictWord{10, 11, 154},\n\tdictWord{11, 11, 641},\n\tdictWord{13, 11, 85},\n\tdictWord{13, 11, 201},\n\tdictWord{141, 11, 346},\n\tdictWord{6, 0, 177},\n\tdictWord{135, 0, 467},\n\tdictWord{134, 0, 1377},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t116,\n\t},\n\tdictWord{136, 11, 645},\n\tdictWord{4, 11, 166},\n\tdictWord{5, 11, 505},\n\tdictWord{6, 11, 1670},\n\tdictWord{137, 11, 110},\n\tdictWord{133, 10, 487},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t86,\n\t},\n\tdictWord{5, 10, 667},\n\tdictWord{5, 10, 753},\n\tdictWord{6, 10, 316},\n\tdictWord{6, 10, 455},\n\tdictWord{135, 10, 946},\n\tdictWord{133, 0, 200},\n\tdictWord{132, 0, 959},\n\tdictWord{6, 0, 1928},\n\tdictWord{134, 0, 1957},\n\tdictWord{139, 11, 203},\n\tdictWord{150, 10, 45},\n\tdictWord{4, 10, 79},\n\tdictWord{7, 10, 1773},\n\tdictWord{10, 10, 450},\n\tdictWord{11, 10, 589},\n\tdictWord{13, 10, 332},\n\tdictWord{13, 10, 493},\n\tdictWord{14, 10, 183},\n\tdictWord{14, 10, 334},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t362,\n\t},\n\tdictWord{14, 10, 368},\n\tdictWord{14, 10, 376},\n\tdictWord{14, 10, 379},\n\tdictWord{19, 10, 90},\n\tdictWord{19, 10, 103},\n\tdictWord{19, 10, 127},\n\tdictWord{148, 10, 90},\n\tdictWord{6, 0, 1435},\n\tdictWord{135, 11, 1275},\n\tdictWord{134, 0, 481},\n\tdictWord{7, 11, 445},\n\tdictWord{8, 11, 307},\n\tdictWord{8, 11, 704},\n\tdictWord{10, 11, 41},\n\tdictWord{10, 11, 439},\n\tdictWord{11, 11, 237},\n\tdictWord{11, 11, 622},\n\tdictWord{140, 11, 201},\n\tdictWord{135, 11, 869},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t84,\n\t},\n\tdictWord{7, 0, 1482},\n\tdictWord{10, 0, 76},\n\tdictWord{138, 0, 142},\n\tdictWord{11, 11, 277},\n\tdictWord{144, 11, 14},\n\tdictWord{135, 11, 1977},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t189,\n\t},\n\tdictWord{5, 11, 713},\n\tdictWord{136, 11, 57},\n\tdictWord{133, 0, 1015},\n\tdictWord{138, 11, 371},\n\tdictWord{4, 0, 315},\n\tdictWord{5, 0, 507},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1370,\n\t},\n\tdictWord{4, 11, 552},\n\tdictWord{142, 10, 381},\n\tdictWord{9, 0, 759},\n\tdictWord{16, 0, 31},\n\tdictWord{16, 0, 39},\n\tdictWord{16, 0, 75},\n\tdictWord{18, 0, 24},\n\tdictWord{20, 0, 42},\n\tdictWord{152, 0, 1},\n\tdictWord{134, 0, 712},\n\tdictWord{134, 0, 1722},\n\tdictWord{133, 10, 663},\n\tdictWord{133, 10, 846},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t222,\n\t},\n\tdictWord{8, 0, 476},\n\tdictWord{9, 0, 238},\n\tdictWord{11, 0, 516},\n\tdictWord{11, 0, 575},\n\tdictWord{15, 0, 109},\n\tdictWord{146, 0, 100},\n\tdictWord{7, 0, 1402},\n\tdictWord{7, 0, 1414},\n\tdictWord{12, 0, 456},\n\tdictWord{5, 10, 378},\n\tdictWord{8, 10, 465},\n\tdictWord{9, 10, 286},\n\tdictWord{10, 10, 185},\n\tdictWord{10, 10, 562},\n\tdictWord{10, 10, 635},\n\tdictWord{11, 10, 31},\n\tdictWord{11, 10, 393},\n\tdictWord{13, 10, 312},\n\tdictWord{18, 10, 65},\n\tdictWord{18, 10, 96},\n\tdictWord{147, 10, 89},\n\tdictWord{4, 0, 986},\n\tdictWord{6, 0, 1958},\n\tdictWord{6, 0, 2032},\n\tdictWord{8, 0, 934},\n\tdictWord{138, 0, 985},\n\tdictWord{7, 10, 1880},\n\tdictWord{9, 10, 680},\n\tdictWord{139, 10, 798},\n\tdictWord{134, 10, 1770},\n\tdictWord{145, 11, 49},\n\tdictWord{132, 11, 614},\n\tdictWord{132, 10, 648},\n\tdictWord{5, 10, 945},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1656,\n\t},\n\tdictWord{6, 10, 1787},\n\tdictWord{7, 10, 167},\n\tdictWord{8, 10, 824},\n\tdictWord{9, 10, 391},\n\tdictWord{10, 10, 375},\n\tdictWord{139, 10, 185},\n\tdictWord{138, 11, 661},\n\tdictWord{7, 0, 1273},\n\tdictWord{135, 11, 1945},\n\tdictWord{7, 0, 706},\n\tdictWord{7, 0, 1058},\n\tdictWord{138, 0, 538},\n\tdictWord{7, 10, 1645},\n\tdictWord{8, 10, 352},\n\tdictWord{137, 10, 249},\n\tdictWord{132, 10, 152},\n\tdictWord{11, 0, 92},\n\tdictWord{11, 0, 196},\n\tdictWord{11, 0, 409},\n\tdictWord{11, 0, 450},\n\tdictWord{11, 0, 666},\n\tdictWord{11, 0, 777},\n\tdictWord{12, 0, 262},\n\tdictWord{13, 0, 385},\n\tdictWord{13, 0, 393},\n\tdictWord{15, 0, 115},\n\tdictWord{16, 0, 45},\n\tdictWord{145, 0, 82},\n\tdictWord{133, 10, 1006},\n\tdictWord{6, 0, 40},\n\tdictWord{135, 0, 1781},\n\tdictWord{9, 11, 614},\n\tdictWord{139, 11, 327},\n\tdictWord{5, 10, 420},\n\tdictWord{135, 10, 1449},\n\tdictWord{135, 0, 431},\n\tdictWord{10, 0, 97},\n\tdictWord{135, 10, 832},\n\tdictWord{6, 0, 423},\n\tdictWord{7, 0, 665},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1210,\n\t},\n\tdictWord{7, 0, 237},\n\tdictWord{8, 0, 664},\n\tdictWord{9, 0, 42},\n\tdictWord{9, 0, 266},\n\tdictWord{9, 0, 380},\n\tdictWord{9, 0, 645},\n\tdictWord{10, 0, 177},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t276,\n\t},\n\tdictWord{7, 0, 264},\n\tdictWord{133, 10, 351},\n\tdictWord{8, 0, 213},\n\tdictWord{5, 10, 40},\n\tdictWord{7, 10, 598},\n\tdictWord{7, 10, 1638},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t166,\n\t},\n\tdictWord{9, 10, 640},\n\tdictWord{9, 10, 685},\n\tdictWord{9, 10, 773},\n\tdictWord{11, 10, 215},\n\tdictWord{13, 10, 65},\n\tdictWord{14, 10, 172},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t317,\n\t},\n\tdictWord{145, 10, 6},\n\tdictWord{5, 11, 84},\n\tdictWord{134, 11, 163},\n\tdictWord{8, 10, 60},\n\tdictWord{9, 10, 343},\n\tdictWord{139, 10, 769},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t455,\n\t},\n\tdictWord{133, 11, 410},\n\tdictWord{8, 0, 906},\n\tdictWord{12, 0, 700},\n\tdictWord{12, 0, 706},\n\tdictWord{140, 0, 729},\n\tdictWord{21, 11, 33},\n\tdictWord{\n\t\t150,\n\t\t11,\n\t\t40,\n\t},\n\tdictWord{7, 10, 1951},\n\tdictWord{8, 10, 765},\n\tdictWord{8, 10, 772},\n\tdictWord{140, 10, 671},\n\tdictWord{7, 10, 108},\n\tdictWord{8, 10, 219},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t388,\n\t},\n\tdictWord{9, 10, 639},\n\tdictWord{9, 10, 775},\n\tdictWord{11, 10, 275},\n\tdictWord{140, 10, 464},\n\tdictWord{5, 11, 322},\n\tdictWord{7, 11, 1941},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t186,\n\t},\n\tdictWord{9, 11, 262},\n\tdictWord{10, 11, 187},\n\tdictWord{14, 11, 208},\n\tdictWord{146, 11, 130},\n\tdictWord{139, 0, 624},\n\tdictWord{8, 0, 574},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t227,\n\t},\n\tdictWord{140, 11, 29},\n\tdictWord{7, 11, 1546},\n\tdictWord{11, 11, 299},\n\tdictWord{142, 11, 407},\n\tdictWord{5, 10, 15},\n\tdictWord{6, 10, 56},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1758,\n\t},\n\tdictWord{8, 10, 500},\n\tdictWord{9, 10, 730},\n\tdictWord{11, 10, 331},\n\tdictWord{13, 10, 150},\n\tdictWord{142, 10, 282},\n\tdictWord{7, 11, 1395},\n\tdictWord{8, 11, 486},\n\tdictWord{9, 11, 236},\n\tdictWord{9, 11, 878},\n\tdictWord{10, 11, 218},\n\tdictWord{11, 11, 95},\n\tdictWord{19, 11, 17},\n\tdictWord{147, 11, 31},\n\tdictWord{135, 11, 2043},\n\tdictWord{4, 0, 354},\n\tdictWord{146, 11, 4},\n\tdictWord{140, 11, 80},\n\tdictWord{135, 0, 1558},\n\tdictWord{134, 10, 1886},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t205,\n\t},\n\tdictWord{6, 10, 438},\n\tdictWord{137, 10, 711},\n\tdictWord{133, 11, 522},\n\tdictWord{133, 10, 534},\n\tdictWord{7, 0, 235},\n\tdictWord{7, 0, 1475},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t68,\n\t},\n\tdictWord{146, 0, 120},\n\tdictWord{137, 10, 691},\n\tdictWord{4, 0, 942},\n\tdictWord{6, 0, 1813},\n\tdictWord{8, 0, 917},\n\tdictWord{10, 0, 884},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t696,\n\t},\n\tdictWord{12, 0, 717},\n\tdictWord{12, 0, 723},\n\tdictWord{12, 0, 738},\n\tdictWord{12, 0, 749},\n\tdictWord{12, 0, 780},\n\tdictWord{16, 0, 97},\n\tdictWord{146, 0, 169},\n\tdictWord{6, 10, 443},\n\tdictWord{8, 11, 562},\n\tdictWord{9, 10, 237},\n\tdictWord{9, 10, 571},\n\tdictWord{9, 10, 695},\n\tdictWord{10, 10, 139},\n\tdictWord{11, 10, 715},\n\tdictWord{12, 10, 417},\n\tdictWord{141, 10, 421},\n\tdictWord{135, 0, 957},\n\tdictWord{133, 0, 830},\n\tdictWord{134, 11, 1771},\n\tdictWord{146, 0, 23},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t496,\n\t},\n\tdictWord{6, 0, 694},\n\tdictWord{7, 0, 203},\n\tdictWord{7, 11, 1190},\n\tdictWord{137, 11, 620},\n\tdictWord{137, 11, 132},\n\tdictWord{6, 0, 547},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1549,\n\t},\n\tdictWord{8, 11, 258},\n\tdictWord{9, 11, 208},\n\tdictWord{137, 11, 359},\n\tdictWord{4, 0, 864},\n\tdictWord{5, 0, 88},\n\tdictWord{137, 0, 239},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t493,\n\t},\n\tdictWord{4, 11, 317},\n\tdictWord{135, 11, 1279},\n\tdictWord{132, 11, 477},\n\tdictWord{4, 10, 578},\n\tdictWord{5, 11, 63},\n\tdictWord{133, 11, 509},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t650,\n\t},\n\tdictWord{135, 0, 1310},\n\tdictWord{7, 0, 1076},\n\tdictWord{9, 0, 80},\n\tdictWord{11, 0, 78},\n\tdictWord{11, 0, 421},\n\tdictWord{11, 0, 534},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t545,\n\t},\n\tdictWord{132, 11, 288},\n\tdictWord{12, 0, 553},\n\tdictWord{14, 0, 118},\n\tdictWord{133, 10, 923},\n\tdictWord{7, 0, 274},\n\tdictWord{11, 0, 479},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t507,\n\t},\n\tdictWord{8, 11, 89},\n\tdictWord{8, 11, 620},\n\tdictWord{9, 11, 49},\n\tdictWord{10, 11, 774},\n\tdictWord{11, 11, 628},\n\tdictWord{12, 11, 322},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t124,\n\t},\n\tdictWord{4, 0, 497},\n\tdictWord{135, 0, 1584},\n\tdictWord{7, 0, 261},\n\tdictWord{7, 0, 1115},\n\tdictWord{7, 0, 1354},\n\tdictWord{7, 0, 1404},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1588,\n\t},\n\tdictWord{7, 0, 1705},\n\tdictWord{7, 0, 1902},\n\tdictWord{9, 0, 465},\n\tdictWord{10, 0, 248},\n\tdictWord{10, 0, 349},\n\tdictWord{10, 0, 647},\n\tdictWord{11, 0, 527},\n\tdictWord{11, 0, 660},\n\tdictWord{11, 0, 669},\n\tdictWord{12, 0, 529},\n\tdictWord{13, 0, 305},\n\tdictWord{132, 10, 924},\n\tdictWord{133, 10, 665},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t13,\n\t},\n\tdictWord{6, 0, 791},\n\tdictWord{138, 11, 120},\n\tdictWord{7, 0, 642},\n\tdictWord{8, 0, 250},\n\tdictWord{11, 0, 123},\n\tdictWord{11, 0, 137},\n\tdictWord{13, 0, 48},\n\tdictWord{142, 0, 95},\n\tdictWord{4, 10, 265},\n\tdictWord{7, 10, 807},\n\tdictWord{135, 10, 950},\n\tdictWord{5, 10, 93},\n\tdictWord{140, 10, 267},\n\tdictWord{135, 0, 1429},\n\tdictWord{4, 0, 949},\n\tdictWord{10, 0, 885},\n\tdictWord{10, 0, 891},\n\tdictWord{10, 0, 900},\n\tdictWord{10, 0, 939},\n\tdictWord{12, 0, 760},\n\tdictWord{142, 0, 449},\n\tdictWord{139, 11, 366},\n\tdictWord{132, 0, 818},\n\tdictWord{134, 11, 85},\n\tdictWord{135, 10, 994},\n\tdictWord{7, 0, 330},\n\tdictWord{5, 10, 233},\n\tdictWord{5, 10, 320},\n\tdictWord{6, 10, 140},\n\tdictWord{136, 10, 295},\n\tdictWord{4, 0, 1004},\n\tdictWord{8, 0, 982},\n\tdictWord{136, 0, 993},\n\tdictWord{133, 10, 978},\n\tdictWord{4, 10, 905},\n\tdictWord{6, 10, 1701},\n\tdictWord{137, 10, 843},\n\tdictWord{10, 0, 545},\n\tdictWord{140, 0, 301},\n\tdictWord{6, 0, 947},\n\tdictWord{134, 0, 1062},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1188,\n\t},\n\tdictWord{4, 0, 904},\n\tdictWord{5, 0, 794},\n\tdictWord{152, 10, 6},\n\tdictWord{134, 0, 1372},\n\tdictWord{135, 11, 608},\n\tdictWord{5, 11, 279},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t235,\n\t},\n\tdictWord{7, 11, 468},\n\tdictWord{8, 11, 446},\n\tdictWord{9, 11, 637},\n\tdictWord{10, 11, 717},\n\tdictWord{11, 11, 738},\n\tdictWord{140, 11, 514},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t509,\n\t},\n\tdictWord{5, 11, 17},\n\tdictWord{6, 11, 371},\n\tdictWord{137, 11, 528},\n\tdictWord{132, 0, 693},\n\tdictWord{4, 11, 115},\n\tdictWord{5, 11, 669},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t407,\n\t},\n\tdictWord{8, 11, 311},\n\tdictWord{11, 11, 10},\n\tdictWord{141, 11, 5},\n\tdictWord{11, 0, 377},\n\tdictWord{7, 10, 273},\n\tdictWord{137, 11, 381},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t695,\n\t},\n\tdictWord{7, 0, 386},\n\tdictWord{138, 0, 713},\n\tdictWord{135, 10, 1041},\n\tdictWord{134, 0, 1291},\n\tdictWord{6, 0, 7},\n\tdictWord{6, 0, 35},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t147,\n\t},\n\tdictWord{7, 0, 1069},\n\tdictWord{7, 0, 1568},\n\tdictWord{7, 0, 1575},\n\tdictWord{7, 0, 1917},\n\tdictWord{8, 0, 43},\n\tdictWord{8, 0, 208},\n\tdictWord{9, 0, 128},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t866,\n\t},\n\tdictWord{10, 0, 20},\n\tdictWord{11, 0, 981},\n\tdictWord{147, 0, 33},\n\tdictWord{7, 0, 893},\n\tdictWord{141, 0, 424},\n\tdictWord{139, 10, 234},\n\tdictWord{\n\t\t150,\n\t\t11,\n\t\t56,\n\t},\n\tdictWord{5, 11, 779},\n\tdictWord{5, 11, 807},\n\tdictWord{6, 11, 1655},\n\tdictWord{134, 11, 1676},\n\tdictWord{5, 10, 802},\n\tdictWord{7, 10, 2021},\n\tdictWord{136, 10, 805},\n\tdictWord{4, 11, 196},\n\tdictWord{5, 10, 167},\n\tdictWord{5, 11, 558},\n\tdictWord{5, 10, 899},\n\tdictWord{5, 11, 949},\n\tdictWord{6, 10, 410},\n\tdictWord{137, 10, 777},\n\tdictWord{137, 10, 789},\n\tdictWord{134, 10, 1705},\n\tdictWord{8, 0, 904},\n\tdictWord{140, 0, 787},\n\tdictWord{6, 0, 322},\n\tdictWord{9, 0, 552},\n\tdictWord{11, 0, 274},\n\tdictWord{13, 0, 209},\n\tdictWord{13, 0, 499},\n\tdictWord{14, 0, 85},\n\tdictWord{15, 0, 126},\n\tdictWord{145, 0, 70},\n\tdictWord{135, 10, 10},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t11,\n\t},\n\tdictWord{6, 10, 117},\n\tdictWord{6, 10, 485},\n\tdictWord{7, 10, 1133},\n\tdictWord{9, 10, 582},\n\tdictWord{9, 10, 594},\n\tdictWord{11, 10, 21},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t818,\n\t},\n\tdictWord{12, 10, 535},\n\tdictWord{141, 10, 86},\n\tdictWord{4, 10, 264},\n\tdictWord{7, 10, 1067},\n\tdictWord{8, 10, 204},\n\tdictWord{8, 10, 385},\n\tdictWord{139, 10, 953},\n\tdictWord{132, 11, 752},\n\tdictWord{138, 10, 56},\n\tdictWord{133, 10, 470},\n\tdictWord{6, 0, 1808},\n\tdictWord{8, 0, 83},\n\tdictWord{8, 0, 742},\n\tdictWord{8, 0, 817},\n\tdictWord{9, 0, 28},\n\tdictWord{9, 0, 29},\n\tdictWord{9, 0, 885},\n\tdictWord{10, 0, 387},\n\tdictWord{11, 0, 633},\n\tdictWord{11, 0, 740},\n\tdictWord{13, 0, 235},\n\tdictWord{13, 0, 254},\n\tdictWord{15, 0, 143},\n\tdictWord{143, 0, 146},\n\tdictWord{140, 0, 49},\n\tdictWord{134, 0, 1832},\n\tdictWord{4, 11, 227},\n\tdictWord{5, 11, 159},\n\tdictWord{5, 11, 409},\n\tdictWord{7, 11, 80},\n\tdictWord{10, 11, 294},\n\tdictWord{10, 11, 479},\n\tdictWord{12, 11, 418},\n\tdictWord{14, 11, 50},\n\tdictWord{14, 11, 249},\n\tdictWord{142, 11, 295},\n\tdictWord{7, 11, 1470},\n\tdictWord{8, 11, 66},\n\tdictWord{8, 11, 137},\n\tdictWord{8, 11, 761},\n\tdictWord{9, 11, 638},\n\tdictWord{11, 11, 80},\n\tdictWord{11, 11, 212},\n\tdictWord{11, 11, 368},\n\tdictWord{11, 11, 418},\n\tdictWord{12, 11, 8},\n\tdictWord{13, 11, 15},\n\tdictWord{16, 11, 61},\n\tdictWord{17, 11, 59},\n\tdictWord{19, 11, 28},\n\tdictWord{148, 11, 84},\n\tdictWord{139, 10, 1015},\n\tdictWord{138, 11, 468},\n\tdictWord{135, 0, 421},\n\tdictWord{6, 0, 415},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1049,\n\t},\n\tdictWord{137, 0, 442},\n\tdictWord{6, 11, 38},\n\tdictWord{7, 11, 1220},\n\tdictWord{8, 11, 185},\n\tdictWord{8, 11, 256},\n\tdictWord{9, 11, 22},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t331,\n\t},\n\tdictWord{10, 11, 738},\n\tdictWord{11, 11, 205},\n\tdictWord{11, 11, 540},\n\tdictWord{11, 11, 746},\n\tdictWord{13, 11, 399},\n\tdictWord{13, 11, 465},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t88,\n\t},\n\tdictWord{142, 11, 194},\n\tdictWord{139, 0, 289},\n\tdictWord{133, 10, 715},\n\tdictWord{4, 0, 110},\n\tdictWord{10, 0, 415},\n\tdictWord{10, 0, 597},\n\tdictWord{142, 0, 206},\n\tdictWord{4, 11, 159},\n\tdictWord{6, 11, 115},\n\tdictWord{7, 11, 252},\n\tdictWord{7, 11, 257},\n\tdictWord{7, 11, 1928},\n\tdictWord{8, 11, 69},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t384,\n\t},\n\tdictWord{10, 11, 91},\n\tdictWord{10, 11, 615},\n\tdictWord{12, 11, 375},\n\tdictWord{14, 11, 235},\n\tdictWord{18, 11, 117},\n\tdictWord{147, 11, 123},\n\tdictWord{5, 11, 911},\n\tdictWord{136, 11, 278},\n\tdictWord{7, 0, 205},\n\tdictWord{7, 0, 2000},\n\tdictWord{8, 10, 794},\n\tdictWord{9, 10, 400},\n\tdictWord{10, 10, 298},\n\tdictWord{142, 10, 228},\n\tdictWord{135, 11, 1774},\n\tdictWord{4, 11, 151},\n\tdictWord{7, 11, 1567},\n\tdictWord{8, 11, 351},\n\tdictWord{137, 11, 322},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t724,\n\t},\n\tdictWord{133, 11, 990},\n\tdictWord{7, 0, 1539},\n\tdictWord{11, 0, 512},\n\tdictWord{13, 0, 205},\n\tdictWord{19, 0, 30},\n\tdictWord{22, 0, 36},\n\tdictWord{23, 0, 19},\n\tdictWord{135, 11, 1539},\n\tdictWord{5, 11, 194},\n\tdictWord{7, 11, 1662},\n\tdictWord{9, 11, 90},\n\tdictWord{140, 11, 180},\n\tdictWord{6, 10, 190},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t768,\n\t},\n\tdictWord{135, 10, 1170},\n\tdictWord{134, 0, 1340},\n\tdictWord{4, 0, 283},\n\tdictWord{135, 0, 1194},\n\tdictWord{133, 11, 425},\n\tdictWord{133, 11, 971},\n\tdictWord{12, 0, 549},\n\tdictWord{14, 10, 67},\n\tdictWord{147, 10, 60},\n\tdictWord{135, 10, 1023},\n\tdictWord{134, 0, 1720},\n\tdictWord{138, 11, 587},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t72,\n\t},\n\tdictWord{6, 11, 264},\n\tdictWord{7, 11, 21},\n\tdictWord{7, 11, 46},\n\tdictWord{7, 11, 2013},\n\tdictWord{8, 11, 215},\n\tdictWord{8, 11, 513},\n\tdictWord{10, 11, 266},\n\tdictWord{139, 11, 22},\n\tdictWord{5, 0, 319},\n\tdictWord{135, 0, 534},\n\tdictWord{6, 10, 137},\n\tdictWord{9, 10, 75},\n\tdictWord{9, 10, 253},\n\tdictWord{10, 10, 194},\n\tdictWord{138, 10, 444},\n\tdictWord{7, 0, 1180},\n\tdictWord{20, 0, 112},\n\tdictWord{6, 11, 239},\n\tdictWord{7, 11, 118},\n\tdictWord{10, 11, 95},\n\tdictWord{11, 11, 603},\n\tdictWord{13, 11, 443},\n\tdictWord{14, 11, 160},\n\tdictWord{143, 11, 4},\n\tdictWord{134, 11, 431},\n\tdictWord{5, 11, 874},\n\tdictWord{6, 11, 1677},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t643,\n\t},\n\tdictWord{12, 10, 115},\n\tdictWord{143, 11, 0},\n\tdictWord{134, 0, 967},\n\tdictWord{6, 11, 65},\n\tdictWord{7, 11, 939},\n\tdictWord{7, 11, 1172},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1671,\n\t},\n\tdictWord{9, 11, 540},\n\tdictWord{10, 11, 696},\n\tdictWord{11, 11, 265},\n\tdictWord{11, 11, 732},\n\tdictWord{11, 11, 928},\n\tdictWord{11, 11, 937},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t399,\n\t},\n\tdictWord{13, 11, 438},\n\tdictWord{149, 11, 19},\n\tdictWord{137, 11, 200},\n\tdictWord{135, 0, 1940},\n\tdictWord{5, 10, 760},\n\tdictWord{7, 10, 542},\n\tdictWord{8, 10, 135},\n\tdictWord{136, 10, 496},\n\tdictWord{140, 11, 44},\n\tdictWord{7, 11, 1655},\n\tdictWord{136, 11, 305},\n\tdictWord{7, 10, 319},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t355,\n\t},\n\tdictWord{7, 10, 763},\n\tdictWord{10, 10, 389},\n\tdictWord{145, 10, 43},\n\tdictWord{136, 0, 735},\n\tdictWord{138, 10, 786},\n\tdictWord{137, 11, 19},\n\tdictWord{132, 11, 696},\n\tdictWord{5, 0, 132},\n\tdictWord{9, 0, 486},\n\tdictWord{9, 0, 715},\n\tdictWord{10, 0, 458},\n\tdictWord{11, 0, 373},\n\tdictWord{11, 0, 668},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t795,\n\t},\n\tdictWord{11, 0, 897},\n\tdictWord{12, 0, 272},\n\tdictWord{12, 0, 424},\n\tdictWord{12, 0, 539},\n\tdictWord{12, 0, 558},\n\tdictWord{14, 0, 245},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t263,\n\t},\n\tdictWord{14, 0, 264},\n\tdictWord{14, 0, 393},\n\tdictWord{142, 0, 403},\n\tdictWord{10, 0, 38},\n\tdictWord{139, 0, 784},\n\tdictWord{132, 0, 838},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t302,\n\t},\n\tdictWord{135, 11, 1766},\n\tdictWord{133, 0, 379},\n\tdictWord{5, 0, 8},\n\tdictWord{6, 0, 89},\n\tdictWord{6, 0, 400},\n\tdictWord{7, 0, 1569},\n\tdictWord{7, 0, 1623},\n\tdictWord{7, 0, 1850},\n\tdictWord{8, 0, 218},\n\tdictWord{8, 0, 422},\n\tdictWord{9, 0, 570},\n\tdictWord{10, 0, 626},\n\tdictWord{4, 11, 726},\n\tdictWord{133, 11, 630},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t1017,\n\t},\n\tdictWord{138, 0, 660},\n\tdictWord{6, 0, 387},\n\tdictWord{7, 0, 882},\n\tdictWord{141, 0, 111},\n\tdictWord{6, 0, 224},\n\tdictWord{7, 0, 877},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t647,\n\t},\n\tdictWord{4, 10, 58},\n\tdictWord{5, 10, 286},\n\tdictWord{6, 10, 319},\n\tdictWord{7, 10, 402},\n\tdictWord{7, 10, 1254},\n\tdictWord{7, 10, 1903},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t356,\n\t},\n\tdictWord{140, 10, 408},\n\tdictWord{135, 0, 790},\n\tdictWord{9, 0, 510},\n\tdictWord{10, 0, 53},\n\tdictWord{4, 10, 389},\n\tdictWord{9, 10, 181},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t29,\n\t},\n\tdictWord{10, 10, 816},\n\tdictWord{11, 10, 311},\n\tdictWord{11, 10, 561},\n\tdictWord{12, 10, 67},\n\tdictWord{141, 10, 181},\n\tdictWord{142, 0, 458},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t118,\n\t},\n\tdictWord{7, 11, 215},\n\tdictWord{7, 11, 1521},\n\tdictWord{140, 11, 11},\n\tdictWord{134, 0, 954},\n\tdictWord{135, 0, 394},\n\tdictWord{134, 0, 1367},\n\tdictWord{5, 11, 225},\n\tdictWord{133, 10, 373},\n\tdictWord{132, 0, 882},\n\tdictWord{7, 0, 1409},\n\tdictWord{135, 10, 1972},\n\tdictWord{135, 10, 1793},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t370,\n\t},\n\tdictWord{5, 11, 756},\n\tdictWord{135, 11, 1326},\n\tdictWord{150, 11, 13},\n\tdictWord{7, 11, 354},\n\tdictWord{10, 11, 410},\n\tdictWord{139, 11, 815},\n\tdictWord{6, 11, 1662},\n\tdictWord{7, 11, 48},\n\tdictWord{8, 11, 771},\n\tdictWord{10, 11, 116},\n\tdictWord{13, 11, 104},\n\tdictWord{14, 11, 105},\n\tdictWord{14, 11, 184},\n\tdictWord{15, 11, 168},\n\tdictWord{19, 11, 92},\n\tdictWord{148, 11, 68},\n\tdictWord{7, 0, 124},\n\tdictWord{136, 0, 38},\n\tdictWord{5, 0, 261},\n\tdictWord{7, 0, 78},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t199,\n\t},\n\tdictWord{8, 0, 815},\n\tdictWord{9, 0, 126},\n\tdictWord{10, 0, 342},\n\tdictWord{140, 0, 647},\n\tdictWord{4, 0, 628},\n\tdictWord{140, 0, 724},\n\tdictWord{7, 0, 266},\n\tdictWord{8, 0, 804},\n\tdictWord{7, 10, 1651},\n\tdictWord{145, 10, 89},\n\tdictWord{135, 0, 208},\n\tdictWord{134, 0, 1178},\n\tdictWord{6, 0, 79},\n\tdictWord{135, 0, 1519},\n\tdictWord{132, 10, 672},\n\tdictWord{133, 10, 737},\n\tdictWord{136, 0, 741},\n\tdictWord{132, 11, 120},\n\tdictWord{4, 0, 710},\n\tdictWord{6, 0, 376},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t606,\n\t},\n\tdictWord{134, 0, 1347},\n\tdictWord{134, 0, 1494},\n\tdictWord{6, 0, 850},\n\tdictWord{6, 0, 1553},\n\tdictWord{137, 0, 821},\n\tdictWord{5, 10, 145},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t593,\n\t},\n\tdictWord{7, 0, 1311},\n\tdictWord{140, 0, 135},\n\tdictWord{4, 0, 467},\n\tdictWord{5, 0, 405},\n\tdictWord{134, 0, 544},\n\tdictWord{5, 11, 820},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t931,\n\t},\n\tdictWord{6, 0, 100},\n\tdictWord{7, 0, 244},\n\tdictWord{7, 0, 632},\n\tdictWord{7, 0, 1609},\n\tdictWord{8, 0, 178},\n\tdictWord{8, 0, 638},\n\tdictWord{141, 0, 58},\n\tdictWord{4, 10, 387},\n\tdictWord{135, 10, 1288},\n\tdictWord{6, 11, 151},\n\tdictWord{6, 11, 1675},\n\tdictWord{7, 11, 383},\n\tdictWord{151, 11, 10},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t481,\n\t},\n\tdictWord{135, 10, 550},\n\tdictWord{134, 0, 1378},\n\tdictWord{6, 11, 1624},\n\tdictWord{11, 11, 11},\n\tdictWord{12, 11, 422},\n\tdictWord{13, 11, 262},\n\tdictWord{142, 11, 360},\n\tdictWord{133, 0, 791},\n\tdictWord{4, 11, 43},\n\tdictWord{5, 11, 344},\n\tdictWord{133, 11, 357},\n\tdictWord{7, 0, 1227},\n\tdictWord{140, 0, 978},\n\tdictWord{7, 0, 686},\n\tdictWord{8, 0, 33},\n\tdictWord{8, 0, 238},\n\tdictWord{10, 0, 616},\n\tdictWord{11, 0, 467},\n\tdictWord{11, 0, 881},\n\tdictWord{13, 0, 217},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t253,\n\t},\n\tdictWord{142, 0, 268},\n\tdictWord{137, 0, 857},\n\tdictWord{8, 0, 467},\n\tdictWord{8, 0, 1006},\n\tdictWord{7, 11, 148},\n\tdictWord{8, 11, 284},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t63,\n\t},\n\tdictWord{4, 10, 576},\n\tdictWord{135, 10, 1263},\n\tdictWord{133, 11, 888},\n\tdictWord{5, 10, 919},\n\tdictWord{134, 10, 1673},\n\tdictWord{20, 10, 37},\n\tdictWord{148, 11, 37},\n\tdictWord{132, 0, 447},\n\tdictWord{132, 11, 711},\n\tdictWord{4, 0, 128},\n\tdictWord{5, 0, 415},\n\tdictWord{6, 0, 462},\n\tdictWord{7, 0, 294},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t578,\n\t},\n\tdictWord{10, 0, 710},\n\tdictWord{139, 0, 86},\n\tdictWord{4, 10, 82},\n\tdictWord{5, 10, 333},\n\tdictWord{5, 10, 904},\n\tdictWord{6, 10, 207},\n\tdictWord{7, 10, 325},\n\tdictWord{7, 10, 1726},\n\tdictWord{8, 10, 101},\n\tdictWord{10, 10, 778},\n\tdictWord{139, 10, 220},\n\tdictWord{136, 0, 587},\n\tdictWord{137, 11, 440},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t903,\n\t},\n\tdictWord{6, 0, 427},\n\tdictWord{7, 0, 1018},\n\tdictWord{138, 0, 692},\n\tdictWord{4, 0, 195},\n\tdictWord{135, 0, 802},\n\tdictWord{140, 10, 147},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1546,\n\t},\n\tdictWord{134, 0, 684},\n\tdictWord{132, 10, 705},\n\tdictWord{136, 0, 345},\n\tdictWord{11, 11, 678},\n\tdictWord{140, 11, 307},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t365,\n\t},\n\tdictWord{134, 0, 1683},\n\tdictWord{4, 11, 65},\n\tdictWord{5, 11, 479},\n\tdictWord{5, 11, 1004},\n\tdictWord{7, 11, 1913},\n\tdictWord{8, 11, 317},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t302,\n\t},\n\tdictWord{10, 11, 612},\n\tdictWord{141, 11, 22},\n\tdictWord{138, 0, 472},\n\tdictWord{4, 11, 261},\n\tdictWord{135, 11, 510},\n\tdictWord{134, 10, 90},\n\tdictWord{142, 0, 433},\n\tdictWord{151, 0, 28},\n\tdictWord{4, 11, 291},\n\tdictWord{7, 11, 101},\n\tdictWord{9, 11, 515},\n\tdictWord{12, 11, 152},\n\tdictWord{12, 11, 443},\n\tdictWord{13, 11, 392},\n\tdictWord{142, 11, 357},\n\tdictWord{140, 0, 997},\n\tdictWord{5, 0, 3},\n\tdictWord{8, 0, 578},\n\tdictWord{9, 0, 118},\n\tdictWord{10, 0, 705},\n\tdictWord{\n\t\t141,\n\t\t0,\n\t\t279,\n\t},\n\tdictWord{135, 11, 1266},\n\tdictWord{7, 10, 813},\n\tdictWord{12, 10, 497},\n\tdictWord{141, 10, 56},\n\tdictWord{133, 0, 229},\n\tdictWord{6, 10, 125},\n\tdictWord{135, 10, 1277},\n\tdictWord{8, 0, 102},\n\tdictWord{10, 0, 578},\n\tdictWord{10, 0, 672},\n\tdictWord{12, 0, 496},\n\tdictWord{13, 0, 408},\n\tdictWord{14, 0, 121},\n\tdictWord{17, 0, 106},\n\tdictWord{151, 10, 12},\n\tdictWord{6, 0, 866},\n\tdictWord{134, 0, 1080},\n\tdictWord{136, 0, 1022},\n\tdictWord{4, 11, 130},\n\tdictWord{135, 11, 843},\n\tdictWord{5, 11, 42},\n\tdictWord{5, 11, 879},\n\tdictWord{7, 11, 245},\n\tdictWord{7, 11, 324},\n\tdictWord{7, 11, 1532},\n\tdictWord{11, 11, 463},\n\tdictWord{11, 11, 472},\n\tdictWord{13, 11, 363},\n\tdictWord{144, 11, 52},\n\tdictWord{150, 0, 55},\n\tdictWord{8, 0, 115},\n\tdictWord{8, 0, 350},\n\tdictWord{9, 0, 489},\n\tdictWord{10, 0, 128},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t306,\n\t},\n\tdictWord{12, 0, 373},\n\tdictWord{14, 0, 30},\n\tdictWord{17, 0, 79},\n\tdictWord{19, 0, 80},\n\tdictWord{4, 11, 134},\n\tdictWord{133, 11, 372},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t657,\n\t},\n\tdictWord{134, 0, 933},\n\tdictWord{135, 11, 1147},\n\tdictWord{4, 0, 230},\n\tdictWord{133, 0, 702},\n\tdictWord{134, 0, 1728},\n\tdictWord{4, 0, 484},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t26,\n\t},\n\tdictWord{19, 0, 42},\n\tdictWord{20, 0, 43},\n\tdictWord{21, 0, 0},\n\tdictWord{23, 0, 27},\n\tdictWord{152, 0, 14},\n\tdictWord{7, 0, 185},\n\tdictWord{135, 0, 703},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t417,\n\t},\n\tdictWord{10, 0, 618},\n\tdictWord{7, 10, 1106},\n\tdictWord{9, 10, 770},\n\tdictWord{11, 10, 112},\n\tdictWord{140, 10, 413},\n\tdictWord{134, 0, 803},\n\tdictWord{132, 11, 644},\n\tdictWord{134, 0, 1262},\n\tdictWord{7, 11, 540},\n\tdictWord{12, 10, 271},\n\tdictWord{145, 10, 109},\n\tdictWord{135, 11, 123},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t633,\n\t},\n\tdictWord{134, 11, 623},\n\tdictWord{4, 11, 908},\n\tdictWord{5, 11, 359},\n\tdictWord{5, 11, 508},\n\tdictWord{6, 11, 1723},\n\tdictWord{7, 11, 343},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1996,\n\t},\n\tdictWord{135, 11, 2026},\n\tdictWord{135, 0, 479},\n\tdictWord{10, 0, 262},\n\tdictWord{7, 10, 304},\n\tdictWord{9, 10, 646},\n\tdictWord{9, 10, 862},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t696,\n\t},\n\tdictWord{12, 10, 208},\n\tdictWord{15, 10, 79},\n\tdictWord{147, 10, 108},\n\tdictWord{4, 11, 341},\n\tdictWord{135, 11, 480},\n\tdictWord{134, 0, 830},\n\tdictWord{5, 0, 70},\n\tdictWord{5, 0, 622},\n\tdictWord{6, 0, 334},\n\tdictWord{7, 0, 1032},\n\tdictWord{9, 0, 171},\n\tdictWord{11, 0, 26},\n\tdictWord{11, 0, 213},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t637,\n\t},\n\tdictWord{11, 0, 707},\n\tdictWord{12, 0, 202},\n\tdictWord{12, 0, 380},\n\tdictWord{13, 0, 226},\n\tdictWord{13, 0, 355},\n\tdictWord{14, 0, 222},\n\tdictWord{145, 0, 42},\n\tdictWord{135, 10, 981},\n\tdictWord{143, 0, 217},\n\tdictWord{137, 11, 114},\n\tdictWord{4, 0, 23},\n\tdictWord{4, 0, 141},\n\tdictWord{5, 0, 313},\n\tdictWord{5, 0, 1014},\n\tdictWord{6, 0, 50},\n\tdictWord{6, 0, 51},\n\tdictWord{7, 0, 142},\n\tdictWord{7, 0, 384},\n\tdictWord{7, 0, 559},\n\tdictWord{8, 0, 640},\n\tdictWord{9, 0, 460},\n\tdictWord{9, 0, 783},\n\tdictWord{11, 0, 741},\n\tdictWord{12, 0, 183},\n\tdictWord{141, 0, 488},\n\tdictWord{141, 0, 360},\n\tdictWord{7, 0, 1586},\n\tdictWord{7, 11, 1995},\n\tdictWord{8, 11, 299},\n\tdictWord{11, 11, 890},\n\tdictWord{140, 11, 674},\n\tdictWord{132, 10, 434},\n\tdictWord{7, 0, 652},\n\tdictWord{134, 10, 550},\n\tdictWord{7, 0, 766},\n\tdictWord{5, 10, 553},\n\tdictWord{138, 10, 824},\n\tdictWord{7, 0, 737},\n\tdictWord{8, 0, 298},\n\tdictWord{136, 10, 452},\n\tdictWord{4, 11, 238},\n\tdictWord{5, 11, 503},\n\tdictWord{6, 11, 179},\n\tdictWord{7, 11, 2003},\n\tdictWord{8, 11, 381},\n\tdictWord{8, 11, 473},\n\tdictWord{9, 11, 149},\n\tdictWord{10, 11, 183},\n\tdictWord{15, 11, 45},\n\tdictWord{143, 11, 86},\n\tdictWord{133, 10, 292},\n\tdictWord{5, 0, 222},\n\tdictWord{9, 0, 655},\n\tdictWord{138, 0, 534},\n\tdictWord{138, 10, 135},\n\tdictWord{4, 11, 121},\n\tdictWord{5, 11, 156},\n\tdictWord{5, 11, 349},\n\tdictWord{9, 11, 136},\n\tdictWord{10, 11, 605},\n\tdictWord{14, 11, 342},\n\tdictWord{147, 11, 107},\n\tdictWord{137, 0, 906},\n\tdictWord{6, 0, 1013},\n\tdictWord{134, 0, 1250},\n\tdictWord{6, 0, 1956},\n\tdictWord{6, 0, 2009},\n\tdictWord{8, 0, 991},\n\tdictWord{144, 0, 120},\n\tdictWord{135, 11, 1192},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t503,\n\t},\n\tdictWord{5, 0, 154},\n\tdictWord{7, 0, 1491},\n\tdictWord{10, 0, 379},\n\tdictWord{138, 0, 485},\n\tdictWord{6, 0, 1867},\n\tdictWord{6, 0, 1914},\n\tdictWord{6, 0, 1925},\n\tdictWord{9, 0, 917},\n\tdictWord{9, 0, 925},\n\tdictWord{9, 0, 932},\n\tdictWord{9, 0, 951},\n\tdictWord{9, 0, 1007},\n\tdictWord{9, 0, 1013},\n\tdictWord{12, 0, 806},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t810,\n\t},\n\tdictWord{12, 0, 814},\n\tdictWord{12, 0, 816},\n\tdictWord{12, 0, 824},\n\tdictWord{12, 0, 832},\n\tdictWord{12, 0, 837},\n\tdictWord{12, 0, 863},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t868,\n\t},\n\tdictWord{12, 0, 870},\n\tdictWord{12, 0, 889},\n\tdictWord{12, 0, 892},\n\tdictWord{12, 0, 900},\n\tdictWord{12, 0, 902},\n\tdictWord{12, 0, 908},\n\tdictWord{12, 0, 933},\n\tdictWord{12, 0, 942},\n\tdictWord{12, 0, 949},\n\tdictWord{12, 0, 954},\n\tdictWord{15, 0, 175},\n\tdictWord{15, 0, 203},\n\tdictWord{15, 0, 213},\n\tdictWord{15, 0, 218},\n\tdictWord{15, 0, 225},\n\tdictWord{15, 0, 231},\n\tdictWord{15, 0, 239},\n\tdictWord{15, 0, 248},\n\tdictWord{15, 0, 252},\n\tdictWord{18, 0, 190},\n\tdictWord{18, 0, 204},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t215,\n\t},\n\tdictWord{18, 0, 216},\n\tdictWord{18, 0, 222},\n\tdictWord{18, 0, 225},\n\tdictWord{18, 0, 230},\n\tdictWord{18, 0, 239},\n\tdictWord{18, 0, 241},\n\tdictWord{\n\t\t21,\n\t\t0,\n\t\t42,\n\t},\n\tdictWord{21, 0, 43},\n\tdictWord{21, 0, 44},\n\tdictWord{21, 0, 45},\n\tdictWord{21, 0, 46},\n\tdictWord{21, 0, 53},\n\tdictWord{24, 0, 27},\n\tdictWord{152, 0, 31},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t716,\n\t},\n\tdictWord{135, 0, 844},\n\tdictWord{4, 0, 91},\n\tdictWord{5, 0, 388},\n\tdictWord{5, 0, 845},\n\tdictWord{6, 0, 206},\n\tdictWord{6, 0, 252},\n\tdictWord{6, 0, 365},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t136,\n\t},\n\tdictWord{7, 0, 531},\n\tdictWord{136, 0, 621},\n\tdictWord{7, 10, 393},\n\tdictWord{10, 10, 603},\n\tdictWord{139, 10, 206},\n\tdictWord{6, 11, 80},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t1694,\n\t},\n\tdictWord{7, 11, 173},\n\tdictWord{7, 11, 1974},\n\tdictWord{9, 11, 547},\n\tdictWord{10, 11, 730},\n\tdictWord{14, 11, 18},\n\tdictWord{150, 11, 39},\n\tdictWord{137, 0, 748},\n\tdictWord{4, 11, 923},\n\tdictWord{134, 11, 1711},\n\tdictWord{4, 10, 912},\n\tdictWord{137, 10, 232},\n\tdictWord{7, 10, 98},\n\tdictWord{7, 10, 1973},\n\tdictWord{136, 10, 716},\n\tdictWord{14, 0, 103},\n\tdictWord{133, 10, 733},\n\tdictWord{132, 11, 595},\n\tdictWord{12, 0, 158},\n\tdictWord{18, 0, 8},\n\tdictWord{19, 0, 62},\n\tdictWord{20, 0, 6},\n\tdictWord{22, 0, 4},\n\tdictWord{23, 0, 2},\n\tdictWord{23, 0, 9},\n\tdictWord{5, 11, 240},\n\tdictWord{6, 11, 459},\n\tdictWord{7, 11, 12},\n\tdictWord{7, 11, 114},\n\tdictWord{7, 11, 502},\n\tdictWord{7, 11, 1751},\n\tdictWord{7, 11, 1753},\n\tdictWord{7, 11, 1805},\n\tdictWord{8, 11, 658},\n\tdictWord{9, 11, 1},\n\tdictWord{11, 11, 959},\n\tdictWord{13, 11, 446},\n\tdictWord{142, 11, 211},\n\tdictWord{135, 0, 576},\n\tdictWord{5, 0, 771},\n\tdictWord{5, 0, 863},\n\tdictWord{5, 0, 898},\n\tdictWord{6, 0, 648},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1632,\n\t},\n\tdictWord{6, 0, 1644},\n\tdictWord{134, 0, 1780},\n\tdictWord{133, 0, 331},\n\tdictWord{7, 11, 633},\n\tdictWord{7, 11, 905},\n\tdictWord{7, 11, 909},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1538,\n\t},\n\tdictWord{9, 11, 767},\n\tdictWord{140, 11, 636},\n\tdictWord{140, 0, 632},\n\tdictWord{5, 0, 107},\n\tdictWord{7, 0, 201},\n\tdictWord{136, 0, 518},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t446,\n\t},\n\tdictWord{7, 0, 1817},\n\tdictWord{134, 11, 490},\n\tdictWord{9, 0, 851},\n\tdictWord{141, 0, 510},\n\tdictWord{7, 11, 250},\n\tdictWord{8, 11, 506},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t507,\n\t},\n\tdictWord{4, 0, 504},\n\tdictWord{137, 10, 72},\n\tdictWord{132, 11, 158},\n\tdictWord{4, 11, 140},\n\tdictWord{7, 11, 362},\n\tdictWord{8, 11, 209},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t10,\n\t},\n\tdictWord{9, 11, 160},\n\tdictWord{9, 11, 503},\n\tdictWord{10, 11, 689},\n\tdictWord{11, 11, 350},\n\tdictWord{11, 11, 553},\n\tdictWord{11, 11, 725},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t252,\n\t},\n\tdictWord{12, 11, 583},\n\tdictWord{13, 11, 192},\n\tdictWord{13, 11, 352},\n\tdictWord{14, 11, 269},\n\tdictWord{14, 11, 356},\n\tdictWord{148, 11, 50},\n\tdictWord{6, 11, 597},\n\tdictWord{135, 11, 1318},\n\tdictWord{135, 10, 1454},\n\tdictWord{5, 0, 883},\n\tdictWord{5, 0, 975},\n\tdictWord{8, 0, 392},\n\tdictWord{148, 0, 7},\n\tdictWord{6, 11, 228},\n\tdictWord{7, 11, 1341},\n\tdictWord{9, 11, 408},\n\tdictWord{138, 11, 343},\n\tdictWord{11, 11, 348},\n\tdictWord{11, 10, 600},\n\tdictWord{12, 11, 99},\n\tdictWord{13, 10, 245},\n\tdictWord{18, 11, 1},\n\tdictWord{18, 11, 11},\n\tdictWord{147, 11, 4},\n\tdictWord{134, 11, 296},\n\tdictWord{5, 0, 922},\n\tdictWord{134, 0, 1707},\n\tdictWord{132, 11, 557},\n\tdictWord{4, 11, 548},\n\tdictWord{7, 10, 164},\n\tdictWord{7, 10, 1571},\n\tdictWord{9, 10, 107},\n\tdictWord{140, 10, 225},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t197,\n\t},\n\tdictWord{8, 11, 142},\n\tdictWord{8, 11, 325},\n\tdictWord{9, 11, 150},\n\tdictWord{9, 11, 596},\n\tdictWord{10, 11, 350},\n\tdictWord{10, 11, 353},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t74,\n\t},\n\tdictWord{11, 11, 315},\n\tdictWord{14, 11, 423},\n\tdictWord{143, 11, 141},\n\tdictWord{5, 0, 993},\n\tdictWord{7, 0, 515},\n\tdictWord{137, 0, 91},\n\tdictWord{4, 0, 131},\n\tdictWord{8, 0, 200},\n\tdictWord{5, 10, 484},\n\tdictWord{5, 10, 510},\n\tdictWord{6, 10, 434},\n\tdictWord{7, 10, 1000},\n\tdictWord{7, 10, 1098},\n\tdictWord{136, 10, 2},\n\tdictWord{152, 0, 10},\n\tdictWord{4, 11, 62},\n\tdictWord{5, 11, 83},\n\tdictWord{6, 11, 399},\n\tdictWord{6, 11, 579},\n\tdictWord{7, 11, 692},\n\tdictWord{7, 11, 846},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1015,\n\t},\n\tdictWord{7, 11, 1799},\n\tdictWord{8, 11, 403},\n\tdictWord{9, 11, 394},\n\tdictWord{10, 11, 133},\n\tdictWord{12, 11, 4},\n\tdictWord{12, 11, 297},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t452,\n\t},\n\tdictWord{16, 11, 81},\n\tdictWord{18, 11, 19},\n\tdictWord{18, 11, 25},\n\tdictWord{21, 11, 14},\n\tdictWord{22, 11, 12},\n\tdictWord{151, 11, 18},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t459,\n\t},\n\tdictWord{132, 11, 177},\n\tdictWord{7, 0, 1433},\n\tdictWord{9, 0, 365},\n\tdictWord{137, 11, 365},\n\tdictWord{132, 10, 460},\n\tdictWord{5, 0, 103},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t2004,\n\t},\n\tdictWord{7, 0, 921},\n\tdictWord{8, 0, 580},\n\tdictWord{8, 0, 593},\n\tdictWord{8, 0, 630},\n\tdictWord{10, 0, 28},\n\tdictWord{5, 11, 411},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t653,\n\t},\n\tdictWord{4, 10, 932},\n\tdictWord{133, 10, 891},\n\tdictWord{4, 0, 911},\n\tdictWord{5, 0, 867},\n\tdictWord{5, 0, 1013},\n\tdictWord{7, 0, 2034},\n\tdictWord{8, 0, 798},\n\tdictWord{136, 0, 813},\n\tdictWord{7, 11, 439},\n\tdictWord{10, 11, 727},\n\tdictWord{11, 11, 260},\n\tdictWord{139, 11, 684},\n\tdictWord{136, 10, 625},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t208,\n\t},\n\tdictWord{7, 11, 753},\n\tdictWord{135, 11, 1528},\n\tdictWord{5, 0, 461},\n\tdictWord{7, 0, 1925},\n\tdictWord{12, 0, 39},\n\tdictWord{13, 0, 265},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t439,\n\t},\n\tdictWord{134, 10, 76},\n\tdictWord{6, 0, 853},\n\tdictWord{8, 10, 92},\n\tdictWord{137, 10, 221},\n\tdictWord{5, 0, 135},\n\tdictWord{6, 0, 519},\n\tdictWord{7, 0, 1722},\n\tdictWord{10, 0, 271},\n\tdictWord{11, 0, 261},\n\tdictWord{145, 0, 54},\n\tdictWord{139, 11, 814},\n\tdictWord{14, 0, 338},\n\tdictWord{148, 0, 81},\n\tdictWord{4, 0, 300},\n\tdictWord{133, 0, 436},\n\tdictWord{5, 0, 419},\n\tdictWord{5, 0, 687},\n\tdictWord{7, 0, 864},\n\tdictWord{9, 0, 470},\n\tdictWord{135, 11, 864},\n\tdictWord{9, 0, 836},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t242,\n\t},\n\tdictWord{134, 0, 1937},\n\tdictWord{4, 10, 763},\n\tdictWord{133, 11, 953},\n\tdictWord{132, 10, 622},\n\tdictWord{132, 0, 393},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t253,\n\t},\n\tdictWord{8, 0, 357},\n\tdictWord{10, 0, 745},\n\tdictWord{14, 0, 426},\n\tdictWord{17, 0, 94},\n\tdictWord{19, 0, 57},\n\tdictWord{135, 10, 546},\n\tdictWord{5, 11, 615},\n\tdictWord{146, 11, 37},\n\tdictWord{9, 10, 73},\n\tdictWord{10, 10, 110},\n\tdictWord{14, 10, 185},\n\tdictWord{145, 10, 119},\n\tdictWord{11, 0, 703},\n\tdictWord{7, 10, 624},\n\tdictWord{7, 10, 916},\n\tdictWord{10, 10, 256},\n\tdictWord{139, 10, 87},\n\tdictWord{133, 11, 290},\n\tdictWord{5, 10, 212},\n\tdictWord{12, 10, 35},\n\tdictWord{\n\t\t141,\n\t\t10,\n\t\t382,\n\t},\n\tdictWord{132, 11, 380},\n\tdictWord{5, 11, 52},\n\tdictWord{7, 11, 277},\n\tdictWord{9, 11, 368},\n\tdictWord{139, 11, 791},\n\tdictWord{133, 0, 387},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t138,\n\t},\n\tdictWord{139, 11, 476},\n\tdictWord{4, 0, 6},\n\tdictWord{5, 0, 708},\n\tdictWord{136, 0, 75},\n\tdictWord{7, 0, 1351},\n\tdictWord{9, 0, 581},\n\tdictWord{10, 0, 639},\n\tdictWord{11, 0, 453},\n\tdictWord{140, 0, 584},\n\tdictWord{132, 0, 303},\n\tdictWord{138, 0, 772},\n\tdictWord{135, 10, 1175},\n\tdictWord{4, 0, 749},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t816,\n\t},\n\tdictWord{6, 11, 256},\n\tdictWord{7, 11, 307},\n\tdictWord{7, 11, 999},\n\tdictWord{7, 11, 1481},\n\tdictWord{7, 11, 1732},\n\tdictWord{7, 11, 1738},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t265,\n\t},\n\tdictWord{9, 11, 414},\n\tdictWord{11, 11, 316},\n\tdictWord{12, 11, 52},\n\tdictWord{13, 11, 420},\n\tdictWord{147, 11, 100},\n\tdictWord{135, 11, 1296},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1065,\n\t},\n\tdictWord{5, 10, 869},\n\tdictWord{5, 10, 968},\n\tdictWord{6, 10, 1626},\n\tdictWord{8, 10, 734},\n\tdictWord{136, 10, 784},\n\tdictWord{4, 10, 542},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t1716,\n\t},\n\tdictWord{6, 10, 1727},\n\tdictWord{7, 10, 1082},\n\tdictWord{7, 10, 1545},\n\tdictWord{8, 10, 56},\n\tdictWord{8, 10, 118},\n\tdictWord{8, 10, 412},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t564,\n\t},\n\tdictWord{9, 10, 888},\n\tdictWord{9, 10, 908},\n\tdictWord{10, 10, 50},\n\tdictWord{10, 10, 423},\n\tdictWord{11, 10, 685},\n\tdictWord{11, 10, 697},\n\tdictWord{11, 10, 933},\n\tdictWord{12, 10, 299},\n\tdictWord{13, 10, 126},\n\tdictWord{13, 10, 136},\n\tdictWord{13, 10, 170},\n\tdictWord{141, 10, 190},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t226,\n\t},\n\tdictWord{4, 0, 106},\n\tdictWord{7, 0, 310},\n\tdictWord{11, 0, 717},\n\tdictWord{133, 11, 723},\n\tdictWord{5, 0, 890},\n\tdictWord{5, 0, 988},\n\tdictWord{4, 10, 232},\n\tdictWord{9, 10, 202},\n\tdictWord{10, 10, 474},\n\tdictWord{140, 10, 433},\n\tdictWord{6, 0, 626},\n\tdictWord{142, 0, 431},\n\tdictWord{10, 0, 706},\n\tdictWord{150, 0, 44},\n\tdictWord{13, 0, 51},\n\tdictWord{6, 10, 108},\n\tdictWord{7, 10, 1003},\n\tdictWord{7, 10, 1181},\n\tdictWord{8, 10, 111},\n\tdictWord{136, 10, 343},\n\tdictWord{132, 0, 698},\n\tdictWord{5, 11, 109},\n\tdictWord{6, 11, 1784},\n\tdictWord{7, 11, 1895},\n\tdictWord{12, 11, 296},\n\tdictWord{140, 11, 302},\n\tdictWord{134, 0, 828},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1712,\n\t},\n\tdictWord{138, 0, 17},\n\tdictWord{7, 0, 1929},\n\tdictWord{4, 10, 133},\n\tdictWord{5, 11, 216},\n\tdictWord{7, 10, 711},\n\tdictWord{7, 10, 1298},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1585,\n\t},\n\tdictWord{7, 11, 1879},\n\tdictWord{9, 11, 141},\n\tdictWord{9, 11, 270},\n\tdictWord{9, 11, 679},\n\tdictWord{10, 11, 159},\n\tdictWord{10, 11, 553},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t197,\n\t},\n\tdictWord{11, 11, 438},\n\tdictWord{12, 11, 538},\n\tdictWord{12, 11, 559},\n\tdictWord{13, 11, 193},\n\tdictWord{13, 11, 423},\n\tdictWord{14, 11, 144},\n\tdictWord{14, 11, 166},\n\tdictWord{14, 11, 167},\n\tdictWord{15, 11, 67},\n\tdictWord{147, 11, 84},\n\tdictWord{141, 11, 127},\n\tdictWord{7, 11, 1872},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t81,\n\t},\n\tdictWord{6, 10, 99},\n\tdictWord{7, 10, 1808},\n\tdictWord{145, 10, 57},\n\tdictWord{134, 11, 391},\n\tdictWord{5, 0, 689},\n\tdictWord{6, 0, 84},\n\tdictWord{7, 0, 1250},\n\tdictWord{6, 10, 574},\n\tdictWord{7, 10, 428},\n\tdictWord{10, 10, 669},\n\tdictWord{11, 10, 485},\n\tdictWord{11, 10, 840},\n\tdictWord{12, 10, 300},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t250,\n\t},\n\tdictWord{7, 11, 322},\n\tdictWord{136, 11, 249},\n\tdictWord{7, 11, 432},\n\tdictWord{135, 11, 1649},\n\tdictWord{135, 10, 1871},\n\tdictWord{137, 10, 252},\n\tdictWord{6, 11, 155},\n\tdictWord{140, 11, 234},\n\tdictWord{7, 0, 871},\n\tdictWord{19, 0, 27},\n\tdictWord{147, 11, 27},\n\tdictWord{140, 0, 498},\n\tdictWord{5, 0, 986},\n\tdictWord{6, 0, 130},\n\tdictWord{138, 0, 823},\n\tdictWord{6, 0, 1793},\n\tdictWord{7, 0, 1582},\n\tdictWord{8, 0, 458},\n\tdictWord{10, 0, 101},\n\tdictWord{10, 0, 318},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t945,\n\t},\n\tdictWord{12, 0, 734},\n\tdictWord{16, 0, 104},\n\tdictWord{18, 0, 177},\n\tdictWord{6, 10, 323},\n\tdictWord{135, 10, 1564},\n\tdictWord{5, 11, 632},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t526,\n\t},\n\tdictWord{10, 0, 435},\n\tdictWord{7, 10, 461},\n\tdictWord{136, 10, 775},\n\tdictWord{6, 11, 144},\n\tdictWord{7, 11, 948},\n\tdictWord{7, 11, 1042},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1857,\n\t},\n\tdictWord{8, 11, 235},\n\tdictWord{8, 11, 461},\n\tdictWord{9, 11, 453},\n\tdictWord{9, 11, 530},\n\tdictWord{10, 11, 354},\n\tdictWord{17, 11, 77},\n\tdictWord{\n\t\t19,\n\t\t11,\n\t\t99,\n\t},\n\tdictWord{148, 11, 79},\n\tdictWord{138, 0, 966},\n\tdictWord{7, 0, 1644},\n\tdictWord{137, 0, 129},\n\tdictWord{135, 0, 997},\n\tdictWord{136, 0, 502},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t196,\n\t},\n\tdictWord{6, 11, 486},\n\tdictWord{7, 11, 212},\n\tdictWord{8, 11, 309},\n\tdictWord{136, 11, 346},\n\tdictWord{7, 10, 727},\n\tdictWord{146, 10, 73},\n\tdictWord{132, 0, 823},\n\tdictWord{132, 11, 686},\n\tdictWord{135, 0, 1927},\n\tdictWord{4, 0, 762},\n\tdictWord{7, 0, 1756},\n\tdictWord{137, 0, 98},\n\tdictWord{136, 10, 577},\n\tdictWord{24, 0, 8},\n\tdictWord{4, 11, 30},\n\tdictWord{5, 11, 43},\n\tdictWord{152, 11, 8},\n\tdictWord{7, 0, 1046},\n\tdictWord{139, 0, 160},\n\tdictWord{7, 0, 492},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t413,\n\t},\n\tdictWord{5, 10, 677},\n\tdictWord{7, 11, 492},\n\tdictWord{8, 10, 432},\n\tdictWord{140, 10, 280},\n\tdictWord{6, 0, 45},\n\tdictWord{7, 0, 433},\n\tdictWord{8, 0, 129},\n\tdictWord{9, 0, 21},\n\tdictWord{10, 0, 392},\n\tdictWord{11, 0, 79},\n\tdictWord{12, 0, 499},\n\tdictWord{13, 0, 199},\n\tdictWord{141, 0, 451},\n\tdictWord{7, 0, 558},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t353,\n\t},\n\tdictWord{4, 11, 220},\n\tdictWord{7, 11, 1535},\n\tdictWord{9, 11, 93},\n\tdictWord{139, 11, 474},\n\tdictWord{7, 10, 646},\n\tdictWord{7, 10, 1730},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t446,\n\t},\n\tdictWord{141, 10, 178},\n\tdictWord{133, 0, 785},\n\tdictWord{134, 0, 1145},\n\tdictWord{8, 0, 81},\n\tdictWord{9, 0, 189},\n\tdictWord{9, 0, 201},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t478,\n\t},\n\tdictWord{11, 0, 712},\n\tdictWord{141, 0, 338},\n\tdictWord{5, 0, 353},\n\tdictWord{151, 0, 26},\n\tdictWord{11, 0, 762},\n\tdictWord{132, 10, 395},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t2024,\n\t},\n\tdictWord{4, 0, 611},\n\tdictWord{133, 0, 606},\n\tdictWord{9, 10, 174},\n\tdictWord{10, 10, 164},\n\tdictWord{11, 10, 440},\n\tdictWord{11, 10, 841},\n\tdictWord{\n\t\t143,\n\t\t10,\n\t\t98,\n\t},\n\tdictWord{134, 10, 426},\n\tdictWord{10, 10, 608},\n\tdictWord{139, 10, 1002},\n\tdictWord{138, 10, 250},\n\tdictWord{6, 0, 25},\n\tdictWord{7, 0, 855},\n\tdictWord{7, 0, 1258},\n\tdictWord{144, 0, 32},\n\tdictWord{7, 11, 1725},\n\tdictWord{138, 11, 393},\n\tdictWord{5, 11, 263},\n\tdictWord{134, 11, 414},\n\tdictWord{6, 0, 2011},\n\tdictWord{133, 10, 476},\n\tdictWord{4, 0, 4},\n\tdictWord{7, 0, 1118},\n\tdictWord{7, 0, 1320},\n\tdictWord{7, 0, 1706},\n\tdictWord{8, 0, 277},\n\tdictWord{9, 0, 622},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t9,\n\t},\n\tdictWord{11, 0, 724},\n\tdictWord{12, 0, 350},\n\tdictWord{12, 0, 397},\n\tdictWord{13, 0, 28},\n\tdictWord{13, 0, 159},\n\tdictWord{15, 0, 89},\n\tdictWord{18, 0, 5},\n\tdictWord{\n\t\t19,\n\t\t0,\n\t\t9,\n\t},\n\tdictWord{20, 0, 34},\n\tdictWord{22, 0, 47},\n\tdictWord{6, 11, 178},\n\tdictWord{6, 11, 1750},\n\tdictWord{8, 11, 251},\n\tdictWord{9, 11, 690},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t155,\n\t},\n\tdictWord{10, 11, 196},\n\tdictWord{10, 11, 373},\n\tdictWord{11, 11, 698},\n\tdictWord{13, 11, 155},\n\tdictWord{148, 11, 93},\n\tdictWord{5, 11, 97},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t393,\n\t},\n\tdictWord{7, 0, 764},\n\tdictWord{11, 0, 461},\n\tdictWord{12, 0, 172},\n\tdictWord{5, 10, 76},\n\tdictWord{6, 10, 458},\n\tdictWord{6, 10, 497},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t868,\n\t},\n\tdictWord{9, 10, 658},\n\tdictWord{10, 10, 594},\n\tdictWord{11, 10, 566},\n\tdictWord{12, 10, 338},\n\tdictWord{141, 10, 200},\n\tdictWord{134, 0, 1449},\n\tdictWord{138, 11, 40},\n\tdictWord{134, 11, 1639},\n\tdictWord{134, 0, 1445},\n\tdictWord{6, 0, 1168},\n\tdictWord{4, 10, 526},\n\tdictWord{7, 10, 1029},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1054,\n\t},\n\tdictWord{4, 11, 191},\n\tdictWord{7, 11, 934},\n\tdictWord{8, 11, 647},\n\tdictWord{145, 11, 97},\n\tdictWord{132, 10, 636},\n\tdictWord{6, 0, 233},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t660,\n\t},\n\tdictWord{7, 10, 1124},\n\tdictWord{17, 10, 31},\n\tdictWord{19, 10, 22},\n\tdictWord{151, 10, 14},\n\tdictWord{6, 10, 1699},\n\tdictWord{136, 11, 110},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t246,\n\t},\n\tdictWord{15, 11, 162},\n\tdictWord{19, 11, 64},\n\tdictWord{20, 11, 8},\n\tdictWord{20, 11, 95},\n\tdictWord{22, 11, 24},\n\tdictWord{152, 11, 17},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t165,\n\t},\n\tdictWord{9, 11, 346},\n\tdictWord{138, 11, 655},\n\tdictWord{5, 11, 319},\n\tdictWord{135, 11, 534},\n\tdictWord{134, 0, 255},\n\tdictWord{9, 0, 216},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t128,\n\t},\n\tdictWord{139, 11, 179},\n\tdictWord{9, 0, 183},\n\tdictWord{139, 0, 286},\n\tdictWord{11, 0, 956},\n\tdictWord{151, 0, 3},\n\tdictWord{4, 0, 536},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1141,\n\t},\n\tdictWord{10, 0, 723},\n\tdictWord{139, 0, 371},\n\tdictWord{4, 10, 279},\n\tdictWord{7, 10, 301},\n\tdictWord{137, 10, 362},\n\tdictWord{7, 0, 285},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t57,\n\t},\n\tdictWord{6, 11, 101},\n\tdictWord{6, 11, 1663},\n\tdictWord{7, 11, 132},\n\tdictWord{7, 11, 1048},\n\tdictWord{7, 11, 1154},\n\tdictWord{7, 11, 1415},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1507,\n\t},\n\tdictWord{12, 11, 493},\n\tdictWord{15, 11, 105},\n\tdictWord{151, 11, 15},\n\tdictWord{5, 11, 459},\n\tdictWord{7, 11, 1073},\n\tdictWord{7, 10, 1743},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t241,\n\t},\n\tdictWord{136, 11, 334},\n\tdictWord{4, 10, 178},\n\tdictWord{133, 10, 399},\n\tdictWord{135, 0, 560},\n\tdictWord{132, 0, 690},\n\tdictWord{135, 0, 1246},\n\tdictWord{18, 0, 157},\n\tdictWord{147, 0, 63},\n\tdictWord{10, 0, 599},\n\tdictWord{11, 0, 33},\n\tdictWord{12, 0, 571},\n\tdictWord{149, 0, 1},\n\tdictWord{6, 11, 324},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t520,\n\t},\n\tdictWord{7, 11, 338},\n\tdictWord{7, 11, 1616},\n\tdictWord{7, 11, 1729},\n\tdictWord{8, 11, 228},\n\tdictWord{9, 11, 69},\n\tdictWord{139, 11, 750},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1862,\n\t},\n\tdictWord{12, 0, 491},\n\tdictWord{12, 0, 520},\n\tdictWord{13, 0, 383},\n\tdictWord{142, 0, 244},\n\tdictWord{135, 11, 734},\n\tdictWord{134, 10, 1692},\n\tdictWord{10, 0, 448},\n\tdictWord{11, 0, 630},\n\tdictWord{17, 0, 117},\n\tdictWord{6, 10, 202},\n\tdictWord{7, 11, 705},\n\tdictWord{12, 10, 360},\n\tdictWord{17, 10, 118},\n\tdictWord{18, 10, 27},\n\tdictWord{148, 10, 67},\n\tdictWord{4, 11, 73},\n\tdictWord{6, 11, 612},\n\tdictWord{7, 11, 927},\n\tdictWord{7, 11, 1822},\n\tdictWord{8, 11, 217},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t472,\n\t},\n\tdictWord{9, 11, 765},\n\tdictWord{9, 11, 766},\n\tdictWord{10, 11, 408},\n\tdictWord{11, 11, 51},\n\tdictWord{11, 11, 793},\n\tdictWord{12, 11, 266},\n\tdictWord{\n\t\t15,\n\t\t11,\n\t\t158,\n\t},\n\tdictWord{20, 11, 89},\n\tdictWord{150, 11, 32},\n\tdictWord{4, 0, 190},\n\tdictWord{133, 0, 554},\n\tdictWord{133, 0, 1001},\n\tdictWord{5, 11, 389},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t636,\n\t},\n\tdictWord{137, 11, 229},\n\tdictWord{5, 0, 446},\n\tdictWord{7, 10, 872},\n\tdictWord{10, 10, 516},\n\tdictWord{139, 10, 167},\n\tdictWord{137, 10, 313},\n\tdictWord{132, 10, 224},\n\tdictWord{134, 0, 1313},\n\tdictWord{5, 10, 546},\n\tdictWord{7, 10, 35},\n\tdictWord{8, 10, 11},\n\tdictWord{8, 10, 12},\n\tdictWord{9, 10, 315},\n\tdictWord{9, 10, 533},\n\tdictWord{10, 10, 802},\n\tdictWord{11, 10, 166},\n\tdictWord{12, 10, 525},\n\tdictWord{142, 10, 243},\n\tdictWord{6, 0, 636},\n\tdictWord{137, 0, 837},\n\tdictWord{5, 10, 241},\n\tdictWord{8, 10, 242},\n\tdictWord{9, 10, 451},\n\tdictWord{10, 10, 667},\n\tdictWord{11, 10, 598},\n\tdictWord{140, 10, 429},\n\tdictWord{22, 10, 46},\n\tdictWord{150, 11, 46},\n\tdictWord{136, 11, 472},\n\tdictWord{11, 0, 278},\n\tdictWord{142, 0, 73},\n\tdictWord{141, 11, 185},\n\tdictWord{132, 0, 868},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t972,\n\t},\n\tdictWord{4, 10, 366},\n\tdictWord{137, 10, 516},\n\tdictWord{138, 0, 1010},\n\tdictWord{5, 11, 189},\n\tdictWord{6, 10, 1736},\n\tdictWord{7, 11, 442},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t443,\n\t},\n\tdictWord{8, 11, 281},\n\tdictWord{12, 11, 174},\n\tdictWord{13, 11, 83},\n\tdictWord{141, 11, 261},\n\tdictWord{139, 11, 384},\n\tdictWord{6, 11, 2},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t191,\n\t},\n\tdictWord{7, 11, 446},\n\tdictWord{7, 11, 758},\n\tdictWord{7, 11, 1262},\n\tdictWord{7, 11, 1737},\n\tdictWord{8, 11, 22},\n\tdictWord{8, 11, 270},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t612,\n\t},\n\tdictWord{9, 11, 4},\n\tdictWord{9, 11, 167},\n\tdictWord{9, 11, 312},\n\tdictWord{9, 11, 436},\n\tdictWord{10, 11, 156},\n\tdictWord{10, 11, 216},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t311,\n\t},\n\tdictWord{10, 11, 623},\n\tdictWord{11, 11, 72},\n\tdictWord{11, 11, 330},\n\tdictWord{11, 11, 455},\n\tdictWord{12, 11, 101},\n\tdictWord{12, 11, 321},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t504,\n\t},\n\tdictWord{12, 11, 530},\n\tdictWord{12, 11, 543},\n\tdictWord{13, 11, 17},\n\tdictWord{13, 11, 156},\n\tdictWord{13, 11, 334},\n\tdictWord{14, 11, 48},\n\tdictWord{15, 11, 70},\n\tdictWord{17, 11, 60},\n\tdictWord{148, 11, 64},\n\tdictWord{6, 10, 331},\n\tdictWord{136, 10, 623},\n\tdictWord{135, 0, 1231},\n\tdictWord{132, 0, 304},\n\tdictWord{6, 11, 60},\n\tdictWord{7, 11, 670},\n\tdictWord{7, 11, 1327},\n\tdictWord{8, 11, 411},\n\tdictWord{8, 11, 435},\n\tdictWord{9, 11, 653},\n\tdictWord{9, 11, 740},\n\tdictWord{10, 11, 385},\n\tdictWord{11, 11, 222},\n\tdictWord{11, 11, 324},\n\tdictWord{11, 11, 829},\n\tdictWord{140, 11, 611},\n\tdictWord{7, 0, 506},\n\tdictWord{6, 11, 166},\n\tdictWord{7, 11, 374},\n\tdictWord{135, 11, 1174},\n\tdictWord{14, 11, 43},\n\tdictWord{146, 11, 21},\n\tdictWord{135, 11, 1694},\n\tdictWord{135, 10, 1888},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t206,\n\t},\n\tdictWord{134, 11, 398},\n\tdictWord{135, 11, 50},\n\tdictWord{150, 0, 26},\n\tdictWord{6, 0, 53},\n\tdictWord{6, 0, 199},\n\tdictWord{7, 0, 1408},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t32,\n\t},\n\tdictWord{8, 0, 93},\n\tdictWord{10, 0, 397},\n\tdictWord{10, 0, 629},\n\tdictWord{11, 0, 593},\n\tdictWord{11, 0, 763},\n\tdictWord{13, 0, 326},\n\tdictWord{145, 0, 35},\n\tdictWord{134, 0, 105},\n\tdictWord{132, 10, 394},\n\tdictWord{4, 0, 843},\n\tdictWord{138, 0, 794},\n\tdictWord{11, 0, 704},\n\tdictWord{141, 0, 396},\n\tdictWord{5, 0, 114},\n\tdictWord{5, 0, 255},\n\tdictWord{141, 0, 285},\n\tdictWord{6, 0, 619},\n\tdictWord{7, 0, 898},\n\tdictWord{7, 0, 1092},\n\tdictWord{8, 0, 485},\n\tdictWord{18, 0, 28},\n\tdictWord{\n\t\t19,\n\t\t0,\n\t\t116,\n\t},\n\tdictWord{135, 10, 1931},\n\tdictWord{9, 0, 145},\n\tdictWord{7, 10, 574},\n\tdictWord{135, 10, 1719},\n\tdictWord{7, 0, 2035},\n\tdictWord{8, 0, 19},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t89,\n\t},\n\tdictWord{138, 0, 831},\n\tdictWord{132, 10, 658},\n\tdictWord{6, 11, 517},\n\tdictWord{7, 11, 1159},\n\tdictWord{10, 11, 621},\n\tdictWord{139, 11, 192},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1933,\n\t},\n\tdictWord{7, 11, 1933},\n\tdictWord{9, 10, 781},\n\tdictWord{10, 10, 144},\n\tdictWord{11, 10, 385},\n\tdictWord{13, 10, 161},\n\tdictWord{13, 10, 228},\n\tdictWord{13, 10, 268},\n\tdictWord{148, 10, 107},\n\tdictWord{136, 10, 374},\n\tdictWord{10, 11, 223},\n\tdictWord{139, 11, 645},\n\tdictWord{135, 0, 1728},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t64,\n\t},\n\tdictWord{7, 11, 289},\n\tdictWord{136, 11, 245},\n\tdictWord{4, 10, 344},\n\tdictWord{6, 10, 498},\n\tdictWord{139, 10, 323},\n\tdictWord{136, 0, 746},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1063,\n\t},\n\tdictWord{137, 10, 155},\n\tdictWord{4, 0, 987},\n\tdictWord{6, 0, 1964},\n\tdictWord{6, 0, 1974},\n\tdictWord{6, 0, 1990},\n\tdictWord{136, 0, 995},\n\tdictWord{133, 11, 609},\n\tdictWord{133, 10, 906},\n\tdictWord{134, 0, 1550},\n\tdictWord{134, 0, 874},\n\tdictWord{5, 11, 129},\n\tdictWord{6, 11, 61},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t947,\n\t},\n\tdictWord{4, 0, 1018},\n\tdictWord{6, 0, 1938},\n\tdictWord{6, 0, 2021},\n\tdictWord{134, 0, 2039},\n\tdictWord{132, 0, 814},\n\tdictWord{11, 0, 126},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t287,\n\t},\n\tdictWord{134, 0, 1264},\n\tdictWord{5, 0, 955},\n\tdictWord{136, 0, 814},\n\tdictWord{141, 11, 506},\n\tdictWord{132, 11, 314},\n\tdictWord{6, 0, 981},\n\tdictWord{139, 11, 1000},\n\tdictWord{5, 0, 56},\n\tdictWord{8, 0, 892},\n\tdictWord{8, 0, 915},\n\tdictWord{140, 0, 776},\n\tdictWord{148, 0, 100},\n\tdictWord{10, 0, 4},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t13,\n\t},\n\tdictWord{11, 0, 638},\n\tdictWord{148, 0, 57},\n\tdictWord{148, 11, 74},\n\tdictWord{5, 0, 738},\n\tdictWord{132, 10, 616},\n\tdictWord{133, 11, 637},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t692,\n\t},\n\tdictWord{133, 0, 758},\n\tdictWord{132, 10, 305},\n\tdictWord{137, 11, 590},\n\tdictWord{5, 11, 280},\n\tdictWord{135, 11, 1226},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t494,\n\t},\n\tdictWord{135, 0, 1112},\n\tdictWord{133, 11, 281},\n\tdictWord{13, 0, 44},\n\tdictWord{14, 0, 214},\n\tdictWord{5, 10, 214},\n\tdictWord{7, 10, 603},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t611,\n\t},\n\tdictWord{9, 10, 686},\n\tdictWord{10, 10, 88},\n\tdictWord{11, 10, 459},\n\tdictWord{11, 10, 496},\n\tdictWord{12, 10, 463},\n\tdictWord{140, 10, 590},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t328,\n\t},\n\tdictWord{135, 11, 1064},\n\tdictWord{137, 0, 133},\n\tdictWord{7, 0, 168},\n\tdictWord{13, 0, 196},\n\tdictWord{141, 0, 237},\n\tdictWord{134, 10, 1703},\n\tdictWord{134, 0, 1152},\n\tdictWord{135, 0, 1245},\n\tdictWord{5, 0, 110},\n\tdictWord{6, 0, 169},\n\tdictWord{6, 0, 1702},\n\tdictWord{7, 0, 400},\n\tdictWord{8, 0, 538},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t184,\n\t},\n\tdictWord{9, 0, 524},\n\tdictWord{140, 0, 218},\n\tdictWord{6, 0, 1816},\n\tdictWord{10, 0, 871},\n\tdictWord{12, 0, 769},\n\tdictWord{140, 0, 785},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t630,\n\t},\n\tdictWord{7, 11, 33},\n\tdictWord{7, 11, 120},\n\tdictWord{8, 11, 489},\n\tdictWord{9, 11, 319},\n\tdictWord{10, 11, 820},\n\tdictWord{11, 11, 1004},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t379,\n\t},\n\tdictWord{13, 11, 117},\n\tdictWord{13, 11, 412},\n\tdictWord{14, 11, 25},\n\tdictWord{15, 11, 52},\n\tdictWord{15, 11, 161},\n\tdictWord{16, 11, 47},\n\tdictWord{149, 11, 2},\n\tdictWord{6, 0, 133},\n\tdictWord{8, 0, 413},\n\tdictWord{9, 0, 353},\n\tdictWord{139, 0, 993},\n\tdictWord{145, 10, 19},\n\tdictWord{4, 11, 937},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t801,\n\t},\n\tdictWord{134, 0, 978},\n\tdictWord{6, 0, 93},\n\tdictWord{6, 0, 1508},\n\tdictWord{7, 0, 1422},\n\tdictWord{7, 0, 1851},\n\tdictWord{8, 0, 673},\n\tdictWord{9, 0, 529},\n\tdictWord{140, 0, 43},\n\tdictWord{6, 0, 317},\n\tdictWord{10, 0, 512},\n\tdictWord{4, 10, 737},\n\tdictWord{11, 10, 294},\n\tdictWord{12, 10, 60},\n\tdictWord{12, 10, 437},\n\tdictWord{13, 10, 64},\n\tdictWord{13, 10, 380},\n\tdictWord{142, 10, 430},\n\tdictWord{9, 0, 371},\n\tdictWord{7, 11, 1591},\n\tdictWord{144, 11, 43},\n\tdictWord{6, 10, 1758},\n\tdictWord{8, 10, 520},\n\tdictWord{9, 10, 345},\n\tdictWord{9, 10, 403},\n\tdictWord{142, 10, 350},\n\tdictWord{5, 0, 526},\n\tdictWord{10, 10, 242},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t579,\n\t},\n\tdictWord{9, 0, 25},\n\tdictWord{10, 0, 467},\n\tdictWord{138, 0, 559},\n\tdictWord{5, 10, 139},\n\tdictWord{7, 10, 1168},\n\tdictWord{138, 10, 539},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t335,\n\t},\n\tdictWord{135, 0, 942},\n\tdictWord{140, 0, 754},\n\tdictWord{132, 11, 365},\n\tdictWord{11, 0, 182},\n\tdictWord{142, 0, 195},\n\tdictWord{142, 11, 29},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t7,\n\t},\n\tdictWord{139, 11, 774},\n\tdictWord{4, 11, 746},\n\tdictWord{135, 11, 1090},\n\tdictWord{8, 0, 39},\n\tdictWord{10, 0, 773},\n\tdictWord{11, 0, 84},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t205,\n\t},\n\tdictWord{142, 0, 1},\n\tdictWord{5, 0, 601},\n\tdictWord{5, 0, 870},\n\tdictWord{5, 11, 360},\n\tdictWord{136, 11, 237},\n\tdictWord{132, 0, 181},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t370,\n\t},\n\tdictWord{134, 0, 1652},\n\tdictWord{8, 0, 358},\n\tdictWord{4, 10, 107},\n\tdictWord{7, 10, 613},\n\tdictWord{8, 10, 439},\n\tdictWord{8, 10, 504},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t501,\n\t},\n\tdictWord{10, 10, 383},\n\tdictWord{139, 10, 477},\n\tdictWord{132, 10, 229},\n\tdictWord{137, 11, 785},\n\tdictWord{4, 0, 97},\n\tdictWord{5, 0, 147},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t286,\n\t},\n\tdictWord{7, 0, 1362},\n\tdictWord{141, 0, 176},\n\tdictWord{6, 0, 537},\n\tdictWord{7, 0, 788},\n\tdictWord{7, 0, 1816},\n\tdictWord{132, 10, 903},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t71,\n\t},\n\tdictWord{6, 0, 743},\n\tdictWord{134, 0, 1223},\n\tdictWord{6, 0, 375},\n\tdictWord{7, 0, 169},\n\tdictWord{7, 0, 254},\n\tdictWord{8, 0, 780},\n\tdictWord{135, 11, 1493},\n\tdictWord{7, 0, 1714},\n\tdictWord{4, 10, 47},\n\tdictWord{6, 10, 373},\n\tdictWord{7, 10, 452},\n\tdictWord{7, 10, 543},\n\tdictWord{7, 10, 1856},\n\tdictWord{9, 10, 6},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t257,\n\t},\n\tdictWord{139, 10, 391},\n\tdictWord{6, 0, 896},\n\tdictWord{136, 0, 1003},\n\tdictWord{135, 0, 1447},\n\tdictWord{137, 11, 341},\n\tdictWord{5, 10, 980},\n\tdictWord{134, 10, 1754},\n\tdictWord{145, 11, 22},\n\tdictWord{4, 11, 277},\n\tdictWord{5, 11, 608},\n\tdictWord{6, 11, 493},\n\tdictWord{7, 11, 457},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t384,\n\t},\n\tdictWord{7, 10, 536},\n\tdictWord{7, 10, 1331},\n\tdictWord{136, 10, 143},\n\tdictWord{140, 0, 744},\n\tdictWord{7, 11, 27},\n\tdictWord{135, 11, 316},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t126,\n\t},\n\tdictWord{5, 10, 19},\n\tdictWord{134, 10, 533},\n\tdictWord{4, 0, 788},\n\tdictWord{11, 0, 41},\n\tdictWord{5, 11, 552},\n\tdictWord{5, 11, 586},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t676,\n\t},\n\tdictWord{6, 11, 448},\n\tdictWord{8, 11, 244},\n\tdictWord{11, 11, 1},\n\tdictWord{11, 11, 41},\n\tdictWord{13, 11, 3},\n\tdictWord{16, 11, 54},\n\tdictWord{17, 11, 4},\n\tdictWord{146, 11, 13},\n\tdictWord{4, 0, 985},\n\tdictWord{6, 0, 1801},\n\tdictWord{4, 11, 401},\n\tdictWord{137, 11, 264},\n\tdictWord{5, 10, 395},\n\tdictWord{5, 10, 951},\n\tdictWord{134, 10, 1776},\n\tdictWord{5, 0, 629},\n\tdictWord{135, 0, 1549},\n\tdictWord{11, 10, 663},\n\tdictWord{12, 10, 210},\n\tdictWord{13, 10, 166},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t310,\n\t},\n\tdictWord{14, 10, 373},\n\tdictWord{147, 10, 43},\n\tdictWord{9, 11, 543},\n\tdictWord{10, 11, 524},\n\tdictWord{11, 11, 30},\n\tdictWord{12, 11, 524},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t315,\n\t},\n\tdictWord{16, 11, 18},\n\tdictWord{20, 11, 26},\n\tdictWord{148, 11, 65},\n\tdictWord{4, 11, 205},\n\tdictWord{5, 11, 623},\n\tdictWord{7, 11, 104},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t519,\n\t},\n\tdictWord{5, 0, 293},\n\tdictWord{134, 0, 601},\n\tdictWord{7, 11, 579},\n\tdictWord{9, 11, 41},\n\tdictWord{9, 11, 244},\n\tdictWord{9, 11, 669},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t5,\n\t},\n\tdictWord{11, 11, 861},\n\tdictWord{11, 11, 951},\n\tdictWord{139, 11, 980},\n\tdictWord{132, 11, 717},\n\tdictWord{132, 10, 695},\n\tdictWord{7, 10, 497},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t387,\n\t},\n\tdictWord{147, 10, 81},\n\tdictWord{132, 0, 420},\n\tdictWord{142, 0, 37},\n\tdictWord{6, 0, 1134},\n\tdictWord{6, 0, 1900},\n\tdictWord{12, 0, 830},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t878,\n\t},\n\tdictWord{12, 0, 894},\n\tdictWord{15, 0, 221},\n\tdictWord{143, 0, 245},\n\tdictWord{132, 11, 489},\n\tdictWord{7, 0, 1570},\n\tdictWord{140, 0, 542},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t933,\n\t},\n\tdictWord{136, 0, 957},\n\tdictWord{6, 0, 1371},\n\tdictWord{7, 0, 31},\n\tdictWord{8, 0, 373},\n\tdictWord{5, 10, 284},\n\tdictWord{6, 10, 49},\n\tdictWord{6, 10, 350},\n\tdictWord{7, 10, 377},\n\tdictWord{7, 10, 1693},\n\tdictWord{8, 10, 678},\n\tdictWord{9, 10, 161},\n\tdictWord{9, 10, 585},\n\tdictWord{9, 10, 671},\n\tdictWord{9, 10, 839},\n\tdictWord{11, 10, 912},\n\tdictWord{141, 10, 427},\n\tdictWord{135, 11, 892},\n\tdictWord{4, 0, 325},\n\tdictWord{138, 0, 125},\n\tdictWord{139, 11, 47},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t597,\n\t},\n\tdictWord{138, 0, 323},\n\tdictWord{6, 0, 1547},\n\tdictWord{7, 11, 1605},\n\tdictWord{9, 11, 473},\n\tdictWord{11, 11, 962},\n\tdictWord{146, 11, 139},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t908,\n\t},\n\tdictWord{7, 11, 819},\n\tdictWord{9, 11, 26},\n\tdictWord{9, 11, 392},\n\tdictWord{10, 11, 152},\n\tdictWord{10, 11, 226},\n\tdictWord{11, 11, 19},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t276,\n\t},\n\tdictWord{12, 11, 426},\n\tdictWord{12, 11, 589},\n\tdictWord{13, 11, 460},\n\tdictWord{15, 11, 97},\n\tdictWord{19, 11, 48},\n\tdictWord{148, 11, 104},\n\tdictWord{135, 11, 51},\n\tdictWord{4, 0, 718},\n\tdictWord{135, 0, 1216},\n\tdictWord{6, 0, 1896},\n\tdictWord{6, 0, 1905},\n\tdictWord{6, 0, 1912},\n\tdictWord{9, 0, 947},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t974,\n\t},\n\tdictWord{12, 0, 809},\n\tdictWord{12, 0, 850},\n\tdictWord{12, 0, 858},\n\tdictWord{12, 0, 874},\n\tdictWord{12, 0, 887},\n\tdictWord{12, 0, 904},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t929,\n\t},\n\tdictWord{12, 0, 948},\n\tdictWord{12, 0, 952},\n\tdictWord{15, 0, 198},\n\tdictWord{15, 0, 206},\n\tdictWord{15, 0, 220},\n\tdictWord{15, 0, 227},\n\tdictWord{15, 0, 247},\n\tdictWord{18, 0, 188},\n\tdictWord{21, 0, 48},\n\tdictWord{21, 0, 50},\n\tdictWord{24, 0, 25},\n\tdictWord{24, 0, 29},\n\tdictWord{7, 11, 761},\n\tdictWord{7, 11, 1051},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t545,\n\t},\n\tdictWord{5, 0, 124},\n\tdictWord{5, 0, 144},\n\tdictWord{6, 0, 548},\n\tdictWord{7, 0, 15},\n\tdictWord{7, 0, 153},\n\tdictWord{137, 0, 629},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t606,\n\t},\n\tdictWord{135, 10, 2014},\n\tdictWord{7, 10, 2007},\n\tdictWord{9, 11, 46},\n\tdictWord{9, 10, 101},\n\tdictWord{9, 10, 450},\n\tdictWord{10, 10, 66},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t842,\n\t},\n\tdictWord{11, 10, 536},\n\tdictWord{140, 10, 587},\n\tdictWord{6, 0, 75},\n\tdictWord{7, 0, 1531},\n\tdictWord{8, 0, 416},\n\tdictWord{9, 0, 240},\n\tdictWord{9, 0, 275},\n\tdictWord{10, 0, 100},\n\tdictWord{11, 0, 658},\n\tdictWord{11, 0, 979},\n\tdictWord{12, 0, 86},\n\tdictWord{14, 0, 207},\n\tdictWord{15, 0, 20},\n\tdictWord{143, 0, 25},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t141,\n\t},\n\tdictWord{5, 0, 915},\n\tdictWord{6, 0, 1783},\n\tdictWord{7, 0, 211},\n\tdictWord{7, 0, 698},\n\tdictWord{7, 0, 1353},\n\tdictWord{9, 0, 83},\n\tdictWord{9, 0, 281},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t376,\n\t},\n\tdictWord{10, 0, 431},\n\tdictWord{11, 0, 543},\n\tdictWord{12, 0, 664},\n\tdictWord{13, 0, 280},\n\tdictWord{13, 0, 428},\n\tdictWord{14, 0, 61},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t128,\n\t},\n\tdictWord{17, 0, 52},\n\tdictWord{145, 0, 81},\n\tdictWord{132, 11, 674},\n\tdictWord{135, 0, 533},\n\tdictWord{149, 0, 6},\n\tdictWord{132, 11, 770},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t538,\n\t},\n\tdictWord{5, 11, 79},\n\tdictWord{7, 11, 1027},\n\tdictWord{7, 11, 1477},\n\tdictWord{139, 11, 52},\n\tdictWord{139, 10, 62},\n\tdictWord{4, 0, 338},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t400,\n\t},\n\tdictWord{5, 11, 789},\n\tdictWord{134, 11, 195},\n\tdictWord{4, 11, 251},\n\tdictWord{4, 11, 688},\n\tdictWord{7, 11, 513},\n\tdictWord{7, 11, 1284},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t87,\n\t},\n\tdictWord{138, 11, 365},\n\tdictWord{134, 10, 1766},\n\tdictWord{6, 0, 0},\n\tdictWord{7, 0, 84},\n\tdictWord{11, 0, 895},\n\tdictWord{145, 0, 11},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t892,\n\t},\n\tdictWord{4, 0, 221},\n\tdictWord{5, 0, 659},\n\tdictWord{7, 0, 697},\n\tdictWord{7, 0, 1211},\n\tdictWord{138, 0, 284},\n\tdictWord{133, 0, 989},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t889,\n\t},\n\tdictWord{4, 11, 160},\n\tdictWord{5, 11, 330},\n\tdictWord{7, 11, 1434},\n\tdictWord{136, 11, 174},\n\tdictWord{6, 10, 1665},\n\tdictWord{7, 10, 256},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1388,\n\t},\n\tdictWord{10, 10, 499},\n\tdictWord{139, 10, 670},\n\tdictWord{7, 0, 848},\n\tdictWord{4, 10, 22},\n\tdictWord{5, 10, 10},\n\tdictWord{136, 10, 97},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t507,\n\t},\n\tdictWord{133, 10, 481},\n\tdictWord{4, 0, 188},\n\tdictWord{135, 0, 805},\n\tdictWord{5, 0, 884},\n\tdictWord{6, 0, 732},\n\tdictWord{139, 0, 991},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t968,\n\t},\n\tdictWord{11, 11, 636},\n\tdictWord{15, 11, 145},\n\tdictWord{17, 11, 34},\n\tdictWord{19, 11, 50},\n\tdictWord{151, 11, 20},\n\tdictWord{7, 0, 959},\n\tdictWord{\n\t\t16,\n\t\t0,\n\t\t60,\n\t},\n\tdictWord{6, 10, 134},\n\tdictWord{7, 10, 437},\n\tdictWord{9, 10, 37},\n\tdictWord{14, 10, 285},\n\tdictWord{142, 10, 371},\n\tdictWord{7, 10, 486},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t155,\n\t},\n\tdictWord{11, 10, 93},\n\tdictWord{140, 10, 164},\n\tdictWord{134, 0, 1653},\n\tdictWord{7, 0, 337},\n\tdictWord{133, 10, 591},\n\tdictWord{6, 0, 1989},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t922,\n\t},\n\tdictWord{8, 0, 978},\n\tdictWord{133, 11, 374},\n\tdictWord{132, 0, 638},\n\tdictWord{138, 0, 500},\n\tdictWord{133, 11, 731},\n\tdictWord{5, 10, 380},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t650,\n\t},\n\tdictWord{136, 10, 310},\n\tdictWord{138, 11, 381},\n\tdictWord{4, 10, 364},\n\tdictWord{7, 10, 1156},\n\tdictWord{7, 10, 1187},\n\tdictWord{137, 10, 409},\n\tdictWord{137, 11, 224},\n\tdictWord{140, 0, 166},\n\tdictWord{134, 10, 482},\n\tdictWord{4, 11, 626},\n\tdictWord{5, 11, 642},\n\tdictWord{6, 11, 425},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t202,\n\t},\n\tdictWord{139, 11, 141},\n\tdictWord{4, 10, 781},\n\tdictWord{6, 10, 487},\n\tdictWord{7, 10, 926},\n\tdictWord{8, 10, 263},\n\tdictWord{139, 10, 500},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t418,\n\t},\n\tdictWord{4, 10, 94},\n\tdictWord{135, 10, 1265},\n\tdictWord{136, 0, 760},\n\tdictWord{132, 10, 417},\n\tdictWord{136, 11, 835},\n\tdictWord{5, 10, 348},\n\tdictWord{134, 10, 522},\n\tdictWord{6, 0, 1277},\n\tdictWord{134, 0, 1538},\n\tdictWord{139, 11, 541},\n\tdictWord{135, 11, 1597},\n\tdictWord{5, 11, 384},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t455,\n\t},\n\tdictWord{140, 11, 48},\n\tdictWord{136, 0, 770},\n\tdictWord{5, 11, 264},\n\tdictWord{134, 11, 184},\n\tdictWord{4, 0, 89},\n\tdictWord{5, 0, 489},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t315,\n\t},\n\tdictWord{7, 0, 553},\n\tdictWord{7, 0, 1745},\n\tdictWord{138, 0, 243},\n\tdictWord{4, 10, 408},\n\tdictWord{4, 10, 741},\n\tdictWord{135, 10, 500},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1396,\n\t},\n\tdictWord{133, 0, 560},\n\tdictWord{6, 0, 1658},\n\tdictWord{9, 0, 3},\n\tdictWord{10, 0, 154},\n\tdictWord{11, 0, 641},\n\tdictWord{13, 0, 85},\n\tdictWord{13, 0, 201},\n\tdictWord{141, 0, 346},\n\tdictWord{135, 11, 1595},\n\tdictWord{5, 11, 633},\n\tdictWord{6, 11, 28},\n\tdictWord{7, 11, 219},\n\tdictWord{135, 11, 1323},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t769,\n\t},\n\tdictWord{140, 11, 185},\n\tdictWord{135, 11, 785},\n\tdictWord{7, 11, 359},\n\tdictWord{8, 11, 243},\n\tdictWord{140, 11, 175},\n\tdictWord{138, 0, 586},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1271,\n\t},\n\tdictWord{134, 10, 73},\n\tdictWord{132, 11, 105},\n\tdictWord{4, 0, 166},\n\tdictWord{5, 0, 505},\n\tdictWord{134, 0, 1670},\n\tdictWord{133, 10, 576},\n\tdictWord{4, 11, 324},\n\tdictWord{138, 11, 104},\n\tdictWord{142, 10, 231},\n\tdictWord{6, 0, 637},\n\tdictWord{7, 10, 1264},\n\tdictWord{7, 10, 1678},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t945,\n\t},\n\tdictWord{12, 10, 341},\n\tdictWord{12, 10, 471},\n\tdictWord{12, 10, 569},\n\tdictWord{23, 11, 21},\n\tdictWord{151, 11, 23},\n\tdictWord{8, 11, 559},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t109,\n\t},\n\tdictWord{134, 0, 1947},\n\tdictWord{7, 0, 445},\n\tdictWord{8, 0, 307},\n\tdictWord{8, 0, 704},\n\tdictWord{10, 0, 41},\n\tdictWord{10, 0, 439},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t237,\n\t},\n\tdictWord{11, 0, 622},\n\tdictWord{140, 0, 201},\n\tdictWord{135, 11, 963},\n\tdictWord{135, 0, 1977},\n\tdictWord{4, 0, 189},\n\tdictWord{5, 0, 713},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t57,\n\t},\n\tdictWord{138, 0, 371},\n\tdictWord{135, 10, 538},\n\tdictWord{132, 0, 552},\n\tdictWord{6, 0, 883},\n\tdictWord{133, 10, 413},\n\tdictWord{6, 0, 923},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t758,\n\t},\n\tdictWord{138, 11, 215},\n\tdictWord{136, 10, 495},\n\tdictWord{7, 10, 54},\n\tdictWord{8, 10, 312},\n\tdictWord{10, 10, 191},\n\tdictWord{10, 10, 614},\n\tdictWord{140, 10, 567},\n\tdictWord{7, 11, 351},\n\tdictWord{139, 11, 128},\n\tdictWord{7, 0, 875},\n\tdictWord{6, 10, 468},\n\tdictWord{7, 10, 1478},\n\tdictWord{8, 10, 530},\n\tdictWord{142, 10, 290},\n\tdictWord{135, 0, 1788},\n\tdictWord{17, 0, 49},\n\tdictWord{133, 11, 918},\n\tdictWord{12, 11, 398},\n\tdictWord{20, 11, 39},\n\tdictWord{\n\t\t21,\n\t\t11,\n\t\t11,\n\t},\n\tdictWord{150, 11, 41},\n\tdictWord{10, 0, 661},\n\tdictWord{6, 10, 484},\n\tdictWord{135, 10, 822},\n\tdictWord{135, 0, 1945},\n\tdictWord{134, 0, 794},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t900,\n\t},\n\tdictWord{135, 10, 1335},\n\tdictWord{6, 10, 1724},\n\tdictWord{135, 10, 2022},\n\tdictWord{132, 11, 340},\n\tdictWord{134, 0, 1135},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t784,\n\t},\n\tdictWord{133, 0, 745},\n\tdictWord{5, 0, 84},\n\tdictWord{134, 0, 163},\n\tdictWord{133, 0, 410},\n\tdictWord{4, 0, 976},\n\tdictWord{5, 11, 985},\n\tdictWord{7, 11, 509},\n\tdictWord{7, 11, 529},\n\tdictWord{145, 11, 96},\n\tdictWord{132, 10, 474},\n\tdictWord{134, 0, 703},\n\tdictWord{135, 11, 1919},\n\tdictWord{5, 0, 322},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t186,\n\t},\n\tdictWord{9, 0, 262},\n\tdictWord{10, 0, 187},\n\tdictWord{142, 0, 208},\n\tdictWord{135, 10, 1504},\n\tdictWord{133, 0, 227},\n\tdictWord{9, 0, 560},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t208,\n\t},\n\tdictWord{133, 10, 305},\n\tdictWord{132, 11, 247},\n\tdictWord{7, 0, 1395},\n\tdictWord{8, 0, 486},\n\tdictWord{9, 0, 236},\n\tdictWord{9, 0, 878},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t218,\n\t},\n\tdictWord{11, 0, 95},\n\tdictWord{19, 0, 17},\n\tdictWord{147, 0, 31},\n\tdictWord{7, 0, 2043},\n\tdictWord{8, 0, 672},\n\tdictWord{141, 0, 448},\n\tdictWord{4, 11, 184},\n\tdictWord{5, 11, 390},\n\tdictWord{6, 11, 337},\n\tdictWord{7, 11, 23},\n\tdictWord{7, 11, 494},\n\tdictWord{7, 11, 618},\n\tdictWord{7, 11, 1456},\n\tdictWord{8, 11, 27},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t599,\n\t},\n\tdictWord{10, 11, 153},\n\tdictWord{139, 11, 710},\n\tdictWord{135, 0, 466},\n\tdictWord{135, 10, 1236},\n\tdictWord{6, 0, 167},\n\tdictWord{7, 0, 186},\n\tdictWord{7, 0, 656},\n\tdictWord{10, 0, 643},\n\tdictWord{4, 10, 480},\n\tdictWord{6, 10, 302},\n\tdictWord{6, 10, 1642},\n\tdictWord{7, 10, 837},\n\tdictWord{7, 10, 1547},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1657,\n\t},\n\tdictWord{8, 10, 429},\n\tdictWord{9, 10, 228},\n\tdictWord{13, 10, 289},\n\tdictWord{13, 10, 343},\n\tdictWord{147, 10, 101},\n\tdictWord{134, 0, 1428},\n\tdictWord{134, 0, 1440},\n\tdictWord{5, 0, 412},\n\tdictWord{7, 10, 278},\n\tdictWord{10, 10, 739},\n\tdictWord{11, 10, 708},\n\tdictWord{141, 10, 348},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1118,\n\t},\n\tdictWord{136, 0, 562},\n\tdictWord{148, 11, 46},\n\tdictWord{9, 0, 316},\n\tdictWord{139, 0, 256},\n\tdictWord{134, 0, 1771},\n\tdictWord{135, 0, 1190},\n\tdictWord{137, 0, 132},\n\tdictWord{10, 11, 227},\n\tdictWord{11, 11, 497},\n\tdictWord{11, 11, 709},\n\tdictWord{140, 11, 415},\n\tdictWord{143, 0, 66},\n\tdictWord{6, 11, 360},\n\tdictWord{7, 11, 1664},\n\tdictWord{136, 11, 478},\n\tdictWord{144, 10, 28},\n\tdictWord{4, 0, 317},\n\tdictWord{135, 0, 1279},\n\tdictWord{5, 0, 63},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t509,\n\t},\n\tdictWord{136, 11, 699},\n\tdictWord{145, 10, 36},\n\tdictWord{134, 0, 1475},\n\tdictWord{11, 11, 343},\n\tdictWord{142, 11, 127},\n\tdictWord{132, 11, 739},\n\tdictWord{132, 0, 288},\n\tdictWord{135, 11, 1757},\n\tdictWord{8, 0, 89},\n\tdictWord{8, 0, 620},\n\tdictWord{9, 0, 608},\n\tdictWord{11, 0, 628},\n\tdictWord{12, 0, 322},\n\tdictWord{143, 0, 124},\n\tdictWord{134, 0, 1225},\n\tdictWord{7, 0, 1189},\n\tdictWord{4, 11, 67},\n\tdictWord{5, 11, 422},\n\tdictWord{6, 10, 363},\n\tdictWord{7, 11, 1037},\n\tdictWord{7, 11, 1289},\n\tdictWord{7, 11, 1555},\n\tdictWord{7, 10, 1955},\n\tdictWord{8, 10, 725},\n\tdictWord{9, 11, 741},\n\tdictWord{145, 11, 108},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1468,\n\t},\n\tdictWord{6, 0, 689},\n\tdictWord{134, 0, 1451},\n\tdictWord{138, 0, 120},\n\tdictWord{151, 0, 1},\n\tdictWord{137, 10, 805},\n\tdictWord{142, 0, 329},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t813,\n\t},\n\tdictWord{135, 10, 2046},\n\tdictWord{135, 0, 226},\n\tdictWord{138, 11, 96},\n\tdictWord{7, 0, 1855},\n\tdictWord{5, 10, 712},\n\tdictWord{11, 10, 17},\n\tdictWord{13, 10, 321},\n\tdictWord{144, 10, 67},\n\tdictWord{9, 0, 461},\n\tdictWord{6, 10, 320},\n\tdictWord{7, 10, 781},\n\tdictWord{7, 10, 1921},\n\tdictWord{9, 10, 55},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t186,\n\t},\n\tdictWord{10, 10, 273},\n\tdictWord{10, 10, 664},\n\tdictWord{10, 10, 801},\n\tdictWord{11, 10, 996},\n\tdictWord{11, 10, 997},\n\tdictWord{13, 10, 157},\n\tdictWord{142, 10, 170},\n\tdictWord{8, 11, 203},\n\tdictWord{8, 10, 271},\n\tdictWord{11, 11, 823},\n\tdictWord{11, 11, 846},\n\tdictWord{12, 11, 482},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t133,\n\t},\n\tdictWord{13, 11, 277},\n\tdictWord{13, 11, 302},\n\tdictWord{13, 11, 464},\n\tdictWord{14, 11, 205},\n\tdictWord{142, 11, 221},\n\tdictWord{135, 0, 1346},\n\tdictWord{4, 11, 449},\n\tdictWord{133, 11, 718},\n\tdictWord{134, 0, 85},\n\tdictWord{14, 0, 299},\n\tdictWord{7, 10, 103},\n\tdictWord{7, 10, 863},\n\tdictWord{11, 10, 184},\n\tdictWord{145, 10, 62},\n\tdictWord{4, 11, 355},\n\tdictWord{6, 11, 311},\n\tdictWord{9, 11, 256},\n\tdictWord{138, 11, 404},\n\tdictWord{137, 10, 659},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t758,\n\t},\n\tdictWord{133, 11, 827},\n\tdictWord{5, 11, 64},\n\tdictWord{140, 11, 581},\n\tdictWord{134, 0, 1171},\n\tdictWord{4, 11, 442},\n\tdictWord{7, 11, 1047},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1352,\n\t},\n\tdictWord{135, 11, 1643},\n\tdictWord{132, 0, 980},\n\tdictWord{5, 11, 977},\n\tdictWord{6, 11, 288},\n\tdictWord{7, 11, 528},\n\tdictWord{135, 11, 1065},\n\tdictWord{5, 0, 279},\n\tdictWord{6, 0, 235},\n\tdictWord{7, 0, 468},\n\tdictWord{8, 0, 446},\n\tdictWord{9, 0, 637},\n\tdictWord{10, 0, 717},\n\tdictWord{11, 0, 738},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t514,\n\t},\n\tdictWord{132, 0, 293},\n\tdictWord{11, 10, 337},\n\tdictWord{142, 10, 303},\n\tdictWord{136, 11, 285},\n\tdictWord{5, 0, 17},\n\tdictWord{6, 0, 371},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t528,\n\t},\n\tdictWord{12, 0, 364},\n\tdictWord{132, 11, 254},\n\tdictWord{5, 10, 77},\n\tdictWord{7, 10, 1455},\n\tdictWord{10, 10, 843},\n\tdictWord{147, 10, 73},\n\tdictWord{\n\t\t150,\n\t\t0,\n\t\t5,\n\t},\n\tdictWord{132, 10, 458},\n\tdictWord{6, 11, 12},\n\tdictWord{7, 11, 1219},\n\tdictWord{145, 11, 73},\n\tdictWord{135, 10, 1420},\n\tdictWord{6, 10, 109},\n\tdictWord{138, 10, 382},\n\tdictWord{135, 11, 125},\n\tdictWord{6, 10, 330},\n\tdictWord{7, 10, 1084},\n\tdictWord{139, 10, 142},\n\tdictWord{6, 11, 369},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t502,\n\t},\n\tdictWord{7, 11, 1036},\n\tdictWord{8, 11, 348},\n\tdictWord{9, 11, 452},\n\tdictWord{10, 11, 26},\n\tdictWord{11, 11, 224},\n\tdictWord{11, 11, 387},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t772,\n\t},\n\tdictWord{12, 11, 95},\n\tdictWord{12, 11, 629},\n\tdictWord{13, 11, 195},\n\tdictWord{13, 11, 207},\n\tdictWord{13, 11, 241},\n\tdictWord{14, 11, 260},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t270,\n\t},\n\tdictWord{143, 11, 140},\n\tdictWord{132, 11, 269},\n\tdictWord{5, 11, 480},\n\tdictWord{7, 11, 532},\n\tdictWord{7, 11, 1197},\n\tdictWord{7, 11, 1358},\n\tdictWord{8, 11, 291},\n\tdictWord{11, 11, 349},\n\tdictWord{142, 11, 396},\n\tdictWord{150, 0, 48},\n\tdictWord{10, 0, 601},\n\tdictWord{13, 0, 353},\n\tdictWord{141, 0, 376},\n\tdictWord{5, 0, 779},\n\tdictWord{5, 0, 807},\n\tdictWord{6, 0, 1655},\n\tdictWord{134, 0, 1676},\n\tdictWord{142, 11, 223},\n\tdictWord{4, 0, 196},\n\tdictWord{5, 0, 558},\n\tdictWord{133, 0, 949},\n\tdictWord{148, 11, 15},\n\tdictWord{135, 11, 1764},\n\tdictWord{134, 0, 1322},\n\tdictWord{132, 0, 752},\n\tdictWord{139, 0, 737},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t657,\n\t},\n\tdictWord{136, 11, 533},\n\tdictWord{135, 0, 412},\n\tdictWord{4, 0, 227},\n\tdictWord{5, 0, 159},\n\tdictWord{5, 0, 409},\n\tdictWord{7, 0, 80},\n\tdictWord{8, 0, 556},\n\tdictWord{10, 0, 479},\n\tdictWord{12, 0, 418},\n\tdictWord{14, 0, 50},\n\tdictWord{14, 0, 123},\n\tdictWord{14, 0, 192},\n\tdictWord{14, 0, 249},\n\tdictWord{14, 0, 295},\n\tdictWord{143, 0, 27},\n\tdictWord{7, 0, 1470},\n\tdictWord{8, 0, 66},\n\tdictWord{8, 0, 137},\n\tdictWord{8, 0, 761},\n\tdictWord{9, 0, 638},\n\tdictWord{11, 0, 80},\n\tdictWord{11, 0, 212},\n\tdictWord{11, 0, 368},\n\tdictWord{11, 0, 418},\n\tdictWord{12, 0, 8},\n\tdictWord{13, 0, 15},\n\tdictWord{16, 0, 61},\n\tdictWord{17, 0, 59},\n\tdictWord{19, 0, 28},\n\tdictWord{\n\t\t148,\n\t\t0,\n\t\t84,\n\t},\n\tdictWord{135, 10, 1985},\n\tdictWord{4, 11, 211},\n\tdictWord{4, 11, 332},\n\tdictWord{5, 11, 335},\n\tdictWord{6, 11, 238},\n\tdictWord{7, 11, 269},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t811,\n\t},\n\tdictWord{7, 11, 1797},\n\tdictWord{8, 10, 122},\n\tdictWord{8, 11, 836},\n\tdictWord{9, 11, 507},\n\tdictWord{141, 11, 242},\n\tdictWord{6, 0, 683},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1252,\n\t},\n\tdictWord{4, 0, 873},\n\tdictWord{132, 10, 234},\n\tdictWord{134, 0, 835},\n\tdictWord{6, 0, 38},\n\tdictWord{7, 0, 1220},\n\tdictWord{8, 0, 185},\n\tdictWord{8, 0, 256},\n\tdictWord{9, 0, 22},\n\tdictWord{9, 0, 331},\n\tdictWord{10, 0, 738},\n\tdictWord{11, 0, 205},\n\tdictWord{11, 0, 540},\n\tdictWord{11, 0, 746},\n\tdictWord{13, 0, 465},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t88,\n\t},\n\tdictWord{142, 0, 194},\n\tdictWord{138, 0, 986},\n\tdictWord{5, 11, 1009},\n\tdictWord{12, 11, 582},\n\tdictWord{146, 11, 131},\n\tdictWord{4, 0, 159},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t115,\n\t},\n\tdictWord{7, 0, 252},\n\tdictWord{7, 0, 257},\n\tdictWord{7, 0, 1928},\n\tdictWord{8, 0, 69},\n\tdictWord{9, 0, 384},\n\tdictWord{10, 0, 91},\n\tdictWord{10, 0, 615},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t375,\n\t},\n\tdictWord{14, 0, 235},\n\tdictWord{18, 0, 117},\n\tdictWord{147, 0, 123},\n\tdictWord{133, 0, 911},\n\tdictWord{136, 0, 278},\n\tdictWord{5, 10, 430},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t932,\n\t},\n\tdictWord{6, 10, 131},\n\tdictWord{7, 10, 417},\n\tdictWord{9, 10, 522},\n\tdictWord{11, 10, 314},\n\tdictWord{141, 10, 390},\n\tdictWord{14, 10, 149},\n\tdictWord{14, 10, 399},\n\tdictWord{143, 10, 57},\n\tdictWord{4, 0, 151},\n\tdictWord{7, 0, 1567},\n\tdictWord{136, 0, 749},\n\tdictWord{5, 11, 228},\n\tdictWord{6, 11, 203},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t156,\n\t},\n\tdictWord{8, 11, 347},\n\tdictWord{137, 11, 265},\n\tdictWord{132, 10, 507},\n\tdictWord{10, 0, 989},\n\tdictWord{140, 0, 956},\n\tdictWord{133, 0, 990},\n\tdictWord{5, 0, 194},\n\tdictWord{6, 0, 927},\n\tdictWord{7, 0, 1662},\n\tdictWord{9, 0, 90},\n\tdictWord{140, 0, 564},\n\tdictWord{4, 10, 343},\n\tdictWord{133, 10, 511},\n\tdictWord{133, 0, 425},\n\tdictWord{7, 10, 455},\n\tdictWord{138, 10, 591},\n\tdictWord{4, 0, 774},\n\tdictWord{7, 11, 476},\n\tdictWord{7, 11, 1592},\n\tdictWord{138, 11, 87},\n\tdictWord{5, 0, 971},\n\tdictWord{135, 10, 1381},\n\tdictWord{5, 11, 318},\n\tdictWord{147, 11, 121},\n\tdictWord{5, 11, 291},\n\tdictWord{7, 11, 765},\n\tdictWord{9, 11, 389},\n\tdictWord{140, 11, 548},\n\tdictWord{134, 10, 575},\n\tdictWord{4, 0, 827},\n\tdictWord{12, 0, 646},\n\tdictWord{12, 0, 705},\n\tdictWord{12, 0, 712},\n\tdictWord{140, 0, 714},\n\tdictWord{139, 0, 752},\n\tdictWord{137, 0, 662},\n\tdictWord{5, 0, 72},\n\tdictWord{6, 0, 264},\n\tdictWord{7, 0, 21},\n\tdictWord{7, 0, 46},\n\tdictWord{7, 0, 2013},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t215,\n\t},\n\tdictWord{8, 0, 513},\n\tdictWord{10, 0, 266},\n\tdictWord{139, 0, 22},\n\tdictWord{139, 11, 522},\n\tdictWord{6, 0, 239},\n\tdictWord{7, 0, 118},\n\tdictWord{10, 0, 95},\n\tdictWord{11, 0, 603},\n\tdictWord{13, 0, 443},\n\tdictWord{14, 0, 160},\n\tdictWord{143, 0, 4},\n\tdictWord{6, 0, 431},\n\tdictWord{134, 0, 669},\n\tdictWord{7, 10, 1127},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1572,\n\t},\n\tdictWord{10, 10, 297},\n\tdictWord{10, 10, 422},\n\tdictWord{11, 10, 764},\n\tdictWord{11, 10, 810},\n\tdictWord{12, 10, 264},\n\tdictWord{13, 10, 102},\n\tdictWord{13, 10, 300},\n\tdictWord{13, 10, 484},\n\tdictWord{14, 10, 147},\n\tdictWord{14, 10, 229},\n\tdictWord{17, 10, 71},\n\tdictWord{18, 10, 118},\n\tdictWord{\n\t\t147,\n\t\t10,\n\t\t120,\n\t},\n\tdictWord{5, 0, 874},\n\tdictWord{6, 0, 1677},\n\tdictWord{15, 0, 0},\n\tdictWord{10, 11, 525},\n\tdictWord{139, 11, 82},\n\tdictWord{6, 0, 65},\n\tdictWord{7, 0, 939},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1172,\n\t},\n\tdictWord{7, 0, 1671},\n\tdictWord{9, 0, 540},\n\tdictWord{10, 0, 696},\n\tdictWord{11, 0, 265},\n\tdictWord{11, 0, 732},\n\tdictWord{11, 0, 928},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t937,\n\t},\n\tdictWord{141, 0, 438},\n\tdictWord{134, 0, 1350},\n\tdictWord{136, 11, 547},\n\tdictWord{132, 11, 422},\n\tdictWord{5, 11, 355},\n\tdictWord{145, 11, 0},\n\tdictWord{137, 11, 905},\n\tdictWord{5, 0, 682},\n\tdictWord{135, 0, 1887},\n\tdictWord{132, 0, 809},\n\tdictWord{4, 0, 696},\n\tdictWord{133, 11, 865},\n\tdictWord{6, 0, 1074},\n\tdictWord{6, 0, 1472},\n\tdictWord{14, 10, 35},\n\tdictWord{142, 10, 191},\n\tdictWord{5, 11, 914},\n\tdictWord{134, 11, 1625},\n\tdictWord{133, 11, 234},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1383,\n\t},\n\tdictWord{137, 11, 780},\n\tdictWord{132, 10, 125},\n\tdictWord{4, 0, 726},\n\tdictWord{133, 0, 630},\n\tdictWord{8, 0, 802},\n\tdictWord{136, 0, 838},\n\tdictWord{132, 10, 721},\n\tdictWord{6, 0, 1337},\n\tdictWord{7, 0, 776},\n\tdictWord{19, 0, 56},\n\tdictWord{136, 10, 145},\n\tdictWord{132, 0, 970},\n\tdictWord{7, 10, 792},\n\tdictWord{8, 10, 147},\n\tdictWord{10, 10, 821},\n\tdictWord{139, 10, 1021},\n\tdictWord{139, 10, 970},\n\tdictWord{8, 0, 940},\n\tdictWord{137, 0, 797},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1312,\n\t},\n\tdictWord{9, 0, 248},\n\tdictWord{10, 0, 400},\n\tdictWord{7, 11, 816},\n\tdictWord{7, 11, 1241},\n\tdictWord{7, 10, 1999},\n\tdictWord{9, 11, 283},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t520,\n\t},\n\tdictWord{10, 11, 213},\n\tdictWord{10, 11, 307},\n\tdictWord{10, 11, 463},\n\tdictWord{10, 11, 671},\n\tdictWord{10, 11, 746},\n\tdictWord{11, 11, 401},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t794,\n\t},\n\tdictWord{12, 11, 517},\n\tdictWord{18, 11, 107},\n\tdictWord{147, 11, 115},\n\tdictWord{6, 0, 1951},\n\tdictWord{134, 0, 2040},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t339,\n\t},\n\tdictWord{13, 0, 41},\n\tdictWord{15, 0, 93},\n\tdictWord{5, 10, 168},\n\tdictWord{5, 10, 930},\n\tdictWord{8, 10, 74},\n\tdictWord{9, 10, 623},\n\tdictWord{12, 10, 500},\n\tdictWord{140, 10, 579},\n\tdictWord{6, 0, 118},\n\tdictWord{7, 0, 215},\n\tdictWord{7, 0, 1521},\n\tdictWord{140, 0, 11},\n\tdictWord{6, 10, 220},\n\tdictWord{7, 10, 1101},\n\tdictWord{141, 10, 105},\n\tdictWord{6, 11, 421},\n\tdictWord{7, 11, 61},\n\tdictWord{7, 11, 1540},\n\tdictWord{10, 11, 11},\n\tdictWord{138, 11, 501},\n\tdictWord{7, 0, 615},\n\tdictWord{138, 0, 251},\n\tdictWord{140, 11, 631},\n\tdictWord{135, 0, 1044},\n\tdictWord{6, 10, 19},\n\tdictWord{7, 10, 1413},\n\tdictWord{139, 10, 428},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t225,\n\t},\n\tdictWord{7, 10, 96},\n\tdictWord{8, 10, 401},\n\tdictWord{8, 10, 703},\n\tdictWord{137, 10, 896},\n\tdictWord{145, 10, 116},\n\tdictWord{6, 11, 102},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t72,\n\t},\n\tdictWord{15, 11, 142},\n\tdictWord{147, 11, 67},\n\tdictWord{7, 10, 1961},\n\tdictWord{7, 10, 1965},\n\tdictWord{8, 10, 702},\n\tdictWord{136, 10, 750},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t2030,\n\t},\n\tdictWord{8, 10, 150},\n\tdictWord{8, 10, 737},\n\tdictWord{12, 10, 366},\n\tdictWord{151, 11, 30},\n\tdictWord{4, 0, 370},\n\tdictWord{5, 0, 756},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1326,\n\t},\n\tdictWord{135, 11, 823},\n\tdictWord{8, 10, 800},\n\tdictWord{9, 10, 148},\n\tdictWord{9, 10, 872},\n\tdictWord{9, 10, 890},\n\tdictWord{11, 10, 309},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t1001,\n\t},\n\tdictWord{13, 10, 267},\n\tdictWord{141, 10, 323},\n\tdictWord{6, 0, 1662},\n\tdictWord{7, 0, 48},\n\tdictWord{8, 0, 771},\n\tdictWord{10, 0, 116},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t104,\n\t},\n\tdictWord{14, 0, 105},\n\tdictWord{14, 0, 184},\n\tdictWord{15, 0, 168},\n\tdictWord{19, 0, 92},\n\tdictWord{148, 0, 68},\n\tdictWord{10, 0, 209},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1870,\n\t},\n\tdictWord{7, 11, 68},\n\tdictWord{8, 11, 48},\n\tdictWord{8, 11, 88},\n\tdictWord{8, 11, 582},\n\tdictWord{8, 11, 681},\n\tdictWord{9, 11, 373},\n\tdictWord{9, 11, 864},\n\tdictWord{11, 11, 157},\n\tdictWord{11, 11, 336},\n\tdictWord{11, 11, 843},\n\tdictWord{148, 11, 27},\n\tdictWord{134, 0, 930},\n\tdictWord{4, 11, 88},\n\tdictWord{5, 11, 137},\n\tdictWord{5, 11, 174},\n\tdictWord{5, 11, 777},\n\tdictWord{6, 11, 1664},\n\tdictWord{6, 11, 1725},\n\tdictWord{7, 11, 77},\n\tdictWord{7, 11, 426},\n\tdictWord{7, 11, 1317},\n\tdictWord{7, 11, 1355},\n\tdictWord{8, 11, 126},\n\tdictWord{8, 11, 563},\n\tdictWord{9, 11, 523},\n\tdictWord{9, 11, 750},\n\tdictWord{10, 11, 310},\n\tdictWord{10, 11, 836},\n\tdictWord{11, 11, 42},\n\tdictWord{11, 11, 318},\n\tdictWord{11, 11, 731},\n\tdictWord{12, 11, 68},\n\tdictWord{12, 11, 92},\n\tdictWord{12, 11, 507},\n\tdictWord{12, 11, 692},\n\tdictWord{13, 11, 81},\n\tdictWord{13, 11, 238},\n\tdictWord{13, 11, 374},\n\tdictWord{18, 11, 138},\n\tdictWord{19, 11, 78},\n\tdictWord{19, 11, 111},\n\tdictWord{20, 11, 55},\n\tdictWord{20, 11, 77},\n\tdictWord{148, 11, 92},\n\tdictWord{4, 11, 938},\n\tdictWord{135, 11, 1831},\n\tdictWord{5, 10, 547},\n\tdictWord{7, 10, 424},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t617,\n\t},\n\tdictWord{138, 11, 351},\n\tdictWord{6, 0, 1286},\n\tdictWord{6, 11, 1668},\n\tdictWord{7, 11, 1499},\n\tdictWord{8, 11, 117},\n\tdictWord{9, 11, 314},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t174,\n\t},\n\tdictWord{6, 0, 759},\n\tdictWord{6, 0, 894},\n\tdictWord{7, 11, 707},\n\tdictWord{139, 11, 563},\n\tdictWord{4, 0, 120},\n\tdictWord{135, 0, 1894},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t385,\n\t},\n\tdictWord{149, 0, 17},\n\tdictWord{138, 0, 429},\n\tdictWord{133, 11, 403},\n\tdictWord{5, 0, 820},\n\tdictWord{135, 0, 931},\n\tdictWord{10, 0, 199},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t133,\n\t},\n\tdictWord{6, 0, 151},\n\tdictWord{6, 0, 1675},\n\tdictWord{7, 0, 383},\n\tdictWord{151, 0, 10},\n\tdictWord{6, 0, 761},\n\tdictWord{136, 10, 187},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t365,\n\t},\n\tdictWord{10, 10, 0},\n\tdictWord{10, 10, 818},\n\tdictWord{139, 10, 988},\n\tdictWord{4, 11, 44},\n\tdictWord{5, 11, 311},\n\tdictWord{6, 11, 156},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t639,\n\t},\n\tdictWord{7, 11, 762},\n\tdictWord{7, 11, 1827},\n\tdictWord{9, 11, 8},\n\tdictWord{9, 11, 462},\n\tdictWord{148, 11, 83},\n\tdictWord{4, 11, 346},\n\tdictWord{7, 11, 115},\n\tdictWord{9, 11, 180},\n\tdictWord{9, 11, 456},\n\tdictWord{138, 11, 363},\n\tdictWord{136, 10, 685},\n\tdictWord{7, 0, 1086},\n\tdictWord{145, 0, 46},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1624,\n\t},\n\tdictWord{11, 0, 11},\n\tdictWord{12, 0, 422},\n\tdictWord{13, 0, 444},\n\tdictWord{142, 0, 360},\n\tdictWord{6, 0, 1020},\n\tdictWord{6, 0, 1260},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1589,\n\t},\n\tdictWord{4, 0, 43},\n\tdictWord{5, 0, 344},\n\tdictWord{5, 0, 357},\n\tdictWord{14, 0, 472},\n\tdictWord{150, 0, 58},\n\tdictWord{6, 0, 1864},\n\tdictWord{6, 0, 1866},\n\tdictWord{6, 0, 1868},\n\tdictWord{6, 0, 1869},\n\tdictWord{6, 0, 1874},\n\tdictWord{6, 0, 1877},\n\tdictWord{6, 0, 1903},\n\tdictWord{6, 0, 1911},\n\tdictWord{9, 0, 920},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t921,\n\t},\n\tdictWord{9, 0, 924},\n\tdictWord{9, 0, 946},\n\tdictWord{9, 0, 959},\n\tdictWord{9, 0, 963},\n\tdictWord{9, 0, 970},\n\tdictWord{9, 0, 997},\n\tdictWord{9, 0, 1008},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t1017,\n\t},\n\tdictWord{12, 0, 795},\n\tdictWord{12, 0, 797},\n\tdictWord{12, 0, 798},\n\tdictWord{12, 0, 800},\n\tdictWord{12, 0, 803},\n\tdictWord{12, 0, 811},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t820,\n\t},\n\tdictWord{12, 0, 821},\n\tdictWord{12, 0, 839},\n\tdictWord{12, 0, 841},\n\tdictWord{12, 0, 848},\n\tdictWord{12, 0, 911},\n\tdictWord{12, 0, 921},\n\tdictWord{12, 0, 922},\n\tdictWord{12, 0, 925},\n\tdictWord{12, 0, 937},\n\tdictWord{12, 0, 944},\n\tdictWord{12, 0, 945},\n\tdictWord{12, 0, 953},\n\tdictWord{15, 0, 184},\n\tdictWord{15, 0, 191},\n\tdictWord{15, 0, 199},\n\tdictWord{15, 0, 237},\n\tdictWord{15, 0, 240},\n\tdictWord{15, 0, 243},\n\tdictWord{15, 0, 246},\n\tdictWord{18, 0, 203},\n\tdictWord{21, 0, 40},\n\tdictWord{\n\t\t21,\n\t\t0,\n\t\t52,\n\t},\n\tdictWord{21, 0, 57},\n\tdictWord{24, 0, 23},\n\tdictWord{24, 0, 28},\n\tdictWord{152, 0, 30},\n\tdictWord{134, 0, 725},\n\tdictWord{145, 11, 58},\n\tdictWord{133, 0, 888},\n\tdictWord{137, 10, 874},\n\tdictWord{4, 0, 711},\n\tdictWord{8, 10, 774},\n\tdictWord{10, 10, 670},\n\tdictWord{140, 10, 51},\n\tdictWord{144, 11, 40},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t185,\n\t},\n\tdictWord{7, 11, 1899},\n\tdictWord{139, 11, 673},\n\tdictWord{137, 10, 701},\n\tdictWord{137, 0, 440},\n\tdictWord{4, 11, 327},\n\tdictWord{5, 11, 478},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1332,\n\t},\n\tdictWord{8, 11, 753},\n\tdictWord{140, 11, 227},\n\tdictWord{4, 10, 127},\n\tdictWord{5, 10, 350},\n\tdictWord{6, 10, 356},\n\tdictWord{8, 10, 426},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t572,\n\t},\n\tdictWord{10, 10, 247},\n\tdictWord{139, 10, 312},\n\tdictWord{5, 11, 1020},\n\tdictWord{133, 11, 1022},\n\tdictWord{4, 11, 103},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t401,\n\t},\n\tdictWord{6, 0, 1913},\n\tdictWord{6, 0, 1926},\n\tdictWord{6, 0, 1959},\n\tdictWord{9, 0, 914},\n\tdictWord{9, 0, 939},\n\tdictWord{9, 0, 952},\n\tdictWord{9, 0, 979},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t990,\n\t},\n\tdictWord{9, 0, 998},\n\tdictWord{9, 0, 1003},\n\tdictWord{9, 0, 1023},\n\tdictWord{12, 0, 827},\n\tdictWord{12, 0, 834},\n\tdictWord{12, 0, 845},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t912,\n\t},\n\tdictWord{12, 0, 935},\n\tdictWord{12, 0, 951},\n\tdictWord{15, 0, 172},\n\tdictWord{15, 0, 174},\n\tdictWord{18, 0, 198},\n\tdictWord{149, 0, 63},\n\tdictWord{5, 0, 958},\n\tdictWord{5, 0, 987},\n\tdictWord{4, 11, 499},\n\tdictWord{135, 11, 1421},\n\tdictWord{7, 0, 885},\n\tdictWord{6, 10, 59},\n\tdictWord{6, 10, 1762},\n\tdictWord{9, 10, 603},\n\tdictWord{141, 10, 397},\n\tdictWord{10, 11, 62},\n\tdictWord{141, 11, 164},\n\tdictWord{4, 0, 847},\n\tdictWord{135, 0, 326},\n\tdictWord{11, 0, 276},\n\tdictWord{142, 0, 293},\n\tdictWord{4, 0, 65},\n\tdictWord{5, 0, 479},\n\tdictWord{5, 0, 1004},\n\tdictWord{7, 0, 1913},\n\tdictWord{8, 0, 317},\n\tdictWord{9, 0, 302},\n\tdictWord{10, 0, 612},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t22,\n\t},\n\tdictWord{132, 11, 96},\n\tdictWord{4, 0, 261},\n\tdictWord{135, 0, 510},\n\tdictWord{135, 0, 1514},\n\tdictWord{6, 10, 111},\n\tdictWord{7, 10, 4},\n\tdictWord{8, 10, 163},\n\tdictWord{8, 10, 776},\n\tdictWord{138, 10, 566},\n\tdictWord{4, 0, 291},\n\tdictWord{9, 0, 515},\n\tdictWord{12, 0, 152},\n\tdictWord{12, 0, 443},\n\tdictWord{13, 0, 392},\n\tdictWord{142, 0, 357},\n\tdictWord{7, 11, 399},\n\tdictWord{135, 11, 1492},\n\tdictWord{4, 0, 589},\n\tdictWord{139, 0, 282},\n\tdictWord{6, 11, 563},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1994,\n\t},\n\tdictWord{5, 10, 297},\n\tdictWord{135, 10, 1038},\n\tdictWord{4, 0, 130},\n\tdictWord{7, 0, 843},\n\tdictWord{135, 0, 1562},\n\tdictWord{5, 0, 42},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t879,\n\t},\n\tdictWord{7, 0, 245},\n\tdictWord{7, 0, 324},\n\tdictWord{7, 0, 1532},\n\tdictWord{11, 0, 463},\n\tdictWord{11, 0, 472},\n\tdictWord{13, 0, 363},\n\tdictWord{144, 0, 52},\n\tdictWord{4, 0, 134},\n\tdictWord{133, 0, 372},\n\tdictWord{133, 0, 680},\n\tdictWord{136, 10, 363},\n\tdictWord{6, 0, 1997},\n\tdictWord{8, 0, 935},\n\tdictWord{136, 0, 977},\n\tdictWord{4, 0, 810},\n\tdictWord{135, 0, 1634},\n\tdictWord{135, 10, 1675},\n\tdictWord{7, 0, 1390},\n\tdictWord{4, 11, 910},\n\tdictWord{133, 11, 832},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t808,\n\t},\n\tdictWord{8, 11, 266},\n\tdictWord{139, 11, 578},\n\tdictWord{132, 0, 644},\n\tdictWord{4, 0, 982},\n\tdictWord{138, 0, 867},\n\tdictWord{132, 10, 280},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t540,\n\t},\n\tdictWord{140, 10, 54},\n\tdictWord{135, 0, 123},\n\tdictWord{134, 0, 1978},\n\tdictWord{4, 10, 421},\n\tdictWord{133, 10, 548},\n\tdictWord{6, 0, 623},\n\tdictWord{136, 0, 789},\n\tdictWord{4, 0, 908},\n\tdictWord{5, 0, 359},\n\tdictWord{5, 0, 508},\n\tdictWord{6, 0, 1723},\n\tdictWord{7, 0, 343},\n\tdictWord{7, 0, 1996},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t2026,\n\t},\n\tdictWord{134, 0, 1220},\n\tdictWord{4, 0, 341},\n\tdictWord{135, 0, 480},\n\tdictWord{6, 10, 254},\n\tdictWord{9, 10, 109},\n\tdictWord{138, 10, 103},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t888,\n\t},\n\tdictWord{8, 11, 528},\n\tdictWord{137, 11, 348},\n\tdictWord{7, 0, 1995},\n\tdictWord{8, 0, 299},\n\tdictWord{11, 0, 890},\n\tdictWord{12, 0, 674},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t20,\n\t},\n\tdictWord{133, 11, 616},\n\tdictWord{135, 11, 1094},\n\tdictWord{134, 10, 1630},\n\tdictWord{4, 0, 238},\n\tdictWord{5, 0, 503},\n\tdictWord{6, 0, 179},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t2003,\n\t},\n\tdictWord{8, 0, 381},\n\tdictWord{8, 0, 473},\n\tdictWord{9, 0, 149},\n\tdictWord{10, 0, 788},\n\tdictWord{15, 0, 45},\n\tdictWord{15, 0, 86},\n\tdictWord{20, 0, 110},\n\tdictWord{150, 0, 57},\n\tdictWord{133, 10, 671},\n\tdictWord{4, 11, 26},\n\tdictWord{5, 11, 429},\n\tdictWord{6, 11, 245},\n\tdictWord{7, 11, 704},\n\tdictWord{7, 11, 1379},\n\tdictWord{135, 11, 1474},\n\tdictWord{4, 0, 121},\n\tdictWord{5, 0, 156},\n\tdictWord{5, 0, 349},\n\tdictWord{9, 0, 431},\n\tdictWord{10, 0, 605},\n\tdictWord{142, 0, 342},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t943,\n\t},\n\tdictWord{139, 11, 614},\n\tdictWord{132, 10, 889},\n\tdictWord{132, 11, 621},\n\tdictWord{7, 10, 1382},\n\tdictWord{7, 11, 1382},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1910,\n\t},\n\tdictWord{132, 10, 627},\n\tdictWord{133, 10, 775},\n\tdictWord{133, 11, 542},\n\tdictWord{133, 11, 868},\n\tdictWord{136, 11, 433},\n\tdictWord{6, 0, 1373},\n\tdictWord{7, 0, 1011},\n\tdictWord{11, 10, 362},\n\tdictWord{11, 10, 948},\n\tdictWord{140, 10, 388},\n\tdictWord{6, 0, 80},\n\tdictWord{7, 0, 173},\n\tdictWord{9, 0, 547},\n\tdictWord{10, 0, 730},\n\tdictWord{14, 0, 18},\n\tdictWord{22, 0, 39},\n\tdictWord{135, 11, 1495},\n\tdictWord{6, 0, 1694},\n\tdictWord{135, 0, 1974},\n\tdictWord{140, 0, 196},\n\tdictWord{4, 0, 923},\n\tdictWord{6, 0, 507},\n\tdictWord{6, 0, 1711},\n\tdictWord{7, 10, 451},\n\tdictWord{8, 10, 389},\n\tdictWord{12, 10, 490},\n\tdictWord{13, 10, 16},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t215,\n\t},\n\tdictWord{13, 10, 351},\n\tdictWord{18, 10, 132},\n\tdictWord{147, 10, 125},\n\tdictWord{6, 0, 646},\n\tdictWord{134, 0, 1047},\n\tdictWord{135, 10, 841},\n\tdictWord{136, 10, 566},\n\tdictWord{6, 0, 1611},\n\tdictWord{135, 0, 1214},\n\tdictWord{139, 0, 926},\n\tdictWord{132, 11, 525},\n\tdictWord{132, 0, 595},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t240,\n\t},\n\tdictWord{6, 0, 459},\n\tdictWord{7, 0, 12},\n\tdictWord{7, 0, 114},\n\tdictWord{7, 0, 949},\n\tdictWord{7, 0, 1753},\n\tdictWord{7, 0, 1805},\n\tdictWord{8, 0, 658},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t1,\n\t},\n\tdictWord{11, 0, 959},\n\tdictWord{141, 0, 446},\n\tdictWord{5, 10, 912},\n\tdictWord{134, 10, 1695},\n\tdictWord{132, 0, 446},\n\tdictWord{7, 11, 62},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t45,\n\t},\n\tdictWord{147, 11, 112},\n\tdictWord{5, 10, 236},\n\tdictWord{6, 10, 572},\n\tdictWord{8, 10, 492},\n\tdictWord{11, 10, 618},\n\tdictWord{144, 10, 56},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t190,\n\t},\n\tdictWord{136, 10, 318},\n\tdictWord{135, 10, 1376},\n\tdictWord{4, 11, 223},\n\tdictWord{6, 11, 359},\n\tdictWord{11, 11, 3},\n\tdictWord{13, 11, 108},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t89,\n\t},\n\tdictWord{144, 11, 22},\n\tdictWord{132, 11, 647},\n\tdictWord{134, 0, 490},\n\tdictWord{134, 0, 491},\n\tdictWord{134, 0, 1584},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t685,\n\t},\n\tdictWord{138, 11, 220},\n\tdictWord{7, 0, 250},\n\tdictWord{136, 0, 507},\n\tdictWord{132, 0, 158},\n\tdictWord{4, 0, 140},\n\tdictWord{7, 0, 362},\n\tdictWord{8, 0, 209},\n\tdictWord{9, 0, 10},\n\tdictWord{9, 0, 160},\n\tdictWord{9, 0, 503},\n\tdictWord{9, 0, 614},\n\tdictWord{10, 0, 689},\n\tdictWord{11, 0, 327},\n\tdictWord{11, 0, 553},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t725,\n\t},\n\tdictWord{11, 0, 767},\n\tdictWord{12, 0, 252},\n\tdictWord{12, 0, 583},\n\tdictWord{13, 0, 192},\n\tdictWord{14, 0, 269},\n\tdictWord{14, 0, 356},\n\tdictWord{148, 0, 50},\n\tdictWord{19, 0, 1},\n\tdictWord{19, 0, 26},\n\tdictWord{150, 0, 9},\n\tdictWord{132, 11, 109},\n\tdictWord{6, 0, 228},\n\tdictWord{7, 0, 1341},\n\tdictWord{9, 0, 408},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t343,\n\t},\n\tdictWord{4, 0, 373},\n\tdictWord{5, 0, 283},\n\tdictWord{6, 0, 480},\n\tdictWord{7, 0, 609},\n\tdictWord{10, 0, 860},\n\tdictWord{138, 0, 878},\n\tdictWord{6, 0, 779},\n\tdictWord{134, 0, 1209},\n\tdictWord{4, 0, 557},\n\tdictWord{7, 11, 263},\n\tdictWord{7, 11, 628},\n\tdictWord{136, 11, 349},\n\tdictWord{132, 0, 548},\n\tdictWord{7, 0, 197},\n\tdictWord{8, 0, 142},\n\tdictWord{8, 0, 325},\n\tdictWord{9, 0, 150},\n\tdictWord{9, 0, 596},\n\tdictWord{10, 0, 350},\n\tdictWord{10, 0, 353},\n\tdictWord{11, 0, 74},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t315,\n\t},\n\tdictWord{12, 0, 662},\n\tdictWord{12, 0, 681},\n\tdictWord{14, 0, 423},\n\tdictWord{143, 0, 141},\n\tdictWord{4, 11, 40},\n\tdictWord{10, 11, 67},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t117,\n\t},\n\tdictWord{11, 11, 768},\n\tdictWord{139, 11, 935},\n\tdictWord{7, 11, 992},\n\tdictWord{8, 11, 301},\n\tdictWord{9, 11, 722},\n\tdictWord{12, 11, 63},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t29,\n\t},\n\tdictWord{14, 11, 161},\n\tdictWord{143, 11, 18},\n\tdictWord{6, 0, 1490},\n\tdictWord{138, 11, 532},\n\tdictWord{5, 0, 580},\n\tdictWord{7, 0, 378},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t674,\n\t},\n\tdictWord{7, 0, 1424},\n\tdictWord{15, 0, 83},\n\tdictWord{16, 0, 11},\n\tdictWord{15, 11, 83},\n\tdictWord{144, 11, 11},\n\tdictWord{6, 0, 1057},\n\tdictWord{6, 0, 1335},\n\tdictWord{10, 0, 316},\n\tdictWord{7, 10, 85},\n\tdictWord{7, 10, 247},\n\tdictWord{8, 10, 585},\n\tdictWord{138, 10, 163},\n\tdictWord{4, 0, 169},\n\tdictWord{5, 0, 83},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t399,\n\t},\n\tdictWord{6, 0, 579},\n\tdictWord{6, 0, 1513},\n\tdictWord{7, 0, 692},\n\tdictWord{7, 0, 846},\n\tdictWord{7, 0, 1015},\n\tdictWord{7, 0, 1799},\n\tdictWord{8, 0, 403},\n\tdictWord{9, 0, 394},\n\tdictWord{10, 0, 133},\n\tdictWord{12, 0, 4},\n\tdictWord{12, 0, 297},\n\tdictWord{12, 0, 452},\n\tdictWord{16, 0, 81},\n\tdictWord{18, 0, 25},\n\tdictWord{21, 0, 14},\n\tdictWord{22, 0, 12},\n\tdictWord{151, 0, 18},\n\tdictWord{134, 0, 1106},\n\tdictWord{7, 0, 1546},\n\tdictWord{11, 0, 299},\n\tdictWord{142, 0, 407},\n\tdictWord{134, 0, 1192},\n\tdictWord{132, 0, 177},\n\tdictWord{5, 0, 411},\n\tdictWord{135, 0, 653},\n\tdictWord{7, 0, 439},\n\tdictWord{10, 0, 727},\n\tdictWord{11, 0, 260},\n\tdictWord{139, 0, 684},\n\tdictWord{138, 10, 145},\n\tdictWord{147, 10, 83},\n\tdictWord{5, 0, 208},\n\tdictWord{7, 0, 753},\n\tdictWord{135, 0, 1528},\n\tdictWord{137, 11, 617},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1922,\n\t},\n\tdictWord{135, 11, 825},\n\tdictWord{11, 0, 422},\n\tdictWord{13, 0, 389},\n\tdictWord{4, 10, 124},\n\tdictWord{10, 10, 457},\n\tdictWord{11, 10, 121},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t169,\n\t},\n\tdictWord{11, 10, 870},\n\tdictWord{12, 10, 214},\n\tdictWord{14, 10, 187},\n\tdictWord{143, 10, 77},\n\tdictWord{11, 0, 615},\n\tdictWord{15, 0, 58},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t615,\n\t},\n\tdictWord{143, 11, 58},\n\tdictWord{9, 0, 618},\n\tdictWord{138, 0, 482},\n\tdictWord{6, 0, 1952},\n\tdictWord{6, 0, 1970},\n\tdictWord{142, 0, 505},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1193,\n\t},\n\tdictWord{135, 11, 1838},\n\tdictWord{133, 0, 242},\n\tdictWord{135, 10, 1333},\n\tdictWord{6, 10, 107},\n\tdictWord{7, 10, 638},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1632,\n\t},\n\tdictWord{137, 10, 396},\n\tdictWord{133, 0, 953},\n\tdictWord{5, 10, 370},\n\tdictWord{134, 10, 1756},\n\tdictWord{5, 11, 28},\n\tdictWord{6, 11, 204},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t320,\n\t},\n\tdictWord{10, 11, 583},\n\tdictWord{13, 11, 502},\n\tdictWord{14, 11, 72},\n\tdictWord{14, 11, 274},\n\tdictWord{14, 11, 312},\n\tdictWord{14, 11, 344},\n\tdictWord{15, 11, 159},\n\tdictWord{16, 11, 62},\n\tdictWord{16, 11, 69},\n\tdictWord{17, 11, 30},\n\tdictWord{18, 11, 42},\n\tdictWord{18, 11, 53},\n\tdictWord{18, 11, 84},\n\tdictWord{18, 11, 140},\n\tdictWord{19, 11, 68},\n\tdictWord{19, 11, 85},\n\tdictWord{20, 11, 5},\n\tdictWord{20, 11, 45},\n\tdictWord{20, 11, 101},\n\tdictWord{22, 11, 7},\n\tdictWord{\n\t\t150,\n\t\t11,\n\t\t20,\n\t},\n\tdictWord{4, 11, 558},\n\tdictWord{6, 11, 390},\n\tdictWord{7, 11, 162},\n\tdictWord{7, 11, 689},\n\tdictWord{9, 11, 360},\n\tdictWord{138, 11, 653},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t802,\n\t},\n\tdictWord{141, 0, 67},\n\tdictWord{133, 10, 204},\n\tdictWord{133, 0, 290},\n\tdictWord{5, 10, 970},\n\tdictWord{134, 10, 1706},\n\tdictWord{132, 0, 380},\n\tdictWord{5, 0, 52},\n\tdictWord{7, 0, 277},\n\tdictWord{9, 0, 368},\n\tdictWord{139, 0, 791},\n\tdictWord{5, 11, 856},\n\tdictWord{6, 11, 1672},\n\tdictWord{6, 11, 1757},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t1781,\n\t},\n\tdictWord{7, 11, 1150},\n\tdictWord{7, 11, 1425},\n\tdictWord{7, 11, 1453},\n\tdictWord{140, 11, 513},\n\tdictWord{5, 11, 92},\n\tdictWord{7, 10, 3},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t736,\n\t},\n\tdictWord{140, 11, 102},\n\tdictWord{4, 0, 112},\n\tdictWord{5, 0, 653},\n\tdictWord{5, 10, 483},\n\tdictWord{5, 10, 685},\n\tdictWord{6, 10, 489},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1204,\n\t},\n\tdictWord{136, 10, 394},\n\tdictWord{132, 10, 921},\n\tdictWord{6, 0, 1028},\n\tdictWord{133, 10, 1007},\n\tdictWord{5, 11, 590},\n\tdictWord{9, 11, 213},\n\tdictWord{145, 11, 91},\n\tdictWord{135, 10, 1696},\n\tdictWord{10, 0, 138},\n\tdictWord{139, 0, 476},\n\tdictWord{5, 0, 725},\n\tdictWord{5, 0, 727},\n\tdictWord{135, 0, 1811},\n\tdictWord{4, 0, 979},\n\tdictWord{6, 0, 1821},\n\tdictWord{6, 0, 1838},\n\tdictWord{8, 0, 876},\n\tdictWord{8, 0, 883},\n\tdictWord{8, 0, 889},\n\tdictWord{8, 0, 893},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t895,\n\t},\n\tdictWord{10, 0, 934},\n\tdictWord{12, 0, 720},\n\tdictWord{14, 0, 459},\n\tdictWord{148, 0, 123},\n\tdictWord{135, 11, 551},\n\tdictWord{4, 0, 38},\n\tdictWord{6, 0, 435},\n\tdictWord{7, 0, 307},\n\tdictWord{7, 0, 999},\n\tdictWord{7, 0, 1481},\n\tdictWord{7, 0, 1732},\n\tdictWord{7, 0, 1738},\n\tdictWord{8, 0, 371},\n\tdictWord{9, 0, 414},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t316,\n\t},\n\tdictWord{12, 0, 52},\n\tdictWord{13, 0, 420},\n\tdictWord{147, 0, 100},\n\tdictWord{135, 0, 1296},\n\tdictWord{132, 10, 712},\n\tdictWord{134, 10, 1629},\n\tdictWord{133, 0, 723},\n\tdictWord{134, 0, 651},\n\tdictWord{136, 11, 191},\n\tdictWord{9, 11, 791},\n\tdictWord{10, 11, 93},\n\tdictWord{11, 11, 301},\n\tdictWord{16, 11, 13},\n\tdictWord{17, 11, 23},\n\tdictWord{18, 11, 135},\n\tdictWord{19, 11, 12},\n\tdictWord{20, 11, 1},\n\tdictWord{20, 11, 12},\n\tdictWord{148, 11, 14},\n\tdictWord{136, 11, 503},\n\tdictWord{6, 11, 466},\n\tdictWord{135, 11, 671},\n\tdictWord{6, 0, 1200},\n\tdictWord{134, 0, 1330},\n\tdictWord{135, 0, 1255},\n\tdictWord{134, 0, 986},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t109,\n\t},\n\tdictWord{6, 0, 1784},\n\tdictWord{7, 0, 1895},\n\tdictWord{12, 0, 296},\n\tdictWord{140, 0, 302},\n\tdictWord{135, 11, 983},\n\tdictWord{133, 10, 485},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t660,\n\t},\n\tdictWord{134, 0, 800},\n\tdictWord{5, 0, 216},\n\tdictWord{5, 0, 294},\n\tdictWord{6, 0, 591},\n\tdictWord{7, 0, 1879},\n\tdictWord{9, 0, 141},\n\tdictWord{9, 0, 270},\n\tdictWord{9, 0, 679},\n\tdictWord{10, 0, 159},\n\tdictWord{11, 0, 197},\n\tdictWord{11, 0, 438},\n\tdictWord{12, 0, 538},\n\tdictWord{12, 0, 559},\n\tdictWord{14, 0, 144},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t167,\n\t},\n\tdictWord{15, 0, 67},\n\tdictWord{4, 10, 285},\n\tdictWord{5, 10, 317},\n\tdictWord{6, 10, 301},\n\tdictWord{7, 10, 7},\n\tdictWord{8, 10, 153},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t766,\n\t},\n\tdictWord{11, 10, 468},\n\tdictWord{12, 10, 467},\n\tdictWord{141, 10, 143},\n\tdictWord{136, 0, 945},\n\tdictWord{134, 0, 1090},\n\tdictWord{137, 0, 81},\n\tdictWord{12, 11, 468},\n\tdictWord{19, 11, 96},\n\tdictWord{148, 11, 24},\n\tdictWord{134, 0, 391},\n\tdictWord{138, 11, 241},\n\tdictWord{7, 0, 322},\n\tdictWord{136, 0, 249},\n\tdictWord{134, 0, 1412},\n\tdictWord{135, 11, 795},\n\tdictWord{5, 0, 632},\n\tdictWord{138, 0, 526},\n\tdictWord{136, 10, 819},\n\tdictWord{6, 0, 144},\n\tdictWord{7, 0, 948},\n\tdictWord{7, 0, 1042},\n\tdictWord{8, 0, 235},\n\tdictWord{8, 0, 461},\n\tdictWord{9, 0, 453},\n\tdictWord{9, 0, 796},\n\tdictWord{10, 0, 354},\n\tdictWord{17, 0, 77},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t954,\n\t},\n\tdictWord{139, 10, 917},\n\tdictWord{6, 0, 940},\n\tdictWord{134, 0, 1228},\n\tdictWord{4, 0, 362},\n\tdictWord{7, 0, 52},\n\tdictWord{135, 0, 303},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t549,\n\t},\n\tdictWord{8, 11, 34},\n\tdictWord{8, 11, 283},\n\tdictWord{9, 11, 165},\n\tdictWord{138, 11, 475},\n\tdictWord{7, 11, 370},\n\tdictWord{7, 11, 1007},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1177,\n\t},\n\tdictWord{135, 11, 1565},\n\tdictWord{5, 11, 652},\n\tdictWord{5, 11, 701},\n\tdictWord{135, 11, 449},\n\tdictWord{5, 0, 196},\n\tdictWord{6, 0, 486},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t212,\n\t},\n\tdictWord{8, 0, 309},\n\tdictWord{136, 0, 346},\n\tdictWord{6, 10, 1719},\n\tdictWord{6, 10, 1735},\n\tdictWord{7, 10, 2016},\n\tdictWord{7, 10, 2020},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t837,\n\t},\n\tdictWord{137, 10, 852},\n\tdictWord{6, 11, 159},\n\tdictWord{6, 11, 364},\n\tdictWord{7, 11, 516},\n\tdictWord{7, 11, 1439},\n\tdictWord{137, 11, 518},\n\tdictWord{135, 0, 1912},\n\tdictWord{135, 0, 1290},\n\tdictWord{132, 0, 686},\n\tdictWord{141, 11, 151},\n\tdictWord{138, 0, 625},\n\tdictWord{136, 0, 706},\n\tdictWord{\n\t\t138,\n\t\t10,\n\t\t568,\n\t},\n\tdictWord{139, 0, 412},\n\tdictWord{4, 0, 30},\n\tdictWord{133, 0, 43},\n\tdictWord{8, 10, 67},\n\tdictWord{138, 10, 419},\n\tdictWord{7, 0, 967},\n\tdictWord{\n\t\t141,\n\t\t0,\n\t\t11,\n\t},\n\tdictWord{12, 0, 758},\n\tdictWord{14, 0, 441},\n\tdictWord{142, 0, 462},\n\tdictWord{10, 10, 657},\n\tdictWord{14, 10, 297},\n\tdictWord{142, 10, 361},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t729,\n\t},\n\tdictWord{4, 0, 220},\n\tdictWord{135, 0, 1535},\n\tdictWord{7, 11, 501},\n\tdictWord{9, 11, 111},\n\tdictWord{10, 11, 141},\n\tdictWord{11, 11, 332},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t43,\n\t},\n\tdictWord{13, 11, 429},\n\tdictWord{14, 11, 130},\n\tdictWord{14, 11, 415},\n\tdictWord{145, 11, 102},\n\tdictWord{4, 0, 950},\n\tdictWord{6, 0, 1859},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t11,\n\t},\n\tdictWord{8, 0, 873},\n\tdictWord{12, 0, 710},\n\tdictWord{12, 0, 718},\n\tdictWord{12, 0, 748},\n\tdictWord{12, 0, 765},\n\tdictWord{148, 0, 124},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t149,\n\t},\n\tdictWord{5, 11, 935},\n\tdictWord{136, 11, 233},\n\tdictWord{142, 11, 291},\n\tdictWord{134, 0, 1579},\n\tdictWord{7, 0, 890},\n\tdictWord{8, 10, 51},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t868,\n\t},\n\tdictWord{10, 10, 833},\n\tdictWord{12, 10, 481},\n\tdictWord{12, 10, 570},\n\tdictWord{148, 10, 106},\n\tdictWord{141, 0, 2},\n\tdictWord{132, 10, 445},\n\tdictWord{136, 11, 801},\n\tdictWord{135, 0, 1774},\n\tdictWord{7, 0, 1725},\n\tdictWord{138, 0, 393},\n\tdictWord{5, 0, 263},\n\tdictWord{134, 0, 414},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t322,\n\t},\n\tdictWord{133, 10, 239},\n\tdictWord{7, 0, 456},\n\tdictWord{7, 10, 1990},\n\tdictWord{8, 10, 130},\n\tdictWord{139, 10, 720},\n\tdictWord{137, 0, 818},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t123,\n\t},\n\tdictWord{6, 10, 530},\n\tdictWord{7, 10, 348},\n\tdictWord{135, 10, 1419},\n\tdictWord{135, 10, 2024},\n\tdictWord{6, 0, 178},\n\tdictWord{6, 0, 1750},\n\tdictWord{8, 0, 251},\n\tdictWord{9, 0, 690},\n\tdictWord{10, 0, 155},\n\tdictWord{10, 0, 196},\n\tdictWord{10, 0, 373},\n\tdictWord{11, 0, 698},\n\tdictWord{13, 0, 155},\n\tdictWord{\n\t\t148,\n\t\t0,\n\t\t93,\n\t},\n\tdictWord{5, 0, 97},\n\tdictWord{137, 0, 393},\n\tdictWord{134, 0, 674},\n\tdictWord{11, 0, 223},\n\tdictWord{140, 0, 168},\n\tdictWord{132, 10, 210},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t464,\n\t},\n\tdictWord{6, 0, 1639},\n\tdictWord{146, 0, 159},\n\tdictWord{139, 11, 2},\n\tdictWord{7, 0, 934},\n\tdictWord{8, 0, 647},\n\tdictWord{17, 0, 97},\n\tdictWord{19, 0, 59},\n\tdictWord{150, 0, 2},\n\tdictWord{132, 0, 191},\n\tdictWord{5, 0, 165},\n\tdictWord{9, 0, 346},\n\tdictWord{10, 0, 655},\n\tdictWord{11, 0, 885},\n\tdictWord{4, 10, 430},\n\tdictWord{135, 11, 357},\n\tdictWord{133, 0, 877},\n\tdictWord{5, 10, 213},\n\tdictWord{133, 11, 406},\n\tdictWord{8, 0, 128},\n\tdictWord{139, 0, 179},\n\tdictWord{6, 11, 69},\n\tdictWord{135, 11, 117},\n\tdictWord{135, 0, 1297},\n\tdictWord{11, 11, 43},\n\tdictWord{13, 11, 72},\n\tdictWord{141, 11, 142},\n\tdictWord{135, 11, 1830},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t164,\n\t},\n\tdictWord{5, 0, 57},\n\tdictWord{6, 0, 101},\n\tdictWord{6, 0, 586},\n\tdictWord{6, 0, 1663},\n\tdictWord{7, 0, 132},\n\tdictWord{7, 0, 1154},\n\tdictWord{7, 0, 1415},\n\tdictWord{7, 0, 1507},\n\tdictWord{12, 0, 493},\n\tdictWord{15, 0, 105},\n\tdictWord{151, 0, 15},\n\tdictWord{5, 0, 459},\n\tdictWord{7, 0, 1073},\n\tdictWord{8, 0, 241},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t334,\n\t},\n\tdictWord{133, 11, 826},\n\tdictWord{133, 10, 108},\n\tdictWord{5, 10, 219},\n\tdictWord{10, 11, 132},\n\tdictWord{11, 11, 191},\n\tdictWord{11, 11, 358},\n\tdictWord{139, 11, 460},\n\tdictWord{6, 0, 324},\n\tdictWord{6, 0, 520},\n\tdictWord{7, 0, 338},\n\tdictWord{7, 0, 1729},\n\tdictWord{8, 0, 228},\n\tdictWord{139, 0, 750},\n\tdictWord{\n\t\t21,\n\t\t0,\n\t\t30,\n\t},\n\tdictWord{22, 0, 53},\n\tdictWord{4, 10, 193},\n\tdictWord{5, 10, 916},\n\tdictWord{7, 10, 364},\n\tdictWord{10, 10, 398},\n\tdictWord{10, 10, 726},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t317,\n\t},\n\tdictWord{11, 10, 626},\n\tdictWord{12, 10, 142},\n\tdictWord{12, 10, 288},\n\tdictWord{12, 10, 678},\n\tdictWord{13, 10, 313},\n\tdictWord{15, 10, 113},\n\tdictWord{146, 10, 114},\n\tdictWord{6, 11, 110},\n\tdictWord{135, 11, 1681},\n\tdictWord{135, 0, 910},\n\tdictWord{6, 10, 241},\n\tdictWord{7, 10, 907},\n\tdictWord{8, 10, 832},\n\tdictWord{9, 10, 342},\n\tdictWord{10, 10, 729},\n\tdictWord{11, 10, 284},\n\tdictWord{11, 10, 445},\n\tdictWord{11, 10, 651},\n\tdictWord{11, 10, 863},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t398,\n\t},\n\tdictWord{146, 10, 99},\n\tdictWord{7, 0, 705},\n\tdictWord{9, 0, 734},\n\tdictWord{5, 11, 1000},\n\tdictWord{7, 11, 733},\n\tdictWord{137, 11, 583},\n\tdictWord{4, 0, 73},\n\tdictWord{6, 0, 612},\n\tdictWord{7, 0, 927},\n\tdictWord{7, 0, 1822},\n\tdictWord{8, 0, 217},\n\tdictWord{9, 0, 765},\n\tdictWord{9, 0, 766},\n\tdictWord{10, 0, 408},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t51,\n\t},\n\tdictWord{11, 0, 793},\n\tdictWord{12, 0, 266},\n\tdictWord{15, 0, 158},\n\tdictWord{20, 0, 89},\n\tdictWord{150, 0, 32},\n\tdictWord{7, 0, 1330},\n\tdictWord{4, 11, 297},\n\tdictWord{6, 11, 529},\n\tdictWord{7, 11, 152},\n\tdictWord{7, 11, 713},\n\tdictWord{7, 11, 1845},\n\tdictWord{8, 11, 710},\n\tdictWord{8, 11, 717},\n\tdictWord{140, 11, 639},\n\tdictWord{5, 0, 389},\n\tdictWord{136, 0, 636},\n\tdictWord{134, 0, 1409},\n\tdictWord{4, 10, 562},\n\tdictWord{9, 10, 254},\n\tdictWord{139, 10, 879},\n\tdictWord{134, 0, 893},\n\tdictWord{132, 10, 786},\n\tdictWord{4, 11, 520},\n\tdictWord{135, 11, 575},\n\tdictWord{136, 0, 21},\n\tdictWord{140, 0, 721},\n\tdictWord{136, 0, 959},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1428,\n\t},\n\tdictWord{7, 11, 1640},\n\tdictWord{9, 11, 169},\n\tdictWord{9, 11, 182},\n\tdictWord{9, 11, 367},\n\tdictWord{9, 11, 478},\n\tdictWord{9, 11, 506},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t551,\n\t},\n\tdictWord{9, 11, 648},\n\tdictWord{9, 11, 651},\n\tdictWord{9, 11, 697},\n\tdictWord{9, 11, 705},\n\tdictWord{9, 11, 725},\n\tdictWord{9, 11, 787},\n\tdictWord{9, 11, 794},\n\tdictWord{10, 11, 198},\n\tdictWord{10, 11, 214},\n\tdictWord{10, 11, 267},\n\tdictWord{10, 11, 275},\n\tdictWord{10, 11, 456},\n\tdictWord{10, 11, 551},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t561,\n\t},\n\tdictWord{10, 11, 613},\n\tdictWord{10, 11, 627},\n\tdictWord{10, 11, 668},\n\tdictWord{10, 11, 675},\n\tdictWord{10, 11, 691},\n\tdictWord{10, 11, 695},\n\tdictWord{10, 11, 707},\n\tdictWord{10, 11, 715},\n\tdictWord{11, 11, 183},\n\tdictWord{11, 11, 201},\n\tdictWord{11, 11, 244},\n\tdictWord{11, 11, 262},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t352,\n\t},\n\tdictWord{11, 11, 439},\n\tdictWord{11, 11, 493},\n\tdictWord{11, 11, 572},\n\tdictWord{11, 11, 591},\n\tdictWord{11, 11, 608},\n\tdictWord{11, 11, 611},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t646,\n\t},\n\tdictWord{11, 11, 674},\n\tdictWord{11, 11, 711},\n\tdictWord{11, 11, 751},\n\tdictWord{11, 11, 761},\n\tdictWord{11, 11, 776},\n\tdictWord{11, 11, 785},\n\tdictWord{11, 11, 850},\n\tdictWord{11, 11, 853},\n\tdictWord{11, 11, 862},\n\tdictWord{11, 11, 865},\n\tdictWord{11, 11, 868},\n\tdictWord{11, 11, 898},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t902,\n\t},\n\tdictWord{11, 11, 903},\n\tdictWord{11, 11, 910},\n\tdictWord{11, 11, 932},\n\tdictWord{11, 11, 942},\n\tdictWord{11, 11, 957},\n\tdictWord{11, 11, 967},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t972,\n\t},\n\tdictWord{12, 11, 148},\n\tdictWord{12, 11, 195},\n\tdictWord{12, 11, 220},\n\tdictWord{12, 11, 237},\n\tdictWord{12, 11, 318},\n\tdictWord{12, 11, 339},\n\tdictWord{12, 11, 393},\n\tdictWord{12, 11, 445},\n\tdictWord{12, 11, 450},\n\tdictWord{12, 11, 474},\n\tdictWord{12, 11, 509},\n\tdictWord{12, 11, 533},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t591,\n\t},\n\tdictWord{12, 11, 594},\n\tdictWord{12, 11, 597},\n\tdictWord{12, 11, 621},\n\tdictWord{12, 11, 633},\n\tdictWord{12, 11, 642},\n\tdictWord{13, 11, 59},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t60,\n\t},\n\tdictWord{13, 11, 145},\n\tdictWord{13, 11, 239},\n\tdictWord{13, 11, 250},\n\tdictWord{13, 11, 273},\n\tdictWord{13, 11, 329},\n\tdictWord{13, 11, 344},\n\tdictWord{13, 11, 365},\n\tdictWord{13, 11, 372},\n\tdictWord{13, 11, 387},\n\tdictWord{13, 11, 403},\n\tdictWord{13, 11, 414},\n\tdictWord{13, 11, 456},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t478,\n\t},\n\tdictWord{13, 11, 483},\n\tdictWord{13, 11, 489},\n\tdictWord{14, 11, 55},\n\tdictWord{14, 11, 57},\n\tdictWord{14, 11, 81},\n\tdictWord{14, 11, 90},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t148,\n\t},\n\tdictWord{14, 11, 239},\n\tdictWord{14, 11, 266},\n\tdictWord{14, 11, 321},\n\tdictWord{14, 11, 326},\n\tdictWord{14, 11, 327},\n\tdictWord{14, 11, 330},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t347,\n\t},\n\tdictWord{14, 11, 355},\n\tdictWord{14, 11, 401},\n\tdictWord{14, 11, 411},\n\tdictWord{14, 11, 414},\n\tdictWord{14, 11, 416},\n\tdictWord{14, 11, 420},\n\tdictWord{15, 11, 61},\n\tdictWord{15, 11, 74},\n\tdictWord{15, 11, 87},\n\tdictWord{15, 11, 88},\n\tdictWord{15, 11, 94},\n\tdictWord{15, 11, 96},\n\tdictWord{15, 11, 116},\n\tdictWord{15, 11, 149},\n\tdictWord{15, 11, 154},\n\tdictWord{16, 11, 50},\n\tdictWord{16, 11, 63},\n\tdictWord{16, 11, 73},\n\tdictWord{17, 11, 2},\n\tdictWord{17, 11, 66},\n\tdictWord{\n\t\t17,\n\t\t11,\n\t\t92,\n\t},\n\tdictWord{17, 11, 103},\n\tdictWord{17, 11, 112},\n\tdictWord{18, 11, 50},\n\tdictWord{18, 11, 54},\n\tdictWord{18, 11, 82},\n\tdictWord{18, 11, 86},\n\tdictWord{\n\t\t18,\n\t\t11,\n\t\t90,\n\t},\n\tdictWord{18, 11, 111},\n\tdictWord{18, 11, 115},\n\tdictWord{18, 11, 156},\n\tdictWord{19, 11, 40},\n\tdictWord{19, 11, 79},\n\tdictWord{20, 11, 78},\n\tdictWord{\n\t\t149,\n\t\t11,\n\t\t22,\n\t},\n\tdictWord{137, 11, 170},\n\tdictWord{134, 0, 1433},\n\tdictWord{135, 11, 1307},\n\tdictWord{139, 11, 411},\n\tdictWord{5, 0, 189},\n\tdictWord{7, 0, 442},\n\tdictWord{7, 0, 443},\n\tdictWord{8, 0, 281},\n\tdictWord{12, 0, 174},\n\tdictWord{141, 0, 261},\n\tdictWord{6, 10, 216},\n\tdictWord{7, 10, 901},\n\tdictWord{7, 10, 1343},\n\tdictWord{136, 10, 493},\n\tdictWord{5, 11, 397},\n\tdictWord{6, 11, 154},\n\tdictWord{7, 10, 341},\n\tdictWord{7, 11, 676},\n\tdictWord{8, 11, 443},\n\tdictWord{8, 11, 609},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t24,\n\t},\n\tdictWord{9, 11, 325},\n\tdictWord{10, 11, 35},\n\tdictWord{11, 10, 219},\n\tdictWord{11, 11, 535},\n\tdictWord{11, 11, 672},\n\tdictWord{11, 11, 1018},\n\tdictWord{12, 11, 637},\n\tdictWord{144, 11, 30},\n\tdictWord{6, 0, 2},\n\tdictWord{7, 0, 191},\n\tdictWord{7, 0, 446},\n\tdictWord{7, 0, 1262},\n\tdictWord{7, 0, 1737},\n\tdictWord{8, 0, 22},\n\tdictWord{8, 0, 270},\n\tdictWord{8, 0, 612},\n\tdictWord{9, 0, 4},\n\tdictWord{9, 0, 312},\n\tdictWord{9, 0, 436},\n\tdictWord{9, 0, 626},\n\tdictWord{10, 0, 216},\n\tdictWord{10, 0, 311},\n\tdictWord{10, 0, 521},\n\tdictWord{10, 0, 623},\n\tdictWord{11, 0, 72},\n\tdictWord{11, 0, 330},\n\tdictWord{11, 0, 455},\n\tdictWord{12, 0, 321},\n\tdictWord{12, 0, 504},\n\tdictWord{12, 0, 530},\n\tdictWord{12, 0, 543},\n\tdictWord{13, 0, 17},\n\tdictWord{13, 0, 156},\n\tdictWord{13, 0, 334},\n\tdictWord{14, 0, 131},\n\tdictWord{17, 0, 60},\n\tdictWord{\n\t\t148,\n\t\t0,\n\t\t64,\n\t},\n\tdictWord{7, 0, 354},\n\tdictWord{10, 0, 410},\n\tdictWord{139, 0, 815},\n\tdictWord{139, 10, 130},\n\tdictWord{7, 10, 1734},\n\tdictWord{137, 11, 631},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t425,\n\t},\n\tdictWord{15, 0, 112},\n\tdictWord{10, 10, 115},\n\tdictWord{11, 10, 420},\n\tdictWord{13, 10, 404},\n\tdictWord{14, 10, 346},\n\tdictWord{143, 10, 54},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t60,\n\t},\n\tdictWord{6, 0, 166},\n\tdictWord{7, 0, 374},\n\tdictWord{7, 0, 670},\n\tdictWord{7, 0, 1327},\n\tdictWord{8, 0, 411},\n\tdictWord{8, 0, 435},\n\tdictWord{9, 0, 653},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t740,\n\t},\n\tdictWord{10, 0, 385},\n\tdictWord{11, 0, 222},\n\tdictWord{11, 0, 324},\n\tdictWord{11, 0, 829},\n\tdictWord{140, 0, 611},\n\tdictWord{7, 0, 1611},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t14,\n\t},\n\tdictWord{15, 0, 44},\n\tdictWord{19, 0, 13},\n\tdictWord{148, 0, 76},\n\tdictWord{133, 11, 981},\n\tdictWord{4, 11, 56},\n\tdictWord{7, 11, 1791},\n\tdictWord{8, 11, 607},\n\tdictWord{8, 11, 651},\n\tdictWord{11, 11, 465},\n\tdictWord{11, 11, 835},\n\tdictWord{12, 11, 337},\n\tdictWord{141, 11, 480},\n\tdictWord{6, 0, 1478},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t1011,\n\t},\n\tdictWord{136, 10, 701},\n\tdictWord{139, 0, 596},\n\tdictWord{5, 0, 206},\n\tdictWord{134, 0, 398},\n\tdictWord{4, 10, 54},\n\tdictWord{5, 10, 666},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1039,\n\t},\n\tdictWord{7, 10, 1130},\n\tdictWord{9, 10, 195},\n\tdictWord{138, 10, 302},\n\tdictWord{7, 0, 50},\n\tdictWord{9, 11, 158},\n\tdictWord{138, 11, 411},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1120,\n\t},\n\tdictWord{6, 0, 517},\n\tdictWord{7, 0, 1159},\n\tdictWord{10, 0, 621},\n\tdictWord{11, 0, 192},\n\tdictWord{134, 10, 1669},\n\tdictWord{4, 0, 592},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t600,\n\t},\n\tdictWord{135, 0, 1653},\n\tdictWord{10, 0, 223},\n\tdictWord{139, 0, 645},\n\tdictWord{136, 11, 139},\n\tdictWord{7, 0, 64},\n\tdictWord{136, 0, 245},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t278,\n\t},\n\tdictWord{6, 11, 622},\n\tdictWord{135, 11, 1030},\n\tdictWord{136, 0, 604},\n\tdictWord{134, 0, 1502},\n\tdictWord{138, 0, 265},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t168,\n\t},\n\tdictWord{7, 0, 1763},\n\tdictWord{140, 0, 310},\n\tdictWord{7, 10, 798},\n\tdictWord{139, 11, 719},\n\tdictWord{7, 11, 160},\n\tdictWord{10, 11, 624},\n\tdictWord{\n\t\t142,\n\t\t11,\n\t\t279,\n\t},\n\tdictWord{132, 11, 363},\n\tdictWord{7, 10, 122},\n\tdictWord{9, 10, 259},\n\tdictWord{10, 10, 84},\n\tdictWord{11, 10, 470},\n\tdictWord{12, 10, 541},\n\tdictWord{141, 10, 379},\n\tdictWord{5, 0, 129},\n\tdictWord{6, 0, 61},\n\tdictWord{135, 0, 947},\n\tdictWord{134, 0, 1356},\n\tdictWord{135, 11, 1191},\n\tdictWord{13, 0, 505},\n\tdictWord{141, 0, 506},\n\tdictWord{11, 0, 1000},\n\tdictWord{5, 10, 82},\n\tdictWord{5, 10, 131},\n\tdictWord{7, 10, 1755},\n\tdictWord{8, 10, 31},\n\tdictWord{9, 10, 168},\n\tdictWord{9, 10, 764},\n\tdictWord{139, 10, 869},\n\tdictWord{134, 0, 966},\n\tdictWord{134, 10, 605},\n\tdictWord{134, 11, 292},\n\tdictWord{5, 11, 177},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t616,\n\t},\n\tdictWord{7, 11, 827},\n\tdictWord{9, 11, 525},\n\tdictWord{138, 11, 656},\n\tdictWord{135, 11, 1486},\n\tdictWord{138, 11, 31},\n\tdictWord{5, 10, 278},\n\tdictWord{137, 10, 68},\n\tdictWord{4, 10, 163},\n\tdictWord{5, 10, 201},\n\tdictWord{5, 10, 307},\n\tdictWord{5, 10, 310},\n\tdictWord{6, 10, 335},\n\tdictWord{7, 10, 284},\n\tdictWord{136, 10, 165},\n\tdictWord{6, 0, 839},\n\tdictWord{135, 10, 1660},\n\tdictWord{136, 10, 781},\n\tdictWord{6, 10, 33},\n\tdictWord{135, 10, 1244},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t637,\n\t},\n\tdictWord{4, 11, 161},\n\tdictWord{133, 11, 631},\n\tdictWord{137, 0, 590},\n\tdictWord{7, 10, 1953},\n\tdictWord{136, 10, 720},\n\tdictWord{5, 0, 280},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1226,\n\t},\n\tdictWord{138, 10, 203},\n\tdictWord{134, 0, 1386},\n\tdictWord{5, 0, 281},\n\tdictWord{6, 0, 1026},\n\tdictWord{6, 10, 326},\n\tdictWord{7, 10, 677},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t425,\n\t},\n\tdictWord{7, 11, 1557},\n\tdictWord{135, 11, 1684},\n\tdictWord{135, 0, 1064},\n\tdictWord{9, 11, 469},\n\tdictWord{9, 11, 709},\n\tdictWord{12, 11, 512},\n\tdictWord{14, 11, 65},\n\tdictWord{145, 11, 12},\n\tdictWord{134, 0, 917},\n\tdictWord{10, 11, 229},\n\tdictWord{11, 11, 73},\n\tdictWord{11, 11, 376},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t433,\n\t},\n\tdictWord{7, 0, 555},\n\tdictWord{9, 0, 192},\n\tdictWord{13, 0, 30},\n\tdictWord{13, 0, 49},\n\tdictWord{15, 0, 150},\n\tdictWord{16, 0, 76},\n\tdictWord{20, 0, 52},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1316,\n\t},\n\tdictWord{7, 10, 1412},\n\tdictWord{7, 10, 1839},\n\tdictWord{9, 10, 589},\n\tdictWord{11, 10, 241},\n\tdictWord{11, 10, 676},\n\tdictWord{11, 10, 811},\n\tdictWord{11, 10, 891},\n\tdictWord{12, 10, 140},\n\tdictWord{12, 10, 346},\n\tdictWord{12, 10, 479},\n\tdictWord{13, 10, 381},\n\tdictWord{14, 10, 188},\n\tdictWord{\n\t\t146,\n\t\t10,\n\t\t30,\n\t},\n\tdictWord{149, 0, 15},\n\tdictWord{6, 0, 1882},\n\tdictWord{6, 0, 1883},\n\tdictWord{6, 0, 1897},\n\tdictWord{9, 0, 945},\n\tdictWord{9, 0, 1014},\n\tdictWord{9, 0, 1020},\n\tdictWord{12, 0, 823},\n\tdictWord{12, 0, 842},\n\tdictWord{12, 0, 866},\n\tdictWord{12, 0, 934},\n\tdictWord{15, 0, 242},\n\tdictWord{146, 0, 208},\n\tdictWord{6, 0, 965},\n\tdictWord{134, 0, 1499},\n\tdictWord{7, 0, 33},\n\tdictWord{7, 0, 120},\n\tdictWord{8, 0, 489},\n\tdictWord{9, 0, 319},\n\tdictWord{10, 0, 820},\n\tdictWord{11, 0, 1004},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t379,\n\t},\n\tdictWord{12, 0, 679},\n\tdictWord{13, 0, 117},\n\tdictWord{13, 0, 412},\n\tdictWord{14, 0, 25},\n\tdictWord{15, 0, 52},\n\tdictWord{15, 0, 161},\n\tdictWord{16, 0, 47},\n\tdictWord{149, 0, 2},\n\tdictWord{6, 11, 558},\n\tdictWord{7, 11, 651},\n\tdictWord{8, 11, 421},\n\tdictWord{9, 11, 0},\n\tdictWord{138, 11, 34},\n\tdictWord{4, 0, 937},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t801,\n\t},\n\tdictWord{7, 0, 473},\n\tdictWord{5, 10, 358},\n\tdictWord{7, 10, 1184},\n\tdictWord{10, 10, 662},\n\tdictWord{13, 10, 212},\n\tdictWord{13, 10, 304},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t333,\n\t},\n\tdictWord{145, 10, 98},\n\tdictWord{132, 0, 877},\n\tdictWord{6, 0, 693},\n\tdictWord{134, 0, 824},\n\tdictWord{132, 0, 365},\n\tdictWord{7, 11, 1832},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t374,\n\t},\n\tdictWord{5, 0, 7},\n\tdictWord{139, 0, 774},\n\tdictWord{4, 0, 734},\n\tdictWord{5, 0, 662},\n\tdictWord{134, 0, 430},\n\tdictWord{4, 0, 746},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1090,\n\t},\n\tdictWord{5, 0, 360},\n\tdictWord{8, 0, 237},\n\tdictWord{10, 0, 231},\n\tdictWord{147, 0, 124},\n\tdictWord{138, 11, 348},\n\tdictWord{6, 11, 6},\n\tdictWord{7, 11, 81},\n\tdictWord{7, 11, 771},\n\tdictWord{7, 11, 1731},\n\tdictWord{9, 11, 405},\n\tdictWord{138, 11, 421},\n\tdictWord{6, 0, 740},\n\tdictWord{137, 0, 822},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t946,\n\t},\n\tdictWord{7, 0, 1485},\n\tdictWord{136, 0, 929},\n\tdictWord{7, 10, 411},\n\tdictWord{8, 10, 631},\n\tdictWord{9, 10, 323},\n\tdictWord{10, 10, 355},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t491,\n\t},\n\tdictWord{12, 10, 143},\n\tdictWord{12, 10, 402},\n\tdictWord{13, 10, 73},\n\tdictWord{14, 10, 408},\n\tdictWord{15, 10, 107},\n\tdictWord{146, 10, 71},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t590,\n\t},\n\tdictWord{5, 11, 881},\n\tdictWord{133, 11, 885},\n\tdictWord{150, 11, 25},\n\tdictWord{4, 0, 852},\n\tdictWord{5, 11, 142},\n\tdictWord{134, 11, 546},\n\tdictWord{7, 10, 1467},\n\tdictWord{8, 10, 328},\n\tdictWord{10, 10, 544},\n\tdictWord{11, 10, 955},\n\tdictWord{13, 10, 320},\n\tdictWord{145, 10, 83},\n\tdictWord{9, 0, 17},\n\tdictWord{10, 0, 291},\n\tdictWord{11, 10, 511},\n\tdictWord{13, 10, 394},\n\tdictWord{14, 10, 298},\n\tdictWord{14, 10, 318},\n\tdictWord{146, 10, 103},\n\tdictWord{5, 11, 466},\n\tdictWord{11, 11, 571},\n\tdictWord{12, 11, 198},\n\tdictWord{13, 11, 283},\n\tdictWord{14, 11, 186},\n\tdictWord{15, 11, 21},\n\tdictWord{143, 11, 103},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1001,\n\t},\n\tdictWord{4, 11, 185},\n\tdictWord{5, 11, 257},\n\tdictWord{5, 11, 839},\n\tdictWord{5, 11, 936},\n\tdictWord{7, 11, 171},\n\tdictWord{9, 11, 399},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t258,\n\t},\n\tdictWord{10, 11, 395},\n\tdictWord{10, 11, 734},\n\tdictWord{11, 11, 1014},\n\tdictWord{12, 11, 23},\n\tdictWord{13, 11, 350},\n\tdictWord{14, 11, 150},\n\tdictWord{147, 11, 6},\n\tdictWord{143, 0, 35},\n\tdictWord{132, 0, 831},\n\tdictWord{5, 10, 835},\n\tdictWord{134, 10, 483},\n\tdictWord{4, 0, 277},\n\tdictWord{5, 0, 608},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t493,\n\t},\n\tdictWord{7, 0, 457},\n\tdictWord{12, 0, 384},\n\tdictWord{7, 11, 404},\n\tdictWord{7, 11, 1377},\n\tdictWord{7, 11, 1430},\n\tdictWord{7, 11, 2017},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t149,\n\t},\n\tdictWord{8, 11, 239},\n\tdictWord{8, 11, 512},\n\tdictWord{8, 11, 793},\n\tdictWord{8, 11, 818},\n\tdictWord{9, 11, 474},\n\tdictWord{9, 11, 595},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t122,\n\t},\n\tdictWord{10, 11, 565},\n\tdictWord{10, 11, 649},\n\tdictWord{10, 11, 783},\n\tdictWord{11, 11, 239},\n\tdictWord{11, 11, 295},\n\tdictWord{11, 11, 447},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t528,\n\t},\n\tdictWord{11, 11, 639},\n\tdictWord{11, 11, 800},\n\tdictWord{11, 11, 936},\n\tdictWord{12, 11, 25},\n\tdictWord{12, 11, 73},\n\tdictWord{12, 11, 77},\n\tdictWord{12, 11, 157},\n\tdictWord{12, 11, 316},\n\tdictWord{12, 11, 390},\n\tdictWord{12, 11, 391},\n\tdictWord{12, 11, 394},\n\tdictWord{12, 11, 395},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t478,\n\t},\n\tdictWord{12, 11, 503},\n\tdictWord{12, 11, 592},\n\tdictWord{12, 11, 680},\n\tdictWord{13, 11, 50},\n\tdictWord{13, 11, 53},\n\tdictWord{13, 11, 132},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t198,\n\t},\n\tdictWord{13, 11, 275},\n\tdictWord{13, 11, 322},\n\tdictWord{13, 11, 415},\n\tdictWord{14, 11, 71},\n\tdictWord{14, 11, 257},\n\tdictWord{14, 11, 395},\n\tdictWord{15, 11, 71},\n\tdictWord{15, 11, 136},\n\tdictWord{17, 11, 123},\n\tdictWord{18, 11, 93},\n\tdictWord{147, 11, 58},\n\tdictWord{134, 0, 1351},\n\tdictWord{7, 0, 27},\n\tdictWord{135, 0, 316},\n\tdictWord{136, 11, 712},\n\tdictWord{136, 0, 984},\n\tdictWord{133, 0, 552},\n\tdictWord{137, 0, 264},\n\tdictWord{132, 0, 401},\n\tdictWord{6, 0, 710},\n\tdictWord{6, 0, 1111},\n\tdictWord{134, 0, 1343},\n\tdictWord{134, 0, 1211},\n\tdictWord{9, 0, 543},\n\tdictWord{10, 0, 524},\n\tdictWord{11, 0, 108},\n\tdictWord{11, 0, 653},\n\tdictWord{12, 0, 524},\n\tdictWord{13, 0, 123},\n\tdictWord{14, 0, 252},\n\tdictWord{16, 0, 18},\n\tdictWord{19, 0, 38},\n\tdictWord{20, 0, 26},\n\tdictWord{20, 0, 65},\n\tdictWord{\n\t\t21,\n\t\t0,\n\t\t3,\n\t},\n\tdictWord{151, 0, 11},\n\tdictWord{4, 0, 205},\n\tdictWord{5, 0, 623},\n\tdictWord{7, 0, 104},\n\tdictWord{8, 0, 519},\n\tdictWord{137, 0, 716},\n\tdictWord{132, 10, 677},\n\tdictWord{4, 11, 377},\n\tdictWord{152, 11, 13},\n\tdictWord{135, 11, 1673},\n\tdictWord{7, 0, 579},\n\tdictWord{9, 0, 41},\n\tdictWord{9, 0, 244},\n\tdictWord{9, 0, 669},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t5,\n\t},\n\tdictWord{11, 0, 861},\n\tdictWord{11, 0, 951},\n\tdictWord{139, 0, 980},\n\tdictWord{132, 0, 717},\n\tdictWord{136, 0, 1011},\n\tdictWord{132, 0, 805},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t180,\n\t},\n\tdictWord{135, 11, 1906},\n\tdictWord{132, 10, 777},\n\tdictWord{132, 10, 331},\n\tdictWord{132, 0, 489},\n\tdictWord{6, 0, 1024},\n\tdictWord{4, 11, 491},\n\tdictWord{133, 10, 747},\n\tdictWord{135, 11, 1182},\n\tdictWord{4, 11, 171},\n\tdictWord{138, 11, 234},\n\tdictWord{4, 11, 586},\n\tdictWord{7, 11, 1186},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t631,\n\t},\n\tdictWord{135, 0, 892},\n\tdictWord{135, 11, 336},\n\tdictWord{9, 11, 931},\n\tdictWord{10, 11, 334},\n\tdictWord{148, 11, 71},\n\tdictWord{137, 0, 473},\n\tdictWord{6, 0, 864},\n\tdictWord{12, 0, 659},\n\tdictWord{139, 11, 926},\n\tdictWord{7, 0, 819},\n\tdictWord{9, 0, 26},\n\tdictWord{9, 0, 392},\n\tdictWord{10, 0, 152},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t226,\n\t},\n\tdictWord{11, 0, 19},\n\tdictWord{12, 0, 276},\n\tdictWord{12, 0, 426},\n\tdictWord{12, 0, 589},\n\tdictWord{13, 0, 460},\n\tdictWord{15, 0, 97},\n\tdictWord{19, 0, 48},\n\tdictWord{148, 0, 104},\n\tdictWord{135, 0, 51},\n\tdictWord{133, 10, 326},\n\tdictWord{4, 10, 691},\n\tdictWord{146, 10, 16},\n\tdictWord{9, 0, 130},\n\tdictWord{11, 0, 765},\n\tdictWord{10, 10, 680},\n\tdictWord{10, 10, 793},\n\tdictWord{141, 10, 357},\n\tdictWord{133, 11, 765},\n\tdictWord{8, 0, 229},\n\tdictWord{6, 10, 32},\n\tdictWord{7, 10, 385},\n\tdictWord{7, 10, 757},\n\tdictWord{7, 10, 1916},\n\tdictWord{8, 10, 94},\n\tdictWord{8, 10, 711},\n\tdictWord{9, 10, 541},\n\tdictWord{10, 10, 162},\n\tdictWord{10, 10, 795},\n\tdictWord{11, 10, 989},\n\tdictWord{11, 10, 1010},\n\tdictWord{12, 10, 14},\n\tdictWord{142, 10, 308},\n\tdictWord{7, 11, 474},\n\tdictWord{137, 11, 578},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t674,\n\t},\n\tdictWord{132, 0, 770},\n\tdictWord{5, 0, 79},\n\tdictWord{7, 0, 1027},\n\tdictWord{7, 0, 1477},\n\tdictWord{139, 0, 52},\n\tdictWord{133, 11, 424},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1666,\n\t},\n\tdictWord{6, 0, 409},\n\tdictWord{6, 10, 349},\n\tdictWord{6, 10, 1682},\n\tdictWord{7, 10, 1252},\n\tdictWord{8, 10, 112},\n\tdictWord{8, 11, 714},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t435,\n\t},\n\tdictWord{9, 10, 668},\n\tdictWord{10, 10, 290},\n\tdictWord{10, 10, 319},\n\tdictWord{10, 10, 815},\n\tdictWord{11, 10, 180},\n\tdictWord{11, 10, 837},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t240,\n\t},\n\tdictWord{13, 10, 152},\n\tdictWord{13, 10, 219},\n\tdictWord{142, 10, 158},\n\tdictWord{5, 0, 789},\n\tdictWord{134, 0, 195},\n\tdictWord{4, 0, 251},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t688,\n\t},\n\tdictWord{7, 0, 513},\n\tdictWord{135, 0, 1284},\n\tdictWord{132, 10, 581},\n\tdictWord{9, 11, 420},\n\tdictWord{10, 11, 269},\n\tdictWord{10, 11, 285},\n\tdictWord{10, 11, 576},\n\tdictWord{11, 11, 397},\n\tdictWord{13, 11, 175},\n\tdictWord{145, 11, 90},\n\tdictWord{6, 10, 126},\n\tdictWord{7, 10, 573},\n\tdictWord{8, 10, 397},\n\tdictWord{142, 10, 44},\n\tdictWord{132, 11, 429},\n\tdictWord{133, 0, 889},\n\tdictWord{4, 0, 160},\n\tdictWord{5, 0, 330},\n\tdictWord{7, 0, 1434},\n\tdictWord{136, 0, 174},\n\tdictWord{7, 11, 18},\n\tdictWord{7, 11, 699},\n\tdictWord{7, 11, 1966},\n\tdictWord{8, 11, 752},\n\tdictWord{9, 11, 273},\n\tdictWord{9, 11, 412},\n\tdictWord{9, 11, 703},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t71,\n\t},\n\tdictWord{10, 11, 427},\n\tdictWord{10, 11, 508},\n\tdictWord{146, 11, 97},\n\tdictWord{6, 0, 872},\n\tdictWord{134, 0, 899},\n\tdictWord{133, 10, 926},\n\tdictWord{134, 0, 1126},\n\tdictWord{134, 0, 918},\n\tdictWord{4, 11, 53},\n\tdictWord{5, 11, 186},\n\tdictWord{135, 11, 752},\n\tdictWord{7, 0, 268},\n\tdictWord{136, 0, 569},\n\tdictWord{134, 0, 1224},\n\tdictWord{6, 0, 1361},\n\tdictWord{7, 10, 1232},\n\tdictWord{137, 10, 531},\n\tdictWord{8, 11, 575},\n\tdictWord{10, 11, 289},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t319,\n\t},\n\tdictWord{133, 10, 670},\n\tdictWord{132, 11, 675},\n\tdictWord{133, 0, 374},\n\tdictWord{135, 10, 1957},\n\tdictWord{133, 0, 731},\n\tdictWord{11, 0, 190},\n\tdictWord{15, 0, 49},\n\tdictWord{11, 11, 190},\n\tdictWord{143, 11, 49},\n\tdictWord{4, 0, 626},\n\tdictWord{5, 0, 506},\n\tdictWord{5, 0, 642},\n\tdictWord{6, 0, 425},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t202,\n\t},\n\tdictWord{139, 0, 141},\n\tdictWord{137, 0, 444},\n\tdictWord{7, 10, 242},\n\tdictWord{135, 10, 1942},\n\tdictWord{6, 11, 209},\n\tdictWord{8, 11, 468},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t210,\n\t},\n\tdictWord{11, 11, 36},\n\tdictWord{12, 11, 28},\n\tdictWord{12, 11, 630},\n\tdictWord{13, 11, 21},\n\tdictWord{13, 11, 349},\n\tdictWord{14, 11, 7},\n\tdictWord{\n\t\t145,\n\t\t11,\n\t\t13,\n\t},\n\tdictWord{4, 11, 342},\n\tdictWord{135, 11, 1179},\n\tdictWord{5, 10, 834},\n\tdictWord{7, 10, 1202},\n\tdictWord{8, 10, 14},\n\tdictWord{9, 10, 481},\n\tdictWord{\n\t\t137,\n\t\t10,\n\t\t880,\n\t},\n\tdictWord{4, 11, 928},\n\tdictWord{133, 11, 910},\n\tdictWord{4, 11, 318},\n\tdictWord{4, 11, 496},\n\tdictWord{7, 11, 856},\n\tdictWord{139, 11, 654},\n\tdictWord{136, 0, 835},\n\tdictWord{7, 0, 1526},\n\tdictWord{138, 10, 465},\n\tdictWord{151, 0, 17},\n\tdictWord{135, 0, 477},\n\tdictWord{4, 10, 357},\n\tdictWord{6, 10, 172},\n\tdictWord{7, 10, 143},\n\tdictWord{137, 10, 413},\n\tdictWord{6, 0, 1374},\n\tdictWord{138, 0, 994},\n\tdictWord{18, 0, 76},\n\tdictWord{132, 10, 590},\n\tdictWord{7, 0, 287},\n\tdictWord{8, 0, 355},\n\tdictWord{9, 0, 293},\n\tdictWord{137, 0, 743},\n\tdictWord{134, 0, 1389},\n\tdictWord{7, 11, 915},\n\tdictWord{8, 11, 247},\n\tdictWord{147, 11, 0},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t202,\n\t},\n\tdictWord{5, 11, 382},\n\tdictWord{6, 11, 454},\n\tdictWord{7, 11, 936},\n\tdictWord{7, 11, 1803},\n\tdictWord{8, 11, 758},\n\tdictWord{9, 11, 375},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t895,\n\t},\n\tdictWord{10, 11, 743},\n\tdictWord{10, 11, 792},\n\tdictWord{11, 11, 978},\n\tdictWord{11, 11, 1012},\n\tdictWord{142, 11, 109},\n\tdictWord{5, 0, 384},\n\tdictWord{8, 0, 455},\n\tdictWord{140, 0, 48},\n\tdictWord{132, 11, 390},\n\tdictWord{5, 10, 169},\n\tdictWord{7, 10, 333},\n\tdictWord{136, 10, 45},\n\tdictWord{5, 0, 264},\n\tdictWord{134, 0, 184},\n\tdictWord{138, 11, 791},\n\tdictWord{133, 11, 717},\n\tdictWord{132, 10, 198},\n\tdictWord{6, 11, 445},\n\tdictWord{7, 11, 332},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t909,\n\t},\n\tdictWord{136, 0, 1001},\n\tdictWord{4, 10, 24},\n\tdictWord{5, 10, 140},\n\tdictWord{5, 10, 185},\n\tdictWord{7, 10, 1500},\n\tdictWord{11, 10, 565},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t838,\n\t},\n\tdictWord{134, 11, 578},\n\tdictWord{5, 0, 633},\n\tdictWord{6, 0, 28},\n\tdictWord{135, 0, 1323},\n\tdictWord{132, 0, 851},\n\tdictWord{136, 11, 267},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t359,\n\t},\n\tdictWord{8, 0, 243},\n\tdictWord{140, 0, 175},\n\tdictWord{4, 10, 334},\n\tdictWord{133, 10, 593},\n\tdictWord{141, 11, 87},\n\tdictWord{136, 11, 766},\n\tdictWord{10, 0, 287},\n\tdictWord{12, 0, 138},\n\tdictWord{10, 11, 287},\n\tdictWord{140, 11, 138},\n\tdictWord{4, 0, 105},\n\tdictWord{132, 0, 740},\n\tdictWord{140, 10, 116},\n\tdictWord{134, 0, 857},\n\tdictWord{135, 11, 1841},\n\tdictWord{6, 0, 1402},\n\tdictWord{137, 0, 819},\n\tdictWord{132, 11, 584},\n\tdictWord{132, 10, 709},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t897,\n\t},\n\tdictWord{5, 0, 224},\n\tdictWord{13, 0, 174},\n\tdictWord{146, 0, 52},\n\tdictWord{135, 10, 1840},\n\tdictWord{4, 10, 608},\n\tdictWord{133, 10, 497},\n\tdictWord{139, 11, 60},\n\tdictWord{4, 0, 758},\n\tdictWord{135, 0, 1649},\n\tdictWord{4, 11, 226},\n\tdictWord{4, 11, 326},\n\tdictWord{135, 11, 1770},\n\tdictWord{5, 11, 426},\n\tdictWord{8, 11, 30},\n\tdictWord{9, 11, 2},\n\tdictWord{11, 11, 549},\n\tdictWord{147, 11, 122},\n\tdictWord{135, 10, 2039},\n\tdictWord{6, 10, 540},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t136,\n\t},\n\tdictWord{4, 0, 573},\n\tdictWord{8, 0, 655},\n\tdictWord{4, 10, 897},\n\tdictWord{133, 10, 786},\n\tdictWord{7, 0, 351},\n\tdictWord{139, 0, 128},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t999,\n\t},\n\tdictWord{4, 10, 299},\n\tdictWord{135, 10, 1004},\n\tdictWord{133, 0, 918},\n\tdictWord{132, 11, 345},\n\tdictWord{4, 11, 385},\n\tdictWord{7, 11, 265},\n\tdictWord{135, 11, 587},\n\tdictWord{133, 10, 456},\n\tdictWord{136, 10, 180},\n\tdictWord{6, 0, 687},\n\tdictWord{134, 0, 1537},\n\tdictWord{4, 11, 347},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t423,\n\t},\n\tdictWord{5, 11, 996},\n\tdictWord{135, 11, 1329},\n\tdictWord{132, 10, 755},\n\tdictWord{7, 11, 1259},\n\tdictWord{9, 11, 125},\n\tdictWord{11, 11, 65},\n\tdictWord{140, 11, 285},\n\tdictWord{5, 11, 136},\n\tdictWord{6, 11, 136},\n\tdictWord{136, 11, 644},\n\tdictWord{134, 0, 1525},\n\tdictWord{4, 0, 1009},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1139,\n\t},\n\tdictWord{139, 10, 338},\n\tdictWord{132, 0, 340},\n\tdictWord{135, 10, 1464},\n\tdictWord{8, 0, 847},\n\tdictWord{10, 0, 861},\n\tdictWord{10, 0, 876},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t889,\n\t},\n\tdictWord{10, 0, 922},\n\tdictWord{10, 0, 929},\n\tdictWord{10, 0, 933},\n\tdictWord{12, 0, 784},\n\tdictWord{140, 0, 791},\n\tdictWord{139, 0, 176},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t134,\n\t},\n\tdictWord{10, 11, 2},\n\tdictWord{10, 11, 27},\n\tdictWord{10, 11, 333},\n\tdictWord{11, 11, 722},\n\tdictWord{143, 11, 1},\n\tdictWord{4, 11, 433},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t719,\n\t},\n\tdictWord{5, 0, 985},\n\tdictWord{7, 0, 509},\n\tdictWord{7, 0, 529},\n\tdictWord{145, 0, 96},\n\tdictWord{132, 0, 615},\n\tdictWord{4, 10, 890},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t805,\n\t},\n\tdictWord{5, 10, 819},\n\tdictWord{5, 10, 961},\n\tdictWord{6, 10, 396},\n\tdictWord{6, 10, 1631},\n\tdictWord{6, 10, 1678},\n\tdictWord{7, 10, 1967},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t2041,\n\t},\n\tdictWord{9, 10, 630},\n\tdictWord{11, 10, 8},\n\tdictWord{11, 10, 1019},\n\tdictWord{12, 10, 176},\n\tdictWord{13, 10, 225},\n\tdictWord{14, 10, 292},\n\tdictWord{\n\t\t149,\n\t\t10,\n\t\t24,\n\t},\n\tdictWord{135, 0, 1919},\n\tdictWord{134, 0, 1131},\n\tdictWord{144, 11, 21},\n\tdictWord{144, 11, 51},\n\tdictWord{135, 10, 1815},\n\tdictWord{4, 0, 247},\n\tdictWord{7, 10, 1505},\n\tdictWord{10, 10, 190},\n\tdictWord{10, 10, 634},\n\tdictWord{11, 10, 792},\n\tdictWord{12, 10, 358},\n\tdictWord{140, 10, 447},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t0,\n\t},\n\tdictWord{6, 10, 536},\n\tdictWord{7, 10, 604},\n\tdictWord{13, 10, 445},\n\tdictWord{145, 10, 126},\n\tdictWord{4, 0, 184},\n\tdictWord{5, 0, 390},\n\tdictWord{6, 0, 337},\n\tdictWord{7, 0, 23},\n\tdictWord{7, 0, 494},\n\tdictWord{7, 0, 618},\n\tdictWord{7, 0, 1456},\n\tdictWord{8, 0, 27},\n\tdictWord{8, 0, 599},\n\tdictWord{10, 0, 153},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t710,\n\t},\n\tdictWord{6, 10, 232},\n\tdictWord{6, 10, 412},\n\tdictWord{7, 10, 1074},\n\tdictWord{8, 10, 9},\n\tdictWord{8, 10, 157},\n\tdictWord{8, 10, 786},\n\tdictWord{9, 10, 196},\n\tdictWord{9, 10, 352},\n\tdictWord{9, 10, 457},\n\tdictWord{10, 10, 337},\n\tdictWord{11, 10, 232},\n\tdictWord{11, 10, 877},\n\tdictWord{12, 10, 480},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t546,\n\t},\n\tdictWord{13, 0, 38},\n\tdictWord{135, 10, 958},\n\tdictWord{4, 10, 382},\n\tdictWord{136, 10, 579},\n\tdictWord{4, 10, 212},\n\tdictWord{135, 10, 1206},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t555,\n\t},\n\tdictWord{8, 11, 536},\n\tdictWord{138, 11, 288},\n\tdictWord{11, 11, 139},\n\tdictWord{139, 11, 171},\n\tdictWord{9, 11, 370},\n\tdictWord{138, 11, 90},\n\tdictWord{132, 0, 1015},\n\tdictWord{134, 0, 1088},\n\tdictWord{5, 10, 655},\n\tdictWord{135, 11, 977},\n\tdictWord{134, 0, 1585},\n\tdictWord{17, 10, 67},\n\tdictWord{\n\t\t147,\n\t\t10,\n\t\t74,\n\t},\n\tdictWord{10, 0, 227},\n\tdictWord{11, 0, 497},\n\tdictWord{11, 0, 709},\n\tdictWord{140, 0, 415},\n\tdictWord{6, 0, 360},\n\tdictWord{7, 0, 1664},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t478,\n\t},\n\tdictWord{7, 0, 95},\n\tdictWord{6, 10, 231},\n\tdictWord{136, 10, 423},\n\tdictWord{140, 11, 65},\n\tdictWord{4, 11, 257},\n\tdictWord{135, 11, 2031},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1768,\n\t},\n\tdictWord{133, 10, 300},\n\tdictWord{139, 11, 211},\n\tdictWord{136, 0, 699},\n\tdictWord{6, 10, 237},\n\tdictWord{7, 10, 611},\n\tdictWord{8, 10, 100},\n\tdictWord{9, 10, 416},\n\tdictWord{11, 10, 335},\n\tdictWord{12, 10, 173},\n\tdictWord{146, 10, 101},\n\tdictWord{14, 0, 26},\n\tdictWord{146, 0, 150},\n\tdictWord{6, 0, 581},\n\tdictWord{135, 0, 1119},\n\tdictWord{135, 10, 1208},\n\tdictWord{132, 0, 739},\n\tdictWord{6, 11, 83},\n\tdictWord{6, 11, 1733},\n\tdictWord{135, 11, 1389},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t869,\n\t},\n\tdictWord{4, 0, 67},\n\tdictWord{5, 0, 422},\n\tdictWord{7, 0, 1037},\n\tdictWord{7, 0, 1289},\n\tdictWord{7, 0, 1555},\n\tdictWord{9, 0, 741},\n\tdictWord{145, 0, 108},\n\tdictWord{133, 10, 199},\n\tdictWord{12, 10, 427},\n\tdictWord{146, 10, 38},\n\tdictWord{136, 0, 464},\n\tdictWord{142, 0, 42},\n\tdictWord{10, 0, 96},\n\tdictWord{8, 11, 501},\n\tdictWord{137, 11, 696},\n\tdictWord{134, 11, 592},\n\tdictWord{4, 0, 512},\n\tdictWord{4, 0, 966},\n\tdictWord{5, 0, 342},\n\tdictWord{6, 0, 1855},\n\tdictWord{8, 0, 869},\n\tdictWord{8, 0, 875},\n\tdictWord{8, 0, 901},\n\tdictWord{144, 0, 26},\n\tdictWord{8, 0, 203},\n\tdictWord{11, 0, 823},\n\tdictWord{11, 0, 846},\n\tdictWord{12, 0, 482},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t277,\n\t},\n\tdictWord{13, 0, 302},\n\tdictWord{13, 0, 464},\n\tdictWord{14, 0, 205},\n\tdictWord{142, 0, 221},\n\tdictWord{4, 0, 449},\n\tdictWord{133, 0, 718},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1718,\n\t},\n\tdictWord{9, 11, 95},\n\tdictWord{9, 11, 274},\n\tdictWord{10, 11, 279},\n\tdictWord{10, 11, 317},\n\tdictWord{10, 11, 420},\n\tdictWord{11, 11, 303},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t808,\n\t},\n\tdictWord{12, 11, 134},\n\tdictWord{12, 11, 367},\n\tdictWord{13, 11, 149},\n\tdictWord{13, 11, 347},\n\tdictWord{14, 11, 349},\n\tdictWord{14, 11, 406},\n\tdictWord{18, 11, 22},\n\tdictWord{18, 11, 89},\n\tdictWord{18, 11, 122},\n\tdictWord{147, 11, 47},\n\tdictWord{133, 11, 26},\n\tdictWord{4, 0, 355},\n\tdictWord{6, 0, 311},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t256,\n\t},\n\tdictWord{138, 0, 404},\n\tdictWord{132, 11, 550},\n\tdictWord{10, 0, 758},\n\tdictWord{6, 10, 312},\n\tdictWord{6, 10, 1715},\n\tdictWord{10, 10, 584},\n\tdictWord{11, 10, 546},\n\tdictWord{11, 10, 692},\n\tdictWord{12, 10, 259},\n\tdictWord{12, 10, 295},\n\tdictWord{13, 10, 46},\n\tdictWord{141, 10, 154},\n\tdictWord{\n\t\t136,\n\t\t11,\n\t\t822,\n\t},\n\tdictWord{5, 0, 827},\n\tdictWord{4, 11, 902},\n\tdictWord{5, 11, 809},\n\tdictWord{6, 11, 122},\n\tdictWord{135, 11, 896},\n\tdictWord{5, 0, 64},\n\tdictWord{140, 0, 581},\n\tdictWord{4, 0, 442},\n\tdictWord{6, 0, 739},\n\tdictWord{7, 0, 1047},\n\tdictWord{7, 0, 1352},\n\tdictWord{7, 0, 1643},\n\tdictWord{7, 11, 1911},\n\tdictWord{9, 11, 449},\n\tdictWord{10, 11, 192},\n\tdictWord{138, 11, 740},\n\tdictWord{135, 11, 262},\n\tdictWord{132, 10, 588},\n\tdictWord{133, 11, 620},\n\tdictWord{5, 0, 977},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t288,\n\t},\n\tdictWord{7, 0, 528},\n\tdictWord{4, 11, 34},\n\tdictWord{5, 11, 574},\n\tdictWord{7, 11, 279},\n\tdictWord{7, 11, 1624},\n\tdictWord{136, 11, 601},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1375,\n\t},\n\tdictWord{4, 10, 231},\n\tdictWord{5, 10, 61},\n\tdictWord{6, 10, 104},\n\tdictWord{7, 10, 729},\n\tdictWord{7, 10, 964},\n\tdictWord{7, 10, 1658},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t414,\n\t},\n\tdictWord{6, 10, 263},\n\tdictWord{138, 10, 757},\n\tdictWord{132, 10, 320},\n\tdictWord{4, 0, 254},\n\tdictWord{7, 0, 1309},\n\tdictWord{5, 11, 332},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1309,\n\t},\n\tdictWord{6, 11, 261},\n\tdictWord{8, 11, 182},\n\tdictWord{139, 11, 943},\n\tdictWord{132, 10, 225},\n\tdictWord{6, 0, 12},\n\tdictWord{135, 0, 1219},\n\tdictWord{4, 0, 275},\n\tdictWord{12, 0, 376},\n\tdictWord{6, 11, 1721},\n\tdictWord{141, 11, 490},\n\tdictWord{4, 11, 933},\n\tdictWord{133, 11, 880},\n\tdictWord{6, 0, 951},\n\tdictWord{6, 0, 1109},\n\tdictWord{6, 0, 1181},\n\tdictWord{7, 0, 154},\n\tdictWord{4, 10, 405},\n\tdictWord{7, 10, 817},\n\tdictWord{14, 10, 58},\n\tdictWord{17, 10, 37},\n\tdictWord{\n\t\t146,\n\t\t10,\n\t\t124,\n\t},\n\tdictWord{6, 0, 1520},\n\tdictWord{133, 10, 974},\n\tdictWord{134, 0, 1753},\n\tdictWord{6, 0, 369},\n\tdictWord{6, 0, 502},\n\tdictWord{7, 0, 1036},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t348,\n\t},\n\tdictWord{9, 0, 452},\n\tdictWord{10, 0, 26},\n\tdictWord{11, 0, 224},\n\tdictWord{11, 0, 387},\n\tdictWord{11, 0, 772},\n\tdictWord{12, 0, 95},\n\tdictWord{12, 0, 629},\n\tdictWord{13, 0, 195},\n\tdictWord{13, 0, 207},\n\tdictWord{13, 0, 241},\n\tdictWord{14, 0, 260},\n\tdictWord{14, 0, 270},\n\tdictWord{143, 0, 140},\n\tdictWord{132, 0, 269},\n\tdictWord{5, 0, 480},\n\tdictWord{7, 0, 532},\n\tdictWord{7, 0, 1197},\n\tdictWord{7, 0, 1358},\n\tdictWord{8, 0, 291},\n\tdictWord{11, 0, 349},\n\tdictWord{142, 0, 396},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t235,\n\t},\n\tdictWord{7, 10, 1239},\n\tdictWord{11, 10, 131},\n\tdictWord{140, 10, 370},\n\tdictWord{7, 10, 956},\n\tdictWord{7, 10, 1157},\n\tdictWord{7, 10, 1506},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1606,\n\t},\n\tdictWord{7, 10, 1615},\n\tdictWord{7, 10, 1619},\n\tdictWord{7, 10, 1736},\n\tdictWord{7, 10, 1775},\n\tdictWord{8, 10, 590},\n\tdictWord{9, 10, 324},\n\tdictWord{9, 10, 736},\n\tdictWord{9, 10, 774},\n\tdictWord{9, 10, 776},\n\tdictWord{9, 10, 784},\n\tdictWord{10, 10, 567},\n\tdictWord{10, 10, 708},\n\tdictWord{11, 10, 518},\n\tdictWord{11, 10, 613},\n\tdictWord{11, 10, 695},\n\tdictWord{11, 10, 716},\n\tdictWord{11, 10, 739},\n\tdictWord{11, 10, 770},\n\tdictWord{11, 10, 771},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t848,\n\t},\n\tdictWord{11, 10, 857},\n\tdictWord{11, 10, 931},\n\tdictWord{11, 10, 947},\n\tdictWord{12, 10, 326},\n\tdictWord{12, 10, 387},\n\tdictWord{12, 10, 484},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t528,\n\t},\n\tdictWord{12, 10, 552},\n\tdictWord{12, 10, 613},\n\tdictWord{13, 10, 189},\n\tdictWord{13, 10, 256},\n\tdictWord{13, 10, 340},\n\tdictWord{13, 10, 432},\n\tdictWord{13, 10, 436},\n\tdictWord{13, 10, 440},\n\tdictWord{13, 10, 454},\n\tdictWord{14, 10, 174},\n\tdictWord{14, 10, 220},\n\tdictWord{14, 10, 284},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t390,\n\t},\n\tdictWord{145, 10, 121},\n\tdictWord{8, 11, 598},\n\tdictWord{9, 11, 664},\n\tdictWord{138, 11, 441},\n\tdictWord{9, 10, 137},\n\tdictWord{138, 10, 221},\n\tdictWord{133, 11, 812},\n\tdictWord{148, 0, 15},\n\tdictWord{134, 0, 1341},\n\tdictWord{6, 0, 1017},\n\tdictWord{4, 11, 137},\n\tdictWord{7, 11, 1178},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1520,\n\t},\n\tdictWord{7, 10, 390},\n\tdictWord{138, 10, 140},\n\tdictWord{7, 11, 1260},\n\tdictWord{135, 11, 1790},\n\tdictWord{137, 11, 191},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1144,\n\t},\n\tdictWord{6, 0, 1810},\n\tdictWord{7, 0, 657},\n\tdictWord{8, 0, 886},\n\tdictWord{10, 0, 857},\n\tdictWord{14, 0, 440},\n\tdictWord{144, 0, 96},\n\tdictWord{8, 0, 533},\n\tdictWord{6, 11, 1661},\n\tdictWord{7, 11, 1975},\n\tdictWord{7, 11, 2009},\n\tdictWord{135, 11, 2011},\n\tdictWord{6, 0, 1453},\n\tdictWord{134, 10, 464},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t715,\n\t},\n\tdictWord{5, 10, 407},\n\tdictWord{11, 10, 204},\n\tdictWord{11, 10, 243},\n\tdictWord{11, 10, 489},\n\tdictWord{12, 10, 293},\n\tdictWord{19, 10, 37},\n\tdictWord{20, 10, 73},\n\tdictWord{150, 10, 38},\n\tdictWord{133, 11, 703},\n\tdictWord{4, 0, 211},\n\tdictWord{7, 0, 1483},\n\tdictWord{5, 10, 325},\n\tdictWord{8, 10, 5},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t227,\n\t},\n\tdictWord{9, 10, 105},\n\tdictWord{10, 10, 585},\n\tdictWord{140, 10, 614},\n\tdictWord{4, 0, 332},\n\tdictWord{5, 0, 335},\n\tdictWord{6, 0, 238},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t269,\n\t},\n\tdictWord{7, 0, 811},\n\tdictWord{7, 0, 1797},\n\tdictWord{8, 0, 836},\n\tdictWord{9, 0, 507},\n\tdictWord{141, 0, 242},\n\tdictWord{5, 11, 89},\n\tdictWord{7, 11, 1915},\n\tdictWord{9, 11, 185},\n\tdictWord{9, 11, 235},\n\tdictWord{9, 11, 496},\n\tdictWord{10, 11, 64},\n\tdictWord{10, 11, 270},\n\tdictWord{10, 11, 403},\n\tdictWord{10, 11, 469},\n\tdictWord{10, 11, 529},\n\tdictWord{10, 11, 590},\n\tdictWord{11, 11, 140},\n\tdictWord{11, 11, 860},\n\tdictWord{13, 11, 1},\n\tdictWord{13, 11, 422},\n\tdictWord{14, 11, 341},\n\tdictWord{14, 11, 364},\n\tdictWord{17, 11, 93},\n\tdictWord{18, 11, 113},\n\tdictWord{19, 11, 97},\n\tdictWord{147, 11, 113},\n\tdictWord{133, 11, 695},\n\tdictWord{\n\t\t16,\n\t\t0,\n\t\t19,\n\t},\n\tdictWord{5, 11, 6},\n\tdictWord{6, 11, 183},\n\tdictWord{6, 10, 621},\n\tdictWord{7, 11, 680},\n\tdictWord{7, 11, 978},\n\tdictWord{7, 11, 1013},\n\tdictWord{7, 11, 1055},\n\tdictWord{12, 11, 230},\n\tdictWord{13, 11, 172},\n\tdictWord{13, 10, 504},\n\tdictWord{146, 11, 29},\n\tdictWord{136, 0, 156},\n\tdictWord{133, 0, 1009},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t29,\n\t},\n\tdictWord{139, 11, 63},\n\tdictWord{134, 0, 820},\n\tdictWord{134, 10, 218},\n\tdictWord{7, 10, 454},\n\tdictWord{7, 10, 782},\n\tdictWord{8, 10, 768},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t686,\n\t},\n\tdictWord{5, 0, 228},\n\tdictWord{6, 0, 203},\n\tdictWord{7, 0, 156},\n\tdictWord{8, 0, 347},\n\tdictWord{9, 0, 265},\n\tdictWord{18, 0, 39},\n\tdictWord{20, 0, 54},\n\tdictWord{21, 0, 31},\n\tdictWord{22, 0, 3},\n\tdictWord{23, 0, 0},\n\tdictWord{15, 11, 8},\n\tdictWord{18, 11, 39},\n\tdictWord{20, 11, 54},\n\tdictWord{21, 11, 31},\n\tdictWord{22, 11, 3},\n\tdictWord{151, 11, 0},\n\tdictWord{7, 0, 1131},\n\tdictWord{135, 0, 1468},\n\tdictWord{144, 10, 0},\n\tdictWord{134, 0, 1276},\n\tdictWord{10, 10, 676},\n\tdictWord{\n\t\t140,\n\t\t10,\n\t\t462,\n\t},\n\tdictWord{132, 11, 311},\n\tdictWord{134, 11, 1740},\n\tdictWord{7, 11, 170},\n\tdictWord{8, 11, 90},\n\tdictWord{8, 11, 177},\n\tdictWord{8, 11, 415},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t714,\n\t},\n\tdictWord{142, 11, 281},\n\tdictWord{134, 10, 164},\n\tdictWord{6, 0, 1792},\n\tdictWord{138, 0, 849},\n\tdictWord{150, 10, 50},\n\tdictWord{5, 0, 291},\n\tdictWord{5, 0, 318},\n\tdictWord{7, 0, 765},\n\tdictWord{9, 0, 389},\n\tdictWord{12, 0, 548},\n\tdictWord{8, 11, 522},\n\tdictWord{142, 11, 328},\n\tdictWord{11, 11, 91},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t129,\n\t},\n\tdictWord{15, 11, 101},\n\tdictWord{145, 11, 125},\n\tdictWord{4, 11, 494},\n\tdictWord{6, 11, 74},\n\tdictWord{7, 11, 44},\n\tdictWord{7, 11, 407},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t551,\n\t},\n\tdictWord{12, 11, 17},\n\tdictWord{15, 11, 5},\n\tdictWord{148, 11, 11},\n\tdictWord{4, 11, 276},\n\tdictWord{133, 11, 296},\n\tdictWord{6, 10, 343},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t195,\n\t},\n\tdictWord{7, 11, 1777},\n\tdictWord{9, 10, 226},\n\tdictWord{10, 10, 197},\n\tdictWord{10, 10, 575},\n\tdictWord{11, 10, 502},\n\tdictWord{139, 10, 899},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t525,\n\t},\n\tdictWord{139, 0, 82},\n\tdictWord{14, 0, 453},\n\tdictWord{4, 11, 7},\n\tdictWord{5, 11, 90},\n\tdictWord{5, 11, 158},\n\tdictWord{6, 11, 542},\n\tdictWord{7, 11, 221},\n\tdictWord{7, 11, 1574},\n\tdictWord{9, 11, 490},\n\tdictWord{10, 11, 540},\n\tdictWord{11, 11, 443},\n\tdictWord{139, 11, 757},\n\tdictWord{135, 0, 666},\n\tdictWord{\n\t\t22,\n\t\t10,\n\t\t29,\n\t},\n\tdictWord{150, 11, 29},\n\tdictWord{4, 0, 422},\n\tdictWord{147, 10, 8},\n\tdictWord{5, 0, 355},\n\tdictWord{145, 0, 0},\n\tdictWord{6, 0, 1873},\n\tdictWord{9, 0, 918},\n\tdictWord{7, 11, 588},\n\tdictWord{9, 11, 175},\n\tdictWord{138, 11, 530},\n\tdictWord{143, 11, 31},\n\tdictWord{11, 0, 165},\n\tdictWord{7, 10, 1125},\n\tdictWord{9, 10, 143},\n\tdictWord{14, 10, 405},\n\tdictWord{150, 10, 21},\n\tdictWord{9, 0, 260},\n\tdictWord{137, 0, 905},\n\tdictWord{5, 11, 872},\n\tdictWord{6, 11, 57},\n\tdictWord{6, 11, 479},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t562,\n\t},\n\tdictWord{7, 11, 471},\n\tdictWord{7, 11, 1060},\n\tdictWord{9, 11, 447},\n\tdictWord{9, 11, 454},\n\tdictWord{141, 11, 6},\n\tdictWord{138, 11, 704},\n\tdictWord{133, 0, 865},\n\tdictWord{5, 0, 914},\n\tdictWord{134, 0, 1625},\n\tdictWord{133, 0, 234},\n\tdictWord{7, 0, 1383},\n\tdictWord{5, 11, 31},\n\tdictWord{6, 11, 614},\n\tdictWord{145, 11, 61},\n\tdictWord{7, 11, 1200},\n\tdictWord{138, 11, 460},\n\tdictWord{6, 11, 424},\n\tdictWord{135, 11, 1866},\n\tdictWord{136, 0, 306},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t959,\n\t},\n\tdictWord{12, 11, 30},\n\tdictWord{13, 11, 148},\n\tdictWord{14, 11, 87},\n\tdictWord{14, 11, 182},\n\tdictWord{16, 11, 42},\n\tdictWord{18, 11, 92},\n\tdictWord{\n\t\t148,\n\t\t11,\n\t\t70,\n\t},\n\tdictWord{6, 0, 1919},\n\tdictWord{6, 0, 1921},\n\tdictWord{9, 0, 923},\n\tdictWord{9, 0, 930},\n\tdictWord{9, 0, 941},\n\tdictWord{9, 0, 949},\n\tdictWord{9, 0, 987},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t988,\n\t},\n\tdictWord{9, 0, 992},\n\tdictWord{12, 0, 802},\n\tdictWord{12, 0, 815},\n\tdictWord{12, 0, 856},\n\tdictWord{12, 0, 885},\n\tdictWord{12, 0, 893},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t898,\n\t},\n\tdictWord{12, 0, 919},\n\tdictWord{12, 0, 920},\n\tdictWord{12, 0, 941},\n\tdictWord{12, 0, 947},\n\tdictWord{15, 0, 183},\n\tdictWord{15, 0, 185},\n\tdictWord{15, 0, 189},\n\tdictWord{15, 0, 197},\n\tdictWord{15, 0, 202},\n\tdictWord{15, 0, 233},\n\tdictWord{18, 0, 218},\n\tdictWord{18, 0, 219},\n\tdictWord{18, 0, 233},\n\tdictWord{143, 11, 156},\n\tdictWord{135, 10, 1759},\n\tdictWord{136, 10, 173},\n\tdictWord{13, 0, 163},\n\tdictWord{13, 0, 180},\n\tdictWord{18, 0, 78},\n\tdictWord{20, 0, 35},\n\tdictWord{5, 11, 13},\n\tdictWord{134, 11, 142},\n\tdictWord{134, 10, 266},\n\tdictWord{6, 11, 97},\n\tdictWord{7, 11, 116},\n\tdictWord{8, 11, 322},\n\tdictWord{8, 11, 755},\n\tdictWord{9, 11, 548},\n\tdictWord{10, 11, 714},\n\tdictWord{11, 11, 884},\n\tdictWord{141, 11, 324},\n\tdictWord{135, 0, 1312},\n\tdictWord{9, 0, 814},\n\tdictWord{137, 11, 676},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t707,\n\t},\n\tdictWord{135, 0, 1493},\n\tdictWord{6, 0, 421},\n\tdictWord{7, 0, 61},\n\tdictWord{7, 0, 1540},\n\tdictWord{10, 0, 11},\n\tdictWord{138, 0, 501},\n\tdictWord{12, 0, 733},\n\tdictWord{12, 0, 766},\n\tdictWord{7, 11, 866},\n\tdictWord{135, 11, 1163},\n\tdictWord{137, 0, 341},\n\tdictWord{142, 0, 98},\n\tdictWord{145, 11, 115},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1111,\n\t},\n\tdictWord{136, 10, 300},\n\tdictWord{136, 0, 1014},\n\tdictWord{8, 11, 1},\n\tdictWord{9, 11, 112},\n\tdictWord{138, 11, 326},\n\tdictWord{132, 11, 730},\n\tdictWord{5, 11, 488},\n\tdictWord{6, 11, 527},\n\tdictWord{7, 11, 489},\n\tdictWord{7, 11, 1636},\n\tdictWord{8, 11, 121},\n\tdictWord{8, 11, 144},\n\tdictWord{8, 11, 359},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t193,\n\t},\n\tdictWord{9, 11, 241},\n\tdictWord{9, 11, 336},\n\tdictWord{9, 11, 882},\n\tdictWord{11, 11, 266},\n\tdictWord{11, 11, 372},\n\tdictWord{11, 11, 944},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t401,\n\t},\n\tdictWord{140, 11, 641},\n\tdictWord{6, 0, 971},\n\tdictWord{134, 0, 1121},\n\tdictWord{6, 0, 102},\n\tdictWord{7, 0, 72},\n\tdictWord{15, 0, 142},\n\tdictWord{\n\t\t147,\n\t\t0,\n\t\t67,\n\t},\n\tdictWord{151, 0, 30},\n\tdictWord{135, 0, 823},\n\tdictWord{134, 0, 1045},\n\tdictWord{5, 10, 427},\n\tdictWord{5, 10, 734},\n\tdictWord{7, 10, 478},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t52,\n\t},\n\tdictWord{7, 0, 1930},\n\tdictWord{11, 10, 217},\n\tdictWord{142, 10, 165},\n\tdictWord{6, 0, 1512},\n\tdictWord{135, 0, 1870},\n\tdictWord{9, 11, 31},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t244,\n\t},\n\tdictWord{10, 11, 699},\n\tdictWord{12, 11, 149},\n\tdictWord{141, 11, 497},\n\tdictWord{133, 11, 377},\n\tdictWord{145, 11, 101},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t158,\n\t},\n\tdictWord{13, 11, 13},\n\tdictWord{13, 11, 137},\n\tdictWord{13, 11, 258},\n\tdictWord{14, 11, 111},\n\tdictWord{14, 11, 225},\n\tdictWord{14, 11, 253},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t304,\n\t},\n\tdictWord{14, 11, 339},\n\tdictWord{14, 11, 417},\n\tdictWord{146, 11, 33},\n\tdictWord{6, 0, 87},\n\tdictWord{6, 10, 1734},\n\tdictWord{7, 10, 20},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1056,\n\t},\n\tdictWord{8, 10, 732},\n\tdictWord{9, 10, 406},\n\tdictWord{9, 10, 911},\n\tdictWord{138, 10, 694},\n\tdictWord{134, 0, 1243},\n\tdictWord{137, 0, 245},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t68,\n\t},\n\tdictWord{8, 0, 48},\n\tdictWord{8, 0, 88},\n\tdictWord{8, 0, 582},\n\tdictWord{8, 0, 681},\n\tdictWord{9, 0, 373},\n\tdictWord{9, 0, 864},\n\tdictWord{11, 0, 157},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t336,\n\t},\n\tdictWord{11, 0, 843},\n\tdictWord{148, 0, 27},\n\tdictWord{8, 11, 663},\n\tdictWord{144, 11, 8},\n\tdictWord{133, 10, 613},\n\tdictWord{4, 0, 88},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t137,\n\t},\n\tdictWord{5, 0, 174},\n\tdictWord{5, 0, 777},\n\tdictWord{6, 0, 1664},\n\tdictWord{6, 0, 1725},\n\tdictWord{7, 0, 77},\n\tdictWord{7, 0, 426},\n\tdictWord{7, 0, 1317},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1355,\n\t},\n\tdictWord{8, 0, 126},\n\tdictWord{8, 0, 563},\n\tdictWord{9, 0, 523},\n\tdictWord{9, 0, 750},\n\tdictWord{10, 0, 310},\n\tdictWord{10, 0, 836},\n\tdictWord{11, 0, 42},\n\tdictWord{11, 0, 318},\n\tdictWord{11, 0, 731},\n\tdictWord{12, 0, 68},\n\tdictWord{12, 0, 92},\n\tdictWord{12, 0, 507},\n\tdictWord{12, 0, 692},\n\tdictWord{13, 0, 81},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t238,\n\t},\n\tdictWord{13, 0, 374},\n\tdictWord{14, 0, 436},\n\tdictWord{18, 0, 138},\n\tdictWord{19, 0, 78},\n\tdictWord{19, 0, 111},\n\tdictWord{20, 0, 55},\n\tdictWord{20, 0, 77},\n\tdictWord{148, 0, 92},\n\tdictWord{141, 0, 418},\n\tdictWord{4, 0, 938},\n\tdictWord{137, 0, 625},\n\tdictWord{138, 0, 351},\n\tdictWord{5, 11, 843},\n\tdictWord{7, 10, 32},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t984,\n\t},\n\tdictWord{8, 10, 85},\n\tdictWord{8, 10, 709},\n\tdictWord{9, 10, 579},\n\tdictWord{9, 10, 847},\n\tdictWord{9, 10, 856},\n\tdictWord{10, 10, 799},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t258,\n\t},\n\tdictWord{11, 10, 1007},\n\tdictWord{12, 10, 331},\n\tdictWord{12, 10, 615},\n\tdictWord{13, 10, 188},\n\tdictWord{13, 10, 435},\n\tdictWord{14, 10, 8},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t165,\n\t},\n\tdictWord{16, 10, 27},\n\tdictWord{148, 10, 40},\n\tdictWord{6, 0, 1668},\n\tdictWord{7, 0, 1499},\n\tdictWord{8, 0, 117},\n\tdictWord{9, 0, 314},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t174,\n\t},\n\tdictWord{135, 0, 707},\n\tdictWord{132, 11, 554},\n\tdictWord{133, 11, 536},\n\tdictWord{5, 0, 403},\n\tdictWord{5, 11, 207},\n\tdictWord{9, 11, 79},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t625,\n\t},\n\tdictWord{145, 11, 7},\n\tdictWord{132, 11, 424},\n\tdictWord{136, 11, 785},\n\tdictWord{4, 10, 167},\n\tdictWord{135, 10, 82},\n\tdictWord{9, 0, 7},\n\tdictWord{\n\t\t23,\n\t\t0,\n\t\t6,\n\t},\n\tdictWord{9, 11, 7},\n\tdictWord{151, 11, 6},\n\tdictWord{6, 0, 282},\n\tdictWord{5, 10, 62},\n\tdictWord{6, 10, 534},\n\tdictWord{7, 10, 74},\n\tdictWord{7, 10, 678},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t684,\n\t},\n\tdictWord{7, 10, 1043},\n\tdictWord{7, 10, 1072},\n\tdictWord{8, 10, 280},\n\tdictWord{8, 10, 541},\n\tdictWord{8, 10, 686},\n\tdictWord{9, 10, 258},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t519,\n\t},\n\tdictWord{11, 10, 252},\n\tdictWord{140, 10, 282},\n\tdictWord{138, 10, 33},\n\tdictWord{132, 10, 359},\n\tdictWord{4, 0, 44},\n\tdictWord{5, 0, 311},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t156,\n\t},\n\tdictWord{7, 0, 639},\n\tdictWord{7, 0, 762},\n\tdictWord{7, 0, 1827},\n\tdictWord{9, 0, 8},\n\tdictWord{9, 0, 462},\n\tdictWord{148, 0, 83},\n\tdictWord{7, 11, 769},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t18,\n\t},\n\tdictWord{138, 11, 358},\n\tdictWord{4, 0, 346},\n\tdictWord{7, 0, 115},\n\tdictWord{9, 0, 180},\n\tdictWord{9, 0, 456},\n\tdictWord{10, 0, 363},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t896,\n\t},\n\tdictWord{134, 11, 1777},\n\tdictWord{133, 10, 211},\n\tdictWord{7, 0, 761},\n\tdictWord{7, 0, 1051},\n\tdictWord{137, 0, 545},\n\tdictWord{6, 10, 145},\n\tdictWord{\n\t\t141,\n\t\t10,\n\t\t336,\n\t},\n\tdictWord{7, 11, 750},\n\tdictWord{9, 11, 223},\n\tdictWord{11, 11, 27},\n\tdictWord{11, 11, 466},\n\tdictWord{12, 11, 624},\n\tdictWord{14, 11, 265},\n\tdictWord{146, 11, 61},\n\tdictWord{6, 0, 752},\n\tdictWord{6, 0, 768},\n\tdictWord{6, 0, 1195},\n\tdictWord{6, 0, 1254},\n\tdictWord{6, 0, 1619},\n\tdictWord{137, 0, 835},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1936,\n\t},\n\tdictWord{8, 0, 930},\n\tdictWord{136, 0, 960},\n\tdictWord{132, 10, 263},\n\tdictWord{132, 11, 249},\n\tdictWord{12, 0, 653},\n\tdictWord{132, 10, 916},\n\tdictWord{4, 11, 603},\n\tdictWord{133, 11, 661},\n\tdictWord{8, 0, 344},\n\tdictWord{4, 11, 11},\n\tdictWord{6, 11, 128},\n\tdictWord{7, 11, 231},\n\tdictWord{7, 11, 1533},\n\tdictWord{138, 11, 725},\n\tdictWord{134, 0, 1483},\n\tdictWord{134, 0, 875},\n\tdictWord{6, 0, 185},\n\tdictWord{7, 0, 1899},\n\tdictWord{9, 0, 875},\n\tdictWord{139, 0, 673},\n\tdictWord{15, 10, 155},\n\tdictWord{144, 10, 79},\n\tdictWord{7, 0, 93},\n\tdictWord{7, 0, 210},\n\tdictWord{7, 0, 1223},\n\tdictWord{8, 0, 451},\n\tdictWord{8, 0, 460},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t353,\n\t},\n\tdictWord{11, 0, 475},\n\tdictWord{4, 10, 599},\n\tdictWord{6, 10, 1634},\n\tdictWord{7, 10, 67},\n\tdictWord{7, 10, 691},\n\tdictWord{7, 10, 979},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1697,\n\t},\n\tdictWord{8, 10, 207},\n\tdictWord{8, 10, 214},\n\tdictWord{8, 10, 231},\n\tdictWord{8, 10, 294},\n\tdictWord{8, 10, 336},\n\tdictWord{8, 10, 428},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t471,\n\t},\n\tdictWord{8, 10, 622},\n\tdictWord{8, 10, 626},\n\tdictWord{8, 10, 679},\n\tdictWord{8, 10, 759},\n\tdictWord{8, 10, 829},\n\tdictWord{9, 10, 11},\n\tdictWord{9, 10, 246},\n\tdictWord{9, 10, 484},\n\tdictWord{9, 10, 573},\n\tdictWord{9, 10, 706},\n\tdictWord{9, 10, 762},\n\tdictWord{9, 10, 798},\n\tdictWord{9, 10, 855},\n\tdictWord{9, 10, 870},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t912,\n\t},\n\tdictWord{10, 10, 303},\n\tdictWord{10, 10, 335},\n\tdictWord{10, 10, 424},\n\tdictWord{10, 10, 461},\n\tdictWord{10, 10, 543},\n\tdictWord{10, 10, 759},\n\tdictWord{10, 10, 814},\n\tdictWord{11, 10, 59},\n\tdictWord{11, 10, 235},\n\tdictWord{11, 10, 590},\n\tdictWord{11, 10, 929},\n\tdictWord{11, 10, 963},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t987,\n\t},\n\tdictWord{12, 10, 114},\n\tdictWord{12, 10, 182},\n\tdictWord{12, 10, 226},\n\tdictWord{12, 10, 332},\n\tdictWord{12, 10, 439},\n\tdictWord{12, 10, 575},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t598,\n\t},\n\tdictWord{12, 10, 675},\n\tdictWord{13, 10, 8},\n\tdictWord{13, 10, 125},\n\tdictWord{13, 10, 194},\n\tdictWord{13, 10, 287},\n\tdictWord{14, 10, 197},\n\tdictWord{14, 10, 383},\n\tdictWord{15, 10, 53},\n\tdictWord{17, 10, 63},\n\tdictWord{19, 10, 46},\n\tdictWord{19, 10, 98},\n\tdictWord{19, 10, 106},\n\tdictWord{148, 10, 85},\n\tdictWord{132, 11, 476},\n\tdictWord{4, 0, 327},\n\tdictWord{5, 0, 478},\n\tdictWord{7, 0, 1332},\n\tdictWord{136, 0, 753},\n\tdictWord{5, 0, 1020},\n\tdictWord{133, 0, 1022},\n\tdictWord{135, 11, 1807},\n\tdictWord{4, 0, 103},\n\tdictWord{133, 0, 401},\n\tdictWord{4, 0, 499},\n\tdictWord{135, 0, 1421},\n\tdictWord{10, 0, 207},\n\tdictWord{13, 0, 164},\n\tdictWord{147, 10, 126},\n\tdictWord{9, 11, 20},\n\tdictWord{10, 11, 324},\n\tdictWord{139, 11, 488},\n\tdictWord{132, 0, 96},\n\tdictWord{9, 11, 280},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t134,\n\t},\n\tdictWord{135, 0, 968},\n\tdictWord{133, 10, 187},\n\tdictWord{135, 10, 1286},\n\tdictWord{5, 11, 112},\n\tdictWord{6, 11, 103},\n\tdictWord{134, 11, 150},\n\tdictWord{8, 0, 914},\n\tdictWord{10, 0, 3},\n\tdictWord{4, 10, 215},\n\tdictWord{9, 10, 38},\n\tdictWord{11, 10, 23},\n\tdictWord{11, 10, 127},\n\tdictWord{139, 10, 796},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t399,\n\t},\n\tdictWord{6, 0, 563},\n\tdictWord{137, 0, 224},\n\tdictWord{6, 0, 704},\n\tdictWord{134, 0, 1214},\n\tdictWord{4, 11, 708},\n\tdictWord{8, 11, 15},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t50,\n\t},\n\tdictWord{9, 11, 386},\n\tdictWord{11, 11, 18},\n\tdictWord{11, 11, 529},\n\tdictWord{140, 11, 228},\n\tdictWord{4, 11, 563},\n\tdictWord{7, 11, 109},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t592,\n\t},\n\tdictWord{7, 11, 637},\n\tdictWord{7, 11, 770},\n\tdictWord{7, 11, 1701},\n\tdictWord{8, 11, 436},\n\tdictWord{8, 11, 463},\n\tdictWord{9, 11, 60},\n\tdictWord{9, 11, 335},\n\tdictWord{9, 11, 904},\n\tdictWord{10, 11, 73},\n\tdictWord{11, 11, 434},\n\tdictWord{12, 11, 585},\n\tdictWord{13, 11, 331},\n\tdictWord{18, 11, 110},\n\tdictWord{\n\t\t148,\n\t\t11,\n\t\t60,\n\t},\n\tdictWord{134, 0, 1559},\n\tdictWord{132, 11, 502},\n\tdictWord{6, 11, 347},\n\tdictWord{138, 11, 161},\n\tdictWord{4, 11, 33},\n\tdictWord{5, 11, 102},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t500,\n\t},\n\tdictWord{6, 11, 284},\n\tdictWord{7, 11, 1079},\n\tdictWord{7, 11, 1423},\n\tdictWord{7, 11, 1702},\n\tdictWord{8, 11, 470},\n\tdictWord{9, 11, 554},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t723,\n\t},\n\tdictWord{139, 11, 333},\n\tdictWord{7, 11, 246},\n\tdictWord{135, 11, 840},\n\tdictWord{6, 11, 10},\n\tdictWord{8, 11, 571},\n\tdictWord{9, 11, 739},\n\tdictWord{\n\t\t143,\n\t\t11,\n\t\t91,\n\t},\n\tdictWord{8, 0, 861},\n\tdictWord{10, 0, 905},\n\tdictWord{12, 0, 730},\n\tdictWord{12, 0, 789},\n\tdictWord{133, 11, 626},\n\tdictWord{134, 0, 946},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t746,\n\t},\n\tdictWord{12, 0, 333},\n\tdictWord{14, 0, 332},\n\tdictWord{12, 11, 333},\n\tdictWord{142, 11, 332},\n\tdictWord{5, 11, 18},\n\tdictWord{6, 11, 526},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t24,\n\t},\n\tdictWord{13, 11, 110},\n\tdictWord{19, 11, 5},\n\tdictWord{147, 11, 44},\n\tdictWord{4, 0, 910},\n\tdictWord{5, 0, 832},\n\tdictWord{135, 10, 2002},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t768,\n\t},\n\tdictWord{139, 11, 787},\n\tdictWord{4, 11, 309},\n\tdictWord{5, 11, 462},\n\tdictWord{7, 11, 970},\n\tdictWord{135, 11, 1097},\n\tdictWord{4, 10, 28},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t440,\n\t},\n\tdictWord{7, 10, 248},\n\tdictWord{11, 10, 833},\n\tdictWord{140, 10, 344},\n\tdictWord{134, 10, 1654},\n\tdictWord{6, 0, 632},\n\tdictWord{6, 0, 652},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1272,\n\t},\n\tdictWord{6, 0, 1384},\n\tdictWord{134, 0, 1560},\n\tdictWord{134, 11, 1704},\n\tdictWord{6, 0, 1393},\n\tdictWord{133, 10, 853},\n\tdictWord{6, 10, 249},\n\tdictWord{7, 10, 1234},\n\tdictWord{139, 10, 573},\n\tdictWord{5, 11, 86},\n\tdictWord{7, 11, 743},\n\tdictWord{9, 11, 85},\n\tdictWord{10, 11, 281},\n\tdictWord{10, 11, 432},\n\tdictWord{11, 11, 490},\n\tdictWord{12, 11, 251},\n\tdictWord{13, 11, 118},\n\tdictWord{14, 11, 378},\n\tdictWord{146, 11, 143},\n\tdictWord{5, 11, 524},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t744,\n\t},\n\tdictWord{134, 0, 1514},\n\tdictWord{10, 0, 201},\n\tdictWord{142, 0, 319},\n\tdictWord{7, 0, 717},\n\tdictWord{10, 0, 510},\n\tdictWord{7, 10, 392},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t20,\n\t},\n\tdictWord{8, 10, 172},\n\tdictWord{8, 10, 690},\n\tdictWord{9, 10, 383},\n\tdictWord{9, 10, 845},\n\tdictWord{11, 10, 293},\n\tdictWord{11, 10, 832},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t920,\n\t},\n\tdictWord{11, 10, 984},\n\tdictWord{141, 10, 221},\n\tdictWord{134, 0, 1381},\n\tdictWord{5, 10, 858},\n\tdictWord{133, 10, 992},\n\tdictWord{8, 0, 528},\n\tdictWord{137, 0, 348},\n\tdictWord{10, 11, 107},\n\tdictWord{140, 11, 436},\n\tdictWord{4, 0, 20},\n\tdictWord{133, 0, 616},\n\tdictWord{134, 0, 1251},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t927,\n\t},\n\tdictWord{10, 11, 123},\n\tdictWord{12, 11, 670},\n\tdictWord{13, 11, 371},\n\tdictWord{14, 11, 142},\n\tdictWord{146, 11, 94},\n\tdictWord{134, 0, 1163},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1149,\n\t},\n\tdictWord{137, 11, 156},\n\tdictWord{134, 0, 307},\n\tdictWord{133, 11, 778},\n\tdictWord{7, 0, 1091},\n\tdictWord{135, 0, 1765},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t502,\n\t},\n\tdictWord{6, 10, 268},\n\tdictWord{137, 10, 62},\n\tdictWord{8, 11, 196},\n\tdictWord{10, 11, 283},\n\tdictWord{139, 11, 406},\n\tdictWord{4, 0, 26},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t429,\n\t},\n\tdictWord{6, 0, 245},\n\tdictWord{7, 0, 704},\n\tdictWord{7, 0, 1379},\n\tdictWord{135, 0, 1474},\n\tdictWord{133, 11, 855},\n\tdictWord{132, 0, 881},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t621,\n\t},\n\tdictWord{135, 11, 1596},\n\tdictWord{7, 11, 1400},\n\tdictWord{9, 11, 446},\n\tdictWord{138, 11, 45},\n\tdictWord{6, 0, 736},\n\tdictWord{138, 10, 106},\n\tdictWord{133, 0, 542},\n\tdictWord{134, 0, 348},\n\tdictWord{133, 0, 868},\n\tdictWord{136, 0, 433},\n\tdictWord{135, 0, 1495},\n\tdictWord{138, 0, 771},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t613,\n\t},\n\tdictWord{136, 10, 223},\n\tdictWord{138, 0, 215},\n\tdictWord{141, 0, 124},\n\tdictWord{136, 11, 391},\n\tdictWord{135, 11, 172},\n\tdictWord{132, 10, 670},\n\tdictWord{140, 0, 55},\n\tdictWord{9, 10, 40},\n\tdictWord{139, 10, 136},\n\tdictWord{7, 0, 62},\n\tdictWord{147, 0, 112},\n\tdictWord{132, 0, 856},\n\tdictWord{132, 11, 568},\n\tdictWord{12, 0, 270},\n\tdictWord{139, 10, 259},\n\tdictWord{8, 0, 572},\n\tdictWord{137, 0, 698},\n\tdictWord{4, 11, 732},\n\tdictWord{9, 10, 310},\n\tdictWord{137, 10, 682},\n\tdictWord{142, 10, 296},\n\tdictWord{134, 0, 939},\n\tdictWord{136, 11, 733},\n\tdictWord{135, 11, 1435},\n\tdictWord{7, 10, 1401},\n\tdictWord{135, 10, 1476},\n\tdictWord{6, 0, 352},\n\tdictWord{4, 10, 296},\n\tdictWord{7, 10, 401},\n\tdictWord{7, 10, 1410},\n\tdictWord{7, 10, 1594},\n\tdictWord{7, 10, 1674},\n\tdictWord{8, 10, 63},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t660,\n\t},\n\tdictWord{137, 10, 74},\n\tdictWord{4, 11, 428},\n\tdictWord{133, 11, 668},\n\tdictWord{4, 10, 139},\n\tdictWord{4, 10, 388},\n\tdictWord{140, 10, 188},\n\tdictWord{7, 11, 2015},\n\tdictWord{140, 11, 665},\n\tdictWord{132, 0, 647},\n\tdictWord{146, 0, 10},\n\tdictWord{138, 0, 220},\n\tdictWord{142, 0, 464},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t109,\n\t},\n\tdictWord{134, 0, 1746},\n\tdictWord{6, 0, 515},\n\tdictWord{4, 10, 747},\n\tdictWord{6, 11, 1623},\n\tdictWord{6, 11, 1681},\n\tdictWord{7, 10, 649},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1479,\n\t},\n\tdictWord{135, 10, 1583},\n\tdictWord{133, 10, 232},\n\tdictWord{135, 0, 566},\n\tdictWord{137, 10, 887},\n\tdictWord{4, 0, 40},\n\tdictWord{10, 0, 67},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t117,\n\t},\n\tdictWord{11, 0, 768},\n\tdictWord{139, 0, 935},\n\tdictWord{132, 0, 801},\n\tdictWord{7, 0, 992},\n\tdictWord{8, 0, 301},\n\tdictWord{9, 0, 722},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t63,\n\t},\n\tdictWord{13, 0, 29},\n\tdictWord{14, 0, 161},\n\tdictWord{143, 0, 18},\n\tdictWord{139, 0, 923},\n\tdictWord{6, 11, 1748},\n\tdictWord{8, 11, 715},\n\tdictWord{9, 11, 802},\n\tdictWord{10, 11, 46},\n\tdictWord{10, 11, 819},\n\tdictWord{13, 11, 308},\n\tdictWord{14, 11, 351},\n\tdictWord{14, 11, 363},\n\tdictWord{146, 11, 67},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t745,\n\t},\n\tdictWord{7, 0, 1145},\n\tdictWord{4, 10, 14},\n\tdictWord{7, 10, 1801},\n\tdictWord{10, 10, 748},\n\tdictWord{141, 10, 458},\n\tdictWord{4, 11, 63},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t347,\n\t},\n\tdictWord{134, 11, 474},\n\tdictWord{135, 0, 568},\n\tdictWord{4, 10, 425},\n\tdictWord{7, 11, 577},\n\tdictWord{7, 11, 1432},\n\tdictWord{9, 11, 475},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t505,\n\t},\n\tdictWord{9, 11, 526},\n\tdictWord{9, 11, 609},\n\tdictWord{9, 11, 689},\n\tdictWord{9, 11, 726},\n\tdictWord{9, 11, 735},\n\tdictWord{9, 11, 738},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t556,\n\t},\n\tdictWord{10, 11, 674},\n\tdictWord{10, 11, 684},\n\tdictWord{11, 11, 89},\n\tdictWord{11, 11, 202},\n\tdictWord{11, 11, 272},\n\tdictWord{11, 11, 380},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t415,\n\t},\n\tdictWord{11, 11, 505},\n\tdictWord{11, 11, 537},\n\tdictWord{11, 11, 550},\n\tdictWord{11, 11, 562},\n\tdictWord{11, 11, 640},\n\tdictWord{11, 11, 667},\n\tdictWord{11, 11, 688},\n\tdictWord{11, 11, 847},\n\tdictWord{11, 11, 927},\n\tdictWord{11, 11, 930},\n\tdictWord{11, 11, 940},\n\tdictWord{12, 11, 144},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t325,\n\t},\n\tdictWord{12, 11, 329},\n\tdictWord{12, 11, 389},\n\tdictWord{12, 11, 403},\n\tdictWord{12, 11, 451},\n\tdictWord{12, 11, 515},\n\tdictWord{12, 11, 604},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t616,\n\t},\n\tdictWord{12, 11, 626},\n\tdictWord{13, 11, 66},\n\tdictWord{13, 11, 131},\n\tdictWord{13, 11, 167},\n\tdictWord{13, 11, 236},\n\tdictWord{13, 11, 368},\n\tdictWord{13, 11, 411},\n\tdictWord{13, 11, 434},\n\tdictWord{13, 11, 453},\n\tdictWord{13, 11, 461},\n\tdictWord{13, 11, 474},\n\tdictWord{14, 11, 59},\n\tdictWord{14, 11, 60},\n\tdictWord{14, 11, 139},\n\tdictWord{14, 11, 152},\n\tdictWord{14, 11, 276},\n\tdictWord{14, 11, 353},\n\tdictWord{14, 11, 402},\n\tdictWord{15, 11, 28},\n\tdictWord{\n\t\t15,\n\t\t11,\n\t\t81,\n\t},\n\tdictWord{15, 11, 123},\n\tdictWord{15, 11, 152},\n\tdictWord{18, 11, 136},\n\tdictWord{148, 11, 88},\n\tdictWord{137, 0, 247},\n\tdictWord{135, 11, 1622},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t544,\n\t},\n\tdictWord{11, 11, 413},\n\tdictWord{144, 11, 25},\n\tdictWord{4, 0, 645},\n\tdictWord{7, 0, 825},\n\tdictWord{6, 10, 1768},\n\tdictWord{135, 11, 89},\n\tdictWord{140, 0, 328},\n\tdictWord{5, 10, 943},\n\tdictWord{134, 10, 1779},\n\tdictWord{134, 0, 1363},\n\tdictWord{5, 10, 245},\n\tdictWord{6, 10, 576},\n\tdictWord{7, 10, 582},\n\tdictWord{136, 10, 225},\n\tdictWord{134, 0, 1280},\n\tdictWord{5, 11, 824},\n\tdictWord{133, 11, 941},\n\tdictWord{7, 11, 440},\n\tdictWord{8, 11, 230},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t106,\n\t},\n\tdictWord{5, 0, 28},\n\tdictWord{6, 0, 204},\n\tdictWord{10, 0, 320},\n\tdictWord{10, 0, 583},\n\tdictWord{13, 0, 502},\n\tdictWord{14, 0, 72},\n\tdictWord{14, 0, 274},\n\tdictWord{14, 0, 312},\n\tdictWord{14, 0, 344},\n\tdictWord{15, 0, 159},\n\tdictWord{16, 0, 62},\n\tdictWord{16, 0, 69},\n\tdictWord{17, 0, 30},\n\tdictWord{18, 0, 42},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t53,\n\t},\n\tdictWord{18, 0, 84},\n\tdictWord{18, 0, 140},\n\tdictWord{19, 0, 68},\n\tdictWord{19, 0, 85},\n\tdictWord{20, 0, 5},\n\tdictWord{20, 0, 45},\n\tdictWord{20, 0, 101},\n\tdictWord{\n\t\t22,\n\t\t0,\n\t\t7,\n\t},\n\tdictWord{150, 0, 20},\n\tdictWord{4, 0, 558},\n\tdictWord{6, 0, 390},\n\tdictWord{7, 0, 162},\n\tdictWord{7, 0, 689},\n\tdictWord{9, 0, 360},\n\tdictWord{138, 0, 653},\n\tdictWord{134, 0, 764},\n\tdictWord{6, 0, 862},\n\tdictWord{137, 0, 833},\n\tdictWord{5, 0, 856},\n\tdictWord{6, 0, 1672},\n\tdictWord{6, 0, 1757},\n\tdictWord{134, 0, 1781},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t92,\n\t},\n\tdictWord{10, 0, 736},\n\tdictWord{140, 0, 102},\n\tdictWord{6, 0, 1927},\n\tdictWord{6, 0, 1944},\n\tdictWord{8, 0, 924},\n\tdictWord{8, 0, 948},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t967,\n\t},\n\tdictWord{138, 0, 978},\n\tdictWord{134, 0, 1479},\n\tdictWord{5, 0, 590},\n\tdictWord{8, 0, 360},\n\tdictWord{9, 0, 213},\n\tdictWord{138, 0, 63},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1521,\n\t},\n\tdictWord{6, 0, 709},\n\tdictWord{134, 0, 891},\n\tdictWord{132, 10, 443},\n\tdictWord{13, 0, 477},\n\tdictWord{14, 0, 120},\n\tdictWord{148, 0, 61},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t914,\n\t},\n\tdictWord{5, 11, 800},\n\tdictWord{133, 11, 852},\n\tdictWord{10, 11, 54},\n\tdictWord{141, 11, 115},\n\tdictWord{4, 11, 918},\n\tdictWord{133, 11, 876},\n\tdictWord{139, 11, 152},\n\tdictWord{4, 11, 92},\n\tdictWord{133, 11, 274},\n\tdictWord{135, 11, 1901},\n\tdictWord{9, 11, 800},\n\tdictWord{10, 11, 693},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t482,\n\t},\n\tdictWord{11, 11, 734},\n\tdictWord{139, 11, 789},\n\tdictWord{9, 0, 483},\n\tdictWord{132, 10, 298},\n\tdictWord{6, 0, 1213},\n\tdictWord{141, 11, 498},\n\tdictWord{135, 11, 1451},\n\tdictWord{133, 11, 743},\n\tdictWord{4, 0, 1022},\n\tdictWord{10, 0, 1000},\n\tdictWord{12, 0, 957},\n\tdictWord{12, 0, 980},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t1013,\n\t},\n\tdictWord{14, 0, 481},\n\tdictWord{144, 0, 116},\n\tdictWord{8, 0, 503},\n\tdictWord{17, 0, 29},\n\tdictWord{4, 11, 49},\n\tdictWord{7, 11, 280},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1633,\n\t},\n\tdictWord{135, 0, 1712},\n\tdictWord{134, 0, 466},\n\tdictWord{136, 11, 47},\n\tdictWord{5, 10, 164},\n\tdictWord{7, 10, 121},\n\tdictWord{142, 10, 189},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t812,\n\t},\n\tdictWord{7, 10, 1261},\n\tdictWord{7, 10, 1360},\n\tdictWord{9, 10, 632},\n\tdictWord{140, 10, 352},\n\tdictWord{139, 10, 556},\n\tdictWord{132, 0, 731},\n\tdictWord{5, 11, 272},\n\tdictWord{5, 11, 908},\n\tdictWord{5, 11, 942},\n\tdictWord{7, 11, 1008},\n\tdictWord{7, 11, 1560},\n\tdictWord{8, 11, 197},\n\tdictWord{9, 11, 47},\n\tdictWord{11, 11, 538},\n\tdictWord{139, 11, 742},\n\tdictWord{4, 10, 172},\n\tdictWord{9, 10, 611},\n\tdictWord{10, 10, 436},\n\tdictWord{12, 10, 673},\n\tdictWord{\n\t\t141,\n\t\t10,\n\t\t255,\n\t},\n\tdictWord{133, 10, 844},\n\tdictWord{10, 0, 484},\n\tdictWord{11, 0, 754},\n\tdictWord{12, 0, 457},\n\tdictWord{14, 0, 171},\n\tdictWord{14, 0, 389},\n\tdictWord{\n\t\t146,\n\t\t0,\n\t\t153,\n\t},\n\tdictWord{9, 10, 263},\n\tdictWord{10, 10, 147},\n\tdictWord{138, 10, 492},\n\tdictWord{137, 11, 891},\n\tdictWord{138, 0, 241},\n\tdictWord{133, 10, 537},\n\tdictWord{6, 0, 2005},\n\tdictWord{136, 0, 964},\n\tdictWord{137, 10, 842},\n\tdictWord{151, 11, 8},\n\tdictWord{4, 11, 407},\n\tdictWord{132, 11, 560},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1884,\n\t},\n\tdictWord{6, 0, 1100},\n\tdictWord{134, 0, 1242},\n\tdictWord{135, 0, 954},\n\tdictWord{5, 10, 230},\n\tdictWord{5, 10, 392},\n\tdictWord{6, 10, 420},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t568,\n\t},\n\tdictWord{140, 10, 612},\n\tdictWord{4, 11, 475},\n\tdictWord{11, 11, 35},\n\tdictWord{11, 11, 90},\n\tdictWord{13, 11, 7},\n\tdictWord{13, 11, 71},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t177,\n\t},\n\tdictWord{142, 11, 422},\n\tdictWord{136, 11, 332},\n\tdictWord{135, 0, 1958},\n\tdictWord{6, 0, 549},\n\tdictWord{8, 0, 34},\n\tdictWord{8, 0, 283},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t165,\n\t},\n\tdictWord{138, 0, 475},\n\tdictWord{10, 0, 952},\n\tdictWord{12, 0, 966},\n\tdictWord{140, 0, 994},\n\tdictWord{5, 0, 652},\n\tdictWord{5, 0, 701},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t449,\n\t},\n\tdictWord{4, 0, 655},\n\tdictWord{7, 0, 850},\n\tdictWord{17, 0, 75},\n\tdictWord{146, 0, 137},\n\tdictWord{4, 0, 146},\n\tdictWord{7, 0, 1618},\n\tdictWord{8, 0, 670},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t41,\n\t},\n\tdictWord{7, 10, 1459},\n\tdictWord{7, 10, 1469},\n\tdictWord{7, 10, 1859},\n\tdictWord{9, 10, 549},\n\tdictWord{139, 10, 905},\n\tdictWord{133, 10, 696},\n\tdictWord{6, 0, 159},\n\tdictWord{6, 0, 364},\n\tdictWord{7, 0, 516},\n\tdictWord{137, 0, 518},\n\tdictWord{135, 0, 1439},\n\tdictWord{6, 11, 222},\n\tdictWord{7, 11, 636},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1620,\n\t},\n\tdictWord{8, 11, 409},\n\tdictWord{9, 11, 693},\n\tdictWord{139, 11, 77},\n\tdictWord{13, 0, 151},\n\tdictWord{141, 11, 45},\n\tdictWord{6, 0, 1027},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t336,\n\t},\n\tdictWord{132, 10, 771},\n\tdictWord{139, 11, 392},\n\tdictWord{10, 11, 121},\n\tdictWord{11, 11, 175},\n\tdictWord{149, 11, 16},\n\tdictWord{8, 0, 950},\n\tdictWord{138, 0, 983},\n\tdictWord{133, 10, 921},\n\tdictWord{135, 0, 993},\n\tdictWord{6, 10, 180},\n\tdictWord{7, 10, 1137},\n\tdictWord{8, 10, 751},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t805,\n\t},\n\tdictWord{7, 0, 501},\n\tdictWord{9, 0, 111},\n\tdictWord{10, 0, 141},\n\tdictWord{11, 0, 332},\n\tdictWord{13, 0, 43},\n\tdictWord{13, 0, 429},\n\tdictWord{14, 0, 130},\n\tdictWord{14, 0, 415},\n\tdictWord{145, 0, 102},\n\tdictWord{4, 10, 183},\n\tdictWord{5, 11, 882},\n\tdictWord{7, 10, 271},\n\tdictWord{11, 10, 824},\n\tdictWord{11, 10, 952},\n\tdictWord{13, 10, 278},\n\tdictWord{13, 10, 339},\n\tdictWord{13, 10, 482},\n\tdictWord{14, 10, 424},\n\tdictWord{148, 10, 99},\n\tdictWord{4, 10, 19},\n\tdictWord{5, 10, 477},\n\tdictWord{5, 10, 596},\n\tdictWord{6, 10, 505},\n\tdictWord{7, 10, 1221},\n\tdictWord{11, 10, 907},\n\tdictWord{12, 10, 209},\n\tdictWord{141, 10, 214},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1215,\n\t},\n\tdictWord{133, 0, 452},\n\tdictWord{132, 11, 426},\n\tdictWord{5, 0, 149},\n\tdictWord{136, 0, 233},\n\tdictWord{133, 0, 935},\n\tdictWord{6, 11, 58},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t654,\n\t},\n\tdictWord{7, 11, 745},\n\tdictWord{7, 11, 1969},\n\tdictWord{8, 11, 240},\n\tdictWord{8, 11, 675},\n\tdictWord{9, 11, 479},\n\tdictWord{9, 11, 731},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t330,\n\t},\n\tdictWord{10, 11, 593},\n\tdictWord{10, 11, 817},\n\tdictWord{11, 11, 32},\n\tdictWord{11, 11, 133},\n\tdictWord{11, 11, 221},\n\tdictWord{145, 11, 68},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t582,\n\t},\n\tdictWord{18, 0, 131},\n\tdictWord{7, 11, 102},\n\tdictWord{137, 11, 538},\n\tdictWord{136, 0, 801},\n\tdictWord{134, 10, 1645},\n\tdictWord{132, 0, 70},\n\tdictWord{6, 10, 92},\n\tdictWord{6, 10, 188},\n\tdictWord{7, 10, 1269},\n\tdictWord{7, 10, 1524},\n\tdictWord{7, 10, 1876},\n\tdictWord{10, 10, 228},\n\tdictWord{139, 10, 1020},\n\tdictWord{4, 10, 459},\n\tdictWord{133, 10, 966},\n\tdictWord{138, 0, 369},\n\tdictWord{16, 0, 36},\n\tdictWord{140, 10, 330},\n\tdictWord{141, 11, 366},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t721,\n\t},\n\tdictWord{10, 0, 236},\n\tdictWord{12, 0, 204},\n\tdictWord{6, 10, 18},\n\tdictWord{7, 10, 932},\n\tdictWord{8, 10, 757},\n\tdictWord{9, 10, 54},\n\tdictWord{9, 10, 65},\n\tdictWord{9, 10, 844},\n\tdictWord{10, 10, 113},\n\tdictWord{10, 10, 315},\n\tdictWord{10, 10, 798},\n\tdictWord{11, 10, 153},\n\tdictWord{12, 10, 151},\n\tdictWord{12, 10, 392},\n\tdictWord{12, 10, 666},\n\tdictWord{142, 10, 248},\n\tdictWord{7, 0, 241},\n\tdictWord{10, 0, 430},\n\tdictWord{8, 10, 548},\n\tdictWord{9, 10, 532},\n\tdictWord{10, 10, 117},\n\tdictWord{11, 10, 351},\n\tdictWord{11, 10, 375},\n\tdictWord{143, 10, 23},\n\tdictWord{134, 10, 1742},\n\tdictWord{133, 10, 965},\n\tdictWord{133, 11, 566},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t48,\n\t},\n\tdictWord{135, 11, 63},\n\tdictWord{134, 10, 182},\n\tdictWord{10, 10, 65},\n\tdictWord{10, 10, 488},\n\tdictWord{138, 10, 497},\n\tdictWord{6, 11, 114},\n\tdictWord{7, 11, 1224},\n\tdictWord{7, 11, 1556},\n\tdictWord{136, 11, 3},\n\tdictWord{134, 0, 1817},\n\tdictWord{8, 11, 576},\n\tdictWord{137, 11, 267},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1078,\n\t},\n\tdictWord{144, 0, 16},\n\tdictWord{9, 10, 588},\n\tdictWord{138, 10, 260},\n\tdictWord{138, 0, 1021},\n\tdictWord{5, 0, 406},\n\tdictWord{134, 0, 2022},\n\tdictWord{133, 11, 933},\n\tdictWord{6, 0, 69},\n\tdictWord{135, 0, 117},\n\tdictWord{7, 0, 1830},\n\tdictWord{136, 11, 427},\n\tdictWord{4, 0, 432},\n\tdictWord{135, 0, 824},\n\tdictWord{134, 10, 1786},\n\tdictWord{133, 0, 826},\n\tdictWord{139, 11, 67},\n\tdictWord{133, 11, 759},\n\tdictWord{135, 10, 308},\n\tdictWord{137, 0, 816},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t1000,\n\t},\n\tdictWord{4, 0, 297},\n\tdictWord{6, 0, 529},\n\tdictWord{7, 0, 152},\n\tdictWord{7, 0, 713},\n\tdictWord{7, 0, 1845},\n\tdictWord{8, 0, 710},\n\tdictWord{8, 0, 717},\n\tdictWord{12, 0, 639},\n\tdictWord{140, 0, 685},\n\tdictWord{7, 0, 423},\n\tdictWord{136, 10, 588},\n\tdictWord{136, 10, 287},\n\tdictWord{136, 0, 510},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1048,\n\t},\n\tdictWord{6, 0, 618},\n\tdictWord{7, 11, 56},\n\tdictWord{7, 11, 1989},\n\tdictWord{8, 11, 337},\n\tdictWord{8, 11, 738},\n\tdictWord{9, 11, 600},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t483,\n\t},\n\tdictWord{12, 11, 37},\n\tdictWord{13, 11, 447},\n\tdictWord{142, 11, 92},\n\tdictWord{4, 0, 520},\n\tdictWord{135, 0, 575},\n\tdictWord{8, 0, 990},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t977,\n\t},\n\tdictWord{135, 11, 774},\n\tdictWord{9, 11, 347},\n\tdictWord{11, 11, 24},\n\tdictWord{140, 11, 170},\n\tdictWord{136, 11, 379},\n\tdictWord{140, 10, 290},\n\tdictWord{132, 11, 328},\n\tdictWord{4, 0, 321},\n\tdictWord{134, 0, 569},\n\tdictWord{4, 11, 101},\n\tdictWord{135, 11, 1171},\n\tdictWord{7, 0, 723},\n\tdictWord{7, 0, 1135},\n\tdictWord{5, 11, 833},\n\tdictWord{136, 11, 744},\n\tdictWord{7, 10, 719},\n\tdictWord{8, 10, 809},\n\tdictWord{136, 10, 834},\n\tdictWord{8, 0, 921},\n\tdictWord{136, 10, 796},\n\tdictWord{5, 10, 210},\n\tdictWord{6, 10, 213},\n\tdictWord{7, 10, 60},\n\tdictWord{10, 10, 364},\n\tdictWord{139, 10, 135},\n\tdictWord{5, 0, 397},\n\tdictWord{6, 0, 154},\n\tdictWord{7, 0, 676},\n\tdictWord{8, 0, 443},\n\tdictWord{8, 0, 609},\n\tdictWord{9, 0, 24},\n\tdictWord{9, 0, 325},\n\tdictWord{10, 0, 35},\n\tdictWord{11, 0, 535},\n\tdictWord{11, 0, 672},\n\tdictWord{11, 0, 1018},\n\tdictWord{12, 0, 637},\n\tdictWord{16, 0, 30},\n\tdictWord{5, 10, 607},\n\tdictWord{8, 10, 326},\n\tdictWord{136, 10, 490},\n\tdictWord{4, 10, 701},\n\tdictWord{5, 10, 472},\n\tdictWord{6, 11, 9},\n\tdictWord{6, 11, 397},\n\tdictWord{7, 11, 53},\n\tdictWord{7, 11, 1742},\n\tdictWord{9, 10, 758},\n\tdictWord{10, 11, 632},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t828,\n\t},\n\tdictWord{140, 11, 146},\n\tdictWord{135, 10, 380},\n\tdictWord{135, 10, 1947},\n\tdictWord{148, 11, 109},\n\tdictWord{10, 10, 278},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t278,\n\t},\n\tdictWord{134, 0, 856},\n\tdictWord{7, 0, 139},\n\tdictWord{4, 10, 386},\n\tdictWord{8, 10, 405},\n\tdictWord{8, 10, 728},\n\tdictWord{9, 10, 497},\n\tdictWord{\n\t\t11,\n\t\t10,\n\t\t110,\n\t},\n\tdictWord{11, 10, 360},\n\tdictWord{15, 10, 37},\n\tdictWord{144, 10, 84},\n\tdictWord{141, 0, 282},\n\tdictWord{133, 0, 981},\n\tdictWord{5, 0, 288},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1452,\n\t},\n\tdictWord{7, 10, 1480},\n\tdictWord{8, 10, 634},\n\tdictWord{140, 10, 472},\n\tdictWord{7, 0, 1890},\n\tdictWord{8, 11, 367},\n\tdictWord{10, 11, 760},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t79,\n\t},\n\tdictWord{20, 11, 17},\n\tdictWord{152, 11, 0},\n\tdictWord{4, 10, 524},\n\tdictWord{136, 10, 810},\n\tdictWord{4, 0, 56},\n\tdictWord{7, 0, 1791},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t607,\n\t},\n\tdictWord{8, 0, 651},\n\tdictWord{11, 0, 465},\n\tdictWord{11, 0, 835},\n\tdictWord{12, 0, 337},\n\tdictWord{141, 0, 480},\n\tdictWord{10, 10, 238},\n\tdictWord{\n\t\t141,\n\t\t10,\n\t\t33,\n\t},\n\tdictWord{11, 11, 417},\n\tdictWord{12, 11, 223},\n\tdictWord{140, 11, 265},\n\tdictWord{9, 0, 158},\n\tdictWord{10, 0, 411},\n\tdictWord{140, 0, 261},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t532,\n\t},\n\tdictWord{133, 10, 997},\n\tdictWord{12, 11, 186},\n\tdictWord{12, 11, 292},\n\tdictWord{14, 11, 100},\n\tdictWord{146, 11, 70},\n\tdictWord{6, 0, 1403},\n\tdictWord{136, 0, 617},\n\tdictWord{134, 0, 1205},\n\tdictWord{139, 0, 563},\n\tdictWord{4, 0, 242},\n\tdictWord{134, 0, 333},\n\tdictWord{4, 11, 186},\n\tdictWord{5, 11, 157},\n\tdictWord{8, 11, 168},\n\tdictWord{138, 11, 6},\n\tdictWord{132, 0, 369},\n\tdictWord{133, 11, 875},\n\tdictWord{5, 10, 782},\n\tdictWord{5, 10, 829},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1738,\n\t},\n\tdictWord{134, 0, 622},\n\tdictWord{135, 11, 1272},\n\tdictWord{6, 0, 1407},\n\tdictWord{7, 11, 111},\n\tdictWord{136, 11, 581},\n\tdictWord{7, 10, 1823},\n\tdictWord{139, 10, 693},\n\tdictWord{7, 0, 160},\n\tdictWord{10, 0, 624},\n\tdictWord{142, 0, 279},\n\tdictWord{132, 0, 363},\n\tdictWord{10, 11, 589},\n\tdictWord{12, 11, 111},\n\tdictWord{13, 11, 260},\n\tdictWord{14, 11, 82},\n\tdictWord{18, 11, 63},\n\tdictWord{147, 11, 45},\n\tdictWord{7, 11, 1364},\n\tdictWord{7, 11, 1907},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t158,\n\t},\n\tdictWord{4, 11, 404},\n\tdictWord{4, 11, 659},\n\tdictWord{135, 11, 675},\n\tdictWord{13, 11, 211},\n\tdictWord{14, 11, 133},\n\tdictWord{14, 11, 204},\n\tdictWord{\n\t\t15,\n\t\t11,\n\t\t64,\n\t},\n\tdictWord{15, 11, 69},\n\tdictWord{15, 11, 114},\n\tdictWord{16, 11, 10},\n\tdictWord{19, 11, 23},\n\tdictWord{19, 11, 35},\n\tdictWord{19, 11, 39},\n\tdictWord{\n\t\t19,\n\t\t11,\n\t\t51,\n\t},\n\tdictWord{19, 11, 71},\n\tdictWord{19, 11, 75},\n\tdictWord{152, 11, 15},\n\tdictWord{4, 10, 78},\n\tdictWord{5, 10, 96},\n\tdictWord{5, 10, 182},\n\tdictWord{7, 10, 1724},\n\tdictWord{7, 10, 1825},\n\tdictWord{10, 10, 394},\n\tdictWord{10, 10, 471},\n\tdictWord{11, 10, 532},\n\tdictWord{14, 10, 340},\n\tdictWord{145, 10, 88},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t1964,\n\t},\n\tdictWord{133, 11, 391},\n\tdictWord{11, 11, 887},\n\tdictWord{14, 11, 365},\n\tdictWord{142, 11, 375},\n\tdictWord{5, 11, 540},\n\tdictWord{6, 11, 1697},\n\tdictWord{7, 11, 222},\n\tdictWord{136, 11, 341},\n\tdictWord{134, 11, 78},\n\tdictWord{9, 0, 601},\n\tdictWord{9, 0, 619},\n\tdictWord{10, 0, 505},\n\tdictWord{10, 0, 732},\n\tdictWord{11, 0, 355},\n\tdictWord{140, 0, 139},\n\tdictWord{134, 0, 292},\n\tdictWord{139, 0, 174},\n\tdictWord{5, 0, 177},\n\tdictWord{6, 0, 616},\n\tdictWord{7, 0, 827},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t525,\n\t},\n\tdictWord{138, 0, 656},\n\tdictWord{10, 0, 31},\n\tdictWord{6, 10, 215},\n\tdictWord{7, 10, 1028},\n\tdictWord{7, 10, 1473},\n\tdictWord{7, 10, 1721},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t424,\n\t},\n\tdictWord{138, 10, 779},\n\tdictWord{135, 10, 584},\n\tdictWord{136, 11, 293},\n\tdictWord{134, 0, 685},\n\tdictWord{135, 11, 1868},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t460,\n\t},\n\tdictWord{7, 0, 647},\n\tdictWord{6, 10, 67},\n\tdictWord{7, 10, 1630},\n\tdictWord{9, 10, 354},\n\tdictWord{9, 10, 675},\n\tdictWord{10, 10, 830},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t80,\n\t},\n\tdictWord{145, 10, 80},\n\tdictWord{4, 0, 161},\n\tdictWord{133, 0, 631},\n\tdictWord{6, 10, 141},\n\tdictWord{7, 10, 225},\n\tdictWord{9, 10, 59},\n\tdictWord{9, 10, 607},\n\tdictWord{10, 10, 312},\n\tdictWord{11, 10, 687},\n\tdictWord{12, 10, 555},\n\tdictWord{13, 10, 373},\n\tdictWord{13, 10, 494},\n\tdictWord{148, 10, 58},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t965,\n\t},\n\tdictWord{7, 11, 1460},\n\tdictWord{135, 11, 1604},\n\tdictWord{136, 10, 783},\n\tdictWord{134, 11, 388},\n\tdictWord{6, 0, 722},\n\tdictWord{6, 0, 1267},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t511,\n\t},\n\tdictWord{9, 11, 333},\n\tdictWord{9, 11, 379},\n\tdictWord{10, 11, 602},\n\tdictWord{11, 11, 441},\n\tdictWord{11, 11, 723},\n\tdictWord{11, 11, 976},\n\tdictWord{140, 11, 357},\n\tdictWord{134, 0, 1797},\n\tdictWord{135, 0, 1684},\n\tdictWord{9, 0, 469},\n\tdictWord{9, 0, 709},\n\tdictWord{12, 0, 512},\n\tdictWord{14, 0, 65},\n\tdictWord{17, 0, 12},\n\tdictWord{5, 11, 938},\n\tdictWord{136, 11, 707},\n\tdictWord{7, 0, 1230},\n\tdictWord{136, 0, 531},\n\tdictWord{10, 0, 229},\n\tdictWord{11, 0, 73},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t376,\n\t},\n\tdictWord{139, 0, 433},\n\tdictWord{12, 0, 268},\n\tdictWord{12, 0, 640},\n\tdictWord{142, 0, 119},\n\tdictWord{7, 10, 430},\n\tdictWord{139, 10, 46},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t558,\n\t},\n\tdictWord{7, 0, 651},\n\tdictWord{8, 0, 421},\n\tdictWord{9, 0, 0},\n\tdictWord{10, 0, 34},\n\tdictWord{139, 0, 1008},\n\tdictWord{6, 0, 106},\n\tdictWord{7, 0, 1786},\n\tdictWord{7, 0, 1821},\n\tdictWord{9, 0, 102},\n\tdictWord{9, 0, 763},\n\tdictWord{5, 10, 602},\n\tdictWord{7, 10, 2018},\n\tdictWord{137, 10, 418},\n\tdictWord{5, 0, 65},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t416,\n\t},\n\tdictWord{7, 0, 1720},\n\tdictWord{7, 0, 1924},\n\tdictWord{10, 0, 109},\n\tdictWord{11, 0, 14},\n\tdictWord{11, 0, 70},\n\tdictWord{11, 0, 569},\n\tdictWord{11, 0, 735},\n\tdictWord{15, 0, 153},\n\tdictWord{20, 0, 80},\n\tdictWord{136, 10, 677},\n\tdictWord{135, 11, 1625},\n\tdictWord{137, 11, 772},\n\tdictWord{136, 0, 595},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t469,\n\t},\n\tdictWord{7, 11, 1709},\n\tdictWord{138, 11, 515},\n\tdictWord{7, 0, 1832},\n\tdictWord{138, 0, 374},\n\tdictWord{9, 0, 106},\n\tdictWord{9, 0, 163},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t296,\n\t},\n\tdictWord{10, 0, 167},\n\tdictWord{10, 0, 172},\n\tdictWord{10, 0, 777},\n\tdictWord{139, 0, 16},\n\tdictWord{6, 0, 6},\n\tdictWord{7, 0, 81},\n\tdictWord{7, 0, 771},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1731,\n\t},\n\tdictWord{9, 0, 405},\n\tdictWord{138, 0, 421},\n\tdictWord{4, 11, 500},\n\tdictWord{135, 11, 938},\n\tdictWord{5, 11, 68},\n\tdictWord{134, 11, 383},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t881,\n\t},\n\tdictWord{133, 0, 885},\n\tdictWord{6, 0, 854},\n\tdictWord{6, 0, 1132},\n\tdictWord{6, 0, 1495},\n\tdictWord{6, 0, 1526},\n\tdictWord{6, 0, 1533},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1577,\n\t},\n\tdictWord{4, 11, 337},\n\tdictWord{6, 11, 353},\n\tdictWord{7, 11, 1934},\n\tdictWord{8, 11, 488},\n\tdictWord{137, 11, 429},\n\tdictWord{7, 11, 236},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1795,\n\t},\n\tdictWord{8, 11, 259},\n\tdictWord{9, 11, 135},\n\tdictWord{9, 11, 177},\n\tdictWord{10, 11, 825},\n\tdictWord{11, 11, 115},\n\tdictWord{11, 11, 370},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t405,\n\t},\n\tdictWord{11, 11, 604},\n\tdictWord{12, 11, 10},\n\tdictWord{12, 11, 667},\n\tdictWord{12, 11, 669},\n\tdictWord{13, 11, 76},\n\tdictWord{14, 11, 310},\n\tdictWord{15, 11, 76},\n\tdictWord{15, 11, 147},\n\tdictWord{148, 11, 23},\n\tdictWord{5, 0, 142},\n\tdictWord{134, 0, 546},\n\tdictWord{4, 11, 15},\n\tdictWord{5, 11, 22},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t244,\n\t},\n\tdictWord{7, 11, 40},\n\tdictWord{7, 11, 200},\n\tdictWord{7, 11, 906},\n\tdictWord{7, 11, 1199},\n\tdictWord{9, 11, 616},\n\tdictWord{10, 11, 716},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t635,\n\t},\n\tdictWord{11, 11, 801},\n\tdictWord{140, 11, 458},\n\tdictWord{5, 0, 466},\n\tdictWord{11, 0, 571},\n\tdictWord{12, 0, 198},\n\tdictWord{13, 0, 283},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t186,\n\t},\n\tdictWord{15, 0, 21},\n\tdictWord{15, 0, 103},\n\tdictWord{135, 10, 329},\n\tdictWord{4, 0, 185},\n\tdictWord{5, 0, 257},\n\tdictWord{5, 0, 839},\n\tdictWord{5, 0, 936},\n\tdictWord{9, 0, 399},\n\tdictWord{10, 0, 258},\n\tdictWord{10, 0, 395},\n\tdictWord{10, 0, 734},\n\tdictWord{11, 0, 1014},\n\tdictWord{12, 0, 23},\n\tdictWord{13, 0, 350},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t150,\n\t},\n\tdictWord{19, 0, 6},\n\tdictWord{135, 11, 1735},\n\tdictWord{12, 11, 36},\n\tdictWord{141, 11, 337},\n\tdictWord{5, 11, 598},\n\tdictWord{7, 11, 791},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t108,\n\t},\n\tdictWord{137, 11, 123},\n\tdictWord{132, 10, 469},\n\tdictWord{7, 0, 404},\n\tdictWord{7, 0, 1377},\n\tdictWord{7, 0, 1430},\n\tdictWord{7, 0, 2017},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t149,\n\t},\n\tdictWord{8, 0, 239},\n\tdictWord{8, 0, 512},\n\tdictWord{8, 0, 793},\n\tdictWord{8, 0, 818},\n\tdictWord{9, 0, 474},\n\tdictWord{9, 0, 595},\n\tdictWord{10, 0, 122},\n\tdictWord{10, 0, 565},\n\tdictWord{10, 0, 649},\n\tdictWord{10, 0, 783},\n\tdictWord{11, 0, 239},\n\tdictWord{11, 0, 295},\n\tdictWord{11, 0, 447},\n\tdictWord{11, 0, 528},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t639,\n\t},\n\tdictWord{11, 0, 800},\n\tdictWord{12, 0, 25},\n\tdictWord{12, 0, 77},\n\tdictWord{12, 0, 157},\n\tdictWord{12, 0, 256},\n\tdictWord{12, 0, 316},\n\tdictWord{12, 0, 390},\n\tdictWord{12, 0, 391},\n\tdictWord{12, 0, 395},\n\tdictWord{12, 0, 478},\n\tdictWord{12, 0, 503},\n\tdictWord{12, 0, 592},\n\tdictWord{12, 0, 680},\n\tdictWord{13, 0, 50},\n\tdictWord{13, 0, 53},\n\tdictWord{13, 0, 132},\n\tdictWord{13, 0, 198},\n\tdictWord{13, 0, 322},\n\tdictWord{13, 0, 415},\n\tdictWord{13, 0, 511},\n\tdictWord{14, 0, 71},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t395,\n\t},\n\tdictWord{15, 0, 71},\n\tdictWord{15, 0, 136},\n\tdictWord{17, 0, 123},\n\tdictWord{18, 0, 93},\n\tdictWord{147, 0, 58},\n\tdictWord{136, 0, 712},\n\tdictWord{\n\t\t134,\n\t\t10,\n\t\t1743,\n\t},\n\tdictWord{5, 10, 929},\n\tdictWord{6, 10, 340},\n\tdictWord{8, 10, 376},\n\tdictWord{136, 10, 807},\n\tdictWord{6, 0, 1848},\n\tdictWord{8, 0, 860},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t856,\n\t},\n\tdictWord{10, 0, 859},\n\tdictWord{10, 0, 925},\n\tdictWord{10, 0, 941},\n\tdictWord{140, 0, 762},\n\tdictWord{6, 0, 629},\n\tdictWord{6, 0, 906},\n\tdictWord{9, 0, 810},\n\tdictWord{140, 0, 652},\n\tdictWord{5, 10, 218},\n\tdictWord{7, 10, 1610},\n\tdictWord{138, 10, 83},\n\tdictWord{7, 10, 1512},\n\tdictWord{135, 10, 1794},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t377,\n\t},\n\tdictWord{24, 0, 13},\n\tdictWord{4, 11, 155},\n\tdictWord{7, 11, 1689},\n\tdictWord{11, 10, 0},\n\tdictWord{144, 10, 78},\n\tdictWord{4, 11, 164},\n\tdictWord{5, 11, 151},\n\tdictWord{5, 11, 730},\n\tdictWord{5, 11, 741},\n\tdictWord{7, 11, 498},\n\tdictWord{7, 11, 870},\n\tdictWord{7, 11, 1542},\n\tdictWord{12, 11, 213},\n\tdictWord{14, 11, 36},\n\tdictWord{14, 11, 391},\n\tdictWord{17, 11, 111},\n\tdictWord{18, 11, 6},\n\tdictWord{18, 11, 46},\n\tdictWord{18, 11, 151},\n\tdictWord{19, 11, 36},\n\tdictWord{20, 11, 32},\n\tdictWord{20, 11, 56},\n\tdictWord{20, 11, 69},\n\tdictWord{20, 11, 102},\n\tdictWord{21, 11, 4},\n\tdictWord{22, 11, 8},\n\tdictWord{22, 11, 10},\n\tdictWord{22, 11, 14},\n\tdictWord{\n\t\t150,\n\t\t11,\n\t\t31,\n\t},\n\tdictWord{7, 0, 1842},\n\tdictWord{133, 10, 571},\n\tdictWord{4, 10, 455},\n\tdictWord{4, 11, 624},\n\tdictWord{135, 11, 1752},\n\tdictWord{134, 0, 1501},\n\tdictWord{4, 11, 492},\n\tdictWord{5, 11, 451},\n\tdictWord{6, 10, 161},\n\tdictWord{7, 10, 372},\n\tdictWord{137, 10, 597},\n\tdictWord{132, 10, 349},\n\tdictWord{4, 0, 180},\n\tdictWord{135, 0, 1906},\n\tdictWord{135, 11, 835},\n\tdictWord{141, 11, 70},\n\tdictWord{132, 0, 491},\n\tdictWord{137, 10, 751},\n\tdictWord{6, 10, 432},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t322,\n\t},\n\tdictWord{4, 0, 171},\n\tdictWord{138, 0, 234},\n\tdictWord{6, 11, 113},\n\tdictWord{135, 11, 436},\n\tdictWord{4, 0, 586},\n\tdictWord{7, 0, 1186},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t631,\n\t},\n\tdictWord{5, 10, 468},\n\tdictWord{10, 10, 325},\n\tdictWord{11, 10, 856},\n\tdictWord{12, 10, 345},\n\tdictWord{143, 10, 104},\n\tdictWord{5, 10, 223},\n\tdictWord{10, 11, 592},\n\tdictWord{10, 11, 753},\n\tdictWord{12, 11, 317},\n\tdictWord{12, 11, 355},\n\tdictWord{12, 11, 465},\n\tdictWord{12, 11, 469},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t560,\n\t},\n\tdictWord{12, 11, 578},\n\tdictWord{141, 11, 243},\n\tdictWord{132, 10, 566},\n\tdictWord{135, 11, 520},\n\tdictWord{4, 10, 59},\n\tdictWord{135, 10, 1394},\n\tdictWord{6, 10, 436},\n\tdictWord{139, 10, 481},\n\tdictWord{9, 0, 931},\n\tdictWord{10, 0, 334},\n\tdictWord{20, 0, 71},\n\tdictWord{4, 10, 48},\n\tdictWord{5, 10, 271},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t953,\n\t},\n\tdictWord{135, 11, 1878},\n\tdictWord{11, 0, 170},\n\tdictWord{5, 10, 610},\n\tdictWord{136, 10, 457},\n\tdictWord{133, 10, 755},\n\tdictWord{6, 0, 1587},\n\tdictWord{135, 10, 1217},\n\tdictWord{4, 10, 197},\n\tdictWord{149, 11, 26},\n\tdictWord{133, 11, 585},\n\tdictWord{137, 11, 521},\n\tdictWord{133, 0, 765},\n\tdictWord{\n\t\t133,\n\t\t10,\n\t\t217,\n\t},\n\tdictWord{139, 11, 586},\n\tdictWord{133, 0, 424},\n\tdictWord{9, 11, 752},\n\tdictWord{12, 11, 610},\n\tdictWord{13, 11, 431},\n\tdictWord{16, 11, 59},\n\tdictWord{146, 11, 109},\n\tdictWord{136, 0, 714},\n\tdictWord{7, 0, 685},\n\tdictWord{132, 11, 307},\n\tdictWord{9, 0, 420},\n\tdictWord{10, 0, 269},\n\tdictWord{10, 0, 285},\n\tdictWord{10, 0, 576},\n\tdictWord{11, 0, 397},\n\tdictWord{13, 0, 175},\n\tdictWord{145, 0, 90},\n\tdictWord{132, 0, 429},\n\tdictWord{133, 11, 964},\n\tdictWord{9, 11, 463},\n\tdictWord{138, 11, 595},\n\tdictWord{7, 0, 18},\n\tdictWord{7, 0, 699},\n\tdictWord{7, 0, 1966},\n\tdictWord{8, 0, 752},\n\tdictWord{9, 0, 273},\n\tdictWord{9, 0, 412},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t703,\n\t},\n\tdictWord{10, 0, 71},\n\tdictWord{10, 0, 427},\n\tdictWord{138, 0, 508},\n\tdictWord{4, 10, 165},\n\tdictWord{7, 10, 1398},\n\tdictWord{135, 10, 1829},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t53,\n\t},\n\tdictWord{5, 0, 186},\n\tdictWord{7, 0, 752},\n\tdictWord{7, 0, 828},\n\tdictWord{142, 0, 116},\n\tdictWord{8, 0, 575},\n\tdictWord{10, 0, 289},\n\tdictWord{139, 0, 319},\n\tdictWord{132, 0, 675},\n\tdictWord{134, 0, 1424},\n\tdictWord{4, 11, 75},\n\tdictWord{5, 11, 180},\n\tdictWord{6, 11, 500},\n\tdictWord{7, 11, 58},\n\tdictWord{7, 11, 710},\n\tdictWord{138, 11, 645},\n\tdictWord{133, 11, 649},\n\tdictWord{6, 11, 276},\n\tdictWord{7, 11, 282},\n\tdictWord{7, 11, 879},\n\tdictWord{7, 11, 924},\n\tdictWord{8, 11, 459},\n\tdictWord{9, 11, 599},\n\tdictWord{9, 11, 754},\n\tdictWord{11, 11, 574},\n\tdictWord{12, 11, 128},\n\tdictWord{12, 11, 494},\n\tdictWord{13, 11, 52},\n\tdictWord{13, 11, 301},\n\tdictWord{15, 11, 30},\n\tdictWord{143, 11, 132},\n\tdictWord{6, 0, 647},\n\tdictWord{134, 0, 1095},\n\tdictWord{5, 10, 9},\n\tdictWord{7, 10, 297},\n\tdictWord{7, 10, 966},\n\tdictWord{140, 10, 306},\n\tdictWord{132, 11, 200},\n\tdictWord{134, 0, 1334},\n\tdictWord{5, 10, 146},\n\tdictWord{6, 10, 411},\n\tdictWord{138, 10, 721},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t209,\n\t},\n\tdictWord{6, 0, 1141},\n\tdictWord{6, 0, 1288},\n\tdictWord{8, 0, 468},\n\tdictWord{9, 0, 210},\n\tdictWord{11, 0, 36},\n\tdictWord{12, 0, 28},\n\tdictWord{12, 0, 630},\n\tdictWord{13, 0, 21},\n\tdictWord{13, 0, 349},\n\tdictWord{14, 0, 7},\n\tdictWord{145, 0, 13},\n\tdictWord{6, 10, 177},\n\tdictWord{135, 10, 467},\n\tdictWord{4, 0, 342},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1179,\n\t},\n\tdictWord{10, 11, 454},\n\tdictWord{140, 11, 324},\n\tdictWord{4, 0, 928},\n\tdictWord{133, 0, 910},\n\tdictWord{7, 0, 1838},\n\tdictWord{6, 11, 225},\n\tdictWord{\n\t\t137,\n\t\t11,\n\t\t211,\n\t},\n\tdictWord{16, 0, 101},\n\tdictWord{20, 0, 115},\n\tdictWord{20, 0, 118},\n\tdictWord{148, 0, 122},\n\tdictWord{4, 0, 496},\n\tdictWord{135, 0, 856},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t318,\n\t},\n\tdictWord{11, 0, 654},\n\tdictWord{7, 11, 718},\n\tdictWord{139, 11, 102},\n\tdictWord{8, 11, 58},\n\tdictWord{9, 11, 724},\n\tdictWord{11, 11, 809},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t113,\n\t},\n\tdictWord{145, 11, 72},\n\tdictWord{5, 10, 200},\n\tdictWord{6, 11, 345},\n\tdictWord{135, 11, 1247},\n\tdictWord{8, 11, 767},\n\tdictWord{8, 11, 803},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t301,\n\t},\n\tdictWord{137, 11, 903},\n\tdictWord{7, 0, 915},\n\tdictWord{8, 0, 247},\n\tdictWord{19, 0, 0},\n\tdictWord{7, 11, 1949},\n\tdictWord{136, 11, 674},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t202,\n\t},\n\tdictWord{5, 0, 382},\n\tdictWord{6, 0, 454},\n\tdictWord{7, 0, 936},\n\tdictWord{7, 0, 1803},\n\tdictWord{8, 0, 758},\n\tdictWord{9, 0, 375},\n\tdictWord{9, 0, 895},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t743,\n\t},\n\tdictWord{10, 0, 792},\n\tdictWord{11, 0, 978},\n\tdictWord{11, 0, 1012},\n\tdictWord{142, 0, 109},\n\tdictWord{7, 0, 1150},\n\tdictWord{7, 0, 1425},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1453,\n\t},\n\tdictWord{140, 0, 513},\n\tdictWord{134, 11, 259},\n\tdictWord{138, 0, 791},\n\tdictWord{11, 0, 821},\n\tdictWord{12, 0, 110},\n\tdictWord{12, 0, 153},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t41,\n\t},\n\tdictWord{150, 0, 19},\n\tdictWord{134, 10, 481},\n\tdictWord{132, 0, 796},\n\tdictWord{6, 0, 445},\n\tdictWord{9, 0, 909},\n\tdictWord{136, 11, 254},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t776,\n\t},\n\tdictWord{13, 0, 345},\n\tdictWord{142, 0, 425},\n\tdictWord{4, 10, 84},\n\tdictWord{7, 10, 1482},\n\tdictWord{10, 10, 76},\n\tdictWord{138, 10, 142},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t742,\n\t},\n\tdictWord{6, 0, 578},\n\tdictWord{133, 10, 1015},\n\tdictWord{6, 0, 1387},\n\tdictWord{4, 10, 315},\n\tdictWord{5, 10, 507},\n\tdictWord{135, 10, 1370},\n\tdictWord{4, 0, 438},\n\tdictWord{133, 0, 555},\n\tdictWord{136, 0, 766},\n\tdictWord{133, 11, 248},\n\tdictWord{134, 10, 1722},\n\tdictWord{4, 11, 116},\n\tdictWord{5, 11, 95},\n\tdictWord{5, 11, 445},\n\tdictWord{7, 11, 1688},\n\tdictWord{8, 11, 29},\n\tdictWord{9, 11, 272},\n\tdictWord{11, 11, 509},\n\tdictWord{139, 11, 915},\n\tdictWord{135, 0, 541},\n\tdictWord{133, 11, 543},\n\tdictWord{8, 10, 222},\n\tdictWord{8, 10, 476},\n\tdictWord{9, 10, 238},\n\tdictWord{11, 10, 516},\n\tdictWord{11, 10, 575},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t109,\n\t},\n\tdictWord{146, 10, 100},\n\tdictWord{6, 0, 880},\n\tdictWord{134, 0, 1191},\n\tdictWord{5, 11, 181},\n\tdictWord{136, 11, 41},\n\tdictWord{134, 0, 1506},\n\tdictWord{132, 11, 681},\n\tdictWord{7, 11, 25},\n\tdictWord{8, 11, 202},\n\tdictWord{138, 11, 536},\n\tdictWord{139, 0, 983},\n\tdictWord{137, 0, 768},\n\tdictWord{132, 0, 584},\n\tdictWord{9, 11, 423},\n\tdictWord{140, 11, 89},\n\tdictWord{8, 11, 113},\n\tdictWord{9, 11, 877},\n\tdictWord{10, 11, 554},\n\tdictWord{11, 11, 83},\n\tdictWord{12, 11, 136},\n\tdictWord{147, 11, 109},\n\tdictWord{7, 10, 706},\n\tdictWord{7, 10, 1058},\n\tdictWord{138, 10, 538},\n\tdictWord{133, 11, 976},\n\tdictWord{4, 11, 206},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t746,\n\t},\n\tdictWord{136, 11, 526},\n\tdictWord{140, 0, 737},\n\tdictWord{11, 10, 92},\n\tdictWord{11, 10, 196},\n\tdictWord{11, 10, 409},\n\tdictWord{11, 10, 450},\n\tdictWord{11, 10, 666},\n\tdictWord{11, 10, 777},\n\tdictWord{12, 10, 262},\n\tdictWord{13, 10, 385},\n\tdictWord{13, 10, 393},\n\tdictWord{15, 10, 115},\n\tdictWord{\n\t\t16,\n\t\t10,\n\t\t45,\n\t},\n\tdictWord{145, 10, 82},\n\tdictWord{4, 0, 226},\n\tdictWord{4, 0, 326},\n\tdictWord{7, 0, 1770},\n\tdictWord{4, 11, 319},\n\tdictWord{5, 11, 699},\n\tdictWord{138, 11, 673},\n\tdictWord{6, 10, 40},\n\tdictWord{135, 10, 1781},\n\tdictWord{5, 0, 426},\n\tdictWord{8, 0, 30},\n\tdictWord{9, 0, 2},\n\tdictWord{11, 0, 549},\n\tdictWord{147, 0, 122},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1161,\n\t},\n\tdictWord{134, 0, 1329},\n\tdictWord{138, 10, 97},\n\tdictWord{6, 10, 423},\n\tdictWord{7, 10, 665},\n\tdictWord{135, 10, 1210},\n\tdictWord{7, 11, 13},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t226,\n\t},\n\tdictWord{10, 11, 537},\n\tdictWord{11, 11, 570},\n\tdictWord{11, 11, 605},\n\tdictWord{11, 11, 799},\n\tdictWord{11, 11, 804},\n\tdictWord{12, 11, 85},\n\tdictWord{12, 11, 516},\n\tdictWord{12, 11, 623},\n\tdictWord{13, 11, 112},\n\tdictWord{13, 11, 361},\n\tdictWord{14, 11, 77},\n\tdictWord{14, 11, 78},\n\tdictWord{17, 11, 28},\n\tdictWord{147, 11, 110},\n\tdictWord{132, 11, 769},\n\tdictWord{132, 11, 551},\n\tdictWord{132, 11, 728},\n\tdictWord{147, 0, 117},\n\tdictWord{9, 11, 57},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t459,\n\t},\n\tdictWord{10, 11, 425},\n\tdictWord{11, 11, 119},\n\tdictWord{12, 11, 184},\n\tdictWord{12, 11, 371},\n\tdictWord{13, 11, 358},\n\tdictWord{145, 11, 51},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t188,\n\t},\n\tdictWord{5, 11, 814},\n\tdictWord{8, 11, 10},\n\tdictWord{9, 11, 421},\n\tdictWord{9, 11, 729},\n\tdictWord{10, 11, 609},\n\tdictWord{139, 11, 689},\n\tdictWord{134, 11, 624},\n\tdictWord{135, 11, 298},\n\tdictWord{135, 0, 462},\n\tdictWord{4, 0, 345},\n\tdictWord{139, 10, 624},\n\tdictWord{136, 10, 574},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t385,\n\t},\n\tdictWord{7, 0, 265},\n\tdictWord{135, 0, 587},\n\tdictWord{6, 0, 808},\n\tdictWord{132, 11, 528},\n\tdictWord{133, 0, 398},\n\tdictWord{132, 10, 354},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t347,\n\t},\n\tdictWord{5, 0, 423},\n\tdictWord{5, 0, 996},\n\tdictWord{135, 0, 1329},\n\tdictWord{135, 10, 1558},\n\tdictWord{7, 0, 1259},\n\tdictWord{9, 0, 125},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t65,\n\t},\n\tdictWord{5, 0, 136},\n\tdictWord{6, 0, 136},\n\tdictWord{136, 0, 644},\n\tdictWord{5, 11, 104},\n\tdictWord{6, 11, 173},\n\tdictWord{135, 11, 1631},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t469,\n\t},\n\tdictWord{133, 10, 830},\n\tdictWord{4, 0, 278},\n\tdictWord{5, 0, 465},\n\tdictWord{135, 0, 1367},\n\tdictWord{7, 11, 810},\n\tdictWord{8, 11, 138},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t342,\n\t},\n\tdictWord{9, 11, 84},\n\tdictWord{10, 11, 193},\n\tdictWord{11, 11, 883},\n\tdictWord{140, 11, 359},\n\tdictWord{5, 10, 496},\n\tdictWord{135, 10, 203},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t433,\n\t},\n\tdictWord{133, 0, 719},\n\tdictWord{6, 11, 95},\n\tdictWord{134, 10, 547},\n\tdictWord{5, 10, 88},\n\tdictWord{137, 10, 239},\n\tdictWord{6, 11, 406},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t409,\n\t},\n\tdictWord{10, 11, 447},\n\tdictWord{11, 11, 44},\n\tdictWord{140, 11, 100},\n\tdictWord{134, 0, 1423},\n\tdictWord{7, 10, 650},\n\tdictWord{135, 10, 1310},\n\tdictWord{134, 0, 749},\n\tdictWord{135, 11, 1243},\n\tdictWord{135, 0, 1363},\n\tdictWord{6, 0, 381},\n\tdictWord{7, 0, 645},\n\tdictWord{7, 0, 694},\n\tdictWord{8, 0, 546},\n\tdictWord{7, 10, 1076},\n\tdictWord{9, 10, 80},\n\tdictWord{11, 10, 78},\n\tdictWord{11, 10, 421},\n\tdictWord{11, 10, 534},\n\tdictWord{140, 10, 545},\n\tdictWord{\n\t\t134,\n\t\t11,\n\t\t1636,\n\t},\n\tdictWord{135, 11, 1344},\n\tdictWord{12, 0, 277},\n\tdictWord{7, 10, 274},\n\tdictWord{11, 10, 479},\n\tdictWord{139, 10, 507},\n\tdictWord{6, 0, 705},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t783,\n\t},\n\tdictWord{6, 0, 1275},\n\tdictWord{6, 0, 1481},\n\tdictWord{4, 11, 282},\n\tdictWord{7, 11, 1034},\n\tdictWord{11, 11, 398},\n\tdictWord{11, 11, 634},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t1,\n\t},\n\tdictWord{12, 11, 79},\n\tdictWord{12, 11, 544},\n\tdictWord{14, 11, 237},\n\tdictWord{17, 11, 10},\n\tdictWord{146, 11, 20},\n\tdictWord{134, 0, 453},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t555,\n\t},\n\tdictWord{8, 0, 536},\n\tdictWord{10, 0, 288},\n\tdictWord{11, 0, 1005},\n\tdictWord{4, 10, 497},\n\tdictWord{135, 10, 1584},\n\tdictWord{5, 11, 118},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t499,\n\t},\n\tdictWord{6, 11, 476},\n\tdictWord{7, 11, 600},\n\tdictWord{7, 11, 888},\n\tdictWord{135, 11, 1096},\n\tdictWord{138, 0, 987},\n\tdictWord{7, 0, 1107},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t261,\n\t},\n\tdictWord{7, 10, 1115},\n\tdictWord{7, 10, 1354},\n\tdictWord{7, 10, 1588},\n\tdictWord{7, 10, 1705},\n\tdictWord{7, 10, 1902},\n\tdictWord{9, 10, 465},\n\tdictWord{10, 10, 248},\n\tdictWord{10, 10, 349},\n\tdictWord{10, 10, 647},\n\tdictWord{11, 10, 527},\n\tdictWord{11, 10, 660},\n\tdictWord{11, 10, 669},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t529,\n\t},\n\tdictWord{141, 10, 305},\n\tdictWord{7, 11, 296},\n\tdictWord{7, 11, 596},\n\tdictWord{8, 11, 560},\n\tdictWord{8, 11, 586},\n\tdictWord{9, 11, 612},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t100,\n\t},\n\tdictWord{11, 11, 304},\n\tdictWord{12, 11, 46},\n\tdictWord{13, 11, 89},\n\tdictWord{14, 11, 112},\n\tdictWord{145, 11, 122},\n\tdictWord{9, 0, 370},\n\tdictWord{\n\t\t138,\n\t\t0,\n\t\t90,\n\t},\n\tdictWord{136, 10, 13},\n\tdictWord{132, 0, 860},\n\tdictWord{7, 10, 642},\n\tdictWord{8, 10, 250},\n\tdictWord{11, 10, 123},\n\tdictWord{11, 10, 137},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t48,\n\t},\n\tdictWord{142, 10, 95},\n\tdictWord{135, 10, 1429},\n\tdictWord{137, 11, 321},\n\tdictWord{132, 0, 257},\n\tdictWord{135, 0, 2031},\n\tdictWord{7, 0, 1768},\n\tdictWord{7, 11, 1599},\n\tdictWord{7, 11, 1723},\n\tdictWord{8, 11, 79},\n\tdictWord{8, 11, 106},\n\tdictWord{8, 11, 190},\n\tdictWord{8, 11, 302},\n\tdictWord{8, 11, 383},\n\tdictWord{9, 11, 119},\n\tdictWord{9, 11, 233},\n\tdictWord{9, 11, 298},\n\tdictWord{9, 11, 419},\n\tdictWord{9, 11, 471},\n\tdictWord{10, 11, 181},\n\tdictWord{10, 11, 406},\n\tdictWord{11, 11, 57},\n\tdictWord{11, 11, 85},\n\tdictWord{11, 11, 120},\n\tdictWord{11, 11, 177},\n\tdictWord{11, 11, 296},\n\tdictWord{11, 11, 382},\n\tdictWord{11, 11, 454},\n\tdictWord{11, 11, 758},\n\tdictWord{11, 11, 999},\n\tdictWord{12, 11, 27},\n\tdictWord{12, 11, 98},\n\tdictWord{12, 11, 131},\n\tdictWord{12, 11, 245},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t312,\n\t},\n\tdictWord{12, 11, 446},\n\tdictWord{12, 11, 454},\n\tdictWord{13, 11, 25},\n\tdictWord{13, 11, 98},\n\tdictWord{13, 11, 426},\n\tdictWord{13, 11, 508},\n\tdictWord{\n\t\t14,\n\t\t11,\n\t\t6,\n\t},\n\tdictWord{14, 11, 163},\n\tdictWord{14, 11, 272},\n\tdictWord{14, 11, 277},\n\tdictWord{14, 11, 370},\n\tdictWord{15, 11, 95},\n\tdictWord{15, 11, 138},\n\tdictWord{\n\t\t15,\n\t\t11,\n\t\t167,\n\t},\n\tdictWord{17, 11, 18},\n\tdictWord{17, 11, 38},\n\tdictWord{20, 11, 96},\n\tdictWord{149, 11, 32},\n\tdictWord{5, 11, 722},\n\tdictWord{134, 11, 1759},\n\tdictWord{145, 11, 16},\n\tdictWord{6, 0, 1071},\n\tdictWord{134, 0, 1561},\n\tdictWord{10, 10, 545},\n\tdictWord{140, 10, 301},\n\tdictWord{6, 0, 83},\n\tdictWord{6, 0, 1733},\n\tdictWord{135, 0, 1389},\n\tdictWord{4, 0, 835},\n\tdictWord{135, 0, 1818},\n\tdictWord{133, 11, 258},\n\tdictWord{4, 10, 904},\n\tdictWord{133, 10, 794},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t2006,\n\t},\n\tdictWord{5, 11, 30},\n\tdictWord{7, 11, 495},\n\tdictWord{8, 11, 134},\n\tdictWord{9, 11, 788},\n\tdictWord{140, 11, 438},\n\tdictWord{135, 11, 2004},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t696,\n\t},\n\tdictWord{5, 11, 50},\n\tdictWord{6, 11, 439},\n\tdictWord{7, 11, 780},\n\tdictWord{135, 11, 1040},\n\tdictWord{7, 11, 772},\n\tdictWord{7, 11, 1104},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1647,\n\t},\n\tdictWord{11, 11, 269},\n\tdictWord{11, 11, 539},\n\tdictWord{11, 11, 607},\n\tdictWord{11, 11, 627},\n\tdictWord{11, 11, 706},\n\tdictWord{11, 11, 975},\n\tdictWord{12, 11, 248},\n\tdictWord{12, 11, 311},\n\tdictWord{12, 11, 434},\n\tdictWord{12, 11, 600},\n\tdictWord{12, 11, 622},\n\tdictWord{13, 11, 297},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t367,\n\t},\n\tdictWord{13, 11, 485},\n\tdictWord{14, 11, 69},\n\tdictWord{14, 11, 409},\n\tdictWord{143, 11, 108},\n\tdictWord{5, 11, 1},\n\tdictWord{6, 11, 81},\n\tdictWord{\n\t\t138,\n\t\t11,\n\t\t520,\n\t},\n\tdictWord{7, 0, 1718},\n\tdictWord{9, 0, 95},\n\tdictWord{9, 0, 274},\n\tdictWord{10, 0, 279},\n\tdictWord{10, 0, 317},\n\tdictWord{10, 0, 420},\n\tdictWord{11, 0, 303},\n\tdictWord{11, 0, 808},\n\tdictWord{12, 0, 134},\n\tdictWord{12, 0, 367},\n\tdictWord{13, 0, 149},\n\tdictWord{13, 0, 347},\n\tdictWord{14, 0, 349},\n\tdictWord{14, 0, 406},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t22,\n\t},\n\tdictWord{18, 0, 89},\n\tdictWord{18, 0, 122},\n\tdictWord{147, 0, 47},\n\tdictWord{5, 11, 482},\n\tdictWord{8, 11, 98},\n\tdictWord{9, 11, 172},\n\tdictWord{10, 11, 222},\n\tdictWord{10, 11, 700},\n\tdictWord{10, 11, 822},\n\tdictWord{11, 11, 302},\n\tdictWord{11, 11, 778},\n\tdictWord{12, 11, 50},\n\tdictWord{12, 11, 127},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t396,\n\t},\n\tdictWord{13, 11, 62},\n\tdictWord{13, 11, 328},\n\tdictWord{14, 11, 122},\n\tdictWord{147, 11, 72},\n\tdictWord{7, 10, 386},\n\tdictWord{138, 10, 713},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t7,\n\t},\n\tdictWord{6, 10, 35},\n\tdictWord{7, 10, 147},\n\tdictWord{7, 10, 1069},\n\tdictWord{7, 10, 1568},\n\tdictWord{7, 10, 1575},\n\tdictWord{7, 10, 1917},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t43,\n\t},\n\tdictWord{8, 10, 208},\n\tdictWord{9, 10, 128},\n\tdictWord{9, 10, 866},\n\tdictWord{10, 10, 20},\n\tdictWord{11, 10, 981},\n\tdictWord{147, 10, 33},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t26,\n\t},\n\tdictWord{132, 0, 550},\n\tdictWord{5, 11, 2},\n\tdictWord{7, 11, 1494},\n\tdictWord{136, 11, 589},\n\tdictWord{6, 11, 512},\n\tdictWord{7, 11, 797},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t253,\n\t},\n\tdictWord{9, 11, 77},\n\tdictWord{10, 11, 1},\n\tdictWord{10, 11, 129},\n\tdictWord{10, 11, 225},\n\tdictWord{11, 11, 118},\n\tdictWord{11, 11, 226},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t251,\n\t},\n\tdictWord{11, 11, 430},\n\tdictWord{11, 11, 701},\n\tdictWord{11, 11, 974},\n\tdictWord{11, 11, 982},\n\tdictWord{12, 11, 64},\n\tdictWord{12, 11, 260},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t488,\n\t},\n\tdictWord{140, 11, 690},\n\tdictWord{7, 10, 893},\n\tdictWord{141, 10, 424},\n\tdictWord{134, 0, 901},\n\tdictWord{136, 0, 822},\n\tdictWord{4, 0, 902},\n\tdictWord{5, 0, 809},\n\tdictWord{134, 0, 122},\n\tdictWord{6, 0, 807},\n\tdictWord{134, 0, 1366},\n\tdictWord{7, 0, 262},\n\tdictWord{5, 11, 748},\n\tdictWord{134, 11, 553},\n\tdictWord{133, 0, 620},\n\tdictWord{4, 0, 34},\n\tdictWord{5, 0, 574},\n\tdictWord{7, 0, 279},\n\tdictWord{7, 0, 1624},\n\tdictWord{136, 0, 601},\n\tdictWord{9, 0, 170},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t322,\n\t},\n\tdictWord{9, 10, 552},\n\tdictWord{11, 10, 274},\n\tdictWord{13, 10, 209},\n\tdictWord{13, 10, 499},\n\tdictWord{14, 10, 85},\n\tdictWord{15, 10, 126},\n\tdictWord{\n\t\t145,\n\t\t10,\n\t\t70,\n\t},\n\tdictWord{132, 0, 537},\n\tdictWord{4, 11, 12},\n\tdictWord{7, 11, 420},\n\tdictWord{7, 11, 522},\n\tdictWord{7, 11, 809},\n\tdictWord{8, 11, 797},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t88,\n\t},\n\tdictWord{133, 0, 332},\n\tdictWord{8, 10, 83},\n\tdictWord{8, 10, 742},\n\tdictWord{8, 10, 817},\n\tdictWord{9, 10, 28},\n\tdictWord{9, 10, 29},\n\tdictWord{9, 10, 885},\n\tdictWord{10, 10, 387},\n\tdictWord{11, 10, 633},\n\tdictWord{11, 10, 740},\n\tdictWord{13, 10, 235},\n\tdictWord{13, 10, 254},\n\tdictWord{15, 10, 143},\n\tdictWord{\n\t\t143,\n\t\t10,\n\t\t146,\n\t},\n\tdictWord{6, 0, 1909},\n\tdictWord{9, 0, 964},\n\tdictWord{12, 0, 822},\n\tdictWord{12, 0, 854},\n\tdictWord{12, 0, 865},\n\tdictWord{12, 0, 910},\n\tdictWord{12, 0, 938},\n\tdictWord{15, 0, 169},\n\tdictWord{15, 0, 208},\n\tdictWord{15, 0, 211},\n\tdictWord{18, 0, 205},\n\tdictWord{18, 0, 206},\n\tdictWord{18, 0, 220},\n\tdictWord{18, 0, 223},\n\tdictWord{152, 0, 24},\n\tdictWord{140, 10, 49},\n\tdictWord{5, 11, 528},\n\tdictWord{135, 11, 1580},\n\tdictWord{6, 0, 261},\n\tdictWord{8, 0, 182},\n\tdictWord{139, 0, 943},\n\tdictWord{134, 0, 1721},\n\tdictWord{4, 0, 933},\n\tdictWord{133, 0, 880},\n\tdictWord{136, 11, 321},\n\tdictWord{5, 11, 266},\n\tdictWord{9, 11, 290},\n\tdictWord{9, 11, 364},\n\tdictWord{10, 11, 293},\n\tdictWord{11, 11, 606},\n\tdictWord{142, 11, 45},\n\tdictWord{6, 0, 1609},\n\tdictWord{4, 11, 50},\n\tdictWord{6, 11, 510},\n\tdictWord{6, 11, 594},\n\tdictWord{9, 11, 121},\n\tdictWord{10, 11, 49},\n\tdictWord{10, 11, 412},\n\tdictWord{139, 11, 834},\n\tdictWord{7, 0, 895},\n\tdictWord{136, 11, 748},\n\tdictWord{132, 11, 466},\n\tdictWord{4, 10, 110},\n\tdictWord{10, 10, 415},\n\tdictWord{10, 10, 597},\n\tdictWord{142, 10, 206},\n\tdictWord{133, 0, 812},\n\tdictWord{135, 11, 281},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1890,\n\t},\n\tdictWord{6, 0, 1902},\n\tdictWord{6, 0, 1916},\n\tdictWord{9, 0, 929},\n\tdictWord{9, 0, 942},\n\tdictWord{9, 0, 975},\n\tdictWord{9, 0, 984},\n\tdictWord{9, 0, 986},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t1011,\n\t},\n\tdictWord{9, 0, 1019},\n\tdictWord{12, 0, 804},\n\tdictWord{12, 0, 851},\n\tdictWord{12, 0, 867},\n\tdictWord{12, 0, 916},\n\tdictWord{12, 0, 923},\n\tdictWord{\n\t\t15,\n\t\t0,\n\t\t194,\n\t},\n\tdictWord{15, 0, 204},\n\tdictWord{15, 0, 210},\n\tdictWord{15, 0, 222},\n\tdictWord{15, 0, 223},\n\tdictWord{15, 0, 229},\n\tdictWord{15, 0, 250},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t179,\n\t},\n\tdictWord{18, 0, 186},\n\tdictWord{18, 0, 192},\n\tdictWord{7, 10, 205},\n\tdictWord{135, 10, 2000},\n\tdictWord{132, 11, 667},\n\tdictWord{135, 0, 778},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t137,\n\t},\n\tdictWord{7, 0, 1178},\n\tdictWord{135, 0, 1520},\n\tdictWord{134, 0, 1314},\n\tdictWord{4, 11, 242},\n\tdictWord{134, 11, 333},\n\tdictWord{6, 0, 1661},\n\tdictWord{7, 0, 1975},\n\tdictWord{7, 0, 2009},\n\tdictWord{135, 0, 2011},\n\tdictWord{134, 0, 1591},\n\tdictWord{4, 10, 283},\n\tdictWord{135, 10, 1194},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t820,\n\t},\n\tdictWord{150, 0, 51},\n\tdictWord{4, 11, 39},\n\tdictWord{5, 11, 36},\n\tdictWord{7, 11, 1843},\n\tdictWord{8, 11, 407},\n\tdictWord{11, 11, 144},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t523,\n\t},\n\tdictWord{134, 10, 1720},\n\tdictWord{4, 11, 510},\n\tdictWord{7, 11, 29},\n\tdictWord{7, 11, 66},\n\tdictWord{7, 11, 1980},\n\tdictWord{10, 11, 487},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t809,\n\t},\n\tdictWord{146, 11, 9},\n\tdictWord{5, 0, 89},\n\tdictWord{7, 0, 1915},\n\tdictWord{9, 0, 185},\n\tdictWord{9, 0, 235},\n\tdictWord{10, 0, 64},\n\tdictWord{10, 0, 270},\n\tdictWord{10, 0, 403},\n\tdictWord{10, 0, 469},\n\tdictWord{10, 0, 529},\n\tdictWord{10, 0, 590},\n\tdictWord{11, 0, 140},\n\tdictWord{11, 0, 860},\n\tdictWord{13, 0, 1},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t422,\n\t},\n\tdictWord{14, 0, 341},\n\tdictWord{14, 0, 364},\n\tdictWord{17, 0, 93},\n\tdictWord{18, 0, 113},\n\tdictWord{19, 0, 97},\n\tdictWord{147, 0, 113},\n\tdictWord{133, 0, 695},\n\tdictWord{6, 0, 987},\n\tdictWord{134, 0, 1160},\n\tdictWord{5, 0, 6},\n\tdictWord{6, 0, 183},\n\tdictWord{7, 0, 680},\n\tdictWord{7, 0, 978},\n\tdictWord{7, 0, 1013},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1055,\n\t},\n\tdictWord{12, 0, 230},\n\tdictWord{13, 0, 172},\n\tdictWord{146, 0, 29},\n\tdictWord{134, 11, 570},\n\tdictWord{132, 11, 787},\n\tdictWord{134, 11, 518},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t29,\n\t},\n\tdictWord{139, 0, 63},\n\tdictWord{132, 11, 516},\n\tdictWord{136, 11, 821},\n\tdictWord{132, 0, 311},\n\tdictWord{134, 0, 1740},\n\tdictWord{7, 0, 170},\n\tdictWord{8, 0, 90},\n\tdictWord{8, 0, 177},\n\tdictWord{8, 0, 415},\n\tdictWord{11, 0, 714},\n\tdictWord{14, 0, 281},\n\tdictWord{136, 10, 735},\n\tdictWord{134, 0, 1961},\n\tdictWord{\n\t\t135,\n\t\t11,\n\t\t1405,\n\t},\n\tdictWord{4, 11, 10},\n\tdictWord{7, 11, 917},\n\tdictWord{139, 11, 786},\n\tdictWord{5, 10, 132},\n\tdictWord{9, 10, 486},\n\tdictWord{9, 10, 715},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t458,\n\t},\n\tdictWord{11, 10, 373},\n\tdictWord{11, 10, 668},\n\tdictWord{11, 10, 795},\n\tdictWord{11, 10, 897},\n\tdictWord{12, 10, 272},\n\tdictWord{12, 10, 424},\n\tdictWord{12, 10, 539},\n\tdictWord{12, 10, 558},\n\tdictWord{14, 10, 245},\n\tdictWord{14, 10, 263},\n\tdictWord{14, 10, 264},\n\tdictWord{14, 10, 393},\n\tdictWord{\n\t\t142,\n\t\t10,\n\t\t403,\n\t},\n\tdictWord{11, 0, 91},\n\tdictWord{13, 0, 129},\n\tdictWord{15, 0, 101},\n\tdictWord{145, 0, 125},\n\tdictWord{135, 0, 1132},\n\tdictWord{4, 0, 494},\n\tdictWord{6, 0, 74},\n\tdictWord{7, 0, 44},\n\tdictWord{7, 0, 407},\n\tdictWord{12, 0, 17},\n\tdictWord{15, 0, 5},\n\tdictWord{148, 0, 11},\n\tdictWord{133, 10, 379},\n\tdictWord{5, 0, 270},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t684,\n\t},\n\tdictWord{6, 10, 89},\n\tdictWord{6, 10, 400},\n\tdictWord{7, 10, 1569},\n\tdictWord{7, 10, 1623},\n\tdictWord{7, 10, 1850},\n\tdictWord{8, 10, 218},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t422,\n\t},\n\tdictWord{9, 10, 570},\n\tdictWord{138, 10, 626},\n\tdictWord{4, 0, 276},\n\tdictWord{133, 0, 296},\n\tdictWord{6, 0, 1523},\n\tdictWord{134, 11, 27},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t387,\n\t},\n\tdictWord{7, 10, 882},\n\tdictWord{141, 10, 111},\n\tdictWord{6, 10, 224},\n\tdictWord{7, 10, 877},\n\tdictWord{137, 10, 647},\n\tdictWord{135, 10, 790},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t7,\n\t},\n\tdictWord{5, 0, 90},\n\tdictWord{5, 0, 158},\n\tdictWord{6, 0, 542},\n\tdictWord{7, 0, 221},\n\tdictWord{7, 0, 1574},\n\tdictWord{9, 0, 490},\n\tdictWord{10, 0, 540},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t443,\n\t},\n\tdictWord{139, 0, 757},\n\tdictWord{7, 0, 588},\n\tdictWord{9, 0, 175},\n\tdictWord{138, 0, 530},\n\tdictWord{135, 10, 394},\n\tdictWord{142, 11, 23},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t786,\n\t},\n\tdictWord{135, 0, 580},\n\tdictWord{7, 0, 88},\n\tdictWord{136, 0, 627},\n\tdictWord{5, 0, 872},\n\tdictWord{6, 0, 57},\n\tdictWord{7, 0, 471},\n\tdictWord{9, 0, 447},\n\tdictWord{137, 0, 454},\n\tdictWord{6, 11, 342},\n\tdictWord{6, 11, 496},\n\tdictWord{8, 11, 275},\n\tdictWord{137, 11, 206},\n\tdictWord{4, 11, 909},\n\tdictWord{133, 11, 940},\n\tdictWord{6, 0, 735},\n\tdictWord{132, 11, 891},\n\tdictWord{8, 0, 845},\n\tdictWord{8, 0, 916},\n\tdictWord{135, 10, 1409},\n\tdictWord{5, 0, 31},\n\tdictWord{134, 0, 614},\n\tdictWord{11, 0, 458},\n\tdictWord{12, 0, 15},\n\tdictWord{140, 0, 432},\n\tdictWord{8, 0, 330},\n\tdictWord{140, 0, 477},\n\tdictWord{4, 0, 530},\n\tdictWord{5, 0, 521},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1200,\n\t},\n\tdictWord{10, 0, 460},\n\tdictWord{132, 11, 687},\n\tdictWord{6, 0, 424},\n\tdictWord{135, 0, 1866},\n\tdictWord{9, 0, 569},\n\tdictWord{12, 0, 12},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t81,\n\t},\n\tdictWord{12, 0, 319},\n\tdictWord{13, 0, 69},\n\tdictWord{14, 0, 259},\n\tdictWord{16, 0, 87},\n\tdictWord{17, 0, 1},\n\tdictWord{17, 0, 21},\n\tdictWord{17, 0, 24},\n\tdictWord{\n\t\t18,\n\t\t0,\n\t\t15,\n\t},\n\tdictWord{18, 0, 56},\n\tdictWord{18, 0, 59},\n\tdictWord{18, 0, 127},\n\tdictWord{18, 0, 154},\n\tdictWord{19, 0, 19},\n\tdictWord{148, 0, 31},\n\tdictWord{7, 0, 1302},\n\tdictWord{136, 10, 38},\n\tdictWord{134, 11, 253},\n\tdictWord{5, 10, 261},\n\tdictWord{7, 10, 78},\n\tdictWord{7, 10, 199},\n\tdictWord{8, 10, 815},\n\tdictWord{9, 10, 126},\n\tdictWord{138, 10, 342},\n\tdictWord{5, 0, 595},\n\tdictWord{135, 0, 1863},\n\tdictWord{6, 11, 41},\n\tdictWord{141, 11, 160},\n\tdictWord{5, 0, 13},\n\tdictWord{134, 0, 142},\n\tdictWord{6, 0, 97},\n\tdictWord{7, 0, 116},\n\tdictWord{8, 0, 322},\n\tdictWord{8, 0, 755},\n\tdictWord{9, 0, 548},\n\tdictWord{10, 0, 714},\n\tdictWord{11, 0, 884},\n\tdictWord{13, 0, 324},\n\tdictWord{7, 11, 1304},\n\tdictWord{138, 11, 477},\n\tdictWord{132, 10, 628},\n\tdictWord{134, 11, 1718},\n\tdictWord{7, 10, 266},\n\tdictWord{136, 10, 804},\n\tdictWord{135, 10, 208},\n\tdictWord{7, 0, 1021},\n\tdictWord{6, 10, 79},\n\tdictWord{135, 10, 1519},\n\tdictWord{7, 0, 1472},\n\tdictWord{135, 0, 1554},\n\tdictWord{6, 11, 362},\n\tdictWord{146, 11, 51},\n\tdictWord{7, 0, 1071},\n\tdictWord{7, 0, 1541},\n\tdictWord{7, 0, 1767},\n\tdictWord{7, 0, 1806},\n\tdictWord{11, 0, 162},\n\tdictWord{11, 0, 242},\n\tdictWord{11, 0, 452},\n\tdictWord{12, 0, 605},\n\tdictWord{15, 0, 26},\n\tdictWord{144, 0, 44},\n\tdictWord{136, 10, 741},\n\tdictWord{133, 11, 115},\n\tdictWord{145, 0, 115},\n\tdictWord{134, 10, 376},\n\tdictWord{6, 0, 1406},\n\tdictWord{134, 0, 1543},\n\tdictWord{5, 11, 193},\n\tdictWord{12, 11, 178},\n\tdictWord{13, 11, 130},\n\tdictWord{\n\t\t145,\n\t\t11,\n\t\t84,\n\t},\n\tdictWord{135, 0, 1111},\n\tdictWord{8, 0, 1},\n\tdictWord{9, 0, 650},\n\tdictWord{10, 0, 326},\n\tdictWord{5, 11, 705},\n\tdictWord{137, 11, 606},\n\tdictWord{5, 0, 488},\n\tdictWord{6, 0, 527},\n\tdictWord{7, 0, 489},\n\tdictWord{7, 0, 1636},\n\tdictWord{8, 0, 121},\n\tdictWord{8, 0, 144},\n\tdictWord{8, 0, 359},\n\tdictWord{9, 0, 193},\n\tdictWord{9, 0, 241},\n\tdictWord{9, 0, 336},\n\tdictWord{9, 0, 882},\n\tdictWord{11, 0, 266},\n\tdictWord{11, 0, 372},\n\tdictWord{11, 0, 944},\n\tdictWord{12, 0, 401},\n\tdictWord{140, 0, 641},\n\tdictWord{135, 11, 174},\n\tdictWord{6, 0, 267},\n\tdictWord{7, 10, 244},\n\tdictWord{7, 10, 632},\n\tdictWord{7, 10, 1609},\n\tdictWord{8, 10, 178},\n\tdictWord{8, 10, 638},\n\tdictWord{141, 10, 58},\n\tdictWord{134, 0, 1983},\n\tdictWord{134, 0, 1155},\n\tdictWord{134, 0, 1575},\n\tdictWord{134, 0, 1438},\n\tdictWord{9, 0, 31},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t244,\n\t},\n\tdictWord{10, 0, 699},\n\tdictWord{12, 0, 149},\n\tdictWord{141, 0, 497},\n\tdictWord{133, 0, 377},\n\tdictWord{4, 11, 122},\n\tdictWord{5, 11, 796},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t952,\n\t},\n\tdictWord{6, 11, 1660},\n\tdictWord{6, 11, 1671},\n\tdictWord{8, 11, 567},\n\tdictWord{9, 11, 687},\n\tdictWord{9, 11, 742},\n\tdictWord{10, 11, 686},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t356,\n\t},\n\tdictWord{11, 11, 682},\n\tdictWord{140, 11, 281},\n\tdictWord{145, 0, 101},\n\tdictWord{11, 11, 0},\n\tdictWord{144, 11, 78},\n\tdictWord{5, 11, 179},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t791,\n\t},\n\tdictWord{7, 11, 1095},\n\tdictWord{135, 11, 1213},\n\tdictWord{8, 11, 372},\n\tdictWord{9, 11, 122},\n\tdictWord{138, 11, 175},\n\tdictWord{7, 10, 686},\n\tdictWord{8, 10, 33},\n\tdictWord{8, 10, 238},\n\tdictWord{10, 10, 616},\n\tdictWord{11, 10, 467},\n\tdictWord{11, 10, 881},\n\tdictWord{13, 10, 217},\n\tdictWord{13, 10, 253},\n\tdictWord{142, 10, 268},\n\tdictWord{9, 0, 476},\n\tdictWord{4, 11, 66},\n\tdictWord{7, 11, 722},\n\tdictWord{135, 11, 904},\n\tdictWord{7, 11, 352},\n\tdictWord{137, 11, 684},\n\tdictWord{135, 0, 2023},\n\tdictWord{135, 0, 1836},\n\tdictWord{132, 10, 447},\n\tdictWord{5, 0, 843},\n\tdictWord{144, 0, 35},\n\tdictWord{137, 11, 779},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t35,\n\t},\n\tdictWord{4, 10, 128},\n\tdictWord{5, 10, 415},\n\tdictWord{6, 10, 462},\n\tdictWord{7, 10, 294},\n\tdictWord{7, 10, 578},\n\tdictWord{10, 10, 710},\n\tdictWord{\n\t\t139,\n\t\t10,\n\t\t86,\n\t},\n\tdictWord{132, 0, 554},\n\tdictWord{133, 0, 536},\n\tdictWord{136, 10, 587},\n\tdictWord{5, 0, 207},\n\tdictWord{9, 0, 79},\n\tdictWord{11, 0, 625},\n\tdictWord{\n\t\t145,\n\t\t0,\n\t\t7,\n\t},\n\tdictWord{7, 0, 1371},\n\tdictWord{6, 10, 427},\n\tdictWord{138, 10, 692},\n\tdictWord{4, 0, 424},\n\tdictWord{4, 10, 195},\n\tdictWord{135, 10, 802},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t785,\n\t},\n\tdictWord{133, 11, 564},\n\tdictWord{135, 0, 336},\n\tdictWord{4, 0, 896},\n\tdictWord{6, 0, 1777},\n\tdictWord{134, 11, 556},\n\tdictWord{137, 11, 103},\n\tdictWord{134, 10, 1683},\n\tdictWord{7, 11, 544},\n\tdictWord{8, 11, 719},\n\tdictWord{138, 11, 61},\n\tdictWord{138, 10, 472},\n\tdictWord{4, 11, 5},\n\tdictWord{5, 11, 498},\n\tdictWord{136, 11, 637},\n\tdictWord{7, 0, 750},\n\tdictWord{9, 0, 223},\n\tdictWord{11, 0, 27},\n\tdictWord{11, 0, 466},\n\tdictWord{12, 0, 624},\n\tdictWord{14, 0, 265},\n\tdictWord{\n\t\t146,\n\t\t0,\n\t\t61,\n\t},\n\tdictWord{12, 0, 238},\n\tdictWord{18, 0, 155},\n\tdictWord{12, 11, 238},\n\tdictWord{146, 11, 155},\n\tdictWord{151, 10, 28},\n\tdictWord{133, 11, 927},\n\tdictWord{12, 0, 383},\n\tdictWord{5, 10, 3},\n\tdictWord{8, 10, 578},\n\tdictWord{9, 10, 118},\n\tdictWord{10, 10, 705},\n\tdictWord{141, 10, 279},\n\tdictWord{4, 11, 893},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t780,\n\t},\n\tdictWord{133, 11, 893},\n\tdictWord{4, 0, 603},\n\tdictWord{133, 0, 661},\n\tdictWord{4, 0, 11},\n\tdictWord{6, 0, 128},\n\tdictWord{7, 0, 231},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1533,\n\t},\n\tdictWord{10, 0, 725},\n\tdictWord{5, 10, 229},\n\tdictWord{5, 11, 238},\n\tdictWord{135, 11, 1350},\n\tdictWord{8, 10, 102},\n\tdictWord{10, 10, 578},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t672,\n\t},\n\tdictWord{12, 10, 496},\n\tdictWord{13, 10, 408},\n\tdictWord{14, 10, 121},\n\tdictWord{145, 10, 106},\n\tdictWord{132, 0, 476},\n\tdictWord{134, 0, 1552},\n\tdictWord{134, 11, 1729},\n\tdictWord{8, 10, 115},\n\tdictWord{8, 10, 350},\n\tdictWord{9, 10, 489},\n\tdictWord{10, 10, 128},\n\tdictWord{11, 10, 306},\n\tdictWord{\n\t\t12,\n\t\t10,\n\t\t373,\n\t},\n\tdictWord{14, 10, 30},\n\tdictWord{17, 10, 79},\n\tdictWord{19, 10, 80},\n\tdictWord{150, 10, 55},\n\tdictWord{135, 0, 1807},\n\tdictWord{4, 0, 680},\n\tdictWord{\n\t\t4,\n\t\t11,\n\t\t60,\n\t},\n\tdictWord{7, 11, 760},\n\tdictWord{7, 11, 1800},\n\tdictWord{8, 11, 314},\n\tdictWord{9, 11, 700},\n\tdictWord{139, 11, 487},\n\tdictWord{4, 10, 230},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t702,\n\t},\n\tdictWord{148, 11, 94},\n\tdictWord{132, 11, 228},\n\tdictWord{139, 0, 435},\n\tdictWord{9, 0, 20},\n\tdictWord{10, 0, 324},\n\tdictWord{10, 0, 807},\n\tdictWord{\n\t\t139,\n\t\t0,\n\t\t488,\n\t},\n\tdictWord{6, 10, 1728},\n\tdictWord{136, 11, 419},\n\tdictWord{4, 10, 484},\n\tdictWord{18, 10, 26},\n\tdictWord{19, 10, 42},\n\tdictWord{20, 10, 43},\n\tdictWord{\n\t\t21,\n\t\t10,\n\t\t0,\n\t},\n\tdictWord{23, 10, 27},\n\tdictWord{152, 10, 14},\n\tdictWord{135, 0, 1431},\n\tdictWord{133, 11, 828},\n\tdictWord{5, 0, 112},\n\tdictWord{6, 0, 103},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t150,\n\t},\n\tdictWord{7, 0, 1303},\n\tdictWord{9, 0, 292},\n\tdictWord{10, 0, 481},\n\tdictWord{20, 0, 13},\n\tdictWord{7, 11, 176},\n\tdictWord{7, 11, 178},\n\tdictWord{7, 11, 1110},\n\tdictWord{10, 11, 481},\n\tdictWord{148, 11, 13},\n\tdictWord{138, 0, 356},\n\tdictWord{4, 11, 51},\n\tdictWord{5, 11, 39},\n\tdictWord{6, 11, 4},\n\tdictWord{7, 11, 591},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t849,\n\t},\n\tdictWord{7, 11, 951},\n\tdictWord{7, 11, 1129},\n\tdictWord{7, 11, 1613},\n\tdictWord{7, 11, 1760},\n\tdictWord{7, 11, 1988},\n\tdictWord{9, 11, 434},\n\tdictWord{10, 11, 754},\n\tdictWord{11, 11, 25},\n\tdictWord{11, 11, 37},\n\tdictWord{139, 11, 414},\n\tdictWord{6, 0, 1963},\n\tdictWord{134, 0, 2000},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t633,\n\t},\n\tdictWord{6, 0, 1244},\n\tdictWord{133, 11, 902},\n\tdictWord{135, 11, 928},\n\tdictWord{140, 0, 18},\n\tdictWord{138, 0, 204},\n\tdictWord{135, 11, 1173},\n\tdictWord{134, 0, 867},\n\tdictWord{4, 0, 708},\n\tdictWord{8, 0, 15},\n\tdictWord{9, 0, 50},\n\tdictWord{9, 0, 386},\n\tdictWord{11, 0, 18},\n\tdictWord{11, 0, 529},\n\tdictWord{140, 0, 228},\n\tdictWord{134, 11, 270},\n\tdictWord{4, 0, 563},\n\tdictWord{7, 0, 109},\n\tdictWord{7, 0, 592},\n\tdictWord{7, 0, 637},\n\tdictWord{7, 0, 770},\n\tdictWord{8, 0, 463},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t60,\n\t},\n\tdictWord{9, 0, 335},\n\tdictWord{9, 0, 904},\n\tdictWord{10, 0, 73},\n\tdictWord{11, 0, 434},\n\tdictWord{12, 0, 585},\n\tdictWord{13, 0, 331},\n\tdictWord{18, 0, 110},\n\tdictWord{148, 0, 60},\n\tdictWord{132, 0, 502},\n\tdictWord{14, 11, 359},\n\tdictWord{19, 11, 52},\n\tdictWord{148, 11, 47},\n\tdictWord{6, 11, 377},\n\tdictWord{7, 11, 1025},\n\tdictWord{9, 11, 613},\n\tdictWord{145, 11, 104},\n\tdictWord{6, 0, 347},\n\tdictWord{10, 0, 161},\n\tdictWord{5, 10, 70},\n\tdictWord{5, 10, 622},\n\tdictWord{6, 10, 334},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1032,\n\t},\n\tdictWord{9, 10, 171},\n\tdictWord{11, 10, 26},\n\tdictWord{11, 10, 213},\n\tdictWord{11, 10, 637},\n\tdictWord{11, 10, 707},\n\tdictWord{12, 10, 202},\n\tdictWord{12, 10, 380},\n\tdictWord{13, 10, 226},\n\tdictWord{13, 10, 355},\n\tdictWord{14, 10, 222},\n\tdictWord{145, 10, 42},\n\tdictWord{132, 11, 416},\n\tdictWord{4, 0, 33},\n\tdictWord{5, 0, 102},\n\tdictWord{6, 0, 284},\n\tdictWord{7, 0, 1079},\n\tdictWord{7, 0, 1423},\n\tdictWord{7, 0, 1702},\n\tdictWord{8, 0, 470},\n\tdictWord{9, 0, 554},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t723,\n\t},\n\tdictWord{11, 0, 333},\n\tdictWord{142, 11, 372},\n\tdictWord{5, 11, 152},\n\tdictWord{5, 11, 197},\n\tdictWord{7, 11, 340},\n\tdictWord{7, 11, 867},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t548,\n\t},\n\tdictWord{10, 11, 581},\n\tdictWord{11, 11, 6},\n\tdictWord{12, 11, 3},\n\tdictWord{12, 11, 19},\n\tdictWord{14, 11, 110},\n\tdictWord{142, 11, 289},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t246,\n\t},\n\tdictWord{135, 0, 840},\n\tdictWord{6, 0, 10},\n\tdictWord{8, 0, 571},\n\tdictWord{9, 0, 739},\n\tdictWord{143, 0, 91},\n\tdictWord{6, 0, 465},\n\tdictWord{7, 0, 1465},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t23,\n\t},\n\tdictWord{4, 10, 141},\n\tdictWord{5, 10, 313},\n\tdictWord{5, 10, 1014},\n\tdictWord{6, 10, 50},\n\tdictWord{7, 10, 142},\n\tdictWord{7, 10, 559},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t640,\n\t},\n\tdictWord{9, 10, 460},\n\tdictWord{9, 10, 783},\n\tdictWord{11, 10, 741},\n\tdictWord{12, 10, 183},\n\tdictWord{141, 10, 488},\n\tdictWord{133, 0, 626},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t614,\n\t},\n\tdictWord{138, 0, 237},\n\tdictWord{7, 11, 34},\n\tdictWord{7, 11, 190},\n\tdictWord{8, 11, 28},\n\tdictWord{8, 11, 141},\n\tdictWord{8, 11, 444},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t811,\n\t},\n\tdictWord{9, 11, 468},\n\tdictWord{11, 11, 334},\n\tdictWord{12, 11, 24},\n\tdictWord{12, 11, 386},\n\tdictWord{140, 11, 576},\n\tdictWord{133, 11, 757},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t18,\n\t},\n\tdictWord{6, 0, 526},\n\tdictWord{13, 0, 24},\n\tdictWord{13, 0, 110},\n\tdictWord{19, 0, 5},\n\tdictWord{147, 0, 44},\n\tdictWord{6, 0, 506},\n\tdictWord{134, 11, 506},\n\tdictWord{135, 11, 1553},\n\tdictWord{4, 0, 309},\n\tdictWord{5, 0, 462},\n\tdictWord{7, 0, 970},\n\tdictWord{7, 0, 1097},\n\tdictWord{22, 0, 30},\n\tdictWord{22, 0, 33},\n\tdictWord{\n\t\t7,\n\t\t11,\n\t\t1385,\n\t},\n\tdictWord{11, 11, 582},\n\tdictWord{11, 11, 650},\n\tdictWord{11, 11, 901},\n\tdictWord{11, 11, 949},\n\tdictWord{12, 11, 232},\n\tdictWord{12, 11, 236},\n\tdictWord{13, 11, 413},\n\tdictWord{13, 11, 501},\n\tdictWord{146, 11, 116},\n\tdictWord{9, 0, 140},\n\tdictWord{5, 10, 222},\n\tdictWord{138, 10, 534},\n\tdictWord{6, 0, 1056},\n\tdictWord{137, 10, 906},\n\tdictWord{134, 0, 1704},\n\tdictWord{138, 10, 503},\n\tdictWord{134, 0, 1036},\n\tdictWord{5, 10, 154},\n\tdictWord{7, 10, 1491},\n\tdictWord{\n\t\t10,\n\t\t10,\n\t\t379,\n\t},\n\tdictWord{138, 10, 485},\n\tdictWord{4, 11, 383},\n\tdictWord{133, 10, 716},\n\tdictWord{134, 0, 1315},\n\tdictWord{5, 0, 86},\n\tdictWord{7, 0, 743},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t85,\n\t},\n\tdictWord{10, 0, 281},\n\tdictWord{10, 0, 432},\n\tdictWord{11, 0, 825},\n\tdictWord{12, 0, 251},\n\tdictWord{13, 0, 118},\n\tdictWord{142, 0, 378},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t264,\n\t},\n\tdictWord{4, 10, 91},\n\tdictWord{5, 10, 388},\n\tdictWord{5, 10, 845},\n\tdictWord{6, 10, 206},\n\tdictWord{6, 10, 252},\n\tdictWord{6, 10, 365},\n\tdictWord{7, 10, 136},\n\tdictWord{7, 10, 531},\n\tdictWord{136, 10, 621},\n\tdictWord{5, 0, 524},\n\tdictWord{133, 0, 744},\n\tdictWord{5, 11, 277},\n\tdictWord{141, 11, 247},\n\tdictWord{\n\t\t132,\n\t\t11,\n\t\t435,\n\t},\n\tdictWord{10, 0, 107},\n\tdictWord{140, 0, 436},\n\tdictWord{132, 0, 927},\n\tdictWord{10, 0, 123},\n\tdictWord{12, 0, 670},\n\tdictWord{146, 0, 94},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t1149,\n\t},\n\tdictWord{9, 0, 156},\n\tdictWord{138, 0, 957},\n\tdictWord{5, 11, 265},\n\tdictWord{6, 11, 212},\n\tdictWord{135, 11, 28},\n\tdictWord{133, 0, 778},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t502,\n\t},\n\tdictWord{8, 0, 196},\n\tdictWord{10, 0, 283},\n\tdictWord{139, 0, 406},\n\tdictWord{135, 10, 576},\n\tdictWord{136, 11, 535},\n\tdictWord{134, 0, 1312},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t771,\n\t},\n\tdictWord{5, 10, 863},\n\tdictWord{5, 10, 898},\n\tdictWord{6, 10, 1632},\n\tdictWord{6, 10, 1644},\n\tdictWord{134, 10, 1780},\n\tdictWord{5, 0, 855},\n\tdictWord{5, 10, 331},\n\tdictWord{135, 11, 1487},\n\tdictWord{132, 11, 702},\n\tdictWord{5, 11, 808},\n\tdictWord{135, 11, 2045},\n\tdictWord{7, 0, 1400},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t446,\n\t},\n\tdictWord{138, 0, 45},\n\tdictWord{140, 10, 632},\n\tdictWord{132, 0, 1003},\n\tdictWord{5, 11, 166},\n\tdictWord{8, 11, 739},\n\tdictWord{140, 11, 511},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t107,\n\t},\n\tdictWord{7, 10, 201},\n\tdictWord{136, 10, 518},\n\tdictWord{6, 10, 446},\n\tdictWord{135, 10, 1817},\n\tdictWord{134, 0, 1532},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1097,\n\t},\n\tdictWord{4, 11, 119},\n\tdictWord{5, 11, 170},\n\tdictWord{5, 11, 447},\n\tdictWord{7, 11, 1708},\n\tdictWord{7, 11, 1889},\n\tdictWord{9, 11, 357},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t719,\n\t},\n\tdictWord{12, 11, 486},\n\tdictWord{140, 11, 596},\n\tdictWord{9, 10, 851},\n\tdictWord{141, 10, 510},\n\tdictWord{7, 0, 612},\n\tdictWord{8, 0, 545},\n\tdictWord{\n\t\t8,\n\t\t0,\n\t\t568,\n\t},\n\tdictWord{8, 0, 642},\n\tdictWord{9, 0, 717},\n\tdictWord{10, 0, 541},\n\tdictWord{10, 0, 763},\n\tdictWord{11, 0, 449},\n\tdictWord{12, 0, 489},\n\tdictWord{13, 0, 153},\n\tdictWord{13, 0, 296},\n\tdictWord{14, 0, 138},\n\tdictWord{14, 0, 392},\n\tdictWord{15, 0, 50},\n\tdictWord{16, 0, 6},\n\tdictWord{16, 0, 12},\n\tdictWord{20, 0, 9},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t504,\n\t},\n\tdictWord{4, 11, 450},\n\tdictWord{135, 11, 1158},\n\tdictWord{11, 0, 54},\n\tdictWord{13, 0, 173},\n\tdictWord{13, 0, 294},\n\tdictWord{5, 10, 883},\n\tdictWord{\n\t\t5,\n\t\t10,\n\t\t975,\n\t},\n\tdictWord{8, 10, 392},\n\tdictWord{148, 10, 7},\n\tdictWord{13, 0, 455},\n\tdictWord{15, 0, 99},\n\tdictWord{15, 0, 129},\n\tdictWord{144, 0, 68},\n\tdictWord{135, 0, 172},\n\tdictWord{132, 11, 754},\n\tdictWord{5, 10, 922},\n\tdictWord{134, 10, 1707},\n\tdictWord{134, 0, 1029},\n\tdictWord{17, 11, 39},\n\tdictWord{148, 11, 36},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t568,\n\t},\n\tdictWord{5, 10, 993},\n\tdictWord{7, 10, 515},\n\tdictWord{137, 10, 91},\n\tdictWord{132, 0, 732},\n\tdictWord{10, 0, 617},\n\tdictWord{138, 11, 617},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t974,\n\t},\n\tdictWord{7, 0, 989},\n\tdictWord{10, 0, 377},\n\tdictWord{12, 0, 363},\n\tdictWord{13, 0, 68},\n\tdictWord{13, 0, 94},\n\tdictWord{14, 0, 108},\n\tdictWord{\n\t\t142,\n\t\t0,\n\t\t306,\n\t},\n\tdictWord{136, 0, 733},\n\tdictWord{132, 0, 428},\n\tdictWord{7, 0, 1789},\n\tdictWord{135, 11, 1062},\n\tdictWord{7, 0, 2015},\n\tdictWord{140, 0, 665},\n\tdictWord{135, 10, 1433},\n\tdictWord{5, 0, 287},\n\tdictWord{7, 10, 921},\n\tdictWord{8, 10, 580},\n\tdictWord{8, 10, 593},\n\tdictWord{8, 10, 630},\n\tdictWord{138, 10, 28},\n\tdictWord{138, 0, 806},\n\tdictWord{4, 10, 911},\n\tdictWord{5, 10, 867},\n\tdictWord{5, 10, 1013},\n\tdictWord{7, 10, 2034},\n\tdictWord{8, 10, 798},\n\tdictWord{136, 10, 813},\n\tdictWord{134, 0, 1539},\n\tdictWord{8, 11, 523},\n\tdictWord{150, 11, 34},\n\tdictWord{135, 11, 740},\n\tdictWord{7, 11, 238},\n\tdictWord{7, 11, 2033},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t120,\n\t},\n\tdictWord{8, 11, 188},\n\tdictWord{8, 11, 659},\n\tdictWord{9, 11, 598},\n\tdictWord{10, 11, 466},\n\tdictWord{12, 11, 342},\n\tdictWord{12, 11, 588},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t503,\n\t},\n\tdictWord{14, 11, 246},\n\tdictWord{143, 11, 92},\n\tdictWord{7, 0, 1563},\n\tdictWord{141, 0, 182},\n\tdictWord{5, 10, 135},\n\tdictWord{6, 10, 519},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1722,\n\t},\n\tdictWord{10, 10, 271},\n\tdictWord{11, 10, 261},\n\tdictWord{145, 10, 54},\n\tdictWord{14, 10, 338},\n\tdictWord{148, 10, 81},\n\tdictWord{7, 0, 484},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t300,\n\t},\n\tdictWord{133, 10, 436},\n\tdictWord{145, 11, 114},\n\tdictWord{6, 0, 1623},\n\tdictWord{134, 0, 1681},\n\tdictWord{133, 11, 640},\n\tdictWord{4, 11, 201},\n\tdictWord{7, 11, 1744},\n\tdictWord{8, 11, 602},\n\tdictWord{11, 11, 247},\n\tdictWord{11, 11, 826},\n\tdictWord{145, 11, 65},\n\tdictWord{8, 11, 164},\n\tdictWord{\n\t\t146,\n\t\t11,\n\t\t62,\n\t},\n\tdictWord{6, 0, 1833},\n\tdictWord{6, 0, 1861},\n\tdictWord{136, 0, 878},\n\tdictWord{134, 0, 1569},\n\tdictWord{8, 10, 357},\n\tdictWord{10, 10, 745},\n\tdictWord{\n\t\t14,\n\t\t10,\n\t\t426,\n\t},\n\tdictWord{17, 10, 94},\n\tdictWord{147, 10, 57},\n\tdictWord{12, 0, 93},\n\tdictWord{12, 0, 501},\n\tdictWord{13, 0, 362},\n\tdictWord{14, 0, 151},\n\tdictWord{15, 0, 40},\n\tdictWord{15, 0, 59},\n\tdictWord{16, 0, 46},\n\tdictWord{17, 0, 25},\n\tdictWord{18, 0, 14},\n\tdictWord{18, 0, 134},\n\tdictWord{19, 0, 25},\n\tdictWord{19, 0, 69},\n\tdictWord{\n\t\t20,\n\t\t0,\n\t\t16,\n\t},\n\tdictWord{20, 0, 19},\n\tdictWord{20, 0, 66},\n\tdictWord{21, 0, 23},\n\tdictWord{21, 0, 25},\n\tdictWord{150, 0, 42},\n\tdictWord{6, 0, 1748},\n\tdictWord{8, 0, 715},\n\tdictWord{\n\t\t9,\n\t\t0,\n\t\t802,\n\t},\n\tdictWord{10, 0, 46},\n\tdictWord{10, 0, 819},\n\tdictWord{13, 0, 308},\n\tdictWord{14, 0, 351},\n\tdictWord{14, 0, 363},\n\tdictWord{146, 0, 67},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t994,\n\t},\n\tdictWord{4, 0, 63},\n\tdictWord{133, 0, 347},\n\tdictWord{132, 0, 591},\n\tdictWord{133, 0, 749},\n\tdictWord{7, 11, 1577},\n\tdictWord{10, 11, 304},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t549,\n\t},\n\tdictWord{11, 11, 424},\n\tdictWord{12, 11, 365},\n\tdictWord{13, 11, 220},\n\tdictWord{13, 11, 240},\n\tdictWord{142, 11, 33},\n\tdictWord{133, 0, 366},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t557,\n\t},\n\tdictWord{12, 0, 547},\n\tdictWord{14, 0, 86},\n\tdictWord{133, 10, 387},\n\tdictWord{135, 0, 1747},\n\tdictWord{132, 11, 907},\n\tdictWord{5, 11, 100},\n\tdictWord{10, 11, 329},\n\tdictWord{12, 11, 416},\n\tdictWord{149, 11, 29},\n\tdictWord{4, 10, 6},\n\tdictWord{5, 10, 708},\n\tdictWord{136, 10, 75},\n\tdictWord{7, 10, 1351},\n\tdictWord{9, 10, 581},\n\tdictWord{10, 10, 639},\n\tdictWord{11, 10, 453},\n\tdictWord{140, 10, 584},\n\tdictWord{7, 0, 89},\n\tdictWord{132, 10, 303},\n\tdictWord{138, 10, 772},\n\tdictWord{132, 11, 176},\n\tdictWord{5, 11, 636},\n\tdictWord{5, 11, 998},\n\tdictWord{8, 11, 26},\n\tdictWord{137, 11, 358},\n\tdictWord{7, 11, 9},\n\tdictWord{7, 11, 1508},\n\tdictWord{9, 11, 317},\n\tdictWord{10, 11, 210},\n\tdictWord{10, 11, 292},\n\tdictWord{10, 11, 533},\n\tdictWord{11, 11, 555},\n\tdictWord{12, 11, 526},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t607,\n\t},\n\tdictWord{13, 11, 263},\n\tdictWord{13, 11, 459},\n\tdictWord{142, 11, 271},\n\tdictWord{134, 0, 1463},\n\tdictWord{6, 0, 772},\n\tdictWord{6, 0, 1137},\n\tdictWord{\n\t\t139,\n\t\t11,\n\t\t595,\n\t},\n\tdictWord{7, 0, 977},\n\tdictWord{139, 11, 66},\n\tdictWord{138, 0, 893},\n\tdictWord{20, 0, 48},\n\tdictWord{148, 11, 48},\n\tdictWord{5, 0, 824},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t941,\n\t},\n\tdictWord{134, 11, 295},\n\tdictWord{7, 0, 1543},\n\tdictWord{7, 0, 1785},\n\tdictWord{10, 0, 690},\n\tdictWord{4, 10, 106},\n\tdictWord{139, 10, 717},\n\tdictWord{\n\t\t7,\n\t\t0,\n\t\t440,\n\t},\n\tdictWord{8, 0, 230},\n\tdictWord{139, 0, 106},\n\tdictWord{5, 10, 890},\n\tdictWord{133, 10, 988},\n\tdictWord{6, 10, 626},\n\tdictWord{142, 10, 431},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t127,\n\t},\n\tdictWord{141, 11, 27},\n\tdictWord{17, 0, 32},\n\tdictWord{10, 10, 706},\n\tdictWord{150, 10, 44},\n\tdictWord{132, 0, 216},\n\tdictWord{137, 0, 332},\n\tdictWord{4, 10, 698},\n\tdictWord{136, 11, 119},\n\tdictWord{139, 11, 267},\n\tdictWord{138, 10, 17},\n\tdictWord{11, 11, 526},\n\tdictWord{11, 11, 939},\n\tdictWord{\n\t\t141,\n\t\t11,\n\t\t290,\n\t},\n\tdictWord{7, 11, 1167},\n\tdictWord{11, 11, 934},\n\tdictWord{13, 11, 391},\n\tdictWord{145, 11, 76},\n\tdictWord{139, 11, 39},\n\tdictWord{134, 10, 84},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t914,\n\t},\n\tdictWord{5, 0, 800},\n\tdictWord{133, 0, 852},\n\tdictWord{10, 0, 416},\n\tdictWord{141, 0, 115},\n\tdictWord{7, 0, 564},\n\tdictWord{142, 0, 168},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t918,\n\t},\n\tdictWord{133, 0, 876},\n\tdictWord{134, 0, 1764},\n\tdictWord{152, 0, 3},\n\tdictWord{4, 0, 92},\n\tdictWord{5, 0, 274},\n\tdictWord{7, 11, 126},\n\tdictWord{136, 11, 84},\n\tdictWord{140, 10, 498},\n\tdictWord{136, 11, 790},\n\tdictWord{8, 0, 501},\n\tdictWord{5, 10, 986},\n\tdictWord{6, 10, 130},\n\tdictWord{7, 10, 1582},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t458,\n\t},\n\tdictWord{10, 10, 101},\n\tdictWord{10, 10, 318},\n\tdictWord{138, 10, 823},\n\tdictWord{6, 11, 64},\n\tdictWord{12, 11, 377},\n\tdictWord{141, 11, 309},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t743,\n\t},\n\tdictWord{138, 0, 851},\n\tdictWord{4, 0, 49},\n\tdictWord{7, 0, 280},\n\tdictWord{135, 0, 1633},\n\tdictWord{134, 0, 879},\n\tdictWord{136, 0, 47},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1644,\n\t},\n\tdictWord{137, 10, 129},\n\tdictWord{132, 0, 865},\n\tdictWord{134, 0, 1202},\n\tdictWord{9, 11, 34},\n\tdictWord{139, 11, 484},\n\tdictWord{135, 10, 997},\n\tdictWord{5, 0, 272},\n\tdictWord{5, 0, 908},\n\tdictWord{5, 0, 942},\n\tdictWord{8, 0, 197},\n\tdictWord{9, 0, 47},\n\tdictWord{11, 0, 538},\n\tdictWord{139, 0, 742},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t1700,\n\t},\n\tdictWord{7, 11, 26},\n\tdictWord{7, 11, 293},\n\tdictWord{7, 11, 382},\n\tdictWord{7, 11, 1026},\n\tdictWord{7, 11, 1087},\n\tdictWord{7, 11, 2027},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t24,\n\t},\n\tdictWord{8, 11, 114},\n\tdictWord{8, 11, 252},\n\tdictWord{8, 11, 727},\n\tdictWord{8, 11, 729},\n\tdictWord{9, 11, 30},\n\tdictWord{9, 11, 199},\n\tdictWord{9, 11, 231},\n\tdictWord{9, 11, 251},\n\tdictWord{9, 11, 334},\n\tdictWord{9, 11, 361},\n\tdictWord{9, 11, 488},\n\tdictWord{9, 11, 712},\n\tdictWord{10, 11, 55},\n\tdictWord{10, 11, 60},\n\tdictWord{\n\t\t10,\n\t\t11,\n\t\t232,\n\t},\n\tdictWord{10, 11, 332},\n\tdictWord{10, 11, 384},\n\tdictWord{10, 11, 396},\n\tdictWord{10, 11, 504},\n\tdictWord{10, 11, 542},\n\tdictWord{10, 11, 652},\n\tdictWord{11, 11, 20},\n\tdictWord{11, 11, 48},\n\tdictWord{11, 11, 207},\n\tdictWord{11, 11, 291},\n\tdictWord{11, 11, 298},\n\tdictWord{11, 11, 342},\n\tdictWord{\n\t\t11,\n\t\t11,\n\t\t365,\n\t},\n\tdictWord{11, 11, 394},\n\tdictWord{11, 11, 620},\n\tdictWord{11, 11, 705},\n\tdictWord{11, 11, 1017},\n\tdictWord{12, 11, 123},\n\tdictWord{12, 11, 340},\n\tdictWord{12, 11, 406},\n\tdictWord{12, 11, 643},\n\tdictWord{13, 11, 61},\n\tdictWord{13, 11, 269},\n\tdictWord{13, 11, 311},\n\tdictWord{13, 11, 319},\n\tdictWord{13, 11, 486},\n\tdictWord{14, 11, 234},\n\tdictWord{15, 11, 62},\n\tdictWord{15, 11, 85},\n\tdictWord{16, 11, 71},\n\tdictWord{18, 11, 119},\n\tdictWord{148, 11, 105},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t1455,\n\t},\n\tdictWord{150, 11, 37},\n\tdictWord{135, 10, 1927},\n\tdictWord{135, 0, 1911},\n\tdictWord{137, 0, 891},\n\tdictWord{7, 10, 1756},\n\tdictWord{137, 10, 98},\n\tdictWord{7, 10, 1046},\n\tdictWord{139, 10, 160},\n\tdictWord{132, 0, 761},\n\tdictWord{6, 11, 379},\n\tdictWord{7, 11, 270},\n\tdictWord{7, 11, 1116},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t176,\n\t},\n\tdictWord{8, 11, 183},\n\tdictWord{9, 11, 432},\n\tdictWord{9, 11, 661},\n\tdictWord{12, 11, 247},\n\tdictWord{12, 11, 617},\n\tdictWord{146, 11, 125},\n\tdictWord{\n\t\t6,\n\t\t10,\n\t\t45,\n\t},\n\tdictWord{7, 10, 433},\n\tdictWord{8, 10, 129},\n\tdictWord{9, 10, 21},\n\tdictWord{10, 10, 392},\n\tdictWord{11, 10, 79},\n\tdictWord{12, 10, 499},\n\tdictWord{\n\t\t13,\n\t\t10,\n\t\t199,\n\t},\n\tdictWord{141, 10, 451},\n\tdictWord{4, 0, 407},\n\tdictWord{5, 11, 792},\n\tdictWord{133, 11, 900},\n\tdictWord{132, 0, 560},\n\tdictWord{135, 0, 183},\n\tdictWord{\n\t\t13,\n\t\t0,\n\t\t490,\n\t},\n\tdictWord{7, 10, 558},\n\tdictWord{136, 10, 353},\n\tdictWord{4, 0, 475},\n\tdictWord{6, 0, 731},\n\tdictWord{11, 0, 35},\n\tdictWord{13, 0, 71},\n\tdictWord{13, 0, 177},\n\tdictWord{14, 0, 422},\n\tdictWord{133, 10, 785},\n\tdictWord{8, 10, 81},\n\tdictWord{9, 10, 189},\n\tdictWord{9, 10, 201},\n\tdictWord{11, 10, 478},\n\tdictWord{11, 10, 712},\n\tdictWord{141, 10, 338},\n\tdictWord{4, 0, 418},\n\tdictWord{4, 0, 819},\n\tdictWord{133, 10, 353},\n\tdictWord{151, 10, 26},\n\tdictWord{4, 11, 901},\n\tdictWord{\n\t\t133,\n\t\t11,\n\t\t776,\n\t},\n\tdictWord{132, 0, 575},\n\tdictWord{7, 0, 818},\n\tdictWord{16, 0, 92},\n\tdictWord{17, 0, 14},\n\tdictWord{17, 0, 45},\n\tdictWord{18, 0, 75},\n\tdictWord{148, 0, 18},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t222,\n\t},\n\tdictWord{7, 0, 636},\n\tdictWord{7, 0, 1620},\n\tdictWord{8, 0, 409},\n\tdictWord{9, 0, 693},\n\tdictWord{139, 0, 77},\n\tdictWord{6, 10, 25},\n\tdictWord{7, 10, 855},\n\tdictWord{7, 10, 1258},\n\tdictWord{144, 10, 32},\n\tdictWord{6, 0, 1880},\n\tdictWord{6, 0, 1887},\n\tdictWord{6, 0, 1918},\n\tdictWord{6, 0, 1924},\n\tdictWord{9, 0, 967},\n\tdictWord{9, 0, 995},\n\tdictWord{9, 0, 1015},\n\tdictWord{12, 0, 826},\n\tdictWord{12, 0, 849},\n\tdictWord{12, 0, 857},\n\tdictWord{12, 0, 860},\n\tdictWord{12, 0, 886},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t932,\n\t},\n\tdictWord{18, 0, 228},\n\tdictWord{18, 0, 231},\n\tdictWord{146, 0, 240},\n\tdictWord{134, 0, 633},\n\tdictWord{134, 0, 1308},\n\tdictWord{4, 11, 37},\n\tdictWord{\n\t\t5,\n\t\t11,\n\t\t334,\n\t},\n\tdictWord{135, 11, 1253},\n\tdictWord{10, 0, 86},\n\tdictWord{4, 10, 4},\n\tdictWord{7, 10, 1118},\n\tdictWord{7, 10, 1320},\n\tdictWord{7, 10, 1706},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t277,\n\t},\n\tdictWord{9, 10, 622},\n\tdictWord{11, 10, 724},\n\tdictWord{12, 10, 350},\n\tdictWord{12, 10, 397},\n\tdictWord{13, 10, 28},\n\tdictWord{13, 10, 159},\n\tdictWord{\n\t\t15,\n\t\t10,\n\t\t89,\n\t},\n\tdictWord{18, 10, 5},\n\tdictWord{19, 10, 9},\n\tdictWord{20, 10, 34},\n\tdictWord{150, 10, 47},\n\tdictWord{132, 11, 508},\n\tdictWord{137, 11, 448},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t107,\n\t},\n\tdictWord{146, 11, 31},\n\tdictWord{132, 0, 817},\n\tdictWord{134, 0, 663},\n\tdictWord{133, 0, 882},\n\tdictWord{134, 0, 914},\n\tdictWord{132, 11, 540},\n\tdictWord{132, 11, 533},\n\tdictWord{136, 11, 608},\n\tdictWord{8, 0, 885},\n\tdictWord{138, 0, 865},\n\tdictWord{132, 0, 426},\n\tdictWord{6, 0, 58},\n\tdictWord{7, 0, 745},\n\tdictWord{7, 0, 1969},\n\tdictWord{8, 0, 399},\n\tdictWord{8, 0, 675},\n\tdictWord{9, 0, 479},\n\tdictWord{9, 0, 731},\n\tdictWord{10, 0, 330},\n\tdictWord{10, 0, 593},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t817,\n\t},\n\tdictWord{11, 0, 32},\n\tdictWord{11, 0, 133},\n\tdictWord{11, 0, 221},\n\tdictWord{145, 0, 68},\n\tdictWord{134, 10, 255},\n\tdictWord{7, 0, 102},\n\tdictWord{\n\t\t137,\n\t\t0,\n\t\t538,\n\t},\n\tdictWord{137, 10, 216},\n\tdictWord{7, 11, 253},\n\tdictWord{136, 11, 549},\n\tdictWord{135, 11, 912},\n\tdictWord{9, 10, 183},\n\tdictWord{139, 10, 286},\n\tdictWord{11, 10, 956},\n\tdictWord{151, 10, 3},\n\tdictWord{8, 11, 527},\n\tdictWord{18, 11, 60},\n\tdictWord{147, 11, 24},\n\tdictWord{4, 10, 536},\n\tdictWord{7, 10, 1141},\n\tdictWord{10, 10, 723},\n\tdictWord{139, 10, 371},\n\tdictWord{133, 11, 920},\n\tdictWord{7, 0, 876},\n\tdictWord{135, 10, 285},\n\tdictWord{135, 10, 560},\n\tdictWord{\n\t\t132,\n\t\t10,\n\t\t690,\n\t},\n\tdictWord{142, 11, 126},\n\tdictWord{11, 10, 33},\n\tdictWord{12, 10, 571},\n\tdictWord{149, 10, 1},\n\tdictWord{133, 0, 566},\n\tdictWord{9, 0, 139},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t399,\n\t},\n\tdictWord{11, 0, 469},\n\tdictWord{12, 0, 634},\n\tdictWord{13, 0, 223},\n\tdictWord{132, 11, 483},\n\tdictWord{6, 0, 48},\n\tdictWord{135, 0, 63},\n\tdictWord{18, 0, 12},\n\tdictWord{7, 10, 1862},\n\tdictWord{12, 10, 491},\n\tdictWord{12, 10, 520},\n\tdictWord{13, 10, 383},\n\tdictWord{142, 10, 244},\n\tdictWord{135, 11, 1665},\n\tdictWord{132, 11, 448},\n\tdictWord{9, 11, 495},\n\tdictWord{146, 11, 104},\n\tdictWord{6, 0, 114},\n\tdictWord{7, 0, 1224},\n\tdictWord{7, 0, 1556},\n\tdictWord{136, 0, 3},\n\tdictWord{\n\t\t4,\n\t\t10,\n\t\t190,\n\t},\n\tdictWord{133, 10, 554},\n\tdictWord{8, 0, 576},\n\tdictWord{9, 0, 267},\n\tdictWord{133, 10, 1001},\n\tdictWord{133, 10, 446},\n\tdictWord{133, 0, 933},\n\tdictWord{139, 11, 1009},\n\tdictWord{8, 11, 653},\n\tdictWord{13, 11, 93},\n\tdictWord{147, 11, 14},\n\tdictWord{6, 0, 692},\n\tdictWord{6, 0, 821},\n\tdictWord{134, 0, 1077},\n\tdictWord{5, 11, 172},\n\tdictWord{135, 11, 801},\n\tdictWord{138, 0, 752},\n\tdictWord{4, 0, 375},\n\tdictWord{134, 0, 638},\n\tdictWord{134, 0, 1011},\n\tdictWord{\n\t\t140,\n\t\t11,\n\t\t540,\n\t},\n\tdictWord{9, 0, 96},\n\tdictWord{133, 11, 260},\n\tdictWord{139, 11, 587},\n\tdictWord{135, 10, 1231},\n\tdictWord{12, 0, 30},\n\tdictWord{13, 0, 148},\n\tdictWord{\n\t\t14,\n\t\t0,\n\t\t87,\n\t},\n\tdictWord{14, 0, 182},\n\tdictWord{16, 0, 42},\n\tdictWord{20, 0, 70},\n\tdictWord{132, 10, 304},\n\tdictWord{6, 0, 1398},\n\tdictWord{7, 0, 56},\n\tdictWord{7, 0, 1989},\n\tdictWord{8, 0, 337},\n\tdictWord{8, 0, 738},\n\tdictWord{9, 0, 600},\n\tdictWord{12, 0, 37},\n\tdictWord{13, 0, 447},\n\tdictWord{142, 0, 92},\n\tdictWord{138, 0, 666},\n\tdictWord{\n\t\t5,\n\t\t0,\n\t\t394,\n\t},\n\tdictWord{7, 0, 487},\n\tdictWord{136, 0, 246},\n\tdictWord{9, 0, 437},\n\tdictWord{6, 10, 53},\n\tdictWord{6, 10, 199},\n\tdictWord{7, 10, 1408},\n\tdictWord{8, 10, 32},\n\tdictWord{8, 10, 93},\n\tdictWord{10, 10, 397},\n\tdictWord{10, 10, 629},\n\tdictWord{11, 10, 593},\n\tdictWord{11, 10, 763},\n\tdictWord{13, 10, 326},\n\tdictWord{145, 10, 35},\n\tdictWord{134, 10, 105},\n\tdictWord{9, 0, 320},\n\tdictWord{10, 0, 506},\n\tdictWord{138, 10, 794},\n\tdictWord{7, 11, 57},\n\tdictWord{8, 11, 167},\n\tdictWord{8, 11, 375},\n\tdictWord{9, 11, 82},\n\tdictWord{9, 11, 561},\n\tdictWord{10, 11, 620},\n\tdictWord{10, 11, 770},\n\tdictWord{11, 10, 704},\n\tdictWord{141, 10, 396},\n\tdictWord{6, 0, 1003},\n\tdictWord{5, 10, 114},\n\tdictWord{5, 10, 255},\n\tdictWord{141, 10, 285},\n\tdictWord{7, 0, 866},\n\tdictWord{135, 0, 1163},\n\tdictWord{133, 11, 531},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t328,\n\t},\n\tdictWord{7, 10, 2035},\n\tdictWord{8, 10, 19},\n\tdictWord{9, 10, 89},\n\tdictWord{138, 10, 831},\n\tdictWord{8, 11, 194},\n\tdictWord{136, 11, 756},\n\tdictWord{\n\t\t136,\n\t\t0,\n\t\t1000,\n\t},\n\tdictWord{5, 11, 453},\n\tdictWord{134, 11, 441},\n\tdictWord{4, 0, 101},\n\tdictWord{5, 0, 833},\n\tdictWord{7, 0, 1171},\n\tdictWord{136, 0, 744},\n\tdictWord{\n\t\t133,\n\t\t0,\n\t\t726,\n\t},\n\tdictWord{136, 10, 746},\n\tdictWord{138, 0, 176},\n\tdictWord{6, 0, 9},\n\tdictWord{6, 0, 397},\n\tdictWord{7, 0, 53},\n\tdictWord{7, 0, 1742},\n\tdictWord{10, 0, 632},\n\tdictWord{11, 0, 828},\n\tdictWord{140, 0, 146},\n\tdictWord{135, 11, 22},\n\tdictWord{145, 11, 64},\n\tdictWord{132, 0, 839},\n\tdictWord{11, 0, 417},\n\tdictWord{12, 0, 223},\n\tdictWord{140, 0, 265},\n\tdictWord{4, 11, 102},\n\tdictWord{7, 11, 815},\n\tdictWord{7, 11, 1699},\n\tdictWord{139, 11, 964},\n\tdictWord{5, 10, 955},\n\tdictWord{\n\t\t136,\n\t\t10,\n\t\t814,\n\t},\n\tdictWord{6, 0, 1931},\n\tdictWord{6, 0, 2007},\n\tdictWord{18, 0, 246},\n\tdictWord{146, 0, 247},\n\tdictWord{8, 0, 198},\n\tdictWord{11, 0, 29},\n\tdictWord{140, 0, 534},\n\tdictWord{135, 0, 1771},\n\tdictWord{6, 0, 846},\n\tdictWord{7, 11, 1010},\n\tdictWord{11, 11, 733},\n\tdictWord{11, 11, 759},\n\tdictWord{12, 11, 563},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t34,\n\t},\n\tdictWord{14, 11, 101},\n\tdictWord{18, 11, 45},\n\tdictWord{146, 11, 129},\n\tdictWord{4, 0, 186},\n\tdictWord{5, 0, 157},\n\tdictWord{8, 0, 168},\n\tdictWord{138, 0, 6},\n\tdictWord{132, 11, 899},\n\tdictWord{133, 10, 56},\n\tdictWord{148, 10, 100},\n\tdictWord{133, 0, 875},\n\tdictWord{5, 0, 773},\n\tdictWord{5, 0, 991},\n\tdictWord{6, 0, 1635},\n\tdictWord{134, 0, 1788},\n\tdictWord{6, 0, 1274},\n\tdictWord{9, 0, 477},\n\tdictWord{141, 0, 78},\n\tdictWord{4, 0, 639},\n\tdictWord{7, 0, 111},\n\tdictWord{8, 0, 581},\n\tdictWord{\n\t\t12,\n\t\t0,\n\t\t177,\n\t},\n\tdictWord{6, 11, 52},\n\tdictWord{9, 11, 104},\n\tdictWord{9, 11, 559},\n\tdictWord{10, 10, 4},\n\tdictWord{10, 10, 13},\n\tdictWord{11, 10, 638},\n\tdictWord{\n\t\t12,\n\t\t11,\n\t\t308,\n\t},\n\tdictWord{19, 11, 87},\n\tdictWord{148, 10, 57},\n\tdictWord{132, 11, 604},\n\tdictWord{4, 11, 301},\n\tdictWord{133, 10, 738},\n\tdictWord{133, 10, 758},\n\tdictWord{134, 0, 1747},\n\tdictWord{7, 11, 1440},\n\tdictWord{11, 11, 854},\n\tdictWord{11, 11, 872},\n\tdictWord{11, 11, 921},\n\tdictWord{12, 11, 551},\n\tdictWord{\n\t\t13,\n\t\t11,\n\t\t472,\n\t},\n\tdictWord{142, 11, 367},\n\tdictWord{7, 0, 1364},\n\tdictWord{7, 0, 1907},\n\tdictWord{141, 0, 158},\n\tdictWord{134, 0, 873},\n\tdictWord{4, 0, 404},\n\tdictWord{\n\t\t4,\n\t\t0,\n\t\t659,\n\t},\n\tdictWord{7, 0, 552},\n\tdictWord{135, 0, 675},\n\tdictWord{135, 10, 1112},\n\tdictWord{139, 10, 328},\n\tdictWord{7, 11, 508},\n\tdictWord{137, 10, 133},\n\tdictWord{133, 0, 391},\n\tdictWord{5, 10, 110},\n\tdictWord{6, 10, 169},\n\tdictWord{6, 10, 1702},\n\tdictWord{7, 10, 400},\n\tdictWord{8, 10, 538},\n\tdictWord{9, 10, 184},\n\tdictWord{\n\t\t9,\n\t\t10,\n\t\t524,\n\t},\n\tdictWord{140, 10, 218},\n\tdictWord{6, 11, 310},\n\tdictWord{7, 11, 1849},\n\tdictWord{8, 11, 72},\n\tdictWord{8, 11, 272},\n\tdictWord{8, 11, 431},\n\tdictWord{\n\t\t9,\n\t\t11,\n\t\t12,\n\t},\n\tdictWord{9, 11, 351},\n\tdictWord{10, 11, 563},\n\tdictWord{10, 11, 630},\n\tdictWord{10, 11, 810},\n\tdictWord{11, 11, 367},\n\tdictWord{11, 11, 599},\n\tdictWord{11, 11, 686},\n\tdictWord{140, 11, 672},\n\tdictWord{5, 0, 540},\n\tdictWord{6, 0, 1697},\n\tdictWord{136, 0, 668},\n\tdictWord{132, 0, 883},\n\tdictWord{134, 0, 78},\n\tdictWord{12, 0, 628},\n\tdictWord{18, 0, 79},\n\tdictWord{6, 10, 133},\n\tdictWord{9, 10, 353},\n\tdictWord{139, 10, 993},\n\tdictWord{6, 11, 181},\n\tdictWord{7, 11, 537},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t64,\n\t},\n\tdictWord{9, 11, 127},\n\tdictWord{10, 11, 496},\n\tdictWord{12, 11, 510},\n\tdictWord{141, 11, 384},\n\tdictWord{6, 10, 93},\n\tdictWord{7, 10, 1422},\n\tdictWord{\n\t\t7,\n\t\t10,\n\t\t1851,\n\t},\n\tdictWord{8, 10, 673},\n\tdictWord{9, 10, 529},\n\tdictWord{140, 10, 43},\n\tdictWord{137, 10, 371},\n\tdictWord{134, 0, 1460},\n\tdictWord{134, 0, 962},\n\tdictWord{4, 11, 244},\n\tdictWord{135, 11, 233},\n\tdictWord{9, 10, 25},\n\tdictWord{10, 10, 467},\n\tdictWord{138, 10, 559},\n\tdictWord{4, 10, 335},\n\tdictWord{\n\t\t135,\n\t\t10,\n\t\t942,\n\t},\n\tdictWord{133, 0, 460},\n\tdictWord{135, 11, 334},\n\tdictWord{134, 11, 1650},\n\tdictWord{4, 0, 199},\n\tdictWord{139, 0, 34},\n\tdictWord{5, 10, 601},\n\tdictWord{\n\t\t8,\n\t\t10,\n\t\t39,\n\t},\n\tdictWord{10, 10, 773},\n\tdictWord{11, 10, 84},\n\tdictWord{12, 10, 205},\n\tdictWord{142, 10, 1},\n\tdictWord{133, 10, 870},\n\tdictWord{134, 0, 388},\n\tdictWord{14, 0, 474},\n\tdictWord{148, 0, 120},\n\tdictWord{133, 11, 369},\n\tdictWord{139, 0, 271},\n\tdictWord{4, 0, 511},\n\tdictWord{9, 0, 333},\n\tdictWord{9, 0, 379},\n\tdictWord{\n\t\t10,\n\t\t0,\n\t\t602,\n\t},\n\tdictWord{11, 0, 441},\n\tdictWord{11, 0, 723},\n\tdictWord{11, 0, 976},\n\tdictWord{12, 0, 357},\n\tdictWord{132, 10, 181},\n\tdictWord{134, 0, 608},\n\tdictWord{134, 10, 1652},\n\tdictWord{22, 0, 49},\n\tdictWord{137, 11, 338},\n\tdictWord{140, 0, 988},\n\tdictWord{134, 0, 617},\n\tdictWord{5, 0, 938},\n\tdictWord{136, 0, 707},\n\tdictWord{132, 10, 97},\n\tdictWord{5, 10, 147},\n\tdictWord{6, 10, 286},\n\tdictWord{7, 10, 1362},\n\tdictWord{141, 10, 176},\n\tdictWord{6, 0, 756},\n\tdictWord{\n\t\t134,\n\t\t0,\n\t\t1149,\n\t},\n\tdictWord{133, 11, 896},\n\tdictWord{6, 10, 375},\n\tdictWord{7, 10, 169},\n\tdictWord{7, 10, 254},\n\tdictWord{136, 10, 780},\n\tdictWord{134, 0, 1583},\n\tdictWord{135, 10, 1447},\n\tdictWord{139, 0, 285},\n\tdictWord{7, 11, 1117},\n\tdictWord{8, 11, 393},\n\tdictWord{136, 11, 539},\n\tdictWord{135, 0, 344},\n\tdictWord{\n\t\t6,\n\t\t0,\n\t\t469,\n\t},\n\tdictWord{7, 0, 1709},\n\tdictWord{138, 0, 515},\n\tdictWord{5, 10, 629},\n\tdictWord{135, 10, 1549},\n\tdictWord{5, 11, 4},\n\tdictWord{5, 11, 810},\n\tdictWord{\n\t\t6,\n\t\t11,\n\t\t13,\n\t},\n\tdictWord{6, 11, 538},\n\tdictWord{6, 11, 1690},\n\tdictWord{6, 11, 1726},\n\tdictWord{7, 11, 499},\n\tdictWord{7, 11, 1819},\n\tdictWord{8, 11, 148},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t696,\n\t},\n\tdictWord{8, 11, 791},\n\tdictWord{12, 11, 125},\n\tdictWord{13, 11, 54},\n\tdictWord{143, 11, 9},\n\tdictWord{135, 11, 1268},\n\tdictWord{137, 0, 404},\n\tdictWord{\n\t\t132,\n\t\t0,\n\t\t500,\n\t},\n\tdictWord{5, 0, 68},\n\tdictWord{134, 0, 383},\n\tdictWord{11, 0, 216},\n\tdictWord{139, 0, 340},\n\tdictWord{4, 11, 925},\n\tdictWord{5, 11, 803},\n\tdictWord{\n\t\t8,\n\t\t11,\n\t\t698,\n\t},\n\tdictWord{138, 11, 828},\n\tdictWord{4, 0, 337},\n\tdictWord{6, 0, 353},\n\tdictWord{7, 0, 1934},\n\tdictWord{8, 0, 488},\n\tdictWord{137, 0, 429},\n\tdictWord{7, 0, 236},\n\tdictWord{7, 0, 1795},\n\tdictWord{8, 0, 259},\n\tdictWord{9, 0, 135},\n\tdictWord{9, 0, 177},\n\tdictWord{9, 0, 860},\n\tdictWord{10, 0, 825},\n\tdictWord{11, 0, 115},\n\tdictWord{\n\t\t11,\n\t\t0,\n\t\t370,\n\t},\n\tdictWord{11, 0, 405},\n\tdictWord{11, 0, 604},\n\tdictWord{12, 0, 10},\n\tdictWord{12, 0, 667},\n\tdictWord{12, 0, 669},\n\tdictWord{13, 0, 76},\n\tdictWord{14, 0, 310},\n\tdictWord{15, 0, 76},\n\tdictWord{15, 0, 147},\n\tdictWord{148, 0, 23},\n\tdictWord{4, 0, 15},\n\tdictWord{4, 0, 490},\n\tdictWord{5, 0, 22},\n\tdictWord{6, 0, 244},\n\tdictWord{7, 0, 40},\n\tdictWord{7, 0, 200},\n\tdictWord{7, 0, 906},\n\tdictWord{7, 0, 1199},\n\tdictWord{9, 0, 616},\n\tdictWord{10, 0, 716},\n\tdictWord{11, 0, 635},\n\tdictWord{11, 0, 801},\n\tdictWord{\n\t\t140,\n\t\t0,\n\t\t458,\n\t},\n\tdictWord{12, 0, 756},\n\tdictWord{132, 10, 420},\n\tdictWord{134, 0, 1504},\n\tdictWord{6, 0, 757},\n\tdictWord{133, 11, 383},\n\tdictWord{6, 0, 1266},\n\tdictWord{\n\t\t135,\n\t\t0,\n\t\t1735,\n\t},\n\tdictWord{5, 0, 598},\n\tdictWord{7, 0, 791},\n\tdictWord{8, 0, 108},\n\tdictWord{9, 0, 123},\n\tdictWord{7, 10, 1570},\n\tdictWord{140, 10, 542},\n\tdictWord{\n\t\t142,\n\t\t11,\n\t\t410,\n\t},\n\tdictWord{9, 11, 660},\n\tdictWord{138, 11, 347},\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/symbol_list.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Utilities for building Huffman decoding tables. */\n\ntype symbolList struct {\n\tstorage []uint16\n\toffset  int\n}\n\nfunc symbolListGet(sl symbolList, i int) uint16 {\n\treturn sl.storage[i+sl.offset]\n}\n\nfunc symbolListPut(sl symbolList, i int, val uint16) {\n\tsl.storage[i+sl.offset] = val\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/transform.go",
    "content": "package brotli\n\nconst (\n\ttransformIdentity       = 0\n\ttransformOmitLast1      = 1\n\ttransformOmitLast2      = 2\n\ttransformOmitLast3      = 3\n\ttransformOmitLast4      = 4\n\ttransformOmitLast5      = 5\n\ttransformOmitLast6      = 6\n\ttransformOmitLast7      = 7\n\ttransformOmitLast8      = 8\n\ttransformOmitLast9      = 9\n\ttransformUppercaseFirst = 10\n\ttransformUppercaseAll   = 11\n\ttransformOmitFirst1     = 12\n\ttransformOmitFirst2     = 13\n\ttransformOmitFirst3     = 14\n\ttransformOmitFirst4     = 15\n\ttransformOmitFirst5     = 16\n\ttransformOmitFirst6     = 17\n\ttransformOmitFirst7     = 18\n\ttransformOmitFirst8     = 19\n\ttransformOmitFirst9     = 20\n\ttransformShiftFirst     = 21\n\ttransformShiftAll       = 22 + iota - 22\n\tnumTransformTypes\n)\n\nconst transformsMaxCutOff = transformOmitLast9\n\ntype transforms struct {\n\tprefix_suffix_size uint16\n\tprefix_suffix      []byte\n\tprefix_suffix_map  []uint16\n\tnum_transforms     uint32\n\ttransforms         []byte\n\tparams             []byte\n\tcutOffTransforms   [transformsMaxCutOff + 1]int16\n}\n\nfunc transformPrefixId(t *transforms, I int) byte {\n\treturn t.transforms[(I*3)+0]\n}\n\nfunc transformType(t *transforms, I int) byte {\n\treturn t.transforms[(I*3)+1]\n}\n\nfunc transformSuffixId(t *transforms, I int) byte {\n\treturn t.transforms[(I*3)+2]\n}\n\nfunc transformPrefix(t *transforms, I int) []byte {\n\treturn t.prefix_suffix[t.prefix_suffix_map[transformPrefixId(t, I)]:]\n}\n\nfunc transformSuffix(t *transforms, I int) []byte {\n\treturn t.prefix_suffix[t.prefix_suffix_map[transformSuffixId(t, I)]:]\n}\n\n/* RFC 7932 transforms string data */\nconst kPrefixSuffix string = \"\\001 \\002, \\010 of the \\004 of \\002s \\001.\\005 and \\004 \" + \"in \\001\\\"\\004 to \\002\\\">\\001\\n\\002. \\001]\\005 for \\003 a \\006 \" + \"that \\001'\\006 with \\006 from \\004 by \\001(\\006. T\" + \"he \\004 on \\004 as \\004 is \\004ing \\002\\n\\t\\001:\\003ed \" + \"\\002=\\\"\\004 at \\003ly \\001,\\002='\\005.com/\\007. This \\005\" + \" not \\003er \\003al \\004ful \\004ive \\005less \\004es\" + \"t \\004ize \\002\\xc2\\xa0\\004ous \\005 the \\002e \\000\"\n\nvar kPrefixSuffixMap = [50]uint16{\n\t0x00,\n\t0x02,\n\t0x05,\n\t0x0E,\n\t0x13,\n\t0x16,\n\t0x18,\n\t0x1E,\n\t0x23,\n\t0x25,\n\t0x2A,\n\t0x2D,\n\t0x2F,\n\t0x32,\n\t0x34,\n\t0x3A,\n\t0x3E,\n\t0x45,\n\t0x47,\n\t0x4E,\n\t0x55,\n\t0x5A,\n\t0x5C,\n\t0x63,\n\t0x68,\n\t0x6D,\n\t0x72,\n\t0x77,\n\t0x7A,\n\t0x7C,\n\t0x80,\n\t0x83,\n\t0x88,\n\t0x8C,\n\t0x8E,\n\t0x91,\n\t0x97,\n\t0x9F,\n\t0xA5,\n\t0xA9,\n\t0xAD,\n\t0xB2,\n\t0xB7,\n\t0xBD,\n\t0xC2,\n\t0xC7,\n\t0xCA,\n\t0xCF,\n\t0xD5,\n\t0xD8,\n}\n\n/* RFC 7932 transforms */\nvar kTransformsData = []byte{\n\t49,\n\ttransformIdentity,\n\t49,\n\t49,\n\ttransformIdentity,\n\t0,\n\t0,\n\ttransformIdentity,\n\t0,\n\t49,\n\ttransformOmitFirst1,\n\t49,\n\t49,\n\ttransformUppercaseFirst,\n\t0,\n\t49,\n\ttransformIdentity,\n\t47,\n\t0,\n\ttransformIdentity,\n\t49,\n\t4,\n\ttransformIdentity,\n\t0,\n\t49,\n\ttransformIdentity,\n\t3,\n\t49,\n\ttransformUppercaseFirst,\n\t49,\n\t49,\n\ttransformIdentity,\n\t6,\n\t49,\n\ttransformOmitFirst2,\n\t49,\n\t49,\n\ttransformOmitLast1,\n\t49,\n\t1,\n\ttransformIdentity,\n\t0,\n\t49,\n\ttransformIdentity,\n\t1,\n\t0,\n\ttransformUppercaseFirst,\n\t0,\n\t49,\n\ttransformIdentity,\n\t7,\n\t49,\n\ttransformIdentity,\n\t9,\n\t48,\n\ttransformIdentity,\n\t0,\n\t49,\n\ttransformIdentity,\n\t8,\n\t49,\n\ttransformIdentity,\n\t5,\n\t49,\n\ttransformIdentity,\n\t10,\n\t49,\n\ttransformIdentity,\n\t11,\n\t49,\n\ttransformOmitLast3,\n\t49,\n\t49,\n\ttransformIdentity,\n\t13,\n\t49,\n\ttransformIdentity,\n\t14,\n\t49,\n\ttransformOmitFirst3,\n\t49,\n\t49,\n\ttransformOmitLast2,\n\t49,\n\t49,\n\ttransformIdentity,\n\t15,\n\t49,\n\ttransformIdentity,\n\t16,\n\t0,\n\ttransformUppercaseFirst,\n\t49,\n\t49,\n\ttransformIdentity,\n\t12,\n\t5,\n\ttransformIdentity,\n\t49,\n\t0,\n\ttransformIdentity,\n\t1,\n\t49,\n\ttransformOmitFirst4,\n\t49,\n\t49,\n\ttransformIdentity,\n\t18,\n\t49,\n\ttransformIdentity,\n\t17,\n\t49,\n\ttransformIdentity,\n\t19,\n\t49,\n\ttransformIdentity,\n\t20,\n\t49,\n\ttransformOmitFirst5,\n\t49,\n\t49,\n\ttransformOmitFirst6,\n\t49,\n\t47,\n\ttransformIdentity,\n\t49,\n\t49,\n\ttransformOmitLast4,\n\t49,\n\t49,\n\ttransformIdentity,\n\t22,\n\t49,\n\ttransformUppercaseAll,\n\t49,\n\t49,\n\ttransformIdentity,\n\t23,\n\t49,\n\ttransformIdentity,\n\t24,\n\t49,\n\ttransformIdentity,\n\t25,\n\t49,\n\ttransformOmitLast7,\n\t49,\n\t49,\n\ttransformOmitLast1,\n\t26,\n\t49,\n\ttransformIdentity,\n\t27,\n\t49,\n\ttransformIdentity,\n\t28,\n\t0,\n\ttransformIdentity,\n\t12,\n\t49,\n\ttransformIdentity,\n\t29,\n\t49,\n\ttransformOmitFirst9,\n\t49,\n\t49,\n\ttransformOmitFirst7,\n\t49,\n\t49,\n\ttransformOmitLast6,\n\t49,\n\t49,\n\ttransformIdentity,\n\t21,\n\t49,\n\ttransformUppercaseFirst,\n\t1,\n\t49,\n\ttransformOmitLast8,\n\t49,\n\t49,\n\ttransformIdentity,\n\t31,\n\t49,\n\ttransformIdentity,\n\t32,\n\t47,\n\ttransformIdentity,\n\t3,\n\t49,\n\ttransformOmitLast5,\n\t49,\n\t49,\n\ttransformOmitLast9,\n\t49,\n\t0,\n\ttransformUppercaseFirst,\n\t1,\n\t49,\n\ttransformUppercaseFirst,\n\t8,\n\t5,\n\ttransformIdentity,\n\t21,\n\t49,\n\ttransformUppercaseAll,\n\t0,\n\t49,\n\ttransformUppercaseFirst,\n\t10,\n\t49,\n\ttransformIdentity,\n\t30,\n\t0,\n\ttransformIdentity,\n\t5,\n\t35,\n\ttransformIdentity,\n\t49,\n\t47,\n\ttransformIdentity,\n\t2,\n\t49,\n\ttransformUppercaseFirst,\n\t17,\n\t49,\n\ttransformIdentity,\n\t36,\n\t49,\n\ttransformIdentity,\n\t33,\n\t5,\n\ttransformIdentity,\n\t0,\n\t49,\n\ttransformUppercaseFirst,\n\t21,\n\t49,\n\ttransformUppercaseFirst,\n\t5,\n\t49,\n\ttransformIdentity,\n\t37,\n\t0,\n\ttransformIdentity,\n\t30,\n\t49,\n\ttransformIdentity,\n\t38,\n\t0,\n\ttransformUppercaseAll,\n\t0,\n\t49,\n\ttransformIdentity,\n\t39,\n\t0,\n\ttransformUppercaseAll,\n\t49,\n\t49,\n\ttransformIdentity,\n\t34,\n\t49,\n\ttransformUppercaseAll,\n\t8,\n\t49,\n\ttransformUppercaseFirst,\n\t12,\n\t0,\n\ttransformIdentity,\n\t21,\n\t49,\n\ttransformIdentity,\n\t40,\n\t0,\n\ttransformUppercaseFirst,\n\t12,\n\t49,\n\ttransformIdentity,\n\t41,\n\t49,\n\ttransformIdentity,\n\t42,\n\t49,\n\ttransformUppercaseAll,\n\t17,\n\t49,\n\ttransformIdentity,\n\t43,\n\t0,\n\ttransformUppercaseFirst,\n\t5,\n\t49,\n\ttransformUppercaseAll,\n\t10,\n\t0,\n\ttransformIdentity,\n\t34,\n\t49,\n\ttransformUppercaseFirst,\n\t33,\n\t49,\n\ttransformIdentity,\n\t44,\n\t49,\n\ttransformUppercaseAll,\n\t5,\n\t45,\n\ttransformIdentity,\n\t49,\n\t0,\n\ttransformIdentity,\n\t33,\n\t49,\n\ttransformUppercaseFirst,\n\t30,\n\t49,\n\ttransformUppercaseAll,\n\t30,\n\t49,\n\ttransformIdentity,\n\t46,\n\t49,\n\ttransformUppercaseAll,\n\t1,\n\t49,\n\ttransformUppercaseFirst,\n\t34,\n\t0,\n\ttransformUppercaseFirst,\n\t33,\n\t0,\n\ttransformUppercaseAll,\n\t30,\n\t0,\n\ttransformUppercaseAll,\n\t1,\n\t49,\n\ttransformUppercaseAll,\n\t33,\n\t49,\n\ttransformUppercaseAll,\n\t21,\n\t49,\n\ttransformUppercaseAll,\n\t12,\n\t0,\n\ttransformUppercaseAll,\n\t5,\n\t49,\n\ttransformUppercaseAll,\n\t34,\n\t0,\n\ttransformUppercaseAll,\n\t12,\n\t0,\n\ttransformUppercaseFirst,\n\t30,\n\t0,\n\ttransformUppercaseAll,\n\t34,\n\t0,\n\ttransformUppercaseFirst,\n\t34,\n}\n\nvar kBrotliTransforms = transforms{\n\t217,\n\t[]byte(kPrefixSuffix),\n\tkPrefixSuffixMap[:],\n\t121,\n\tkTransformsData,\n\tnil, /* no extra parameters */\n\t[transformsMaxCutOff + 1]int16{0, 12, 27, 23, 42, 63, 56, 48, 59, 64},\n}\n\nfunc getTransforms() *transforms {\n\treturn &kBrotliTransforms\n}\n\nfunc toUpperCase(p []byte) int {\n\tif p[0] < 0xC0 {\n\t\tif p[0] >= 'a' && p[0] <= 'z' {\n\t\t\tp[0] ^= 32\n\t\t}\n\n\t\treturn 1\n\t}\n\n\t/* An overly simplified uppercasing model for UTF-8. */\n\tif p[0] < 0xE0 {\n\t\tp[1] ^= 32\n\t\treturn 2\n\t}\n\n\t/* An arbitrary transform for three byte characters. */\n\tp[2] ^= 5\n\n\treturn 3\n}\n\nfunc shiftTransform(word []byte, word_len int, parameter uint16) int {\n\t/* Limited sign extension: scalar < (1 << 24). */\n\tvar scalar uint32 = (uint32(parameter) & 0x7FFF) + (0x1000000 - (uint32(parameter) & 0x8000))\n\tif word[0] < 0x80 {\n\t\t/* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */\n\t\tscalar += uint32(word[0])\n\n\t\tword[0] = byte(scalar & 0x7F)\n\t\treturn 1\n\t} else if word[0] < 0xC0 {\n\t\t/* Continuation / 10AAAAAA. */\n\t\treturn 1\n\t} else if word[0] < 0xE0 {\n\t\t/* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */\n\t\tif word_len < 2 {\n\t\t\treturn 1\n\t\t}\n\t\tscalar += uint32(word[1]&0x3F | (word[0]&0x1F)<<6)\n\t\tword[0] = byte(0xC0 | (scalar>>6)&0x1F)\n\t\tword[1] = byte(uint32(word[1]&0xC0) | scalar&0x3F)\n\t\treturn 2\n\t} else if word[0] < 0xF0 {\n\t\t/* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */\n\t\tif word_len < 3 {\n\t\t\treturn word_len\n\t\t}\n\t\tscalar += uint32(word[2])&0x3F | uint32(word[1]&0x3F)<<6 | uint32(word[0]&0x0F)<<12\n\t\tword[0] = byte(0xE0 | (scalar>>12)&0x0F)\n\t\tword[1] = byte(uint32(word[1]&0xC0) | (scalar>>6)&0x3F)\n\t\tword[2] = byte(uint32(word[2]&0xC0) | scalar&0x3F)\n\t\treturn 3\n\t} else if word[0] < 0xF8 {\n\t\t/* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */\n\t\tif word_len < 4 {\n\t\t\treturn word_len\n\t\t}\n\t\tscalar += uint32(word[3])&0x3F | uint32(word[2]&0x3F)<<6 | uint32(word[1]&0x3F)<<12 | uint32(word[0]&0x07)<<18\n\t\tword[0] = byte(0xF0 | (scalar>>18)&0x07)\n\t\tword[1] = byte(uint32(word[1]&0xC0) | (scalar>>12)&0x3F)\n\t\tword[2] = byte(uint32(word[2]&0xC0) | (scalar>>6)&0x3F)\n\t\tword[3] = byte(uint32(word[3]&0xC0) | scalar&0x3F)\n\t\treturn 4\n\t}\n\n\treturn 1\n}\n\nfunc transformDictionaryWord(dst []byte, word []byte, len int, trans *transforms, transform_idx int) int {\n\tvar idx int = 0\n\tvar prefix []byte = transformPrefix(trans, transform_idx)\n\tvar type_ byte = transformType(trans, transform_idx)\n\tvar suffix []byte = transformSuffix(trans, transform_idx)\n\t{\n\t\tvar prefix_len int = int(prefix[0])\n\t\tprefix = prefix[1:]\n\t\tfor {\n\t\t\ttmp1 := prefix_len\n\t\t\tprefix_len--\n\t\t\tif tmp1 == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdst[idx] = prefix[0]\n\t\t\tidx++\n\t\t\tprefix = prefix[1:]\n\t\t}\n\t}\n\t{\n\t\tvar t int = int(type_)\n\t\tvar i int = 0\n\t\tif t <= transformOmitLast9 {\n\t\t\tlen -= t\n\t\t} else if t >= transformOmitFirst1 && t <= transformOmitFirst9 {\n\t\t\tvar skip int = t - (transformOmitFirst1 - 1)\n\t\t\tword = word[skip:]\n\t\t\tlen -= skip\n\t\t}\n\n\t\tfor i < len {\n\t\t\tdst[idx] = word[i]\n\t\t\tidx++\n\t\t\ti++\n\t\t}\n\t\tif t == transformUppercaseFirst {\n\t\t\ttoUpperCase(dst[idx-len:])\n\t\t} else if t == transformUppercaseAll {\n\t\t\tvar uppercase []byte = dst\n\t\t\tuppercase = uppercase[idx-len:]\n\t\t\tfor len > 0 {\n\t\t\t\tvar step int = toUpperCase(uppercase)\n\t\t\t\tuppercase = uppercase[step:]\n\t\t\t\tlen -= step\n\t\t\t}\n\t\t} else if t == transformShiftFirst {\n\t\t\tvar param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8\n\t\t\tshiftTransform(dst[idx-len:], int(len), param)\n\t\t} else if t == transformShiftAll {\n\t\t\tvar param uint16 = uint16(trans.params[transform_idx*2]) + uint16(trans.params[transform_idx*2+1])<<8\n\t\t\tvar shift []byte = dst\n\t\t\tshift = shift[idx-len:]\n\t\t\tfor len > 0 {\n\t\t\t\tvar step int = shiftTransform(shift, int(len), param)\n\t\t\t\tshift = shift[step:]\n\t\t\t\tlen -= step\n\t\t\t}\n\t\t}\n\t}\n\t{\n\t\tvar suffix_len int = int(suffix[0])\n\t\tsuffix = suffix[1:]\n\t\tfor {\n\t\t\ttmp2 := suffix_len\n\t\t\tsuffix_len--\n\t\t\tif tmp2 == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tdst[idx] = suffix[0]\n\t\t\tidx++\n\t\t\tsuffix = suffix[1:]\n\t\t}\n\t\treturn idx\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/utf8_util.go",
    "content": "package brotli\n\n/* Copyright 2013 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Heuristics for deciding about the UTF8-ness of strings. */\n\nconst kMinUTF8Ratio float64 = 0.75\n\n/* Returns 1 if at least min_fraction of the bytes between pos and\n   pos + length in the (data, mask) ring-buffer is UTF8-encoded, otherwise\n   returns 0. */\nfunc parseAsUTF8(symbol *int, input []byte, size uint) uint {\n\t/* ASCII */\n\tif input[0]&0x80 == 0 {\n\t\t*symbol = int(input[0])\n\t\tif *symbol > 0 {\n\t\t\treturn 1\n\t\t}\n\t}\n\n\t/* 2-byte UTF8 */\n\tif size > 1 && input[0]&0xE0 == 0xC0 && input[1]&0xC0 == 0x80 {\n\t\t*symbol = (int(input[0])&0x1F)<<6 | int(input[1])&0x3F\n\t\tif *symbol > 0x7F {\n\t\t\treturn 2\n\t\t}\n\t}\n\n\t/* 3-byte UFT8 */\n\tif size > 2 && input[0]&0xF0 == 0xE0 && input[1]&0xC0 == 0x80 && input[2]&0xC0 == 0x80 {\n\t\t*symbol = (int(input[0])&0x0F)<<12 | (int(input[1])&0x3F)<<6 | int(input[2])&0x3F\n\t\tif *symbol > 0x7FF {\n\t\t\treturn 3\n\t\t}\n\t}\n\n\t/* 4-byte UFT8 */\n\tif size > 3 && input[0]&0xF8 == 0xF0 && input[1]&0xC0 == 0x80 && input[2]&0xC0 == 0x80 && input[3]&0xC0 == 0x80 {\n\t\t*symbol = (int(input[0])&0x07)<<18 | (int(input[1])&0x3F)<<12 | (int(input[2])&0x3F)<<6 | int(input[3])&0x3F\n\t\tif *symbol > 0xFFFF && *symbol <= 0x10FFFF {\n\t\t\treturn 4\n\t\t}\n\t}\n\n\t/* Not UTF8, emit a special symbol above the UTF8-code space */\n\t*symbol = 0x110000 | int(input[0])\n\n\treturn 1\n}\n\n/* Returns 1 if at least min_fraction of the data is UTF8-encoded.*/\nfunc isMostlyUTF8(data []byte, pos uint, mask uint, length uint, min_fraction float64) bool {\n\tvar size_utf8 uint = 0\n\tvar i uint = 0\n\tfor i < length {\n\t\tvar symbol int\n\t\tcurrent_data := data[(pos+i)&mask:]\n\t\tvar bytes_read uint = parseAsUTF8(&symbol, current_data, length-i)\n\t\ti += bytes_read\n\t\tif symbol < 0x110000 {\n\t\t\tsize_utf8 += bytes_read\n\t\t}\n\t}\n\n\treturn float64(size_utf8) > min_fraction*float64(length)\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/util.go",
    "content": "package brotli\n\nfunc assert(cond bool) {\n\tif !cond {\n\t\tpanic(\"assertion failure\")\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/write_bits.go",
    "content": "package brotli\n\nimport \"encoding/binary\"\n\n/* Copyright 2010 Google Inc. All Rights Reserved.\n\n   Distributed under MIT license.\n   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT\n*/\n\n/* Write bits into a byte array. */\n\n/* This function writes bits into bytes in increasing addresses, and within\n   a byte least-significant-bit first.\n\n   The function can write up to 56 bits in one go with WriteBits\n   Example: let's assume that 3 bits (Rs below) have been written already:\n\n   BYTE-0     BYTE+1       BYTE+2\n\n   0000 0RRR    0000 0000    0000 0000\n\n   Now, we could write 5 or less bits in MSB by just sifting by 3\n   and OR'ing to BYTE-0.\n\n   For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,\n   and locate the rest in BYTE+1, BYTE+2, etc. */\nfunc writeBits(n_bits uint, bits uint64, pos *uint, array []byte) {\n\t/* This branch of the code can write up to 56 bits at a time,\n\t   7 bits are lost by being perhaps already in *p and at least\n\t   1 bit is needed to initialize the bit-stream ahead (i.e. if 7\n\t   bits are in *p and we write 57 bits, then the next write will\n\t   access a byte that was never initialized). */\n\tp := array[*pos>>3:]\n\tv := uint64(p[0])\n\tv |= bits << (*pos & 7)\n\tbinary.LittleEndian.PutUint64(p, v)\n\t*pos += n_bits\n}\n\nfunc writeSingleBit(bit bool, pos *uint, array []byte) {\n\tif bit {\n\t\twriteBits(1, 1, pos, array)\n\t} else {\n\t\twriteBits(1, 0, pos, array)\n\t}\n}\n\nfunc writeBitsPrepareStorage(pos uint, array []byte) {\n\tassert(pos&7 == 0)\n\tarray[pos>>3] = 0\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/brotli/writer.go",
    "content": "package brotli\n\nimport (\n\t\"errors\"\n\t\"io\"\n\n\t\"github.com/andybalholm/brotli/matchfinder\"\n)\n\nconst (\n\tBestSpeed          = 0\n\tBestCompression    = 11\n\tDefaultCompression = 6\n)\n\n// WriterOptions configures Writer.\ntype WriterOptions struct {\n\t// Quality controls the compression-speed vs compression-density trade-offs.\n\t// The higher the quality, the slower the compression. Range is 0 to 11.\n\tQuality int\n\t// LGWin is the base 2 logarithm of the sliding window size.\n\t// Range is 10 to 24. 0 indicates automatic configuration based on Quality.\n\tLGWin int\n}\n\nvar (\n\terrEncode       = errors.New(\"brotli: encode error\")\n\terrWriterClosed = errors.New(\"brotli: Writer is closed\")\n)\n\n// Writes to the returned writer are compressed and written to dst.\n// It is the caller's responsibility to call Close on the Writer when done.\n// Writes may be buffered and not flushed until Close.\nfunc NewWriter(dst io.Writer) *Writer {\n\treturn NewWriterLevel(dst, DefaultCompression)\n}\n\n// NewWriterLevel is like NewWriter but specifies the compression level instead\n// of assuming DefaultCompression.\n// The compression level can be DefaultCompression or any integer value between\n// BestSpeed and BestCompression inclusive.\nfunc NewWriterLevel(dst io.Writer, level int) *Writer {\n\treturn NewWriterOptions(dst, WriterOptions{\n\t\tQuality: level,\n\t})\n}\n\n// NewWriterOptions is like NewWriter but specifies WriterOptions\nfunc NewWriterOptions(dst io.Writer, options WriterOptions) *Writer {\n\tw := new(Writer)\n\tw.options = options\n\tw.Reset(dst)\n\treturn w\n}\n\n// Reset discards the Writer's state and makes it equivalent to the result of\n// its original state from NewWriter or NewWriterLevel, but writing to dst\n// instead. This permits reusing a Writer rather than allocating a new one.\nfunc (w *Writer) Reset(dst io.Writer) {\n\tencoderInitState(w)\n\tw.params.quality = w.options.Quality\n\tif w.options.LGWin > 0 {\n\t\tw.params.lgwin = uint(w.options.LGWin)\n\t}\n\tw.dst = dst\n\tw.err = nil\n}\n\nfunc (w *Writer) writeChunk(p []byte, op int) (n int, err error) {\n\tif w.dst == nil {\n\t\treturn 0, errWriterClosed\n\t}\n\tif w.err != nil {\n\t\treturn 0, w.err\n\t}\n\n\tfor {\n\t\tavailableIn := uint(len(p))\n\t\tnextIn := p\n\t\tsuccess := encoderCompressStream(w, op, &availableIn, &nextIn)\n\t\tbytesConsumed := len(p) - int(availableIn)\n\t\tp = p[bytesConsumed:]\n\t\tn += bytesConsumed\n\t\tif !success {\n\t\t\treturn n, errEncode\n\t\t}\n\n\t\tif len(p) == 0 || w.err != nil {\n\t\t\treturn n, w.err\n\t\t}\n\t}\n}\n\n// Flush outputs encoded data for all input provided to Write. The resulting\n// output can be decoded to match all input before Flush, but the stream is\n// not yet complete until after Close.\n// Flush has a negative impact on compression.\nfunc (w *Writer) Flush() error {\n\t_, err := w.writeChunk(nil, operationFlush)\n\treturn err\n}\n\n// Close flushes remaining data to the decorated writer.\nfunc (w *Writer) Close() error {\n\t// If stream is already closed, it is reported by `writeChunk`.\n\t_, err := w.writeChunk(nil, operationFinish)\n\tw.dst = nil\n\treturn err\n}\n\n// Write implements io.Writer. Flush or Close must be called to ensure that the\n// encoded bytes are actually flushed to the underlying Writer.\nfunc (w *Writer) Write(p []byte) (n int, err error) {\n\treturn w.writeChunk(p, operationProcess)\n}\n\ntype nopCloser struct {\n\tio.Writer\n}\n\nfunc (nopCloser) Close() error { return nil }\n\n// NewWriterV2 is like NewWriterLevel, but it uses the new implementation\n// based on the matchfinder package. It currently supports up to level 9;\n// if a higher level is specified, level 9 will be used.\nfunc NewWriterV2(dst io.Writer, level int) *matchfinder.Writer {\n\tvar mf matchfinder.MatchFinder\n\tif level < 2 {\n\t\tmf = matchfinder.M0{Lazy: level == 1}\n\t} else if level < 8 {\n\t\thashLen := 6\n\t\tif level >= 6 {\n\t\t\thashLen = 5\n\t\t}\n\t\tchainLen := 16\n\t\tswitch level {\n\t\tcase 2:\n\t\t\tchainLen = 0\n\t\tcase 3:\n\t\t\tchainLen = 1\n\t\tcase 4:\n\t\t\tchainLen = 2\n\t\tcase 5:\n\t\t\tchainLen = 4\n\t\tcase 6:\n\t\t\tchainLen = 8\n\t\t}\n\t\tmf = &matchfinder.M4{\n\t\t\tMaxDistance:     1 << 20,\n\t\t\tChainLength:     chainLen,\n\t\t\tHashLen:         hashLen,\n\t\t\tDistanceBitCost: 66,\n\t\t}\n\t} else {\n\t\tchainLen := 32\n\t\thashLen := 5\n\t\tif level == 8 {\n\t\t\tchainLen = 4\n\t\t\thashLen = 6\n\t\t}\n\t\tmf = &matchfinder.Pathfinder{\n\t\t\tMaxDistance: 1 << 20,\n\t\t\tChainLength: chainLen,\n\t\t\tHashLen:     hashLen,\n\t\t}\n\t}\n\n\treturn &matchfinder.Writer{\n\t\tDest:        dst,\n\t\tMatchFinder: mf,\n\t\tEncoder:     &Encoder{},\n\t\tBlockSize:   1 << 16,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/cascadia/LICENSE",
    "content": "Copyright (c) 2011 Andy Balholm. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "vendor/github.com/andybalholm/cascadia/parser.go",
    "content": "// Package cascadia is an implementation of CSS selectors.\npackage cascadia\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// a parser for CSS selectors\ntype parser struct {\n\ts string // the source text\n\ti int    // the current position\n\n\t// if `false`, parsing a pseudo-element\n\t// returns an error.\n\tacceptPseudoElements bool\n}\n\n// parseEscape parses a backslash escape.\nfunc (p *parser) parseEscape() (result string, err error) {\n\tif len(p.s) < p.i+2 || p.s[p.i] != '\\\\' {\n\t\treturn \"\", errors.New(\"invalid escape sequence\")\n\t}\n\n\tstart := p.i + 1\n\tc := p.s[start]\n\tswitch {\n\tcase c == '\\r' || c == '\\n' || c == '\\f':\n\t\treturn \"\", errors.New(\"escaped line ending outside string\")\n\tcase hexDigit(c):\n\t\t// unicode escape (hex)\n\t\tvar i int\n\t\tfor i = start; i < start+6 && i < len(p.s) && hexDigit(p.s[i]); i++ {\n\t\t\t// empty\n\t\t}\n\t\tv, _ := strconv.ParseUint(p.s[start:i], 16, 64)\n\t\tif len(p.s) > i {\n\t\t\tswitch p.s[i] {\n\t\t\tcase '\\r':\n\t\t\t\ti++\n\t\t\t\tif len(p.s) > i && p.s[i] == '\\n' {\n\t\t\t\t\ti++\n\t\t\t\t}\n\t\t\tcase ' ', '\\t', '\\n', '\\f':\n\t\t\t\ti++\n\t\t\t}\n\t\t}\n\t\tp.i = i\n\t\treturn string(rune(v)), nil\n\t}\n\n\t// Return the literal character after the backslash.\n\tresult = p.s[start : start+1]\n\tp.i += 2\n\treturn result, nil\n}\n\n// toLowerASCII returns s with all ASCII capital letters lowercased.\nfunc toLowerASCII(s string) string {\n\tvar b []byte\n\tfor i := 0; i < len(s); i++ {\n\t\tif c := s[i]; 'A' <= c && c <= 'Z' {\n\t\t\tif b == nil {\n\t\t\t\tb = make([]byte, len(s))\n\t\t\t\tcopy(b, s)\n\t\t\t}\n\t\t\tb[i] = s[i] + ('a' - 'A')\n\t\t}\n\t}\n\n\tif b == nil {\n\t\treturn s\n\t}\n\n\treturn string(b)\n}\n\nfunc hexDigit(c byte) bool {\n\treturn '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F'\n}\n\n// nameStart returns whether c can be the first character of an identifier\n// (not counting an initial hyphen, or an escape sequence).\nfunc nameStart(c byte) bool {\n\treturn 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c > 127\n}\n\n// nameChar returns whether c can be a character within an identifier\n// (not counting an escape sequence).\nfunc nameChar(c byte) bool {\n\treturn 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_' || c > 127 ||\n\t\tc == '-' || '0' <= c && c <= '9'\n}\n\n// parseIdentifier parses an identifier.\nfunc (p *parser) parseIdentifier() (result string, err error) {\n\tconst prefix = '-'\n\tvar numPrefix int\n\n\tfor len(p.s) > p.i && p.s[p.i] == prefix {\n\t\tp.i++\n\t\tnumPrefix++\n\t}\n\n\tif len(p.s) <= p.i {\n\t\treturn \"\", errors.New(\"expected identifier, found EOF instead\")\n\t}\n\n\tif c := p.s[p.i]; !(nameStart(c) || c == '\\\\') {\n\t\treturn \"\", fmt.Errorf(\"expected identifier, found %c instead\", c)\n\t}\n\n\tresult, err = p.parseName()\n\tif numPrefix > 0 && err == nil {\n\t\tresult = strings.Repeat(string(prefix), numPrefix) + result\n\t}\n\treturn\n}\n\n// parseName parses a name (which is like an identifier, but doesn't have\n// extra restrictions on the first character).\nfunc (p *parser) parseName() (result string, err error) {\n\ti := p.i\nloop:\n\tfor i < len(p.s) {\n\t\tc := p.s[i]\n\t\tswitch {\n\t\tcase nameChar(c):\n\t\t\tstart := i\n\t\t\tfor i < len(p.s) && nameChar(p.s[i]) {\n\t\t\t\ti++\n\t\t\t}\n\t\t\tresult += p.s[start:i]\n\t\tcase c == '\\\\':\n\t\t\tp.i = i\n\t\t\tval, err := p.parseEscape()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\ti = p.i\n\t\t\tresult += val\n\t\tdefault:\n\t\t\tbreak loop\n\t\t}\n\t}\n\n\tif result == \"\" {\n\t\treturn \"\", errors.New(\"expected name, found EOF instead\")\n\t}\n\n\tp.i = i\n\treturn result, nil\n}\n\n// parseString parses a single- or double-quoted string.\nfunc (p *parser) parseString() (result string, err error) {\n\ti := p.i\n\tif len(p.s) < i+2 {\n\t\treturn \"\", errors.New(\"expected string, found EOF instead\")\n\t}\n\n\tquote := p.s[i]\n\ti++\n\nloop:\n\tfor i < len(p.s) {\n\t\tswitch p.s[i] {\n\t\tcase '\\\\':\n\t\t\tif len(p.s) > i+1 {\n\t\t\t\tswitch c := p.s[i+1]; c {\n\t\t\t\tcase '\\r':\n\t\t\t\t\tif len(p.s) > i+2 && p.s[i+2] == '\\n' {\n\t\t\t\t\t\ti += 3\n\t\t\t\t\t\tcontinue loop\n\t\t\t\t\t}\n\t\t\t\t\tfallthrough\n\t\t\t\tcase '\\n', '\\f':\n\t\t\t\t\ti += 2\n\t\t\t\t\tcontinue loop\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.i = i\n\t\t\tval, err := p.parseEscape()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\ti = p.i\n\t\t\tresult += val\n\t\tcase quote:\n\t\t\tbreak loop\n\t\tcase '\\r', '\\n', '\\f':\n\t\t\treturn \"\", errors.New(\"unexpected end of line in string\")\n\t\tdefault:\n\t\t\tstart := i\n\t\t\tfor i < len(p.s) {\n\t\t\t\tif c := p.s[i]; c == quote || c == '\\\\' || c == '\\r' || c == '\\n' || c == '\\f' {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ti++\n\t\t\t}\n\t\t\tresult += p.s[start:i]\n\t\t}\n\t}\n\n\tif i >= len(p.s) {\n\t\treturn \"\", errors.New(\"EOF in string\")\n\t}\n\n\t// Consume the final quote.\n\ti++\n\n\tp.i = i\n\treturn result, nil\n}\n\n// parseRegex parses a regular expression; the end is defined by encountering an\n// unmatched closing ')' or ']' which is not consumed\nfunc (p *parser) parseRegex() (rx *regexp.Regexp, err error) {\n\ti := p.i\n\tif len(p.s) < i+2 {\n\t\treturn nil, errors.New(\"expected regular expression, found EOF instead\")\n\t}\n\n\t// number of open parens or brackets;\n\t// when it becomes negative, finished parsing regex\n\topen := 0\n\nloop:\n\tfor i < len(p.s) {\n\t\tswitch p.s[i] {\n\t\tcase '(', '[':\n\t\t\topen++\n\t\tcase ')', ']':\n\t\t\topen--\n\t\t\tif open < 0 {\n\t\t\t\tbreak loop\n\t\t\t}\n\t\t}\n\t\ti++\n\t}\n\n\tif i >= len(p.s) {\n\t\treturn nil, errors.New(\"EOF in regular expression\")\n\t}\n\trx, err = regexp.Compile(p.s[p.i:i])\n\tp.i = i\n\treturn rx, err\n}\n\n// skipWhitespace consumes whitespace characters and comments.\n// It returns true if there was actually anything to skip.\nfunc (p *parser) skipWhitespace() bool {\n\ti := p.i\n\tfor i < len(p.s) {\n\t\tswitch p.s[i] {\n\t\tcase ' ', '\\t', '\\r', '\\n', '\\f':\n\t\t\ti++\n\t\t\tcontinue\n\t\tcase '/':\n\t\t\tif strings.HasPrefix(p.s[i:], \"/*\") {\n\t\t\t\tend := strings.Index(p.s[i+len(\"/*\"):], \"*/\")\n\t\t\t\tif end != -1 {\n\t\t\t\t\ti += end + len(\"/**/\")\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak\n\t}\n\n\tif i > p.i {\n\t\tp.i = i\n\t\treturn true\n\t}\n\n\treturn false\n}\n\n// consumeParenthesis consumes an opening parenthesis and any following\n// whitespace. It returns true if there was actually a parenthesis to skip.\nfunc (p *parser) consumeParenthesis() bool {\n\tif p.i < len(p.s) && p.s[p.i] == '(' {\n\t\tp.i++\n\t\tp.skipWhitespace()\n\t\treturn true\n\t}\n\treturn false\n}\n\n// consumeClosingParenthesis consumes a closing parenthesis and any preceding\n// whitespace. It returns true if there was actually a parenthesis to skip.\nfunc (p *parser) consumeClosingParenthesis() bool {\n\ti := p.i\n\tp.skipWhitespace()\n\tif p.i < len(p.s) && p.s[p.i] == ')' {\n\t\tp.i++\n\t\treturn true\n\t}\n\tp.i = i\n\treturn false\n}\n\n// parseTypeSelector parses a type selector (one that matches by tag name).\nfunc (p *parser) parseTypeSelector() (result tagSelector, err error) {\n\ttag, err := p.parseIdentifier()\n\tif err != nil {\n\t\treturn\n\t}\n\treturn tagSelector{tag: toLowerASCII(tag)}, nil\n}\n\n// parseIDSelector parses a selector that matches by id attribute.\nfunc (p *parser) parseIDSelector() (idSelector, error) {\n\tif p.i >= len(p.s) {\n\t\treturn idSelector{}, fmt.Errorf(\"expected id selector (#id), found EOF instead\")\n\t}\n\tif p.s[p.i] != '#' {\n\t\treturn idSelector{}, fmt.Errorf(\"expected id selector (#id), found '%c' instead\", p.s[p.i])\n\t}\n\n\tp.i++\n\tid, err := p.parseName()\n\tif err != nil {\n\t\treturn idSelector{}, err\n\t}\n\n\treturn idSelector{id: id}, nil\n}\n\n// parseClassSelector parses a selector that matches by class attribute.\nfunc (p *parser) parseClassSelector() (classSelector, error) {\n\tif p.i >= len(p.s) {\n\t\treturn classSelector{}, fmt.Errorf(\"expected class selector (.class), found EOF instead\")\n\t}\n\tif p.s[p.i] != '.' {\n\t\treturn classSelector{}, fmt.Errorf(\"expected class selector (.class), found '%c' instead\", p.s[p.i])\n\t}\n\n\tp.i++\n\tclass, err := p.parseIdentifier()\n\tif err != nil {\n\t\treturn classSelector{}, err\n\t}\n\n\treturn classSelector{class: class}, nil\n}\n\n// parseAttributeSelector parses a selector that matches by attribute value.\nfunc (p *parser) parseAttributeSelector() (attrSelector, error) {\n\tif p.i >= len(p.s) {\n\t\treturn attrSelector{}, fmt.Errorf(\"expected attribute selector ([attribute]), found EOF instead\")\n\t}\n\tif p.s[p.i] != '[' {\n\t\treturn attrSelector{}, fmt.Errorf(\"expected attribute selector ([attribute]), found '%c' instead\", p.s[p.i])\n\t}\n\n\tp.i++\n\tp.skipWhitespace()\n\tkey, err := p.parseIdentifier()\n\tif err != nil {\n\t\treturn attrSelector{}, err\n\t}\n\tkey = toLowerASCII(key)\n\n\tp.skipWhitespace()\n\tif p.i >= len(p.s) {\n\t\treturn attrSelector{}, errors.New(\"unexpected EOF in attribute selector\")\n\t}\n\n\tif p.s[p.i] == ']' {\n\t\tp.i++\n\t\treturn attrSelector{key: key, operation: \"\"}, nil\n\t}\n\n\tif p.i+2 >= len(p.s) {\n\t\treturn attrSelector{}, errors.New(\"unexpected EOF in attribute selector\")\n\t}\n\n\top := p.s[p.i : p.i+2]\n\tif op[0] == '=' {\n\t\top = \"=\"\n\t} else if op[1] != '=' {\n\t\treturn attrSelector{}, fmt.Errorf(`expected equality operator, found \"%s\" instead`, op)\n\t}\n\tp.i += len(op)\n\n\tp.skipWhitespace()\n\tif p.i >= len(p.s) {\n\t\treturn attrSelector{}, errors.New(\"unexpected EOF in attribute selector\")\n\t}\n\tvar val string\n\tvar rx *regexp.Regexp\n\tif op == \"#=\" {\n\t\trx, err = p.parseRegex()\n\t} else {\n\t\tswitch p.s[p.i] {\n\t\tcase '\\'', '\"':\n\t\t\tval, err = p.parseString()\n\t\tdefault:\n\t\t\tval, err = p.parseIdentifier()\n\t\t}\n\t}\n\tif err != nil {\n\t\treturn attrSelector{}, err\n\t}\n\n\tp.skipWhitespace()\n\tif p.i >= len(p.s) {\n\t\treturn attrSelector{}, errors.New(\"unexpected EOF in attribute selector\")\n\t}\n\n\t// check if the attribute contains an ignore case flag\n\tignoreCase := false\n\tif p.s[p.i] == 'i' || p.s[p.i] == 'I' {\n\t\tignoreCase = true\n\t\tp.i++\n\t}\n\n\tp.skipWhitespace()\n\tif p.i >= len(p.s) {\n\t\treturn attrSelector{}, errors.New(\"unexpected EOF in attribute selector\")\n\t}\n\n\tif p.s[p.i] != ']' {\n\t\treturn attrSelector{}, fmt.Errorf(\"expected ']', found '%c' instead\", p.s[p.i])\n\t}\n\tp.i++\n\n\tswitch op {\n\tcase \"=\", \"!=\", \"~=\", \"|=\", \"^=\", \"$=\", \"*=\", \"#=\":\n\t\treturn attrSelector{key: key, val: val, operation: op, regexp: rx, insensitive: ignoreCase}, nil\n\tdefault:\n\t\treturn attrSelector{}, fmt.Errorf(\"attribute operator %q is not supported\", op)\n\t}\n}\n\nvar (\n\terrExpectedParenthesis        = errors.New(\"expected '(' but didn't find it\")\n\terrExpectedClosingParenthesis = errors.New(\"expected ')' but didn't find it\")\n\terrUnmatchedParenthesis       = errors.New(\"unmatched '('\")\n)\n\n// parsePseudoclassSelector parses a pseudoclass selector like :not(p) or a pseudo-element\n// For backwards compatibility, both ':' and '::' prefix are allowed for pseudo-elements.\n// https://drafts.csswg.org/selectors-3/#pseudo-elements\n// Returning a nil `Sel` (and a nil `error`) means we found a pseudo-element.\nfunc (p *parser) parsePseudoclassSelector() (out Sel, pseudoElement string, err error) {\n\tif p.i >= len(p.s) {\n\t\treturn nil, \"\", fmt.Errorf(\"expected pseudoclass selector (:pseudoclass), found EOF instead\")\n\t}\n\tif p.s[p.i] != ':' {\n\t\treturn nil, \"\", fmt.Errorf(\"expected attribute selector (:pseudoclass), found '%c' instead\", p.s[p.i])\n\t}\n\n\tp.i++\n\tvar mustBePseudoElement bool\n\tif p.i >= len(p.s) {\n\t\treturn nil, \"\", fmt.Errorf(\"got empty pseudoclass (or pseudoelement)\")\n\t}\n\tif p.s[p.i] == ':' { // we found a pseudo-element\n\t\tmustBePseudoElement = true\n\t\tp.i++\n\t}\n\n\tname, err := p.parseIdentifier()\n\tif err != nil {\n\t\treturn\n\t}\n\tname = toLowerASCII(name)\n\tif mustBePseudoElement && (name != \"after\" && name != \"backdrop\" && name != \"before\" &&\n\t\tname != \"cue\" && name != \"first-letter\" && name != \"first-line\" && name != \"grammar-error\" &&\n\t\tname != \"marker\" && name != \"placeholder\" && name != \"selection\" && name != \"spelling-error\") {\n\t\treturn out, \"\", fmt.Errorf(\"unknown pseudoelement :%s\", name)\n\t}\n\n\tswitch name {\n\tcase \"not\", \"has\", \"haschild\":\n\t\tif !p.consumeParenthesis() {\n\t\t\treturn out, \"\", errExpectedParenthesis\n\t\t}\n\t\tsel, parseErr := p.parseSelectorGroup()\n\t\tif parseErr != nil {\n\t\t\treturn out, \"\", parseErr\n\t\t}\n\t\tif !p.consumeClosingParenthesis() {\n\t\t\treturn out, \"\", errExpectedClosingParenthesis\n\t\t}\n\n\t\tout = relativePseudoClassSelector{name: name, match: sel}\n\n\tcase \"contains\", \"containsown\":\n\t\tif !p.consumeParenthesis() {\n\t\t\treturn out, \"\", errExpectedParenthesis\n\t\t}\n\t\tif p.i == len(p.s) {\n\t\t\treturn out, \"\", errUnmatchedParenthesis\n\t\t}\n\t\tvar val string\n\t\tswitch p.s[p.i] {\n\t\tcase '\\'', '\"':\n\t\t\tval, err = p.parseString()\n\t\tdefault:\n\t\t\tval, err = p.parseIdentifier()\n\t\t}\n\t\tif err != nil {\n\t\t\treturn out, \"\", err\n\t\t}\n\t\tval = strings.ToLower(val)\n\t\tp.skipWhitespace()\n\t\tif p.i >= len(p.s) {\n\t\t\treturn out, \"\", errors.New(\"unexpected EOF in pseudo selector\")\n\t\t}\n\t\tif !p.consumeClosingParenthesis() {\n\t\t\treturn out, \"\", errExpectedClosingParenthesis\n\t\t}\n\n\t\tout = containsPseudoClassSelector{own: name == \"containsown\", value: val}\n\n\tcase \"matches\", \"matchesown\":\n\t\tif !p.consumeParenthesis() {\n\t\t\treturn out, \"\", errExpectedParenthesis\n\t\t}\n\t\trx, err := p.parseRegex()\n\t\tif err != nil {\n\t\t\treturn out, \"\", err\n\t\t}\n\t\tif p.i >= len(p.s) {\n\t\t\treturn out, \"\", errors.New(\"unexpected EOF in pseudo selector\")\n\t\t}\n\t\tif !p.consumeClosingParenthesis() {\n\t\t\treturn out, \"\", errExpectedClosingParenthesis\n\t\t}\n\n\t\tout = regexpPseudoClassSelector{own: name == \"matchesown\", regexp: rx}\n\n\tcase \"nth-child\", \"nth-last-child\", \"nth-of-type\", \"nth-last-of-type\":\n\t\tif !p.consumeParenthesis() {\n\t\t\treturn out, \"\", errExpectedParenthesis\n\t\t}\n\t\ta, b, err := p.parseNth()\n\t\tif err != nil {\n\t\t\treturn out, \"\", err\n\t\t}\n\t\tif !p.consumeClosingParenthesis() {\n\t\t\treturn out, \"\", errExpectedClosingParenthesis\n\t\t}\n\t\tlast := name == \"nth-last-child\" || name == \"nth-last-of-type\"\n\t\tofType := name == \"nth-of-type\" || name == \"nth-last-of-type\"\n\t\tout = nthPseudoClassSelector{a: a, b: b, last: last, ofType: ofType}\n\n\tcase \"first-child\":\n\t\tout = nthPseudoClassSelector{a: 0, b: 1, ofType: false, last: false}\n\tcase \"last-child\":\n\t\tout = nthPseudoClassSelector{a: 0, b: 1, ofType: false, last: true}\n\tcase \"first-of-type\":\n\t\tout = nthPseudoClassSelector{a: 0, b: 1, ofType: true, last: false}\n\tcase \"last-of-type\":\n\t\tout = nthPseudoClassSelector{a: 0, b: 1, ofType: true, last: true}\n\tcase \"only-child\":\n\t\tout = onlyChildPseudoClassSelector{ofType: false}\n\tcase \"only-of-type\":\n\t\tout = onlyChildPseudoClassSelector{ofType: true}\n\tcase \"input\":\n\t\tout = inputPseudoClassSelector{}\n\tcase \"empty\":\n\t\tout = emptyElementPseudoClassSelector{}\n\tcase \"root\":\n\t\tout = rootPseudoClassSelector{}\n\tcase \"link\":\n\t\tout = linkPseudoClassSelector{}\n\tcase \"lang\":\n\t\tif !p.consumeParenthesis() {\n\t\t\treturn out, \"\", errExpectedParenthesis\n\t\t}\n\t\tif p.i == len(p.s) {\n\t\t\treturn out, \"\", errUnmatchedParenthesis\n\t\t}\n\t\tval, err := p.parseIdentifier()\n\t\tif err != nil {\n\t\t\treturn out, \"\", err\n\t\t}\n\t\tval = strings.ToLower(val)\n\t\tp.skipWhitespace()\n\t\tif p.i >= len(p.s) {\n\t\t\treturn out, \"\", errors.New(\"unexpected EOF in pseudo selector\")\n\t\t}\n\t\tif !p.consumeClosingParenthesis() {\n\t\t\treturn out, \"\", errExpectedClosingParenthesis\n\t\t}\n\t\tout = langPseudoClassSelector{lang: val}\n\tcase \"enabled\":\n\t\tout = enabledPseudoClassSelector{}\n\tcase \"disabled\":\n\t\tout = disabledPseudoClassSelector{}\n\tcase \"checked\":\n\t\tout = checkedPseudoClassSelector{}\n\tcase \"visited\", \"hover\", \"active\", \"focus\", \"target\":\n\t\t// Not applicable in a static context: never match.\n\t\tout = neverMatchSelector{value: \":\" + name}\n\tcase \"after\", \"backdrop\", \"before\", \"cue\", \"first-letter\", \"first-line\", \"grammar-error\", \"marker\", \"placeholder\", \"selection\", \"spelling-error\":\n\t\treturn nil, name, nil\n\tdefault:\n\t\treturn out, \"\", fmt.Errorf(\"unknown pseudoclass or pseudoelement :%s\", name)\n\t}\n\treturn\n}\n\n// parseInteger parses a  decimal integer.\nfunc (p *parser) parseInteger() (int, error) {\n\ti := p.i\n\tstart := i\n\tfor i < len(p.s) && '0' <= p.s[i] && p.s[i] <= '9' {\n\t\ti++\n\t}\n\tif i == start {\n\t\treturn 0, errors.New(\"expected integer, but didn't find it\")\n\t}\n\tp.i = i\n\n\tval, err := strconv.Atoi(p.s[start:i])\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn val, nil\n}\n\n// parseNth parses the argument for :nth-child (normally of the form an+b).\nfunc (p *parser) parseNth() (a, b int, err error) {\n\t// initial state\n\tif p.i >= len(p.s) {\n\t\tgoto eof\n\t}\n\tswitch p.s[p.i] {\n\tcase '-':\n\t\tp.i++\n\t\tgoto negativeA\n\tcase '+':\n\t\tp.i++\n\t\tgoto positiveA\n\tcase '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':\n\t\tgoto positiveA\n\tcase 'n', 'N':\n\t\ta = 1\n\t\tp.i++\n\t\tgoto readN\n\tcase 'o', 'O', 'e', 'E':\n\t\tid, nameErr := p.parseName()\n\t\tif nameErr != nil {\n\t\t\treturn 0, 0, nameErr\n\t\t}\n\t\tid = toLowerASCII(id)\n\t\tif id == \"odd\" {\n\t\t\treturn 2, 1, nil\n\t\t}\n\t\tif id == \"even\" {\n\t\t\treturn 2, 0, nil\n\t\t}\n\t\treturn 0, 0, fmt.Errorf(\"expected 'odd' or 'even', but found '%s' instead\", id)\n\tdefault:\n\t\tgoto invalid\n\t}\n\npositiveA:\n\tif p.i >= len(p.s) {\n\t\tgoto eof\n\t}\n\tswitch p.s[p.i] {\n\tcase '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':\n\t\ta, err = p.parseInteger()\n\t\tif err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\tgoto readA\n\tcase 'n', 'N':\n\t\ta = 1\n\t\tp.i++\n\t\tgoto readN\n\tdefault:\n\t\tgoto invalid\n\t}\n\nnegativeA:\n\tif p.i >= len(p.s) {\n\t\tgoto eof\n\t}\n\tswitch p.s[p.i] {\n\tcase '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':\n\t\ta, err = p.parseInteger()\n\t\tif err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\ta = -a\n\t\tgoto readA\n\tcase 'n', 'N':\n\t\ta = -1\n\t\tp.i++\n\t\tgoto readN\n\tdefault:\n\t\tgoto invalid\n\t}\n\nreadA:\n\tif p.i >= len(p.s) {\n\t\tgoto eof\n\t}\n\tswitch p.s[p.i] {\n\tcase 'n', 'N':\n\t\tp.i++\n\t\tgoto readN\n\tdefault:\n\t\t// The number we read as a is actually b.\n\t\treturn 0, a, nil\n\t}\n\nreadN:\n\tp.skipWhitespace()\n\tif p.i >= len(p.s) {\n\t\tgoto eof\n\t}\n\tswitch p.s[p.i] {\n\tcase '+':\n\t\tp.i++\n\t\tp.skipWhitespace()\n\t\tb, err = p.parseInteger()\n\t\tif err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\treturn a, b, nil\n\tcase '-':\n\t\tp.i++\n\t\tp.skipWhitespace()\n\t\tb, err = p.parseInteger()\n\t\tif err != nil {\n\t\t\treturn 0, 0, err\n\t\t}\n\t\treturn a, -b, nil\n\tdefault:\n\t\treturn a, 0, nil\n\t}\n\neof:\n\treturn 0, 0, errors.New(\"unexpected EOF while attempting to parse expression of form an+b\")\n\ninvalid:\n\treturn 0, 0, errors.New(\"unexpected character while attempting to parse expression of form an+b\")\n}\n\n// parseSimpleSelectorSequence parses a selector sequence that applies to\n// a single element.\nfunc (p *parser) parseSimpleSelectorSequence() (Sel, error) {\n\tvar selectors []Sel\n\n\tif p.i >= len(p.s) {\n\t\treturn nil, errors.New(\"expected selector, found EOF instead\")\n\t}\n\n\tswitch p.s[p.i] {\n\tcase '*':\n\t\t// It's the universal selector. Just skip over it, since it doesn't affect the meaning.\n\t\tp.i++\n\t\tif p.i+2 < len(p.s) && p.s[p.i:p.i+2] == \"|*\" { // other version of universal selector\n\t\t\tp.i += 2\n\t\t}\n\tcase '#', '.', '[', ':':\n\t\t// There's no type selector. Wait to process the other till the main loop.\n\tdefault:\n\t\tr, err := p.parseTypeSelector()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tselectors = append(selectors, r)\n\t}\n\n\tvar pseudoElement string\nloop:\n\tfor p.i < len(p.s) {\n\t\tvar (\n\t\t\tns               Sel\n\t\t\tnewPseudoElement string\n\t\t\terr              error\n\t\t)\n\t\tswitch p.s[p.i] {\n\t\tcase '#':\n\t\t\tns, err = p.parseIDSelector()\n\t\tcase '.':\n\t\t\tns, err = p.parseClassSelector()\n\t\tcase '[':\n\t\t\tns, err = p.parseAttributeSelector()\n\t\tcase ':':\n\t\t\tns, newPseudoElement, err = p.parsePseudoclassSelector()\n\t\tdefault:\n\t\t\tbreak loop\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\t// From https://drafts.csswg.org/selectors-3/#pseudo-elements :\n\t\t// \"Only one pseudo-element may appear per selector, and if present\n\t\t// it must appear after the sequence of simple selectors that\n\t\t// represents the subjects of the selector.\"\"\n\t\tif ns == nil { // we found a pseudo-element\n\t\t\tif pseudoElement != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"only one pseudo-element is accepted per selector, got %s and %s\", pseudoElement, newPseudoElement)\n\t\t\t}\n\t\t\tif !p.acceptPseudoElements {\n\t\t\t\treturn nil, fmt.Errorf(\"pseudo-element %s found, but pseudo-elements support is disabled\", newPseudoElement)\n\t\t\t}\n\t\t\tpseudoElement = newPseudoElement\n\t\t} else {\n\t\t\tif pseudoElement != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"pseudo-element %s must be at the end of selector\", pseudoElement)\n\t\t\t}\n\t\t\tselectors = append(selectors, ns)\n\t\t}\n\n\t}\n\tif len(selectors) == 1 && pseudoElement == \"\" { // no need wrap the selectors in compoundSelector\n\t\treturn selectors[0], nil\n\t}\n\treturn compoundSelector{selectors: selectors, pseudoElement: pseudoElement}, nil\n}\n\n// parseSelector parses a selector that may include combinators.\nfunc (p *parser) parseSelector() (Sel, error) {\n\tp.skipWhitespace()\n\tresult, err := p.parseSimpleSelectorSequence()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor {\n\t\tvar (\n\t\t\tcombinator byte\n\t\t\tc          Sel\n\t\t)\n\t\tif p.skipWhitespace() {\n\t\t\tcombinator = ' '\n\t\t}\n\t\tif p.i >= len(p.s) {\n\t\t\treturn result, nil\n\t\t}\n\n\t\tswitch p.s[p.i] {\n\t\tcase '+', '>', '~':\n\t\t\tcombinator = p.s[p.i]\n\t\t\tp.i++\n\t\t\tp.skipWhitespace()\n\t\tcase ',', ')':\n\t\t\t// These characters can't begin a selector, but they can legally occur after one.\n\t\t\treturn result, nil\n\t\t}\n\n\t\tif combinator == 0 {\n\t\t\treturn result, nil\n\t\t}\n\n\t\tc, err = p.parseSimpleSelectorSequence()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult = combinedSelector{first: result, combinator: combinator, second: c}\n\t}\n}\n\n// parseSelectorGroup parses a group of selectors, separated by commas.\nfunc (p *parser) parseSelectorGroup() (SelectorGroup, error) {\n\tcurrent, err := p.parseSelector()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresult := SelectorGroup{current}\n\n\tfor p.i < len(p.s) {\n\t\tif p.s[p.i] != ',' {\n\t\t\tbreak\n\t\t}\n\t\tp.i++\n\t\tc, err := p.parseSelector()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tresult = append(result, c)\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/cascadia/pseudo_classes.go",
    "content": "package cascadia\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n\t\"golang.org/x/net/html/atom\"\n)\n\n// This file implements the pseudo classes selectors,\n// which share the implementation of PseudoElement() and Specificity()\n\ntype abstractPseudoClass struct{}\n\nfunc (s abstractPseudoClass) Specificity() Specificity {\n\treturn Specificity{0, 1, 0}\n}\n\nfunc (c abstractPseudoClass) PseudoElement() string {\n\treturn \"\"\n}\n\ntype relativePseudoClassSelector struct {\n\tname  string // one of \"not\", \"has\", \"haschild\"\n\tmatch SelectorGroup\n}\n\nfunc (s relativePseudoClassSelector) Match(n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\tswitch s.name {\n\tcase \"not\":\n\t\t// matches elements that do not match a.\n\t\treturn !s.match.Match(n)\n\tcase \"has\":\n\t\t//  matches elements with any descendant that matches a.\n\t\treturn hasDescendantMatch(n, s.match)\n\tcase \"haschild\":\n\t\t// matches elements with a child that matches a.\n\t\treturn hasChildMatch(n, s.match)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unsupported relative pseudo class selector : %s\", s.name))\n\t}\n}\n\n// hasChildMatch returns whether n has any child that matches a.\nfunc hasChildMatch(n *html.Node, a Matcher) bool {\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tif a.Match(c) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// hasDescendantMatch performs a depth-first search of n's descendants,\n// testing whether any of them match a. It returns true as soon as a match is\n// found, or false if no match is found.\nfunc hasDescendantMatch(n *html.Node, a Matcher) bool {\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tif a.Match(c) || (c.Type == html.ElementNode && hasDescendantMatch(c, a)) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// Specificity returns the specificity of the most specific selectors\n// in the pseudo-class arguments.\n// See https://www.w3.org/TR/selectors/#specificity-rules\nfunc (s relativePseudoClassSelector) Specificity() Specificity {\n\tvar max Specificity\n\tfor _, sel := range s.match {\n\t\tnewSpe := sel.Specificity()\n\t\tif max.Less(newSpe) {\n\t\t\tmax = newSpe\n\t\t}\n\t}\n\treturn max\n}\n\nfunc (c relativePseudoClassSelector) PseudoElement() string {\n\treturn \"\"\n}\n\ntype containsPseudoClassSelector struct {\n\tabstractPseudoClass\n\tvalue string\n\town   bool\n}\n\nfunc (s containsPseudoClassSelector) Match(n *html.Node) bool {\n\tvar text string\n\tif s.own {\n\t\t// matches nodes that directly contain the given text\n\t\ttext = strings.ToLower(nodeOwnText(n))\n\t} else {\n\t\t// matches nodes that contain the given text.\n\t\ttext = strings.ToLower(nodeText(n))\n\t}\n\treturn strings.Contains(text, s.value)\n}\n\ntype regexpPseudoClassSelector struct {\n\tabstractPseudoClass\n\tregexp *regexp.Regexp\n\town    bool\n}\n\nfunc (s regexpPseudoClassSelector) Match(n *html.Node) bool {\n\tvar text string\n\tif s.own {\n\t\t// matches nodes whose text directly matches the specified regular expression\n\t\ttext = nodeOwnText(n)\n\t} else {\n\t\t// matches nodes whose text matches the specified regular expression\n\t\ttext = nodeText(n)\n\t}\n\treturn s.regexp.MatchString(text)\n}\n\n// writeNodeText writes the text contained in n and its descendants to b.\nfunc writeNodeText(n *html.Node, b *bytes.Buffer) {\n\tswitch n.Type {\n\tcase html.TextNode:\n\t\tb.WriteString(n.Data)\n\tcase html.ElementNode:\n\t\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\t\twriteNodeText(c, b)\n\t\t}\n\t}\n}\n\n// nodeText returns the text contained in n and its descendants.\nfunc nodeText(n *html.Node) string {\n\tvar b bytes.Buffer\n\twriteNodeText(n, &b)\n\treturn b.String()\n}\n\n// nodeOwnText returns the contents of the text nodes that are direct\n// children of n.\nfunc nodeOwnText(n *html.Node) string {\n\tvar b bytes.Buffer\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tif c.Type == html.TextNode {\n\t\t\tb.WriteString(c.Data)\n\t\t}\n\t}\n\treturn b.String()\n}\n\ntype nthPseudoClassSelector struct {\n\tabstractPseudoClass\n\ta, b         int\n\tlast, ofType bool\n}\n\nfunc (s nthPseudoClassSelector) Match(n *html.Node) bool {\n\tif s.a == 0 {\n\t\tif s.last {\n\t\t\treturn simpleNthLastChildMatch(s.b, s.ofType, n)\n\t\t} else {\n\t\t\treturn simpleNthChildMatch(s.b, s.ofType, n)\n\t\t}\n\t}\n\treturn nthChildMatch(s.a, s.b, s.last, s.ofType, n)\n}\n\n// nthChildMatch implements :nth-child(an+b).\n// If last is true, implements :nth-last-child instead.\n// If ofType is true, implements :nth-of-type instead.\nfunc nthChildMatch(a, b int, last, ofType bool, n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\n\tparent := n.Parent\n\tif parent == nil {\n\t\treturn false\n\t}\n\n\ti := -1\n\tcount := 0\n\tfor c := parent.FirstChild; c != nil; c = c.NextSibling {\n\t\tif (c.Type != html.ElementNode) || (ofType && c.Data != n.Data) {\n\t\t\tcontinue\n\t\t}\n\t\tcount++\n\t\tif c == n {\n\t\t\ti = count\n\t\t\tif !last {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif i == -1 {\n\t\t// This shouldn't happen, since n should always be one of its parent's children.\n\t\treturn false\n\t}\n\n\tif last {\n\t\ti = count - i + 1\n\t}\n\n\ti -= b\n\tif a == 0 {\n\t\treturn i == 0\n\t}\n\n\treturn i%a == 0 && i/a >= 0\n}\n\n// simpleNthChildMatch implements :nth-child(b).\n// If ofType is true, implements :nth-of-type instead.\nfunc simpleNthChildMatch(b int, ofType bool, n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\n\tparent := n.Parent\n\tif parent == nil {\n\t\treturn false\n\t}\n\n\tcount := 0\n\tfor c := parent.FirstChild; c != nil; c = c.NextSibling {\n\t\tif c.Type != html.ElementNode || (ofType && c.Data != n.Data) {\n\t\t\tcontinue\n\t\t}\n\t\tcount++\n\t\tif c == n {\n\t\t\treturn count == b\n\t\t}\n\t\tif count >= b {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\n// simpleNthLastChildMatch implements :nth-last-child(b).\n// If ofType is true, implements :nth-last-of-type instead.\nfunc simpleNthLastChildMatch(b int, ofType bool, n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\n\tparent := n.Parent\n\tif parent == nil {\n\t\treturn false\n\t}\n\n\tcount := 0\n\tfor c := parent.LastChild; c != nil; c = c.PrevSibling {\n\t\tif c.Type != html.ElementNode || (ofType && c.Data != n.Data) {\n\t\t\tcontinue\n\t\t}\n\t\tcount++\n\t\tif c == n {\n\t\t\treturn count == b\n\t\t}\n\t\tif count >= b {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\ntype onlyChildPseudoClassSelector struct {\n\tabstractPseudoClass\n\tofType bool\n}\n\n// Match implements :only-child.\n// If `ofType` is true, it implements :only-of-type instead.\nfunc (s onlyChildPseudoClassSelector) Match(n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\n\tparent := n.Parent\n\tif parent == nil {\n\t\treturn false\n\t}\n\n\tcount := 0\n\tfor c := parent.FirstChild; c != nil; c = c.NextSibling {\n\t\tif (c.Type != html.ElementNode) || (s.ofType && c.Data != n.Data) {\n\t\t\tcontinue\n\t\t}\n\t\tcount++\n\t\tif count > 1 {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn count == 1\n}\n\ntype inputPseudoClassSelector struct {\n\tabstractPseudoClass\n}\n\n// Matches input, select, textarea and button elements.\nfunc (s inputPseudoClassSelector) Match(n *html.Node) bool {\n\treturn n.Type == html.ElementNode && (n.Data == \"input\" || n.Data == \"select\" || n.Data == \"textarea\" || n.Data == \"button\")\n}\n\ntype emptyElementPseudoClassSelector struct {\n\tabstractPseudoClass\n}\n\n// Matches empty elements.\nfunc (s emptyElementPseudoClassSelector) Match(n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tswitch c.Type {\n\t\tcase html.ElementNode:\n\t\t\treturn false\n\t\tcase html.TextNode:\n\t\t\tif strings.TrimSpace(nodeText(c)) == \"\" {\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\ntype rootPseudoClassSelector struct {\n\tabstractPseudoClass\n}\n\n// Match implements :root\nfunc (s rootPseudoClassSelector) Match(n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\tif n.Parent == nil {\n\t\treturn false\n\t}\n\treturn n.Parent.Type == html.DocumentNode\n}\n\nfunc hasAttr(n *html.Node, attr string) bool {\n\treturn matchAttribute(n, attr, func(string) bool { return true })\n}\n\ntype linkPseudoClassSelector struct {\n\tabstractPseudoClass\n}\n\n// Match implements :link\nfunc (s linkPseudoClassSelector) Match(n *html.Node) bool {\n\treturn (n.DataAtom == atom.A || n.DataAtom == atom.Area || n.DataAtom == atom.Link) && hasAttr(n, \"href\")\n}\n\ntype langPseudoClassSelector struct {\n\tabstractPseudoClass\n\tlang string\n}\n\nfunc (s langPseudoClassSelector) Match(n *html.Node) bool {\n\town := matchAttribute(n, \"lang\", func(val string) bool {\n\t\treturn val == s.lang || strings.HasPrefix(val, s.lang+\"-\")\n\t})\n\tif n.Parent == nil {\n\t\treturn own\n\t}\n\treturn own || s.Match(n.Parent)\n}\n\ntype enabledPseudoClassSelector struct {\n\tabstractPseudoClass\n}\n\nfunc (s enabledPseudoClassSelector) Match(n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\tswitch n.DataAtom {\n\tcase atom.A, atom.Area, atom.Link:\n\t\treturn hasAttr(n, \"href\")\n\tcase atom.Optgroup, atom.Menuitem, atom.Fieldset:\n\t\treturn !hasAttr(n, \"disabled\")\n\tcase atom.Button, atom.Input, atom.Select, atom.Textarea, atom.Option:\n\t\treturn !hasAttr(n, \"disabled\") && !inDisabledFieldset(n)\n\t}\n\treturn false\n}\n\ntype disabledPseudoClassSelector struct {\n\tabstractPseudoClass\n}\n\nfunc (s disabledPseudoClassSelector) Match(n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\tswitch n.DataAtom {\n\tcase atom.Optgroup, atom.Menuitem, atom.Fieldset:\n\t\treturn hasAttr(n, \"disabled\")\n\tcase atom.Button, atom.Input, atom.Select, atom.Textarea, atom.Option:\n\t\treturn hasAttr(n, \"disabled\") || inDisabledFieldset(n)\n\t}\n\treturn false\n}\n\nfunc hasLegendInPreviousSiblings(n *html.Node) bool {\n\tfor s := n.PrevSibling; s != nil; s = s.PrevSibling {\n\t\tif s.DataAtom == atom.Legend {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc inDisabledFieldset(n *html.Node) bool {\n\tif n.Parent == nil {\n\t\treturn false\n\t}\n\tif n.Parent.DataAtom == atom.Fieldset && hasAttr(n.Parent, \"disabled\") &&\n\t\t(n.DataAtom != atom.Legend || hasLegendInPreviousSiblings(n)) {\n\t\treturn true\n\t}\n\treturn inDisabledFieldset(n.Parent)\n}\n\ntype checkedPseudoClassSelector struct {\n\tabstractPseudoClass\n}\n\nfunc (s checkedPseudoClassSelector) Match(n *html.Node) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\tswitch n.DataAtom {\n\tcase atom.Input, atom.Menuitem:\n\t\treturn hasAttr(n, \"checked\") && matchAttribute(n, \"type\", func(val string) bool {\n\t\t\tt := toLowerASCII(val)\n\t\t\treturn t == \"checkbox\" || t == \"radio\"\n\t\t})\n\tcase atom.Option:\n\t\treturn hasAttr(n, \"selected\")\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/cascadia/selector.go",
    "content": "package cascadia\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"golang.org/x/net/html\"\n)\n\n// Matcher is the interface for basic selector functionality.\n// Match returns whether a selector matches n.\ntype Matcher interface {\n\tMatch(n *html.Node) bool\n}\n\n// Sel is the interface for all the functionality provided by selectors.\ntype Sel interface {\n\tMatcher\n\tSpecificity() Specificity\n\n\t// Returns a CSS input compiling to this selector.\n\tString() string\n\n\t// Returns a pseudo-element, or an empty string.\n\tPseudoElement() string\n}\n\n// Parse parses a selector. Use `ParseWithPseudoElement`\n// if you need support for pseudo-elements.\nfunc Parse(sel string) (Sel, error) {\n\tp := &parser{s: sel}\n\tcompiled, err := p.parseSelector()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif p.i < len(sel) {\n\t\treturn nil, fmt.Errorf(\"parsing %q: %d bytes left over\", sel, len(sel)-p.i)\n\t}\n\n\treturn compiled, nil\n}\n\n// ParseWithPseudoElement parses a single selector,\n// with support for pseudo-element.\nfunc ParseWithPseudoElement(sel string) (Sel, error) {\n\tp := &parser{s: sel, acceptPseudoElements: true}\n\tcompiled, err := p.parseSelector()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif p.i < len(sel) {\n\t\treturn nil, fmt.Errorf(\"parsing %q: %d bytes left over\", sel, len(sel)-p.i)\n\t}\n\n\treturn compiled, nil\n}\n\n// ParseGroup parses a selector, or a group of selectors separated by commas.\n// Use `ParseGroupWithPseudoElements`\n// if you need support for pseudo-elements.\nfunc ParseGroup(sel string) (SelectorGroup, error) {\n\tp := &parser{s: sel}\n\tcompiled, err := p.parseSelectorGroup()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif p.i < len(sel) {\n\t\treturn nil, fmt.Errorf(\"parsing %q: %d bytes left over\", sel, len(sel)-p.i)\n\t}\n\n\treturn compiled, nil\n}\n\n// ParseGroupWithPseudoElements parses a selector, or a group of selectors separated by commas.\n// It supports pseudo-elements.\nfunc ParseGroupWithPseudoElements(sel string) (SelectorGroup, error) {\n\tp := &parser{s: sel, acceptPseudoElements: true}\n\tcompiled, err := p.parseSelectorGroup()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif p.i < len(sel) {\n\t\treturn nil, fmt.Errorf(\"parsing %q: %d bytes left over\", sel, len(sel)-p.i)\n\t}\n\n\treturn compiled, nil\n}\n\n// A Selector is a function which tells whether a node matches or not.\n//\n// This type is maintained for compatibility; I recommend using the newer and\n// more idiomatic interfaces Sel and Matcher.\ntype Selector func(*html.Node) bool\n\n// Compile parses a selector and returns, if successful, a Selector object\n// that can be used to match against html.Node objects.\nfunc Compile(sel string) (Selector, error) {\n\tcompiled, err := ParseGroup(sel)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn Selector(compiled.Match), nil\n}\n\n// MustCompile is like Compile, but panics instead of returning an error.\nfunc MustCompile(sel string) Selector {\n\tcompiled, err := Compile(sel)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn compiled\n}\n\n// MatchAll returns a slice of the nodes that match the selector,\n// from n and its children.\nfunc (s Selector) MatchAll(n *html.Node) []*html.Node {\n\treturn s.matchAllInto(n, nil)\n}\n\nfunc (s Selector) matchAllInto(n *html.Node, storage []*html.Node) []*html.Node {\n\tif s(n) {\n\t\tstorage = append(storage, n)\n\t}\n\n\tfor child := n.FirstChild; child != nil; child = child.NextSibling {\n\t\tstorage = s.matchAllInto(child, storage)\n\t}\n\n\treturn storage\n}\n\nfunc queryInto(n *html.Node, m Matcher, storage []*html.Node) []*html.Node {\n\tfor child := n.FirstChild; child != nil; child = child.NextSibling {\n\t\tif m.Match(child) {\n\t\t\tstorage = append(storage, child)\n\t\t}\n\t\tstorage = queryInto(child, m, storage)\n\t}\n\n\treturn storage\n}\n\n// QueryAll returns a slice of all the nodes that match m, from the descendants\n// of n.\nfunc QueryAll(n *html.Node, m Matcher) []*html.Node {\n\treturn queryInto(n, m, nil)\n}\n\n// Match returns true if the node matches the selector.\nfunc (s Selector) Match(n *html.Node) bool {\n\treturn s(n)\n}\n\n// MatchFirst returns the first node that matches s, from n and its children.\nfunc (s Selector) MatchFirst(n *html.Node) *html.Node {\n\tif s.Match(n) {\n\t\treturn n\n\t}\n\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tm := s.MatchFirst(c)\n\t\tif m != nil {\n\t\t\treturn m\n\t\t}\n\t}\n\treturn nil\n}\n\n// Query returns the first node that matches m, from the descendants of n.\n// If none matches, it returns nil.\nfunc Query(n *html.Node, m Matcher) *html.Node {\n\tfor c := n.FirstChild; c != nil; c = c.NextSibling {\n\t\tif m.Match(c) {\n\t\t\treturn c\n\t\t}\n\t\tif matched := Query(c, m); matched != nil {\n\t\t\treturn matched\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Filter returns the nodes in nodes that match the selector.\nfunc (s Selector) Filter(nodes []*html.Node) (result []*html.Node) {\n\tfor _, n := range nodes {\n\t\tif s(n) {\n\t\t\tresult = append(result, n)\n\t\t}\n\t}\n\treturn result\n}\n\n// Filter returns the nodes that match m.\nfunc Filter(nodes []*html.Node, m Matcher) (result []*html.Node) {\n\tfor _, n := range nodes {\n\t\tif m.Match(n) {\n\t\t\tresult = append(result, n)\n\t\t}\n\t}\n\treturn result\n}\n\ntype tagSelector struct {\n\ttag string\n}\n\n// Matches elements with a given tag name.\nfunc (t tagSelector) Match(n *html.Node) bool {\n\treturn n.Type == html.ElementNode && n.Data == t.tag\n}\n\nfunc (c tagSelector) Specificity() Specificity {\n\treturn Specificity{0, 0, 1}\n}\n\nfunc (c tagSelector) PseudoElement() string {\n\treturn \"\"\n}\n\ntype classSelector struct {\n\tclass string\n}\n\n// Matches elements by class attribute.\nfunc (t classSelector) Match(n *html.Node) bool {\n\treturn matchAttribute(n, \"class\", func(s string) bool {\n\t\treturn matchInclude(t.class, s, false)\n\t})\n}\n\nfunc (c classSelector) Specificity() Specificity {\n\treturn Specificity{0, 1, 0}\n}\n\nfunc (c classSelector) PseudoElement() string {\n\treturn \"\"\n}\n\ntype idSelector struct {\n\tid string\n}\n\n// Matches elements by id attribute.\nfunc (t idSelector) Match(n *html.Node) bool {\n\treturn matchAttribute(n, \"id\", func(s string) bool {\n\t\treturn s == t.id\n\t})\n}\n\nfunc (c idSelector) Specificity() Specificity {\n\treturn Specificity{1, 0, 0}\n}\n\nfunc (c idSelector) PseudoElement() string {\n\treturn \"\"\n}\n\ntype attrSelector struct {\n\tkey, val, operation string\n\tregexp              *regexp.Regexp\n\tinsensitive         bool\n}\n\n// Matches elements by attribute value.\nfunc (t attrSelector) Match(n *html.Node) bool {\n\tswitch t.operation {\n\tcase \"\":\n\t\treturn matchAttribute(n, t.key, func(string) bool { return true })\n\tcase \"=\":\n\t\treturn matchAttribute(n, t.key, func(s string) bool { return matchInsensitiveValue(s, t.val, t.insensitive) })\n\tcase \"!=\":\n\t\treturn attributeNotEqualMatch(t.key, t.val, n, t.insensitive)\n\tcase \"~=\":\n\t\t// matches elements where the attribute named key is a whitespace-separated list that includes val.\n\t\treturn matchAttribute(n, t.key, func(s string) bool { return matchInclude(t.val, s, t.insensitive) })\n\tcase \"|=\":\n\t\treturn attributeDashMatch(t.key, t.val, n, t.insensitive)\n\tcase \"^=\":\n\t\treturn attributePrefixMatch(t.key, t.val, n, t.insensitive)\n\tcase \"$=\":\n\t\treturn attributeSuffixMatch(t.key, t.val, n, t.insensitive)\n\tcase \"*=\":\n\t\treturn attributeSubstringMatch(t.key, t.val, n, t.insensitive)\n\tcase \"#=\":\n\t\treturn attributeRegexMatch(t.key, t.regexp, n)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unsuported operation : %s\", t.operation))\n\t}\n}\n\n// matches elements where we ignore (or not) the case of the attribute value\n// the user attribute is the value set by the user to match elements\n// the real attribute is the attribute value found in the code parsed\nfunc matchInsensitiveValue(userAttr string, realAttr string, ignoreCase bool) bool {\n\tif ignoreCase {\n\t\treturn strings.EqualFold(userAttr, realAttr)\n\t}\n\treturn userAttr == realAttr\n\n}\n\n// matches elements where the attribute named key satisifes the function f.\nfunc matchAttribute(n *html.Node, key string, f func(string) bool) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\tfor _, a := range n.Attr {\n\t\tif a.Key == key && f(a.Val) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// attributeNotEqualMatch matches elements where\n// the attribute named key does not have the value val.\nfunc attributeNotEqualMatch(key, val string, n *html.Node, ignoreCase bool) bool {\n\tif n.Type != html.ElementNode {\n\t\treturn false\n\t}\n\tfor _, a := range n.Attr {\n\t\tif a.Key == key && matchInsensitiveValue(a.Val, val, ignoreCase) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// returns true if s is a whitespace-separated list that includes val.\nfunc matchInclude(val string, s string, ignoreCase bool) bool {\n\tfor s != \"\" {\n\t\ti := strings.IndexAny(s, \" \\t\\r\\n\\f\")\n\t\tif i == -1 {\n\t\t\treturn matchInsensitiveValue(s, val, ignoreCase)\n\t\t}\n\t\tif matchInsensitiveValue(s[:i], val, ignoreCase) {\n\t\t\treturn true\n\t\t}\n\t\ts = s[i+1:]\n\t}\n\treturn false\n}\n\n//  matches elements where the attribute named key equals val or starts with val plus a hyphen.\nfunc attributeDashMatch(key, val string, n *html.Node, ignoreCase bool) bool {\n\treturn matchAttribute(n, key,\n\t\tfunc(s string) bool {\n\t\t\tif matchInsensitiveValue(s, val, ignoreCase) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif len(s) <= len(val) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif matchInsensitiveValue(s[:len(val)], val, ignoreCase) && s[len(val)] == '-' {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t})\n}\n\n// attributePrefixMatch returns a Selector that matches elements where\n// the attribute named key starts with val.\nfunc attributePrefixMatch(key, val string, n *html.Node, ignoreCase bool) bool {\n\treturn matchAttribute(n, key,\n\t\tfunc(s string) bool {\n\t\t\tif strings.TrimSpace(s) == \"\" {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif ignoreCase {\n\t\t\t\treturn strings.HasPrefix(strings.ToLower(s), strings.ToLower(val))\n\t\t\t}\n\t\t\treturn strings.HasPrefix(s, val)\n\t\t})\n}\n\n// attributeSuffixMatch matches elements where\n// the attribute named key ends with val.\nfunc attributeSuffixMatch(key, val string, n *html.Node, ignoreCase bool) bool {\n\treturn matchAttribute(n, key,\n\t\tfunc(s string) bool {\n\t\t\tif strings.TrimSpace(s) == \"\" {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif ignoreCase {\n\t\t\t\treturn strings.HasSuffix(strings.ToLower(s), strings.ToLower(val))\n\t\t\t}\n\t\t\treturn strings.HasSuffix(s, val)\n\t\t})\n}\n\n// attributeSubstringMatch matches nodes where\n// the attribute named key contains val.\nfunc attributeSubstringMatch(key, val string, n *html.Node, ignoreCase bool) bool {\n\treturn matchAttribute(n, key,\n\t\tfunc(s string) bool {\n\t\t\tif strings.TrimSpace(s) == \"\" {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif ignoreCase {\n\t\t\t\treturn strings.Contains(strings.ToLower(s), strings.ToLower(val))\n\t\t\t}\n\t\t\treturn strings.Contains(s, val)\n\t\t})\n}\n\n// attributeRegexMatch  matches nodes where\n// the attribute named key matches the regular expression rx\nfunc attributeRegexMatch(key string, rx *regexp.Regexp, n *html.Node) bool {\n\treturn matchAttribute(n, key,\n\t\tfunc(s string) bool {\n\t\t\treturn rx.MatchString(s)\n\t\t})\n}\n\nfunc (c attrSelector) Specificity() Specificity {\n\treturn Specificity{0, 1, 0}\n}\n\nfunc (c attrSelector) PseudoElement() string {\n\treturn \"\"\n}\n\n// see pseudo_classes.go for pseudo classes selectors\n\n// on a static context, some selectors can't match anything\ntype neverMatchSelector struct {\n\tvalue string\n}\n\nfunc (s neverMatchSelector) Match(n *html.Node) bool {\n\treturn false\n}\n\nfunc (s neverMatchSelector) Specificity() Specificity {\n\treturn Specificity{0, 0, 0}\n}\n\nfunc (c neverMatchSelector) PseudoElement() string {\n\treturn \"\"\n}\n\ntype compoundSelector struct {\n\tselectors     []Sel\n\tpseudoElement string\n}\n\n// Matches elements if each sub-selectors matches.\nfunc (t compoundSelector) Match(n *html.Node) bool {\n\tif len(t.selectors) == 0 {\n\t\treturn n.Type == html.ElementNode\n\t}\n\n\tfor _, sel := range t.selectors {\n\t\tif !sel.Match(n) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (s compoundSelector) Specificity() Specificity {\n\tvar out Specificity\n\tfor _, sel := range s.selectors {\n\t\tout = out.Add(sel.Specificity())\n\t}\n\tif s.pseudoElement != \"\" {\n\t\t// https://drafts.csswg.org/selectors-3/#specificity\n\t\tout = out.Add(Specificity{0, 0, 1})\n\t}\n\treturn out\n}\n\nfunc (c compoundSelector) PseudoElement() string {\n\treturn c.pseudoElement\n}\n\ntype combinedSelector struct {\n\tfirst      Sel\n\tcombinator byte\n\tsecond     Sel\n}\n\nfunc (t combinedSelector) Match(n *html.Node) bool {\n\tif t.first == nil {\n\t\treturn false // maybe we should panic\n\t}\n\tswitch t.combinator {\n\tcase 0:\n\t\treturn t.first.Match(n)\n\tcase ' ':\n\t\treturn descendantMatch(t.first, t.second, n)\n\tcase '>':\n\t\treturn childMatch(t.first, t.second, n)\n\tcase '+':\n\t\treturn siblingMatch(t.first, t.second, true, n)\n\tcase '~':\n\t\treturn siblingMatch(t.first, t.second, false, n)\n\tdefault:\n\t\tpanic(\"unknown combinator\")\n\t}\n}\n\n// matches an element if it matches d and has an ancestor that matches a.\nfunc descendantMatch(a, d Matcher, n *html.Node) bool {\n\tif !d.Match(n) {\n\t\treturn false\n\t}\n\n\tfor p := n.Parent; p != nil; p = p.Parent {\n\t\tif a.Match(p) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// matches an element if it matches d and its parent matches a.\nfunc childMatch(a, d Matcher, n *html.Node) bool {\n\treturn d.Match(n) && n.Parent != nil && a.Match(n.Parent)\n}\n\n// matches an element if it matches s2 and is preceded by an element that matches s1.\n// If adjacent is true, the sibling must be immediately before the element.\nfunc siblingMatch(s1, s2 Matcher, adjacent bool, n *html.Node) bool {\n\tif !s2.Match(n) {\n\t\treturn false\n\t}\n\n\tif adjacent {\n\t\tfor n = n.PrevSibling; n != nil; n = n.PrevSibling {\n\t\t\tif n.Type == html.TextNode || n.Type == html.CommentNode {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn s1.Match(n)\n\t\t}\n\t\treturn false\n\t}\n\n\t// Walk backwards looking for element that matches s1\n\tfor c := n.PrevSibling; c != nil; c = c.PrevSibling {\n\t\tif s1.Match(c) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (s combinedSelector) Specificity() Specificity {\n\tspec := s.first.Specificity()\n\tif s.second != nil {\n\t\tspec = spec.Add(s.second.Specificity())\n\t}\n\treturn spec\n}\n\n// on combinedSelector, a pseudo-element only makes sens on the last\n// selector, although others increase specificity.\nfunc (c combinedSelector) PseudoElement() string {\n\tif c.second == nil {\n\t\treturn \"\"\n\t}\n\treturn c.second.PseudoElement()\n}\n\n// A SelectorGroup is a list of selectors, which matches if any of the\n// individual selectors matches.\ntype SelectorGroup []Sel\n\n// Match returns true if the node matches one of the single selectors.\nfunc (s SelectorGroup) Match(n *html.Node) bool {\n\tfor _, sel := range s {\n\t\tif sel.Match(n) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/cascadia/serialize.go",
    "content": "package cascadia\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// implements the reverse operation Sel -> string\n\nvar specialCharReplacer *strings.Replacer\n\nfunc init() {\n\tvar pairs []string\n\tfor _, s := range \",!\\\"#$%&'()*+ -./:;<=>?@[\\\\]^`{|}~\" {\n\t\tpairs = append(pairs, string(s), \"\\\\\"+string(s))\n\t}\n\tspecialCharReplacer = strings.NewReplacer(pairs...)\n}\n\n// espace special CSS char\nfunc escape(s string) string { return specialCharReplacer.Replace(s) }\n\nfunc (c tagSelector) String() string {\n\treturn c.tag\n}\n\nfunc (c idSelector) String() string {\n\treturn \"#\" + escape(c.id)\n}\n\nfunc (c classSelector) String() string {\n\treturn \".\" + escape(c.class)\n}\n\nfunc (c attrSelector) String() string {\n\tval := c.val\n\tif c.operation == \"#=\" {\n\t\tval = c.regexp.String()\n\t} else if c.operation != \"\" {\n\t\tval = fmt.Sprintf(`\"%s\"`, val)\n\t}\n\n\tignoreCase := \"\"\n\n\tif c.insensitive {\n\t\tignoreCase = \" i\"\n\t}\n\n\treturn fmt.Sprintf(`[%s%s%s%s]`, c.key, c.operation, val, ignoreCase)\n}\n\nfunc (c relativePseudoClassSelector) String() string {\n\treturn fmt.Sprintf(\":%s(%s)\", c.name, c.match.String())\n}\n\nfunc (c containsPseudoClassSelector) String() string {\n\ts := \"contains\"\n\tif c.own {\n\t\ts += \"Own\"\n\t}\n\treturn fmt.Sprintf(`:%s(\"%s\")`, s, c.value)\n}\n\nfunc (c regexpPseudoClassSelector) String() string {\n\ts := \"matches\"\n\tif c.own {\n\t\ts += \"Own\"\n\t}\n\treturn fmt.Sprintf(\":%s(%s)\", s, c.regexp.String())\n}\n\nfunc (c nthPseudoClassSelector) String() string {\n\tif c.a == 0 && c.b == 1 { // special cases\n\t\ts := \":first-\"\n\t\tif c.last {\n\t\t\ts = \":last-\"\n\t\t}\n\t\tif c.ofType {\n\t\t\ts += \"of-type\"\n\t\t} else {\n\t\t\ts += \"child\"\n\t\t}\n\t\treturn s\n\t}\n\tvar name string\n\tswitch [2]bool{c.last, c.ofType} {\n\tcase [2]bool{true, true}:\n\t\tname = \"nth-last-of-type\"\n\tcase [2]bool{true, false}:\n\t\tname = \"nth-last-child\"\n\tcase [2]bool{false, true}:\n\t\tname = \"nth-of-type\"\n\tcase [2]bool{false, false}:\n\t\tname = \"nth-child\"\n\t}\n\ts := fmt.Sprintf(\"+%d\", c.b)\n\tif c.b < 0 { // avoid +-8 invalid syntax\n\t\ts = strconv.Itoa(c.b)\n\t}\n\treturn fmt.Sprintf(\":%s(%dn%s)\", name, c.a, s)\n}\n\nfunc (c onlyChildPseudoClassSelector) String() string {\n\tif c.ofType {\n\t\treturn \":only-of-type\"\n\t}\n\treturn \":only-child\"\n}\n\nfunc (c inputPseudoClassSelector) String() string {\n\treturn \":input\"\n}\n\nfunc (c emptyElementPseudoClassSelector) String() string {\n\treturn \":empty\"\n}\n\nfunc (c rootPseudoClassSelector) String() string {\n\treturn \":root\"\n}\n\nfunc (c linkPseudoClassSelector) String() string {\n\treturn \":link\"\n}\n\nfunc (c langPseudoClassSelector) String() string {\n\treturn fmt.Sprintf(\":lang(%s)\", c.lang)\n}\n\nfunc (c neverMatchSelector) String() string {\n\treturn c.value\n}\n\nfunc (c enabledPseudoClassSelector) String() string {\n\treturn \":enabled\"\n}\n\nfunc (c disabledPseudoClassSelector) String() string {\n\treturn \":disabled\"\n}\n\nfunc (c checkedPseudoClassSelector) String() string {\n\treturn \":checked\"\n}\n\nfunc (c compoundSelector) String() string {\n\tif len(c.selectors) == 0 && c.pseudoElement == \"\" {\n\t\treturn \"*\"\n\t}\n\tchunks := make([]string, len(c.selectors))\n\tfor i, sel := range c.selectors {\n\t\tchunks[i] = sel.String()\n\t}\n\ts := strings.Join(chunks, \"\")\n\tif c.pseudoElement != \"\" {\n\t\ts += \"::\" + c.pseudoElement\n\t}\n\treturn s\n}\n\nfunc (c combinedSelector) String() string {\n\tstart := c.first.String()\n\tif c.second != nil {\n\t\tstart += fmt.Sprintf(\" %s %s\", string(c.combinator), c.second.String())\n\t}\n\treturn start\n}\n\nfunc (c SelectorGroup) String() string {\n\tck := make([]string, len(c))\n\tfor i, s := range c {\n\t\tck[i] = s.String()\n\t}\n\treturn strings.Join(ck, \", \")\n}\n"
  },
  {
    "path": "vendor/github.com/andybalholm/cascadia/specificity.go",
    "content": "package cascadia\n\n// Specificity is the CSS specificity as defined in\n// https://www.w3.org/TR/selectors/#specificity-rules\n// with the convention Specificity = [A,B,C].\ntype Specificity [3]int\n\n// returns `true` if s < other (strictly), false otherwise\nfunc (s Specificity) Less(other Specificity) bool {\n\tfor i := range s {\n\t\tif s[i] < other[i] {\n\t\t\treturn true\n\t\t}\n\t\tif s[i] > other[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (s Specificity) Add(other Specificity) Specificity {\n\tfor i, sp := range other {\n\t\ts[i] += sp\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "vendor/github.com/beorn7/perks/LICENSE",
    "content": "Copyright (C) 2013 Blake Mizerany\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/beorn7/perks/quantile/stream.go",
    "content": "// Package quantile computes approximate quantiles over an unbounded data\n// stream within low memory and CPU bounds.\n//\n// A small amount of accuracy is traded to achieve the above properties.\n//\n// Multiple streams can be merged before calling Query to generate a single set\n// of results. This is meaningful when the streams represent the same type of\n// data. See Merge and Samples.\n//\n// For more detailed information about the algorithm used, see:\n//\n// Effective Computation of Biased Quantiles over Data Streams\n//\n// http://www.cs.rutgers.edu/~muthu/bquant.pdf\npackage quantile\n\nimport (\n\t\"math\"\n\t\"sort\"\n)\n\n// Sample holds an observed value and meta information for compression. JSON\n// tags have been added for convenience.\ntype Sample struct {\n\tValue float64 `json:\",string\"`\n\tWidth float64 `json:\",string\"`\n\tDelta float64 `json:\",string\"`\n}\n\n// Samples represents a slice of samples. It implements sort.Interface.\ntype Samples []Sample\n\nfunc (a Samples) Len() int           { return len(a) }\nfunc (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value }\nfunc (a Samples) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }\n\ntype invariant func(s *stream, r float64) float64\n\n// NewLowBiased returns an initialized Stream for low-biased quantiles\n// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but\n// error guarantees can still be given even for the lower ranks of the data\n// distribution.\n//\n// The provided epsilon is a relative error, i.e. the true quantile of a value\n// returned by a query is guaranteed to be within (1±Epsilon)*Quantile.\n//\n// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error\n// properties.\nfunc NewLowBiased(epsilon float64) *Stream {\n\tƒ := func(s *stream, r float64) float64 {\n\t\treturn 2 * epsilon * r\n\t}\n\treturn newStream(ƒ)\n}\n\n// NewHighBiased returns an initialized Stream for high-biased quantiles\n// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but\n// error guarantees can still be given even for the higher ranks of the data\n// distribution.\n//\n// The provided epsilon is a relative error, i.e. the true quantile of a value\n// returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile).\n//\n// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error\n// properties.\nfunc NewHighBiased(epsilon float64) *Stream {\n\tƒ := func(s *stream, r float64) float64 {\n\t\treturn 2 * epsilon * (s.n - r)\n\t}\n\treturn newStream(ƒ)\n}\n\n// NewTargeted returns an initialized Stream concerned with a particular set of\n// quantile values that are supplied a priori. Knowing these a priori reduces\n// space and computation time. The targets map maps the desired quantiles to\n// their absolute errors, i.e. the true quantile of a value returned by a query\n// is guaranteed to be within (Quantile±Epsilon).\n//\n// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.\nfunc NewTargeted(targetMap map[float64]float64) *Stream {\n\t// Convert map to slice to avoid slow iterations on a map.\n\t// ƒ is called on the hot path, so converting the map to a slice\n\t// beforehand results in significant CPU savings.\n\ttargets := targetMapToSlice(targetMap)\n\n\tƒ := func(s *stream, r float64) float64 {\n\t\tvar m = math.MaxFloat64\n\t\tvar f float64\n\t\tfor _, t := range targets {\n\t\t\tif t.quantile*s.n <= r {\n\t\t\t\tf = (2 * t.epsilon * r) / t.quantile\n\t\t\t} else {\n\t\t\t\tf = (2 * t.epsilon * (s.n - r)) / (1 - t.quantile)\n\t\t\t}\n\t\t\tif f < m {\n\t\t\t\tm = f\n\t\t\t}\n\t\t}\n\t\treturn m\n\t}\n\treturn newStream(ƒ)\n}\n\ntype target struct {\n\tquantile float64\n\tepsilon  float64\n}\n\nfunc targetMapToSlice(targetMap map[float64]float64) []target {\n\ttargets := make([]target, 0, len(targetMap))\n\n\tfor quantile, epsilon := range targetMap {\n\t\tt := target{\n\t\t\tquantile: quantile,\n\t\t\tepsilon:  epsilon,\n\t\t}\n\t\ttargets = append(targets, t)\n\t}\n\n\treturn targets\n}\n\n// Stream computes quantiles for a stream of float64s. It is not thread-safe by\n// design. Take care when using across multiple goroutines.\ntype Stream struct {\n\t*stream\n\tb      Samples\n\tsorted bool\n}\n\nfunc newStream(ƒ invariant) *Stream {\n\tx := &stream{ƒ: ƒ}\n\treturn &Stream{x, make(Samples, 0, 500), true}\n}\n\n// Insert inserts v into the stream.\nfunc (s *Stream) Insert(v float64) {\n\ts.insert(Sample{Value: v, Width: 1})\n}\n\nfunc (s *Stream) insert(sample Sample) {\n\ts.b = append(s.b, sample)\n\ts.sorted = false\n\tif len(s.b) == cap(s.b) {\n\t\ts.flush()\n\t}\n}\n\n// Query returns the computed qth percentiles value. If s was created with\n// NewTargeted, and q is not in the set of quantiles provided a priori, Query\n// will return an unspecified result.\nfunc (s *Stream) Query(q float64) float64 {\n\tif !s.flushed() {\n\t\t// Fast path when there hasn't been enough data for a flush;\n\t\t// this also yields better accuracy for small sets of data.\n\t\tl := len(s.b)\n\t\tif l == 0 {\n\t\t\treturn 0\n\t\t}\n\t\ti := int(math.Ceil(float64(l) * q))\n\t\tif i > 0 {\n\t\t\ti -= 1\n\t\t}\n\t\ts.maybeSort()\n\t\treturn s.b[i].Value\n\t}\n\ts.flush()\n\treturn s.stream.query(q)\n}\n\n// Merge merges samples into the underlying streams samples. This is handy when\n// merging multiple streams from separate threads, database shards, etc.\n//\n// ATTENTION: This method is broken and does not yield correct results. The\n// underlying algorithm is not capable of merging streams correctly.\nfunc (s *Stream) Merge(samples Samples) {\n\tsort.Sort(samples)\n\ts.stream.merge(samples)\n}\n\n// Reset reinitializes and clears the list reusing the samples buffer memory.\nfunc (s *Stream) Reset() {\n\ts.stream.reset()\n\ts.b = s.b[:0]\n}\n\n// Samples returns stream samples held by s.\nfunc (s *Stream) Samples() Samples {\n\tif !s.flushed() {\n\t\treturn s.b\n\t}\n\ts.flush()\n\treturn s.stream.samples()\n}\n\n// Count returns the total number of samples observed in the stream\n// since initialization.\nfunc (s *Stream) Count() int {\n\treturn len(s.b) + s.stream.count()\n}\n\nfunc (s *Stream) flush() {\n\ts.maybeSort()\n\ts.stream.merge(s.b)\n\ts.b = s.b[:0]\n}\n\nfunc (s *Stream) maybeSort() {\n\tif !s.sorted {\n\t\ts.sorted = true\n\t\tsort.Sort(s.b)\n\t}\n}\n\nfunc (s *Stream) flushed() bool {\n\treturn len(s.stream.l) > 0\n}\n\ntype stream struct {\n\tn float64\n\tl []Sample\n\tƒ invariant\n}\n\nfunc (s *stream) reset() {\n\ts.l = s.l[:0]\n\ts.n = 0\n}\n\nfunc (s *stream) insert(v float64) {\n\ts.merge(Samples{{v, 1, 0}})\n}\n\nfunc (s *stream) merge(samples Samples) {\n\t// TODO(beorn7): This tries to merge not only individual samples, but\n\t// whole summaries. The paper doesn't mention merging summaries at\n\t// all. Unittests show that the merging is inaccurate. Find out how to\n\t// do merges properly.\n\tvar r float64\n\ti := 0\n\tfor _, sample := range samples {\n\t\tfor ; i < len(s.l); i++ {\n\t\t\tc := s.l[i]\n\t\t\tif c.Value > sample.Value {\n\t\t\t\t// Insert at position i.\n\t\t\t\ts.l = append(s.l, Sample{})\n\t\t\t\tcopy(s.l[i+1:], s.l[i:])\n\t\t\t\ts.l[i] = Sample{\n\t\t\t\t\tsample.Value,\n\t\t\t\t\tsample.Width,\n\t\t\t\t\tmath.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1),\n\t\t\t\t\t// TODO(beorn7): How to calculate delta correctly?\n\t\t\t\t}\n\t\t\t\ti++\n\t\t\t\tgoto inserted\n\t\t\t}\n\t\t\tr += c.Width\n\t\t}\n\t\ts.l = append(s.l, Sample{sample.Value, sample.Width, 0})\n\t\ti++\n\tinserted:\n\t\ts.n += sample.Width\n\t\tr += sample.Width\n\t}\n\ts.compress()\n}\n\nfunc (s *stream) count() int {\n\treturn int(s.n)\n}\n\nfunc (s *stream) query(q float64) float64 {\n\tt := math.Ceil(q * s.n)\n\tt += math.Ceil(s.ƒ(s, t) / 2)\n\tp := s.l[0]\n\tvar r float64\n\tfor _, c := range s.l[1:] {\n\t\tr += p.Width\n\t\tif r+c.Width+c.Delta > t {\n\t\t\treturn p.Value\n\t\t}\n\t\tp = c\n\t}\n\treturn p.Value\n}\n\nfunc (s *stream) compress() {\n\tif len(s.l) < 2 {\n\t\treturn\n\t}\n\tx := s.l[len(s.l)-1]\n\txi := len(s.l) - 1\n\tr := s.n - 1 - x.Width\n\n\tfor i := len(s.l) - 2; i >= 0; i-- {\n\t\tc := s.l[i]\n\t\tif c.Width+x.Width+x.Delta <= s.ƒ(s, r) {\n\t\t\tx.Width += c.Width\n\t\t\ts.l[xi] = x\n\t\t\t// Remove element at i.\n\t\t\tcopy(s.l[i:], s.l[i+1:])\n\t\t\ts.l = s.l[:len(s.l)-1]\n\t\t\txi -= 1\n\t\t} else {\n\t\t\tx = c\n\t\t\txi = i\n\t\t}\n\t\tr -= c.Width\n\t}\n}\n\nfunc (s *stream) samples() Samples {\n\tsamples := make(Samples, len(s.l))\n\tcopy(samples, s.l)\n\treturn samples\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/.protoc_version",
    "content": "27.0\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020-2024 Buf Technologies, Inc.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/doc.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package ast defines types for modeling the AST (Abstract Syntax\n// Tree) for the Protocol Buffers interface definition language.\n//\n// # Nodes\n//\n// All nodes of the tree implement the [Node] interface. Leaf nodes in the\n// tree implement [TerminalNode], and all others implement [CompositeNode].\n// The root of the tree for a proto source file is a *[FileNode].\n//\n// A [TerminalNode] represents a single lexical element, or [Token]. A\n// [CompositeNode] represents a sub-tree of the AST and range of tokens.\n//\n// Position information is tracked using a *[FileInfo]. The lexer invokes its\n// various Add* methods to add details as the file is tokenized. Storing\n// the position information in the *[FileInfo], instead of in each AST node,\n// allows the AST to have a much more compact representation. To extract\n// detailed position information, you must use the NodeInfo method, available\n// on either the *[FileInfo] which produced the node's items or the *[FileNode]\n// root of the tree that contains the node.\n//\n// # Items, Tokens, and Comments\n//\n// An [Item] represents a lexical item, excluding whitespace. This can be\n// either a [Token] or a [Comment].\n//\n// Comments are not represented as nodes in the tree. Instead, they are\n// attributed to terminal nodes in the tree. So, when lexing, comments\n// are accumulated until the next non-comment token is found. The AST\n// model in this package thus provides access to all comments in the\n// file, regardless of location (unlike the SourceCodeInfo present in\n// descriptor protos, which is lossy). The comments associated with a\n// non-leaf/non-token node (i.e. a CompositeNode) come from the first\n// and last nodes in its sub-tree, for leading and trailing comments\n// respectively.\n//\n// A [Comment] value corresponds to a line (\"//\") or block (\"/*\") style\n// comment in the source. These have no bearing on the grammar and are\n// effectively ignored as the parser is determining the shape of the\n// syntax tree.\n//\n// A [Token] value corresponds to a component of the grammar, that is\n// used to produce an AST. They correspond to leaves in the AST (i.e.\n// [TerminalNode]).\n//\n// The *[FileInfo] and *[FileNode] types provide methods for querying\n// and iterating through all the items or tokens in the file. They also\n// include a method for resolving an [Item] into a [Token] or [Comment].\n//\n// # Factory Functions\n//\n// Creation of AST nodes should use the factory functions in this\n// package instead of struct literals. Some factory functions accept\n// optional arguments, which means the arguments can be nil. If nil\n// values are provided for other (non-optional) arguments, the resulting\n// node may be invalid and cause panics later in the program.\n//\n// This package defines numerous interfaces. However, user code should\n// not attempt to implement any of them. Most consumers of an AST will\n// not work correctly if they encounter concrete implementations other\n// than the ones defined in this package.\npackage ast\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/enum.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// EnumNode represents an enum declaration. Example:\n//\n//\tenum Foo { BAR = 0; BAZ = 1 }\ntype EnumNode struct {\n\tcompositeNode\n\tKeyword    *KeywordNode\n\tName       *IdentNode\n\tOpenBrace  *RuneNode\n\tDecls      []EnumElement\n\tCloseBrace *RuneNode\n}\n\nfunc (*EnumNode) fileElement() {}\nfunc (*EnumNode) msgElement()  {}\n\n// NewEnumNode creates a new *EnumNode. All arguments must be non-nil. While\n// it is technically allowed for decls to be nil or empty, the resulting node\n// will not be a valid enum, which must have at least one value.\n//   - keyword: The token corresponding to the \"enum\" keyword.\n//   - name: The token corresponding to the enum's name.\n//   - openBrace: The token corresponding to the \"{\" rune that starts the body.\n//   - decls: All declarations inside the enum body.\n//   - closeBrace: The token corresponding to the \"}\" rune that ends the body.\nfunc NewEnumNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []EnumElement, closeBrace *RuneNode) *EnumNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif openBrace == nil {\n\t\tpanic(\"openBrace is nil\")\n\t}\n\tif closeBrace == nil {\n\t\tpanic(\"closeBrace is nil\")\n\t}\n\tchildren := make([]Node, 0, 4+len(decls))\n\tchildren = append(children, keyword, name, openBrace)\n\tfor _, decl := range decls {\n\t\tswitch decl.(type) {\n\t\tcase *OptionNode, *EnumValueNode, *ReservedNode, *EmptyDeclNode:\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"invalid EnumElement type: %T\", decl))\n\t\t}\n\t\tchildren = append(children, decl)\n\t}\n\tchildren = append(children, closeBrace)\n\n\treturn &EnumNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:    keyword,\n\t\tName:       name,\n\t\tOpenBrace:  openBrace,\n\t\tCloseBrace: closeBrace,\n\t\tDecls:      decls,\n\t}\n}\n\nfunc (n *EnumNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, decl := range n.Decls {\n\t\tif opt, ok := decl.(*OptionNode); ok {\n\t\t\tif !fn(opt) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// EnumElement is an interface implemented by all AST nodes that can\n// appear in the body of an enum declaration.\ntype EnumElement interface {\n\tNode\n\tenumElement()\n}\n\nvar _ EnumElement = (*OptionNode)(nil)\nvar _ EnumElement = (*EnumValueNode)(nil)\nvar _ EnumElement = (*ReservedNode)(nil)\nvar _ EnumElement = (*EmptyDeclNode)(nil)\n\n// EnumValueDeclNode is a placeholder interface for AST nodes that represent\n// enum values. This allows NoSourceNode to be used in place of *EnumValueNode\n// for some usages.\ntype EnumValueDeclNode interface {\n\tNodeWithOptions\n\tGetName() Node\n\tGetNumber() Node\n}\n\nvar _ EnumValueDeclNode = (*EnumValueNode)(nil)\nvar _ EnumValueDeclNode = (*NoSourceNode)(nil)\n\n// EnumValueNode represents an enum declaration. Example:\n//\n//\tUNSET = 0 [deprecated = true];\ntype EnumValueNode struct {\n\tcompositeNode\n\tName      *IdentNode\n\tEquals    *RuneNode\n\tNumber    IntValueNode\n\tOptions   *CompactOptionsNode\n\tSemicolon *RuneNode\n}\n\nfunc (*EnumValueNode) enumElement() {}\n\n// NewEnumValueNode creates a new *EnumValueNode. All arguments must be non-nil\n// except opts which is only non-nil if the declaration included options.\n//   - name: The token corresponding to the enum value's name.\n//   - equals: The token corresponding to the '=' rune after the name.\n//   - number: The token corresponding to the enum value's number.\n//   - opts: Optional set of enum value options.\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewEnumValueNode(name *IdentNode, equals *RuneNode, number IntValueNode, opts *CompactOptionsNode, semicolon *RuneNode) *EnumValueNode {\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif equals == nil {\n\t\tpanic(\"equals is nil\")\n\t}\n\tif number == nil {\n\t\tpanic(\"number is nil\")\n\t}\n\tnumChildren := 3\n\tif semicolon != nil {\n\t\tnumChildren++\n\t}\n\tif opts != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, name, equals, number)\n\tif opts != nil {\n\t\tchildren = append(children, opts)\n\t}\n\tif semicolon != nil {\n\t\tchildren = append(children, semicolon)\n\t}\n\treturn &EnumValueNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tName:      name,\n\t\tEquals:    equals,\n\t\tNumber:    number,\n\t\tOptions:   opts,\n\t\tSemicolon: semicolon,\n\t}\n}\n\nfunc (e *EnumValueNode) GetName() Node {\n\treturn e.Name\n}\n\nfunc (e *EnumValueNode) GetNumber() Node {\n\treturn e.Number\n}\n\nfunc (e *EnumValueNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, opt := range e.Options.Options {\n\t\tif !fn(opt) {\n\t\t\treturn\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/field.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// FieldDeclNode is a node in the AST that defines a field. This includes\n// normal message fields as well as extensions. There are multiple types\n// of AST nodes that declare fields:\n//   - *FieldNode\n//   - *GroupNode\n//   - *MapFieldNode\n//   - *SyntheticMapField\n//\n// This also allows NoSourceNode and SyntheticMapField to be used in place of\n// one of the above for some usages.\ntype FieldDeclNode interface {\n\tNodeWithOptions\n\tFieldLabel() Node\n\tFieldName() Node\n\tFieldType() Node\n\tFieldTag() Node\n\tFieldExtendee() Node\n\tGetGroupKeyword() Node\n\tGetOptions() *CompactOptionsNode\n}\n\nvar _ FieldDeclNode = (*FieldNode)(nil)\nvar _ FieldDeclNode = (*GroupNode)(nil)\nvar _ FieldDeclNode = (*MapFieldNode)(nil)\nvar _ FieldDeclNode = (*SyntheticMapField)(nil)\nvar _ FieldDeclNode = (*NoSourceNode)(nil)\n\n// FieldNode represents a normal field declaration (not groups or maps). It\n// can represent extension fields as well as non-extension fields (both inside\n// of messages and inside of one-ofs). Example:\n//\n//\toptional string foo = 1;\ntype FieldNode struct {\n\tcompositeNode\n\tLabel     FieldLabel\n\tFldType   IdentValueNode\n\tName      *IdentNode\n\tEquals    *RuneNode\n\tTag       *UintLiteralNode\n\tOptions   *CompactOptionsNode\n\tSemicolon *RuneNode\n\n\t// This is an up-link to the containing *ExtendNode for fields\n\t// that are defined inside of \"extend\" blocks.\n\tExtendee *ExtendNode\n}\n\nfunc (*FieldNode) msgElement()    {}\nfunc (*FieldNode) oneofElement()  {}\nfunc (*FieldNode) extendElement() {}\n\n// NewFieldNode creates a new *FieldNode. The label and options arguments may be\n// nil but the others must be non-nil.\n//   - label: The token corresponding to the label keyword if present (\"optional\",\n//     \"required\", or \"repeated\").\n//   - fieldType: The token corresponding to the field's type.\n//   - name: The token corresponding to the field's name.\n//   - equals: The token corresponding to the '=' rune after the name.\n//   - tag: The token corresponding to the field's tag number.\n//   - opts: Optional set of field options.\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewFieldNode(label *KeywordNode, fieldType IdentValueNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, semicolon *RuneNode) *FieldNode {\n\tif fieldType == nil {\n\t\tpanic(\"fieldType is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tnumChildren := 2\n\tif equals != nil {\n\t\tnumChildren++\n\t}\n\tif tag != nil {\n\t\tnumChildren++\n\t}\n\tif semicolon != nil {\n\t\tnumChildren++\n\t}\n\tif label != nil {\n\t\tnumChildren++\n\t}\n\tif opts != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tif label != nil {\n\t\tchildren = append(children, label)\n\t}\n\tchildren = append(children, fieldType, name)\n\tif equals != nil {\n\t\tchildren = append(children, equals)\n\t}\n\tif tag != nil {\n\t\tchildren = append(children, tag)\n\t}\n\tif opts != nil {\n\t\tchildren = append(children, opts)\n\t}\n\tif semicolon != nil {\n\t\tchildren = append(children, semicolon)\n\t}\n\n\treturn &FieldNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tLabel:     newFieldLabel(label),\n\t\tFldType:   fieldType,\n\t\tName:      name,\n\t\tEquals:    equals,\n\t\tTag:       tag,\n\t\tOptions:   opts,\n\t\tSemicolon: semicolon,\n\t}\n}\n\nfunc (n *FieldNode) FieldLabel() Node {\n\t// proto3 fields and fields inside one-ofs will not have a label and we need\n\t// this check in order to return a nil node -- otherwise we'd return a\n\t// non-nil node that has a nil pointer value in it :/\n\tif n.Label.KeywordNode == nil {\n\t\treturn nil\n\t}\n\treturn n.Label.KeywordNode\n}\n\nfunc (n *FieldNode) FieldName() Node {\n\treturn n.Name\n}\n\nfunc (n *FieldNode) FieldType() Node {\n\treturn n.FldType\n}\n\nfunc (n *FieldNode) FieldTag() Node {\n\tif n.Tag == nil {\n\t\treturn n\n\t}\n\treturn n.Tag\n}\n\nfunc (n *FieldNode) FieldExtendee() Node {\n\tif n.Extendee != nil {\n\t\treturn n.Extendee.Extendee\n\t}\n\treturn nil\n}\n\nfunc (n *FieldNode) GetGroupKeyword() Node {\n\treturn nil\n}\n\nfunc (n *FieldNode) GetOptions() *CompactOptionsNode {\n\treturn n.Options\n}\n\nfunc (n *FieldNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, opt := range n.Options.Options {\n\t\tif !fn(opt) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// FieldLabel represents the label of a field, which indicates its cardinality\n// (i.e. whether it is optional, required, or repeated).\ntype FieldLabel struct {\n\t*KeywordNode\n\tRepeated bool\n\tRequired bool\n}\n\nfunc newFieldLabel(lbl *KeywordNode) FieldLabel {\n\trepeated, required := false, false\n\tif lbl != nil {\n\t\trepeated = lbl.Val == \"repeated\"\n\t\trequired = lbl.Val == \"required\"\n\t}\n\treturn FieldLabel{\n\t\tKeywordNode: lbl,\n\t\tRepeated:    repeated,\n\t\tRequired:    required,\n\t}\n}\n\n// IsPresent returns true if a label keyword was present in the declaration\n// and false if it was absent.\nfunc (f *FieldLabel) IsPresent() bool {\n\treturn f.KeywordNode != nil\n}\n\n// GroupNode represents a group declaration, which doubles as a field and inline\n// message declaration. It can represent extension fields as well as\n// non-extension fields (both inside of messages and inside of one-ofs).\n// Example:\n//\n//\toptional group Key = 4 {\n//\t  optional uint64 id = 1;\n//\t  optional string name = 2;\n//\t}\ntype GroupNode struct {\n\tcompositeNode\n\tLabel   FieldLabel\n\tKeyword *KeywordNode\n\tName    *IdentNode\n\tEquals  *RuneNode\n\tTag     *UintLiteralNode\n\tOptions *CompactOptionsNode\n\tMessageBody\n\n\t// This is an up-link to the containing *ExtendNode for groups\n\t// that are defined inside of \"extend\" blocks.\n\tExtendee *ExtendNode\n}\n\nfunc (*GroupNode) msgElement()    {}\nfunc (*GroupNode) oneofElement()  {}\nfunc (*GroupNode) extendElement() {}\n\n// NewGroupNode creates a new *GroupNode. The label and options arguments may be\n// nil but the others must be non-nil.\n//   - label: The token corresponding to the label keyword if present (\"optional\",\n//     \"required\", or \"repeated\").\n//   - keyword: The token corresponding to the \"group\" keyword.\n//   - name: The token corresponding to the field's name.\n//   - equals: The token corresponding to the '=' rune after the name.\n//   - tag: The token corresponding to the field's tag number.\n//   - opts: Optional set of field options.\n//   - openBrace: The token corresponding to the \"{\" rune that starts the body.\n//   - decls: All declarations inside the group body.\n//   - closeBrace: The token corresponding to the \"}\" rune that ends the body.\nfunc NewGroupNode(label *KeywordNode, keyword *KeywordNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) *GroupNode {\n\tif keyword == nil {\n\t\tpanic(\"fieldType is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif openBrace == nil {\n\t\tpanic(\"openBrace is nil\")\n\t}\n\tif closeBrace == nil {\n\t\tpanic(\"closeBrace is nil\")\n\t}\n\tnumChildren := 4 + len(decls)\n\tif label != nil {\n\t\tnumChildren++\n\t}\n\tif equals != nil {\n\t\tnumChildren++\n\t}\n\tif tag != nil {\n\t\tnumChildren++\n\t}\n\tif opts != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tif label != nil {\n\t\tchildren = append(children, label)\n\t}\n\tchildren = append(children, keyword, name)\n\tif equals != nil {\n\t\tchildren = append(children, equals)\n\t}\n\tif tag != nil {\n\t\tchildren = append(children, tag)\n\t}\n\tif opts != nil {\n\t\tchildren = append(children, opts)\n\t}\n\tchildren = append(children, openBrace)\n\tfor _, decl := range decls {\n\t\tchildren = append(children, decl)\n\t}\n\tchildren = append(children, closeBrace)\n\n\tret := &GroupNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tLabel:   newFieldLabel(label),\n\t\tKeyword: keyword,\n\t\tName:    name,\n\t\tEquals:  equals,\n\t\tTag:     tag,\n\t\tOptions: opts,\n\t}\n\tpopulateMessageBody(&ret.MessageBody, openBrace, decls, closeBrace)\n\treturn ret\n}\n\nfunc (n *GroupNode) FieldLabel() Node {\n\tif n.Label.KeywordNode == nil {\n\t\t// return nil interface to indicate absence, not a typed nil\n\t\treturn nil\n\t}\n\treturn n.Label.KeywordNode\n}\n\nfunc (n *GroupNode) FieldName() Node {\n\treturn n.Name\n}\n\nfunc (n *GroupNode) FieldType() Node {\n\treturn n.Keyword\n}\n\nfunc (n *GroupNode) FieldTag() Node {\n\tif n.Tag == nil {\n\t\treturn n\n\t}\n\treturn n.Tag\n}\n\nfunc (n *GroupNode) FieldExtendee() Node {\n\tif n.Extendee != nil {\n\t\treturn n.Extendee.Extendee\n\t}\n\treturn nil\n}\n\nfunc (n *GroupNode) GetGroupKeyword() Node {\n\treturn n.Keyword\n}\n\nfunc (n *GroupNode) GetOptions() *CompactOptionsNode {\n\treturn n.Options\n}\n\nfunc (n *GroupNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, opt := range n.Options.Options {\n\t\tif !fn(opt) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (n *GroupNode) AsMessage() *SyntheticGroupMessageNode {\n\treturn (*SyntheticGroupMessageNode)(n)\n}\n\n// SyntheticGroupMessageNode is a view of a GroupNode that implements MessageDeclNode.\n// Since a group field implicitly defines a message type, this node represents\n// that message type while the corresponding GroupNode represents the field.\n//\n// This type is considered synthetic since it never appears in a file's AST, but\n// is only returned from other accessors (e.g. GroupNode.AsMessage).\ntype SyntheticGroupMessageNode GroupNode\n\nfunc (n *SyntheticGroupMessageNode) MessageName() Node {\n\treturn n.Name\n}\n\nfunc (n *SyntheticGroupMessageNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, decl := range n.Decls {\n\t\tif opt, ok := decl.(*OptionNode); ok {\n\t\t\tif !fn(opt) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// OneofDeclNode is a node in the AST that defines a oneof. There are\n// multiple types of AST nodes that declare oneofs:\n//   - *OneofNode\n//   - *SyntheticOneof\n//\n// This also allows NoSourceNode to be used in place of one of the above\n// for some usages.\ntype OneofDeclNode interface {\n\tNodeWithOptions\n\tOneofName() Node\n}\n\nvar _ OneofDeclNode = (*OneofNode)(nil)\nvar _ OneofDeclNode = (*SyntheticOneof)(nil)\nvar _ OneofDeclNode = (*NoSourceNode)(nil)\n\n// OneofNode represents a one-of declaration. Example:\n//\n//\toneof query {\n//\t  string by_name = 2;\n//\t  Type by_type = 3;\n//\t  Address by_address = 4;\n//\t  Labels by_label = 5;\n//\t}\ntype OneofNode struct {\n\tcompositeNode\n\tKeyword    *KeywordNode\n\tName       *IdentNode\n\tOpenBrace  *RuneNode\n\tDecls      []OneofElement\n\tCloseBrace *RuneNode\n}\n\nfunc (*OneofNode) msgElement() {}\n\n// NewOneofNode creates a new *OneofNode. All arguments must be non-nil. While\n// it is technically allowed for decls to be nil or empty, the resulting node\n// will not be a valid oneof, which must have at least one field.\n//   - keyword: The token corresponding to the \"oneof\" keyword.\n//   - name: The token corresponding to the oneof's name.\n//   - openBrace: The token corresponding to the \"{\" rune that starts the body.\n//   - decls: All declarations inside the oneof body.\n//   - closeBrace: The token corresponding to the \"}\" rune that ends the body.\nfunc NewOneofNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []OneofElement, closeBrace *RuneNode) *OneofNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif openBrace == nil {\n\t\tpanic(\"openBrace is nil\")\n\t}\n\tif closeBrace == nil {\n\t\tpanic(\"closeBrace is nil\")\n\t}\n\tchildren := make([]Node, 0, 4+len(decls))\n\tchildren = append(children, keyword, name, openBrace)\n\tfor _, decl := range decls {\n\t\tchildren = append(children, decl)\n\t}\n\tchildren = append(children, closeBrace)\n\n\tfor _, decl := range decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *OptionNode, *FieldNode, *GroupNode, *EmptyDeclNode:\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"invalid OneofElement type: %T\", decl))\n\t\t}\n\t}\n\n\treturn &OneofNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:    keyword,\n\t\tName:       name,\n\t\tOpenBrace:  openBrace,\n\t\tDecls:      decls,\n\t\tCloseBrace: closeBrace,\n\t}\n}\n\nfunc (n *OneofNode) OneofName() Node {\n\treturn n.Name\n}\n\nfunc (n *OneofNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, decl := range n.Decls {\n\t\tif opt, ok := decl.(*OptionNode); ok {\n\t\t\tif !fn(opt) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// OneofElement is an interface implemented by all AST nodes that can\n// appear in the body of a oneof declaration.\ntype OneofElement interface {\n\tNode\n\toneofElement()\n}\n\nvar _ OneofElement = (*OptionNode)(nil)\nvar _ OneofElement = (*FieldNode)(nil)\nvar _ OneofElement = (*GroupNode)(nil)\nvar _ OneofElement = (*EmptyDeclNode)(nil)\n\n// SyntheticOneof is not an actual node in the AST but a synthetic node\n// that represents the oneof implied by a proto3 optional field.\n//\n// This type is considered synthetic since it never appears in a file's AST,\n// but is only returned from other functions (e.g. NewSyntheticOneof).\ntype SyntheticOneof struct {\n\t// The proto3 optional field that implies the presence of this oneof.\n\tField *FieldNode\n}\n\nvar _ Node = (*SyntheticOneof)(nil)\n\n// NewSyntheticOneof creates a new *SyntheticOneof that corresponds to the\n// given proto3 optional field.\nfunc NewSyntheticOneof(field *FieldNode) *SyntheticOneof {\n\treturn &SyntheticOneof{Field: field}\n}\n\nfunc (n *SyntheticOneof) Start() Token {\n\treturn n.Field.Start()\n}\n\nfunc (n *SyntheticOneof) End() Token {\n\treturn n.Field.End()\n}\n\nfunc (n *SyntheticOneof) LeadingComments() []Comment {\n\treturn nil\n}\n\nfunc (n *SyntheticOneof) TrailingComments() []Comment {\n\treturn nil\n}\n\nfunc (n *SyntheticOneof) OneofName() Node {\n\treturn n.Field.FieldName()\n}\n\nfunc (n *SyntheticOneof) RangeOptions(_ func(*OptionNode) bool) {\n}\n\n// MapTypeNode represents the type declaration for a map field. It defines\n// both the key and value types for the map. Example:\n//\n//\tmap<string, Values>\ntype MapTypeNode struct {\n\tcompositeNode\n\tKeyword    *KeywordNode\n\tOpenAngle  *RuneNode\n\tKeyType    *IdentNode\n\tComma      *RuneNode\n\tValueType  IdentValueNode\n\tCloseAngle *RuneNode\n}\n\n// NewMapTypeNode creates a new *MapTypeNode. All arguments must be non-nil.\n//   - keyword: The token corresponding to the \"map\" keyword.\n//   - openAngle: The token corresponding to the \"<\" rune after the keyword.\n//   - keyType: The token corresponding to the key type for the map.\n//   - comma: The token corresponding to the \",\" rune between key and value types.\n//   - valType: The token corresponding to the value type for the map.\n//   - closeAngle: The token corresponding to the \">\" rune that ends the declaration.\nfunc NewMapTypeNode(keyword *KeywordNode, openAngle *RuneNode, keyType *IdentNode, comma *RuneNode, valType IdentValueNode, closeAngle *RuneNode) *MapTypeNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif openAngle == nil {\n\t\tpanic(\"openAngle is nil\")\n\t}\n\tif keyType == nil {\n\t\tpanic(\"keyType is nil\")\n\t}\n\tif comma == nil {\n\t\tpanic(\"comma is nil\")\n\t}\n\tif valType == nil {\n\t\tpanic(\"valType is nil\")\n\t}\n\tif closeAngle == nil {\n\t\tpanic(\"closeAngle is nil\")\n\t}\n\tchildren := []Node{keyword, openAngle, keyType, comma, valType, closeAngle}\n\treturn &MapTypeNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:    keyword,\n\t\tOpenAngle:  openAngle,\n\t\tKeyType:    keyType,\n\t\tComma:      comma,\n\t\tValueType:  valType,\n\t\tCloseAngle: closeAngle,\n\t}\n}\n\n// MapFieldNode represents a map field declaration. Example:\n//\n//\tmap<string,string> replacements = 3 [deprecated = true];\ntype MapFieldNode struct {\n\tcompositeNode\n\tMapType   *MapTypeNode\n\tName      *IdentNode\n\tEquals    *RuneNode\n\tTag       *UintLiteralNode\n\tOptions   *CompactOptionsNode\n\tSemicolon *RuneNode\n}\n\nfunc (*MapFieldNode) msgElement() {}\n\n// NewMapFieldNode creates a new *MapFieldNode. All arguments must be non-nil\n// except opts, which may be nil.\n//   - mapType: The token corresponding to the map type.\n//   - name: The token corresponding to the field's name.\n//   - equals: The token corresponding to the '=' rune after the name.\n//   - tag: The token corresponding to the field's tag number.\n//   - opts: Optional set of field options.\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewMapFieldNode(mapType *MapTypeNode, name *IdentNode, equals *RuneNode, tag *UintLiteralNode, opts *CompactOptionsNode, semicolon *RuneNode) *MapFieldNode {\n\tif mapType == nil {\n\t\tpanic(\"mapType is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tnumChildren := 2\n\tif equals != nil {\n\t\tnumChildren++\n\t}\n\tif tag != nil {\n\t\tnumChildren++\n\t}\n\tif opts != nil {\n\t\tnumChildren++\n\t}\n\tif semicolon != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, mapType, name)\n\tif equals != nil {\n\t\tchildren = append(children, equals)\n\t}\n\tif tag != nil {\n\t\tchildren = append(children, tag)\n\t}\n\tif opts != nil {\n\t\tchildren = append(children, opts)\n\t}\n\tif semicolon != nil {\n\t\tchildren = append(children, semicolon)\n\t}\n\n\treturn &MapFieldNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tMapType:   mapType,\n\t\tName:      name,\n\t\tEquals:    equals,\n\t\tTag:       tag,\n\t\tOptions:   opts,\n\t\tSemicolon: semicolon,\n\t}\n}\n\nfunc (n *MapFieldNode) FieldLabel() Node {\n\treturn nil\n}\n\nfunc (n *MapFieldNode) FieldName() Node {\n\treturn n.Name\n}\n\nfunc (n *MapFieldNode) FieldType() Node {\n\treturn n.MapType\n}\n\nfunc (n *MapFieldNode) FieldTag() Node {\n\tif n.Tag == nil {\n\t\treturn n\n\t}\n\treturn n.Tag\n}\n\nfunc (n *MapFieldNode) FieldExtendee() Node {\n\treturn nil\n}\n\nfunc (n *MapFieldNode) GetGroupKeyword() Node {\n\treturn nil\n}\n\nfunc (n *MapFieldNode) GetOptions() *CompactOptionsNode {\n\treturn n.Options\n}\n\nfunc (n *MapFieldNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, opt := range n.Options.Options {\n\t\tif !fn(opt) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (n *MapFieldNode) AsMessage() *SyntheticMapEntryNode {\n\treturn (*SyntheticMapEntryNode)(n)\n}\n\nfunc (n *MapFieldNode) KeyField() *SyntheticMapField {\n\treturn NewSyntheticMapField(n.MapType.KeyType, 1)\n}\n\nfunc (n *MapFieldNode) ValueField() *SyntheticMapField {\n\treturn NewSyntheticMapField(n.MapType.ValueType, 2)\n}\n\n// SyntheticMapEntryNode is a view of a MapFieldNode that implements MessageDeclNode.\n// Since a map field implicitly defines a message type for the map entry,\n// this node represents that message type.\n//\n// This type is considered synthetic since it never appears in a file's AST, but\n// is only returned from other accessors (e.g. MapFieldNode.AsMessage).\ntype SyntheticMapEntryNode MapFieldNode\n\nfunc (n *SyntheticMapEntryNode) MessageName() Node {\n\treturn n.Name\n}\n\nfunc (n *SyntheticMapEntryNode) RangeOptions(_ func(*OptionNode) bool) {\n}\n\n// SyntheticMapField is not an actual node in the AST but a synthetic node\n// that implements FieldDeclNode. These are used to represent the implicit\n// field declarations of the \"key\" and \"value\" fields in a map entry.\n//\n// This type is considered synthetic since it never appears in a file's AST,\n// but is only returned from other accessors and functions (e.g.\n// MapFieldNode.KeyField, MapFieldNode.ValueField, and NewSyntheticMapField).\ntype SyntheticMapField struct {\n\tIdent IdentValueNode\n\tTag   *UintLiteralNode\n}\n\n// NewSyntheticMapField creates a new *SyntheticMapField for the given\n// identifier (either a key or value type in a map declaration) and tag\n// number (1 for key, 2 for value).\nfunc NewSyntheticMapField(ident IdentValueNode, tagNum uint64) *SyntheticMapField {\n\ttag := &UintLiteralNode{\n\t\tterminalNode: ident.Start().asTerminalNode(),\n\t\tVal:          tagNum,\n\t}\n\treturn &SyntheticMapField{Ident: ident, Tag: tag}\n}\n\nfunc (n *SyntheticMapField) Start() Token {\n\treturn n.Ident.Start()\n}\n\nfunc (n *SyntheticMapField) End() Token {\n\treturn n.Ident.End()\n}\n\nfunc (n *SyntheticMapField) LeadingComments() []Comment {\n\treturn nil\n}\n\nfunc (n *SyntheticMapField) TrailingComments() []Comment {\n\treturn nil\n}\n\nfunc (n *SyntheticMapField) FieldLabel() Node {\n\treturn n.Ident\n}\n\nfunc (n *SyntheticMapField) FieldName() Node {\n\treturn n.Ident\n}\n\nfunc (n *SyntheticMapField) FieldType() Node {\n\treturn n.Ident\n}\n\nfunc (n *SyntheticMapField) FieldTag() Node {\n\tif n.Tag == nil {\n\t\treturn n\n\t}\n\treturn n.Tag\n}\n\nfunc (n *SyntheticMapField) FieldExtendee() Node {\n\treturn nil\n}\n\nfunc (n *SyntheticMapField) GetGroupKeyword() Node {\n\treturn nil\n}\n\nfunc (n *SyntheticMapField) GetOptions() *CompactOptionsNode {\n\treturn nil\n}\n\nfunc (n *SyntheticMapField) RangeOptions(_ func(*OptionNode) bool) {\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/file.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// FileDeclNode is a placeholder interface for AST nodes that represent files.\n// This allows NoSourceNode to be used in place of *FileNode for some usages.\ntype FileDeclNode interface {\n\tNodeWithOptions\n\tName() string\n\tNodeInfo(n Node) NodeInfo\n}\n\nvar _ FileDeclNode = (*FileNode)(nil)\nvar _ FileDeclNode = (*NoSourceNode)(nil)\n\n// FileNode is the root of the AST hierarchy. It represents an entire\n// protobuf source file.\ntype FileNode struct {\n\tcompositeNode\n\tfileInfo *FileInfo\n\n\t// A file has either a Syntax or Edition node, never both.\n\t// If both are nil, neither declaration is present and the\n\t// file is assumed to use \"proto2\" syntax.\n\tSyntax  *SyntaxNode\n\tEdition *EditionNode\n\n\tDecls []FileElement\n\n\t// This synthetic node allows access to final comments and whitespace\n\tEOF *RuneNode\n}\n\n// NewFileNode creates a new *FileNode. The syntax parameter is optional. If it\n// is absent, it means the file had no syntax declaration.\n//\n// This function panics if the concrete type of any element of decls is not\n// from this package.\nfunc NewFileNode(info *FileInfo, syntax *SyntaxNode, decls []FileElement, eof Token) *FileNode {\n\treturn newFileNode(info, syntax, nil, decls, eof)\n}\n\n// NewFileNodeWithEdition creates a new *FileNode. The edition parameter is required. If a file\n// has no edition declaration, use NewFileNode instead.\n//\n// This function panics if the concrete type of any element of decls is not\n// from this package.\nfunc NewFileNodeWithEdition(info *FileInfo, edition *EditionNode, decls []FileElement, eof Token) *FileNode {\n\tif edition == nil {\n\t\tpanic(\"edition is nil\")\n\t}\n\treturn newFileNode(info, nil, edition, decls, eof)\n}\n\nfunc newFileNode(info *FileInfo, syntax *SyntaxNode, edition *EditionNode, decls []FileElement, eof Token) *FileNode {\n\tnumChildren := len(decls) + 1\n\tif syntax != nil || edition != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tif syntax != nil {\n\t\tchildren = append(children, syntax)\n\t} else if edition != nil {\n\t\tchildren = append(children, edition)\n\t}\n\tfor _, decl := range decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *PackageNode, *ImportNode, *OptionNode, *MessageNode,\n\t\t\t*EnumNode, *ExtendNode, *ServiceNode, *EmptyDeclNode:\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"invalid FileElement type: %T\", decl))\n\t\t}\n\t\tchildren = append(children, decl)\n\t}\n\n\teofNode := NewRuneNode(0, eof)\n\tchildren = append(children, eofNode)\n\n\treturn &FileNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tfileInfo: info,\n\t\tSyntax:   syntax,\n\t\tEdition:  edition,\n\t\tDecls:    decls,\n\t\tEOF:      eofNode,\n\t}\n}\n\n// NewEmptyFileNode returns an empty AST for a file with the given name.\nfunc NewEmptyFileNode(filename string) *FileNode {\n\tfileInfo := NewFileInfo(filename, []byte{})\n\treturn NewFileNode(fileInfo, nil, nil, fileInfo.AddToken(0, 0))\n}\n\nfunc (f *FileNode) Name() string {\n\treturn f.fileInfo.Name()\n}\n\nfunc (f *FileNode) NodeInfo(n Node) NodeInfo {\n\treturn f.fileInfo.NodeInfo(n)\n}\n\nfunc (f *FileNode) TokenInfo(t Token) NodeInfo {\n\treturn f.fileInfo.TokenInfo(t)\n}\n\nfunc (f *FileNode) ItemInfo(i Item) ItemInfo {\n\treturn f.fileInfo.ItemInfo(i)\n}\n\nfunc (f *FileNode) GetItem(i Item) (Token, Comment) {\n\treturn f.fileInfo.GetItem(i)\n}\n\nfunc (f *FileNode) Items() Sequence[Item] {\n\treturn f.fileInfo.Items()\n}\n\nfunc (f *FileNode) Tokens() Sequence[Token] {\n\treturn f.fileInfo.Tokens()\n}\n\nfunc (f *FileNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, decl := range f.Decls {\n\t\tif opt, ok := decl.(*OptionNode); ok {\n\t\t\tif !fn(opt) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// FileElement is an interface implemented by all AST nodes that are\n// allowed as top-level declarations in the file.\ntype FileElement interface {\n\tNode\n\tfileElement()\n}\n\nvar _ FileElement = (*ImportNode)(nil)\nvar _ FileElement = (*PackageNode)(nil)\nvar _ FileElement = (*OptionNode)(nil)\nvar _ FileElement = (*MessageNode)(nil)\nvar _ FileElement = (*EnumNode)(nil)\nvar _ FileElement = (*ExtendNode)(nil)\nvar _ FileElement = (*ServiceNode)(nil)\nvar _ FileElement = (*EmptyDeclNode)(nil)\n\n// SyntaxNode represents a syntax declaration, which if present must be\n// the first non-comment content. Example:\n//\n//\tsyntax = \"proto2\";\n//\n// Files that don't have a syntax node are assumed to use proto2 syntax.\ntype SyntaxNode struct {\n\tcompositeNode\n\tKeyword   *KeywordNode\n\tEquals    *RuneNode\n\tSyntax    StringValueNode\n\tSemicolon *RuneNode\n}\n\n// NewSyntaxNode creates a new *SyntaxNode. All four arguments must be non-nil:\n//   - keyword: The token corresponding to the \"syntax\" keyword.\n//   - equals: The token corresponding to the \"=\" rune.\n//   - syntax: The actual syntax value, e.g. \"proto2\" or \"proto3\".\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewSyntaxNode(keyword *KeywordNode, equals *RuneNode, syntax StringValueNode, semicolon *RuneNode) *SyntaxNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif equals == nil {\n\t\tpanic(\"equals is nil\")\n\t}\n\tif syntax == nil {\n\t\tpanic(\"syntax is nil\")\n\t}\n\tvar children []Node\n\tif semicolon == nil {\n\t\tchildren = []Node{keyword, equals, syntax}\n\t} else {\n\t\tchildren = []Node{keyword, equals, syntax, semicolon}\n\t}\n\treturn &SyntaxNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tEquals:    equals,\n\t\tSyntax:    syntax,\n\t\tSemicolon: semicolon,\n\t}\n}\n\n// EditionNode represents an edition declaration, which if present must be\n// the first non-comment content. Example:\n//\n//\tedition = \"2023\";\n//\n// Files may include either an edition node or a syntax node, but not both.\n// If neither are present, the file is assumed to use proto2 syntax.\ntype EditionNode struct {\n\tcompositeNode\n\tKeyword   *KeywordNode\n\tEquals    *RuneNode\n\tEdition   StringValueNode\n\tSemicolon *RuneNode\n}\n\n// NewEditionNode creates a new *EditionNode. All four arguments must be non-nil:\n//   - keyword: The token corresponding to the \"edition\" keyword.\n//   - equals: The token corresponding to the \"=\" rune.\n//   - edition: The actual edition value, e.g. \"2023\".\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewEditionNode(keyword *KeywordNode, equals *RuneNode, edition StringValueNode, semicolon *RuneNode) *EditionNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif equals == nil {\n\t\tpanic(\"equals is nil\")\n\t}\n\tif edition == nil {\n\t\tpanic(\"edition is nil\")\n\t}\n\tif semicolon == nil {\n\t\tpanic(\"semicolon is nil\")\n\t}\n\tchildren := []Node{keyword, equals, edition, semicolon}\n\treturn &EditionNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tEquals:    equals,\n\t\tEdition:   edition,\n\t\tSemicolon: semicolon,\n\t}\n}\n\n// ImportNode represents an import statement. Example:\n//\n//\timport \"google/protobuf/empty.proto\";\ntype ImportNode struct {\n\tcompositeNode\n\tKeyword *KeywordNode\n\t// Optional; if present indicates this is a public import\n\tPublic *KeywordNode\n\t// Optional; if present indicates this is a weak import\n\tWeak      *KeywordNode\n\tName      StringValueNode\n\tSemicolon *RuneNode\n}\n\n// NewImportNode creates a new *ImportNode. The public and weak arguments are optional\n// and only one or the other (or neither) may be specified, not both. When public is\n// non-nil, it indicates the \"public\" keyword in the import statement and means this is\n// a public import. When weak is non-nil, it indicates the \"weak\" keyword in the import\n// statement and means this is a weak import. When both are nil, this is a normal import.\n// The other arguments must be non-nil:\n//   - keyword: The token corresponding to the \"import\" keyword.\n//   - public: The token corresponding to the optional \"public\" keyword.\n//   - weak: The token corresponding to the optional \"weak\" keyword.\n//   - name: The actual imported file name.\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewImportNode(keyword *KeywordNode, public *KeywordNode, weak *KeywordNode, name StringValueNode, semicolon *RuneNode) *ImportNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tnumChildren := 2\n\tif semicolon == nil {\n\t\tnumChildren++\n\t}\n\tif public != nil || weak != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, keyword)\n\tif public != nil {\n\t\tchildren = append(children, public)\n\t} else if weak != nil {\n\t\tchildren = append(children, weak)\n\t}\n\tchildren = append(children, name)\n\tif semicolon != nil {\n\t\tchildren = append(children, semicolon)\n\t}\n\n\treturn &ImportNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tPublic:    public,\n\t\tWeak:      weak,\n\t\tName:      name,\n\t\tSemicolon: semicolon,\n\t}\n}\n\nfunc (*ImportNode) fileElement() {}\n\n// PackageNode represents a package declaration. Example:\n//\n//\tpackage foobar.com;\ntype PackageNode struct {\n\tcompositeNode\n\tKeyword   *KeywordNode\n\tName      IdentValueNode\n\tSemicolon *RuneNode\n}\n\nfunc (*PackageNode) fileElement() {}\n\n// NewPackageNode creates a new *PackageNode. All three arguments must be non-nil:\n//   - keyword: The token corresponding to the \"package\" keyword.\n//   - name: The package name declared for the file.\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewPackageNode(keyword *KeywordNode, name IdentValueNode, semicolon *RuneNode) *PackageNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tvar children []Node\n\tif semicolon == nil {\n\t\tchildren = []Node{keyword, name}\n\t} else {\n\t\tchildren = []Node{keyword, name, semicolon}\n\t}\n\treturn &PackageNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tName:      name,\n\t\tSemicolon: semicolon,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/file_info.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"unicode/utf8\"\n)\n\n// FileInfo contains information about the contents of a source file, including\n// details about comments and items. A lexer accumulates these details as it\n// scans the file contents. This allows efficient representation of things like\n// source positions.\ntype FileInfo struct {\n\t// The name of the source file.\n\tname string\n\t// The raw contents of the source file.\n\tdata []byte\n\t// The offsets for each line in the file. The value is the zero-based byte\n\t// offset for a given line. The line is given by its index. So the value at\n\t// index 0 is the offset for the first line (which is always zero). The\n\t// value at index 1 is the offset at which the second line begins. Etc.\n\tlines []int\n\t// The info for every comment in the file. This is empty if the file has no\n\t// comments. The first entry corresponds to the first comment in the file,\n\t// and so on.\n\tcomments []commentInfo\n\t// The info for every lexed item in the file. The last item in the slice\n\t// corresponds to the EOF, so every file (even an empty one) should have at\n\t// least one entry. This includes all terminal symbols (tokens) in the AST\n\t// as well as all comments.\n\titems []itemSpan\n}\n\ntype commentInfo struct {\n\t// the index of the item, in the file's items slice, that represents this\n\t// comment\n\tindex int\n\t// the index of the token to which this comment is attributed.\n\tattributedToIndex int\n}\n\ntype itemSpan struct {\n\t// the offset into the file of the first character of an item.\n\toffset int\n\t// the length of the item\n\tlength int\n}\n\n// NewFileInfo creates a new instance for the given file.\nfunc NewFileInfo(filename string, contents []byte) *FileInfo {\n\treturn &FileInfo{\n\t\tname:  filename,\n\t\tdata:  contents,\n\t\tlines: []int{0},\n\t}\n}\n\nfunc (f *FileInfo) Name() string {\n\treturn f.name\n}\n\n// AddLine adds the offset representing the beginning of the \"next\" line in the file.\n// The first line always starts at offset 0, the second line starts at offset-of-newline-char+1.\nfunc (f *FileInfo) AddLine(offset int) {\n\tif offset < 0 {\n\t\tpanic(fmt.Sprintf(\"invalid offset: %d must not be negative\", offset))\n\t}\n\tif offset > len(f.data) {\n\t\tpanic(fmt.Sprintf(\"invalid offset: %d is greater than file size %d\", offset, len(f.data)))\n\t}\n\n\tif len(f.lines) > 0 {\n\t\tlastOffset := f.lines[len(f.lines)-1]\n\t\tif offset <= lastOffset {\n\t\t\tpanic(fmt.Sprintf(\"invalid offset: %d is not greater than previously observed line offset %d\", offset, lastOffset))\n\t\t}\n\t}\n\n\tf.lines = append(f.lines, offset)\n}\n\n// AddToken adds info about a token at the given location to this file. It\n// returns a value that allows access to all of the token's details.\nfunc (f *FileInfo) AddToken(offset, length int) Token {\n\tif offset < 0 {\n\t\tpanic(fmt.Sprintf(\"invalid offset: %d must not be negative\", offset))\n\t}\n\tif length < 0 {\n\t\tpanic(fmt.Sprintf(\"invalid length: %d must not be negative\", length))\n\t}\n\tif offset+length > len(f.data) {\n\t\tpanic(fmt.Sprintf(\"invalid offset+length: %d is greater than file size %d\", offset+length, len(f.data)))\n\t}\n\n\ttokenID := len(f.items)\n\tif len(f.items) > 0 {\n\t\tlastToken := f.items[tokenID-1]\n\t\tlastEnd := lastToken.offset + lastToken.length - 1\n\t\tif offset <= lastEnd {\n\t\t\tpanic(fmt.Sprintf(\"invalid offset: %d is not greater than previously observed token end %d\", offset, lastEnd))\n\t\t}\n\t}\n\n\tf.items = append(f.items, itemSpan{offset: offset, length: length})\n\treturn Token(tokenID)\n}\n\n// AddComment adds info about a comment to this file. Comments must first be\n// added as items via f.AddToken(). The given comment argument is the Token\n// from that step. The given attributedTo argument indicates another token in the\n// file with which the comment is associated. If comment's offset is before that\n// of attributedTo, then this is a leading comment. Otherwise, it is a trailing\n// comment.\nfunc (f *FileInfo) AddComment(comment, attributedTo Token) Comment {\n\tif len(f.comments) > 0 {\n\t\tlastComment := f.comments[len(f.comments)-1]\n\t\tif int(comment) <= lastComment.index {\n\t\t\tpanic(fmt.Sprintf(\"invalid index: %d is not greater than previously observed comment index %d\", comment, lastComment.index))\n\t\t}\n\t\tif int(attributedTo) < lastComment.attributedToIndex {\n\t\t\tpanic(fmt.Sprintf(\"invalid attribution: %d is not greater than previously observed comment attribution index %d\", attributedTo, lastComment.attributedToIndex))\n\t\t}\n\t}\n\n\tf.comments = append(f.comments, commentInfo{index: int(comment), attributedToIndex: int(attributedTo)})\n\treturn Comment{\n\t\tfileInfo: f,\n\t\tindex:    len(f.comments) - 1,\n\t}\n}\n\n// NodeInfo returns details from the original source for the given AST node.\n//\n// If the given n is out of range, this returns an invalid NodeInfo (i.e.\n// nodeInfo.IsValid() returns false). If the given n is not out of range but\n// also from a different file than f, then the result is undefined.\nfunc (f *FileInfo) NodeInfo(n Node) NodeInfo {\n\treturn f.nodeInfo(int(n.Start()), int(n.End()))\n}\n\n// TokenInfo returns details from the original source for the given token.\n//\n// If the given t is out of range, this returns an invalid NodeInfo (i.e.\n// nodeInfo.IsValid() returns false). If the given t is not out of range but\n// also from a different file than f, then the result is undefined.\nfunc (f *FileInfo) TokenInfo(t Token) NodeInfo {\n\treturn f.nodeInfo(int(t), int(t))\n}\n\nfunc (f *FileInfo) nodeInfo(start, end int) NodeInfo {\n\tif start < 0 || start >= len(f.items) {\n\t\treturn NodeInfo{fileInfo: f}\n\t}\n\tif end < 0 || end >= len(f.items) {\n\t\treturn NodeInfo{fileInfo: f}\n\t}\n\treturn NodeInfo{fileInfo: f, startIndex: start, endIndex: end}\n}\n\n// ItemInfo returns details from the original source for the given item.\n//\n// If the given i is out of range, this returns nil. If the given i is not\n// out of range but also from a different file than f, then the result is\n// undefined.\nfunc (f *FileInfo) ItemInfo(i Item) ItemInfo {\n\ttok, cmt := f.GetItem(i)\n\tif tok != TokenError {\n\t\treturn f.TokenInfo(tok)\n\t}\n\tif cmt.IsValid() {\n\t\treturn cmt\n\t}\n\treturn nil\n}\n\n// GetItem returns the token or comment represented by the given item. Only one\n// of the return values will be valid. If the item is a token then the returned\n// comment will be a zero value and thus invalid (i.e. comment.IsValid() returns\n// false). If the item is a comment then the returned token will be TokenError.\n//\n// If the given i is out of range, this returns (TokenError, Comment{}). If the\n// given i is not out of range but also from a different file than f, then\n// the result is undefined.\nfunc (f *FileInfo) GetItem(i Item) (Token, Comment) {\n\tif i < 0 || int(i) >= len(f.items) {\n\t\treturn TokenError, Comment{}\n\t}\n\tif !f.isComment(i) {\n\t\treturn Token(i), Comment{}\n\t}\n\t// It's a comment, so find its location in f.comments\n\tc := sort.Search(len(f.comments), func(c int) bool {\n\t\treturn f.comments[c].index >= int(i)\n\t})\n\tif c < len(f.comments) && f.comments[c].index == int(i) {\n\t\treturn TokenError, Comment{fileInfo: f, index: c}\n\t}\n\t// f.isComment(i) returned true, but we couldn't find it\n\t// in f.comments? Uh oh... that shouldn't be possible.\n\treturn TokenError, Comment{}\n}\n\nfunc (f *FileInfo) isDummyFile() bool {\n\treturn f == nil || f.lines == nil\n}\n\n// Sequence represents a navigable sequence of elements.\ntype Sequence[T any] interface {\n\t// First returns the first element in the sequence. The bool return\n\t// is false if this sequence contains no elements. For example, an\n\t// empty file has no items or tokens.\n\tFirst() (T, bool)\n\t// Next returns the next element in the sequence that comes after\n\t// the given element. The bool returns is false if there is no next\n\t// item (i.e. the given element is the last one). It also returns\n\t// false if the given element is invalid.\n\tNext(T) (T, bool)\n\t// Last returns the last element in the sequence. The bool return\n\t// is false if this sequence contains no elements. For example, an\n\t// empty file has no items or tokens.\n\tLast() (T, bool)\n\t// Previous returns the previous element in the sequence that comes\n\t// before the given element. The bool returns is false if there is no\n\t// previous item (i.e. the given element is the first one). It also\n\t// returns false if the given element is invalid.\n\tPrevious(T) (T, bool)\n}\n\nfunc (f *FileInfo) Items() Sequence[Item] {\n\treturn items{fileInfo: f}\n}\n\nfunc (f *FileInfo) Tokens() Sequence[Token] {\n\treturn tokens{fileInfo: f}\n}\n\ntype items struct {\n\tfileInfo *FileInfo\n}\n\nfunc (i items) First() (Item, bool) {\n\tif len(i.fileInfo.items) == 0 {\n\t\treturn 0, false\n\t}\n\treturn 0, true\n}\n\nfunc (i items) Next(item Item) (Item, bool) {\n\tif item < 0 || int(item) >= len(i.fileInfo.items)-1 {\n\t\treturn 0, false\n\t}\n\treturn i.fileInfo.itemForward(item+1, true)\n}\n\nfunc (i items) Last() (Item, bool) {\n\tif len(i.fileInfo.items) == 0 {\n\t\treturn 0, false\n\t}\n\treturn Item(len(i.fileInfo.items) - 1), true\n}\n\nfunc (i items) Previous(item Item) (Item, bool) {\n\tif item <= 0 || int(item) >= len(i.fileInfo.items) {\n\t\treturn 0, false\n\t}\n\treturn i.fileInfo.itemBackward(item-1, true)\n}\n\ntype tokens struct {\n\tfileInfo *FileInfo\n}\n\nfunc (t tokens) First() (Token, bool) {\n\ti, ok := t.fileInfo.itemForward(0, false)\n\treturn Token(i), ok\n}\n\nfunc (t tokens) Next(tok Token) (Token, bool) {\n\tif tok < 0 || int(tok) >= len(t.fileInfo.items)-1 {\n\t\treturn 0, false\n\t}\n\ti, ok := t.fileInfo.itemForward(Item(tok+1), false)\n\treturn Token(i), ok\n}\n\nfunc (t tokens) Last() (Token, bool) {\n\ti, ok := t.fileInfo.itemBackward(Item(len(t.fileInfo.items))-1, false)\n\treturn Token(i), ok\n}\n\nfunc (t tokens) Previous(tok Token) (Token, bool) {\n\tif tok <= 0 || int(tok) >= len(t.fileInfo.items) {\n\t\treturn 0, false\n\t}\n\ti, ok := t.fileInfo.itemBackward(Item(tok-1), false)\n\treturn Token(i), ok\n}\n\nfunc (f *FileInfo) itemForward(i Item, allowComment bool) (Item, bool) {\n\tend := Item(len(f.items))\n\tfor i < end {\n\t\tif allowComment || !f.isComment(i) {\n\t\t\treturn i, true\n\t\t}\n\t\ti++\n\t}\n\treturn 0, false\n}\n\nfunc (f *FileInfo) itemBackward(i Item, allowComment bool) (Item, bool) {\n\tfor i >= 0 {\n\t\tif allowComment || !f.isComment(i) {\n\t\t\treturn i, true\n\t\t}\n\t\ti--\n\t}\n\treturn 0, false\n}\n\n// isComment is comment returns true if i refers to a comment.\n// (If it returns false, i refers to a token.)\nfunc (f *FileInfo) isComment(i Item) bool {\n\titem := f.items[i]\n\tif item.length < 2 {\n\t\treturn false\n\t}\n\t// see if item text starts with \"//\" or \"/*\"\n\tif f.data[item.offset] != '/' {\n\t\treturn false\n\t}\n\tc := f.data[item.offset+1]\n\treturn c == '/' || c == '*'\n}\n\nfunc (f *FileInfo) SourcePos(offset int) SourcePos {\n\tlineNumber := sort.Search(len(f.lines), func(n int) bool {\n\t\treturn f.lines[n] > offset\n\t})\n\n\t// If it weren't for tabs and multibyte unicode characters, we\n\t// could trivially compute the column just based on offset and the\n\t// starting offset of lineNumber :(\n\t// Wish this were more efficient... that would require also storing\n\t// computed line+column information, which would triple the size of\n\t// f's items slice...\n\tcol := 0\n\tfor i := f.lines[lineNumber-1]; i < offset; i++ {\n\t\tif f.data[i] == '\\t' {\n\t\t\tnextTabStop := 8 - (col % 8)\n\t\t\tcol += nextTabStop\n\t\t} else if utf8.RuneStart(f.data[i]) {\n\t\t\tcol++\n\t\t}\n\t}\n\n\treturn SourcePos{\n\t\tFilename: f.name,\n\t\tOffset:   offset,\n\t\tLine:     lineNumber,\n\t\t// Columns are 1-indexed in this AST\n\t\tCol: col + 1,\n\t}\n}\n\n// Token represents a single lexed token.\ntype Token int\n\n// TokenError indicates an invalid token. It is returned from query\n// functions when no valid token satisfies the request.\nconst TokenError = Token(-1)\n\n// AsItem returns the Item that corresponds to t.\nfunc (t Token) AsItem() Item {\n\treturn Item(t)\n}\n\nfunc (t Token) asTerminalNode() terminalNode {\n\treturn terminalNode(t)\n}\n\n// Item represents an item lexed from source. It represents either\n// a Token or a Comment.\ntype Item int\n\n// ItemInfo provides details about an item's location in the source file and\n// its contents.\ntype ItemInfo interface {\n\tSourceSpan\n\tLeadingWhitespace() string\n\tRawText() string\n}\n\n// NodeInfo represents the details for a node or token in the source file's AST.\n// It provides access to information about the node's location in the source\n// file. It also provides access to the original text in the source file (with\n// all the original formatting intact) and also provides access to surrounding\n// comments.\ntype NodeInfo struct {\n\tfileInfo             *FileInfo\n\tstartIndex, endIndex int\n}\n\nvar _ ItemInfo = NodeInfo{}\n\n// IsValid returns true if this node info is valid. If n is a zero-value struct,\n// it is not valid.\nfunc (n NodeInfo) IsValid() bool {\n\treturn n.fileInfo != nil\n}\n\n// Start returns the starting position of the element. This is the first\n// character of the node or token.\nfunc (n NodeInfo) Start() SourcePos {\n\tif n.fileInfo.isDummyFile() {\n\t\treturn UnknownPos(n.fileInfo.name)\n\t}\n\n\ttok := n.fileInfo.items[n.startIndex]\n\treturn n.fileInfo.SourcePos(tok.offset)\n}\n\n// End returns the ending position of the element, exclusive. This is the\n// location after the last character of the node or token. If n returns\n// the same position for Start() and End(), the element in source had a\n// length of zero (which should only happen for the special EOF token\n// that designates the end of the file).\nfunc (n NodeInfo) End() SourcePos {\n\tif n.fileInfo.isDummyFile() {\n\t\treturn UnknownPos(n.fileInfo.name)\n\t}\n\n\ttok := n.fileInfo.items[n.endIndex]\n\t// find offset of last character in the span\n\toffset := tok.offset\n\tif tok.length > 0 {\n\t\toffset += tok.length - 1\n\t}\n\tpos := n.fileInfo.SourcePos(offset)\n\tif tok.length > 0 {\n\t\t// We return \"open range\", so end is the position *after* the\n\t\t// last character in the span. So we adjust\n\t\tpos.Col++\n\t}\n\treturn pos\n}\n\n// LeadingWhitespace returns any whitespace prior to the element. If there\n// were comments in between this element and the previous one, this will\n// return the whitespace between the last such comment in the element. If\n// there were no such comments, this returns the whitespace between the\n// previous element and the current one.\nfunc (n NodeInfo) LeadingWhitespace() string {\n\tif n.fileInfo.isDummyFile() {\n\t\treturn \"\"\n\t}\n\n\ttok := n.fileInfo.items[n.startIndex]\n\tvar prevEnd int\n\tif n.startIndex > 0 {\n\t\tprevTok := n.fileInfo.items[n.startIndex-1]\n\t\tprevEnd = prevTok.offset + prevTok.length\n\t}\n\treturn string(n.fileInfo.data[prevEnd:tok.offset])\n}\n\n// LeadingComments returns all comments in the source that exist between the\n// element and the previous element, except for any trailing comment on the\n// previous element.\nfunc (n NodeInfo) LeadingComments() Comments {\n\tif n.fileInfo.isDummyFile() {\n\t\treturn EmptyComments\n\t}\n\n\tstart := sort.Search(len(n.fileInfo.comments), func(i int) bool {\n\t\treturn n.fileInfo.comments[i].attributedToIndex >= n.startIndex\n\t})\n\n\tif start == len(n.fileInfo.comments) || n.fileInfo.comments[start].attributedToIndex != n.startIndex {\n\t\t// no comments associated with this token\n\t\treturn EmptyComments\n\t}\n\n\tnumComments := 0\n\tfor i := start; i < len(n.fileInfo.comments); i++ {\n\t\tcomment := n.fileInfo.comments[i]\n\t\tif comment.attributedToIndex == n.startIndex &&\n\t\t\tcomment.index < n.startIndex {\n\t\t\tnumComments++\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn Comments{\n\t\tfileInfo: n.fileInfo,\n\t\tfirst:    start,\n\t\tnum:      numComments,\n\t}\n}\n\n// TrailingComments returns the trailing comment for the element, if any.\n// An element will have a trailing comment only if it is the last token\n// on a line and is followed by a comment on the same line. Typically, the\n// following comment is a line-style comment (starting with \"//\").\n//\n// If the following comment is a block-style comment that spans multiple\n// lines, and the next token is on the same line as the end of the comment,\n// the comment is NOT considered a trailing comment.\n//\n// Examples:\n//\n//\tfoo // this is a trailing comment for foo\n//\n//\tbar /* this is a trailing comment for bar */\n//\n//\tbaz /* this is a trailing\n//\t       comment for baz */\n//\n//\tfizz /* this is NOT a trailing\n//\t        comment for fizz because\n//\t        its on the same line as the\n//\t        following token buzz */       buzz\nfunc (n NodeInfo) TrailingComments() Comments {\n\tif n.fileInfo.isDummyFile() {\n\t\treturn EmptyComments\n\t}\n\n\tstart := sort.Search(len(n.fileInfo.comments), func(i int) bool {\n\t\tcomment := n.fileInfo.comments[i]\n\t\treturn comment.attributedToIndex >= n.endIndex &&\n\t\t\tcomment.index > n.endIndex\n\t})\n\n\tif start == len(n.fileInfo.comments) || n.fileInfo.comments[start].attributedToIndex != n.endIndex {\n\t\t// no comments associated with this token\n\t\treturn EmptyComments\n\t}\n\n\tnumComments := 0\n\tfor i := start; i < len(n.fileInfo.comments); i++ {\n\t\tcomment := n.fileInfo.comments[i]\n\t\tif comment.attributedToIndex == n.endIndex {\n\t\t\tnumComments++\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn Comments{\n\t\tfileInfo: n.fileInfo,\n\t\tfirst:    start,\n\t\tnum:      numComments,\n\t}\n}\n\n// RawText returns the actual text in the source file that corresponds to the\n// element. If the element is a node in the AST that encompasses multiple\n// items (like an entire declaration), the full text of all items is returned\n// including any interior whitespace and comments.\nfunc (n NodeInfo) RawText() string {\n\tstartTok := n.fileInfo.items[n.startIndex]\n\tendTok := n.fileInfo.items[n.endIndex]\n\treturn string(n.fileInfo.data[startTok.offset : endTok.offset+endTok.length])\n}\n\n// SourcePos identifies a location in a proto source file.\ntype SourcePos struct {\n\tFilename string\n\t// The line and column numbers for this position. These are\n\t// one-based, so the first line and column is 1 (not zero). If\n\t// either is zero, then the line and column are unknown and\n\t// only the file name is known.\n\tLine, Col int\n\t// The offset, in bytes, from the beginning of the file. This\n\t// is zero-based: the first character in the file is offset zero.\n\tOffset int\n}\n\nfunc (pos SourcePos) String() string {\n\tif pos.Line <= 0 || pos.Col <= 0 {\n\t\treturn pos.Filename\n\t}\n\treturn fmt.Sprintf(\"%s:%d:%d\", pos.Filename, pos.Line, pos.Col)\n}\n\n// SourceSpan represents a range of source positions.\ntype SourceSpan interface {\n\tStart() SourcePos\n\tEnd() SourcePos\n}\n\n// NewSourceSpan creates a new span that covers the given range.\nfunc NewSourceSpan(start SourcePos, end SourcePos) SourceSpan {\n\treturn sourceSpan{StartPos: start, EndPos: end}\n}\n\ntype sourceSpan struct {\n\tStartPos SourcePos\n\tEndPos   SourcePos\n}\n\nfunc (p sourceSpan) Start() SourcePos {\n\treturn p.StartPos\n}\n\nfunc (p sourceSpan) End() SourcePos {\n\treturn p.EndPos\n}\n\nvar _ SourceSpan = sourceSpan{}\n\n// Comments represents a range of sequential comments in a source file\n// (e.g. no interleaving items or AST nodes).\ntype Comments struct {\n\tfileInfo   *FileInfo\n\tfirst, num int\n}\n\n// EmptyComments is an empty set of comments.\nvar EmptyComments = Comments{}\n\n// Len returns the number of comments in c.\nfunc (c Comments) Len() int {\n\treturn c.num\n}\n\nfunc (c Comments) Index(i int) Comment {\n\tif i < 0 || i >= c.num {\n\t\tpanic(fmt.Sprintf(\"index %d out of range (len = %d)\", i, c.num))\n\t}\n\treturn Comment{\n\t\tfileInfo: c.fileInfo,\n\t\tindex:    c.first + i,\n\t}\n}\n\n// Comment represents a single comment in a source file. It indicates\n// the position of the comment and its contents. A single comment means\n// one line-style comment (\"//\" to end of line) or one block comment\n// (\"/*\" through \"*/\"). If a longer comment uses multiple line comments,\n// each line is considered to be a separate comment. For example:\n//\n//\t// This is a single comment, and\n//\t// this is a separate comment.\ntype Comment struct {\n\tfileInfo *FileInfo\n\tindex    int\n}\n\nvar _ ItemInfo = Comment{}\n\n// IsValid returns true if this comment is valid. If this comment is\n// a zero-value struct, it is not valid.\nfunc (c Comment) IsValid() bool {\n\treturn c.fileInfo != nil && c.index >= 0\n}\n\n// AsItem returns the Item that corresponds to c.\nfunc (c Comment) AsItem() Item {\n\treturn Item(c.fileInfo.comments[c.index].index)\n}\n\nfunc (c Comment) Start() SourcePos {\n\tspan := c.fileInfo.items[c.AsItem()]\n\treturn c.fileInfo.SourcePos(span.offset)\n}\n\nfunc (c Comment) End() SourcePos {\n\tspan := c.fileInfo.items[c.AsItem()]\n\treturn c.fileInfo.SourcePos(span.offset + span.length - 1)\n}\n\nfunc (c Comment) LeadingWhitespace() string {\n\titem := c.AsItem()\n\tspan := c.fileInfo.items[item]\n\tvar prevEnd int\n\tif item > 0 {\n\t\tprevItem := c.fileInfo.items[item-1]\n\t\tprevEnd = prevItem.offset + prevItem.length\n\t}\n\treturn string(c.fileInfo.data[prevEnd:span.offset])\n}\n\nfunc (c Comment) RawText() string {\n\tspan := c.fileInfo.items[c.AsItem()]\n\treturn string(c.fileInfo.data[span.offset : span.offset+span.length])\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/identifiers.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Identifier is a possibly-qualified name. This is used to distinguish\n// ValueNode values that are references/identifiers vs. those that are\n// string literals.\ntype Identifier string\n\n// IdentValueNode is an AST node that represents an identifier.\ntype IdentValueNode interface {\n\tValueNode\n\tAsIdentifier() Identifier\n}\n\nvar _ IdentValueNode = (*IdentNode)(nil)\nvar _ IdentValueNode = (*CompoundIdentNode)(nil)\n\n// IdentNode represents a simple, unqualified identifier. These are used to name\n// elements declared in a protobuf file or to refer to elements. Example:\n//\n//\tfoobar\ntype IdentNode struct {\n\tterminalNode\n\tVal string\n}\n\n// NewIdentNode creates a new *IdentNode. The given val is the identifier text.\nfunc NewIdentNode(val string, tok Token) *IdentNode {\n\treturn &IdentNode{\n\t\tterminalNode: tok.asTerminalNode(),\n\t\tVal:          val,\n\t}\n}\n\nfunc (n *IdentNode) Value() interface{} {\n\treturn n.AsIdentifier()\n}\n\nfunc (n *IdentNode) AsIdentifier() Identifier {\n\treturn Identifier(n.Val)\n}\n\n// ToKeyword is used to convert identifiers to keywords. Since keywords are not\n// reserved in the protobuf language, they are initially lexed as identifiers\n// and then converted to keywords based on context.\nfunc (n *IdentNode) ToKeyword() *KeywordNode {\n\treturn (*KeywordNode)(n)\n}\n\n// CompoundIdentNode represents a qualified identifier. A qualified identifier\n// has at least one dot and possibly multiple identifier names (all separated by\n// dots). If the identifier has a leading dot, then it is a *fully* qualified\n// identifier. Example:\n//\n//\t.com.foobar.Baz\ntype CompoundIdentNode struct {\n\tcompositeNode\n\t// Optional leading dot, indicating that the identifier is fully qualified.\n\tLeadingDot *RuneNode\n\tComponents []*IdentNode\n\t// Dots[0] is the dot after Components[0]. The length of Dots is always\n\t// one less than the length of Components.\n\tDots []*RuneNode\n\t// The text value of the identifier, with all components and dots\n\t// concatenated.\n\tVal string\n}\n\n// NewCompoundIdentNode creates a *CompoundIdentNode. The leadingDot may be nil.\n// The dots arg must have a length that is one less than the length of\n// components. The components arg must not be empty.\nfunc NewCompoundIdentNode(leadingDot *RuneNode, components []*IdentNode, dots []*RuneNode) *CompoundIdentNode {\n\tif len(components) == 0 {\n\t\tpanic(\"must have at least one component\")\n\t}\n\tif len(dots) != len(components)-1 && len(dots) != len(components) {\n\t\tpanic(fmt.Sprintf(\"%d components requires %d dots, not %d\", len(components), len(components)-1, len(dots)))\n\t}\n\tnumChildren := len(components) + len(dots)\n\tif leadingDot != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tvar b strings.Builder\n\tif leadingDot != nil {\n\t\tchildren = append(children, leadingDot)\n\t\tb.WriteRune(leadingDot.Rune)\n\t}\n\tfor i, comp := range components {\n\t\tif i > 0 {\n\t\t\tdot := dots[i-1]\n\t\t\tchildren = append(children, dot)\n\t\t\tb.WriteRune(dot.Rune)\n\t\t}\n\t\tchildren = append(children, comp)\n\t\tb.WriteString(comp.Val)\n\t}\n\tif len(dots) == len(components) {\n\t\tdot := dots[len(dots)-1]\n\t\tchildren = append(children, dot)\n\t\tb.WriteRune(dot.Rune)\n\t}\n\treturn &CompoundIdentNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tLeadingDot: leadingDot,\n\t\tComponents: components,\n\t\tDots:       dots,\n\t\tVal:        b.String(),\n\t}\n}\n\nfunc (n *CompoundIdentNode) Value() interface{} {\n\treturn n.AsIdentifier()\n}\n\nfunc (n *CompoundIdentNode) AsIdentifier() Identifier {\n\treturn Identifier(n.Val)\n}\n\n// KeywordNode is an AST node that represents a keyword. Keywords are\n// like identifiers, but they have special meaning in particular contexts.\n// Example:\n//\n//\tmessage\ntype KeywordNode IdentNode\n\n// NewKeywordNode creates a new *KeywordNode. The given val is the keyword.\nfunc NewKeywordNode(val string, tok Token) *KeywordNode {\n\treturn &KeywordNode{\n\t\tterminalNode: tok.asTerminalNode(),\n\t\tVal:          val,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/message.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// MessageDeclNode is a node in the AST that defines a message type. This\n// includes normal message fields as well as implicit messages:\n//   - *MessageNode\n//   - *SyntheticGroupMessageNode (the group is a field and inline message type)\n//   - *SyntheticMapEntryNode (map fields implicitly define a MapEntry message type)\n//\n// This also allows NoSourceNode to be used in place of one of the above\n// for some usages.\ntype MessageDeclNode interface {\n\tNodeWithOptions\n\tMessageName() Node\n}\n\nvar _ MessageDeclNode = (*MessageNode)(nil)\nvar _ MessageDeclNode = (*SyntheticGroupMessageNode)(nil)\nvar _ MessageDeclNode = (*SyntheticMapEntryNode)(nil)\nvar _ MessageDeclNode = (*NoSourceNode)(nil)\n\n// MessageNode represents a message declaration. Example:\n//\n//\tmessage Foo {\n//\t  string name = 1;\n//\t  repeated string labels = 2;\n//\t  bytes extra = 3;\n//\t}\ntype MessageNode struct {\n\tcompositeNode\n\tKeyword *KeywordNode\n\tName    *IdentNode\n\tMessageBody\n}\n\nfunc (*MessageNode) fileElement() {}\nfunc (*MessageNode) msgElement()  {}\n\n// NewMessageNode creates a new *MessageNode. All arguments must be non-nil.\n//   - keyword: The token corresponding to the \"message\" keyword.\n//   - name: The token corresponding to the field's name.\n//   - openBrace: The token corresponding to the \"{\" rune that starts the body.\n//   - decls: All declarations inside the message body.\n//   - closeBrace: The token corresponding to the \"}\" rune that ends the body.\nfunc NewMessageNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) *MessageNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif openBrace == nil {\n\t\tpanic(\"openBrace is nil\")\n\t}\n\tif closeBrace == nil {\n\t\tpanic(\"closeBrace is nil\")\n\t}\n\tchildren := make([]Node, 0, 4+len(decls))\n\tchildren = append(children, keyword, name, openBrace)\n\tfor _, decl := range decls {\n\t\tchildren = append(children, decl)\n\t}\n\tchildren = append(children, closeBrace)\n\n\tret := &MessageNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword: keyword,\n\t\tName:    name,\n\t}\n\tpopulateMessageBody(&ret.MessageBody, openBrace, decls, closeBrace)\n\treturn ret\n}\n\nfunc (n *MessageNode) MessageName() Node {\n\treturn n.Name\n}\n\nfunc (n *MessageNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, decl := range n.Decls {\n\t\tif opt, ok := decl.(*OptionNode); ok {\n\t\t\tif !fn(opt) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// MessageBody represents the body of a message. It is used by both\n// MessageNodes and GroupNodes.\ntype MessageBody struct {\n\tOpenBrace  *RuneNode\n\tDecls      []MessageElement\n\tCloseBrace *RuneNode\n}\n\nfunc populateMessageBody(m *MessageBody, openBrace *RuneNode, decls []MessageElement, closeBrace *RuneNode) {\n\tm.OpenBrace = openBrace\n\tm.Decls = decls\n\tfor _, decl := range decls {\n\t\tswitch decl.(type) {\n\t\tcase *OptionNode, *FieldNode, *MapFieldNode, *GroupNode, *OneofNode,\n\t\t\t*MessageNode, *EnumNode, *ExtendNode, *ExtensionRangeNode,\n\t\t\t*ReservedNode, *EmptyDeclNode:\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"invalid MessageElement type: %T\", decl))\n\t\t}\n\t}\n\tm.CloseBrace = closeBrace\n}\n\n// MessageElement is an interface implemented by all AST nodes that can\n// appear in a message body.\ntype MessageElement interface {\n\tNode\n\tmsgElement()\n}\n\nvar _ MessageElement = (*OptionNode)(nil)\nvar _ MessageElement = (*FieldNode)(nil)\nvar _ MessageElement = (*MapFieldNode)(nil)\nvar _ MessageElement = (*OneofNode)(nil)\nvar _ MessageElement = (*GroupNode)(nil)\nvar _ MessageElement = (*MessageNode)(nil)\nvar _ MessageElement = (*EnumNode)(nil)\nvar _ MessageElement = (*ExtendNode)(nil)\nvar _ MessageElement = (*ExtensionRangeNode)(nil)\nvar _ MessageElement = (*ReservedNode)(nil)\nvar _ MessageElement = (*EmptyDeclNode)(nil)\n\n// ExtendNode represents a declaration of extension fields. Example:\n//\n//\textend google.protobuf.FieldOptions {\n//\t  bool redacted = 33333;\n//\t}\ntype ExtendNode struct {\n\tcompositeNode\n\tKeyword    *KeywordNode\n\tExtendee   IdentValueNode\n\tOpenBrace  *RuneNode\n\tDecls      []ExtendElement\n\tCloseBrace *RuneNode\n}\n\nfunc (*ExtendNode) fileElement() {}\nfunc (*ExtendNode) msgElement()  {}\n\n// NewExtendNode creates a new *ExtendNode. All arguments must be non-nil.\n//   - keyword: The token corresponding to the \"extend\" keyword.\n//   - extendee: The token corresponding to the name of the extended message.\n//   - openBrace: The token corresponding to the \"{\" rune that starts the body.\n//   - decls: All declarations inside the message body.\n//   - closeBrace: The token corresponding to the \"}\" rune that ends the body.\nfunc NewExtendNode(keyword *KeywordNode, extendee IdentValueNode, openBrace *RuneNode, decls []ExtendElement, closeBrace *RuneNode) *ExtendNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif extendee == nil {\n\t\tpanic(\"extendee is nil\")\n\t}\n\tif openBrace == nil {\n\t\tpanic(\"openBrace is nil\")\n\t}\n\tif closeBrace == nil {\n\t\tpanic(\"closeBrace is nil\")\n\t}\n\tchildren := make([]Node, 0, 4+len(decls))\n\tchildren = append(children, keyword, extendee, openBrace)\n\tfor _, decl := range decls {\n\t\tchildren = append(children, decl)\n\t}\n\tchildren = append(children, closeBrace)\n\n\tret := &ExtendNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:    keyword,\n\t\tExtendee:   extendee,\n\t\tOpenBrace:  openBrace,\n\t\tDecls:      decls,\n\t\tCloseBrace: closeBrace,\n\t}\n\tfor _, decl := range decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *FieldNode:\n\t\t\tdecl.Extendee = ret\n\t\tcase *GroupNode:\n\t\t\tdecl.Extendee = ret\n\t\tcase *EmptyDeclNode:\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"invalid ExtendElement type: %T\", decl))\n\t\t}\n\t}\n\treturn ret\n}\n\n// ExtendElement is an interface implemented by all AST nodes that can\n// appear in the body of an extends declaration.\ntype ExtendElement interface {\n\tNode\n\textendElement()\n}\n\nvar _ ExtendElement = (*FieldNode)(nil)\nvar _ ExtendElement = (*GroupNode)(nil)\nvar _ ExtendElement = (*EmptyDeclNode)(nil)\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/no_source.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\n// UnknownPos is a placeholder position when only the source file\n// name is known.\nfunc UnknownPos(filename string) SourcePos {\n\treturn SourcePos{Filename: filename}\n}\n\n// UnknownSpan is a placeholder span when only the source file\n// name is known.\nfunc UnknownSpan(filename string) SourceSpan {\n\treturn unknownSpan{filename: filename}\n}\n\ntype unknownSpan struct {\n\tfilename string\n}\n\nfunc (s unknownSpan) Start() SourcePos {\n\treturn UnknownPos(s.filename)\n}\n\nfunc (s unknownSpan) End() SourcePos {\n\treturn UnknownPos(s.filename)\n}\n\n// NoSourceNode is a placeholder AST node that implements numerous\n// interfaces in this package. It can be used to represent an AST\n// element for a file whose source is not available.\ntype NoSourceNode FileInfo\n\n// NewNoSourceNode creates a new NoSourceNode for the given filename.\nfunc NewNoSourceNode(filename string) *NoSourceNode {\n\treturn &NoSourceNode{name: filename}\n}\n\nfunc (n *NoSourceNode) Name() string {\n\treturn n.name\n}\n\nfunc (n *NoSourceNode) Start() Token {\n\treturn 0\n}\n\nfunc (n *NoSourceNode) End() Token {\n\treturn 0\n}\n\nfunc (n *NoSourceNode) NodeInfo(Node) NodeInfo {\n\treturn NodeInfo{\n\t\tfileInfo: (*FileInfo)(n),\n\t}\n}\n\nfunc (n *NoSourceNode) GetSyntax() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) GetName() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) GetValue() ValueNode {\n\treturn n\n}\n\nfunc (n *NoSourceNode) FieldLabel() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) FieldName() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) FieldType() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) FieldTag() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) FieldExtendee() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) GetGroupKeyword() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) GetOptions() *CompactOptionsNode {\n\treturn nil\n}\n\nfunc (n *NoSourceNode) RangeStart() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) RangeEnd() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) GetNumber() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) MessageName() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) OneofName() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) GetInputType() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) GetOutputType() Node {\n\treturn n\n}\n\nfunc (n *NoSourceNode) Value() interface{} {\n\treturn nil\n}\n\nfunc (n *NoSourceNode) RangeOptions(func(*OptionNode) bool) {\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/node.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\n// Node is the interface implemented by all nodes in the AST. It\n// provides information about the span of this AST node in terms\n// of location in the source file. It also provides information\n// about all prior comments (attached as leading comments) and\n// optional subsequent comments (attached as trailing comments).\ntype Node interface {\n\tStart() Token\n\tEnd() Token\n}\n\n// TerminalNode represents a leaf in the AST. These represent\n// the items/lexemes in the protobuf language. Comments and\n// whitespace are accumulated by the lexer and associated with\n// the following lexed token.\ntype TerminalNode interface {\n\tNode\n\tToken() Token\n}\n\nvar _ TerminalNode = (*StringLiteralNode)(nil)\nvar _ TerminalNode = (*UintLiteralNode)(nil)\nvar _ TerminalNode = (*FloatLiteralNode)(nil)\nvar _ TerminalNode = (*IdentNode)(nil)\nvar _ TerminalNode = (*SpecialFloatLiteralNode)(nil)\nvar _ TerminalNode = (*KeywordNode)(nil)\nvar _ TerminalNode = (*RuneNode)(nil)\n\n// CompositeNode represents any non-terminal node in the tree. These\n// are interior or root nodes and have child nodes.\ntype CompositeNode interface {\n\tNode\n\t// Children contains all AST nodes that are immediate children of this one.\n\tChildren() []Node\n}\n\n// terminalNode contains bookkeeping shared by all TerminalNode\n// implementations. It is embedded in all such node types in this\n// package. It provides the implementation of the TerminalNode\n// interface.\ntype terminalNode Token\n\nfunc (n terminalNode) Start() Token {\n\treturn Token(n)\n}\n\nfunc (n terminalNode) End() Token {\n\treturn Token(n)\n}\n\nfunc (n terminalNode) Token() Token {\n\treturn Token(n)\n}\n\n// compositeNode contains bookkeeping shared by all CompositeNode\n// implementations. It is embedded in all such node types in this\n// package. It provides the implementation of the CompositeNode\n// interface.\ntype compositeNode struct {\n\tchildren []Node\n}\n\nfunc (n *compositeNode) Children() []Node {\n\treturn n.children\n}\n\nfunc (n *compositeNode) Start() Token {\n\treturn n.children[0].Start()\n}\n\nfunc (n *compositeNode) End() Token {\n\treturn n.children[len(n.children)-1].End()\n}\n\n// RuneNode represents a single rune in protobuf source. Runes\n// are typically collected into items, but some runes stand on\n// their own, such as punctuation/symbols like commas, semicolons,\n// equals signs, open and close symbols (braces, brackets, angles,\n// and parentheses), and periods/dots.\n// TODO: make this more compact; if runes don't have attributed comments\n// then we don't need a Token to represent them and only need an offset\n// into the file's contents.\ntype RuneNode struct {\n\tterminalNode\n\tRune rune\n}\n\n// NewRuneNode creates a new *RuneNode with the given properties.\nfunc NewRuneNode(r rune, tok Token) *RuneNode {\n\treturn &RuneNode{\n\t\tterminalNode: tok.asTerminalNode(),\n\t\tRune:         r,\n\t}\n}\n\n// EmptyDeclNode represents an empty declaration in protobuf source.\n// These amount to extra semicolons, with no actual content preceding\n// the semicolon.\ntype EmptyDeclNode struct {\n\tcompositeNode\n\tSemicolon *RuneNode\n}\n\n// NewEmptyDeclNode creates a new *EmptyDeclNode. The one argument must\n// be non-nil.\nfunc NewEmptyDeclNode(semicolon *RuneNode) *EmptyDeclNode {\n\tif semicolon == nil {\n\t\tpanic(\"semicolon is nil\")\n\t}\n\treturn &EmptyDeclNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: []Node{semicolon},\n\t\t},\n\t\tSemicolon: semicolon,\n\t}\n}\n\nfunc (e *EmptyDeclNode) fileElement()    {}\nfunc (e *EmptyDeclNode) msgElement()     {}\nfunc (e *EmptyDeclNode) extendElement()  {}\nfunc (e *EmptyDeclNode) oneofElement()   {}\nfunc (e *EmptyDeclNode) enumElement()    {}\nfunc (e *EmptyDeclNode) serviceElement() {}\nfunc (e *EmptyDeclNode) methodElement()  {}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/options.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// OptionDeclNode is a placeholder interface for AST nodes that represent\n// options. This allows NoSourceNode to be used in place of *OptionNode\n// for some usages.\ntype OptionDeclNode interface {\n\tNode\n\tGetName() Node\n\tGetValue() ValueNode\n}\n\nvar _ OptionDeclNode = (*OptionNode)(nil)\nvar _ OptionDeclNode = (*NoSourceNode)(nil)\n\n// OptionNode represents the declaration of a single option for an element.\n// It is used both for normal option declarations (start with \"option\" keyword\n// and end with semicolon) and for compact options found in fields, enum values,\n// and extension ranges. Example:\n//\n//\toption (custom.option) = \"foo\";\ntype OptionNode struct {\n\tcompositeNode\n\tKeyword   *KeywordNode // absent for compact options\n\tName      *OptionNameNode\n\tEquals    *RuneNode\n\tVal       ValueNode\n\tSemicolon *RuneNode // absent for compact options\n}\n\nfunc (*OptionNode) fileElement()    {}\nfunc (*OptionNode) msgElement()     {}\nfunc (*OptionNode) oneofElement()   {}\nfunc (*OptionNode) enumElement()    {}\nfunc (*OptionNode) serviceElement() {}\nfunc (*OptionNode) methodElement()  {}\n\n// NewOptionNode creates a new *OptionNode for a full option declaration (as\n// used in files, messages, oneofs, enums, services, and methods). All arguments\n// must be non-nil. (Also see NewCompactOptionNode.)\n//   - keyword: The token corresponding to the \"option\" keyword.\n//   - name: The token corresponding to the name of the option.\n//   - equals: The token corresponding to the \"=\" rune after the name.\n//   - val: The token corresponding to the option value.\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewOptionNode(keyword *KeywordNode, name *OptionNameNode, equals *RuneNode, val ValueNode, semicolon *RuneNode) *OptionNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif equals == nil {\n\t\tpanic(\"equals is nil\")\n\t}\n\tif val == nil {\n\t\tpanic(\"val is nil\")\n\t}\n\tvar children []Node\n\tif semicolon == nil {\n\t\tchildren = []Node{keyword, name, equals, val}\n\t} else {\n\t\tchildren = []Node{keyword, name, equals, val, semicolon}\n\t}\n\n\treturn &OptionNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tName:      name,\n\t\tEquals:    equals,\n\t\tVal:       val,\n\t\tSemicolon: semicolon,\n\t}\n}\n\n// NewCompactOptionNode creates a new *OptionNode for a full compact declaration\n// (as used in fields, enum values, and extension ranges). All arguments must be\n// non-nil.\n//   - name: The token corresponding to the name of the option.\n//   - equals: The token corresponding to the \"=\" rune after the name.\n//   - val: The token corresponding to the option value.\nfunc NewCompactOptionNode(name *OptionNameNode, equals *RuneNode, val ValueNode) *OptionNode {\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif equals == nil && val != nil {\n\t\tpanic(\"equals is nil but val is not\")\n\t}\n\tif val == nil && equals != nil {\n\t\tpanic(\"val is nil but equals is not\")\n\t}\n\tvar children []Node\n\tif equals == nil && val == nil {\n\t\tchildren = []Node{name}\n\t} else {\n\t\tchildren = []Node{name, equals, val}\n\t}\n\treturn &OptionNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tName:   name,\n\t\tEquals: equals,\n\t\tVal:    val,\n\t}\n}\n\nfunc (n *OptionNode) GetName() Node {\n\treturn n.Name\n}\n\nfunc (n *OptionNode) GetValue() ValueNode {\n\treturn n.Val\n}\n\n// OptionNameNode represents an option name or even a traversal through message\n// types to name a nested option field. Example:\n//\n//\t(foo.bar).baz.(bob)\ntype OptionNameNode struct {\n\tcompositeNode\n\tParts []*FieldReferenceNode\n\t// Dots represent the separating '.' characters between name parts. The\n\t// length of this slice must be exactly len(Parts)-1, each item in Parts\n\t// having a corresponding item in this slice *except the last* (since a\n\t// trailing dot is not allowed).\n\t//\n\t// These do *not* include dots that are inside of an extension name. For\n\t// example: (foo.bar).baz.(bob) has three parts:\n\t//    1. (foo.bar)  - an extension name\n\t//    2. baz        - a regular field in foo.bar\n\t//    3. (bob)      - an extension field in baz\n\t// Note that the dot in foo.bar will thus not be present in Dots but is\n\t// instead in Parts[0].\n\tDots []*RuneNode\n}\n\n// NewOptionNameNode creates a new *OptionNameNode. The dots arg must have a\n// length that is one less than the length of parts. The parts arg must not be\n// empty.\nfunc NewOptionNameNode(parts []*FieldReferenceNode, dots []*RuneNode) *OptionNameNode {\n\tif len(parts) == 0 {\n\t\tpanic(\"must have at least one part\")\n\t}\n\tif len(dots) != len(parts)-1 && len(dots) != len(parts) {\n\t\tpanic(fmt.Sprintf(\"%d parts requires %d dots, not %d\", len(parts), len(parts)-1, len(dots)))\n\t}\n\tchildren := make([]Node, 0, len(parts)+len(dots))\n\tfor i, part := range parts {\n\t\tif part == nil {\n\t\t\tpanic(fmt.Sprintf(\"parts[%d] is nil\", i))\n\t\t}\n\t\tif i > 0 {\n\t\t\tif dots[i-1] == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"dots[%d] is nil\", i-1))\n\t\t\t}\n\t\t\tchildren = append(children, dots[i-1])\n\t\t}\n\t\tchildren = append(children, part)\n\t}\n\tif len(dots) == len(parts) { // Add the erroneous, but tolerated trailing dot.\n\t\tif dots[len(dots)-1] == nil {\n\t\t\tpanic(fmt.Sprintf(\"dots[%d] is nil\", len(dots)-1))\n\t\t}\n\t\tchildren = append(children, dots[len(dots)-1])\n\t}\n\treturn &OptionNameNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tParts: parts,\n\t\tDots:  dots,\n\t}\n}\n\n// FieldReferenceNode is a reference to a field name. It can indicate a regular\n// field (simple unqualified name), an extension field (possibly-qualified name\n// that is enclosed either in brackets or parentheses), or an \"any\" type\n// reference (a type URL in the form \"server.host/fully.qualified.Name\" that is\n// enclosed in brackets).\n//\n// Extension names are used in options to refer to custom options (which are\n// actually extensions), in which case the name is enclosed in parentheses \"(\"\n// and \")\". They can also be used to refer to extension fields of options.\n//\n// Extension names are also used in message literals to set extension fields,\n// in which case the name is enclosed in square brackets \"[\" and \"]\".\n//\n// \"Any\" type references can only be used in message literals, and are not\n// allowed in option names. They are always enclosed in square brackets. An\n// \"any\" type reference is distinguished from an extension name by the presence\n// of a slash, which must be present in an \"any\" type reference and must be\n// absent in an extension name.\n//\n// Examples:\n//\n//\tfoobar\n//\t(foo.bar)\n//\t[foo.bar]\n//\t[type.googleapis.com/foo.bar]\ntype FieldReferenceNode struct {\n\tcompositeNode\n\tOpen *RuneNode // only present for extension names and \"any\" type references\n\n\t// only present for \"any\" type references\n\tURLPrefix IdentValueNode\n\tSlash     *RuneNode\n\n\tName IdentValueNode\n\n\tClose *RuneNode // only present for extension names and \"any\" type references\n}\n\n// NewFieldReferenceNode creates a new *FieldReferenceNode for a regular field.\n// The name arg must not be nil.\nfunc NewFieldReferenceNode(name *IdentNode) *FieldReferenceNode {\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tchildren := []Node{name}\n\treturn &FieldReferenceNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tName: name,\n\t}\n}\n\n// NewExtensionFieldReferenceNode creates a new *FieldReferenceNode for an\n// extension field. All args must be non-nil. The openSym and closeSym runes\n// should be \"(\" and \")\" or \"[\" and \"]\".\nfunc NewExtensionFieldReferenceNode(openSym *RuneNode, name IdentValueNode, closeSym *RuneNode) *FieldReferenceNode {\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif openSym == nil {\n\t\tpanic(\"openSym is nil\")\n\t}\n\tif closeSym == nil {\n\t\tpanic(\"closeSym is nil\")\n\t}\n\tchildren := []Node{openSym, name, closeSym}\n\treturn &FieldReferenceNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tOpen:  openSym,\n\t\tName:  name,\n\t\tClose: closeSym,\n\t}\n}\n\n// NewAnyTypeReferenceNode creates a new *FieldReferenceNode for an \"any\"\n// type reference. All args must be non-nil. The openSym and closeSym runes\n// should be \"[\" and \"]\". The slashSym run should be \"/\".\nfunc NewAnyTypeReferenceNode(openSym *RuneNode, urlPrefix IdentValueNode, slashSym *RuneNode, name IdentValueNode, closeSym *RuneNode) *FieldReferenceNode {\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif openSym == nil {\n\t\tpanic(\"openSym is nil\")\n\t}\n\tif closeSym == nil {\n\t\tpanic(\"closeSym is nil\")\n\t}\n\tif urlPrefix == nil {\n\t\tpanic(\"urlPrefix is nil\")\n\t}\n\tif slashSym == nil {\n\t\tpanic(\"slashSym is nil\")\n\t}\n\tchildren := []Node{openSym, urlPrefix, slashSym, name, closeSym}\n\treturn &FieldReferenceNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tOpen:      openSym,\n\t\tURLPrefix: urlPrefix,\n\t\tSlash:     slashSym,\n\t\tName:      name,\n\t\tClose:     closeSym,\n\t}\n}\n\n// IsExtension reports if this is an extension name or not (e.g. enclosed in\n// punctuation, such as parentheses or brackets).\nfunc (a *FieldReferenceNode) IsExtension() bool {\n\treturn a.Open != nil && a.Slash == nil\n}\n\n// IsAnyTypeReference reports if this is an Any type reference.\nfunc (a *FieldReferenceNode) IsAnyTypeReference() bool {\n\treturn a.Slash != nil\n}\n\nfunc (a *FieldReferenceNode) Value() string {\n\tif a.Open != nil {\n\t\tif a.Slash != nil {\n\t\t\treturn string(a.Open.Rune) + string(a.URLPrefix.AsIdentifier()) + string(a.Slash.Rune) + string(a.Name.AsIdentifier()) + string(a.Close.Rune)\n\t\t}\n\t\treturn string(a.Open.Rune) + string(a.Name.AsIdentifier()) + string(a.Close.Rune)\n\t}\n\treturn string(a.Name.AsIdentifier())\n}\n\n// CompactOptionsNode represents a compact options declaration, as used with\n// fields, enum values, and extension ranges. Example:\n//\n//\t[deprecated = true, json_name = \"foo_bar\"]\ntype CompactOptionsNode struct {\n\tcompositeNode\n\tOpenBracket *RuneNode\n\tOptions     []*OptionNode\n\t// Commas represent the separating ',' characters between options. The\n\t// length of this slice must be exactly len(Options)-1, with each item\n\t// in Options having a corresponding item in this slice *except the last*\n\t// (since a trailing comma is not allowed).\n\tCommas       []*RuneNode\n\tCloseBracket *RuneNode\n}\n\n// NewCompactOptionsNode creates a *CompactOptionsNode. All args must be\n// non-nil. The commas arg must have a length that is one less than the\n// length of opts. The opts arg must not be empty.\nfunc NewCompactOptionsNode(openBracket *RuneNode, opts []*OptionNode, commas []*RuneNode, closeBracket *RuneNode) *CompactOptionsNode {\n\tif openBracket == nil {\n\t\tpanic(\"openBracket is nil\")\n\t}\n\tif closeBracket == nil {\n\t\tpanic(\"closeBracket is nil\")\n\t}\n\tif len(opts) == 0 && len(commas) != 0 {\n\t\tpanic(\"opts is empty but commas is not\")\n\t}\n\tif len(opts) != len(commas) && len(opts) != len(commas)+1 {\n\t\tpanic(fmt.Sprintf(\"%d opts requires %d commas, not %d\", len(opts), len(opts)-1, len(commas)))\n\t}\n\tchildren := make([]Node, 0, len(opts)+len(commas)+2)\n\tchildren = append(children, openBracket)\n\tif len(opts) > 0 {\n\t\tfor i, opt := range opts {\n\t\t\tif i > 0 {\n\t\t\t\tif commas[i-1] == nil {\n\t\t\t\t\tpanic(fmt.Sprintf(\"commas[%d] is nil\", i-1))\n\t\t\t\t}\n\t\t\t\tchildren = append(children, commas[i-1])\n\t\t\t}\n\t\t\tif opt == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"opts[%d] is nil\", i))\n\t\t\t}\n\t\t\tchildren = append(children, opt)\n\t\t}\n\t\tif len(opts) == len(commas) { // Add the erroneous, but tolerated trailing comma.\n\t\t\tif commas[len(commas)-1] == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"commas[%d] is nil\", len(commas)-1))\n\t\t\t}\n\t\t\tchildren = append(children, commas[len(commas)-1])\n\t\t}\n\t}\n\tchildren = append(children, closeBracket)\n\n\treturn &CompactOptionsNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tOpenBracket:  openBracket,\n\t\tOptions:      opts,\n\t\tCommas:       commas,\n\t\tCloseBracket: closeBracket,\n\t}\n}\n\nfunc (e *CompactOptionsNode) GetElements() []*OptionNode {\n\tif e == nil {\n\t\treturn nil\n\t}\n\treturn e.Options\n}\n\n// NodeWithOptions represents a node in the AST that contains\n// option statements.\ntype NodeWithOptions interface {\n\tNode\n\tRangeOptions(func(*OptionNode) bool)\n}\n\nvar _ NodeWithOptions = FileDeclNode(nil)\nvar _ NodeWithOptions = MessageDeclNode(nil)\nvar _ NodeWithOptions = OneofDeclNode(nil)\nvar _ NodeWithOptions = (*EnumNode)(nil)\nvar _ NodeWithOptions = (*ServiceNode)(nil)\nvar _ NodeWithOptions = RPCDeclNode(nil)\nvar _ NodeWithOptions = FieldDeclNode(nil)\nvar _ NodeWithOptions = EnumValueDeclNode(nil)\nvar _ NodeWithOptions = (*ExtensionRangeNode)(nil)\nvar _ NodeWithOptions = (*NoSourceNode)(nil)\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/ranges.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// ExtensionRangeNode represents an extension range declaration in an extendable\n// message. Example:\n//\n//\textensions 100 to max;\ntype ExtensionRangeNode struct {\n\tcompositeNode\n\tKeyword *KeywordNode\n\tRanges  []*RangeNode\n\t// Commas represent the separating ',' characters between ranges. The\n\t// length of this slice must be exactly len(Ranges)-1, each item in Ranges\n\t// having a corresponding item in this slice *except the last* (since a\n\t// trailing comma is not allowed).\n\tCommas    []*RuneNode\n\tOptions   *CompactOptionsNode\n\tSemicolon *RuneNode\n}\n\nfunc (*ExtensionRangeNode) msgElement() {}\n\n// NewExtensionRangeNode creates a new *ExtensionRangeNode. All args must be\n// non-nil except opts, which may be nil.\n//   - keyword: The token corresponding to the \"extends\" keyword.\n//   - ranges: One or more range expressions.\n//   - commas: Tokens that represent the \",\" runes that delimit the range expressions.\n//     The length of commas must be one less than the length of ranges.\n//   - opts: The node corresponding to options that apply to each of the ranges.\n//   - semicolon The token corresponding to the \";\" rune that ends the declaration.\nfunc NewExtensionRangeNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, opts *CompactOptionsNode, semicolon *RuneNode) *ExtensionRangeNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif semicolon == nil {\n\t\tpanic(\"semicolon is nil\")\n\t}\n\tif len(ranges) == 0 {\n\t\tpanic(\"must have at least one range\")\n\t}\n\tif len(commas) != len(ranges)-1 {\n\t\tpanic(fmt.Sprintf(\"%d ranges requires %d commas, not %d\", len(ranges), len(ranges)-1, len(commas)))\n\t}\n\tnumChildren := len(ranges)*2 + 1\n\tif opts != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, keyword)\n\tfor i, rng := range ranges {\n\t\tif i > 0 {\n\t\t\tif commas[i-1] == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"commas[%d] is nil\", i-1))\n\t\t\t}\n\t\t\tchildren = append(children, commas[i-1])\n\t\t}\n\t\tif rng == nil {\n\t\t\tpanic(fmt.Sprintf(\"ranges[%d] is nil\", i))\n\t\t}\n\t\tchildren = append(children, rng)\n\t}\n\tif opts != nil {\n\t\tchildren = append(children, opts)\n\t}\n\tchildren = append(children, semicolon)\n\treturn &ExtensionRangeNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tRanges:    ranges,\n\t\tCommas:    commas,\n\t\tOptions:   opts,\n\t\tSemicolon: semicolon,\n\t}\n}\n\nfunc (e *ExtensionRangeNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, opt := range e.Options.Options {\n\t\tif !fn(opt) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\n// RangeDeclNode is a placeholder interface for AST nodes that represent\n// numeric values. This allows NoSourceNode to be used in place of *RangeNode\n// for some usages.\ntype RangeDeclNode interface {\n\tNode\n\tRangeStart() Node\n\tRangeEnd() Node\n}\n\nvar _ RangeDeclNode = (*RangeNode)(nil)\nvar _ RangeDeclNode = (*NoSourceNode)(nil)\n\n// RangeNode represents a range expression, used in both extension ranges and\n// reserved ranges. Example:\n//\n//\t1000 to max\ntype RangeNode struct {\n\tcompositeNode\n\tStartVal IntValueNode\n\t// if To is non-nil, then exactly one of EndVal or Max must also be non-nil\n\tTo *KeywordNode\n\t// EndVal and Max are mutually exclusive\n\tEndVal IntValueNode\n\tMax    *KeywordNode\n}\n\n// NewRangeNode creates a new *RangeNode. The start argument must be non-nil.\n// The to argument represents the \"to\" keyword. If present (i.e. if it is non-nil),\n// then so must be exactly one of end or max. If max is non-nil, it indicates a\n// \"100 to max\" style range. But if end is non-nil, the end of the range is a\n// literal, such as \"100 to 200\".\nfunc NewRangeNode(start IntValueNode, to *KeywordNode, end IntValueNode, maxEnd *KeywordNode) *RangeNode {\n\tif start == nil {\n\t\tpanic(\"start is nil\")\n\t}\n\tnumChildren := 1\n\tif to != nil {\n\t\tif end == nil && maxEnd == nil {\n\t\t\tpanic(\"to is not nil, but end and max both are\")\n\t\t}\n\t\tif end != nil && maxEnd != nil {\n\t\t\tpanic(\"end and max cannot be both non-nil\")\n\t\t}\n\t\tnumChildren = 3\n\t} else {\n\t\tif end != nil {\n\t\t\tpanic(\"to is nil, but end is not\")\n\t\t}\n\t\tif maxEnd != nil {\n\t\t\tpanic(\"to is nil, but max is not\")\n\t\t}\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, start)\n\tif to != nil {\n\t\tchildren = append(children, to)\n\t\tif end != nil {\n\t\t\tchildren = append(children, end)\n\t\t} else {\n\t\t\tchildren = append(children, maxEnd)\n\t\t}\n\t}\n\treturn &RangeNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tStartVal: start,\n\t\tTo:       to,\n\t\tEndVal:   end,\n\t\tMax:      maxEnd,\n\t}\n}\n\nfunc (n *RangeNode) RangeStart() Node {\n\treturn n.StartVal\n}\n\nfunc (n *RangeNode) RangeEnd() Node {\n\tif n.Max != nil {\n\t\treturn n.Max\n\t}\n\tif n.EndVal != nil {\n\t\treturn n.EndVal\n\t}\n\treturn n.StartVal\n}\n\nfunc (n *RangeNode) StartValue() interface{} {\n\treturn n.StartVal.Value()\n}\n\nfunc (n *RangeNode) StartValueAsInt32(minVal, maxVal int32) (int32, bool) {\n\treturn AsInt32(n.StartVal, minVal, maxVal)\n}\n\nfunc (n *RangeNode) EndValue() interface{} {\n\tif n.EndVal == nil {\n\t\treturn nil\n\t}\n\treturn n.EndVal.Value()\n}\n\nfunc (n *RangeNode) EndValueAsInt32(minVal, maxVal int32) (int32, bool) {\n\tif n.Max != nil {\n\t\treturn maxVal, true\n\t}\n\tif n.EndVal == nil {\n\t\treturn n.StartValueAsInt32(minVal, maxVal)\n\t}\n\treturn AsInt32(n.EndVal, minVal, maxVal)\n}\n\n// ReservedNode represents reserved declaration, which can be used to reserve\n// either names or numbers. Examples:\n//\n//\treserved 1, 10-12, 15;\n//\treserved \"foo\", \"bar\", \"baz\";\n//\treserved foo, bar, baz;\ntype ReservedNode struct {\n\tcompositeNode\n\tKeyword *KeywordNode\n\t// If non-empty, this node represents reserved ranges, and Names and Identifiers\n\t// will be empty.\n\tRanges []*RangeNode\n\t// If non-empty, this node represents reserved names as string literals, and\n\t// Ranges and Identifiers will be empty. String literals are used for reserved\n\t// names in proto2 and proto3 syntax.\n\tNames []StringValueNode\n\t// If non-empty, this node represents reserved names as identifiers, and Ranges\n\t// and Names will be empty. Identifiers are used for reserved names in editions.\n\tIdentifiers []*IdentNode\n\t// Commas represent the separating ',' characters between options. The\n\t// length of this slice must be exactly len(Ranges)-1 or len(Names)-1, depending\n\t// on whether this node represents reserved ranges or reserved names. Each item\n\t// in Ranges or Names has a corresponding item in this slice *except the last*\n\t// (since a trailing comma is not allowed).\n\tCommas    []*RuneNode\n\tSemicolon *RuneNode\n}\n\nfunc (*ReservedNode) msgElement()  {}\nfunc (*ReservedNode) enumElement() {}\n\n// NewReservedRangesNode creates a new *ReservedNode that represents reserved\n// numeric ranges. All args must be non-nil.\n//   - keyword: The token corresponding to the \"reserved\" keyword.\n//   - ranges: One or more range expressions.\n//   - commas: Tokens that represent the \",\" runes that delimit the range expressions.\n//     The length of commas must be one less than the length of ranges.\n//   - semicolon The token corresponding to the \";\" rune that ends the declaration.\nfunc NewReservedRangesNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif semicolon == nil {\n\t\tpanic(\"semicolon is nil\")\n\t}\n\tif len(ranges) == 0 {\n\t\tpanic(\"must have at least one range\")\n\t}\n\tif len(commas) != len(ranges)-1 {\n\t\tpanic(fmt.Sprintf(\"%d ranges requires %d commas, not %d\", len(ranges), len(ranges)-1, len(commas)))\n\t}\n\tchildren := make([]Node, 0, len(ranges)*2+1)\n\tchildren = append(children, keyword)\n\tfor i, rng := range ranges {\n\t\tif i > 0 {\n\t\t\tif commas[i-1] == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"commas[%d] is nil\", i-1))\n\t\t\t}\n\t\t\tchildren = append(children, commas[i-1])\n\t\t}\n\t\tif rng == nil {\n\t\t\tpanic(fmt.Sprintf(\"ranges[%d] is nil\", i))\n\t\t}\n\t\tchildren = append(children, rng)\n\t}\n\tchildren = append(children, semicolon)\n\treturn &ReservedNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tRanges:    ranges,\n\t\tCommas:    commas,\n\t\tSemicolon: semicolon,\n\t}\n}\n\n// NewReservedNamesNode creates a new *ReservedNode that represents reserved\n// names. All args must be non-nil.\n//   - keyword: The token corresponding to the \"reserved\" keyword.\n//   - names: One or more names.\n//   - commas: Tokens that represent the \",\" runes that delimit the names.\n//     The length of commas must be one less than the length of names.\n//   - semicolon The token corresponding to the \";\" rune that ends the declaration.\nfunc NewReservedNamesNode(keyword *KeywordNode, names []StringValueNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif len(names) == 0 {\n\t\tpanic(\"must have at least one name\")\n\t}\n\tif len(commas) != len(names)-1 {\n\t\tpanic(fmt.Sprintf(\"%d names requires %d commas, not %d\", len(names), len(names)-1, len(commas)))\n\t}\n\tnumChildren := len(names) * 2\n\tif semicolon != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, keyword)\n\tfor i, name := range names {\n\t\tif i > 0 {\n\t\t\tif commas[i-1] == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"commas[%d] is nil\", i-1))\n\t\t\t}\n\t\t\tchildren = append(children, commas[i-1])\n\t\t}\n\t\tif name == nil {\n\t\t\tpanic(fmt.Sprintf(\"names[%d] is nil\", i))\n\t\t}\n\t\tchildren = append(children, name)\n\t}\n\tif semicolon != nil {\n\t\tchildren = append(children, semicolon)\n\t}\n\treturn &ReservedNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tNames:     names,\n\t\tCommas:    commas,\n\t\tSemicolon: semicolon,\n\t}\n}\n\n// NewReservedIdentifiersNode creates a new *ReservedNode that represents reserved\n// names. All args must be non-nil.\n//   - keyword: The token corresponding to the \"reserved\" keyword.\n//   - names: One or more names.\n//   - commas: Tokens that represent the \",\" runes that delimit the names.\n//     The length of commas must be one less than the length of names.\n//   - semicolon The token corresponding to the \";\" rune that ends the declaration.\nfunc NewReservedIdentifiersNode(keyword *KeywordNode, names []*IdentNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif len(names) == 0 {\n\t\tpanic(\"must have at least one name\")\n\t}\n\tif len(commas) != len(names)-1 {\n\t\tpanic(fmt.Sprintf(\"%d names requires %d commas, not %d\", len(names), len(names)-1, len(commas)))\n\t}\n\tnumChildren := len(names) * 2\n\tif semicolon != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, keyword)\n\tfor i, name := range names {\n\t\tif i > 0 {\n\t\t\tif commas[i-1] == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"commas[%d] is nil\", i-1))\n\t\t\t}\n\t\t\tchildren = append(children, commas[i-1])\n\t\t}\n\t\tif name == nil {\n\t\t\tpanic(fmt.Sprintf(\"names[%d] is nil\", i))\n\t\t}\n\t\tchildren = append(children, name)\n\t}\n\tif semicolon != nil {\n\t\tchildren = append(children, semicolon)\n\t}\n\treturn &ReservedNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:     keyword,\n\t\tIdentifiers: names,\n\t\tCommas:      commas,\n\t\tSemicolon:   semicolon,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/service.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// ServiceNode represents a service declaration. Example:\n//\n//\tservice Foo {\n//\t  rpc Bar (Baz) returns (Bob);\n//\t  rpc Frobnitz (stream Parts) returns (Gyzmeaux);\n//\t}\ntype ServiceNode struct {\n\tcompositeNode\n\tKeyword    *KeywordNode\n\tName       *IdentNode\n\tOpenBrace  *RuneNode\n\tDecls      []ServiceElement\n\tCloseBrace *RuneNode\n}\n\nfunc (*ServiceNode) fileElement() {}\n\n// NewServiceNode creates a new *ServiceNode. All arguments must be non-nil.\n//   - keyword: The token corresponding to the \"service\" keyword.\n//   - name: The token corresponding to the service's name.\n//   - openBrace: The token corresponding to the \"{\" rune that starts the body.\n//   - decls: All declarations inside the service body.\n//   - closeBrace: The token corresponding to the \"}\" rune that ends the body.\nfunc NewServiceNode(keyword *KeywordNode, name *IdentNode, openBrace *RuneNode, decls []ServiceElement, closeBrace *RuneNode) *ServiceNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif openBrace == nil {\n\t\tpanic(\"openBrace is nil\")\n\t}\n\tif closeBrace == nil {\n\t\tpanic(\"closeBrace is nil\")\n\t}\n\tchildren := make([]Node, 0, 4+len(decls))\n\tchildren = append(children, keyword, name, openBrace)\n\tfor _, decl := range decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *OptionNode, *RPCNode, *EmptyDeclNode:\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"invalid ServiceElement type: %T\", decl))\n\t\t}\n\t\tchildren = append(children, decl)\n\t}\n\tchildren = append(children, closeBrace)\n\n\treturn &ServiceNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:    keyword,\n\t\tName:       name,\n\t\tOpenBrace:  openBrace,\n\t\tDecls:      decls,\n\t\tCloseBrace: closeBrace,\n\t}\n}\n\nfunc (n *ServiceNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, decl := range n.Decls {\n\t\tif opt, ok := decl.(*OptionNode); ok {\n\t\t\tif !fn(opt) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ServiceElement is an interface implemented by all AST nodes that can\n// appear in the body of a service declaration.\ntype ServiceElement interface {\n\tNode\n\tserviceElement()\n}\n\nvar _ ServiceElement = (*OptionNode)(nil)\nvar _ ServiceElement = (*RPCNode)(nil)\nvar _ ServiceElement = (*EmptyDeclNode)(nil)\n\n// RPCDeclNode is a placeholder interface for AST nodes that represent RPC\n// declarations. This allows NoSourceNode to be used in place of *RPCNode\n// for some usages.\ntype RPCDeclNode interface {\n\tNodeWithOptions\n\tGetName() Node\n\tGetInputType() Node\n\tGetOutputType() Node\n}\n\nvar _ RPCDeclNode = (*RPCNode)(nil)\nvar _ RPCDeclNode = (*NoSourceNode)(nil)\n\n// RPCNode represents an RPC declaration. Example:\n//\n//\trpc Foo (Bar) returns (Baz);\ntype RPCNode struct {\n\tcompositeNode\n\tKeyword    *KeywordNode\n\tName       *IdentNode\n\tInput      *RPCTypeNode\n\tReturns    *KeywordNode\n\tOutput     *RPCTypeNode\n\tSemicolon  *RuneNode\n\tOpenBrace  *RuneNode\n\tDecls      []RPCElement\n\tCloseBrace *RuneNode\n}\n\nfunc (n *RPCNode) serviceElement() {}\n\n// NewRPCNode creates a new *RPCNode with no body. All arguments must be non-nil.\n//   - keyword: The token corresponding to the \"rpc\" keyword.\n//   - name: The token corresponding to the RPC's name.\n//   - input: The token corresponding to the RPC input message type.\n//   - returns: The token corresponding to the \"returns\" keyword that precedes the output type.\n//   - output: The token corresponding to the RPC output message type.\n//   - semicolon: The token corresponding to the \";\" rune that ends the declaration.\nfunc NewRPCNode(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, semicolon *RuneNode) *RPCNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif input == nil {\n\t\tpanic(\"input is nil\")\n\t}\n\tif returns == nil {\n\t\tpanic(\"returns is nil\")\n\t}\n\tif output == nil {\n\t\tpanic(\"output is nil\")\n\t}\n\tvar children []Node\n\tif semicolon == nil {\n\t\tchildren = []Node{keyword, name, input, returns, output}\n\t} else {\n\t\tchildren = []Node{keyword, name, input, returns, output, semicolon}\n\t}\n\treturn &RPCNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:   keyword,\n\t\tName:      name,\n\t\tInput:     input,\n\t\tReturns:   returns,\n\t\tOutput:    output,\n\t\tSemicolon: semicolon,\n\t}\n}\n\n// NewRPCNodeWithBody creates a new *RPCNode that includes a body (and possibly\n// options). All arguments must be non-nil.\n//   - keyword: The token corresponding to the \"rpc\" keyword.\n//   - name: The token corresponding to the RPC's name.\n//   - input: The token corresponding to the RPC input message type.\n//   - returns: The token corresponding to the \"returns\" keyword that precedes the output type.\n//   - output: The token corresponding to the RPC output message type.\n//   - openBrace: The token corresponding to the \"{\" rune that starts the body.\n//   - decls: All declarations inside the RPC body.\n//   - closeBrace: The token corresponding to the \"}\" rune that ends the body.\nfunc NewRPCNodeWithBody(keyword *KeywordNode, name *IdentNode, input *RPCTypeNode, returns *KeywordNode, output *RPCTypeNode, openBrace *RuneNode, decls []RPCElement, closeBrace *RuneNode) *RPCNode {\n\tif keyword == nil {\n\t\tpanic(\"keyword is nil\")\n\t}\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif input == nil {\n\t\tpanic(\"input is nil\")\n\t}\n\tif returns == nil {\n\t\tpanic(\"returns is nil\")\n\t}\n\tif output == nil {\n\t\tpanic(\"output is nil\")\n\t}\n\tif openBrace == nil {\n\t\tpanic(\"openBrace is nil\")\n\t}\n\tif closeBrace == nil {\n\t\tpanic(\"closeBrace is nil\")\n\t}\n\tchildren := make([]Node, 0, 7+len(decls))\n\tchildren = append(children, keyword, name, input, returns, output, openBrace)\n\tfor _, decl := range decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *OptionNode, *EmptyDeclNode:\n\t\tdefault:\n\t\t\tpanic(fmt.Sprintf(\"invalid RPCElement type: %T\", decl))\n\t\t}\n\t\tchildren = append(children, decl)\n\t}\n\tchildren = append(children, closeBrace)\n\n\treturn &RPCNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tKeyword:    keyword,\n\t\tName:       name,\n\t\tInput:      input,\n\t\tReturns:    returns,\n\t\tOutput:     output,\n\t\tOpenBrace:  openBrace,\n\t\tDecls:      decls,\n\t\tCloseBrace: closeBrace,\n\t}\n}\n\nfunc (n *RPCNode) GetName() Node {\n\treturn n.Name\n}\n\nfunc (n *RPCNode) GetInputType() Node {\n\treturn n.Input.MessageType\n}\n\nfunc (n *RPCNode) GetOutputType() Node {\n\treturn n.Output.MessageType\n}\n\nfunc (n *RPCNode) RangeOptions(fn func(*OptionNode) bool) {\n\tfor _, decl := range n.Decls {\n\t\tif opt, ok := decl.(*OptionNode); ok {\n\t\t\tif !fn(opt) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\n// RPCElement is an interface implemented by all AST nodes that can\n// appear in the body of an rpc declaration (aka method).\ntype RPCElement interface {\n\tNode\n\tmethodElement()\n}\n\nvar _ RPCElement = (*OptionNode)(nil)\nvar _ RPCElement = (*EmptyDeclNode)(nil)\n\n// RPCTypeNode represents the declaration of a request or response type for an\n// RPC. Example:\n//\n//\t(stream foo.Bar)\ntype RPCTypeNode struct {\n\tcompositeNode\n\tOpenParen   *RuneNode\n\tStream      *KeywordNode\n\tMessageType IdentValueNode\n\tCloseParen  *RuneNode\n}\n\n// NewRPCTypeNode creates a new *RPCTypeNode. All arguments must be non-nil\n// except stream, which may be nil.\n//   - openParen: The token corresponding to the \"(\" rune that starts the declaration.\n//   - stream: The token corresponding to the \"stream\" keyword or nil if not present.\n//   - msgType: The token corresponding to the message type's name.\n//   - closeParen: The token corresponding to the \")\" rune that ends the declaration.\nfunc NewRPCTypeNode(openParen *RuneNode, stream *KeywordNode, msgType IdentValueNode, closeParen *RuneNode) *RPCTypeNode {\n\tif openParen == nil {\n\t\tpanic(\"openParen is nil\")\n\t}\n\tif msgType == nil {\n\t\tpanic(\"msgType is nil\")\n\t}\n\tif closeParen == nil {\n\t\tpanic(\"closeParen is nil\")\n\t}\n\tvar children []Node\n\tif stream != nil {\n\t\tchildren = []Node{openParen, stream, msgType, closeParen}\n\t} else {\n\t\tchildren = []Node{openParen, msgType, closeParen}\n\t}\n\n\treturn &RPCTypeNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tOpenParen:   openParen,\n\t\tStream:      stream,\n\t\tMessageType: msgType,\n\t\tCloseParen:  closeParen,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/values.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n)\n\n// ValueNode is an AST node that represents a literal value.\n//\n// It also includes references (e.g. IdentifierValueNode), which can be\n// used as values in some contexts, such as describing the default value\n// for a field, which can refer to an enum value.\n//\n// This also allows NoSourceNode to be used in place of a real value node\n// for some usages.\ntype ValueNode interface {\n\tNode\n\t// Value returns a Go representation of the value. For scalars, this\n\t// will be a string, int64, uint64, float64, or bool. This could also\n\t// be an Identifier (e.g. IdentValueNodes). It can also be a composite\n\t// literal:\n\t//   * For array literals, the type returned will be []ValueNode\n\t//   * For message literals, the type returned will be []*MessageFieldNode\n\t//\n\t// If the ValueNode is a NoSourceNode, indicating that there is no actual\n\t// source code (and thus not AST information), then this method always\n\t// returns nil.\n\tValue() interface{}\n}\n\nvar _ ValueNode = (*IdentNode)(nil)\nvar _ ValueNode = (*CompoundIdentNode)(nil)\nvar _ ValueNode = (*StringLiteralNode)(nil)\nvar _ ValueNode = (*CompoundStringLiteralNode)(nil)\nvar _ ValueNode = (*UintLiteralNode)(nil)\nvar _ ValueNode = (*NegativeIntLiteralNode)(nil)\nvar _ ValueNode = (*FloatLiteralNode)(nil)\nvar _ ValueNode = (*SpecialFloatLiteralNode)(nil)\nvar _ ValueNode = (*SignedFloatLiteralNode)(nil)\nvar _ ValueNode = (*ArrayLiteralNode)(nil)\nvar _ ValueNode = (*MessageLiteralNode)(nil)\nvar _ ValueNode = (*NoSourceNode)(nil)\n\n// StringValueNode is an AST node that represents a string literal.\n// Such a node can be a single literal (*StringLiteralNode) or a\n// concatenation of multiple literals (*CompoundStringLiteralNode).\ntype StringValueNode interface {\n\tValueNode\n\tAsString() string\n}\n\nvar _ StringValueNode = (*StringLiteralNode)(nil)\nvar _ StringValueNode = (*CompoundStringLiteralNode)(nil)\n\n// StringLiteralNode represents a simple string literal. Example:\n//\n//\t\"proto2\"\ntype StringLiteralNode struct {\n\tterminalNode\n\t// Val is the actual string value that the literal indicates.\n\tVal string\n}\n\n// NewStringLiteralNode creates a new *StringLiteralNode with the given val.\nfunc NewStringLiteralNode(val string, tok Token) *StringLiteralNode {\n\treturn &StringLiteralNode{\n\t\tterminalNode: tok.asTerminalNode(),\n\t\tVal:          val,\n\t}\n}\n\nfunc (n *StringLiteralNode) Value() interface{} {\n\treturn n.AsString()\n}\n\nfunc (n *StringLiteralNode) AsString() string {\n\treturn n.Val\n}\n\n// CompoundStringLiteralNode represents a compound string literal, which is\n// the concatenaton of adjacent string literals. Example:\n//\n//\t\"this \"  \"is\"   \" all one \"   \"string\"\ntype CompoundStringLiteralNode struct {\n\tcompositeNode\n\tVal string\n}\n\n// NewCompoundLiteralStringNode creates a new *CompoundStringLiteralNode that\n// consists of the given string components. The components argument may not be\n// empty.\nfunc NewCompoundLiteralStringNode(components ...*StringLiteralNode) *CompoundStringLiteralNode {\n\tif len(components) == 0 {\n\t\tpanic(\"must have at least one component\")\n\t}\n\tchildren := make([]Node, len(components))\n\tvar b strings.Builder\n\tfor i, comp := range components {\n\t\tchildren[i] = comp\n\t\tb.WriteString(comp.Val)\n\t}\n\treturn &CompoundStringLiteralNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tVal: b.String(),\n\t}\n}\n\nfunc (n *CompoundStringLiteralNode) Value() interface{} {\n\treturn n.AsString()\n}\n\nfunc (n *CompoundStringLiteralNode) AsString() string {\n\treturn n.Val\n}\n\n// IntValueNode is an AST node that represents an integer literal. If\n// an integer literal is too large for an int64 (or uint64 for\n// positive literals), it is represented instead by a FloatValueNode.\ntype IntValueNode interface {\n\tValueNode\n\tAsInt64() (int64, bool)\n\tAsUint64() (uint64, bool)\n}\n\n// AsInt32 range checks the given int value and returns its value is\n// in the range or 0, false if it is outside the range.\nfunc AsInt32(n IntValueNode, minVal, maxVal int32) (int32, bool) {\n\ti, ok := n.AsInt64()\n\tif !ok {\n\t\treturn 0, false\n\t}\n\tif i < int64(minVal) || i > int64(maxVal) {\n\t\treturn 0, false\n\t}\n\treturn int32(i), true\n}\n\nvar _ IntValueNode = (*UintLiteralNode)(nil)\nvar _ IntValueNode = (*NegativeIntLiteralNode)(nil)\n\n// UintLiteralNode represents a simple integer literal with no sign character.\ntype UintLiteralNode struct {\n\tterminalNode\n\t// Val is the numeric value indicated by the literal\n\tVal uint64\n}\n\n// NewUintLiteralNode creates a new *UintLiteralNode with the given val.\nfunc NewUintLiteralNode(val uint64, tok Token) *UintLiteralNode {\n\treturn &UintLiteralNode{\n\t\tterminalNode: tok.asTerminalNode(),\n\t\tVal:          val,\n\t}\n}\n\nfunc (n *UintLiteralNode) Value() interface{} {\n\treturn n.Val\n}\n\nfunc (n *UintLiteralNode) AsInt64() (int64, bool) {\n\tif n.Val > math.MaxInt64 {\n\t\treturn 0, false\n\t}\n\treturn int64(n.Val), true\n}\n\nfunc (n *UintLiteralNode) AsUint64() (uint64, bool) {\n\treturn n.Val, true\n}\n\nfunc (n *UintLiteralNode) AsFloat() float64 {\n\treturn float64(n.Val)\n}\n\n// NegativeIntLiteralNode represents an integer literal with a negative (-) sign.\ntype NegativeIntLiteralNode struct {\n\tcompositeNode\n\tMinus *RuneNode\n\tUint  *UintLiteralNode\n\tVal   int64\n}\n\n// NewNegativeIntLiteralNode creates a new *NegativeIntLiteralNode. Both\n// arguments must be non-nil.\nfunc NewNegativeIntLiteralNode(sign *RuneNode, i *UintLiteralNode) *NegativeIntLiteralNode {\n\tif sign == nil {\n\t\tpanic(\"sign is nil\")\n\t}\n\tif i == nil {\n\t\tpanic(\"i is nil\")\n\t}\n\tchildren := []Node{sign, i}\n\treturn &NegativeIntLiteralNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tMinus: sign,\n\t\tUint:  i,\n\t\tVal:   -int64(i.Val),\n\t}\n}\n\nfunc (n *NegativeIntLiteralNode) Value() interface{} {\n\treturn n.Val\n}\n\nfunc (n *NegativeIntLiteralNode) AsInt64() (int64, bool) {\n\treturn n.Val, true\n}\n\nfunc (n *NegativeIntLiteralNode) AsUint64() (uint64, bool) {\n\tif n.Val < 0 {\n\t\treturn 0, false\n\t}\n\treturn uint64(n.Val), true\n}\n\n// FloatValueNode is an AST node that represents a numeric literal with\n// a floating point, in scientific notation, or too large to fit in an\n// int64 or uint64.\ntype FloatValueNode interface {\n\tValueNode\n\tAsFloat() float64\n}\n\nvar _ FloatValueNode = (*FloatLiteralNode)(nil)\nvar _ FloatValueNode = (*SpecialFloatLiteralNode)(nil)\nvar _ FloatValueNode = (*UintLiteralNode)(nil)\n\n// FloatLiteralNode represents a floating point numeric literal.\ntype FloatLiteralNode struct {\n\tterminalNode\n\t// Val is the numeric value indicated by the literal\n\tVal float64\n}\n\n// NewFloatLiteralNode creates a new *FloatLiteralNode with the given val.\nfunc NewFloatLiteralNode(val float64, tok Token) *FloatLiteralNode {\n\treturn &FloatLiteralNode{\n\t\tterminalNode: tok.asTerminalNode(),\n\t\tVal:          val,\n\t}\n}\n\nfunc (n *FloatLiteralNode) Value() interface{} {\n\treturn n.AsFloat()\n}\n\nfunc (n *FloatLiteralNode) AsFloat() float64 {\n\treturn n.Val\n}\n\n// SpecialFloatLiteralNode represents a special floating point numeric literal\n// for \"inf\" and \"nan\" values.\ntype SpecialFloatLiteralNode struct {\n\t*KeywordNode\n\tVal float64\n}\n\n// NewSpecialFloatLiteralNode returns a new *SpecialFloatLiteralNode for the\n// given keyword. The given keyword should be \"inf\", \"infinity\", or \"nan\"\n// in any case.\nfunc NewSpecialFloatLiteralNode(name *KeywordNode) *SpecialFloatLiteralNode {\n\tvar f float64\n\tswitch strings.ToLower(name.Val) {\n\tcase \"inf\", \"infinity\":\n\t\tf = math.Inf(1)\n\tdefault:\n\t\tf = math.NaN()\n\t}\n\treturn &SpecialFloatLiteralNode{\n\t\tKeywordNode: name,\n\t\tVal:         f,\n\t}\n}\n\nfunc (n *SpecialFloatLiteralNode) Value() interface{} {\n\treturn n.AsFloat()\n}\n\nfunc (n *SpecialFloatLiteralNode) AsFloat() float64 {\n\treturn n.Val\n}\n\n// SignedFloatLiteralNode represents a signed floating point number.\ntype SignedFloatLiteralNode struct {\n\tcompositeNode\n\tSign  *RuneNode\n\tFloat FloatValueNode\n\tVal   float64\n}\n\n// NewSignedFloatLiteralNode creates a new *SignedFloatLiteralNode. Both\n// arguments must be non-nil.\nfunc NewSignedFloatLiteralNode(sign *RuneNode, f FloatValueNode) *SignedFloatLiteralNode {\n\tif sign == nil {\n\t\tpanic(\"sign is nil\")\n\t}\n\tif f == nil {\n\t\tpanic(\"f is nil\")\n\t}\n\tchildren := []Node{sign, f}\n\tval := f.AsFloat()\n\tif sign.Rune == '-' {\n\t\tval = -val\n\t}\n\treturn &SignedFloatLiteralNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tSign:  sign,\n\t\tFloat: f,\n\t\tVal:   val,\n\t}\n}\n\nfunc (n *SignedFloatLiteralNode) Value() interface{} {\n\treturn n.Val\n}\n\nfunc (n *SignedFloatLiteralNode) AsFloat() float64 {\n\treturn n.Val\n}\n\n// ArrayLiteralNode represents an array literal, which is only allowed inside of\n// a MessageLiteralNode, to indicate values for a repeated field. Example:\n//\n//\t[\"foo\", \"bar\", \"baz\"]\ntype ArrayLiteralNode struct {\n\tcompositeNode\n\tOpenBracket *RuneNode\n\tElements    []ValueNode\n\t// Commas represent the separating ',' characters between elements. The\n\t// length of this slice must be exactly len(Elements)-1, with each item\n\t// in Elements having a corresponding item in this slice *except the last*\n\t// (since a trailing comma is not allowed).\n\tCommas       []*RuneNode\n\tCloseBracket *RuneNode\n}\n\n// NewArrayLiteralNode creates a new *ArrayLiteralNode. The openBracket and\n// closeBracket args must be non-nil and represent the \"[\" and \"]\" runes that\n// surround the array values. The given commas arg must have a length that is\n// one less than the length of the vals arg. However, vals may be empty, in\n// which case commas must also be empty.\nfunc NewArrayLiteralNode(openBracket *RuneNode, vals []ValueNode, commas []*RuneNode, closeBracket *RuneNode) *ArrayLiteralNode {\n\tif openBracket == nil {\n\t\tpanic(\"openBracket is nil\")\n\t}\n\tif closeBracket == nil {\n\t\tpanic(\"closeBracket is nil\")\n\t}\n\tif len(vals) == 0 && len(commas) != 0 {\n\t\tpanic(\"vals is empty but commas is not\")\n\t}\n\tif len(vals) > 0 && len(commas) != len(vals)-1 {\n\t\tpanic(fmt.Sprintf(\"%d vals requires %d commas, not %d\", len(vals), len(vals)-1, len(commas)))\n\t}\n\tchildren := make([]Node, 0, len(vals)*2+1)\n\tchildren = append(children, openBracket)\n\tfor i, val := range vals {\n\t\tif i > 0 {\n\t\t\tif commas[i-1] == nil {\n\t\t\t\tpanic(fmt.Sprintf(\"commas[%d] is nil\", i-1))\n\t\t\t}\n\t\t\tchildren = append(children, commas[i-1])\n\t\t}\n\t\tif val == nil {\n\t\t\tpanic(fmt.Sprintf(\"vals[%d] is nil\", i))\n\t\t}\n\t\tchildren = append(children, val)\n\t}\n\tchildren = append(children, closeBracket)\n\n\treturn &ArrayLiteralNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tOpenBracket:  openBracket,\n\t\tElements:     vals,\n\t\tCommas:       commas,\n\t\tCloseBracket: closeBracket,\n\t}\n}\n\nfunc (n *ArrayLiteralNode) Value() interface{} {\n\treturn n.Elements\n}\n\n// MessageLiteralNode represents a message literal, which is compatible with the\n// protobuf text format and can be used for custom options with message types.\n// Example:\n//\n//\t{ foo:1 foo:2 foo:3 bar:<name:\"abc\" id:123> }\ntype MessageLiteralNode struct {\n\tcompositeNode\n\tOpen     *RuneNode // should be '{' or '<'\n\tElements []*MessageFieldNode\n\t// Separator characters between elements, which can be either ','\n\t// or ';' if present. This slice must be exactly len(Elements) in\n\t// length, with each item in Elements having one corresponding item\n\t// in Seps. Separators in message literals are optional, so a given\n\t// item in this slice may be nil to indicate absence of a separator.\n\tSeps  []*RuneNode\n\tClose *RuneNode // should be '}' or '>', depending on Open\n}\n\n// NewMessageLiteralNode creates a new *MessageLiteralNode. The openSym and\n// closeSym runes must not be nil and should be \"{\" and \"}\" or \"<\" and \">\".\n//\n// Unlike separators (dots and commas) used for other AST nodes that represent\n// a list of elements, the seps arg must be the SAME length as vals, and it may\n// contain nil values to indicate absence of a separator (in fact, it could be\n// all nils).\nfunc NewMessageLiteralNode(openSym *RuneNode, vals []*MessageFieldNode, seps []*RuneNode, closeSym *RuneNode) *MessageLiteralNode {\n\tif openSym == nil {\n\t\tpanic(\"openSym is nil\")\n\t}\n\tif closeSym == nil {\n\t\tpanic(\"closeSym is nil\")\n\t}\n\tif len(seps) != len(vals) {\n\t\tpanic(fmt.Sprintf(\"%d vals requires %d commas, not %d\", len(vals), len(vals), len(seps)))\n\t}\n\tnumChildren := len(vals) + 2\n\tfor _, sep := range seps {\n\t\tif sep != nil {\n\t\t\tnumChildren++\n\t\t}\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, openSym)\n\tfor i, val := range vals {\n\t\tif val == nil {\n\t\t\tpanic(fmt.Sprintf(\"vals[%d] is nil\", i))\n\t\t}\n\t\tchildren = append(children, val)\n\t\tif seps[i] != nil {\n\t\t\tchildren = append(children, seps[i])\n\t\t}\n\t}\n\tchildren = append(children, closeSym)\n\n\treturn &MessageLiteralNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tOpen:     openSym,\n\t\tElements: vals,\n\t\tSeps:     seps,\n\t\tClose:    closeSym,\n\t}\n}\n\nfunc (n *MessageLiteralNode) Value() interface{} {\n\treturn n.Elements\n}\n\n// MessageFieldNode represents a single field (name and value) inside of a\n// message literal. Example:\n//\n//\tfoo:\"bar\"\ntype MessageFieldNode struct {\n\tcompositeNode\n\tName *FieldReferenceNode\n\t// Sep represents the ':' separator between the name and value. If\n\t// the value is a message or list literal (and thus starts with '<',\n\t// '{', or '['), then the separator may be omitted and this field may\n\t// be nil.\n\tSep *RuneNode\n\tVal ValueNode\n}\n\n// NewMessageFieldNode creates a new *MessageFieldNode. All args except sep\n// must be non-nil.\nfunc NewMessageFieldNode(name *FieldReferenceNode, sep *RuneNode, val ValueNode) *MessageFieldNode {\n\tif name == nil {\n\t\tpanic(\"name is nil\")\n\t}\n\tif val == nil {\n\t\tpanic(\"val is nil\")\n\t}\n\tnumChildren := 2\n\tif sep != nil {\n\t\tnumChildren++\n\t}\n\tchildren := make([]Node, 0, numChildren)\n\tchildren = append(children, name)\n\tif sep != nil {\n\t\tchildren = append(children, sep)\n\t}\n\tchildren = append(children, val)\n\n\treturn &MessageFieldNode{\n\t\tcompositeNode: compositeNode{\n\t\t\tchildren: children,\n\t\t},\n\t\tName: name,\n\t\tSep:  sep,\n\t\tVal:  val,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/ast/walk.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage ast\n\nimport \"fmt\"\n\n// Walk conducts a walk of the AST rooted at the given root using the\n// given visitor. It performs a \"pre-order traversal\", visiting a\n// given AST node before it visits that node's descendants.\n//\n// If a visitor returns an error while walking the tree, the entire\n// operation is aborted and that error is returned.\nfunc Walk(root Node, v Visitor, opts ...WalkOption) error {\n\tvar wOpts walkOptions\n\tfor _, opt := range opts {\n\t\topt(&wOpts)\n\t}\n\treturn walk(root, v, wOpts)\n}\n\n// WalkOption represents an option used with the Walk function. These\n// allow optional before and after hooks to be invoked as each node in\n// the tree is visited.\ntype WalkOption func(*walkOptions)\n\ntype walkOptions struct {\n\tbefore, after func(Node) error\n}\n\n// WithBefore returns a WalkOption that will cause the given function to be\n// invoked before a node is visited during a walk operation. If this hook\n// returns an error, the node is not visited and the walk operation is aborted.\nfunc WithBefore(fn func(Node) error) WalkOption {\n\treturn func(options *walkOptions) {\n\t\toptions.before = fn\n\t}\n}\n\n// WithAfter returns a WalkOption that will cause the given function to be\n// invoked after a node (as well as any descendants) is visited during a walk\n// operation. If this hook returns an error, the node is not visited and the\n// walk operation is aborted.\n//\n// If the walk is aborted due to some other visitor or before hook returning an\n// error, the after hook is still called for all nodes that have been visited.\n// However, the walk operation fails with the first error it encountered, so any\n// error returned from an after hook is effectively ignored.\nfunc WithAfter(fn func(Node) error) WalkOption {\n\treturn func(options *walkOptions) {\n\t\toptions.after = fn\n\t}\n}\n\nfunc walk(root Node, v Visitor, opts walkOptions) (err error) {\n\tif opts.before != nil {\n\t\tif err := opts.before(root); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif opts.after != nil {\n\t\tdefer func() {\n\t\t\tif afterErr := opts.after(root); afterErr != nil {\n\t\t\t\t// if another call already returned an error then we\n\t\t\t\t// have to ignore the error from the after hook\n\t\t\t\tif err == nil {\n\t\t\t\t\terr = afterErr\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\n\tif err := Visit(root, v); err != nil {\n\t\treturn err\n\t}\n\n\tif comp, ok := root.(CompositeNode); ok {\n\t\tfor _, child := range comp.Children() {\n\t\t\tif err := walk(child, v, opts); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// Visit implements the double-dispatch idiom and visits the given node by\n// calling the appropriate method of the given visitor.\nfunc Visit(n Node, v Visitor) error {\n\tswitch n := n.(type) {\n\tcase *FileNode:\n\t\treturn v.VisitFileNode(n)\n\tcase *SyntaxNode:\n\t\treturn v.VisitSyntaxNode(n)\n\tcase *EditionNode:\n\t\treturn v.VisitEditionNode(n)\n\tcase *PackageNode:\n\t\treturn v.VisitPackageNode(n)\n\tcase *ImportNode:\n\t\treturn v.VisitImportNode(n)\n\tcase *OptionNode:\n\t\treturn v.VisitOptionNode(n)\n\tcase *OptionNameNode:\n\t\treturn v.VisitOptionNameNode(n)\n\tcase *FieldReferenceNode:\n\t\treturn v.VisitFieldReferenceNode(n)\n\tcase *CompactOptionsNode:\n\t\treturn v.VisitCompactOptionsNode(n)\n\tcase *MessageNode:\n\t\treturn v.VisitMessageNode(n)\n\tcase *ExtendNode:\n\t\treturn v.VisitExtendNode(n)\n\tcase *ExtensionRangeNode:\n\t\treturn v.VisitExtensionRangeNode(n)\n\tcase *ReservedNode:\n\t\treturn v.VisitReservedNode(n)\n\tcase *RangeNode:\n\t\treturn v.VisitRangeNode(n)\n\tcase *FieldNode:\n\t\treturn v.VisitFieldNode(n)\n\tcase *GroupNode:\n\t\treturn v.VisitGroupNode(n)\n\tcase *MapFieldNode:\n\t\treturn v.VisitMapFieldNode(n)\n\tcase *MapTypeNode:\n\t\treturn v.VisitMapTypeNode(n)\n\tcase *OneofNode:\n\t\treturn v.VisitOneofNode(n)\n\tcase *EnumNode:\n\t\treturn v.VisitEnumNode(n)\n\tcase *EnumValueNode:\n\t\treturn v.VisitEnumValueNode(n)\n\tcase *ServiceNode:\n\t\treturn v.VisitServiceNode(n)\n\tcase *RPCNode:\n\t\treturn v.VisitRPCNode(n)\n\tcase *RPCTypeNode:\n\t\treturn v.VisitRPCTypeNode(n)\n\tcase *IdentNode:\n\t\treturn v.VisitIdentNode(n)\n\tcase *CompoundIdentNode:\n\t\treturn v.VisitCompoundIdentNode(n)\n\tcase *StringLiteralNode:\n\t\treturn v.VisitStringLiteralNode(n)\n\tcase *CompoundStringLiteralNode:\n\t\treturn v.VisitCompoundStringLiteralNode(n)\n\tcase *UintLiteralNode:\n\t\treturn v.VisitUintLiteralNode(n)\n\tcase *NegativeIntLiteralNode:\n\t\treturn v.VisitNegativeIntLiteralNode(n)\n\tcase *FloatLiteralNode:\n\t\treturn v.VisitFloatLiteralNode(n)\n\tcase *SpecialFloatLiteralNode:\n\t\treturn v.VisitSpecialFloatLiteralNode(n)\n\tcase *SignedFloatLiteralNode:\n\t\treturn v.VisitSignedFloatLiteralNode(n)\n\tcase *ArrayLiteralNode:\n\t\treturn v.VisitArrayLiteralNode(n)\n\tcase *MessageLiteralNode:\n\t\treturn v.VisitMessageLiteralNode(n)\n\tcase *MessageFieldNode:\n\t\treturn v.VisitMessageFieldNode(n)\n\tcase *KeywordNode:\n\t\treturn v.VisitKeywordNode(n)\n\tcase *RuneNode:\n\t\treturn v.VisitRuneNode(n)\n\tcase *EmptyDeclNode:\n\t\treturn v.VisitEmptyDeclNode(n)\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected type of node: %T\", n))\n\t}\n}\n\n// AncestorTracker is used to track the path of nodes during a walk operation.\n// By passing AsWalkOptions to a call to Walk, a visitor can inspect the path to\n// the node being visited using this tracker.\ntype AncestorTracker struct {\n\tancestors []Node\n}\n\n// AsWalkOptions returns WalkOption values that will cause this ancestor tracker\n// to track the path through the AST during the walk operation.\nfunc (t *AncestorTracker) AsWalkOptions() []WalkOption {\n\treturn []WalkOption{\n\t\tWithBefore(func(n Node) error {\n\t\t\tt.ancestors = append(t.ancestors, n)\n\t\t\treturn nil\n\t\t}),\n\t\tWithAfter(func(_ Node) error {\n\t\t\tt.ancestors = t.ancestors[:len(t.ancestors)-1]\n\t\t\treturn nil\n\t\t}),\n\t}\n}\n\n// Path returns a slice of nodes that represents the path from the root of the\n// walk operaiton to the currently visited node. The first element in the path\n// is the root supplied to Walk. The last element in the path is the currently\n// visited node.\n//\n// The returned slice is not a defensive copy; so callers should NOT mutate it.\nfunc (t *AncestorTracker) Path() []Node {\n\treturn t.ancestors\n}\n\n// Parent returns the parent node of the currently visited node. If the node\n// currently being visited is the root supplied to Walk then nil is returned.\nfunc (t *AncestorTracker) Parent() Node {\n\tif len(t.ancestors) <= 1 {\n\t\treturn nil\n\t}\n\treturn t.ancestors[len(t.ancestors)-2]\n}\n\n// VisitChildren visits all direct children of the given node using the given\n// visitor. If visiting a child returns an error, that error is immediately\n// returned, and other children will not be visited.\nfunc VisitChildren(n CompositeNode, v Visitor) error {\n\tfor _, ch := range n.Children() {\n\t\tif err := Visit(ch, v); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// Visitor provides a technique for walking the AST that allows for\n// dynamic dispatch, where a particular function is invoked based on\n// the runtime type of the argument.\n//\n// It consists of a number of functions, each of which matches a\n// concrete Node type.\n//\n// NOTE: As the language evolves, new methods may be added to this\n// interface to correspond to new grammar elements. That is why it\n// cannot be directly implemented outside this package. Visitor\n// implementations must embed NoOpVisitor and then implement the\n// subset of methods of interest. If such an implementation is used\n// with an AST that has newer elements, the visitor will not do\n// anything in response to the new node types.\n//\n// An alternative to embedding NoOpVisitor is to use an instance of\n// SimpleVisitor.\n//\n// Visitors can be supplied to a Walk operation or passed to a call\n// to Visit or VisitChildren.\n//\n// Note that there are some AST node types defined in this package\n// that do not have corresponding visit methods. These are synthetic\n// node types, that have specialized use from the parser, but never\n// appear in an actual AST (which is always rooted at FileNode).\n// These include SyntheticMapField, SyntheticOneof,\n// SyntheticGroupMessageNode, and SyntheticMapEntryNode.\ntype Visitor interface {\n\t// VisitFileNode is invoked when visiting a *FileNode in the AST.\n\tVisitFileNode(*FileNode) error\n\t// VisitSyntaxNode is invoked when visiting a *SyntaxNode in the AST.\n\tVisitSyntaxNode(*SyntaxNode) error\n\t// VisitEditionNode is invoked when visiting an *EditionNode in the AST.\n\tVisitEditionNode(*EditionNode) error\n\t// VisitPackageNode is invoked when visiting a *PackageNode in the AST.\n\tVisitPackageNode(*PackageNode) error\n\t// VisitImportNode is invoked when visiting an *ImportNode in the AST.\n\tVisitImportNode(*ImportNode) error\n\t// VisitOptionNode is invoked when visiting an *OptionNode in the AST.\n\tVisitOptionNode(*OptionNode) error\n\t// VisitOptionNameNode is invoked when visiting an *OptionNameNode in the AST.\n\tVisitOptionNameNode(*OptionNameNode) error\n\t// VisitFieldReferenceNode is invoked when visiting a *FieldReferenceNode in the AST.\n\tVisitFieldReferenceNode(*FieldReferenceNode) error\n\t// VisitCompactOptionsNode is invoked when visiting a *CompactOptionsNode in the AST.\n\tVisitCompactOptionsNode(*CompactOptionsNode) error\n\t// VisitMessageNode is invoked when visiting a *MessageNode in the AST.\n\tVisitMessageNode(*MessageNode) error\n\t// VisitExtendNode is invoked when visiting an *ExtendNode in the AST.\n\tVisitExtendNode(*ExtendNode) error\n\t// VisitExtensionRangeNode is invoked when visiting an *ExtensionRangeNode in the AST.\n\tVisitExtensionRangeNode(*ExtensionRangeNode) error\n\t// VisitReservedNode is invoked when visiting a *ReservedNode in the AST.\n\tVisitReservedNode(*ReservedNode) error\n\t// VisitRangeNode is invoked when visiting a *RangeNode in the AST.\n\tVisitRangeNode(*RangeNode) error\n\t// VisitFieldNode is invoked when visiting a *FieldNode in the AST.\n\tVisitFieldNode(*FieldNode) error\n\t// VisitGroupNode is invoked when visiting a *GroupNode in the AST.\n\tVisitGroupNode(*GroupNode) error\n\t// VisitMapFieldNode is invoked when visiting a *MapFieldNode in the AST.\n\tVisitMapFieldNode(*MapFieldNode) error\n\t// VisitMapTypeNode is invoked when visiting a *MapTypeNode in the AST.\n\tVisitMapTypeNode(*MapTypeNode) error\n\t// VisitOneofNode is invoked when visiting a *OneofNode in the AST.\n\tVisitOneofNode(*OneofNode) error\n\t// VisitEnumNode is invoked when visiting an *EnumNode in the AST.\n\tVisitEnumNode(*EnumNode) error\n\t// VisitEnumValueNode is invoked when visiting an *EnumValueNode in the AST.\n\tVisitEnumValueNode(*EnumValueNode) error\n\t// VisitServiceNode is invoked when visiting a *ServiceNode in the AST.\n\tVisitServiceNode(*ServiceNode) error\n\t// VisitRPCNode is invoked when visiting an *RPCNode in the AST.\n\tVisitRPCNode(*RPCNode) error\n\t// VisitRPCTypeNode is invoked when visiting an *RPCTypeNode in the AST.\n\tVisitRPCTypeNode(*RPCTypeNode) error\n\t// VisitIdentNode is invoked when visiting an *IdentNode in the AST.\n\tVisitIdentNode(*IdentNode) error\n\t// VisitCompoundIdentNode is invoked when visiting a *CompoundIdentNode in the AST.\n\tVisitCompoundIdentNode(*CompoundIdentNode) error\n\t// VisitStringLiteralNode is invoked when visiting a *StringLiteralNode in the AST.\n\tVisitStringLiteralNode(*StringLiteralNode) error\n\t// VisitCompoundStringLiteralNode is invoked when visiting a *CompoundStringLiteralNode in the AST.\n\tVisitCompoundStringLiteralNode(*CompoundStringLiteralNode) error\n\t// VisitUintLiteralNode is invoked when visiting a *UintLiteralNode in the AST.\n\tVisitUintLiteralNode(*UintLiteralNode) error\n\t// VisitNegativeIntLiteralNode is invoked when visiting a *NegativeIntLiteralNode in the AST.\n\tVisitNegativeIntLiteralNode(*NegativeIntLiteralNode) error\n\t// VisitFloatLiteralNode is invoked when visiting a *FloatLiteralNode in the AST.\n\tVisitFloatLiteralNode(*FloatLiteralNode) error\n\t// VisitSpecialFloatLiteralNode is invoked when visiting a *SpecialFloatLiteralNode in the AST.\n\tVisitSpecialFloatLiteralNode(*SpecialFloatLiteralNode) error\n\t// VisitSignedFloatLiteralNode is invoked when visiting a *SignedFloatLiteralNode in the AST.\n\tVisitSignedFloatLiteralNode(*SignedFloatLiteralNode) error\n\t// VisitArrayLiteralNode is invoked when visiting an *ArrayLiteralNode in the AST.\n\tVisitArrayLiteralNode(*ArrayLiteralNode) error\n\t// VisitMessageLiteralNode is invoked when visiting a *MessageLiteralNode in the AST.\n\tVisitMessageLiteralNode(*MessageLiteralNode) error\n\t// VisitMessageFieldNode is invoked when visiting a *MessageFieldNode in the AST.\n\tVisitMessageFieldNode(*MessageFieldNode) error\n\t// VisitKeywordNode is invoked when visiting a *KeywordNode in the AST.\n\tVisitKeywordNode(*KeywordNode) error\n\t// VisitRuneNode is invoked when visiting a *RuneNode in the AST.\n\tVisitRuneNode(*RuneNode) error\n\t// VisitEmptyDeclNode is invoked when visiting a *EmptyDeclNode in the AST.\n\tVisitEmptyDeclNode(*EmptyDeclNode) error\n\n\t// Unexported method prevents callers from directly implementing.\n\tisVisitor()\n}\n\n// NoOpVisitor is a visitor implementation that does nothing. All methods\n// unconditionally return nil. This can be embedded into a struct to make that\n// struct implement the Visitor interface, and only the relevant visit methods\n// then need to be implemented on the struct.\ntype NoOpVisitor struct{}\n\nvar _ Visitor = NoOpVisitor{}\n\nfunc (n NoOpVisitor) isVisitor() {}\n\nfunc (n NoOpVisitor) VisitFileNode(_ *FileNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitSyntaxNode(_ *SyntaxNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitEditionNode(_ *EditionNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitPackageNode(_ *PackageNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitImportNode(_ *ImportNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitOptionNode(_ *OptionNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitOptionNameNode(_ *OptionNameNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitFieldReferenceNode(_ *FieldReferenceNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitCompactOptionsNode(_ *CompactOptionsNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitMessageNode(_ *MessageNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitExtendNode(_ *ExtendNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitExtensionRangeNode(_ *ExtensionRangeNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitReservedNode(_ *ReservedNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitRangeNode(_ *RangeNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitFieldNode(_ *FieldNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitGroupNode(_ *GroupNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitMapFieldNode(_ *MapFieldNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitMapTypeNode(_ *MapTypeNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitOneofNode(_ *OneofNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitEnumNode(_ *EnumNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitEnumValueNode(_ *EnumValueNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitServiceNode(_ *ServiceNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitRPCNode(_ *RPCNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitRPCTypeNode(_ *RPCTypeNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitIdentNode(_ *IdentNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitCompoundIdentNode(_ *CompoundIdentNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitStringLiteralNode(_ *StringLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitCompoundStringLiteralNode(_ *CompoundStringLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitUintLiteralNode(_ *UintLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitNegativeIntLiteralNode(_ *NegativeIntLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitFloatLiteralNode(_ *FloatLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitSpecialFloatLiteralNode(_ *SpecialFloatLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitSignedFloatLiteralNode(_ *SignedFloatLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitArrayLiteralNode(_ *ArrayLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitMessageLiteralNode(_ *MessageLiteralNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitMessageFieldNode(_ *MessageFieldNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitKeywordNode(_ *KeywordNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitRuneNode(_ *RuneNode) error {\n\treturn nil\n}\n\nfunc (n NoOpVisitor) VisitEmptyDeclNode(_ *EmptyDeclNode) error {\n\treturn nil\n}\n\n// SimpleVisitor is a visitor implementation that uses numerous function fields.\n// If a relevant function field is not nil, then it will be invoked when a node\n// is visited.\n//\n// In addition to a function for each concrete node type (and thus for each\n// Visit* method of the Visitor interface), it also has function fields that\n// accept interface types. So a visitor can, for example, easily treat all\n// ValueNodes uniformly by providing a non-nil value for DoVisitValueNode\n// instead of having to supply values for the various DoVisit*Node methods\n// corresponding to all types that implement ValueNode.\n//\n// The most specific function provided that matches a given node is the one that\n// will be invoked. For example, DoVisitStringValueNode will be called if\n// present and applicable before DoVisitValueNode. Similarly, DoVisitValueNode\n// would be called before DoVisitTerminalNode or DoVisitCompositeNode. The\n// DoVisitNode is the most generic function and is called only if no more\n// specific function is present for a given node type.\n//\n// The *UintLiteralNode type implements both IntValueNode and FloatValueNode.\n// In this case, the DoVisitIntValueNode function is considered more specific\n// than DoVisitFloatValueNode, so will be preferred if present.\n//\n// Similarly, *MapFieldNode and *GroupNode implement both FieldDeclNode and\n// MessageDeclNode. In this case, the DoVisitFieldDeclNode function is\n// treated as more specific than DoVisitMessageDeclNode, so will be preferred\n// if both are present.\ntype SimpleVisitor struct {\n\tDoVisitFileNode                  func(*FileNode) error\n\tDoVisitSyntaxNode                func(*SyntaxNode) error\n\tDoVisitEditionNode               func(*EditionNode) error\n\tDoVisitPackageNode               func(*PackageNode) error\n\tDoVisitImportNode                func(*ImportNode) error\n\tDoVisitOptionNode                func(*OptionNode) error\n\tDoVisitOptionNameNode            func(*OptionNameNode) error\n\tDoVisitFieldReferenceNode        func(*FieldReferenceNode) error\n\tDoVisitCompactOptionsNode        func(*CompactOptionsNode) error\n\tDoVisitMessageNode               func(*MessageNode) error\n\tDoVisitExtendNode                func(*ExtendNode) error\n\tDoVisitExtensionRangeNode        func(*ExtensionRangeNode) error\n\tDoVisitReservedNode              func(*ReservedNode) error\n\tDoVisitRangeNode                 func(*RangeNode) error\n\tDoVisitFieldNode                 func(*FieldNode) error\n\tDoVisitGroupNode                 func(*GroupNode) error\n\tDoVisitMapFieldNode              func(*MapFieldNode) error\n\tDoVisitMapTypeNode               func(*MapTypeNode) error\n\tDoVisitOneofNode                 func(*OneofNode) error\n\tDoVisitEnumNode                  func(*EnumNode) error\n\tDoVisitEnumValueNode             func(*EnumValueNode) error\n\tDoVisitServiceNode               func(*ServiceNode) error\n\tDoVisitRPCNode                   func(*RPCNode) error\n\tDoVisitRPCTypeNode               func(*RPCTypeNode) error\n\tDoVisitIdentNode                 func(*IdentNode) error\n\tDoVisitCompoundIdentNode         func(*CompoundIdentNode) error\n\tDoVisitStringLiteralNode         func(*StringLiteralNode) error\n\tDoVisitCompoundStringLiteralNode func(*CompoundStringLiteralNode) error\n\tDoVisitUintLiteralNode           func(*UintLiteralNode) error\n\tDoVisitNegativeIntLiteralNode    func(*NegativeIntLiteralNode) error\n\tDoVisitFloatLiteralNode          func(*FloatLiteralNode) error\n\tDoVisitSpecialFloatLiteralNode   func(*SpecialFloatLiteralNode) error\n\tDoVisitSignedFloatLiteralNode    func(*SignedFloatLiteralNode) error\n\tDoVisitArrayLiteralNode          func(*ArrayLiteralNode) error\n\tDoVisitMessageLiteralNode        func(*MessageLiteralNode) error\n\tDoVisitMessageFieldNode          func(*MessageFieldNode) error\n\tDoVisitKeywordNode               func(*KeywordNode) error\n\tDoVisitRuneNode                  func(*RuneNode) error\n\tDoVisitEmptyDeclNode             func(*EmptyDeclNode) error\n\n\tDoVisitFieldDeclNode   func(FieldDeclNode) error\n\tDoVisitMessageDeclNode func(MessageDeclNode) error\n\n\tDoVisitIdentValueNode  func(IdentValueNode) error\n\tDoVisitStringValueNode func(StringValueNode) error\n\tDoVisitIntValueNode    func(IntValueNode) error\n\tDoVisitFloatValueNode  func(FloatValueNode) error\n\tDoVisitValueNode       func(ValueNode) error\n\n\tDoVisitTerminalNode  func(TerminalNode) error\n\tDoVisitCompositeNode func(CompositeNode) error\n\tDoVisitNode          func(Node) error\n}\n\nvar _ Visitor = (*SimpleVisitor)(nil)\n\nfunc (v *SimpleVisitor) isVisitor() {}\n\nfunc (v *SimpleVisitor) visitInterface(node Node) error {\n\tswitch n := node.(type) {\n\tcase FieldDeclNode:\n\t\tif v.DoVisitFieldDeclNode != nil {\n\t\t\treturn v.DoVisitFieldDeclNode(n)\n\t\t}\n\t\t// *MapFieldNode and *GroupNode both implement both FieldDeclNode and\n\t\t// MessageDeclNode, so handle other case here\n\t\tif fn, ok := n.(MessageDeclNode); ok && v.DoVisitMessageDeclNode != nil {\n\t\t\treturn v.DoVisitMessageDeclNode(fn)\n\t\t}\n\tcase MessageDeclNode:\n\t\tif v.DoVisitMessageDeclNode != nil {\n\t\t\treturn v.DoVisitMessageDeclNode(n)\n\t\t}\n\tcase IdentValueNode:\n\t\tif v.DoVisitIdentValueNode != nil {\n\t\t\treturn v.DoVisitIdentValueNode(n)\n\t\t}\n\tcase StringValueNode:\n\t\tif v.DoVisitStringValueNode != nil {\n\t\t\treturn v.DoVisitStringValueNode(n)\n\t\t}\n\tcase IntValueNode:\n\t\tif v.DoVisitIntValueNode != nil {\n\t\t\treturn v.DoVisitIntValueNode(n)\n\t\t}\n\t\t// *UintLiteralNode implements both IntValueNode and FloatValueNode,\n\t\t// so handle other case here\n\t\tif fn, ok := n.(FloatValueNode); ok && v.DoVisitFloatValueNode != nil {\n\t\t\treturn v.DoVisitFloatValueNode(fn)\n\t\t}\n\tcase FloatValueNode:\n\t\tif v.DoVisitFloatValueNode != nil {\n\t\t\treturn v.DoVisitFloatValueNode(n)\n\t\t}\n\t}\n\n\tif n, ok := node.(ValueNode); ok && v.DoVisitValueNode != nil {\n\t\treturn v.DoVisitValueNode(n)\n\t}\n\n\tswitch n := node.(type) {\n\tcase TerminalNode:\n\t\tif v.DoVisitTerminalNode != nil {\n\t\t\treturn v.DoVisitTerminalNode(n)\n\t\t}\n\tcase CompositeNode:\n\t\tif v.DoVisitCompositeNode != nil {\n\t\t\treturn v.DoVisitCompositeNode(n)\n\t\t}\n\t}\n\n\tif v.DoVisitNode != nil {\n\t\treturn v.DoVisitNode(node)\n\t}\n\n\treturn nil\n}\n\nfunc (v *SimpleVisitor) VisitFileNode(node *FileNode) error {\n\tif v.DoVisitFileNode != nil {\n\t\treturn v.DoVisitFileNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitSyntaxNode(node *SyntaxNode) error {\n\tif v.DoVisitSyntaxNode != nil {\n\t\treturn v.DoVisitSyntaxNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitEditionNode(node *EditionNode) error {\n\tif v.DoVisitEditionNode != nil {\n\t\treturn v.DoVisitEditionNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitPackageNode(node *PackageNode) error {\n\tif v.DoVisitPackageNode != nil {\n\t\treturn v.DoVisitPackageNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitImportNode(node *ImportNode) error {\n\tif v.DoVisitImportNode != nil {\n\t\treturn v.DoVisitImportNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitOptionNode(node *OptionNode) error {\n\tif v.DoVisitOptionNode != nil {\n\t\treturn v.DoVisitOptionNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitOptionNameNode(node *OptionNameNode) error {\n\tif v.DoVisitOptionNameNode != nil {\n\t\treturn v.DoVisitOptionNameNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitFieldReferenceNode(node *FieldReferenceNode) error {\n\tif v.DoVisitFieldReferenceNode != nil {\n\t\treturn v.DoVisitFieldReferenceNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitCompactOptionsNode(node *CompactOptionsNode) error {\n\tif v.DoVisitCompactOptionsNode != nil {\n\t\treturn v.DoVisitCompactOptionsNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitMessageNode(node *MessageNode) error {\n\tif v.DoVisitMessageNode != nil {\n\t\treturn v.DoVisitMessageNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitExtendNode(node *ExtendNode) error {\n\tif v.DoVisitExtendNode != nil {\n\t\treturn v.DoVisitExtendNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitExtensionRangeNode(node *ExtensionRangeNode) error {\n\tif v.DoVisitExtensionRangeNode != nil {\n\t\treturn v.DoVisitExtensionRangeNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitReservedNode(node *ReservedNode) error {\n\tif v.DoVisitReservedNode != nil {\n\t\treturn v.DoVisitReservedNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitRangeNode(node *RangeNode) error {\n\tif v.DoVisitRangeNode != nil {\n\t\treturn v.DoVisitRangeNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitFieldNode(node *FieldNode) error {\n\tif v.DoVisitFieldNode != nil {\n\t\treturn v.DoVisitFieldNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitGroupNode(node *GroupNode) error {\n\tif v.DoVisitGroupNode != nil {\n\t\treturn v.DoVisitGroupNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitMapFieldNode(node *MapFieldNode) error {\n\tif v.DoVisitMapFieldNode != nil {\n\t\treturn v.DoVisitMapFieldNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitMapTypeNode(node *MapTypeNode) error {\n\tif v.DoVisitMapTypeNode != nil {\n\t\treturn v.DoVisitMapTypeNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitOneofNode(node *OneofNode) error {\n\tif v.DoVisitOneofNode != nil {\n\t\treturn v.DoVisitOneofNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitEnumNode(node *EnumNode) error {\n\tif v.DoVisitEnumNode != nil {\n\t\treturn v.DoVisitEnumNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitEnumValueNode(node *EnumValueNode) error {\n\tif v.DoVisitEnumValueNode != nil {\n\t\treturn v.DoVisitEnumValueNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitServiceNode(node *ServiceNode) error {\n\tif v.DoVisitServiceNode != nil {\n\t\treturn v.DoVisitServiceNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitRPCNode(node *RPCNode) error {\n\tif v.DoVisitRPCNode != nil {\n\t\treturn v.DoVisitRPCNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitRPCTypeNode(node *RPCTypeNode) error {\n\tif v.DoVisitRPCTypeNode != nil {\n\t\treturn v.DoVisitRPCTypeNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitIdentNode(node *IdentNode) error {\n\tif v.DoVisitIdentNode != nil {\n\t\treturn v.DoVisitIdentNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitCompoundIdentNode(node *CompoundIdentNode) error {\n\tif v.DoVisitCompoundIdentNode != nil {\n\t\treturn v.DoVisitCompoundIdentNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitStringLiteralNode(node *StringLiteralNode) error {\n\tif v.DoVisitStringLiteralNode != nil {\n\t\treturn v.DoVisitStringLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitCompoundStringLiteralNode(node *CompoundStringLiteralNode) error {\n\tif v.DoVisitCompoundStringLiteralNode != nil {\n\t\treturn v.DoVisitCompoundStringLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitUintLiteralNode(node *UintLiteralNode) error {\n\tif v.DoVisitUintLiteralNode != nil {\n\t\treturn v.DoVisitUintLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitNegativeIntLiteralNode(node *NegativeIntLiteralNode) error {\n\tif v.DoVisitNegativeIntLiteralNode != nil {\n\t\treturn v.DoVisitNegativeIntLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitFloatLiteralNode(node *FloatLiteralNode) error {\n\tif v.DoVisitFloatLiteralNode != nil {\n\t\treturn v.DoVisitFloatLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitSpecialFloatLiteralNode(node *SpecialFloatLiteralNode) error {\n\tif v.DoVisitSpecialFloatLiteralNode != nil {\n\t\treturn v.DoVisitSpecialFloatLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitSignedFloatLiteralNode(node *SignedFloatLiteralNode) error {\n\tif v.DoVisitSignedFloatLiteralNode != nil {\n\t\treturn v.DoVisitSignedFloatLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitArrayLiteralNode(node *ArrayLiteralNode) error {\n\tif v.DoVisitArrayLiteralNode != nil {\n\t\treturn v.DoVisitArrayLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitMessageLiteralNode(node *MessageLiteralNode) error {\n\tif v.DoVisitMessageLiteralNode != nil {\n\t\treturn v.DoVisitMessageLiteralNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitMessageFieldNode(node *MessageFieldNode) error {\n\tif v.DoVisitMessageFieldNode != nil {\n\t\treturn v.DoVisitMessageFieldNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitKeywordNode(node *KeywordNode) error {\n\tif v.DoVisitKeywordNode != nil {\n\t\treturn v.DoVisitKeywordNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitRuneNode(node *RuneNode) error {\n\tif v.DoVisitRuneNode != nil {\n\t\treturn v.DoVisitRuneNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n\nfunc (v *SimpleVisitor) VisitEmptyDeclNode(node *EmptyDeclNode) error {\n\tif v.DoVisitEmptyDeclNode != nil {\n\t\treturn v.DoVisitEmptyDeclNode(node)\n\t}\n\treturn v.visitInterface(node)\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/compiler.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage protocompile\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"golang.org/x/sync/semaphore\"\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/linker\"\n\t\"github.com/bufbuild/protocompile/options\"\n\t\"github.com/bufbuild/protocompile/parser\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n\t\"github.com/bufbuild/protocompile/sourceinfo\"\n)\n\n// Compiler handles compilation tasks, to turn protobuf source files, or other\n// intermediate representations, into fully linked descriptors.\n//\n// The compilation process involves five steps for each protobuf source file:\n//  1. Parsing the source into an AST (abstract syntax tree).\n//  2. Converting the AST into descriptor protos.\n//  3. Linking descriptor protos into fully linked descriptors.\n//  4. Interpreting options.\n//  5. Computing source code information.\n//\n// With fully linked descriptors, code generators and protoc plugins could be\n// invoked (though that step is not implemented by this package and not a\n// responsibility of this type).\ntype Compiler struct {\n\t// Resolves path/file names into source code or intermediate representations\n\t// for protobuf source files. This is how the compiler loads the files to\n\t// be compiled as well as all dependencies. This field is the only required\n\t// field.\n\tResolver Resolver\n\t// The maximum parallelism to use when compiling. If unspecified or set to\n\t// a non-positive value, then min(runtime.NumCPU(), runtime.GOMAXPROCS(-1))\n\t// will be used.\n\tMaxParallelism int\n\t// A custom error and warning reporter. If unspecified a default reporter\n\t// is used. A default reporter fails the compilation after encountering any\n\t// errors and ignores all warnings.\n\tReporter reporter.Reporter\n\n\t// If unspecified or set to SourceInfoNone, source code information will not\n\t// be included in the resulting descriptors. Source code information is\n\t// metadata in the file descriptor that provides position information (i.e.\n\t// the line and column where file elements were defined) as well as comments.\n\t//\n\t// If set to SourceInfoStandard, normal source code information will be\n\t// included in the resulting descriptors. This matches the output of protoc\n\t// (the reference compiler for Protocol Buffers). If set to\n\t// SourceInfoMoreComments, the resulting descriptor will attempt to preserve\n\t// as many comments as possible, for all elements in the file, not just for\n\t// complete declarations.\n\t//\n\t// If Resolver returns descriptors or descriptor protos for a file, then\n\t// those descriptors will not be modified. If they do not already include\n\t// source code info, they will be left that way when the compile operation\n\t// concludes. Similarly, if they already have source code info but this flag\n\t// is false, existing info will be left in place.\n\tSourceInfoMode SourceInfoMode\n\n\t// If true, ASTs are retained in compilation results for which an AST was\n\t// constructed. So any linker.Result value in the resulting compiled files\n\t// will have an AST, in addition to descriptors. If left false, the AST\n\t// will be removed as soon as it's no longer needed. This can help reduce\n\t// total memory usage for operations involving a large number of files.\n\tRetainASTs bool\n\n\t// If non-nil, the set of symbols already known. Any symbols in the current\n\t// compilation will be added to it. If the compilation tries to redefine any\n\t// of these symbols, it will be reported as a collision.\n\t//\n\t// This allows a large compilation to be split up into multiple, smaller\n\t// operations and still be able to identify naming collisions and extension\n\t// number collisions across all operations.\n\tSymbols *linker.Symbols\n}\n\n// SourceInfoMode indicates how source code info is generated by a Compiler.\ntype SourceInfoMode int\n\nconst (\n\t// SourceInfoNone indicates that no source code info is generated.\n\tSourceInfoNone = SourceInfoMode(0)\n\t// SourceInfoStandard indicates that the standard source code info is\n\t// generated, which includes comments only for complete declarations.\n\tSourceInfoStandard = SourceInfoMode(1)\n\t// SourceInfoExtraComments indicates that source code info is generated\n\t// and will include comments for all elements (more comments than would\n\t// be found in a descriptor produced by protoc).\n\tSourceInfoExtraComments = SourceInfoMode(2)\n\t// SourceInfoExtraOptionLocations indicates that source code info is\n\t// generated with additional locations for elements inside of message\n\t// literals in option values. This can be combined with the above by\n\t// bitwise-OR'ing it with SourceInfoExtraComments.\n\tSourceInfoExtraOptionLocations = SourceInfoMode(4)\n)\n\n// Compile compiles the given file names into fully-linked descriptors. The\n// compiler's resolver is used to locate source code (or intermediate artifacts\n// such as parsed ASTs or descriptor protos) and then do what is necessary to\n// transform that into descriptors (parsing, linking, etc).\n//\n// Elements in the given returned files will implement [linker.Result] if the\n// compiler had to link it (i.e. the resolver provided either a descriptor proto\n// or source code). That result will contain a full AST for the file if the\n// compiler had to parse it (i.e. the resolver provided source code for that\n// file).\nfunc (c *Compiler) Compile(ctx context.Context, files ...string) (linker.Files, error) {\n\tif len(files) == 0 {\n\t\treturn nil, nil\n\t}\n\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tpar := c.MaxParallelism\n\tif par <= 0 {\n\t\tpar = runtime.GOMAXPROCS(-1)\n\t\tcpus := runtime.NumCPU()\n\t\tif par > cpus {\n\t\t\tpar = cpus\n\t\t}\n\t}\n\n\th := reporter.NewHandler(c.Reporter)\n\n\tsym := c.Symbols\n\tif sym == nil {\n\t\tsym = &linker.Symbols{}\n\t}\n\te := executor{\n\t\tc:       c,\n\t\th:       h,\n\t\ts:       semaphore.NewWeighted(int64(par)),\n\t\tcancel:  cancel,\n\t\tsym:     sym,\n\t\tresults: map[string]*result{},\n\t}\n\n\t// We lock now and create all tasks under lock to make sure that no\n\t// async task can create a duplicate result. For example, if files\n\t// contains both \"foo.proto\" and \"bar.proto\", then there is a race\n\t// after we start compiling \"foo.proto\" between this loop and the\n\t// async compilation task to create the result for \"bar.proto\". But\n\t// we need to know if the file is directly requested for compilation,\n\t// so we need this loop to define the result. So this loop holds the\n\t// lock the whole time so async tasks can't create a result first.\n\tresults := make([]*result, len(files))\n\tfunc() {\n\t\te.mu.Lock()\n\t\tdefer e.mu.Unlock()\n\t\tfor i, f := range files {\n\t\t\tresults[i] = e.compileLocked(ctx, f, true)\n\t\t}\n\t}()\n\n\tdescs := make([]linker.File, len(files))\n\tvar firstError error\n\tfor i, r := range results {\n\t\tselect {\n\t\tcase <-r.ready:\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ctx.Err()\n\t\t}\n\t\tif r.err != nil {\n\t\t\tif firstError == nil {\n\t\t\t\tfirstError = r.err\n\t\t\t}\n\t\t}\n\t\tdescs[i] = r.res\n\t}\n\n\tif err := h.Error(); err != nil {\n\t\treturn descs, err\n\t}\n\t// this should probably never happen; if any task returned an\n\t// error, h.Error() should be non-nil\n\treturn descs, firstError\n}\n\ntype result struct {\n\tname  string\n\tready chan struct{}\n\n\t// true if this file was explicitly provided to the compiler; otherwise\n\t// this file is an import that is implicitly included\n\texplicitFile bool\n\n\t// produces a linker.File or error, only available when ready is closed\n\tres linker.File\n\terr error\n\n\tmu sync.Mutex\n\t// the results that are dependencies of this result; this result is\n\t// blocked, waiting on these dependencies to complete\n\tblockedOn []string\n}\n\nfunc (r *result) fail(err error) {\n\tr.err = err\n\tclose(r.ready)\n}\n\nfunc (r *result) complete(f linker.File) {\n\tr.res = f\n\tclose(r.ready)\n}\n\nfunc (r *result) setBlockedOn(deps []string) {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\tr.blockedOn = deps\n}\n\nfunc (r *result) getBlockedOn() []string {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\treturn r.blockedOn\n}\n\ntype executor struct {\n\tc      *Compiler\n\th      *reporter.Handler\n\ts      *semaphore.Weighted\n\tcancel context.CancelFunc\n\tsym    *linker.Symbols\n\n\tdescriptorProtoCheck    sync.Once\n\tdescriptorProtoIsCustom bool\n\n\tmu      sync.Mutex\n\tresults map[string]*result\n}\n\nfunc (e *executor) compile(ctx context.Context, file string) *result {\n\te.mu.Lock()\n\tdefer e.mu.Unlock()\n\n\treturn e.compileLocked(ctx, file, false)\n}\n\nfunc (e *executor) compileLocked(ctx context.Context, file string, explicitFile bool) *result {\n\tr := e.results[file]\n\tif r != nil {\n\t\treturn r\n\t}\n\n\tr = &result{\n\t\tname:         file,\n\t\tready:        make(chan struct{}),\n\t\texplicitFile: explicitFile,\n\t}\n\te.results[file] = r\n\tgo func() {\n\t\tdefer func() {\n\t\t\tif p := recover(); p != nil {\n\t\t\t\tif r.err == nil {\n\t\t\t\t\t// TODO: strip top frames from stack trace so that the panic is\n\t\t\t\t\t//  the top of the trace?\n\t\t\t\t\tpanicErr := PanicError{File: file, Value: p, Stack: string(debug.Stack())}\n\t\t\t\t\tr.fail(panicErr)\n\t\t\t\t}\n\t\t\t\t// TODO: if r.err != nil, then this task has already\n\t\t\t\t//  failed and there's nothing we can really do to\n\t\t\t\t//  communicate this panic to parent goroutine. This\n\t\t\t\t//  means the panic must have happened *after* the\n\t\t\t\t//  failure was already recorded (or during?)\n\t\t\t\t//  It would be nice to do something else here, like\n\t\t\t\t//  send the compiler an out-of-band error? Or log?\n\t\t\t}\n\t\t}()\n\t\te.doCompile(ctx, file, r)\n\t}()\n\treturn r\n}\n\n// PanicError is an error value that represents a recovered panic. It includes\n// the value returned by recover() as well as the stack trace.\n//\n// This should generally only be seen if a Resolver implementation panics.\n//\n// An error returned by a Compiler may wrap a PanicError, so you may need to\n// use errors.As(...) to access panic details.\ntype PanicError struct {\n\t// The file that was being processed when the panic occurred\n\tFile string\n\t// The value returned by recover()\n\tValue interface{}\n\t// A formatted stack trace\n\tStack string\n}\n\n// Error implements the error interface. It does NOT include the stack trace.\n// Use a type assertion and query the Stack field directly to access that.\nfunc (p PanicError) Error() string {\n\treturn fmt.Sprintf(\"panic handling %q: %v\", p.File, p.Value)\n}\n\ntype errFailedToResolve struct {\n\terr  error\n\tpath string\n}\n\nfunc (e errFailedToResolve) Error() string {\n\terrMsg := e.err.Error()\n\tif strings.Contains(errMsg, e.path) {\n\t\t// underlying error already refers to path in question, so we don't need to add more context\n\t\treturn errMsg\n\t}\n\treturn fmt.Sprintf(\"could not resolve path %q: %s\", e.path, e.err.Error())\n}\n\nfunc (e errFailedToResolve) Unwrap() error {\n\treturn e.err\n}\n\nfunc (e *executor) hasOverrideDescriptorProto() bool {\n\te.descriptorProtoCheck.Do(func() {\n\t\tdefer func() {\n\t\t\t// ignore a panic here; just assume no custom descriptor.proto\n\t\t\t_ = recover()\n\t\t}()\n\t\tres, err := e.c.Resolver.FindFileByPath(descriptorProtoPath)\n\t\te.descriptorProtoIsCustom = err == nil && res.Desc != standardImports[descriptorProtoPath]\n\t})\n\treturn e.descriptorProtoIsCustom\n}\n\nfunc (e *executor) doCompile(ctx context.Context, file string, r *result) {\n\tt := task{e: e, h: e.h.SubHandler(), r: r}\n\tif err := e.s.Acquire(ctx, 1); err != nil {\n\t\tr.fail(err)\n\t\treturn\n\t}\n\tdefer t.release()\n\n\tsr, err := e.c.Resolver.FindFileByPath(file)\n\tif err != nil {\n\t\tr.fail(errFailedToResolve{err: err, path: file})\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\t// if results included a result, don't leave it open if it can be closed\n\t\tif sr.Source == nil {\n\t\t\treturn\n\t\t}\n\t\tif c, ok := sr.Source.(io.Closer); ok {\n\t\t\t_ = c.Close()\n\t\t}\n\t}()\n\n\tdesc, err := t.asFile(ctx, file, sr)\n\tif err != nil {\n\t\tr.fail(err)\n\t\treturn\n\t}\n\tr.complete(desc)\n}\n\n// A compilation task. The executor has a semaphore that limits the number\n// of concurrent, running tasks.\ntype task struct {\n\te *executor\n\n\t// handler for this task\n\th *reporter.Handler\n\n\t// If true, this task needs to acquire a semaphore permit before running.\n\t// If false, this task needs to release its semaphore permit on completion.\n\treleased bool\n\n\t// the result that is populated by this task\n\tr *result\n}\n\nfunc (t *task) release() {\n\tif !t.released {\n\t\tt.e.s.Release(1)\n\t\tt.released = true\n\t}\n}\n\nconst descriptorProtoPath = \"google/protobuf/descriptor.proto\"\n\nfunc (t *task) asFile(ctx context.Context, name string, r SearchResult) (linker.File, error) {\n\tif r.Desc != nil {\n\t\tif r.Desc.Path() != name {\n\t\t\treturn nil, fmt.Errorf(\"search result for %q returned descriptor for %q\", name, r.Desc.Path())\n\t\t}\n\t\treturn linker.NewFileRecursive(r.Desc)\n\t}\n\n\tparseRes, err := t.asParseResult(name, r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif linkRes, ok := parseRes.(linker.Result); ok {\n\t\t// if resolver returned a parse result that was actually a link result,\n\t\t// use the link result directly (no other steps needed)\n\t\treturn linkRes, nil\n\t}\n\n\tvar deps []linker.File\n\tfileDescriptorProto := parseRes.FileDescriptorProto()\n\tvar wantsDescriptorProto bool\n\timports := fileDescriptorProto.Dependency\n\n\tif t.e.hasOverrideDescriptorProto() {\n\t\t// we only consider implicitly including descriptor.proto if it's overridden\n\t\tif name != descriptorProtoPath {\n\t\t\tvar includesDescriptorProto bool\n\t\t\tfor _, dep := range fileDescriptorProto.Dependency {\n\t\t\t\tif dep == descriptorProtoPath {\n\t\t\t\t\tincludesDescriptorProto = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !includesDescriptorProto {\n\t\t\t\twantsDescriptorProto = true\n\t\t\t\t// make a defensive copy so we don't inadvertently mutate\n\t\t\t\t// slice's backing array when adding this implicit dep\n\t\t\t\timportsCopy := make([]string, len(imports)+1)\n\t\t\t\tcopy(importsCopy, imports)\n\t\t\t\timportsCopy[len(imports)] = descriptorProtoPath\n\t\t\t\timports = importsCopy\n\t\t\t}\n\t\t}\n\t}\n\n\tvar overrideDescriptorProto linker.File\n\tif len(imports) > 0 {\n\t\tt.r.setBlockedOn(imports)\n\n\t\tresults := make([]*result, len(fileDescriptorProto.Dependency))\n\t\tchecked := map[string]struct{}{}\n\t\tfor i, dep := range fileDescriptorProto.Dependency {\n\t\t\tspan := findImportSpan(parseRes, dep)\n\t\t\tif name == dep {\n\t\t\t\t// doh! file imports itself\n\t\t\t\thandleImportCycle(t.h, span, []string{name}, dep)\n\t\t\t\treturn nil, t.h.Error()\n\t\t\t}\n\n\t\t\tres := t.e.compile(ctx, dep)\n\t\t\t// check for dependency cycle to prevent deadlock\n\t\t\tif err := t.e.checkForDependencyCycle(res, []string{name, dep}, span, checked); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tresults[i] = res\n\t\t}\n\t\tdeps = make([]linker.File, len(results))\n\t\tvar descriptorProtoRes *result\n\t\tif wantsDescriptorProto {\n\t\t\tdescriptorProtoRes = t.e.compile(ctx, descriptorProtoPath)\n\t\t}\n\n\t\t// release our semaphore so dependencies can be processed w/out risk of deadlock\n\t\tt.e.s.Release(1)\n\t\tt.released = true\n\n\t\t// now we wait for them all to be computed\n\t\tfor i, res := range results {\n\t\t\tselect {\n\t\t\tcase <-res.ready:\n\t\t\t\tif res.err != nil {\n\t\t\t\t\tif rerr, ok := res.err.(errFailedToResolve); ok {\n\t\t\t\t\t\t// We don't report errors to get file from resolver to handler since\n\t\t\t\t\t\t// it's usually considered immediately fatal. However, if the reason\n\t\t\t\t\t\t// we were resolving is due to an import, turn this into an error with\n\t\t\t\t\t\t// source position that pinpoints the import statement and report it.\n\t\t\t\t\t\treturn nil, reporter.Error(findImportSpan(parseRes, res.name), rerr)\n\t\t\t\t\t}\n\t\t\t\t\treturn nil, res.err\n\t\t\t\t}\n\t\t\t\tdeps[i] = res.res\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil, ctx.Err()\n\t\t\t}\n\t\t}\n\t\tif descriptorProtoRes != nil {\n\t\t\tselect {\n\t\t\tcase <-descriptorProtoRes.ready:\n\t\t\t\t// descriptor.proto wasn't explicitly imported, so we can ignore a failure\n\t\t\t\tif descriptorProtoRes.err == nil {\n\t\t\t\t\toverrideDescriptorProto = descriptorProtoRes.res\n\t\t\t\t}\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn nil, ctx.Err()\n\t\t\t}\n\t\t}\n\t\t// all deps resolved\n\t\tt.r.setBlockedOn(nil)\n\t\t// reacquire semaphore so we can proceed\n\t\tif err := t.e.s.Acquire(ctx, 1); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tt.released = false\n\t}\n\n\treturn t.link(parseRes, deps, overrideDescriptorProto)\n}\n\nfunc (e *executor) checkForDependencyCycle(res *result, sequence []string, span ast.SourceSpan, checked map[string]struct{}) error {\n\tif _, ok := checked[res.name]; ok {\n\t\t// already checked this one\n\t\treturn nil\n\t}\n\tchecked[res.name] = struct{}{}\n\tdeps := res.getBlockedOn()\n\tfor _, dep := range deps {\n\t\t// is this a cycle?\n\t\tfor _, file := range sequence {\n\t\t\tif file == dep {\n\t\t\t\thandleImportCycle(e.h, span, sequence, dep)\n\t\t\t\treturn e.h.Error()\n\t\t\t}\n\t\t}\n\n\t\te.mu.Lock()\n\t\tdepRes := e.results[dep]\n\t\te.mu.Unlock()\n\t\tif depRes == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif err := e.checkForDependencyCycle(depRes, append(sequence, dep), span, checked); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc handleImportCycle(h *reporter.Handler, span ast.SourceSpan, importSequence []string, dep string) {\n\tvar buf bytes.Buffer\n\tbuf.WriteString(\"cycle found in imports: \")\n\tfor _, imp := range importSequence {\n\t\t_, _ = fmt.Fprintf(&buf, \"%q -> \", imp)\n\t}\n\t_, _ = fmt.Fprintf(&buf, \"%q\", dep)\n\t// error is saved and returned in caller\n\t_ = h.HandleErrorWithPos(span, errors.New(buf.String()))\n}\n\nfunc findImportSpan(res parser.Result, dep string) ast.SourceSpan {\n\troot := res.AST()\n\tif root == nil {\n\t\treturn ast.UnknownSpan(res.FileNode().Name())\n\t}\n\tfor _, decl := range root.Decls {\n\t\tif imp, ok := decl.(*ast.ImportNode); ok {\n\t\t\tif imp.Name.AsString() == dep {\n\t\t\t\treturn root.NodeInfo(imp.Name)\n\t\t\t}\n\t\t}\n\t}\n\t// this should never happen...\n\treturn ast.UnknownSpan(res.FileNode().Name())\n}\n\nfunc (t *task) link(parseRes parser.Result, deps linker.Files, overrideDescriptorProtoRes linker.File) (linker.File, error) {\n\tfile, err := linker.Link(parseRes, deps, t.e.sym, t.h)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar interpretOpts []options.InterpreterOption\n\tif overrideDescriptorProtoRes != nil {\n\t\tinterpretOpts = []options.InterpreterOption{options.WithOverrideDescriptorProto(overrideDescriptorProtoRes)}\n\t}\n\n\toptsIndex, err := options.InterpretOptions(file, t.h, interpretOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// now that options are interpreted, we can do some additional checks\n\tif err := file.ValidateOptions(t.h, t.e.sym); err != nil {\n\t\treturn nil, err\n\t}\n\tif t.r.explicitFile {\n\t\tfile.CheckForUnusedImports(t.h)\n\t}\n\tif err := t.h.Error(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif needsSourceInfo(parseRes, t.e.c.SourceInfoMode) {\n\t\tvar srcInfoOpts []sourceinfo.GenerateOption\n\t\tif t.e.c.SourceInfoMode&SourceInfoExtraComments != 0 {\n\t\t\tsrcInfoOpts = append(srcInfoOpts, sourceinfo.WithExtraComments())\n\t\t}\n\t\tif t.e.c.SourceInfoMode&SourceInfoExtraOptionLocations != 0 {\n\t\t\tsrcInfoOpts = append(srcInfoOpts, sourceinfo.WithExtraOptionLocations())\n\t\t}\n\t\tparseRes.FileDescriptorProto().SourceCodeInfo = sourceinfo.GenerateSourceInfo(parseRes.AST(), optsIndex, srcInfoOpts...)\n\t} else if t.e.c.SourceInfoMode == SourceInfoNone {\n\t\t// If results came from unlinked FileDescriptorProto, it could have\n\t\t// source info that we should strip.\n\t\tparseRes.FileDescriptorProto().SourceCodeInfo = nil\n\t}\n\tif len(parseRes.FileDescriptorProto().GetSourceCodeInfo().GetLocation()) > 0 {\n\t\t// If we have source code info in the descriptor proto at this point,\n\t\t// we have to build the index of locations.\n\t\tfile.PopulateSourceCodeInfo()\n\t}\n\n\tif !t.e.c.RetainASTs {\n\t\tfile.RemoveAST()\n\t}\n\treturn file, nil\n}\n\nfunc needsSourceInfo(parseRes parser.Result, mode SourceInfoMode) bool {\n\treturn mode != SourceInfoNone && parseRes.AST() != nil && parseRes.FileDescriptorProto().SourceCodeInfo == nil\n}\n\nfunc (t *task) asParseResult(name string, r SearchResult) (parser.Result, error) {\n\tif r.ParseResult != nil {\n\t\tif r.ParseResult.FileDescriptorProto().GetName() != name {\n\t\t\treturn nil, fmt.Errorf(\"search result for %q returned descriptor for %q\", name, r.ParseResult.FileDescriptorProto().GetName())\n\t\t}\n\t\t// If the file descriptor needs linking, it will be mutated during the\n\t\t// next stage. So to make anu mutations thread-safe, we must make a\n\t\t// defensive copy.\n\t\tres := parser.Clone(r.ParseResult)\n\t\treturn res, nil\n\t}\n\n\tif r.Proto != nil {\n\t\tif r.Proto.GetName() != name {\n\t\t\treturn nil, fmt.Errorf(\"search result for %q returned descriptor for %q\", name, r.Proto.GetName())\n\t\t}\n\t\t// If the file descriptor needs linking, it will be mutated during the\n\t\t// next stage. So to make any mutations thread-safe, we must make a\n\t\t// defensive copy.\n\t\tdescProto := proto.Clone(r.Proto).(*descriptorpb.FileDescriptorProto) //nolint:errcheck\n\t\treturn parser.ResultWithoutAST(descProto), nil\n\t}\n\n\tfile, err := t.asAST(name, r)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn parser.ResultFromAST(file, true, t.h)\n}\n\nfunc (t *task) asAST(name string, r SearchResult) (*ast.FileNode, error) {\n\tif r.AST != nil {\n\t\tif r.AST.Name() != name {\n\t\t\treturn nil, fmt.Errorf(\"search result for %q returned descriptor for %q\", name, r.AST.Name())\n\t\t}\n\t\treturn r.AST, nil\n\t}\n\n\treturn parser.Parse(name, r.Source, t.h)\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/doc.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package protocompile provides the entry point for a high performance\n// native Go protobuf compiler. \"Compile\" in this case just means parsing\n// and validating source and generating fully-linked descriptors in the end.\n// Unlike the protoc command-line tool, this package does not try to use the\n// descriptors to perform code generation.\n//\n// The various sub-packages represent the various compile phases and contain\n// models for the intermediate results. Those phases follow:\n//  1. Parse into AST.\n//     Also see: parser.Parse\n//  2. Convert AST to unlinked descriptor protos.\n//     Also see: parser.ResultFromAST\n//  3. Link descriptor protos into \"rich\" descriptors.\n//     Also see: linker.Link\n//  4. Interpret custom options.\n//     Also see: options.InterpretOptions\n//  5. Generate source code info.\n//     Also see: sourceinfo.GenerateSourceInfo\n//\n// This package provides an easy-to-use interface that does all the relevant\n// phases, based on the inputs given. If an input is provided as source, all\n// phases apply. If an input is provided as a descriptor proto, only phases\n// 3 to 5 apply. Nothing is necessary if provided a linked descriptor (which\n// is usually only the case for select system dependencies).\n//\n// This package is also capable of taking advantage of multiple CPU cores, so\n// a compilation involving thousands of files can be done very quickly by\n// compiling things in parallel.\n//\n// # Resolvers\n//\n// A Resolver is how the compiler locates artifacts that are inputs to the\n// compilation. For example, it can load protobuf source code that must be\n// processed. A Resolver could also supply some already-compiled dependencies\n// as fully-linked descriptors, alleviating the need to re-compile them.\n//\n// A Resolver can provide any of the following in response to a query for an\n// input.\n//   - Source code: If a resolver answers a query with protobuf source, the\n//     compiler will parse and compile it.\n//   - AST: If a resolver answers a query with an AST, the parsing step can be\n//     skipped, and the rest of the compilation steps will be applied.\n//   - Descriptor proto: If a resolver answers a query with an unlinked proto,\n//     only the other compilation steps, including linking, need to be applied.\n//   - Descriptor: If a resolver answers a query with a fully-linked descriptor,\n//     nothing further needs to be done. The descriptor is used as-is.\n//\n// Compilation will use the Resolver to load the files that are to be compiled\n// and also to load all dependencies (i.e. other files imported by those being\n// compiled).\n//\n// # Compiler\n//\n// A Compiler accepts a list of file names and produces the list of descriptors.\n// A Compiler has several fields that control how it works but only the Resolver\n// field is required. A minimal Compiler, that resolves files by loading them\n// from the file system based on the current working directory, can be had with\n// the following simple snippet:\n//\n//\tcompiler := protocompile.Compiler{\n//\t    Resolver: &protocompile.SourceResolver{},\n//\t}\n//\n// This minimal Compiler will use default parallelism, equal to the number of\n// CPU cores detected; it will not generate source code info in the resulting\n// descriptors; and it will fail fast at the first sign of any error. All of\n// these aspects can be customized by setting other fields.\npackage protocompile\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/go.work",
    "content": "go 1.21\n\nuse (\n\t.\n\t./internal/benchmarks\n)\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/go.work.sum",
    "content": "cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=\ncloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=\ncloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=\ncloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=\ncloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=\ncloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=\ncloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=\ncloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=\ncloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=\ncloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=\ncloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=\ncloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=\ncloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=\ncloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=\ngithub.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/bufbuild/protocompile v0.2.1-0.20230123224550-da57cd758c2f/go.mod h1:tleDrpPTlLUVmgnEoN6qBliKWqJaZFJXqZdFjTd+ocU=\ngithub.com/bufbuild/protocompile v0.13.0/go.mod h1:dr++fGGeMPWHv7jPeT06ZKukm45NJscd7rUxQVzEKRk=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=\ngithub.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=\ngithub.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=\ngithub.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=\ngithub.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=\ngithub.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=\ngithub.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=\ngithub.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=\ngithub.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=\ngithub.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=\ngithub.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=\ngithub.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=\ngithub.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg=\ngithub.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo=\ngithub.com/jhump/protoreflect v1.15.0 h1:U5T5/2LF0AZQFP9T4W5GfBjBaTruomrKobiR4E+oA/Q=\ngithub.com/jhump/protoreflect v1.15.0/go.mod h1:qww51KYjD2hoCl/ohxw5cK2LSssFczrbO1t8Ld2TENs=\ngithub.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=\ngolang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=\ngolang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=\ngolang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=\ngolang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3 h1:XQyxROzUlZH+WIQwySDgnISgOivlhjIEwaQaJEJrrN0=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 h1:LQmS1nU0twXLA96Kt7U9qtHJEbBk3z6Q0V4UXjZkpr4=\ngolang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=\ngolang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=\ngolang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=\ngolang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=\ngolang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=\ngolang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=\ngolang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=\ngolang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=\ngolang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=\ngolang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 h1:0c3L82FDQ5rt1bjTBlchS8t6RQ6299/+5bWMnRLh+uI=\ngolang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=\ngoogle.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=\ngoogle.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=\ngoogle.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=\ngoogle.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=\ngoogle.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=\ngoogle.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=\ngoogle.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=\ngoogle.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=\ngoogle.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=\ngoogle.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=\ngoogle.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=\ngoogle.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=\ngoogle.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=\ngoogle.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=\ngoogle.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko=\ngoogle.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=\ngoogle.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=\ngoogle.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=\ngoogle.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=\ngoogle.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=\ngoogle.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=\ngoogle.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=\ngoogle.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=\ngoogle.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=\ngoogle.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=\ngoogle.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=\ngoogle.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=\ngoogle.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=\ngoogle.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=\ngoogle.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=\ngoogle.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngoogle.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=\ngoogle.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs=\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/editions/editions.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package editions contains helpers related to resolving features for\n// Protobuf editions. These are lower-level helpers. Higher-level helpers\n// (which use this package under the hood) can be found in the exported\n// protoutil package.\npackage editions\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"google.golang.org/protobuf/encoding/prototext\"\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n)\n\nconst (\n\t// MinSupportedEdition is the earliest edition supported by this module.\n\t// It should be 2023 (the first edition) for the indefinite future.\n\tMinSupportedEdition = descriptorpb.Edition_EDITION_2023\n\n\t// MaxSupportedEdition is the most recent edition supported by this module.\n\tMaxSupportedEdition = descriptorpb.Edition_EDITION_2023\n)\n\nvar (\n\t// SupportedEditions is the exhaustive set of editions that protocompile\n\t// can support. We don't allow it to compile future/unknown editions, to\n\t// make sure we don't generate incorrect descriptors, in the event that\n\t// a future edition introduces a change or new feature that requires\n\t// new logic in the compiler.\n\tSupportedEditions = computeSupportedEditions(MinSupportedEdition, MaxSupportedEdition)\n\n\t// FeatureSetDescriptor is the message descriptor for the compiled-in\n\t// version (in the descriptorpb package) of the google.protobuf.FeatureSet\n\t// message type.\n\tFeatureSetDescriptor = (*descriptorpb.FeatureSet)(nil).ProtoReflect().Descriptor()\n\t// FeatureSetType is the message type for the compiled-in version (in\n\t// the descriptorpb package) of google.protobuf.FeatureSet.\n\tFeatureSetType = (*descriptorpb.FeatureSet)(nil).ProtoReflect().Type()\n\n\teditionDefaults     map[descriptorpb.Edition]*descriptorpb.FeatureSet\n\teditionDefaultsInit sync.Once\n)\n\n// HasFeatures is implemented by all options messages and provides a\n// nil-receiver-safe way of accessing the features explicitly configured\n// in those options.\ntype HasFeatures interface {\n\tGetFeatures() *descriptorpb.FeatureSet\n}\n\nvar _ HasFeatures = (*descriptorpb.FileOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.MessageOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.FieldOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.OneofOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.ExtensionRangeOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.EnumOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.EnumValueOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.ServiceOptions)(nil)\nvar _ HasFeatures = (*descriptorpb.MethodOptions)(nil)\n\n// ResolveFeature resolves a feature for the given descriptor. This simple\n// helper examines the given element and its ancestors, searching for an\n// override. If there is no overridden value, it returns a zero value.\nfunc ResolveFeature(\n\telement protoreflect.Descriptor,\n\tfields ...protoreflect.FieldDescriptor,\n) (protoreflect.Value, error) {\n\tfor {\n\t\tvar features *descriptorpb.FeatureSet\n\t\tif withFeatures, ok := element.Options().(HasFeatures); ok {\n\t\t\t// It should not really be possible for 'ok' to ever be false...\n\t\t\tfeatures = withFeatures.GetFeatures()\n\t\t}\n\n\t\t// TODO: adaptFeatureSet is only looking at the first field. But if we needed to\n\t\t//       support an extension field inside a custom feature, we'd really need\n\t\t//       to check all fields. That gets particularly complicated if the traversal\n\t\t//       path of fields includes list and map values. Luckily, features are not\n\t\t//       supposed to be repeated and not supposed to themselves have extensions.\n\t\t//       So this should be fine, at least for now.\n\t\tmsgRef, err := adaptFeatureSet(features, fields[0])\n\t\tif err != nil {\n\t\t\treturn protoreflect.Value{}, err\n\t\t}\n\t\t// Navigate the fields to find the value\n\t\tvar val protoreflect.Value\n\t\tfor i, field := range fields {\n\t\t\tif i > 0 {\n\t\t\t\tmsgRef = val.Message()\n\t\t\t}\n\t\t\tif !msgRef.Has(field) {\n\t\t\t\tval = protoreflect.Value{}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tval = msgRef.Get(field)\n\t\t}\n\t\tif val.IsValid() {\n\t\t\t// All fields were set!\n\t\t\treturn val, nil\n\t\t}\n\n\t\tparent := element.Parent()\n\t\tif parent == nil {\n\t\t\t// We've reached the end of the inheritance chain.\n\t\t\treturn protoreflect.Value{}, nil\n\t\t}\n\t\telement = parent\n\t}\n}\n\n// HasEdition should be implemented by values that implement\n// [protoreflect.FileDescriptor], to provide access to the file's\n// edition when its syntax is [protoreflect.Editions].\ntype HasEdition interface {\n\t// Edition returns the numeric value of a google.protobuf.Edition enum\n\t// value that corresponds to the edition of this file. If the file does\n\t// not use editions, it should return the enum value that corresponds\n\t// to the syntax level, EDITION_PROTO2 or EDITION_PROTO3.\n\tEdition() int32\n}\n\n// GetEdition returns the edition for a given element. It returns\n// EDITION_PROTO2 or EDITION_PROTO3 if the element is in a file that\n// uses proto2 or proto3 syntax, respectively. It returns EDITION_UNKNOWN\n// if the syntax of the given element is not recognized or if the edition\n// cannot be ascertained from the element's [protoreflect.FileDescriptor].\nfunc GetEdition(d protoreflect.Descriptor) descriptorpb.Edition {\n\tswitch d.ParentFile().Syntax() {\n\tcase protoreflect.Proto2:\n\t\treturn descriptorpb.Edition_EDITION_PROTO2\n\tcase protoreflect.Proto3:\n\t\treturn descriptorpb.Edition_EDITION_PROTO3\n\tcase protoreflect.Editions:\n\t\twithEdition, ok := d.ParentFile().(HasEdition)\n\t\tif !ok {\n\t\t\t// The parent file should always be a *result, so we should\n\t\t\t// never be able to actually get in here. If we somehow did\n\t\t\t// have another implementation of protoreflect.FileDescriptor,\n\t\t\t// it doesn't provide a way to get the edition, other than the\n\t\t\t// potentially expensive step of generating a FileDescriptorProto\n\t\t\t// and then querying for the edition from that. :/\n\t\t\treturn descriptorpb.Edition_EDITION_UNKNOWN\n\t\t}\n\t\treturn descriptorpb.Edition(withEdition.Edition())\n\tdefault:\n\t\treturn descriptorpb.Edition_EDITION_UNKNOWN\n\t}\n}\n\n// GetEditionDefaults returns the default feature values for the given edition.\n// It returns nil if the given edition is not known.\n//\n// This only populates known features, those that are fields of [*descriptorpb.FeatureSet].\n// It does not populate any extension fields.\n//\n// The returned value must not be mutated as it references shared package state.\nfunc GetEditionDefaults(edition descriptorpb.Edition) *descriptorpb.FeatureSet {\n\teditionDefaultsInit.Do(func() {\n\t\teditionDefaults = make(map[descriptorpb.Edition]*descriptorpb.FeatureSet, len(descriptorpb.Edition_name))\n\t\t// Compute default for all known editions in descriptorpb.\n\t\tfor editionInt := range descriptorpb.Edition_name {\n\t\t\tedition := descriptorpb.Edition(editionInt)\n\t\t\tdefaults := &descriptorpb.FeatureSet{}\n\t\t\tdefaultsRef := defaults.ProtoReflect()\n\t\t\tfields := defaultsRef.Descriptor().Fields()\n\t\t\t// Note: we are not computing defaults for extensions. Those are not needed\n\t\t\t// by anything in the compiler, so we can get away with just computing\n\t\t\t// defaults for these static, non-extension fields.\n\t\t\tfor i, length := 0, fields.Len(); i < length; i++ {\n\t\t\t\tfield := fields.Get(i)\n\t\t\t\tval, err := GetFeatureDefault(edition, FeatureSetType, field)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// should we fail somehow??\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tdefaultsRef.Set(field, val)\n\t\t\t}\n\t\t\teditionDefaults[edition] = defaults\n\t\t}\n\t})\n\treturn editionDefaults[edition]\n}\n\n// GetFeatureDefault computes the default value for a feature. The given container\n// is the message type that contains the field. This should usually be the descriptor\n// for google.protobuf.FeatureSet, but can be a different message for computing the\n// default value of custom features.\n//\n// Note that this always re-computes the default. For known fields of FeatureSet,\n// it is more efficient to query from the statically computed default messages,\n// like so:\n//\n//\teditions.GetEditionDefaults(edition).ProtoReflect().Get(feature)\nfunc GetFeatureDefault(edition descriptorpb.Edition, container protoreflect.MessageType, feature protoreflect.FieldDescriptor) (protoreflect.Value, error) {\n\topts, ok := feature.Options().(*descriptorpb.FieldOptions)\n\tif !ok {\n\t\t// this is most likely impossible except for contrived use cases...\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"options is %T instead of *descriptorpb.FieldOptions\", feature.Options())\n\t}\n\tmaxEdition := descriptorpb.Edition(-1)\n\tvar maxVal string\n\tfor _, def := range opts.EditionDefaults {\n\t\tif def.GetEdition() <= edition && def.GetEdition() > maxEdition {\n\t\t\tmaxEdition = def.GetEdition()\n\t\t\tmaxVal = def.GetValue()\n\t\t}\n\t}\n\tif maxEdition == -1 {\n\t\t// no matching default found\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"no relevant default for edition %s\", edition)\n\t}\n\t// We use a typed nil so that it won't fall back to the global registry. Features\n\t// should not use extensions or google.protobuf.Any, so a nil *Types is fine.\n\tunmarshaler := prototext.UnmarshalOptions{Resolver: (*protoregistry.Types)(nil)}\n\t// The string value is in the text format: either a field value literal or a\n\t// message literal. (Repeated and map features aren't supported, so there's no\n\t// array or map literal syntax to worry about.)\n\tif feature.Kind() == protoreflect.MessageKind || feature.Kind() == protoreflect.GroupKind {\n\t\tfldVal := container.Zero().NewField(feature)\n\t\terr := unmarshaler.Unmarshal([]byte(maxVal), fldVal.Message().Interface())\n\t\tif err != nil {\n\t\t\treturn protoreflect.Value{}, err\n\t\t}\n\t\treturn fldVal, nil\n\t}\n\t// The value is the textformat for the field. But prototext doesn't provide a way\n\t// to unmarshal a single field value. To work around, we unmarshal into an enclosing\n\t// message, which means we must prefix the value with the field name.\n\tif feature.IsExtension() {\n\t\tmaxVal = fmt.Sprintf(\"[%s]: %s\", feature.FullName(), maxVal)\n\t} else {\n\t\tmaxVal = fmt.Sprintf(\"%s: %s\", feature.Name(), maxVal)\n\t}\n\tempty := container.New()\n\terr := unmarshaler.Unmarshal([]byte(maxVal), empty.Interface())\n\tif err != nil {\n\t\treturn protoreflect.Value{}, err\n\t}\n\treturn empty.Get(feature), nil\n}\n\nfunc adaptFeatureSet(msg *descriptorpb.FeatureSet, field protoreflect.FieldDescriptor) (protoreflect.Message, error) {\n\tmsgRef := msg.ProtoReflect()\n\tvar actualField protoreflect.FieldDescriptor\n\tswitch {\n\tcase field.IsExtension():\n\t\t// Extensions can be used directly with the feature set, even if\n\t\t// field.ContainingMessage() != FeatureSetDescriptor. But only if\n\t\t// the value is either not a message or is a message with the\n\t\t// right descriptor, i.e. val.Descriptor() == field.Message().\n\t\tif actualField = actualDescriptor(msgRef, field); actualField == nil || actualField == field {\n\t\t\tif msgRef.Has(field) || len(msgRef.GetUnknown()) == 0 {\n\t\t\t\treturn msgRef, nil\n\t\t\t}\n\t\t\t// The field is not present, but the message has unrecognized values. So\n\t\t\t// let's try to parse the unrecognized bytes, just in case they contain\n\t\t\t// this extension.\n\t\t\ttemp := &descriptorpb.FeatureSet{}\n\t\t\tunmarshaler := proto.UnmarshalOptions{\n\t\t\t\tAllowPartial: true,\n\t\t\t\tResolver:     resolverForExtension{field},\n\t\t\t}\n\t\t\tif err := unmarshaler.Unmarshal(msgRef.GetUnknown(), temp); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse unrecognized fields of FeatureSet: %w\", err)\n\t\t\t}\n\t\t\treturn temp.ProtoReflect(), nil\n\t\t}\n\tcase field.ContainingMessage() == FeatureSetDescriptor:\n\t\t// Known field, not dynamically generated. Can directly use with the feature set.\n\t\treturn msgRef, nil\n\tdefault:\n\t\tactualField = FeatureSetDescriptor.Fields().ByNumber(field.Number())\n\t}\n\n\t// If we get here, we have a dynamic field descriptor or an extension\n\t// descriptor whose message type does not match the descriptor of the\n\t// stored value. We need to copy its value into a dynamic message,\n\t// which requires marshalling/unmarshalling.\n\t// We only need to copy over the unrecognized bytes (if any)\n\t// and the same field (if present).\n\tdata := msgRef.GetUnknown()\n\tif actualField != nil && msgRef.Has(actualField) {\n\t\tsubset := &descriptorpb.FeatureSet{}\n\t\tsubset.ProtoReflect().Set(actualField, msgRef.Get(actualField))\n\t\tvar err error\n\t\tdata, err = proto.MarshalOptions{AllowPartial: true}.MarshalAppend(data, subset)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to marshal FeatureSet field %s to bytes: %w\", field.Name(), err)\n\t\t}\n\t}\n\tif len(data) == 0 {\n\t\t// No relevant data to copy over, so we can just return\n\t\t// a zero value message\n\t\treturn dynamicpb.NewMessageType(field.ContainingMessage()).Zero(), nil\n\t}\n\n\tother := dynamicpb.NewMessage(field.ContainingMessage())\n\t// We don't need to use a resolver for this step because we know that\n\t// field is not an extension. And features are not allowed to themselves\n\t// have extensions.\n\tif err := (proto.UnmarshalOptions{AllowPartial: true}).Unmarshal(data, other); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to marshal FeatureSet field %s to bytes: %w\", field.Name(), err)\n\t}\n\treturn other, nil\n}\n\ntype resolverForExtension struct {\n\text protoreflect.ExtensionDescriptor\n}\n\nfunc (r resolverForExtension) FindMessageByName(_ protoreflect.FullName) (protoreflect.MessageType, error) {\n\treturn nil, protoregistry.NotFound\n}\n\nfunc (r resolverForExtension) FindMessageByURL(_ string) (protoreflect.MessageType, error) {\n\treturn nil, protoregistry.NotFound\n}\n\nfunc (r resolverForExtension) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {\n\tif field == r.ext.FullName() {\n\t\treturn asExtensionType(r.ext), nil\n\t}\n\treturn nil, protoregistry.NotFound\n}\n\nfunc (r resolverForExtension) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {\n\tif message == r.ext.ContainingMessage().FullName() && field == r.ext.Number() {\n\t\treturn asExtensionType(r.ext), nil\n\t}\n\treturn nil, protoregistry.NotFound\n}\n\nfunc asExtensionType(ext protoreflect.ExtensionDescriptor) protoreflect.ExtensionType {\n\tif xtd, ok := ext.(protoreflect.ExtensionTypeDescriptor); ok {\n\t\treturn xtd.Type()\n\t}\n\treturn dynamicpb.NewExtensionType(ext)\n}\n\nfunc computeSupportedEditions(minEdition, maxEdition descriptorpb.Edition) map[string]descriptorpb.Edition {\n\tsupportedEditions := map[string]descriptorpb.Edition{}\n\tfor editionNum := range descriptorpb.Edition_name {\n\t\tedition := descriptorpb.Edition(editionNum)\n\t\tif edition >= minEdition && edition <= maxEdition {\n\t\t\tname := strings.TrimPrefix(edition.String(), \"EDITION_\")\n\t\t\tsupportedEditions[name] = edition\n\t\t}\n\t}\n\treturn supportedEditions\n}\n\n// actualDescriptor returns the actual field descriptor referenced by msg that\n// corresponds to the given ext (i.e. same number). It returns nil if msg has\n// no reference, if the actual descriptor is the same as ext, or if ext is\n// otherwise safe to use as is.\nfunc actualDescriptor(msg protoreflect.Message, ext protoreflect.ExtensionDescriptor) protoreflect.FieldDescriptor {\n\tif !msg.Has(ext) || ext.Message() == nil {\n\t\t// nothing to match; safe as is\n\t\treturn nil\n\t}\n\tval := msg.Get(ext)\n\tswitch {\n\tcase ext.IsMap(): // should not actually be possible\n\t\texpectedDescriptor := ext.MapValue().Message()\n\t\tif expectedDescriptor == nil {\n\t\t\treturn nil // nothing to match\n\t\t}\n\t\t// We know msg.Has(field) is true, from above, so there's at least one entry.\n\t\tvar matches bool\n\t\tval.Map().Range(func(_ protoreflect.MapKey, val protoreflect.Value) bool {\n\t\t\tmatches = val.Message().Descriptor() == expectedDescriptor\n\t\t\treturn false\n\t\t})\n\t\tif matches {\n\t\t\treturn nil\n\t\t}\n\tcase ext.IsList():\n\t\t// We know msg.Has(field) is true, from above, so there's at least one entry.\n\t\tif val.List().Get(0).Message().Descriptor() == ext.Message() {\n\t\t\treturn nil\n\t\t}\n\tcase !ext.IsMap():\n\t\tif val.Message().Descriptor() == ext.Message() {\n\t\t\treturn nil\n\t\t}\n\t}\n\t// The underlying message descriptors do not match. So we need to return\n\t// the actual field descriptor. Sadly, protoreflect.Message provides no way\n\t// to query the field descriptor in a message by number. For non-extensions,\n\t// one can query the associated message descriptor. But for extensions, we\n\t// have to do the slow thing, and range through all fields looking for it.\n\tvar actualField protoreflect.FieldDescriptor\n\tmsg.Range(func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {\n\t\tif fd.Number() == ext.Number() {\n\t\t\tactualField = fd\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t})\n\treturn actualField\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/featuresext/featuresext.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package featuresext provides file descriptors for the\n// \"google/protobuf/cpp_features.proto\" and \"google/protobuf/java_features.proto\"\n// standard import files. Unlike the other standard/well-known\n// imports, these files have no standard Go package in their\n// runtime with generated code. So in order to make them available\n// as \"standard imports\" to compiler users, we must embed these\n// descriptors into a Go package.\npackage featuresext\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"sync\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protodesc\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n)\n\nvar (\n\t//go:embed cpp_features.protoset\n\tcppFeatures []byte\n\n\t//go:embed java_features.protoset\n\tjavaFeatures []byte\n\n\tinitOnce         sync.Once\n\tinitCppFeatures  protoreflect.FileDescriptor\n\tinitCppErr       error\n\tinitJavaFeatures protoreflect.FileDescriptor\n\tinitJavaErr      error\n)\n\nfunc initDescriptors() {\n\tinitOnce.Do(func() {\n\t\tinitCppFeatures, initCppErr = buildDescriptor(\"google/protobuf/cpp_features.proto\", cppFeatures)\n\t\tinitJavaFeatures, initJavaErr = buildDescriptor(\"google/protobuf/java_features.proto\", javaFeatures)\n\t})\n}\n\nfunc CppFeaturesDescriptor() (protoreflect.FileDescriptor, error) {\n\tinitDescriptors()\n\treturn initCppFeatures, initCppErr\n}\n\nfunc JavaFeaturesDescriptor() (protoreflect.FileDescriptor, error) {\n\tinitDescriptors()\n\treturn initJavaFeatures, initJavaErr\n}\n\nfunc buildDescriptor(name string, data []byte) (protoreflect.FileDescriptor, error) {\n\tvar files descriptorpb.FileDescriptorSet\n\terr := proto.Unmarshal(data, &files)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load descriptor for %q: %w\", name, err)\n\t}\n\tif len(files.File) != 1 {\n\t\treturn nil, fmt.Errorf(\"failed to load descriptor for %q: expected embedded descriptor set to contain exactly one file but it instead has %d\", name, len(files.File))\n\t}\n\tif files.File[0].GetName() != name {\n\t\treturn nil, fmt.Errorf(\"failed to load descriptor for %q: embedded descriptor contains wrong file %q\", name, files.File[0].GetName())\n\t}\n\tdescriptor, err := protodesc.NewFile(files.File[0], protoregistry.GlobalFiles)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to load descriptor for %q: %w\", name, err)\n\t}\n\treturn descriptor, nil\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/message_context.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage internal\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n)\n\n// ParsedFile wraps an optional AST and required FileDescriptorProto.\n// This is used so types like parser.Result can be passed to this internal package avoiding circular imports.\n// Additionally, it makes it less likely that users might specify one or the other.\ntype ParsedFile interface {\n\t// AST returns the parsed abstract syntax tree. This returns nil if the\n\t// Result was created without an AST.\n\tAST() *ast.FileNode\n\t// FileDescriptorProto returns the file descriptor proto.\n\tFileDescriptorProto() *descriptorpb.FileDescriptorProto\n}\n\n// MessageContext provides information about the location in a descriptor\n// hierarchy, for adding context to warnings and error messages.\ntype MessageContext struct {\n\t// The relevant file\n\tFile ParsedFile\n\n\t// The type and fully-qualified name of the element within the file.\n\tElementType string\n\tElementName string\n\n\t// If the element being processed is an option (or *in* an option)\n\t// on the named element above, this will be non-nil.\n\tOption *descriptorpb.UninterpretedOption\n\t// If the element being processed is inside a message literal in an\n\t// option value, this will be non-empty and represent a traversal\n\t// to the element in question.\n\tOptAggPath string\n}\n\nfunc (c *MessageContext) String() string {\n\tvar ctx bytes.Buffer\n\tif c.ElementType != \"file\" {\n\t\t_, _ = fmt.Fprintf(&ctx, \"%s %s: \", c.ElementType, c.ElementName)\n\t}\n\tif c.Option != nil && c.Option.Name != nil {\n\t\tctx.WriteString(\"option \")\n\t\twriteOptionName(&ctx, c.Option.Name)\n\t\tif c.File.AST() == nil {\n\t\t\t// if we have no source position info, try to provide as much context\n\t\t\t// as possible (if nodes != nil, we don't need this because any errors\n\t\t\t// will actually have file and line numbers)\n\t\t\tif c.OptAggPath != \"\" {\n\t\t\t\t_, _ = fmt.Fprintf(&ctx, \" at %s\", c.OptAggPath)\n\t\t\t}\n\t\t}\n\t\tctx.WriteString(\": \")\n\t}\n\treturn ctx.String()\n}\n\nfunc writeOptionName(buf *bytes.Buffer, parts []*descriptorpb.UninterpretedOption_NamePart) {\n\tfirst := true\n\tfor _, p := range parts {\n\t\tif first {\n\t\t\tfirst = false\n\t\t} else {\n\t\t\tbuf.WriteByte('.')\n\t\t}\n\t\tnm := p.GetNamePart()\n\t\tif nm[0] == '.' {\n\t\t\t// skip leading dot\n\t\t\tnm = nm[1:]\n\t\t}\n\t\tif p.GetIsExtension() {\n\t\t\tbuf.WriteByte('(')\n\t\t\tbuf.WriteString(nm)\n\t\t\tbuf.WriteByte(')')\n\t\t} else {\n\t\t\tbuf.WriteString(nm)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/messageset/messageset.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage messageset\n\nimport (\n\t\"math\"\n\t\"sync\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protodesc\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n)\n\nvar (\n\tmessageSetSupport     bool\n\tmessageSetSupportInit sync.Once\n)\n\n// CanSupportMessageSets returns true if the protobuf-go runtime supports\n// serializing messages with the message set wire format.\nfunc CanSupportMessageSets() bool {\n\tmessageSetSupportInit.Do(func() {\n\t\t// We check using the protodesc package, instead of just relying\n\t\t// on protolegacy build tag, in case someone links in a fork of\n\t\t// the protobuf-go runtime that supports legacy proto1 features\n\t\t// or in case the protobuf-go runtime adds another mechanism to\n\t\t// enable or disable it (such as environment variable).\n\t\t_, err := protodesc.NewFile(&descriptorpb.FileDescriptorProto{\n\t\t\tName: proto.String(\"test.proto\"),\n\t\t\tMessageType: []*descriptorpb.DescriptorProto{\n\t\t\t\t{\n\t\t\t\t\tName: proto.String(\"MessageSet\"),\n\t\t\t\t\tOptions: &descriptorpb.MessageOptions{\n\t\t\t\t\t\tMessageSetWireFormat: proto.Bool(true),\n\t\t\t\t\t},\n\t\t\t\t\tExtensionRange: []*descriptorpb.DescriptorProto_ExtensionRange{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tStart: proto.Int32(1),\n\t\t\t\t\t\t\tEnd:   proto.Int32(math.MaxInt32),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}, nil)\n\t\t// When message sets are not supported, the above returns an error:\n\t\t//    message \"MessageSet\" is a MessageSet, which is a legacy proto1 feature that is no longer supported\n\t\tmessageSetSupport = err == nil\n\t})\n\treturn messageSetSupport\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/norace.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build !race\n\npackage internal\n\nconst IsRace = false\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/options.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage internal\n\nimport (\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n)\n\ntype hasOptionNode interface {\n\tOptionNode(part *descriptorpb.UninterpretedOption) ast.OptionDeclNode\n\tFileNode() ast.FileDeclNode // needed in order to query for NodeInfo\n}\n\ntype errorHandler func(span ast.SourceSpan, format string, args ...interface{}) error\n\nfunc FindFirstOption(res hasOptionNode, handler errorHandler, scope string, opts []*descriptorpb.UninterpretedOption, name string) (int, error) {\n\treturn findOption(res, handler, scope, opts, name, false, true)\n}\n\nfunc FindOption(res hasOptionNode, handler errorHandler, scope string, opts []*descriptorpb.UninterpretedOption, name string) (int, error) {\n\treturn findOption(res, handler, scope, opts, name, true, false)\n}\n\nfunc findOption(res hasOptionNode, handler errorHandler, scope string, opts []*descriptorpb.UninterpretedOption, name string, exact, first bool) (int, error) {\n\tfound := -1\n\tfor i, opt := range opts {\n\t\tif exact && len(opt.Name) != 1 {\n\t\t\tcontinue\n\t\t}\n\t\tif opt.Name[0].GetIsExtension() || opt.Name[0].GetNamePart() != name {\n\t\t\tcontinue\n\t\t}\n\t\tif first {\n\t\t\treturn i, nil\n\t\t}\n\t\tif found >= 0 {\n\t\t\toptNode := res.OptionNode(opt)\n\t\t\tfn := res.FileNode()\n\t\t\tnode := optNode.GetName()\n\t\t\tnodeInfo := fn.NodeInfo(node)\n\t\t\treturn -1, handler(nodeInfo, \"%s: option %s cannot be defined more than once\", scope, name)\n\t\t}\n\t\tfound = i\n\t}\n\treturn found, nil\n}\n\nfunc RemoveOption(uo []*descriptorpb.UninterpretedOption, indexToRemove int) []*descriptorpb.UninterpretedOption {\n\tswitch {\n\tcase indexToRemove == 0:\n\t\treturn uo[1:]\n\tcase indexToRemove == len(uo)-1:\n\t\treturn uo[:len(uo)-1]\n\tdefault:\n\t\treturn append(uo[:indexToRemove], uo[indexToRemove+1:]...)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/race.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build race\n\npackage internal\n\nconst IsRace = true\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/tags.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage internal\n\nimport \"math\"\n\nconst (\n\t// MaxNormalTag is the maximum allowed tag number for a field in a normal message.\n\tMaxNormalTag = 536870911 // 2^29 - 1\n\n\t// MaxMessageSetTag is the maximum allowed tag number of a field in a message that\n\t// uses the message set wire format.\n\tMaxMessageSetTag = math.MaxInt32 - 1\n\n\t// MaxTag is the maximum allowed tag number. (It is the same as MaxMessageSetTag\n\t// since that is the absolute highest allowed.)\n\tMaxTag = MaxMessageSetTag\n\n\t// SpecialReservedStart is the first tag in a range that is reserved and not\n\t// allowed for use in message definitions.\n\tSpecialReservedStart = 19000\n\t// SpecialReservedEnd is the last tag in a range that is reserved and not\n\t// allowed for use in message definitions.\n\tSpecialReservedEnd = 19999\n\n\t// NB: It would be nice to use constants from generated code instead of\n\t// hard-coding these here. But code-gen does not emit these as constants\n\t// anywhere. The only places they appear in generated code are struct tags\n\t// on fields of the generated descriptor protos.\n\n\t// FilePackageTag is the tag number of the package element in a file\n\t// descriptor proto.\n\tFilePackageTag = 2\n\t// FileDependencyTag is the tag number of the dependencies element in a\n\t// file descriptor proto.\n\tFileDependencyTag = 3\n\t// FileMessagesTag is the tag number of the messages element in a file\n\t// descriptor proto.\n\tFileMessagesTag = 4\n\t// FileEnumsTag is the tag number of the enums element in a file descriptor\n\t// proto.\n\tFileEnumsTag = 5\n\t// FileServicesTag is the tag number of the services element in a file\n\t// descriptor proto.\n\tFileServicesTag = 6\n\t// FileExtensionsTag is the tag number of the extensions element in a file\n\t// descriptor proto.\n\tFileExtensionsTag = 7\n\t// FileOptionsTag is the tag number of the options element in a file\n\t// descriptor proto.\n\tFileOptionsTag = 8\n\t// FileOptionsJavaStringCheckUTF8Tag is the tag number of the java_string_check_utf8\n\t// field in the FileOptions proto.\n\tFileOptionsJavaStringCheckUTF8Tag = 27\n\t// FileOptionsFeaturesTag is the tag number of the features field in the\n\t// FileOptions proto.\n\tFileOptionsFeaturesTag = 50\n\t// FileSourceCodeInfoTag is the tag number of the source code info element\n\t// in a file descriptor proto.\n\tFileSourceCodeInfoTag = 9\n\t// FilePublicDependencyTag is the tag number of the public dependency element\n\t// in a file descriptor proto.\n\tFilePublicDependencyTag = 10\n\t// FileWeakDependencyTag is the tag number of the weak dependency element\n\t// in a file descriptor proto.\n\tFileWeakDependencyTag = 11\n\t// FileSyntaxTag is the tag number of the syntax element in a file\n\t// descriptor proto.\n\tFileSyntaxTag = 12\n\t// FileEditionTag is the tag number of the edition element in a file\n\t// descriptor proto.\n\tFileEditionTag = 14\n\t// MessageNameTag is the tag number of the name element in a message\n\t// descriptor proto.\n\tMessageNameTag = 1\n\t// MessageFieldsTag is the tag number of the fields element in a message\n\t// descriptor proto.\n\tMessageFieldsTag = 2\n\t// MessageNestedMessagesTag is the tag number of the nested messages\n\t// element in a message descriptor proto.\n\tMessageNestedMessagesTag = 3\n\t// MessageEnumsTag is the tag number of the enums element in a message\n\t// descriptor proto.\n\tMessageEnumsTag = 4\n\t// MessageExtensionRangesTag is the tag number of the extension ranges\n\t// element in a message descriptor proto.\n\tMessageExtensionRangesTag = 5\n\t// MessageExtensionsTag is the tag number of the extensions element in a\n\t// message descriptor proto.\n\tMessageExtensionsTag = 6\n\t// MessageOptionsTag is the tag number of the options element in a message\n\t// descriptor proto.\n\tMessageOptionsTag = 7\n\t// MessageOptionsFeaturesTag is the tag number of the features field in the\n\t// MessageOptions proto.\n\tMessageOptionsFeaturesTag = 12\n\t// MessageOneofsTag is the tag number of the one-ofs element in a message\n\t// descriptor proto.\n\tMessageOneofsTag = 8\n\t// MessageReservedRangesTag is the tag number of the reserved ranges element\n\t// in a message descriptor proto.\n\tMessageReservedRangesTag = 9\n\t// MessageReservedNamesTag is the tag number of the reserved names element\n\t// in a message descriptor proto.\n\tMessageReservedNamesTag = 10\n\t// ExtensionRangeStartTag is the tag number of the start index in an\n\t// extension range proto.\n\tExtensionRangeStartTag = 1\n\t// ExtensionRangeEndTag is the tag number of the end index in an\n\t// extension range proto.\n\tExtensionRangeEndTag = 2\n\t// ExtensionRangeOptionsTag is the tag number of the options element in an\n\t// extension range proto.\n\tExtensionRangeOptionsTag = 3\n\t// ExtensionRangeOptionsDeclarationTag is the tag number of the declaration\n\t// field in the ExtensionRangeOptions proto.\n\tExtensionRangeOptionsDeclarationTag = 2\n\t// ExtensionRangeOptionsVerificationTag is the tag number of the verification\n\t// field in the ExtensionRangeOptions proto.\n\tExtensionRangeOptionsVerificationTag = 3\n\t// ExtensionRangeOptionsDeclarationNumberTag is the tag number of the number\n\t// field in the ExtensionRangeOptions.Declaration proto.\n\tExtensionRangeOptionsDeclarationNumberTag = 1\n\t// ExtensionRangeOptionsDeclarationFullNameTag is the tag number of the full_name\n\t// field in the ExtensionRangeOptions.Declaration proto.\n\tExtensionRangeOptionsDeclarationFullNameTag = 2\n\t// ExtensionRangeOptionsDeclarationTypeTag is the tag number of the type\n\t// field in the ExtensionRangeOptions.Declaration proto.\n\tExtensionRangeOptionsDeclarationTypeTag = 3\n\t// ExtensionRangeOptionsDeclarationReservedTag is the tag number of the reserved\n\t// field in the ExtensionRangeOptions.Declaration proto.\n\tExtensionRangeOptionsDeclarationReservedTag = 5\n\t// ExtensionRangeOptionsDeclarationRepeatedTag is the tag number of the repeated\n\t// field in the ExtensionRangeOptions.Declaration proto.\n\tExtensionRangeOptionsDeclarationRepeatedTag = 6\n\t// ExtensionRangeOptionsFeaturesTag is the tag number of the features field in the\n\t// ExtensionRangeOptions proto.\n\tExtensionRangeOptionsFeaturesTag = 50\n\t// ReservedRangeStartTag is the tag number of the start index in a reserved\n\t// range proto. This field number is the same for both \"flavors\" of reserved\n\t// ranges: DescriptorProto.ReservedRange and EnumDescriptorProto.EnumReservedRange.\n\tReservedRangeStartTag = 1\n\t// ReservedRangeEndTag is the tag number of the end index in a reserved\n\t// range proto. This field number is the same for both \"flavors\" of reserved\n\t// ranges: DescriptorProto.ReservedRange and EnumDescriptorProto.EnumReservedRange.\n\tReservedRangeEndTag = 2\n\t// FieldNameTag is the tag number of the name element in a field descriptor\n\t// proto.\n\tFieldNameTag = 1\n\t// FieldExtendeeTag is the tag number of the extendee element in a field\n\t// descriptor proto.\n\tFieldExtendeeTag = 2\n\t// FieldNumberTag is the tag number of the number element in a field\n\t// descriptor proto.\n\tFieldNumberTag = 3\n\t// FieldLabelTag is the tag number of the label element in a field\n\t// descriptor proto.\n\tFieldLabelTag = 4\n\t// FieldTypeTag is the tag number of the type element in a field descriptor\n\t// proto.\n\tFieldTypeTag = 5\n\t// FieldTypeNameTag is the tag number of the type name element in a field\n\t// descriptor proto.\n\tFieldTypeNameTag = 6\n\t// FieldDefaultTag is the tag number of the default value element in a\n\t// field descriptor proto.\n\tFieldDefaultTag = 7\n\t// FieldOptionsTag is the tag number of the options element in a field\n\t// descriptor proto.\n\tFieldOptionsTag = 8\n\t// FieldOptionsCTypeTag is the number of the ctype field in the\n\t// FieldOptions proto.\n\tFieldOptionsCTypeTag = 1\n\t// FieldOptionsPackedTag is the number of the packed field in the\n\t// FieldOptions proto.\n\tFieldOptionsPackedTag = 2\n\t// FieldOptionsLazyTag is the number of the lazy field in the\n\t// FieldOptions proto.\n\tFieldOptionsLazyTag = 5\n\t// FieldOptionsJSTypeTag is the number of the jstype field in the\n\t// FieldOptions proto.\n\tFieldOptionsJSTypeTag = 6\n\t// FieldOptionsUnverifiedLazyTag is the number of the unverified_lazy\n\t// field in the FieldOptions proto.\n\tFieldOptionsUnverifiedLazyTag = 15\n\t// FieldOptionsFeaturesTag is the tag number of the features field in the\n\t// FieldOptions proto.\n\tFieldOptionsFeaturesTag = 21\n\t// FieldOneofIndexTag is the tag number of the oneof index element in a\n\t// field descriptor proto.\n\tFieldOneofIndexTag = 9\n\t// FieldJSONNameTag is the tag number of the JSON name element in a field\n\t// descriptor proto.\n\tFieldJSONNameTag = 10\n\t// FieldProto3OptionalTag is the tag number of the proto3_optional element\n\t// in a descriptor proto.\n\tFieldProto3OptionalTag = 17\n\t// OneofNameTag is the tag number of the name element in a one-of\n\t// descriptor proto.\n\tOneofNameTag = 1\n\t// OneofOptionsTag is the tag number of the options element in a one-of\n\t// descriptor proto.\n\tOneofOptionsTag = 2\n\t// OneofOptionsFeaturesTag is the tag number of the features field in the\n\t// OneofOptions proto.\n\tOneofOptionsFeaturesTag = 1\n\t// EnumNameTag is the tag number of the name element in an enum descriptor\n\t// proto.\n\tEnumNameTag = 1\n\t// EnumValuesTag is the tag number of the values element in an enum\n\t// descriptor proto.\n\tEnumValuesTag = 2\n\t// EnumOptionsTag is the tag number of the options element in an enum\n\t// descriptor proto.\n\tEnumOptionsTag = 3\n\t// EnumOptionsFeaturesTag is the tag number of the features field in the\n\t// EnumOptions proto.\n\tEnumOptionsFeaturesTag = 7\n\t// EnumReservedRangesTag is the tag number of the reserved ranges element in\n\t// an enum descriptor proto.\n\tEnumReservedRangesTag = 4\n\t// EnumReservedNamesTag is the tag number of the reserved names element in\n\t// an enum descriptor proto.\n\tEnumReservedNamesTag = 5\n\t// EnumValNameTag is the tag number of the name element in an enum value\n\t// descriptor proto.\n\tEnumValNameTag = 1\n\t// EnumValNumberTag is the tag number of the number element in an enum\n\t// value descriptor proto.\n\tEnumValNumberTag = 2\n\t// EnumValOptionsTag is the tag number of the options element in an enum\n\t// value descriptor proto.\n\tEnumValOptionsTag = 3\n\t// EnumValOptionsFeaturesTag is the tag number of the features field in the\n\t// EnumValueOptions proto.\n\tEnumValOptionsFeaturesTag = 2\n\t// ServiceNameTag is the tag number of the name element in a service\n\t// descriptor proto.\n\tServiceNameTag = 1\n\t// ServiceMethodsTag is the tag number of the methods element in a service\n\t// descriptor proto.\n\tServiceMethodsTag = 2\n\t// ServiceOptionsTag is the tag number of the options element in a service\n\t// descriptor proto.\n\tServiceOptionsTag = 3\n\t// ServiceOptionsFeaturesTag is the tag number of the features field in the\n\t// ServiceOptions proto.\n\tServiceOptionsFeaturesTag = 34\n\t// MethodNameTag is the tag number of the name element in a method\n\t// descriptor proto.\n\tMethodNameTag = 1\n\t// MethodInputTag is the tag number of the input type element in a method\n\t// descriptor proto.\n\tMethodInputTag = 2\n\t// MethodOutputTag is the tag number of the output type element in a method\n\t// descriptor proto.\n\tMethodOutputTag = 3\n\t// MethodOptionsTag is the tag number of the options element in a method\n\t// descriptor proto.\n\tMethodOptionsTag = 4\n\t// MethodOptionsFeaturesTag is the tag number of the features field in the\n\t// MethodOptions proto.\n\tMethodOptionsFeaturesTag = 35\n\t// MethodInputStreamTag is the tag number of the input stream flag in a\n\t// method descriptor proto.\n\tMethodInputStreamTag = 5\n\t// MethodOutputStreamTag is the tag number of the output stream flag in a\n\t// method descriptor proto.\n\tMethodOutputStreamTag = 6\n\n\t// UninterpretedOptionsTag is the tag number of the uninterpreted options\n\t// element. All *Options messages use the same tag for the field that stores\n\t// uninterpreted options.\n\tUninterpretedOptionsTag = 999\n\n\t// UninterpretedNameTag is the tag number of the name element in an\n\t// uninterpreted options proto.\n\tUninterpretedNameTag = 2\n\t// UninterpretedIdentTag is the tag number of the identifier value in an\n\t// uninterpreted options proto.\n\tUninterpretedIdentTag = 3\n\t// UninterpretedPosIntTag is the tag number of the positive int value in an\n\t// uninterpreted options proto.\n\tUninterpretedPosIntTag = 4\n\t// UninterpretedNegIntTag is the tag number of the negative int value in an\n\t// uninterpreted options proto.\n\tUninterpretedNegIntTag = 5\n\t// UninterpretedDoubleTag is the tag number of the double value in an\n\t// uninterpreted options proto.\n\tUninterpretedDoubleTag = 6\n\t// UninterpretedStringTag is the tag number of the string value in an\n\t// uninterpreted options proto.\n\tUninterpretedStringTag = 7\n\t// UninterpretedAggregateTag is the tag number of the aggregate value in an\n\t// uninterpreted options proto.\n\tUninterpretedAggregateTag = 8\n\t// UninterpretedNameNameTag is the tag number of the name element in an\n\t// uninterpreted option name proto.\n\tUninterpretedNameNameTag = 1\n\n\t// AnyTypeURLTag is the tag number of the type_url field of the Any proto.\n\tAnyTypeURLTag = 1\n\t// AnyValueTag is the tag number of the value field of the Any proto.\n\tAnyValueTag = 2\n\n\t// FeatureSetFieldPresenceTag is the tag number of the field_presence field\n\t// in the FeatureSet proto.\n\tFeatureSetFieldPresenceTag = 1\n\t// FeatureSetEnumTypeTag is the tag number of the enum_type field in the\n\t// FeatureSet proto.\n\tFeatureSetEnumTypeTag = 2\n\t// FeatureSetRepeatedFieldEncodingTag is the tag number of the repeated_field_encoding\n\t// field in the FeatureSet proto.\n\tFeatureSetRepeatedFieldEncodingTag = 3\n\t// FeatureSetUTF8ValidationTag is the tag number of the utf8_validation field\n\t// in the FeatureSet proto.\n\tFeatureSetUTF8ValidationTag = 4\n\t// FeatureSetMessageEncodingTag is the tag number of the message_encoding\n\t// field in the FeatureSet proto.\n\tFeatureSetMessageEncodingTag = 5\n\t// FeatureSetJSONFormatTag is the tag number of the json_format field in\n\t// the FeatureSet proto.\n\tFeatureSetJSONFormatTag = 6\n)\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/types.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage internal\n\nimport \"google.golang.org/protobuf/types/descriptorpb\"\n\nvar FieldTypes = map[string]descriptorpb.FieldDescriptorProto_Type{\n\t\"double\":   descriptorpb.FieldDescriptorProto_TYPE_DOUBLE,\n\t\"float\":    descriptorpb.FieldDescriptorProto_TYPE_FLOAT,\n\t\"int32\":    descriptorpb.FieldDescriptorProto_TYPE_INT32,\n\t\"int64\":    descriptorpb.FieldDescriptorProto_TYPE_INT64,\n\t\"uint32\":   descriptorpb.FieldDescriptorProto_TYPE_UINT32,\n\t\"uint64\":   descriptorpb.FieldDescriptorProto_TYPE_UINT64,\n\t\"sint32\":   descriptorpb.FieldDescriptorProto_TYPE_SINT32,\n\t\"sint64\":   descriptorpb.FieldDescriptorProto_TYPE_SINT64,\n\t\"fixed32\":  descriptorpb.FieldDescriptorProto_TYPE_FIXED32,\n\t\"fixed64\":  descriptorpb.FieldDescriptorProto_TYPE_FIXED64,\n\t\"sfixed32\": descriptorpb.FieldDescriptorProto_TYPE_SFIXED32,\n\t\"sfixed64\": descriptorpb.FieldDescriptorProto_TYPE_SFIXED64,\n\t\"bool\":     descriptorpb.FieldDescriptorProto_TYPE_BOOL,\n\t\"string\":   descriptorpb.FieldDescriptorProto_TYPE_STRING,\n\t\"bytes\":    descriptorpb.FieldDescriptorProto_TYPE_BYTES,\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/internal/util.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage internal\n\nimport (\n\t\"bytes\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n)\n\n// JSONName returns the default JSON name for a field with the given name.\n// This mirrors the algorithm in protoc:\n//\n//\thttps://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L95\nfunc JSONName(name string) string {\n\tvar js []rune\n\tnextUpper := false\n\tfor _, r := range name {\n\t\tif r == '_' {\n\t\t\tnextUpper = true\n\t\t\tcontinue\n\t\t}\n\t\tif nextUpper {\n\t\t\tnextUpper = false\n\t\t\tjs = append(js, unicode.ToUpper(r))\n\t\t} else {\n\t\t\tjs = append(js, r)\n\t\t}\n\t}\n\treturn string(js)\n}\n\n// InitCap returns the given field name, but with the first letter capitalized.\nfunc InitCap(name string) string {\n\tr, sz := utf8.DecodeRuneInString(name)\n\treturn string(unicode.ToUpper(r)) + name[sz:]\n}\n\n// CreatePrefixList returns a list of package prefixes to search when resolving\n// a symbol name. If the given package is blank, it returns only the empty\n// string. If the given package contains only one token, e.g. \"foo\", it returns\n// that token and the empty string, e.g. [\"foo\", \"\"]. Otherwise, it returns\n// successively shorter prefixes of the package and then the empty string. For\n// example, for a package named \"foo.bar.baz\" it will return the following list:\n//\n//\t[\"foo.bar.baz\", \"foo.bar\", \"foo\", \"\"]\nfunc CreatePrefixList(pkg string) []string {\n\tif pkg == \"\" {\n\t\treturn []string{\"\"}\n\t}\n\n\tnumDots := 0\n\t// one pass to pre-allocate the returned slice\n\tfor i := 0; i < len(pkg); i++ {\n\t\tif pkg[i] == '.' {\n\t\t\tnumDots++\n\t\t}\n\t}\n\tif numDots == 0 {\n\t\treturn []string{pkg, \"\"}\n\t}\n\n\tprefixes := make([]string, numDots+2)\n\t// second pass to fill in returned slice\n\tfor i := 0; i < len(pkg); i++ {\n\t\tif pkg[i] == '.' {\n\t\t\tprefixes[numDots] = pkg[:i]\n\t\t\tnumDots--\n\t\t}\n\t}\n\tprefixes[0] = pkg\n\n\treturn prefixes\n}\n\nfunc WriteEscapedBytes(buf *bytes.Buffer, b []byte) {\n\t// This uses the same algorithm as the protoc C++ code for escaping strings.\n\t// The protoc C++ code in turn uses the abseil C++ library's CEscape function:\n\t//  https://github.com/abseil/abseil-cpp/blob/934f613818ffcb26c942dff4a80be9a4031c662c/absl/strings/escaping.cc#L406\n\tfor _, c := range b {\n\t\tswitch c {\n\t\tcase '\\n':\n\t\t\tbuf.WriteString(\"\\\\n\")\n\t\tcase '\\r':\n\t\t\tbuf.WriteString(\"\\\\r\")\n\t\tcase '\\t':\n\t\t\tbuf.WriteString(\"\\\\t\")\n\t\tcase '\"':\n\t\t\tbuf.WriteString(\"\\\\\\\"\")\n\t\tcase '\\'':\n\t\t\tbuf.WriteString(\"\\\\'\")\n\t\tcase '\\\\':\n\t\t\tbuf.WriteString(\"\\\\\\\\\")\n\t\tdefault:\n\t\t\tif c >= 0x20 && c < 0x7f {\n\t\t\t\t// simple printable characters\n\t\t\t\tbuf.WriteByte(c)\n\t\t\t} else {\n\t\t\t\t// use octal escape for all other values\n\t\t\t\tbuf.WriteRune('\\\\')\n\t\t\t\tbuf.WriteByte('0' + ((c >> 6) & 0x7))\n\t\t\t\tbuf.WriteByte('0' + ((c >> 3) & 0x7))\n\t\t\t\tbuf.WriteByte('0' + (c & 0x7))\n\t\t\t}\n\t\t}\n\t}\n}\n\n// IsZeroLocation returns true if the given loc is a zero value\n// (which is returned from queries that have no result).\nfunc IsZeroLocation(loc protoreflect.SourceLocation) bool {\n\treturn loc.Path == nil &&\n\t\tloc.StartLine == 0 &&\n\t\tloc.StartColumn == 0 &&\n\t\tloc.EndLine == 0 &&\n\t\tloc.EndColumn == 0 &&\n\t\tloc.LeadingDetachedComments == nil &&\n\t\tloc.LeadingComments == \"\" &&\n\t\tloc.TrailingComments == \"\" &&\n\t\tloc.Next == 0\n}\n\n// ComputePath computes the source location path for the given descriptor.\n// The boolean value indicates whether the result is valid. If the path\n// cannot be computed for d, the function returns nil, false.\nfunc ComputePath(d protoreflect.Descriptor) (protoreflect.SourcePath, bool) {\n\t_, ok := d.(protoreflect.FileDescriptor)\n\tif ok {\n\t\treturn nil, true\n\t}\n\tvar path protoreflect.SourcePath\n\tfor {\n\t\tp := d.Parent()\n\t\tswitch d := d.(type) {\n\t\tcase protoreflect.FileDescriptor:\n\t\t\treturn reverse(path), true\n\t\tcase protoreflect.MessageDescriptor:\n\t\t\tpath = append(path, int32(d.Index()))\n\t\t\tswitch p.(type) {\n\t\t\tcase protoreflect.FileDescriptor:\n\t\t\t\tpath = append(path, FileMessagesTag)\n\t\t\tcase protoreflect.MessageDescriptor:\n\t\t\t\tpath = append(path, MessageNestedMessagesTag)\n\t\t\tdefault:\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\tcase protoreflect.FieldDescriptor:\n\t\t\tpath = append(path, int32(d.Index()))\n\t\t\tswitch p.(type) {\n\t\t\tcase protoreflect.FileDescriptor:\n\t\t\t\tif d.IsExtension() {\n\t\t\t\t\tpath = append(path, FileExtensionsTag)\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, false\n\t\t\t\t}\n\t\t\tcase protoreflect.MessageDescriptor:\n\t\t\t\tif d.IsExtension() {\n\t\t\t\t\tpath = append(path, MessageExtensionsTag)\n\t\t\t\t} else {\n\t\t\t\t\tpath = append(path, MessageFieldsTag)\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\tcase protoreflect.OneofDescriptor:\n\t\t\tpath = append(path, int32(d.Index()))\n\t\t\tif _, ok := p.(protoreflect.MessageDescriptor); ok {\n\t\t\t\tpath = append(path, MessageOneofsTag)\n\t\t\t} else {\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\tcase protoreflect.EnumDescriptor:\n\t\t\tpath = append(path, int32(d.Index()))\n\t\t\tswitch p.(type) {\n\t\t\tcase protoreflect.FileDescriptor:\n\t\t\t\tpath = append(path, FileEnumsTag)\n\t\t\tcase protoreflect.MessageDescriptor:\n\t\t\t\tpath = append(path, MessageEnumsTag)\n\t\t\tdefault:\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\tcase protoreflect.EnumValueDescriptor:\n\t\t\tpath = append(path, int32(d.Index()))\n\t\t\tif _, ok := p.(protoreflect.EnumDescriptor); ok {\n\t\t\t\tpath = append(path, EnumValuesTag)\n\t\t\t} else {\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\tcase protoreflect.ServiceDescriptor:\n\t\t\tpath = append(path, int32(d.Index()))\n\t\t\tif _, ok := p.(protoreflect.FileDescriptor); ok {\n\t\t\t\tpath = append(path, FileServicesTag)\n\t\t\t} else {\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\tcase protoreflect.MethodDescriptor:\n\t\t\tpath = append(path, int32(d.Index()))\n\t\t\tif _, ok := p.(protoreflect.ServiceDescriptor); ok {\n\t\t\t\tpath = append(path, ServiceMethodsTag)\n\t\t\t} else {\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\t}\n\t\td = p\n\t}\n}\n\n// CanPack returns true if a repeated field of the given kind\n// can use packed encoding.\nfunc CanPack(k protoreflect.Kind) bool {\n\tswitch k {\n\tcase protoreflect.MessageKind, protoreflect.GroupKind, protoreflect.StringKind, protoreflect.BytesKind:\n\t\treturn false\n\tdefault:\n\t\treturn true\n\t}\n}\n\nfunc ClonePath(path protoreflect.SourcePath) protoreflect.SourcePath {\n\tclone := make(protoreflect.SourcePath, len(path))\n\tcopy(clone, path)\n\treturn clone\n}\n\nfunc reverse(p protoreflect.SourcePath) protoreflect.SourcePath {\n\tfor i, j := 0, len(p)-1; i < j; i, j = i+1, j-1 {\n\t\tp[i], p[j] = p[j], p[i]\n\t}\n\treturn p\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/descriptors.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage linker\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protodesc\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n\t\"github.com/bufbuild/protocompile/internal/editions\"\n\t\"github.com/bufbuild/protocompile/parser\"\n\t\"github.com/bufbuild/protocompile/protoutil\"\n)\n\nvar (\n\t// These \"noOp*\" values are all descriptors. The protoreflect.Descriptor\n\t// interface and its sub-interfaces are all marked with an unexported\n\t// method so that they cannot be implemented outside of the google.golang.org/protobuf\n\t// module. So, to provide implementations from this package, we must embed\n\t// them. If we simply left the embedded interface field nil, then if/when\n\t// new methods are added to the interfaces, it could induce panics in this\n\t// package or users of this module (since trying to invoke one of these new\n\t// methods would end up trying to call a method on a nil interface value).\n\t//\n\t// So instead of leaving the embedded interface fields nil, we embed an actual\n\t// value. While new methods are unlikely to return the correct value (since\n\t// the calls will be delegated to these no-op instances), it is a less\n\t// dangerous latent bug than inducing a nil-dereference panic.\n\n\tnoOpFile      protoreflect.FileDescriptor\n\tnoOpMessage   protoreflect.MessageDescriptor\n\tnoOpOneof     protoreflect.OneofDescriptor\n\tnoOpField     protoreflect.FieldDescriptor\n\tnoOpEnum      protoreflect.EnumDescriptor\n\tnoOpEnumValue protoreflect.EnumValueDescriptor\n\tnoOpExtension protoreflect.ExtensionDescriptor\n\tnoOpService   protoreflect.ServiceDescriptor\n\tnoOpMethod    protoreflect.MethodDescriptor\n)\n\nvar (\n\tfieldPresenceField         = editions.FeatureSetDescriptor.Fields().ByName(\"field_presence\")\n\trepeatedFieldEncodingField = editions.FeatureSetDescriptor.Fields().ByName(\"repeated_field_encoding\")\n\tmessageEncodingField       = editions.FeatureSetDescriptor.Fields().ByName(\"message_encoding\")\n\tenumTypeField              = editions.FeatureSetDescriptor.Fields().ByName(\"enum_type\")\n\tjsonFormatField            = editions.FeatureSetDescriptor.Fields().ByName(\"json_format\")\n)\n\nfunc init() {\n\tnoOpFile, _ = protodesc.NewFile(\n\t\t&descriptorpb.FileDescriptorProto{\n\t\t\tName:       proto.String(\"no-op.proto\"),\n\t\t\tSyntax:     proto.String(\"proto2\"),\n\t\t\tDependency: []string{\"google/protobuf/descriptor.proto\"},\n\t\t\tMessageType: []*descriptorpb.DescriptorProto{\n\t\t\t\t{\n\t\t\t\t\tName: proto.String(\"NoOpMsg\"),\n\t\t\t\t\tField: []*descriptorpb.FieldDescriptorProto{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:       proto.String(\"no_op\"),\n\t\t\t\t\t\t\tType:       descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),\n\t\t\t\t\t\t\tLabel:      descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),\n\t\t\t\t\t\t\tNumber:     proto.Int32(1),\n\t\t\t\t\t\t\tJsonName:   proto.String(\"noOp\"),\n\t\t\t\t\t\t\tOneofIndex: proto.Int32(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tOneofDecl: []*descriptorpb.OneofDescriptorProto{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName: proto.String(\"no_op_oneof\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tEnumType: []*descriptorpb.EnumDescriptorProto{\n\t\t\t\t{\n\t\t\t\t\tName: proto.String(\"NoOpEnum\"),\n\t\t\t\t\tValue: []*descriptorpb.EnumValueDescriptorProto{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:   proto.String(\"NO_OP\"),\n\t\t\t\t\t\t\tNumber: proto.Int32(0),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tExtension: []*descriptorpb.FieldDescriptorProto{\n\t\t\t\t{\n\t\t\t\t\tExtendee: proto.String(\".google.protobuf.FileOptions\"),\n\t\t\t\t\tName:     proto.String(\"no_op\"),\n\t\t\t\t\tType:     descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(),\n\t\t\t\t\tLabel:    descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),\n\t\t\t\t\tNumber:   proto.Int32(50000),\n\t\t\t\t},\n\t\t\t},\n\t\t\tService: []*descriptorpb.ServiceDescriptorProto{\n\t\t\t\t{\n\t\t\t\t\tName: proto.String(\"NoOpService\"),\n\t\t\t\t\tMethod: []*descriptorpb.MethodDescriptorProto{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tName:       proto.String(\"NoOp\"),\n\t\t\t\t\t\t\tInputType:  proto.String(\".NoOpMsg\"),\n\t\t\t\t\t\t\tOutputType: proto.String(\".NoOpMsg\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tprotoregistry.GlobalFiles,\n\t)\n\tnoOpMessage = noOpFile.Messages().Get(0)\n\tnoOpOneof = noOpMessage.Oneofs().Get(0)\n\tnoOpField = noOpMessage.Fields().Get(0)\n\tnoOpEnum = noOpFile.Enums().Get(0)\n\tnoOpEnumValue = noOpEnum.Values().Get(0)\n\tnoOpExtension = noOpFile.Extensions().Get(0)\n\tnoOpService = noOpFile.Services().Get(0)\n\tnoOpMethod = noOpService.Methods().Get(0)\n}\n\n// This file contains implementations of protoreflect.Descriptor. Note that\n// this is a hack since those interfaces have a \"doNotImplement\" tag\n// interface therein. We do just enough to make dynamicpb happy; constructing\n// a regular descriptor would fail because we haven't yet interpreted options\n// at the point we need these, and some validations will fail if the options\n// aren't present.\n\ntype result struct {\n\tprotoreflect.FileDescriptor\n\tparser.Result\n\tprefix string\n\tdeps   Files\n\n\t// A map of all descriptors keyed by their fully-qualified name (without\n\t// any leading dot).\n\tdescriptors map[string]protoreflect.Descriptor\n\n\t// A set of imports that have been used in the course of linking and\n\t// interpreting options.\n\tusedImports map[string]struct{}\n\n\t// A map of AST nodes that represent identifiers in ast.FieldReferenceNodes\n\t// to their fully-qualified name. The identifiers are for field names in\n\t// message literals (in option values) that are extension fields. These names\n\t// are resolved during linking and stored here, to be used to interpret options.\n\toptionQualifiedNames map[ast.IdentValueNode]string\n\n\timports      fileImports\n\tmessages     msgDescriptors\n\tenums        enumDescriptors\n\textensions   extDescriptors\n\tservices     svcDescriptors\n\tsrcLocations srcLocs\n}\n\nvar _ protoreflect.FileDescriptor = (*result)(nil)\nvar _ Result = (*result)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*result)(nil)\nvar _ editions.HasEdition = (*result)(nil)\n\nfunc (r *result) RemoveAST() {\n\tr.Result = parser.ResultWithoutAST(r.FileDescriptorProto())\n\tr.optionQualifiedNames = nil\n}\n\nfunc (r *result) AsProto() proto.Message {\n\treturn r.FileDescriptorProto()\n}\n\nfunc (r *result) ParentFile() protoreflect.FileDescriptor {\n\treturn r\n}\n\nfunc (r *result) Parent() protoreflect.Descriptor {\n\treturn nil\n}\n\nfunc (r *result) Index() int {\n\treturn 0\n}\n\nfunc (r *result) Syntax() protoreflect.Syntax {\n\tswitch r.FileDescriptorProto().GetSyntax() {\n\tcase \"proto2\", \"\":\n\t\treturn protoreflect.Proto2\n\tcase \"proto3\":\n\t\treturn protoreflect.Proto3\n\tcase \"editions\":\n\t\treturn protoreflect.Editions\n\tdefault:\n\t\treturn 0 // ???\n\t}\n}\n\nfunc (r *result) Edition() int32 {\n\tswitch r.Syntax() {\n\tcase protoreflect.Proto2:\n\t\treturn int32(descriptorpb.Edition_EDITION_PROTO2)\n\tcase protoreflect.Proto3:\n\t\treturn int32(descriptorpb.Edition_EDITION_PROTO3)\n\tcase protoreflect.Editions:\n\t\treturn int32(r.FileDescriptorProto().GetEdition())\n\tdefault:\n\t\treturn int32(descriptorpb.Edition_EDITION_UNKNOWN) // ???\n\t}\n}\n\nfunc (r *result) Name() protoreflect.Name {\n\treturn \"\"\n}\n\nfunc (r *result) FullName() protoreflect.FullName {\n\treturn r.Package()\n}\n\nfunc (r *result) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (r *result) Options() protoreflect.ProtoMessage {\n\treturn r.FileDescriptorProto().Options\n}\n\nfunc (r *result) Path() string {\n\treturn r.FileDescriptorProto().GetName()\n}\n\nfunc (r *result) Package() protoreflect.FullName {\n\treturn protoreflect.FullName(r.FileDescriptorProto().GetPackage())\n}\n\nfunc (r *result) Imports() protoreflect.FileImports {\n\treturn &r.imports\n}\n\nfunc (r *result) Enums() protoreflect.EnumDescriptors {\n\treturn &r.enums\n}\n\nfunc (r *result) Messages() protoreflect.MessageDescriptors {\n\treturn &r.messages\n}\n\nfunc (r *result) Extensions() protoreflect.ExtensionDescriptors {\n\treturn &r.extensions\n}\n\nfunc (r *result) Services() protoreflect.ServiceDescriptors {\n\treturn &r.services\n}\n\nfunc (r *result) PopulateSourceCodeInfo() {\n\tsrcLocProtos := asSourceLocations(r.FileDescriptorProto().GetSourceCodeInfo().GetLocation())\n\tsrcLocIndex := computeSourceLocIndex(srcLocProtos)\n\tr.srcLocations = srcLocs{file: r, locs: srcLocProtos, index: srcLocIndex}\n}\n\nfunc (r *result) SourceLocations() protoreflect.SourceLocations {\n\treturn &r.srcLocations\n}\n\nfunc computeSourceLocIndex(locs []protoreflect.SourceLocation) map[interface{}]int {\n\tindex := map[interface{}]int{}\n\tfor i, loc := range locs {\n\t\tif loc.Next == 0 {\n\t\t\tindex[pathKey(loc.Path)] = i\n\t\t}\n\t}\n\treturn index\n}\n\nfunc asSourceLocations(srcInfoProtos []*descriptorpb.SourceCodeInfo_Location) []protoreflect.SourceLocation {\n\tlocs := make([]protoreflect.SourceLocation, len(srcInfoProtos))\n\tprev := map[any]*protoreflect.SourceLocation{}\n\tfor i, loc := range srcInfoProtos {\n\t\tvar stLin, stCol, enLin, enCol int\n\t\tif len(loc.Span) == 3 {\n\t\t\tstLin, stCol, enCol = int(loc.Span[0]), int(loc.Span[1]), int(loc.Span[2])\n\t\t\tenLin = stLin\n\t\t} else {\n\t\t\tstLin, stCol, enLin, enCol = int(loc.Span[0]), int(loc.Span[1]), int(loc.Span[2]), int(loc.Span[3])\n\t\t}\n\t\tlocs[i] = protoreflect.SourceLocation{\n\t\t\tPath:                    loc.Path,\n\t\t\tLeadingComments:         loc.GetLeadingComments(),\n\t\t\tLeadingDetachedComments: loc.GetLeadingDetachedComments(),\n\t\t\tTrailingComments:        loc.GetTrailingComments(),\n\t\t\tStartLine:               stLin,\n\t\t\tStartColumn:             stCol,\n\t\t\tEndLine:                 enLin,\n\t\t\tEndColumn:               enCol,\n\t\t}\n\t\tstr := pathKey(loc.Path)\n\t\tpr := prev[str]\n\t\tif pr != nil {\n\t\t\tpr.Next = i\n\t\t}\n\t\tprev[str] = &locs[i]\n\t}\n\treturn locs\n}\n\ntype fileImports struct {\n\tprotoreflect.FileImports\n\tfiles []protoreflect.FileImport\n}\n\nfunc (r *result) createImports() fileImports {\n\tfd := r.FileDescriptorProto()\n\timps := make([]protoreflect.FileImport, len(fd.Dependency))\n\tfor i, dep := range fd.Dependency {\n\t\tdesc := r.deps.FindFileByPath(dep)\n\t\timps[i] = protoreflect.FileImport{FileDescriptor: unwrap(desc)}\n\t}\n\tfor _, publicIndex := range fd.PublicDependency {\n\t\timps[int(publicIndex)].IsPublic = true\n\t}\n\tfor _, weakIndex := range fd.WeakDependency {\n\t\timps[int(weakIndex)].IsWeak = true\n\t}\n\treturn fileImports{files: imps}\n}\n\nfunc unwrap(descriptor protoreflect.FileDescriptor) protoreflect.FileDescriptor {\n\twrapped, ok := descriptor.(interface {\n\t\tUnwrap() protoreflect.FileDescriptor\n\t})\n\tif !ok {\n\t\treturn descriptor\n\t}\n\tunwrapped := wrapped.Unwrap()\n\tif unwrapped == nil {\n\t\treturn descriptor // shouldn't ever happen\n\t}\n\treturn unwrapped\n}\n\nfunc (f *fileImports) Len() int {\n\treturn len(f.files)\n}\n\nfunc (f *fileImports) Get(i int) protoreflect.FileImport {\n\treturn f.files[i]\n}\n\ntype srcLocs struct {\n\tprotoreflect.SourceLocations\n\tfile  *result\n\tlocs  []protoreflect.SourceLocation\n\tindex map[interface{}]int\n}\n\nfunc (s *srcLocs) Len() int {\n\treturn len(s.locs)\n}\n\nfunc (s *srcLocs) Get(i int) protoreflect.SourceLocation {\n\treturn s.locs[i]\n}\n\nfunc (s *srcLocs) ByPath(p protoreflect.SourcePath) protoreflect.SourceLocation {\n\tindex, ok := s.index[pathKey(p)]\n\tif !ok {\n\t\treturn protoreflect.SourceLocation{}\n\t}\n\treturn s.locs[index]\n}\n\nfunc (s *srcLocs) ByDescriptor(d protoreflect.Descriptor) protoreflect.SourceLocation {\n\tif d.ParentFile() != s.file {\n\t\treturn protoreflect.SourceLocation{}\n\t}\n\tpath, ok := internal.ComputePath(d)\n\tif !ok {\n\t\treturn protoreflect.SourceLocation{}\n\t}\n\treturn s.ByPath(path)\n}\n\ntype msgDescriptors struct {\n\tprotoreflect.MessageDescriptors\n\tmsgs []msgDescriptor\n}\n\nfunc (r *result) createMessages(prefix string, parent protoreflect.Descriptor, msgProtos []*descriptorpb.DescriptorProto, pool *allocPool) msgDescriptors {\n\tmsgs := pool.getMessages(len(msgProtos))\n\tfor i, msgProto := range msgProtos {\n\t\tr.createMessageDescriptor(&msgs[i], msgProto, parent, i, prefix+msgProto.GetName(), pool)\n\t}\n\treturn msgDescriptors{msgs: msgs}\n}\n\nfunc (m *msgDescriptors) Len() int {\n\treturn len(m.msgs)\n}\n\nfunc (m *msgDescriptors) Get(i int) protoreflect.MessageDescriptor {\n\treturn &m.msgs[i]\n}\n\nfunc (m *msgDescriptors) ByName(s protoreflect.Name) protoreflect.MessageDescriptor {\n\tfor i := range m.msgs {\n\t\tmsg := &m.msgs[i]\n\t\tif msg.Name() == s {\n\t\t\treturn msg\n\t\t}\n\t}\n\treturn nil\n}\n\ntype msgDescriptor struct {\n\tprotoreflect.MessageDescriptor\n\tfile   *result\n\tparent protoreflect.Descriptor\n\tindex  int\n\tproto  *descriptorpb.DescriptorProto\n\tfqn    string\n\n\tfields           fldDescriptors\n\toneofs           oneofDescriptors\n\tnestedMessages   msgDescriptors\n\tnestedEnums      enumDescriptors\n\tnestedExtensions extDescriptors\n\n\textRanges  fieldRanges\n\trsvdRanges fieldRanges\n\trsvdNames  names\n}\n\nvar _ protoreflect.MessageDescriptor = (*msgDescriptor)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*msgDescriptor)(nil)\n\nfunc (r *result) createMessageDescriptor(ret *msgDescriptor, md *descriptorpb.DescriptorProto, parent protoreflect.Descriptor, index int, fqn string, pool *allocPool) {\n\tr.descriptors[fqn] = ret\n\n\tret.MessageDescriptor = noOpMessage\n\tret.file = r\n\tret.parent = parent\n\tret.index = index\n\tret.proto = md\n\tret.fqn = fqn\n\n\tprefix := fqn + \".\"\n\t// NB: We MUST create fields before oneofs so that we can populate the\n\t//  set of fields that belong to the oneof\n\tret.fields = r.createFields(prefix, ret, md.Field, pool)\n\tret.oneofs = r.createOneofs(prefix, ret, md.OneofDecl, pool)\n\tret.nestedMessages = r.createMessages(prefix, ret, md.NestedType, pool)\n\tret.nestedEnums = r.createEnums(prefix, ret, md.EnumType, pool)\n\tret.nestedExtensions = r.createExtensions(prefix, ret, md.Extension, pool)\n\tret.extRanges = createFieldRanges(md.ExtensionRange)\n\tret.rsvdRanges = createFieldRanges(md.ReservedRange)\n\tret.rsvdNames = names{s: md.ReservedName}\n}\n\nfunc (m *msgDescriptor) MessageDescriptorProto() *descriptorpb.DescriptorProto {\n\treturn m.proto\n}\n\nfunc (m *msgDescriptor) AsProto() proto.Message {\n\treturn m.proto\n}\n\nfunc (m *msgDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn m.file\n}\n\nfunc (m *msgDescriptor) Parent() protoreflect.Descriptor {\n\treturn m.parent\n}\n\nfunc (m *msgDescriptor) Index() int {\n\treturn m.index\n}\n\nfunc (m *msgDescriptor) Syntax() protoreflect.Syntax {\n\treturn m.file.Syntax()\n}\n\nfunc (m *msgDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(m.proto.GetName())\n}\n\nfunc (m *msgDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(m.fqn)\n}\n\nfunc (m *msgDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (m *msgDescriptor) Options() protoreflect.ProtoMessage {\n\treturn m.proto.Options\n}\n\nfunc (m *msgDescriptor) IsMapEntry() bool {\n\treturn m.proto.Options.GetMapEntry()\n}\n\nfunc (m *msgDescriptor) Fields() protoreflect.FieldDescriptors {\n\treturn &m.fields\n}\n\nfunc (m *msgDescriptor) Oneofs() protoreflect.OneofDescriptors {\n\treturn &m.oneofs\n}\n\nfunc (m *msgDescriptor) ReservedNames() protoreflect.Names {\n\treturn m.rsvdNames\n}\n\nfunc (m *msgDescriptor) ReservedRanges() protoreflect.FieldRanges {\n\treturn m.rsvdRanges\n}\n\nfunc (m *msgDescriptor) RequiredNumbers() protoreflect.FieldNumbers {\n\tvar indexes fieldNums\n\tfor _, fld := range m.proto.Field {\n\t\tif fld.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REQUIRED {\n\t\t\tindexes.s = append(indexes.s, fld.GetNumber())\n\t\t}\n\t}\n\treturn indexes\n}\n\nfunc (m *msgDescriptor) ExtensionRanges() protoreflect.FieldRanges {\n\treturn m.extRanges\n}\n\nfunc (m *msgDescriptor) ExtensionRangeOptions(i int) protoreflect.ProtoMessage {\n\treturn m.proto.ExtensionRange[i].Options\n}\n\nfunc (m *msgDescriptor) Enums() protoreflect.EnumDescriptors {\n\treturn &m.nestedEnums\n}\n\nfunc (m *msgDescriptor) Messages() protoreflect.MessageDescriptors {\n\treturn &m.nestedMessages\n}\n\nfunc (m *msgDescriptor) Extensions() protoreflect.ExtensionDescriptors {\n\treturn &m.nestedExtensions\n}\n\ntype names struct {\n\tprotoreflect.Names\n\ts []string\n}\n\nfunc (n names) Len() int {\n\treturn len(n.s)\n}\n\nfunc (n names) Get(i int) protoreflect.Name {\n\treturn protoreflect.Name(n.s[i])\n}\n\nfunc (n names) Has(s protoreflect.Name) bool {\n\tfor _, name := range n.s {\n\t\tif name == string(s) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype fieldNums struct {\n\tprotoreflect.FieldNumbers\n\ts []int32\n}\n\nfunc (n fieldNums) Len() int {\n\treturn len(n.s)\n}\n\nfunc (n fieldNums) Get(i int) protoreflect.FieldNumber {\n\treturn protoreflect.FieldNumber(n.s[i])\n}\n\nfunc (n fieldNums) Has(s protoreflect.FieldNumber) bool {\n\tfor _, num := range n.s {\n\t\tif num == int32(s) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype fieldRanges struct {\n\tprotoreflect.FieldRanges\n\tranges [][2]protoreflect.FieldNumber\n}\n\ntype fieldRange interface {\n\tGetStart() int32\n\tGetEnd() int32\n}\n\nfunc createFieldRanges[T fieldRange](rangeProtos []T) fieldRanges {\n\tranges := make([][2]protoreflect.FieldNumber, len(rangeProtos))\n\tfor i, r := range rangeProtos {\n\t\tranges[i] = [2]protoreflect.FieldNumber{\n\t\t\tprotoreflect.FieldNumber(r.GetStart()),\n\t\t\tprotoreflect.FieldNumber(r.GetEnd()),\n\t\t}\n\t}\n\treturn fieldRanges{ranges: ranges}\n}\n\nfunc (f fieldRanges) Len() int {\n\treturn len(f.ranges)\n}\n\nfunc (f fieldRanges) Get(i int) [2]protoreflect.FieldNumber {\n\treturn f.ranges[i]\n}\n\nfunc (f fieldRanges) Has(n protoreflect.FieldNumber) bool {\n\tfor _, r := range f.ranges {\n\t\tif r[0] <= n && r[1] > n {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype enumDescriptors struct {\n\tprotoreflect.EnumDescriptors\n\tenums []enumDescriptor\n}\n\nfunc (r *result) createEnums(prefix string, parent protoreflect.Descriptor, enumProtos []*descriptorpb.EnumDescriptorProto, pool *allocPool) enumDescriptors {\n\tenums := pool.getEnums(len(enumProtos))\n\tfor i, enumProto := range enumProtos {\n\t\tr.createEnumDescriptor(&enums[i], enumProto, parent, i, prefix+enumProto.GetName(), pool)\n\t}\n\treturn enumDescriptors{enums: enums}\n}\n\nfunc (e *enumDescriptors) Len() int {\n\treturn len(e.enums)\n}\n\nfunc (e *enumDescriptors) Get(i int) protoreflect.EnumDescriptor {\n\treturn &e.enums[i]\n}\n\nfunc (e *enumDescriptors) ByName(s protoreflect.Name) protoreflect.EnumDescriptor {\n\tfor i := range e.enums {\n\t\tenum := &e.enums[i]\n\t\tif enum.Name() == s {\n\t\t\treturn enum\n\t\t}\n\t}\n\treturn nil\n}\n\ntype enumDescriptor struct {\n\tprotoreflect.EnumDescriptor\n\tfile   *result\n\tparent protoreflect.Descriptor\n\tindex  int\n\tproto  *descriptorpb.EnumDescriptorProto\n\tfqn    string\n\n\tvalues enValDescriptors\n\n\trsvdRanges enumRanges\n\trsvdNames  names\n}\n\nvar _ protoreflect.EnumDescriptor = (*enumDescriptor)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*enumDescriptor)(nil)\n\nfunc (r *result) createEnumDescriptor(ret *enumDescriptor, ed *descriptorpb.EnumDescriptorProto, parent protoreflect.Descriptor, index int, fqn string, pool *allocPool) {\n\tr.descriptors[fqn] = ret\n\n\tret.EnumDescriptor = noOpEnum\n\tret.file = r\n\tret.parent = parent\n\tret.index = index\n\tret.proto = ed\n\tret.fqn = fqn\n\n\t// Unlike all other elements, the fully-qualified names of enum values\n\t// are NOT scoped to their parent element (the enum), but rather to\n\t// the enum's parent element. This follows C++ scoping rules for\n\t// enum values.\n\tprefix := strings.TrimSuffix(fqn, ed.GetName())\n\tret.values = r.createEnumValues(prefix, ret, ed.Value, pool)\n\tret.rsvdRanges = createEnumRanges(ed.ReservedRange)\n\tret.rsvdNames = names{s: ed.ReservedName}\n}\n\nfunc (e *enumDescriptor) EnumDescriptorProto() *descriptorpb.EnumDescriptorProto {\n\treturn e.proto\n}\n\nfunc (e *enumDescriptor) AsProto() proto.Message {\n\treturn e.proto\n}\n\nfunc (e *enumDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn e.file\n}\n\nfunc (e *enumDescriptor) Parent() protoreflect.Descriptor {\n\treturn e.parent\n}\n\nfunc (e *enumDescriptor) Index() int {\n\treturn e.index\n}\n\nfunc (e *enumDescriptor) Syntax() protoreflect.Syntax {\n\treturn e.file.Syntax()\n}\n\nfunc (e *enumDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(e.proto.GetName())\n}\n\nfunc (e *enumDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(e.fqn)\n}\n\nfunc (e *enumDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (e *enumDescriptor) Options() protoreflect.ProtoMessage {\n\treturn e.proto.Options\n}\n\nfunc (e *enumDescriptor) Values() protoreflect.EnumValueDescriptors {\n\treturn &e.values\n}\n\nfunc (e *enumDescriptor) ReservedNames() protoreflect.Names {\n\treturn e.rsvdNames\n}\n\nfunc (e *enumDescriptor) ReservedRanges() protoreflect.EnumRanges {\n\treturn e.rsvdRanges\n}\n\nfunc (e *enumDescriptor) IsClosed() bool {\n\tenumType := resolveFeature(e, enumTypeField)\n\treturn descriptorpb.FeatureSet_EnumType(enumType.Enum()) == descriptorpb.FeatureSet_CLOSED\n}\n\ntype enumRanges struct {\n\tprotoreflect.EnumRanges\n\tranges [][2]protoreflect.EnumNumber\n}\n\nfunc createEnumRanges(rangeProtos []*descriptorpb.EnumDescriptorProto_EnumReservedRange) enumRanges {\n\tranges := make([][2]protoreflect.EnumNumber, len(rangeProtos))\n\tfor i, r := range rangeProtos {\n\t\tranges[i] = [2]protoreflect.EnumNumber{\n\t\t\tprotoreflect.EnumNumber(r.GetStart()),\n\t\t\tprotoreflect.EnumNumber(r.GetEnd()),\n\t\t}\n\t}\n\treturn enumRanges{ranges: ranges}\n}\n\nfunc (e enumRanges) Len() int {\n\treturn len(e.ranges)\n}\n\nfunc (e enumRanges) Get(i int) [2]protoreflect.EnumNumber {\n\treturn e.ranges[i]\n}\n\nfunc (e enumRanges) Has(n protoreflect.EnumNumber) bool {\n\tfor _, r := range e.ranges {\n\t\tif r[0] <= n && r[1] >= n {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\ntype enValDescriptors struct {\n\tprotoreflect.EnumValueDescriptors\n\tvals []enValDescriptor\n}\n\nfunc (r *result) createEnumValues(prefix string, parent *enumDescriptor, enValProtos []*descriptorpb.EnumValueDescriptorProto, pool *allocPool) enValDescriptors {\n\tvals := pool.getEnumValues(len(enValProtos))\n\tfor i, enValProto := range enValProtos {\n\t\tr.createEnumValueDescriptor(&vals[i], enValProto, parent, i, prefix+enValProto.GetName())\n\t}\n\treturn enValDescriptors{vals: vals}\n}\n\nfunc (e *enValDescriptors) Len() int {\n\treturn len(e.vals)\n}\n\nfunc (e *enValDescriptors) Get(i int) protoreflect.EnumValueDescriptor {\n\treturn &e.vals[i]\n}\n\nfunc (e *enValDescriptors) ByName(s protoreflect.Name) protoreflect.EnumValueDescriptor {\n\tfor i := range e.vals {\n\t\tval := &e.vals[i]\n\t\tif val.Name() == s {\n\t\t\treturn val\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (e *enValDescriptors) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor {\n\tfor i := range e.vals {\n\t\tval := &e.vals[i]\n\t\tif val.Number() == n {\n\t\t\treturn val\n\t\t}\n\t}\n\treturn nil\n}\n\ntype enValDescriptor struct {\n\tprotoreflect.EnumValueDescriptor\n\tfile   *result\n\tparent *enumDescriptor\n\tindex  int\n\tproto  *descriptorpb.EnumValueDescriptorProto\n\tfqn    string\n}\n\nvar _ protoreflect.EnumValueDescriptor = (*enValDescriptor)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*enValDescriptor)(nil)\n\nfunc (r *result) createEnumValueDescriptor(ret *enValDescriptor, ed *descriptorpb.EnumValueDescriptorProto, parent *enumDescriptor, index int, fqn string) {\n\tr.descriptors[fqn] = ret\n\tret.EnumValueDescriptor = noOpEnumValue\n\tret.file = r\n\tret.parent = parent\n\tret.index = index\n\tret.proto = ed\n\tret.fqn = fqn\n}\n\nfunc (e *enValDescriptor) EnumValueDescriptorProto() *descriptorpb.EnumValueDescriptorProto {\n\treturn e.proto\n}\n\nfunc (e *enValDescriptor) AsProto() proto.Message {\n\treturn e.proto\n}\n\nfunc (e *enValDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn e.file\n}\n\nfunc (e *enValDescriptor) Parent() protoreflect.Descriptor {\n\treturn e.parent\n}\n\nfunc (e *enValDescriptor) Index() int {\n\treturn e.index\n}\n\nfunc (e *enValDescriptor) Syntax() protoreflect.Syntax {\n\treturn e.file.Syntax()\n}\n\nfunc (e *enValDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(e.proto.GetName())\n}\n\nfunc (e *enValDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(e.fqn)\n}\n\nfunc (e *enValDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (e *enValDescriptor) Options() protoreflect.ProtoMessage {\n\treturn e.proto.Options\n}\n\nfunc (e *enValDescriptor) Number() protoreflect.EnumNumber {\n\treturn protoreflect.EnumNumber(e.proto.GetNumber())\n}\n\ntype extDescriptors struct {\n\tprotoreflect.ExtensionDescriptors\n\texts []extTypeDescriptor\n}\n\nfunc (r *result) createExtensions(prefix string, parent protoreflect.Descriptor, extProtos []*descriptorpb.FieldDescriptorProto, pool *allocPool) extDescriptors {\n\texts := pool.getExtensions(len(extProtos))\n\tfor i, extProto := range extProtos {\n\t\tr.createExtTypeDescriptor(&exts[i], extProto, parent, i, prefix+extProto.GetName())\n\t}\n\treturn extDescriptors{exts: exts}\n}\n\nfunc (e *extDescriptors) Len() int {\n\treturn len(e.exts)\n}\n\nfunc (e *extDescriptors) Get(i int) protoreflect.ExtensionDescriptor {\n\treturn &e.exts[i]\n}\n\nfunc (e *extDescriptors) ByName(s protoreflect.Name) protoreflect.ExtensionDescriptor {\n\tfor i := range e.exts {\n\t\text := &e.exts[i]\n\t\tif ext.Name() == s {\n\t\t\treturn ext\n\t\t}\n\t}\n\treturn nil\n}\n\ntype extTypeDescriptor struct {\n\tprotoreflect.ExtensionTypeDescriptor\n\tfield fldDescriptor\n}\n\nvar _ protoutil.DescriptorProtoWrapper = &extTypeDescriptor{}\n\nfunc (r *result) createExtTypeDescriptor(ret *extTypeDescriptor, fd *descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, index int, fqn string) {\n\tr.descriptors[fqn] = ret\n\tret.field = fldDescriptor{FieldDescriptor: noOpExtension, file: r, parent: parent, index: index, proto: fd, fqn: fqn}\n\tret.ExtensionTypeDescriptor = dynamicpb.NewExtensionType(&ret.field).TypeDescriptor()\n}\n\nfunc (e *extTypeDescriptor) FieldDescriptorProto() *descriptorpb.FieldDescriptorProto {\n\treturn e.field.proto\n}\n\nfunc (e *extTypeDescriptor) AsProto() proto.Message {\n\treturn e.field.proto\n}\n\ntype fldDescriptors struct {\n\tprotoreflect.FieldDescriptors\n\t// We use pointers here, instead of flattened slice, because oneofs\n\t// also have fields, but need to point to values in the parent\n\t// message's fields. Even though they are pointers, in the containing\n\t// message, we always allocate a flattened slice and then point into\n\t// that, so we're still doing fewer allocations (2 per set of fields\n\t// instead of 1 per each field).\n\tfields []*fldDescriptor\n}\n\nfunc (r *result) createFields(prefix string, parent *msgDescriptor, fldProtos []*descriptorpb.FieldDescriptorProto, pool *allocPool) fldDescriptors {\n\tfields := pool.getFields(len(fldProtos))\n\tfieldPtrs := make([]*fldDescriptor, len(fldProtos))\n\tfor i, fldProto := range fldProtos {\n\t\tr.createFieldDescriptor(&fields[i], fldProto, parent, i, prefix+fldProto.GetName())\n\t\tfieldPtrs[i] = &fields[i]\n\t}\n\treturn fldDescriptors{fields: fieldPtrs}\n}\n\nfunc (f *fldDescriptors) Len() int {\n\treturn len(f.fields)\n}\n\nfunc (f *fldDescriptors) Get(i int) protoreflect.FieldDescriptor {\n\treturn f.fields[i]\n}\n\nfunc (f *fldDescriptors) ByName(s protoreflect.Name) protoreflect.FieldDescriptor {\n\tfor _, fld := range f.fields {\n\t\tif fld.Name() == s {\n\t\t\treturn fld\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (f *fldDescriptors) ByJSONName(s string) protoreflect.FieldDescriptor {\n\tfor _, fld := range f.fields {\n\t\tif fld.JSONName() == s {\n\t\t\treturn fld\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (f *fldDescriptors) ByTextName(s string) protoreflect.FieldDescriptor {\n\tfld := f.ByName(protoreflect.Name(s))\n\tif fld != nil {\n\t\treturn fld\n\t}\n\t// Groups use type name instead, so we fallback to slow search\n\tfor _, fld := range f.fields {\n\t\tif fld.TextName() == s {\n\t\t\treturn fld\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (f *fldDescriptors) ByNumber(n protoreflect.FieldNumber) protoreflect.FieldDescriptor {\n\tfor _, fld := range f.fields {\n\t\tif fld.Number() == n {\n\t\t\treturn fld\n\t\t}\n\t}\n\treturn nil\n}\n\ntype fldDescriptor struct {\n\tprotoreflect.FieldDescriptor\n\tfile   *result\n\tparent protoreflect.Descriptor\n\tindex  int\n\tproto  *descriptorpb.FieldDescriptorProto\n\tfqn    string\n\n\tmsgType  protoreflect.MessageDescriptor\n\textendee protoreflect.MessageDescriptor\n\tenumType protoreflect.EnumDescriptor\n\toneof    protoreflect.OneofDescriptor\n}\n\nvar _ protoreflect.FieldDescriptor = (*fldDescriptor)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*fldDescriptor)(nil)\n\nfunc (r *result) createFieldDescriptor(ret *fldDescriptor, fd *descriptorpb.FieldDescriptorProto, parent *msgDescriptor, index int, fqn string) {\n\tr.descriptors[fqn] = ret\n\tret.FieldDescriptor = noOpField\n\tret.file = r\n\tret.parent = parent\n\tret.index = index\n\tret.proto = fd\n\tret.fqn = fqn\n}\n\nfunc (f *fldDescriptor) FieldDescriptorProto() *descriptorpb.FieldDescriptorProto {\n\treturn f.proto\n}\n\nfunc (f *fldDescriptor) AsProto() proto.Message {\n\treturn f.proto\n}\n\nfunc (f *fldDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn f.file\n}\n\nfunc (f *fldDescriptor) Parent() protoreflect.Descriptor {\n\treturn f.parent\n}\n\nfunc (f *fldDescriptor) Index() int {\n\treturn f.index\n}\n\nfunc (f *fldDescriptor) Syntax() protoreflect.Syntax {\n\treturn f.file.Syntax()\n}\n\nfunc (f *fldDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(f.proto.GetName())\n}\n\nfunc (f *fldDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(f.fqn)\n}\n\nfunc (f *fldDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (f *fldDescriptor) Options() protoreflect.ProtoMessage {\n\treturn f.proto.Options\n}\n\nfunc (f *fldDescriptor) Number() protoreflect.FieldNumber {\n\treturn protoreflect.FieldNumber(f.proto.GetNumber())\n}\n\nfunc (f *fldDescriptor) Cardinality() protoreflect.Cardinality {\n\tswitch f.proto.GetLabel() {\n\tcase descriptorpb.FieldDescriptorProto_LABEL_REPEATED:\n\t\treturn protoreflect.Repeated\n\tcase descriptorpb.FieldDescriptorProto_LABEL_REQUIRED:\n\t\treturn protoreflect.Required\n\tcase descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL:\n\t\tif f.Syntax() == protoreflect.Editions {\n\t\t\t// Editions does not use label to indicate required. It instead\n\t\t\t// uses a feature, and label is always optional.\n\t\t\tfieldPresence := descriptorpb.FeatureSet_FieldPresence(resolveFeature(f, fieldPresenceField).Enum())\n\t\t\tif fieldPresence == descriptorpb.FeatureSet_LEGACY_REQUIRED {\n\t\t\t\treturn protoreflect.Required\n\t\t\t}\n\t\t}\n\t\treturn protoreflect.Optional\n\tdefault:\n\t\treturn 0\n\t}\n}\n\nfunc (f *fldDescriptor) Kind() protoreflect.Kind {\n\tif f.proto.GetType() == descriptorpb.FieldDescriptorProto_TYPE_MESSAGE && f.Syntax() == protoreflect.Editions &&\n\t\t!f.IsMap() && !f.parentIsMap() {\n\t\t// In editions, \"group encoding\" (aka \"delimited encoding\") is toggled\n\t\t// via a feature. So we report group kind when that feature is enabled.\n\t\tmessageEncoding := resolveFeature(f, messageEncodingField)\n\t\tif descriptorpb.FeatureSet_MessageEncoding(messageEncoding.Enum()) == descriptorpb.FeatureSet_DELIMITED {\n\t\t\treturn protoreflect.GroupKind\n\t\t}\n\t}\n\treturn protoreflect.Kind(f.proto.GetType())\n}\n\nfunc (f *fldDescriptor) HasJSONName() bool {\n\treturn f.proto.JsonName != nil\n}\n\nfunc (f *fldDescriptor) JSONName() string {\n\tif f.IsExtension() {\n\t\treturn f.TextName()\n\t}\n\treturn f.proto.GetJsonName()\n}\n\nfunc (f *fldDescriptor) TextName() string {\n\tif f.IsExtension() {\n\t\treturn fmt.Sprintf(\"[%s]\", f.FullName())\n\t}\n\tif f.looksLikeGroup() {\n\t\t// groups use the type name\n\t\treturn string(protoreflect.FullName(f.proto.GetTypeName()).Name())\n\t}\n\treturn string(f.Name())\n}\n\nfunc (f *fldDescriptor) looksLikeGroup() bool {\n\t// It looks like a group if it uses group/delimited encoding (checked via f.Kind)\n\t// and the message type is a sibling whose name is a mixed-case version of the field name.\n\treturn f.Kind() == protoreflect.GroupKind &&\n\t\tf.Message().FullName().Parent() == f.FullName().Parent() &&\n\t\tstring(f.Name()) == strings.ToLower(string(f.Message().Name()))\n}\n\nfunc (f *fldDescriptor) HasPresence() bool {\n\tif f.proto.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED {\n\t\treturn false\n\t}\n\tif f.IsExtension() ||\n\t\tf.Kind() == protoreflect.MessageKind || f.Kind() == protoreflect.GroupKind ||\n\t\tf.proto.OneofIndex != nil {\n\t\treturn true\n\t}\n\tfieldPresence := descriptorpb.FeatureSet_FieldPresence(resolveFeature(f, fieldPresenceField).Enum())\n\treturn fieldPresence == descriptorpb.FeatureSet_EXPLICIT || fieldPresence == descriptorpb.FeatureSet_LEGACY_REQUIRED\n}\n\nfunc (f *fldDescriptor) IsExtension() bool {\n\treturn f.proto.GetExtendee() != \"\"\n}\n\nfunc (f *fldDescriptor) HasOptionalKeyword() bool {\n\tif f.proto.GetLabel() != descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL {\n\t\treturn false\n\t}\n\tif f.proto.GetProto3Optional() {\n\t\t// NB: This smells weird to return false here. If the proto3_optional field\n\t\t// is set, it's because the keyword WAS present. However, the Go runtime\n\t\t// returns false for this case, so we mirror that behavior.\n\t\treturn !f.IsExtension()\n\t}\n\t// If it's optional, but not a proto3 optional, then the keyword is only\n\t// present for proto2 files, for fields that are not part of a oneof.\n\treturn f.file.Syntax() == protoreflect.Proto2 && f.proto.OneofIndex == nil\n}\n\nfunc (f *fldDescriptor) IsWeak() bool {\n\treturn f.proto.Options.GetWeak()\n}\n\nfunc (f *fldDescriptor) IsPacked() bool {\n\tif f.Cardinality() != protoreflect.Repeated || !internal.CanPack(f.Kind()) {\n\t\treturn false\n\t}\n\topts := f.proto.GetOptions()\n\tif opts != nil && opts.Packed != nil {\n\t\t// packed option is set explicitly\n\t\treturn *opts.Packed\n\t}\n\tfieldEncoding := resolveFeature(f, repeatedFieldEncodingField)\n\treturn descriptorpb.FeatureSet_RepeatedFieldEncoding(fieldEncoding.Enum()) == descriptorpb.FeatureSet_PACKED\n}\n\nfunc (f *fldDescriptor) IsList() bool {\n\tif f.proto.GetLabel() != descriptorpb.FieldDescriptorProto_LABEL_REPEATED {\n\t\treturn false\n\t}\n\treturn !f.isMapEntry()\n}\n\nfunc (f *fldDescriptor) IsMap() bool {\n\tif f.proto.GetLabel() != descriptorpb.FieldDescriptorProto_LABEL_REPEATED {\n\t\treturn false\n\t}\n\tif f.IsExtension() {\n\t\treturn false\n\t}\n\treturn f.isMapEntry()\n}\n\nfunc (f *fldDescriptor) isMapEntry() bool {\n\tif f.proto.GetType() != descriptorpb.FieldDescriptorProto_TYPE_MESSAGE {\n\t\treturn false\n\t}\n\treturn f.Message().IsMapEntry()\n}\n\nfunc (f *fldDescriptor) parentIsMap() bool {\n\tparent, ok := f.parent.(protoreflect.MessageDescriptor)\n\treturn ok && parent.IsMapEntry()\n}\n\nfunc (f *fldDescriptor) MapKey() protoreflect.FieldDescriptor {\n\tif !f.IsMap() {\n\t\treturn nil\n\t}\n\treturn f.Message().Fields().ByNumber(1)\n}\n\nfunc (f *fldDescriptor) MapValue() protoreflect.FieldDescriptor {\n\tif !f.IsMap() {\n\t\treturn nil\n\t}\n\treturn f.Message().Fields().ByNumber(2)\n}\n\nfunc (f *fldDescriptor) HasDefault() bool {\n\treturn f.proto.DefaultValue != nil\n}\n\nfunc (f *fldDescriptor) Default() protoreflect.Value {\n\t// We only return a valid value for scalar fields\n\tif f.proto.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED ||\n\t\tf.Kind() == protoreflect.GroupKind || f.Kind() == protoreflect.MessageKind {\n\t\treturn protoreflect.Value{}\n\t}\n\n\tif f.proto.DefaultValue != nil {\n\t\tdefVal := f.parseDefaultValue(f.proto.GetDefaultValue())\n\t\tif defVal.IsValid() {\n\t\t\treturn defVal\n\t\t}\n\t\t// if we cannot parse a valid value, fall back to zero value below\n\t}\n\n\t// No custom default value, so return the zero value for the type\n\tswitch f.Kind() {\n\tcase protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:\n\t\treturn protoreflect.ValueOfInt32(0)\n\tcase protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:\n\t\treturn protoreflect.ValueOfInt64(0)\n\tcase protoreflect.Uint32Kind, protoreflect.Fixed32Kind:\n\t\treturn protoreflect.ValueOfUint32(0)\n\tcase protoreflect.Uint64Kind, protoreflect.Fixed64Kind:\n\t\treturn protoreflect.ValueOfUint64(0)\n\tcase protoreflect.FloatKind:\n\t\treturn protoreflect.ValueOfFloat32(0)\n\tcase protoreflect.DoubleKind:\n\t\treturn protoreflect.ValueOfFloat64(0)\n\tcase protoreflect.BoolKind:\n\t\treturn protoreflect.ValueOfBool(false)\n\tcase protoreflect.BytesKind:\n\t\treturn protoreflect.ValueOfBytes(nil)\n\tcase protoreflect.StringKind:\n\t\treturn protoreflect.ValueOfString(\"\")\n\tcase protoreflect.EnumKind:\n\t\treturn protoreflect.ValueOfEnum(f.Enum().Values().Get(0).Number())\n\tcase protoreflect.GroupKind, protoreflect.MessageKind:\n\t\treturn protoreflect.ValueOfMessage(dynamicpb.NewMessage(f.Message()))\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unknown kind: %v\", f.Kind()))\n\t}\n}\n\nfunc (f *fldDescriptor) parseDefaultValue(val string) protoreflect.Value {\n\tswitch f.Kind() {\n\tcase protoreflect.EnumKind:\n\t\tvd := f.Enum().Values().ByName(protoreflect.Name(val))\n\t\tif vd != nil {\n\t\t\treturn protoreflect.ValueOfEnum(vd.Number())\n\t\t}\n\t\treturn protoreflect.Value{}\n\tcase protoreflect.BoolKind:\n\t\tswitch val {\n\t\tcase \"true\":\n\t\t\treturn protoreflect.ValueOfBool(true)\n\t\tcase \"false\":\n\t\t\treturn protoreflect.ValueOfBool(false)\n\t\tdefault:\n\t\t\treturn protoreflect.Value{}\n\t\t}\n\tcase protoreflect.BytesKind:\n\t\treturn protoreflect.ValueOfBytes([]byte(unescape(val)))\n\tcase protoreflect.StringKind:\n\t\treturn protoreflect.ValueOfString(val)\n\tcase protoreflect.FloatKind:\n\t\tif f, err := strconv.ParseFloat(val, 32); err == nil {\n\t\t\treturn protoreflect.ValueOfFloat32(float32(f))\n\t\t}\n\t\treturn protoreflect.Value{}\n\tcase protoreflect.DoubleKind:\n\t\tif f, err := strconv.ParseFloat(val, 64); err == nil {\n\t\t\treturn protoreflect.ValueOfFloat64(f)\n\t\t}\n\t\treturn protoreflect.Value{}\n\tcase protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:\n\t\tif i, err := strconv.ParseInt(val, 10, 32); err == nil {\n\t\t\treturn protoreflect.ValueOfInt32(int32(i))\n\t\t}\n\t\treturn protoreflect.Value{}\n\tcase protoreflect.Uint32Kind, protoreflect.Fixed32Kind:\n\t\tif i, err := strconv.ParseUint(val, 10, 32); err == nil {\n\t\t\treturn protoreflect.ValueOfUint32(uint32(i))\n\t\t}\n\t\treturn protoreflect.Value{}\n\tcase protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:\n\t\tif i, err := strconv.ParseInt(val, 10, 64); err == nil {\n\t\t\treturn protoreflect.ValueOfInt64(i)\n\t\t}\n\t\treturn protoreflect.Value{}\n\tcase protoreflect.Uint64Kind, protoreflect.Fixed64Kind:\n\t\tif i, err := strconv.ParseUint(val, 10, 64); err == nil {\n\t\t\treturn protoreflect.ValueOfUint64(i)\n\t\t}\n\t\treturn protoreflect.Value{}\n\tdefault:\n\t\treturn protoreflect.Value{}\n\t}\n}\n\nfunc unescape(s string) string {\n\t// protoc encodes default values for 'bytes' fields using C escaping,\n\t// so this function reverses that escaping\n\tout := make([]byte, 0, len(s))\n\tvar buf [4]byte\n\tfor len(s) > 0 {\n\t\tif s[0] != '\\\\' || len(s) < 2 {\n\t\t\t// not escape sequence, or too short to be well-formed escape\n\t\t\tout = append(out, s[0])\n\t\t\ts = s[1:]\n\t\t\tcontinue\n\t\t}\n\t\tnextIndex := 2 // by default, skip '\\' + escaped character\n\t\tswitch s[1] {\n\t\tcase 'x', 'X':\n\t\t\tn := matchPrefix(s[2:], 2, isHex)\n\t\t\tif n == 0 {\n\t\t\t\t// bad escape\n\t\t\t\tout = append(out, s[:2]...)\n\t\t\t} else {\n\t\t\t\tc, err := strconv.ParseUint(s[2:2+n], 16, 8)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// shouldn't really happen...\n\t\t\t\t\tout = append(out, s[:2+n]...)\n\t\t\t\t} else {\n\t\t\t\t\tout = append(out, byte(c))\n\t\t\t\t}\n\t\t\t\tnextIndex = 2 + n\n\t\t\t}\n\t\tcase '0', '1', '2', '3', '4', '5', '6', '7':\n\t\t\tn := 1 + matchPrefix(s[2:], 2, isOctal)\n\t\t\tc, err := strconv.ParseUint(s[1:1+n], 8, 8)\n\t\t\tif err != nil || c > 0xff {\n\t\t\t\tout = append(out, s[:1+n]...)\n\t\t\t} else {\n\t\t\t\tout = append(out, byte(c))\n\t\t\t}\n\t\t\tnextIndex = 1 + n\n\t\tcase 'u':\n\t\t\tif len(s) < 6 {\n\t\t\t\t// bad escape\n\t\t\t\tout = append(out, s...)\n\t\t\t\tnextIndex = len(s)\n\t\t\t} else {\n\t\t\t\tc, err := strconv.ParseUint(s[2:6], 16, 16)\n\t\t\t\tif err != nil {\n\t\t\t\t\t// bad escape\n\t\t\t\t\tout = append(out, s[:6]...)\n\t\t\t\t} else {\n\t\t\t\t\tw := utf8.EncodeRune(buf[:], rune(c))\n\t\t\t\t\tout = append(out, buf[:w]...)\n\t\t\t\t}\n\t\t\t\tnextIndex = 6\n\t\t\t}\n\t\tcase 'U':\n\t\t\tif len(s) < 10 {\n\t\t\t\t// bad escape\n\t\t\t\tout = append(out, s...)\n\t\t\t\tnextIndex = len(s)\n\t\t\t} else {\n\t\t\t\tc, err := strconv.ParseUint(s[2:10], 16, 32)\n\t\t\t\tif err != nil || c > 0x10ffff {\n\t\t\t\t\t// bad escape\n\t\t\t\t\tout = append(out, s[:10]...)\n\t\t\t\t} else {\n\t\t\t\t\tw := utf8.EncodeRune(buf[:], rune(c))\n\t\t\t\t\tout = append(out, buf[:w]...)\n\t\t\t\t}\n\t\t\t\tnextIndex = 10\n\t\t\t}\n\t\tcase 'a':\n\t\t\tout = append(out, '\\a')\n\t\tcase 'b':\n\t\t\tout = append(out, '\\b')\n\t\tcase 'f':\n\t\t\tout = append(out, '\\f')\n\t\tcase 'n':\n\t\t\tout = append(out, '\\n')\n\t\tcase 'r':\n\t\t\tout = append(out, '\\r')\n\t\tcase 't':\n\t\t\tout = append(out, '\\t')\n\t\tcase 'v':\n\t\t\tout = append(out, '\\v')\n\t\tcase '\\\\', '\\'', '\"', '?':\n\t\t\tout = append(out, s[1])\n\t\tdefault:\n\t\t\t// invalid escape, just copy it as-is\n\t\t\tout = append(out, s[:2]...)\n\t\t}\n\t\ts = s[nextIndex:]\n\t}\n\treturn string(out)\n}\n\nfunc isOctal(b byte) bool { return b >= '0' && b <= '7' }\nfunc isHex(b byte) bool {\n\treturn (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')\n}\nfunc matchPrefix(s string, limit int, fn func(byte) bool) int {\n\tl := len(s)\n\tif l > limit {\n\t\tl = limit\n\t}\n\ti := 0\n\tfor ; i < l; i++ {\n\t\tif !fn(s[i]) {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn i\n}\n\nfunc (f *fldDescriptor) DefaultEnumValue() protoreflect.EnumValueDescriptor {\n\ted := f.Enum()\n\tif ed == nil {\n\t\treturn nil\n\t}\n\tif f.proto.DefaultValue != nil {\n\t\tif val := ed.Values().ByName(protoreflect.Name(f.proto.GetDefaultValue())); val != nil {\n\t\t\treturn val\n\t\t}\n\t}\n\t// if no default specified in source, return nil\n\treturn nil\n}\n\nfunc (f *fldDescriptor) ContainingOneof() protoreflect.OneofDescriptor {\n\treturn f.oneof\n}\n\nfunc (f *fldDescriptor) ContainingMessage() protoreflect.MessageDescriptor {\n\tif f.extendee != nil {\n\t\treturn f.extendee\n\t}\n\treturn f.parent.(protoreflect.MessageDescriptor)\n}\n\nfunc (f *fldDescriptor) Enum() protoreflect.EnumDescriptor {\n\treturn f.enumType\n}\n\nfunc (f *fldDescriptor) Message() protoreflect.MessageDescriptor {\n\treturn f.msgType\n}\n\ntype oneofDescriptors struct {\n\tprotoreflect.OneofDescriptors\n\toneofs []oneofDescriptor\n}\n\nfunc (r *result) createOneofs(prefix string, parent *msgDescriptor, ooProtos []*descriptorpb.OneofDescriptorProto, pool *allocPool) oneofDescriptors {\n\toos := pool.getOneofs(len(ooProtos))\n\tfor i, fldProto := range ooProtos {\n\t\tr.createOneofDescriptor(&oos[i], fldProto, parent, i, prefix+fldProto.GetName())\n\t}\n\treturn oneofDescriptors{oneofs: oos}\n}\n\nfunc (o *oneofDescriptors) Len() int {\n\treturn len(o.oneofs)\n}\n\nfunc (o *oneofDescriptors) Get(i int) protoreflect.OneofDescriptor {\n\treturn &o.oneofs[i]\n}\n\nfunc (o *oneofDescriptors) ByName(s protoreflect.Name) protoreflect.OneofDescriptor {\n\tfor i := range o.oneofs {\n\t\too := &o.oneofs[i]\n\t\tif oo.Name() == s {\n\t\t\treturn oo\n\t\t}\n\t}\n\treturn nil\n}\n\ntype oneofDescriptor struct {\n\tprotoreflect.OneofDescriptor\n\tfile   *result\n\tparent *msgDescriptor\n\tindex  int\n\tproto  *descriptorpb.OneofDescriptorProto\n\tfqn    string\n\n\tfields fldDescriptors\n}\n\nvar _ protoreflect.OneofDescriptor = (*oneofDescriptor)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*oneofDescriptor)(nil)\n\nfunc (r *result) createOneofDescriptor(ret *oneofDescriptor, ood *descriptorpb.OneofDescriptorProto, parent *msgDescriptor, index int, fqn string) {\n\tr.descriptors[fqn] = ret\n\tret.OneofDescriptor = noOpOneof\n\tret.file = r\n\tret.parent = parent\n\tret.index = index\n\tret.proto = ood\n\tret.fqn = fqn\n\n\tvar fields []*fldDescriptor\n\tfor _, fld := range parent.fields.fields {\n\t\tif fld.proto.OneofIndex != nil && int(fld.proto.GetOneofIndex()) == index {\n\t\t\tfields = append(fields, fld)\n\t\t}\n\t}\n\tret.fields = fldDescriptors{fields: fields}\n}\n\nfunc (o *oneofDescriptor) OneofDescriptorProto() *descriptorpb.OneofDescriptorProto {\n\treturn o.proto\n}\n\nfunc (o *oneofDescriptor) AsProto() proto.Message {\n\treturn o.proto\n}\n\nfunc (o *oneofDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn o.file\n}\n\nfunc (o *oneofDescriptor) Parent() protoreflect.Descriptor {\n\treturn o.parent\n}\n\nfunc (o *oneofDescriptor) Index() int {\n\treturn o.index\n}\n\nfunc (o *oneofDescriptor) Syntax() protoreflect.Syntax {\n\treturn o.file.Syntax()\n}\n\nfunc (o *oneofDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(o.proto.GetName())\n}\n\nfunc (o *oneofDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(o.fqn)\n}\n\nfunc (o *oneofDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (o *oneofDescriptor) Options() protoreflect.ProtoMessage {\n\treturn o.proto.Options\n}\n\nfunc (o *oneofDescriptor) IsSynthetic() bool {\n\tfor _, fld := range o.parent.proto.GetField() {\n\t\tif fld.OneofIndex != nil && int(fld.GetOneofIndex()) == o.index {\n\t\t\treturn fld.GetProto3Optional()\n\t\t}\n\t}\n\treturn false // NB: we should never get here\n}\n\nfunc (o *oneofDescriptor) Fields() protoreflect.FieldDescriptors {\n\treturn &o.fields\n}\n\ntype svcDescriptors struct {\n\tprotoreflect.ServiceDescriptors\n\tsvcs []svcDescriptor\n}\n\nfunc (r *result) createServices(prefix string, svcProtos []*descriptorpb.ServiceDescriptorProto, pool *allocPool) svcDescriptors {\n\tsvcs := pool.getServices(len(svcProtos))\n\tfor i, svcProto := range svcProtos {\n\t\tr.createServiceDescriptor(&svcs[i], svcProto, i, prefix+svcProto.GetName(), pool)\n\t}\n\treturn svcDescriptors{svcs: svcs}\n}\n\nfunc (s *svcDescriptors) Len() int {\n\treturn len(s.svcs)\n}\n\nfunc (s *svcDescriptors) Get(i int) protoreflect.ServiceDescriptor {\n\treturn &s.svcs[i]\n}\n\nfunc (s *svcDescriptors) ByName(n protoreflect.Name) protoreflect.ServiceDescriptor {\n\tfor i := range s.svcs {\n\t\tsvc := &s.svcs[i]\n\t\tif svc.Name() == n {\n\t\t\treturn svc\n\t\t}\n\t}\n\treturn nil\n}\n\ntype svcDescriptor struct {\n\tprotoreflect.ServiceDescriptor\n\tfile  *result\n\tindex int\n\tproto *descriptorpb.ServiceDescriptorProto\n\tfqn   string\n\n\tmethods mtdDescriptors\n}\n\nvar _ protoreflect.ServiceDescriptor = (*svcDescriptor)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*svcDescriptor)(nil)\n\nfunc (r *result) createServiceDescriptor(ret *svcDescriptor, sd *descriptorpb.ServiceDescriptorProto, index int, fqn string, pool *allocPool) {\n\tr.descriptors[fqn] = ret\n\tret.ServiceDescriptor = noOpService\n\tret.file = r\n\tret.index = index\n\tret.proto = sd\n\tret.fqn = fqn\n\n\tprefix := fqn + \".\"\n\tret.methods = r.createMethods(prefix, ret, sd.Method, pool)\n}\n\nfunc (s *svcDescriptor) ServiceDescriptorProto() *descriptorpb.ServiceDescriptorProto {\n\treturn s.proto\n}\n\nfunc (s *svcDescriptor) AsProto() proto.Message {\n\treturn s.proto\n}\n\nfunc (s *svcDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn s.file\n}\n\nfunc (s *svcDescriptor) Parent() protoreflect.Descriptor {\n\treturn s.file\n}\n\nfunc (s *svcDescriptor) Index() int {\n\treturn s.index\n}\n\nfunc (s *svcDescriptor) Syntax() protoreflect.Syntax {\n\treturn s.file.Syntax()\n}\n\nfunc (s *svcDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(s.proto.GetName())\n}\n\nfunc (s *svcDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(s.fqn)\n}\n\nfunc (s *svcDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (s *svcDescriptor) Options() protoreflect.ProtoMessage {\n\treturn s.proto.Options\n}\n\nfunc (s *svcDescriptor) Methods() protoreflect.MethodDescriptors {\n\treturn &s.methods\n}\n\ntype mtdDescriptors struct {\n\tprotoreflect.MethodDescriptors\n\tmtds []mtdDescriptor\n}\n\nfunc (r *result) createMethods(prefix string, parent *svcDescriptor, mtdProtos []*descriptorpb.MethodDescriptorProto, pool *allocPool) mtdDescriptors {\n\tmtds := pool.getMethods(len(mtdProtos))\n\tfor i, mtdProto := range mtdProtos {\n\t\tr.createMethodDescriptor(&mtds[i], mtdProto, parent, i, prefix+mtdProto.GetName())\n\t}\n\treturn mtdDescriptors{mtds: mtds}\n}\n\nfunc (m *mtdDescriptors) Len() int {\n\treturn len(m.mtds)\n}\n\nfunc (m *mtdDescriptors) Get(i int) protoreflect.MethodDescriptor {\n\treturn &m.mtds[i]\n}\n\nfunc (m *mtdDescriptors) ByName(n protoreflect.Name) protoreflect.MethodDescriptor {\n\tfor i := range m.mtds {\n\t\tmtd := &m.mtds[i]\n\t\tif mtd.Name() == n {\n\t\t\treturn mtd\n\t\t}\n\t}\n\treturn nil\n}\n\ntype mtdDescriptor struct {\n\tprotoreflect.MethodDescriptor\n\tfile   *result\n\tparent *svcDescriptor\n\tindex  int\n\tproto  *descriptorpb.MethodDescriptorProto\n\tfqn    string\n\n\tinputType, outputType protoreflect.MessageDescriptor\n}\n\nvar _ protoreflect.MethodDescriptor = (*mtdDescriptor)(nil)\nvar _ protoutil.DescriptorProtoWrapper = (*mtdDescriptor)(nil)\n\nfunc (r *result) createMethodDescriptor(ret *mtdDescriptor, mtd *descriptorpb.MethodDescriptorProto, parent *svcDescriptor, index int, fqn string) {\n\tr.descriptors[fqn] = ret\n\tret.MethodDescriptor = noOpMethod\n\tret.file = r\n\tret.parent = parent\n\tret.index = index\n\tret.proto = mtd\n\tret.fqn = fqn\n}\n\nfunc (m *mtdDescriptor) MethodDescriptorProto() *descriptorpb.MethodDescriptorProto {\n\treturn m.proto\n}\n\nfunc (m *mtdDescriptor) AsProto() proto.Message {\n\treturn m.proto\n}\n\nfunc (m *mtdDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn m.file\n}\n\nfunc (m *mtdDescriptor) Parent() protoreflect.Descriptor {\n\treturn m.parent\n}\n\nfunc (m *mtdDescriptor) Index() int {\n\treturn m.index\n}\n\nfunc (m *mtdDescriptor) Syntax() protoreflect.Syntax {\n\treturn m.file.Syntax()\n}\n\nfunc (m *mtdDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(m.proto.GetName())\n}\n\nfunc (m *mtdDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(m.fqn)\n}\n\nfunc (m *mtdDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (m *mtdDescriptor) Options() protoreflect.ProtoMessage {\n\treturn m.proto.Options\n}\n\nfunc (m *mtdDescriptor) Input() protoreflect.MessageDescriptor {\n\treturn m.inputType\n}\n\nfunc (m *mtdDescriptor) Output() protoreflect.MessageDescriptor {\n\treturn m.outputType\n}\n\nfunc (m *mtdDescriptor) IsStreamingClient() bool {\n\treturn m.proto.GetClientStreaming()\n}\n\nfunc (m *mtdDescriptor) IsStreamingServer() bool {\n\treturn m.proto.GetServerStreaming()\n}\n\nfunc (r *result) FindImportByPath(path string) File {\n\treturn r.deps.FindFileByPath(path)\n}\n\nfunc (r *result) FindExtensionByNumber(msg protoreflect.FullName, tag protoreflect.FieldNumber) protoreflect.ExtensionTypeDescriptor {\n\treturn findExtension(r, msg, tag)\n}\n\nfunc (r *result) FindDescriptorByName(name protoreflect.FullName) protoreflect.Descriptor {\n\tfqn := strings.TrimPrefix(string(name), \".\")\n\treturn r.descriptors[fqn]\n}\n\nfunc (r *result) hasSource() bool {\n\tn := r.FileNode()\n\t_, ok := n.(*ast.FileNode)\n\treturn ok\n}\n\n// resolveFeature resolves a feature for the given descriptor. If the given element\n// is in a proto2 or proto3 syntax file, this skips resolution and just returns the\n// relevant default (since such files are not allowed to override features).\n//\n// If neither the given element nor any of its ancestors override the given feature,\n// the relevant default is returned.\nfunc resolveFeature(element protoreflect.Descriptor, feature protoreflect.FieldDescriptor) protoreflect.Value {\n\tedition := editions.GetEdition(element)\n\tif edition == descriptorpb.Edition_EDITION_PROTO2 || edition == descriptorpb.Edition_EDITION_PROTO3 {\n\t\t// these syntax levels can't specify features, so we can short-circuit the search\n\t\t// through the descriptor hierarchy for feature overrides\n\t\tdefaults := editions.GetEditionDefaults(edition)\n\t\treturn defaults.ProtoReflect().Get(feature) // returns default value if field is not present\n\t}\n\tval, err := editions.ResolveFeature(element, feature)\n\tif err == nil && val.IsValid() {\n\t\treturn val\n\t}\n\tdefaults := editions.GetEditionDefaults(edition)\n\treturn defaults.ProtoReflect().Get(feature)\n}\n\nfunc isJSONCompliant(d protoreflect.Descriptor) bool {\n\tjsonFormat := resolveFeature(d, jsonFormatField)\n\treturn descriptorpb.FeatureSet_JsonFormat(jsonFormat.Enum()) == descriptorpb.FeatureSet_ALLOW\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/doc.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package linker contains logic and APIs related to linking a protobuf file.\n// The process of linking involves resolving all symbol references to the\n// referenced descriptor. The result of linking is a \"rich\" descriptor that\n// is more useful than just a descriptor proto since the links allow easy\n// traversal of a protobuf type schema and the relationships between elements.\n//\n// # Files\n//\n// This package uses an augmentation to protoreflect.FileDescriptor instances\n// in the form of the File interface. There are also factory functions for\n// promoting a FileDescriptor into a linker.File. This new interface provides\n// additional methods for resolving symbols in the file.\n//\n// This interface is both the result of linking but also an input to the linking\n// process, as all dependencies of a file to be linked must be provided in this\n// form. The actual result of the Link function, a Result, is an even broader\n// interface than File: The linker.Result interface provides even more functions,\n// which are needed for subsequent compilation steps: interpreting options and\n// generating source code info.\n//\n// # Symbols\n//\n// This package has a type named Symbols which represents a symbol table. This\n// is usually an internal detail when linking, but callers can provide an\n// instance so that symbols across multiple compile/link operations all have\n// access to the same table. This allows for detection of cases where multiple\n// files try to declare elements with conflicting fully-qualified names or\n// declare extensions for a particular extendable message that have conflicting\n// tag numbers.\n//\n// The calling code simply uses the same Symbols instance across all compile\n// operations and if any files processed have such conflicts, they can be\n// reported.\npackage linker\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/files.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage linker\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"google.golang.org/protobuf/reflect/protodesc\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n\n\t\"github.com/bufbuild/protocompile/walk\"\n)\n\n// File is like a super-powered protoreflect.FileDescriptor. It includes helpful\n// methods for looking up elements in the descriptor and can be used to create a\n// resolver for the entire transitive closure of the file's dependencies. (See\n// ResolverFromFile.)\ntype File interface {\n\tprotoreflect.FileDescriptor\n\t// FindDescriptorByName returns the given named element that is defined in\n\t// this file. If no such element exists, nil is returned.\n\tFindDescriptorByName(name protoreflect.FullName) protoreflect.Descriptor\n\t// FindImportByPath returns the File corresponding to the given import path.\n\t// If this file does not import the given path, nil is returned.\n\tFindImportByPath(path string) File\n\t// FindExtensionByNumber returns the extension descriptor for the given tag\n\t// that extends the given message name. If no such extension is defined in this\n\t// file, nil is returned.\n\tFindExtensionByNumber(message protoreflect.FullName, tag protoreflect.FieldNumber) protoreflect.ExtensionTypeDescriptor\n}\n\n// NewFile converts a protoreflect.FileDescriptor to a File. The given deps must\n// contain all dependencies/imports of f. Also see NewFileRecursive.\nfunc NewFile(f protoreflect.FileDescriptor, deps Files) (File, error) {\n\tif asFile, ok := f.(File); ok {\n\t\treturn asFile, nil\n\t}\n\tcheckedDeps := make(Files, f.Imports().Len())\n\tfor i := 0; i < f.Imports().Len(); i++ {\n\t\timprt := f.Imports().Get(i)\n\t\tdep := deps.FindFileByPath(imprt.Path())\n\t\tif dep == nil {\n\t\t\treturn nil, fmt.Errorf(\"cannot create File for %q: missing dependency for %q\", f.Path(), imprt.Path())\n\t\t}\n\t\tcheckedDeps[i] = dep\n\t}\n\treturn newFile(f, checkedDeps)\n}\n\nfunc newFile(f protoreflect.FileDescriptor, deps Files) (File, error) {\n\tdescs := map[protoreflect.FullName]protoreflect.Descriptor{}\n\terr := walk.Descriptors(f, func(d protoreflect.Descriptor) error {\n\t\tif _, ok := descs[d.FullName()]; ok {\n\t\t\treturn fmt.Errorf(\"file %q contains multiple elements with the name %s\", f.Path(), d.FullName())\n\t\t}\n\t\tdescs[d.FullName()] = d\n\t\treturn nil\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &file{\n\t\tFileDescriptor: f,\n\t\tdescs:          descs,\n\t\tdeps:           deps,\n\t}, nil\n}\n\n// NewFileRecursive recursively converts a protoreflect.FileDescriptor to a File.\n// If f has any dependencies/imports, they are converted, too, including any and\n// all transitive dependencies.\n//\n// If f already implements File, it is returned unchanged.\nfunc NewFileRecursive(f protoreflect.FileDescriptor) (File, error) {\n\tif asFile, ok := f.(File); ok {\n\t\treturn asFile, nil\n\t}\n\treturn newFileRecursive(f, map[protoreflect.FileDescriptor]File{})\n}\n\nfunc newFileRecursive(fd protoreflect.FileDescriptor, seen map[protoreflect.FileDescriptor]File) (File, error) {\n\tif res, ok := seen[fd]; ok {\n\t\tif res == nil {\n\t\t\treturn nil, fmt.Errorf(\"import cycle encountered: file %s transitively imports itself\", fd.Path())\n\t\t}\n\t\treturn res, nil\n\t}\n\n\tif f, ok := fd.(File); ok {\n\t\tseen[fd] = f\n\t\treturn f, nil\n\t}\n\n\tseen[fd] = nil\n\tdeps := make([]File, fd.Imports().Len())\n\tfor i := 0; i < fd.Imports().Len(); i++ {\n\t\timprt := fd.Imports().Get(i)\n\t\tdep, err := newFileRecursive(imprt, seen)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdeps[i] = dep\n\t}\n\n\tf, err := newFile(fd, deps)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tseen[fd] = f\n\treturn f, nil\n}\n\ntype file struct {\n\tprotoreflect.FileDescriptor\n\tdescs map[protoreflect.FullName]protoreflect.Descriptor\n\tdeps  Files\n}\n\nvar _ File = (*file)(nil)\n\nfunc (f *file) FindDescriptorByName(name protoreflect.FullName) protoreflect.Descriptor {\n\treturn f.descs[name]\n}\n\nfunc (f *file) FindImportByPath(path string) File {\n\treturn f.deps.FindFileByPath(path)\n}\n\nfunc (f *file) FindExtensionByNumber(msg protoreflect.FullName, tag protoreflect.FieldNumber) protoreflect.ExtensionTypeDescriptor {\n\treturn findExtension(f, msg, tag)\n}\n\nfunc (f *file) Unwrap() protoreflect.FileDescriptor {\n\treturn f.FileDescriptor\n}\n\n// Files represents a set of protobuf files. It is a slice of File values, but\n// also provides a method for easily looking up files by path and name.\ntype Files []File\n\n// FindFileByPath finds a file in f that has the given path and name. If f\n// contains no such file, nil is returned.\nfunc (f Files) FindFileByPath(path string) File {\n\tfor _, file := range f {\n\t\tif file.Path() == path {\n\t\t\treturn file\n\t\t}\n\t}\n\treturn nil\n}\n\n// AsResolver returns a Resolver that uses f as the source of descriptors. If\n// a given query cannot be answered with the files in f, the query will fail\n// with a protoregistry.NotFound error. The implementation just delegates calls\n// to each file until a result is found.\n//\n// Also see ResolverFromFile.\nfunc (f Files) AsResolver() Resolver {\n\treturn filesResolver(f)\n}\n\n// Resolver is an interface that can resolve various kinds of queries about\n// descriptors. It satisfies the resolver interfaces defined in protodesc\n// and protoregistry packages.\ntype Resolver interface {\n\tprotodesc.Resolver\n\tprotoregistry.MessageTypeResolver\n\tprotoregistry.ExtensionTypeResolver\n}\n\n// ResolverFromFile returns a Resolver that can resolve any element that is\n// visible to the given file. It will search the given file, its imports, and\n// any transitive public imports.\n//\n// Note that this function does not compute any additional indexes for efficient\n// search, so queries generally take linear time, O(n) where n is the number of\n// files whose elements are visible to the given file. Queries for an extension\n// by number have runtime complexity that is linear with the number of messages\n// and extensions defined across those files.\nfunc ResolverFromFile(f File) Resolver {\n\treturn fileResolver{f: f}\n}\n\ntype fileResolver struct {\n\tf File\n}\n\nfunc (r fileResolver) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {\n\treturn resolveInFile(r.f, false, nil, func(f File) (protoreflect.FileDescriptor, error) {\n\t\tif f.Path() == path {\n\t\t\treturn f, nil\n\t\t}\n\t\treturn nil, protoregistry.NotFound\n\t})\n}\n\nfunc (r fileResolver) FindDescriptorByName(name protoreflect.FullName) (protoreflect.Descriptor, error) {\n\treturn resolveInFile(r.f, false, nil, func(f File) (protoreflect.Descriptor, error) {\n\t\tif d := f.FindDescriptorByName(name); d != nil {\n\t\t\treturn d, nil\n\t\t}\n\t\treturn nil, protoregistry.NotFound\n\t})\n}\n\nfunc (r fileResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {\n\treturn resolveInFile(r.f, false, nil, func(f File) (protoreflect.MessageType, error) {\n\t\td := f.FindDescriptorByName(message)\n\t\tif d != nil {\n\t\t\tmd, ok := d.(protoreflect.MessageDescriptor)\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"%q is %s, not a message\", message, descriptorTypeWithArticle(d))\n\t\t\t}\n\t\t\treturn dynamicpb.NewMessageType(md), nil\n\t\t}\n\t\treturn nil, protoregistry.NotFound\n\t})\n}\n\nfunc (r fileResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {\n\tfullName := messageNameFromURL(url)\n\treturn r.FindMessageByName(protoreflect.FullName(fullName))\n}\n\nfunc messageNameFromURL(url string) string {\n\tlastSlash := strings.LastIndexByte(url, '/')\n\treturn url[lastSlash+1:]\n}\n\nfunc (r fileResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {\n\treturn resolveInFile(r.f, false, nil, func(f File) (protoreflect.ExtensionType, error) {\n\t\td := f.FindDescriptorByName(field)\n\t\tif d != nil {\n\t\t\tfld, ok := d.(protoreflect.FieldDescriptor)\n\t\t\tif !ok || !fld.IsExtension() {\n\t\t\t\treturn nil, fmt.Errorf(\"%q is %s, not an extension\", field, descriptorTypeWithArticle(d))\n\t\t\t}\n\t\t\tif extd, ok := fld.(protoreflect.ExtensionTypeDescriptor); ok {\n\t\t\t\treturn extd.Type(), nil\n\t\t\t}\n\t\t\treturn dynamicpb.NewExtensionType(fld), nil\n\t\t}\n\t\treturn nil, protoregistry.NotFound\n\t})\n}\n\nfunc (r fileResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {\n\treturn resolveInFile(r.f, false, nil, func(f File) (protoreflect.ExtensionType, error) {\n\t\text := findExtension(f, message, field)\n\t\tif ext != nil {\n\t\t\treturn ext.Type(), nil\n\t\t}\n\t\treturn nil, protoregistry.NotFound\n\t})\n}\n\ntype filesResolver []File\n\nfunc (r filesResolver) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {\n\tfor _, f := range r {\n\t\tif f.Path() == path {\n\t\t\treturn f, nil\n\t\t}\n\t}\n\treturn nil, protoregistry.NotFound\n}\n\nfunc (r filesResolver) FindDescriptorByName(name protoreflect.FullName) (protoreflect.Descriptor, error) {\n\tfor _, f := range r {\n\t\tresult := f.FindDescriptorByName(name)\n\t\tif result != nil {\n\t\t\treturn result, nil\n\t\t}\n\t}\n\treturn nil, protoregistry.NotFound\n}\n\nfunc (r filesResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {\n\tfor _, f := range r {\n\t\td := f.FindDescriptorByName(message)\n\t\tif d != nil {\n\t\t\tif md, ok := d.(protoreflect.MessageDescriptor); ok {\n\t\t\t\treturn dynamicpb.NewMessageType(md), nil\n\t\t\t}\n\t\t\treturn nil, protoregistry.NotFound\n\t\t}\n\t}\n\treturn nil, protoregistry.NotFound\n}\n\nfunc (r filesResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {\n\tname := messageNameFromURL(url)\n\treturn r.FindMessageByName(protoreflect.FullName(name))\n}\n\nfunc (r filesResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {\n\tfor _, f := range r {\n\t\td := f.FindDescriptorByName(field)\n\t\tif d != nil {\n\t\t\tif extd, ok := d.(protoreflect.ExtensionTypeDescriptor); ok {\n\t\t\t\treturn extd.Type(), nil\n\t\t\t}\n\t\t\tif fld, ok := d.(protoreflect.FieldDescriptor); ok && fld.IsExtension() {\n\t\t\t\treturn dynamicpb.NewExtensionType(fld), nil\n\t\t\t}\n\t\t\treturn nil, protoregistry.NotFound\n\t\t}\n\t}\n\treturn nil, protoregistry.NotFound\n}\n\nfunc (r filesResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {\n\tfor _, f := range r {\n\t\text := findExtension(f, message, field)\n\t\tif ext != nil {\n\t\t\treturn ext.Type(), nil\n\t\t}\n\t}\n\treturn nil, protoregistry.NotFound\n}\n\ntype hasExtensionsAndMessages interface {\n\tMessages() protoreflect.MessageDescriptors\n\tExtensions() protoreflect.ExtensionDescriptors\n}\n\nfunc findExtension(d hasExtensionsAndMessages, message protoreflect.FullName, field protoreflect.FieldNumber) protoreflect.ExtensionTypeDescriptor {\n\tfor i := 0; i < d.Extensions().Len(); i++ {\n\t\tif extType := isExtensionMatch(d.Extensions().Get(i), message, field); extType != nil {\n\t\t\treturn extType\n\t\t}\n\t}\n\n\tfor i := 0; i < d.Messages().Len(); i++ {\n\t\tif extType := findExtension(d.Messages().Get(i), message, field); extType != nil {\n\t\t\treturn extType\n\t\t}\n\t}\n\n\treturn nil // could not be found\n}\n\nfunc isExtensionMatch(ext protoreflect.ExtensionDescriptor, message protoreflect.FullName, field protoreflect.FieldNumber) protoreflect.ExtensionTypeDescriptor {\n\tif ext.Number() != field || ext.ContainingMessage().FullName() != message {\n\t\treturn nil\n\t}\n\tif extType, ok := ext.(protoreflect.ExtensionTypeDescriptor); ok {\n\t\treturn extType\n\t}\n\treturn dynamicpb.NewExtensionType(ext).TypeDescriptor()\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/linker.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage linker\n\nimport (\n\t\"fmt\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/parser\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n)\n\n// Link handles linking a parsed descriptor proto into a fully-linked descriptor.\n// If the given parser.Result has imports, they must all be present in the given\n// dependencies.\n//\n// The symbols value is optional and may be nil. If it is not nil, it must be the\n// same instance used to create and link all of the given result's dependencies\n// (or otherwise already have all dependencies imported). Otherwise, linking may\n// fail with spurious errors resolving symbols.\n//\n// The handler value is used to report any link errors. If any such errors are\n// reported, this function returns a non-nil error. The Result value returned\n// also implements protoreflect.FileDescriptor.\n//\n// Note that linking does NOT interpret options. So options messages in the\n// returned value have all values stored in UninterpretedOptions fields.\nfunc Link(parsed parser.Result, dependencies Files, symbols *Symbols, handler *reporter.Handler) (Result, error) {\n\tif symbols == nil {\n\t\tsymbols = &Symbols{}\n\t}\n\tprefix := parsed.FileDescriptorProto().GetPackage()\n\tif prefix != \"\" {\n\t\tprefix += \".\"\n\t}\n\n\tfor _, imp := range parsed.FileDescriptorProto().Dependency {\n\t\tdep := dependencies.FindFileByPath(imp)\n\t\tif dep == nil {\n\t\t\treturn nil, fmt.Errorf(\"dependencies is missing import %q\", imp)\n\t\t}\n\t\tif err := symbols.Import(dep, handler); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tr := &result{\n\t\tFileDescriptor:       noOpFile,\n\t\tResult:               parsed,\n\t\tdeps:                 dependencies,\n\t\tdescriptors:          map[string]protoreflect.Descriptor{},\n\t\tusedImports:          map[string]struct{}{},\n\t\tprefix:               prefix,\n\t\toptionQualifiedNames: map[ast.IdentValueNode]string{},\n\t}\n\t// First, we create the hierarchy of descendant descriptors.\n\tr.createDescendants()\n\n\t// Then we can put all symbols into a single pool, which lets us ensure there\n\t// are no duplicate symbols and will also let us resolve and revise all type\n\t// references in next step.\n\tif err := symbols.importResult(r, handler); err != nil {\n\t\treturn nil, err\n\t}\n\n\t// After we've populated the pool, we can now try to resolve all type\n\t// references. All references must be checked for correct type, any fields\n\t// with enum types must be corrected (since we parse them as if they are\n\t// message references since we don't actually know message or enum until\n\t// link time), and references will be re-written to be fully-qualified\n\t// references (e.g. start with a dot \".\").\n\tif err := r.resolveReferences(handler, symbols); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn r, handler.Error()\n}\n\n// Result is the result of linking. This is a protoreflect.FileDescriptor, but\n// with some additional methods for exposing additional information, such as the\n// for accessing the input AST or file descriptor.\n//\n// It also provides Resolve* methods, for looking up enums, messages, and\n// extensions that are available to the protobuf source file this result\n// represents. An element is \"available\" if it meets any of the following\n// criteria:\n//  1. The element is defined in this file itself.\n//  2. The element is defined in a file that is directly imported by this file.\n//  3. The element is \"available\" to a file that is directly imported by this\n//     file as a public import.\n//\n// Other elements, even if in the transitive closure of this file, are not\n// available and thus won't be returned by these methods.\ntype Result interface {\n\tFile\n\tparser.Result\n\n\t// ResolveMessageLiteralExtensionName returns the fully qualified name for\n\t// an identifier for extension field names in message literals.\n\tResolveMessageLiteralExtensionName(ast.IdentValueNode) string\n\t// ValidateOptions runs some validation checks on the descriptor that can only\n\t// be done after options are interpreted. Any errors or warnings encountered\n\t// will be reported via the given handler. If any error is reported, this\n\t// function returns a non-nil error.\n\tValidateOptions(handler *reporter.Handler, symbols *Symbols) error\n\t// CheckForUnusedImports is used to report warnings for unused imports. This\n\t// should be called after options have been interpreted. Otherwise, the logic\n\t// could incorrectly report imports as unused if the only symbol used were a\n\t// custom option.\n\tCheckForUnusedImports(handler *reporter.Handler)\n\t// PopulateSourceCodeInfo is used to populate source code info for the file\n\t// descriptor. This step requires that the underlying descriptor proto have\n\t// its `source_code_info` field populated. This is typically a post-process\n\t// step separate from linking, because computing source code info requires\n\t// interpreting options (which is done after linking).\n\tPopulateSourceCodeInfo()\n\n\t// RemoveAST drops the AST information from this result.\n\tRemoveAST()\n}\n\n// ErrorUnusedImport may be passed to a warning reporter when an unused\n// import is detected. The error the reporter receives will be wrapped\n// with source position that indicates the file and line where the import\n// statement appeared.\ntype ErrorUnusedImport interface {\n\terror\n\tUnusedImport() string\n}\n\ntype errUnusedImport string\n\nfunc (e errUnusedImport) Error() string {\n\treturn fmt.Sprintf(\"import %q not used\", string(e))\n}\n\nfunc (e errUnusedImport) UnusedImport() string {\n\treturn string(e)\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/pathkey_no_unsafe.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build appengine || gopherjs || purego\n// +build appengine gopherjs purego\n\n// NB: other environments where unsafe is inappropriate should use \"purego\" build tag\n// https://github.com/golang/go/issues/23172\n\npackage linker\n\nimport (\n\t\"reflect\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n)\n\nfunc pathKey(p protoreflect.SourcePath) interface{} {\n\trv := reflect.ValueOf(p)\n\tarrayType := reflect.ArrayOf(rv.Len(), rv.Type().Elem())\n\tarray := reflect.New(arrayType).Elem()\n\treflect.Copy(array, rv)\n\treturn array.Interface()\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/pathkey_unsafe.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n//go:build !appengine && !gopherjs && !purego\n// +build !appengine,!gopherjs,!purego\n\n// NB: other environments where unsafe is inappropriate should use \"purego\" build tag\n// https://github.com/golang/go/issues/23172\n\npackage linker\n\nimport (\n\t\"reflect\"\n\t\"unsafe\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n)\n\nvar pathElementType = reflect.TypeOf(protoreflect.SourcePath{}).Elem()\n\nfunc pathKey(p protoreflect.SourcePath) interface{} {\n\tif p == nil {\n\t\t// Reflection code below doesn't work with nil slices\n\t\treturn [0]int32{}\n\t}\n\thdr := (*reflect.SliceHeader)(unsafe.Pointer(reflect.ValueOf(&p).Pointer()))\n\tarray := reflect.NewAt(reflect.ArrayOf(hdr.Len, pathElementType), unsafe.Pointer(hdr.Data))\n\treturn array.Elem().Interface()\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/pool.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage linker\n\nimport \"google.golang.org/protobuf/types/descriptorpb\"\n\n// allocPool helps allocate descriptor instances. Instead of allocating\n// them one at a time, we allocate a pool -- a large, flat slice to hold\n// all descriptors of a particular kind for a file. We then use capacity\n// in the pool when we need space for individual descriptors.\ntype allocPool struct {\n\tnumMessages   int\n\tnumFields     int\n\tnumOneofs     int\n\tnumEnums      int\n\tnumEnumValues int\n\tnumExtensions int\n\tnumServices   int\n\tnumMethods    int\n\n\tmessages   []msgDescriptor\n\tfields     []fldDescriptor\n\toneofs     []oneofDescriptor\n\tenums      []enumDescriptor\n\tenumVals   []enValDescriptor\n\textensions []extTypeDescriptor\n\tservices   []svcDescriptor\n\tmethods    []mtdDescriptor\n}\n\nfunc newAllocPool(file *descriptorpb.FileDescriptorProto) *allocPool {\n\tvar pool allocPool\n\tpool.countElements(file)\n\tpool.messages = make([]msgDescriptor, pool.numMessages)\n\tpool.fields = make([]fldDescriptor, pool.numFields)\n\tpool.oneofs = make([]oneofDescriptor, pool.numOneofs)\n\tpool.enums = make([]enumDescriptor, pool.numEnums)\n\tpool.enumVals = make([]enValDescriptor, pool.numEnumValues)\n\tpool.extensions = make([]extTypeDescriptor, pool.numExtensions)\n\tpool.services = make([]svcDescriptor, pool.numServices)\n\tpool.methods = make([]mtdDescriptor, pool.numMethods)\n\treturn &pool\n}\n\nfunc (p *allocPool) getMessages(count int) []msgDescriptor {\n\tallocated := p.messages[:count]\n\tp.messages = p.messages[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) getFields(count int) []fldDescriptor {\n\tallocated := p.fields[:count]\n\tp.fields = p.fields[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) getOneofs(count int) []oneofDescriptor {\n\tallocated := p.oneofs[:count]\n\tp.oneofs = p.oneofs[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) getEnums(count int) []enumDescriptor {\n\tallocated := p.enums[:count]\n\tp.enums = p.enums[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) getEnumValues(count int) []enValDescriptor {\n\tallocated := p.enumVals[:count]\n\tp.enumVals = p.enumVals[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) getExtensions(count int) []extTypeDescriptor {\n\tallocated := p.extensions[:count]\n\tp.extensions = p.extensions[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) getServices(count int) []svcDescriptor {\n\tallocated := p.services[:count]\n\tp.services = p.services[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) getMethods(count int) []mtdDescriptor {\n\tallocated := p.methods[:count]\n\tp.methods = p.methods[count:]\n\treturn allocated\n}\n\nfunc (p *allocPool) countElements(file *descriptorpb.FileDescriptorProto) {\n\tp.countElementsInMessages(file.MessageType)\n\tp.countElementsInEnums(file.EnumType)\n\tp.numExtensions += len(file.Extension)\n\tp.numServices += len(file.Service)\n\tfor _, svc := range file.Service {\n\t\tp.numMethods += len(svc.Method)\n\t}\n}\n\nfunc (p *allocPool) countElementsInMessages(msgs []*descriptorpb.DescriptorProto) {\n\tp.numMessages += len(msgs)\n\tfor _, msg := range msgs {\n\t\tp.numFields += len(msg.Field)\n\t\tp.numOneofs += len(msg.OneofDecl)\n\t\tp.countElementsInMessages(msg.NestedType)\n\t\tp.countElementsInEnums(msg.EnumType)\n\t\tp.numExtensions += len(msg.Extension)\n\t}\n}\n\nfunc (p *allocPool) countElementsInEnums(enums []*descriptorpb.EnumDescriptorProto) {\n\tp.numEnums += len(enums)\n\tfor _, enum := range enums {\n\t\tp.numEnumValues += len(enum.Value)\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/resolve.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage linker\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n\t\"github.com/bufbuild/protocompile/walk\"\n)\n\nfunc (r *result) ResolveMessageLiteralExtensionName(node ast.IdentValueNode) string {\n\treturn r.optionQualifiedNames[node]\n}\n\nfunc (r *result) resolveElement(name protoreflect.FullName, checkedCache []string) protoreflect.Descriptor {\n\tif len(name) > 0 && name[0] == '.' {\n\t\tname = name[1:]\n\t}\n\tres, _ := resolveInFile(r, false, checkedCache[:0], func(f File) (protoreflect.Descriptor, error) {\n\t\td := resolveElementInFile(name, f)\n\t\tif d != nil {\n\t\t\treturn d, nil\n\t\t}\n\t\treturn nil, protoregistry.NotFound\n\t})\n\treturn res\n}\n\nfunc resolveInFile[T any](f File, publicImportsOnly bool, checked []string, fn func(File) (T, error)) (T, error) {\n\tvar zero T\n\tpath := f.Path()\n\tfor _, str := range checked {\n\t\tif str == path {\n\t\t\t// already checked\n\t\t\treturn zero, protoregistry.NotFound\n\t\t}\n\t}\n\tchecked = append(checked, path)\n\n\tres, err := fn(f)\n\tif err == nil {\n\t\t// found it\n\t\treturn res, nil\n\t}\n\tif !errors.Is(err, protoregistry.NotFound) {\n\t\treturn zero, err\n\t}\n\n\timports := f.Imports()\n\tfor i, l := 0, imports.Len(); i < l; i++ {\n\t\timp := imports.Get(i)\n\t\tif publicImportsOnly && !imp.IsPublic {\n\t\t\tcontinue\n\t\t}\n\t\tres, err := resolveInFile(f.FindImportByPath(imp.Path()), true, checked, fn)\n\t\tif errors.Is(err, protoregistry.NotFound) {\n\t\t\tcontinue\n\t\t}\n\t\tif err != nil {\n\t\t\treturn zero, err\n\t\t}\n\t\tif !imp.IsPublic {\n\t\t\tif r, ok := f.(*result); ok {\n\t\t\t\tr.markUsed(imp.Path())\n\t\t\t}\n\t\t}\n\t\treturn res, nil\n\t}\n\treturn zero, err\n}\n\nfunc (r *result) markUsed(importPath string) {\n\tr.usedImports[importPath] = struct{}{}\n}\n\nfunc (r *result) CheckForUnusedImports(handler *reporter.Handler) {\n\tfd := r.FileDescriptorProto()\n\tfile, _ := r.FileNode().(*ast.FileNode)\n\tfor i, dep := range fd.Dependency {\n\t\tif _, ok := r.usedImports[dep]; !ok {\n\t\t\tisPublic := false\n\t\t\t// it's fine if it's a public import\n\t\t\tfor _, j := range fd.PublicDependency {\n\t\t\t\tif i == int(j) {\n\t\t\t\t\tisPublic = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif isPublic {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tspan := ast.UnknownSpan(fd.GetName())\n\t\t\tif file != nil {\n\t\t\t\tfor _, decl := range file.Decls {\n\t\t\t\t\timp, ok := decl.(*ast.ImportNode)\n\t\t\t\t\tif ok && imp.Name.AsString() == dep {\n\t\t\t\t\t\tspan = file.NodeInfo(imp)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\thandler.HandleWarningWithPos(span, errUnusedImport(dep))\n\t\t}\n\t}\n}\n\nfunc descriptorTypeWithArticle(d protoreflect.Descriptor) string {\n\tswitch d := d.(type) {\n\tcase protoreflect.MessageDescriptor:\n\t\treturn \"a message\"\n\tcase protoreflect.FieldDescriptor:\n\t\tif d.IsExtension() {\n\t\t\treturn \"an extension\"\n\t\t}\n\t\treturn \"a field\"\n\tcase protoreflect.OneofDescriptor:\n\t\treturn \"a oneof\"\n\tcase protoreflect.EnumDescriptor:\n\t\treturn \"an enum\"\n\tcase protoreflect.EnumValueDescriptor:\n\t\treturn \"an enum value\"\n\tcase protoreflect.ServiceDescriptor:\n\t\treturn \"a service\"\n\tcase protoreflect.MethodDescriptor:\n\t\treturn \"a method\"\n\tcase protoreflect.FileDescriptor:\n\t\treturn \"a file\"\n\tdefault:\n\t\t// shouldn't be possible\n\t\treturn fmt.Sprintf(\"a %T\", d)\n\t}\n}\n\nfunc (r *result) createDescendants() {\n\tfd := r.FileDescriptorProto()\n\tpool := newAllocPool(fd)\n\tprefix := \"\"\n\tif fd.GetPackage() != \"\" {\n\t\tprefix = fd.GetPackage() + \".\"\n\t}\n\tr.imports = r.createImports()\n\tr.messages = r.createMessages(prefix, r, fd.MessageType, pool)\n\tr.enums = r.createEnums(prefix, r, fd.EnumType, pool)\n\tr.extensions = r.createExtensions(prefix, r, fd.Extension, pool)\n\tr.services = r.createServices(prefix, fd.Service, pool)\n}\n\nfunc (r *result) resolveReferences(handler *reporter.Handler, s *Symbols) error {\n\tfd := r.FileDescriptorProto()\n\tcheckedCache := make([]string, 0, 16)\n\tscopes := []scope{fileScope(r, checkedCache)}\n\tif fd.Options != nil {\n\t\tif err := r.resolveOptions(handler, \"file\", protoreflect.FullName(fd.GetName()), fd.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// This is to de-dupe extendee-releated error messages when the same\n\t// extendee is referenced from multiple extension field definitions.\n\t// We leave it nil if there's no AST.\n\tvar extendeeNodes map[ast.Node]struct{}\n\n\treturn walk.DescriptorsEnterAndExit(r,\n\t\tfunc(d protoreflect.Descriptor) error {\n\t\t\tfqn := d.FullName()\n\t\t\tswitch d := d.(type) {\n\t\t\tcase *msgDescriptor:\n\t\t\t\t// Strangely, when protoc resolves extension names, it uses the *enclosing* scope\n\t\t\t\t// instead of the message's scope. So if the message contains an extension named \"i\",\n\t\t\t\t// an option cannot refer to it as simply \"i\" but must qualify it (at a minimum \"Msg.i\").\n\t\t\t\t// So we don't add this messages scope to our scopes slice until *after* we do options.\n\t\t\t\tif d.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"message\", fqn, d.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tscopes = append(scopes, messageScope(r, fqn)) // push new scope on entry\n\t\t\t\t// walk only visits descriptors, so we need to loop over extension ranges ourselves\n\t\t\t\tfor _, er := range d.proto.ExtensionRange {\n\t\t\t\t\tif er.Options != nil {\n\t\t\t\t\t\terName := protoreflect.FullName(fmt.Sprintf(\"%s:%d-%d\", fqn, er.GetStart(), er.GetEnd()-1))\n\t\t\t\t\t\tif err := r.resolveOptions(handler, \"extension range\", erName, er.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *extTypeDescriptor:\n\t\t\t\tif d.field.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"extension\", fqn, d.field.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif extendeeNodes == nil && r.AST() != nil {\n\t\t\t\t\textendeeNodes = map[ast.Node]struct{}{}\n\t\t\t\t}\n\t\t\t\tif err := resolveFieldTypes(&d.field, handler, extendeeNodes, s, scopes, checkedCache); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tif r.Syntax() == protoreflect.Proto3 && !allowedProto3Extendee(d.field.proto.GetExtendee()) {\n\t\t\t\t\tfile := r.FileNode()\n\t\t\t\t\tnode := r.FieldNode(d.field.proto).FieldExtendee()\n\t\t\t\t\tif err := handler.HandleErrorf(file.NodeInfo(node), \"extend blocks in proto3 can only be used to define custom options\"); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *fldDescriptor:\n\t\t\t\tif d.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"field\", fqn, d.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err := resolveFieldTypes(d, handler, nil, s, scopes, checkedCache); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase *oneofDescriptor:\n\t\t\t\tif d.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"oneof\", fqn, d.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *enumDescriptor:\n\t\t\t\tif d.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"enum\", fqn, d.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *enValDescriptor:\n\t\t\t\tif d.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"enum value\", fqn, d.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase *svcDescriptor:\n\t\t\t\tif d.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"service\", fqn, d.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// not a message, but same scoping rules for nested elements as if it were\n\t\t\t\tscopes = append(scopes, messageScope(r, fqn)) // push new scope on entry\n\t\t\tcase *mtdDescriptor:\n\t\t\t\tif d.proto.Options != nil {\n\t\t\t\t\tif err := r.resolveOptions(handler, \"method\", fqn, d.proto.Options.UninterpretedOption, scopes, checkedCache); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err := resolveMethodTypes(d, handler, scopes, checkedCache); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t\tfunc(d protoreflect.Descriptor) error {\n\t\t\tswitch d.(type) {\n\t\t\tcase protoreflect.MessageDescriptor, protoreflect.ServiceDescriptor:\n\t\t\t\t// pop message scope on exit\n\t\t\t\tscopes = scopes[:len(scopes)-1]\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n}\n\nvar allowedProto3Extendees = map[string]struct{}{\n\t\".google.protobuf.FileOptions\":           {},\n\t\".google.protobuf.MessageOptions\":        {},\n\t\".google.protobuf.FieldOptions\":          {},\n\t\".google.protobuf.OneofOptions\":          {},\n\t\".google.protobuf.ExtensionRangeOptions\": {},\n\t\".google.protobuf.EnumOptions\":           {},\n\t\".google.protobuf.EnumValueOptions\":      {},\n\t\".google.protobuf.ServiceOptions\":        {},\n\t\".google.protobuf.MethodOptions\":         {},\n}\n\nfunc allowedProto3Extendee(n string) bool {\n\tif n == \"\" {\n\t\t// not an extension, allowed\n\t\treturn true\n\t}\n\t_, ok := allowedProto3Extendees[n]\n\treturn ok\n}\n\nfunc resolveFieldTypes(f *fldDescriptor, handler *reporter.Handler, extendees map[ast.Node]struct{}, s *Symbols, scopes []scope, checkedCache []string) error {\n\tr := f.file\n\tfld := f.proto\n\tfile := r.FileNode()\n\tnode := r.FieldNode(fld)\n\tkind := \"field\"\n\tif fld.GetExtendee() != \"\" {\n\t\tkind = \"extension\"\n\t\tvar alreadyReported bool\n\t\tif extendees != nil {\n\t\t\t_, alreadyReported = extendees[node.FieldExtendee()]\n\t\t\tif !alreadyReported {\n\t\t\t\textendees[node.FieldExtendee()] = struct{}{}\n\t\t\t}\n\t\t}\n\t\tdsc := r.resolve(fld.GetExtendee(), false, scopes, checkedCache)\n\t\tif dsc == nil {\n\t\t\tif alreadyReported {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar extendeePrefix string\n\t\t\tif extendees == nil {\n\t\t\t\textendeePrefix = kind + \" \" + f.fqn + \": \"\n\t\t\t}\n\t\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldExtendee()), \"%sunknown extendee type %s\", extendeePrefix, fld.GetExtendee())\n\t\t}\n\t\tif isSentinelDescriptor(dsc) {\n\t\t\tif alreadyReported {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar extendeePrefix string\n\t\t\tif extendees == nil {\n\t\t\t\textendeePrefix = kind + \" \" + f.fqn + \": \"\n\t\t\t}\n\t\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldExtendee()), \"%sunknown extendee type %s; resolved to %s which is not defined; consider using a leading dot\", extendeePrefix, fld.GetExtendee(), dsc.FullName())\n\t\t}\n\t\textd, ok := dsc.(protoreflect.MessageDescriptor)\n\t\tif !ok {\n\t\t\tif alreadyReported {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar extendeePrefix string\n\t\t\tif extendees == nil {\n\t\t\t\textendeePrefix = kind + \" \" + f.fqn + \": \"\n\t\t\t}\n\t\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldExtendee()), \"%sextendee is invalid: %s is %s, not a message\", extendeePrefix, dsc.FullName(), descriptorTypeWithArticle(dsc))\n\t\t}\n\n\t\tf.extendee = extd\n\t\textendeeName := \".\" + string(dsc.FullName())\n\t\tif fld.GetExtendee() != extendeeName {\n\t\t\tfld.Extendee = proto.String(extendeeName)\n\t\t}\n\t\t// make sure the tag number is in range\n\t\tfound := false\n\t\ttag := protoreflect.FieldNumber(fld.GetNumber())\n\t\tfor i := 0; i < extd.ExtensionRanges().Len(); i++ {\n\t\t\trng := extd.ExtensionRanges().Get(i)\n\t\t\tif tag >= rng[0] && tag < rng[1] {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tif err := handler.HandleErrorf(file.NodeInfo(node.FieldTag()), \"%s %s: tag %d is not in valid range for extended type %s\", kind, f.fqn, tag, dsc.FullName()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\t// make sure tag is not a duplicate\n\t\t\tif err := s.AddExtension(packageFor(dsc), dsc.FullName(), tag, file.NodeInfo(node.FieldTag()), handler); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t} else if f.proto.OneofIndex != nil {\n\t\tparent := f.parent.(protoreflect.MessageDescriptor) //nolint:errcheck\n\t\tindex := int(f.proto.GetOneofIndex())\n\t\tf.oneof = parent.Oneofs().Get(index)\n\t}\n\n\tif fld.GetTypeName() == \"\" {\n\t\t// scalar type; no further resolution required\n\t\treturn nil\n\t}\n\n\tdsc := r.resolve(fld.GetTypeName(), true, scopes, checkedCache)\n\tif dsc == nil {\n\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldType()), \"%s %s: unknown type %s\", kind, f.fqn, fld.GetTypeName())\n\t}\n\tif isSentinelDescriptor(dsc) {\n\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldType()), \"%s %s: unknown type %s; resolved to %s which is not defined; consider using a leading dot\", kind, f.fqn, fld.GetTypeName(), dsc.FullName())\n\t}\n\tswitch dsc := dsc.(type) {\n\tcase protoreflect.MessageDescriptor:\n\t\tif dsc.IsMapEntry() {\n\t\t\tisValid := false\n\t\t\tswitch node.(type) {\n\t\t\tcase *ast.MapFieldNode:\n\t\t\t\t// We have an AST for this file and can see this field is from a map declaration\n\t\t\t\tisValid = true\n\t\t\tcase *ast.NoSourceNode:\n\t\t\t\t// We don't have an AST for the file (it came from a provided descriptor). So we\n\t\t\t\t// need to validate that it's not an illegal reference. To be valid, the field\n\t\t\t\t// must be repeated and the entry type must be nested in the same enclosing\n\t\t\t\t// message as the field.\n\t\t\t\tisValid = isValidMap(f, dsc)\n\t\t\t\tif isValid && f.index > 0 {\n\t\t\t\t\t// also make sure there are no earlier fields that are valid for this map entry\n\t\t\t\t\tflds := f.Parent().(protoreflect.MessageDescriptor).Fields()\n\t\t\t\t\tfor i := 0; i < f.index; i++ {\n\t\t\t\t\t\tif isValidMap(flds.Get(i), dsc) {\n\t\t\t\t\t\t\tisValid = false\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !isValid {\n\t\t\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldType()), \"%s %s: %s is a synthetic map entry and may not be referenced explicitly\", kind, f.fqn, dsc.FullName())\n\t\t\t}\n\t\t}\n\t\ttypeName := \".\" + string(dsc.FullName())\n\t\tif fld.GetTypeName() != typeName {\n\t\t\tfld.TypeName = proto.String(typeName)\n\t\t}\n\t\tif fld.Type == nil {\n\t\t\t// if type was tentatively unset, we now know it's actually a message\n\t\t\tfld.Type = descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum()\n\t\t} else if fld.GetType() != descriptorpb.FieldDescriptorProto_TYPE_MESSAGE && fld.GetType() != descriptorpb.FieldDescriptorProto_TYPE_GROUP {\n\t\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldType()), \"%s %s: descriptor proto indicates type %v but should be %v\", kind, f.fqn, fld.GetType(), descriptorpb.FieldDescriptorProto_TYPE_MESSAGE)\n\t\t}\n\t\tf.msgType = dsc\n\tcase protoreflect.EnumDescriptor:\n\t\ttypeName := \".\" + string(dsc.FullName())\n\t\tif fld.GetTypeName() != typeName {\n\t\t\tfld.TypeName = proto.String(typeName)\n\t\t}\n\t\tif fld.Type == nil {\n\t\t\t// the type was tentatively unset, but now we know it's actually an enum\n\t\t\tfld.Type = descriptorpb.FieldDescriptorProto_TYPE_ENUM.Enum()\n\t\t} else if fld.GetType() != descriptorpb.FieldDescriptorProto_TYPE_ENUM {\n\t\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldType()), \"%s %s: descriptor proto indicates type %v but should be %v\", kind, f.fqn, fld.GetType(), descriptorpb.FieldDescriptorProto_TYPE_ENUM)\n\t\t}\n\t\tf.enumType = dsc\n\tdefault:\n\t\treturn handler.HandleErrorf(file.NodeInfo(node.FieldType()), \"%s %s: invalid type: %s is %s, not a message or enum\", kind, f.fqn, dsc.FullName(), descriptorTypeWithArticle(dsc))\n\t}\n\treturn nil\n}\n\nfunc packageFor(dsc protoreflect.Descriptor) protoreflect.FullName {\n\tif dsc.ParentFile() != nil {\n\t\treturn dsc.ParentFile().Package()\n\t}\n\t// Can't access package? Make a best effort guess.\n\treturn dsc.FullName().Parent()\n}\n\nfunc isValidMap(mapField protoreflect.FieldDescriptor, mapEntry protoreflect.MessageDescriptor) bool {\n\treturn !mapField.IsExtension() &&\n\t\tmapEntry.Parent() == mapField.ContainingMessage() &&\n\t\tmapField.Cardinality() == protoreflect.Repeated &&\n\t\tstring(mapEntry.Name()) == internal.InitCap(internal.JSONName(string(mapField.Name())))+\"Entry\"\n}\n\nfunc resolveMethodTypes(m *mtdDescriptor, handler *reporter.Handler, scopes []scope, checkedCache []string) error {\n\tscope := \"method \" + m.fqn\n\tr := m.file\n\tmtd := m.proto\n\tfile := r.FileNode()\n\tnode := r.MethodNode(mtd)\n\tdsc := r.resolve(mtd.GetInputType(), false, scopes, checkedCache)\n\tif dsc == nil {\n\t\tif err := handler.HandleErrorf(file.NodeInfo(node.GetInputType()), \"%s: unknown request type %s\", scope, mtd.GetInputType()); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if isSentinelDescriptor(dsc) {\n\t\tif err := handler.HandleErrorf(file.NodeInfo(node.GetInputType()), \"%s: unknown request type %s; resolved to %s which is not defined; consider using a leading dot\", scope, mtd.GetInputType(), dsc.FullName()); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if msg, ok := dsc.(protoreflect.MessageDescriptor); !ok {\n\t\tif err := handler.HandleErrorf(file.NodeInfo(node.GetInputType()), \"%s: invalid request type: %s is %s, not a message\", scope, dsc.FullName(), descriptorTypeWithArticle(dsc)); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\ttypeName := \".\" + string(dsc.FullName())\n\t\tif mtd.GetInputType() != typeName {\n\t\t\tmtd.InputType = proto.String(typeName)\n\t\t}\n\t\tm.inputType = msg\n\t}\n\n\t// TODO: make input and output type resolution more DRY\n\tdsc = r.resolve(mtd.GetOutputType(), false, scopes, checkedCache)\n\tif dsc == nil {\n\t\tif err := handler.HandleErrorf(file.NodeInfo(node.GetOutputType()), \"%s: unknown response type %s\", scope, mtd.GetOutputType()); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if isSentinelDescriptor(dsc) {\n\t\tif err := handler.HandleErrorf(file.NodeInfo(node.GetOutputType()), \"%s: unknown response type %s; resolved to %s which is not defined; consider using a leading dot\", scope, mtd.GetOutputType(), dsc.FullName()); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else if msg, ok := dsc.(protoreflect.MessageDescriptor); !ok {\n\t\tif err := handler.HandleErrorf(file.NodeInfo(node.GetOutputType()), \"%s: invalid response type: %s is %s, not a message\", scope, dsc.FullName(), descriptorTypeWithArticle(dsc)); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\ttypeName := \".\" + string(dsc.FullName())\n\t\tif mtd.GetOutputType() != typeName {\n\t\t\tmtd.OutputType = proto.String(typeName)\n\t\t}\n\t\tm.outputType = msg\n\t}\n\n\treturn nil\n}\n\nfunc (r *result) resolveOptions(handler *reporter.Handler, elemType string, elemName protoreflect.FullName, opts []*descriptorpb.UninterpretedOption, scopes []scope, checkedCache []string) error {\n\tmc := &internal.MessageContext{\n\t\tFile:        r,\n\t\tElementName: string(elemName),\n\t\tElementType: elemType,\n\t}\n\tfile := r.FileNode()\nopts:\n\tfor _, opt := range opts {\n\t\t// resolve any extension names found in option names\n\t\tfor _, nm := range opt.Name {\n\t\t\tif nm.GetIsExtension() {\n\t\t\t\tnode := r.OptionNamePartNode(nm)\n\t\t\t\tfqn, err := r.resolveExtensionName(nm.GetNamePart(), scopes, checkedCache)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif err := handler.HandleErrorf(file.NodeInfo(node), \"%v%v\", mc, err); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\tcontinue opts\n\t\t\t\t}\n\t\t\t\tnm.NamePart = proto.String(fqn)\n\t\t\t}\n\t\t}\n\t\t// also resolve any extension names found inside message literals in option values\n\t\tmc.Option = opt\n\t\toptVal := r.OptionNode(opt).GetValue()\n\t\tif err := r.resolveOptionValue(handler, mc, optVal, scopes, checkedCache); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmc.Option = nil\n\t}\n\treturn nil\n}\n\nfunc (r *result) resolveOptionValue(handler *reporter.Handler, mc *internal.MessageContext, val ast.ValueNode, scopes []scope, checkedCache []string) error {\n\toptVal := val.Value()\n\tswitch optVal := optVal.(type) {\n\tcase []ast.ValueNode:\n\t\torigPath := mc.OptAggPath\n\t\tdefer func() {\n\t\t\tmc.OptAggPath = origPath\n\t\t}()\n\t\tfor i, v := range optVal {\n\t\t\tmc.OptAggPath = fmt.Sprintf(\"%s[%d]\", origPath, i)\n\t\t\tif err := r.resolveOptionValue(handler, mc, v, scopes, checkedCache); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\tcase []*ast.MessageFieldNode:\n\t\torigPath := mc.OptAggPath\n\t\tdefer func() {\n\t\t\tmc.OptAggPath = origPath\n\t\t}()\n\t\tfor _, fld := range optVal {\n\t\t\t// check for extension name\n\t\t\tif fld.Name.IsExtension() {\n\t\t\t\t// Confusingly, an extension reference inside a message literal cannot refer to\n\t\t\t\t// elements in the same enclosing message without a qualifier. Basically, we\n\t\t\t\t// treat this as if there were no message scopes, so only the package name is\n\t\t\t\t// used for resolving relative references. (Inconsistent protoc behavior, but\n\t\t\t\t// likely due to how it re-uses C++ text format implementation, and normal text\n\t\t\t\t// format doesn't expect that kind of relative reference.)\n\t\t\t\tscopes := scopes[:1] // first scope is file, the rest are enclosing messages\n\t\t\t\tfqn, err := r.resolveExtensionName(string(fld.Name.Name.AsIdentifier()), scopes, checkedCache)\n\t\t\t\tif err != nil {\n\t\t\t\t\tif err := handler.HandleErrorf(r.FileNode().NodeInfo(fld.Name.Name), \"%v%v\", mc, err); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tr.optionQualifiedNames[fld.Name.Name] = fqn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// recurse into value\n\t\t\tmc.OptAggPath = origPath\n\t\t\tif origPath != \"\" {\n\t\t\t\tmc.OptAggPath += \".\"\n\t\t\t}\n\t\t\tif fld.Name.IsExtension() {\n\t\t\t\tmc.OptAggPath = fmt.Sprintf(\"%s[%s]\", mc.OptAggPath, string(fld.Name.Name.AsIdentifier()))\n\t\t\t} else {\n\t\t\t\tmc.OptAggPath = fmt.Sprintf(\"%s%s\", mc.OptAggPath, string(fld.Name.Name.AsIdentifier()))\n\t\t\t}\n\n\t\t\tif err := r.resolveOptionValue(handler, mc, fld.Val, scopes, checkedCache); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *result) resolveExtensionName(name string, scopes []scope, checkedCache []string) (string, error) {\n\tdsc := r.resolve(name, false, scopes, checkedCache)\n\tif dsc == nil {\n\t\treturn \"\", fmt.Errorf(\"unknown extension %s\", name)\n\t}\n\tif isSentinelDescriptor(dsc) {\n\t\treturn \"\", fmt.Errorf(\"unknown extension %s; resolved to %s which is not defined; consider using a leading dot\", name, dsc.FullName())\n\t}\n\tif ext, ok := dsc.(protoreflect.FieldDescriptor); !ok {\n\t\treturn \"\", fmt.Errorf(\"invalid extension: %s is %s, not an extension\", name, descriptorTypeWithArticle(dsc))\n\t} else if !ext.IsExtension() {\n\t\treturn \"\", fmt.Errorf(\"invalid extension: %s is a field but not an extension\", name)\n\t}\n\treturn string(\".\" + dsc.FullName()), nil\n}\n\nfunc (r *result) resolve(name string, onlyTypes bool, scopes []scope, checkedCache []string) protoreflect.Descriptor {\n\tif strings.HasPrefix(name, \".\") {\n\t\t// already fully-qualified\n\t\treturn r.resolveElement(protoreflect.FullName(name[1:]), checkedCache)\n\t}\n\t// unqualified, so we look in the enclosing (last) scope first and move\n\t// towards outermost (first) scope, trying to resolve the symbol\n\tpos := strings.IndexByte(name, '.')\n\tfirstName := name\n\tif pos > 0 {\n\t\tfirstName = name[:pos]\n\t}\n\tvar bestGuess protoreflect.Descriptor\n\tfor i := len(scopes) - 1; i >= 0; i-- {\n\t\td := scopes[i](firstName, name)\n\t\tif d != nil {\n\t\t\t// In `protoc`, it will skip a match of the wrong type and move on\n\t\t\t// to the next scope, but only if the reference is unqualified. So\n\t\t\t// we mirror that behavior here. When we skip and move on, we go\n\t\t\t// ahead and save the match of the wrong type so we can at least use\n\t\t\t// it to construct a better error in the event that we don't find\n\t\t\t// any match of the right type.\n\t\t\tif !onlyTypes || isType(d) || firstName != name {\n\t\t\t\treturn d\n\t\t\t}\n\t\t\tif bestGuess == nil {\n\t\t\t\tbestGuess = d\n\t\t\t}\n\t\t}\n\t}\n\t// we return best guess, even though it was not an allowed kind of\n\t// descriptor, so caller can print a better error message (e.g.\n\t// indicating that the name was found but that it's the wrong type)\n\treturn bestGuess\n}\n\nfunc isType(d protoreflect.Descriptor) bool {\n\tswitch d.(type) {\n\tcase protoreflect.MessageDescriptor, protoreflect.EnumDescriptor:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// scope represents a lexical scope in a proto file in which messages and enums\n// can be declared.\ntype scope func(firstName, fullName string) protoreflect.Descriptor\n\nfunc fileScope(r *result, checkedCache []string) scope {\n\t// we search symbols in this file, but also symbols in other files that have\n\t// the same package as this file or a \"parent\" package (in protobuf,\n\t// packages are a hierarchy like C++ namespaces)\n\tprefixes := internal.CreatePrefixList(r.FileDescriptorProto().GetPackage())\n\tquerySymbol := func(n string) protoreflect.Descriptor {\n\t\treturn r.resolveElement(protoreflect.FullName(n), checkedCache)\n\t}\n\treturn func(firstName, fullName string) protoreflect.Descriptor {\n\t\tfor _, prefix := range prefixes {\n\t\t\tvar n1, n string\n\t\t\tif prefix == \"\" {\n\t\t\t\t// exhausted all prefixes, so it must be in this one\n\t\t\t\tn1, n = fullName, fullName\n\t\t\t} else {\n\t\t\t\tn = prefix + \".\" + fullName\n\t\t\t\tn1 = prefix + \".\" + firstName\n\t\t\t}\n\t\t\td := resolveElementRelative(n1, n, querySymbol)\n\t\t\tif d != nil {\n\t\t\t\treturn d\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n}\n\nfunc messageScope(r *result, messageName protoreflect.FullName) scope {\n\tquerySymbol := func(n string) protoreflect.Descriptor {\n\t\treturn resolveElementInFile(protoreflect.FullName(n), r)\n\t}\n\treturn func(firstName, fullName string) protoreflect.Descriptor {\n\t\tn1 := string(messageName) + \".\" + firstName\n\t\tn := string(messageName) + \".\" + fullName\n\t\treturn resolveElementRelative(n1, n, querySymbol)\n\t}\n}\n\nfunc resolveElementRelative(firstName, fullName string, query func(name string) protoreflect.Descriptor) protoreflect.Descriptor {\n\td := query(firstName)\n\tif d == nil {\n\t\treturn nil\n\t}\n\tif firstName == fullName {\n\t\treturn d\n\t}\n\tif !isAggregateDescriptor(d) {\n\t\t// can't possibly find the rest of full name if\n\t\t// the first name indicated a leaf descriptor\n\t\treturn nil\n\t}\n\td = query(fullName)\n\tif d == nil {\n\t\treturn newSentinelDescriptor(fullName)\n\t}\n\treturn d\n}\n\nfunc resolveElementInFile(name protoreflect.FullName, f File) protoreflect.Descriptor {\n\td := f.FindDescriptorByName(name)\n\tif d != nil {\n\t\treturn d\n\t}\n\n\tif matchesPkgNamespace(name, f.Package()) {\n\t\t// this sentinel means the name is a valid namespace but\n\t\t// does not refer to a descriptor\n\t\treturn newSentinelDescriptor(string(name))\n\t}\n\treturn nil\n}\n\nfunc matchesPkgNamespace(fqn, pkg protoreflect.FullName) bool {\n\tif pkg == \"\" {\n\t\treturn false\n\t}\n\tif fqn == pkg {\n\t\treturn true\n\t}\n\tif len(pkg) > len(fqn) && strings.HasPrefix(string(pkg), string(fqn)) {\n\t\t// if char after fqn is a dot, then fqn is a namespace\n\t\tif pkg[len(fqn)] == '.' {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc isAggregateDescriptor(d protoreflect.Descriptor) bool {\n\tif isSentinelDescriptor(d) {\n\t\t// this indicates the name matched a package, not a\n\t\t// descriptor, but a package is an aggregate, so\n\t\t// we return true\n\t\treturn true\n\t}\n\tswitch d.(type) {\n\tcase protoreflect.MessageDescriptor, protoreflect.EnumDescriptor, protoreflect.ServiceDescriptor:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc isSentinelDescriptor(d protoreflect.Descriptor) bool {\n\t_, ok := d.(*sentinelDescriptor)\n\treturn ok\n}\n\nfunc newSentinelDescriptor(name string) protoreflect.Descriptor {\n\treturn &sentinelDescriptor{name: name}\n}\n\n// sentinelDescriptor is a placeholder descriptor. It is used instead of nil to\n// distinguish between two situations:\n//  1. The given name could not be found.\n//  2. The given name *cannot* be a valid result so stop searching.\n//\n// In these cases, attempts to resolve an element name will return nil for the\n// first case and will return a sentinelDescriptor in the second. The sentinel\n// contains the fully-qualified name which caused the search to stop (which may\n// be a prefix of the actual name being resolved).\ntype sentinelDescriptor struct {\n\tprotoreflect.Descriptor\n\tname string\n}\n\nfunc (p *sentinelDescriptor) ParentFile() protoreflect.FileDescriptor {\n\treturn nil\n}\n\nfunc (p *sentinelDescriptor) Parent() protoreflect.Descriptor {\n\treturn nil\n}\n\nfunc (p *sentinelDescriptor) Index() int {\n\treturn 0\n}\n\nfunc (p *sentinelDescriptor) Syntax() protoreflect.Syntax {\n\treturn 0\n}\n\nfunc (p *sentinelDescriptor) Name() protoreflect.Name {\n\treturn protoreflect.Name(p.name)\n}\n\nfunc (p *sentinelDescriptor) FullName() protoreflect.FullName {\n\treturn protoreflect.FullName(p.name)\n}\n\nfunc (p *sentinelDescriptor) IsPlaceholder() bool {\n\treturn false\n}\n\nfunc (p *sentinelDescriptor) Options() protoreflect.ProtoMessage {\n\treturn nil\n}\n\nvar _ protoreflect.Descriptor = (*sentinelDescriptor)(nil)\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/symbols.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage linker\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n\t\"github.com/bufbuild/protocompile/protoutil\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n\t\"github.com/bufbuild/protocompile/walk\"\n)\n\nconst unknownFilePath = \"<unknown file>\"\n\n// Symbols is a symbol table that maps names for all program elements to their\n// location in source. It also tracks extension tag numbers. This can be used\n// to enforce uniqueness for symbol names and tag numbers across many files and\n// many link operations.\n//\n// This type is thread-safe.\ntype Symbols struct {\n\tpkgTrie packageSymbols\n\n\t// We don't know the packages for these symbols, so we can't\n\t// keep them in the pkgTrie. In vast majority of cases, this\n\t// will always be empty/unused. When used, it ensures that\n\t// multiple extension declarations don't refer to the same\n\t// extension.\n\textDeclsMu sync.Mutex\n\textDecls   map[protoreflect.FullName]extDecl\n}\n\ntype packageSymbols struct {\n\tmu       sync.RWMutex\n\tchildren map[protoreflect.FullName]*packageSymbols\n\tfiles    map[protoreflect.FileDescriptor]struct{}\n\tsymbols  map[protoreflect.FullName]symbolEntry\n\texts     map[extNumber]ast.SourceSpan\n}\n\ntype extNumber struct {\n\textendee protoreflect.FullName\n\ttag      protoreflect.FieldNumber\n}\n\ntype symbolEntry struct {\n\tspan        ast.SourceSpan\n\tisEnumValue bool\n\tisPackage   bool\n}\n\ntype extDecl struct {\n\tspan     ast.SourceSpan\n\textendee protoreflect.FullName\n\ttag      protoreflect.FieldNumber\n}\n\n// Import populates the symbol table with all symbols/elements and extension\n// tags present in the given file descriptor. If s is nil or if fd has already\n// been imported into s, this returns immediately without doing anything. If any\n// collisions in symbol names or extension tags are identified, an error will be\n// returned and the symbol table will not be updated.\nfunc (s *Symbols) Import(fd protoreflect.FileDescriptor, handler *reporter.Handler) error {\n\tif s == nil {\n\t\treturn nil\n\t}\n\n\tif f, ok := fd.(protoreflect.FileImport); ok {\n\t\t// unwrap any import instance\n\t\tfd = f.FileDescriptor\n\t}\n\tif f, ok := fd.(*file); ok {\n\t\t// unwrap any file instance\n\t\tfd = f.FileDescriptor\n\t}\n\n\tvar pkgSpan ast.SourceSpan\n\tif res, ok := fd.(*result); ok {\n\t\tpkgSpan = packageNameSpan(res)\n\t} else {\n\t\tpkgSpan = sourceSpanForPackage(fd)\n\t}\n\tpkg, err := s.importPackages(pkgSpan, fd.Package(), handler)\n\tif err != nil || pkg == nil {\n\t\treturn err\n\t}\n\n\tpkg.mu.RLock()\n\t_, alreadyImported := pkg.files[fd]\n\tpkg.mu.RUnlock()\n\n\tif alreadyImported {\n\t\treturn nil\n\t}\n\n\tfor i := 0; i < fd.Imports().Len(); i++ {\n\t\tif err := s.Import(fd.Imports().Get(i).FileDescriptor, handler); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif res, ok := fd.(*result); ok && res.hasSource() {\n\t\treturn s.importResultWithExtensions(pkg, res, handler)\n\t}\n\n\treturn s.importFileWithExtensions(pkg, fd, handler)\n}\n\nfunc (s *Symbols) importFileWithExtensions(pkg *packageSymbols, fd protoreflect.FileDescriptor, handler *reporter.Handler) error {\n\timported, err := pkg.importFile(fd, handler)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !imported {\n\t\t// nothing else to do\n\t\treturn nil\n\t}\n\n\treturn walk.Descriptors(fd, func(d protoreflect.Descriptor) error {\n\t\tfld, ok := d.(protoreflect.FieldDescriptor)\n\t\tif !ok || !fld.IsExtension() {\n\t\t\treturn nil\n\t\t}\n\t\tspan := sourceSpanForNumber(fld)\n\t\textendee := fld.ContainingMessage()\n\t\treturn s.AddExtension(packageFor(extendee), extendee.FullName(), fld.Number(), span, handler)\n\t})\n}\n\nfunc (s *packageSymbols) importFile(fd protoreflect.FileDescriptor, handler *reporter.Handler) (bool, error) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tif _, ok := s.files[fd]; ok {\n\t\t// have to double-check if it's already imported, in case\n\t\t// it was added after above read-locked check\n\t\treturn false, nil\n\t}\n\n\t// first pass: check for conflicts\n\tif err := s.checkFileLocked(fd, handler); err != nil {\n\t\treturn false, err\n\t}\n\tif err := handler.Error(); err != nil {\n\t\treturn false, err\n\t}\n\n\t// second pass: commit all symbols\n\ts.commitFileLocked(fd)\n\n\treturn true, nil\n}\n\nfunc (s *Symbols) importPackages(pkgSpan ast.SourceSpan, pkg protoreflect.FullName, handler *reporter.Handler) (*packageSymbols, error) {\n\tif pkg == \"\" {\n\t\treturn &s.pkgTrie, nil\n\t}\n\n\tcur := &s.pkgTrie\n\tenumerator := nameEnumerator{name: pkg}\n\tfor {\n\t\tp, ok := enumerator.next()\n\t\tif !ok {\n\t\t\treturn cur, nil\n\t\t}\n\t\tvar err error\n\t\tcur, err = cur.importPackage(pkgSpan, p, handler)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif cur == nil {\n\t\t\treturn nil, nil\n\t\t}\n\t}\n}\n\nfunc (s *packageSymbols) importPackage(pkgSpan ast.SourceSpan, pkg protoreflect.FullName, handler *reporter.Handler) (*packageSymbols, error) {\n\ts.mu.RLock()\n\texisting, ok := s.symbols[pkg]\n\tvar child *packageSymbols\n\tif ok && existing.isPackage {\n\t\tchild = s.children[pkg]\n\t}\n\ts.mu.RUnlock()\n\n\tif ok && existing.isPackage {\n\t\t// package already exists\n\t\treturn child, nil\n\t} else if ok {\n\t\treturn nil, reportSymbolCollision(pkgSpan, pkg, false, existing, handler)\n\t}\n\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\t// have to double-check in case it was added while upgrading to write lock\n\texisting, ok = s.symbols[pkg]\n\tif ok && existing.isPackage {\n\t\t// package already exists\n\t\treturn s.children[pkg], nil\n\t} else if ok {\n\t\treturn nil, reportSymbolCollision(pkgSpan, pkg, false, existing, handler)\n\t}\n\tif s.symbols == nil {\n\t\ts.symbols = map[protoreflect.FullName]symbolEntry{}\n\t}\n\ts.symbols[pkg] = symbolEntry{span: pkgSpan, isPackage: true}\n\tchild = &packageSymbols{}\n\tif s.children == nil {\n\t\ts.children = map[protoreflect.FullName]*packageSymbols{}\n\t}\n\ts.children[pkg] = child\n\treturn child, nil\n}\n\nfunc (s *Symbols) getPackage(pkg protoreflect.FullName, exact bool) *packageSymbols {\n\tif pkg == \"\" {\n\t\treturn &s.pkgTrie\n\t}\n\tcur := &s.pkgTrie\n\tenumerator := nameEnumerator{name: pkg}\n\tfor {\n\t\tp, ok := enumerator.next()\n\t\tif !ok {\n\t\t\treturn cur\n\t\t}\n\t\tcur.mu.RLock()\n\t\tnext := cur.children[p]\n\t\tcur.mu.RUnlock()\n\n\t\tif next == nil {\n\t\t\tif exact {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn cur\n\t\t}\n\t\tcur = next\n\t}\n}\n\nfunc reportSymbolCollision(span ast.SourceSpan, fqn protoreflect.FullName, additionIsEnumVal bool, existing symbolEntry, handler *reporter.Handler) error {\n\t// because of weird scoping for enum values, provide more context in error message\n\t// if this conflict is with an enum value\n\tvar isPkg, suffix string\n\tif additionIsEnumVal || existing.isEnumValue {\n\t\tsuffix = \"; protobuf uses C++ scoping rules for enum values, so they exist in the scope enclosing the enum\"\n\t}\n\tif existing.isPackage {\n\t\tisPkg = \" as a package\"\n\t}\n\torig := existing.span\n\tconflict := span\n\tif posLess(conflict.Start(), orig.Start()) {\n\t\torig, conflict = conflict, orig\n\t}\n\treturn handler.HandleErrorf(conflict, \"symbol %q already defined%s at %v%s\", fqn, isPkg, orig.Start(), suffix)\n}\n\nfunc posLess(a, b ast.SourcePos) bool {\n\tif a.Filename == b.Filename {\n\t\tif a.Line == b.Line {\n\t\t\treturn a.Col < b.Col\n\t\t}\n\t\treturn a.Line < b.Line\n\t}\n\treturn false\n}\n\nfunc (s *packageSymbols) checkFileLocked(f protoreflect.FileDescriptor, handler *reporter.Handler) error {\n\treturn walk.Descriptors(f, func(d protoreflect.Descriptor) error {\n\t\tspan := sourceSpanFor(d)\n\t\tif existing, ok := s.symbols[d.FullName()]; ok {\n\t\t\t_, isEnumVal := d.(protoreflect.EnumValueDescriptor)\n\t\t\tif err := reportSymbolCollision(span, d.FullName(), isEnumVal, existing, handler); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc sourceSpanForPackage(fd protoreflect.FileDescriptor) ast.SourceSpan {\n\tloc := fd.SourceLocations().ByPath([]int32{internal.FilePackageTag})\n\tif internal.IsZeroLocation(loc) {\n\t\treturn ast.UnknownSpan(fd.Path())\n\t}\n\treturn ast.NewSourceSpan(\n\t\tast.SourcePos{\n\t\t\tFilename: fd.Path(),\n\t\t\tLine:     loc.StartLine,\n\t\t\tCol:      loc.StartColumn,\n\t\t},\n\t\tast.SourcePos{\n\t\t\tFilename: fd.Path(),\n\t\t\tLine:     loc.EndLine,\n\t\t\tCol:      loc.EndColumn,\n\t\t},\n\t)\n}\n\nfunc sourceSpanFor(d protoreflect.Descriptor) ast.SourceSpan {\n\tfile := d.ParentFile()\n\tif file == nil {\n\t\treturn ast.UnknownSpan(unknownFilePath)\n\t}\n\tif result, ok := file.(*result); ok {\n\t\treturn nameSpan(result.FileNode(), result.Node(protoutil.ProtoFromDescriptor(d)))\n\t}\n\tpath, ok := internal.ComputePath(d)\n\tif !ok {\n\t\treturn ast.UnknownSpan(file.Path())\n\t}\n\tnamePath := path\n\tswitch d.(type) {\n\tcase protoreflect.FieldDescriptor:\n\t\tnamePath = append(namePath, internal.FieldNameTag)\n\tcase protoreflect.MessageDescriptor:\n\t\tnamePath = append(namePath, internal.MessageNameTag)\n\tcase protoreflect.OneofDescriptor:\n\t\tnamePath = append(namePath, internal.OneofNameTag)\n\tcase protoreflect.EnumDescriptor:\n\t\tnamePath = append(namePath, internal.EnumNameTag)\n\tcase protoreflect.EnumValueDescriptor:\n\t\tnamePath = append(namePath, internal.EnumValNameTag)\n\tcase protoreflect.ServiceDescriptor:\n\t\tnamePath = append(namePath, internal.ServiceNameTag)\n\tcase protoreflect.MethodDescriptor:\n\t\tnamePath = append(namePath, internal.MethodNameTag)\n\tdefault:\n\t\t// NB: shouldn't really happen, but just in case fall back to path to\n\t\t// descriptor, sans name field\n\t}\n\tloc := file.SourceLocations().ByPath(namePath)\n\tif internal.IsZeroLocation(loc) {\n\t\tloc = file.SourceLocations().ByPath(path)\n\t\tif internal.IsZeroLocation(loc) {\n\t\t\treturn ast.UnknownSpan(file.Path())\n\t\t}\n\t}\n\n\treturn ast.NewSourceSpan(\n\t\tast.SourcePos{\n\t\t\tFilename: file.Path(),\n\t\t\tLine:     loc.StartLine,\n\t\t\tCol:      loc.StartColumn,\n\t\t},\n\t\tast.SourcePos{\n\t\t\tFilename: file.Path(),\n\t\t\tLine:     loc.EndLine,\n\t\t\tCol:      loc.EndColumn,\n\t\t},\n\t)\n}\n\nfunc sourceSpanForNumber(fd protoreflect.FieldDescriptor) ast.SourceSpan {\n\tfile := fd.ParentFile()\n\tif file == nil {\n\t\treturn ast.UnknownSpan(unknownFilePath)\n\t}\n\tpath, ok := internal.ComputePath(fd)\n\tif !ok {\n\t\treturn ast.UnknownSpan(file.Path())\n\t}\n\tnumberPath := path\n\tnumberPath = append(numberPath, internal.FieldNumberTag)\n\tloc := file.SourceLocations().ByPath(numberPath)\n\tif internal.IsZeroLocation(loc) {\n\t\tloc = file.SourceLocations().ByPath(path)\n\t\tif internal.IsZeroLocation(loc) {\n\t\t\treturn ast.UnknownSpan(file.Path())\n\t\t}\n\t}\n\treturn ast.NewSourceSpan(\n\t\tast.SourcePos{\n\t\t\tFilename: file.Path(),\n\t\t\tLine:     loc.StartLine,\n\t\t\tCol:      loc.StartColumn,\n\t\t},\n\t\tast.SourcePos{\n\t\t\tFilename: file.Path(),\n\t\t\tLine:     loc.EndLine,\n\t\t\tCol:      loc.EndColumn,\n\t\t},\n\t)\n}\n\nfunc (s *packageSymbols) commitFileLocked(f protoreflect.FileDescriptor) {\n\tif s.symbols == nil {\n\t\ts.symbols = map[protoreflect.FullName]symbolEntry{}\n\t}\n\tif s.exts == nil {\n\t\ts.exts = map[extNumber]ast.SourceSpan{}\n\t}\n\t_ = walk.Descriptors(f, func(d protoreflect.Descriptor) error {\n\t\tspan := sourceSpanFor(d)\n\t\tname := d.FullName()\n\t\t_, isEnumValue := d.(protoreflect.EnumValueDescriptor)\n\t\ts.symbols[name] = symbolEntry{span: span, isEnumValue: isEnumValue}\n\t\treturn nil\n\t})\n\n\tif s.files == nil {\n\t\ts.files = map[protoreflect.FileDescriptor]struct{}{}\n\t}\n\ts.files[f] = struct{}{}\n}\n\nfunc (s *Symbols) importResultWithExtensions(pkg *packageSymbols, r *result, handler *reporter.Handler) error {\n\timported, err := pkg.importResult(r, handler)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif !imported {\n\t\t// nothing else to do\n\t\treturn nil\n\t}\n\n\treturn walk.Descriptors(r, func(d protoreflect.Descriptor) error {\n\t\tfd, ok := d.(*extTypeDescriptor)\n\t\tif !ok {\n\t\t\treturn nil\n\t\t}\n\t\tfile := r.FileNode()\n\t\tnode := r.FieldNode(fd.FieldDescriptorProto())\n\t\tinfo := file.NodeInfo(node.FieldTag())\n\t\textendee := fd.ContainingMessage()\n\t\treturn s.AddExtension(packageFor(extendee), extendee.FullName(), fd.Number(), info, handler)\n\t})\n}\n\nfunc (s *Symbols) importResult(r *result, handler *reporter.Handler) error {\n\tpkg, err := s.importPackages(packageNameSpan(r), r.Package(), handler)\n\tif err != nil || pkg == nil {\n\t\treturn err\n\t}\n\t_, err = pkg.importResult(r, handler)\n\treturn err\n}\n\nfunc (s *packageSymbols) importResult(r *result, handler *reporter.Handler) (bool, error) {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tif _, ok := s.files[r]; ok {\n\t\t// already imported\n\t\treturn false, nil\n\t}\n\n\t// first pass: check for conflicts\n\tif err := s.checkResultLocked(r, handler); err != nil {\n\t\treturn false, err\n\t}\n\tif err := handler.Error(); err != nil {\n\t\treturn false, err\n\t}\n\n\t// second pass: commit all symbols\n\ts.commitFileLocked(r)\n\n\treturn true, nil\n}\n\nfunc (s *packageSymbols) checkResultLocked(r *result, handler *reporter.Handler) error {\n\tresultSyms := map[protoreflect.FullName]symbolEntry{}\n\treturn walk.Descriptors(r, func(d protoreflect.Descriptor) error {\n\t\t_, isEnumVal := d.(protoreflect.EnumValueDescriptor)\n\t\tfile := r.FileNode()\n\t\tname := d.FullName()\n\t\tnode := r.Node(protoutil.ProtoFromDescriptor(d))\n\t\tspan := nameSpan(file, node)\n\t\t// check symbols already in this symbol table\n\t\tif existing, ok := s.symbols[name]; ok {\n\t\t\tif err := reportSymbolCollision(span, name, isEnumVal, existing, handler); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// also check symbols from this result (that are not yet in symbol table)\n\t\tif existing, ok := resultSyms[name]; ok {\n\t\t\tif err := reportSymbolCollision(span, name, isEnumVal, existing, handler); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tresultSyms[name] = symbolEntry{\n\t\t\tspan:        span,\n\t\t\tisEnumValue: isEnumVal,\n\t\t}\n\n\t\treturn nil\n\t})\n}\n\nfunc packageNameSpan(r *result) ast.SourceSpan {\n\tif node, ok := r.FileNode().(*ast.FileNode); ok {\n\t\tfor _, decl := range node.Decls {\n\t\t\tif pkgNode, ok := decl.(*ast.PackageNode); ok {\n\t\t\t\treturn r.FileNode().NodeInfo(pkgNode.Name)\n\t\t\t}\n\t\t}\n\t}\n\treturn ast.UnknownSpan(r.Path())\n}\n\nfunc nameSpan(file ast.FileDeclNode, n ast.Node) ast.SourceSpan {\n\t// TODO: maybe ast package needs a NamedNode interface to simplify this?\n\tswitch n := n.(type) {\n\tcase ast.FieldDeclNode:\n\t\treturn file.NodeInfo(n.FieldName())\n\tcase ast.MessageDeclNode:\n\t\treturn file.NodeInfo(n.MessageName())\n\tcase ast.OneofDeclNode:\n\t\treturn file.NodeInfo(n.OneofName())\n\tcase ast.EnumValueDeclNode:\n\t\treturn file.NodeInfo(n.GetName())\n\tcase *ast.EnumNode:\n\t\treturn file.NodeInfo(n.Name)\n\tcase *ast.ServiceNode:\n\t\treturn file.NodeInfo(n.Name)\n\tcase ast.RPCDeclNode:\n\t\treturn file.NodeInfo(n.GetName())\n\tdefault:\n\t\treturn file.NodeInfo(n)\n\t}\n}\n\n// AddExtension records the given extension, which is used to ensure that no two files\n// attempt to extend the same message using the same tag. The given pkg should be the\n// package that defines extendee.\nfunc (s *Symbols) AddExtension(pkg, extendee protoreflect.FullName, tag protoreflect.FieldNumber, span ast.SourceSpan, handler *reporter.Handler) error {\n\tif pkg != \"\" {\n\t\tif !strings.HasPrefix(string(extendee), string(pkg)+\".\") {\n\t\t\treturn handler.HandleErrorf(span, \"could not register extension: extendee %q does not match package %q\", extendee, pkg)\n\t\t}\n\t}\n\tpkgSyms := s.getPackage(pkg, true)\n\tif pkgSyms == nil {\n\t\t// should never happen\n\t\treturn handler.HandleErrorf(span, \"could not register extension: missing package symbols for %q\", pkg)\n\t}\n\treturn pkgSyms.addExtension(extendee, tag, span, handler)\n}\n\nfunc (s *packageSymbols) addExtension(extendee protoreflect.FullName, tag protoreflect.FieldNumber, span ast.SourceSpan, handler *reporter.Handler) error {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\textNum := extNumber{extendee: extendee, tag: tag}\n\tif existing, ok := s.exts[extNum]; ok {\n\t\treturn handler.HandleErrorf(span, \"extension with tag %d for message %s already defined at %v\", tag, extendee, existing.Start())\n\t}\n\n\tif s.exts == nil {\n\t\ts.exts = map[extNumber]ast.SourceSpan{}\n\t}\n\ts.exts[extNum] = span\n\treturn nil\n}\n\n// AddExtensionDeclaration records the given extension declaration, which is used to\n// ensure that no two declarations refer to the same extension.\nfunc (s *Symbols) AddExtensionDeclaration(extension, extendee protoreflect.FullName, tag protoreflect.FieldNumber, span ast.SourceSpan, handler *reporter.Handler) error {\n\ts.extDeclsMu.Lock()\n\tdefer s.extDeclsMu.Unlock()\n\texisting, ok := s.extDecls[extension]\n\tif ok {\n\t\tif existing.extendee == extendee && existing.tag == tag {\n\t\t\t// This is a declaration that has already been added. Ignore.\n\t\t\treturn nil\n\t\t}\n\t\treturn handler.HandleErrorf(span, \"extension %s already declared as extending %s with tag %d at %v\", extension, existing.extendee, existing.tag, existing.span.Start())\n\t}\n\tif s.extDecls == nil {\n\t\ts.extDecls = map[protoreflect.FullName]extDecl{}\n\t}\n\ts.extDecls[extension] = extDecl{\n\t\tspan:     span,\n\t\textendee: extendee,\n\t\ttag:      tag,\n\t}\n\treturn nil\n}\n\n// Lookup finds the registered location of the given name. If the given name has\n// not been seen/registered, nil is returned.\nfunc (s *Symbols) Lookup(name protoreflect.FullName) ast.SourceSpan {\n\t// note: getPackage never returns nil when exact=false\n\tpkgSyms := s.getPackage(name, false)\n\tif entry, ok := pkgSyms.symbols[name]; ok {\n\t\treturn entry.span\n\t}\n\treturn nil\n}\n\n// LookupExtension finds the registered location of the given extension. If the given\n// extension has not been seen/registered, nil is returned.\nfunc (s *Symbols) LookupExtension(messageName protoreflect.FullName, extensionNumber protoreflect.FieldNumber) ast.SourceSpan {\n\t// note: getPackage never returns nil when exact=false\n\tpkgSyms := s.getPackage(messageName, false)\n\treturn pkgSyms.exts[extNumber{messageName, extensionNumber}]\n}\n\ntype nameEnumerator struct {\n\tname  protoreflect.FullName\n\tstart int\n}\n\nfunc (e *nameEnumerator) next() (protoreflect.FullName, bool) {\n\tif e.start < 0 {\n\t\treturn \"\", false\n\t}\n\tpos := strings.IndexByte(string(e.name[e.start:]), '.')\n\tif pos == -1 {\n\t\te.start = -1\n\t\treturn e.name, true\n\t}\n\tpos += e.start\n\te.start = pos + 1\n\treturn e.name[:pos], true\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/linker/validate.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage linker\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n\t\"github.com/bufbuild/protocompile/protoutil\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n\t\"github.com/bufbuild/protocompile/walk\"\n)\n\n// ValidateOptions runs some validation checks on the result that can only\n// be done after options are interpreted.\nfunc (r *result) ValidateOptions(handler *reporter.Handler, symbols *Symbols) error {\n\tif err := r.validateFile(handler); err != nil {\n\t\treturn err\n\t}\n\treturn walk.Descriptors(r, func(d protoreflect.Descriptor) error {\n\t\tswitch d := d.(type) {\n\t\tcase protoreflect.FieldDescriptor:\n\t\t\tif err := r.validateField(d, handler); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase protoreflect.MessageDescriptor:\n\t\t\tif symbols == nil {\n\t\t\t\tsymbols = &Symbols{}\n\t\t\t}\n\t\t\tif err := r.validateMessage(d, handler, symbols); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase protoreflect.EnumDescriptor:\n\t\t\tif err := r.validateEnum(d, handler); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc (r *result) validateFile(handler *reporter.Handler) error {\n\topts := r.FileDescriptorProto().GetOptions()\n\tif opts.GetOptimizeFor() != descriptorpb.FileOptions_LITE_RUNTIME {\n\t\t// Non-lite files may not import lite files.\n\t\timports := r.Imports()\n\t\tfor i, length := 0, imports.Len(); i < length; i++ {\n\t\t\tdep := imports.Get(i)\n\t\t\tdepOpts, ok := dep.Options().(*descriptorpb.FileOptions)\n\t\t\tif !ok {\n\t\t\t\tcontinue // what else to do?\n\t\t\t}\n\t\t\tif depOpts.GetOptimizeFor() == descriptorpb.FileOptions_LITE_RUNTIME {\n\t\t\t\terr := handler.HandleErrorf(r.getImportLocation(dep.Path()), \"a file that does not use optimize_for=LITE_RUNTIME may not import file %q that does\", dep.Path())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif isEditions(r) {\n\t\t// Validate features\n\t\tif opts.GetFeatures().GetFieldPresence() == descriptorpb.FeatureSet_LEGACY_REQUIRED {\n\t\t\tspan := r.findOptionSpan(r, internal.FileOptionsFeaturesTag, internal.FeatureSetFieldPresenceTag)\n\t\t\terr := handler.HandleErrorf(span, \"LEGACY_REQUIRED field presence cannot be set as the default for a file\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif opts != nil && opts.JavaStringCheckUtf8 != nil {\n\t\t\tspan := r.findOptionSpan(r, internal.FileOptionsJavaStringCheckUTF8Tag)\n\t\t\terr := handler.HandleErrorf(span, `file option java_string_check_utf8 is not allowed with editions; import \"google/protobuf/java_features.proto\" and use (pb.java).utf8_validation instead`)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *result) validateField(fld protoreflect.FieldDescriptor, handler *reporter.Handler) error {\n\tif xtd, ok := fld.(protoreflect.ExtensionTypeDescriptor); ok {\n\t\tfld = xtd.Descriptor()\n\t}\n\tfd, ok := fld.(*fldDescriptor)\n\tif !ok {\n\t\t// should not be possible\n\t\treturn fmt.Errorf(\"field descriptor is wrong type: expecting %T, got %T\", (*fldDescriptor)(nil), fld)\n\t}\n\n\tif err := r.validatePacked(fd, handler); err != nil {\n\t\treturn err\n\t}\n\tif fd.Kind() == protoreflect.EnumKind {\n\t\trequiresOpen := !fd.IsList() && !fd.HasPresence()\n\t\tif requiresOpen && fd.Enum().IsClosed() {\n\t\t\t// Fields in a proto3 message cannot refer to proto2 enums.\n\t\t\t// In editions, this translates to implicit presence fields\n\t\t\t// not being able to refer to closed enums.\n\t\t\t// TODO: This really should be based solely on whether the enum's first\n\t\t\t//       value is zero, NOT based on if it's open vs closed.\n\t\t\t//       https://github.com/protocolbuffers/protobuf/issues/16249\n\t\t\tfile := r.FileNode()\n\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldType())\n\t\t\tif err := handler.HandleErrorf(info, \"cannot use closed enum %s in a field with implicit presence\", fd.Enum().FullName()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif fd.HasDefault() && !fd.HasPresence() {\n\t\tspan := r.findScalarOptionSpan(r.FieldNode(fd.proto), \"default\")\n\t\terr := handler.HandleErrorf(span, \"default value is not allowed on fields with implicit presence\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif fd.proto.Options != nil && fd.proto.Options.Ctype != nil {\n\t\tif descriptorpb.Edition(r.Edition()) >= descriptorpb.Edition_EDITION_2024 {\n\t\t\t// We don't support edition 2024 yet, but we went ahead and mimic'ed this check\n\t\t\t// from protoc, which currently has experimental support for 2024.\n\t\t\tspan := r.findOptionSpan(fd, internal.FieldOptionsCTypeTag)\n\t\t\tif err := handler.HandleErrorf(span, \"ctype option cannot be used as of edition 2024; use features.string_type instead\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if descriptorpb.Edition(r.Edition()) == descriptorpb.Edition_EDITION_2023 {\n\t\t\tif fld.Kind() != protoreflect.StringKind && fld.Kind() != protoreflect.BytesKind {\n\t\t\t\tspan := r.findOptionSpan(fd, internal.FieldOptionsCTypeTag)\n\t\t\t\tif err := handler.HandleErrorf(span, \"ctype option can only be used on string and bytes fields\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif fd.proto.Options.GetCtype() == descriptorpb.FieldOptions_CORD && fd.IsExtension() {\n\t\t\t\tspan := r.findOptionSpan(fd, internal.FieldOptionsCTypeTag)\n\t\t\t\tif err := handler.HandleErrorf(span, \"ctype option cannot be CORD for extension fields\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (fd.proto.Options.GetLazy() || fd.proto.Options.GetUnverifiedLazy()) && fd.Kind() != protoreflect.MessageKind {\n\t\tvar span ast.SourceSpan\n\t\tvar optionName string\n\t\tif fd.proto.Options.GetLazy() {\n\t\t\tspan = r.findOptionSpan(fd, internal.FieldOptionsLazyTag)\n\t\t\toptionName = \"lazy\"\n\t\t} else {\n\t\t\tspan = r.findOptionSpan(fd, internal.FieldOptionsUnverifiedLazyTag)\n\t\t\toptionName = \"unverified_lazy\"\n\t\t}\n\t\tvar suffix string\n\t\tif fd.Kind() == protoreflect.GroupKind {\n\t\t\tif isEditions(r) {\n\t\t\t\tsuffix = \" that use length-prefixed encoding\"\n\t\t\t} else {\n\t\t\t\tsuffix = \", not groups\"\n\t\t\t}\n\t\t}\n\t\tif err := handler.HandleErrorf(span, \"%s option can only be used with message fields%s\", optionName, suffix); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif fd.proto.Options.GetJstype() != descriptorpb.FieldOptions_JS_NORMAL {\n\t\tswitch fd.Kind() {\n\t\tcase protoreflect.Int64Kind, protoreflect.Uint64Kind, protoreflect.Sint64Kind,\n\t\t\tprotoreflect.Fixed64Kind, protoreflect.Sfixed64Kind:\n\t\t\t// allowed only for 64-bit integer types\n\t\tdefault:\n\t\t\tspan := r.findOptionSpan(fd, internal.FieldOptionsJSTypeTag)\n\t\t\terr := handler.HandleErrorf(span, \"only 64-bit integer fields (int64, uint64, sint64, fixed64, and sfixed64) can specify a jstype other than JS_NORMAL\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif isEditions(r) {\n\t\tif err := r.validateFieldFeatures(fd, handler); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif fld.IsExtension() {\n\t\t// More checks if this is an extension field.\n\t\tif err := r.validateExtension(fd, handler); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (r *result) validateExtension(fd *fldDescriptor, handler *reporter.Handler) error {\n\t// NB: It's a little gross that we don't enforce these in validateBasic().\n\t// But it requires linking to resolve the extendee, so we can interrogate\n\t// its descriptor.\n\tmsg := fd.ContainingMessage()\n\tif msg.Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat() {\n\t\t// Message set wire format requires that all extensions be messages\n\t\t// themselves (no scalar extensions)\n\t\tif fd.Kind() != protoreflect.MessageKind {\n\t\t\tfile := r.FileNode()\n\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldType())\n\t\t\terr := handler.HandleErrorf(info, \"messages with message-set wire format cannot contain scalar extensions, only messages\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif fd.Cardinality() == protoreflect.Repeated {\n\t\t\tfile := r.FileNode()\n\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldLabel())\n\t\t\terr := handler.HandleErrorf(info, \"messages with message-set wire format cannot contain repeated extensions, only optional\")\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t} else if fd.Number() > internal.MaxNormalTag {\n\t\t// In validateBasic() we just made sure these were within bounds for any message. But\n\t\t// now that things are linked, we can check if the extendee is messageset wire format\n\t\t// and, if not, enforce tighter limit.\n\t\tfile := r.FileNode()\n\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldTag())\n\t\terr := handler.HandleErrorf(info, \"tag number %d is higher than max allowed tag number (%d)\", fd.Number(), internal.MaxNormalTag)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tfileOpts := r.FileDescriptorProto().GetOptions()\n\tif fileOpts.GetOptimizeFor() == descriptorpb.FileOptions_LITE_RUNTIME {\n\t\textendeeFileOpts, _ := msg.ParentFile().Options().(*descriptorpb.FileOptions)\n\t\tif extendeeFileOpts.GetOptimizeFor() != descriptorpb.FileOptions_LITE_RUNTIME {\n\t\t\tfile := r.FileNode()\n\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto))\n\t\t\terr := handler.HandleErrorf(info, \"extensions in a file that uses optimize_for=LITE_RUNTIME may not extend messages in file %q which does not\", msg.ParentFile().Path())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// If the extendee uses extension declarations, make sure this extension matches.\n\tmd := protoutil.ProtoFromMessageDescriptor(msg)\n\tfor i, extRange := range md.ExtensionRange {\n\t\tif int32(fd.Number()) < extRange.GetStart() || int32(fd.Number()) >= extRange.GetEnd() {\n\t\t\tcontinue\n\t\t}\n\t\textRangeOpts := extRange.GetOptions()\n\t\tif extRangeOpts == nil {\n\t\t\tbreak\n\t\t}\n\t\tif len(extRangeOpts.Declaration) == 0 && extRangeOpts.GetVerification() != descriptorpb.ExtensionRangeOptions_DECLARATION {\n\t\t\tbreak\n\t\t}\n\t\tvar found bool\n\t\tfor j, extDecl := range extRangeOpts.Declaration {\n\t\t\tif extDecl.GetNumber() != int32(fd.Number()) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfound = true\n\t\t\tif extDecl.GetReserved() {\n\t\t\t\tfile := r.FileNode()\n\t\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldTag())\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(msg.ParentFile(), msg, i, extRange,\n\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(j), internal.ExtensionRangeOptionsDeclarationReservedTag)\n\t\t\t\terr := handler.HandleErrorf(info, \"cannot use field number %d for an extension because it is reserved in declaration at %v\",\n\t\t\t\t\tfd.Number(), span.Start())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif extDecl.GetFullName() != \".\"+string(fd.FullName()) {\n\t\t\t\tfile := r.FileNode()\n\t\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldName())\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(msg.ParentFile(), msg, i, extRange,\n\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(j), internal.ExtensionRangeOptionsDeclarationFullNameTag)\n\t\t\t\terr := handler.HandleErrorf(info, \"expected extension with number %d to be named %s, not %s, per declaration at %v\",\n\t\t\t\t\tfd.Number(), strings.TrimPrefix(extDecl.GetFullName(), \".\"), fd.FullName(), span.Start())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif extDecl.GetType() != getTypeName(fd) {\n\t\t\t\tfile := r.FileNode()\n\t\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldType())\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(msg.ParentFile(), msg, i, extRange,\n\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(j), internal.ExtensionRangeOptionsDeclarationTypeTag)\n\t\t\t\terr := handler.HandleErrorf(info, \"expected extension with number %d to have type %s, not %s, per declaration at %v\",\n\t\t\t\t\tfd.Number(), strings.TrimPrefix(extDecl.GetType(), \".\"), getTypeName(fd), span.Start())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif extDecl.GetRepeated() != (fd.Cardinality() == protoreflect.Repeated) {\n\t\t\t\texpected, actual := \"repeated\", \"optional\"\n\t\t\t\tif !extDecl.GetRepeated() {\n\t\t\t\t\texpected, actual = actual, expected\n\t\t\t\t}\n\t\t\t\tfile := r.FileNode()\n\t\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldLabel())\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(msg.ParentFile(), msg, i, extRange,\n\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(j), internal.ExtensionRangeOptionsDeclarationRepeatedTag)\n\t\t\t\terr := handler.HandleErrorf(info, \"expected extension with number %d to be %s, not %s, per declaration at %v\",\n\t\t\t\t\tfd.Number(), expected, actual, span.Start())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tif !found {\n\t\t\tfile := r.FileNode()\n\t\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldTag())\n\t\t\tspan, _ := findExtensionRangeOptionSpan(fd.ParentFile(), msg, i, extRange,\n\t\t\t\tinternal.ExtensionRangeOptionsVerificationTag)\n\t\t\terr := handler.HandleErrorf(info, \"expected extension with number %d to be declared in type %s, but no declaration found at %v\",\n\t\t\t\tfd.Number(), fd.ContainingMessage().FullName(), span.Start())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (r *result) validatePacked(fd *fldDescriptor, handler *reporter.Handler) error {\n\tif fd.proto.Options != nil && fd.proto.Options.Packed != nil && isEditions(r) {\n\t\tspan := r.findOptionSpan(fd, internal.FieldOptionsPackedTag)\n\t\terr := handler.HandleErrorf(span, \"packed option cannot be used with editions; use features.repeated_field_encoding=PACKED instead\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif !fd.proto.GetOptions().GetPacked() {\n\t\t// if packed isn't true, nothing to validate\n\t\treturn nil\n\t}\n\tif fd.proto.GetLabel() != descriptorpb.FieldDescriptorProto_LABEL_REPEATED {\n\t\tfile := r.FileNode()\n\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldLabel())\n\t\terr := handler.HandleErrorf(info, \"packed option is only allowed on repeated fields\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tswitch fd.proto.GetType() {\n\tcase descriptorpb.FieldDescriptorProto_TYPE_STRING, descriptorpb.FieldDescriptorProto_TYPE_BYTES,\n\t\tdescriptorpb.FieldDescriptorProto_TYPE_MESSAGE, descriptorpb.FieldDescriptorProto_TYPE_GROUP:\n\t\tfile := r.FileNode()\n\t\tinfo := file.NodeInfo(r.FieldNode(fd.proto).FieldType())\n\t\terr := handler.HandleErrorf(info, \"packed option is only allowed on numeric, boolean, and enum fields\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *result) validateFieldFeatures(fld *fldDescriptor, handler *reporter.Handler) error {\n\tif msg, ok := fld.Parent().(*msgDescriptor); ok && msg.proto.GetOptions().GetMapEntry() {\n\t\t// Skip validating features on fields of synthetic map entry messages.\n\t\t// We blindly propagate them from the map field's features, but some may\n\t\t// really only apply to the map field and not to a key or value entry field.\n\t\treturn nil\n\t}\n\tfeatures := fld.proto.GetOptions().GetFeatures()\n\tif features == nil {\n\t\t// No features to validate.\n\t\treturn nil\n\t}\n\tif features.FieldPresence != nil {\n\t\tswitch {\n\t\tcase fld.proto.OneofIndex != nil:\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetFieldPresenceTag)\n\t\t\tif err := handler.HandleErrorf(span, \"oneof fields may not specify field presence\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase fld.Cardinality() == protoreflect.Repeated:\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetFieldPresenceTag)\n\t\t\tif err := handler.HandleErrorf(span, \"repeated fields may not specify field presence\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase fld.IsExtension():\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetFieldPresenceTag)\n\t\t\tif err := handler.HandleErrorf(span, \"extension fields may not specify field presence\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase fld.Message() != nil && features.GetFieldPresence() == descriptorpb.FeatureSet_IMPLICIT:\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetFieldPresenceTag)\n\t\t\tif err := handler.HandleErrorf(span, \"message fields may not specify implicit presence\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif features.RepeatedFieldEncoding != nil {\n\t\tif fld.Cardinality() != protoreflect.Repeated {\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetRepeatedFieldEncodingTag)\n\t\t\tif err := handler.HandleErrorf(span, \"only repeated fields may specify repeated field encoding\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if !internal.CanPack(fld.Kind()) && features.GetRepeatedFieldEncoding() == descriptorpb.FeatureSet_PACKED {\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetRepeatedFieldEncodingTag)\n\t\t\tif err := handler.HandleErrorf(span, \"only repeated primitive fields may specify packed encoding\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif features.Utf8Validation != nil {\n\t\tisMap := fld.IsMap()\n\t\tif (!isMap && fld.Kind() != protoreflect.StringKind) ||\n\t\t\t(isMap &&\n\t\t\t\tfld.MapKey().Kind() != protoreflect.StringKind &&\n\t\t\t\tfld.MapValue().Kind() != protoreflect.StringKind) {\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetUTF8ValidationTag)\n\t\t\tif err := handler.HandleErrorf(span, \"only string fields may specify UTF8 validation\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif features.MessageEncoding != nil {\n\t\tif fld.Message() == nil || fld.IsMap() {\n\t\t\tspan := r.findOptionSpan(fld, internal.FieldOptionsFeaturesTag, internal.FeatureSetMessageEncodingTag)\n\t\t\tif err := handler.HandleErrorf(span, \"only message fields may specify message encoding\"); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *result) validateMessage(d protoreflect.MessageDescriptor, handler *reporter.Handler, symbols *Symbols) error {\n\tmd, ok := d.(*msgDescriptor)\n\tif !ok {\n\t\t// should not be possible\n\t\treturn fmt.Errorf(\"message descriptor is wrong type: expecting %T, got %T\", (*msgDescriptor)(nil), d)\n\t}\n\n\tif err := r.validateJSONNamesInMessage(md, handler); err != nil {\n\t\treturn err\n\t}\n\n\treturn r.validateExtensionDeclarations(md, handler, symbols)\n}\n\nfunc (r *result) validateJSONNamesInMessage(md *msgDescriptor, handler *reporter.Handler) error {\n\tif err := r.validateFieldJSONNames(md, false, handler); err != nil {\n\t\treturn err\n\t}\n\tif err := r.validateFieldJSONNames(md, true, handler); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc (r *result) validateEnum(d protoreflect.EnumDescriptor, handler *reporter.Handler) error {\n\ted, ok := d.(*enumDescriptor)\n\tif !ok {\n\t\t// should not be possible\n\t\treturn fmt.Errorf(\"enum descriptor is wrong type: expecting %T, got %T\", (*enumDescriptor)(nil), d)\n\t}\n\n\tfirstValue := ed.Values().Get(0)\n\tif !ed.IsClosed() && firstValue.Number() != 0 {\n\t\t// TODO: This check doesn't really belong here. Whether the\n\t\t//       first value is zero s/b orthogonal to whether the\n\t\t//       allowed values are open or closed.\n\t\t//       https://github.com/protocolbuffers/protobuf/issues/16249\n\t\tfile := r.FileNode()\n\t\tevd, ok := firstValue.(*enValDescriptor)\n\t\tif !ok {\n\t\t\t// should not be possible\n\t\t\treturn fmt.Errorf(\"enum value descriptor is wrong type: expecting %T, got %T\", (*enValDescriptor)(nil), firstValue)\n\t\t}\n\t\tinfo := file.NodeInfo(r.EnumValueNode(evd.proto).GetNumber())\n\t\tif err := handler.HandleErrorf(info, \"first value of open enum %s must have numeric value zero\", ed.FullName()); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := r.validateJSONNamesInEnum(ed, handler); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (r *result) validateJSONNamesInEnum(ed *enumDescriptor, handler *reporter.Handler) error {\n\tseen := map[string]*descriptorpb.EnumValueDescriptorProto{}\n\tfor _, evd := range ed.proto.GetValue() {\n\t\tscope := \"enum value \" + ed.proto.GetName() + \".\" + evd.GetName()\n\n\t\tname := canonicalEnumValueName(evd.GetName(), ed.proto.GetName())\n\t\tif existing, ok := seen[name]; ok && evd.GetNumber() != existing.GetNumber() {\n\t\t\tfldNode := r.EnumValueNode(evd)\n\t\t\texistingNode := r.EnumValueNode(existing)\n\t\t\tconflictErr := fmt.Errorf(\"%s: camel-case name (with optional enum name prefix removed) %q conflicts with camel-case name of enum value %s, defined at %v\",\n\t\t\t\tscope, name, existing.GetName(), r.FileNode().NodeInfo(existingNode).Start())\n\n\t\t\t// Since proto2 did not originally have a JSON format, we report conflicts as just warnings.\n\t\t\t// With editions, not fully supporting JSON is allowed via feature: json_format == BEST_EFFORT\n\t\t\tif !isJSONCompliant(ed) {\n\t\t\t\thandler.HandleWarningWithPos(r.FileNode().NodeInfo(fldNode), conflictErr)\n\t\t\t} else if err := handler.HandleErrorWithPos(r.FileNode().NodeInfo(fldNode), conflictErr); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else {\n\t\t\tseen[name] = evd\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *result) validateFieldJSONNames(md *msgDescriptor, useCustom bool, handler *reporter.Handler) error {\n\ttype jsonName struct {\n\t\tsource *descriptorpb.FieldDescriptorProto\n\t\t// true if orig is a custom JSON name (vs. the field's default JSON name)\n\t\tcustom bool\n\t}\n\tseen := map[string]jsonName{}\n\n\tfor _, fd := range md.proto.GetField() {\n\t\tscope := \"field \" + md.proto.GetName() + \".\" + fd.GetName()\n\t\tdefaultName := internal.JSONName(fd.GetName())\n\t\tname := defaultName\n\t\tcustom := false\n\t\tif useCustom {\n\t\t\tn := fd.GetJsonName()\n\t\t\tif n != defaultName || r.hasCustomJSONName(fd) {\n\t\t\t\tname = n\n\t\t\t\tcustom = true\n\t\t\t}\n\t\t}\n\t\tif existing, ok := seen[name]; ok {\n\t\t\t// When useCustom is true, we'll only report an issue when a conflict is\n\t\t\t// due to a custom name. That way, we don't double report conflicts on\n\t\t\t// non-custom names.\n\t\t\tif !useCustom || custom || existing.custom {\n\t\t\t\tfldNode := r.FieldNode(fd)\n\t\t\t\tcustomStr, srcCustomStr := \"custom\", \"custom\"\n\t\t\t\tif !custom {\n\t\t\t\t\tcustomStr = \"default\"\n\t\t\t\t}\n\t\t\t\tif !existing.custom {\n\t\t\t\t\tsrcCustomStr = \"default\"\n\t\t\t\t}\n\t\t\t\tinfo := r.FileNode().NodeInfo(fldNode)\n\t\t\t\tconflictErr := reporter.Errorf(info, \"%s: %s JSON name %q conflicts with %s JSON name of field %s, defined at %v\",\n\t\t\t\t\tscope, customStr, name, srcCustomStr, existing.source.GetName(), r.FileNode().NodeInfo(r.FieldNode(existing.source)).Start())\n\n\t\t\t\t// Since proto2 did not originally have default JSON names, we report conflicts\n\t\t\t\t// between default names (neither is a custom name) as just warnings.\n\t\t\t\t// With editions, not fully supporting JSON is allowed via feature: json_format == BEST_EFFORT\n\t\t\t\tif !isJSONCompliant(md) && !custom && !existing.custom {\n\t\t\t\t\thandler.HandleWarning(conflictErr)\n\t\t\t\t} else if err := handler.HandleError(conflictErr); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tseen[name] = jsonName{source: fd, custom: custom}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *result) validateExtensionDeclarations(md *msgDescriptor, handler *reporter.Handler, symbols *Symbols) error {\n\tfor i, extRange := range md.proto.ExtensionRange {\n\t\topts := extRange.GetOptions()\n\t\tif len(opts.GetDeclaration()) == 0 {\n\t\t\t// nothing to check\n\t\t\tcontinue\n\t\t}\n\t\t// If any declarations are present, verification is assumed to be\n\t\t// DECLARATION. It's an error for declarations to be present but the\n\t\t// verification field explicitly set to something other than that.\n\t\tif opts.Verification != nil && opts.GetVerification() != descriptorpb.ExtensionRangeOptions_DECLARATION {\n\t\t\tspan, ok := findExtensionRangeOptionSpan(r, md, i, extRange, internal.ExtensionRangeOptionsVerificationTag)\n\t\t\tif !ok {\n\t\t\t\tspan, _ = findExtensionRangeOptionSpan(r, md, i, extRange, internal.ExtensionRangeOptionsDeclarationTag, 0)\n\t\t\t}\n\t\t\tif err := handler.HandleErrorf(span, \"extension range cannot have declarations and have verification of %s\", opts.GetVerification()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tdeclsByTag := map[int32]ast.SourcePos{}\n\t\tfor i, extDecl := range extRange.GetOptions().GetDeclaration() {\n\t\t\tif extDecl.Number == nil {\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(r, md, i, extRange, internal.ExtensionRangeOptionsDeclarationTag, int32(i))\n\t\t\t\tif err := handler.HandleErrorf(span, \"extension declaration is missing required field number\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\textensionNumberSpan, _ := findExtensionRangeOptionSpan(r, md, i, extRange,\n\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(i), internal.ExtensionRangeOptionsDeclarationNumberTag)\n\t\t\t\tif extDecl.GetNumber() < extRange.GetStart() || extDecl.GetNumber() >= extRange.GetEnd() {\n\t\t\t\t\t// Number is out of range.\n\t\t\t\t\t// See if one of the other ranges on the same extends statement includes the number,\n\t\t\t\t\t// so we can provide a helpful message.\n\t\t\t\t\tvar suffix string\n\t\t\t\t\tif extRange, ok := r.ExtensionsNode(extRange).(*ast.ExtensionRangeNode); ok {\n\t\t\t\t\t\tfor _, rng := range extRange.Ranges {\n\t\t\t\t\t\t\tstart, _ := rng.StartVal.AsInt64()\n\t\t\t\t\t\t\tvar end int64\n\t\t\t\t\t\t\tswitch {\n\t\t\t\t\t\t\tcase rng.Max != nil:\n\t\t\t\t\t\t\t\tend = math.MaxInt64\n\t\t\t\t\t\t\tcase rng.EndVal != nil:\n\t\t\t\t\t\t\t\tend, _ = rng.EndVal.AsInt64()\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tend = start\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif int64(extDecl.GetNumber()) >= start && int64(extDecl.GetNumber()) <= end {\n\t\t\t\t\t\t\t\t// Found another range that matches\n\t\t\t\t\t\t\t\tsuffix = \"; when using declarations, extends statements should indicate only a single span of field numbers\"\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\terr := handler.HandleErrorf(extensionNumberSpan, \"extension declaration has number outside the range: %d not in [%d,%d]%s\",\n\t\t\t\t\t\textDecl.GetNumber(), extRange.GetStart(), extRange.GetEnd()-1, suffix)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Valid number; make sure it's not a duplicate\n\t\t\t\t\tif existing, ok := declsByTag[extDecl.GetNumber()]; ok {\n\t\t\t\t\t\terr := handler.HandleErrorf(extensionNumberSpan, \"extension for tag number %d already declared at %v\",\n\t\t\t\t\t\t\textDecl.GetNumber(), existing)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdeclsByTag[extDecl.GetNumber()] = extensionNumberSpan.Start()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif extDecl.FullName == nil && !extDecl.GetReserved() {\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(r, md, i, extRange, internal.ExtensionRangeOptionsDeclarationTag, int32(i))\n\t\t\t\tif err := handler.HandleErrorf(span, \"extension declaration that is not marked reserved must have a full_name\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else if extDecl.FullName != nil {\n\t\t\t\tvar extensionFullName protoreflect.FullName\n\t\t\t\textensionNameSpan, _ := findExtensionRangeOptionSpan(r, md, i, extRange,\n\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(i), internal.ExtensionRangeOptionsDeclarationFullNameTag)\n\t\t\t\tif !strings.HasPrefix(extDecl.GetFullName(), \".\") {\n\t\t\t\t\tif err := handler.HandleErrorf(extensionNameSpan, \"extension declaration full name %q should start with a leading dot (.)\", extDecl.GetFullName()); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t\textensionFullName = protoreflect.FullName(extDecl.GetFullName())\n\t\t\t\t} else {\n\t\t\t\t\textensionFullName = protoreflect.FullName(extDecl.GetFullName()[1:])\n\t\t\t\t}\n\t\t\t\tif !extensionFullName.IsValid() {\n\t\t\t\t\tif err := handler.HandleErrorf(extensionNameSpan, \"extension declaration full name %q is not a valid qualified name\", extDecl.GetFullName()); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif err := symbols.AddExtensionDeclaration(extensionFullName, md.FullName(), protoreflect.FieldNumber(extDecl.GetNumber()), extensionNameSpan, handler); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif extDecl.Type == nil && !extDecl.GetReserved() {\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(r, md, i, extRange, internal.ExtensionRangeOptionsDeclarationTag, int32(i))\n\t\t\t\tif err := handler.HandleErrorf(span, \"extension declaration that is not marked reserved must have a type\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t} else if extDecl.Type != nil {\n\t\t\t\tif strings.HasPrefix(extDecl.GetType(), \".\") {\n\t\t\t\t\tif !protoreflect.FullName(extDecl.GetType()[1:]).IsValid() {\n\t\t\t\t\t\tspan, _ := findExtensionRangeOptionSpan(r, md, i, extRange,\n\t\t\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(i), internal.ExtensionRangeOptionsDeclarationTypeTag)\n\t\t\t\t\t\tif err := handler.HandleErrorf(span, \"extension declaration type %q is not a valid qualified name\", extDecl.GetType()); err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if !isBuiltinTypeName(extDecl.GetType()) {\n\t\t\t\t\tspan, _ := findExtensionRangeOptionSpan(r, md, i, extRange,\n\t\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(i), internal.ExtensionRangeOptionsDeclarationTypeTag)\n\t\t\t\t\tif err := handler.HandleErrorf(span, \"extension declaration type %q must be a builtin type or start with a leading dot (.)\", extDecl.GetType()); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif extDecl.GetReserved() && (extDecl.FullName == nil) != (extDecl.Type == nil) {\n\t\t\t\tvar fieldTag int32\n\t\t\t\tif extDecl.FullName != nil {\n\t\t\t\t\tfieldTag = internal.ExtensionRangeOptionsDeclarationFullNameTag\n\t\t\t\t} else {\n\t\t\t\t\tfieldTag = internal.ExtensionRangeOptionsDeclarationTypeTag\n\t\t\t\t}\n\t\t\t\tspan, _ := findExtensionRangeOptionSpan(r, md, i, extRange,\n\t\t\t\t\tinternal.ExtensionRangeOptionsDeclarationTag, int32(i), fieldTag)\n\t\t\t\tif err := handler.HandleErrorf(span, \"extension declarations that are reserved should specify both full_name and type or neither\"); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *result) hasCustomJSONName(fdProto *descriptorpb.FieldDescriptorProto) bool {\n\t// if we have the AST, we can more precisely determine if there was a custom\n\t// JSON named defined, even if it is explicitly configured to tbe the same\n\t// as the default JSON name for the field.\n\topts := r.FieldNode(fdProto).GetOptions()\n\tif opts == nil {\n\t\treturn false\n\t}\n\tfor _, opt := range opts.Options {\n\t\tif len(opt.Name.Parts) == 1 &&\n\t\t\topt.Name.Parts[0].Name.AsIdentifier() == \"json_name\" &&\n\t\t\t!opt.Name.Parts[0].IsExtension() {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc canonicalEnumValueName(enumValueName, enumName string) string {\n\treturn enumValCamelCase(removePrefix(enumValueName, enumName))\n}\n\n// removePrefix is used to remove the given prefix from the given str. It does not require\n// an exact match and ignores case and underscores. If the all non-underscore characters\n// would be removed from str, str is returned unchanged. If str does not have the given\n// prefix (even with the very lenient matching, in regard to case and underscores), then\n// str is returned unchanged.\n//\n// The algorithm is adapted from the protoc source:\n//\n//\thttps://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L922\nfunc removePrefix(str, prefix string) string {\n\tj := 0\n\tfor i, r := range str {\n\t\tif r == '_' {\n\t\t\t// skip underscores in the input\n\t\t\tcontinue\n\t\t}\n\n\t\tp, sz := utf8.DecodeRuneInString(prefix[j:])\n\t\tfor p == '_' {\n\t\t\tj += sz // consume/skip underscore\n\t\t\tp, sz = utf8.DecodeRuneInString(prefix[j:])\n\t\t}\n\n\t\tif j == len(prefix) {\n\t\t\t// matched entire prefix; return rest of str\n\t\t\t// but skipping any leading underscores\n\t\t\tresult := strings.TrimLeft(str[i:], \"_\")\n\t\t\tif len(result) == 0 {\n\t\t\t\t// result can't be empty string\n\t\t\t\treturn str\n\t\t\t}\n\t\t\treturn result\n\t\t}\n\t\tif unicode.ToLower(r) != unicode.ToLower(p) {\n\t\t\t// does not match prefix\n\t\t\treturn str\n\t\t}\n\t\tj += sz // consume matched rune of prefix\n\t}\n\treturn str\n}\n\n// enumValCamelCase converts the given string to upper-camel-case.\n//\n// The algorithm is adapted from the protoc source:\n//\n//\thttps://github.com/protocolbuffers/protobuf/blob/v21.3/src/google/protobuf/descriptor.cc#L887\nfunc enumValCamelCase(name string) string {\n\tvar js []rune\n\tnextUpper := true\n\tfor _, r := range name {\n\t\tif r == '_' {\n\t\t\tnextUpper = true\n\t\t\tcontinue\n\t\t}\n\t\tif nextUpper {\n\t\t\tnextUpper = false\n\t\t\tjs = append(js, unicode.ToUpper(r))\n\t\t} else {\n\t\t\tjs = append(js, unicode.ToLower(r))\n\t\t}\n\t}\n\treturn string(js)\n}\n\nfunc isBuiltinTypeName(typeName string) bool {\n\tswitch typeName {\n\tcase \"int32\", \"int64\", \"uint32\", \"uint64\", \"sint32\", \"sint64\",\n\t\t\"fixed32\", \"fixed64\", \"sfixed32\", \"sfixed64\",\n\t\t\"bool\", \"double\", \"float\", \"string\", \"bytes\":\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc getTypeName(fd protoreflect.FieldDescriptor) string {\n\tswitch fd.Kind() {\n\tcase protoreflect.MessageKind, protoreflect.GroupKind:\n\t\treturn \".\" + string(fd.Message().FullName())\n\tcase protoreflect.EnumKind:\n\t\treturn \".\" + string(fd.Enum().FullName())\n\tdefault:\n\t\treturn fd.Kind().String()\n\t}\n}\n\nfunc findExtensionRangeOptionSpan(\n\tfile protoreflect.FileDescriptor,\n\textended protoreflect.MessageDescriptor,\n\textRangeIndex int,\n\textRange *descriptorpb.DescriptorProto_ExtensionRange,\n\tpath ...int32,\n) (ast.SourceSpan, bool) {\n\t// NB: Typically, we have an AST for a file and NOT source code info, because the\n\t// compiler validates options before computing source code info. However, we might\n\t// be validating an extension (whose source/AST we have), but whose extendee (and\n\t// thus extension range options for declarations) could be in some other file, which\n\t// could be provided to the compiler as an already-compiled descriptor. So this\n\t// function can fallback to using source code info if an AST is not available.\n\n\tif r, ok := file.(Result); ok && r.AST() != nil {\n\t\t// Find the location using the AST, which will generally be higher fidelity\n\t\t// than what we might find in a file descriptor's source code info.\n\t\texts := r.ExtensionsNode(extRange)\n\t\treturn findOptionSpan(r.FileNode(), exts, extRange.Options.ProtoReflect().Descriptor(), path...)\n\t}\n\n\tsrcLocs := file.SourceLocations()\n\tif srcLocs.Len() == 0 {\n\t\t// no source code info, can't do any better than the filename. We\n\t\t// return true as the boolean so the caller doesn't try again with\n\t\t// an alternate path, since we won't be able to do any better.\n\t\treturn ast.UnknownSpan(file.Path()), true\n\t}\n\tmsgPath, ok := internal.ComputePath(extended)\n\tif !ok {\n\t\t// Same as above: return true since no subsequent query can do better.\n\t\treturn ast.UnknownSpan(file.Path()), true\n\t}\n\n\t//nolint:gocritic // intentionally assigning to different slice variables\n\textRangePath := append(msgPath, internal.MessageExtensionRangesTag, int32(extRangeIndex))\n\toptsPath := append(extRangePath, internal.ExtensionRangeOptionsTag) //nolint:gocritic\n\tfullPath := append(optsPath, path...)                               //nolint:gocritic\n\tsrcLoc := srcLocs.ByPath(fullPath)\n\tif srcLoc.Path != nil {\n\t\t// found it\n\t\treturn asSpan(file.Path(), srcLoc), true\n\t}\n\n\t// Slow path to find closest match :/\n\t// We look for longest matching path that is at least len(extRangePath)\n\t// long. If we find a path that is longer (meaning a path that points INSIDE\n\t// the request element), accept the first such location.\n\tvar bestMatch protoreflect.SourceLocation\n\tvar bestMatchPathLen int\n\tfor i, length := 0, srcLocs.Len(); i < length; i++ {\n\t\tsrcLoc := srcLocs.Get(i)\n\t\tif len(srcLoc.Path) >= len(extRangePath) &&\n\t\t\tisDescendantPath(fullPath, srcLoc.Path) &&\n\t\t\tlen(srcLoc.Path) > bestMatchPathLen {\n\t\t\tbestMatch = srcLoc\n\t\t\tbestMatchPathLen = len(srcLoc.Path)\n\t\t} else if isDescendantPath(srcLoc.Path, path) {\n\t\t\treturn asSpan(file.Path(), srcLoc), false\n\t\t}\n\t}\n\tif bestMatchPathLen > 0 {\n\t\treturn asSpan(file.Path(), bestMatch), false\n\t}\n\treturn ast.UnknownSpan(file.Path()), false\n}\n\nfunc (r *result) findScalarOptionSpan(\n\troot ast.NodeWithOptions,\n\tname string,\n) ast.SourceSpan {\n\tmatch := ast.Node(root)\n\troot.RangeOptions(func(n *ast.OptionNode) bool {\n\t\tif len(n.Name.Parts) == 1 && !n.Name.Parts[0].IsExtension() &&\n\t\t\tstring(n.Name.Parts[0].Name.AsIdentifier()) == name {\n\t\t\tmatch = n\n\t\t\treturn false\n\t\t}\n\t\treturn true\n\t})\n\treturn r.FileNode().NodeInfo(match)\n}\n\nfunc (r *result) findOptionSpan(\n\td protoutil.DescriptorProtoWrapper,\n\tpath ...int32,\n) ast.SourceSpan {\n\tnode := r.Node(d.AsProto())\n\tnodeWithOpts, ok := node.(ast.NodeWithOptions)\n\tif !ok {\n\t\treturn r.FileNode().NodeInfo(node)\n\t}\n\tspan, _ := findOptionSpan(r.FileNode(), nodeWithOpts, d.Options().ProtoReflect().Descriptor(), path...)\n\treturn span\n}\n\nfunc findOptionSpan(\n\tfile ast.FileDeclNode,\n\troot ast.NodeWithOptions,\n\tmd protoreflect.MessageDescriptor,\n\tpath ...int32,\n) (ast.SourceSpan, bool) {\n\tbestMatch := ast.Node(root)\n\tvar bestMatchLen int\n\tvar repeatedIndices []int\n\troot.RangeOptions(func(n *ast.OptionNode) bool {\n\t\tdesc := md\n\t\tlimit := len(n.Name.Parts)\n\t\tif limit > len(path) {\n\t\t\tlimit = len(path)\n\t\t}\n\t\tvar nextIsIndex bool\n\t\tfor i := 0; i < limit; i++ {\n\t\t\tif desc == nil || nextIsIndex {\n\t\t\t\t// Can't match anymore. Try next option.\n\t\t\t\treturn true\n\t\t\t}\n\t\t\twantField := desc.Fields().ByNumber(protoreflect.FieldNumber(path[i]))\n\t\t\tif wantField == nil {\n\t\t\t\t// Should not be possible... next option won't fare any better since\n\t\t\t\t// it's a disagreement between given path and given descriptor so bail.\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif n.Name.Parts[i].Open != nil ||\n\t\t\t\tstring(n.Name.Parts[i].Name.AsIdentifier()) != string(wantField.Name()) {\n\t\t\t\t// This is an extension/custom option or indicates the wrong name.\n\t\t\t\t// Try the next one.\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tdesc = wantField.Message()\n\t\t\tnextIsIndex = wantField.Cardinality() == protoreflect.Repeated\n\t\t}\n\t\t// If we made it this far, we've matched everything so far.\n\t\tif len(n.Name.Parts) >= len(path) {\n\t\t\t// Either an exact match (if equal) or this option points *inside* the\n\t\t\t// item we care about (if greater). Either way, the first such result\n\t\t\t// is a keeper.\n\t\t\tbestMatch = n.Name.Parts[len(path)-1]\n\t\t\tbestMatchLen = len(n.Name.Parts)\n\t\t\treturn false\n\t\t}\n\t\t// We've got more path elements to try to match with the value.\n\t\tmatch, matchLen := findMatchingValueNode(\n\t\t\tdesc,\n\t\t\tpath[len(n.Name.Parts):],\n\t\t\tnextIsIndex,\n\t\t\t0,\n\t\t\t&repeatedIndices,\n\t\t\tn,\n\t\t\tn.Val)\n\t\tif match != nil {\n\t\t\ttotalMatchLen := matchLen + len(n.Name.Parts)\n\t\t\tif totalMatchLen > bestMatchLen {\n\t\t\t\tbestMatch, bestMatchLen = match, totalMatchLen\n\t\t\t}\n\t\t}\n\t\treturn bestMatchLen != len(path) // no exact match, so keep looking\n\t})\n\treturn file.NodeInfo(bestMatch), bestMatchLen == len(path)\n}\n\nfunc findMatchingValueNode(\n\tmd protoreflect.MessageDescriptor,\n\tpath protoreflect.SourcePath,\n\tcurrIsRepeated bool,\n\trepeatedCount int,\n\trepeatedIndices *[]int,\n\tnode ast.Node,\n\tval ast.ValueNode,\n) (ast.Node, int) {\n\tvar matchLen int\n\tvar index int\n\tif currIsRepeated {\n\t\t// Compute the index of the current value (or, if an array literal, the\n\t\t// index of the first value in the array).\n\t\tif len(*repeatedIndices) > repeatedCount {\n\t\t\t(*repeatedIndices)[repeatedCount]++\n\t\t\tindex = (*repeatedIndices)[repeatedCount]\n\t\t} else {\n\t\t\t*repeatedIndices = append(*repeatedIndices, 0)\n\t\t\tindex = 0\n\t\t}\n\t\trepeatedCount++\n\t}\n\n\tif arrayVal, ok := val.(*ast.ArrayLiteralNode); ok {\n\t\tif !currIsRepeated {\n\t\t\t// This should not happen.\n\t\t\treturn nil, 0\n\t\t}\n\t\toffset := int(path[0]) - index\n\t\tif offset >= len(arrayVal.Elements) {\n\t\t\t// The index we are looking for is not in this array.\n\t\t\treturn nil, 0\n\t\t}\n\t\telem := arrayVal.Elements[offset]\n\t\t// We've matched the index!\n\t\tmatchLen++\n\t\tpath = path[1:]\n\t\t// Recurse into array element.\n\t\tnextMatch, nextMatchLen := findMatchingValueNode(\n\t\t\tmd,\n\t\t\tpath,\n\t\t\tfalse,\n\t\t\trepeatedCount,\n\t\t\trepeatedIndices,\n\t\t\telem,\n\t\t\telem,\n\t\t)\n\t\treturn nextMatch, nextMatchLen + matchLen\n\t}\n\n\tif currIsRepeated {\n\t\tif index != int(path[0]) {\n\t\t\t// Not a match!\n\t\t\treturn nil, 0\n\t\t}\n\t\t// We've matched the index!\n\t\tmatchLen++\n\t\tpath = path[1:]\n\t\tif len(path) == 0 {\n\t\t\t// We're done matching!\n\t\t\treturn node, matchLen\n\t\t}\n\t}\n\n\tmsgValue, ok := val.(*ast.MessageLiteralNode)\n\tif !ok {\n\t\t// We can't go any further\n\t\treturn node, matchLen\n\t}\n\n\tvar wantField protoreflect.FieldDescriptor\n\tif md != nil {\n\t\twantField = md.Fields().ByNumber(protoreflect.FieldNumber(path[0]))\n\t}\n\tif wantField == nil {\n\t\t// Should not be possible... next option won't fare any better since\n\t\t// it's a disagreement between given path and given descriptor so bail.\n\t\treturn nil, 0\n\t}\n\tfor _, field := range msgValue.Elements {\n\t\tif field.Name.Open != nil ||\n\t\t\tstring(field.Name.Name.AsIdentifier()) != string(wantField.Name()) {\n\t\t\t// This is an extension/custom option or indicates the wrong name.\n\t\t\t// Try the next one.\n\t\t\tcontinue\n\t\t}\n\t\t// We've matched this field.\n\t\tmatchLen++\n\t\tpath = path[1:]\n\t\tif len(path) == 0 {\n\t\t\t// Perfect match!\n\t\t\treturn field, matchLen\n\t\t}\n\t\tnextMatch, nextMatchLen := findMatchingValueNode(\n\t\t\twantField.Message(),\n\t\t\tpath,\n\t\t\twantField.Cardinality() == protoreflect.Repeated,\n\t\t\trepeatedCount,\n\t\t\trepeatedIndices,\n\t\t\tfield,\n\t\t\tfield.Val,\n\t\t)\n\t\treturn nextMatch, nextMatchLen + matchLen\n\t}\n\n\t// If we didn't find the right field, just return what we have so far.\n\treturn node, matchLen\n}\n\nfunc isDescendantPath(descendant, ancestor protoreflect.SourcePath) bool {\n\tif len(descendant) < len(ancestor) {\n\t\treturn false\n\t}\n\tfor i := range ancestor {\n\t\tif descendant[i] != ancestor[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc asSpan(file string, srcLoc protoreflect.SourceLocation) ast.SourceSpan {\n\treturn ast.NewSourceSpan(\n\t\tast.SourcePos{\n\t\t\tFilename: file,\n\t\t\tLine:     srcLoc.StartLine + 1,\n\t\t\tCol:      srcLoc.StartColumn + 1,\n\t\t},\n\t\tast.SourcePos{\n\t\t\tFilename: file,\n\t\t\tLine:     srcLoc.EndLine + 1,\n\t\t\tCol:      srcLoc.EndColumn + 1,\n\t\t},\n\t)\n}\n\nfunc (r *result) getImportLocation(path string) ast.SourceSpan {\n\tnode, ok := r.FileNode().(*ast.FileNode)\n\tif !ok {\n\t\treturn ast.UnknownSpan(path)\n\t}\n\tfor _, decl := range node.Decls {\n\t\timp, ok := decl.(*ast.ImportNode)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif imp.Name.AsString() == path {\n\t\t\treturn node.NodeInfo(imp.Name)\n\t\t}\n\t}\n\t// Couldn't find it? Should never happen...\n\treturn ast.UnknownSpan(path)\n}\n\nfunc isEditions(r *result) bool {\n\treturn descriptorpb.Edition(r.Edition()) >= descriptorpb.Edition_EDITION_2023\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/options/options.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package options contains the logic for interpreting options. The parse step\n// of compilation stores the options in uninterpreted form, which contains raw\n// identifiers and literal values.\n//\n// The process of interpreting an option is to resolve identifiers, by examining\n// descriptors for the google.protobuf.*Options types and their available\n// extensions (custom options). As field names are resolved, the values can be\n// type-checked against the types indicated in field descriptors.\n//\n// On success, the various fields and extensions of the options message are\n// populated and the field holding the uninterpreted form is cleared.\npackage options\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\n\t\"google.golang.org/protobuf/encoding/prototext\"\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n\t\"github.com/bufbuild/protocompile/internal/messageset\"\n\t\"github.com/bufbuild/protocompile/linker\"\n\t\"github.com/bufbuild/protocompile/parser\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n\t\"github.com/bufbuild/protocompile/sourceinfo\"\n)\n\ntype interpreter struct {\n\tfile                    file\n\tresolver                linker.Resolver\n\toverrideDescriptorProto linker.File\n\n\tindex      sourceinfo.OptionIndex\n\tpathBuffer []int32\n\n\treporter *reporter.Handler\n\tlenient  bool\n\n\t// lenienceEnabled is set to true when errors reported to reporter\n\t// should be lenient\n\tlenienceEnabled    bool\n\tlenientErrReported bool\n}\n\ntype file interface {\n\tparser.Result\n\tResolveMessageLiteralExtensionName(ast.IdentValueNode) string\n}\n\ntype noResolveFile struct {\n\tparser.Result\n}\n\nfunc (n noResolveFile) ResolveMessageLiteralExtensionName(ast.IdentValueNode) string {\n\treturn \"\"\n}\n\n// InterpreterOption is an option that can be passed to InterpretOptions and\n// its variants.\ntype InterpreterOption func(*interpreter)\n\n// WithOverrideDescriptorProto returns an option that indicates that the given file\n// should be consulted when looking up a definition for an option type. The given\n// file should usually have the path \"google/protobuf/descriptor.proto\". The given\n// file will only be consulted if the option type is otherwise not visible to the\n// file whose options are being interpreted.\nfunc WithOverrideDescriptorProto(f linker.File) InterpreterOption {\n\treturn func(interp *interpreter) {\n\t\tinterp.overrideDescriptorProto = f\n\t}\n}\n\n// InterpretOptions interprets options in the given linked result, returning\n// an index that can be used to generate source code info. This step mutates\n// the linked result's underlying proto to move option elements out of the\n// \"uninterpreted_option\" fields and into proper option fields and extensions.\n//\n// The given handler is used to report errors and warnings. If any errors are\n// reported, this function returns a non-nil error.\nfunc InterpretOptions(linked linker.Result, handler *reporter.Handler, opts ...InterpreterOption) (sourceinfo.OptionIndex, error) {\n\treturn interpretOptions(false, linked, linker.ResolverFromFile(linked), handler, opts)\n}\n\n// InterpretOptionsLenient interprets options in a lenient/best-effort way in\n// the given linked result, returning an index that can be used to generate\n// source code info. This step mutates the linked result's underlying proto to\n// move option elements out of the \"uninterpreted_option\" fields and into proper\n// option fields and extensions.\n//\n// In lenient more, errors resolving option names and type errors are ignored.\n// Any options that are uninterpretable (due to such errors) will remain in the\n// \"uninterpreted_option\" fields.\nfunc InterpretOptionsLenient(linked linker.Result, opts ...InterpreterOption) (sourceinfo.OptionIndex, error) {\n\treturn interpretOptions(true, linked, linker.ResolverFromFile(linked), reporter.NewHandler(nil), opts)\n}\n\n// InterpretUnlinkedOptions does a best-effort attempt to interpret options in\n// the given parsed result, returning an index that can be used to generate\n// source code info. This step mutates the parsed result's underlying proto to\n// move option elements out of the \"uninterpreted_option\" fields and into proper\n// option fields and extensions.\n//\n// This is the same as InterpretOptionsLenient except that it accepts an\n// unlinked result. Because the file is unlinked, custom options cannot be\n// interpreted. Other errors resolving option names or type errors will be\n// effectively ignored. Any options that are uninterpretable (due to such\n// errors) will remain in the \"uninterpreted_option\" fields.\nfunc InterpretUnlinkedOptions(parsed parser.Result, opts ...InterpreterOption) (sourceinfo.OptionIndex, error) {\n\treturn interpretOptions(true, noResolveFile{parsed}, nil, reporter.NewHandler(nil), opts)\n}\n\nfunc interpretOptions(lenient bool, file file, res linker.Resolver, handler *reporter.Handler, interpOpts []InterpreterOption) (sourceinfo.OptionIndex, error) {\n\tinterp := &interpreter{\n\t\tfile:       file,\n\t\tresolver:   res,\n\t\tlenient:    lenient,\n\t\treporter:   handler,\n\t\tindex:      sourceinfo.OptionIndex{},\n\t\tpathBuffer: make([]int32, 0, 16),\n\t}\n\tfor _, opt := range interpOpts {\n\t\topt(interp)\n\t}\n\t// We have to do this in two phases. First we interpret non-custom options.\n\t// This allows us to handle standard options and features that may needed to\n\t// correctly reference the custom options in the second phase.\n\tif err := interp.interpretFileOptions(file, false); err != nil {\n\t\treturn nil, err\n\t}\n\t// Now we can do custom options.\n\tif err := interp.interpretFileOptions(file, true); err != nil {\n\t\treturn nil, err\n\t}\n\treturn interp.index, nil\n}\n\nfunc (interp *interpreter) handleErrorf(span ast.SourceSpan, msg string, args ...interface{}) error {\n\tif interp.lenienceEnabled {\n\t\tinterp.lenientErrReported = true\n\t\treturn nil\n\t}\n\treturn interp.reporter.HandleErrorf(span, msg, args...)\n}\n\nfunc (interp *interpreter) handleErrorWithPos(span ast.SourceSpan, err error) error {\n\tif interp.lenienceEnabled {\n\t\tinterp.lenientErrReported = true\n\t\treturn nil\n\t}\n\treturn interp.reporter.HandleErrorWithPos(span, err)\n}\n\nfunc (interp *interpreter) handleError(err error) error {\n\tif interp.lenienceEnabled {\n\t\tinterp.lenientErrReported = true\n\t\treturn nil\n\t}\n\treturn interp.reporter.HandleError(err)\n}\n\nfunc (interp *interpreter) interpretFileOptions(file file, customOpts bool) error {\n\tfd := file.FileDescriptorProto()\n\tprefix := fd.GetPackage()\n\tif prefix != \"\" {\n\t\tprefix += \".\"\n\t}\n\terr := interpretElementOptions(interp, fd.GetName(), targetTypeFile, fd, customOpts)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, md := range fd.GetMessageType() {\n\t\tfqn := prefix + md.GetName()\n\t\tif err := interp.interpretMessageOptions(fqn, md, customOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, fld := range fd.GetExtension() {\n\t\tfqn := prefix + fld.GetName()\n\t\tif err := interp.interpretFieldOptions(fqn, fld, customOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, ed := range fd.GetEnumType() {\n\t\tfqn := prefix + ed.GetName()\n\t\tif err := interp.interpretEnumOptions(fqn, ed, customOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, sd := range fd.GetService() {\n\t\tfqn := prefix + sd.GetName()\n\t\terr := interpretElementOptions(interp, fqn, targetTypeService, sd, customOpts)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor _, mtd := range sd.GetMethod() {\n\t\t\tmtdFqn := fqn + \".\" + mtd.GetName()\n\t\t\terr := interpretElementOptions(interp, mtdFqn, targetTypeMethod, mtd, customOpts)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc resolveDescriptor[T protoreflect.Descriptor](res linker.Resolver, name string) T {\n\tvar zero T\n\tif res == nil {\n\t\treturn zero\n\t}\n\tif len(name) > 0 && name[0] == '.' {\n\t\tname = name[1:]\n\t}\n\tdesc, _ := res.FindDescriptorByName(protoreflect.FullName(name))\n\ttypedDesc, ok := desc.(T)\n\tif ok {\n\t\treturn typedDesc\n\t}\n\treturn zero\n}\n\nfunc (interp *interpreter) resolveExtensionType(name string) (protoreflect.ExtensionTypeDescriptor, error) {\n\tif interp.resolver == nil {\n\t\treturn nil, protoregistry.NotFound\n\t}\n\tif len(name) > 0 && name[0] == '.' {\n\t\tname = name[1:]\n\t}\n\text, err := interp.resolver.FindExtensionByName(protoreflect.FullName(name))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn ext.TypeDescriptor(), nil\n}\n\nfunc (interp *interpreter) resolveOptionsType(name string) protoreflect.MessageDescriptor {\n\tmd := resolveDescriptor[protoreflect.MessageDescriptor](interp.resolver, name)\n\tif md != nil {\n\t\treturn md\n\t}\n\tif interp.overrideDescriptorProto == nil {\n\t\treturn nil\n\t}\n\tif len(name) > 0 && name[0] == '.' {\n\t\tname = name[1:]\n\t}\n\tdesc := interp.overrideDescriptorProto.FindDescriptorByName(protoreflect.FullName(name))\n\tif md, ok := desc.(protoreflect.MessageDescriptor); ok {\n\t\treturn md\n\t}\n\treturn nil\n}\n\nfunc (interp *interpreter) nodeInfo(n ast.Node) ast.NodeInfo {\n\treturn interp.file.FileNode().NodeInfo(n)\n}\n\nfunc (interp *interpreter) interpretMessageOptions(fqn string, md *descriptorpb.DescriptorProto, customOpts bool) error {\n\terr := interpretElementOptions(interp, fqn, targetTypeMessage, md, customOpts)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, fld := range md.GetField() {\n\t\tfldFqn := fqn + \".\" + fld.GetName()\n\t\tif err := interp.interpretFieldOptions(fldFqn, fld, customOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, ood := range md.GetOneofDecl() {\n\t\toodFqn := fqn + \".\" + ood.GetName()\n\t\terr := interpretElementOptions(interp, oodFqn, targetTypeOneof, ood, customOpts)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, fld := range md.GetExtension() {\n\t\tfldFqn := fqn + \".\" + fld.GetName()\n\t\tif err := interp.interpretFieldOptions(fldFqn, fld, customOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, er := range md.GetExtensionRange() {\n\t\terFqn := fmt.Sprintf(\"%s.%d-%d\", fqn, er.GetStart(), er.GetEnd())\n\t\terr := interpretElementOptions(interp, erFqn, targetTypeExtensionRange, er, customOpts)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, nmd := range md.GetNestedType() {\n\t\tnmdFqn := fqn + \".\" + nmd.GetName()\n\t\tif err := interp.interpretMessageOptions(nmdFqn, nmd, customOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor _, ed := range md.GetEnumType() {\n\t\tedFqn := fqn + \".\" + ed.GetName()\n\t\tif err := interp.interpretEnumOptions(edFqn, ed, customOpts); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// We also copy features for map fields down to their synthesized key and value fields.\n\tfor _, fld := range md.GetField() {\n\t\tentryName := internal.InitCap(internal.JSONName(fld.GetName())) + \"Entry\"\n\t\tif fld.GetLabel() != descriptorpb.FieldDescriptorProto_LABEL_REPEATED ||\n\t\t\tfld.GetType() != descriptorpb.FieldDescriptorProto_TYPE_MESSAGE &&\n\t\t\t\tfld.GetTypeName() != \".\"+fqn+\".\"+entryName {\n\t\t\t// can't be a map field\n\t\t\tcontinue\n\t\t}\n\t\tif fld.Options == nil || fld.Options.Features == nil {\n\t\t\t// no features to propagate\n\t\t\tcontinue\n\t\t}\n\t\tfor _, nmd := range md.GetNestedType() {\n\t\t\tif nmd.GetName() == entryName {\n\t\t\t\t// found the entry message\n\t\t\t\tif !nmd.GetOptions().GetMapEntry() {\n\t\t\t\t\tbreak // not a map\n\t\t\t\t}\n\t\t\t\tfor _, mapField := range nmd.Field {\n\t\t\t\t\tif mapField.Options == nil {\n\t\t\t\t\t\tmapField.Options = &descriptorpb.FieldOptions{}\n\t\t\t\t\t}\n\t\t\t\t\tfeatures := proto.Clone(fld.Options.Features).(*descriptorpb.FeatureSet) //nolint:errcheck\n\t\t\t\t\tif mapField.Options.Features != nil {\n\t\t\t\t\t\tproto.Merge(features, mapField.Options.Features)\n\t\t\t\t\t}\n\t\t\t\t\tmapField.Options.Features = features\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nvar emptyFieldOptions = &descriptorpb.FieldOptions{}\n\nfunc (interp *interpreter) interpretFieldOptions(fqn string, fld *descriptorpb.FieldDescriptorProto, customOpts bool) error {\n\topts := fld.GetOptions()\n\temptyOptionsAlreadyPresent := opts != nil && len(opts.GetUninterpretedOption()) == 0\n\n\t// For non-custom phase, first process pseudo-options\n\tif len(opts.GetUninterpretedOption()) > 0 && !customOpts {\n\t\tinterp.enableLenience(true)\n\t\terr := interp.interpretFieldPseudoOptions(fqn, fld, opts)\n\t\tinterp.enableLenience(false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Must re-check length of uninterpreted options since above step could remove some.\n\tif len(opts.GetUninterpretedOption()) == 0 {\n\t\t// If the message has no other interpreted options, we clear it out. But don't\n\t\t// do that if the descriptor came in with empty options or if it already has\n\t\t// interpreted option fields.\n\t\tif opts != nil && !emptyOptionsAlreadyPresent && proto.Equal(fld.Options, emptyFieldOptions) {\n\t\t\tfld.Options = nil\n\t\t}\n\t\treturn nil\n\t}\n\n\t// Then process actual options.\n\treturn interpretElementOptions(interp, fqn, targetTypeField, fld, customOpts)\n}\n\nfunc (interp *interpreter) interpretFieldPseudoOptions(fqn string, fld *descriptorpb.FieldDescriptorProto, opts *descriptorpb.FieldOptions) error {\n\tscope := \"field \" + fqn\n\tuo := opts.UninterpretedOption\n\n\t// process json_name pseudo-option\n\tif index, err := internal.FindOption(interp.file, interp.handleErrorf, scope, uo, \"json_name\"); err != nil {\n\t\treturn err\n\t} else if index >= 0 {\n\t\topt := uo[index]\n\t\toptNode := interp.file.OptionNode(opt)\n\t\tif opt.StringValue == nil {\n\t\t\treturn interp.handleErrorf(interp.nodeInfo(optNode.GetValue()), \"%s: expecting string value for json_name option\", scope)\n\t\t}\n\t\tjsonName := string(opt.StringValue)\n\t\t// Extensions don't support custom json_name values.\n\t\t// If the value is already set (via the descriptor) and doesn't match the default value, return an error.\n\t\tif fld.GetExtendee() != \"\" && jsonName != \"\" && jsonName != internal.JSONName(fld.GetName()) {\n\t\t\treturn interp.handleErrorf(interp.nodeInfo(optNode.GetName()), \"%s: option json_name is not allowed on extensions\", scope)\n\t\t}\n\t\t// attribute source code info\n\t\tif on, ok := optNode.(*ast.OptionNode); ok {\n\t\t\tinterp.index[on] = &sourceinfo.OptionSourceInfo{Path: []int32{-1, internal.FieldJSONNameTag}}\n\t\t}\n\t\tuo = internal.RemoveOption(uo, index)\n\t\tif strings.HasPrefix(jsonName, \"[\") && strings.HasSuffix(jsonName, \"]\") {\n\t\t\treturn interp.handleErrorf(interp.nodeInfo(optNode.GetValue()), \"%s: option json_name value cannot start with '[' and end with ']'; that is reserved for representing extensions\", scope)\n\t\t}\n\t\tfld.JsonName = proto.String(jsonName)\n\t}\n\n\t// and process default pseudo-option\n\tif index, err := interp.processDefaultOption(scope, fqn, fld, uo); err != nil {\n\t\treturn err\n\t} else if index >= 0 {\n\t\t// attribute source code info\n\t\toptNode := interp.file.OptionNode(uo[index])\n\t\tif on, ok := optNode.(*ast.OptionNode); ok {\n\t\t\tinterp.index[on] = &sourceinfo.OptionSourceInfo{Path: []int32{-1, internal.FieldDefaultTag}}\n\t\t}\n\t\tuo = internal.RemoveOption(uo, index)\n\t}\n\n\topts.UninterpretedOption = uo\n\treturn nil\n}\n\nfunc (interp *interpreter) processDefaultOption(scope string, fqn string, fld *descriptorpb.FieldDescriptorProto, uos []*descriptorpb.UninterpretedOption) (defaultIndex int, err error) {\n\tfound, err := internal.FindOption(interp.file, interp.handleErrorf, scope, uos, \"default\")\n\tif err != nil || found == -1 {\n\t\treturn -1, err\n\t}\n\topt := uos[found]\n\toptNode := interp.file.OptionNode(opt)\n\tif fld.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REPEATED {\n\t\treturn -1, interp.handleErrorf(interp.nodeInfo(optNode.GetName()), \"%s: default value cannot be set because field is repeated\", scope)\n\t}\n\tif fld.GetType() == descriptorpb.FieldDescriptorProto_TYPE_GROUP || fld.GetType() == descriptorpb.FieldDescriptorProto_TYPE_MESSAGE {\n\t\treturn -1, interp.handleErrorf(interp.nodeInfo(optNode.GetName()), \"%s: default value cannot be set because field is a message\", scope)\n\t}\n\tmc := &internal.MessageContext{\n\t\tFile:        interp.file,\n\t\tElementName: fqn,\n\t\tElementType: descriptorType(fld),\n\t\tOption:      opt,\n\t}\n\n\tval := optNode.GetValue()\n\tvar v interface{}\n\tif val.Value() == nil {\n\t\t// no value in the AST, so we dig the value out of the uninterpreted option proto\n\t\tv, err = interp.defaultValueFromProto(mc, fld, opt, val)\n\t} else {\n\t\t// compute value from AST\n\t\tv, err = interp.defaultValue(mc, fld, val)\n\t}\n\tif err != nil {\n\t\treturn -1, interp.handleError(err)\n\t}\n\n\tif str, ok := v.(string); ok {\n\t\tfld.DefaultValue = proto.String(str)\n\t} else if b, ok := v.([]byte); ok {\n\t\tfld.DefaultValue = proto.String(encodeDefaultBytes(b))\n\t} else {\n\t\tvar flt float64\n\t\tvar ok bool\n\t\tif flt, ok = v.(float64); !ok {\n\t\t\tvar flt32 float32\n\t\t\tif flt32, ok = v.(float32); ok {\n\t\t\t\tflt = float64(flt32)\n\t\t\t}\n\t\t}\n\t\tif ok {\n\t\t\tswitch {\n\t\t\tcase math.IsInf(flt, 1):\n\t\t\t\tfld.DefaultValue = proto.String(\"inf\")\n\t\t\tcase math.IsInf(flt, -1):\n\t\t\t\tfld.DefaultValue = proto.String(\"-inf\")\n\t\t\tcase math.IsNaN(flt):\n\t\t\t\tfld.DefaultValue = proto.String(\"nan\")\n\t\t\tdefault:\n\t\t\t\tfld.DefaultValue = proto.String(fmt.Sprintf(\"%v\", v))\n\t\t\t}\n\t\t} else {\n\t\t\tfld.DefaultValue = proto.String(fmt.Sprintf(\"%v\", v))\n\t\t}\n\t}\n\treturn found, nil\n}\n\nfunc (interp *interpreter) defaultValue(mc *internal.MessageContext, fld *descriptorpb.FieldDescriptorProto, val ast.ValueNode) (interface{}, error) {\n\tif _, ok := val.(*ast.MessageLiteralNode); ok {\n\t\treturn -1, reporter.Errorf(interp.nodeInfo(val), \"%vdefault value cannot be a message\", mc)\n\t}\n\tif fld.GetType() == descriptorpb.FieldDescriptorProto_TYPE_ENUM {\n\t\ted := resolveDescriptor[protoreflect.EnumDescriptor](interp.resolver, fld.GetTypeName())\n\t\tif ed == nil {\n\t\t\treturn -1, reporter.Errorf(interp.nodeInfo(val), \"%vunable to resolve enum type %q for field %q\", mc, fld.GetTypeName(), fld.GetName())\n\t\t}\n\t\t_, name, err := interp.enumFieldValue(mc, ed, val, false)\n\t\tif err != nil {\n\t\t\treturn -1, err\n\t\t}\n\t\treturn string(name), nil\n\t}\n\treturn interp.scalarFieldValue(mc, fld.GetType(), val, false)\n}\n\nfunc (interp *interpreter) defaultValueFromProto(mc *internal.MessageContext, fld *descriptorpb.FieldDescriptorProto, opt *descriptorpb.UninterpretedOption, node ast.Node) (interface{}, error) {\n\tif opt.AggregateValue != nil {\n\t\treturn -1, reporter.Errorf(interp.nodeInfo(node), \"%vdefault value cannot be a message\", mc)\n\t}\n\tif fld.GetType() == descriptorpb.FieldDescriptorProto_TYPE_ENUM {\n\t\ted := resolveDescriptor[protoreflect.EnumDescriptor](interp.resolver, fld.GetTypeName())\n\t\tif ed == nil {\n\t\t\treturn -1, reporter.Errorf(interp.nodeInfo(node), \"%vunable to resolve enum type %q for field %q\", mc, fld.GetTypeName(), fld.GetName())\n\t\t}\n\t\t_, name, err := interp.enumFieldValueFromProto(mc, ed, opt, node)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn string(name), nil\n\t}\n\treturn interp.scalarFieldValueFromProto(mc, fld.GetType(), opt, node)\n}\n\nfunc encodeDefaultBytes(b []byte) string {\n\tvar buf bytes.Buffer\n\tinternal.WriteEscapedBytes(&buf, b)\n\treturn buf.String()\n}\n\nfunc (interp *interpreter) interpretEnumOptions(fqn string, ed *descriptorpb.EnumDescriptorProto, customOpts bool) error {\n\terr := interpretElementOptions(interp, fqn, targetTypeEnum, ed, customOpts)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, evd := range ed.GetValue() {\n\t\tevdFqn := fqn + \".\" + evd.GetName()\n\t\terr := interpretElementOptions(interp, evdFqn, targetTypeEnumValue, evd, customOpts)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc interpretElementOptions[Elem elementType[OptsStruct, Opts], OptsStruct any, Opts optionsType[OptsStruct]](\n\tinterp *interpreter,\n\tfqn string,\n\ttarget *targetType[Elem, OptsStruct, Opts],\n\telem Elem,\n\tcustomOpts bool,\n) error {\n\topts := elem.GetOptions()\n\tuninterpreted := opts.GetUninterpretedOption()\n\tif len(uninterpreted) > 0 {\n\t\tremain, err := interp.interpretOptions(fqn, target.t, elem, opts, uninterpreted, customOpts)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\ttarget.setUninterpretedOptions(opts, remain)\n\t} else if customOpts {\n\t\t// If customOpts is true, we are in second pass of interpreting.\n\t\t// For second pass, even if there are no options to interpret, we still\n\t\t// need to verify feature usage.\n\t\tfeatures := opts.GetFeatures()\n\t\tvar msg protoreflect.Message\n\t\tif len(features.ProtoReflect().GetUnknown()) > 0 {\n\t\t\t// We need to first convert to a message that uses the sources' definition\n\t\t\t// of FeatureSet.\n\t\t\toptsDesc := opts.ProtoReflect().Descriptor()\n\t\t\toptsFqn := string(optsDesc.FullName())\n\t\t\tif md := interp.resolveOptionsType(optsFqn); md != nil {\n\t\t\t\tdm := dynamicpb.NewMessage(md)\n\t\t\t\tif err := cloneInto(dm, opts, interp.resolver); err != nil {\n\t\t\t\t\tnode := interp.file.Node(elem)\n\t\t\t\t\treturn interp.handleError(reporter.Error(interp.nodeInfo(node), err))\n\t\t\t\t}\n\t\t\t\tmsg = dm\n\t\t\t}\n\t\t}\n\t\tif msg == nil {\n\t\t\tmsg = opts.ProtoReflect()\n\t\t}\n\t\terr := interp.validateRecursive(false, msg, \"\", elem, nil, false, false, false)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// interpretOptions processes the options in uninterpreted, which are interpreted as fields\n// of the given opts message. The first return value is the features to use for child elements.\n// On success, the latter two return values will usually be nil, nil. But if the current\n// operation is lenient, it may return a non-nil slice of uninterpreted options on success.\n// In such a case, the returned slice contains the options which could not be interpreted.\nfunc (interp *interpreter) interpretOptions(\n\tfqn string,\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\telement, opts proto.Message,\n\tuninterpreted []*descriptorpb.UninterpretedOption,\n\tcustomOpts bool,\n) ([]*descriptorpb.UninterpretedOption, error) {\n\toptsDesc := opts.ProtoReflect().Descriptor()\n\toptsFqn := string(optsDesc.FullName())\n\tvar msg protoreflect.Message\n\t// see if the parse included an override copy for these options\n\tif md := interp.resolveOptionsType(optsFqn); md != nil {\n\t\tdm := dynamicpb.NewMessage(md)\n\t\tif err := cloneInto(dm, opts, interp.resolver); err != nil {\n\t\t\tnode := interp.file.Node(element)\n\t\t\treturn nil, interp.handleError(reporter.Error(interp.nodeInfo(node), err))\n\t\t}\n\t\tmsg = dm\n\t} else {\n\t\tmsg = proto.Clone(opts).ProtoReflect()\n\t}\n\n\tmc := &internal.MessageContext{\n\t\tFile:        interp.file,\n\t\tElementName: fqn,\n\t\tElementType: descriptorType(element),\n\t}\n\tvar remain []*descriptorpb.UninterpretedOption\n\tfor _, uo := range uninterpreted {\n\t\tisCustom := uo.Name[0].GetIsExtension()\n\t\tif isCustom != customOpts {\n\t\t\t// We're not looking at these this phase.\n\t\t\tremain = append(remain, uo)\n\t\t\tcontinue\n\t\t}\n\t\tfirstName := uo.Name[0].GetNamePart()\n\t\tif targetType == descriptorpb.FieldOptions_TARGET_TYPE_FIELD &&\n\t\t\t!isCustom && (firstName == \"default\" || firstName == \"json_name\") {\n\t\t\t// Field pseudo-option that we can skip and is handled elsewhere.\n\t\t\tremain = append(remain, uo)\n\t\t\tcontinue\n\t\t}\n\t\tnode := interp.file.OptionNode(uo)\n\t\tif !isCustom && firstName == \"uninterpreted_option\" {\n\t\t\tif interp.lenient {\n\t\t\t\tremain = append(remain, uo)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// uninterpreted_option might be found reflectively, but is not actually valid for use\n\t\t\tif err := interp.handleErrorf(interp.nodeInfo(node.GetName()), \"%vinvalid option 'uninterpreted_option'\", mc); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\tmc.Option = uo\n\t\tinterp.enableLenience(true)\n\t\tsrcInfo, err := interp.interpretField(targetType, mc, msg, uo, 0, interp.pathBuffer)\n\t\tinterp.enableLenience(false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif interp.lenientErrReported {\n\t\t\tremain = append(remain, uo)\n\t\t\tcontinue\n\t\t}\n\n\t\tif srcInfo != nil {\n\t\t\tif optn, ok := node.(*ast.OptionNode); ok {\n\t\t\t\tinterp.index[optn] = srcInfo\n\t\t\t}\n\t\t}\n\t}\n\n\t// customOpts is true for the second pass, which is also when we want to validate feature usage.\n\tdoValidation := customOpts\n\tif doValidation {\n\t\tvalidateRequiredFields := !interp.lenient\n\t\terr := interp.validateRecursive(validateRequiredFields, msg, \"\", element, nil, false, false, false)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif interp.lenient {\n\t\t// If we're lenient, then we don't want to clobber the passed in message\n\t\t// and leave it partially populated. So we convert into a copy first\n\t\toptsClone := opts.ProtoReflect().New().Interface()\n\t\tif err := cloneInto(optsClone, msg.Interface(), interp.resolver); err != nil {\n\t\t\t// TODO: do this in a more granular way, so we can convert individual\n\t\t\t// fields and leave bad ones uninterpreted instead of skipping all of\n\t\t\t// the work we've done so far.\n\t\t\treturn uninterpreted, nil\n\t\t}\n\t\tif doValidation {\n\t\t\tif err := proto.CheckInitialized(optsClone); err != nil {\n\t\t\t\t// Conversion from dynamic message failed to set some required fields.\n\t\t\t\t// TODO above applies here as well...\n\t\t\t\treturn uninterpreted, nil\n\t\t\t}\n\t\t}\n\t\t// conversion from dynamic message above worked, so now\n\t\t// it is safe to overwrite the passed in message\n\t\tproto.Reset(opts)\n\t\tproto.Merge(opts, optsClone)\n\n\t\treturn remain, nil\n\t}\n\n\t// now try to convert into the passed in message and fail if not successful\n\tif err := cloneInto(opts, msg.Interface(), interp.resolver); err != nil {\n\t\tnode := interp.file.Node(element)\n\t\treturn nil, interp.handleError(reporter.Error(interp.nodeInfo(node), err))\n\t}\n\n\treturn remain, nil\n}\n\n// checkFieldUsage verifies that the given option field can be used\n// for the given target type. It reports an error if not and returns\n// a non-nil error if the handler returned a non-nil error.\nfunc (interp *interpreter) checkFieldUsage(\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\tfld protoreflect.FieldDescriptor,\n\tnode ast.Node,\n) error {\n\tmsgOpts, _ := fld.ContainingMessage().Options().(*descriptorpb.MessageOptions)\n\tif msgOpts.GetMessageSetWireFormat() && !messageset.CanSupportMessageSets() {\n\t\terr := interp.handleErrorf(interp.nodeInfo(node), \"field %q may not be used in an option: it uses 'message set wire format' legacy proto1 feature which is not supported\", fld.FullName())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\topts, ok := fld.Options().(*descriptorpb.FieldOptions)\n\tif !ok {\n\t\treturn nil\n\t}\n\ttargetTypes := opts.GetTargets()\n\tif len(targetTypes) == 0 {\n\t\treturn nil\n\t}\n\tfor _, allowedType := range targetTypes {\n\t\tif allowedType == targetType {\n\t\t\treturn nil\n\t\t}\n\t}\n\tallowedTypes := make([]string, len(targetTypes))\n\tfor i, t := range targetTypes {\n\t\tallowedTypes[i] = targetTypeString(t)\n\t}\n\tif len(targetTypes) == 1 && targetTypes[0] == descriptorpb.FieldOptions_TARGET_TYPE_UNKNOWN {\n\t\treturn interp.handleErrorf(interp.nodeInfo(node), \"field %q may not be used in an option (it declares no allowed target types)\", fld.FullName())\n\t}\n\treturn interp.handleErrorf(interp.nodeInfo(node), \"field %q is allowed on [%s], not on %s\", fld.FullName(), strings.Join(allowedTypes, \",\"), targetTypeString(targetType))\n}\n\nfunc targetTypeString(t descriptorpb.FieldOptions_OptionTargetType) string {\n\treturn strings.ToLower(strings.ReplaceAll(strings.TrimPrefix(t.String(), \"TARGET_TYPE_\"), \"_\", \" \"))\n}\n\nfunc editionString(t descriptorpb.Edition) string {\n\treturn strings.ToLower(strings.ReplaceAll(strings.TrimPrefix(t.String(), \"EDITION_\"), \"_\", \"-\"))\n}\n\nfunc cloneInto(dest proto.Message, src proto.Message, res linker.Resolver) error {\n\tif dest.ProtoReflect().Descriptor() == src.ProtoReflect().Descriptor() {\n\t\tproto.Reset(dest)\n\t\tproto.Merge(dest, src)\n\t\treturn nil\n\t}\n\n\t// If descriptors are not the same, we could have field descriptors in src that\n\t// don't match the ones in dest. There's no easy/sane way to handle that. So we\n\t// just marshal to bytes and back to do this\n\tmarshaler := proto.MarshalOptions{\n\t\t// We've already validated required fields before this point,\n\t\t// so we can allow partial here.\n\t\tAllowPartial: true,\n\t}\n\tdata, err := marshaler.Marshal(src)\n\tif err != nil {\n\t\treturn err\n\t}\n\tunmarshaler := proto.UnmarshalOptions{AllowPartial: true}\n\tif res != nil {\n\t\tunmarshaler.Resolver = res\n\t} else {\n\t\t// Use a typed nil, which returns \"not found\" to all queries\n\t\t// and prevents fallback to protoregistry.GlobalTypes.\n\t\tunmarshaler.Resolver = (*protoregistry.Types)(nil)\n\t}\n\treturn unmarshaler.Unmarshal(data, dest)\n}\n\nfunc (interp *interpreter) validateRecursive(\n\tvalidateRequiredFields bool,\n\tmsg protoreflect.Message,\n\tprefix string,\n\telement proto.Message,\n\tpath []int32,\n\tisFeatures bool,\n\tinFeatures bool,\n\tinMap bool,\n) error {\n\tif validateRequiredFields {\n\t\tflds := msg.Descriptor().Fields()\n\t\tvar missingFields []string\n\t\tfor i := 0; i < flds.Len(); i++ {\n\t\t\tfld := flds.Get(i)\n\t\t\tif fld.Cardinality() == protoreflect.Required && !msg.Has(fld) {\n\t\t\t\tmissingFields = append(missingFields, fmt.Sprintf(\"%s%s\", prefix, fld.Name()))\n\t\t\t}\n\t\t}\n\t\tif len(missingFields) > 0 {\n\t\t\tnode := interp.findOptionNode(path, element)\n\t\t\terr := interp.handleErrorf(interp.nodeInfo(node), \"error in %s options: some required fields missing: %v\", descriptorType(element), strings.Join(missingFields, \", \"))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tvar err error\n\tmsg.Range(func(fld protoreflect.FieldDescriptor, val protoreflect.Value) bool {\n\t\tchpath := path\n\t\tif !inMap {\n\t\t\tchpath = append(chpath, int32(fld.Number()))\n\t\t}\n\t\tchInFeatures := isFeatures || inFeatures\n\t\tchIsFeatures := !chInFeatures && len(path) == 0 && fld.Name() == \"features\"\n\n\t\tif (isFeatures || (inFeatures && fld.IsExtension())) &&\n\t\t\tinterp.file.FileNode().Name() == fld.ParentFile().Path() {\n\t\t\tvar what, name string\n\t\t\tif fld.IsExtension() {\n\t\t\t\twhat = \"custom feature\"\n\t\t\t\tname = \"(\" + string(fld.FullName()) + \")\"\n\t\t\t} else {\n\t\t\t\twhat = \"feature\"\n\t\t\t\tname = string(fld.Name())\n\t\t\t}\n\t\t\tnode := interp.findOptionNode(path, element)\n\t\t\terr = interp.handleErrorf(interp.nodeInfo(node), \"%s %s cannot be used from the same file in which it is defined\", what, name)\n\t\t\tif err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tif chInFeatures {\n\t\t\t// Validate feature usage against feature settings.\n\n\t\t\t// First, check the feature support settings of the field.\n\t\t\topts, _ := fld.Options().(*descriptorpb.FieldOptions)\n\t\t\tedition := interp.file.FileDescriptorProto().GetEdition()\n\t\t\tif opts != nil && opts.FeatureSupport != nil {\n\t\t\t\terr = interp.validateFeatureSupport(edition, opts.FeatureSupport, \"field\", string(fld.FullName()), chpath, element)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Then, if it's an enum or has an enum, check the feature support settings of the enum values.\n\t\t\tvar enum protoreflect.EnumDescriptor\n\t\t\tif fld.Enum() != nil {\n\t\t\t\tenum = fld.Enum()\n\t\t\t} else if fld.IsMap() && fld.MapValue().Enum() != nil {\n\t\t\t\tenum = fld.MapValue().Enum()\n\t\t\t}\n\t\t\tif enum != nil {\n\t\t\t\tswitch {\n\t\t\t\tcase fld.IsMap():\n\t\t\t\t\tval.Map().Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {\n\t\t\t\t\t\t// Can't construct path to particular map entry since we don't this entry's index.\n\t\t\t\t\t\t// So we leave chpath alone, and it will have to point to the whole map value (or\n\t\t\t\t\t\t// the first entry if the map is de-structured across multiple option statements).\n\t\t\t\t\t\terr = interp.validateEnumValueFeatureSupport(edition, enum, v.Enum(), chpath, element)\n\t\t\t\t\t\treturn err == nil\n\t\t\t\t\t})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\tcase fld.IsList():\n\t\t\t\t\tsl := val.List()\n\t\t\t\t\tfor i := 0; i < sl.Len(); i++ {\n\t\t\t\t\t\tv := sl.Get(i)\n\t\t\t\t\t\terr = interp.validateEnumValueFeatureSupport(edition, enum, v.Enum(), append(chpath, int32(i)), element)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\terr = interp.validateEnumValueFeatureSupport(edition, enum, val.Enum(), chpath, element)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If it's a message or contains a message, recursively validate fields in those messages.\n\t\tswitch {\n\t\tcase fld.IsMap() && fld.MapValue().Message() != nil:\n\t\t\tval.Map().Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {\n\t\t\t\tchprefix := fmt.Sprintf(\"%s%s[%v].\", prefix, fieldName(fld), k)\n\t\t\t\terr = interp.validateRecursive(validateRequiredFields, v.Message(), chprefix, element, chpath, chIsFeatures, chInFeatures, true)\n\t\t\t\treturn err == nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\tcase fld.IsList() && fld.Message() != nil:\n\t\t\tsl := val.List()\n\t\t\tfor i := 0; i < sl.Len(); i++ {\n\t\t\t\tv := sl.Get(i)\n\t\t\t\tchprefix := fmt.Sprintf(\"%s%s[%d].\", prefix, fieldName(fld), i)\n\t\t\t\tif !inMap {\n\t\t\t\t\tchpath = append(chpath, int32(i))\n\t\t\t\t}\n\t\t\t\terr = interp.validateRecursive(validateRequiredFields, v.Message(), chprefix, element, chpath, chIsFeatures, chInFeatures, inMap)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\tcase !fld.IsMap() && fld.Message() != nil:\n\t\t\tchprefix := fmt.Sprintf(\"%s%s.\", prefix, fieldName(fld))\n\t\t\terr = interp.validateRecursive(validateRequiredFields, val.Message(), chprefix, element, chpath, chIsFeatures, chInFeatures, inMap)\n\t\t\tif err != nil {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n\treturn err\n}\n\nfunc (interp *interpreter) validateEnumValueFeatureSupport(\n\tedition descriptorpb.Edition,\n\tenum protoreflect.EnumDescriptor,\n\tnumber protoreflect.EnumNumber,\n\tpath []int32,\n\telement proto.Message,\n) error {\n\tenumVal := enum.Values().ByNumber(number)\n\tif enumVal == nil {\n\t\treturn nil\n\t}\n\tenumValOpts, _ := enumVal.Options().(*descriptorpb.EnumValueOptions)\n\tif enumValOpts == nil || enumValOpts.FeatureSupport == nil {\n\t\treturn nil\n\t}\n\treturn interp.validateFeatureSupport(edition, enumValOpts.FeatureSupport, \"enum value\", string(enumVal.Name()), path, element)\n}\n\nfunc (interp *interpreter) validateFeatureSupport(\n\tedition descriptorpb.Edition,\n\tfeatureSupport *descriptorpb.FieldOptions_FeatureSupport,\n\twhat string,\n\tname string,\n\tpath []int32,\n\telement proto.Message,\n) error {\n\tif featureSupport.EditionIntroduced != nil && edition < featureSupport.GetEditionIntroduced() {\n\t\tnode := interp.findOptionNode(path, element)\n\t\terr := interp.handleErrorf(interp.nodeInfo(node), \"%s %q was not introduced until edition %s\", what, name, editionString(featureSupport.GetEditionIntroduced()))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif featureSupport.EditionRemoved != nil && edition >= featureSupport.GetEditionRemoved() {\n\t\tnode := interp.findOptionNode(path, element)\n\t\terr := interp.handleErrorf(interp.nodeInfo(node), \"%s %q was removed in edition %s\", what, name, editionString(featureSupport.GetEditionRemoved()))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif featureSupport.EditionDeprecated != nil && edition >= featureSupport.GetEditionDeprecated() {\n\t\tnode := interp.findOptionNode(path, element)\n\t\tvar suffix string\n\t\tif featureSupport.GetDeprecationWarning() != \"\" {\n\t\t\tsuffix = \": \" + featureSupport.GetDeprecationWarning()\n\t\t}\n\t\tinterp.reporter.HandleWarningf(interp.nodeInfo(node), \"%s %q is deprecated as of edition %s%s\", what, name, editionString(featureSupport.GetEditionDeprecated()), suffix)\n\t}\n\treturn nil\n}\n\nfunc (interp *interpreter) findOptionNode(\n\tpath []int32,\n\telement proto.Message,\n) ast.Node {\n\telementNode := interp.file.Node(element)\n\tnodeWithOpts, _ := elementNode.(ast.NodeWithOptions)\n\tif nodeWithOpts == nil {\n\t\treturn elementNode\n\t}\n\tnode, _ := findOptionNode[*ast.OptionNode](\n\t\tpath,\n\t\toptionsRanger{nodeWithOpts},\n\t\tfunc(n *ast.OptionNode) *sourceinfo.OptionSourceInfo {\n\t\t\treturn interp.index[n]\n\t\t},\n\t)\n\tif node != nil {\n\t\treturn node\n\t}\n\treturn elementNode\n}\n\nfunc findOptionNode[N ast.Node](\n\tpath []int32,\n\tnodes interface {\n\t\tRange(func(N, ast.ValueNode) bool)\n\t},\n\tsrcInfoAccessor func(N) *sourceinfo.OptionSourceInfo,\n) (ast.Node, int) {\n\tvar bestMatch ast.Node\n\tvar bestMatchLen int\n\tnodes.Range(func(node N, val ast.ValueNode) bool {\n\t\tsrcInfo := srcInfoAccessor(node)\n\t\tif srcInfo == nil {\n\t\t\t// can happen if we are lenient when interpreting -- this node\n\t\t\t// could not be interpreted and thus has no source info; skip\n\t\t\treturn true\n\t\t}\n\t\tif srcInfo.Path[0] < 0 {\n\t\t\t// negative first value means it's a field pseudo-option; skip\n\t\t\treturn true\n\t\t}\n\t\tmatch, matchLen := findOptionValueNode(path, node, val, srcInfo)\n\t\tif matchLen > bestMatchLen {\n\t\t\tbestMatch = match\n\t\t\tbestMatchLen = matchLen\n\t\t\tif matchLen >= len(path) {\n\t\t\t\t// not going to find a better one\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t})\n\treturn bestMatch, bestMatchLen\n}\n\ntype optionsRanger struct {\n\tnode ast.NodeWithOptions\n}\n\nfunc (r optionsRanger) Range(f func(*ast.OptionNode, ast.ValueNode) bool) {\n\tr.node.RangeOptions(func(optNode *ast.OptionNode) bool {\n\t\treturn f(optNode, optNode.Val)\n\t})\n}\n\ntype valueRanger []ast.ValueNode\n\nfunc (r valueRanger) Range(f func(ast.ValueNode, ast.ValueNode) bool) {\n\tfor _, elem := range r {\n\t\tif !f(elem, elem) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\ntype fieldRanger map[*ast.MessageFieldNode]*sourceinfo.OptionSourceInfo\n\nfunc (r fieldRanger) Range(f func(*ast.MessageFieldNode, ast.ValueNode) bool) {\n\tfor elem := range r {\n\t\tif !f(elem, elem.Val) {\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc isPathMatch(a, b []int32) bool {\n\tlength := len(a)\n\tif len(b) < length {\n\t\tlength = len(b)\n\t}\n\tfor i := 0; i < length; i++ {\n\t\tif a[i] != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc findOptionValueNode(\n\tpath []int32,\n\tnode ast.Node,\n\tvalue ast.ValueNode,\n\tsrcInfo *sourceinfo.OptionSourceInfo,\n) (ast.Node, int) {\n\tsrcInfoPath := srcInfo.Path\n\tif _, ok := srcInfo.Children.(*sourceinfo.ArrayLiteralSourceInfo); ok {\n\t\t// Last path element for array source info is the index of the\n\t\t// first element. So exclude in the comparison, since path could\n\t\t// indicate a later index, which is present in the array.\n\t\tsrcInfoPath = srcInfo.Path[:len(srcInfo.Path)-1]\n\t}\n\n\tif !isPathMatch(path, srcInfoPath) {\n\t\treturn nil, 0\n\t}\n\tif len(srcInfoPath) >= len(path) {\n\t\treturn node, len(path)\n\t}\n\n\tswitch children := srcInfo.Children.(type) {\n\tcase *sourceinfo.ArrayLiteralSourceInfo:\n\t\tarray, ok := value.(*ast.ArrayLiteralNode)\n\t\tif !ok {\n\t\t\tbreak // should never happen\n\t\t}\n\t\tvar i int\n\t\tmatch, matchLen := findOptionNode[ast.ValueNode](\n\t\t\tpath,\n\t\t\tvalueRanger(array.Elements),\n\t\t\tfunc(_ ast.ValueNode) *sourceinfo.OptionSourceInfo {\n\t\t\t\tval := &children.Elements[i]\n\t\t\t\ti++\n\t\t\t\treturn val\n\t\t\t},\n\t\t)\n\t\tif match != nil {\n\t\t\treturn match, matchLen\n\t\t}\n\n\tcase *sourceinfo.MessageLiteralSourceInfo:\n\t\tmatch, matchLen := findOptionNode[*ast.MessageFieldNode](\n\t\t\tpath,\n\t\t\tfieldRanger(children.Fields),\n\t\t\tfunc(n *ast.MessageFieldNode) *sourceinfo.OptionSourceInfo {\n\t\t\t\treturn children.Fields[n]\n\t\t\t},\n\t\t)\n\t\tif match != nil {\n\t\t\treturn match, matchLen\n\t\t}\n\t}\n\n\treturn node, len(srcInfoPath)\n}\n\n// interpretField interprets the option described by opt, as a field inside the given msg. This\n// interprets components of the option name starting at nameIndex. When nameIndex == 0, then\n// msg must be an options message. For nameIndex > 0, msg is a nested message inside of the\n// options message. The given pathPrefix is the path (sequence of field numbers and indices\n// with a FileDescriptorProto as the start) up to but not including the given nameIndex.\n//\n// Any errors encountered will be handled, so the returned error will only be non-nil if\n// the handler returned non-nil. Callers must check that the source info is non-nil before\n// using it since it can be nil (in the event of a problem) even if the error is nil.\nfunc (interp *interpreter) interpretField(\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\tmc *internal.MessageContext,\n\tmsg protoreflect.Message,\n\topt *descriptorpb.UninterpretedOption,\n\tnameIndex int,\n\tpathPrefix []int32,\n) (*sourceinfo.OptionSourceInfo, error) {\n\tvar fld protoreflect.FieldDescriptor\n\tnm := opt.GetName()[nameIndex]\n\tnode := interp.file.OptionNamePartNode(nm)\n\tif nm.GetIsExtension() {\n\t\textName := nm.GetNamePart()\n\t\tif extName[0] == '.' {\n\t\t\textName = extName[1:] /* skip leading dot */\n\t\t}\n\t\tvar err error\n\t\tfld, err = interp.resolveExtensionType(extName)\n\t\tif errors.Is(err, protoregistry.NotFound) {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(node),\n\t\t\t\t\"%vunrecognized extension %s of %s\",\n\t\t\t\tmc, extName, msg.Descriptor().FullName())\n\t\t} else if err != nil {\n\t\t\treturn nil, interp.handleErrorWithPos(interp.nodeInfo(node), err)\n\t\t}\n\t\tif fld.ContainingMessage().FullName() != msg.Descriptor().FullName() {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(node),\n\t\t\t\t\"%vextension %s should extend %s but instead extends %s\",\n\t\t\t\tmc, extName, msg.Descriptor().FullName(), fld.ContainingMessage().FullName())\n\t\t}\n\t} else {\n\t\tfld = msg.Descriptor().Fields().ByName(protoreflect.Name(nm.GetNamePart()))\n\t\tif fld == nil {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(node),\n\t\t\t\t\"%vfield %s of %s does not exist\",\n\t\t\t\tmc, nm.GetNamePart(), msg.Descriptor().FullName())\n\t\t}\n\t}\n\tpathPrefix = append(pathPrefix, int32(fld.Number()))\n\n\tif err := interp.checkFieldUsage(targetType, fld, node); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(opt.GetName()) > nameIndex+1 {\n\t\tnextnm := opt.GetName()[nameIndex+1]\n\t\tnextnode := interp.file.OptionNamePartNode(nextnm)\n\t\tk := fld.Kind()\n\t\tif k != protoreflect.MessageKind && k != protoreflect.GroupKind {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(nextnode),\n\t\t\t\t\"%vcannot set field %s because %s is not a message\",\n\t\t\t\tmc, nextnm.GetNamePart(), nm.GetNamePart())\n\t\t}\n\t\tif fld.Cardinality() == protoreflect.Repeated {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(nextnode),\n\t\t\t\t\"%vcannot set field %s because %s is repeated (must use an aggregate)\",\n\t\t\t\tmc, nextnm.GetNamePart(), nm.GetNamePart())\n\t\t}\n\t\tvar fdm protoreflect.Message\n\t\tif msg.Has(fld) {\n\t\t\tv := msg.Mutable(fld)\n\t\t\tfdm = v.Message()\n\t\t} else {\n\t\t\tif ood := fld.ContainingOneof(); ood != nil {\n\t\t\t\texistingFld := msg.WhichOneof(ood)\n\t\t\t\tif existingFld != nil && existingFld.Number() != fld.Number() {\n\t\t\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(node),\n\t\t\t\t\t\t\"%voneof %q already has field %q set\",\n\t\t\t\t\t\tmc, ood.Name(), fieldName(existingFld))\n\t\t\t\t}\n\t\t\t}\n\t\t\tfldVal := msg.NewField(fld)\n\t\t\tfdm = fldVal.Message()\n\t\t\tmsg.Set(fld, fldVal)\n\t\t}\n\t\t// recurse to set next part of name\n\t\treturn interp.interpretField(targetType, mc, fdm, opt, nameIndex+1, pathPrefix)\n\t}\n\n\toptNode := interp.file.OptionNode(opt)\n\toptValNode := optNode.GetValue()\n\tvar srcInfo *sourceinfo.OptionSourceInfo\n\tvar err error\n\tif optValNode.Value() == nil {\n\t\terr = interp.setOptionFieldFromProto(targetType, mc, msg, fld, node, opt, optValNode)\n\t\tsrcInfoVal := newSrcInfo(pathPrefix, nil)\n\t\tsrcInfo = &srcInfoVal\n\t} else {\n\t\tsrcInfo, err = interp.setOptionField(targetType, mc, msg, fld, node, optValNode, false, pathPrefix)\n\t}\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn srcInfo, nil\n}\n\n// setOptionField sets the value for field fld in the given message msg to the value represented\n// by AST node val. The given name is the AST node that corresponds to the name of fld. On success,\n// it returns additional metadata about the field that was set.\nfunc (interp *interpreter) setOptionField(\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\tmc *internal.MessageContext,\n\tmsg protoreflect.Message,\n\tfld protoreflect.FieldDescriptor,\n\tname ast.Node,\n\tval ast.ValueNode,\n\tinsideMsgLiteral bool,\n\tpathPrefix []int32,\n) (*sourceinfo.OptionSourceInfo, error) {\n\tv := val.Value()\n\tif sl, ok := v.([]ast.ValueNode); ok {\n\t\t// handle slices a little differently than the others\n\t\tif fld.Cardinality() != protoreflect.Repeated {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(val), \"%vvalue is an array but field is not repeated\", mc)\n\t\t}\n\t\torigPath := mc.OptAggPath\n\t\tdefer func() {\n\t\t\tmc.OptAggPath = origPath\n\t\t}()\n\t\tchildVals := make([]sourceinfo.OptionSourceInfo, len(sl))\n\t\tvar firstIndex int\n\t\tif fld.IsMap() {\n\t\t\tfirstIndex = msg.Get(fld).Map().Len()\n\t\t} else {\n\t\t\tfirstIndex = msg.Get(fld).List().Len()\n\t\t}\n\t\tfor index, item := range sl {\n\t\t\tmc.OptAggPath = fmt.Sprintf(\"%s[%d]\", origPath, index)\n\t\t\tvalue, srcInfo, err := interp.fieldValue(targetType, mc, msg, fld, item, insideMsgLiteral, append(pathPrefix, int32(firstIndex+index)))\n\t\t\tif err != nil || !value.IsValid() {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif fld.IsMap() {\n\t\t\t\tmv := msg.Mutable(fld).Map()\n\t\t\t\tsetMapEntry(fld, msg, mv, value.Message())\n\t\t\t} else {\n\t\t\t\tlv := msg.Mutable(fld).List()\n\t\t\t\tlv.Append(value)\n\t\t\t}\n\t\t\tchildVals[index] = srcInfo\n\t\t}\n\t\tsrcInfo := newSrcInfo(append(pathPrefix, int32(firstIndex)), &sourceinfo.ArrayLiteralSourceInfo{Elements: childVals})\n\t\treturn &srcInfo, nil\n\t}\n\n\tif fld.IsMap() {\n\t\tpathPrefix = append(pathPrefix, int32(msg.Get(fld).Map().Len()))\n\t} else if fld.IsList() {\n\t\tpathPrefix = append(pathPrefix, int32(msg.Get(fld).List().Len()))\n\t}\n\n\tvalue, srcInfo, err := interp.fieldValue(targetType, mc, msg, fld, val, insideMsgLiteral, pathPrefix)\n\tif err != nil || !value.IsValid() {\n\t\treturn nil, err\n\t}\n\n\tif ood := fld.ContainingOneof(); ood != nil {\n\t\texistingFld := msg.WhichOneof(ood)\n\t\tif existingFld != nil && existingFld.Number() != fld.Number() {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(name), \"%voneof %q already has field %q set\", mc, ood.Name(), fieldName(existingFld))\n\t\t}\n\t}\n\n\tswitch {\n\tcase fld.IsMap():\n\t\tmv := msg.Mutable(fld).Map()\n\t\tsetMapEntry(fld, msg, mv, value.Message())\n\tcase fld.IsList():\n\t\tlv := msg.Mutable(fld).List()\n\t\tlv.Append(value)\n\tdefault:\n\t\tif msg.Has(fld) {\n\t\t\treturn nil, interp.handleErrorf(interp.nodeInfo(name), \"%vnon-repeated option field %s already set\", mc, fieldName(fld))\n\t\t}\n\t\tmsg.Set(fld, value)\n\t}\n\treturn &srcInfo, nil\n}\n\n// setOptionFieldFromProto sets the value for field fld in the given message msg to the value\n// represented by the given uninterpreted option. The given ast.Node, if non-nil, will be used\n// to report source positions in error messages. On success, it returns additional metadata\n// about the field that was set.\nfunc (interp *interpreter) setOptionFieldFromProto(\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\tmc *internal.MessageContext,\n\tmsg protoreflect.Message,\n\tfld protoreflect.FieldDescriptor,\n\tname ast.Node,\n\topt *descriptorpb.UninterpretedOption,\n\tnode ast.Node,\n) error {\n\tk := fld.Kind()\n\tvar value protoreflect.Value\n\tswitch k {\n\tcase protoreflect.EnumKind:\n\t\tnum, _, err := interp.enumFieldValueFromProto(mc, fld.Enum(), opt, node)\n\t\tif err != nil {\n\t\t\treturn interp.handleError(err)\n\t\t}\n\t\tvalue = protoreflect.ValueOfEnum(num)\n\n\tcase protoreflect.MessageKind, protoreflect.GroupKind:\n\t\tif opt.AggregateValue == nil {\n\t\t\treturn interp.handleErrorf(interp.nodeInfo(node), \"%vexpecting message, got %s\", mc, optionValueKind(opt))\n\t\t}\n\t\t// We must parse the text format from the aggregate value string\n\t\tvar elem protoreflect.Message\n\t\tswitch {\n\t\tcase fld.IsMap():\n\t\t\telem = dynamicpb.NewMessage(fld.Message())\n\t\tcase fld.IsList():\n\t\t\telem = msg.Get(fld).List().NewElement().Message()\n\t\tdefault:\n\t\t\telem = msg.NewField(fld).Message()\n\t\t}\n\t\terr := prototext.UnmarshalOptions{\n\t\t\tResolver:     &msgLiteralResolver{interp: interp, pkg: fld.ParentFile().Package()},\n\t\t\tAllowPartial: true,\n\t\t}.Unmarshal([]byte(opt.GetAggregateValue()), elem.Interface())\n\t\tif err != nil {\n\t\t\treturn interp.handleErrorf(interp.nodeInfo(node), \"%vfailed to parse message literal %w\", mc, err)\n\t\t}\n\t\tif err := interp.checkFieldUsagesInMessage(targetType, elem, node); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvalue = protoreflect.ValueOfMessage(elem)\n\n\tdefault:\n\t\tv, err := interp.scalarFieldValueFromProto(mc, descriptorpb.FieldDescriptorProto_Type(k), opt, node)\n\t\tif err != nil {\n\t\t\treturn interp.handleError(err)\n\t\t}\n\t\tvalue = protoreflect.ValueOf(v)\n\t}\n\n\tif ood := fld.ContainingOneof(); ood != nil {\n\t\texistingFld := msg.WhichOneof(ood)\n\t\tif existingFld != nil && existingFld.Number() != fld.Number() {\n\t\t\treturn interp.handleErrorf(interp.nodeInfo(name), \"%voneof %q already has field %q set\", mc, ood.Name(), fieldName(existingFld))\n\t\t}\n\t}\n\n\tswitch {\n\tcase fld.IsMap():\n\t\tmv := msg.Mutable(fld).Map()\n\t\tsetMapEntry(fld, msg, mv, value.Message())\n\tcase fld.IsList():\n\t\tmsg.Mutable(fld).List().Append(value)\n\tdefault:\n\t\tif msg.Has(fld) {\n\t\t\treturn interp.handleErrorf(interp.nodeInfo(name), \"%vnon-repeated option field %s already set\", mc, fieldName(fld))\n\t\t}\n\t\tmsg.Set(fld, value)\n\t}\n\treturn nil\n}\n\n// checkFieldUsagesInMessage verifies that all fields present in the given\n// message can be used for the given target type. When an AST is\n// present, we validate each field as it is processed. But without\n// an AST, we unmarshal a message from an uninterpreted option's\n// aggregate value string, and then must make sure that all fields\n// set in that message are valid. This reports an error for each\n// invalid field it encounters and returns a non-nil error if/when\n// the handler returns a non-nil error.\nfunc (interp *interpreter) checkFieldUsagesInMessage(\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\tmsg protoreflect.Message,\n\tnode ast.Node,\n) error {\n\tvar err error\n\tmsg.Range(func(fld protoreflect.FieldDescriptor, val protoreflect.Value) bool {\n\t\terr = interp.checkFieldUsage(targetType, fld, node)\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tswitch {\n\t\tcase fld.IsList() && fld.Message() != nil:\n\t\t\tlistVal := val.List()\n\t\t\tfor i, length := 0, listVal.Len(); i < length; i++ {\n\t\t\t\terr = interp.checkFieldUsagesInMessage(targetType, listVal.Get(i).Message(), node)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\tcase fld.IsMap() && fld.MapValue().Message() != nil:\n\t\t\tmapVal := val.Map()\n\t\t\tmapVal.Range(func(_ protoreflect.MapKey, val protoreflect.Value) bool {\n\t\t\t\terr = interp.checkFieldUsagesInMessage(targetType, val.Message(), node)\n\t\t\t\treturn err == nil\n\t\t\t})\n\t\tcase !fld.IsMap() && fld.Message() != nil:\n\t\t\terr = interp.checkFieldUsagesInMessage(targetType, val.Message(), node)\n\t\t}\n\t\treturn err == nil\n\t})\n\treturn err\n}\n\nfunc (interp *interpreter) enableLenience(enable bool) {\n\tif !interp.lenient {\n\t\treturn // nothing to do\n\t}\n\tif enable {\n\t\t// reset the flag that tracks if an error has been reported\n\t\tinterp.lenientErrReported = false\n\t}\n\tinterp.lenienceEnabled = enable\n}\n\nfunc setMapEntry(\n\tfld protoreflect.FieldDescriptor,\n\tmsg protoreflect.Message,\n\tmapVal protoreflect.Map,\n\tentry protoreflect.Message,\n) {\n\tkeyFld, valFld := fld.MapKey(), fld.MapValue()\n\tkey := entry.Get(keyFld)\n\tval := entry.Get(valFld)\n\tif fld.MapValue().Kind() == protoreflect.MessageKind {\n\t\t// Replace any nil/invalid values with an empty message\n\t\tdm, valIsDynamic := val.Interface().(*dynamicpb.Message)\n\t\tif (valIsDynamic && dm == nil) || !val.Message().IsValid() {\n\t\t\tval = protoreflect.ValueOfMessage(dynamicpb.NewMessage(valFld.Message()))\n\t\t}\n\t\t_, containerIsDynamic := msg.Interface().(*dynamicpb.Message)\n\t\tif valIsDynamic && !containerIsDynamic {\n\t\t\t// This happens because we create dynamic messages to represent map entries,\n\t\t\t// but the container of the map may expect a non-dynamic, generated type.\n\t\t\tdest := mapVal.NewValue()\n\t\t\t_, destIsDynamic := dest.Message().Interface().(*dynamicpb.Message)\n\t\t\tif !destIsDynamic {\n\t\t\t\t// reflection Set methods do not support cases where destination is\n\t\t\t\t// generated but source is dynamic (or vice versa). But proto.Merge\n\t\t\t\t// *DOES* support that, as long as dest and source use the same\n\t\t\t\t// descriptor.\n\t\t\t\tproto.Merge(dest.Message().Interface(), val.Message().Interface())\n\t\t\t\tval = dest\n\t\t\t}\n\t\t}\n\t}\n\t// TODO: error if key is already present\n\tmapVal.Set(key.MapKey(), val)\n}\n\ntype msgLiteralResolver struct {\n\tinterp *interpreter\n\tpkg    protoreflect.FullName\n}\n\nfunc (r *msgLiteralResolver) FindMessageByName(message protoreflect.FullName) (protoreflect.MessageType, error) {\n\tif r.interp.resolver == nil {\n\t\treturn nil, protoregistry.NotFound\n\t}\n\treturn r.interp.resolver.FindMessageByName(message)\n}\n\nfunc (r *msgLiteralResolver) FindMessageByURL(url string) (protoreflect.MessageType, error) {\n\t// In a message literal, we don't allow arbitrary URL prefixes\n\tpos := strings.LastIndexByte(url, '/')\n\tvar urlPrefix string\n\tif pos > 0 {\n\t\turlPrefix = url[:pos]\n\t}\n\tif urlPrefix != \"type.googleapis.com\" && urlPrefix != \"type.googleprod.com\" {\n\t\treturn nil, fmt.Errorf(\"could not resolve type reference %s\", url)\n\t}\n\treturn r.FindMessageByName(protoreflect.FullName(url[pos+1:]))\n}\n\nfunc (r *msgLiteralResolver) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {\n\tif r.interp.resolver == nil {\n\t\treturn nil, protoregistry.NotFound\n\t}\n\t// In a message literal, extension name may be partially qualified, relative to package.\n\t// So we have to search through package scopes.\n\tpkg := r.pkg\n\tfor {\n\t\t// TODO: This does not *fully* implement the insane logic of protoc with regards\n\t\t//       to resolving relative references.\n\t\t//       https://protobuf.com/docs/language-spec#reference-resolution\n\t\tname := pkg.Append(protoreflect.Name(field))\n\t\text, err := r.interp.resolver.FindExtensionByName(name)\n\t\tif err == nil {\n\t\t\treturn ext, nil\n\t\t}\n\t\tif pkg == \"\" {\n\t\t\t// no more namespaces to check\n\t\t\treturn nil, err\n\t\t}\n\t\tpkg = pkg.Parent()\n\t}\n}\n\nfunc (r *msgLiteralResolver) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {\n\tif r.interp.resolver == nil {\n\t\treturn nil, protoregistry.NotFound\n\t}\n\treturn r.interp.resolver.FindExtensionByNumber(message, field)\n}\n\nfunc fieldName(fld protoreflect.FieldDescriptor) string {\n\tif fld.IsExtension() {\n\t\treturn fmt.Sprintf(\"(%s)\", fld.FullName())\n\t}\n\treturn string(fld.Name())\n}\n\nfunc valueKind(val interface{}) string {\n\tswitch val := val.(type) {\n\tcase ast.Identifier:\n\t\treturn \"identifier\"\n\tcase bool:\n\t\treturn \"bool\"\n\tcase int64:\n\t\tif val < 0 {\n\t\t\treturn \"negative integer\"\n\t\t}\n\t\treturn \"integer\"\n\tcase uint64:\n\t\treturn \"integer\"\n\tcase float64:\n\t\treturn \"double\"\n\tcase string, []byte:\n\t\treturn \"string\"\n\tcase []*ast.MessageFieldNode:\n\t\treturn \"message\"\n\tcase []ast.ValueNode:\n\t\treturn \"array\"\n\tdefault:\n\t\treturn fmt.Sprintf(\"%T\", val)\n\t}\n}\n\nfunc optionValueKind(opt *descriptorpb.UninterpretedOption) string {\n\tswitch {\n\tcase opt.IdentifierValue != nil:\n\t\treturn \"identifier\"\n\tcase opt.PositiveIntValue != nil:\n\t\treturn \"integer\"\n\tcase opt.NegativeIntValue != nil:\n\t\treturn \"negative integer\"\n\tcase opt.DoubleValue != nil:\n\t\treturn \"double\"\n\tcase opt.StringValue != nil:\n\t\treturn \"string\"\n\tcase opt.AggregateValue != nil:\n\t\treturn \"message\"\n\tdefault:\n\t\t// should not be possible\n\t\treturn \"<nil>\"\n\t}\n}\n\n// fieldValue computes a compile-time value (constant or list or message literal) for the given\n// AST node val. The value in val must be assignable to the field fld.\n//\n// If the returned value is not valid, then an error occurred during processing.\n// The returned err may be nil, however, as any errors will already have been\n// handled (so the resulting error could be nil if the handler returned nil).\nfunc (interp *interpreter) fieldValue(\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\tmc *internal.MessageContext,\n\tmsg protoreflect.Message,\n\tfld protoreflect.FieldDescriptor,\n\tval ast.ValueNode,\n\tinsideMsgLiteral bool,\n\tpathPrefix []int32,\n) (protoreflect.Value, sourceinfo.OptionSourceInfo, error) {\n\tk := fld.Kind()\n\tswitch k {\n\tcase protoreflect.EnumKind:\n\t\tnum, _, err := interp.enumFieldValue(mc, fld.Enum(), val, insideMsgLiteral)\n\t\tif err != nil {\n\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, interp.handleError(err)\n\t\t}\n\t\treturn protoreflect.ValueOfEnum(num), newSrcInfo(pathPrefix, nil), nil\n\n\tcase protoreflect.MessageKind, protoreflect.GroupKind:\n\t\tv := val.Value()\n\t\tif aggs, ok := v.([]*ast.MessageFieldNode); ok {\n\t\t\tvar childMsg protoreflect.Message\n\t\t\tswitch {\n\t\t\tcase fld.IsList():\n\t\t\t\t// List of messages\n\t\t\t\tval := msg.NewField(fld)\n\t\t\t\tchildMsg = val.List().NewElement().Message()\n\t\t\tcase fld.IsMap():\n\t\t\t\t// No generated type for map entries, so we use a dynamic type\n\t\t\t\tchildMsg = dynamicpb.NewMessage(fld.Message())\n\t\t\tdefault:\n\t\t\t\t// Normal message field\n\t\t\t\tchildMsg = msg.NewField(fld).Message()\n\t\t\t}\n\t\t\treturn interp.messageLiteralValue(targetType, mc, aggs, childMsg, pathPrefix)\n\t\t}\n\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{},\n\t\t\tinterp.handleErrorf(interp.nodeInfo(val), \"%vexpecting message, got %s\", mc, valueKind(v))\n\n\tdefault:\n\t\tv, err := interp.scalarFieldValue(mc, descriptorpb.FieldDescriptorProto_Type(k), val, insideMsgLiteral)\n\t\tif err != nil {\n\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, interp.handleError(err)\n\t\t}\n\t\treturn protoreflect.ValueOf(v), newSrcInfo(pathPrefix, nil), nil\n\t}\n}\n\n// enumFieldValue resolves the given AST node val as an enum value descriptor. If the given\n// value is not a valid identifier (or number if allowed), an error is returned instead.\nfunc (interp *interpreter) enumFieldValue(\n\tmc *internal.MessageContext,\n\ted protoreflect.EnumDescriptor,\n\tval ast.ValueNode,\n\tallowNumber bool,\n) (protoreflect.EnumNumber, protoreflect.Name, error) {\n\tv := val.Value()\n\tvar num protoreflect.EnumNumber\n\tswitch v := v.(type) {\n\tcase ast.Identifier:\n\t\tname := protoreflect.Name(v)\n\t\tev := ed.Values().ByName(name)\n\t\tif ev == nil {\n\t\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(val), \"%venum %s has no value named %s\", mc, ed.FullName(), v)\n\t\t}\n\t\treturn ev.Number(), name, nil\n\tcase int64:\n\t\tif !allowNumber {\n\t\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(val), \"%vexpecting enum name, got %s\", mc, valueKind(v))\n\t\t}\n\t\tif v > math.MaxInt32 || v < math.MinInt32 {\n\t\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for an enum\", mc, v)\n\t\t}\n\t\tnum = protoreflect.EnumNumber(v)\n\tcase uint64:\n\t\tif !allowNumber {\n\t\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(val), \"%vexpecting enum name, got %s\", mc, valueKind(v))\n\t\t}\n\t\tif v > math.MaxInt32 {\n\t\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for an enum\", mc, v)\n\t\t}\n\t\tnum = protoreflect.EnumNumber(v)\n\tdefault:\n\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(val), \"%vexpecting enum, got %s\", mc, valueKind(v))\n\t}\n\tev := ed.Values().ByNumber(num)\n\tif ev != nil {\n\t\treturn num, ev.Name(), nil\n\t}\n\tif ed.IsClosed() {\n\t\treturn num, \"\", reporter.Errorf(interp.nodeInfo(val), \"%vclosed enum %s has no value with number %d\", mc, ed.FullName(), num)\n\t}\n\t// unknown value, but enum is open, so we allow it and return blank name\n\treturn num, \"\", nil\n}\n\n// enumFieldValueFromProto resolves the given uninterpreted option value as an enum value descriptor.\n// If the given value is not a valid identifier, an error is returned instead.\nfunc (interp *interpreter) enumFieldValueFromProto(\n\tmc *internal.MessageContext,\n\ted protoreflect.EnumDescriptor,\n\topt *descriptorpb.UninterpretedOption,\n\tnode ast.Node,\n) (protoreflect.EnumNumber, protoreflect.Name, error) {\n\t// We don't have to worry about allowing numbers because numbers are never allowed\n\t// in uninterpreted values; they are only allowed inside aggregate values (i.e.\n\t// message literals).\n\tswitch {\n\tcase opt.IdentifierValue != nil:\n\t\tname := protoreflect.Name(opt.GetIdentifierValue())\n\t\tev := ed.Values().ByName(name)\n\t\tif ev == nil {\n\t\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(node), \"%venum %s has no value named %s\", mc, ed.FullName(), name)\n\t\t}\n\t\treturn ev.Number(), name, nil\n\tdefault:\n\t\treturn 0, \"\", reporter.Errorf(interp.nodeInfo(node), \"%vexpecting enum, got %s\", mc, optionValueKind(opt))\n\t}\n}\n\n// scalarFieldValue resolves the given AST node val as a value whose type is assignable to a\n// field with the given fldType.\nfunc (interp *interpreter) scalarFieldValue(\n\tmc *internal.MessageContext,\n\tfldType descriptorpb.FieldDescriptorProto_Type,\n\tval ast.ValueNode,\n\tinsideMsgLiteral bool,\n) (interface{}, error) {\n\tv := val.Value()\n\tswitch fldType {\n\tcase descriptorpb.FieldDescriptorProto_TYPE_BOOL:\n\t\tif b, ok := v.(bool); ok {\n\t\t\treturn b, nil\n\t\t}\n\t\tif id, ok := v.(ast.Identifier); ok {\n\t\t\tif insideMsgLiteral {\n\t\t\t\t// inside a message literal, values use the protobuf text format,\n\t\t\t\t// which is lenient in that it accepts \"t\" and \"f\" or \"True\" and \"False\"\n\t\t\t\tswitch id {\n\t\t\t\tcase \"t\", \"true\", \"True\":\n\t\t\t\t\treturn true, nil\n\t\t\t\tcase \"f\", \"false\", \"False\":\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// options with simple scalar values (no message literal) are stricter\n\t\t\t\tswitch id {\n\t\t\t\tcase \"true\":\n\t\t\t\t\treturn true, nil\n\t\t\t\tcase \"false\":\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting bool, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_BYTES:\n\t\tif str, ok := v.(string); ok {\n\t\t\treturn []byte(str), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting bytes, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_STRING:\n\t\tif str, ok := v.(string); ok {\n\t\t\treturn str, nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting string, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_INT32, descriptorpb.FieldDescriptorProto_TYPE_SINT32, descriptorpb.FieldDescriptorProto_TYPE_SFIXED32:\n\t\tif i, ok := v.(int64); ok {\n\t\t\tif i > math.MaxInt32 || i < math.MinInt32 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for int32\", mc, i)\n\t\t\t}\n\t\t\treturn int32(i), nil\n\t\t}\n\t\tif ui, ok := v.(uint64); ok {\n\t\t\tif ui > math.MaxInt32 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for int32\", mc, ui)\n\t\t\t}\n\t\t\treturn int32(ui), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting int32, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_UINT32, descriptorpb.FieldDescriptorProto_TYPE_FIXED32:\n\t\tif i, ok := v.(int64); ok {\n\t\t\tif i > math.MaxUint32 || i < 0 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for uint32\", mc, i)\n\t\t\t}\n\t\t\treturn uint32(i), nil\n\t\t}\n\t\tif ui, ok := v.(uint64); ok {\n\t\t\tif ui > math.MaxUint32 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for uint32\", mc, ui)\n\t\t\t}\n\t\t\treturn uint32(ui), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting uint32, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_INT64, descriptorpb.FieldDescriptorProto_TYPE_SINT64, descriptorpb.FieldDescriptorProto_TYPE_SFIXED64:\n\t\tif i, ok := v.(int64); ok {\n\t\t\treturn i, nil\n\t\t}\n\t\tif ui, ok := v.(uint64); ok {\n\t\t\tif ui > math.MaxInt64 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for int64\", mc, ui)\n\t\t\t}\n\t\t\treturn int64(ui), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting int64, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_UINT64, descriptorpb.FieldDescriptorProto_TYPE_FIXED64:\n\t\tif i, ok := v.(int64); ok {\n\t\t\tif i < 0 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vvalue %d is out of range for uint64\", mc, i)\n\t\t\t}\n\t\t\treturn uint64(i), nil\n\t\t}\n\t\tif ui, ok := v.(uint64); ok {\n\t\t\treturn ui, nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting uint64, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_DOUBLE:\n\t\tif id, ok := v.(ast.Identifier); ok {\n\t\t\tswitch id {\n\t\t\tcase \"inf\":\n\t\t\t\treturn math.Inf(1), nil\n\t\t\tcase \"nan\":\n\t\t\t\treturn math.NaN(), nil\n\t\t\t}\n\t\t}\n\t\tif d, ok := v.(float64); ok {\n\t\t\treturn d, nil\n\t\t}\n\t\tif i, ok := v.(int64); ok {\n\t\t\treturn float64(i), nil\n\t\t}\n\t\tif u, ok := v.(uint64); ok {\n\t\t\treturn float64(u), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting double, got %s\", mc, valueKind(v))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_FLOAT:\n\t\tif id, ok := v.(ast.Identifier); ok {\n\t\t\tswitch id {\n\t\t\tcase \"inf\":\n\t\t\t\treturn float32(math.Inf(1)), nil\n\t\t\tcase \"nan\":\n\t\t\t\treturn float32(math.NaN()), nil\n\t\t\t}\n\t\t}\n\t\tif d, ok := v.(float64); ok {\n\t\t\treturn float32(d), nil\n\t\t}\n\t\tif i, ok := v.(int64); ok {\n\t\t\treturn float32(i), nil\n\t\t}\n\t\tif u, ok := v.(uint64); ok {\n\t\t\treturn float32(u), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vexpecting float, got %s\", mc, valueKind(v))\n\tdefault:\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(val), \"%vunrecognized field type: %s\", mc, fldType)\n\t}\n}\n\n// scalarFieldValue resolves the given uninterpreted option value as a value whose type is\n// assignable to a field with the given fldType.\nfunc (interp *interpreter) scalarFieldValueFromProto(\n\tmc *internal.MessageContext,\n\tfldType descriptorpb.FieldDescriptorProto_Type,\n\topt *descriptorpb.UninterpretedOption,\n\tnode ast.Node,\n) (interface{}, error) {\n\tswitch fldType {\n\tcase descriptorpb.FieldDescriptorProto_TYPE_BOOL:\n\t\tif opt.IdentifierValue != nil {\n\t\t\tswitch opt.GetIdentifierValue() {\n\t\t\tcase \"true\":\n\t\t\t\treturn true, nil\n\t\t\tcase \"false\":\n\t\t\t\treturn false, nil\n\t\t\t}\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting bool, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_BYTES:\n\t\tif opt.StringValue != nil {\n\t\t\treturn opt.GetStringValue(), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting bytes, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_STRING:\n\t\tif opt.StringValue != nil {\n\t\t\treturn string(opt.GetStringValue()), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting string, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_INT32, descriptorpb.FieldDescriptorProto_TYPE_SINT32, descriptorpb.FieldDescriptorProto_TYPE_SFIXED32:\n\t\tif opt.NegativeIntValue != nil {\n\t\t\ti := opt.GetNegativeIntValue()\n\t\t\tif i > math.MaxInt32 || i < math.MinInt32 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vvalue %d is out of range for int32\", mc, i)\n\t\t\t}\n\t\t\treturn int32(i), nil\n\t\t}\n\t\tif opt.PositiveIntValue != nil {\n\t\t\tui := opt.GetPositiveIntValue()\n\t\t\tif ui > math.MaxInt32 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vvalue %d is out of range for int32\", mc, ui)\n\t\t\t}\n\t\t\treturn int32(ui), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting int32, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_UINT32, descriptorpb.FieldDescriptorProto_TYPE_FIXED32:\n\t\tif opt.NegativeIntValue != nil {\n\t\t\ti := opt.GetNegativeIntValue()\n\t\t\tif i > math.MaxUint32 || i < 0 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vvalue %d is out of range for uint32\", mc, i)\n\t\t\t}\n\t\t\treturn uint32(i), nil\n\t\t}\n\t\tif opt.PositiveIntValue != nil {\n\t\t\tui := opt.GetPositiveIntValue()\n\t\t\tif ui > math.MaxUint32 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vvalue %d is out of range for uint32\", mc, ui)\n\t\t\t}\n\t\t\treturn uint32(ui), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting uint32, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_INT64, descriptorpb.FieldDescriptorProto_TYPE_SINT64, descriptorpb.FieldDescriptorProto_TYPE_SFIXED64:\n\t\tif opt.NegativeIntValue != nil {\n\t\t\treturn opt.GetNegativeIntValue(), nil\n\t\t}\n\t\tif opt.PositiveIntValue != nil {\n\t\t\tui := opt.GetPositiveIntValue()\n\t\t\tif ui > math.MaxInt64 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vvalue %d is out of range for int64\", mc, ui)\n\t\t\t}\n\t\t\treturn int64(ui), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting int64, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_UINT64, descriptorpb.FieldDescriptorProto_TYPE_FIXED64:\n\t\tif opt.NegativeIntValue != nil {\n\t\t\ti := opt.GetNegativeIntValue()\n\t\t\tif i < 0 {\n\t\t\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vvalue %d is out of range for uint64\", mc, i)\n\t\t\t}\n\t\t\t// should not be possible since i should always be negative...\n\t\t\treturn uint64(i), nil\n\t\t}\n\t\tif opt.PositiveIntValue != nil {\n\t\t\treturn opt.GetPositiveIntValue(), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting uint64, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_DOUBLE:\n\t\tif opt.IdentifierValue != nil {\n\t\t\tswitch opt.GetIdentifierValue() {\n\t\t\tcase \"inf\":\n\t\t\t\treturn math.Inf(1), nil\n\t\t\tcase \"nan\":\n\t\t\t\treturn math.NaN(), nil\n\t\t\t}\n\t\t}\n\t\tif opt.DoubleValue != nil {\n\t\t\treturn opt.GetDoubleValue(), nil\n\t\t}\n\t\tif opt.NegativeIntValue != nil {\n\t\t\treturn float64(opt.GetNegativeIntValue()), nil\n\t\t}\n\t\tif opt.PositiveIntValue != nil {\n\t\t\treturn float64(opt.GetPositiveIntValue()), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting double, got %s\", mc, optionValueKind(opt))\n\tcase descriptorpb.FieldDescriptorProto_TYPE_FLOAT:\n\t\tif opt.IdentifierValue != nil {\n\t\t\tswitch opt.GetIdentifierValue() {\n\t\t\tcase \"inf\":\n\t\t\t\treturn float32(math.Inf(1)), nil\n\t\t\tcase \"nan\":\n\t\t\t\treturn float32(math.NaN()), nil\n\t\t\t}\n\t\t}\n\t\tif opt.DoubleValue != nil {\n\t\t\treturn float32(opt.GetDoubleValue()), nil\n\t\t}\n\t\tif opt.NegativeIntValue != nil {\n\t\t\treturn float32(opt.GetNegativeIntValue()), nil\n\t\t}\n\t\tif opt.PositiveIntValue != nil {\n\t\t\treturn float32(opt.GetPositiveIntValue()), nil\n\t\t}\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vexpecting float, got %s\", mc, optionValueKind(opt))\n\tdefault:\n\t\treturn nil, reporter.Errorf(interp.nodeInfo(node), \"%vunrecognized field type: %s\", mc, fldType)\n\t}\n}\n\nfunc descriptorType(m proto.Message) string {\n\tswitch m := m.(type) {\n\tcase *descriptorpb.DescriptorProto:\n\t\treturn \"message\"\n\tcase *descriptorpb.DescriptorProto_ExtensionRange:\n\t\treturn \"extension range\"\n\tcase *descriptorpb.FieldDescriptorProto:\n\t\tif m.GetExtendee() == \"\" {\n\t\t\treturn \"field\"\n\t\t}\n\t\treturn \"extension\"\n\tcase *descriptorpb.EnumDescriptorProto:\n\t\treturn \"enum\"\n\tcase *descriptorpb.EnumValueDescriptorProto:\n\t\treturn \"enum value\"\n\tcase *descriptorpb.ServiceDescriptorProto:\n\t\treturn \"service\"\n\tcase *descriptorpb.MethodDescriptorProto:\n\t\treturn \"method\"\n\tcase *descriptorpb.FileDescriptorProto:\n\t\treturn \"file\"\n\tdefault:\n\t\t// shouldn't be possible\n\t\treturn fmt.Sprintf(\"%T\", m)\n\t}\n}\n\n// messageLiteralValue processes a message literal value.\n//\n// If the returned value is not valid, then an error occurred during processing.\n// The returned err may be nil, however, as any errors will already have been\n// handled (so the resulting error could be nil if the handler returned nil).\nfunc (interp *interpreter) messageLiteralValue(\n\ttargetType descriptorpb.FieldOptions_OptionTargetType,\n\tmc *internal.MessageContext,\n\tfieldNodes []*ast.MessageFieldNode,\n\tmsg protoreflect.Message,\n\tpathPrefix []int32,\n) (protoreflect.Value, sourceinfo.OptionSourceInfo, error) {\n\tfmd := msg.Descriptor()\n\torigPath := mc.OptAggPath\n\tdefer func() {\n\t\tmc.OptAggPath = origPath\n\t}()\n\tflds := make(map[*ast.MessageFieldNode]*sourceinfo.OptionSourceInfo, len(fieldNodes))\n\tvar hadError bool\n\tfor _, fieldNode := range fieldNodes {\n\t\tif origPath == \"\" {\n\t\t\tmc.OptAggPath = fieldNode.Name.Value()\n\t\t} else {\n\t\t\tmc.OptAggPath = origPath + \".\" + fieldNode.Name.Value()\n\t\t}\n\t\tif fieldNode.Name.IsAnyTypeReference() {\n\t\t\tif len(fieldNodes) > 1 {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Name.URLPrefix), \"%vany type references cannot be repeated or mixed with other fields\", mc)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t}\n\n\t\t\tif fmd.FullName() != \"google.protobuf.Any\" {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Name.URLPrefix), \"%vtype references are only allowed for google.protobuf.Any, but this type is %s\", mc, fmd.FullName())\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\ttypeURLDescriptor := fmd.Fields().ByNumber(internal.AnyTypeURLTag)\n\t\t\tvar err error\n\t\t\tswitch {\n\t\t\tcase typeURLDescriptor == nil:\n\t\t\t\terr = fmt.Errorf(\"message schema is missing type_url field (number %d)\", internal.AnyTypeURLTag)\n\t\t\tcase typeURLDescriptor.IsList():\n\t\t\t\terr = fmt.Errorf(\"message schema has type_url field (number %d) that is a list but should be singular\", internal.AnyTypeURLTag)\n\t\t\tcase typeURLDescriptor.Kind() != protoreflect.StringKind:\n\t\t\t\terr = fmt.Errorf(\"message schema has type_url field (number %d) that is %s but should be string\", internal.AnyTypeURLTag, typeURLDescriptor.Kind())\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Name), \"%v%w\", mc, err)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvalueDescriptor := fmd.Fields().ByNumber(internal.AnyValueTag)\n\t\t\tswitch {\n\t\t\tcase valueDescriptor == nil:\n\t\t\t\terr = fmt.Errorf(\"message schema is missing value field (number %d)\", internal.AnyValueTag)\n\t\t\tcase valueDescriptor.IsList():\n\t\t\t\terr = fmt.Errorf(\"message schema has value field (number %d) that is a list but should be singular\", internal.AnyValueTag)\n\t\t\tcase valueDescriptor.Kind() != protoreflect.BytesKind:\n\t\t\t\terr = fmt.Errorf(\"message schema has value field (number %d) that is %s but should be bytes\", internal.AnyValueTag, valueDescriptor.Kind())\n\t\t\t}\n\t\t\tif err != nil {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Name), \"%v%w\", mc, err)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\turlPrefix := fieldNode.Name.URLPrefix.AsIdentifier()\n\t\t\tmsgName := fieldNode.Name.Name.AsIdentifier()\n\t\t\tfullURL := fmt.Sprintf(\"%s/%s\", urlPrefix, msgName)\n\t\t\t// TODO: Support other URLs dynamically -- the caller of protocompile\n\t\t\t// should be able to provide a custom resolver that can resolve type\n\t\t\t// URLs into message descriptors. The default resolver would be\n\t\t\t// implemented as below, only accepting \"type.googleapis.com\" and\n\t\t\t// \"type.googleprod.com\" as hosts/prefixes and using the compiled\n\t\t\t// file's transitive closure to find the named message, since that\n\t\t\t// is what protoc does.\n\t\t\tif urlPrefix != \"type.googleapis.com\" && urlPrefix != \"type.googleprod.com\" {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Name.URLPrefix), \"%vcould not resolve type reference %s\", mc, fullURL)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tanyFields, ok := fieldNode.Val.Value().([]*ast.MessageFieldNode)\n\t\t\tif !ok {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Val), \"%vtype references for google.protobuf.Any must have message literal value\", mc)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tanyMd := resolveDescriptor[protoreflect.MessageDescriptor](interp.resolver, string(msgName))\n\t\t\tif anyMd == nil {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Name.URLPrefix), \"%vcould not resolve type reference %s\", mc, fullURL)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// parse the message value\n\t\t\tmsgVal, valueSrcInfo, err := interp.messageLiteralValue(targetType, mc, anyFields, dynamicpb.NewMessage(anyMd), append(pathPrefix, internal.AnyValueTag))\n\t\t\tif err != nil {\n\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t} else if !msgVal.IsValid() {\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tb, err := (proto.MarshalOptions{Deterministic: true}).Marshal(msgVal.Message().Interface())\n\t\t\tif err != nil {\n\t\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Val), \"%vfailed to serialize message value: %w\", mc, err)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t\t}\n\t\t\t\thadError = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Success!\n\t\t\tif !hadError {\n\t\t\t\tmsg.Set(typeURLDescriptor, protoreflect.ValueOfString(fullURL))\n\t\t\t\tmsg.Set(valueDescriptor, protoreflect.ValueOfBytes(b))\n\t\t\t\tflds[fieldNode] = &valueSrcInfo\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Not expanded Any syntax; handle normal field.\n\t\tvar ffld protoreflect.FieldDescriptor\n\t\tvar err error\n\t\tif fieldNode.Name.IsExtension() {\n\t\t\tn := interp.file.ResolveMessageLiteralExtensionName(fieldNode.Name.Name)\n\t\t\tif n == \"\" {\n\t\t\t\t// this should not be possible!\n\t\t\t\tn = string(fieldNode.Name.Name.AsIdentifier())\n\t\t\t}\n\t\t\tffld, err = interp.resolveExtensionType(n)\n\t\t\tif errors.Is(err, protoregistry.NotFound) {\n\t\t\t\t// may need to qualify with package name\n\t\t\t\t// (this should not be necessary!)\n\t\t\t\tpkg := mc.File.FileDescriptorProto().GetPackage()\n\t\t\t\tif pkg != \"\" {\n\t\t\t\t\tffld, err = interp.resolveExtensionType(pkg + \".\" + n)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tffld = fmd.Fields().ByName(protoreflect.Name(fieldNode.Name.Value()))\n\t\t\tif ffld == nil {\n\t\t\t\terr = protoregistry.NotFound\n\t\t\t\t// It could be a proto2 group, where the text format refers to the group type\n\t\t\t\t// name, and the field name is the lower-cased form of that.\n\t\t\t\tffld = fmd.Fields().ByName(protoreflect.Name(strings.ToLower(fieldNode.Name.Value())))\n\t\t\t\tif ffld != nil {\n\t\t\t\t\t// In editions, we support using the group type name only for fields that\n\t\t\t\t\t// \"look like\" proto2 groups.\n\t\t\t\t\tif protoreflect.Name(fieldNode.Name.Value()) == ffld.Message().Name() && // text format uses type name\n\t\t\t\t\t\tffld.Message().FullName().Parent() == ffld.FullName().Parent() && // message and field declared in same scope\n\t\t\t\t\t\tffld.Kind() == protoreflect.GroupKind /* uses delimited encoding */ {\n\t\t\t\t\t\t// This one looks like a proto2 group, so it's a keeper.\n\t\t\t\t\t\terr = nil\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// It doesn't look like a proto2 group, so this is not a match.\n\t\t\t\t\t\tffld = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif errors.Is(err, protoregistry.NotFound) {\n\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Name), \"%vfield %s not found\", mc, string(fieldNode.Name.Name.AsIdentifier()))\n\t\t\tif err != nil {\n\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t}\n\t\t\thadError = true\n\t\t\tcontinue\n\t\t} else if err != nil {\n\t\t\terr := interp.handleErrorWithPos(interp.nodeInfo(fieldNode.Name), err)\n\t\t\tif err != nil {\n\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t}\n\t\t\thadError = true\n\t\t\tcontinue\n\t\t}\n\t\tif err := interp.checkFieldUsage(targetType, ffld, fieldNode.Name); err != nil {\n\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t}\n\t\tif fieldNode.Sep == nil && ffld.Message() == nil {\n\t\t\t// If there is no separator, the field type should be a message.\n\t\t\t// Otherwise, it is an error in the text format.\n\t\t\terr := interp.handleErrorf(interp.nodeInfo(fieldNode.Val), \"syntax error: unexpected value, expecting ':'\")\n\t\t\tif err != nil {\n\t\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t\t}\n\t\t\thadError = true\n\t\t\tcontinue\n\t\t}\n\t\tsrcInfo, err := interp.setOptionField(targetType, mc, msg, ffld, fieldNode.Name, fieldNode.Val, true, append(pathPrefix, int32(ffld.Number())))\n\t\tif err != nil {\n\t\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, err\n\t\t}\n\t\tif srcInfo != nil {\n\t\t\tflds[fieldNode] = srcInfo\n\t\t}\n\t}\n\tif hadError {\n\t\treturn protoreflect.Value{}, sourceinfo.OptionSourceInfo{}, nil\n\t}\n\treturn protoreflect.ValueOfMessage(msg),\n\t\tnewSrcInfo(pathPrefix, &sourceinfo.MessageLiteralSourceInfo{Fields: flds}),\n\t\tnil\n}\n\nfunc newSrcInfo(path []int32, children sourceinfo.OptionChildrenSourceInfo) sourceinfo.OptionSourceInfo {\n\treturn sourceinfo.OptionSourceInfo{\n\t\tPath:     internal.ClonePath(path),\n\t\tChildren: children,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/options/source_retention_options.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage options\n\nimport (\n\t\"fmt\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/internal\"\n)\n\n// StripSourceRetentionOptionsFromFile returns a file descriptor proto that omits any\n// options in file that are defined to be retained only in source. If file has no\n// such options, then it is returned as is. If it does have such options, a copy is\n// made; the given file will not be mutated.\n//\n// Even when a copy is returned, it is not a deep copy: it may share data with the\n// original file. So callers should not mutate the returned file unless mutating the\n// input file is also safe.\nfunc StripSourceRetentionOptionsFromFile(file *descriptorpb.FileDescriptorProto) (*descriptorpb.FileDescriptorProto, error) {\n\tvar path sourcePath\n\tvar removedPaths *sourcePathTrie\n\tif file.SourceCodeInfo != nil && len(file.SourceCodeInfo.Location) > 0 {\n\t\tpath = make(sourcePath, 0, 16)\n\t\tremovedPaths = &sourcePathTrie{}\n\t}\n\tvar dirty bool\n\toptionsPath := path.push(internal.FileOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(file.GetOptions(), optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts != file.GetOptions() {\n\t\tdirty = true\n\t}\n\tmsgsPath := path.push(internal.FileMessagesTag)\n\tnewMsgs, changed, err := stripOptionsFromAll(file.GetMessageType(), stripSourceRetentionOptionsFromMessage, msgsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\tenumsPath := path.push(internal.FileEnumsTag)\n\tnewEnums, changed, err := stripOptionsFromAll(file.GetEnumType(), stripSourceRetentionOptionsFromEnum, enumsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\textsPath := path.push(internal.FileExtensionsTag)\n\tnewExts, changed, err := stripOptionsFromAll(file.GetExtension(), stripSourceRetentionOptionsFromField, extsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\tsvcsPath := path.push(internal.FileServicesTag)\n\tnewSvcs, changed, err := stripOptionsFromAll(file.GetService(), stripSourceRetentionOptionsFromService, svcsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\n\tif !dirty {\n\t\treturn file, nil\n\t}\n\n\tnewFile, err := shallowCopy(file)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewFile.Options = newOpts\n\tnewFile.MessageType = newMsgs\n\tnewFile.EnumType = newEnums\n\tnewFile.Extension = newExts\n\tnewFile.Service = newSvcs\n\tnewFile.SourceCodeInfo = stripSourcePathsForSourceRetentionOptions(newFile.SourceCodeInfo, removedPaths)\n\treturn newFile, nil\n}\n\ntype sourcePath protoreflect.SourcePath\n\nfunc (p sourcePath) push(element int32) sourcePath {\n\tif p == nil {\n\t\treturn nil\n\t}\n\treturn append(p, element)\n}\n\ntype sourcePathTrie struct {\n\tremoved  bool\n\tchildren map[int32]*sourcePathTrie\n}\n\nfunc (t *sourcePathTrie) addPath(p sourcePath) {\n\tif t == nil {\n\t\treturn\n\t}\n\tif len(p) == 0 {\n\t\tt.removed = true\n\t\treturn\n\t}\n\tchild := t.children[p[0]]\n\tif child == nil {\n\t\tif t.children == nil {\n\t\t\tt.children = map[int32]*sourcePathTrie{}\n\t\t}\n\t\tchild = &sourcePathTrie{}\n\t\tt.children[p[0]] = child\n\t}\n\tchild.addPath(p[1:])\n}\n\nfunc (t *sourcePathTrie) isRemoved(p []int32) bool {\n\tif t == nil {\n\t\treturn false\n\t}\n\tif t.removed {\n\t\treturn true\n\t}\n\tif len(p) == 0 {\n\t\treturn false\n\t}\n\tchild := t.children[p[0]]\n\tif child == nil {\n\t\treturn false\n\t}\n\treturn child.isRemoved(p[1:])\n}\n\nfunc stripSourceRetentionOptions[M proto.Message](\n\toptions M,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (M, error) {\n\toptionsRef := options.ProtoReflect()\n\t// See if there are any options to strip.\n\tvar hasFieldToStrip bool\n\tvar numFieldsToKeep int\n\tvar err error\n\toptionsRef.Range(func(field protoreflect.FieldDescriptor, _ protoreflect.Value) bool {\n\t\tfieldOpts, ok := field.Options().(*descriptorpb.FieldOptions)\n\t\tif !ok {\n\t\t\terr = fmt.Errorf(\"field options is unexpected type: got %T, want %T\", field.Options(), fieldOpts)\n\t\t\treturn false\n\t\t}\n\t\tif fieldOpts.GetRetention() == descriptorpb.FieldOptions_RETENTION_SOURCE {\n\t\t\thasFieldToStrip = true\n\t\t} else {\n\t\t\tnumFieldsToKeep++\n\t\t}\n\t\treturn true\n\t})\n\tvar zero M\n\tif err != nil {\n\t\treturn zero, err\n\t}\n\tif !hasFieldToStrip {\n\t\treturn options, nil\n\t}\n\n\tif numFieldsToKeep == 0 {\n\t\t// Stripping the message would remove *all* options. In that case,\n\t\t// we'll clear out the options by returning the zero value (i.e. nil).\n\t\tremovedPaths.addPath(path) // clear out all source locations, too\n\t\treturn zero, nil\n\t}\n\n\t// There is at least one option to remove. So we need to make a copy that does not have those options.\n\tnewOptions := optionsRef.New()\n\tret, ok := newOptions.Interface().(M)\n\tif !ok {\n\t\treturn zero, fmt.Errorf(\"creating new message of same type resulted in unexpected type; got %T, want %T\", newOptions.Interface(), zero)\n\t}\n\toptionsRef.Range(func(field protoreflect.FieldDescriptor, val protoreflect.Value) bool {\n\t\tfieldOpts, ok := field.Options().(*descriptorpb.FieldOptions)\n\t\tif !ok {\n\t\t\terr = fmt.Errorf(\"field options is unexpected type: got %T, want %T\", field.Options(), fieldOpts)\n\t\t\treturn false\n\t\t}\n\t\tif fieldOpts.GetRetention() != descriptorpb.FieldOptions_RETENTION_SOURCE {\n\t\t\tnewOptions.Set(field, val)\n\t\t} else {\n\t\t\tremovedPaths.addPath(path.push(int32(field.Number())))\n\t\t}\n\t\treturn true\n\t})\n\tif err != nil {\n\t\treturn zero, err\n\t}\n\treturn ret, nil\n}\n\nfunc stripSourceRetentionOptionsFromMessage(\n\tmsg *descriptorpb.DescriptorProto,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.DescriptorProto, error) {\n\tvar dirty bool\n\toptionsPath := path.push(internal.MessageOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(msg.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts != msg.Options {\n\t\tdirty = true\n\t}\n\tfieldsPath := path.push(internal.MessageFieldsTag)\n\tnewFields, changed, err := stripOptionsFromAll(msg.Field, stripSourceRetentionOptionsFromField, fieldsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\toneofsPath := path.push(internal.MessageOneofsTag)\n\tnewOneofs, changed, err := stripOptionsFromAll(msg.OneofDecl, stripSourceRetentionOptionsFromOneof, oneofsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\textRangesPath := path.push(internal.MessageExtensionRangesTag)\n\tnewExtRanges, changed, err := stripOptionsFromAll(msg.ExtensionRange, stripSourceRetentionOptionsFromExtensionRange, extRangesPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\tmsgsPath := path.push(internal.MessageNestedMessagesTag)\n\tnewMsgs, changed, err := stripOptionsFromAll(msg.NestedType, stripSourceRetentionOptionsFromMessage, msgsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\tenumsPath := path.push(internal.MessageEnumsTag)\n\tnewEnums, changed, err := stripOptionsFromAll(msg.EnumType, stripSourceRetentionOptionsFromEnum, enumsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\textsPath := path.push(internal.MessageExtensionsTag)\n\tnewExts, changed, err := stripOptionsFromAll(msg.Extension, stripSourceRetentionOptionsFromField, extsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\n\tif !dirty {\n\t\treturn msg, nil\n\t}\n\n\tnewMsg, err := shallowCopy(msg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewMsg.Options = newOpts\n\tnewMsg.Field = newFields\n\tnewMsg.OneofDecl = newOneofs\n\tnewMsg.ExtensionRange = newExtRanges\n\tnewMsg.NestedType = newMsgs\n\tnewMsg.EnumType = newEnums\n\tnewMsg.Extension = newExts\n\treturn newMsg, nil\n}\n\nfunc stripSourceRetentionOptionsFromField(\n\tfield *descriptorpb.FieldDescriptorProto,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.FieldDescriptorProto, error) {\n\toptionsPath := path.push(internal.FieldOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(field.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts == field.Options {\n\t\treturn field, nil\n\t}\n\tnewField, err := shallowCopy(field)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewField.Options = newOpts\n\treturn newField, nil\n}\n\nfunc stripSourceRetentionOptionsFromOneof(\n\toneof *descriptorpb.OneofDescriptorProto,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.OneofDescriptorProto, error) {\n\toptionsPath := path.push(internal.OneofOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(oneof.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts == oneof.Options {\n\t\treturn oneof, nil\n\t}\n\tnewOneof, err := shallowCopy(oneof)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewOneof.Options = newOpts\n\treturn newOneof, nil\n}\n\nfunc stripSourceRetentionOptionsFromExtensionRange(\n\textRange *descriptorpb.DescriptorProto_ExtensionRange,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.DescriptorProto_ExtensionRange, error) {\n\toptionsPath := path.push(internal.ExtensionRangeOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(extRange.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts == extRange.Options {\n\t\treturn extRange, nil\n\t}\n\tnewExtRange, err := shallowCopy(extRange)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewExtRange.Options = newOpts\n\treturn newExtRange, nil\n}\n\nfunc stripSourceRetentionOptionsFromEnum(\n\tenum *descriptorpb.EnumDescriptorProto,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.EnumDescriptorProto, error) {\n\tvar dirty bool\n\toptionsPath := path.push(internal.EnumOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(enum.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts != enum.Options {\n\t\tdirty = true\n\t}\n\tvalsPath := path.push(internal.EnumValuesTag)\n\tnewVals, changed, err := stripOptionsFromAll(enum.Value, stripSourceRetentionOptionsFromEnumValue, valsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\n\tif !dirty {\n\t\treturn enum, nil\n\t}\n\n\tnewEnum, err := shallowCopy(enum)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewEnum.Options = newOpts\n\tnewEnum.Value = newVals\n\treturn newEnum, nil\n}\n\nfunc stripSourceRetentionOptionsFromEnumValue(\n\tenumVal *descriptorpb.EnumValueDescriptorProto,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.EnumValueDescriptorProto, error) {\n\toptionsPath := path.push(internal.EnumValOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(enumVal.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts == enumVal.Options {\n\t\treturn enumVal, nil\n\t}\n\tnewEnumVal, err := shallowCopy(enumVal)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewEnumVal.Options = newOpts\n\treturn newEnumVal, nil\n}\n\nfunc stripSourceRetentionOptionsFromService(\n\tsvc *descriptorpb.ServiceDescriptorProto,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.ServiceDescriptorProto, error) {\n\tvar dirty bool\n\toptionsPath := path.push(internal.ServiceOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(svc.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts != svc.Options {\n\t\tdirty = true\n\t}\n\tmethodsPath := path.push(internal.ServiceMethodsTag)\n\tnewMethods, changed, err := stripOptionsFromAll(svc.Method, stripSourceRetentionOptionsFromMethod, methodsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif changed {\n\t\tdirty = true\n\t}\n\n\tif !dirty {\n\t\treturn svc, nil\n\t}\n\n\tnewSvc, err := shallowCopy(svc)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewSvc.Options = newOpts\n\tnewSvc.Method = newMethods\n\treturn newSvc, nil\n}\n\nfunc stripSourceRetentionOptionsFromMethod(\n\tmethod *descriptorpb.MethodDescriptorProto,\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) (*descriptorpb.MethodDescriptorProto, error) {\n\toptionsPath := path.push(internal.MethodOptionsTag)\n\tnewOpts, err := stripSourceRetentionOptions(method.Options, optionsPath, removedPaths)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif newOpts == method.Options {\n\t\treturn method, nil\n\t}\n\tnewMethod, err := shallowCopy(method)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewMethod.Options = newOpts\n\treturn newMethod, nil\n}\n\nfunc stripSourcePathsForSourceRetentionOptions(\n\tsourceInfo *descriptorpb.SourceCodeInfo,\n\tremovedPaths *sourcePathTrie,\n) *descriptorpb.SourceCodeInfo {\n\tif sourceInfo == nil || len(sourceInfo.Location) == 0 || removedPaths == nil {\n\t\t// nothing to do\n\t\treturn sourceInfo\n\t}\n\tnewLocations := make([]*descriptorpb.SourceCodeInfo_Location, len(sourceInfo.Location))\n\tvar i int\n\tfor _, loc := range sourceInfo.Location {\n\t\tif removedPaths.isRemoved(loc.Path) {\n\t\t\tcontinue\n\t\t}\n\t\tnewLocations[i] = loc\n\t\ti++\n\t}\n\tnewLocations = newLocations[:i]\n\treturn &descriptorpb.SourceCodeInfo{Location: newLocations}\n}\n\nfunc shallowCopy[M proto.Message](msg M) (M, error) {\n\tmsgRef := msg.ProtoReflect()\n\tother := msgRef.New()\n\tret, ok := other.Interface().(M)\n\tif !ok {\n\t\treturn ret, fmt.Errorf(\"creating new message of same type resulted in unexpected type; got %T, want %T\", other.Interface(), ret)\n\t}\n\tmsgRef.Range(func(field protoreflect.FieldDescriptor, val protoreflect.Value) bool {\n\t\tother.Set(field, val)\n\t\treturn true\n\t})\n\treturn ret, nil\n}\n\n// stripOptionsFromAll applies the given function to each element in the given\n// slice in order to remove source-retention options from it. It returns the new\n// slice and a bool indicating whether anything was actually changed. If the\n// second value is false, then the returned slice is the same slice as the input\n// slice. Usually, T is a pointer type, in which case the given updateFunc should\n// NOT mutate the input value. Instead, it should return the input value if only\n// if there is no update needed. If a mutation is needed, it should return a new\n// value.\nfunc stripOptionsFromAll[T comparable](\n\tslice []T,\n\tupdateFunc func(T, sourcePath, *sourcePathTrie) (T, error),\n\tpath sourcePath,\n\tremovedPaths *sourcePathTrie,\n) ([]T, bool, error) {\n\tvar updated []T // initialized lazily, only when/if a copy is needed\n\tfor i, item := range slice {\n\t\tnewItem, err := updateFunc(item, path.push(int32(i)), removedPaths)\n\t\tif err != nil {\n\t\t\treturn nil, false, err\n\t\t}\n\t\tif updated != nil {\n\t\t\tupdated[i] = newItem\n\t\t} else if newItem != item {\n\t\t\tupdated = make([]T, len(slice))\n\t\t\tcopy(updated[:i], slice)\n\t\t\tupdated[i] = newItem\n\t\t}\n\t}\n\tif updated != nil {\n\t\treturn updated, true, nil\n\t}\n\treturn slice, false, nil\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/options/target_types.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage options\n\nimport (\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n)\n\ntype optionsType[T any] interface {\n\t*T\n\tproto.Message\n\tGetFeatures() *descriptorpb.FeatureSet\n\tGetUninterpretedOption() []*descriptorpb.UninterpretedOption\n}\n\ntype elementType[OptsStruct any, Opts optionsType[OptsStruct]] interface {\n\tproto.Message\n\tGetOptions() Opts\n}\n\ntype targetType[Elem elementType[OptsStruct, Opts], OptsStruct any, Opts optionsType[OptsStruct]] struct {\n\tt                       descriptorpb.FieldOptions_OptionTargetType\n\tsetUninterpretedOptions func(opts Opts, uninterpreted []*descriptorpb.UninterpretedOption)\n\tsetOptions              func(elem Elem, opts Opts)\n}\n\nvar (\n\ttargetTypeFile = newTargetType[*descriptorpb.FileDescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_FILE, setUninterpretedFileOptions, setFileOptions,\n\t)\n\ttargetTypeMessage = newTargetType[*descriptorpb.DescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_MESSAGE, setUninterpretedMessageOptions, setMessageOptions,\n\t)\n\ttargetTypeField = newTargetType[*descriptorpb.FieldDescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_FIELD, setUninterpretedFieldOptions, setFieldOptions,\n\t)\n\ttargetTypeOneof = newTargetType[*descriptorpb.OneofDescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_ONEOF, setUninterpretedOneofOptions, setOneofOptions,\n\t)\n\ttargetTypeExtensionRange = newTargetType[*descriptorpb.DescriptorProto_ExtensionRange](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_EXTENSION_RANGE, setUninterpretedExtensionRangeOptions, setExtensionRangeOptions,\n\t)\n\ttargetTypeEnum = newTargetType[*descriptorpb.EnumDescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_ENUM, setUninterpretedEnumOptions, setEnumOptions,\n\t)\n\ttargetTypeEnumValue = newTargetType[*descriptorpb.EnumValueDescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_ENUM_ENTRY, setUninterpretedEnumValueOptions, setEnumValueOptions,\n\t)\n\ttargetTypeService = newTargetType[*descriptorpb.ServiceDescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_SERVICE, setUninterpretedServiceOptions, setServiceOptions,\n\t)\n\ttargetTypeMethod = newTargetType[*descriptorpb.MethodDescriptorProto](\n\t\tdescriptorpb.FieldOptions_TARGET_TYPE_METHOD, setUninterpretedMethodOptions, setMethodOptions,\n\t)\n)\n\nfunc newTargetType[Elem elementType[OptsStruct, Opts], OptsStruct any, Opts optionsType[OptsStruct]](\n\tt descriptorpb.FieldOptions_OptionTargetType,\n\tsetUninterpretedOptions func(opts Opts, uninterpreted []*descriptorpb.UninterpretedOption),\n\tsetOptions func(elem Elem, opts Opts),\n) *targetType[Elem, OptsStruct, Opts] {\n\treturn &targetType[Elem, OptsStruct, Opts]{\n\t\tt:                       t,\n\t\tsetUninterpretedOptions: setUninterpretedOptions,\n\t\tsetOptions:              setOptions,\n\t}\n}\n\nfunc setUninterpretedFileOptions(opts *descriptorpb.FileOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedMessageOptions(opts *descriptorpb.MessageOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedFieldOptions(opts *descriptorpb.FieldOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedOneofOptions(opts *descriptorpb.OneofOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedExtensionRangeOptions(opts *descriptorpb.ExtensionRangeOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedEnumOptions(opts *descriptorpb.EnumOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedEnumValueOptions(opts *descriptorpb.EnumValueOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedServiceOptions(opts *descriptorpb.ServiceOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setUninterpretedMethodOptions(opts *descriptorpb.MethodOptions, uninterpreted []*descriptorpb.UninterpretedOption) {\n\topts.UninterpretedOption = uninterpreted\n}\n\nfunc setFileOptions(desc *descriptorpb.FileDescriptorProto, opts *descriptorpb.FileOptions) {\n\tdesc.Options = opts\n}\n\nfunc setMessageOptions(desc *descriptorpb.DescriptorProto, opts *descriptorpb.MessageOptions) {\n\tdesc.Options = opts\n}\n\nfunc setFieldOptions(desc *descriptorpb.FieldDescriptorProto, opts *descriptorpb.FieldOptions) {\n\tdesc.Options = opts\n}\n\nfunc setOneofOptions(desc *descriptorpb.OneofDescriptorProto, opts *descriptorpb.OneofOptions) {\n\tdesc.Options = opts\n}\n\nfunc setExtensionRangeOptions(desc *descriptorpb.DescriptorProto_ExtensionRange, opts *descriptorpb.ExtensionRangeOptions) {\n\tdesc.Options = opts\n}\n\nfunc setEnumOptions(desc *descriptorpb.EnumDescriptorProto, opts *descriptorpb.EnumOptions) {\n\tdesc.Options = opts\n}\n\nfunc setEnumValueOptions(desc *descriptorpb.EnumValueDescriptorProto, opts *descriptorpb.EnumValueOptions) {\n\tdesc.Options = opts\n}\n\nfunc setServiceOptions(desc *descriptorpb.ServiceDescriptorProto, opts *descriptorpb.ServiceOptions) {\n\tdesc.Options = opts\n}\n\nfunc setMethodOptions(desc *descriptorpb.MethodDescriptorProto, opts *descriptorpb.MethodOptions) {\n\tdesc.Options = opts\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/ast.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"github.com/bufbuild/protocompile/ast\"\n)\n\n// the types below are accumulator types, just used in intermediate productions\n// to accumulate slices that will get stored in AST nodes\n\ntype compactOptionSlices struct {\n\toptions []*ast.OptionNode\n\tcommas  []*ast.RuneNode\n}\n\nfunc toStringValueNode(strs []*ast.StringLiteralNode) ast.StringValueNode {\n\tif len(strs) == 1 {\n\t\treturn strs[0]\n\t}\n\treturn ast.NewCompoundLiteralStringNode(strs...)\n}\n\ntype nameSlices struct {\n\t// only names or idents will be set, never both\n\tnames  []ast.StringValueNode\n\tidents []*ast.IdentNode\n\tcommas []*ast.RuneNode\n}\n\ntype rangeSlices struct {\n\tranges []*ast.RangeNode\n\tcommas []*ast.RuneNode\n}\n\ntype valueSlices struct {\n\tvals   []ast.ValueNode\n\tcommas []*ast.RuneNode\n}\n\ntype fieldRefSlices struct {\n\trefs []*ast.FieldReferenceNode\n\tdots []*ast.RuneNode\n}\n\ntype identSlices struct {\n\tidents []*ast.IdentNode\n\tdots   []*ast.RuneNode\n}\n\nfunc (s *identSlices) toIdentValueNode(leadingDot *ast.RuneNode) ast.IdentValueNode {\n\tif len(s.idents) == 1 && leadingDot == nil {\n\t\t// single simple name\n\t\treturn s.idents[0]\n\t}\n\treturn ast.NewCompoundIdentNode(leadingDot, s.idents, s.dots)\n}\n\ntype messageFieldList struct {\n\tfield     *ast.MessageFieldNode\n\tdelimiter *ast.RuneNode\n\tnext      *messageFieldList\n}\n\nfunc (list *messageFieldList) toNodes() ([]*ast.MessageFieldNode, []*ast.RuneNode) {\n\tif list == nil {\n\t\treturn nil, nil\n\t}\n\tl := 0\n\tfor cur := list; cur != nil; cur = cur.next {\n\t\tl++\n\t}\n\tfields := make([]*ast.MessageFieldNode, l)\n\tdelimiters := make([]*ast.RuneNode, l)\n\tfor cur, i := list, 0; cur != nil; cur, i = cur.next, i+1 {\n\t\tfields[i] = cur.field\n\t\tif cur.delimiter != nil {\n\t\t\tdelimiters[i] = cur.delimiter\n\t\t}\n\t}\n\treturn fields, delimiters\n}\n\nfunc prependRunes[T ast.Node](convert func(*ast.RuneNode) T, runes []*ast.RuneNode, elements []T) []T {\n\telems := make([]T, 0, len(runes)+len(elements))\n\tfor _, rune := range runes {\n\t\telems = append(elems, convert(rune))\n\t}\n\telems = append(elems, elements...)\n\treturn elems\n}\n\nfunc toServiceElement(semi *ast.RuneNode) ast.ServiceElement {\n\treturn ast.NewEmptyDeclNode(semi)\n}\n\nfunc toMethodElement(semi *ast.RuneNode) ast.RPCElement {\n\treturn ast.NewEmptyDeclNode(semi)\n}\n\nfunc toFileElement(semi *ast.RuneNode) ast.FileElement {\n\treturn ast.NewEmptyDeclNode(semi)\n}\n\nfunc toEnumElement(semi *ast.RuneNode) ast.EnumElement {\n\treturn ast.NewEmptyDeclNode(semi)\n}\n\nfunc toMessageElement(semi *ast.RuneNode) ast.MessageElement {\n\treturn ast.NewEmptyDeclNode(semi)\n}\n\ntype nodeWithRunes[T ast.Node] struct {\n\tNode  T\n\tRunes []*ast.RuneNode\n}\n\nfunc newNodeWithRunes[T ast.Node](node T, trailingRunes ...*ast.RuneNode) nodeWithRunes[T] {\n\treturn nodeWithRunes[T]{\n\t\tNode:  node,\n\t\tRunes: trailingRunes,\n\t}\n}\n\nfunc toElements[T ast.Node](convert func(*ast.RuneNode) T, node T, runes []*ast.RuneNode) []T {\n\telements := make([]T, 1+len(runes))\n\telements[0] = node\n\tfor i, rune := range runes {\n\t\telements[i+1] = convert(rune)\n\t}\n\treturn elements\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/clone.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n)\n\n// Clone returns a copy of the given result. Since descriptor protos may be\n// mutated during linking, this can return a defensive copy so that mutations\n// don't impact concurrent operations in an unsafe way. This is called if the\n// parse result could be re-used across concurrent operations and has unresolved\n// references and options which will require mutation by the linker.\n//\n// If the given value has a method with the following signature, it will be\n// called to perform the operation:\n//\n//\tClone() Result\n//\n// If the given value does not provide a Clone method and is not the implementation\n// provided by this package, it is possible for an error to occur in creating the\n// copy, which may result in a panic. This can happen if the AST of the given result\n// is not actually valid and a file descriptor proto cannot be successfully derived\n// from it.\nfunc Clone(r Result) Result {\n\tif cl, ok := r.(interface{ Clone() Result }); ok {\n\t\treturn cl.Clone()\n\t}\n\tif res, ok := r.(*result); ok {\n\t\tnewProto := proto.Clone(res.proto).(*descriptorpb.FileDescriptorProto) //nolint:errcheck\n\t\tnewNodes := make(map[proto.Message]ast.Node, len(res.nodes))\n\t\tnewResult := &result{\n\t\t\tfile:  res.file,\n\t\t\tproto: newProto,\n\t\t\tnodes: newNodes,\n\t\t}\n\t\trecreateNodeIndexForFile(res, newResult, res.proto, newProto)\n\t\treturn newResult\n\t}\n\n\t// Can't do the deep-copy we know how to do. So we have to take a\n\t// different tactic.\n\tif r.AST() == nil {\n\t\t// no AST? all we have to do is copy the proto\n\t\tfileProto := proto.Clone(r.FileDescriptorProto()).(*descriptorpb.FileDescriptorProto) //nolint:errcheck\n\t\treturn ResultWithoutAST(fileProto)\n\t}\n\t// Otherwise, we have an AST, but no way to clone the result's\n\t// internals. So just re-create them from scratch.\n\tres, err := ResultFromAST(r.AST(), false, reporter.NewHandler(nil))\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn res\n}\n\nfunc recreateNodeIndexForFile(orig, clone *result, origProto, cloneProto *descriptorpb.FileDescriptorProto) {\n\tupdateNodeIndexWithOptions[*descriptorpb.FileOptions](orig, clone, origProto, cloneProto)\n\tfor i, origMd := range origProto.MessageType {\n\t\tcloneMd := cloneProto.MessageType[i]\n\t\trecreateNodeIndexForMessage(orig, clone, origMd, cloneMd)\n\t}\n\tfor i, origEd := range origProto.EnumType {\n\t\tcloneEd := cloneProto.EnumType[i]\n\t\trecreateNodeIndexForEnum(orig, clone, origEd, cloneEd)\n\t}\n\tfor i, origExtd := range origProto.Extension {\n\t\tcloneExtd := cloneProto.Extension[i]\n\t\tupdateNodeIndexWithOptions[*descriptorpb.FieldOptions](orig, clone, origExtd, cloneExtd)\n\t}\n\tfor i, origSd := range origProto.Service {\n\t\tcloneSd := cloneProto.Service[i]\n\t\tupdateNodeIndexWithOptions[*descriptorpb.ServiceOptions](orig, clone, origSd, cloneSd)\n\t\tfor j, origMtd := range origSd.Method {\n\t\t\tcloneMtd := cloneSd.Method[j]\n\t\t\tupdateNodeIndexWithOptions[*descriptorpb.MethodOptions](orig, clone, origMtd, cloneMtd)\n\t\t}\n\t}\n}\n\nfunc recreateNodeIndexForMessage(orig, clone *result, origProto, cloneProto *descriptorpb.DescriptorProto) {\n\tupdateNodeIndexWithOptions[*descriptorpb.MessageOptions](orig, clone, origProto, cloneProto)\n\tfor i, origFld := range origProto.Field {\n\t\tcloneFld := cloneProto.Field[i]\n\t\tupdateNodeIndexWithOptions[*descriptorpb.FieldOptions](orig, clone, origFld, cloneFld)\n\t}\n\tfor i, origOod := range origProto.OneofDecl {\n\t\tcloneOod := cloneProto.OneofDecl[i]\n\t\tupdateNodeIndexWithOptions[*descriptorpb.OneofOptions](orig, clone, origOod, cloneOod)\n\t}\n\tfor i, origExtr := range origProto.ExtensionRange {\n\t\tcloneExtr := cloneProto.ExtensionRange[i]\n\t\tupdateNodeIndex(orig, clone, asExtsNode(origExtr), asExtsNode(cloneExtr))\n\t\tupdateNodeIndexWithOptions[*descriptorpb.ExtensionRangeOptions](orig, clone, origExtr, cloneExtr)\n\t}\n\tfor i, origRr := range origProto.ReservedRange {\n\t\tcloneRr := cloneProto.ReservedRange[i]\n\t\tupdateNodeIndex(orig, clone, origRr, cloneRr)\n\t}\n\tfor i, origNmd := range origProto.NestedType {\n\t\tcloneNmd := cloneProto.NestedType[i]\n\t\trecreateNodeIndexForMessage(orig, clone, origNmd, cloneNmd)\n\t}\n\tfor i, origEd := range origProto.EnumType {\n\t\tcloneEd := cloneProto.EnumType[i]\n\t\trecreateNodeIndexForEnum(orig, clone, origEd, cloneEd)\n\t}\n\tfor i, origExtd := range origProto.Extension {\n\t\tcloneExtd := cloneProto.Extension[i]\n\t\tupdateNodeIndexWithOptions[*descriptorpb.FieldOptions](orig, clone, origExtd, cloneExtd)\n\t}\n}\n\nfunc recreateNodeIndexForEnum(orig, clone *result, origProto, cloneProto *descriptorpb.EnumDescriptorProto) {\n\tupdateNodeIndexWithOptions[*descriptorpb.EnumOptions](orig, clone, origProto, cloneProto)\n\tfor i, origEvd := range origProto.Value {\n\t\tcloneEvd := cloneProto.Value[i]\n\t\tupdateNodeIndexWithOptions[*descriptorpb.EnumValueOptions](orig, clone, origEvd, cloneEvd)\n\t}\n\tfor i, origRr := range origProto.ReservedRange {\n\t\tcloneRr := cloneProto.ReservedRange[i]\n\t\tupdateNodeIndex(orig, clone, origRr, cloneRr)\n\t}\n}\n\nfunc recreateNodeIndexForOptions(orig, clone *result, origProtos, cloneProtos []*descriptorpb.UninterpretedOption) {\n\tfor i, origOpt := range origProtos {\n\t\tcloneOpt := cloneProtos[i]\n\t\tupdateNodeIndex(orig, clone, origOpt, cloneOpt)\n\t\tfor j, origName := range origOpt.Name {\n\t\t\tcloneName := cloneOpt.Name[j]\n\t\t\tupdateNodeIndex(orig, clone, origName, cloneName)\n\t\t}\n\t}\n}\n\nfunc updateNodeIndex[M proto.Message](orig, clone *result, origProto, cloneProto M) {\n\tnode := orig.nodes[origProto]\n\tif node != nil {\n\t\tclone.nodes[cloneProto] = node\n\t}\n}\n\ntype pointerMessage[T any] interface {\n\t*T\n\tproto.Message\n}\n\ntype options[T any] interface {\n\t// need this type instead of just proto.Message so we can check for nil pointer\n\tpointerMessage[T]\n\tGetUninterpretedOption() []*descriptorpb.UninterpretedOption\n}\n\ntype withOptions[O options[T], T any] interface {\n\tproto.Message\n\tGetOptions() O\n}\n\nfunc updateNodeIndexWithOptions[O options[T], M withOptions[O, T], T any](orig, clone *result, origProto, cloneProto M) {\n\tupdateNodeIndex(orig, clone, origProto, cloneProto)\n\torigOpts := origProto.GetOptions()\n\tcloneOpts := cloneProto.GetOptions()\n\tif origOpts != nil {\n\t\trecreateNodeIndexForOptions(orig, clone, origOpts.GetUninterpretedOption(), cloneOpts.GetUninterpretedOption())\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/doc.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package parser contains the logic for parsing protobuf source code into an\n// AST (abstract syntax tree) and also for converting an AST into a descriptor\n// proto.\n//\n// A FileDescriptorProto is very similar to an AST, but the AST this package\n// uses is more useful because it contains more information about the source\n// code, including details about whitespace and comments, that cannot be\n// represented by a descriptor proto. This makes it ideal for things like\n// code formatters, which may want to preserve things like whitespace and\n// comment format.\npackage parser\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/errors.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport \"errors\"\n\n// ErrNoSyntax is a sentinel error that may be passed to a warning reporter.\n// The error the reporter receives will be wrapped with source position that\n// indicates the file that had no syntax statement.\nvar ErrNoSyntax = errors.New(\"no syntax specified; defaulting to proto2 syntax\")\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/lexer.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n)\n\ntype runeReader struct {\n\tdata []byte\n\tpos  int\n\terr  error\n\tmark int\n\t// Enable this check to make input required to be valid UTF-8.\n\t// For now, since protoc allows invalid UTF-8, default to false.\n\tutf8Strict bool\n}\n\nfunc (rr *runeReader) readRune() (r rune, size int, err error) {\n\tif rr.err != nil {\n\t\treturn 0, 0, rr.err\n\t}\n\tif rr.pos == len(rr.data) {\n\t\trr.err = io.EOF\n\t\treturn 0, 0, rr.err\n\t}\n\tr, sz := utf8.DecodeRune(rr.data[rr.pos:])\n\tif rr.utf8Strict && r == utf8.RuneError {\n\t\trr.err = fmt.Errorf(\"invalid UTF8 at offset %d: %x\", rr.pos, rr.data[rr.pos])\n\t\treturn 0, 0, rr.err\n\t}\n\trr.pos += sz\n\treturn r, sz, nil\n}\n\nfunc (rr *runeReader) offset() int {\n\treturn rr.pos\n}\n\nfunc (rr *runeReader) unreadRune(sz int) {\n\tnewPos := rr.pos - sz\n\tif newPos < rr.mark {\n\t\tpanic(\"unread past mark\")\n\t}\n\trr.pos = newPos\n}\n\nfunc (rr *runeReader) setMark() {\n\trr.mark = rr.pos\n}\n\nfunc (rr *runeReader) getMark() string {\n\treturn string(rr.data[rr.mark:rr.pos])\n}\n\ntype protoLex struct {\n\tinput   *runeReader\n\tinfo    *ast.FileInfo\n\thandler *reporter.Handler\n\tres     *ast.FileNode\n\n\tprevSym    ast.TerminalNode\n\tprevOffset int\n\teof        ast.Token\n\n\tcomments []ast.Token\n}\n\nvar utf8Bom = []byte{0xEF, 0xBB, 0xBF}\n\nfunc newLexer(in io.Reader, filename string, handler *reporter.Handler) (*protoLex, error) {\n\tbr := bufio.NewReader(in)\n\n\t// if file has UTF8 byte order marker preface, consume it\n\tmarker, err := br.Peek(3)\n\tif err == nil && bytes.Equal(marker, utf8Bom) {\n\t\t_, _ = br.Discard(3)\n\t}\n\n\tcontents, err := io.ReadAll(br)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &protoLex{\n\t\tinput:   &runeReader{data: contents},\n\t\tinfo:    ast.NewFileInfo(filename, contents),\n\t\thandler: handler,\n\t}, nil\n}\n\nvar keywords = map[string]int{\n\t\"syntax\":     _SYNTAX,\n\t\"edition\":    _EDITION,\n\t\"import\":     _IMPORT,\n\t\"weak\":       _WEAK,\n\t\"public\":     _PUBLIC,\n\t\"package\":    _PACKAGE,\n\t\"option\":     _OPTION,\n\t\"true\":       _TRUE,\n\t\"false\":      _FALSE,\n\t\"inf\":        _INF,\n\t\"nan\":        _NAN,\n\t\"repeated\":   _REPEATED,\n\t\"optional\":   _OPTIONAL,\n\t\"required\":   _REQUIRED,\n\t\"double\":     _DOUBLE,\n\t\"float\":      _FLOAT,\n\t\"int32\":      _INT32,\n\t\"int64\":      _INT64,\n\t\"uint32\":     _UINT32,\n\t\"uint64\":     _UINT64,\n\t\"sint32\":     _SINT32,\n\t\"sint64\":     _SINT64,\n\t\"fixed32\":    _FIXED32,\n\t\"fixed64\":    _FIXED64,\n\t\"sfixed32\":   _SFIXED32,\n\t\"sfixed64\":   _SFIXED64,\n\t\"bool\":       _BOOL,\n\t\"string\":     _STRING,\n\t\"bytes\":      _BYTES,\n\t\"group\":      _GROUP,\n\t\"oneof\":      _ONEOF,\n\t\"map\":        _MAP,\n\t\"extensions\": _EXTENSIONS,\n\t\"to\":         _TO,\n\t\"max\":        _MAX,\n\t\"reserved\":   _RESERVED,\n\t\"enum\":       _ENUM,\n\t\"message\":    _MESSAGE,\n\t\"extend\":     _EXTEND,\n\t\"service\":    _SERVICE,\n\t\"rpc\":        _RPC,\n\t\"stream\":     _STREAM,\n\t\"returns\":    _RETURNS,\n}\n\nfunc (l *protoLex) maybeNewLine(r rune) {\n\tif r == '\\n' {\n\t\tl.info.AddLine(l.input.offset())\n\t}\n}\n\nfunc (l *protoLex) prev() ast.SourcePos {\n\treturn l.info.SourcePos(l.prevOffset)\n}\n\nfunc (l *protoLex) Lex(lval *protoSymType) int {\n\tif l.handler.ReporterError() != nil {\n\t\t// if error reporter already returned non-nil error,\n\t\t// we can skip the rest of the input\n\t\treturn 0\n\t}\n\n\tl.comments = nil\n\n\tfor {\n\t\tl.input.setMark()\n\n\t\tl.prevOffset = l.input.offset()\n\t\tc, _, err := l.input.readRune()\n\t\tif err == io.EOF {\n\t\t\t// we're not actually returning a rune, but this will associate\n\t\t\t// accumulated comments as a trailing comment on last symbol\n\t\t\t// (if appropriate)\n\t\t\tl.setRune(lval, 0)\n\t\t\tl.eof = lval.b.Token()\n\t\t\treturn 0\n\t\t}\n\t\tif err != nil {\n\t\t\tl.setError(lval, err)\n\t\t\treturn _ERROR\n\t\t}\n\n\t\tif strings.ContainsRune(\"\\n\\r\\t\\f\\v \", c) {\n\t\t\t// skip whitespace\n\t\t\tl.maybeNewLine(c)\n\t\t\tcontinue\n\t\t}\n\n\t\tif c == '.' {\n\t\t\t// decimal literals could start with a dot\n\t\t\tcn, szn, err := l.input.readRune()\n\t\t\tif err != nil {\n\t\t\t\tl.setRune(lval, c)\n\t\t\t\treturn int(c)\n\t\t\t}\n\t\t\tif cn >= '0' && cn <= '9' {\n\t\t\t\tl.readNumber()\n\t\t\t\ttoken := l.input.getMark()\n\t\t\t\tf, err := parseFloat(token)\n\t\t\t\tif err != nil {\n\t\t\t\t\tl.setError(lval, numError(err, \"float\", token))\n\t\t\t\t\treturn _ERROR\n\t\t\t\t}\n\t\t\t\tl.setFloat(lval, f)\n\t\t\t\treturn _FLOAT_LIT\n\t\t\t}\n\t\t\tl.input.unreadRune(szn)\n\t\t\tl.setRune(lval, c)\n\t\t\treturn int(c)\n\t\t}\n\n\t\tif c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') {\n\t\t\t// identifier\n\t\t\tl.readIdentifier()\n\t\t\tstr := l.input.getMark()\n\t\t\tif t, ok := keywords[str]; ok {\n\t\t\t\tl.setIdent(lval, str)\n\t\t\t\treturn t\n\t\t\t}\n\t\t\tl.setIdent(lval, str)\n\t\t\treturn _NAME\n\t\t}\n\n\t\tif c >= '0' && c <= '9' {\n\t\t\t// integer or float literal\n\t\t\tl.readNumber()\n\t\t\ttoken := l.input.getMark()\n\t\t\tif strings.HasPrefix(token, \"0x\") || strings.HasPrefix(token, \"0X\") {\n\t\t\t\t// hexadecimal\n\t\t\t\tui, err := strconv.ParseUint(token[2:], 16, 64)\n\t\t\t\tif err != nil {\n\t\t\t\t\tl.setError(lval, numError(err, \"hexadecimal integer\", token[2:]))\n\t\t\t\t\treturn _ERROR\n\t\t\t\t}\n\t\t\t\tl.setInt(lval, ui)\n\t\t\t\treturn _INT_LIT\n\t\t\t}\n\t\t\tif strings.ContainsAny(token, \".eE\") {\n\t\t\t\t// floating point!\n\t\t\t\tf, err := parseFloat(token)\n\t\t\t\tif err != nil {\n\t\t\t\t\tl.setError(lval, numError(err, \"float\", token))\n\t\t\t\t\treturn _ERROR\n\t\t\t\t}\n\t\t\t\tl.setFloat(lval, f)\n\t\t\t\treturn _FLOAT_LIT\n\t\t\t}\n\t\t\t// integer! (decimal or octal)\n\t\t\tbase := 10\n\t\t\tif token[0] == '0' {\n\t\t\t\tbase = 8\n\t\t\t}\n\t\t\tui, err := strconv.ParseUint(token, base, 64)\n\t\t\tif err != nil {\n\t\t\t\tkind := \"integer\"\n\t\t\t\tif base == 8 {\n\t\t\t\t\tkind = \"octal integer\"\n\t\t\t\t} else if numErr, ok := err.(*strconv.NumError); ok && numErr.Err == strconv.ErrRange {\n\t\t\t\t\t// if it's too big to be an int, parse it as a float\n\t\t\t\t\tvar f float64\n\t\t\t\t\tkind = \"float\"\n\t\t\t\t\tf, err = parseFloat(token)\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tl.setFloat(lval, f)\n\t\t\t\t\t\treturn _FLOAT_LIT\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tl.setError(lval, numError(err, kind, token))\n\t\t\t\treturn _ERROR\n\t\t\t}\n\t\t\tl.setInt(lval, ui)\n\t\t\treturn _INT_LIT\n\t\t}\n\n\t\tif c == '\\'' || c == '\"' {\n\t\t\t// string literal\n\t\t\tstr, err := l.readStringLiteral(c)\n\t\t\tif err != nil {\n\t\t\t\tl.setError(lval, err)\n\t\t\t\treturn _ERROR\n\t\t\t}\n\t\t\tl.setString(lval, str)\n\t\t\treturn _STRING_LIT\n\t\t}\n\n\t\tif c == '/' {\n\t\t\t// comment\n\t\t\tcn, szn, err := l.input.readRune()\n\t\t\tif err != nil {\n\t\t\t\tl.setRune(lval, '/')\n\t\t\t\treturn int(c)\n\t\t\t}\n\t\t\tif cn == '/' {\n\t\t\t\tif hasErr := l.skipToEndOfLineComment(lval); hasErr {\n\t\t\t\t\treturn _ERROR\n\t\t\t\t}\n\t\t\t\tl.comments = append(l.comments, l.newToken())\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif cn == '*' {\n\t\t\t\tok, hasErr := l.skipToEndOfBlockComment(lval)\n\t\t\t\tif hasErr {\n\t\t\t\t\treturn _ERROR\n\t\t\t\t}\n\t\t\t\tif !ok {\n\t\t\t\t\tl.setError(lval, errors.New(\"block comment never terminates, unexpected EOF\"))\n\t\t\t\t\treturn _ERROR\n\t\t\t\t}\n\t\t\t\tl.comments = append(l.comments, l.newToken())\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tl.input.unreadRune(szn)\n\t\t}\n\n\t\tif c < 32 || c == 127 {\n\t\t\tl.setError(lval, errors.New(\"invalid control character\"))\n\t\t\treturn _ERROR\n\t\t}\n\t\tif !strings.ContainsRune(\";,.:=-+(){}[]<>/\", c) {\n\t\t\tl.setError(lval, errors.New(\"invalid character\"))\n\t\t\treturn _ERROR\n\t\t}\n\t\tl.setRune(lval, c)\n\t\treturn int(c)\n\t}\n}\n\nfunc parseFloat(token string) (float64, error) {\n\t// strconv.ParseFloat allows _ to separate digits, but protobuf does not\n\tif strings.ContainsRune(token, '_') {\n\t\treturn 0, &strconv.NumError{\n\t\t\tFunc: \"parseFloat\",\n\t\t\tNum:  token,\n\t\t\tErr:  strconv.ErrSyntax,\n\t\t}\n\t}\n\tf, err := strconv.ParseFloat(token, 64)\n\tif err == nil {\n\t\treturn f, nil\n\t}\n\tif numErr, ok := err.(*strconv.NumError); ok && numErr.Err == strconv.ErrRange && math.IsInf(f, 1) {\n\t\t// protoc doesn't complain about float overflow and instead just uses \"infinity\"\n\t\t// so we mirror that behavior by just returning infinity and ignoring the error\n\t\treturn f, nil\n\t}\n\treturn f, err\n}\n\nfunc (l *protoLex) newToken() ast.Token {\n\toffset := l.input.mark\n\tlength := l.input.pos - l.input.mark\n\treturn l.info.AddToken(offset, length)\n}\n\nfunc (l *protoLex) setPrevAndAddComments(n ast.TerminalNode) {\n\tcomments := l.comments\n\tl.comments = nil\n\tvar prevTrailingComments []ast.Token\n\tif l.prevSym != nil && len(comments) > 0 {\n\t\tprevEnd := l.info.NodeInfo(l.prevSym).End().Line\n\t\tinfo := l.info.NodeInfo(n)\n\t\tnStart := info.Start().Line\n\t\tif nStart == prevEnd {\n\t\t\tif rn, ok := n.(*ast.RuneNode); ok && rn.Rune == 0 {\n\t\t\t\t// if current token is EOF, pretend its on separate line\n\t\t\t\t// so that the logic below can attribute a final trailing\n\t\t\t\t// comment to the previous token\n\t\t\t\tnStart++\n\t\t\t}\n\t\t}\n\t\tc := comments[0]\n\t\tcommentInfo := l.info.TokenInfo(c)\n\t\tcommentStart := commentInfo.Start().Line\n\t\tif nStart > prevEnd && commentStart == prevEnd {\n\t\t\t// Comment starts right after the previous token. If it's a\n\t\t\t// line comment, we record that as a trailing comment.\n\t\t\t//\n\t\t\t// But if it's a block comment, it is only a trailing comment\n\t\t\t// if there are multiple comments or if the block comment ends\n\t\t\t// on a line before n.\n\t\t\tcanDonate := strings.HasPrefix(commentInfo.RawText(), \"//\") ||\n\t\t\t\tlen(comments) > 1 || commentInfo.End().Line < nStart\n\n\t\t\tif canDonate {\n\t\t\t\tprevTrailingComments = comments[:1]\n\t\t\t\tcomments = comments[1:]\n\t\t\t}\n\t\t}\n\t}\n\n\t// now we can associate comments\n\tfor _, c := range prevTrailingComments {\n\t\tl.info.AddComment(c, l.prevSym.Token())\n\t}\n\tfor _, c := range comments {\n\t\tl.info.AddComment(c, n.Token())\n\t}\n\n\tl.prevSym = n\n}\n\nfunc (l *protoLex) setString(lval *protoSymType, val string) {\n\tlval.s = ast.NewStringLiteralNode(val, l.newToken())\n\tl.setPrevAndAddComments(lval.s)\n}\n\nfunc (l *protoLex) setIdent(lval *protoSymType, val string) {\n\tlval.id = ast.NewIdentNode(val, l.newToken())\n\tl.setPrevAndAddComments(lval.id)\n}\n\nfunc (l *protoLex) setInt(lval *protoSymType, val uint64) {\n\tlval.i = ast.NewUintLiteralNode(val, l.newToken())\n\tl.setPrevAndAddComments(lval.i)\n}\n\nfunc (l *protoLex) setFloat(lval *protoSymType, val float64) {\n\tlval.f = ast.NewFloatLiteralNode(val, l.newToken())\n\tl.setPrevAndAddComments(lval.f)\n}\n\nfunc (l *protoLex) setRune(lval *protoSymType, val rune) {\n\tlval.b = ast.NewRuneNode(val, l.newToken())\n\tl.setPrevAndAddComments(lval.b)\n}\n\nfunc (l *protoLex) setError(lval *protoSymType, err error) {\n\tlval.err, _ = l.addSourceError(err)\n}\n\nfunc (l *protoLex) readNumber() {\n\tallowExpSign := false\n\tfor {\n\t\tc, sz, err := l.input.readRune()\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif (c == '-' || c == '+') && !allowExpSign {\n\t\t\tl.input.unreadRune(sz)\n\t\t\tbreak\n\t\t}\n\t\tallowExpSign = false\n\t\tif c != '.' && c != '_' && (c < '0' || c > '9') &&\n\t\t\t(c < 'a' || c > 'z') && (c < 'A' || c > 'Z') &&\n\t\t\tc != '-' && c != '+' {\n\t\t\t// no more chars in the number token\n\t\t\tl.input.unreadRune(sz)\n\t\t\tbreak\n\t\t}\n\t\tif c == 'e' || c == 'E' {\n\t\t\t// scientific notation char can be followed by\n\t\t\t// an exponent sign\n\t\t\tallowExpSign = true\n\t\t}\n\t}\n}\n\nfunc numError(err error, kind, s string) error {\n\tne, ok := err.(*strconv.NumError)\n\tif !ok {\n\t\treturn err\n\t}\n\tif ne.Err == strconv.ErrRange {\n\t\treturn fmt.Errorf(\"value out of range for %s: %s\", kind, s)\n\t}\n\t// syntax error\n\treturn fmt.Errorf(\"invalid syntax in %s value: %s\", kind, s)\n}\n\nfunc (l *protoLex) readIdentifier() {\n\tfor {\n\t\tc, sz, err := l.input.readRune()\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') {\n\t\t\tl.input.unreadRune(sz)\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (l *protoLex) readStringLiteral(quote rune) (string, error) {\n\tvar buf bytes.Buffer\n\tvar escapeError reporter.ErrorWithPos\n\tvar noMoreErrors bool\n\treportErr := func(msg, badEscape string) {\n\t\tif noMoreErrors {\n\t\t\treturn\n\t\t}\n\t\tif escapeError != nil {\n\t\t\t// report previous one\n\t\t\t_, ok := l.addSourceError(escapeError)\n\t\t\tif !ok {\n\t\t\t\tnoMoreErrors = true\n\t\t\t}\n\t\t}\n\t\tvar err error\n\t\tif strings.HasSuffix(msg, \"%s\") {\n\t\t\terr = fmt.Errorf(msg, badEscape)\n\t\t} else {\n\t\t\terr = errors.New(msg)\n\t\t}\n\t\t// we've now consumed the bad escape and lexer position is after it, so we need\n\t\t// to back up to the beginning of the escape to report the correct position\n\t\tescapeError = l.errWithCurrentPos(err, -len(badEscape))\n\t}\n\tfor {\n\t\tc, _, err := l.input.readRune()\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\terr = io.ErrUnexpectedEOF\n\t\t\t}\n\t\t\treturn \"\", err\n\t\t}\n\t\tif c == '\\n' {\n\t\t\treturn \"\", errors.New(\"encountered end-of-line before end of string literal\")\n\t\t}\n\t\tif c == quote {\n\t\t\tbreak\n\t\t}\n\t\tif c == 0 {\n\t\t\treportErr(\"null character ('\\\\0') not allowed in string literal\", string(rune(0)))\n\t\t\tcontinue\n\t\t}\n\t\tif c == '\\\\' {\n\t\t\t// escape sequence\n\t\t\tc, _, err = l.input.readRune()\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\tswitch {\n\t\t\tcase c == 'x' || c == 'X':\n\t\t\t\t// hex escape\n\t\t\t\tc1, sz1, err := l.input.readRune()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t\tif c1 == quote || c1 == '\\\\' {\n\t\t\t\t\tl.input.unreadRune(sz1)\n\t\t\t\t\treportErr(\"invalid hex escape: %s\", \"\\\\\"+string(c))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tc2, sz2, err := l.input.readRune()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t\tvar hex string\n\t\t\t\tif (c2 < '0' || c2 > '9') && (c2 < 'a' || c2 > 'f') && (c2 < 'A' || c2 > 'F') {\n\t\t\t\t\tl.input.unreadRune(sz2)\n\t\t\t\t\thex = string(c1)\n\t\t\t\t} else {\n\t\t\t\t\thex = string([]rune{c1, c2})\n\t\t\t\t}\n\t\t\t\ti, err := strconv.ParseInt(hex, 16, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treportErr(\"invalid hex escape: %s\", \"\\\\\"+string(c)+hex)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbuf.WriteByte(byte(i))\n\t\t\tcase c >= '0' && c <= '7':\n\t\t\t\t// octal escape\n\t\t\t\tc2, sz2, err := l.input.readRune()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn \"\", err\n\t\t\t\t}\n\t\t\t\tvar octal string\n\t\t\t\tif c2 < '0' || c2 > '7' {\n\t\t\t\t\tl.input.unreadRune(sz2)\n\t\t\t\t\toctal = string(c)\n\t\t\t\t} else {\n\t\t\t\t\tc3, sz3, err := l.input.readRune()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn \"\", err\n\t\t\t\t\t}\n\t\t\t\t\tif c3 < '0' || c3 > '7' {\n\t\t\t\t\t\tl.input.unreadRune(sz3)\n\t\t\t\t\t\toctal = string([]rune{c, c2})\n\t\t\t\t\t} else {\n\t\t\t\t\t\toctal = string([]rune{c, c2, c3})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti, err := strconv.ParseInt(octal, 8, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treportErr(\"invalid octal escape: %s\", \"\\\\\"+octal)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif i > 0xff {\n\t\t\t\t\treportErr(\"octal escape is out range, must be between 0 and 377: %s\", \"\\\\\"+octal)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbuf.WriteByte(byte(i))\n\t\t\tcase c == 'u':\n\t\t\t\t// short unicode escape\n\t\t\t\tu := make([]rune, 4)\n\t\t\t\tfor i := range u {\n\t\t\t\t\tc2, sz2, err := l.input.readRune()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn \"\", err\n\t\t\t\t\t}\n\t\t\t\t\tif c2 == quote || c2 == '\\\\' {\n\t\t\t\t\t\tl.input.unreadRune(sz2)\n\t\t\t\t\t\tu = u[:i]\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tu[i] = c2\n\t\t\t\t}\n\t\t\t\tcodepointStr := string(u)\n\t\t\t\tif len(u) < 4 {\n\t\t\t\t\treportErr(\"invalid unicode escape: %s\", \"\\\\u\"+codepointStr)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ti, err := strconv.ParseInt(codepointStr, 16, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treportErr(\"invalid unicode escape: %s\", \"\\\\u\"+codepointStr)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbuf.WriteRune(rune(i))\n\t\t\tcase c == 'U':\n\t\t\t\t// long unicode escape\n\t\t\t\tu := make([]rune, 8)\n\t\t\t\tfor i := range u {\n\t\t\t\t\tc2, sz2, err := l.input.readRune()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn \"\", err\n\t\t\t\t\t}\n\t\t\t\t\tif c2 == quote || c2 == '\\\\' {\n\t\t\t\t\t\tl.input.unreadRune(sz2)\n\t\t\t\t\t\tu = u[:i]\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tu[i] = c2\n\t\t\t\t}\n\t\t\t\tcodepointStr := string(u)\n\t\t\t\tif len(u) < 8 {\n\t\t\t\t\treportErr(\"invalid unicode escape: %s\", \"\\\\U\"+codepointStr)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\ti, err := strconv.ParseInt(string(u), 16, 32)\n\t\t\t\tif err != nil {\n\t\t\t\t\treportErr(\"invalid unicode escape: %s\", \"\\\\U\"+codepointStr)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif i > 0x10ffff || i < 0 {\n\t\t\t\t\treportErr(\"unicode escape is out of range, must be between 0 and 0x10ffff: %s\", \"\\\\U\"+codepointStr)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbuf.WriteRune(rune(i))\n\t\t\tcase c == 'a':\n\t\t\t\tbuf.WriteByte('\\a')\n\t\t\tcase c == 'b':\n\t\t\t\tbuf.WriteByte('\\b')\n\t\t\tcase c == 'f':\n\t\t\t\tbuf.WriteByte('\\f')\n\t\t\tcase c == 'n':\n\t\t\t\tbuf.WriteByte('\\n')\n\t\t\tcase c == 'r':\n\t\t\t\tbuf.WriteByte('\\r')\n\t\t\tcase c == 't':\n\t\t\t\tbuf.WriteByte('\\t')\n\t\t\tcase c == 'v':\n\t\t\t\tbuf.WriteByte('\\v')\n\t\t\tcase c == '\\\\':\n\t\t\t\tbuf.WriteByte('\\\\')\n\t\t\tcase c == '\\'':\n\t\t\t\tbuf.WriteByte('\\'')\n\t\t\tcase c == '\"':\n\t\t\t\tbuf.WriteByte('\"')\n\t\t\tcase c == '?':\n\t\t\t\tbuf.WriteByte('?')\n\t\t\tdefault:\n\t\t\t\treportErr(\"invalid escape sequence: %s\", \"\\\\\"+string(c))\n\t\t\t\tcontinue\n\t\t\t}\n\t\t} else {\n\t\t\tbuf.WriteRune(c)\n\t\t}\n\t}\n\tif escapeError != nil {\n\t\treturn \"\", escapeError\n\t}\n\treturn buf.String(), nil\n}\n\nfunc (l *protoLex) skipToEndOfLineComment(lval *protoSymType) (hasErr bool) {\n\tfor {\n\t\tc, sz, err := l.input.readRune()\n\t\tif err != nil {\n\t\t\t// eof\n\t\t\treturn false\n\t\t}\n\t\tswitch c {\n\t\tcase '\\n':\n\t\t\t// don't include newline in the comment\n\t\t\tl.input.unreadRune(sz)\n\t\t\treturn false\n\t\tcase 0:\n\t\t\tl.setError(lval, errors.New(\"invalid control character\"))\n\t\t\treturn true\n\t\t}\n\t}\n}\n\nfunc (l *protoLex) skipToEndOfBlockComment(lval *protoSymType) (ok, hasErr bool) {\n\tfor {\n\t\tc, _, err := l.input.readRune()\n\t\tif err != nil {\n\t\t\treturn false, false\n\t\t}\n\t\tif c == 0 {\n\t\t\tl.setError(lval, errors.New(\"invalid control character\"))\n\t\t\treturn false, true\n\t\t}\n\t\tl.maybeNewLine(c)\n\t\tif c == '*' {\n\t\t\tc, sz, err := l.input.readRune()\n\t\t\tif err != nil {\n\t\t\t\treturn false, false\n\t\t\t}\n\t\t\tif c == '/' {\n\t\t\t\treturn true, false\n\t\t\t}\n\t\t\tl.input.unreadRune(sz)\n\t\t}\n\t}\n}\n\nfunc (l *protoLex) addSourceError(err error) (reporter.ErrorWithPos, bool) {\n\tewp, ok := err.(reporter.ErrorWithPos)\n\tif !ok {\n\t\t// TODO: Store the previous span instead of just the position.\n\t\tewp = reporter.Error(ast.NewSourceSpan(l.prev(), l.prev()), err)\n\t}\n\thandlerErr := l.handler.HandleError(ewp)\n\treturn ewp, handlerErr == nil\n}\n\nfunc (l *protoLex) Error(s string) {\n\t_, _ = l.addSourceError(errors.New(s))\n}\n\n// TODO: Accept both a start and end offset, and use that to create a span.\nfunc (l *protoLex) errWithCurrentPos(err error, offset int) reporter.ErrorWithPos {\n\tif ewp, ok := err.(reporter.ErrorWithPos); ok {\n\t\treturn ewp\n\t}\n\tpos := l.info.SourcePos(l.input.offset() + offset)\n\treturn reporter.Error(ast.NewSourceSpan(pos, pos), err)\n}\n\nfunc (l *protoLex) requireSemicolon(semicolons []*ast.RuneNode) (*ast.RuneNode, []*ast.RuneNode) {\n\tif len(semicolons) == 0 {\n\t\tl.Error(\"syntax error: expecting ';'\")\n\t\treturn nil, nil\n\t}\n\treturn semicolons[0], semicolons[1:]\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/parser.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n)\n\n// The path ../.tmp/bin/goyacc is built when using `make generate` from repo root.\n//go:generate ../.tmp/bin/goyacc -o proto.y.go -l -p proto proto.y\n\nfunc init() {\n\tprotoErrorVerbose = true\n\n\t// fix up the generated \"token name\" array so that error messages are nicer\n\tsetTokenName(_STRING_LIT, \"string literal\")\n\tsetTokenName(_INT_LIT, \"int literal\")\n\tsetTokenName(_FLOAT_LIT, \"float literal\")\n\tsetTokenName(_NAME, \"identifier\")\n\tsetTokenName(_ERROR, \"error\")\n\t// for keywords, just show the keyword itself wrapped in quotes\n\tfor str, i := range keywords {\n\t\tsetTokenName(i, fmt.Sprintf(`\"%s\"`, str))\n\t}\n}\n\nfunc setTokenName(token int, text string) {\n\t// NB: this is based on logic in generated parse code that translates the\n\t// int returned from the lexer into an internal token number.\n\tvar intern int8\n\tif token < len(protoTok1) {\n\t\tintern = protoTok1[token]\n\t} else {\n\t\tif token >= protoPrivate {\n\t\t\tif token < protoPrivate+len(protoTok2) {\n\t\t\t\tintern = protoTok2[token-protoPrivate]\n\t\t\t}\n\t\t}\n\t\tif intern == 0 {\n\t\t\tfor i := 0; i+1 < len(protoTok3); i += 2 {\n\t\t\t\tif int(protoTok3[i]) == token {\n\t\t\t\t\tintern = protoTok3[i+1]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif intern >= 1 && int(intern-1) < len(protoToknames) {\n\t\tprotoToknames[intern-1] = text\n\t\treturn\n\t}\n\n\tpanic(fmt.Sprintf(\"Unknown token value: %d\", token))\n}\n\n// Parse parses the given source code info and returns an AST. The given filename\n// is used to construct error messages and position information. The given reader\n// supplies the source code. The given handler is used to report errors and\n// warnings encountered while parsing. If any errors are reported, this function\n// returns a non-nil error.\n//\n// If the error returned is due to a syntax error in the source, then a non-nil\n// AST is also returned. If the handler chooses to not abort the parse (e.g. the\n// underlying error reporter returns nil instead of an error), the parser will\n// attempt to recover and keep going. This allows multiple syntax errors to be\n// reported in a single pass. And it also means that more of the AST can be\n// populated (erroneous productions around the syntax error will of course be\n// absent).\n//\n// The degree to which the parser can recover from errors and populate the AST\n// depends on the nature of the syntax error and if there are any tokens after the\n// syntax error that can help the parser recover. This error recovery and partial\n// AST production is best effort.\nfunc Parse(filename string, r io.Reader, handler *reporter.Handler) (*ast.FileNode, error) {\n\tlx, err := newLexer(r, filename, handler)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tprotoParse(lx)\n\tif lx.res == nil {\n\t\t// nil AST means there was an error that prevented any parsing\n\t\t// or the file was empty; synthesize empty non-nil AST\n\t\tlx.res = ast.NewEmptyFileNode(filename)\n\t}\n\treturn lx.res, handler.Error()\n}\n\n// Result is the result of constructing a descriptor proto from a parsed AST.\n// From this result, the AST and the file descriptor proto can be had. This\n// also contains numerous lookup functions, for looking up AST nodes that\n// correspond to various elements of the descriptor hierarchy.\n//\n// Results can be created without AST information, using the ResultWithoutAST()\n// function. All functions other than AST() will still return non-nil values,\n// allowing compile operations to work with files that have only intermediate\n// descriptor protos and no source code. For such results, the function that\n// return AST nodes will return placeholder nodes. The position information for\n// placeholder nodes contains only the filename.\ntype Result interface {\n\t// AST returns the parsed abstract syntax tree. This returns nil if the\n\t// Result was created without an AST.\n\tAST() *ast.FileNode\n\t// FileDescriptorProto returns the file descriptor proto.\n\tFileDescriptorProto() *descriptorpb.FileDescriptorProto\n\n\t// FileNode returns the root of the AST. If this result has no AST then a\n\t// placeholder node is returned.\n\tFileNode() ast.FileDeclNode\n\t// Node returns the AST node from which the given message was created. This\n\t// can return nil, such as if the given message is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tNode(proto.Message) ast.Node\n\t// OptionNode returns the AST node corresponding to the given uninterpreted\n\t// option. This can return nil, such as if the given option is not part of\n\t// the FileDescriptorProto hierarchy. If this result has no AST, this\n\t// returns a placeholder node.\n\tOptionNode(*descriptorpb.UninterpretedOption) ast.OptionDeclNode\n\t// OptionNamePartNode returns the AST node corresponding to the given name\n\t// part for an uninterpreted option. This can return nil, such as if the\n\t// given name part is not part of the FileDescriptorProto hierarchy. If this\n\t// result has no AST, this returns a placeholder node.\n\tOptionNamePartNode(*descriptorpb.UninterpretedOption_NamePart) ast.Node\n\t// MessageNode returns the AST node corresponding to the given message. This\n\t// can return nil, such as if the given message is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tMessageNode(*descriptorpb.DescriptorProto) ast.MessageDeclNode\n\t// FieldNode returns the AST node corresponding to the given field. This can\n\t// return nil, such as if the given field is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tFieldNode(*descriptorpb.FieldDescriptorProto) ast.FieldDeclNode\n\t// OneofNode returns the AST node corresponding to the given oneof. This can\n\t// return nil, such as if the given oneof is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tOneofNode(*descriptorpb.OneofDescriptorProto) ast.OneofDeclNode\n\t// ExtensionRangeNode returns the AST node corresponding to the given\n\t// extension range. This can return nil, such as if the given range is not\n\t// part of the FileDescriptorProto hierarchy. If this result has no AST,\n\t// this returns a placeholder node.\n\tExtensionRangeNode(*descriptorpb.DescriptorProto_ExtensionRange) ast.RangeDeclNode\n\n\t// ExtensionsNode returns the AST node corresponding to the \"extensions\"\n\t// statement in a message that corresponds to the given range. This will be\n\t// the parent of the node returned by ExtensionRangeNode, which contains the\n\t// options that apply to all child ranges.\n\tExtensionsNode(*descriptorpb.DescriptorProto_ExtensionRange) ast.NodeWithOptions\n\n\t// MessageReservedRangeNode returns the AST node corresponding to the given\n\t// reserved range. This can return nil, such as if the given range is not\n\t// part of the FileDescriptorProto hierarchy. If this result has no AST,\n\t// this returns a placeholder node.\n\tMessageReservedRangeNode(*descriptorpb.DescriptorProto_ReservedRange) ast.RangeDeclNode\n\t// EnumNode returns the AST node corresponding to the given enum. This can\n\t// return nil, such as if the given enum is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tEnumNode(*descriptorpb.EnumDescriptorProto) ast.NodeWithOptions\n\t// EnumValueNode returns the AST node corresponding to the given enum. This\n\t// can return nil, such as if the given enum value is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tEnumValueNode(*descriptorpb.EnumValueDescriptorProto) ast.EnumValueDeclNode\n\t// EnumReservedRangeNode returns the AST node corresponding to the given\n\t// reserved range. This can return nil, such as if the given range is not\n\t// part of the FileDescriptorProto hierarchy. If this result has no AST,\n\t// this returns a placeholder node.\n\tEnumReservedRangeNode(*descriptorpb.EnumDescriptorProto_EnumReservedRange) ast.RangeDeclNode\n\t// ServiceNode returns the AST node corresponding to the given service. This\n\t// can return nil, such as if the given service is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tServiceNode(*descriptorpb.ServiceDescriptorProto) ast.NodeWithOptions\n\t// MethodNode returns the AST node corresponding to the given method. This\n\t// can return nil, such as if the given method is not part of the\n\t// FileDescriptorProto hierarchy. If this result has no AST, this returns a\n\t// placeholder node.\n\tMethodNode(*descriptorpb.MethodDescriptorProto) ast.RPCDeclNode\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/proto.y",
    "content": "%{\npackage parser\n\n//lint:file-ignore SA4006 generated parser has unused values\n\nimport (\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n)\n\n%}\n\n// fields inside this union end up as the fields in a structure known\n// as ${PREFIX}SymType, of which a reference is passed to the lexer.\n%union{\n\tfile         *ast.FileNode\n\tsyn          *ast.SyntaxNode\n\ted           *ast.EditionNode\n\tfileElements []ast.FileElement\n\tpkg          nodeWithRunes[*ast.PackageNode]\n\timprt        nodeWithRunes[*ast.ImportNode]\n\tmsg          nodeWithRunes[*ast.MessageNode]\n\tmsgElements  []ast.MessageElement\n\tfld          *ast.FieldNode\n\tmsgFld       nodeWithRunes[*ast.FieldNode]\n\tmapFld       nodeWithRunes[*ast.MapFieldNode]\n\tmapType      *ast.MapTypeNode\n\tgrp          *ast.GroupNode\n\tmsgGrp       nodeWithRunes[*ast.GroupNode]\n\too           nodeWithRunes[*ast.OneofNode]\n\tooElement    ast.OneofElement\n\tooElements   []ast.OneofElement\n\text          nodeWithRunes[*ast.ExtensionRangeNode]\n\tresvd        nodeWithRunes[*ast.ReservedNode]\n\ten           nodeWithRunes[*ast.EnumNode]\n\tenElements   []ast.EnumElement\n\tenv          nodeWithRunes[*ast.EnumValueNode]\n\textend       nodeWithRunes[*ast.ExtendNode]\n\textElement   ast.ExtendElement\n\textElements  []ast.ExtendElement\n\tsvc          nodeWithRunes[*ast.ServiceNode]\n\tsvcElements  []ast.ServiceElement\n\tmtd          nodeWithRunes[*ast.RPCNode]\n\tmtdMsgType   *ast.RPCTypeNode\n\tmtdElements  []ast.RPCElement\n\toptRaw       *ast.OptionNode\n\topt          nodeWithRunes[*ast.OptionNode]\n\topts         *compactOptionSlices\n\trefRaw       *ast.FieldReferenceNode\n\tref\t\t\t     nodeWithRunes[*ast.FieldReferenceNode]\n\toptNms       *fieldRefSlices\n\tcmpctOpts    *ast.CompactOptionsNode\n\trng          *ast.RangeNode\n\trngs         *rangeSlices\n\tnames        *nameSlices\n\tcidPart      nodeWithRunes[*ast.IdentNode]\n\tcid          *identSlices\n\ttid          ast.IdentValueNode\n\tsl           *valueSlices\n\tmsgLitFlds   *messageFieldList\n\tmsgLitFld    *ast.MessageFieldNode\n\tv            ast.ValueNode\n\til           ast.IntValueNode\n\tstr          []*ast.StringLiteralNode\n\ts            *ast.StringLiteralNode\n\ti            *ast.UintLiteralNode\n\tf            *ast.FloatLiteralNode\n\tid           *ast.IdentNode\n\tb            *ast.RuneNode\n\tbs           []*ast.RuneNode\n\terr          error\n}\n\n// any non-terminal which returns a value needs a type, which is\n// really a field name in the above union struct\n%type <file>         file\n%type <syn>          syntaxDecl\n%type <ed>           editionDecl\n%type <fileElements> fileBody fileElement fileElements\n%type <imprt>        importDecl\n%type <pkg>          packageDecl\n%type <optRaw>       compactOption oneofOptionDecl\n%type <opt>          optionDecl compactOptionEntry compactOptionFinal\n%type <opts>         compactOptionDecls compactOptionLeadingDecls\n%type <refRaw>       extensionName messageLiteralFieldName optionNamePart\n%type <ref>          optionNameEntry optionNameFinal\n%type <optNms>       optionName optionNameLeading\n%type <cmpctOpts>    compactOptions\n%type <v>            fieldValue optionValue scalarValue fieldScalarValue messageLiteralWithBraces messageLiteral numLit specialFloatLit listLiteral listElement listOfMessagesLiteral messageValue\n%type <il>           enumValueNumber\n%type <id>           identifier mapKeyType msgElementName extElementName oneofElementName notGroupElementName mtdElementName enumValueName fieldCardinality\n%type <cidPart>      qualifiedIdentifierEntry qualifiedIdentifierFinal mtdElementIdentEntry mtdElementIdentFinal\n%type <cid>          qualifiedIdentifier msgElementIdent extElementIdent oneofElementIdent notGroupElementIdent mtdElementIdent qualifiedIdentifierDot qualifiedIdentifierLeading mtdElementIdentLeading\n%type <tid>          typeName msgElementTypeIdent extElementTypeIdent oneofElementTypeIdent notGroupElementTypeIdent mtdElementTypeIdent\n%type <sl>           listElements messageLiterals\n%type <msgLitFlds>   messageLiteralFieldEntry messageLiteralFields messageTextFormat\n%type <msgLitFld>    messageLiteralField\n%type <msgFld>       messageFieldDecl\n%type <fld>          oneofFieldDecl extensionFieldDecl\n%type <oo>           oneofDecl\n%type <grp>          groupDecl oneofGroupDecl\n%type <msgGrp>       messageGroupDecl\n%type <mapFld>       mapFieldDecl\n%type <mapType>      mapType\n%type <msg>          messageDecl\n%type <msgElements>  messageElement messageElements messageBody\n%type <ooElement>    oneofElement\n%type <ooElements>   oneofElements oneofBody\n%type <names>        fieldNameStrings fieldNameIdents\n%type <resvd>        msgReserved enumReserved reservedNames\n%type <rng>          tagRange enumValueRange\n%type <rngs>         tagRanges enumValueRanges\n%type <ext>          extensionRangeDecl\n%type <en>           enumDecl\n%type <enElements>   enumElement enumElements enumBody\n%type <env>          enumValueDecl\n%type <extend>       extensionDecl\n%type <extElement>   extensionElement\n%type <extElements>  extensionElements extensionBody\n%type <str>          stringLit\n%type <svc>          serviceDecl\n%type <svcElements>  serviceElement serviceElements serviceBody\n%type <mtd>          methodDecl\n%type <mtdElements>  methodElement methodElements methodBody\n%type <mtdMsgType>   methodMessageType\n%type <b>            semicolon\n%type <bs>           semicolons semicolonList\n\n// same for terminals\n%token <s>   _STRING_LIT\n%token <i>   _INT_LIT\n%token <f>   _FLOAT_LIT\n%token <id>  _NAME\n%token <id>  _SYNTAX _EDITION _IMPORT _WEAK _PUBLIC _PACKAGE _OPTION _TRUE _FALSE _INF _NAN _REPEATED _OPTIONAL _REQUIRED\n%token <id>  _DOUBLE _FLOAT _INT32 _INT64 _UINT32 _UINT64 _SINT32 _SINT64 _FIXED32 _FIXED64 _SFIXED32 _SFIXED64\n%token <id>  _BOOL _STRING _BYTES _GROUP _ONEOF _MAP _EXTENSIONS _TO _MAX _RESERVED _ENUM _MESSAGE _EXTEND\n%token <id>  _SERVICE _RPC _STREAM _RETURNS\n%token <err> _ERROR\n// we define all of these, even ones that aren't used, to improve error messages\n// so it shows the unexpected symbol instead of showing \"$unk\"\n%token <b>   '=' ';' ':' '{' '}' '\\\\' '/' '?' '.' ',' '>' '<' '+' '-' '(' ')' '[' ']' '*' '&' '^' '%' '$' '#' '@' '!' '~' '`'\n\n%%\n\nfile : syntaxDecl {\n\t\tlex := protolex.(*protoLex)\n\t\t$$ = ast.NewFileNode(lex.info, $1, nil, lex.eof)\n\t\tlex.res = $$\n\t}\n\t| editionDecl {\n\t\tlex := protolex.(*protoLex)\n\t\t$$ = ast.NewFileNodeWithEdition(lex.info, $1, nil, lex.eof)\n\t\tlex.res = $$\n\t}\n\t| fileBody  {\n\t\tlex := protolex.(*protoLex)\n\t\t$$ = ast.NewFileNode(lex.info, nil, $1, lex.eof)\n\t\tlex.res = $$\n\t}\n\t| syntaxDecl fileBody {\n\t\tlex := protolex.(*protoLex)\n\t\t$$ = ast.NewFileNode(lex.info, $1, $2, lex.eof)\n\t\tlex.res = $$\n\t}\n\t| editionDecl fileBody {\n\t\tlex := protolex.(*protoLex)\n\t\t$$ = ast.NewFileNodeWithEdition(lex.info, $1, $2, lex.eof)\n\t\tlex.res = $$\n\t}\n\t| {\n\t\tlex := protolex.(*protoLex)\n\t\t$$ = ast.NewFileNode(lex.info, nil, nil, lex.eof)\n\t\tlex.res = $$\n\t}\n\nfileBody : semicolons fileElements {\n\t\t$$ = prependRunes(toFileElement, $1, $2)\n\t}\n\nfileElements : fileElements fileElement {\n\t\t$$ = append($1, $2...)\n\t}\n\t| fileElement {\n\t\t$$ = $1\n\t}\n\nfileElement : importDecl {\n\t  $$ = toElements[ast.FileElement](toFileElement, $1.Node, $1.Runes)\n\t}\n\t| packageDecl {\n\t  $$ = toElements[ast.FileElement](toFileElement, $1.Node, $1.Runes)\n\t}\n\t| optionDecl {\n\t  $$ = toElements[ast.FileElement](toFileElement, $1.Node, $1.Runes)\n\t}\n\t| messageDecl {\n\t  $$ = toElements[ast.FileElement](toFileElement, $1.Node, $1.Runes)\n\t}\n\t| enumDecl {\n\t  $$ = toElements[ast.FileElement](toFileElement, $1.Node, $1.Runes)\n\t}\n\t| extensionDecl {\n\t  $$ = toElements[ast.FileElement](toFileElement, $1.Node, $1.Runes)\n\t}\n\t| serviceDecl {\n\t  $$ = toElements[ast.FileElement](toFileElement, $1.Node, $1.Runes)\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\nsemicolonList : ';' {\n\t\t$$ = []*ast.RuneNode{$1}\n\t}\n\t| semicolonList ';' {\n\t\t$$ = append($1, $2)\n\t}\n\nsemicolons : semicolonList {\n\t\t$$ = $1\n\t}\n\t| {\n\t\t$$ = nil\n\t}\n\nsemicolon : ';' {\n\t\t$$ = $1\n\t} |\n\t{\n\t\tprotolex.(*protoLex).Error(\"syntax error: expecting ';'\")\n\t\t$$ = nil\n\t}\n\nsyntaxDecl : _SYNTAX '=' stringLit ';' {\n\t\t$$ = ast.NewSyntaxNode($1.ToKeyword(), $2, toStringValueNode($3), $4)\n\t}\n\neditionDecl : _EDITION '=' stringLit ';' {\n\t\t$$ = ast.NewEditionNode($1.ToKeyword(), $2, toStringValueNode($3), $4)\n\t}\n\nimportDecl : _IMPORT stringLit semicolons {\n\t  semi, extra := protolex.(*protoLex).requireSemicolon($3)\n\t\t$$ = newNodeWithRunes(ast.NewImportNode($1.ToKeyword(), nil, nil, toStringValueNode($2), semi), extra...)\n\t}\n\t| _IMPORT _WEAK stringLit semicolons {\n\t  semi, extra := protolex.(*protoLex).requireSemicolon($4)\n\t\t$$ = newNodeWithRunes(ast.NewImportNode($1.ToKeyword(), nil, $2.ToKeyword(), toStringValueNode($3), semi), extra...)\n\t}\n\t| _IMPORT _PUBLIC stringLit semicolons {\n\t  semi, extra := protolex.(*protoLex).requireSemicolon($4)\n\t\t$$ = newNodeWithRunes(ast.NewImportNode($1.ToKeyword(), $2.ToKeyword(), nil, toStringValueNode($3), semi), extra...)\n\t}\n\npackageDecl : _PACKAGE qualifiedIdentifier semicolons {\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($3)\n\t\t$$ = newNodeWithRunes(ast.NewPackageNode($1.ToKeyword(), $2.toIdentValueNode(nil), semi), extra...)\n\t}\n\nqualifiedIdentifier : identifier {\n\t\t$$ = &identSlices{idents: []*ast.IdentNode{$1}}\n\t}\n\t| qualifiedIdentifier '.' identifier {\n\t\t$1.idents = append($1.idents, $3)\n\t\t$1.dots = append($1.dots, $2)\n\t\t$$ = $1\n\t}\n\nqualifiedIdentifierDot : qualifiedIdentifierFinal {\n\t\t$$ = &identSlices{idents: []*ast.IdentNode{$1.Node}, dots: $1.Runes}\n\t}\n\t| qualifiedIdentifierLeading qualifiedIdentifierFinal {\n\t\t$1.idents = append($1.idents, $2.Node)\n\t\t$1.dots = append($1.dots, $2.Runes...)\n\t\t$$ = $1\n\t}\n\nqualifiedIdentifierLeading : qualifiedIdentifierEntry {\n\t  $$ = &identSlices{idents: []*ast.IdentNode{$1.Node}, dots: $1.Runes}\n\t}\n\t| qualifiedIdentifierLeading qualifiedIdentifierEntry {\n\t\t$1.idents = append($1.idents, $2.Node)\n\t\t$1.dots = append($1.dots, $2.Runes...)\n\t\t$$ = $1\n\t}\n\nqualifiedIdentifierFinal : identifier {\n\t\t$$ = newNodeWithRunes($1)\n\t}\n\t| qualifiedIdentifierEntry {\n\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected '.'\")\n\t\t$$ = $1\n\t}\n\nqualifiedIdentifierEntry : identifier '.' {\n\t\t$$ = newNodeWithRunes($1, $2)\n\t}\n\n// to mimic limitations of protoc recursive-descent parser,\n// we don't allowed message statement keywords as identifiers\n// (or oneof statement keywords [e.g. \"option\"] below)\n\nmsgElementIdent : msgElementName {\n\t\t$$ = &identSlices{idents: []*ast.IdentNode{$1}}\n\t}\n\t| msgElementIdent '.' identifier {\n\t\t$1.idents = append($1.idents, $3)\n\t\t$1.dots = append($1.dots, $2)\n\t\t$$ = $1\n\t}\n\nextElementIdent : extElementName {\n\t\t$$ = &identSlices{idents: []*ast.IdentNode{$1}}\n\t}\n\t| extElementIdent '.' identifier {\n\t\t$1.idents = append($1.idents, $3)\n\t\t$1.dots = append($1.dots, $2)\n\t\t$$ = $1\n\t}\n\noneofElementIdent : oneofElementName {\n\t\t$$ = &identSlices{idents: []*ast.IdentNode{$1}}\n\t}\n\t| oneofElementIdent '.' identifier {\n\t\t$1.idents = append($1.idents, $3)\n\t\t$1.dots = append($1.dots, $2)\n\t\t$$ = $1\n\t}\n\nnotGroupElementIdent : notGroupElementName {\n\t\t$$ = &identSlices{idents: []*ast.IdentNode{$1}}\n\t}\n\t| notGroupElementIdent '.' identifier {\n\t\t$1.idents = append($1.idents, $3)\n\t\t$1.dots = append($1.dots, $2)\n\t\t$$ = $1\n\t}\n\nmtdElementIdent : mtdElementIdentFinal {\n\t\t$$ = &identSlices{idents: []*ast.IdentNode{$1.Node}, dots: $1.Runes}\n\t}\n\t| mtdElementIdentLeading mtdElementIdentFinal {\n\t\t$1.idents = append($1.idents, $2.Node)\n\t\t$1.dots = append($1.dots, $2.Runes...)\n\t\t$$ = $1\n\t}\n\nmtdElementIdentLeading : mtdElementIdentEntry {\n\t  $$ = &identSlices{idents: []*ast.IdentNode{$1.Node}, dots: $1.Runes}\n\t}\n\t| mtdElementIdentLeading mtdElementIdentEntry {\n\t\t$1.idents = append($1.idents, $2.Node)\n\t\t$1.dots = append($1.dots, $2.Runes...)\n\t\t$$ = $1\n\t}\n\nmtdElementIdentFinal : mtdElementName {\n\t  $$ = newNodeWithRunes($1)\n  }\n  | mtdElementIdentEntry {\n\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected '.'\")\n\t\t$$ = $1\n\t}\n\nmtdElementIdentEntry : mtdElementName '.' {\n\t  $$ = newNodeWithRunes($1, $2)\n\t}\n\noneofOptionDecl : _OPTION optionName '=' optionValue semicolon {\n\t\toptName := ast.NewOptionNameNode($2.refs, $2.dots)\n\t\t$$ = ast.NewOptionNode($1.ToKeyword(), optName, $3, $4, $5)\n\t}\n\noptionDecl : _OPTION optionName '=' optionValue semicolons {\n\t\toptName := ast.NewOptionNameNode($2.refs, $2.dots)\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($5)\n\t\t$$ = newNodeWithRunes(ast.NewOptionNode($1.ToKeyword(), optName, $3, $4, semi), extra...)\n\t}\n\noptionNamePart : identifier {\n\t\t$$ = ast.NewFieldReferenceNode($1)\n\t}\n\t| extensionName {\n\t\t$$ = $1\n\t}\n\noptionNameEntry : optionNamePart '.' {\n\t\t$$ = newNodeWithRunes($1, $2)\n\t}\n\noptionNameFinal : optionNamePart {\n\t\t$$ = newNodeWithRunes($1)\n\t}\n\t| optionNameEntry {\n\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected '.'\")\n\t\t$$ = $1\n\t}\n\noptionNameLeading : optionNameEntry {\n\t  $$ = &fieldRefSlices{refs: []*ast.FieldReferenceNode{$1.Node}, dots: $1.Runes}\n  }\n\t| optionNameLeading optionNameEntry {\n\t\t$1.refs = append($1.refs, $2.Node)\n\t\t$1.dots = append($1.dots, $2.Runes...)\n\t\t$$ = $1\n\t}\n\noptionName : optionNameFinal {\n\t  $$ = &fieldRefSlices{refs: []*ast.FieldReferenceNode{$1.Node}, dots: $1.Runes}\n\t}\n\t| optionNameLeading optionNameFinal {\n\t\t$1.refs = append($1.refs, $2.Node)\n\t\t$1.dots = append($1.dots, $2.Runes...)\n\t\t$$ = $1\n\t}\n\nextensionName : '(' typeName ')' {\n\t\t$$ = ast.NewExtensionFieldReferenceNode($1, $2, $3)\n\t}\n\noptionValue : scalarValue\n\t| messageLiteralWithBraces\n\nscalarValue : stringLit {\n\t\t$$ = toStringValueNode($1)\n\t}\n\t| numLit\n\t| specialFloatLit\n\t| identifier {\n\t\t$$ = $1\n\t}\n\nnumLit : _FLOAT_LIT {\n\t\t$$ = $1\n\t}\n\t| '-' _FLOAT_LIT {\n\t\t$$ = ast.NewSignedFloatLiteralNode($1, $2)\n\t}\n\t| _INT_LIT {\n\t\t$$ = $1\n\t}\n\t| '-' _INT_LIT {\n\t\tif $2.Val > math.MaxInt64 + 1 {\n\t\t\t// can't represent as int so treat as float literal\n\t\t\t$$ = ast.NewSignedFloatLiteralNode($1, $2)\n\t\t} else {\n\t\t\t$$ = ast.NewNegativeIntLiteralNode($1, $2)\n\t\t}\n\t}\n\nspecialFloatLit : '-' _INF {\n\t\tf := ast.NewSpecialFloatLiteralNode($2.ToKeyword())\n\t\t$$ = ast.NewSignedFloatLiteralNode($1, f)\n\t}\n\t| '-' _NAN {\n\t\tf := ast.NewSpecialFloatLiteralNode($2.ToKeyword())\n\t\t$$ = ast.NewSignedFloatLiteralNode($1, f)\n\t}\n\nstringLit : _STRING_LIT {\n\t\t$$ = []*ast.StringLiteralNode{$1}\n\t}\n\t| stringLit _STRING_LIT {\n\t\t$$ = append($1, $2)\n\t}\n\nmessageLiteralWithBraces : '{' messageTextFormat '}' {\n\t\tif $2 == nil {\n\t\t\t$$ = ast.NewMessageLiteralNode($1, nil, nil, $3)\n\t\t} else {\n\t\t\tfields, delimiters := $2.toNodes()\n\t\t\t$$ = ast.NewMessageLiteralNode($1, fields, delimiters, $3)\n\t\t}\n\t}\n\t| '{' '}' {\n\t\t$$ = ast.NewMessageLiteralNode($1, nil, nil, $2)\n\t}\n\nmessageTextFormat : messageLiteralFields\n\nmessageLiteralFields : messageLiteralFieldEntry\n\t| messageLiteralFieldEntry messageLiteralFields {\n\t\tif $1 != nil {\n\t\t\t$1.next = $2\n\t\t\t$$ = $1\n\t\t} else {\n\t\t\t$$ = $2\n\t\t}\n\t}\n\nmessageLiteralFieldEntry : messageLiteralField {\n\t\tif $1 != nil {\n\t\t\t$$ = &messageFieldList{field: $1}\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n\t| messageLiteralField ',' {\n\t\tif $1 != nil {\n\t\t\t$$ = &messageFieldList{field: $1, delimiter: $2}\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n\t| messageLiteralField ';' {\n\t\tif $1 != nil {\n\t\t\t$$ = &messageFieldList{field: $1, delimiter: $2}\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n\t| error ',' {\n\t\t$$ = nil\n\t}\n\t| error ';' {\n\t\t$$ = nil\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\nmessageLiteralField : messageLiteralFieldName ':' fieldValue {\n\t\tif $1 != nil && $2 != nil {\n\t\t\t$$ = ast.NewMessageFieldNode($1, $2, $3)\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n\t| messageLiteralFieldName messageValue {\n\t\tif $1 != nil && $2 != nil {\n\t\t\t$$ = ast.NewMessageFieldNode($1, nil, $2)\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n\t| error ':' fieldValue {\n\t\t$$ = nil\n\t}\n\nmessageLiteralFieldName : identifier {\n\t\t$$ = ast.NewFieldReferenceNode($1)\n\t}\n\t| '[' qualifiedIdentifierDot ']' {\n\t\t$$ = ast.NewExtensionFieldReferenceNode($1, $2.toIdentValueNode(nil), $3)\n\t}\n\t| '[' qualifiedIdentifierDot '/' qualifiedIdentifierDot ']' {\n\t\t$$ = ast.NewAnyTypeReferenceNode($1, $2.toIdentValueNode(nil), $3, $4.toIdentValueNode(nil), $5)\n\t}\n\t| '[' error ']' {\n\t\t$$ = nil\n\t}\n\nfieldValue : fieldScalarValue\n\t| messageLiteral\n\t| listLiteral\n\nfieldScalarValue : stringLit {\n\t\t$$ = toStringValueNode($1)\n\t}\n\t| numLit\n\t| '-' identifier {\n\t\tkw := $2.ToKeyword()\n\t\tswitch strings.ToLower(kw.Val) {\n\t\tcase \"inf\", \"infinity\", \"nan\":\n\t\t\t// these are acceptable\n\t\tdefault:\n\t\t\t// anything else is not\n\t\t\tprotolex.(*protoLex).Error(`only identifiers \"inf\", \"infinity\", or \"nan\" may appear after negative sign`)\n\t\t}\n\t\t// we'll validate the identifier later\n\t\tf := ast.NewSpecialFloatLiteralNode(kw)\n\t\t$$ = ast.NewSignedFloatLiteralNode($1, f)\n\t}\n\t| identifier {\n\t\t$$ = $1\n\t}\n\nmessageValue : messageLiteral\n\t| listOfMessagesLiteral\n\nmessageLiteral : messageLiteralWithBraces\n\t| '<' messageTextFormat '>' {\n\t\tif $2 == nil {\n\t\t\t$$ = ast.NewMessageLiteralNode($1, nil, nil, $3)\n\t\t} else {\n\t\t\tfields, delimiters := $2.toNodes()\n\t\t\t$$ = ast.NewMessageLiteralNode($1, fields, delimiters, $3)\n\t\t}\n\t}\n\t| '<' '>' {\n\t\t$$ = ast.NewMessageLiteralNode($1, nil, nil, $2)\n\t}\n\nlistLiteral : '[' listElements ']' {\n\t\tif $2 == nil {\n\t\t\t$$ = ast.NewArrayLiteralNode($1, nil, nil, $3)\n\t\t} else {\n\t\t\t$$ = ast.NewArrayLiteralNode($1, $2.vals, $2.commas, $3)\n\t\t}\n\t}\n\t| '[' ']' {\n\t\t$$ = ast.NewArrayLiteralNode($1, nil, nil, $2)\n\t}\n\t| '[' error ']' {\n\t\t$$ = ast.NewArrayLiteralNode($1, nil, nil, $3)\n\t}\n\nlistElements : listElement {\n\t\t$$ = &valueSlices{vals: []ast.ValueNode{$1}}\n\t}\n\t| listElements ',' listElement {\n\t\t$1.vals = append($1.vals, $3)\n\t\t$1.commas = append($1.commas, $2)\n\t\t$$ = $1\n\t}\n\nlistElement : fieldScalarValue\n\t| messageLiteral\n\nlistOfMessagesLiteral : '[' messageLiterals ']' {\n\t\tif $2 == nil {\n\t\t\t$$ = ast.NewArrayLiteralNode($1, nil, nil, $3)\n\t\t} else {\n\t\t\t$$ = ast.NewArrayLiteralNode($1, $2.vals, $2.commas, $3)\n\t\t}\n\t}\n\t| '[' ']' {\n\t\t$$ = ast.NewArrayLiteralNode($1, nil, nil, $2)\n\t}\n\t| '[' error ']' {\n\t\t$$ = ast.NewArrayLiteralNode($1, nil, nil, $3)\n\t}\n\nmessageLiterals : messageLiteral {\n\t\t$$ = &valueSlices{vals: []ast.ValueNode{$1}}\n\t}\n\t| messageLiterals ',' messageLiteral {\n\t\t$1.vals = append($1.vals, $3)\n\t\t$1.commas = append($1.commas, $2)\n\t\t$$ = $1\n\t}\n\ntypeName : qualifiedIdentifierDot {\n\t\t$$ = $1.toIdentValueNode(nil)\n\t}\n\t| '.' qualifiedIdentifierDot {\n\t\t$$ = $2.toIdentValueNode($1)\n\t}\n\nmsgElementTypeIdent : msgElementIdent {\n\t\t$$ = $1.toIdentValueNode(nil)\n\t}\n\t| '.' qualifiedIdentifier {\n\t\t$$ = $2.toIdentValueNode($1)\n\t}\n\nextElementTypeIdent : extElementIdent {\n\t\t$$ = $1.toIdentValueNode(nil)\n\t}\n\t| '.' qualifiedIdentifier {\n\t\t$$ = $2.toIdentValueNode($1)\n\t}\n\noneofElementTypeIdent : oneofElementIdent {\n\t\t$$ = $1.toIdentValueNode(nil)\n\t}\n\t| '.' qualifiedIdentifier {\n\t\t$$ = $2.toIdentValueNode($1)\n\t}\n\nnotGroupElementTypeIdent : notGroupElementIdent {\n\t\t$$ = $1.toIdentValueNode(nil)\n\t}\n\t| '.' qualifiedIdentifier {\n\t\t$$ = $2.toIdentValueNode($1)\n\t}\n\nmtdElementTypeIdent : mtdElementIdent {\n\t\t$$ = $1.toIdentValueNode(nil)\n\t}\n\t| '.' qualifiedIdentifierDot {\n\t\t$$ = $2.toIdentValueNode($1)\n\t}\n\nfieldCardinality : _REQUIRED\n\t| _OPTIONAL\n\t| _REPEATED\n\ncompactOptions : '[' compactOptionDecls ']' {\n\t\t$$ = ast.NewCompactOptionsNode($1, $2.options, $2.commas, $3)\n\t}\n\t| '[' ']' {\n\t\tprotolex.(*protoLex).Error(\"compact options must have at least one option\")\n\t\t$$ = ast.NewCompactOptionsNode($1, nil, nil, $2)\n\t}\n\ncompactOptionDecls : compactOptionFinal {\n\t\t$$ = &compactOptionSlices{options: []*ast.OptionNode{$1.Node}, commas: $1.Runes}\n\t}\n\t| compactOptionLeadingDecls compactOptionFinal {\n\t\t$1.options = append($1.options, $2.Node)\n\t\t$1.commas = append($1.commas, $2.Runes...)\n\t\t$$ = $1\n\t}\n\ncompactOptionLeadingDecls : compactOptionEntry {\n\t  $$ = &compactOptionSlices{options: []*ast.OptionNode{$1.Node}, commas: $1.Runes}\n\t}\n\t| compactOptionLeadingDecls compactOptionEntry {\n\t\t$1.options = append($1.options, $2.Node)\n\t\t$1.commas = append($1.commas, $2.Runes...)\n\t\t$$ = $1\n\t}\n\ncompactOptionFinal : compactOption {\n\t\t$$ = newNodeWithRunes($1)\n\t}\n\t| compactOptionEntry {\n\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected ','\")\n\t\t$$ = $1\n\t}\n\ncompactOptionEntry : compactOption ',' {\n\t  $$ = newNodeWithRunes($1, $2)\n  }\n\ncompactOption : optionName '=' optionValue {\n\t\toptName := ast.NewOptionNameNode($1.refs, $1.dots)\n\t\t$$ = ast.NewCompactOptionNode(optName, $2, $3)\n\t}\n\t| optionName {\n\t\toptName := ast.NewOptionNameNode($1.refs, $1.dots)\n\t\tprotolex.(*protoLex).Error(\"compact option must have a value\")\n\t\t$$ = ast.NewCompactOptionNode(optName, nil, nil)\n\t}\n\n\ngroupDecl : fieldCardinality _GROUP identifier '=' _INT_LIT '{' messageBody '}' {\n\t\t$$ = ast.NewGroupNode($1.ToKeyword(), $2.ToKeyword(), $3, $4, $5, nil, $6, $7, $8)\n\t}\n\t| fieldCardinality _GROUP identifier '=' _INT_LIT compactOptions '{' messageBody '}' {\n\t\t$$ = ast.NewGroupNode($1.ToKeyword(), $2.ToKeyword(), $3, $4, $5, $6, $7, $8, $9)\n\t}\n\nmessageGroupDecl : fieldCardinality _GROUP identifier '=' _INT_LIT '{' messageBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewGroupNode($1.ToKeyword(), $2.ToKeyword(), $3, $4, $5, nil, $6, $7, $8), $9...)\n\t}\n\t| fieldCardinality _GROUP identifier '=' _INT_LIT compactOptions '{' messageBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewGroupNode($1.ToKeyword(), $2.ToKeyword(), $3, $4, $5, $6, $7, $8, $9), $10...)\n\t}\n\t| fieldCardinality _GROUP identifier '{' messageBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewGroupNode($1.ToKeyword(), $2.ToKeyword(), $3, nil, nil, nil, $4, $5, $6), $7...)\n\t}\n\t| fieldCardinality _GROUP identifier compactOptions '{' messageBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewGroupNode($1.ToKeyword(), $2.ToKeyword(), $3, nil, nil, $4, $5, $6, $7), $8...)\n\t}\n\noneofDecl : _ONEOF identifier '{' oneofBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewOneofNode($1.ToKeyword(), $2, $3, $4, $5), $6...)\n\t}\n\noneofBody : {\n\t\t$$ = nil\n\t}\n\t| oneofElements\n\noneofElements : oneofElements oneofElement {\n\t\tif $2 != nil {\n\t\t\t$$ = append($1, $2)\n\t\t} else {\n\t\t\t$$ = $1\n\t\t}\n\t}\n\t| oneofElement {\n\t\tif $1 != nil {\n\t\t\t$$ = []ast.OneofElement{$1}\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n\noneofElement : oneofOptionDecl {\n\t\t$$ = $1\n\t}\n\t| oneofFieldDecl {\n\t\t$$ = $1\n\t}\n\t| oneofGroupDecl {\n\t\t$$ = $1\n\t}\n\t| error ';' {\n\t\t$$ = nil\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\noneofFieldDecl : oneofElementTypeIdent identifier '=' _INT_LIT semicolon {\n\t\t$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, nil, $5)\n\t}\n\t| oneofElementTypeIdent identifier '=' _INT_LIT compactOptions semicolon {\n\t\t$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, $5, $6)\n\t}\n\t| oneofElementTypeIdent identifier semicolon {\n\t\t$$ = ast.NewFieldNode(nil, $1, $2, nil, nil, nil, $3)\n\t}\n\t| oneofElementTypeIdent identifier compactOptions semicolon {\n\t\t$$ = ast.NewFieldNode(nil, $1, $2, nil, nil, $3, $4)\n\t}\n\noneofGroupDecl : _GROUP identifier '=' _INT_LIT '{' messageBody '}' {\n\t\t$$ = ast.NewGroupNode(nil, $1.ToKeyword(), $2, $3, $4, nil, $5, $6, $7)\n\t}\n\t| _GROUP identifier '=' _INT_LIT compactOptions '{' messageBody '}' {\n\t\t$$ = ast.NewGroupNode(nil, $1.ToKeyword(), $2, $3, $4, $5, $6, $7, $8)\n\t}\n\t| _GROUP identifier '{' messageBody '}' {\n\t\t$$ = ast.NewGroupNode(nil, $1.ToKeyword(), $2, nil, nil, nil, $3, $4, $5)\n\t}\n\t| _GROUP identifier compactOptions '{' messageBody '}' {\n\t\t$$ = ast.NewGroupNode(nil, $1.ToKeyword(), $2, nil, nil, $3, $4, $5, $6)\n\t}\n\n\nmapFieldDecl : mapType identifier '=' _INT_LIT semicolons {\n\t  semi, extra := protolex.(*protoLex).requireSemicolon($5)\n\t\t$$ = newNodeWithRunes(ast.NewMapFieldNode($1, $2, $3, $4, nil, semi), extra...)\n\t}\n\t| mapType identifier '=' _INT_LIT compactOptions semicolons {\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($6)\n\t\t$$ = newNodeWithRunes(ast.NewMapFieldNode($1, $2, $3, $4, $5, semi), extra...)\n\t}\n\t| mapType identifier semicolons {\n\t  semi, extra := protolex.(*protoLex).requireSemicolon($3)\n\t\t$$ = newNodeWithRunes(ast.NewMapFieldNode($1, $2, nil, nil, nil, semi), extra...)\n\t}\n\t| mapType identifier compactOptions semicolons {\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($4)\n\t\t$$ = newNodeWithRunes(ast.NewMapFieldNode($1, $2, nil, nil, $3, semi), extra...)\n\t}\n\nmapType : _MAP '<' mapKeyType ',' typeName '>' {\n\t\t$$ = ast.NewMapTypeNode($1.ToKeyword(), $2, $3, $4, $5, $6)\n\t}\n\nmapKeyType : _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\nextensionRangeDecl : _EXTENSIONS tagRanges ';' semicolons {\n\t  // TODO: Tolerate a missing semicolon here. This currnelty creates a shift/reduce conflict\n\t\t// between `extensions 1 to 10` and `extensions 1` followed by `to = 10`.\n\t\t$$ = newNodeWithRunes(ast.NewExtensionRangeNode($1.ToKeyword(), $2.ranges, $2.commas, nil, $3), $4...)\n\t}\n\t| _EXTENSIONS tagRanges compactOptions semicolons {\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($4)\n\t\t$$ = newNodeWithRunes(ast.NewExtensionRangeNode($1.ToKeyword(), $2.ranges, $2.commas, $3, semi), extra...)\n\t}\n\ntagRanges : tagRange {\n\t\t$$ = &rangeSlices{ranges: []*ast.RangeNode{$1}}\n\t}\n\t| tagRanges ',' tagRange {\n\t\t$1.ranges = append($1.ranges, $3)\n\t\t$1.commas = append($1.commas, $2)\n\t\t$$ = $1\n\t}\n\ntagRange : _INT_LIT {\n\t\t$$ = ast.NewRangeNode($1, nil, nil, nil)\n\t}\n\t| _INT_LIT _TO _INT_LIT {\n\t\t$$ = ast.NewRangeNode($1, $2.ToKeyword(), $3, nil)\n\t}\n\t| _INT_LIT _TO _MAX {\n\t\t$$ = ast.NewRangeNode($1, $2.ToKeyword(), nil, $3.ToKeyword())\n\t}\n\nenumValueRanges : enumValueRange {\n\t\t$$ = &rangeSlices{ranges: []*ast.RangeNode{$1}}\n\t}\n\t| enumValueRanges ',' enumValueRange {\n\t\t$1.ranges = append($1.ranges, $3)\n\t\t$1.commas = append($1.commas, $2)\n\t\t$$ = $1\n\t}\n\nenumValueRange : enumValueNumber {\n\t\t$$ = ast.NewRangeNode($1, nil, nil, nil)\n\t}\n\t| enumValueNumber _TO enumValueNumber {\n\t\t$$ = ast.NewRangeNode($1, $2.ToKeyword(), $3, nil)\n\t}\n\t| enumValueNumber _TO _MAX {\n\t\t$$ = ast.NewRangeNode($1, $2.ToKeyword(), nil, $3.ToKeyword())\n\t}\n\nenumValueNumber : _INT_LIT {\n\t\t$$ = $1\n\t}\n\t| '-' _INT_LIT {\n\t\t$$ = ast.NewNegativeIntLiteralNode($1, $2)\n\t}\n\nmsgReserved : _RESERVED tagRanges ';' semicolons {\n\t  // TODO: Tolerate a missing semicolon here. This currnelty creates a shift/reduce conflict\n\t\t// between `reserved 1 to 10` and `reserved 1` followed by `to = 10`.\n\t\t$$ = newNodeWithRunes(ast.NewReservedRangesNode($1.ToKeyword(), $2.ranges, $2.commas, $3), $4...)\n\t}\n\t| reservedNames\n\nenumReserved : _RESERVED enumValueRanges ';' semicolons {\n\t  // TODO: Tolerate a missing semicolon here. This currnelty creates a shift/reduce conflict\n\t\t// between `reserved 1 to 10` and `reserved 1` followed by `to = 10`.\n\t\t$$ = newNodeWithRunes(ast.NewReservedRangesNode($1.ToKeyword(), $2.ranges, $2.commas, $3), $4...)\n\t}\n\t| reservedNames\n\nreservedNames : _RESERVED fieldNameStrings semicolons {\n\t  semi, extra := protolex.(*protoLex).requireSemicolon($3)\n\t\t$$ = newNodeWithRunes(ast.NewReservedNamesNode($1.ToKeyword(), $2.names, $2.commas, semi), extra...)\n\t}\n\t| _RESERVED fieldNameIdents semicolons {\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($3)\n\t\t$$ = newNodeWithRunes(ast.NewReservedIdentifiersNode($1.ToKeyword(), $2.idents, $2.commas, semi), extra...)\n\t}\n\nfieldNameStrings : stringLit {\n\t\t$$ = &nameSlices{names: []ast.StringValueNode{toStringValueNode($1)}}\n\t}\n\t| fieldNameStrings ',' stringLit {\n\t\t$1.names = append($1.names, toStringValueNode($3))\n\t\t$1.commas = append($1.commas, $2)\n\t\t$$ = $1\n\t}\n\nfieldNameIdents : identifier {\n\t\t$$ = &nameSlices{idents: []*ast.IdentNode{$1}}\n\t}\n\t| fieldNameIdents ',' identifier {\n\t\t$1.idents = append($1.idents, $3)\n\t\t$1.commas = append($1.commas, $2)\n\t\t$$ = $1\n\t}\n\nenumDecl : _ENUM identifier '{' enumBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewEnumNode($1.ToKeyword(), $2, $3, $4, $5), $6...)\n\t}\n\nenumBody : semicolons {\n\t\t$$ = prependRunes(toEnumElement, $1, nil)\n\t}\n\t| semicolons enumElements {\n\t\t$$ = prependRunes(toEnumElement, $1, $2)\n\t}\n\nenumElements : enumElements enumElement {\n\t\t$$ = append($1, $2...)\n\t}\n\t| enumElement {\n\t\t$$ = $1\n\t}\n\nenumElement : optionDecl {\n\t\t$$ = toElements[ast.EnumElement](toEnumElement, $1.Node, $1.Runes)\n\t}\n\t| enumValueDecl {\n\t\t$$ = toElements[ast.EnumElement](toEnumElement, $1.Node, $1.Runes)\n\t}\n\t| enumReserved {\n\t\t$$ = toElements[ast.EnumElement](toEnumElement, $1.Node, $1.Runes)\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\nenumValueDecl : enumValueName '=' enumValueNumber semicolons {\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($4)\n\t\t$$ = newNodeWithRunes(ast.NewEnumValueNode($1, $2, $3, nil, semi), extra...)\n\t}\n\t|  enumValueName '=' enumValueNumber compactOptions semicolons {\n\t\tsemi, extra := protolex.(*protoLex).requireSemicolon($5)\n\t\t$$ = newNodeWithRunes(ast.NewEnumValueNode($1, $2, $3, $4, semi), extra...)\n\t}\n\nmessageDecl : _MESSAGE identifier '{' messageBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewMessageNode($1.ToKeyword(), $2, $3, $4, $5), $6...)\n\t}\n\nmessageBody : semicolons {\n\t\t$$ = prependRunes(toMessageElement, $1, nil)\n\t}\n\t| semicolons messageElements {\n\t\t$$ = prependRunes(toMessageElement, $1, $2)\n\t}\n\nmessageElements : messageElements messageElement {\n\t\t$$ = append($1, $2...)\n\t}\n\t| messageElement {\n\t\t$$ = $1\n\t}\n\nmessageElement : messageFieldDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| enumDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| messageDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| extensionDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| extensionRangeDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| messageGroupDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| optionDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| oneofDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| mapFieldDecl {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| msgReserved {\n\t\t$$ = toElements[ast.MessageElement](toMessageElement, $1.Node, $1.Runes)\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\nmessageFieldDecl : fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($6)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode($1.ToKeyword(), $2, $3, $4, $5, nil, semis), extra...)\n\t}\n\t| fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT compactOptions semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($7)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode($1.ToKeyword(), $2, $3, $4, $5, $6, semis), extra...)\n\t}\n\t| msgElementTypeIdent identifier '=' _INT_LIT semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($5)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode(nil, $1, $2, $3, $4, nil, semis), extra...)\n\t}\n\t| msgElementTypeIdent identifier '=' _INT_LIT compactOptions semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($6)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode(nil, $1, $2, $3, $4, $5, semis), extra...)\n\t}\n\t| fieldCardinality notGroupElementTypeIdent identifier semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($4)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode($1.ToKeyword(), $2, $3, nil, nil, nil, semis), extra...)\n\t}\n\t| fieldCardinality notGroupElementTypeIdent identifier compactOptions semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($5)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode($1.ToKeyword(), $2, $3, nil, nil, $4, semis), extra...)\n\t}\n\t| msgElementTypeIdent identifier semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($3)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode(nil, $1, $2, nil, nil, nil, semis), extra...)\n\t}\n\t| msgElementTypeIdent identifier compactOptions semicolons {\n\t\tsemis, extra := protolex.(*protoLex).requireSemicolon($4)\n\t\t$$ = newNodeWithRunes(ast.NewFieldNode(nil, $1, $2, nil, nil, $3, semis), extra...)\n\t}\n\n\nextensionDecl : _EXTEND typeName '{' extensionBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewExtendNode($1.ToKeyword(), $2, $3, $4, $5), $6...)\n\t}\n\nextensionBody : {\n\t\t$$ = nil\n\t}\n\t| extensionElements\n\nextensionElements : extensionElements extensionElement {\n\t\tif $2 != nil {\n\t\t\t$$ = append($1, $2)\n\t\t} else {\n\t\t\t$$ = $1\n\t\t}\n\t}\n\t| extensionElement {\n\t\tif $1 != nil {\n\t\t\t$$ = []ast.ExtendElement{$1}\n\t\t} else {\n\t\t\t$$ = nil\n\t\t}\n\t}\n\nextensionElement : extensionFieldDecl {\n\t\t$$ = $1\n\t}\n\t| groupDecl {\n\t\t$$ = $1\n\t}\n\t| error ';' {\n\t\t$$ = nil\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\nextensionFieldDecl : fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT semicolon {\n\t\t$$ = ast.NewFieldNode($1.ToKeyword(), $2, $3, $4, $5, nil, $6)\n\t}\n\t| fieldCardinality notGroupElementTypeIdent identifier '=' _INT_LIT compactOptions semicolon {\n\t\t$$ = ast.NewFieldNode($1.ToKeyword(), $2, $3, $4, $5, $6, $7)\n\t}\n\t| extElementTypeIdent identifier '=' _INT_LIT semicolon {\n\t\t$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, nil, $5)\n\t}\n\t| extElementTypeIdent identifier '=' _INT_LIT compactOptions semicolon {\n\t\t$$ = ast.NewFieldNode(nil, $1, $2, $3, $4, $5, $6)\n\t}\n\nserviceDecl : _SERVICE identifier '{' serviceBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewServiceNode($1.ToKeyword(), $2, $3, $4, $5), $6...)\n\t}\n\nserviceBody : semicolons {\n\t  $$ = prependRunes(toServiceElement, $1, nil)\n\t}\n\t| semicolons serviceElements {\n\t\t$$ = prependRunes(toServiceElement, $1, $2)\n\t}\n\nserviceElements : serviceElements serviceElement {\n\t\t$$ = append($1, $2...)\n\t}\n\t| serviceElement {\n\t\t$$ = $1\n\t}\n\n// NB: doc suggests support for \"stream\" declaration, separate from \"rpc\", but\n// it does not appear to be supported in protoc (doc is likely from grammar for\n// Google-internal version of protoc, with support for streaming stubby)\nserviceElement : optionDecl {\n\t\t$$ = toElements[ast.ServiceElement](toServiceElement, $1.Node, $1.Runes)\n\t}\n\t| methodDecl {\n\t\t$$ = toElements[ast.ServiceElement](toServiceElement, $1.Node, $1.Runes)\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\nmethodDecl : _RPC identifier methodMessageType _RETURNS methodMessageType semicolons {\n\t  semi, extra := protolex.(*protoLex).requireSemicolon($6)\n\t\t$$ = newNodeWithRunes(ast.NewRPCNode($1.ToKeyword(), $2, $3, $4.ToKeyword(), $5, semi), extra...)\n\t}\n\t| _RPC identifier methodMessageType _RETURNS methodMessageType '{' methodBody '}' semicolons {\n\t\t$$ = newNodeWithRunes(ast.NewRPCNodeWithBody($1.ToKeyword(), $2, $3, $4.ToKeyword(), $5, $6, $7, $8), $9...)\n\t}\n\nmethodMessageType : '(' _STREAM typeName ')' {\n\t\t$$ = ast.NewRPCTypeNode($1, $2.ToKeyword(), $3, $4)\n\t}\n\t| '(' mtdElementTypeIdent ')' {\n\t\t$$ = ast.NewRPCTypeNode($1, nil, $2, $3)\n\t}\n\nmethodBody : semicolons {\n\t\t$$ = prependRunes(toMethodElement, $1, nil)\n\t}\n\t| semicolons methodElements {\n\t\t$$ = prependRunes(toMethodElement, $1, $2)\n\t}\n\nmethodElements : methodElements methodElement {\n\t\t$$ = append($1, $2...)\n\t}\n\t| methodElement {\n\t\t$$ = $1\n\t}\n\nmethodElement : optionDecl {\n\t\t$$ = toElements[ast.RPCElement](toMethodElement, $1.Node, $1.Runes)\n\t}\n\t| error {\n\t\t$$ = nil\n\t}\n\n// excludes message, enum, oneof, extensions, reserved, extend,\n//   option, group, optional, required, and repeated\nmsgElementName : _NAME\n\t| _SYNTAX\n\t| _EDITION\n\t| _IMPORT\n\t| _WEAK\n\t| _PUBLIC\n\t| _PACKAGE\n\t| _TRUE\n\t| _FALSE\n\t| _INF\n\t| _NAN\n\t| _DOUBLE\n\t| _FLOAT\n\t| _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\t| _BYTES\n\t| _MAP\n\t| _TO\n\t| _MAX\n\t| _SERVICE\n\t| _RPC\n\t| _STREAM\n\t| _RETURNS\n\n// excludes group, optional, required, and repeated\nextElementName : _NAME\n\t| _SYNTAX\n\t| _EDITION\n\t| _IMPORT\n\t| _WEAK\n\t| _PUBLIC\n\t| _PACKAGE\n\t| _OPTION\n\t| _TRUE\n\t| _FALSE\n\t| _INF\n\t| _NAN\n\t| _DOUBLE\n\t| _FLOAT\n\t| _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\t| _BYTES\n\t| _ONEOF\n\t| _MAP\n\t| _EXTENSIONS\n\t| _TO\n\t| _MAX\n\t| _RESERVED\n\t| _ENUM\n\t| _MESSAGE\n\t| _EXTEND\n\t| _SERVICE\n\t| _RPC\n\t| _STREAM\n\t| _RETURNS\n\n// excludes reserved, option\nenumValueName : _NAME\n\t| _SYNTAX\n\t| _EDITION\n\t| _IMPORT\n\t| _WEAK\n\t| _PUBLIC\n\t| _PACKAGE\n\t| _TRUE\n\t| _FALSE\n\t| _INF\n\t| _NAN\n\t| _REPEATED\n\t| _OPTIONAL\n\t| _REQUIRED\n\t| _DOUBLE\n\t| _FLOAT\n\t| _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\t| _BYTES\n\t| _GROUP\n\t| _ONEOF\n\t| _MAP\n\t| _EXTENSIONS\n\t| _TO\n\t| _MAX\n\t| _ENUM\n\t| _MESSAGE\n\t| _EXTEND\n\t| _SERVICE\n\t| _RPC\n\t| _STREAM\n\t| _RETURNS\n\n// excludes group, option, optional, required, and repeated\noneofElementName : _NAME\n\t| _SYNTAX\n\t| _EDITION\n\t| _IMPORT\n\t| _WEAK\n\t| _PUBLIC\n\t| _PACKAGE\n\t| _TRUE\n\t| _FALSE\n\t| _INF\n\t| _NAN\n\t| _DOUBLE\n\t| _FLOAT\n\t| _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\t| _BYTES\n\t| _ONEOF\n\t| _MAP\n\t| _EXTENSIONS\n\t| _TO\n\t| _MAX\n\t| _RESERVED\n\t| _ENUM\n\t| _MESSAGE\n\t| _EXTEND\n\t| _SERVICE\n\t| _RPC\n\t| _STREAM\n\t| _RETURNS\n\n// excludes group\nnotGroupElementName : _NAME\n\t| _SYNTAX\n\t| _EDITION\n\t| _IMPORT\n\t| _WEAK\n\t| _PUBLIC\n\t| _PACKAGE\n\t| _OPTION\n\t| _TRUE\n\t| _FALSE\n\t| _INF\n\t| _NAN\n\t| _REPEATED\n\t| _OPTIONAL\n\t| _REQUIRED\n\t| _DOUBLE\n\t| _FLOAT\n\t| _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\t| _BYTES\n\t| _ONEOF\n\t| _MAP\n\t| _EXTENSIONS\n\t| _TO\n\t| _MAX\n\t| _RESERVED\n\t| _ENUM\n\t| _MESSAGE\n\t| _EXTEND\n\t| _SERVICE\n\t| _RPC\n\t| _STREAM\n\t| _RETURNS\n\n// excludes stream\nmtdElementName : _NAME\n\t| _SYNTAX\n\t| _EDITION\n\t| _IMPORT\n\t| _WEAK\n\t| _PUBLIC\n\t| _PACKAGE\n\t| _OPTION\n\t| _TRUE\n\t| _FALSE\n\t| _INF\n\t| _NAN\n\t| _REPEATED\n\t| _OPTIONAL\n\t| _REQUIRED\n\t| _DOUBLE\n\t| _FLOAT\n\t| _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\t| _BYTES\n\t| _GROUP\n\t| _ONEOF\n\t| _MAP\n\t| _EXTENSIONS\n\t| _TO\n\t| _MAX\n\t| _RESERVED\n\t| _ENUM\n\t| _MESSAGE\n\t| _EXTEND\n\t| _SERVICE\n\t| _RPC\n\t| _RETURNS\n\nidentifier : _NAME\n\t| _SYNTAX\n\t| _EDITION\n\t| _IMPORT\n\t| _WEAK\n\t| _PUBLIC\n\t| _PACKAGE\n\t| _OPTION\n\t| _TRUE\n\t| _FALSE\n\t| _INF\n\t| _NAN\n\t| _REPEATED\n\t| _OPTIONAL\n\t| _REQUIRED\n\t| _DOUBLE\n\t| _FLOAT\n\t| _INT32\n\t| _INT64\n\t| _UINT32\n\t| _UINT64\n\t| _SINT32\n\t| _SINT64\n\t| _FIXED32\n\t| _FIXED64\n\t| _SFIXED32\n\t| _SFIXED64\n\t| _BOOL\n\t| _STRING\n\t| _BYTES\n\t| _GROUP\n\t| _ONEOF\n\t| _MAP\n\t| _EXTENSIONS\n\t| _TO\n\t| _MAX\n\t| _RESERVED\n\t| _ENUM\n\t| _MESSAGE\n\t| _EXTEND\n\t| _SERVICE\n\t| _RPC\n\t| _STREAM\n\t| _RETURNS\n\n%%\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/proto.y.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Code generated by goyacc -o proto.y.go -l -p proto proto.y. DO NOT EDIT.\npackage parser\n\nimport __yyfmt__ \"fmt\"\n\n//lint:file-ignore SA4006 generated parser has unused values\n\nimport (\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n)\n\ntype protoSymType struct {\n\tyys          int\n\tfile         *ast.FileNode\n\tsyn          *ast.SyntaxNode\n\ted           *ast.EditionNode\n\tfileElements []ast.FileElement\n\tpkg          nodeWithRunes[*ast.PackageNode]\n\timprt        nodeWithRunes[*ast.ImportNode]\n\tmsg          nodeWithRunes[*ast.MessageNode]\n\tmsgElements  []ast.MessageElement\n\tfld          *ast.FieldNode\n\tmsgFld       nodeWithRunes[*ast.FieldNode]\n\tmapFld       nodeWithRunes[*ast.MapFieldNode]\n\tmapType      *ast.MapTypeNode\n\tgrp          *ast.GroupNode\n\tmsgGrp       nodeWithRunes[*ast.GroupNode]\n\too           nodeWithRunes[*ast.OneofNode]\n\tooElement    ast.OneofElement\n\tooElements   []ast.OneofElement\n\text          nodeWithRunes[*ast.ExtensionRangeNode]\n\tresvd        nodeWithRunes[*ast.ReservedNode]\n\ten           nodeWithRunes[*ast.EnumNode]\n\tenElements   []ast.EnumElement\n\tenv          nodeWithRunes[*ast.EnumValueNode]\n\textend       nodeWithRunes[*ast.ExtendNode]\n\textElement   ast.ExtendElement\n\textElements  []ast.ExtendElement\n\tsvc          nodeWithRunes[*ast.ServiceNode]\n\tsvcElements  []ast.ServiceElement\n\tmtd          nodeWithRunes[*ast.RPCNode]\n\tmtdMsgType   *ast.RPCTypeNode\n\tmtdElements  []ast.RPCElement\n\toptRaw       *ast.OptionNode\n\topt          nodeWithRunes[*ast.OptionNode]\n\topts         *compactOptionSlices\n\trefRaw       *ast.FieldReferenceNode\n\tref          nodeWithRunes[*ast.FieldReferenceNode]\n\toptNms       *fieldRefSlices\n\tcmpctOpts    *ast.CompactOptionsNode\n\trng          *ast.RangeNode\n\trngs         *rangeSlices\n\tnames        *nameSlices\n\tcidPart      nodeWithRunes[*ast.IdentNode]\n\tcid          *identSlices\n\ttid          ast.IdentValueNode\n\tsl           *valueSlices\n\tmsgLitFlds   *messageFieldList\n\tmsgLitFld    *ast.MessageFieldNode\n\tv            ast.ValueNode\n\til           ast.IntValueNode\n\tstr          []*ast.StringLiteralNode\n\ts            *ast.StringLiteralNode\n\ti            *ast.UintLiteralNode\n\tf            *ast.FloatLiteralNode\n\tid           *ast.IdentNode\n\tb            *ast.RuneNode\n\tbs           []*ast.RuneNode\n\terr          error\n}\n\nconst _STRING_LIT = 57346\nconst _INT_LIT = 57347\nconst _FLOAT_LIT = 57348\nconst _NAME = 57349\nconst _SYNTAX = 57350\nconst _EDITION = 57351\nconst _IMPORT = 57352\nconst _WEAK = 57353\nconst _PUBLIC = 57354\nconst _PACKAGE = 57355\nconst _OPTION = 57356\nconst _TRUE = 57357\nconst _FALSE = 57358\nconst _INF = 57359\nconst _NAN = 57360\nconst _REPEATED = 57361\nconst _OPTIONAL = 57362\nconst _REQUIRED = 57363\nconst _DOUBLE = 57364\nconst _FLOAT = 57365\nconst _INT32 = 57366\nconst _INT64 = 57367\nconst _UINT32 = 57368\nconst _UINT64 = 57369\nconst _SINT32 = 57370\nconst _SINT64 = 57371\nconst _FIXED32 = 57372\nconst _FIXED64 = 57373\nconst _SFIXED32 = 57374\nconst _SFIXED64 = 57375\nconst _BOOL = 57376\nconst _STRING = 57377\nconst _BYTES = 57378\nconst _GROUP = 57379\nconst _ONEOF = 57380\nconst _MAP = 57381\nconst _EXTENSIONS = 57382\nconst _TO = 57383\nconst _MAX = 57384\nconst _RESERVED = 57385\nconst _ENUM = 57386\nconst _MESSAGE = 57387\nconst _EXTEND = 57388\nconst _SERVICE = 57389\nconst _RPC = 57390\nconst _STREAM = 57391\nconst _RETURNS = 57392\nconst _ERROR = 57393\n\nvar protoToknames = [...]string{\n\t\"$end\",\n\t\"error\",\n\t\"$unk\",\n\t\"_STRING_LIT\",\n\t\"_INT_LIT\",\n\t\"_FLOAT_LIT\",\n\t\"_NAME\",\n\t\"_SYNTAX\",\n\t\"_EDITION\",\n\t\"_IMPORT\",\n\t\"_WEAK\",\n\t\"_PUBLIC\",\n\t\"_PACKAGE\",\n\t\"_OPTION\",\n\t\"_TRUE\",\n\t\"_FALSE\",\n\t\"_INF\",\n\t\"_NAN\",\n\t\"_REPEATED\",\n\t\"_OPTIONAL\",\n\t\"_REQUIRED\",\n\t\"_DOUBLE\",\n\t\"_FLOAT\",\n\t\"_INT32\",\n\t\"_INT64\",\n\t\"_UINT32\",\n\t\"_UINT64\",\n\t\"_SINT32\",\n\t\"_SINT64\",\n\t\"_FIXED32\",\n\t\"_FIXED64\",\n\t\"_SFIXED32\",\n\t\"_SFIXED64\",\n\t\"_BOOL\",\n\t\"_STRING\",\n\t\"_BYTES\",\n\t\"_GROUP\",\n\t\"_ONEOF\",\n\t\"_MAP\",\n\t\"_EXTENSIONS\",\n\t\"_TO\",\n\t\"_MAX\",\n\t\"_RESERVED\",\n\t\"_ENUM\",\n\t\"_MESSAGE\",\n\t\"_EXTEND\",\n\t\"_SERVICE\",\n\t\"_RPC\",\n\t\"_STREAM\",\n\t\"_RETURNS\",\n\t\"_ERROR\",\n\t\"'='\",\n\t\"';'\",\n\t\"':'\",\n\t\"'{'\",\n\t\"'}'\",\n\t\"'\\\\\\\\'\",\n\t\"'/'\",\n\t\"'?'\",\n\t\"'.'\",\n\t\"','\",\n\t\"'>'\",\n\t\"'<'\",\n\t\"'+'\",\n\t\"'-'\",\n\t\"'('\",\n\t\"')'\",\n\t\"'['\",\n\t\"']'\",\n\t\"'*'\",\n\t\"'&'\",\n\t\"'^'\",\n\t\"'%'\",\n\t\"'$'\",\n\t\"'#'\",\n\t\"'@'\",\n\t\"'!'\",\n\t\"'~'\",\n\t\"'`'\",\n}\n\nvar protoStatenames = [...]string{}\n\nconst protoEofCode = 1\nconst protoErrCode = 2\nconst protoInitialStackSize = 16\n\nvar protoExca = [...]int16{\n\t-1, 0,\n\t1, 6,\n\t-2, 21,\n\t-1, 1,\n\t1, -1,\n\t-2, 0,\n\t-1, 2,\n\t1, 1,\n\t-2, 21,\n\t-1, 3,\n\t1, 2,\n\t-2, 21,\n\t-1, 14,\n\t1, 7,\n\t-2, 0,\n\t-1, 89,\n\t52, 60,\n\t61, 60,\n\t69, 60,\n\t-2, 61,\n\t-1, 101,\n\t55, 37,\n\t58, 37,\n\t62, 37,\n\t67, 37,\n\t69, 37,\n\t-2, 34,\n\t-1, 112,\n\t52, 60,\n\t61, 60,\n\t69, 60,\n\t-2, 62,\n\t-1, 118,\n\t56, 249,\n\t-2, 0,\n\t-1, 121,\n\t55, 37,\n\t58, 37,\n\t62, 37,\n\t67, 37,\n\t69, 37,\n\t-2, 35,\n\t-1, 140,\n\t56, 225,\n\t-2, 0,\n\t-1, 142,\n\t56, 214,\n\t-2, 0,\n\t-1, 144,\n\t56, 250,\n\t-2, 0,\n\t-1, 198,\n\t56, 262,\n\t-2, 0,\n\t-1, 203,\n\t56, 83,\n\t62, 83,\n\t-2, 0,\n\t-1, 214,\n\t56, 226,\n\t-2, 0,\n\t-1, 271,\n\t56, 215,\n\t-2, 0,\n\t-1, 377,\n\t56, 263,\n\t-2, 0,\n\t-1, 464,\n\t56, 155,\n\t-2, 0,\n\t-1, 523,\n\t69, 144,\n\t-2, 141,\n\t-1, 531,\n\t56, 156,\n\t-2, 0,\n\t-1, 607,\n\t67, 52,\n\t-2, 49,\n\t-1, 665,\n\t69, 144,\n\t-2, 142,\n\t-1, 690,\n\t67, 52,\n\t-2, 50,\n\t-1, 732,\n\t56, 273,\n\t-2, 0,\n\t-1, 745,\n\t56, 274,\n\t-2, 0,\n}\n\nconst protoPrivate = 57344\n\nconst protoLast = 2053\n\nvar protoAct = [...]int16{\n\t140, 7, 746, 7, 7, 100, 139, 18, 440, 394,\n\t604, 436, 607, 439, 502, 39, 524, 596, 95, 532,\n\t496, 127, 437, 422, 520, 200, 32, 34, 523, 233,\n\t421, 40, 90, 93, 94, 405, 102, 106, 36, 96,\n\t109, 435, 272, 85, 378, 458, 326, 404, 21, 20,\n\t19, 107, 108, 149, 215, 202, 145, 98, 101, 86,\n\t663, 89, 449, 390, 134, 706, 703, 598, 707, 513,\n\t9, 652, 395, 510, 465, 9, 511, 396, 717, 651,\n\t507, 459, 459, 460, 452, 459, 456, 9, 506, 459,\n\t459, 462, 739, 90, 693, 451, 655, 598, 459, 9,\n\t680, 653, 459, 687, 508, 459, 423, 459, 124, 125,\n\t453, 115, 459, 459, 459, 134, 126, 133, 142, 138,\n\t131, 129, 497, 395, 198, 130, 423, 134, 199, 448,\n\t416, 388, 389, 711, 489, 395, 505, 119, 9, 387,\n\t207, 666, 488, 593, 9, 468, 472, 113, 222, 112,\n\t273, 386, 470, 462, 587, 9, 373, 120, 121, 385,\n\t110, 40, 110, 691, 674, 428, 424, 414, 374, 122,\n\t114, 375, 279, 760, 758, 754, 750, 104, 744, 743,\n\t741, 733, 729, 721, 695, 9, 424, 716, 753, 219,\n\t217, 218, 668, 383, 227, 376, 322, 270, 213, 728,\n\t719, 323, 713, 658, 464, 123, 379, 118, 117, 207,\n\t116, 5, 6, 104, 399, 9, 598, 104, 670, 324,\n\t31, 702, 222, 667, 493, 490, 9, 492, 430, 392,\n\t419, 111, 13, 12, 403, 599, 407, 408, 413, 528,\n\t463, 40, 381, 748, 726, 8, 412, 724, 397, 659,\n\t33, 415, 15, 656, 26, 26, 9, 37, 38, 384,\n\t210, 209, 105, 219, 217, 218, 103, 35, 227, 400,\n\t595, 417, 211, 212, 402, 23, 529, 594, 104, 273,\n\t409, 582, 406, 24, 413, 516, 25, 26, 382, 495,\n\t491, 4, 412, 33, 10, 11, 731, 745, 380, 197,\n\t377, 279, 475, 476, 477, 478, 479, 480, 481, 482,\n\t483, 484, 485, 486, 418, 22, 143, 28, 27, 29,\n\t30, 144, 274, 425, 141, 271, 220, 420, 275, 225,\n\t411, 426, 427, 410, 40, 530, 531, 214, 231, 224,\n\t221, 535, 147, 223, 429, 146, 534, 216, 204, 203,\n\t447, 499, 601, 538, 150, 228, 605, 99, 602, 327,\n\t540, 154, 234, 277, 606, 329, 542, 156, 237, 474,\n\t391, 393, 438, 132, 128, 87, 88, 432, 206, 91,\n\t431, 521, 518, 533, 522, 379, 17, 16, 434, 14,\n\t3, 2, 1, 0, 0, 442, 442, 0, 0, 0,\n\t0, 207, 0, 0, 457, 0, 0, 454, 455, 466,\n\t0, 469, 471, 0, 0, 0, 0, 0, 0, 450,\n\t473, 445, 433, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 444, 0, 494, 0, 0, 0, 0, 0,\n\t0, 0, 0, 487, 0, 0, 0, 498, 0, 442,\n\t461, 0, 0, 0, 467, 503, 514, 0, 0, 517,\n\t0, 525, 526, 0, 0, 90, 504, 0, 583, 584,\n\t0, 0, 0, 0, 0, 0, 0, 0, 586, 0,\n\t0, 0, 0, 0, 585, 0, 0, 0, 588, 0,\n\t591, 0, 509, 0, 0, 0, 0, 0, 527, 0,\n\t512, 515, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 592, 0, 660, 661, 657, 590,\n\t0, 0, 0, 0, 0, 0, 0, 90, 0, 0,\n\t654, 0, 0, 589, 0, 0, 0, 0, 0, 0,\n\t0, 597, 0, 90, 672, 673, 664, 40, 0, 0,\n\t665, 669, 0, 0, 671, 0, 0, 675, 0, 0,\n\t0, 0, 662, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 676, 0, 0, 0, 0, 0, 0,\n\t679, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 678, 0, 0, 0,\n\t0, 0, 0, 682, 0, 684, 689, 0, 690, 686,\n\t685, 0, 0, 0, 0, 0, 0, 0, 677, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t681, 683, 0, 688, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 442, 0,\n\t697, 0, 0, 699, 503, 696, 0, 692, 0, 701,\n\t0, 0, 0, 133, 0, 504, 131, 129, 710, 0,\n\t709, 130, 0, 0, 0, 0, 715, 712, 0, 700,\n\t704, 0, 0, 0, 0, 0, 720, 0, 0, 722,\n\t718, 714, 694, 0, 0, 698, 0, 0, 133, 0,\n\t0, 131, 129, 0, 727, 0, 130, 732, 705, 708,\n\t730, 0, 735, 725, 723, 0, 734, 0, 0, 0,\n\t0, 0, 0, 0, 749, 742, 0, 0, 0, 0,\n\t747, 736, 737, 0, 0, 755, 752, 0, 756, 0,\n\t0, 757, 0, 747, 0, 0, 751, 0, 0, 0,\n\t759, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t738, 501, 740, 33, 137, 135, 41, 42, 43, 44,\n\t45, 46, 47, 48, 49, 50, 51, 52, 53, 54,\n\t55, 56, 57, 58, 59, 60, 61, 62, 63, 64,\n\t65, 66, 67, 68, 69, 70, 71, 72, 73, 74,\n\t75, 76, 77, 78, 79, 80, 81, 82, 83, 84,\n\t0, 0, 0, 0, 134, 0, 0, 0, 0, 0,\n\t0, 0, 395, 0, 441, 0, 0, 0, 500, 33,\n\t137, 135, 41, 42, 43, 44, 45, 46, 47, 48,\n\t49, 50, 51, 52, 53, 54, 55, 56, 57, 58,\n\t59, 60, 61, 62, 63, 64, 65, 66, 67, 68,\n\t69, 70, 71, 72, 73, 74, 75, 76, 77, 78,\n\t79, 80, 81, 82, 83, 84, 0, 0, 0, 0,\n\t134, 0, 0, 0, 0, 0, 0, 0, 395, 0,\n\t441, 0, 0, 443, 33, 137, 135, 41, 42, 43,\n\t44, 45, 46, 47, 48, 49, 50, 51, 52, 53,\n\t54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n\t64, 65, 66, 67, 68, 69, 70, 71, 72, 73,\n\t74, 75, 76, 77, 78, 79, 80, 81, 82, 83,\n\t84, 0, 0, 0, 0, 134, 0, 0, 0, 0,\n\t0, 0, 0, 395, 0, 441, 41, 42, 43, 44,\n\t45, 46, 47, 48, 49, 50, 51, 52, 53, 54,\n\t55, 56, 57, 58, 59, 60, 61, 62, 63, 64,\n\t65, 66, 67, 68, 69, 70, 71, 72, 73, 74,\n\t75, 76, 77, 78, 79, 80, 81, 82, 83, 84,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 205, 92, 0, 0, 519, 41,\n\t42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\n\t52, 53, 54, 55, 56, 57, 58, 59, 60, 61,\n\t62, 63, 64, 65, 66, 67, 68, 69, 70, 71,\n\t72, 73, 74, 75, 76, 77, 78, 79, 80, 81,\n\t82, 83, 84, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 446, 0, 205, 0, 0, 0,\n\t208, 41, 42, 43, 44, 45, 46, 47, 48, 49,\n\t50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\n\t60, 61, 62, 63, 64, 65, 66, 67, 68, 69,\n\t70, 71, 72, 73, 74, 75, 76, 77, 78, 79,\n\t80, 81, 82, 83, 84, 0, 0, 0, 0, 0,\n\t201, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 208, 33, 137, 135, 41, 42, 43, 44,\n\t45, 46, 47, 48, 49, 50, 51, 52, 53, 54,\n\t55, 56, 57, 58, 59, 60, 61, 62, 63, 64,\n\t65, 66, 67, 68, 69, 70, 71, 72, 73, 74,\n\t75, 76, 77, 78, 79, 80, 81, 82, 83, 84,\n\t0, 0, 0, 0, 134, 0, 0, 0, 0, 0,\n\t205, 0, 0, 0, 136, 41, 42, 43, 44, 45,\n\t46, 47, 48, 49, 50, 51, 52, 53, 54, 55,\n\t56, 57, 58, 59, 60, 61, 62, 63, 64, 65,\n\t66, 67, 68, 69, 70, 71, 72, 73, 74, 75,\n\t76, 77, 78, 79, 80, 81, 82, 83, 84, 0,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 33, 423, 208, 41, 42, 43,\n\t44, 45, 46, 47, 48, 49, 50, 51, 52, 53,\n\t54, 55, 56, 57, 58, 59, 60, 61, 62, 63,\n\t64, 65, 66, 67, 68, 69, 70, 71, 72, 73,\n\t74, 75, 76, 77, 78, 79, 80, 81, 82, 83,\n\t84, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 424, 41, 42, 43, 44,\n\t45, 46, 47, 48, 49, 50, 51, 52, 53, 54,\n\t55, 56, 57, 58, 59, 60, 61, 62, 63, 64,\n\t65, 66, 67, 68, 69, 70, 71, 72, 73, 74,\n\t75, 76, 77, 78, 79, 80, 81, 82, 83, 84,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 0, 0, 92, 41, 42, 43, 44,\n\t45, 46, 47, 48, 49, 50, 51, 52, 53, 54,\n\t55, 56, 57, 58, 59, 60, 61, 62, 63, 64,\n\t65, 66, 67, 68, 69, 70, 71, 72, 73, 74,\n\t75, 76, 77, 78, 79, 80, 81, 82, 83, 84,\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 97,\n\t608, 609, 610, 611, 612, 613, 614, 615, 616, 617,\n\t618, 619, 620, 621, 622, 623, 624, 625, 626, 627,\n\t628, 629, 630, 631, 632, 633, 634, 635, 636, 637,\n\t638, 639, 640, 641, 642, 643, 644, 645, 646, 647,\n\t648, 649, 600, 650, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 603, 330, 331, 332, 333, 334, 335,\n\t336, 337, 338, 339, 340, 341, 342, 343, 344, 345,\n\t346, 347, 348, 349, 350, 351, 352, 353, 354, 355,\n\t356, 357, 358, 359, 401, 360, 361, 362, 363, 364,\n\t365, 366, 367, 368, 369, 370, 371, 372, 0, 0,\n\t0, 0, 0, 226, 0, 0, 0, 328, 238, 239,\n\t240, 241, 242, 243, 244, 26, 245, 246, 247, 248,\n\t153, 152, 151, 249, 250, 251, 252, 253, 254, 255,\n\t256, 257, 258, 259, 260, 261, 262, 263, 0, 230,\n\t236, 229, 264, 265, 232, 28, 27, 29, 266, 267,\n\t268, 269, 0, 0, 0, 0, 0, 0, 0, 0,\n\t0, 235, 330, 331, 332, 333, 334, 335, 336, 337,\n\t338, 339, 340, 341, 342, 343, 344, 345, 346, 347,\n\t348, 349, 350, 351, 352, 353, 354, 355, 356, 357,\n\t358, 359, 325, 360, 361, 362, 363, 364, 365, 366,\n\t367, 368, 369, 370, 371, 372, 0, 0, 0, 0,\n\t0, 148, 0, 0, 0, 328, 157, 158, 159, 160,\n\t161, 162, 163, 164, 165, 166, 167, 168, 153, 152,\n\t151, 169, 170, 171, 172, 173, 174, 175, 176, 177,\n\t178, 179, 180, 181, 182, 183, 0, 184, 185, 186,\n\t187, 188, 189, 190, 191, 192, 193, 194, 195, 196,\n\t0, 0, 0, 0, 0, 536, 0, 0, 0, 155,\n\t543, 544, 545, 546, 547, 548, 549, 537, 550, 551,\n\t552, 553, 0, 0, 0, 554, 555, 556, 557, 558,\n\t559, 560, 561, 562, 563, 564, 565, 566, 567, 568,\n\t539, 569, 570, 571, 572, 573, 574, 575, 576, 577,\n\t578, 579, 580, 581, 0, 0, 0, 0, 0, 0,\n\t0, 0, 0, 541, 210, 209, 41, 42, 43, 44,\n\t45, 46, 47, 48, 49, 50, 51, 52, 53, 54,\n\t55, 56, 57, 58, 59, 60, 61, 62, 63, 64,\n\t65, 66, 67, 68, 69, 70, 71, 72, 73, 74,\n\t75, 76, 77, 78, 79, 80, 81, 82, 83, 84,\n\t33, 406, 0, 41, 42, 43, 44, 45, 46, 47,\n\t48, 49, 50, 51, 52, 53, 54, 55, 56, 57,\n\t58, 59, 60, 61, 62, 63, 64, 65, 66, 67,\n\t68, 69, 70, 71, 72, 73, 74, 75, 76, 77,\n\t78, 79, 80, 81, 82, 83, 84, 276, 0, 0,\n\t0, 0, 280, 281, 282, 283, 284, 285, 286, 26,\n\t287, 288, 289, 290, 291, 292, 293, 294, 295, 296,\n\t297, 298, 299, 300, 301, 302, 303, 304, 305, 306,\n\t307, 308, 309, 310, 311, 312, 313, 314, 278, 315,\n\t316, 317, 318, 319, 320, 321, 398, 0, 0, 0,\n\t0, 41, 42, 43, 44, 45, 46, 47, 48, 49,\n\t50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\n\t60, 61, 62, 63, 64, 65, 66, 67, 68, 69,\n\t70, 71, 72, 73, 74, 75, 76, 77, 78, 79,\n\t80, 81, 82, 83, 84, 41, 42, 43, 44, 45,\n\t46, 47, 48, 49, 50, 51, 52, 53, 54, 55,\n\t56, 57, 58, 59, 60, 61, 62, 63, 64, 65,\n\t66, 67, 68, 69, 70, 71, 72, 73, 74, 75,\n\t76, 77, 78, 79, 80, 81, 82, 83, 84, 608,\n\t609, 610, 611, 612, 613, 614, 615, 616, 617, 618,\n\t619, 620, 621, 622, 623, 624, 625, 626, 627, 628,\n\t629, 630, 631, 632, 633, 634, 635, 636, 637, 638,\n\t639, 640, 641, 642, 643, 644, 645, 646, 647, 648,\n\t649, 0, 650,\n}\n\nvar protoPact = [...]int16{\n\t203, -1000, 162, 162, -1000, 181, 180, 273, 167, -1000,\n\t-1000, -1000, 289, 289, 273, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, 246, 1958, 1329, 1958, 1958, 1389,\n\t1958, -1000, 213, -1000, 209, -1000, 173, 289, 289, 102,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, 179, -1000, 1329, 110, -1000,\n\t-1000, -1000, 1389, 155, 153, 152, -1000, 1958, -1000, 1958,\n\t109, -1000, 150, -1000, -1000, -1000, -1000, 173, 173, -1000,\n\t1958, 1149, -1000, -1000, -1000, 52, 162, 162, 1659, -1000,\n\t-1000, -1000, -1000, 162, -1000, -1000, -1000, 162, -1000, -1000,\n\t274, -1000, -1000, -1000, 1084, -1000, 255, -1000, -1000, 142,\n\t1551, 141, 1865, 140, 1659, -1000, -1000, -1000, 166, 1605,\n\t1958, -1000, -1000, -1000, 108, 1958, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, 139, 240, -1000,\n\t137, -1000, -1000, 1208, 98, 78, 9, -1000, 1914, -1000,\n\t-1000, -1000, -1000, 162, 1551, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, 1497, 1958, 277,\n\t1958, 1958, 1816, -1000, 107, 1958, 67, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t162, 1865, -1000, -1000, -1000, -1000, -1000, 178, 1270, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, 162, -1000, -1000, 1958, 1958, 105, 1958, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, 176, 1958, 100, 162, 240, -1000, -1000,\n\t-1000, -1000, 1958, -1000, -1000, -1000, -1000, -1000, -1000, 835,\n\t835, -1000, -1000, -1000, -1000, 1022, 60, 26, 41, -1000,\n\t-1000, 1958, 1958, 34, 30, -1000, 199, 149, 22, 92,\n\t91, 85, 274, -1000, 1958, 100, 278, -1000, -1000, 121,\n\t81, -1000, 184, -1000, 285, -1000, 175, 172, 1958, 100,\n\t284, -1000, -1000, -1000, 56, -1000, -1000, -1000, -1000, 274,\n\t-1000, 1769, -1000, 769, -1000, 74, -1000, 19, -1000, 35,\n\t-1000, -1000, 1958, -1000, 21, 17, 280, -1000, 162, 959,\n\t162, 162, 277, 234, 1713, 276, -1000, 162, 162, -1000,\n\t289, -1000, 1958, -1000, 93, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, 46, 121, 162,\n\t101, -1000, 272, 265, -1000, 44, 185, 1443, -1000, 10,\n\t-1000, 32, -1000, -1000, -1000, -1000, -1000, 72, -1000, 27,\n\t248, 162, 148, 244, -1000, 162, 46, -1000, -9, -1000,\n\t-1000, 1329, 80, -1000, 171, -1000, -1000, -1000, -1000, -1000,\n\t136, 1713, -1000, -1000, -1000, -1000, 165, 1329, 1958, 1958,\n\t104, 1958, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, 46, -1000, -1000, 274, -1000, 1389, -1000, 162,\n\t-1000, -1000, -1000, -1000, 45, 44, -1000, 163, -1000, 56,\n\t1389, 36, -1000, 1958, -1000, 2002, 103, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,\n\t-1000, -1000, 900, -1000, -1000, -1000, 39, 128, 162, 46,\n\t-1000, -1000, 162, -1000, -1000, -1000, -1000, 1149, 162, -1000,\n\t-1000, 169, 14, 13, 1958, 100, -1000, 162, 71, -1000,\n\t162, 147, -1000, 163, -1000, 132, 11, -1000, -1000, -1000,\n\t-1000, -1000, -1000, 162, 145, 162, 127, -1000, 162, -1000,\n\t-1000, -1000, 1149, 242, -1000, 163, 239, 162, 144, -1000,\n\t-1000, -1000, 126, 162, -1000, -1000, 162, -1000, 125, 162,\n\t-1000, 162, -1000, 163, 44, -1000, 37, 124, 162, -1000,\n\t123, 122, 241, 162, 120, -1000, -1000, -1000, 163, 162,\n\t133, -1000, 119, -1000, 162, 241, -1000, -1000, -1000, -1000,\n\t162, -1000, 118, 162, -1000, -1000, -1000, -1000, -1000, 117,\n\t-1000,\n}\n\nvar protoPgo = [...]int16{\n\t0, 392, 391, 390, 291, 252, 389, 387, 386, 384,\n\t383, 7, 28, 24, 382, 381, 379, 378, 376, 61,\n\t59, 16, 375, 45, 41, 21, 374, 11, 9, 22,\n\t8, 373, 372, 14, 371, 370, 23, 5, 369, 368,\n\t367, 366, 365, 364, 363, 53, 58, 57, 12, 10,\n\t15, 362, 361, 360, 359, 358, 39, 357, 356, 18,\n\t355, 354, 353, 46, 352, 351, 350, 349, 55, 25,\n\t348, 347, 346, 345, 343, 342, 341, 340, 339, 338,\n\t50, 54, 337, 6, 19, 336, 335, 333, 330, 329,\n\t328, 29, 35, 30, 47, 327, 326, 49, 42, 325,\n\t324, 322, 48, 56, 321, 316, 13, 315, 44, 300,\n\t299, 298, 2, 297, 296, 20, 17, 0, 245,\n}\n\nvar protoR1 = [...]int8{\n\t0, 1, 1, 1, 1, 1, 1, 4, 6, 6,\n\t5, 5, 5, 5, 5, 5, 5, 5, 118, 118,\n\t117, 117, 116, 116, 2, 3, 7, 7, 7, 8,\n\t50, 50, 56, 56, 57, 57, 47, 47, 46, 51,\n\t51, 52, 52, 53, 53, 54, 54, 55, 55, 58,\n\t58, 49, 49, 48, 10, 11, 18, 18, 19, 20,\n\t20, 22, 22, 21, 21, 16, 25, 25, 26, 26,\n\t26, 26, 30, 30, 30, 30, 31, 31, 106, 106,\n\t28, 28, 69, 68, 68, 67, 67, 67, 67, 67,\n\t67, 70, 70, 70, 17, 17, 17, 17, 24, 24,\n\t24, 27, 27, 27, 27, 35, 35, 29, 29, 29,\n\t32, 32, 32, 65, 65, 33, 33, 34, 34, 34,\n\t66, 66, 59, 59, 60, 60, 61, 61, 62, 62,\n\t63, 63, 64, 64, 45, 45, 45, 23, 23, 14,\n\t14, 15, 15, 13, 13, 12, 9, 9, 75, 75,\n\t77, 77, 77, 77, 74, 86, 86, 85, 85, 84,\n\t84, 84, 84, 84, 72, 72, 72, 72, 76, 76,\n\t76, 76, 78, 78, 78, 78, 79, 38, 38, 38,\n\t38, 38, 38, 38, 38, 38, 38, 38, 38, 96,\n\t96, 94, 94, 92, 92, 92, 95, 95, 93, 93,\n\t93, 36, 36, 89, 89, 90, 90, 91, 91, 87,\n\t87, 88, 88, 97, 100, 100, 99, 99, 98, 98,\n\t98, 98, 101, 101, 80, 83, 83, 82, 82, 81,\n\t81, 81, 81, 81, 81, 81, 81, 81, 81, 81,\n\t71, 71, 71, 71, 71, 71, 71, 71, 102, 105,\n\t105, 104, 104, 103, 103, 103, 103, 73, 73, 73,\n\t73, 107, 110, 110, 109, 109, 108, 108, 108, 111,\n\t111, 115, 115, 114, 114, 113, 113, 112, 112, 39,\n\t39, 39, 39, 39, 39, 39, 39, 39, 39, 39,\n\t39, 39, 39, 39, 39, 39, 39, 39, 39, 39,\n\t39, 39, 39, 39, 39, 39, 39, 39, 39, 39,\n\t39, 39, 40, 40, 40, 40, 40, 40, 40, 40,\n\t40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n\t40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n\t40, 40, 40, 40, 40, 40, 40, 40, 40, 40,\n\t40, 40, 44, 44, 44, 44, 44, 44, 44, 44,\n\t44, 44, 44, 44, 44, 44, 44, 44, 44, 44,\n\t44, 44, 44, 44, 44, 44, 44, 44, 44, 44,\n\t44, 44, 44, 44, 44, 44, 44, 44, 44, 44,\n\t44, 44, 44, 44, 41, 41, 41, 41, 41, 41,\n\t41, 41, 41, 41, 41, 41, 41, 41, 41, 41,\n\t41, 41, 41, 41, 41, 41, 41, 41, 41, 41,\n\t41, 41, 41, 41, 41, 41, 41, 41, 41, 41,\n\t41, 41, 41, 42, 42, 42, 42, 42, 42, 42,\n\t42, 42, 42, 42, 42, 42, 42, 42, 42, 42,\n\t42, 42, 42, 42, 42, 42, 42, 42, 42, 42,\n\t42, 42, 42, 42, 42, 42, 42, 42, 42, 42,\n\t42, 42, 42, 42, 42, 42, 43, 43, 43, 43,\n\t43, 43, 43, 43, 43, 43, 43, 43, 43, 43,\n\t43, 43, 43, 43, 43, 43, 43, 43, 43, 43,\n\t43, 43, 43, 43, 43, 43, 43, 43, 43, 43,\n\t43, 43, 43, 43, 43, 43, 43, 43, 43, 37,\n\t37, 37, 37, 37, 37, 37, 37, 37, 37, 37,\n\t37, 37, 37, 37, 37, 37, 37, 37, 37, 37,\n\t37, 37, 37, 37, 37, 37, 37, 37, 37, 37,\n\t37, 37, 37, 37, 37, 37, 37, 37, 37, 37,\n\t37, 37, 37,\n}\n\nvar protoR2 = [...]int8{\n\t0, 1, 1, 1, 2, 2, 0, 2, 2, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 2,\n\t1, 0, 1, 0, 4, 4, 3, 4, 4, 3,\n\t1, 3, 1, 2, 1, 2, 1, 1, 2, 1,\n\t3, 1, 3, 1, 3, 1, 3, 1, 2, 1,\n\t2, 1, 1, 2, 5, 5, 1, 1, 2, 1,\n\t1, 1, 2, 1, 2, 3, 1, 1, 1, 1,\n\t1, 1, 1, 2, 1, 2, 2, 2, 1, 2,\n\t3, 2, 1, 1, 2, 1, 2, 2, 2, 2,\n\t1, 3, 2, 3, 1, 3, 5, 3, 1, 1,\n\t1, 1, 1, 2, 1, 1, 1, 1, 3, 2,\n\t3, 2, 3, 1, 3, 1, 1, 3, 2, 3,\n\t1, 3, 1, 2, 1, 2, 1, 2, 1, 2,\n\t1, 2, 1, 2, 1, 1, 1, 3, 2, 1,\n\t2, 1, 2, 1, 1, 2, 3, 1, 8, 9,\n\t9, 10, 7, 8, 6, 0, 1, 2, 1, 1,\n\t1, 1, 2, 1, 5, 6, 3, 4, 7, 8,\n\t5, 6, 5, 6, 3, 4, 6, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 4,\n\t4, 1, 3, 1, 3, 3, 1, 3, 1, 3,\n\t3, 1, 2, 4, 1, 4, 1, 3, 3, 1,\n\t3, 1, 3, 6, 1, 2, 2, 1, 1, 1,\n\t1, 1, 4, 5, 6, 1, 2, 2, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t6, 7, 5, 6, 4, 5, 3, 4, 6, 0,\n\t1, 2, 1, 1, 1, 2, 1, 6, 7, 5,\n\t6, 6, 1, 2, 2, 1, 1, 1, 1, 6,\n\t9, 4, 3, 1, 2, 2, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n\t1, 1, 1,\n}\n\nvar protoChk = [...]int16{\n\t-1000, -1, -2, -3, -4, 8, 9, -117, -118, 53,\n\t-4, -4, 52, 52, -6, -5, -7, -8, -11, -80,\n\t-97, -102, -107, 2, 10, 13, 14, 45, 44, 46,\n\t47, 53, -106, 4, -106, -5, -106, 11, 12, -50,\n\t-37, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n\t16, 17, 18, 19, 20, 21, 22, 23, 24, 25,\n\t26, 27, 28, 29, 30, 31, 32, 33, 34, 35,\n\t36, 37, 38, 39, 40, 41, 42, 43, 44, 45,\n\t46, 47, 48, 49, 50, -21, -20, -22, -18, -19,\n\t-37, -16, 66, -37, -37, -59, -56, 60, -47, -57,\n\t-37, -46, -37, 53, 4, 53, -117, -106, -106, -117,\n\t60, 52, -19, -20, 60, -59, 55, 55, 55, -56,\n\t-47, -46, 60, 55, -117, -117, -37, -25, -26, -28,\n\t-106, -30, -31, -37, 55, 6, 65, 5, 67, -83,\n\t-117, -100, -117, -105, -104, -103, -73, -75, 2, -45,\n\t-61, 21, 20, 19, -52, 60, -40, 7, 8, 9,\n\t10, 11, 12, 13, 14, 15, 16, 17, 18, 22,\n\t23, 24, 25, 26, 27, 28, 29, 30, 31, 32,\n\t33, 34, 35, 36, 38, 39, 40, 41, 42, 43,\n\t44, 45, 46, 47, 48, 49, 50, -110, -117, -117,\n\t-69, 56, -68, -67, -70, 2, -17, -37, 68, 6,\n\t5, 17, 18, 56, -82, -81, -71, -97, -80, -102,\n\t-96, -77, -11, -74, -78, -89, 2, -45, -60, 40,\n\t38, -79, 43, -91, -51, 60, 39, -39, 7, 8,\n\t9, 10, 11, 12, 13, 15, 16, 17, 18, 22,\n\t23, 24, 25, 26, 27, 28, 29, 30, 31, 32,\n\t33, 34, 35, 36, 41, 42, 47, 48, 49, 50,\n\t56, -99, -98, -11, -101, -90, 2, -44, 43, -91,\n\t7, 8, 9, 10, 11, 12, 13, 15, 16, 17,\n\t18, 19, 20, 21, 22, 23, 24, 25, 26, 27,\n\t28, 29, 30, 31, 32, 33, 34, 35, 36, 37,\n\t38, 39, 40, 41, 42, 44, 45, 46, 47, 48,\n\t49, 50, 56, -103, 53, 37, -63, -54, 60, -42,\n\t7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n\t17, 18, 19, 20, 21, 22, 23, 24, 25, 26,\n\t27, 28, 29, 30, 31, 32, 33, 34, 35, 36,\n\t38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n\t48, 49, 50, -37, 60, -50, 56, -109, -108, -11,\n\t-111, 2, 48, 56, -68, 61, 53, 61, 53, 54,\n\t54, -35, -29, -34, -28, 63, 68, -56, 2, -117,\n\t-81, 37, -63, -37, -94, -92, 5, -37, -37, -94,\n\t-87, -88, -106, -37, 60, -50, 63, -117, -98, 52,\n\t-95, -93, -36, 5, 65, -117, -37, -37, 60, -50,\n\t52, -37, -117, -108, -37, -24, -27, -29, -32, -106,\n\t-30, 65, -37, 68, -24, -69, 62, -66, 69, 2,\n\t-29, 69, 58, 69, -37, -37, 52, -117, -23, 68,\n\t53, -23, 61, 41, 55, 52, -117, -23, 53, -117,\n\t61, -117, 61, -37, -38, 24, 25, 26, 27, 28,\n\t29, 30, 31, 32, 33, 34, 35, -36, 61, 53,\n\t41, 5, 52, 52, -37, 5, -115, 66, -37, -65,\n\t69, 2, -33, -27, -29, 62, 69, 61, 69, -56,\n\t52, 55, -23, 52, -117, -23, 5, -117, -14, 69,\n\t-13, -15, -9, -12, -21, -117, -117, -92, 5, 42,\n\t-86, -85, -84, -10, -72, -76, 2, 14, -62, 37,\n\t-53, 60, -41, 7, 8, 9, 10, 11, 12, 13,\n\t15, 16, 17, 18, 22, 23, 24, 25, 26, 27,\n\t28, 29, 30, 31, 32, 33, 34, 35, 36, 38,\n\t39, 40, 41, 42, 43, 44, 45, 46, 47, 48,\n\t49, 50, 5, -117, -117, -106, -37, 61, -117, -23,\n\t-93, -117, -36, 42, 5, 5, -116, -23, 53, 50,\n\t49, -64, -55, 60, -49, -58, -43, -48, 7, 8,\n\t9, 10, 11, 12, 13, 14, 15, 16, 17, 18,\n\t19, 20, 21, 22, 23, 24, 25, 26, 27, 28,\n\t29, 30, 31, 32, 33, 34, 35, 36, 37, 38,\n\t39, 40, 41, 42, 43, 44, 45, 46, 47, 48,\n\t50, 69, 61, 69, -29, 69, 5, -83, 55, 5,\n\t-117, -117, -23, 69, -13, -12, 61, 52, 56, -84,\n\t53, -21, -37, -37, 60, -50, -117, -23, -59, -117,\n\t55, -23, -116, -23, -116, -115, -59, 67, -56, -49,\n\t-48, 60, -33, 55, -23, 56, -83, -117, -23, -117,\n\t-25, -117, 52, 52, -116, -23, 52, 55, -23, -37,\n\t-117, 62, -83, 55, -116, -117, 55, 67, -83, 55,\n\t-117, 56, -117, -25, 5, -116, 5, -83, 55, 56,\n\t-83, -114, -117, 56, -83, -117, -116, -116, -23, 55,\n\t-23, 56, -83, 56, 56, -113, -112, -11, 2, -117,\n\t56, -116, -83, 55, 56, -117, -112, -117, 56, -83,\n\t56,\n}\n\nvar protoDef = [...]int16{\n\t-2, -2, -2, -2, 3, 0, 0, 0, 20, 18,\n\t4, 5, 0, 0, -2, 9, 10, 11, 12, 13,\n\t14, 15, 16, 17, 0, 0, 0, 0, 0, 0,\n\t0, 19, 0, 78, 0, 8, 21, 0, 0, 21,\n\t30, 519, 520, 521, 522, 523, 524, 525, 526, 527,\n\t528, 529, 530, 531, 532, 533, 534, 535, 536, 537,\n\t538, 539, 540, 541, 542, 543, 544, 545, 546, 547,\n\t548, 549, 550, 551, 552, 553, 554, 555, 556, 557,\n\t558, 559, 560, 561, 562, 0, 63, 0, 59, -2,\n\t56, 57, 0, 0, 0, 0, 122, 0, 32, 0,\n\t36, -2, 0, 24, 79, 25, 26, 21, 21, 29,\n\t0, 0, -2, 64, 58, 0, 21, 21, -2, 123,\n\t33, -2, 38, 21, 27, 28, 31, 21, 66, 67,\n\t68, 69, 70, 71, 0, 72, 0, 74, 65, 0,\n\t-2, 0, -2, 0, -2, 252, 253, 254, 256, 0,\n\t0, 134, 135, 136, 126, 0, 41, 312, 313, 314,\n\t315, 316, 317, 318, 319, 320, 321, 322, 323, 324,\n\t325, 326, 327, 328, 329, 330, 331, 332, 333, 334,\n\t335, 336, 337, 338, 339, 340, 341, 342, 343, 344,\n\t345, 346, 347, 348, 349, 350, 351, 0, -2, 55,\n\t0, 81, 82, -2, 85, 90, 0, 94, 0, 73,\n\t75, 76, 77, 21, -2, 228, 229, 230, 231, 232,\n\t233, 234, 235, 236, 237, 238, 239, 0, 0, 0,\n\t0, 0, 0, 204, 124, 0, 305, 39, 279, 280,\n\t281, 282, 283, 284, 285, 286, 287, 288, 289, 290,\n\t291, 292, 293, 294, 295, 296, 297, 298, 299, 300,\n\t301, 302, 303, 304, 306, 307, 308, 309, 310, 311,\n\t21, -2, 217, 218, 219, 220, 221, 0, 0, 206,\n\t352, 353, 354, 355, 356, 357, 358, 359, 360, 361,\n\t362, 363, 364, 365, 366, 367, 368, 369, 370, 371,\n\t372, 373, 374, 375, 376, 377, 378, 379, 380, 381,\n\t382, 383, 384, 385, 386, 387, 388, 389, 390, 391,\n\t392, 393, 21, 251, 255, 0, 0, 130, 0, 45,\n\t433, 434, 435, 436, 437, 438, 439, 440, 441, 442,\n\t443, 444, 445, 446, 447, 448, 449, 450, 451, 452,\n\t453, 454, 455, 456, 457, 458, 459, 460, 461, 462,\n\t463, 464, 465, 466, 467, 468, 469, 470, 471, 472,\n\t473, 474, 475, 0, 0, 127, 21, -2, 265, 266,\n\t267, 268, 0, 80, 84, 86, 87, 88, 89, 0,\n\t0, 92, 105, 106, 107, 0, 0, 0, 0, 224,\n\t227, 0, 0, 21, 0, 191, 193, 0, 21, 0,\n\t21, 21, 209, 211, 0, 125, 0, 213, 216, 0,\n\t0, 196, 198, 201, 0, 248, 0, 0, 0, 131,\n\t0, 42, 261, 264, 0, 93, 98, 99, 100, 101,\n\t102, 0, 104, 0, 91, 0, 109, 0, 118, 0,\n\t120, 95, 0, 97, 0, 21, 0, 246, 21, 0,\n\t21, 21, 0, 0, -2, 0, 174, 21, 21, 207,\n\t0, 208, 0, 40, 0, 177, 178, 179, 180, 181,\n\t182, 183, 184, 185, 186, 187, 188, 21, 0, 21,\n\t0, 202, 0, 0, 46, 23, 0, 0, 103, 0,\n\t111, 0, 113, 115, 116, 108, 117, 0, 119, 0,\n\t0, 21, 0, 0, 244, 21, 21, 247, 0, 138,\n\t139, 0, 143, -2, 147, 189, 190, 192, 194, 195,\n\t0, -2, 158, 159, 160, 161, 163, 0, 0, 0,\n\t128, 0, 43, 394, 395, 396, 397, 398, 399, 400,\n\t401, 402, 403, 404, 405, 406, 407, 408, 409, 410,\n\t411, 412, 413, 414, 415, 416, 417, 418, 419, 420,\n\t421, 422, 423, 424, 425, 426, 427, 428, 429, 430,\n\t431, 432, 21, 175, 203, 210, 212, 0, 222, 21,\n\t197, 205, 199, 200, 0, 23, 259, 23, 22, 0,\n\t0, 0, 132, 0, 47, 0, 51, -2, 476, 477,\n\t478, 479, 480, 481, 482, 483, 484, 485, 486, 487,\n\t488, 489, 490, 491, 492, 493, 494, 495, 496, 497,\n\t498, 499, 500, 501, 502, 503, 504, 505, 506, 507,\n\t508, 509, 510, 511, 512, 513, 514, 515, 516, 517,\n\t518, 110, 0, 112, 121, 96, 0, 0, 21, 21,\n\t245, 242, 21, 137, 140, -2, 145, 0, 21, 157,\n\t162, 0, 23, 0, 0, 129, 172, 21, 0, 223,\n\t21, 0, 257, 23, 260, 21, 0, 272, 133, 48,\n\t-2, 53, 114, 21, 0, 21, 0, 240, 21, 243,\n\t146, 154, 0, 0, 166, 23, 0, 21, 0, 44,\n\t173, 176, 0, 21, 258, 269, 21, 271, 0, 21,\n\t152, 21, 241, 23, 23, 167, 0, 0, 21, 148,\n\t0, 0, -2, 21, 0, 153, 54, 164, 23, 21,\n\t0, 170, 0, 149, 21, -2, 276, 277, 278, 150,\n\t21, 165, 0, 21, 171, 270, 275, 151, 168, 0,\n\t169,\n}\n\nvar protoTok1 = [...]int8{\n\t1, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t3, 3, 3, 77, 3, 75, 74, 73, 71, 3,\n\t66, 67, 70, 64, 61, 65, 60, 58, 3, 3,\n\t3, 3, 3, 3, 3, 3, 3, 3, 54, 53,\n\t63, 52, 62, 59, 76, 3, 3, 3, 3, 3,\n\t3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t3, 68, 57, 69, 72, 3, 79, 3, 3, 3,\n\t3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n\t3, 3, 3, 55, 3, 56, 78,\n}\n\nvar protoTok2 = [...]int8{\n\t2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\n\t12, 13, 14, 15, 16, 17, 18, 19, 20, 21,\n\t22, 23, 24, 25, 26, 27, 28, 29, 30, 31,\n\t32, 33, 34, 35, 36, 37, 38, 39, 40, 41,\n\t42, 43, 44, 45, 46, 47, 48, 49, 50, 51,\n}\n\nvar protoTok3 = [...]int8{\n\t0,\n}\n\nvar protoErrorMessages = [...]struct {\n\tstate int\n\ttoken int\n\tmsg   string\n}{}\n\n/*\tparser for yacc output\t*/\n\nvar (\n\tprotoDebug        = 0\n\tprotoErrorVerbose = false\n)\n\ntype protoLexer interface {\n\tLex(lval *protoSymType) int\n\tError(s string)\n}\n\ntype protoParser interface {\n\tParse(protoLexer) int\n\tLookahead() int\n}\n\ntype protoParserImpl struct {\n\tlval  protoSymType\n\tstack [protoInitialStackSize]protoSymType\n\tchar  int\n}\n\nfunc (p *protoParserImpl) Lookahead() int {\n\treturn p.char\n}\n\nfunc protoNewParser() protoParser {\n\treturn &protoParserImpl{}\n}\n\nconst protoFlag = -1000\n\nfunc protoTokname(c int) string {\n\tif c >= 1 && c-1 < len(protoToknames) {\n\t\tif protoToknames[c-1] != \"\" {\n\t\t\treturn protoToknames[c-1]\n\t\t}\n\t}\n\treturn __yyfmt__.Sprintf(\"tok-%v\", c)\n}\n\nfunc protoStatname(s int) string {\n\tif s >= 0 && s < len(protoStatenames) {\n\t\tif protoStatenames[s] != \"\" {\n\t\t\treturn protoStatenames[s]\n\t\t}\n\t}\n\treturn __yyfmt__.Sprintf(\"state-%v\", s)\n}\n\nfunc protoErrorMessage(state, lookAhead int) string {\n\tconst TOKSTART = 4\n\n\tif !protoErrorVerbose {\n\t\treturn \"syntax error\"\n\t}\n\n\tfor _, e := range protoErrorMessages {\n\t\tif e.state == state && e.token == lookAhead {\n\t\t\treturn \"syntax error: \" + e.msg\n\t\t}\n\t}\n\n\tres := \"syntax error: unexpected \" + protoTokname(lookAhead)\n\n\t// To match Bison, suggest at most four expected tokens.\n\texpected := make([]int, 0, 4)\n\n\t// Look for shiftable tokens.\n\tbase := int(protoPact[state])\n\tfor tok := TOKSTART; tok-1 < len(protoToknames); tok++ {\n\t\tif n := base + tok; n >= 0 && n < protoLast && int(protoChk[int(protoAct[n])]) == tok {\n\t\t\tif len(expected) == cap(expected) {\n\t\t\t\treturn res\n\t\t\t}\n\t\t\texpected = append(expected, tok)\n\t\t}\n\t}\n\n\tif protoDef[state] == -2 {\n\t\ti := 0\n\t\tfor protoExca[i] != -1 || int(protoExca[i+1]) != state {\n\t\t\ti += 2\n\t\t}\n\n\t\t// Look for tokens that we accept or reduce.\n\t\tfor i += 2; protoExca[i] >= 0; i += 2 {\n\t\t\ttok := int(protoExca[i])\n\t\t\tif tok < TOKSTART || protoExca[i+1] == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif len(expected) == cap(expected) {\n\t\t\t\treturn res\n\t\t\t}\n\t\t\texpected = append(expected, tok)\n\t\t}\n\n\t\t// If the default action is to accept or reduce, give up.\n\t\tif protoExca[i+1] != 0 {\n\t\t\treturn res\n\t\t}\n\t}\n\n\tfor i, tok := range expected {\n\t\tif i == 0 {\n\t\t\tres += \", expecting \"\n\t\t} else {\n\t\t\tres += \" or \"\n\t\t}\n\t\tres += protoTokname(tok)\n\t}\n\treturn res\n}\n\nfunc protolex1(lex protoLexer, lval *protoSymType) (char, token int) {\n\ttoken = 0\n\tchar = lex.Lex(lval)\n\tif char <= 0 {\n\t\ttoken = int(protoTok1[0])\n\t\tgoto out\n\t}\n\tif char < len(protoTok1) {\n\t\ttoken = int(protoTok1[char])\n\t\tgoto out\n\t}\n\tif char >= protoPrivate {\n\t\tif char < protoPrivate+len(protoTok2) {\n\t\t\ttoken = int(protoTok2[char-protoPrivate])\n\t\t\tgoto out\n\t\t}\n\t}\n\tfor i := 0; i < len(protoTok3); i += 2 {\n\t\ttoken = int(protoTok3[i+0])\n\t\tif token == char {\n\t\t\ttoken = int(protoTok3[i+1])\n\t\t\tgoto out\n\t\t}\n\t}\n\nout:\n\tif token == 0 {\n\t\ttoken = int(protoTok2[1]) /* unknown char */\n\t}\n\tif protoDebug >= 3 {\n\t\t__yyfmt__.Printf(\"lex %s(%d)\\n\", protoTokname(token), uint(char))\n\t}\n\treturn char, token\n}\n\nfunc protoParse(protolex protoLexer) int {\n\treturn protoNewParser().Parse(protolex)\n}\n\nfunc (protorcvr *protoParserImpl) Parse(protolex protoLexer) int {\n\tvar proton int\n\tvar protoVAL protoSymType\n\tvar protoDollar []protoSymType\n\t_ = protoDollar // silence set and not used\n\tprotoS := protorcvr.stack[:]\n\n\tNerrs := 0   /* number of errors */\n\tErrflag := 0 /* error recovery flag */\n\tprotostate := 0\n\tprotorcvr.char = -1\n\tprototoken := -1 // protorcvr.char translated into internal numbering\n\tdefer func() {\n\t\t// Make sure we report no lookahead when not parsing.\n\t\tprotostate = -1\n\t\tprotorcvr.char = -1\n\t\tprototoken = -1\n\t}()\n\tprotop := -1\n\tgoto protostack\n\nret0:\n\treturn 0\n\nret1:\n\treturn 1\n\nprotostack:\n\t/* put a state and value onto the stack */\n\tif protoDebug >= 4 {\n\t\t__yyfmt__.Printf(\"char %v in %v\\n\", protoTokname(prototoken), protoStatname(protostate))\n\t}\n\n\tprotop++\n\tif protop >= len(protoS) {\n\t\tnyys := make([]protoSymType, len(protoS)*2)\n\t\tcopy(nyys, protoS)\n\t\tprotoS = nyys\n\t}\n\tprotoS[protop] = protoVAL\n\tprotoS[protop].yys = protostate\n\nprotonewstate:\n\tproton = int(protoPact[protostate])\n\tif proton <= protoFlag {\n\t\tgoto protodefault /* simple state */\n\t}\n\tif protorcvr.char < 0 {\n\t\tprotorcvr.char, prototoken = protolex1(protolex, &protorcvr.lval)\n\t}\n\tproton += prototoken\n\tif proton < 0 || proton >= protoLast {\n\t\tgoto protodefault\n\t}\n\tproton = int(protoAct[proton])\n\tif int(protoChk[proton]) == prototoken { /* valid shift */\n\t\tprotorcvr.char = -1\n\t\tprototoken = -1\n\t\tprotoVAL = protorcvr.lval\n\t\tprotostate = proton\n\t\tif Errflag > 0 {\n\t\t\tErrflag--\n\t\t}\n\t\tgoto protostack\n\t}\n\nprotodefault:\n\t/* default state action */\n\tproton = int(protoDef[protostate])\n\tif proton == -2 {\n\t\tif protorcvr.char < 0 {\n\t\t\tprotorcvr.char, prototoken = protolex1(protolex, &protorcvr.lval)\n\t\t}\n\n\t\t/* look through exception table */\n\t\txi := 0\n\t\tfor {\n\t\t\tif protoExca[xi+0] == -1 && int(protoExca[xi+1]) == protostate {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\txi += 2\n\t\t}\n\t\tfor xi += 2; ; xi += 2 {\n\t\t\tproton = int(protoExca[xi+0])\n\t\t\tif proton < 0 || proton == prototoken {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tproton = int(protoExca[xi+1])\n\t\tif proton < 0 {\n\t\t\tgoto ret0\n\t\t}\n\t}\n\tif proton == 0 {\n\t\t/* error ... attempt to resume parsing */\n\t\tswitch Errflag {\n\t\tcase 0: /* brand new error */\n\t\t\tprotolex.Error(protoErrorMessage(protostate, prototoken))\n\t\t\tNerrs++\n\t\t\tif protoDebug >= 1 {\n\t\t\t\t__yyfmt__.Printf(\"%s\", protoStatname(protostate))\n\t\t\t\t__yyfmt__.Printf(\" saw %s\\n\", protoTokname(prototoken))\n\t\t\t}\n\t\t\tfallthrough\n\n\t\tcase 1, 2: /* incompletely recovered error ... try again */\n\t\t\tErrflag = 3\n\n\t\t\t/* find a state where \"error\" is a legal shift action */\n\t\t\tfor protop >= 0 {\n\t\t\t\tproton = int(protoPact[protoS[protop].yys]) + protoErrCode\n\t\t\t\tif proton >= 0 && proton < protoLast {\n\t\t\t\t\tprotostate = int(protoAct[proton]) /* simulate a shift of \"error\" */\n\t\t\t\t\tif int(protoChk[protostate]) == protoErrCode {\n\t\t\t\t\t\tgoto protostack\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* the current p has no shift on \"error\", pop stack */\n\t\t\t\tif protoDebug >= 2 {\n\t\t\t\t\t__yyfmt__.Printf(\"error recovery pops state %d\\n\", protoS[protop].yys)\n\t\t\t\t}\n\t\t\t\tprotop--\n\t\t\t}\n\t\t\t/* there is no state on the stack with an error shift ... abort */\n\t\t\tgoto ret1\n\n\t\tcase 3: /* no shift yet; clobber input char */\n\t\t\tif protoDebug >= 2 {\n\t\t\t\t__yyfmt__.Printf(\"error recovery discards %s\\n\", protoTokname(prototoken))\n\t\t\t}\n\t\t\tif prototoken == protoEofCode {\n\t\t\t\tgoto ret1\n\t\t\t}\n\t\t\tprotorcvr.char = -1\n\t\t\tprototoken = -1\n\t\t\tgoto protonewstate /* try again in the same state */\n\t\t}\n\t}\n\n\t/* reduction by production proton */\n\tif protoDebug >= 2 {\n\t\t__yyfmt__.Printf(\"reduce %v in:\\n\\t%v\\n\", proton, protoStatname(protostate))\n\t}\n\n\tprotont := proton\n\tprotopt := protop\n\t_ = protopt // guard against \"declared and not used\"\n\n\tprotop -= int(protoR2[proton])\n\t// protop is now the index of $0. Perform the default action. Iff the\n\t// reduced production is ε, $1 is possibly out of range.\n\tif protop+1 >= len(protoS) {\n\t\tnyys := make([]protoSymType, len(protoS)*2)\n\t\tcopy(nyys, protoS)\n\t\tprotoS = nyys\n\t}\n\tprotoVAL = protoS[protop+1]\n\n\t/* consult goto table to find next state */\n\tproton = int(protoR1[proton])\n\tprotog := int(protoPgo[proton])\n\tprotoj := protog + protoS[protop].yys + 1\n\n\tif protoj >= protoLast {\n\t\tprotostate = int(protoAct[protog])\n\t} else {\n\t\tprotostate = int(protoAct[protoj])\n\t\tif int(protoChk[protostate]) != -proton {\n\t\t\tprotostate = int(protoAct[protog])\n\t\t}\n\t}\n\t// dummy call; replaced with literal code\n\tswitch protont {\n\n\tcase 1:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tlex := protolex.(*protoLex)\n\t\t\tprotoVAL.file = ast.NewFileNode(lex.info, protoDollar[1].syn, nil, lex.eof)\n\t\t\tlex.res = protoVAL.file\n\t\t}\n\tcase 2:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tlex := protolex.(*protoLex)\n\t\t\tprotoVAL.file = ast.NewFileNodeWithEdition(lex.info, protoDollar[1].ed, nil, lex.eof)\n\t\t\tlex.res = protoVAL.file\n\t\t}\n\tcase 3:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tlex := protolex.(*protoLex)\n\t\t\tprotoVAL.file = ast.NewFileNode(lex.info, nil, protoDollar[1].fileElements, lex.eof)\n\t\t\tlex.res = protoVAL.file\n\t\t}\n\tcase 4:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tlex := protolex.(*protoLex)\n\t\t\tprotoVAL.file = ast.NewFileNode(lex.info, protoDollar[1].syn, protoDollar[2].fileElements, lex.eof)\n\t\t\tlex.res = protoVAL.file\n\t\t}\n\tcase 5:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tlex := protolex.(*protoLex)\n\t\t\tprotoVAL.file = ast.NewFileNodeWithEdition(lex.info, protoDollar[1].ed, protoDollar[2].fileElements, lex.eof)\n\t\t\tlex.res = protoVAL.file\n\t\t}\n\tcase 6:\n\t\tprotoDollar = protoS[protopt-0 : protopt+1]\n\t\t{\n\t\t\tlex := protolex.(*protoLex)\n\t\t\tprotoVAL.file = ast.NewFileNode(lex.info, nil, nil, lex.eof)\n\t\t\tlex.res = protoVAL.file\n\t\t}\n\tcase 7:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = prependRunes(toFileElement, protoDollar[1].bs, protoDollar[2].fileElements)\n\t\t}\n\tcase 8:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = append(protoDollar[1].fileElements, protoDollar[2].fileElements...)\n\t\t}\n\tcase 9:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = protoDollar[1].fileElements\n\t\t}\n\tcase 10:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = toElements[ast.FileElement](toFileElement, protoDollar[1].imprt.Node, protoDollar[1].imprt.Runes)\n\t\t}\n\tcase 11:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = toElements[ast.FileElement](toFileElement, protoDollar[1].pkg.Node, protoDollar[1].pkg.Runes)\n\t\t}\n\tcase 12:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = toElements[ast.FileElement](toFileElement, protoDollar[1].opt.Node, protoDollar[1].opt.Runes)\n\t\t}\n\tcase 13:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = toElements[ast.FileElement](toFileElement, protoDollar[1].msg.Node, protoDollar[1].msg.Runes)\n\t\t}\n\tcase 14:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = toElements[ast.FileElement](toFileElement, protoDollar[1].en.Node, protoDollar[1].en.Runes)\n\t\t}\n\tcase 15:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = toElements[ast.FileElement](toFileElement, protoDollar[1].extend.Node, protoDollar[1].extend.Runes)\n\t\t}\n\tcase 16:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = toElements[ast.FileElement](toFileElement, protoDollar[1].svc.Node, protoDollar[1].svc.Runes)\n\t\t}\n\tcase 17:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fileElements = nil\n\t\t}\n\tcase 18:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.bs = []*ast.RuneNode{protoDollar[1].b}\n\t\t}\n\tcase 19:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.bs = append(protoDollar[1].bs, protoDollar[2].b)\n\t\t}\n\tcase 20:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.bs = protoDollar[1].bs\n\t\t}\n\tcase 21:\n\t\tprotoDollar = protoS[protopt-0 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.bs = nil\n\t\t}\n\tcase 22:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.b = protoDollar[1].b\n\t\t}\n\tcase 23:\n\t\tprotoDollar = protoS[protopt-0 : protopt+1]\n\t\t{\n\t\t\tprotolex.(*protoLex).Error(\"syntax error: expecting ';'\")\n\t\t\tprotoVAL.b = nil\n\t\t}\n\tcase 24:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.syn = ast.NewSyntaxNode(protoDollar[1].id.ToKeyword(), protoDollar[2].b, toStringValueNode(protoDollar[3].str), protoDollar[4].b)\n\t\t}\n\tcase 25:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ed = ast.NewEditionNode(protoDollar[1].id.ToKeyword(), protoDollar[2].b, toStringValueNode(protoDollar[3].str), protoDollar[4].b)\n\t\t}\n\tcase 26:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[3].bs)\n\t\t\tprotoVAL.imprt = newNodeWithRunes(ast.NewImportNode(protoDollar[1].id.ToKeyword(), nil, nil, toStringValueNode(protoDollar[2].str), semi), extra...)\n\t\t}\n\tcase 27:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[4].bs)\n\t\t\tprotoVAL.imprt = newNodeWithRunes(ast.NewImportNode(protoDollar[1].id.ToKeyword(), nil, protoDollar[2].id.ToKeyword(), toStringValueNode(protoDollar[3].str), semi), extra...)\n\t\t}\n\tcase 28:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[4].bs)\n\t\t\tprotoVAL.imprt = newNodeWithRunes(ast.NewImportNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id.ToKeyword(), nil, toStringValueNode(protoDollar[3].str), semi), extra...)\n\t\t}\n\tcase 29:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[3].bs)\n\t\t\tprotoVAL.pkg = newNodeWithRunes(ast.NewPackageNode(protoDollar[1].id.ToKeyword(), protoDollar[2].cid.toIdentValueNode(nil), semi), extra...)\n\t\t}\n\tcase 30:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].id}}\n\t\t}\n\tcase 31:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[3].id)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].b)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 32:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].cidPart.Node}, dots: protoDollar[1].cidPart.Runes}\n\t\t}\n\tcase 33:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[2].cidPart.Node)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].cidPart.Runes...)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 34:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].cidPart.Node}, dots: protoDollar[1].cidPart.Runes}\n\t\t}\n\tcase 35:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[2].cidPart.Node)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].cidPart.Runes...)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 36:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cidPart = newNodeWithRunes(protoDollar[1].id)\n\t\t}\n\tcase 37:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected '.'\")\n\t\t\tprotoVAL.cidPart = protoDollar[1].cidPart\n\t\t}\n\tcase 38:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cidPart = newNodeWithRunes(protoDollar[1].id, protoDollar[2].b)\n\t\t}\n\tcase 39:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].id}}\n\t\t}\n\tcase 40:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[3].id)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].b)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 41:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].id}}\n\t\t}\n\tcase 42:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[3].id)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].b)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 43:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].id}}\n\t\t}\n\tcase 44:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[3].id)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].b)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 45:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].id}}\n\t\t}\n\tcase 46:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[3].id)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].b)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 47:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].cidPart.Node}, dots: protoDollar[1].cidPart.Runes}\n\t\t}\n\tcase 48:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[2].cidPart.Node)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].cidPart.Runes...)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 49:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cid = &identSlices{idents: []*ast.IdentNode{protoDollar[1].cidPart.Node}, dots: protoDollar[1].cidPart.Runes}\n\t\t}\n\tcase 50:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].cid.idents = append(protoDollar[1].cid.idents, protoDollar[2].cidPart.Node)\n\t\t\tprotoDollar[1].cid.dots = append(protoDollar[1].cid.dots, protoDollar[2].cidPart.Runes...)\n\t\t\tprotoVAL.cid = protoDollar[1].cid\n\t\t}\n\tcase 51:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cidPart = newNodeWithRunes(protoDollar[1].id)\n\t\t}\n\tcase 52:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected '.'\")\n\t\t\tprotoVAL.cidPart = protoDollar[1].cidPart\n\t\t}\n\tcase 53:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cidPart = newNodeWithRunes(protoDollar[1].id, protoDollar[2].b)\n\t\t}\n\tcase 54:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\toptName := ast.NewOptionNameNode(protoDollar[2].optNms.refs, protoDollar[2].optNms.dots)\n\t\t\tprotoVAL.optRaw = ast.NewOptionNode(protoDollar[1].id.ToKeyword(), optName, protoDollar[3].b, protoDollar[4].v, protoDollar[5].b)\n\t\t}\n\tcase 55:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\toptName := ast.NewOptionNameNode(protoDollar[2].optNms.refs, protoDollar[2].optNms.dots)\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[5].bs)\n\t\t\tprotoVAL.opt = newNodeWithRunes(ast.NewOptionNode(protoDollar[1].id.ToKeyword(), optName, protoDollar[3].b, protoDollar[4].v, semi), extra...)\n\t\t}\n\tcase 56:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.refRaw = ast.NewFieldReferenceNode(protoDollar[1].id)\n\t\t}\n\tcase 57:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.refRaw = protoDollar[1].refRaw\n\t\t}\n\tcase 58:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ref = newNodeWithRunes(protoDollar[1].refRaw, protoDollar[2].b)\n\t\t}\n\tcase 59:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ref = newNodeWithRunes(protoDollar[1].refRaw)\n\t\t}\n\tcase 60:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected '.'\")\n\t\t\tprotoVAL.ref = protoDollar[1].ref\n\t\t}\n\tcase 61:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.optNms = &fieldRefSlices{refs: []*ast.FieldReferenceNode{protoDollar[1].ref.Node}, dots: protoDollar[1].ref.Runes}\n\t\t}\n\tcase 62:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].optNms.refs = append(protoDollar[1].optNms.refs, protoDollar[2].ref.Node)\n\t\t\tprotoDollar[1].optNms.dots = append(protoDollar[1].optNms.dots, protoDollar[2].ref.Runes...)\n\t\t\tprotoVAL.optNms = protoDollar[1].optNms\n\t\t}\n\tcase 63:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.optNms = &fieldRefSlices{refs: []*ast.FieldReferenceNode{protoDollar[1].ref.Node}, dots: protoDollar[1].ref.Runes}\n\t\t}\n\tcase 64:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].optNms.refs = append(protoDollar[1].optNms.refs, protoDollar[2].ref.Node)\n\t\t\tprotoDollar[1].optNms.dots = append(protoDollar[1].optNms.dots, protoDollar[2].ref.Runes...)\n\t\t\tprotoVAL.optNms = protoDollar[1].optNms\n\t\t}\n\tcase 65:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.refRaw = ast.NewExtensionFieldReferenceNode(protoDollar[1].b, protoDollar[2].tid, protoDollar[3].b)\n\t\t}\n\tcase 68:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = toStringValueNode(protoDollar[1].str)\n\t\t}\n\tcase 71:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = protoDollar[1].id\n\t\t}\n\tcase 72:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = protoDollar[1].f\n\t\t}\n\tcase 73:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = ast.NewSignedFloatLiteralNode(protoDollar[1].b, protoDollar[2].f)\n\t\t}\n\tcase 74:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = protoDollar[1].i\n\t\t}\n\tcase 75:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[2].i.Val > math.MaxInt64+1 {\n\t\t\t\t// can't represent as int so treat as float literal\n\t\t\t\tprotoVAL.v = ast.NewSignedFloatLiteralNode(protoDollar[1].b, protoDollar[2].i)\n\t\t\t} else {\n\t\t\t\tprotoVAL.v = ast.NewNegativeIntLiteralNode(protoDollar[1].b, protoDollar[2].i)\n\t\t\t}\n\t\t}\n\tcase 76:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tf := ast.NewSpecialFloatLiteralNode(protoDollar[2].id.ToKeyword())\n\t\t\tprotoVAL.v = ast.NewSignedFloatLiteralNode(protoDollar[1].b, f)\n\t\t}\n\tcase 77:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tf := ast.NewSpecialFloatLiteralNode(protoDollar[2].id.ToKeyword())\n\t\t\tprotoVAL.v = ast.NewSignedFloatLiteralNode(protoDollar[1].b, f)\n\t\t}\n\tcase 78:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.str = []*ast.StringLiteralNode{protoDollar[1].s}\n\t\t}\n\tcase 79:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.str = append(protoDollar[1].str, protoDollar[2].s)\n\t\t}\n\tcase 80:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[2].msgLitFlds == nil {\n\t\t\t\tprotoVAL.v = ast.NewMessageLiteralNode(protoDollar[1].b, nil, nil, protoDollar[3].b)\n\t\t\t} else {\n\t\t\t\tfields, delimiters := protoDollar[2].msgLitFlds.toNodes()\n\t\t\t\tprotoVAL.v = ast.NewMessageLiteralNode(protoDollar[1].b, fields, delimiters, protoDollar[3].b)\n\t\t\t}\n\t\t}\n\tcase 81:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = ast.NewMessageLiteralNode(protoDollar[1].b, nil, nil, protoDollar[2].b)\n\t\t}\n\tcase 84:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].msgLitFlds != nil {\n\t\t\t\tprotoDollar[1].msgLitFlds.next = protoDollar[2].msgLitFlds\n\t\t\t\tprotoVAL.msgLitFlds = protoDollar[1].msgLitFlds\n\t\t\t} else {\n\t\t\t\tprotoVAL.msgLitFlds = protoDollar[2].msgLitFlds\n\t\t\t}\n\t\t}\n\tcase 85:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].msgLitFld != nil {\n\t\t\t\tprotoVAL.msgLitFlds = &messageFieldList{field: protoDollar[1].msgLitFld}\n\t\t\t} else {\n\t\t\t\tprotoVAL.msgLitFlds = nil\n\t\t\t}\n\t\t}\n\tcase 86:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].msgLitFld != nil {\n\t\t\t\tprotoVAL.msgLitFlds = &messageFieldList{field: protoDollar[1].msgLitFld, delimiter: protoDollar[2].b}\n\t\t\t} else {\n\t\t\t\tprotoVAL.msgLitFlds = nil\n\t\t\t}\n\t\t}\n\tcase 87:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].msgLitFld != nil {\n\t\t\t\tprotoVAL.msgLitFlds = &messageFieldList{field: protoDollar[1].msgLitFld, delimiter: protoDollar[2].b}\n\t\t\t} else {\n\t\t\t\tprotoVAL.msgLitFlds = nil\n\t\t\t}\n\t\t}\n\tcase 88:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgLitFlds = nil\n\t\t}\n\tcase 89:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgLitFlds = nil\n\t\t}\n\tcase 90:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgLitFlds = nil\n\t\t}\n\tcase 91:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].refRaw != nil && protoDollar[2].b != nil {\n\t\t\t\tprotoVAL.msgLitFld = ast.NewMessageFieldNode(protoDollar[1].refRaw, protoDollar[2].b, protoDollar[3].v)\n\t\t\t} else {\n\t\t\t\tprotoVAL.msgLitFld = nil\n\t\t\t}\n\t\t}\n\tcase 92:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].refRaw != nil && protoDollar[2].v != nil {\n\t\t\t\tprotoVAL.msgLitFld = ast.NewMessageFieldNode(protoDollar[1].refRaw, nil, protoDollar[2].v)\n\t\t\t} else {\n\t\t\t\tprotoVAL.msgLitFld = nil\n\t\t\t}\n\t\t}\n\tcase 93:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgLitFld = nil\n\t\t}\n\tcase 94:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.refRaw = ast.NewFieldReferenceNode(protoDollar[1].id)\n\t\t}\n\tcase 95:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.refRaw = ast.NewExtensionFieldReferenceNode(protoDollar[1].b, protoDollar[2].cid.toIdentValueNode(nil), protoDollar[3].b)\n\t\t}\n\tcase 96:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.refRaw = ast.NewAnyTypeReferenceNode(protoDollar[1].b, protoDollar[2].cid.toIdentValueNode(nil), protoDollar[3].b, protoDollar[4].cid.toIdentValueNode(nil), protoDollar[5].b)\n\t\t}\n\tcase 97:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.refRaw = nil\n\t\t}\n\tcase 101:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = toStringValueNode(protoDollar[1].str)\n\t\t}\n\tcase 103:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tkw := protoDollar[2].id.ToKeyword()\n\t\t\tswitch strings.ToLower(kw.Val) {\n\t\t\tcase \"inf\", \"infinity\", \"nan\":\n\t\t\t\t// these are acceptable\n\t\t\tdefault:\n\t\t\t\t// anything else is not\n\t\t\t\tprotolex.(*protoLex).Error(`only identifiers \"inf\", \"infinity\", or \"nan\" may appear after negative sign`)\n\t\t\t}\n\t\t\t// we'll validate the identifier later\n\t\t\tf := ast.NewSpecialFloatLiteralNode(kw)\n\t\t\tprotoVAL.v = ast.NewSignedFloatLiteralNode(protoDollar[1].b, f)\n\t\t}\n\tcase 104:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = protoDollar[1].id\n\t\t}\n\tcase 108:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[2].msgLitFlds == nil {\n\t\t\t\tprotoVAL.v = ast.NewMessageLiteralNode(protoDollar[1].b, nil, nil, protoDollar[3].b)\n\t\t\t} else {\n\t\t\t\tfields, delimiters := protoDollar[2].msgLitFlds.toNodes()\n\t\t\t\tprotoVAL.v = ast.NewMessageLiteralNode(protoDollar[1].b, fields, delimiters, protoDollar[3].b)\n\t\t\t}\n\t\t}\n\tcase 109:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = ast.NewMessageLiteralNode(protoDollar[1].b, nil, nil, protoDollar[2].b)\n\t\t}\n\tcase 110:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[2].sl == nil {\n\t\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, nil, nil, protoDollar[3].b)\n\t\t\t} else {\n\t\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, protoDollar[2].sl.vals, protoDollar[2].sl.commas, protoDollar[3].b)\n\t\t\t}\n\t\t}\n\tcase 111:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, nil, nil, protoDollar[2].b)\n\t\t}\n\tcase 112:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, nil, nil, protoDollar[3].b)\n\t\t}\n\tcase 113:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.sl = &valueSlices{vals: []ast.ValueNode{protoDollar[1].v}}\n\t\t}\n\tcase 114:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].sl.vals = append(protoDollar[1].sl.vals, protoDollar[3].v)\n\t\t\tprotoDollar[1].sl.commas = append(protoDollar[1].sl.commas, protoDollar[2].b)\n\t\t\tprotoVAL.sl = protoDollar[1].sl\n\t\t}\n\tcase 117:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[2].sl == nil {\n\t\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, nil, nil, protoDollar[3].b)\n\t\t\t} else {\n\t\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, protoDollar[2].sl.vals, protoDollar[2].sl.commas, protoDollar[3].b)\n\t\t\t}\n\t\t}\n\tcase 118:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, nil, nil, protoDollar[2].b)\n\t\t}\n\tcase 119:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.v = ast.NewArrayLiteralNode(protoDollar[1].b, nil, nil, protoDollar[3].b)\n\t\t}\n\tcase 120:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.sl = &valueSlices{vals: []ast.ValueNode{protoDollar[1].v}}\n\t\t}\n\tcase 121:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].sl.vals = append(protoDollar[1].sl.vals, protoDollar[3].v)\n\t\t\tprotoDollar[1].sl.commas = append(protoDollar[1].sl.commas, protoDollar[2].b)\n\t\t\tprotoVAL.sl = protoDollar[1].sl\n\t\t}\n\tcase 122:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[1].cid.toIdentValueNode(nil)\n\t\t}\n\tcase 123:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[2].cid.toIdentValueNode(protoDollar[1].b)\n\t\t}\n\tcase 124:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[1].cid.toIdentValueNode(nil)\n\t\t}\n\tcase 125:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[2].cid.toIdentValueNode(protoDollar[1].b)\n\t\t}\n\tcase 126:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[1].cid.toIdentValueNode(nil)\n\t\t}\n\tcase 127:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[2].cid.toIdentValueNode(protoDollar[1].b)\n\t\t}\n\tcase 128:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[1].cid.toIdentValueNode(nil)\n\t\t}\n\tcase 129:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[2].cid.toIdentValueNode(protoDollar[1].b)\n\t\t}\n\tcase 130:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[1].cid.toIdentValueNode(nil)\n\t\t}\n\tcase 131:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[2].cid.toIdentValueNode(protoDollar[1].b)\n\t\t}\n\tcase 132:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[1].cid.toIdentValueNode(nil)\n\t\t}\n\tcase 133:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.tid = protoDollar[2].cid.toIdentValueNode(protoDollar[1].b)\n\t\t}\n\tcase 137:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.cmpctOpts = ast.NewCompactOptionsNode(protoDollar[1].b, protoDollar[2].opts.options, protoDollar[2].opts.commas, protoDollar[3].b)\n\t\t}\n\tcase 138:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotolex.(*protoLex).Error(\"compact options must have at least one option\")\n\t\t\tprotoVAL.cmpctOpts = ast.NewCompactOptionsNode(protoDollar[1].b, nil, nil, protoDollar[2].b)\n\t\t}\n\tcase 139:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.opts = &compactOptionSlices{options: []*ast.OptionNode{protoDollar[1].opt.Node}, commas: protoDollar[1].opt.Runes}\n\t\t}\n\tcase 140:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].opts.options = append(protoDollar[1].opts.options, protoDollar[2].opt.Node)\n\t\t\tprotoDollar[1].opts.commas = append(protoDollar[1].opts.commas, protoDollar[2].opt.Runes...)\n\t\t\tprotoVAL.opts = protoDollar[1].opts\n\t\t}\n\tcase 141:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.opts = &compactOptionSlices{options: []*ast.OptionNode{protoDollar[1].opt.Node}, commas: protoDollar[1].opt.Runes}\n\t\t}\n\tcase 142:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].opts.options = append(protoDollar[1].opts.options, protoDollar[2].opt.Node)\n\t\t\tprotoDollar[1].opts.commas = append(protoDollar[1].opts.commas, protoDollar[2].opt.Runes...)\n\t\t\tprotoVAL.opts = protoDollar[1].opts\n\t\t}\n\tcase 143:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.opt = newNodeWithRunes(protoDollar[1].optRaw)\n\t\t}\n\tcase 144:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotolex.(*protoLex).Error(\"syntax error: unexpected ','\")\n\t\t\tprotoVAL.opt = protoDollar[1].opt\n\t\t}\n\tcase 145:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.opt = newNodeWithRunes(protoDollar[1].optRaw, protoDollar[2].b)\n\t\t}\n\tcase 146:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\toptName := ast.NewOptionNameNode(protoDollar[1].optNms.refs, protoDollar[1].optNms.dots)\n\t\t\tprotoVAL.optRaw = ast.NewCompactOptionNode(optName, protoDollar[2].b, protoDollar[3].v)\n\t\t}\n\tcase 147:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\toptName := ast.NewOptionNameNode(protoDollar[1].optNms.refs, protoDollar[1].optNms.dots)\n\t\t\tprotolex.(*protoLex).Error(\"compact option must have a value\")\n\t\t\tprotoVAL.optRaw = ast.NewCompactOptionNode(optName, nil, nil)\n\t\t}\n\tcase 148:\n\t\tprotoDollar = protoS[protopt-8 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.grp = ast.NewGroupNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id.ToKeyword(), protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, nil, protoDollar[6].b, protoDollar[7].msgElements, protoDollar[8].b)\n\t\t}\n\tcase 149:\n\t\tprotoDollar = protoS[protopt-9 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.grp = ast.NewGroupNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id.ToKeyword(), protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, protoDollar[6].cmpctOpts, protoDollar[7].b, protoDollar[8].msgElements, protoDollar[9].b)\n\t\t}\n\tcase 150:\n\t\tprotoDollar = protoS[protopt-9 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgGrp = newNodeWithRunes(ast.NewGroupNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id.ToKeyword(), protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, nil, protoDollar[6].b, protoDollar[7].msgElements, protoDollar[8].b), protoDollar[9].bs...)\n\t\t}\n\tcase 151:\n\t\tprotoDollar = protoS[protopt-10 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgGrp = newNodeWithRunes(ast.NewGroupNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id.ToKeyword(), protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, protoDollar[6].cmpctOpts, protoDollar[7].b, protoDollar[8].msgElements, protoDollar[9].b), protoDollar[10].bs...)\n\t\t}\n\tcase 152:\n\t\tprotoDollar = protoS[protopt-7 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgGrp = newNodeWithRunes(ast.NewGroupNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id.ToKeyword(), protoDollar[3].id, nil, nil, nil, protoDollar[4].b, protoDollar[5].msgElements, protoDollar[6].b), protoDollar[7].bs...)\n\t\t}\n\tcase 153:\n\t\tprotoDollar = protoS[protopt-8 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgGrp = newNodeWithRunes(ast.NewGroupNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id.ToKeyword(), protoDollar[3].id, nil, nil, protoDollar[4].cmpctOpts, protoDollar[5].b, protoDollar[6].msgElements, protoDollar[7].b), protoDollar[8].bs...)\n\t\t}\n\tcase 154:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.oo = newNodeWithRunes(ast.NewOneofNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].b, protoDollar[4].ooElements, protoDollar[5].b), protoDollar[6].bs...)\n\t\t}\n\tcase 155:\n\t\tprotoDollar = protoS[protopt-0 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ooElements = nil\n\t\t}\n\tcase 157:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[2].ooElement != nil {\n\t\t\t\tprotoVAL.ooElements = append(protoDollar[1].ooElements, protoDollar[2].ooElement)\n\t\t\t} else {\n\t\t\t\tprotoVAL.ooElements = protoDollar[1].ooElements\n\t\t\t}\n\t\t}\n\tcase 158:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].ooElement != nil {\n\t\t\t\tprotoVAL.ooElements = []ast.OneofElement{protoDollar[1].ooElement}\n\t\t\t} else {\n\t\t\t\tprotoVAL.ooElements = nil\n\t\t\t}\n\t\t}\n\tcase 159:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ooElement = protoDollar[1].optRaw\n\t\t}\n\tcase 160:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ooElement = protoDollar[1].fld\n\t\t}\n\tcase 161:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ooElement = protoDollar[1].grp\n\t\t}\n\tcase 162:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ooElement = nil\n\t\t}\n\tcase 163:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.ooElement = nil\n\t\t}\n\tcase 164:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, nil, protoDollar[5].b)\n\t\t}\n\tcase 165:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, protoDollar[5].cmpctOpts, protoDollar[6].b)\n\t\t}\n\tcase 166:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, nil, nil, nil, protoDollar[3].b)\n\t\t}\n\tcase 167:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, nil, nil, protoDollar[3].cmpctOpts, protoDollar[4].b)\n\t\t}\n\tcase 168:\n\t\tprotoDollar = protoS[protopt-7 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.grp = ast.NewGroupNode(nil, protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, nil, protoDollar[5].b, protoDollar[6].msgElements, protoDollar[7].b)\n\t\t}\n\tcase 169:\n\t\tprotoDollar = protoS[protopt-8 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.grp = ast.NewGroupNode(nil, protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, protoDollar[5].cmpctOpts, protoDollar[6].b, protoDollar[7].msgElements, protoDollar[8].b)\n\t\t}\n\tcase 170:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.grp = ast.NewGroupNode(nil, protoDollar[1].id.ToKeyword(), protoDollar[2].id, nil, nil, nil, protoDollar[3].b, protoDollar[4].msgElements, protoDollar[5].b)\n\t\t}\n\tcase 171:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.grp = ast.NewGroupNode(nil, protoDollar[1].id.ToKeyword(), protoDollar[2].id, nil, nil, protoDollar[3].cmpctOpts, protoDollar[4].b, protoDollar[5].msgElements, protoDollar[6].b)\n\t\t}\n\tcase 172:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[5].bs)\n\t\t\tprotoVAL.mapFld = newNodeWithRunes(ast.NewMapFieldNode(protoDollar[1].mapType, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, nil, semi), extra...)\n\t\t}\n\tcase 173:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[6].bs)\n\t\t\tprotoVAL.mapFld = newNodeWithRunes(ast.NewMapFieldNode(protoDollar[1].mapType, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, protoDollar[5].cmpctOpts, semi), extra...)\n\t\t}\n\tcase 174:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[3].bs)\n\t\t\tprotoVAL.mapFld = newNodeWithRunes(ast.NewMapFieldNode(protoDollar[1].mapType, protoDollar[2].id, nil, nil, nil, semi), extra...)\n\t\t}\n\tcase 175:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[4].bs)\n\t\t\tprotoVAL.mapFld = newNodeWithRunes(ast.NewMapFieldNode(protoDollar[1].mapType, protoDollar[2].id, nil, nil, protoDollar[3].cmpctOpts, semi), extra...)\n\t\t}\n\tcase 176:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mapType = ast.NewMapTypeNode(protoDollar[1].id.ToKeyword(), protoDollar[2].b, protoDollar[3].id, protoDollar[4].b, protoDollar[5].tid, protoDollar[6].b)\n\t\t}\n\tcase 189:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\t// TODO: Tolerate a missing semicolon here. This currnelty creates a shift/reduce conflict\n\t\t\t// between `extensions 1 to 10` and `extensions 1` followed by `to = 10`.\n\t\t\tprotoVAL.ext = newNodeWithRunes(ast.NewExtensionRangeNode(protoDollar[1].id.ToKeyword(), protoDollar[2].rngs.ranges, protoDollar[2].rngs.commas, nil, protoDollar[3].b), protoDollar[4].bs...)\n\t\t}\n\tcase 190:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[4].bs)\n\t\t\tprotoVAL.ext = newNodeWithRunes(ast.NewExtensionRangeNode(protoDollar[1].id.ToKeyword(), protoDollar[2].rngs.ranges, protoDollar[2].rngs.commas, protoDollar[3].cmpctOpts, semi), extra...)\n\t\t}\n\tcase 191:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rngs = &rangeSlices{ranges: []*ast.RangeNode{protoDollar[1].rng}}\n\t\t}\n\tcase 192:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].rngs.ranges = append(protoDollar[1].rngs.ranges, protoDollar[3].rng)\n\t\t\tprotoDollar[1].rngs.commas = append(protoDollar[1].rngs.commas, protoDollar[2].b)\n\t\t\tprotoVAL.rngs = protoDollar[1].rngs\n\t\t}\n\tcase 193:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rng = ast.NewRangeNode(protoDollar[1].i, nil, nil, nil)\n\t\t}\n\tcase 194:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rng = ast.NewRangeNode(protoDollar[1].i, protoDollar[2].id.ToKeyword(), protoDollar[3].i, nil)\n\t\t}\n\tcase 195:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rng = ast.NewRangeNode(protoDollar[1].i, protoDollar[2].id.ToKeyword(), nil, protoDollar[3].id.ToKeyword())\n\t\t}\n\tcase 196:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rngs = &rangeSlices{ranges: []*ast.RangeNode{protoDollar[1].rng}}\n\t\t}\n\tcase 197:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].rngs.ranges = append(protoDollar[1].rngs.ranges, protoDollar[3].rng)\n\t\t\tprotoDollar[1].rngs.commas = append(protoDollar[1].rngs.commas, protoDollar[2].b)\n\t\t\tprotoVAL.rngs = protoDollar[1].rngs\n\t\t}\n\tcase 198:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rng = ast.NewRangeNode(protoDollar[1].il, nil, nil, nil)\n\t\t}\n\tcase 199:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rng = ast.NewRangeNode(protoDollar[1].il, protoDollar[2].id.ToKeyword(), protoDollar[3].il, nil)\n\t\t}\n\tcase 200:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.rng = ast.NewRangeNode(protoDollar[1].il, protoDollar[2].id.ToKeyword(), nil, protoDollar[3].id.ToKeyword())\n\t\t}\n\tcase 201:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.il = protoDollar[1].i\n\t\t}\n\tcase 202:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.il = ast.NewNegativeIntLiteralNode(protoDollar[1].b, protoDollar[2].i)\n\t\t}\n\tcase 203:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\t// TODO: Tolerate a missing semicolon here. This currnelty creates a shift/reduce conflict\n\t\t\t// between `reserved 1 to 10` and `reserved 1` followed by `to = 10`.\n\t\t\tprotoVAL.resvd = newNodeWithRunes(ast.NewReservedRangesNode(protoDollar[1].id.ToKeyword(), protoDollar[2].rngs.ranges, protoDollar[2].rngs.commas, protoDollar[3].b), protoDollar[4].bs...)\n\t\t}\n\tcase 205:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\t// TODO: Tolerate a missing semicolon here. This currnelty creates a shift/reduce conflict\n\t\t\t// between `reserved 1 to 10` and `reserved 1` followed by `to = 10`.\n\t\t\tprotoVAL.resvd = newNodeWithRunes(ast.NewReservedRangesNode(protoDollar[1].id.ToKeyword(), protoDollar[2].rngs.ranges, protoDollar[2].rngs.commas, protoDollar[3].b), protoDollar[4].bs...)\n\t\t}\n\tcase 207:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[3].bs)\n\t\t\tprotoVAL.resvd = newNodeWithRunes(ast.NewReservedNamesNode(protoDollar[1].id.ToKeyword(), protoDollar[2].names.names, protoDollar[2].names.commas, semi), extra...)\n\t\t}\n\tcase 208:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[3].bs)\n\t\t\tprotoVAL.resvd = newNodeWithRunes(ast.NewReservedIdentifiersNode(protoDollar[1].id.ToKeyword(), protoDollar[2].names.idents, protoDollar[2].names.commas, semi), extra...)\n\t\t}\n\tcase 209:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.names = &nameSlices{names: []ast.StringValueNode{toStringValueNode(protoDollar[1].str)}}\n\t\t}\n\tcase 210:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].names.names = append(protoDollar[1].names.names, toStringValueNode(protoDollar[3].str))\n\t\t\tprotoDollar[1].names.commas = append(protoDollar[1].names.commas, protoDollar[2].b)\n\t\t\tprotoVAL.names = protoDollar[1].names\n\t\t}\n\tcase 211:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.names = &nameSlices{idents: []*ast.IdentNode{protoDollar[1].id}}\n\t\t}\n\tcase 212:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoDollar[1].names.idents = append(protoDollar[1].names.idents, protoDollar[3].id)\n\t\t\tprotoDollar[1].names.commas = append(protoDollar[1].names.commas, protoDollar[2].b)\n\t\t\tprotoVAL.names = protoDollar[1].names\n\t\t}\n\tcase 213:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.en = newNodeWithRunes(ast.NewEnumNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].b, protoDollar[4].enElements, protoDollar[5].b), protoDollar[6].bs...)\n\t\t}\n\tcase 214:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = prependRunes(toEnumElement, protoDollar[1].bs, nil)\n\t\t}\n\tcase 215:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = prependRunes(toEnumElement, protoDollar[1].bs, protoDollar[2].enElements)\n\t\t}\n\tcase 216:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = append(protoDollar[1].enElements, protoDollar[2].enElements...)\n\t\t}\n\tcase 217:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = protoDollar[1].enElements\n\t\t}\n\tcase 218:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = toElements[ast.EnumElement](toEnumElement, protoDollar[1].opt.Node, protoDollar[1].opt.Runes)\n\t\t}\n\tcase 219:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = toElements[ast.EnumElement](toEnumElement, protoDollar[1].env.Node, protoDollar[1].env.Runes)\n\t\t}\n\tcase 220:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = toElements[ast.EnumElement](toEnumElement, protoDollar[1].resvd.Node, protoDollar[1].resvd.Runes)\n\t\t}\n\tcase 221:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.enElements = nil\n\t\t}\n\tcase 222:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[4].bs)\n\t\t\tprotoVAL.env = newNodeWithRunes(ast.NewEnumValueNode(protoDollar[1].id, protoDollar[2].b, protoDollar[3].il, nil, semi), extra...)\n\t\t}\n\tcase 223:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[5].bs)\n\t\t\tprotoVAL.env = newNodeWithRunes(ast.NewEnumValueNode(protoDollar[1].id, protoDollar[2].b, protoDollar[3].il, protoDollar[4].cmpctOpts, semi), extra...)\n\t\t}\n\tcase 224:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msg = newNodeWithRunes(ast.NewMessageNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].b, protoDollar[4].msgElements, protoDollar[5].b), protoDollar[6].bs...)\n\t\t}\n\tcase 225:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = prependRunes(toMessageElement, protoDollar[1].bs, nil)\n\t\t}\n\tcase 226:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = prependRunes(toMessageElement, protoDollar[1].bs, protoDollar[2].msgElements)\n\t\t}\n\tcase 227:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = append(protoDollar[1].msgElements, protoDollar[2].msgElements...)\n\t\t}\n\tcase 228:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = protoDollar[1].msgElements\n\t\t}\n\tcase 229:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].msgFld.Node, protoDollar[1].msgFld.Runes)\n\t\t}\n\tcase 230:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].en.Node, protoDollar[1].en.Runes)\n\t\t}\n\tcase 231:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].msg.Node, protoDollar[1].msg.Runes)\n\t\t}\n\tcase 232:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].extend.Node, protoDollar[1].extend.Runes)\n\t\t}\n\tcase 233:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].ext.Node, protoDollar[1].ext.Runes)\n\t\t}\n\tcase 234:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].msgGrp.Node, protoDollar[1].msgGrp.Runes)\n\t\t}\n\tcase 235:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].opt.Node, protoDollar[1].opt.Runes)\n\t\t}\n\tcase 236:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].oo.Node, protoDollar[1].oo.Runes)\n\t\t}\n\tcase 237:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].mapFld.Node, protoDollar[1].mapFld.Runes)\n\t\t}\n\tcase 238:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = toElements[ast.MessageElement](toMessageElement, protoDollar[1].resvd.Node, protoDollar[1].resvd.Runes)\n\t\t}\n\tcase 239:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.msgElements = nil\n\t\t}\n\tcase 240:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[6].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(protoDollar[1].id.ToKeyword(), protoDollar[2].tid, protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, nil, semis), extra...)\n\t\t}\n\tcase 241:\n\t\tprotoDollar = protoS[protopt-7 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[7].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(protoDollar[1].id.ToKeyword(), protoDollar[2].tid, protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, protoDollar[6].cmpctOpts, semis), extra...)\n\t\t}\n\tcase 242:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[5].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, nil, semis), extra...)\n\t\t}\n\tcase 243:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[6].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, protoDollar[5].cmpctOpts, semis), extra...)\n\t\t}\n\tcase 244:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[4].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(protoDollar[1].id.ToKeyword(), protoDollar[2].tid, protoDollar[3].id, nil, nil, nil, semis), extra...)\n\t\t}\n\tcase 245:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[5].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(protoDollar[1].id.ToKeyword(), protoDollar[2].tid, protoDollar[3].id, nil, nil, protoDollar[4].cmpctOpts, semis), extra...)\n\t\t}\n\tcase 246:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[3].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, nil, nil, nil, semis), extra...)\n\t\t}\n\tcase 247:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tsemis, extra := protolex.(*protoLex).requireSemicolon(protoDollar[4].bs)\n\t\t\tprotoVAL.msgFld = newNodeWithRunes(ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, nil, nil, protoDollar[3].cmpctOpts, semis), extra...)\n\t\t}\n\tcase 248:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.extend = newNodeWithRunes(ast.NewExtendNode(protoDollar[1].id.ToKeyword(), protoDollar[2].tid, protoDollar[3].b, protoDollar[4].extElements, protoDollar[5].b), protoDollar[6].bs...)\n\t\t}\n\tcase 249:\n\t\tprotoDollar = protoS[protopt-0 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.extElements = nil\n\t\t}\n\tcase 251:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[2].extElement != nil {\n\t\t\t\tprotoVAL.extElements = append(protoDollar[1].extElements, protoDollar[2].extElement)\n\t\t\t} else {\n\t\t\t\tprotoVAL.extElements = protoDollar[1].extElements\n\t\t\t}\n\t\t}\n\tcase 252:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tif protoDollar[1].extElement != nil {\n\t\t\t\tprotoVAL.extElements = []ast.ExtendElement{protoDollar[1].extElement}\n\t\t\t} else {\n\t\t\t\tprotoVAL.extElements = nil\n\t\t\t}\n\t\t}\n\tcase 253:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.extElement = protoDollar[1].fld\n\t\t}\n\tcase 254:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.extElement = protoDollar[1].grp\n\t\t}\n\tcase 255:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.extElement = nil\n\t\t}\n\tcase 256:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.extElement = nil\n\t\t}\n\tcase 257:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(protoDollar[1].id.ToKeyword(), protoDollar[2].tid, protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, nil, protoDollar[6].b)\n\t\t}\n\tcase 258:\n\t\tprotoDollar = protoS[protopt-7 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(protoDollar[1].id.ToKeyword(), protoDollar[2].tid, protoDollar[3].id, protoDollar[4].b, protoDollar[5].i, protoDollar[6].cmpctOpts, protoDollar[7].b)\n\t\t}\n\tcase 259:\n\t\tprotoDollar = protoS[protopt-5 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, nil, protoDollar[5].b)\n\t\t}\n\tcase 260:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.fld = ast.NewFieldNode(nil, protoDollar[1].tid, protoDollar[2].id, protoDollar[3].b, protoDollar[4].i, protoDollar[5].cmpctOpts, protoDollar[6].b)\n\t\t}\n\tcase 261:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svc = newNodeWithRunes(ast.NewServiceNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].b, protoDollar[4].svcElements, protoDollar[5].b), protoDollar[6].bs...)\n\t\t}\n\tcase 262:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svcElements = prependRunes(toServiceElement, protoDollar[1].bs, nil)\n\t\t}\n\tcase 263:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svcElements = prependRunes(toServiceElement, protoDollar[1].bs, protoDollar[2].svcElements)\n\t\t}\n\tcase 264:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svcElements = append(protoDollar[1].svcElements, protoDollar[2].svcElements...)\n\t\t}\n\tcase 265:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svcElements = protoDollar[1].svcElements\n\t\t}\n\tcase 266:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svcElements = toElements[ast.ServiceElement](toServiceElement, protoDollar[1].opt.Node, protoDollar[1].opt.Runes)\n\t\t}\n\tcase 267:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svcElements = toElements[ast.ServiceElement](toServiceElement, protoDollar[1].mtd.Node, protoDollar[1].mtd.Runes)\n\t\t}\n\tcase 268:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.svcElements = nil\n\t\t}\n\tcase 269:\n\t\tprotoDollar = protoS[protopt-6 : protopt+1]\n\t\t{\n\t\t\tsemi, extra := protolex.(*protoLex).requireSemicolon(protoDollar[6].bs)\n\t\t\tprotoVAL.mtd = newNodeWithRunes(ast.NewRPCNode(protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].mtdMsgType, protoDollar[4].id.ToKeyword(), protoDollar[5].mtdMsgType, semi), extra...)\n\t\t}\n\tcase 270:\n\t\tprotoDollar = protoS[protopt-9 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtd = newNodeWithRunes(ast.NewRPCNodeWithBody(protoDollar[1].id.ToKeyword(), protoDollar[2].id, protoDollar[3].mtdMsgType, protoDollar[4].id.ToKeyword(), protoDollar[5].mtdMsgType, protoDollar[6].b, protoDollar[7].mtdElements, protoDollar[8].b), protoDollar[9].bs...)\n\t\t}\n\tcase 271:\n\t\tprotoDollar = protoS[protopt-4 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdMsgType = ast.NewRPCTypeNode(protoDollar[1].b, protoDollar[2].id.ToKeyword(), protoDollar[3].tid, protoDollar[4].b)\n\t\t}\n\tcase 272:\n\t\tprotoDollar = protoS[protopt-3 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdMsgType = ast.NewRPCTypeNode(protoDollar[1].b, nil, protoDollar[2].tid, protoDollar[3].b)\n\t\t}\n\tcase 273:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdElements = prependRunes(toMethodElement, protoDollar[1].bs, nil)\n\t\t}\n\tcase 274:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdElements = prependRunes(toMethodElement, protoDollar[1].bs, protoDollar[2].mtdElements)\n\t\t}\n\tcase 275:\n\t\tprotoDollar = protoS[protopt-2 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdElements = append(protoDollar[1].mtdElements, protoDollar[2].mtdElements...)\n\t\t}\n\tcase 276:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdElements = protoDollar[1].mtdElements\n\t\t}\n\tcase 277:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdElements = toElements[ast.RPCElement](toMethodElement, protoDollar[1].opt.Node, protoDollar[1].opt.Runes)\n\t\t}\n\tcase 278:\n\t\tprotoDollar = protoS[protopt-1 : protopt+1]\n\t\t{\n\t\t\tprotoVAL.mtdElements = nil\n\t\t}\n\t}\n\tgoto protostack /* stack new state and value */\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/result.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"sort\"\n\t\"strings\"\n\t\"unicode\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n\t\"github.com/bufbuild/protocompile/internal/editions\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n)\n\ntype result struct {\n\tfile  *ast.FileNode\n\tproto *descriptorpb.FileDescriptorProto\n\n\tnodes   map[proto.Message]ast.Node\n\tifNoAST *ast.NoSourceNode\n}\n\n// ResultWithoutAST returns a parse result that has no AST. All methods for\n// looking up AST nodes return a placeholder node that contains only the filename\n// in position information.\nfunc ResultWithoutAST(proto *descriptorpb.FileDescriptorProto) Result {\n\treturn &result{proto: proto, ifNoAST: ast.NewNoSourceNode(proto.GetName())}\n}\n\n// ResultFromAST constructs a descriptor proto from the given AST. The returned\n// result includes the descriptor proto and also contains an index that can be\n// used to lookup AST node information for elements in the descriptor proto\n// hierarchy.\n//\n// If validate is true, some basic validation is performed, to make sure the\n// resulting descriptor proto is valid per protobuf rules and semantics. Only\n// some language elements can be validated since some rules and semantics can\n// only be checked after all symbols are all resolved, which happens in the\n// linking step.\n//\n// The given handler is used to report any errors or warnings encountered. If any\n// errors are reported, this function returns a non-nil error.\nfunc ResultFromAST(file *ast.FileNode, validate bool, handler *reporter.Handler) (Result, error) {\n\tfilename := file.Name()\n\tr := &result{file: file, nodes: map[proto.Message]ast.Node{}}\n\tr.createFileDescriptor(filename, file, handler)\n\tif validate {\n\t\tvalidateBasic(r, handler)\n\t}\n\t// Now that we're done validating, we can set any missing labels to optional\n\t// (we leave them absent in first pass if label was missing in source, so we\n\t// can do validation on presence of label, but final descriptors are expected\n\t// to always have them present).\n\tfillInMissingLabels(r.proto)\n\treturn r, handler.Error()\n}\n\nfunc (r *result) AST() *ast.FileNode {\n\treturn r.file\n}\n\nfunc (r *result) FileDescriptorProto() *descriptorpb.FileDescriptorProto {\n\treturn r.proto\n}\n\nfunc (r *result) createFileDescriptor(filename string, file *ast.FileNode, handler *reporter.Handler) {\n\tfd := &descriptorpb.FileDescriptorProto{Name: proto.String(filename)}\n\tr.proto = fd\n\n\tr.putFileNode(fd, file)\n\n\tvar syntax protoreflect.Syntax\n\tswitch {\n\tcase file.Syntax != nil:\n\t\tswitch file.Syntax.Syntax.AsString() {\n\t\tcase \"proto3\":\n\t\t\tsyntax = protoreflect.Proto3\n\t\tcase \"proto2\":\n\t\t\tsyntax = protoreflect.Proto2\n\t\tdefault:\n\t\t\tnodeInfo := file.NodeInfo(file.Syntax.Syntax)\n\t\t\tif handler.HandleErrorf(nodeInfo, `syntax value must be \"proto2\" or \"proto3\"`) != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\t// proto2 is the default, so no need to set for that value\n\t\tif syntax != protoreflect.Proto2 {\n\t\t\tfd.Syntax = proto.String(file.Syntax.Syntax.AsString())\n\t\t}\n\tcase file.Edition != nil:\n\t\tedition := file.Edition.Edition.AsString()\n\t\tsyntax = protoreflect.Editions\n\n\t\tfd.Syntax = proto.String(\"editions\")\n\t\teditionEnum, ok := editions.SupportedEditions[edition]\n\t\tif !ok {\n\t\t\tnodeInfo := file.NodeInfo(file.Edition.Edition)\n\t\t\teditionStrs := make([]string, 0, len(editions.SupportedEditions))\n\t\t\tfor supportedEdition := range editions.SupportedEditions {\n\t\t\t\teditionStrs = append(editionStrs, fmt.Sprintf(\"%q\", supportedEdition))\n\t\t\t}\n\t\t\tsort.Strings(editionStrs)\n\t\t\tif handler.HandleErrorf(nodeInfo, `edition value %q not recognized; should be one of [%s]`, edition, strings.Join(editionStrs, \",\")) != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\tfd.Edition = editionEnum.Enum()\n\tdefault:\n\t\tsyntax = protoreflect.Proto2\n\t\tnodeInfo := file.NodeInfo(file)\n\t\thandler.HandleWarningWithPos(nodeInfo, ErrNoSyntax)\n\t}\n\n\tfor _, decl := range file.Decls {\n\t\tif handler.ReporterError() != nil {\n\t\t\treturn\n\t\t}\n\t\tswitch decl := decl.(type) {\n\t\tcase *ast.EnumNode:\n\t\t\tfd.EnumType = append(fd.EnumType, r.asEnumDescriptor(decl, syntax, handler))\n\t\tcase *ast.ExtendNode:\n\t\t\tr.addExtensions(decl, &fd.Extension, &fd.MessageType, syntax, handler, 0)\n\t\tcase *ast.ImportNode:\n\t\t\tindex := len(fd.Dependency)\n\t\t\tfd.Dependency = append(fd.Dependency, decl.Name.AsString())\n\t\t\tif decl.Public != nil {\n\t\t\t\tfd.PublicDependency = append(fd.PublicDependency, int32(index))\n\t\t\t} else if decl.Weak != nil {\n\t\t\t\tfd.WeakDependency = append(fd.WeakDependency, int32(index))\n\t\t\t}\n\t\tcase *ast.MessageNode:\n\t\t\tfd.MessageType = append(fd.MessageType, r.asMessageDescriptor(decl, syntax, handler, 1))\n\t\tcase *ast.OptionNode:\n\t\t\tif fd.Options == nil {\n\t\t\t\tfd.Options = &descriptorpb.FileOptions{}\n\t\t\t}\n\t\t\tfd.Options.UninterpretedOption = append(fd.Options.UninterpretedOption, r.asUninterpretedOption(decl))\n\t\tcase *ast.ServiceNode:\n\t\t\tfd.Service = append(fd.Service, r.asServiceDescriptor(decl))\n\t\tcase *ast.PackageNode:\n\t\t\tif fd.Package != nil {\n\t\t\t\tnodeInfo := file.NodeInfo(decl)\n\t\t\t\tif handler.HandleErrorf(nodeInfo, \"files should have only one package declaration\") != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tpkgName := string(decl.Name.AsIdentifier())\n\t\t\tif len(pkgName) >= 512 {\n\t\t\t\tnodeInfo := file.NodeInfo(decl.Name)\n\t\t\t\tif handler.HandleErrorf(nodeInfo, \"package name (with whitespace removed) must be less than 512 characters long\") != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tif strings.Count(pkgName, \".\") > 100 {\n\t\t\t\tnodeInfo := file.NodeInfo(decl.Name)\n\t\t\t\tif handler.HandleErrorf(nodeInfo, \"package name may not contain more than 100 periods\") != nil {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tfd.Package = proto.String(string(decl.Name.AsIdentifier()))\n\t\t}\n\t}\n}\n\nfunc (r *result) asUninterpretedOptions(nodes []*ast.OptionNode) []*descriptorpb.UninterpretedOption {\n\tif len(nodes) == 0 {\n\t\treturn nil\n\t}\n\topts := make([]*descriptorpb.UninterpretedOption, len(nodes))\n\tfor i, n := range nodes {\n\t\topts[i] = r.asUninterpretedOption(n)\n\t}\n\treturn opts\n}\n\nfunc (r *result) asUninterpretedOption(node *ast.OptionNode) *descriptorpb.UninterpretedOption {\n\topt := &descriptorpb.UninterpretedOption{Name: r.asUninterpretedOptionName(node.Name.Parts)}\n\tr.putOptionNode(opt, node)\n\n\tswitch val := node.Val.Value().(type) {\n\tcase bool:\n\t\tif val {\n\t\t\topt.IdentifierValue = proto.String(\"true\")\n\t\t} else {\n\t\t\topt.IdentifierValue = proto.String(\"false\")\n\t\t}\n\tcase int64:\n\t\topt.NegativeIntValue = proto.Int64(val)\n\tcase uint64:\n\t\topt.PositiveIntValue = proto.Uint64(val)\n\tcase float64:\n\t\topt.DoubleValue = proto.Float64(val)\n\tcase string:\n\t\topt.StringValue = []byte(val)\n\tcase ast.Identifier:\n\t\topt.IdentifierValue = proto.String(string(val))\n\tdefault:\n\t\t// the grammar does not allow arrays here, so the only possible case\n\t\t// left should be []*ast.MessageFieldNode, which corresponds to an\n\t\t// *ast.MessageLiteralNode\n\t\tif n, ok := node.Val.(*ast.MessageLiteralNode); ok {\n\t\t\tvar buf bytes.Buffer\n\t\t\tfor i, el := range n.Elements {\n\t\t\t\tflattenNode(r.file, el, &buf)\n\t\t\t\tif len(n.Seps) > i && n.Seps[i] != nil {\n\t\t\t\t\tbuf.WriteRune(' ')\n\t\t\t\t\tbuf.WriteRune(n.Seps[i].Rune)\n\t\t\t\t}\n\t\t\t}\n\t\t\taggStr := buf.String()\n\t\t\topt.AggregateValue = proto.String(aggStr)\n\t\t}\n\t\t// TODO: else that reports an error or panics??\n\t}\n\treturn opt\n}\n\nfunc flattenNode(f *ast.FileNode, n ast.Node, buf *bytes.Buffer) {\n\tif cn, ok := n.(ast.CompositeNode); ok {\n\t\tfor _, ch := range cn.Children() {\n\t\t\tflattenNode(f, ch, buf)\n\t\t}\n\t\treturn\n\t}\n\n\tif buf.Len() > 0 {\n\t\tbuf.WriteRune(' ')\n\t}\n\tbuf.WriteString(f.NodeInfo(n).RawText())\n}\n\nfunc (r *result) asUninterpretedOptionName(parts []*ast.FieldReferenceNode) []*descriptorpb.UninterpretedOption_NamePart {\n\tret := make([]*descriptorpb.UninterpretedOption_NamePart, len(parts))\n\tfor i, part := range parts {\n\t\tnp := &descriptorpb.UninterpretedOption_NamePart{\n\t\t\tNamePart:    proto.String(string(part.Name.AsIdentifier())),\n\t\t\tIsExtension: proto.Bool(part.IsExtension()),\n\t\t}\n\t\tr.putOptionNamePartNode(np, part)\n\t\tret[i] = np\n\t}\n\treturn ret\n}\n\nfunc (r *result) addExtensions(ext *ast.ExtendNode, flds *[]*descriptorpb.FieldDescriptorProto, msgs *[]*descriptorpb.DescriptorProto, syntax protoreflect.Syntax, handler *reporter.Handler, depth int) {\n\textendee := string(ext.Extendee.AsIdentifier())\n\tcount := 0\n\tfor _, decl := range ext.Decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *ast.FieldNode:\n\t\t\tcount++\n\t\t\t// use higher limit since we don't know yet whether extendee is messageset wire format\n\t\t\tfd := r.asFieldDescriptor(decl, internal.MaxTag, syntax, handler)\n\t\t\tfd.Extendee = proto.String(extendee)\n\t\t\t*flds = append(*flds, fd)\n\t\tcase *ast.GroupNode:\n\t\t\tcount++\n\t\t\t// ditto: use higher limit right now\n\t\t\tfd, md := r.asGroupDescriptors(decl, syntax, internal.MaxTag, handler, depth+1)\n\t\t\tfd.Extendee = proto.String(extendee)\n\t\t\t*flds = append(*flds, fd)\n\t\t\t*msgs = append(*msgs, md)\n\t\t}\n\t}\n\tif count == 0 {\n\t\tnodeInfo := r.file.NodeInfo(ext)\n\t\t_ = handler.HandleErrorf(nodeInfo, \"extend sections must define at least one extension\")\n\t}\n}\n\nfunc asLabel(lbl *ast.FieldLabel) *descriptorpb.FieldDescriptorProto_Label {\n\tif !lbl.IsPresent() {\n\t\treturn nil\n\t}\n\tswitch {\n\tcase lbl.Repeated:\n\t\treturn descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum()\n\tcase lbl.Required:\n\t\treturn descriptorpb.FieldDescriptorProto_LABEL_REQUIRED.Enum()\n\tdefault:\n\t\treturn descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()\n\t}\n}\n\nfunc (r *result) asFieldDescriptor(node *ast.FieldNode, maxTag int32, syntax protoreflect.Syntax, handler *reporter.Handler) *descriptorpb.FieldDescriptorProto {\n\tvar tag *int32\n\tif node.Tag != nil {\n\t\tif err := r.checkTag(node.Tag, node.Tag.Val, maxTag); err != nil {\n\t\t\t_ = handler.HandleError(err)\n\t\t}\n\t\ttag = proto.Int32(int32(node.Tag.Val))\n\t}\n\tfd := newFieldDescriptor(node.Name.Val, string(node.FldType.AsIdentifier()), tag, asLabel(&node.Label))\n\tr.putFieldNode(fd, node)\n\tif opts := node.Options.GetElements(); len(opts) > 0 {\n\t\tfd.Options = &descriptorpb.FieldOptions{UninterpretedOption: r.asUninterpretedOptions(opts)}\n\t}\n\tif syntax == protoreflect.Proto3 && fd.Label != nil && fd.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL {\n\t\tfd.Proto3Optional = proto.Bool(true)\n\t}\n\treturn fd\n}\n\nvar fieldTypes = map[string]descriptorpb.FieldDescriptorProto_Type{\n\t\"double\":   descriptorpb.FieldDescriptorProto_TYPE_DOUBLE,\n\t\"float\":    descriptorpb.FieldDescriptorProto_TYPE_FLOAT,\n\t\"int32\":    descriptorpb.FieldDescriptorProto_TYPE_INT32,\n\t\"int64\":    descriptorpb.FieldDescriptorProto_TYPE_INT64,\n\t\"uint32\":   descriptorpb.FieldDescriptorProto_TYPE_UINT32,\n\t\"uint64\":   descriptorpb.FieldDescriptorProto_TYPE_UINT64,\n\t\"sint32\":   descriptorpb.FieldDescriptorProto_TYPE_SINT32,\n\t\"sint64\":   descriptorpb.FieldDescriptorProto_TYPE_SINT64,\n\t\"fixed32\":  descriptorpb.FieldDescriptorProto_TYPE_FIXED32,\n\t\"fixed64\":  descriptorpb.FieldDescriptorProto_TYPE_FIXED64,\n\t\"sfixed32\": descriptorpb.FieldDescriptorProto_TYPE_SFIXED32,\n\t\"sfixed64\": descriptorpb.FieldDescriptorProto_TYPE_SFIXED64,\n\t\"bool\":     descriptorpb.FieldDescriptorProto_TYPE_BOOL,\n\t\"string\":   descriptorpb.FieldDescriptorProto_TYPE_STRING,\n\t\"bytes\":    descriptorpb.FieldDescriptorProto_TYPE_BYTES,\n}\n\nfunc newFieldDescriptor(name string, fieldType string, tag *int32, lbl *descriptorpb.FieldDescriptorProto_Label) *descriptorpb.FieldDescriptorProto {\n\tfd := &descriptorpb.FieldDescriptorProto{\n\t\tName:     proto.String(name),\n\t\tJsonName: proto.String(internal.JSONName(name)),\n\t\tNumber:   tag,\n\t\tLabel:    lbl,\n\t}\n\tt, ok := fieldTypes[fieldType]\n\tif ok {\n\t\tfd.Type = t.Enum()\n\t} else {\n\t\t// NB: we don't have enough info to determine whether this is an enum\n\t\t// or a message type, so we'll leave Type nil and set it later\n\t\t// (during linking)\n\t\tfd.TypeName = proto.String(fieldType)\n\t}\n\treturn fd\n}\n\nfunc (r *result) asGroupDescriptors(group *ast.GroupNode, syntax protoreflect.Syntax, maxTag int32, handler *reporter.Handler, depth int) (*descriptorpb.FieldDescriptorProto, *descriptorpb.DescriptorProto) {\n\tvar tag *int32\n\tif group.Tag != nil {\n\t\tif err := r.checkTag(group.Tag, group.Tag.Val, maxTag); err != nil {\n\t\t\t_ = handler.HandleError(err)\n\t\t}\n\t\ttag = proto.Int32(int32(group.Tag.Val))\n\t}\n\tif !unicode.IsUpper(rune(group.Name.Val[0])) {\n\t\tnameNodeInfo := r.file.NodeInfo(group.Name)\n\t\t_ = handler.HandleErrorf(nameNodeInfo, \"group %s should have a name that starts with a capital letter\", group.Name.Val)\n\t}\n\tfieldName := strings.ToLower(group.Name.Val)\n\tfd := &descriptorpb.FieldDescriptorProto{\n\t\tName:     proto.String(fieldName),\n\t\tJsonName: proto.String(internal.JSONName(fieldName)),\n\t\tNumber:   tag,\n\t\tLabel:    asLabel(&group.Label),\n\t\tType:     descriptorpb.FieldDescriptorProto_TYPE_GROUP.Enum(),\n\t\tTypeName: proto.String(group.Name.Val),\n\t}\n\tr.putFieldNode(fd, group)\n\tif opts := group.Options.GetElements(); len(opts) > 0 {\n\t\tfd.Options = &descriptorpb.FieldOptions{UninterpretedOption: r.asUninterpretedOptions(opts)}\n\t}\n\tmd := &descriptorpb.DescriptorProto{Name: proto.String(group.Name.Val)}\n\tgroupMsg := group.AsMessage()\n\tr.putMessageNode(md, groupMsg)\n\t// don't bother processing body if we've exceeded depth\n\tif r.checkDepth(depth, groupMsg, handler) {\n\t\tr.addMessageBody(md, &group.MessageBody, syntax, handler, depth)\n\t}\n\treturn fd, md\n}\n\nfunc (r *result) asMapDescriptors(mapField *ast.MapFieldNode, syntax protoreflect.Syntax, maxTag int32, handler *reporter.Handler, depth int) (*descriptorpb.FieldDescriptorProto, *descriptorpb.DescriptorProto) {\n\tvar tag *int32\n\tif mapField.Tag != nil {\n\t\tif err := r.checkTag(mapField.Tag, mapField.Tag.Val, maxTag); err != nil {\n\t\t\t_ = handler.HandleError(err)\n\t\t}\n\t\ttag = proto.Int32(int32(mapField.Tag.Val))\n\t}\n\tmapEntry := mapField.AsMessage()\n\tr.checkDepth(depth, mapEntry, handler)\n\tvar lbl *descriptorpb.FieldDescriptorProto_Label\n\tif syntax == protoreflect.Proto2 {\n\t\tlbl = descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()\n\t}\n\tkeyFd := newFieldDescriptor(\"key\", mapField.MapType.KeyType.Val, proto.Int32(1), lbl)\n\tr.putFieldNode(keyFd, mapField.KeyField())\n\tvalFd := newFieldDescriptor(\"value\", string(mapField.MapType.ValueType.AsIdentifier()), proto.Int32(2), lbl)\n\tr.putFieldNode(valFd, mapField.ValueField())\n\tentryName := internal.InitCap(internal.JSONName(mapField.Name.Val)) + \"Entry\"\n\tfd := newFieldDescriptor(mapField.Name.Val, entryName, tag, descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum())\n\tif opts := mapField.Options.GetElements(); len(opts) > 0 {\n\t\tfd.Options = &descriptorpb.FieldOptions{UninterpretedOption: r.asUninterpretedOptions(opts)}\n\t}\n\tr.putFieldNode(fd, mapField)\n\tmd := &descriptorpb.DescriptorProto{\n\t\tName:    proto.String(entryName),\n\t\tOptions: &descriptorpb.MessageOptions{MapEntry: proto.Bool(true)},\n\t\tField:   []*descriptorpb.FieldDescriptorProto{keyFd, valFd},\n\t}\n\tr.putMessageNode(md, mapEntry)\n\treturn fd, md\n}\n\nfunc (r *result) asExtensionRanges(node *ast.ExtensionRangeNode, maxTag int32, handler *reporter.Handler) []*descriptorpb.DescriptorProto_ExtensionRange {\n\topts := r.asUninterpretedOptions(node.Options.GetElements())\n\ters := make([]*descriptorpb.DescriptorProto_ExtensionRange, len(node.Ranges))\n\tfor i, rng := range node.Ranges {\n\t\tstart, end := r.getRangeBounds(rng, 1, maxTag, handler)\n\t\ter := &descriptorpb.DescriptorProto_ExtensionRange{\n\t\t\tStart: proto.Int32(start),\n\t\t\tEnd:   proto.Int32(end + 1),\n\t\t}\n\t\tif len(opts) > 0 {\n\t\t\ter.Options = &descriptorpb.ExtensionRangeOptions{UninterpretedOption: opts}\n\t\t}\n\t\tr.putExtensionRangeNode(er, node, rng)\n\t\ters[i] = er\n\t}\n\treturn ers\n}\n\nfunc (r *result) asEnumValue(ev *ast.EnumValueNode, handler *reporter.Handler) *descriptorpb.EnumValueDescriptorProto {\n\tnum, ok := ast.AsInt32(ev.Number, math.MinInt32, math.MaxInt32)\n\tif !ok {\n\t\tnumberNodeInfo := r.file.NodeInfo(ev.Number)\n\t\t_ = handler.HandleErrorf(numberNodeInfo, \"value %d is out of range: should be between %d and %d\", ev.Number.Value(), math.MinInt32, math.MaxInt32)\n\t}\n\tevd := &descriptorpb.EnumValueDescriptorProto{Name: proto.String(ev.Name.Val), Number: proto.Int32(num)}\n\tr.putEnumValueNode(evd, ev)\n\tif opts := ev.Options.GetElements(); len(opts) > 0 {\n\t\tevd.Options = &descriptorpb.EnumValueOptions{UninterpretedOption: r.asUninterpretedOptions(opts)}\n\t}\n\treturn evd\n}\n\nfunc (r *result) asMethodDescriptor(node *ast.RPCNode) *descriptorpb.MethodDescriptorProto {\n\tmd := &descriptorpb.MethodDescriptorProto{\n\t\tName:       proto.String(node.Name.Val),\n\t\tInputType:  proto.String(string(node.Input.MessageType.AsIdentifier())),\n\t\tOutputType: proto.String(string(node.Output.MessageType.AsIdentifier())),\n\t}\n\tr.putMethodNode(md, node)\n\tif node.Input.Stream != nil {\n\t\tmd.ClientStreaming = proto.Bool(true)\n\t}\n\tif node.Output.Stream != nil {\n\t\tmd.ServerStreaming = proto.Bool(true)\n\t}\n\t// protoc always adds a MethodOptions if there are brackets\n\t// We do the same to match protoc as closely as possible\n\t// https://github.com/protocolbuffers/protobuf/blob/0c3f43a6190b77f1f68b7425d1b7e1a8257a8d0c/src/google/protobuf/compiler/parser.cc#L2152\n\tif node.OpenBrace != nil {\n\t\tmd.Options = &descriptorpb.MethodOptions{}\n\t\tfor _, decl := range node.Decls {\n\t\t\tif option, ok := decl.(*ast.OptionNode); ok {\n\t\t\t\tmd.Options.UninterpretedOption = append(md.Options.UninterpretedOption, r.asUninterpretedOption(option))\n\t\t\t}\n\t\t}\n\t}\n\treturn md\n}\n\nfunc (r *result) asEnumDescriptor(en *ast.EnumNode, syntax protoreflect.Syntax, handler *reporter.Handler) *descriptorpb.EnumDescriptorProto {\n\ted := &descriptorpb.EnumDescriptorProto{Name: proto.String(en.Name.Val)}\n\tr.putEnumNode(ed, en)\n\trsvdNames := map[string]ast.SourcePos{}\n\tfor _, decl := range en.Decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *ast.OptionNode:\n\t\t\tif ed.Options == nil {\n\t\t\t\ted.Options = &descriptorpb.EnumOptions{}\n\t\t\t}\n\t\t\ted.Options.UninterpretedOption = append(ed.Options.UninterpretedOption, r.asUninterpretedOption(decl))\n\t\tcase *ast.EnumValueNode:\n\t\t\ted.Value = append(ed.Value, r.asEnumValue(decl, handler))\n\t\tcase *ast.ReservedNode:\n\t\t\tr.addReservedNames(&ed.ReservedName, decl, syntax, handler, rsvdNames)\n\t\t\tfor _, rng := range decl.Ranges {\n\t\t\t\ted.ReservedRange = append(ed.ReservedRange, r.asEnumReservedRange(rng, handler))\n\t\t\t}\n\t\t}\n\t}\n\treturn ed\n}\n\nfunc (r *result) asEnumReservedRange(rng *ast.RangeNode, handler *reporter.Handler) *descriptorpb.EnumDescriptorProto_EnumReservedRange {\n\tstart, end := r.getRangeBounds(rng, math.MinInt32, math.MaxInt32, handler)\n\trr := &descriptorpb.EnumDescriptorProto_EnumReservedRange{\n\t\tStart: proto.Int32(start),\n\t\tEnd:   proto.Int32(end),\n\t}\n\tr.putEnumReservedRangeNode(rr, rng)\n\treturn rr\n}\n\nfunc (r *result) asMessageDescriptor(node *ast.MessageNode, syntax protoreflect.Syntax, handler *reporter.Handler, depth int) *descriptorpb.DescriptorProto {\n\tmsgd := &descriptorpb.DescriptorProto{Name: proto.String(node.Name.Val)}\n\tr.putMessageNode(msgd, node)\n\t// don't bother processing body if we've exceeded depth\n\tif r.checkDepth(depth, node, handler) {\n\t\tr.addMessageBody(msgd, &node.MessageBody, syntax, handler, depth)\n\t}\n\treturn msgd\n}\n\nfunc (r *result) addReservedNames(names *[]string, node *ast.ReservedNode, syntax protoreflect.Syntax, handler *reporter.Handler, alreadyReserved map[string]ast.SourcePos) {\n\tif syntax == protoreflect.Editions {\n\t\tif len(node.Names) > 0 {\n\t\t\tnameNodeInfo := r.file.NodeInfo(node.Names[0])\n\t\t\t_ = handler.HandleErrorf(nameNodeInfo, `must use identifiers, not string literals, to reserved names with editions`)\n\t\t}\n\t\tfor _, n := range node.Identifiers {\n\t\t\tname := string(n.AsIdentifier())\n\t\t\tnameNodeInfo := r.file.NodeInfo(n)\n\t\t\tif existing, ok := alreadyReserved[name]; ok {\n\t\t\t\t_ = handler.HandleErrorf(nameNodeInfo, \"name %q is already reserved at %s\", name, existing)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\talreadyReserved[name] = nameNodeInfo.Start()\n\t\t\t*names = append(*names, name)\n\t\t}\n\t\treturn\n\t}\n\n\tif len(node.Identifiers) > 0 {\n\t\tnameNodeInfo := r.file.NodeInfo(node.Identifiers[0])\n\t\t_ = handler.HandleErrorf(nameNodeInfo, `must use string literals, not identifiers, to reserved names with proto2 and proto3`)\n\t}\n\tfor _, n := range node.Names {\n\t\tname := n.AsString()\n\t\tnameNodeInfo := r.file.NodeInfo(n)\n\t\tif existing, ok := alreadyReserved[name]; ok {\n\t\t\t_ = handler.HandleErrorf(nameNodeInfo, \"name %q is already reserved at %s\", name, existing)\n\t\t\tcontinue\n\t\t}\n\t\talreadyReserved[name] = nameNodeInfo.Start()\n\t\t*names = append(*names, name)\n\t}\n}\n\nfunc (r *result) checkDepth(depth int, node ast.MessageDeclNode, handler *reporter.Handler) bool {\n\tif depth < 32 {\n\t\treturn true\n\t}\n\tn := ast.Node(node)\n\tif grp, ok := n.(*ast.SyntheticGroupMessageNode); ok {\n\t\t// pinpoint the group keyword if the source is a group\n\t\tn = grp.Keyword\n\t}\n\t_ = handler.HandleErrorf(r.file.NodeInfo(n), \"message nesting depth must be less than 32\")\n\treturn false\n}\n\nfunc (r *result) addMessageBody(msgd *descriptorpb.DescriptorProto, body *ast.MessageBody, syntax protoreflect.Syntax, handler *reporter.Handler, depth int) {\n\t// first process any options\n\tfor _, decl := range body.Decls {\n\t\tif opt, ok := decl.(*ast.OptionNode); ok {\n\t\t\tif msgd.Options == nil {\n\t\t\t\tmsgd.Options = &descriptorpb.MessageOptions{}\n\t\t\t}\n\t\t\tmsgd.Options.UninterpretedOption = append(msgd.Options.UninterpretedOption, r.asUninterpretedOption(opt))\n\t\t}\n\t}\n\n\t// now that we have options, we can see if this uses messageset wire format, which\n\t// impacts how we validate tag numbers in any fields in the message\n\tmaxTag := int32(internal.MaxNormalTag)\n\tmessageSetOpt, err := r.isMessageSetWireFormat(\"message \"+msgd.GetName(), msgd, handler)\n\tif err != nil {\n\t\treturn\n\t} else if messageSetOpt != nil {\n\t\tif syntax == protoreflect.Proto3 {\n\t\t\tnode := r.OptionNode(messageSetOpt)\n\t\t\tnodeInfo := r.file.NodeInfo(node)\n\t\t\t_ = handler.HandleErrorf(nodeInfo, \"messages with message-set wire format are not allowed with proto3 syntax\")\n\t\t}\n\t\tmaxTag = internal.MaxTag // higher limit for messageset wire format\n\t}\n\n\trsvdNames := map[string]ast.SourcePos{}\n\n\t// now we can process the rest\n\tfor _, decl := range body.Decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *ast.EnumNode:\n\t\t\tmsgd.EnumType = append(msgd.EnumType, r.asEnumDescriptor(decl, syntax, handler))\n\t\tcase *ast.ExtendNode:\n\t\t\tr.addExtensions(decl, &msgd.Extension, &msgd.NestedType, syntax, handler, depth)\n\t\tcase *ast.ExtensionRangeNode:\n\t\t\tmsgd.ExtensionRange = append(msgd.ExtensionRange, r.asExtensionRanges(decl, maxTag, handler)...)\n\t\tcase *ast.FieldNode:\n\t\t\tfd := r.asFieldDescriptor(decl, maxTag, syntax, handler)\n\t\t\tmsgd.Field = append(msgd.Field, fd)\n\t\tcase *ast.MapFieldNode:\n\t\t\tfd, md := r.asMapDescriptors(decl, syntax, maxTag, handler, depth+1)\n\t\t\tmsgd.Field = append(msgd.Field, fd)\n\t\t\tmsgd.NestedType = append(msgd.NestedType, md)\n\t\tcase *ast.GroupNode:\n\t\t\tfd, md := r.asGroupDescriptors(decl, syntax, maxTag, handler, depth+1)\n\t\t\tmsgd.Field = append(msgd.Field, fd)\n\t\t\tmsgd.NestedType = append(msgd.NestedType, md)\n\t\tcase *ast.OneofNode:\n\t\t\toodIndex := len(msgd.OneofDecl)\n\t\t\tood := &descriptorpb.OneofDescriptorProto{Name: proto.String(decl.Name.Val)}\n\t\t\tr.putOneofNode(ood, decl)\n\t\t\tmsgd.OneofDecl = append(msgd.OneofDecl, ood)\n\t\t\tooFields := 0\n\t\t\tfor _, oodecl := range decl.Decls {\n\t\t\t\tswitch oodecl := oodecl.(type) {\n\t\t\t\tcase *ast.OptionNode:\n\t\t\t\t\tif ood.Options == nil {\n\t\t\t\t\t\tood.Options = &descriptorpb.OneofOptions{}\n\t\t\t\t\t}\n\t\t\t\t\tood.Options.UninterpretedOption = append(ood.Options.UninterpretedOption, r.asUninterpretedOption(oodecl))\n\t\t\t\tcase *ast.FieldNode:\n\t\t\t\t\tfd := r.asFieldDescriptor(oodecl, maxTag, syntax, handler)\n\t\t\t\t\tfd.OneofIndex = proto.Int32(int32(oodIndex))\n\t\t\t\t\tmsgd.Field = append(msgd.Field, fd)\n\t\t\t\t\tooFields++\n\t\t\t\tcase *ast.GroupNode:\n\t\t\t\t\tfd, md := r.asGroupDescriptors(oodecl, syntax, maxTag, handler, depth+1)\n\t\t\t\t\tfd.OneofIndex = proto.Int32(int32(oodIndex))\n\t\t\t\t\tmsgd.Field = append(msgd.Field, fd)\n\t\t\t\t\tmsgd.NestedType = append(msgd.NestedType, md)\n\t\t\t\t\tooFields++\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ooFields == 0 {\n\t\t\t\tdeclNodeInfo := r.file.NodeInfo(decl)\n\t\t\t\t_ = handler.HandleErrorf(declNodeInfo, \"oneof must contain at least one field\")\n\t\t\t}\n\t\tcase *ast.MessageNode:\n\t\t\tmsgd.NestedType = append(msgd.NestedType, r.asMessageDescriptor(decl, syntax, handler, depth+1))\n\t\tcase *ast.ReservedNode:\n\t\t\tr.addReservedNames(&msgd.ReservedName, decl, syntax, handler, rsvdNames)\n\t\t\tfor _, rng := range decl.Ranges {\n\t\t\t\tmsgd.ReservedRange = append(msgd.ReservedRange, r.asMessageReservedRange(rng, maxTag, handler))\n\t\t\t}\n\t\t}\n\t}\n\n\tif messageSetOpt != nil {\n\t\tif len(msgd.Field) > 0 {\n\t\t\tnode := r.FieldNode(msgd.Field[0])\n\t\t\tnodeInfo := r.file.NodeInfo(node)\n\t\t\t_ = handler.HandleErrorf(nodeInfo, \"messages with message-set wire format cannot contain non-extension fields\")\n\t\t}\n\t\tif len(msgd.ExtensionRange) == 0 {\n\t\t\tnode := r.OptionNode(messageSetOpt)\n\t\t\tnodeInfo := r.file.NodeInfo(node)\n\t\t\t_ = handler.HandleErrorf(nodeInfo, \"messages with message-set wire format must contain at least one extension range\")\n\t\t}\n\t}\n\n\t// process any proto3_optional fields\n\tif syntax == protoreflect.Proto3 {\n\t\tr.processProto3OptionalFields(msgd)\n\t}\n}\n\nfunc (r *result) isMessageSetWireFormat(scope string, md *descriptorpb.DescriptorProto, handler *reporter.Handler) (*descriptorpb.UninterpretedOption, error) {\n\tuo := md.GetOptions().GetUninterpretedOption()\n\tindex, err := internal.FindOption(r, handler.HandleErrorf, scope, uo, \"message_set_wire_format\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif index == -1 {\n\t\t// no such option\n\t\treturn nil, nil\n\t}\n\n\topt := uo[index]\n\n\tswitch opt.GetIdentifierValue() {\n\tcase \"true\":\n\t\treturn opt, nil\n\tcase \"false\":\n\t\treturn nil, nil\n\tdefault:\n\t\toptNode := r.OptionNode(opt)\n\t\toptNodeInfo := r.file.NodeInfo(optNode.GetValue())\n\t\treturn nil, handler.HandleErrorf(optNodeInfo, \"%s: expecting bool value for message_set_wire_format option\", scope)\n\t}\n}\n\nfunc (r *result) asMessageReservedRange(rng *ast.RangeNode, maxTag int32, handler *reporter.Handler) *descriptorpb.DescriptorProto_ReservedRange {\n\tstart, end := r.getRangeBounds(rng, 1, maxTag, handler)\n\trr := &descriptorpb.DescriptorProto_ReservedRange{\n\t\tStart: proto.Int32(start),\n\t\tEnd:   proto.Int32(end + 1),\n\t}\n\tr.putMessageReservedRangeNode(rr, rng)\n\treturn rr\n}\n\nfunc (r *result) getRangeBounds(rng *ast.RangeNode, minVal, maxVal int32, handler *reporter.Handler) (int32, int32) {\n\tcheckOrder := true\n\tstart, ok := rng.StartValueAsInt32(minVal, maxVal)\n\tif !ok {\n\t\tcheckOrder = false\n\t\tstartValNodeInfo := r.file.NodeInfo(rng.StartVal)\n\t\t_ = handler.HandleErrorf(startValNodeInfo, \"range start %d is out of range: should be between %d and %d\", rng.StartValue(), minVal, maxVal)\n\t}\n\n\tend, ok := rng.EndValueAsInt32(minVal, maxVal)\n\tif !ok {\n\t\tcheckOrder = false\n\t\tif rng.EndVal != nil {\n\t\t\tendValNodeInfo := r.file.NodeInfo(rng.EndVal)\n\t\t\t_ = handler.HandleErrorf(endValNodeInfo, \"range end %d is out of range: should be between %d and %d\", rng.EndValue(), minVal, maxVal)\n\t\t}\n\t}\n\n\tif checkOrder && start > end {\n\t\trangeStartNodeInfo := r.file.NodeInfo(rng.RangeStart())\n\t\t_ = handler.HandleErrorf(rangeStartNodeInfo, \"range, %d to %d, is invalid: start must be <= end\", start, end)\n\t}\n\n\treturn start, end\n}\n\nfunc (r *result) asServiceDescriptor(svc *ast.ServiceNode) *descriptorpb.ServiceDescriptorProto {\n\tsd := &descriptorpb.ServiceDescriptorProto{Name: proto.String(svc.Name.Val)}\n\tr.putServiceNode(sd, svc)\n\tfor _, decl := range svc.Decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *ast.OptionNode:\n\t\t\tif sd.Options == nil {\n\t\t\t\tsd.Options = &descriptorpb.ServiceOptions{}\n\t\t\t}\n\t\t\tsd.Options.UninterpretedOption = append(sd.Options.UninterpretedOption, r.asUninterpretedOption(decl))\n\t\tcase *ast.RPCNode:\n\t\t\tsd.Method = append(sd.Method, r.asMethodDescriptor(decl))\n\t\t}\n\t}\n\treturn sd\n}\n\nfunc (r *result) checkTag(n ast.Node, v uint64, maxTag int32) error {\n\tswitch {\n\tcase v < 1:\n\t\treturn reporter.Errorf(r.file.NodeInfo(n), \"tag number %d must be greater than zero\", v)\n\tcase v > uint64(maxTag):\n\t\treturn reporter.Errorf(r.file.NodeInfo(n), \"tag number %d is higher than max allowed tag number (%d)\", v, maxTag)\n\tcase v >= internal.SpecialReservedStart && v <= internal.SpecialReservedEnd:\n\t\treturn reporter.Errorf(r.file.NodeInfo(n), \"tag number %d is in disallowed reserved range %d-%d\", v, internal.SpecialReservedStart, internal.SpecialReservedEnd)\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// processProto3OptionalFields adds synthetic oneofs to the given message descriptor\n// for each proto3 optional field. It also updates the fields to have the correct\n// oneof index reference.\nfunc (r *result) processProto3OptionalFields(msgd *descriptorpb.DescriptorProto) {\n\t// add synthetic oneofs to the given message descriptor for each proto3\n\t// optional field, and update each field to have correct oneof index\n\tvar allNames map[string]struct{}\n\tfor _, fd := range msgd.Field {\n\t\tif fd.GetProto3Optional() {\n\t\t\t// lazy init the set of all names\n\t\t\tif allNames == nil {\n\t\t\t\tallNames = map[string]struct{}{}\n\t\t\t\tfor _, fd := range msgd.Field {\n\t\t\t\t\tallNames[fd.GetName()] = struct{}{}\n\t\t\t\t}\n\t\t\t\tfor _, od := range msgd.OneofDecl {\n\t\t\t\t\tallNames[od.GetName()] = struct{}{}\n\t\t\t\t}\n\t\t\t\t// NB: protoc only considers names of other fields and oneofs\n\t\t\t\t// when computing the synthetic oneof name. But that feels like\n\t\t\t\t// a bug, since it means it could generate a name that conflicts\n\t\t\t\t// with some other symbol defined in the message. If it's decided\n\t\t\t\t// that's NOT a bug and is desirable, then we should remove the\n\t\t\t\t// following four loops to mimic protoc's behavior.\n\t\t\t\tfor _, fd := range msgd.Extension {\n\t\t\t\t\tallNames[fd.GetName()] = struct{}{}\n\t\t\t\t}\n\t\t\t\tfor _, ed := range msgd.EnumType {\n\t\t\t\t\tallNames[ed.GetName()] = struct{}{}\n\t\t\t\t\tfor _, evd := range ed.Value {\n\t\t\t\t\t\tallNames[evd.GetName()] = struct{}{}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor _, fd := range msgd.NestedType {\n\t\t\t\t\tallNames[fd.GetName()] = struct{}{}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Compute a name for the synthetic oneof. This uses the same\n\t\t\t// algorithm as used in protoc:\n\t\t\t//  https://github.com/protocolbuffers/protobuf/blob/74ad62759e0a9b5a21094f3fb9bb4ebfaa0d1ab8/src/google/protobuf/compiler/parser.cc#L785-L803\n\t\t\tooName := fd.GetName()\n\t\t\tif !strings.HasPrefix(ooName, \"_\") {\n\t\t\t\tooName = \"_\" + ooName\n\t\t\t}\n\t\t\tfor {\n\t\t\t\t_, ok := allNames[ooName]\n\t\t\t\tif !ok {\n\t\t\t\t\t// found a unique name\n\t\t\t\t\tallNames[ooName] = struct{}{}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tooName = \"X\" + ooName\n\t\t\t}\n\n\t\t\tfd.OneofIndex = proto.Int32(int32(len(msgd.OneofDecl)))\n\t\t\tood := &descriptorpb.OneofDescriptorProto{Name: proto.String(ooName)}\n\t\t\tmsgd.OneofDecl = append(msgd.OneofDecl, ood)\n\t\t\tooident := r.FieldNode(fd).(*ast.FieldNode) //nolint:errcheck\n\t\t\tr.putOneofNode(ood, ast.NewSyntheticOneof(ooident))\n\t\t}\n\t}\n}\n\nfunc (r *result) Node(m proto.Message) ast.Node {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[m]\n}\n\nfunc (r *result) FileNode() ast.FileDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[r.proto].(ast.FileDeclNode)\n}\n\nfunc (r *result) OptionNode(o *descriptorpb.UninterpretedOption) ast.OptionDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[o].(ast.OptionDeclNode)\n}\n\nfunc (r *result) OptionNamePartNode(o *descriptorpb.UninterpretedOption_NamePart) ast.Node {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[o]\n}\n\nfunc (r *result) MessageNode(m *descriptorpb.DescriptorProto) ast.MessageDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[m].(ast.MessageDeclNode)\n}\n\nfunc (r *result) FieldNode(f *descriptorpb.FieldDescriptorProto) ast.FieldDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[f].(ast.FieldDeclNode)\n}\n\nfunc (r *result) OneofNode(o *descriptorpb.OneofDescriptorProto) ast.OneofDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[o].(ast.OneofDeclNode)\n}\n\nfunc (r *result) ExtensionsNode(e *descriptorpb.DescriptorProto_ExtensionRange) ast.NodeWithOptions {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[asExtsNode(e)].(ast.NodeWithOptions)\n}\n\nfunc (r *result) ExtensionRangeNode(e *descriptorpb.DescriptorProto_ExtensionRange) ast.RangeDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[e].(ast.RangeDeclNode)\n}\n\nfunc (r *result) MessageReservedRangeNode(rr *descriptorpb.DescriptorProto_ReservedRange) ast.RangeDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[rr].(ast.RangeDeclNode)\n}\n\nfunc (r *result) EnumNode(e *descriptorpb.EnumDescriptorProto) ast.NodeWithOptions {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[e].(ast.NodeWithOptions)\n}\n\nfunc (r *result) EnumValueNode(e *descriptorpb.EnumValueDescriptorProto) ast.EnumValueDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[e].(ast.EnumValueDeclNode)\n}\n\nfunc (r *result) EnumReservedRangeNode(rr *descriptorpb.EnumDescriptorProto_EnumReservedRange) ast.RangeDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[rr].(ast.RangeDeclNode)\n}\n\nfunc (r *result) ServiceNode(s *descriptorpb.ServiceDescriptorProto) ast.NodeWithOptions {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[s].(ast.NodeWithOptions)\n}\n\nfunc (r *result) MethodNode(m *descriptorpb.MethodDescriptorProto) ast.RPCDeclNode {\n\tif r.nodes == nil {\n\t\treturn r.ifNoAST\n\t}\n\treturn r.nodes[m].(ast.RPCDeclNode)\n}\n\nfunc (r *result) putFileNode(f *descriptorpb.FileDescriptorProto, n *ast.FileNode) {\n\tr.nodes[f] = n\n}\n\nfunc (r *result) putOptionNode(o *descriptorpb.UninterpretedOption, n *ast.OptionNode) {\n\tr.nodes[o] = n\n}\n\nfunc (r *result) putOptionNamePartNode(o *descriptorpb.UninterpretedOption_NamePart, n *ast.FieldReferenceNode) {\n\tr.nodes[o] = n\n}\n\nfunc (r *result) putMessageNode(m *descriptorpb.DescriptorProto, n ast.MessageDeclNode) {\n\tr.nodes[m] = n\n}\n\nfunc (r *result) putFieldNode(f *descriptorpb.FieldDescriptorProto, n ast.FieldDeclNode) {\n\tr.nodes[f] = n\n}\n\nfunc (r *result) putOneofNode(o *descriptorpb.OneofDescriptorProto, n ast.OneofDeclNode) {\n\tr.nodes[o] = n\n}\n\nfunc (r *result) putExtensionRangeNode(e *descriptorpb.DescriptorProto_ExtensionRange, er *ast.ExtensionRangeNode, n *ast.RangeNode) {\n\tr.nodes[asExtsNode(e)] = er\n\tr.nodes[e] = n\n}\n\nfunc (r *result) putMessageReservedRangeNode(rr *descriptorpb.DescriptorProto_ReservedRange, n *ast.RangeNode) {\n\tr.nodes[rr] = n\n}\n\nfunc (r *result) putEnumNode(e *descriptorpb.EnumDescriptorProto, n *ast.EnumNode) {\n\tr.nodes[e] = n\n}\n\nfunc (r *result) putEnumValueNode(e *descriptorpb.EnumValueDescriptorProto, n *ast.EnumValueNode) {\n\tr.nodes[e] = n\n}\n\nfunc (r *result) putEnumReservedRangeNode(rr *descriptorpb.EnumDescriptorProto_EnumReservedRange, n *ast.RangeNode) {\n\tr.nodes[rr] = n\n}\n\nfunc (r *result) putServiceNode(s *descriptorpb.ServiceDescriptorProto, n *ast.ServiceNode) {\n\tr.nodes[s] = n\n}\n\nfunc (r *result) putMethodNode(m *descriptorpb.MethodDescriptorProto, n *ast.RPCNode) {\n\tr.nodes[m] = n\n}\n\n// NB: If we ever add other put*Node methods, to index other kinds of elements in the descriptor\n//     proto hierarchy, we need to update the index recreation logic in clone.go, too.\n\nfunc asExtsNode(er *descriptorpb.DescriptorProto_ExtensionRange) proto.Message {\n\treturn extsParent{er}\n}\n\n// a simple marker type that allows us to have two distinct keys in a map for\n// the same ExtensionRange proto -- one for the range itself and another to\n// associate with the enclosing/parent AST node.\ntype extsParent struct {\n\t*descriptorpb.DescriptorProto_ExtensionRange\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/parser/validate.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage parser\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n\t\"github.com/bufbuild/protocompile/reporter\"\n\t\"github.com/bufbuild/protocompile/walk\"\n)\n\nfunc validateBasic(res *result, handler *reporter.Handler) {\n\tfd := res.proto\n\tvar syntax protoreflect.Syntax\n\tswitch fd.GetSyntax() {\n\tcase \"\", \"proto2\":\n\t\tsyntax = protoreflect.Proto2\n\tcase \"proto3\":\n\t\tsyntax = protoreflect.Proto3\n\tcase \"editions\":\n\t\tsyntax = protoreflect.Editions\n\t\t// TODO: default: error?\n\t}\n\n\tif err := validateImports(res, handler); err != nil {\n\t\treturn\n\t}\n\n\tif err := validateNoFeatures(res, syntax, \"file options\", fd.Options.GetUninterpretedOption(), handler); err != nil {\n\t\treturn\n\t}\n\n\t_ = walk.DescriptorProtos(fd,\n\t\tfunc(name protoreflect.FullName, d proto.Message) error {\n\t\t\tswitch d := d.(type) {\n\t\t\tcase *descriptorpb.DescriptorProto:\n\t\t\t\tif err := validateMessage(res, syntax, name, d, handler); err != nil {\n\t\t\t\t\t// exit func is not called when enter returns error\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase *descriptorpb.FieldDescriptorProto:\n\t\t\t\tif err := validateField(res, syntax, name, d, handler); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase *descriptorpb.OneofDescriptorProto:\n\t\t\t\tif err := validateNoFeatures(res, syntax, fmt.Sprintf(\"oneof %s\", name), d.Options.GetUninterpretedOption(), handler); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase *descriptorpb.EnumDescriptorProto:\n\t\t\t\tif err := validateEnum(res, syntax, name, d, handler); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase *descriptorpb.EnumValueDescriptorProto:\n\t\t\t\tif err := validateNoFeatures(res, syntax, fmt.Sprintf(\"enum value %s\", name), d.Options.GetUninterpretedOption(), handler); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase *descriptorpb.ServiceDescriptorProto:\n\t\t\t\tif err := validateNoFeatures(res, syntax, fmt.Sprintf(\"service %s\", name), d.Options.GetUninterpretedOption(), handler); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\tcase *descriptorpb.MethodDescriptorProto:\n\t\t\t\tif err := validateNoFeatures(res, syntax, fmt.Sprintf(\"method %s\", name), d.Options.GetUninterpretedOption(), handler); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\t\t})\n}\n\nfunc validateImports(res *result, handler *reporter.Handler) error {\n\tfileNode := res.file\n\tif fileNode == nil {\n\t\treturn nil\n\t}\n\timports := make(map[string]ast.SourcePos)\n\tfor _, decl := range fileNode.Decls {\n\t\timp, ok := decl.(*ast.ImportNode)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tinfo := fileNode.NodeInfo(decl)\n\t\tname := imp.Name.AsString()\n\t\tif prev, ok := imports[name]; ok {\n\t\t\treturn handler.HandleErrorf(info, \"%q was already imported at %v\", name, prev)\n\t\t}\n\t\timports[name] = info.Start()\n\t}\n\treturn nil\n}\n\nfunc validateNoFeatures(res *result, syntax protoreflect.Syntax, scope string, opts []*descriptorpb.UninterpretedOption, handler *reporter.Handler) error {\n\tif syntax == protoreflect.Editions {\n\t\t// Editions is allowed to use features\n\t\treturn nil\n\t}\n\tif index, err := internal.FindFirstOption(res, handler.HandleErrorf, scope, opts, \"features\"); err != nil {\n\t\treturn err\n\t} else if index >= 0 {\n\t\toptNode := res.OptionNode(opts[index])\n\t\toptNameNodeInfo := res.file.NodeInfo(optNode.GetName())\n\t\tif err := handler.HandleErrorf(optNameNodeInfo, \"%s: option 'features' may only be used with editions but file uses %s syntax\", scope, syntax); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateMessage(res *result, syntax protoreflect.Syntax, name protoreflect.FullName, md *descriptorpb.DescriptorProto, handler *reporter.Handler) error {\n\tscope := fmt.Sprintf(\"message %s\", name)\n\n\tif syntax == protoreflect.Proto3 && len(md.ExtensionRange) > 0 {\n\t\tn := res.ExtensionRangeNode(md.ExtensionRange[0])\n\t\tnInfo := res.file.NodeInfo(n)\n\t\tif err := handler.HandleErrorf(nInfo, \"%s: extension ranges are not allowed in proto3\", scope); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif index, err := internal.FindOption(res, handler.HandleErrorf, scope, md.Options.GetUninterpretedOption(), \"map_entry\"); err != nil {\n\t\treturn err\n\t} else if index >= 0 {\n\t\toptNode := res.OptionNode(md.Options.GetUninterpretedOption()[index])\n\t\toptNameNodeInfo := res.file.NodeInfo(optNode.GetName())\n\t\tif err := handler.HandleErrorf(optNameNodeInfo, \"%s: map_entry option should not be set explicitly; use map type instead\", scope); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := validateNoFeatures(res, syntax, scope, md.Options.GetUninterpretedOption(), handler); err != nil {\n\t\treturn err\n\t}\n\n\t// reserved ranges should not overlap\n\trsvd := make(tagRanges, len(md.ReservedRange))\n\tfor i, r := range md.ReservedRange {\n\t\tn := res.MessageReservedRangeNode(r)\n\t\trsvd[i] = tagRange{start: r.GetStart(), end: r.GetEnd(), node: n}\n\t}\n\tsort.Sort(rsvd)\n\tfor i := 1; i < len(rsvd); i++ {\n\t\tif rsvd[i].start < rsvd[i-1].end {\n\t\t\trangeNodeInfo := res.file.NodeInfo(rsvd[i].node)\n\t\t\tif err := handler.HandleErrorf(rangeNodeInfo, \"%s: reserved ranges overlap: %d to %d and %d to %d\", scope, rsvd[i-1].start, rsvd[i-1].end-1, rsvd[i].start, rsvd[i].end-1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// extensions ranges should not overlap\n\texts := make(tagRanges, len(md.ExtensionRange))\n\tfor i, r := range md.ExtensionRange {\n\t\tif err := validateNoFeatures(res, syntax, scope, r.Options.GetUninterpretedOption(), handler); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tn := res.ExtensionRangeNode(r)\n\t\texts[i] = tagRange{start: r.GetStart(), end: r.GetEnd(), node: n}\n\t}\n\tsort.Sort(exts)\n\tfor i := 1; i < len(exts); i++ {\n\t\tif exts[i].start < exts[i-1].end {\n\t\t\trangeNodeInfo := res.file.NodeInfo(exts[i].node)\n\t\t\tif err := handler.HandleErrorf(rangeNodeInfo, \"%s: extension ranges overlap: %d to %d and %d to %d\", scope, exts[i-1].start, exts[i-1].end-1, exts[i].start, exts[i].end-1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// see if any extension range overlaps any reserved range\n\tvar i, j int // i indexes rsvd; j indexes exts\n\tfor i < len(rsvd) && j < len(exts) {\n\t\tif rsvd[i].start >= exts[j].start && rsvd[i].start < exts[j].end ||\n\t\t\texts[j].start >= rsvd[i].start && exts[j].start < rsvd[i].end {\n\t\t\tvar span ast.SourceSpan\n\t\t\tif rsvd[i].start >= exts[j].start && rsvd[i].start < exts[j].end {\n\t\t\t\trangeNodeInfo := res.file.NodeInfo(rsvd[i].node)\n\t\t\t\tspan = rangeNodeInfo\n\t\t\t} else {\n\t\t\t\trangeNodeInfo := res.file.NodeInfo(exts[j].node)\n\t\t\t\tspan = rangeNodeInfo\n\t\t\t}\n\t\t\t// ranges overlap\n\t\t\tif err := handler.HandleErrorf(span, \"%s: extension range %d to %d overlaps reserved range %d to %d\", scope, exts[j].start, exts[j].end-1, rsvd[i].start, rsvd[i].end-1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif rsvd[i].start < exts[j].start {\n\t\t\ti++\n\t\t} else {\n\t\t\tj++\n\t\t}\n\t}\n\n\t// now, check that fields don't re-use tags and don't try to use extension\n\t// or reserved ranges or reserved names\n\trsvdNames := map[string]struct{}{}\n\tfor _, n := range md.ReservedName {\n\t\t// validate reserved name while we're here\n\t\tif !isIdentifier(n) {\n\t\t\tnode := findMessageReservedNameNode(res.MessageNode(md), n)\n\t\t\tnodeInfo := res.file.NodeInfo(node)\n\t\t\tif err := handler.HandleErrorf(nodeInfo, \"%s: reserved name %q is not a valid identifier\", scope, n); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\trsvdNames[n] = struct{}{}\n\t}\n\tfieldTags := map[int32]string{}\n\tfor _, fld := range md.Field {\n\t\tfn := res.FieldNode(fld)\n\t\tif _, ok := rsvdNames[fld.GetName()]; ok {\n\t\t\tfieldNameNodeInfo := res.file.NodeInfo(fn.FieldName())\n\t\t\tif err := handler.HandleErrorf(fieldNameNodeInfo, \"%s: field %s is using a reserved name\", scope, fld.GetName()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif existing := fieldTags[fld.GetNumber()]; existing != \"\" {\n\t\t\tfieldTagNodeInfo := res.file.NodeInfo(fn.FieldTag())\n\t\t\tif err := handler.HandleErrorf(fieldTagNodeInfo, \"%s: fields %s and %s both have the same tag %d\", scope, existing, fld.GetName(), fld.GetNumber()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tfieldTags[fld.GetNumber()] = fld.GetName()\n\t\t// check reserved ranges\n\t\tr := sort.Search(len(rsvd), func(index int) bool { return rsvd[index].end > fld.GetNumber() })\n\t\tif r < len(rsvd) && rsvd[r].start <= fld.GetNumber() {\n\t\t\tfieldTagNodeInfo := res.file.NodeInfo(fn.FieldTag())\n\t\t\tif err := handler.HandleErrorf(fieldTagNodeInfo, \"%s: field %s is using tag %d which is in reserved range %d to %d\", scope, fld.GetName(), fld.GetNumber(), rsvd[r].start, rsvd[r].end-1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t// and check extension ranges\n\t\te := sort.Search(len(exts), func(index int) bool { return exts[index].end > fld.GetNumber() })\n\t\tif e < len(exts) && exts[e].start <= fld.GetNumber() {\n\t\t\tfieldTagNodeInfo := res.file.NodeInfo(fn.FieldTag())\n\t\t\tif err := handler.HandleErrorf(fieldTagNodeInfo, \"%s: field %s is using tag %d which is in extension range %d to %d\", scope, fld.GetName(), fld.GetNumber(), exts[e].start, exts[e].end-1); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc isIdentifier(s string) bool {\n\tif len(s) == 0 {\n\t\treturn false\n\t}\n\tfor i, r := range s {\n\t\tif i == 0 && r >= '0' && r <= '9' {\n\t\t\t// can't start with number\n\t\t\treturn false\n\t\t}\n\t\t// alphanumeric and underscore ok; everything else bad\n\t\tswitch {\n\t\tcase r >= '0' && r <= '9':\n\t\tcase r >= 'a' && r <= 'z':\n\t\tcase r >= 'A' && r <= 'Z':\n\t\tcase r == '_':\n\t\tdefault:\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc findMessageReservedNameNode(msgNode ast.MessageDeclNode, name string) ast.Node {\n\tvar decls []ast.MessageElement\n\tswitch msgNode := msgNode.(type) {\n\tcase *ast.MessageNode:\n\t\tdecls = msgNode.Decls\n\tcase *ast.SyntheticGroupMessageNode:\n\t\tdecls = msgNode.Decls\n\tdefault:\n\t\t// leave decls empty\n\t}\n\treturn findReservedNameNode(msgNode, decls, name)\n}\n\nfunc findReservedNameNode[T ast.Node](parent ast.Node, decls []T, name string) ast.Node {\n\tfor _, decl := range decls {\n\t\t// NB: We have to convert to empty interface first, before we can do a type\n\t\t// assertion because type assertions on type parameters aren't allowed. (The\n\t\t// compiler cannot yet know whether T is an interface type or not.)\n\t\trsvd, ok := any(decl).(*ast.ReservedNode)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, rsvdName := range rsvd.Names {\n\t\t\tif rsvdName.AsString() == name {\n\t\t\t\treturn rsvdName\n\t\t\t}\n\t\t}\n\t}\n\t// couldn't find it? Instead of puking, report position of the parent.\n\treturn parent\n}\n\nfunc validateEnum(res *result, syntax protoreflect.Syntax, name protoreflect.FullName, ed *descriptorpb.EnumDescriptorProto, handler *reporter.Handler) error {\n\tscope := fmt.Sprintf(\"enum %s\", name)\n\n\tif len(ed.Value) == 0 {\n\t\tenNode := res.EnumNode(ed)\n\t\tenNodeInfo := res.file.NodeInfo(enNode)\n\t\tif err := handler.HandleErrorf(enNodeInfo, \"%s: enums must define at least one value\", scope); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif err := validateNoFeatures(res, syntax, scope, ed.Options.GetUninterpretedOption(), handler); err != nil {\n\t\treturn err\n\t}\n\n\tallowAlias := false\n\tvar allowAliasOpt *descriptorpb.UninterpretedOption\n\tif index, err := internal.FindOption(res, handler.HandleErrorf, scope, ed.Options.GetUninterpretedOption(), \"allow_alias\"); err != nil {\n\t\treturn err\n\t} else if index >= 0 {\n\t\tallowAliasOpt = ed.Options.UninterpretedOption[index]\n\t\tvalid := false\n\t\tif allowAliasOpt.IdentifierValue != nil {\n\t\t\tif allowAliasOpt.GetIdentifierValue() == \"true\" {\n\t\t\t\tallowAlias = true\n\t\t\t\tvalid = true\n\t\t\t} else if allowAliasOpt.GetIdentifierValue() == \"false\" {\n\t\t\t\tvalid = true\n\t\t\t}\n\t\t}\n\t\tif !valid {\n\t\t\toptNode := res.OptionNode(allowAliasOpt)\n\t\t\toptNodeInfo := res.file.NodeInfo(optNode.GetValue())\n\t\t\tif err := handler.HandleErrorf(optNodeInfo, \"%s: expecting bool value for allow_alias option\", scope); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\tif syntax == protoreflect.Proto3 && len(ed.Value) > 0 && ed.Value[0].GetNumber() != 0 {\n\t\tevNode := res.EnumValueNode(ed.Value[0])\n\t\tevNodeInfo := res.file.NodeInfo(evNode.GetNumber())\n\t\tif err := handler.HandleErrorf(evNodeInfo, \"%s: proto3 requires that first value of enum have numeric value zero\", scope); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// check for aliases\n\tvals := map[int32]string{}\n\thasAlias := false\n\tfor _, evd := range ed.Value {\n\t\texisting := vals[evd.GetNumber()]\n\t\tif existing != \"\" {\n\t\t\tif allowAlias {\n\t\t\t\thasAlias = true\n\t\t\t} else {\n\t\t\t\tevNode := res.EnumValueNode(evd)\n\t\t\t\tevNodeInfo := res.file.NodeInfo(evNode.GetNumber())\n\t\t\t\tif err := handler.HandleErrorf(evNodeInfo, \"%s: values %s and %s both have the same numeric value %d; use allow_alias option if intentional\", scope, existing, evd.GetName(), evd.GetNumber()); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvals[evd.GetNumber()] = evd.GetName()\n\t}\n\tif allowAlias && !hasAlias {\n\t\toptNode := res.OptionNode(allowAliasOpt)\n\t\toptNodeInfo := res.file.NodeInfo(optNode.GetValue())\n\t\tif err := handler.HandleErrorf(optNodeInfo, \"%s: allow_alias is true but no values are aliases\", scope); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// reserved ranges should not overlap\n\trsvd := make(tagRanges, len(ed.ReservedRange))\n\tfor i, r := range ed.ReservedRange {\n\t\tn := res.EnumReservedRangeNode(r)\n\t\trsvd[i] = tagRange{start: r.GetStart(), end: r.GetEnd(), node: n}\n\t}\n\tsort.Sort(rsvd)\n\tfor i := 1; i < len(rsvd); i++ {\n\t\tif rsvd[i].start <= rsvd[i-1].end {\n\t\t\trangeNodeInfo := res.file.NodeInfo(rsvd[i].node)\n\t\t\tif err := handler.HandleErrorf(rangeNodeInfo, \"%s: reserved ranges overlap: %d to %d and %d to %d\", scope, rsvd[i-1].start, rsvd[i-1].end, rsvd[i].start, rsvd[i].end); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\t// now, check that fields don't re-use tags and don't try to use extension\n\t// or reserved ranges or reserved names\n\trsvdNames := map[string]struct{}{}\n\tfor _, n := range ed.ReservedName {\n\t\t// validate reserved name while we're here\n\t\tif !isIdentifier(n) {\n\t\t\tnode := findEnumReservedNameNode(res.EnumNode(ed), n)\n\t\t\tnodeInfo := res.file.NodeInfo(node)\n\t\t\tif err := handler.HandleErrorf(nodeInfo, \"%s: reserved name %q is not a valid identifier\", scope, n); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\trsvdNames[n] = struct{}{}\n\t}\n\tfor _, ev := range ed.Value {\n\t\tevn := res.EnumValueNode(ev)\n\t\tif _, ok := rsvdNames[ev.GetName()]; ok {\n\t\t\tenumValNodeInfo := res.file.NodeInfo(evn.GetName())\n\t\t\tif err := handler.HandleErrorf(enumValNodeInfo, \"%s: value %s is using a reserved name\", scope, ev.GetName()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\t// check reserved ranges\n\t\tr := sort.Search(len(rsvd), func(index int) bool { return rsvd[index].end >= ev.GetNumber() })\n\t\tif r < len(rsvd) && rsvd[r].start <= ev.GetNumber() {\n\t\t\tenumValNodeInfo := res.file.NodeInfo(evn.GetNumber())\n\t\t\tif err := handler.HandleErrorf(enumValNodeInfo, \"%s: value %s is using number %d which is in reserved range %d to %d\", scope, ev.GetName(), ev.GetNumber(), rsvd[r].start, rsvd[r].end); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc findEnumReservedNameNode(enumNode ast.Node, name string) ast.Node {\n\tvar decls []ast.EnumElement\n\tif enumNode, ok := enumNode.(*ast.EnumNode); ok {\n\t\tdecls = enumNode.Decls\n\t\t// if not the right type, we leave decls empty\n\t}\n\treturn findReservedNameNode(enumNode, decls, name)\n}\n\nfunc validateField(res *result, syntax protoreflect.Syntax, name protoreflect.FullName, fld *descriptorpb.FieldDescriptorProto, handler *reporter.Handler) error {\n\tvar scope string\n\tif fld.Extendee != nil {\n\t\tscope = fmt.Sprintf(\"extension %s\", name)\n\t} else {\n\t\tscope = fmt.Sprintf(\"field %s\", name)\n\t}\n\n\tnode := res.FieldNode(fld)\n\tif fld.Number == nil {\n\t\tfieldTagNodeInfo := res.file.NodeInfo(node)\n\t\tif err := handler.HandleErrorf(fieldTagNodeInfo, \"%s: missing field tag number\", scope); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif syntax != protoreflect.Proto2 {\n\t\tif fld.GetType() == descriptorpb.FieldDescriptorProto_TYPE_GROUP {\n\t\t\tgroupNodeInfo := res.file.NodeInfo(node.GetGroupKeyword())\n\t\t\tif err := handler.HandleErrorf(groupNodeInfo, \"%s: groups are not allowed in proto3 or editions\", scope); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t} else if fld.Label != nil && fld.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REQUIRED {\n\t\t\tfieldLabelNodeInfo := res.file.NodeInfo(node.FieldLabel())\n\t\t\tif err := handler.HandleErrorf(fieldLabelNodeInfo, \"%s: label 'required' is not allowed in proto3 or editions\", scope); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif syntax == protoreflect.Editions {\n\t\t\tif fld.Label != nil && fld.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL {\n\t\t\t\tfieldLabelNodeInfo := res.file.NodeInfo(node.FieldLabel())\n\t\t\t\tif err := handler.HandleErrorf(fieldLabelNodeInfo, \"%s: label 'optional' is not allowed in editions; use option features.field_presence instead\", scope); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t\tif index, err := internal.FindOption(res, handler.HandleErrorf, scope, fld.Options.GetUninterpretedOption(), \"packed\"); err != nil {\n\t\t\t\treturn err\n\t\t\t} else if index >= 0 {\n\t\t\t\toptNode := res.OptionNode(fld.Options.GetUninterpretedOption()[index])\n\t\t\t\toptNameNodeInfo := res.file.NodeInfo(optNode.GetName())\n\t\t\t\tif err := handler.HandleErrorf(optNameNodeInfo, \"%s: packed option is not allowed in editions; use option features.repeated_field_encoding instead\", scope); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t} else if syntax == protoreflect.Proto3 {\n\t\t\tif index, err := internal.FindOption(res, handler.HandleErrorf, scope, fld.Options.GetUninterpretedOption(), \"default\"); err != nil {\n\t\t\t\treturn err\n\t\t\t} else if index >= 0 {\n\t\t\t\toptNode := res.OptionNode(fld.Options.GetUninterpretedOption()[index])\n\t\t\t\toptNameNodeInfo := res.file.NodeInfo(optNode.GetName())\n\t\t\t\tif err := handler.HandleErrorf(optNameNodeInfo, \"%s: default values are not allowed in proto3\", scope); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif fld.Label == nil && fld.OneofIndex == nil {\n\t\t\tfieldNameNodeInfo := res.file.NodeInfo(node.FieldName())\n\t\t\tif err := handler.HandleErrorf(fieldNameNodeInfo, \"%s: field has no label; proto2 requires explicit 'optional' label\", scope); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tif fld.GetExtendee() != \"\" && fld.Label != nil && fld.GetLabel() == descriptorpb.FieldDescriptorProto_LABEL_REQUIRED {\n\t\t\tfieldLabelNodeInfo := res.file.NodeInfo(node.FieldLabel())\n\t\t\tif err := handler.HandleErrorf(fieldLabelNodeInfo, \"%s: extension fields cannot be 'required'\", scope); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\n\treturn validateNoFeatures(res, syntax, scope, fld.Options.GetUninterpretedOption(), handler)\n}\n\ntype tagRange struct {\n\tstart int32\n\tend   int32\n\tnode  ast.RangeDeclNode\n}\n\ntype tagRanges []tagRange\n\nfunc (r tagRanges) Len() int {\n\treturn len(r)\n}\n\nfunc (r tagRanges) Less(i, j int) bool {\n\treturn r[i].start < r[j].start ||\n\t\t(r[i].start == r[j].start && r[i].end < r[j].end)\n}\n\nfunc (r tagRanges) Swap(i, j int) {\n\tr[i], r[j] = r[j], r[i]\n}\n\nfunc fillInMissingLabels(fd *descriptorpb.FileDescriptorProto) {\n\tfor _, md := range fd.MessageType {\n\t\tfillInMissingLabelsInMsg(md)\n\t}\n\tfor _, extd := range fd.Extension {\n\t\tfillInMissingLabel(extd)\n\t}\n}\n\nfunc fillInMissingLabelsInMsg(md *descriptorpb.DescriptorProto) {\n\tfor _, fld := range md.Field {\n\t\tfillInMissingLabel(fld)\n\t}\n\tfor _, nmd := range md.NestedType {\n\t\tfillInMissingLabelsInMsg(nmd)\n\t}\n\tfor _, extd := range md.Extension {\n\t\tfillInMissingLabel(extd)\n\t}\n}\n\nfunc fillInMissingLabel(fld *descriptorpb.FieldDescriptorProto) {\n\tif fld.Label == nil {\n\t\tfld.Label = descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/protoutil/editions.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage protoutil\n\nimport (\n\t\"fmt\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\t\"google.golang.org/protobuf/types/dynamicpb\"\n\n\t\"github.com/bufbuild/protocompile/internal/editions\"\n)\n\n// GetFeatureDefault gets the default value for the given feature and the given\n// edition. The given feature must represent a field of the google.protobuf.FeatureSet\n// message and must not be an extension.\n//\n// If the given field is from a dynamically built descriptor (i.e. it's containing\n// message descriptor is different from the linked-in descriptor for\n// [*descriptorpb.FeatureSet]), the returned value may be a dynamic value. In such\n// cases, the value may not be directly usable using [protoreflect.Message.Set] with\n// an instance of [*descriptorpb.FeatureSet] and must instead be used with a\n// [*dynamicpb.Message].\n//\n// To get the default value of a custom feature, use [GetCustomFeatureDefault]\n// instead.\nfunc GetFeatureDefault(edition descriptorpb.Edition, feature protoreflect.FieldDescriptor) (protoreflect.Value, error) {\n\tif feature.ContainingMessage().FullName() != editions.FeatureSetDescriptor.FullName() {\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"feature %s is a field of %s but should be a field of %s\",\n\t\t\tfeature.Name(), feature.ContainingMessage().FullName(), editions.FeatureSetDescriptor.FullName())\n\t}\n\tvar msgType protoreflect.MessageType\n\tif feature.ContainingMessage() == editions.FeatureSetDescriptor {\n\t\tmsgType = editions.FeatureSetType\n\t} else {\n\t\tmsgType = dynamicpb.NewMessageType(feature.ContainingMessage())\n\t}\n\treturn editions.GetFeatureDefault(edition, msgType, feature)\n}\n\n// GetCustomFeatureDefault gets the default value for the given custom feature\n// and given edition. A custom feature is a field whose containing message is the\n// type of an extension field of google.protobuf.FeatureSet. The given extension\n// describes that extension field and message type. The given feature must be a\n// field of that extension's message type.\nfunc GetCustomFeatureDefault(edition descriptorpb.Edition, extension protoreflect.ExtensionType, feature protoreflect.FieldDescriptor) (protoreflect.Value, error) {\n\textDesc := extension.TypeDescriptor()\n\tif extDesc.ContainingMessage().FullName() != editions.FeatureSetDescriptor.FullName() {\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"extension %s does not extend %s\", extDesc.FullName(), editions.FeatureSetDescriptor.FullName())\n\t}\n\tif extDesc.Message() == nil {\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"extensions of %s should be messages; %s is instead %s\",\n\t\t\teditions.FeatureSetDescriptor.FullName(), extDesc.FullName(), extDesc.Kind().String())\n\t}\n\tif feature.IsExtension() {\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"feature %s is an extension, but feature extension %s may not itself have extensions\",\n\t\t\tfeature.FullName(), extDesc.FullName())\n\t}\n\tif feature.ContainingMessage().FullName() != extDesc.Message().FullName() {\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"feature %s is a field of %s but should be a field of %s\",\n\t\t\tfeature.Name(), feature.ContainingMessage().FullName(), extDesc.Message().FullName())\n\t}\n\tif feature.ContainingMessage() != extDesc.Message() {\n\t\treturn protoreflect.Value{}, fmt.Errorf(\"feature %s has a different message descriptor from the given extension type for %s\",\n\t\t\tfeature.Name(), extDesc.Message().FullName())\n\t}\n\treturn editions.GetFeatureDefault(edition, extension.Zero().Message().Type(), feature)\n}\n\n// ResolveFeature resolves a feature for the given descriptor.\n//\n// If the given element is in a proto2 or proto3 syntax file, this skips\n// resolution and just returns the relevant default (since such files are not\n// allowed to override features). If neither the given element nor any of its\n// ancestors override the given feature, the relevant default is returned.\n//\n// This has the same caveat as GetFeatureDefault if the given feature is from a\n// dynamically built descriptor.\nfunc ResolveFeature(element protoreflect.Descriptor, feature protoreflect.FieldDescriptor) (protoreflect.Value, error) {\n\tedition := editions.GetEdition(element)\n\tdefaultVal, err := GetFeatureDefault(edition, feature)\n\tif err != nil {\n\t\treturn protoreflect.Value{}, err\n\t}\n\treturn resolveFeature(edition, defaultVal, element, feature)\n}\n\n// ResolveCustomFeature resolves a custom feature for the given extension and\n// field descriptor.\n//\n// The given extension must be an extension of google.protobuf.FeatureSet that\n// represents a non-repeated message value. The given feature is a field in\n// that extension's message type.\n//\n// If the given element is in a proto2 or proto3 syntax file, this skips\n// resolution and just returns the relevant default (since such files are not\n// allowed to override features). If neither the given element nor any of its\n// ancestors override the given feature, the relevant default is returned.\nfunc ResolveCustomFeature(element protoreflect.Descriptor, extension protoreflect.ExtensionType, feature protoreflect.FieldDescriptor) (protoreflect.Value, error) {\n\tedition := editions.GetEdition(element)\n\tdefaultVal, err := GetCustomFeatureDefault(edition, extension, feature)\n\tif err != nil {\n\t\treturn protoreflect.Value{}, err\n\t}\n\treturn resolveFeature(edition, defaultVal, element, extension.TypeDescriptor(), feature)\n}\n\nfunc resolveFeature(\n\tedition descriptorpb.Edition,\n\tdefaultVal protoreflect.Value,\n\telement protoreflect.Descriptor,\n\tfields ...protoreflect.FieldDescriptor,\n) (protoreflect.Value, error) {\n\tif edition == descriptorpb.Edition_EDITION_PROTO2 || edition == descriptorpb.Edition_EDITION_PROTO3 {\n\t\t// these syntax levels can't specify features, so we can short-circuit the search\n\t\t// through the descriptor hierarchy for feature overrides\n\t\treturn defaultVal, nil\n\t}\n\tval, err := editions.ResolveFeature(element, fields...)\n\tif err != nil {\n\t\treturn protoreflect.Value{}, err\n\t}\n\tif val.IsValid() {\n\t\treturn val, nil\n\t}\n\treturn defaultVal, nil\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/protoutil/protos.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package protoutil contains useful functions for interacting with descriptors.\n// For now these include only functions for efficiently converting descriptors\n// produced by the compiler to descriptor protos and functions for resolving\n// \"features\" (a core concept of Protobuf Editions).\n//\n// Despite the fact that descriptor protos are mutable, calling code should NOT\n// mutate any of the protos returned from this package. For efficiency, some\n// values returned from this package may reference internal state of a compiler\n// result, and mutating the proto could corrupt or invalidate parts of that\n// result.\npackage protoutil\n\nimport (\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protodesc\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n)\n\n// DescriptorProtoWrapper is a protoreflect.Descriptor that wraps an\n// underlying descriptor proto. It provides the same interface as\n// Descriptor but with one extra operation, to efficiently query for\n// the underlying descriptor proto.\n//\n// Descriptors that implement this will also implement another method\n// whose specified return type is the concrete type returned by the\n// AsProto method. The name of this method varies by the type of this\n// descriptor:\n//\n//\t Descriptor Type        Other Method Name\n//\t---------------------+------------------------------------\n//\t FileDescriptor      |  FileDescriptorProto()\n//\t MessageDescriptor   |  MessageDescriptorProto()\n//\t FieldDescriptor     |  FieldDescriptorProto()\n//\t OneofDescriptor     |  OneofDescriptorProto()\n//\t EnumDescriptor      |  EnumDescriptorProto()\n//\t EnumValueDescriptor |  EnumValueDescriptorProto()\n//\t ServiceDescriptor   |  ServiceDescriptorProto()\n//\t MethodDescriptor    |  MethodDescriptorProto()\n//\n// For example, a DescriptorProtoWrapper that implements FileDescriptor\n// returns a *descriptorpb.FileDescriptorProto value from its AsProto\n// method and also provides a method with the following signature:\n//\n//\tFileDescriptorProto() *descriptorpb.FileDescriptorProto\ntype DescriptorProtoWrapper interface {\n\tprotoreflect.Descriptor\n\t// AsProto returns the underlying descriptor proto. The concrete\n\t// type of the proto message depends on the type of this\n\t// descriptor:\n\t//    Descriptor Type        Proto Message Type\n\t//   ---------------------+------------------------------------\n\t//    FileDescriptor      |  *descriptorpb.FileDescriptorProto\n\t//    MessageDescriptor   |  *descriptorpb.DescriptorProto\n\t//    FieldDescriptor     |  *descriptorpb.FieldDescriptorProto\n\t//    OneofDescriptor     |  *descriptorpb.OneofDescriptorProto\n\t//    EnumDescriptor      |  *descriptorpb.EnumDescriptorProto\n\t//    EnumValueDescriptor |  *descriptorpb.EnumValueDescriptorProto\n\t//    ServiceDescriptor   |  *descriptorpb.ServiceDescriptorProto\n\t//    MethodDescriptor    |  *descriptorpb.MethodDescriptorProto\n\tAsProto() proto.Message\n}\n\n// ProtoFromDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromDescriptor(d protoreflect.Descriptor) proto.Message {\n\tswitch d := d.(type) {\n\tcase protoreflect.FileDescriptor:\n\t\treturn ProtoFromFileDescriptor(d)\n\tcase protoreflect.MessageDescriptor:\n\t\treturn ProtoFromMessageDescriptor(d)\n\tcase protoreflect.FieldDescriptor:\n\t\treturn ProtoFromFieldDescriptor(d)\n\tcase protoreflect.OneofDescriptor:\n\t\treturn ProtoFromOneofDescriptor(d)\n\tcase protoreflect.EnumDescriptor:\n\t\treturn ProtoFromEnumDescriptor(d)\n\tcase protoreflect.EnumValueDescriptor:\n\t\treturn ProtoFromEnumValueDescriptor(d)\n\tcase protoreflect.ServiceDescriptor:\n\t\treturn ProtoFromServiceDescriptor(d)\n\tcase protoreflect.MethodDescriptor:\n\t\treturn ProtoFromMethodDescriptor(d)\n\tdefault:\n\t\t// WTF??\n\t\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\t\treturn res.AsProto()\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// ProtoFromFileDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For file descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. File descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromFileDescriptor(d protoreflect.FileDescriptor) *descriptorpb.FileDescriptorProto {\n\tif imp, ok := d.(protoreflect.FileImport); ok {\n\t\td = imp.FileDescriptor\n\t}\n\ttype canProto interface {\n\t\tFileDescriptorProto() *descriptorpb.FileDescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.FileDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif fd, ok := res.AsProto().(*descriptorpb.FileDescriptorProto); ok {\n\t\t\treturn fd\n\t\t}\n\t}\n\treturn protodesc.ToFileDescriptorProto(d)\n}\n\n// ProtoFromMessageDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For message descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Message descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromMessageDescriptor(d protoreflect.MessageDescriptor) *descriptorpb.DescriptorProto {\n\ttype canProto interface {\n\t\tMessageDescriptorProto() *descriptorpb.DescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.MessageDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif md, ok := res.AsProto().(*descriptorpb.DescriptorProto); ok {\n\t\t\treturn md\n\t\t}\n\t}\n\treturn protodesc.ToDescriptorProto(d)\n}\n\n// ProtoFromFieldDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For field descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Field descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromFieldDescriptor(d protoreflect.FieldDescriptor) *descriptorpb.FieldDescriptorProto {\n\ttype canProto interface {\n\t\tFieldDescriptorProto() *descriptorpb.FieldDescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.FieldDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif fd, ok := res.AsProto().(*descriptorpb.FieldDescriptorProto); ok {\n\t\t\treturn fd\n\t\t}\n\t}\n\treturn protodesc.ToFieldDescriptorProto(d)\n}\n\n// ProtoFromOneofDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For oneof descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Oneof descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromOneofDescriptor(d protoreflect.OneofDescriptor) *descriptorpb.OneofDescriptorProto {\n\ttype canProto interface {\n\t\tOneofDescriptorProto() *descriptorpb.OneofDescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.OneofDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif ood, ok := res.AsProto().(*descriptorpb.OneofDescriptorProto); ok {\n\t\t\treturn ood\n\t\t}\n\t}\n\treturn protodesc.ToOneofDescriptorProto(d)\n}\n\n// ProtoFromEnumDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For enum descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Enum descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromEnumDescriptor(d protoreflect.EnumDescriptor) *descriptorpb.EnumDescriptorProto {\n\ttype canProto interface {\n\t\tEnumDescriptorProto() *descriptorpb.EnumDescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.EnumDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif ed, ok := res.AsProto().(*descriptorpb.EnumDescriptorProto); ok {\n\t\t\treturn ed\n\t\t}\n\t}\n\treturn protodesc.ToEnumDescriptorProto(d)\n}\n\n// ProtoFromEnumValueDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For enum value descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Enum value descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromEnumValueDescriptor(d protoreflect.EnumValueDescriptor) *descriptorpb.EnumValueDescriptorProto {\n\ttype canProto interface {\n\t\tEnumValueDescriptorProto() *descriptorpb.EnumValueDescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.EnumValueDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif ed, ok := res.AsProto().(*descriptorpb.EnumValueDescriptorProto); ok {\n\t\t\treturn ed\n\t\t}\n\t}\n\treturn protodesc.ToEnumValueDescriptorProto(d)\n}\n\n// ProtoFromServiceDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For service descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Service descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromServiceDescriptor(d protoreflect.ServiceDescriptor) *descriptorpb.ServiceDescriptorProto {\n\ttype canProto interface {\n\t\tServiceDescriptorProto() *descriptorpb.ServiceDescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.ServiceDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif sd, ok := res.AsProto().(*descriptorpb.ServiceDescriptorProto); ok {\n\t\t\treturn sd\n\t\t}\n\t}\n\treturn protodesc.ToServiceDescriptorProto(d)\n}\n\n// ProtoFromMethodDescriptor extracts a descriptor proto from the given \"rich\"\n// descriptor. For method descriptors generated by the compiler, this is an\n// inexpensive and non-lossy operation. Method descriptors from other sources\n// however may be expensive (to re-create a proto) and even lossy.\nfunc ProtoFromMethodDescriptor(d protoreflect.MethodDescriptor) *descriptorpb.MethodDescriptorProto {\n\ttype canProto interface {\n\t\tMethodDescriptorProto() *descriptorpb.MethodDescriptorProto\n\t}\n\tif res, ok := d.(canProto); ok {\n\t\treturn res.MethodDescriptorProto()\n\t}\n\tif res, ok := d.(DescriptorProtoWrapper); ok {\n\t\tif md, ok := res.AsProto().(*descriptorpb.MethodDescriptorProto); ok {\n\t\t\treturn md\n\t\t}\n\t}\n\treturn protodesc.ToMethodDescriptorProto(d)\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/reporter/errors.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage reporter\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n)\n\n// ErrInvalidSource is a sentinel error that is returned by compilation and\n// stand-alone compilation steps (such as parsing, linking) when one or more\n// errors is reported but the configured ErrorReporter always returns nil.\nvar ErrInvalidSource = errors.New(\"parse failed: invalid proto source\")\n\n// ErrorWithPos is an error about a proto source file that adds information\n// about the location in the file that caused the error.\ntype ErrorWithPos interface {\n\terror\n\tast.SourceSpan\n\t// GetPosition returns the start source position that caused the underlying error.\n\tGetPosition() ast.SourcePos\n\t// Unwrap returns the underlying error.\n\tUnwrap() error\n}\n\n// Error creates a new ErrorWithPos from the given error and source position.\nfunc Error(span ast.SourceSpan, err error) ErrorWithPos {\n\tvar ewp ErrorWithPos\n\tif errors.As(err, &ewp) {\n\t\t// replace existing position with given one\n\t\treturn &errorWithSpan{SourceSpan: span, underlying: ewp.Unwrap()}\n\t}\n\treturn &errorWithSpan{SourceSpan: span, underlying: err}\n}\n\n// Errorf creates a new ErrorWithPos whose underlying error is created using the\n// given message format and arguments (via fmt.Errorf).\nfunc Errorf(span ast.SourceSpan, format string, args ...interface{}) ErrorWithPos {\n\treturn Error(span, fmt.Errorf(format, args...))\n}\n\ntype errorWithSpan struct {\n\tast.SourceSpan\n\tunderlying error\n}\n\nfunc (e *errorWithSpan) Error() string {\n\tsourcePos := e.GetPosition()\n\treturn fmt.Sprintf(\"%s: %v\", sourcePos, e.underlying)\n}\n\nfunc (e *errorWithSpan) GetPosition() ast.SourcePos {\n\treturn e.Start()\n}\n\nfunc (e *errorWithSpan) Unwrap() error {\n\treturn e.underlying\n}\n\nvar _ ErrorWithPos = (*errorWithSpan)(nil)\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/reporter/reporter.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package reporter contains the types used for reporting errors from\n// protocompile operations. It contains error types as well as interfaces\n// for reporting and handling errors and warnings.\npackage reporter\n\nimport (\n\t\"sync\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n)\n\n// ErrorReporter is responsible for reporting the given error. If the reporter\n// returns a non-nil error, parsing/linking will abort with that error. If the\n// reporter returns nil, parsing will continue, allowing the parser to try to\n// report as many syntax and/or link errors as it can find.\ntype ErrorReporter func(err ErrorWithPos) error\n\n// WarningReporter is responsible for reporting the given warning. This is used\n// for indicating non-error messages to the calling program for things that do\n// not cause the parse to fail but are considered bad practice. Though they are\n// just warnings, the details are supplied to the reporter via an error type.\ntype WarningReporter func(ErrorWithPos)\n\n// Reporter is a type that handles reporting both errors and warnings.\n// A reporter does not need to be thread-safe. Safe concurrent access is\n// managed by a Handler.\ntype Reporter interface {\n\t// Error is called when the given error is encountered and needs to be\n\t// reported to the calling program. This signature matches ErrorReporter\n\t// because it has the same semantics. If this function returns non-nil\n\t// then the operation will abort immediately with the given error. But\n\t// if it returns nil, the operation will continue, reporting more errors\n\t// as they are encountered. If the reporter never returns non-nil then\n\t// the operation will eventually fail with ErrInvalidSource.\n\tError(ErrorWithPos) error\n\t// Warning is called when the given warnings is encountered and needs to be\n\t// reported to the calling program. Despite the argument being an error\n\t// type, a warning will never cause the operation to abort or fail (unless\n\t// the reporter's implementation of this method panics).\n\tWarning(ErrorWithPos)\n}\n\n// NewReporter creates a new reporter that invokes the given functions on error\n// or warning.\nfunc NewReporter(errs ErrorReporter, warnings WarningReporter) Reporter {\n\treturn reporterFuncs{errs: errs, warnings: warnings}\n}\n\ntype reporterFuncs struct {\n\terrs     ErrorReporter\n\twarnings WarningReporter\n}\n\nfunc (r reporterFuncs) Error(err ErrorWithPos) error {\n\tif r.errs == nil {\n\t\treturn err\n\t}\n\treturn r.errs(err)\n}\n\nfunc (r reporterFuncs) Warning(err ErrorWithPos) {\n\tif r.warnings != nil {\n\t\tr.warnings(err)\n\t}\n}\n\n// Handler is used by protocompile operations for handling errors and warnings.\n// This type is thread-safe. It uses a mutex to serialize calls to its reporter\n// so that reporter instances do not have to be thread-safe (unless re-used\n// across multiple handlers).\ntype Handler struct {\n\tparent       *Handler\n\tmu           sync.Mutex\n\treporter     Reporter\n\terrsReported bool\n\terr          error\n}\n\n// NewHandler creates a new Handler that reports errors and warnings using the\n// given reporter.\nfunc NewHandler(rep Reporter) *Handler {\n\tif rep == nil {\n\t\trep = NewReporter(nil, nil)\n\t}\n\treturn &Handler{reporter: rep}\n}\n\n// SubHandler returns a \"child\" of h. Use of a child handler is the same as use\n// of the parent, except that the Error() and ReporterError() functions only\n// report non-nil for errors that were reported using the child handler. So\n// errors reported directly to the parent or to a different child handler won't\n// be returned. This is useful for making concurrent access to the handler more\n// deterministic: if a child handler is only used from one goroutine, its view\n// of reported errors is consistent and unimpacted by concurrent operations.\nfunc (h *Handler) SubHandler() *Handler {\n\treturn &Handler{parent: h}\n}\n\n// HandleError handles the given error. If the given err is an ErrorWithPos, it\n// is reported, and this function returns the error returned by the reporter. If\n// the given err is NOT an ErrorWithPos, the current operation will abort\n// immediately.\n//\n// If the handler has already aborted (by returning a non-nil error from a prior\n// call to HandleError or HandleErrorf), that same error is returned and the\n// given error is not reported.\nfunc (h *Handler) HandleError(err error) error {\n\tif h.parent != nil {\n\t\t_, isErrWithPos := err.(ErrorWithPos)\n\t\terr = h.parent.HandleError(err)\n\n\t\t// update child state\n\t\th.mu.Lock()\n\t\tdefer h.mu.Unlock()\n\t\tif isErrWithPos {\n\t\t\th.errsReported = true\n\t\t}\n\t\th.err = err\n\t\treturn err\n\t}\n\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\n\tif h.err != nil {\n\t\treturn h.err\n\t}\n\tif ewp, ok := err.(ErrorWithPos); ok {\n\t\th.errsReported = true\n\t\terr = h.reporter.Error(ewp)\n\t}\n\th.err = err\n\treturn err\n}\n\n// HandleErrorWithPos handles an error with the given source position.\n//\n// If the handler has already aborted (by returning a non-nil error from a prior\n// call to HandleError or HandleErrorf), that same error is returned and the\n// given error is not reported.\nfunc (h *Handler) HandleErrorWithPos(span ast.SourceSpan, err error) error {\n\treturn h.HandleError(Error(span, err))\n}\n\n// HandleErrorf handles an error with the given source position, creating the\n// error using the given message format and arguments.\n//\n// If the handler has already aborted (by returning a non-nil error from a call\n// to HandleError or HandleErrorf), that same error is returned and the given\n// error is not reported.\nfunc (h *Handler) HandleErrorf(span ast.SourceSpan, format string, args ...interface{}) error {\n\treturn h.HandleError(Errorf(span, format, args...))\n}\n\n// HandleWarning handles the given warning. This will delegate to the handler's\n// configured reporter.\nfunc (h *Handler) HandleWarning(err ErrorWithPos) {\n\tif h.parent != nil {\n\t\th.parent.HandleWarning(err)\n\t\treturn\n\t}\n\n\t// even though we aren't touching mutable fields, we acquire lock anyway so\n\t// that underlying reporter does not have to be thread-safe\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\n\th.reporter.Warning(err)\n}\n\n// HandleWarningWithPos handles a warning with the given source position. This will\n// delegate to the handler's configured reporter.\nfunc (h *Handler) HandleWarningWithPos(span ast.SourceSpan, err error) {\n\th.HandleWarning(Error(span, err))\n}\n\n// HandleWarningf handles a warning with the given source position, creating the\n// actual error value using the given message format and arguments.\nfunc (h *Handler) HandleWarningf(span ast.SourceSpan, format string, args ...interface{}) {\n\th.HandleWarning(Errorf(span, format, args...))\n}\n\n// Error returns the handler result. If any errors have been reported then this\n// returns a non-nil error. If the reporter never returned a non-nil error then\n// ErrInvalidSource is returned. Otherwise, this returns the error returned by\n// the  handler's reporter (the same value returned by ReporterError).\nfunc (h *Handler) Error() error {\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\n\tif h.errsReported && h.err == nil {\n\t\treturn ErrInvalidSource\n\t}\n\treturn h.err\n}\n\n// ReporterError returns the error returned by the handler's reporter. If\n// the reporter has either not been invoked (no errors handled) or has not\n// returned any non-nil value, then this returns nil.\nfunc (h *Handler) ReporterError() error {\n\th.mu.Lock()\n\tdefer h.mu.Unlock()\n\n\treturn h.err\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/resolver.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage protocompile\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/parser\"\n)\n\n// Resolver is used by the compiler to resolve a proto source file name\n// into some unit that is usable by the compiler. The result could be source\n// for a proto file or it could be an already-parsed AST or descriptor.\n//\n// Resolver implementations must be thread-safe as a single compilation\n// operation could invoke FindFileByPath from multiple goroutines.\ntype Resolver interface {\n\t// FindFileByPath searches for information for the given file path. If no\n\t// result is available, it should return a non-nil error, such as\n\t// protoregistry.NotFound.\n\tFindFileByPath(path string) (SearchResult, error)\n}\n\n// SearchResult represents information about a proto source file. Only one of\n// the various fields must be set, based on what is available for a file. If\n// multiple fields are set, the compiler prefers them in opposite order listed:\n// so it uses a descriptor if present and only falls back to source if nothing\n// else is available.\ntype SearchResult struct {\n\t// Represents source code for the file. This should be nil if source code\n\t// is not available. If no field below is set, then the compiler will parse\n\t// the source code into an AST.\n\tSource io.Reader\n\t// Represents the abstract syntax tree for the file. If no field below is\n\t// set, then the compiler will convert the AST into a descriptor proto.\n\tAST *ast.FileNode\n\t// A descriptor proto that represents the file. If the field below is not\n\t// set, then the compiler will link this proto with its dependencies to\n\t// produce a linked descriptor.\n\tProto *descriptorpb.FileDescriptorProto\n\t// A parse result for the file. This packages both an AST and a descriptor\n\t// proto in one. When a parser result is available, it is more efficient\n\t// than using an AST search result, since the descriptor proto need not be\n\t// re-created. And it provides better error messages than a descriptor proto\n\t// search result, since the AST has greater fidelity with regard to source\n\t// positions (even if the descriptor proto includes source code info).\n\tParseResult parser.Result\n\t// A fully linked descriptor that represents the file. If this field is set,\n\t// then the compiler has little or no additional work to do for this file as\n\t// it is already compiled. If this value implements linker.File, there is no\n\t// additional work. Otherwise, the additional work is to compute an index of\n\t// symbols in the file, for efficient lookup.\n\tDesc protoreflect.FileDescriptor\n}\n\n// ResolverFunc is a simple function type that implements Resolver.\ntype ResolverFunc func(string) (SearchResult, error)\n\nvar _ Resolver = ResolverFunc(nil)\n\nfunc (f ResolverFunc) FindFileByPath(path string) (SearchResult, error) {\n\treturn f(path)\n}\n\n// CompositeResolver is a slice of resolvers, which are consulted in order\n// until one can supply a result. If none of the constituent resolvers can\n// supply a result, the error returned by the first resolver is returned. If\n// the slice of resolvers is empty, all operations return\n// protoregistry.NotFound.\ntype CompositeResolver []Resolver\n\nvar _ Resolver = CompositeResolver(nil)\n\nfunc (f CompositeResolver) FindFileByPath(path string) (SearchResult, error) {\n\tif len(f) == 0 {\n\t\treturn SearchResult{}, protoregistry.NotFound\n\t}\n\tvar firstErr error\n\tfor _, res := range f {\n\t\tr, err := res.FindFileByPath(path)\n\t\tif err == nil {\n\t\t\treturn r, nil\n\t\t}\n\t\tif firstErr == nil {\n\t\t\tfirstErr = err\n\t\t}\n\t}\n\treturn SearchResult{}, firstErr\n}\n\n// SourceResolver can resolve file names by returning source code. It uses\n// an optional list of import paths to search. By default, it searches the\n// file system.\ntype SourceResolver struct {\n\t// Optional list of import paths. If present and not empty, then all\n\t// file paths to find are assumed to be relative to one of these paths.\n\t// If nil or empty, all file paths to find are assumed to be relative to\n\t// the current working directory.\n\tImportPaths []string\n\t// Optional function for returning a file's contents. If nil, then\n\t// os.Open is used to open files on the file system.\n\t//\n\t// This function must be thread-safe as a single compilation operation\n\t// could result in concurrent invocations of this function from\n\t// multiple goroutines.\n\tAccessor func(path string) (io.ReadCloser, error)\n}\n\nvar _ Resolver = (*SourceResolver)(nil)\n\nfunc (r *SourceResolver) FindFileByPath(path string) (SearchResult, error) {\n\tif len(r.ImportPaths) == 0 {\n\t\treader, err := r.accessFile(path)\n\t\tif err != nil {\n\t\t\treturn SearchResult{}, err\n\t\t}\n\t\treturn SearchResult{Source: reader}, nil\n\t}\n\n\tvar e error\n\tfor _, importPath := range r.ImportPaths {\n\t\treader, err := r.accessFile(filepath.Join(importPath, path))\n\t\tif err != nil {\n\t\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\t\te = err\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn SearchResult{}, err\n\t\t}\n\t\treturn SearchResult{Source: reader}, nil\n\t}\n\treturn SearchResult{}, e\n}\n\nfunc (r *SourceResolver) accessFile(path string) (io.ReadCloser, error) {\n\tif r.Accessor != nil {\n\t\treturn r.Accessor(path)\n\t}\n\treturn os.Open(path)\n}\n\n// SourceAccessorFromMap returns a function that can be used as the Accessor\n// field of a SourceResolver that uses the given map to load source. The map\n// keys are file names and the values are the corresponding file contents.\n//\n// The given map is used directly and not copied. Since accessor functions\n// must be thread-safe, this means that the provided map must not be mutated\n// once this accessor is provided to a compile operation.\nfunc SourceAccessorFromMap(srcs map[string]string) func(string) (io.ReadCloser, error) {\n\treturn func(path string) (io.ReadCloser, error) {\n\t\tsrc, ok := srcs[path]\n\t\tif !ok {\n\t\t\treturn nil, os.ErrNotExist\n\t\t}\n\t\treturn io.NopCloser(strings.NewReader(src)), nil\n\t}\n}\n\n// WithStandardImports returns a new resolver that knows about the same standard\n// imports that are included with protoc.\n//\n// Note that this uses the descriptors embedded in generated code in the packages\n// of the Protobuf Go module, except for \"google/protobuf/cpp_features.proto\" and\n// \"google/protobuf/java_features.proto\". For those two files, compiled descriptors\n// are embedded in this module because there is no package in the Protobuf Go module\n// that contains generated code for those files. This resolver also provides results\n// for the \"google/protobuf/go_features.proto\", which is technically not a standard\n// file (it is not included with protoc) but is included in generated code in the\n// Protobuf Go module.\n//\n// As of v0.14.0 of this module (and v1.34.2 of the Protobuf Go module and v27.0 of\n// Protobuf), the contents of the standard import \"google/protobuf/descriptor.proto\"\n// contain extension declarations which are *absent* from the descriptors that this\n// resolver returns. That is because extension declarations are only retained in\n// source, not at runtime, which means they are not available in the embedded\n// descriptors in generated code.\n//\n// To use versions of the standard imports that *do* include these extension\n// declarations, see wellknownimports.WithStandardImports instead. As of this\n// writing, the declarations are only needed to prevent source files from\n// illegally re-defining the custom features for C++, Java, and Go.\nfunc WithStandardImports(r Resolver) Resolver {\n\treturn ResolverFunc(func(name string) (SearchResult, error) {\n\t\tres, err := r.FindFileByPath(name)\n\t\tif err != nil {\n\t\t\t// error from given resolver? see if it's a known standard file\n\t\t\tif d, ok := standardImports[name]; ok {\n\t\t\t\treturn SearchResult{Desc: d}, nil\n\t\t\t}\n\t\t}\n\t\treturn res, err\n\t})\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/sourceinfo/source_code_info.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package sourceinfo contains the logic for computing source code info for a\n// file descriptor.\n//\n// The inputs to the computation are an AST for a file as well as the index of\n// interpreted options for that file.\npackage sourceinfo\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/ast\"\n\t\"github.com/bufbuild/protocompile/internal\"\n)\n\n// OptionIndex is a mapping of AST nodes that define options to corresponding\n// paths into the containing file descriptor. The path is a sequence of field\n// tags and indexes that define a traversal path from the root (the file\n// descriptor) to the resolved option field. The info also includes similar\n// information about child elements, for options whose values are composite\n// (like a list or message literal).\ntype OptionIndex map[*ast.OptionNode]*OptionSourceInfo\n\n// OptionSourceInfo describes the source info path for an option value and\n// contains information about the value's descendants in the AST.\ntype OptionSourceInfo struct {\n\t// The source info path to this element. If this element represents a\n\t// declaration with an array-literal value, the last element of the\n\t// path is the index of the first item in the array.\n\t//\n\t// This path is relative to the options message. So the first element\n\t// is a field number of the options message.\n\t//\n\t// If the first element is negative, it indicates the number of path\n\t// components to remove from the path to the relevant options. This is\n\t// used for field pseudo-options, so that the path indicates a field on\n\t// the descriptor, which is a parent of the options message (since that\n\t// is how the pseudo-options are actually stored).\n\tPath []int32\n\t// Children can be an *ArrayLiteralSourceInfo, a *MessageLiteralSourceInfo,\n\t// or nil, depending on whether the option's value is an\n\t// [*ast.ArrayLiteralNode], an [*ast.MessageLiteralNode], or neither.\n\t// For [*ast.ArrayLiteralNode] values, this is only populated if the\n\t// value is a non-empty array of messages. (Empty arrays and arrays\n\t// of scalar values do not need any additional info.)\n\tChildren OptionChildrenSourceInfo\n}\n\n// OptionChildrenSourceInfo represents source info paths for child elements of\n// an option value.\ntype OptionChildrenSourceInfo interface {\n\tisChildSourceInfo()\n}\n\n// ArrayLiteralSourceInfo represents source info paths for the child\n// elements of an [*ast.ArrayLiteralNode]. This value is only useful for\n// non-empty array literals that contain messages.\ntype ArrayLiteralSourceInfo struct {\n\tElements []OptionSourceInfo\n}\n\nfunc (*ArrayLiteralSourceInfo) isChildSourceInfo() {}\n\n// MessageLiteralSourceInfo represents source info paths for the child\n// elements of an [*ast.MessageLiteralNode].\ntype MessageLiteralSourceInfo struct {\n\tFields map[*ast.MessageFieldNode]*OptionSourceInfo\n}\n\nfunc (*MessageLiteralSourceInfo) isChildSourceInfo() {}\n\n// GenerateSourceInfo generates source code info for the given AST. If the given\n// opts is present, it can generate source code info for interpreted options.\n// Otherwise, any options in the AST will get source code info as uninterpreted\n// options.\nfunc GenerateSourceInfo(file *ast.FileNode, opts OptionIndex, genOpts ...GenerateOption) *descriptorpb.SourceCodeInfo {\n\tif file == nil {\n\t\treturn nil\n\t}\n\tsci := sourceCodeInfo{file: file, commentsUsed: map[ast.SourcePos]struct{}{}}\n\tfor _, sourceInfoOpt := range genOpts {\n\t\tsourceInfoOpt.apply(&sci)\n\t}\n\tgenerateSourceInfoForFile(opts, &sci, file)\n\treturn &descriptorpb.SourceCodeInfo{Location: sci.locs}\n}\n\n// GenerateOption represents an option for how source code info is generated.\ntype GenerateOption interface {\n\tapply(*sourceCodeInfo)\n}\n\n// WithExtraComments will result in source code info that contains extra comments.\n// By default, comments are only generated for full declarations. Inline comments\n// around elements of a declaration are not included in source code info. This option\n// changes that behavior so that as many comments as possible are described in the\n// source code info.\nfunc WithExtraComments() GenerateOption {\n\treturn extraCommentsOption{}\n}\n\n// WithExtraOptionLocations will result in source code info that contains extra\n// locations to describe elements inside of a message literal. By default, option\n// values are treated as opaque, so the only locations included are for the entire\n// option value. But with this option, paths to the various fields set inside a\n// message literal will also have locations. This makes it possible for usages of\n// the source code info to report precise locations for specific fields inside the\n// value.\nfunc WithExtraOptionLocations() GenerateOption {\n\treturn extraOptionLocationsOption{}\n}\n\ntype extraCommentsOption struct{}\n\nfunc (e extraCommentsOption) apply(info *sourceCodeInfo) {\n\tinfo.extraComments = true\n}\n\ntype extraOptionLocationsOption struct{}\n\nfunc (e extraOptionLocationsOption) apply(info *sourceCodeInfo) {\n\tinfo.extraOptionLocs = true\n}\n\nfunc generateSourceInfoForFile(opts OptionIndex, sci *sourceCodeInfo, file *ast.FileNode) {\n\tpath := make([]int32, 0, 16)\n\n\tsci.newLocWithoutComments(file, nil)\n\n\tif file.Syntax != nil {\n\t\tsci.newLocWithComments(file.Syntax, append(path, internal.FileSyntaxTag))\n\t}\n\tif file.Edition != nil {\n\t\tsci.newLocWithComments(file.Edition, append(path, internal.FileEditionTag))\n\t}\n\n\tvar depIndex, pubDepIndex, weakDepIndex, optIndex, msgIndex, enumIndex, extendIndex, svcIndex int32\n\n\tfor _, child := range file.Decls {\n\t\tswitch child := child.(type) {\n\t\tcase *ast.ImportNode:\n\t\t\tsci.newLocWithComments(child, append(path, internal.FileDependencyTag, depIndex))\n\t\t\tdepIndex++\n\t\t\tif child.Public != nil {\n\t\t\t\tsci.newLoc(child.Public, append(path, internal.FilePublicDependencyTag, pubDepIndex))\n\t\t\t\tpubDepIndex++\n\t\t\t} else if child.Weak != nil {\n\t\t\t\tsci.newLoc(child.Weak, append(path, internal.FileWeakDependencyTag, weakDepIndex))\n\t\t\t\tweakDepIndex++\n\t\t\t}\n\t\tcase *ast.PackageNode:\n\t\t\tsci.newLocWithComments(child, append(path, internal.FilePackageTag))\n\t\tcase *ast.OptionNode:\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, child, false, &optIndex, append(path, internal.FileOptionsTag))\n\t\tcase *ast.MessageNode:\n\t\t\tgenerateSourceCodeInfoForMessage(opts, sci, child, nil, append(path, internal.FileMessagesTag, msgIndex))\n\t\t\tmsgIndex++\n\t\tcase *ast.EnumNode:\n\t\t\tgenerateSourceCodeInfoForEnum(opts, sci, child, append(path, internal.FileEnumsTag, enumIndex))\n\t\t\tenumIndex++\n\t\tcase *ast.ExtendNode:\n\t\t\textsPath := append(path, internal.FileExtensionsTag) //nolint:gocritic // intentionally creating new slice var\n\t\t\t// we clone the path here so that append can't mutate extsPath, since they may share storage\n\t\t\tmsgsPath := append(internal.ClonePath(path), internal.FileMessagesTag)\n\t\t\tgenerateSourceCodeInfoForExtensions(opts, sci, child, &extendIndex, &msgIndex, extsPath, msgsPath)\n\t\tcase *ast.ServiceNode:\n\t\t\tgenerateSourceCodeInfoForService(opts, sci, child, append(path, internal.FileServicesTag, svcIndex))\n\t\t\tsvcIndex++\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForOption(opts OptionIndex, sci *sourceCodeInfo, n *ast.OptionNode, compact bool, uninterpIndex *int32, path []int32) {\n\tif !compact {\n\t\tsci.newLocWithoutComments(n, path)\n\t}\n\toptInfo := opts[n]\n\tif optInfo != nil {\n\t\tfullPath := combinePathsForOption(path, optInfo.Path)\n\t\tif compact {\n\t\t\tsci.newLoc(n, fullPath)\n\t\t} else {\n\t\t\tsci.newLocWithComments(n, fullPath)\n\t\t}\n\t\tif sci.extraOptionLocs {\n\t\t\tgenerateSourceInfoForOptionChildren(sci, n.Val, path, fullPath, optInfo.Children)\n\t\t}\n\t\treturn\n\t}\n\n\t// it's an uninterpreted option\n\toptPath := path\n\toptPath = append(optPath, internal.UninterpretedOptionsTag, *uninterpIndex)\n\t*uninterpIndex++\n\tsci.newLoc(n, optPath)\n\tvar valTag int32\n\tswitch n.Val.(type) {\n\tcase ast.IdentValueNode:\n\t\tvalTag = internal.UninterpretedIdentTag\n\tcase *ast.NegativeIntLiteralNode:\n\t\tvalTag = internal.UninterpretedNegIntTag\n\tcase ast.IntValueNode:\n\t\tvalTag = internal.UninterpretedPosIntTag\n\tcase ast.FloatValueNode:\n\t\tvalTag = internal.UninterpretedDoubleTag\n\tcase ast.StringValueNode:\n\t\tvalTag = internal.UninterpretedStringTag\n\tcase *ast.MessageLiteralNode:\n\t\tvalTag = internal.UninterpretedAggregateTag\n\t}\n\tif valTag != 0 {\n\t\tsci.newLoc(n.Val, append(optPath, valTag))\n\t}\n\tfor j, nn := range n.Name.Parts {\n\t\toptNmPath := optPath\n\t\toptNmPath = append(optNmPath, internal.UninterpretedNameTag, int32(j))\n\t\tsci.newLoc(nn, optNmPath)\n\t\tsci.newLoc(nn.Name, append(optNmPath, internal.UninterpretedNameNameTag))\n\t}\n}\n\nfunc combinePathsForOption(prefix, optionPath []int32) []int32 {\n\tfullPath := make([]int32, len(prefix), len(prefix)+len(optionPath))\n\tcopy(fullPath, prefix)\n\tif optionPath[0] == -1 {\n\t\t// used by \"default\" and \"json_name\" field pseudo-options\n\t\t// to attribute path to parent element (since those are\n\t\t// stored directly on the descriptor, not its options)\n\t\toptionPath = optionPath[1:]\n\t\tfullPath = fullPath[:len(prefix)-1]\n\t}\n\treturn append(fullPath, optionPath...)\n}\n\nfunc generateSourceInfoForOptionChildren(sci *sourceCodeInfo, n ast.ValueNode, pathPrefix, path []int32, childInfo OptionChildrenSourceInfo) {\n\tswitch childInfo := childInfo.(type) {\n\tcase *ArrayLiteralSourceInfo:\n\t\tif arrayLiteral, ok := n.(*ast.ArrayLiteralNode); ok {\n\t\t\tfor i, val := range arrayLiteral.Elements {\n\t\t\t\telementInfo := childInfo.Elements[i]\n\t\t\t\tfullPath := combinePathsForOption(pathPrefix, elementInfo.Path)\n\t\t\t\tsci.newLoc(val, fullPath)\n\t\t\t\tgenerateSourceInfoForOptionChildren(sci, val, pathPrefix, fullPath, elementInfo.Children)\n\t\t\t}\n\t\t}\n\tcase *MessageLiteralSourceInfo:\n\t\tif msgLiteral, ok := n.(*ast.MessageLiteralNode); ok {\n\t\t\tfor _, fieldNode := range msgLiteral.Elements {\n\t\t\t\tfieldInfo, ok := childInfo.Fields[fieldNode]\n\t\t\t\tif !ok {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfullPath := combinePathsForOption(pathPrefix, fieldInfo.Path)\n\t\t\t\tlocationNode := ast.Node(fieldNode)\n\t\t\t\tif fieldNode.Name.IsAnyTypeReference() && fullPath[len(fullPath)-1] == internal.AnyValueTag {\n\t\t\t\t\t// This is a special expanded Any. So also insert a location\n\t\t\t\t\t// for the type URL field.\n\t\t\t\t\ttypeURLPath := make([]int32, len(fullPath))\n\t\t\t\t\tcopy(typeURLPath, fullPath)\n\t\t\t\t\ttypeURLPath[len(typeURLPath)-1] = internal.AnyTypeURLTag\n\t\t\t\t\tsci.newLoc(fieldNode.Name, fullPath)\n\t\t\t\t\t// And create the next location so it's just the value,\n\t\t\t\t\t// not the full field definition.\n\t\t\t\t\tlocationNode = fieldNode.Val\n\t\t\t\t}\n\t\t\t\t_, isArrayLiteral := fieldNode.Val.(*ast.ArrayLiteralNode)\n\t\t\t\tif !isArrayLiteral {\n\t\t\t\t\t// We don't include this with an array literal since the path\n\t\t\t\t\t// is to the first element of the array. If we added it here,\n\t\t\t\t\t// it would be redundant with the child info we add next, and\n\t\t\t\t\t// it wouldn't be entirely correct since it only indicates the\n\t\t\t\t\t// index of the first element in the array (and not the others).\n\t\t\t\t\tsci.newLoc(locationNode, fullPath)\n\t\t\t\t}\n\t\t\t\tgenerateSourceInfoForOptionChildren(sci, fieldNode.Val, pathPrefix, fullPath, fieldInfo.Children)\n\t\t\t}\n\t\t}\n\tcase nil:\n\t\tif arrayLiteral, ok := n.(*ast.ArrayLiteralNode); ok {\n\t\t\t// an array literal without child source info is an array of scalars\n\t\t\tfor i, val := range arrayLiteral.Elements {\n\t\t\t\t// last element of path is starting index for array literal\n\t\t\t\telementPath := append(([]int32)(nil), path...)\n\t\t\t\telementPath[len(elementPath)-1] += int32(i)\n\t\t\t\tsci.newLoc(val, elementPath)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForMessage(opts OptionIndex, sci *sourceCodeInfo, n ast.MessageDeclNode, fieldPath []int32, path []int32) {\n\tvar openBrace ast.Node\n\n\tvar decls []ast.MessageElement\n\tswitch n := n.(type) {\n\tcase *ast.MessageNode:\n\t\topenBrace = n.OpenBrace\n\t\tdecls = n.Decls\n\tcase *ast.SyntheticGroupMessageNode:\n\t\topenBrace = n.OpenBrace\n\t\tdecls = n.Decls\n\tcase *ast.SyntheticMapEntryNode:\n\t\tsci.newLoc(n, path)\n\t\t// map entry so nothing else to do\n\t\treturn\n\t}\n\tsci.newBlockLocWithComments(n, openBrace, path)\n\n\tsci.newLoc(n.MessageName(), append(path, internal.MessageNameTag))\n\t// matching protoc, which emits the corresponding field type name (for group fields)\n\t// right after the source location for the group message name\n\tif fieldPath != nil {\n\t\tsci.newLoc(n.MessageName(), append(fieldPath, internal.FieldTypeNameTag))\n\t}\n\n\tvar optIndex, fieldIndex, oneofIndex, extendIndex, nestedMsgIndex int32\n\tvar nestedEnumIndex, extRangeIndex, reservedRangeIndex, reservedNameIndex int32\n\tfor _, child := range decls {\n\t\tswitch child := child.(type) {\n\t\tcase *ast.OptionNode:\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, child, false, &optIndex, append(path, internal.MessageOptionsTag))\n\t\tcase *ast.FieldNode:\n\t\t\tgenerateSourceCodeInfoForField(opts, sci, child, append(path, internal.MessageFieldsTag, fieldIndex))\n\t\t\tfieldIndex++\n\t\tcase *ast.GroupNode:\n\t\t\tfldPath := append(path, internal.MessageFieldsTag, fieldIndex) //nolint:gocritic // intentionally creating new slice var\n\t\t\tgenerateSourceCodeInfoForField(opts, sci, child, fldPath)\n\t\t\tfieldIndex++\n\t\t\t// we clone the path here so that append can't mutate fldPath, since they may share storage\n\t\t\tmsgPath := append(internal.ClonePath(path), internal.MessageNestedMessagesTag, nestedMsgIndex)\n\t\t\tgenerateSourceCodeInfoForMessage(opts, sci, child.AsMessage(), fldPath, msgPath)\n\t\t\tnestedMsgIndex++\n\t\tcase *ast.MapFieldNode:\n\t\t\tgenerateSourceCodeInfoForField(opts, sci, child, append(path, internal.MessageFieldsTag, fieldIndex))\n\t\t\tfieldIndex++\n\t\t\tnestedMsgIndex++\n\t\tcase *ast.OneofNode:\n\t\t\tfldsPath := append(path, internal.MessageFieldsTag) //nolint:gocritic // intentionally creating new slice var\n\t\t\t// we clone the path here and below so that append ops can't mutate\n\t\t\t// fldPath or msgsPath, since they may otherwise share storage\n\t\t\tmsgsPath := append(internal.ClonePath(path), internal.MessageNestedMessagesTag)\n\t\t\tooPath := append(internal.ClonePath(path), internal.MessageOneofsTag, oneofIndex)\n\t\t\tgenerateSourceCodeInfoForOneof(opts, sci, child, &fieldIndex, &nestedMsgIndex, fldsPath, msgsPath, ooPath)\n\t\t\toneofIndex++\n\t\tcase *ast.MessageNode:\n\t\t\tgenerateSourceCodeInfoForMessage(opts, sci, child, nil, append(path, internal.MessageNestedMessagesTag, nestedMsgIndex))\n\t\t\tnestedMsgIndex++\n\t\tcase *ast.EnumNode:\n\t\t\tgenerateSourceCodeInfoForEnum(opts, sci, child, append(path, internal.MessageEnumsTag, nestedEnumIndex))\n\t\t\tnestedEnumIndex++\n\t\tcase *ast.ExtendNode:\n\t\t\textsPath := append(path, internal.MessageExtensionsTag) //nolint:gocritic // intentionally creating new slice var\n\t\t\t// we clone the path here so that append can't mutate extsPath, since they may share storage\n\t\t\tmsgsPath := append(internal.ClonePath(path), internal.MessageNestedMessagesTag)\n\t\t\tgenerateSourceCodeInfoForExtensions(opts, sci, child, &extendIndex, &nestedMsgIndex, extsPath, msgsPath)\n\t\tcase *ast.ExtensionRangeNode:\n\t\t\tgenerateSourceCodeInfoForExtensionRanges(opts, sci, child, &extRangeIndex, append(path, internal.MessageExtensionRangesTag))\n\t\tcase *ast.ReservedNode:\n\t\t\tif len(child.Names) > 0 {\n\t\t\t\tresPath := path\n\t\t\t\tresPath = append(resPath, internal.MessageReservedNamesTag)\n\t\t\t\tsci.newLocWithComments(child, resPath)\n\t\t\t\tfor _, rn := range child.Names {\n\t\t\t\t\tsci.newLoc(rn, append(resPath, reservedNameIndex))\n\t\t\t\t\treservedNameIndex++\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(child.Ranges) > 0 {\n\t\t\t\tresPath := path\n\t\t\t\tresPath = append(resPath, internal.MessageReservedRangesTag)\n\t\t\t\tsci.newLocWithComments(child, resPath)\n\t\t\t\tfor _, rr := range child.Ranges {\n\t\t\t\t\tgenerateSourceCodeInfoForReservedRange(sci, rr, append(resPath, reservedRangeIndex))\n\t\t\t\t\treservedRangeIndex++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForEnum(opts OptionIndex, sci *sourceCodeInfo, n *ast.EnumNode, path []int32) {\n\tsci.newBlockLocWithComments(n, n.OpenBrace, path)\n\tsci.newLoc(n.Name, append(path, internal.EnumNameTag))\n\n\tvar optIndex, valIndex, reservedNameIndex, reservedRangeIndex int32\n\tfor _, child := range n.Decls {\n\t\tswitch child := child.(type) {\n\t\tcase *ast.OptionNode:\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, child, false, &optIndex, append(path, internal.EnumOptionsTag))\n\t\tcase *ast.EnumValueNode:\n\t\t\tgenerateSourceCodeInfoForEnumValue(opts, sci, child, append(path, internal.EnumValuesTag, valIndex))\n\t\t\tvalIndex++\n\t\tcase *ast.ReservedNode:\n\t\t\tif len(child.Names) > 0 {\n\t\t\t\tresPath := path\n\t\t\t\tresPath = append(resPath, internal.EnumReservedNamesTag)\n\t\t\t\tsci.newLocWithComments(child, resPath)\n\t\t\t\tfor _, rn := range child.Names {\n\t\t\t\t\tsci.newLoc(rn, append(resPath, reservedNameIndex))\n\t\t\t\t\treservedNameIndex++\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(child.Ranges) > 0 {\n\t\t\t\tresPath := path\n\t\t\t\tresPath = append(resPath, internal.EnumReservedRangesTag)\n\t\t\t\tsci.newLocWithComments(child, resPath)\n\t\t\t\tfor _, rr := range child.Ranges {\n\t\t\t\t\tgenerateSourceCodeInfoForReservedRange(sci, rr, append(resPath, reservedRangeIndex))\n\t\t\t\t\treservedRangeIndex++\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForEnumValue(opts OptionIndex, sci *sourceCodeInfo, n *ast.EnumValueNode, path []int32) {\n\tsci.newLocWithComments(n, path)\n\tsci.newLoc(n.Name, append(path, internal.EnumValNameTag))\n\tsci.newLoc(n.Number, append(path, internal.EnumValNumberTag))\n\n\t// enum value options\n\tif n.Options != nil {\n\t\toptsPath := path\n\t\toptsPath = append(optsPath, internal.EnumValOptionsTag)\n\t\tsci.newLoc(n.Options, optsPath)\n\t\tvar optIndex int32\n\t\tfor _, opt := range n.Options.GetElements() {\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, opt, true, &optIndex, optsPath)\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForReservedRange(sci *sourceCodeInfo, n *ast.RangeNode, path []int32) {\n\tsci.newLoc(n, path)\n\tsci.newLoc(n.StartVal, append(path, internal.ReservedRangeStartTag))\n\tswitch {\n\tcase n.EndVal != nil:\n\t\tsci.newLoc(n.EndVal, append(path, internal.ReservedRangeEndTag))\n\tcase n.Max != nil:\n\t\tsci.newLoc(n.Max, append(path, internal.ReservedRangeEndTag))\n\tdefault:\n\t\tsci.newLoc(n.StartVal, append(path, internal.ReservedRangeEndTag))\n\t}\n}\n\nfunc generateSourceCodeInfoForExtensions(opts OptionIndex, sci *sourceCodeInfo, n *ast.ExtendNode, extendIndex, msgIndex *int32, extendPath, msgPath []int32) {\n\tsci.newBlockLocWithComments(n, n.OpenBrace, extendPath)\n\tfor _, decl := range n.Decls {\n\t\tswitch decl := decl.(type) {\n\t\tcase *ast.FieldNode:\n\t\t\tgenerateSourceCodeInfoForField(opts, sci, decl, append(extendPath, *extendIndex))\n\t\t\t*extendIndex++\n\t\tcase *ast.GroupNode:\n\t\t\tfldPath := extendPath\n\t\t\tfldPath = append(fldPath, *extendIndex)\n\t\t\tgenerateSourceCodeInfoForField(opts, sci, decl, fldPath)\n\t\t\t*extendIndex++\n\t\t\tgenerateSourceCodeInfoForMessage(opts, sci, decl.AsMessage(), fldPath, append(msgPath, *msgIndex))\n\t\t\t*msgIndex++\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForOneof(opts OptionIndex, sci *sourceCodeInfo, n *ast.OneofNode, fieldIndex, nestedMsgIndex *int32, fieldPath, nestedMsgPath, oneofPath []int32) {\n\tsci.newBlockLocWithComments(n, n.OpenBrace, oneofPath)\n\tsci.newLoc(n.Name, append(oneofPath, internal.OneofNameTag))\n\n\tvar optIndex int32\n\tfor _, child := range n.Decls {\n\t\tswitch child := child.(type) {\n\t\tcase *ast.OptionNode:\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, child, false, &optIndex, append(oneofPath, internal.OneofOptionsTag))\n\t\tcase *ast.FieldNode:\n\t\t\tgenerateSourceCodeInfoForField(opts, sci, child, append(fieldPath, *fieldIndex))\n\t\t\t*fieldIndex++\n\t\tcase *ast.GroupNode:\n\t\t\tfldPath := fieldPath\n\t\t\tfldPath = append(fldPath, *fieldIndex)\n\t\t\tgenerateSourceCodeInfoForField(opts, sci, child, fldPath)\n\t\t\t*fieldIndex++\n\t\t\tgenerateSourceCodeInfoForMessage(opts, sci, child.AsMessage(), fldPath, append(nestedMsgPath, *nestedMsgIndex))\n\t\t\t*nestedMsgIndex++\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForField(opts OptionIndex, sci *sourceCodeInfo, n ast.FieldDeclNode, path []int32) {\n\tvar fieldType string\n\tif f, ok := n.(*ast.FieldNode); ok {\n\t\tfieldType = string(f.FldType.AsIdentifier())\n\t}\n\n\tif n.GetGroupKeyword() != nil {\n\t\t// comments will appear on group message\n\t\tsci.newLocWithoutComments(n, path)\n\t\tif n.FieldExtendee() != nil {\n\t\t\tsci.newLoc(n.FieldExtendee(), append(path, internal.FieldExtendeeTag))\n\t\t}\n\t\tif n.FieldLabel() != nil {\n\t\t\t// no comments here either (label is first token for group, so we want\n\t\t\t// to leave the comments to be associated with the group message instead)\n\t\t\tsci.newLocWithoutComments(n.FieldLabel(), append(path, internal.FieldLabelTag))\n\t\t}\n\t\tsci.newLoc(n.FieldType(), append(path, internal.FieldTypeTag))\n\t\t// let the name comments be attributed to the group name\n\t\tsci.newLocWithoutComments(n.FieldName(), append(path, internal.FieldNameTag))\n\t} else {\n\t\tsci.newLocWithComments(n, path)\n\t\tif n.FieldExtendee() != nil {\n\t\t\tsci.newLoc(n.FieldExtendee(), append(path, internal.FieldExtendeeTag))\n\t\t}\n\t\tif n.FieldLabel() != nil {\n\t\t\tsci.newLoc(n.FieldLabel(), append(path, internal.FieldLabelTag))\n\t\t}\n\t\tvar tag int32\n\t\tif _, isScalar := internal.FieldTypes[fieldType]; isScalar {\n\t\t\ttag = internal.FieldTypeTag\n\t\t} else {\n\t\t\t// this is a message or an enum, so attribute type location\n\t\t\t// to the type name field\n\t\t\ttag = internal.FieldTypeNameTag\n\t\t}\n\t\tsci.newLoc(n.FieldType(), append(path, tag))\n\t\tsci.newLoc(n.FieldName(), append(path, internal.FieldNameTag))\n\t}\n\tsci.newLoc(n.FieldTag(), append(path, internal.FieldNumberTag))\n\n\tif n.GetOptions() != nil {\n\t\toptsPath := path\n\t\toptsPath = append(optsPath, internal.FieldOptionsTag)\n\t\tsci.newLoc(n.GetOptions(), optsPath)\n\t\tvar optIndex int32\n\t\tfor _, opt := range n.GetOptions().GetElements() {\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, opt, true, &optIndex, optsPath)\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForExtensionRanges(opts OptionIndex, sci *sourceCodeInfo, n *ast.ExtensionRangeNode, extRangeIndex *int32, path []int32) {\n\tsci.newLocWithComments(n, path)\n\tstartExtRangeIndex := *extRangeIndex\n\tfor _, child := range n.Ranges {\n\t\tpath := append(path, *extRangeIndex)\n\t\t*extRangeIndex++\n\t\tsci.newLoc(child, path)\n\t\tsci.newLoc(child.StartVal, append(path, internal.ExtensionRangeStartTag))\n\t\tswitch {\n\t\tcase child.EndVal != nil:\n\t\t\tsci.newLoc(child.EndVal, append(path, internal.ExtensionRangeEndTag))\n\t\tcase child.Max != nil:\n\t\t\tsci.newLoc(child.Max, append(path, internal.ExtensionRangeEndTag))\n\t\tdefault:\n\t\t\tsci.newLoc(child.StartVal, append(path, internal.ExtensionRangeEndTag))\n\t\t}\n\t}\n\t// options for all ranges go after the start+end values\n\tfor range n.Ranges {\n\t\tpath := append(path, startExtRangeIndex)\n\t\tstartExtRangeIndex++\n\t\tif n.Options != nil {\n\t\t\toptsPath := path\n\t\t\toptsPath = append(optsPath, internal.ExtensionRangeOptionsTag)\n\t\t\tsci.newLoc(n.Options, optsPath)\n\t\t\tvar optIndex int32\n\t\t\tfor _, opt := range n.Options.GetElements() {\n\t\t\t\tgenerateSourceCodeInfoForOption(opts, sci, opt, true, &optIndex, optsPath)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForService(opts OptionIndex, sci *sourceCodeInfo, n *ast.ServiceNode, path []int32) {\n\tsci.newBlockLocWithComments(n, n.OpenBrace, path)\n\tsci.newLoc(n.Name, append(path, internal.ServiceNameTag))\n\tvar optIndex, rpcIndex int32\n\tfor _, child := range n.Decls {\n\t\tswitch child := child.(type) {\n\t\tcase *ast.OptionNode:\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, child, false, &optIndex, append(path, internal.ServiceOptionsTag))\n\t\tcase *ast.RPCNode:\n\t\t\tgenerateSourceCodeInfoForMethod(opts, sci, child, append(path, internal.ServiceMethodsTag, rpcIndex))\n\t\t\trpcIndex++\n\t\t}\n\t}\n}\n\nfunc generateSourceCodeInfoForMethod(opts OptionIndex, sci *sourceCodeInfo, n *ast.RPCNode, path []int32) {\n\tif n.OpenBrace != nil {\n\t\tsci.newBlockLocWithComments(n, n.OpenBrace, path)\n\t} else {\n\t\tsci.newLocWithComments(n, path)\n\t}\n\tsci.newLoc(n.Name, append(path, internal.MethodNameTag))\n\tif n.Input.Stream != nil {\n\t\tsci.newLoc(n.Input.Stream, append(path, internal.MethodInputStreamTag))\n\t}\n\tsci.newLoc(n.Input.MessageType, append(path, internal.MethodInputTag))\n\tif n.Output.Stream != nil {\n\t\tsci.newLoc(n.Output.Stream, append(path, internal.MethodOutputStreamTag))\n\t}\n\tsci.newLoc(n.Output.MessageType, append(path, internal.MethodOutputTag))\n\n\toptsPath := path\n\toptsPath = append(optsPath, internal.MethodOptionsTag)\n\tvar optIndex int32\n\tfor _, decl := range n.Decls {\n\t\tif opt, ok := decl.(*ast.OptionNode); ok {\n\t\t\tgenerateSourceCodeInfoForOption(opts, sci, opt, false, &optIndex, optsPath)\n\t\t}\n\t}\n}\n\ntype sourceCodeInfo struct {\n\tfile            *ast.FileNode\n\textraComments   bool\n\textraOptionLocs bool\n\tlocs            []*descriptorpb.SourceCodeInfo_Location\n\tcommentsUsed    map[ast.SourcePos]struct{}\n}\n\nfunc (sci *sourceCodeInfo) newLocWithoutComments(n ast.Node, path []int32) {\n\tvar start, end ast.SourcePos\n\tif n == sci.file {\n\t\t// For files, we don't want to consider trailing EOF token\n\t\t// as part of the span. We want the span to only include\n\t\t// actual lexical elements in the file (which also excludes\n\t\t// whitespace and comments).\n\t\tchildren := sci.file.Children()\n\t\tif len(children) > 0 && isEOF(children[len(children)-1]) {\n\t\t\tchildren = children[:len(children)-1]\n\t\t}\n\t\tif len(children) == 0 {\n\t\t\tstart = ast.SourcePos{Filename: sci.file.Name(), Line: 1, Col: 1}\n\t\t\tend = start\n\t\t} else {\n\t\t\tstart = sci.file.TokenInfo(n.Start()).Start()\n\t\t\tend = sci.file.TokenInfo(children[len(children)-1].End()).End()\n\t\t}\n\t} else {\n\t\tinfo := sci.file.NodeInfo(n)\n\t\tstart, end = info.Start(), info.End()\n\t}\n\tsci.locs = append(sci.locs, &descriptorpb.SourceCodeInfo_Location{\n\t\tPath: internal.ClonePath(path),\n\t\tSpan: makeSpan(start, end),\n\t})\n}\n\nfunc (sci *sourceCodeInfo) newLoc(n ast.Node, path []int32) {\n\tinfo := sci.file.NodeInfo(n)\n\tif !sci.extraComments {\n\t\tstart, end := info.Start(), info.End()\n\t\tsci.locs = append(sci.locs, &descriptorpb.SourceCodeInfo_Location{\n\t\t\tPath: internal.ClonePath(path),\n\t\t\tSpan: makeSpan(start, end),\n\t\t})\n\t} else {\n\t\tdetachedComments, leadingComments := sci.getLeadingComments(n)\n\t\ttrailingComments := sci.getTrailingComments(n)\n\t\tsci.newLocWithGivenComments(info, detachedComments, leadingComments, trailingComments, path)\n\t}\n}\n\nfunc isEOF(n ast.Node) bool {\n\tr, ok := n.(*ast.RuneNode)\n\treturn ok && r.Rune == 0\n}\n\nfunc (sci *sourceCodeInfo) newBlockLocWithComments(n, openBrace ast.Node, path []int32) {\n\t// Block definitions use trailing comments after the open brace \"{\" as the\n\t// element's trailing comments. For example:\n\t//\n\t//    message Foo { // this is a trailing comment for a message\n\t//\n\t//    }             // not this\n\t//\n\tnodeInfo := sci.file.NodeInfo(n)\n\tdetachedComments, leadingComments := sci.getLeadingComments(n)\n\ttrailingComments := sci.getTrailingComments(openBrace)\n\tsci.newLocWithGivenComments(nodeInfo, detachedComments, leadingComments, trailingComments, path)\n}\n\nfunc (sci *sourceCodeInfo) newLocWithComments(n ast.Node, path []int32) {\n\tnodeInfo := sci.file.NodeInfo(n)\n\tdetachedComments, leadingComments := sci.getLeadingComments(n)\n\ttrailingComments := sci.getTrailingComments(n)\n\tsci.newLocWithGivenComments(nodeInfo, detachedComments, leadingComments, trailingComments, path)\n}\n\nfunc (sci *sourceCodeInfo) newLocWithGivenComments(nodeInfo ast.NodeInfo, detachedComments []comments, leadingComments comments, trailingComments comments, path []int32) {\n\tif (len(detachedComments) > 0 && sci.commentUsed(detachedComments[0])) ||\n\t\t(len(detachedComments) == 0 && sci.commentUsed(leadingComments)) {\n\t\tdetachedComments = nil\n\t\tleadingComments = ast.EmptyComments\n\t}\n\tif sci.commentUsed(trailingComments) {\n\t\ttrailingComments = ast.EmptyComments\n\t}\n\n\tvar trail *string\n\tif trailingComments.Len() > 0 {\n\t\ttrail = proto.String(sci.combineComments(trailingComments))\n\t}\n\n\tvar lead *string\n\tif leadingComments.Len() > 0 {\n\t\tlead = proto.String(sci.combineComments(leadingComments))\n\t}\n\n\tdetached := make([]string, len(detachedComments))\n\tfor i, cmts := range detachedComments {\n\t\tdetached[i] = sci.combineComments(cmts)\n\t}\n\n\tsci.locs = append(sci.locs, &descriptorpb.SourceCodeInfo_Location{\n\t\tLeadingDetachedComments: detached,\n\t\tLeadingComments:         lead,\n\t\tTrailingComments:        trail,\n\t\tPath:                    internal.ClonePath(path),\n\t\tSpan:                    makeSpan(nodeInfo.Start(), nodeInfo.End()),\n\t})\n}\n\ntype comments interface {\n\tLen() int\n\tIndex(int) ast.Comment\n}\n\ntype subComments struct {\n\toffs, n int\n\tc       ast.Comments\n}\n\nfunc (s subComments) Len() int {\n\treturn s.n\n}\n\nfunc (s subComments) Index(i int) ast.Comment {\n\tif i < 0 || i >= s.n {\n\t\tpanic(fmt.Errorf(\"runtime error: index out of range [%d] with length %d\", i, s.n))\n\t}\n\treturn s.c.Index(i + s.offs)\n}\n\nfunc (sci *sourceCodeInfo) getLeadingComments(n ast.Node) ([]comments, comments) {\n\ts := n.Start()\n\tinfo := sci.file.TokenInfo(s)\n\tvar prevInfo ast.NodeInfo\n\tif prev, ok := sci.file.Tokens().Previous(s); ok {\n\t\tprevInfo = sci.file.TokenInfo(prev)\n\t}\n\t_, d, l := sci.attributeComments(prevInfo, info)\n\treturn d, l\n}\n\nfunc (sci *sourceCodeInfo) getTrailingComments(n ast.Node) comments {\n\te := n.End()\n\tnext, ok := sci.file.Tokens().Next(e)\n\tif !ok {\n\t\treturn ast.EmptyComments\n\t}\n\tinfo := sci.file.TokenInfo(e)\n\tnextInfo := sci.file.TokenInfo(next)\n\tt, _, _ := sci.attributeComments(info, nextInfo)\n\treturn t\n}\n\nfunc (sci *sourceCodeInfo) attributeComments(prevInfo, info ast.NodeInfo) (t comments, d []comments, l comments) {\n\tdetached := groupComments(info.LeadingComments())\n\tvar trail comments\n\tif prevInfo.IsValid() {\n\t\ttrail = comments(prevInfo.TrailingComments())\n\t\tif trail.Len() == 0 {\n\t\t\ttrail, detached = sci.maybeDonate(prevInfo, info, detached)\n\t\t}\n\t} else {\n\t\ttrail = ast.EmptyComments\n\t}\n\tdetached, lead := sci.maybeAttach(prevInfo, info, trail.Len() > 0, detached)\n\treturn trail, detached, lead\n}\n\nfunc (sci *sourceCodeInfo) maybeDonate(prevInfo ast.NodeInfo, info ast.NodeInfo, lead []comments) (t comments, l []comments) {\n\tif len(lead) == 0 {\n\t\t// nothing to donate\n\t\treturn ast.EmptyComments, nil\n\t}\n\tfirstCommentPos := lead[0].Index(0)\n\tif firstCommentPos.Start().Line > prevInfo.End().Line+1 {\n\t\t// first comment is detached from previous token, so can't be a trailing comment\n\t\treturn ast.EmptyComments, lead\n\t}\n\tif len(lead) > 1 {\n\t\t// multiple groups? then donate first comment to previous token\n\t\treturn lead[0], lead[1:]\n\t}\n\t// there is only one element in lead\n\tcomment := lead[0]\n\tlastCommentPos := comment.Index(comment.Len() - 1)\n\tif lastCommentPos.End().Line < info.Start().Line-1 {\n\t\t// there is a blank line between the comments and subsequent token, so\n\t\t// we can donate the comment to previous token\n\t\treturn comment, nil\n\t}\n\tif txt := info.RawText(); txt == \"\" || (len(txt) == 1 && strings.ContainsAny(txt, \"}]),;\")) {\n\t\t// token is a symbol for the end of a scope or EOF, which doesn't need a leading comment\n\t\tif !sci.extraComments && txt != \"\" &&\n\t\t\tfirstCommentPos.Start().Line == prevInfo.End().Line &&\n\t\t\tlastCommentPos.End().Line == info.Start().Line {\n\t\t\t// protoc does not donate if prev and next token are on the same line since it's\n\t\t\t// ambiguous which one should get the comment; so we mirror that here\n\t\t\treturn ast.EmptyComments, lead\n\t\t}\n\t\t// But with extra comments, we always donate in this situation in order to capture\n\t\t// more comments. Because otherwise, these comments are lost since these symbols\n\t\t// don't map to a location in source code info.\n\t\treturn comment, nil\n\t}\n\t// cannot donate\n\treturn ast.EmptyComments, lead\n}\n\nfunc (sci *sourceCodeInfo) maybeAttach(prevInfo ast.NodeInfo, info ast.NodeInfo, hasTrail bool, lead []comments) (d []comments, l comments) {\n\tif len(lead) == 0 {\n\t\treturn nil, ast.EmptyComments\n\t}\n\n\tif len(lead) == 1 && !hasTrail && prevInfo.IsValid() {\n\t\t// If the one comment appears attached to both previous and next tokens,\n\t\t// don't attach to either.\n\t\tcomment := lead[0]\n\t\tattachedToPrevious := comment.Index(0).Start().Line == prevInfo.End().Line\n\t\tattachedToNext := comment.Index(comment.Len()-1).End().Line == info.Start().Line\n\t\tif attachedToPrevious && attachedToNext {\n\t\t\t// Since attachment is ambiguous, leave it detached.\n\t\t\treturn lead, ast.EmptyComments\n\t\t}\n\t}\n\n\tlastComment := lead[len(lead)-1]\n\tif lastComment.Index(lastComment.Len()-1).End().Line >= info.Start().Line-1 {\n\t\treturn lead[:len(lead)-1], lastComment\n\t}\n\n\treturn lead, ast.EmptyComments\n}\n\nfunc makeSpan(start, end ast.SourcePos) []int32 {\n\tif start.Line == end.Line {\n\t\treturn []int32{int32(start.Line) - 1, int32(start.Col) - 1, int32(end.Col) - 1}\n\t}\n\treturn []int32{int32(start.Line) - 1, int32(start.Col) - 1, int32(end.Line) - 1, int32(end.Col) - 1}\n}\n\nfunc (sci *sourceCodeInfo) commentUsed(c comments) bool {\n\tif c.Len() == 0 {\n\t\treturn false\n\t}\n\tpos := c.Index(0).Start()\n\tif _, ok := sci.commentsUsed[pos]; ok {\n\t\treturn true\n\t}\n\n\tsci.commentsUsed[pos] = struct{}{}\n\treturn false\n}\n\nfunc groupComments(cmts ast.Comments) []comments {\n\tif cmts.Len() == 0 {\n\t\treturn nil\n\t}\n\tvar groups []comments\n\tsingleLineStyle := cmts.Index(0).RawText()[:2] == \"//\"\n\tline := cmts.Index(0).End().Line\n\tstart := 0\n\tfor i := 1; i < cmts.Len(); i++ {\n\t\tc := cmts.Index(i)\n\t\tprevSingleLine := singleLineStyle\n\t\tsingleLineStyle = strings.HasPrefix(c.RawText(), \"//\")\n\t\tif !singleLineStyle || prevSingleLine != singleLineStyle || c.Start().Line > line+1 {\n\t\t\t// new group!\n\t\t\tgroups = append(groups, subComments{offs: start, n: i - start, c: cmts})\n\t\t\tstart = i\n\t\t}\n\t\tline = c.End().Line\n\t}\n\t// don't forget last group\n\tgroups = append(groups, subComments{offs: start, n: cmts.Len() - start, c: cmts})\n\treturn groups\n}\n\nfunc (sci *sourceCodeInfo) combineComments(comments comments) string {\n\tif comments.Len() == 0 {\n\t\treturn \"\"\n\t}\n\tvar buf bytes.Buffer\n\tfor i, l := 0, comments.Len(); i < l; i++ {\n\t\tc := comments.Index(i)\n\t\ttxt := c.RawText()\n\t\tif txt[:2] == \"//\" {\n\t\t\tbuf.WriteString(txt[2:])\n\t\t\t// protoc includes trailing newline for line comments,\n\t\t\t// but it's not present in the AST comment. So we need\n\t\t\t// to add it if present.\n\t\t\tif i, ok := sci.file.Items().Next(c.AsItem()); ok {\n\t\t\t\tinfo := sci.file.ItemInfo(i)\n\t\t\t\tif strings.HasPrefix(info.LeadingWhitespace(), \"\\n\") {\n\t\t\t\t\tbuf.WriteRune('\\n')\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlines := strings.Split(txt[2:len(txt)-2], \"\\n\")\n\t\t\tfirst := true\n\t\t\tfor _, l := range lines {\n\t\t\t\tif first {\n\t\t\t\t\tfirst = false\n\t\t\t\t\tbuf.WriteString(l)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tbuf.WriteByte('\\n')\n\n\t\t\t\t// strip a prefix of whitespace followed by '*'\n\t\t\t\tj := 0\n\t\t\t\tfor j < len(l) {\n\t\t\t\t\tif l[j] != ' ' && l[j] != '\\t' {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tj++\n\t\t\t\t}\n\t\t\t\tswitch {\n\t\t\t\tcase j == len(l):\n\t\t\t\t\tl = \"\"\n\t\t\t\tcase l[j] == '*':\n\t\t\t\t\tl = l[j+1:]\n\t\t\t\tcase j > 0:\n\t\t\t\t\tl = l[j:]\n\t\t\t\t}\n\n\t\t\t\tbuf.WriteString(l)\n\t\t\t}\n\t\t}\n\t}\n\treturn buf.String()\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/std_imports.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage protocompile\n\nimport (\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/reflect/protoregistry\"\n\t_ \"google.golang.org/protobuf/types/gofeaturespb\" // link in packages that include the standard protos included with protoc.\n\t_ \"google.golang.org/protobuf/types/known/anypb\"\n\t_ \"google.golang.org/protobuf/types/known/apipb\"\n\t_ \"google.golang.org/protobuf/types/known/durationpb\"\n\t_ \"google.golang.org/protobuf/types/known/emptypb\"\n\t_ \"google.golang.org/protobuf/types/known/fieldmaskpb\"\n\t_ \"google.golang.org/protobuf/types/known/sourcecontextpb\"\n\t_ \"google.golang.org/protobuf/types/known/structpb\"\n\t_ \"google.golang.org/protobuf/types/known/timestamppb\"\n\t_ \"google.golang.org/protobuf/types/known/typepb\"\n\t_ \"google.golang.org/protobuf/types/known/wrapperspb\"\n\t_ \"google.golang.org/protobuf/types/pluginpb\"\n\n\t\"github.com/bufbuild/protocompile/internal/featuresext\"\n)\n\n// All files that are included with protoc are also included with this package\n// so that clients do not need to explicitly supply a copy of these protos (just\n// like callers of protoc do not need to supply them).\nvar standardImports map[string]protoreflect.FileDescriptor\n\nfunc init() {\n\tstandardFilenames := []string{\n\t\t\"google/protobuf/any.proto\",\n\t\t\"google/protobuf/api.proto\",\n\t\t\"google/protobuf/compiler/plugin.proto\",\n\t\t\"google/protobuf/descriptor.proto\",\n\t\t\"google/protobuf/duration.proto\",\n\t\t\"google/protobuf/empty.proto\",\n\t\t\"google/protobuf/field_mask.proto\",\n\t\t\"google/protobuf/go_features.proto\",\n\t\t\"google/protobuf/source_context.proto\",\n\t\t\"google/protobuf/struct.proto\",\n\t\t\"google/protobuf/timestamp.proto\",\n\t\t\"google/protobuf/type.proto\",\n\t\t\"google/protobuf/wrappers.proto\",\n\t}\n\n\tstandardImports = map[string]protoreflect.FileDescriptor{}\n\tfor _, fn := range standardFilenames {\n\t\tfd, err := protoregistry.GlobalFiles.FindFileByPath(fn)\n\t\tif err != nil {\n\t\t\tpanic(err.Error())\n\t\t}\n\t\tstandardImports[fn] = fd\n\t}\n\n\totherFeatures := []struct {\n\t\tName          string\n\t\tGetDescriptor func() (protoreflect.FileDescriptor, error)\n\t}{\n\t\t{\n\t\t\tName:          \"google/protobuf/cpp_features.proto\",\n\t\t\tGetDescriptor: featuresext.CppFeaturesDescriptor,\n\t\t},\n\t\t{\n\t\t\tName:          \"google/protobuf/java_features.proto\",\n\t\t\tGetDescriptor: featuresext.JavaFeaturesDescriptor,\n\t\t},\n\t}\n\tfor _, feature := range otherFeatures {\n\t\t// First see if the program has generated Go code for this\n\t\t// file linked in:\n\t\tfd, err := protoregistry.GlobalFiles.FindFileByPath(feature.Name)\n\t\tif err == nil {\n\t\t\tstandardImports[feature.Name] = fd\n\t\t\tcontinue\n\t\t}\n\t\tfd, err = feature.GetDescriptor()\n\t\tif err != nil {\n\t\t\t// For these extensions to FeatureSet, we are lenient. If\n\t\t\t// we can't load them, just ignore them.\n\t\t\tcontinue\n\t\t}\n\t\tstandardImports[feature.Name] = fd\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/supported_editions.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage protocompile\n\nimport (\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/internal/editions\"\n)\n\n// IsEditionSupported returns true if this module can compile sources for\n// the given edition. This returns true for the special EDITION_PROTO2 and\n// EDITION_PROTO3 as well as all actual editions supported.\nfunc IsEditionSupported(edition descriptorpb.Edition) bool {\n\treturn edition == descriptorpb.Edition_EDITION_PROTO2 ||\n\t\tedition == descriptorpb.Edition_EDITION_PROTO3 ||\n\t\t(edition >= editions.MinSupportedEdition && edition <= editions.MaxSupportedEdition)\n}\n"
  },
  {
    "path": "vendor/github.com/bufbuild/protocompile/walk/walk.go",
    "content": "// Copyright 2020-2024 Buf Technologies, Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n// Package walk provides helper functions for traversing all elements in a\n// protobuf file descriptor. There are versions both for traversing \"rich\"\n// descriptors (protoreflect.Descriptor) and for traversing the underlying\n// \"raw\" descriptor protos.\n//\n// # Enter And Exit\n//\n// This package includes variants of the functions that accept two callback\n// functions. These variants have names ending with \"EnterAndExit\". One function\n// is called as each element is visited (\"enter\") and the other is called after\n// the element and all of its descendants have been visited (\"exit\"). This\n// can be useful when you need to track state that is scoped to the visitation\n// of a single element.\n//\n// # Source Path\n//\n// When traversing raw descriptor protos, this package include variants whose\n// callback accepts a protoreflect.SourcePath. These variants have names that\n// include \"WithPath\". This path can be used to locate corresponding data in the\n// file's source code info (if present).\npackage walk\n\nimport (\n\t\"google.golang.org/protobuf/proto\"\n\t\"google.golang.org/protobuf/reflect/protoreflect\"\n\t\"google.golang.org/protobuf/types/descriptorpb\"\n\n\t\"github.com/bufbuild/protocompile/internal\"\n)\n\n// Descriptors walks all descriptors in the given file using a depth-first\n// traversal, calling the given function for each descriptor in the hierarchy.\n// The walk ends when traversal is complete or when the function returns an\n// error. If the function returns an error, that is returned as the result of the\n// walk operation.\n//\n// Descriptors are visited using a pre-order traversal, where the function is\n// called for a descriptor before it is called for any of its descendants.\nfunc Descriptors(file protoreflect.FileDescriptor, fn func(protoreflect.Descriptor) error) error {\n\treturn DescriptorsEnterAndExit(file, fn, nil)\n}\n\n// DescriptorsEnterAndExit walks all descriptors in the given file using a\n// depth-first traversal, calling the given functions on entry and on exit\n// for each descriptor in the hierarchy. The walk ends when traversal is\n// complete or when a function returns an error. If a function returns an error,\n// that is returned as the result of the walk operation.\n//\n// The enter function is called using a pre-order traversal, where the function\n// is called for a descriptor before it is called for any of its descendants.\n// The exit function is called using a post-order traversal, where the function\n// is called for a descriptor only after it is called for any descendants.\nfunc DescriptorsEnterAndExit(file protoreflect.FileDescriptor, enter, exit func(protoreflect.Descriptor) error) error {\n\tif err := walkContainer(file, enter, exit); err != nil {\n\t\treturn err\n\t}\n\tservices := file.Services()\n\tfor i, length := 0, services.Len(); i < length; i++ {\n\t\tsvc := services.Get(i)\n\t\tif err := enter(svc); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tmethods := svc.Methods()\n\t\tfor i, length := 0, methods.Len(); i < length; i++ {\n\t\t\tmtd := methods.Get(i)\n\t\t\tif err := enter(mtd); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif exit != nil {\n\t\t\t\tif err := exit(mtd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif exit != nil {\n\t\t\tif err := exit(svc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\ntype container interface {\n\tMessages() protoreflect.MessageDescriptors\n\tEnums() protoreflect.EnumDescriptors\n\tExtensions() protoreflect.ExtensionDescriptors\n}\n\nfunc walkContainer(container container, enter, exit func(protoreflect.Descriptor) error) error {\n\tmessages := container.Messages()\n\tfor i, length := 0, messages.Len(); i < length; i++ {\n\t\tmsg := messages.Get(i)\n\t\tif err := messageDescriptor(msg, enter, exit); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tenums := container.Enums()\n\tfor i, length := 0, enums.Len(); i < length; i++ {\n\t\ten := enums.Get(i)\n\t\tif err := enumDescriptor(en, enter, exit); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\texts := container.Extensions()\n\tfor i, length := 0, exts.Len(); i < length; i++ {\n\t\text := exts.Get(i)\n\t\tif err := enter(ext); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif exit != nil {\n\t\t\tif err := exit(ext); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc messageDescriptor(msg protoreflect.MessageDescriptor, enter, exit func(protoreflect.Descriptor) error) error {\n\tif err := enter(msg); err != nil {\n\t\treturn err\n\t}\n\tfields := msg.Fields()\n\tfor i, length := 0, fields.Len(); i < length; i++ {\n\t\tfld := fields.Get(i)\n\t\tif err := enter(fld); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif exit != nil {\n\t\t\tif err := exit(fld); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\toneofs := msg.Oneofs()\n\tfor i, length := 0, oneofs.Len(); i < length; i++ {\n\t\too := oneofs.Get(i)\n\t\tif err := enter(oo); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif exit != nil {\n\t\t\tif err := exit(oo); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif err := walkContainer(msg, enter, exit); err != nil {\n\t\treturn err\n\t}\n\tif exit != nil {\n\t\tif err := exit(msg); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc enumDescriptor(en protoreflect.EnumDescriptor, enter, exit func(protoreflect.Descriptor) error) error {\n\tif err := enter(en); err != nil {\n\t\treturn err\n\t}\n\tvals := en.Values()\n\tfor i, length := 0, vals.Len(); i < length; i++ {\n\t\tenVal := vals.Get(i)\n\t\tif err := enter(enVal); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif exit != nil {\n\t\t\tif err := exit(enVal); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif exit != nil {\n\t\tif err := exit(en); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\n// DescriptorProtosWithPath walks all descriptor protos in the given file using\n// a depth-first traversal. This is the same as DescriptorProtos except that the\n// callback function, fn, receives a protoreflect.SourcePath, that indicates the\n// path for the element in the file's source code info.\nfunc DescriptorProtosWithPath(file *descriptorpb.FileDescriptorProto, fn func(protoreflect.FullName, protoreflect.SourcePath, proto.Message) error) error {\n\treturn DescriptorProtosWithPathEnterAndExit(file, fn, nil)\n}\n\n// DescriptorProtosWithPathEnterAndExit walks all descriptor protos in the given\n// file using a depth-first traversal. This is the same as\n// DescriptorProtosEnterAndExit except that the callback function, fn, receives\n// a protoreflect.SourcePath, that indicates the path for the element in the\n// file's source code info.\nfunc DescriptorProtosWithPathEnterAndExit(file *descriptorpb.FileDescriptorProto, enter, exit func(protoreflect.FullName, protoreflect.SourcePath, proto.Message) error) error {\n\tw := &protoWalker{usePath: true, enter: enter, exit: exit}\n\treturn w.walkDescriptorProtos(file)\n}\n\n// DescriptorProtos walks all descriptor protos in the given file using a\n// depth-first traversal, calling the given function for each descriptor proto\n// in the hierarchy. The walk ends when traversal is complete or when the\n// function returns an error. If the function returns an error, that is\n// returned as the result of the walk operation.\n//\n// Descriptor protos are visited using a pre-order traversal, where the function\n// is called for a descriptor before it is called for any of its descendants.\nfunc DescriptorProtos(file *descriptorpb.FileDescriptorProto, fn func(protoreflect.FullName, proto.Message) error) error {\n\treturn DescriptorProtosEnterAndExit(file, fn, nil)\n}\n\n// DescriptorProtosEnterAndExit walks all descriptor protos in the given file\n// using a depth-first traversal, calling the given functions on entry and on\n// exit for each descriptor in the hierarchy. The walk ends when traversal is\n// complete or when a function returns an error. If a function returns an error,\n// that is returned as the result of the walk operation.\n//\n// The enter function is called using a pre-order traversal, where the function\n// is called for a descriptor proto before it is called for any of its\n// descendants. The exit function is called using a post-order traversal, where\n// the function is called for a descriptor proto only after it is called for any\n// descendants.\nfunc DescriptorProtosEnterAndExit(file *descriptorpb.FileDescriptorProto, enter, exit func(protoreflect.FullName, proto.Message) error) error {\n\tenterWithPath := func(n protoreflect.FullName, _ protoreflect.SourcePath, m proto.Message) error {\n\t\treturn enter(n, m)\n\t}\n\tvar exitWithPath func(protoreflect.FullName, protoreflect.SourcePath, proto.Message) error\n\tif exit != nil {\n\t\texitWithPath = func(n protoreflect.FullName, _ protoreflect.SourcePath, m proto.Message) error {\n\t\t\treturn exit(n, m)\n\t\t}\n\t}\n\tw := &protoWalker{\n\t\tenter: enterWithPath,\n\t\texit:  exitWithPath,\n\t}\n\treturn w.walkDescriptorProtos(file)\n}\n\ntype protoWalker struct {\n\tusePath     bool\n\tenter, exit func(protoreflect.FullName, protoreflect.SourcePath, proto.Message) error\n}\n\nfunc (w *protoWalker) walkDescriptorProtos(file *descriptorpb.FileDescriptorProto) error {\n\tprefix := file.GetPackage()\n\tif prefix != \"\" {\n\t\tprefix += \".\"\n\t}\n\tvar path protoreflect.SourcePath\n\tfor i, msg := range file.MessageType {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.FileMessagesTag, int32(i))\n\t\t}\n\t\tif err := w.walkDescriptorProto(prefix, p, msg); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i, en := range file.EnumType {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.FileEnumsTag, int32(i))\n\t\t}\n\t\tif err := w.walkEnumDescriptorProto(prefix, p, en); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i, ext := range file.Extension {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.FileExtensionsTag, int32(i))\n\t\t}\n\t\tfqn := prefix + ext.GetName()\n\t\tif err := w.enter(protoreflect.FullName(fqn), p, ext); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif w.exit != nil {\n\t\t\tif err := w.exit(protoreflect.FullName(fqn), p, ext); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tfor i, svc := range file.Service {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.FileServicesTag, int32(i))\n\t\t}\n\t\tfqn := prefix + svc.GetName()\n\t\tif err := w.enter(protoreflect.FullName(fqn), p, svc); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tfor j, mtd := range svc.Method {\n\t\t\tvar mp protoreflect.SourcePath\n\t\t\tif w.usePath {\n\t\t\t\tmp = p\n\t\t\t\tmp = append(mp, internal.ServiceMethodsTag, int32(j))\n\t\t\t}\n\t\t\tmtdFqn := fqn + \".\" + mtd.GetName()\n\t\t\tif err := w.enter(protoreflect.FullName(mtdFqn), mp, mtd); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif w.exit != nil {\n\t\t\t\tif err := w.exit(protoreflect.FullName(mtdFqn), mp, mtd); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif w.exit != nil {\n\t\t\tif err := w.exit(protoreflect.FullName(fqn), p, svc); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *protoWalker) walkDescriptorProto(prefix string, path protoreflect.SourcePath, msg *descriptorpb.DescriptorProto) error {\n\tfqn := prefix + msg.GetName()\n\tif err := w.enter(protoreflect.FullName(fqn), path, msg); err != nil {\n\t\treturn err\n\t}\n\tprefix = fqn + \".\"\n\tfor i, fld := range msg.Field {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.MessageFieldsTag, int32(i))\n\t\t}\n\t\tfqn := prefix + fld.GetName()\n\t\tif err := w.enter(protoreflect.FullName(fqn), p, fld); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif w.exit != nil {\n\t\t\tif err := w.exit(protoreflect.FullName(fqn), p, fld); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tfor i, oo := range msg.OneofDecl {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.MessageOneofsTag, int32(i))\n\t\t}\n\t\tfqn := prefix + oo.GetName()\n\t\tif err := w.enter(protoreflect.FullName(fqn), p, oo); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif w.exit != nil {\n\t\t\tif err := w.exit(protoreflect.FullName(fqn), p, oo); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tfor i, nested := range msg.NestedType {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.MessageNestedMessagesTag, int32(i))\n\t\t}\n\t\tif err := w.walkDescriptorProto(prefix, p, nested); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i, en := range msg.EnumType {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.MessageEnumsTag, int32(i))\n\t\t}\n\t\tif err := w.walkEnumDescriptorProto(prefix, p, en); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tfor i, ext := range msg.Extension {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.MessageExtensionsTag, int32(i))\n\t\t}\n\t\tfqn := prefix + ext.GetName()\n\t\tif err := w.enter(protoreflect.FullName(fqn), p, ext); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif w.exit != nil {\n\t\t\tif err := w.exit(protoreflect.FullName(fqn), p, ext); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif w.exit != nil {\n\t\tif err := w.exit(protoreflect.FullName(fqn), path, msg); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (w *protoWalker) walkEnumDescriptorProto(prefix string, path protoreflect.SourcePath, en *descriptorpb.EnumDescriptorProto) error {\n\tfqn := prefix + en.GetName()\n\tif err := w.enter(protoreflect.FullName(fqn), path, en); err != nil {\n\t\treturn err\n\t}\n\tfor i, val := range en.Value {\n\t\tvar p protoreflect.SourcePath\n\t\tif w.usePath {\n\t\t\tp = path\n\t\t\tp = append(p, internal.EnumValuesTag, int32(i))\n\t\t}\n\t\tfqn := prefix + val.GetName()\n\t\tif err := w.enter(protoreflect.FullName(fqn), p, val); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif w.exit != nil {\n\t\t\tif err := w.exit(protoreflect.FullName(fqn), p, val); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t}\n\tif w.exit != nil {\n\t\tif err := w.exit(protoreflect.FullName(fqn), path, en); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [5.0.0] - 2024-12-19\n\n### Added\n\n- RetryAfterError can be returned from an operation to indicate how long to wait before the next retry.\n\n### Changed\n\n- Retry function now accepts additional options for specifying max number of tries and max elapsed time.\n- Retry function now accepts a context.Context.\n- Operation function signature changed to return result (any type) and error.\n\n### Removed\n\n- RetryNotify* and RetryWithData functions. Only single Retry function remains.\n- Optional arguments from ExponentialBackoff constructor.\n- Clock and Timer interfaces.\n\n### Fixed\n\n- The original error is returned from Retry if there's a PermanentError. (#144)\n- The Retry function respects the wrapped PermanentError. (#140)\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Cenk Altı\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/backoff.go",
    "content": "// Package backoff implements backoff algorithms for retrying operations.\n//\n// Use Retry function for retrying operations that may fail.\n// If Retry does not meet your needs,\n// copy/paste the function into your project and modify as you wish.\n//\n// There is also Ticker type similar to time.Ticker.\n// You can use it if you need to work with channels.\n//\n// See Examples section below for usage examples.\npackage backoff\n\nimport \"time\"\n\n// BackOff is a backoff policy for retrying an operation.\ntype BackOff interface {\n\t// NextBackOff returns the duration to wait before retrying the operation,\n\t// backoff.Stop to indicate that no more retries should be made.\n\t//\n\t// Example usage:\n\t//\n\t//     duration := backoff.NextBackOff()\n\t//     if duration == backoff.Stop {\n\t//         // Do not retry operation.\n\t//     } else {\n\t//         // Sleep for duration and retry operation.\n\t//     }\n\t//\n\tNextBackOff() time.Duration\n\n\t// Reset to initial state.\n\tReset()\n}\n\n// Stop indicates that no more retries should be made for use in NextBackOff().\nconst Stop time.Duration = -1\n\n// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,\n// meaning that the operation is retried immediately without waiting, indefinitely.\ntype ZeroBackOff struct{}\n\nfunc (b *ZeroBackOff) Reset() {}\n\nfunc (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }\n\n// StopBackOff is a fixed backoff policy that always returns backoff.Stop for\n// NextBackOff(), meaning that the operation should never be retried.\ntype StopBackOff struct{}\n\nfunc (b *StopBackOff) Reset() {}\n\nfunc (b *StopBackOff) NextBackOff() time.Duration { return Stop }\n\n// ConstantBackOff is a backoff policy that always returns the same backoff delay.\n// This is in contrast to an exponential backoff policy,\n// which returns a delay that grows longer as you call NextBackOff() over and over again.\ntype ConstantBackOff struct {\n\tInterval time.Duration\n}\n\nfunc (b *ConstantBackOff) Reset()                     {}\nfunc (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }\n\nfunc NewConstantBackOff(d time.Duration) *ConstantBackOff {\n\treturn &ConstantBackOff{Interval: d}\n}\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/error.go",
    "content": "package backoff\n\nimport (\n\t\"fmt\"\n\t\"time\"\n)\n\n// PermanentError signals that the operation should not be retried.\ntype PermanentError struct {\n\tErr error\n}\n\n// Permanent wraps the given err in a *PermanentError.\nfunc Permanent(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\treturn &PermanentError{\n\t\tErr: err,\n\t}\n}\n\n// Error returns a string representation of the Permanent error.\nfunc (e *PermanentError) Error() string {\n\treturn e.Err.Error()\n}\n\n// Unwrap returns the wrapped error.\nfunc (e *PermanentError) Unwrap() error {\n\treturn e.Err\n}\n\n// RetryAfterError signals that the operation should be retried after the given duration.\ntype RetryAfterError struct {\n\tDuration time.Duration\n}\n\n// RetryAfter returns a RetryAfter error that specifies how long to wait before retrying.\nfunc RetryAfter(seconds int) error {\n\treturn &RetryAfterError{Duration: time.Duration(seconds) * time.Second}\n}\n\n// Error returns a string representation of the RetryAfter error.\nfunc (e *RetryAfterError) Error() string {\n\treturn fmt.Sprintf(\"retry after %s\", e.Duration)\n}\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/exponential.go",
    "content": "package backoff\n\nimport (\n\t\"math/rand/v2\"\n\t\"time\"\n)\n\n/*\nExponentialBackOff is a backoff implementation that increases the backoff\nperiod for each retry attempt using a randomization function that grows exponentially.\n\nNextBackOff() is calculated using the following formula:\n\n\trandomized interval =\n\t    RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])\n\nIn other words NextBackOff() will range between the randomization factor\npercentage below and above the retry interval.\n\nFor example, given the following parameters:\n\n\tRetryInterval = 2\n\tRandomizationFactor = 0.5\n\tMultiplier = 2\n\nthe actual backoff period used in the next retry attempt will range between 1 and 3 seconds,\nmultiplied by the exponential, that is, between 2 and 6 seconds.\n\nNote: MaxInterval caps the RetryInterval and not the randomized interval.\n\nExample: Given the following default arguments, for 9 tries the sequence will be:\n\n\tRequest #  RetryInterval (seconds)  Randomized Interval (seconds)\n\n\t 1          0.5                     [0.25,   0.75]\n\t 2          0.75                    [0.375,  1.125]\n\t 3          1.125                   [0.562,  1.687]\n\t 4          1.687                   [0.8435, 2.53]\n\t 5          2.53                    [1.265,  3.795]\n\t 6          3.795                   [1.897,  5.692]\n\t 7          5.692                   [2.846,  8.538]\n\t 8          8.538                   [4.269, 12.807]\n\t 9         12.807                   [6.403, 19.210]\n\nNote: Implementation is not thread-safe.\n*/\ntype ExponentialBackOff struct {\n\tInitialInterval     time.Duration\n\tRandomizationFactor float64\n\tMultiplier          float64\n\tMaxInterval         time.Duration\n\n\tcurrentInterval time.Duration\n}\n\n// Default values for ExponentialBackOff.\nconst (\n\tDefaultInitialInterval     = 500 * time.Millisecond\n\tDefaultRandomizationFactor = 0.5\n\tDefaultMultiplier          = 1.5\n\tDefaultMaxInterval         = 60 * time.Second\n)\n\n// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.\nfunc NewExponentialBackOff() *ExponentialBackOff {\n\treturn &ExponentialBackOff{\n\t\tInitialInterval:     DefaultInitialInterval,\n\t\tRandomizationFactor: DefaultRandomizationFactor,\n\t\tMultiplier:          DefaultMultiplier,\n\t\tMaxInterval:         DefaultMaxInterval,\n\t}\n}\n\n// Reset the interval back to the initial retry interval and restarts the timer.\n// Reset must be called before using b.\nfunc (b *ExponentialBackOff) Reset() {\n\tb.currentInterval = b.InitialInterval\n}\n\n// NextBackOff calculates the next backoff interval using the formula:\n//\n//\tRandomized interval = RetryInterval * (1 ± RandomizationFactor)\nfunc (b *ExponentialBackOff) NextBackOff() time.Duration {\n\tif b.currentInterval == 0 {\n\t\tb.currentInterval = b.InitialInterval\n\t}\n\n\tnext := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)\n\tb.incrementCurrentInterval()\n\treturn next\n}\n\n// Increments the current interval by multiplying it with the multiplier.\nfunc (b *ExponentialBackOff) incrementCurrentInterval() {\n\t// Check for overflow, if overflow is detected set the current interval to the max interval.\n\tif float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {\n\t\tb.currentInterval = b.MaxInterval\n\t} else {\n\t\tb.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)\n\t}\n}\n\n// Returns a random value from the following interval:\n//\n//\t[currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].\nfunc getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {\n\tif randomizationFactor == 0 {\n\t\treturn currentInterval // make sure no randomness is used when randomizationFactor is 0.\n\t}\n\tvar delta = randomizationFactor * float64(currentInterval)\n\tvar minInterval = float64(currentInterval) - delta\n\tvar maxInterval = float64(currentInterval) + delta\n\n\t// Get a random value from the range [minInterval, maxInterval].\n\t// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then\n\t// we want a 33% chance for selecting either 1, 2 or 3.\n\treturn time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))\n}\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/retry.go",
    "content": "package backoff\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"time\"\n)\n\n// DefaultMaxElapsedTime sets a default limit for the total retry duration.\nconst DefaultMaxElapsedTime = 15 * time.Minute\n\n// Operation is a function that attempts an operation and may be retried.\ntype Operation[T any] func() (T, error)\n\n// Notify is a function called on operation error with the error and backoff duration.\ntype Notify func(error, time.Duration)\n\n// retryOptions holds configuration settings for the retry mechanism.\ntype retryOptions struct {\n\tBackOff        BackOff       // Strategy for calculating backoff periods.\n\tTimer          timer         // Timer to manage retry delays.\n\tNotify         Notify        // Optional function to notify on each retry error.\n\tMaxTries       uint          // Maximum number of retry attempts.\n\tMaxElapsedTime time.Duration // Maximum total time for all retries.\n}\n\ntype RetryOption func(*retryOptions)\n\n// WithBackOff configures a custom backoff strategy.\nfunc WithBackOff(b BackOff) RetryOption {\n\treturn func(args *retryOptions) {\n\t\targs.BackOff = b\n\t}\n}\n\n// withTimer sets a custom timer for managing delays between retries.\nfunc withTimer(t timer) RetryOption {\n\treturn func(args *retryOptions) {\n\t\targs.Timer = t\n\t}\n}\n\n// WithNotify sets a notification function to handle retry errors.\nfunc WithNotify(n Notify) RetryOption {\n\treturn func(args *retryOptions) {\n\t\targs.Notify = n\n\t}\n}\n\n// WithMaxTries limits the number of all attempts.\nfunc WithMaxTries(n uint) RetryOption {\n\treturn func(args *retryOptions) {\n\t\targs.MaxTries = n\n\t}\n}\n\n// WithMaxElapsedTime limits the total duration for retry attempts.\nfunc WithMaxElapsedTime(d time.Duration) RetryOption {\n\treturn func(args *retryOptions) {\n\t\targs.MaxElapsedTime = d\n\t}\n}\n\n// Retry attempts the operation until success, a permanent error, or backoff completion.\n// It ensures the operation is executed at least once.\n//\n// Returns the operation result or error if retries are exhausted or context is cancelled.\nfunc Retry[T any](ctx context.Context, operation Operation[T], opts ...RetryOption) (T, error) {\n\t// Initialize default retry options.\n\targs := &retryOptions{\n\t\tBackOff:        NewExponentialBackOff(),\n\t\tTimer:          &defaultTimer{},\n\t\tMaxElapsedTime: DefaultMaxElapsedTime,\n\t}\n\n\t// Apply user-provided options to the default settings.\n\tfor _, opt := range opts {\n\t\topt(args)\n\t}\n\n\tdefer args.Timer.Stop()\n\n\tstartedAt := time.Now()\n\targs.BackOff.Reset()\n\tfor numTries := uint(1); ; numTries++ {\n\t\t// Execute the operation.\n\t\tres, err := operation()\n\t\tif err == nil {\n\t\t\treturn res, nil\n\t\t}\n\n\t\t// Stop retrying if maximum tries exceeded.\n\t\tif args.MaxTries > 0 && numTries >= args.MaxTries {\n\t\t\treturn res, err\n\t\t}\n\n\t\t// Handle permanent errors without retrying.\n\t\tvar permanent *PermanentError\n\t\tif errors.As(err, &permanent) {\n\t\t\treturn res, permanent.Unwrap()\n\t\t}\n\n\t\t// Stop retrying if context is cancelled.\n\t\tif cerr := context.Cause(ctx); cerr != nil {\n\t\t\treturn res, cerr\n\t\t}\n\n\t\t// Calculate next backoff duration.\n\t\tnext := args.BackOff.NextBackOff()\n\t\tif next == Stop {\n\t\t\treturn res, err\n\t\t}\n\n\t\t// Reset backoff if RetryAfterError is encountered.\n\t\tvar retryAfter *RetryAfterError\n\t\tif errors.As(err, &retryAfter) {\n\t\t\tnext = retryAfter.Duration\n\t\t\targs.BackOff.Reset()\n\t\t}\n\n\t\t// Stop retrying if maximum elapsed time exceeded.\n\t\tif args.MaxElapsedTime > 0 && time.Since(startedAt)+next > args.MaxElapsedTime {\n\t\t\treturn res, err\n\t\t}\n\n\t\t// Notify on error if a notifier function is provided.\n\t\tif args.Notify != nil {\n\t\t\targs.Notify(err, next)\n\t\t}\n\n\t\t// Wait for the next backoff period or context cancellation.\n\t\targs.Timer.Start(next)\n\t\tselect {\n\t\tcase <-args.Timer.C():\n\t\tcase <-ctx.Done():\n\t\t\treturn res, context.Cause(ctx)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/ticker.go",
    "content": "package backoff\n\nimport (\n\t\"sync\"\n\t\"time\"\n)\n\n// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.\n//\n// Ticks will continue to arrive when the previous operation is still running,\n// so operations that take a while to fail could run in quick succession.\ntype Ticker struct {\n\tC        <-chan time.Time\n\tc        chan time.Time\n\tb        BackOff\n\ttimer    timer\n\tstop     chan struct{}\n\tstopOnce sync.Once\n}\n\n// NewTicker returns a new Ticker containing a channel that will send\n// the time at times specified by the BackOff argument. Ticker is\n// guaranteed to tick at least once.  The channel is closed when Stop\n// method is called or BackOff stops. It is not safe to manipulate the\n// provided backoff policy (notably calling NextBackOff or Reset)\n// while the ticker is running.\nfunc NewTicker(b BackOff) *Ticker {\n\tc := make(chan time.Time)\n\tt := &Ticker{\n\t\tC:     c,\n\t\tc:     c,\n\t\tb:     b,\n\t\ttimer: &defaultTimer{},\n\t\tstop:  make(chan struct{}),\n\t}\n\tt.b.Reset()\n\tgo t.run()\n\treturn t\n}\n\n// Stop turns off a ticker. After Stop, no more ticks will be sent.\nfunc (t *Ticker) Stop() {\n\tt.stopOnce.Do(func() { close(t.stop) })\n}\n\nfunc (t *Ticker) run() {\n\tc := t.c\n\tdefer close(c)\n\n\t// Ticker is guaranteed to tick at least once.\n\tafterC := t.send(time.Now())\n\n\tfor {\n\t\tif afterC == nil {\n\t\t\treturn\n\t\t}\n\n\t\tselect {\n\t\tcase tick := <-afterC:\n\t\t\tafterC = t.send(tick)\n\t\tcase <-t.stop:\n\t\t\tt.c = nil // Prevent future ticks from being sent to the channel.\n\t\t\treturn\n\t\t}\n\t}\n}\n\nfunc (t *Ticker) send(tick time.Time) <-chan time.Time {\n\tselect {\n\tcase t.c <- tick:\n\tcase <-t.stop:\n\t\treturn nil\n\t}\n\n\tnext := t.b.NextBackOff()\n\tif next == Stop {\n\t\tt.Stop()\n\t\treturn nil\n\t}\n\n\tt.timer.Start(next)\n\treturn t.timer.C()\n}\n"
  },
  {
    "path": "vendor/github.com/cenkalti/backoff/v5/timer.go",
    "content": "package backoff\n\nimport \"time\"\n\ntype timer interface {\n\tStart(duration time.Duration)\n\tStop()\n\tC() <-chan time.Time\n}\n\n// defaultTimer implements Timer interface using time.Timer\ntype defaultTimer struct {\n\ttimer *time.Timer\n}\n\n// C returns the timers channel which receives the current time when the timer fires.\nfunc (t *defaultTimer) C() <-chan time.Time {\n\treturn t.timer.C\n}\n\n// Start starts the timer to fire after the given duration\nfunc (t *defaultTimer) Start(duration time.Duration) {\n\tif t.timer == nil {\n\t\tt.timer = time.NewTimer(duration)\n\t} else {\n\t\tt.timer.Reset(duration)\n\t}\n}\n\n// Stop is called when the timer is not used anymore and resources may be freed.\nfunc (t *defaultTimer) Stop() {\n\tif t.timer != nil {\n\t\tt.timer.Stop()\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/LICENSE.txt",
    "content": "Copyright (c) 2016 Caleb Spare\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/testall.sh",
    "content": "#!/bin/bash\nset -eu -o pipefail\n\n# Small convenience script for running the tests with various combinations of\n# arch/tags. This assumes we're running on amd64 and have qemu available.\n\ngo test ./...\ngo test -tags purego ./...\nGOARCH=arm64 go test\nGOARCH=arm64 go test -tags purego\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/xxhash.go",
    "content": "// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described\n// at http://cyan4973.github.io/xxHash/.\npackage xxhash\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"math/bits\"\n)\n\nconst (\n\tprime1 uint64 = 11400714785074694791\n\tprime2 uint64 = 14029467366897019727\n\tprime3 uint64 = 1609587929392839161\n\tprime4 uint64 = 9650029242287828579\n\tprime5 uint64 = 2870177450012600261\n)\n\n// Store the primes in an array as well.\n//\n// The consts are used when possible in Go code to avoid MOVs but we need a\n// contiguous array for the assembly code.\nvar primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}\n\n// Digest implements hash.Hash64.\n//\n// Note that a zero-valued Digest is not ready to receive writes.\n// Call Reset or create a Digest using New before calling other methods.\ntype Digest struct {\n\tv1    uint64\n\tv2    uint64\n\tv3    uint64\n\tv4    uint64\n\ttotal uint64\n\tmem   [32]byte\n\tn     int // how much of mem is used\n}\n\n// New creates a new Digest with a zero seed.\nfunc New() *Digest {\n\treturn NewWithSeed(0)\n}\n\n// NewWithSeed creates a new Digest with the given seed.\nfunc NewWithSeed(seed uint64) *Digest {\n\tvar d Digest\n\td.ResetWithSeed(seed)\n\treturn &d\n}\n\n// Reset clears the Digest's state so that it can be reused.\n// It uses a seed value of zero.\nfunc (d *Digest) Reset() {\n\td.ResetWithSeed(0)\n}\n\n// ResetWithSeed clears the Digest's state so that it can be reused.\n// It uses the given seed to initialize the state.\nfunc (d *Digest) ResetWithSeed(seed uint64) {\n\td.v1 = seed + prime1 + prime2\n\td.v2 = seed + prime2\n\td.v3 = seed\n\td.v4 = seed - prime1\n\td.total = 0\n\td.n = 0\n}\n\n// Size always returns 8 bytes.\nfunc (d *Digest) Size() int { return 8 }\n\n// BlockSize always returns 32 bytes.\nfunc (d *Digest) BlockSize() int { return 32 }\n\n// Write adds more data to d. It always returns len(b), nil.\nfunc (d *Digest) Write(b []byte) (n int, err error) {\n\tn = len(b)\n\td.total += uint64(n)\n\n\tmemleft := d.mem[d.n&(len(d.mem)-1):]\n\n\tif d.n+n < 32 {\n\t\t// This new data doesn't even fill the current block.\n\t\tcopy(memleft, b)\n\t\td.n += n\n\t\treturn\n\t}\n\n\tif d.n > 0 {\n\t\t// Finish off the partial block.\n\t\tc := copy(memleft, b)\n\t\td.v1 = round(d.v1, u64(d.mem[0:8]))\n\t\td.v2 = round(d.v2, u64(d.mem[8:16]))\n\t\td.v3 = round(d.v3, u64(d.mem[16:24]))\n\t\td.v4 = round(d.v4, u64(d.mem[24:32]))\n\t\tb = b[c:]\n\t\td.n = 0\n\t}\n\n\tif len(b) >= 32 {\n\t\t// One or more full blocks left.\n\t\tnw := writeBlocks(d, b)\n\t\tb = b[nw:]\n\t}\n\n\t// Store any remaining partial block.\n\tcopy(d.mem[:], b)\n\td.n = len(b)\n\n\treturn\n}\n\n// Sum appends the current hash to b and returns the resulting slice.\nfunc (d *Digest) Sum(b []byte) []byte {\n\ts := d.Sum64()\n\treturn append(\n\t\tb,\n\t\tbyte(s>>56),\n\t\tbyte(s>>48),\n\t\tbyte(s>>40),\n\t\tbyte(s>>32),\n\t\tbyte(s>>24),\n\t\tbyte(s>>16),\n\t\tbyte(s>>8),\n\t\tbyte(s),\n\t)\n}\n\n// Sum64 returns the current hash.\nfunc (d *Digest) Sum64() uint64 {\n\tvar h uint64\n\n\tif d.total >= 32 {\n\t\tv1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4\n\t\th = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)\n\t\th = mergeRound(h, v1)\n\t\th = mergeRound(h, v2)\n\t\th = mergeRound(h, v3)\n\t\th = mergeRound(h, v4)\n\t} else {\n\t\th = d.v3 + prime5\n\t}\n\n\th += d.total\n\n\tb := d.mem[:d.n&(len(d.mem)-1)]\n\tfor ; len(b) >= 8; b = b[8:] {\n\t\tk1 := round(0, u64(b[:8]))\n\t\th ^= k1\n\t\th = rol27(h)*prime1 + prime4\n\t}\n\tif len(b) >= 4 {\n\t\th ^= uint64(u32(b[:4])) * prime1\n\t\th = rol23(h)*prime2 + prime3\n\t\tb = b[4:]\n\t}\n\tfor ; len(b) > 0; b = b[1:] {\n\t\th ^= uint64(b[0]) * prime5\n\t\th = rol11(h) * prime1\n\t}\n\n\th ^= h >> 33\n\th *= prime2\n\th ^= h >> 29\n\th *= prime3\n\th ^= h >> 32\n\n\treturn h\n}\n\nconst (\n\tmagic         = \"xxh\\x06\"\n\tmarshaledSize = len(magic) + 8*5 + 32\n)\n\n// MarshalBinary implements the encoding.BinaryMarshaler interface.\nfunc (d *Digest) MarshalBinary() ([]byte, error) {\n\tb := make([]byte, 0, marshaledSize)\n\tb = append(b, magic...)\n\tb = appendUint64(b, d.v1)\n\tb = appendUint64(b, d.v2)\n\tb = appendUint64(b, d.v3)\n\tb = appendUint64(b, d.v4)\n\tb = appendUint64(b, d.total)\n\tb = append(b, d.mem[:d.n]...)\n\tb = b[:len(b)+len(d.mem)-d.n]\n\treturn b, nil\n}\n\n// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.\nfunc (d *Digest) UnmarshalBinary(b []byte) error {\n\tif len(b) < len(magic) || string(b[:len(magic)]) != magic {\n\t\treturn errors.New(\"xxhash: invalid hash state identifier\")\n\t}\n\tif len(b) != marshaledSize {\n\t\treturn errors.New(\"xxhash: invalid hash state size\")\n\t}\n\tb = b[len(magic):]\n\tb, d.v1 = consumeUint64(b)\n\tb, d.v2 = consumeUint64(b)\n\tb, d.v3 = consumeUint64(b)\n\tb, d.v4 = consumeUint64(b)\n\tb, d.total = consumeUint64(b)\n\tcopy(d.mem[:], b)\n\td.n = int(d.total % uint64(len(d.mem)))\n\treturn nil\n}\n\nfunc appendUint64(b []byte, x uint64) []byte {\n\tvar a [8]byte\n\tbinary.LittleEndian.PutUint64(a[:], x)\n\treturn append(b, a[:]...)\n}\n\nfunc consumeUint64(b []byte) ([]byte, uint64) {\n\tx := u64(b)\n\treturn b[8:], x\n}\n\nfunc u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }\nfunc u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }\n\nfunc round(acc, input uint64) uint64 {\n\tacc += input * prime2\n\tacc = rol31(acc)\n\tacc *= prime1\n\treturn acc\n}\n\nfunc mergeRound(acc, val uint64) uint64 {\n\tval = round(0, val)\n\tacc ^= val\n\tacc = acc*prime1 + prime4\n\treturn acc\n}\n\nfunc rol1(x uint64) uint64  { return bits.RotateLeft64(x, 1) }\nfunc rol7(x uint64) uint64  { return bits.RotateLeft64(x, 7) }\nfunc rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }\nfunc rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }\nfunc rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }\nfunc rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }\nfunc rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }\nfunc rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s",
    "content": "//go:build !appengine && gc && !purego\n// +build !appengine\n// +build gc\n// +build !purego\n\n#include \"textflag.h\"\n\n// Registers:\n#define h      AX\n#define d      AX\n#define p      SI // pointer to advance through b\n#define n      DX\n#define end    BX // loop end\n#define v1     R8\n#define v2     R9\n#define v3     R10\n#define v4     R11\n#define x      R12\n#define prime1 R13\n#define prime2 R14\n#define prime4 DI\n\n#define round(acc, x) \\\n\tIMULQ prime2, x   \\\n\tADDQ  x, acc      \\\n\tROLQ  $31, acc    \\\n\tIMULQ prime1, acc\n\n// round0 performs the operation x = round(0, x).\n#define round0(x) \\\n\tIMULQ prime2, x \\\n\tROLQ  $31, x    \\\n\tIMULQ prime1, x\n\n// mergeRound applies a merge round on the two registers acc and x.\n// It assumes that prime1, prime2, and prime4 have been loaded.\n#define mergeRound(acc, x) \\\n\tround0(x)         \\\n\tXORQ  x, acc      \\\n\tIMULQ prime1, acc \\\n\tADDQ  prime4, acc\n\n// blockLoop processes as many 32-byte blocks as possible,\n// updating v1, v2, v3, and v4. It assumes that there is at least one block\n// to process.\n#define blockLoop() \\\nloop:  \\\n\tMOVQ +0(p), x  \\\n\tround(v1, x)   \\\n\tMOVQ +8(p), x  \\\n\tround(v2, x)   \\\n\tMOVQ +16(p), x \\\n\tround(v3, x)   \\\n\tMOVQ +24(p), x \\\n\tround(v4, x)   \\\n\tADDQ $32, p    \\\n\tCMPQ p, end    \\\n\tJLE  loop\n\n// func Sum64(b []byte) uint64\nTEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32\n\t// Load fixed primes.\n\tMOVQ ·primes+0(SB), prime1\n\tMOVQ ·primes+8(SB), prime2\n\tMOVQ ·primes+24(SB), prime4\n\n\t// Load slice.\n\tMOVQ b_base+0(FP), p\n\tMOVQ b_len+8(FP), n\n\tLEAQ (p)(n*1), end\n\n\t// The first loop limit will be len(b)-32.\n\tSUBQ $32, end\n\n\t// Check whether we have at least one block.\n\tCMPQ n, $32\n\tJLT  noBlocks\n\n\t// Set up initial state (v1, v2, v3, v4).\n\tMOVQ prime1, v1\n\tADDQ prime2, v1\n\tMOVQ prime2, v2\n\tXORQ v3, v3\n\tXORQ v4, v4\n\tSUBQ prime1, v4\n\n\tblockLoop()\n\n\tMOVQ v1, h\n\tROLQ $1, h\n\tMOVQ v2, x\n\tROLQ $7, x\n\tADDQ x, h\n\tMOVQ v3, x\n\tROLQ $12, x\n\tADDQ x, h\n\tMOVQ v4, x\n\tROLQ $18, x\n\tADDQ x, h\n\n\tmergeRound(h, v1)\n\tmergeRound(h, v2)\n\tmergeRound(h, v3)\n\tmergeRound(h, v4)\n\n\tJMP afterBlocks\n\nnoBlocks:\n\tMOVQ ·primes+32(SB), h\n\nafterBlocks:\n\tADDQ n, h\n\n\tADDQ $24, end\n\tCMPQ p, end\n\tJG   try4\n\nloop8:\n\tMOVQ  (p), x\n\tADDQ  $8, p\n\tround0(x)\n\tXORQ  x, h\n\tROLQ  $27, h\n\tIMULQ prime1, h\n\tADDQ  prime4, h\n\n\tCMPQ p, end\n\tJLE  loop8\n\ntry4:\n\tADDQ $4, end\n\tCMPQ p, end\n\tJG   try1\n\n\tMOVL  (p), x\n\tADDQ  $4, p\n\tIMULQ prime1, x\n\tXORQ  x, h\n\n\tROLQ  $23, h\n\tIMULQ prime2, h\n\tADDQ  ·primes+16(SB), h\n\ntry1:\n\tADDQ $4, end\n\tCMPQ p, end\n\tJGE  finalize\n\nloop1:\n\tMOVBQZX (p), x\n\tADDQ    $1, p\n\tIMULQ   ·primes+32(SB), x\n\tXORQ    x, h\n\tROLQ    $11, h\n\tIMULQ   prime1, h\n\n\tCMPQ p, end\n\tJL   loop1\n\nfinalize:\n\tMOVQ  h, x\n\tSHRQ  $33, x\n\tXORQ  x, h\n\tIMULQ prime2, h\n\tMOVQ  h, x\n\tSHRQ  $29, x\n\tXORQ  x, h\n\tIMULQ ·primes+16(SB), h\n\tMOVQ  h, x\n\tSHRQ  $32, x\n\tXORQ  x, h\n\n\tMOVQ h, ret+24(FP)\n\tRET\n\n// func writeBlocks(d *Digest, b []byte) int\nTEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40\n\t// Load fixed primes needed for round.\n\tMOVQ ·primes+0(SB), prime1\n\tMOVQ ·primes+8(SB), prime2\n\n\t// Load slice.\n\tMOVQ b_base+8(FP), p\n\tMOVQ b_len+16(FP), n\n\tLEAQ (p)(n*1), end\n\tSUBQ $32, end\n\n\t// Load vN from d.\n\tMOVQ s+0(FP), d\n\tMOVQ 0(d), v1\n\tMOVQ 8(d), v2\n\tMOVQ 16(d), v3\n\tMOVQ 24(d), v4\n\n\t// We don't need to check the loop condition here; this function is\n\t// always called with at least one block of data to process.\n\tblockLoop()\n\n\t// Copy vN back to d.\n\tMOVQ v1, 0(d)\n\tMOVQ v2, 8(d)\n\tMOVQ v3, 16(d)\n\tMOVQ v4, 24(d)\n\n\t// The number of bytes written is p minus the old base pointer.\n\tSUBQ b_base+8(FP), p\n\tMOVQ p, ret+32(FP)\n\n\tRET\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s",
    "content": "//go:build !appengine && gc && !purego\n// +build !appengine\n// +build gc\n// +build !purego\n\n#include \"textflag.h\"\n\n// Registers:\n#define digest\tR1\n#define h\tR2 // return value\n#define p\tR3 // input pointer\n#define n\tR4 // input length\n#define nblocks\tR5 // n / 32\n#define prime1\tR7\n#define prime2\tR8\n#define prime3\tR9\n#define prime4\tR10\n#define prime5\tR11\n#define v1\tR12\n#define v2\tR13\n#define v3\tR14\n#define v4\tR15\n#define x1\tR20\n#define x2\tR21\n#define x3\tR22\n#define x4\tR23\n\n#define round(acc, x) \\\n\tMADD prime2, acc, x, acc \\\n\tROR  $64-31, acc         \\\n\tMUL  prime1, acc\n\n// round0 performs the operation x = round(0, x).\n#define round0(x) \\\n\tMUL prime2, x \\\n\tROR $64-31, x \\\n\tMUL prime1, x\n\n#define mergeRound(acc, x) \\\n\tround0(x)                     \\\n\tEOR  x, acc                   \\\n\tMADD acc, prime4, prime1, acc\n\n// blockLoop processes as many 32-byte blocks as possible,\n// updating v1, v2, v3, and v4. It assumes that n >= 32.\n#define blockLoop() \\\n\tLSR     $5, n, nblocks  \\\n\tPCALIGN $16             \\\n\tloop:                   \\\n\tLDP.P   16(p), (x1, x2) \\\n\tLDP.P   16(p), (x3, x4) \\\n\tround(v1, x1)           \\\n\tround(v2, x2)           \\\n\tround(v3, x3)           \\\n\tround(v4, x4)           \\\n\tSUB     $1, nblocks     \\\n\tCBNZ    nblocks, loop\n\n// func Sum64(b []byte) uint64\nTEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32\n\tLDP b_base+0(FP), (p, n)\n\n\tLDP  ·primes+0(SB), (prime1, prime2)\n\tLDP  ·primes+16(SB), (prime3, prime4)\n\tMOVD ·primes+32(SB), prime5\n\n\tCMP  $32, n\n\tCSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 }\n\tBLT  afterLoop\n\n\tADD  prime1, prime2, v1\n\tMOVD prime2, v2\n\tMOVD $0, v3\n\tNEG  prime1, v4\n\n\tblockLoop()\n\n\tROR $64-1, v1, x1\n\tROR $64-7, v2, x2\n\tADD x1, x2\n\tROR $64-12, v3, x3\n\tROR $64-18, v4, x4\n\tADD x3, x4\n\tADD x2, x4, h\n\n\tmergeRound(h, v1)\n\tmergeRound(h, v2)\n\tmergeRound(h, v3)\n\tmergeRound(h, v4)\n\nafterLoop:\n\tADD n, h\n\n\tTBZ   $4, n, try8\n\tLDP.P 16(p), (x1, x2)\n\n\tround0(x1)\n\n\t// NOTE: here and below, sequencing the EOR after the ROR (using a\n\t// rotated register) is worth a small but measurable speedup for small\n\t// inputs.\n\tROR  $64-27, h\n\tEOR  x1 @> 64-27, h, h\n\tMADD h, prime4, prime1, h\n\n\tround0(x2)\n\tROR  $64-27, h\n\tEOR  x2 @> 64-27, h, h\n\tMADD h, prime4, prime1, h\n\ntry8:\n\tTBZ    $3, n, try4\n\tMOVD.P 8(p), x1\n\n\tround0(x1)\n\tROR  $64-27, h\n\tEOR  x1 @> 64-27, h, h\n\tMADD h, prime4, prime1, h\n\ntry4:\n\tTBZ     $2, n, try2\n\tMOVWU.P 4(p), x2\n\n\tMUL  prime1, x2\n\tROR  $64-23, h\n\tEOR  x2 @> 64-23, h, h\n\tMADD h, prime3, prime2, h\n\ntry2:\n\tTBZ     $1, n, try1\n\tMOVHU.P 2(p), x3\n\tAND     $255, x3, x1\n\tLSR     $8, x3, x2\n\n\tMUL prime5, x1\n\tROR $64-11, h\n\tEOR x1 @> 64-11, h, h\n\tMUL prime1, h\n\n\tMUL prime5, x2\n\tROR $64-11, h\n\tEOR x2 @> 64-11, h, h\n\tMUL prime1, h\n\ntry1:\n\tTBZ   $0, n, finalize\n\tMOVBU (p), x4\n\n\tMUL prime5, x4\n\tROR $64-11, h\n\tEOR x4 @> 64-11, h, h\n\tMUL prime1, h\n\nfinalize:\n\tEOR h >> 33, h\n\tMUL prime2, h\n\tEOR h >> 29, h\n\tMUL prime3, h\n\tEOR h >> 32, h\n\n\tMOVD h, ret+24(FP)\n\tRET\n\n// func writeBlocks(d *Digest, b []byte) int\nTEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40\n\tLDP ·primes+0(SB), (prime1, prime2)\n\n\t// Load state. Assume v[1-4] are stored contiguously.\n\tMOVD d+0(FP), digest\n\tLDP  0(digest), (v1, v2)\n\tLDP  16(digest), (v3, v4)\n\n\tLDP b_base+8(FP), (p, n)\n\n\tblockLoop()\n\n\t// Store updated state.\n\tSTP (v1, v2), 0(digest)\n\tSTP (v3, v4), 16(digest)\n\n\tBIC  $31, n\n\tMOVD n, ret+32(FP)\n\tRET\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/xxhash_asm.go",
    "content": "//go:build (amd64 || arm64) && !appengine && gc && !purego\n// +build amd64 arm64\n// +build !appengine\n// +build gc\n// +build !purego\n\npackage xxhash\n\n// Sum64 computes the 64-bit xxHash digest of b with a zero seed.\n//\n//go:noescape\nfunc Sum64(b []byte) uint64\n\n//go:noescape\nfunc writeBlocks(d *Digest, b []byte) int\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/xxhash_other.go",
    "content": "//go:build (!amd64 && !arm64) || appengine || !gc || purego\n// +build !amd64,!arm64 appengine !gc purego\n\npackage xxhash\n\n// Sum64 computes the 64-bit xxHash digest of b with a zero seed.\nfunc Sum64(b []byte) uint64 {\n\t// A simpler version would be\n\t//   d := New()\n\t//   d.Write(b)\n\t//   return d.Sum64()\n\t// but this is faster, particularly for small inputs.\n\n\tn := len(b)\n\tvar h uint64\n\n\tif n >= 32 {\n\t\tv1 := primes[0] + prime2\n\t\tv2 := prime2\n\t\tv3 := uint64(0)\n\t\tv4 := -primes[0]\n\t\tfor len(b) >= 32 {\n\t\t\tv1 = round(v1, u64(b[0:8:len(b)]))\n\t\t\tv2 = round(v2, u64(b[8:16:len(b)]))\n\t\t\tv3 = round(v3, u64(b[16:24:len(b)]))\n\t\t\tv4 = round(v4, u64(b[24:32:len(b)]))\n\t\t\tb = b[32:len(b):len(b)]\n\t\t}\n\t\th = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)\n\t\th = mergeRound(h, v1)\n\t\th = mergeRound(h, v2)\n\t\th = mergeRound(h, v3)\n\t\th = mergeRound(h, v4)\n\t} else {\n\t\th = prime5\n\t}\n\n\th += uint64(n)\n\n\tfor ; len(b) >= 8; b = b[8:] {\n\t\tk1 := round(0, u64(b[:8]))\n\t\th ^= k1\n\t\th = rol27(h)*prime1 + prime4\n\t}\n\tif len(b) >= 4 {\n\t\th ^= uint64(u32(b[:4])) * prime1\n\t\th = rol23(h)*prime2 + prime3\n\t\tb = b[4:]\n\t}\n\tfor ; len(b) > 0; b = b[1:] {\n\t\th ^= uint64(b[0]) * prime5\n\t\th = rol11(h) * prime1\n\t}\n\n\th ^= h >> 33\n\th *= prime2\n\th ^= h >> 29\n\th *= prime3\n\th ^= h >> 32\n\n\treturn h\n}\n\nfunc writeBlocks(d *Digest, b []byte) int {\n\tv1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4\n\tn := len(b)\n\tfor len(b) >= 32 {\n\t\tv1 = round(v1, u64(b[0:8:len(b)]))\n\t\tv2 = round(v2, u64(b[8:16:len(b)]))\n\t\tv3 = round(v3, u64(b[16:24:len(b)]))\n\t\tv4 = round(v4, u64(b[24:32:len(b)]))\n\t\tb = b[32:len(b):len(b)]\n\t}\n\td.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4\n\treturn n - len(b)\n}\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/xxhash_safe.go",
    "content": "//go:build appengine\n// +build appengine\n\n// This file contains the safe implementations of otherwise unsafe-using code.\n\npackage xxhash\n\n// Sum64String computes the 64-bit xxHash digest of s with a zero seed.\nfunc Sum64String(s string) uint64 {\n\treturn Sum64([]byte(s))\n}\n\n// WriteString adds more data to d. It always returns len(s), nil.\nfunc (d *Digest) WriteString(s string) (n int, err error) {\n\treturn d.Write([]byte(s))\n}\n"
  },
  {
    "path": "vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go",
    "content": "//go:build !appengine\n// +build !appengine\n\n// This file encapsulates usage of unsafe.\n// xxhash_safe.go contains the safe implementations.\n\npackage xxhash\n\nimport (\n\t\"unsafe\"\n)\n\n// In the future it's possible that compiler optimizations will make these\n// XxxString functions unnecessary by realizing that calls such as\n// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205.\n// If that happens, even if we keep these functions they can be replaced with\n// the trivial safe code.\n\n// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is:\n//\n//   var b []byte\n//   bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))\n//   bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data\n//   bh.Len = len(s)\n//   bh.Cap = len(s)\n//\n// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough\n// weight to this sequence of expressions that any function that uses it will\n// not be inlined. Instead, the functions below use a different unsafe\n// conversion designed to minimize the inliner weight and allow both to be\n// inlined. There is also a test (TestInlining) which verifies that these are\n// inlined.\n//\n// See https://github.com/golang/go/issues/42739 for discussion.\n\n// Sum64String computes the 64-bit xxHash digest of s with a zero seed.\n// It may be faster than Sum64([]byte(s)) by avoiding a copy.\nfunc Sum64String(s string) uint64 {\n\tb := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))\n\treturn Sum64(b)\n}\n\n// WriteString adds more data to d. It always returns len(s), nil.\n// It may be faster than Write([]byte(s)) by avoiding a copy.\nfunc (d *Digest) WriteString(s string) (n int, err error) {\n\td.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))\n\t// d.Write always returns len(s), nil.\n\t// Ignoring the return output and returning these fixed values buys a\n\t// savings of 6 in the inliner's cost model.\n\treturn len(s), nil\n}\n\n// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout\n// of the first two words is the same as the layout of a string.\ntype sliceHeader struct {\n\ts   string\n\tcap int\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016-2025 Kenneth Shaw\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/accessibility/accessibility.go",
    "content": "// Package accessibility provides the Chrome DevTools Protocol\n// commands, types, and events for the Accessibility domain.\n//\n// Generated by the cdproto-gen command.\npackage accessibility\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// DisableParams disables the accessibility domain.\ntype DisableParams struct{}\n\n// Disable disables the accessibility domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Accessibility.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables the accessibility domain which causes AXNodeIds to\n// remain consistent between method calls. This turns on accessibility for the\n// page, which can impact performance until accessibility is disabled.\ntype EnableParams struct{}\n\n// Enable enables the accessibility domain which causes AXNodeIds to remain\n// consistent between method calls. This turns on accessibility for the page,\n// which can impact performance until accessibility is disabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Accessibility.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// GetPartialAXTreeParams fetches the accessibility node and partial\n// accessibility tree for this DOM node, if it exists.\ntype GetPartialAXTreeParams struct {\n\tNodeID         cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node to get the partial accessibility tree for.\n\tBackendNodeID  cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node to get the partial accessibility tree for.\n\tObjectID       runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper to get the partial accessibility tree for.\n\tFetchRelatives bool                   `json:\"fetchRelatives\"`                   // Whether to fetch this node's ancestors, siblings and children. Defaults to true.\n}\n\n// GetPartialAXTree fetches the accessibility node and partial accessibility\n// tree for this DOM node, if it exists.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getPartialAXTree\n//\n// parameters:\nfunc GetPartialAXTree() *GetPartialAXTreeParams {\n\treturn &GetPartialAXTreeParams{\n\t\tFetchRelatives: true,\n\t}\n}\n\n// WithNodeID identifier of the node to get the partial accessibility tree\n// for.\nfunc (p GetPartialAXTreeParams) WithNodeID(nodeID cdp.NodeID) *GetPartialAXTreeParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node to get the partial\n// accessibility tree for.\nfunc (p GetPartialAXTreeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetPartialAXTreeParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper to get the partial\n// accessibility tree for.\nfunc (p GetPartialAXTreeParams) WithObjectID(objectID runtime.RemoteObjectID) *GetPartialAXTreeParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// WithFetchRelatives whether to fetch this node's ancestors, siblings and\n// children. Defaults to true.\nfunc (p GetPartialAXTreeParams) WithFetchRelatives(fetchRelatives bool) *GetPartialAXTreeParams {\n\tp.FetchRelatives = fetchRelatives\n\treturn &p\n}\n\n// GetPartialAXTreeReturns return values.\ntype GetPartialAXTreeReturns struct {\n\tNodes []*Node `json:\"nodes,omitempty,omitzero\"` // The Accessibility.AXNode for this DOM node, if it exists, plus its ancestors, siblings and children, if requested.\n}\n\n// Do executes Accessibility.getPartialAXTree against the provided context.\n//\n// returns:\n//\n//\tnodes - The Accessibility.AXNode for this DOM node, if it exists, plus its ancestors, siblings and children, if requested.\nfunc (p *GetPartialAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) {\n\t// execute\n\tvar res GetPartialAXTreeReturns\n\terr = cdp.Execute(ctx, CommandGetPartialAXTree, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Nodes, nil\n}\n\n// GetFullAXTreeParams fetches the entire accessibility tree for the root\n// Document.\ntype GetFullAXTreeParams struct {\n\tDepth   int64       `json:\"depth,omitempty,omitzero\"`   // The maximum depth at which descendants of the root node should be retrieved. If omitted, the full tree is returned.\n\tFrameID cdp.FrameID `json:\"frameId,omitempty,omitzero\"` // The frame for whose document the AX tree should be retrieved. If omitted, the root frame is used.\n}\n\n// GetFullAXTree fetches the entire accessibility tree for the root Document.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getFullAXTree\n//\n// parameters:\nfunc GetFullAXTree() *GetFullAXTreeParams {\n\treturn &GetFullAXTreeParams{}\n}\n\n// WithDepth the maximum depth at which descendants of the root node should\n// be retrieved. If omitted, the full tree is returned.\nfunc (p GetFullAXTreeParams) WithDepth(depth int64) *GetFullAXTreeParams {\n\tp.Depth = depth\n\treturn &p\n}\n\n// WithFrameID the frame for whose document the AX tree should be retrieved.\n// If omitted, the root frame is used.\nfunc (p GetFullAXTreeParams) WithFrameID(frameID cdp.FrameID) *GetFullAXTreeParams {\n\tp.FrameID = frameID\n\treturn &p\n}\n\n// GetFullAXTreeReturns return values.\ntype GetFullAXTreeReturns struct {\n\tNodes []*Node `json:\"nodes,omitempty,omitzero\"`\n}\n\n// Do executes Accessibility.getFullAXTree against the provided context.\n//\n// returns:\n//\n//\tnodes\nfunc (p *GetFullAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) {\n\t// execute\n\tvar res GetFullAXTreeReturns\n\terr = cdp.Execute(ctx, CommandGetFullAXTree, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Nodes, nil\n}\n\n// GetRootAXNodeParams fetches the root node. Requires enable() to have been\n// called previously.\ntype GetRootAXNodeParams struct {\n\tFrameID cdp.FrameID `json:\"frameId,omitempty,omitzero\"` // The frame in whose document the node resides. If omitted, the root frame is used.\n}\n\n// GetRootAXNode fetches the root node. Requires enable() to have been called\n// previously.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getRootAXNode\n//\n// parameters:\nfunc GetRootAXNode() *GetRootAXNodeParams {\n\treturn &GetRootAXNodeParams{}\n}\n\n// WithFrameID the frame in whose document the node resides. If omitted, the\n// root frame is used.\nfunc (p GetRootAXNodeParams) WithFrameID(frameID cdp.FrameID) *GetRootAXNodeParams {\n\tp.FrameID = frameID\n\treturn &p\n}\n\n// GetRootAXNodeReturns return values.\ntype GetRootAXNodeReturns struct {\n\tNode *Node `json:\"node,omitempty,omitzero\"`\n}\n\n// Do executes Accessibility.getRootAXNode against the provided context.\n//\n// returns:\n//\n//\tnode\nfunc (p *GetRootAXNodeParams) Do(ctx context.Context) (node *Node, err error) {\n\t// execute\n\tvar res GetRootAXNodeReturns\n\terr = cdp.Execute(ctx, CommandGetRootAXNode, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Node, nil\n}\n\n// GetAXNodeAndAncestorsParams fetches a node and all ancestors up to and\n// including the root. Requires enable() to have been called previously.\ntype GetAXNodeAndAncestorsParams struct {\n\tNodeID        cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node to get.\n\tBackendNodeID cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node to get.\n\tObjectID      runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper to get.\n}\n\n// GetAXNodeAndAncestors fetches a node and all ancestors up to and including\n// the root. Requires enable() to have been called previously.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getAXNodeAndAncestors\n//\n// parameters:\nfunc GetAXNodeAndAncestors() *GetAXNodeAndAncestorsParams {\n\treturn &GetAXNodeAndAncestorsParams{}\n}\n\n// WithNodeID identifier of the node to get.\nfunc (p GetAXNodeAndAncestorsParams) WithNodeID(nodeID cdp.NodeID) *GetAXNodeAndAncestorsParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node to get.\nfunc (p GetAXNodeAndAncestorsParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetAXNodeAndAncestorsParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper to get.\nfunc (p GetAXNodeAndAncestorsParams) WithObjectID(objectID runtime.RemoteObjectID) *GetAXNodeAndAncestorsParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// GetAXNodeAndAncestorsReturns return values.\ntype GetAXNodeAndAncestorsReturns struct {\n\tNodes []*Node `json:\"nodes,omitempty,omitzero\"`\n}\n\n// Do executes Accessibility.getAXNodeAndAncestors against the provided context.\n//\n// returns:\n//\n//\tnodes\nfunc (p *GetAXNodeAndAncestorsParams) Do(ctx context.Context) (nodes []*Node, err error) {\n\t// execute\n\tvar res GetAXNodeAndAncestorsReturns\n\terr = cdp.Execute(ctx, CommandGetAXNodeAndAncestors, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Nodes, nil\n}\n\n// GetChildAXNodesParams fetches a particular accessibility node by AXNodeId.\n// Requires enable() to have been called previously.\ntype GetChildAXNodesParams struct {\n\tID      NodeID      `json:\"id\"`\n\tFrameID cdp.FrameID `json:\"frameId,omitempty,omitzero\"` // The frame in whose document the node resides. If omitted, the root frame is used.\n}\n\n// GetChildAXNodes fetches a particular accessibility node by AXNodeId.\n// Requires enable() to have been called previously.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-getChildAXNodes\n//\n// parameters:\n//\n//\tid\nfunc GetChildAXNodes(id NodeID) *GetChildAXNodesParams {\n\treturn &GetChildAXNodesParams{\n\t\tID: id,\n\t}\n}\n\n// WithFrameID the frame in whose document the node resides. If omitted, the\n// root frame is used.\nfunc (p GetChildAXNodesParams) WithFrameID(frameID cdp.FrameID) *GetChildAXNodesParams {\n\tp.FrameID = frameID\n\treturn &p\n}\n\n// GetChildAXNodesReturns return values.\ntype GetChildAXNodesReturns struct {\n\tNodes []*Node `json:\"nodes,omitempty,omitzero\"`\n}\n\n// Do executes Accessibility.getChildAXNodes against the provided context.\n//\n// returns:\n//\n//\tnodes\nfunc (p *GetChildAXNodesParams) Do(ctx context.Context) (nodes []*Node, err error) {\n\t// execute\n\tvar res GetChildAXNodesReturns\n\terr = cdp.Execute(ctx, CommandGetChildAXNodes, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Nodes, nil\n}\n\n// QueryAXTreeParams query a DOM node's accessibility subtree for accessible\n// name and role. This command computes the name and role for all nodes in the\n// subtree, including those that are ignored for accessibility, and returns\n// those that match the specified name and role. If no DOM node is specified, or\n// the DOM node does not exist, the command returns an error. If neither\n// accessibleName or role is specified, it returns all the accessibility nodes\n// in the subtree.\ntype QueryAXTreeParams struct {\n\tNodeID         cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`         // Identifier of the node for the root to query.\n\tBackendNodeID  cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"`  // Identifier of the backend node for the root to query.\n\tObjectID       runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`       // JavaScript object id of the node wrapper for the root to query.\n\tAccessibleName string                 `json:\"accessibleName,omitempty,omitzero\"` // Find nodes with this computed name.\n\tRole           string                 `json:\"role,omitempty,omitzero\"`           // Find nodes with this computed role.\n}\n\n// QueryAXTree query a DOM node's accessibility subtree for accessible name\n// and role. This command computes the name and role for all nodes in the\n// subtree, including those that are ignored for accessibility, and returns\n// those that match the specified name and role. If no DOM node is specified, or\n// the DOM node does not exist, the command returns an error. If neither\n// accessibleName or role is specified, it returns all the accessibility nodes\n// in the subtree.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#method-queryAXTree\n//\n// parameters:\nfunc QueryAXTree() *QueryAXTreeParams {\n\treturn &QueryAXTreeParams{}\n}\n\n// WithNodeID identifier of the node for the root to query.\nfunc (p QueryAXTreeParams) WithNodeID(nodeID cdp.NodeID) *QueryAXTreeParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node for the root to query.\nfunc (p QueryAXTreeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *QueryAXTreeParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper for the root to\n// query.\nfunc (p QueryAXTreeParams) WithObjectID(objectID runtime.RemoteObjectID) *QueryAXTreeParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// WithAccessibleName find nodes with this computed name.\nfunc (p QueryAXTreeParams) WithAccessibleName(accessibleName string) *QueryAXTreeParams {\n\tp.AccessibleName = accessibleName\n\treturn &p\n}\n\n// WithRole find nodes with this computed role.\nfunc (p QueryAXTreeParams) WithRole(role string) *QueryAXTreeParams {\n\tp.Role = role\n\treturn &p\n}\n\n// QueryAXTreeReturns return values.\ntype QueryAXTreeReturns struct {\n\tNodes []*Node `json:\"nodes,omitempty,omitzero\"` // A list of Accessibility.AXNode matching the specified attributes, including nodes that are ignored for accessibility.\n}\n\n// Do executes Accessibility.queryAXTree against the provided context.\n//\n// returns:\n//\n//\tnodes - A list of Accessibility.AXNode matching the specified attributes, including nodes that are ignored for accessibility.\nfunc (p *QueryAXTreeParams) Do(ctx context.Context) (nodes []*Node, err error) {\n\t// execute\n\tvar res QueryAXTreeReturns\n\terr = cdp.Execute(ctx, CommandQueryAXTree, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Nodes, nil\n}\n\n// Command names.\nconst (\n\tCommandDisable               = \"Accessibility.disable\"\n\tCommandEnable                = \"Accessibility.enable\"\n\tCommandGetPartialAXTree      = \"Accessibility.getPartialAXTree\"\n\tCommandGetFullAXTree         = \"Accessibility.getFullAXTree\"\n\tCommandGetRootAXNode         = \"Accessibility.getRootAXNode\"\n\tCommandGetAXNodeAndAncestors = \"Accessibility.getAXNodeAndAncestors\"\n\tCommandGetChildAXNodes       = \"Accessibility.getChildAXNodes\"\n\tCommandQueryAXTree           = \"Accessibility.queryAXTree\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/accessibility/events.go",
    "content": "package accessibility\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventLoadComplete the loadComplete event mirrors the load complete event\n// sent by the browser to assistive technology when the web page has finished\n// loading.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#event-loadComplete\ntype EventLoadComplete struct {\n\tRoot *Node `json:\"root\"` // New document root node.\n}\n\n// EventNodesUpdated the nodesUpdated event is sent every time a previously\n// requested node has changed the in tree.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#event-nodesUpdated\ntype EventNodesUpdated struct {\n\tNodes []*Node `json:\"nodes\"` // Updated node data.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/accessibility/types.go",
    "content": "package accessibility\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// NodeID unique accessibility node identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXNodeId\ntype NodeID string\n\n// String returns the NodeID as string value.\nfunc (t NodeID) String() string {\n\treturn string(t)\n}\n\n// ValueType enum of possible property types.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueType\ntype ValueType string\n\n// String returns the ValueType as string value.\nfunc (t ValueType) String() string {\n\treturn string(t)\n}\n\n// ValueType values.\nconst (\n\tValueTypeBoolean            ValueType = \"boolean\"\n\tValueTypeTristate           ValueType = \"tristate\"\n\tValueTypeBooleanOrUndefined ValueType = \"booleanOrUndefined\"\n\tValueTypeIdref              ValueType = \"idref\"\n\tValueTypeIdrefList          ValueType = \"idrefList\"\n\tValueTypeInteger            ValueType = \"integer\"\n\tValueTypeNode               ValueType = \"node\"\n\tValueTypeNodeList           ValueType = \"nodeList\"\n\tValueTypeNumber             ValueType = \"number\"\n\tValueTypeString             ValueType = \"string\"\n\tValueTypeComputedString     ValueType = \"computedString\"\n\tValueTypeToken              ValueType = \"token\"\n\tValueTypeTokenList          ValueType = \"tokenList\"\n\tValueTypeDomRelation        ValueType = \"domRelation\"\n\tValueTypeRole               ValueType = \"role\"\n\tValueTypeInternalRole       ValueType = \"internalRole\"\n\tValueTypeValueUndefined     ValueType = \"valueUndefined\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ValueType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ValueType(s) {\n\tcase ValueTypeBoolean:\n\t\t*t = ValueTypeBoolean\n\tcase ValueTypeTristate:\n\t\t*t = ValueTypeTristate\n\tcase ValueTypeBooleanOrUndefined:\n\t\t*t = ValueTypeBooleanOrUndefined\n\tcase ValueTypeIdref:\n\t\t*t = ValueTypeIdref\n\tcase ValueTypeIdrefList:\n\t\t*t = ValueTypeIdrefList\n\tcase ValueTypeInteger:\n\t\t*t = ValueTypeInteger\n\tcase ValueTypeNode:\n\t\t*t = ValueTypeNode\n\tcase ValueTypeNodeList:\n\t\t*t = ValueTypeNodeList\n\tcase ValueTypeNumber:\n\t\t*t = ValueTypeNumber\n\tcase ValueTypeString:\n\t\t*t = ValueTypeString\n\tcase ValueTypeComputedString:\n\t\t*t = ValueTypeComputedString\n\tcase ValueTypeToken:\n\t\t*t = ValueTypeToken\n\tcase ValueTypeTokenList:\n\t\t*t = ValueTypeTokenList\n\tcase ValueTypeDomRelation:\n\t\t*t = ValueTypeDomRelation\n\tcase ValueTypeRole:\n\t\t*t = ValueTypeRole\n\tcase ValueTypeInternalRole:\n\t\t*t = ValueTypeInternalRole\n\tcase ValueTypeValueUndefined:\n\t\t*t = ValueTypeValueUndefined\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ValueType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ValueSourceType enum of possible property sources.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueSourceType\ntype ValueSourceType string\n\n// String returns the ValueSourceType as string value.\nfunc (t ValueSourceType) String() string {\n\treturn string(t)\n}\n\n// ValueSourceType values.\nconst (\n\tValueSourceTypeAttribute      ValueSourceType = \"attribute\"\n\tValueSourceTypeImplicit       ValueSourceType = \"implicit\"\n\tValueSourceTypeStyle          ValueSourceType = \"style\"\n\tValueSourceTypeContents       ValueSourceType = \"contents\"\n\tValueSourceTypePlaceholder    ValueSourceType = \"placeholder\"\n\tValueSourceTypeRelatedElement ValueSourceType = \"relatedElement\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ValueSourceType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ValueSourceType(s) {\n\tcase ValueSourceTypeAttribute:\n\t\t*t = ValueSourceTypeAttribute\n\tcase ValueSourceTypeImplicit:\n\t\t*t = ValueSourceTypeImplicit\n\tcase ValueSourceTypeStyle:\n\t\t*t = ValueSourceTypeStyle\n\tcase ValueSourceTypeContents:\n\t\t*t = ValueSourceTypeContents\n\tcase ValueSourceTypePlaceholder:\n\t\t*t = ValueSourceTypePlaceholder\n\tcase ValueSourceTypeRelatedElement:\n\t\t*t = ValueSourceTypeRelatedElement\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ValueSourceType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ValueNativeSourceType enum of possible native property sources (as a\n// subtype of a particular AXValueSourceType).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueNativeSourceType\ntype ValueNativeSourceType string\n\n// String returns the ValueNativeSourceType as string value.\nfunc (t ValueNativeSourceType) String() string {\n\treturn string(t)\n}\n\n// ValueNativeSourceType values.\nconst (\n\tValueNativeSourceTypeDescription    ValueNativeSourceType = \"description\"\n\tValueNativeSourceTypeFigcaption     ValueNativeSourceType = \"figcaption\"\n\tValueNativeSourceTypeLabel          ValueNativeSourceType = \"label\"\n\tValueNativeSourceTypeLabelfor       ValueNativeSourceType = \"labelfor\"\n\tValueNativeSourceTypeLabelwrapped   ValueNativeSourceType = \"labelwrapped\"\n\tValueNativeSourceTypeLegend         ValueNativeSourceType = \"legend\"\n\tValueNativeSourceTypeRubyannotation ValueNativeSourceType = \"rubyannotation\"\n\tValueNativeSourceTypeTablecaption   ValueNativeSourceType = \"tablecaption\"\n\tValueNativeSourceTypeTitle          ValueNativeSourceType = \"title\"\n\tValueNativeSourceTypeOther          ValueNativeSourceType = \"other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ValueNativeSourceType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ValueNativeSourceType(s) {\n\tcase ValueNativeSourceTypeDescription:\n\t\t*t = ValueNativeSourceTypeDescription\n\tcase ValueNativeSourceTypeFigcaption:\n\t\t*t = ValueNativeSourceTypeFigcaption\n\tcase ValueNativeSourceTypeLabel:\n\t\t*t = ValueNativeSourceTypeLabel\n\tcase ValueNativeSourceTypeLabelfor:\n\t\t*t = ValueNativeSourceTypeLabelfor\n\tcase ValueNativeSourceTypeLabelwrapped:\n\t\t*t = ValueNativeSourceTypeLabelwrapped\n\tcase ValueNativeSourceTypeLegend:\n\t\t*t = ValueNativeSourceTypeLegend\n\tcase ValueNativeSourceTypeRubyannotation:\n\t\t*t = ValueNativeSourceTypeRubyannotation\n\tcase ValueNativeSourceTypeTablecaption:\n\t\t*t = ValueNativeSourceTypeTablecaption\n\tcase ValueNativeSourceTypeTitle:\n\t\t*t = ValueNativeSourceTypeTitle\n\tcase ValueNativeSourceTypeOther:\n\t\t*t = ValueNativeSourceTypeOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ValueNativeSourceType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ValueSource a single source for a computed AX property.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValueSource\ntype ValueSource struct {\n\tType              ValueSourceType       `json:\"type\"`                                 // What type of source this is.\n\tValue             *Value                `json:\"value,omitempty,omitzero\"`             // The value of this property source.\n\tAttribute         string                `json:\"attribute,omitempty,omitzero\"`         // The name of the relevant attribute, if any.\n\tAttributeValue    *Value                `json:\"attributeValue,omitempty,omitzero\"`    // The value of the relevant attribute, if any.\n\tSuperseded        bool                  `json:\"superseded\"`                           // Whether this source is superseded by a higher priority source.\n\tNativeSource      ValueNativeSourceType `json:\"nativeSource,omitempty,omitzero\"`      // The native markup source for this value, e.g. a <label> element.\n\tNativeSourceValue *Value                `json:\"nativeSourceValue,omitempty,omitzero\"` // The value, such as a node or node list, of the native source.\n\tInvalid           bool                  `json:\"invalid\"`                              // Whether the value for this property is invalid.\n\tInvalidReason     string                `json:\"invalidReason,omitempty,omitzero\"`     // Reason for the value being invalid, if it is.\n}\n\n// RelatedNode [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXRelatedNode\ntype RelatedNode struct {\n\tBackendDOMNodeID cdp.BackendNodeID `json:\"backendDOMNodeId\"`         // The BackendNodeId of the related DOM node.\n\tIdref            string            `json:\"idref,omitempty,omitzero\"` // The IDRef value provided, if any.\n\tText             string            `json:\"text,omitempty,omitzero\"`  // The text alternative of this node in the current context.\n}\n\n// Property [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXProperty\ntype Property struct {\n\tName  PropertyName `json:\"name\"`  // The name of this property.\n\tValue *Value       `json:\"value\"` // The value of this property.\n}\n\n// Value a single computed AX property.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXValue\ntype Value struct {\n\tType         ValueType      `json:\"type\"`                            // The type of this value.\n\tValue        jsontext.Value `json:\"value,omitempty,omitzero\"`        // The computed value of this property.\n\tRelatedNodes []*RelatedNode `json:\"relatedNodes,omitempty,omitzero\"` // One or more related nodes, if applicable.\n\tSources      []*ValueSource `json:\"sources,omitempty,omitzero\"`      // The sources which contributed to the computation of this property.\n}\n\n// PropertyName values of AXProperty name: - from 'busy' to\n// 'roledescription': states which apply to every AX node - from 'live' to\n// 'root': attributes which apply to nodes in live regions - from 'autocomplete'\n// to 'valuetext': attributes which apply to widgets - from 'checked' to\n// 'selected': states which apply to widgets - from 'activedescendant' to 'owns'\n// - relationships between elements other than parent/child/sibling.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXPropertyName\ntype PropertyName string\n\n// String returns the PropertyName as string value.\nfunc (t PropertyName) String() string {\n\treturn string(t)\n}\n\n// PropertyName values.\nconst (\n\tPropertyNameActions          PropertyName = \"actions\"\n\tPropertyNameBusy             PropertyName = \"busy\"\n\tPropertyNameDisabled         PropertyName = \"disabled\"\n\tPropertyNameEditable         PropertyName = \"editable\"\n\tPropertyNameFocusable        PropertyName = \"focusable\"\n\tPropertyNameFocused          PropertyName = \"focused\"\n\tPropertyNameHidden           PropertyName = \"hidden\"\n\tPropertyNameHiddenRoot       PropertyName = \"hiddenRoot\"\n\tPropertyNameInvalid          PropertyName = \"invalid\"\n\tPropertyNameKeyshortcuts     PropertyName = \"keyshortcuts\"\n\tPropertyNameSettable         PropertyName = \"settable\"\n\tPropertyNameRoledescription  PropertyName = \"roledescription\"\n\tPropertyNameLive             PropertyName = \"live\"\n\tPropertyNameAtomic           PropertyName = \"atomic\"\n\tPropertyNameRelevant         PropertyName = \"relevant\"\n\tPropertyNameRoot             PropertyName = \"root\"\n\tPropertyNameAutocomplete     PropertyName = \"autocomplete\"\n\tPropertyNameHasPopup         PropertyName = \"hasPopup\"\n\tPropertyNameLevel            PropertyName = \"level\"\n\tPropertyNameMultiselectable  PropertyName = \"multiselectable\"\n\tPropertyNameOrientation      PropertyName = \"orientation\"\n\tPropertyNameMultiline        PropertyName = \"multiline\"\n\tPropertyNameReadonly         PropertyName = \"readonly\"\n\tPropertyNameRequired         PropertyName = \"required\"\n\tPropertyNameValuemin         PropertyName = \"valuemin\"\n\tPropertyNameValuemax         PropertyName = \"valuemax\"\n\tPropertyNameValuetext        PropertyName = \"valuetext\"\n\tPropertyNameChecked          PropertyName = \"checked\"\n\tPropertyNameExpanded         PropertyName = \"expanded\"\n\tPropertyNameModal            PropertyName = \"modal\"\n\tPropertyNamePressed          PropertyName = \"pressed\"\n\tPropertyNameSelected         PropertyName = \"selected\"\n\tPropertyNameActivedescendant PropertyName = \"activedescendant\"\n\tPropertyNameControls         PropertyName = \"controls\"\n\tPropertyNameDescribedby      PropertyName = \"describedby\"\n\tPropertyNameDetails          PropertyName = \"details\"\n\tPropertyNameErrormessage     PropertyName = \"errormessage\"\n\tPropertyNameFlowto           PropertyName = \"flowto\"\n\tPropertyNameLabelledby       PropertyName = \"labelledby\"\n\tPropertyNameOwns             PropertyName = \"owns\"\n\tPropertyNameURL              PropertyName = \"url\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PropertyName) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PropertyName(s) {\n\tcase PropertyNameActions:\n\t\t*t = PropertyNameActions\n\tcase PropertyNameBusy:\n\t\t*t = PropertyNameBusy\n\tcase PropertyNameDisabled:\n\t\t*t = PropertyNameDisabled\n\tcase PropertyNameEditable:\n\t\t*t = PropertyNameEditable\n\tcase PropertyNameFocusable:\n\t\t*t = PropertyNameFocusable\n\tcase PropertyNameFocused:\n\t\t*t = PropertyNameFocused\n\tcase PropertyNameHidden:\n\t\t*t = PropertyNameHidden\n\tcase PropertyNameHiddenRoot:\n\t\t*t = PropertyNameHiddenRoot\n\tcase PropertyNameInvalid:\n\t\t*t = PropertyNameInvalid\n\tcase PropertyNameKeyshortcuts:\n\t\t*t = PropertyNameKeyshortcuts\n\tcase PropertyNameSettable:\n\t\t*t = PropertyNameSettable\n\tcase PropertyNameRoledescription:\n\t\t*t = PropertyNameRoledescription\n\tcase PropertyNameLive:\n\t\t*t = PropertyNameLive\n\tcase PropertyNameAtomic:\n\t\t*t = PropertyNameAtomic\n\tcase PropertyNameRelevant:\n\t\t*t = PropertyNameRelevant\n\tcase PropertyNameRoot:\n\t\t*t = PropertyNameRoot\n\tcase PropertyNameAutocomplete:\n\t\t*t = PropertyNameAutocomplete\n\tcase PropertyNameHasPopup:\n\t\t*t = PropertyNameHasPopup\n\tcase PropertyNameLevel:\n\t\t*t = PropertyNameLevel\n\tcase PropertyNameMultiselectable:\n\t\t*t = PropertyNameMultiselectable\n\tcase PropertyNameOrientation:\n\t\t*t = PropertyNameOrientation\n\tcase PropertyNameMultiline:\n\t\t*t = PropertyNameMultiline\n\tcase PropertyNameReadonly:\n\t\t*t = PropertyNameReadonly\n\tcase PropertyNameRequired:\n\t\t*t = PropertyNameRequired\n\tcase PropertyNameValuemin:\n\t\t*t = PropertyNameValuemin\n\tcase PropertyNameValuemax:\n\t\t*t = PropertyNameValuemax\n\tcase PropertyNameValuetext:\n\t\t*t = PropertyNameValuetext\n\tcase PropertyNameChecked:\n\t\t*t = PropertyNameChecked\n\tcase PropertyNameExpanded:\n\t\t*t = PropertyNameExpanded\n\tcase PropertyNameModal:\n\t\t*t = PropertyNameModal\n\tcase PropertyNamePressed:\n\t\t*t = PropertyNamePressed\n\tcase PropertyNameSelected:\n\t\t*t = PropertyNameSelected\n\tcase PropertyNameActivedescendant:\n\t\t*t = PropertyNameActivedescendant\n\tcase PropertyNameControls:\n\t\t*t = PropertyNameControls\n\tcase PropertyNameDescribedby:\n\t\t*t = PropertyNameDescribedby\n\tcase PropertyNameDetails:\n\t\t*t = PropertyNameDetails\n\tcase PropertyNameErrormessage:\n\t\t*t = PropertyNameErrormessage\n\tcase PropertyNameFlowto:\n\t\t*t = PropertyNameFlowto\n\tcase PropertyNameLabelledby:\n\t\t*t = PropertyNameLabelledby\n\tcase PropertyNameOwns:\n\t\t*t = PropertyNameOwns\n\tcase PropertyNameURL:\n\t\t*t = PropertyNameURL\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PropertyName value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Node a node in the accessibility tree.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Accessibility#type-AXNode\ntype Node struct {\n\tNodeID           NodeID            `json:\"nodeId\"`                              // Unique identifier for this node.\n\tIgnored          bool              `json:\"ignored\"`                             // Whether this node is ignored for accessibility\n\tIgnoredReasons   []*Property       `json:\"ignoredReasons,omitempty,omitzero\"`   // Collection of reasons why this node is hidden.\n\tRole             *Value            `json:\"role,omitempty,omitzero\"`             // This Node's role, whether explicit or implicit.\n\tChromeRole       *Value            `json:\"chromeRole,omitempty,omitzero\"`       // This Node's Chrome raw role.\n\tName             *Value            `json:\"name,omitempty,omitzero\"`             // The accessible name for this Node.\n\tDescription      *Value            `json:\"description,omitempty,omitzero\"`      // The accessible description for this Node.\n\tValue            *Value            `json:\"value,omitempty,omitzero\"`            // The value for this Node.\n\tProperties       []*Property       `json:\"properties,omitempty,omitzero\"`       // All other properties\n\tParentID         NodeID            `json:\"parentId,omitempty,omitzero\"`         // ID for this node's parent.\n\tChildIDs         []NodeID          `json:\"childIds,omitempty,omitzero\"`         // IDs for each of this node's child nodes.\n\tBackendDOMNodeID cdp.BackendNodeID `json:\"backendDOMNodeId,omitempty,omitzero\"` // The backend ID for the associated DOM node, if any.\n\tFrameID          cdp.FrameID       `json:\"frameId,omitempty,omitzero\"`          // The frame ID for the frame associated with this nodes document.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/animation/animation.go",
    "content": "// Package animation provides the Chrome DevTools Protocol\n// commands, types, and events for the Animation domain.\n//\n// Generated by the cdproto-gen command.\npackage animation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// DisableParams disables animation domain notifications.\ntype DisableParams struct{}\n\n// Disable disables animation domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Animation.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables animation domain notifications.\ntype EnableParams struct{}\n\n// Enable enables animation domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Animation.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// GetCurrentTimeParams returns the current time of the an animation.\ntype GetCurrentTimeParams struct {\n\tID string `json:\"id\"` // Id of animation.\n}\n\n// GetCurrentTime returns the current time of the an animation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-getCurrentTime\n//\n// parameters:\n//\n//\tid - Id of animation.\nfunc GetCurrentTime(id string) *GetCurrentTimeParams {\n\treturn &GetCurrentTimeParams{\n\t\tID: id,\n\t}\n}\n\n// GetCurrentTimeReturns return values.\ntype GetCurrentTimeReturns struct {\n\tCurrentTime float64 `json:\"currentTime,omitempty,omitzero\"` // Current time of the page.\n}\n\n// Do executes Animation.getCurrentTime against the provided context.\n//\n// returns:\n//\n//\tcurrentTime - Current time of the page.\nfunc (p *GetCurrentTimeParams) Do(ctx context.Context) (currentTime float64, err error) {\n\t// execute\n\tvar res GetCurrentTimeReturns\n\terr = cdp.Execute(ctx, CommandGetCurrentTime, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.CurrentTime, nil\n}\n\n// GetPlaybackRateParams gets the playback rate of the document timeline.\ntype GetPlaybackRateParams struct{}\n\n// GetPlaybackRate gets the playback rate of the document timeline.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-getPlaybackRate\nfunc GetPlaybackRate() *GetPlaybackRateParams {\n\treturn &GetPlaybackRateParams{}\n}\n\n// GetPlaybackRateReturns return values.\ntype GetPlaybackRateReturns struct {\n\tPlaybackRate float64 `json:\"playbackRate,omitempty,omitzero\"` // Playback rate for animations on page.\n}\n\n// Do executes Animation.getPlaybackRate against the provided context.\n//\n// returns:\n//\n//\tplaybackRate - Playback rate for animations on page.\nfunc (p *GetPlaybackRateParams) Do(ctx context.Context) (playbackRate float64, err error) {\n\t// execute\n\tvar res GetPlaybackRateReturns\n\terr = cdp.Execute(ctx, CommandGetPlaybackRate, nil, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.PlaybackRate, nil\n}\n\n// ReleaseAnimationsParams releases a set of animations to no longer be\n// manipulated.\ntype ReleaseAnimationsParams struct {\n\tAnimations []string `json:\"animations\"` // List of animation ids to seek.\n}\n\n// ReleaseAnimations releases a set of animations to no longer be\n// manipulated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-releaseAnimations\n//\n// parameters:\n//\n//\tanimations - List of animation ids to seek.\nfunc ReleaseAnimations(animations []string) *ReleaseAnimationsParams {\n\treturn &ReleaseAnimationsParams{\n\t\tAnimations: animations,\n\t}\n}\n\n// Do executes Animation.releaseAnimations against the provided context.\nfunc (p *ReleaseAnimationsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandReleaseAnimations, p, nil)\n}\n\n// ResolveAnimationParams gets the remote object of the Animation.\ntype ResolveAnimationParams struct {\n\tAnimationID string `json:\"animationId\"` // Animation id.\n}\n\n// ResolveAnimation gets the remote object of the Animation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-resolveAnimation\n//\n// parameters:\n//\n//\tanimationID - Animation id.\nfunc ResolveAnimation(animationID string) *ResolveAnimationParams {\n\treturn &ResolveAnimationParams{\n\t\tAnimationID: animationID,\n\t}\n}\n\n// ResolveAnimationReturns return values.\ntype ResolveAnimationReturns struct {\n\tRemoteObject *runtime.RemoteObject `json:\"remoteObject,omitempty,omitzero\"` // Corresponding remote object.\n}\n\n// Do executes Animation.resolveAnimation against the provided context.\n//\n// returns:\n//\n//\tremoteObject - Corresponding remote object.\nfunc (p *ResolveAnimationParams) Do(ctx context.Context) (remoteObject *runtime.RemoteObject, err error) {\n\t// execute\n\tvar res ResolveAnimationReturns\n\terr = cdp.Execute(ctx, CommandResolveAnimation, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.RemoteObject, nil\n}\n\n// SeekAnimationsParams seek a set of animations to a particular time within\n// each animation.\ntype SeekAnimationsParams struct {\n\tAnimations  []string `json:\"animations\"`  // List of animation ids to seek.\n\tCurrentTime float64  `json:\"currentTime\"` // Set the current time of each animation.\n}\n\n// SeekAnimations seek a set of animations to a particular time within each\n// animation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-seekAnimations\n//\n// parameters:\n//\n//\tanimations - List of animation ids to seek.\n//\tcurrentTime - Set the current time of each animation.\nfunc SeekAnimations(animations []string, currentTime float64) *SeekAnimationsParams {\n\treturn &SeekAnimationsParams{\n\t\tAnimations:  animations,\n\t\tCurrentTime: currentTime,\n\t}\n}\n\n// Do executes Animation.seekAnimations against the provided context.\nfunc (p *SeekAnimationsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSeekAnimations, p, nil)\n}\n\n// SetPausedParams sets the paused state of a set of animations.\ntype SetPausedParams struct {\n\tAnimations []string `json:\"animations\"` // Animations to set the pause state of.\n\tPaused     bool     `json:\"paused\"`     // Paused state to set to.\n}\n\n// SetPaused sets the paused state of a set of animations.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-setPaused\n//\n// parameters:\n//\n//\tanimations - Animations to set the pause state of.\n//\tpaused - Paused state to set to.\nfunc SetPaused(animations []string, paused bool) *SetPausedParams {\n\treturn &SetPausedParams{\n\t\tAnimations: animations,\n\t\tPaused:     paused,\n\t}\n}\n\n// Do executes Animation.setPaused against the provided context.\nfunc (p *SetPausedParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPaused, p, nil)\n}\n\n// SetPlaybackRateParams sets the playback rate of the document timeline.\ntype SetPlaybackRateParams struct {\n\tPlaybackRate float64 `json:\"playbackRate\"` // Playback rate for animations on page\n}\n\n// SetPlaybackRate sets the playback rate of the document timeline.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-setPlaybackRate\n//\n// parameters:\n//\n//\tplaybackRate - Playback rate for animations on page\nfunc SetPlaybackRate(playbackRate float64) *SetPlaybackRateParams {\n\treturn &SetPlaybackRateParams{\n\t\tPlaybackRate: playbackRate,\n\t}\n}\n\n// Do executes Animation.setPlaybackRate against the provided context.\nfunc (p *SetPlaybackRateParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPlaybackRate, p, nil)\n}\n\n// SetTimingParams sets the timing of an animation node.\ntype SetTimingParams struct {\n\tAnimationID string  `json:\"animationId\"` // Animation id.\n\tDuration    float64 `json:\"duration\"`    // Duration of the animation.\n\tDelay       float64 `json:\"delay\"`       // Delay of the animation.\n}\n\n// SetTiming sets the timing of an animation node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#method-setTiming\n//\n// parameters:\n//\n//\tanimationID - Animation id.\n//\tduration - Duration of the animation.\n//\tdelay - Delay of the animation.\nfunc SetTiming(animationID string, duration float64, delay float64) *SetTimingParams {\n\treturn &SetTimingParams{\n\t\tAnimationID: animationID,\n\t\tDuration:    duration,\n\t\tDelay:       delay,\n\t}\n}\n\n// Do executes Animation.setTiming against the provided context.\nfunc (p *SetTimingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetTiming, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandDisable           = \"Animation.disable\"\n\tCommandEnable            = \"Animation.enable\"\n\tCommandGetCurrentTime    = \"Animation.getCurrentTime\"\n\tCommandGetPlaybackRate   = \"Animation.getPlaybackRate\"\n\tCommandReleaseAnimations = \"Animation.releaseAnimations\"\n\tCommandResolveAnimation  = \"Animation.resolveAnimation\"\n\tCommandSeekAnimations    = \"Animation.seekAnimations\"\n\tCommandSetPaused         = \"Animation.setPaused\"\n\tCommandSetPlaybackRate   = \"Animation.setPlaybackRate\"\n\tCommandSetTiming         = \"Animation.setTiming\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/animation/events.go",
    "content": "package animation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventAnimationCanceled event for when an animation has been cancelled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#event-animationCanceled\ntype EventAnimationCanceled struct {\n\tID string `json:\"id\"` // Id of the animation that was cancelled.\n}\n\n// EventAnimationCreated event for each animation that has been created.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#event-animationCreated\ntype EventAnimationCreated struct {\n\tID string `json:\"id\"` // Id of the animation that was created.\n}\n\n// EventAnimationStarted event for animation that has been started.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#event-animationStarted\ntype EventAnimationStarted struct {\n\tAnimation *Animation `json:\"animation\"` // Animation that was started.\n}\n\n// EventAnimationUpdated event for animation that has been updated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#event-animationUpdated\ntype EventAnimationUpdated struct {\n\tAnimation *Animation `json:\"animation\"` // Animation that was updated.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/animation/types.go",
    "content": "package animation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n)\n\n// Animation animation instance.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-Animation\ntype Animation struct {\n\tID                   string                `json:\"id\"`                                      // Animation's id.\n\tName                 string                `json:\"name\"`                                    // Animation's name.\n\tPausedState          bool                  `json:\"pausedState\"`                             // Animation's internal paused state.\n\tPlayState            string                `json:\"playState\"`                               // Animation's play state.\n\tPlaybackRate         float64               `json:\"playbackRate\"`                            // Animation's playback rate.\n\tStartTime            float64               `json:\"startTime\"`                               // Animation's start time. Milliseconds for time based animations and percentage [0 - 100] for scroll driven animations (i.e. when viewOrScrollTimeline exists).\n\tCurrentTime          float64               `json:\"currentTime\"`                             // Animation's current time.\n\tType                 Type                  `json:\"type\"`                                    // Animation type of Animation.\n\tSource               *Effect               `json:\"source,omitempty,omitzero\"`               // Animation's source animation node.\n\tCSSID                string                `json:\"cssId,omitempty,omitzero\"`                // A unique ID for Animation representing the sources that triggered this CSS animation/transition.\n\tViewOrScrollTimeline *ViewOrScrollTimeline `json:\"viewOrScrollTimeline,omitempty,omitzero\"` // View or scroll timeline\n}\n\n// ViewOrScrollTimeline timeline instance.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-ViewOrScrollTimeline\ntype ViewOrScrollTimeline struct {\n\tSourceNodeID  cdp.BackendNodeID     `json:\"sourceNodeId,omitempty,omitzero\"`  // Scroll container node\n\tStartOffset   float64               `json:\"startOffset,omitempty,omitzero\"`   // Represents the starting scroll position of the timeline as a length offset in pixels from scroll origin.\n\tEndOffset     float64               `json:\"endOffset,omitempty,omitzero\"`     // Represents the ending scroll position of the timeline as a length offset in pixels from scroll origin.\n\tSubjectNodeID cdp.BackendNodeID     `json:\"subjectNodeId,omitempty,omitzero\"` // The element whose principal box's visibility in the scrollport defined the progress of the timeline. Does not exist for animations with ScrollTimeline\n\tAxis          dom.ScrollOrientation `json:\"axis\"`                             // Orientation of the scroll\n}\n\n// Effect animationEffect instance.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-AnimationEffect\ntype Effect struct {\n\tDelay          float64           `json:\"delay\"`                            // AnimationEffect's delay.\n\tEndDelay       float64           `json:\"endDelay\"`                         // AnimationEffect's end delay.\n\tIterationStart float64           `json:\"iterationStart\"`                   // AnimationEffect's iteration start.\n\tIterations     float64           `json:\"iterations\"`                       // AnimationEffect's iterations.\n\tDuration       float64           `json:\"duration\"`                         // AnimationEffect's iteration duration. Milliseconds for time based animations and percentage [0 - 100] for scroll driven animations (i.e. when viewOrScrollTimeline exists).\n\tDirection      string            `json:\"direction\"`                        // AnimationEffect's playback direction.\n\tFill           string            `json:\"fill\"`                             // AnimationEffect's fill mode.\n\tBackendNodeID  cdp.BackendNodeID `json:\"backendNodeId,omitempty,omitzero\"` // AnimationEffect's target node.\n\tKeyframesRule  *KeyframesRule    `json:\"keyframesRule,omitempty,omitzero\"` // AnimationEffect's keyframes.\n\tEasing         string            `json:\"easing\"`                           // AnimationEffect's timing function.\n}\n\n// KeyframesRule keyframes Rule.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-KeyframesRule\ntype KeyframesRule struct {\n\tName      string           `json:\"name,omitempty,omitzero\"` // CSS keyframed animation's name.\n\tKeyframes []*KeyframeStyle `json:\"keyframes\"`               // List of animation keyframes.\n}\n\n// KeyframeStyle keyframe Style.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-KeyframeStyle\ntype KeyframeStyle struct {\n\tOffset string `json:\"offset\"` // Keyframe's time offset.\n\tEasing string `json:\"easing\"` // AnimationEffect's timing function.\n}\n\n// Type animation type of Animation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Animation#type-Animation\ntype Type string\n\n// String returns the Type as string value.\nfunc (t Type) String() string {\n\treturn string(t)\n}\n\n// Type values.\nconst (\n\tTypeCSSTransition Type = \"CSSTransition\"\n\tTypeCSSAnimation  Type = \"CSSAnimation\"\n\tTypeWebAnimation  Type = \"WebAnimation\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Type) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Type(s) {\n\tcase TypeCSSTransition:\n\t\t*t = TypeCSSTransition\n\tcase TypeCSSAnimation:\n\t\t*t = TypeCSSAnimation\n\tcase TypeWebAnimation:\n\t\t*t = TypeWebAnimation\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Type value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/audits/audits.go",
    "content": "// Package audits provides the Chrome DevTools Protocol\n// commands, types, and events for the Audits domain.\n//\n// Audits domain allows investigation of page violations and possible\n// improvements.\n//\n// Generated by the cdproto-gen command.\npackage audits\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n)\n\n// GetEncodedResponseParams returns the response body and size if it were\n// re-encoded with the specified settings. Only applies to images.\ntype GetEncodedResponseParams struct {\n\tRequestID network.RequestID          `json:\"requestId\"`                  // Identifier of the network request to get content for.\n\tEncoding  GetEncodedResponseEncoding `json:\"encoding\"`                   // The encoding to use.\n\tQuality   float64                    `json:\"quality,omitempty,omitzero\"` // The quality of the encoding (0-1). (defaults to 1)\n\tSizeOnly  bool                       `json:\"sizeOnly\"`                   // Whether to only return the size information (defaults to false).\n}\n\n// GetEncodedResponse returns the response body and size if it were\n// re-encoded with the specified settings. Only applies to images.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-getEncodedResponse\n//\n// parameters:\n//\n//\trequestID - Identifier of the network request to get content for.\n//\tencoding - The encoding to use.\nfunc GetEncodedResponse(requestID network.RequestID, encoding GetEncodedResponseEncoding) *GetEncodedResponseParams {\n\treturn &GetEncodedResponseParams{\n\t\tRequestID: requestID,\n\t\tEncoding:  encoding,\n\t\tSizeOnly:  false,\n\t}\n}\n\n// WithQuality the quality of the encoding (0-1). (defaults to 1).\nfunc (p GetEncodedResponseParams) WithQuality(quality float64) *GetEncodedResponseParams {\n\tp.Quality = quality\n\treturn &p\n}\n\n// WithSizeOnly whether to only return the size information (defaults to\n// false).\nfunc (p GetEncodedResponseParams) WithSizeOnly(sizeOnly bool) *GetEncodedResponseParams {\n\tp.SizeOnly = sizeOnly\n\treturn &p\n}\n\n// GetEncodedResponseReturns return values.\ntype GetEncodedResponseReturns struct {\n\tBody         string `json:\"body,omitempty,omitzero\"`         // The encoded body as a base64 string. Omitted if sizeOnly is true.\n\tOriginalSize int64  `json:\"originalSize,omitempty,omitzero\"` // Size before re-encoding.\n\tEncodedSize  int64  `json:\"encodedSize,omitempty,omitzero\"`  // Size after re-encoding.\n}\n\n// Do executes Audits.getEncodedResponse against the provided context.\n//\n// returns:\n//\n//\tbody - The encoded body as a base64 string. Omitted if sizeOnly is true.\n//\toriginalSize - Size before re-encoding.\n//\tencodedSize - Size after re-encoding.\nfunc (p *GetEncodedResponseParams) Do(ctx context.Context) (body []byte, originalSize int64, encodedSize int64, err error) {\n\t// execute\n\tvar res GetEncodedResponseReturns\n\terr = cdp.Execute(ctx, CommandGetEncodedResponse, p, &res)\n\tif err != nil {\n\t\treturn nil, 0, 0, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tdec, err = base64.StdEncoding.DecodeString(res.Body)\n\tif err != nil {\n\t\treturn nil, 0, 0, err\n\t}\n\treturn dec, res.OriginalSize, res.EncodedSize, nil\n}\n\n// DisableParams disables issues domain, prevents further issues from being\n// reported to the client.\ntype DisableParams struct{}\n\n// Disable disables issues domain, prevents further issues from being\n// reported to the client.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Audits.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables issues domain, sends the issues collected so far to\n// the client by means of the issueAdded event.\ntype EnableParams struct{}\n\n// Enable enables issues domain, sends the issues collected so far to the\n// client by means of the issueAdded event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Audits.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// CheckContrastParams runs the contrast check for the target page. Found\n// issues are reported using Audits.issueAdded event.\ntype CheckContrastParams struct {\n\tReportAAA bool `json:\"reportAAA\"` // Whether to report WCAG AAA level issues. Default is false.\n}\n\n// CheckContrast runs the contrast check for the target page. Found issues\n// are reported using Audits.issueAdded event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-checkContrast\n//\n// parameters:\nfunc CheckContrast() *CheckContrastParams {\n\treturn &CheckContrastParams{\n\t\tReportAAA: false,\n\t}\n}\n\n// WithReportAAA whether to report WCAG AAA level issues. Default is false.\nfunc (p CheckContrastParams) WithReportAAA(reportAAA bool) *CheckContrastParams {\n\tp.ReportAAA = reportAAA\n\treturn &p\n}\n\n// Do executes Audits.checkContrast against the provided context.\nfunc (p *CheckContrastParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCheckContrast, p, nil)\n}\n\n// CheckFormsIssuesParams runs the form issues check for the target page.\n// Found issues are reported using Audits.issueAdded event.\ntype CheckFormsIssuesParams struct{}\n\n// CheckFormsIssues runs the form issues check for the target page. Found\n// issues are reported using Audits.issueAdded event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-checkFormsIssues\nfunc CheckFormsIssues() *CheckFormsIssuesParams {\n\treturn &CheckFormsIssuesParams{}\n}\n\n// CheckFormsIssuesReturns return values.\ntype CheckFormsIssuesReturns struct {\n\tFormIssues []*GenericIssueDetails `json:\"formIssues,omitempty,omitzero\"`\n}\n\n// Do executes Audits.checkFormsIssues against the provided context.\n//\n// returns:\n//\n//\tformIssues\nfunc (p *CheckFormsIssuesParams) Do(ctx context.Context) (formIssues []*GenericIssueDetails, err error) {\n\t// execute\n\tvar res CheckFormsIssuesReturns\n\terr = cdp.Execute(ctx, CommandCheckFormsIssues, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.FormIssues, nil\n}\n\n// Command names.\nconst (\n\tCommandGetEncodedResponse = \"Audits.getEncodedResponse\"\n\tCommandDisable            = \"Audits.disable\"\n\tCommandEnable             = \"Audits.enable\"\n\tCommandCheckContrast      = \"Audits.checkContrast\"\n\tCommandCheckFormsIssues   = \"Audits.checkFormsIssues\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/audits/events.go",
    "content": "package audits\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventIssueAdded [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#event-issueAdded\ntype EventIssueAdded struct {\n\tIssue *InspectorIssue `json:\"issue\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/audits/types.go",
    "content": "package audits\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// AffectedCookie information about a cookie that is affected by an inspector\n// issue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-AffectedCookie\ntype AffectedCookie struct {\n\tName   string `json:\"name\"` // The following three properties uniquely identify a cookie\n\tPath   string `json:\"path\"`\n\tDomain string `json:\"domain\"`\n}\n\n// AffectedRequest information about a request that is affected by an\n// inspector issue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-AffectedRequest\ntype AffectedRequest struct {\n\tRequestID network.RequestID `json:\"requestId,omitempty,omitzero\"` // The unique request id.\n\tURL       string            `json:\"url\"`\n}\n\n// AffectedFrame information about the frame affected by an inspector issue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-AffectedFrame\ntype AffectedFrame struct {\n\tFrameID cdp.FrameID `json:\"frameId\"`\n}\n\n// CookieExclusionReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-CookieExclusionReason\ntype CookieExclusionReason string\n\n// String returns the CookieExclusionReason as string value.\nfunc (t CookieExclusionReason) String() string {\n\treturn string(t)\n}\n\n// CookieExclusionReason values.\nconst (\n\tCookieExclusionReasonExcludeSameSiteUnspecifiedTreatedAsLax        CookieExclusionReason = \"ExcludeSameSiteUnspecifiedTreatedAsLax\"\n\tCookieExclusionReasonExcludeSameSiteNoneInsecure                   CookieExclusionReason = \"ExcludeSameSiteNoneInsecure\"\n\tCookieExclusionReasonExcludeSameSiteLax                            CookieExclusionReason = \"ExcludeSameSiteLax\"\n\tCookieExclusionReasonExcludeSameSiteStrict                         CookieExclusionReason = \"ExcludeSameSiteStrict\"\n\tCookieExclusionReasonExcludeInvalidSameParty                       CookieExclusionReason = \"ExcludeInvalidSameParty\"\n\tCookieExclusionReasonExcludeSamePartyCrossPartyContext             CookieExclusionReason = \"ExcludeSamePartyCrossPartyContext\"\n\tCookieExclusionReasonExcludeDomainNonASCII                         CookieExclusionReason = \"ExcludeDomainNonASCII\"\n\tCookieExclusionReasonExcludeThirdPartyCookieBlockedInFirstPartySet CookieExclusionReason = \"ExcludeThirdPartyCookieBlockedInFirstPartySet\"\n\tCookieExclusionReasonExcludeThirdPartyPhaseout                     CookieExclusionReason = \"ExcludeThirdPartyPhaseout\"\n\tCookieExclusionReasonExcludePortMismatch                           CookieExclusionReason = \"ExcludePortMismatch\"\n\tCookieExclusionReasonExcludeSchemeMismatch                         CookieExclusionReason = \"ExcludeSchemeMismatch\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookieExclusionReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookieExclusionReason(s) {\n\tcase CookieExclusionReasonExcludeSameSiteUnspecifiedTreatedAsLax:\n\t\t*t = CookieExclusionReasonExcludeSameSiteUnspecifiedTreatedAsLax\n\tcase CookieExclusionReasonExcludeSameSiteNoneInsecure:\n\t\t*t = CookieExclusionReasonExcludeSameSiteNoneInsecure\n\tcase CookieExclusionReasonExcludeSameSiteLax:\n\t\t*t = CookieExclusionReasonExcludeSameSiteLax\n\tcase CookieExclusionReasonExcludeSameSiteStrict:\n\t\t*t = CookieExclusionReasonExcludeSameSiteStrict\n\tcase CookieExclusionReasonExcludeInvalidSameParty:\n\t\t*t = CookieExclusionReasonExcludeInvalidSameParty\n\tcase CookieExclusionReasonExcludeSamePartyCrossPartyContext:\n\t\t*t = CookieExclusionReasonExcludeSamePartyCrossPartyContext\n\tcase CookieExclusionReasonExcludeDomainNonASCII:\n\t\t*t = CookieExclusionReasonExcludeDomainNonASCII\n\tcase CookieExclusionReasonExcludeThirdPartyCookieBlockedInFirstPartySet:\n\t\t*t = CookieExclusionReasonExcludeThirdPartyCookieBlockedInFirstPartySet\n\tcase CookieExclusionReasonExcludeThirdPartyPhaseout:\n\t\t*t = CookieExclusionReasonExcludeThirdPartyPhaseout\n\tcase CookieExclusionReasonExcludePortMismatch:\n\t\t*t = CookieExclusionReasonExcludePortMismatch\n\tcase CookieExclusionReasonExcludeSchemeMismatch:\n\t\t*t = CookieExclusionReasonExcludeSchemeMismatch\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookieExclusionReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookieWarningReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-CookieWarningReason\ntype CookieWarningReason string\n\n// String returns the CookieWarningReason as string value.\nfunc (t CookieWarningReason) String() string {\n\treturn string(t)\n}\n\n// CookieWarningReason values.\nconst (\n\tCookieWarningReasonWarnSameSiteUnspecifiedCrossSiteContext        CookieWarningReason = \"WarnSameSiteUnspecifiedCrossSiteContext\"\n\tCookieWarningReasonWarnSameSiteNoneInsecure                       CookieWarningReason = \"WarnSameSiteNoneInsecure\"\n\tCookieWarningReasonWarnSameSiteUnspecifiedLaxAllowUnsafe          CookieWarningReason = \"WarnSameSiteUnspecifiedLaxAllowUnsafe\"\n\tCookieWarningReasonWarnSameSiteStrictLaxDowngradeStrict           CookieWarningReason = \"WarnSameSiteStrictLaxDowngradeStrict\"\n\tCookieWarningReasonWarnSameSiteStrictCrossDowngradeStrict         CookieWarningReason = \"WarnSameSiteStrictCrossDowngradeStrict\"\n\tCookieWarningReasonWarnSameSiteStrictCrossDowngradeLax            CookieWarningReason = \"WarnSameSiteStrictCrossDowngradeLax\"\n\tCookieWarningReasonWarnSameSiteLaxCrossDowngradeStrict            CookieWarningReason = \"WarnSameSiteLaxCrossDowngradeStrict\"\n\tCookieWarningReasonWarnSameSiteLaxCrossDowngradeLax               CookieWarningReason = \"WarnSameSiteLaxCrossDowngradeLax\"\n\tCookieWarningReasonWarnAttributeValueExceedsMaxSize               CookieWarningReason = \"WarnAttributeValueExceedsMaxSize\"\n\tCookieWarningReasonWarnDomainNonASCII                             CookieWarningReason = \"WarnDomainNonASCII\"\n\tCookieWarningReasonWarnThirdPartyPhaseout                         CookieWarningReason = \"WarnThirdPartyPhaseout\"\n\tCookieWarningReasonWarnCrossSiteRedirectDowngradeChangesInclusion CookieWarningReason = \"WarnCrossSiteRedirectDowngradeChangesInclusion\"\n\tCookieWarningReasonWarnDeprecationTrialMetadata                   CookieWarningReason = \"WarnDeprecationTrialMetadata\"\n\tCookieWarningReasonWarnThirdPartyCookieHeuristic                  CookieWarningReason = \"WarnThirdPartyCookieHeuristic\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookieWarningReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookieWarningReason(s) {\n\tcase CookieWarningReasonWarnSameSiteUnspecifiedCrossSiteContext:\n\t\t*t = CookieWarningReasonWarnSameSiteUnspecifiedCrossSiteContext\n\tcase CookieWarningReasonWarnSameSiteNoneInsecure:\n\t\t*t = CookieWarningReasonWarnSameSiteNoneInsecure\n\tcase CookieWarningReasonWarnSameSiteUnspecifiedLaxAllowUnsafe:\n\t\t*t = CookieWarningReasonWarnSameSiteUnspecifiedLaxAllowUnsafe\n\tcase CookieWarningReasonWarnSameSiteStrictLaxDowngradeStrict:\n\t\t*t = CookieWarningReasonWarnSameSiteStrictLaxDowngradeStrict\n\tcase CookieWarningReasonWarnSameSiteStrictCrossDowngradeStrict:\n\t\t*t = CookieWarningReasonWarnSameSiteStrictCrossDowngradeStrict\n\tcase CookieWarningReasonWarnSameSiteStrictCrossDowngradeLax:\n\t\t*t = CookieWarningReasonWarnSameSiteStrictCrossDowngradeLax\n\tcase CookieWarningReasonWarnSameSiteLaxCrossDowngradeStrict:\n\t\t*t = CookieWarningReasonWarnSameSiteLaxCrossDowngradeStrict\n\tcase CookieWarningReasonWarnSameSiteLaxCrossDowngradeLax:\n\t\t*t = CookieWarningReasonWarnSameSiteLaxCrossDowngradeLax\n\tcase CookieWarningReasonWarnAttributeValueExceedsMaxSize:\n\t\t*t = CookieWarningReasonWarnAttributeValueExceedsMaxSize\n\tcase CookieWarningReasonWarnDomainNonASCII:\n\t\t*t = CookieWarningReasonWarnDomainNonASCII\n\tcase CookieWarningReasonWarnThirdPartyPhaseout:\n\t\t*t = CookieWarningReasonWarnThirdPartyPhaseout\n\tcase CookieWarningReasonWarnCrossSiteRedirectDowngradeChangesInclusion:\n\t\t*t = CookieWarningReasonWarnCrossSiteRedirectDowngradeChangesInclusion\n\tcase CookieWarningReasonWarnDeprecationTrialMetadata:\n\t\t*t = CookieWarningReasonWarnDeprecationTrialMetadata\n\tcase CookieWarningReasonWarnThirdPartyCookieHeuristic:\n\t\t*t = CookieWarningReasonWarnThirdPartyCookieHeuristic\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookieWarningReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookieOperation [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-CookieOperation\ntype CookieOperation string\n\n// String returns the CookieOperation as string value.\nfunc (t CookieOperation) String() string {\n\treturn string(t)\n}\n\n// CookieOperation values.\nconst (\n\tCookieOperationSetCookie  CookieOperation = \"SetCookie\"\n\tCookieOperationReadCookie CookieOperation = \"ReadCookie\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookieOperation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookieOperation(s) {\n\tcase CookieOperationSetCookie:\n\t\t*t = CookieOperationSetCookie\n\tcase CookieOperationReadCookie:\n\t\t*t = CookieOperationReadCookie\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookieOperation value: %v\", s)\n\t}\n\treturn nil\n}\n\n// InsightType represents the category of insight that a cookie issue falls\n// under.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-InsightType\ntype InsightType string\n\n// String returns the InsightType as string value.\nfunc (t InsightType) String() string {\n\treturn string(t)\n}\n\n// InsightType values.\nconst (\n\tInsightTypeGitHubResource InsightType = \"GitHubResource\"\n\tInsightTypeGracePeriod    InsightType = \"GracePeriod\"\n\tInsightTypeHeuristics     InsightType = \"Heuristics\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InsightType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InsightType(s) {\n\tcase InsightTypeGitHubResource:\n\t\t*t = InsightTypeGitHubResource\n\tcase InsightTypeGracePeriod:\n\t\t*t = InsightTypeGracePeriod\n\tcase InsightTypeHeuristics:\n\t\t*t = InsightTypeHeuristics\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InsightType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookieIssueInsight information about the suggested solution to a cookie\n// issue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-CookieIssueInsight\ntype CookieIssueInsight struct {\n\tType          InsightType `json:\"type\"`\n\tTableEntryURL string      `json:\"tableEntryUrl,omitempty,omitzero\"` // Link to table entry in third-party cookie migration readiness list.\n}\n\n// CookieIssueDetails this information is currently necessary, as the\n// front-end has a difficult time finding a specific cookie. With this, we can\n// convey specific error information without the cookie.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-CookieIssueDetails\ntype CookieIssueDetails struct {\n\tCookie                 *AffectedCookie         `json:\"cookie,omitempty,omitzero\"` // If AffectedCookie is not set then rawCookieLine contains the raw Set-Cookie header string. This hints at a problem where the cookie line is syntactically or semantically malformed in a way that no valid cookie could be created.\n\tRawCookieLine          string                  `json:\"rawCookieLine,omitempty,omitzero\"`\n\tCookieWarningReasons   []CookieWarningReason   `json:\"cookieWarningReasons\"`\n\tCookieExclusionReasons []CookieExclusionReason `json:\"cookieExclusionReasons\"`\n\tOperation              CookieOperation         `json:\"operation\"` // Optionally identifies the site-for-cookies and the cookie url, which may be used by the front-end as additional context.\n\tSiteForCookies         string                  `json:\"siteForCookies,omitempty,omitzero\"`\n\tCookieURL              string                  `json:\"cookieUrl,omitempty,omitzero\"`\n\tRequest                *AffectedRequest        `json:\"request,omitempty,omitzero\"`\n\tInsight                *CookieIssueInsight     `json:\"insight,omitempty,omitzero\"` // The recommended solution to the issue.\n}\n\n// MixedContentResolutionStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-MixedContentResolutionStatus\ntype MixedContentResolutionStatus string\n\n// String returns the MixedContentResolutionStatus as string value.\nfunc (t MixedContentResolutionStatus) String() string {\n\treturn string(t)\n}\n\n// MixedContentResolutionStatus values.\nconst (\n\tMixedContentResolutionStatusMixedContentBlocked               MixedContentResolutionStatus = \"MixedContentBlocked\"\n\tMixedContentResolutionStatusMixedContentAutomaticallyUpgraded MixedContentResolutionStatus = \"MixedContentAutomaticallyUpgraded\"\n\tMixedContentResolutionStatusMixedContentWarning               MixedContentResolutionStatus = \"MixedContentWarning\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MixedContentResolutionStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch MixedContentResolutionStatus(s) {\n\tcase MixedContentResolutionStatusMixedContentBlocked:\n\t\t*t = MixedContentResolutionStatusMixedContentBlocked\n\tcase MixedContentResolutionStatusMixedContentAutomaticallyUpgraded:\n\t\t*t = MixedContentResolutionStatusMixedContentAutomaticallyUpgraded\n\tcase MixedContentResolutionStatusMixedContentWarning:\n\t\t*t = MixedContentResolutionStatusMixedContentWarning\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MixedContentResolutionStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// MixedContentResourceType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-MixedContentResourceType\ntype MixedContentResourceType string\n\n// String returns the MixedContentResourceType as string value.\nfunc (t MixedContentResourceType) String() string {\n\treturn string(t)\n}\n\n// MixedContentResourceType values.\nconst (\n\tMixedContentResourceTypeAttributionSrc   MixedContentResourceType = \"AttributionSrc\"\n\tMixedContentResourceTypeAudio            MixedContentResourceType = \"Audio\"\n\tMixedContentResourceTypeBeacon           MixedContentResourceType = \"Beacon\"\n\tMixedContentResourceTypeCSPReport        MixedContentResourceType = \"CSPReport\"\n\tMixedContentResourceTypeDownload         MixedContentResourceType = \"Download\"\n\tMixedContentResourceTypeEventSource      MixedContentResourceType = \"EventSource\"\n\tMixedContentResourceTypeFavicon          MixedContentResourceType = \"Favicon\"\n\tMixedContentResourceTypeFont             MixedContentResourceType = \"Font\"\n\tMixedContentResourceTypeForm             MixedContentResourceType = \"Form\"\n\tMixedContentResourceTypeFrame            MixedContentResourceType = \"Frame\"\n\tMixedContentResourceTypeImage            MixedContentResourceType = \"Image\"\n\tMixedContentResourceTypeImport           MixedContentResourceType = \"Import\"\n\tMixedContentResourceTypeJSON             MixedContentResourceType = \"JSON\"\n\tMixedContentResourceTypeManifest         MixedContentResourceType = \"Manifest\"\n\tMixedContentResourceTypePing             MixedContentResourceType = \"Ping\"\n\tMixedContentResourceTypePluginData       MixedContentResourceType = \"PluginData\"\n\tMixedContentResourceTypePluginResource   MixedContentResourceType = \"PluginResource\"\n\tMixedContentResourceTypePrefetch         MixedContentResourceType = \"Prefetch\"\n\tMixedContentResourceTypeResource         MixedContentResourceType = \"Resource\"\n\tMixedContentResourceTypeScript           MixedContentResourceType = \"Script\"\n\tMixedContentResourceTypeServiceWorker    MixedContentResourceType = \"ServiceWorker\"\n\tMixedContentResourceTypeSharedWorker     MixedContentResourceType = \"SharedWorker\"\n\tMixedContentResourceTypeSpeculationRules MixedContentResourceType = \"SpeculationRules\"\n\tMixedContentResourceTypeStylesheet       MixedContentResourceType = \"Stylesheet\"\n\tMixedContentResourceTypeTrack            MixedContentResourceType = \"Track\"\n\tMixedContentResourceTypeVideo            MixedContentResourceType = \"Video\"\n\tMixedContentResourceTypeWorker           MixedContentResourceType = \"Worker\"\n\tMixedContentResourceTypeXMLHTTPRequest   MixedContentResourceType = \"XMLHttpRequest\"\n\tMixedContentResourceTypeXSLT             MixedContentResourceType = \"XSLT\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MixedContentResourceType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch MixedContentResourceType(s) {\n\tcase MixedContentResourceTypeAttributionSrc:\n\t\t*t = MixedContentResourceTypeAttributionSrc\n\tcase MixedContentResourceTypeAudio:\n\t\t*t = MixedContentResourceTypeAudio\n\tcase MixedContentResourceTypeBeacon:\n\t\t*t = MixedContentResourceTypeBeacon\n\tcase MixedContentResourceTypeCSPReport:\n\t\t*t = MixedContentResourceTypeCSPReport\n\tcase MixedContentResourceTypeDownload:\n\t\t*t = MixedContentResourceTypeDownload\n\tcase MixedContentResourceTypeEventSource:\n\t\t*t = MixedContentResourceTypeEventSource\n\tcase MixedContentResourceTypeFavicon:\n\t\t*t = MixedContentResourceTypeFavicon\n\tcase MixedContentResourceTypeFont:\n\t\t*t = MixedContentResourceTypeFont\n\tcase MixedContentResourceTypeForm:\n\t\t*t = MixedContentResourceTypeForm\n\tcase MixedContentResourceTypeFrame:\n\t\t*t = MixedContentResourceTypeFrame\n\tcase MixedContentResourceTypeImage:\n\t\t*t = MixedContentResourceTypeImage\n\tcase MixedContentResourceTypeImport:\n\t\t*t = MixedContentResourceTypeImport\n\tcase MixedContentResourceTypeJSON:\n\t\t*t = MixedContentResourceTypeJSON\n\tcase MixedContentResourceTypeManifest:\n\t\t*t = MixedContentResourceTypeManifest\n\tcase MixedContentResourceTypePing:\n\t\t*t = MixedContentResourceTypePing\n\tcase MixedContentResourceTypePluginData:\n\t\t*t = MixedContentResourceTypePluginData\n\tcase MixedContentResourceTypePluginResource:\n\t\t*t = MixedContentResourceTypePluginResource\n\tcase MixedContentResourceTypePrefetch:\n\t\t*t = MixedContentResourceTypePrefetch\n\tcase MixedContentResourceTypeResource:\n\t\t*t = MixedContentResourceTypeResource\n\tcase MixedContentResourceTypeScript:\n\t\t*t = MixedContentResourceTypeScript\n\tcase MixedContentResourceTypeServiceWorker:\n\t\t*t = MixedContentResourceTypeServiceWorker\n\tcase MixedContentResourceTypeSharedWorker:\n\t\t*t = MixedContentResourceTypeSharedWorker\n\tcase MixedContentResourceTypeSpeculationRules:\n\t\t*t = MixedContentResourceTypeSpeculationRules\n\tcase MixedContentResourceTypeStylesheet:\n\t\t*t = MixedContentResourceTypeStylesheet\n\tcase MixedContentResourceTypeTrack:\n\t\t*t = MixedContentResourceTypeTrack\n\tcase MixedContentResourceTypeVideo:\n\t\t*t = MixedContentResourceTypeVideo\n\tcase MixedContentResourceTypeWorker:\n\t\t*t = MixedContentResourceTypeWorker\n\tcase MixedContentResourceTypeXMLHTTPRequest:\n\t\t*t = MixedContentResourceTypeXMLHTTPRequest\n\tcase MixedContentResourceTypeXSLT:\n\t\t*t = MixedContentResourceTypeXSLT\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MixedContentResourceType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// MixedContentIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-MixedContentIssueDetails\ntype MixedContentIssueDetails struct {\n\tResourceType     MixedContentResourceType     `json:\"resourceType,omitempty,omitzero\"` // The type of resource causing the mixed content issue (css, js, iframe, form,...). Marked as optional because it is mapped to from blink::mojom::RequestContextType, which will be replaced by network::mojom::RequestDestination\n\tResolutionStatus MixedContentResolutionStatus `json:\"resolutionStatus\"`                // The way the mixed content issue is being resolved.\n\tInsecureURL      string                       `json:\"insecureURL\"`                     // The unsafe http url causing the mixed content issue.\n\tMainResourceURL  string                       `json:\"mainResourceURL\"`                 // The url responsible for the call to an unsafe url.\n\tRequest          *AffectedRequest             `json:\"request,omitempty,omitzero\"`      // The mixed content request. Does not always exist (e.g. for unsafe form submission urls).\n\tFrame            *AffectedFrame               `json:\"frame,omitempty,omitzero\"`        // Optional because not every mixed content issue is necessarily linked to a frame.\n}\n\n// BlockedByResponseReason enum indicating the reason a response has been\n// blocked. These reasons are refinements of the net error BLOCKED_BY_RESPONSE.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-BlockedByResponseReason\ntype BlockedByResponseReason string\n\n// String returns the BlockedByResponseReason as string value.\nfunc (t BlockedByResponseReason) String() string {\n\treturn string(t)\n}\n\n// BlockedByResponseReason values.\nconst (\n\tBlockedByResponseReasonCoepFrameResourceNeedsCoepHeader                        BlockedByResponseReason = \"CoepFrameResourceNeedsCoepHeader\"\n\tBlockedByResponseReasonCoopSandboxedIFrameCannotNavigateToCoopPage             BlockedByResponseReason = \"CoopSandboxedIFrameCannotNavigateToCoopPage\"\n\tBlockedByResponseReasonCorpNotSameOrigin                                       BlockedByResponseReason = \"CorpNotSameOrigin\"\n\tBlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoep       BlockedByResponseReason = \"CorpNotSameOriginAfterDefaultedToSameOriginByCoep\"\n\tBlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByDip        BlockedByResponseReason = \"CorpNotSameOriginAfterDefaultedToSameOriginByDip\"\n\tBlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip BlockedByResponseReason = \"CorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip\"\n\tBlockedByResponseReasonCorpNotSameSite                                         BlockedByResponseReason = \"CorpNotSameSite\"\n\tBlockedByResponseReasonSRIMessageSignatureMismatch                             BlockedByResponseReason = \"SRIMessageSignatureMismatch\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *BlockedByResponseReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch BlockedByResponseReason(s) {\n\tcase BlockedByResponseReasonCoepFrameResourceNeedsCoepHeader:\n\t\t*t = BlockedByResponseReasonCoepFrameResourceNeedsCoepHeader\n\tcase BlockedByResponseReasonCoopSandboxedIFrameCannotNavigateToCoopPage:\n\t\t*t = BlockedByResponseReasonCoopSandboxedIFrameCannotNavigateToCoopPage\n\tcase BlockedByResponseReasonCorpNotSameOrigin:\n\t\t*t = BlockedByResponseReasonCorpNotSameOrigin\n\tcase BlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoep:\n\t\t*t = BlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoep\n\tcase BlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByDip:\n\t\t*t = BlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByDip\n\tcase BlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:\n\t\t*t = BlockedByResponseReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip\n\tcase BlockedByResponseReasonCorpNotSameSite:\n\t\t*t = BlockedByResponseReasonCorpNotSameSite\n\tcase BlockedByResponseReasonSRIMessageSignatureMismatch:\n\t\t*t = BlockedByResponseReasonSRIMessageSignatureMismatch\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown BlockedByResponseReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// BlockedByResponseIssueDetails details for a request that has been blocked\n// with the BLOCKED_BY_RESPONSE code. Currently only used for COEP/COOP, but may\n// be extended to include some CSP errors in the future.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-BlockedByResponseIssueDetails\ntype BlockedByResponseIssueDetails struct {\n\tRequest      *AffectedRequest        `json:\"request\"`\n\tParentFrame  *AffectedFrame          `json:\"parentFrame,omitempty,omitzero\"`\n\tBlockedFrame *AffectedFrame          `json:\"blockedFrame,omitempty,omitzero\"`\n\tReason       BlockedByResponseReason `json:\"reason\"`\n}\n\n// HeavyAdResolutionStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-HeavyAdResolutionStatus\ntype HeavyAdResolutionStatus string\n\n// String returns the HeavyAdResolutionStatus as string value.\nfunc (t HeavyAdResolutionStatus) String() string {\n\treturn string(t)\n}\n\n// HeavyAdResolutionStatus values.\nconst (\n\tHeavyAdResolutionStatusHeavyAdBlocked HeavyAdResolutionStatus = \"HeavyAdBlocked\"\n\tHeavyAdResolutionStatusHeavyAdWarning HeavyAdResolutionStatus = \"HeavyAdWarning\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *HeavyAdResolutionStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch HeavyAdResolutionStatus(s) {\n\tcase HeavyAdResolutionStatusHeavyAdBlocked:\n\t\t*t = HeavyAdResolutionStatusHeavyAdBlocked\n\tcase HeavyAdResolutionStatusHeavyAdWarning:\n\t\t*t = HeavyAdResolutionStatusHeavyAdWarning\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown HeavyAdResolutionStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// HeavyAdReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-HeavyAdReason\ntype HeavyAdReason string\n\n// String returns the HeavyAdReason as string value.\nfunc (t HeavyAdReason) String() string {\n\treturn string(t)\n}\n\n// HeavyAdReason values.\nconst (\n\tHeavyAdReasonNetworkTotalLimit HeavyAdReason = \"NetworkTotalLimit\"\n\tHeavyAdReasonCPUTotalLimit     HeavyAdReason = \"CpuTotalLimit\"\n\tHeavyAdReasonCPUPeakLimit      HeavyAdReason = \"CpuPeakLimit\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *HeavyAdReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch HeavyAdReason(s) {\n\tcase HeavyAdReasonNetworkTotalLimit:\n\t\t*t = HeavyAdReasonNetworkTotalLimit\n\tcase HeavyAdReasonCPUTotalLimit:\n\t\t*t = HeavyAdReasonCPUTotalLimit\n\tcase HeavyAdReasonCPUPeakLimit:\n\t\t*t = HeavyAdReasonCPUPeakLimit\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown HeavyAdReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// HeavyAdIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-HeavyAdIssueDetails\ntype HeavyAdIssueDetails struct {\n\tResolution HeavyAdResolutionStatus `json:\"resolution\"` // The resolution status, either blocking the content or warning.\n\tReason     HeavyAdReason           `json:\"reason\"`     // The reason the ad was blocked, total network or cpu or peak cpu.\n\tFrame      *AffectedFrame          `json:\"frame\"`      // The frame that was blocked.\n}\n\n// ContentSecurityPolicyViolationType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-ContentSecurityPolicyViolationType\ntype ContentSecurityPolicyViolationType string\n\n// String returns the ContentSecurityPolicyViolationType as string value.\nfunc (t ContentSecurityPolicyViolationType) String() string {\n\treturn string(t)\n}\n\n// ContentSecurityPolicyViolationType values.\nconst (\n\tContentSecurityPolicyViolationTypeKInlineViolation             ContentSecurityPolicyViolationType = \"kInlineViolation\"\n\tContentSecurityPolicyViolationTypeKEvalViolation               ContentSecurityPolicyViolationType = \"kEvalViolation\"\n\tContentSecurityPolicyViolationTypeKURLViolation                ContentSecurityPolicyViolationType = \"kURLViolation\"\n\tContentSecurityPolicyViolationTypeKSRIViolation                ContentSecurityPolicyViolationType = \"kSRIViolation\"\n\tContentSecurityPolicyViolationTypeKTrustedTypesSinkViolation   ContentSecurityPolicyViolationType = \"kTrustedTypesSinkViolation\"\n\tContentSecurityPolicyViolationTypeKTrustedTypesPolicyViolation ContentSecurityPolicyViolationType = \"kTrustedTypesPolicyViolation\"\n\tContentSecurityPolicyViolationTypeKWasmEvalViolation           ContentSecurityPolicyViolationType = \"kWasmEvalViolation\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ContentSecurityPolicyViolationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ContentSecurityPolicyViolationType(s) {\n\tcase ContentSecurityPolicyViolationTypeKInlineViolation:\n\t\t*t = ContentSecurityPolicyViolationTypeKInlineViolation\n\tcase ContentSecurityPolicyViolationTypeKEvalViolation:\n\t\t*t = ContentSecurityPolicyViolationTypeKEvalViolation\n\tcase ContentSecurityPolicyViolationTypeKURLViolation:\n\t\t*t = ContentSecurityPolicyViolationTypeKURLViolation\n\tcase ContentSecurityPolicyViolationTypeKSRIViolation:\n\t\t*t = ContentSecurityPolicyViolationTypeKSRIViolation\n\tcase ContentSecurityPolicyViolationTypeKTrustedTypesSinkViolation:\n\t\t*t = ContentSecurityPolicyViolationTypeKTrustedTypesSinkViolation\n\tcase ContentSecurityPolicyViolationTypeKTrustedTypesPolicyViolation:\n\t\t*t = ContentSecurityPolicyViolationTypeKTrustedTypesPolicyViolation\n\tcase ContentSecurityPolicyViolationTypeKWasmEvalViolation:\n\t\t*t = ContentSecurityPolicyViolationTypeKWasmEvalViolation\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ContentSecurityPolicyViolationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SourceCodeLocation [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-SourceCodeLocation\ntype SourceCodeLocation struct {\n\tScriptID     runtime.ScriptID `json:\"scriptId,omitempty,omitzero\"`\n\tURL          string           `json:\"url\"`\n\tLineNumber   int64            `json:\"lineNumber\"`\n\tColumnNumber int64            `json:\"columnNumber\"`\n}\n\n// ContentSecurityPolicyIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-ContentSecurityPolicyIssueDetails\ntype ContentSecurityPolicyIssueDetails struct {\n\tBlockedURL                         string                             `json:\"blockedURL,omitempty,omitzero\"` // The url not included in allowed sources.\n\tViolatedDirective                  string                             `json:\"violatedDirective\"`             // Specific directive that is violated, causing the CSP issue.\n\tIsReportOnly                       bool                               `json:\"isReportOnly\"`\n\tContentSecurityPolicyViolationType ContentSecurityPolicyViolationType `json:\"contentSecurityPolicyViolationType\"`\n\tFrameAncestor                      *AffectedFrame                     `json:\"frameAncestor,omitempty,omitzero\"`\n\tSourceCodeLocation                 *SourceCodeLocation                `json:\"sourceCodeLocation,omitempty,omitzero\"`\n\tViolatingNodeID                    cdp.BackendNodeID                  `json:\"violatingNodeId,omitempty,omitzero\"`\n}\n\n// SharedArrayBufferIssueType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-SharedArrayBufferIssueType\ntype SharedArrayBufferIssueType string\n\n// String returns the SharedArrayBufferIssueType as string value.\nfunc (t SharedArrayBufferIssueType) String() string {\n\treturn string(t)\n}\n\n// SharedArrayBufferIssueType values.\nconst (\n\tSharedArrayBufferIssueTypeTransferIssue SharedArrayBufferIssueType = \"TransferIssue\"\n\tSharedArrayBufferIssueTypeCreationIssue SharedArrayBufferIssueType = \"CreationIssue\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SharedArrayBufferIssueType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SharedArrayBufferIssueType(s) {\n\tcase SharedArrayBufferIssueTypeTransferIssue:\n\t\t*t = SharedArrayBufferIssueTypeTransferIssue\n\tcase SharedArrayBufferIssueTypeCreationIssue:\n\t\t*t = SharedArrayBufferIssueTypeCreationIssue\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SharedArrayBufferIssueType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SharedArrayBufferIssueDetails details for a issue arising from an SAB\n// being instantiated in, or transferred to a context that is not cross-origin\n// isolated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-SharedArrayBufferIssueDetails\ntype SharedArrayBufferIssueDetails struct {\n\tSourceCodeLocation *SourceCodeLocation        `json:\"sourceCodeLocation\"`\n\tIsWarning          bool                       `json:\"isWarning\"`\n\tType               SharedArrayBufferIssueType `json:\"type\"`\n}\n\n// LowTextContrastIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-LowTextContrastIssueDetails\ntype LowTextContrastIssueDetails struct {\n\tViolatingNodeID       cdp.BackendNodeID `json:\"violatingNodeId\"`\n\tViolatingNodeSelector string            `json:\"violatingNodeSelector\"`\n\tContrastRatio         float64           `json:\"contrastRatio\"`\n\tThresholdAA           float64           `json:\"thresholdAA\"`\n\tThresholdAAA          float64           `json:\"thresholdAAA\"`\n\tFontSize              string            `json:\"fontSize\"`\n\tFontWeight            string            `json:\"fontWeight\"`\n}\n\n// CorsIssueDetails details for a CORS related issue, e.g. a warning or error\n// related to CORS RFC1918 enforcement.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-CorsIssueDetails\ntype CorsIssueDetails struct {\n\tCorsErrorStatus        *network.CorsErrorStatus     `json:\"corsErrorStatus\"`\n\tIsWarning              bool                         `json:\"isWarning\"`\n\tRequest                *AffectedRequest             `json:\"request\"`\n\tLocation               *SourceCodeLocation          `json:\"location,omitempty,omitzero\"`\n\tInitiatorOrigin        string                       `json:\"initiatorOrigin,omitempty,omitzero\"`\n\tResourceIPAddressSpace network.IPAddressSpace       `json:\"resourceIPAddressSpace,omitempty,omitzero\"`\n\tClientSecurityState    *network.ClientSecurityState `json:\"clientSecurityState,omitempty,omitzero\"`\n}\n\n// AttributionReportingIssueType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-AttributionReportingIssueType\ntype AttributionReportingIssueType string\n\n// String returns the AttributionReportingIssueType as string value.\nfunc (t AttributionReportingIssueType) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingIssueType values.\nconst (\n\tAttributionReportingIssueTypePermissionPolicyDisabled                             AttributionReportingIssueType = \"PermissionPolicyDisabled\"\n\tAttributionReportingIssueTypeUntrustworthyReportingOrigin                         AttributionReportingIssueType = \"UntrustworthyReportingOrigin\"\n\tAttributionReportingIssueTypeInsecureContext                                      AttributionReportingIssueType = \"InsecureContext\"\n\tAttributionReportingIssueTypeInvalidHeader                                        AttributionReportingIssueType = \"InvalidHeader\"\n\tAttributionReportingIssueTypeInvalidRegisterTriggerHeader                         AttributionReportingIssueType = \"InvalidRegisterTriggerHeader\"\n\tAttributionReportingIssueTypeSourceAndTriggerHeaders                              AttributionReportingIssueType = \"SourceAndTriggerHeaders\"\n\tAttributionReportingIssueTypeSourceIgnored                                        AttributionReportingIssueType = \"SourceIgnored\"\n\tAttributionReportingIssueTypeTriggerIgnored                                       AttributionReportingIssueType = \"TriggerIgnored\"\n\tAttributionReportingIssueTypeOsSourceIgnored                                      AttributionReportingIssueType = \"OsSourceIgnored\"\n\tAttributionReportingIssueTypeOsTriggerIgnored                                     AttributionReportingIssueType = \"OsTriggerIgnored\"\n\tAttributionReportingIssueTypeInvalidRegisterOsSourceHeader                        AttributionReportingIssueType = \"InvalidRegisterOsSourceHeader\"\n\tAttributionReportingIssueTypeInvalidRegisterOsTriggerHeader                       AttributionReportingIssueType = \"InvalidRegisterOsTriggerHeader\"\n\tAttributionReportingIssueTypeWebAndOsHeaders                                      AttributionReportingIssueType = \"WebAndOsHeaders\"\n\tAttributionReportingIssueTypeNoWebOrOsSupport                                     AttributionReportingIssueType = \"NoWebOrOsSupport\"\n\tAttributionReportingIssueTypeNavigationRegistrationWithoutTransientUserActivation AttributionReportingIssueType = \"NavigationRegistrationWithoutTransientUserActivation\"\n\tAttributionReportingIssueTypeInvalidInfoHeader                                    AttributionReportingIssueType = \"InvalidInfoHeader\"\n\tAttributionReportingIssueTypeNoRegisterSourceHeader                               AttributionReportingIssueType = \"NoRegisterSourceHeader\"\n\tAttributionReportingIssueTypeNoRegisterTriggerHeader                              AttributionReportingIssueType = \"NoRegisterTriggerHeader\"\n\tAttributionReportingIssueTypeNoRegisterOsSourceHeader                             AttributionReportingIssueType = \"NoRegisterOsSourceHeader\"\n\tAttributionReportingIssueTypeNoRegisterOsTriggerHeader                            AttributionReportingIssueType = \"NoRegisterOsTriggerHeader\"\n\tAttributionReportingIssueTypeNavigationRegistrationUniqueScopeAlreadySet          AttributionReportingIssueType = \"NavigationRegistrationUniqueScopeAlreadySet\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingIssueType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingIssueType(s) {\n\tcase AttributionReportingIssueTypePermissionPolicyDisabled:\n\t\t*t = AttributionReportingIssueTypePermissionPolicyDisabled\n\tcase AttributionReportingIssueTypeUntrustworthyReportingOrigin:\n\t\t*t = AttributionReportingIssueTypeUntrustworthyReportingOrigin\n\tcase AttributionReportingIssueTypeInsecureContext:\n\t\t*t = AttributionReportingIssueTypeInsecureContext\n\tcase AttributionReportingIssueTypeInvalidHeader:\n\t\t*t = AttributionReportingIssueTypeInvalidHeader\n\tcase AttributionReportingIssueTypeInvalidRegisterTriggerHeader:\n\t\t*t = AttributionReportingIssueTypeInvalidRegisterTriggerHeader\n\tcase AttributionReportingIssueTypeSourceAndTriggerHeaders:\n\t\t*t = AttributionReportingIssueTypeSourceAndTriggerHeaders\n\tcase AttributionReportingIssueTypeSourceIgnored:\n\t\t*t = AttributionReportingIssueTypeSourceIgnored\n\tcase AttributionReportingIssueTypeTriggerIgnored:\n\t\t*t = AttributionReportingIssueTypeTriggerIgnored\n\tcase AttributionReportingIssueTypeOsSourceIgnored:\n\t\t*t = AttributionReportingIssueTypeOsSourceIgnored\n\tcase AttributionReportingIssueTypeOsTriggerIgnored:\n\t\t*t = AttributionReportingIssueTypeOsTriggerIgnored\n\tcase AttributionReportingIssueTypeInvalidRegisterOsSourceHeader:\n\t\t*t = AttributionReportingIssueTypeInvalidRegisterOsSourceHeader\n\tcase AttributionReportingIssueTypeInvalidRegisterOsTriggerHeader:\n\t\t*t = AttributionReportingIssueTypeInvalidRegisterOsTriggerHeader\n\tcase AttributionReportingIssueTypeWebAndOsHeaders:\n\t\t*t = AttributionReportingIssueTypeWebAndOsHeaders\n\tcase AttributionReportingIssueTypeNoWebOrOsSupport:\n\t\t*t = AttributionReportingIssueTypeNoWebOrOsSupport\n\tcase AttributionReportingIssueTypeNavigationRegistrationWithoutTransientUserActivation:\n\t\t*t = AttributionReportingIssueTypeNavigationRegistrationWithoutTransientUserActivation\n\tcase AttributionReportingIssueTypeInvalidInfoHeader:\n\t\t*t = AttributionReportingIssueTypeInvalidInfoHeader\n\tcase AttributionReportingIssueTypeNoRegisterSourceHeader:\n\t\t*t = AttributionReportingIssueTypeNoRegisterSourceHeader\n\tcase AttributionReportingIssueTypeNoRegisterTriggerHeader:\n\t\t*t = AttributionReportingIssueTypeNoRegisterTriggerHeader\n\tcase AttributionReportingIssueTypeNoRegisterOsSourceHeader:\n\t\t*t = AttributionReportingIssueTypeNoRegisterOsSourceHeader\n\tcase AttributionReportingIssueTypeNoRegisterOsTriggerHeader:\n\t\t*t = AttributionReportingIssueTypeNoRegisterOsTriggerHeader\n\tcase AttributionReportingIssueTypeNavigationRegistrationUniqueScopeAlreadySet:\n\t\t*t = AttributionReportingIssueTypeNavigationRegistrationUniqueScopeAlreadySet\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingIssueType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SharedDictionaryError [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-SharedDictionaryError\ntype SharedDictionaryError string\n\n// String returns the SharedDictionaryError as string value.\nfunc (t SharedDictionaryError) String() string {\n\treturn string(t)\n}\n\n// SharedDictionaryError values.\nconst (\n\tSharedDictionaryErrorUseErrorCrossOriginNoCorsRequest          SharedDictionaryError = \"UseErrorCrossOriginNoCorsRequest\"\n\tSharedDictionaryErrorUseErrorDictionaryLoadFailure             SharedDictionaryError = \"UseErrorDictionaryLoadFailure\"\n\tSharedDictionaryErrorUseErrorMatchingDictionaryNotUsed         SharedDictionaryError = \"UseErrorMatchingDictionaryNotUsed\"\n\tSharedDictionaryErrorUseErrorUnexpectedContentDictionaryHeader SharedDictionaryError = \"UseErrorUnexpectedContentDictionaryHeader\"\n\tSharedDictionaryErrorWriteErrorCossOriginNoCorsRequest         SharedDictionaryError = \"WriteErrorCossOriginNoCorsRequest\"\n\tSharedDictionaryErrorWriteErrorDisallowedBySettings            SharedDictionaryError = \"WriteErrorDisallowedBySettings\"\n\tSharedDictionaryErrorWriteErrorExpiredResponse                 SharedDictionaryError = \"WriteErrorExpiredResponse\"\n\tSharedDictionaryErrorWriteErrorFeatureDisabled                 SharedDictionaryError = \"WriteErrorFeatureDisabled\"\n\tSharedDictionaryErrorWriteErrorInsufficientResources           SharedDictionaryError = \"WriteErrorInsufficientResources\"\n\tSharedDictionaryErrorWriteErrorInvalidMatchField               SharedDictionaryError = \"WriteErrorInvalidMatchField\"\n\tSharedDictionaryErrorWriteErrorInvalidStructuredHeader         SharedDictionaryError = \"WriteErrorInvalidStructuredHeader\"\n\tSharedDictionaryErrorWriteErrorNavigationRequest               SharedDictionaryError = \"WriteErrorNavigationRequest\"\n\tSharedDictionaryErrorWriteErrorNoMatchField                    SharedDictionaryError = \"WriteErrorNoMatchField\"\n\tSharedDictionaryErrorWriteErrorNonListMatchDestField           SharedDictionaryError = \"WriteErrorNonListMatchDestField\"\n\tSharedDictionaryErrorWriteErrorNonSecureContext                SharedDictionaryError = \"WriteErrorNonSecureContext\"\n\tSharedDictionaryErrorWriteErrorNonStringIDField                SharedDictionaryError = \"WriteErrorNonStringIdField\"\n\tSharedDictionaryErrorWriteErrorNonStringInMatchDestList        SharedDictionaryError = \"WriteErrorNonStringInMatchDestList\"\n\tSharedDictionaryErrorWriteErrorNonStringMatchField             SharedDictionaryError = \"WriteErrorNonStringMatchField\"\n\tSharedDictionaryErrorWriteErrorNonTokenTypeField               SharedDictionaryError = \"WriteErrorNonTokenTypeField\"\n\tSharedDictionaryErrorWriteErrorRequestAborted                  SharedDictionaryError = \"WriteErrorRequestAborted\"\n\tSharedDictionaryErrorWriteErrorShuttingDown                    SharedDictionaryError = \"WriteErrorShuttingDown\"\n\tSharedDictionaryErrorWriteErrorTooLongIDField                  SharedDictionaryError = \"WriteErrorTooLongIdField\"\n\tSharedDictionaryErrorWriteErrorUnsupportedType                 SharedDictionaryError = \"WriteErrorUnsupportedType\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SharedDictionaryError) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SharedDictionaryError(s) {\n\tcase SharedDictionaryErrorUseErrorCrossOriginNoCorsRequest:\n\t\t*t = SharedDictionaryErrorUseErrorCrossOriginNoCorsRequest\n\tcase SharedDictionaryErrorUseErrorDictionaryLoadFailure:\n\t\t*t = SharedDictionaryErrorUseErrorDictionaryLoadFailure\n\tcase SharedDictionaryErrorUseErrorMatchingDictionaryNotUsed:\n\t\t*t = SharedDictionaryErrorUseErrorMatchingDictionaryNotUsed\n\tcase SharedDictionaryErrorUseErrorUnexpectedContentDictionaryHeader:\n\t\t*t = SharedDictionaryErrorUseErrorUnexpectedContentDictionaryHeader\n\tcase SharedDictionaryErrorWriteErrorCossOriginNoCorsRequest:\n\t\t*t = SharedDictionaryErrorWriteErrorCossOriginNoCorsRequest\n\tcase SharedDictionaryErrorWriteErrorDisallowedBySettings:\n\t\t*t = SharedDictionaryErrorWriteErrorDisallowedBySettings\n\tcase SharedDictionaryErrorWriteErrorExpiredResponse:\n\t\t*t = SharedDictionaryErrorWriteErrorExpiredResponse\n\tcase SharedDictionaryErrorWriteErrorFeatureDisabled:\n\t\t*t = SharedDictionaryErrorWriteErrorFeatureDisabled\n\tcase SharedDictionaryErrorWriteErrorInsufficientResources:\n\t\t*t = SharedDictionaryErrorWriteErrorInsufficientResources\n\tcase SharedDictionaryErrorWriteErrorInvalidMatchField:\n\t\t*t = SharedDictionaryErrorWriteErrorInvalidMatchField\n\tcase SharedDictionaryErrorWriteErrorInvalidStructuredHeader:\n\t\t*t = SharedDictionaryErrorWriteErrorInvalidStructuredHeader\n\tcase SharedDictionaryErrorWriteErrorNavigationRequest:\n\t\t*t = SharedDictionaryErrorWriteErrorNavigationRequest\n\tcase SharedDictionaryErrorWriteErrorNoMatchField:\n\t\t*t = SharedDictionaryErrorWriteErrorNoMatchField\n\tcase SharedDictionaryErrorWriteErrorNonListMatchDestField:\n\t\t*t = SharedDictionaryErrorWriteErrorNonListMatchDestField\n\tcase SharedDictionaryErrorWriteErrorNonSecureContext:\n\t\t*t = SharedDictionaryErrorWriteErrorNonSecureContext\n\tcase SharedDictionaryErrorWriteErrorNonStringIDField:\n\t\t*t = SharedDictionaryErrorWriteErrorNonStringIDField\n\tcase SharedDictionaryErrorWriteErrorNonStringInMatchDestList:\n\t\t*t = SharedDictionaryErrorWriteErrorNonStringInMatchDestList\n\tcase SharedDictionaryErrorWriteErrorNonStringMatchField:\n\t\t*t = SharedDictionaryErrorWriteErrorNonStringMatchField\n\tcase SharedDictionaryErrorWriteErrorNonTokenTypeField:\n\t\t*t = SharedDictionaryErrorWriteErrorNonTokenTypeField\n\tcase SharedDictionaryErrorWriteErrorRequestAborted:\n\t\t*t = SharedDictionaryErrorWriteErrorRequestAborted\n\tcase SharedDictionaryErrorWriteErrorShuttingDown:\n\t\t*t = SharedDictionaryErrorWriteErrorShuttingDown\n\tcase SharedDictionaryErrorWriteErrorTooLongIDField:\n\t\t*t = SharedDictionaryErrorWriteErrorTooLongIDField\n\tcase SharedDictionaryErrorWriteErrorUnsupportedType:\n\t\t*t = SharedDictionaryErrorWriteErrorUnsupportedType\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SharedDictionaryError value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SRIMessageSignatureError [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-SRIMessageSignatureError\ntype SRIMessageSignatureError string\n\n// String returns the SRIMessageSignatureError as string value.\nfunc (t SRIMessageSignatureError) String() string {\n\treturn string(t)\n}\n\n// SRIMessageSignatureError values.\nconst (\n\tSRIMessageSignatureErrorMissingSignatureHeader                               SRIMessageSignatureError = \"MissingSignatureHeader\"\n\tSRIMessageSignatureErrorMissingSignatureInputHeader                          SRIMessageSignatureError = \"MissingSignatureInputHeader\"\n\tSRIMessageSignatureErrorInvalidSignatureHeader                               SRIMessageSignatureError = \"InvalidSignatureHeader\"\n\tSRIMessageSignatureErrorInvalidSignatureInputHeader                          SRIMessageSignatureError = \"InvalidSignatureInputHeader\"\n\tSRIMessageSignatureErrorSignatureHeaderValueIsNotByteSequence                SRIMessageSignatureError = \"SignatureHeaderValueIsNotByteSequence\"\n\tSRIMessageSignatureErrorSignatureHeaderValueIsParameterized                  SRIMessageSignatureError = \"SignatureHeaderValueIsParameterized\"\n\tSRIMessageSignatureErrorSignatureHeaderValueIsIncorrectLength                SRIMessageSignatureError = \"SignatureHeaderValueIsIncorrectLength\"\n\tSRIMessageSignatureErrorSignatureInputHeaderMissingLabel                     SRIMessageSignatureError = \"SignatureInputHeaderMissingLabel\"\n\tSRIMessageSignatureErrorSignatureInputHeaderValueNotInnerList                SRIMessageSignatureError = \"SignatureInputHeaderValueNotInnerList\"\n\tSRIMessageSignatureErrorSignatureInputHeaderValueMissingComponents           SRIMessageSignatureError = \"SignatureInputHeaderValueMissingComponents\"\n\tSRIMessageSignatureErrorSignatureInputHeaderInvalidComponentType             SRIMessageSignatureError = \"SignatureInputHeaderInvalidComponentType\"\n\tSRIMessageSignatureErrorSignatureInputHeaderInvalidComponentName             SRIMessageSignatureError = \"SignatureInputHeaderInvalidComponentName\"\n\tSRIMessageSignatureErrorSignatureInputHeaderInvalidHeaderComponentParameter  SRIMessageSignatureError = \"SignatureInputHeaderInvalidHeaderComponentParameter\"\n\tSRIMessageSignatureErrorSignatureInputHeaderInvalidDerivedComponentParameter SRIMessageSignatureError = \"SignatureInputHeaderInvalidDerivedComponentParameter\"\n\tSRIMessageSignatureErrorSignatureInputHeaderKeyIDLength                      SRIMessageSignatureError = \"SignatureInputHeaderKeyIdLength\"\n\tSRIMessageSignatureErrorSignatureInputHeaderInvalidParameter                 SRIMessageSignatureError = \"SignatureInputHeaderInvalidParameter\"\n\tSRIMessageSignatureErrorSignatureInputHeaderMissingRequiredParameters        SRIMessageSignatureError = \"SignatureInputHeaderMissingRequiredParameters\"\n\tSRIMessageSignatureErrorValidationFailedSignatureExpired                     SRIMessageSignatureError = \"ValidationFailedSignatureExpired\"\n\tSRIMessageSignatureErrorValidationFailedInvalidLength                        SRIMessageSignatureError = \"ValidationFailedInvalidLength\"\n\tSRIMessageSignatureErrorValidationFailedSignatureMismatch                    SRIMessageSignatureError = \"ValidationFailedSignatureMismatch\"\n\tSRIMessageSignatureErrorValidationFailedIntegrityMismatch                    SRIMessageSignatureError = \"ValidationFailedIntegrityMismatch\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SRIMessageSignatureError) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SRIMessageSignatureError(s) {\n\tcase SRIMessageSignatureErrorMissingSignatureHeader:\n\t\t*t = SRIMessageSignatureErrorMissingSignatureHeader\n\tcase SRIMessageSignatureErrorMissingSignatureInputHeader:\n\t\t*t = SRIMessageSignatureErrorMissingSignatureInputHeader\n\tcase SRIMessageSignatureErrorInvalidSignatureHeader:\n\t\t*t = SRIMessageSignatureErrorInvalidSignatureHeader\n\tcase SRIMessageSignatureErrorInvalidSignatureInputHeader:\n\t\t*t = SRIMessageSignatureErrorInvalidSignatureInputHeader\n\tcase SRIMessageSignatureErrorSignatureHeaderValueIsNotByteSequence:\n\t\t*t = SRIMessageSignatureErrorSignatureHeaderValueIsNotByteSequence\n\tcase SRIMessageSignatureErrorSignatureHeaderValueIsParameterized:\n\t\t*t = SRIMessageSignatureErrorSignatureHeaderValueIsParameterized\n\tcase SRIMessageSignatureErrorSignatureHeaderValueIsIncorrectLength:\n\t\t*t = SRIMessageSignatureErrorSignatureHeaderValueIsIncorrectLength\n\tcase SRIMessageSignatureErrorSignatureInputHeaderMissingLabel:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderMissingLabel\n\tcase SRIMessageSignatureErrorSignatureInputHeaderValueNotInnerList:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderValueNotInnerList\n\tcase SRIMessageSignatureErrorSignatureInputHeaderValueMissingComponents:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderValueMissingComponents\n\tcase SRIMessageSignatureErrorSignatureInputHeaderInvalidComponentType:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderInvalidComponentType\n\tcase SRIMessageSignatureErrorSignatureInputHeaderInvalidComponentName:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderInvalidComponentName\n\tcase SRIMessageSignatureErrorSignatureInputHeaderInvalidHeaderComponentParameter:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderInvalidHeaderComponentParameter\n\tcase SRIMessageSignatureErrorSignatureInputHeaderInvalidDerivedComponentParameter:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderInvalidDerivedComponentParameter\n\tcase SRIMessageSignatureErrorSignatureInputHeaderKeyIDLength:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderKeyIDLength\n\tcase SRIMessageSignatureErrorSignatureInputHeaderInvalidParameter:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderInvalidParameter\n\tcase SRIMessageSignatureErrorSignatureInputHeaderMissingRequiredParameters:\n\t\t*t = SRIMessageSignatureErrorSignatureInputHeaderMissingRequiredParameters\n\tcase SRIMessageSignatureErrorValidationFailedSignatureExpired:\n\t\t*t = SRIMessageSignatureErrorValidationFailedSignatureExpired\n\tcase SRIMessageSignatureErrorValidationFailedInvalidLength:\n\t\t*t = SRIMessageSignatureErrorValidationFailedInvalidLength\n\tcase SRIMessageSignatureErrorValidationFailedSignatureMismatch:\n\t\t*t = SRIMessageSignatureErrorValidationFailedSignatureMismatch\n\tcase SRIMessageSignatureErrorValidationFailedIntegrityMismatch:\n\t\t*t = SRIMessageSignatureErrorValidationFailedIntegrityMismatch\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SRIMessageSignatureError value: %v\", s)\n\t}\n\treturn nil\n}\n\n// UnencodedDigestError [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-UnencodedDigestError\ntype UnencodedDigestError string\n\n// String returns the UnencodedDigestError as string value.\nfunc (t UnencodedDigestError) String() string {\n\treturn string(t)\n}\n\n// UnencodedDigestError values.\nconst (\n\tUnencodedDigestErrorMalformedDictionary   UnencodedDigestError = \"MalformedDictionary\"\n\tUnencodedDigestErrorUnknownAlgorithm      UnencodedDigestError = \"UnknownAlgorithm\"\n\tUnencodedDigestErrorIncorrectDigestType   UnencodedDigestError = \"IncorrectDigestType\"\n\tUnencodedDigestErrorIncorrectDigestLength UnencodedDigestError = \"IncorrectDigestLength\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *UnencodedDigestError) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch UnencodedDigestError(s) {\n\tcase UnencodedDigestErrorMalformedDictionary:\n\t\t*t = UnencodedDigestErrorMalformedDictionary\n\tcase UnencodedDigestErrorUnknownAlgorithm:\n\t\t*t = UnencodedDigestErrorUnknownAlgorithm\n\tcase UnencodedDigestErrorIncorrectDigestType:\n\t\t*t = UnencodedDigestErrorIncorrectDigestType\n\tcase UnencodedDigestErrorIncorrectDigestLength:\n\t\t*t = UnencodedDigestErrorIncorrectDigestLength\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown UnencodedDigestError value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AttributionReportingIssueDetails details for issues around \"Attribution\n// Reporting API\" usage. Explainer:\n// https://github.com/WICG/attribution-reporting-api.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-AttributionReportingIssueDetails\ntype AttributionReportingIssueDetails struct {\n\tViolationType    AttributionReportingIssueType `json:\"violationType\"`\n\tRequest          *AffectedRequest              `json:\"request,omitempty,omitzero\"`\n\tViolatingNodeID  cdp.BackendNodeID             `json:\"violatingNodeId,omitempty,omitzero\"`\n\tInvalidParameter string                        `json:\"invalidParameter,omitempty,omitzero\"`\n}\n\n// QuirksModeIssueDetails details for issues about documents in Quirks Mode\n// or Limited Quirks Mode that affects page layouting.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-QuirksModeIssueDetails\ntype QuirksModeIssueDetails struct {\n\tIsLimitedQuirksMode bool              `json:\"isLimitedQuirksMode\"` // If false, it means the document's mode is \"quirks\" instead of \"limited-quirks\".\n\tDocumentNodeID      cdp.BackendNodeID `json:\"documentNodeId\"`\n\tURL                 string            `json:\"url\"`\n\tFrameID             cdp.FrameID       `json:\"frameId\"`\n\tLoaderID            cdp.LoaderID      `json:\"loaderId\"`\n}\n\n// SharedDictionaryIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-SharedDictionaryIssueDetails\ntype SharedDictionaryIssueDetails struct {\n\tSharedDictionaryError SharedDictionaryError `json:\"sharedDictionaryError\"`\n\tRequest               *AffectedRequest      `json:\"request\"`\n}\n\n// SRIMessageSignatureIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-SRIMessageSignatureIssueDetails\ntype SRIMessageSignatureIssueDetails struct {\n\tError               SRIMessageSignatureError `json:\"error\"`\n\tSignatureBase       string                   `json:\"signatureBase\"`\n\tIntegrityAssertions []string                 `json:\"integrityAssertions\"`\n\tRequest             *AffectedRequest         `json:\"request\"`\n}\n\n// UnencodedDigestIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-UnencodedDigestIssueDetails\ntype UnencodedDigestIssueDetails struct {\n\tError   UnencodedDigestError `json:\"error\"`\n\tRequest *AffectedRequest     `json:\"request\"`\n}\n\n// GenericIssueErrorType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-GenericIssueErrorType\ntype GenericIssueErrorType string\n\n// String returns the GenericIssueErrorType as string value.\nfunc (t GenericIssueErrorType) String() string {\n\treturn string(t)\n}\n\n// GenericIssueErrorType values.\nconst (\n\tGenericIssueErrorTypeFormLabelForNameError                                      GenericIssueErrorType = \"FormLabelForNameError\"\n\tGenericIssueErrorTypeFormDuplicateIDForInputError                               GenericIssueErrorType = \"FormDuplicateIdForInputError\"\n\tGenericIssueErrorTypeFormInputWithNoLabelError                                  GenericIssueErrorType = \"FormInputWithNoLabelError\"\n\tGenericIssueErrorTypeFormAutocompleteAttributeEmptyError                        GenericIssueErrorType = \"FormAutocompleteAttributeEmptyError\"\n\tGenericIssueErrorTypeFormEmptyIDAndNameAttributesForInputError                  GenericIssueErrorType = \"FormEmptyIdAndNameAttributesForInputError\"\n\tGenericIssueErrorTypeFormAriaLabelledByToNonExistingID                          GenericIssueErrorType = \"FormAriaLabelledByToNonExistingId\"\n\tGenericIssueErrorTypeFormInputAssignedAutocompleteValueToIDOrNameAttributeError GenericIssueErrorType = \"FormInputAssignedAutocompleteValueToIdOrNameAttributeError\"\n\tGenericIssueErrorTypeFormLabelHasNeitherForNorNestedInput                       GenericIssueErrorType = \"FormLabelHasNeitherForNorNestedInput\"\n\tGenericIssueErrorTypeFormLabelForMatchesNonExistingIDError                      GenericIssueErrorType = \"FormLabelForMatchesNonExistingIdError\"\n\tGenericIssueErrorTypeFormInputHasWrongButWellIntendedAutocompleteValueError     GenericIssueErrorType = \"FormInputHasWrongButWellIntendedAutocompleteValueError\"\n\tGenericIssueErrorTypeResponseWasBlockedByORB                                    GenericIssueErrorType = \"ResponseWasBlockedByORB\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *GenericIssueErrorType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch GenericIssueErrorType(s) {\n\tcase GenericIssueErrorTypeFormLabelForNameError:\n\t\t*t = GenericIssueErrorTypeFormLabelForNameError\n\tcase GenericIssueErrorTypeFormDuplicateIDForInputError:\n\t\t*t = GenericIssueErrorTypeFormDuplicateIDForInputError\n\tcase GenericIssueErrorTypeFormInputWithNoLabelError:\n\t\t*t = GenericIssueErrorTypeFormInputWithNoLabelError\n\tcase GenericIssueErrorTypeFormAutocompleteAttributeEmptyError:\n\t\t*t = GenericIssueErrorTypeFormAutocompleteAttributeEmptyError\n\tcase GenericIssueErrorTypeFormEmptyIDAndNameAttributesForInputError:\n\t\t*t = GenericIssueErrorTypeFormEmptyIDAndNameAttributesForInputError\n\tcase GenericIssueErrorTypeFormAriaLabelledByToNonExistingID:\n\t\t*t = GenericIssueErrorTypeFormAriaLabelledByToNonExistingID\n\tcase GenericIssueErrorTypeFormInputAssignedAutocompleteValueToIDOrNameAttributeError:\n\t\t*t = GenericIssueErrorTypeFormInputAssignedAutocompleteValueToIDOrNameAttributeError\n\tcase GenericIssueErrorTypeFormLabelHasNeitherForNorNestedInput:\n\t\t*t = GenericIssueErrorTypeFormLabelHasNeitherForNorNestedInput\n\tcase GenericIssueErrorTypeFormLabelForMatchesNonExistingIDError:\n\t\t*t = GenericIssueErrorTypeFormLabelForMatchesNonExistingIDError\n\tcase GenericIssueErrorTypeFormInputHasWrongButWellIntendedAutocompleteValueError:\n\t\t*t = GenericIssueErrorTypeFormInputHasWrongButWellIntendedAutocompleteValueError\n\tcase GenericIssueErrorTypeResponseWasBlockedByORB:\n\t\t*t = GenericIssueErrorTypeResponseWasBlockedByORB\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown GenericIssueErrorType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// GenericIssueDetails depending on the concrete errorType, different\n// properties are set.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-GenericIssueDetails\ntype GenericIssueDetails struct {\n\tErrorType              GenericIssueErrorType `json:\"errorType\"` // Issues with the same errorType are aggregated in the frontend.\n\tFrameID                cdp.FrameID           `json:\"frameId,omitempty,omitzero\"`\n\tViolatingNodeID        cdp.BackendNodeID     `json:\"violatingNodeId,omitempty,omitzero\"`\n\tViolatingNodeAttribute string                `json:\"violatingNodeAttribute,omitempty,omitzero\"`\n\tRequest                *AffectedRequest      `json:\"request,omitempty,omitzero\"`\n}\n\n// DeprecationIssueDetails this issue tracks information needed to print a\n// deprecation message.\n// https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/third_party/blink/renderer/core/frame/deprecation/README.md.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-DeprecationIssueDetails\ntype DeprecationIssueDetails struct {\n\tAffectedFrame      *AffectedFrame      `json:\"affectedFrame,omitempty,omitzero\"`\n\tSourceCodeLocation *SourceCodeLocation `json:\"sourceCodeLocation\"`\n\tType               string              `json:\"type\"` // One of the deprecation names from third_party/blink/renderer/core/frame/deprecation/deprecation.json5\n}\n\n// BounceTrackingIssueDetails this issue warns about sites in the redirect\n// chain of a finished navigation that may be flagged as trackers and have their\n// state cleared if they don't receive a user interaction. Note that in this\n// context 'site' means eTLD+1. For example, if the URL\n// https://example.test:80/bounce was in the redirect chain, the site reported\n// would be example.test.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-BounceTrackingIssueDetails\ntype BounceTrackingIssueDetails struct {\n\tTrackingSites []string `json:\"trackingSites\"`\n}\n\n// CookieDeprecationMetadataIssueDetails this issue warns about third-party\n// sites that are accessing cookies on the current page, and have been permitted\n// due to having a global metadata grant. Note that in this context 'site' means\n// eTLD+1. For example, if the URL https://example.test:80/web_page was\n// accessing cookies, the site reported would be example.test.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-CookieDeprecationMetadataIssueDetails\ntype CookieDeprecationMetadataIssueDetails struct {\n\tAllowedSites     []string        `json:\"allowedSites\"`\n\tOptOutPercentage float64         `json:\"optOutPercentage\"`\n\tIsOptOutTopLevel bool            `json:\"isOptOutTopLevel\"`\n\tOperation        CookieOperation `json:\"operation\"`\n}\n\n// ClientHintIssueReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-ClientHintIssueReason\ntype ClientHintIssueReason string\n\n// String returns the ClientHintIssueReason as string value.\nfunc (t ClientHintIssueReason) String() string {\n\treturn string(t)\n}\n\n// ClientHintIssueReason values.\nconst (\n\tClientHintIssueReasonMetaTagAllowListInvalidOrigin ClientHintIssueReason = \"MetaTagAllowListInvalidOrigin\"\n\tClientHintIssueReasonMetaTagModifiedHTML           ClientHintIssueReason = \"MetaTagModifiedHTML\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ClientHintIssueReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ClientHintIssueReason(s) {\n\tcase ClientHintIssueReasonMetaTagAllowListInvalidOrigin:\n\t\t*t = ClientHintIssueReasonMetaTagAllowListInvalidOrigin\n\tcase ClientHintIssueReasonMetaTagModifiedHTML:\n\t\t*t = ClientHintIssueReasonMetaTagModifiedHTML\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ClientHintIssueReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// FederatedAuthRequestIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-FederatedAuthRequestIssueDetails\ntype FederatedAuthRequestIssueDetails struct {\n\tFederatedAuthRequestIssueReason FederatedAuthRequestIssueReason `json:\"federatedAuthRequestIssueReason\"`\n}\n\n// FederatedAuthRequestIssueReason represents the failure reason when a\n// federated authentication reason fails. Should be updated alongside\n// RequestIdTokenStatus in\n// third_party/blink/public/mojom/devtools/inspector_issue.mojom to include all\n// cases except for success.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-FederatedAuthRequestIssueReason\ntype FederatedAuthRequestIssueReason string\n\n// String returns the FederatedAuthRequestIssueReason as string value.\nfunc (t FederatedAuthRequestIssueReason) String() string {\n\treturn string(t)\n}\n\n// FederatedAuthRequestIssueReason values.\nconst (\n\tFederatedAuthRequestIssueReasonShouldEmbargo                    FederatedAuthRequestIssueReason = \"ShouldEmbargo\"\n\tFederatedAuthRequestIssueReasonTooManyRequests                  FederatedAuthRequestIssueReason = \"TooManyRequests\"\n\tFederatedAuthRequestIssueReasonWellKnownHTTPNotFound            FederatedAuthRequestIssueReason = \"WellKnownHttpNotFound\"\n\tFederatedAuthRequestIssueReasonWellKnownNoResponse              FederatedAuthRequestIssueReason = \"WellKnownNoResponse\"\n\tFederatedAuthRequestIssueReasonWellKnownInvalidResponse         FederatedAuthRequestIssueReason = \"WellKnownInvalidResponse\"\n\tFederatedAuthRequestIssueReasonWellKnownListEmpty               FederatedAuthRequestIssueReason = \"WellKnownListEmpty\"\n\tFederatedAuthRequestIssueReasonWellKnownInvalidContentType      FederatedAuthRequestIssueReason = \"WellKnownInvalidContentType\"\n\tFederatedAuthRequestIssueReasonConfigNotInWellKnown             FederatedAuthRequestIssueReason = \"ConfigNotInWellKnown\"\n\tFederatedAuthRequestIssueReasonWellKnownTooBig                  FederatedAuthRequestIssueReason = \"WellKnownTooBig\"\n\tFederatedAuthRequestIssueReasonConfigHTTPNotFound               FederatedAuthRequestIssueReason = \"ConfigHttpNotFound\"\n\tFederatedAuthRequestIssueReasonConfigNoResponse                 FederatedAuthRequestIssueReason = \"ConfigNoResponse\"\n\tFederatedAuthRequestIssueReasonConfigInvalidResponse            FederatedAuthRequestIssueReason = \"ConfigInvalidResponse\"\n\tFederatedAuthRequestIssueReasonConfigInvalidContentType         FederatedAuthRequestIssueReason = \"ConfigInvalidContentType\"\n\tFederatedAuthRequestIssueReasonClientMetadataHTTPNotFound       FederatedAuthRequestIssueReason = \"ClientMetadataHttpNotFound\"\n\tFederatedAuthRequestIssueReasonClientMetadataNoResponse         FederatedAuthRequestIssueReason = \"ClientMetadataNoResponse\"\n\tFederatedAuthRequestIssueReasonClientMetadataInvalidResponse    FederatedAuthRequestIssueReason = \"ClientMetadataInvalidResponse\"\n\tFederatedAuthRequestIssueReasonClientMetadataInvalidContentType FederatedAuthRequestIssueReason = \"ClientMetadataInvalidContentType\"\n\tFederatedAuthRequestIssueReasonIdpNotPotentiallyTrustworthy     FederatedAuthRequestIssueReason = \"IdpNotPotentiallyTrustworthy\"\n\tFederatedAuthRequestIssueReasonDisabledInSettings               FederatedAuthRequestIssueReason = \"DisabledInSettings\"\n\tFederatedAuthRequestIssueReasonDisabledInFlags                  FederatedAuthRequestIssueReason = \"DisabledInFlags\"\n\tFederatedAuthRequestIssueReasonErrorFetchingSignin              FederatedAuthRequestIssueReason = \"ErrorFetchingSignin\"\n\tFederatedAuthRequestIssueReasonInvalidSigninResponse            FederatedAuthRequestIssueReason = \"InvalidSigninResponse\"\n\tFederatedAuthRequestIssueReasonAccountsHTTPNotFound             FederatedAuthRequestIssueReason = \"AccountsHttpNotFound\"\n\tFederatedAuthRequestIssueReasonAccountsNoResponse               FederatedAuthRequestIssueReason = \"AccountsNoResponse\"\n\tFederatedAuthRequestIssueReasonAccountsInvalidResponse          FederatedAuthRequestIssueReason = \"AccountsInvalidResponse\"\n\tFederatedAuthRequestIssueReasonAccountsListEmpty                FederatedAuthRequestIssueReason = \"AccountsListEmpty\"\n\tFederatedAuthRequestIssueReasonAccountsInvalidContentType       FederatedAuthRequestIssueReason = \"AccountsInvalidContentType\"\n\tFederatedAuthRequestIssueReasonIDTokenHTTPNotFound              FederatedAuthRequestIssueReason = \"IdTokenHttpNotFound\"\n\tFederatedAuthRequestIssueReasonIDTokenNoResponse                FederatedAuthRequestIssueReason = \"IdTokenNoResponse\"\n\tFederatedAuthRequestIssueReasonIDTokenInvalidResponse           FederatedAuthRequestIssueReason = \"IdTokenInvalidResponse\"\n\tFederatedAuthRequestIssueReasonIDTokenIdpErrorResponse          FederatedAuthRequestIssueReason = \"IdTokenIdpErrorResponse\"\n\tFederatedAuthRequestIssueReasonIDTokenCrossSiteIdpErrorResponse FederatedAuthRequestIssueReason = \"IdTokenCrossSiteIdpErrorResponse\"\n\tFederatedAuthRequestIssueReasonIDTokenInvalidRequest            FederatedAuthRequestIssueReason = \"IdTokenInvalidRequest\"\n\tFederatedAuthRequestIssueReasonIDTokenInvalidContentType        FederatedAuthRequestIssueReason = \"IdTokenInvalidContentType\"\n\tFederatedAuthRequestIssueReasonErrorIDToken                     FederatedAuthRequestIssueReason = \"ErrorIdToken\"\n\tFederatedAuthRequestIssueReasonCanceled                         FederatedAuthRequestIssueReason = \"Canceled\"\n\tFederatedAuthRequestIssueReasonRpPageNotVisible                 FederatedAuthRequestIssueReason = \"RpPageNotVisible\"\n\tFederatedAuthRequestIssueReasonSilentMediationFailure           FederatedAuthRequestIssueReason = \"SilentMediationFailure\"\n\tFederatedAuthRequestIssueReasonThirdPartyCookiesBlocked         FederatedAuthRequestIssueReason = \"ThirdPartyCookiesBlocked\"\n\tFederatedAuthRequestIssueReasonNotSignedInWithIdp               FederatedAuthRequestIssueReason = \"NotSignedInWithIdp\"\n\tFederatedAuthRequestIssueReasonMissingTransientUserActivation   FederatedAuthRequestIssueReason = \"MissingTransientUserActivation\"\n\tFederatedAuthRequestIssueReasonReplacedByActiveMode             FederatedAuthRequestIssueReason = \"ReplacedByActiveMode\"\n\tFederatedAuthRequestIssueReasonInvalidFieldsSpecified           FederatedAuthRequestIssueReason = \"InvalidFieldsSpecified\"\n\tFederatedAuthRequestIssueReasonRelyingPartyOriginIsOpaque       FederatedAuthRequestIssueReason = \"RelyingPartyOriginIsOpaque\"\n\tFederatedAuthRequestIssueReasonTypeNotMatching                  FederatedAuthRequestIssueReason = \"TypeNotMatching\"\n\tFederatedAuthRequestIssueReasonUIDismissedNoEmbargo             FederatedAuthRequestIssueReason = \"UiDismissedNoEmbargo\"\n\tFederatedAuthRequestIssueReasonCorsError                        FederatedAuthRequestIssueReason = \"CorsError\"\n\tFederatedAuthRequestIssueReasonSuppressedBySegmentationPlatform FederatedAuthRequestIssueReason = \"SuppressedBySegmentationPlatform\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *FederatedAuthRequestIssueReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch FederatedAuthRequestIssueReason(s) {\n\tcase FederatedAuthRequestIssueReasonShouldEmbargo:\n\t\t*t = FederatedAuthRequestIssueReasonShouldEmbargo\n\tcase FederatedAuthRequestIssueReasonTooManyRequests:\n\t\t*t = FederatedAuthRequestIssueReasonTooManyRequests\n\tcase FederatedAuthRequestIssueReasonWellKnownHTTPNotFound:\n\t\t*t = FederatedAuthRequestIssueReasonWellKnownHTTPNotFound\n\tcase FederatedAuthRequestIssueReasonWellKnownNoResponse:\n\t\t*t = FederatedAuthRequestIssueReasonWellKnownNoResponse\n\tcase FederatedAuthRequestIssueReasonWellKnownInvalidResponse:\n\t\t*t = FederatedAuthRequestIssueReasonWellKnownInvalidResponse\n\tcase FederatedAuthRequestIssueReasonWellKnownListEmpty:\n\t\t*t = FederatedAuthRequestIssueReasonWellKnownListEmpty\n\tcase FederatedAuthRequestIssueReasonWellKnownInvalidContentType:\n\t\t*t = FederatedAuthRequestIssueReasonWellKnownInvalidContentType\n\tcase FederatedAuthRequestIssueReasonConfigNotInWellKnown:\n\t\t*t = FederatedAuthRequestIssueReasonConfigNotInWellKnown\n\tcase FederatedAuthRequestIssueReasonWellKnownTooBig:\n\t\t*t = FederatedAuthRequestIssueReasonWellKnownTooBig\n\tcase FederatedAuthRequestIssueReasonConfigHTTPNotFound:\n\t\t*t = FederatedAuthRequestIssueReasonConfigHTTPNotFound\n\tcase FederatedAuthRequestIssueReasonConfigNoResponse:\n\t\t*t = FederatedAuthRequestIssueReasonConfigNoResponse\n\tcase FederatedAuthRequestIssueReasonConfigInvalidResponse:\n\t\t*t = FederatedAuthRequestIssueReasonConfigInvalidResponse\n\tcase FederatedAuthRequestIssueReasonConfigInvalidContentType:\n\t\t*t = FederatedAuthRequestIssueReasonConfigInvalidContentType\n\tcase FederatedAuthRequestIssueReasonClientMetadataHTTPNotFound:\n\t\t*t = FederatedAuthRequestIssueReasonClientMetadataHTTPNotFound\n\tcase FederatedAuthRequestIssueReasonClientMetadataNoResponse:\n\t\t*t = FederatedAuthRequestIssueReasonClientMetadataNoResponse\n\tcase FederatedAuthRequestIssueReasonClientMetadataInvalidResponse:\n\t\t*t = FederatedAuthRequestIssueReasonClientMetadataInvalidResponse\n\tcase FederatedAuthRequestIssueReasonClientMetadataInvalidContentType:\n\t\t*t = FederatedAuthRequestIssueReasonClientMetadataInvalidContentType\n\tcase FederatedAuthRequestIssueReasonIdpNotPotentiallyTrustworthy:\n\t\t*t = FederatedAuthRequestIssueReasonIdpNotPotentiallyTrustworthy\n\tcase FederatedAuthRequestIssueReasonDisabledInSettings:\n\t\t*t = FederatedAuthRequestIssueReasonDisabledInSettings\n\tcase FederatedAuthRequestIssueReasonDisabledInFlags:\n\t\t*t = FederatedAuthRequestIssueReasonDisabledInFlags\n\tcase FederatedAuthRequestIssueReasonErrorFetchingSignin:\n\t\t*t = FederatedAuthRequestIssueReasonErrorFetchingSignin\n\tcase FederatedAuthRequestIssueReasonInvalidSigninResponse:\n\t\t*t = FederatedAuthRequestIssueReasonInvalidSigninResponse\n\tcase FederatedAuthRequestIssueReasonAccountsHTTPNotFound:\n\t\t*t = FederatedAuthRequestIssueReasonAccountsHTTPNotFound\n\tcase FederatedAuthRequestIssueReasonAccountsNoResponse:\n\t\t*t = FederatedAuthRequestIssueReasonAccountsNoResponse\n\tcase FederatedAuthRequestIssueReasonAccountsInvalidResponse:\n\t\t*t = FederatedAuthRequestIssueReasonAccountsInvalidResponse\n\tcase FederatedAuthRequestIssueReasonAccountsListEmpty:\n\t\t*t = FederatedAuthRequestIssueReasonAccountsListEmpty\n\tcase FederatedAuthRequestIssueReasonAccountsInvalidContentType:\n\t\t*t = FederatedAuthRequestIssueReasonAccountsInvalidContentType\n\tcase FederatedAuthRequestIssueReasonIDTokenHTTPNotFound:\n\t\t*t = FederatedAuthRequestIssueReasonIDTokenHTTPNotFound\n\tcase FederatedAuthRequestIssueReasonIDTokenNoResponse:\n\t\t*t = FederatedAuthRequestIssueReasonIDTokenNoResponse\n\tcase FederatedAuthRequestIssueReasonIDTokenInvalidResponse:\n\t\t*t = FederatedAuthRequestIssueReasonIDTokenInvalidResponse\n\tcase FederatedAuthRequestIssueReasonIDTokenIdpErrorResponse:\n\t\t*t = FederatedAuthRequestIssueReasonIDTokenIdpErrorResponse\n\tcase FederatedAuthRequestIssueReasonIDTokenCrossSiteIdpErrorResponse:\n\t\t*t = FederatedAuthRequestIssueReasonIDTokenCrossSiteIdpErrorResponse\n\tcase FederatedAuthRequestIssueReasonIDTokenInvalidRequest:\n\t\t*t = FederatedAuthRequestIssueReasonIDTokenInvalidRequest\n\tcase FederatedAuthRequestIssueReasonIDTokenInvalidContentType:\n\t\t*t = FederatedAuthRequestIssueReasonIDTokenInvalidContentType\n\tcase FederatedAuthRequestIssueReasonErrorIDToken:\n\t\t*t = FederatedAuthRequestIssueReasonErrorIDToken\n\tcase FederatedAuthRequestIssueReasonCanceled:\n\t\t*t = FederatedAuthRequestIssueReasonCanceled\n\tcase FederatedAuthRequestIssueReasonRpPageNotVisible:\n\t\t*t = FederatedAuthRequestIssueReasonRpPageNotVisible\n\tcase FederatedAuthRequestIssueReasonSilentMediationFailure:\n\t\t*t = FederatedAuthRequestIssueReasonSilentMediationFailure\n\tcase FederatedAuthRequestIssueReasonThirdPartyCookiesBlocked:\n\t\t*t = FederatedAuthRequestIssueReasonThirdPartyCookiesBlocked\n\tcase FederatedAuthRequestIssueReasonNotSignedInWithIdp:\n\t\t*t = FederatedAuthRequestIssueReasonNotSignedInWithIdp\n\tcase FederatedAuthRequestIssueReasonMissingTransientUserActivation:\n\t\t*t = FederatedAuthRequestIssueReasonMissingTransientUserActivation\n\tcase FederatedAuthRequestIssueReasonReplacedByActiveMode:\n\t\t*t = FederatedAuthRequestIssueReasonReplacedByActiveMode\n\tcase FederatedAuthRequestIssueReasonInvalidFieldsSpecified:\n\t\t*t = FederatedAuthRequestIssueReasonInvalidFieldsSpecified\n\tcase FederatedAuthRequestIssueReasonRelyingPartyOriginIsOpaque:\n\t\t*t = FederatedAuthRequestIssueReasonRelyingPartyOriginIsOpaque\n\tcase FederatedAuthRequestIssueReasonTypeNotMatching:\n\t\t*t = FederatedAuthRequestIssueReasonTypeNotMatching\n\tcase FederatedAuthRequestIssueReasonUIDismissedNoEmbargo:\n\t\t*t = FederatedAuthRequestIssueReasonUIDismissedNoEmbargo\n\tcase FederatedAuthRequestIssueReasonCorsError:\n\t\t*t = FederatedAuthRequestIssueReasonCorsError\n\tcase FederatedAuthRequestIssueReasonSuppressedBySegmentationPlatform:\n\t\t*t = FederatedAuthRequestIssueReasonSuppressedBySegmentationPlatform\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown FederatedAuthRequestIssueReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// FederatedAuthUserInfoRequestIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-FederatedAuthUserInfoRequestIssueDetails\ntype FederatedAuthUserInfoRequestIssueDetails struct {\n\tFederatedAuthUserInfoRequestIssueReason FederatedAuthUserInfoRequestIssueReason `json:\"federatedAuthUserInfoRequestIssueReason\"`\n}\n\n// FederatedAuthUserInfoRequestIssueReason represents the failure reason when\n// a getUserInfo() call fails. Should be updated alongside\n// FederatedAuthUserInfoRequestResult in\n// third_party/blink/public/mojom/devtools/inspector_issue.mojom.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-FederatedAuthUserInfoRequestIssueReason\ntype FederatedAuthUserInfoRequestIssueReason string\n\n// String returns the FederatedAuthUserInfoRequestIssueReason as string value.\nfunc (t FederatedAuthUserInfoRequestIssueReason) String() string {\n\treturn string(t)\n}\n\n// FederatedAuthUserInfoRequestIssueReason values.\nconst (\n\tFederatedAuthUserInfoRequestIssueReasonNotSameOrigin                      FederatedAuthUserInfoRequestIssueReason = \"NotSameOrigin\"\n\tFederatedAuthUserInfoRequestIssueReasonNotIframe                          FederatedAuthUserInfoRequestIssueReason = \"NotIframe\"\n\tFederatedAuthUserInfoRequestIssueReasonNotPotentiallyTrustworthy          FederatedAuthUserInfoRequestIssueReason = \"NotPotentiallyTrustworthy\"\n\tFederatedAuthUserInfoRequestIssueReasonNoAPIPermission                    FederatedAuthUserInfoRequestIssueReason = \"NoApiPermission\"\n\tFederatedAuthUserInfoRequestIssueReasonNotSignedInWithIdp                 FederatedAuthUserInfoRequestIssueReason = \"NotSignedInWithIdp\"\n\tFederatedAuthUserInfoRequestIssueReasonNoAccountSharingPermission         FederatedAuthUserInfoRequestIssueReason = \"NoAccountSharingPermission\"\n\tFederatedAuthUserInfoRequestIssueReasonInvalidConfigOrWellKnown           FederatedAuthUserInfoRequestIssueReason = \"InvalidConfigOrWellKnown\"\n\tFederatedAuthUserInfoRequestIssueReasonInvalidAccountsResponse            FederatedAuthUserInfoRequestIssueReason = \"InvalidAccountsResponse\"\n\tFederatedAuthUserInfoRequestIssueReasonNoReturningUserFromFetchedAccounts FederatedAuthUserInfoRequestIssueReason = \"NoReturningUserFromFetchedAccounts\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *FederatedAuthUserInfoRequestIssueReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch FederatedAuthUserInfoRequestIssueReason(s) {\n\tcase FederatedAuthUserInfoRequestIssueReasonNotSameOrigin:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonNotSameOrigin\n\tcase FederatedAuthUserInfoRequestIssueReasonNotIframe:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonNotIframe\n\tcase FederatedAuthUserInfoRequestIssueReasonNotPotentiallyTrustworthy:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonNotPotentiallyTrustworthy\n\tcase FederatedAuthUserInfoRequestIssueReasonNoAPIPermission:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonNoAPIPermission\n\tcase FederatedAuthUserInfoRequestIssueReasonNotSignedInWithIdp:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonNotSignedInWithIdp\n\tcase FederatedAuthUserInfoRequestIssueReasonNoAccountSharingPermission:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonNoAccountSharingPermission\n\tcase FederatedAuthUserInfoRequestIssueReasonInvalidConfigOrWellKnown:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonInvalidConfigOrWellKnown\n\tcase FederatedAuthUserInfoRequestIssueReasonInvalidAccountsResponse:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonInvalidAccountsResponse\n\tcase FederatedAuthUserInfoRequestIssueReasonNoReturningUserFromFetchedAccounts:\n\t\t*t = FederatedAuthUserInfoRequestIssueReasonNoReturningUserFromFetchedAccounts\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown FederatedAuthUserInfoRequestIssueReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ClientHintIssueDetails this issue tracks client hints related issues. It's\n// used to deprecate old features, encourage the use of new ones, and provide\n// general guidance.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-ClientHintIssueDetails\ntype ClientHintIssueDetails struct {\n\tSourceCodeLocation    *SourceCodeLocation   `json:\"sourceCodeLocation\"`\n\tClientHintIssueReason ClientHintIssueReason `json:\"clientHintIssueReason\"`\n}\n\n// FailedRequestInfo [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-FailedRequestInfo\ntype FailedRequestInfo struct {\n\tURL            string            `json:\"url\"`            // The URL that failed to load.\n\tFailureMessage string            `json:\"failureMessage\"` // The failure message for the failed request.\n\tRequestID      network.RequestID `json:\"requestId,omitempty,omitzero\"`\n}\n\n// PartitioningBlobURLInfo [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-PartitioningBlobURLInfo\ntype PartitioningBlobURLInfo string\n\n// String returns the PartitioningBlobURLInfo as string value.\nfunc (t PartitioningBlobURLInfo) String() string {\n\treturn string(t)\n}\n\n// PartitioningBlobURLInfo values.\nconst (\n\tPartitioningBlobURLInfoBlockedCrossPartitionFetching PartitioningBlobURLInfo = \"BlockedCrossPartitionFetching\"\n\tPartitioningBlobURLInfoEnforceNoopenerForNavigation  PartitioningBlobURLInfo = \"EnforceNoopenerForNavigation\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PartitioningBlobURLInfo) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PartitioningBlobURLInfo(s) {\n\tcase PartitioningBlobURLInfoBlockedCrossPartitionFetching:\n\t\t*t = PartitioningBlobURLInfoBlockedCrossPartitionFetching\n\tcase PartitioningBlobURLInfoEnforceNoopenerForNavigation:\n\t\t*t = PartitioningBlobURLInfoEnforceNoopenerForNavigation\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PartitioningBlobURLInfo value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PartitioningBlobURLIssueDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-PartitioningBlobURLIssueDetails\ntype PartitioningBlobURLIssueDetails struct {\n\tURL                     string                  `json:\"url\"`                     // The BlobURL that failed to load.\n\tPartitioningBlobURLInfo PartitioningBlobURLInfo `json:\"partitioningBlobURLInfo\"` // Additional information about the Partitioning Blob URL issue.\n}\n\n// ElementAccessibilityIssueReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-ElementAccessibilityIssueReason\ntype ElementAccessibilityIssueReason string\n\n// String returns the ElementAccessibilityIssueReason as string value.\nfunc (t ElementAccessibilityIssueReason) String() string {\n\treturn string(t)\n}\n\n// ElementAccessibilityIssueReason values.\nconst (\n\tElementAccessibilityIssueReasonDisallowedSelectChild               ElementAccessibilityIssueReason = \"DisallowedSelectChild\"\n\tElementAccessibilityIssueReasonDisallowedOptGroupChild             ElementAccessibilityIssueReason = \"DisallowedOptGroupChild\"\n\tElementAccessibilityIssueReasonNonPhrasingContentOptionChild       ElementAccessibilityIssueReason = \"NonPhrasingContentOptionChild\"\n\tElementAccessibilityIssueReasonInteractiveContentOptionChild       ElementAccessibilityIssueReason = \"InteractiveContentOptionChild\"\n\tElementAccessibilityIssueReasonInteractiveContentLegendChild       ElementAccessibilityIssueReason = \"InteractiveContentLegendChild\"\n\tElementAccessibilityIssueReasonInteractiveContentSummaryDescendant ElementAccessibilityIssueReason = \"InteractiveContentSummaryDescendant\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ElementAccessibilityIssueReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ElementAccessibilityIssueReason(s) {\n\tcase ElementAccessibilityIssueReasonDisallowedSelectChild:\n\t\t*t = ElementAccessibilityIssueReasonDisallowedSelectChild\n\tcase ElementAccessibilityIssueReasonDisallowedOptGroupChild:\n\t\t*t = ElementAccessibilityIssueReasonDisallowedOptGroupChild\n\tcase ElementAccessibilityIssueReasonNonPhrasingContentOptionChild:\n\t\t*t = ElementAccessibilityIssueReasonNonPhrasingContentOptionChild\n\tcase ElementAccessibilityIssueReasonInteractiveContentOptionChild:\n\t\t*t = ElementAccessibilityIssueReasonInteractiveContentOptionChild\n\tcase ElementAccessibilityIssueReasonInteractiveContentLegendChild:\n\t\t*t = ElementAccessibilityIssueReasonInteractiveContentLegendChild\n\tcase ElementAccessibilityIssueReasonInteractiveContentSummaryDescendant:\n\t\t*t = ElementAccessibilityIssueReasonInteractiveContentSummaryDescendant\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ElementAccessibilityIssueReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ElementAccessibilityIssueDetails this issue warns about errors in the\n// select or summary element content model.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-ElementAccessibilityIssueDetails\ntype ElementAccessibilityIssueDetails struct {\n\tNodeID                          cdp.BackendNodeID               `json:\"nodeId\"`\n\tElementAccessibilityIssueReason ElementAccessibilityIssueReason `json:\"elementAccessibilityIssueReason\"`\n\tHasDisallowedAttributes         bool                            `json:\"hasDisallowedAttributes\"`\n}\n\n// StyleSheetLoadingIssueReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-StyleSheetLoadingIssueReason\ntype StyleSheetLoadingIssueReason string\n\n// String returns the StyleSheetLoadingIssueReason as string value.\nfunc (t StyleSheetLoadingIssueReason) String() string {\n\treturn string(t)\n}\n\n// StyleSheetLoadingIssueReason values.\nconst (\n\tStyleSheetLoadingIssueReasonLateImportRule StyleSheetLoadingIssueReason = \"LateImportRule\"\n\tStyleSheetLoadingIssueReasonRequestFailed  StyleSheetLoadingIssueReason = \"RequestFailed\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *StyleSheetLoadingIssueReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch StyleSheetLoadingIssueReason(s) {\n\tcase StyleSheetLoadingIssueReasonLateImportRule:\n\t\t*t = StyleSheetLoadingIssueReasonLateImportRule\n\tcase StyleSheetLoadingIssueReasonRequestFailed:\n\t\t*t = StyleSheetLoadingIssueReasonRequestFailed\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown StyleSheetLoadingIssueReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// StylesheetLoadingIssueDetails this issue warns when a referenced\n// stylesheet couldn't be loaded.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-StylesheetLoadingIssueDetails\ntype StylesheetLoadingIssueDetails struct {\n\tSourceCodeLocation           *SourceCodeLocation          `json:\"sourceCodeLocation\"`                   // Source code position that referenced the failing stylesheet.\n\tStyleSheetLoadingIssueReason StyleSheetLoadingIssueReason `json:\"styleSheetLoadingIssueReason\"`         // Reason why the stylesheet couldn't be loaded.\n\tFailedRequestInfo            *FailedRequestInfo           `json:\"failedRequestInfo,omitempty,omitzero\"` // Contains additional info when the failure was due to a request.\n}\n\n// PropertyRuleIssueReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-PropertyRuleIssueReason\ntype PropertyRuleIssueReason string\n\n// String returns the PropertyRuleIssueReason as string value.\nfunc (t PropertyRuleIssueReason) String() string {\n\treturn string(t)\n}\n\n// PropertyRuleIssueReason values.\nconst (\n\tPropertyRuleIssueReasonInvalidSyntax       PropertyRuleIssueReason = \"InvalidSyntax\"\n\tPropertyRuleIssueReasonInvalidInitialValue PropertyRuleIssueReason = \"InvalidInitialValue\"\n\tPropertyRuleIssueReasonInvalidInherits     PropertyRuleIssueReason = \"InvalidInherits\"\n\tPropertyRuleIssueReasonInvalidName         PropertyRuleIssueReason = \"InvalidName\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PropertyRuleIssueReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PropertyRuleIssueReason(s) {\n\tcase PropertyRuleIssueReasonInvalidSyntax:\n\t\t*t = PropertyRuleIssueReasonInvalidSyntax\n\tcase PropertyRuleIssueReasonInvalidInitialValue:\n\t\t*t = PropertyRuleIssueReasonInvalidInitialValue\n\tcase PropertyRuleIssueReasonInvalidInherits:\n\t\t*t = PropertyRuleIssueReasonInvalidInherits\n\tcase PropertyRuleIssueReasonInvalidName:\n\t\t*t = PropertyRuleIssueReasonInvalidName\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PropertyRuleIssueReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PropertyRuleIssueDetails this issue warns about errors in property rules\n// that lead to property registrations being ignored.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-PropertyRuleIssueDetails\ntype PropertyRuleIssueDetails struct {\n\tSourceCodeLocation      *SourceCodeLocation     `json:\"sourceCodeLocation\"`               // Source code position of the property rule.\n\tPropertyRuleIssueReason PropertyRuleIssueReason `json:\"propertyRuleIssueReason\"`          // Reason why the property rule was discarded.\n\tPropertyValue           string                  `json:\"propertyValue,omitempty,omitzero\"` // The value of the property rule property that failed to parse\n}\n\n// UserReidentificationIssueType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-UserReidentificationIssueType\ntype UserReidentificationIssueType string\n\n// String returns the UserReidentificationIssueType as string value.\nfunc (t UserReidentificationIssueType) String() string {\n\treturn string(t)\n}\n\n// UserReidentificationIssueType values.\nconst (\n\tUserReidentificationIssueTypeBlockedFrameNavigation UserReidentificationIssueType = \"BlockedFrameNavigation\"\n\tUserReidentificationIssueTypeBlockedSubresource     UserReidentificationIssueType = \"BlockedSubresource\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *UserReidentificationIssueType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch UserReidentificationIssueType(s) {\n\tcase UserReidentificationIssueTypeBlockedFrameNavigation:\n\t\t*t = UserReidentificationIssueTypeBlockedFrameNavigation\n\tcase UserReidentificationIssueTypeBlockedSubresource:\n\t\t*t = UserReidentificationIssueTypeBlockedSubresource\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown UserReidentificationIssueType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// UserReidentificationIssueDetails this issue warns about uses of APIs that\n// may be considered misuse to re-identify users.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-UserReidentificationIssueDetails\ntype UserReidentificationIssueDetails struct {\n\tType    UserReidentificationIssueType `json:\"type\"`\n\tRequest *AffectedRequest              `json:\"request,omitempty,omitzero\"` // Applies to BlockedFrameNavigation and BlockedSubresource issue types.\n}\n\n// InspectorIssueCode a unique identifier for the type of issue. Each type\n// may use one of the optional fields in InspectorIssueDetails to convey more\n// specific information about the kind of issue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-InspectorIssueCode\ntype InspectorIssueCode string\n\n// String returns the InspectorIssueCode as string value.\nfunc (t InspectorIssueCode) String() string {\n\treturn string(t)\n}\n\n// InspectorIssueCode values.\nconst (\n\tInspectorIssueCodeCookieIssue                       InspectorIssueCode = \"CookieIssue\"\n\tInspectorIssueCodeMixedContentIssue                 InspectorIssueCode = \"MixedContentIssue\"\n\tInspectorIssueCodeBlockedByResponseIssue            InspectorIssueCode = \"BlockedByResponseIssue\"\n\tInspectorIssueCodeHeavyAdIssue                      InspectorIssueCode = \"HeavyAdIssue\"\n\tInspectorIssueCodeContentSecurityPolicyIssue        InspectorIssueCode = \"ContentSecurityPolicyIssue\"\n\tInspectorIssueCodeSharedArrayBufferIssue            InspectorIssueCode = \"SharedArrayBufferIssue\"\n\tInspectorIssueCodeLowTextContrastIssue              InspectorIssueCode = \"LowTextContrastIssue\"\n\tInspectorIssueCodeCorsIssue                         InspectorIssueCode = \"CorsIssue\"\n\tInspectorIssueCodeAttributionReportingIssue         InspectorIssueCode = \"AttributionReportingIssue\"\n\tInspectorIssueCodeQuirksModeIssue                   InspectorIssueCode = \"QuirksModeIssue\"\n\tInspectorIssueCodePartitioningBlobURLIssue          InspectorIssueCode = \"PartitioningBlobURLIssue\"\n\tInspectorIssueCodeNavigatorUserAgentIssue           InspectorIssueCode = \"NavigatorUserAgentIssue\"\n\tInspectorIssueCodeGenericIssue                      InspectorIssueCode = \"GenericIssue\"\n\tInspectorIssueCodeDeprecationIssue                  InspectorIssueCode = \"DeprecationIssue\"\n\tInspectorIssueCodeClientHintIssue                   InspectorIssueCode = \"ClientHintIssue\"\n\tInspectorIssueCodeFederatedAuthRequestIssue         InspectorIssueCode = \"FederatedAuthRequestIssue\"\n\tInspectorIssueCodeBounceTrackingIssue               InspectorIssueCode = \"BounceTrackingIssue\"\n\tInspectorIssueCodeCookieDeprecationMetadataIssue    InspectorIssueCode = \"CookieDeprecationMetadataIssue\"\n\tInspectorIssueCodeStylesheetLoadingIssue            InspectorIssueCode = \"StylesheetLoadingIssue\"\n\tInspectorIssueCodeFederatedAuthUserInfoRequestIssue InspectorIssueCode = \"FederatedAuthUserInfoRequestIssue\"\n\tInspectorIssueCodePropertyRuleIssue                 InspectorIssueCode = \"PropertyRuleIssue\"\n\tInspectorIssueCodeSharedDictionaryIssue             InspectorIssueCode = \"SharedDictionaryIssue\"\n\tInspectorIssueCodeElementAccessibilityIssue         InspectorIssueCode = \"ElementAccessibilityIssue\"\n\tInspectorIssueCodeSRIMessageSignatureIssue          InspectorIssueCode = \"SRIMessageSignatureIssue\"\n\tInspectorIssueCodeUnencodedDigestIssue              InspectorIssueCode = \"UnencodedDigestIssue\"\n\tInspectorIssueCodeUserReidentificationIssue         InspectorIssueCode = \"UserReidentificationIssue\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InspectorIssueCode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InspectorIssueCode(s) {\n\tcase InspectorIssueCodeCookieIssue:\n\t\t*t = InspectorIssueCodeCookieIssue\n\tcase InspectorIssueCodeMixedContentIssue:\n\t\t*t = InspectorIssueCodeMixedContentIssue\n\tcase InspectorIssueCodeBlockedByResponseIssue:\n\t\t*t = InspectorIssueCodeBlockedByResponseIssue\n\tcase InspectorIssueCodeHeavyAdIssue:\n\t\t*t = InspectorIssueCodeHeavyAdIssue\n\tcase InspectorIssueCodeContentSecurityPolicyIssue:\n\t\t*t = InspectorIssueCodeContentSecurityPolicyIssue\n\tcase InspectorIssueCodeSharedArrayBufferIssue:\n\t\t*t = InspectorIssueCodeSharedArrayBufferIssue\n\tcase InspectorIssueCodeLowTextContrastIssue:\n\t\t*t = InspectorIssueCodeLowTextContrastIssue\n\tcase InspectorIssueCodeCorsIssue:\n\t\t*t = InspectorIssueCodeCorsIssue\n\tcase InspectorIssueCodeAttributionReportingIssue:\n\t\t*t = InspectorIssueCodeAttributionReportingIssue\n\tcase InspectorIssueCodeQuirksModeIssue:\n\t\t*t = InspectorIssueCodeQuirksModeIssue\n\tcase InspectorIssueCodePartitioningBlobURLIssue:\n\t\t*t = InspectorIssueCodePartitioningBlobURLIssue\n\tcase InspectorIssueCodeNavigatorUserAgentIssue:\n\t\t*t = InspectorIssueCodeNavigatorUserAgentIssue\n\tcase InspectorIssueCodeGenericIssue:\n\t\t*t = InspectorIssueCodeGenericIssue\n\tcase InspectorIssueCodeDeprecationIssue:\n\t\t*t = InspectorIssueCodeDeprecationIssue\n\tcase InspectorIssueCodeClientHintIssue:\n\t\t*t = InspectorIssueCodeClientHintIssue\n\tcase InspectorIssueCodeFederatedAuthRequestIssue:\n\t\t*t = InspectorIssueCodeFederatedAuthRequestIssue\n\tcase InspectorIssueCodeBounceTrackingIssue:\n\t\t*t = InspectorIssueCodeBounceTrackingIssue\n\tcase InspectorIssueCodeCookieDeprecationMetadataIssue:\n\t\t*t = InspectorIssueCodeCookieDeprecationMetadataIssue\n\tcase InspectorIssueCodeStylesheetLoadingIssue:\n\t\t*t = InspectorIssueCodeStylesheetLoadingIssue\n\tcase InspectorIssueCodeFederatedAuthUserInfoRequestIssue:\n\t\t*t = InspectorIssueCodeFederatedAuthUserInfoRequestIssue\n\tcase InspectorIssueCodePropertyRuleIssue:\n\t\t*t = InspectorIssueCodePropertyRuleIssue\n\tcase InspectorIssueCodeSharedDictionaryIssue:\n\t\t*t = InspectorIssueCodeSharedDictionaryIssue\n\tcase InspectorIssueCodeElementAccessibilityIssue:\n\t\t*t = InspectorIssueCodeElementAccessibilityIssue\n\tcase InspectorIssueCodeSRIMessageSignatureIssue:\n\t\t*t = InspectorIssueCodeSRIMessageSignatureIssue\n\tcase InspectorIssueCodeUnencodedDigestIssue:\n\t\t*t = InspectorIssueCodeUnencodedDigestIssue\n\tcase InspectorIssueCodeUserReidentificationIssue:\n\t\t*t = InspectorIssueCodeUserReidentificationIssue\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InspectorIssueCode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// InspectorIssueDetails this struct holds a list of optional fields with\n// additional information specific to the kind of issue. When adding a new issue\n// code, please also add a new optional field to this type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-InspectorIssueDetails\ntype InspectorIssueDetails struct {\n\tCookieIssueDetails                       *CookieIssueDetails                       `json:\"cookieIssueDetails,omitempty,omitzero\"`\n\tMixedContentIssueDetails                 *MixedContentIssueDetails                 `json:\"mixedContentIssueDetails,omitempty,omitzero\"`\n\tBlockedByResponseIssueDetails            *BlockedByResponseIssueDetails            `json:\"blockedByResponseIssueDetails,omitempty,omitzero\"`\n\tHeavyAdIssueDetails                      *HeavyAdIssueDetails                      `json:\"heavyAdIssueDetails,omitempty,omitzero\"`\n\tContentSecurityPolicyIssueDetails        *ContentSecurityPolicyIssueDetails        `json:\"contentSecurityPolicyIssueDetails,omitempty,omitzero\"`\n\tSharedArrayBufferIssueDetails            *SharedArrayBufferIssueDetails            `json:\"sharedArrayBufferIssueDetails,omitempty,omitzero\"`\n\tLowTextContrastIssueDetails              *LowTextContrastIssueDetails              `json:\"lowTextContrastIssueDetails,omitempty,omitzero\"`\n\tCorsIssueDetails                         *CorsIssueDetails                         `json:\"corsIssueDetails,omitempty,omitzero\"`\n\tAttributionReportingIssueDetails         *AttributionReportingIssueDetails         `json:\"attributionReportingIssueDetails,omitempty,omitzero\"`\n\tQuirksModeIssueDetails                   *QuirksModeIssueDetails                   `json:\"quirksModeIssueDetails,omitempty,omitzero\"`\n\tPartitioningBlobURLIssueDetails          *PartitioningBlobURLIssueDetails          `json:\"partitioningBlobURLIssueDetails,omitempty,omitzero\"`\n\tGenericIssueDetails                      *GenericIssueDetails                      `json:\"genericIssueDetails,omitempty,omitzero\"`\n\tDeprecationIssueDetails                  *DeprecationIssueDetails                  `json:\"deprecationIssueDetails,omitempty,omitzero\"`\n\tClientHintIssueDetails                   *ClientHintIssueDetails                   `json:\"clientHintIssueDetails,omitempty,omitzero\"`\n\tFederatedAuthRequestIssueDetails         *FederatedAuthRequestIssueDetails         `json:\"federatedAuthRequestIssueDetails,omitempty,omitzero\"`\n\tBounceTrackingIssueDetails               *BounceTrackingIssueDetails               `json:\"bounceTrackingIssueDetails,omitempty,omitzero\"`\n\tCookieDeprecationMetadataIssueDetails    *CookieDeprecationMetadataIssueDetails    `json:\"cookieDeprecationMetadataIssueDetails,omitempty,omitzero\"`\n\tStylesheetLoadingIssueDetails            *StylesheetLoadingIssueDetails            `json:\"stylesheetLoadingIssueDetails,omitempty,omitzero\"`\n\tPropertyRuleIssueDetails                 *PropertyRuleIssueDetails                 `json:\"propertyRuleIssueDetails,omitempty,omitzero\"`\n\tFederatedAuthUserInfoRequestIssueDetails *FederatedAuthUserInfoRequestIssueDetails `json:\"federatedAuthUserInfoRequestIssueDetails,omitempty,omitzero\"`\n\tSharedDictionaryIssueDetails             *SharedDictionaryIssueDetails             `json:\"sharedDictionaryIssueDetails,omitempty,omitzero\"`\n\tElementAccessibilityIssueDetails         *ElementAccessibilityIssueDetails         `json:\"elementAccessibilityIssueDetails,omitempty,omitzero\"`\n\tSriMessageSignatureIssueDetails          *SRIMessageSignatureIssueDetails          `json:\"sriMessageSignatureIssueDetails,omitempty,omitzero\"`\n\tUnencodedDigestIssueDetails              *UnencodedDigestIssueDetails              `json:\"unencodedDigestIssueDetails,omitempty,omitzero\"`\n\tUserReidentificationIssueDetails         *UserReidentificationIssueDetails         `json:\"userReidentificationIssueDetails,omitempty,omitzero\"`\n}\n\n// IssueID a unique id for a DevTools inspector issue. Allows other entities\n// (e.g. exceptions, CDP message, console messages, etc.) to reference an issue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-IssueId\ntype IssueID string\n\n// String returns the IssueID as string value.\nfunc (t IssueID) String() string {\n\treturn string(t)\n}\n\n// InspectorIssue an inspector issue reported from the back-end.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#type-InspectorIssue\ntype InspectorIssue struct {\n\tCode    InspectorIssueCode     `json:\"code\"`\n\tDetails *InspectorIssueDetails `json:\"details\"`\n\tIssueID IssueID                `json:\"issueId,omitempty,omitzero\"` // A unique id for this issue. May be omitted if no other entity (e.g. exception, CDP message, etc.) is referencing this issue.\n}\n\n// GetEncodedResponseEncoding the encoding to use.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Audits#method-getEncodedResponse\ntype GetEncodedResponseEncoding string\n\n// String returns the GetEncodedResponseEncoding as string value.\nfunc (t GetEncodedResponseEncoding) String() string {\n\treturn string(t)\n}\n\n// GetEncodedResponseEncoding values.\nconst (\n\tGetEncodedResponseEncodingWebp GetEncodedResponseEncoding = \"webp\"\n\tGetEncodedResponseEncodingJpeg GetEncodedResponseEncoding = \"jpeg\"\n\tGetEncodedResponseEncodingPng  GetEncodedResponseEncoding = \"png\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *GetEncodedResponseEncoding) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch GetEncodedResponseEncoding(s) {\n\tcase GetEncodedResponseEncodingWebp:\n\t\t*t = GetEncodedResponseEncodingWebp\n\tcase GetEncodedResponseEncodingJpeg:\n\t\t*t = GetEncodedResponseEncodingJpeg\n\tcase GetEncodedResponseEncodingPng:\n\t\t*t = GetEncodedResponseEncodingPng\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown GetEncodedResponseEncoding value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/autofill/autofill.go",
    "content": "// Package autofill provides the Chrome DevTools Protocol\n// commands, types, and events for the Autofill domain.\n//\n// Defines commands and events for Autofill.\n//\n// Generated by the cdproto-gen command.\npackage autofill\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// TriggerParams trigger autofill on a form identified by the fieldId. If the\n// field and related form cannot be autofilled, returns an error.\ntype TriggerParams struct {\n\tFieldID cdp.BackendNodeID `json:\"fieldId\"`                    // Identifies a field that serves as an anchor for autofill.\n\tFrameID cdp.FrameID       `json:\"frameId,omitempty,omitzero\"` // Identifies the frame that field belongs to.\n\tCard    *CreditCard       `json:\"card\"`                       // Credit card information to fill out the form. Credit card data is not saved.\n}\n\n// Trigger trigger autofill on a form identified by the fieldId. If the field\n// and related form cannot be autofilled, returns an error.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#method-trigger\n//\n// parameters:\n//\n//\tfieldID - Identifies a field that serves as an anchor for autofill.\n//\tcard - Credit card information to fill out the form. Credit card data is not saved.\nfunc Trigger(fieldID cdp.BackendNodeID, card *CreditCard) *TriggerParams {\n\treturn &TriggerParams{\n\t\tFieldID: fieldID,\n\t\tCard:    card,\n\t}\n}\n\n// WithFrameID identifies the frame that field belongs to.\nfunc (p TriggerParams) WithFrameID(frameID cdp.FrameID) *TriggerParams {\n\tp.FrameID = frameID\n\treturn &p\n}\n\n// Do executes Autofill.trigger against the provided context.\nfunc (p *TriggerParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTrigger, p, nil)\n}\n\n// SetAddressesParams set addresses so that developers can verify their forms\n// implementation.\ntype SetAddressesParams struct {\n\tAddresses []*Address `json:\"addresses\"`\n}\n\n// SetAddresses set addresses so that developers can verify their forms\n// implementation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#method-setAddresses\n//\n// parameters:\n//\n//\taddresses\nfunc SetAddresses(addresses []*Address) *SetAddressesParams {\n\treturn &SetAddressesParams{\n\t\tAddresses: addresses,\n\t}\n}\n\n// Do executes Autofill.setAddresses against the provided context.\nfunc (p *SetAddressesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAddresses, p, nil)\n}\n\n// DisableParams disables autofill domain notifications.\ntype DisableParams struct{}\n\n// Disable disables autofill domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Autofill.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables autofill domain notifications.\ntype EnableParams struct{}\n\n// Enable enables autofill domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Autofill.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// Command names.\nconst (\n\tCommandTrigger      = \"Autofill.trigger\"\n\tCommandSetAddresses = \"Autofill.setAddresses\"\n\tCommandDisable      = \"Autofill.disable\"\n\tCommandEnable       = \"Autofill.enable\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/autofill/events.go",
    "content": "package autofill\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventAddressFormFilled emitted when an address form is filled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#event-addressFormFilled\ntype EventAddressFormFilled struct {\n\tFilledFields []*FilledField `json:\"filledFields\"` // Information about the fields that were filled\n\tAddressUI    *AddressUI     `json:\"addressUi\"`    // An UI representation of the address used to fill the form. Consists of a 2D array where each child represents an address/profile line.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/autofill/types.go",
    "content": "package autofill\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// CreditCard [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#type-CreditCard\ntype CreditCard struct {\n\tNumber      string `json:\"number\"`      // 16-digit credit card number.\n\tName        string `json:\"name\"`        // Name of the credit card owner.\n\tExpiryMonth string `json:\"expiryMonth\"` // 2-digit expiry month.\n\tExpiryYear  string `json:\"expiryYear\"`  // 4-digit expiry year.\n\tCvc         string `json:\"cvc\"`         // 3-digit card verification code.\n}\n\n// AddressField [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#type-AddressField\ntype AddressField struct {\n\tName  string `json:\"name\"`  // address field name, for example GIVEN_NAME.\n\tValue string `json:\"value\"` // address field value, for example Jon Doe.\n}\n\n// AddressFields a list of address fields.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#type-AddressFields\ntype AddressFields struct {\n\tFields []*AddressField `json:\"fields\"`\n}\n\n// Address [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#type-Address\ntype Address struct {\n\tFields []*AddressField `json:\"fields\"` // fields and values defining an address.\n}\n\n// AddressUI defines how an address can be displayed like in\n// chrome://settings/addresses. Address UI is a two dimensional array, each\n// inner array is an \"address information line\", and when rendered in a UI\n// surface should be displayed as such. The following address UI for instance:\n// [[{name: \"GIVE_NAME\", value: \"Jon\"}, {name: \"FAMILY_NAME\", value: \"Doe\"}],\n// [{name: \"CITY\", value: \"Munich\"}, {name: \"ZIP\", value: \"81456\"}]] should\n// allow the receiver to render: Jon Doe Munich 81456.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#type-AddressUI\ntype AddressUI struct {\n\tAddressFields []*AddressFields `json:\"addressFields\"` // A two dimension array containing the representation of values from an address profile.\n}\n\n// FillingStrategy specified whether a filled field was done so by using the\n// html autocomplete attribute or autofill heuristics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#type-FillingStrategy\ntype FillingStrategy string\n\n// String returns the FillingStrategy as string value.\nfunc (t FillingStrategy) String() string {\n\treturn string(t)\n}\n\n// FillingStrategy values.\nconst (\n\tFillingStrategyAutocompleteAttribute FillingStrategy = \"autocompleteAttribute\"\n\tFillingStrategyAutofillInferred      FillingStrategy = \"autofillInferred\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *FillingStrategy) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch FillingStrategy(s) {\n\tcase FillingStrategyAutocompleteAttribute:\n\t\t*t = FillingStrategyAutocompleteAttribute\n\tcase FillingStrategyAutofillInferred:\n\t\t*t = FillingStrategyAutofillInferred\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown FillingStrategy value: %v\", s)\n\t}\n\treturn nil\n}\n\n// FilledField [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Autofill#type-FilledField\ntype FilledField struct {\n\tHTMLType        string            `json:\"htmlType\"`        // The type of the field, e.g text, password etc.\n\tID              string            `json:\"id\"`              // the html id\n\tName            string            `json:\"name\"`            // the html name\n\tValue           string            `json:\"value\"`           // the field value\n\tAutofillType    string            `json:\"autofillType\"`    // The actual field type, e.g FAMILY_NAME\n\tFillingStrategy FillingStrategy   `json:\"fillingStrategy\"` // The filling strategy\n\tFrameID         cdp.FrameID       `json:\"frameId\"`         // The frame the field belongs to\n\tFieldID         cdp.BackendNodeID `json:\"fieldId\"`         // The form field's DOM node\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/backgroundservice/backgroundservice.go",
    "content": "// Package backgroundservice provides the Chrome DevTools Protocol\n// commands, types, and events for the BackgroundService domain.\n//\n// Defines events for background web platform features.\n//\n// Generated by the cdproto-gen command.\npackage backgroundservice\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// StartObservingParams enables event updates for the service.\ntype StartObservingParams struct {\n\tService ServiceName `json:\"service\"`\n}\n\n// StartObserving enables event updates for the service.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#method-startObserving\n//\n// parameters:\n//\n//\tservice\nfunc StartObserving(service ServiceName) *StartObservingParams {\n\treturn &StartObservingParams{\n\t\tService: service,\n\t}\n}\n\n// Do executes BackgroundService.startObserving against the provided context.\nfunc (p *StartObservingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartObserving, p, nil)\n}\n\n// StopObservingParams disables event updates for the service.\ntype StopObservingParams struct {\n\tService ServiceName `json:\"service\"`\n}\n\n// StopObserving disables event updates for the service.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#method-stopObserving\n//\n// parameters:\n//\n//\tservice\nfunc StopObserving(service ServiceName) *StopObservingParams {\n\treturn &StopObservingParams{\n\t\tService: service,\n\t}\n}\n\n// Do executes BackgroundService.stopObserving against the provided context.\nfunc (p *StopObservingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopObserving, p, nil)\n}\n\n// SetRecordingParams set the recording state for the service.\ntype SetRecordingParams struct {\n\tShouldRecord bool        `json:\"shouldRecord\"`\n\tService      ServiceName `json:\"service\"`\n}\n\n// SetRecording set the recording state for the service.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#method-setRecording\n//\n// parameters:\n//\n//\tshouldRecord\n//\tservice\nfunc SetRecording(shouldRecord bool, service ServiceName) *SetRecordingParams {\n\treturn &SetRecordingParams{\n\t\tShouldRecord: shouldRecord,\n\t\tService:      service,\n\t}\n}\n\n// Do executes BackgroundService.setRecording against the provided context.\nfunc (p *SetRecordingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetRecording, p, nil)\n}\n\n// ClearEventsParams clears all stored data for the service.\ntype ClearEventsParams struct {\n\tService ServiceName `json:\"service\"`\n}\n\n// ClearEvents clears all stored data for the service.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#method-clearEvents\n//\n// parameters:\n//\n//\tservice\nfunc ClearEvents(service ServiceName) *ClearEventsParams {\n\treturn &ClearEventsParams{\n\t\tService: service,\n\t}\n}\n\n// Do executes BackgroundService.clearEvents against the provided context.\nfunc (p *ClearEventsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearEvents, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandStartObserving = \"BackgroundService.startObserving\"\n\tCommandStopObserving  = \"BackgroundService.stopObserving\"\n\tCommandSetRecording   = \"BackgroundService.setRecording\"\n\tCommandClearEvents    = \"BackgroundService.clearEvents\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/backgroundservice/events.go",
    "content": "package backgroundservice\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventRecordingStateChanged called when the recording state for the service\n// has been updated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#event-recordingStateChanged\ntype EventRecordingStateChanged struct {\n\tIsRecording bool        `json:\"isRecording\"`\n\tService     ServiceName `json:\"service\"`\n}\n\n// EventBackgroundServiceEventReceived called with all existing\n// backgroundServiceEvents when enabled, and all new events afterwards if\n// enabled and recording.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#event-backgroundServiceEventReceived\ntype EventBackgroundServiceEventReceived struct {\n\tBackgroundServiceEvent *Event `json:\"backgroundServiceEvent\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/backgroundservice/types.go",
    "content": "package backgroundservice\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/serviceworker\"\n)\n\n// ServiceName the Background Service that will be associated with the\n// commands/events. Every Background Service operates independently, but they\n// share the same API.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#type-ServiceName\ntype ServiceName string\n\n// String returns the ServiceName as string value.\nfunc (t ServiceName) String() string {\n\treturn string(t)\n}\n\n// ServiceName values.\nconst (\n\tServiceNameBackgroundFetch        ServiceName = \"backgroundFetch\"\n\tServiceNameBackgroundSync         ServiceName = \"backgroundSync\"\n\tServiceNamePushMessaging          ServiceName = \"pushMessaging\"\n\tServiceNameNotifications          ServiceName = \"notifications\"\n\tServiceNamePaymentHandler         ServiceName = \"paymentHandler\"\n\tServiceNamePeriodicBackgroundSync ServiceName = \"periodicBackgroundSync\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ServiceName) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ServiceName(s) {\n\tcase ServiceNameBackgroundFetch:\n\t\t*t = ServiceNameBackgroundFetch\n\tcase ServiceNameBackgroundSync:\n\t\t*t = ServiceNameBackgroundSync\n\tcase ServiceNamePushMessaging:\n\t\t*t = ServiceNamePushMessaging\n\tcase ServiceNameNotifications:\n\t\t*t = ServiceNameNotifications\n\tcase ServiceNamePaymentHandler:\n\t\t*t = ServiceNamePaymentHandler\n\tcase ServiceNamePeriodicBackgroundSync:\n\t\t*t = ServiceNamePeriodicBackgroundSync\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ServiceName value: %v\", s)\n\t}\n\treturn nil\n}\n\n// EventMetadata a key-value pair for additional event information to pass\n// along.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#type-EventMetadata\ntype EventMetadata struct {\n\tKey   string `json:\"key\"`\n\tValue string `json:\"value\"`\n}\n\n// Event [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BackgroundService#type-BackgroundServiceEvent\ntype Event struct {\n\tTimestamp                   *cdp.TimeSinceEpoch          `json:\"timestamp\"`                   // Timestamp of the event (in seconds).\n\tOrigin                      string                       `json:\"origin\"`                      // The origin this event belongs to.\n\tServiceWorkerRegistrationID serviceworker.RegistrationID `json:\"serviceWorkerRegistrationId\"` // The Service Worker ID that initiated the event.\n\tService                     ServiceName                  `json:\"service\"`                     // The Background Service this event belongs to.\n\tEventName                   string                       `json:\"eventName\"`                   // A description of the event.\n\tInstanceID                  string                       `json:\"instanceId\"`                  // An identifier that groups related events together.\n\tEventMetadata               []*EventMetadata             `json:\"eventMetadata\"`               // A list of event-specific information.\n\tStorageKey                  string                       `json:\"storageKey\"`                  // Storage key this event belongs to.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/bluetoothemulation/bluetoothemulation.go",
    "content": "// Package bluetoothemulation provides the Chrome DevTools Protocol\n// commands, types, and events for the BluetoothEmulation domain.\n//\n// This domain allows configuring virtual Bluetooth devices to test the\n// web-bluetooth API.\n//\n// Generated by the cdproto-gen command.\npackage bluetoothemulation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams enable the BluetoothEmulation domain.\ntype EnableParams struct {\n\tState       CentralState `json:\"state\"`       // State of the simulated central.\n\tLeSupported bool         `json:\"leSupported\"` // If the simulated central supports low-energy.\n}\n\n// Enable enable the BluetoothEmulation domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-enable\n//\n// parameters:\n//\n//\tstate - State of the simulated central.\n//\tleSupported - If the simulated central supports low-energy.\nfunc Enable(state CentralState, leSupported bool) *EnableParams {\n\treturn &EnableParams{\n\t\tState:       state,\n\t\tLeSupported: leSupported,\n\t}\n}\n\n// Do executes BluetoothEmulation.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// SetSimulatedCentralStateParams set the state of the simulated central.\ntype SetSimulatedCentralStateParams struct {\n\tState CentralState `json:\"state\"` // State of the simulated central.\n}\n\n// SetSimulatedCentralState set the state of the simulated central.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-setSimulatedCentralState\n//\n// parameters:\n//\n//\tstate - State of the simulated central.\nfunc SetSimulatedCentralState(state CentralState) *SetSimulatedCentralStateParams {\n\treturn &SetSimulatedCentralStateParams{\n\t\tState: state,\n\t}\n}\n\n// Do executes BluetoothEmulation.setSimulatedCentralState against the provided context.\nfunc (p *SetSimulatedCentralStateParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSimulatedCentralState, p, nil)\n}\n\n// DisableParams disable the BluetoothEmulation domain.\ntype DisableParams struct{}\n\n// Disable disable the BluetoothEmulation domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes BluetoothEmulation.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// SimulatePreconnectedPeripheralParams simulates a peripheral with\n// |address|, |name| and |knownServiceUuids| that has already been connected to\n// the system.\ntype SimulatePreconnectedPeripheralParams struct {\n\tAddress           string              `json:\"address\"`\n\tName              string              `json:\"name\"`\n\tManufacturerData  []*ManufacturerData `json:\"manufacturerData\"`\n\tKnownServiceUUIDs []string            `json:\"knownServiceUuids\"`\n}\n\n// SimulatePreconnectedPeripheral simulates a peripheral with |address|,\n// |name| and |knownServiceUuids| that has already been connected to the system.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-simulatePreconnectedPeripheral\n//\n// parameters:\n//\n//\taddress\n//\tname\n//\tmanufacturerData\n//\tknownServiceUUIDs\nfunc SimulatePreconnectedPeripheral(address string, name string, manufacturerData []*ManufacturerData, knownServiceUUIDs []string) *SimulatePreconnectedPeripheralParams {\n\treturn &SimulatePreconnectedPeripheralParams{\n\t\tAddress:           address,\n\t\tName:              name,\n\t\tManufacturerData:  manufacturerData,\n\t\tKnownServiceUUIDs: knownServiceUUIDs,\n\t}\n}\n\n// Do executes BluetoothEmulation.simulatePreconnectedPeripheral against the provided context.\nfunc (p *SimulatePreconnectedPeripheralParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSimulatePreconnectedPeripheral, p, nil)\n}\n\n// SimulateAdvertisementParams simulates an advertisement packet described in\n// |entry| being received by the central.\ntype SimulateAdvertisementParams struct {\n\tEntry *ScanEntry `json:\"entry\"`\n}\n\n// SimulateAdvertisement simulates an advertisement packet described in\n// |entry| being received by the central.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-simulateAdvertisement\n//\n// parameters:\n//\n//\tentry\nfunc SimulateAdvertisement(entry *ScanEntry) *SimulateAdvertisementParams {\n\treturn &SimulateAdvertisementParams{\n\t\tEntry: entry,\n\t}\n}\n\n// Do executes BluetoothEmulation.simulateAdvertisement against the provided context.\nfunc (p *SimulateAdvertisementParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSimulateAdvertisement, p, nil)\n}\n\n// SimulateGATTOperationResponseParams simulates the response code from the\n// peripheral with |address| for a GATT operation of |type|. The |code| value\n// follows the HCI Error Codes from Bluetooth Core Specification Vol 2 Part D\n// 1.3 List Of Error Codes.\ntype SimulateGATTOperationResponseParams struct {\n\tAddress string            `json:\"address\"`\n\tType    GATTOperationType `json:\"type\"`\n\tCode    int64             `json:\"code\"`\n}\n\n// SimulateGATTOperationResponse simulates the response code from the\n// peripheral with |address| for a GATT operation of |type|. The |code| value\n// follows the HCI Error Codes from Bluetooth Core Specification Vol 2 Part D\n// 1.3 List Of Error Codes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-simulateGATTOperationResponse\n//\n// parameters:\n//\n//\taddress\n//\ttype\n//\tcode\nfunc SimulateGATTOperationResponse(address string, typeVal GATTOperationType, code int64) *SimulateGATTOperationResponseParams {\n\treturn &SimulateGATTOperationResponseParams{\n\t\tAddress: address,\n\t\tType:    typeVal,\n\t\tCode:    code,\n\t}\n}\n\n// Do executes BluetoothEmulation.simulateGATTOperationResponse against the provided context.\nfunc (p *SimulateGATTOperationResponseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSimulateGATTOperationResponse, p, nil)\n}\n\n// SimulateCharacteristicOperationResponseParams simulates the response from\n// the characteristic with |characteristicId| for a characteristic operation of\n// |type|. The |code| value follows the Error Codes from Bluetooth Core\n// Specification Vol 3 Part F 3.4.1.1 Error Response. The |data| is expected to\n// exist when simulating a successful read operation response.\ntype SimulateCharacteristicOperationResponseParams struct {\n\tCharacteristicID string                      `json:\"characteristicId\"`\n\tType             CharacteristicOperationType `json:\"type\"`\n\tCode             int64                       `json:\"code\"`\n\tData             string                      `json:\"data,omitempty,omitzero\"`\n}\n\n// SimulateCharacteristicOperationResponse simulates the response from the\n// characteristic with |characteristicId| for a characteristic operation of\n// |type|. The |code| value follows the Error Codes from Bluetooth Core\n// Specification Vol 3 Part F 3.4.1.1 Error Response. The |data| is expected to\n// exist when simulating a successful read operation response.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-simulateCharacteristicOperationResponse\n//\n// parameters:\n//\n//\tcharacteristicID\n//\ttype\n//\tcode\nfunc SimulateCharacteristicOperationResponse(characteristicID string, typeVal CharacteristicOperationType, code int64) *SimulateCharacteristicOperationResponseParams {\n\treturn &SimulateCharacteristicOperationResponseParams{\n\t\tCharacteristicID: characteristicID,\n\t\tType:             typeVal,\n\t\tCode:             code,\n\t}\n}\n\n// WithData [no description].\nfunc (p SimulateCharacteristicOperationResponseParams) WithData(data string) *SimulateCharacteristicOperationResponseParams {\n\tp.Data = data\n\treturn &p\n}\n\n// Do executes BluetoothEmulation.simulateCharacteristicOperationResponse against the provided context.\nfunc (p *SimulateCharacteristicOperationResponseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSimulateCharacteristicOperationResponse, p, nil)\n}\n\n// SimulateDescriptorOperationResponseParams simulates the response from the\n// descriptor with |descriptorId| for a descriptor operation of |type|. The\n// |code| value follows the Error Codes from Bluetooth Core Specification Vol 3\n// Part F 3.4.1.1 Error Response. The |data| is expected to exist when\n// simulating a successful read operation response.\ntype SimulateDescriptorOperationResponseParams struct {\n\tDescriptorID string                  `json:\"descriptorId\"`\n\tType         DescriptorOperationType `json:\"type\"`\n\tCode         int64                   `json:\"code\"`\n\tData         string                  `json:\"data,omitempty,omitzero\"`\n}\n\n// SimulateDescriptorOperationResponse simulates the response from the\n// descriptor with |descriptorId| for a descriptor operation of |type|. The\n// |code| value follows the Error Codes from Bluetooth Core Specification Vol 3\n// Part F 3.4.1.1 Error Response. The |data| is expected to exist when\n// simulating a successful read operation response.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-simulateDescriptorOperationResponse\n//\n// parameters:\n//\n//\tdescriptorID\n//\ttype\n//\tcode\nfunc SimulateDescriptorOperationResponse(descriptorID string, typeVal DescriptorOperationType, code int64) *SimulateDescriptorOperationResponseParams {\n\treturn &SimulateDescriptorOperationResponseParams{\n\t\tDescriptorID: descriptorID,\n\t\tType:         typeVal,\n\t\tCode:         code,\n\t}\n}\n\n// WithData [no description].\nfunc (p SimulateDescriptorOperationResponseParams) WithData(data string) *SimulateDescriptorOperationResponseParams {\n\tp.Data = data\n\treturn &p\n}\n\n// Do executes BluetoothEmulation.simulateDescriptorOperationResponse against the provided context.\nfunc (p *SimulateDescriptorOperationResponseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSimulateDescriptorOperationResponse, p, nil)\n}\n\n// AddServiceParams adds a service with |serviceUuid| to the peripheral with\n// |address|.\ntype AddServiceParams struct {\n\tAddress     string `json:\"address\"`\n\tServiceUUID string `json:\"serviceUuid\"`\n}\n\n// AddService adds a service with |serviceUuid| to the peripheral with\n// |address|.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-addService\n//\n// parameters:\n//\n//\taddress\n//\tserviceUUID\nfunc AddService(address string, serviceUUID string) *AddServiceParams {\n\treturn &AddServiceParams{\n\t\tAddress:     address,\n\t\tServiceUUID: serviceUUID,\n\t}\n}\n\n// AddServiceReturns return values.\ntype AddServiceReturns struct {\n\tServiceID string `json:\"serviceId,omitempty,omitzero\"` // An identifier that uniquely represents this service.\n}\n\n// Do executes BluetoothEmulation.addService against the provided context.\n//\n// returns:\n//\n//\tserviceID - An identifier that uniquely represents this service.\nfunc (p *AddServiceParams) Do(ctx context.Context) (serviceID string, err error) {\n\t// execute\n\tvar res AddServiceReturns\n\terr = cdp.Execute(ctx, CommandAddService, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.ServiceID, nil\n}\n\n// RemoveServiceParams removes the service respresented by |serviceId| from\n// the simulated central.\ntype RemoveServiceParams struct {\n\tServiceID string `json:\"serviceId\"`\n}\n\n// RemoveService removes the service respresented by |serviceId| from the\n// simulated central.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-removeService\n//\n// parameters:\n//\n//\tserviceID\nfunc RemoveService(serviceID string) *RemoveServiceParams {\n\treturn &RemoveServiceParams{\n\t\tServiceID: serviceID,\n\t}\n}\n\n// Do executes BluetoothEmulation.removeService against the provided context.\nfunc (p *RemoveServiceParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveService, p, nil)\n}\n\n// AddCharacteristicParams adds a characteristic with |characteristicUuid|\n// and |properties| to the service represented by |serviceId|.\ntype AddCharacteristicParams struct {\n\tServiceID          string                    `json:\"serviceId\"`\n\tCharacteristicUUID string                    `json:\"characteristicUuid\"`\n\tProperties         *CharacteristicProperties `json:\"properties\"`\n}\n\n// AddCharacteristic adds a characteristic with |characteristicUuid| and\n// |properties| to the service represented by |serviceId|.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-addCharacteristic\n//\n// parameters:\n//\n//\tserviceID\n//\tcharacteristicUUID\n//\tproperties\nfunc AddCharacteristic(serviceID string, characteristicUUID string, properties *CharacteristicProperties) *AddCharacteristicParams {\n\treturn &AddCharacteristicParams{\n\t\tServiceID:          serviceID,\n\t\tCharacteristicUUID: characteristicUUID,\n\t\tProperties:         properties,\n\t}\n}\n\n// AddCharacteristicReturns return values.\ntype AddCharacteristicReturns struct {\n\tCharacteristicID string `json:\"characteristicId,omitempty,omitzero\"` // An identifier that uniquely represents this characteristic.\n}\n\n// Do executes BluetoothEmulation.addCharacteristic against the provided context.\n//\n// returns:\n//\n//\tcharacteristicID - An identifier that uniquely represents this characteristic.\nfunc (p *AddCharacteristicParams) Do(ctx context.Context) (characteristicID string, err error) {\n\t// execute\n\tvar res AddCharacteristicReturns\n\terr = cdp.Execute(ctx, CommandAddCharacteristic, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.CharacteristicID, nil\n}\n\n// RemoveCharacteristicParams removes the characteristic respresented by\n// |characteristicId| from the simulated central.\ntype RemoveCharacteristicParams struct {\n\tCharacteristicID string `json:\"characteristicId\"`\n}\n\n// RemoveCharacteristic removes the characteristic respresented by\n// |characteristicId| from the simulated central.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-removeCharacteristic\n//\n// parameters:\n//\n//\tcharacteristicID\nfunc RemoveCharacteristic(characteristicID string) *RemoveCharacteristicParams {\n\treturn &RemoveCharacteristicParams{\n\t\tCharacteristicID: characteristicID,\n\t}\n}\n\n// Do executes BluetoothEmulation.removeCharacteristic against the provided context.\nfunc (p *RemoveCharacteristicParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveCharacteristic, p, nil)\n}\n\n// AddDescriptorParams adds a descriptor with |descriptorUuid| to the\n// characteristic respresented by |characteristicId|.\ntype AddDescriptorParams struct {\n\tCharacteristicID string `json:\"characteristicId\"`\n\tDescriptorUUID   string `json:\"descriptorUuid\"`\n}\n\n// AddDescriptor adds a descriptor with |descriptorUuid| to the\n// characteristic respresented by |characteristicId|.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-addDescriptor\n//\n// parameters:\n//\n//\tcharacteristicID\n//\tdescriptorUUID\nfunc AddDescriptor(characteristicID string, descriptorUUID string) *AddDescriptorParams {\n\treturn &AddDescriptorParams{\n\t\tCharacteristicID: characteristicID,\n\t\tDescriptorUUID:   descriptorUUID,\n\t}\n}\n\n// AddDescriptorReturns return values.\ntype AddDescriptorReturns struct {\n\tDescriptorID string `json:\"descriptorId,omitempty,omitzero\"` // An identifier that uniquely represents this descriptor.\n}\n\n// Do executes BluetoothEmulation.addDescriptor against the provided context.\n//\n// returns:\n//\n//\tdescriptorID - An identifier that uniquely represents this descriptor.\nfunc (p *AddDescriptorParams) Do(ctx context.Context) (descriptorID string, err error) {\n\t// execute\n\tvar res AddDescriptorReturns\n\terr = cdp.Execute(ctx, CommandAddDescriptor, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.DescriptorID, nil\n}\n\n// RemoveDescriptorParams removes the descriptor with |descriptorId| from the\n// simulated central.\ntype RemoveDescriptorParams struct {\n\tDescriptorID string `json:\"descriptorId\"`\n}\n\n// RemoveDescriptor removes the descriptor with |descriptorId| from the\n// simulated central.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-removeDescriptor\n//\n// parameters:\n//\n//\tdescriptorID\nfunc RemoveDescriptor(descriptorID string) *RemoveDescriptorParams {\n\treturn &RemoveDescriptorParams{\n\t\tDescriptorID: descriptorID,\n\t}\n}\n\n// Do executes BluetoothEmulation.removeDescriptor against the provided context.\nfunc (p *RemoveDescriptorParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveDescriptor, p, nil)\n}\n\n// SimulateGATTDisconnectionParams simulates a GATT disconnection from the\n// peripheral with |address|.\ntype SimulateGATTDisconnectionParams struct {\n\tAddress string `json:\"address\"`\n}\n\n// SimulateGATTDisconnection simulates a GATT disconnection from the\n// peripheral with |address|.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#method-simulateGATTDisconnection\n//\n// parameters:\n//\n//\taddress\nfunc SimulateGATTDisconnection(address string) *SimulateGATTDisconnectionParams {\n\treturn &SimulateGATTDisconnectionParams{\n\t\tAddress: address,\n\t}\n}\n\n// Do executes BluetoothEmulation.simulateGATTDisconnection against the provided context.\nfunc (p *SimulateGATTDisconnectionParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSimulateGATTDisconnection, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable                                  = \"BluetoothEmulation.enable\"\n\tCommandSetSimulatedCentralState                = \"BluetoothEmulation.setSimulatedCentralState\"\n\tCommandDisable                                 = \"BluetoothEmulation.disable\"\n\tCommandSimulatePreconnectedPeripheral          = \"BluetoothEmulation.simulatePreconnectedPeripheral\"\n\tCommandSimulateAdvertisement                   = \"BluetoothEmulation.simulateAdvertisement\"\n\tCommandSimulateGATTOperationResponse           = \"BluetoothEmulation.simulateGATTOperationResponse\"\n\tCommandSimulateCharacteristicOperationResponse = \"BluetoothEmulation.simulateCharacteristicOperationResponse\"\n\tCommandSimulateDescriptorOperationResponse     = \"BluetoothEmulation.simulateDescriptorOperationResponse\"\n\tCommandAddService                              = \"BluetoothEmulation.addService\"\n\tCommandRemoveService                           = \"BluetoothEmulation.removeService\"\n\tCommandAddCharacteristic                       = \"BluetoothEmulation.addCharacteristic\"\n\tCommandRemoveCharacteristic                    = \"BluetoothEmulation.removeCharacteristic\"\n\tCommandAddDescriptor                           = \"BluetoothEmulation.addDescriptor\"\n\tCommandRemoveDescriptor                        = \"BluetoothEmulation.removeDescriptor\"\n\tCommandSimulateGATTDisconnection               = \"BluetoothEmulation.simulateGATTDisconnection\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/bluetoothemulation/events.go",
    "content": "package bluetoothemulation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventGattOperationReceived event for when a GATT operation of |type| to\n// the peripheral with |address| happened.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#event-gattOperationReceived\ntype EventGattOperationReceived struct {\n\tAddress string            `json:\"address\"`\n\tType    GATTOperationType `json:\"type\"`\n}\n\n// EventCharacteristicOperationReceived event for when a characteristic\n// operation of |type| to the characteristic respresented by |characteristicId|\n// happened. |data| and |writeType| is expected to exist when |type| is write.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#event-characteristicOperationReceived\ntype EventCharacteristicOperationReceived struct {\n\tCharacteristicID string                      `json:\"characteristicId\"`\n\tType             CharacteristicOperationType `json:\"type\"`\n\tData             string                      `json:\"data,omitempty,omitzero\"`\n\tWriteType        CharacteristicWriteType     `json:\"writeType,omitempty,omitzero\"`\n}\n\n// EventDescriptorOperationReceived event for when a descriptor operation of\n// |type| to the descriptor respresented by |descriptorId| happened. |data| is\n// expected to exist when |type| is write.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#event-descriptorOperationReceived\ntype EventDescriptorOperationReceived struct {\n\tDescriptorID string                  `json:\"descriptorId\"`\n\tType         DescriptorOperationType `json:\"type\"`\n\tData         string                  `json:\"data,omitempty,omitzero\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/bluetoothemulation/types.go",
    "content": "package bluetoothemulation\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// CentralState indicates the various states of Central.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-CentralState\ntype CentralState string\n\n// String returns the CentralState as string value.\nfunc (t CentralState) String() string {\n\treturn string(t)\n}\n\n// CentralState values.\nconst (\n\tCentralStateAbsent     CentralState = \"absent\"\n\tCentralStatePoweredOff CentralState = \"powered-off\"\n\tCentralStatePoweredOn  CentralState = \"powered-on\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CentralState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CentralState(s) {\n\tcase CentralStateAbsent:\n\t\t*t = CentralStateAbsent\n\tcase CentralStatePoweredOff:\n\t\t*t = CentralStatePoweredOff\n\tcase CentralStatePoweredOn:\n\t\t*t = CentralStatePoweredOn\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CentralState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// GATTOperationType indicates the various types of GATT event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-GATTOperationType\ntype GATTOperationType string\n\n// String returns the GATTOperationType as string value.\nfunc (t GATTOperationType) String() string {\n\treturn string(t)\n}\n\n// GATTOperationType values.\nconst (\n\tGATTOperationTypeConnection GATTOperationType = \"connection\"\n\tGATTOperationTypeDiscovery  GATTOperationType = \"discovery\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *GATTOperationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch GATTOperationType(s) {\n\tcase GATTOperationTypeConnection:\n\t\t*t = GATTOperationTypeConnection\n\tcase GATTOperationTypeDiscovery:\n\t\t*t = GATTOperationTypeDiscovery\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown GATTOperationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CharacteristicWriteType indicates the various types of characteristic\n// write.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-CharacteristicWriteType\ntype CharacteristicWriteType string\n\n// String returns the CharacteristicWriteType as string value.\nfunc (t CharacteristicWriteType) String() string {\n\treturn string(t)\n}\n\n// CharacteristicWriteType values.\nconst (\n\tCharacteristicWriteTypeWriteDefaultDeprecated CharacteristicWriteType = \"write-default-deprecated\"\n\tCharacteristicWriteTypeWriteWithResponse      CharacteristicWriteType = \"write-with-response\"\n\tCharacteristicWriteTypeWriteWithoutResponse   CharacteristicWriteType = \"write-without-response\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CharacteristicWriteType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CharacteristicWriteType(s) {\n\tcase CharacteristicWriteTypeWriteDefaultDeprecated:\n\t\t*t = CharacteristicWriteTypeWriteDefaultDeprecated\n\tcase CharacteristicWriteTypeWriteWithResponse:\n\t\t*t = CharacteristicWriteTypeWriteWithResponse\n\tcase CharacteristicWriteTypeWriteWithoutResponse:\n\t\t*t = CharacteristicWriteTypeWriteWithoutResponse\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CharacteristicWriteType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CharacteristicOperationType indicates the various types of characteristic\n// operation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-CharacteristicOperationType\ntype CharacteristicOperationType string\n\n// String returns the CharacteristicOperationType as string value.\nfunc (t CharacteristicOperationType) String() string {\n\treturn string(t)\n}\n\n// CharacteristicOperationType values.\nconst (\n\tCharacteristicOperationTypeRead                         CharacteristicOperationType = \"read\"\n\tCharacteristicOperationTypeWrite                        CharacteristicOperationType = \"write\"\n\tCharacteristicOperationTypeSubscribeToNotifications     CharacteristicOperationType = \"subscribe-to-notifications\"\n\tCharacteristicOperationTypeUnsubscribeFromNotifications CharacteristicOperationType = \"unsubscribe-from-notifications\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CharacteristicOperationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CharacteristicOperationType(s) {\n\tcase CharacteristicOperationTypeRead:\n\t\t*t = CharacteristicOperationTypeRead\n\tcase CharacteristicOperationTypeWrite:\n\t\t*t = CharacteristicOperationTypeWrite\n\tcase CharacteristicOperationTypeSubscribeToNotifications:\n\t\t*t = CharacteristicOperationTypeSubscribeToNotifications\n\tcase CharacteristicOperationTypeUnsubscribeFromNotifications:\n\t\t*t = CharacteristicOperationTypeUnsubscribeFromNotifications\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CharacteristicOperationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DescriptorOperationType indicates the various types of descriptor\n// operation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-DescriptorOperationType\ntype DescriptorOperationType string\n\n// String returns the DescriptorOperationType as string value.\nfunc (t DescriptorOperationType) String() string {\n\treturn string(t)\n}\n\n// DescriptorOperationType values.\nconst (\n\tDescriptorOperationTypeRead  DescriptorOperationType = \"read\"\n\tDescriptorOperationTypeWrite DescriptorOperationType = \"write\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DescriptorOperationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DescriptorOperationType(s) {\n\tcase DescriptorOperationTypeRead:\n\t\t*t = DescriptorOperationTypeRead\n\tcase DescriptorOperationTypeWrite:\n\t\t*t = DescriptorOperationTypeWrite\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DescriptorOperationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ManufacturerData stores the manufacturer data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-ManufacturerData\ntype ManufacturerData struct {\n\tKey  int64  `json:\"key\"`  // Company identifier https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/company_identifiers/company_identifiers.yaml https://usb.org/developers\n\tData string `json:\"data\"` // Manufacturer-specific data\n}\n\n// ScanRecord stores the byte data of the advertisement packet sent by a\n// Bluetooth device.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-ScanRecord\ntype ScanRecord struct {\n\tName             string              `json:\"name,omitempty,omitzero\"`\n\tUUIDs            []string            `json:\"uuids,omitempty,omitzero\"`\n\tAppearance       int64               `json:\"appearance,omitempty,omitzero\"`       // Stores the external appearance description of the device.\n\tTxPower          int64               `json:\"txPower,omitempty,omitzero\"`          // Stores the transmission power of a broadcasting device.\n\tManufacturerData []*ManufacturerData `json:\"manufacturerData,omitempty,omitzero\"` // Key is the company identifier and the value is an array of bytes of manufacturer specific data.\n}\n\n// ScanEntry stores the advertisement packet information that is sent by a\n// Bluetooth device.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-ScanEntry\ntype ScanEntry struct {\n\tDeviceAddress string      `json:\"deviceAddress\"`\n\tRssi          int64       `json:\"rssi\"`\n\tScanRecord    *ScanRecord `json:\"scanRecord\"`\n}\n\n// CharacteristicProperties describes the properties of a characteristic.\n// This follows Bluetooth Core Specification BT 4.2 Vol 3 Part G 3.3.1.\n// Characteristic Properties.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/BluetoothEmulation#type-CharacteristicProperties\ntype CharacteristicProperties struct {\n\tBroadcast                 bool `json:\"broadcast\"`\n\tRead                      bool `json:\"read\"`\n\tWriteWithoutResponse      bool `json:\"writeWithoutResponse\"`\n\tWrite                     bool `json:\"write\"`\n\tNotify                    bool `json:\"notify\"`\n\tIndicate                  bool `json:\"indicate\"`\n\tAuthenticatedSignedWrites bool `json:\"authenticatedSignedWrites\"`\n\tExtendedProperties        bool `json:\"extendedProperties\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/browser/browser.go",
    "content": "// Package browser provides the Chrome DevTools Protocol\n// commands, types, and events for the Browser domain.\n//\n// The Browser domain defines methods and events for browser managing.\n//\n// Generated by the cdproto-gen command.\npackage browser\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/target\"\n)\n\n// SetPermissionParams set permission settings for given origin.\ntype SetPermissionParams struct {\n\tPermission       *PermissionDescriptor `json:\"permission\"`                          // Descriptor of permission to override.\n\tSetting          PermissionSetting     `json:\"setting\"`                             // Setting of the permission.\n\tOrigin           string                `json:\"origin,omitempty,omitzero\"`           // Origin the permission applies to, all origins if not specified.\n\tBrowserContextID cdp.BrowserContextID  `json:\"browserContextId,omitempty,omitzero\"` // Context to override. When omitted, default browser context is used.\n}\n\n// SetPermission set permission settings for given origin.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-setPermission\n//\n// parameters:\n//\n//\tpermission - Descriptor of permission to override.\n//\tsetting - Setting of the permission.\nfunc SetPermission(permission *PermissionDescriptor, setting PermissionSetting) *SetPermissionParams {\n\treturn &SetPermissionParams{\n\t\tPermission: permission,\n\t\tSetting:    setting,\n\t}\n}\n\n// WithOrigin origin the permission applies to, all origins if not specified.\nfunc (p SetPermissionParams) WithOrigin(origin string) *SetPermissionParams {\n\tp.Origin = origin\n\treturn &p\n}\n\n// WithBrowserContextID context to override. When omitted, default browser\n// context is used.\nfunc (p SetPermissionParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *SetPermissionParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// Do executes Browser.setPermission against the provided context.\nfunc (p *SetPermissionParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPermission, p, nil)\n}\n\n// GrantPermissionsParams grant specific permissions to the given origin and\n// reject all others.\ntype GrantPermissionsParams struct {\n\tPermissions      []PermissionType     `json:\"permissions\"`\n\tOrigin           string               `json:\"origin,omitempty,omitzero\"`           // Origin the permission applies to, all origins if not specified.\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // BrowserContext to override permissions. When omitted, default browser context is used.\n}\n\n// GrantPermissions grant specific permissions to the given origin and reject\n// all others.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-grantPermissions\n//\n// parameters:\n//\n//\tpermissions\nfunc GrantPermissions(permissions []PermissionType) *GrantPermissionsParams {\n\treturn &GrantPermissionsParams{\n\t\tPermissions: permissions,\n\t}\n}\n\n// WithOrigin origin the permission applies to, all origins if not specified.\nfunc (p GrantPermissionsParams) WithOrigin(origin string) *GrantPermissionsParams {\n\tp.Origin = origin\n\treturn &p\n}\n\n// WithBrowserContextID browserContext to override permissions. When omitted,\n// default browser context is used.\nfunc (p GrantPermissionsParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *GrantPermissionsParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// Do executes Browser.grantPermissions against the provided context.\nfunc (p *GrantPermissionsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandGrantPermissions, p, nil)\n}\n\n// ResetPermissionsParams reset all permission management for all origins.\ntype ResetPermissionsParams struct {\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // BrowserContext to reset permissions. When omitted, default browser context is used.\n}\n\n// ResetPermissions reset all permission management for all origins.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-resetPermissions\n//\n// parameters:\nfunc ResetPermissions() *ResetPermissionsParams {\n\treturn &ResetPermissionsParams{}\n}\n\n// WithBrowserContextID browserContext to reset permissions. When omitted,\n// default browser context is used.\nfunc (p ResetPermissionsParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *ResetPermissionsParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// Do executes Browser.resetPermissions against the provided context.\nfunc (p *ResetPermissionsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandResetPermissions, p, nil)\n}\n\n// SetDownloadBehaviorParams set the behavior when downloading a file.\ntype SetDownloadBehaviorParams struct {\n\tBehavior         SetDownloadBehaviorBehavior `json:\"behavior\"`                            // Whether to allow all or deny all download requests, or use default Chrome behavior if available (otherwise deny). |allowAndName| allows download and names files according to their download guids.\n\tBrowserContextID cdp.BrowserContextID        `json:\"browserContextId,omitempty,omitzero\"` // BrowserContext to set download behavior. When omitted, default browser context is used.\n\tDownloadPath     string                      `json:\"downloadPath,omitempty,omitzero\"`     // The default path to save downloaded files to. This is required if behavior is set to 'allow' or 'allowAndName'.\n\tEventsEnabled    bool                        `json:\"eventsEnabled\"`                       // Whether to emit download events (defaults to false).\n}\n\n// SetDownloadBehavior set the behavior when downloading a file.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-setDownloadBehavior\n//\n// parameters:\n//\n//\tbehavior - Whether to allow all or deny all download requests, or use default Chrome behavior if available (otherwise deny). |allowAndName| allows download and names files according to their download guids.\nfunc SetDownloadBehavior(behavior SetDownloadBehaviorBehavior) *SetDownloadBehaviorParams {\n\treturn &SetDownloadBehaviorParams{\n\t\tBehavior:      behavior,\n\t\tEventsEnabled: false,\n\t}\n}\n\n// WithBrowserContextID browserContext to set download behavior. When\n// omitted, default browser context is used.\nfunc (p SetDownloadBehaviorParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *SetDownloadBehaviorParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// WithDownloadPath the default path to save downloaded files to. This is\n// required if behavior is set to 'allow' or 'allowAndName'.\nfunc (p SetDownloadBehaviorParams) WithDownloadPath(downloadPath string) *SetDownloadBehaviorParams {\n\tp.DownloadPath = downloadPath\n\treturn &p\n}\n\n// WithEventsEnabled whether to emit download events (defaults to false).\nfunc (p SetDownloadBehaviorParams) WithEventsEnabled(eventsEnabled bool) *SetDownloadBehaviorParams {\n\tp.EventsEnabled = eventsEnabled\n\treturn &p\n}\n\n// Do executes Browser.setDownloadBehavior against the provided context.\nfunc (p *SetDownloadBehaviorParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDownloadBehavior, p, nil)\n}\n\n// CancelDownloadParams cancel a download if in progress.\ntype CancelDownloadParams struct {\n\tGUID             string               `json:\"guid\"`                                // Global unique identifier of the download.\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // BrowserContext to perform the action in. When omitted, default browser context is used.\n}\n\n// CancelDownload cancel a download if in progress.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-cancelDownload\n//\n// parameters:\n//\n//\tguid - Global unique identifier of the download.\nfunc CancelDownload(guid string) *CancelDownloadParams {\n\treturn &CancelDownloadParams{\n\t\tGUID: guid,\n\t}\n}\n\n// WithBrowserContextID browserContext to perform the action in. When\n// omitted, default browser context is used.\nfunc (p CancelDownloadParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *CancelDownloadParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// Do executes Browser.cancelDownload against the provided context.\nfunc (p *CancelDownloadParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCancelDownload, p, nil)\n}\n\n// CloseParams close browser gracefully.\ntype CloseParams struct{}\n\n// Close close browser gracefully.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-close\nfunc Close() *CloseParams {\n\treturn &CloseParams{}\n}\n\n// Do executes Browser.close against the provided context.\nfunc (p *CloseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClose, nil, nil)\n}\n\n// CrashParams crashes browser on the main thread.\ntype CrashParams struct{}\n\n// Crash crashes browser on the main thread.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-crash\nfunc Crash() *CrashParams {\n\treturn &CrashParams{}\n}\n\n// Do executes Browser.crash against the provided context.\nfunc (p *CrashParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCrash, nil, nil)\n}\n\n// CrashGPUProcessParams crashes GPU process.\ntype CrashGPUProcessParams struct{}\n\n// CrashGPUProcess crashes GPU process.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-crashGpuProcess\nfunc CrashGPUProcess() *CrashGPUProcessParams {\n\treturn &CrashGPUProcessParams{}\n}\n\n// Do executes Browser.crashGpuProcess against the provided context.\nfunc (p *CrashGPUProcessParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCrashGPUProcess, nil, nil)\n}\n\n// GetVersionParams returns version information.\ntype GetVersionParams struct{}\n\n// GetVersion returns version information.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-getVersion\nfunc GetVersion() *GetVersionParams {\n\treturn &GetVersionParams{}\n}\n\n// GetVersionReturns return values.\ntype GetVersionReturns struct {\n\tProtocolVersion string `json:\"protocolVersion,omitempty,omitzero\"` // Protocol version.\n\tProduct         string `json:\"product,omitempty,omitzero\"`         // Product name.\n\tRevision        string `json:\"revision,omitempty,omitzero\"`        // Product revision.\n\tUserAgent       string `json:\"userAgent,omitempty,omitzero\"`       // User-Agent.\n\tJsVersion       string `json:\"jsVersion,omitempty,omitzero\"`       // V8 version.\n}\n\n// Do executes Browser.getVersion against the provided context.\n//\n// returns:\n//\n//\tprotocolVersion - Protocol version.\n//\tproduct - Product name.\n//\trevision - Product revision.\n//\tuserAgent - User-Agent.\n//\tjsVersion - V8 version.\nfunc (p *GetVersionParams) Do(ctx context.Context) (protocolVersion string, product string, revision string, userAgent string, jsVersion string, err error) {\n\t// execute\n\tvar res GetVersionReturns\n\terr = cdp.Execute(ctx, CommandGetVersion, nil, &res)\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", \"\", \"\", err\n\t}\n\n\treturn res.ProtocolVersion, res.Product, res.Revision, res.UserAgent, res.JsVersion, nil\n}\n\n// GetBrowserCommandLineParams returns the command line switches for the\n// browser process if, and only if --enable-automation is on the commandline.\ntype GetBrowserCommandLineParams struct{}\n\n// GetBrowserCommandLine returns the command line switches for the browser\n// process if, and only if --enable-automation is on the commandline.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-getBrowserCommandLine\nfunc GetBrowserCommandLine() *GetBrowserCommandLineParams {\n\treturn &GetBrowserCommandLineParams{}\n}\n\n// GetBrowserCommandLineReturns return values.\ntype GetBrowserCommandLineReturns struct {\n\tArguments []string `json:\"arguments,omitempty,omitzero\"` // Commandline parameters\n}\n\n// Do executes Browser.getBrowserCommandLine against the provided context.\n//\n// returns:\n//\n//\targuments - Commandline parameters\nfunc (p *GetBrowserCommandLineParams) Do(ctx context.Context) (arguments []string, err error) {\n\t// execute\n\tvar res GetBrowserCommandLineReturns\n\terr = cdp.Execute(ctx, CommandGetBrowserCommandLine, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Arguments, nil\n}\n\n// GetHistogramsParams get Chrome histograms.\ntype GetHistogramsParams struct {\n\tQuery string `json:\"query,omitempty,omitzero\"` // Requested substring in name. Only histograms which have query as a substring in their name are extracted. An empty or absent query returns all histograms.\n\tDelta bool   `json:\"delta\"`                    // If true, retrieve delta since last delta call.\n}\n\n// GetHistograms get Chrome histograms.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-getHistograms\n//\n// parameters:\nfunc GetHistograms() *GetHistogramsParams {\n\treturn &GetHistogramsParams{\n\t\tDelta: false,\n\t}\n}\n\n// WithQuery requested substring in name. Only histograms which have query as\n// a substring in their name are extracted. An empty or absent query returns all\n// histograms.\nfunc (p GetHistogramsParams) WithQuery(query string) *GetHistogramsParams {\n\tp.Query = query\n\treturn &p\n}\n\n// WithDelta if true, retrieve delta since last delta call.\nfunc (p GetHistogramsParams) WithDelta(delta bool) *GetHistogramsParams {\n\tp.Delta = delta\n\treturn &p\n}\n\n// GetHistogramsReturns return values.\ntype GetHistogramsReturns struct {\n\tHistograms []*Histogram `json:\"histograms,omitempty,omitzero\"` // Histograms.\n}\n\n// Do executes Browser.getHistograms against the provided context.\n//\n// returns:\n//\n//\thistograms - Histograms.\nfunc (p *GetHistogramsParams) Do(ctx context.Context) (histograms []*Histogram, err error) {\n\t// execute\n\tvar res GetHistogramsReturns\n\terr = cdp.Execute(ctx, CommandGetHistograms, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Histograms, nil\n}\n\n// GetHistogramParams get a Chrome histogram by name.\ntype GetHistogramParams struct {\n\tName  string `json:\"name\"`  // Requested histogram name.\n\tDelta bool   `json:\"delta\"` // If true, retrieve delta since last delta call.\n}\n\n// GetHistogram get a Chrome histogram by name.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-getHistogram\n//\n// parameters:\n//\n//\tname - Requested histogram name.\nfunc GetHistogram(name string) *GetHistogramParams {\n\treturn &GetHistogramParams{\n\t\tName:  name,\n\t\tDelta: false,\n\t}\n}\n\n// WithDelta if true, retrieve delta since last delta call.\nfunc (p GetHistogramParams) WithDelta(delta bool) *GetHistogramParams {\n\tp.Delta = delta\n\treturn &p\n}\n\n// GetHistogramReturns return values.\ntype GetHistogramReturns struct {\n\tHistogram *Histogram `json:\"histogram,omitempty,omitzero\"` // Histogram.\n}\n\n// Do executes Browser.getHistogram against the provided context.\n//\n// returns:\n//\n//\thistogram - Histogram.\nfunc (p *GetHistogramParams) Do(ctx context.Context) (histogram *Histogram, err error) {\n\t// execute\n\tvar res GetHistogramReturns\n\terr = cdp.Execute(ctx, CommandGetHistogram, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Histogram, nil\n}\n\n// GetWindowBoundsParams get position and size of the browser window.\ntype GetWindowBoundsParams struct {\n\tWindowID WindowID `json:\"windowId\"` // Browser window id.\n}\n\n// GetWindowBounds get position and size of the browser window.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-getWindowBounds\n//\n// parameters:\n//\n//\twindowID - Browser window id.\nfunc GetWindowBounds(windowID WindowID) *GetWindowBoundsParams {\n\treturn &GetWindowBoundsParams{\n\t\tWindowID: windowID,\n\t}\n}\n\n// GetWindowBoundsReturns return values.\ntype GetWindowBoundsReturns struct {\n\tBounds *Bounds `json:\"bounds,omitempty,omitzero\"` // Bounds information of the window. When window state is 'minimized', the restored window position and size are returned.\n}\n\n// Do executes Browser.getWindowBounds against the provided context.\n//\n// returns:\n//\n//\tbounds - Bounds information of the window. When window state is 'minimized', the restored window position and size are returned.\nfunc (p *GetWindowBoundsParams) Do(ctx context.Context) (bounds *Bounds, err error) {\n\t// execute\n\tvar res GetWindowBoundsReturns\n\terr = cdp.Execute(ctx, CommandGetWindowBounds, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Bounds, nil\n}\n\n// GetWindowForTargetParams get the browser window that contains the devtools\n// target.\ntype GetWindowForTargetParams struct {\n\tTargetID target.ID `json:\"targetId,omitempty,omitzero\"` // Devtools agent host id. If called as a part of the session, associated targetId is used.\n}\n\n// GetWindowForTarget get the browser window that contains the devtools\n// target.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-getWindowForTarget\n//\n// parameters:\nfunc GetWindowForTarget() *GetWindowForTargetParams {\n\treturn &GetWindowForTargetParams{}\n}\n\n// WithTargetID devtools agent host id. If called as a part of the session,\n// associated targetId is used.\nfunc (p GetWindowForTargetParams) WithTargetID(targetID target.ID) *GetWindowForTargetParams {\n\tp.TargetID = targetID\n\treturn &p\n}\n\n// GetWindowForTargetReturns return values.\ntype GetWindowForTargetReturns struct {\n\tWindowID WindowID `json:\"windowId,omitempty,omitzero\"` // Browser window id.\n\tBounds   *Bounds  `json:\"bounds,omitempty,omitzero\"`   // Bounds information of the window. When window state is 'minimized', the restored window position and size are returned.\n}\n\n// Do executes Browser.getWindowForTarget against the provided context.\n//\n// returns:\n//\n//\twindowID - Browser window id.\n//\tbounds - Bounds information of the window. When window state is 'minimized', the restored window position and size are returned.\nfunc (p *GetWindowForTargetParams) Do(ctx context.Context) (windowID WindowID, bounds *Bounds, err error) {\n\t// execute\n\tvar res GetWindowForTargetReturns\n\terr = cdp.Execute(ctx, CommandGetWindowForTarget, p, &res)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\treturn res.WindowID, res.Bounds, nil\n}\n\n// SetWindowBoundsParams set position and/or size of the browser window.\ntype SetWindowBoundsParams struct {\n\tWindowID WindowID `json:\"windowId\"` // Browser window id.\n\tBounds   *Bounds  `json:\"bounds\"`   // New window bounds. The 'minimized', 'maximized' and 'fullscreen' states cannot be combined with 'left', 'top', 'width' or 'height'. Leaves unspecified fields unchanged.\n}\n\n// SetWindowBounds set position and/or size of the browser window.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-setWindowBounds\n//\n// parameters:\n//\n//\twindowID - Browser window id.\n//\tbounds - New window bounds. The 'minimized', 'maximized' and 'fullscreen' states cannot be combined with 'left', 'top', 'width' or 'height'. Leaves unspecified fields unchanged.\nfunc SetWindowBounds(windowID WindowID, bounds *Bounds) *SetWindowBoundsParams {\n\treturn &SetWindowBoundsParams{\n\t\tWindowID: windowID,\n\t\tBounds:   bounds,\n\t}\n}\n\n// Do executes Browser.setWindowBounds against the provided context.\nfunc (p *SetWindowBoundsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetWindowBounds, p, nil)\n}\n\n// SetContentsSizeParams set size of the browser contents resizing browser\n// window as necessary.\ntype SetContentsSizeParams struct {\n\tWindowID WindowID `json:\"windowId\"`                  // Browser window id.\n\tWidth    int64    `json:\"width,omitempty,omitzero\"`  // The window contents width in DIP. Assumes current width if omitted. Must be specified if 'height' is omitted.\n\tHeight   int64    `json:\"height,omitempty,omitzero\"` // The window contents height in DIP. Assumes current height if omitted. Must be specified if 'width' is omitted.\n}\n\n// SetContentsSize set size of the browser contents resizing browser window\n// as necessary.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-setContentsSize\n//\n// parameters:\n//\n//\twindowID - Browser window id.\nfunc SetContentsSize(windowID WindowID) *SetContentsSizeParams {\n\treturn &SetContentsSizeParams{\n\t\tWindowID: windowID,\n\t}\n}\n\n// WithWidth the window contents width in DIP. Assumes current width if\n// omitted. Must be specified if 'height' is omitted.\nfunc (p SetContentsSizeParams) WithWidth(width int64) *SetContentsSizeParams {\n\tp.Width = width\n\treturn &p\n}\n\n// WithHeight the window contents height in DIP. Assumes current height if\n// omitted. Must be specified if 'width' is omitted.\nfunc (p SetContentsSizeParams) WithHeight(height int64) *SetContentsSizeParams {\n\tp.Height = height\n\treturn &p\n}\n\n// Do executes Browser.setContentsSize against the provided context.\nfunc (p *SetContentsSizeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetContentsSize, p, nil)\n}\n\n// SetDockTileParams set dock tile details, platform-specific.\ntype SetDockTileParams struct {\n\tBadgeLabel string `json:\"badgeLabel,omitempty,omitzero\"`\n\tImage      string `json:\"image,omitempty,omitzero\"` // Png encoded image.\n}\n\n// SetDockTile set dock tile details, platform-specific.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-setDockTile\n//\n// parameters:\nfunc SetDockTile() *SetDockTileParams {\n\treturn &SetDockTileParams{}\n}\n\n// WithBadgeLabel [no description].\nfunc (p SetDockTileParams) WithBadgeLabel(badgeLabel string) *SetDockTileParams {\n\tp.BadgeLabel = badgeLabel\n\treturn &p\n}\n\n// WithImage png encoded image.\nfunc (p SetDockTileParams) WithImage(image string) *SetDockTileParams {\n\tp.Image = image\n\treturn &p\n}\n\n// Do executes Browser.setDockTile against the provided context.\nfunc (p *SetDockTileParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDockTile, p, nil)\n}\n\n// ExecuteBrowserCommandParams invoke custom browser commands used by\n// telemetry.\ntype ExecuteBrowserCommandParams struct {\n\tCommandID CommandID `json:\"commandId\"`\n}\n\n// ExecuteBrowserCommand invoke custom browser commands used by telemetry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-executeBrowserCommand\n//\n// parameters:\n//\n//\tcommandID\nfunc ExecuteBrowserCommand(commandID CommandID) *ExecuteBrowserCommandParams {\n\treturn &ExecuteBrowserCommandParams{\n\t\tCommandID: commandID,\n\t}\n}\n\n// Do executes Browser.executeBrowserCommand against the provided context.\nfunc (p *ExecuteBrowserCommandParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandExecuteBrowserCommand, p, nil)\n}\n\n// AddPrivacySandboxEnrollmentOverrideParams allows a site to use privacy\n// sandbox features that require enrollment without the site actually being\n// enrolled. Only supported on page targets.\ntype AddPrivacySandboxEnrollmentOverrideParams struct {\n\tURL string `json:\"url\"`\n}\n\n// AddPrivacySandboxEnrollmentOverride allows a site to use privacy sandbox\n// features that require enrollment without the site actually being enrolled.\n// Only supported on page targets.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-addPrivacySandboxEnrollmentOverride\n//\n// parameters:\n//\n//\turl\nfunc AddPrivacySandboxEnrollmentOverride(url string) *AddPrivacySandboxEnrollmentOverrideParams {\n\treturn &AddPrivacySandboxEnrollmentOverrideParams{\n\t\tURL: url,\n\t}\n}\n\n// Do executes Browser.addPrivacySandboxEnrollmentOverride against the provided context.\nfunc (p *AddPrivacySandboxEnrollmentOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandAddPrivacySandboxEnrollmentOverride, p, nil)\n}\n\n// AddPrivacySandboxCoordinatorKeyConfigParams configures encryption keys\n// used with a given privacy sandbox API to talk to a trusted coordinator. Since\n// this is intended for test automation only, coordinatorOrigin must be a .test\n// domain. No existing coordinator configuration for the origin may exist.\ntype AddPrivacySandboxCoordinatorKeyConfigParams struct {\n\tAPI               PrivacySandboxAPI    `json:\"api\"`\n\tCoordinatorOrigin string               `json:\"coordinatorOrigin\"`\n\tKeyConfig         string               `json:\"keyConfig\"`\n\tBrowserContextID  cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // BrowserContext to perform the action in. When omitted, default browser context is used.\n}\n\n// AddPrivacySandboxCoordinatorKeyConfig configures encryption keys used with\n// a given privacy sandbox API to talk to a trusted coordinator. Since this is\n// intended for test automation only, coordinatorOrigin must be a .test domain.\n// No existing coordinator configuration for the origin may exist.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-addPrivacySandboxCoordinatorKeyConfig\n//\n// parameters:\n//\n//\tapi\n//\tcoordinatorOrigin\n//\tkeyConfig\nfunc AddPrivacySandboxCoordinatorKeyConfig(api PrivacySandboxAPI, coordinatorOrigin string, keyConfig string) *AddPrivacySandboxCoordinatorKeyConfigParams {\n\treturn &AddPrivacySandboxCoordinatorKeyConfigParams{\n\t\tAPI:               api,\n\t\tCoordinatorOrigin: coordinatorOrigin,\n\t\tKeyConfig:         keyConfig,\n\t}\n}\n\n// WithBrowserContextID browserContext to perform the action in. When\n// omitted, default browser context is used.\nfunc (p AddPrivacySandboxCoordinatorKeyConfigParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *AddPrivacySandboxCoordinatorKeyConfigParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// Do executes Browser.addPrivacySandboxCoordinatorKeyConfig against the provided context.\nfunc (p *AddPrivacySandboxCoordinatorKeyConfigParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandAddPrivacySandboxCoordinatorKeyConfig, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandSetPermission                         = \"Browser.setPermission\"\n\tCommandGrantPermissions                      = \"Browser.grantPermissions\"\n\tCommandResetPermissions                      = \"Browser.resetPermissions\"\n\tCommandSetDownloadBehavior                   = \"Browser.setDownloadBehavior\"\n\tCommandCancelDownload                        = \"Browser.cancelDownload\"\n\tCommandClose                                 = \"Browser.close\"\n\tCommandCrash                                 = \"Browser.crash\"\n\tCommandCrashGPUProcess                       = \"Browser.crashGpuProcess\"\n\tCommandGetVersion                            = \"Browser.getVersion\"\n\tCommandGetBrowserCommandLine                 = \"Browser.getBrowserCommandLine\"\n\tCommandGetHistograms                         = \"Browser.getHistograms\"\n\tCommandGetHistogram                          = \"Browser.getHistogram\"\n\tCommandGetWindowBounds                       = \"Browser.getWindowBounds\"\n\tCommandGetWindowForTarget                    = \"Browser.getWindowForTarget\"\n\tCommandSetWindowBounds                       = \"Browser.setWindowBounds\"\n\tCommandSetContentsSize                       = \"Browser.setContentsSize\"\n\tCommandSetDockTile                           = \"Browser.setDockTile\"\n\tCommandExecuteBrowserCommand                 = \"Browser.executeBrowserCommand\"\n\tCommandAddPrivacySandboxEnrollmentOverride   = \"Browser.addPrivacySandboxEnrollmentOverride\"\n\tCommandAddPrivacySandboxCoordinatorKeyConfig = \"Browser.addPrivacySandboxCoordinatorKeyConfig\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/browser/events.go",
    "content": "package browser\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EventDownloadWillBegin fired when page is about to start a download.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#event-downloadWillBegin\ntype EventDownloadWillBegin struct {\n\tFrameID           cdp.FrameID `json:\"frameId\"`           // Id of the frame that caused the download to begin.\n\tGUID              string      `json:\"guid\"`              // Global unique identifier of the download.\n\tURL               string      `json:\"url\"`               // URL of the resource being downloaded.\n\tSuggestedFilename string      `json:\"suggestedFilename\"` // Suggested file name of the resource (the actual name of the file saved on disk may differ).\n}\n\n// EventDownloadProgress fired when download makes progress. Last call has\n// |done| == true.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#event-downloadProgress\ntype EventDownloadProgress struct {\n\tGUID          string                `json:\"guid\"`                        // Global unique identifier of the download.\n\tTotalBytes    float64               `json:\"totalBytes\"`                  // Total expected bytes to download.\n\tReceivedBytes float64               `json:\"receivedBytes\"`               // Total bytes received.\n\tState         DownloadProgressState `json:\"state\"`                       // Download status.\n\tFilePath      string                `json:\"filePath,omitempty,omitzero\"` // If download is \"completed\", provides the path of the downloaded file. Depending on the platform, it is not guaranteed to be set, nor the file is guaranteed to exist.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/browser/types.go",
    "content": "package browser\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// WindowID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-WindowID\ntype WindowID int64\n\n// Int64 returns the WindowID as int64 value.\nfunc (t WindowID) Int64() int64 {\n\treturn int64(t)\n}\n\n// WindowState the state of the browser window.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-WindowState\ntype WindowState string\n\n// String returns the WindowState as string value.\nfunc (t WindowState) String() string {\n\treturn string(t)\n}\n\n// WindowState values.\nconst (\n\tWindowStateNormal     WindowState = \"normal\"\n\tWindowStateMinimized  WindowState = \"minimized\"\n\tWindowStateMaximized  WindowState = \"maximized\"\n\tWindowStateFullscreen WindowState = \"fullscreen\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *WindowState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch WindowState(s) {\n\tcase WindowStateNormal:\n\t\t*t = WindowStateNormal\n\tcase WindowStateMinimized:\n\t\t*t = WindowStateMinimized\n\tcase WindowStateMaximized:\n\t\t*t = WindowStateMaximized\n\tcase WindowStateFullscreen:\n\t\t*t = WindowStateFullscreen\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown WindowState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Bounds browser window bounds information.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-Bounds\ntype Bounds struct {\n\tLeft        int64       `json:\"left,omitempty,omitzero\"`        // The offset from the left edge of the screen to the window in pixels.\n\tTop         int64       `json:\"top,omitempty,omitzero\"`         // The offset from the top edge of the screen to the window in pixels.\n\tWidth       int64       `json:\"width,omitempty,omitzero\"`       // The window width in pixels.\n\tHeight      int64       `json:\"height,omitempty,omitzero\"`      // The window height in pixels.\n\tWindowState WindowState `json:\"windowState,omitempty,omitzero\"` // The window state. Default to normal.\n}\n\n// PermissionType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-PermissionType\ntype PermissionType string\n\n// String returns the PermissionType as string value.\nfunc (t PermissionType) String() string {\n\treturn string(t)\n}\n\n// PermissionType values.\nconst (\n\tPermissionTypeAr                       PermissionType = \"ar\"\n\tPermissionTypeAudioCapture             PermissionType = \"audioCapture\"\n\tPermissionTypeAutomaticFullscreen      PermissionType = \"automaticFullscreen\"\n\tPermissionTypeBackgroundFetch          PermissionType = \"backgroundFetch\"\n\tPermissionTypeBackgroundSync           PermissionType = \"backgroundSync\"\n\tPermissionTypeCameraPanTiltZoom        PermissionType = \"cameraPanTiltZoom\"\n\tPermissionTypeCapturedSurfaceControl   PermissionType = \"capturedSurfaceControl\"\n\tPermissionTypeClipboardReadWrite       PermissionType = \"clipboardReadWrite\"\n\tPermissionTypeClipboardSanitizedWrite  PermissionType = \"clipboardSanitizedWrite\"\n\tPermissionTypeDisplayCapture           PermissionType = \"displayCapture\"\n\tPermissionTypeDurableStorage           PermissionType = \"durableStorage\"\n\tPermissionTypeGeolocation              PermissionType = \"geolocation\"\n\tPermissionTypeHandTracking             PermissionType = \"handTracking\"\n\tPermissionTypeIdleDetection            PermissionType = \"idleDetection\"\n\tPermissionTypeKeyboardLock             PermissionType = \"keyboardLock\"\n\tPermissionTypeLocalFonts               PermissionType = \"localFonts\"\n\tPermissionTypeLocalNetworkAccess       PermissionType = \"localNetworkAccess\"\n\tPermissionTypeMidi                     PermissionType = \"midi\"\n\tPermissionTypeMidiSysex                PermissionType = \"midiSysex\"\n\tPermissionTypeNfc                      PermissionType = \"nfc\"\n\tPermissionTypeNotifications            PermissionType = \"notifications\"\n\tPermissionTypePaymentHandler           PermissionType = \"paymentHandler\"\n\tPermissionTypePeriodicBackgroundSync   PermissionType = \"periodicBackgroundSync\"\n\tPermissionTypePointerLock              PermissionType = \"pointerLock\"\n\tPermissionTypeProtectedMediaIdentifier PermissionType = \"protectedMediaIdentifier\"\n\tPermissionTypeSensors                  PermissionType = \"sensors\"\n\tPermissionTypeSmartCard                PermissionType = \"smartCard\"\n\tPermissionTypeSpeakerSelection         PermissionType = \"speakerSelection\"\n\tPermissionTypeStorageAccess            PermissionType = \"storageAccess\"\n\tPermissionTypeTopLevelStorageAccess    PermissionType = \"topLevelStorageAccess\"\n\tPermissionTypeVideoCapture             PermissionType = \"videoCapture\"\n\tPermissionTypeVr                       PermissionType = \"vr\"\n\tPermissionTypeWakeLockScreen           PermissionType = \"wakeLockScreen\"\n\tPermissionTypeWakeLockSystem           PermissionType = \"wakeLockSystem\"\n\tPermissionTypeWebAppInstallation       PermissionType = \"webAppInstallation\"\n\tPermissionTypeWebPrinting              PermissionType = \"webPrinting\"\n\tPermissionTypeWindowManagement         PermissionType = \"windowManagement\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PermissionType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PermissionType(s) {\n\tcase PermissionTypeAr:\n\t\t*t = PermissionTypeAr\n\tcase PermissionTypeAudioCapture:\n\t\t*t = PermissionTypeAudioCapture\n\tcase PermissionTypeAutomaticFullscreen:\n\t\t*t = PermissionTypeAutomaticFullscreen\n\tcase PermissionTypeBackgroundFetch:\n\t\t*t = PermissionTypeBackgroundFetch\n\tcase PermissionTypeBackgroundSync:\n\t\t*t = PermissionTypeBackgroundSync\n\tcase PermissionTypeCameraPanTiltZoom:\n\t\t*t = PermissionTypeCameraPanTiltZoom\n\tcase PermissionTypeCapturedSurfaceControl:\n\t\t*t = PermissionTypeCapturedSurfaceControl\n\tcase PermissionTypeClipboardReadWrite:\n\t\t*t = PermissionTypeClipboardReadWrite\n\tcase PermissionTypeClipboardSanitizedWrite:\n\t\t*t = PermissionTypeClipboardSanitizedWrite\n\tcase PermissionTypeDisplayCapture:\n\t\t*t = PermissionTypeDisplayCapture\n\tcase PermissionTypeDurableStorage:\n\t\t*t = PermissionTypeDurableStorage\n\tcase PermissionTypeGeolocation:\n\t\t*t = PermissionTypeGeolocation\n\tcase PermissionTypeHandTracking:\n\t\t*t = PermissionTypeHandTracking\n\tcase PermissionTypeIdleDetection:\n\t\t*t = PermissionTypeIdleDetection\n\tcase PermissionTypeKeyboardLock:\n\t\t*t = PermissionTypeKeyboardLock\n\tcase PermissionTypeLocalFonts:\n\t\t*t = PermissionTypeLocalFonts\n\tcase PermissionTypeLocalNetworkAccess:\n\t\t*t = PermissionTypeLocalNetworkAccess\n\tcase PermissionTypeMidi:\n\t\t*t = PermissionTypeMidi\n\tcase PermissionTypeMidiSysex:\n\t\t*t = PermissionTypeMidiSysex\n\tcase PermissionTypeNfc:\n\t\t*t = PermissionTypeNfc\n\tcase PermissionTypeNotifications:\n\t\t*t = PermissionTypeNotifications\n\tcase PermissionTypePaymentHandler:\n\t\t*t = PermissionTypePaymentHandler\n\tcase PermissionTypePeriodicBackgroundSync:\n\t\t*t = PermissionTypePeriodicBackgroundSync\n\tcase PermissionTypePointerLock:\n\t\t*t = PermissionTypePointerLock\n\tcase PermissionTypeProtectedMediaIdentifier:\n\t\t*t = PermissionTypeProtectedMediaIdentifier\n\tcase PermissionTypeSensors:\n\t\t*t = PermissionTypeSensors\n\tcase PermissionTypeSmartCard:\n\t\t*t = PermissionTypeSmartCard\n\tcase PermissionTypeSpeakerSelection:\n\t\t*t = PermissionTypeSpeakerSelection\n\tcase PermissionTypeStorageAccess:\n\t\t*t = PermissionTypeStorageAccess\n\tcase PermissionTypeTopLevelStorageAccess:\n\t\t*t = PermissionTypeTopLevelStorageAccess\n\tcase PermissionTypeVideoCapture:\n\t\t*t = PermissionTypeVideoCapture\n\tcase PermissionTypeVr:\n\t\t*t = PermissionTypeVr\n\tcase PermissionTypeWakeLockScreen:\n\t\t*t = PermissionTypeWakeLockScreen\n\tcase PermissionTypeWakeLockSystem:\n\t\t*t = PermissionTypeWakeLockSystem\n\tcase PermissionTypeWebAppInstallation:\n\t\t*t = PermissionTypeWebAppInstallation\n\tcase PermissionTypeWebPrinting:\n\t\t*t = PermissionTypeWebPrinting\n\tcase PermissionTypeWindowManagement:\n\t\t*t = PermissionTypeWindowManagement\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PermissionType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PermissionSetting [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-PermissionSetting\ntype PermissionSetting string\n\n// String returns the PermissionSetting as string value.\nfunc (t PermissionSetting) String() string {\n\treturn string(t)\n}\n\n// PermissionSetting values.\nconst (\n\tPermissionSettingGranted PermissionSetting = \"granted\"\n\tPermissionSettingDenied  PermissionSetting = \"denied\"\n\tPermissionSettingPrompt  PermissionSetting = \"prompt\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PermissionSetting) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PermissionSetting(s) {\n\tcase PermissionSettingGranted:\n\t\t*t = PermissionSettingGranted\n\tcase PermissionSettingDenied:\n\t\t*t = PermissionSettingDenied\n\tcase PermissionSettingPrompt:\n\t\t*t = PermissionSettingPrompt\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PermissionSetting value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PermissionDescriptor definition of PermissionDescriptor defined in the\n// Permissions API: https://w3c.github.io/permissions/#dom-permissiondescriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-PermissionDescriptor\ntype PermissionDescriptor struct {\n\tName                     string `json:\"name\"`                     // Name of permission. See https://cs.chromium.org/chromium/src/third_party/blink/renderer/modules/permissions/permission_descriptor.idl for valid permission names.\n\tSysex                    bool   `json:\"sysex\"`                    // For \"midi\" permission, may also specify sysex control.\n\tUserVisibleOnly          bool   `json:\"userVisibleOnly\"`          // For \"push\" permission, may specify userVisibleOnly. Note that userVisibleOnly = true is the only currently supported type.\n\tAllowWithoutSanitization bool   `json:\"allowWithoutSanitization\"` // For \"clipboard\" permission, may specify allowWithoutSanitization.\n\tAllowWithoutGesture      bool   `json:\"allowWithoutGesture\"`      // For \"fullscreen\" permission, must specify allowWithoutGesture:true.\n\tPanTiltZoom              bool   `json:\"panTiltZoom\"`              // For \"camera\" permission, may specify panTiltZoom.\n}\n\n// CommandID browser command ids used by executeBrowserCommand.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-BrowserCommandId\ntype CommandID string\n\n// String returns the CommandID as string value.\nfunc (t CommandID) String() string {\n\treturn string(t)\n}\n\n// CommandID values.\nconst (\n\tCommandIDOpenTabSearch  CommandID = \"openTabSearch\"\n\tCommandIDCloseTabSearch CommandID = \"closeTabSearch\"\n\tCommandIDOpenGlic       CommandID = \"openGlic\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CommandID) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CommandID(s) {\n\tcase CommandIDOpenTabSearch:\n\t\t*t = CommandIDOpenTabSearch\n\tcase CommandIDCloseTabSearch:\n\t\t*t = CommandIDCloseTabSearch\n\tcase CommandIDOpenGlic:\n\t\t*t = CommandIDOpenGlic\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CommandID value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Bucket chrome histogram bucket.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-Bucket\ntype Bucket struct {\n\tLow   int64 `json:\"low\"`   // Minimum value (inclusive).\n\tHigh  int64 `json:\"high\"`  // Maximum value (exclusive).\n\tCount int64 `json:\"count\"` // Number of samples.\n}\n\n// Histogram chrome histogram.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-Histogram\ntype Histogram struct {\n\tName    string    `json:\"name\"`    // Name.\n\tSum     int64     `json:\"sum\"`     // Sum of sample values.\n\tCount   int64     `json:\"count\"`   // Total number of samples.\n\tBuckets []*Bucket `json:\"buckets\"` // Buckets.\n}\n\n// PrivacySandboxAPI [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-PrivacySandboxAPI\ntype PrivacySandboxAPI string\n\n// String returns the PrivacySandboxAPI as string value.\nfunc (t PrivacySandboxAPI) String() string {\n\treturn string(t)\n}\n\n// PrivacySandboxAPI values.\nconst (\n\tPrivacySandboxAPIBiddingAndAuctionServices PrivacySandboxAPI = \"BiddingAndAuctionServices\"\n\tPrivacySandboxAPITrustedKeyValue           PrivacySandboxAPI = \"TrustedKeyValue\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PrivacySandboxAPI) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PrivacySandboxAPI(s) {\n\tcase PrivacySandboxAPIBiddingAndAuctionServices:\n\t\t*t = PrivacySandboxAPIBiddingAndAuctionServices\n\tcase PrivacySandboxAPITrustedKeyValue:\n\t\t*t = PrivacySandboxAPITrustedKeyValue\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PrivacySandboxAPI value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DownloadProgressState download status.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#event-downloadProgress\ntype DownloadProgressState string\n\n// String returns the DownloadProgressState as string value.\nfunc (t DownloadProgressState) String() string {\n\treturn string(t)\n}\n\n// DownloadProgressState values.\nconst (\n\tDownloadProgressStateInProgress DownloadProgressState = \"inProgress\"\n\tDownloadProgressStateCompleted  DownloadProgressState = \"completed\"\n\tDownloadProgressStateCanceled   DownloadProgressState = \"canceled\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DownloadProgressState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DownloadProgressState(s) {\n\tcase DownloadProgressStateInProgress:\n\t\t*t = DownloadProgressStateInProgress\n\tcase DownloadProgressStateCompleted:\n\t\t*t = DownloadProgressStateCompleted\n\tcase DownloadProgressStateCanceled:\n\t\t*t = DownloadProgressStateCanceled\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DownloadProgressState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetDownloadBehaviorBehavior whether to allow all or deny all download\n// requests, or use default Chrome behavior if available (otherwise deny).\n// |allowAndName| allows download and names files according to their download\n// guids.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#method-setDownloadBehavior\ntype SetDownloadBehaviorBehavior string\n\n// String returns the SetDownloadBehaviorBehavior as string value.\nfunc (t SetDownloadBehaviorBehavior) String() string {\n\treturn string(t)\n}\n\n// SetDownloadBehaviorBehavior values.\nconst (\n\tSetDownloadBehaviorBehaviorDeny         SetDownloadBehaviorBehavior = \"deny\"\n\tSetDownloadBehaviorBehaviorAllow        SetDownloadBehaviorBehavior = \"allow\"\n\tSetDownloadBehaviorBehaviorAllowAndName SetDownloadBehaviorBehavior = \"allowAndName\"\n\tSetDownloadBehaviorBehaviorDefault      SetDownloadBehaviorBehavior = \"default\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetDownloadBehaviorBehavior) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetDownloadBehaviorBehavior(s) {\n\tcase SetDownloadBehaviorBehaviorDeny:\n\t\t*t = SetDownloadBehaviorBehaviorDeny\n\tcase SetDownloadBehaviorBehaviorAllow:\n\t\t*t = SetDownloadBehaviorBehaviorAllow\n\tcase SetDownloadBehaviorBehaviorAllowAndName:\n\t\t*t = SetDownloadBehaviorBehaviorAllowAndName\n\tcase SetDownloadBehaviorBehaviorDefault:\n\t\t*t = SetDownloadBehaviorBehaviorDefault\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetDownloadBehaviorBehavior value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/cachestorage/cachestorage.go",
    "content": "// Package cachestorage provides the Chrome DevTools Protocol\n// commands, types, and events for the CacheStorage domain.\n//\n// Generated by the cdproto-gen command.\npackage cachestorage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/storage\"\n)\n\n// DeleteCacheParams deletes a cache.\ntype DeleteCacheParams struct {\n\tCacheID CacheID `json:\"cacheId\"` // Id of cache for deletion.\n}\n\n// DeleteCache deletes a cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#method-deleteCache\n//\n// parameters:\n//\n//\tcacheID - Id of cache for deletion.\nfunc DeleteCache(cacheID CacheID) *DeleteCacheParams {\n\treturn &DeleteCacheParams{\n\t\tCacheID: cacheID,\n\t}\n}\n\n// Do executes CacheStorage.deleteCache against the provided context.\nfunc (p *DeleteCacheParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeleteCache, p, nil)\n}\n\n// DeleteEntryParams deletes a cache entry.\ntype DeleteEntryParams struct {\n\tCacheID CacheID `json:\"cacheId\"` // Id of cache where the entry will be deleted.\n\tRequest string  `json:\"request\"` // URL spec of the request.\n}\n\n// DeleteEntry deletes a cache entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#method-deleteEntry\n//\n// parameters:\n//\n//\tcacheID - Id of cache where the entry will be deleted.\n//\trequest - URL spec of the request.\nfunc DeleteEntry(cacheID CacheID, request string) *DeleteEntryParams {\n\treturn &DeleteEntryParams{\n\t\tCacheID: cacheID,\n\t\tRequest: request,\n\t}\n}\n\n// Do executes CacheStorage.deleteEntry against the provided context.\nfunc (p *DeleteEntryParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeleteEntry, p, nil)\n}\n\n// RequestCacheNamesParams requests cache names.\ntype RequestCacheNamesParams struct {\n\tSecurityOrigin string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, storageBucket must be specified. Security origin.\n\tStorageKey     string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket  *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n}\n\n// RequestCacheNames requests cache names.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#method-requestCacheNames\n//\n// parameters:\nfunc RequestCacheNames() *RequestCacheNamesParams {\n\treturn &RequestCacheNamesParams{}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// storageBucket must be specified. Security origin.\nfunc (p RequestCacheNamesParams) WithSecurityOrigin(securityOrigin string) *RequestCacheNamesParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p RequestCacheNamesParams) WithStorageKey(storageKey string) *RequestCacheNamesParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p RequestCacheNamesParams) WithStorageBucket(storageBucket *storage.Bucket) *RequestCacheNamesParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// RequestCacheNamesReturns return values.\ntype RequestCacheNamesReturns struct {\n\tCaches []*Cache `json:\"caches,omitempty,omitzero\"` // Caches for the security origin.\n}\n\n// Do executes CacheStorage.requestCacheNames against the provided context.\n//\n// returns:\n//\n//\tcaches - Caches for the security origin.\nfunc (p *RequestCacheNamesParams) Do(ctx context.Context) (caches []*Cache, err error) {\n\t// execute\n\tvar res RequestCacheNamesReturns\n\terr = cdp.Execute(ctx, CommandRequestCacheNames, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Caches, nil\n}\n\n// RequestCachedResponseParams fetches cache entry.\ntype RequestCachedResponseParams struct {\n\tCacheID        CacheID   `json:\"cacheId\"`        // Id of cache that contains the entry.\n\tRequestURL     string    `json:\"requestURL\"`     // URL spec of the request.\n\tRequestHeaders []*Header `json:\"requestHeaders\"` // headers of the request.\n}\n\n// RequestCachedResponse fetches cache entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#method-requestCachedResponse\n//\n// parameters:\n//\n//\tcacheID - Id of cache that contains the entry.\n//\trequestURL - URL spec of the request.\n//\trequestHeaders - headers of the request.\nfunc RequestCachedResponse(cacheID CacheID, requestURL string, requestHeaders []*Header) *RequestCachedResponseParams {\n\treturn &RequestCachedResponseParams{\n\t\tCacheID:        cacheID,\n\t\tRequestURL:     requestURL,\n\t\tRequestHeaders: requestHeaders,\n\t}\n}\n\n// RequestCachedResponseReturns return values.\ntype RequestCachedResponseReturns struct {\n\tResponse *CachedResponse `json:\"response,omitempty,omitzero\"` // Response read from the cache.\n}\n\n// Do executes CacheStorage.requestCachedResponse against the provided context.\n//\n// returns:\n//\n//\tresponse - Response read from the cache.\nfunc (p *RequestCachedResponseParams) Do(ctx context.Context) (response *CachedResponse, err error) {\n\t// execute\n\tvar res RequestCachedResponseReturns\n\terr = cdp.Execute(ctx, CommandRequestCachedResponse, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Response, nil\n}\n\n// RequestEntriesParams requests data from cache.\ntype RequestEntriesParams struct {\n\tCacheID    CacheID `json:\"cacheId\"`                       // ID of cache to get entries from.\n\tSkipCount  int64   `json:\"skipCount,omitempty,omitzero\"`  // Number of records to skip.\n\tPageSize   int64   `json:\"pageSize,omitempty,omitzero\"`   // Number of records to fetch.\n\tPathFilter string  `json:\"pathFilter,omitempty,omitzero\"` // If present, only return the entries containing this substring in the path\n}\n\n// RequestEntries requests data from cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#method-requestEntries\n//\n// parameters:\n//\n//\tcacheID - ID of cache to get entries from.\nfunc RequestEntries(cacheID CacheID) *RequestEntriesParams {\n\treturn &RequestEntriesParams{\n\t\tCacheID: cacheID,\n\t}\n}\n\n// WithSkipCount number of records to skip.\nfunc (p RequestEntriesParams) WithSkipCount(skipCount int64) *RequestEntriesParams {\n\tp.SkipCount = skipCount\n\treturn &p\n}\n\n// WithPageSize number of records to fetch.\nfunc (p RequestEntriesParams) WithPageSize(pageSize int64) *RequestEntriesParams {\n\tp.PageSize = pageSize\n\treturn &p\n}\n\n// WithPathFilter if present, only return the entries containing this\n// substring in the path.\nfunc (p RequestEntriesParams) WithPathFilter(pathFilter string) *RequestEntriesParams {\n\tp.PathFilter = pathFilter\n\treturn &p\n}\n\n// RequestEntriesReturns return values.\ntype RequestEntriesReturns struct {\n\tCacheDataEntries []*DataEntry `json:\"cacheDataEntries,omitempty,omitzero\"` // Array of object store data entries.\n\tReturnCount      float64      `json:\"returnCount,omitempty,omitzero\"`      // Count of returned entries from this storage. If pathFilter is empty, it is the count of all entries from this storage.\n}\n\n// Do executes CacheStorage.requestEntries against the provided context.\n//\n// returns:\n//\n//\tcacheDataEntries - Array of object store data entries.\n//\treturnCount - Count of returned entries from this storage. If pathFilter is empty, it is the count of all entries from this storage.\nfunc (p *RequestEntriesParams) Do(ctx context.Context) (cacheDataEntries []*DataEntry, returnCount float64, err error) {\n\t// execute\n\tvar res RequestEntriesReturns\n\terr = cdp.Execute(ctx, CommandRequestEntries, p, &res)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\treturn res.CacheDataEntries, res.ReturnCount, nil\n}\n\n// Command names.\nconst (\n\tCommandDeleteCache           = \"CacheStorage.deleteCache\"\n\tCommandDeleteEntry           = \"CacheStorage.deleteEntry\"\n\tCommandRequestCacheNames     = \"CacheStorage.requestCacheNames\"\n\tCommandRequestCachedResponse = \"CacheStorage.requestCachedResponse\"\n\tCommandRequestEntries        = \"CacheStorage.requestEntries\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/cachestorage/types.go",
    "content": "package cachestorage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/storage\"\n)\n\n// CacheID unique identifier of the Cache object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-CacheId\ntype CacheID string\n\n// String returns the CacheID as string value.\nfunc (t CacheID) String() string {\n\treturn string(t)\n}\n\n// CachedResponseType type of HTTP response cached.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-CachedResponseType\ntype CachedResponseType string\n\n// String returns the CachedResponseType as string value.\nfunc (t CachedResponseType) String() string {\n\treturn string(t)\n}\n\n// CachedResponseType values.\nconst (\n\tCachedResponseTypeBasic          CachedResponseType = \"basic\"\n\tCachedResponseTypeCors           CachedResponseType = \"cors\"\n\tCachedResponseTypeDefault        CachedResponseType = \"default\"\n\tCachedResponseTypeError          CachedResponseType = \"error\"\n\tCachedResponseTypeOpaqueResponse CachedResponseType = \"opaqueResponse\"\n\tCachedResponseTypeOpaqueRedirect CachedResponseType = \"opaqueRedirect\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CachedResponseType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CachedResponseType(s) {\n\tcase CachedResponseTypeBasic:\n\t\t*t = CachedResponseTypeBasic\n\tcase CachedResponseTypeCors:\n\t\t*t = CachedResponseTypeCors\n\tcase CachedResponseTypeDefault:\n\t\t*t = CachedResponseTypeDefault\n\tcase CachedResponseTypeError:\n\t\t*t = CachedResponseTypeError\n\tcase CachedResponseTypeOpaqueResponse:\n\t\t*t = CachedResponseTypeOpaqueResponse\n\tcase CachedResponseTypeOpaqueRedirect:\n\t\t*t = CachedResponseTypeOpaqueRedirect\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CachedResponseType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DataEntry data entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-DataEntry\ntype DataEntry struct {\n\tRequestURL         string             `json:\"requestURL\"`         // Request URL.\n\tRequestMethod      string             `json:\"requestMethod\"`      // Request method.\n\tRequestHeaders     []*Header          `json:\"requestHeaders\"`     // Request headers\n\tResponseTime       float64            `json:\"responseTime\"`       // Number of seconds since epoch.\n\tResponseStatus     int64              `json:\"responseStatus\"`     // HTTP response status code.\n\tResponseStatusText string             `json:\"responseStatusText\"` // HTTP response status text.\n\tResponseType       CachedResponseType `json:\"responseType\"`       // HTTP response type\n\tResponseHeaders    []*Header          `json:\"responseHeaders\"`    // Response headers\n}\n\n// Cache cache identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-Cache\ntype Cache struct {\n\tCacheID        CacheID         `json:\"cacheId\"`                          // An opaque unique id of the cache.\n\tSecurityOrigin string          `json:\"securityOrigin\"`                   // Security origin of the cache.\n\tStorageKey     string          `json:\"storageKey\"`                       // Storage key of the cache.\n\tStorageBucket  *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"` // Storage bucket of the cache.\n\tCacheName      string          `json:\"cacheName\"`                        // The name of the cache.\n}\n\n// Header [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-Header\ntype Header struct {\n\tName  string `json:\"name\"`\n\tValue string `json:\"value\"`\n}\n\n// CachedResponse cached response.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CacheStorage#type-CachedResponse\ntype CachedResponse struct {\n\tBody string `json:\"body\"` // Entry content, base64-encoded.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/cast/cast.go",
    "content": "// Package cast provides the Chrome DevTools Protocol\n// commands, types, and events for the Cast domain.\n//\n// A domain for interacting with Cast, Presentation API, and Remote Playback\n// API functionalities.\n//\n// Generated by the cdproto-gen command.\npackage cast\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams starts observing for sinks that can be used for tab\n// mirroring, and if set, sinks compatible with |presentationUrl| as well. When\n// sinks are found, a |sinksUpdated| event is fired. Also starts observing for\n// issue messages. When an issue is added or removed, an |issueUpdated| event is\n// fired.\ntype EnableParams struct {\n\tPresentationURL string `json:\"presentationUrl,omitempty,omitzero\"`\n}\n\n// Enable starts observing for sinks that can be used for tab mirroring, and\n// if set, sinks compatible with |presentationUrl| as well. When sinks are\n// found, a |sinksUpdated| event is fired. Also starts observing for issue\n// messages. When an issue is added or removed, an |issueUpdated| event is\n// fired.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// WithPresentationURL [no description].\nfunc (p EnableParams) WithPresentationURL(presentationURL string) *EnableParams {\n\tp.PresentationURL = presentationURL\n\treturn &p\n}\n\n// Do executes Cast.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// DisableParams stops observing for sinks and issues.\ntype DisableParams struct{}\n\n// Disable stops observing for sinks and issues.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Cast.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// SetSinkToUseParams sets a sink to be used when the web page requests the\n// browser to choose a sink via Presentation API, Remote Playback API, or Cast\n// SDK.\ntype SetSinkToUseParams struct {\n\tSinkName string `json:\"sinkName\"`\n}\n\n// SetSinkToUse sets a sink to be used when the web page requests the browser\n// to choose a sink via Presentation API, Remote Playback API, or Cast SDK.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#method-setSinkToUse\n//\n// parameters:\n//\n//\tsinkName\nfunc SetSinkToUse(sinkName string) *SetSinkToUseParams {\n\treturn &SetSinkToUseParams{\n\t\tSinkName: sinkName,\n\t}\n}\n\n// Do executes Cast.setSinkToUse against the provided context.\nfunc (p *SetSinkToUseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSinkToUse, p, nil)\n}\n\n// StartDesktopMirroringParams starts mirroring the desktop to the sink.\ntype StartDesktopMirroringParams struct {\n\tSinkName string `json:\"sinkName\"`\n}\n\n// StartDesktopMirroring starts mirroring the desktop to the sink.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#method-startDesktopMirroring\n//\n// parameters:\n//\n//\tsinkName\nfunc StartDesktopMirroring(sinkName string) *StartDesktopMirroringParams {\n\treturn &StartDesktopMirroringParams{\n\t\tSinkName: sinkName,\n\t}\n}\n\n// Do executes Cast.startDesktopMirroring against the provided context.\nfunc (p *StartDesktopMirroringParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartDesktopMirroring, p, nil)\n}\n\n// StartTabMirroringParams starts mirroring the tab to the sink.\ntype StartTabMirroringParams struct {\n\tSinkName string `json:\"sinkName\"`\n}\n\n// StartTabMirroring starts mirroring the tab to the sink.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#method-startTabMirroring\n//\n// parameters:\n//\n//\tsinkName\nfunc StartTabMirroring(sinkName string) *StartTabMirroringParams {\n\treturn &StartTabMirroringParams{\n\t\tSinkName: sinkName,\n\t}\n}\n\n// Do executes Cast.startTabMirroring against the provided context.\nfunc (p *StartTabMirroringParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartTabMirroring, p, nil)\n}\n\n// StopCastingParams stops the active Cast session on the sink.\ntype StopCastingParams struct {\n\tSinkName string `json:\"sinkName\"`\n}\n\n// StopCasting stops the active Cast session on the sink.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#method-stopCasting\n//\n// parameters:\n//\n//\tsinkName\nfunc StopCasting(sinkName string) *StopCastingParams {\n\treturn &StopCastingParams{\n\t\tSinkName: sinkName,\n\t}\n}\n\n// Do executes Cast.stopCasting against the provided context.\nfunc (p *StopCastingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopCasting, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable                = \"Cast.enable\"\n\tCommandDisable               = \"Cast.disable\"\n\tCommandSetSinkToUse          = \"Cast.setSinkToUse\"\n\tCommandStartDesktopMirroring = \"Cast.startDesktopMirroring\"\n\tCommandStartTabMirroring     = \"Cast.startTabMirroring\"\n\tCommandStopCasting           = \"Cast.stopCasting\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/cast/events.go",
    "content": "package cast\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventSinksUpdated this is fired whenever the list of available sinks\n// changes. A sink is a device or a software surface that you can cast to.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#event-sinksUpdated\ntype EventSinksUpdated struct {\n\tSinks []*Sink `json:\"sinks\"`\n}\n\n// EventIssueUpdated this is fired whenever the outstanding issue/error\n// message changes. |issueMessage| is empty if there is no issue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#event-issueUpdated\ntype EventIssueUpdated struct {\n\tIssueMessage string `json:\"issueMessage\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/cast/types.go",
    "content": "package cast\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// Sink [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Cast#type-Sink\ntype Sink struct {\n\tName    string `json:\"name\"`\n\tID      string `json:\"id\"`\n\tSession string `json:\"session,omitempty,omitzero\"` // Text describing the current session. Present only if there is an active session on the sink.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/cdp/types.go",
    "content": "package cdp\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/chromedp/sysutil\"\n)\n\n// Executor is the common interface for executing a command.\ntype Executor interface {\n\t// Execute executes the command.\n\tExecute(context.Context, string, any, any) error\n}\n\n// contextKey is the context key type.\ntype contextKey int\n\n// context keys.\nconst (\n\texecutorKey contextKey = iota\n)\n\n// WithExecutor sets the message executor for the context.\nfunc WithExecutor(parent context.Context, executor Executor) context.Context {\n\treturn context.WithValue(parent, executorKey, executor)\n}\n\n// ExecutorFromContext returns the message executor for the context.\nfunc ExecutorFromContext(ctx context.Context) Executor {\n\treturn ctx.Value(executorKey).(Executor)\n}\n\n// Execute uses the context's message executor to send a command or event\n// method marshaling the provided parameters, and unmarshaling to res.\nfunc Execute(ctx context.Context, method string, params, res any) error {\n\tif executor := ctx.Value(executorKey); executor != nil {\n\t\treturn executor.(Executor).Execute(ctx, method, params, res)\n\t}\n\treturn ErrInvalidContext\n}\n\n// Error is a error.\ntype Error string\n\n// Error values.\nconst (\n\t// ErrInvalidContext is the invalid context error.\n\tErrInvalidContext Error = \"invalid context\"\n\n\t// ErrMsgMissingParamsOrResult is the msg missing params or result error.\n\tErrMsgMissingParamsOrResult Error = \"msg missing params or result\"\n)\n\n// Error satisfies the error interface.\nfunc (err Error) Error() string {\n\treturn string(err)\n}\n\n// ErrUnknownCommandOrEvent is an unknown command or event error.\ntype ErrUnknownCommandOrEvent string\n\n// Error satisfies the error interface.\nfunc (err ErrUnknownCommandOrEvent) Error() string {\n\treturn fmt.Sprintf(\"unknown command or event %q\", string(err))\n}\n\n// BrowserContextID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Browser#type-BrowserContextID\ntype BrowserContextID string\n\n// String returns the BrowserContextID as string value.\nfunc (t BrowserContextID) String() string {\n\treturn string(t)\n}\n\n// NodeID unique DOM node identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-NodeId\ntype NodeID int64\n\n// Int64 returns the NodeID as int64 value.\nfunc (t NodeID) Int64() int64 {\n\treturn int64(t)\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *NodeID) UnmarshalJSON(buf []byte) error {\n\tif l := len(buf); l > 2 && buf[0] == '\"' && buf[l-1] == '\"' {\n\t\tbuf = buf[1 : l-1]\n\t}\n\n\tv, err := strconv.ParseInt(string(buf), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*t = NodeID(v)\n\treturn nil\n}\n\n// BackendNodeID unique DOM node identifier used to reference a node that may\n// not have been pushed to the front-end.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-BackendNodeId\ntype BackendNodeID int64\n\n// Int64 returns the BackendNodeID as int64 value.\nfunc (t BackendNodeID) Int64() int64 {\n\treturn int64(t)\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *BackendNodeID) UnmarshalJSON(buf []byte) error {\n\tif l := len(buf); l > 2 && buf[0] == '\"' && buf[l-1] == '\"' {\n\t\tbuf = buf[1 : l-1]\n\t}\n\n\tv, err := strconv.ParseInt(string(buf), 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t*t = BackendNodeID(v)\n\treturn nil\n}\n\n// BackendNode backend node with a friendly name.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-BackendNode\ntype BackendNode struct {\n\tNodeType      NodeType      `json:\"nodeType\"` // Node's nodeType.\n\tNodeName      string        `json:\"nodeName\"` // Node's nodeName.\n\tBackendNodeID BackendNodeID `json:\"backendNodeId\"`\n}\n\n// PseudoType pseudo element type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PseudoType\ntype PseudoType string\n\n// String returns the PseudoType as string value.\nfunc (t PseudoType) String() string {\n\treturn string(t)\n}\n\n// PseudoType values.\nconst (\n\tPseudoTypeFirstLine                   PseudoType = \"first-line\"\n\tPseudoTypeFirstLetter                 PseudoType = \"first-letter\"\n\tPseudoTypeCheckmark                   PseudoType = \"checkmark\"\n\tPseudoTypeBefore                      PseudoType = \"before\"\n\tPseudoTypeAfter                       PseudoType = \"after\"\n\tPseudoTypePickerIcon                  PseudoType = \"picker-icon\"\n\tPseudoTypeMarker                      PseudoType = \"marker\"\n\tPseudoTypeBackdrop                    PseudoType = \"backdrop\"\n\tPseudoTypeColumn                      PseudoType = \"column\"\n\tPseudoTypeSelection                   PseudoType = \"selection\"\n\tPseudoTypeSearchText                  PseudoType = \"search-text\"\n\tPseudoTypeTargetText                  PseudoType = \"target-text\"\n\tPseudoTypeSpellingError               PseudoType = \"spelling-error\"\n\tPseudoTypeGrammarError                PseudoType = \"grammar-error\"\n\tPseudoTypeHighlight                   PseudoType = \"highlight\"\n\tPseudoTypeFirstLineInherited          PseudoType = \"first-line-inherited\"\n\tPseudoTypeScrollMarker                PseudoType = \"scroll-marker\"\n\tPseudoTypeScrollMarkerGroup           PseudoType = \"scroll-marker-group\"\n\tPseudoTypeScrollButton                PseudoType = \"scroll-button\"\n\tPseudoTypeScrollbar                   PseudoType = \"scrollbar\"\n\tPseudoTypeScrollbarThumb              PseudoType = \"scrollbar-thumb\"\n\tPseudoTypeScrollbarButton             PseudoType = \"scrollbar-button\"\n\tPseudoTypeScrollbarTrack              PseudoType = \"scrollbar-track\"\n\tPseudoTypeScrollbarTrackPiece         PseudoType = \"scrollbar-track-piece\"\n\tPseudoTypeScrollbarCorner             PseudoType = \"scrollbar-corner\"\n\tPseudoTypeResizer                     PseudoType = \"resizer\"\n\tPseudoTypeInputListButton             PseudoType = \"input-list-button\"\n\tPseudoTypeViewTransition              PseudoType = \"view-transition\"\n\tPseudoTypeViewTransitionGroup         PseudoType = \"view-transition-group\"\n\tPseudoTypeViewTransitionImagePair     PseudoType = \"view-transition-image-pair\"\n\tPseudoTypeViewTransitionGroupChildren PseudoType = \"view-transition-group-children\"\n\tPseudoTypeViewTransitionOld           PseudoType = \"view-transition-old\"\n\tPseudoTypeViewTransitionNew           PseudoType = \"view-transition-new\"\n\tPseudoTypePlaceholder                 PseudoType = \"placeholder\"\n\tPseudoTypeFileSelectorButton          PseudoType = \"file-selector-button\"\n\tPseudoTypeDetailsContent              PseudoType = \"details-content\"\n\tPseudoTypePicker                      PseudoType = \"picker\"\n\tPseudoTypePermissionIcon              PseudoType = \"permission-icon\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PseudoType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PseudoType(s) {\n\tcase PseudoTypeFirstLine:\n\t\t*t = PseudoTypeFirstLine\n\tcase PseudoTypeFirstLetter:\n\t\t*t = PseudoTypeFirstLetter\n\tcase PseudoTypeCheckmark:\n\t\t*t = PseudoTypeCheckmark\n\tcase PseudoTypeBefore:\n\t\t*t = PseudoTypeBefore\n\tcase PseudoTypeAfter:\n\t\t*t = PseudoTypeAfter\n\tcase PseudoTypePickerIcon:\n\t\t*t = PseudoTypePickerIcon\n\tcase PseudoTypeMarker:\n\t\t*t = PseudoTypeMarker\n\tcase PseudoTypeBackdrop:\n\t\t*t = PseudoTypeBackdrop\n\tcase PseudoTypeColumn:\n\t\t*t = PseudoTypeColumn\n\tcase PseudoTypeSelection:\n\t\t*t = PseudoTypeSelection\n\tcase PseudoTypeSearchText:\n\t\t*t = PseudoTypeSearchText\n\tcase PseudoTypeTargetText:\n\t\t*t = PseudoTypeTargetText\n\tcase PseudoTypeSpellingError:\n\t\t*t = PseudoTypeSpellingError\n\tcase PseudoTypeGrammarError:\n\t\t*t = PseudoTypeGrammarError\n\tcase PseudoTypeHighlight:\n\t\t*t = PseudoTypeHighlight\n\tcase PseudoTypeFirstLineInherited:\n\t\t*t = PseudoTypeFirstLineInherited\n\tcase PseudoTypeScrollMarker:\n\t\t*t = PseudoTypeScrollMarker\n\tcase PseudoTypeScrollMarkerGroup:\n\t\t*t = PseudoTypeScrollMarkerGroup\n\tcase PseudoTypeScrollButton:\n\t\t*t = PseudoTypeScrollButton\n\tcase PseudoTypeScrollbar:\n\t\t*t = PseudoTypeScrollbar\n\tcase PseudoTypeScrollbarThumb:\n\t\t*t = PseudoTypeScrollbarThumb\n\tcase PseudoTypeScrollbarButton:\n\t\t*t = PseudoTypeScrollbarButton\n\tcase PseudoTypeScrollbarTrack:\n\t\t*t = PseudoTypeScrollbarTrack\n\tcase PseudoTypeScrollbarTrackPiece:\n\t\t*t = PseudoTypeScrollbarTrackPiece\n\tcase PseudoTypeScrollbarCorner:\n\t\t*t = PseudoTypeScrollbarCorner\n\tcase PseudoTypeResizer:\n\t\t*t = PseudoTypeResizer\n\tcase PseudoTypeInputListButton:\n\t\t*t = PseudoTypeInputListButton\n\tcase PseudoTypeViewTransition:\n\t\t*t = PseudoTypeViewTransition\n\tcase PseudoTypeViewTransitionGroup:\n\t\t*t = PseudoTypeViewTransitionGroup\n\tcase PseudoTypeViewTransitionImagePair:\n\t\t*t = PseudoTypeViewTransitionImagePair\n\tcase PseudoTypeViewTransitionGroupChildren:\n\t\t*t = PseudoTypeViewTransitionGroupChildren\n\tcase PseudoTypeViewTransitionOld:\n\t\t*t = PseudoTypeViewTransitionOld\n\tcase PseudoTypeViewTransitionNew:\n\t\t*t = PseudoTypeViewTransitionNew\n\tcase PseudoTypePlaceholder:\n\t\t*t = PseudoTypePlaceholder\n\tcase PseudoTypeFileSelectorButton:\n\t\t*t = PseudoTypeFileSelectorButton\n\tcase PseudoTypeDetailsContent:\n\t\t*t = PseudoTypeDetailsContent\n\tcase PseudoTypePicker:\n\t\t*t = PseudoTypePicker\n\tcase PseudoTypePermissionIcon:\n\t\t*t = PseudoTypePermissionIcon\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PseudoType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ShadowRootType shadow root type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-ShadowRootType\ntype ShadowRootType string\n\n// String returns the ShadowRootType as string value.\nfunc (t ShadowRootType) String() string {\n\treturn string(t)\n}\n\n// ShadowRootType values.\nconst (\n\tShadowRootTypeUserAgent ShadowRootType = \"user-agent\"\n\tShadowRootTypeOpen      ShadowRootType = \"open\"\n\tShadowRootTypeClosed    ShadowRootType = \"closed\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ShadowRootType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ShadowRootType(s) {\n\tcase ShadowRootTypeUserAgent:\n\t\t*t = ShadowRootTypeUserAgent\n\tcase ShadowRootTypeOpen:\n\t\t*t = ShadowRootTypeOpen\n\tcase ShadowRootTypeClosed:\n\t\t*t = ShadowRootTypeClosed\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ShadowRootType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CompatibilityMode document compatibility mode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-CompatibilityMode\ntype CompatibilityMode string\n\n// String returns the CompatibilityMode as string value.\nfunc (t CompatibilityMode) String() string {\n\treturn string(t)\n}\n\n// CompatibilityMode values.\nconst (\n\tCompatibilityModeQuirksMode        CompatibilityMode = \"QuirksMode\"\n\tCompatibilityModeLimitedQuirksMode CompatibilityMode = \"LimitedQuirksMode\"\n\tCompatibilityModeNoQuirksMode      CompatibilityMode = \"NoQuirksMode\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CompatibilityMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CompatibilityMode(s) {\n\tcase CompatibilityModeQuirksMode:\n\t\t*t = CompatibilityModeQuirksMode\n\tcase CompatibilityModeLimitedQuirksMode:\n\t\t*t = CompatibilityModeLimitedQuirksMode\n\tcase CompatibilityModeNoQuirksMode:\n\t\t*t = CompatibilityModeNoQuirksMode\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CompatibilityMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Node DOM interaction is implemented in terms of mirror objects that\n// represent the actual DOM nodes. DOMNode is a base node mirror type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-Node\ntype Node struct {\n\tNodeID            NodeID            `json:\"nodeId\"`                              // Node identifier that is passed into the rest of the DOM messages as the nodeId. Backend will only push node with given id once. It is aware of all requested nodes and will only fire DOM events for nodes known to the client.\n\tParentID          NodeID            `json:\"parentId,omitempty,omitzero\"`         // The id of the parent node if any.\n\tBackendNodeID     BackendNodeID     `json:\"backendNodeId\"`                       // The BackendNodeId for this node.\n\tNodeType          NodeType          `json:\"nodeType\"`                            // Node's nodeType.\n\tNodeName          string            `json:\"nodeName\"`                            // Node's nodeName.\n\tLocalName         string            `json:\"localName\"`                           // Node's localName.\n\tNodeValue         string            `json:\"nodeValue\"`                           // Node's nodeValue.\n\tChildNodeCount    int64             `json:\"childNodeCount,omitempty,omitzero\"`   // Child count for Container nodes.\n\tChildren          []*Node           `json:\"children,omitempty,omitzero\"`         // Child nodes of this node when requested with children.\n\tAttributes        []string          `json:\"attributes,omitempty,omitzero\"`       // Attributes of the Element node in the form of flat array [name1, value1, name2, value2].\n\tDocumentURL       string            `json:\"documentURL,omitempty,omitzero\"`      // Document URL that Document or FrameOwner node points to.\n\tBaseURL           string            `json:\"baseURL,omitempty,omitzero\"`          // Base URL that Document or FrameOwner node uses for URL completion.\n\tPublicID          string            `json:\"publicId,omitempty,omitzero\"`         // DocumentType's publicId.\n\tSystemID          string            `json:\"systemId,omitempty,omitzero\"`         // DocumentType's systemId.\n\tInternalSubset    string            `json:\"internalSubset,omitempty,omitzero\"`   // DocumentType's internalSubset.\n\tXMLVersion        string            `json:\"xmlVersion,omitempty,omitzero\"`       // Document's XML version in case of XML documents.\n\tName              string            `json:\"name,omitempty,omitzero\"`             // Attr's name.\n\tValue             string            `json:\"value,omitempty,omitzero\"`            // Attr's value.\n\tPseudoType        PseudoType        `json:\"pseudoType,omitempty,omitzero\"`       // Pseudo element type for this node.\n\tPseudoIdentifier  string            `json:\"pseudoIdentifier,omitempty,omitzero\"` // Pseudo element identifier for this node. Only present if there is a valid pseudoType.\n\tShadowRootType    ShadowRootType    `json:\"shadowRootType,omitempty,omitzero\"`   // Shadow root type.\n\tFrameID           FrameID           `json:\"frameId,omitempty,omitzero\"`          // Frame ID for frame owner elements.\n\tContentDocument   *Node             `json:\"contentDocument,omitempty,omitzero\"`  // Content document for frame owner elements.\n\tShadowRoots       []*Node           `json:\"shadowRoots,omitempty,omitzero\"`      // Shadow root list for given element host.\n\tTemplateContent   *Node             `json:\"templateContent,omitempty,omitzero\"`  // Content document fragment for template elements.\n\tPseudoElements    []*Node           `json:\"pseudoElements,omitempty,omitzero\"`   // Pseudo elements associated with this node.\n\tDistributedNodes  []*BackendNode    `json:\"distributedNodes,omitempty,omitzero\"` // Distributed nodes for given insertion point.\n\tIsSVG             bool              `json:\"isSVG\"`                               // Whether the node is SVG.\n\tCompatibilityMode CompatibilityMode `json:\"compatibilityMode,omitempty,omitzero\"`\n\tAssignedSlot      *BackendNode      `json:\"assignedSlot,omitempty,omitzero\"`\n\tIsScrollable      bool              `json:\"isScrollable\"`\n\tParent            *Node             `json:\"-\"` // Parent node.\n\tInvalidated       chan struct{}     `json:\"-\"` // Invalidated channel.\n\tState             NodeState         `json:\"-\"` // Node state.\n\tsync.RWMutex      `json:\"-\"`        // Read write mutex.\n}\n\n// AttributeValue returns the named attribute for the node.\nfunc (n *Node) AttributeValue(name string) string {\n\tvalue, _ := n.Attribute(name)\n\treturn value\n}\n\n// Attribute returns the named attribute for the node and if it exists.\nfunc (n *Node) Attribute(name string) (string, bool) {\n\tn.RLock()\n\tdefer n.RUnlock()\n\n\tfor i := 0; i < len(n.Attributes); i += 2 {\n\t\tif n.Attributes[i] == name {\n\t\t\treturn n.Attributes[i+1], true\n\t\t}\n\t}\n\n\treturn \"\", false\n}\n\n// xpath builds the xpath string.\nfunc (n *Node) xpath(stopAtDocument, stopAtID bool) string {\n\tn.RLock()\n\tdefer n.RUnlock()\n\n\tp, pos, id := \"\", \"\", n.AttributeValue(\"id\")\n\tswitch {\n\tcase n.Parent == nil:\n\t\treturn n.LocalName\n\n\tcase stopAtDocument && n.NodeType == NodeTypeDocument:\n\t\treturn \"\"\n\n\tcase stopAtID && id != \"\":\n\t\tp = \"/\"\n\t\tpos = `[@id='` + id + `']`\n\n\tcase n.Parent != nil:\n\t\tvar i int\n\t\tvar found bool\n\n\t\tn.Parent.RLock()\n\t\tfor j := 0; j < len(n.Parent.Children); j++ {\n\t\t\tif n.Parent.Children[j].LocalName == n.LocalName {\n\t\t\t\ti++\n\t\t\t}\n\t\t\tif n.Parent.Children[j].NodeID == n.NodeID {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tn.Parent.RUnlock()\n\n\t\tif found {\n\t\t\tpos = \"[\" + strconv.Itoa(i) + \"]\"\n\t\t}\n\n\t\tp = n.Parent.xpath(stopAtDocument, stopAtID)\n\t}\n\n\tlocalName := n.LocalName\n\tif n.IsSVG {\n\t\tlocalName = `*[local-name()='` + localName + `']`\n\t}\n\treturn p + \"/\" + localName + pos\n}\n\n// PartialXPathByID returns the partial XPath for the node, stopping at the\n// first parent with an id attribute or at nearest parent document node.\nfunc (n *Node) PartialXPathByID() string {\n\treturn n.xpath(true, true)\n}\n\n// PartialXPath returns the partial XPath for the node, stopping at the nearest\n// parent document node.\nfunc (n *Node) PartialXPath() string {\n\treturn n.xpath(true, false)\n}\n\n// FullXPathByID returns the full XPath for the node, stopping at the top most\n// document root or at the closest parent node with an id attribute.\nfunc (n *Node) FullXPathByID() string {\n\treturn n.xpath(false, true)\n}\n\n// FullXPath returns the full XPath for the node, stopping only at the top most\n// document root.\nfunc (n *Node) FullXPath() string {\n\treturn n.xpath(false, false)\n}\n\n// WriteTo writes a readable representation of the node and all its children to w.\nfunc (n *Node) WriteTo(w io.Writer, prefix, indent string, nodeIDs bool) (int, error) {\n\tif n == nil {\n\t\treturn w.Write([]byte(prefix + \"<nil>\"))\n\t}\n\n\tn.RLock()\n\tdefer n.RUnlock()\n\n\tvar err error\n\tvar nn, c int\n\n\t// prefix\n\tif c, err = w.Write([]byte(prefix)); err != nil {\n\t\treturn nn + c, err\n\t}\n\tnn += c\n\n\t// node name\n\tif n.LocalName != \"\" {\n\t\tif c, err = w.Write([]byte(n.LocalName)); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t} else {\n\t\tif c, err = w.Write([]byte(n.NodeName)); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t}\n\n\t// add #id\n\tvar hasID int\n\tfor i := 0; i < len(n.Attributes); i += 2 {\n\t\tif strings.ToLower(n.Attributes[i]) == \"id\" {\n\t\t\tif c, err = w.Write([]byte(\"#\" + n.Attributes[i+1])); err != nil {\n\t\t\t\treturn nn + c, err\n\t\t\t}\n\t\t\tnn += c\n\t\t\thasID = 2\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// node type\n\tif n.NodeType != NodeTypeElement && n.NodeType != NodeTypeText {\n\t\tif c, err = fmt.Fprintf(w, \" <%s>\", n.NodeType); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t}\n\n\t// node value\n\tif n.NodeType == NodeTypeText {\n\t\tv := n.NodeValue\n\t\tif len(v) > 15 {\n\t\t\tv = v[:15] + \"...\"\n\t\t}\n\t\tif c, err = fmt.Fprintf(w, \" %q\", v); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t}\n\n\t// attributes\n\tif n.NodeType == NodeTypeElement && len(n.Attributes) > hasID {\n\t\tif c, err = w.Write([]byte(\" [\")); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t\tfor i, space := 0, \"\"; i < len(n.Attributes); i += 2 {\n\t\t\tif strings.ToLower(n.Attributes[i]) == \"id\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif c, err = fmt.Fprintf(w, \"%s%s=%q\", space, n.Attributes[i], n.Attributes[i+1]); err != nil {\n\t\t\t\treturn nn + c, err\n\t\t\t}\n\t\t\tnn += c\n\t\t\tif space == \"\" {\n\t\t\t\tspace = \" \"\n\t\t\t}\n\t\t}\n\t\tif c, err = w.Write([]byte{']'}); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t}\n\n\t// node id\n\tif nodeIDs {\n\t\tif c, err = fmt.Fprintf(w, \" (%d)\", n.NodeID); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t}\n\n\t// children\n\tfor i := 0; i < len(n.Children); i++ {\n\t\tif c, err = fmt.Fprintln(w); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t\tif c, err = n.Children[i].WriteTo(w, prefix+indent, indent, nodeIDs); err != nil {\n\t\t\treturn nn + c, err\n\t\t}\n\t\tnn += c\n\t}\n\treturn nn, nil\n}\n\n// Dump builds a printable string representation of the node and its children.\nfunc (n *Node) Dump(prefix, indent string, nodeIDs bool) string {\n\tvar buf bytes.Buffer\n\t_, _ = n.WriteTo(&buf, prefix, indent, nodeIDs)\n\treturn buf.String()\n}\n\n// NodeState is the state of a DOM node.\ntype NodeState uint8\n\n// NodeState enum values.\nconst (\n\tNodeReady NodeState = 1 << (7 - iota)\n\tNodeVisible\n\tNodeHighlighted\n)\n\n// nodeStateNames are the names of the node states.\nvar nodeStateNames = map[NodeState]string{\n\tNodeReady:       \"Ready\",\n\tNodeVisible:     \"Visible\",\n\tNodeHighlighted: \"Highlighted\",\n}\n\n// String satisfies stringer interface.\nfunc (ns NodeState) String() string {\n\tvar s []string\n\tfor k, v := range nodeStateNames {\n\t\tif ns&k != 0 {\n\t\t\ts = append(s, v)\n\t\t}\n\t}\n\treturn \"[\" + strings.Join(s, \" \") + \"]\"\n}\n\n// EmptyNodeID is the \"non-existent\" node id.\nconst EmptyNodeID = NodeID(0)\n\n// RGBA a structure holding an RGBA color.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-RGBA\ntype RGBA struct {\n\tR int64   `json:\"r\"` // The red component, in the [0-255] range.\n\tG int64   `json:\"g\"` // The green component, in the [0-255] range.\n\tB int64   `json:\"b\"` // The blue component, in the [0-255] range.\n\tA float64 `json:\"a\"` // The alpha component, in the [0-1] range (default: 1).\n}\n\n// NodeType node type.\n//\n// See: https://developer.mozilla.org/en/docs/Web/API/Node/nodeType\ntype NodeType int64\n\n// Int64 returns the NodeType as int64 value.\nfunc (t NodeType) Int64() int64 {\n\treturn int64(t)\n}\n\n// NodeType values.\nconst (\n\tNodeTypeElement               NodeType = 1\n\tNodeTypeAttribute             NodeType = 2\n\tNodeTypeText                  NodeType = 3\n\tNodeTypeCDATA                 NodeType = 4\n\tNodeTypeEntityReference       NodeType = 5\n\tNodeTypeEntity                NodeType = 6\n\tNodeTypeProcessingInstruction NodeType = 7\n\tNodeTypeComment               NodeType = 8\n\tNodeTypeDocument              NodeType = 9\n\tNodeTypeDocumentType          NodeType = 10\n\tNodeTypeDocumentFragment      NodeType = 11\n\tNodeTypeNotation              NodeType = 12\n)\n\n// String satisfies the [fmt.Stringer] interface.\nfunc (t NodeType) String() string {\n\tswitch t {\n\tcase NodeTypeElement:\n\t\treturn \"Element\"\n\tcase NodeTypeAttribute:\n\t\treturn \"Attribute\"\n\tcase NodeTypeText:\n\t\treturn \"Text\"\n\tcase NodeTypeCDATA:\n\t\treturn \"CDATA\"\n\tcase NodeTypeEntityReference:\n\t\treturn \"EntityReference\"\n\tcase NodeTypeEntity:\n\t\treturn \"Entity\"\n\tcase NodeTypeProcessingInstruction:\n\t\treturn \"ProcessingInstruction\"\n\tcase NodeTypeComment:\n\t\treturn \"Comment\"\n\tcase NodeTypeDocument:\n\t\treturn \"Document\"\n\tcase NodeTypeDocumentType:\n\t\treturn \"DocumentType\"\n\tcase NodeTypeDocumentFragment:\n\t\treturn \"DocumentFragment\"\n\tcase NodeTypeNotation:\n\t\treturn \"Notation\"\n\t}\n\treturn fmt.Sprintf(\"NodeType(%d)\", t)\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *NodeType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\tv, err := strconv.ParseInt(s, 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\tswitch NodeType(v) {\n\tcase NodeTypeElement:\n\t\t*t = NodeTypeElement\n\tcase NodeTypeAttribute:\n\t\t*t = NodeTypeAttribute\n\tcase NodeTypeText:\n\t\t*t = NodeTypeText\n\tcase NodeTypeCDATA:\n\t\t*t = NodeTypeCDATA\n\tcase NodeTypeEntityReference:\n\t\t*t = NodeTypeEntityReference\n\tcase NodeTypeEntity:\n\t\t*t = NodeTypeEntity\n\tcase NodeTypeProcessingInstruction:\n\t\t*t = NodeTypeProcessingInstruction\n\tcase NodeTypeComment:\n\t\t*t = NodeTypeComment\n\tcase NodeTypeDocument:\n\t\t*t = NodeTypeDocument\n\tcase NodeTypeDocumentType:\n\t\t*t = NodeTypeDocumentType\n\tcase NodeTypeDocumentFragment:\n\t\t*t = NodeTypeDocumentFragment\n\tcase NodeTypeNotation:\n\t\t*t = NodeTypeNotation\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown NodeType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// LoaderID unique loader identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-LoaderId\ntype LoaderID string\n\n// String returns the LoaderID as string value.\nfunc (t LoaderID) String() string {\n\treturn string(t)\n}\n\n// TimeSinceEpoch UTC time in seconds, counted from January 1, 1970.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-TimeSinceEpoch\ntype TimeSinceEpoch time.Time\n\n// Time returns the TimeSinceEpoch as time.Time value.\nfunc (t TimeSinceEpoch) Time() time.Time {\n\treturn time.Time(t)\n}\n\n// MarshalJSON satisfies [json.Marshaler].\nfunc (t TimeSinceEpoch) MarshalJSON() ([]byte, error) {\n\tv := float64(time.Time(t).UnixNano() / int64(time.Second))\n\treturn strconv.AppendFloat(make([]byte, 0, 20), v, 'f', -1, 64), nil\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TimeSinceEpoch) UnmarshalJSON(buf []byte) error {\n\tf, err := strconv.ParseFloat(string(buf), 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*t = TimeSinceEpoch(time.Unix(0, int64(f*float64(time.Second))))\n\treturn nil\n}\n\n// MonotonicTime monotonically increasing time in seconds since an arbitrary\n// point in the past.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-MonotonicTime\ntype MonotonicTime time.Time\n\n// Time returns the MonotonicTime as time.Time value.\nfunc (t MonotonicTime) Time() time.Time {\n\treturn time.Time(t)\n}\n\n// MonotonicTimeEpoch is the MonotonicTime time epoch.\nvar MonotonicTimeEpoch *time.Time\n\nfunc init() {\n\t// initialize epoch\n\tbt := sysutil.BootTime()\n\tMonotonicTimeEpoch = &bt\n}\n\n// MarshalJSON satisfies [json.Marshaler].\nfunc (t MonotonicTime) MarshalJSON() ([]byte, error) {\n\tv := float64(time.Time(t).Sub(*MonotonicTimeEpoch)) / float64(time.Second)\n\treturn strconv.AppendFloat(make([]byte, 0, 20), v, 'f', -1, 64), nil\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MonotonicTime) UnmarshalJSON(buf []byte) error {\n\tf, err := strconv.ParseFloat(string(buf), 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*t = MonotonicTime(MonotonicTimeEpoch.Add(time.Duration(f * float64(time.Second))))\n\treturn nil\n}\n\n// TimeSinceEpochMilli special timestamp type for Response's responseTime\n// field.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-TimeSinceEpochMilli\ntype TimeSinceEpochMilli time.Time\n\n// Time returns the TimeSinceEpochMilli as time.Time value.\nfunc (t TimeSinceEpochMilli) Time() time.Time {\n\treturn time.Time(t)\n}\n\n// MarshalJSON satisfies [json.Marshaler].\nfunc (t TimeSinceEpochMilli) MarshalJSON() ([]byte, error) {\n\tv := float64(time.Time(t).UnixNano() / int64(time.Millisecond))\n\treturn strconv.AppendFloat(make([]byte, 0, 20), v, 'f', -1, 64), nil\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TimeSinceEpochMilli) UnmarshalJSON(buf []byte) error {\n\tf, err := strconv.ParseFloat(string(buf), 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*t = TimeSinceEpochMilli(time.Unix(0, int64(f*float64(time.Millisecond))))\n\treturn nil\n}\n\n// FrameID unique frame identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FrameId\ntype FrameID string\n\n// String returns the FrameID as string value.\nfunc (t FrameID) String() string {\n\treturn string(t)\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *FrameID) UnmarshalJSON(buf []byte) error {\n\tif l := len(buf); l > 2 && buf[0] == '\"' && buf[l-1] == '\"' {\n\t\tbuf = buf[1 : l-1]\n\t}\n\n\t*t = FrameID(buf)\n\treturn nil\n}\n\n// AdFrameType indicates whether a frame has been identified as an ad.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-AdFrameType\ntype AdFrameType string\n\n// String returns the AdFrameType as string value.\nfunc (t AdFrameType) String() string {\n\treturn string(t)\n}\n\n// AdFrameType values.\nconst (\n\tAdFrameTypeNone  AdFrameType = \"none\"\n\tAdFrameTypeChild AdFrameType = \"child\"\n\tAdFrameTypeRoot  AdFrameType = \"root\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AdFrameType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AdFrameType(s) {\n\tcase AdFrameTypeNone:\n\t\t*t = AdFrameTypeNone\n\tcase AdFrameTypeChild:\n\t\t*t = AdFrameTypeChild\n\tcase AdFrameTypeRoot:\n\t\t*t = AdFrameTypeRoot\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AdFrameType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AdFrameExplanation [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-AdFrameExplanation\ntype AdFrameExplanation string\n\n// String returns the AdFrameExplanation as string value.\nfunc (t AdFrameExplanation) String() string {\n\treturn string(t)\n}\n\n// AdFrameExplanation values.\nconst (\n\tAdFrameExplanationParentIsAd          AdFrameExplanation = \"ParentIsAd\"\n\tAdFrameExplanationCreatedByAdScript   AdFrameExplanation = \"CreatedByAdScript\"\n\tAdFrameExplanationMatchedBlockingRule AdFrameExplanation = \"MatchedBlockingRule\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AdFrameExplanation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AdFrameExplanation(s) {\n\tcase AdFrameExplanationParentIsAd:\n\t\t*t = AdFrameExplanationParentIsAd\n\tcase AdFrameExplanationCreatedByAdScript:\n\t\t*t = AdFrameExplanationCreatedByAdScript\n\tcase AdFrameExplanationMatchedBlockingRule:\n\t\t*t = AdFrameExplanationMatchedBlockingRule\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AdFrameExplanation value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AdFrameStatus indicates whether a frame has been identified as an ad and\n// why.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-AdFrameStatus\ntype AdFrameStatus struct {\n\tAdFrameType  AdFrameType          `json:\"adFrameType\"`\n\tExplanations []AdFrameExplanation `json:\"explanations,omitempty,omitzero\"`\n}\n\n// SecureContextType indicates whether the frame is a secure context and why\n// it is the case.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-SecureContextType\ntype SecureContextType string\n\n// String returns the SecureContextType as string value.\nfunc (t SecureContextType) String() string {\n\treturn string(t)\n}\n\n// SecureContextType values.\nconst (\n\tSecureContextTypeSecure           SecureContextType = \"Secure\"\n\tSecureContextTypeSecureLocalhost  SecureContextType = \"SecureLocalhost\"\n\tSecureContextTypeInsecureScheme   SecureContextType = \"InsecureScheme\"\n\tSecureContextTypeInsecureAncestor SecureContextType = \"InsecureAncestor\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SecureContextType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SecureContextType(s) {\n\tcase SecureContextTypeSecure:\n\t\t*t = SecureContextTypeSecure\n\tcase SecureContextTypeSecureLocalhost:\n\t\t*t = SecureContextTypeSecureLocalhost\n\tcase SecureContextTypeInsecureScheme:\n\t\t*t = SecureContextTypeInsecureScheme\n\tcase SecureContextTypeInsecureAncestor:\n\t\t*t = SecureContextTypeInsecureAncestor\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SecureContextType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CrossOriginIsolatedContextType indicates whether the frame is cross-origin\n// isolated and why it is the case.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-CrossOriginIsolatedContextType\ntype CrossOriginIsolatedContextType string\n\n// String returns the CrossOriginIsolatedContextType as string value.\nfunc (t CrossOriginIsolatedContextType) String() string {\n\treturn string(t)\n}\n\n// CrossOriginIsolatedContextType values.\nconst (\n\tCrossOriginIsolatedContextTypeIsolated                   CrossOriginIsolatedContextType = \"Isolated\"\n\tCrossOriginIsolatedContextTypeNotIsolated                CrossOriginIsolatedContextType = \"NotIsolated\"\n\tCrossOriginIsolatedContextTypeNotIsolatedFeatureDisabled CrossOriginIsolatedContextType = \"NotIsolatedFeatureDisabled\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CrossOriginIsolatedContextType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CrossOriginIsolatedContextType(s) {\n\tcase CrossOriginIsolatedContextTypeIsolated:\n\t\t*t = CrossOriginIsolatedContextTypeIsolated\n\tcase CrossOriginIsolatedContextTypeNotIsolated:\n\t\t*t = CrossOriginIsolatedContextTypeNotIsolated\n\tcase CrossOriginIsolatedContextTypeNotIsolatedFeatureDisabled:\n\t\t*t = CrossOriginIsolatedContextTypeNotIsolatedFeatureDisabled\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CrossOriginIsolatedContextType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// GatedAPIFeatures [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-GatedAPIFeatures\ntype GatedAPIFeatures string\n\n// String returns the GatedAPIFeatures as string value.\nfunc (t GatedAPIFeatures) String() string {\n\treturn string(t)\n}\n\n// GatedAPIFeatures values.\nconst (\n\tGatedAPIFeaturesSharedArrayBuffers                GatedAPIFeatures = \"SharedArrayBuffers\"\n\tGatedAPIFeaturesSharedArrayBuffersTransferAllowed GatedAPIFeatures = \"SharedArrayBuffersTransferAllowed\"\n\tGatedAPIFeaturesPerformanceMeasureMemory          GatedAPIFeatures = \"PerformanceMeasureMemory\"\n\tGatedAPIFeaturesPerformanceProfile                GatedAPIFeatures = \"PerformanceProfile\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *GatedAPIFeatures) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch GatedAPIFeatures(s) {\n\tcase GatedAPIFeaturesSharedArrayBuffers:\n\t\t*t = GatedAPIFeaturesSharedArrayBuffers\n\tcase GatedAPIFeaturesSharedArrayBuffersTransferAllowed:\n\t\t*t = GatedAPIFeaturesSharedArrayBuffersTransferAllowed\n\tcase GatedAPIFeaturesPerformanceMeasureMemory:\n\t\t*t = GatedAPIFeaturesPerformanceMeasureMemory\n\tcase GatedAPIFeaturesPerformanceProfile:\n\t\t*t = GatedAPIFeaturesPerformanceProfile\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown GatedAPIFeatures value: %v\", s)\n\t}\n\treturn nil\n}\n\n// OriginTrialTokenStatus origin\n// Trial(https://www.chromium.org/blink/origin-trials) support. Status for an\n// Origin Trial token.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-OriginTrialTokenStatus\ntype OriginTrialTokenStatus string\n\n// String returns the OriginTrialTokenStatus as string value.\nfunc (t OriginTrialTokenStatus) String() string {\n\treturn string(t)\n}\n\n// OriginTrialTokenStatus values.\nconst (\n\tOriginTrialTokenStatusSuccess                OriginTrialTokenStatus = \"Success\"\n\tOriginTrialTokenStatusNotSupported           OriginTrialTokenStatus = \"NotSupported\"\n\tOriginTrialTokenStatusInsecure               OriginTrialTokenStatus = \"Insecure\"\n\tOriginTrialTokenStatusExpired                OriginTrialTokenStatus = \"Expired\"\n\tOriginTrialTokenStatusWrongOrigin            OriginTrialTokenStatus = \"WrongOrigin\"\n\tOriginTrialTokenStatusInvalidSignature       OriginTrialTokenStatus = \"InvalidSignature\"\n\tOriginTrialTokenStatusMalformed              OriginTrialTokenStatus = \"Malformed\"\n\tOriginTrialTokenStatusWrongVersion           OriginTrialTokenStatus = \"WrongVersion\"\n\tOriginTrialTokenStatusFeatureDisabled        OriginTrialTokenStatus = \"FeatureDisabled\"\n\tOriginTrialTokenStatusTokenDisabled          OriginTrialTokenStatus = \"TokenDisabled\"\n\tOriginTrialTokenStatusFeatureDisabledForUser OriginTrialTokenStatus = \"FeatureDisabledForUser\"\n\tOriginTrialTokenStatusUnknownTrial           OriginTrialTokenStatus = \"UnknownTrial\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *OriginTrialTokenStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch OriginTrialTokenStatus(s) {\n\tcase OriginTrialTokenStatusSuccess:\n\t\t*t = OriginTrialTokenStatusSuccess\n\tcase OriginTrialTokenStatusNotSupported:\n\t\t*t = OriginTrialTokenStatusNotSupported\n\tcase OriginTrialTokenStatusInsecure:\n\t\t*t = OriginTrialTokenStatusInsecure\n\tcase OriginTrialTokenStatusExpired:\n\t\t*t = OriginTrialTokenStatusExpired\n\tcase OriginTrialTokenStatusWrongOrigin:\n\t\t*t = OriginTrialTokenStatusWrongOrigin\n\tcase OriginTrialTokenStatusInvalidSignature:\n\t\t*t = OriginTrialTokenStatusInvalidSignature\n\tcase OriginTrialTokenStatusMalformed:\n\t\t*t = OriginTrialTokenStatusMalformed\n\tcase OriginTrialTokenStatusWrongVersion:\n\t\t*t = OriginTrialTokenStatusWrongVersion\n\tcase OriginTrialTokenStatusFeatureDisabled:\n\t\t*t = OriginTrialTokenStatusFeatureDisabled\n\tcase OriginTrialTokenStatusTokenDisabled:\n\t\t*t = OriginTrialTokenStatusTokenDisabled\n\tcase OriginTrialTokenStatusFeatureDisabledForUser:\n\t\t*t = OriginTrialTokenStatusFeatureDisabledForUser\n\tcase OriginTrialTokenStatusUnknownTrial:\n\t\t*t = OriginTrialTokenStatusUnknownTrial\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown OriginTrialTokenStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// OriginTrialStatus status for an Origin Trial.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-OriginTrialStatus\ntype OriginTrialStatus string\n\n// String returns the OriginTrialStatus as string value.\nfunc (t OriginTrialStatus) String() string {\n\treturn string(t)\n}\n\n// OriginTrialStatus values.\nconst (\n\tOriginTrialStatusEnabled               OriginTrialStatus = \"Enabled\"\n\tOriginTrialStatusValidTokenNotProvided OriginTrialStatus = \"ValidTokenNotProvided\"\n\tOriginTrialStatusOSNotSupported        OriginTrialStatus = \"OSNotSupported\"\n\tOriginTrialStatusTrialNotAllowed       OriginTrialStatus = \"TrialNotAllowed\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *OriginTrialStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch OriginTrialStatus(s) {\n\tcase OriginTrialStatusEnabled:\n\t\t*t = OriginTrialStatusEnabled\n\tcase OriginTrialStatusValidTokenNotProvided:\n\t\t*t = OriginTrialStatusValidTokenNotProvided\n\tcase OriginTrialStatusOSNotSupported:\n\t\t*t = OriginTrialStatusOSNotSupported\n\tcase OriginTrialStatusTrialNotAllowed:\n\t\t*t = OriginTrialStatusTrialNotAllowed\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown OriginTrialStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// OriginTrialUsageRestriction [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-OriginTrialUsageRestriction\ntype OriginTrialUsageRestriction string\n\n// String returns the OriginTrialUsageRestriction as string value.\nfunc (t OriginTrialUsageRestriction) String() string {\n\treturn string(t)\n}\n\n// OriginTrialUsageRestriction values.\nconst (\n\tOriginTrialUsageRestrictionNone   OriginTrialUsageRestriction = \"None\"\n\tOriginTrialUsageRestrictionSubset OriginTrialUsageRestriction = \"Subset\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *OriginTrialUsageRestriction) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch OriginTrialUsageRestriction(s) {\n\tcase OriginTrialUsageRestrictionNone:\n\t\t*t = OriginTrialUsageRestrictionNone\n\tcase OriginTrialUsageRestrictionSubset:\n\t\t*t = OriginTrialUsageRestrictionSubset\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown OriginTrialUsageRestriction value: %v\", s)\n\t}\n\treturn nil\n}\n\n// OriginTrialToken [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-OriginTrialToken\ntype OriginTrialToken struct {\n\tOrigin           string                      `json:\"origin\"`\n\tMatchSubDomains  bool                        `json:\"matchSubDomains\"`\n\tTrialName        string                      `json:\"trialName\"`\n\tExpiryTime       *TimeSinceEpoch             `json:\"expiryTime\"`\n\tIsThirdParty     bool                        `json:\"isThirdParty\"`\n\tUsageRestriction OriginTrialUsageRestriction `json:\"usageRestriction\"`\n}\n\n// OriginTrialTokenWithStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-OriginTrialTokenWithStatus\ntype OriginTrialTokenWithStatus struct {\n\tRawTokenText string                 `json:\"rawTokenText\"`\n\tParsedToken  *OriginTrialToken      `json:\"parsedToken,omitempty,omitzero\"` // parsedToken is present only when the token is extractable and parsable.\n\tStatus       OriginTrialTokenStatus `json:\"status\"`\n}\n\n// OriginTrial [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-OriginTrial\ntype OriginTrial struct {\n\tTrialName        string                        `json:\"trialName\"`\n\tStatus           OriginTrialStatus             `json:\"status\"`\n\tTokensWithStatus []*OriginTrialTokenWithStatus `json:\"tokensWithStatus\"`\n}\n\n// SecurityOriginDetails additional information about the frame document's\n// security origin.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-SecurityOriginDetails\ntype SecurityOriginDetails struct {\n\tIsLocalhost bool `json:\"isLocalhost\"` // Indicates whether the frame document's security origin is one of the local hostnames (e.g. \"localhost\") or IP addresses (IPv4 127.0.0.0/8 or IPv6 ::1).\n}\n\n// Frame information about the Frame on the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-Frame\ntype Frame struct {\n\tID                             FrameID                        `json:\"id\"`                                       // Frame unique identifier.\n\tParentID                       FrameID                        `json:\"parentId,omitempty,omitzero\"`              // Parent frame identifier.\n\tLoaderID                       LoaderID                       `json:\"loaderId\"`                                 // Identifier of the loader associated with this frame.\n\tName                           string                         `json:\"name,omitempty,omitzero\"`                  // Frame's name as specified in the tag.\n\tURL                            string                         `json:\"url\"`                                      // Frame document's URL without fragment.\n\tURLFragment                    string                         `json:\"urlFragment,omitempty,omitzero\"`           // Frame document's URL fragment including the '#'.\n\tDomainAndRegistry              string                         `json:\"domainAndRegistry\"`                        // Frame document's registered domain, taking the public suffixes list into account. Extracted from the Frame's url. Example URLs: http://www.google.com/file.html -> \"google.com\" http://a.b.co.uk/file.html      -> \"b.co.uk\"\n\tSecurityOrigin                 string                         `json:\"securityOrigin\"`                           // Frame document's security origin.\n\tSecurityOriginDetails          *SecurityOriginDetails         `json:\"securityOriginDetails,omitempty,omitzero\"` // Additional details about the frame document's security origin.\n\tMimeType                       string                         `json:\"mimeType\"`                                 // Frame document's mimeType as determined by the browser.\n\tUnreachableURL                 string                         `json:\"unreachableUrl,omitempty,omitzero\"`        // If the frame failed to load, this contains the URL that could not be loaded. Note that unlike url above, this URL may contain a fragment.\n\tAdFrameStatus                  *AdFrameStatus                 `json:\"adFrameStatus,omitempty,omitzero\"`         // Indicates whether this frame was tagged as an ad and why.\n\tSecureContextType              SecureContextType              `json:\"secureContextType\"`                        // Indicates whether the main document is a secure context and explains why that is the case.\n\tCrossOriginIsolatedContextType CrossOriginIsolatedContextType `json:\"crossOriginIsolatedContextType\"`           // Indicates whether this is a cross origin isolated context.\n\tGatedAPIFeatures               []GatedAPIFeatures             `json:\"gatedAPIFeatures\"`                         // Indicated which gated APIs / features are available.\n\tState                          FrameState                     `json:\"-\"`                                        // Frame state.\n\tRoot                           *Node                          `json:\"-\"`                                        // Frame document root.\n\tNodes                          map[NodeID]*Node               `json:\"-\"`                                        // Frame nodes.\n\tsync.RWMutex                   `json:\"-\"`                     // Read write mutex.\n}\n\n// FrameState is the state of a Frame.\ntype FrameState uint16\n\n// FrameState enum values.\nconst (\n\tFrameDOMContentEventFired FrameState = 1 << (15 - iota)\n\tFrameLoadEventFired\n\tFrameAttached\n\tFrameNavigated\n\tFrameLoading\n\tFrameScheduledNavigation\n)\n\n// frameStateNames are the names of the frame states.\nvar frameStateNames = map[FrameState]string{\n\tFrameDOMContentEventFired: \"DOMContentEventFired\",\n\tFrameLoadEventFired:       \"LoadEventFired\",\n\tFrameAttached:             \"Attached\",\n\tFrameNavigated:            \"Navigated\",\n\tFrameLoading:              \"Loading\",\n\tFrameScheduledNavigation:  \"ScheduledNavigation\",\n}\n\n// String satisfies stringer interface.\nfunc (fs FrameState) String() string {\n\tvar s []string\n\tfor k, v := range frameStateNames {\n\t\tif fs&k != 0 {\n\t\t\ts = append(s, v)\n\t\t}\n\t}\n\treturn \"[\" + strings.Join(s, \" \") + \"]\"\n}\n\n// EmptyFrameID is the \"non-existent\" frame id.\nconst EmptyFrameID = FrameID(\"\")\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/cdproto.go",
    "content": "// Package cdproto provides the Chrome DevTools Protocol\n// commands, types, and events for the cdproto domain.\n//\n// Chrome DevTools Protocol types.\n//\n// Generated by the cdproto-gen command.\npackage cdproto\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/accessibility\"\n\t\"github.com/chromedp/cdproto/animation\"\n\t\"github.com/chromedp/cdproto/audits\"\n\t\"github.com/chromedp/cdproto/autofill\"\n\t\"github.com/chromedp/cdproto/backgroundservice\"\n\t\"github.com/chromedp/cdproto/bluetoothemulation\"\n\t\"github.com/chromedp/cdproto/browser\"\n\t\"github.com/chromedp/cdproto/cachestorage\"\n\t\"github.com/chromedp/cdproto/cast\"\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/css\"\n\t\"github.com/chromedp/cdproto/debugger\"\n\t\"github.com/chromedp/cdproto/deviceaccess\"\n\t\"github.com/chromedp/cdproto/deviceorientation\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/chromedp/cdproto/domdebugger\"\n\t\"github.com/chromedp/cdproto/domsnapshot\"\n\t\"github.com/chromedp/cdproto/domstorage\"\n\t\"github.com/chromedp/cdproto/emulation\"\n\t\"github.com/chromedp/cdproto/eventbreakpoints\"\n\t\"github.com/chromedp/cdproto/extensions\"\n\t\"github.com/chromedp/cdproto/fedcm\"\n\t\"github.com/chromedp/cdproto/fetch\"\n\t\"github.com/chromedp/cdproto/filesystem\"\n\t\"github.com/chromedp/cdproto/headlessexperimental\"\n\t\"github.com/chromedp/cdproto/heapprofiler\"\n\t\"github.com/chromedp/cdproto/indexeddb\"\n\t\"github.com/chromedp/cdproto/input\"\n\t\"github.com/chromedp/cdproto/inspector\"\n\t\"github.com/chromedp/cdproto/io\"\n\t\"github.com/chromedp/cdproto/layertree\"\n\t\"github.com/chromedp/cdproto/log\"\n\t\"github.com/chromedp/cdproto/media\"\n\t\"github.com/chromedp/cdproto/memory\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/overlay\"\n\t\"github.com/chromedp/cdproto/page\"\n\t\"github.com/chromedp/cdproto/performance\"\n\t\"github.com/chromedp/cdproto/performancetimeline\"\n\t\"github.com/chromedp/cdproto/preload\"\n\t\"github.com/chromedp/cdproto/profiler\"\n\t\"github.com/chromedp/cdproto/pwa\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/chromedp/cdproto/security\"\n\t\"github.com/chromedp/cdproto/serviceworker\"\n\t\"github.com/chromedp/cdproto/storage\"\n\t\"github.com/chromedp/cdproto/systeminfo\"\n\t\"github.com/chromedp/cdproto/target\"\n\t\"github.com/chromedp/cdproto/tethering\"\n\t\"github.com/chromedp/cdproto/tracing\"\n\t\"github.com/chromedp/cdproto/webaudio\"\n\t\"github.com/chromedp/cdproto/webauthn\"\n\tjsonv2 \"github.com/go-json-experiment/json\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// MethodType chrome DevTools Protocol method type (ie, event and command\n// names).\ntype MethodType string\n\n// String returns the MethodType as string value.\nfunc (t MethodType) String() string {\n\treturn string(t)\n}\n\n// Domain returns the Chrome DevTools Protocol domain of the event or command.\nfunc (t MethodType) Domain() string {\n\treturn string(t[:strings.IndexByte(string(t), '.')])\n}\n\n// MethodType values.\nconst (\n\tCommandAccessibilityDisable                                      = accessibility.CommandDisable\n\tCommandAccessibilityEnable                                       = accessibility.CommandEnable\n\tCommandAccessibilityGetPartialAXTree                             = accessibility.CommandGetPartialAXTree\n\tCommandAccessibilityGetFullAXTree                                = accessibility.CommandGetFullAXTree\n\tCommandAccessibilityGetRootAXNode                                = accessibility.CommandGetRootAXNode\n\tCommandAccessibilityGetAXNodeAndAncestors                        = accessibility.CommandGetAXNodeAndAncestors\n\tCommandAccessibilityGetChildAXNodes                              = accessibility.CommandGetChildAXNodes\n\tCommandAccessibilityQueryAXTree                                  = accessibility.CommandQueryAXTree\n\tEventAccessibilityLoadComplete                                   = \"Accessibility.loadComplete\"\n\tEventAccessibilityNodesUpdated                                   = \"Accessibility.nodesUpdated\"\n\tCommandAnimationDisable                                          = animation.CommandDisable\n\tCommandAnimationEnable                                           = animation.CommandEnable\n\tCommandAnimationGetCurrentTime                                   = animation.CommandGetCurrentTime\n\tCommandAnimationGetPlaybackRate                                  = animation.CommandGetPlaybackRate\n\tCommandAnimationReleaseAnimations                                = animation.CommandReleaseAnimations\n\tCommandAnimationResolveAnimation                                 = animation.CommandResolveAnimation\n\tCommandAnimationSeekAnimations                                   = animation.CommandSeekAnimations\n\tCommandAnimationSetPaused                                        = animation.CommandSetPaused\n\tCommandAnimationSetPlaybackRate                                  = animation.CommandSetPlaybackRate\n\tCommandAnimationSetTiming                                        = animation.CommandSetTiming\n\tEventAnimationAnimationCanceled                                  = \"Animation.animationCanceled\"\n\tEventAnimationAnimationCreated                                   = \"Animation.animationCreated\"\n\tEventAnimationAnimationStarted                                   = \"Animation.animationStarted\"\n\tEventAnimationAnimationUpdated                                   = \"Animation.animationUpdated\"\n\tCommandAuditsGetEncodedResponse                                  = audits.CommandGetEncodedResponse\n\tCommandAuditsDisable                                             = audits.CommandDisable\n\tCommandAuditsEnable                                              = audits.CommandEnable\n\tCommandAuditsCheckContrast                                       = audits.CommandCheckContrast\n\tCommandAuditsCheckFormsIssues                                    = audits.CommandCheckFormsIssues\n\tEventAuditsIssueAdded                                            = \"Audits.issueAdded\"\n\tCommandAutofillTrigger                                           = autofill.CommandTrigger\n\tCommandAutofillSetAddresses                                      = autofill.CommandSetAddresses\n\tCommandAutofillDisable                                           = autofill.CommandDisable\n\tCommandAutofillEnable                                            = autofill.CommandEnable\n\tEventAutofillAddressFormFilled                                   = \"Autofill.addressFormFilled\"\n\tCommandBackgroundServiceStartObserving                           = backgroundservice.CommandStartObserving\n\tCommandBackgroundServiceStopObserving                            = backgroundservice.CommandStopObserving\n\tCommandBackgroundServiceSetRecording                             = backgroundservice.CommandSetRecording\n\tCommandBackgroundServiceClearEvents                              = backgroundservice.CommandClearEvents\n\tEventBackgroundServiceRecordingStateChanged                      = \"BackgroundService.recordingStateChanged\"\n\tEventBackgroundServiceBackgroundServiceEventReceived             = \"BackgroundService.backgroundServiceEventReceived\"\n\tCommandBluetoothEmulationEnable                                  = bluetoothemulation.CommandEnable\n\tCommandBluetoothEmulationSetSimulatedCentralState                = bluetoothemulation.CommandSetSimulatedCentralState\n\tCommandBluetoothEmulationDisable                                 = bluetoothemulation.CommandDisable\n\tCommandBluetoothEmulationSimulatePreconnectedPeripheral          = bluetoothemulation.CommandSimulatePreconnectedPeripheral\n\tCommandBluetoothEmulationSimulateAdvertisement                   = bluetoothemulation.CommandSimulateAdvertisement\n\tCommandBluetoothEmulationSimulateGATTOperationResponse           = bluetoothemulation.CommandSimulateGATTOperationResponse\n\tCommandBluetoothEmulationSimulateCharacteristicOperationResponse = bluetoothemulation.CommandSimulateCharacteristicOperationResponse\n\tCommandBluetoothEmulationSimulateDescriptorOperationResponse     = bluetoothemulation.CommandSimulateDescriptorOperationResponse\n\tCommandBluetoothEmulationAddService                              = bluetoothemulation.CommandAddService\n\tCommandBluetoothEmulationRemoveService                           = bluetoothemulation.CommandRemoveService\n\tCommandBluetoothEmulationAddCharacteristic                       = bluetoothemulation.CommandAddCharacteristic\n\tCommandBluetoothEmulationRemoveCharacteristic                    = bluetoothemulation.CommandRemoveCharacteristic\n\tCommandBluetoothEmulationAddDescriptor                           = bluetoothemulation.CommandAddDescriptor\n\tCommandBluetoothEmulationRemoveDescriptor                        = bluetoothemulation.CommandRemoveDescriptor\n\tCommandBluetoothEmulationSimulateGATTDisconnection               = bluetoothemulation.CommandSimulateGATTDisconnection\n\tEventBluetoothEmulationGattOperationReceived                     = \"BluetoothEmulation.gattOperationReceived\"\n\tEventBluetoothEmulationCharacteristicOperationReceived           = \"BluetoothEmulation.characteristicOperationReceived\"\n\tEventBluetoothEmulationDescriptorOperationReceived               = \"BluetoothEmulation.descriptorOperationReceived\"\n\tCommandBrowserSetPermission                                      = browser.CommandSetPermission\n\tCommandBrowserGrantPermissions                                   = browser.CommandGrantPermissions\n\tCommandBrowserResetPermissions                                   = browser.CommandResetPermissions\n\tCommandBrowserSetDownloadBehavior                                = browser.CommandSetDownloadBehavior\n\tCommandBrowserCancelDownload                                     = browser.CommandCancelDownload\n\tCommandBrowserClose                                              = browser.CommandClose\n\tCommandBrowserCrash                                              = browser.CommandCrash\n\tCommandBrowserCrashGPUProcess                                    = browser.CommandCrashGPUProcess\n\tCommandBrowserGetVersion                                         = browser.CommandGetVersion\n\tCommandBrowserGetBrowserCommandLine                              = browser.CommandGetBrowserCommandLine\n\tCommandBrowserGetHistograms                                      = browser.CommandGetHistograms\n\tCommandBrowserGetHistogram                                       = browser.CommandGetHistogram\n\tCommandBrowserGetWindowBounds                                    = browser.CommandGetWindowBounds\n\tCommandBrowserGetWindowForTarget                                 = browser.CommandGetWindowForTarget\n\tCommandBrowserSetWindowBounds                                    = browser.CommandSetWindowBounds\n\tCommandBrowserSetContentsSize                                    = browser.CommandSetContentsSize\n\tCommandBrowserSetDockTile                                        = browser.CommandSetDockTile\n\tCommandBrowserExecuteBrowserCommand                              = browser.CommandExecuteBrowserCommand\n\tCommandBrowserAddPrivacySandboxEnrollmentOverride                = browser.CommandAddPrivacySandboxEnrollmentOverride\n\tCommandBrowserAddPrivacySandboxCoordinatorKeyConfig              = browser.CommandAddPrivacySandboxCoordinatorKeyConfig\n\tEventBrowserDownloadWillBegin                                    = \"Browser.downloadWillBegin\"\n\tEventBrowserDownloadProgress                                     = \"Browser.downloadProgress\"\n\tCommandCSSAddRule                                                = css.CommandAddRule\n\tCommandCSSCollectClassNames                                      = css.CommandCollectClassNames\n\tCommandCSSCreateStyleSheet                                       = css.CommandCreateStyleSheet\n\tCommandCSSDisable                                                = css.CommandDisable\n\tCommandCSSEnable                                                 = css.CommandEnable\n\tCommandCSSForcePseudoState                                       = css.CommandForcePseudoState\n\tCommandCSSForceStartingStyle                                     = css.CommandForceStartingStyle\n\tCommandCSSGetBackgroundColors                                    = css.CommandGetBackgroundColors\n\tCommandCSSGetComputedStyleForNode                                = css.CommandGetComputedStyleForNode\n\tCommandCSSResolveValues                                          = css.CommandResolveValues\n\tCommandCSSGetLonghandProperties                                  = css.CommandGetLonghandProperties\n\tCommandCSSGetInlineStylesForNode                                 = css.CommandGetInlineStylesForNode\n\tCommandCSSGetAnimatedStylesForNode                               = css.CommandGetAnimatedStylesForNode\n\tCommandCSSGetMatchedStylesForNode                                = css.CommandGetMatchedStylesForNode\n\tCommandCSSGetEnvironmentVariables                                = css.CommandGetEnvironmentVariables\n\tCommandCSSGetMediaQueries                                        = css.CommandGetMediaQueries\n\tCommandCSSGetPlatformFontsForNode                                = css.CommandGetPlatformFontsForNode\n\tCommandCSSGetStyleSheetText                                      = css.CommandGetStyleSheetText\n\tCommandCSSGetLayersForNode                                       = css.CommandGetLayersForNode\n\tCommandCSSGetLocationForSelector                                 = css.CommandGetLocationForSelector\n\tCommandCSSTrackComputedStyleUpdatesForNode                       = css.CommandTrackComputedStyleUpdatesForNode\n\tCommandCSSTrackComputedStyleUpdates                              = css.CommandTrackComputedStyleUpdates\n\tCommandCSSTakeComputedStyleUpdates                               = css.CommandTakeComputedStyleUpdates\n\tCommandCSSSetEffectivePropertyValueForNode                       = css.CommandSetEffectivePropertyValueForNode\n\tCommandCSSSetPropertyRulePropertyName                            = css.CommandSetPropertyRulePropertyName\n\tCommandCSSSetKeyframeKey                                         = css.CommandSetKeyframeKey\n\tCommandCSSSetMediaText                                           = css.CommandSetMediaText\n\tCommandCSSSetContainerQueryText                                  = css.CommandSetContainerQueryText\n\tCommandCSSSetSupportsText                                        = css.CommandSetSupportsText\n\tCommandCSSSetScopeText                                           = css.CommandSetScopeText\n\tCommandCSSSetRuleSelector                                        = css.CommandSetRuleSelector\n\tCommandCSSSetStyleSheetText                                      = css.CommandSetStyleSheetText\n\tCommandCSSSetStyleTexts                                          = css.CommandSetStyleTexts\n\tCommandCSSStartRuleUsageTracking                                 = css.CommandStartRuleUsageTracking\n\tCommandCSSStopRuleUsageTracking                                  = css.CommandStopRuleUsageTracking\n\tCommandCSSTakeCoverageDelta                                      = css.CommandTakeCoverageDelta\n\tCommandCSSSetLocalFontsEnabled                                   = css.CommandSetLocalFontsEnabled\n\tEventCSSFontsUpdated                                             = \"CSS.fontsUpdated\"\n\tEventCSSMediaQueryResultChanged                                  = \"CSS.mediaQueryResultChanged\"\n\tEventCSSStyleSheetAdded                                          = \"CSS.styleSheetAdded\"\n\tEventCSSStyleSheetChanged                                        = \"CSS.styleSheetChanged\"\n\tEventCSSStyleSheetRemoved                                        = \"CSS.styleSheetRemoved\"\n\tEventCSSComputedStyleUpdated                                     = \"CSS.computedStyleUpdated\"\n\tCommandCacheStorageDeleteCache                                   = cachestorage.CommandDeleteCache\n\tCommandCacheStorageDeleteEntry                                   = cachestorage.CommandDeleteEntry\n\tCommandCacheStorageRequestCacheNames                             = cachestorage.CommandRequestCacheNames\n\tCommandCacheStorageRequestCachedResponse                         = cachestorage.CommandRequestCachedResponse\n\tCommandCacheStorageRequestEntries                                = cachestorage.CommandRequestEntries\n\tCommandCastEnable                                                = cast.CommandEnable\n\tCommandCastDisable                                               = cast.CommandDisable\n\tCommandCastSetSinkToUse                                          = cast.CommandSetSinkToUse\n\tCommandCastStartDesktopMirroring                                 = cast.CommandStartDesktopMirroring\n\tCommandCastStartTabMirroring                                     = cast.CommandStartTabMirroring\n\tCommandCastStopCasting                                           = cast.CommandStopCasting\n\tEventCastSinksUpdated                                            = \"Cast.sinksUpdated\"\n\tEventCastIssueUpdated                                            = \"Cast.issueUpdated\"\n\tCommandDOMCollectClassNamesFromSubtree                           = dom.CommandCollectClassNamesFromSubtree\n\tCommandDOMCopyTo                                                 = dom.CommandCopyTo\n\tCommandDOMDescribeNode                                           = dom.CommandDescribeNode\n\tCommandDOMScrollIntoViewIfNeeded                                 = dom.CommandScrollIntoViewIfNeeded\n\tCommandDOMDisable                                                = dom.CommandDisable\n\tCommandDOMDiscardSearchResults                                   = dom.CommandDiscardSearchResults\n\tCommandDOMEnable                                                 = dom.CommandEnable\n\tCommandDOMFocus                                                  = dom.CommandFocus\n\tCommandDOMGetAttributes                                          = dom.CommandGetAttributes\n\tCommandDOMGetBoxModel                                            = dom.CommandGetBoxModel\n\tCommandDOMGetContentQuads                                        = dom.CommandGetContentQuads\n\tCommandDOMGetDocument                                            = dom.CommandGetDocument\n\tCommandDOMGetNodesForSubtreeByStyle                              = dom.CommandGetNodesForSubtreeByStyle\n\tCommandDOMGetNodeForLocation                                     = dom.CommandGetNodeForLocation\n\tCommandDOMGetOuterHTML                                           = dom.CommandGetOuterHTML\n\tCommandDOMGetRelayoutBoundary                                    = dom.CommandGetRelayoutBoundary\n\tCommandDOMGetSearchResults                                       = dom.CommandGetSearchResults\n\tCommandDOMMarkUndoableState                                      = dom.CommandMarkUndoableState\n\tCommandDOMMoveTo                                                 = dom.CommandMoveTo\n\tCommandDOMPerformSearch                                          = dom.CommandPerformSearch\n\tCommandDOMPushNodeByPathToFrontend                               = dom.CommandPushNodeByPathToFrontend\n\tCommandDOMPushNodesByBackendIDsToFrontend                        = dom.CommandPushNodesByBackendIDsToFrontend\n\tCommandDOMQuerySelector                                          = dom.CommandQuerySelector\n\tCommandDOMQuerySelectorAll                                       = dom.CommandQuerySelectorAll\n\tCommandDOMGetTopLayerElements                                    = dom.CommandGetTopLayerElements\n\tCommandDOMGetElementByRelation                                   = dom.CommandGetElementByRelation\n\tCommandDOMRedo                                                   = dom.CommandRedo\n\tCommandDOMRemoveAttribute                                        = dom.CommandRemoveAttribute\n\tCommandDOMRemoveNode                                             = dom.CommandRemoveNode\n\tCommandDOMRequestChildNodes                                      = dom.CommandRequestChildNodes\n\tCommandDOMRequestNode                                            = dom.CommandRequestNode\n\tCommandDOMResolveNode                                            = dom.CommandResolveNode\n\tCommandDOMSetAttributeValue                                      = dom.CommandSetAttributeValue\n\tCommandDOMSetAttributesAsText                                    = dom.CommandSetAttributesAsText\n\tCommandDOMSetFileInputFiles                                      = dom.CommandSetFileInputFiles\n\tCommandDOMSetNodeStackTracesEnabled                              = dom.CommandSetNodeStackTracesEnabled\n\tCommandDOMGetNodeStackTraces                                     = dom.CommandGetNodeStackTraces\n\tCommandDOMGetFileInfo                                            = dom.CommandGetFileInfo\n\tCommandDOMGetDetachedDomNodes                                    = dom.CommandGetDetachedDomNodes\n\tCommandDOMSetInspectedNode                                       = dom.CommandSetInspectedNode\n\tCommandDOMSetNodeName                                            = dom.CommandSetNodeName\n\tCommandDOMSetNodeValue                                           = dom.CommandSetNodeValue\n\tCommandDOMSetOuterHTML                                           = dom.CommandSetOuterHTML\n\tCommandDOMUndo                                                   = dom.CommandUndo\n\tCommandDOMGetFrameOwner                                          = dom.CommandGetFrameOwner\n\tCommandDOMGetContainerForNode                                    = dom.CommandGetContainerForNode\n\tCommandDOMGetQueryingDescendantsForContainer                     = dom.CommandGetQueryingDescendantsForContainer\n\tCommandDOMGetAnchorElement                                       = dom.CommandGetAnchorElement\n\tCommandDOMForceShowPopover                                       = dom.CommandForceShowPopover\n\tEventDOMAttributeModified                                        = \"DOM.attributeModified\"\n\tEventDOMAttributeRemoved                                         = \"DOM.attributeRemoved\"\n\tEventDOMCharacterDataModified                                    = \"DOM.characterDataModified\"\n\tEventDOMChildNodeCountUpdated                                    = \"DOM.childNodeCountUpdated\"\n\tEventDOMChildNodeInserted                                        = \"DOM.childNodeInserted\"\n\tEventDOMChildNodeRemoved                                         = \"DOM.childNodeRemoved\"\n\tEventDOMDistributedNodesUpdated                                  = \"DOM.distributedNodesUpdated\"\n\tEventDOMDocumentUpdated                                          = \"DOM.documentUpdated\"\n\tEventDOMInlineStyleInvalidated                                   = \"DOM.inlineStyleInvalidated\"\n\tEventDOMPseudoElementAdded                                       = \"DOM.pseudoElementAdded\"\n\tEventDOMTopLayerElementsUpdated                                  = \"DOM.topLayerElementsUpdated\"\n\tEventDOMScrollableFlagUpdated                                    = \"DOM.scrollableFlagUpdated\"\n\tEventDOMPseudoElementRemoved                                     = \"DOM.pseudoElementRemoved\"\n\tEventDOMSetChildNodes                                            = \"DOM.setChildNodes\"\n\tEventDOMShadowRootPopped                                         = \"DOM.shadowRootPopped\"\n\tEventDOMShadowRootPushed                                         = \"DOM.shadowRootPushed\"\n\tCommandDOMDebuggerGetEventListeners                              = domdebugger.CommandGetEventListeners\n\tCommandDOMDebuggerRemoveDOMBreakpoint                            = domdebugger.CommandRemoveDOMBreakpoint\n\tCommandDOMDebuggerRemoveEventListenerBreakpoint                  = domdebugger.CommandRemoveEventListenerBreakpoint\n\tCommandDOMDebuggerRemoveXHRBreakpoint                            = domdebugger.CommandRemoveXHRBreakpoint\n\tCommandDOMDebuggerSetBreakOnCSPViolation                         = domdebugger.CommandSetBreakOnCSPViolation\n\tCommandDOMDebuggerSetDOMBreakpoint                               = domdebugger.CommandSetDOMBreakpoint\n\tCommandDOMDebuggerSetEventListenerBreakpoint                     = domdebugger.CommandSetEventListenerBreakpoint\n\tCommandDOMDebuggerSetXHRBreakpoint                               = domdebugger.CommandSetXHRBreakpoint\n\tCommandDOMSnapshotDisable                                        = domsnapshot.CommandDisable\n\tCommandDOMSnapshotEnable                                         = domsnapshot.CommandEnable\n\tCommandDOMSnapshotCaptureSnapshot                                = domsnapshot.CommandCaptureSnapshot\n\tCommandDOMStorageClear                                           = domstorage.CommandClear\n\tCommandDOMStorageDisable                                         = domstorage.CommandDisable\n\tCommandDOMStorageEnable                                          = domstorage.CommandEnable\n\tCommandDOMStorageGetDOMStorageItems                              = domstorage.CommandGetDOMStorageItems\n\tCommandDOMStorageRemoveDOMStorageItem                            = domstorage.CommandRemoveDOMStorageItem\n\tCommandDOMStorageSetDOMStorageItem                               = domstorage.CommandSetDOMStorageItem\n\tEventDOMStorageDomStorageItemAdded                               = \"DOMStorage.domStorageItemAdded\"\n\tEventDOMStorageDomStorageItemRemoved                             = \"DOMStorage.domStorageItemRemoved\"\n\tEventDOMStorageDomStorageItemUpdated                             = \"DOMStorage.domStorageItemUpdated\"\n\tEventDOMStorageDomStorageItemsCleared                            = \"DOMStorage.domStorageItemsCleared\"\n\tCommandDebuggerContinueToLocation                                = debugger.CommandContinueToLocation\n\tCommandDebuggerDisable                                           = debugger.CommandDisable\n\tCommandDebuggerEnable                                            = debugger.CommandEnable\n\tCommandDebuggerEvaluateOnCallFrame                               = debugger.CommandEvaluateOnCallFrame\n\tCommandDebuggerGetPossibleBreakpoints                            = debugger.CommandGetPossibleBreakpoints\n\tCommandDebuggerGetScriptSource                                   = debugger.CommandGetScriptSource\n\tCommandDebuggerDisassembleWasmModule                             = debugger.CommandDisassembleWasmModule\n\tCommandDebuggerNextWasmDisassemblyChunk                          = debugger.CommandNextWasmDisassemblyChunk\n\tCommandDebuggerGetStackTrace                                     = debugger.CommandGetStackTrace\n\tCommandDebuggerPause                                             = debugger.CommandPause\n\tCommandDebuggerRemoveBreakpoint                                  = debugger.CommandRemoveBreakpoint\n\tCommandDebuggerRestartFrame                                      = debugger.CommandRestartFrame\n\tCommandDebuggerResume                                            = debugger.CommandResume\n\tCommandDebuggerSearchInContent                                   = debugger.CommandSearchInContent\n\tCommandDebuggerSetAsyncCallStackDepth                            = debugger.CommandSetAsyncCallStackDepth\n\tCommandDebuggerSetBlackboxExecutionContexts                      = debugger.CommandSetBlackboxExecutionContexts\n\tCommandDebuggerSetBlackboxPatterns                               = debugger.CommandSetBlackboxPatterns\n\tCommandDebuggerSetBlackboxedRanges                               = debugger.CommandSetBlackboxedRanges\n\tCommandDebuggerSetBreakpoint                                     = debugger.CommandSetBreakpoint\n\tCommandDebuggerSetInstrumentationBreakpoint                      = debugger.CommandSetInstrumentationBreakpoint\n\tCommandDebuggerSetBreakpointByURL                                = debugger.CommandSetBreakpointByURL\n\tCommandDebuggerSetBreakpointOnFunctionCall                       = debugger.CommandSetBreakpointOnFunctionCall\n\tCommandDebuggerSetBreakpointsActive                              = debugger.CommandSetBreakpointsActive\n\tCommandDebuggerSetPauseOnExceptions                              = debugger.CommandSetPauseOnExceptions\n\tCommandDebuggerSetReturnValue                                    = debugger.CommandSetReturnValue\n\tCommandDebuggerSetScriptSource                                   = debugger.CommandSetScriptSource\n\tCommandDebuggerSetSkipAllPauses                                  = debugger.CommandSetSkipAllPauses\n\tCommandDebuggerSetVariableValue                                  = debugger.CommandSetVariableValue\n\tCommandDebuggerStepInto                                          = debugger.CommandStepInto\n\tCommandDebuggerStepOut                                           = debugger.CommandStepOut\n\tCommandDebuggerStepOver                                          = debugger.CommandStepOver\n\tEventDebuggerPaused                                              = \"Debugger.paused\"\n\tEventDebuggerResumed                                             = \"Debugger.resumed\"\n\tEventDebuggerScriptFailedToParse                                 = \"Debugger.scriptFailedToParse\"\n\tEventDebuggerScriptParsed                                        = \"Debugger.scriptParsed\"\n\tCommandDeviceAccessEnable                                        = deviceaccess.CommandEnable\n\tCommandDeviceAccessDisable                                       = deviceaccess.CommandDisable\n\tCommandDeviceAccessSelectPrompt                                  = deviceaccess.CommandSelectPrompt\n\tCommandDeviceAccessCancelPrompt                                  = deviceaccess.CommandCancelPrompt\n\tEventDeviceAccessDeviceRequestPrompted                           = \"DeviceAccess.deviceRequestPrompted\"\n\tCommandDeviceOrientationClearDeviceOrientationOverride           = deviceorientation.CommandClearDeviceOrientationOverride\n\tCommandDeviceOrientationSetDeviceOrientationOverride             = deviceorientation.CommandSetDeviceOrientationOverride\n\tCommandEmulationClearDeviceMetricsOverride                       = emulation.CommandClearDeviceMetricsOverride\n\tCommandEmulationClearGeolocationOverride                         = emulation.CommandClearGeolocationOverride\n\tCommandEmulationResetPageScaleFactor                             = emulation.CommandResetPageScaleFactor\n\tCommandEmulationSetFocusEmulationEnabled                         = emulation.CommandSetFocusEmulationEnabled\n\tCommandEmulationSetAutoDarkModeOverride                          = emulation.CommandSetAutoDarkModeOverride\n\tCommandEmulationSetCPUThrottlingRate                             = emulation.CommandSetCPUThrottlingRate\n\tCommandEmulationSetDefaultBackgroundColorOverride                = emulation.CommandSetDefaultBackgroundColorOverride\n\tCommandEmulationSetSafeAreaInsetsOverride                        = emulation.CommandSetSafeAreaInsetsOverride\n\tCommandEmulationSetDeviceMetricsOverride                         = emulation.CommandSetDeviceMetricsOverride\n\tCommandEmulationSetDevicePostureOverride                         = emulation.CommandSetDevicePostureOverride\n\tCommandEmulationClearDevicePostureOverride                       = emulation.CommandClearDevicePostureOverride\n\tCommandEmulationSetDisplayFeaturesOverride                       = emulation.CommandSetDisplayFeaturesOverride\n\tCommandEmulationClearDisplayFeaturesOverride                     = emulation.CommandClearDisplayFeaturesOverride\n\tCommandEmulationSetScrollbarsHidden                              = emulation.CommandSetScrollbarsHidden\n\tCommandEmulationSetDocumentCookieDisabled                        = emulation.CommandSetDocumentCookieDisabled\n\tCommandEmulationSetEmitTouchEventsForMouse                       = emulation.CommandSetEmitTouchEventsForMouse\n\tCommandEmulationSetEmulatedMedia                                 = emulation.CommandSetEmulatedMedia\n\tCommandEmulationSetEmulatedVisionDeficiency                      = emulation.CommandSetEmulatedVisionDeficiency\n\tCommandEmulationSetEmulatedOSTextScale                           = emulation.CommandSetEmulatedOSTextScale\n\tCommandEmulationSetGeolocationOverride                           = emulation.CommandSetGeolocationOverride\n\tCommandEmulationGetOverriddenSensorInformation                   = emulation.CommandGetOverriddenSensorInformation\n\tCommandEmulationSetSensorOverrideEnabled                         = emulation.CommandSetSensorOverrideEnabled\n\tCommandEmulationSetSensorOverrideReadings                        = emulation.CommandSetSensorOverrideReadings\n\tCommandEmulationSetPressureSourceOverrideEnabled                 = emulation.CommandSetPressureSourceOverrideEnabled\n\tCommandEmulationSetPressureStateOverride                         = emulation.CommandSetPressureStateOverride\n\tCommandEmulationSetPressureDataOverride                          = emulation.CommandSetPressureDataOverride\n\tCommandEmulationSetIdleOverride                                  = emulation.CommandSetIdleOverride\n\tCommandEmulationClearIdleOverride                                = emulation.CommandClearIdleOverride\n\tCommandEmulationSetPageScaleFactor                               = emulation.CommandSetPageScaleFactor\n\tCommandEmulationSetScriptExecutionDisabled                       = emulation.CommandSetScriptExecutionDisabled\n\tCommandEmulationSetTouchEmulationEnabled                         = emulation.CommandSetTouchEmulationEnabled\n\tCommandEmulationSetVirtualTimePolicy                             = emulation.CommandSetVirtualTimePolicy\n\tCommandEmulationSetLocaleOverride                                = emulation.CommandSetLocaleOverride\n\tCommandEmulationSetTimezoneOverride                              = emulation.CommandSetTimezoneOverride\n\tCommandEmulationSetDisabledImageTypes                            = emulation.CommandSetDisabledImageTypes\n\tCommandEmulationSetDataSaverOverride                             = emulation.CommandSetDataSaverOverride\n\tCommandEmulationSetHardwareConcurrencyOverride                   = emulation.CommandSetHardwareConcurrencyOverride\n\tCommandEmulationSetUserAgentOverride                             = emulation.CommandSetUserAgentOverride\n\tCommandEmulationSetAutomationOverride                            = emulation.CommandSetAutomationOverride\n\tCommandEmulationSetSmallViewportHeightDifferenceOverride         = emulation.CommandSetSmallViewportHeightDifferenceOverride\n\tEventEmulationVirtualTimeBudgetExpired                           = \"Emulation.virtualTimeBudgetExpired\"\n\tCommandEventBreakpointsSetInstrumentationBreakpoint              = eventbreakpoints.CommandSetInstrumentationBreakpoint\n\tCommandEventBreakpointsRemoveInstrumentationBreakpoint           = eventbreakpoints.CommandRemoveInstrumentationBreakpoint\n\tCommandEventBreakpointsDisable                                   = eventbreakpoints.CommandDisable\n\tCommandExtensionsLoadUnpacked                                    = extensions.CommandLoadUnpacked\n\tCommandExtensionsUninstall                                       = extensions.CommandUninstall\n\tCommandExtensionsGetStorageItems                                 = extensions.CommandGetStorageItems\n\tCommandExtensionsRemoveStorageItems                              = extensions.CommandRemoveStorageItems\n\tCommandExtensionsClearStorageItems                               = extensions.CommandClearStorageItems\n\tCommandExtensionsSetStorageItems                                 = extensions.CommandSetStorageItems\n\tCommandFedCmEnable                                               = fedcm.CommandEnable\n\tCommandFedCmDisable                                              = fedcm.CommandDisable\n\tCommandFedCmSelectAccount                                        = fedcm.CommandSelectAccount\n\tCommandFedCmClickDialogButton                                    = fedcm.CommandClickDialogButton\n\tCommandFedCmOpenURL                                              = fedcm.CommandOpenURL\n\tCommandFedCmDismissDialog                                        = fedcm.CommandDismissDialog\n\tCommandFedCmResetCooldown                                        = fedcm.CommandResetCooldown\n\tEventFedCmDialogShown                                            = \"FedCm.dialogShown\"\n\tEventFedCmDialogClosed                                           = \"FedCm.dialogClosed\"\n\tCommandFetchDisable                                              = fetch.CommandDisable\n\tCommandFetchEnable                                               = fetch.CommandEnable\n\tCommandFetchFailRequest                                          = fetch.CommandFailRequest\n\tCommandFetchFulfillRequest                                       = fetch.CommandFulfillRequest\n\tCommandFetchContinueRequest                                      = fetch.CommandContinueRequest\n\tCommandFetchContinueWithAuth                                     = fetch.CommandContinueWithAuth\n\tCommandFetchContinueResponse                                     = fetch.CommandContinueResponse\n\tCommandFetchGetResponseBody                                      = fetch.CommandGetResponseBody\n\tCommandFetchTakeResponseBodyAsStream                             = fetch.CommandTakeResponseBodyAsStream\n\tEventFetchRequestPaused                                          = \"Fetch.requestPaused\"\n\tEventFetchAuthRequired                                           = \"Fetch.authRequired\"\n\tCommandFileSystemGetDirectory                                    = filesystem.CommandGetDirectory\n\tCommandHeadlessExperimentalBeginFrame                            = headlessexperimental.CommandBeginFrame\n\tCommandHeapProfilerAddInspectedHeapObject                        = heapprofiler.CommandAddInspectedHeapObject\n\tCommandHeapProfilerCollectGarbage                                = heapprofiler.CommandCollectGarbage\n\tCommandHeapProfilerDisable                                       = heapprofiler.CommandDisable\n\tCommandHeapProfilerEnable                                        = heapprofiler.CommandEnable\n\tCommandHeapProfilerGetHeapObjectID                               = heapprofiler.CommandGetHeapObjectID\n\tCommandHeapProfilerGetObjectByHeapObjectID                       = heapprofiler.CommandGetObjectByHeapObjectID\n\tCommandHeapProfilerGetSamplingProfile                            = heapprofiler.CommandGetSamplingProfile\n\tCommandHeapProfilerStartSampling                                 = heapprofiler.CommandStartSampling\n\tCommandHeapProfilerStartTrackingHeapObjects                      = heapprofiler.CommandStartTrackingHeapObjects\n\tCommandHeapProfilerStopSampling                                  = heapprofiler.CommandStopSampling\n\tCommandHeapProfilerStopTrackingHeapObjects                       = heapprofiler.CommandStopTrackingHeapObjects\n\tCommandHeapProfilerTakeHeapSnapshot                              = heapprofiler.CommandTakeHeapSnapshot\n\tEventHeapProfilerAddHeapSnapshotChunk                            = \"HeapProfiler.addHeapSnapshotChunk\"\n\tEventHeapProfilerHeapStatsUpdate                                 = \"HeapProfiler.heapStatsUpdate\"\n\tEventHeapProfilerLastSeenObjectID                                = \"HeapProfiler.lastSeenObjectId\"\n\tEventHeapProfilerReportHeapSnapshotProgress                      = \"HeapProfiler.reportHeapSnapshotProgress\"\n\tEventHeapProfilerResetProfiles                                   = \"HeapProfiler.resetProfiles\"\n\tCommandIOClose                                                   = io.CommandClose\n\tCommandIORead                                                    = io.CommandRead\n\tCommandIOResolveBlob                                             = io.CommandResolveBlob\n\tCommandIndexedDBClearObjectStore                                 = indexeddb.CommandClearObjectStore\n\tCommandIndexedDBDeleteDatabase                                   = indexeddb.CommandDeleteDatabase\n\tCommandIndexedDBDeleteObjectStoreEntries                         = indexeddb.CommandDeleteObjectStoreEntries\n\tCommandIndexedDBDisable                                          = indexeddb.CommandDisable\n\tCommandIndexedDBEnable                                           = indexeddb.CommandEnable\n\tCommandIndexedDBRequestData                                      = indexeddb.CommandRequestData\n\tCommandIndexedDBGetMetadata                                      = indexeddb.CommandGetMetadata\n\tCommandIndexedDBRequestDatabase                                  = indexeddb.CommandRequestDatabase\n\tCommandIndexedDBRequestDatabaseNames                             = indexeddb.CommandRequestDatabaseNames\n\tCommandInputDispatchDragEvent                                    = input.CommandDispatchDragEvent\n\tCommandInputDispatchKeyEvent                                     = input.CommandDispatchKeyEvent\n\tCommandInputInsertText                                           = input.CommandInsertText\n\tCommandInputImeSetComposition                                    = input.CommandImeSetComposition\n\tCommandInputDispatchMouseEvent                                   = input.CommandDispatchMouseEvent\n\tCommandInputDispatchTouchEvent                                   = input.CommandDispatchTouchEvent\n\tCommandInputCancelDragging                                       = input.CommandCancelDragging\n\tCommandInputEmulateTouchFromMouseEvent                           = input.CommandEmulateTouchFromMouseEvent\n\tCommandInputSetIgnoreInputEvents                                 = input.CommandSetIgnoreInputEvents\n\tCommandInputSetInterceptDrags                                    = input.CommandSetInterceptDrags\n\tCommandInputSynthesizePinchGesture                               = input.CommandSynthesizePinchGesture\n\tCommandInputSynthesizeScrollGesture                              = input.CommandSynthesizeScrollGesture\n\tCommandInputSynthesizeTapGesture                                 = input.CommandSynthesizeTapGesture\n\tEventInputDragIntercepted                                        = \"Input.dragIntercepted\"\n\tCommandInspectorDisable                                          = inspector.CommandDisable\n\tCommandInspectorEnable                                           = inspector.CommandEnable\n\tEventInspectorDetached                                           = \"Inspector.detached\"\n\tEventInspectorTargetCrashed                                      = \"Inspector.targetCrashed\"\n\tEventInspectorTargetReloadedAfterCrash                           = \"Inspector.targetReloadedAfterCrash\"\n\tCommandLayerTreeCompositingReasons                               = layertree.CommandCompositingReasons\n\tCommandLayerTreeDisable                                          = layertree.CommandDisable\n\tCommandLayerTreeEnable                                           = layertree.CommandEnable\n\tCommandLayerTreeLoadSnapshot                                     = layertree.CommandLoadSnapshot\n\tCommandLayerTreeMakeSnapshot                                     = layertree.CommandMakeSnapshot\n\tCommandLayerTreeProfileSnapshot                                  = layertree.CommandProfileSnapshot\n\tCommandLayerTreeReleaseSnapshot                                  = layertree.CommandReleaseSnapshot\n\tCommandLayerTreeReplaySnapshot                                   = layertree.CommandReplaySnapshot\n\tCommandLayerTreeSnapshotCommandLog                               = layertree.CommandSnapshotCommandLog\n\tEventLayerTreeLayerPainted                                       = \"LayerTree.layerPainted\"\n\tEventLayerTreeLayerTreeDidChange                                 = \"LayerTree.layerTreeDidChange\"\n\tCommandLogClear                                                  = log.CommandClear\n\tCommandLogDisable                                                = log.CommandDisable\n\tCommandLogEnable                                                 = log.CommandEnable\n\tCommandLogStartViolationsReport                                  = log.CommandStartViolationsReport\n\tCommandLogStopViolationsReport                                   = log.CommandStopViolationsReport\n\tEventLogEntryAdded                                               = \"Log.entryAdded\"\n\tCommandMediaEnable                                               = media.CommandEnable\n\tCommandMediaDisable                                              = media.CommandDisable\n\tEventMediaPlayerPropertiesChanged                                = \"Media.playerPropertiesChanged\"\n\tEventMediaPlayerEventsAdded                                      = \"Media.playerEventsAdded\"\n\tEventMediaPlayerMessagesLogged                                   = \"Media.playerMessagesLogged\"\n\tEventMediaPlayerErrorsRaised                                     = \"Media.playerErrorsRaised\"\n\tEventMediaPlayersCreated                                         = \"Media.playersCreated\"\n\tCommandMemoryGetDOMCounters                                      = memory.CommandGetDOMCounters\n\tCommandMemoryGetDOMCountersForLeakDetection                      = memory.CommandGetDOMCountersForLeakDetection\n\tCommandMemoryPrepareForLeakDetection                             = memory.CommandPrepareForLeakDetection\n\tCommandMemoryForciblyPurgeJavaScriptMemory                       = memory.CommandForciblyPurgeJavaScriptMemory\n\tCommandMemorySetPressureNotificationsSuppressed                  = memory.CommandSetPressureNotificationsSuppressed\n\tCommandMemorySimulatePressureNotification                        = memory.CommandSimulatePressureNotification\n\tCommandMemoryStartSampling                                       = memory.CommandStartSampling\n\tCommandMemoryStopSampling                                        = memory.CommandStopSampling\n\tCommandMemoryGetAllTimeSamplingProfile                           = memory.CommandGetAllTimeSamplingProfile\n\tCommandMemoryGetBrowserSamplingProfile                           = memory.CommandGetBrowserSamplingProfile\n\tCommandMemoryGetSamplingProfile                                  = memory.CommandGetSamplingProfile\n\tCommandNetworkSetAcceptedEncodings                               = network.CommandSetAcceptedEncodings\n\tCommandNetworkClearAcceptedEncodingsOverride                     = network.CommandClearAcceptedEncodingsOverride\n\tCommandNetworkClearBrowserCache                                  = network.CommandClearBrowserCache\n\tCommandNetworkClearBrowserCookies                                = network.CommandClearBrowserCookies\n\tCommandNetworkDeleteCookies                                      = network.CommandDeleteCookies\n\tCommandNetworkDisable                                            = network.CommandDisable\n\tCommandNetworkEmulateNetworkConditions                           = network.CommandEmulateNetworkConditions\n\tCommandNetworkEnable                                             = network.CommandEnable\n\tCommandNetworkGetCertificate                                     = network.CommandGetCertificate\n\tCommandNetworkGetCookies                                         = network.CommandGetCookies\n\tCommandNetworkGetResponseBody                                    = network.CommandGetResponseBody\n\tCommandNetworkGetRequestPostData                                 = network.CommandGetRequestPostData\n\tCommandNetworkGetResponseBodyForInterception                     = network.CommandGetResponseBodyForInterception\n\tCommandNetworkTakeResponseBodyForInterceptionAsStream            = network.CommandTakeResponseBodyForInterceptionAsStream\n\tCommandNetworkReplayXHR                                          = network.CommandReplayXHR\n\tCommandNetworkSearchInResponseBody                               = network.CommandSearchInResponseBody\n\tCommandNetworkSetBlockedURLs                                     = network.CommandSetBlockedURLs\n\tCommandNetworkSetBypassServiceWorker                             = network.CommandSetBypassServiceWorker\n\tCommandNetworkSetCacheDisabled                                   = network.CommandSetCacheDisabled\n\tCommandNetworkSetCookie                                          = network.CommandSetCookie\n\tCommandNetworkSetCookies                                         = network.CommandSetCookies\n\tCommandNetworkSetExtraHTTPHeaders                                = network.CommandSetExtraHTTPHeaders\n\tCommandNetworkSetAttachDebugStack                                = network.CommandSetAttachDebugStack\n\tCommandNetworkStreamResourceContent                              = network.CommandStreamResourceContent\n\tCommandNetworkGetSecurityIsolationStatus                         = network.CommandGetSecurityIsolationStatus\n\tCommandNetworkEnableReportingAPI                                 = network.CommandEnableReportingAPI\n\tCommandNetworkLoadNetworkResource                                = network.CommandLoadNetworkResource\n\tCommandNetworkSetCookieControls                                  = network.CommandSetCookieControls\n\tEventNetworkDataReceived                                         = \"Network.dataReceived\"\n\tEventNetworkEventSourceMessageReceived                           = \"Network.eventSourceMessageReceived\"\n\tEventNetworkLoadingFailed                                        = \"Network.loadingFailed\"\n\tEventNetworkLoadingFinished                                      = \"Network.loadingFinished\"\n\tEventNetworkRequestServedFromCache                               = \"Network.requestServedFromCache\"\n\tEventNetworkRequestWillBeSent                                    = \"Network.requestWillBeSent\"\n\tEventNetworkResourceChangedPriority                              = \"Network.resourceChangedPriority\"\n\tEventNetworkSignedExchangeReceived                               = \"Network.signedExchangeReceived\"\n\tEventNetworkResponseReceived                                     = \"Network.responseReceived\"\n\tEventNetworkWebSocketClosed                                      = \"Network.webSocketClosed\"\n\tEventNetworkWebSocketCreated                                     = \"Network.webSocketCreated\"\n\tEventNetworkWebSocketFrameError                                  = \"Network.webSocketFrameError\"\n\tEventNetworkWebSocketFrameReceived                               = \"Network.webSocketFrameReceived\"\n\tEventNetworkWebSocketFrameSent                                   = \"Network.webSocketFrameSent\"\n\tEventNetworkWebSocketHandshakeResponseReceived                   = \"Network.webSocketHandshakeResponseReceived\"\n\tEventNetworkWebSocketWillSendHandshakeRequest                    = \"Network.webSocketWillSendHandshakeRequest\"\n\tEventNetworkWebTransportCreated                                  = \"Network.webTransportCreated\"\n\tEventNetworkWebTransportConnectionEstablished                    = \"Network.webTransportConnectionEstablished\"\n\tEventNetworkWebTransportClosed                                   = \"Network.webTransportClosed\"\n\tEventNetworkDirectTCPSocketCreated                               = \"Network.directTCPSocketCreated\"\n\tEventNetworkDirectTCPSocketOpened                                = \"Network.directTCPSocketOpened\"\n\tEventNetworkDirectTCPSocketAborted                               = \"Network.directTCPSocketAborted\"\n\tEventNetworkDirectTCPSocketClosed                                = \"Network.directTCPSocketClosed\"\n\tEventNetworkDirectTCPSocketChunkSent                             = \"Network.directTCPSocketChunkSent\"\n\tEventNetworkDirectTCPSocketChunkReceived                         = \"Network.directTCPSocketChunkReceived\"\n\tEventNetworkDirectUDPSocketCreated                               = \"Network.directUDPSocketCreated\"\n\tEventNetworkDirectUDPSocketOpened                                = \"Network.directUDPSocketOpened\"\n\tEventNetworkDirectUDPSocketAborted                               = \"Network.directUDPSocketAborted\"\n\tEventNetworkDirectUDPSocketClosed                                = \"Network.directUDPSocketClosed\"\n\tEventNetworkDirectUDPSocketChunkSent                             = \"Network.directUDPSocketChunkSent\"\n\tEventNetworkDirectUDPSocketChunkReceived                         = \"Network.directUDPSocketChunkReceived\"\n\tEventNetworkRequestWillBeSentExtraInfo                           = \"Network.requestWillBeSentExtraInfo\"\n\tEventNetworkResponseReceivedExtraInfo                            = \"Network.responseReceivedExtraInfo\"\n\tEventNetworkResponseReceivedEarlyHints                           = \"Network.responseReceivedEarlyHints\"\n\tEventNetworkTrustTokenOperationDone                              = \"Network.trustTokenOperationDone\"\n\tEventNetworkPolicyUpdated                                        = \"Network.policyUpdated\"\n\tEventNetworkSubresourceWebBundleMetadataReceived                 = \"Network.subresourceWebBundleMetadataReceived\"\n\tEventNetworkSubresourceWebBundleMetadataError                    = \"Network.subresourceWebBundleMetadataError\"\n\tEventNetworkSubresourceWebBundleInnerResponseParsed              = \"Network.subresourceWebBundleInnerResponseParsed\"\n\tEventNetworkSubresourceWebBundleInnerResponseError               = \"Network.subresourceWebBundleInnerResponseError\"\n\tEventNetworkReportingAPIReportAdded                              = \"Network.reportingApiReportAdded\"\n\tEventNetworkReportingAPIReportUpdated                            = \"Network.reportingApiReportUpdated\"\n\tEventNetworkReportingAPIEndpointsChangedForOrigin                = \"Network.reportingApiEndpointsChangedForOrigin\"\n\tCommandOverlayDisable                                            = overlay.CommandDisable\n\tCommandOverlayEnable                                             = overlay.CommandEnable\n\tCommandOverlayGetHighlightObjectForTest                          = overlay.CommandGetHighlightObjectForTest\n\tCommandOverlayGetGridHighlightObjectsForTest                     = overlay.CommandGetGridHighlightObjectsForTest\n\tCommandOverlayGetSourceOrderHighlightObjectForTest               = overlay.CommandGetSourceOrderHighlightObjectForTest\n\tCommandOverlayHideHighlight                                      = overlay.CommandHideHighlight\n\tCommandOverlayHighlightNode                                      = overlay.CommandHighlightNode\n\tCommandOverlayHighlightQuad                                      = overlay.CommandHighlightQuad\n\tCommandOverlayHighlightRect                                      = overlay.CommandHighlightRect\n\tCommandOverlayHighlightSourceOrder                               = overlay.CommandHighlightSourceOrder\n\tCommandOverlaySetInspectMode                                     = overlay.CommandSetInspectMode\n\tCommandOverlaySetShowAdHighlights                                = overlay.CommandSetShowAdHighlights\n\tCommandOverlaySetPausedInDebuggerMessage                         = overlay.CommandSetPausedInDebuggerMessage\n\tCommandOverlaySetShowDebugBorders                                = overlay.CommandSetShowDebugBorders\n\tCommandOverlaySetShowFPSCounter                                  = overlay.CommandSetShowFPSCounter\n\tCommandOverlaySetShowGridOverlays                                = overlay.CommandSetShowGridOverlays\n\tCommandOverlaySetShowFlexOverlays                                = overlay.CommandSetShowFlexOverlays\n\tCommandOverlaySetShowScrollSnapOverlays                          = overlay.CommandSetShowScrollSnapOverlays\n\tCommandOverlaySetShowContainerQueryOverlays                      = overlay.CommandSetShowContainerQueryOverlays\n\tCommandOverlaySetShowPaintRects                                  = overlay.CommandSetShowPaintRects\n\tCommandOverlaySetShowLayoutShiftRegions                          = overlay.CommandSetShowLayoutShiftRegions\n\tCommandOverlaySetShowScrollBottleneckRects                       = overlay.CommandSetShowScrollBottleneckRects\n\tCommandOverlaySetShowViewportSizeOnResize                        = overlay.CommandSetShowViewportSizeOnResize\n\tCommandOverlaySetShowHinge                                       = overlay.CommandSetShowHinge\n\tCommandOverlaySetShowIsolatedElements                            = overlay.CommandSetShowIsolatedElements\n\tCommandOverlaySetShowWindowControlsOverlay                       = overlay.CommandSetShowWindowControlsOverlay\n\tEventOverlayInspectNodeRequested                                 = \"Overlay.inspectNodeRequested\"\n\tEventOverlayNodeHighlightRequested                               = \"Overlay.nodeHighlightRequested\"\n\tEventOverlayScreenshotRequested                                  = \"Overlay.screenshotRequested\"\n\tEventOverlayInspectModeCanceled                                  = \"Overlay.inspectModeCanceled\"\n\tCommandPWAGetOsAppState                                          = pwa.CommandGetOsAppState\n\tCommandPWAInstall                                                = pwa.CommandInstall\n\tCommandPWAUninstall                                              = pwa.CommandUninstall\n\tCommandPWALaunch                                                 = pwa.CommandLaunch\n\tCommandPWALaunchFilesInApp                                       = pwa.CommandLaunchFilesInApp\n\tCommandPWAOpenCurrentPageInApp                                   = pwa.CommandOpenCurrentPageInApp\n\tCommandPWAChangeAppUserSettings                                  = pwa.CommandChangeAppUserSettings\n\tCommandPageAddScriptToEvaluateOnNewDocument                      = page.CommandAddScriptToEvaluateOnNewDocument\n\tCommandPageBringToFront                                          = page.CommandBringToFront\n\tCommandPageCaptureScreenshot                                     = page.CommandCaptureScreenshot\n\tCommandPageCaptureSnapshot                                       = page.CommandCaptureSnapshot\n\tCommandPageCreateIsolatedWorld                                   = page.CommandCreateIsolatedWorld\n\tCommandPageDisable                                               = page.CommandDisable\n\tCommandPageEnable                                                = page.CommandEnable\n\tCommandPageGetAppManifest                                        = page.CommandGetAppManifest\n\tCommandPageGetInstallabilityErrors                               = page.CommandGetInstallabilityErrors\n\tCommandPageGetAppID                                              = page.CommandGetAppID\n\tCommandPageGetAdScriptAncestry                                   = page.CommandGetAdScriptAncestry\n\tCommandPageGetFrameTree                                          = page.CommandGetFrameTree\n\tCommandPageGetLayoutMetrics                                      = page.CommandGetLayoutMetrics\n\tCommandPageGetNavigationHistory                                  = page.CommandGetNavigationHistory\n\tCommandPageResetNavigationHistory                                = page.CommandResetNavigationHistory\n\tCommandPageGetResourceContent                                    = page.CommandGetResourceContent\n\tCommandPageGetResourceTree                                       = page.CommandGetResourceTree\n\tCommandPageHandleJavaScriptDialog                                = page.CommandHandleJavaScriptDialog\n\tCommandPageNavigate                                              = page.CommandNavigate\n\tCommandPageNavigateToHistoryEntry                                = page.CommandNavigateToHistoryEntry\n\tCommandPagePrintToPDF                                            = page.CommandPrintToPDF\n\tCommandPageReload                                                = page.CommandReload\n\tCommandPageRemoveScriptToEvaluateOnNewDocument                   = page.CommandRemoveScriptToEvaluateOnNewDocument\n\tCommandPageScreencastFrameAck                                    = page.CommandScreencastFrameAck\n\tCommandPageSearchInResource                                      = page.CommandSearchInResource\n\tCommandPageSetAdBlockingEnabled                                  = page.CommandSetAdBlockingEnabled\n\tCommandPageSetBypassCSP                                          = page.CommandSetBypassCSP\n\tCommandPageGetPermissionsPolicyState                             = page.CommandGetPermissionsPolicyState\n\tCommandPageGetOriginTrials                                       = page.CommandGetOriginTrials\n\tCommandPageSetFontFamilies                                       = page.CommandSetFontFamilies\n\tCommandPageSetFontSizes                                          = page.CommandSetFontSizes\n\tCommandPageSetDocumentContent                                    = page.CommandSetDocumentContent\n\tCommandPageSetLifecycleEventsEnabled                             = page.CommandSetLifecycleEventsEnabled\n\tCommandPageStartScreencast                                       = page.CommandStartScreencast\n\tCommandPageStopLoading                                           = page.CommandStopLoading\n\tCommandPageCrash                                                 = page.CommandCrash\n\tCommandPageClose                                                 = page.CommandClose\n\tCommandPageSetWebLifecycleState                                  = page.CommandSetWebLifecycleState\n\tCommandPageStopScreencast                                        = page.CommandStopScreencast\n\tCommandPageProduceCompilationCache                               = page.CommandProduceCompilationCache\n\tCommandPageAddCompilationCache                                   = page.CommandAddCompilationCache\n\tCommandPageClearCompilationCache                                 = page.CommandClearCompilationCache\n\tCommandPageSetSPCTransactionMode                                 = page.CommandSetSPCTransactionMode\n\tCommandPageSetRPHRegistrationMode                                = page.CommandSetRPHRegistrationMode\n\tCommandPageGenerateTestReport                                    = page.CommandGenerateTestReport\n\tCommandPageWaitForDebugger                                       = page.CommandWaitForDebugger\n\tCommandPageSetInterceptFileChooserDialog                         = page.CommandSetInterceptFileChooserDialog\n\tCommandPageSetPrerenderingAllowed                                = page.CommandSetPrerenderingAllowed\n\tEventPageDomContentEventFired                                    = \"Page.domContentEventFired\"\n\tEventPageFileChooserOpened                                       = \"Page.fileChooserOpened\"\n\tEventPageFrameAttached                                           = \"Page.frameAttached\"\n\tEventPageFrameDetached                                           = \"Page.frameDetached\"\n\tEventPageFrameSubtreeWillBeDetached                              = \"Page.frameSubtreeWillBeDetached\"\n\tEventPageFrameNavigated                                          = \"Page.frameNavigated\"\n\tEventPageDocumentOpened                                          = \"Page.documentOpened\"\n\tEventPageFrameResized                                            = \"Page.frameResized\"\n\tEventPageFrameStartedNavigating                                  = \"Page.frameStartedNavigating\"\n\tEventPageFrameRequestedNavigation                                = \"Page.frameRequestedNavigation\"\n\tEventPageFrameStartedLoading                                     = \"Page.frameStartedLoading\"\n\tEventPageFrameStoppedLoading                                     = \"Page.frameStoppedLoading\"\n\tEventPageInterstitialHidden                                      = \"Page.interstitialHidden\"\n\tEventPageInterstitialShown                                       = \"Page.interstitialShown\"\n\tEventPageJavascriptDialogClosed                                  = \"Page.javascriptDialogClosed\"\n\tEventPageJavascriptDialogOpening                                 = \"Page.javascriptDialogOpening\"\n\tEventPageLifecycleEvent                                          = \"Page.lifecycleEvent\"\n\tEventPageBackForwardCacheNotUsed                                 = \"Page.backForwardCacheNotUsed\"\n\tEventPageLoadEventFired                                          = \"Page.loadEventFired\"\n\tEventPageNavigatedWithinDocument                                 = \"Page.navigatedWithinDocument\"\n\tEventPageScreencastFrame                                         = \"Page.screencastFrame\"\n\tEventPageScreencastVisibilityChanged                             = \"Page.screencastVisibilityChanged\"\n\tEventPageWindowOpen                                              = \"Page.windowOpen\"\n\tEventPageCompilationCacheProduced                                = \"Page.compilationCacheProduced\"\n\tCommandPerformanceDisable                                        = performance.CommandDisable\n\tCommandPerformanceEnable                                         = performance.CommandEnable\n\tCommandPerformanceGetMetrics                                     = performance.CommandGetMetrics\n\tEventPerformanceMetrics                                          = \"Performance.metrics\"\n\tCommandPerformanceTimelineEnable                                 = performancetimeline.CommandEnable\n\tEventPerformanceTimelineTimelineEventAdded                       = \"PerformanceTimeline.timelineEventAdded\"\n\tCommandPreloadEnable                                             = preload.CommandEnable\n\tCommandPreloadDisable                                            = preload.CommandDisable\n\tEventPreloadRuleSetUpdated                                       = \"Preload.ruleSetUpdated\"\n\tEventPreloadRuleSetRemoved                                       = \"Preload.ruleSetRemoved\"\n\tEventPreloadPreloadEnabledStateUpdated                           = \"Preload.preloadEnabledStateUpdated\"\n\tEventPreloadPrefetchStatusUpdated                                = \"Preload.prefetchStatusUpdated\"\n\tEventPreloadPrerenderStatusUpdated                               = \"Preload.prerenderStatusUpdated\"\n\tEventPreloadPreloadingAttemptSourcesUpdated                      = \"Preload.preloadingAttemptSourcesUpdated\"\n\tCommandProfilerDisable                                           = profiler.CommandDisable\n\tCommandProfilerEnable                                            = profiler.CommandEnable\n\tCommandProfilerGetBestEffortCoverage                             = profiler.CommandGetBestEffortCoverage\n\tCommandProfilerSetSamplingInterval                               = profiler.CommandSetSamplingInterval\n\tCommandProfilerStart                                             = profiler.CommandStart\n\tCommandProfilerStartPreciseCoverage                              = profiler.CommandStartPreciseCoverage\n\tCommandProfilerStop                                              = profiler.CommandStop\n\tCommandProfilerStopPreciseCoverage                               = profiler.CommandStopPreciseCoverage\n\tCommandProfilerTakePreciseCoverage                               = profiler.CommandTakePreciseCoverage\n\tEventProfilerConsoleProfileFinished                              = \"Profiler.consoleProfileFinished\"\n\tEventProfilerConsoleProfileStarted                               = \"Profiler.consoleProfileStarted\"\n\tEventProfilerPreciseCoverageDeltaUpdate                          = \"Profiler.preciseCoverageDeltaUpdate\"\n\tCommandRuntimeAwaitPromise                                       = runtime.CommandAwaitPromise\n\tCommandRuntimeCallFunctionOn                                     = runtime.CommandCallFunctionOn\n\tCommandRuntimeCompileScript                                      = runtime.CommandCompileScript\n\tCommandRuntimeDisable                                            = runtime.CommandDisable\n\tCommandRuntimeDiscardConsoleEntries                              = runtime.CommandDiscardConsoleEntries\n\tCommandRuntimeEnable                                             = runtime.CommandEnable\n\tCommandRuntimeEvaluate                                           = runtime.CommandEvaluate\n\tCommandRuntimeGetIsolateID                                       = runtime.CommandGetIsolateID\n\tCommandRuntimeGetHeapUsage                                       = runtime.CommandGetHeapUsage\n\tCommandRuntimeGetProperties                                      = runtime.CommandGetProperties\n\tCommandRuntimeGlobalLexicalScopeNames                            = runtime.CommandGlobalLexicalScopeNames\n\tCommandRuntimeQueryObjects                                       = runtime.CommandQueryObjects\n\tCommandRuntimeReleaseObject                                      = runtime.CommandReleaseObject\n\tCommandRuntimeReleaseObjectGroup                                 = runtime.CommandReleaseObjectGroup\n\tCommandRuntimeRunIfWaitingForDebugger                            = runtime.CommandRunIfWaitingForDebugger\n\tCommandRuntimeRunScript                                          = runtime.CommandRunScript\n\tCommandRuntimeSetCustomObjectFormatterEnabled                    = runtime.CommandSetCustomObjectFormatterEnabled\n\tCommandRuntimeSetMaxCallStackSizeToCapture                       = runtime.CommandSetMaxCallStackSizeToCapture\n\tCommandRuntimeTerminateExecution                                 = runtime.CommandTerminateExecution\n\tCommandRuntimeAddBinding                                         = runtime.CommandAddBinding\n\tCommandRuntimeRemoveBinding                                      = runtime.CommandRemoveBinding\n\tCommandRuntimeGetExceptionDetails                                = runtime.CommandGetExceptionDetails\n\tEventRuntimeBindingCalled                                        = \"Runtime.bindingCalled\"\n\tEventRuntimeConsoleAPICalled                                     = \"Runtime.consoleAPICalled\"\n\tEventRuntimeExceptionRevoked                                     = \"Runtime.exceptionRevoked\"\n\tEventRuntimeExceptionThrown                                      = \"Runtime.exceptionThrown\"\n\tEventRuntimeExecutionContextCreated                              = \"Runtime.executionContextCreated\"\n\tEventRuntimeExecutionContextDestroyed                            = \"Runtime.executionContextDestroyed\"\n\tEventRuntimeExecutionContextsCleared                             = \"Runtime.executionContextsCleared\"\n\tEventRuntimeInspectRequested                                     = \"Runtime.inspectRequested\"\n\tCommandSecurityDisable                                           = security.CommandDisable\n\tCommandSecurityEnable                                            = security.CommandEnable\n\tCommandSecuritySetIgnoreCertificateErrors                        = security.CommandSetIgnoreCertificateErrors\n\tEventSecurityVisibleSecurityStateChanged                         = \"Security.visibleSecurityStateChanged\"\n\tCommandServiceWorkerDeliverPushMessage                           = serviceworker.CommandDeliverPushMessage\n\tCommandServiceWorkerDisable                                      = serviceworker.CommandDisable\n\tCommandServiceWorkerDispatchSyncEvent                            = serviceworker.CommandDispatchSyncEvent\n\tCommandServiceWorkerDispatchPeriodicSyncEvent                    = serviceworker.CommandDispatchPeriodicSyncEvent\n\tCommandServiceWorkerEnable                                       = serviceworker.CommandEnable\n\tCommandServiceWorkerSetForceUpdateOnPageLoad                     = serviceworker.CommandSetForceUpdateOnPageLoad\n\tCommandServiceWorkerSkipWaiting                                  = serviceworker.CommandSkipWaiting\n\tCommandServiceWorkerStartWorker                                  = serviceworker.CommandStartWorker\n\tCommandServiceWorkerStopAllWorkers                               = serviceworker.CommandStopAllWorkers\n\tCommandServiceWorkerStopWorker                                   = serviceworker.CommandStopWorker\n\tCommandServiceWorkerUnregister                                   = serviceworker.CommandUnregister\n\tCommandServiceWorkerUpdateRegistration                           = serviceworker.CommandUpdateRegistration\n\tEventServiceWorkerWorkerErrorReported                            = \"ServiceWorker.workerErrorReported\"\n\tEventServiceWorkerWorkerRegistrationUpdated                      = \"ServiceWorker.workerRegistrationUpdated\"\n\tEventServiceWorkerWorkerVersionUpdated                           = \"ServiceWorker.workerVersionUpdated\"\n\tCommandStorageGetStorageKeyForFrame                              = storage.CommandGetStorageKeyForFrame\n\tCommandStorageClearDataForOrigin                                 = storage.CommandClearDataForOrigin\n\tCommandStorageClearDataForStorageKey                             = storage.CommandClearDataForStorageKey\n\tCommandStorageGetCookies                                         = storage.CommandGetCookies\n\tCommandStorageSetCookies                                         = storage.CommandSetCookies\n\tCommandStorageClearCookies                                       = storage.CommandClearCookies\n\tCommandStorageGetUsageAndQuota                                   = storage.CommandGetUsageAndQuota\n\tCommandStorageOverrideQuotaForOrigin                             = storage.CommandOverrideQuotaForOrigin\n\tCommandStorageTrackCacheStorageForOrigin                         = storage.CommandTrackCacheStorageForOrigin\n\tCommandStorageTrackCacheStorageForStorageKey                     = storage.CommandTrackCacheStorageForStorageKey\n\tCommandStorageTrackIndexedDBForOrigin                            = storage.CommandTrackIndexedDBForOrigin\n\tCommandStorageTrackIndexedDBForStorageKey                        = storage.CommandTrackIndexedDBForStorageKey\n\tCommandStorageUntrackCacheStorageForOrigin                       = storage.CommandUntrackCacheStorageForOrigin\n\tCommandStorageUntrackCacheStorageForStorageKey                   = storage.CommandUntrackCacheStorageForStorageKey\n\tCommandStorageUntrackIndexedDBForOrigin                          = storage.CommandUntrackIndexedDBForOrigin\n\tCommandStorageUntrackIndexedDBForStorageKey                      = storage.CommandUntrackIndexedDBForStorageKey\n\tCommandStorageGetTrustTokens                                     = storage.CommandGetTrustTokens\n\tCommandStorageClearTrustTokens                                   = storage.CommandClearTrustTokens\n\tCommandStorageGetInterestGroupDetails                            = storage.CommandGetInterestGroupDetails\n\tCommandStorageSetInterestGroupTracking                           = storage.CommandSetInterestGroupTracking\n\tCommandStorageSetInterestGroupAuctionTracking                    = storage.CommandSetInterestGroupAuctionTracking\n\tCommandStorageGetSharedStorageMetadata                           = storage.CommandGetSharedStorageMetadata\n\tCommandStorageGetSharedStorageEntries                            = storage.CommandGetSharedStorageEntries\n\tCommandStorageSetSharedStorageEntry                              = storage.CommandSetSharedStorageEntry\n\tCommandStorageDeleteSharedStorageEntry                           = storage.CommandDeleteSharedStorageEntry\n\tCommandStorageClearSharedStorageEntries                          = storage.CommandClearSharedStorageEntries\n\tCommandStorageResetSharedStorageBudget                           = storage.CommandResetSharedStorageBudget\n\tCommandStorageSetSharedStorageTracking                           = storage.CommandSetSharedStorageTracking\n\tCommandStorageSetStorageBucketTracking                           = storage.CommandSetStorageBucketTracking\n\tCommandStorageDeleteStorageBucket                                = storage.CommandDeleteStorageBucket\n\tCommandStorageRunBounceTrackingMitigations                       = storage.CommandRunBounceTrackingMitigations\n\tCommandStorageSetAttributionReportingLocalTestingMode            = storage.CommandSetAttributionReportingLocalTestingMode\n\tCommandStorageSetAttributionReportingTracking                    = storage.CommandSetAttributionReportingTracking\n\tCommandStorageSendPendingAttributionReports                      = storage.CommandSendPendingAttributionReports\n\tCommandStorageGetRelatedWebsiteSets                              = storage.CommandGetRelatedWebsiteSets\n\tCommandStorageGetAffectedURLsForThirdPartyCookieMetadata         = storage.CommandGetAffectedURLsForThirdPartyCookieMetadata\n\tCommandStorageSetProtectedAudienceKAnonymity                     = storage.CommandSetProtectedAudienceKAnonymity\n\tEventStorageCacheStorageContentUpdated                           = \"Storage.cacheStorageContentUpdated\"\n\tEventStorageCacheStorageListUpdated                              = \"Storage.cacheStorageListUpdated\"\n\tEventStorageIndexedDBContentUpdated                              = \"Storage.indexedDBContentUpdated\"\n\tEventStorageIndexedDBListUpdated                                 = \"Storage.indexedDBListUpdated\"\n\tEventStorageInterestGroupAccessed                                = \"Storage.interestGroupAccessed\"\n\tEventStorageInterestGroupAuctionEventOccurred                    = \"Storage.interestGroupAuctionEventOccurred\"\n\tEventStorageInterestGroupAuctionNetworkRequestCreated            = \"Storage.interestGroupAuctionNetworkRequestCreated\"\n\tEventStorageSharedStorageAccessed                                = \"Storage.sharedStorageAccessed\"\n\tEventStorageSharedStorageWorkletOperationExecutionFinished       = \"Storage.sharedStorageWorkletOperationExecutionFinished\"\n\tEventStorageStorageBucketCreatedOrUpdated                        = \"Storage.storageBucketCreatedOrUpdated\"\n\tEventStorageStorageBucketDeleted                                 = \"Storage.storageBucketDeleted\"\n\tEventStorageAttributionReportingSourceRegistered                 = \"Storage.attributionReportingSourceRegistered\"\n\tEventStorageAttributionReportingTriggerRegistered                = \"Storage.attributionReportingTriggerRegistered\"\n\tEventStorageAttributionReportingReportSent                       = \"Storage.attributionReportingReportSent\"\n\tEventStorageAttributionReportingVerboseDebugReportSent           = \"Storage.attributionReportingVerboseDebugReportSent\"\n\tCommandSystemInfoGetInfo                                         = systeminfo.CommandGetInfo\n\tCommandSystemInfoGetFeatureState                                 = systeminfo.CommandGetFeatureState\n\tCommandSystemInfoGetProcessInfo                                  = systeminfo.CommandGetProcessInfo\n\tCommandTargetActivateTarget                                      = target.CommandActivateTarget\n\tCommandTargetAttachToTarget                                      = target.CommandAttachToTarget\n\tCommandTargetAttachToBrowserTarget                               = target.CommandAttachToBrowserTarget\n\tCommandTargetCloseTarget                                         = target.CommandCloseTarget\n\tCommandTargetExposeDevToolsProtocol                              = target.CommandExposeDevToolsProtocol\n\tCommandTargetCreateBrowserContext                                = target.CommandCreateBrowserContext\n\tCommandTargetGetBrowserContexts                                  = target.CommandGetBrowserContexts\n\tCommandTargetCreateTarget                                        = target.CommandCreateTarget\n\tCommandTargetDetachFromTarget                                    = target.CommandDetachFromTarget\n\tCommandTargetDisposeBrowserContext                               = target.CommandDisposeBrowserContext\n\tCommandTargetGetTargetInfo                                       = target.CommandGetTargetInfo\n\tCommandTargetGetTargets                                          = target.CommandGetTargets\n\tCommandTargetSetAutoAttach                                       = target.CommandSetAutoAttach\n\tCommandTargetAutoAttachRelated                                   = target.CommandAutoAttachRelated\n\tCommandTargetSetDiscoverTargets                                  = target.CommandSetDiscoverTargets\n\tCommandTargetSetRemoteLocations                                  = target.CommandSetRemoteLocations\n\tCommandTargetOpenDevTools                                        = target.CommandOpenDevTools\n\tEventTargetAttachedToTarget                                      = \"Target.attachedToTarget\"\n\tEventTargetDetachedFromTarget                                    = \"Target.detachedFromTarget\"\n\tEventTargetReceivedMessageFromTarget                             = \"Target.receivedMessageFromTarget\"\n\tEventTargetTargetCreated                                         = \"Target.targetCreated\"\n\tEventTargetTargetDestroyed                                       = \"Target.targetDestroyed\"\n\tEventTargetTargetCrashed                                         = \"Target.targetCrashed\"\n\tEventTargetTargetInfoChanged                                     = \"Target.targetInfoChanged\"\n\tCommandTetheringBind                                             = tethering.CommandBind\n\tCommandTetheringUnbind                                           = tethering.CommandUnbind\n\tEventTetheringAccepted                                           = \"Tethering.accepted\"\n\tCommandTracingEnd                                                = tracing.CommandEnd\n\tCommandTracingGetCategories                                      = tracing.CommandGetCategories\n\tCommandTracingRecordClockSyncMarker                              = tracing.CommandRecordClockSyncMarker\n\tCommandTracingRequestMemoryDump                                  = tracing.CommandRequestMemoryDump\n\tCommandTracingStart                                              = tracing.CommandStart\n\tEventTracingBufferUsage                                          = \"Tracing.bufferUsage\"\n\tEventTracingDataCollected                                        = \"Tracing.dataCollected\"\n\tEventTracingTracingComplete                                      = \"Tracing.tracingComplete\"\n\tCommandWebAudioEnable                                            = webaudio.CommandEnable\n\tCommandWebAudioDisable                                           = webaudio.CommandDisable\n\tCommandWebAudioGetRealtimeData                                   = webaudio.CommandGetRealtimeData\n\tEventWebAudioContextCreated                                      = \"WebAudio.contextCreated\"\n\tEventWebAudioContextWillBeDestroyed                              = \"WebAudio.contextWillBeDestroyed\"\n\tEventWebAudioContextChanged                                      = \"WebAudio.contextChanged\"\n\tEventWebAudioAudioListenerCreated                                = \"WebAudio.audioListenerCreated\"\n\tEventWebAudioAudioListenerWillBeDestroyed                        = \"WebAudio.audioListenerWillBeDestroyed\"\n\tEventWebAudioAudioNodeCreated                                    = \"WebAudio.audioNodeCreated\"\n\tEventWebAudioAudioNodeWillBeDestroyed                            = \"WebAudio.audioNodeWillBeDestroyed\"\n\tEventWebAudioAudioParamCreated                                   = \"WebAudio.audioParamCreated\"\n\tEventWebAudioAudioParamWillBeDestroyed                           = \"WebAudio.audioParamWillBeDestroyed\"\n\tEventWebAudioNodesConnected                                      = \"WebAudio.nodesConnected\"\n\tEventWebAudioNodesDisconnected                                   = \"WebAudio.nodesDisconnected\"\n\tEventWebAudioNodeParamConnected                                  = \"WebAudio.nodeParamConnected\"\n\tEventWebAudioNodeParamDisconnected                               = \"WebAudio.nodeParamDisconnected\"\n\tCommandWebAuthnEnable                                            = webauthn.CommandEnable\n\tCommandWebAuthnDisable                                           = webauthn.CommandDisable\n\tCommandWebAuthnAddVirtualAuthenticator                           = webauthn.CommandAddVirtualAuthenticator\n\tCommandWebAuthnSetResponseOverrideBits                           = webauthn.CommandSetResponseOverrideBits\n\tCommandWebAuthnRemoveVirtualAuthenticator                        = webauthn.CommandRemoveVirtualAuthenticator\n\tCommandWebAuthnAddCredential                                     = webauthn.CommandAddCredential\n\tCommandWebAuthnGetCredential                                     = webauthn.CommandGetCredential\n\tCommandWebAuthnGetCredentials                                    = webauthn.CommandGetCredentials\n\tCommandWebAuthnRemoveCredential                                  = webauthn.CommandRemoveCredential\n\tCommandWebAuthnClearCredentials                                  = webauthn.CommandClearCredentials\n\tCommandWebAuthnSetUserVerified                                   = webauthn.CommandSetUserVerified\n\tCommandWebAuthnSetAutomaticPresenceSimulation                    = webauthn.CommandSetAutomaticPresenceSimulation\n\tCommandWebAuthnSetCredentialProperties                           = webauthn.CommandSetCredentialProperties\n\tEventWebAuthnCredentialAdded                                     = \"WebAuthn.credentialAdded\"\n\tEventWebAuthnCredentialDeleted                                   = \"WebAuthn.credentialDeleted\"\n\tEventWebAuthnCredentialUpdated                                   = \"WebAuthn.credentialUpdated\"\n\tEventWebAuthnCredentialAsserted                                  = \"WebAuthn.credentialAsserted\"\n)\n\n// Error error type.\ntype Error struct {\n\tCode    int64  `json:\"code\"`    // Error code.\n\tMessage string `json:\"message\"` // Error message.\n}\n\n// Error satisfies the error interface.\nfunc (e *Error) Error() string {\n\treturn fmt.Sprintf(\"%s (%d)\", e.Message, e.Code)\n}\n\n// Message chrome DevTools Protocol message sent/read over websocket\n// connection.\ntype Message struct {\n\tID        int64            `json:\"id,omitempty,omitzero\"`        // Unique message identifier.\n\tSessionID target.SessionID `json:\"sessionId,omitempty,omitzero\"` // Session that the message belongs to when using flat access.\n\tMethod    MethodType       `json:\"method,omitempty,omitzero\"`    // Event or command type.\n\tParams    jsontext.Value   `json:\"params,omitempty,omitzero\"`    // Event or command parameters.\n\tResult    jsontext.Value   `json:\"result,omitempty,omitzero\"`    // Command return values.\n\tError     *Error           `json:\"error,omitempty,omitzero\"`     // Error message.\n}\n\ntype empty struct{}\n\nvar emptyVal = &empty{}\n\n// UnmarshalMessage unmarshals the message result or params.\nfunc UnmarshalMessage(msg *Message, opts ...jsonv2.Options) (any, error) {\n\tvar v any\n\tswitch msg.Method {\n\tcase CommandAccessibilityDisable:\n\t\treturn emptyVal, nil\n\tcase CommandAccessibilityEnable:\n\t\treturn emptyVal, nil\n\tcase CommandAccessibilityGetPartialAXTree:\n\t\tv = new(accessibility.GetPartialAXTreeReturns)\n\tcase CommandAccessibilityGetFullAXTree:\n\t\tv = new(accessibility.GetFullAXTreeReturns)\n\tcase CommandAccessibilityGetRootAXNode:\n\t\tv = new(accessibility.GetRootAXNodeReturns)\n\tcase CommandAccessibilityGetAXNodeAndAncestors:\n\t\tv = new(accessibility.GetAXNodeAndAncestorsReturns)\n\tcase CommandAccessibilityGetChildAXNodes:\n\t\tv = new(accessibility.GetChildAXNodesReturns)\n\tcase CommandAccessibilityQueryAXTree:\n\t\tv = new(accessibility.QueryAXTreeReturns)\n\tcase EventAccessibilityLoadComplete:\n\t\tv = new(accessibility.EventLoadComplete)\n\tcase EventAccessibilityNodesUpdated:\n\t\tv = new(accessibility.EventNodesUpdated)\n\tcase CommandAnimationDisable:\n\t\treturn emptyVal, nil\n\tcase CommandAnimationEnable:\n\t\treturn emptyVal, nil\n\tcase CommandAnimationGetCurrentTime:\n\t\tv = new(animation.GetCurrentTimeReturns)\n\tcase CommandAnimationGetPlaybackRate:\n\t\tv = new(animation.GetPlaybackRateReturns)\n\tcase CommandAnimationReleaseAnimations:\n\t\treturn emptyVal, nil\n\tcase CommandAnimationResolveAnimation:\n\t\tv = new(animation.ResolveAnimationReturns)\n\tcase CommandAnimationSeekAnimations:\n\t\treturn emptyVal, nil\n\tcase CommandAnimationSetPaused:\n\t\treturn emptyVal, nil\n\tcase CommandAnimationSetPlaybackRate:\n\t\treturn emptyVal, nil\n\tcase CommandAnimationSetTiming:\n\t\treturn emptyVal, nil\n\tcase EventAnimationAnimationCanceled:\n\t\tv = new(animation.EventAnimationCanceled)\n\tcase EventAnimationAnimationCreated:\n\t\tv = new(animation.EventAnimationCreated)\n\tcase EventAnimationAnimationStarted:\n\t\tv = new(animation.EventAnimationStarted)\n\tcase EventAnimationAnimationUpdated:\n\t\tv = new(animation.EventAnimationUpdated)\n\tcase CommandAuditsGetEncodedResponse:\n\t\tv = new(audits.GetEncodedResponseReturns)\n\tcase CommandAuditsDisable:\n\t\treturn emptyVal, nil\n\tcase CommandAuditsEnable:\n\t\treturn emptyVal, nil\n\tcase CommandAuditsCheckContrast:\n\t\treturn emptyVal, nil\n\tcase CommandAuditsCheckFormsIssues:\n\t\tv = new(audits.CheckFormsIssuesReturns)\n\tcase EventAuditsIssueAdded:\n\t\tv = new(audits.EventIssueAdded)\n\tcase CommandAutofillTrigger:\n\t\treturn emptyVal, nil\n\tcase CommandAutofillSetAddresses:\n\t\treturn emptyVal, nil\n\tcase CommandAutofillDisable:\n\t\treturn emptyVal, nil\n\tcase CommandAutofillEnable:\n\t\treturn emptyVal, nil\n\tcase EventAutofillAddressFormFilled:\n\t\tv = new(autofill.EventAddressFormFilled)\n\tcase CommandBackgroundServiceStartObserving:\n\t\treturn emptyVal, nil\n\tcase CommandBackgroundServiceStopObserving:\n\t\treturn emptyVal, nil\n\tcase CommandBackgroundServiceSetRecording:\n\t\treturn emptyVal, nil\n\tcase CommandBackgroundServiceClearEvents:\n\t\treturn emptyVal, nil\n\tcase EventBackgroundServiceRecordingStateChanged:\n\t\tv = new(backgroundservice.EventRecordingStateChanged)\n\tcase EventBackgroundServiceBackgroundServiceEventReceived:\n\t\tv = new(backgroundservice.EventBackgroundServiceEventReceived)\n\tcase CommandBluetoothEmulationEnable:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationSetSimulatedCentralState:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationDisable:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationSimulatePreconnectedPeripheral:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationSimulateAdvertisement:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationSimulateGATTOperationResponse:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationSimulateCharacteristicOperationResponse:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationSimulateDescriptorOperationResponse:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationAddService:\n\t\tv = new(bluetoothemulation.AddServiceReturns)\n\tcase CommandBluetoothEmulationRemoveService:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationAddCharacteristic:\n\t\tv = new(bluetoothemulation.AddCharacteristicReturns)\n\tcase CommandBluetoothEmulationRemoveCharacteristic:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationAddDescriptor:\n\t\tv = new(bluetoothemulation.AddDescriptorReturns)\n\tcase CommandBluetoothEmulationRemoveDescriptor:\n\t\treturn emptyVal, nil\n\tcase CommandBluetoothEmulationSimulateGATTDisconnection:\n\t\treturn emptyVal, nil\n\tcase EventBluetoothEmulationGattOperationReceived:\n\t\tv = new(bluetoothemulation.EventGattOperationReceived)\n\tcase EventBluetoothEmulationCharacteristicOperationReceived:\n\t\tv = new(bluetoothemulation.EventCharacteristicOperationReceived)\n\tcase EventBluetoothEmulationDescriptorOperationReceived:\n\t\tv = new(bluetoothemulation.EventDescriptorOperationReceived)\n\tcase CommandBrowserSetPermission:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserGrantPermissions:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserResetPermissions:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserSetDownloadBehavior:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserCancelDownload:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserClose:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserCrash:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserCrashGPUProcess:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserGetVersion:\n\t\tv = new(browser.GetVersionReturns)\n\tcase CommandBrowserGetBrowserCommandLine:\n\t\tv = new(browser.GetBrowserCommandLineReturns)\n\tcase CommandBrowserGetHistograms:\n\t\tv = new(browser.GetHistogramsReturns)\n\tcase CommandBrowserGetHistogram:\n\t\tv = new(browser.GetHistogramReturns)\n\tcase CommandBrowserGetWindowBounds:\n\t\tv = new(browser.GetWindowBoundsReturns)\n\tcase CommandBrowserGetWindowForTarget:\n\t\tv = new(browser.GetWindowForTargetReturns)\n\tcase CommandBrowserSetWindowBounds:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserSetContentsSize:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserSetDockTile:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserExecuteBrowserCommand:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserAddPrivacySandboxEnrollmentOverride:\n\t\treturn emptyVal, nil\n\tcase CommandBrowserAddPrivacySandboxCoordinatorKeyConfig:\n\t\treturn emptyVal, nil\n\tcase EventBrowserDownloadWillBegin:\n\t\tv = new(browser.EventDownloadWillBegin)\n\tcase EventBrowserDownloadProgress:\n\t\tv = new(browser.EventDownloadProgress)\n\tcase CommandCSSAddRule:\n\t\tv = new(css.AddRuleReturns)\n\tcase CommandCSSCollectClassNames:\n\t\tv = new(css.CollectClassNamesReturns)\n\tcase CommandCSSCreateStyleSheet:\n\t\tv = new(css.CreateStyleSheetReturns)\n\tcase CommandCSSDisable:\n\t\treturn emptyVal, nil\n\tcase CommandCSSEnable:\n\t\treturn emptyVal, nil\n\tcase CommandCSSForcePseudoState:\n\t\treturn emptyVal, nil\n\tcase CommandCSSForceStartingStyle:\n\t\treturn emptyVal, nil\n\tcase CommandCSSGetBackgroundColors:\n\t\tv = new(css.GetBackgroundColorsReturns)\n\tcase CommandCSSGetComputedStyleForNode:\n\t\tv = new(css.GetComputedStyleForNodeReturns)\n\tcase CommandCSSResolveValues:\n\t\tv = new(css.ResolveValuesReturns)\n\tcase CommandCSSGetLonghandProperties:\n\t\tv = new(css.GetLonghandPropertiesReturns)\n\tcase CommandCSSGetInlineStylesForNode:\n\t\tv = new(css.GetInlineStylesForNodeReturns)\n\tcase CommandCSSGetAnimatedStylesForNode:\n\t\tv = new(css.GetAnimatedStylesForNodeReturns)\n\tcase CommandCSSGetMatchedStylesForNode:\n\t\tv = new(css.GetMatchedStylesForNodeReturns)\n\tcase CommandCSSGetEnvironmentVariables:\n\t\tv = new(css.GetEnvironmentVariablesReturns)\n\tcase CommandCSSGetMediaQueries:\n\t\tv = new(css.GetMediaQueriesReturns)\n\tcase CommandCSSGetPlatformFontsForNode:\n\t\tv = new(css.GetPlatformFontsForNodeReturns)\n\tcase CommandCSSGetStyleSheetText:\n\t\tv = new(css.GetStyleSheetTextReturns)\n\tcase CommandCSSGetLayersForNode:\n\t\tv = new(css.GetLayersForNodeReturns)\n\tcase CommandCSSGetLocationForSelector:\n\t\tv = new(css.GetLocationForSelectorReturns)\n\tcase CommandCSSTrackComputedStyleUpdatesForNode:\n\t\treturn emptyVal, nil\n\tcase CommandCSSTrackComputedStyleUpdates:\n\t\treturn emptyVal, nil\n\tcase CommandCSSTakeComputedStyleUpdates:\n\t\tv = new(css.TakeComputedStyleUpdatesReturns)\n\tcase CommandCSSSetEffectivePropertyValueForNode:\n\t\treturn emptyVal, nil\n\tcase CommandCSSSetPropertyRulePropertyName:\n\t\tv = new(css.SetPropertyRulePropertyNameReturns)\n\tcase CommandCSSSetKeyframeKey:\n\t\tv = new(css.SetKeyframeKeyReturns)\n\tcase CommandCSSSetMediaText:\n\t\tv = new(css.SetMediaTextReturns)\n\tcase CommandCSSSetContainerQueryText:\n\t\tv = new(css.SetContainerQueryTextReturns)\n\tcase CommandCSSSetSupportsText:\n\t\tv = new(css.SetSupportsTextReturns)\n\tcase CommandCSSSetScopeText:\n\t\tv = new(css.SetScopeTextReturns)\n\tcase CommandCSSSetRuleSelector:\n\t\tv = new(css.SetRuleSelectorReturns)\n\tcase CommandCSSSetStyleSheetText:\n\t\tv = new(css.SetStyleSheetTextReturns)\n\tcase CommandCSSSetStyleTexts:\n\t\tv = new(css.SetStyleTextsReturns)\n\tcase CommandCSSStartRuleUsageTracking:\n\t\treturn emptyVal, nil\n\tcase CommandCSSStopRuleUsageTracking:\n\t\tv = new(css.StopRuleUsageTrackingReturns)\n\tcase CommandCSSTakeCoverageDelta:\n\t\tv = new(css.TakeCoverageDeltaReturns)\n\tcase CommandCSSSetLocalFontsEnabled:\n\t\treturn emptyVal, nil\n\tcase EventCSSFontsUpdated:\n\t\tv = new(css.EventFontsUpdated)\n\tcase EventCSSMediaQueryResultChanged:\n\t\tv = new(css.EventMediaQueryResultChanged)\n\tcase EventCSSStyleSheetAdded:\n\t\tv = new(css.EventStyleSheetAdded)\n\tcase EventCSSStyleSheetChanged:\n\t\tv = new(css.EventStyleSheetChanged)\n\tcase EventCSSStyleSheetRemoved:\n\t\tv = new(css.EventStyleSheetRemoved)\n\tcase EventCSSComputedStyleUpdated:\n\t\tv = new(css.EventComputedStyleUpdated)\n\tcase CommandCacheStorageDeleteCache:\n\t\treturn emptyVal, nil\n\tcase CommandCacheStorageDeleteEntry:\n\t\treturn emptyVal, nil\n\tcase CommandCacheStorageRequestCacheNames:\n\t\tv = new(cachestorage.RequestCacheNamesReturns)\n\tcase CommandCacheStorageRequestCachedResponse:\n\t\tv = new(cachestorage.RequestCachedResponseReturns)\n\tcase CommandCacheStorageRequestEntries:\n\t\tv = new(cachestorage.RequestEntriesReturns)\n\tcase CommandCastEnable:\n\t\treturn emptyVal, nil\n\tcase CommandCastDisable:\n\t\treturn emptyVal, nil\n\tcase CommandCastSetSinkToUse:\n\t\treturn emptyVal, nil\n\tcase CommandCastStartDesktopMirroring:\n\t\treturn emptyVal, nil\n\tcase CommandCastStartTabMirroring:\n\t\treturn emptyVal, nil\n\tcase CommandCastStopCasting:\n\t\treturn emptyVal, nil\n\tcase EventCastSinksUpdated:\n\t\tv = new(cast.EventSinksUpdated)\n\tcase EventCastIssueUpdated:\n\t\tv = new(cast.EventIssueUpdated)\n\tcase CommandDOMCollectClassNamesFromSubtree:\n\t\tv = new(dom.CollectClassNamesFromSubtreeReturns)\n\tcase CommandDOMCopyTo:\n\t\tv = new(dom.CopyToReturns)\n\tcase CommandDOMDescribeNode:\n\t\tv = new(dom.DescribeNodeReturns)\n\tcase CommandDOMScrollIntoViewIfNeeded:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDisable:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDiscardSearchResults:\n\t\treturn emptyVal, nil\n\tcase CommandDOMEnable:\n\t\treturn emptyVal, nil\n\tcase CommandDOMFocus:\n\t\treturn emptyVal, nil\n\tcase CommandDOMGetAttributes:\n\t\tv = new(dom.GetAttributesReturns)\n\tcase CommandDOMGetBoxModel:\n\t\tv = new(dom.GetBoxModelReturns)\n\tcase CommandDOMGetContentQuads:\n\t\tv = new(dom.GetContentQuadsReturns)\n\tcase CommandDOMGetDocument:\n\t\tv = new(dom.GetDocumentReturns)\n\tcase CommandDOMGetNodesForSubtreeByStyle:\n\t\tv = new(dom.GetNodesForSubtreeByStyleReturns)\n\tcase CommandDOMGetNodeForLocation:\n\t\tv = new(dom.GetNodeForLocationReturns)\n\tcase CommandDOMGetOuterHTML:\n\t\tv = new(dom.GetOuterHTMLReturns)\n\tcase CommandDOMGetRelayoutBoundary:\n\t\tv = new(dom.GetRelayoutBoundaryReturns)\n\tcase CommandDOMGetSearchResults:\n\t\tv = new(dom.GetSearchResultsReturns)\n\tcase CommandDOMMarkUndoableState:\n\t\treturn emptyVal, nil\n\tcase CommandDOMMoveTo:\n\t\tv = new(dom.MoveToReturns)\n\tcase CommandDOMPerformSearch:\n\t\tv = new(dom.PerformSearchReturns)\n\tcase CommandDOMPushNodeByPathToFrontend:\n\t\tv = new(dom.PushNodeByPathToFrontendReturns)\n\tcase CommandDOMPushNodesByBackendIDsToFrontend:\n\t\tv = new(dom.PushNodesByBackendIDsToFrontendReturns)\n\tcase CommandDOMQuerySelector:\n\t\tv = new(dom.QuerySelectorReturns)\n\tcase CommandDOMQuerySelectorAll:\n\t\tv = new(dom.QuerySelectorAllReturns)\n\tcase CommandDOMGetTopLayerElements:\n\t\tv = new(dom.GetTopLayerElementsReturns)\n\tcase CommandDOMGetElementByRelation:\n\t\tv = new(dom.GetElementByRelationReturns)\n\tcase CommandDOMRedo:\n\t\treturn emptyVal, nil\n\tcase CommandDOMRemoveAttribute:\n\t\treturn emptyVal, nil\n\tcase CommandDOMRemoveNode:\n\t\treturn emptyVal, nil\n\tcase CommandDOMRequestChildNodes:\n\t\treturn emptyVal, nil\n\tcase CommandDOMRequestNode:\n\t\tv = new(dom.RequestNodeReturns)\n\tcase CommandDOMResolveNode:\n\t\tv = new(dom.ResolveNodeReturns)\n\tcase CommandDOMSetAttributeValue:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSetAttributesAsText:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSetFileInputFiles:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSetNodeStackTracesEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandDOMGetNodeStackTraces:\n\t\tv = new(dom.GetNodeStackTracesReturns)\n\tcase CommandDOMGetFileInfo:\n\t\tv = new(dom.GetFileInfoReturns)\n\tcase CommandDOMGetDetachedDomNodes:\n\t\tv = new(dom.GetDetachedDomNodesReturns)\n\tcase CommandDOMSetInspectedNode:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSetNodeName:\n\t\tv = new(dom.SetNodeNameReturns)\n\tcase CommandDOMSetNodeValue:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSetOuterHTML:\n\t\treturn emptyVal, nil\n\tcase CommandDOMUndo:\n\t\treturn emptyVal, nil\n\tcase CommandDOMGetFrameOwner:\n\t\tv = new(dom.GetFrameOwnerReturns)\n\tcase CommandDOMGetContainerForNode:\n\t\tv = new(dom.GetContainerForNodeReturns)\n\tcase CommandDOMGetQueryingDescendantsForContainer:\n\t\tv = new(dom.GetQueryingDescendantsForContainerReturns)\n\tcase CommandDOMGetAnchorElement:\n\t\tv = new(dom.GetAnchorElementReturns)\n\tcase CommandDOMForceShowPopover:\n\t\tv = new(dom.ForceShowPopoverReturns)\n\tcase EventDOMAttributeModified:\n\t\tv = new(dom.EventAttributeModified)\n\tcase EventDOMAttributeRemoved:\n\t\tv = new(dom.EventAttributeRemoved)\n\tcase EventDOMCharacterDataModified:\n\t\tv = new(dom.EventCharacterDataModified)\n\tcase EventDOMChildNodeCountUpdated:\n\t\tv = new(dom.EventChildNodeCountUpdated)\n\tcase EventDOMChildNodeInserted:\n\t\tv = new(dom.EventChildNodeInserted)\n\tcase EventDOMChildNodeRemoved:\n\t\tv = new(dom.EventChildNodeRemoved)\n\tcase EventDOMDistributedNodesUpdated:\n\t\tv = new(dom.EventDistributedNodesUpdated)\n\tcase EventDOMDocumentUpdated:\n\t\tv = new(dom.EventDocumentUpdated)\n\tcase EventDOMInlineStyleInvalidated:\n\t\tv = new(dom.EventInlineStyleInvalidated)\n\tcase EventDOMPseudoElementAdded:\n\t\tv = new(dom.EventPseudoElementAdded)\n\tcase EventDOMTopLayerElementsUpdated:\n\t\tv = new(dom.EventTopLayerElementsUpdated)\n\tcase EventDOMScrollableFlagUpdated:\n\t\tv = new(dom.EventScrollableFlagUpdated)\n\tcase EventDOMPseudoElementRemoved:\n\t\tv = new(dom.EventPseudoElementRemoved)\n\tcase EventDOMSetChildNodes:\n\t\tv = new(dom.EventSetChildNodes)\n\tcase EventDOMShadowRootPopped:\n\t\tv = new(dom.EventShadowRootPopped)\n\tcase EventDOMShadowRootPushed:\n\t\tv = new(dom.EventShadowRootPushed)\n\tcase CommandDOMDebuggerGetEventListeners:\n\t\tv = new(domdebugger.GetEventListenersReturns)\n\tcase CommandDOMDebuggerRemoveDOMBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDebuggerRemoveEventListenerBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDebuggerRemoveXHRBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDebuggerSetBreakOnCSPViolation:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDebuggerSetDOMBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDebuggerSetEventListenerBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandDOMDebuggerSetXHRBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSnapshotDisable:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSnapshotEnable:\n\t\treturn emptyVal, nil\n\tcase CommandDOMSnapshotCaptureSnapshot:\n\t\tv = new(domsnapshot.CaptureSnapshotReturns)\n\tcase CommandDOMStorageClear:\n\t\treturn emptyVal, nil\n\tcase CommandDOMStorageDisable:\n\t\treturn emptyVal, nil\n\tcase CommandDOMStorageEnable:\n\t\treturn emptyVal, nil\n\tcase CommandDOMStorageGetDOMStorageItems:\n\t\tv = new(domstorage.GetDOMStorageItemsReturns)\n\tcase CommandDOMStorageRemoveDOMStorageItem:\n\t\treturn emptyVal, nil\n\tcase CommandDOMStorageSetDOMStorageItem:\n\t\treturn emptyVal, nil\n\tcase EventDOMStorageDomStorageItemAdded:\n\t\tv = new(domstorage.EventDomStorageItemAdded)\n\tcase EventDOMStorageDomStorageItemRemoved:\n\t\tv = new(domstorage.EventDomStorageItemRemoved)\n\tcase EventDOMStorageDomStorageItemUpdated:\n\t\tv = new(domstorage.EventDomStorageItemUpdated)\n\tcase EventDOMStorageDomStorageItemsCleared:\n\t\tv = new(domstorage.EventDomStorageItemsCleared)\n\tcase CommandDebuggerContinueToLocation:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerDisable:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerEnable:\n\t\tv = new(debugger.EnableReturns)\n\tcase CommandDebuggerEvaluateOnCallFrame:\n\t\tv = new(debugger.EvaluateOnCallFrameReturns)\n\tcase CommandDebuggerGetPossibleBreakpoints:\n\t\tv = new(debugger.GetPossibleBreakpointsReturns)\n\tcase CommandDebuggerGetScriptSource:\n\t\tv = new(debugger.GetScriptSourceReturns)\n\tcase CommandDebuggerDisassembleWasmModule:\n\t\tv = new(debugger.DisassembleWasmModuleReturns)\n\tcase CommandDebuggerNextWasmDisassemblyChunk:\n\t\tv = new(debugger.NextWasmDisassemblyChunkReturns)\n\tcase CommandDebuggerGetStackTrace:\n\t\tv = new(debugger.GetStackTraceReturns)\n\tcase CommandDebuggerPause:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerRemoveBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerRestartFrame:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerResume:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSearchInContent:\n\t\tv = new(debugger.SearchInContentReturns)\n\tcase CommandDebuggerSetAsyncCallStackDepth:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetBlackboxExecutionContexts:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetBlackboxPatterns:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetBlackboxedRanges:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetBreakpoint:\n\t\tv = new(debugger.SetBreakpointReturns)\n\tcase CommandDebuggerSetInstrumentationBreakpoint:\n\t\tv = new(debugger.SetInstrumentationBreakpointReturns)\n\tcase CommandDebuggerSetBreakpointByURL:\n\t\tv = new(debugger.SetBreakpointByURLReturns)\n\tcase CommandDebuggerSetBreakpointOnFunctionCall:\n\t\tv = new(debugger.SetBreakpointOnFunctionCallReturns)\n\tcase CommandDebuggerSetBreakpointsActive:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetPauseOnExceptions:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetReturnValue:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetScriptSource:\n\t\tv = new(debugger.SetScriptSourceReturns)\n\tcase CommandDebuggerSetSkipAllPauses:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerSetVariableValue:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerStepInto:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerStepOut:\n\t\treturn emptyVal, nil\n\tcase CommandDebuggerStepOver:\n\t\treturn emptyVal, nil\n\tcase EventDebuggerPaused:\n\t\tv = new(debugger.EventPaused)\n\tcase EventDebuggerResumed:\n\t\tv = new(debugger.EventResumed)\n\tcase EventDebuggerScriptFailedToParse:\n\t\tv = new(debugger.EventScriptFailedToParse)\n\tcase EventDebuggerScriptParsed:\n\t\tv = new(debugger.EventScriptParsed)\n\tcase CommandDeviceAccessEnable:\n\t\treturn emptyVal, nil\n\tcase CommandDeviceAccessDisable:\n\t\treturn emptyVal, nil\n\tcase CommandDeviceAccessSelectPrompt:\n\t\treturn emptyVal, nil\n\tcase CommandDeviceAccessCancelPrompt:\n\t\treturn emptyVal, nil\n\tcase EventDeviceAccessDeviceRequestPrompted:\n\t\tv = new(deviceaccess.EventDeviceRequestPrompted)\n\tcase CommandDeviceOrientationClearDeviceOrientationOverride:\n\t\treturn emptyVal, nil\n\tcase CommandDeviceOrientationSetDeviceOrientationOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationClearDeviceMetricsOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationClearGeolocationOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationResetPageScaleFactor:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetFocusEmulationEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetAutoDarkModeOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetCPUThrottlingRate:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetDefaultBackgroundColorOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetSafeAreaInsetsOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetDeviceMetricsOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetDevicePostureOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationClearDevicePostureOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetDisplayFeaturesOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationClearDisplayFeaturesOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetScrollbarsHidden:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetDocumentCookieDisabled:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetEmitTouchEventsForMouse:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetEmulatedMedia:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetEmulatedVisionDeficiency:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetEmulatedOSTextScale:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetGeolocationOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationGetOverriddenSensorInformation:\n\t\tv = new(emulation.GetOverriddenSensorInformationReturns)\n\tcase CommandEmulationSetSensorOverrideEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetSensorOverrideReadings:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetPressureSourceOverrideEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetPressureStateOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetPressureDataOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetIdleOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationClearIdleOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetPageScaleFactor:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetScriptExecutionDisabled:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetTouchEmulationEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetVirtualTimePolicy:\n\t\tv = new(emulation.SetVirtualTimePolicyReturns)\n\tcase CommandEmulationSetLocaleOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetTimezoneOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetDisabledImageTypes:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetDataSaverOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetHardwareConcurrencyOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetUserAgentOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetAutomationOverride:\n\t\treturn emptyVal, nil\n\tcase CommandEmulationSetSmallViewportHeightDifferenceOverride:\n\t\treturn emptyVal, nil\n\tcase EventEmulationVirtualTimeBudgetExpired:\n\t\tv = new(emulation.EventVirtualTimeBudgetExpired)\n\tcase CommandEventBreakpointsSetInstrumentationBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandEventBreakpointsRemoveInstrumentationBreakpoint:\n\t\treturn emptyVal, nil\n\tcase CommandEventBreakpointsDisable:\n\t\treturn emptyVal, nil\n\tcase CommandExtensionsLoadUnpacked:\n\t\tv = new(extensions.LoadUnpackedReturns)\n\tcase CommandExtensionsUninstall:\n\t\treturn emptyVal, nil\n\tcase CommandExtensionsGetStorageItems:\n\t\tv = new(extensions.GetStorageItemsReturns)\n\tcase CommandExtensionsRemoveStorageItems:\n\t\treturn emptyVal, nil\n\tcase CommandExtensionsClearStorageItems:\n\t\treturn emptyVal, nil\n\tcase CommandExtensionsSetStorageItems:\n\t\treturn emptyVal, nil\n\tcase CommandFedCmEnable:\n\t\treturn emptyVal, nil\n\tcase CommandFedCmDisable:\n\t\treturn emptyVal, nil\n\tcase CommandFedCmSelectAccount:\n\t\treturn emptyVal, nil\n\tcase CommandFedCmClickDialogButton:\n\t\treturn emptyVal, nil\n\tcase CommandFedCmOpenURL:\n\t\treturn emptyVal, nil\n\tcase CommandFedCmDismissDialog:\n\t\treturn emptyVal, nil\n\tcase CommandFedCmResetCooldown:\n\t\treturn emptyVal, nil\n\tcase EventFedCmDialogShown:\n\t\tv = new(fedcm.EventDialogShown)\n\tcase EventFedCmDialogClosed:\n\t\tv = new(fedcm.EventDialogClosed)\n\tcase CommandFetchDisable:\n\t\treturn emptyVal, nil\n\tcase CommandFetchEnable:\n\t\treturn emptyVal, nil\n\tcase CommandFetchFailRequest:\n\t\treturn emptyVal, nil\n\tcase CommandFetchFulfillRequest:\n\t\treturn emptyVal, nil\n\tcase CommandFetchContinueRequest:\n\t\treturn emptyVal, nil\n\tcase CommandFetchContinueWithAuth:\n\t\treturn emptyVal, nil\n\tcase CommandFetchContinueResponse:\n\t\treturn emptyVal, nil\n\tcase CommandFetchGetResponseBody:\n\t\tv = new(fetch.GetResponseBodyReturns)\n\tcase CommandFetchTakeResponseBodyAsStream:\n\t\tv = new(fetch.TakeResponseBodyAsStreamReturns)\n\tcase EventFetchRequestPaused:\n\t\tv = new(fetch.EventRequestPaused)\n\tcase EventFetchAuthRequired:\n\t\tv = new(fetch.EventAuthRequired)\n\tcase CommandFileSystemGetDirectory:\n\t\tv = new(filesystem.GetDirectoryReturns)\n\tcase CommandHeadlessExperimentalBeginFrame:\n\t\tv = new(headlessexperimental.BeginFrameReturns)\n\tcase CommandHeapProfilerAddInspectedHeapObject:\n\t\treturn emptyVal, nil\n\tcase CommandHeapProfilerCollectGarbage:\n\t\treturn emptyVal, nil\n\tcase CommandHeapProfilerDisable:\n\t\treturn emptyVal, nil\n\tcase CommandHeapProfilerEnable:\n\t\treturn emptyVal, nil\n\tcase CommandHeapProfilerGetHeapObjectID:\n\t\tv = new(heapprofiler.GetHeapObjectIDReturns)\n\tcase CommandHeapProfilerGetObjectByHeapObjectID:\n\t\tv = new(heapprofiler.GetObjectByHeapObjectIDReturns)\n\tcase CommandHeapProfilerGetSamplingProfile:\n\t\tv = new(heapprofiler.GetSamplingProfileReturns)\n\tcase CommandHeapProfilerStartSampling:\n\t\treturn emptyVal, nil\n\tcase CommandHeapProfilerStartTrackingHeapObjects:\n\t\treturn emptyVal, nil\n\tcase CommandHeapProfilerStopSampling:\n\t\tv = new(heapprofiler.StopSamplingReturns)\n\tcase CommandHeapProfilerStopTrackingHeapObjects:\n\t\treturn emptyVal, nil\n\tcase CommandHeapProfilerTakeHeapSnapshot:\n\t\treturn emptyVal, nil\n\tcase EventHeapProfilerAddHeapSnapshotChunk:\n\t\tv = new(heapprofiler.EventAddHeapSnapshotChunk)\n\tcase EventHeapProfilerHeapStatsUpdate:\n\t\tv = new(heapprofiler.EventHeapStatsUpdate)\n\tcase EventHeapProfilerLastSeenObjectID:\n\t\tv = new(heapprofiler.EventLastSeenObjectID)\n\tcase EventHeapProfilerReportHeapSnapshotProgress:\n\t\tv = new(heapprofiler.EventReportHeapSnapshotProgress)\n\tcase EventHeapProfilerResetProfiles:\n\t\tv = new(heapprofiler.EventResetProfiles)\n\tcase CommandIOClose:\n\t\treturn emptyVal, nil\n\tcase CommandIORead:\n\t\tv = new(io.ReadReturns)\n\tcase CommandIOResolveBlob:\n\t\tv = new(io.ResolveBlobReturns)\n\tcase CommandIndexedDBClearObjectStore:\n\t\treturn emptyVal, nil\n\tcase CommandIndexedDBDeleteDatabase:\n\t\treturn emptyVal, nil\n\tcase CommandIndexedDBDeleteObjectStoreEntries:\n\t\treturn emptyVal, nil\n\tcase CommandIndexedDBDisable:\n\t\treturn emptyVal, nil\n\tcase CommandIndexedDBEnable:\n\t\treturn emptyVal, nil\n\tcase CommandIndexedDBRequestData:\n\t\tv = new(indexeddb.RequestDataReturns)\n\tcase CommandIndexedDBGetMetadata:\n\t\tv = new(indexeddb.GetMetadataReturns)\n\tcase CommandIndexedDBRequestDatabase:\n\t\tv = new(indexeddb.RequestDatabaseReturns)\n\tcase CommandIndexedDBRequestDatabaseNames:\n\t\tv = new(indexeddb.RequestDatabaseNamesReturns)\n\tcase CommandInputDispatchDragEvent:\n\t\treturn emptyVal, nil\n\tcase CommandInputDispatchKeyEvent:\n\t\treturn emptyVal, nil\n\tcase CommandInputInsertText:\n\t\treturn emptyVal, nil\n\tcase CommandInputImeSetComposition:\n\t\treturn emptyVal, nil\n\tcase CommandInputDispatchMouseEvent:\n\t\treturn emptyVal, nil\n\tcase CommandInputDispatchTouchEvent:\n\t\treturn emptyVal, nil\n\tcase CommandInputCancelDragging:\n\t\treturn emptyVal, nil\n\tcase CommandInputEmulateTouchFromMouseEvent:\n\t\treturn emptyVal, nil\n\tcase CommandInputSetIgnoreInputEvents:\n\t\treturn emptyVal, nil\n\tcase CommandInputSetInterceptDrags:\n\t\treturn emptyVal, nil\n\tcase CommandInputSynthesizePinchGesture:\n\t\treturn emptyVal, nil\n\tcase CommandInputSynthesizeScrollGesture:\n\t\treturn emptyVal, nil\n\tcase CommandInputSynthesizeTapGesture:\n\t\treturn emptyVal, nil\n\tcase EventInputDragIntercepted:\n\t\tv = new(input.EventDragIntercepted)\n\tcase CommandInspectorDisable:\n\t\treturn emptyVal, nil\n\tcase CommandInspectorEnable:\n\t\treturn emptyVal, nil\n\tcase EventInspectorDetached:\n\t\tv = new(inspector.EventDetached)\n\tcase EventInspectorTargetCrashed:\n\t\tv = new(inspector.EventTargetCrashed)\n\tcase EventInspectorTargetReloadedAfterCrash:\n\t\tv = new(inspector.EventTargetReloadedAfterCrash)\n\tcase CommandLayerTreeCompositingReasons:\n\t\tv = new(layertree.CompositingReasonsReturns)\n\tcase CommandLayerTreeDisable:\n\t\treturn emptyVal, nil\n\tcase CommandLayerTreeEnable:\n\t\treturn emptyVal, nil\n\tcase CommandLayerTreeLoadSnapshot:\n\t\tv = new(layertree.LoadSnapshotReturns)\n\tcase CommandLayerTreeMakeSnapshot:\n\t\tv = new(layertree.MakeSnapshotReturns)\n\tcase CommandLayerTreeProfileSnapshot:\n\t\tv = new(layertree.ProfileSnapshotReturns)\n\tcase CommandLayerTreeReleaseSnapshot:\n\t\treturn emptyVal, nil\n\tcase CommandLayerTreeReplaySnapshot:\n\t\tv = new(layertree.ReplaySnapshotReturns)\n\tcase CommandLayerTreeSnapshotCommandLog:\n\t\tv = new(layertree.SnapshotCommandLogReturns)\n\tcase EventLayerTreeLayerPainted:\n\t\tv = new(layertree.EventLayerPainted)\n\tcase EventLayerTreeLayerTreeDidChange:\n\t\tv = new(layertree.EventLayerTreeDidChange)\n\tcase CommandLogClear:\n\t\treturn emptyVal, nil\n\tcase CommandLogDisable:\n\t\treturn emptyVal, nil\n\tcase CommandLogEnable:\n\t\treturn emptyVal, nil\n\tcase CommandLogStartViolationsReport:\n\t\treturn emptyVal, nil\n\tcase CommandLogStopViolationsReport:\n\t\treturn emptyVal, nil\n\tcase EventLogEntryAdded:\n\t\tv = new(log.EventEntryAdded)\n\tcase CommandMediaEnable:\n\t\treturn emptyVal, nil\n\tcase CommandMediaDisable:\n\t\treturn emptyVal, nil\n\tcase EventMediaPlayerPropertiesChanged:\n\t\tv = new(media.EventPlayerPropertiesChanged)\n\tcase EventMediaPlayerEventsAdded:\n\t\tv = new(media.EventPlayerEventsAdded)\n\tcase EventMediaPlayerMessagesLogged:\n\t\tv = new(media.EventPlayerMessagesLogged)\n\tcase EventMediaPlayerErrorsRaised:\n\t\tv = new(media.EventPlayerErrorsRaised)\n\tcase EventMediaPlayersCreated:\n\t\tv = new(media.EventPlayersCreated)\n\tcase CommandMemoryGetDOMCounters:\n\t\tv = new(memory.GetDOMCountersReturns)\n\tcase CommandMemoryGetDOMCountersForLeakDetection:\n\t\tv = new(memory.GetDOMCountersForLeakDetectionReturns)\n\tcase CommandMemoryPrepareForLeakDetection:\n\t\treturn emptyVal, nil\n\tcase CommandMemoryForciblyPurgeJavaScriptMemory:\n\t\treturn emptyVal, nil\n\tcase CommandMemorySetPressureNotificationsSuppressed:\n\t\treturn emptyVal, nil\n\tcase CommandMemorySimulatePressureNotification:\n\t\treturn emptyVal, nil\n\tcase CommandMemoryStartSampling:\n\t\treturn emptyVal, nil\n\tcase CommandMemoryStopSampling:\n\t\treturn emptyVal, nil\n\tcase CommandMemoryGetAllTimeSamplingProfile:\n\t\tv = new(memory.GetAllTimeSamplingProfileReturns)\n\tcase CommandMemoryGetBrowserSamplingProfile:\n\t\tv = new(memory.GetBrowserSamplingProfileReturns)\n\tcase CommandMemoryGetSamplingProfile:\n\t\tv = new(memory.GetSamplingProfileReturns)\n\tcase CommandNetworkSetAcceptedEncodings:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkClearAcceptedEncodingsOverride:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkClearBrowserCache:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkClearBrowserCookies:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkDeleteCookies:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkDisable:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkEmulateNetworkConditions:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkEnable:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkGetCertificate:\n\t\tv = new(network.GetCertificateReturns)\n\tcase CommandNetworkGetCookies:\n\t\tv = new(network.GetCookiesReturns)\n\tcase CommandNetworkGetResponseBody:\n\t\tv = new(network.GetResponseBodyReturns)\n\tcase CommandNetworkGetRequestPostData:\n\t\tv = new(network.GetRequestPostDataReturns)\n\tcase CommandNetworkGetResponseBodyForInterception:\n\t\tv = new(network.GetResponseBodyForInterceptionReturns)\n\tcase CommandNetworkTakeResponseBodyForInterceptionAsStream:\n\t\tv = new(network.TakeResponseBodyForInterceptionAsStreamReturns)\n\tcase CommandNetworkReplayXHR:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkSearchInResponseBody:\n\t\tv = new(network.SearchInResponseBodyReturns)\n\tcase CommandNetworkSetBlockedURLs:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkSetBypassServiceWorker:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkSetCacheDisabled:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkSetCookie:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkSetCookies:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkSetExtraHTTPHeaders:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkSetAttachDebugStack:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkStreamResourceContent:\n\t\tv = new(network.StreamResourceContentReturns)\n\tcase CommandNetworkGetSecurityIsolationStatus:\n\t\tv = new(network.GetSecurityIsolationStatusReturns)\n\tcase CommandNetworkEnableReportingAPI:\n\t\treturn emptyVal, nil\n\tcase CommandNetworkLoadNetworkResource:\n\t\tv = new(network.LoadNetworkResourceReturns)\n\tcase CommandNetworkSetCookieControls:\n\t\treturn emptyVal, nil\n\tcase EventNetworkDataReceived:\n\t\tv = new(network.EventDataReceived)\n\tcase EventNetworkEventSourceMessageReceived:\n\t\tv = new(network.EventEventSourceMessageReceived)\n\tcase EventNetworkLoadingFailed:\n\t\tv = new(network.EventLoadingFailed)\n\tcase EventNetworkLoadingFinished:\n\t\tv = new(network.EventLoadingFinished)\n\tcase EventNetworkRequestServedFromCache:\n\t\tv = new(network.EventRequestServedFromCache)\n\tcase EventNetworkRequestWillBeSent:\n\t\tv = new(network.EventRequestWillBeSent)\n\tcase EventNetworkResourceChangedPriority:\n\t\tv = new(network.EventResourceChangedPriority)\n\tcase EventNetworkSignedExchangeReceived:\n\t\tv = new(network.EventSignedExchangeReceived)\n\tcase EventNetworkResponseReceived:\n\t\tv = new(network.EventResponseReceived)\n\tcase EventNetworkWebSocketClosed:\n\t\tv = new(network.EventWebSocketClosed)\n\tcase EventNetworkWebSocketCreated:\n\t\tv = new(network.EventWebSocketCreated)\n\tcase EventNetworkWebSocketFrameError:\n\t\tv = new(network.EventWebSocketFrameError)\n\tcase EventNetworkWebSocketFrameReceived:\n\t\tv = new(network.EventWebSocketFrameReceived)\n\tcase EventNetworkWebSocketFrameSent:\n\t\tv = new(network.EventWebSocketFrameSent)\n\tcase EventNetworkWebSocketHandshakeResponseReceived:\n\t\tv = new(network.EventWebSocketHandshakeResponseReceived)\n\tcase EventNetworkWebSocketWillSendHandshakeRequest:\n\t\tv = new(network.EventWebSocketWillSendHandshakeRequest)\n\tcase EventNetworkWebTransportCreated:\n\t\tv = new(network.EventWebTransportCreated)\n\tcase EventNetworkWebTransportConnectionEstablished:\n\t\tv = new(network.EventWebTransportConnectionEstablished)\n\tcase EventNetworkWebTransportClosed:\n\t\tv = new(network.EventWebTransportClosed)\n\tcase EventNetworkDirectTCPSocketCreated:\n\t\tv = new(network.EventDirectTCPSocketCreated)\n\tcase EventNetworkDirectTCPSocketOpened:\n\t\tv = new(network.EventDirectTCPSocketOpened)\n\tcase EventNetworkDirectTCPSocketAborted:\n\t\tv = new(network.EventDirectTCPSocketAborted)\n\tcase EventNetworkDirectTCPSocketClosed:\n\t\tv = new(network.EventDirectTCPSocketClosed)\n\tcase EventNetworkDirectTCPSocketChunkSent:\n\t\tv = new(network.EventDirectTCPSocketChunkSent)\n\tcase EventNetworkDirectTCPSocketChunkReceived:\n\t\tv = new(network.EventDirectTCPSocketChunkReceived)\n\tcase EventNetworkDirectUDPSocketCreated:\n\t\tv = new(network.EventDirectUDPSocketCreated)\n\tcase EventNetworkDirectUDPSocketOpened:\n\t\tv = new(network.EventDirectUDPSocketOpened)\n\tcase EventNetworkDirectUDPSocketAborted:\n\t\tv = new(network.EventDirectUDPSocketAborted)\n\tcase EventNetworkDirectUDPSocketClosed:\n\t\tv = new(network.EventDirectUDPSocketClosed)\n\tcase EventNetworkDirectUDPSocketChunkSent:\n\t\tv = new(network.EventDirectUDPSocketChunkSent)\n\tcase EventNetworkDirectUDPSocketChunkReceived:\n\t\tv = new(network.EventDirectUDPSocketChunkReceived)\n\tcase EventNetworkRequestWillBeSentExtraInfo:\n\t\tv = new(network.EventRequestWillBeSentExtraInfo)\n\tcase EventNetworkResponseReceivedExtraInfo:\n\t\tv = new(network.EventResponseReceivedExtraInfo)\n\tcase EventNetworkResponseReceivedEarlyHints:\n\t\tv = new(network.EventResponseReceivedEarlyHints)\n\tcase EventNetworkTrustTokenOperationDone:\n\t\tv = new(network.EventTrustTokenOperationDone)\n\tcase EventNetworkPolicyUpdated:\n\t\tv = new(network.EventPolicyUpdated)\n\tcase EventNetworkSubresourceWebBundleMetadataReceived:\n\t\tv = new(network.EventSubresourceWebBundleMetadataReceived)\n\tcase EventNetworkSubresourceWebBundleMetadataError:\n\t\tv = new(network.EventSubresourceWebBundleMetadataError)\n\tcase EventNetworkSubresourceWebBundleInnerResponseParsed:\n\t\tv = new(network.EventSubresourceWebBundleInnerResponseParsed)\n\tcase EventNetworkSubresourceWebBundleInnerResponseError:\n\t\tv = new(network.EventSubresourceWebBundleInnerResponseError)\n\tcase EventNetworkReportingAPIReportAdded:\n\t\tv = new(network.EventReportingAPIReportAdded)\n\tcase EventNetworkReportingAPIReportUpdated:\n\t\tv = new(network.EventReportingAPIReportUpdated)\n\tcase EventNetworkReportingAPIEndpointsChangedForOrigin:\n\t\tv = new(network.EventReportingAPIEndpointsChangedForOrigin)\n\tcase CommandOverlayDisable:\n\t\treturn emptyVal, nil\n\tcase CommandOverlayEnable:\n\t\treturn emptyVal, nil\n\tcase CommandOverlayGetHighlightObjectForTest:\n\t\tv = new(overlay.GetHighlightObjectForTestReturns)\n\tcase CommandOverlayGetGridHighlightObjectsForTest:\n\t\tv = new(overlay.GetGridHighlightObjectsForTestReturns)\n\tcase CommandOverlayGetSourceOrderHighlightObjectForTest:\n\t\tv = new(overlay.GetSourceOrderHighlightObjectForTestReturns)\n\tcase CommandOverlayHideHighlight:\n\t\treturn emptyVal, nil\n\tcase CommandOverlayHighlightNode:\n\t\treturn emptyVal, nil\n\tcase CommandOverlayHighlightQuad:\n\t\treturn emptyVal, nil\n\tcase CommandOverlayHighlightRect:\n\t\treturn emptyVal, nil\n\tcase CommandOverlayHighlightSourceOrder:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetInspectMode:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowAdHighlights:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetPausedInDebuggerMessage:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowDebugBorders:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowFPSCounter:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowGridOverlays:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowFlexOverlays:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowScrollSnapOverlays:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowContainerQueryOverlays:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowPaintRects:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowLayoutShiftRegions:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowScrollBottleneckRects:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowViewportSizeOnResize:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowHinge:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowIsolatedElements:\n\t\treturn emptyVal, nil\n\tcase CommandOverlaySetShowWindowControlsOverlay:\n\t\treturn emptyVal, nil\n\tcase EventOverlayInspectNodeRequested:\n\t\tv = new(overlay.EventInspectNodeRequested)\n\tcase EventOverlayNodeHighlightRequested:\n\t\tv = new(overlay.EventNodeHighlightRequested)\n\tcase EventOverlayScreenshotRequested:\n\t\tv = new(overlay.EventScreenshotRequested)\n\tcase EventOverlayInspectModeCanceled:\n\t\tv = new(overlay.EventInspectModeCanceled)\n\tcase CommandPWAGetOsAppState:\n\t\tv = new(pwa.GetOsAppStateReturns)\n\tcase CommandPWAInstall:\n\t\treturn emptyVal, nil\n\tcase CommandPWAUninstall:\n\t\treturn emptyVal, nil\n\tcase CommandPWALaunch:\n\t\tv = new(pwa.LaunchReturns)\n\tcase CommandPWALaunchFilesInApp:\n\t\tv = new(pwa.LaunchFilesInAppReturns)\n\tcase CommandPWAOpenCurrentPageInApp:\n\t\treturn emptyVal, nil\n\tcase CommandPWAChangeAppUserSettings:\n\t\treturn emptyVal, nil\n\tcase CommandPageAddScriptToEvaluateOnNewDocument:\n\t\tv = new(page.AddScriptToEvaluateOnNewDocumentReturns)\n\tcase CommandPageBringToFront:\n\t\treturn emptyVal, nil\n\tcase CommandPageCaptureScreenshot:\n\t\tv = new(page.CaptureScreenshotReturns)\n\tcase CommandPageCaptureSnapshot:\n\t\tv = new(page.CaptureSnapshotReturns)\n\tcase CommandPageCreateIsolatedWorld:\n\t\tv = new(page.CreateIsolatedWorldReturns)\n\tcase CommandPageDisable:\n\t\treturn emptyVal, nil\n\tcase CommandPageEnable:\n\t\treturn emptyVal, nil\n\tcase CommandPageGetAppManifest:\n\t\tv = new(page.GetAppManifestReturns)\n\tcase CommandPageGetInstallabilityErrors:\n\t\tv = new(page.GetInstallabilityErrorsReturns)\n\tcase CommandPageGetAppID:\n\t\tv = new(page.GetAppIDReturns)\n\tcase CommandPageGetAdScriptAncestry:\n\t\tv = new(page.GetAdScriptAncestryReturns)\n\tcase CommandPageGetFrameTree:\n\t\tv = new(page.GetFrameTreeReturns)\n\tcase CommandPageGetLayoutMetrics:\n\t\tv = new(page.GetLayoutMetricsReturns)\n\tcase CommandPageGetNavigationHistory:\n\t\tv = new(page.GetNavigationHistoryReturns)\n\tcase CommandPageResetNavigationHistory:\n\t\treturn emptyVal, nil\n\tcase CommandPageGetResourceContent:\n\t\tv = new(page.GetResourceContentReturns)\n\tcase CommandPageGetResourceTree:\n\t\tv = new(page.GetResourceTreeReturns)\n\tcase CommandPageHandleJavaScriptDialog:\n\t\treturn emptyVal, nil\n\tcase CommandPageNavigate:\n\t\tv = new(page.NavigateReturns)\n\tcase CommandPageNavigateToHistoryEntry:\n\t\treturn emptyVal, nil\n\tcase CommandPagePrintToPDF:\n\t\tv = new(page.PrintToPDFReturns)\n\tcase CommandPageReload:\n\t\treturn emptyVal, nil\n\tcase CommandPageRemoveScriptToEvaluateOnNewDocument:\n\t\treturn emptyVal, nil\n\tcase CommandPageScreencastFrameAck:\n\t\treturn emptyVal, nil\n\tcase CommandPageSearchInResource:\n\t\tv = new(page.SearchInResourceReturns)\n\tcase CommandPageSetAdBlockingEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetBypassCSP:\n\t\treturn emptyVal, nil\n\tcase CommandPageGetPermissionsPolicyState:\n\t\tv = new(page.GetPermissionsPolicyStateReturns)\n\tcase CommandPageGetOriginTrials:\n\t\tv = new(page.GetOriginTrialsReturns)\n\tcase CommandPageSetFontFamilies:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetFontSizes:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetDocumentContent:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetLifecycleEventsEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandPageStartScreencast:\n\t\treturn emptyVal, nil\n\tcase CommandPageStopLoading:\n\t\treturn emptyVal, nil\n\tcase CommandPageCrash:\n\t\treturn emptyVal, nil\n\tcase CommandPageClose:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetWebLifecycleState:\n\t\treturn emptyVal, nil\n\tcase CommandPageStopScreencast:\n\t\treturn emptyVal, nil\n\tcase CommandPageProduceCompilationCache:\n\t\treturn emptyVal, nil\n\tcase CommandPageAddCompilationCache:\n\t\treturn emptyVal, nil\n\tcase CommandPageClearCompilationCache:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetSPCTransactionMode:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetRPHRegistrationMode:\n\t\treturn emptyVal, nil\n\tcase CommandPageGenerateTestReport:\n\t\treturn emptyVal, nil\n\tcase CommandPageWaitForDebugger:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetInterceptFileChooserDialog:\n\t\treturn emptyVal, nil\n\tcase CommandPageSetPrerenderingAllowed:\n\t\treturn emptyVal, nil\n\tcase EventPageDomContentEventFired:\n\t\tv = new(page.EventDomContentEventFired)\n\tcase EventPageFileChooserOpened:\n\t\tv = new(page.EventFileChooserOpened)\n\tcase EventPageFrameAttached:\n\t\tv = new(page.EventFrameAttached)\n\tcase EventPageFrameDetached:\n\t\tv = new(page.EventFrameDetached)\n\tcase EventPageFrameSubtreeWillBeDetached:\n\t\tv = new(page.EventFrameSubtreeWillBeDetached)\n\tcase EventPageFrameNavigated:\n\t\tv = new(page.EventFrameNavigated)\n\tcase EventPageDocumentOpened:\n\t\tv = new(page.EventDocumentOpened)\n\tcase EventPageFrameResized:\n\t\tv = new(page.EventFrameResized)\n\tcase EventPageFrameStartedNavigating:\n\t\tv = new(page.EventFrameStartedNavigating)\n\tcase EventPageFrameRequestedNavigation:\n\t\tv = new(page.EventFrameRequestedNavigation)\n\tcase EventPageFrameStartedLoading:\n\t\tv = new(page.EventFrameStartedLoading)\n\tcase EventPageFrameStoppedLoading:\n\t\tv = new(page.EventFrameStoppedLoading)\n\tcase EventPageInterstitialHidden:\n\t\tv = new(page.EventInterstitialHidden)\n\tcase EventPageInterstitialShown:\n\t\tv = new(page.EventInterstitialShown)\n\tcase EventPageJavascriptDialogClosed:\n\t\tv = new(page.EventJavascriptDialogClosed)\n\tcase EventPageJavascriptDialogOpening:\n\t\tv = new(page.EventJavascriptDialogOpening)\n\tcase EventPageLifecycleEvent:\n\t\tv = new(page.EventLifecycleEvent)\n\tcase EventPageBackForwardCacheNotUsed:\n\t\tv = new(page.EventBackForwardCacheNotUsed)\n\tcase EventPageLoadEventFired:\n\t\tv = new(page.EventLoadEventFired)\n\tcase EventPageNavigatedWithinDocument:\n\t\tv = new(page.EventNavigatedWithinDocument)\n\tcase EventPageScreencastFrame:\n\t\tv = new(page.EventScreencastFrame)\n\tcase EventPageScreencastVisibilityChanged:\n\t\tv = new(page.EventScreencastVisibilityChanged)\n\tcase EventPageWindowOpen:\n\t\tv = new(page.EventWindowOpen)\n\tcase EventPageCompilationCacheProduced:\n\t\tv = new(page.EventCompilationCacheProduced)\n\tcase CommandPerformanceDisable:\n\t\treturn emptyVal, nil\n\tcase CommandPerformanceEnable:\n\t\treturn emptyVal, nil\n\tcase CommandPerformanceGetMetrics:\n\t\tv = new(performance.GetMetricsReturns)\n\tcase EventPerformanceMetrics:\n\t\tv = new(performance.EventMetrics)\n\tcase CommandPerformanceTimelineEnable:\n\t\treturn emptyVal, nil\n\tcase EventPerformanceTimelineTimelineEventAdded:\n\t\tv = new(performancetimeline.EventTimelineEventAdded)\n\tcase CommandPreloadEnable:\n\t\treturn emptyVal, nil\n\tcase CommandPreloadDisable:\n\t\treturn emptyVal, nil\n\tcase EventPreloadRuleSetUpdated:\n\t\tv = new(preload.EventRuleSetUpdated)\n\tcase EventPreloadRuleSetRemoved:\n\t\tv = new(preload.EventRuleSetRemoved)\n\tcase EventPreloadPreloadEnabledStateUpdated:\n\t\tv = new(preload.EventPreloadEnabledStateUpdated)\n\tcase EventPreloadPrefetchStatusUpdated:\n\t\tv = new(preload.EventPrefetchStatusUpdated)\n\tcase EventPreloadPrerenderStatusUpdated:\n\t\tv = new(preload.EventPrerenderStatusUpdated)\n\tcase EventPreloadPreloadingAttemptSourcesUpdated:\n\t\tv = new(preload.EventPreloadingAttemptSourcesUpdated)\n\tcase CommandProfilerDisable:\n\t\treturn emptyVal, nil\n\tcase CommandProfilerEnable:\n\t\treturn emptyVal, nil\n\tcase CommandProfilerGetBestEffortCoverage:\n\t\tv = new(profiler.GetBestEffortCoverageReturns)\n\tcase CommandProfilerSetSamplingInterval:\n\t\treturn emptyVal, nil\n\tcase CommandProfilerStart:\n\t\treturn emptyVal, nil\n\tcase CommandProfilerStartPreciseCoverage:\n\t\tv = new(profiler.StartPreciseCoverageReturns)\n\tcase CommandProfilerStop:\n\t\tv = new(profiler.StopReturns)\n\tcase CommandProfilerStopPreciseCoverage:\n\t\treturn emptyVal, nil\n\tcase CommandProfilerTakePreciseCoverage:\n\t\tv = new(profiler.TakePreciseCoverageReturns)\n\tcase EventProfilerConsoleProfileFinished:\n\t\tv = new(profiler.EventConsoleProfileFinished)\n\tcase EventProfilerConsoleProfileStarted:\n\t\tv = new(profiler.EventConsoleProfileStarted)\n\tcase EventProfilerPreciseCoverageDeltaUpdate:\n\t\tv = new(profiler.EventPreciseCoverageDeltaUpdate)\n\tcase CommandRuntimeAwaitPromise:\n\t\tv = new(runtime.AwaitPromiseReturns)\n\tcase CommandRuntimeCallFunctionOn:\n\t\tv = new(runtime.CallFunctionOnReturns)\n\tcase CommandRuntimeCompileScript:\n\t\tv = new(runtime.CompileScriptReturns)\n\tcase CommandRuntimeDisable:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeDiscardConsoleEntries:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeEnable:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeEvaluate:\n\t\tv = new(runtime.EvaluateReturns)\n\tcase CommandRuntimeGetIsolateID:\n\t\tv = new(runtime.GetIsolateIDReturns)\n\tcase CommandRuntimeGetHeapUsage:\n\t\tv = new(runtime.GetHeapUsageReturns)\n\tcase CommandRuntimeGetProperties:\n\t\tv = new(runtime.GetPropertiesReturns)\n\tcase CommandRuntimeGlobalLexicalScopeNames:\n\t\tv = new(runtime.GlobalLexicalScopeNamesReturns)\n\tcase CommandRuntimeQueryObjects:\n\t\tv = new(runtime.QueryObjectsReturns)\n\tcase CommandRuntimeReleaseObject:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeReleaseObjectGroup:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeRunIfWaitingForDebugger:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeRunScript:\n\t\tv = new(runtime.RunScriptReturns)\n\tcase CommandRuntimeSetCustomObjectFormatterEnabled:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeSetMaxCallStackSizeToCapture:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeTerminateExecution:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeAddBinding:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeRemoveBinding:\n\t\treturn emptyVal, nil\n\tcase CommandRuntimeGetExceptionDetails:\n\t\tv = new(runtime.GetExceptionDetailsReturns)\n\tcase EventRuntimeBindingCalled:\n\t\tv = new(runtime.EventBindingCalled)\n\tcase EventRuntimeConsoleAPICalled:\n\t\tv = new(runtime.EventConsoleAPICalled)\n\tcase EventRuntimeExceptionRevoked:\n\t\tv = new(runtime.EventExceptionRevoked)\n\tcase EventRuntimeExceptionThrown:\n\t\tv = new(runtime.EventExceptionThrown)\n\tcase EventRuntimeExecutionContextCreated:\n\t\tv = new(runtime.EventExecutionContextCreated)\n\tcase EventRuntimeExecutionContextDestroyed:\n\t\tv = new(runtime.EventExecutionContextDestroyed)\n\tcase EventRuntimeExecutionContextsCleared:\n\t\tv = new(runtime.EventExecutionContextsCleared)\n\tcase EventRuntimeInspectRequested:\n\t\tv = new(runtime.EventInspectRequested)\n\tcase CommandSecurityDisable:\n\t\treturn emptyVal, nil\n\tcase CommandSecurityEnable:\n\t\treturn emptyVal, nil\n\tcase CommandSecuritySetIgnoreCertificateErrors:\n\t\treturn emptyVal, nil\n\tcase EventSecurityVisibleSecurityStateChanged:\n\t\tv = new(security.EventVisibleSecurityStateChanged)\n\tcase CommandServiceWorkerDeliverPushMessage:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerDisable:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerDispatchSyncEvent:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerDispatchPeriodicSyncEvent:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerEnable:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerSetForceUpdateOnPageLoad:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerSkipWaiting:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerStartWorker:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerStopAllWorkers:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerStopWorker:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerUnregister:\n\t\treturn emptyVal, nil\n\tcase CommandServiceWorkerUpdateRegistration:\n\t\treturn emptyVal, nil\n\tcase EventServiceWorkerWorkerErrorReported:\n\t\tv = new(serviceworker.EventWorkerErrorReported)\n\tcase EventServiceWorkerWorkerRegistrationUpdated:\n\t\tv = new(serviceworker.EventWorkerRegistrationUpdated)\n\tcase EventServiceWorkerWorkerVersionUpdated:\n\t\tv = new(serviceworker.EventWorkerVersionUpdated)\n\tcase CommandStorageGetStorageKeyForFrame:\n\t\tv = new(storage.GetStorageKeyForFrameReturns)\n\tcase CommandStorageClearDataForOrigin:\n\t\treturn emptyVal, nil\n\tcase CommandStorageClearDataForStorageKey:\n\t\treturn emptyVal, nil\n\tcase CommandStorageGetCookies:\n\t\tv = new(storage.GetCookiesReturns)\n\tcase CommandStorageSetCookies:\n\t\treturn emptyVal, nil\n\tcase CommandStorageClearCookies:\n\t\treturn emptyVal, nil\n\tcase CommandStorageGetUsageAndQuota:\n\t\tv = new(storage.GetUsageAndQuotaReturns)\n\tcase CommandStorageOverrideQuotaForOrigin:\n\t\treturn emptyVal, nil\n\tcase CommandStorageTrackCacheStorageForOrigin:\n\t\treturn emptyVal, nil\n\tcase CommandStorageTrackCacheStorageForStorageKey:\n\t\treturn emptyVal, nil\n\tcase CommandStorageTrackIndexedDBForOrigin:\n\t\treturn emptyVal, nil\n\tcase CommandStorageTrackIndexedDBForStorageKey:\n\t\treturn emptyVal, nil\n\tcase CommandStorageUntrackCacheStorageForOrigin:\n\t\treturn emptyVal, nil\n\tcase CommandStorageUntrackCacheStorageForStorageKey:\n\t\treturn emptyVal, nil\n\tcase CommandStorageUntrackIndexedDBForOrigin:\n\t\treturn emptyVal, nil\n\tcase CommandStorageUntrackIndexedDBForStorageKey:\n\t\treturn emptyVal, nil\n\tcase CommandStorageGetTrustTokens:\n\t\tv = new(storage.GetTrustTokensReturns)\n\tcase CommandStorageClearTrustTokens:\n\t\tv = new(storage.ClearTrustTokensReturns)\n\tcase CommandStorageGetInterestGroupDetails:\n\t\tv = new(storage.GetInterestGroupDetailsReturns)\n\tcase CommandStorageSetInterestGroupTracking:\n\t\treturn emptyVal, nil\n\tcase CommandStorageSetInterestGroupAuctionTracking:\n\t\treturn emptyVal, nil\n\tcase CommandStorageGetSharedStorageMetadata:\n\t\tv = new(storage.GetSharedStorageMetadataReturns)\n\tcase CommandStorageGetSharedStorageEntries:\n\t\tv = new(storage.GetSharedStorageEntriesReturns)\n\tcase CommandStorageSetSharedStorageEntry:\n\t\treturn emptyVal, nil\n\tcase CommandStorageDeleteSharedStorageEntry:\n\t\treturn emptyVal, nil\n\tcase CommandStorageClearSharedStorageEntries:\n\t\treturn emptyVal, nil\n\tcase CommandStorageResetSharedStorageBudget:\n\t\treturn emptyVal, nil\n\tcase CommandStorageSetSharedStorageTracking:\n\t\treturn emptyVal, nil\n\tcase CommandStorageSetStorageBucketTracking:\n\t\treturn emptyVal, nil\n\tcase CommandStorageDeleteStorageBucket:\n\t\treturn emptyVal, nil\n\tcase CommandStorageRunBounceTrackingMitigations:\n\t\tv = new(storage.RunBounceTrackingMitigationsReturns)\n\tcase CommandStorageSetAttributionReportingLocalTestingMode:\n\t\treturn emptyVal, nil\n\tcase CommandStorageSetAttributionReportingTracking:\n\t\treturn emptyVal, nil\n\tcase CommandStorageSendPendingAttributionReports:\n\t\tv = new(storage.SendPendingAttributionReportsReturns)\n\tcase CommandStorageGetRelatedWebsiteSets:\n\t\tv = new(storage.GetRelatedWebsiteSetsReturns)\n\tcase CommandStorageGetAffectedURLsForThirdPartyCookieMetadata:\n\t\tv = new(storage.GetAffectedURLsForThirdPartyCookieMetadataReturns)\n\tcase CommandStorageSetProtectedAudienceKAnonymity:\n\t\treturn emptyVal, nil\n\tcase EventStorageCacheStorageContentUpdated:\n\t\tv = new(storage.EventCacheStorageContentUpdated)\n\tcase EventStorageCacheStorageListUpdated:\n\t\tv = new(storage.EventCacheStorageListUpdated)\n\tcase EventStorageIndexedDBContentUpdated:\n\t\tv = new(storage.EventIndexedDBContentUpdated)\n\tcase EventStorageIndexedDBListUpdated:\n\t\tv = new(storage.EventIndexedDBListUpdated)\n\tcase EventStorageInterestGroupAccessed:\n\t\tv = new(storage.EventInterestGroupAccessed)\n\tcase EventStorageInterestGroupAuctionEventOccurred:\n\t\tv = new(storage.EventInterestGroupAuctionEventOccurred)\n\tcase EventStorageInterestGroupAuctionNetworkRequestCreated:\n\t\tv = new(storage.EventInterestGroupAuctionNetworkRequestCreated)\n\tcase EventStorageSharedStorageAccessed:\n\t\tv = new(storage.EventSharedStorageAccessed)\n\tcase EventStorageSharedStorageWorkletOperationExecutionFinished:\n\t\tv = new(storage.EventSharedStorageWorkletOperationExecutionFinished)\n\tcase EventStorageStorageBucketCreatedOrUpdated:\n\t\tv = new(storage.EventStorageBucketCreatedOrUpdated)\n\tcase EventStorageStorageBucketDeleted:\n\t\tv = new(storage.EventStorageBucketDeleted)\n\tcase EventStorageAttributionReportingSourceRegistered:\n\t\tv = new(storage.EventAttributionReportingSourceRegistered)\n\tcase EventStorageAttributionReportingTriggerRegistered:\n\t\tv = new(storage.EventAttributionReportingTriggerRegistered)\n\tcase EventStorageAttributionReportingReportSent:\n\t\tv = new(storage.EventAttributionReportingReportSent)\n\tcase EventStorageAttributionReportingVerboseDebugReportSent:\n\t\tv = new(storage.EventAttributionReportingVerboseDebugReportSent)\n\tcase CommandSystemInfoGetInfo:\n\t\tv = new(systeminfo.GetInfoReturns)\n\tcase CommandSystemInfoGetFeatureState:\n\t\tv = new(systeminfo.GetFeatureStateReturns)\n\tcase CommandSystemInfoGetProcessInfo:\n\t\tv = new(systeminfo.GetProcessInfoReturns)\n\tcase CommandTargetActivateTarget:\n\t\treturn emptyVal, nil\n\tcase CommandTargetAttachToTarget:\n\t\tv = new(target.AttachToTargetReturns)\n\tcase CommandTargetAttachToBrowserTarget:\n\t\tv = new(target.AttachToBrowserTargetReturns)\n\tcase CommandTargetCloseTarget:\n\t\treturn emptyVal, nil\n\tcase CommandTargetExposeDevToolsProtocol:\n\t\treturn emptyVal, nil\n\tcase CommandTargetCreateBrowserContext:\n\t\tv = new(target.CreateBrowserContextReturns)\n\tcase CommandTargetGetBrowserContexts:\n\t\tv = new(target.GetBrowserContextsReturns)\n\tcase CommandTargetCreateTarget:\n\t\tv = new(target.CreateTargetReturns)\n\tcase CommandTargetDetachFromTarget:\n\t\treturn emptyVal, nil\n\tcase CommandTargetDisposeBrowserContext:\n\t\treturn emptyVal, nil\n\tcase CommandTargetGetTargetInfo:\n\t\tv = new(target.GetTargetInfoReturns)\n\tcase CommandTargetGetTargets:\n\t\tv = new(target.GetTargetsReturns)\n\tcase CommandTargetSetAutoAttach:\n\t\treturn emptyVal, nil\n\tcase CommandTargetAutoAttachRelated:\n\t\treturn emptyVal, nil\n\tcase CommandTargetSetDiscoverTargets:\n\t\treturn emptyVal, nil\n\tcase CommandTargetSetRemoteLocations:\n\t\treturn emptyVal, nil\n\tcase CommandTargetOpenDevTools:\n\t\tv = new(target.OpenDevToolsReturns)\n\tcase EventTargetAttachedToTarget:\n\t\tv = new(target.EventAttachedToTarget)\n\tcase EventTargetDetachedFromTarget:\n\t\tv = new(target.EventDetachedFromTarget)\n\tcase EventTargetReceivedMessageFromTarget:\n\t\tv = new(target.EventReceivedMessageFromTarget)\n\tcase EventTargetTargetCreated:\n\t\tv = new(target.EventTargetCreated)\n\tcase EventTargetTargetDestroyed:\n\t\tv = new(target.EventTargetDestroyed)\n\tcase EventTargetTargetCrashed:\n\t\tv = new(target.EventTargetCrashed)\n\tcase EventTargetTargetInfoChanged:\n\t\tv = new(target.EventTargetInfoChanged)\n\tcase CommandTetheringBind:\n\t\treturn emptyVal, nil\n\tcase CommandTetheringUnbind:\n\t\treturn emptyVal, nil\n\tcase EventTetheringAccepted:\n\t\tv = new(tethering.EventAccepted)\n\tcase CommandTracingEnd:\n\t\treturn emptyVal, nil\n\tcase CommandTracingGetCategories:\n\t\tv = new(tracing.GetCategoriesReturns)\n\tcase CommandTracingRecordClockSyncMarker:\n\t\treturn emptyVal, nil\n\tcase CommandTracingRequestMemoryDump:\n\t\tv = new(tracing.RequestMemoryDumpReturns)\n\tcase CommandTracingStart:\n\t\treturn emptyVal, nil\n\tcase EventTracingBufferUsage:\n\t\tv = new(tracing.EventBufferUsage)\n\tcase EventTracingDataCollected:\n\t\tv = new(tracing.EventDataCollected)\n\tcase EventTracingTracingComplete:\n\t\tv = new(tracing.EventTracingComplete)\n\tcase CommandWebAudioEnable:\n\t\treturn emptyVal, nil\n\tcase CommandWebAudioDisable:\n\t\treturn emptyVal, nil\n\tcase CommandWebAudioGetRealtimeData:\n\t\tv = new(webaudio.GetRealtimeDataReturns)\n\tcase EventWebAudioContextCreated:\n\t\tv = new(webaudio.EventContextCreated)\n\tcase EventWebAudioContextWillBeDestroyed:\n\t\tv = new(webaudio.EventContextWillBeDestroyed)\n\tcase EventWebAudioContextChanged:\n\t\tv = new(webaudio.EventContextChanged)\n\tcase EventWebAudioAudioListenerCreated:\n\t\tv = new(webaudio.EventAudioListenerCreated)\n\tcase EventWebAudioAudioListenerWillBeDestroyed:\n\t\tv = new(webaudio.EventAudioListenerWillBeDestroyed)\n\tcase EventWebAudioAudioNodeCreated:\n\t\tv = new(webaudio.EventAudioNodeCreated)\n\tcase EventWebAudioAudioNodeWillBeDestroyed:\n\t\tv = new(webaudio.EventAudioNodeWillBeDestroyed)\n\tcase EventWebAudioAudioParamCreated:\n\t\tv = new(webaudio.EventAudioParamCreated)\n\tcase EventWebAudioAudioParamWillBeDestroyed:\n\t\tv = new(webaudio.EventAudioParamWillBeDestroyed)\n\tcase EventWebAudioNodesConnected:\n\t\tv = new(webaudio.EventNodesConnected)\n\tcase EventWebAudioNodesDisconnected:\n\t\tv = new(webaudio.EventNodesDisconnected)\n\tcase EventWebAudioNodeParamConnected:\n\t\tv = new(webaudio.EventNodeParamConnected)\n\tcase EventWebAudioNodeParamDisconnected:\n\t\tv = new(webaudio.EventNodeParamDisconnected)\n\tcase CommandWebAuthnEnable:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnDisable:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnAddVirtualAuthenticator:\n\t\tv = new(webauthn.AddVirtualAuthenticatorReturns)\n\tcase CommandWebAuthnSetResponseOverrideBits:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnRemoveVirtualAuthenticator:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnAddCredential:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnGetCredential:\n\t\tv = new(webauthn.GetCredentialReturns)\n\tcase CommandWebAuthnGetCredentials:\n\t\tv = new(webauthn.GetCredentialsReturns)\n\tcase CommandWebAuthnRemoveCredential:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnClearCredentials:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnSetUserVerified:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnSetAutomaticPresenceSimulation:\n\t\treturn emptyVal, nil\n\tcase CommandWebAuthnSetCredentialProperties:\n\t\treturn emptyVal, nil\n\tcase EventWebAuthnCredentialAdded:\n\t\tv = new(webauthn.EventCredentialAdded)\n\tcase EventWebAuthnCredentialDeleted:\n\t\tv = new(webauthn.EventCredentialDeleted)\n\tcase EventWebAuthnCredentialUpdated:\n\t\tv = new(webauthn.EventCredentialUpdated)\n\tcase EventWebAuthnCredentialAsserted:\n\t\tv = new(webauthn.EventCredentialAsserted)\n\tdefault:\n\t\treturn nil, cdp.ErrUnknownCommandOrEvent(msg.Method)\n\t}\n\n\tvar buf jsontext.Value\n\tswitch {\n\tcase msg.Params != nil:\n\t\tbuf = msg.Params\n\tcase msg.Result != nil:\n\t\tbuf = msg.Result\n\tdefault:\n\t\treturn nil, cdp.ErrMsgMissingParamsOrResult\n\t}\n\tif err := jsonv2.Unmarshal(buf, v, opts...); err != nil {\n\t\treturn nil, err\n\t}\n\treturn v, nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/css/css.go",
    "content": "// Package css provides the Chrome DevTools Protocol\n// commands, types, and events for the CSS domain.\n//\n// This domain exposes CSS read/write operations. All CSS objects\n// (stylesheets, rules, and styles) have an associated id used in subsequent\n// operations on the related object. Each object type has a specific id\n// structure, and those are not interchangeable between objects of different\n// kinds. CSS objects can be loaded using the get*ForNode() calls (which accept\n// a DOM node id). A client can also keep track of stylesheets via the\n// styleSheetAdded/styleSheetRemoved events and subsequently load the required\n// stylesheet contents using the getStyleSheet[Text]() methods.\n//\n// Generated by the cdproto-gen command.\npackage css\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// AddRuleParams inserts a new rule with the given ruleText in a stylesheet\n// with given styleSheetId, at the position specified by location.\ntype AddRuleParams struct {\n\tStyleSheetID                    StyleSheetID `json:\"styleSheetId\"`                                       // The css style sheet identifier where a new rule should be inserted.\n\tRuleText                        string       `json:\"ruleText\"`                                           // The text of a new rule.\n\tLocation                        *SourceRange `json:\"location\"`                                           // Text position of a new rule in the target style sheet.\n\tNodeForPropertySyntaxValidation cdp.NodeID   `json:\"nodeForPropertySyntaxValidation,omitempty,omitzero\"` // NodeId for the DOM node in whose context custom property declarations for registered properties should be validated. If omitted, declarations in the new rule text can only be validated statically, which may produce incorrect results if the declaration contains a var() for example.\n}\n\n// AddRule inserts a new rule with the given ruleText in a stylesheet with\n// given styleSheetId, at the position specified by location.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-addRule\n//\n// parameters:\n//\n//\tstyleSheetID - The css style sheet identifier where a new rule should be inserted.\n//\truleText - The text of a new rule.\n//\tlocation - Text position of a new rule in the target style sheet.\nfunc AddRule(styleSheetID StyleSheetID, ruleText string, location *SourceRange) *AddRuleParams {\n\treturn &AddRuleParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRuleText:     ruleText,\n\t\tLocation:     location,\n\t}\n}\n\n// WithNodeForPropertySyntaxValidation nodeId for the DOM node in whose\n// context custom property declarations for registered properties should be\n// validated. If omitted, declarations in the new rule text can only be\n// validated statically, which may produce incorrect results if the declaration\n// contains a var() for example.\nfunc (p AddRuleParams) WithNodeForPropertySyntaxValidation(nodeForPropertySyntaxValidation cdp.NodeID) *AddRuleParams {\n\tp.NodeForPropertySyntaxValidation = nodeForPropertySyntaxValidation\n\treturn &p\n}\n\n// AddRuleReturns return values.\ntype AddRuleReturns struct {\n\tRule *Rule `json:\"rule,omitempty,omitzero\"` // The newly created rule.\n}\n\n// Do executes CSS.addRule against the provided context.\n//\n// returns:\n//\n//\trule - The newly created rule.\nfunc (p *AddRuleParams) Do(ctx context.Context) (rule *Rule, err error) {\n\t// execute\n\tvar res AddRuleReturns\n\terr = cdp.Execute(ctx, CommandAddRule, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Rule, nil\n}\n\n// CollectClassNamesParams returns all class names from specified stylesheet.\ntype CollectClassNamesParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n}\n\n// CollectClassNames returns all class names from specified stylesheet.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-collectClassNames\n//\n// parameters:\n//\n//\tstyleSheetID\nfunc CollectClassNames(styleSheetID StyleSheetID) *CollectClassNamesParams {\n\treturn &CollectClassNamesParams{\n\t\tStyleSheetID: styleSheetID,\n\t}\n}\n\n// CollectClassNamesReturns return values.\ntype CollectClassNamesReturns struct {\n\tClassNames []string `json:\"classNames,omitempty,omitzero\"` // Class name list.\n}\n\n// Do executes CSS.collectClassNames against the provided context.\n//\n// returns:\n//\n//\tclassNames - Class name list.\nfunc (p *CollectClassNamesParams) Do(ctx context.Context) (classNames []string, err error) {\n\t// execute\n\tvar res CollectClassNamesReturns\n\terr = cdp.Execute(ctx, CommandCollectClassNames, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.ClassNames, nil\n}\n\n// CreateStyleSheetParams creates a new special \"via-inspector\" stylesheet in\n// the frame with given frameId.\ntype CreateStyleSheetParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"` // Identifier of the frame where \"via-inspector\" stylesheet should be created.\n\tForce   bool        `json:\"force\"`   // If true, creates a new stylesheet for every call. If false, returns a stylesheet previously created by a call with force=false for the frame's document if it exists or creates a new stylesheet (default: false).\n}\n\n// CreateStyleSheet creates a new special \"via-inspector\" stylesheet in the\n// frame with given frameId.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-createStyleSheet\n//\n// parameters:\n//\n//\tframeID - Identifier of the frame where \"via-inspector\" stylesheet should be created.\nfunc CreateStyleSheet(frameID cdp.FrameID) *CreateStyleSheetParams {\n\treturn &CreateStyleSheetParams{\n\t\tFrameID: frameID,\n\t\tForce:   false,\n\t}\n}\n\n// WithForce if true, creates a new stylesheet for every call. If false,\n// returns a stylesheet previously created by a call with force=false for the\n// frame's document if it exists or creates a new stylesheet (default: false).\nfunc (p CreateStyleSheetParams) WithForce(force bool) *CreateStyleSheetParams {\n\tp.Force = force\n\treturn &p\n}\n\n// CreateStyleSheetReturns return values.\ntype CreateStyleSheetReturns struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId,omitempty,omitzero\"` // Identifier of the created \"via-inspector\" stylesheet.\n}\n\n// Do executes CSS.createStyleSheet against the provided context.\n//\n// returns:\n//\n//\tstyleSheetID - Identifier of the created \"via-inspector\" stylesheet.\nfunc (p *CreateStyleSheetParams) Do(ctx context.Context) (styleSheetID StyleSheetID, err error) {\n\t// execute\n\tvar res CreateStyleSheetReturns\n\terr = cdp.Execute(ctx, CommandCreateStyleSheet, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.StyleSheetID, nil\n}\n\n// DisableParams disables the CSS agent for the given page.\ntype DisableParams struct{}\n\n// Disable disables the CSS agent for the given page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes CSS.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables the CSS agent for the given page. Clients should not\n// assume that the CSS agent has been enabled until the result of this command\n// is received.\ntype EnableParams struct{}\n\n// Enable enables the CSS agent for the given page. Clients should not assume\n// that the CSS agent has been enabled until the result of this command is\n// received.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes CSS.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// ForcePseudoStateParams ensures that the given node will have specified\n// pseudo-classes whenever its style is computed by the browser.\ntype ForcePseudoStateParams struct {\n\tNodeID              cdp.NodeID `json:\"nodeId\"`              // The element id for which to force the pseudo state.\n\tForcedPseudoClasses []string   `json:\"forcedPseudoClasses\"` // Element pseudo classes to force when computing the element's style.\n}\n\n// ForcePseudoState ensures that the given node will have specified\n// pseudo-classes whenever its style is computed by the browser.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-forcePseudoState\n//\n// parameters:\n//\n//\tnodeID - The element id for which to force the pseudo state.\n//\tforcedPseudoClasses - Element pseudo classes to force when computing the element's style.\nfunc ForcePseudoState(nodeID cdp.NodeID, forcedPseudoClasses []string) *ForcePseudoStateParams {\n\treturn &ForcePseudoStateParams{\n\t\tNodeID:              nodeID,\n\t\tForcedPseudoClasses: forcedPseudoClasses,\n\t}\n}\n\n// Do executes CSS.forcePseudoState against the provided context.\nfunc (p *ForcePseudoStateParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandForcePseudoState, p, nil)\n}\n\n// ForceStartingStyleParams ensures that the given node is in its\n// starting-style state.\ntype ForceStartingStyleParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // The element id for which to force the starting-style state.\n\tForced bool       `json:\"forced\"` // Boolean indicating if this is on or off.\n}\n\n// ForceStartingStyle ensures that the given node is in its starting-style\n// state.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-forceStartingStyle\n//\n// parameters:\n//\n//\tnodeID - The element id for which to force the starting-style state.\n//\tforced - Boolean indicating if this is on or off.\nfunc ForceStartingStyle(nodeID cdp.NodeID, forced bool) *ForceStartingStyleParams {\n\treturn &ForceStartingStyleParams{\n\t\tNodeID: nodeID,\n\t\tForced: forced,\n\t}\n}\n\n// Do executes CSS.forceStartingStyle against the provided context.\nfunc (p *ForceStartingStyleParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandForceStartingStyle, p, nil)\n}\n\n// GetBackgroundColorsParams [no description].\ntype GetBackgroundColorsParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to get background colors for.\n}\n\n// GetBackgroundColors [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getBackgroundColors\n//\n// parameters:\n//\n//\tnodeID - Id of the node to get background colors for.\nfunc GetBackgroundColors(nodeID cdp.NodeID) *GetBackgroundColorsParams {\n\treturn &GetBackgroundColorsParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetBackgroundColorsReturns return values.\ntype GetBackgroundColorsReturns struct {\n\tBackgroundColors   []string `json:\"backgroundColors,omitempty,omitzero\"`   // The range of background colors behind this element, if it contains any visible text. If no visible text is present, this will be undefined. In the case of a flat background color, this will consist of simply that color. In the case of a gradient, this will consist of each of the color stops. For anything more complicated, this will be an empty array. Images will be ignored (as if the image had failed to load).\n\tComputedFontSize   string   `json:\"computedFontSize,omitempty,omitzero\"`   // The computed font size for this node, as a CSS computed value string (e.g. '12px').\n\tComputedFontWeight string   `json:\"computedFontWeight,omitempty,omitzero\"` // The computed font weight for this node, as a CSS computed value string (e.g. 'normal' or '100').\n}\n\n// Do executes CSS.getBackgroundColors against the provided context.\n//\n// returns:\n//\n//\tbackgroundColors - The range of background colors behind this element, if it contains any visible text. If no visible text is present, this will be undefined. In the case of a flat background color, this will consist of simply that color. In the case of a gradient, this will consist of each of the color stops. For anything more complicated, this will be an empty array. Images will be ignored (as if the image had failed to load).\n//\tcomputedFontSize - The computed font size for this node, as a CSS computed value string (e.g. '12px').\n//\tcomputedFontWeight - The computed font weight for this node, as a CSS computed value string (e.g. 'normal' or '100').\nfunc (p *GetBackgroundColorsParams) Do(ctx context.Context) (backgroundColors []string, computedFontSize string, computedFontWeight string, err error) {\n\t// execute\n\tvar res GetBackgroundColorsReturns\n\terr = cdp.Execute(ctx, CommandGetBackgroundColors, p, &res)\n\tif err != nil {\n\t\treturn nil, \"\", \"\", err\n\t}\n\n\treturn res.BackgroundColors, res.ComputedFontSize, res.ComputedFontWeight, nil\n}\n\n// GetComputedStyleForNodeParams returns the computed style for a DOM node\n// identified by nodeId.\ntype GetComputedStyleForNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`\n}\n\n// GetComputedStyleForNode returns the computed style for a DOM node\n// identified by nodeId.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getComputedStyleForNode\n//\n// parameters:\n//\n//\tnodeID\nfunc GetComputedStyleForNode(nodeID cdp.NodeID) *GetComputedStyleForNodeParams {\n\treturn &GetComputedStyleForNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetComputedStyleForNodeReturns return values.\ntype GetComputedStyleForNodeReturns struct {\n\tComputedStyle []*ComputedStyleProperty `json:\"computedStyle,omitempty,omitzero\"` // Computed style for the specified DOM node.\n}\n\n// Do executes CSS.getComputedStyleForNode against the provided context.\n//\n// returns:\n//\n//\tcomputedStyle - Computed style for the specified DOM node.\nfunc (p *GetComputedStyleForNodeParams) Do(ctx context.Context) (computedStyle []*ComputedStyleProperty, err error) {\n\t// execute\n\tvar res GetComputedStyleForNodeReturns\n\terr = cdp.Execute(ctx, CommandGetComputedStyleForNode, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.ComputedStyle, nil\n}\n\n// ResolveValuesParams resolve the specified values in the context of the\n// provided element. For example, a value of '1em' is evaluated according to the\n// computed 'font-size' of the element and a value 'calc(1px + 2px)' will be\n// resolved to '3px'. If the propertyName was specified the values are resolved\n// as if they were property's declaration. If a value cannot be parsed according\n// to the provided property syntax, the value is parsed using combined syntax as\n// if null propertyName was provided. If the value cannot be resolved even then,\n// return the provided value without any changes.\ntype ResolveValuesParams struct {\n\tValues           []string       `json:\"values\"`                              // Substitution functions (var()/env()/attr()) and cascade-dependent keywords (revert/revert-layer) do not work.\n\tNodeID           cdp.NodeID     `json:\"nodeId\"`                              // Id of the node in whose context the expression is evaluated\n\tPropertyName     string         `json:\"propertyName,omitempty,omitzero\"`     // Only longhands and custom property names are accepted.\n\tPseudoType       cdp.PseudoType `json:\"pseudoType,omitempty,omitzero\"`       // Pseudo element type, only works for pseudo elements that generate elements in the tree, such as ::before and ::after.\n\tPseudoIdentifier string         `json:\"pseudoIdentifier,omitempty,omitzero\"` // Pseudo element custom ident.\n}\n\n// ResolveValues resolve the specified values in the context of the provided\n// element. For example, a value of '1em' is evaluated according to the computed\n// 'font-size' of the element and a value 'calc(1px + 2px)' will be resolved to\n// '3px'. If the propertyName was specified the values are resolved as if they\n// were property's declaration. If a value cannot be parsed according to the\n// provided property syntax, the value is parsed using combined syntax as if\n// null propertyName was provided. If the value cannot be resolved even then,\n// return the provided value without any changes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-resolveValues\n//\n// parameters:\n//\n//\tvalues - Substitution functions (var()/env()/attr()) and cascade-dependent keywords (revert/revert-layer) do not work.\n//\tnodeID - Id of the node in whose context the expression is evaluated\nfunc ResolveValues(values []string, nodeID cdp.NodeID) *ResolveValuesParams {\n\treturn &ResolveValuesParams{\n\t\tValues: values,\n\t\tNodeID: nodeID,\n\t}\n}\n\n// WithPropertyName only longhands and custom property names are accepted.\nfunc (p ResolveValuesParams) WithPropertyName(propertyName string) *ResolveValuesParams {\n\tp.PropertyName = propertyName\n\treturn &p\n}\n\n// WithPseudoType pseudo element type, only works for pseudo elements that\n// generate elements in the tree, such as ::before and ::after.\nfunc (p ResolveValuesParams) WithPseudoType(pseudoType cdp.PseudoType) *ResolveValuesParams {\n\tp.PseudoType = pseudoType\n\treturn &p\n}\n\n// WithPseudoIdentifier pseudo element custom ident.\nfunc (p ResolveValuesParams) WithPseudoIdentifier(pseudoIdentifier string) *ResolveValuesParams {\n\tp.PseudoIdentifier = pseudoIdentifier\n\treturn &p\n}\n\n// ResolveValuesReturns return values.\ntype ResolveValuesReturns struct {\n\tResults []string `json:\"results,omitempty,omitzero\"`\n}\n\n// Do executes CSS.resolveValues against the provided context.\n//\n// returns:\n//\n//\tresults\nfunc (p *ResolveValuesParams) Do(ctx context.Context) (results []string, err error) {\n\t// execute\n\tvar res ResolveValuesReturns\n\terr = cdp.Execute(ctx, CommandResolveValues, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Results, nil\n}\n\n// GetLonghandPropertiesParams [no description].\ntype GetLonghandPropertiesParams struct {\n\tShorthandName string `json:\"shorthandName\"`\n\tValue         string `json:\"value\"`\n}\n\n// GetLonghandProperties [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getLonghandProperties\n//\n// parameters:\n//\n//\tshorthandName\n//\tvalue\nfunc GetLonghandProperties(shorthandName string, value string) *GetLonghandPropertiesParams {\n\treturn &GetLonghandPropertiesParams{\n\t\tShorthandName: shorthandName,\n\t\tValue:         value,\n\t}\n}\n\n// GetLonghandPropertiesReturns return values.\ntype GetLonghandPropertiesReturns struct {\n\tLonghandProperties []*Property `json:\"longhandProperties,omitempty,omitzero\"`\n}\n\n// Do executes CSS.getLonghandProperties against the provided context.\n//\n// returns:\n//\n//\tlonghandProperties\nfunc (p *GetLonghandPropertiesParams) Do(ctx context.Context) (longhandProperties []*Property, err error) {\n\t// execute\n\tvar res GetLonghandPropertiesReturns\n\terr = cdp.Execute(ctx, CommandGetLonghandProperties, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.LonghandProperties, nil\n}\n\n// GetInlineStylesForNodeParams returns the styles defined inline (explicitly\n// in the \"style\" attribute and implicitly, using DOM attributes) for a DOM node\n// identified by nodeId.\ntype GetInlineStylesForNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`\n}\n\n// GetInlineStylesForNode returns the styles defined inline (explicitly in\n// the \"style\" attribute and implicitly, using DOM attributes) for a DOM node\n// identified by nodeId.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getInlineStylesForNode\n//\n// parameters:\n//\n//\tnodeID\nfunc GetInlineStylesForNode(nodeID cdp.NodeID) *GetInlineStylesForNodeParams {\n\treturn &GetInlineStylesForNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetInlineStylesForNodeReturns return values.\ntype GetInlineStylesForNodeReturns struct {\n\tInlineStyle     *Style `json:\"inlineStyle,omitempty,omitzero\"`     // Inline style for the specified DOM node.\n\tAttributesStyle *Style `json:\"attributesStyle,omitempty,omitzero\"` // Attribute-defined element style (e.g. resulting from \"width=20 height=100%\").\n}\n\n// Do executes CSS.getInlineStylesForNode against the provided context.\n//\n// returns:\n//\n//\tinlineStyle - Inline style for the specified DOM node.\n//\tattributesStyle - Attribute-defined element style (e.g. resulting from \"width=20 height=100%\").\nfunc (p *GetInlineStylesForNodeParams) Do(ctx context.Context) (inlineStyle *Style, attributesStyle *Style, err error) {\n\t// execute\n\tvar res GetInlineStylesForNodeReturns\n\terr = cdp.Execute(ctx, CommandGetInlineStylesForNode, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.InlineStyle, res.AttributesStyle, nil\n}\n\n// GetAnimatedStylesForNodeParams returns the styles coming from animations &\n// transitions including the animation & transition styles coming from\n// inheritance chain.\ntype GetAnimatedStylesForNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`\n}\n\n// GetAnimatedStylesForNode returns the styles coming from animations &\n// transitions including the animation & transition styles coming from\n// inheritance chain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getAnimatedStylesForNode\n//\n// parameters:\n//\n//\tnodeID\nfunc GetAnimatedStylesForNode(nodeID cdp.NodeID) *GetAnimatedStylesForNodeParams {\n\treturn &GetAnimatedStylesForNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetAnimatedStylesForNodeReturns return values.\ntype GetAnimatedStylesForNodeReturns struct {\n\tAnimationStyles  []*AnimationStyle              `json:\"animationStyles,omitempty,omitzero\"`  // Styles coming from animations.\n\tTransitionsStyle *Style                         `json:\"transitionsStyle,omitempty,omitzero\"` // Style coming from transitions.\n\tInherited        []*InheritedAnimatedStyleEntry `json:\"inherited,omitempty,omitzero\"`        // Inherited style entries for animationsStyle and transitionsStyle from the inheritance chain of the element.\n}\n\n// Do executes CSS.getAnimatedStylesForNode against the provided context.\n//\n// returns:\n//\n//\tanimationStyles - Styles coming from animations.\n//\ttransitionsStyle - Style coming from transitions.\n//\tinherited - Inherited style entries for animationsStyle and transitionsStyle from the inheritance chain of the element.\nfunc (p *GetAnimatedStylesForNodeParams) Do(ctx context.Context) (animationStyles []*AnimationStyle, transitionsStyle *Style, inherited []*InheritedAnimatedStyleEntry, err error) {\n\t// execute\n\tvar res GetAnimatedStylesForNodeReturns\n\terr = cdp.Execute(ctx, CommandGetAnimatedStylesForNode, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, nil, err\n\t}\n\n\treturn res.AnimationStyles, res.TransitionsStyle, res.Inherited, nil\n}\n\n// GetMatchedStylesForNodeParams returns requested styles for a DOM node\n// identified by nodeId.\ntype GetMatchedStylesForNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`\n}\n\n// GetMatchedStylesForNode returns requested styles for a DOM node identified\n// by nodeId.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getMatchedStylesForNode\n//\n// parameters:\n//\n//\tnodeID\nfunc GetMatchedStylesForNode(nodeID cdp.NodeID) *GetMatchedStylesForNodeParams {\n\treturn &GetMatchedStylesForNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetMatchedStylesForNodeReturns return values.\ntype GetMatchedStylesForNodeReturns struct {\n\tInlineStyle                 *Style                           `json:\"inlineStyle,omitempty,omitzero\"`                 // Inline style for the specified DOM node.\n\tAttributesStyle             *Style                           `json:\"attributesStyle,omitempty,omitzero\"`             // Attribute-defined element style (e.g. resulting from \"width=20 height=100%\").\n\tMatchedCSSRules             []*RuleMatch                     `json:\"matchedCSSRules,omitempty,omitzero\"`             // CSS rules matching this node, from all applicable stylesheets.\n\tPseudoElements              []*PseudoElementMatches          `json:\"pseudoElements,omitempty,omitzero\"`              // Pseudo style matches for this node.\n\tInherited                   []*InheritedStyleEntry           `json:\"inherited,omitempty,omitzero\"`                   // A chain of inherited styles (from the immediate node parent up to the DOM tree root).\n\tInheritedPseudoElements     []*InheritedPseudoElementMatches `json:\"inheritedPseudoElements,omitempty,omitzero\"`     // A chain of inherited pseudo element styles (from the immediate node parent up to the DOM tree root).\n\tCSSKeyframesRules           []*KeyframesRule                 `json:\"cssKeyframesRules,omitempty,omitzero\"`           // A list of CSS keyframed animations matching this node.\n\tCSSPositionTryRules         []*PositionTryRule               `json:\"cssPositionTryRules,omitempty,omitzero\"`         // A list of CSS @position-try rules matching this node, based on the position-try-fallbacks property.\n\tActivePositionFallbackIndex int64                            `json:\"activePositionFallbackIndex,omitempty,omitzero\"` // Index of the active fallback in the applied position-try-fallback property, will not be set if there is no active position-try fallback.\n\tCSSPropertyRules            []*PropertyRule                  `json:\"cssPropertyRules,omitempty,omitzero\"`            // A list of CSS at-property rules matching this node.\n\tCSSPropertyRegistrations    []*PropertyRegistration          `json:\"cssPropertyRegistrations,omitempty,omitzero\"`    // A list of CSS property registrations matching this node.\n\tCSSFontPaletteValuesRule    *FontPaletteValuesRule           `json:\"cssFontPaletteValuesRule,omitempty,omitzero\"`    // A font-palette-values rule matching this node.\n\tParentLayoutNodeID          cdp.NodeID                       `json:\"parentLayoutNodeId,omitempty,omitzero\"`          // Id of the first parent element that does not have display: contents.\n\tCSSFunctionRules            []*FunctionRule                  `json:\"cssFunctionRules,omitempty,omitzero\"`            // A list of CSS at-function rules referenced by styles of this node.\n}\n\n// Do executes CSS.getMatchedStylesForNode against the provided context.\n//\n// returns:\n//\n//\tinlineStyle - Inline style for the specified DOM node.\n//\tattributesStyle - Attribute-defined element style (e.g. resulting from \"width=20 height=100%\").\n//\tmatchedCSSRules - CSS rules matching this node, from all applicable stylesheets.\n//\tpseudoElements - Pseudo style matches for this node.\n//\tinherited - A chain of inherited styles (from the immediate node parent up to the DOM tree root).\n//\tinheritedPseudoElements - A chain of inherited pseudo element styles (from the immediate node parent up to the DOM tree root).\n//\tcssKeyframesRules - A list of CSS keyframed animations matching this node.\n//\tcssPositionTryRules - A list of CSS @position-try rules matching this node, based on the position-try-fallbacks property.\n//\tactivePositionFallbackIndex - Index of the active fallback in the applied position-try-fallback property, will not be set if there is no active position-try fallback.\n//\tcssPropertyRules - A list of CSS at-property rules matching this node.\n//\tcssPropertyRegistrations - A list of CSS property registrations matching this node.\n//\tcssFontPaletteValuesRule - A font-palette-values rule matching this node.\n//\tparentLayoutNodeID - Id of the first parent element that does not have display: contents.\n//\tcssFunctionRules - A list of CSS at-function rules referenced by styles of this node.\nfunc (p *GetMatchedStylesForNodeParams) Do(ctx context.Context) (inlineStyle *Style, attributesStyle *Style, matchedCSSRules []*RuleMatch, pseudoElements []*PseudoElementMatches, inherited []*InheritedStyleEntry, inheritedPseudoElements []*InheritedPseudoElementMatches, cssKeyframesRules []*KeyframesRule, cssPositionTryRules []*PositionTryRule, activePositionFallbackIndex int64, cssPropertyRules []*PropertyRule, cssPropertyRegistrations []*PropertyRegistration, cssFontPaletteValuesRule *FontPaletteValuesRule, parentLayoutNodeID cdp.NodeID, cssFunctionRules []*FunctionRule, err error) {\n\t// execute\n\tvar res GetMatchedStylesForNodeReturns\n\terr = cdp.Execute(ctx, CommandGetMatchedStylesForNode, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, nil, nil, nil, nil, nil, nil, 0, nil, nil, nil, 0, nil, err\n\t}\n\n\treturn res.InlineStyle, res.AttributesStyle, res.MatchedCSSRules, res.PseudoElements, res.Inherited, res.InheritedPseudoElements, res.CSSKeyframesRules, res.CSSPositionTryRules, res.ActivePositionFallbackIndex, res.CSSPropertyRules, res.CSSPropertyRegistrations, res.CSSFontPaletteValuesRule, res.ParentLayoutNodeID, res.CSSFunctionRules, nil\n}\n\n// GetEnvironmentVariablesParams returns the values of the default UA-defined\n// environment variables used in env().\ntype GetEnvironmentVariablesParams struct{}\n\n// GetEnvironmentVariables returns the values of the default UA-defined\n// environment variables used in env().\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getEnvironmentVariables\nfunc GetEnvironmentVariables() *GetEnvironmentVariablesParams {\n\treturn &GetEnvironmentVariablesParams{}\n}\n\n// GetEnvironmentVariablesReturns return values.\ntype GetEnvironmentVariablesReturns struct {\n\tEnvironmentVariables jsontext.Value `json:\"environmentVariables,omitempty,omitzero\"`\n}\n\n// Do executes CSS.getEnvironmentVariables against the provided context.\n//\n// returns:\n//\n//\tenvironmentVariables\nfunc (p *GetEnvironmentVariablesParams) Do(ctx context.Context) (environmentVariables jsontext.Value, err error) {\n\t// execute\n\tvar res GetEnvironmentVariablesReturns\n\terr = cdp.Execute(ctx, CommandGetEnvironmentVariables, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.EnvironmentVariables, nil\n}\n\n// GetMediaQueriesParams returns all media queries parsed by the rendering\n// engine.\ntype GetMediaQueriesParams struct{}\n\n// GetMediaQueries returns all media queries parsed by the rendering engine.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getMediaQueries\nfunc GetMediaQueries() *GetMediaQueriesParams {\n\treturn &GetMediaQueriesParams{}\n}\n\n// GetMediaQueriesReturns return values.\ntype GetMediaQueriesReturns struct {\n\tMedias []*Media `json:\"medias,omitempty,omitzero\"`\n}\n\n// Do executes CSS.getMediaQueries against the provided context.\n//\n// returns:\n//\n//\tmedias\nfunc (p *GetMediaQueriesParams) Do(ctx context.Context) (medias []*Media, err error) {\n\t// execute\n\tvar res GetMediaQueriesReturns\n\terr = cdp.Execute(ctx, CommandGetMediaQueries, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Medias, nil\n}\n\n// GetPlatformFontsForNodeParams requests information about platform fonts\n// which we used to render child TextNodes in the given node.\ntype GetPlatformFontsForNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`\n}\n\n// GetPlatformFontsForNode requests information about platform fonts which we\n// used to render child TextNodes in the given node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getPlatformFontsForNode\n//\n// parameters:\n//\n//\tnodeID\nfunc GetPlatformFontsForNode(nodeID cdp.NodeID) *GetPlatformFontsForNodeParams {\n\treturn &GetPlatformFontsForNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetPlatformFontsForNodeReturns return values.\ntype GetPlatformFontsForNodeReturns struct {\n\tFonts []*PlatformFontUsage `json:\"fonts,omitempty,omitzero\"` // Usage statistics for every employed platform font.\n}\n\n// Do executes CSS.getPlatformFontsForNode against the provided context.\n//\n// returns:\n//\n//\tfonts - Usage statistics for every employed platform font.\nfunc (p *GetPlatformFontsForNodeParams) Do(ctx context.Context) (fonts []*PlatformFontUsage, err error) {\n\t// execute\n\tvar res GetPlatformFontsForNodeReturns\n\terr = cdp.Execute(ctx, CommandGetPlatformFontsForNode, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Fonts, nil\n}\n\n// GetStyleSheetTextParams returns the current textual content for a\n// stylesheet.\ntype GetStyleSheetTextParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n}\n\n// GetStyleSheetText returns the current textual content for a stylesheet.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getStyleSheetText\n//\n// parameters:\n//\n//\tstyleSheetID\nfunc GetStyleSheetText(styleSheetID StyleSheetID) *GetStyleSheetTextParams {\n\treturn &GetStyleSheetTextParams{\n\t\tStyleSheetID: styleSheetID,\n\t}\n}\n\n// GetStyleSheetTextReturns return values.\ntype GetStyleSheetTextReturns struct {\n\tText string `json:\"text,omitempty,omitzero\"` // The stylesheet text.\n}\n\n// Do executes CSS.getStyleSheetText against the provided context.\n//\n// returns:\n//\n//\ttext - The stylesheet text.\nfunc (p *GetStyleSheetTextParams) Do(ctx context.Context) (text string, err error) {\n\t// execute\n\tvar res GetStyleSheetTextReturns\n\terr = cdp.Execute(ctx, CommandGetStyleSheetText, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.Text, nil\n}\n\n// GetLayersForNodeParams returns all layers parsed by the rendering engine\n// for the tree scope of a node. Given a DOM element identified by nodeId,\n// getLayersForNode returns the root layer for the nearest ancestor document or\n// shadow root. The layer root contains the full layer tree for the tree scope\n// and their ordering.\ntype GetLayersForNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`\n}\n\n// GetLayersForNode returns all layers parsed by the rendering engine for the\n// tree scope of a node. Given a DOM element identified by nodeId,\n// getLayersForNode returns the root layer for the nearest ancestor document or\n// shadow root. The layer root contains the full layer tree for the tree scope\n// and their ordering.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getLayersForNode\n//\n// parameters:\n//\n//\tnodeID\nfunc GetLayersForNode(nodeID cdp.NodeID) *GetLayersForNodeParams {\n\treturn &GetLayersForNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetLayersForNodeReturns return values.\ntype GetLayersForNodeReturns struct {\n\tRootLayer *LayerData `json:\"rootLayer,omitempty,omitzero\"`\n}\n\n// Do executes CSS.getLayersForNode against the provided context.\n//\n// returns:\n//\n//\trootLayer\nfunc (p *GetLayersForNodeParams) Do(ctx context.Context) (rootLayer *LayerData, err error) {\n\t// execute\n\tvar res GetLayersForNodeReturns\n\terr = cdp.Execute(ctx, CommandGetLayersForNode, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.RootLayer, nil\n}\n\n// GetLocationForSelectorParams given a CSS selector text and a style sheet\n// ID, getLocationForSelector returns an array of locations of the CSS selector\n// in the style sheet.\ntype GetLocationForSelectorParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tSelectorText string       `json:\"selectorText\"`\n}\n\n// GetLocationForSelector given a CSS selector text and a style sheet ID,\n// getLocationForSelector returns an array of locations of the CSS selector in\n// the style sheet.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-getLocationForSelector\n//\n// parameters:\n//\n//\tstyleSheetID\n//\tselectorText\nfunc GetLocationForSelector(styleSheetID StyleSheetID, selectorText string) *GetLocationForSelectorParams {\n\treturn &GetLocationForSelectorParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tSelectorText: selectorText,\n\t}\n}\n\n// GetLocationForSelectorReturns return values.\ntype GetLocationForSelectorReturns struct {\n\tRanges []*SourceRange `json:\"ranges,omitempty,omitzero\"`\n}\n\n// Do executes CSS.getLocationForSelector against the provided context.\n//\n// returns:\n//\n//\tranges\nfunc (p *GetLocationForSelectorParams) Do(ctx context.Context) (ranges []*SourceRange, err error) {\n\t// execute\n\tvar res GetLocationForSelectorReturns\n\terr = cdp.Execute(ctx, CommandGetLocationForSelector, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Ranges, nil\n}\n\n// TrackComputedStyleUpdatesForNodeParams starts tracking the given node for\n// the computed style updates and whenever the computed style is updated for\n// node, it queues a computedStyleUpdated event with throttling. There can only\n// be 1 node tracked for computed style updates so passing a new node id removes\n// tracking from the previous node. Pass undefined to disable tracking.\ntype TrackComputedStyleUpdatesForNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"`\n}\n\n// TrackComputedStyleUpdatesForNode starts tracking the given node for the\n// computed style updates and whenever the computed style is updated for node,\n// it queues a computedStyleUpdated event with throttling. There can only be 1\n// node tracked for computed style updates so passing a new node id removes\n// tracking from the previous node. Pass undefined to disable tracking.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-trackComputedStyleUpdatesForNode\n//\n// parameters:\nfunc TrackComputedStyleUpdatesForNode() *TrackComputedStyleUpdatesForNodeParams {\n\treturn &TrackComputedStyleUpdatesForNodeParams{}\n}\n\n// WithNodeID [no description].\nfunc (p TrackComputedStyleUpdatesForNodeParams) WithNodeID(nodeID cdp.NodeID) *TrackComputedStyleUpdatesForNodeParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// Do executes CSS.trackComputedStyleUpdatesForNode against the provided context.\nfunc (p *TrackComputedStyleUpdatesForNodeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTrackComputedStyleUpdatesForNode, p, nil)\n}\n\n// TrackComputedStyleUpdatesParams starts tracking the given computed styles\n// for updates. The specified array of properties replaces the one previously\n// specified. Pass empty array to disable tracking. Use takeComputedStyleUpdates\n// to retrieve the list of nodes that had properties modified. The changes to\n// computed style properties are only tracked for nodes pushed to the front-end\n// by the DOM agent. If no changes to the tracked properties occur after the\n// node has been pushed to the front-end, no updates will be issued for the\n// node.\ntype TrackComputedStyleUpdatesParams struct {\n\tPropertiesToTrack []*ComputedStyleProperty `json:\"propertiesToTrack\"`\n}\n\n// TrackComputedStyleUpdates starts tracking the given computed styles for\n// updates. The specified array of properties replaces the one previously\n// specified. Pass empty array to disable tracking. Use takeComputedStyleUpdates\n// to retrieve the list of nodes that had properties modified. The changes to\n// computed style properties are only tracked for nodes pushed to the front-end\n// by the DOM agent. If no changes to the tracked properties occur after the\n// node has been pushed to the front-end, no updates will be issued for the\n// node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-trackComputedStyleUpdates\n//\n// parameters:\n//\n//\tpropertiesToTrack\nfunc TrackComputedStyleUpdates(propertiesToTrack []*ComputedStyleProperty) *TrackComputedStyleUpdatesParams {\n\treturn &TrackComputedStyleUpdatesParams{\n\t\tPropertiesToTrack: propertiesToTrack,\n\t}\n}\n\n// Do executes CSS.trackComputedStyleUpdates against the provided context.\nfunc (p *TrackComputedStyleUpdatesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTrackComputedStyleUpdates, p, nil)\n}\n\n// TakeComputedStyleUpdatesParams polls the next batch of computed style\n// updates.\ntype TakeComputedStyleUpdatesParams struct{}\n\n// TakeComputedStyleUpdates polls the next batch of computed style updates.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-takeComputedStyleUpdates\nfunc TakeComputedStyleUpdates() *TakeComputedStyleUpdatesParams {\n\treturn &TakeComputedStyleUpdatesParams{}\n}\n\n// TakeComputedStyleUpdatesReturns return values.\ntype TakeComputedStyleUpdatesReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // The list of node Ids that have their tracked computed styles updated.\n}\n\n// Do executes CSS.takeComputedStyleUpdates against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - The list of node Ids that have their tracked computed styles updated.\nfunc (p *TakeComputedStyleUpdatesParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res TakeComputedStyleUpdatesReturns\n\terr = cdp.Execute(ctx, CommandTakeComputedStyleUpdates, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// SetEffectivePropertyValueForNodeParams find a rule with the given active\n// property for the given node and set the new value for this property.\ntype SetEffectivePropertyValueForNodeParams struct {\n\tNodeID       cdp.NodeID `json:\"nodeId\"` // The element id for which to set property.\n\tPropertyName string     `json:\"propertyName\"`\n\tValue        string     `json:\"value\"`\n}\n\n// SetEffectivePropertyValueForNode find a rule with the given active\n// property for the given node and set the new value for this property.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setEffectivePropertyValueForNode\n//\n// parameters:\n//\n//\tnodeID - The element id for which to set property.\n//\tpropertyName\n//\tvalue\nfunc SetEffectivePropertyValueForNode(nodeID cdp.NodeID, propertyName string, value string) *SetEffectivePropertyValueForNodeParams {\n\treturn &SetEffectivePropertyValueForNodeParams{\n\t\tNodeID:       nodeID,\n\t\tPropertyName: propertyName,\n\t\tValue:        value,\n\t}\n}\n\n// Do executes CSS.setEffectivePropertyValueForNode against the provided context.\nfunc (p *SetEffectivePropertyValueForNodeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetEffectivePropertyValueForNode, p, nil)\n}\n\n// SetPropertyRulePropertyNameParams modifies the property rule property\n// name.\ntype SetPropertyRulePropertyNameParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tRange        *SourceRange `json:\"range\"`\n\tPropertyName string       `json:\"propertyName\"`\n}\n\n// SetPropertyRulePropertyName modifies the property rule property name.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setPropertyRulePropertyName\n//\n// parameters:\n//\n//\tstyleSheetID\n//\trange\n//\tpropertyName\nfunc SetPropertyRulePropertyName(styleSheetID StyleSheetID, rangeVal *SourceRange, propertyName string) *SetPropertyRulePropertyNameParams {\n\treturn &SetPropertyRulePropertyNameParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRange:        rangeVal,\n\t\tPropertyName: propertyName,\n\t}\n}\n\n// SetPropertyRulePropertyNameReturns return values.\ntype SetPropertyRulePropertyNameReturns struct {\n\tPropertyName *Value `json:\"propertyName,omitempty,omitzero\"` // The resulting key text after modification.\n}\n\n// Do executes CSS.setPropertyRulePropertyName against the provided context.\n//\n// returns:\n//\n//\tpropertyName - The resulting key text after modification.\nfunc (p *SetPropertyRulePropertyNameParams) Do(ctx context.Context) (propertyName *Value, err error) {\n\t// execute\n\tvar res SetPropertyRulePropertyNameReturns\n\terr = cdp.Execute(ctx, CommandSetPropertyRulePropertyName, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.PropertyName, nil\n}\n\n// SetKeyframeKeyParams modifies the keyframe rule key text.\ntype SetKeyframeKeyParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tRange        *SourceRange `json:\"range\"`\n\tKeyText      string       `json:\"keyText\"`\n}\n\n// SetKeyframeKey modifies the keyframe rule key text.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setKeyframeKey\n//\n// parameters:\n//\n//\tstyleSheetID\n//\trange\n//\tkeyText\nfunc SetKeyframeKey(styleSheetID StyleSheetID, rangeVal *SourceRange, keyText string) *SetKeyframeKeyParams {\n\treturn &SetKeyframeKeyParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRange:        rangeVal,\n\t\tKeyText:      keyText,\n\t}\n}\n\n// SetKeyframeKeyReturns return values.\ntype SetKeyframeKeyReturns struct {\n\tKeyText *Value `json:\"keyText,omitempty,omitzero\"` // The resulting key text after modification.\n}\n\n// Do executes CSS.setKeyframeKey against the provided context.\n//\n// returns:\n//\n//\tkeyText - The resulting key text after modification.\nfunc (p *SetKeyframeKeyParams) Do(ctx context.Context) (keyText *Value, err error) {\n\t// execute\n\tvar res SetKeyframeKeyReturns\n\terr = cdp.Execute(ctx, CommandSetKeyframeKey, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.KeyText, nil\n}\n\n// SetMediaTextParams modifies the rule selector.\ntype SetMediaTextParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tRange        *SourceRange `json:\"range\"`\n\tText         string       `json:\"text\"`\n}\n\n// SetMediaText modifies the rule selector.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setMediaText\n//\n// parameters:\n//\n//\tstyleSheetID\n//\trange\n//\ttext\nfunc SetMediaText(styleSheetID StyleSheetID, rangeVal *SourceRange, text string) *SetMediaTextParams {\n\treturn &SetMediaTextParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRange:        rangeVal,\n\t\tText:         text,\n\t}\n}\n\n// SetMediaTextReturns return values.\ntype SetMediaTextReturns struct {\n\tMedia *Media `json:\"media,omitempty,omitzero\"` // The resulting CSS media rule after modification.\n}\n\n// Do executes CSS.setMediaText against the provided context.\n//\n// returns:\n//\n//\tmedia - The resulting CSS media rule after modification.\nfunc (p *SetMediaTextParams) Do(ctx context.Context) (media *Media, err error) {\n\t// execute\n\tvar res SetMediaTextReturns\n\terr = cdp.Execute(ctx, CommandSetMediaText, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Media, nil\n}\n\n// SetContainerQueryTextParams modifies the expression of a container query.\ntype SetContainerQueryTextParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tRange        *SourceRange `json:\"range\"`\n\tText         string       `json:\"text\"`\n}\n\n// SetContainerQueryText modifies the expression of a container query.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setContainerQueryText\n//\n// parameters:\n//\n//\tstyleSheetID\n//\trange\n//\ttext\nfunc SetContainerQueryText(styleSheetID StyleSheetID, rangeVal *SourceRange, text string) *SetContainerQueryTextParams {\n\treturn &SetContainerQueryTextParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRange:        rangeVal,\n\t\tText:         text,\n\t}\n}\n\n// SetContainerQueryTextReturns return values.\ntype SetContainerQueryTextReturns struct {\n\tContainerQuery *ContainerQuery `json:\"containerQuery,omitempty,omitzero\"` // The resulting CSS container query rule after modification.\n}\n\n// Do executes CSS.setContainerQueryText against the provided context.\n//\n// returns:\n//\n//\tcontainerQuery - The resulting CSS container query rule after modification.\nfunc (p *SetContainerQueryTextParams) Do(ctx context.Context) (containerQuery *ContainerQuery, err error) {\n\t// execute\n\tvar res SetContainerQueryTextReturns\n\terr = cdp.Execute(ctx, CommandSetContainerQueryText, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.ContainerQuery, nil\n}\n\n// SetSupportsTextParams modifies the expression of a supports at-rule.\ntype SetSupportsTextParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tRange        *SourceRange `json:\"range\"`\n\tText         string       `json:\"text\"`\n}\n\n// SetSupportsText modifies the expression of a supports at-rule.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setSupportsText\n//\n// parameters:\n//\n//\tstyleSheetID\n//\trange\n//\ttext\nfunc SetSupportsText(styleSheetID StyleSheetID, rangeVal *SourceRange, text string) *SetSupportsTextParams {\n\treturn &SetSupportsTextParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRange:        rangeVal,\n\t\tText:         text,\n\t}\n}\n\n// SetSupportsTextReturns return values.\ntype SetSupportsTextReturns struct {\n\tSupports *Supports `json:\"supports,omitempty,omitzero\"` // The resulting CSS Supports rule after modification.\n}\n\n// Do executes CSS.setSupportsText against the provided context.\n//\n// returns:\n//\n//\tsupports - The resulting CSS Supports rule after modification.\nfunc (p *SetSupportsTextParams) Do(ctx context.Context) (supports *Supports, err error) {\n\t// execute\n\tvar res SetSupportsTextReturns\n\terr = cdp.Execute(ctx, CommandSetSupportsText, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Supports, nil\n}\n\n// SetScopeTextParams modifies the expression of a scope at-rule.\ntype SetScopeTextParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tRange        *SourceRange `json:\"range\"`\n\tText         string       `json:\"text\"`\n}\n\n// SetScopeText modifies the expression of a scope at-rule.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setScopeText\n//\n// parameters:\n//\n//\tstyleSheetID\n//\trange\n//\ttext\nfunc SetScopeText(styleSheetID StyleSheetID, rangeVal *SourceRange, text string) *SetScopeTextParams {\n\treturn &SetScopeTextParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRange:        rangeVal,\n\t\tText:         text,\n\t}\n}\n\n// SetScopeTextReturns return values.\ntype SetScopeTextReturns struct {\n\tScope *Scope `json:\"scope,omitempty,omitzero\"` // The resulting CSS Scope rule after modification.\n}\n\n// Do executes CSS.setScopeText against the provided context.\n//\n// returns:\n//\n//\tscope - The resulting CSS Scope rule after modification.\nfunc (p *SetScopeTextParams) Do(ctx context.Context) (scope *Scope, err error) {\n\t// execute\n\tvar res SetScopeTextReturns\n\terr = cdp.Execute(ctx, CommandSetScopeText, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Scope, nil\n}\n\n// SetRuleSelectorParams modifies the rule selector.\ntype SetRuleSelectorParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tRange        *SourceRange `json:\"range\"`\n\tSelector     string       `json:\"selector\"`\n}\n\n// SetRuleSelector modifies the rule selector.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setRuleSelector\n//\n// parameters:\n//\n//\tstyleSheetID\n//\trange\n//\tselector\nfunc SetRuleSelector(styleSheetID StyleSheetID, rangeVal *SourceRange, selector string) *SetRuleSelectorParams {\n\treturn &SetRuleSelectorParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tRange:        rangeVal,\n\t\tSelector:     selector,\n\t}\n}\n\n// SetRuleSelectorReturns return values.\ntype SetRuleSelectorReturns struct {\n\tSelectorList *SelectorList `json:\"selectorList,omitempty,omitzero\"` // The resulting selector list after modification.\n}\n\n// Do executes CSS.setRuleSelector against the provided context.\n//\n// returns:\n//\n//\tselectorList - The resulting selector list after modification.\nfunc (p *SetRuleSelectorParams) Do(ctx context.Context) (selectorList *SelectorList, err error) {\n\t// execute\n\tvar res SetRuleSelectorReturns\n\terr = cdp.Execute(ctx, CommandSetRuleSelector, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.SelectorList, nil\n}\n\n// SetStyleSheetTextParams sets the new stylesheet text.\ntype SetStyleSheetTextParams struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n\tText         string       `json:\"text\"`\n}\n\n// SetStyleSheetText sets the new stylesheet text.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setStyleSheetText\n//\n// parameters:\n//\n//\tstyleSheetID\n//\ttext\nfunc SetStyleSheetText(styleSheetID StyleSheetID, text string) *SetStyleSheetTextParams {\n\treturn &SetStyleSheetTextParams{\n\t\tStyleSheetID: styleSheetID,\n\t\tText:         text,\n\t}\n}\n\n// SetStyleSheetTextReturns return values.\ntype SetStyleSheetTextReturns struct {\n\tSourceMapURL string `json:\"sourceMapURL,omitempty,omitzero\"` // URL of source map associated with script (if any).\n}\n\n// Do executes CSS.setStyleSheetText against the provided context.\n//\n// returns:\n//\n//\tsourceMapURL - URL of source map associated with script (if any).\nfunc (p *SetStyleSheetTextParams) Do(ctx context.Context) (sourceMapURL string, err error) {\n\t// execute\n\tvar res SetStyleSheetTextReturns\n\terr = cdp.Execute(ctx, CommandSetStyleSheetText, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.SourceMapURL, nil\n}\n\n// SetStyleTextsParams applies specified style edits one after another in the\n// given order.\ntype SetStyleTextsParams struct {\n\tEdits                           []*StyleDeclarationEdit `json:\"edits\"`\n\tNodeForPropertySyntaxValidation cdp.NodeID              `json:\"nodeForPropertySyntaxValidation,omitempty,omitzero\"` // NodeId for the DOM node in whose context custom property declarations for registered properties should be validated. If omitted, declarations in the new rule text can only be validated statically, which may produce incorrect results if the declaration contains a var() for example.\n}\n\n// SetStyleTexts applies specified style edits one after another in the given\n// order.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setStyleTexts\n//\n// parameters:\n//\n//\tedits\nfunc SetStyleTexts(edits []*StyleDeclarationEdit) *SetStyleTextsParams {\n\treturn &SetStyleTextsParams{\n\t\tEdits: edits,\n\t}\n}\n\n// WithNodeForPropertySyntaxValidation nodeId for the DOM node in whose\n// context custom property declarations for registered properties should be\n// validated. If omitted, declarations in the new rule text can only be\n// validated statically, which may produce incorrect results if the declaration\n// contains a var() for example.\nfunc (p SetStyleTextsParams) WithNodeForPropertySyntaxValidation(nodeForPropertySyntaxValidation cdp.NodeID) *SetStyleTextsParams {\n\tp.NodeForPropertySyntaxValidation = nodeForPropertySyntaxValidation\n\treturn &p\n}\n\n// SetStyleTextsReturns return values.\ntype SetStyleTextsReturns struct {\n\tStyles []*Style `json:\"styles,omitempty,omitzero\"` // The resulting styles after modification.\n}\n\n// Do executes CSS.setStyleTexts against the provided context.\n//\n// returns:\n//\n//\tstyles - The resulting styles after modification.\nfunc (p *SetStyleTextsParams) Do(ctx context.Context) (styles []*Style, err error) {\n\t// execute\n\tvar res SetStyleTextsReturns\n\terr = cdp.Execute(ctx, CommandSetStyleTexts, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Styles, nil\n}\n\n// StartRuleUsageTrackingParams enables the selector recording.\ntype StartRuleUsageTrackingParams struct{}\n\n// StartRuleUsageTracking enables the selector recording.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-startRuleUsageTracking\nfunc StartRuleUsageTracking() *StartRuleUsageTrackingParams {\n\treturn &StartRuleUsageTrackingParams{}\n}\n\n// Do executes CSS.startRuleUsageTracking against the provided context.\nfunc (p *StartRuleUsageTrackingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartRuleUsageTracking, nil, nil)\n}\n\n// StopRuleUsageTrackingParams stop tracking rule usage and return the list\n// of rules that were used since last call to takeCoverageDelta (or since start\n// of coverage instrumentation).\ntype StopRuleUsageTrackingParams struct{}\n\n// StopRuleUsageTracking stop tracking rule usage and return the list of\n// rules that were used since last call to takeCoverageDelta (or since start of\n// coverage instrumentation).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-stopRuleUsageTracking\nfunc StopRuleUsageTracking() *StopRuleUsageTrackingParams {\n\treturn &StopRuleUsageTrackingParams{}\n}\n\n// StopRuleUsageTrackingReturns return values.\ntype StopRuleUsageTrackingReturns struct {\n\tRuleUsage []*RuleUsage `json:\"ruleUsage,omitempty,omitzero\"`\n}\n\n// Do executes CSS.stopRuleUsageTracking against the provided context.\n//\n// returns:\n//\n//\truleUsage\nfunc (p *StopRuleUsageTrackingParams) Do(ctx context.Context) (ruleUsage []*RuleUsage, err error) {\n\t// execute\n\tvar res StopRuleUsageTrackingReturns\n\terr = cdp.Execute(ctx, CommandStopRuleUsageTracking, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.RuleUsage, nil\n}\n\n// TakeCoverageDeltaParams obtain list of rules that became used since last\n// call to this method (or since start of coverage instrumentation).\ntype TakeCoverageDeltaParams struct{}\n\n// TakeCoverageDelta obtain list of rules that became used since last call to\n// this method (or since start of coverage instrumentation).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-takeCoverageDelta\nfunc TakeCoverageDelta() *TakeCoverageDeltaParams {\n\treturn &TakeCoverageDeltaParams{}\n}\n\n// TakeCoverageDeltaReturns return values.\ntype TakeCoverageDeltaReturns struct {\n\tCoverage  []*RuleUsage `json:\"coverage,omitempty,omitzero\"`\n\tTimestamp float64      `json:\"timestamp,omitempty,omitzero\"` // Monotonically increasing time, in seconds.\n}\n\n// Do executes CSS.takeCoverageDelta against the provided context.\n//\n// returns:\n//\n//\tcoverage\n//\ttimestamp - Monotonically increasing time, in seconds.\nfunc (p *TakeCoverageDeltaParams) Do(ctx context.Context) (coverage []*RuleUsage, timestamp float64, err error) {\n\t// execute\n\tvar res TakeCoverageDeltaReturns\n\terr = cdp.Execute(ctx, CommandTakeCoverageDelta, nil, &res)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\treturn res.Coverage, res.Timestamp, nil\n}\n\n// SetLocalFontsEnabledParams enables/disables rendering of local CSS fonts\n// (enabled by default).\ntype SetLocalFontsEnabledParams struct {\n\tEnabled bool `json:\"enabled\"` // Whether rendering of local fonts is enabled.\n}\n\n// SetLocalFontsEnabled enables/disables rendering of local CSS fonts\n// (enabled by default).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#method-setLocalFontsEnabled\n//\n// parameters:\n//\n//\tenabled - Whether rendering of local fonts is enabled.\nfunc SetLocalFontsEnabled(enabled bool) *SetLocalFontsEnabledParams {\n\treturn &SetLocalFontsEnabledParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes CSS.setLocalFontsEnabled against the provided context.\nfunc (p *SetLocalFontsEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetLocalFontsEnabled, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandAddRule                          = \"CSS.addRule\"\n\tCommandCollectClassNames                = \"CSS.collectClassNames\"\n\tCommandCreateStyleSheet                 = \"CSS.createStyleSheet\"\n\tCommandDisable                          = \"CSS.disable\"\n\tCommandEnable                           = \"CSS.enable\"\n\tCommandForcePseudoState                 = \"CSS.forcePseudoState\"\n\tCommandForceStartingStyle               = \"CSS.forceStartingStyle\"\n\tCommandGetBackgroundColors              = \"CSS.getBackgroundColors\"\n\tCommandGetComputedStyleForNode          = \"CSS.getComputedStyleForNode\"\n\tCommandResolveValues                    = \"CSS.resolveValues\"\n\tCommandGetLonghandProperties            = \"CSS.getLonghandProperties\"\n\tCommandGetInlineStylesForNode           = \"CSS.getInlineStylesForNode\"\n\tCommandGetAnimatedStylesForNode         = \"CSS.getAnimatedStylesForNode\"\n\tCommandGetMatchedStylesForNode          = \"CSS.getMatchedStylesForNode\"\n\tCommandGetEnvironmentVariables          = \"CSS.getEnvironmentVariables\"\n\tCommandGetMediaQueries                  = \"CSS.getMediaQueries\"\n\tCommandGetPlatformFontsForNode          = \"CSS.getPlatformFontsForNode\"\n\tCommandGetStyleSheetText                = \"CSS.getStyleSheetText\"\n\tCommandGetLayersForNode                 = \"CSS.getLayersForNode\"\n\tCommandGetLocationForSelector           = \"CSS.getLocationForSelector\"\n\tCommandTrackComputedStyleUpdatesForNode = \"CSS.trackComputedStyleUpdatesForNode\"\n\tCommandTrackComputedStyleUpdates        = \"CSS.trackComputedStyleUpdates\"\n\tCommandTakeComputedStyleUpdates         = \"CSS.takeComputedStyleUpdates\"\n\tCommandSetEffectivePropertyValueForNode = \"CSS.setEffectivePropertyValueForNode\"\n\tCommandSetPropertyRulePropertyName      = \"CSS.setPropertyRulePropertyName\"\n\tCommandSetKeyframeKey                   = \"CSS.setKeyframeKey\"\n\tCommandSetMediaText                     = \"CSS.setMediaText\"\n\tCommandSetContainerQueryText            = \"CSS.setContainerQueryText\"\n\tCommandSetSupportsText                  = \"CSS.setSupportsText\"\n\tCommandSetScopeText                     = \"CSS.setScopeText\"\n\tCommandSetRuleSelector                  = \"CSS.setRuleSelector\"\n\tCommandSetStyleSheetText                = \"CSS.setStyleSheetText\"\n\tCommandSetStyleTexts                    = \"CSS.setStyleTexts\"\n\tCommandStartRuleUsageTracking           = \"CSS.startRuleUsageTracking\"\n\tCommandStopRuleUsageTracking            = \"CSS.stopRuleUsageTracking\"\n\tCommandTakeCoverageDelta                = \"CSS.takeCoverageDelta\"\n\tCommandSetLocalFontsEnabled             = \"CSS.setLocalFontsEnabled\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/css/events.go",
    "content": "package css\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EventFontsUpdated fires whenever a web font is updated. A non-empty font\n// parameter indicates a successfully loaded web font.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#event-fontsUpdated\ntype EventFontsUpdated struct {\n\tFont *FontFace `json:\"font,omitempty,omitzero\"` // The web font that has loaded.\n}\n\n// EventMediaQueryResultChanged fires whenever a MediaQuery result changes\n// (for example, after a browser window has been resized.) The current\n// implementation considers only viewport-dependent media features.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#event-mediaQueryResultChanged\ntype EventMediaQueryResultChanged struct{}\n\n// EventStyleSheetAdded fired whenever an active document stylesheet is\n// added.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#event-styleSheetAdded\ntype EventStyleSheetAdded struct {\n\tHeader *StyleSheetHeader `json:\"header\"` // Added stylesheet metainfo.\n}\n\n// EventStyleSheetChanged fired whenever a stylesheet is changed as a result\n// of the client operation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#event-styleSheetChanged\ntype EventStyleSheetChanged struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"`\n}\n\n// EventStyleSheetRemoved fired whenever an active document stylesheet is\n// removed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#event-styleSheetRemoved\ntype EventStyleSheetRemoved struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"` // Identifier of the removed stylesheet.\n}\n\n// EventComputedStyleUpdated [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#event-computedStyleUpdated\ntype EventComputedStyleUpdated struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // The node id that has updated computed styles.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/css/types.go",
    "content": "package css\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n)\n\n// StyleSheetID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-StyleSheetId\ntype StyleSheetID string\n\n// String returns the StyleSheetID as string value.\nfunc (t StyleSheetID) String() string {\n\treturn string(t)\n}\n\n// StyleSheetOrigin stylesheet type: \"injected\" for stylesheets injected via\n// extension, \"user-agent\" for user-agent stylesheets, \"inspector\" for\n// stylesheets created by the inspector (i.e. those holding the \"via inspector\"\n// rules), \"regular\" for regular stylesheets.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-StyleSheetOrigin\ntype StyleSheetOrigin string\n\n// String returns the StyleSheetOrigin as string value.\nfunc (t StyleSheetOrigin) String() string {\n\treturn string(t)\n}\n\n// StyleSheetOrigin values.\nconst (\n\tStyleSheetOriginInjected  StyleSheetOrigin = \"injected\"\n\tStyleSheetOriginUserAgent StyleSheetOrigin = \"user-agent\"\n\tStyleSheetOriginInspector StyleSheetOrigin = \"inspector\"\n\tStyleSheetOriginRegular   StyleSheetOrigin = \"regular\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *StyleSheetOrigin) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch StyleSheetOrigin(s) {\n\tcase StyleSheetOriginInjected:\n\t\t*t = StyleSheetOriginInjected\n\tcase StyleSheetOriginUserAgent:\n\t\t*t = StyleSheetOriginUserAgent\n\tcase StyleSheetOriginInspector:\n\t\t*t = StyleSheetOriginInspector\n\tcase StyleSheetOriginRegular:\n\t\t*t = StyleSheetOriginRegular\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown StyleSheetOrigin value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PseudoElementMatches CSS rule collection for a single pseudo style.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-PseudoElementMatches\ntype PseudoElementMatches struct {\n\tPseudoType       cdp.PseudoType `json:\"pseudoType\"`                          // Pseudo element type.\n\tPseudoIdentifier string         `json:\"pseudoIdentifier,omitempty,omitzero\"` // Pseudo element custom ident.\n\tMatches          []*RuleMatch   `json:\"matches\"`                             // Matches of CSS rules applicable to the pseudo style.\n}\n\n// AnimationStyle CSS style coming from animations with the name of the\n// animation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSAnimationStyle\ntype AnimationStyle struct {\n\tName  string `json:\"name,omitempty,omitzero\"` // The name of the animation.\n\tStyle *Style `json:\"style\"`                   // The style coming from the animation.\n}\n\n// InheritedStyleEntry inherited CSS rule collection from ancestor node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-InheritedStyleEntry\ntype InheritedStyleEntry struct {\n\tInlineStyle     *Style       `json:\"inlineStyle,omitempty,omitzero\"` // The ancestor node's inline style, if any, in the style inheritance chain.\n\tMatchedCSSRules []*RuleMatch `json:\"matchedCSSRules\"`                // Matches of CSS rules matching the ancestor node in the style inheritance chain.\n}\n\n// InheritedAnimatedStyleEntry inherited CSS style collection for animated\n// styles from ancestor node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-InheritedAnimatedStyleEntry\ntype InheritedAnimatedStyleEntry struct {\n\tAnimationStyles  []*AnimationStyle `json:\"animationStyles,omitempty,omitzero\"`  // Styles coming from the animations of the ancestor, if any, in the style inheritance chain.\n\tTransitionsStyle *Style            `json:\"transitionsStyle,omitempty,omitzero\"` // The style coming from the transitions of the ancestor, if any, in the style inheritance chain.\n}\n\n// InheritedPseudoElementMatches inherited pseudo element matches from\n// pseudos of an ancestor node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-InheritedPseudoElementMatches\ntype InheritedPseudoElementMatches struct {\n\tPseudoElements []*PseudoElementMatches `json:\"pseudoElements\"` // Matches of pseudo styles from the pseudos of an ancestor node.\n}\n\n// RuleMatch match data for a CSS rule.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-RuleMatch\ntype RuleMatch struct {\n\tRule              *Rule   `json:\"rule\"`              // CSS rule in the match.\n\tMatchingSelectors []int64 `json:\"matchingSelectors\"` // Matching selector indices in the rule's selectorList selectors (0-based).\n}\n\n// Value data for a simple selector (these are delimited by commas in a\n// selector list).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-Value\ntype Value struct {\n\tText        string       `json:\"text\"`                           // Value text.\n\tRange       *SourceRange `json:\"range,omitempty,omitzero\"`       // Value range in the underlying resource (if available).\n\tSpecificity *Specificity `json:\"specificity,omitempty,omitzero\"` // Specificity of the selector.\n}\n\n// Specificity specificity:\n// https://drafts.csswg.org/selectors/#specificity-rules.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-Specificity\ntype Specificity struct {\n\tA int64 `json:\"a\"` // The a component, which represents the number of ID selectors.\n\tB int64 `json:\"b\"` // The b component, which represents the number of class selectors, attributes selectors, and pseudo-classes.\n\tC int64 `json:\"c\"` // The c component, which represents the number of type selectors and pseudo-elements.\n}\n\n// SelectorList selector list data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-SelectorList\ntype SelectorList struct {\n\tSelectors []*Value `json:\"selectors\"` // Selectors in the list.\n\tText      string   `json:\"text\"`      // Rule selector text.\n}\n\n// StyleSheetHeader CSS stylesheet metainformation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSStyleSheetHeader\ntype StyleSheetHeader struct {\n\tStyleSheetID  StyleSheetID      `json:\"styleSheetId\"`                    // The stylesheet identifier.\n\tFrameID       cdp.FrameID       `json:\"frameId\"`                         // Owner frame identifier.\n\tSourceURL     string            `json:\"sourceURL\"`                       // Stylesheet resource URL. Empty if this is a constructed stylesheet created using new CSSStyleSheet() (but non-empty if this is a constructed stylesheet imported as a CSS module script).\n\tSourceMapURL  string            `json:\"sourceMapURL,omitempty,omitzero\"` // URL of source map associated with the stylesheet (if any).\n\tOrigin        StyleSheetOrigin  `json:\"origin\"`                          // Stylesheet origin.\n\tTitle         string            `json:\"title\"`                           // Stylesheet title.\n\tOwnerNode     cdp.BackendNodeID `json:\"ownerNode,omitempty,omitzero\"`    // The backend id for the owner node of the stylesheet.\n\tDisabled      bool              `json:\"disabled\"`                        // Denotes whether the stylesheet is disabled.\n\tHasSourceURL  bool              `json:\"hasSourceURL\"`                    // Whether the sourceURL field value comes from the sourceURL comment.\n\tIsInline      bool              `json:\"isInline\"`                        // Whether this stylesheet is created for STYLE tag by parser. This flag is not set for document.written STYLE tags.\n\tIsMutable     bool              `json:\"isMutable\"`                       // Whether this stylesheet is mutable. Inline stylesheets become mutable after they have been modified via CSSOM API. <link> element's stylesheets become mutable only if DevTools modifies them. Constructed stylesheets (new CSSStyleSheet()) are mutable immediately after creation.\n\tIsConstructed bool              `json:\"isConstructed\"`                   // True if this stylesheet is created through new CSSStyleSheet() or imported as a CSS module script.\n\tStartLine     float64           `json:\"startLine\"`                       // Line offset of the stylesheet within the resource (zero based).\n\tStartColumn   float64           `json:\"startColumn\"`                     // Column offset of the stylesheet within the resource (zero based).\n\tLength        float64           `json:\"length\"`                          // Size of the content (in characters).\n\tEndLine       float64           `json:\"endLine\"`                         // Line offset of the end of the stylesheet within the resource (zero based).\n\tEndColumn     float64           `json:\"endColumn\"`                       // Column offset of the end of the stylesheet within the resource (zero based).\n\tLoadingFailed bool              `json:\"loadingFailed\"`                   // If the style sheet was loaded from a network resource, this indicates when the resource failed to load\n}\n\n// Rule CSS rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSRule\ntype Rule struct {\n\tStyleSheetID     StyleSheetID      `json:\"styleSheetId,omitempty,omitzero\"`     // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tSelectorList     *SelectorList     `json:\"selectorList\"`                        // Rule selector data.\n\tNestingSelectors []string          `json:\"nestingSelectors,omitempty,omitzero\"` // Array of selectors from ancestor style rules, sorted by distance from the current rule.\n\tOrigin           StyleSheetOrigin  `json:\"origin\"`                              // Parent stylesheet's origin.\n\tStyle            *Style            `json:\"style\"`                               // Associated style declaration.\n\tMedia            []*Media          `json:\"media,omitempty,omitzero\"`            // Media list array (for rules involving media queries). The array enumerates media queries starting with the innermost one, going outwards.\n\tContainerQueries []*ContainerQuery `json:\"containerQueries,omitempty,omitzero\"` // Container query list array (for rules involving container queries). The array enumerates container queries starting with the innermost one, going outwards.\n\tSupports         []*Supports       `json:\"supports,omitempty,omitzero\"`         // @supports CSS at-rule array. The array enumerates @supports at-rules starting with the innermost one, going outwards.\n\tLayers           []*Layer          `json:\"layers,omitempty,omitzero\"`           // Cascade layer array. Contains the layer hierarchy that this rule belongs to starting with the innermost layer and going outwards.\n\tScopes           []*Scope          `json:\"scopes,omitempty,omitzero\"`           // @scope CSS at-rule array. The array enumerates @scope at-rules starting with the innermost one, going outwards.\n\tRuleTypes        []RuleType        `json:\"ruleTypes,omitempty,omitzero\"`        // The array keeps the types of ancestor CSSRules from the innermost going outwards.\n\tStartingStyles   []*StartingStyle  `json:\"startingStyles,omitempty,omitzero\"`   // @starting-style CSS at-rule array. The array enumerates @starting-style at-rules starting with the innermost one, going outwards.\n}\n\n// RuleType enum indicating the type of a CSS rule, used to represent the\n// order of a style rule's ancestors. This list only contains rule types that\n// are collected during the ancestor rule collection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSRuleType\ntype RuleType string\n\n// String returns the RuleType as string value.\nfunc (t RuleType) String() string {\n\treturn string(t)\n}\n\n// RuleType values.\nconst (\n\tRuleTypeMediaRule         RuleType = \"MediaRule\"\n\tRuleTypeSupportsRule      RuleType = \"SupportsRule\"\n\tRuleTypeContainerRule     RuleType = \"ContainerRule\"\n\tRuleTypeLayerRule         RuleType = \"LayerRule\"\n\tRuleTypeScopeRule         RuleType = \"ScopeRule\"\n\tRuleTypeStyleRule         RuleType = \"StyleRule\"\n\tRuleTypeStartingStyleRule RuleType = \"StartingStyleRule\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *RuleType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch RuleType(s) {\n\tcase RuleTypeMediaRule:\n\t\t*t = RuleTypeMediaRule\n\tcase RuleTypeSupportsRule:\n\t\t*t = RuleTypeSupportsRule\n\tcase RuleTypeContainerRule:\n\t\t*t = RuleTypeContainerRule\n\tcase RuleTypeLayerRule:\n\t\t*t = RuleTypeLayerRule\n\tcase RuleTypeScopeRule:\n\t\t*t = RuleTypeScopeRule\n\tcase RuleTypeStyleRule:\n\t\t*t = RuleTypeStyleRule\n\tcase RuleTypeStartingStyleRule:\n\t\t*t = RuleTypeStartingStyleRule\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown RuleType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// RuleUsage CSS coverage information.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-RuleUsage\ntype RuleUsage struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tStartOffset  float64      `json:\"startOffset\"`  // Offset of the start of the rule (including selector) from the beginning of the stylesheet.\n\tEndOffset    float64      `json:\"endOffset\"`    // Offset of the end of the rule body from the beginning of the stylesheet.\n\tUsed         bool         `json:\"used\"`         // Indicates whether the rule was actually used by some element in the page.\n}\n\n// SourceRange text range within a resource. All numbers are zero-based.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-SourceRange\ntype SourceRange struct {\n\tStartLine   int64 `json:\"startLine\"`   // Start line of range.\n\tStartColumn int64 `json:\"startColumn\"` // Start column of range (inclusive).\n\tEndLine     int64 `json:\"endLine\"`     // End line of range\n\tEndColumn   int64 `json:\"endColumn\"`   // End column of range (exclusive).\n}\n\n// ShorthandEntry [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-ShorthandEntry\ntype ShorthandEntry struct {\n\tName      string `json:\"name\"`      // Shorthand name.\n\tValue     string `json:\"value\"`     // Shorthand value.\n\tImportant bool   `json:\"important\"` // Whether the property has \"!important\" annotation (implies false if absent).\n}\n\n// ComputedStyleProperty [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSComputedStyleProperty\ntype ComputedStyleProperty struct {\n\tName  string `json:\"name\"`  // Computed style property name.\n\tValue string `json:\"value\"` // Computed style property value.\n}\n\n// Style CSS style representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSStyle\ntype Style struct {\n\tStyleSheetID     StyleSheetID      `json:\"styleSheetId,omitempty,omitzero\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tCSSProperties    []*Property       `json:\"cssProperties\"`                   // CSS properties in the style.\n\tShorthandEntries []*ShorthandEntry `json:\"shorthandEntries\"`                // Computed values for all shorthands found in the style.\n\tCSSText          string            `json:\"cssText,omitempty,omitzero\"`      // Style declaration text (if available).\n\tRange            *SourceRange      `json:\"range,omitempty,omitzero\"`        // Style declaration range in the enclosing stylesheet (if available).\n}\n\n// Property CSS property declaration data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSProperty\ntype Property struct {\n\tName               string       `json:\"name\"`                                  // The property name.\n\tValue              string       `json:\"value\"`                                 // The property value.\n\tImportant          bool         `json:\"important\"`                             // Whether the property has \"!important\" annotation (implies false if absent).\n\tImplicit           bool         `json:\"implicit\"`                              // Whether the property is implicit (implies false if absent).\n\tText               string       `json:\"text,omitempty,omitzero\"`               // The full property text as specified in the style.\n\tParsedOk           bool         `json:\"parsedOk\"`                              // Whether the property is understood by the browser (implies true if absent).\n\tDisabled           bool         `json:\"disabled\"`                              // Whether the property is disabled by the user (present for source-based properties only).\n\tRange              *SourceRange `json:\"range,omitempty,omitzero\"`              // The entire property range in the enclosing style declaration (if available).\n\tLonghandProperties []*Property  `json:\"longhandProperties,omitempty,omitzero\"` // Parsed longhand components of this property if it is a shorthand. This field will be empty if the given property is not a shorthand.\n}\n\n// Media CSS media rule descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSMedia\ntype Media struct {\n\tText         string        `json:\"text\"`                            // Media query text.\n\tSource       MediaSource   `json:\"source\"`                          // Source of the media query: \"mediaRule\" if specified by a @media rule, \"importRule\" if specified by an @import rule, \"linkedSheet\" if specified by a \"media\" attribute in a linked stylesheet's LINK tag, \"inlineSheet\" if specified by a \"media\" attribute in an inline stylesheet's STYLE tag.\n\tSourceURL    string        `json:\"sourceURL,omitempty,omitzero\"`    // URL of the document containing the media query description.\n\tRange        *SourceRange  `json:\"range,omitempty,omitzero\"`        // The associated rule (@media or @import) header range in the enclosing stylesheet (if available).\n\tStyleSheetID StyleSheetID  `json:\"styleSheetId,omitempty,omitzero\"` // Identifier of the stylesheet containing this object (if exists).\n\tMediaList    []*MediaQuery `json:\"mediaList,omitempty,omitzero\"`    // Array of media queries.\n}\n\n// MediaQuery media query descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-MediaQuery\ntype MediaQuery struct {\n\tExpressions []*MediaQueryExpression `json:\"expressions\"` // Array of media query expressions.\n\tActive      bool                    `json:\"active\"`      // Whether the media query condition is satisfied.\n}\n\n// MediaQueryExpression media query expression descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-MediaQueryExpression\ntype MediaQueryExpression struct {\n\tValue          float64      `json:\"value\"`                             // Media query expression value.\n\tUnit           string       `json:\"unit\"`                              // Media query expression units.\n\tFeature        string       `json:\"feature\"`                           // Media query expression feature.\n\tValueRange     *SourceRange `json:\"valueRange,omitempty,omitzero\"`     // The associated range of the value text in the enclosing stylesheet (if available).\n\tComputedLength float64      `json:\"computedLength,omitempty,omitzero\"` // Computed length of media query expression (if applicable).\n}\n\n// ContainerQuery CSS container query rule descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSContainerQuery\ntype ContainerQuery struct {\n\tText               string           `json:\"text\"`                            // Container query text.\n\tRange              *SourceRange     `json:\"range,omitempty,omitzero\"`        // The associated rule header range in the enclosing stylesheet (if available).\n\tStyleSheetID       StyleSheetID     `json:\"styleSheetId,omitempty,omitzero\"` // Identifier of the stylesheet containing this object (if exists).\n\tName               string           `json:\"name,omitempty,omitzero\"`         // Optional name for the container.\n\tPhysicalAxes       dom.PhysicalAxes `json:\"physicalAxes,omitempty,omitzero\"` // Optional physical axes queried for the container.\n\tLogicalAxes        dom.LogicalAxes  `json:\"logicalAxes,omitempty,omitzero\"`  // Optional logical axes queried for the container.\n\tQueriesScrollState bool             `json:\"queriesScrollState\"`              // true if the query contains scroll-state() queries.\n\tQueriesAnchored    bool             `json:\"queriesAnchored\"`                 // true if the query contains anchored() queries.\n}\n\n// Supports CSS Supports at-rule descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSSupports\ntype Supports struct {\n\tText         string       `json:\"text\"`                            // Supports rule text.\n\tActive       bool         `json:\"active\"`                          // Whether the supports condition is satisfied.\n\tRange        *SourceRange `json:\"range,omitempty,omitzero\"`        // The associated rule header range in the enclosing stylesheet (if available).\n\tStyleSheetID StyleSheetID `json:\"styleSheetId,omitempty,omitzero\"` // Identifier of the stylesheet containing this object (if exists).\n}\n\n// Scope CSS Scope at-rule descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSScope\ntype Scope struct {\n\tText         string       `json:\"text\"`                            // Scope rule text.\n\tRange        *SourceRange `json:\"range,omitempty,omitzero\"`        // The associated rule header range in the enclosing stylesheet (if available).\n\tStyleSheetID StyleSheetID `json:\"styleSheetId,omitempty,omitzero\"` // Identifier of the stylesheet containing this object (if exists).\n}\n\n// Layer CSS Layer at-rule descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSLayer\ntype Layer struct {\n\tText         string       `json:\"text\"`                            // Layer name.\n\tRange        *SourceRange `json:\"range,omitempty,omitzero\"`        // The associated rule header range in the enclosing stylesheet (if available).\n\tStyleSheetID StyleSheetID `json:\"styleSheetId,omitempty,omitzero\"` // Identifier of the stylesheet containing this object (if exists).\n}\n\n// StartingStyle CSS Starting Style at-rule descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSStartingStyle\ntype StartingStyle struct {\n\tRange        *SourceRange `json:\"range,omitempty,omitzero\"`        // The associated rule header range in the enclosing stylesheet (if available).\n\tStyleSheetID StyleSheetID `json:\"styleSheetId,omitempty,omitzero\"` // Identifier of the stylesheet containing this object (if exists).\n}\n\n// LayerData CSS Layer data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSLayerData\ntype LayerData struct {\n\tName      string       `json:\"name\"`                         // Layer name.\n\tSubLayers []*LayerData `json:\"subLayers,omitempty,omitzero\"` // Direct sub-layers\n\tOrder     float64      `json:\"order\"`                        // Layer order. The order determines the order of the layer in the cascade order. A higher number has higher priority in the cascade order.\n}\n\n// PlatformFontUsage information about amount of glyphs that were rendered\n// with given font.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-PlatformFontUsage\ntype PlatformFontUsage struct {\n\tFamilyName     string  `json:\"familyName\"`     // Font's family name reported by platform.\n\tPostScriptName string  `json:\"postScriptName\"` // Font's PostScript name reported by platform.\n\tIsCustomFont   bool    `json:\"isCustomFont\"`   // Indicates if the font was downloaded or resolved locally.\n\tGlyphCount     float64 `json:\"glyphCount\"`     // Amount of glyphs that were rendered with this font.\n}\n\n// FontVariationAxis information about font variation axes for variable\n// fonts.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-FontVariationAxis\ntype FontVariationAxis struct {\n\tTag          string  `json:\"tag\"`          // The font-variation-setting tag (a.k.a. \"axis tag\").\n\tName         string  `json:\"name\"`         // Human-readable variation name in the default language (normally, \"en\").\n\tMinValue     float64 `json:\"minValue\"`     // The minimum value (inclusive) the font supports for this tag.\n\tMaxValue     float64 `json:\"maxValue\"`     // The maximum value (inclusive) the font supports for this tag.\n\tDefaultValue float64 `json:\"defaultValue\"` // The default value.\n}\n\n// FontFace properties of a web font:\n// https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#font-descriptions and\n// additional information such as platformFontFamily and fontVariationAxes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-FontFace\ntype FontFace struct {\n\tFontFamily         string               `json:\"fontFamily\"`                           // The font-family.\n\tFontStyle          string               `json:\"fontStyle\"`                            // The font-style.\n\tFontVariant        string               `json:\"fontVariant\"`                          // The font-variant.\n\tFontWeight         string               `json:\"fontWeight\"`                           // The font-weight.\n\tFontStretch        string               `json:\"fontStretch\"`                          // The font-stretch.\n\tFontDisplay        string               `json:\"fontDisplay\"`                          // The font-display.\n\tUnicodeRange       string               `json:\"unicodeRange\"`                         // The unicode-range.\n\tSrc                string               `json:\"src\"`                                  // The src.\n\tPlatformFontFamily string               `json:\"platformFontFamily\"`                   // The resolved platform font family\n\tFontVariationAxes  []*FontVariationAxis `json:\"fontVariationAxes,omitempty,omitzero\"` // Available variation settings (a.k.a. \"axes\").\n}\n\n// TryRule CSS try rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSTryRule\ntype TryRule struct {\n\tStyleSheetID StyleSheetID     `json:\"styleSheetId,omitempty,omitzero\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tOrigin       StyleSheetOrigin `json:\"origin\"`                          // Parent stylesheet's origin.\n\tStyle        *Style           `json:\"style\"`                           // Associated style declaration.\n}\n\n// PositionTryRule CSS @position-try rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSPositionTryRule\ntype PositionTryRule struct {\n\tName         *Value           `json:\"name\"`                            // The prelude dashed-ident name\n\tStyleSheetID StyleSheetID     `json:\"styleSheetId,omitempty,omitzero\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tOrigin       StyleSheetOrigin `json:\"origin\"`                          // Parent stylesheet's origin.\n\tStyle        *Style           `json:\"style\"`                           // Associated style declaration.\n\tActive       bool             `json:\"active\"`\n}\n\n// KeyframesRule CSS keyframes rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSKeyframesRule\ntype KeyframesRule struct {\n\tAnimationName *Value          `json:\"animationName\"` // Animation name.\n\tKeyframes     []*KeyframeRule `json:\"keyframes\"`     // List of keyframes.\n}\n\n// PropertyRegistration representation of a custom property registration\n// through CSS.registerProperty.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSPropertyRegistration\ntype PropertyRegistration struct {\n\tPropertyName string `json:\"propertyName\"`\n\tInitialValue *Value `json:\"initialValue,omitempty,omitzero\"`\n\tInherits     bool   `json:\"inherits\"`\n\tSyntax       string `json:\"syntax\"`\n}\n\n// FontPaletteValuesRule CSS font-palette-values rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSFontPaletteValuesRule\ntype FontPaletteValuesRule struct {\n\tStyleSheetID    StyleSheetID     `json:\"styleSheetId,omitempty,omitzero\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tOrigin          StyleSheetOrigin `json:\"origin\"`                          // Parent stylesheet's origin.\n\tFontPaletteName *Value           `json:\"fontPaletteName\"`                 // Associated font palette name.\n\tStyle           *Style           `json:\"style\"`                           // Associated style declaration.\n}\n\n// PropertyRule CSS property at-rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSPropertyRule\ntype PropertyRule struct {\n\tStyleSheetID StyleSheetID     `json:\"styleSheetId,omitempty,omitzero\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tOrigin       StyleSheetOrigin `json:\"origin\"`                          // Parent stylesheet's origin.\n\tPropertyName *Value           `json:\"propertyName\"`                    // Associated property name.\n\tStyle        *Style           `json:\"style\"`                           // Associated style declaration.\n}\n\n// FunctionParameter CSS function argument representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSFunctionParameter\ntype FunctionParameter struct {\n\tName string `json:\"name\"` // The parameter name.\n\tType string `json:\"type\"` // The parameter type.\n}\n\n// FunctionConditionNode CSS function conditional block representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSFunctionConditionNode\ntype FunctionConditionNode struct {\n\tMedia            *Media          `json:\"media,omitempty,omitzero\"`            // Media query for this conditional block. Only one type of condition should be set.\n\tContainerQueries *ContainerQuery `json:\"containerQueries,omitempty,omitzero\"` // Container query for this conditional block. Only one type of condition should be set.\n\tSupports         *Supports       `json:\"supports,omitempty,omitzero\"`         // @supports CSS at-rule condition. Only one type of condition should be set.\n\tChildren         []*FunctionNode `json:\"children\"`                            // Block body.\n\tConditionText    string          `json:\"conditionText\"`                       // The condition text.\n}\n\n// FunctionNode section of the body of a CSS function rule.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSFunctionNode\ntype FunctionNode struct {\n\tCondition *FunctionConditionNode `json:\"condition,omitempty,omitzero\"` // A conditional block. If set, style should not be set.\n\tStyle     *Style                 `json:\"style,omitempty,omitzero\"`     // Values set by this node. If set, condition should not be set.\n}\n\n// FunctionRule CSS function at-rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSFunctionRule\ntype FunctionRule struct {\n\tName         *Value               `json:\"name\"`                            // Name of the function.\n\tStyleSheetID StyleSheetID         `json:\"styleSheetId,omitempty,omitzero\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tOrigin       StyleSheetOrigin     `json:\"origin\"`                          // Parent stylesheet's origin.\n\tParameters   []*FunctionParameter `json:\"parameters\"`                      // List of parameters.\n\tChildren     []*FunctionNode      `json:\"children\"`                        // Function body.\n}\n\n// KeyframeRule CSS keyframe rule representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSKeyframeRule\ntype KeyframeRule struct {\n\tStyleSheetID StyleSheetID     `json:\"styleSheetId,omitempty,omitzero\"` // The css style sheet identifier (absent for user agent stylesheet and user-specified stylesheet rules) this rule came from.\n\tOrigin       StyleSheetOrigin `json:\"origin\"`                          // Parent stylesheet's origin.\n\tKeyText      *Value           `json:\"keyText\"`                         // Associated key text.\n\tStyle        *Style           `json:\"style\"`                           // Associated style declaration.\n}\n\n// StyleDeclarationEdit a descriptor of operation to mutate style declaration\n// text.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-StyleDeclarationEdit\ntype StyleDeclarationEdit struct {\n\tStyleSheetID StyleSheetID `json:\"styleSheetId\"` // The css style sheet identifier.\n\tRange        *SourceRange `json:\"range\"`        // The range of the style text in the enclosing stylesheet.\n\tText         string       `json:\"text\"`         // New style text.\n}\n\n// MediaSource source of the media query: \"mediaRule\" if specified by a\n// @media rule, \"importRule\" if specified by an @import rule, \"linkedSheet\" if\n// specified by a \"media\" attribute in a linked stylesheet's LINK tag,\n// \"inlineSheet\" if specified by a \"media\" attribute in an inline stylesheet's\n// STYLE tag.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/CSS#type-CSSMedia\ntype MediaSource string\n\n// String returns the MediaSource as string value.\nfunc (t MediaSource) String() string {\n\treturn string(t)\n}\n\n// MediaSource values.\nconst (\n\tMediaSourceMediaRule   MediaSource = \"mediaRule\"\n\tMediaSourceImportRule  MediaSource = \"importRule\"\n\tMediaSourceLinkedSheet MediaSource = \"linkedSheet\"\n\tMediaSourceInlineSheet MediaSource = \"inlineSheet\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MediaSource) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch MediaSource(s) {\n\tcase MediaSourceMediaRule:\n\t\t*t = MediaSourceMediaRule\n\tcase MediaSourceImportRule:\n\t\t*t = MediaSourceImportRule\n\tcase MediaSourceLinkedSheet:\n\t\t*t = MediaSourceLinkedSheet\n\tcase MediaSourceInlineSheet:\n\t\t*t = MediaSourceInlineSheet\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MediaSource value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/debugger/debugger.go",
    "content": "// Package debugger provides the Chrome DevTools Protocol\n// commands, types, and events for the Debugger domain.\n//\n// Debugger domain exposes JavaScript debugging capabilities. It allows\n// setting and removing breakpoints, stepping through execution, exploring stack\n// traces, etc.\n//\n// Generated by the cdproto-gen command.\npackage debugger\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// ContinueToLocationParams continues execution until specific location is\n// reached.\ntype ContinueToLocationParams struct {\n\tLocation         *Location                          `json:\"location\"` // Location to continue to.\n\tTargetCallFrames ContinueToLocationTargetCallFrames `json:\"targetCallFrames,omitempty,omitzero\"`\n}\n\n// ContinueToLocation continues execution until specific location is reached.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-continueToLocation\n//\n// parameters:\n//\n//\tlocation - Location to continue to.\nfunc ContinueToLocation(location *Location) *ContinueToLocationParams {\n\treturn &ContinueToLocationParams{\n\t\tLocation: location,\n\t}\n}\n\n// WithTargetCallFrames [no description].\nfunc (p ContinueToLocationParams) WithTargetCallFrames(targetCallFrames ContinueToLocationTargetCallFrames) *ContinueToLocationParams {\n\tp.TargetCallFrames = targetCallFrames\n\treturn &p\n}\n\n// Do executes Debugger.continueToLocation against the provided context.\nfunc (p *ContinueToLocationParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandContinueToLocation, p, nil)\n}\n\n// DisableParams disables debugger for given page.\ntype DisableParams struct{}\n\n// Disable disables debugger for given page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Debugger.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables debugger for the given page. Clients should not\n// assume that the debugging has been enabled until the result for this command\n// is received.\ntype EnableParams struct {\n\tMaxScriptsCacheSize float64 `json:\"maxScriptsCacheSize,omitempty,omitzero\"` // The maximum size in bytes of collected scripts (not referenced by other heap objects) the debugger can hold. Puts no limit if parameter is omitted.\n}\n\n// Enable enables debugger for the given page. Clients should not assume that\n// the debugging has been enabled until the result for this command is received.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// WithMaxScriptsCacheSize the maximum size in bytes of collected scripts\n// (not referenced by other heap objects) the debugger can hold. Puts no limit\n// if parameter is omitted.\nfunc (p EnableParams) WithMaxScriptsCacheSize(maxScriptsCacheSize float64) *EnableParams {\n\tp.MaxScriptsCacheSize = maxScriptsCacheSize\n\treturn &p\n}\n\n// EnableReturns return values.\ntype EnableReturns struct {\n\tDebuggerID runtime.UniqueDebuggerID `json:\"debuggerId,omitempty,omitzero\"` // Unique identifier of the debugger.\n}\n\n// Do executes Debugger.enable against the provided context.\n//\n// returns:\n//\n//\tdebuggerID - Unique identifier of the debugger.\nfunc (p *EnableParams) Do(ctx context.Context) (debuggerID runtime.UniqueDebuggerID, err error) {\n\t// execute\n\tvar res EnableReturns\n\terr = cdp.Execute(ctx, CommandEnable, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.DebuggerID, nil\n}\n\n// EvaluateOnCallFrameParams evaluates expression on a given call frame.\ntype EvaluateOnCallFrameParams struct {\n\tCallFrameID           CallFrameID       `json:\"callFrameId\"`                    // Call frame identifier to evaluate on.\n\tExpression            string            `json:\"expression\"`                     // Expression to evaluate.\n\tObjectGroup           string            `json:\"objectGroup,omitempty,omitzero\"` // String object group name to put result into (allows rapid releasing resulting object handles using releaseObjectGroup).\n\tIncludeCommandLineAPI bool              `json:\"includeCommandLineAPI\"`          // Specifies whether command line API should be available to the evaluated expression, defaults to false.\n\tSilent                bool              `json:\"silent\"`                         // In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state.\n\tReturnByValue         bool              `json:\"returnByValue\"`                  // Whether the result is expected to be a JSON object that should be sent by value.\n\tGeneratePreview       bool              `json:\"generatePreview\"`                // Whether preview should be generated for the result.\n\tThrowOnSideEffect     bool              `json:\"throwOnSideEffect\"`              // Whether to throw an exception if side effect cannot be ruled out during evaluation.\n\tTimeout               runtime.TimeDelta `json:\"timeout,omitempty,omitzero\"`     // Terminate execution after timing out (number of milliseconds).\n}\n\n// EvaluateOnCallFrame evaluates expression on a given call frame.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-evaluateOnCallFrame\n//\n// parameters:\n//\n//\tcallFrameID - Call frame identifier to evaluate on.\n//\texpression - Expression to evaluate.\nfunc EvaluateOnCallFrame(callFrameID CallFrameID, expression string) *EvaluateOnCallFrameParams {\n\treturn &EvaluateOnCallFrameParams{\n\t\tCallFrameID:           callFrameID,\n\t\tExpression:            expression,\n\t\tIncludeCommandLineAPI: false,\n\t\tSilent:                false,\n\t\tReturnByValue:         false,\n\t\tGeneratePreview:       false,\n\t\tThrowOnSideEffect:     false,\n\t}\n}\n\n// WithObjectGroup string object group name to put result into (allows rapid\n// releasing resulting object handles using releaseObjectGroup).\nfunc (p EvaluateOnCallFrameParams) WithObjectGroup(objectGroup string) *EvaluateOnCallFrameParams {\n\tp.ObjectGroup = objectGroup\n\treturn &p\n}\n\n// WithIncludeCommandLineAPI specifies whether command line API should be\n// available to the evaluated expression, defaults to false.\nfunc (p EvaluateOnCallFrameParams) WithIncludeCommandLineAPI(includeCommandLineAPI bool) *EvaluateOnCallFrameParams {\n\tp.IncludeCommandLineAPI = includeCommandLineAPI\n\treturn &p\n}\n\n// WithSilent in silent mode exceptions thrown during evaluation are not\n// reported and do not pause execution. Overrides setPauseOnException state.\nfunc (p EvaluateOnCallFrameParams) WithSilent(silent bool) *EvaluateOnCallFrameParams {\n\tp.Silent = silent\n\treturn &p\n}\n\n// WithReturnByValue whether the result is expected to be a JSON object that\n// should be sent by value.\nfunc (p EvaluateOnCallFrameParams) WithReturnByValue(returnByValue bool) *EvaluateOnCallFrameParams {\n\tp.ReturnByValue = returnByValue\n\treturn &p\n}\n\n// WithGeneratePreview whether preview should be generated for the result.\nfunc (p EvaluateOnCallFrameParams) WithGeneratePreview(generatePreview bool) *EvaluateOnCallFrameParams {\n\tp.GeneratePreview = generatePreview\n\treturn &p\n}\n\n// WithThrowOnSideEffect whether to throw an exception if side effect cannot\n// be ruled out during evaluation.\nfunc (p EvaluateOnCallFrameParams) WithThrowOnSideEffect(throwOnSideEffect bool) *EvaluateOnCallFrameParams {\n\tp.ThrowOnSideEffect = throwOnSideEffect\n\treturn &p\n}\n\n// WithTimeout terminate execution after timing out (number of milliseconds).\nfunc (p EvaluateOnCallFrameParams) WithTimeout(timeout runtime.TimeDelta) *EvaluateOnCallFrameParams {\n\tp.Timeout = timeout\n\treturn &p\n}\n\n// EvaluateOnCallFrameReturns return values.\ntype EvaluateOnCallFrameReturns struct {\n\tResult           *runtime.RemoteObject     `json:\"result,omitempty,omitzero\"`           // Object wrapper for the evaluation result.\n\tExceptionDetails *runtime.ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"` // Exception details.\n}\n\n// Do executes Debugger.evaluateOnCallFrame against the provided context.\n//\n// returns:\n//\n//\tresult - Object wrapper for the evaluation result.\n//\texceptionDetails - Exception details.\nfunc (p *EvaluateOnCallFrameParams) Do(ctx context.Context) (result *runtime.RemoteObject, exceptionDetails *runtime.ExceptionDetails, err error) {\n\t// execute\n\tvar res EvaluateOnCallFrameReturns\n\terr = cdp.Execute(ctx, CommandEvaluateOnCallFrame, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.Result, res.ExceptionDetails, nil\n}\n\n// GetPossibleBreakpointsParams returns possible locations for breakpoint.\n// scriptId in start and end range locations should be the same.\ntype GetPossibleBreakpointsParams struct {\n\tStart              *Location `json:\"start\"`                  // Start of range to search possible breakpoint locations in.\n\tEnd                *Location `json:\"end,omitempty,omitzero\"` // End of range to search possible breakpoint locations in (excluding). When not specified, end of scripts is used as end of range.\n\tRestrictToFunction bool      `json:\"restrictToFunction\"`     // Only consider locations which are in the same (non-nested) function as start.\n}\n\n// GetPossibleBreakpoints returns possible locations for breakpoint. scriptId\n// in start and end range locations should be the same.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-getPossibleBreakpoints\n//\n// parameters:\n//\n//\tstart - Start of range to search possible breakpoint locations in.\nfunc GetPossibleBreakpoints(start *Location) *GetPossibleBreakpointsParams {\n\treturn &GetPossibleBreakpointsParams{\n\t\tStart:              start,\n\t\tRestrictToFunction: false,\n\t}\n}\n\n// WithEnd end of range to search possible breakpoint locations in\n// (excluding). When not specified, end of scripts is used as end of range.\nfunc (p GetPossibleBreakpointsParams) WithEnd(end *Location) *GetPossibleBreakpointsParams {\n\tp.End = end\n\treturn &p\n}\n\n// WithRestrictToFunction only consider locations which are in the same\n// (non-nested) function as start.\nfunc (p GetPossibleBreakpointsParams) WithRestrictToFunction(restrictToFunction bool) *GetPossibleBreakpointsParams {\n\tp.RestrictToFunction = restrictToFunction\n\treturn &p\n}\n\n// GetPossibleBreakpointsReturns return values.\ntype GetPossibleBreakpointsReturns struct {\n\tLocations []*BreakLocation `json:\"locations,omitempty,omitzero\"` // List of the possible breakpoint locations.\n}\n\n// Do executes Debugger.getPossibleBreakpoints against the provided context.\n//\n// returns:\n//\n//\tlocations - List of the possible breakpoint locations.\nfunc (p *GetPossibleBreakpointsParams) Do(ctx context.Context) (locations []*BreakLocation, err error) {\n\t// execute\n\tvar res GetPossibleBreakpointsReturns\n\terr = cdp.Execute(ctx, CommandGetPossibleBreakpoints, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Locations, nil\n}\n\n// GetScriptSourceParams returns source for the script with given id.\ntype GetScriptSourceParams struct {\n\tScriptID runtime.ScriptID `json:\"scriptId\"` // Id of the script to get source for.\n}\n\n// GetScriptSource returns source for the script with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-getScriptSource\n//\n// parameters:\n//\n//\tscriptID - Id of the script to get source for.\nfunc GetScriptSource(scriptID runtime.ScriptID) *GetScriptSourceParams {\n\treturn &GetScriptSourceParams{\n\t\tScriptID: scriptID,\n\t}\n}\n\n// GetScriptSourceReturns return values.\ntype GetScriptSourceReturns struct {\n\tScriptSource string `json:\"scriptSource,omitempty,omitzero\"` // Script source (empty in case of Wasm bytecode).\n\tBytecode     string `json:\"bytecode,omitempty,omitzero\"`     // Wasm bytecode.\n}\n\n// Do executes Debugger.getScriptSource against the provided context.\n//\n// returns:\n//\n//\tscriptSource - Script source (empty in case of Wasm bytecode).\n//\tbytecode - Wasm bytecode.\nfunc (p *GetScriptSourceParams) Do(ctx context.Context) (scriptSource string, bytecode []byte, err error) {\n\t// execute\n\tvar res GetScriptSourceReturns\n\terr = cdp.Execute(ctx, CommandGetScriptSource, p, &res)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tdec, err = base64.StdEncoding.DecodeString(res.Bytecode)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\treturn res.ScriptSource, dec, nil\n}\n\n// DisassembleWasmModuleParams [no description].\ntype DisassembleWasmModuleParams struct {\n\tScriptID runtime.ScriptID `json:\"scriptId\"` // Id of the script to disassemble\n}\n\n// DisassembleWasmModule [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-disassembleWasmModule\n//\n// parameters:\n//\n//\tscriptID - Id of the script to disassemble\nfunc DisassembleWasmModule(scriptID runtime.ScriptID) *DisassembleWasmModuleParams {\n\treturn &DisassembleWasmModuleParams{\n\t\tScriptID: scriptID,\n\t}\n}\n\n// DisassembleWasmModuleReturns return values.\ntype DisassembleWasmModuleReturns struct {\n\tStreamID            string                `json:\"streamId,omitempty,omitzero\"`            // For large modules, return a stream from which additional chunks of disassembly can be read successively.\n\tTotalNumberOfLines  int64                 `json:\"totalNumberOfLines,omitempty,omitzero\"`  // The total number of lines in the disassembly text.\n\tFunctionBodyOffsets []int64               `json:\"functionBodyOffsets,omitempty,omitzero\"` // The offsets of all function bodies, in the format [start1, end1, start2, end2, ...] where all ends are exclusive.\n\tChunk               *WasmDisassemblyChunk `json:\"chunk,omitempty,omitzero\"`               // The first chunk of disassembly.\n}\n\n// Do executes Debugger.disassembleWasmModule against the provided context.\n//\n// returns:\n//\n//\tstreamID - For large modules, return a stream from which additional chunks of disassembly can be read successively.\n//\ttotalNumberOfLines - The total number of lines in the disassembly text.\n//\tfunctionBodyOffsets - The offsets of all function bodies, in the format [start1, end1, start2, end2, ...] where all ends are exclusive.\n//\tchunk - The first chunk of disassembly.\nfunc (p *DisassembleWasmModuleParams) Do(ctx context.Context) (streamID string, totalNumberOfLines int64, functionBodyOffsets []int64, chunk *WasmDisassemblyChunk, err error) {\n\t// execute\n\tvar res DisassembleWasmModuleReturns\n\terr = cdp.Execute(ctx, CommandDisassembleWasmModule, p, &res)\n\tif err != nil {\n\t\treturn \"\", 0, nil, nil, err\n\t}\n\n\treturn res.StreamID, res.TotalNumberOfLines, res.FunctionBodyOffsets, res.Chunk, nil\n}\n\n// NextWasmDisassemblyChunkParams disassemble the next chunk of lines for the\n// module corresponding to the stream. If disassembly is complete, this API will\n// invalidate the streamId and return an empty chunk. Any subsequent calls for\n// the now invalid stream will return errors.\ntype NextWasmDisassemblyChunkParams struct {\n\tStreamID string `json:\"streamId\"`\n}\n\n// NextWasmDisassemblyChunk disassemble the next chunk of lines for the\n// module corresponding to the stream. If disassembly is complete, this API will\n// invalidate the streamId and return an empty chunk. Any subsequent calls for\n// the now invalid stream will return errors.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-nextWasmDisassemblyChunk\n//\n// parameters:\n//\n//\tstreamID\nfunc NextWasmDisassemblyChunk(streamID string) *NextWasmDisassemblyChunkParams {\n\treturn &NextWasmDisassemblyChunkParams{\n\t\tStreamID: streamID,\n\t}\n}\n\n// NextWasmDisassemblyChunkReturns return values.\ntype NextWasmDisassemblyChunkReturns struct {\n\tChunk *WasmDisassemblyChunk `json:\"chunk,omitempty,omitzero\"` // The next chunk of disassembly.\n}\n\n// Do executes Debugger.nextWasmDisassemblyChunk against the provided context.\n//\n// returns:\n//\n//\tchunk - The next chunk of disassembly.\nfunc (p *NextWasmDisassemblyChunkParams) Do(ctx context.Context) (chunk *WasmDisassemblyChunk, err error) {\n\t// execute\n\tvar res NextWasmDisassemblyChunkReturns\n\terr = cdp.Execute(ctx, CommandNextWasmDisassemblyChunk, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Chunk, nil\n}\n\n// GetStackTraceParams returns stack trace with given stackTraceId.\ntype GetStackTraceParams struct {\n\tStackTraceID *runtime.StackTraceID `json:\"stackTraceId\"`\n}\n\n// GetStackTrace returns stack trace with given stackTraceId.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-getStackTrace\n//\n// parameters:\n//\n//\tstackTraceID\nfunc GetStackTrace(stackTraceID *runtime.StackTraceID) *GetStackTraceParams {\n\treturn &GetStackTraceParams{\n\t\tStackTraceID: stackTraceID,\n\t}\n}\n\n// GetStackTraceReturns return values.\ntype GetStackTraceReturns struct {\n\tStackTrace *runtime.StackTrace `json:\"stackTrace,omitempty,omitzero\"`\n}\n\n// Do executes Debugger.getStackTrace against the provided context.\n//\n// returns:\n//\n//\tstackTrace\nfunc (p *GetStackTraceParams) Do(ctx context.Context) (stackTrace *runtime.StackTrace, err error) {\n\t// execute\n\tvar res GetStackTraceReturns\n\terr = cdp.Execute(ctx, CommandGetStackTrace, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.StackTrace, nil\n}\n\n// PauseParams stops on the next JavaScript statement.\ntype PauseParams struct{}\n\n// Pause stops on the next JavaScript statement.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-pause\nfunc Pause() *PauseParams {\n\treturn &PauseParams{}\n}\n\n// Do executes Debugger.pause against the provided context.\nfunc (p *PauseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandPause, nil, nil)\n}\n\n// RemoveBreakpointParams removes JavaScript breakpoint.\ntype RemoveBreakpointParams struct {\n\tBreakpointID BreakpointID `json:\"breakpointId\"`\n}\n\n// RemoveBreakpoint removes JavaScript breakpoint.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-removeBreakpoint\n//\n// parameters:\n//\n//\tbreakpointID\nfunc RemoveBreakpoint(breakpointID BreakpointID) *RemoveBreakpointParams {\n\treturn &RemoveBreakpointParams{\n\t\tBreakpointID: breakpointID,\n\t}\n}\n\n// Do executes Debugger.removeBreakpoint against the provided context.\nfunc (p *RemoveBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveBreakpoint, p, nil)\n}\n\n// RestartFrameParams restarts particular call frame from the beginning. The\n// old, deprecated behavior of restartFrame is to stay paused and allow further\n// CDP commands after a restart was scheduled. This can cause problems with\n// restarting, so we now continue execution immediately after it has been\n// scheduled until we reach the beginning of the restarted frame. To stay\n// back-wards compatible, restartFrame now expects a mode parameter to be\n// present. If the mode parameter is missing, restartFrame errors out. The\n// various return values are deprecated and callFrames is always empty. Use the\n// call frames from the Debugger#paused events instead, that fires once V8\n// pauses at the beginning of the restarted function.\ntype RestartFrameParams struct {\n\tCallFrameID CallFrameID      `json:\"callFrameId\"`             // Call frame identifier to evaluate on.\n\tMode        RestartFrameMode `json:\"mode,omitempty,omitzero\"` // The mode parameter must be present and set to 'StepInto', otherwise restartFrame will error out.\n}\n\n// RestartFrame restarts particular call frame from the beginning. The old,\n// deprecated behavior of restartFrame is to stay paused and allow further CDP\n// commands after a restart was scheduled. This can cause problems with\n// restarting, so we now continue execution immediately after it has been\n// scheduled until we reach the beginning of the restarted frame. To stay\n// back-wards compatible, restartFrame now expects a mode parameter to be\n// present. If the mode parameter is missing, restartFrame errors out. The\n// various return values are deprecated and callFrames is always empty. Use the\n// call frames from the Debugger#paused events instead, that fires once V8\n// pauses at the beginning of the restarted function.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-restartFrame\n//\n// parameters:\n//\n//\tcallFrameID - Call frame identifier to evaluate on.\nfunc RestartFrame(callFrameID CallFrameID) *RestartFrameParams {\n\treturn &RestartFrameParams{\n\t\tCallFrameID: callFrameID,\n\t}\n}\n\n// WithMode the mode parameter must be present and set to 'StepInto',\n// otherwise restartFrame will error out.\nfunc (p RestartFrameParams) WithMode(mode RestartFrameMode) *RestartFrameParams {\n\tp.Mode = mode\n\treturn &p\n}\n\n// Do executes Debugger.restartFrame against the provided context.\nfunc (p *RestartFrameParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRestartFrame, p, nil)\n}\n\n// ResumeParams resumes JavaScript execution.\ntype ResumeParams struct {\n\tTerminateOnResume bool `json:\"terminateOnResume\"` // Set to true to terminate execution upon resuming execution. In contrast to Runtime.terminateExecution, this will allows to execute further JavaScript (i.e. via evaluation) until execution of the paused code is actually resumed, at which point termination is triggered. If execution is currently not paused, this parameter has no effect.\n}\n\n// Resume resumes JavaScript execution.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-resume\n//\n// parameters:\nfunc Resume() *ResumeParams {\n\treturn &ResumeParams{\n\t\tTerminateOnResume: false,\n\t}\n}\n\n// WithTerminateOnResume set to true to terminate execution upon resuming\n// execution. In contrast to Runtime.terminateExecution, this will allows to\n// execute further JavaScript (i.e. via evaluation) until execution of the\n// paused code is actually resumed, at which point termination is triggered. If\n// execution is currently not paused, this parameter has no effect.\nfunc (p ResumeParams) WithTerminateOnResume(terminateOnResume bool) *ResumeParams {\n\tp.TerminateOnResume = terminateOnResume\n\treturn &p\n}\n\n// Do executes Debugger.resume against the provided context.\nfunc (p *ResumeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandResume, p, nil)\n}\n\n// SearchInContentParams searches for given string in script content.\ntype SearchInContentParams struct {\n\tScriptID      runtime.ScriptID `json:\"scriptId\"`      // Id of the script to search in.\n\tQuery         string           `json:\"query\"`         // String to search for.\n\tCaseSensitive bool             `json:\"caseSensitive\"` // If true, search is case sensitive.\n\tIsRegex       bool             `json:\"isRegex\"`       // If true, treats string parameter as regex.\n}\n\n// SearchInContent searches for given string in script content.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-searchInContent\n//\n// parameters:\n//\n//\tscriptID - Id of the script to search in.\n//\tquery - String to search for.\nfunc SearchInContent(scriptID runtime.ScriptID, query string) *SearchInContentParams {\n\treturn &SearchInContentParams{\n\t\tScriptID:      scriptID,\n\t\tQuery:         query,\n\t\tCaseSensitive: false,\n\t\tIsRegex:       false,\n\t}\n}\n\n// WithCaseSensitive if true, search is case sensitive.\nfunc (p SearchInContentParams) WithCaseSensitive(caseSensitive bool) *SearchInContentParams {\n\tp.CaseSensitive = caseSensitive\n\treturn &p\n}\n\n// WithIsRegex if true, treats string parameter as regex.\nfunc (p SearchInContentParams) WithIsRegex(isRegex bool) *SearchInContentParams {\n\tp.IsRegex = isRegex\n\treturn &p\n}\n\n// SearchInContentReturns return values.\ntype SearchInContentReturns struct {\n\tResult []*SearchMatch `json:\"result,omitempty,omitzero\"` // List of search matches.\n}\n\n// Do executes Debugger.searchInContent against the provided context.\n//\n// returns:\n//\n//\tresult - List of search matches.\nfunc (p *SearchInContentParams) Do(ctx context.Context) (result []*SearchMatch, err error) {\n\t// execute\n\tvar res SearchInContentReturns\n\terr = cdp.Execute(ctx, CommandSearchInContent, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Result, nil\n}\n\n// SetAsyncCallStackDepthParams enables or disables async call stacks\n// tracking.\ntype SetAsyncCallStackDepthParams struct {\n\tMaxDepth int64 `json:\"maxDepth\"` // Maximum depth of async call stacks. Setting to 0 will effectively disable collecting async call stacks (default).\n}\n\n// SetAsyncCallStackDepth enables or disables async call stacks tracking.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setAsyncCallStackDepth\n//\n// parameters:\n//\n//\tmaxDepth - Maximum depth of async call stacks. Setting to 0 will effectively disable collecting async call stacks (default).\nfunc SetAsyncCallStackDepth(maxDepth int64) *SetAsyncCallStackDepthParams {\n\treturn &SetAsyncCallStackDepthParams{\n\t\tMaxDepth: maxDepth,\n\t}\n}\n\n// Do executes Debugger.setAsyncCallStackDepth against the provided context.\nfunc (p *SetAsyncCallStackDepthParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAsyncCallStackDepth, p, nil)\n}\n\n// SetBlackboxExecutionContextsParams replace previous blackbox execution\n// contexts with passed ones. Forces backend to skip stepping/pausing in scripts\n// in these execution contexts. VM will try to leave blackboxed script by\n// performing 'step in' several times, finally resorting to 'step out' if\n// unsuccessful.\ntype SetBlackboxExecutionContextsParams struct {\n\tUniqueIDs []string `json:\"uniqueIds\"` // Array of execution context unique ids for the debugger to ignore.\n}\n\n// SetBlackboxExecutionContexts replace previous blackbox execution contexts\n// with passed ones. Forces backend to skip stepping/pausing in scripts in these\n// execution contexts. VM will try to leave blackboxed script by performing\n// 'step in' several times, finally resorting to 'step out' if unsuccessful.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setBlackboxExecutionContexts\n//\n// parameters:\n//\n//\tuniqueIDs - Array of execution context unique ids for the debugger to ignore.\nfunc SetBlackboxExecutionContexts(uniqueIDs []string) *SetBlackboxExecutionContextsParams {\n\treturn &SetBlackboxExecutionContextsParams{\n\t\tUniqueIDs: uniqueIDs,\n\t}\n}\n\n// Do executes Debugger.setBlackboxExecutionContexts against the provided context.\nfunc (p *SetBlackboxExecutionContextsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBlackboxExecutionContexts, p, nil)\n}\n\n// SetBlackboxPatternsParams replace previous blackbox patterns with passed\n// ones. Forces backend to skip stepping/pausing in scripts with url matching\n// one of the patterns. VM will try to leave blackboxed script by performing\n// 'step in' several times, finally resorting to 'step out' if unsuccessful.\ntype SetBlackboxPatternsParams struct {\n\tPatterns      []string `json:\"patterns\"`      // Array of regexps that will be used to check script url for blackbox state.\n\tSkipAnonymous bool     `json:\"skipAnonymous\"` // If true, also ignore scripts with no source url.\n}\n\n// SetBlackboxPatterns replace previous blackbox patterns with passed ones.\n// Forces backend to skip stepping/pausing in scripts with url matching one of\n// the patterns. VM will try to leave blackboxed script by performing 'step in'\n// several times, finally resorting to 'step out' if unsuccessful.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setBlackboxPatterns\n//\n// parameters:\n//\n//\tpatterns - Array of regexps that will be used to check script url for blackbox state.\nfunc SetBlackboxPatterns(patterns []string) *SetBlackboxPatternsParams {\n\treturn &SetBlackboxPatternsParams{\n\t\tPatterns:      patterns,\n\t\tSkipAnonymous: false,\n\t}\n}\n\n// WithSkipAnonymous if true, also ignore scripts with no source url.\nfunc (p SetBlackboxPatternsParams) WithSkipAnonymous(skipAnonymous bool) *SetBlackboxPatternsParams {\n\tp.SkipAnonymous = skipAnonymous\n\treturn &p\n}\n\n// Do executes Debugger.setBlackboxPatterns against the provided context.\nfunc (p *SetBlackboxPatternsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBlackboxPatterns, p, nil)\n}\n\n// SetBlackboxedRangesParams makes backend skip steps in the script in\n// blackboxed ranges. VM will try leave blacklisted scripts by performing 'step\n// in' several times, finally resorting to 'step out' if unsuccessful. Positions\n// array contains positions where blackbox state is changed. First interval\n// isn't blackboxed. Array should be sorted.\ntype SetBlackboxedRangesParams struct {\n\tScriptID  runtime.ScriptID  `json:\"scriptId\"` // Id of the script.\n\tPositions []*ScriptPosition `json:\"positions\"`\n}\n\n// SetBlackboxedRanges makes backend skip steps in the script in blackboxed\n// ranges. VM will try leave blacklisted scripts by performing 'step in' several\n// times, finally resorting to 'step out' if unsuccessful. Positions array\n// contains positions where blackbox state is changed. First interval isn't\n// blackboxed. Array should be sorted.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setBlackboxedRanges\n//\n// parameters:\n//\n//\tscriptID - Id of the script.\n//\tpositions\nfunc SetBlackboxedRanges(scriptID runtime.ScriptID, positions []*ScriptPosition) *SetBlackboxedRangesParams {\n\treturn &SetBlackboxedRangesParams{\n\t\tScriptID:  scriptID,\n\t\tPositions: positions,\n\t}\n}\n\n// Do executes Debugger.setBlackboxedRanges against the provided context.\nfunc (p *SetBlackboxedRangesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBlackboxedRanges, p, nil)\n}\n\n// SetBreakpointParams sets JavaScript breakpoint at a given location.\ntype SetBreakpointParams struct {\n\tLocation  *Location `json:\"location\"`                     // Location to set breakpoint in.\n\tCondition string    `json:\"condition,omitempty,omitzero\"` // Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true.\n}\n\n// SetBreakpoint sets JavaScript breakpoint at a given location.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setBreakpoint\n//\n// parameters:\n//\n//\tlocation - Location to set breakpoint in.\nfunc SetBreakpoint(location *Location) *SetBreakpointParams {\n\treturn &SetBreakpointParams{\n\t\tLocation: location,\n\t}\n}\n\n// WithCondition expression to use as a breakpoint condition. When specified,\n// debugger will only stop on the breakpoint if this expression evaluates to\n// true.\nfunc (p SetBreakpointParams) WithCondition(condition string) *SetBreakpointParams {\n\tp.Condition = condition\n\treturn &p\n}\n\n// SetBreakpointReturns return values.\ntype SetBreakpointReturns struct {\n\tBreakpointID   BreakpointID `json:\"breakpointId,omitempty,omitzero\"`   // Id of the created breakpoint for further reference.\n\tActualLocation *Location    `json:\"actualLocation,omitempty,omitzero\"` // Location this breakpoint resolved into.\n}\n\n// Do executes Debugger.setBreakpoint against the provided context.\n//\n// returns:\n//\n//\tbreakpointID - Id of the created breakpoint for further reference.\n//\tactualLocation - Location this breakpoint resolved into.\nfunc (p *SetBreakpointParams) Do(ctx context.Context) (breakpointID BreakpointID, actualLocation *Location, err error) {\n\t// execute\n\tvar res SetBreakpointReturns\n\terr = cdp.Execute(ctx, CommandSetBreakpoint, p, &res)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\treturn res.BreakpointID, res.ActualLocation, nil\n}\n\n// SetInstrumentationBreakpointParams sets instrumentation breakpoint.\ntype SetInstrumentationBreakpointParams struct {\n\tInstrumentation SetInstrumentationBreakpointInstrumentation `json:\"instrumentation\"` // Instrumentation name.\n}\n\n// SetInstrumentationBreakpoint sets instrumentation breakpoint.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setInstrumentationBreakpoint\n//\n// parameters:\n//\n//\tinstrumentation - Instrumentation name.\nfunc SetInstrumentationBreakpoint(instrumentation SetInstrumentationBreakpointInstrumentation) *SetInstrumentationBreakpointParams {\n\treturn &SetInstrumentationBreakpointParams{\n\t\tInstrumentation: instrumentation,\n\t}\n}\n\n// SetInstrumentationBreakpointReturns return values.\ntype SetInstrumentationBreakpointReturns struct {\n\tBreakpointID BreakpointID `json:\"breakpointId,omitempty,omitzero\"` // Id of the created breakpoint for further reference.\n}\n\n// Do executes Debugger.setInstrumentationBreakpoint against the provided context.\n//\n// returns:\n//\n//\tbreakpointID - Id of the created breakpoint for further reference.\nfunc (p *SetInstrumentationBreakpointParams) Do(ctx context.Context) (breakpointID BreakpointID, err error) {\n\t// execute\n\tvar res SetInstrumentationBreakpointReturns\n\terr = cdp.Execute(ctx, CommandSetInstrumentationBreakpoint, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.BreakpointID, nil\n}\n\n// SetBreakpointByURLParams sets JavaScript breakpoint at given location\n// specified either by URL or URL regex. Once this command is issued, all\n// existing parsed scripts will have breakpoints resolved and returned in\n// locations property. Further matching script parsing will result in subsequent\n// breakpointResolved events issued. This logical breakpoint will survive page\n// reloads.\ntype SetBreakpointByURLParams struct {\n\tLineNumber   int64  `json:\"lineNumber\"`                      // Line number to set breakpoint at.\n\tURL          string `json:\"url,omitempty,omitzero\"`          // URL of the resources to set breakpoint on.\n\tURLRegex     string `json:\"urlRegex,omitempty,omitzero\"`     // Regex pattern for the URLs of the resources to set breakpoints on. Either url or urlRegex must be specified.\n\tScriptHash   string `json:\"scriptHash,omitempty,omitzero\"`   // Script hash of the resources to set breakpoint on.\n\tColumnNumber int64  `json:\"columnNumber,omitempty,omitzero\"` // Offset in the line to set breakpoint at.\n\tCondition    string `json:\"condition,omitempty,omitzero\"`    // Expression to use as a breakpoint condition. When specified, debugger will only stop on the breakpoint if this expression evaluates to true.\n}\n\n// SetBreakpointByURL sets JavaScript breakpoint at given location specified\n// either by URL or URL regex. Once this command is issued, all existing parsed\n// scripts will have breakpoints resolved and returned in locations property.\n// Further matching script parsing will result in subsequent breakpointResolved\n// events issued. This logical breakpoint will survive page reloads.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setBreakpointByUrl\n//\n// parameters:\n//\n//\tlineNumber - Line number to set breakpoint at.\nfunc SetBreakpointByURL(lineNumber int64) *SetBreakpointByURLParams {\n\treturn &SetBreakpointByURLParams{\n\t\tLineNumber: lineNumber,\n\t}\n}\n\n// WithURL URL of the resources to set breakpoint on.\nfunc (p SetBreakpointByURLParams) WithURL(url string) *SetBreakpointByURLParams {\n\tp.URL = url\n\treturn &p\n}\n\n// WithURLRegex regex pattern for the URLs of the resources to set\n// breakpoints on. Either url or urlRegex must be specified.\nfunc (p SetBreakpointByURLParams) WithURLRegex(urlRegex string) *SetBreakpointByURLParams {\n\tp.URLRegex = urlRegex\n\treturn &p\n}\n\n// WithScriptHash script hash of the resources to set breakpoint on.\nfunc (p SetBreakpointByURLParams) WithScriptHash(scriptHash string) *SetBreakpointByURLParams {\n\tp.ScriptHash = scriptHash\n\treturn &p\n}\n\n// WithColumnNumber offset in the line to set breakpoint at.\nfunc (p SetBreakpointByURLParams) WithColumnNumber(columnNumber int64) *SetBreakpointByURLParams {\n\tp.ColumnNumber = columnNumber\n\treturn &p\n}\n\n// WithCondition expression to use as a breakpoint condition. When specified,\n// debugger will only stop on the breakpoint if this expression evaluates to\n// true.\nfunc (p SetBreakpointByURLParams) WithCondition(condition string) *SetBreakpointByURLParams {\n\tp.Condition = condition\n\treturn &p\n}\n\n// SetBreakpointByURLReturns return values.\ntype SetBreakpointByURLReturns struct {\n\tBreakpointID BreakpointID `json:\"breakpointId,omitempty,omitzero\"` // Id of the created breakpoint for further reference.\n\tLocations    []*Location  `json:\"locations,omitempty,omitzero\"`    // List of the locations this breakpoint resolved into upon addition.\n}\n\n// Do executes Debugger.setBreakpointByUrl against the provided context.\n//\n// returns:\n//\n//\tbreakpointID - Id of the created breakpoint for further reference.\n//\tlocations - List of the locations this breakpoint resolved into upon addition.\nfunc (p *SetBreakpointByURLParams) Do(ctx context.Context) (breakpointID BreakpointID, locations []*Location, err error) {\n\t// execute\n\tvar res SetBreakpointByURLReturns\n\terr = cdp.Execute(ctx, CommandSetBreakpointByURL, p, &res)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\treturn res.BreakpointID, res.Locations, nil\n}\n\n// SetBreakpointOnFunctionCallParams sets JavaScript breakpoint before each\n// call to the given function. If another function was created from the same\n// source as a given one, calling it will also trigger the breakpoint.\ntype SetBreakpointOnFunctionCallParams struct {\n\tObjectID  runtime.RemoteObjectID `json:\"objectId\"`                     // Function object id.\n\tCondition string                 `json:\"condition,omitempty,omitzero\"` // Expression to use as a breakpoint condition. When specified, debugger will stop on the breakpoint if this expression evaluates to true.\n}\n\n// SetBreakpointOnFunctionCall sets JavaScript breakpoint before each call to\n// the given function. If another function was created from the same source as a\n// given one, calling it will also trigger the breakpoint.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setBreakpointOnFunctionCall\n//\n// parameters:\n//\n//\tobjectID - Function object id.\nfunc SetBreakpointOnFunctionCall(objectID runtime.RemoteObjectID) *SetBreakpointOnFunctionCallParams {\n\treturn &SetBreakpointOnFunctionCallParams{\n\t\tObjectID: objectID,\n\t}\n}\n\n// WithCondition expression to use as a breakpoint condition. When specified,\n// debugger will stop on the breakpoint if this expression evaluates to true.\nfunc (p SetBreakpointOnFunctionCallParams) WithCondition(condition string) *SetBreakpointOnFunctionCallParams {\n\tp.Condition = condition\n\treturn &p\n}\n\n// SetBreakpointOnFunctionCallReturns return values.\ntype SetBreakpointOnFunctionCallReturns struct {\n\tBreakpointID BreakpointID `json:\"breakpointId,omitempty,omitzero\"` // Id of the created breakpoint for further reference.\n}\n\n// Do executes Debugger.setBreakpointOnFunctionCall against the provided context.\n//\n// returns:\n//\n//\tbreakpointID - Id of the created breakpoint for further reference.\nfunc (p *SetBreakpointOnFunctionCallParams) Do(ctx context.Context) (breakpointID BreakpointID, err error) {\n\t// execute\n\tvar res SetBreakpointOnFunctionCallReturns\n\terr = cdp.Execute(ctx, CommandSetBreakpointOnFunctionCall, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.BreakpointID, nil\n}\n\n// SetBreakpointsActiveParams activates / deactivates all breakpoints on the\n// page.\ntype SetBreakpointsActiveParams struct {\n\tActive bool `json:\"active\"` // New value for breakpoints active state.\n}\n\n// SetBreakpointsActive activates / deactivates all breakpoints on the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setBreakpointsActive\n//\n// parameters:\n//\n//\tactive - New value for breakpoints active state.\nfunc SetBreakpointsActive(active bool) *SetBreakpointsActiveParams {\n\treturn &SetBreakpointsActiveParams{\n\t\tActive: active,\n\t}\n}\n\n// Do executes Debugger.setBreakpointsActive against the provided context.\nfunc (p *SetBreakpointsActiveParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBreakpointsActive, p, nil)\n}\n\n// SetPauseOnExceptionsParams defines pause on exceptions state. Can be set\n// to stop on all exceptions, uncaught exceptions, or caught exceptions, no\n// exceptions. Initial pause on exceptions state is none.\ntype SetPauseOnExceptionsParams struct {\n\tState ExceptionsState `json:\"state\"` // Pause on exceptions mode.\n}\n\n// SetPauseOnExceptions defines pause on exceptions state. Can be set to stop\n// on all exceptions, uncaught exceptions, or caught exceptions, no exceptions.\n// Initial pause on exceptions state is none.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setPauseOnExceptions\n//\n// parameters:\n//\n//\tstate - Pause on exceptions mode.\nfunc SetPauseOnExceptions(state ExceptionsState) *SetPauseOnExceptionsParams {\n\treturn &SetPauseOnExceptionsParams{\n\t\tState: state,\n\t}\n}\n\n// Do executes Debugger.setPauseOnExceptions against the provided context.\nfunc (p *SetPauseOnExceptionsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPauseOnExceptions, p, nil)\n}\n\n// SetReturnValueParams changes return value in top frame. Available only at\n// return break position.\ntype SetReturnValueParams struct {\n\tNewValue *runtime.CallArgument `json:\"newValue\"` // New return value.\n}\n\n// SetReturnValue changes return value in top frame. Available only at return\n// break position.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setReturnValue\n//\n// parameters:\n//\n//\tnewValue - New return value.\nfunc SetReturnValue(newValue *runtime.CallArgument) *SetReturnValueParams {\n\treturn &SetReturnValueParams{\n\t\tNewValue: newValue,\n\t}\n}\n\n// Do executes Debugger.setReturnValue against the provided context.\nfunc (p *SetReturnValueParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetReturnValue, p, nil)\n}\n\n// SetScriptSourceParams edits JavaScript source live. In general, functions\n// that are currently on the stack can not be edited with a single exception: If\n// the edited function is the top-most stack frame and that is the only\n// activation of that function on the stack. In this case the live edit will be\n// successful and a Debugger.restartFrame for the top-most function is\n// automatically triggered.\ntype SetScriptSourceParams struct {\n\tScriptID             runtime.ScriptID `json:\"scriptId\"`             // Id of the script to edit.\n\tScriptSource         string           `json:\"scriptSource\"`         // New content of the script.\n\tDryRun               bool             `json:\"dryRun\"`               // If true the change will not actually be applied. Dry run may be used to get result description without actually modifying the code.\n\tAllowTopFrameEditing bool             `json:\"allowTopFrameEditing\"` // If true, then scriptSource is allowed to change the function on top of the stack as long as the top-most stack frame is the only activation of that function.\n}\n\n// SetScriptSource edits JavaScript source live. In general, functions that\n// are currently on the stack can not be edited with a single exception: If the\n// edited function is the top-most stack frame and that is the only activation\n// of that function on the stack. In this case the live edit will be successful\n// and a Debugger.restartFrame for the top-most function is automatically\n// triggered.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setScriptSource\n//\n// parameters:\n//\n//\tscriptID - Id of the script to edit.\n//\tscriptSource - New content of the script.\nfunc SetScriptSource(scriptID runtime.ScriptID, scriptSource string) *SetScriptSourceParams {\n\treturn &SetScriptSourceParams{\n\t\tScriptID:             scriptID,\n\t\tScriptSource:         scriptSource,\n\t\tDryRun:               false,\n\t\tAllowTopFrameEditing: false,\n\t}\n}\n\n// WithDryRun if true the change will not actually be applied. Dry run may be\n// used to get result description without actually modifying the code.\nfunc (p SetScriptSourceParams) WithDryRun(dryRun bool) *SetScriptSourceParams {\n\tp.DryRun = dryRun\n\treturn &p\n}\n\n// WithAllowTopFrameEditing if true, then scriptSource is allowed to change\n// the function on top of the stack as long as the top-most stack frame is the\n// only activation of that function.\nfunc (p SetScriptSourceParams) WithAllowTopFrameEditing(allowTopFrameEditing bool) *SetScriptSourceParams {\n\tp.AllowTopFrameEditing = allowTopFrameEditing\n\treturn &p\n}\n\n// SetScriptSourceReturns return values.\ntype SetScriptSourceReturns struct {\n\tStatus           SetScriptSourceStatus     `json:\"status,omitempty,omitzero\"`           // Whether the operation was successful or not. Only Ok denotes a successful live edit while the other enum variants denote why the live edit failed.\n\tExceptionDetails *runtime.ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"` // Exception details if any. Only present when status is CompileError.\n}\n\n// Do executes Debugger.setScriptSource against the provided context.\n//\n// returns:\n//\n//\tstatus - Whether the operation was successful or not. Only Ok denotes a successful live edit while the other enum variants denote why the live edit failed.\n//\texceptionDetails - Exception details if any. Only present when status is CompileError.\nfunc (p *SetScriptSourceParams) Do(ctx context.Context) (status SetScriptSourceStatus, exceptionDetails *runtime.ExceptionDetails, err error) {\n\t// execute\n\tvar res SetScriptSourceReturns\n\terr = cdp.Execute(ctx, CommandSetScriptSource, p, &res)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\treturn res.Status, res.ExceptionDetails, nil\n}\n\n// SetSkipAllPausesParams makes page not interrupt on any pauses (breakpoint,\n// exception, dom exception etc).\ntype SetSkipAllPausesParams struct {\n\tSkip bool `json:\"skip\"` // New value for skip pauses state.\n}\n\n// SetSkipAllPauses makes page not interrupt on any pauses (breakpoint,\n// exception, dom exception etc).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setSkipAllPauses\n//\n// parameters:\n//\n//\tskip - New value for skip pauses state.\nfunc SetSkipAllPauses(skip bool) *SetSkipAllPausesParams {\n\treturn &SetSkipAllPausesParams{\n\t\tSkip: skip,\n\t}\n}\n\n// Do executes Debugger.setSkipAllPauses against the provided context.\nfunc (p *SetSkipAllPausesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSkipAllPauses, p, nil)\n}\n\n// SetVariableValueParams changes value of variable in a callframe.\n// Object-based scopes are not supported and must be mutated manually.\ntype SetVariableValueParams struct {\n\tScopeNumber  int64                 `json:\"scopeNumber\"`  // 0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually.\n\tVariableName string                `json:\"variableName\"` // Variable name.\n\tNewValue     *runtime.CallArgument `json:\"newValue\"`     // New variable value.\n\tCallFrameID  CallFrameID           `json:\"callFrameId\"`  // Id of callframe that holds variable.\n}\n\n// SetVariableValue changes value of variable in a callframe. Object-based\n// scopes are not supported and must be mutated manually.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setVariableValue\n//\n// parameters:\n//\n//\tscopeNumber - 0-based number of scope as was listed in scope chain. Only 'local', 'closure' and 'catch' scope types are allowed. Other scopes could be manipulated manually.\n//\tvariableName - Variable name.\n//\tnewValue - New variable value.\n//\tcallFrameID - Id of callframe that holds variable.\nfunc SetVariableValue(scopeNumber int64, variableName string, newValue *runtime.CallArgument, callFrameID CallFrameID) *SetVariableValueParams {\n\treturn &SetVariableValueParams{\n\t\tScopeNumber:  scopeNumber,\n\t\tVariableName: variableName,\n\t\tNewValue:     newValue,\n\t\tCallFrameID:  callFrameID,\n\t}\n}\n\n// Do executes Debugger.setVariableValue against the provided context.\nfunc (p *SetVariableValueParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetVariableValue, p, nil)\n}\n\n// StepIntoParams steps into the function call.\ntype StepIntoParams struct {\n\tBreakOnAsyncCall bool             `json:\"breakOnAsyncCall\"`            // Debugger will pause on the execution of the first async task which was scheduled before next pause.\n\tSkipList         []*LocationRange `json:\"skipList,omitempty,omitzero\"` // The skipList specifies location ranges that should be skipped on step into.\n}\n\n// StepInto steps into the function call.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-stepInto\n//\n// parameters:\nfunc StepInto() *StepIntoParams {\n\treturn &StepIntoParams{\n\t\tBreakOnAsyncCall: false,\n\t}\n}\n\n// WithBreakOnAsyncCall debugger will pause on the execution of the first\n// async task which was scheduled before next pause.\nfunc (p StepIntoParams) WithBreakOnAsyncCall(breakOnAsyncCall bool) *StepIntoParams {\n\tp.BreakOnAsyncCall = breakOnAsyncCall\n\treturn &p\n}\n\n// WithSkipList the skipList specifies location ranges that should be skipped\n// on step into.\nfunc (p StepIntoParams) WithSkipList(skipList []*LocationRange) *StepIntoParams {\n\tp.SkipList = skipList\n\treturn &p\n}\n\n// Do executes Debugger.stepInto against the provided context.\nfunc (p *StepIntoParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStepInto, p, nil)\n}\n\n// StepOutParams steps out of the function call.\ntype StepOutParams struct{}\n\n// StepOut steps out of the function call.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-stepOut\nfunc StepOut() *StepOutParams {\n\treturn &StepOutParams{}\n}\n\n// Do executes Debugger.stepOut against the provided context.\nfunc (p *StepOutParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStepOut, nil, nil)\n}\n\n// StepOverParams steps over the statement.\ntype StepOverParams struct {\n\tSkipList []*LocationRange `json:\"skipList,omitempty,omitzero\"` // The skipList specifies location ranges that should be skipped on step over.\n}\n\n// StepOver steps over the statement.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-stepOver\n//\n// parameters:\nfunc StepOver() *StepOverParams {\n\treturn &StepOverParams{}\n}\n\n// WithSkipList the skipList specifies location ranges that should be skipped\n// on step over.\nfunc (p StepOverParams) WithSkipList(skipList []*LocationRange) *StepOverParams {\n\tp.SkipList = skipList\n\treturn &p\n}\n\n// Do executes Debugger.stepOver against the provided context.\nfunc (p *StepOverParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStepOver, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandContinueToLocation           = \"Debugger.continueToLocation\"\n\tCommandDisable                      = \"Debugger.disable\"\n\tCommandEnable                       = \"Debugger.enable\"\n\tCommandEvaluateOnCallFrame          = \"Debugger.evaluateOnCallFrame\"\n\tCommandGetPossibleBreakpoints       = \"Debugger.getPossibleBreakpoints\"\n\tCommandGetScriptSource              = \"Debugger.getScriptSource\"\n\tCommandDisassembleWasmModule        = \"Debugger.disassembleWasmModule\"\n\tCommandNextWasmDisassemblyChunk     = \"Debugger.nextWasmDisassemblyChunk\"\n\tCommandGetStackTrace                = \"Debugger.getStackTrace\"\n\tCommandPause                        = \"Debugger.pause\"\n\tCommandRemoveBreakpoint             = \"Debugger.removeBreakpoint\"\n\tCommandRestartFrame                 = \"Debugger.restartFrame\"\n\tCommandResume                       = \"Debugger.resume\"\n\tCommandSearchInContent              = \"Debugger.searchInContent\"\n\tCommandSetAsyncCallStackDepth       = \"Debugger.setAsyncCallStackDepth\"\n\tCommandSetBlackboxExecutionContexts = \"Debugger.setBlackboxExecutionContexts\"\n\tCommandSetBlackboxPatterns          = \"Debugger.setBlackboxPatterns\"\n\tCommandSetBlackboxedRanges          = \"Debugger.setBlackboxedRanges\"\n\tCommandSetBreakpoint                = \"Debugger.setBreakpoint\"\n\tCommandSetInstrumentationBreakpoint = \"Debugger.setInstrumentationBreakpoint\"\n\tCommandSetBreakpointByURL           = \"Debugger.setBreakpointByUrl\"\n\tCommandSetBreakpointOnFunctionCall  = \"Debugger.setBreakpointOnFunctionCall\"\n\tCommandSetBreakpointsActive         = \"Debugger.setBreakpointsActive\"\n\tCommandSetPauseOnExceptions         = \"Debugger.setPauseOnExceptions\"\n\tCommandSetReturnValue               = \"Debugger.setReturnValue\"\n\tCommandSetScriptSource              = \"Debugger.setScriptSource\"\n\tCommandSetSkipAllPauses             = \"Debugger.setSkipAllPauses\"\n\tCommandSetVariableValue             = \"Debugger.setVariableValue\"\n\tCommandStepInto                     = \"Debugger.stepInto\"\n\tCommandStepOut                      = \"Debugger.stepOut\"\n\tCommandStepOver                     = \"Debugger.stepOver\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/debugger/events.go",
    "content": "package debugger\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// EventPaused fired when the virtual machine stopped on breakpoint or\n// exception or any other stop criteria.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#event-paused\ntype EventPaused struct {\n\tCallFrames        []*CallFrame          `json:\"callFrames\"` // Call stack the virtual machine stopped on.\n\tReason            PausedReason          `json:\"reason\"`     // Pause reason.\n\tData              jsontext.Value        `json:\"data,omitempty,omitzero\"`\n\tHitBreakpoints    []string              `json:\"hitBreakpoints,omitempty,omitzero\"`    // Hit breakpoints IDs\n\tAsyncStackTrace   *runtime.StackTrace   `json:\"asyncStackTrace,omitempty,omitzero\"`   // Async stack trace, if any.\n\tAsyncStackTraceID *runtime.StackTraceID `json:\"asyncStackTraceId,omitempty,omitzero\"` // Async stack trace, if any.\n}\n\n// EventResumed fired when the virtual machine resumed execution.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#event-resumed\ntype EventResumed struct{}\n\n// EventScriptFailedToParse fired when virtual machine fails to parse the\n// script.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#event-scriptFailedToParse\ntype EventScriptFailedToParse struct {\n\tScriptID                runtime.ScriptID           `json:\"scriptId\"`           // Identifier of the script parsed.\n\tURL                     string                     `json:\"url\"`                // URL or name of the script parsed (if any).\n\tStartLine               int64                      `json:\"startLine\"`          // Line offset of the script within the resource with given URL (for script tags).\n\tStartColumn             int64                      `json:\"startColumn\"`        // Column offset of the script within the resource with given URL.\n\tEndLine                 int64                      `json:\"endLine\"`            // Last line of the script.\n\tEndColumn               int64                      `json:\"endColumn\"`          // Length of the last line of the script.\n\tExecutionContextID      runtime.ExecutionContextID `json:\"executionContextId\"` // Specifies script creation context.\n\tHash                    string                     `json:\"hash\"`               // Content hash of the script, SHA-256.\n\tBuildID                 string                     `json:\"buildId\"`            // For Wasm modules, the content of the build_id custom section. For JavaScript the debugId magic comment.\n\tExecutionContextAuxData jsontext.Value             `json:\"executionContextAuxData,omitempty,omitzero\"`\n\tSourceMapURL            string                     `json:\"sourceMapURL,omitempty,omitzero\"`   // URL of source map associated with script (if any).\n\tHasSourceURL            bool                       `json:\"hasSourceURL\"`                      // True, if this script has sourceURL.\n\tIsModule                bool                       `json:\"isModule\"`                          // True, if this script is ES6 module.\n\tLength                  int64                      `json:\"length,omitempty,omitzero\"`         // This script length.\n\tStackTrace              *runtime.StackTrace        `json:\"stackTrace,omitempty,omitzero\"`     // JavaScript top stack frame of where the script parsed event was triggered if available.\n\tCodeOffset              int64                      `json:\"codeOffset,omitempty,omitzero\"`     // If the scriptLanguage is WebAssembly, the code section offset in the module.\n\tScriptLanguage          ScriptLanguage             `json:\"scriptLanguage,omitempty,omitzero\"` // The language of the script.\n\tEmbedderName            string                     `json:\"embedderName,omitempty,omitzero\"`   // The name the embedder supplied for this script.\n}\n\n// EventScriptParsed fired when virtual machine parses script. This event is\n// also fired for all known and uncollected scripts upon enabling debugger.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#event-scriptParsed\ntype EventScriptParsed struct {\n\tScriptID                runtime.ScriptID           `json:\"scriptId\"`           // Identifier of the script parsed.\n\tURL                     string                     `json:\"url\"`                // URL or name of the script parsed (if any).\n\tStartLine               int64                      `json:\"startLine\"`          // Line offset of the script within the resource with given URL (for script tags).\n\tStartColumn             int64                      `json:\"startColumn\"`        // Column offset of the script within the resource with given URL.\n\tEndLine                 int64                      `json:\"endLine\"`            // Last line of the script.\n\tEndColumn               int64                      `json:\"endColumn\"`          // Length of the last line of the script.\n\tExecutionContextID      runtime.ExecutionContextID `json:\"executionContextId\"` // Specifies script creation context.\n\tHash                    string                     `json:\"hash\"`               // Content hash of the script, SHA-256.\n\tBuildID                 string                     `json:\"buildId\"`            // For Wasm modules, the content of the build_id custom section. For JavaScript the debugId magic comment.\n\tExecutionContextAuxData jsontext.Value             `json:\"executionContextAuxData,omitempty,omitzero\"`\n\tIsLiveEdit              bool                       `json:\"isLiveEdit\"`                             // True, if this script is generated as a result of the live edit operation.\n\tSourceMapURL            string                     `json:\"sourceMapURL,omitempty,omitzero\"`        // URL of source map associated with script (if any).\n\tHasSourceURL            bool                       `json:\"hasSourceURL\"`                           // True, if this script has sourceURL.\n\tIsModule                bool                       `json:\"isModule\"`                               // True, if this script is ES6 module.\n\tLength                  int64                      `json:\"length,omitempty,omitzero\"`              // This script length.\n\tStackTrace              *runtime.StackTrace        `json:\"stackTrace,omitempty,omitzero\"`          // JavaScript top stack frame of where the script parsed event was triggered if available.\n\tCodeOffset              int64                      `json:\"codeOffset,omitempty,omitzero\"`          // If the scriptLanguage is WebAssembly, the code section offset in the module.\n\tScriptLanguage          ScriptLanguage             `json:\"scriptLanguage,omitempty,omitzero\"`      // The language of the script.\n\tDebugSymbols            []*DebugSymbols            `json:\"debugSymbols,omitempty,omitzero\"`        // If the scriptLanguage is WebAssembly, the source of debug symbols for the module.\n\tEmbedderName            string                     `json:\"embedderName,omitempty,omitzero\"`        // The name the embedder supplied for this script.\n\tResolvedBreakpoints     []*ResolvedBreakpoint      `json:\"resolvedBreakpoints,omitempty,omitzero\"` // The list of set breakpoints in this script if calls to setBreakpointByUrl matches this script's URL or hash. Clients that use this list can ignore the breakpointResolved event. They are equivalent.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/debugger/types.go",
    "content": "package debugger\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// BreakpointID breakpoint identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-BreakpointId\ntype BreakpointID string\n\n// String returns the BreakpointID as string value.\nfunc (t BreakpointID) String() string {\n\treturn string(t)\n}\n\n// CallFrameID call frame identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-CallFrameId\ntype CallFrameID string\n\n// String returns the CallFrameID as string value.\nfunc (t CallFrameID) String() string {\n\treturn string(t)\n}\n\n// Location location in the source code.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-Location\ntype Location struct {\n\tScriptID     runtime.ScriptID `json:\"scriptId\"`                        // Script identifier as reported in the Debugger.scriptParsed.\n\tLineNumber   int64            `json:\"lineNumber\"`                      // Line number in the script (0-based).\n\tColumnNumber int64            `json:\"columnNumber,omitempty,omitzero\"` // Column number in the script (0-based).\n}\n\n// ScriptPosition location in the source code.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-ScriptPosition\ntype ScriptPosition struct {\n\tLineNumber   int64 `json:\"lineNumber\"`\n\tColumnNumber int64 `json:\"columnNumber\"`\n}\n\n// LocationRange location range within one script.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-LocationRange\ntype LocationRange struct {\n\tScriptID runtime.ScriptID `json:\"scriptId\"`\n\tStart    *ScriptPosition  `json:\"start\"`\n\tEnd      *ScriptPosition  `json:\"end\"`\n}\n\n// CallFrame JavaScript call frame. Array of call frames form the call stack.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-CallFrame\ntype CallFrame struct {\n\tCallFrameID      CallFrameID           `json:\"callFrameId\"`                         // Call frame identifier. This identifier is only valid while the virtual machine is paused.\n\tFunctionName     string                `json:\"functionName\"`                        // Name of the JavaScript function called on this call frame.\n\tFunctionLocation *Location             `json:\"functionLocation,omitempty,omitzero\"` // Location in the source code.\n\tLocation         *Location             `json:\"location\"`                            // Location in the source code.\n\tScopeChain       []*Scope              `json:\"scopeChain\"`                          // Scope chain for this call frame.\n\tThis             *runtime.RemoteObject `json:\"this\"`                                // this object for this call frame.\n\tReturnValue      *runtime.RemoteObject `json:\"returnValue,omitempty,omitzero\"`      // The value being returned, if the function is at return point.\n\tCanBeRestarted   bool                  `json:\"canBeRestarted\"`                      // Valid only while the VM is paused and indicates whether this frame can be restarted or not. Note that a true value here does not guarantee that Debugger#restartFrame with this CallFrameId will be successful, but it is very likely.\n}\n\n// Scope scope description.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-Scope\ntype Scope struct {\n\tType          ScopeType             `json:\"type\"`   // Scope type.\n\tObject        *runtime.RemoteObject `json:\"object\"` // Object representing the scope. For global and with scopes it represents the actual object; for the rest of the scopes, it is artificial transient object enumerating scope variables as its properties.\n\tName          string                `json:\"name,omitempty,omitzero\"`\n\tStartLocation *Location             `json:\"startLocation,omitempty,omitzero\"` // Location in the source code where scope starts\n\tEndLocation   *Location             `json:\"endLocation,omitempty,omitzero\"`   // Location in the source code where scope ends\n}\n\n// SearchMatch search match for resource.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-SearchMatch\ntype SearchMatch struct {\n\tLineNumber  float64 `json:\"lineNumber\"`  // Line number in resource content.\n\tLineContent string  `json:\"lineContent\"` // Line with match content.\n}\n\n// BreakLocation [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-BreakLocation\ntype BreakLocation struct {\n\tScriptID     runtime.ScriptID  `json:\"scriptId\"`                        // Script identifier as reported in the Debugger.scriptParsed.\n\tLineNumber   int64             `json:\"lineNumber\"`                      // Line number in the script (0-based).\n\tColumnNumber int64             `json:\"columnNumber,omitempty,omitzero\"` // Column number in the script (0-based).\n\tType         BreakLocationType `json:\"type,omitempty,omitzero\"`\n}\n\n// WasmDisassemblyChunk [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-WasmDisassemblyChunk\ntype WasmDisassemblyChunk struct {\n\tLines           []string `json:\"lines\"`           // The next chunk of disassembled lines.\n\tBytecodeOffsets []int64  `json:\"bytecodeOffsets\"` // The bytecode offsets describing the start of each line.\n}\n\n// ScriptLanguage enum of possible script languages.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-ScriptLanguage\ntype ScriptLanguage string\n\n// String returns the ScriptLanguage as string value.\nfunc (t ScriptLanguage) String() string {\n\treturn string(t)\n}\n\n// ScriptLanguage values.\nconst (\n\tScriptLanguageJavaScript  ScriptLanguage = \"JavaScript\"\n\tScriptLanguageWebAssembly ScriptLanguage = \"WebAssembly\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ScriptLanguage) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ScriptLanguage(s) {\n\tcase ScriptLanguageJavaScript:\n\t\t*t = ScriptLanguageJavaScript\n\tcase ScriptLanguageWebAssembly:\n\t\t*t = ScriptLanguageWebAssembly\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ScriptLanguage value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DebugSymbols debug symbols available for a wasm script.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-DebugSymbols\ntype DebugSymbols struct {\n\tType        DebugSymbolsType `json:\"type\"`                           // Type of the debug symbols.\n\tExternalURL string           `json:\"externalURL,omitempty,omitzero\"` // URL of the external symbol source.\n}\n\n// ResolvedBreakpoint [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-ResolvedBreakpoint\ntype ResolvedBreakpoint struct {\n\tBreakpointID BreakpointID `json:\"breakpointId\"` // Breakpoint unique identifier.\n\tLocation     *Location    `json:\"location\"`     // Actual breakpoint location.\n}\n\n// ScopeType scope type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-Scope\ntype ScopeType string\n\n// String returns the ScopeType as string value.\nfunc (t ScopeType) String() string {\n\treturn string(t)\n}\n\n// ScopeType values.\nconst (\n\tScopeTypeGlobal              ScopeType = \"global\"\n\tScopeTypeLocal               ScopeType = \"local\"\n\tScopeTypeWith                ScopeType = \"with\"\n\tScopeTypeClosure             ScopeType = \"closure\"\n\tScopeTypeCatch               ScopeType = \"catch\"\n\tScopeTypeBlock               ScopeType = \"block\"\n\tScopeTypeScript              ScopeType = \"script\"\n\tScopeTypeEval                ScopeType = \"eval\"\n\tScopeTypeModule              ScopeType = \"module\"\n\tScopeTypeWasmExpressionStack ScopeType = \"wasm-expression-stack\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ScopeType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ScopeType(s) {\n\tcase ScopeTypeGlobal:\n\t\t*t = ScopeTypeGlobal\n\tcase ScopeTypeLocal:\n\t\t*t = ScopeTypeLocal\n\tcase ScopeTypeWith:\n\t\t*t = ScopeTypeWith\n\tcase ScopeTypeClosure:\n\t\t*t = ScopeTypeClosure\n\tcase ScopeTypeCatch:\n\t\t*t = ScopeTypeCatch\n\tcase ScopeTypeBlock:\n\t\t*t = ScopeTypeBlock\n\tcase ScopeTypeScript:\n\t\t*t = ScopeTypeScript\n\tcase ScopeTypeEval:\n\t\t*t = ScopeTypeEval\n\tcase ScopeTypeModule:\n\t\t*t = ScopeTypeModule\n\tcase ScopeTypeWasmExpressionStack:\n\t\t*t = ScopeTypeWasmExpressionStack\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ScopeType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// BreakLocationType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-BreakLocation\ntype BreakLocationType string\n\n// String returns the BreakLocationType as string value.\nfunc (t BreakLocationType) String() string {\n\treturn string(t)\n}\n\n// BreakLocationType values.\nconst (\n\tBreakLocationTypeDebuggerStatement BreakLocationType = \"debuggerStatement\"\n\tBreakLocationTypeCall              BreakLocationType = \"call\"\n\tBreakLocationTypeReturn            BreakLocationType = \"return\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *BreakLocationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch BreakLocationType(s) {\n\tcase BreakLocationTypeDebuggerStatement:\n\t\t*t = BreakLocationTypeDebuggerStatement\n\tcase BreakLocationTypeCall:\n\t\t*t = BreakLocationTypeCall\n\tcase BreakLocationTypeReturn:\n\t\t*t = BreakLocationTypeReturn\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown BreakLocationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DebugSymbolsType type of the debug symbols.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#type-DebugSymbols\ntype DebugSymbolsType string\n\n// String returns the DebugSymbolsType as string value.\nfunc (t DebugSymbolsType) String() string {\n\treturn string(t)\n}\n\n// DebugSymbolsType values.\nconst (\n\tDebugSymbolsTypeSourceMap     DebugSymbolsType = \"SourceMap\"\n\tDebugSymbolsTypeEmbeddedDWARF DebugSymbolsType = \"EmbeddedDWARF\"\n\tDebugSymbolsTypeExternalDWARF DebugSymbolsType = \"ExternalDWARF\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DebugSymbolsType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DebugSymbolsType(s) {\n\tcase DebugSymbolsTypeSourceMap:\n\t\t*t = DebugSymbolsTypeSourceMap\n\tcase DebugSymbolsTypeEmbeddedDWARF:\n\t\t*t = DebugSymbolsTypeEmbeddedDWARF\n\tcase DebugSymbolsTypeExternalDWARF:\n\t\t*t = DebugSymbolsTypeExternalDWARF\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DebugSymbolsType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PausedReason pause reason.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#event-paused\ntype PausedReason string\n\n// String returns the PausedReason as string value.\nfunc (t PausedReason) String() string {\n\treturn string(t)\n}\n\n// PausedReason values.\nconst (\n\tPausedReasonAmbiguous        PausedReason = \"ambiguous\"\n\tPausedReasonAssert           PausedReason = \"assert\"\n\tPausedReasonCSPViolation     PausedReason = \"CSPViolation\"\n\tPausedReasonDebugCommand     PausedReason = \"debugCommand\"\n\tPausedReasonDOM              PausedReason = \"DOM\"\n\tPausedReasonEventListener    PausedReason = \"EventListener\"\n\tPausedReasonException        PausedReason = \"exception\"\n\tPausedReasonInstrumentation  PausedReason = \"instrumentation\"\n\tPausedReasonOOM              PausedReason = \"OOM\"\n\tPausedReasonOther            PausedReason = \"other\"\n\tPausedReasonPromiseRejection PausedReason = \"promiseRejection\"\n\tPausedReasonXHR              PausedReason = \"XHR\"\n\tPausedReasonStep             PausedReason = \"step\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PausedReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PausedReason(s) {\n\tcase PausedReasonAmbiguous:\n\t\t*t = PausedReasonAmbiguous\n\tcase PausedReasonAssert:\n\t\t*t = PausedReasonAssert\n\tcase PausedReasonCSPViolation:\n\t\t*t = PausedReasonCSPViolation\n\tcase PausedReasonDebugCommand:\n\t\t*t = PausedReasonDebugCommand\n\tcase PausedReasonDOM:\n\t\t*t = PausedReasonDOM\n\tcase PausedReasonEventListener:\n\t\t*t = PausedReasonEventListener\n\tcase PausedReasonException:\n\t\t*t = PausedReasonException\n\tcase PausedReasonInstrumentation:\n\t\t*t = PausedReasonInstrumentation\n\tcase PausedReasonOOM:\n\t\t*t = PausedReasonOOM\n\tcase PausedReasonOther:\n\t\t*t = PausedReasonOther\n\tcase PausedReasonPromiseRejection:\n\t\t*t = PausedReasonPromiseRejection\n\tcase PausedReasonXHR:\n\t\t*t = PausedReasonXHR\n\tcase PausedReasonStep:\n\t\t*t = PausedReasonStep\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PausedReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ContinueToLocationTargetCallFrames [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-continueToLocation\ntype ContinueToLocationTargetCallFrames string\n\n// String returns the ContinueToLocationTargetCallFrames as string value.\nfunc (t ContinueToLocationTargetCallFrames) String() string {\n\treturn string(t)\n}\n\n// ContinueToLocationTargetCallFrames values.\nconst (\n\tContinueToLocationTargetCallFramesAny     ContinueToLocationTargetCallFrames = \"any\"\n\tContinueToLocationTargetCallFramesCurrent ContinueToLocationTargetCallFrames = \"current\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ContinueToLocationTargetCallFrames) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ContinueToLocationTargetCallFrames(s) {\n\tcase ContinueToLocationTargetCallFramesAny:\n\t\t*t = ContinueToLocationTargetCallFramesAny\n\tcase ContinueToLocationTargetCallFramesCurrent:\n\t\t*t = ContinueToLocationTargetCallFramesCurrent\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ContinueToLocationTargetCallFrames value: %v\", s)\n\t}\n\treturn nil\n}\n\n// RestartFrameMode the mode parameter must be present and set to 'StepInto',\n// otherwise restartFrame will error out.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-restartFrame\ntype RestartFrameMode string\n\n// String returns the RestartFrameMode as string value.\nfunc (t RestartFrameMode) String() string {\n\treturn string(t)\n}\n\n// RestartFrameMode values.\nconst (\n\tRestartFrameModeStepInto RestartFrameMode = \"StepInto\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *RestartFrameMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch RestartFrameMode(s) {\n\tcase RestartFrameModeStepInto:\n\t\t*t = RestartFrameModeStepInto\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown RestartFrameMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetInstrumentationBreakpointInstrumentation instrumentation name.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setInstrumentationBreakpoint\ntype SetInstrumentationBreakpointInstrumentation string\n\n// String returns the SetInstrumentationBreakpointInstrumentation as string value.\nfunc (t SetInstrumentationBreakpointInstrumentation) String() string {\n\treturn string(t)\n}\n\n// SetInstrumentationBreakpointInstrumentation values.\nconst (\n\tSetInstrumentationBreakpointInstrumentationBeforeScriptExecution              SetInstrumentationBreakpointInstrumentation = \"beforeScriptExecution\"\n\tSetInstrumentationBreakpointInstrumentationBeforeScriptWithSourceMapExecution SetInstrumentationBreakpointInstrumentation = \"beforeScriptWithSourceMapExecution\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetInstrumentationBreakpointInstrumentation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetInstrumentationBreakpointInstrumentation(s) {\n\tcase SetInstrumentationBreakpointInstrumentationBeforeScriptExecution:\n\t\t*t = SetInstrumentationBreakpointInstrumentationBeforeScriptExecution\n\tcase SetInstrumentationBreakpointInstrumentationBeforeScriptWithSourceMapExecution:\n\t\t*t = SetInstrumentationBreakpointInstrumentationBeforeScriptWithSourceMapExecution\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetInstrumentationBreakpointInstrumentation value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ExceptionsState pause on exceptions mode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setPauseOnExceptions\ntype ExceptionsState string\n\n// String returns the ExceptionsState as string value.\nfunc (t ExceptionsState) String() string {\n\treturn string(t)\n}\n\n// ExceptionsState values.\nconst (\n\tExceptionsStateNone     ExceptionsState = \"none\"\n\tExceptionsStateCaught   ExceptionsState = \"caught\"\n\tExceptionsStateUncaught ExceptionsState = \"uncaught\"\n\tExceptionsStateAll      ExceptionsState = \"all\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ExceptionsState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ExceptionsState(s) {\n\tcase ExceptionsStateNone:\n\t\t*t = ExceptionsStateNone\n\tcase ExceptionsStateCaught:\n\t\t*t = ExceptionsStateCaught\n\tcase ExceptionsStateUncaught:\n\t\t*t = ExceptionsStateUncaught\n\tcase ExceptionsStateAll:\n\t\t*t = ExceptionsStateAll\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ExceptionsState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetScriptSourceStatus whether the operation was successful or not. Only Ok\n// denotes a successful live edit while the other enum variants denote why the\n// live edit failed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Debugger#method-setScriptSource\ntype SetScriptSourceStatus string\n\n// String returns the SetScriptSourceStatus as string value.\nfunc (t SetScriptSourceStatus) String() string {\n\treturn string(t)\n}\n\n// SetScriptSourceStatus values.\nconst (\n\tSetScriptSourceStatusOk                              SetScriptSourceStatus = \"Ok\"\n\tSetScriptSourceStatusCompileError                    SetScriptSourceStatus = \"CompileError\"\n\tSetScriptSourceStatusBlockedByActiveGenerator        SetScriptSourceStatus = \"BlockedByActiveGenerator\"\n\tSetScriptSourceStatusBlockedByActiveFunction         SetScriptSourceStatus = \"BlockedByActiveFunction\"\n\tSetScriptSourceStatusBlockedByTopLevelEsModuleChange SetScriptSourceStatus = \"BlockedByTopLevelEsModuleChange\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetScriptSourceStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetScriptSourceStatus(s) {\n\tcase SetScriptSourceStatusOk:\n\t\t*t = SetScriptSourceStatusOk\n\tcase SetScriptSourceStatusCompileError:\n\t\t*t = SetScriptSourceStatusCompileError\n\tcase SetScriptSourceStatusBlockedByActiveGenerator:\n\t\t*t = SetScriptSourceStatusBlockedByActiveGenerator\n\tcase SetScriptSourceStatusBlockedByActiveFunction:\n\t\t*t = SetScriptSourceStatusBlockedByActiveFunction\n\tcase SetScriptSourceStatusBlockedByTopLevelEsModuleChange:\n\t\t*t = SetScriptSourceStatusBlockedByTopLevelEsModuleChange\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetScriptSourceStatus value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/deviceaccess/deviceaccess.go",
    "content": "// Package deviceaccess provides the Chrome DevTools Protocol\n// commands, types, and events for the DeviceAccess domain.\n//\n// Generated by the cdproto-gen command.\npackage deviceaccess\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams enable events in this domain.\ntype EnableParams struct{}\n\n// Enable enable events in this domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes DeviceAccess.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// DisableParams disable events in this domain.\ntype DisableParams struct{}\n\n// Disable disable events in this domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes DeviceAccess.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// SelectPromptParams select a device in response to a\n// DeviceAccess.deviceRequestPrompted event.\ntype SelectPromptParams struct {\n\tID       RequestID `json:\"id\"`\n\tDeviceID DeviceID  `json:\"deviceId\"`\n}\n\n// SelectPrompt select a device in response to a\n// DeviceAccess.deviceRequestPrompted event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#method-selectPrompt\n//\n// parameters:\n//\n//\tid\n//\tdeviceID\nfunc SelectPrompt(id RequestID, deviceID DeviceID) *SelectPromptParams {\n\treturn &SelectPromptParams{\n\t\tID:       id,\n\t\tDeviceID: deviceID,\n\t}\n}\n\n// Do executes DeviceAccess.selectPrompt against the provided context.\nfunc (p *SelectPromptParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSelectPrompt, p, nil)\n}\n\n// CancelPromptParams cancel a prompt in response to a\n// DeviceAccess.deviceRequestPrompted event.\ntype CancelPromptParams struct {\n\tID RequestID `json:\"id\"`\n}\n\n// CancelPrompt cancel a prompt in response to a\n// DeviceAccess.deviceRequestPrompted event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#method-cancelPrompt\n//\n// parameters:\n//\n//\tid\nfunc CancelPrompt(id RequestID) *CancelPromptParams {\n\treturn &CancelPromptParams{\n\t\tID: id,\n\t}\n}\n\n// Do executes DeviceAccess.cancelPrompt against the provided context.\nfunc (p *CancelPromptParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCancelPrompt, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable       = \"DeviceAccess.enable\"\n\tCommandDisable      = \"DeviceAccess.disable\"\n\tCommandSelectPrompt = \"DeviceAccess.selectPrompt\"\n\tCommandCancelPrompt = \"DeviceAccess.cancelPrompt\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/deviceaccess/events.go",
    "content": "package deviceaccess\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventDeviceRequestPrompted a device request opened a user prompt to select\n// a device. Respond with the selectPrompt or cancelPrompt command.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#event-deviceRequestPrompted\ntype EventDeviceRequestPrompted struct {\n\tID      RequestID       `json:\"id\"`\n\tDevices []*PromptDevice `json:\"devices\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/deviceaccess/types.go",
    "content": "package deviceaccess\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// RequestID device request id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#type-RequestId\ntype RequestID string\n\n// String returns the RequestID as string value.\nfunc (t RequestID) String() string {\n\treturn string(t)\n}\n\n// DeviceID a device id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#type-DeviceId\ntype DeviceID string\n\n// String returns the DeviceID as string value.\nfunc (t DeviceID) String() string {\n\treturn string(t)\n}\n\n// PromptDevice device information displayed in a user prompt to select a\n// device.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceAccess#type-PromptDevice\ntype PromptDevice struct {\n\tID   DeviceID `json:\"id\"`\n\tName string   `json:\"name\"` // Display name as it appears in a device request user prompt.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/deviceorientation/deviceorientation.go",
    "content": "// Package deviceorientation provides the Chrome DevTools Protocol\n// commands, types, and events for the DeviceOrientation domain.\n//\n// Generated by the cdproto-gen command.\npackage deviceorientation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// ClearDeviceOrientationOverrideParams clears the overridden Device\n// Orientation.\ntype ClearDeviceOrientationOverrideParams struct{}\n\n// ClearDeviceOrientationOverride clears the overridden Device Orientation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceOrientation#method-clearDeviceOrientationOverride\nfunc ClearDeviceOrientationOverride() *ClearDeviceOrientationOverrideParams {\n\treturn &ClearDeviceOrientationOverrideParams{}\n}\n\n// Do executes DeviceOrientation.clearDeviceOrientationOverride against the provided context.\nfunc (p *ClearDeviceOrientationOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearDeviceOrientationOverride, nil, nil)\n}\n\n// SetDeviceOrientationOverrideParams overrides the Device Orientation.\ntype SetDeviceOrientationOverrideParams struct {\n\tAlpha float64 `json:\"alpha\"` // Mock alpha\n\tBeta  float64 `json:\"beta\"`  // Mock beta\n\tGamma float64 `json:\"gamma\"` // Mock gamma\n}\n\n// SetDeviceOrientationOverride overrides the Device Orientation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DeviceOrientation#method-setDeviceOrientationOverride\n//\n// parameters:\n//\n//\talpha - Mock alpha\n//\tbeta - Mock beta\n//\tgamma - Mock gamma\nfunc SetDeviceOrientationOverride(alpha float64, beta float64, gamma float64) *SetDeviceOrientationOverrideParams {\n\treturn &SetDeviceOrientationOverrideParams{\n\t\tAlpha: alpha,\n\t\tBeta:  beta,\n\t\tGamma: gamma,\n\t}\n}\n\n// Do executes DeviceOrientation.setDeviceOrientationOverride against the provided context.\nfunc (p *SetDeviceOrientationOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDeviceOrientationOverride, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandClearDeviceOrientationOverride = \"DeviceOrientation.clearDeviceOrientationOverride\"\n\tCommandSetDeviceOrientationOverride   = \"DeviceOrientation.setDeviceOrientationOverride\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/dom/dom.go",
    "content": "// Package dom provides the Chrome DevTools Protocol\n// commands, types, and events for the DOM domain.\n//\n// This domain exposes DOM read/write operations. Each DOM Node is\n// represented with its mirror object that has an id. This id can be used to get\n// additional information on the Node, resolve it into the JavaScript object\n// wrapper, etc. It is important that client receives DOM events only for the\n// nodes that are known to the client. Backend keeps track of the nodes that\n// were sent to the client and never sends the same node twice. It is client's\n// responsibility to collect information about the nodes that were sent to the\n// client. Note that iframe owner elements will return corresponding document\n// elements as their child nodes.\n//\n// Generated by the cdproto-gen command.\npackage dom\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// CollectClassNamesFromSubtreeParams collects class names for the node with\n// given id and all of it's child nodes.\ntype CollectClassNamesFromSubtreeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to collect class names.\n}\n\n// CollectClassNamesFromSubtree collects class names for the node with given\n// id and all of it's child nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-collectClassNamesFromSubtree\n//\n// parameters:\n//\n//\tnodeID - Id of the node to collect class names.\nfunc CollectClassNamesFromSubtree(nodeID cdp.NodeID) *CollectClassNamesFromSubtreeParams {\n\treturn &CollectClassNamesFromSubtreeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// CollectClassNamesFromSubtreeReturns return values.\ntype CollectClassNamesFromSubtreeReturns struct {\n\tClassNames []string `json:\"classNames,omitempty,omitzero\"` // Class name list.\n}\n\n// Do executes DOM.collectClassNamesFromSubtree against the provided context.\n//\n// returns:\n//\n//\tclassNames - Class name list.\nfunc (p *CollectClassNamesFromSubtreeParams) Do(ctx context.Context) (classNames []string, err error) {\n\t// execute\n\tvar res CollectClassNamesFromSubtreeReturns\n\terr = cdp.Execute(ctx, CommandCollectClassNamesFromSubtree, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.ClassNames, nil\n}\n\n// CopyToParams creates a deep copy of the specified node and places it into\n// the target container before the given anchor.\ntype CopyToParams struct {\n\tNodeID             cdp.NodeID `json:\"nodeId\"`                                // Id of the node to copy.\n\tTargetNodeID       cdp.NodeID `json:\"targetNodeId\"`                          // Id of the element to drop the copy into.\n\tInsertBeforeNodeID cdp.NodeID `json:\"insertBeforeNodeId,omitempty,omitzero\"` // Drop the copy before this node (if absent, the copy becomes the last child of targetNodeId).\n}\n\n// CopyTo creates a deep copy of the specified node and places it into the\n// target container before the given anchor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-copyTo\n//\n// parameters:\n//\n//\tnodeID - Id of the node to copy.\n//\ttargetNodeID - Id of the element to drop the copy into.\nfunc CopyTo(nodeID cdp.NodeID, targetNodeID cdp.NodeID) *CopyToParams {\n\treturn &CopyToParams{\n\t\tNodeID:       nodeID,\n\t\tTargetNodeID: targetNodeID,\n\t}\n}\n\n// WithInsertBeforeNodeID drop the copy before this node (if absent, the copy\n// becomes the last child of targetNodeId).\nfunc (p CopyToParams) WithInsertBeforeNodeID(insertBeforeNodeID cdp.NodeID) *CopyToParams {\n\tp.InsertBeforeNodeID = insertBeforeNodeID\n\treturn &p\n}\n\n// CopyToReturns return values.\ntype CopyToReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // Id of the node clone.\n}\n\n// Do executes DOM.copyTo against the provided context.\n//\n// returns:\n//\n//\tnodeID - Id of the node clone.\nfunc (p *CopyToParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res CopyToReturns\n\terr = cdp.Execute(ctx, CommandCopyTo, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// DescribeNodeParams describes node given its id, does not require domain to\n// be enabled. Does not start tracking any objects, can be used for automation.\ntype DescribeNodeParams struct {\n\tNodeID        cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node.\n\tBackendNodeID cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node.\n\tObjectID      runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper.\n\tDepth         int64                  `json:\"depth,omitempty,omitzero\"`         // The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.\n\tPierce        bool                   `json:\"pierce\"`                           // Whether or not iframes and shadow roots should be traversed when returning the subtree (default is false).\n}\n\n// DescribeNode describes node given its id, does not require domain to be\n// enabled. Does not start tracking any objects, can be used for automation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-describeNode\n//\n// parameters:\nfunc DescribeNode() *DescribeNodeParams {\n\treturn &DescribeNodeParams{\n\t\tPierce: false,\n\t}\n}\n\n// WithNodeID identifier of the node.\nfunc (p DescribeNodeParams) WithNodeID(nodeID cdp.NodeID) *DescribeNodeParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node.\nfunc (p DescribeNodeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *DescribeNodeParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper.\nfunc (p DescribeNodeParams) WithObjectID(objectID runtime.RemoteObjectID) *DescribeNodeParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// WithDepth the maximum depth at which children should be retrieved,\n// defaults to 1. Use -1 for the entire subtree or provide an integer larger\n// than 0.\nfunc (p DescribeNodeParams) WithDepth(depth int64) *DescribeNodeParams {\n\tp.Depth = depth\n\treturn &p\n}\n\n// WithPierce whether or not iframes and shadow roots should be traversed\n// when returning the subtree (default is false).\nfunc (p DescribeNodeParams) WithPierce(pierce bool) *DescribeNodeParams {\n\tp.Pierce = pierce\n\treturn &p\n}\n\n// DescribeNodeReturns return values.\ntype DescribeNodeReturns struct {\n\tNode *cdp.Node `json:\"node,omitempty,omitzero\"` // Node description.\n}\n\n// Do executes DOM.describeNode against the provided context.\n//\n// returns:\n//\n//\tnode - Node description.\nfunc (p *DescribeNodeParams) Do(ctx context.Context) (node *cdp.Node, err error) {\n\t// execute\n\tvar res DescribeNodeReturns\n\terr = cdp.Execute(ctx, CommandDescribeNode, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Node, nil\n}\n\n// ScrollIntoViewIfNeededParams scrolls the specified rect of the given node\n// into view if not already visible. Note: exactly one between nodeId,\n// backendNodeId and objectId should be passed to identify the node.\ntype ScrollIntoViewIfNeededParams struct {\n\tNodeID        cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node.\n\tBackendNodeID cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node.\n\tObjectID      runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper.\n\tRect          *Rect                  `json:\"rect,omitempty,omitzero\"`          // The rect to be scrolled into view, relative to the node's border box, in CSS pixels. When omitted, center of the node will be used, similar to Element.scrollIntoView.\n}\n\n// ScrollIntoViewIfNeeded scrolls the specified rect of the given node into\n// view if not already visible. Note: exactly one between nodeId, backendNodeId\n// and objectId should be passed to identify the node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-scrollIntoViewIfNeeded\n//\n// parameters:\nfunc ScrollIntoViewIfNeeded() *ScrollIntoViewIfNeededParams {\n\treturn &ScrollIntoViewIfNeededParams{}\n}\n\n// WithNodeID identifier of the node.\nfunc (p ScrollIntoViewIfNeededParams) WithNodeID(nodeID cdp.NodeID) *ScrollIntoViewIfNeededParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node.\nfunc (p ScrollIntoViewIfNeededParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *ScrollIntoViewIfNeededParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper.\nfunc (p ScrollIntoViewIfNeededParams) WithObjectID(objectID runtime.RemoteObjectID) *ScrollIntoViewIfNeededParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// WithRect the rect to be scrolled into view, relative to the node's border\n// box, in CSS pixels. When omitted, center of the node will be used, similar to\n// Element.scrollIntoView.\nfunc (p ScrollIntoViewIfNeededParams) WithRect(rect *Rect) *ScrollIntoViewIfNeededParams {\n\tp.Rect = rect\n\treturn &p\n}\n\n// Do executes DOM.scrollIntoViewIfNeeded against the provided context.\nfunc (p *ScrollIntoViewIfNeededParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandScrollIntoViewIfNeeded, p, nil)\n}\n\n// DisableParams disables DOM agent for the given page.\ntype DisableParams struct{}\n\n// Disable disables DOM agent for the given page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes DOM.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// DiscardSearchResultsParams discards search results from the session with\n// the given id. getSearchResults should no longer be called for that search.\ntype DiscardSearchResultsParams struct {\n\tSearchID string `json:\"searchId\"` // Unique search session identifier.\n}\n\n// DiscardSearchResults discards search results from the session with the\n// given id. getSearchResults should no longer be called for that search.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-discardSearchResults\n//\n// parameters:\n//\n//\tsearchID - Unique search session identifier.\nfunc DiscardSearchResults(searchID string) *DiscardSearchResultsParams {\n\treturn &DiscardSearchResultsParams{\n\t\tSearchID: searchID,\n\t}\n}\n\n// Do executes DOM.discardSearchResults against the provided context.\nfunc (p *DiscardSearchResultsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDiscardSearchResults, p, nil)\n}\n\n// EnableParams enables DOM agent for the given page.\ntype EnableParams struct {\n\tIncludeWhitespace EnableIncludeWhitespace `json:\"includeWhitespace,omitempty,omitzero\"` // Whether to include whitespaces in the children array of returned Nodes.\n}\n\n// Enable enables DOM agent for the given page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// WithIncludeWhitespace whether to include whitespaces in the children array\n// of returned Nodes.\nfunc (p EnableParams) WithIncludeWhitespace(includeWhitespace EnableIncludeWhitespace) *EnableParams {\n\tp.IncludeWhitespace = includeWhitespace\n\treturn &p\n}\n\n// Do executes DOM.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// FocusParams focuses the given element.\ntype FocusParams struct {\n\tNodeID        cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node.\n\tBackendNodeID cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node.\n\tObjectID      runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper.\n}\n\n// Focus focuses the given element.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-focus\n//\n// parameters:\nfunc Focus() *FocusParams {\n\treturn &FocusParams{}\n}\n\n// WithNodeID identifier of the node.\nfunc (p FocusParams) WithNodeID(nodeID cdp.NodeID) *FocusParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node.\nfunc (p FocusParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *FocusParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper.\nfunc (p FocusParams) WithObjectID(objectID runtime.RemoteObjectID) *FocusParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// Do executes DOM.focus against the provided context.\nfunc (p *FocusParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandFocus, p, nil)\n}\n\n// GetAttributesParams returns attributes for the specified node.\ntype GetAttributesParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to retrieve attributes for.\n}\n\n// GetAttributes returns attributes for the specified node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getAttributes\n//\n// parameters:\n//\n//\tnodeID - Id of the node to retrieve attributes for.\nfunc GetAttributes(nodeID cdp.NodeID) *GetAttributesParams {\n\treturn &GetAttributesParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetAttributesReturns return values.\ntype GetAttributesReturns struct {\n\tAttributes []string `json:\"attributes,omitempty,omitzero\"` // An interleaved array of node attribute names and values.\n}\n\n// Do executes DOM.getAttributes against the provided context.\n//\n// returns:\n//\n//\tattributes - An interleaved array of node attribute names and values.\nfunc (p *GetAttributesParams) Do(ctx context.Context) (attributes []string, err error) {\n\t// execute\n\tvar res GetAttributesReturns\n\terr = cdp.Execute(ctx, CommandGetAttributes, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Attributes, nil\n}\n\n// GetBoxModelParams returns boxes for the given node.\ntype GetBoxModelParams struct {\n\tNodeID        cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node.\n\tBackendNodeID cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node.\n\tObjectID      runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper.\n}\n\n// GetBoxModel returns boxes for the given node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getBoxModel\n//\n// parameters:\nfunc GetBoxModel() *GetBoxModelParams {\n\treturn &GetBoxModelParams{}\n}\n\n// WithNodeID identifier of the node.\nfunc (p GetBoxModelParams) WithNodeID(nodeID cdp.NodeID) *GetBoxModelParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node.\nfunc (p GetBoxModelParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetBoxModelParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper.\nfunc (p GetBoxModelParams) WithObjectID(objectID runtime.RemoteObjectID) *GetBoxModelParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// GetBoxModelReturns return values.\ntype GetBoxModelReturns struct {\n\tModel *BoxModel `json:\"model,omitempty,omitzero\"` // Box model for the node.\n}\n\n// Do executes DOM.getBoxModel against the provided context.\n//\n// returns:\n//\n//\tmodel - Box model for the node.\nfunc (p *GetBoxModelParams) Do(ctx context.Context) (model *BoxModel, err error) {\n\t// execute\n\tvar res GetBoxModelReturns\n\terr = cdp.Execute(ctx, CommandGetBoxModel, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Model, nil\n}\n\n// GetContentQuadsParams returns quads that describe node position on the\n// page. This method might return multiple quads for inline nodes.\ntype GetContentQuadsParams struct {\n\tNodeID        cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node.\n\tBackendNodeID cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node.\n\tObjectID      runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper.\n}\n\n// GetContentQuads returns quads that describe node position on the page.\n// This method might return multiple quads for inline nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getContentQuads\n//\n// parameters:\nfunc GetContentQuads() *GetContentQuadsParams {\n\treturn &GetContentQuadsParams{}\n}\n\n// WithNodeID identifier of the node.\nfunc (p GetContentQuadsParams) WithNodeID(nodeID cdp.NodeID) *GetContentQuadsParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node.\nfunc (p GetContentQuadsParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetContentQuadsParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper.\nfunc (p GetContentQuadsParams) WithObjectID(objectID runtime.RemoteObjectID) *GetContentQuadsParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// GetContentQuadsReturns return values.\ntype GetContentQuadsReturns struct {\n\tQuads []Quad `json:\"quads,omitempty,omitzero\"` // Quads that describe node layout relative to viewport.\n}\n\n// Do executes DOM.getContentQuads against the provided context.\n//\n// returns:\n//\n//\tquads - Quads that describe node layout relative to viewport.\nfunc (p *GetContentQuadsParams) Do(ctx context.Context) (quads []Quad, err error) {\n\t// execute\n\tvar res GetContentQuadsReturns\n\terr = cdp.Execute(ctx, CommandGetContentQuads, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Quads, nil\n}\n\n// GetDocumentParams returns the root DOM node (and optionally the subtree)\n// to the caller. Implicitly enables the DOM domain events for the current\n// target.\ntype GetDocumentParams struct {\n\tDepth  int64 `json:\"depth,omitempty,omitzero\"` // The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.\n\tPierce bool  `json:\"pierce\"`                   // Whether or not iframes and shadow roots should be traversed when returning the subtree (default is false).\n}\n\n// GetDocument returns the root DOM node (and optionally the subtree) to the\n// caller. Implicitly enables the DOM domain events for the current target.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getDocument\n//\n// parameters:\nfunc GetDocument() *GetDocumentParams {\n\treturn &GetDocumentParams{\n\t\tPierce: false,\n\t}\n}\n\n// WithDepth the maximum depth at which children should be retrieved,\n// defaults to 1. Use -1 for the entire subtree or provide an integer larger\n// than 0.\nfunc (p GetDocumentParams) WithDepth(depth int64) *GetDocumentParams {\n\tp.Depth = depth\n\treturn &p\n}\n\n// WithPierce whether or not iframes and shadow roots should be traversed\n// when returning the subtree (default is false).\nfunc (p GetDocumentParams) WithPierce(pierce bool) *GetDocumentParams {\n\tp.Pierce = pierce\n\treturn &p\n}\n\n// GetDocumentReturns return values.\ntype GetDocumentReturns struct {\n\tRoot *cdp.Node `json:\"root,omitempty,omitzero\"` // Resulting node.\n}\n\n// Do executes DOM.getDocument against the provided context.\n//\n// returns:\n//\n//\troot - Resulting node.\nfunc (p *GetDocumentParams) Do(ctx context.Context) (root *cdp.Node, err error) {\n\t// execute\n\tvar res GetDocumentReturns\n\terr = cdp.Execute(ctx, CommandGetDocument, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Root, nil\n}\n\n// GetNodesForSubtreeByStyleParams finds nodes with a given computed style in\n// a subtree.\ntype GetNodesForSubtreeByStyleParams struct {\n\tNodeID         cdp.NodeID                  `json:\"nodeId\"`         // Node ID pointing to the root of a subtree.\n\tComputedStyles []*CSSComputedStyleProperty `json:\"computedStyles\"` // The style to filter nodes by (includes nodes if any of properties matches).\n\tPierce         bool                        `json:\"pierce\"`         // Whether or not iframes and shadow roots in the same target should be traversed when returning the results (default is false).\n}\n\n// GetNodesForSubtreeByStyle finds nodes with a given computed style in a\n// subtree.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getNodesForSubtreeByStyle\n//\n// parameters:\n//\n//\tnodeID - Node ID pointing to the root of a subtree.\n//\tcomputedStyles - The style to filter nodes by (includes nodes if any of properties matches).\nfunc GetNodesForSubtreeByStyle(nodeID cdp.NodeID, computedStyles []*CSSComputedStyleProperty) *GetNodesForSubtreeByStyleParams {\n\treturn &GetNodesForSubtreeByStyleParams{\n\t\tNodeID:         nodeID,\n\t\tComputedStyles: computedStyles,\n\t\tPierce:         false,\n\t}\n}\n\n// WithPierce whether or not iframes and shadow roots in the same target\n// should be traversed when returning the results (default is false).\nfunc (p GetNodesForSubtreeByStyleParams) WithPierce(pierce bool) *GetNodesForSubtreeByStyleParams {\n\tp.Pierce = pierce\n\treturn &p\n}\n\n// GetNodesForSubtreeByStyleReturns return values.\ntype GetNodesForSubtreeByStyleReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // Resulting nodes.\n}\n\n// Do executes DOM.getNodesForSubtreeByStyle against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - Resulting nodes.\nfunc (p *GetNodesForSubtreeByStyleParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res GetNodesForSubtreeByStyleReturns\n\terr = cdp.Execute(ctx, CommandGetNodesForSubtreeByStyle, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// GetNodeForLocationParams returns node id at given location. Depending on\n// whether DOM domain is enabled, nodeId is either returned or not.\ntype GetNodeForLocationParams struct {\n\tX                         int64 `json:\"x\"`                         // X coordinate.\n\tY                         int64 `json:\"y\"`                         // Y coordinate.\n\tIncludeUserAgentShadowDOM bool  `json:\"includeUserAgentShadowDOM\"` // False to skip to the nearest non-UA shadow root ancestor (default: false).\n\tIgnorePointerEventsNone   bool  `json:\"ignorePointerEventsNone\"`   // Whether to ignore pointer-events: none on elements and hit test them.\n}\n\n// GetNodeForLocation returns node id at given location. Depending on whether\n// DOM domain is enabled, nodeId is either returned or not.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getNodeForLocation\n//\n// parameters:\n//\n//\tx - X coordinate.\n//\ty - Y coordinate.\nfunc GetNodeForLocation(x int64, y int64) *GetNodeForLocationParams {\n\treturn &GetNodeForLocationParams{\n\t\tX:                         x,\n\t\tY:                         y,\n\t\tIncludeUserAgentShadowDOM: false,\n\t\tIgnorePointerEventsNone:   false,\n\t}\n}\n\n// WithIncludeUserAgentShadowDOM false to skip to the nearest non-UA shadow\n// root ancestor (default: false).\nfunc (p GetNodeForLocationParams) WithIncludeUserAgentShadowDOM(includeUserAgentShadowDOM bool) *GetNodeForLocationParams {\n\tp.IncludeUserAgentShadowDOM = includeUserAgentShadowDOM\n\treturn &p\n}\n\n// WithIgnorePointerEventsNone whether to ignore pointer-events: none on\n// elements and hit test them.\nfunc (p GetNodeForLocationParams) WithIgnorePointerEventsNone(ignorePointerEventsNone bool) *GetNodeForLocationParams {\n\tp.IgnorePointerEventsNone = ignorePointerEventsNone\n\treturn &p\n}\n\n// GetNodeForLocationReturns return values.\ntype GetNodeForLocationReturns struct {\n\tBackendNodeID cdp.BackendNodeID `json:\"backendNodeId,omitempty,omitzero\"` // Resulting node.\n\tFrameID       cdp.FrameID       `json:\"frameId,omitempty,omitzero\"`       // Frame this node belongs to.\n\tNodeID        cdp.NodeID        `json:\"nodeId,omitempty,omitzero\"`        // Id of the node at given coordinates, only when enabled and requested document.\n}\n\n// Do executes DOM.getNodeForLocation against the provided context.\n//\n// returns:\n//\n//\tbackendNodeID - Resulting node.\n//\tframeID - Frame this node belongs to.\n//\tnodeID - Id of the node at given coordinates, only when enabled and requested document.\nfunc (p *GetNodeForLocationParams) Do(ctx context.Context) (backendNodeID cdp.BackendNodeID, frameID cdp.FrameID, nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res GetNodeForLocationReturns\n\terr = cdp.Execute(ctx, CommandGetNodeForLocation, p, &res)\n\tif err != nil {\n\t\treturn 0, \"\", 0, err\n\t}\n\n\treturn res.BackendNodeID, res.FrameID, res.NodeID, nil\n}\n\n// GetOuterHTMLParams returns node's HTML markup.\ntype GetOuterHTMLParams struct {\n\tNodeID           cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node.\n\tBackendNodeID    cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node.\n\tObjectID         runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper.\n\tIncludeShadowDOM bool                   `json:\"includeShadowDOM\"`                 // Include all shadow roots. Equals to false if not specified.\n}\n\n// GetOuterHTML returns node's HTML markup.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getOuterHTML\n//\n// parameters:\nfunc GetOuterHTML() *GetOuterHTMLParams {\n\treturn &GetOuterHTMLParams{\n\t\tIncludeShadowDOM: false,\n\t}\n}\n\n// WithNodeID identifier of the node.\nfunc (p GetOuterHTMLParams) WithNodeID(nodeID cdp.NodeID) *GetOuterHTMLParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node.\nfunc (p GetOuterHTMLParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *GetOuterHTMLParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper.\nfunc (p GetOuterHTMLParams) WithObjectID(objectID runtime.RemoteObjectID) *GetOuterHTMLParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// WithIncludeShadowDOM include all shadow roots. Equals to false if not\n// specified.\nfunc (p GetOuterHTMLParams) WithIncludeShadowDOM(includeShadowDOM bool) *GetOuterHTMLParams {\n\tp.IncludeShadowDOM = includeShadowDOM\n\treturn &p\n}\n\n// GetOuterHTMLReturns return values.\ntype GetOuterHTMLReturns struct {\n\tOuterHTML string `json:\"outerHTML,omitempty,omitzero\"` // Outer HTML markup.\n}\n\n// Do executes DOM.getOuterHTML against the provided context.\n//\n// returns:\n//\n//\touterHTML - Outer HTML markup.\nfunc (p *GetOuterHTMLParams) Do(ctx context.Context) (outerHTML string, err error) {\n\t// execute\n\tvar res GetOuterHTMLReturns\n\terr = cdp.Execute(ctx, CommandGetOuterHTML, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.OuterHTML, nil\n}\n\n// GetRelayoutBoundaryParams returns the id of the nearest ancestor that is a\n// relayout boundary.\ntype GetRelayoutBoundaryParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node.\n}\n\n// GetRelayoutBoundary returns the id of the nearest ancestor that is a\n// relayout boundary.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getRelayoutBoundary\n//\n// parameters:\n//\n//\tnodeID - Id of the node.\nfunc GetRelayoutBoundary(nodeID cdp.NodeID) *GetRelayoutBoundaryParams {\n\treturn &GetRelayoutBoundaryParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetRelayoutBoundaryReturns return values.\ntype GetRelayoutBoundaryReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // Relayout boundary node id for the given node.\n}\n\n// Do executes DOM.getRelayoutBoundary against the provided context.\n//\n// returns:\n//\n//\tnodeID - Relayout boundary node id for the given node.\nfunc (p *GetRelayoutBoundaryParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res GetRelayoutBoundaryReturns\n\terr = cdp.Execute(ctx, CommandGetRelayoutBoundary, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// GetSearchResultsParams returns search results from given fromIndex to\n// given toIndex from the search with the given identifier.\ntype GetSearchResultsParams struct {\n\tSearchID  string `json:\"searchId\"`  // Unique search session identifier.\n\tFromIndex int64  `json:\"fromIndex\"` // Start index of the search result to be returned.\n\tToIndex   int64  `json:\"toIndex\"`   // End index of the search result to be returned.\n}\n\n// GetSearchResults returns search results from given fromIndex to given\n// toIndex from the search with the given identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getSearchResults\n//\n// parameters:\n//\n//\tsearchID - Unique search session identifier.\n//\tfromIndex - Start index of the search result to be returned.\n//\ttoIndex - End index of the search result to be returned.\nfunc GetSearchResults(searchID string, fromIndex int64, toIndex int64) *GetSearchResultsParams {\n\treturn &GetSearchResultsParams{\n\t\tSearchID:  searchID,\n\t\tFromIndex: fromIndex,\n\t\tToIndex:   toIndex,\n\t}\n}\n\n// GetSearchResultsReturns return values.\ntype GetSearchResultsReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // Ids of the search result nodes.\n}\n\n// Do executes DOM.getSearchResults against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - Ids of the search result nodes.\nfunc (p *GetSearchResultsParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res GetSearchResultsReturns\n\terr = cdp.Execute(ctx, CommandGetSearchResults, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// MarkUndoableStateParams marks last undoable state.\ntype MarkUndoableStateParams struct{}\n\n// MarkUndoableState marks last undoable state.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-markUndoableState\nfunc MarkUndoableState() *MarkUndoableStateParams {\n\treturn &MarkUndoableStateParams{}\n}\n\n// Do executes DOM.markUndoableState against the provided context.\nfunc (p *MarkUndoableStateParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandMarkUndoableState, nil, nil)\n}\n\n// MoveToParams moves node into the new container, places it before the given\n// anchor.\ntype MoveToParams struct {\n\tNodeID             cdp.NodeID `json:\"nodeId\"`                                // Id of the node to move.\n\tTargetNodeID       cdp.NodeID `json:\"targetNodeId\"`                          // Id of the element to drop the moved node into.\n\tInsertBeforeNodeID cdp.NodeID `json:\"insertBeforeNodeId,omitempty,omitzero\"` // Drop node before this one (if absent, the moved node becomes the last child of targetNodeId).\n}\n\n// MoveTo moves node into the new container, places it before the given\n// anchor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-moveTo\n//\n// parameters:\n//\n//\tnodeID - Id of the node to move.\n//\ttargetNodeID - Id of the element to drop the moved node into.\nfunc MoveTo(nodeID cdp.NodeID, targetNodeID cdp.NodeID) *MoveToParams {\n\treturn &MoveToParams{\n\t\tNodeID:       nodeID,\n\t\tTargetNodeID: targetNodeID,\n\t}\n}\n\n// WithInsertBeforeNodeID drop node before this one (if absent, the moved\n// node becomes the last child of targetNodeId).\nfunc (p MoveToParams) WithInsertBeforeNodeID(insertBeforeNodeID cdp.NodeID) *MoveToParams {\n\tp.InsertBeforeNodeID = insertBeforeNodeID\n\treturn &p\n}\n\n// MoveToReturns return values.\ntype MoveToReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // New id of the moved node.\n}\n\n// Do executes DOM.moveTo against the provided context.\n//\n// returns:\n//\n//\tnodeID - New id of the moved node.\nfunc (p *MoveToParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res MoveToReturns\n\terr = cdp.Execute(ctx, CommandMoveTo, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// PerformSearchParams searches for a given string in the DOM tree. Use\n// getSearchResults to access search results or cancelSearch to end this search\n// session.\ntype PerformSearchParams struct {\n\tQuery                     string `json:\"query\"`                     // Plain text or query selector or XPath search query.\n\tIncludeUserAgentShadowDOM bool   `json:\"includeUserAgentShadowDOM\"` // True to search in user agent shadow DOM.\n}\n\n// PerformSearch searches for a given string in the DOM tree. Use\n// getSearchResults to access search results or cancelSearch to end this search\n// session.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-performSearch\n//\n// parameters:\n//\n//\tquery - Plain text or query selector or XPath search query.\nfunc PerformSearch(query string) *PerformSearchParams {\n\treturn &PerformSearchParams{\n\t\tQuery:                     query,\n\t\tIncludeUserAgentShadowDOM: false,\n\t}\n}\n\n// WithIncludeUserAgentShadowDOM true to search in user agent shadow DOM.\nfunc (p PerformSearchParams) WithIncludeUserAgentShadowDOM(includeUserAgentShadowDOM bool) *PerformSearchParams {\n\tp.IncludeUserAgentShadowDOM = includeUserAgentShadowDOM\n\treturn &p\n}\n\n// PerformSearchReturns return values.\ntype PerformSearchReturns struct {\n\tSearchID    string `json:\"searchId,omitempty,omitzero\"`    // Unique search session identifier.\n\tResultCount int64  `json:\"resultCount,omitempty,omitzero\"` // Number of search results.\n}\n\n// Do executes DOM.performSearch against the provided context.\n//\n// returns:\n//\n//\tsearchID - Unique search session identifier.\n//\tresultCount - Number of search results.\nfunc (p *PerformSearchParams) Do(ctx context.Context) (searchID string, resultCount int64, err error) {\n\t// execute\n\tvar res PerformSearchReturns\n\terr = cdp.Execute(ctx, CommandPerformSearch, p, &res)\n\tif err != nil {\n\t\treturn \"\", 0, err\n\t}\n\n\treturn res.SearchID, res.ResultCount, nil\n}\n\n// PushNodeByPathToFrontendParams requests that the node is sent to the\n// caller given its path. // FIXME, use XPath.\ntype PushNodeByPathToFrontendParams struct {\n\tPath string `json:\"path\"` // Path to node in the proprietary format.\n}\n\n// PushNodeByPathToFrontend requests that the node is sent to the caller\n// given its path. // FIXME, use XPath.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-pushNodeByPathToFrontend\n//\n// parameters:\n//\n//\tpath - Path to node in the proprietary format.\nfunc PushNodeByPathToFrontend(path string) *PushNodeByPathToFrontendParams {\n\treturn &PushNodeByPathToFrontendParams{\n\t\tPath: path,\n\t}\n}\n\n// PushNodeByPathToFrontendReturns return values.\ntype PushNodeByPathToFrontendReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // Id of the node for given path.\n}\n\n// Do executes DOM.pushNodeByPathToFrontend against the provided context.\n//\n// returns:\n//\n//\tnodeID - Id of the node for given path.\nfunc (p *PushNodeByPathToFrontendParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res PushNodeByPathToFrontendReturns\n\terr = cdp.Execute(ctx, CommandPushNodeByPathToFrontend, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// PushNodesByBackendIDsToFrontendParams requests that a batch of nodes is\n// sent to the caller given their backend node ids.\ntype PushNodesByBackendIDsToFrontendParams struct {\n\tBackendNodeIDs []cdp.BackendNodeID `json:\"backendNodeIds\"` // The array of backend node ids.\n}\n\n// PushNodesByBackendIDsToFrontend requests that a batch of nodes is sent to\n// the caller given their backend node ids.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-pushNodesByBackendIdsToFrontend\n//\n// parameters:\n//\n//\tbackendNodeIDs - The array of backend node ids.\nfunc PushNodesByBackendIDsToFrontend(backendNodeIDs []cdp.BackendNodeID) *PushNodesByBackendIDsToFrontendParams {\n\treturn &PushNodesByBackendIDsToFrontendParams{\n\t\tBackendNodeIDs: backendNodeIDs,\n\t}\n}\n\n// PushNodesByBackendIDsToFrontendReturns return values.\ntype PushNodesByBackendIDsToFrontendReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // The array of ids of pushed nodes that correspond to the backend ids specified in backendNodeIds.\n}\n\n// Do executes DOM.pushNodesByBackendIdsToFrontend against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - The array of ids of pushed nodes that correspond to the backend ids specified in backendNodeIds.\nfunc (p *PushNodesByBackendIDsToFrontendParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res PushNodesByBackendIDsToFrontendReturns\n\terr = cdp.Execute(ctx, CommandPushNodesByBackendIDsToFrontend, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// QuerySelectorParams executes querySelector on a given node.\ntype QuerySelectorParams struct {\n\tNodeID   cdp.NodeID `json:\"nodeId\"`   // Id of the node to query upon.\n\tSelector string     `json:\"selector\"` // Selector string.\n}\n\n// QuerySelector executes querySelector on a given node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-querySelector\n//\n// parameters:\n//\n//\tnodeID - Id of the node to query upon.\n//\tselector - Selector string.\nfunc QuerySelector(nodeID cdp.NodeID, selector string) *QuerySelectorParams {\n\treturn &QuerySelectorParams{\n\t\tNodeID:   nodeID,\n\t\tSelector: selector,\n\t}\n}\n\n// QuerySelectorReturns return values.\ntype QuerySelectorReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // Query selector result.\n}\n\n// Do executes DOM.querySelector against the provided context.\n//\n// returns:\n//\n//\tnodeID - Query selector result.\nfunc (p *QuerySelectorParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res QuerySelectorReturns\n\terr = cdp.Execute(ctx, CommandQuerySelector, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// QuerySelectorAllParams executes querySelectorAll on a given node.\ntype QuerySelectorAllParams struct {\n\tNodeID   cdp.NodeID `json:\"nodeId\"`   // Id of the node to query upon.\n\tSelector string     `json:\"selector\"` // Selector string.\n}\n\n// QuerySelectorAll executes querySelectorAll on a given node.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-querySelectorAll\n//\n// parameters:\n//\n//\tnodeID - Id of the node to query upon.\n//\tselector - Selector string.\nfunc QuerySelectorAll(nodeID cdp.NodeID, selector string) *QuerySelectorAllParams {\n\treturn &QuerySelectorAllParams{\n\t\tNodeID:   nodeID,\n\t\tSelector: selector,\n\t}\n}\n\n// QuerySelectorAllReturns return values.\ntype QuerySelectorAllReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // Query selector result.\n}\n\n// Do executes DOM.querySelectorAll against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - Query selector result.\nfunc (p *QuerySelectorAllParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res QuerySelectorAllReturns\n\terr = cdp.Execute(ctx, CommandQuerySelectorAll, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// GetTopLayerElementsParams returns NodeIds of current top layer elements.\n// Top layer is rendered closest to the user within a viewport, therefore its\n// elements always appear on top of all other content.\ntype GetTopLayerElementsParams struct{}\n\n// GetTopLayerElements returns NodeIds of current top layer elements. Top\n// layer is rendered closest to the user within a viewport, therefore its\n// elements always appear on top of all other content.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getTopLayerElements\nfunc GetTopLayerElements() *GetTopLayerElementsParams {\n\treturn &GetTopLayerElementsParams{}\n}\n\n// GetTopLayerElementsReturns return values.\ntype GetTopLayerElementsReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // NodeIds of top layer elements\n}\n\n// Do executes DOM.getTopLayerElements against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - NodeIds of top layer elements\nfunc (p *GetTopLayerElementsParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res GetTopLayerElementsReturns\n\terr = cdp.Execute(ctx, CommandGetTopLayerElements, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// GetElementByRelationParams returns the NodeId of the matched element\n// according to certain relations.\ntype GetElementByRelationParams struct {\n\tNodeID   cdp.NodeID                   `json:\"nodeId\"`   // Id of the node from which to query the relation.\n\tRelation GetElementByRelationRelation `json:\"relation\"` // Type of relation to get.\n}\n\n// GetElementByRelation returns the NodeId of the matched element according\n// to certain relations.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getElementByRelation\n//\n// parameters:\n//\n//\tnodeID - Id of the node from which to query the relation.\n//\trelation - Type of relation to get.\nfunc GetElementByRelation(nodeID cdp.NodeID, relation GetElementByRelationRelation) *GetElementByRelationParams {\n\treturn &GetElementByRelationParams{\n\t\tNodeID:   nodeID,\n\t\tRelation: relation,\n\t}\n}\n\n// GetElementByRelationReturns return values.\ntype GetElementByRelationReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // NodeId of the element matching the queried relation.\n}\n\n// Do executes DOM.getElementByRelation against the provided context.\n//\n// returns:\n//\n//\tnodeID - NodeId of the element matching the queried relation.\nfunc (p *GetElementByRelationParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res GetElementByRelationReturns\n\terr = cdp.Execute(ctx, CommandGetElementByRelation, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// RedoParams re-does the last undone action.\ntype RedoParams struct{}\n\n// Redo re-does the last undone action.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-redo\nfunc Redo() *RedoParams {\n\treturn &RedoParams{}\n}\n\n// Do executes DOM.redo against the provided context.\nfunc (p *RedoParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRedo, nil, nil)\n}\n\n// RemoveAttributeParams removes attribute with given name from an element\n// with given id.\ntype RemoveAttributeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the element to remove attribute from.\n\tName   string     `json:\"name\"`   // Name of the attribute to remove.\n}\n\n// RemoveAttribute removes attribute with given name from an element with\n// given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-removeAttribute\n//\n// parameters:\n//\n//\tnodeID - Id of the element to remove attribute from.\n//\tname - Name of the attribute to remove.\nfunc RemoveAttribute(nodeID cdp.NodeID, name string) *RemoveAttributeParams {\n\treturn &RemoveAttributeParams{\n\t\tNodeID: nodeID,\n\t\tName:   name,\n\t}\n}\n\n// Do executes DOM.removeAttribute against the provided context.\nfunc (p *RemoveAttributeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveAttribute, p, nil)\n}\n\n// RemoveNodeParams removes node with given id.\ntype RemoveNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to remove.\n}\n\n// RemoveNode removes node with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-removeNode\n//\n// parameters:\n//\n//\tnodeID - Id of the node to remove.\nfunc RemoveNode(nodeID cdp.NodeID) *RemoveNodeParams {\n\treturn &RemoveNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// Do executes DOM.removeNode against the provided context.\nfunc (p *RemoveNodeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveNode, p, nil)\n}\n\n// RequestChildNodesParams requests that children of the node with given id\n// are returned to the caller in form of setChildNodes events where not only\n// immediate children are retrieved, but all children down to the specified\n// depth.\ntype RequestChildNodesParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`                   // Id of the node to get children for.\n\tDepth  int64      `json:\"depth,omitempty,omitzero\"` // The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.\n\tPierce bool       `json:\"pierce\"`                   // Whether or not iframes and shadow roots should be traversed when returning the sub-tree (default is false).\n}\n\n// RequestChildNodes requests that children of the node with given id are\n// returned to the caller in form of setChildNodes events where not only\n// immediate children are retrieved, but all children down to the specified\n// depth.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-requestChildNodes\n//\n// parameters:\n//\n//\tnodeID - Id of the node to get children for.\nfunc RequestChildNodes(nodeID cdp.NodeID) *RequestChildNodesParams {\n\treturn &RequestChildNodesParams{\n\t\tNodeID: nodeID,\n\t\tPierce: false,\n\t}\n}\n\n// WithDepth the maximum depth at which children should be retrieved,\n// defaults to 1. Use -1 for the entire subtree or provide an integer larger\n// than 0.\nfunc (p RequestChildNodesParams) WithDepth(depth int64) *RequestChildNodesParams {\n\tp.Depth = depth\n\treturn &p\n}\n\n// WithPierce whether or not iframes and shadow roots should be traversed\n// when returning the sub-tree (default is false).\nfunc (p RequestChildNodesParams) WithPierce(pierce bool) *RequestChildNodesParams {\n\tp.Pierce = pierce\n\treturn &p\n}\n\n// Do executes DOM.requestChildNodes against the provided context.\nfunc (p *RequestChildNodesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRequestChildNodes, p, nil)\n}\n\n// RequestNodeParams requests that the node is sent to the caller given the\n// JavaScript node object reference. All nodes that form the path from the node\n// to the root are also sent to the client as a series of setChildNodes\n// notifications.\ntype RequestNodeParams struct {\n\tObjectID runtime.RemoteObjectID `json:\"objectId\"` // JavaScript object id to convert into node.\n}\n\n// RequestNode requests that the node is sent to the caller given the\n// JavaScript node object reference. All nodes that form the path from the node\n// to the root are also sent to the client as a series of setChildNodes\n// notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-requestNode\n//\n// parameters:\n//\n//\tobjectID - JavaScript object id to convert into node.\nfunc RequestNode(objectID runtime.RemoteObjectID) *RequestNodeParams {\n\treturn &RequestNodeParams{\n\t\tObjectID: objectID,\n\t}\n}\n\n// RequestNodeReturns return values.\ntype RequestNodeReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // Node id for given object.\n}\n\n// Do executes DOM.requestNode against the provided context.\n//\n// returns:\n//\n//\tnodeID - Node id for given object.\nfunc (p *RequestNodeParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res RequestNodeReturns\n\terr = cdp.Execute(ctx, CommandRequestNode, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// ResolveNodeParams resolves the JavaScript node object for a given NodeId\n// or BackendNodeId.\ntype ResolveNodeParams struct {\n\tNodeID             cdp.NodeID                 `json:\"nodeId,omitempty,omitzero\"`             // Id of the node to resolve.\n\tBackendNodeID      cdp.BackendNodeID          `json:\"backendNodeId,omitempty,omitzero\"`      // Backend identifier of the node to resolve.\n\tObjectGroup        string                     `json:\"objectGroup,omitempty,omitzero\"`        // Symbolic group name that can be used to release multiple objects.\n\tExecutionContextID runtime.ExecutionContextID `json:\"executionContextId,omitempty,omitzero\"` // Execution context in which to resolve the node.\n}\n\n// ResolveNode resolves the JavaScript node object for a given NodeId or\n// BackendNodeId.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-resolveNode\n//\n// parameters:\nfunc ResolveNode() *ResolveNodeParams {\n\treturn &ResolveNodeParams{}\n}\n\n// WithNodeID ID of the node to resolve.\nfunc (p ResolveNodeParams) WithNodeID(nodeID cdp.NodeID) *ResolveNodeParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID backend identifier of the node to resolve.\nfunc (p ResolveNodeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *ResolveNodeParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectGroup symbolic group name that can be used to release multiple\n// objects.\nfunc (p ResolveNodeParams) WithObjectGroup(objectGroup string) *ResolveNodeParams {\n\tp.ObjectGroup = objectGroup\n\treturn &p\n}\n\n// WithExecutionContextID execution context in which to resolve the node.\nfunc (p ResolveNodeParams) WithExecutionContextID(executionContextID runtime.ExecutionContextID) *ResolveNodeParams {\n\tp.ExecutionContextID = executionContextID\n\treturn &p\n}\n\n// ResolveNodeReturns return values.\ntype ResolveNodeReturns struct {\n\tObject *runtime.RemoteObject `json:\"object,omitempty,omitzero\"` // JavaScript object wrapper for given node.\n}\n\n// Do executes DOM.resolveNode against the provided context.\n//\n// returns:\n//\n//\tobject - JavaScript object wrapper for given node.\nfunc (p *ResolveNodeParams) Do(ctx context.Context) (object *runtime.RemoteObject, err error) {\n\t// execute\n\tvar res ResolveNodeReturns\n\terr = cdp.Execute(ctx, CommandResolveNode, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Object, nil\n}\n\n// SetAttributeValueParams sets attribute for an element with given id.\ntype SetAttributeValueParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the element to set attribute for.\n\tName   string     `json:\"name\"`   // Attribute name.\n\tValue  string     `json:\"value\"`  // Attribute value.\n}\n\n// SetAttributeValue sets attribute for an element with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setAttributeValue\n//\n// parameters:\n//\n//\tnodeID - Id of the element to set attribute for.\n//\tname - Attribute name.\n//\tvalue - Attribute value.\nfunc SetAttributeValue(nodeID cdp.NodeID, name string, value string) *SetAttributeValueParams {\n\treturn &SetAttributeValueParams{\n\t\tNodeID: nodeID,\n\t\tName:   name,\n\t\tValue:  value,\n\t}\n}\n\n// Do executes DOM.setAttributeValue against the provided context.\nfunc (p *SetAttributeValueParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAttributeValue, p, nil)\n}\n\n// SetAttributesAsTextParams sets attributes on element with given id. This\n// method is useful when user edits some existing attribute value and types in\n// several attribute name/value pairs.\ntype SetAttributesAsTextParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`                  // Id of the element to set attributes for.\n\tText   string     `json:\"text\"`                    // Text with a number of attributes. Will parse this text using HTML parser.\n\tName   string     `json:\"name,omitempty,omitzero\"` // Attribute name to replace with new attributes derived from text in case text parsed successfully.\n}\n\n// SetAttributesAsText sets attributes on element with given id. This method\n// is useful when user edits some existing attribute value and types in several\n// attribute name/value pairs.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setAttributesAsText\n//\n// parameters:\n//\n//\tnodeID - Id of the element to set attributes for.\n//\ttext - Text with a number of attributes. Will parse this text using HTML parser.\nfunc SetAttributesAsText(nodeID cdp.NodeID, text string) *SetAttributesAsTextParams {\n\treturn &SetAttributesAsTextParams{\n\t\tNodeID: nodeID,\n\t\tText:   text,\n\t}\n}\n\n// WithName attribute name to replace with new attributes derived from text\n// in case text parsed successfully.\nfunc (p SetAttributesAsTextParams) WithName(name string) *SetAttributesAsTextParams {\n\tp.Name = name\n\treturn &p\n}\n\n// Do executes DOM.setAttributesAsText against the provided context.\nfunc (p *SetAttributesAsTextParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAttributesAsText, p, nil)\n}\n\n// SetFileInputFilesParams sets files for the given file input element.\ntype SetFileInputFilesParams struct {\n\tFiles         []string               `json:\"files\"`                            // Array of file paths to set.\n\tNodeID        cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node.\n\tBackendNodeID cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node.\n\tObjectID      runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node wrapper.\n}\n\n// SetFileInputFiles sets files for the given file input element.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setFileInputFiles\n//\n// parameters:\n//\n//\tfiles - Array of file paths to set.\nfunc SetFileInputFiles(files []string) *SetFileInputFilesParams {\n\treturn &SetFileInputFilesParams{\n\t\tFiles: files,\n\t}\n}\n\n// WithNodeID identifier of the node.\nfunc (p SetFileInputFilesParams) WithNodeID(nodeID cdp.NodeID) *SetFileInputFilesParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node.\nfunc (p SetFileInputFilesParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *SetFileInputFilesParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node wrapper.\nfunc (p SetFileInputFilesParams) WithObjectID(objectID runtime.RemoteObjectID) *SetFileInputFilesParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// Do executes DOM.setFileInputFiles against the provided context.\nfunc (p *SetFileInputFilesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetFileInputFiles, p, nil)\n}\n\n// SetNodeStackTracesEnabledParams sets if stack traces should be captured\n// for Nodes. See Node.getNodeStackTraces. Default is disabled.\ntype SetNodeStackTracesEnabledParams struct {\n\tEnable bool `json:\"enable\"` // Enable or disable.\n}\n\n// SetNodeStackTracesEnabled sets if stack traces should be captured for\n// Nodes. See Node.getNodeStackTraces. Default is disabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setNodeStackTracesEnabled\n//\n// parameters:\n//\n//\tenable - Enable or disable.\nfunc SetNodeStackTracesEnabled(enable bool) *SetNodeStackTracesEnabledParams {\n\treturn &SetNodeStackTracesEnabledParams{\n\t\tEnable: enable,\n\t}\n}\n\n// Do executes DOM.setNodeStackTracesEnabled against the provided context.\nfunc (p *SetNodeStackTracesEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetNodeStackTracesEnabled, p, nil)\n}\n\n// GetNodeStackTracesParams gets stack traces associated with a Node. As of\n// now, only provides stack trace for Node creation.\ntype GetNodeStackTracesParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to get stack traces for.\n}\n\n// GetNodeStackTraces gets stack traces associated with a Node. As of now,\n// only provides stack trace for Node creation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getNodeStackTraces\n//\n// parameters:\n//\n//\tnodeID - Id of the node to get stack traces for.\nfunc GetNodeStackTraces(nodeID cdp.NodeID) *GetNodeStackTracesParams {\n\treturn &GetNodeStackTracesParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetNodeStackTracesReturns return values.\ntype GetNodeStackTracesReturns struct {\n\tCreation *runtime.StackTrace `json:\"creation,omitempty,omitzero\"` // Creation stack trace, if available.\n}\n\n// Do executes DOM.getNodeStackTraces against the provided context.\n//\n// returns:\n//\n//\tcreation - Creation stack trace, if available.\nfunc (p *GetNodeStackTracesParams) Do(ctx context.Context) (creation *runtime.StackTrace, err error) {\n\t// execute\n\tvar res GetNodeStackTracesReturns\n\terr = cdp.Execute(ctx, CommandGetNodeStackTraces, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Creation, nil\n}\n\n// GetFileInfoParams returns file information for the given File wrapper.\ntype GetFileInfoParams struct {\n\tObjectID runtime.RemoteObjectID `json:\"objectId\"` // JavaScript object id of the node wrapper.\n}\n\n// GetFileInfo returns file information for the given File wrapper.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getFileInfo\n//\n// parameters:\n//\n//\tobjectID - JavaScript object id of the node wrapper.\nfunc GetFileInfo(objectID runtime.RemoteObjectID) *GetFileInfoParams {\n\treturn &GetFileInfoParams{\n\t\tObjectID: objectID,\n\t}\n}\n\n// GetFileInfoReturns return values.\ntype GetFileInfoReturns struct {\n\tPath string `json:\"path,omitempty,omitzero\"`\n}\n\n// Do executes DOM.getFileInfo against the provided context.\n//\n// returns:\n//\n//\tpath\nfunc (p *GetFileInfoParams) Do(ctx context.Context) (path string, err error) {\n\t// execute\n\tvar res GetFileInfoReturns\n\terr = cdp.Execute(ctx, CommandGetFileInfo, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.Path, nil\n}\n\n// GetDetachedDomNodesParams returns list of detached nodes.\ntype GetDetachedDomNodesParams struct{}\n\n// GetDetachedDomNodes returns list of detached nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getDetachedDomNodes\nfunc GetDetachedDomNodes() *GetDetachedDomNodesParams {\n\treturn &GetDetachedDomNodesParams{}\n}\n\n// GetDetachedDomNodesReturns return values.\ntype GetDetachedDomNodesReturns struct {\n\tDetachedNodes []*DetachedElementInfo `json:\"detachedNodes,omitempty,omitzero\"` // The list of detached nodes\n}\n\n// Do executes DOM.getDetachedDomNodes against the provided context.\n//\n// returns:\n//\n//\tdetachedNodes - The list of detached nodes\nfunc (p *GetDetachedDomNodesParams) Do(ctx context.Context) (detachedNodes []*DetachedElementInfo, err error) {\n\t// execute\n\tvar res GetDetachedDomNodesReturns\n\terr = cdp.Execute(ctx, CommandGetDetachedDomNodes, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.DetachedNodes, nil\n}\n\n// SetInspectedNodeParams enables console to refer to the node with given id\n// via $x (see Command Line API for more details $x functions).\ntype SetInspectedNodeParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // DOM node id to be accessible by means of $x command line API.\n}\n\n// SetInspectedNode enables console to refer to the node with given id via $x\n// (see Command Line API for more details $x functions).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setInspectedNode\n//\n// parameters:\n//\n//\tnodeID - DOM node id to be accessible by means of $x command line API.\nfunc SetInspectedNode(nodeID cdp.NodeID) *SetInspectedNodeParams {\n\treturn &SetInspectedNodeParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// Do executes DOM.setInspectedNode against the provided context.\nfunc (p *SetInspectedNodeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetInspectedNode, p, nil)\n}\n\n// SetNodeNameParams sets node name for a node with given id.\ntype SetNodeNameParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to set name for.\n\tName   string     `json:\"name\"`   // New node's name.\n}\n\n// SetNodeName sets node name for a node with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setNodeName\n//\n// parameters:\n//\n//\tnodeID - Id of the node to set name for.\n//\tname - New node's name.\nfunc SetNodeName(nodeID cdp.NodeID, name string) *SetNodeNameParams {\n\treturn &SetNodeNameParams{\n\t\tNodeID: nodeID,\n\t\tName:   name,\n\t}\n}\n\n// SetNodeNameReturns return values.\ntype SetNodeNameReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // New node's id.\n}\n\n// Do executes DOM.setNodeName against the provided context.\n//\n// returns:\n//\n//\tnodeID - New node's id.\nfunc (p *SetNodeNameParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res SetNodeNameReturns\n\terr = cdp.Execute(ctx, CommandSetNodeName, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// SetNodeValueParams sets node value for a node with given id.\ntype SetNodeValueParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to set value for.\n\tValue  string     `json:\"value\"`  // New node's value.\n}\n\n// SetNodeValue sets node value for a node with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setNodeValue\n//\n// parameters:\n//\n//\tnodeID - Id of the node to set value for.\n//\tvalue - New node's value.\nfunc SetNodeValue(nodeID cdp.NodeID, value string) *SetNodeValueParams {\n\treturn &SetNodeValueParams{\n\t\tNodeID: nodeID,\n\t\tValue:  value,\n\t}\n}\n\n// Do executes DOM.setNodeValue against the provided context.\nfunc (p *SetNodeValueParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetNodeValue, p, nil)\n}\n\n// SetOuterHTMLParams sets node HTML markup, returns new node id.\ntype SetOuterHTMLParams struct {\n\tNodeID    cdp.NodeID `json:\"nodeId\"`    // Id of the node to set markup for.\n\tOuterHTML string     `json:\"outerHTML\"` // Outer HTML markup to set.\n}\n\n// SetOuterHTML sets node HTML markup, returns new node id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-setOuterHTML\n//\n// parameters:\n//\n//\tnodeID - Id of the node to set markup for.\n//\touterHTML - Outer HTML markup to set.\nfunc SetOuterHTML(nodeID cdp.NodeID, outerHTML string) *SetOuterHTMLParams {\n\treturn &SetOuterHTMLParams{\n\t\tNodeID:    nodeID,\n\t\tOuterHTML: outerHTML,\n\t}\n}\n\n// Do executes DOM.setOuterHTML against the provided context.\nfunc (p *SetOuterHTMLParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetOuterHTML, p, nil)\n}\n\n// UndoParams undoes the last performed action.\ntype UndoParams struct{}\n\n// Undo undoes the last performed action.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-undo\nfunc Undo() *UndoParams {\n\treturn &UndoParams{}\n}\n\n// Do executes DOM.undo against the provided context.\nfunc (p *UndoParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUndo, nil, nil)\n}\n\n// GetFrameOwnerParams returns iframe node that owns iframe with the given\n// domain.\ntype GetFrameOwnerParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"`\n}\n\n// GetFrameOwner returns iframe node that owns iframe with the given domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getFrameOwner\n//\n// parameters:\n//\n//\tframeID\nfunc GetFrameOwner(frameID cdp.FrameID) *GetFrameOwnerParams {\n\treturn &GetFrameOwnerParams{\n\t\tFrameID: frameID,\n\t}\n}\n\n// GetFrameOwnerReturns return values.\ntype GetFrameOwnerReturns struct {\n\tBackendNodeID cdp.BackendNodeID `json:\"backendNodeId,omitempty,omitzero\"` // Resulting node.\n\tNodeID        cdp.NodeID        `json:\"nodeId,omitempty,omitzero\"`        // Id of the node at given coordinates, only when enabled and requested document.\n}\n\n// Do executes DOM.getFrameOwner against the provided context.\n//\n// returns:\n//\n//\tbackendNodeID - Resulting node.\n//\tnodeID - Id of the node at given coordinates, only when enabled and requested document.\nfunc (p *GetFrameOwnerParams) Do(ctx context.Context) (backendNodeID cdp.BackendNodeID, nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res GetFrameOwnerReturns\n\terr = cdp.Execute(ctx, CommandGetFrameOwner, p, &res)\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\n\treturn res.BackendNodeID, res.NodeID, nil\n}\n\n// GetContainerForNodeParams returns the query container of the given node\n// based on container query conditions: containerName, physical and logical\n// axes, and whether it queries scroll-state or anchored elements. If no axes\n// are provided and queriesScrollState is false, the style container is\n// returned, which is the direct parent or the closest element with a matching\n// container-name.\ntype GetContainerForNodeParams struct {\n\tNodeID             cdp.NodeID   `json:\"nodeId\"`\n\tContainerName      string       `json:\"containerName,omitempty,omitzero\"`\n\tPhysicalAxes       PhysicalAxes `json:\"physicalAxes,omitempty,omitzero\"`\n\tLogicalAxes        LogicalAxes  `json:\"logicalAxes,omitempty,omitzero\"`\n\tQueriesScrollState bool         `json:\"queriesScrollState\"`\n\tQueriesAnchored    bool         `json:\"queriesAnchored\"`\n}\n\n// GetContainerForNode returns the query container of the given node based on\n// container query conditions: containerName, physical and logical axes, and\n// whether it queries scroll-state or anchored elements. If no axes are provided\n// and queriesScrollState is false, the style container is returned, which is\n// the direct parent or the closest element with a matching container-name.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getContainerForNode\n//\n// parameters:\n//\n//\tnodeID\nfunc GetContainerForNode(nodeID cdp.NodeID) *GetContainerForNodeParams {\n\treturn &GetContainerForNodeParams{\n\t\tNodeID:             nodeID,\n\t\tQueriesScrollState: false,\n\t\tQueriesAnchored:    false,\n\t}\n}\n\n// WithContainerName [no description].\nfunc (p GetContainerForNodeParams) WithContainerName(containerName string) *GetContainerForNodeParams {\n\tp.ContainerName = containerName\n\treturn &p\n}\n\n// WithPhysicalAxes [no description].\nfunc (p GetContainerForNodeParams) WithPhysicalAxes(physicalAxes PhysicalAxes) *GetContainerForNodeParams {\n\tp.PhysicalAxes = physicalAxes\n\treturn &p\n}\n\n// WithLogicalAxes [no description].\nfunc (p GetContainerForNodeParams) WithLogicalAxes(logicalAxes LogicalAxes) *GetContainerForNodeParams {\n\tp.LogicalAxes = logicalAxes\n\treturn &p\n}\n\n// WithQueriesScrollState [no description].\nfunc (p GetContainerForNodeParams) WithQueriesScrollState(queriesScrollState bool) *GetContainerForNodeParams {\n\tp.QueriesScrollState = queriesScrollState\n\treturn &p\n}\n\n// WithQueriesAnchored [no description].\nfunc (p GetContainerForNodeParams) WithQueriesAnchored(queriesAnchored bool) *GetContainerForNodeParams {\n\tp.QueriesAnchored = queriesAnchored\n\treturn &p\n}\n\n// GetContainerForNodeReturns return values.\ntype GetContainerForNodeReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // The container node for the given node, or null if not found.\n}\n\n// Do executes DOM.getContainerForNode against the provided context.\n//\n// returns:\n//\n//\tnodeID - The container node for the given node, or null if not found.\nfunc (p *GetContainerForNodeParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res GetContainerForNodeReturns\n\terr = cdp.Execute(ctx, CommandGetContainerForNode, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// GetQueryingDescendantsForContainerParams returns the descendants of a\n// container query container that have container queries against this container.\ntype GetQueryingDescendantsForContainerParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the container node to find querying descendants from.\n}\n\n// GetQueryingDescendantsForContainer returns the descendants of a container\n// query container that have container queries against this container.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getQueryingDescendantsForContainer\n//\n// parameters:\n//\n//\tnodeID - Id of the container node to find querying descendants from.\nfunc GetQueryingDescendantsForContainer(nodeID cdp.NodeID) *GetQueryingDescendantsForContainerParams {\n\treturn &GetQueryingDescendantsForContainerParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetQueryingDescendantsForContainerReturns return values.\ntype GetQueryingDescendantsForContainerReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // Descendant nodes with container queries against the given container.\n}\n\n// Do executes DOM.getQueryingDescendantsForContainer against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - Descendant nodes with container queries against the given container.\nfunc (p *GetQueryingDescendantsForContainerParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res GetQueryingDescendantsForContainerReturns\n\terr = cdp.Execute(ctx, CommandGetQueryingDescendantsForContainer, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// GetAnchorElementParams returns the target anchor element of the given\n// anchor query according to\n// https://www.w3.org/TR/css-anchor-position-1/#target.\ntype GetAnchorElementParams struct {\n\tNodeID          cdp.NodeID `json:\"nodeId\"`                             // Id of the positioned element from which to find the anchor.\n\tAnchorSpecifier string     `json:\"anchorSpecifier,omitempty,omitzero\"` // An optional anchor specifier, as defined in https://www.w3.org/TR/css-anchor-position-1/#anchor-specifier. If not provided, it will return the implicit anchor element for the given positioned element.\n}\n\n// GetAnchorElement returns the target anchor element of the given anchor\n// query according to https://www.w3.org/TR/css-anchor-position-1/#target.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getAnchorElement\n//\n// parameters:\n//\n//\tnodeID - Id of the positioned element from which to find the anchor.\nfunc GetAnchorElement(nodeID cdp.NodeID) *GetAnchorElementParams {\n\treturn &GetAnchorElementParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// WithAnchorSpecifier an optional anchor specifier, as defined in\n// https://www.w3.org/TR/css-anchor-position-1/#anchor-specifier. If not\n// provided, it will return the implicit anchor element for the given positioned\n// element.\nfunc (p GetAnchorElementParams) WithAnchorSpecifier(anchorSpecifier string) *GetAnchorElementParams {\n\tp.AnchorSpecifier = anchorSpecifier\n\treturn &p\n}\n\n// GetAnchorElementReturns return values.\ntype GetAnchorElementReturns struct {\n\tNodeID cdp.NodeID `json:\"nodeId,omitempty,omitzero\"` // The anchor element of the given anchor query.\n}\n\n// Do executes DOM.getAnchorElement against the provided context.\n//\n// returns:\n//\n//\tnodeID - The anchor element of the given anchor query.\nfunc (p *GetAnchorElementParams) Do(ctx context.Context) (nodeID cdp.NodeID, err error) {\n\t// execute\n\tvar res GetAnchorElementReturns\n\terr = cdp.Execute(ctx, CommandGetAnchorElement, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NodeID, nil\n}\n\n// ForceShowPopoverParams when enabling, this API force-opens the popover\n// identified by nodeId and keeps it open until disabled.\ntype ForceShowPopoverParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the popover HTMLElement\n\tEnable bool       `json:\"enable\"` // If true, opens the popover and keeps it open. If false, closes the popover if it was previously force-opened.\n}\n\n// ForceShowPopover when enabling, this API force-opens the popover\n// identified by nodeId and keeps it open until disabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-forceShowPopover\n//\n// parameters:\n//\n//\tnodeID - Id of the popover HTMLElement\n//\tenable - If true, opens the popover and keeps it open. If false, closes the popover if it was previously force-opened.\nfunc ForceShowPopover(nodeID cdp.NodeID, enable bool) *ForceShowPopoverParams {\n\treturn &ForceShowPopoverParams{\n\t\tNodeID: nodeID,\n\t\tEnable: enable,\n\t}\n}\n\n// ForceShowPopoverReturns return values.\ntype ForceShowPopoverReturns struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds,omitempty,omitzero\"` // List of popovers that were closed in order to respect popover stacking order.\n}\n\n// Do executes DOM.forceShowPopover against the provided context.\n//\n// returns:\n//\n//\tnodeIDs - List of popovers that were closed in order to respect popover stacking order.\nfunc (p *ForceShowPopoverParams) Do(ctx context.Context) (nodeIDs []cdp.NodeID, err error) {\n\t// execute\n\tvar res ForceShowPopoverReturns\n\terr = cdp.Execute(ctx, CommandForceShowPopover, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.NodeIDs, nil\n}\n\n// Command names.\nconst (\n\tCommandCollectClassNamesFromSubtree       = \"DOM.collectClassNamesFromSubtree\"\n\tCommandCopyTo                             = \"DOM.copyTo\"\n\tCommandDescribeNode                       = \"DOM.describeNode\"\n\tCommandScrollIntoViewIfNeeded             = \"DOM.scrollIntoViewIfNeeded\"\n\tCommandDisable                            = \"DOM.disable\"\n\tCommandDiscardSearchResults               = \"DOM.discardSearchResults\"\n\tCommandEnable                             = \"DOM.enable\"\n\tCommandFocus                              = \"DOM.focus\"\n\tCommandGetAttributes                      = \"DOM.getAttributes\"\n\tCommandGetBoxModel                        = \"DOM.getBoxModel\"\n\tCommandGetContentQuads                    = \"DOM.getContentQuads\"\n\tCommandGetDocument                        = \"DOM.getDocument\"\n\tCommandGetNodesForSubtreeByStyle          = \"DOM.getNodesForSubtreeByStyle\"\n\tCommandGetNodeForLocation                 = \"DOM.getNodeForLocation\"\n\tCommandGetOuterHTML                       = \"DOM.getOuterHTML\"\n\tCommandGetRelayoutBoundary                = \"DOM.getRelayoutBoundary\"\n\tCommandGetSearchResults                   = \"DOM.getSearchResults\"\n\tCommandMarkUndoableState                  = \"DOM.markUndoableState\"\n\tCommandMoveTo                             = \"DOM.moveTo\"\n\tCommandPerformSearch                      = \"DOM.performSearch\"\n\tCommandPushNodeByPathToFrontend           = \"DOM.pushNodeByPathToFrontend\"\n\tCommandPushNodesByBackendIDsToFrontend    = \"DOM.pushNodesByBackendIdsToFrontend\"\n\tCommandQuerySelector                      = \"DOM.querySelector\"\n\tCommandQuerySelectorAll                   = \"DOM.querySelectorAll\"\n\tCommandGetTopLayerElements                = \"DOM.getTopLayerElements\"\n\tCommandGetElementByRelation               = \"DOM.getElementByRelation\"\n\tCommandRedo                               = \"DOM.redo\"\n\tCommandRemoveAttribute                    = \"DOM.removeAttribute\"\n\tCommandRemoveNode                         = \"DOM.removeNode\"\n\tCommandRequestChildNodes                  = \"DOM.requestChildNodes\"\n\tCommandRequestNode                        = \"DOM.requestNode\"\n\tCommandResolveNode                        = \"DOM.resolveNode\"\n\tCommandSetAttributeValue                  = \"DOM.setAttributeValue\"\n\tCommandSetAttributesAsText                = \"DOM.setAttributesAsText\"\n\tCommandSetFileInputFiles                  = \"DOM.setFileInputFiles\"\n\tCommandSetNodeStackTracesEnabled          = \"DOM.setNodeStackTracesEnabled\"\n\tCommandGetNodeStackTraces                 = \"DOM.getNodeStackTraces\"\n\tCommandGetFileInfo                        = \"DOM.getFileInfo\"\n\tCommandGetDetachedDomNodes                = \"DOM.getDetachedDomNodes\"\n\tCommandSetInspectedNode                   = \"DOM.setInspectedNode\"\n\tCommandSetNodeName                        = \"DOM.setNodeName\"\n\tCommandSetNodeValue                       = \"DOM.setNodeValue\"\n\tCommandSetOuterHTML                       = \"DOM.setOuterHTML\"\n\tCommandUndo                               = \"DOM.undo\"\n\tCommandGetFrameOwner                      = \"DOM.getFrameOwner\"\n\tCommandGetContainerForNode                = \"DOM.getContainerForNode\"\n\tCommandGetQueryingDescendantsForContainer = \"DOM.getQueryingDescendantsForContainer\"\n\tCommandGetAnchorElement                   = \"DOM.getAnchorElement\"\n\tCommandForceShowPopover                   = \"DOM.forceShowPopover\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/dom/events.go",
    "content": "package dom\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EventAttributeModified fired when Element's attribute is modified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-attributeModified\ntype EventAttributeModified struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node that has changed.\n\tName   string     `json:\"name\"`   // Attribute name.\n\tValue  string     `json:\"value\"`  // Attribute value.\n}\n\n// EventAttributeRemoved fired when Element's attribute is removed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-attributeRemoved\ntype EventAttributeRemoved struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node that has changed.\n\tName   string     `json:\"name\"`   // A ttribute name.\n}\n\n// EventCharacterDataModified mirrors DOMCharacterDataModified event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-characterDataModified\ntype EventCharacterDataModified struct {\n\tNodeID        cdp.NodeID `json:\"nodeId\"`        // Id of the node that has changed.\n\tCharacterData string     `json:\"characterData\"` // New text value.\n}\n\n// EventChildNodeCountUpdated fired when Container's child node count has\n// changed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-childNodeCountUpdated\ntype EventChildNodeCountUpdated struct {\n\tNodeID         cdp.NodeID `json:\"nodeId\"`         // Id of the node that has changed.\n\tChildNodeCount int64      `json:\"childNodeCount\"` // New node count.\n}\n\n// EventChildNodeInserted mirrors DOMNodeInserted event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-childNodeInserted\ntype EventChildNodeInserted struct {\n\tParentNodeID   cdp.NodeID `json:\"parentNodeId\"`   // Id of the node that has changed.\n\tPreviousNodeID cdp.NodeID `json:\"previousNodeId\"` // Id of the previous sibling.\n\tNode           *cdp.Node  `json:\"node\"`           // Inserted node data.\n}\n\n// EventChildNodeRemoved mirrors DOMNodeRemoved event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-childNodeRemoved\ntype EventChildNodeRemoved struct {\n\tParentNodeID cdp.NodeID `json:\"parentNodeId\"` // Parent id.\n\tNodeID       cdp.NodeID `json:\"nodeId\"`       // Id of the node that has been removed.\n}\n\n// EventDistributedNodesUpdated called when distribution is changed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-distributedNodesUpdated\ntype EventDistributedNodesUpdated struct {\n\tInsertionPointID cdp.NodeID         `json:\"insertionPointId\"` // Insertion point where distributed nodes were updated.\n\tDistributedNodes []*cdp.BackendNode `json:\"distributedNodes\"` // Distributed nodes for given insertion point.\n}\n\n// EventDocumentUpdated fired when Document has been totally updated. Node\n// ids are no longer valid.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-documentUpdated\ntype EventDocumentUpdated struct{}\n\n// EventInlineStyleInvalidated fired when Element's inline style is modified\n// via a CSS property modification.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-inlineStyleInvalidated\ntype EventInlineStyleInvalidated struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds\"` // Ids of the nodes for which the inline styles have been invalidated.\n}\n\n// EventPseudoElementAdded called when a pseudo element is added to an\n// element.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-pseudoElementAdded\ntype EventPseudoElementAdded struct {\n\tParentID      cdp.NodeID `json:\"parentId\"`      // Pseudo element's parent element id.\n\tPseudoElement *cdp.Node  `json:\"pseudoElement\"` // The added pseudo element.\n}\n\n// EventTopLayerElementsUpdated called when top layer elements are changed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-topLayerElementsUpdated\ntype EventTopLayerElementsUpdated struct{}\n\n// EventScrollableFlagUpdated fired when a node's scrollability state\n// changes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-scrollableFlagUpdated\ntype EventScrollableFlagUpdated struct {\n\tNodeID       cdp.NodeID `json:\"nodeId\"`       // The id of the node.\n\tIsScrollable bool       `json:\"isScrollable\"` // If the node is scrollable.\n}\n\n// EventPseudoElementRemoved called when a pseudo element is removed from an\n// element.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-pseudoElementRemoved\ntype EventPseudoElementRemoved struct {\n\tParentID        cdp.NodeID `json:\"parentId\"`        // Pseudo element's parent element id.\n\tPseudoElementID cdp.NodeID `json:\"pseudoElementId\"` // The removed pseudo element id.\n}\n\n// EventSetChildNodes fired when backend wants to provide client with the\n// missing DOM structure. This happens upon most of the calls requesting node\n// ids.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-setChildNodes\ntype EventSetChildNodes struct {\n\tParentID cdp.NodeID  `json:\"parentId\"` // Parent node id to populate with children.\n\tNodes    []*cdp.Node `json:\"nodes\"`    // Child nodes array.\n}\n\n// EventShadowRootPopped called when shadow root is popped from the element.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-shadowRootPopped\ntype EventShadowRootPopped struct {\n\tHostID cdp.NodeID `json:\"hostId\"` // Host element id.\n\tRootID cdp.NodeID `json:\"rootId\"` // Shadow root id.\n}\n\n// EventShadowRootPushed called when shadow root is pushed into the element.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#event-shadowRootPushed\ntype EventShadowRootPushed struct {\n\tHostID cdp.NodeID `json:\"hostId\"` // Host element id.\n\tRoot   *cdp.Node  `json:\"root\"`   // Shadow root.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/dom/types.go",
    "content": "package dom\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// PhysicalAxes containerSelector physical axes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PhysicalAxes\ntype PhysicalAxes string\n\n// String returns the PhysicalAxes as string value.\nfunc (t PhysicalAxes) String() string {\n\treturn string(t)\n}\n\n// PhysicalAxes values.\nconst (\n\tPhysicalAxesHorizontal PhysicalAxes = \"Horizontal\"\n\tPhysicalAxesVertical   PhysicalAxes = \"Vertical\"\n\tPhysicalAxesBoth       PhysicalAxes = \"Both\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PhysicalAxes) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PhysicalAxes(s) {\n\tcase PhysicalAxesHorizontal:\n\t\t*t = PhysicalAxesHorizontal\n\tcase PhysicalAxesVertical:\n\t\t*t = PhysicalAxesVertical\n\tcase PhysicalAxesBoth:\n\t\t*t = PhysicalAxesBoth\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PhysicalAxes value: %v\", s)\n\t}\n\treturn nil\n}\n\n// LogicalAxes containerSelector logical axes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-LogicalAxes\ntype LogicalAxes string\n\n// String returns the LogicalAxes as string value.\nfunc (t LogicalAxes) String() string {\n\treturn string(t)\n}\n\n// LogicalAxes values.\nconst (\n\tLogicalAxesInline LogicalAxes = \"Inline\"\n\tLogicalAxesBlock  LogicalAxes = \"Block\"\n\tLogicalAxesBoth   LogicalAxes = \"Both\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *LogicalAxes) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch LogicalAxes(s) {\n\tcase LogicalAxesInline:\n\t\t*t = LogicalAxesInline\n\tcase LogicalAxesBlock:\n\t\t*t = LogicalAxesBlock\n\tcase LogicalAxesBoth:\n\t\t*t = LogicalAxesBoth\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown LogicalAxes value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ScrollOrientation physical scroll orientation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-ScrollOrientation\ntype ScrollOrientation string\n\n// String returns the ScrollOrientation as string value.\nfunc (t ScrollOrientation) String() string {\n\treturn string(t)\n}\n\n// ScrollOrientation values.\nconst (\n\tScrollOrientationHorizontal ScrollOrientation = \"horizontal\"\n\tScrollOrientationVertical   ScrollOrientation = \"vertical\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ScrollOrientation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ScrollOrientation(s) {\n\tcase ScrollOrientationHorizontal:\n\t\t*t = ScrollOrientationHorizontal\n\tcase ScrollOrientationVertical:\n\t\t*t = ScrollOrientationVertical\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ScrollOrientation value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DetachedElementInfo a structure to hold the top-level node of a detached\n// tree and an array of its retained descendants.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-DetachedElementInfo\ntype DetachedElementInfo struct {\n\tTreeNode        *cdp.Node    `json:\"treeNode\"`\n\tRetainedNodeIDs []cdp.NodeID `json:\"retainedNodeIds\"`\n}\n\n// Quad an array of quad vertices, x immediately followed by y for each\n// point, points clock-wise.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-Quad\ntype Quad []float64\n\n// BoxModel box model.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-BoxModel\ntype BoxModel struct {\n\tContent      Quad              `json:\"content\"`                         // Content box\n\tPadding      Quad              `json:\"padding\"`                         // Padding box\n\tBorder       Quad              `json:\"border\"`                          // Border box\n\tMargin       Quad              `json:\"margin\"`                          // Margin box\n\tWidth        int64             `json:\"width\"`                           // Node width\n\tHeight       int64             `json:\"height\"`                          // Node height\n\tShapeOutside *ShapeOutsideInfo `json:\"shapeOutside,omitempty,omitzero\"` // Shape outside coordinates\n}\n\n// ShapeOutsideInfo CSS Shape Outside details.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-ShapeOutsideInfo\ntype ShapeOutsideInfo struct {\n\tBounds      Quad             `json:\"bounds\"`      // Shape bounds\n\tShape       []jsontext.Value `json:\"shape\"`       // Shape coordinate details\n\tMarginShape []jsontext.Value `json:\"marginShape\"` // Margin shape bounds\n}\n\n// Rect Rectangle.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-Rect\ntype Rect struct {\n\tX      float64 `json:\"x\"`      // X coordinate\n\tY      float64 `json:\"y\"`      // Y coordinate\n\tWidth  float64 `json:\"width\"`  // Rectangle width\n\tHeight float64 `json:\"height\"` // Rectangle height\n}\n\n// CSSComputedStyleProperty [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-CSSComputedStyleProperty\ntype CSSComputedStyleProperty struct {\n\tName  string `json:\"name\"`  // Computed style property name.\n\tValue string `json:\"value\"` // Computed style property value.\n}\n\n// EnableIncludeWhitespace whether to include whitespaces in the children\n// array of returned Nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-enable\ntype EnableIncludeWhitespace string\n\n// String returns the EnableIncludeWhitespace as string value.\nfunc (t EnableIncludeWhitespace) String() string {\n\treturn string(t)\n}\n\n// EnableIncludeWhitespace values.\nconst (\n\tEnableIncludeWhitespaceNone EnableIncludeWhitespace = \"none\"\n\tEnableIncludeWhitespaceAll  EnableIncludeWhitespace = \"all\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *EnableIncludeWhitespace) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch EnableIncludeWhitespace(s) {\n\tcase EnableIncludeWhitespaceNone:\n\t\t*t = EnableIncludeWhitespaceNone\n\tcase EnableIncludeWhitespaceAll:\n\t\t*t = EnableIncludeWhitespaceAll\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown EnableIncludeWhitespace value: %v\", s)\n\t}\n\treturn nil\n}\n\n// GetElementByRelationRelation type of relation to get.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOM#method-getElementByRelation\ntype GetElementByRelationRelation string\n\n// String returns the GetElementByRelationRelation as string value.\nfunc (t GetElementByRelationRelation) String() string {\n\treturn string(t)\n}\n\n// GetElementByRelationRelation values.\nconst (\n\tGetElementByRelationRelationPopoverTarget  GetElementByRelationRelation = \"PopoverTarget\"\n\tGetElementByRelationRelationInterestTarget GetElementByRelationRelation = \"InterestTarget\"\n\tGetElementByRelationRelationCommandFor     GetElementByRelationRelation = \"CommandFor\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *GetElementByRelationRelation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch GetElementByRelationRelation(s) {\n\tcase GetElementByRelationRelationPopoverTarget:\n\t\t*t = GetElementByRelationRelationPopoverTarget\n\tcase GetElementByRelationRelationInterestTarget:\n\t\t*t = GetElementByRelationRelationInterestTarget\n\tcase GetElementByRelationRelationCommandFor:\n\t\t*t = GetElementByRelationRelationCommandFor\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown GetElementByRelationRelation value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/domdebugger/domdebugger.go",
    "content": "// Package domdebugger provides the Chrome DevTools Protocol\n// commands, types, and events for the DOMDebugger domain.\n//\n// DOM debugging allows setting breakpoints on particular DOM operations and\n// events. JavaScript execution will stop on these operations as if there was a\n// regular breakpoint set.\n//\n// Generated by the cdproto-gen command.\npackage domdebugger\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// GetEventListenersParams returns event listeners of the given object.\ntype GetEventListenersParams struct {\n\tObjectID runtime.RemoteObjectID `json:\"objectId\"`                 // Identifier of the object to return listeners for.\n\tDepth    int64                  `json:\"depth,omitempty,omitzero\"` // The maximum depth at which Node children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.\n\tPierce   bool                   `json:\"pierce\"`                   // Whether or not iframes and shadow roots should be traversed when returning the subtree (default is false). Reports listeners for all contexts if pierce is enabled.\n}\n\n// GetEventListeners returns event listeners of the given object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-getEventListeners\n//\n// parameters:\n//\n//\tobjectID - Identifier of the object to return listeners for.\nfunc GetEventListeners(objectID runtime.RemoteObjectID) *GetEventListenersParams {\n\treturn &GetEventListenersParams{\n\t\tObjectID: objectID,\n\t\tPierce:   false,\n\t}\n}\n\n// WithDepth the maximum depth at which Node children should be retrieved,\n// defaults to 1. Use -1 for the entire subtree or provide an integer larger\n// than 0.\nfunc (p GetEventListenersParams) WithDepth(depth int64) *GetEventListenersParams {\n\tp.Depth = depth\n\treturn &p\n}\n\n// WithPierce whether or not iframes and shadow roots should be traversed\n// when returning the subtree (default is false). Reports listeners for all\n// contexts if pierce is enabled.\nfunc (p GetEventListenersParams) WithPierce(pierce bool) *GetEventListenersParams {\n\tp.Pierce = pierce\n\treturn &p\n}\n\n// GetEventListenersReturns return values.\ntype GetEventListenersReturns struct {\n\tListeners []*EventListener `json:\"listeners,omitempty,omitzero\"` // Array of relevant listeners.\n}\n\n// Do executes DOMDebugger.getEventListeners against the provided context.\n//\n// returns:\n//\n//\tlisteners - Array of relevant listeners.\nfunc (p *GetEventListenersParams) Do(ctx context.Context) (listeners []*EventListener, err error) {\n\t// execute\n\tvar res GetEventListenersReturns\n\terr = cdp.Execute(ctx, CommandGetEventListeners, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Listeners, nil\n}\n\n// RemoveDOMBreakpointParams removes DOM breakpoint that was set using\n// setDOMBreakpoint.\ntype RemoveDOMBreakpointParams struct {\n\tNodeID cdp.NodeID        `json:\"nodeId\"` // Identifier of the node to remove breakpoint from.\n\tType   DOMBreakpointType `json:\"type\"`   // Type of the breakpoint to remove.\n}\n\n// RemoveDOMBreakpoint removes DOM breakpoint that was set using\n// setDOMBreakpoint.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-removeDOMBreakpoint\n//\n// parameters:\n//\n//\tnodeID - Identifier of the node to remove breakpoint from.\n//\ttype - Type of the breakpoint to remove.\nfunc RemoveDOMBreakpoint(nodeID cdp.NodeID, typeVal DOMBreakpointType) *RemoveDOMBreakpointParams {\n\treturn &RemoveDOMBreakpointParams{\n\t\tNodeID: nodeID,\n\t\tType:   typeVal,\n\t}\n}\n\n// Do executes DOMDebugger.removeDOMBreakpoint against the provided context.\nfunc (p *RemoveDOMBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveDOMBreakpoint, p, nil)\n}\n\n// RemoveEventListenerBreakpointParams removes breakpoint on particular DOM\n// event.\ntype RemoveEventListenerBreakpointParams struct {\n\tEventName  string `json:\"eventName\"`                     // Event name.\n\tTargetName string `json:\"targetName,omitempty,omitzero\"` // EventTarget interface name.\n}\n\n// RemoveEventListenerBreakpoint removes breakpoint on particular DOM event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-removeEventListenerBreakpoint\n//\n// parameters:\n//\n//\teventName - Event name.\nfunc RemoveEventListenerBreakpoint(eventName string) *RemoveEventListenerBreakpointParams {\n\treturn &RemoveEventListenerBreakpointParams{\n\t\tEventName: eventName,\n\t}\n}\n\n// WithTargetName eventTarget interface name.\nfunc (p RemoveEventListenerBreakpointParams) WithTargetName(targetName string) *RemoveEventListenerBreakpointParams {\n\tp.TargetName = targetName\n\treturn &p\n}\n\n// Do executes DOMDebugger.removeEventListenerBreakpoint against the provided context.\nfunc (p *RemoveEventListenerBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveEventListenerBreakpoint, p, nil)\n}\n\n// RemoveXHRBreakpointParams removes breakpoint from XMLHttpRequest.\ntype RemoveXHRBreakpointParams struct {\n\tURL string `json:\"url\"` // Resource URL substring.\n}\n\n// RemoveXHRBreakpoint removes breakpoint from XMLHttpRequest.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-removeXHRBreakpoint\n//\n// parameters:\n//\n//\turl - Resource URL substring.\nfunc RemoveXHRBreakpoint(url string) *RemoveXHRBreakpointParams {\n\treturn &RemoveXHRBreakpointParams{\n\t\tURL: url,\n\t}\n}\n\n// Do executes DOMDebugger.removeXHRBreakpoint against the provided context.\nfunc (p *RemoveXHRBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveXHRBreakpoint, p, nil)\n}\n\n// SetBreakOnCSPViolationParams sets breakpoint on particular CSP violations.\ntype SetBreakOnCSPViolationParams struct {\n\tViolationTypes []CSPViolationType `json:\"violationTypes\"` // CSP Violations to stop upon.\n}\n\n// SetBreakOnCSPViolation sets breakpoint on particular CSP violations.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-setBreakOnCSPViolation\n//\n// parameters:\n//\n//\tviolationTypes - CSP Violations to stop upon.\nfunc SetBreakOnCSPViolation(violationTypes []CSPViolationType) *SetBreakOnCSPViolationParams {\n\treturn &SetBreakOnCSPViolationParams{\n\t\tViolationTypes: violationTypes,\n\t}\n}\n\n// Do executes DOMDebugger.setBreakOnCSPViolation against the provided context.\nfunc (p *SetBreakOnCSPViolationParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBreakOnCSPViolation, p, nil)\n}\n\n// SetDOMBreakpointParams sets breakpoint on particular operation with DOM.\ntype SetDOMBreakpointParams struct {\n\tNodeID cdp.NodeID        `json:\"nodeId\"` // Identifier of the node to set breakpoint on.\n\tType   DOMBreakpointType `json:\"type\"`   // Type of the operation to stop upon.\n}\n\n// SetDOMBreakpoint sets breakpoint on particular operation with DOM.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-setDOMBreakpoint\n//\n// parameters:\n//\n//\tnodeID - Identifier of the node to set breakpoint on.\n//\ttype - Type of the operation to stop upon.\nfunc SetDOMBreakpoint(nodeID cdp.NodeID, typeVal DOMBreakpointType) *SetDOMBreakpointParams {\n\treturn &SetDOMBreakpointParams{\n\t\tNodeID: nodeID,\n\t\tType:   typeVal,\n\t}\n}\n\n// Do executes DOMDebugger.setDOMBreakpoint against the provided context.\nfunc (p *SetDOMBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDOMBreakpoint, p, nil)\n}\n\n// SetEventListenerBreakpointParams sets breakpoint on particular DOM event.\ntype SetEventListenerBreakpointParams struct {\n\tEventName  string `json:\"eventName\"`                     // DOM Event name to stop on (any DOM event will do).\n\tTargetName string `json:\"targetName,omitempty,omitzero\"` // EventTarget interface name to stop on. If equal to \"*\" or not provided, will stop on any EventTarget.\n}\n\n// SetEventListenerBreakpoint sets breakpoint on particular DOM event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-setEventListenerBreakpoint\n//\n// parameters:\n//\n//\teventName - DOM Event name to stop on (any DOM event will do).\nfunc SetEventListenerBreakpoint(eventName string) *SetEventListenerBreakpointParams {\n\treturn &SetEventListenerBreakpointParams{\n\t\tEventName: eventName,\n\t}\n}\n\n// WithTargetName eventTarget interface name to stop on. If equal to \"*\" or\n// not provided, will stop on any EventTarget.\nfunc (p SetEventListenerBreakpointParams) WithTargetName(targetName string) *SetEventListenerBreakpointParams {\n\tp.TargetName = targetName\n\treturn &p\n}\n\n// Do executes DOMDebugger.setEventListenerBreakpoint against the provided context.\nfunc (p *SetEventListenerBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetEventListenerBreakpoint, p, nil)\n}\n\n// SetXHRBreakpointParams sets breakpoint on XMLHttpRequest.\ntype SetXHRBreakpointParams struct {\n\tURL string `json:\"url\"` // Resource URL substring. All XHRs having this substring in the URL will get stopped upon.\n}\n\n// SetXHRBreakpoint sets breakpoint on XMLHttpRequest.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#method-setXHRBreakpoint\n//\n// parameters:\n//\n//\turl - Resource URL substring. All XHRs having this substring in the URL will get stopped upon.\nfunc SetXHRBreakpoint(url string) *SetXHRBreakpointParams {\n\treturn &SetXHRBreakpointParams{\n\t\tURL: url,\n\t}\n}\n\n// Do executes DOMDebugger.setXHRBreakpoint against the provided context.\nfunc (p *SetXHRBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetXHRBreakpoint, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandGetEventListeners             = \"DOMDebugger.getEventListeners\"\n\tCommandRemoveDOMBreakpoint           = \"DOMDebugger.removeDOMBreakpoint\"\n\tCommandRemoveEventListenerBreakpoint = \"DOMDebugger.removeEventListenerBreakpoint\"\n\tCommandRemoveXHRBreakpoint           = \"DOMDebugger.removeXHRBreakpoint\"\n\tCommandSetBreakOnCSPViolation        = \"DOMDebugger.setBreakOnCSPViolation\"\n\tCommandSetDOMBreakpoint              = \"DOMDebugger.setDOMBreakpoint\"\n\tCommandSetEventListenerBreakpoint    = \"DOMDebugger.setEventListenerBreakpoint\"\n\tCommandSetXHRBreakpoint              = \"DOMDebugger.setXHRBreakpoint\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/domdebugger/types.go",
    "content": "package domdebugger\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// DOMBreakpointType DOM breakpoint type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#type-DOMBreakpointType\ntype DOMBreakpointType string\n\n// String returns the DOMBreakpointType as string value.\nfunc (t DOMBreakpointType) String() string {\n\treturn string(t)\n}\n\n// DOMBreakpointType values.\nconst (\n\tDOMBreakpointTypeSubtreeModified   DOMBreakpointType = \"subtree-modified\"\n\tDOMBreakpointTypeAttributeModified DOMBreakpointType = \"attribute-modified\"\n\tDOMBreakpointTypeNodeRemoved       DOMBreakpointType = \"node-removed\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DOMBreakpointType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DOMBreakpointType(s) {\n\tcase DOMBreakpointTypeSubtreeModified:\n\t\t*t = DOMBreakpointTypeSubtreeModified\n\tcase DOMBreakpointTypeAttributeModified:\n\t\t*t = DOMBreakpointTypeAttributeModified\n\tcase DOMBreakpointTypeNodeRemoved:\n\t\t*t = DOMBreakpointTypeNodeRemoved\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DOMBreakpointType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CSPViolationType cSP Violation type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#type-CSPViolationType\ntype CSPViolationType string\n\n// String returns the CSPViolationType as string value.\nfunc (t CSPViolationType) String() string {\n\treturn string(t)\n}\n\n// CSPViolationType values.\nconst (\n\tCSPViolationTypeTrustedtypeSinkViolation   CSPViolationType = \"trustedtype-sink-violation\"\n\tCSPViolationTypeTrustedtypePolicyViolation CSPViolationType = \"trustedtype-policy-violation\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CSPViolationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CSPViolationType(s) {\n\tcase CSPViolationTypeTrustedtypeSinkViolation:\n\t\t*t = CSPViolationTypeTrustedtypeSinkViolation\n\tcase CSPViolationTypeTrustedtypePolicyViolation:\n\t\t*t = CSPViolationTypeTrustedtypePolicyViolation\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CSPViolationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// EventListener object event listener.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger#type-EventListener\ntype EventListener struct {\n\tType            string                `json:\"type\"`                               // EventListener's type.\n\tUseCapture      bool                  `json:\"useCapture\"`                         // EventListener's useCapture.\n\tPassive         bool                  `json:\"passive\"`                            // EventListener's passive flag.\n\tOnce            bool                  `json:\"once\"`                               // EventListener's once flag.\n\tScriptID        runtime.ScriptID      `json:\"scriptId\"`                           // Script id of the handler code.\n\tLineNumber      int64                 `json:\"lineNumber\"`                         // Line number in the script (0-based).\n\tColumnNumber    int64                 `json:\"columnNumber\"`                       // Column number in the script (0-based).\n\tHandler         *runtime.RemoteObject `json:\"handler,omitempty,omitzero\"`         // Event handler function value.\n\tOriginalHandler *runtime.RemoteObject `json:\"originalHandler,omitempty,omitzero\"` // Event original handler function value.\n\tBackendNodeID   cdp.BackendNodeID     `json:\"backendNodeId,omitempty,omitzero\"`   // Node the listener is added to (if any).\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/domsnapshot/domsnapshot.go",
    "content": "// Package domsnapshot provides the Chrome DevTools Protocol\n// commands, types, and events for the DOMSnapshot domain.\n//\n// This domain facilitates obtaining document snapshots with DOM, layout, and\n// style information.\n//\n// Generated by the cdproto-gen command.\npackage domsnapshot\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// DisableParams disables DOM snapshot agent for the given page.\ntype DisableParams struct{}\n\n// Disable disables DOM snapshot agent for the given page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes DOMSnapshot.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables DOM snapshot agent for the given page.\ntype EnableParams struct{}\n\n// Enable enables DOM snapshot agent for the given page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes DOMSnapshot.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// CaptureSnapshotParams returns a document snapshot, including the full DOM\n// tree of the root node (including iframes, template contents, and imported\n// documents) in a flattened array, as well as layout and white-listed computed\n// style information for the nodes. Shadow DOM in the returned DOM tree is\n// flattened.\ntype CaptureSnapshotParams struct {\n\tComputedStyles                 []string `json:\"computedStyles\"`                 // Whitelist of computed styles to return.\n\tIncludePaintOrder              bool     `json:\"includePaintOrder\"`              // Whether to include layout object paint orders into the snapshot.\n\tIncludeDOMRects                bool     `json:\"includeDOMRects\"`                // Whether to include DOM rectangles (offsetRects, clientRects, scrollRects) into the snapshot\n\tIncludeBlendedBackgroundColors bool     `json:\"includeBlendedBackgroundColors\"` // Whether to include blended background colors in the snapshot (default: false). Blended background color is achieved by blending background colors of all elements that overlap with the current element.\n\tIncludeTextColorOpacities      bool     `json:\"includeTextColorOpacities\"`      // Whether to include text color opacity in the snapshot (default: false). An element might have the opacity property set that affects the text color of the element. The final text color opacity is computed based on the opacity of all overlapping elements.\n}\n\n// CaptureSnapshot returns a document snapshot, including the full DOM tree\n// of the root node (including iframes, template contents, and imported\n// documents) in a flattened array, as well as layout and white-listed computed\n// style information for the nodes. Shadow DOM in the returned DOM tree is\n// flattened.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#method-captureSnapshot\n//\n// parameters:\n//\n//\tcomputedStyles - Whitelist of computed styles to return.\nfunc CaptureSnapshot(computedStyles []string) *CaptureSnapshotParams {\n\treturn &CaptureSnapshotParams{\n\t\tComputedStyles:                 computedStyles,\n\t\tIncludePaintOrder:              false,\n\t\tIncludeDOMRects:                false,\n\t\tIncludeBlendedBackgroundColors: false,\n\t\tIncludeTextColorOpacities:      false,\n\t}\n}\n\n// WithIncludePaintOrder whether to include layout object paint orders into\n// the snapshot.\nfunc (p CaptureSnapshotParams) WithIncludePaintOrder(includePaintOrder bool) *CaptureSnapshotParams {\n\tp.IncludePaintOrder = includePaintOrder\n\treturn &p\n}\n\n// WithIncludeDOMRects whether to include DOM rectangles (offsetRects,\n// clientRects, scrollRects) into the snapshot.\nfunc (p CaptureSnapshotParams) WithIncludeDOMRects(includeDOMRects bool) *CaptureSnapshotParams {\n\tp.IncludeDOMRects = includeDOMRects\n\treturn &p\n}\n\n// WithIncludeBlendedBackgroundColors whether to include blended background\n// colors in the snapshot (default: false). Blended background color is achieved\n// by blending background colors of all elements that overlap with the current\n// element.\nfunc (p CaptureSnapshotParams) WithIncludeBlendedBackgroundColors(includeBlendedBackgroundColors bool) *CaptureSnapshotParams {\n\tp.IncludeBlendedBackgroundColors = includeBlendedBackgroundColors\n\treturn &p\n}\n\n// WithIncludeTextColorOpacities whether to include text color opacity in the\n// snapshot (default: false). An element might have the opacity property set\n// that affects the text color of the element. The final text color opacity is\n// computed based on the opacity of all overlapping elements.\nfunc (p CaptureSnapshotParams) WithIncludeTextColorOpacities(includeTextColorOpacities bool) *CaptureSnapshotParams {\n\tp.IncludeTextColorOpacities = includeTextColorOpacities\n\treturn &p\n}\n\n// CaptureSnapshotReturns return values.\ntype CaptureSnapshotReturns struct {\n\tDocuments []*DocumentSnapshot `json:\"documents,omitempty,omitzero\"` // The nodes in the DOM tree. The DOMNode at index 0 corresponds to the root document.\n\tStrings   []string            `json:\"strings,omitempty,omitzero\"`   // Shared string table that all string properties refer to with indexes.\n}\n\n// Do executes DOMSnapshot.captureSnapshot against the provided context.\n//\n// returns:\n//\n//\tdocuments - The nodes in the DOM tree. The DOMNode at index 0 corresponds to the root document.\n//\tstrings - Shared string table that all string properties refer to with indexes.\nfunc (p *CaptureSnapshotParams) Do(ctx context.Context) (documents []*DocumentSnapshot, strings []string, err error) {\n\t// execute\n\tvar res CaptureSnapshotReturns\n\terr = cdp.Execute(ctx, CommandCaptureSnapshot, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.Documents, res.Strings, nil\n}\n\n// Command names.\nconst (\n\tCommandDisable         = \"DOMSnapshot.disable\"\n\tCommandEnable          = \"DOMSnapshot.enable\"\n\tCommandCaptureSnapshot = \"DOMSnapshot.captureSnapshot\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/domsnapshot/types.go",
    "content": "package domsnapshot\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/chromedp/cdproto/domdebugger\"\n)\n\n// DOMNode a Node in the DOM tree.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-DOMNode\ntype DOMNode struct {\n\tNodeType             cdp.NodeType                 `json:\"nodeType\"`                                // Node's nodeType.\n\tNodeName             string                       `json:\"nodeName\"`                                // Node's nodeName.\n\tNodeValue            string                       `json:\"nodeValue\"`                               // Node's nodeValue.\n\tTextValue            string                       `json:\"textValue,omitempty,omitzero\"`            // Only set for textarea elements, contains the text value.\n\tInputValue           string                       `json:\"inputValue,omitempty,omitzero\"`           // Only set for input elements, contains the input's associated text value.\n\tInputChecked         bool                         `json:\"inputChecked\"`                            // Only set for radio and checkbox input elements, indicates if the element has been checked\n\tOptionSelected       bool                         `json:\"optionSelected\"`                          // Only set for option elements, indicates if the element has been selected\n\tBackendNodeID        cdp.BackendNodeID            `json:\"backendNodeId\"`                           // Node's id, corresponds to DOM.Node.backendNodeId.\n\tChildNodeIndexes     []int64                      `json:\"childNodeIndexes,omitempty,omitzero\"`     // The indexes of the node's child nodes in the domNodes array returned by getSnapshot, if any.\n\tAttributes           []*NameValue                 `json:\"attributes,omitempty,omitzero\"`           // Attributes of an Element node.\n\tPseudoElementIndexes []int64                      `json:\"pseudoElementIndexes,omitempty,omitzero\"` // Indexes of pseudo elements associated with this node in the domNodes array returned by getSnapshot, if any.\n\tLayoutNodeIndex      int64                        `json:\"layoutNodeIndex,omitempty,omitzero\"`      // The index of the node's related layout tree node in the layoutTreeNodes array returned by getSnapshot, if any.\n\tDocumentURL          string                       `json:\"documentURL,omitempty,omitzero\"`          // Document URL that Document or FrameOwner node points to.\n\tBaseURL              string                       `json:\"baseURL,omitempty,omitzero\"`              // Base URL that Document or FrameOwner node uses for URL completion.\n\tContentLanguage      string                       `json:\"contentLanguage,omitempty,omitzero\"`      // Only set for documents, contains the document's content language.\n\tDocumentEncoding     string                       `json:\"documentEncoding,omitempty,omitzero\"`     // Only set for documents, contains the document's character set encoding.\n\tPublicID             string                       `json:\"publicId,omitempty,omitzero\"`             // DocumentType node's publicId.\n\tSystemID             string                       `json:\"systemId,omitempty,omitzero\"`             // DocumentType node's systemId.\n\tFrameID              cdp.FrameID                  `json:\"frameId,omitempty,omitzero\"`              // Frame ID for frame owner elements and also for the document node.\n\tContentDocumentIndex int64                        `json:\"contentDocumentIndex,omitempty,omitzero\"` // The index of a frame owner element's content document in the domNodes array returned by getSnapshot, if any.\n\tPseudoType           cdp.PseudoType               `json:\"pseudoType,omitempty,omitzero\"`           // Type of a pseudo element node.\n\tShadowRootType       cdp.ShadowRootType           `json:\"shadowRootType,omitempty,omitzero\"`       // Shadow root type.\n\tIsClickable          bool                         `json:\"isClickable\"`                             // Whether this DOM node responds to mouse clicks. This includes nodes that have had click event listeners attached via JavaScript as well as anchor tags that naturally navigate when clicked.\n\tEventListeners       []*domdebugger.EventListener `json:\"eventListeners,omitempty,omitzero\"`       // Details of the node's event listeners, if any.\n\tCurrentSourceURL     string                       `json:\"currentSourceURL,omitempty,omitzero\"`     // The selected url for nodes with a srcset attribute.\n\tOriginURL            string                       `json:\"originURL,omitempty,omitzero\"`            // The url of the script (if any) that generates this node.\n\tScrollOffsetX        float64                      `json:\"scrollOffsetX,omitempty,omitzero\"`        // Scroll offsets, set when this node is a Document.\n\tScrollOffsetY        float64                      `json:\"scrollOffsetY,omitempty,omitzero\"`\n}\n\n// InlineTextBox details of post layout rendered text positions. The exact\n// layout should not be regarded as stable and may change between versions.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-InlineTextBox\ntype InlineTextBox struct {\n\tBoundingBox         *dom.Rect `json:\"boundingBox\"`         // The bounding box in document coordinates. Note that scroll offset of the document is ignored.\n\tStartCharacterIndex int64     `json:\"startCharacterIndex\"` // The starting index in characters, for this post layout textbox substring. Characters that would be represented as a surrogate pair in UTF-16 have length 2.\n\tNumCharacters       int64     `json:\"numCharacters\"`       // The number of characters in this post layout textbox substring. Characters that would be represented as a surrogate pair in UTF-16 have length 2.\n}\n\n// LayoutTreeNode details of an element in the DOM tree with a LayoutObject.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-LayoutTreeNode\ntype LayoutTreeNode struct {\n\tDomNodeIndex      int64            `json:\"domNodeIndex\"`                       // The index of the related DOM node in the domNodes array returned by getSnapshot.\n\tBoundingBox       *dom.Rect        `json:\"boundingBox\"`                        // The bounding box in document coordinates. Note that scroll offset of the document is ignored.\n\tLayoutText        string           `json:\"layoutText,omitempty,omitzero\"`      // Contents of the LayoutText, if any.\n\tInlineTextNodes   []*InlineTextBox `json:\"inlineTextNodes,omitempty,omitzero\"` // The post-layout inline text nodes, if any.\n\tStyleIndex        int64            `json:\"styleIndex,omitempty,omitzero\"`      // Index into the computedStyles array returned by getSnapshot.\n\tPaintOrder        int64            `json:\"paintOrder,omitempty,omitzero\"`      // Global paint order index, which is determined by the stacking order of the nodes. Nodes that are painted together will have the same index. Only provided if includePaintOrder in getSnapshot was true.\n\tIsStackingContext bool             `json:\"isStackingContext\"`                  // Set to true to indicate the element begins a new stacking context.\n}\n\n// ComputedStyle a subset of the full ComputedStyle as defined by the request\n// whitelist.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-ComputedStyle\ntype ComputedStyle struct {\n\tProperties []*NameValue `json:\"properties\"` // Name/value pairs of computed style properties.\n}\n\n// NameValue a name/value pair.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-NameValue\ntype NameValue struct {\n\tName  string `json:\"name\"`  // Attribute/property name.\n\tValue string `json:\"value\"` // Attribute/property value.\n}\n\n// StringIndex index of the string in the strings table.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-StringIndex\ntype StringIndex int64\n\n// Int64 returns the StringIndex as int64 value.\nfunc (t StringIndex) Int64() int64 {\n\treturn int64(t)\n}\n\n// ArrayOfStrings index of the string in the strings table.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-ArrayOfStrings\ntype ArrayOfStrings []int64\n\n// RareStringData data that is only present on rare nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-RareStringData\ntype RareStringData struct {\n\tIndex []int64       `json:\"index\"`\n\tValue []StringIndex `json:\"value\"`\n}\n\n// RareBooleanData [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-RareBooleanData\ntype RareBooleanData struct {\n\tIndex []int64 `json:\"index\"`\n}\n\n// RareIntegerData [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-RareIntegerData\ntype RareIntegerData struct {\n\tIndex []int64 `json:\"index\"`\n\tValue []int64 `json:\"value\"`\n}\n\n// Rectangle [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-Rectangle\ntype Rectangle []float64\n\n// DocumentSnapshot document snapshot.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-DocumentSnapshot\ntype DocumentSnapshot struct {\n\tDocumentURL     StringIndex         `json:\"documentURL\"`                      // Document URL that Document or FrameOwner node points to.\n\tTitle           StringIndex         `json:\"title\"`                            // Document title.\n\tBaseURL         StringIndex         `json:\"baseURL\"`                          // Base URL that Document or FrameOwner node uses for URL completion.\n\tContentLanguage StringIndex         `json:\"contentLanguage\"`                  // Contains the document's content language.\n\tEncodingName    StringIndex         `json:\"encodingName\"`                     // Contains the document's character set encoding.\n\tPublicID        StringIndex         `json:\"publicId\"`                         // DocumentType node's publicId.\n\tSystemID        StringIndex         `json:\"systemId\"`                         // DocumentType node's systemId.\n\tFrameID         StringIndex         `json:\"frameId\"`                          // Frame ID for frame owner elements and also for the document node.\n\tNodes           *NodeTreeSnapshot   `json:\"nodes\"`                            // A table with dom nodes.\n\tLayout          *LayoutTreeSnapshot `json:\"layout\"`                           // The nodes in the layout tree.\n\tTextBoxes       *TextBoxSnapshot    `json:\"textBoxes\"`                        // The post-layout inline text nodes.\n\tScrollOffsetX   float64             `json:\"scrollOffsetX,omitempty,omitzero\"` // Horizontal scroll offset.\n\tScrollOffsetY   float64             `json:\"scrollOffsetY,omitempty,omitzero\"` // Vertical scroll offset.\n\tContentWidth    float64             `json:\"contentWidth,omitempty,omitzero\"`  // Document content width.\n\tContentHeight   float64             `json:\"contentHeight,omitempty,omitzero\"` // Document content height.\n}\n\n// NodeTreeSnapshot table containing nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-NodeTreeSnapshot\ntype NodeTreeSnapshot struct {\n\tParentIndex          []int64             `json:\"parentIndex,omitempty,omitzero\"`          // Parent node index.\n\tNodeType             []int64             `json:\"nodeType,omitempty,omitzero\"`             // Node's nodeType.\n\tShadowRootType       *RareStringData     `json:\"shadowRootType,omitempty,omitzero\"`       // Type of the shadow root the Node is in. String values are equal to the ShadowRootType enum.\n\tNodeName             []StringIndex       `json:\"nodeName,omitempty,omitzero\"`             // Node's nodeName.\n\tNodeValue            []StringIndex       `json:\"nodeValue,omitempty,omitzero\"`            // Node's nodeValue.\n\tBackendNodeID        []cdp.BackendNodeID `json:\"backendNodeId,omitempty,omitzero\"`        // Node's id, corresponds to DOM.Node.backendNodeId.\n\tAttributes           []ArrayOfStrings    `json:\"attributes,omitempty,omitzero\"`           // Attributes of an Element node. Flatten name, value pairs.\n\tTextValue            *RareStringData     `json:\"textValue,omitempty,omitzero\"`            // Only set for textarea elements, contains the text value.\n\tInputValue           *RareStringData     `json:\"inputValue,omitempty,omitzero\"`           // Only set for input elements, contains the input's associated text value.\n\tInputChecked         *RareBooleanData    `json:\"inputChecked,omitempty,omitzero\"`         // Only set for radio and checkbox input elements, indicates if the element has been checked\n\tOptionSelected       *RareBooleanData    `json:\"optionSelected,omitempty,omitzero\"`       // Only set for option elements, indicates if the element has been selected\n\tContentDocumentIndex *RareIntegerData    `json:\"contentDocumentIndex,omitempty,omitzero\"` // The index of the document in the list of the snapshot documents.\n\tPseudoType           *RareStringData     `json:\"pseudoType,omitempty,omitzero\"`           // Type of a pseudo element node.\n\tPseudoIdentifier     *RareStringData     `json:\"pseudoIdentifier,omitempty,omitzero\"`     // Pseudo element identifier for this node. Only present if there is a valid pseudoType.\n\tIsClickable          *RareBooleanData    `json:\"isClickable,omitempty,omitzero\"`          // Whether this DOM node responds to mouse clicks. This includes nodes that have had click event listeners attached via JavaScript as well as anchor tags that naturally navigate when clicked.\n\tCurrentSourceURL     *RareStringData     `json:\"currentSourceURL,omitempty,omitzero\"`     // The selected url for nodes with a srcset attribute.\n\tOriginURL            *RareStringData     `json:\"originURL,omitempty,omitzero\"`            // The url of the script (if any) that generates this node.\n}\n\n// LayoutTreeSnapshot table of details of an element in the DOM tree with a\n// LayoutObject.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-LayoutTreeSnapshot\ntype LayoutTreeSnapshot struct {\n\tNodeIndex               []int64          `json:\"nodeIndex\"`                                  // Index of the corresponding node in the NodeTreeSnapshot array returned by captureSnapshot.\n\tStyles                  []ArrayOfStrings `json:\"styles\"`                                     // Array of indexes specifying computed style strings, filtered according to the computedStyles parameter passed to captureSnapshot.\n\tBounds                  []Rectangle      `json:\"bounds\"`                                     // The absolute position bounding box.\n\tText                    []StringIndex    `json:\"text\"`                                       // Contents of the LayoutText, if any.\n\tStackingContexts        *RareBooleanData `json:\"stackingContexts\"`                           // Stacking context information.\n\tPaintOrders             []int64          `json:\"paintOrders,omitempty,omitzero\"`             // Global paint order index, which is determined by the stacking order of the nodes. Nodes that are painted together will have the same index. Only provided if includePaintOrder in captureSnapshot was true.\n\tOffsetRects             []Rectangle      `json:\"offsetRects,omitempty,omitzero\"`             // The offset rect of nodes. Only available when includeDOMRects is set to true\n\tScrollRects             []Rectangle      `json:\"scrollRects,omitempty,omitzero\"`             // The scroll rect of nodes. Only available when includeDOMRects is set to true\n\tClientRects             []Rectangle      `json:\"clientRects,omitempty,omitzero\"`             // The client rect of nodes. Only available when includeDOMRects is set to true\n\tBlendedBackgroundColors []StringIndex    `json:\"blendedBackgroundColors,omitempty,omitzero\"` // The list of background colors that are blended with colors of overlapping elements.\n\tTextColorOpacities      []float64        `json:\"textColorOpacities,omitempty,omitzero\"`      // The list of computed text opacities.\n}\n\n// TextBoxSnapshot table of details of the post layout rendered text\n// positions. The exact layout should not be regarded as stable and may change\n// between versions.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMSnapshot#type-TextBoxSnapshot\ntype TextBoxSnapshot struct {\n\tLayoutIndex []int64     `json:\"layoutIndex\"` // Index of the layout tree node that owns this box collection.\n\tBounds      []Rectangle `json:\"bounds\"`      // The absolute position bounding box.\n\tStart       []int64     `json:\"start\"`       // The starting index in characters, for this post layout textbox substring. Characters that would be represented as a surrogate pair in UTF-16 have length 2.\n\tLength      []int64     `json:\"length\"`      // The number of characters in this post layout textbox substring. Characters that would be represented as a surrogate pair in UTF-16 have length 2.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/domstorage/domstorage.go",
    "content": "// Package domstorage provides the Chrome DevTools Protocol\n// commands, types, and events for the DOMStorage domain.\n//\n// Query and modify DOM storage.\n//\n// Generated by the cdproto-gen command.\npackage domstorage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// ClearParams [no description].\ntype ClearParams struct {\n\tStorageID *StorageID `json:\"storageId\"`\n}\n\n// Clear [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#method-clear\n//\n// parameters:\n//\n//\tstorageID\nfunc Clear(storageID *StorageID) *ClearParams {\n\treturn &ClearParams{\n\t\tStorageID: storageID,\n\t}\n}\n\n// Do executes DOMStorage.clear against the provided context.\nfunc (p *ClearParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClear, p, nil)\n}\n\n// DisableParams disables storage tracking, prevents storage events from\n// being sent to the client.\ntype DisableParams struct{}\n\n// Disable disables storage tracking, prevents storage events from being sent\n// to the client.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes DOMStorage.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables storage tracking, storage events will now be\n// delivered to the client.\ntype EnableParams struct{}\n\n// Enable enables storage tracking, storage events will now be delivered to\n// the client.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes DOMStorage.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// GetDOMStorageItemsParams [no description].\ntype GetDOMStorageItemsParams struct {\n\tStorageID *StorageID `json:\"storageId\"`\n}\n\n// GetDOMStorageItems [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#method-getDOMStorageItems\n//\n// parameters:\n//\n//\tstorageID\nfunc GetDOMStorageItems(storageID *StorageID) *GetDOMStorageItemsParams {\n\treturn &GetDOMStorageItemsParams{\n\t\tStorageID: storageID,\n\t}\n}\n\n// GetDOMStorageItemsReturns return values.\ntype GetDOMStorageItemsReturns struct {\n\tEntries []Item `json:\"entries,omitempty,omitzero\"`\n}\n\n// Do executes DOMStorage.getDOMStorageItems against the provided context.\n//\n// returns:\n//\n//\tentries\nfunc (p *GetDOMStorageItemsParams) Do(ctx context.Context) (entries []Item, err error) {\n\t// execute\n\tvar res GetDOMStorageItemsReturns\n\terr = cdp.Execute(ctx, CommandGetDOMStorageItems, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Entries, nil\n}\n\n// RemoveDOMStorageItemParams [no description].\ntype RemoveDOMStorageItemParams struct {\n\tStorageID *StorageID `json:\"storageId\"`\n\tKey       string     `json:\"key\"`\n}\n\n// RemoveDOMStorageItem [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#method-removeDOMStorageItem\n//\n// parameters:\n//\n//\tstorageID\n//\tkey\nfunc RemoveDOMStorageItem(storageID *StorageID, key string) *RemoveDOMStorageItemParams {\n\treturn &RemoveDOMStorageItemParams{\n\t\tStorageID: storageID,\n\t\tKey:       key,\n\t}\n}\n\n// Do executes DOMStorage.removeDOMStorageItem against the provided context.\nfunc (p *RemoveDOMStorageItemParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveDOMStorageItem, p, nil)\n}\n\n// SetDOMStorageItemParams [no description].\ntype SetDOMStorageItemParams struct {\n\tStorageID *StorageID `json:\"storageId\"`\n\tKey       string     `json:\"key\"`\n\tValue     string     `json:\"value\"`\n}\n\n// SetDOMStorageItem [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#method-setDOMStorageItem\n//\n// parameters:\n//\n//\tstorageID\n//\tkey\n//\tvalue\nfunc SetDOMStorageItem(storageID *StorageID, key string, value string) *SetDOMStorageItemParams {\n\treturn &SetDOMStorageItemParams{\n\t\tStorageID: storageID,\n\t\tKey:       key,\n\t\tValue:     value,\n\t}\n}\n\n// Do executes DOMStorage.setDOMStorageItem against the provided context.\nfunc (p *SetDOMStorageItemParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDOMStorageItem, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandClear                = \"DOMStorage.clear\"\n\tCommandDisable              = \"DOMStorage.disable\"\n\tCommandEnable               = \"DOMStorage.enable\"\n\tCommandGetDOMStorageItems   = \"DOMStorage.getDOMStorageItems\"\n\tCommandRemoveDOMStorageItem = \"DOMStorage.removeDOMStorageItem\"\n\tCommandSetDOMStorageItem    = \"DOMStorage.setDOMStorageItem\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/domstorage/events.go",
    "content": "package domstorage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventDomStorageItemAdded [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#event-domStorageItemAdded\ntype EventDomStorageItemAdded struct {\n\tStorageID *StorageID `json:\"storageId\"`\n\tKey       string     `json:\"key\"`\n\tNewValue  string     `json:\"newValue\"`\n}\n\n// EventDomStorageItemRemoved [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#event-domStorageItemRemoved\ntype EventDomStorageItemRemoved struct {\n\tStorageID *StorageID `json:\"storageId\"`\n\tKey       string     `json:\"key\"`\n}\n\n// EventDomStorageItemUpdated [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#event-domStorageItemUpdated\ntype EventDomStorageItemUpdated struct {\n\tStorageID *StorageID `json:\"storageId\"`\n\tKey       string     `json:\"key\"`\n\tOldValue  string     `json:\"oldValue\"`\n\tNewValue  string     `json:\"newValue\"`\n}\n\n// EventDomStorageItemsCleared [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#event-domStorageItemsCleared\ntype EventDomStorageItemsCleared struct {\n\tStorageID *StorageID `json:\"storageId\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/domstorage/types.go",
    "content": "package domstorage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// SerializedStorageKey [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#type-SerializedStorageKey\ntype SerializedStorageKey string\n\n// String returns the SerializedStorageKey as string value.\nfunc (t SerializedStorageKey) String() string {\n\treturn string(t)\n}\n\n// StorageID DOM Storage identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#type-StorageId\ntype StorageID struct {\n\tSecurityOrigin string               `json:\"securityOrigin,omitempty,omitzero\"` // Security origin for the storage.\n\tStorageKey     SerializedStorageKey `json:\"storageKey,omitempty,omitzero\"`     // Represents a key by which DOM Storage keys its CachedStorageAreas\n\tIsLocalStorage bool                 `json:\"isLocalStorage\"`                    // Whether the storage is local storage (not session storage).\n}\n\n// Item DOM Storage item.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/DOMStorage#type-Item\ntype Item []string\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/emulation/emulation.go",
    "content": "// Package emulation provides the Chrome DevTools Protocol\n// commands, types, and events for the Emulation domain.\n//\n// This domain emulates different environments for the page.\n//\n// Generated by the cdproto-gen command.\npackage emulation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/page\"\n)\n\n// ClearDeviceMetricsOverrideParams clears the overridden device metrics.\ntype ClearDeviceMetricsOverrideParams struct{}\n\n// ClearDeviceMetricsOverride clears the overridden device metrics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-clearDeviceMetricsOverride\nfunc ClearDeviceMetricsOverride() *ClearDeviceMetricsOverrideParams {\n\treturn &ClearDeviceMetricsOverrideParams{}\n}\n\n// Do executes Emulation.clearDeviceMetricsOverride against the provided context.\nfunc (p *ClearDeviceMetricsOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearDeviceMetricsOverride, nil, nil)\n}\n\n// ClearGeolocationOverrideParams clears the overridden Geolocation Position\n// and Error.\ntype ClearGeolocationOverrideParams struct{}\n\n// ClearGeolocationOverride clears the overridden Geolocation Position and\n// Error.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-clearGeolocationOverride\nfunc ClearGeolocationOverride() *ClearGeolocationOverrideParams {\n\treturn &ClearGeolocationOverrideParams{}\n}\n\n// Do executes Emulation.clearGeolocationOverride against the provided context.\nfunc (p *ClearGeolocationOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearGeolocationOverride, nil, nil)\n}\n\n// ResetPageScaleFactorParams requests that page scale factor is reset to\n// initial values.\ntype ResetPageScaleFactorParams struct{}\n\n// ResetPageScaleFactor requests that page scale factor is reset to initial\n// values.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-resetPageScaleFactor\nfunc ResetPageScaleFactor() *ResetPageScaleFactorParams {\n\treturn &ResetPageScaleFactorParams{}\n}\n\n// Do executes Emulation.resetPageScaleFactor against the provided context.\nfunc (p *ResetPageScaleFactorParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandResetPageScaleFactor, nil, nil)\n}\n\n// SetFocusEmulationEnabledParams enables or disables simulating a focused\n// and active page.\ntype SetFocusEmulationEnabledParams struct {\n\tEnabled bool `json:\"enabled\"` // Whether to enable to disable focus emulation.\n}\n\n// SetFocusEmulationEnabled enables or disables simulating a focused and\n// active page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setFocusEmulationEnabled\n//\n// parameters:\n//\n//\tenabled - Whether to enable to disable focus emulation.\nfunc SetFocusEmulationEnabled(enabled bool) *SetFocusEmulationEnabledParams {\n\treturn &SetFocusEmulationEnabledParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Emulation.setFocusEmulationEnabled against the provided context.\nfunc (p *SetFocusEmulationEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetFocusEmulationEnabled, p, nil)\n}\n\n// SetAutoDarkModeOverrideParams automatically render all web contents using\n// a dark theme.\ntype SetAutoDarkModeOverrideParams struct {\n\tEnabled bool `json:\"enabled\"` // Whether to enable or disable automatic dark mode. If not specified, any existing override will be cleared.\n}\n\n// SetAutoDarkModeOverride automatically render all web contents using a dark\n// theme.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setAutoDarkModeOverride\n//\n// parameters:\nfunc SetAutoDarkModeOverride() *SetAutoDarkModeOverrideParams {\n\treturn &SetAutoDarkModeOverrideParams{\n\t\tEnabled: false,\n\t}\n}\n\n// WithEnabled whether to enable or disable automatic dark mode. If not\n// specified, any existing override will be cleared.\nfunc (p SetAutoDarkModeOverrideParams) WithEnabled(enabled bool) *SetAutoDarkModeOverrideParams {\n\tp.Enabled = enabled\n\treturn &p\n}\n\n// Do executes Emulation.setAutoDarkModeOverride against the provided context.\nfunc (p *SetAutoDarkModeOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAutoDarkModeOverride, p, nil)\n}\n\n// SetCPUThrottlingRateParams enables CPU throttling to emulate slow CPUs.\ntype SetCPUThrottlingRateParams struct {\n\tRate float64 `json:\"rate\"` // Throttling rate as a slowdown factor (1 is no throttle, 2 is 2x slowdown, etc).\n}\n\n// SetCPUThrottlingRate enables CPU throttling to emulate slow CPUs.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setCPUThrottlingRate\n//\n// parameters:\n//\n//\trate - Throttling rate as a slowdown factor (1 is no throttle, 2 is 2x slowdown, etc).\nfunc SetCPUThrottlingRate(rate float64) *SetCPUThrottlingRateParams {\n\treturn &SetCPUThrottlingRateParams{\n\t\tRate: rate,\n\t}\n}\n\n// Do executes Emulation.setCPUThrottlingRate against the provided context.\nfunc (p *SetCPUThrottlingRateParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCPUThrottlingRate, p, nil)\n}\n\n// SetDefaultBackgroundColorOverrideParams sets or clears an override of the\n// default background color of the frame. This override is used if the content\n// does not specify one.\ntype SetDefaultBackgroundColorOverrideParams struct {\n\tColor *cdp.RGBA `json:\"color,omitempty,omitzero\"` // RGBA of the default background color. If not specified, any existing override will be cleared.\n}\n\n// SetDefaultBackgroundColorOverride sets or clears an override of the\n// default background color of the frame. This override is used if the content\n// does not specify one.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setDefaultBackgroundColorOverride\n//\n// parameters:\nfunc SetDefaultBackgroundColorOverride() *SetDefaultBackgroundColorOverrideParams {\n\treturn &SetDefaultBackgroundColorOverrideParams{}\n}\n\n// WithColor rGBA of the default background color. If not specified, any\n// existing override will be cleared.\nfunc (p SetDefaultBackgroundColorOverrideParams) WithColor(color *cdp.RGBA) *SetDefaultBackgroundColorOverrideParams {\n\tp.Color = color\n\treturn &p\n}\n\n// Do executes Emulation.setDefaultBackgroundColorOverride against the provided context.\nfunc (p *SetDefaultBackgroundColorOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDefaultBackgroundColorOverride, p, nil)\n}\n\n// SetSafeAreaInsetsOverrideParams overrides the values for\n// env(safe-area-inset-*) and env(safe-area-max-inset-*). Unset values will\n// cause the respective variables to be undefined, even if previously\n// overridden.\ntype SetSafeAreaInsetsOverrideParams struct {\n\tInsets *SafeAreaInsets `json:\"insets\"`\n}\n\n// SetSafeAreaInsetsOverride overrides the values for env(safe-area-inset-*)\n// and env(safe-area-max-inset-*). Unset values will cause the respective\n// variables to be undefined, even if previously overridden.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setSafeAreaInsetsOverride\n//\n// parameters:\n//\n//\tinsets\nfunc SetSafeAreaInsetsOverride(insets *SafeAreaInsets) *SetSafeAreaInsetsOverrideParams {\n\treturn &SetSafeAreaInsetsOverrideParams{\n\t\tInsets: insets,\n\t}\n}\n\n// Do executes Emulation.setSafeAreaInsetsOverride against the provided context.\nfunc (p *SetSafeAreaInsetsOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSafeAreaInsetsOverride, p, nil)\n}\n\n// SetDeviceMetricsOverrideParams overrides the values of device screen\n// dimensions (window.screen.width, window.screen.height, window.innerWidth,\n// window.innerHeight, and \"device-width\"/\"device-height\"-related CSS media\n// query results).\ntype SetDeviceMetricsOverrideParams struct {\n\tWidth              int64              `json:\"width\"`                                // Overriding width value in pixels (minimum 0, maximum 10000000). 0 disables the override.\n\tHeight             int64              `json:\"height\"`                               // Overriding height value in pixels (minimum 0, maximum 10000000). 0 disables the override.\n\tDeviceScaleFactor  float64            `json:\"deviceScaleFactor\"`                    // Overriding device scale factor value. 0 disables the override.\n\tMobile             bool               `json:\"mobile\"`                               // Whether to emulate mobile device. This includes viewport meta tag, overlay scrollbars, text autosizing and more.\n\tScale              float64            `json:\"scale,omitempty,omitzero\"`             // Scale to apply to resulting view image.\n\tScreenWidth        int64              `json:\"screenWidth,omitempty,omitzero\"`       // Overriding screen width value in pixels (minimum 0, maximum 10000000).\n\tScreenHeight       int64              `json:\"screenHeight,omitempty,omitzero\"`      // Overriding screen height value in pixels (minimum 0, maximum 10000000).\n\tPositionX          int64              `json:\"positionX,omitempty,omitzero\"`         // Overriding view X position on screen in pixels (minimum 0, maximum 10000000).\n\tPositionY          int64              `json:\"positionY,omitempty,omitzero\"`         // Overriding view Y position on screen in pixels (minimum 0, maximum 10000000).\n\tDontSetVisibleSize bool               `json:\"dontSetVisibleSize\"`                   // Do not set visible view size, rely upon explicit setVisibleSize call.\n\tScreenOrientation  *ScreenOrientation `json:\"screenOrientation,omitempty,omitzero\"` // Screen orientation override.\n\tViewport           *page.Viewport     `json:\"viewport,omitempty,omitzero\"`          // If set, the visible area of the page will be overridden to this viewport. This viewport change is not observed by the page, e.g. viewport-relative elements do not change positions.\n}\n\n// SetDeviceMetricsOverride overrides the values of device screen dimensions\n// (window.screen.width, window.screen.height, window.innerWidth,\n// window.innerHeight, and \"device-width\"/\"device-height\"-related CSS media\n// query results).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setDeviceMetricsOverride\n//\n// parameters:\n//\n//\twidth - Overriding width value in pixels (minimum 0, maximum 10000000). 0 disables the override.\n//\theight - Overriding height value in pixels (minimum 0, maximum 10000000). 0 disables the override.\n//\tdeviceScaleFactor - Overriding device scale factor value. 0 disables the override.\n//\tmobile - Whether to emulate mobile device. This includes viewport meta tag, overlay scrollbars, text autosizing and more.\nfunc SetDeviceMetricsOverride(width int64, height int64, deviceScaleFactor float64, mobile bool) *SetDeviceMetricsOverrideParams {\n\treturn &SetDeviceMetricsOverrideParams{\n\t\tWidth:              width,\n\t\tHeight:             height,\n\t\tDeviceScaleFactor:  deviceScaleFactor,\n\t\tMobile:             mobile,\n\t\tDontSetVisibleSize: false,\n\t}\n}\n\n// WithScale scale to apply to resulting view image.\nfunc (p SetDeviceMetricsOverrideParams) WithScale(scale float64) *SetDeviceMetricsOverrideParams {\n\tp.Scale = scale\n\treturn &p\n}\n\n// WithScreenWidth overriding screen width value in pixels (minimum 0,\n// maximum 10000000).\nfunc (p SetDeviceMetricsOverrideParams) WithScreenWidth(screenWidth int64) *SetDeviceMetricsOverrideParams {\n\tp.ScreenWidth = screenWidth\n\treturn &p\n}\n\n// WithScreenHeight overriding screen height value in pixels (minimum 0,\n// maximum 10000000).\nfunc (p SetDeviceMetricsOverrideParams) WithScreenHeight(screenHeight int64) *SetDeviceMetricsOverrideParams {\n\tp.ScreenHeight = screenHeight\n\treturn &p\n}\n\n// WithPositionX overriding view X position on screen in pixels (minimum 0,\n// maximum 10000000).\nfunc (p SetDeviceMetricsOverrideParams) WithPositionX(positionX int64) *SetDeviceMetricsOverrideParams {\n\tp.PositionX = positionX\n\treturn &p\n}\n\n// WithPositionY overriding view Y position on screen in pixels (minimum 0,\n// maximum 10000000).\nfunc (p SetDeviceMetricsOverrideParams) WithPositionY(positionY int64) *SetDeviceMetricsOverrideParams {\n\tp.PositionY = positionY\n\treturn &p\n}\n\n// WithDontSetVisibleSize do not set visible view size, rely upon explicit\n// setVisibleSize call.\nfunc (p SetDeviceMetricsOverrideParams) WithDontSetVisibleSize(dontSetVisibleSize bool) *SetDeviceMetricsOverrideParams {\n\tp.DontSetVisibleSize = dontSetVisibleSize\n\treturn &p\n}\n\n// WithScreenOrientation screen orientation override.\nfunc (p SetDeviceMetricsOverrideParams) WithScreenOrientation(screenOrientation *ScreenOrientation) *SetDeviceMetricsOverrideParams {\n\tp.ScreenOrientation = screenOrientation\n\treturn &p\n}\n\n// WithViewport if set, the visible area of the page will be overridden to\n// this viewport. This viewport change is not observed by the page, e.g.\n// viewport-relative elements do not change positions.\nfunc (p SetDeviceMetricsOverrideParams) WithViewport(viewport *page.Viewport) *SetDeviceMetricsOverrideParams {\n\tp.Viewport = viewport\n\treturn &p\n}\n\n// Do executes Emulation.setDeviceMetricsOverride against the provided context.\nfunc (p *SetDeviceMetricsOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDeviceMetricsOverride, p, nil)\n}\n\n// SetDevicePostureOverrideParams start reporting the given posture value to\n// the Device Posture API. This override can also be set in\n// setDeviceMetricsOverride().\ntype SetDevicePostureOverrideParams struct {\n\tPosture *DevicePosture `json:\"posture\"`\n}\n\n// SetDevicePostureOverride start reporting the given posture value to the\n// Device Posture API. This override can also be set in\n// setDeviceMetricsOverride().\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setDevicePostureOverride\n//\n// parameters:\n//\n//\tposture\nfunc SetDevicePostureOverride(posture *DevicePosture) *SetDevicePostureOverrideParams {\n\treturn &SetDevicePostureOverrideParams{\n\t\tPosture: posture,\n\t}\n}\n\n// Do executes Emulation.setDevicePostureOverride against the provided context.\nfunc (p *SetDevicePostureOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDevicePostureOverride, p, nil)\n}\n\n// ClearDevicePostureOverrideParams clears a device posture override set with\n// either setDeviceMetricsOverride() or setDevicePostureOverride() and starts\n// using posture information from the platform again. Does nothing if no\n// override is set.\ntype ClearDevicePostureOverrideParams struct{}\n\n// ClearDevicePostureOverride clears a device posture override set with\n// either setDeviceMetricsOverride() or setDevicePostureOverride() and starts\n// using posture information from the platform again. Does nothing if no\n// override is set.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-clearDevicePostureOverride\nfunc ClearDevicePostureOverride() *ClearDevicePostureOverrideParams {\n\treturn &ClearDevicePostureOverrideParams{}\n}\n\n// Do executes Emulation.clearDevicePostureOverride against the provided context.\nfunc (p *ClearDevicePostureOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearDevicePostureOverride, nil, nil)\n}\n\n// SetDisplayFeaturesOverrideParams start using the given display features to\n// pupulate the Viewport Segments API. This override can also be set in\n// setDeviceMetricsOverride().\ntype SetDisplayFeaturesOverrideParams struct {\n\tFeatures []*DisplayFeature `json:\"features\"`\n}\n\n// SetDisplayFeaturesOverride start using the given display features to\n// pupulate the Viewport Segments API. This override can also be set in\n// setDeviceMetricsOverride().\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setDisplayFeaturesOverride\n//\n// parameters:\n//\n//\tfeatures\nfunc SetDisplayFeaturesOverride(features []*DisplayFeature) *SetDisplayFeaturesOverrideParams {\n\treturn &SetDisplayFeaturesOverrideParams{\n\t\tFeatures: features,\n\t}\n}\n\n// Do executes Emulation.setDisplayFeaturesOverride against the provided context.\nfunc (p *SetDisplayFeaturesOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDisplayFeaturesOverride, p, nil)\n}\n\n// ClearDisplayFeaturesOverrideParams clears the display features override\n// set with either setDeviceMetricsOverride() or setDisplayFeaturesOverride()\n// and starts using display features from the platform again. Does nothing if no\n// override is set.\ntype ClearDisplayFeaturesOverrideParams struct{}\n\n// ClearDisplayFeaturesOverride clears the display features override set with\n// either setDeviceMetricsOverride() or setDisplayFeaturesOverride() and starts\n// using display features from the platform again. Does nothing if no override\n// is set.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-clearDisplayFeaturesOverride\nfunc ClearDisplayFeaturesOverride() *ClearDisplayFeaturesOverrideParams {\n\treturn &ClearDisplayFeaturesOverrideParams{}\n}\n\n// Do executes Emulation.clearDisplayFeaturesOverride against the provided context.\nfunc (p *ClearDisplayFeaturesOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearDisplayFeaturesOverride, nil, nil)\n}\n\n// SetScrollbarsHiddenParams [no description].\ntype SetScrollbarsHiddenParams struct {\n\tHidden bool `json:\"hidden\"` // Whether scrollbars should be always hidden.\n}\n\n// SetScrollbarsHidden [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setScrollbarsHidden\n//\n// parameters:\n//\n//\thidden - Whether scrollbars should be always hidden.\nfunc SetScrollbarsHidden(hidden bool) *SetScrollbarsHiddenParams {\n\treturn &SetScrollbarsHiddenParams{\n\t\tHidden: hidden,\n\t}\n}\n\n// Do executes Emulation.setScrollbarsHidden against the provided context.\nfunc (p *SetScrollbarsHiddenParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetScrollbarsHidden, p, nil)\n}\n\n// SetDocumentCookieDisabledParams [no description].\ntype SetDocumentCookieDisabledParams struct {\n\tDisabled bool `json:\"disabled\"` // Whether document.coookie API should be disabled.\n}\n\n// SetDocumentCookieDisabled [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setDocumentCookieDisabled\n//\n// parameters:\n//\n//\tdisabled - Whether document.coookie API should be disabled.\nfunc SetDocumentCookieDisabled(disabled bool) *SetDocumentCookieDisabledParams {\n\treturn &SetDocumentCookieDisabledParams{\n\t\tDisabled: disabled,\n\t}\n}\n\n// Do executes Emulation.setDocumentCookieDisabled against the provided context.\nfunc (p *SetDocumentCookieDisabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDocumentCookieDisabled, p, nil)\n}\n\n// SetEmitTouchEventsForMouseParams [no description].\ntype SetEmitTouchEventsForMouseParams struct {\n\tEnabled       bool                                    `json:\"enabled\"`                          // Whether touch emulation based on mouse input should be enabled.\n\tConfiguration SetEmitTouchEventsForMouseConfiguration `json:\"configuration,omitempty,omitzero\"` // Touch/gesture events configuration. Default: current platform.\n}\n\n// SetEmitTouchEventsForMouse [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setEmitTouchEventsForMouse\n//\n// parameters:\n//\n//\tenabled - Whether touch emulation based on mouse input should be enabled.\nfunc SetEmitTouchEventsForMouse(enabled bool) *SetEmitTouchEventsForMouseParams {\n\treturn &SetEmitTouchEventsForMouseParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// WithConfiguration touch/gesture events configuration. Default: current\n// platform.\nfunc (p SetEmitTouchEventsForMouseParams) WithConfiguration(configuration SetEmitTouchEventsForMouseConfiguration) *SetEmitTouchEventsForMouseParams {\n\tp.Configuration = configuration\n\treturn &p\n}\n\n// Do executes Emulation.setEmitTouchEventsForMouse against the provided context.\nfunc (p *SetEmitTouchEventsForMouseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetEmitTouchEventsForMouse, p, nil)\n}\n\n// SetEmulatedMediaParams emulates the given media type or media feature for\n// CSS media queries.\ntype SetEmulatedMediaParams struct {\n\tMedia    string          `json:\"media,omitempty,omitzero\"`    // Media type to emulate. Empty string disables the override.\n\tFeatures []*MediaFeature `json:\"features,omitempty,omitzero\"` // Media features to emulate.\n}\n\n// SetEmulatedMedia emulates the given media type or media feature for CSS\n// media queries.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setEmulatedMedia\n//\n// parameters:\nfunc SetEmulatedMedia() *SetEmulatedMediaParams {\n\treturn &SetEmulatedMediaParams{}\n}\n\n// WithMedia media type to emulate. Empty string disables the override.\nfunc (p SetEmulatedMediaParams) WithMedia(media string) *SetEmulatedMediaParams {\n\tp.Media = media\n\treturn &p\n}\n\n// WithFeatures media features to emulate.\nfunc (p SetEmulatedMediaParams) WithFeatures(features []*MediaFeature) *SetEmulatedMediaParams {\n\tp.Features = features\n\treturn &p\n}\n\n// Do executes Emulation.setEmulatedMedia against the provided context.\nfunc (p *SetEmulatedMediaParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetEmulatedMedia, p, nil)\n}\n\n// SetEmulatedVisionDeficiencyParams emulates the given vision deficiency.\ntype SetEmulatedVisionDeficiencyParams struct {\n\tType SetEmulatedVisionDeficiencyType `json:\"type\"` // Vision deficiency to emulate. Order: best-effort emulations come first, followed by any physiologically accurate emulations for medically recognized color vision deficiencies.\n}\n\n// SetEmulatedVisionDeficiency emulates the given vision deficiency.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setEmulatedVisionDeficiency\n//\n// parameters:\n//\n//\ttype - Vision deficiency to emulate. Order: best-effort emulations come first, followed by any physiologically accurate emulations for medically recognized color vision deficiencies.\nfunc SetEmulatedVisionDeficiency(typeVal SetEmulatedVisionDeficiencyType) *SetEmulatedVisionDeficiencyParams {\n\treturn &SetEmulatedVisionDeficiencyParams{\n\t\tType: typeVal,\n\t}\n}\n\n// Do executes Emulation.setEmulatedVisionDeficiency against the provided context.\nfunc (p *SetEmulatedVisionDeficiencyParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetEmulatedVisionDeficiency, p, nil)\n}\n\n// SetEmulatedOSTextScaleParams emulates the given OS text scale.\ntype SetEmulatedOSTextScaleParams struct {\n\tScale float64 `json:\"scale,omitempty,omitzero\"`\n}\n\n// SetEmulatedOSTextScale emulates the given OS text scale.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setEmulatedOSTextScale\n//\n// parameters:\nfunc SetEmulatedOSTextScale() *SetEmulatedOSTextScaleParams {\n\treturn &SetEmulatedOSTextScaleParams{}\n}\n\n// WithScale [no description].\nfunc (p SetEmulatedOSTextScaleParams) WithScale(scale float64) *SetEmulatedOSTextScaleParams {\n\tp.Scale = scale\n\treturn &p\n}\n\n// Do executes Emulation.setEmulatedOSTextScale against the provided context.\nfunc (p *SetEmulatedOSTextScaleParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetEmulatedOSTextScale, p, nil)\n}\n\n// SetGeolocationOverrideParams overrides the Geolocation Position or Error.\n// Omitting latitude, longitude or accuracy emulates position unavailable.\ntype SetGeolocationOverrideParams struct {\n\tLatitude         float64 `json:\"latitude,omitempty,omitzero\"`         // Mock latitude\n\tLongitude        float64 `json:\"longitude,omitempty,omitzero\"`        // Mock longitude\n\tAccuracy         float64 `json:\"accuracy,omitempty,omitzero\"`         // Mock accuracy\n\tAltitude         float64 `json:\"altitude,omitempty,omitzero\"`         // Mock altitude\n\tAltitudeAccuracy float64 `json:\"altitudeAccuracy,omitempty,omitzero\"` // Mock altitudeAccuracy\n\tHeading          float64 `json:\"heading,omitempty,omitzero\"`          // Mock heading\n\tSpeed            float64 `json:\"speed,omitempty,omitzero\"`            // Mock speed\n}\n\n// SetGeolocationOverride overrides the Geolocation Position or Error.\n// Omitting latitude, longitude or accuracy emulates position unavailable.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setGeolocationOverride\n//\n// parameters:\nfunc SetGeolocationOverride() *SetGeolocationOverrideParams {\n\treturn &SetGeolocationOverrideParams{}\n}\n\n// WithLatitude mock latitude.\nfunc (p SetGeolocationOverrideParams) WithLatitude(latitude float64) *SetGeolocationOverrideParams {\n\tp.Latitude = latitude\n\treturn &p\n}\n\n// WithLongitude mock longitude.\nfunc (p SetGeolocationOverrideParams) WithLongitude(longitude float64) *SetGeolocationOverrideParams {\n\tp.Longitude = longitude\n\treturn &p\n}\n\n// WithAccuracy mock accuracy.\nfunc (p SetGeolocationOverrideParams) WithAccuracy(accuracy float64) *SetGeolocationOverrideParams {\n\tp.Accuracy = accuracy\n\treturn &p\n}\n\n// WithAltitude mock altitude.\nfunc (p SetGeolocationOverrideParams) WithAltitude(altitude float64) *SetGeolocationOverrideParams {\n\tp.Altitude = altitude\n\treturn &p\n}\n\n// WithAltitudeAccuracy mock altitudeAccuracy.\nfunc (p SetGeolocationOverrideParams) WithAltitudeAccuracy(altitudeAccuracy float64) *SetGeolocationOverrideParams {\n\tp.AltitudeAccuracy = altitudeAccuracy\n\treturn &p\n}\n\n// WithHeading mock heading.\nfunc (p SetGeolocationOverrideParams) WithHeading(heading float64) *SetGeolocationOverrideParams {\n\tp.Heading = heading\n\treturn &p\n}\n\n// WithSpeed mock speed.\nfunc (p SetGeolocationOverrideParams) WithSpeed(speed float64) *SetGeolocationOverrideParams {\n\tp.Speed = speed\n\treturn &p\n}\n\n// Do executes Emulation.setGeolocationOverride against the provided context.\nfunc (p *SetGeolocationOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetGeolocationOverride, p, nil)\n}\n\n// GetOverriddenSensorInformationParams [no description].\ntype GetOverriddenSensorInformationParams struct {\n\tType SensorType `json:\"type\"`\n}\n\n// GetOverriddenSensorInformation [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-getOverriddenSensorInformation\n//\n// parameters:\n//\n//\ttype\nfunc GetOverriddenSensorInformation(typeVal SensorType) *GetOverriddenSensorInformationParams {\n\treturn &GetOverriddenSensorInformationParams{\n\t\tType: typeVal,\n\t}\n}\n\n// GetOverriddenSensorInformationReturns return values.\ntype GetOverriddenSensorInformationReturns struct {\n\tRequestedSamplingFrequency float64 `json:\"requestedSamplingFrequency,omitempty,omitzero\"`\n}\n\n// Do executes Emulation.getOverriddenSensorInformation against the provided context.\n//\n// returns:\n//\n//\trequestedSamplingFrequency\nfunc (p *GetOverriddenSensorInformationParams) Do(ctx context.Context) (requestedSamplingFrequency float64, err error) {\n\t// execute\n\tvar res GetOverriddenSensorInformationReturns\n\terr = cdp.Execute(ctx, CommandGetOverriddenSensorInformation, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.RequestedSamplingFrequency, nil\n}\n\n// SetSensorOverrideEnabledParams overrides a platform sensor of a given\n// type. If |enabled| is true, calls to Sensor.start() will use a virtual sensor\n// as backend rather than fetching data from a real hardware sensor. Otherwise,\n// existing virtual sensor-backend Sensor objects will fire an error event and\n// new calls to Sensor.start() will attempt to use a real sensor instead.\ntype SetSensorOverrideEnabledParams struct {\n\tEnabled  bool            `json:\"enabled\"`\n\tType     SensorType      `json:\"type\"`\n\tMetadata *SensorMetadata `json:\"metadata,omitempty,omitzero\"`\n}\n\n// SetSensorOverrideEnabled overrides a platform sensor of a given type. If\n// |enabled| is true, calls to Sensor.start() will use a virtual sensor as\n// backend rather than fetching data from a real hardware sensor. Otherwise,\n// existing virtual sensor-backend Sensor objects will fire an error event and\n// new calls to Sensor.start() will attempt to use a real sensor instead.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setSensorOverrideEnabled\n//\n// parameters:\n//\n//\tenabled\n//\ttype\nfunc SetSensorOverrideEnabled(enabled bool, typeVal SensorType) *SetSensorOverrideEnabledParams {\n\treturn &SetSensorOverrideEnabledParams{\n\t\tEnabled: enabled,\n\t\tType:    typeVal,\n\t}\n}\n\n// WithMetadata [no description].\nfunc (p SetSensorOverrideEnabledParams) WithMetadata(metadata *SensorMetadata) *SetSensorOverrideEnabledParams {\n\tp.Metadata = metadata\n\treturn &p\n}\n\n// Do executes Emulation.setSensorOverrideEnabled against the provided context.\nfunc (p *SetSensorOverrideEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSensorOverrideEnabled, p, nil)\n}\n\n// SetSensorOverrideReadingsParams updates the sensor readings reported by a\n// sensor type previously overridden by setSensorOverrideEnabled.\ntype SetSensorOverrideReadingsParams struct {\n\tType    SensorType     `json:\"type\"`\n\tReading *SensorReading `json:\"reading\"`\n}\n\n// SetSensorOverrideReadings updates the sensor readings reported by a sensor\n// type previously overridden by setSensorOverrideEnabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setSensorOverrideReadings\n//\n// parameters:\n//\n//\ttype\n//\treading\nfunc SetSensorOverrideReadings(typeVal SensorType, reading *SensorReading) *SetSensorOverrideReadingsParams {\n\treturn &SetSensorOverrideReadingsParams{\n\t\tType:    typeVal,\n\t\tReading: reading,\n\t}\n}\n\n// Do executes Emulation.setSensorOverrideReadings against the provided context.\nfunc (p *SetSensorOverrideReadingsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSensorOverrideReadings, p, nil)\n}\n\n// SetPressureSourceOverrideEnabledParams overrides a pressure source of a\n// given type, as used by the Compute Pressure API, so that updates to\n// PressureObserver.observe() are provided via setPressureStateOverride instead\n// of being retrieved from platform-provided telemetry data.\ntype SetPressureSourceOverrideEnabledParams struct {\n\tEnabled  bool              `json:\"enabled\"`\n\tSource   PressureSource    `json:\"source\"`\n\tMetadata *PressureMetadata `json:\"metadata,omitempty,omitzero\"`\n}\n\n// SetPressureSourceOverrideEnabled overrides a pressure source of a given\n// type, as used by the Compute Pressure API, so that updates to\n// PressureObserver.observe() are provided via setPressureStateOverride instead\n// of being retrieved from platform-provided telemetry data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setPressureSourceOverrideEnabled\n//\n// parameters:\n//\n//\tenabled\n//\tsource\nfunc SetPressureSourceOverrideEnabled(enabled bool, source PressureSource) *SetPressureSourceOverrideEnabledParams {\n\treturn &SetPressureSourceOverrideEnabledParams{\n\t\tEnabled: enabled,\n\t\tSource:  source,\n\t}\n}\n\n// WithMetadata [no description].\nfunc (p SetPressureSourceOverrideEnabledParams) WithMetadata(metadata *PressureMetadata) *SetPressureSourceOverrideEnabledParams {\n\tp.Metadata = metadata\n\treturn &p\n}\n\n// Do executes Emulation.setPressureSourceOverrideEnabled against the provided context.\nfunc (p *SetPressureSourceOverrideEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPressureSourceOverrideEnabled, p, nil)\n}\n\n// SetPressureStateOverrideParams tODO: OBSOLETE: To remove when\n// setPressureDataOverride is merged. Provides a given pressure state that will\n// be processed and eventually be delivered to PressureObserver users. |source|\n// must have been previously overridden by setPressureSourceOverrideEnabled.\ntype SetPressureStateOverrideParams struct {\n\tSource PressureSource `json:\"source\"`\n\tState  PressureState  `json:\"state\"`\n}\n\n// SetPressureStateOverride tODO: OBSOLETE: To remove when\n// setPressureDataOverride is merged. Provides a given pressure state that will\n// be processed and eventually be delivered to PressureObserver users. |source|\n// must have been previously overridden by setPressureSourceOverrideEnabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setPressureStateOverride\n//\n// parameters:\n//\n//\tsource\n//\tstate\nfunc SetPressureStateOverride(source PressureSource, state PressureState) *SetPressureStateOverrideParams {\n\treturn &SetPressureStateOverrideParams{\n\t\tSource: source,\n\t\tState:  state,\n\t}\n}\n\n// Do executes Emulation.setPressureStateOverride against the provided context.\nfunc (p *SetPressureStateOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPressureStateOverride, p, nil)\n}\n\n// SetPressureDataOverrideParams provides a given pressure data set that will\n// be processed and eventually be delivered to PressureObserver users. |source|\n// must have been previously overridden by setPressureSourceOverrideEnabled.\ntype SetPressureDataOverrideParams struct {\n\tSource                  PressureSource `json:\"source\"`\n\tState                   PressureState  `json:\"state\"`\n\tOwnContributionEstimate float64        `json:\"ownContributionEstimate,omitempty,omitzero\"`\n}\n\n// SetPressureDataOverride provides a given pressure data set that will be\n// processed and eventually be delivered to PressureObserver users. |source|\n// must have been previously overridden by setPressureSourceOverrideEnabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setPressureDataOverride\n//\n// parameters:\n//\n//\tsource\n//\tstate\nfunc SetPressureDataOverride(source PressureSource, state PressureState) *SetPressureDataOverrideParams {\n\treturn &SetPressureDataOverrideParams{\n\t\tSource: source,\n\t\tState:  state,\n\t}\n}\n\n// WithOwnContributionEstimate [no description].\nfunc (p SetPressureDataOverrideParams) WithOwnContributionEstimate(ownContributionEstimate float64) *SetPressureDataOverrideParams {\n\tp.OwnContributionEstimate = ownContributionEstimate\n\treturn &p\n}\n\n// Do executes Emulation.setPressureDataOverride against the provided context.\nfunc (p *SetPressureDataOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPressureDataOverride, p, nil)\n}\n\n// SetIdleOverrideParams overrides the Idle state.\ntype SetIdleOverrideParams struct {\n\tIsUserActive     bool `json:\"isUserActive\"`     // Mock isUserActive\n\tIsScreenUnlocked bool `json:\"isScreenUnlocked\"` // Mock isScreenUnlocked\n}\n\n// SetIdleOverride overrides the Idle state.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setIdleOverride\n//\n// parameters:\n//\n//\tisUserActive - Mock isUserActive\n//\tisScreenUnlocked - Mock isScreenUnlocked\nfunc SetIdleOverride(isUserActive bool, isScreenUnlocked bool) *SetIdleOverrideParams {\n\treturn &SetIdleOverrideParams{\n\t\tIsUserActive:     isUserActive,\n\t\tIsScreenUnlocked: isScreenUnlocked,\n\t}\n}\n\n// Do executes Emulation.setIdleOverride against the provided context.\nfunc (p *SetIdleOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetIdleOverride, p, nil)\n}\n\n// ClearIdleOverrideParams clears Idle state overrides.\ntype ClearIdleOverrideParams struct{}\n\n// ClearIdleOverride clears Idle state overrides.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-clearIdleOverride\nfunc ClearIdleOverride() *ClearIdleOverrideParams {\n\treturn &ClearIdleOverrideParams{}\n}\n\n// Do executes Emulation.clearIdleOverride against the provided context.\nfunc (p *ClearIdleOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearIdleOverride, nil, nil)\n}\n\n// SetPageScaleFactorParams sets a specified page scale factor.\ntype SetPageScaleFactorParams struct {\n\tPageScaleFactor float64 `json:\"pageScaleFactor\"` // Page scale factor.\n}\n\n// SetPageScaleFactor sets a specified page scale factor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setPageScaleFactor\n//\n// parameters:\n//\n//\tpageScaleFactor - Page scale factor.\nfunc SetPageScaleFactor(pageScaleFactor float64) *SetPageScaleFactorParams {\n\treturn &SetPageScaleFactorParams{\n\t\tPageScaleFactor: pageScaleFactor,\n\t}\n}\n\n// Do executes Emulation.setPageScaleFactor against the provided context.\nfunc (p *SetPageScaleFactorParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPageScaleFactor, p, nil)\n}\n\n// SetScriptExecutionDisabledParams switches script execution in the page.\ntype SetScriptExecutionDisabledParams struct {\n\tValue bool `json:\"value\"` // Whether script execution should be disabled in the page.\n}\n\n// SetScriptExecutionDisabled switches script execution in the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setScriptExecutionDisabled\n//\n// parameters:\n//\n//\tvalue - Whether script execution should be disabled in the page.\nfunc SetScriptExecutionDisabled(value bool) *SetScriptExecutionDisabledParams {\n\treturn &SetScriptExecutionDisabledParams{\n\t\tValue: value,\n\t}\n}\n\n// Do executes Emulation.setScriptExecutionDisabled against the provided context.\nfunc (p *SetScriptExecutionDisabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetScriptExecutionDisabled, p, nil)\n}\n\n// SetTouchEmulationEnabledParams enables touch on platforms which do not\n// support them.\ntype SetTouchEmulationEnabledParams struct {\n\tEnabled        bool  `json:\"enabled\"`                           // Whether the touch event emulation should be enabled.\n\tMaxTouchPoints int64 `json:\"maxTouchPoints,omitempty,omitzero\"` // Maximum touch points supported. Defaults to one.\n}\n\n// SetTouchEmulationEnabled enables touch on platforms which do not support\n// them.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setTouchEmulationEnabled\n//\n// parameters:\n//\n//\tenabled - Whether the touch event emulation should be enabled.\nfunc SetTouchEmulationEnabled(enabled bool) *SetTouchEmulationEnabledParams {\n\treturn &SetTouchEmulationEnabledParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// WithMaxTouchPoints maximum touch points supported. Defaults to one.\nfunc (p SetTouchEmulationEnabledParams) WithMaxTouchPoints(maxTouchPoints int64) *SetTouchEmulationEnabledParams {\n\tp.MaxTouchPoints = maxTouchPoints\n\treturn &p\n}\n\n// Do executes Emulation.setTouchEmulationEnabled against the provided context.\nfunc (p *SetTouchEmulationEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetTouchEmulationEnabled, p, nil)\n}\n\n// SetVirtualTimePolicyParams turns on virtual time for all frames (replacing\n// real-time with a synthetic time source) and sets the current virtual time\n// policy. Note this supersedes any previous time budget.\ntype SetVirtualTimePolicyParams struct {\n\tPolicy                            VirtualTimePolicy   `json:\"policy\"`\n\tBudget                            float64             `json:\"budget,omitempty,omitzero\"`                            // If set, after this many virtual milliseconds have elapsed virtual time will be paused and a virtualTimeBudgetExpired event is sent.\n\tMaxVirtualTimeTaskStarvationCount int64               `json:\"maxVirtualTimeTaskStarvationCount,omitempty,omitzero\"` // If set this specifies the maximum number of tasks that can be run before virtual is forced forwards to prevent deadlock.\n\tInitialVirtualTime                *cdp.TimeSinceEpoch `json:\"initialVirtualTime,omitempty,omitzero\"`                // If set, base::Time::Now will be overridden to initially return this value.\n}\n\n// SetVirtualTimePolicy turns on virtual time for all frames (replacing\n// real-time with a synthetic time source) and sets the current virtual time\n// policy. Note this supersedes any previous time budget.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setVirtualTimePolicy\n//\n// parameters:\n//\n//\tpolicy\nfunc SetVirtualTimePolicy(policy VirtualTimePolicy) *SetVirtualTimePolicyParams {\n\treturn &SetVirtualTimePolicyParams{\n\t\tPolicy: policy,\n\t}\n}\n\n// WithBudget if set, after this many virtual milliseconds have elapsed\n// virtual time will be paused and a virtualTimeBudgetExpired event is sent.\nfunc (p SetVirtualTimePolicyParams) WithBudget(budget float64) *SetVirtualTimePolicyParams {\n\tp.Budget = budget\n\treturn &p\n}\n\n// WithMaxVirtualTimeTaskStarvationCount if set this specifies the maximum\n// number of tasks that can be run before virtual is forced forwards to prevent\n// deadlock.\nfunc (p SetVirtualTimePolicyParams) WithMaxVirtualTimeTaskStarvationCount(maxVirtualTimeTaskStarvationCount int64) *SetVirtualTimePolicyParams {\n\tp.MaxVirtualTimeTaskStarvationCount = maxVirtualTimeTaskStarvationCount\n\treturn &p\n}\n\n// WithInitialVirtualTime if set, base::Time::Now will be overridden to\n// initially return this value.\nfunc (p SetVirtualTimePolicyParams) WithInitialVirtualTime(initialVirtualTime *cdp.TimeSinceEpoch) *SetVirtualTimePolicyParams {\n\tp.InitialVirtualTime = initialVirtualTime\n\treturn &p\n}\n\n// SetVirtualTimePolicyReturns return values.\ntype SetVirtualTimePolicyReturns struct {\n\tVirtualTimeTicksBase float64 `json:\"virtualTimeTicksBase,omitempty,omitzero\"` // Absolute timestamp at which virtual time was first enabled (up time in milliseconds).\n}\n\n// Do executes Emulation.setVirtualTimePolicy against the provided context.\n//\n// returns:\n//\n//\tvirtualTimeTicksBase - Absolute timestamp at which virtual time was first enabled (up time in milliseconds).\nfunc (p *SetVirtualTimePolicyParams) Do(ctx context.Context) (virtualTimeTicksBase float64, err error) {\n\t// execute\n\tvar res SetVirtualTimePolicyReturns\n\terr = cdp.Execute(ctx, CommandSetVirtualTimePolicy, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.VirtualTimeTicksBase, nil\n}\n\n// SetLocaleOverrideParams overrides default host system locale with the\n// specified one.\ntype SetLocaleOverrideParams struct {\n\tLocale string `json:\"locale,omitempty,omitzero\"` // ICU style C locale (e.g. \"en_US\"). If not specified or empty, disables the override and restores default host system locale.\n}\n\n// SetLocaleOverride overrides default host system locale with the specified\n// one.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setLocaleOverride\n//\n// parameters:\nfunc SetLocaleOverride() *SetLocaleOverrideParams {\n\treturn &SetLocaleOverrideParams{}\n}\n\n// WithLocale iCU style C locale (e.g. \"en_US\"). If not specified or empty,\n// disables the override and restores default host system locale.\nfunc (p SetLocaleOverrideParams) WithLocale(locale string) *SetLocaleOverrideParams {\n\tp.Locale = locale\n\treturn &p\n}\n\n// Do executes Emulation.setLocaleOverride against the provided context.\nfunc (p *SetLocaleOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetLocaleOverride, p, nil)\n}\n\n// SetTimezoneOverrideParams overrides default host system timezone with the\n// specified one.\ntype SetTimezoneOverrideParams struct {\n\tTimezoneID string `json:\"timezoneId\"` // The timezone identifier. List of supported timezones: https://source.chromium.org/chromium/chromium/deps/icu.git/+/faee8bc70570192d82d2978a71e2a615788597d1:source/data/misc/metaZones.txt If empty, disables the override and restores default host system timezone.\n}\n\n// SetTimezoneOverride overrides default host system timezone with the\n// specified one.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setTimezoneOverride\n//\n// parameters:\n//\n//\ttimezoneID - The timezone identifier. List of supported timezones: https://source.chromium.org/chromium/chromium/deps/icu.git/+/faee8bc70570192d82d2978a71e2a615788597d1:source/data/misc/metaZones.txt If empty, disables the override and restores default host system timezone.\nfunc SetTimezoneOverride(timezoneID string) *SetTimezoneOverrideParams {\n\treturn &SetTimezoneOverrideParams{\n\t\tTimezoneID: timezoneID,\n\t}\n}\n\n// Do executes Emulation.setTimezoneOverride against the provided context.\nfunc (p *SetTimezoneOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetTimezoneOverride, p, nil)\n}\n\n// SetDisabledImageTypesParams [no description].\ntype SetDisabledImageTypesParams struct {\n\tImageTypes []DisabledImageType `json:\"imageTypes\"` // Image types to disable.\n}\n\n// SetDisabledImageTypes [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setDisabledImageTypes\n//\n// parameters:\n//\n//\timageTypes - Image types to disable.\nfunc SetDisabledImageTypes(imageTypes []DisabledImageType) *SetDisabledImageTypesParams {\n\treturn &SetDisabledImageTypesParams{\n\t\tImageTypes: imageTypes,\n\t}\n}\n\n// Do executes Emulation.setDisabledImageTypes against the provided context.\nfunc (p *SetDisabledImageTypesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDisabledImageTypes, p, nil)\n}\n\n// SetDataSaverOverrideParams override the value of\n// navigator.connection.saveData.\ntype SetDataSaverOverrideParams struct {\n\tDataSaverEnabled bool `json:\"dataSaverEnabled\"` // Override value. Omitting the parameter disables the override.\n}\n\n// SetDataSaverOverride override the value of navigator.connection.saveData.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setDataSaverOverride\n//\n// parameters:\nfunc SetDataSaverOverride() *SetDataSaverOverrideParams {\n\treturn &SetDataSaverOverrideParams{\n\t\tDataSaverEnabled: false,\n\t}\n}\n\n// WithDataSaverEnabled override value. Omitting the parameter disables the\n// override.\nfunc (p SetDataSaverOverrideParams) WithDataSaverEnabled(dataSaverEnabled bool) *SetDataSaverOverrideParams {\n\tp.DataSaverEnabled = dataSaverEnabled\n\treturn &p\n}\n\n// Do executes Emulation.setDataSaverOverride against the provided context.\nfunc (p *SetDataSaverOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDataSaverOverride, p, nil)\n}\n\n// SetHardwareConcurrencyOverrideParams [no description].\ntype SetHardwareConcurrencyOverrideParams struct {\n\tHardwareConcurrency int64 `json:\"hardwareConcurrency\"` // Hardware concurrency to report\n}\n\n// SetHardwareConcurrencyOverride [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setHardwareConcurrencyOverride\n//\n// parameters:\n//\n//\thardwareConcurrency - Hardware concurrency to report\nfunc SetHardwareConcurrencyOverride(hardwareConcurrency int64) *SetHardwareConcurrencyOverrideParams {\n\treturn &SetHardwareConcurrencyOverrideParams{\n\t\tHardwareConcurrency: hardwareConcurrency,\n\t}\n}\n\n// Do executes Emulation.setHardwareConcurrencyOverride against the provided context.\nfunc (p *SetHardwareConcurrencyOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetHardwareConcurrencyOverride, p, nil)\n}\n\n// SetUserAgentOverrideParams allows overriding user agent with the given\n// string. userAgentMetadata must be set for Client Hint headers to be sent.\ntype SetUserAgentOverrideParams struct {\n\tUserAgent         string             `json:\"userAgent\"`                            // User agent to use.\n\tAcceptLanguage    string             `json:\"acceptLanguage,omitempty,omitzero\"`    // Browser language to emulate.\n\tPlatform          string             `json:\"platform,omitempty,omitzero\"`          // The platform navigator.platform should return.\n\tUserAgentMetadata *UserAgentMetadata `json:\"userAgentMetadata,omitempty,omitzero\"` // To be sent in Sec-CH-UA-* headers and returned in navigator.userAgentData\n}\n\n// SetUserAgentOverride allows overriding user agent with the given string.\n// userAgentMetadata must be set for Client Hint headers to be sent.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setUserAgentOverride\n//\n// parameters:\n//\n//\tuserAgent - User agent to use.\nfunc SetUserAgentOverride(userAgent string) *SetUserAgentOverrideParams {\n\treturn &SetUserAgentOverrideParams{\n\t\tUserAgent: userAgent,\n\t}\n}\n\n// WithAcceptLanguage browser language to emulate.\nfunc (p SetUserAgentOverrideParams) WithAcceptLanguage(acceptLanguage string) *SetUserAgentOverrideParams {\n\tp.AcceptLanguage = acceptLanguage\n\treturn &p\n}\n\n// WithPlatform the platform navigator.platform should return.\nfunc (p SetUserAgentOverrideParams) WithPlatform(platform string) *SetUserAgentOverrideParams {\n\tp.Platform = platform\n\treturn &p\n}\n\n// WithUserAgentMetadata to be sent in Sec-CH-UA-* headers and returned in\n// navigator.userAgentData.\nfunc (p SetUserAgentOverrideParams) WithUserAgentMetadata(userAgentMetadata *UserAgentMetadata) *SetUserAgentOverrideParams {\n\tp.UserAgentMetadata = userAgentMetadata\n\treturn &p\n}\n\n// Do executes Emulation.setUserAgentOverride against the provided context.\nfunc (p *SetUserAgentOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetUserAgentOverride, p, nil)\n}\n\n// SetAutomationOverrideParams allows overriding the automation flag.\ntype SetAutomationOverrideParams struct {\n\tEnabled bool `json:\"enabled\"` // Whether the override should be enabled.\n}\n\n// SetAutomationOverride allows overriding the automation flag.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setAutomationOverride\n//\n// parameters:\n//\n//\tenabled - Whether the override should be enabled.\nfunc SetAutomationOverride(enabled bool) *SetAutomationOverrideParams {\n\treturn &SetAutomationOverrideParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Emulation.setAutomationOverride against the provided context.\nfunc (p *SetAutomationOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAutomationOverride, p, nil)\n}\n\n// SetSmallViewportHeightDifferenceOverrideParams allows overriding the\n// difference between the small and large viewport sizes, which determine the\n// value of the svh and lvh unit, respectively. Only supported for top-level\n// frames.\ntype SetSmallViewportHeightDifferenceOverrideParams struct {\n\tDifference int64 `json:\"difference\"` // This will cause an element of size 100svh to be difference pixels smaller than an element of size 100lvh.\n}\n\n// SetSmallViewportHeightDifferenceOverride allows overriding the difference\n// between the small and large viewport sizes, which determine the value of the\n// svh and lvh unit, respectively. Only supported for top-level frames.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setSmallViewportHeightDifferenceOverride\n//\n// parameters:\n//\n//\tdifference - This will cause an element of size 100svh to be difference pixels smaller than an element of size 100lvh.\nfunc SetSmallViewportHeightDifferenceOverride(difference int64) *SetSmallViewportHeightDifferenceOverrideParams {\n\treturn &SetSmallViewportHeightDifferenceOverrideParams{\n\t\tDifference: difference,\n\t}\n}\n\n// Do executes Emulation.setSmallViewportHeightDifferenceOverride against the provided context.\nfunc (p *SetSmallViewportHeightDifferenceOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSmallViewportHeightDifferenceOverride, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandClearDeviceMetricsOverride               = \"Emulation.clearDeviceMetricsOverride\"\n\tCommandClearGeolocationOverride                 = \"Emulation.clearGeolocationOverride\"\n\tCommandResetPageScaleFactor                     = \"Emulation.resetPageScaleFactor\"\n\tCommandSetFocusEmulationEnabled                 = \"Emulation.setFocusEmulationEnabled\"\n\tCommandSetAutoDarkModeOverride                  = \"Emulation.setAutoDarkModeOverride\"\n\tCommandSetCPUThrottlingRate                     = \"Emulation.setCPUThrottlingRate\"\n\tCommandSetDefaultBackgroundColorOverride        = \"Emulation.setDefaultBackgroundColorOverride\"\n\tCommandSetSafeAreaInsetsOverride                = \"Emulation.setSafeAreaInsetsOverride\"\n\tCommandSetDeviceMetricsOverride                 = \"Emulation.setDeviceMetricsOverride\"\n\tCommandSetDevicePostureOverride                 = \"Emulation.setDevicePostureOverride\"\n\tCommandClearDevicePostureOverride               = \"Emulation.clearDevicePostureOverride\"\n\tCommandSetDisplayFeaturesOverride               = \"Emulation.setDisplayFeaturesOverride\"\n\tCommandClearDisplayFeaturesOverride             = \"Emulation.clearDisplayFeaturesOverride\"\n\tCommandSetScrollbarsHidden                      = \"Emulation.setScrollbarsHidden\"\n\tCommandSetDocumentCookieDisabled                = \"Emulation.setDocumentCookieDisabled\"\n\tCommandSetEmitTouchEventsForMouse               = \"Emulation.setEmitTouchEventsForMouse\"\n\tCommandSetEmulatedMedia                         = \"Emulation.setEmulatedMedia\"\n\tCommandSetEmulatedVisionDeficiency              = \"Emulation.setEmulatedVisionDeficiency\"\n\tCommandSetEmulatedOSTextScale                   = \"Emulation.setEmulatedOSTextScale\"\n\tCommandSetGeolocationOverride                   = \"Emulation.setGeolocationOverride\"\n\tCommandGetOverriddenSensorInformation           = \"Emulation.getOverriddenSensorInformation\"\n\tCommandSetSensorOverrideEnabled                 = \"Emulation.setSensorOverrideEnabled\"\n\tCommandSetSensorOverrideReadings                = \"Emulation.setSensorOverrideReadings\"\n\tCommandSetPressureSourceOverrideEnabled         = \"Emulation.setPressureSourceOverrideEnabled\"\n\tCommandSetPressureStateOverride                 = \"Emulation.setPressureStateOverride\"\n\tCommandSetPressureDataOverride                  = \"Emulation.setPressureDataOverride\"\n\tCommandSetIdleOverride                          = \"Emulation.setIdleOverride\"\n\tCommandClearIdleOverride                        = \"Emulation.clearIdleOverride\"\n\tCommandSetPageScaleFactor                       = \"Emulation.setPageScaleFactor\"\n\tCommandSetScriptExecutionDisabled               = \"Emulation.setScriptExecutionDisabled\"\n\tCommandSetTouchEmulationEnabled                 = \"Emulation.setTouchEmulationEnabled\"\n\tCommandSetVirtualTimePolicy                     = \"Emulation.setVirtualTimePolicy\"\n\tCommandSetLocaleOverride                        = \"Emulation.setLocaleOverride\"\n\tCommandSetTimezoneOverride                      = \"Emulation.setTimezoneOverride\"\n\tCommandSetDisabledImageTypes                    = \"Emulation.setDisabledImageTypes\"\n\tCommandSetDataSaverOverride                     = \"Emulation.setDataSaverOverride\"\n\tCommandSetHardwareConcurrencyOverride           = \"Emulation.setHardwareConcurrencyOverride\"\n\tCommandSetUserAgentOverride                     = \"Emulation.setUserAgentOverride\"\n\tCommandSetAutomationOverride                    = \"Emulation.setAutomationOverride\"\n\tCommandSetSmallViewportHeightDifferenceOverride = \"Emulation.setSmallViewportHeightDifferenceOverride\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/emulation/events.go",
    "content": "package emulation\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventVirtualTimeBudgetExpired notification sent after the virtual time\n// budget for the current VirtualTimePolicy has run out.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#event-virtualTimeBudgetExpired\ntype EventVirtualTimeBudgetExpired struct{}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/emulation/types.go",
    "content": "package emulation\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// SafeAreaInsets [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-SafeAreaInsets\ntype SafeAreaInsets struct {\n\tTop       int64 `json:\"top,omitempty,omitzero\"`       // Overrides safe-area-inset-top.\n\tTopMax    int64 `json:\"topMax,omitempty,omitzero\"`    // Overrides safe-area-max-inset-top.\n\tLeft      int64 `json:\"left,omitempty,omitzero\"`      // Overrides safe-area-inset-left.\n\tLeftMax   int64 `json:\"leftMax,omitempty,omitzero\"`   // Overrides safe-area-max-inset-left.\n\tBottom    int64 `json:\"bottom,omitempty,omitzero\"`    // Overrides safe-area-inset-bottom.\n\tBottomMax int64 `json:\"bottomMax,omitempty,omitzero\"` // Overrides safe-area-max-inset-bottom.\n\tRight     int64 `json:\"right,omitempty,omitzero\"`     // Overrides safe-area-inset-right.\n\tRightMax  int64 `json:\"rightMax,omitempty,omitzero\"`  // Overrides safe-area-max-inset-right.\n}\n\n// ScreenOrientation screen orientation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-ScreenOrientation\ntype ScreenOrientation struct {\n\tType  OrientationType `json:\"type\"`  // Orientation type.\n\tAngle int64           `json:\"angle\"` // Orientation angle.\n}\n\n// DisplayFeature [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-DisplayFeature\ntype DisplayFeature struct {\n\tOrientation DisplayFeatureOrientation `json:\"orientation\"` // Orientation of a display feature in relation to screen\n\tOffset      int64                     `json:\"offset\"`      // The offset from the screen origin in either the x (for vertical orientation) or y (for horizontal orientation) direction.\n\tMaskLength  int64                     `json:\"maskLength\"`  // A display feature may mask content such that it is not physically displayed - this length along with the offset describes this area. A display feature that only splits content will have a 0 mask_length.\n}\n\n// DevicePosture [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-DevicePosture\ntype DevicePosture struct {\n\tType DevicePostureType `json:\"type\"` // Current posture of the device\n}\n\n// MediaFeature [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-MediaFeature\ntype MediaFeature struct {\n\tName  string `json:\"name\"`\n\tValue string `json:\"value\"`\n}\n\n// VirtualTimePolicy advance: If the scheduler runs out of immediate work,\n// the virtual time base may fast forward to allow the next delayed task (if\n// any) to run; pause: The virtual time base may not advance;\n// pauseIfNetworkFetchesPending: The virtual time base may not advance if there\n// are any pending resource fetches.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-VirtualTimePolicy\ntype VirtualTimePolicy string\n\n// String returns the VirtualTimePolicy as string value.\nfunc (t VirtualTimePolicy) String() string {\n\treturn string(t)\n}\n\n// VirtualTimePolicy values.\nconst (\n\tVirtualTimePolicyAdvance                      VirtualTimePolicy = \"advance\"\n\tVirtualTimePolicyPause                        VirtualTimePolicy = \"pause\"\n\tVirtualTimePolicyPauseIfNetworkFetchesPending VirtualTimePolicy = \"pauseIfNetworkFetchesPending\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *VirtualTimePolicy) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch VirtualTimePolicy(s) {\n\tcase VirtualTimePolicyAdvance:\n\t\t*t = VirtualTimePolicyAdvance\n\tcase VirtualTimePolicyPause:\n\t\t*t = VirtualTimePolicyPause\n\tcase VirtualTimePolicyPauseIfNetworkFetchesPending:\n\t\t*t = VirtualTimePolicyPauseIfNetworkFetchesPending\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown VirtualTimePolicy value: %v\", s)\n\t}\n\treturn nil\n}\n\n// UserAgentBrandVersion used to specify User Agent Client Hints to emulate.\n// See https://wicg.github.io/ua-client-hints.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-UserAgentBrandVersion\ntype UserAgentBrandVersion struct {\n\tBrand   string `json:\"brand\"`\n\tVersion string `json:\"version\"`\n}\n\n// UserAgentMetadata used to specify User Agent Client Hints to emulate. See\n// https://wicg.github.io/ua-client-hints Missing optional values will be filled\n// in by the target with what it would normally use.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-UserAgentMetadata\ntype UserAgentMetadata struct {\n\tBrands          []*UserAgentBrandVersion `json:\"brands,omitempty,omitzero\"`          // Brands appearing in Sec-CH-UA.\n\tFullVersionList []*UserAgentBrandVersion `json:\"fullVersionList,omitempty,omitzero\"` // Brands appearing in Sec-CH-UA-Full-Version-List.\n\tPlatform        string                   `json:\"platform\"`\n\tPlatformVersion string                   `json:\"platformVersion\"`\n\tArchitecture    string                   `json:\"architecture\"`\n\tModel           string                   `json:\"model\"`\n\tMobile          bool                     `json:\"mobile\"`\n\tBitness         string                   `json:\"bitness,omitempty,omitzero\"`\n\tWow64           bool                     `json:\"wow64\"`\n\tFormFactors     []string                 `json:\"formFactors,omitempty,omitzero\"` // Used to specify User Agent form-factor values. See https://wicg.github.io/ua-client-hints/#sec-ch-ua-form-factors\n}\n\n// SensorType used to specify sensor types to emulate. See\n// https://w3c.github.io/sensors/#automation for more information.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-SensorType\ntype SensorType string\n\n// String returns the SensorType as string value.\nfunc (t SensorType) String() string {\n\treturn string(t)\n}\n\n// SensorType values.\nconst (\n\tSensorTypeAbsoluteOrientation SensorType = \"absolute-orientation\"\n\tSensorTypeAccelerometer       SensorType = \"accelerometer\"\n\tSensorTypeAmbientLight        SensorType = \"ambient-light\"\n\tSensorTypeGravity             SensorType = \"gravity\"\n\tSensorTypeGyroscope           SensorType = \"gyroscope\"\n\tSensorTypeLinearAcceleration  SensorType = \"linear-acceleration\"\n\tSensorTypeMagnetometer        SensorType = \"magnetometer\"\n\tSensorTypeRelativeOrientation SensorType = \"relative-orientation\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SensorType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SensorType(s) {\n\tcase SensorTypeAbsoluteOrientation:\n\t\t*t = SensorTypeAbsoluteOrientation\n\tcase SensorTypeAccelerometer:\n\t\t*t = SensorTypeAccelerometer\n\tcase SensorTypeAmbientLight:\n\t\t*t = SensorTypeAmbientLight\n\tcase SensorTypeGravity:\n\t\t*t = SensorTypeGravity\n\tcase SensorTypeGyroscope:\n\t\t*t = SensorTypeGyroscope\n\tcase SensorTypeLinearAcceleration:\n\t\t*t = SensorTypeLinearAcceleration\n\tcase SensorTypeMagnetometer:\n\t\t*t = SensorTypeMagnetometer\n\tcase SensorTypeRelativeOrientation:\n\t\t*t = SensorTypeRelativeOrientation\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SensorType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SensorMetadata [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-SensorMetadata\ntype SensorMetadata struct {\n\tAvailable        bool    `json:\"available\"`\n\tMinimumFrequency float64 `json:\"minimumFrequency,omitempty,omitzero\"`\n\tMaximumFrequency float64 `json:\"maximumFrequency,omitempty,omitzero\"`\n}\n\n// SensorReadingSingle [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-SensorReadingSingle\ntype SensorReadingSingle struct {\n\tValue float64 `json:\"value\"`\n}\n\n// SensorReadingXYZ [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-SensorReadingXYZ\ntype SensorReadingXYZ struct {\n\tX float64 `json:\"x\"`\n\tY float64 `json:\"y\"`\n\tZ float64 `json:\"z\"`\n}\n\n// SensorReadingQuaternion [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-SensorReadingQuaternion\ntype SensorReadingQuaternion struct {\n\tX float64 `json:\"x\"`\n\tY float64 `json:\"y\"`\n\tZ float64 `json:\"z\"`\n\tW float64 `json:\"w\"`\n}\n\n// SensorReading [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-SensorReading\ntype SensorReading struct {\n\tSingle     *SensorReadingSingle     `json:\"single,omitempty,omitzero\"`\n\tXyz        *SensorReadingXYZ        `json:\"xyz,omitempty,omitzero\"`\n\tQuaternion *SensorReadingQuaternion `json:\"quaternion,omitempty,omitzero\"`\n}\n\n// PressureSource [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-PressureSource\ntype PressureSource string\n\n// String returns the PressureSource as string value.\nfunc (t PressureSource) String() string {\n\treturn string(t)\n}\n\n// PressureSource values.\nconst (\n\tPressureSourceCPU PressureSource = \"cpu\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PressureSource) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PressureSource(s) {\n\tcase PressureSourceCPU:\n\t\t*t = PressureSourceCPU\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PressureSource value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PressureState [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-PressureState\ntype PressureState string\n\n// String returns the PressureState as string value.\nfunc (t PressureState) String() string {\n\treturn string(t)\n}\n\n// PressureState values.\nconst (\n\tPressureStateNominal  PressureState = \"nominal\"\n\tPressureStateFair     PressureState = \"fair\"\n\tPressureStateSerious  PressureState = \"serious\"\n\tPressureStateCritical PressureState = \"critical\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PressureState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PressureState(s) {\n\tcase PressureStateNominal:\n\t\t*t = PressureStateNominal\n\tcase PressureStateFair:\n\t\t*t = PressureStateFair\n\tcase PressureStateSerious:\n\t\t*t = PressureStateSerious\n\tcase PressureStateCritical:\n\t\t*t = PressureStateCritical\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PressureState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PressureMetadata [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-PressureMetadata\ntype PressureMetadata struct {\n\tAvailable bool `json:\"available\"`\n}\n\n// DisabledImageType enum of image types that can be disabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-DisabledImageType\ntype DisabledImageType string\n\n// String returns the DisabledImageType as string value.\nfunc (t DisabledImageType) String() string {\n\treturn string(t)\n}\n\n// DisabledImageType values.\nconst (\n\tDisabledImageTypeAvif DisabledImageType = \"avif\"\n\tDisabledImageTypeWebp DisabledImageType = \"webp\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DisabledImageType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DisabledImageType(s) {\n\tcase DisabledImageTypeAvif:\n\t\t*t = DisabledImageTypeAvif\n\tcase DisabledImageTypeWebp:\n\t\t*t = DisabledImageTypeWebp\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DisabledImageType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// OrientationType orientation type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-ScreenOrientation\ntype OrientationType string\n\n// String returns the OrientationType as string value.\nfunc (t OrientationType) String() string {\n\treturn string(t)\n}\n\n// OrientationType values.\nconst (\n\tOrientationTypePortraitPrimary    OrientationType = \"portraitPrimary\"\n\tOrientationTypePortraitSecondary  OrientationType = \"portraitSecondary\"\n\tOrientationTypeLandscapePrimary   OrientationType = \"landscapePrimary\"\n\tOrientationTypeLandscapeSecondary OrientationType = \"landscapeSecondary\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *OrientationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch OrientationType(s) {\n\tcase OrientationTypePortraitPrimary:\n\t\t*t = OrientationTypePortraitPrimary\n\tcase OrientationTypePortraitSecondary:\n\t\t*t = OrientationTypePortraitSecondary\n\tcase OrientationTypeLandscapePrimary:\n\t\t*t = OrientationTypeLandscapePrimary\n\tcase OrientationTypeLandscapeSecondary:\n\t\t*t = OrientationTypeLandscapeSecondary\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown OrientationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DisplayFeatureOrientation orientation of a display feature in relation to\n// screen.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-DisplayFeature\ntype DisplayFeatureOrientation string\n\n// String returns the DisplayFeatureOrientation as string value.\nfunc (t DisplayFeatureOrientation) String() string {\n\treturn string(t)\n}\n\n// DisplayFeatureOrientation values.\nconst (\n\tDisplayFeatureOrientationVertical   DisplayFeatureOrientation = \"vertical\"\n\tDisplayFeatureOrientationHorizontal DisplayFeatureOrientation = \"horizontal\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DisplayFeatureOrientation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DisplayFeatureOrientation(s) {\n\tcase DisplayFeatureOrientationVertical:\n\t\t*t = DisplayFeatureOrientationVertical\n\tcase DisplayFeatureOrientationHorizontal:\n\t\t*t = DisplayFeatureOrientationHorizontal\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DisplayFeatureOrientation value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DevicePostureType current posture of the device.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#type-DevicePosture\ntype DevicePostureType string\n\n// String returns the DevicePostureType as string value.\nfunc (t DevicePostureType) String() string {\n\treturn string(t)\n}\n\n// DevicePostureType values.\nconst (\n\tDevicePostureTypeContinuous DevicePostureType = \"continuous\"\n\tDevicePostureTypeFolded     DevicePostureType = \"folded\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DevicePostureType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DevicePostureType(s) {\n\tcase DevicePostureTypeContinuous:\n\t\t*t = DevicePostureTypeContinuous\n\tcase DevicePostureTypeFolded:\n\t\t*t = DevicePostureTypeFolded\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DevicePostureType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetEmitTouchEventsForMouseConfiguration touch/gesture events\n// configuration. Default: current platform.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setEmitTouchEventsForMouse\ntype SetEmitTouchEventsForMouseConfiguration string\n\n// String returns the SetEmitTouchEventsForMouseConfiguration as string value.\nfunc (t SetEmitTouchEventsForMouseConfiguration) String() string {\n\treturn string(t)\n}\n\n// SetEmitTouchEventsForMouseConfiguration values.\nconst (\n\tSetEmitTouchEventsForMouseConfigurationMobile  SetEmitTouchEventsForMouseConfiguration = \"mobile\"\n\tSetEmitTouchEventsForMouseConfigurationDesktop SetEmitTouchEventsForMouseConfiguration = \"desktop\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetEmitTouchEventsForMouseConfiguration) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetEmitTouchEventsForMouseConfiguration(s) {\n\tcase SetEmitTouchEventsForMouseConfigurationMobile:\n\t\t*t = SetEmitTouchEventsForMouseConfigurationMobile\n\tcase SetEmitTouchEventsForMouseConfigurationDesktop:\n\t\t*t = SetEmitTouchEventsForMouseConfigurationDesktop\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetEmitTouchEventsForMouseConfiguration value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetEmulatedVisionDeficiencyType vision deficiency to emulate. Order:\n// best-effort emulations come first, followed by any physiologically accurate\n// emulations for medically recognized color vision deficiencies.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Emulation#method-setEmulatedVisionDeficiency\ntype SetEmulatedVisionDeficiencyType string\n\n// String returns the SetEmulatedVisionDeficiencyType as string value.\nfunc (t SetEmulatedVisionDeficiencyType) String() string {\n\treturn string(t)\n}\n\n// SetEmulatedVisionDeficiencyType values.\nconst (\n\tSetEmulatedVisionDeficiencyTypeNone            SetEmulatedVisionDeficiencyType = \"none\"\n\tSetEmulatedVisionDeficiencyTypeBlurredVision   SetEmulatedVisionDeficiencyType = \"blurredVision\"\n\tSetEmulatedVisionDeficiencyTypeReducedContrast SetEmulatedVisionDeficiencyType = \"reducedContrast\"\n\tSetEmulatedVisionDeficiencyTypeAchromatopsia   SetEmulatedVisionDeficiencyType = \"achromatopsia\"\n\tSetEmulatedVisionDeficiencyTypeDeuteranopia    SetEmulatedVisionDeficiencyType = \"deuteranopia\"\n\tSetEmulatedVisionDeficiencyTypeProtanopia      SetEmulatedVisionDeficiencyType = \"protanopia\"\n\tSetEmulatedVisionDeficiencyTypeTritanopia      SetEmulatedVisionDeficiencyType = \"tritanopia\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetEmulatedVisionDeficiencyType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetEmulatedVisionDeficiencyType(s) {\n\tcase SetEmulatedVisionDeficiencyTypeNone:\n\t\t*t = SetEmulatedVisionDeficiencyTypeNone\n\tcase SetEmulatedVisionDeficiencyTypeBlurredVision:\n\t\t*t = SetEmulatedVisionDeficiencyTypeBlurredVision\n\tcase SetEmulatedVisionDeficiencyTypeReducedContrast:\n\t\t*t = SetEmulatedVisionDeficiencyTypeReducedContrast\n\tcase SetEmulatedVisionDeficiencyTypeAchromatopsia:\n\t\t*t = SetEmulatedVisionDeficiencyTypeAchromatopsia\n\tcase SetEmulatedVisionDeficiencyTypeDeuteranopia:\n\t\t*t = SetEmulatedVisionDeficiencyTypeDeuteranopia\n\tcase SetEmulatedVisionDeficiencyTypeProtanopia:\n\t\t*t = SetEmulatedVisionDeficiencyTypeProtanopia\n\tcase SetEmulatedVisionDeficiencyTypeTritanopia:\n\t\t*t = SetEmulatedVisionDeficiencyTypeTritanopia\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetEmulatedVisionDeficiencyType value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/eventbreakpoints/eventbreakpoints.go",
    "content": "// Package eventbreakpoints provides the Chrome DevTools Protocol\n// commands, types, and events for the EventBreakpoints domain.\n//\n// EventBreakpoints permits setting JavaScript breakpoints on operations and\n// events occurring in native code invoked from JavaScript. Once breakpoint is\n// hit, it is reported through Debugger domain, similarly to regular breakpoints\n// being hit.\n//\n// Generated by the cdproto-gen command.\npackage eventbreakpoints\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// SetInstrumentationBreakpointParams sets breakpoint on particular native\n// event.\ntype SetInstrumentationBreakpointParams struct {\n\tEventName string `json:\"eventName\"` // Instrumentation name to stop on.\n}\n\n// SetInstrumentationBreakpoint sets breakpoint on particular native event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/EventBreakpoints#method-setInstrumentationBreakpoint\n//\n// parameters:\n//\n//\teventName - Instrumentation name to stop on.\nfunc SetInstrumentationBreakpoint(eventName string) *SetInstrumentationBreakpointParams {\n\treturn &SetInstrumentationBreakpointParams{\n\t\tEventName: eventName,\n\t}\n}\n\n// Do executes EventBreakpoints.setInstrumentationBreakpoint against the provided context.\nfunc (p *SetInstrumentationBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetInstrumentationBreakpoint, p, nil)\n}\n\n// RemoveInstrumentationBreakpointParams removes breakpoint on particular\n// native event.\ntype RemoveInstrumentationBreakpointParams struct {\n\tEventName string `json:\"eventName\"` // Instrumentation name to stop on.\n}\n\n// RemoveInstrumentationBreakpoint removes breakpoint on particular native\n// event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/EventBreakpoints#method-removeInstrumentationBreakpoint\n//\n// parameters:\n//\n//\teventName - Instrumentation name to stop on.\nfunc RemoveInstrumentationBreakpoint(eventName string) *RemoveInstrumentationBreakpointParams {\n\treturn &RemoveInstrumentationBreakpointParams{\n\t\tEventName: eventName,\n\t}\n}\n\n// Do executes EventBreakpoints.removeInstrumentationBreakpoint against the provided context.\nfunc (p *RemoveInstrumentationBreakpointParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveInstrumentationBreakpoint, p, nil)\n}\n\n// DisableParams removes all breakpoints.\ntype DisableParams struct{}\n\n// Disable removes all breakpoints.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/EventBreakpoints#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes EventBreakpoints.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// Command names.\nconst (\n\tCommandSetInstrumentationBreakpoint    = \"EventBreakpoints.setInstrumentationBreakpoint\"\n\tCommandRemoveInstrumentationBreakpoint = \"EventBreakpoints.removeInstrumentationBreakpoint\"\n\tCommandDisable                         = \"EventBreakpoints.disable\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/extensions/extensions.go",
    "content": "// Package extensions provides the Chrome DevTools Protocol\n// commands, types, and events for the Extensions domain.\n//\n// Defines commands and events for browser extensions.\n//\n// Generated by the cdproto-gen command.\npackage extensions\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// LoadUnpackedParams installs an unpacked extension from the filesystem\n// similar to --load-extension CLI flags. Returns extension ID once the\n// extension has been installed. Available if the client is connected using the\n// --remote-debugging-pipe flag and the --enable-unsafe-extension-debugging flag\n// is set.\ntype LoadUnpackedParams struct {\n\tPath string `json:\"path\"` // Absolute file path.\n}\n\n// LoadUnpacked installs an unpacked extension from the filesystem similar to\n// --load-extension CLI flags. Returns extension ID once the extension has been\n// installed. Available if the client is connected using the\n// --remote-debugging-pipe flag and the --enable-unsafe-extension-debugging flag\n// is set.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Extensions#method-loadUnpacked\n//\n// parameters:\n//\n//\tpath - Absolute file path.\nfunc LoadUnpacked(path string) *LoadUnpackedParams {\n\treturn &LoadUnpackedParams{\n\t\tPath: path,\n\t}\n}\n\n// LoadUnpackedReturns return values.\ntype LoadUnpackedReturns struct {\n\tID string `json:\"id,omitempty,omitzero\"` // Extension id.\n}\n\n// Do executes Extensions.loadUnpacked against the provided context.\n//\n// returns:\n//\n//\tid - Extension id.\nfunc (p *LoadUnpackedParams) Do(ctx context.Context) (id string, err error) {\n\t// execute\n\tvar res LoadUnpackedReturns\n\terr = cdp.Execute(ctx, CommandLoadUnpacked, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.ID, nil\n}\n\n// UninstallParams uninstalls an unpacked extension (others not supported)\n// from the profile. Available if the client is connected using the\n// --remote-debugging-pipe flag and the --enable-unsafe-extension-debugging.\ntype UninstallParams struct {\n\tID string `json:\"id\"` // Extension id.\n}\n\n// Uninstall uninstalls an unpacked extension (others not supported) from the\n// profile. Available if the client is connected using the\n// --remote-debugging-pipe flag and the --enable-unsafe-extension-debugging.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Extensions#method-uninstall\n//\n// parameters:\n//\n//\tid - Extension id.\nfunc Uninstall(id string) *UninstallParams {\n\treturn &UninstallParams{\n\t\tID: id,\n\t}\n}\n\n// Do executes Extensions.uninstall against the provided context.\nfunc (p *UninstallParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUninstall, p, nil)\n}\n\n// GetStorageItemsParams gets data from extension storage in the given\n// storageArea. If keys is specified, these are used to filter the result.\ntype GetStorageItemsParams struct {\n\tID          string      `json:\"id\"`                      // ID of extension.\n\tStorageArea StorageArea `json:\"storageArea\"`             // StorageArea to retrieve data from.\n\tKeys        []string    `json:\"keys,omitempty,omitzero\"` // Keys to retrieve.\n}\n\n// GetStorageItems gets data from extension storage in the given storageArea.\n// If keys is specified, these are used to filter the result.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Extensions#method-getStorageItems\n//\n// parameters:\n//\n//\tid - ID of extension.\n//\tstorageArea - StorageArea to retrieve data from.\nfunc GetStorageItems(id string, storageArea StorageArea) *GetStorageItemsParams {\n\treturn &GetStorageItemsParams{\n\t\tID:          id,\n\t\tStorageArea: storageArea,\n\t}\n}\n\n// WithKeys keys to retrieve.\nfunc (p GetStorageItemsParams) WithKeys(keys []string) *GetStorageItemsParams {\n\tp.Keys = keys\n\treturn &p\n}\n\n// GetStorageItemsReturns return values.\ntype GetStorageItemsReturns struct {\n\tData jsontext.Value `json:\"data,omitempty,omitzero\"`\n}\n\n// Do executes Extensions.getStorageItems against the provided context.\n//\n// returns:\n//\n//\tdata\nfunc (p *GetStorageItemsParams) Do(ctx context.Context) (data jsontext.Value, err error) {\n\t// execute\n\tvar res GetStorageItemsReturns\n\terr = cdp.Execute(ctx, CommandGetStorageItems, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Data, nil\n}\n\n// RemoveStorageItemsParams removes keys from extension storage in the given\n// storageArea.\ntype RemoveStorageItemsParams struct {\n\tID          string      `json:\"id\"`          // ID of extension.\n\tStorageArea StorageArea `json:\"storageArea\"` // StorageArea to remove data from.\n\tKeys        []string    `json:\"keys\"`        // Keys to remove.\n}\n\n// RemoveStorageItems removes keys from extension storage in the given\n// storageArea.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Extensions#method-removeStorageItems\n//\n// parameters:\n//\n//\tid - ID of extension.\n//\tstorageArea - StorageArea to remove data from.\n//\tkeys - Keys to remove.\nfunc RemoveStorageItems(id string, storageArea StorageArea, keys []string) *RemoveStorageItemsParams {\n\treturn &RemoveStorageItemsParams{\n\t\tID:          id,\n\t\tStorageArea: storageArea,\n\t\tKeys:        keys,\n\t}\n}\n\n// Do executes Extensions.removeStorageItems against the provided context.\nfunc (p *RemoveStorageItemsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveStorageItems, p, nil)\n}\n\n// ClearStorageItemsParams clears extension storage in the given storageArea.\ntype ClearStorageItemsParams struct {\n\tID          string      `json:\"id\"`          // ID of extension.\n\tStorageArea StorageArea `json:\"storageArea\"` // StorageArea to remove data from.\n}\n\n// ClearStorageItems clears extension storage in the given storageArea.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Extensions#method-clearStorageItems\n//\n// parameters:\n//\n//\tid - ID of extension.\n//\tstorageArea - StorageArea to remove data from.\nfunc ClearStorageItems(id string, storageArea StorageArea) *ClearStorageItemsParams {\n\treturn &ClearStorageItemsParams{\n\t\tID:          id,\n\t\tStorageArea: storageArea,\n\t}\n}\n\n// Do executes Extensions.clearStorageItems against the provided context.\nfunc (p *ClearStorageItemsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearStorageItems, p, nil)\n}\n\n// SetStorageItemsParams sets values in extension storage in the given\n// storageArea. The provided values will be merged with existing values in the\n// storage area.\ntype SetStorageItemsParams struct {\n\tID          string         `json:\"id\"`          // ID of extension.\n\tStorageArea StorageArea    `json:\"storageArea\"` // StorageArea to set data in.\n\tValues      jsontext.Value `json:\"values\"`\n}\n\n// SetStorageItems sets values in extension storage in the given storageArea.\n// The provided values will be merged with existing values in the storage area.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Extensions#method-setStorageItems\n//\n// parameters:\n//\n//\tid - ID of extension.\n//\tstorageArea - StorageArea to set data in.\n//\tvalues - Values to set.\nfunc SetStorageItems(id string, storageArea StorageArea, values jsontext.Value) *SetStorageItemsParams {\n\treturn &SetStorageItemsParams{\n\t\tID:          id,\n\t\tStorageArea: storageArea,\n\t\tValues:      values,\n\t}\n}\n\n// Do executes Extensions.setStorageItems against the provided context.\nfunc (p *SetStorageItemsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetStorageItems, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandLoadUnpacked       = \"Extensions.loadUnpacked\"\n\tCommandUninstall          = \"Extensions.uninstall\"\n\tCommandGetStorageItems    = \"Extensions.getStorageItems\"\n\tCommandRemoveStorageItems = \"Extensions.removeStorageItems\"\n\tCommandClearStorageItems  = \"Extensions.clearStorageItems\"\n\tCommandSetStorageItems    = \"Extensions.setStorageItems\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/extensions/types.go",
    "content": "package extensions\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// StorageArea storage areas.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Extensions#type-StorageArea\ntype StorageArea string\n\n// String returns the StorageArea as string value.\nfunc (t StorageArea) String() string {\n\treturn string(t)\n}\n\n// StorageArea values.\nconst (\n\tStorageAreaSession StorageArea = \"session\"\n\tStorageAreaLocal   StorageArea = \"local\"\n\tStorageAreaSync    StorageArea = \"sync\"\n\tStorageAreaManaged StorageArea = \"managed\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *StorageArea) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch StorageArea(s) {\n\tcase StorageAreaSession:\n\t\t*t = StorageAreaSession\n\tcase StorageAreaLocal:\n\t\t*t = StorageAreaLocal\n\tcase StorageAreaSync:\n\t\t*t = StorageAreaSync\n\tcase StorageAreaManaged:\n\t\t*t = StorageAreaManaged\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown StorageArea value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/fedcm/events.go",
    "content": "package fedcm\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventDialogShown [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#event-dialogShown\ntype EventDialogShown struct {\n\tDialogID   string     `json:\"dialogId\"`\n\tDialogType DialogType `json:\"dialogType\"`\n\tAccounts   []*Account `json:\"accounts\"`\n\tTitle      string     `json:\"title\"` // These exist primarily so that the caller can verify the RP context was used appropriately.\n\tSubtitle   string     `json:\"subtitle,omitempty,omitzero\"`\n}\n\n// EventDialogClosed triggered when a dialog is closed, either by user\n// action, JS abort, or a command below.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#event-dialogClosed\ntype EventDialogClosed struct {\n\tDialogID string `json:\"dialogId\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/fedcm/fedcm.go",
    "content": "// Package fedcm provides the Chrome DevTools Protocol\n// commands, types, and events for the FedCm domain.\n//\n// This domain allows interacting with the FedCM dialog.\n//\n// Generated by the cdproto-gen command.\npackage fedcm\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams [no description].\ntype EnableParams struct {\n\tDisableRejectionDelay bool `json:\"disableRejectionDelay\"` // Allows callers to disable the promise rejection delay that would normally happen, if this is unimportant to what's being tested. (step 4 of https://fedidcg.github.io/FedCM/#browser-api-rp-sign-in)\n}\n\n// Enable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{\n\t\tDisableRejectionDelay: false,\n\t}\n}\n\n// WithDisableRejectionDelay allows callers to disable the promise rejection\n// delay that would normally happen, if this is unimportant to what's being\n// tested. (step 4 of https://fedidcg.github.io/FedCM/#browser-api-rp-sign-in).\nfunc (p EnableParams) WithDisableRejectionDelay(disableRejectionDelay bool) *EnableParams {\n\tp.DisableRejectionDelay = disableRejectionDelay\n\treturn &p\n}\n\n// Do executes FedCm.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// DisableParams [no description].\ntype DisableParams struct{}\n\n// Disable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes FedCm.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// SelectAccountParams [no description].\ntype SelectAccountParams struct {\n\tDialogID     string `json:\"dialogId\"`\n\tAccountIndex int64  `json:\"accountIndex\"`\n}\n\n// SelectAccount [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#method-selectAccount\n//\n// parameters:\n//\n//\tdialogID\n//\taccountIndex\nfunc SelectAccount(dialogID string, accountIndex int64) *SelectAccountParams {\n\treturn &SelectAccountParams{\n\t\tDialogID:     dialogID,\n\t\tAccountIndex: accountIndex,\n\t}\n}\n\n// Do executes FedCm.selectAccount against the provided context.\nfunc (p *SelectAccountParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSelectAccount, p, nil)\n}\n\n// ClickDialogButtonParams [no description].\ntype ClickDialogButtonParams struct {\n\tDialogID     string       `json:\"dialogId\"`\n\tDialogButton DialogButton `json:\"dialogButton\"`\n}\n\n// ClickDialogButton [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#method-clickDialogButton\n//\n// parameters:\n//\n//\tdialogID\n//\tdialogButton\nfunc ClickDialogButton(dialogID string, dialogButton DialogButton) *ClickDialogButtonParams {\n\treturn &ClickDialogButtonParams{\n\t\tDialogID:     dialogID,\n\t\tDialogButton: dialogButton,\n\t}\n}\n\n// Do executes FedCm.clickDialogButton against the provided context.\nfunc (p *ClickDialogButtonParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClickDialogButton, p, nil)\n}\n\n// OpenURLParams [no description].\ntype OpenURLParams struct {\n\tDialogID       string         `json:\"dialogId\"`\n\tAccountIndex   int64          `json:\"accountIndex\"`\n\tAccountURLType AccountURLType `json:\"accountUrlType\"`\n}\n\n// OpenURL [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#method-openUrl\n//\n// parameters:\n//\n//\tdialogID\n//\taccountIndex\n//\taccountURLType\nfunc OpenURL(dialogID string, accountIndex int64, accountURLType AccountURLType) *OpenURLParams {\n\treturn &OpenURLParams{\n\t\tDialogID:       dialogID,\n\t\tAccountIndex:   accountIndex,\n\t\tAccountURLType: accountURLType,\n\t}\n}\n\n// Do executes FedCm.openUrl against the provided context.\nfunc (p *OpenURLParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandOpenURL, p, nil)\n}\n\n// DismissDialogParams [no description].\ntype DismissDialogParams struct {\n\tDialogID        string `json:\"dialogId\"`\n\tTriggerCooldown bool   `json:\"triggerCooldown\"`\n}\n\n// DismissDialog [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#method-dismissDialog\n//\n// parameters:\n//\n//\tdialogID\nfunc DismissDialog(dialogID string) *DismissDialogParams {\n\treturn &DismissDialogParams{\n\t\tDialogID:        dialogID,\n\t\tTriggerCooldown: false,\n\t}\n}\n\n// WithTriggerCooldown [no description].\nfunc (p DismissDialogParams) WithTriggerCooldown(triggerCooldown bool) *DismissDialogParams {\n\tp.TriggerCooldown = triggerCooldown\n\treturn &p\n}\n\n// Do executes FedCm.dismissDialog against the provided context.\nfunc (p *DismissDialogParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDismissDialog, p, nil)\n}\n\n// ResetCooldownParams resets the cooldown time, if any, to allow the next\n// FedCM call to show a dialog even if one was recently dismissed by the user.\ntype ResetCooldownParams struct{}\n\n// ResetCooldown resets the cooldown time, if any, to allow the next FedCM\n// call to show a dialog even if one was recently dismissed by the user.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#method-resetCooldown\nfunc ResetCooldown() *ResetCooldownParams {\n\treturn &ResetCooldownParams{}\n}\n\n// Do executes FedCm.resetCooldown against the provided context.\nfunc (p *ResetCooldownParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandResetCooldown, nil, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable            = \"FedCm.enable\"\n\tCommandDisable           = \"FedCm.disable\"\n\tCommandSelectAccount     = \"FedCm.selectAccount\"\n\tCommandClickDialogButton = \"FedCm.clickDialogButton\"\n\tCommandOpenURL           = \"FedCm.openUrl\"\n\tCommandDismissDialog     = \"FedCm.dismissDialog\"\n\tCommandResetCooldown     = \"FedCm.resetCooldown\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/fedcm/types.go",
    "content": "package fedcm\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// LoginState whether this is a sign-up or sign-in action for this account,\n// i.e. whether this account has ever been used to sign in to this RP before.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#type-LoginState\ntype LoginState string\n\n// String returns the LoginState as string value.\nfunc (t LoginState) String() string {\n\treturn string(t)\n}\n\n// LoginState values.\nconst (\n\tLoginStateSignIn LoginState = \"SignIn\"\n\tLoginStateSignUp LoginState = \"SignUp\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *LoginState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch LoginState(s) {\n\tcase LoginStateSignIn:\n\t\t*t = LoginStateSignIn\n\tcase LoginStateSignUp:\n\t\t*t = LoginStateSignUp\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown LoginState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DialogType the types of FedCM dialogs.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#type-DialogType\ntype DialogType string\n\n// String returns the DialogType as string value.\nfunc (t DialogType) String() string {\n\treturn string(t)\n}\n\n// DialogType values.\nconst (\n\tDialogTypeAccountChooser  DialogType = \"AccountChooser\"\n\tDialogTypeAutoReauthn     DialogType = \"AutoReauthn\"\n\tDialogTypeConfirmIdpLogin DialogType = \"ConfirmIdpLogin\"\n\tDialogTypeError           DialogType = \"Error\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DialogType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DialogType(s) {\n\tcase DialogTypeAccountChooser:\n\t\t*t = DialogTypeAccountChooser\n\tcase DialogTypeAutoReauthn:\n\t\t*t = DialogTypeAutoReauthn\n\tcase DialogTypeConfirmIdpLogin:\n\t\t*t = DialogTypeConfirmIdpLogin\n\tcase DialogTypeError:\n\t\t*t = DialogTypeError\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DialogType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DialogButton the buttons on the FedCM dialog.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#type-DialogButton\ntype DialogButton string\n\n// String returns the DialogButton as string value.\nfunc (t DialogButton) String() string {\n\treturn string(t)\n}\n\n// DialogButton values.\nconst (\n\tDialogButtonConfirmIdpLoginContinue DialogButton = \"ConfirmIdpLoginContinue\"\n\tDialogButtonErrorGotIt              DialogButton = \"ErrorGotIt\"\n\tDialogButtonErrorMoreDetails        DialogButton = \"ErrorMoreDetails\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DialogButton) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DialogButton(s) {\n\tcase DialogButtonConfirmIdpLoginContinue:\n\t\t*t = DialogButtonConfirmIdpLoginContinue\n\tcase DialogButtonErrorGotIt:\n\t\t*t = DialogButtonErrorGotIt\n\tcase DialogButtonErrorMoreDetails:\n\t\t*t = DialogButtonErrorMoreDetails\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DialogButton value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AccountURLType the URLs that each account has.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#type-AccountUrlType\ntype AccountURLType string\n\n// String returns the AccountURLType as string value.\nfunc (t AccountURLType) String() string {\n\treturn string(t)\n}\n\n// AccountURLType values.\nconst (\n\tAccountURLTypeTermsOfService AccountURLType = \"TermsOfService\"\n\tAccountURLTypePrivacyPolicy  AccountURLType = \"PrivacyPolicy\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AccountURLType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AccountURLType(s) {\n\tcase AccountURLTypeTermsOfService:\n\t\t*t = AccountURLTypeTermsOfService\n\tcase AccountURLTypePrivacyPolicy:\n\t\t*t = AccountURLTypePrivacyPolicy\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AccountURLType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Account corresponds to IdentityRequestAccount.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FedCm#type-Account\ntype Account struct {\n\tAccountID         string     `json:\"accountId\"`\n\tEmail             string     `json:\"email\"`\n\tName              string     `json:\"name\"`\n\tGivenName         string     `json:\"givenName\"`\n\tPictureURL        string     `json:\"pictureUrl\"`\n\tIdpConfigURL      string     `json:\"idpConfigUrl\"`\n\tIdpLoginURL       string     `json:\"idpLoginUrl\"`\n\tLoginState        LoginState `json:\"loginState\"`\n\tTermsOfServiceURL string     `json:\"termsOfServiceUrl,omitempty,omitzero\"` // These two are only set if the loginState is signUp\n\tPrivacyPolicyURL  string     `json:\"privacyPolicyUrl,omitempty,omitzero\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/fetch/events.go",
    "content": "package fetch\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n)\n\n// EventRequestPaused issued when the domain is enabled and the request URL\n// matches the specified filter. The request is paused until the client responds\n// with one of continueRequest, failRequest or fulfillRequest. The stage of the\n// request can be determined by presence of responseErrorReason and\n// responseStatusCode -- the request is at the response stage if either of these\n// fields is present and in the request stage otherwise. Redirect responses and\n// subsequent requests are reported similarly to regular responses and requests.\n// Redirect responses may be distinguished by the value of responseStatusCode\n// (which is one of 301, 302, 303, 307, 308) along with presence of the location\n// header. Requests resulting from a redirect will have redirectedRequestId\n// field set.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#event-requestPaused\ntype EventRequestPaused struct {\n\tRequestID           RequestID            `json:\"requestId\"`                              // Each request the page makes will have a unique id.\n\tRequest             *network.Request     `json:\"request\"`                                // The details of the request.\n\tFrameID             cdp.FrameID          `json:\"frameId\"`                                // The id of the frame that initiated the request.\n\tResourceType        network.ResourceType `json:\"resourceType\"`                           // How the requested resource will be used.\n\tResponseErrorReason network.ErrorReason  `json:\"responseErrorReason,omitempty,omitzero\"` // Response error if intercepted at response stage.\n\tResponseStatusCode  int64                `json:\"responseStatusCode,omitempty,omitzero\"`  // Response code if intercepted at response stage.\n\tResponseStatusText  string               `json:\"responseStatusText,omitempty,omitzero\"`  // Response status text if intercepted at response stage.\n\tResponseHeaders     []*HeaderEntry       `json:\"responseHeaders,omitempty,omitzero\"`     // Response headers if intercepted at the response stage.\n\tNetworkID           network.RequestID    `json:\"networkId,omitempty,omitzero\"`           // If the intercepted request had a corresponding Network.requestWillBeSent event fired for it, then this networkId will be the same as the requestId present in the requestWillBeSent event.\n\tRedirectedRequestID RequestID            `json:\"redirectedRequestId,omitempty,omitzero\"` // If the request is due to a redirect response from the server, the id of the request that has caused the redirect.\n}\n\n// EventAuthRequired issued when the domain is enabled with\n// handleAuthRequests set to true. The request is paused until client responds\n// with continueWithAuth.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#event-authRequired\ntype EventAuthRequired struct {\n\tRequestID     RequestID            `json:\"requestId\"`     // Each request the page makes will have a unique id.\n\tRequest       *network.Request     `json:\"request\"`       // The details of the request.\n\tFrameID       cdp.FrameID          `json:\"frameId\"`       // The id of the frame that initiated the request.\n\tResourceType  network.ResourceType `json:\"resourceType\"`  // How the requested resource will be used.\n\tAuthChallenge *AuthChallenge       `json:\"authChallenge\"` // Details of the Authorization Challenge encountered. If this is set, client should respond with continueRequest that contains AuthChallengeResponse.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/fetch/fetch.go",
    "content": "// Package fetch provides the Chrome DevTools Protocol\n// commands, types, and events for the Fetch domain.\n//\n// A domain for letting clients substitute browser's network layer with\n// client code.\n//\n// Generated by the cdproto-gen command.\npackage fetch\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/io\"\n\t\"github.com/chromedp/cdproto/network\"\n)\n\n// DisableParams disables the fetch domain.\ntype DisableParams struct{}\n\n// Disable disables the fetch domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Fetch.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables issuing of requestPaused events. A request will be\n// paused until client calls one of failRequest, fulfillRequest or\n// continueRequest/continueWithAuth.\ntype EnableParams struct {\n\tPatterns           []*RequestPattern `json:\"patterns,omitempty,omitzero\"` // If specified, only requests matching any of these patterns will produce fetchRequested event and will be paused until clients response. If not set, all requests will be affected.\n\tHandleAuthRequests bool              `json:\"handleAuthRequests\"`          // If true, authRequired events will be issued and requests will be paused expecting a call to continueWithAuth.\n}\n\n// Enable enables issuing of requestPaused events. A request will be paused\n// until client calls one of failRequest, fulfillRequest or\n// continueRequest/continueWithAuth.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{\n\t\tHandleAuthRequests: false,\n\t}\n}\n\n// WithPatterns if specified, only requests matching any of these patterns\n// will produce fetchRequested event and will be paused until clients response.\n// If not set, all requests will be affected.\nfunc (p EnableParams) WithPatterns(patterns []*RequestPattern) *EnableParams {\n\tp.Patterns = patterns\n\treturn &p\n}\n\n// WithHandleAuthRequests if true, authRequired events will be issued and\n// requests will be paused expecting a call to continueWithAuth.\nfunc (p EnableParams) WithHandleAuthRequests(handleAuthRequests bool) *EnableParams {\n\tp.HandleAuthRequests = handleAuthRequests\n\treturn &p\n}\n\n// Do executes Fetch.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// FailRequestParams causes the request to fail with specified reason.\ntype FailRequestParams struct {\n\tRequestID   RequestID           `json:\"requestId\"`   // An id the client received in requestPaused event.\n\tErrorReason network.ErrorReason `json:\"errorReason\"` // Causes the request to fail with the given reason.\n}\n\n// FailRequest causes the request to fail with specified reason.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-failRequest\n//\n// parameters:\n//\n//\trequestID - An id the client received in requestPaused event.\n//\terrorReason - Causes the request to fail with the given reason.\nfunc FailRequest(requestID RequestID, errorReason network.ErrorReason) *FailRequestParams {\n\treturn &FailRequestParams{\n\t\tRequestID:   requestID,\n\t\tErrorReason: errorReason,\n\t}\n}\n\n// Do executes Fetch.failRequest against the provided context.\nfunc (p *FailRequestParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandFailRequest, p, nil)\n}\n\n// FulfillRequestParams provides response to the request.\ntype FulfillRequestParams struct {\n\tRequestID             RequestID      `json:\"requestId\"`                                // An id the client received in requestPaused event.\n\tResponseCode          int64          `json:\"responseCode\"`                             // An HTTP response code.\n\tResponseHeaders       []*HeaderEntry `json:\"responseHeaders,omitempty,omitzero\"`       // Response headers.\n\tBinaryResponseHeaders string         `json:\"binaryResponseHeaders,omitempty,omitzero\"` // Alternative way of specifying response headers as a \\0-separated series of name: value pairs. Prefer the above method unless you need to represent some non-UTF8 values that can't be transmitted over the protocol as text.\n\tBody                  string         `json:\"body,omitempty,omitzero\"`                  // A response body. If absent, original response body will be used if the request is intercepted at the response stage and empty body will be used if the request is intercepted at the request stage.\n\tResponsePhrase        string         `json:\"responsePhrase,omitempty,omitzero\"`        // A textual representation of responseCode. If absent, a standard phrase matching responseCode is used.\n}\n\n// FulfillRequest provides response to the request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-fulfillRequest\n//\n// parameters:\n//\n//\trequestID - An id the client received in requestPaused event.\n//\tresponseCode - An HTTP response code.\nfunc FulfillRequest(requestID RequestID, responseCode int64) *FulfillRequestParams {\n\treturn &FulfillRequestParams{\n\t\tRequestID:    requestID,\n\t\tResponseCode: responseCode,\n\t}\n}\n\n// WithResponseHeaders response headers.\nfunc (p FulfillRequestParams) WithResponseHeaders(responseHeaders []*HeaderEntry) *FulfillRequestParams {\n\tp.ResponseHeaders = responseHeaders\n\treturn &p\n}\n\n// WithBinaryResponseHeaders alternative way of specifying response headers\n// as a \\0-separated series of name: value pairs. Prefer the above method unless\n// you need to represent some non-UTF8 values that can't be transmitted over the\n// protocol as text.\nfunc (p FulfillRequestParams) WithBinaryResponseHeaders(binaryResponseHeaders string) *FulfillRequestParams {\n\tp.BinaryResponseHeaders = binaryResponseHeaders\n\treturn &p\n}\n\n// WithBody a response body. If absent, original response body will be used\n// if the request is intercepted at the response stage and empty body will be\n// used if the request is intercepted at the request stage.\nfunc (p FulfillRequestParams) WithBody(body string) *FulfillRequestParams {\n\tp.Body = body\n\treturn &p\n}\n\n// WithResponsePhrase a textual representation of responseCode. If absent, a\n// standard phrase matching responseCode is used.\nfunc (p FulfillRequestParams) WithResponsePhrase(responsePhrase string) *FulfillRequestParams {\n\tp.ResponsePhrase = responsePhrase\n\treturn &p\n}\n\n// Do executes Fetch.fulfillRequest against the provided context.\nfunc (p *FulfillRequestParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandFulfillRequest, p, nil)\n}\n\n// ContinueRequestParams continues the request, optionally modifying some of\n// its parameters.\ntype ContinueRequestParams struct {\n\tRequestID         RequestID      `json:\"requestId\"`                   // An id the client received in requestPaused event.\n\tURL               string         `json:\"url,omitempty,omitzero\"`      // If set, the request url will be modified in a way that's not observable by page.\n\tMethod            string         `json:\"method,omitempty,omitzero\"`   // If set, the request method is overridden.\n\tPostData          string         `json:\"postData,omitempty,omitzero\"` // If set, overrides the post data in the request.\n\tHeaders           []*HeaderEntry `json:\"headers,omitempty,omitzero\"`  // If set, overrides the request headers. Note that the overrides do not extend to subsequent redirect hops, if a redirect happens. Another override may be applied to a different request produced by a redirect.\n\tInterceptResponse bool           `json:\"interceptResponse\"`           // If set, overrides response interception behavior for this request.\n}\n\n// ContinueRequest continues the request, optionally modifying some of its\n// parameters.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-continueRequest\n//\n// parameters:\n//\n//\trequestID - An id the client received in requestPaused event.\nfunc ContinueRequest(requestID RequestID) *ContinueRequestParams {\n\treturn &ContinueRequestParams{\n\t\tRequestID:         requestID,\n\t\tInterceptResponse: false,\n\t}\n}\n\n// WithURL if set, the request url will be modified in a way that's not\n// observable by page.\nfunc (p ContinueRequestParams) WithURL(url string) *ContinueRequestParams {\n\tp.URL = url\n\treturn &p\n}\n\n// WithMethod if set, the request method is overridden.\nfunc (p ContinueRequestParams) WithMethod(method string) *ContinueRequestParams {\n\tp.Method = method\n\treturn &p\n}\n\n// WithPostData if set, overrides the post data in the request.\nfunc (p ContinueRequestParams) WithPostData(postData string) *ContinueRequestParams {\n\tp.PostData = postData\n\treturn &p\n}\n\n// WithHeaders if set, overrides the request headers. Note that the overrides\n// do not extend to subsequent redirect hops, if a redirect happens. Another\n// override may be applied to a different request produced by a redirect.\nfunc (p ContinueRequestParams) WithHeaders(headers []*HeaderEntry) *ContinueRequestParams {\n\tp.Headers = headers\n\treturn &p\n}\n\n// WithInterceptResponse if set, overrides response interception behavior for\n// this request.\nfunc (p ContinueRequestParams) WithInterceptResponse(interceptResponse bool) *ContinueRequestParams {\n\tp.InterceptResponse = interceptResponse\n\treturn &p\n}\n\n// Do executes Fetch.continueRequest against the provided context.\nfunc (p *ContinueRequestParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandContinueRequest, p, nil)\n}\n\n// ContinueWithAuthParams continues a request supplying authChallengeResponse\n// following authRequired event.\ntype ContinueWithAuthParams struct {\n\tRequestID             RequestID              `json:\"requestId\"`             // An id the client received in authRequired event.\n\tAuthChallengeResponse *AuthChallengeResponse `json:\"authChallengeResponse\"` // Response to  with an authChallenge.\n}\n\n// ContinueWithAuth continues a request supplying authChallengeResponse\n// following authRequired event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-continueWithAuth\n//\n// parameters:\n//\n//\trequestID - An id the client received in authRequired event.\n//\tauthChallengeResponse - Response to  with an authChallenge.\nfunc ContinueWithAuth(requestID RequestID, authChallengeResponse *AuthChallengeResponse) *ContinueWithAuthParams {\n\treturn &ContinueWithAuthParams{\n\t\tRequestID:             requestID,\n\t\tAuthChallengeResponse: authChallengeResponse,\n\t}\n}\n\n// Do executes Fetch.continueWithAuth against the provided context.\nfunc (p *ContinueWithAuthParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandContinueWithAuth, p, nil)\n}\n\n// ContinueResponseParams continues loading of the paused response,\n// optionally modifying the response headers. If either responseCode or headers\n// are modified, all of them must be present.\ntype ContinueResponseParams struct {\n\tRequestID             RequestID      `json:\"requestId\"`                                // An id the client received in requestPaused event.\n\tResponseCode          int64          `json:\"responseCode,omitempty,omitzero\"`          // An HTTP response code. If absent, original response code will be used.\n\tResponsePhrase        string         `json:\"responsePhrase,omitempty,omitzero\"`        // A textual representation of responseCode. If absent, a standard phrase matching responseCode is used.\n\tResponseHeaders       []*HeaderEntry `json:\"responseHeaders,omitempty,omitzero\"`       // Response headers. If absent, original response headers will be used.\n\tBinaryResponseHeaders string         `json:\"binaryResponseHeaders,omitempty,omitzero\"` // Alternative way of specifying response headers as a \\0-separated series of name: value pairs. Prefer the above method unless you need to represent some non-UTF8 values that can't be transmitted over the protocol as text.\n}\n\n// ContinueResponse continues loading of the paused response, optionally\n// modifying the response headers. If either responseCode or headers are\n// modified, all of them must be present.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-continueResponse\n//\n// parameters:\n//\n//\trequestID - An id the client received in requestPaused event.\nfunc ContinueResponse(requestID RequestID) *ContinueResponseParams {\n\treturn &ContinueResponseParams{\n\t\tRequestID: requestID,\n\t}\n}\n\n// WithResponseCode an HTTP response code. If absent, original response code\n// will be used.\nfunc (p ContinueResponseParams) WithResponseCode(responseCode int64) *ContinueResponseParams {\n\tp.ResponseCode = responseCode\n\treturn &p\n}\n\n// WithResponsePhrase a textual representation of responseCode. If absent, a\n// standard phrase matching responseCode is used.\nfunc (p ContinueResponseParams) WithResponsePhrase(responsePhrase string) *ContinueResponseParams {\n\tp.ResponsePhrase = responsePhrase\n\treturn &p\n}\n\n// WithResponseHeaders response headers. If absent, original response headers\n// will be used.\nfunc (p ContinueResponseParams) WithResponseHeaders(responseHeaders []*HeaderEntry) *ContinueResponseParams {\n\tp.ResponseHeaders = responseHeaders\n\treturn &p\n}\n\n// WithBinaryResponseHeaders alternative way of specifying response headers\n// as a \\0-separated series of name: value pairs. Prefer the above method unless\n// you need to represent some non-UTF8 values that can't be transmitted over the\n// protocol as text.\nfunc (p ContinueResponseParams) WithBinaryResponseHeaders(binaryResponseHeaders string) *ContinueResponseParams {\n\tp.BinaryResponseHeaders = binaryResponseHeaders\n\treturn &p\n}\n\n// Do executes Fetch.continueResponse against the provided context.\nfunc (p *ContinueResponseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandContinueResponse, p, nil)\n}\n\n// GetResponseBodyParams causes the body of the response to be received from\n// the server and returned as a single string. May only be issued for a request\n// that is paused in the Response stage and is mutually exclusive with\n// takeResponseBodyForInterceptionAsStream. Calling other methods that affect\n// the request or disabling fetch domain before body is received results in an\n// undefined behavior. Note that the response body is not available for\n// redirects. Requests paused in the _redirect received_ state may be\n// differentiated by responseCode and presence of location response header, see\n// comments to requestPaused for details.\ntype GetResponseBodyParams struct {\n\tRequestID RequestID `json:\"requestId\"` // Identifier for the intercepted request to get body for.\n}\n\n// GetResponseBody causes the body of the response to be received from the\n// server and returned as a single string. May only be issued for a request that\n// is paused in the Response stage and is mutually exclusive with\n// takeResponseBodyForInterceptionAsStream. Calling other methods that affect\n// the request or disabling fetch domain before body is received results in an\n// undefined behavior. Note that the response body is not available for\n// redirects. Requests paused in the _redirect received_ state may be\n// differentiated by responseCode and presence of location response header, see\n// comments to requestPaused for details.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-getResponseBody\n//\n// parameters:\n//\n//\trequestID - Identifier for the intercepted request to get body for.\nfunc GetResponseBody(requestID RequestID) *GetResponseBodyParams {\n\treturn &GetResponseBodyParams{\n\t\tRequestID: requestID,\n\t}\n}\n\n// GetResponseBodyReturns return values.\ntype GetResponseBodyReturns struct {\n\tBody          string `json:\"body,omitempty,omitzero\"` // Response body.\n\tBase64encoded bool   `json:\"base64Encoded\"`           // True, if content was sent as base64.\n}\n\n// Do executes Fetch.getResponseBody against the provided context.\n//\n// returns:\n//\n//\tbody - Response body.\nfunc (p *GetResponseBodyParams) Do(ctx context.Context) (body []byte, err error) {\n\t// execute\n\tvar res GetResponseBodyReturns\n\terr = cdp.Execute(ctx, CommandGetResponseBody, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tif res.Base64encoded {\n\t\tdec, err = base64.StdEncoding.DecodeString(res.Body)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tdec = []byte(res.Body)\n\t}\n\treturn dec, nil\n}\n\n// TakeResponseBodyAsStreamParams returns a handle to the stream representing\n// the response body. The request must be paused in the HeadersReceived stage.\n// Note that after this command the request can't be continued as is -- client\n// either needs to cancel it or to provide the response body. The stream only\n// supports sequential read, IO.read will fail if the position is specified.\n// This method is mutually exclusive with getResponseBody. Calling other methods\n// that affect the request or disabling fetch domain before body is received\n// results in an undefined behavior.\ntype TakeResponseBodyAsStreamParams struct {\n\tRequestID RequestID `json:\"requestId\"`\n}\n\n// TakeResponseBodyAsStream returns a handle to the stream representing the\n// response body. The request must be paused in the HeadersReceived stage. Note\n// that after this command the request can't be continued as is -- client either\n// needs to cancel it or to provide the response body. The stream only supports\n// sequential read, IO.read will fail if the position is specified. This method\n// is mutually exclusive with getResponseBody. Calling other methods that affect\n// the request or disabling fetch domain before body is received results in an\n// undefined behavior.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#method-takeResponseBodyAsStream\n//\n// parameters:\n//\n//\trequestID\nfunc TakeResponseBodyAsStream(requestID RequestID) *TakeResponseBodyAsStreamParams {\n\treturn &TakeResponseBodyAsStreamParams{\n\t\tRequestID: requestID,\n\t}\n}\n\n// TakeResponseBodyAsStreamReturns return values.\ntype TakeResponseBodyAsStreamReturns struct {\n\tStream io.StreamHandle `json:\"stream,omitempty,omitzero\"`\n}\n\n// Do executes Fetch.takeResponseBodyAsStream against the provided context.\n//\n// returns:\n//\n//\tstream\nfunc (p *TakeResponseBodyAsStreamParams) Do(ctx context.Context) (stream io.StreamHandle, err error) {\n\t// execute\n\tvar res TakeResponseBodyAsStreamReturns\n\terr = cdp.Execute(ctx, CommandTakeResponseBodyAsStream, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.Stream, nil\n}\n\n// Command names.\nconst (\n\tCommandDisable                  = \"Fetch.disable\"\n\tCommandEnable                   = \"Fetch.enable\"\n\tCommandFailRequest              = \"Fetch.failRequest\"\n\tCommandFulfillRequest           = \"Fetch.fulfillRequest\"\n\tCommandContinueRequest          = \"Fetch.continueRequest\"\n\tCommandContinueWithAuth         = \"Fetch.continueWithAuth\"\n\tCommandContinueResponse         = \"Fetch.continueResponse\"\n\tCommandGetResponseBody          = \"Fetch.getResponseBody\"\n\tCommandTakeResponseBodyAsStream = \"Fetch.takeResponseBodyAsStream\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/fetch/types.go",
    "content": "package fetch\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/network\"\n)\n\n// RequestID unique request identifier. Note that this does not identify\n// individual HTTP requests that are part of a network request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-RequestId\ntype RequestID string\n\n// String returns the RequestID as string value.\nfunc (t RequestID) String() string {\n\treturn string(t)\n}\n\n// RequestStage stages of the request to handle. Request will intercept\n// before the request is sent. Response will intercept after the response is\n// received (but before response body is received).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-RequestStage\ntype RequestStage string\n\n// String returns the RequestStage as string value.\nfunc (t RequestStage) String() string {\n\treturn string(t)\n}\n\n// RequestStage values.\nconst (\n\tRequestStageRequest  RequestStage = \"Request\"\n\tRequestStageResponse RequestStage = \"Response\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *RequestStage) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch RequestStage(s) {\n\tcase RequestStageRequest:\n\t\t*t = RequestStageRequest\n\tcase RequestStageResponse:\n\t\t*t = RequestStageResponse\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown RequestStage value: %v\", s)\n\t}\n\treturn nil\n}\n\n// RequestPattern [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-RequestPattern\ntype RequestPattern struct {\n\tURLPattern   string               `json:\"urlPattern,omitempty,omitzero\"`   // Wildcards ('*' -> zero or more, '?' -> exactly one) are allowed. Escape character is backslash. Omitting is equivalent to \"*\".\n\tResourceType network.ResourceType `json:\"resourceType,omitempty,omitzero\"` // If set, only requests for matching resource types will be intercepted.\n\tRequestStage RequestStage         `json:\"requestStage,omitempty,omitzero\"` // Stage at which to begin intercepting requests. Default is Request.\n}\n\n// HeaderEntry response HTTP header entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-HeaderEntry\ntype HeaderEntry struct {\n\tName  string `json:\"name\"`\n\tValue string `json:\"value\"`\n}\n\n// AuthChallenge authorization challenge for HTTP status code 401 or 407.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-AuthChallenge\ntype AuthChallenge struct {\n\tSource AuthChallengeSource `json:\"source,omitempty,omitzero\"` // Source of the authentication challenge.\n\tOrigin string              `json:\"origin\"`                    // Origin of the challenger.\n\tScheme string              `json:\"scheme\"`                    // The authentication scheme used, such as basic or digest\n\tRealm  string              `json:\"realm\"`                     // The realm of the challenge. May be empty.\n}\n\n// AuthChallengeResponse response to an AuthChallenge.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-AuthChallengeResponse\ntype AuthChallengeResponse struct {\n\tResponse AuthChallengeResponseResponse `json:\"response\"`                    // The decision on what to do in response to the authorization challenge.  Default means deferring to the default behavior of the net stack, which will likely either the Cancel authentication or display a popup dialog box.\n\tUsername string                        `json:\"username,omitempty,omitzero\"` // The username to provide, possibly empty. Should only be set if response is ProvideCredentials.\n\tPassword string                        `json:\"password,omitempty,omitzero\"` // The password to provide, possibly empty. Should only be set if response is ProvideCredentials.\n}\n\n// AuthChallengeSource source of the authentication challenge.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-AuthChallenge\ntype AuthChallengeSource string\n\n// String returns the AuthChallengeSource as string value.\nfunc (t AuthChallengeSource) String() string {\n\treturn string(t)\n}\n\n// AuthChallengeSource values.\nconst (\n\tAuthChallengeSourceServer AuthChallengeSource = \"Server\"\n\tAuthChallengeSourceProxy  AuthChallengeSource = \"Proxy\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AuthChallengeSource) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AuthChallengeSource(s) {\n\tcase AuthChallengeSourceServer:\n\t\t*t = AuthChallengeSourceServer\n\tcase AuthChallengeSourceProxy:\n\t\t*t = AuthChallengeSourceProxy\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AuthChallengeSource value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AuthChallengeResponseResponse the decision on what to do in response to\n// the authorization challenge. Default means deferring to the default behavior\n// of the net stack, which will likely either the Cancel authentication or\n// display a popup dialog box.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Fetch#type-AuthChallengeResponse\ntype AuthChallengeResponseResponse string\n\n// String returns the AuthChallengeResponseResponse as string value.\nfunc (t AuthChallengeResponseResponse) String() string {\n\treturn string(t)\n}\n\n// AuthChallengeResponseResponse values.\nconst (\n\tAuthChallengeResponseResponseDefault            AuthChallengeResponseResponse = \"Default\"\n\tAuthChallengeResponseResponseCancelAuth         AuthChallengeResponseResponse = \"CancelAuth\"\n\tAuthChallengeResponseResponseProvideCredentials AuthChallengeResponseResponse = \"ProvideCredentials\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AuthChallengeResponseResponse) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AuthChallengeResponseResponse(s) {\n\tcase AuthChallengeResponseResponseDefault:\n\t\t*t = AuthChallengeResponseResponseDefault\n\tcase AuthChallengeResponseResponseCancelAuth:\n\t\t*t = AuthChallengeResponseResponseCancelAuth\n\tcase AuthChallengeResponseResponseProvideCredentials:\n\t\t*t = AuthChallengeResponseResponseProvideCredentials\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AuthChallengeResponseResponse value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/filesystem/filesystem.go",
    "content": "// Package filesystem provides the Chrome DevTools Protocol\n// commands, types, and events for the FileSystem domain.\n//\n// Generated by the cdproto-gen command.\npackage filesystem\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// GetDirectoryParams [no description].\ntype GetDirectoryParams struct {\n\tBucketFileSystemLocator *BucketFileSystemLocator `json:\"bucketFileSystemLocator\"`\n}\n\n// GetDirectory [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FileSystem#method-getDirectory\n//\n// parameters:\n//\n//\tbucketFileSystemLocator\nfunc GetDirectory(bucketFileSystemLocator *BucketFileSystemLocator) *GetDirectoryParams {\n\treturn &GetDirectoryParams{\n\t\tBucketFileSystemLocator: bucketFileSystemLocator,\n\t}\n}\n\n// GetDirectoryReturns return values.\ntype GetDirectoryReturns struct {\n\tDirectory *Directory `json:\"directory,omitempty,omitzero\"` // Returns the directory object at the path.\n}\n\n// Do executes FileSystem.getDirectory against the provided context.\n//\n// returns:\n//\n//\tdirectory - Returns the directory object at the path.\nfunc (p *GetDirectoryParams) Do(ctx context.Context) (directory *Directory, err error) {\n\t// execute\n\tvar res GetDirectoryReturns\n\terr = cdp.Execute(ctx, CommandGetDirectory, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Directory, nil\n}\n\n// Command names.\nconst (\n\tCommandGetDirectory = \"FileSystem.getDirectory\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/filesystem/types.go",
    "content": "package filesystem\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/storage\"\n)\n\n// File [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FileSystem#type-File\ntype File struct {\n\tName         string              `json:\"name\"`\n\tLastModified *cdp.TimeSinceEpoch `json:\"lastModified\"` // Timestamp\n\tSize         float64             `json:\"size\"`         // Size in bytes\n\tType         string              `json:\"type\"`\n}\n\n// Directory [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FileSystem#type-Directory\ntype Directory struct {\n\tName              string   `json:\"name\"`\n\tNestedDirectories []string `json:\"nestedDirectories\"`\n\tNestedFiles       []*File  `json:\"nestedFiles\"` // Files that are directly nested under this directory.\n}\n\n// BucketFileSystemLocator [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/FileSystem#type-BucketFileSystemLocator\ntype BucketFileSystemLocator struct {\n\tStorageKey     storage.SerializedStorageKey `json:\"storageKey\"`                    // Storage key\n\tBucketName     string                       `json:\"bucketName,omitempty,omitzero\"` // Bucket name. Not passing a bucketName will retrieve the default Bucket. (https://developer.mozilla.org/en-US/docs/Web/API/Storage_API#storage_buckets)\n\tPathComponents []string                     `json:\"pathComponents\"`                // Path to the directory using each path component as an array item.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/headlessexperimental/headlessexperimental.go",
    "content": "// Package headlessexperimental provides the Chrome DevTools Protocol\n// commands, types, and events for the HeadlessExperimental domain.\n//\n// This domain provides experimental commands only supported in headless\n// mode.\n//\n// Generated by the cdproto-gen command.\npackage headlessexperimental\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// BeginFrameParams sends a BeginFrame to the target and returns when the\n// frame was completed. Optionally captures a screenshot from the resulting\n// frame. Requires that the target was created with enabled BeginFrameControl.\n// Designed for use with --run-all-compositor-stages-before-draw, see also\n// https://goo.gle/chrome-headless-rendering for more background.\ntype BeginFrameParams struct {\n\tFrameTimeTicks   float64           `json:\"frameTimeTicks,omitempty,omitzero\"` // Timestamp of this BeginFrame in Renderer TimeTicks (milliseconds of uptime). If not set, the current time will be used.\n\tInterval         float64           `json:\"interval,omitempty,omitzero\"`       // The interval between BeginFrames that is reported to the compositor, in milliseconds. Defaults to a 60 frames/second interval, i.e. about 16.666 milliseconds.\n\tNoDisplayUpdates bool              `json:\"noDisplayUpdates\"`                  // Whether updates should not be committed and drawn onto the display. False by default. If true, only side effects of the BeginFrame will be run, such as layout and animations, but any visual updates may not be visible on the display or in screenshots.\n\tScreenshot       *ScreenshotParams `json:\"screenshot,omitempty,omitzero\"`     // If set, a screenshot of the frame will be captured and returned in the response. Otherwise, no screenshot will be captured. Note that capturing a screenshot can fail, for example, during renderer initialization. In such a case, no screenshot data will be returned.\n}\n\n// BeginFrame sends a BeginFrame to the target and returns when the frame was\n// completed. Optionally captures a screenshot from the resulting frame.\n// Requires that the target was created with enabled BeginFrameControl. Designed\n// for use with --run-all-compositor-stages-before-draw, see also\n// https://goo.gle/chrome-headless-rendering for more background.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeadlessExperimental#method-beginFrame\n//\n// parameters:\nfunc BeginFrame() *BeginFrameParams {\n\treturn &BeginFrameParams{\n\t\tNoDisplayUpdates: false,\n\t}\n}\n\n// WithFrameTimeTicks timestamp of this BeginFrame in Renderer TimeTicks\n// (milliseconds of uptime). If not set, the current time will be used.\nfunc (p BeginFrameParams) WithFrameTimeTicks(frameTimeTicks float64) *BeginFrameParams {\n\tp.FrameTimeTicks = frameTimeTicks\n\treturn &p\n}\n\n// WithInterval the interval between BeginFrames that is reported to the\n// compositor, in milliseconds. Defaults to a 60 frames/second interval, i.e.\n// about 16.666 milliseconds.\nfunc (p BeginFrameParams) WithInterval(interval float64) *BeginFrameParams {\n\tp.Interval = interval\n\treturn &p\n}\n\n// WithNoDisplayUpdates whether updates should not be committed and drawn\n// onto the display. False by default. If true, only side effects of the\n// BeginFrame will be run, such as layout and animations, but any visual updates\n// may not be visible on the display or in screenshots.\nfunc (p BeginFrameParams) WithNoDisplayUpdates(noDisplayUpdates bool) *BeginFrameParams {\n\tp.NoDisplayUpdates = noDisplayUpdates\n\treturn &p\n}\n\n// WithScreenshot if set, a screenshot of the frame will be captured and\n// returned in the response. Otherwise, no screenshot will be captured. Note\n// that capturing a screenshot can fail, for example, during renderer\n// initialization. In such a case, no screenshot data will be returned.\nfunc (p BeginFrameParams) WithScreenshot(screenshot *ScreenshotParams) *BeginFrameParams {\n\tp.Screenshot = screenshot\n\treturn &p\n}\n\n// BeginFrameReturns return values.\ntype BeginFrameReturns struct {\n\tHasDamage      bool   `json:\"hasDamage\"`                         // Whether the BeginFrame resulted in damage and, thus, a new frame was committed to the display. Reported for diagnostic uses, may be removed in the future.\n\tScreenshotData string `json:\"screenshotData,omitempty,omitzero\"` // Base64-encoded image data of the screenshot, if one was requested and successfully taken.\n}\n\n// Do executes HeadlessExperimental.beginFrame against the provided context.\n//\n// returns:\n//\n//\thasDamage - Whether the BeginFrame resulted in damage and, thus, a new frame was committed to the display. Reported for diagnostic uses, may be removed in the future.\n//\tscreenshotData - Base64-encoded image data of the screenshot, if one was requested and successfully taken.\nfunc (p *BeginFrameParams) Do(ctx context.Context) (hasDamage bool, screenshotData []byte, err error) {\n\t// execute\n\tvar res BeginFrameReturns\n\terr = cdp.Execute(ctx, CommandBeginFrame, p, &res)\n\tif err != nil {\n\t\treturn false, nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tdec, err = base64.StdEncoding.DecodeString(res.ScreenshotData)\n\tif err != nil {\n\t\treturn false, nil, err\n\t}\n\treturn res.HasDamage, dec, nil\n}\n\n// Command names.\nconst (\n\tCommandBeginFrame = \"HeadlessExperimental.beginFrame\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/headlessexperimental/types.go",
    "content": "package headlessexperimental\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// ScreenshotParams encoding options for a screenshot.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeadlessExperimental#type-ScreenshotParams\ntype ScreenshotParams struct {\n\tFormat           ScreenshotParamsFormat `json:\"format,omitempty,omitzero\"`  // Image compression format (defaults to png).\n\tQuality          int64                  `json:\"quality,omitempty,omitzero\"` // Compression quality from range [0..100] (jpeg and webp only).\n\tOptimizeForSpeed bool                   `json:\"optimizeForSpeed\"`           // Optimize image encoding for speed, not for resulting size (defaults to false)\n}\n\n// ScreenshotParamsFormat image compression format (defaults to png).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeadlessExperimental#type-ScreenshotParams\ntype ScreenshotParamsFormat string\n\n// String returns the ScreenshotParamsFormat as string value.\nfunc (t ScreenshotParamsFormat) String() string {\n\treturn string(t)\n}\n\n// ScreenshotParamsFormat values.\nconst (\n\tScreenshotParamsFormatJpeg ScreenshotParamsFormat = \"jpeg\"\n\tScreenshotParamsFormatPng  ScreenshotParamsFormat = \"png\"\n\tScreenshotParamsFormatWebp ScreenshotParamsFormat = \"webp\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ScreenshotParamsFormat) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ScreenshotParamsFormat(s) {\n\tcase ScreenshotParamsFormatJpeg:\n\t\t*t = ScreenshotParamsFormatJpeg\n\tcase ScreenshotParamsFormatPng:\n\t\t*t = ScreenshotParamsFormatPng\n\tcase ScreenshotParamsFormatWebp:\n\t\t*t = ScreenshotParamsFormatWebp\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ScreenshotParamsFormat value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/heapprofiler/events.go",
    "content": "package heapprofiler\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventAddHeapSnapshotChunk [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#event-addHeapSnapshotChunk\ntype EventAddHeapSnapshotChunk struct {\n\tChunk string `json:\"chunk\"`\n}\n\n// EventHeapStatsUpdate if heap objects tracking has been started then\n// backend may send update for one or more fragments.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#event-heapStatsUpdate\ntype EventHeapStatsUpdate struct {\n\tStatsUpdate []int64 `json:\"statsUpdate\"` // An array of triplets. Each triplet describes a fragment. The first integer is the fragment index, the second integer is a total count of objects for the fragment, the third integer is a total size of the objects for the fragment.\n}\n\n// EventLastSeenObjectID if heap objects tracking has been started then\n// backend regularly sends a current value for last seen object id and\n// corresponding timestamp. If the were changes in the heap since last event\n// then one or more heapStatsUpdate events will be sent before a new\n// lastSeenObjectId event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#event-lastSeenObjectId\ntype EventLastSeenObjectID struct {\n\tLastSeenObjectID int64   `json:\"lastSeenObjectId\"`\n\tTimestamp        float64 `json:\"timestamp\"`\n}\n\n// EventReportHeapSnapshotProgress [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#event-reportHeapSnapshotProgress\ntype EventReportHeapSnapshotProgress struct {\n\tDone     int64 `json:\"done\"`\n\tTotal    int64 `json:\"total\"`\n\tFinished bool  `json:\"finished\"`\n}\n\n// EventResetProfiles [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#event-resetProfiles\ntype EventResetProfiles struct{}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/heapprofiler/heapprofiler.go",
    "content": "// Package heapprofiler provides the Chrome DevTools Protocol\n// commands, types, and events for the HeapProfiler domain.\n//\n// Generated by the cdproto-gen command.\npackage heapprofiler\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// AddInspectedHeapObjectParams enables console to refer to the node with\n// given id via $x (see Command Line API for more details $x functions).\ntype AddInspectedHeapObjectParams struct {\n\tHeapObjectID HeapSnapshotObjectID `json:\"heapObjectId\"` // Heap snapshot object id to be accessible by means of $x command line API.\n}\n\n// AddInspectedHeapObject enables console to refer to the node with given id\n// via $x (see Command Line API for more details $x functions).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-addInspectedHeapObject\n//\n// parameters:\n//\n//\theapObjectID - Heap snapshot object id to be accessible by means of $x command line API.\nfunc AddInspectedHeapObject(heapObjectID HeapSnapshotObjectID) *AddInspectedHeapObjectParams {\n\treturn &AddInspectedHeapObjectParams{\n\t\tHeapObjectID: heapObjectID,\n\t}\n}\n\n// Do executes HeapProfiler.addInspectedHeapObject against the provided context.\nfunc (p *AddInspectedHeapObjectParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandAddInspectedHeapObject, p, nil)\n}\n\n// CollectGarbageParams [no description].\ntype CollectGarbageParams struct{}\n\n// CollectGarbage [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-collectGarbage\nfunc CollectGarbage() *CollectGarbageParams {\n\treturn &CollectGarbageParams{}\n}\n\n// Do executes HeapProfiler.collectGarbage against the provided context.\nfunc (p *CollectGarbageParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCollectGarbage, nil, nil)\n}\n\n// DisableParams [no description].\ntype DisableParams struct{}\n\n// Disable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes HeapProfiler.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams [no description].\ntype EnableParams struct{}\n\n// Enable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes HeapProfiler.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// GetHeapObjectIDParams [no description].\ntype GetHeapObjectIDParams struct {\n\tObjectID runtime.RemoteObjectID `json:\"objectId\"` // Identifier of the object to get heap object id for.\n}\n\n// GetHeapObjectID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-getHeapObjectId\n//\n// parameters:\n//\n//\tobjectID - Identifier of the object to get heap object id for.\nfunc GetHeapObjectID(objectID runtime.RemoteObjectID) *GetHeapObjectIDParams {\n\treturn &GetHeapObjectIDParams{\n\t\tObjectID: objectID,\n\t}\n}\n\n// GetHeapObjectIDReturns return values.\ntype GetHeapObjectIDReturns struct {\n\tHeapSnapshotObjectID HeapSnapshotObjectID `json:\"heapSnapshotObjectId,omitempty,omitzero\"` // Id of the heap snapshot object corresponding to the passed remote object id.\n}\n\n// Do executes HeapProfiler.getHeapObjectId against the provided context.\n//\n// returns:\n//\n//\theapSnapshotObjectID - Id of the heap snapshot object corresponding to the passed remote object id.\nfunc (p *GetHeapObjectIDParams) Do(ctx context.Context) (heapSnapshotObjectID HeapSnapshotObjectID, err error) {\n\t// execute\n\tvar res GetHeapObjectIDReturns\n\terr = cdp.Execute(ctx, CommandGetHeapObjectID, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.HeapSnapshotObjectID, nil\n}\n\n// GetObjectByHeapObjectIDParams [no description].\ntype GetObjectByHeapObjectIDParams struct {\n\tObjectID    HeapSnapshotObjectID `json:\"objectId\"`\n\tObjectGroup string               `json:\"objectGroup,omitempty,omitzero\"` // Symbolic group name that can be used to release multiple objects.\n}\n\n// GetObjectByHeapObjectID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-getObjectByHeapObjectId\n//\n// parameters:\n//\n//\tobjectID\nfunc GetObjectByHeapObjectID(objectID HeapSnapshotObjectID) *GetObjectByHeapObjectIDParams {\n\treturn &GetObjectByHeapObjectIDParams{\n\t\tObjectID: objectID,\n\t}\n}\n\n// WithObjectGroup symbolic group name that can be used to release multiple\n// objects.\nfunc (p GetObjectByHeapObjectIDParams) WithObjectGroup(objectGroup string) *GetObjectByHeapObjectIDParams {\n\tp.ObjectGroup = objectGroup\n\treturn &p\n}\n\n// GetObjectByHeapObjectIDReturns return values.\ntype GetObjectByHeapObjectIDReturns struct {\n\tResult *runtime.RemoteObject `json:\"result,omitempty,omitzero\"` // Evaluation result.\n}\n\n// Do executes HeapProfiler.getObjectByHeapObjectId against the provided context.\n//\n// returns:\n//\n//\tresult - Evaluation result.\nfunc (p *GetObjectByHeapObjectIDParams) Do(ctx context.Context) (result *runtime.RemoteObject, err error) {\n\t// execute\n\tvar res GetObjectByHeapObjectIDReturns\n\terr = cdp.Execute(ctx, CommandGetObjectByHeapObjectID, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Result, nil\n}\n\n// GetSamplingProfileParams [no description].\ntype GetSamplingProfileParams struct{}\n\n// GetSamplingProfile [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-getSamplingProfile\nfunc GetSamplingProfile() *GetSamplingProfileParams {\n\treturn &GetSamplingProfileParams{}\n}\n\n// GetSamplingProfileReturns return values.\ntype GetSamplingProfileReturns struct {\n\tProfile *SamplingHeapProfile `json:\"profile,omitempty,omitzero\"` // Return the sampling profile being collected.\n}\n\n// Do executes HeapProfiler.getSamplingProfile against the provided context.\n//\n// returns:\n//\n//\tprofile - Return the sampling profile being collected.\nfunc (p *GetSamplingProfileParams) Do(ctx context.Context) (profile *SamplingHeapProfile, err error) {\n\t// execute\n\tvar res GetSamplingProfileReturns\n\terr = cdp.Execute(ctx, CommandGetSamplingProfile, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Profile, nil\n}\n\n// StartSamplingParams [no description].\ntype StartSamplingParams struct {\n\tSamplingInterval                 float64 `json:\"samplingInterval,omitempty,omitzero\"` // Average sample interval in bytes. Poisson distribution is used for the intervals. The default value is 32768 bytes.\n\tIncludeObjectsCollectedByMajorGC bool    `json:\"includeObjectsCollectedByMajorGC\"`    // By default, the sampling heap profiler reports only objects which are still alive when the profile is returned via getSamplingProfile or stopSampling, which is useful for determining what functions contribute the most to steady-state memory usage. This flag instructs the sampling heap profiler to also include information about objects discarded by major GC, which will show which functions cause large temporary memory usage or long GC pauses.\n\tIncludeObjectsCollectedByMinorGC bool    `json:\"includeObjectsCollectedByMinorGC\"`    // By default, the sampling heap profiler reports only objects which are still alive when the profile is returned via getSamplingProfile or stopSampling, which is useful for determining what functions contribute the most to steady-state memory usage. This flag instructs the sampling heap profiler to also include information about objects discarded by minor GC, which is useful when tuning a latency-sensitive application for minimal GC activity.\n}\n\n// StartSampling [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-startSampling\n//\n// parameters:\nfunc StartSampling() *StartSamplingParams {\n\treturn &StartSamplingParams{\n\t\tIncludeObjectsCollectedByMajorGC: false,\n\t\tIncludeObjectsCollectedByMinorGC: false,\n\t}\n}\n\n// WithSamplingInterval average sample interval in bytes. Poisson\n// distribution is used for the intervals. The default value is 32768 bytes.\nfunc (p StartSamplingParams) WithSamplingInterval(samplingInterval float64) *StartSamplingParams {\n\tp.SamplingInterval = samplingInterval\n\treturn &p\n}\n\n// WithIncludeObjectsCollectedByMajorGC by default, the sampling heap\n// profiler reports only objects which are still alive when the profile is\n// returned via getSamplingProfile or stopSampling, which is useful for\n// determining what functions contribute the most to steady-state memory usage.\n// This flag instructs the sampling heap profiler to also include information\n// about objects discarded by major GC, which will show which functions cause\n// large temporary memory usage or long GC pauses.\nfunc (p StartSamplingParams) WithIncludeObjectsCollectedByMajorGC(includeObjectsCollectedByMajorGC bool) *StartSamplingParams {\n\tp.IncludeObjectsCollectedByMajorGC = includeObjectsCollectedByMajorGC\n\treturn &p\n}\n\n// WithIncludeObjectsCollectedByMinorGC by default, the sampling heap\n// profiler reports only objects which are still alive when the profile is\n// returned via getSamplingProfile or stopSampling, which is useful for\n// determining what functions contribute the most to steady-state memory usage.\n// This flag instructs the sampling heap profiler to also include information\n// about objects discarded by minor GC, which is useful when tuning a\n// latency-sensitive application for minimal GC activity.\nfunc (p StartSamplingParams) WithIncludeObjectsCollectedByMinorGC(includeObjectsCollectedByMinorGC bool) *StartSamplingParams {\n\tp.IncludeObjectsCollectedByMinorGC = includeObjectsCollectedByMinorGC\n\treturn &p\n}\n\n// Do executes HeapProfiler.startSampling against the provided context.\nfunc (p *StartSamplingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartSampling, p, nil)\n}\n\n// StartTrackingHeapObjectsParams [no description].\ntype StartTrackingHeapObjectsParams struct {\n\tTrackAllocations bool `json:\"trackAllocations\"`\n}\n\n// StartTrackingHeapObjects [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-startTrackingHeapObjects\n//\n// parameters:\nfunc StartTrackingHeapObjects() *StartTrackingHeapObjectsParams {\n\treturn &StartTrackingHeapObjectsParams{\n\t\tTrackAllocations: false,\n\t}\n}\n\n// WithTrackAllocations [no description].\nfunc (p StartTrackingHeapObjectsParams) WithTrackAllocations(trackAllocations bool) *StartTrackingHeapObjectsParams {\n\tp.TrackAllocations = trackAllocations\n\treturn &p\n}\n\n// Do executes HeapProfiler.startTrackingHeapObjects against the provided context.\nfunc (p *StartTrackingHeapObjectsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartTrackingHeapObjects, p, nil)\n}\n\n// StopSamplingParams [no description].\ntype StopSamplingParams struct{}\n\n// StopSampling [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-stopSampling\nfunc StopSampling() *StopSamplingParams {\n\treturn &StopSamplingParams{}\n}\n\n// StopSamplingReturns return values.\ntype StopSamplingReturns struct {\n\tProfile *SamplingHeapProfile `json:\"profile,omitempty,omitzero\"` // Recorded sampling heap profile.\n}\n\n// Do executes HeapProfiler.stopSampling against the provided context.\n//\n// returns:\n//\n//\tprofile - Recorded sampling heap profile.\nfunc (p *StopSamplingParams) Do(ctx context.Context) (profile *SamplingHeapProfile, err error) {\n\t// execute\n\tvar res StopSamplingReturns\n\terr = cdp.Execute(ctx, CommandStopSampling, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Profile, nil\n}\n\n// StopTrackingHeapObjectsParams [no description].\ntype StopTrackingHeapObjectsParams struct {\n\tReportProgress      bool `json:\"reportProgress\"`      // If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken when the tracking is stopped.\n\tCaptureNumericValue bool `json:\"captureNumericValue\"` // If true, numerical values are included in the snapshot\n\tExposeInternals     bool `json:\"exposeInternals\"`     // If true, exposes internals of the snapshot.\n}\n\n// StopTrackingHeapObjects [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-stopTrackingHeapObjects\n//\n// parameters:\nfunc StopTrackingHeapObjects() *StopTrackingHeapObjectsParams {\n\treturn &StopTrackingHeapObjectsParams{\n\t\tReportProgress:      false,\n\t\tCaptureNumericValue: false,\n\t\tExposeInternals:     false,\n\t}\n}\n\n// WithReportProgress if true 'reportHeapSnapshotProgress' events will be\n// generated while snapshot is being taken when the tracking is stopped.\nfunc (p StopTrackingHeapObjectsParams) WithReportProgress(reportProgress bool) *StopTrackingHeapObjectsParams {\n\tp.ReportProgress = reportProgress\n\treturn &p\n}\n\n// WithCaptureNumericValue if true, numerical values are included in the\n// snapshot.\nfunc (p StopTrackingHeapObjectsParams) WithCaptureNumericValue(captureNumericValue bool) *StopTrackingHeapObjectsParams {\n\tp.CaptureNumericValue = captureNumericValue\n\treturn &p\n}\n\n// WithExposeInternals if true, exposes internals of the snapshot.\nfunc (p StopTrackingHeapObjectsParams) WithExposeInternals(exposeInternals bool) *StopTrackingHeapObjectsParams {\n\tp.ExposeInternals = exposeInternals\n\treturn &p\n}\n\n// Do executes HeapProfiler.stopTrackingHeapObjects against the provided context.\nfunc (p *StopTrackingHeapObjectsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopTrackingHeapObjects, p, nil)\n}\n\n// TakeHeapSnapshotParams [no description].\ntype TakeHeapSnapshotParams struct {\n\tReportProgress      bool `json:\"reportProgress\"`      // If true 'reportHeapSnapshotProgress' events will be generated while snapshot is being taken.\n\tCaptureNumericValue bool `json:\"captureNumericValue\"` // If true, numerical values are included in the snapshot\n\tExposeInternals     bool `json:\"exposeInternals\"`     // If true, exposes internals of the snapshot.\n}\n\n// TakeHeapSnapshot [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#method-takeHeapSnapshot\n//\n// parameters:\nfunc TakeHeapSnapshot() *TakeHeapSnapshotParams {\n\treturn &TakeHeapSnapshotParams{\n\t\tReportProgress:      false,\n\t\tCaptureNumericValue: false,\n\t\tExposeInternals:     false,\n\t}\n}\n\n// WithReportProgress if true 'reportHeapSnapshotProgress' events will be\n// generated while snapshot is being taken.\nfunc (p TakeHeapSnapshotParams) WithReportProgress(reportProgress bool) *TakeHeapSnapshotParams {\n\tp.ReportProgress = reportProgress\n\treturn &p\n}\n\n// WithCaptureNumericValue if true, numerical values are included in the\n// snapshot.\nfunc (p TakeHeapSnapshotParams) WithCaptureNumericValue(captureNumericValue bool) *TakeHeapSnapshotParams {\n\tp.CaptureNumericValue = captureNumericValue\n\treturn &p\n}\n\n// WithExposeInternals if true, exposes internals of the snapshot.\nfunc (p TakeHeapSnapshotParams) WithExposeInternals(exposeInternals bool) *TakeHeapSnapshotParams {\n\tp.ExposeInternals = exposeInternals\n\treturn &p\n}\n\n// Do executes HeapProfiler.takeHeapSnapshot against the provided context.\nfunc (p *TakeHeapSnapshotParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTakeHeapSnapshot, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandAddInspectedHeapObject   = \"HeapProfiler.addInspectedHeapObject\"\n\tCommandCollectGarbage           = \"HeapProfiler.collectGarbage\"\n\tCommandDisable                  = \"HeapProfiler.disable\"\n\tCommandEnable                   = \"HeapProfiler.enable\"\n\tCommandGetHeapObjectID          = \"HeapProfiler.getHeapObjectId\"\n\tCommandGetObjectByHeapObjectID  = \"HeapProfiler.getObjectByHeapObjectId\"\n\tCommandGetSamplingProfile       = \"HeapProfiler.getSamplingProfile\"\n\tCommandStartSampling            = \"HeapProfiler.startSampling\"\n\tCommandStartTrackingHeapObjects = \"HeapProfiler.startTrackingHeapObjects\"\n\tCommandStopSampling             = \"HeapProfiler.stopSampling\"\n\tCommandStopTrackingHeapObjects  = \"HeapProfiler.stopTrackingHeapObjects\"\n\tCommandTakeHeapSnapshot         = \"HeapProfiler.takeHeapSnapshot\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/heapprofiler/types.go",
    "content": "package heapprofiler\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// HeapSnapshotObjectID heap snapshot object id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-HeapSnapshotObjectId\ntype HeapSnapshotObjectID string\n\n// String returns the HeapSnapshotObjectID as string value.\nfunc (t HeapSnapshotObjectID) String() string {\n\treturn string(t)\n}\n\n// SamplingHeapProfileNode sampling Heap Profile node. Holds callsite\n// information, allocation statistics and child nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-SamplingHeapProfileNode\ntype SamplingHeapProfileNode struct {\n\tCallFrame *runtime.CallFrame         `json:\"callFrame\"` // Function location.\n\tSelfSize  float64                    `json:\"selfSize\"`  // Allocations size in bytes for the node excluding children.\n\tID        int64                      `json:\"id\"`        // Node id. Ids are unique across all profiles collected between startSampling and stopSampling.\n\tChildren  []*SamplingHeapProfileNode `json:\"children\"`  // Child nodes.\n}\n\n// SamplingHeapProfileSample a single sample from a sampling profile.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-SamplingHeapProfileSample\ntype SamplingHeapProfileSample struct {\n\tSize    float64 `json:\"size\"`    // Allocation size in bytes attributed to the sample.\n\tNodeID  int64   `json:\"nodeId\"`  // Id of the corresponding profile tree node.\n\tOrdinal float64 `json:\"ordinal\"` // Time-ordered sample ordinal number. It is unique across all profiles retrieved between startSampling and stopSampling.\n}\n\n// SamplingHeapProfile sampling profile.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/HeapProfiler#type-SamplingHeapProfile\ntype SamplingHeapProfile struct {\n\tHead    *SamplingHeapProfileNode     `json:\"head\"`\n\tSamples []*SamplingHeapProfileSample `json:\"samples\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/indexeddb/indexeddb.go",
    "content": "// Package indexeddb provides the Chrome DevTools Protocol\n// commands, types, and events for the IndexedDB domain.\n//\n// Generated by the cdproto-gen command.\npackage indexeddb\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/storage\"\n)\n\n// ClearObjectStoreParams clears all entries from an object store.\ntype ClearObjectStoreParams struct {\n\tSecurityOrigin  string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, or storageBucket must be specified. Security origin.\n\tStorageKey      string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket   *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n\tDatabaseName    string          `json:\"databaseName\"`                      // Database name.\n\tObjectStoreName string          `json:\"objectStoreName\"`                   // Object store name.\n}\n\n// ClearObjectStore clears all entries from an object store.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-clearObjectStore\n//\n// parameters:\n//\n//\tdatabaseName - Database name.\n//\tobjectStoreName - Object store name.\nfunc ClearObjectStore(databaseName string, objectStoreName string) *ClearObjectStoreParams {\n\treturn &ClearObjectStoreParams{\n\t\tDatabaseName:    databaseName,\n\t\tObjectStoreName: objectStoreName,\n\t}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// or storageBucket must be specified. Security origin.\nfunc (p ClearObjectStoreParams) WithSecurityOrigin(securityOrigin string) *ClearObjectStoreParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p ClearObjectStoreParams) WithStorageKey(storageKey string) *ClearObjectStoreParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p ClearObjectStoreParams) WithStorageBucket(storageBucket *storage.Bucket) *ClearObjectStoreParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// Do executes IndexedDB.clearObjectStore against the provided context.\nfunc (p *ClearObjectStoreParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearObjectStore, p, nil)\n}\n\n// DeleteDatabaseParams deletes a database.\ntype DeleteDatabaseParams struct {\n\tSecurityOrigin string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, or storageBucket must be specified. Security origin.\n\tStorageKey     string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket  *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n\tDatabaseName   string          `json:\"databaseName\"`                      // Database name.\n}\n\n// DeleteDatabase deletes a database.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-deleteDatabase\n//\n// parameters:\n//\n//\tdatabaseName - Database name.\nfunc DeleteDatabase(databaseName string) *DeleteDatabaseParams {\n\treturn &DeleteDatabaseParams{\n\t\tDatabaseName: databaseName,\n\t}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// or storageBucket must be specified. Security origin.\nfunc (p DeleteDatabaseParams) WithSecurityOrigin(securityOrigin string) *DeleteDatabaseParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p DeleteDatabaseParams) WithStorageKey(storageKey string) *DeleteDatabaseParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p DeleteDatabaseParams) WithStorageBucket(storageBucket *storage.Bucket) *DeleteDatabaseParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// Do executes IndexedDB.deleteDatabase against the provided context.\nfunc (p *DeleteDatabaseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeleteDatabase, p, nil)\n}\n\n// DeleteObjectStoreEntriesParams delete a range of entries from an object\n// store.\ntype DeleteObjectStoreEntriesParams struct {\n\tSecurityOrigin  string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, or storageBucket must be specified. Security origin.\n\tStorageKey      string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket   *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n\tDatabaseName    string          `json:\"databaseName\"`\n\tObjectStoreName string          `json:\"objectStoreName\"`\n\tKeyRange        *KeyRange       `json:\"keyRange\"` // Range of entry keys to delete\n}\n\n// DeleteObjectStoreEntries delete a range of entries from an object store.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-deleteObjectStoreEntries\n//\n// parameters:\n//\n//\tdatabaseName\n//\tobjectStoreName\n//\tkeyRange - Range of entry keys to delete\nfunc DeleteObjectStoreEntries(databaseName string, objectStoreName string, keyRange *KeyRange) *DeleteObjectStoreEntriesParams {\n\treturn &DeleteObjectStoreEntriesParams{\n\t\tDatabaseName:    databaseName,\n\t\tObjectStoreName: objectStoreName,\n\t\tKeyRange:        keyRange,\n\t}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// or storageBucket must be specified. Security origin.\nfunc (p DeleteObjectStoreEntriesParams) WithSecurityOrigin(securityOrigin string) *DeleteObjectStoreEntriesParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p DeleteObjectStoreEntriesParams) WithStorageKey(storageKey string) *DeleteObjectStoreEntriesParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p DeleteObjectStoreEntriesParams) WithStorageBucket(storageBucket *storage.Bucket) *DeleteObjectStoreEntriesParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// Do executes IndexedDB.deleteObjectStoreEntries against the provided context.\nfunc (p *DeleteObjectStoreEntriesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeleteObjectStoreEntries, p, nil)\n}\n\n// DisableParams disables events from backend.\ntype DisableParams struct{}\n\n// Disable disables events from backend.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes IndexedDB.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables events from backend.\ntype EnableParams struct{}\n\n// Enable enables events from backend.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes IndexedDB.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// RequestDataParams requests data from object store or index.\ntype RequestDataParams struct {\n\tSecurityOrigin  string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, or storageBucket must be specified. Security origin.\n\tStorageKey      string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket   *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n\tDatabaseName    string          `json:\"databaseName\"`                      // Database name.\n\tObjectStoreName string          `json:\"objectStoreName\"`                   // Object store name.\n\tIndexName       string          `json:\"indexName\"`                         // Index name, empty string for object store data requests.\n\tSkipCount       int64           `json:\"skipCount\"`                         // Number of records to skip.\n\tPageSize        int64           `json:\"pageSize\"`                          // Number of records to fetch.\n\tKeyRange        *KeyRange       `json:\"keyRange,omitempty,omitzero\"`       // Key range.\n}\n\n// RequestData requests data from object store or index.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-requestData\n//\n// parameters:\n//\n//\tdatabaseName - Database name.\n//\tobjectStoreName - Object store name.\n//\tindexName - Index name, empty string for object store data requests.\n//\tskipCount - Number of records to skip.\n//\tpageSize - Number of records to fetch.\nfunc RequestData(databaseName string, objectStoreName string, indexName string, skipCount int64, pageSize int64) *RequestDataParams {\n\treturn &RequestDataParams{\n\t\tDatabaseName:    databaseName,\n\t\tObjectStoreName: objectStoreName,\n\t\tIndexName:       indexName,\n\t\tSkipCount:       skipCount,\n\t\tPageSize:        pageSize,\n\t}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// or storageBucket must be specified. Security origin.\nfunc (p RequestDataParams) WithSecurityOrigin(securityOrigin string) *RequestDataParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p RequestDataParams) WithStorageKey(storageKey string) *RequestDataParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p RequestDataParams) WithStorageBucket(storageBucket *storage.Bucket) *RequestDataParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// WithKeyRange key range.\nfunc (p RequestDataParams) WithKeyRange(keyRange *KeyRange) *RequestDataParams {\n\tp.KeyRange = keyRange\n\treturn &p\n}\n\n// RequestDataReturns return values.\ntype RequestDataReturns struct {\n\tObjectStoreDataEntries []*DataEntry `json:\"objectStoreDataEntries,omitempty,omitzero\"` // Array of object store data entries.\n\tHasMore                bool         `json:\"hasMore\"`                                   // If true, there are more entries to fetch in the given range.\n}\n\n// Do executes IndexedDB.requestData against the provided context.\n//\n// returns:\n//\n//\tobjectStoreDataEntries - Array of object store data entries.\n//\thasMore - If true, there are more entries to fetch in the given range.\nfunc (p *RequestDataParams) Do(ctx context.Context) (objectStoreDataEntries []*DataEntry, hasMore bool, err error) {\n\t// execute\n\tvar res RequestDataReturns\n\terr = cdp.Execute(ctx, CommandRequestData, p, &res)\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\n\treturn res.ObjectStoreDataEntries, res.HasMore, nil\n}\n\n// GetMetadataParams gets metadata of an object store.\ntype GetMetadataParams struct {\n\tSecurityOrigin  string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, or storageBucket must be specified. Security origin.\n\tStorageKey      string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket   *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n\tDatabaseName    string          `json:\"databaseName\"`                      // Database name.\n\tObjectStoreName string          `json:\"objectStoreName\"`                   // Object store name.\n}\n\n// GetMetadata gets metadata of an object store.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-getMetadata\n//\n// parameters:\n//\n//\tdatabaseName - Database name.\n//\tobjectStoreName - Object store name.\nfunc GetMetadata(databaseName string, objectStoreName string) *GetMetadataParams {\n\treturn &GetMetadataParams{\n\t\tDatabaseName:    databaseName,\n\t\tObjectStoreName: objectStoreName,\n\t}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// or storageBucket must be specified. Security origin.\nfunc (p GetMetadataParams) WithSecurityOrigin(securityOrigin string) *GetMetadataParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p GetMetadataParams) WithStorageKey(storageKey string) *GetMetadataParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p GetMetadataParams) WithStorageBucket(storageBucket *storage.Bucket) *GetMetadataParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// GetMetadataReturns return values.\ntype GetMetadataReturns struct {\n\tEntriesCount      float64 `json:\"entriesCount,omitempty,omitzero\"`      // the entries count\n\tKeyGeneratorValue float64 `json:\"keyGeneratorValue,omitempty,omitzero\"` // the current value of key generator, to become the next inserted key into the object store. Valid if objectStore.autoIncrement is true.\n}\n\n// Do executes IndexedDB.getMetadata against the provided context.\n//\n// returns:\n//\n//\tentriesCount - the entries count\n//\tkeyGeneratorValue - the current value of key generator, to become the next inserted key into the object store. Valid if objectStore.autoIncrement is true.\nfunc (p *GetMetadataParams) Do(ctx context.Context) (entriesCount float64, keyGeneratorValue float64, err error) {\n\t// execute\n\tvar res GetMetadataReturns\n\terr = cdp.Execute(ctx, CommandGetMetadata, p, &res)\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\n\treturn res.EntriesCount, res.KeyGeneratorValue, nil\n}\n\n// RequestDatabaseParams requests database with given name in given frame.\ntype RequestDatabaseParams struct {\n\tSecurityOrigin string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, or storageBucket must be specified. Security origin.\n\tStorageKey     string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket  *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n\tDatabaseName   string          `json:\"databaseName\"`                      // Database name.\n}\n\n// RequestDatabase requests database with given name in given frame.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-requestDatabase\n//\n// parameters:\n//\n//\tdatabaseName - Database name.\nfunc RequestDatabase(databaseName string) *RequestDatabaseParams {\n\treturn &RequestDatabaseParams{\n\t\tDatabaseName: databaseName,\n\t}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// or storageBucket must be specified. Security origin.\nfunc (p RequestDatabaseParams) WithSecurityOrigin(securityOrigin string) *RequestDatabaseParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p RequestDatabaseParams) WithStorageKey(storageKey string) *RequestDatabaseParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p RequestDatabaseParams) WithStorageBucket(storageBucket *storage.Bucket) *RequestDatabaseParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// RequestDatabaseReturns return values.\ntype RequestDatabaseReturns struct {\n\tDatabaseWithObjectStores *DatabaseWithObjectStores `json:\"databaseWithObjectStores,omitempty,omitzero\"` // Database with an array of object stores.\n}\n\n// Do executes IndexedDB.requestDatabase against the provided context.\n//\n// returns:\n//\n//\tdatabaseWithObjectStores - Database with an array of object stores.\nfunc (p *RequestDatabaseParams) Do(ctx context.Context) (databaseWithObjectStores *DatabaseWithObjectStores, err error) {\n\t// execute\n\tvar res RequestDatabaseReturns\n\terr = cdp.Execute(ctx, CommandRequestDatabase, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.DatabaseWithObjectStores, nil\n}\n\n// RequestDatabaseNamesParams requests database names for given security\n// origin.\ntype RequestDatabaseNamesParams struct {\n\tSecurityOrigin string          `json:\"securityOrigin,omitempty,omitzero\"` // At least and at most one of securityOrigin, storageKey, or storageBucket must be specified. Security origin.\n\tStorageKey     string          `json:\"storageKey,omitempty,omitzero\"`     // Storage key.\n\tStorageBucket  *storage.Bucket `json:\"storageBucket,omitempty,omitzero\"`  // Storage bucket. If not specified, it uses the default bucket.\n}\n\n// RequestDatabaseNames requests database names for given security origin.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#method-requestDatabaseNames\n//\n// parameters:\nfunc RequestDatabaseNames() *RequestDatabaseNamesParams {\n\treturn &RequestDatabaseNamesParams{}\n}\n\n// WithSecurityOrigin at least and at most one of securityOrigin, storageKey,\n// or storageBucket must be specified. Security origin.\nfunc (p RequestDatabaseNamesParams) WithSecurityOrigin(securityOrigin string) *RequestDatabaseNamesParams {\n\tp.SecurityOrigin = securityOrigin\n\treturn &p\n}\n\n// WithStorageKey storage key.\nfunc (p RequestDatabaseNamesParams) WithStorageKey(storageKey string) *RequestDatabaseNamesParams {\n\tp.StorageKey = storageKey\n\treturn &p\n}\n\n// WithStorageBucket storage bucket. If not specified, it uses the default\n// bucket.\nfunc (p RequestDatabaseNamesParams) WithStorageBucket(storageBucket *storage.Bucket) *RequestDatabaseNamesParams {\n\tp.StorageBucket = storageBucket\n\treturn &p\n}\n\n// RequestDatabaseNamesReturns return values.\ntype RequestDatabaseNamesReturns struct {\n\tDatabaseNames []string `json:\"databaseNames,omitempty,omitzero\"` // Database names for origin.\n}\n\n// Do executes IndexedDB.requestDatabaseNames against the provided context.\n//\n// returns:\n//\n//\tdatabaseNames - Database names for origin.\nfunc (p *RequestDatabaseNamesParams) Do(ctx context.Context) (databaseNames []string, err error) {\n\t// execute\n\tvar res RequestDatabaseNamesReturns\n\terr = cdp.Execute(ctx, CommandRequestDatabaseNames, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.DatabaseNames, nil\n}\n\n// Command names.\nconst (\n\tCommandClearObjectStore         = \"IndexedDB.clearObjectStore\"\n\tCommandDeleteDatabase           = \"IndexedDB.deleteDatabase\"\n\tCommandDeleteObjectStoreEntries = \"IndexedDB.deleteObjectStoreEntries\"\n\tCommandDisable                  = \"IndexedDB.disable\"\n\tCommandEnable                   = \"IndexedDB.enable\"\n\tCommandRequestData              = \"IndexedDB.requestData\"\n\tCommandGetMetadata              = \"IndexedDB.getMetadata\"\n\tCommandRequestDatabase          = \"IndexedDB.requestDatabase\"\n\tCommandRequestDatabaseNames     = \"IndexedDB.requestDatabaseNames\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/indexeddb/types.go",
    "content": "package indexeddb\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// DatabaseWithObjectStores database with an array of object stores.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-DatabaseWithObjectStores\ntype DatabaseWithObjectStores struct {\n\tName         string         `json:\"name\"`         // Database name.\n\tVersion      float64        `json:\"version\"`      // Database version (type is not 'integer', as the standard requires the version number to be 'unsigned long long')\n\tObjectStores []*ObjectStore `json:\"objectStores\"` // Object stores in this database.\n}\n\n// ObjectStore object store.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-ObjectStore\ntype ObjectStore struct {\n\tName          string              `json:\"name\"`          // Object store name.\n\tKeyPath       *KeyPath            `json:\"keyPath\"`       // Object store key path.\n\tAutoIncrement bool                `json:\"autoIncrement\"` // If true, object store has auto increment flag set.\n\tIndexes       []*ObjectStoreIndex `json:\"indexes\"`       // Indexes in this object store.\n}\n\n// ObjectStoreIndex object store index.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-ObjectStoreIndex\ntype ObjectStoreIndex struct {\n\tName       string   `json:\"name\"`       // Index name.\n\tKeyPath    *KeyPath `json:\"keyPath\"`    // Index key path.\n\tUnique     bool     `json:\"unique\"`     // If true, index is unique.\n\tMultiEntry bool     `json:\"multiEntry\"` // If true, index allows multiple entries for a key.\n}\n\n// Key Key.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-Key\ntype Key struct {\n\tType   KeyType `json:\"type\"`                      // Key type.\n\tNumber float64 `json:\"number,omitempty,omitzero\"` // Number value.\n\tString string  `json:\"string,omitempty,omitzero\"` // String value.\n\tDate   float64 `json:\"date,omitempty,omitzero\"`   // Date value.\n\tArray  []*Key  `json:\"array,omitempty,omitzero\"`  // Array value.\n}\n\n// KeyRange key range.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-KeyRange\ntype KeyRange struct {\n\tLower     *Key `json:\"lower,omitempty,omitzero\"` // Lower bound.\n\tUpper     *Key `json:\"upper,omitempty,omitzero\"` // Upper bound.\n\tLowerOpen bool `json:\"lowerOpen\"`                // If true lower bound is open.\n\tUpperOpen bool `json:\"upperOpen\"`                // If true upper bound is open.\n}\n\n// DataEntry data entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-DataEntry\ntype DataEntry struct {\n\tKey        *runtime.RemoteObject `json:\"key\"`        // Key object.\n\tPrimaryKey *runtime.RemoteObject `json:\"primaryKey\"` // Primary key object.\n\tValue      *runtime.RemoteObject `json:\"value\"`      // Value object.\n}\n\n// KeyPath key path.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-KeyPath\ntype KeyPath struct {\n\tType   KeyPathType `json:\"type\"`                      // Key path type.\n\tString string      `json:\"string,omitempty,omitzero\"` // String value.\n\tArray  []string    `json:\"array,omitempty,omitzero\"`  // Array value.\n}\n\n// KeyType key type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-Key\ntype KeyType string\n\n// String returns the KeyType as string value.\nfunc (t KeyType) String() string {\n\treturn string(t)\n}\n\n// KeyType values.\nconst (\n\tKeyTypeNumber KeyType = \"number\"\n\tKeyTypeString KeyType = \"string\"\n\tKeyTypeDate   KeyType = \"date\"\n\tKeyTypeArray  KeyType = \"array\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *KeyType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch KeyType(s) {\n\tcase KeyTypeNumber:\n\t\t*t = KeyTypeNumber\n\tcase KeyTypeString:\n\t\t*t = KeyTypeString\n\tcase KeyTypeDate:\n\t\t*t = KeyTypeDate\n\tcase KeyTypeArray:\n\t\t*t = KeyTypeArray\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown KeyType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// KeyPathType key path type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IndexedDB#type-KeyPath\ntype KeyPathType string\n\n// String returns the KeyPathType as string value.\nfunc (t KeyPathType) String() string {\n\treturn string(t)\n}\n\n// KeyPathType values.\nconst (\n\tKeyPathTypeNull   KeyPathType = \"null\"\n\tKeyPathTypeString KeyPathType = \"string\"\n\tKeyPathTypeArray  KeyPathType = \"array\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *KeyPathType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch KeyPathType(s) {\n\tcase KeyPathTypeNull:\n\t\t*t = KeyPathTypeNull\n\tcase KeyPathTypeString:\n\t\t*t = KeyPathTypeString\n\tcase KeyPathTypeArray:\n\t\t*t = KeyPathTypeArray\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown KeyPathType value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/input/events.go",
    "content": "package input\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventDragIntercepted emitted only when Input.setInterceptDrags is enabled.\n// Use this data with Input.dispatchDragEvent to restore normal drag and drop\n// behavior.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#event-dragIntercepted\ntype EventDragIntercepted struct {\n\tData *DragData `json:\"data\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/input/input.go",
    "content": "// Package input provides the Chrome DevTools Protocol\n// commands, types, and events for the Input domain.\n//\n// Generated by the cdproto-gen command.\npackage input\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// DispatchDragEventParams dispatches a drag event into the page.\ntype DispatchDragEventParams struct {\n\tType      DispatchDragEventType `json:\"type\"` // Type of the drag event.\n\tX         float64               `json:\"x\"`    // X coordinate of the event relative to the main frame's viewport in CSS pixels.\n\tY         float64               `json:\"y\"`    // Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.\n\tData      *DragData             `json:\"data\"`\n\tModifiers Modifier              `json:\"modifiers\"` // Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0).\n}\n\n// DispatchDragEvent dispatches a drag event into the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchDragEvent\n//\n// parameters:\n//\n//\ttype - Type of the drag event.\n//\tx - X coordinate of the event relative to the main frame's viewport in CSS pixels.\n//\ty - Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.\n//\tdata\nfunc DispatchDragEvent(typeVal DispatchDragEventType, x float64, y float64, data *DragData) *DispatchDragEventParams {\n\treturn &DispatchDragEventParams{\n\t\tType: typeVal,\n\t\tX:    x,\n\t\tY:    y,\n\t\tData: data,\n\t}\n}\n\n// WithModifiers bit field representing pressed modifier keys. Alt=1, Ctrl=2,\n// Meta/Command=4, Shift=8 (default: 0).\nfunc (p DispatchDragEventParams) WithModifiers(modifiers Modifier) *DispatchDragEventParams {\n\tp.Modifiers = modifiers\n\treturn &p\n}\n\n// Do executes Input.dispatchDragEvent against the provided context.\nfunc (p *DispatchDragEventParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDispatchDragEvent, p, nil)\n}\n\n// DispatchKeyEventParams dispatches a key event to the page.\ntype DispatchKeyEventParams struct {\n\tType                  KeyType         `json:\"type\"`                                     // Type of the key event.\n\tModifiers             Modifier        `json:\"modifiers\"`                                // Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0).\n\tTimestamp             *TimeSinceEpoch `json:\"timestamp,omitempty,omitzero\"`             // Time at which the event occurred.\n\tText                  string          `json:\"text,omitempty,omitzero\"`                  // Text as generated by processing a virtual key code with a keyboard layout. Not needed for for keyUp and rawKeyDown events (default: \"\")\n\tUnmodifiedText        string          `json:\"unmodifiedText,omitempty,omitzero\"`        // Text that would have been generated by the keyboard if no modifiers were pressed (except for shift). Useful for shortcut (accelerator) key handling (default: \"\").\n\tKeyIdentifier         string          `json:\"keyIdentifier,omitempty,omitzero\"`         // Unique key identifier (e.g., 'U+0041') (default: \"\").\n\tCode                  string          `json:\"code,omitempty,omitzero\"`                  // Unique DOM defined string value for each physical key (e.g., 'KeyA') (default: \"\").\n\tKey                   string          `json:\"key,omitempty,omitzero\"`                   // Unique DOM defined string value describing the meaning of the key in the context of active modifiers, keyboard layout, etc (e.g., 'AltGr') (default: \"\").\n\tWindowsVirtualKeyCode int64           `json:\"windowsVirtualKeyCode,omitempty,omitzero\"` // Windows virtual key code (default: 0).\n\tNativeVirtualKeyCode  int64           `json:\"nativeVirtualKeyCode,omitempty,omitzero\"`  // Native virtual key code (default: 0).\n\tAutoRepeat            bool            `json:\"autoRepeat\"`                               // Whether the event was generated from auto repeat (default: false).\n\tIsKeypad              bool            `json:\"isKeypad\"`                                 // Whether the event was generated from the keypad (default: false).\n\tIsSystemKey           bool            `json:\"isSystemKey\"`                              // Whether the event was a system key event (default: false).\n\tLocation              int64           `json:\"location,omitempty,omitzero\"`              // Whether the event was from the left or right side of the keyboard. 1=Left, 2=Right (default: 0).\n\tCommands              []string        `json:\"commands,omitempty,omitzero\"`              // Editing commands to send with the key event (e.g., 'selectAll') (default: []). These are related to but not equal the command names used in document.execCommand and NSStandardKeyBindingResponding. See https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h for valid command names.\n}\n\n// DispatchKeyEvent dispatches a key event to the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchKeyEvent\n//\n// parameters:\n//\n//\ttype - Type of the key event.\nfunc DispatchKeyEvent(typeVal KeyType) *DispatchKeyEventParams {\n\treturn &DispatchKeyEventParams{\n\t\tType:        typeVal,\n\t\tAutoRepeat:  false,\n\t\tIsKeypad:    false,\n\t\tIsSystemKey: false,\n\t}\n}\n\n// WithModifiers bit field representing pressed modifier keys. Alt=1, Ctrl=2,\n// Meta/Command=4, Shift=8 (default: 0).\nfunc (p DispatchKeyEventParams) WithModifiers(modifiers Modifier) *DispatchKeyEventParams {\n\tp.Modifiers = modifiers\n\treturn &p\n}\n\n// WithTimestamp time at which the event occurred.\nfunc (p DispatchKeyEventParams) WithTimestamp(timestamp *TimeSinceEpoch) *DispatchKeyEventParams {\n\tp.Timestamp = timestamp\n\treturn &p\n}\n\n// WithText text as generated by processing a virtual key code with a\n// keyboard layout. Not needed for for keyUp and rawKeyDown events (default:\n// \"\").\nfunc (p DispatchKeyEventParams) WithText(text string) *DispatchKeyEventParams {\n\tp.Text = text\n\treturn &p\n}\n\n// WithUnmodifiedText text that would have been generated by the keyboard if\n// no modifiers were pressed (except for shift). Useful for shortcut\n// (accelerator) key handling (default: \"\").\nfunc (p DispatchKeyEventParams) WithUnmodifiedText(unmodifiedText string) *DispatchKeyEventParams {\n\tp.UnmodifiedText = unmodifiedText\n\treturn &p\n}\n\n// WithKeyIdentifier unique key identifier (e.g., 'U+0041') (default: \"\").\nfunc (p DispatchKeyEventParams) WithKeyIdentifier(keyIdentifier string) *DispatchKeyEventParams {\n\tp.KeyIdentifier = keyIdentifier\n\treturn &p\n}\n\n// WithCode unique DOM defined string value for each physical key (e.g.,\n// 'KeyA') (default: \"\").\nfunc (p DispatchKeyEventParams) WithCode(code string) *DispatchKeyEventParams {\n\tp.Code = code\n\treturn &p\n}\n\n// WithKey unique DOM defined string value describing the meaning of the key\n// in the context of active modifiers, keyboard layout, etc (e.g., 'AltGr')\n// (default: \"\").\nfunc (p DispatchKeyEventParams) WithKey(key string) *DispatchKeyEventParams {\n\tp.Key = key\n\treturn &p\n}\n\n// WithWindowsVirtualKeyCode windows virtual key code (default: 0).\nfunc (p DispatchKeyEventParams) WithWindowsVirtualKeyCode(windowsVirtualKeyCode int64) *DispatchKeyEventParams {\n\tp.WindowsVirtualKeyCode = windowsVirtualKeyCode\n\treturn &p\n}\n\n// WithNativeVirtualKeyCode native virtual key code (default: 0).\nfunc (p DispatchKeyEventParams) WithNativeVirtualKeyCode(nativeVirtualKeyCode int64) *DispatchKeyEventParams {\n\tp.NativeVirtualKeyCode = nativeVirtualKeyCode\n\treturn &p\n}\n\n// WithAutoRepeat whether the event was generated from auto repeat (default:\n// false).\nfunc (p DispatchKeyEventParams) WithAutoRepeat(autoRepeat bool) *DispatchKeyEventParams {\n\tp.AutoRepeat = autoRepeat\n\treturn &p\n}\n\n// WithIsKeypad whether the event was generated from the keypad (default:\n// false).\nfunc (p DispatchKeyEventParams) WithIsKeypad(isKeypad bool) *DispatchKeyEventParams {\n\tp.IsKeypad = isKeypad\n\treturn &p\n}\n\n// WithIsSystemKey whether the event was a system key event (default: false).\nfunc (p DispatchKeyEventParams) WithIsSystemKey(isSystemKey bool) *DispatchKeyEventParams {\n\tp.IsSystemKey = isSystemKey\n\treturn &p\n}\n\n// WithLocation whether the event was from the left or right side of the\n// keyboard. 1=Left, 2=Right (default: 0).\nfunc (p DispatchKeyEventParams) WithLocation(location int64) *DispatchKeyEventParams {\n\tp.Location = location\n\treturn &p\n}\n\n// WithCommands editing commands to send with the key event (e.g.,\n// 'selectAll') (default: []). These are related to but not equal the command\n// names used in document.execCommand and NSStandardKeyBindingResponding. See\n// https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h\n// for valid command names.\nfunc (p DispatchKeyEventParams) WithCommands(commands []string) *DispatchKeyEventParams {\n\tp.Commands = commands\n\treturn &p\n}\n\n// Do executes Input.dispatchKeyEvent against the provided context.\nfunc (p *DispatchKeyEventParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDispatchKeyEvent, p, nil)\n}\n\n// InsertTextParams this method emulates inserting text that doesn't come\n// from a key press, for example an emoji keyboard or an IME.\ntype InsertTextParams struct {\n\tText string `json:\"text\"` // The text to insert.\n}\n\n// InsertText this method emulates inserting text that doesn't come from a\n// key press, for example an emoji keyboard or an IME.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-insertText\n//\n// parameters:\n//\n//\ttext - The text to insert.\nfunc InsertText(text string) *InsertTextParams {\n\treturn &InsertTextParams{\n\t\tText: text,\n\t}\n}\n\n// Do executes Input.insertText against the provided context.\nfunc (p *InsertTextParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandInsertText, p, nil)\n}\n\n// ImeSetCompositionParams this method sets the current candidate text for\n// IME. Use imeCommitComposition to commit the final text. Use imeSetComposition\n// with empty string as text to cancel composition.\ntype ImeSetCompositionParams struct {\n\tText             string `json:\"text\"`                                // The text to insert\n\tSelectionStart   int64  `json:\"selectionStart\"`                      // selection start\n\tSelectionEnd     int64  `json:\"selectionEnd\"`                        // selection end\n\tReplacementStart int64  `json:\"replacementStart,omitempty,omitzero\"` // replacement start\n\tReplacementEnd   int64  `json:\"replacementEnd,omitempty,omitzero\"`   // replacement end\n}\n\n// ImeSetComposition this method sets the current candidate text for IME. Use\n// imeCommitComposition to commit the final text. Use imeSetComposition with\n// empty string as text to cancel composition.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-imeSetComposition\n//\n// parameters:\n//\n//\ttext - The text to insert\n//\tselectionStart - selection start\n//\tselectionEnd - selection end\nfunc ImeSetComposition(text string, selectionStart int64, selectionEnd int64) *ImeSetCompositionParams {\n\treturn &ImeSetCompositionParams{\n\t\tText:           text,\n\t\tSelectionStart: selectionStart,\n\t\tSelectionEnd:   selectionEnd,\n\t}\n}\n\n// WithReplacementStart replacement start.\nfunc (p ImeSetCompositionParams) WithReplacementStart(replacementStart int64) *ImeSetCompositionParams {\n\tp.ReplacementStart = replacementStart\n\treturn &p\n}\n\n// WithReplacementEnd replacement end.\nfunc (p ImeSetCompositionParams) WithReplacementEnd(replacementEnd int64) *ImeSetCompositionParams {\n\tp.ReplacementEnd = replacementEnd\n\treturn &p\n}\n\n// Do executes Input.imeSetComposition against the provided context.\nfunc (p *ImeSetCompositionParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandImeSetComposition, p, nil)\n}\n\n// DispatchMouseEventParams dispatches a mouse event to the page.\ntype DispatchMouseEventParams struct {\n\tType               MouseType                     `json:\"type\"`                                  // Type of the mouse event.\n\tX                  float64                       `json:\"x\"`                                     // X coordinate of the event relative to the main frame's viewport in CSS pixels.\n\tY                  float64                       `json:\"y\"`                                     // Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.\n\tModifiers          Modifier                      `json:\"modifiers\"`                             // Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0).\n\tTimestamp          *TimeSinceEpoch               `json:\"timestamp,omitempty,omitzero\"`          // Time at which the event occurred.\n\tButton             MouseButton                   `json:\"button,omitempty,omitzero\"`             // Mouse button (default: \"none\").\n\tButtons            int64                         `json:\"buttons,omitempty,omitzero\"`            // A number indicating which buttons are pressed on the mouse when a mouse event is triggered. Left=1, Right=2, Middle=4, Back=8, Forward=16, None=0.\n\tClickCount         int64                         `json:\"clickCount,omitempty,omitzero\"`         // Number of times the mouse button was clicked (default: 0).\n\tForce              float64                       `json:\"force,omitempty,omitzero\"`              // The normalized pressure, which has a range of [0,1] (default: 0).\n\tTangentialPressure float64                       `json:\"tangentialPressure,omitempty,omitzero\"` // The normalized tangential pressure, which has a range of [-1,1] (default: 0).\n\tTiltX              float64                       `json:\"tiltX,omitempty,omitzero\"`              // The plane angle between the Y-Z plane and the plane containing both the stylus axis and the Y axis, in degrees of the range [-90,90], a positive tiltX is to the right (default: 0).\n\tTiltY              float64                       `json:\"tiltY,omitempty,omitzero\"`              // The plane angle between the X-Z plane and the plane containing both the stylus axis and the X axis, in degrees of the range [-90,90], a positive tiltY is towards the user (default: 0).\n\tTwist              int64                         `json:\"twist,omitempty,omitzero\"`              // The clockwise rotation of a pen stylus around its own major axis, in degrees in the range [0,359] (default: 0).\n\tDeltaX             float64                       `json:\"deltaX\"`                                // X delta in CSS pixels for mouse wheel event (default: 0).\n\tDeltaY             float64                       `json:\"deltaY\"`                                // Y delta in CSS pixels for mouse wheel event (default: 0).\n\tPointerType        DispatchMouseEventPointerType `json:\"pointerType,omitempty,omitzero\"`        // Pointer type (default: \"mouse\").\n}\n\n// DispatchMouseEvent dispatches a mouse event to the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchMouseEvent\n//\n// parameters:\n//\n//\ttype - Type of the mouse event.\n//\tx - X coordinate of the event relative to the main frame's viewport in CSS pixels.\n//\ty - Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.\nfunc DispatchMouseEvent(typeVal MouseType, x float64, y float64) *DispatchMouseEventParams {\n\treturn &DispatchMouseEventParams{\n\t\tType: typeVal,\n\t\tX:    x,\n\t\tY:    y,\n\t}\n}\n\n// WithModifiers bit field representing pressed modifier keys. Alt=1, Ctrl=2,\n// Meta/Command=4, Shift=8 (default: 0).\nfunc (p DispatchMouseEventParams) WithModifiers(modifiers Modifier) *DispatchMouseEventParams {\n\tp.Modifiers = modifiers\n\treturn &p\n}\n\n// WithTimestamp time at which the event occurred.\nfunc (p DispatchMouseEventParams) WithTimestamp(timestamp *TimeSinceEpoch) *DispatchMouseEventParams {\n\tp.Timestamp = timestamp\n\treturn &p\n}\n\n// WithButton mouse button (default: \"none\").\nfunc (p DispatchMouseEventParams) WithButton(button MouseButton) *DispatchMouseEventParams {\n\tp.Button = button\n\treturn &p\n}\n\n// WithButtons a number indicating which buttons are pressed on the mouse\n// when a mouse event is triggered. Left=1, Right=2, Middle=4, Back=8,\n// Forward=16, None=0.\nfunc (p DispatchMouseEventParams) WithButtons(buttons int64) *DispatchMouseEventParams {\n\tp.Buttons = buttons\n\treturn &p\n}\n\n// WithClickCount number of times the mouse button was clicked (default: 0).\nfunc (p DispatchMouseEventParams) WithClickCount(clickCount int64) *DispatchMouseEventParams {\n\tp.ClickCount = clickCount\n\treturn &p\n}\n\n// WithForce the normalized pressure, which has a range of [0,1] (default:\n// 0).\nfunc (p DispatchMouseEventParams) WithForce(force float64) *DispatchMouseEventParams {\n\tp.Force = force\n\treturn &p\n}\n\n// WithTangentialPressure the normalized tangential pressure, which has a\n// range of [-1,1] (default: 0).\nfunc (p DispatchMouseEventParams) WithTangentialPressure(tangentialPressure float64) *DispatchMouseEventParams {\n\tp.TangentialPressure = tangentialPressure\n\treturn &p\n}\n\n// WithTiltX the plane angle between the Y-Z plane and the plane containing\n// both the stylus axis and the Y axis, in degrees of the range [-90,90], a\n// positive tiltX is to the right (default: 0).\nfunc (p DispatchMouseEventParams) WithTiltX(tiltX float64) *DispatchMouseEventParams {\n\tp.TiltX = tiltX\n\treturn &p\n}\n\n// WithTiltY the plane angle between the X-Z plane and the plane containing\n// both the stylus axis and the X axis, in degrees of the range [-90,90], a\n// positive tiltY is towards the user (default: 0).\nfunc (p DispatchMouseEventParams) WithTiltY(tiltY float64) *DispatchMouseEventParams {\n\tp.TiltY = tiltY\n\treturn &p\n}\n\n// WithTwist the clockwise rotation of a pen stylus around its own major\n// axis, in degrees in the range [0,359] (default: 0).\nfunc (p DispatchMouseEventParams) WithTwist(twist int64) *DispatchMouseEventParams {\n\tp.Twist = twist\n\treturn &p\n}\n\n// WithDeltaX X delta in CSS pixels for mouse wheel event (default: 0).\nfunc (p DispatchMouseEventParams) WithDeltaX(deltaX float64) *DispatchMouseEventParams {\n\tp.DeltaX = deltaX\n\treturn &p\n}\n\n// WithDeltaY Y delta in CSS pixels for mouse wheel event (default: 0).\nfunc (p DispatchMouseEventParams) WithDeltaY(deltaY float64) *DispatchMouseEventParams {\n\tp.DeltaY = deltaY\n\treturn &p\n}\n\n// WithPointerType pointer type (default: \"mouse\").\nfunc (p DispatchMouseEventParams) WithPointerType(pointerType DispatchMouseEventPointerType) *DispatchMouseEventParams {\n\tp.PointerType = pointerType\n\treturn &p\n}\n\n// Do executes Input.dispatchMouseEvent against the provided context.\nfunc (p *DispatchMouseEventParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDispatchMouseEvent, p, nil)\n}\n\n// DispatchTouchEventParams dispatches a touch event to the page.\ntype DispatchTouchEventParams struct {\n\tType        TouchType       `json:\"type\"`                         // Type of the touch event. TouchEnd and TouchCancel must not contain any touch points, while TouchStart and TouchMove must contains at least one.\n\tTouchPoints []*TouchPoint   `json:\"touchPoints\"`                  // Active touch points on the touch device. One event per any changed point (compared to previous touch event in a sequence) is generated, emulating pressing/moving/releasing points one by one.\n\tModifiers   Modifier        `json:\"modifiers\"`                    // Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0).\n\tTimestamp   *TimeSinceEpoch `json:\"timestamp,omitempty,omitzero\"` // Time at which the event occurred.\n}\n\n// DispatchTouchEvent dispatches a touch event to the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchTouchEvent\n//\n// parameters:\n//\n//\ttype - Type of the touch event. TouchEnd and TouchCancel must not contain any touch points, while TouchStart and TouchMove must contains at least one.\n//\ttouchPoints - Active touch points on the touch device. One event per any changed point (compared to previous touch event in a sequence) is generated, emulating pressing/moving/releasing points one by one.\nfunc DispatchTouchEvent(typeVal TouchType, touchPoints []*TouchPoint) *DispatchTouchEventParams {\n\treturn &DispatchTouchEventParams{\n\t\tType:        typeVal,\n\t\tTouchPoints: touchPoints,\n\t}\n}\n\n// WithModifiers bit field representing pressed modifier keys. Alt=1, Ctrl=2,\n// Meta/Command=4, Shift=8 (default: 0).\nfunc (p DispatchTouchEventParams) WithModifiers(modifiers Modifier) *DispatchTouchEventParams {\n\tp.Modifiers = modifiers\n\treturn &p\n}\n\n// WithTimestamp time at which the event occurred.\nfunc (p DispatchTouchEventParams) WithTimestamp(timestamp *TimeSinceEpoch) *DispatchTouchEventParams {\n\tp.Timestamp = timestamp\n\treturn &p\n}\n\n// Do executes Input.dispatchTouchEvent against the provided context.\nfunc (p *DispatchTouchEventParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDispatchTouchEvent, p, nil)\n}\n\n// CancelDraggingParams cancels any active dragging in the page.\ntype CancelDraggingParams struct{}\n\n// CancelDragging cancels any active dragging in the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-cancelDragging\nfunc CancelDragging() *CancelDraggingParams {\n\treturn &CancelDraggingParams{}\n}\n\n// Do executes Input.cancelDragging against the provided context.\nfunc (p *CancelDraggingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCancelDragging, nil, nil)\n}\n\n// EmulateTouchFromMouseEventParams emulates touch event from the mouse event\n// parameters.\ntype EmulateTouchFromMouseEventParams struct {\n\tType       MouseType       `json:\"type\"`                          // Type of the mouse event.\n\tX          int64           `json:\"x\"`                             // X coordinate of the mouse pointer in DIP.\n\tY          int64           `json:\"y\"`                             // Y coordinate of the mouse pointer in DIP.\n\tButton     MouseButton     `json:\"button\"`                        // Mouse button. Only \"none\", \"left\", \"right\" are supported.\n\tTimestamp  *TimeSinceEpoch `json:\"timestamp,omitempty,omitzero\"`  // Time at which the event occurred (default: current time).\n\tDeltaX     float64         `json:\"deltaX\"`                        // X delta in DIP for mouse wheel event (default: 0).\n\tDeltaY     float64         `json:\"deltaY\"`                        // Y delta in DIP for mouse wheel event (default: 0).\n\tModifiers  Modifier        `json:\"modifiers\"`                     // Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0).\n\tClickCount int64           `json:\"clickCount,omitempty,omitzero\"` // Number of times the mouse button was clicked (default: 0).\n}\n\n// EmulateTouchFromMouseEvent emulates touch event from the mouse event\n// parameters.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-emulateTouchFromMouseEvent\n//\n// parameters:\n//\n//\ttype - Type of the mouse event.\n//\tx - X coordinate of the mouse pointer in DIP.\n//\ty - Y coordinate of the mouse pointer in DIP.\n//\tbutton - Mouse button. Only \"none\", \"left\", \"right\" are supported.\nfunc EmulateTouchFromMouseEvent(typeVal MouseType, x int64, y int64, button MouseButton) *EmulateTouchFromMouseEventParams {\n\treturn &EmulateTouchFromMouseEventParams{\n\t\tType:   typeVal,\n\t\tX:      x,\n\t\tY:      y,\n\t\tButton: button,\n\t}\n}\n\n// WithTimestamp time at which the event occurred (default: current time).\nfunc (p EmulateTouchFromMouseEventParams) WithTimestamp(timestamp *TimeSinceEpoch) *EmulateTouchFromMouseEventParams {\n\tp.Timestamp = timestamp\n\treturn &p\n}\n\n// WithDeltaX X delta in DIP for mouse wheel event (default: 0).\nfunc (p EmulateTouchFromMouseEventParams) WithDeltaX(deltaX float64) *EmulateTouchFromMouseEventParams {\n\tp.DeltaX = deltaX\n\treturn &p\n}\n\n// WithDeltaY Y delta in DIP for mouse wheel event (default: 0).\nfunc (p EmulateTouchFromMouseEventParams) WithDeltaY(deltaY float64) *EmulateTouchFromMouseEventParams {\n\tp.DeltaY = deltaY\n\treturn &p\n}\n\n// WithModifiers bit field representing pressed modifier keys. Alt=1, Ctrl=2,\n// Meta/Command=4, Shift=8 (default: 0).\nfunc (p EmulateTouchFromMouseEventParams) WithModifiers(modifiers Modifier) *EmulateTouchFromMouseEventParams {\n\tp.Modifiers = modifiers\n\treturn &p\n}\n\n// WithClickCount number of times the mouse button was clicked (default: 0).\nfunc (p EmulateTouchFromMouseEventParams) WithClickCount(clickCount int64) *EmulateTouchFromMouseEventParams {\n\tp.ClickCount = clickCount\n\treturn &p\n}\n\n// Do executes Input.emulateTouchFromMouseEvent against the provided context.\nfunc (p *EmulateTouchFromMouseEventParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEmulateTouchFromMouseEvent, p, nil)\n}\n\n// SetIgnoreInputEventsParams ignores input events (useful while auditing\n// page).\ntype SetIgnoreInputEventsParams struct {\n\tIgnore bool `json:\"ignore\"` // Ignores input events processing when set to true.\n}\n\n// SetIgnoreInputEvents ignores input events (useful while auditing page).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-setIgnoreInputEvents\n//\n// parameters:\n//\n//\tignore - Ignores input events processing when set to true.\nfunc SetIgnoreInputEvents(ignore bool) *SetIgnoreInputEventsParams {\n\treturn &SetIgnoreInputEventsParams{\n\t\tIgnore: ignore,\n\t}\n}\n\n// Do executes Input.setIgnoreInputEvents against the provided context.\nfunc (p *SetIgnoreInputEventsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetIgnoreInputEvents, p, nil)\n}\n\n// SetInterceptDragsParams prevents default drag and drop behavior and\n// instead emits Input.dragIntercepted events. Drag and drop behavior can be\n// directly controlled via Input.dispatchDragEvent.\ntype SetInterceptDragsParams struct {\n\tEnabled bool `json:\"enabled\"`\n}\n\n// SetInterceptDrags prevents default drag and drop behavior and instead\n// emits Input.dragIntercepted events. Drag and drop behavior can be directly\n// controlled via Input.dispatchDragEvent.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-setInterceptDrags\n//\n// parameters:\n//\n//\tenabled\nfunc SetInterceptDrags(enabled bool) *SetInterceptDragsParams {\n\treturn &SetInterceptDragsParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Input.setInterceptDrags against the provided context.\nfunc (p *SetInterceptDragsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetInterceptDrags, p, nil)\n}\n\n// SynthesizePinchGestureParams synthesizes a pinch gesture over a time\n// period by issuing appropriate touch events.\ntype SynthesizePinchGestureParams struct {\n\tX                 float64           `json:\"x\"`                                    // X coordinate of the start of the gesture in CSS pixels.\n\tY                 float64           `json:\"y\"`                                    // Y coordinate of the start of the gesture in CSS pixels.\n\tScaleFactor       float64           `json:\"scaleFactor\"`                          // Relative scale factor after zooming (>1.0 zooms in, <1.0 zooms out).\n\tRelativeSpeed     int64             `json:\"relativeSpeed,omitempty,omitzero\"`     // Relative pointer speed in pixels per second (default: 800).\n\tGestureSourceType GestureSourceType `json:\"gestureSourceType,omitempty,omitzero\"` // Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type).\n}\n\n// SynthesizePinchGesture synthesizes a pinch gesture over a time period by\n// issuing appropriate touch events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-synthesizePinchGesture\n//\n// parameters:\n//\n//\tx - X coordinate of the start of the gesture in CSS pixels.\n//\ty - Y coordinate of the start of the gesture in CSS pixels.\n//\tscaleFactor - Relative scale factor after zooming (>1.0 zooms in, <1.0 zooms out).\nfunc SynthesizePinchGesture(x float64, y float64, scaleFactor float64) *SynthesizePinchGestureParams {\n\treturn &SynthesizePinchGestureParams{\n\t\tX:           x,\n\t\tY:           y,\n\t\tScaleFactor: scaleFactor,\n\t}\n}\n\n// WithRelativeSpeed relative pointer speed in pixels per second (default:\n// 800).\nfunc (p SynthesizePinchGestureParams) WithRelativeSpeed(relativeSpeed int64) *SynthesizePinchGestureParams {\n\tp.RelativeSpeed = relativeSpeed\n\treturn &p\n}\n\n// WithGestureSourceType which type of input events to be generated (default:\n// 'default', which queries the platform for the preferred input type).\nfunc (p SynthesizePinchGestureParams) WithGestureSourceType(gestureSourceType GestureSourceType) *SynthesizePinchGestureParams {\n\tp.GestureSourceType = gestureSourceType\n\treturn &p\n}\n\n// Do executes Input.synthesizePinchGesture against the provided context.\nfunc (p *SynthesizePinchGestureParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSynthesizePinchGesture, p, nil)\n}\n\n// SynthesizeScrollGestureParams synthesizes a scroll gesture over a time\n// period by issuing appropriate touch events.\ntype SynthesizeScrollGestureParams struct {\n\tX                     float64           `json:\"x\"`                                        // X coordinate of the start of the gesture in CSS pixels.\n\tY                     float64           `json:\"y\"`                                        // Y coordinate of the start of the gesture in CSS pixels.\n\tXDistance             float64           `json:\"xDistance,omitempty,omitzero\"`             // The distance to scroll along the X axis (positive to scroll left).\n\tYDistance             float64           `json:\"yDistance,omitempty,omitzero\"`             // The distance to scroll along the Y axis (positive to scroll up).\n\tXOverscroll           float64           `json:\"xOverscroll,omitempty,omitzero\"`           // The number of additional pixels to scroll back along the X axis, in addition to the given distance.\n\tYOverscroll           float64           `json:\"yOverscroll,omitempty,omitzero\"`           // The number of additional pixels to scroll back along the Y axis, in addition to the given distance.\n\tPreventFling          bool              `json:\"preventFling\"`                             // Prevent fling (default: true).\n\tSpeed                 int64             `json:\"speed,omitempty,omitzero\"`                 // Swipe speed in pixels per second (default: 800).\n\tGestureSourceType     GestureSourceType `json:\"gestureSourceType,omitempty,omitzero\"`     // Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type).\n\tRepeatCount           int64             `json:\"repeatCount,omitempty,omitzero\"`           // The number of times to repeat the gesture (default: 0).\n\tRepeatDelayMs         int64             `json:\"repeatDelayMs,omitempty,omitzero\"`         // The number of milliseconds delay between each repeat. (default: 250).\n\tInteractionMarkerName string            `json:\"interactionMarkerName,omitempty,omitzero\"` // The name of the interaction markers to generate, if not empty (default: \"\").\n}\n\n// SynthesizeScrollGesture synthesizes a scroll gesture over a time period by\n// issuing appropriate touch events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-synthesizeScrollGesture\n//\n// parameters:\n//\n//\tx - X coordinate of the start of the gesture in CSS pixels.\n//\ty - Y coordinate of the start of the gesture in CSS pixels.\nfunc SynthesizeScrollGesture(x float64, y float64) *SynthesizeScrollGestureParams {\n\treturn &SynthesizeScrollGestureParams{\n\t\tX:            x,\n\t\tY:            y,\n\t\tPreventFling: true,\n\t}\n}\n\n// WithXDistance the distance to scroll along the X axis (positive to scroll\n// left).\nfunc (p SynthesizeScrollGestureParams) WithXDistance(xDistance float64) *SynthesizeScrollGestureParams {\n\tp.XDistance = xDistance\n\treturn &p\n}\n\n// WithYDistance the distance to scroll along the Y axis (positive to scroll\n// up).\nfunc (p SynthesizeScrollGestureParams) WithYDistance(yDistance float64) *SynthesizeScrollGestureParams {\n\tp.YDistance = yDistance\n\treturn &p\n}\n\n// WithXOverscroll the number of additional pixels to scroll back along the X\n// axis, in addition to the given distance.\nfunc (p SynthesizeScrollGestureParams) WithXOverscroll(xOverscroll float64) *SynthesizeScrollGestureParams {\n\tp.XOverscroll = xOverscroll\n\treturn &p\n}\n\n// WithYOverscroll the number of additional pixels to scroll back along the Y\n// axis, in addition to the given distance.\nfunc (p SynthesizeScrollGestureParams) WithYOverscroll(yOverscroll float64) *SynthesizeScrollGestureParams {\n\tp.YOverscroll = yOverscroll\n\treturn &p\n}\n\n// WithPreventFling prevent fling (default: true).\nfunc (p SynthesizeScrollGestureParams) WithPreventFling(preventFling bool) *SynthesizeScrollGestureParams {\n\tp.PreventFling = preventFling\n\treturn &p\n}\n\n// WithSpeed swipe speed in pixels per second (default: 800).\nfunc (p SynthesizeScrollGestureParams) WithSpeed(speed int64) *SynthesizeScrollGestureParams {\n\tp.Speed = speed\n\treturn &p\n}\n\n// WithGestureSourceType which type of input events to be generated (default:\n// 'default', which queries the platform for the preferred input type).\nfunc (p SynthesizeScrollGestureParams) WithGestureSourceType(gestureSourceType GestureSourceType) *SynthesizeScrollGestureParams {\n\tp.GestureSourceType = gestureSourceType\n\treturn &p\n}\n\n// WithRepeatCount the number of times to repeat the gesture (default: 0).\nfunc (p SynthesizeScrollGestureParams) WithRepeatCount(repeatCount int64) *SynthesizeScrollGestureParams {\n\tp.RepeatCount = repeatCount\n\treturn &p\n}\n\n// WithRepeatDelayMs the number of milliseconds delay between each repeat.\n// (default: 250).\nfunc (p SynthesizeScrollGestureParams) WithRepeatDelayMs(repeatDelayMs int64) *SynthesizeScrollGestureParams {\n\tp.RepeatDelayMs = repeatDelayMs\n\treturn &p\n}\n\n// WithInteractionMarkerName the name of the interaction markers to generate,\n// if not empty (default: \"\").\nfunc (p SynthesizeScrollGestureParams) WithInteractionMarkerName(interactionMarkerName string) *SynthesizeScrollGestureParams {\n\tp.InteractionMarkerName = interactionMarkerName\n\treturn &p\n}\n\n// Do executes Input.synthesizeScrollGesture against the provided context.\nfunc (p *SynthesizeScrollGestureParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSynthesizeScrollGesture, p, nil)\n}\n\n// SynthesizeTapGestureParams synthesizes a tap gesture over a time period by\n// issuing appropriate touch events.\ntype SynthesizeTapGestureParams struct {\n\tX                 float64           `json:\"x\"`                                    // X coordinate of the start of the gesture in CSS pixels.\n\tY                 float64           `json:\"y\"`                                    // Y coordinate of the start of the gesture in CSS pixels.\n\tDuration          int64             `json:\"duration,omitempty,omitzero\"`          // Duration between touchdown and touchup events in ms (default: 50).\n\tTapCount          int64             `json:\"tapCount,omitempty,omitzero\"`          // Number of times to perform the tap (e.g. 2 for double tap, default: 1).\n\tGestureSourceType GestureSourceType `json:\"gestureSourceType,omitempty,omitzero\"` // Which type of input events to be generated (default: 'default', which queries the platform for the preferred input type).\n}\n\n// SynthesizeTapGesture synthesizes a tap gesture over a time period by\n// issuing appropriate touch events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-synthesizeTapGesture\n//\n// parameters:\n//\n//\tx - X coordinate of the start of the gesture in CSS pixels.\n//\ty - Y coordinate of the start of the gesture in CSS pixels.\nfunc SynthesizeTapGesture(x float64, y float64) *SynthesizeTapGestureParams {\n\treturn &SynthesizeTapGestureParams{\n\t\tX: x,\n\t\tY: y,\n\t}\n}\n\n// WithDuration duration between touchdown and touchup events in ms (default:\n// 50).\nfunc (p SynthesizeTapGestureParams) WithDuration(duration int64) *SynthesizeTapGestureParams {\n\tp.Duration = duration\n\treturn &p\n}\n\n// WithTapCount number of times to perform the tap (e.g. 2 for double tap,\n// default: 1).\nfunc (p SynthesizeTapGestureParams) WithTapCount(tapCount int64) *SynthesizeTapGestureParams {\n\tp.TapCount = tapCount\n\treturn &p\n}\n\n// WithGestureSourceType which type of input events to be generated (default:\n// 'default', which queries the platform for the preferred input type).\nfunc (p SynthesizeTapGestureParams) WithGestureSourceType(gestureSourceType GestureSourceType) *SynthesizeTapGestureParams {\n\tp.GestureSourceType = gestureSourceType\n\treturn &p\n}\n\n// Do executes Input.synthesizeTapGesture against the provided context.\nfunc (p *SynthesizeTapGestureParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSynthesizeTapGesture, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandDispatchDragEvent          = \"Input.dispatchDragEvent\"\n\tCommandDispatchKeyEvent           = \"Input.dispatchKeyEvent\"\n\tCommandInsertText                 = \"Input.insertText\"\n\tCommandImeSetComposition          = \"Input.imeSetComposition\"\n\tCommandDispatchMouseEvent         = \"Input.dispatchMouseEvent\"\n\tCommandDispatchTouchEvent         = \"Input.dispatchTouchEvent\"\n\tCommandCancelDragging             = \"Input.cancelDragging\"\n\tCommandEmulateTouchFromMouseEvent = \"Input.emulateTouchFromMouseEvent\"\n\tCommandSetIgnoreInputEvents       = \"Input.setIgnoreInputEvents\"\n\tCommandSetInterceptDrags          = \"Input.setInterceptDrags\"\n\tCommandSynthesizePinchGesture     = \"Input.synthesizePinchGesture\"\n\tCommandSynthesizeScrollGesture    = \"Input.synthesizeScrollGesture\"\n\tCommandSynthesizeTapGesture       = \"Input.synthesizeTapGesture\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/input/types.go",
    "content": "package input\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// TouchPoint [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#type-TouchPoint\ntype TouchPoint struct {\n\tX                  float64 `json:\"x\"`                                     // X coordinate of the event relative to the main frame's viewport in CSS pixels.\n\tY                  float64 `json:\"y\"`                                     // Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to the top of the viewport and Y increases as it proceeds towards the bottom of the viewport.\n\tRadiusX            float64 `json:\"radiusX,omitempty,omitzero\"`            // X radius of the touch area (default: 1.0).\n\tRadiusY            float64 `json:\"radiusY,omitempty,omitzero\"`            // Y radius of the touch area (default: 1.0).\n\tRotationAngle      float64 `json:\"rotationAngle,omitempty,omitzero\"`      // Rotation angle (default: 0.0).\n\tForce              float64 `json:\"force,omitempty,omitzero\"`              // Force (default: 1.0).\n\tTangentialPressure float64 `json:\"tangentialPressure,omitempty,omitzero\"` // The normalized tangential pressure, which has a range of [-1,1] (default: 0).\n\tTiltX              float64 `json:\"tiltX,omitempty,omitzero\"`              // The plane angle between the Y-Z plane and the plane containing both the stylus axis and the Y axis, in degrees of the range [-90,90], a positive tiltX is to the right (default: 0)\n\tTiltY              float64 `json:\"tiltY,omitempty,omitzero\"`              // The plane angle between the X-Z plane and the plane containing both the stylus axis and the X axis, in degrees of the range [-90,90], a positive tiltY is towards the user (default: 0).\n\tTwist              int64   `json:\"twist,omitempty,omitzero\"`              // The clockwise rotation of a pen stylus around its own major axis, in degrees in the range [0,359] (default: 0).\n\tID                 float64 `json:\"id,omitempty,omitzero\"`                 // Identifier used to track touch sources between events, must be unique within an event.\n}\n\n// GestureSourceType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#type-GestureSourceType\ntype GestureSourceType string\n\n// String returns the GestureSourceType as string value.\nfunc (t GestureSourceType) String() string {\n\treturn string(t)\n}\n\n// GestureSourceType values.\nconst (\n\tGestureDefault GestureSourceType = \"default\"\n\tGestureTouch   GestureSourceType = \"touch\"\n\tGestureMouse   GestureSourceType = \"mouse\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *GestureSourceType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch GestureSourceType(s) {\n\tcase GestureDefault:\n\t\t*t = GestureDefault\n\tcase GestureTouch:\n\t\t*t = GestureTouch\n\tcase GestureMouse:\n\t\t*t = GestureMouse\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown GestureSourceType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// MouseButton [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#type-MouseButton\ntype MouseButton string\n\n// String returns the MouseButton as string value.\nfunc (t MouseButton) String() string {\n\treturn string(t)\n}\n\n// MouseButton values.\nconst (\n\tNone    MouseButton = \"none\"\n\tLeft    MouseButton = \"left\"\n\tMiddle  MouseButton = \"middle\"\n\tRight   MouseButton = \"right\"\n\tBack    MouseButton = \"back\"\n\tForward MouseButton = \"forward\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MouseButton) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch MouseButton(s) {\n\tcase None:\n\t\t*t = None\n\tcase Left:\n\t\t*t = Left\n\tcase Middle:\n\t\t*t = Middle\n\tcase Right:\n\t\t*t = Right\n\tcase Back:\n\t\t*t = Back\n\tcase Forward:\n\t\t*t = Forward\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MouseButton value: %v\", s)\n\t}\n\treturn nil\n}\n\n// TimeSinceEpoch UTC time in seconds, counted from January 1, 1970.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#type-TimeSinceEpoch\ntype TimeSinceEpoch time.Time\n\n// Time returns the TimeSinceEpoch as time.Time value.\nfunc (t TimeSinceEpoch) Time() time.Time {\n\treturn time.Time(t)\n}\n\n// MarshalJSON satisfies [json.Marshaler].\nfunc (t TimeSinceEpoch) MarshalJSON() ([]byte, error) {\n\tv := float64(time.Time(t).UnixNano() / int64(time.Second))\n\treturn strconv.AppendFloat(make([]byte, 0, 20), v, 'f', -1, 64), nil\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TimeSinceEpoch) UnmarshalJSON(buf []byte) error {\n\tf, err := strconv.ParseFloat(string(buf), 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*t = TimeSinceEpoch(time.Unix(0, int64(f*float64(time.Second))))\n\treturn nil\n}\n\n// DragDataItem [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#type-DragDataItem\ntype DragDataItem struct {\n\tMimeType string `json:\"mimeType\"`                   // Mime type of the dragged data.\n\tData     string `json:\"data\"`                       // Depending of the value of mimeType, it contains the dragged link, text, HTML markup or any other data.\n\tTitle    string `json:\"title,omitempty,omitzero\"`   // Title associated with a link. Only valid when mimeType == \"text/uri-list\".\n\tBaseURL  string `json:\"baseURL,omitempty,omitzero\"` // Stores the base URL for the contained markup. Only valid when mimeType == \"text/html\".\n}\n\n// DragData [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#type-DragData\ntype DragData struct {\n\tItems              []*DragDataItem `json:\"items\"`\n\tFiles              []string        `json:\"files,omitempty,omitzero\"` // List of filenames that should be included when dropping\n\tDragOperationsMask int64           `json:\"dragOperationsMask\"`       // Bit field representing allowed drag operations. Copy = 1, Link = 2, Move = 16\n}\n\n// Modifier input key modifier type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchKeyEvent\ntype Modifier int64\n\n// Int64 returns the Modifier as int64 value.\nfunc (t Modifier) Int64() int64 {\n\treturn int64(t)\n}\n\n// Modifier values.\nconst (\n\tModifierNone  Modifier = 0\n\tModifierAlt   Modifier = 1\n\tModifierCtrl  Modifier = 2\n\tModifierMeta  Modifier = 4\n\tModifierShift Modifier = 8\n)\n\n// String satisfies the [fmt.Stringer] interface.\nfunc (t Modifier) String() string {\n\tswitch t {\n\tcase ModifierNone:\n\t\treturn \"None\"\n\tcase ModifierAlt:\n\t\treturn \"Alt\"\n\tcase ModifierCtrl:\n\t\treturn \"Ctrl\"\n\tcase ModifierMeta:\n\t\treturn \"Meta\"\n\tcase ModifierShift:\n\t\treturn \"Shift\"\n\t}\n\treturn fmt.Sprintf(\"Modifier(%d)\", t)\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Modifier) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\tv, err := strconv.ParseInt(s, 10, 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\tswitch Modifier(v) {\n\tcase ModifierNone:\n\t\t*t = ModifierNone\n\tcase ModifierAlt:\n\t\t*t = ModifierAlt\n\tcase ModifierCtrl:\n\t\t*t = ModifierCtrl\n\tcase ModifierMeta:\n\t\t*t = ModifierMeta\n\tcase ModifierShift:\n\t\t*t = ModifierShift\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Modifier value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ModifierCommand is an alias for ModifierMeta.\nconst ModifierCommand Modifier = ModifierMeta\n\n// DispatchDragEventType type of the drag event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchDragEvent\ntype DispatchDragEventType string\n\n// String returns the DispatchDragEventType as string value.\nfunc (t DispatchDragEventType) String() string {\n\treturn string(t)\n}\n\n// DispatchDragEventType values.\nconst (\n\tDragEnter  DispatchDragEventType = \"dragEnter\"\n\tDragOver   DispatchDragEventType = \"dragOver\"\n\tDrop       DispatchDragEventType = \"drop\"\n\tDragCancel DispatchDragEventType = \"dragCancel\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DispatchDragEventType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DispatchDragEventType(s) {\n\tcase DragEnter:\n\t\t*t = DragEnter\n\tcase DragOver:\n\t\t*t = DragOver\n\tcase Drop:\n\t\t*t = Drop\n\tcase DragCancel:\n\t\t*t = DragCancel\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DispatchDragEventType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// KeyType type of the key event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchKeyEvent\ntype KeyType string\n\n// String returns the KeyType as string value.\nfunc (t KeyType) String() string {\n\treturn string(t)\n}\n\n// KeyType values.\nconst (\n\tKeyDown    KeyType = \"keyDown\"\n\tKeyUp      KeyType = \"keyUp\"\n\tKeyRawDown KeyType = \"rawKeyDown\"\n\tKeyChar    KeyType = \"char\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *KeyType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch KeyType(s) {\n\tcase KeyDown:\n\t\t*t = KeyDown\n\tcase KeyUp:\n\t\t*t = KeyUp\n\tcase KeyRawDown:\n\t\t*t = KeyRawDown\n\tcase KeyChar:\n\t\t*t = KeyChar\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown KeyType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// MouseType type of the mouse event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchMouseEvent\ntype MouseType string\n\n// String returns the MouseType as string value.\nfunc (t MouseType) String() string {\n\treturn string(t)\n}\n\n// MouseType values.\nconst (\n\tMousePressed  MouseType = \"mousePressed\"\n\tMouseReleased MouseType = \"mouseReleased\"\n\tMouseMoved    MouseType = \"mouseMoved\"\n\tMouseWheel    MouseType = \"mouseWheel\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MouseType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch MouseType(s) {\n\tcase MousePressed:\n\t\t*t = MousePressed\n\tcase MouseReleased:\n\t\t*t = MouseReleased\n\tcase MouseMoved:\n\t\t*t = MouseMoved\n\tcase MouseWheel:\n\t\t*t = MouseWheel\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MouseType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DispatchMouseEventPointerType pointer type (default: \"mouse\").\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchMouseEvent\ntype DispatchMouseEventPointerType string\n\n// String returns the DispatchMouseEventPointerType as string value.\nfunc (t DispatchMouseEventPointerType) String() string {\n\treturn string(t)\n}\n\n// DispatchMouseEventPointerType values.\nconst (\n\tMouse DispatchMouseEventPointerType = \"mouse\"\n\tPen   DispatchMouseEventPointerType = \"pen\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DispatchMouseEventPointerType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DispatchMouseEventPointerType(s) {\n\tcase Mouse:\n\t\t*t = Mouse\n\tcase Pen:\n\t\t*t = Pen\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DispatchMouseEventPointerType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// TouchType type of the touch event. TouchEnd and TouchCancel must not\n// contain any touch points, while TouchStart and TouchMove must contains at\n// least one.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Input#method-dispatchTouchEvent\ntype TouchType string\n\n// String returns the TouchType as string value.\nfunc (t TouchType) String() string {\n\treturn string(t)\n}\n\n// TouchType values.\nconst (\n\tTouchStart  TouchType = \"touchStart\"\n\tTouchEnd    TouchType = \"touchEnd\"\n\tTouchMove   TouchType = \"touchMove\"\n\tTouchCancel TouchType = \"touchCancel\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TouchType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch TouchType(s) {\n\tcase TouchStart:\n\t\t*t = TouchStart\n\tcase TouchEnd:\n\t\t*t = TouchEnd\n\tcase TouchMove:\n\t\t*t = TouchMove\n\tcase TouchCancel:\n\t\t*t = TouchCancel\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown TouchType value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/inspector/events.go",
    "content": "package inspector\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventDetached fired when remote debugging connection is about to be\n// terminated. Contains detach reason.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Inspector#event-detached\ntype EventDetached struct {\n\tReason DetachReason `json:\"reason\"` // The reason why connection has been terminated.\n}\n\n// EventTargetCrashed fired when debugging target has crashed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Inspector#event-targetCrashed\ntype EventTargetCrashed struct{}\n\n// EventTargetReloadedAfterCrash fired when debugging target has reloaded\n// after crash.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Inspector#event-targetReloadedAfterCrash\ntype EventTargetReloadedAfterCrash struct{}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/inspector/inspector.go",
    "content": "// Package inspector provides the Chrome DevTools Protocol\n// commands, types, and events for the Inspector domain.\n//\n// Generated by the cdproto-gen command.\npackage inspector\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// DisableParams disables inspector domain notifications.\ntype DisableParams struct{}\n\n// Disable disables inspector domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Inspector#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Inspector.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables inspector domain notifications.\ntype EnableParams struct{}\n\n// Enable enables inspector domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Inspector#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Inspector.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// Command names.\nconst (\n\tCommandDisable = \"Inspector.disable\"\n\tCommandEnable  = \"Inspector.enable\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/inspector/types.go",
    "content": "package inspector\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// DetachReason detach reason.\n//\n// See: ( -- none -- )\ntype DetachReason string\n\n// String returns the DetachReason as string value.\nfunc (t DetachReason) String() string {\n\treturn string(t)\n}\n\n// DetachReason values.\nconst (\n\tDetachReasonTargetClosed         DetachReason = \"target_closed\"\n\tDetachReasonCanceledByUser       DetachReason = \"canceled_by_user\"\n\tDetachReasonReplacedWithDevtools DetachReason = \"replaced_with_devtools\"\n\tDetachReasonRenderProcessGone    DetachReason = \"Render process gone.\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DetachReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DetachReason(s) {\n\tcase DetachReasonTargetClosed:\n\t\t*t = DetachReasonTargetClosed\n\tcase DetachReasonCanceledByUser:\n\t\t*t = DetachReasonCanceledByUser\n\tcase DetachReasonReplacedWithDevtools:\n\t\t*t = DetachReasonReplacedWithDevtools\n\tcase DetachReasonRenderProcessGone:\n\t\t*t = DetachReasonRenderProcessGone\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DetachReason value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/io/io.go",
    "content": "// Package io provides the Chrome DevTools Protocol\n// commands, types, and events for the IO domain.\n//\n// Input/Output operations for streams produced by DevTools.\n//\n// Generated by the cdproto-gen command.\npackage io\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// CloseParams close the stream, discard any temporary backing storage.\ntype CloseParams struct {\n\tHandle StreamHandle `json:\"handle\"` // Handle of the stream to close.\n}\n\n// Close close the stream, discard any temporary backing storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IO#method-close\n//\n// parameters:\n//\n//\thandle - Handle of the stream to close.\nfunc Close(handle StreamHandle) *CloseParams {\n\treturn &CloseParams{\n\t\tHandle: handle,\n\t}\n}\n\n// Do executes IO.close against the provided context.\nfunc (p *CloseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClose, p, nil)\n}\n\n// ReadParams read a chunk of the stream.\ntype ReadParams struct {\n\tHandle StreamHandle `json:\"handle\"`                    // Handle of the stream to read.\n\tOffset int64        `json:\"offset,omitempty,omitzero\"` // Seek to the specified offset before reading (if not specified, proceed with offset following the last read). Some types of streams may only support sequential reads.\n\tSize   int64        `json:\"size,omitempty,omitzero\"`   // Maximum number of bytes to read (left upon the agent discretion if not specified).\n}\n\n// Read read a chunk of the stream.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IO#method-read\n//\n// parameters:\n//\n//\thandle - Handle of the stream to read.\nfunc Read(handle StreamHandle) *ReadParams {\n\treturn &ReadParams{\n\t\tHandle: handle,\n\t}\n}\n\n// WithOffset seek to the specified offset before reading (if not specified,\n// proceed with offset following the last read). Some types of streams may only\n// support sequential reads.\nfunc (p ReadParams) WithOffset(offset int64) *ReadParams {\n\tp.Offset = offset\n\treturn &p\n}\n\n// WithSize maximum number of bytes to read (left upon the agent discretion\n// if not specified).\nfunc (p ReadParams) WithSize(size int64) *ReadParams {\n\tp.Size = size\n\treturn &p\n}\n\n// ReadReturns return values.\ntype ReadReturns struct {\n\tBase64encoded bool   `json:\"base64Encoded\"`           // Set if the data is base64-encoded\n\tData          string `json:\"data,omitempty,omitzero\"` // Data that were read.\n\tEOF           bool   `json:\"eof\"`                     // Set if the end-of-file condition occurred while reading.\n}\n\n// Do executes IO.read against the provided context.\n//\n// returns:\n//\n//\tdata - Data that were read.\n//\teof - Set if the end-of-file condition occurred while reading.\nfunc (p *ReadParams) Do(ctx context.Context) (data string, eof bool, err error) {\n\t// execute\n\tvar res ReadReturns\n\terr = cdp.Execute(ctx, CommandRead, p, &res)\n\tif err != nil {\n\t\treturn \"\", false, err\n\t}\n\n\treturn res.Data, res.EOF, nil\n}\n\n// ResolveBlobParams return UUID of Blob object specified by a remote object\n// id.\ntype ResolveBlobParams struct {\n\tObjectID runtime.RemoteObjectID `json:\"objectId\"` // Object id of a Blob object wrapper.\n}\n\n// ResolveBlob return UUID of Blob object specified by a remote object id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IO#method-resolveBlob\n//\n// parameters:\n//\n//\tobjectID - Object id of a Blob object wrapper.\nfunc ResolveBlob(objectID runtime.RemoteObjectID) *ResolveBlobParams {\n\treturn &ResolveBlobParams{\n\t\tObjectID: objectID,\n\t}\n}\n\n// ResolveBlobReturns return values.\ntype ResolveBlobReturns struct {\n\tUUID string `json:\"uuid,omitempty,omitzero\"` // UUID of the specified Blob.\n}\n\n// Do executes IO.resolveBlob against the provided context.\n//\n// returns:\n//\n//\tuuid - UUID of the specified Blob.\nfunc (p *ResolveBlobParams) Do(ctx context.Context) (uuid string, err error) {\n\t// execute\n\tvar res ResolveBlobReturns\n\terr = cdp.Execute(ctx, CommandResolveBlob, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.UUID, nil\n}\n\n// Command names.\nconst (\n\tCommandClose       = \"IO.close\"\n\tCommandRead        = \"IO.read\"\n\tCommandResolveBlob = \"IO.resolveBlob\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/io/types.go",
    "content": "package io\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// StreamHandle this is either obtained from another method or specified as\n// blob:<uuid> where <uuid> is an UUID of a Blob.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/IO#type-StreamHandle\ntype StreamHandle string\n\n// String returns the StreamHandle as string value.\nfunc (t StreamHandle) String() string {\n\treturn string(t)\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/layertree/events.go",
    "content": "package layertree\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/dom\"\n)\n\n// EventLayerPainted [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#event-layerPainted\ntype EventLayerPainted struct {\n\tLayerID LayerID   `json:\"layerId\"` // The id of the painted layer.\n\tClip    *dom.Rect `json:\"clip\"`    // Clip rectangle.\n}\n\n// EventLayerTreeDidChange [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#event-layerTreeDidChange\ntype EventLayerTreeDidChange struct {\n\tLayers []*Layer `json:\"layers,omitempty,omitzero\"` // Layer tree, absent if not in the compositing mode.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/layertree/layertree.go",
    "content": "// Package layertree provides the Chrome DevTools Protocol\n// commands, types, and events for the LayerTree domain.\n//\n// Generated by the cdproto-gen command.\npackage layertree\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// CompositingReasonsParams provides the reasons why the given layer was\n// composited.\ntype CompositingReasonsParams struct {\n\tLayerID LayerID `json:\"layerId\"` // The id of the layer for which we want to get the reasons it was composited.\n}\n\n// CompositingReasons provides the reasons why the given layer was\n// composited.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-compositingReasons\n//\n// parameters:\n//\n//\tlayerID - The id of the layer for which we want to get the reasons it was composited.\nfunc CompositingReasons(layerID LayerID) *CompositingReasonsParams {\n\treturn &CompositingReasonsParams{\n\t\tLayerID: layerID,\n\t}\n}\n\n// CompositingReasonsReturns return values.\ntype CompositingReasonsReturns struct {\n\tCompositingReasons   []string `json:\"compositingReasons,omitempty,omitzero\"`   // A list of strings specifying reasons for the given layer to become composited.\n\tCompositingReasonIDs []string `json:\"compositingReasonIds,omitempty,omitzero\"` // A list of strings specifying reason IDs for the given layer to become composited.\n}\n\n// Do executes LayerTree.compositingReasons against the provided context.\n//\n// returns:\n//\n//\tcompositingReasons - A list of strings specifying reasons for the given layer to become composited.\n//\tcompositingReasonIDs - A list of strings specifying reason IDs for the given layer to become composited.\nfunc (p *CompositingReasonsParams) Do(ctx context.Context) (compositingReasons []string, compositingReasonIDs []string, err error) {\n\t// execute\n\tvar res CompositingReasonsReturns\n\terr = cdp.Execute(ctx, CommandCompositingReasons, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.CompositingReasons, res.CompositingReasonIDs, nil\n}\n\n// DisableParams disables compositing tree inspection.\ntype DisableParams struct{}\n\n// Disable disables compositing tree inspection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes LayerTree.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables compositing tree inspection.\ntype EnableParams struct{}\n\n// Enable enables compositing tree inspection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes LayerTree.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// LoadSnapshotParams returns the snapshot identifier.\ntype LoadSnapshotParams struct {\n\tTiles []*PictureTile `json:\"tiles\"` // An array of tiles composing the snapshot.\n}\n\n// LoadSnapshot returns the snapshot identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-loadSnapshot\n//\n// parameters:\n//\n//\ttiles - An array of tiles composing the snapshot.\nfunc LoadSnapshot(tiles []*PictureTile) *LoadSnapshotParams {\n\treturn &LoadSnapshotParams{\n\t\tTiles: tiles,\n\t}\n}\n\n// LoadSnapshotReturns return values.\ntype LoadSnapshotReturns struct {\n\tSnapshotID SnapshotID `json:\"snapshotId,omitempty,omitzero\"` // The id of the snapshot.\n}\n\n// Do executes LayerTree.loadSnapshot against the provided context.\n//\n// returns:\n//\n//\tsnapshotID - The id of the snapshot.\nfunc (p *LoadSnapshotParams) Do(ctx context.Context) (snapshotID SnapshotID, err error) {\n\t// execute\n\tvar res LoadSnapshotReturns\n\terr = cdp.Execute(ctx, CommandLoadSnapshot, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.SnapshotID, nil\n}\n\n// MakeSnapshotParams returns the layer snapshot identifier.\ntype MakeSnapshotParams struct {\n\tLayerID LayerID `json:\"layerId\"` // The id of the layer.\n}\n\n// MakeSnapshot returns the layer snapshot identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-makeSnapshot\n//\n// parameters:\n//\n//\tlayerID - The id of the layer.\nfunc MakeSnapshot(layerID LayerID) *MakeSnapshotParams {\n\treturn &MakeSnapshotParams{\n\t\tLayerID: layerID,\n\t}\n}\n\n// MakeSnapshotReturns return values.\ntype MakeSnapshotReturns struct {\n\tSnapshotID SnapshotID `json:\"snapshotId,omitempty,omitzero\"` // The id of the layer snapshot.\n}\n\n// Do executes LayerTree.makeSnapshot against the provided context.\n//\n// returns:\n//\n//\tsnapshotID - The id of the layer snapshot.\nfunc (p *MakeSnapshotParams) Do(ctx context.Context) (snapshotID SnapshotID, err error) {\n\t// execute\n\tvar res MakeSnapshotReturns\n\terr = cdp.Execute(ctx, CommandMakeSnapshot, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.SnapshotID, nil\n}\n\n// ProfileSnapshotParams [no description].\ntype ProfileSnapshotParams struct {\n\tSnapshotID     SnapshotID `json:\"snapshotId\"`                        // The id of the layer snapshot.\n\tMinRepeatCount int64      `json:\"minRepeatCount,omitempty,omitzero\"` // The maximum number of times to replay the snapshot (1, if not specified).\n\tMinDuration    float64    `json:\"minDuration,omitempty,omitzero\"`    // The minimum duration (in seconds) to replay the snapshot.\n\tClipRect       *dom.Rect  `json:\"clipRect,omitempty,omitzero\"`       // The clip rectangle to apply when replaying the snapshot.\n}\n\n// ProfileSnapshot [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-profileSnapshot\n//\n// parameters:\n//\n//\tsnapshotID - The id of the layer snapshot.\nfunc ProfileSnapshot(snapshotID SnapshotID) *ProfileSnapshotParams {\n\treturn &ProfileSnapshotParams{\n\t\tSnapshotID: snapshotID,\n\t}\n}\n\n// WithMinRepeatCount the maximum number of times to replay the snapshot (1,\n// if not specified).\nfunc (p ProfileSnapshotParams) WithMinRepeatCount(minRepeatCount int64) *ProfileSnapshotParams {\n\tp.MinRepeatCount = minRepeatCount\n\treturn &p\n}\n\n// WithMinDuration the minimum duration (in seconds) to replay the snapshot.\nfunc (p ProfileSnapshotParams) WithMinDuration(minDuration float64) *ProfileSnapshotParams {\n\tp.MinDuration = minDuration\n\treturn &p\n}\n\n// WithClipRect the clip rectangle to apply when replaying the snapshot.\nfunc (p ProfileSnapshotParams) WithClipRect(clipRect *dom.Rect) *ProfileSnapshotParams {\n\tp.ClipRect = clipRect\n\treturn &p\n}\n\n// ProfileSnapshotReturns return values.\ntype ProfileSnapshotReturns struct {\n\tTimings []PaintProfile `json:\"timings,omitempty,omitzero\"` // The array of paint profiles, one per run.\n}\n\n// Do executes LayerTree.profileSnapshot against the provided context.\n//\n// returns:\n//\n//\ttimings - The array of paint profiles, one per run.\nfunc (p *ProfileSnapshotParams) Do(ctx context.Context) (timings []PaintProfile, err error) {\n\t// execute\n\tvar res ProfileSnapshotReturns\n\terr = cdp.Execute(ctx, CommandProfileSnapshot, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Timings, nil\n}\n\n// ReleaseSnapshotParams releases layer snapshot captured by the back-end.\ntype ReleaseSnapshotParams struct {\n\tSnapshotID SnapshotID `json:\"snapshotId\"` // The id of the layer snapshot.\n}\n\n// ReleaseSnapshot releases layer snapshot captured by the back-end.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-releaseSnapshot\n//\n// parameters:\n//\n//\tsnapshotID - The id of the layer snapshot.\nfunc ReleaseSnapshot(snapshotID SnapshotID) *ReleaseSnapshotParams {\n\treturn &ReleaseSnapshotParams{\n\t\tSnapshotID: snapshotID,\n\t}\n}\n\n// Do executes LayerTree.releaseSnapshot against the provided context.\nfunc (p *ReleaseSnapshotParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandReleaseSnapshot, p, nil)\n}\n\n// ReplaySnapshotParams replays the layer snapshot and returns the resulting\n// bitmap.\ntype ReplaySnapshotParams struct {\n\tSnapshotID SnapshotID `json:\"snapshotId\"`                  // The id of the layer snapshot.\n\tFromStep   int64      `json:\"fromStep,omitempty,omitzero\"` // The first step to replay from (replay from the very start if not specified).\n\tToStep     int64      `json:\"toStep,omitempty,omitzero\"`   // The last step to replay to (replay till the end if not specified).\n\tScale      float64    `json:\"scale,omitempty,omitzero\"`    // The scale to apply while replaying (defaults to 1).\n}\n\n// ReplaySnapshot replays the layer snapshot and returns the resulting\n// bitmap.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-replaySnapshot\n//\n// parameters:\n//\n//\tsnapshotID - The id of the layer snapshot.\nfunc ReplaySnapshot(snapshotID SnapshotID) *ReplaySnapshotParams {\n\treturn &ReplaySnapshotParams{\n\t\tSnapshotID: snapshotID,\n\t}\n}\n\n// WithFromStep the first step to replay from (replay from the very start if\n// not specified).\nfunc (p ReplaySnapshotParams) WithFromStep(fromStep int64) *ReplaySnapshotParams {\n\tp.FromStep = fromStep\n\treturn &p\n}\n\n// WithToStep the last step to replay to (replay till the end if not\n// specified).\nfunc (p ReplaySnapshotParams) WithToStep(toStep int64) *ReplaySnapshotParams {\n\tp.ToStep = toStep\n\treturn &p\n}\n\n// WithScale the scale to apply while replaying (defaults to 1).\nfunc (p ReplaySnapshotParams) WithScale(scale float64) *ReplaySnapshotParams {\n\tp.Scale = scale\n\treturn &p\n}\n\n// ReplaySnapshotReturns return values.\ntype ReplaySnapshotReturns struct {\n\tDataURL string `json:\"dataURL,omitempty,omitzero\"` // A data: URL for resulting image.\n}\n\n// Do executes LayerTree.replaySnapshot against the provided context.\n//\n// returns:\n//\n//\tdataURL - A data: URL for resulting image.\nfunc (p *ReplaySnapshotParams) Do(ctx context.Context) (dataURL string, err error) {\n\t// execute\n\tvar res ReplaySnapshotReturns\n\terr = cdp.Execute(ctx, CommandReplaySnapshot, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.DataURL, nil\n}\n\n// SnapshotCommandLogParams replays the layer snapshot and returns canvas\n// log.\ntype SnapshotCommandLogParams struct {\n\tSnapshotID SnapshotID `json:\"snapshotId\"` // The id of the layer snapshot.\n}\n\n// SnapshotCommandLog replays the layer snapshot and returns canvas log.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#method-snapshotCommandLog\n//\n// parameters:\n//\n//\tsnapshotID - The id of the layer snapshot.\nfunc SnapshotCommandLog(snapshotID SnapshotID) *SnapshotCommandLogParams {\n\treturn &SnapshotCommandLogParams{\n\t\tSnapshotID: snapshotID,\n\t}\n}\n\n// SnapshotCommandLogReturns return values.\ntype SnapshotCommandLogReturns struct {\n\tCommandLog []jsontext.Value `json:\"commandLog,omitempty,omitzero\"` // The array of canvas function calls.\n}\n\n// Do executes LayerTree.snapshotCommandLog against the provided context.\n//\n// returns:\n//\n//\tcommandLog - The array of canvas function calls.\nfunc (p *SnapshotCommandLogParams) Do(ctx context.Context) (commandLog []jsontext.Value, err error) {\n\t// execute\n\tvar res SnapshotCommandLogReturns\n\terr = cdp.Execute(ctx, CommandSnapshotCommandLog, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.CommandLog, nil\n}\n\n// Command names.\nconst (\n\tCommandCompositingReasons = \"LayerTree.compositingReasons\"\n\tCommandDisable            = \"LayerTree.disable\"\n\tCommandEnable             = \"LayerTree.enable\"\n\tCommandLoadSnapshot       = \"LayerTree.loadSnapshot\"\n\tCommandMakeSnapshot       = \"LayerTree.makeSnapshot\"\n\tCommandProfileSnapshot    = \"LayerTree.profileSnapshot\"\n\tCommandReleaseSnapshot    = \"LayerTree.releaseSnapshot\"\n\tCommandReplaySnapshot     = \"LayerTree.replaySnapshot\"\n\tCommandSnapshotCommandLog = \"LayerTree.snapshotCommandLog\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/layertree/types.go",
    "content": "package layertree\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n)\n\n// LayerID unique Layer identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-LayerId\ntype LayerID string\n\n// String returns the LayerID as string value.\nfunc (t LayerID) String() string {\n\treturn string(t)\n}\n\n// SnapshotID unique snapshot identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-SnapshotId\ntype SnapshotID string\n\n// String returns the SnapshotID as string value.\nfunc (t SnapshotID) String() string {\n\treturn string(t)\n}\n\n// ScrollRect rectangle where scrolling happens on the main thread.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-ScrollRect\ntype ScrollRect struct {\n\tRect *dom.Rect      `json:\"rect\"` // Rectangle itself.\n\tType ScrollRectType `json:\"type\"` // Reason for rectangle to force scrolling on the main thread\n}\n\n// StickyPositionConstraint sticky position constraints.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-StickyPositionConstraint\ntype StickyPositionConstraint struct {\n\tStickyBoxRect                       *dom.Rect `json:\"stickyBoxRect\"`                                          // Layout rectangle of the sticky element before being shifted\n\tContainingBlockRect                 *dom.Rect `json:\"containingBlockRect\"`                                    // Layout rectangle of the containing block of the sticky element\n\tNearestLayerShiftingStickyBox       LayerID   `json:\"nearestLayerShiftingStickyBox,omitempty,omitzero\"`       // The nearest sticky layer that shifts the sticky box\n\tNearestLayerShiftingContainingBlock LayerID   `json:\"nearestLayerShiftingContainingBlock,omitempty,omitzero\"` // The nearest sticky layer that shifts the containing block\n}\n\n// PictureTile serialized fragment of layer picture along with its offset\n// within the layer.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-PictureTile\ntype PictureTile struct {\n\tX       float64 `json:\"x\"`       // Offset from owning layer left boundary\n\tY       float64 `json:\"y\"`       // Offset from owning layer top boundary\n\tPicture string  `json:\"picture\"` // Base64-encoded snapshot data.\n}\n\n// Layer information about a compositing layer.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-Layer\ntype Layer struct {\n\tLayerID                  LayerID                   `json:\"layerId\"`                                     // The unique id for this layer.\n\tParentLayerID            LayerID                   `json:\"parentLayerId,omitempty,omitzero\"`            // The id of parent (not present for root).\n\tBackendNodeID            cdp.BackendNodeID         `json:\"backendNodeId,omitempty,omitzero\"`            // The backend id for the node associated with this layer.\n\tOffsetX                  float64                   `json:\"offsetX\"`                                     // Offset from parent layer, X coordinate.\n\tOffsetY                  float64                   `json:\"offsetY\"`                                     // Offset from parent layer, Y coordinate.\n\tWidth                    float64                   `json:\"width\"`                                       // Layer width.\n\tHeight                   float64                   `json:\"height\"`                                      // Layer height.\n\tTransform                []float64                 `json:\"transform,omitempty,omitzero\"`                // Transformation matrix for layer, default is identity matrix\n\tAnchorX                  float64                   `json:\"anchorX,omitempty,omitzero\"`                  // Transform anchor point X, absent if no transform specified\n\tAnchorY                  float64                   `json:\"anchorY,omitempty,omitzero\"`                  // Transform anchor point Y, absent if no transform specified\n\tAnchorZ                  float64                   `json:\"anchorZ,omitempty,omitzero\"`                  // Transform anchor point Z, absent if no transform specified\n\tPaintCount               int64                     `json:\"paintCount\"`                                  // Indicates how many time this layer has painted.\n\tDrawsContent             bool                      `json:\"drawsContent\"`                                // Indicates whether this layer hosts any content, rather than being used for transform/scrolling purposes only.\n\tInvisible                bool                      `json:\"invisible\"`                                   // Set if layer is not visible.\n\tScrollRects              []*ScrollRect             `json:\"scrollRects,omitempty,omitzero\"`              // Rectangles scrolling on main thread only.\n\tStickyPositionConstraint *StickyPositionConstraint `json:\"stickyPositionConstraint,omitempty,omitzero\"` // Sticky position constraint information\n}\n\n// PaintProfile array of timings, one per paint step.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-PaintProfile\ntype PaintProfile []float64\n\n// ScrollRectType reason for rectangle to force scrolling on the main thread.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/LayerTree#type-ScrollRect\ntype ScrollRectType string\n\n// String returns the ScrollRectType as string value.\nfunc (t ScrollRectType) String() string {\n\treturn string(t)\n}\n\n// ScrollRectType values.\nconst (\n\tScrollRectTypeRepaintsOnScroll  ScrollRectType = \"RepaintsOnScroll\"\n\tScrollRectTypeTouchEventHandler ScrollRectType = \"TouchEventHandler\"\n\tScrollRectTypeWheelEventHandler ScrollRectType = \"WheelEventHandler\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ScrollRectType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ScrollRectType(s) {\n\tcase ScrollRectTypeRepaintsOnScroll:\n\t\t*t = ScrollRectTypeRepaintsOnScroll\n\tcase ScrollRectTypeTouchEventHandler:\n\t\t*t = ScrollRectTypeTouchEventHandler\n\tcase ScrollRectTypeWheelEventHandler:\n\t\t*t = ScrollRectTypeWheelEventHandler\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ScrollRectType value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/log/events.go",
    "content": "package log\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventEntryAdded issued when new message was logged.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#event-entryAdded\ntype EventEntryAdded struct {\n\tEntry *Entry `json:\"entry\"` // The entry.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/log/log.go",
    "content": "// Package log provides the Chrome DevTools Protocol\n// commands, types, and events for the Log domain.\n//\n// Provides access to log entries.\n//\n// Generated by the cdproto-gen command.\npackage log\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// ClearParams clears the log.\ntype ClearParams struct{}\n\n// Clear clears the log.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#method-clear\nfunc Clear() *ClearParams {\n\treturn &ClearParams{}\n}\n\n// Do executes Log.clear against the provided context.\nfunc (p *ClearParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClear, nil, nil)\n}\n\n// DisableParams disables log domain, prevents further log entries from being\n// reported to the client.\ntype DisableParams struct{}\n\n// Disable disables log domain, prevents further log entries from being\n// reported to the client.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Log.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables log domain, sends the entries collected so far to the\n// client by means of the entryAdded notification.\ntype EnableParams struct{}\n\n// Enable enables log domain, sends the entries collected so far to the\n// client by means of the entryAdded notification.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Log.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// StartViolationsReportParams start violation reporting.\ntype StartViolationsReportParams struct {\n\tConfig []*ViolationSetting `json:\"config\"` // Configuration for violations.\n}\n\n// StartViolationsReport start violation reporting.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#method-startViolationsReport\n//\n// parameters:\n//\n//\tconfig - Configuration for violations.\nfunc StartViolationsReport(config []*ViolationSetting) *StartViolationsReportParams {\n\treturn &StartViolationsReportParams{\n\t\tConfig: config,\n\t}\n}\n\n// Do executes Log.startViolationsReport against the provided context.\nfunc (p *StartViolationsReportParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartViolationsReport, p, nil)\n}\n\n// StopViolationsReportParams stop violation reporting.\ntype StopViolationsReportParams struct{}\n\n// StopViolationsReport stop violation reporting.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#method-stopViolationsReport\nfunc StopViolationsReport() *StopViolationsReportParams {\n\treturn &StopViolationsReportParams{}\n}\n\n// Do executes Log.stopViolationsReport against the provided context.\nfunc (p *StopViolationsReportParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopViolationsReport, nil, nil)\n}\n\n// Command names.\nconst (\n\tCommandClear                 = \"Log.clear\"\n\tCommandDisable               = \"Log.disable\"\n\tCommandEnable                = \"Log.enable\"\n\tCommandStartViolationsReport = \"Log.startViolationsReport\"\n\tCommandStopViolationsReport  = \"Log.stopViolationsReport\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/log/types.go",
    "content": "package log\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// Entry log entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#type-LogEntry\ntype Entry struct {\n\tSource           Source                  `json:\"source\"` // Log entry source.\n\tLevel            Level                   `json:\"level\"`  // Log entry severity.\n\tText             string                  `json:\"text\"`   // Logged text.\n\tCategory         EntryCategory           `json:\"category,omitempty,omitzero\"`\n\tTimestamp        *runtime.Timestamp      `json:\"timestamp\"`                           // Timestamp when this entry was added.\n\tURL              string                  `json:\"url,omitempty,omitzero\"`              // URL of the resource if known.\n\tLineNumber       int64                   `json:\"lineNumber,omitempty,omitzero\"`       // Line number in the resource.\n\tStackTrace       *runtime.StackTrace     `json:\"stackTrace,omitempty,omitzero\"`       // JavaScript stack trace.\n\tNetworkRequestID network.RequestID       `json:\"networkRequestId,omitempty,omitzero\"` // Identifier of the network request associated with this entry.\n\tWorkerID         string                  `json:\"workerId,omitempty,omitzero\"`         // Identifier of the worker associated with this entry.\n\tArgs             []*runtime.RemoteObject `json:\"args,omitempty,omitzero\"`             // Call arguments.\n}\n\n// ViolationSetting violation configuration setting.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#type-ViolationSetting\ntype ViolationSetting struct {\n\tName      Violation `json:\"name\"`      // Violation type.\n\tThreshold float64   `json:\"threshold\"` // Time threshold to trigger upon.\n}\n\n// Source log entry source.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#type-LogEntry\ntype Source string\n\n// String returns the Source as string value.\nfunc (t Source) String() string {\n\treturn string(t)\n}\n\n// Source values.\nconst (\n\tSourceXML            Source = \"xml\"\n\tSourceJavascript     Source = \"javascript\"\n\tSourceNetwork        Source = \"network\"\n\tSourceStorage        Source = \"storage\"\n\tSourceAppcache       Source = \"appcache\"\n\tSourceRendering      Source = \"rendering\"\n\tSourceSecurity       Source = \"security\"\n\tSourceDeprecation    Source = \"deprecation\"\n\tSourceWorker         Source = \"worker\"\n\tSourceViolation      Source = \"violation\"\n\tSourceIntervention   Source = \"intervention\"\n\tSourceRecommendation Source = \"recommendation\"\n\tSourceOther          Source = \"other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Source) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Source(s) {\n\tcase SourceXML:\n\t\t*t = SourceXML\n\tcase SourceJavascript:\n\t\t*t = SourceJavascript\n\tcase SourceNetwork:\n\t\t*t = SourceNetwork\n\tcase SourceStorage:\n\t\t*t = SourceStorage\n\tcase SourceAppcache:\n\t\t*t = SourceAppcache\n\tcase SourceRendering:\n\t\t*t = SourceRendering\n\tcase SourceSecurity:\n\t\t*t = SourceSecurity\n\tcase SourceDeprecation:\n\t\t*t = SourceDeprecation\n\tcase SourceWorker:\n\t\t*t = SourceWorker\n\tcase SourceViolation:\n\t\t*t = SourceViolation\n\tcase SourceIntervention:\n\t\t*t = SourceIntervention\n\tcase SourceRecommendation:\n\t\t*t = SourceRecommendation\n\tcase SourceOther:\n\t\t*t = SourceOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Source value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Level log entry severity.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#type-LogEntry\ntype Level string\n\n// String returns the Level as string value.\nfunc (t Level) String() string {\n\treturn string(t)\n}\n\n// Level values.\nconst (\n\tLevelVerbose Level = \"verbose\"\n\tLevelInfo    Level = \"info\"\n\tLevelWarning Level = \"warning\"\n\tLevelError   Level = \"error\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Level) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Level(s) {\n\tcase LevelVerbose:\n\t\t*t = LevelVerbose\n\tcase LevelInfo:\n\t\t*t = LevelInfo\n\tcase LevelWarning:\n\t\t*t = LevelWarning\n\tcase LevelError:\n\t\t*t = LevelError\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Level value: %v\", s)\n\t}\n\treturn nil\n}\n\n// EntryCategory [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#type-LogEntry\ntype EntryCategory string\n\n// String returns the EntryCategory as string value.\nfunc (t EntryCategory) String() string {\n\treturn string(t)\n}\n\n// EntryCategory values.\nconst (\n\tEntryCategoryCors EntryCategory = \"cors\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *EntryCategory) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch EntryCategory(s) {\n\tcase EntryCategoryCors:\n\t\t*t = EntryCategoryCors\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown EntryCategory value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Violation violation type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Log#type-ViolationSetting\ntype Violation string\n\n// String returns the Violation as string value.\nfunc (t Violation) String() string {\n\treturn string(t)\n}\n\n// Violation values.\nconst (\n\tViolationLongTask          Violation = \"longTask\"\n\tViolationLongLayout        Violation = \"longLayout\"\n\tViolationBlockedEvent      Violation = \"blockedEvent\"\n\tViolationBlockedParser     Violation = \"blockedParser\"\n\tViolationDiscouragedAPIUse Violation = \"discouragedAPIUse\"\n\tViolationHandler           Violation = \"handler\"\n\tViolationRecurringHandler  Violation = \"recurringHandler\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Violation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Violation(s) {\n\tcase ViolationLongTask:\n\t\t*t = ViolationLongTask\n\tcase ViolationLongLayout:\n\t\t*t = ViolationLongLayout\n\tcase ViolationBlockedEvent:\n\t\t*t = ViolationBlockedEvent\n\tcase ViolationBlockedParser:\n\t\t*t = ViolationBlockedParser\n\tcase ViolationDiscouragedAPIUse:\n\t\t*t = ViolationDiscouragedAPIUse\n\tcase ViolationHandler:\n\t\t*t = ViolationHandler\n\tcase ViolationRecurringHandler:\n\t\t*t = ViolationRecurringHandler\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Violation value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/media/events.go",
    "content": "package media\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventPlayerPropertiesChanged this can be called multiple times, and can be\n// used to set / override / remove player properties. A null propValue indicates\n// removal.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerPropertiesChanged\ntype EventPlayerPropertiesChanged struct {\n\tPlayerID   PlayerID          `json:\"playerId\"`\n\tProperties []*PlayerProperty `json:\"properties\"`\n}\n\n// EventPlayerEventsAdded send events as a list, allowing them to be batched\n// on the browser for less congestion. If batched, events must ALWAYS be in\n// chronological order.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerEventsAdded\ntype EventPlayerEventsAdded struct {\n\tPlayerID PlayerID       `json:\"playerId\"`\n\tEvents   []*PlayerEvent `json:\"events\"`\n}\n\n// EventPlayerMessagesLogged send a list of any messages that need to be\n// delivered.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerMessagesLogged\ntype EventPlayerMessagesLogged struct {\n\tPlayerID PlayerID         `json:\"playerId\"`\n\tMessages []*PlayerMessage `json:\"messages\"`\n}\n\n// EventPlayerErrorsRaised send a list of any errors that need to be\n// delivered.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playerErrorsRaised\ntype EventPlayerErrorsRaised struct {\n\tPlayerID PlayerID       `json:\"playerId\"`\n\tErrors   []*PlayerError `json:\"errors\"`\n}\n\n// EventPlayersCreated called whenever a player is created, or when a new\n// agent joins and receives a list of active players. If an agent is restored,\n// it will receive the full list of player ids and all events again.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#event-playersCreated\ntype EventPlayersCreated struct {\n\tPlayers []PlayerID `json:\"players\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/media/media.go",
    "content": "// Package media provides the Chrome DevTools Protocol\n// commands, types, and events for the Media domain.\n//\n// This domain allows detailed inspection of media elements.\n//\n// Generated by the cdproto-gen command.\npackage media\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams enables the Media domain.\ntype EnableParams struct{}\n\n// Enable enables the Media domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Media.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// DisableParams disables the Media domain.\ntype DisableParams struct{}\n\n// Disable disables the Media domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Media.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable  = \"Media.enable\"\n\tCommandDisable = \"Media.disable\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/media/types.go",
    "content": "package media\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// PlayerID players will get an ID that is unique within the agent context.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerId\ntype PlayerID string\n\n// String returns the PlayerID as string value.\nfunc (t PlayerID) String() string {\n\treturn string(t)\n}\n\n// Timestamp [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-Timestamp\ntype Timestamp float64\n\n// Float64 returns the Timestamp as float64 value.\nfunc (t Timestamp) Float64() float64 {\n\treturn float64(t)\n}\n\n// PlayerMessage have one type per entry in MediaLogRecord::Type Corresponds\n// to kMessage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerMessage\ntype PlayerMessage struct {\n\tLevel   PlayerMessageLevel `json:\"level\"` // Keep in sync with MediaLogMessageLevel We are currently keeping the message level 'error' separate from the PlayerError type because right now they represent different things, this one being a DVLOG(ERROR) style log message that gets printed based on what log level is selected in the UI, and the other is a representation of a media::PipelineStatus object. Soon however we're going to be moving away from using PipelineStatus for errors and introducing a new error type which should hopefully let us integrate the error log level into the PlayerError type.\n\tMessage string             `json:\"message\"`\n}\n\n// PlayerProperty corresponds to kMediaPropertyChange.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerProperty\ntype PlayerProperty struct {\n\tName  string `json:\"name\"`\n\tValue string `json:\"value\"`\n}\n\n// PlayerEvent corresponds to kMediaEventTriggered.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerEvent\ntype PlayerEvent struct {\n\tTimestamp Timestamp `json:\"timestamp\"`\n\tValue     string    `json:\"value\"`\n}\n\n// PlayerErrorSourceLocation represents logged source line numbers reported\n// in an error. NOTE: file and line are from chromium c++ implementation code,\n// not js.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerErrorSourceLocation\ntype PlayerErrorSourceLocation struct {\n\tFile string `json:\"file\"`\n\tLine int64  `json:\"line\"`\n}\n\n// PlayerError corresponds to kMediaError.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerError\ntype PlayerError struct {\n\tErrorType string                       `json:\"errorType\"`\n\tCode      int64                        `json:\"code\"`  // Code is the numeric enum entry for a specific set of error codes, such as PipelineStatusCodes in media/base/pipeline_status.h\n\tStack     []*PlayerErrorSourceLocation `json:\"stack\"` // A trace of where this error was caused / where it passed through.\n\tCause     []*PlayerError               `json:\"cause\"` // Errors potentially have a root cause error, ie, a DecoderError might be caused by an WindowsError\n\tData      jsontext.Value               `json:\"data\"`\n}\n\n// PlayerMessageLevel keep in sync with MediaLogMessageLevel We are currently\n// keeping the message level 'error' separate from the PlayerError type because\n// right now they represent different things, this one being a DVLOG(ERROR)\n// style log message that gets printed based on what log level is selected in\n// the UI, and the other is a representation of a media::PipelineStatus object.\n// Soon however we're going to be moving away from using PipelineStatus for\n// errors and introducing a new error type which should hopefully let us\n// integrate the error log level into the PlayerError type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Media#type-PlayerMessage\ntype PlayerMessageLevel string\n\n// String returns the PlayerMessageLevel as string value.\nfunc (t PlayerMessageLevel) String() string {\n\treturn string(t)\n}\n\n// PlayerMessageLevel values.\nconst (\n\tPlayerMessageLevelError   PlayerMessageLevel = \"error\"\n\tPlayerMessageLevelWarning PlayerMessageLevel = \"warning\"\n\tPlayerMessageLevelInfo    PlayerMessageLevel = \"info\"\n\tPlayerMessageLevelDebug   PlayerMessageLevel = \"debug\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PlayerMessageLevel) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PlayerMessageLevel(s) {\n\tcase PlayerMessageLevelError:\n\t\t*t = PlayerMessageLevelError\n\tcase PlayerMessageLevelWarning:\n\t\t*t = PlayerMessageLevelWarning\n\tcase PlayerMessageLevelInfo:\n\t\t*t = PlayerMessageLevelInfo\n\tcase PlayerMessageLevelDebug:\n\t\t*t = PlayerMessageLevelDebug\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PlayerMessageLevel value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/memory/memory.go",
    "content": "// Package memory provides the Chrome DevTools Protocol\n// commands, types, and events for the Memory domain.\n//\n// Generated by the cdproto-gen command.\npackage memory\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// GetDOMCountersParams retruns current DOM object counters.\ntype GetDOMCountersParams struct{}\n\n// GetDOMCounters retruns current DOM object counters.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-getDOMCounters\nfunc GetDOMCounters() *GetDOMCountersParams {\n\treturn &GetDOMCountersParams{}\n}\n\n// GetDOMCountersReturns return values.\ntype GetDOMCountersReturns struct {\n\tDocuments        int64 `json:\"documents,omitempty,omitzero\"`\n\tNodes            int64 `json:\"nodes,omitempty,omitzero\"`\n\tJsEventListeners int64 `json:\"jsEventListeners,omitempty,omitzero\"`\n}\n\n// Do executes Memory.getDOMCounters against the provided context.\n//\n// returns:\n//\n//\tdocuments\n//\tnodes\n//\tjsEventListeners\nfunc (p *GetDOMCountersParams) Do(ctx context.Context) (documents int64, nodes int64, jsEventListeners int64, err error) {\n\t// execute\n\tvar res GetDOMCountersReturns\n\terr = cdp.Execute(ctx, CommandGetDOMCounters, nil, &res)\n\tif err != nil {\n\t\treturn 0, 0, 0, err\n\t}\n\n\treturn res.Documents, res.Nodes, res.JsEventListeners, nil\n}\n\n// GetDOMCountersForLeakDetectionParams retruns DOM object counters after\n// preparing renderer for leak detection.\ntype GetDOMCountersForLeakDetectionParams struct{}\n\n// GetDOMCountersForLeakDetection retruns DOM object counters after preparing\n// renderer for leak detection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-getDOMCountersForLeakDetection\nfunc GetDOMCountersForLeakDetection() *GetDOMCountersForLeakDetectionParams {\n\treturn &GetDOMCountersForLeakDetectionParams{}\n}\n\n// GetDOMCountersForLeakDetectionReturns return values.\ntype GetDOMCountersForLeakDetectionReturns struct {\n\tCounters []*DOMCounter `json:\"counters,omitempty,omitzero\"` // DOM object counters.\n}\n\n// Do executes Memory.getDOMCountersForLeakDetection against the provided context.\n//\n// returns:\n//\n//\tcounters - DOM object counters.\nfunc (p *GetDOMCountersForLeakDetectionParams) Do(ctx context.Context) (counters []*DOMCounter, err error) {\n\t// execute\n\tvar res GetDOMCountersForLeakDetectionReturns\n\terr = cdp.Execute(ctx, CommandGetDOMCountersForLeakDetection, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Counters, nil\n}\n\n// PrepareForLeakDetectionParams prepares for leak detection by terminating\n// workers, stopping spellcheckers, dropping non-essential internal caches,\n// running garbage collections, etc.\ntype PrepareForLeakDetectionParams struct{}\n\n// PrepareForLeakDetection prepares for leak detection by terminating\n// workers, stopping spellcheckers, dropping non-essential internal caches,\n// running garbage collections, etc.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-prepareForLeakDetection\nfunc PrepareForLeakDetection() *PrepareForLeakDetectionParams {\n\treturn &PrepareForLeakDetectionParams{}\n}\n\n// Do executes Memory.prepareForLeakDetection against the provided context.\nfunc (p *PrepareForLeakDetectionParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandPrepareForLeakDetection, nil, nil)\n}\n\n// ForciblyPurgeJavaScriptMemoryParams simulate OomIntervention by purging V8\n// memory.\ntype ForciblyPurgeJavaScriptMemoryParams struct{}\n\n// ForciblyPurgeJavaScriptMemory simulate OomIntervention by purging V8\n// memory.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-forciblyPurgeJavaScriptMemory\nfunc ForciblyPurgeJavaScriptMemory() *ForciblyPurgeJavaScriptMemoryParams {\n\treturn &ForciblyPurgeJavaScriptMemoryParams{}\n}\n\n// Do executes Memory.forciblyPurgeJavaScriptMemory against the provided context.\nfunc (p *ForciblyPurgeJavaScriptMemoryParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandForciblyPurgeJavaScriptMemory, nil, nil)\n}\n\n// SetPressureNotificationsSuppressedParams enable/disable suppressing memory\n// pressure notifications in all processes.\ntype SetPressureNotificationsSuppressedParams struct {\n\tSuppressed bool `json:\"suppressed\"` // If true, memory pressure notifications will be suppressed.\n}\n\n// SetPressureNotificationsSuppressed enable/disable suppressing memory\n// pressure notifications in all processes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-setPressureNotificationsSuppressed\n//\n// parameters:\n//\n//\tsuppressed - If true, memory pressure notifications will be suppressed.\nfunc SetPressureNotificationsSuppressed(suppressed bool) *SetPressureNotificationsSuppressedParams {\n\treturn &SetPressureNotificationsSuppressedParams{\n\t\tSuppressed: suppressed,\n\t}\n}\n\n// Do executes Memory.setPressureNotificationsSuppressed against the provided context.\nfunc (p *SetPressureNotificationsSuppressedParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPressureNotificationsSuppressed, p, nil)\n}\n\n// SimulatePressureNotificationParams simulate a memory pressure notification\n// in all processes.\ntype SimulatePressureNotificationParams struct {\n\tLevel PressureLevel `json:\"level\"` // Memory pressure level of the notification.\n}\n\n// SimulatePressureNotification simulate a memory pressure notification in\n// all processes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-simulatePressureNotification\n//\n// parameters:\n//\n//\tlevel - Memory pressure level of the notification.\nfunc SimulatePressureNotification(level PressureLevel) *SimulatePressureNotificationParams {\n\treturn &SimulatePressureNotificationParams{\n\t\tLevel: level,\n\t}\n}\n\n// Do executes Memory.simulatePressureNotification against the provided context.\nfunc (p *SimulatePressureNotificationParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSimulatePressureNotification, p, nil)\n}\n\n// StartSamplingParams start collecting native memory profile.\ntype StartSamplingParams struct {\n\tSamplingInterval   int64 `json:\"samplingInterval,omitempty,omitzero\"` // Average number of bytes between samples.\n\tSuppressRandomness bool  `json:\"suppressRandomness\"`                  // Do not randomize intervals between samples.\n}\n\n// StartSampling start collecting native memory profile.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-startSampling\n//\n// parameters:\nfunc StartSampling() *StartSamplingParams {\n\treturn &StartSamplingParams{\n\t\tSuppressRandomness: false,\n\t}\n}\n\n// WithSamplingInterval average number of bytes between samples.\nfunc (p StartSamplingParams) WithSamplingInterval(samplingInterval int64) *StartSamplingParams {\n\tp.SamplingInterval = samplingInterval\n\treturn &p\n}\n\n// WithSuppressRandomness do not randomize intervals between samples.\nfunc (p StartSamplingParams) WithSuppressRandomness(suppressRandomness bool) *StartSamplingParams {\n\tp.SuppressRandomness = suppressRandomness\n\treturn &p\n}\n\n// Do executes Memory.startSampling against the provided context.\nfunc (p *StartSamplingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartSampling, p, nil)\n}\n\n// StopSamplingParams stop collecting native memory profile.\ntype StopSamplingParams struct{}\n\n// StopSampling stop collecting native memory profile.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-stopSampling\nfunc StopSampling() *StopSamplingParams {\n\treturn &StopSamplingParams{}\n}\n\n// Do executes Memory.stopSampling against the provided context.\nfunc (p *StopSamplingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopSampling, nil, nil)\n}\n\n// GetAllTimeSamplingProfileParams retrieve native memory allocations profile\n// collected since renderer process startup.\ntype GetAllTimeSamplingProfileParams struct{}\n\n// GetAllTimeSamplingProfile retrieve native memory allocations profile\n// collected since renderer process startup.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-getAllTimeSamplingProfile\nfunc GetAllTimeSamplingProfile() *GetAllTimeSamplingProfileParams {\n\treturn &GetAllTimeSamplingProfileParams{}\n}\n\n// GetAllTimeSamplingProfileReturns return values.\ntype GetAllTimeSamplingProfileReturns struct {\n\tProfile *SamplingProfile `json:\"profile,omitempty,omitzero\"`\n}\n\n// Do executes Memory.getAllTimeSamplingProfile against the provided context.\n//\n// returns:\n//\n//\tprofile\nfunc (p *GetAllTimeSamplingProfileParams) Do(ctx context.Context) (profile *SamplingProfile, err error) {\n\t// execute\n\tvar res GetAllTimeSamplingProfileReturns\n\terr = cdp.Execute(ctx, CommandGetAllTimeSamplingProfile, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Profile, nil\n}\n\n// GetBrowserSamplingProfileParams retrieve native memory allocations profile\n// collected since browser process startup.\ntype GetBrowserSamplingProfileParams struct{}\n\n// GetBrowserSamplingProfile retrieve native memory allocations profile\n// collected since browser process startup.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-getBrowserSamplingProfile\nfunc GetBrowserSamplingProfile() *GetBrowserSamplingProfileParams {\n\treturn &GetBrowserSamplingProfileParams{}\n}\n\n// GetBrowserSamplingProfileReturns return values.\ntype GetBrowserSamplingProfileReturns struct {\n\tProfile *SamplingProfile `json:\"profile,omitempty,omitzero\"`\n}\n\n// Do executes Memory.getBrowserSamplingProfile against the provided context.\n//\n// returns:\n//\n//\tprofile\nfunc (p *GetBrowserSamplingProfileParams) Do(ctx context.Context) (profile *SamplingProfile, err error) {\n\t// execute\n\tvar res GetBrowserSamplingProfileReturns\n\terr = cdp.Execute(ctx, CommandGetBrowserSamplingProfile, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Profile, nil\n}\n\n// GetSamplingProfileParams retrieve native memory allocations profile\n// collected since last startSampling call.\ntype GetSamplingProfileParams struct{}\n\n// GetSamplingProfile retrieve native memory allocations profile collected\n// since last startSampling call.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#method-getSamplingProfile\nfunc GetSamplingProfile() *GetSamplingProfileParams {\n\treturn &GetSamplingProfileParams{}\n}\n\n// GetSamplingProfileReturns return values.\ntype GetSamplingProfileReturns struct {\n\tProfile *SamplingProfile `json:\"profile,omitempty,omitzero\"`\n}\n\n// Do executes Memory.getSamplingProfile against the provided context.\n//\n// returns:\n//\n//\tprofile\nfunc (p *GetSamplingProfileParams) Do(ctx context.Context) (profile *SamplingProfile, err error) {\n\t// execute\n\tvar res GetSamplingProfileReturns\n\terr = cdp.Execute(ctx, CommandGetSamplingProfile, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Profile, nil\n}\n\n// Command names.\nconst (\n\tCommandGetDOMCounters                     = \"Memory.getDOMCounters\"\n\tCommandGetDOMCountersForLeakDetection     = \"Memory.getDOMCountersForLeakDetection\"\n\tCommandPrepareForLeakDetection            = \"Memory.prepareForLeakDetection\"\n\tCommandForciblyPurgeJavaScriptMemory      = \"Memory.forciblyPurgeJavaScriptMemory\"\n\tCommandSetPressureNotificationsSuppressed = \"Memory.setPressureNotificationsSuppressed\"\n\tCommandSimulatePressureNotification       = \"Memory.simulatePressureNotification\"\n\tCommandStartSampling                      = \"Memory.startSampling\"\n\tCommandStopSampling                       = \"Memory.stopSampling\"\n\tCommandGetAllTimeSamplingProfile          = \"Memory.getAllTimeSamplingProfile\"\n\tCommandGetBrowserSamplingProfile          = \"Memory.getBrowserSamplingProfile\"\n\tCommandGetSamplingProfile                 = \"Memory.getSamplingProfile\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/memory/types.go",
    "content": "package memory\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// PressureLevel memory pressure level.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-PressureLevel\ntype PressureLevel string\n\n// String returns the PressureLevel as string value.\nfunc (t PressureLevel) String() string {\n\treturn string(t)\n}\n\n// PressureLevel values.\nconst (\n\tPressureLevelModerate PressureLevel = \"moderate\"\n\tPressureLevelCritical PressureLevel = \"critical\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PressureLevel) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PressureLevel(s) {\n\tcase PressureLevelModerate:\n\t\t*t = PressureLevelModerate\n\tcase PressureLevelCritical:\n\t\t*t = PressureLevelCritical\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PressureLevel value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SamplingProfileNode heap profile sample.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-SamplingProfileNode\ntype SamplingProfileNode struct {\n\tSize  float64  `json:\"size\"`  // Size of the sampled allocation.\n\tTotal float64  `json:\"total\"` // Total bytes attributed to this sample.\n\tStack []string `json:\"stack\"` // Execution stack at the point of allocation.\n}\n\n// SamplingProfile array of heap profile samples.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-SamplingProfile\ntype SamplingProfile struct {\n\tSamples []*SamplingProfileNode `json:\"samples\"`\n\tModules []*Module              `json:\"modules\"`\n}\n\n// Module executable module information.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-Module\ntype Module struct {\n\tName        string  `json:\"name\"`        // Name of the module.\n\tUUID        string  `json:\"uuid\"`        // UUID of the module.\n\tBaseAddress string  `json:\"baseAddress\"` // Base address where the module is loaded into memory. Encoded as a decimal or hexadecimal (0x prefixed) string.\n\tSize        float64 `json:\"size\"`        // Size of the module in bytes.\n}\n\n// DOMCounter DOM object counter data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Memory#type-DOMCounter\ntype DOMCounter struct {\n\tName  string `json:\"name\"`  // Object name. Note: object names should be presumed volatile and clients should not expect the returned names to be consistent across runs.\n\tCount int64  `json:\"count\"` // Object count.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/network/events.go",
    "content": "package network\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EventDataReceived fired when data chunk was received over the network.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-dataReceived\ntype EventDataReceived struct {\n\tRequestID         RequestID          `json:\"requestId\"`               // Request identifier.\n\tTimestamp         *cdp.MonotonicTime `json:\"timestamp\"`               // Timestamp.\n\tDataLength        int64              `json:\"dataLength\"`              // Data chunk length.\n\tEncodedDataLength int64              `json:\"encodedDataLength\"`       // Actual bytes received (might be less than dataLength for compressed encodings).\n\tData              string             `json:\"data,omitempty,omitzero\"` // Data that was received.\n}\n\n// EventEventSourceMessageReceived fired when EventSource message is\n// received.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-eventSourceMessageReceived\ntype EventEventSourceMessageReceived struct {\n\tRequestID RequestID          `json:\"requestId\"` // Request identifier.\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"` // Timestamp.\n\tEventName string             `json:\"eventName\"` // Message type.\n\tEventID   string             `json:\"eventId\"`   // Message identifier.\n\tData      string             `json:\"data\"`      // Message content.\n}\n\n// EventLoadingFailed fired when HTTP request has failed to load.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-loadingFailed\ntype EventLoadingFailed struct {\n\tRequestID       RequestID          `json:\"requestId\"`                          // Request identifier.\n\tTimestamp       *cdp.MonotonicTime `json:\"timestamp\"`                          // Timestamp.\n\tType            ResourceType       `json:\"type\"`                               // Resource type.\n\tErrorText       string             `json:\"errorText\"`                          // Error message. List of network errors: https://cs.chromium.org/chromium/src/net/base/net_error_list.h\n\tCanceled        bool               `json:\"canceled\"`                           // True if loading was canceled.\n\tBlockedReason   BlockedReason      `json:\"blockedReason,omitempty,omitzero\"`   // The reason why loading was blocked, if any.\n\tCorsErrorStatus *CorsErrorStatus   `json:\"corsErrorStatus,omitempty,omitzero\"` // The reason why loading was blocked by CORS, if any.\n}\n\n// EventLoadingFinished fired when HTTP request has finished loading.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-loadingFinished\ntype EventLoadingFinished struct {\n\tRequestID         RequestID          `json:\"requestId\"`         // Request identifier.\n\tTimestamp         *cdp.MonotonicTime `json:\"timestamp\"`         // Timestamp.\n\tEncodedDataLength float64            `json:\"encodedDataLength\"` // Total number of bytes received for this request.\n}\n\n// EventRequestServedFromCache fired if request ended up loading from cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-requestServedFromCache\ntype EventRequestServedFromCache struct {\n\tRequestID RequestID `json:\"requestId\"` // Request identifier.\n}\n\n// EventRequestWillBeSent fired when page is about to send HTTP request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-requestWillBeSent\ntype EventRequestWillBeSent struct {\n\tRequestID            RequestID           `json:\"requestId\"`                           // Request identifier.\n\tLoaderID             cdp.LoaderID        `json:\"loaderId\"`                            // Loader identifier. Empty string if the request is fetched from worker.\n\tDocumentURL          string              `json:\"documentURL\"`                         // URL of the document this request is loaded for.\n\tRequest              *Request            `json:\"request\"`                             // Request data.\n\tTimestamp            *cdp.MonotonicTime  `json:\"timestamp\"`                           // Timestamp.\n\tWallTime             *cdp.TimeSinceEpoch `json:\"wallTime\"`                            // Timestamp.\n\tInitiator            *Initiator          `json:\"initiator\"`                           // Request initiator.\n\tRedirectHasExtraInfo bool                `json:\"redirectHasExtraInfo\"`                // In the case that redirectResponse is populated, this flag indicates whether requestWillBeSentExtraInfo and responseReceivedExtraInfo events will be or were emitted for the request which was just redirected.\n\tRedirectResponse     *Response           `json:\"redirectResponse,omitempty,omitzero\"` // Redirect response data.\n\tType                 ResourceType        `json:\"type,omitempty,omitzero\"`             // Type of this resource.\n\tFrameID              cdp.FrameID         `json:\"frameId,omitempty,omitzero\"`          // Frame identifier.\n\tHasUserGesture       bool                `json:\"hasUserGesture\"`                      // Whether the request is initiated by a user gesture. Defaults to false.\n}\n\n// EventResourceChangedPriority fired when resource loading priority is\n// changed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-resourceChangedPriority\ntype EventResourceChangedPriority struct {\n\tRequestID   RequestID          `json:\"requestId\"`   // Request identifier.\n\tNewPriority ResourcePriority   `json:\"newPriority\"` // New priority\n\tTimestamp   *cdp.MonotonicTime `json:\"timestamp\"`   // Timestamp.\n}\n\n// EventSignedExchangeReceived fired when a signed exchange was received over\n// the network.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-signedExchangeReceived\ntype EventSignedExchangeReceived struct {\n\tRequestID RequestID           `json:\"requestId\"` // Request identifier.\n\tInfo      *SignedExchangeInfo `json:\"info\"`      // Information about the signed exchange response.\n}\n\n// EventResponseReceived fired when HTTP response is available.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-responseReceived\ntype EventResponseReceived struct {\n\tRequestID    RequestID          `json:\"requestId\"`                  // Request identifier.\n\tLoaderID     cdp.LoaderID       `json:\"loaderId\"`                   // Loader identifier. Empty string if the request is fetched from worker.\n\tTimestamp    *cdp.MonotonicTime `json:\"timestamp\"`                  // Timestamp.\n\tType         ResourceType       `json:\"type\"`                       // Resource type.\n\tResponse     *Response          `json:\"response\"`                   // Response data.\n\tHasExtraInfo bool               `json:\"hasExtraInfo\"`               // Indicates whether requestWillBeSentExtraInfo and responseReceivedExtraInfo events will be or were emitted for this request.\n\tFrameID      cdp.FrameID        `json:\"frameId,omitempty,omitzero\"` // Frame identifier.\n}\n\n// EventWebSocketClosed fired when WebSocket is closed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketClosed\ntype EventWebSocketClosed struct {\n\tRequestID RequestID          `json:\"requestId\"` // Request identifier.\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"` // Timestamp.\n}\n\n// EventWebSocketCreated fired upon WebSocket creation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketCreated\ntype EventWebSocketCreated struct {\n\tRequestID RequestID  `json:\"requestId\"`                    // Request identifier.\n\tURL       string     `json:\"url\"`                          // WebSocket request URL.\n\tInitiator *Initiator `json:\"initiator,omitempty,omitzero\"` // Request initiator.\n}\n\n// EventWebSocketFrameError fired when WebSocket message error occurs.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketFrameError\ntype EventWebSocketFrameError struct {\n\tRequestID    RequestID          `json:\"requestId\"`    // Request identifier.\n\tTimestamp    *cdp.MonotonicTime `json:\"timestamp\"`    // Timestamp.\n\tErrorMessage string             `json:\"errorMessage\"` // WebSocket error message.\n}\n\n// EventWebSocketFrameReceived fired when WebSocket message is received.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketFrameReceived\ntype EventWebSocketFrameReceived struct {\n\tRequestID RequestID          `json:\"requestId\"` // Request identifier.\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"` // Timestamp.\n\tResponse  *WebSocketFrame    `json:\"response\"`  // WebSocket response data.\n}\n\n// EventWebSocketFrameSent fired when WebSocket message is sent.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketFrameSent\ntype EventWebSocketFrameSent struct {\n\tRequestID RequestID          `json:\"requestId\"` // Request identifier.\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"` // Timestamp.\n\tResponse  *WebSocketFrame    `json:\"response\"`  // WebSocket response data.\n}\n\n// EventWebSocketHandshakeResponseReceived fired when WebSocket handshake\n// response becomes available.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketHandshakeResponseReceived\ntype EventWebSocketHandshakeResponseReceived struct {\n\tRequestID RequestID          `json:\"requestId\"` // Request identifier.\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"` // Timestamp.\n\tResponse  *WebSocketResponse `json:\"response\"`  // WebSocket response data.\n}\n\n// EventWebSocketWillSendHandshakeRequest fired when WebSocket is about to\n// initiate handshake.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webSocketWillSendHandshakeRequest\ntype EventWebSocketWillSendHandshakeRequest struct {\n\tRequestID RequestID           `json:\"requestId\"` // Request identifier.\n\tTimestamp *cdp.MonotonicTime  `json:\"timestamp\"` // Timestamp.\n\tWallTime  *cdp.TimeSinceEpoch `json:\"wallTime\"`  // UTC Timestamp.\n\tRequest   *WebSocketRequest   `json:\"request\"`   // WebSocket request data.\n}\n\n// EventWebTransportCreated fired upon WebTransport creation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webTransportCreated\ntype EventWebTransportCreated struct {\n\tTransportID RequestID          `json:\"transportId\"`                  // WebTransport identifier.\n\tURL         string             `json:\"url\"`                          // WebTransport request URL.\n\tTimestamp   *cdp.MonotonicTime `json:\"timestamp\"`                    // Timestamp.\n\tInitiator   *Initiator         `json:\"initiator,omitempty,omitzero\"` // Request initiator.\n}\n\n// EventWebTransportConnectionEstablished fired when WebTransport handshake\n// is finished.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webTransportConnectionEstablished\ntype EventWebTransportConnectionEstablished struct {\n\tTransportID RequestID          `json:\"transportId\"` // WebTransport identifier.\n\tTimestamp   *cdp.MonotonicTime `json:\"timestamp\"`   // Timestamp.\n}\n\n// EventWebTransportClosed fired when WebTransport is disposed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-webTransportClosed\ntype EventWebTransportClosed struct {\n\tTransportID RequestID          `json:\"transportId\"` // WebTransport identifier.\n\tTimestamp   *cdp.MonotonicTime `json:\"timestamp\"`   // Timestamp.\n}\n\n// EventDirectTCPSocketCreated fired upon direct_socket.TCPSocket creation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directTCPSocketCreated\ntype EventDirectTCPSocketCreated struct {\n\tIdentifier RequestID               `json:\"identifier\"`\n\tRemoteAddr string                  `json:\"remoteAddr\"`\n\tRemotePort int64                   `json:\"remotePort\"` // Unsigned int 16.\n\tOptions    *DirectTCPSocketOptions `json:\"options\"`\n\tTimestamp  *cdp.MonotonicTime      `json:\"timestamp\"`\n\tInitiator  *Initiator              `json:\"initiator,omitempty,omitzero\"`\n}\n\n// EventDirectTCPSocketOpened fired when direct_socket.TCPSocket connection\n// is opened.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directTCPSocketOpened\ntype EventDirectTCPSocketOpened struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tRemoteAddr string             `json:\"remoteAddr\"`\n\tRemotePort int64              `json:\"remotePort\"` // Expected to be unsigned integer.\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n\tLocalAddr  string             `json:\"localAddr,omitempty,omitzero\"`\n\tLocalPort  int64              `json:\"localPort,omitempty,omitzero\"` // Expected to be unsigned integer.\n}\n\n// EventDirectTCPSocketAborted fired when direct_socket.TCPSocket is aborted.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directTCPSocketAborted\ntype EventDirectTCPSocketAborted struct {\n\tIdentifier   RequestID          `json:\"identifier\"`\n\tErrorMessage string             `json:\"errorMessage\"`\n\tTimestamp    *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventDirectTCPSocketClosed fired when direct_socket.TCPSocket is closed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directTCPSocketClosed\ntype EventDirectTCPSocketClosed struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventDirectTCPSocketChunkSent fired when data is sent to tcp direct socket\n// stream.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directTCPSocketChunkSent\ntype EventDirectTCPSocketChunkSent struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tData       string             `json:\"data\"`\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventDirectTCPSocketChunkReceived fired when data is received from tcp\n// direct socket stream.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directTCPSocketChunkReceived\ntype EventDirectTCPSocketChunkReceived struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tData       string             `json:\"data\"`\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventDirectUDPSocketCreated fired upon direct_socket.UDPSocket creation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directUDPSocketCreated\ntype EventDirectUDPSocketCreated struct {\n\tIdentifier RequestID               `json:\"identifier\"`\n\tOptions    *DirectUDPSocketOptions `json:\"options\"`\n\tTimestamp  *cdp.MonotonicTime      `json:\"timestamp\"`\n\tInitiator  *Initiator              `json:\"initiator,omitempty,omitzero\"`\n}\n\n// EventDirectUDPSocketOpened fired when direct_socket.UDPSocket connection\n// is opened.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directUDPSocketOpened\ntype EventDirectUDPSocketOpened struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tLocalAddr  string             `json:\"localAddr\"`\n\tLocalPort  int64              `json:\"localPort\"` // Expected to be unsigned integer.\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n\tRemoteAddr string             `json:\"remoteAddr,omitempty,omitzero\"`\n\tRemotePort int64              `json:\"remotePort,omitempty,omitzero\"` // Expected to be unsigned integer.\n}\n\n// EventDirectUDPSocketAborted fired when direct_socket.UDPSocket is aborted.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directUDPSocketAborted\ntype EventDirectUDPSocketAborted struct {\n\tIdentifier   RequestID          `json:\"identifier\"`\n\tErrorMessage string             `json:\"errorMessage\"`\n\tTimestamp    *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventDirectUDPSocketClosed fired when direct_socket.UDPSocket is closed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directUDPSocketClosed\ntype EventDirectUDPSocketClosed struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventDirectUDPSocketChunkSent fired when message is sent to udp direct\n// socket stream.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directUDPSocketChunkSent\ntype EventDirectUDPSocketChunkSent struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tMessage    *DirectUDPMessage  `json:\"message\"`\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventDirectUDPSocketChunkReceived fired when message is received from udp\n// direct socket stream.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-directUDPSocketChunkReceived\ntype EventDirectUDPSocketChunkReceived struct {\n\tIdentifier RequestID          `json:\"identifier\"`\n\tMessage    *DirectUDPMessage  `json:\"message\"`\n\tTimestamp  *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventRequestWillBeSentExtraInfo fired when additional information about a\n// requestWillBeSent event is available from the network stack. Not every\n// requestWillBeSent event will have an additional requestWillBeSentExtraInfo\n// fired for it, and there is no guarantee whether requestWillBeSent or\n// requestWillBeSentExtraInfo will be fired first for the same request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-requestWillBeSentExtraInfo\ntype EventRequestWillBeSentExtraInfo struct {\n\tRequestID                     RequestID            `json:\"requestId\"`                              // Request identifier. Used to match this information to an existing requestWillBeSent event.\n\tAssociatedCookies             []*AssociatedCookie  `json:\"associatedCookies\"`                      // A list of cookies potentially associated to the requested URL. This includes both cookies sent with the request and the ones not sent; the latter are distinguished by having blockedReasons field set.\n\tHeaders                       Headers              `json:\"headers\"`                                // Raw request headers as they will be sent over the wire.\n\tConnectTiming                 *ConnectTiming       `json:\"connectTiming\"`                          // Connection timing information for the request.\n\tClientSecurityState           *ClientSecurityState `json:\"clientSecurityState,omitempty,omitzero\"` // The client security state set for the request.\n\tSiteHasCookieInOtherPartition bool                 `json:\"siteHasCookieInOtherPartition\"`          // Whether the site has partitioned cookies stored in a partition different than the current one.\n}\n\n// EventResponseReceivedExtraInfo fired when additional information about a\n// responseReceived event is available from the network stack. Not every\n// responseReceived event will have an additional responseReceivedExtraInfo for\n// it, and responseReceivedExtraInfo may be fired before or after\n// responseReceived.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-responseReceivedExtraInfo\ntype EventResponseReceivedExtraInfo struct {\n\tRequestID                RequestID                      `json:\"requestId\"`                             // Request identifier. Used to match this information to another responseReceived event.\n\tBlockedCookies           []*BlockedSetCookieWithReason  `json:\"blockedCookies\"`                        // A list of cookies which were not stored from the response along with the corresponding reasons for blocking. The cookies here may not be valid due to syntax errors, which are represented by the invalid cookie line string instead of a proper cookie.\n\tHeaders                  Headers                        `json:\"headers\"`                               // Raw response headers as they were received over the wire. Duplicate headers in the response are represented as a single key with their values concatentated using \\n as the separator. See also headersText that contains verbatim text for HTTP/1.*.\n\tResourceIPAddressSpace   IPAddressSpace                 `json:\"resourceIPAddressSpace\"`                // The IP address space of the resource. The address space can only be determined once the transport established the connection, so we can't send it in requestWillBeSentExtraInfo.\n\tStatusCode               int64                          `json:\"statusCode\"`                            // The status code of the response. This is useful in cases the request failed and no responseReceived event is triggered, which is the case for, e.g., CORS errors. This is also the correct status code for cached requests, where the status in responseReceived is a 200 and this will be 304.\n\tHeadersText              string                         `json:\"headersText,omitempty,omitzero\"`        // Raw response header text as it was received over the wire. The raw text may not always be available, such as in the case of HTTP/2 or QUIC.\n\tCookiePartitionKey       *CookiePartitionKey            `json:\"cookiePartitionKey,omitempty,omitzero\"` // The cookie partition key that will be used to store partitioned cookies set in this response. Only sent when partitioned cookies are enabled.\n\tCookiePartitionKeyOpaque bool                           `json:\"cookiePartitionKeyOpaque\"`              // True if partitioned cookies are enabled, but the partition key is not serializable to string.\n\tExemptedCookies          []*ExemptedSetCookieWithReason `json:\"exemptedCookies,omitempty,omitzero\"`    // A list of cookies which should have been blocked by 3PCD but are exempted and stored from the response with the corresponding reason.\n}\n\n// EventResponseReceivedEarlyHints fired when 103 Early Hints headers is\n// received in addition to the common response. Not every responseReceived event\n// will have an responseReceivedEarlyHints fired. Only one\n// responseReceivedEarlyHints may be fired for eached responseReceived event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-responseReceivedEarlyHints\ntype EventResponseReceivedEarlyHints struct {\n\tRequestID RequestID `json:\"requestId\"` // Request identifier. Used to match this information to another responseReceived event.\n\tHeaders   Headers   `json:\"headers\"`   // Raw response headers as they were received over the wire. Duplicate headers in the response are represented as a single key with their values concatentated using \\n as the separator. See also headersText that contains verbatim text for HTTP/1.*.\n}\n\n// EventTrustTokenOperationDone fired exactly once for each Trust Token\n// operation. Depending on the type of the operation and whether the operation\n// succeeded or failed, the event is fired before the corresponding request was\n// sent or after the response was received.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-trustTokenOperationDone\ntype EventTrustTokenOperationDone struct {\n\tStatus           TrustTokenOperationDoneStatus `json:\"status\"` // Detailed success or error status of the operation. 'AlreadyExists' also signifies a successful operation, as the result of the operation already exists und thus, the operation was abort preemptively (e.g. a cache hit).\n\tType             TrustTokenOperationType       `json:\"type\"`\n\tRequestID        RequestID                     `json:\"requestId\"`\n\tTopLevelOrigin   string                        `json:\"topLevelOrigin,omitempty,omitzero\"`   // Top level origin. The context in which the operation was attempted.\n\tIssuerOrigin     string                        `json:\"issuerOrigin,omitempty,omitzero\"`     // Origin of the issuer in case of a \"Issuance\" or \"Redemption\" operation.\n\tIssuedTokenCount int64                         `json:\"issuedTokenCount,omitempty,omitzero\"` // The number of obtained Trust Tokens on a successful \"Issuance\" operation.\n}\n\n// EventPolicyUpdated fired once security policy has been updated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-policyUpdated\ntype EventPolicyUpdated struct{}\n\n// EventSubresourceWebBundleMetadataReceived fired once when parsing the .wbn\n// file has succeeded. The event contains the information about the web bundle\n// contents.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-subresourceWebBundleMetadataReceived\ntype EventSubresourceWebBundleMetadataReceived struct {\n\tRequestID RequestID `json:\"requestId\"` // Request identifier. Used to match this information to another event.\n\tURLs      []string  `json:\"urls\"`      // A list of URLs of resources in the subresource Web Bundle.\n}\n\n// EventSubresourceWebBundleMetadataError fired once when parsing the .wbn\n// file has failed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-subresourceWebBundleMetadataError\ntype EventSubresourceWebBundleMetadataError struct {\n\tRequestID    RequestID `json:\"requestId\"`    // Request identifier. Used to match this information to another event.\n\tErrorMessage string    `json:\"errorMessage\"` // Error message\n}\n\n// EventSubresourceWebBundleInnerResponseParsed fired when handling requests\n// for resources within a .wbn file. Note: this will only be fired for resources\n// that are requested by the webpage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-subresourceWebBundleInnerResponseParsed\ntype EventSubresourceWebBundleInnerResponseParsed struct {\n\tInnerRequestID  RequestID `json:\"innerRequestId\"`                     // Request identifier of the subresource request\n\tInnerRequestURL string    `json:\"innerRequestURL\"`                    // URL of the subresource resource.\n\tBundleRequestID RequestID `json:\"bundleRequestId,omitempty,omitzero\"` // Bundle request identifier. Used to match this information to another event. This made be absent in case when the instrumentation was enabled only after webbundle was parsed.\n}\n\n// EventSubresourceWebBundleInnerResponseError fired when request for\n// resources within a .wbn file failed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-subresourceWebBundleInnerResponseError\ntype EventSubresourceWebBundleInnerResponseError struct {\n\tInnerRequestID  RequestID `json:\"innerRequestId\"`                     // Request identifier of the subresource request\n\tInnerRequestURL string    `json:\"innerRequestURL\"`                    // URL of the subresource resource.\n\tErrorMessage    string    `json:\"errorMessage\"`                       // Error message\n\tBundleRequestID RequestID `json:\"bundleRequestId,omitempty,omitzero\"` // Bundle request identifier. Used to match this information to another event. This made be absent in case when the instrumentation was enabled only after webbundle was parsed.\n}\n\n// EventReportingAPIReportAdded is sent whenever a new report is added. And\n// after 'enableReportingApi' for all existing reports.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-reportingApiReportAdded\ntype EventReportingAPIReportAdded struct {\n\tReport *ReportingAPIReport `json:\"report\"`\n}\n\n// EventReportingAPIReportUpdated [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-reportingApiReportUpdated\ntype EventReportingAPIReportUpdated struct {\n\tReport *ReportingAPIReport `json:\"report\"`\n}\n\n// EventReportingAPIEndpointsChangedForOrigin [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-reportingApiEndpointsChangedForOrigin\ntype EventReportingAPIEndpointsChangedForOrigin struct {\n\tOrigin    string                  `json:\"origin\"` // Origin of the document(s) which configured the endpoints.\n\tEndpoints []*ReportingAPIEndpoint `json:\"endpoints\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/network/network.go",
    "content": "// Package network provides the Chrome DevTools Protocol\n// commands, types, and events for the Network domain.\n//\n// Network domain allows tracking network activities of the page. It exposes\n// information about http, file, data and other requests and responses, their\n// headers, bodies, timing, etc.\n//\n// Generated by the cdproto-gen command.\npackage network\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/debugger\"\n\t\"github.com/chromedp/cdproto/io\"\n)\n\n// SetAcceptedEncodingsParams sets a list of content encodings that will be\n// accepted. Empty list means no encoding is accepted.\ntype SetAcceptedEncodingsParams struct {\n\tEncodings []ContentEncoding `json:\"encodings\"` // List of accepted content encodings.\n}\n\n// SetAcceptedEncodings sets a list of content encodings that will be\n// accepted. Empty list means no encoding is accepted.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setAcceptedEncodings\n//\n// parameters:\n//\n//\tencodings - List of accepted content encodings.\nfunc SetAcceptedEncodings(encodings []ContentEncoding) *SetAcceptedEncodingsParams {\n\treturn &SetAcceptedEncodingsParams{\n\t\tEncodings: encodings,\n\t}\n}\n\n// Do executes Network.setAcceptedEncodings against the provided context.\nfunc (p *SetAcceptedEncodingsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAcceptedEncodings, p, nil)\n}\n\n// ClearAcceptedEncodingsOverrideParams clears accepted encodings set by\n// setAcceptedEncodings.\ntype ClearAcceptedEncodingsOverrideParams struct{}\n\n// ClearAcceptedEncodingsOverride clears accepted encodings set by\n// setAcceptedEncodings.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-clearAcceptedEncodingsOverride\nfunc ClearAcceptedEncodingsOverride() *ClearAcceptedEncodingsOverrideParams {\n\treturn &ClearAcceptedEncodingsOverrideParams{}\n}\n\n// Do executes Network.clearAcceptedEncodingsOverride against the provided context.\nfunc (p *ClearAcceptedEncodingsOverrideParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearAcceptedEncodingsOverride, nil, nil)\n}\n\n// ClearBrowserCacheParams clears browser cache.\ntype ClearBrowserCacheParams struct{}\n\n// ClearBrowserCache clears browser cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-clearBrowserCache\nfunc ClearBrowserCache() *ClearBrowserCacheParams {\n\treturn &ClearBrowserCacheParams{}\n}\n\n// Do executes Network.clearBrowserCache against the provided context.\nfunc (p *ClearBrowserCacheParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearBrowserCache, nil, nil)\n}\n\n// ClearBrowserCookiesParams clears browser cookies.\ntype ClearBrowserCookiesParams struct{}\n\n// ClearBrowserCookies clears browser cookies.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-clearBrowserCookies\nfunc ClearBrowserCookies() *ClearBrowserCookiesParams {\n\treturn &ClearBrowserCookiesParams{}\n}\n\n// Do executes Network.clearBrowserCookies against the provided context.\nfunc (p *ClearBrowserCookiesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearBrowserCookies, nil, nil)\n}\n\n// DeleteCookiesParams deletes browser cookies with matching name and url or\n// domain/path/partitionKey pair.\ntype DeleteCookiesParams struct {\n\tName         string              `json:\"name\"`                            // Name of the cookies to remove.\n\tURL          string              `json:\"url,omitempty,omitzero\"`          // If specified, deletes all the cookies with the given name where domain and path match provided URL.\n\tDomain       string              `json:\"domain,omitempty,omitzero\"`       // If specified, deletes only cookies with the exact domain.\n\tPath         string              `json:\"path,omitempty,omitzero\"`         // If specified, deletes only cookies with the exact path.\n\tPartitionKey *CookiePartitionKey `json:\"partitionKey,omitempty,omitzero\"` // If specified, deletes only cookies with the the given name and partitionKey where all partition key attributes match the cookie partition key attribute.\n}\n\n// DeleteCookies deletes browser cookies with matching name and url or\n// domain/path/partitionKey pair.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-deleteCookies\n//\n// parameters:\n//\n//\tname - Name of the cookies to remove.\nfunc DeleteCookies(name string) *DeleteCookiesParams {\n\treturn &DeleteCookiesParams{\n\t\tName: name,\n\t}\n}\n\n// WithURL if specified, deletes all the cookies with the given name where\n// domain and path match provided URL.\nfunc (p DeleteCookiesParams) WithURL(url string) *DeleteCookiesParams {\n\tp.URL = url\n\treturn &p\n}\n\n// WithDomain if specified, deletes only cookies with the exact domain.\nfunc (p DeleteCookiesParams) WithDomain(domain string) *DeleteCookiesParams {\n\tp.Domain = domain\n\treturn &p\n}\n\n// WithPath if specified, deletes only cookies with the exact path.\nfunc (p DeleteCookiesParams) WithPath(path string) *DeleteCookiesParams {\n\tp.Path = path\n\treturn &p\n}\n\n// WithPartitionKey if specified, deletes only cookies with the the given\n// name and partitionKey where all partition key attributes match the cookie\n// partition key attribute.\nfunc (p DeleteCookiesParams) WithPartitionKey(partitionKey *CookiePartitionKey) *DeleteCookiesParams {\n\tp.PartitionKey = partitionKey\n\treturn &p\n}\n\n// Do executes Network.deleteCookies against the provided context.\nfunc (p *DeleteCookiesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeleteCookies, p, nil)\n}\n\n// DisableParams disables network tracking, prevents network events from\n// being sent to the client.\ntype DisableParams struct{}\n\n// Disable disables network tracking, prevents network events from being sent\n// to the client.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Network.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EmulateNetworkConditionsParams activates emulation of network conditions.\ntype EmulateNetworkConditionsParams struct {\n\tOffline            bool           `json:\"offline\"`                              // True to emulate internet disconnection.\n\tLatency            float64        `json:\"latency\"`                              // Minimum latency from request sent to response headers received (ms).\n\tDownloadThroughput float64        `json:\"downloadThroughput\"`                   // Maximal aggregated download throughput (bytes/sec). -1 disables download throttling.\n\tUploadThroughput   float64        `json:\"uploadThroughput\"`                     // Maximal aggregated upload throughput (bytes/sec).  -1 disables upload throttling.\n\tConnectionType     ConnectionType `json:\"connectionType,omitempty,omitzero\"`    // Connection type if known.\n\tPacketLoss         float64        `json:\"packetLoss,omitempty,omitzero\"`        // WebRTC packet loss (percent, 0-100). 0 disables packet loss emulation, 100 drops all the packets.\n\tPacketQueueLength  int64          `json:\"packetQueueLength,omitempty,omitzero\"` // WebRTC packet queue length (packet). 0 removes any queue length limitations.\n\tPacketReordering   bool           `json:\"packetReordering\"`                     // WebRTC packetReordering feature.\n}\n\n// EmulateNetworkConditions activates emulation of network conditions.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-emulateNetworkConditions\n//\n// parameters:\n//\n//\toffline - True to emulate internet disconnection.\n//\tlatency - Minimum latency from request sent to response headers received (ms).\n//\tdownloadThroughput - Maximal aggregated download throughput (bytes/sec). -1 disables download throttling.\n//\tuploadThroughput - Maximal aggregated upload throughput (bytes/sec).  -1 disables upload throttling.\nfunc EmulateNetworkConditions(offline bool, latency float64, downloadThroughput float64, uploadThroughput float64) *EmulateNetworkConditionsParams {\n\treturn &EmulateNetworkConditionsParams{\n\t\tOffline:            offline,\n\t\tLatency:            latency,\n\t\tDownloadThroughput: downloadThroughput,\n\t\tUploadThroughput:   uploadThroughput,\n\t\tPacketReordering:   false,\n\t}\n}\n\n// WithConnectionType connection type if known.\nfunc (p EmulateNetworkConditionsParams) WithConnectionType(connectionType ConnectionType) *EmulateNetworkConditionsParams {\n\tp.ConnectionType = connectionType\n\treturn &p\n}\n\n// WithPacketLoss webRTC packet loss (percent, 0-100). 0 disables packet loss\n// emulation, 100 drops all the packets.\nfunc (p EmulateNetworkConditionsParams) WithPacketLoss(packetLoss float64) *EmulateNetworkConditionsParams {\n\tp.PacketLoss = packetLoss\n\treturn &p\n}\n\n// WithPacketQueueLength webRTC packet queue length (packet). 0 removes any\n// queue length limitations.\nfunc (p EmulateNetworkConditionsParams) WithPacketQueueLength(packetQueueLength int64) *EmulateNetworkConditionsParams {\n\tp.PacketQueueLength = packetQueueLength\n\treturn &p\n}\n\n// WithPacketReordering webRTC packetReordering feature.\nfunc (p EmulateNetworkConditionsParams) WithPacketReordering(packetReordering bool) *EmulateNetworkConditionsParams {\n\tp.PacketReordering = packetReordering\n\treturn &p\n}\n\n// Do executes Network.emulateNetworkConditions against the provided context.\nfunc (p *EmulateNetworkConditionsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEmulateNetworkConditions, p, nil)\n}\n\n// EnableParams enables network tracking, network events will now be\n// delivered to the client.\ntype EnableParams struct {\n\tMaxTotalBufferSize        int64 `json:\"maxTotalBufferSize,omitempty,omitzero\"`    // Buffer size in bytes to use when preserving network payloads (XHRs, etc).\n\tMaxResourceBufferSize     int64 `json:\"maxResourceBufferSize,omitempty,omitzero\"` // Per-resource buffer size in bytes to use when preserving network payloads (XHRs, etc).\n\tMaxPostDataSize           int64 `json:\"maxPostDataSize,omitempty,omitzero\"`       // Longest post body size (in bytes) that would be included in requestWillBeSent notification\n\tReportDirectSocketTraffic bool  `json:\"reportDirectSocketTraffic\"`                // Whether DirectSocket chunk send/receive events should be reported.\n}\n\n// Enable enables network tracking, network events will now be delivered to\n// the client.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{\n\t\tReportDirectSocketTraffic: false,\n\t}\n}\n\n// WithMaxTotalBufferSize buffer size in bytes to use when preserving network\n// payloads (XHRs, etc).\nfunc (p EnableParams) WithMaxTotalBufferSize(maxTotalBufferSize int64) *EnableParams {\n\tp.MaxTotalBufferSize = maxTotalBufferSize\n\treturn &p\n}\n\n// WithMaxResourceBufferSize per-resource buffer size in bytes to use when\n// preserving network payloads (XHRs, etc).\nfunc (p EnableParams) WithMaxResourceBufferSize(maxResourceBufferSize int64) *EnableParams {\n\tp.MaxResourceBufferSize = maxResourceBufferSize\n\treturn &p\n}\n\n// WithMaxPostDataSize longest post body size (in bytes) that would be\n// included in requestWillBeSent notification.\nfunc (p EnableParams) WithMaxPostDataSize(maxPostDataSize int64) *EnableParams {\n\tp.MaxPostDataSize = maxPostDataSize\n\treturn &p\n}\n\n// WithReportDirectSocketTraffic whether DirectSocket chunk send/receive\n// events should be reported.\nfunc (p EnableParams) WithReportDirectSocketTraffic(reportDirectSocketTraffic bool) *EnableParams {\n\tp.ReportDirectSocketTraffic = reportDirectSocketTraffic\n\treturn &p\n}\n\n// Do executes Network.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// GetCertificateParams returns the DER-encoded certificate.\ntype GetCertificateParams struct {\n\tOrigin string `json:\"origin\"` // Origin to get certificate for.\n}\n\n// GetCertificate returns the DER-encoded certificate.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-getCertificate\n//\n// parameters:\n//\n//\torigin - Origin to get certificate for.\nfunc GetCertificate(origin string) *GetCertificateParams {\n\treturn &GetCertificateParams{\n\t\tOrigin: origin,\n\t}\n}\n\n// GetCertificateReturns return values.\ntype GetCertificateReturns struct {\n\tTableNames []string `json:\"tableNames,omitempty,omitzero\"`\n}\n\n// Do executes Network.getCertificate against the provided context.\n//\n// returns:\n//\n//\ttableNames\nfunc (p *GetCertificateParams) Do(ctx context.Context) (tableNames []string, err error) {\n\t// execute\n\tvar res GetCertificateReturns\n\terr = cdp.Execute(ctx, CommandGetCertificate, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.TableNames, nil\n}\n\n// GetCookiesParams returns all browser cookies for the current URL.\n// Depending on the backend support, will return detailed cookie information in\n// the cookies field.\ntype GetCookiesParams struct {\n\tURLs []string `json:\"urls,omitempty,omitzero\"` // The list of URLs for which applicable cookies will be fetched. If not specified, it's assumed to be set to the list containing the URLs of the page and all of its subframes.\n}\n\n// GetCookies returns all browser cookies for the current URL. Depending on\n// the backend support, will return detailed cookie information in the cookies\n// field.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-getCookies\n//\n// parameters:\nfunc GetCookies() *GetCookiesParams {\n\treturn &GetCookiesParams{}\n}\n\n// WithURLs the list of URLs for which applicable cookies will be fetched. If\n// not specified, it's assumed to be set to the list containing the URLs of the\n// page and all of its subframes.\nfunc (p GetCookiesParams) WithURLs(urls []string) *GetCookiesParams {\n\tp.URLs = urls\n\treturn &p\n}\n\n// GetCookiesReturns return values.\ntype GetCookiesReturns struct {\n\tCookies []*Cookie `json:\"cookies,omitempty,omitzero\"` // Array of cookie objects.\n}\n\n// Do executes Network.getCookies against the provided context.\n//\n// returns:\n//\n//\tcookies - Array of cookie objects.\nfunc (p *GetCookiesParams) Do(ctx context.Context) (cookies []*Cookie, err error) {\n\t// execute\n\tvar res GetCookiesReturns\n\terr = cdp.Execute(ctx, CommandGetCookies, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Cookies, nil\n}\n\n// GetResponseBodyParams returns content served for the given request.\ntype GetResponseBodyParams struct {\n\tRequestID RequestID `json:\"requestId\"` // Identifier of the network request to get content for.\n}\n\n// GetResponseBody returns content served for the given request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-getResponseBody\n//\n// parameters:\n//\n//\trequestID - Identifier of the network request to get content for.\nfunc GetResponseBody(requestID RequestID) *GetResponseBodyParams {\n\treturn &GetResponseBodyParams{\n\t\tRequestID: requestID,\n\t}\n}\n\n// GetResponseBodyReturns return values.\ntype GetResponseBodyReturns struct {\n\tBody          string `json:\"body,omitempty,omitzero\"` // Response body.\n\tBase64encoded bool   `json:\"base64Encoded\"`           // True, if content was sent as base64.\n}\n\n// Do executes Network.getResponseBody against the provided context.\n//\n// returns:\n//\n//\tbody - Response body.\nfunc (p *GetResponseBodyParams) Do(ctx context.Context) (body []byte, err error) {\n\t// execute\n\tvar res GetResponseBodyReturns\n\terr = cdp.Execute(ctx, CommandGetResponseBody, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tif res.Base64encoded {\n\t\tdec, err = base64.StdEncoding.DecodeString(res.Body)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tdec = []byte(res.Body)\n\t}\n\treturn dec, nil\n}\n\n// GetRequestPostDataParams returns post data sent with the request. Returns\n// an error when no data was sent with the request.\ntype GetRequestPostDataParams struct {\n\tRequestID RequestID `json:\"requestId\"` // Identifier of the network request to get content for.\n}\n\n// GetRequestPostData returns post data sent with the request. Returns an\n// error when no data was sent with the request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-getRequestPostData\n//\n// parameters:\n//\n//\trequestID - Identifier of the network request to get content for.\nfunc GetRequestPostData(requestID RequestID) *GetRequestPostDataParams {\n\treturn &GetRequestPostDataParams{\n\t\tRequestID: requestID,\n\t}\n}\n\n// GetRequestPostDataReturns return values.\ntype GetRequestPostDataReturns struct {\n\tPostData string `json:\"postData,omitempty,omitzero\"` // Request body string, omitting files from multipart requests\n}\n\n// Do executes Network.getRequestPostData against the provided context.\n//\n// returns:\n//\n//\tpostData - Request body string, omitting files from multipart requests\nfunc (p *GetRequestPostDataParams) Do(ctx context.Context) (postData string, err error) {\n\t// execute\n\tvar res GetRequestPostDataReturns\n\terr = cdp.Execute(ctx, CommandGetRequestPostData, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.PostData, nil\n}\n\n// GetResponseBodyForInterceptionParams returns content served for the given\n// currently intercepted request.\ntype GetResponseBodyForInterceptionParams struct {\n\tInterceptionID InterceptionID `json:\"interceptionId\"` // Identifier for the intercepted request to get body for.\n}\n\n// GetResponseBodyForInterception returns content served for the given\n// currently intercepted request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-getResponseBodyForInterception\n//\n// parameters:\n//\n//\tinterceptionID - Identifier for the intercepted request to get body for.\nfunc GetResponseBodyForInterception(interceptionID InterceptionID) *GetResponseBodyForInterceptionParams {\n\treturn &GetResponseBodyForInterceptionParams{\n\t\tInterceptionID: interceptionID,\n\t}\n}\n\n// GetResponseBodyForInterceptionReturns return values.\ntype GetResponseBodyForInterceptionReturns struct {\n\tBody          string `json:\"body,omitempty,omitzero\"` // Response body.\n\tBase64encoded bool   `json:\"base64Encoded\"`           // True, if content was sent as base64.\n}\n\n// Do executes Network.getResponseBodyForInterception against the provided context.\n//\n// returns:\n//\n//\tbody - Response body.\nfunc (p *GetResponseBodyForInterceptionParams) Do(ctx context.Context) (body []byte, err error) {\n\t// execute\n\tvar res GetResponseBodyForInterceptionReturns\n\terr = cdp.Execute(ctx, CommandGetResponseBodyForInterception, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tif res.Base64encoded {\n\t\tdec, err = base64.StdEncoding.DecodeString(res.Body)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tdec = []byte(res.Body)\n\t}\n\treturn dec, nil\n}\n\n// TakeResponseBodyForInterceptionAsStreamParams returns a handle to the\n// stream representing the response body. Note that after this command, the\n// intercepted request can't be continued as is -- you either need to cancel it\n// or to provide the response body. The stream only supports sequential read,\n// IO.read will fail if the position is specified.\ntype TakeResponseBodyForInterceptionAsStreamParams struct {\n\tInterceptionID InterceptionID `json:\"interceptionId\"`\n}\n\n// TakeResponseBodyForInterceptionAsStream returns a handle to the stream\n// representing the response body. Note that after this command, the intercepted\n// request can't be continued as is -- you either need to cancel it or to\n// provide the response body. The stream only supports sequential read, IO.read\n// will fail if the position is specified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-takeResponseBodyForInterceptionAsStream\n//\n// parameters:\n//\n//\tinterceptionID\nfunc TakeResponseBodyForInterceptionAsStream(interceptionID InterceptionID) *TakeResponseBodyForInterceptionAsStreamParams {\n\treturn &TakeResponseBodyForInterceptionAsStreamParams{\n\t\tInterceptionID: interceptionID,\n\t}\n}\n\n// TakeResponseBodyForInterceptionAsStreamReturns return values.\ntype TakeResponseBodyForInterceptionAsStreamReturns struct {\n\tStream io.StreamHandle `json:\"stream,omitempty,omitzero\"`\n}\n\n// Do executes Network.takeResponseBodyForInterceptionAsStream against the provided context.\n//\n// returns:\n//\n//\tstream\nfunc (p *TakeResponseBodyForInterceptionAsStreamParams) Do(ctx context.Context) (stream io.StreamHandle, err error) {\n\t// execute\n\tvar res TakeResponseBodyForInterceptionAsStreamReturns\n\terr = cdp.Execute(ctx, CommandTakeResponseBodyForInterceptionAsStream, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.Stream, nil\n}\n\n// ReplayXHRParams this method sends a new XMLHttpRequest which is identical\n// to the original one. The following parameters should be identical: method,\n// url, async, request body, extra headers, withCredentials attribute, user,\n// password.\ntype ReplayXHRParams struct {\n\tRequestID RequestID `json:\"requestId\"` // Identifier of XHR to replay.\n}\n\n// ReplayXHR this method sends a new XMLHttpRequest which is identical to the\n// original one. The following parameters should be identical: method, url,\n// async, request body, extra headers, withCredentials attribute, user,\n// password.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-replayXHR\n//\n// parameters:\n//\n//\trequestID - Identifier of XHR to replay.\nfunc ReplayXHR(requestID RequestID) *ReplayXHRParams {\n\treturn &ReplayXHRParams{\n\t\tRequestID: requestID,\n\t}\n}\n\n// Do executes Network.replayXHR against the provided context.\nfunc (p *ReplayXHRParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandReplayXHR, p, nil)\n}\n\n// SearchInResponseBodyParams searches for given string in response content.\ntype SearchInResponseBodyParams struct {\n\tRequestID     RequestID `json:\"requestId\"`     // Identifier of the network response to search.\n\tQuery         string    `json:\"query\"`         // String to search for.\n\tCaseSensitive bool      `json:\"caseSensitive\"` // If true, search is case sensitive.\n\tIsRegex       bool      `json:\"isRegex\"`       // If true, treats string parameter as regex.\n}\n\n// SearchInResponseBody searches for given string in response content.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-searchInResponseBody\n//\n// parameters:\n//\n//\trequestID - Identifier of the network response to search.\n//\tquery - String to search for.\nfunc SearchInResponseBody(requestID RequestID, query string) *SearchInResponseBodyParams {\n\treturn &SearchInResponseBodyParams{\n\t\tRequestID:     requestID,\n\t\tQuery:         query,\n\t\tCaseSensitive: false,\n\t\tIsRegex:       false,\n\t}\n}\n\n// WithCaseSensitive if true, search is case sensitive.\nfunc (p SearchInResponseBodyParams) WithCaseSensitive(caseSensitive bool) *SearchInResponseBodyParams {\n\tp.CaseSensitive = caseSensitive\n\treturn &p\n}\n\n// WithIsRegex if true, treats string parameter as regex.\nfunc (p SearchInResponseBodyParams) WithIsRegex(isRegex bool) *SearchInResponseBodyParams {\n\tp.IsRegex = isRegex\n\treturn &p\n}\n\n// SearchInResponseBodyReturns return values.\ntype SearchInResponseBodyReturns struct {\n\tResult []*debugger.SearchMatch `json:\"result,omitempty,omitzero\"` // List of search matches.\n}\n\n// Do executes Network.searchInResponseBody against the provided context.\n//\n// returns:\n//\n//\tresult - List of search matches.\nfunc (p *SearchInResponseBodyParams) Do(ctx context.Context) (result []*debugger.SearchMatch, err error) {\n\t// execute\n\tvar res SearchInResponseBodyReturns\n\terr = cdp.Execute(ctx, CommandSearchInResponseBody, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Result, nil\n}\n\n// SetBlockedURLsParams blocks URLs from loading.\ntype SetBlockedURLsParams struct {\n\tURLs []string `json:\"urls\"` // URL patterns to block. Wildcards ('*') are allowed.\n}\n\n// SetBlockedURLs blocks URLs from loading.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setBlockedURLs\n//\n// parameters:\n//\n//\turls - URL patterns to block. Wildcards ('*') are allowed.\nfunc SetBlockedURLs(urls []string) *SetBlockedURLsParams {\n\treturn &SetBlockedURLsParams{\n\t\tURLs: urls,\n\t}\n}\n\n// Do executes Network.setBlockedURLs against the provided context.\nfunc (p *SetBlockedURLsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBlockedURLs, p, nil)\n}\n\n// SetBypassServiceWorkerParams toggles ignoring of service worker for each\n// request.\ntype SetBypassServiceWorkerParams struct {\n\tBypass bool `json:\"bypass\"` // Bypass service worker and load from network.\n}\n\n// SetBypassServiceWorker toggles ignoring of service worker for each\n// request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setBypassServiceWorker\n//\n// parameters:\n//\n//\tbypass - Bypass service worker and load from network.\nfunc SetBypassServiceWorker(bypass bool) *SetBypassServiceWorkerParams {\n\treturn &SetBypassServiceWorkerParams{\n\t\tBypass: bypass,\n\t}\n}\n\n// Do executes Network.setBypassServiceWorker against the provided context.\nfunc (p *SetBypassServiceWorkerParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBypassServiceWorker, p, nil)\n}\n\n// SetCacheDisabledParams toggles ignoring cache for each request. If true,\n// cache will not be used.\ntype SetCacheDisabledParams struct {\n\tCacheDisabled bool `json:\"cacheDisabled\"` // Cache disabled state.\n}\n\n// SetCacheDisabled toggles ignoring cache for each request. If true, cache\n// will not be used.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setCacheDisabled\n//\n// parameters:\n//\n//\tcacheDisabled - Cache disabled state.\nfunc SetCacheDisabled(cacheDisabled bool) *SetCacheDisabledParams {\n\treturn &SetCacheDisabledParams{\n\t\tCacheDisabled: cacheDisabled,\n\t}\n}\n\n// Do executes Network.setCacheDisabled against the provided context.\nfunc (p *SetCacheDisabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCacheDisabled, p, nil)\n}\n\n// SetCookieParams sets a cookie with the given cookie data; may overwrite\n// equivalent cookies if they exist.\ntype SetCookieParams struct {\n\tName         string              `json:\"name\"`                            // Cookie name.\n\tValue        string              `json:\"value\"`                           // Cookie value.\n\tURL          string              `json:\"url,omitempty,omitzero\"`          // The request-URI to associate with the setting of the cookie. This value can affect the default domain, path, source port, and source scheme values of the created cookie.\n\tDomain       string              `json:\"domain,omitempty,omitzero\"`       // Cookie domain.\n\tPath         string              `json:\"path,omitempty,omitzero\"`         // Cookie path.\n\tSecure       bool                `json:\"secure\"`                          // True if cookie is secure.\n\tHTTPOnly     bool                `json:\"httpOnly\"`                        // True if cookie is http-only.\n\tSameSite     CookieSameSite      `json:\"sameSite,omitempty,omitzero\"`     // Cookie SameSite type.\n\tExpires      *cdp.TimeSinceEpoch `json:\"expires,omitempty,omitzero\"`      // Cookie expiration date, session cookie if not set\n\tPriority     CookiePriority      `json:\"priority,omitempty,omitzero\"`     // Cookie Priority type.\n\tSameParty    bool                `json:\"sameParty\"`                       // True if cookie is SameParty.\n\tSourceScheme CookieSourceScheme  `json:\"sourceScheme,omitempty,omitzero\"` // Cookie source scheme type.\n\tSourcePort   int64               `json:\"sourcePort,omitempty,omitzero\"`   // Cookie source port. Valid values are {-1, [1, 65535]}, -1 indicates an unspecified port. An unspecified port value allows protocol clients to emulate legacy cookie scope for the port. This is a temporary ability and it will be removed in the future.\n\tPartitionKey *CookiePartitionKey `json:\"partitionKey,omitempty,omitzero\"` // Cookie partition key. If not set, the cookie will be set as not partitioned.\n}\n\n// SetCookie sets a cookie with the given cookie data; may overwrite\n// equivalent cookies if they exist.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setCookie\n//\n// parameters:\n//\n//\tname - Cookie name.\n//\tvalue - Cookie value.\nfunc SetCookie(name string, value string) *SetCookieParams {\n\treturn &SetCookieParams{\n\t\tName:      name,\n\t\tValue:     value,\n\t\tSecure:    false,\n\t\tHTTPOnly:  false,\n\t\tSameParty: false,\n\t}\n}\n\n// WithURL the request-URI to associate with the setting of the cookie. This\n// value can affect the default domain, path, source port, and source scheme\n// values of the created cookie.\nfunc (p SetCookieParams) WithURL(url string) *SetCookieParams {\n\tp.URL = url\n\treturn &p\n}\n\n// WithDomain cookie domain.\nfunc (p SetCookieParams) WithDomain(domain string) *SetCookieParams {\n\tp.Domain = domain\n\treturn &p\n}\n\n// WithPath cookie path.\nfunc (p SetCookieParams) WithPath(path string) *SetCookieParams {\n\tp.Path = path\n\treturn &p\n}\n\n// WithSecure true if cookie is secure.\nfunc (p SetCookieParams) WithSecure(secure bool) *SetCookieParams {\n\tp.Secure = secure\n\treturn &p\n}\n\n// WithHTTPOnly true if cookie is http-only.\nfunc (p SetCookieParams) WithHTTPOnly(httpOnly bool) *SetCookieParams {\n\tp.HTTPOnly = httpOnly\n\treturn &p\n}\n\n// WithSameSite cookie SameSite type.\nfunc (p SetCookieParams) WithSameSite(sameSite CookieSameSite) *SetCookieParams {\n\tp.SameSite = sameSite\n\treturn &p\n}\n\n// WithExpires cookie expiration date, session cookie if not set.\nfunc (p SetCookieParams) WithExpires(expires *cdp.TimeSinceEpoch) *SetCookieParams {\n\tp.Expires = expires\n\treturn &p\n}\n\n// WithPriority cookie Priority type.\nfunc (p SetCookieParams) WithPriority(priority CookiePriority) *SetCookieParams {\n\tp.Priority = priority\n\treturn &p\n}\n\n// WithSameParty true if cookie is SameParty.\nfunc (p SetCookieParams) WithSameParty(sameParty bool) *SetCookieParams {\n\tp.SameParty = sameParty\n\treturn &p\n}\n\n// WithSourceScheme cookie source scheme type.\nfunc (p SetCookieParams) WithSourceScheme(sourceScheme CookieSourceScheme) *SetCookieParams {\n\tp.SourceScheme = sourceScheme\n\treturn &p\n}\n\n// WithSourcePort cookie source port. Valid values are {-1, [1, 65535]}, -1\n// indicates an unspecified port. An unspecified port value allows protocol\n// clients to emulate legacy cookie scope for the port. This is a temporary\n// ability and it will be removed in the future.\nfunc (p SetCookieParams) WithSourcePort(sourcePort int64) *SetCookieParams {\n\tp.SourcePort = sourcePort\n\treturn &p\n}\n\n// WithPartitionKey cookie partition key. If not set, the cookie will be set\n// as not partitioned.\nfunc (p SetCookieParams) WithPartitionKey(partitionKey *CookiePartitionKey) *SetCookieParams {\n\tp.PartitionKey = partitionKey\n\treturn &p\n}\n\n// Do executes Network.setCookie against the provided context.\nfunc (p *SetCookieParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCookie, p, nil)\n}\n\n// SetCookiesParams sets given cookies.\ntype SetCookiesParams struct {\n\tCookies []*CookieParam `json:\"cookies\"` // Cookies to be set.\n}\n\n// SetCookies sets given cookies.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setCookies\n//\n// parameters:\n//\n//\tcookies - Cookies to be set.\nfunc SetCookies(cookies []*CookieParam) *SetCookiesParams {\n\treturn &SetCookiesParams{\n\t\tCookies: cookies,\n\t}\n}\n\n// Do executes Network.setCookies against the provided context.\nfunc (p *SetCookiesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCookies, p, nil)\n}\n\n// SetExtraHTTPHeadersParams specifies whether to always send extra HTTP\n// headers with the requests from this page.\ntype SetExtraHTTPHeadersParams struct {\n\tHeaders Headers `json:\"headers\"` // Map with extra HTTP headers.\n}\n\n// SetExtraHTTPHeaders specifies whether to always send extra HTTP headers\n// with the requests from this page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setExtraHTTPHeaders\n//\n// parameters:\n//\n//\theaders - Map with extra HTTP headers.\nfunc SetExtraHTTPHeaders(headers Headers) *SetExtraHTTPHeadersParams {\n\treturn &SetExtraHTTPHeadersParams{\n\t\tHeaders: headers,\n\t}\n}\n\n// Do executes Network.setExtraHTTPHeaders against the provided context.\nfunc (p *SetExtraHTTPHeadersParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetExtraHTTPHeaders, p, nil)\n}\n\n// SetAttachDebugStackParams specifies whether to attach a page script stack\n// id in requests.\ntype SetAttachDebugStackParams struct {\n\tEnabled bool `json:\"enabled\"` // Whether to attach a page script stack for debugging purpose.\n}\n\n// SetAttachDebugStack specifies whether to attach a page script stack id in\n// requests.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setAttachDebugStack\n//\n// parameters:\n//\n//\tenabled - Whether to attach a page script stack for debugging purpose.\nfunc SetAttachDebugStack(enabled bool) *SetAttachDebugStackParams {\n\treturn &SetAttachDebugStackParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Network.setAttachDebugStack against the provided context.\nfunc (p *SetAttachDebugStackParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAttachDebugStack, p, nil)\n}\n\n// StreamResourceContentParams enables streaming of the response for the\n// given requestId. If enabled, the dataReceived event contains the data that\n// was received during streaming.\ntype StreamResourceContentParams struct {\n\tRequestID RequestID `json:\"requestId\"` // Identifier of the request to stream.\n}\n\n// StreamResourceContent enables streaming of the response for the given\n// requestId. If enabled, the dataReceived event contains the data that was\n// received during streaming.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-streamResourceContent\n//\n// parameters:\n//\n//\trequestID - Identifier of the request to stream.\nfunc StreamResourceContent(requestID RequestID) *StreamResourceContentParams {\n\treturn &StreamResourceContentParams{\n\t\tRequestID: requestID,\n\t}\n}\n\n// StreamResourceContentReturns return values.\ntype StreamResourceContentReturns struct {\n\tBufferedData string `json:\"bufferedData,omitempty,omitzero\"` // Data that has been buffered until streaming is enabled.\n}\n\n// Do executes Network.streamResourceContent against the provided context.\n//\n// returns:\n//\n//\tbufferedData - Data that has been buffered until streaming is enabled.\nfunc (p *StreamResourceContentParams) Do(ctx context.Context) (bufferedData []byte, err error) {\n\t// execute\n\tvar res StreamResourceContentReturns\n\terr = cdp.Execute(ctx, CommandStreamResourceContent, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tdec, err = base64.StdEncoding.DecodeString(res.BufferedData)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dec, nil\n}\n\n// GetSecurityIsolationStatusParams returns information about the COEP/COOP\n// isolation status.\ntype GetSecurityIsolationStatusParams struct {\n\tFrameID cdp.FrameID `json:\"frameId,omitempty,omitzero\"` // If no frameId is provided, the status of the target is provided.\n}\n\n// GetSecurityIsolationStatus returns information about the COEP/COOP\n// isolation status.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-getSecurityIsolationStatus\n//\n// parameters:\nfunc GetSecurityIsolationStatus() *GetSecurityIsolationStatusParams {\n\treturn &GetSecurityIsolationStatusParams{}\n}\n\n// WithFrameID if no frameId is provided, the status of the target is\n// provided.\nfunc (p GetSecurityIsolationStatusParams) WithFrameID(frameID cdp.FrameID) *GetSecurityIsolationStatusParams {\n\tp.FrameID = frameID\n\treturn &p\n}\n\n// GetSecurityIsolationStatusReturns return values.\ntype GetSecurityIsolationStatusReturns struct {\n\tStatus *SecurityIsolationStatus `json:\"status,omitempty,omitzero\"`\n}\n\n// Do executes Network.getSecurityIsolationStatus against the provided context.\n//\n// returns:\n//\n//\tstatus\nfunc (p *GetSecurityIsolationStatusParams) Do(ctx context.Context) (status *SecurityIsolationStatus, err error) {\n\t// execute\n\tvar res GetSecurityIsolationStatusReturns\n\terr = cdp.Execute(ctx, CommandGetSecurityIsolationStatus, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Status, nil\n}\n\n// EnableReportingAPIParams enables tracking for the Reporting API, events\n// generated by the Reporting API will now be delivered to the client. Enabling\n// triggers 'reportingApiReportAdded' for all existing reports.\ntype EnableReportingAPIParams struct {\n\tEnable bool `json:\"enable\"` // Whether to enable or disable events for the Reporting API\n}\n\n// EnableReportingAPI enables tracking for the Reporting API, events\n// generated by the Reporting API will now be delivered to the client. Enabling\n// triggers 'reportingApiReportAdded' for all existing reports.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-enableReportingApi\n//\n// parameters:\n//\n//\tenable - Whether to enable or disable events for the Reporting API\nfunc EnableReportingAPI(enable bool) *EnableReportingAPIParams {\n\treturn &EnableReportingAPIParams{\n\t\tEnable: enable,\n\t}\n}\n\n// Do executes Network.enableReportingApi against the provided context.\nfunc (p *EnableReportingAPIParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnableReportingAPI, p, nil)\n}\n\n// LoadNetworkResourceParams fetches the resource and returns the content.\ntype LoadNetworkResourceParams struct {\n\tFrameID cdp.FrameID                 `json:\"frameId,omitempty,omitzero\"` // Frame id to get the resource for. Mandatory for frame targets, and should be omitted for worker targets.\n\tURL     string                      `json:\"url\"`                        // URL of the resource to get content for.\n\tOptions *LoadNetworkResourceOptions `json:\"options\"`                    // Options for the request.\n}\n\n// LoadNetworkResource fetches the resource and returns the content.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-loadNetworkResource\n//\n// parameters:\n//\n//\turl - URL of the resource to get content for.\n//\toptions - Options for the request.\nfunc LoadNetworkResource(url string, options *LoadNetworkResourceOptions) *LoadNetworkResourceParams {\n\treturn &LoadNetworkResourceParams{\n\t\tURL:     url,\n\t\tOptions: options,\n\t}\n}\n\n// WithFrameID frame id to get the resource for. Mandatory for frame targets,\n// and should be omitted for worker targets.\nfunc (p LoadNetworkResourceParams) WithFrameID(frameID cdp.FrameID) *LoadNetworkResourceParams {\n\tp.FrameID = frameID\n\treturn &p\n}\n\n// LoadNetworkResourceReturns return values.\ntype LoadNetworkResourceReturns struct {\n\tResource *LoadNetworkResourcePageResult `json:\"resource,omitempty,omitzero\"`\n}\n\n// Do executes Network.loadNetworkResource against the provided context.\n//\n// returns:\n//\n//\tresource\nfunc (p *LoadNetworkResourceParams) Do(ctx context.Context) (resource *LoadNetworkResourcePageResult, err error) {\n\t// execute\n\tvar res LoadNetworkResourceReturns\n\terr = cdp.Execute(ctx, CommandLoadNetworkResource, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Resource, nil\n}\n\n// SetCookieControlsParams sets Controls for third-party cookie access Page\n// reload is required before the new cookie behavior will be observed.\ntype SetCookieControlsParams struct {\n\tEnableThirdPartyCookieRestriction bool `json:\"enableThirdPartyCookieRestriction\"` // Whether 3pc restriction is enabled.\n\tDisableThirdPartyCookieMetadata   bool `json:\"disableThirdPartyCookieMetadata\"`   // Whether 3pc grace period exception should be enabled; false by default.\n\tDisableThirdPartyCookieHeuristics bool `json:\"disableThirdPartyCookieHeuristics\"` // Whether 3pc heuristics exceptions should be enabled; false by default.\n}\n\n// SetCookieControls sets Controls for third-party cookie access Page reload\n// is required before the new cookie behavior will be observed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#method-setCookieControls\n//\n// parameters:\n//\n//\tenableThirdPartyCookieRestriction - Whether 3pc restriction is enabled.\n//\tdisableThirdPartyCookieMetadata - Whether 3pc grace period exception should be enabled; false by default.\n//\tdisableThirdPartyCookieHeuristics - Whether 3pc heuristics exceptions should be enabled; false by default.\nfunc SetCookieControls(enableThirdPartyCookieRestriction bool, disableThirdPartyCookieMetadata bool, disableThirdPartyCookieHeuristics bool) *SetCookieControlsParams {\n\treturn &SetCookieControlsParams{\n\t\tEnableThirdPartyCookieRestriction: enableThirdPartyCookieRestriction,\n\t\tDisableThirdPartyCookieMetadata:   disableThirdPartyCookieMetadata,\n\t\tDisableThirdPartyCookieHeuristics: disableThirdPartyCookieHeuristics,\n\t}\n}\n\n// Do executes Network.setCookieControls against the provided context.\nfunc (p *SetCookieControlsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCookieControls, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandSetAcceptedEncodings                    = \"Network.setAcceptedEncodings\"\n\tCommandClearAcceptedEncodingsOverride          = \"Network.clearAcceptedEncodingsOverride\"\n\tCommandClearBrowserCache                       = \"Network.clearBrowserCache\"\n\tCommandClearBrowserCookies                     = \"Network.clearBrowserCookies\"\n\tCommandDeleteCookies                           = \"Network.deleteCookies\"\n\tCommandDisable                                 = \"Network.disable\"\n\tCommandEmulateNetworkConditions                = \"Network.emulateNetworkConditions\"\n\tCommandEnable                                  = \"Network.enable\"\n\tCommandGetCertificate                          = \"Network.getCertificate\"\n\tCommandGetCookies                              = \"Network.getCookies\"\n\tCommandGetResponseBody                         = \"Network.getResponseBody\"\n\tCommandGetRequestPostData                      = \"Network.getRequestPostData\"\n\tCommandGetResponseBodyForInterception          = \"Network.getResponseBodyForInterception\"\n\tCommandTakeResponseBodyForInterceptionAsStream = \"Network.takeResponseBodyForInterceptionAsStream\"\n\tCommandReplayXHR                               = \"Network.replayXHR\"\n\tCommandSearchInResponseBody                    = \"Network.searchInResponseBody\"\n\tCommandSetBlockedURLs                          = \"Network.setBlockedURLs\"\n\tCommandSetBypassServiceWorker                  = \"Network.setBypassServiceWorker\"\n\tCommandSetCacheDisabled                        = \"Network.setCacheDisabled\"\n\tCommandSetCookie                               = \"Network.setCookie\"\n\tCommandSetCookies                              = \"Network.setCookies\"\n\tCommandSetExtraHTTPHeaders                     = \"Network.setExtraHTTPHeaders\"\n\tCommandSetAttachDebugStack                     = \"Network.setAttachDebugStack\"\n\tCommandStreamResourceContent                   = \"Network.streamResourceContent\"\n\tCommandGetSecurityIsolationStatus              = \"Network.getSecurityIsolationStatus\"\n\tCommandEnableReportingAPI                      = \"Network.enableReportingApi\"\n\tCommandLoadNetworkResource                     = \"Network.loadNetworkResource\"\n\tCommandSetCookieControls                       = \"Network.setCookieControls\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/network/types.go",
    "content": "package network\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/io\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/chromedp/cdproto/security\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// ResourceType resource type as it was perceived by the rendering engine.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ResourceType\ntype ResourceType string\n\n// String returns the ResourceType as string value.\nfunc (t ResourceType) String() string {\n\treturn string(t)\n}\n\n// ResourceType values.\nconst (\n\tResourceTypeDocument           ResourceType = \"Document\"\n\tResourceTypeStylesheet         ResourceType = \"Stylesheet\"\n\tResourceTypeImage              ResourceType = \"Image\"\n\tResourceTypeMedia              ResourceType = \"Media\"\n\tResourceTypeFont               ResourceType = \"Font\"\n\tResourceTypeScript             ResourceType = \"Script\"\n\tResourceTypeTextTrack          ResourceType = \"TextTrack\"\n\tResourceTypeXHR                ResourceType = \"XHR\"\n\tResourceTypeFetch              ResourceType = \"Fetch\"\n\tResourceTypePrefetch           ResourceType = \"Prefetch\"\n\tResourceTypeEventSource        ResourceType = \"EventSource\"\n\tResourceTypeWebSocket          ResourceType = \"WebSocket\"\n\tResourceTypeManifest           ResourceType = \"Manifest\"\n\tResourceTypeSignedExchange     ResourceType = \"SignedExchange\"\n\tResourceTypePing               ResourceType = \"Ping\"\n\tResourceTypeCSPViolationReport ResourceType = \"CSPViolationReport\"\n\tResourceTypePreflight          ResourceType = \"Preflight\"\n\tResourceTypeFedCM              ResourceType = \"FedCM\"\n\tResourceTypeOther              ResourceType = \"Other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ResourceType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ResourceType(s) {\n\tcase ResourceTypeDocument:\n\t\t*t = ResourceTypeDocument\n\tcase ResourceTypeStylesheet:\n\t\t*t = ResourceTypeStylesheet\n\tcase ResourceTypeImage:\n\t\t*t = ResourceTypeImage\n\tcase ResourceTypeMedia:\n\t\t*t = ResourceTypeMedia\n\tcase ResourceTypeFont:\n\t\t*t = ResourceTypeFont\n\tcase ResourceTypeScript:\n\t\t*t = ResourceTypeScript\n\tcase ResourceTypeTextTrack:\n\t\t*t = ResourceTypeTextTrack\n\tcase ResourceTypeXHR:\n\t\t*t = ResourceTypeXHR\n\tcase ResourceTypeFetch:\n\t\t*t = ResourceTypeFetch\n\tcase ResourceTypePrefetch:\n\t\t*t = ResourceTypePrefetch\n\tcase ResourceTypeEventSource:\n\t\t*t = ResourceTypeEventSource\n\tcase ResourceTypeWebSocket:\n\t\t*t = ResourceTypeWebSocket\n\tcase ResourceTypeManifest:\n\t\t*t = ResourceTypeManifest\n\tcase ResourceTypeSignedExchange:\n\t\t*t = ResourceTypeSignedExchange\n\tcase ResourceTypePing:\n\t\t*t = ResourceTypePing\n\tcase ResourceTypeCSPViolationReport:\n\t\t*t = ResourceTypeCSPViolationReport\n\tcase ResourceTypePreflight:\n\t\t*t = ResourceTypePreflight\n\tcase ResourceTypeFedCM:\n\t\t*t = ResourceTypeFedCM\n\tcase ResourceTypeOther:\n\t\t*t = ResourceTypeOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ResourceType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// RequestID unique network request identifier. Note that this does not\n// identify individual HTTP requests that are part of a network request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-RequestId\ntype RequestID string\n\n// String returns the RequestID as string value.\nfunc (t RequestID) String() string {\n\treturn string(t)\n}\n\n// InterceptionID unique intercepted request identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-InterceptionId\ntype InterceptionID string\n\n// String returns the InterceptionID as string value.\nfunc (t InterceptionID) String() string {\n\treturn string(t)\n}\n\n// ErrorReason network level fetch failure reason.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ErrorReason\ntype ErrorReason string\n\n// String returns the ErrorReason as string value.\nfunc (t ErrorReason) String() string {\n\treturn string(t)\n}\n\n// ErrorReason values.\nconst (\n\tErrorReasonFailed               ErrorReason = \"Failed\"\n\tErrorReasonAborted              ErrorReason = \"Aborted\"\n\tErrorReasonTimedOut             ErrorReason = \"TimedOut\"\n\tErrorReasonAccessDenied         ErrorReason = \"AccessDenied\"\n\tErrorReasonConnectionClosed     ErrorReason = \"ConnectionClosed\"\n\tErrorReasonConnectionReset      ErrorReason = \"ConnectionReset\"\n\tErrorReasonConnectionRefused    ErrorReason = \"ConnectionRefused\"\n\tErrorReasonConnectionAborted    ErrorReason = \"ConnectionAborted\"\n\tErrorReasonConnectionFailed     ErrorReason = \"ConnectionFailed\"\n\tErrorReasonNameNotResolved      ErrorReason = \"NameNotResolved\"\n\tErrorReasonInternetDisconnected ErrorReason = \"InternetDisconnected\"\n\tErrorReasonAddressUnreachable   ErrorReason = \"AddressUnreachable\"\n\tErrorReasonBlockedByClient      ErrorReason = \"BlockedByClient\"\n\tErrorReasonBlockedByResponse    ErrorReason = \"BlockedByResponse\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ErrorReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ErrorReason(s) {\n\tcase ErrorReasonFailed:\n\t\t*t = ErrorReasonFailed\n\tcase ErrorReasonAborted:\n\t\t*t = ErrorReasonAborted\n\tcase ErrorReasonTimedOut:\n\t\t*t = ErrorReasonTimedOut\n\tcase ErrorReasonAccessDenied:\n\t\t*t = ErrorReasonAccessDenied\n\tcase ErrorReasonConnectionClosed:\n\t\t*t = ErrorReasonConnectionClosed\n\tcase ErrorReasonConnectionReset:\n\t\t*t = ErrorReasonConnectionReset\n\tcase ErrorReasonConnectionRefused:\n\t\t*t = ErrorReasonConnectionRefused\n\tcase ErrorReasonConnectionAborted:\n\t\t*t = ErrorReasonConnectionAborted\n\tcase ErrorReasonConnectionFailed:\n\t\t*t = ErrorReasonConnectionFailed\n\tcase ErrorReasonNameNotResolved:\n\t\t*t = ErrorReasonNameNotResolved\n\tcase ErrorReasonInternetDisconnected:\n\t\t*t = ErrorReasonInternetDisconnected\n\tcase ErrorReasonAddressUnreachable:\n\t\t*t = ErrorReasonAddressUnreachable\n\tcase ErrorReasonBlockedByClient:\n\t\t*t = ErrorReasonBlockedByClient\n\tcase ErrorReasonBlockedByResponse:\n\t\t*t = ErrorReasonBlockedByResponse\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ErrorReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Headers request / response headers as keys / values of JSON object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-Headers\ntype Headers map[string]any\n\n// ConnectionType the underlying connection technology that the browser is\n// supposedly using.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ConnectionType\ntype ConnectionType string\n\n// String returns the ConnectionType as string value.\nfunc (t ConnectionType) String() string {\n\treturn string(t)\n}\n\n// ConnectionType values.\nconst (\n\tConnectionTypeNone       ConnectionType = \"none\"\n\tConnectionTypeCellular2g ConnectionType = \"cellular2g\"\n\tConnectionTypeCellular3g ConnectionType = \"cellular3g\"\n\tConnectionTypeCellular4g ConnectionType = \"cellular4g\"\n\tConnectionTypeBluetooth  ConnectionType = \"bluetooth\"\n\tConnectionTypeEthernet   ConnectionType = \"ethernet\"\n\tConnectionTypeWifi       ConnectionType = \"wifi\"\n\tConnectionTypeWimax      ConnectionType = \"wimax\"\n\tConnectionTypeOther      ConnectionType = \"other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ConnectionType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ConnectionType(s) {\n\tcase ConnectionTypeNone:\n\t\t*t = ConnectionTypeNone\n\tcase ConnectionTypeCellular2g:\n\t\t*t = ConnectionTypeCellular2g\n\tcase ConnectionTypeCellular3g:\n\t\t*t = ConnectionTypeCellular3g\n\tcase ConnectionTypeCellular4g:\n\t\t*t = ConnectionTypeCellular4g\n\tcase ConnectionTypeBluetooth:\n\t\t*t = ConnectionTypeBluetooth\n\tcase ConnectionTypeEthernet:\n\t\t*t = ConnectionTypeEthernet\n\tcase ConnectionTypeWifi:\n\t\t*t = ConnectionTypeWifi\n\tcase ConnectionTypeWimax:\n\t\t*t = ConnectionTypeWimax\n\tcase ConnectionTypeOther:\n\t\t*t = ConnectionTypeOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ConnectionType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookieSameSite represents the cookie's 'SameSite' status:\n// https://tools.ietf.org/html/draft-west-first-party-cookies.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CookieSameSite\ntype CookieSameSite string\n\n// String returns the CookieSameSite as string value.\nfunc (t CookieSameSite) String() string {\n\treturn string(t)\n}\n\n// CookieSameSite values.\nconst (\n\tCookieSameSiteStrict CookieSameSite = \"Strict\"\n\tCookieSameSiteLax    CookieSameSite = \"Lax\"\n\tCookieSameSiteNone   CookieSameSite = \"None\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookieSameSite) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookieSameSite(s) {\n\tcase CookieSameSiteStrict:\n\t\t*t = CookieSameSiteStrict\n\tcase CookieSameSiteLax:\n\t\t*t = CookieSameSiteLax\n\tcase CookieSameSiteNone:\n\t\t*t = CookieSameSiteNone\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookieSameSite value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookiePriority represents the cookie's 'Priority' status:\n// https://tools.ietf.org/html/draft-west-cookie-priority-00.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CookiePriority\ntype CookiePriority string\n\n// String returns the CookiePriority as string value.\nfunc (t CookiePriority) String() string {\n\treturn string(t)\n}\n\n// CookiePriority values.\nconst (\n\tCookiePriorityLow    CookiePriority = \"Low\"\n\tCookiePriorityMedium CookiePriority = \"Medium\"\n\tCookiePriorityHigh   CookiePriority = \"High\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookiePriority) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookiePriority(s) {\n\tcase CookiePriorityLow:\n\t\t*t = CookiePriorityLow\n\tcase CookiePriorityMedium:\n\t\t*t = CookiePriorityMedium\n\tcase CookiePriorityHigh:\n\t\t*t = CookiePriorityHigh\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookiePriority value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookieSourceScheme represents the source scheme of the origin that\n// originally set the cookie. A value of \"Unset\" allows protocol clients to\n// emulate legacy cookie scope for the scheme. This is a temporary ability and\n// it will be removed in the future.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CookieSourceScheme\ntype CookieSourceScheme string\n\n// String returns the CookieSourceScheme as string value.\nfunc (t CookieSourceScheme) String() string {\n\treturn string(t)\n}\n\n// CookieSourceScheme values.\nconst (\n\tCookieSourceSchemeUnset     CookieSourceScheme = \"Unset\"\n\tCookieSourceSchemeNonSecure CookieSourceScheme = \"NonSecure\"\n\tCookieSourceSchemeSecure    CookieSourceScheme = \"Secure\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookieSourceScheme) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookieSourceScheme(s) {\n\tcase CookieSourceSchemeUnset:\n\t\t*t = CookieSourceSchemeUnset\n\tcase CookieSourceSchemeNonSecure:\n\t\t*t = CookieSourceSchemeNonSecure\n\tcase CookieSourceSchemeSecure:\n\t\t*t = CookieSourceSchemeSecure\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookieSourceScheme value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ResourceTiming timing information for the request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ResourceTiming\ntype ResourceTiming struct {\n\tRequestTime                 float64 `json:\"requestTime\"`                                    // Timing's requestTime is a baseline in seconds, while the other numbers are ticks in milliseconds relatively to this requestTime.\n\tProxyStart                  float64 `json:\"proxyStart\"`                                     // Started resolving proxy.\n\tProxyEnd                    float64 `json:\"proxyEnd\"`                                       // Finished resolving proxy.\n\tDNSStart                    float64 `json:\"dnsStart\"`                                       // Started DNS address resolve.\n\tDNSEnd                      float64 `json:\"dnsEnd\"`                                         // Finished DNS address resolve.\n\tConnectStart                float64 `json:\"connectStart\"`                                   // Started connecting to the remote host.\n\tConnectEnd                  float64 `json:\"connectEnd\"`                                     // Connected to the remote host.\n\tSslStart                    float64 `json:\"sslStart\"`                                       // Started SSL handshake.\n\tSslEnd                      float64 `json:\"sslEnd\"`                                         // Finished SSL handshake.\n\tWorkerStart                 float64 `json:\"workerStart\"`                                    // Started running ServiceWorker.\n\tWorkerReady                 float64 `json:\"workerReady\"`                                    // Finished Starting ServiceWorker.\n\tWorkerFetchStart            float64 `json:\"workerFetchStart\"`                               // Started fetch event.\n\tWorkerRespondWithSettled    float64 `json:\"workerRespondWithSettled\"`                       // Settled fetch event respondWith promise.\n\tWorkerRouterEvaluationStart float64 `json:\"workerRouterEvaluationStart,omitempty,omitzero\"` // Started ServiceWorker static routing source evaluation.\n\tWorkerCacheLookupStart      float64 `json:\"workerCacheLookupStart,omitempty,omitzero\"`      // Started cache lookup when the source was evaluated to cache.\n\tSendStart                   float64 `json:\"sendStart\"`                                      // Started sending request.\n\tSendEnd                     float64 `json:\"sendEnd\"`                                        // Finished sending request.\n\tPushStart                   float64 `json:\"pushStart\"`                                      // Time the server started pushing request.\n\tPushEnd                     float64 `json:\"pushEnd\"`                                        // Time the server finished pushing request.\n\tReceiveHeadersStart         float64 `json:\"receiveHeadersStart\"`                            // Started receiving response headers.\n\tReceiveHeadersEnd           float64 `json:\"receiveHeadersEnd\"`                              // Finished receiving response headers.\n}\n\n// ResourcePriority loading priority of a resource request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ResourcePriority\ntype ResourcePriority string\n\n// String returns the ResourcePriority as string value.\nfunc (t ResourcePriority) String() string {\n\treturn string(t)\n}\n\n// ResourcePriority values.\nconst (\n\tResourcePriorityVeryLow  ResourcePriority = \"VeryLow\"\n\tResourcePriorityLow      ResourcePriority = \"Low\"\n\tResourcePriorityMedium   ResourcePriority = \"Medium\"\n\tResourcePriorityHigh     ResourcePriority = \"High\"\n\tResourcePriorityVeryHigh ResourcePriority = \"VeryHigh\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ResourcePriority) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ResourcePriority(s) {\n\tcase ResourcePriorityVeryLow:\n\t\t*t = ResourcePriorityVeryLow\n\tcase ResourcePriorityLow:\n\t\t*t = ResourcePriorityLow\n\tcase ResourcePriorityMedium:\n\t\t*t = ResourcePriorityMedium\n\tcase ResourcePriorityHigh:\n\t\t*t = ResourcePriorityHigh\n\tcase ResourcePriorityVeryHigh:\n\t\t*t = ResourcePriorityVeryHigh\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ResourcePriority value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PostDataEntry post data entry for HTTP request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-PostDataEntry\ntype PostDataEntry struct {\n\tBytes string `json:\"bytes,omitempty,omitzero\"`\n}\n\n// Request HTTP request data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-Request\ntype Request struct {\n\tURL              string                    `json:\"url\"`                                 // Request URL (without fragment).\n\tURLFragment      string                    `json:\"urlFragment,omitempty,omitzero\"`      // Fragment of the requested URL starting with hash, if present.\n\tMethod           string                    `json:\"method\"`                              // HTTP request method.\n\tHeaders          Headers                   `json:\"headers\"`                             // HTTP request headers.\n\tHasPostData      bool                      `json:\"hasPostData\"`                         // True when the request has POST data. Note that postData might still be omitted when this flag is true when the data is too long.\n\tPostDataEntries  []*PostDataEntry          `json:\"postDataEntries,omitempty,omitzero\"`  // Request body elements (post data broken into individual entries).\n\tMixedContentType security.MixedContentType `json:\"mixedContentType,omitempty,omitzero\"` // The mixed content type of the request.\n\tInitialPriority  ResourcePriority          `json:\"initialPriority\"`                     // Priority of the resource request at the time request is sent.\n\tReferrerPolicy   ReferrerPolicy            `json:\"referrerPolicy\"`                      // The referrer policy of the request, as defined in https://www.w3.org/TR/referrer-policy/\n\tIsLinkPreload    bool                      `json:\"isLinkPreload\"`                       // Whether is loaded via link preload.\n\tTrustTokenParams *TrustTokenParams         `json:\"trustTokenParams,omitempty,omitzero\"` // Set for requests when the TrustToken API is used. Contains the parameters passed by the developer (e.g. via \"fetch\") as understood by the backend.\n\tIsSameSite       bool                      `json:\"isSameSite\"`                          // True if this resource request is considered to be the 'same site' as the request corresponding to the main frame.\n}\n\n// SignedCertificateTimestamp details of a signed certificate timestamp\n// (SCT).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SignedCertificateTimestamp\ntype SignedCertificateTimestamp struct {\n\tStatus             string  `json:\"status\"`             // Validation status.\n\tOrigin             string  `json:\"origin\"`             // Origin.\n\tLogDescription     string  `json:\"logDescription\"`     // Log name / description.\n\tLogID              string  `json:\"logId\"`              // Log ID.\n\tTimestamp          float64 `json:\"timestamp\"`          // Issuance date. Unlike TimeSinceEpoch, this contains the number of milliseconds since January 1, 1970, UTC, not the number of seconds.\n\tHashAlgorithm      string  `json:\"hashAlgorithm\"`      // Hash algorithm.\n\tSignatureAlgorithm string  `json:\"signatureAlgorithm\"` // Signature algorithm.\n\tSignatureData      string  `json:\"signatureData\"`      // Signature data.\n}\n\n// SecurityDetails security details about a request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SecurityDetails\ntype SecurityDetails struct {\n\tProtocol                          string                            `json:\"protocol\"`                                    // Protocol name (e.g. \"TLS 1.2\" or \"QUIC\").\n\tKeyExchange                       string                            `json:\"keyExchange\"`                                 // Key Exchange used by the connection, or the empty string if not applicable.\n\tKeyExchangeGroup                  string                            `json:\"keyExchangeGroup,omitempty,omitzero\"`         // (EC)DH group used by the connection, if applicable.\n\tCipher                            string                            `json:\"cipher\"`                                      // Cipher name.\n\tMac                               string                            `json:\"mac,omitempty,omitzero\"`                      // TLS MAC. Note that AEAD ciphers do not have separate MACs.\n\tCertificateID                     security.CertificateID            `json:\"certificateId\"`                               // Certificate ID value.\n\tSubjectName                       string                            `json:\"subjectName\"`                                 // Certificate subject name.\n\tSanList                           []string                          `json:\"sanList\"`                                     // Subject Alternative Name (SAN) DNS names and IP addresses.\n\tIssuer                            string                            `json:\"issuer\"`                                      // Name of the issuing CA.\n\tValidFrom                         *cdp.TimeSinceEpoch               `json:\"validFrom\"`                                   // Certificate valid from date.\n\tValidTo                           *cdp.TimeSinceEpoch               `json:\"validTo\"`                                     // Certificate valid to (expiration) date\n\tSignedCertificateTimestampList    []*SignedCertificateTimestamp     `json:\"signedCertificateTimestampList\"`              // List of signed certificate timestamps (SCTs).\n\tCertificateTransparencyCompliance CertificateTransparencyCompliance `json:\"certificateTransparencyCompliance\"`           // Whether the request complied with Certificate Transparency policy\n\tServerSignatureAlgorithm          int64                             `json:\"serverSignatureAlgorithm,omitempty,omitzero\"` // The signature algorithm used by the server in the TLS server signature, represented as a TLS SignatureScheme code point. Omitted if not applicable or not known.\n\tEncryptedClientHello              bool                              `json:\"encryptedClientHello\"`                        // Whether the connection used Encrypted ClientHello\n}\n\n// CertificateTransparencyCompliance whether the request complied with\n// Certificate Transparency policy.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CertificateTransparencyCompliance\ntype CertificateTransparencyCompliance string\n\n// String returns the CertificateTransparencyCompliance as string value.\nfunc (t CertificateTransparencyCompliance) String() string {\n\treturn string(t)\n}\n\n// CertificateTransparencyCompliance values.\nconst (\n\tCertificateTransparencyComplianceUnknown      CertificateTransparencyCompliance = \"unknown\"\n\tCertificateTransparencyComplianceNotCompliant CertificateTransparencyCompliance = \"not-compliant\"\n\tCertificateTransparencyComplianceCompliant    CertificateTransparencyCompliance = \"compliant\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CertificateTransparencyCompliance) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CertificateTransparencyCompliance(s) {\n\tcase CertificateTransparencyComplianceUnknown:\n\t\t*t = CertificateTransparencyComplianceUnknown\n\tcase CertificateTransparencyComplianceNotCompliant:\n\t\t*t = CertificateTransparencyComplianceNotCompliant\n\tcase CertificateTransparencyComplianceCompliant:\n\t\t*t = CertificateTransparencyComplianceCompliant\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CertificateTransparencyCompliance value: %v\", s)\n\t}\n\treturn nil\n}\n\n// BlockedReason the reason why request was blocked.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-BlockedReason\ntype BlockedReason string\n\n// String returns the BlockedReason as string value.\nfunc (t BlockedReason) String() string {\n\treturn string(t)\n}\n\n// BlockedReason values.\nconst (\n\tBlockedReasonOther                                                   BlockedReason = \"other\"\n\tBlockedReasonCsp                                                     BlockedReason = \"csp\"\n\tBlockedReasonMixedContent                                            BlockedReason = \"mixed-content\"\n\tBlockedReasonOrigin                                                  BlockedReason = \"origin\"\n\tBlockedReasonInspector                                               BlockedReason = \"inspector\"\n\tBlockedReasonIntegrity                                               BlockedReason = \"integrity\"\n\tBlockedReasonSubresourceFilter                                       BlockedReason = \"subresource-filter\"\n\tBlockedReasonContentType                                             BlockedReason = \"content-type\"\n\tBlockedReasonCoepFrameResourceNeedsCoepHeader                        BlockedReason = \"coep-frame-resource-needs-coep-header\"\n\tBlockedReasonCoopSandboxedIframeCannotNavigateToCoopPage             BlockedReason = \"coop-sandboxed-iframe-cannot-navigate-to-coop-page\"\n\tBlockedReasonCorpNotSameOrigin                                       BlockedReason = \"corp-not-same-origin\"\n\tBlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoep       BlockedReason = \"corp-not-same-origin-after-defaulted-to-same-origin-by-coep\"\n\tBlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByDip        BlockedReason = \"corp-not-same-origin-after-defaulted-to-same-origin-by-dip\"\n\tBlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip BlockedReason = \"corp-not-same-origin-after-defaulted-to-same-origin-by-coep-and-dip\"\n\tBlockedReasonCorpNotSameSite                                         BlockedReason = \"corp-not-same-site\"\n\tBlockedReasonSriMessageSignatureMismatch                             BlockedReason = \"sri-message-signature-mismatch\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *BlockedReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch BlockedReason(s) {\n\tcase BlockedReasonOther:\n\t\t*t = BlockedReasonOther\n\tcase BlockedReasonCsp:\n\t\t*t = BlockedReasonCsp\n\tcase BlockedReasonMixedContent:\n\t\t*t = BlockedReasonMixedContent\n\tcase BlockedReasonOrigin:\n\t\t*t = BlockedReasonOrigin\n\tcase BlockedReasonInspector:\n\t\t*t = BlockedReasonInspector\n\tcase BlockedReasonIntegrity:\n\t\t*t = BlockedReasonIntegrity\n\tcase BlockedReasonSubresourceFilter:\n\t\t*t = BlockedReasonSubresourceFilter\n\tcase BlockedReasonContentType:\n\t\t*t = BlockedReasonContentType\n\tcase BlockedReasonCoepFrameResourceNeedsCoepHeader:\n\t\t*t = BlockedReasonCoepFrameResourceNeedsCoepHeader\n\tcase BlockedReasonCoopSandboxedIframeCannotNavigateToCoopPage:\n\t\t*t = BlockedReasonCoopSandboxedIframeCannotNavigateToCoopPage\n\tcase BlockedReasonCorpNotSameOrigin:\n\t\t*t = BlockedReasonCorpNotSameOrigin\n\tcase BlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoep:\n\t\t*t = BlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoep\n\tcase BlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByDip:\n\t\t*t = BlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByDip\n\tcase BlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip:\n\t\t*t = BlockedReasonCorpNotSameOriginAfterDefaultedToSameOriginByCoepAndDip\n\tcase BlockedReasonCorpNotSameSite:\n\t\t*t = BlockedReasonCorpNotSameSite\n\tcase BlockedReasonSriMessageSignatureMismatch:\n\t\t*t = BlockedReasonSriMessageSignatureMismatch\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown BlockedReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CorsError the reason why request was blocked.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CorsError\ntype CorsError string\n\n// String returns the CorsError as string value.\nfunc (t CorsError) String() string {\n\treturn string(t)\n}\n\n// CorsError values.\nconst (\n\tCorsErrorDisallowedByMode                          CorsError = \"DisallowedByMode\"\n\tCorsErrorInvalidResponse                           CorsError = \"InvalidResponse\"\n\tCorsErrorWildcardOriginNotAllowed                  CorsError = \"WildcardOriginNotAllowed\"\n\tCorsErrorMissingAllowOriginHeader                  CorsError = \"MissingAllowOriginHeader\"\n\tCorsErrorMultipleAllowOriginValues                 CorsError = \"MultipleAllowOriginValues\"\n\tCorsErrorInvalidAllowOriginValue                   CorsError = \"InvalidAllowOriginValue\"\n\tCorsErrorAllowOriginMismatch                       CorsError = \"AllowOriginMismatch\"\n\tCorsErrorInvalidAllowCredentials                   CorsError = \"InvalidAllowCredentials\"\n\tCorsErrorCorsDisabledScheme                        CorsError = \"CorsDisabledScheme\"\n\tCorsErrorPreflightInvalidStatus                    CorsError = \"PreflightInvalidStatus\"\n\tCorsErrorPreflightDisallowedRedirect               CorsError = \"PreflightDisallowedRedirect\"\n\tCorsErrorPreflightWildcardOriginNotAllowed         CorsError = \"PreflightWildcardOriginNotAllowed\"\n\tCorsErrorPreflightMissingAllowOriginHeader         CorsError = \"PreflightMissingAllowOriginHeader\"\n\tCorsErrorPreflightMultipleAllowOriginValues        CorsError = \"PreflightMultipleAllowOriginValues\"\n\tCorsErrorPreflightInvalidAllowOriginValue          CorsError = \"PreflightInvalidAllowOriginValue\"\n\tCorsErrorPreflightAllowOriginMismatch              CorsError = \"PreflightAllowOriginMismatch\"\n\tCorsErrorPreflightInvalidAllowCredentials          CorsError = \"PreflightInvalidAllowCredentials\"\n\tCorsErrorPreflightMissingAllowExternal             CorsError = \"PreflightMissingAllowExternal\"\n\tCorsErrorPreflightInvalidAllowExternal             CorsError = \"PreflightInvalidAllowExternal\"\n\tCorsErrorPreflightMissingAllowPrivateNetwork       CorsError = \"PreflightMissingAllowPrivateNetwork\"\n\tCorsErrorPreflightInvalidAllowPrivateNetwork       CorsError = \"PreflightInvalidAllowPrivateNetwork\"\n\tCorsErrorInvalidAllowMethodsPreflightResponse      CorsError = \"InvalidAllowMethodsPreflightResponse\"\n\tCorsErrorInvalidAllowHeadersPreflightResponse      CorsError = \"InvalidAllowHeadersPreflightResponse\"\n\tCorsErrorMethodDisallowedByPreflightResponse       CorsError = \"MethodDisallowedByPreflightResponse\"\n\tCorsErrorHeaderDisallowedByPreflightResponse       CorsError = \"HeaderDisallowedByPreflightResponse\"\n\tCorsErrorRedirectContainsCredentials               CorsError = \"RedirectContainsCredentials\"\n\tCorsErrorInsecurePrivateNetwork                    CorsError = \"InsecurePrivateNetwork\"\n\tCorsErrorInvalidPrivateNetworkAccess               CorsError = \"InvalidPrivateNetworkAccess\"\n\tCorsErrorUnexpectedPrivateNetworkAccess            CorsError = \"UnexpectedPrivateNetworkAccess\"\n\tCorsErrorNoCorsRedirectModeNotFollow               CorsError = \"NoCorsRedirectModeNotFollow\"\n\tCorsErrorPreflightMissingPrivateNetworkAccessID    CorsError = \"PreflightMissingPrivateNetworkAccessId\"\n\tCorsErrorPreflightMissingPrivateNetworkAccessName  CorsError = \"PreflightMissingPrivateNetworkAccessName\"\n\tCorsErrorPrivateNetworkAccessPermissionUnavailable CorsError = \"PrivateNetworkAccessPermissionUnavailable\"\n\tCorsErrorPrivateNetworkAccessPermissionDenied      CorsError = \"PrivateNetworkAccessPermissionDenied\"\n\tCorsErrorLocalNetworkAccessPermissionDenied        CorsError = \"LocalNetworkAccessPermissionDenied\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CorsError) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CorsError(s) {\n\tcase CorsErrorDisallowedByMode:\n\t\t*t = CorsErrorDisallowedByMode\n\tcase CorsErrorInvalidResponse:\n\t\t*t = CorsErrorInvalidResponse\n\tcase CorsErrorWildcardOriginNotAllowed:\n\t\t*t = CorsErrorWildcardOriginNotAllowed\n\tcase CorsErrorMissingAllowOriginHeader:\n\t\t*t = CorsErrorMissingAllowOriginHeader\n\tcase CorsErrorMultipleAllowOriginValues:\n\t\t*t = CorsErrorMultipleAllowOriginValues\n\tcase CorsErrorInvalidAllowOriginValue:\n\t\t*t = CorsErrorInvalidAllowOriginValue\n\tcase CorsErrorAllowOriginMismatch:\n\t\t*t = CorsErrorAllowOriginMismatch\n\tcase CorsErrorInvalidAllowCredentials:\n\t\t*t = CorsErrorInvalidAllowCredentials\n\tcase CorsErrorCorsDisabledScheme:\n\t\t*t = CorsErrorCorsDisabledScheme\n\tcase CorsErrorPreflightInvalidStatus:\n\t\t*t = CorsErrorPreflightInvalidStatus\n\tcase CorsErrorPreflightDisallowedRedirect:\n\t\t*t = CorsErrorPreflightDisallowedRedirect\n\tcase CorsErrorPreflightWildcardOriginNotAllowed:\n\t\t*t = CorsErrorPreflightWildcardOriginNotAllowed\n\tcase CorsErrorPreflightMissingAllowOriginHeader:\n\t\t*t = CorsErrorPreflightMissingAllowOriginHeader\n\tcase CorsErrorPreflightMultipleAllowOriginValues:\n\t\t*t = CorsErrorPreflightMultipleAllowOriginValues\n\tcase CorsErrorPreflightInvalidAllowOriginValue:\n\t\t*t = CorsErrorPreflightInvalidAllowOriginValue\n\tcase CorsErrorPreflightAllowOriginMismatch:\n\t\t*t = CorsErrorPreflightAllowOriginMismatch\n\tcase CorsErrorPreflightInvalidAllowCredentials:\n\t\t*t = CorsErrorPreflightInvalidAllowCredentials\n\tcase CorsErrorPreflightMissingAllowExternal:\n\t\t*t = CorsErrorPreflightMissingAllowExternal\n\tcase CorsErrorPreflightInvalidAllowExternal:\n\t\t*t = CorsErrorPreflightInvalidAllowExternal\n\tcase CorsErrorPreflightMissingAllowPrivateNetwork:\n\t\t*t = CorsErrorPreflightMissingAllowPrivateNetwork\n\tcase CorsErrorPreflightInvalidAllowPrivateNetwork:\n\t\t*t = CorsErrorPreflightInvalidAllowPrivateNetwork\n\tcase CorsErrorInvalidAllowMethodsPreflightResponse:\n\t\t*t = CorsErrorInvalidAllowMethodsPreflightResponse\n\tcase CorsErrorInvalidAllowHeadersPreflightResponse:\n\t\t*t = CorsErrorInvalidAllowHeadersPreflightResponse\n\tcase CorsErrorMethodDisallowedByPreflightResponse:\n\t\t*t = CorsErrorMethodDisallowedByPreflightResponse\n\tcase CorsErrorHeaderDisallowedByPreflightResponse:\n\t\t*t = CorsErrorHeaderDisallowedByPreflightResponse\n\tcase CorsErrorRedirectContainsCredentials:\n\t\t*t = CorsErrorRedirectContainsCredentials\n\tcase CorsErrorInsecurePrivateNetwork:\n\t\t*t = CorsErrorInsecurePrivateNetwork\n\tcase CorsErrorInvalidPrivateNetworkAccess:\n\t\t*t = CorsErrorInvalidPrivateNetworkAccess\n\tcase CorsErrorUnexpectedPrivateNetworkAccess:\n\t\t*t = CorsErrorUnexpectedPrivateNetworkAccess\n\tcase CorsErrorNoCorsRedirectModeNotFollow:\n\t\t*t = CorsErrorNoCorsRedirectModeNotFollow\n\tcase CorsErrorPreflightMissingPrivateNetworkAccessID:\n\t\t*t = CorsErrorPreflightMissingPrivateNetworkAccessID\n\tcase CorsErrorPreflightMissingPrivateNetworkAccessName:\n\t\t*t = CorsErrorPreflightMissingPrivateNetworkAccessName\n\tcase CorsErrorPrivateNetworkAccessPermissionUnavailable:\n\t\t*t = CorsErrorPrivateNetworkAccessPermissionUnavailable\n\tcase CorsErrorPrivateNetworkAccessPermissionDenied:\n\t\t*t = CorsErrorPrivateNetworkAccessPermissionDenied\n\tcase CorsErrorLocalNetworkAccessPermissionDenied:\n\t\t*t = CorsErrorLocalNetworkAccessPermissionDenied\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CorsError value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CorsErrorStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CorsErrorStatus\ntype CorsErrorStatus struct {\n\tCorsError       CorsError `json:\"corsError\"`\n\tFailedParameter string    `json:\"failedParameter\"`\n}\n\n// ServiceWorkerResponseSource source of serviceworker response.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ServiceWorkerResponseSource\ntype ServiceWorkerResponseSource string\n\n// String returns the ServiceWorkerResponseSource as string value.\nfunc (t ServiceWorkerResponseSource) String() string {\n\treturn string(t)\n}\n\n// ServiceWorkerResponseSource values.\nconst (\n\tServiceWorkerResponseSourceCacheStorage ServiceWorkerResponseSource = \"cache-storage\"\n\tServiceWorkerResponseSourceHTTPCache    ServiceWorkerResponseSource = \"http-cache\"\n\tServiceWorkerResponseSourceFallbackCode ServiceWorkerResponseSource = \"fallback-code\"\n\tServiceWorkerResponseSourceNetwork      ServiceWorkerResponseSource = \"network\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ServiceWorkerResponseSource) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ServiceWorkerResponseSource(s) {\n\tcase ServiceWorkerResponseSourceCacheStorage:\n\t\t*t = ServiceWorkerResponseSourceCacheStorage\n\tcase ServiceWorkerResponseSourceHTTPCache:\n\t\t*t = ServiceWorkerResponseSourceHTTPCache\n\tcase ServiceWorkerResponseSourceFallbackCode:\n\t\t*t = ServiceWorkerResponseSourceFallbackCode\n\tcase ServiceWorkerResponseSourceNetwork:\n\t\t*t = ServiceWorkerResponseSourceNetwork\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ServiceWorkerResponseSource value: %v\", s)\n\t}\n\treturn nil\n}\n\n// TrustTokenParams determines what type of Trust Token operation is executed\n// and depending on the type, some additional parameters. The values are\n// specified in third_party/blink/renderer/core/fetch/trust_token.idl.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-TrustTokenParams\ntype TrustTokenParams struct {\n\tOperation     TrustTokenOperationType       `json:\"operation\"`\n\tRefreshPolicy TrustTokenParamsRefreshPolicy `json:\"refreshPolicy\"`              // Only set for \"token-redemption\" operation and determine whether to request a fresh SRR or use a still valid cached SRR.\n\tIssuers       []string                      `json:\"issuers,omitempty,omitzero\"` // Origins of issuers from whom to request tokens or redemption records.\n}\n\n// TrustTokenOperationType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-TrustTokenOperationType\ntype TrustTokenOperationType string\n\n// String returns the TrustTokenOperationType as string value.\nfunc (t TrustTokenOperationType) String() string {\n\treturn string(t)\n}\n\n// TrustTokenOperationType values.\nconst (\n\tTrustTokenOperationTypeIssuance   TrustTokenOperationType = \"Issuance\"\n\tTrustTokenOperationTypeRedemption TrustTokenOperationType = \"Redemption\"\n\tTrustTokenOperationTypeSigning    TrustTokenOperationType = \"Signing\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TrustTokenOperationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch TrustTokenOperationType(s) {\n\tcase TrustTokenOperationTypeIssuance:\n\t\t*t = TrustTokenOperationTypeIssuance\n\tcase TrustTokenOperationTypeRedemption:\n\t\t*t = TrustTokenOperationTypeRedemption\n\tcase TrustTokenOperationTypeSigning:\n\t\t*t = TrustTokenOperationTypeSigning\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown TrustTokenOperationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AlternateProtocolUsage the reason why Chrome uses a specific transport\n// protocol for HTTP semantics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-AlternateProtocolUsage\ntype AlternateProtocolUsage string\n\n// String returns the AlternateProtocolUsage as string value.\nfunc (t AlternateProtocolUsage) String() string {\n\treturn string(t)\n}\n\n// AlternateProtocolUsage values.\nconst (\n\tAlternateProtocolUsageAlternativeJobWonWithoutRace AlternateProtocolUsage = \"alternativeJobWonWithoutRace\"\n\tAlternateProtocolUsageAlternativeJobWonRace        AlternateProtocolUsage = \"alternativeJobWonRace\"\n\tAlternateProtocolUsageMainJobWonRace               AlternateProtocolUsage = \"mainJobWonRace\"\n\tAlternateProtocolUsageMappingMissing               AlternateProtocolUsage = \"mappingMissing\"\n\tAlternateProtocolUsageBroken                       AlternateProtocolUsage = \"broken\"\n\tAlternateProtocolUsageDNSAlpnH3jobWonWithoutRace   AlternateProtocolUsage = \"dnsAlpnH3JobWonWithoutRace\"\n\tAlternateProtocolUsageDNSAlpnH3jobWonRace          AlternateProtocolUsage = \"dnsAlpnH3JobWonRace\"\n\tAlternateProtocolUsageUnspecifiedReason            AlternateProtocolUsage = \"unspecifiedReason\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AlternateProtocolUsage) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AlternateProtocolUsage(s) {\n\tcase AlternateProtocolUsageAlternativeJobWonWithoutRace:\n\t\t*t = AlternateProtocolUsageAlternativeJobWonWithoutRace\n\tcase AlternateProtocolUsageAlternativeJobWonRace:\n\t\t*t = AlternateProtocolUsageAlternativeJobWonRace\n\tcase AlternateProtocolUsageMainJobWonRace:\n\t\t*t = AlternateProtocolUsageMainJobWonRace\n\tcase AlternateProtocolUsageMappingMissing:\n\t\t*t = AlternateProtocolUsageMappingMissing\n\tcase AlternateProtocolUsageBroken:\n\t\t*t = AlternateProtocolUsageBroken\n\tcase AlternateProtocolUsageDNSAlpnH3jobWonWithoutRace:\n\t\t*t = AlternateProtocolUsageDNSAlpnH3jobWonWithoutRace\n\tcase AlternateProtocolUsageDNSAlpnH3jobWonRace:\n\t\t*t = AlternateProtocolUsageDNSAlpnH3jobWonRace\n\tcase AlternateProtocolUsageUnspecifiedReason:\n\t\t*t = AlternateProtocolUsageUnspecifiedReason\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AlternateProtocolUsage value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ServiceWorkerRouterSource source of service worker router.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ServiceWorkerRouterSource\ntype ServiceWorkerRouterSource string\n\n// String returns the ServiceWorkerRouterSource as string value.\nfunc (t ServiceWorkerRouterSource) String() string {\n\treturn string(t)\n}\n\n// ServiceWorkerRouterSource values.\nconst (\n\tServiceWorkerRouterSourceNetwork                    ServiceWorkerRouterSource = \"network\"\n\tServiceWorkerRouterSourceCache                      ServiceWorkerRouterSource = \"cache\"\n\tServiceWorkerRouterSourceFetchEvent                 ServiceWorkerRouterSource = \"fetch-event\"\n\tServiceWorkerRouterSourceRaceNetworkAndFetchHandler ServiceWorkerRouterSource = \"race-network-and-fetch-handler\"\n\tServiceWorkerRouterSourceRaceNetworkAndCache        ServiceWorkerRouterSource = \"race-network-and-cache\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ServiceWorkerRouterSource) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ServiceWorkerRouterSource(s) {\n\tcase ServiceWorkerRouterSourceNetwork:\n\t\t*t = ServiceWorkerRouterSourceNetwork\n\tcase ServiceWorkerRouterSourceCache:\n\t\t*t = ServiceWorkerRouterSourceCache\n\tcase ServiceWorkerRouterSourceFetchEvent:\n\t\t*t = ServiceWorkerRouterSourceFetchEvent\n\tcase ServiceWorkerRouterSourceRaceNetworkAndFetchHandler:\n\t\t*t = ServiceWorkerRouterSourceRaceNetworkAndFetchHandler\n\tcase ServiceWorkerRouterSourceRaceNetworkAndCache:\n\t\t*t = ServiceWorkerRouterSourceRaceNetworkAndCache\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ServiceWorkerRouterSource value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ServiceWorkerRouterInfo [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ServiceWorkerRouterInfo\ntype ServiceWorkerRouterInfo struct {\n\tRuleIDMatched     int64                     `json:\"ruleIdMatched,omitempty,omitzero\"`     // ID of the rule matched. If there is a matched rule, this field will be set, otherwiser no value will be set.\n\tMatchedSourceType ServiceWorkerRouterSource `json:\"matchedSourceType,omitempty,omitzero\"` // The router source of the matched rule. If there is a matched rule, this field will be set, otherwise no value will be set.\n\tActualSourceType  ServiceWorkerRouterSource `json:\"actualSourceType,omitempty,omitzero\"`  // The actual router source used.\n}\n\n// Response HTTP response data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-Response\ntype Response struct {\n\tURL                         string                      `json:\"url\"`                                            // Response URL. This URL can be different from CachedResource.url in case of redirect.\n\tStatus                      int64                       `json:\"status\"`                                         // HTTP response status code.\n\tStatusText                  string                      `json:\"statusText\"`                                     // HTTP response status text.\n\tHeaders                     Headers                     `json:\"headers\"`                                        // HTTP response headers.\n\tMimeType                    string                      `json:\"mimeType\"`                                       // Resource mimeType as determined by the browser.\n\tCharset                     string                      `json:\"charset\"`                                        // Resource charset as determined by the browser (if applicable).\n\tRequestHeaders              Headers                     `json:\"requestHeaders,omitempty,omitzero\"`              // Refined HTTP request headers that were actually transmitted over the network.\n\tConnectionReused            bool                        `json:\"connectionReused\"`                               // Specifies whether physical connection was actually reused for this request.\n\tConnectionID                float64                     `json:\"connectionId\"`                                   // Physical connection id that was actually used for this request.\n\tRemoteIPAddress             string                      `json:\"remoteIPAddress,omitempty,omitzero\"`             // Remote IP address.\n\tRemotePort                  int64                       `json:\"remotePort,omitempty,omitzero\"`                  // Remote port.\n\tFromDiskCache               bool                        `json:\"fromDiskCache\"`                                  // Specifies that the request was served from the disk cache.\n\tFromServiceWorker           bool                        `json:\"fromServiceWorker\"`                              // Specifies that the request was served from the ServiceWorker.\n\tFromPrefetchCache           bool                        `json:\"fromPrefetchCache\"`                              // Specifies that the request was served from the prefetch cache.\n\tFromEarlyHints              bool                        `json:\"fromEarlyHints\"`                                 // Specifies that the request was served from the prefetch cache.\n\tServiceWorkerRouterInfo     *ServiceWorkerRouterInfo    `json:\"serviceWorkerRouterInfo,omitempty,omitzero\"`     // Information about how ServiceWorker Static Router API was used. If this field is set with matchedSourceType field, a matching rule is found. If this field is set without matchedSource, no matching rule is found. Otherwise, the API is not used.\n\tEncodedDataLength           float64                     `json:\"encodedDataLength\"`                              // Total number of bytes received for this request so far.\n\tTiming                      *ResourceTiming             `json:\"timing,omitempty,omitzero\"`                      // Timing information for the given request.\n\tServiceWorkerResponseSource ServiceWorkerResponseSource `json:\"serviceWorkerResponseSource,omitempty,omitzero\"` // Response source of response from ServiceWorker.\n\tResponseTime                *cdp.TimeSinceEpochMilli    `json:\"responseTime,omitempty,omitzero\"`                // The time at which the returned response was generated.\n\tCacheStorageCacheName       string                      `json:\"cacheStorageCacheName,omitempty,omitzero\"`       // Cache Storage Cache Name.\n\tProtocol                    string                      `json:\"protocol,omitempty,omitzero\"`                    // Protocol used to fetch this request.\n\tAlternateProtocolUsage      AlternateProtocolUsage      `json:\"alternateProtocolUsage,omitempty,omitzero\"`      // The reason why Chrome uses a specific transport protocol for HTTP semantics.\n\tSecurityState               security.State              `json:\"securityState\"`                                  // Security state of the request resource.\n\tSecurityDetails             *SecurityDetails            `json:\"securityDetails,omitempty,omitzero\"`             // Security details for the request.\n\tIsIPProtectionUsed          bool                        `json:\"isIpProtectionUsed\"`                             // Indicates whether the request was sent through IP Protection proxies. If set to true, the request used the IP Protection privacy feature.\n}\n\n// WebSocketRequest webSocket request data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-WebSocketRequest\ntype WebSocketRequest struct {\n\tHeaders Headers `json:\"headers\"` // HTTP request headers.\n}\n\n// WebSocketResponse webSocket response data.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-WebSocketResponse\ntype WebSocketResponse struct {\n\tStatus             int64   `json:\"status\"`                                // HTTP response status code.\n\tStatusText         string  `json:\"statusText\"`                            // HTTP response status text.\n\tHeaders            Headers `json:\"headers\"`                               // HTTP response headers.\n\tHeadersText        string  `json:\"headersText,omitempty,omitzero\"`        // HTTP response headers text.\n\tRequestHeaders     Headers `json:\"requestHeaders,omitempty,omitzero\"`     // HTTP request headers.\n\tRequestHeadersText string  `json:\"requestHeadersText,omitempty,omitzero\"` // HTTP request headers text.\n}\n\n// WebSocketFrame webSocket message data. This represents an entire WebSocket\n// message, not just a fragmented frame as the name suggests.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-WebSocketFrame\ntype WebSocketFrame struct {\n\tOpcode      float64 `json:\"opcode\"`      // WebSocket message opcode.\n\tMask        bool    `json:\"mask\"`        // WebSocket message mask.\n\tPayloadData string  `json:\"payloadData\"` // WebSocket message payload data. If the opcode is 1, this is a text message and payloadData is a UTF-8 string. If the opcode isn't 1, then payloadData is a base64 encoded string representing binary data.\n}\n\n// CachedResource information about the cached resource.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CachedResource\ntype CachedResource struct {\n\tURL      string       `json:\"url\"`                         // Resource URL. This is the url of the original network request.\n\tType     ResourceType `json:\"type\"`                        // Type of this resource.\n\tResponse *Response    `json:\"response,omitempty,omitzero\"` // Cached response data.\n\tBodySize float64      `json:\"bodySize\"`                    // Cached response body size.\n}\n\n// Initiator information about the request initiator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-Initiator\ntype Initiator struct {\n\tType         InitiatorType       `json:\"type\"`                            // Type of this initiator.\n\tStack        *runtime.StackTrace `json:\"stack,omitempty,omitzero\"`        // Initiator JavaScript stack trace, set for Script only. Requires the Debugger domain to be enabled.\n\tURL          string              `json:\"url,omitempty,omitzero\"`          // Initiator URL, set for Parser type or for Script type (when script is importing module) or for SignedExchange type.\n\tLineNumber   float64             `json:\"lineNumber,omitempty,omitzero\"`   // Initiator line number, set for Parser type or for Script type (when script is importing module) (0-based).\n\tColumnNumber float64             `json:\"columnNumber,omitempty,omitzero\"` // Initiator column number, set for Parser type or for Script type (when script is importing module) (0-based).\n\tRequestID    RequestID           `json:\"requestId,omitempty,omitzero\"`    // Set if another request triggered this request (e.g. preflight).\n}\n\n// CookiePartitionKey cookiePartitionKey object The representation of the\n// components of the key that are created by the cookiePartitionKey class\n// contained in net/cookies/cookie_partition_key.h.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CookiePartitionKey\ntype CookiePartitionKey struct {\n\tTopLevelSite         string `json:\"topLevelSite\"`         // The site of the top-level URL the browser was visiting at the start of the request to the endpoint that set the cookie.\n\tHasCrossSiteAncestor bool   `json:\"hasCrossSiteAncestor\"` // Indicates if the cookie has any ancestors that are cross-site to the topLevelSite.\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookiePartitionKey) OrigUnmarshalJSON(buf []byte) error {\n\tif l := len(buf); l > 2 && buf[0] == '\"' && buf[l-1] == '\"' {\n\t\tvar err error\n\t\tt.TopLevelSite, err = strconv.Unquote(string(buf))\n\t\treturn err\n\t}\n\tdec := json.NewDecoder(bytes.NewReader(buf))\n\tdec.DisallowUnknownFields()\n\tvar v struct {\n\t\tTopLevelSite         string `json:\"topLevelSite\"`\n\t\tHasCrossSiteAncestor bool   `json:\"hasCrossSiteAncestor\"`\n\t}\n\tif err := dec.Decode(&v); err != nil {\n\t\treturn err\n\t}\n\tt.TopLevelSite, t.HasCrossSiteAncestor = v.TopLevelSite, v.HasCrossSiteAncestor\n\treturn nil\n}\n\n// Cookie cookie object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-Cookie\ntype Cookie struct {\n\tName               string              `json:\"name\"`                            // Cookie name.\n\tValue              string              `json:\"value\"`                           // Cookie value.\n\tDomain             string              `json:\"domain\"`                          // Cookie domain.\n\tPath               string              `json:\"path\"`                            // Cookie path.\n\tExpires            float64             `json:\"expires\"`                         // Cookie expiration date as the number of seconds since the UNIX epoch.\n\tSize               int64               `json:\"size\"`                            // Cookie size.\n\tHTTPOnly           bool                `json:\"httpOnly\"`                        // True if cookie is http-only.\n\tSecure             bool                `json:\"secure\"`                          // True if cookie is secure.\n\tSession            bool                `json:\"session\"`                         // True in case of session cookie.\n\tSameSite           CookieSameSite      `json:\"sameSite,omitempty,omitzero\"`     // Cookie SameSite type.\n\tPriority           CookiePriority      `json:\"priority\"`                        // Cookie Priority\n\tSourceScheme       CookieSourceScheme  `json:\"sourceScheme\"`                    // Cookie source scheme type.\n\tSourcePort         int64               `json:\"sourcePort\"`                      // Cookie source port. Valid values are {-1, [1, 65535]}, -1 indicates an unspecified port. An unspecified port value allows protocol clients to emulate legacy cookie scope for the port. This is a temporary ability and it will be removed in the future.\n\tPartitionKey       *CookiePartitionKey `json:\"partitionKey,omitempty,omitzero\"` // Cookie partition key.\n\tPartitionKeyOpaque bool                `json:\"partitionKeyOpaque\"`              // True if cookie partition key is opaque.\n}\n\n// SetCookieBlockedReason types of reasons why a cookie may not be stored\n// from a response.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SetCookieBlockedReason\ntype SetCookieBlockedReason string\n\n// String returns the SetCookieBlockedReason as string value.\nfunc (t SetCookieBlockedReason) String() string {\n\treturn string(t)\n}\n\n// SetCookieBlockedReason values.\nconst (\n\tSetCookieBlockedReasonSecureOnly                               SetCookieBlockedReason = \"SecureOnly\"\n\tSetCookieBlockedReasonSameSiteStrict                           SetCookieBlockedReason = \"SameSiteStrict\"\n\tSetCookieBlockedReasonSameSiteLax                              SetCookieBlockedReason = \"SameSiteLax\"\n\tSetCookieBlockedReasonSameSiteUnspecifiedTreatedAsLax          SetCookieBlockedReason = \"SameSiteUnspecifiedTreatedAsLax\"\n\tSetCookieBlockedReasonSameSiteNoneInsecure                     SetCookieBlockedReason = \"SameSiteNoneInsecure\"\n\tSetCookieBlockedReasonUserPreferences                          SetCookieBlockedReason = \"UserPreferences\"\n\tSetCookieBlockedReasonThirdPartyPhaseout                       SetCookieBlockedReason = \"ThirdPartyPhaseout\"\n\tSetCookieBlockedReasonThirdPartyBlockedInFirstPartySet         SetCookieBlockedReason = \"ThirdPartyBlockedInFirstPartySet\"\n\tSetCookieBlockedReasonSyntaxError                              SetCookieBlockedReason = \"SyntaxError\"\n\tSetCookieBlockedReasonSchemeNotSupported                       SetCookieBlockedReason = \"SchemeNotSupported\"\n\tSetCookieBlockedReasonOverwriteSecure                          SetCookieBlockedReason = \"OverwriteSecure\"\n\tSetCookieBlockedReasonInvalidDomain                            SetCookieBlockedReason = \"InvalidDomain\"\n\tSetCookieBlockedReasonInvalidPrefix                            SetCookieBlockedReason = \"InvalidPrefix\"\n\tSetCookieBlockedReasonUnknownError                             SetCookieBlockedReason = \"UnknownError\"\n\tSetCookieBlockedReasonSchemefulSameSiteStrict                  SetCookieBlockedReason = \"SchemefulSameSiteStrict\"\n\tSetCookieBlockedReasonSchemefulSameSiteLax                     SetCookieBlockedReason = \"SchemefulSameSiteLax\"\n\tSetCookieBlockedReasonSchemefulSameSiteUnspecifiedTreatedAsLax SetCookieBlockedReason = \"SchemefulSameSiteUnspecifiedTreatedAsLax\"\n\tSetCookieBlockedReasonSamePartyFromCrossPartyContext           SetCookieBlockedReason = \"SamePartyFromCrossPartyContext\"\n\tSetCookieBlockedReasonSamePartyConflictsWithOtherAttributes    SetCookieBlockedReason = \"SamePartyConflictsWithOtherAttributes\"\n\tSetCookieBlockedReasonNameValuePairExceedsMaxSize              SetCookieBlockedReason = \"NameValuePairExceedsMaxSize\"\n\tSetCookieBlockedReasonDisallowedCharacter                      SetCookieBlockedReason = \"DisallowedCharacter\"\n\tSetCookieBlockedReasonNoCookieContent                          SetCookieBlockedReason = \"NoCookieContent\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetCookieBlockedReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetCookieBlockedReason(s) {\n\tcase SetCookieBlockedReasonSecureOnly:\n\t\t*t = SetCookieBlockedReasonSecureOnly\n\tcase SetCookieBlockedReasonSameSiteStrict:\n\t\t*t = SetCookieBlockedReasonSameSiteStrict\n\tcase SetCookieBlockedReasonSameSiteLax:\n\t\t*t = SetCookieBlockedReasonSameSiteLax\n\tcase SetCookieBlockedReasonSameSiteUnspecifiedTreatedAsLax:\n\t\t*t = SetCookieBlockedReasonSameSiteUnspecifiedTreatedAsLax\n\tcase SetCookieBlockedReasonSameSiteNoneInsecure:\n\t\t*t = SetCookieBlockedReasonSameSiteNoneInsecure\n\tcase SetCookieBlockedReasonUserPreferences:\n\t\t*t = SetCookieBlockedReasonUserPreferences\n\tcase SetCookieBlockedReasonThirdPartyPhaseout:\n\t\t*t = SetCookieBlockedReasonThirdPartyPhaseout\n\tcase SetCookieBlockedReasonThirdPartyBlockedInFirstPartySet:\n\t\t*t = SetCookieBlockedReasonThirdPartyBlockedInFirstPartySet\n\tcase SetCookieBlockedReasonSyntaxError:\n\t\t*t = SetCookieBlockedReasonSyntaxError\n\tcase SetCookieBlockedReasonSchemeNotSupported:\n\t\t*t = SetCookieBlockedReasonSchemeNotSupported\n\tcase SetCookieBlockedReasonOverwriteSecure:\n\t\t*t = SetCookieBlockedReasonOverwriteSecure\n\tcase SetCookieBlockedReasonInvalidDomain:\n\t\t*t = SetCookieBlockedReasonInvalidDomain\n\tcase SetCookieBlockedReasonInvalidPrefix:\n\t\t*t = SetCookieBlockedReasonInvalidPrefix\n\tcase SetCookieBlockedReasonUnknownError:\n\t\t*t = SetCookieBlockedReasonUnknownError\n\tcase SetCookieBlockedReasonSchemefulSameSiteStrict:\n\t\t*t = SetCookieBlockedReasonSchemefulSameSiteStrict\n\tcase SetCookieBlockedReasonSchemefulSameSiteLax:\n\t\t*t = SetCookieBlockedReasonSchemefulSameSiteLax\n\tcase SetCookieBlockedReasonSchemefulSameSiteUnspecifiedTreatedAsLax:\n\t\t*t = SetCookieBlockedReasonSchemefulSameSiteUnspecifiedTreatedAsLax\n\tcase SetCookieBlockedReasonSamePartyFromCrossPartyContext:\n\t\t*t = SetCookieBlockedReasonSamePartyFromCrossPartyContext\n\tcase SetCookieBlockedReasonSamePartyConflictsWithOtherAttributes:\n\t\t*t = SetCookieBlockedReasonSamePartyConflictsWithOtherAttributes\n\tcase SetCookieBlockedReasonNameValuePairExceedsMaxSize:\n\t\t*t = SetCookieBlockedReasonNameValuePairExceedsMaxSize\n\tcase SetCookieBlockedReasonDisallowedCharacter:\n\t\t*t = SetCookieBlockedReasonDisallowedCharacter\n\tcase SetCookieBlockedReasonNoCookieContent:\n\t\t*t = SetCookieBlockedReasonNoCookieContent\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetCookieBlockedReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookieBlockedReason types of reasons why a cookie may not be sent with a\n// request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CookieBlockedReason\ntype CookieBlockedReason string\n\n// String returns the CookieBlockedReason as string value.\nfunc (t CookieBlockedReason) String() string {\n\treturn string(t)\n}\n\n// CookieBlockedReason values.\nconst (\n\tCookieBlockedReasonSecureOnly                               CookieBlockedReason = \"SecureOnly\"\n\tCookieBlockedReasonNotOnPath                                CookieBlockedReason = \"NotOnPath\"\n\tCookieBlockedReasonDomainMismatch                           CookieBlockedReason = \"DomainMismatch\"\n\tCookieBlockedReasonSameSiteStrict                           CookieBlockedReason = \"SameSiteStrict\"\n\tCookieBlockedReasonSameSiteLax                              CookieBlockedReason = \"SameSiteLax\"\n\tCookieBlockedReasonSameSiteUnspecifiedTreatedAsLax          CookieBlockedReason = \"SameSiteUnspecifiedTreatedAsLax\"\n\tCookieBlockedReasonSameSiteNoneInsecure                     CookieBlockedReason = \"SameSiteNoneInsecure\"\n\tCookieBlockedReasonUserPreferences                          CookieBlockedReason = \"UserPreferences\"\n\tCookieBlockedReasonThirdPartyPhaseout                       CookieBlockedReason = \"ThirdPartyPhaseout\"\n\tCookieBlockedReasonThirdPartyBlockedInFirstPartySet         CookieBlockedReason = \"ThirdPartyBlockedInFirstPartySet\"\n\tCookieBlockedReasonUnknownError                             CookieBlockedReason = \"UnknownError\"\n\tCookieBlockedReasonSchemefulSameSiteStrict                  CookieBlockedReason = \"SchemefulSameSiteStrict\"\n\tCookieBlockedReasonSchemefulSameSiteLax                     CookieBlockedReason = \"SchemefulSameSiteLax\"\n\tCookieBlockedReasonSchemefulSameSiteUnspecifiedTreatedAsLax CookieBlockedReason = \"SchemefulSameSiteUnspecifiedTreatedAsLax\"\n\tCookieBlockedReasonSamePartyFromCrossPartyContext           CookieBlockedReason = \"SamePartyFromCrossPartyContext\"\n\tCookieBlockedReasonNameValuePairExceedsMaxSize              CookieBlockedReason = \"NameValuePairExceedsMaxSize\"\n\tCookieBlockedReasonPortMismatch                             CookieBlockedReason = \"PortMismatch\"\n\tCookieBlockedReasonSchemeMismatch                           CookieBlockedReason = \"SchemeMismatch\"\n\tCookieBlockedReasonAnonymousContext                         CookieBlockedReason = \"AnonymousContext\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookieBlockedReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookieBlockedReason(s) {\n\tcase CookieBlockedReasonSecureOnly:\n\t\t*t = CookieBlockedReasonSecureOnly\n\tcase CookieBlockedReasonNotOnPath:\n\t\t*t = CookieBlockedReasonNotOnPath\n\tcase CookieBlockedReasonDomainMismatch:\n\t\t*t = CookieBlockedReasonDomainMismatch\n\tcase CookieBlockedReasonSameSiteStrict:\n\t\t*t = CookieBlockedReasonSameSiteStrict\n\tcase CookieBlockedReasonSameSiteLax:\n\t\t*t = CookieBlockedReasonSameSiteLax\n\tcase CookieBlockedReasonSameSiteUnspecifiedTreatedAsLax:\n\t\t*t = CookieBlockedReasonSameSiteUnspecifiedTreatedAsLax\n\tcase CookieBlockedReasonSameSiteNoneInsecure:\n\t\t*t = CookieBlockedReasonSameSiteNoneInsecure\n\tcase CookieBlockedReasonUserPreferences:\n\t\t*t = CookieBlockedReasonUserPreferences\n\tcase CookieBlockedReasonThirdPartyPhaseout:\n\t\t*t = CookieBlockedReasonThirdPartyPhaseout\n\tcase CookieBlockedReasonThirdPartyBlockedInFirstPartySet:\n\t\t*t = CookieBlockedReasonThirdPartyBlockedInFirstPartySet\n\tcase CookieBlockedReasonUnknownError:\n\t\t*t = CookieBlockedReasonUnknownError\n\tcase CookieBlockedReasonSchemefulSameSiteStrict:\n\t\t*t = CookieBlockedReasonSchemefulSameSiteStrict\n\tcase CookieBlockedReasonSchemefulSameSiteLax:\n\t\t*t = CookieBlockedReasonSchemefulSameSiteLax\n\tcase CookieBlockedReasonSchemefulSameSiteUnspecifiedTreatedAsLax:\n\t\t*t = CookieBlockedReasonSchemefulSameSiteUnspecifiedTreatedAsLax\n\tcase CookieBlockedReasonSamePartyFromCrossPartyContext:\n\t\t*t = CookieBlockedReasonSamePartyFromCrossPartyContext\n\tcase CookieBlockedReasonNameValuePairExceedsMaxSize:\n\t\t*t = CookieBlockedReasonNameValuePairExceedsMaxSize\n\tcase CookieBlockedReasonPortMismatch:\n\t\t*t = CookieBlockedReasonPortMismatch\n\tcase CookieBlockedReasonSchemeMismatch:\n\t\t*t = CookieBlockedReasonSchemeMismatch\n\tcase CookieBlockedReasonAnonymousContext:\n\t\t*t = CookieBlockedReasonAnonymousContext\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookieBlockedReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CookieExemptionReason types of reasons why a cookie should have been\n// blocked by 3PCD but is exempted for the request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CookieExemptionReason\ntype CookieExemptionReason string\n\n// String returns the CookieExemptionReason as string value.\nfunc (t CookieExemptionReason) String() string {\n\treturn string(t)\n}\n\n// CookieExemptionReason values.\nconst (\n\tCookieExemptionReasonNone                         CookieExemptionReason = \"None\"\n\tCookieExemptionReasonUserSetting                  CookieExemptionReason = \"UserSetting\"\n\tCookieExemptionReasonTPCDMetadata                 CookieExemptionReason = \"TPCDMetadata\"\n\tCookieExemptionReasonTPCDDeprecationTrial         CookieExemptionReason = \"TPCDDeprecationTrial\"\n\tCookieExemptionReasonTopLevelTPCDDeprecationTrial CookieExemptionReason = \"TopLevelTPCDDeprecationTrial\"\n\tCookieExemptionReasonTPCDHeuristics               CookieExemptionReason = \"TPCDHeuristics\"\n\tCookieExemptionReasonEnterprisePolicy             CookieExemptionReason = \"EnterprisePolicy\"\n\tCookieExemptionReasonStorageAccess                CookieExemptionReason = \"StorageAccess\"\n\tCookieExemptionReasonTopLevelStorageAccess        CookieExemptionReason = \"TopLevelStorageAccess\"\n\tCookieExemptionReasonScheme                       CookieExemptionReason = \"Scheme\"\n\tCookieExemptionReasonSameSiteNoneCookiesInSandbox CookieExemptionReason = \"SameSiteNoneCookiesInSandbox\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CookieExemptionReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CookieExemptionReason(s) {\n\tcase CookieExemptionReasonNone:\n\t\t*t = CookieExemptionReasonNone\n\tcase CookieExemptionReasonUserSetting:\n\t\t*t = CookieExemptionReasonUserSetting\n\tcase CookieExemptionReasonTPCDMetadata:\n\t\t*t = CookieExemptionReasonTPCDMetadata\n\tcase CookieExemptionReasonTPCDDeprecationTrial:\n\t\t*t = CookieExemptionReasonTPCDDeprecationTrial\n\tcase CookieExemptionReasonTopLevelTPCDDeprecationTrial:\n\t\t*t = CookieExemptionReasonTopLevelTPCDDeprecationTrial\n\tcase CookieExemptionReasonTPCDHeuristics:\n\t\t*t = CookieExemptionReasonTPCDHeuristics\n\tcase CookieExemptionReasonEnterprisePolicy:\n\t\t*t = CookieExemptionReasonEnterprisePolicy\n\tcase CookieExemptionReasonStorageAccess:\n\t\t*t = CookieExemptionReasonStorageAccess\n\tcase CookieExemptionReasonTopLevelStorageAccess:\n\t\t*t = CookieExemptionReasonTopLevelStorageAccess\n\tcase CookieExemptionReasonScheme:\n\t\t*t = CookieExemptionReasonScheme\n\tcase CookieExemptionReasonSameSiteNoneCookiesInSandbox:\n\t\t*t = CookieExemptionReasonSameSiteNoneCookiesInSandbox\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CookieExemptionReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// BlockedSetCookieWithReason a cookie which was not stored from a response\n// with the corresponding reason.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-BlockedSetCookieWithReason\ntype BlockedSetCookieWithReason struct {\n\tBlockedReasons []SetCookieBlockedReason `json:\"blockedReasons\"`            // The reason(s) this cookie was blocked.\n\tCookieLine     string                   `json:\"cookieLine\"`                // The string representing this individual cookie as it would appear in the header. This is not the entire \"cookie\" or \"set-cookie\" header which could have multiple cookies.\n\tCookie         *Cookie                  `json:\"cookie,omitempty,omitzero\"` // The cookie object which represents the cookie which was not stored. It is optional because sometimes complete cookie information is not available, such as in the case of parsing errors.\n}\n\n// ExemptedSetCookieWithReason a cookie should have been blocked by 3PCD but\n// is exempted and stored from a response with the corresponding reason. A\n// cookie could only have at most one exemption reason.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ExemptedSetCookieWithReason\ntype ExemptedSetCookieWithReason struct {\n\tExemptionReason CookieExemptionReason `json:\"exemptionReason\"` // The reason the cookie was exempted.\n\tCookieLine      string                `json:\"cookieLine\"`      // The string representing this individual cookie as it would appear in the header.\n\tCookie          *Cookie               `json:\"cookie\"`          // The cookie object representing the cookie.\n}\n\n// AssociatedCookie a cookie associated with the request which may or may not\n// be sent with it. Includes the cookies itself and reasons for blocking or\n// exemption.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-AssociatedCookie\ntype AssociatedCookie struct {\n\tCookie          *Cookie               `json:\"cookie\"`                             // The cookie object representing the cookie which was not sent.\n\tBlockedReasons  []CookieBlockedReason `json:\"blockedReasons\"`                     // The reason(s) the cookie was blocked. If empty means the cookie is included.\n\tExemptionReason CookieExemptionReason `json:\"exemptionReason,omitempty,omitzero\"` // The reason the cookie should have been blocked by 3PCD but is exempted. A cookie could only have at most one exemption reason.\n}\n\n// CookieParam cookie parameter object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CookieParam\ntype CookieParam struct {\n\tName         string              `json:\"name\"`                            // Cookie name.\n\tValue        string              `json:\"value\"`                           // Cookie value.\n\tURL          string              `json:\"url,omitempty,omitzero\"`          // The request-URI to associate with the setting of the cookie. This value can affect the default domain, path, source port, and source scheme values of the created cookie.\n\tDomain       string              `json:\"domain,omitempty,omitzero\"`       // Cookie domain.\n\tPath         string              `json:\"path,omitempty,omitzero\"`         // Cookie path.\n\tSecure       bool                `json:\"secure\"`                          // True if cookie is secure.\n\tHTTPOnly     bool                `json:\"httpOnly\"`                        // True if cookie is http-only.\n\tSameSite     CookieSameSite      `json:\"sameSite,omitempty,omitzero\"`     // Cookie SameSite type.\n\tExpires      *cdp.TimeSinceEpoch `json:\"expires,omitempty,omitzero\"`      // Cookie expiration date, session cookie if not set\n\tPriority     CookiePriority      `json:\"priority,omitempty,omitzero\"`     // Cookie Priority.\n\tSameParty    bool                `json:\"sameParty\"`                       // True if cookie is SameParty.\n\tSourceScheme CookieSourceScheme  `json:\"sourceScheme,omitempty,omitzero\"` // Cookie source scheme type.\n\tSourcePort   int64               `json:\"sourcePort,omitempty,omitzero\"`   // Cookie source port. Valid values are {-1, [1, 65535]}, -1 indicates an unspecified port. An unspecified port value allows protocol clients to emulate legacy cookie scope for the port. This is a temporary ability and it will be removed in the future.\n\tPartitionKey *CookiePartitionKey `json:\"partitionKey,omitempty,omitzero\"` // Cookie partition key. If not set, the cookie will be set as not partitioned.\n}\n\n// AuthChallenge authorization challenge for HTTP status code 401 or 407.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-AuthChallenge\ntype AuthChallenge struct {\n\tSource AuthChallengeSource `json:\"source,omitempty,omitzero\"` // Source of the authentication challenge.\n\tOrigin string              `json:\"origin\"`                    // Origin of the challenger.\n\tScheme string              `json:\"scheme\"`                    // The authentication scheme used, such as basic or digest\n\tRealm  string              `json:\"realm\"`                     // The realm of the challenge. May be empty.\n}\n\n// AuthChallengeResponse response to an AuthChallenge.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-AuthChallengeResponse\ntype AuthChallengeResponse struct {\n\tResponse AuthChallengeResponseResponse `json:\"response\"`                    // The decision on what to do in response to the authorization challenge.  Default means deferring to the default behavior of the net stack, which will likely either the Cancel authentication or display a popup dialog box.\n\tUsername string                        `json:\"username,omitempty,omitzero\"` // The username to provide, possibly empty. Should only be set if response is ProvideCredentials.\n\tPassword string                        `json:\"password,omitempty,omitzero\"` // The password to provide, possibly empty. Should only be set if response is ProvideCredentials.\n}\n\n// InterceptionStage stages of the interception to begin intercepting.\n// Request will intercept before the request is sent. Response will intercept\n// after the response is received.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-InterceptionStage\ntype InterceptionStage string\n\n// String returns the InterceptionStage as string value.\nfunc (t InterceptionStage) String() string {\n\treturn string(t)\n}\n\n// InterceptionStage values.\nconst (\n\tInterceptionStageRequest         InterceptionStage = \"Request\"\n\tInterceptionStageHeadersReceived InterceptionStage = \"HeadersReceived\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InterceptionStage) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InterceptionStage(s) {\n\tcase InterceptionStageRequest:\n\t\t*t = InterceptionStageRequest\n\tcase InterceptionStageHeadersReceived:\n\t\t*t = InterceptionStageHeadersReceived\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InterceptionStage value: %v\", s)\n\t}\n\treturn nil\n}\n\n// RequestPattern request pattern for interception.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-RequestPattern\ntype RequestPattern struct {\n\tURLPattern        string            `json:\"urlPattern,omitempty,omitzero\"`        // Wildcards ('*' -> zero or more, '?' -> exactly one) are allowed. Escape character is backslash. Omitting is equivalent to \"*\".\n\tResourceType      ResourceType      `json:\"resourceType,omitempty,omitzero\"`      // If set, only requests for matching resource types will be intercepted.\n\tInterceptionStage InterceptionStage `json:\"interceptionStage,omitempty,omitzero\"` // Stage at which to begin intercepting requests. Default is Request.\n}\n\n// SignedExchangeSignature information about a signed exchange signature.\n// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#rfc.section.3.1.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SignedExchangeSignature\ntype SignedExchangeSignature struct {\n\tLabel        string   `json:\"label\"`                           // Signed exchange signature label.\n\tSignature    string   `json:\"signature\"`                       // The hex string of signed exchange signature.\n\tIntegrity    string   `json:\"integrity\"`                       // Signed exchange signature integrity.\n\tCertURL      string   `json:\"certUrl,omitempty,omitzero\"`      // Signed exchange signature cert Url.\n\tCertSha256   string   `json:\"certSha256,omitempty,omitzero\"`   // The hex string of signed exchange signature cert sha256.\n\tValidityURL  string   `json:\"validityUrl\"`                     // Signed exchange signature validity Url.\n\tDate         int64    `json:\"date\"`                            // Signed exchange signature date.\n\tExpires      int64    `json:\"expires\"`                         // Signed exchange signature expires.\n\tCertificates []string `json:\"certificates,omitempty,omitzero\"` // The encoded certificates.\n}\n\n// SignedExchangeHeader information about a signed exchange header.\n// https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cbor-representation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SignedExchangeHeader\ntype SignedExchangeHeader struct {\n\tRequestURL      string                     `json:\"requestUrl\"`      // Signed exchange request URL.\n\tResponseCode    int64                      `json:\"responseCode\"`    // Signed exchange response code.\n\tResponseHeaders Headers                    `json:\"responseHeaders\"` // Signed exchange response headers.\n\tSignatures      []*SignedExchangeSignature `json:\"signatures\"`      // Signed exchange response signature.\n\tHeaderIntegrity string                     `json:\"headerIntegrity\"` // Signed exchange header integrity hash in the form of sha256-<base64-hash-value>.\n}\n\n// SignedExchangeErrorField field type for a signed exchange related error.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SignedExchangeErrorField\ntype SignedExchangeErrorField string\n\n// String returns the SignedExchangeErrorField as string value.\nfunc (t SignedExchangeErrorField) String() string {\n\treturn string(t)\n}\n\n// SignedExchangeErrorField values.\nconst (\n\tSignedExchangeErrorFieldSignatureSig         SignedExchangeErrorField = \"signatureSig\"\n\tSignedExchangeErrorFieldSignatureIntegrity   SignedExchangeErrorField = \"signatureIntegrity\"\n\tSignedExchangeErrorFieldSignatureCertURL     SignedExchangeErrorField = \"signatureCertUrl\"\n\tSignedExchangeErrorFieldSignatureCertSha256  SignedExchangeErrorField = \"signatureCertSha256\"\n\tSignedExchangeErrorFieldSignatureValidityURL SignedExchangeErrorField = \"signatureValidityUrl\"\n\tSignedExchangeErrorFieldSignatureTimestamps  SignedExchangeErrorField = \"signatureTimestamps\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SignedExchangeErrorField) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SignedExchangeErrorField(s) {\n\tcase SignedExchangeErrorFieldSignatureSig:\n\t\t*t = SignedExchangeErrorFieldSignatureSig\n\tcase SignedExchangeErrorFieldSignatureIntegrity:\n\t\t*t = SignedExchangeErrorFieldSignatureIntegrity\n\tcase SignedExchangeErrorFieldSignatureCertURL:\n\t\t*t = SignedExchangeErrorFieldSignatureCertURL\n\tcase SignedExchangeErrorFieldSignatureCertSha256:\n\t\t*t = SignedExchangeErrorFieldSignatureCertSha256\n\tcase SignedExchangeErrorFieldSignatureValidityURL:\n\t\t*t = SignedExchangeErrorFieldSignatureValidityURL\n\tcase SignedExchangeErrorFieldSignatureTimestamps:\n\t\t*t = SignedExchangeErrorFieldSignatureTimestamps\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SignedExchangeErrorField value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SignedExchangeError information about a signed exchange response.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SignedExchangeError\ntype SignedExchangeError struct {\n\tMessage        string                   `json:\"message\"`                           // Error message.\n\tSignatureIndex int64                    `json:\"signatureIndex,omitempty,omitzero\"` // The index of the signature which caused the error.\n\tErrorField     SignedExchangeErrorField `json:\"errorField,omitempty,omitzero\"`     // The field which caused the error.\n}\n\n// SignedExchangeInfo information about a signed exchange response.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SignedExchangeInfo\ntype SignedExchangeInfo struct {\n\tOuterResponse   *Response              `json:\"outerResponse\"`                      // The outer response of signed HTTP exchange which was received from network.\n\tHasExtraInfo    bool                   `json:\"hasExtraInfo\"`                       // Whether network response for the signed exchange was accompanied by extra headers.\n\tHeader          *SignedExchangeHeader  `json:\"header,omitempty,omitzero\"`          // Information about the signed exchange header.\n\tSecurityDetails *SecurityDetails       `json:\"securityDetails,omitempty,omitzero\"` // Security details for the signed exchange header.\n\tErrors          []*SignedExchangeError `json:\"errors,omitempty,omitzero\"`          // Errors occurred while handling the signed exchange.\n}\n\n// ContentEncoding list of content encodings supported by the backend.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ContentEncoding\ntype ContentEncoding string\n\n// String returns the ContentEncoding as string value.\nfunc (t ContentEncoding) String() string {\n\treturn string(t)\n}\n\n// ContentEncoding values.\nconst (\n\tContentEncodingDeflate ContentEncoding = \"deflate\"\n\tContentEncodingGzip    ContentEncoding = \"gzip\"\n\tContentEncodingBr      ContentEncoding = \"br\"\n\tContentEncodingZstd    ContentEncoding = \"zstd\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ContentEncoding) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ContentEncoding(s) {\n\tcase ContentEncodingDeflate:\n\t\t*t = ContentEncodingDeflate\n\tcase ContentEncodingGzip:\n\t\t*t = ContentEncodingGzip\n\tcase ContentEncodingBr:\n\t\t*t = ContentEncodingBr\n\tcase ContentEncodingZstd:\n\t\t*t = ContentEncodingZstd\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ContentEncoding value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DirectSocketDNSQueryType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-DirectSocketDnsQueryType\ntype DirectSocketDNSQueryType string\n\n// String returns the DirectSocketDNSQueryType as string value.\nfunc (t DirectSocketDNSQueryType) String() string {\n\treturn string(t)\n}\n\n// DirectSocketDNSQueryType values.\nconst (\n\tDirectSocketDNSQueryTypeIpv4 DirectSocketDNSQueryType = \"ipv4\"\n\tDirectSocketDNSQueryTypeIpv6 DirectSocketDNSQueryType = \"ipv6\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DirectSocketDNSQueryType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DirectSocketDNSQueryType(s) {\n\tcase DirectSocketDNSQueryTypeIpv4:\n\t\t*t = DirectSocketDNSQueryTypeIpv4\n\tcase DirectSocketDNSQueryTypeIpv6:\n\t\t*t = DirectSocketDNSQueryTypeIpv6\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DirectSocketDNSQueryType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DirectTCPSocketOptions [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-DirectTCPSocketOptions\ntype DirectTCPSocketOptions struct {\n\tNoDelay           bool                     `json:\"noDelay\"`                              // TCP_NODELAY option\n\tKeepAliveDelay    float64                  `json:\"keepAliveDelay,omitempty,omitzero\"`    // Expected to be unsigned integer.\n\tSendBufferSize    float64                  `json:\"sendBufferSize,omitempty,omitzero\"`    // Expected to be unsigned integer.\n\tReceiveBufferSize float64                  `json:\"receiveBufferSize,omitempty,omitzero\"` // Expected to be unsigned integer.\n\tDNSQueryType      DirectSocketDNSQueryType `json:\"dnsQueryType,omitempty,omitzero\"`\n}\n\n// DirectUDPSocketOptions [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-DirectUDPSocketOptions\ntype DirectUDPSocketOptions struct {\n\tRemoteAddr        string                   `json:\"remoteAddr,omitempty,omitzero\"`\n\tRemotePort        int64                    `json:\"remotePort,omitempty,omitzero\"` // Unsigned int 16.\n\tLocalAddr         string                   `json:\"localAddr,omitempty,omitzero\"`\n\tLocalPort         int64                    `json:\"localPort,omitempty,omitzero\"` // Unsigned int 16.\n\tDNSQueryType      DirectSocketDNSQueryType `json:\"dnsQueryType,omitempty,omitzero\"`\n\tSendBufferSize    float64                  `json:\"sendBufferSize,omitempty,omitzero\"`    // Expected to be unsigned integer.\n\tReceiveBufferSize float64                  `json:\"receiveBufferSize,omitempty,omitzero\"` // Expected to be unsigned integer.\n}\n\n// DirectUDPMessage [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-DirectUDPMessage\ntype DirectUDPMessage struct {\n\tData       string `json:\"data\"`\n\tRemoteAddr string `json:\"remoteAddr,omitempty,omitzero\"` // Null for connected mode.\n\tRemotePort int64  `json:\"remotePort,omitempty,omitzero\"` // Null for connected mode. Expected to be unsigned integer.\n}\n\n// PrivateNetworkRequestPolicy [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-PrivateNetworkRequestPolicy\ntype PrivateNetworkRequestPolicy string\n\n// String returns the PrivateNetworkRequestPolicy as string value.\nfunc (t PrivateNetworkRequestPolicy) String() string {\n\treturn string(t)\n}\n\n// PrivateNetworkRequestPolicy values.\nconst (\n\tPrivateNetworkRequestPolicyAllow                          PrivateNetworkRequestPolicy = \"Allow\"\n\tPrivateNetworkRequestPolicyBlockFromInsecureToMorePrivate PrivateNetworkRequestPolicy = \"BlockFromInsecureToMorePrivate\"\n\tPrivateNetworkRequestPolicyWarnFromInsecureToMorePrivate  PrivateNetworkRequestPolicy = \"WarnFromInsecureToMorePrivate\"\n\tPrivateNetworkRequestPolicyPreflightBlock                 PrivateNetworkRequestPolicy = \"PreflightBlock\"\n\tPrivateNetworkRequestPolicyPreflightWarn                  PrivateNetworkRequestPolicy = \"PreflightWarn\"\n\tPrivateNetworkRequestPolicyPermissionBlock                PrivateNetworkRequestPolicy = \"PermissionBlock\"\n\tPrivateNetworkRequestPolicyPermissionWarn                 PrivateNetworkRequestPolicy = \"PermissionWarn\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PrivateNetworkRequestPolicy) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PrivateNetworkRequestPolicy(s) {\n\tcase PrivateNetworkRequestPolicyAllow:\n\t\t*t = PrivateNetworkRequestPolicyAllow\n\tcase PrivateNetworkRequestPolicyBlockFromInsecureToMorePrivate:\n\t\t*t = PrivateNetworkRequestPolicyBlockFromInsecureToMorePrivate\n\tcase PrivateNetworkRequestPolicyWarnFromInsecureToMorePrivate:\n\t\t*t = PrivateNetworkRequestPolicyWarnFromInsecureToMorePrivate\n\tcase PrivateNetworkRequestPolicyPreflightBlock:\n\t\t*t = PrivateNetworkRequestPolicyPreflightBlock\n\tcase PrivateNetworkRequestPolicyPreflightWarn:\n\t\t*t = PrivateNetworkRequestPolicyPreflightWarn\n\tcase PrivateNetworkRequestPolicyPermissionBlock:\n\t\t*t = PrivateNetworkRequestPolicyPermissionBlock\n\tcase PrivateNetworkRequestPolicyPermissionWarn:\n\t\t*t = PrivateNetworkRequestPolicyPermissionWarn\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PrivateNetworkRequestPolicy value: %v\", s)\n\t}\n\treturn nil\n}\n\n// IPAddressSpace [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-IPAddressSpace\ntype IPAddressSpace string\n\n// String returns the IPAddressSpace as string value.\nfunc (t IPAddressSpace) String() string {\n\treturn string(t)\n}\n\n// IPAddressSpace values.\nconst (\n\tIPAddressSpaceLoopback IPAddressSpace = \"Loopback\"\n\tIPAddressSpaceLocal    IPAddressSpace = \"Local\"\n\tIPAddressSpacePublic   IPAddressSpace = \"Public\"\n\tIPAddressSpaceUnknown  IPAddressSpace = \"Unknown\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *IPAddressSpace) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch IPAddressSpace(s) {\n\tcase IPAddressSpaceLoopback:\n\t\t*t = IPAddressSpaceLoopback\n\tcase IPAddressSpaceLocal:\n\t\t*t = IPAddressSpaceLocal\n\tcase IPAddressSpacePublic:\n\t\t*t = IPAddressSpacePublic\n\tcase IPAddressSpaceUnknown:\n\t\t*t = IPAddressSpaceUnknown\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown IPAddressSpace value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ConnectTiming [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ConnectTiming\ntype ConnectTiming struct {\n\tRequestTime float64 `json:\"requestTime\"` // Timing's requestTime is a baseline in seconds, while the other numbers are ticks in milliseconds relatively to this requestTime. Matches ResourceTiming's requestTime for the same request (but not for redirected requests).\n}\n\n// ClientSecurityState [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ClientSecurityState\ntype ClientSecurityState struct {\n\tInitiatorIsSecureContext    bool                        `json:\"initiatorIsSecureContext\"`\n\tInitiatorIPAddressSpace     IPAddressSpace              `json:\"initiatorIPAddressSpace\"`\n\tPrivateNetworkRequestPolicy PrivateNetworkRequestPolicy `json:\"privateNetworkRequestPolicy\"`\n}\n\n// CrossOriginOpenerPolicyValue [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CrossOriginOpenerPolicyValue\ntype CrossOriginOpenerPolicyValue string\n\n// String returns the CrossOriginOpenerPolicyValue as string value.\nfunc (t CrossOriginOpenerPolicyValue) String() string {\n\treturn string(t)\n}\n\n// CrossOriginOpenerPolicyValue values.\nconst (\n\tCrossOriginOpenerPolicyValueSameOrigin                 CrossOriginOpenerPolicyValue = \"SameOrigin\"\n\tCrossOriginOpenerPolicyValueSameOriginAllowPopups      CrossOriginOpenerPolicyValue = \"SameOriginAllowPopups\"\n\tCrossOriginOpenerPolicyValueRestrictProperties         CrossOriginOpenerPolicyValue = \"RestrictProperties\"\n\tCrossOriginOpenerPolicyValueUnsafeNone                 CrossOriginOpenerPolicyValue = \"UnsafeNone\"\n\tCrossOriginOpenerPolicyValueSameOriginPlusCoep         CrossOriginOpenerPolicyValue = \"SameOriginPlusCoep\"\n\tCrossOriginOpenerPolicyValueRestrictPropertiesPlusCoep CrossOriginOpenerPolicyValue = \"RestrictPropertiesPlusCoep\"\n\tCrossOriginOpenerPolicyValueNoopenerAllowPopups        CrossOriginOpenerPolicyValue = \"NoopenerAllowPopups\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CrossOriginOpenerPolicyValue) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CrossOriginOpenerPolicyValue(s) {\n\tcase CrossOriginOpenerPolicyValueSameOrigin:\n\t\t*t = CrossOriginOpenerPolicyValueSameOrigin\n\tcase CrossOriginOpenerPolicyValueSameOriginAllowPopups:\n\t\t*t = CrossOriginOpenerPolicyValueSameOriginAllowPopups\n\tcase CrossOriginOpenerPolicyValueRestrictProperties:\n\t\t*t = CrossOriginOpenerPolicyValueRestrictProperties\n\tcase CrossOriginOpenerPolicyValueUnsafeNone:\n\t\t*t = CrossOriginOpenerPolicyValueUnsafeNone\n\tcase CrossOriginOpenerPolicyValueSameOriginPlusCoep:\n\t\t*t = CrossOriginOpenerPolicyValueSameOriginPlusCoep\n\tcase CrossOriginOpenerPolicyValueRestrictPropertiesPlusCoep:\n\t\t*t = CrossOriginOpenerPolicyValueRestrictPropertiesPlusCoep\n\tcase CrossOriginOpenerPolicyValueNoopenerAllowPopups:\n\t\t*t = CrossOriginOpenerPolicyValueNoopenerAllowPopups\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CrossOriginOpenerPolicyValue value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CrossOriginOpenerPolicyStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CrossOriginOpenerPolicyStatus\ntype CrossOriginOpenerPolicyStatus struct {\n\tValue                       CrossOriginOpenerPolicyValue `json:\"value\"`\n\tReportOnlyValue             CrossOriginOpenerPolicyValue `json:\"reportOnlyValue\"`\n\tReportingEndpoint           string                       `json:\"reportingEndpoint,omitempty,omitzero\"`\n\tReportOnlyReportingEndpoint string                       `json:\"reportOnlyReportingEndpoint,omitempty,omitzero\"`\n}\n\n// CrossOriginEmbedderPolicyValue [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CrossOriginEmbedderPolicyValue\ntype CrossOriginEmbedderPolicyValue string\n\n// String returns the CrossOriginEmbedderPolicyValue as string value.\nfunc (t CrossOriginEmbedderPolicyValue) String() string {\n\treturn string(t)\n}\n\n// CrossOriginEmbedderPolicyValue values.\nconst (\n\tCrossOriginEmbedderPolicyValueNone           CrossOriginEmbedderPolicyValue = \"None\"\n\tCrossOriginEmbedderPolicyValueCredentialless CrossOriginEmbedderPolicyValue = \"Credentialless\"\n\tCrossOriginEmbedderPolicyValueRequireCorp    CrossOriginEmbedderPolicyValue = \"RequireCorp\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CrossOriginEmbedderPolicyValue) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CrossOriginEmbedderPolicyValue(s) {\n\tcase CrossOriginEmbedderPolicyValueNone:\n\t\t*t = CrossOriginEmbedderPolicyValueNone\n\tcase CrossOriginEmbedderPolicyValueCredentialless:\n\t\t*t = CrossOriginEmbedderPolicyValueCredentialless\n\tcase CrossOriginEmbedderPolicyValueRequireCorp:\n\t\t*t = CrossOriginEmbedderPolicyValueRequireCorp\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CrossOriginEmbedderPolicyValue value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CrossOriginEmbedderPolicyStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-CrossOriginEmbedderPolicyStatus\ntype CrossOriginEmbedderPolicyStatus struct {\n\tValue                       CrossOriginEmbedderPolicyValue `json:\"value\"`\n\tReportOnlyValue             CrossOriginEmbedderPolicyValue `json:\"reportOnlyValue\"`\n\tReportingEndpoint           string                         `json:\"reportingEndpoint,omitempty,omitzero\"`\n\tReportOnlyReportingEndpoint string                         `json:\"reportOnlyReportingEndpoint,omitempty,omitzero\"`\n}\n\n// ContentSecurityPolicySource [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ContentSecurityPolicySource\ntype ContentSecurityPolicySource string\n\n// String returns the ContentSecurityPolicySource as string value.\nfunc (t ContentSecurityPolicySource) String() string {\n\treturn string(t)\n}\n\n// ContentSecurityPolicySource values.\nconst (\n\tContentSecurityPolicySourceHTTP ContentSecurityPolicySource = \"HTTP\"\n\tContentSecurityPolicySourceMeta ContentSecurityPolicySource = \"Meta\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ContentSecurityPolicySource) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ContentSecurityPolicySource(s) {\n\tcase ContentSecurityPolicySourceHTTP:\n\t\t*t = ContentSecurityPolicySourceHTTP\n\tcase ContentSecurityPolicySourceMeta:\n\t\t*t = ContentSecurityPolicySourceMeta\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ContentSecurityPolicySource value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ContentSecurityPolicyStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ContentSecurityPolicyStatus\ntype ContentSecurityPolicyStatus struct {\n\tEffectiveDirectives string                      `json:\"effectiveDirectives\"`\n\tIsEnforced          bool                        `json:\"isEnforced\"`\n\tSource              ContentSecurityPolicySource `json:\"source\"`\n}\n\n// SecurityIsolationStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-SecurityIsolationStatus\ntype SecurityIsolationStatus struct {\n\tCoop *CrossOriginOpenerPolicyStatus   `json:\"coop,omitempty,omitzero\"`\n\tCoep *CrossOriginEmbedderPolicyStatus `json:\"coep,omitempty,omitzero\"`\n\tCsp  []*ContentSecurityPolicyStatus   `json:\"csp,omitempty,omitzero\"`\n}\n\n// ReportStatus the status of a Reporting API report.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ReportStatus\ntype ReportStatus string\n\n// String returns the ReportStatus as string value.\nfunc (t ReportStatus) String() string {\n\treturn string(t)\n}\n\n// ReportStatus values.\nconst (\n\tReportStatusQueued           ReportStatus = \"Queued\"\n\tReportStatusPending          ReportStatus = \"Pending\"\n\tReportStatusMarkedForRemoval ReportStatus = \"MarkedForRemoval\"\n\tReportStatusSuccess          ReportStatus = \"Success\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ReportStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ReportStatus(s) {\n\tcase ReportStatusQueued:\n\t\t*t = ReportStatusQueued\n\tcase ReportStatusPending:\n\t\t*t = ReportStatusPending\n\tcase ReportStatusMarkedForRemoval:\n\t\t*t = ReportStatusMarkedForRemoval\n\tcase ReportStatusSuccess:\n\t\t*t = ReportStatusSuccess\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ReportStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ReportID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ReportId\ntype ReportID string\n\n// String returns the ReportID as string value.\nfunc (t ReportID) String() string {\n\treturn string(t)\n}\n\n// ReportingAPIReport an object representing a report generated by the\n// Reporting API.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ReportingApiReport\ntype ReportingAPIReport struct {\n\tID                ReportID            `json:\"id\"`\n\tInitiatorURL      string              `json:\"initiatorUrl\"`      // The URL of the document that triggered the report.\n\tDestination       string              `json:\"destination\"`       // The name of the endpoint group that should be used to deliver the report.\n\tType              string              `json:\"type\"`              // The type of the report (specifies the set of data that is contained in the report body).\n\tTimestamp         *cdp.TimeSinceEpoch `json:\"timestamp\"`         // When the report was generated.\n\tDepth             int64               `json:\"depth\"`             // How many uploads deep the related request was.\n\tCompletedAttempts int64               `json:\"completedAttempts\"` // The number of delivery attempts made so far, not including an active attempt.\n\tBody              jsontext.Value      `json:\"body\"`\n\tStatus            ReportStatus        `json:\"status\"`\n}\n\n// ReportingAPIEndpoint [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ReportingApiEndpoint\ntype ReportingAPIEndpoint struct {\n\tURL       string `json:\"url\"`       // The URL of the endpoint to which reports may be delivered.\n\tGroupName string `json:\"groupName\"` // Name of the endpoint group.\n}\n\n// LoadNetworkResourcePageResult an object providing the result of a network\n// resource load.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-LoadNetworkResourcePageResult\ntype LoadNetworkResourcePageResult struct {\n\tSuccess        bool            `json:\"success\"`\n\tNetError       float64         `json:\"netError,omitempty,omitzero\"` // Optional values used for error reporting.\n\tNetErrorName   string          `json:\"netErrorName,omitempty,omitzero\"`\n\tHTTPStatusCode float64         `json:\"httpStatusCode,omitempty,omitzero\"`\n\tStream         io.StreamHandle `json:\"stream,omitempty,omitzero\"`  // If successful, one of the following two fields holds the result.\n\tHeaders        Headers         `json:\"headers,omitempty,omitzero\"` // Response headers.\n}\n\n// LoadNetworkResourceOptions an options object that may be extended later to\n// better support CORS, CORB and streaming.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-LoadNetworkResourceOptions\ntype LoadNetworkResourceOptions struct {\n\tDisableCache       bool `json:\"disableCache\"`\n\tIncludeCredentials bool `json:\"includeCredentials\"`\n}\n\n// ReferrerPolicy the referrer policy of the request, as defined in\n// https://www.w3.org/TR/referrer-policy/.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-Request\ntype ReferrerPolicy string\n\n// String returns the ReferrerPolicy as string value.\nfunc (t ReferrerPolicy) String() string {\n\treturn string(t)\n}\n\n// ReferrerPolicy values.\nconst (\n\tReferrerPolicyUnsafeURL                   ReferrerPolicy = \"unsafe-url\"\n\tReferrerPolicyNoReferrerWhenDowngrade     ReferrerPolicy = \"no-referrer-when-downgrade\"\n\tReferrerPolicyNoReferrer                  ReferrerPolicy = \"no-referrer\"\n\tReferrerPolicyOrigin                      ReferrerPolicy = \"origin\"\n\tReferrerPolicyOriginWhenCrossOrigin       ReferrerPolicy = \"origin-when-cross-origin\"\n\tReferrerPolicySameOrigin                  ReferrerPolicy = \"same-origin\"\n\tReferrerPolicyStrictOrigin                ReferrerPolicy = \"strict-origin\"\n\tReferrerPolicyStrictOriginWhenCrossOrigin ReferrerPolicy = \"strict-origin-when-cross-origin\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ReferrerPolicy) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ReferrerPolicy(s) {\n\tcase ReferrerPolicyUnsafeURL:\n\t\t*t = ReferrerPolicyUnsafeURL\n\tcase ReferrerPolicyNoReferrerWhenDowngrade:\n\t\t*t = ReferrerPolicyNoReferrerWhenDowngrade\n\tcase ReferrerPolicyNoReferrer:\n\t\t*t = ReferrerPolicyNoReferrer\n\tcase ReferrerPolicyOrigin:\n\t\t*t = ReferrerPolicyOrigin\n\tcase ReferrerPolicyOriginWhenCrossOrigin:\n\t\t*t = ReferrerPolicyOriginWhenCrossOrigin\n\tcase ReferrerPolicySameOrigin:\n\t\t*t = ReferrerPolicySameOrigin\n\tcase ReferrerPolicyStrictOrigin:\n\t\t*t = ReferrerPolicyStrictOrigin\n\tcase ReferrerPolicyStrictOriginWhenCrossOrigin:\n\t\t*t = ReferrerPolicyStrictOriginWhenCrossOrigin\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ReferrerPolicy value: %v\", s)\n\t}\n\treturn nil\n}\n\n// TrustTokenParamsRefreshPolicy only set for \"token-redemption\" operation\n// and determine whether to request a fresh SRR or use a still valid cached SRR.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-TrustTokenParams\ntype TrustTokenParamsRefreshPolicy string\n\n// String returns the TrustTokenParamsRefreshPolicy as string value.\nfunc (t TrustTokenParamsRefreshPolicy) String() string {\n\treturn string(t)\n}\n\n// TrustTokenParamsRefreshPolicy values.\nconst (\n\tTrustTokenParamsRefreshPolicyUseCached TrustTokenParamsRefreshPolicy = \"UseCached\"\n\tTrustTokenParamsRefreshPolicyRefresh   TrustTokenParamsRefreshPolicy = \"Refresh\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TrustTokenParamsRefreshPolicy) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch TrustTokenParamsRefreshPolicy(s) {\n\tcase TrustTokenParamsRefreshPolicyUseCached:\n\t\t*t = TrustTokenParamsRefreshPolicyUseCached\n\tcase TrustTokenParamsRefreshPolicyRefresh:\n\t\t*t = TrustTokenParamsRefreshPolicyRefresh\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown TrustTokenParamsRefreshPolicy value: %v\", s)\n\t}\n\treturn nil\n}\n\n// InitiatorType type of this initiator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-Initiator\ntype InitiatorType string\n\n// String returns the InitiatorType as string value.\nfunc (t InitiatorType) String() string {\n\treturn string(t)\n}\n\n// InitiatorType values.\nconst (\n\tInitiatorTypeParser         InitiatorType = \"parser\"\n\tInitiatorTypeScript         InitiatorType = \"script\"\n\tInitiatorTypePreload        InitiatorType = \"preload\"\n\tInitiatorTypeSignedExchange InitiatorType = \"SignedExchange\"\n\tInitiatorTypePreflight      InitiatorType = \"preflight\"\n\tInitiatorTypeOther          InitiatorType = \"other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InitiatorType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InitiatorType(s) {\n\tcase InitiatorTypeParser:\n\t\t*t = InitiatorTypeParser\n\tcase InitiatorTypeScript:\n\t\t*t = InitiatorTypeScript\n\tcase InitiatorTypePreload:\n\t\t*t = InitiatorTypePreload\n\tcase InitiatorTypeSignedExchange:\n\t\t*t = InitiatorTypeSignedExchange\n\tcase InitiatorTypePreflight:\n\t\t*t = InitiatorTypePreflight\n\tcase InitiatorTypeOther:\n\t\t*t = InitiatorTypeOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InitiatorType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AuthChallengeSource source of the authentication challenge.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-AuthChallenge\ntype AuthChallengeSource string\n\n// String returns the AuthChallengeSource as string value.\nfunc (t AuthChallengeSource) String() string {\n\treturn string(t)\n}\n\n// AuthChallengeSource values.\nconst (\n\tAuthChallengeSourceServer AuthChallengeSource = \"Server\"\n\tAuthChallengeSourceProxy  AuthChallengeSource = \"Proxy\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AuthChallengeSource) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AuthChallengeSource(s) {\n\tcase AuthChallengeSourceServer:\n\t\t*t = AuthChallengeSourceServer\n\tcase AuthChallengeSourceProxy:\n\t\t*t = AuthChallengeSourceProxy\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AuthChallengeSource value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AuthChallengeResponseResponse the decision on what to do in response to\n// the authorization challenge. Default means deferring to the default behavior\n// of the net stack, which will likely either the Cancel authentication or\n// display a popup dialog box.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#type-AuthChallengeResponse\ntype AuthChallengeResponseResponse string\n\n// String returns the AuthChallengeResponseResponse as string value.\nfunc (t AuthChallengeResponseResponse) String() string {\n\treturn string(t)\n}\n\n// AuthChallengeResponseResponse values.\nconst (\n\tAuthChallengeResponseResponseDefault            AuthChallengeResponseResponse = \"Default\"\n\tAuthChallengeResponseResponseCancelAuth         AuthChallengeResponseResponse = \"CancelAuth\"\n\tAuthChallengeResponseResponseProvideCredentials AuthChallengeResponseResponse = \"ProvideCredentials\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AuthChallengeResponseResponse) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AuthChallengeResponseResponse(s) {\n\tcase AuthChallengeResponseResponseDefault:\n\t\t*t = AuthChallengeResponseResponseDefault\n\tcase AuthChallengeResponseResponseCancelAuth:\n\t\t*t = AuthChallengeResponseResponseCancelAuth\n\tcase AuthChallengeResponseResponseProvideCredentials:\n\t\t*t = AuthChallengeResponseResponseProvideCredentials\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AuthChallengeResponseResponse value: %v\", s)\n\t}\n\treturn nil\n}\n\n// TrustTokenOperationDoneStatus detailed success or error status of the\n// operation. 'AlreadyExists' also signifies a successful operation, as the\n// result of the operation already exists und thus, the operation was abort\n// preemptively (e.g. a cache hit).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Network#event-trustTokenOperationDone\ntype TrustTokenOperationDoneStatus string\n\n// String returns the TrustTokenOperationDoneStatus as string value.\nfunc (t TrustTokenOperationDoneStatus) String() string {\n\treturn string(t)\n}\n\n// TrustTokenOperationDoneStatus values.\nconst (\n\tTrustTokenOperationDoneStatusOk                 TrustTokenOperationDoneStatus = \"Ok\"\n\tTrustTokenOperationDoneStatusInvalidArgument    TrustTokenOperationDoneStatus = \"InvalidArgument\"\n\tTrustTokenOperationDoneStatusMissingIssuerKeys  TrustTokenOperationDoneStatus = \"MissingIssuerKeys\"\n\tTrustTokenOperationDoneStatusFailedPrecondition TrustTokenOperationDoneStatus = \"FailedPrecondition\"\n\tTrustTokenOperationDoneStatusResourceExhausted  TrustTokenOperationDoneStatus = \"ResourceExhausted\"\n\tTrustTokenOperationDoneStatusAlreadyExists      TrustTokenOperationDoneStatus = \"AlreadyExists\"\n\tTrustTokenOperationDoneStatusResourceLimited    TrustTokenOperationDoneStatus = \"ResourceLimited\"\n\tTrustTokenOperationDoneStatusUnauthorized       TrustTokenOperationDoneStatus = \"Unauthorized\"\n\tTrustTokenOperationDoneStatusBadResponse        TrustTokenOperationDoneStatus = \"BadResponse\"\n\tTrustTokenOperationDoneStatusInternalError      TrustTokenOperationDoneStatus = \"InternalError\"\n\tTrustTokenOperationDoneStatusUnknownError       TrustTokenOperationDoneStatus = \"UnknownError\"\n\tTrustTokenOperationDoneStatusFulfilledLocally   TrustTokenOperationDoneStatus = \"FulfilledLocally\"\n\tTrustTokenOperationDoneStatusSiteIssuerLimit    TrustTokenOperationDoneStatus = \"SiteIssuerLimit\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TrustTokenOperationDoneStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch TrustTokenOperationDoneStatus(s) {\n\tcase TrustTokenOperationDoneStatusOk:\n\t\t*t = TrustTokenOperationDoneStatusOk\n\tcase TrustTokenOperationDoneStatusInvalidArgument:\n\t\t*t = TrustTokenOperationDoneStatusInvalidArgument\n\tcase TrustTokenOperationDoneStatusMissingIssuerKeys:\n\t\t*t = TrustTokenOperationDoneStatusMissingIssuerKeys\n\tcase TrustTokenOperationDoneStatusFailedPrecondition:\n\t\t*t = TrustTokenOperationDoneStatusFailedPrecondition\n\tcase TrustTokenOperationDoneStatusResourceExhausted:\n\t\t*t = TrustTokenOperationDoneStatusResourceExhausted\n\tcase TrustTokenOperationDoneStatusAlreadyExists:\n\t\t*t = TrustTokenOperationDoneStatusAlreadyExists\n\tcase TrustTokenOperationDoneStatusResourceLimited:\n\t\t*t = TrustTokenOperationDoneStatusResourceLimited\n\tcase TrustTokenOperationDoneStatusUnauthorized:\n\t\t*t = TrustTokenOperationDoneStatusUnauthorized\n\tcase TrustTokenOperationDoneStatusBadResponse:\n\t\t*t = TrustTokenOperationDoneStatusBadResponse\n\tcase TrustTokenOperationDoneStatusInternalError:\n\t\t*t = TrustTokenOperationDoneStatusInternalError\n\tcase TrustTokenOperationDoneStatusUnknownError:\n\t\t*t = TrustTokenOperationDoneStatusUnknownError\n\tcase TrustTokenOperationDoneStatusFulfilledLocally:\n\t\t*t = TrustTokenOperationDoneStatusFulfilledLocally\n\tcase TrustTokenOperationDoneStatusSiteIssuerLimit:\n\t\t*t = TrustTokenOperationDoneStatusSiteIssuerLimit\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown TrustTokenOperationDoneStatus value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/overlay/events.go",
    "content": "package overlay\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/page\"\n)\n\n// EventInspectNodeRequested fired when the node should be inspected. This\n// happens after call to setInspectMode or when user manually inspects an\n// element.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#event-inspectNodeRequested\ntype EventInspectNodeRequested struct {\n\tBackendNodeID cdp.BackendNodeID `json:\"backendNodeId\"` // Id of the node to inspect.\n}\n\n// EventNodeHighlightRequested fired when the node should be highlighted.\n// This happens after call to setInspectMode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#event-nodeHighlightRequested\ntype EventNodeHighlightRequested struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"`\n}\n\n// EventScreenshotRequested fired when user asks to capture screenshot of\n// some area on the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#event-screenshotRequested\ntype EventScreenshotRequested struct {\n\tViewport *page.Viewport `json:\"viewport\"` // Viewport to capture, in device independent pixels (dip).\n}\n\n// EventInspectModeCanceled fired when user cancels the inspect mode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#event-inspectModeCanceled\ntype EventInspectModeCanceled struct{}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/overlay/overlay.go",
    "content": "// Package overlay provides the Chrome DevTools Protocol\n// commands, types, and events for the Overlay domain.\n//\n// This domain provides various functionality related to drawing atop the\n// inspected page.\n//\n// Generated by the cdproto-gen command.\npackage overlay\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/chromedp/cdproto/runtime\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// DisableParams disables domain notifications.\ntype DisableParams struct{}\n\n// Disable disables domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Overlay.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables domain notifications.\ntype EnableParams struct{}\n\n// Enable enables domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Overlay.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// GetHighlightObjectForTestParams for testing.\ntype GetHighlightObjectForTestParams struct {\n\tNodeID                cdp.NodeID  `json:\"nodeId\"`                         // Id of the node to get highlight object for.\n\tIncludeDistance       bool        `json:\"includeDistance\"`                // Whether to include distance info.\n\tIncludeStyle          bool        `json:\"includeStyle\"`                   // Whether to include style info.\n\tColorFormat           ColorFormat `json:\"colorFormat,omitempty,omitzero\"` // The color format to get config with (default: hex).\n\tShowAccessibilityInfo bool        `json:\"showAccessibilityInfo\"`          // Whether to show accessibility info (default: true).\n}\n\n// GetHighlightObjectForTest for testing.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-getHighlightObjectForTest\n//\n// parameters:\n//\n//\tnodeID - Id of the node to get highlight object for.\nfunc GetHighlightObjectForTest(nodeID cdp.NodeID) *GetHighlightObjectForTestParams {\n\treturn &GetHighlightObjectForTestParams{\n\t\tNodeID:                nodeID,\n\t\tIncludeDistance:       false,\n\t\tIncludeStyle:          false,\n\t\tShowAccessibilityInfo: true,\n\t}\n}\n\n// WithIncludeDistance whether to include distance info.\nfunc (p GetHighlightObjectForTestParams) WithIncludeDistance(includeDistance bool) *GetHighlightObjectForTestParams {\n\tp.IncludeDistance = includeDistance\n\treturn &p\n}\n\n// WithIncludeStyle whether to include style info.\nfunc (p GetHighlightObjectForTestParams) WithIncludeStyle(includeStyle bool) *GetHighlightObjectForTestParams {\n\tp.IncludeStyle = includeStyle\n\treturn &p\n}\n\n// WithColorFormat the color format to get config with (default: hex).\nfunc (p GetHighlightObjectForTestParams) WithColorFormat(colorFormat ColorFormat) *GetHighlightObjectForTestParams {\n\tp.ColorFormat = colorFormat\n\treturn &p\n}\n\n// WithShowAccessibilityInfo whether to show accessibility info (default:\n// true).\nfunc (p GetHighlightObjectForTestParams) WithShowAccessibilityInfo(showAccessibilityInfo bool) *GetHighlightObjectForTestParams {\n\tp.ShowAccessibilityInfo = showAccessibilityInfo\n\treturn &p\n}\n\n// GetHighlightObjectForTestReturns return values.\ntype GetHighlightObjectForTestReturns struct {\n\tHighlight jsontext.Value `json:\"highlight,omitempty,omitzero\"`\n}\n\n// Do executes Overlay.getHighlightObjectForTest against the provided context.\n//\n// returns:\n//\n//\thighlight - Highlight data for the node.\nfunc (p *GetHighlightObjectForTestParams) Do(ctx context.Context) (highlight jsontext.Value, err error) {\n\t// execute\n\tvar res GetHighlightObjectForTestReturns\n\terr = cdp.Execute(ctx, CommandGetHighlightObjectForTest, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Highlight, nil\n}\n\n// GetGridHighlightObjectsForTestParams for Persistent Grid testing.\ntype GetGridHighlightObjectsForTestParams struct {\n\tNodeIDs []cdp.NodeID `json:\"nodeIds\"` // Ids of the node to get highlight object for.\n}\n\n// GetGridHighlightObjectsForTest for Persistent Grid testing.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-getGridHighlightObjectsForTest\n//\n// parameters:\n//\n//\tnodeIDs - Ids of the node to get highlight object for.\nfunc GetGridHighlightObjectsForTest(nodeIDs []cdp.NodeID) *GetGridHighlightObjectsForTestParams {\n\treturn &GetGridHighlightObjectsForTestParams{\n\t\tNodeIDs: nodeIDs,\n\t}\n}\n\n// GetGridHighlightObjectsForTestReturns return values.\ntype GetGridHighlightObjectsForTestReturns struct {\n\tHighlights jsontext.Value `json:\"highlights,omitempty,omitzero\"`\n}\n\n// Do executes Overlay.getGridHighlightObjectsForTest against the provided context.\n//\n// returns:\n//\n//\thighlights - Grid Highlight data for the node ids provided.\nfunc (p *GetGridHighlightObjectsForTestParams) Do(ctx context.Context) (highlights jsontext.Value, err error) {\n\t// execute\n\tvar res GetGridHighlightObjectsForTestReturns\n\terr = cdp.Execute(ctx, CommandGetGridHighlightObjectsForTest, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Highlights, nil\n}\n\n// GetSourceOrderHighlightObjectForTestParams for Source Order Viewer\n// testing.\ntype GetSourceOrderHighlightObjectForTestParams struct {\n\tNodeID cdp.NodeID `json:\"nodeId\"` // Id of the node to highlight.\n}\n\n// GetSourceOrderHighlightObjectForTest for Source Order Viewer testing.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-getSourceOrderHighlightObjectForTest\n//\n// parameters:\n//\n//\tnodeID - Id of the node to highlight.\nfunc GetSourceOrderHighlightObjectForTest(nodeID cdp.NodeID) *GetSourceOrderHighlightObjectForTestParams {\n\treturn &GetSourceOrderHighlightObjectForTestParams{\n\t\tNodeID: nodeID,\n\t}\n}\n\n// GetSourceOrderHighlightObjectForTestReturns return values.\ntype GetSourceOrderHighlightObjectForTestReturns struct {\n\tHighlight jsontext.Value `json:\"highlight,omitempty,omitzero\"`\n}\n\n// Do executes Overlay.getSourceOrderHighlightObjectForTest against the provided context.\n//\n// returns:\n//\n//\thighlight - Source order highlight data for the node id provided.\nfunc (p *GetSourceOrderHighlightObjectForTestParams) Do(ctx context.Context) (highlight jsontext.Value, err error) {\n\t// execute\n\tvar res GetSourceOrderHighlightObjectForTestReturns\n\terr = cdp.Execute(ctx, CommandGetSourceOrderHighlightObjectForTest, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Highlight, nil\n}\n\n// HideHighlightParams hides any highlight.\ntype HideHighlightParams struct{}\n\n// HideHighlight hides any highlight.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-hideHighlight\nfunc HideHighlight() *HideHighlightParams {\n\treturn &HideHighlightParams{}\n}\n\n// Do executes Overlay.hideHighlight against the provided context.\nfunc (p *HideHighlightParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandHideHighlight, nil, nil)\n}\n\n// HighlightNodeParams highlights DOM node with given id or with the given\n// JavaScript object wrapper. Either nodeId or objectId must be specified.\ntype HighlightNodeParams struct {\n\tHighlightConfig *HighlightConfig       `json:\"highlightConfig\"`                  // A descriptor for the highlight appearance.\n\tNodeID          cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node to highlight.\n\tBackendNodeID   cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node to highlight.\n\tObjectID        runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node to be highlighted.\n\tSelector        string                 `json:\"selector,omitempty,omitzero\"`      // Selectors to highlight relevant nodes.\n}\n\n// HighlightNode highlights DOM node with given id or with the given\n// JavaScript object wrapper. Either nodeId or objectId must be specified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-highlightNode\n//\n// parameters:\n//\n//\thighlightConfig - A descriptor for the highlight appearance.\nfunc HighlightNode(highlightConfig *HighlightConfig) *HighlightNodeParams {\n\treturn &HighlightNodeParams{\n\t\tHighlightConfig: highlightConfig,\n\t}\n}\n\n// WithNodeID identifier of the node to highlight.\nfunc (p HighlightNodeParams) WithNodeID(nodeID cdp.NodeID) *HighlightNodeParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node to highlight.\nfunc (p HighlightNodeParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *HighlightNodeParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node to be highlighted.\nfunc (p HighlightNodeParams) WithObjectID(objectID runtime.RemoteObjectID) *HighlightNodeParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// WithSelector selectors to highlight relevant nodes.\nfunc (p HighlightNodeParams) WithSelector(selector string) *HighlightNodeParams {\n\tp.Selector = selector\n\treturn &p\n}\n\n// Do executes Overlay.highlightNode against the provided context.\nfunc (p *HighlightNodeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandHighlightNode, p, nil)\n}\n\n// HighlightQuadParams highlights given quad. Coordinates are absolute with\n// respect to the main frame viewport.\ntype HighlightQuadParams struct {\n\tQuad         dom.Quad  `json:\"quad\"`                            // Quad to highlight\n\tColor        *cdp.RGBA `json:\"color,omitempty,omitzero\"`        // The highlight fill color (default: transparent).\n\tOutlineColor *cdp.RGBA `json:\"outlineColor,omitempty,omitzero\"` // The highlight outline color (default: transparent).\n}\n\n// HighlightQuad highlights given quad. Coordinates are absolute with respect\n// to the main frame viewport.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-highlightQuad\n//\n// parameters:\n//\n//\tquad - Quad to highlight\nfunc HighlightQuad(quad dom.Quad) *HighlightQuadParams {\n\treturn &HighlightQuadParams{\n\t\tQuad: quad,\n\t}\n}\n\n// WithColor the highlight fill color (default: transparent).\nfunc (p HighlightQuadParams) WithColor(color *cdp.RGBA) *HighlightQuadParams {\n\tp.Color = color\n\treturn &p\n}\n\n// WithOutlineColor the highlight outline color (default: transparent).\nfunc (p HighlightQuadParams) WithOutlineColor(outlineColor *cdp.RGBA) *HighlightQuadParams {\n\tp.OutlineColor = outlineColor\n\treturn &p\n}\n\n// Do executes Overlay.highlightQuad against the provided context.\nfunc (p *HighlightQuadParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandHighlightQuad, p, nil)\n}\n\n// HighlightRectParams highlights given rectangle. Coordinates are absolute\n// with respect to the main frame viewport.\ntype HighlightRectParams struct {\n\tX            int64     `json:\"x\"`                               // X coordinate\n\tY            int64     `json:\"y\"`                               // Y coordinate\n\tWidth        int64     `json:\"width\"`                           // Rectangle width\n\tHeight       int64     `json:\"height\"`                          // Rectangle height\n\tColor        *cdp.RGBA `json:\"color,omitempty,omitzero\"`        // The highlight fill color (default: transparent).\n\tOutlineColor *cdp.RGBA `json:\"outlineColor,omitempty,omitzero\"` // The highlight outline color (default: transparent).\n}\n\n// HighlightRect highlights given rectangle. Coordinates are absolute with\n// respect to the main frame viewport.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-highlightRect\n//\n// parameters:\n//\n//\tx - X coordinate\n//\ty - Y coordinate\n//\twidth - Rectangle width\n//\theight - Rectangle height\nfunc HighlightRect(x int64, y int64, width int64, height int64) *HighlightRectParams {\n\treturn &HighlightRectParams{\n\t\tX:      x,\n\t\tY:      y,\n\t\tWidth:  width,\n\t\tHeight: height,\n\t}\n}\n\n// WithColor the highlight fill color (default: transparent).\nfunc (p HighlightRectParams) WithColor(color *cdp.RGBA) *HighlightRectParams {\n\tp.Color = color\n\treturn &p\n}\n\n// WithOutlineColor the highlight outline color (default: transparent).\nfunc (p HighlightRectParams) WithOutlineColor(outlineColor *cdp.RGBA) *HighlightRectParams {\n\tp.OutlineColor = outlineColor\n\treturn &p\n}\n\n// Do executes Overlay.highlightRect against the provided context.\nfunc (p *HighlightRectParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandHighlightRect, p, nil)\n}\n\n// HighlightSourceOrderParams highlights the source order of the children of\n// the DOM node with given id or with the given JavaScript object wrapper.\n// Either nodeId or objectId must be specified.\ntype HighlightSourceOrderParams struct {\n\tSourceOrderConfig *SourceOrderConfig     `json:\"sourceOrderConfig\"`                // A descriptor for the appearance of the overlay drawing.\n\tNodeID            cdp.NodeID             `json:\"nodeId,omitempty,omitzero\"`        // Identifier of the node to highlight.\n\tBackendNodeID     cdp.BackendNodeID      `json:\"backendNodeId,omitempty,omitzero\"` // Identifier of the backend node to highlight.\n\tObjectID          runtime.RemoteObjectID `json:\"objectId,omitempty,omitzero\"`      // JavaScript object id of the node to be highlighted.\n}\n\n// HighlightSourceOrder highlights the source order of the children of the\n// DOM node with given id or with the given JavaScript object wrapper. Either\n// nodeId or objectId must be specified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-highlightSourceOrder\n//\n// parameters:\n//\n//\tsourceOrderConfig - A descriptor for the appearance of the overlay drawing.\nfunc HighlightSourceOrder(sourceOrderConfig *SourceOrderConfig) *HighlightSourceOrderParams {\n\treturn &HighlightSourceOrderParams{\n\t\tSourceOrderConfig: sourceOrderConfig,\n\t}\n}\n\n// WithNodeID identifier of the node to highlight.\nfunc (p HighlightSourceOrderParams) WithNodeID(nodeID cdp.NodeID) *HighlightSourceOrderParams {\n\tp.NodeID = nodeID\n\treturn &p\n}\n\n// WithBackendNodeID identifier of the backend node to highlight.\nfunc (p HighlightSourceOrderParams) WithBackendNodeID(backendNodeID cdp.BackendNodeID) *HighlightSourceOrderParams {\n\tp.BackendNodeID = backendNodeID\n\treturn &p\n}\n\n// WithObjectID JavaScript object id of the node to be highlighted.\nfunc (p HighlightSourceOrderParams) WithObjectID(objectID runtime.RemoteObjectID) *HighlightSourceOrderParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// Do executes Overlay.highlightSourceOrder against the provided context.\nfunc (p *HighlightSourceOrderParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandHighlightSourceOrder, p, nil)\n}\n\n// SetInspectModeParams enters the 'inspect' mode. In this mode, elements\n// that user is hovering over are highlighted. Backend then generates\n// 'inspectNodeRequested' event upon element selection.\ntype SetInspectModeParams struct {\n\tMode            InspectMode      `json:\"mode\"`                               // Set an inspection mode.\n\tHighlightConfig *HighlightConfig `json:\"highlightConfig,omitempty,omitzero\"` // A descriptor for the highlight appearance of hovered-over nodes. May be omitted if enabled == false.\n}\n\n// SetInspectMode enters the 'inspect' mode. In this mode, elements that user\n// is hovering over are highlighted. Backend then generates\n// 'inspectNodeRequested' event upon element selection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setInspectMode\n//\n// parameters:\n//\n//\tmode - Set an inspection mode.\nfunc SetInspectMode(mode InspectMode) *SetInspectModeParams {\n\treturn &SetInspectModeParams{\n\t\tMode: mode,\n\t}\n}\n\n// WithHighlightConfig a descriptor for the highlight appearance of\n// hovered-over nodes. May be omitted if enabled == false.\nfunc (p SetInspectModeParams) WithHighlightConfig(highlightConfig *HighlightConfig) *SetInspectModeParams {\n\tp.HighlightConfig = highlightConfig\n\treturn &p\n}\n\n// Do executes Overlay.setInspectMode against the provided context.\nfunc (p *SetInspectModeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetInspectMode, p, nil)\n}\n\n// SetShowAdHighlightsParams highlights owner element of all frames detected\n// to be ads.\ntype SetShowAdHighlightsParams struct {\n\tShow bool `json:\"show\"` // True for showing ad highlights\n}\n\n// SetShowAdHighlights highlights owner element of all frames detected to be\n// ads.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowAdHighlights\n//\n// parameters:\n//\n//\tshow - True for showing ad highlights\nfunc SetShowAdHighlights(show bool) *SetShowAdHighlightsParams {\n\treturn &SetShowAdHighlightsParams{\n\t\tShow: show,\n\t}\n}\n\n// Do executes Overlay.setShowAdHighlights against the provided context.\nfunc (p *SetShowAdHighlightsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowAdHighlights, p, nil)\n}\n\n// SetPausedInDebuggerMessageParams [no description].\ntype SetPausedInDebuggerMessageParams struct {\n\tMessage string `json:\"message,omitempty,omitzero\"` // The message to display, also triggers resume and step over controls.\n}\n\n// SetPausedInDebuggerMessage [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setPausedInDebuggerMessage\n//\n// parameters:\nfunc SetPausedInDebuggerMessage() *SetPausedInDebuggerMessageParams {\n\treturn &SetPausedInDebuggerMessageParams{}\n}\n\n// WithMessage the message to display, also triggers resume and step over\n// controls.\nfunc (p SetPausedInDebuggerMessageParams) WithMessage(message string) *SetPausedInDebuggerMessageParams {\n\tp.Message = message\n\treturn &p\n}\n\n// Do executes Overlay.setPausedInDebuggerMessage against the provided context.\nfunc (p *SetPausedInDebuggerMessageParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPausedInDebuggerMessage, p, nil)\n}\n\n// SetShowDebugBordersParams requests that backend shows debug borders on\n// layers.\ntype SetShowDebugBordersParams struct {\n\tShow bool `json:\"show\"` // True for showing debug borders\n}\n\n// SetShowDebugBorders requests that backend shows debug borders on layers.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowDebugBorders\n//\n// parameters:\n//\n//\tshow - True for showing debug borders\nfunc SetShowDebugBorders(show bool) *SetShowDebugBordersParams {\n\treturn &SetShowDebugBordersParams{\n\t\tShow: show,\n\t}\n}\n\n// Do executes Overlay.setShowDebugBorders against the provided context.\nfunc (p *SetShowDebugBordersParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowDebugBorders, p, nil)\n}\n\n// SetShowFPSCounterParams requests that backend shows the FPS counter.\ntype SetShowFPSCounterParams struct {\n\tShow bool `json:\"show\"` // True for showing the FPS counter\n}\n\n// SetShowFPSCounter requests that backend shows the FPS counter.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowFPSCounter\n//\n// parameters:\n//\n//\tshow - True for showing the FPS counter\nfunc SetShowFPSCounter(show bool) *SetShowFPSCounterParams {\n\treturn &SetShowFPSCounterParams{\n\t\tShow: show,\n\t}\n}\n\n// Do executes Overlay.setShowFPSCounter against the provided context.\nfunc (p *SetShowFPSCounterParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowFPSCounter, p, nil)\n}\n\n// SetShowGridOverlaysParams highlight multiple elements with the CSS Grid\n// overlay.\ntype SetShowGridOverlaysParams struct {\n\tGridNodeHighlightConfigs []*GridNodeHighlightConfig `json:\"gridNodeHighlightConfigs\"` // An array of node identifiers and descriptors for the highlight appearance.\n}\n\n// SetShowGridOverlays highlight multiple elements with the CSS Grid overlay.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowGridOverlays\n//\n// parameters:\n//\n//\tgridNodeHighlightConfigs - An array of node identifiers and descriptors for the highlight appearance.\nfunc SetShowGridOverlays(gridNodeHighlightConfigs []*GridNodeHighlightConfig) *SetShowGridOverlaysParams {\n\treturn &SetShowGridOverlaysParams{\n\t\tGridNodeHighlightConfigs: gridNodeHighlightConfigs,\n\t}\n}\n\n// Do executes Overlay.setShowGridOverlays against the provided context.\nfunc (p *SetShowGridOverlaysParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowGridOverlays, p, nil)\n}\n\n// SetShowFlexOverlaysParams [no description].\ntype SetShowFlexOverlaysParams struct {\n\tFlexNodeHighlightConfigs []*FlexNodeHighlightConfig `json:\"flexNodeHighlightConfigs\"` // An array of node identifiers and descriptors for the highlight appearance.\n}\n\n// SetShowFlexOverlays [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowFlexOverlays\n//\n// parameters:\n//\n//\tflexNodeHighlightConfigs - An array of node identifiers and descriptors for the highlight appearance.\nfunc SetShowFlexOverlays(flexNodeHighlightConfigs []*FlexNodeHighlightConfig) *SetShowFlexOverlaysParams {\n\treturn &SetShowFlexOverlaysParams{\n\t\tFlexNodeHighlightConfigs: flexNodeHighlightConfigs,\n\t}\n}\n\n// Do executes Overlay.setShowFlexOverlays against the provided context.\nfunc (p *SetShowFlexOverlaysParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowFlexOverlays, p, nil)\n}\n\n// SetShowScrollSnapOverlaysParams [no description].\ntype SetShowScrollSnapOverlaysParams struct {\n\tScrollSnapHighlightConfigs []*ScrollSnapHighlightConfig `json:\"scrollSnapHighlightConfigs\"` // An array of node identifiers and descriptors for the highlight appearance.\n}\n\n// SetShowScrollSnapOverlays [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowScrollSnapOverlays\n//\n// parameters:\n//\n//\tscrollSnapHighlightConfigs - An array of node identifiers and descriptors for the highlight appearance.\nfunc SetShowScrollSnapOverlays(scrollSnapHighlightConfigs []*ScrollSnapHighlightConfig) *SetShowScrollSnapOverlaysParams {\n\treturn &SetShowScrollSnapOverlaysParams{\n\t\tScrollSnapHighlightConfigs: scrollSnapHighlightConfigs,\n\t}\n}\n\n// Do executes Overlay.setShowScrollSnapOverlays against the provided context.\nfunc (p *SetShowScrollSnapOverlaysParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowScrollSnapOverlays, p, nil)\n}\n\n// SetShowContainerQueryOverlaysParams [no description].\ntype SetShowContainerQueryOverlaysParams struct {\n\tContainerQueryHighlightConfigs []*ContainerQueryHighlightConfig `json:\"containerQueryHighlightConfigs\"` // An array of node identifiers and descriptors for the highlight appearance.\n}\n\n// SetShowContainerQueryOverlays [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowContainerQueryOverlays\n//\n// parameters:\n//\n//\tcontainerQueryHighlightConfigs - An array of node identifiers and descriptors for the highlight appearance.\nfunc SetShowContainerQueryOverlays(containerQueryHighlightConfigs []*ContainerQueryHighlightConfig) *SetShowContainerQueryOverlaysParams {\n\treturn &SetShowContainerQueryOverlaysParams{\n\t\tContainerQueryHighlightConfigs: containerQueryHighlightConfigs,\n\t}\n}\n\n// Do executes Overlay.setShowContainerQueryOverlays against the provided context.\nfunc (p *SetShowContainerQueryOverlaysParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowContainerQueryOverlays, p, nil)\n}\n\n// SetShowPaintRectsParams requests that backend shows paint rectangles.\ntype SetShowPaintRectsParams struct {\n\tResult bool `json:\"result\"` // True for showing paint rectangles\n}\n\n// SetShowPaintRects requests that backend shows paint rectangles.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowPaintRects\n//\n// parameters:\n//\n//\tresult - True for showing paint rectangles\nfunc SetShowPaintRects(result bool) *SetShowPaintRectsParams {\n\treturn &SetShowPaintRectsParams{\n\t\tResult: result,\n\t}\n}\n\n// Do executes Overlay.setShowPaintRects against the provided context.\nfunc (p *SetShowPaintRectsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowPaintRects, p, nil)\n}\n\n// SetShowLayoutShiftRegionsParams requests that backend shows layout shift\n// regions.\ntype SetShowLayoutShiftRegionsParams struct {\n\tResult bool `json:\"result\"` // True for showing layout shift regions\n}\n\n// SetShowLayoutShiftRegions requests that backend shows layout shift\n// regions.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowLayoutShiftRegions\n//\n// parameters:\n//\n//\tresult - True for showing layout shift regions\nfunc SetShowLayoutShiftRegions(result bool) *SetShowLayoutShiftRegionsParams {\n\treturn &SetShowLayoutShiftRegionsParams{\n\t\tResult: result,\n\t}\n}\n\n// Do executes Overlay.setShowLayoutShiftRegions against the provided context.\nfunc (p *SetShowLayoutShiftRegionsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowLayoutShiftRegions, p, nil)\n}\n\n// SetShowScrollBottleneckRectsParams requests that backend shows scroll\n// bottleneck rects.\ntype SetShowScrollBottleneckRectsParams struct {\n\tShow bool `json:\"show\"` // True for showing scroll bottleneck rects\n}\n\n// SetShowScrollBottleneckRects requests that backend shows scroll bottleneck\n// rects.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowScrollBottleneckRects\n//\n// parameters:\n//\n//\tshow - True for showing scroll bottleneck rects\nfunc SetShowScrollBottleneckRects(show bool) *SetShowScrollBottleneckRectsParams {\n\treturn &SetShowScrollBottleneckRectsParams{\n\t\tShow: show,\n\t}\n}\n\n// Do executes Overlay.setShowScrollBottleneckRects against the provided context.\nfunc (p *SetShowScrollBottleneckRectsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowScrollBottleneckRects, p, nil)\n}\n\n// SetShowViewportSizeOnResizeParams paints viewport size upon main frame\n// resize.\ntype SetShowViewportSizeOnResizeParams struct {\n\tShow bool `json:\"show\"` // Whether to paint size or not.\n}\n\n// SetShowViewportSizeOnResize paints viewport size upon main frame resize.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowViewportSizeOnResize\n//\n// parameters:\n//\n//\tshow - Whether to paint size or not.\nfunc SetShowViewportSizeOnResize(show bool) *SetShowViewportSizeOnResizeParams {\n\treturn &SetShowViewportSizeOnResizeParams{\n\t\tShow: show,\n\t}\n}\n\n// Do executes Overlay.setShowViewportSizeOnResize against the provided context.\nfunc (p *SetShowViewportSizeOnResizeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowViewportSizeOnResize, p, nil)\n}\n\n// SetShowHingeParams add a dual screen device hinge.\ntype SetShowHingeParams struct {\n\tHingeConfig *HingeConfig `json:\"hingeConfig,omitempty,omitzero\"` // hinge data, null means hideHinge\n}\n\n// SetShowHinge add a dual screen device hinge.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowHinge\n//\n// parameters:\nfunc SetShowHinge() *SetShowHingeParams {\n\treturn &SetShowHingeParams{}\n}\n\n// WithHingeConfig hinge data, null means hideHinge.\nfunc (p SetShowHingeParams) WithHingeConfig(hingeConfig *HingeConfig) *SetShowHingeParams {\n\tp.HingeConfig = hingeConfig\n\treturn &p\n}\n\n// Do executes Overlay.setShowHinge against the provided context.\nfunc (p *SetShowHingeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowHinge, p, nil)\n}\n\n// SetShowIsolatedElementsParams show elements in isolation mode with\n// overlays.\ntype SetShowIsolatedElementsParams struct {\n\tIsolatedElementHighlightConfigs []*IsolatedElementHighlightConfig `json:\"isolatedElementHighlightConfigs\"` // An array of node identifiers and descriptors for the highlight appearance.\n}\n\n// SetShowIsolatedElements show elements in isolation mode with overlays.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowIsolatedElements\n//\n// parameters:\n//\n//\tisolatedElementHighlightConfigs - An array of node identifiers and descriptors for the highlight appearance.\nfunc SetShowIsolatedElements(isolatedElementHighlightConfigs []*IsolatedElementHighlightConfig) *SetShowIsolatedElementsParams {\n\treturn &SetShowIsolatedElementsParams{\n\t\tIsolatedElementHighlightConfigs: isolatedElementHighlightConfigs,\n\t}\n}\n\n// Do executes Overlay.setShowIsolatedElements against the provided context.\nfunc (p *SetShowIsolatedElementsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowIsolatedElements, p, nil)\n}\n\n// SetShowWindowControlsOverlayParams show Window Controls Overlay for PWA.\ntype SetShowWindowControlsOverlayParams struct {\n\tWindowControlsOverlayConfig *WindowControlsOverlayConfig `json:\"windowControlsOverlayConfig,omitempty,omitzero\"` // Window Controls Overlay data, null means hide Window Controls Overlay\n}\n\n// SetShowWindowControlsOverlay show Window Controls Overlay for PWA.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#method-setShowWindowControlsOverlay\n//\n// parameters:\nfunc SetShowWindowControlsOverlay() *SetShowWindowControlsOverlayParams {\n\treturn &SetShowWindowControlsOverlayParams{}\n}\n\n// WithWindowControlsOverlayConfig window Controls Overlay data, null means\n// hide Window Controls Overlay.\nfunc (p SetShowWindowControlsOverlayParams) WithWindowControlsOverlayConfig(windowControlsOverlayConfig *WindowControlsOverlayConfig) *SetShowWindowControlsOverlayParams {\n\tp.WindowControlsOverlayConfig = windowControlsOverlayConfig\n\treturn &p\n}\n\n// Do executes Overlay.setShowWindowControlsOverlay against the provided context.\nfunc (p *SetShowWindowControlsOverlayParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetShowWindowControlsOverlay, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandDisable                              = \"Overlay.disable\"\n\tCommandEnable                               = \"Overlay.enable\"\n\tCommandGetHighlightObjectForTest            = \"Overlay.getHighlightObjectForTest\"\n\tCommandGetGridHighlightObjectsForTest       = \"Overlay.getGridHighlightObjectsForTest\"\n\tCommandGetSourceOrderHighlightObjectForTest = \"Overlay.getSourceOrderHighlightObjectForTest\"\n\tCommandHideHighlight                        = \"Overlay.hideHighlight\"\n\tCommandHighlightNode                        = \"Overlay.highlightNode\"\n\tCommandHighlightQuad                        = \"Overlay.highlightQuad\"\n\tCommandHighlightRect                        = \"Overlay.highlightRect\"\n\tCommandHighlightSourceOrder                 = \"Overlay.highlightSourceOrder\"\n\tCommandSetInspectMode                       = \"Overlay.setInspectMode\"\n\tCommandSetShowAdHighlights                  = \"Overlay.setShowAdHighlights\"\n\tCommandSetPausedInDebuggerMessage           = \"Overlay.setPausedInDebuggerMessage\"\n\tCommandSetShowDebugBorders                  = \"Overlay.setShowDebugBorders\"\n\tCommandSetShowFPSCounter                    = \"Overlay.setShowFPSCounter\"\n\tCommandSetShowGridOverlays                  = \"Overlay.setShowGridOverlays\"\n\tCommandSetShowFlexOverlays                  = \"Overlay.setShowFlexOverlays\"\n\tCommandSetShowScrollSnapOverlays            = \"Overlay.setShowScrollSnapOverlays\"\n\tCommandSetShowContainerQueryOverlays        = \"Overlay.setShowContainerQueryOverlays\"\n\tCommandSetShowPaintRects                    = \"Overlay.setShowPaintRects\"\n\tCommandSetShowLayoutShiftRegions            = \"Overlay.setShowLayoutShiftRegions\"\n\tCommandSetShowScrollBottleneckRects         = \"Overlay.setShowScrollBottleneckRects\"\n\tCommandSetShowViewportSizeOnResize          = \"Overlay.setShowViewportSizeOnResize\"\n\tCommandSetShowHinge                         = \"Overlay.setShowHinge\"\n\tCommandSetShowIsolatedElements              = \"Overlay.setShowIsolatedElements\"\n\tCommandSetShowWindowControlsOverlay         = \"Overlay.setShowWindowControlsOverlay\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/overlay/types.go",
    "content": "package overlay\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n)\n\n// SourceOrderConfig configuration data for drawing the source order of an\n// elements children.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-SourceOrderConfig\ntype SourceOrderConfig struct {\n\tParentOutlineColor *cdp.RGBA `json:\"parentOutlineColor\"` // the color to outline the given element in.\n\tChildOutlineColor  *cdp.RGBA `json:\"childOutlineColor\"`  // the color to outline the child elements in.\n}\n\n// GridHighlightConfig configuration data for the highlighting of Grid\n// elements.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-GridHighlightConfig\ntype GridHighlightConfig struct {\n\tShowGridExtensionLines  bool      `json:\"showGridExtensionLines\"`                 // Whether the extension lines from grid cells to the rulers should be shown (default: false).\n\tShowPositiveLineNumbers bool      `json:\"showPositiveLineNumbers\"`                // Show Positive line number labels (default: false).\n\tShowNegativeLineNumbers bool      `json:\"showNegativeLineNumbers\"`                // Show Negative line number labels (default: false).\n\tShowAreaNames           bool      `json:\"showAreaNames\"`                          // Show area name labels (default: false).\n\tShowLineNames           bool      `json:\"showLineNames\"`                          // Show line name labels (default: false).\n\tShowTrackSizes          bool      `json:\"showTrackSizes\"`                         // Show track size labels (default: false).\n\tGridBorderColor         *cdp.RGBA `json:\"gridBorderColor,omitempty,omitzero\"`     // The grid container border highlight color (default: transparent).\n\tRowLineColor            *cdp.RGBA `json:\"rowLineColor,omitempty,omitzero\"`        // The row line color (default: transparent).\n\tColumnLineColor         *cdp.RGBA `json:\"columnLineColor,omitempty,omitzero\"`     // The column line color (default: transparent).\n\tGridBorderDash          bool      `json:\"gridBorderDash\"`                         // Whether the grid border is dashed (default: false).\n\tRowLineDash             bool      `json:\"rowLineDash\"`                            // Whether row lines are dashed (default: false).\n\tColumnLineDash          bool      `json:\"columnLineDash\"`                         // Whether column lines are dashed (default: false).\n\tRowGapColor             *cdp.RGBA `json:\"rowGapColor,omitempty,omitzero\"`         // The row gap highlight fill color (default: transparent).\n\tRowHatchColor           *cdp.RGBA `json:\"rowHatchColor,omitempty,omitzero\"`       // The row gap hatching fill color (default: transparent).\n\tColumnGapColor          *cdp.RGBA `json:\"columnGapColor,omitempty,omitzero\"`      // The column gap highlight fill color (default: transparent).\n\tColumnHatchColor        *cdp.RGBA `json:\"columnHatchColor,omitempty,omitzero\"`    // The column gap hatching fill color (default: transparent).\n\tAreaBorderColor         *cdp.RGBA `json:\"areaBorderColor,omitempty,omitzero\"`     // The named grid areas border color (Default: transparent).\n\tGridBackgroundColor     *cdp.RGBA `json:\"gridBackgroundColor,omitempty,omitzero\"` // The grid container background color (Default: transparent).\n}\n\n// FlexContainerHighlightConfig configuration data for the highlighting of\n// Flex container elements.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-FlexContainerHighlightConfig\ntype FlexContainerHighlightConfig struct {\n\tContainerBorder       *LineStyle `json:\"containerBorder,omitempty,omitzero\"`       // The style of the container border\n\tLineSeparator         *LineStyle `json:\"lineSeparator,omitempty,omitzero\"`         // The style of the separator between lines\n\tItemSeparator         *LineStyle `json:\"itemSeparator,omitempty,omitzero\"`         // The style of the separator between items\n\tMainDistributedSpace  *BoxStyle  `json:\"mainDistributedSpace,omitempty,omitzero\"`  // Style of content-distribution space on the main axis (justify-content).\n\tCrossDistributedSpace *BoxStyle  `json:\"crossDistributedSpace,omitempty,omitzero\"` // Style of content-distribution space on the cross axis (align-content).\n\tRowGapSpace           *BoxStyle  `json:\"rowGapSpace,omitempty,omitzero\"`           // Style of empty space caused by row gaps (gap/row-gap).\n\tColumnGapSpace        *BoxStyle  `json:\"columnGapSpace,omitempty,omitzero\"`        // Style of empty space caused by columns gaps (gap/column-gap).\n\tCrossAlignment        *LineStyle `json:\"crossAlignment,omitempty,omitzero\"`        // Style of the self-alignment line (align-items).\n}\n\n// FlexItemHighlightConfig configuration data for the highlighting of Flex\n// item elements.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-FlexItemHighlightConfig\ntype FlexItemHighlightConfig struct {\n\tBaseSizeBox      *BoxStyle  `json:\"baseSizeBox,omitempty,omitzero\"`      // Style of the box representing the item's base size\n\tBaseSizeBorder   *LineStyle `json:\"baseSizeBorder,omitempty,omitzero\"`   // Style of the border around the box representing the item's base size\n\tFlexibilityArrow *LineStyle `json:\"flexibilityArrow,omitempty,omitzero\"` // Style of the arrow representing if the item grew or shrank\n}\n\n// LineStyle style information for drawing a line.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-LineStyle\ntype LineStyle struct {\n\tColor   *cdp.RGBA        `json:\"color,omitempty,omitzero\"`   // The color of the line (default: transparent)\n\tPattern LineStylePattern `json:\"pattern,omitempty,omitzero\"` // The line pattern (default: solid)\n}\n\n// BoxStyle style information for drawing a box.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-BoxStyle\ntype BoxStyle struct {\n\tFillColor  *cdp.RGBA `json:\"fillColor,omitempty,omitzero\"`  // The background color for the box (default: transparent)\n\tHatchColor *cdp.RGBA `json:\"hatchColor,omitempty,omitzero\"` // The hatching color for the box (default: transparent)\n}\n\n// ContrastAlgorithm [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-ContrastAlgorithm\ntype ContrastAlgorithm string\n\n// String returns the ContrastAlgorithm as string value.\nfunc (t ContrastAlgorithm) String() string {\n\treturn string(t)\n}\n\n// ContrastAlgorithm values.\nconst (\n\tContrastAlgorithmAa   ContrastAlgorithm = \"aa\"\n\tContrastAlgorithmAaa  ContrastAlgorithm = \"aaa\"\n\tContrastAlgorithmApca ContrastAlgorithm = \"apca\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ContrastAlgorithm) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ContrastAlgorithm(s) {\n\tcase ContrastAlgorithmAa:\n\t\t*t = ContrastAlgorithmAa\n\tcase ContrastAlgorithmAaa:\n\t\t*t = ContrastAlgorithmAaa\n\tcase ContrastAlgorithmApca:\n\t\t*t = ContrastAlgorithmApca\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ContrastAlgorithm value: %v\", s)\n\t}\n\treturn nil\n}\n\n// HighlightConfig configuration data for the highlighting of page elements.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-HighlightConfig\ntype HighlightConfig struct {\n\tShowInfo                               bool                                    `json:\"showInfo\"`                                                  // Whether the node info tooltip should be shown (default: false).\n\tShowStyles                             bool                                    `json:\"showStyles\"`                                                // Whether the node styles in the tooltip (default: false).\n\tShowRulers                             bool                                    `json:\"showRulers\"`                                                // Whether the rulers should be shown (default: false).\n\tShowAccessibilityInfo                  bool                                    `json:\"showAccessibilityInfo\"`                                     // Whether the a11y info should be shown (default: true).\n\tShowExtensionLines                     bool                                    `json:\"showExtensionLines\"`                                        // Whether the extension lines from node to the rulers should be shown (default: false).\n\tContentColor                           *cdp.RGBA                               `json:\"contentColor,omitempty,omitzero\"`                           // The content box highlight fill color (default: transparent).\n\tPaddingColor                           *cdp.RGBA                               `json:\"paddingColor,omitempty,omitzero\"`                           // The padding highlight fill color (default: transparent).\n\tBorderColor                            *cdp.RGBA                               `json:\"borderColor,omitempty,omitzero\"`                            // The border highlight fill color (default: transparent).\n\tMarginColor                            *cdp.RGBA                               `json:\"marginColor,omitempty,omitzero\"`                            // The margin highlight fill color (default: transparent).\n\tEventTargetColor                       *cdp.RGBA                               `json:\"eventTargetColor,omitempty,omitzero\"`                       // The event target element highlight fill color (default: transparent).\n\tShapeColor                             *cdp.RGBA                               `json:\"shapeColor,omitempty,omitzero\"`                             // The shape outside fill color (default: transparent).\n\tShapeMarginColor                       *cdp.RGBA                               `json:\"shapeMarginColor,omitempty,omitzero\"`                       // The shape margin fill color (default: transparent).\n\tCSSGridColor                           *cdp.RGBA                               `json:\"cssGridColor,omitempty,omitzero\"`                           // The grid layout color (default: transparent).\n\tColorFormat                            ColorFormat                             `json:\"colorFormat,omitempty,omitzero\"`                            // The color format used to format color styles (default: hex).\n\tGridHighlightConfig                    *GridHighlightConfig                    `json:\"gridHighlightConfig,omitempty,omitzero\"`                    // The grid layout highlight configuration (default: all transparent).\n\tFlexContainerHighlightConfig           *FlexContainerHighlightConfig           `json:\"flexContainerHighlightConfig,omitempty,omitzero\"`           // The flex container highlight configuration (default: all transparent).\n\tFlexItemHighlightConfig                *FlexItemHighlightConfig                `json:\"flexItemHighlightConfig,omitempty,omitzero\"`                // The flex item highlight configuration (default: all transparent).\n\tContrastAlgorithm                      ContrastAlgorithm                       `json:\"contrastAlgorithm,omitempty,omitzero\"`                      // The contrast algorithm to use for the contrast ratio (default: aa).\n\tContainerQueryContainerHighlightConfig *ContainerQueryContainerHighlightConfig `json:\"containerQueryContainerHighlightConfig,omitempty,omitzero\"` // The container query container highlight configuration (default: all transparent).\n}\n\n// ColorFormat [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-ColorFormat\ntype ColorFormat string\n\n// String returns the ColorFormat as string value.\nfunc (t ColorFormat) String() string {\n\treturn string(t)\n}\n\n// ColorFormat values.\nconst (\n\tColorFormatRgb ColorFormat = \"rgb\"\n\tColorFormatHsl ColorFormat = \"hsl\"\n\tColorFormatHwb ColorFormat = \"hwb\"\n\tColorFormatHex ColorFormat = \"hex\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ColorFormat) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ColorFormat(s) {\n\tcase ColorFormatRgb:\n\t\t*t = ColorFormatRgb\n\tcase ColorFormatHsl:\n\t\t*t = ColorFormatHsl\n\tcase ColorFormatHwb:\n\t\t*t = ColorFormatHwb\n\tcase ColorFormatHex:\n\t\t*t = ColorFormatHex\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ColorFormat value: %v\", s)\n\t}\n\treturn nil\n}\n\n// GridNodeHighlightConfig configurations for Persistent Grid Highlight.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-GridNodeHighlightConfig\ntype GridNodeHighlightConfig struct {\n\tGridHighlightConfig *GridHighlightConfig `json:\"gridHighlightConfig\"` // A descriptor for the highlight appearance.\n\tNodeID              cdp.NodeID           `json:\"nodeId\"`              // Identifier of the node to highlight.\n}\n\n// FlexNodeHighlightConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-FlexNodeHighlightConfig\ntype FlexNodeHighlightConfig struct {\n\tFlexContainerHighlightConfig *FlexContainerHighlightConfig `json:\"flexContainerHighlightConfig\"` // A descriptor for the highlight appearance of flex containers.\n\tNodeID                       cdp.NodeID                    `json:\"nodeId\"`                       // Identifier of the node to highlight.\n}\n\n// ScrollSnapContainerHighlightConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-ScrollSnapContainerHighlightConfig\ntype ScrollSnapContainerHighlightConfig struct {\n\tSnapportBorder     *LineStyle `json:\"snapportBorder,omitempty,omitzero\"`     // The style of the snapport border (default: transparent)\n\tSnapAreaBorder     *LineStyle `json:\"snapAreaBorder,omitempty,omitzero\"`     // The style of the snap area border (default: transparent)\n\tScrollMarginColor  *cdp.RGBA  `json:\"scrollMarginColor,omitempty,omitzero\"`  // The margin highlight fill color (default: transparent).\n\tScrollPaddingColor *cdp.RGBA  `json:\"scrollPaddingColor,omitempty,omitzero\"` // The padding highlight fill color (default: transparent).\n}\n\n// ScrollSnapHighlightConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-ScrollSnapHighlightConfig\ntype ScrollSnapHighlightConfig struct {\n\tScrollSnapContainerHighlightConfig *ScrollSnapContainerHighlightConfig `json:\"scrollSnapContainerHighlightConfig\"` // A descriptor for the highlight appearance of scroll snap containers.\n\tNodeID                             cdp.NodeID                          `json:\"nodeId\"`                             // Identifier of the node to highlight.\n}\n\n// HingeConfig configuration for dual screen hinge.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-HingeConfig\ntype HingeConfig struct {\n\tRect         *dom.Rect `json:\"rect\"`                            // A rectangle represent hinge\n\tContentColor *cdp.RGBA `json:\"contentColor,omitempty,omitzero\"` // The content box highlight fill color (default: a dark color).\n\tOutlineColor *cdp.RGBA `json:\"outlineColor,omitempty,omitzero\"` // The content box highlight outline color (default: transparent).\n}\n\n// WindowControlsOverlayConfig configuration for Window Controls Overlay.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-WindowControlsOverlayConfig\ntype WindowControlsOverlayConfig struct {\n\tShowCSS          bool   `json:\"showCSS\"`          // Whether the title bar CSS should be shown when emulating the Window Controls Overlay.\n\tSelectedPlatform string `json:\"selectedPlatform\"` // Selected platforms to show the overlay.\n\tThemeColor       string `json:\"themeColor\"`       // The theme color defined in app manifest.\n}\n\n// ContainerQueryHighlightConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-ContainerQueryHighlightConfig\ntype ContainerQueryHighlightConfig struct {\n\tContainerQueryContainerHighlightConfig *ContainerQueryContainerHighlightConfig `json:\"containerQueryContainerHighlightConfig\"` // A descriptor for the highlight appearance of container query containers.\n\tNodeID                                 cdp.NodeID                              `json:\"nodeId\"`                                 // Identifier of the container node to highlight.\n}\n\n// ContainerQueryContainerHighlightConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-ContainerQueryContainerHighlightConfig\ntype ContainerQueryContainerHighlightConfig struct {\n\tContainerBorder  *LineStyle `json:\"containerBorder,omitempty,omitzero\"`  // The style of the container border.\n\tDescendantBorder *LineStyle `json:\"descendantBorder,omitempty,omitzero\"` // The style of the descendants' borders.\n}\n\n// IsolatedElementHighlightConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-IsolatedElementHighlightConfig\ntype IsolatedElementHighlightConfig struct {\n\tIsolationModeHighlightConfig *IsolationModeHighlightConfig `json:\"isolationModeHighlightConfig\"` // A descriptor for the highlight appearance of an element in isolation mode.\n\tNodeID                       cdp.NodeID                    `json:\"nodeId\"`                       // Identifier of the isolated element to highlight.\n}\n\n// IsolationModeHighlightConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-IsolationModeHighlightConfig\ntype IsolationModeHighlightConfig struct {\n\tResizerColor       *cdp.RGBA `json:\"resizerColor,omitempty,omitzero\"`       // The fill color of the resizers (default: transparent).\n\tResizerHandleColor *cdp.RGBA `json:\"resizerHandleColor,omitempty,omitzero\"` // The fill color for resizer handles (default: transparent).\n\tMaskColor          *cdp.RGBA `json:\"maskColor,omitempty,omitzero\"`          // The fill color for the mask covering non-isolated elements (default: transparent).\n}\n\n// InspectMode [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-InspectMode\ntype InspectMode string\n\n// String returns the InspectMode as string value.\nfunc (t InspectMode) String() string {\n\treturn string(t)\n}\n\n// InspectMode values.\nconst (\n\tInspectModeSearchForNode         InspectMode = \"searchForNode\"\n\tInspectModeSearchForUAShadowDOM  InspectMode = \"searchForUAShadowDOM\"\n\tInspectModeCaptureAreaScreenshot InspectMode = \"captureAreaScreenshot\"\n\tInspectModeNone                  InspectMode = \"none\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InspectMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InspectMode(s) {\n\tcase InspectModeSearchForNode:\n\t\t*t = InspectModeSearchForNode\n\tcase InspectModeSearchForUAShadowDOM:\n\t\t*t = InspectModeSearchForUAShadowDOM\n\tcase InspectModeCaptureAreaScreenshot:\n\t\t*t = InspectModeCaptureAreaScreenshot\n\tcase InspectModeNone:\n\t\t*t = InspectModeNone\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InspectMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// LineStylePattern the line pattern (default: solid).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Overlay#type-LineStyle\ntype LineStylePattern string\n\n// String returns the LineStylePattern as string value.\nfunc (t LineStylePattern) String() string {\n\treturn string(t)\n}\n\n// LineStylePattern values.\nconst (\n\tLineStylePatternDashed LineStylePattern = \"dashed\"\n\tLineStylePatternDotted LineStylePattern = \"dotted\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *LineStylePattern) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch LineStylePattern(s) {\n\tcase LineStylePatternDashed:\n\t\t*t = LineStylePatternDashed\n\tcase LineStylePatternDotted:\n\t\t*t = LineStylePatternDotted\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown LineStylePattern value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/page/events.go",
    "content": "package page\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// EventDomContentEventFired [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-domContentEventFired\ntype EventDomContentEventFired struct {\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventFileChooserOpened emitted only when page.interceptFileChooser is\n// enabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-fileChooserOpened\ntype EventFileChooserOpened struct {\n\tFrameID       cdp.FrameID           `json:\"frameId\"`                          // Id of the frame containing input node.\n\tMode          FileChooserOpenedMode `json:\"mode\"`                             // Input mode.\n\tBackendNodeID cdp.BackendNodeID     `json:\"backendNodeId,omitempty,omitzero\"` // Input node id. Only present for file choosers opened via an <input type=\"file\"> element.\n}\n\n// EventFrameAttached fired when frame has been attached to its parent.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameAttached\ntype EventFrameAttached struct {\n\tFrameID       cdp.FrameID         `json:\"frameId\"`                  // Id of the frame that has been attached.\n\tParentFrameID cdp.FrameID         `json:\"parentFrameId\"`            // Parent frame identifier.\n\tStack         *runtime.StackTrace `json:\"stack,omitempty,omitzero\"` // JavaScript stack trace of when frame was attached, only set if frame initiated from script.\n}\n\n// EventFrameDetached fired when frame has been detached from its parent.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameDetached\ntype EventFrameDetached struct {\n\tFrameID cdp.FrameID         `json:\"frameId\"` // Id of the frame that has been detached.\n\tReason  FrameDetachedReason `json:\"reason\"`\n}\n\n// EventFrameSubtreeWillBeDetached fired before frame subtree is detached.\n// Emitted before any frame of the subtree is actually detached.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameSubtreeWillBeDetached\ntype EventFrameSubtreeWillBeDetached struct {\n\tFrameID cdp.FrameID `json:\"frameId\"` // Id of the frame that is the root of the subtree that will be detached.\n}\n\n// EventFrameNavigated fired once navigation of the frame has completed.\n// Frame is now associated with the new loader.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameNavigated\ntype EventFrameNavigated struct {\n\tFrame *cdp.Frame     `json:\"frame\"` // Frame object.\n\tType  NavigationType `json:\"type\"`\n}\n\n// EventDocumentOpened fired when opening document to write to.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-documentOpened\ntype EventDocumentOpened struct {\n\tFrame *cdp.Frame `json:\"frame\"` // Frame object.\n}\n\n// EventFrameResized [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameResized\ntype EventFrameResized struct{}\n\n// EventFrameStartedNavigating fired when a navigation starts. This event is\n// fired for both renderer-initiated and browser-initiated navigations. For\n// renderer-initiated navigations, the event is fired after\n// frameRequestedNavigation. Navigation may still be cancelled after the event\n// is issued. Multiple events can be fired for a single navigation, for example,\n// when a same-document navigation becomes a cross-document navigation (such as\n// in the case of a frameset).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameStartedNavigating\ntype EventFrameStartedNavigating struct {\n\tFrameID        cdp.FrameID                          `json:\"frameId\"`  // ID of the frame that is being navigated.\n\tURL            string                               `json:\"url\"`      // The URL the navigation started with. The final URL can be different.\n\tLoaderID       cdp.LoaderID                         `json:\"loaderId\"` // Loader identifier. Even though it is present in case of same-document navigation, the previously committed loaderId would not change unless the navigation changes from a same-document to a cross-document navigation.\n\tNavigationType FrameStartedNavigatingNavigationType `json:\"navigationType\"`\n}\n\n// EventFrameRequestedNavigation fired when a renderer-initiated navigation\n// is requested. Navigation may still be cancelled after the event is issued.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameRequestedNavigation\ntype EventFrameRequestedNavigation struct {\n\tFrameID     cdp.FrameID                 `json:\"frameId\"`     // Id of the frame that is being navigated.\n\tReason      ClientNavigationReason      `json:\"reason\"`      // The reason for the navigation.\n\tURL         string                      `json:\"url\"`         // The destination URL for the requested navigation.\n\tDisposition ClientNavigationDisposition `json:\"disposition\"` // The disposition for the navigation.\n}\n\n// EventFrameStartedLoading fired when frame has started loading.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameStartedLoading\ntype EventFrameStartedLoading struct {\n\tFrameID cdp.FrameID `json:\"frameId\"` // Id of the frame that has started loading.\n}\n\n// EventFrameStoppedLoading fired when frame has stopped loading.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameStoppedLoading\ntype EventFrameStoppedLoading struct {\n\tFrameID cdp.FrameID `json:\"frameId\"` // Id of the frame that has stopped loading.\n}\n\n// EventInterstitialHidden fired when interstitial page was hidden.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-interstitialHidden\ntype EventInterstitialHidden struct{}\n\n// EventInterstitialShown fired when interstitial page was shown.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-interstitialShown\ntype EventInterstitialShown struct{}\n\n// EventJavascriptDialogClosed fired when a JavaScript initiated dialog\n// (alert, confirm, prompt, or onbeforeunload) has been closed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-javascriptDialogClosed\ntype EventJavascriptDialogClosed struct {\n\tFrameID   cdp.FrameID `json:\"frameId\"`   // Frame id.\n\tResult    bool        `json:\"result\"`    // Whether dialog was confirmed.\n\tUserInput string      `json:\"userInput\"` // User input in case of prompt.\n}\n\n// EventJavascriptDialogOpening fired when a JavaScript initiated dialog\n// (alert, confirm, prompt, or onbeforeunload) is about to open.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-javascriptDialogOpening\ntype EventJavascriptDialogOpening struct {\n\tURL               string      `json:\"url\"`                              // Frame url.\n\tFrameID           cdp.FrameID `json:\"frameId\"`                          // Frame id.\n\tMessage           string      `json:\"message\"`                          // Message that will be displayed by the dialog.\n\tType              DialogType  `json:\"type\"`                             // Dialog type.\n\tHasBrowserHandler bool        `json:\"hasBrowserHandler\"`                // True iff browser is capable showing or acting on the given dialog. When browser has no dialog handler for given target, calling alert while Page domain is engaged will stall the page execution. Execution can be resumed via calling Page.handleJavaScriptDialog.\n\tDefaultPrompt     string      `json:\"defaultPrompt,omitempty,omitzero\"` // Default dialog prompt.\n}\n\n// EventLifecycleEvent fired for lifecycle events (navigation, load, paint,\n// etc) in the current target (including local frames).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-lifecycleEvent\ntype EventLifecycleEvent struct {\n\tFrameID   cdp.FrameID        `json:\"frameId\"`  // Id of the frame.\n\tLoaderID  cdp.LoaderID       `json:\"loaderId\"` // Loader identifier. Empty string if the request is fetched from worker.\n\tName      string             `json:\"name\"`\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventBackForwardCacheNotUsed fired for failed bfcache history navigations\n// if BackForwardCache feature is enabled. Do not assume any ordering with the\n// Page.frameNavigated event. This event is fired only for main-frame history\n// navigation where the document changes (non-same-document navigations), when\n// bfcache navigation fails.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-backForwardCacheNotUsed\ntype EventBackForwardCacheNotUsed struct {\n\tLoaderID                    cdp.LoaderID                                `json:\"loaderId\"`                                       // The loader id for the associated navigation.\n\tFrameID                     cdp.FrameID                                 `json:\"frameId\"`                                        // The frame id of the associated frame.\n\tNotRestoredExplanations     []*BackForwardCacheNotRestoredExplanation   `json:\"notRestoredExplanations\"`                        // Array of reasons why the page could not be cached. This must not be empty.\n\tNotRestoredExplanationsTree *BackForwardCacheNotRestoredExplanationTree `json:\"notRestoredExplanationsTree,omitempty,omitzero\"` // Tree structure of reasons why the page could not be cached for each frame.\n}\n\n// EventLoadEventFired [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-loadEventFired\ntype EventLoadEventFired struct {\n\tTimestamp *cdp.MonotonicTime `json:\"timestamp\"`\n}\n\n// EventNavigatedWithinDocument fired when same-document navigation happens,\n// e.g. due to history API usage or anchor navigation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-navigatedWithinDocument\ntype EventNavigatedWithinDocument struct {\n\tFrameID        cdp.FrameID                           `json:\"frameId\"`        // Id of the frame.\n\tURL            string                                `json:\"url\"`            // Frame's new url.\n\tNavigationType NavigatedWithinDocumentNavigationType `json:\"navigationType\"` // Navigation type\n}\n\n// EventScreencastFrame compressed image data requested by the\n// startScreencast.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-screencastFrame\ntype EventScreencastFrame struct {\n\tData      string                   `json:\"data\"`      // Base64-encoded compressed image.\n\tMetadata  *ScreencastFrameMetadata `json:\"metadata\"`  // Screencast frame metadata.\n\tSessionID int64                    `json:\"sessionId\"` // Frame number.\n}\n\n// EventScreencastVisibilityChanged fired when the page with currently\n// enabled screencast was shown or hidden .\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-screencastVisibilityChanged\ntype EventScreencastVisibilityChanged struct {\n\tVisible bool `json:\"visible\"` // True if the page is visible.\n}\n\n// EventWindowOpen fired when a new window is going to be opened, via\n// window.open(), link click, form submission, etc.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-windowOpen\ntype EventWindowOpen struct {\n\tURL            string   `json:\"url\"`            // The URL for the new window.\n\tWindowName     string   `json:\"windowName\"`     // Window name.\n\tWindowFeatures []string `json:\"windowFeatures\"` // An array of enabled window features.\n\tUserGesture    bool     `json:\"userGesture\"`    // Whether or not it was triggered by user gesture.\n}\n\n// EventCompilationCacheProduced issued for every compilation cache\n// generated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-compilationCacheProduced\ntype EventCompilationCacheProduced struct {\n\tURL  string `json:\"url\"`\n\tData string `json:\"data\"` // Base64-encoded data\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/page/page.go",
    "content": "// Package page provides the Chrome DevTools Protocol\n// commands, types, and events for the Page domain.\n//\n// Actions and events related to the inspected page belong to the page\n// domain.\n//\n// Generated by the cdproto-gen command.\npackage page\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/debugger\"\n\t\"github.com/chromedp/cdproto/dom\"\n\t\"github.com/chromedp/cdproto/io\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// AddScriptToEvaluateOnNewDocumentParams evaluates given script in every\n// frame upon creation (before loading frame's scripts).\ntype AddScriptToEvaluateOnNewDocumentParams struct {\n\tSource                string `json:\"source\"`\n\tWorldName             string `json:\"worldName,omitempty,omitzero\"` // If specified, creates an isolated world with the given name and evaluates given script in it. This world name will be used as the ExecutionContextDescription::name when the corresponding event is emitted.\n\tIncludeCommandLineAPI bool   `json:\"includeCommandLineAPI\"`        // Specifies whether command line API should be available to the script, defaults to false.\n\tRunImmediately        bool   `json:\"runImmediately\"`               // If true, runs the script immediately on existing execution contexts or worlds. Default: false.\n}\n\n// AddScriptToEvaluateOnNewDocument evaluates given script in every frame\n// upon creation (before loading frame's scripts).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-addScriptToEvaluateOnNewDocument\n//\n// parameters:\n//\n//\tsource\nfunc AddScriptToEvaluateOnNewDocument(source string) *AddScriptToEvaluateOnNewDocumentParams {\n\treturn &AddScriptToEvaluateOnNewDocumentParams{\n\t\tSource:                source,\n\t\tIncludeCommandLineAPI: false,\n\t\tRunImmediately:        false,\n\t}\n}\n\n// WithWorldName if specified, creates an isolated world with the given name\n// and evaluates given script in it. This world name will be used as the\n// ExecutionContextDescription::name when the corresponding event is emitted.\nfunc (p AddScriptToEvaluateOnNewDocumentParams) WithWorldName(worldName string) *AddScriptToEvaluateOnNewDocumentParams {\n\tp.WorldName = worldName\n\treturn &p\n}\n\n// WithIncludeCommandLineAPI specifies whether command line API should be\n// available to the script, defaults to false.\nfunc (p AddScriptToEvaluateOnNewDocumentParams) WithIncludeCommandLineAPI(includeCommandLineAPI bool) *AddScriptToEvaluateOnNewDocumentParams {\n\tp.IncludeCommandLineAPI = includeCommandLineAPI\n\treturn &p\n}\n\n// WithRunImmediately if true, runs the script immediately on existing\n// execution contexts or worlds. Default: false.\nfunc (p AddScriptToEvaluateOnNewDocumentParams) WithRunImmediately(runImmediately bool) *AddScriptToEvaluateOnNewDocumentParams {\n\tp.RunImmediately = runImmediately\n\treturn &p\n}\n\n// AddScriptToEvaluateOnNewDocumentReturns return values.\ntype AddScriptToEvaluateOnNewDocumentReturns struct {\n\tIdentifier ScriptIdentifier `json:\"identifier,omitempty,omitzero\"` // Identifier of the added script.\n}\n\n// Do executes Page.addScriptToEvaluateOnNewDocument against the provided context.\n//\n// returns:\n//\n//\tidentifier - Identifier of the added script.\nfunc (p *AddScriptToEvaluateOnNewDocumentParams) Do(ctx context.Context) (identifier ScriptIdentifier, err error) {\n\t// execute\n\tvar res AddScriptToEvaluateOnNewDocumentReturns\n\terr = cdp.Execute(ctx, CommandAddScriptToEvaluateOnNewDocument, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.Identifier, nil\n}\n\n// BringToFrontParams brings page to front (activates tab).\ntype BringToFrontParams struct{}\n\n// BringToFront brings page to front (activates tab).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-bringToFront\nfunc BringToFront() *BringToFrontParams {\n\treturn &BringToFrontParams{}\n}\n\n// Do executes Page.bringToFront against the provided context.\nfunc (p *BringToFrontParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandBringToFront, nil, nil)\n}\n\n// CaptureScreenshotParams capture page screenshot.\ntype CaptureScreenshotParams struct {\n\tFormat                CaptureScreenshotFormat `json:\"format,omitempty,omitzero\"`  // Image compression format (defaults to png).\n\tQuality               int64                   `json:\"quality,omitempty,omitzero\"` // Compression quality from range [0..100] (jpeg only).\n\tClip                  *Viewport               `json:\"clip,omitempty,omitzero\"`    // Capture the screenshot of a given region only.\n\tFromSurface           bool                    `json:\"fromSurface\"`                // Capture the screenshot from the surface, rather than the view. Defaults to true.\n\tCaptureBeyondViewport bool                    `json:\"captureBeyondViewport\"`      // Capture the screenshot beyond the viewport. Defaults to false.\n\tOptimizeForSpeed      bool                    `json:\"optimizeForSpeed\"`           // Optimize image encoding for speed, not for resulting size (defaults to false)\n}\n\n// CaptureScreenshot capture page screenshot.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-captureScreenshot\n//\n// parameters:\nfunc CaptureScreenshot() *CaptureScreenshotParams {\n\treturn &CaptureScreenshotParams{\n\t\tFromSurface:           true,\n\t\tCaptureBeyondViewport: false,\n\t\tOptimizeForSpeed:      false,\n\t}\n}\n\n// WithFormat image compression format (defaults to png).\nfunc (p CaptureScreenshotParams) WithFormat(format CaptureScreenshotFormat) *CaptureScreenshotParams {\n\tp.Format = format\n\treturn &p\n}\n\n// WithQuality compression quality from range [0..100] (jpeg only).\nfunc (p CaptureScreenshotParams) WithQuality(quality int64) *CaptureScreenshotParams {\n\tp.Quality = quality\n\treturn &p\n}\n\n// WithClip capture the screenshot of a given region only.\nfunc (p CaptureScreenshotParams) WithClip(clip *Viewport) *CaptureScreenshotParams {\n\tp.Clip = clip\n\treturn &p\n}\n\n// WithFromSurface capture the screenshot from the surface, rather than the\n// view. Defaults to true.\nfunc (p CaptureScreenshotParams) WithFromSurface(fromSurface bool) *CaptureScreenshotParams {\n\tp.FromSurface = fromSurface\n\treturn &p\n}\n\n// WithCaptureBeyondViewport capture the screenshot beyond the viewport.\n// Defaults to false.\nfunc (p CaptureScreenshotParams) WithCaptureBeyondViewport(captureBeyondViewport bool) *CaptureScreenshotParams {\n\tp.CaptureBeyondViewport = captureBeyondViewport\n\treturn &p\n}\n\n// WithOptimizeForSpeed optimize image encoding for speed, not for resulting\n// size (defaults to false).\nfunc (p CaptureScreenshotParams) WithOptimizeForSpeed(optimizeForSpeed bool) *CaptureScreenshotParams {\n\tp.OptimizeForSpeed = optimizeForSpeed\n\treturn &p\n}\n\n// CaptureScreenshotReturns return values.\ntype CaptureScreenshotReturns struct {\n\tData string `json:\"data,omitempty,omitzero\"` // Base64-encoded image data.\n}\n\n// Do executes Page.captureScreenshot against the provided context.\n//\n// returns:\n//\n//\tdata - Base64-encoded image data.\nfunc (p *CaptureScreenshotParams) Do(ctx context.Context) (data []byte, err error) {\n\t// execute\n\tvar res CaptureScreenshotReturns\n\terr = cdp.Execute(ctx, CommandCaptureScreenshot, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tdec, err = base64.StdEncoding.DecodeString(res.Data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn dec, nil\n}\n\n// CaptureSnapshotParams returns a snapshot of the page as a string. For\n// MHTML format, the serialization includes iframes, shadow DOM, external\n// resources, and element-inline styles.\ntype CaptureSnapshotParams struct {\n\tFormat CaptureSnapshotFormat `json:\"format,omitempty,omitzero\"` // Format (defaults to mhtml).\n}\n\n// CaptureSnapshot returns a snapshot of the page as a string. For MHTML\n// format, the serialization includes iframes, shadow DOM, external resources,\n// and element-inline styles.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-captureSnapshot\n//\n// parameters:\nfunc CaptureSnapshot() *CaptureSnapshotParams {\n\treturn &CaptureSnapshotParams{}\n}\n\n// WithFormat format (defaults to mhtml).\nfunc (p CaptureSnapshotParams) WithFormat(format CaptureSnapshotFormat) *CaptureSnapshotParams {\n\tp.Format = format\n\treturn &p\n}\n\n// CaptureSnapshotReturns return values.\ntype CaptureSnapshotReturns struct {\n\tData string `json:\"data,omitempty,omitzero\"` // Serialized page data.\n}\n\n// Do executes Page.captureSnapshot against the provided context.\n//\n// returns:\n//\n//\tdata - Serialized page data.\nfunc (p *CaptureSnapshotParams) Do(ctx context.Context) (data string, err error) {\n\t// execute\n\tvar res CaptureSnapshotReturns\n\terr = cdp.Execute(ctx, CommandCaptureSnapshot, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.Data, nil\n}\n\n// CreateIsolatedWorldParams creates an isolated world for the given frame.\ntype CreateIsolatedWorldParams struct {\n\tFrameID             cdp.FrameID `json:\"frameId\"`                      // Id of the frame in which the isolated world should be created.\n\tWorldName           string      `json:\"worldName,omitempty,omitzero\"` // An optional name which is reported in the Execution Context.\n\tGrantUniveralAccess bool        `json:\"grantUniveralAccess\"`          // Whether or not universal access should be granted to the isolated world. This is a powerful option, use with caution.\n}\n\n// CreateIsolatedWorld creates an isolated world for the given frame.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-createIsolatedWorld\n//\n// parameters:\n//\n//\tframeID - Id of the frame in which the isolated world should be created.\nfunc CreateIsolatedWorld(frameID cdp.FrameID) *CreateIsolatedWorldParams {\n\treturn &CreateIsolatedWorldParams{\n\t\tFrameID:             frameID,\n\t\tGrantUniveralAccess: false,\n\t}\n}\n\n// WithWorldName an optional name which is reported in the Execution Context.\nfunc (p CreateIsolatedWorldParams) WithWorldName(worldName string) *CreateIsolatedWorldParams {\n\tp.WorldName = worldName\n\treturn &p\n}\n\n// WithGrantUniveralAccess whether or not universal access should be granted\n// to the isolated world. This is a powerful option, use with caution.\nfunc (p CreateIsolatedWorldParams) WithGrantUniveralAccess(grantUniveralAccess bool) *CreateIsolatedWorldParams {\n\tp.GrantUniveralAccess = grantUniveralAccess\n\treturn &p\n}\n\n// CreateIsolatedWorldReturns return values.\ntype CreateIsolatedWorldReturns struct {\n\tExecutionContextID runtime.ExecutionContextID `json:\"executionContextId,omitempty,omitzero\"` // Execution context of the isolated world.\n}\n\n// Do executes Page.createIsolatedWorld against the provided context.\n//\n// returns:\n//\n//\texecutionContextID - Execution context of the isolated world.\nfunc (p *CreateIsolatedWorldParams) Do(ctx context.Context) (executionContextID runtime.ExecutionContextID, err error) {\n\t// execute\n\tvar res CreateIsolatedWorldReturns\n\terr = cdp.Execute(ctx, CommandCreateIsolatedWorld, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.ExecutionContextID, nil\n}\n\n// DisableParams disables page domain notifications.\ntype DisableParams struct{}\n\n// Disable disables page domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Page.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables page domain notifications.\ntype EnableParams struct {\n\tEnableFileChooserOpenedEvent bool `json:\"enableFileChooserOpenedEvent\"` // If true, the Page.fileChooserOpened event will be emitted regardless of the state set by Page.setInterceptFileChooserDialog command (default: false).\n}\n\n// Enable enables page domain notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{\n\t\tEnableFileChooserOpenedEvent: false,\n\t}\n}\n\n// WithEnableFileChooserOpenedEvent if true, the Page.fileChooserOpened event\n// will be emitted regardless of the state set by\n// Page.setInterceptFileChooserDialog command (default: false).\nfunc (p EnableParams) WithEnableFileChooserOpenedEvent(enableFileChooserOpenedEvent bool) *EnableParams {\n\tp.EnableFileChooserOpenedEvent = enableFileChooserOpenedEvent\n\treturn &p\n}\n\n// Do executes Page.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// GetAppManifestParams gets the processed manifest for this current\n// document. This API always waits for the manifest to be loaded. If manifestId\n// is provided, and it does not match the manifest of the current document, this\n// API errors out. If there is not a loaded page, this API errors out\n// immediately.\ntype GetAppManifestParams struct {\n\tManifestID string `json:\"manifestId,omitempty,omitzero\"`\n}\n\n// GetAppManifest gets the processed manifest for this current document. This\n// API always waits for the manifest to be loaded. If manifestId is provided,\n// and it does not match the manifest of the current document, this API errors\n// out. If there is not a loaded page, this API errors out immediately.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getAppManifest\n//\n// parameters:\nfunc GetAppManifest() *GetAppManifestParams {\n\treturn &GetAppManifestParams{}\n}\n\n// WithManifestID [no description].\nfunc (p GetAppManifestParams) WithManifestID(manifestID string) *GetAppManifestParams {\n\tp.ManifestID = manifestID\n\treturn &p\n}\n\n// GetAppManifestReturns return values.\ntype GetAppManifestReturns struct {\n\tURL      string              `json:\"url,omitempty,omitzero\"` // Manifest location.\n\tErrors   []*AppManifestError `json:\"errors,omitempty,omitzero\"`\n\tData     string              `json:\"data,omitempty,omitzero\"` // Manifest content.\n\tManifest *WebAppManifest     `json:\"manifest,omitempty,omitzero\"`\n}\n\n// Do executes Page.getAppManifest against the provided context.\n//\n// returns:\n//\n//\turl - Manifest location.\n//\terrors\n//\tdata - Manifest content.\n//\tmanifest\nfunc (p *GetAppManifestParams) Do(ctx context.Context) (url string, errors []*AppManifestError, data string, manifest *WebAppManifest, err error) {\n\t// execute\n\tvar res GetAppManifestReturns\n\terr = cdp.Execute(ctx, CommandGetAppManifest, p, &res)\n\tif err != nil {\n\t\treturn \"\", nil, \"\", nil, err\n\t}\n\n\treturn res.URL, res.Errors, res.Data, res.Manifest, nil\n}\n\n// GetInstallabilityErrorsParams [no description].\ntype GetInstallabilityErrorsParams struct{}\n\n// GetInstallabilityErrors [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getInstallabilityErrors\nfunc GetInstallabilityErrors() *GetInstallabilityErrorsParams {\n\treturn &GetInstallabilityErrorsParams{}\n}\n\n// GetInstallabilityErrorsReturns return values.\ntype GetInstallabilityErrorsReturns struct {\n\tInstallabilityErrors []*InstallabilityError `json:\"installabilityErrors,omitempty,omitzero\"`\n}\n\n// Do executes Page.getInstallabilityErrors against the provided context.\n//\n// returns:\n//\n//\tinstallabilityErrors\nfunc (p *GetInstallabilityErrorsParams) Do(ctx context.Context) (installabilityErrors []*InstallabilityError, err error) {\n\t// execute\n\tvar res GetInstallabilityErrorsReturns\n\terr = cdp.Execute(ctx, CommandGetInstallabilityErrors, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.InstallabilityErrors, nil\n}\n\n// GetAppIDParams returns the unique (PWA) app id. Only returns values if the\n// feature flag 'WebAppEnableManifestId' is enabled.\ntype GetAppIDParams struct{}\n\n// GetAppID returns the unique (PWA) app id. Only returns values if the\n// feature flag 'WebAppEnableManifestId' is enabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getAppId\nfunc GetAppID() *GetAppIDParams {\n\treturn &GetAppIDParams{}\n}\n\n// GetAppIDReturns return values.\ntype GetAppIDReturns struct {\n\tAppID         string `json:\"appId,omitempty,omitzero\"`         // App id, either from manifest's id attribute or computed from start_url\n\tRecommendedID string `json:\"recommendedId,omitempty,omitzero\"` // Recommendation for manifest's id attribute to match current id computed from start_url\n}\n\n// Do executes Page.getAppId against the provided context.\n//\n// returns:\n//\n//\tappID - App id, either from manifest's id attribute or computed from start_url\n//\trecommendedID - Recommendation for manifest's id attribute to match current id computed from start_url\nfunc (p *GetAppIDParams) Do(ctx context.Context) (appID string, recommendedID string, err error) {\n\t// execute\n\tvar res GetAppIDReturns\n\terr = cdp.Execute(ctx, CommandGetAppID, nil, &res)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\treturn res.AppID, res.RecommendedID, nil\n}\n\n// GetAdScriptAncestryParams [no description].\ntype GetAdScriptAncestryParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"`\n}\n\n// GetAdScriptAncestry [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getAdScriptAncestry\n//\n// parameters:\n//\n//\tframeID\nfunc GetAdScriptAncestry(frameID cdp.FrameID) *GetAdScriptAncestryParams {\n\treturn &GetAdScriptAncestryParams{\n\t\tFrameID: frameID,\n\t}\n}\n\n// GetAdScriptAncestryReturns return values.\ntype GetAdScriptAncestryReturns struct {\n\tAdScriptAncestry *AdScriptAncestry `json:\"adScriptAncestry,omitempty,omitzero\"` // The ancestry chain of ad script identifiers leading to this frame's creation, along with the root script's filterlist rule. The ancestry chain is ordered from the most immediate script (in the frame creation stack) to more distant ancestors (that created the immediately preceding script). Only sent if frame is labelled as an ad and ids are available.\n}\n\n// Do executes Page.getAdScriptAncestry against the provided context.\n//\n// returns:\n//\n//\tadScriptAncestry - The ancestry chain of ad script identifiers leading to this frame's creation, along with the root script's filterlist rule. The ancestry chain is ordered from the most immediate script (in the frame creation stack) to more distant ancestors (that created the immediately preceding script). Only sent if frame is labelled as an ad and ids are available.\nfunc (p *GetAdScriptAncestryParams) Do(ctx context.Context) (adScriptAncestry *AdScriptAncestry, err error) {\n\t// execute\n\tvar res GetAdScriptAncestryReturns\n\terr = cdp.Execute(ctx, CommandGetAdScriptAncestry, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.AdScriptAncestry, nil\n}\n\n// GetFrameTreeParams returns present frame tree structure.\ntype GetFrameTreeParams struct{}\n\n// GetFrameTree returns present frame tree structure.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getFrameTree\nfunc GetFrameTree() *GetFrameTreeParams {\n\treturn &GetFrameTreeParams{}\n}\n\n// GetFrameTreeReturns return values.\ntype GetFrameTreeReturns struct {\n\tFrameTree *FrameTree `json:\"frameTree,omitempty,omitzero\"` // Present frame tree structure.\n}\n\n// Do executes Page.getFrameTree against the provided context.\n//\n// returns:\n//\n//\tframeTree - Present frame tree structure.\nfunc (p *GetFrameTreeParams) Do(ctx context.Context) (frameTree *FrameTree, err error) {\n\t// execute\n\tvar res GetFrameTreeReturns\n\terr = cdp.Execute(ctx, CommandGetFrameTree, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.FrameTree, nil\n}\n\n// GetLayoutMetricsParams returns metrics relating to the layouting of the\n// page, such as viewport bounds/scale.\ntype GetLayoutMetricsParams struct{}\n\n// GetLayoutMetrics returns metrics relating to the layouting of the page,\n// such as viewport bounds/scale.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getLayoutMetrics\nfunc GetLayoutMetrics() *GetLayoutMetricsParams {\n\treturn &GetLayoutMetricsParams{}\n}\n\n// GetLayoutMetricsReturns return values.\ntype GetLayoutMetricsReturns struct {\n\tLayoutViewport    *LayoutViewport `json:\"layoutViewport\"`    // Deprecated metrics relating to the layout viewport. Is in device pixels. Use cssLayoutViewport instead.\n\tVisualViewport    *VisualViewport `json:\"visualViewport\"`    // Deprecated metrics relating to the visual viewport. Is in device pixels. Use cssVisualViewport instead.\n\tContentSize       *dom.Rect       `json:\"contentSize\"`       // Deprecated size of scrollable area. Is in DP. Use cssContentSize instead.\n\tCSSLayoutViewport *LayoutViewport `json:\"cssLayoutViewport\"` // Metrics relating to the layout viewport in CSS pixels.\n\tCSSVisualViewport *VisualViewport `json:\"cssVisualViewport\"` // Metrics relating to the visual viewport in CSS pixels.\n\tCSSContentSize    *dom.Rect       `json:\"cssContentSize\"`    // Size of scrollable area in CSS pixels.\n}\n\n// Do executes Page.getLayoutMetrics against the provided context.\n//\n// returns:\n//\n//\tlayoutViewport - Deprecated metrics relating to the layout viewport. Is in device pixels. Use cssLayoutViewport instead.\n//\tvisualViewport - Deprecated metrics relating to the visual viewport. Is in device pixels. Use cssVisualViewport instead.\n//\tcontentSize - Deprecated size of scrollable area. Is in DP. Use cssContentSize instead.\n//\tcssLayoutViewport - Metrics relating to the layout viewport in CSS pixels.\n//\tcssVisualViewport - Metrics relating to the visual viewport in CSS pixels.\n//\tcssContentSize - Size of scrollable area in CSS pixels.\nfunc (p *GetLayoutMetricsParams) Do(ctx context.Context) (layoutViewport *LayoutViewport, visualViewport *VisualViewport, contentSize *dom.Rect, cssLayoutViewport *LayoutViewport, cssVisualViewport *VisualViewport, cssContentSize *dom.Rect, err error) {\n\t// execute\n\tvar res GetLayoutMetricsReturns\n\terr = cdp.Execute(ctx, CommandGetLayoutMetrics, nil, &res)\n\tif err != nil {\n\t\treturn nil, nil, nil, nil, nil, nil, err\n\t}\n\n\treturn res.LayoutViewport, res.VisualViewport, res.ContentSize, res.CSSLayoutViewport, res.CSSVisualViewport, res.CSSContentSize, nil\n}\n\n// GetNavigationHistoryParams returns navigation history for the current\n// page.\ntype GetNavigationHistoryParams struct{}\n\n// GetNavigationHistory returns navigation history for the current page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getNavigationHistory\nfunc GetNavigationHistory() *GetNavigationHistoryParams {\n\treturn &GetNavigationHistoryParams{}\n}\n\n// GetNavigationHistoryReturns return values.\ntype GetNavigationHistoryReturns struct {\n\tCurrentIndex int64              `json:\"currentIndex,omitempty,omitzero\"` // Index of the current navigation history entry.\n\tEntries      []*NavigationEntry `json:\"entries,omitempty,omitzero\"`      // Array of navigation history entries.\n}\n\n// Do executes Page.getNavigationHistory against the provided context.\n//\n// returns:\n//\n//\tcurrentIndex - Index of the current navigation history entry.\n//\tentries - Array of navigation history entries.\nfunc (p *GetNavigationHistoryParams) Do(ctx context.Context) (currentIndex int64, entries []*NavigationEntry, err error) {\n\t// execute\n\tvar res GetNavigationHistoryReturns\n\terr = cdp.Execute(ctx, CommandGetNavigationHistory, nil, &res)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\treturn res.CurrentIndex, res.Entries, nil\n}\n\n// ResetNavigationHistoryParams resets navigation history for the current\n// page.\ntype ResetNavigationHistoryParams struct{}\n\n// ResetNavigationHistory resets navigation history for the current page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-resetNavigationHistory\nfunc ResetNavigationHistory() *ResetNavigationHistoryParams {\n\treturn &ResetNavigationHistoryParams{}\n}\n\n// Do executes Page.resetNavigationHistory against the provided context.\nfunc (p *ResetNavigationHistoryParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandResetNavigationHistory, nil, nil)\n}\n\n// GetResourceContentParams returns content of the given resource.\ntype GetResourceContentParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"` // Frame id to get resource for.\n\tURL     string      `json:\"url\"`     // URL of the resource to get content for.\n}\n\n// GetResourceContent returns content of the given resource.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getResourceContent\n//\n// parameters:\n//\n//\tframeID - Frame id to get resource for.\n//\turl - URL of the resource to get content for.\nfunc GetResourceContent(frameID cdp.FrameID, url string) *GetResourceContentParams {\n\treturn &GetResourceContentParams{\n\t\tFrameID: frameID,\n\t\tURL:     url,\n\t}\n}\n\n// GetResourceContentReturns return values.\ntype GetResourceContentReturns struct {\n\tContent       string `json:\"content,omitempty,omitzero\"` // Resource content.\n\tBase64encoded bool   `json:\"base64Encoded\"`              // True, if content was served as base64.\n}\n\n// Do executes Page.getResourceContent against the provided context.\n//\n// returns:\n//\n//\tcontent - Resource content.\nfunc (p *GetResourceContentParams) Do(ctx context.Context) (content []byte, err error) {\n\t// execute\n\tvar res GetResourceContentReturns\n\terr = cdp.Execute(ctx, CommandGetResourceContent, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tif res.Base64encoded {\n\t\tdec, err = base64.StdEncoding.DecodeString(res.Content)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\tdec = []byte(res.Content)\n\t}\n\treturn dec, nil\n}\n\n// GetResourceTreeParams returns present frame / resource tree structure.\ntype GetResourceTreeParams struct{}\n\n// GetResourceTree returns present frame / resource tree structure.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getResourceTree\nfunc GetResourceTree() *GetResourceTreeParams {\n\treturn &GetResourceTreeParams{}\n}\n\n// GetResourceTreeReturns return values.\ntype GetResourceTreeReturns struct {\n\tFrameTree *FrameResourceTree `json:\"frameTree,omitempty,omitzero\"` // Present frame / resource tree structure.\n}\n\n// Do executes Page.getResourceTree against the provided context.\n//\n// returns:\n//\n//\tframeTree - Present frame / resource tree structure.\nfunc (p *GetResourceTreeParams) Do(ctx context.Context) (frameTree *FrameResourceTree, err error) {\n\t// execute\n\tvar res GetResourceTreeReturns\n\terr = cdp.Execute(ctx, CommandGetResourceTree, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.FrameTree, nil\n}\n\n// HandleJavaScriptDialogParams accepts or dismisses a JavaScript initiated\n// dialog (alert, confirm, prompt, or onbeforeunload).\ntype HandleJavaScriptDialogParams struct {\n\tAccept     bool   `json:\"accept\"`                        // Whether to accept or dismiss the dialog.\n\tPromptText string `json:\"promptText,omitempty,omitzero\"` // The text to enter into the dialog prompt before accepting. Used only if this is a prompt dialog.\n}\n\n// HandleJavaScriptDialog accepts or dismisses a JavaScript initiated dialog\n// (alert, confirm, prompt, or onbeforeunload).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-handleJavaScriptDialog\n//\n// parameters:\n//\n//\taccept - Whether to accept or dismiss the dialog.\nfunc HandleJavaScriptDialog(accept bool) *HandleJavaScriptDialogParams {\n\treturn &HandleJavaScriptDialogParams{\n\t\tAccept: accept,\n\t}\n}\n\n// WithPromptText the text to enter into the dialog prompt before accepting.\n// Used only if this is a prompt dialog.\nfunc (p HandleJavaScriptDialogParams) WithPromptText(promptText string) *HandleJavaScriptDialogParams {\n\tp.PromptText = promptText\n\treturn &p\n}\n\n// Do executes Page.handleJavaScriptDialog against the provided context.\nfunc (p *HandleJavaScriptDialogParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandHandleJavaScriptDialog, p, nil)\n}\n\n// NavigateParams navigates current page to the given URL.\ntype NavigateParams struct {\n\tURL            string         `json:\"url\"`                               // URL to navigate the page to.\n\tReferrer       string         `json:\"referrer,omitempty,omitzero\"`       // Referrer URL.\n\tTransitionType TransitionType `json:\"transitionType,omitempty,omitzero\"` // Intended transition type.\n\tFrameID        cdp.FrameID    `json:\"frameId,omitempty,omitzero\"`        // Frame id to navigate, if not specified navigates the top frame.\n\tReferrerPolicy ReferrerPolicy `json:\"referrerPolicy,omitempty,omitzero\"` // Referrer-policy used for the navigation.\n}\n\n// Navigate navigates current page to the given URL.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-navigate\n//\n// parameters:\n//\n//\turl - URL to navigate the page to.\nfunc Navigate(url string) *NavigateParams {\n\treturn &NavigateParams{\n\t\tURL: url,\n\t}\n}\n\n// WithReferrer referrer URL.\nfunc (p NavigateParams) WithReferrer(referrer string) *NavigateParams {\n\tp.Referrer = referrer\n\treturn &p\n}\n\n// WithTransitionType intended transition type.\nfunc (p NavigateParams) WithTransitionType(transitionType TransitionType) *NavigateParams {\n\tp.TransitionType = transitionType\n\treturn &p\n}\n\n// WithFrameID frame id to navigate, if not specified navigates the top\n// frame.\nfunc (p NavigateParams) WithFrameID(frameID cdp.FrameID) *NavigateParams {\n\tp.FrameID = frameID\n\treturn &p\n}\n\n// WithReferrerPolicy referrer-policy used for the navigation.\nfunc (p NavigateParams) WithReferrerPolicy(referrerPolicy ReferrerPolicy) *NavigateParams {\n\tp.ReferrerPolicy = referrerPolicy\n\treturn &p\n}\n\n// NavigateReturns return values.\ntype NavigateReturns struct {\n\tFrameID    cdp.FrameID  `json:\"frameId,omitempty,omitzero\"`   // Frame id that has navigated (or failed to navigate)\n\tLoaderID   cdp.LoaderID `json:\"loaderId,omitempty,omitzero\"`  // Loader identifier. This is omitted in case of same-document navigation, as the previously committed loaderId would not change.\n\tErrorText  string       `json:\"errorText,omitempty,omitzero\"` // User friendly error message, present if and only if navigation has failed.\n\tIsDownload bool         `json:\"isDownload\"`                   // Whether the navigation resulted in a download.\n}\n\n// Do executes Page.navigate against the provided context.\n//\n// returns:\n//\n//\tframeID - Frame id that has navigated (or failed to navigate)\n//\tloaderID - Loader identifier. This is omitted in case of same-document navigation, as the previously committed loaderId would not change.\n//\terrorText - User friendly error message, present if and only if navigation has failed.\n//\tisDownload - Whether the navigation resulted in a download.\nfunc (p *NavigateParams) Do(ctx context.Context) (frameID cdp.FrameID, loaderID cdp.LoaderID, errorText string, isDownload bool, err error) {\n\t// execute\n\tvar res NavigateReturns\n\terr = cdp.Execute(ctx, CommandNavigate, p, &res)\n\tif err != nil {\n\t\treturn \"\", \"\", \"\", false, err\n\t}\n\n\treturn res.FrameID, res.LoaderID, res.ErrorText, res.IsDownload, nil\n}\n\n// NavigateToHistoryEntryParams navigates current page to the given history\n// entry.\ntype NavigateToHistoryEntryParams struct {\n\tEntryID int64 `json:\"entryId\"` // Unique id of the entry to navigate to.\n}\n\n// NavigateToHistoryEntry navigates current page to the given history entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-navigateToHistoryEntry\n//\n// parameters:\n//\n//\tentryID - Unique id of the entry to navigate to.\nfunc NavigateToHistoryEntry(entryID int64) *NavigateToHistoryEntryParams {\n\treturn &NavigateToHistoryEntryParams{\n\t\tEntryID: entryID,\n\t}\n}\n\n// Do executes Page.navigateToHistoryEntry against the provided context.\nfunc (p *NavigateToHistoryEntryParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandNavigateToHistoryEntry, p, nil)\n}\n\n// PrintToPDFParams print page as PDF.\ntype PrintToPDFParams struct {\n\tLandscape               bool                   `json:\"landscape\"`                         // Paper orientation. Defaults to false.\n\tDisplayHeaderFooter     bool                   `json:\"displayHeaderFooter\"`               // Display header and footer. Defaults to false.\n\tPrintBackground         bool                   `json:\"printBackground\"`                   // Print background graphics. Defaults to false.\n\tScale                   float64                `json:\"scale,omitempty,omitzero\"`          // Scale of the webpage rendering. Defaults to 1.\n\tPaperWidth              float64                `json:\"paperWidth,omitempty,omitzero\"`     // Paper width in inches. Defaults to 8.5 inches.\n\tPaperHeight             float64                `json:\"paperHeight,omitempty,omitzero\"`    // Paper height in inches. Defaults to 11 inches.\n\tMarginTop               float64                `json:\"marginTop\"`                         // Top margin in inches. Defaults to 1cm (~0.4 inches).\n\tMarginBottom            float64                `json:\"marginBottom\"`                      // Bottom margin in inches. Defaults to 1cm (~0.4 inches).\n\tMarginLeft              float64                `json:\"marginLeft\"`                        // Left margin in inches. Defaults to 1cm (~0.4 inches).\n\tMarginRight             float64                `json:\"marginRight\"`                       // Right margin in inches. Defaults to 1cm (~0.4 inches).\n\tPageRanges              string                 `json:\"pageRanges,omitempty,omitzero\"`     // Paper ranges to print, one based, e.g., '1-5, 8, 11-13'. Pages are printed in the document order, not in the order specified, and no more than once. Defaults to empty string, which implies the entire document is printed. The page numbers are quietly capped to actual page count of the document, and ranges beyond the end of the document are ignored. If this results in no pages to print, an error is reported. It is an error to specify a range with start greater than end.\n\tHeaderTemplate          string                 `json:\"headerTemplate,omitempty,omitzero\"` // HTML template for the print header. Should be valid HTML markup with following classes used to inject printing values into them: - date: formatted print date - title: document title - url: document location - pageNumber: current page number - totalPages: total pages in the document  For example, <span class=title></span> would generate span containing the title.\n\tFooterTemplate          string                 `json:\"footerTemplate,omitempty,omitzero\"` // HTML template for the print footer. Should use the same format as the headerTemplate.\n\tPreferCSSPageSize       bool                   `json:\"preferCSSPageSize\"`                 // Whether or not to prefer page size as defined by css. Defaults to false, in which case the content will be scaled to fit the paper size.\n\tTransferMode            PrintToPDFTransferMode `json:\"transferMode,omitempty,omitzero\"`   // return as stream\n\tGenerateTaggedPDF       bool                   `json:\"generateTaggedPDF\"`                 // Whether or not to generate tagged (accessible) PDF. Defaults to embedder choice.\n\tGenerateDocumentOutline bool                   `json:\"generateDocumentOutline\"`           // Whether or not to embed the document outline into the PDF.\n}\n\n// PrintToPDF print page as PDF.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-printToPDF\n//\n// parameters:\nfunc PrintToPDF() *PrintToPDFParams {\n\treturn &PrintToPDFParams{\n\t\tLandscape:               false,\n\t\tDisplayHeaderFooter:     false,\n\t\tPrintBackground:         false,\n\t\tPreferCSSPageSize:       false,\n\t\tGenerateTaggedPDF:       false,\n\t\tGenerateDocumentOutline: false,\n\t}\n}\n\n// WithLandscape paper orientation. Defaults to false.\nfunc (p PrintToPDFParams) WithLandscape(landscape bool) *PrintToPDFParams {\n\tp.Landscape = landscape\n\treturn &p\n}\n\n// WithDisplayHeaderFooter display header and footer. Defaults to false.\nfunc (p PrintToPDFParams) WithDisplayHeaderFooter(displayHeaderFooter bool) *PrintToPDFParams {\n\tp.DisplayHeaderFooter = displayHeaderFooter\n\treturn &p\n}\n\n// WithPrintBackground print background graphics. Defaults to false.\nfunc (p PrintToPDFParams) WithPrintBackground(printBackground bool) *PrintToPDFParams {\n\tp.PrintBackground = printBackground\n\treturn &p\n}\n\n// WithScale scale of the webpage rendering. Defaults to 1.\nfunc (p PrintToPDFParams) WithScale(scale float64) *PrintToPDFParams {\n\tp.Scale = scale\n\treturn &p\n}\n\n// WithPaperWidth paper width in inches. Defaults to 8.5 inches.\nfunc (p PrintToPDFParams) WithPaperWidth(paperWidth float64) *PrintToPDFParams {\n\tp.PaperWidth = paperWidth\n\treturn &p\n}\n\n// WithPaperHeight paper height in inches. Defaults to 11 inches.\nfunc (p PrintToPDFParams) WithPaperHeight(paperHeight float64) *PrintToPDFParams {\n\tp.PaperHeight = paperHeight\n\treturn &p\n}\n\n// WithMarginTop top margin in inches. Defaults to 1cm (~0.4 inches).\nfunc (p PrintToPDFParams) WithMarginTop(marginTop float64) *PrintToPDFParams {\n\tp.MarginTop = marginTop\n\treturn &p\n}\n\n// WithMarginBottom bottom margin in inches. Defaults to 1cm (~0.4 inches).\nfunc (p PrintToPDFParams) WithMarginBottom(marginBottom float64) *PrintToPDFParams {\n\tp.MarginBottom = marginBottom\n\treturn &p\n}\n\n// WithMarginLeft left margin in inches. Defaults to 1cm (~0.4 inches).\nfunc (p PrintToPDFParams) WithMarginLeft(marginLeft float64) *PrintToPDFParams {\n\tp.MarginLeft = marginLeft\n\treturn &p\n}\n\n// WithMarginRight right margin in inches. Defaults to 1cm (~0.4 inches).\nfunc (p PrintToPDFParams) WithMarginRight(marginRight float64) *PrintToPDFParams {\n\tp.MarginRight = marginRight\n\treturn &p\n}\n\n// WithPageRanges paper ranges to print, one based, e.g., '1-5, 8, 11-13'.\n// Pages are printed in the document order, not in the order specified, and no\n// more than once. Defaults to empty string, which implies the entire document\n// is printed. The page numbers are quietly capped to actual page count of the\n// document, and ranges beyond the end of the document are ignored. If this\n// results in no pages to print, an error is reported. It is an error to specify\n// a range with start greater than end.\nfunc (p PrintToPDFParams) WithPageRanges(pageRanges string) *PrintToPDFParams {\n\tp.PageRanges = pageRanges\n\treturn &p\n}\n\n// WithHeaderTemplate HTML template for the print header. Should be valid\n// HTML markup with following classes used to inject printing values into them:\n// - date: formatted print date - title: document title - url: document location\n// - pageNumber: current page number - totalPages: total pages in the document\n// For example, <span class=title></span> would generate span containing the\n// title.\nfunc (p PrintToPDFParams) WithHeaderTemplate(headerTemplate string) *PrintToPDFParams {\n\tp.HeaderTemplate = headerTemplate\n\treturn &p\n}\n\n// WithFooterTemplate HTML template for the print footer. Should use the same\n// format as the headerTemplate.\nfunc (p PrintToPDFParams) WithFooterTemplate(footerTemplate string) *PrintToPDFParams {\n\tp.FooterTemplate = footerTemplate\n\treturn &p\n}\n\n// WithPreferCSSPageSize whether or not to prefer page size as defined by\n// css. Defaults to false, in which case the content will be scaled to fit the\n// paper size.\nfunc (p PrintToPDFParams) WithPreferCSSPageSize(preferCSSPageSize bool) *PrintToPDFParams {\n\tp.PreferCSSPageSize = preferCSSPageSize\n\treturn &p\n}\n\n// WithTransferMode return as stream.\nfunc (p PrintToPDFParams) WithTransferMode(transferMode PrintToPDFTransferMode) *PrintToPDFParams {\n\tp.TransferMode = transferMode\n\treturn &p\n}\n\n// WithGenerateTaggedPDF whether or not to generate tagged (accessible) PDF.\n// Defaults to embedder choice.\nfunc (p PrintToPDFParams) WithGenerateTaggedPDF(generateTaggedPDF bool) *PrintToPDFParams {\n\tp.GenerateTaggedPDF = generateTaggedPDF\n\treturn &p\n}\n\n// WithGenerateDocumentOutline whether or not to embed the document outline\n// into the PDF.\nfunc (p PrintToPDFParams) WithGenerateDocumentOutline(generateDocumentOutline bool) *PrintToPDFParams {\n\tp.GenerateDocumentOutline = generateDocumentOutline\n\treturn &p\n}\n\n// PrintToPDFReturns return values.\ntype PrintToPDFReturns struct {\n\tData   string          `json:\"data,omitempty,omitzero\"`   // Base64-encoded pdf data. Empty if |returnAsStream| is specified.\n\tStream io.StreamHandle `json:\"stream,omitempty,omitzero\"` // A handle of the stream that holds resulting PDF data.\n}\n\n// Do executes Page.printToPDF against the provided context.\n//\n// returns:\n//\n//\tdata - Base64-encoded pdf data. Empty if |returnAsStream| is specified.\n//\tstream - A handle of the stream that holds resulting PDF data.\nfunc (p *PrintToPDFParams) Do(ctx context.Context) (data []byte, stream io.StreamHandle, err error) {\n\t// execute\n\tvar res PrintToPDFReturns\n\terr = cdp.Execute(ctx, CommandPrintToPDF, p, &res)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\t// decode\n\tvar dec []byte\n\tdec, err = base64.StdEncoding.DecodeString(res.Data)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\treturn dec, res.Stream, nil\n}\n\n// ReloadParams reloads given page optionally ignoring the cache.\ntype ReloadParams struct {\n\tIgnoreCache            bool         `json:\"ignoreCache\"`                               // If true, browser cache is ignored (as if the user pressed Shift+refresh).\n\tScriptToEvaluateOnLoad string       `json:\"scriptToEvaluateOnLoad,omitempty,omitzero\"` // If set, the script will be injected into all frames of the inspected page after reload. Argument will be ignored if reloading dataURL origin.\n\tLoaderID               cdp.LoaderID `json:\"loaderId,omitempty,omitzero\"`               // If set, an error will be thrown if the target page's main frame's loader id does not match the provided id. This prevents accidentally reloading an unintended target in case there's a racing navigation.\n}\n\n// Reload reloads given page optionally ignoring the cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-reload\n//\n// parameters:\nfunc Reload() *ReloadParams {\n\treturn &ReloadParams{\n\t\tIgnoreCache: false,\n\t}\n}\n\n// WithIgnoreCache if true, browser cache is ignored (as if the user pressed\n// Shift+refresh).\nfunc (p ReloadParams) WithIgnoreCache(ignoreCache bool) *ReloadParams {\n\tp.IgnoreCache = ignoreCache\n\treturn &p\n}\n\n// WithScriptToEvaluateOnLoad if set, the script will be injected into all\n// frames of the inspected page after reload. Argument will be ignored if\n// reloading dataURL origin.\nfunc (p ReloadParams) WithScriptToEvaluateOnLoad(scriptToEvaluateOnLoad string) *ReloadParams {\n\tp.ScriptToEvaluateOnLoad = scriptToEvaluateOnLoad\n\treturn &p\n}\n\n// WithLoaderID if set, an error will be thrown if the target page's main\n// frame's loader id does not match the provided id. This prevents accidentally\n// reloading an unintended target in case there's a racing navigation.\nfunc (p ReloadParams) WithLoaderID(loaderID cdp.LoaderID) *ReloadParams {\n\tp.LoaderID = loaderID\n\treturn &p\n}\n\n// Do executes Page.reload against the provided context.\nfunc (p *ReloadParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandReload, p, nil)\n}\n\n// RemoveScriptToEvaluateOnNewDocumentParams removes given script from the\n// list.\ntype RemoveScriptToEvaluateOnNewDocumentParams struct {\n\tIdentifier ScriptIdentifier `json:\"identifier\"`\n}\n\n// RemoveScriptToEvaluateOnNewDocument removes given script from the list.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-removeScriptToEvaluateOnNewDocument\n//\n// parameters:\n//\n//\tidentifier\nfunc RemoveScriptToEvaluateOnNewDocument(identifier ScriptIdentifier) *RemoveScriptToEvaluateOnNewDocumentParams {\n\treturn &RemoveScriptToEvaluateOnNewDocumentParams{\n\t\tIdentifier: identifier,\n\t}\n}\n\n// Do executes Page.removeScriptToEvaluateOnNewDocument against the provided context.\nfunc (p *RemoveScriptToEvaluateOnNewDocumentParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveScriptToEvaluateOnNewDocument, p, nil)\n}\n\n// ScreencastFrameAckParams acknowledges that a screencast frame has been\n// received by the frontend.\ntype ScreencastFrameAckParams struct {\n\tSessionID int64 `json:\"sessionId\"` // Frame number.\n}\n\n// ScreencastFrameAck acknowledges that a screencast frame has been received\n// by the frontend.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-screencastFrameAck\n//\n// parameters:\n//\n//\tsessionID - Frame number.\nfunc ScreencastFrameAck(sessionID int64) *ScreencastFrameAckParams {\n\treturn &ScreencastFrameAckParams{\n\t\tSessionID: sessionID,\n\t}\n}\n\n// Do executes Page.screencastFrameAck against the provided context.\nfunc (p *ScreencastFrameAckParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandScreencastFrameAck, p, nil)\n}\n\n// SearchInResourceParams searches for given string in resource content.\ntype SearchInResourceParams struct {\n\tFrameID       cdp.FrameID `json:\"frameId\"`       // Frame id for resource to search in.\n\tURL           string      `json:\"url\"`           // URL of the resource to search in.\n\tQuery         string      `json:\"query\"`         // String to search for.\n\tCaseSensitive bool        `json:\"caseSensitive\"` // If true, search is case sensitive.\n\tIsRegex       bool        `json:\"isRegex\"`       // If true, treats string parameter as regex.\n}\n\n// SearchInResource searches for given string in resource content.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-searchInResource\n//\n// parameters:\n//\n//\tframeID - Frame id for resource to search in.\n//\turl - URL of the resource to search in.\n//\tquery - String to search for.\nfunc SearchInResource(frameID cdp.FrameID, url string, query string) *SearchInResourceParams {\n\treturn &SearchInResourceParams{\n\t\tFrameID:       frameID,\n\t\tURL:           url,\n\t\tQuery:         query,\n\t\tCaseSensitive: false,\n\t\tIsRegex:       false,\n\t}\n}\n\n// WithCaseSensitive if true, search is case sensitive.\nfunc (p SearchInResourceParams) WithCaseSensitive(caseSensitive bool) *SearchInResourceParams {\n\tp.CaseSensitive = caseSensitive\n\treturn &p\n}\n\n// WithIsRegex if true, treats string parameter as regex.\nfunc (p SearchInResourceParams) WithIsRegex(isRegex bool) *SearchInResourceParams {\n\tp.IsRegex = isRegex\n\treturn &p\n}\n\n// SearchInResourceReturns return values.\ntype SearchInResourceReturns struct {\n\tResult []*debugger.SearchMatch `json:\"result,omitempty,omitzero\"` // List of search matches.\n}\n\n// Do executes Page.searchInResource against the provided context.\n//\n// returns:\n//\n//\tresult - List of search matches.\nfunc (p *SearchInResourceParams) Do(ctx context.Context) (result []*debugger.SearchMatch, err error) {\n\t// execute\n\tvar res SearchInResourceReturns\n\terr = cdp.Execute(ctx, CommandSearchInResource, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Result, nil\n}\n\n// SetAdBlockingEnabledParams enable Chrome's experimental ad filter on all\n// sites.\ntype SetAdBlockingEnabledParams struct {\n\tEnabled bool `json:\"enabled\"` // Whether to block ads.\n}\n\n// SetAdBlockingEnabled enable Chrome's experimental ad filter on all sites.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setAdBlockingEnabled\n//\n// parameters:\n//\n//\tenabled - Whether to block ads.\nfunc SetAdBlockingEnabled(enabled bool) *SetAdBlockingEnabledParams {\n\treturn &SetAdBlockingEnabledParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Page.setAdBlockingEnabled against the provided context.\nfunc (p *SetAdBlockingEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAdBlockingEnabled, p, nil)\n}\n\n// SetBypassCSPParams enable page Content Security Policy by-passing.\ntype SetBypassCSPParams struct {\n\tEnabled bool `json:\"enabled\"` // Whether to bypass page CSP.\n}\n\n// SetBypassCSP enable page Content Security Policy by-passing.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setBypassCSP\n//\n// parameters:\n//\n//\tenabled - Whether to bypass page CSP.\nfunc SetBypassCSP(enabled bool) *SetBypassCSPParams {\n\treturn &SetBypassCSPParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Page.setBypassCSP against the provided context.\nfunc (p *SetBypassCSPParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetBypassCSP, p, nil)\n}\n\n// GetPermissionsPolicyStateParams get Permissions Policy state on given\n// frame.\ntype GetPermissionsPolicyStateParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"`\n}\n\n// GetPermissionsPolicyState get Permissions Policy state on given frame.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getPermissionsPolicyState\n//\n// parameters:\n//\n//\tframeID\nfunc GetPermissionsPolicyState(frameID cdp.FrameID) *GetPermissionsPolicyStateParams {\n\treturn &GetPermissionsPolicyStateParams{\n\t\tFrameID: frameID,\n\t}\n}\n\n// GetPermissionsPolicyStateReturns return values.\ntype GetPermissionsPolicyStateReturns struct {\n\tStates []*PermissionsPolicyFeatureState `json:\"states,omitempty,omitzero\"`\n}\n\n// Do executes Page.getPermissionsPolicyState against the provided context.\n//\n// returns:\n//\n//\tstates\nfunc (p *GetPermissionsPolicyStateParams) Do(ctx context.Context) (states []*PermissionsPolicyFeatureState, err error) {\n\t// execute\n\tvar res GetPermissionsPolicyStateReturns\n\terr = cdp.Execute(ctx, CommandGetPermissionsPolicyState, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.States, nil\n}\n\n// GetOriginTrialsParams get Origin Trials on given frame.\ntype GetOriginTrialsParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"`\n}\n\n// GetOriginTrials get Origin Trials on given frame.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-getOriginTrials\n//\n// parameters:\n//\n//\tframeID\nfunc GetOriginTrials(frameID cdp.FrameID) *GetOriginTrialsParams {\n\treturn &GetOriginTrialsParams{\n\t\tFrameID: frameID,\n\t}\n}\n\n// GetOriginTrialsReturns return values.\ntype GetOriginTrialsReturns struct {\n\tOriginTrials []*cdp.OriginTrial `json:\"originTrials,omitempty,omitzero\"`\n}\n\n// Do executes Page.getOriginTrials against the provided context.\n//\n// returns:\n//\n//\toriginTrials\nfunc (p *GetOriginTrialsParams) Do(ctx context.Context) (originTrials []*cdp.OriginTrial, err error) {\n\t// execute\n\tvar res GetOriginTrialsReturns\n\terr = cdp.Execute(ctx, CommandGetOriginTrials, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.OriginTrials, nil\n}\n\n// SetFontFamiliesParams set generic font families.\ntype SetFontFamiliesParams struct {\n\tFontFamilies *FontFamilies         `json:\"fontFamilies\"`                  // Specifies font families to set. If a font family is not specified, it won't be changed.\n\tForScripts   []*ScriptFontFamilies `json:\"forScripts,omitempty,omitzero\"` // Specifies font families to set for individual scripts.\n}\n\n// SetFontFamilies set generic font families.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setFontFamilies\n//\n// parameters:\n//\n//\tfontFamilies - Specifies font families to set. If a font family is not specified, it won't be changed.\nfunc SetFontFamilies(fontFamilies *FontFamilies) *SetFontFamiliesParams {\n\treturn &SetFontFamiliesParams{\n\t\tFontFamilies: fontFamilies,\n\t}\n}\n\n// WithForScripts specifies font families to set for individual scripts.\nfunc (p SetFontFamiliesParams) WithForScripts(forScripts []*ScriptFontFamilies) *SetFontFamiliesParams {\n\tp.ForScripts = forScripts\n\treturn &p\n}\n\n// Do executes Page.setFontFamilies against the provided context.\nfunc (p *SetFontFamiliesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetFontFamilies, p, nil)\n}\n\n// SetFontSizesParams set default font sizes.\ntype SetFontSizesParams struct {\n\tFontSizes *FontSizes `json:\"fontSizes\"` // Specifies font sizes to set. If a font size is not specified, it won't be changed.\n}\n\n// SetFontSizes set default font sizes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setFontSizes\n//\n// parameters:\n//\n//\tfontSizes - Specifies font sizes to set. If a font size is not specified, it won't be changed.\nfunc SetFontSizes(fontSizes *FontSizes) *SetFontSizesParams {\n\treturn &SetFontSizesParams{\n\t\tFontSizes: fontSizes,\n\t}\n}\n\n// Do executes Page.setFontSizes against the provided context.\nfunc (p *SetFontSizesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetFontSizes, p, nil)\n}\n\n// SetDocumentContentParams sets given markup as the document's HTML.\ntype SetDocumentContentParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"` // Frame id to set HTML for.\n\tHTML    string      `json:\"html\"`    // HTML content to set.\n}\n\n// SetDocumentContent sets given markup as the document's HTML.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setDocumentContent\n//\n// parameters:\n//\n//\tframeID - Frame id to set HTML for.\n//\thtml - HTML content to set.\nfunc SetDocumentContent(frameID cdp.FrameID, html string) *SetDocumentContentParams {\n\treturn &SetDocumentContentParams{\n\t\tFrameID: frameID,\n\t\tHTML:    html,\n\t}\n}\n\n// Do executes Page.setDocumentContent against the provided context.\nfunc (p *SetDocumentContentParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDocumentContent, p, nil)\n}\n\n// SetLifecycleEventsEnabledParams controls whether page will emit lifecycle\n// events.\ntype SetLifecycleEventsEnabledParams struct {\n\tEnabled bool `json:\"enabled\"` // If true, starts emitting lifecycle events.\n}\n\n// SetLifecycleEventsEnabled controls whether page will emit lifecycle\n// events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setLifecycleEventsEnabled\n//\n// parameters:\n//\n//\tenabled - If true, starts emitting lifecycle events.\nfunc SetLifecycleEventsEnabled(enabled bool) *SetLifecycleEventsEnabledParams {\n\treturn &SetLifecycleEventsEnabledParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Page.setLifecycleEventsEnabled against the provided context.\nfunc (p *SetLifecycleEventsEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetLifecycleEventsEnabled, p, nil)\n}\n\n// StartScreencastParams starts sending each frame using the screencastFrame\n// event.\ntype StartScreencastParams struct {\n\tFormat        ScreencastFormat `json:\"format,omitempty,omitzero\"`        // Image compression format.\n\tQuality       int64            `json:\"quality,omitempty,omitzero\"`       // Compression quality from range [0..100].\n\tMaxWidth      int64            `json:\"maxWidth,omitempty,omitzero\"`      // Maximum screenshot width.\n\tMaxHeight     int64            `json:\"maxHeight,omitempty,omitzero\"`     // Maximum screenshot height.\n\tEveryNthFrame int64            `json:\"everyNthFrame,omitempty,omitzero\"` // Send every n-th frame.\n}\n\n// StartScreencast starts sending each frame using the screencastFrame event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-startScreencast\n//\n// parameters:\nfunc StartScreencast() *StartScreencastParams {\n\treturn &StartScreencastParams{}\n}\n\n// WithFormat image compression format.\nfunc (p StartScreencastParams) WithFormat(format ScreencastFormat) *StartScreencastParams {\n\tp.Format = format\n\treturn &p\n}\n\n// WithQuality compression quality from range [0..100].\nfunc (p StartScreencastParams) WithQuality(quality int64) *StartScreencastParams {\n\tp.Quality = quality\n\treturn &p\n}\n\n// WithMaxWidth maximum screenshot width.\nfunc (p StartScreencastParams) WithMaxWidth(maxWidth int64) *StartScreencastParams {\n\tp.MaxWidth = maxWidth\n\treturn &p\n}\n\n// WithMaxHeight maximum screenshot height.\nfunc (p StartScreencastParams) WithMaxHeight(maxHeight int64) *StartScreencastParams {\n\tp.MaxHeight = maxHeight\n\treturn &p\n}\n\n// WithEveryNthFrame send every n-th frame.\nfunc (p StartScreencastParams) WithEveryNthFrame(everyNthFrame int64) *StartScreencastParams {\n\tp.EveryNthFrame = everyNthFrame\n\treturn &p\n}\n\n// Do executes Page.startScreencast against the provided context.\nfunc (p *StartScreencastParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartScreencast, p, nil)\n}\n\n// StopLoadingParams force the page stop all navigations and pending resource\n// fetches.\ntype StopLoadingParams struct{}\n\n// StopLoading force the page stop all navigations and pending resource\n// fetches.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-stopLoading\nfunc StopLoading() *StopLoadingParams {\n\treturn &StopLoadingParams{}\n}\n\n// Do executes Page.stopLoading against the provided context.\nfunc (p *StopLoadingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopLoading, nil, nil)\n}\n\n// CrashParams crashes renderer on the IO thread, generates minidumps.\ntype CrashParams struct{}\n\n// Crash crashes renderer on the IO thread, generates minidumps.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-crash\nfunc Crash() *CrashParams {\n\treturn &CrashParams{}\n}\n\n// Do executes Page.crash against the provided context.\nfunc (p *CrashParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCrash, nil, nil)\n}\n\n// CloseParams tries to close page, running its beforeunload hooks, if any.\ntype CloseParams struct{}\n\n// Close tries to close page, running its beforeunload hooks, if any.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-close\nfunc Close() *CloseParams {\n\treturn &CloseParams{}\n}\n\n// Do executes Page.close against the provided context.\nfunc (p *CloseParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClose, nil, nil)\n}\n\n// SetWebLifecycleStateParams tries to update the web lifecycle state of the\n// page. It will transition the page to the given state according to:\n// https://github.com/WICG/web-lifecycle/.\ntype SetWebLifecycleStateParams struct {\n\tState SetWebLifecycleStateState `json:\"state\"` // Target lifecycle state\n}\n\n// SetWebLifecycleState tries to update the web lifecycle state of the page.\n// It will transition the page to the given state according to:\n// https://github.com/WICG/web-lifecycle/.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setWebLifecycleState\n//\n// parameters:\n//\n//\tstate - Target lifecycle state\nfunc SetWebLifecycleState(state SetWebLifecycleStateState) *SetWebLifecycleStateParams {\n\treturn &SetWebLifecycleStateParams{\n\t\tState: state,\n\t}\n}\n\n// Do executes Page.setWebLifecycleState against the provided context.\nfunc (p *SetWebLifecycleStateParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetWebLifecycleState, p, nil)\n}\n\n// StopScreencastParams stops sending each frame in the screencastFrame.\ntype StopScreencastParams struct{}\n\n// StopScreencast stops sending each frame in the screencastFrame.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-stopScreencast\nfunc StopScreencast() *StopScreencastParams {\n\treturn &StopScreencastParams{}\n}\n\n// Do executes Page.stopScreencast against the provided context.\nfunc (p *StopScreencastParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopScreencast, nil, nil)\n}\n\n// ProduceCompilationCacheParams requests backend to produce compilation\n// cache for the specified scripts. scripts are appended to the list of scripts\n// for which the cache would be produced. The list may be reset during page\n// navigation. When script with a matching URL is encountered, the cache is\n// optionally produced upon backend discretion, based on internal heuristics.\n// See also: Page.compilationCacheProduced.\ntype ProduceCompilationCacheParams struct {\n\tScripts []*CompilationCacheParams `json:\"scripts\"`\n}\n\n// ProduceCompilationCache requests backend to produce compilation cache for\n// the specified scripts. scripts are appended to the list of scripts for which\n// the cache would be produced. The list may be reset during page navigation.\n// When script with a matching URL is encountered, the cache is optionally\n// produced upon backend discretion, based on internal heuristics. See also:\n// Page.compilationCacheProduced.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-produceCompilationCache\n//\n// parameters:\n//\n//\tscripts\nfunc ProduceCompilationCache(scripts []*CompilationCacheParams) *ProduceCompilationCacheParams {\n\treturn &ProduceCompilationCacheParams{\n\t\tScripts: scripts,\n\t}\n}\n\n// Do executes Page.produceCompilationCache against the provided context.\nfunc (p *ProduceCompilationCacheParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandProduceCompilationCache, p, nil)\n}\n\n// AddCompilationCacheParams seeds compilation cache for given url.\n// Compilation cache does not survive cross-process navigation.\ntype AddCompilationCacheParams struct {\n\tURL  string `json:\"url\"`\n\tData string `json:\"data\"` // Base64-encoded data\n}\n\n// AddCompilationCache seeds compilation cache for given url. Compilation\n// cache does not survive cross-process navigation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-addCompilationCache\n//\n// parameters:\n//\n//\turl\n//\tdata - Base64-encoded data\nfunc AddCompilationCache(url string, data string) *AddCompilationCacheParams {\n\treturn &AddCompilationCacheParams{\n\t\tURL:  url,\n\t\tData: data,\n\t}\n}\n\n// Do executes Page.addCompilationCache against the provided context.\nfunc (p *AddCompilationCacheParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandAddCompilationCache, p, nil)\n}\n\n// ClearCompilationCacheParams clears seeded compilation cache.\ntype ClearCompilationCacheParams struct{}\n\n// ClearCompilationCache clears seeded compilation cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-clearCompilationCache\nfunc ClearCompilationCache() *ClearCompilationCacheParams {\n\treturn &ClearCompilationCacheParams{}\n}\n\n// Do executes Page.clearCompilationCache against the provided context.\nfunc (p *ClearCompilationCacheParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearCompilationCache, nil, nil)\n}\n\n// SetSPCTransactionModeParams sets the Secure Payment Confirmation\n// transaction mode.\n// https://w3c.github.io/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode.\ntype SetSPCTransactionModeParams struct {\n\tMode SetSPCTransactionModeMode `json:\"mode\"`\n}\n\n// SetSPCTransactionMode sets the Secure Payment Confirmation transaction\n// mode.\n// https://w3c.github.io/secure-payment-confirmation/#sctn-automation-set-spc-transaction-mode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setSPCTransactionMode\n//\n// parameters:\n//\n//\tmode\nfunc SetSPCTransactionMode(mode SetSPCTransactionModeMode) *SetSPCTransactionModeParams {\n\treturn &SetSPCTransactionModeParams{\n\t\tMode: mode,\n\t}\n}\n\n// Do executes Page.setSPCTransactionMode against the provided context.\nfunc (p *SetSPCTransactionModeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSPCTransactionMode, p, nil)\n}\n\n// SetRPHRegistrationModeParams extensions for Custom Handlers API:\n// https://html.spec.whatwg.org/multipage/system-state.html#rph-automation.\ntype SetRPHRegistrationModeParams struct {\n\tMode SetRPHRegistrationModeMode `json:\"mode\"`\n}\n\n// SetRPHRegistrationMode extensions for Custom Handlers API:\n// https://html.spec.whatwg.org/multipage/system-state.html#rph-automation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setRPHRegistrationMode\n//\n// parameters:\n//\n//\tmode\nfunc SetRPHRegistrationMode(mode SetRPHRegistrationModeMode) *SetRPHRegistrationModeParams {\n\treturn &SetRPHRegistrationModeParams{\n\t\tMode: mode,\n\t}\n}\n\n// Do executes Page.setRPHRegistrationMode against the provided context.\nfunc (p *SetRPHRegistrationModeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetRPHRegistrationMode, p, nil)\n}\n\n// GenerateTestReportParams generates a report for testing.\ntype GenerateTestReportParams struct {\n\tMessage string `json:\"message\"`                  // Message to be displayed in the report.\n\tGroup   string `json:\"group,omitempty,omitzero\"` // Specifies the endpoint group to deliver the report to.\n}\n\n// GenerateTestReport generates a report for testing.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-generateTestReport\n//\n// parameters:\n//\n//\tmessage - Message to be displayed in the report.\nfunc GenerateTestReport(message string) *GenerateTestReportParams {\n\treturn &GenerateTestReportParams{\n\t\tMessage: message,\n\t}\n}\n\n// WithGroup specifies the endpoint group to deliver the report to.\nfunc (p GenerateTestReportParams) WithGroup(group string) *GenerateTestReportParams {\n\tp.Group = group\n\treturn &p\n}\n\n// Do executes Page.generateTestReport against the provided context.\nfunc (p *GenerateTestReportParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandGenerateTestReport, p, nil)\n}\n\n// WaitForDebuggerParams pauses page execution. Can be resumed using generic\n// Runtime.runIfWaitingForDebugger.\ntype WaitForDebuggerParams struct{}\n\n// WaitForDebugger pauses page execution. Can be resumed using generic\n// Runtime.runIfWaitingForDebugger.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-waitForDebugger\nfunc WaitForDebugger() *WaitForDebuggerParams {\n\treturn &WaitForDebuggerParams{}\n}\n\n// Do executes Page.waitForDebugger against the provided context.\nfunc (p *WaitForDebuggerParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandWaitForDebugger, nil, nil)\n}\n\n// SetInterceptFileChooserDialogParams intercept file chooser requests and\n// transfer control to protocol clients. When file chooser interception is\n// enabled, native file chooser dialog is not shown. Instead, a protocol event\n// Page.fileChooserOpened is emitted.\ntype SetInterceptFileChooserDialogParams struct {\n\tEnabled bool `json:\"enabled\"`\n\tCancel  bool `json:\"cancel\"` // If true, cancels the dialog by emitting relevant events (if any) in addition to not showing it if the interception is enabled (default: false).\n}\n\n// SetInterceptFileChooserDialog intercept file chooser requests and transfer\n// control to protocol clients. When file chooser interception is enabled,\n// native file chooser dialog is not shown. Instead, a protocol event\n// Page.fileChooserOpened is emitted.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setInterceptFileChooserDialog\n//\n// parameters:\n//\n//\tenabled\nfunc SetInterceptFileChooserDialog(enabled bool) *SetInterceptFileChooserDialogParams {\n\treturn &SetInterceptFileChooserDialogParams{\n\t\tEnabled: enabled,\n\t\tCancel:  false,\n\t}\n}\n\n// WithCancel if true, cancels the dialog by emitting relevant events (if\n// any) in addition to not showing it if the interception is enabled (default:\n// false).\nfunc (p SetInterceptFileChooserDialogParams) WithCancel(cancel bool) *SetInterceptFileChooserDialogParams {\n\tp.Cancel = cancel\n\treturn &p\n}\n\n// Do executes Page.setInterceptFileChooserDialog against the provided context.\nfunc (p *SetInterceptFileChooserDialogParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetInterceptFileChooserDialog, p, nil)\n}\n\n// SetPrerenderingAllowedParams enable/disable prerendering manually. This\n// command is a short-term solution for https://crbug.com/1440085. See\n// https://docs.google.com/document/d/12HVmFxYj5Jc-eJr5OmWsa2bqTJsbgGLKI6ZIyx0_wpA\n// for more details. TODO(https://crbug.com/1440085): Remove this once Puppeteer\n// supports tab targets.\ntype SetPrerenderingAllowedParams struct {\n\tIsAllowed bool `json:\"isAllowed\"`\n}\n\n// SetPrerenderingAllowed enable/disable prerendering manually. This command\n// is a short-term solution for https://crbug.com/1440085. See\n// https://docs.google.com/document/d/12HVmFxYj5Jc-eJr5OmWsa2bqTJsbgGLKI6ZIyx0_wpA\n// for more details. TODO(https://crbug.com/1440085): Remove this once Puppeteer\n// supports tab targets.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setPrerenderingAllowed\n//\n// parameters:\n//\n//\tisAllowed\nfunc SetPrerenderingAllowed(isAllowed bool) *SetPrerenderingAllowedParams {\n\treturn &SetPrerenderingAllowedParams{\n\t\tIsAllowed: isAllowed,\n\t}\n}\n\n// Do executes Page.setPrerenderingAllowed against the provided context.\nfunc (p *SetPrerenderingAllowedParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetPrerenderingAllowed, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandAddScriptToEvaluateOnNewDocument    = \"Page.addScriptToEvaluateOnNewDocument\"\n\tCommandBringToFront                        = \"Page.bringToFront\"\n\tCommandCaptureScreenshot                   = \"Page.captureScreenshot\"\n\tCommandCaptureSnapshot                     = \"Page.captureSnapshot\"\n\tCommandCreateIsolatedWorld                 = \"Page.createIsolatedWorld\"\n\tCommandDisable                             = \"Page.disable\"\n\tCommandEnable                              = \"Page.enable\"\n\tCommandGetAppManifest                      = \"Page.getAppManifest\"\n\tCommandGetInstallabilityErrors             = \"Page.getInstallabilityErrors\"\n\tCommandGetAppID                            = \"Page.getAppId\"\n\tCommandGetAdScriptAncestry                 = \"Page.getAdScriptAncestry\"\n\tCommandGetFrameTree                        = \"Page.getFrameTree\"\n\tCommandGetLayoutMetrics                    = \"Page.getLayoutMetrics\"\n\tCommandGetNavigationHistory                = \"Page.getNavigationHistory\"\n\tCommandResetNavigationHistory              = \"Page.resetNavigationHistory\"\n\tCommandGetResourceContent                  = \"Page.getResourceContent\"\n\tCommandGetResourceTree                     = \"Page.getResourceTree\"\n\tCommandHandleJavaScriptDialog              = \"Page.handleJavaScriptDialog\"\n\tCommandNavigate                            = \"Page.navigate\"\n\tCommandNavigateToHistoryEntry              = \"Page.navigateToHistoryEntry\"\n\tCommandPrintToPDF                          = \"Page.printToPDF\"\n\tCommandReload                              = \"Page.reload\"\n\tCommandRemoveScriptToEvaluateOnNewDocument = \"Page.removeScriptToEvaluateOnNewDocument\"\n\tCommandScreencastFrameAck                  = \"Page.screencastFrameAck\"\n\tCommandSearchInResource                    = \"Page.searchInResource\"\n\tCommandSetAdBlockingEnabled                = \"Page.setAdBlockingEnabled\"\n\tCommandSetBypassCSP                        = \"Page.setBypassCSP\"\n\tCommandGetPermissionsPolicyState           = \"Page.getPermissionsPolicyState\"\n\tCommandGetOriginTrials                     = \"Page.getOriginTrials\"\n\tCommandSetFontFamilies                     = \"Page.setFontFamilies\"\n\tCommandSetFontSizes                        = \"Page.setFontSizes\"\n\tCommandSetDocumentContent                  = \"Page.setDocumentContent\"\n\tCommandSetLifecycleEventsEnabled           = \"Page.setLifecycleEventsEnabled\"\n\tCommandStartScreencast                     = \"Page.startScreencast\"\n\tCommandStopLoading                         = \"Page.stopLoading\"\n\tCommandCrash                               = \"Page.crash\"\n\tCommandClose                               = \"Page.close\"\n\tCommandSetWebLifecycleState                = \"Page.setWebLifecycleState\"\n\tCommandStopScreencast                      = \"Page.stopScreencast\"\n\tCommandProduceCompilationCache             = \"Page.produceCompilationCache\"\n\tCommandAddCompilationCache                 = \"Page.addCompilationCache\"\n\tCommandClearCompilationCache               = \"Page.clearCompilationCache\"\n\tCommandSetSPCTransactionMode               = \"Page.setSPCTransactionMode\"\n\tCommandSetRPHRegistrationMode              = \"Page.setRPHRegistrationMode\"\n\tCommandGenerateTestReport                  = \"Page.generateTestReport\"\n\tCommandWaitForDebugger                     = \"Page.waitForDebugger\"\n\tCommandSetInterceptFileChooserDialog       = \"Page.setInterceptFileChooserDialog\"\n\tCommandSetPrerenderingAllowed              = \"Page.setPrerenderingAllowed\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/page/types.go",
    "content": "package page\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// AdScriptID identifies the script which caused a script or frame to be\n// labelled as an ad.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-AdScriptId\ntype AdScriptID struct {\n\tScriptID   runtime.ScriptID         `json:\"scriptId\"`   // Script Id of the script which caused a script or frame to be labelled as an ad.\n\tDebuggerID runtime.UniqueDebuggerID `json:\"debuggerId\"` // Id of scriptId's debugger.\n}\n\n// AdScriptAncestry encapsulates the script ancestry and the root script\n// filterlist rule that caused the frame to be labelled as an ad. Only created\n// when ancestryChain is not empty.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-AdScriptAncestry\ntype AdScriptAncestry struct {\n\tAncestryChain            []*AdScriptID `json:\"ancestryChain\"`                               // A chain of AdScriptIds representing the ancestry of an ad script that led to the creation of a frame. The chain is ordered from the script itself (lower level) up to its root ancestor that was flagged by filterlist.\n\tRootScriptFilterlistRule string        `json:\"rootScriptFilterlistRule,omitempty,omitzero\"` // The filterlist rule that caused the root (last) script in ancestryChain to be ad-tagged. Only populated if the rule is available.\n}\n\n// PermissionsPolicyFeature all Permissions Policy features. This enum should\n// match the one defined in\n// services/network/public/cpp/permissions_policy/permissions_policy_features.json5.\n// LINT.IfChange(PermissionsPolicyFeature).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-PermissionsPolicyFeature\ntype PermissionsPolicyFeature string\n\n// String returns the PermissionsPolicyFeature as string value.\nfunc (t PermissionsPolicyFeature) String() string {\n\treturn string(t)\n}\n\n// PermissionsPolicyFeature values.\nconst (\n\tPermissionsPolicyFeatureAccelerometer                  PermissionsPolicyFeature = \"accelerometer\"\n\tPermissionsPolicyFeatureAllScreensCapture              PermissionsPolicyFeature = \"all-screens-capture\"\n\tPermissionsPolicyFeatureAmbientLightSensor             PermissionsPolicyFeature = \"ambient-light-sensor\"\n\tPermissionsPolicyFeatureAriaNotify                     PermissionsPolicyFeature = \"aria-notify\"\n\tPermissionsPolicyFeatureAttributionReporting           PermissionsPolicyFeature = \"attribution-reporting\"\n\tPermissionsPolicyFeatureAutoplay                       PermissionsPolicyFeature = \"autoplay\"\n\tPermissionsPolicyFeatureBluetooth                      PermissionsPolicyFeature = \"bluetooth\"\n\tPermissionsPolicyFeatureBrowsingTopics                 PermissionsPolicyFeature = \"browsing-topics\"\n\tPermissionsPolicyFeatureCamera                         PermissionsPolicyFeature = \"camera\"\n\tPermissionsPolicyFeatureCapturedSurfaceControl         PermissionsPolicyFeature = \"captured-surface-control\"\n\tPermissionsPolicyFeatureChDpr                          PermissionsPolicyFeature = \"ch-dpr\"\n\tPermissionsPolicyFeatureChDeviceMemory                 PermissionsPolicyFeature = \"ch-device-memory\"\n\tPermissionsPolicyFeatureChDownlink                     PermissionsPolicyFeature = \"ch-downlink\"\n\tPermissionsPolicyFeatureChEct                          PermissionsPolicyFeature = \"ch-ect\"\n\tPermissionsPolicyFeatureChPrefersColorScheme           PermissionsPolicyFeature = \"ch-prefers-color-scheme\"\n\tPermissionsPolicyFeatureChPrefersReducedMotion         PermissionsPolicyFeature = \"ch-prefers-reduced-motion\"\n\tPermissionsPolicyFeatureChPrefersReducedTransparency   PermissionsPolicyFeature = \"ch-prefers-reduced-transparency\"\n\tPermissionsPolicyFeatureChRtt                          PermissionsPolicyFeature = \"ch-rtt\"\n\tPermissionsPolicyFeatureChSaveData                     PermissionsPolicyFeature = \"ch-save-data\"\n\tPermissionsPolicyFeatureChUa                           PermissionsPolicyFeature = \"ch-ua\"\n\tPermissionsPolicyFeatureChUaArch                       PermissionsPolicyFeature = \"ch-ua-arch\"\n\tPermissionsPolicyFeatureChUaBitness                    PermissionsPolicyFeature = \"ch-ua-bitness\"\n\tPermissionsPolicyFeatureChUaHighEntropyValues          PermissionsPolicyFeature = \"ch-ua-high-entropy-values\"\n\tPermissionsPolicyFeatureChUaPlatform                   PermissionsPolicyFeature = \"ch-ua-platform\"\n\tPermissionsPolicyFeatureChUaModel                      PermissionsPolicyFeature = \"ch-ua-model\"\n\tPermissionsPolicyFeatureChUaMobile                     PermissionsPolicyFeature = \"ch-ua-mobile\"\n\tPermissionsPolicyFeatureChUaFormFactors                PermissionsPolicyFeature = \"ch-ua-form-factors\"\n\tPermissionsPolicyFeatureChUaFullVersion                PermissionsPolicyFeature = \"ch-ua-full-version\"\n\tPermissionsPolicyFeatureChUaFullVersionList            PermissionsPolicyFeature = \"ch-ua-full-version-list\"\n\tPermissionsPolicyFeatureChUaPlatformVersion            PermissionsPolicyFeature = \"ch-ua-platform-version\"\n\tPermissionsPolicyFeatureChUaWow64                      PermissionsPolicyFeature = \"ch-ua-wow64\"\n\tPermissionsPolicyFeatureChViewportHeight               PermissionsPolicyFeature = \"ch-viewport-height\"\n\tPermissionsPolicyFeatureChViewportWidth                PermissionsPolicyFeature = \"ch-viewport-width\"\n\tPermissionsPolicyFeatureChWidth                        PermissionsPolicyFeature = \"ch-width\"\n\tPermissionsPolicyFeatureClipboardRead                  PermissionsPolicyFeature = \"clipboard-read\"\n\tPermissionsPolicyFeatureClipboardWrite                 PermissionsPolicyFeature = \"clipboard-write\"\n\tPermissionsPolicyFeatureComputePressure                PermissionsPolicyFeature = \"compute-pressure\"\n\tPermissionsPolicyFeatureControlledFrame                PermissionsPolicyFeature = \"controlled-frame\"\n\tPermissionsPolicyFeatureCrossOriginIsolated            PermissionsPolicyFeature = \"cross-origin-isolated\"\n\tPermissionsPolicyFeatureDeferredFetch                  PermissionsPolicyFeature = \"deferred-fetch\"\n\tPermissionsPolicyFeatureDeferredFetchMinimal           PermissionsPolicyFeature = \"deferred-fetch-minimal\"\n\tPermissionsPolicyFeatureDeviceAttributes               PermissionsPolicyFeature = \"device-attributes\"\n\tPermissionsPolicyFeatureDigitalCredentialsGet          PermissionsPolicyFeature = \"digital-credentials-get\"\n\tPermissionsPolicyFeatureDirectSockets                  PermissionsPolicyFeature = \"direct-sockets\"\n\tPermissionsPolicyFeatureDirectSocketsPrivate           PermissionsPolicyFeature = \"direct-sockets-private\"\n\tPermissionsPolicyFeatureDisplayCapture                 PermissionsPolicyFeature = \"display-capture\"\n\tPermissionsPolicyFeatureDocumentDomain                 PermissionsPolicyFeature = \"document-domain\"\n\tPermissionsPolicyFeatureEncryptedMedia                 PermissionsPolicyFeature = \"encrypted-media\"\n\tPermissionsPolicyFeatureExecutionWhileOutOfViewport    PermissionsPolicyFeature = \"execution-while-out-of-viewport\"\n\tPermissionsPolicyFeatureExecutionWhileNotRendered      PermissionsPolicyFeature = \"execution-while-not-rendered\"\n\tPermissionsPolicyFeatureFencedUnpartitionedStorageRead PermissionsPolicyFeature = \"fenced-unpartitioned-storage-read\"\n\tPermissionsPolicyFeatureFocusWithoutUserActivation     PermissionsPolicyFeature = \"focus-without-user-activation\"\n\tPermissionsPolicyFeatureFullscreen                     PermissionsPolicyFeature = \"fullscreen\"\n\tPermissionsPolicyFeatureFrobulate                      PermissionsPolicyFeature = \"frobulate\"\n\tPermissionsPolicyFeatureGamepad                        PermissionsPolicyFeature = \"gamepad\"\n\tPermissionsPolicyFeatureGeolocation                    PermissionsPolicyFeature = \"geolocation\"\n\tPermissionsPolicyFeatureGyroscope                      PermissionsPolicyFeature = \"gyroscope\"\n\tPermissionsPolicyFeatureHid                            PermissionsPolicyFeature = \"hid\"\n\tPermissionsPolicyFeatureIdentityCredentialsGet         PermissionsPolicyFeature = \"identity-credentials-get\"\n\tPermissionsPolicyFeatureIdleDetection                  PermissionsPolicyFeature = \"idle-detection\"\n\tPermissionsPolicyFeatureInterestCohort                 PermissionsPolicyFeature = \"interest-cohort\"\n\tPermissionsPolicyFeatureJoinAdInterestGroup            PermissionsPolicyFeature = \"join-ad-interest-group\"\n\tPermissionsPolicyFeatureKeyboardMap                    PermissionsPolicyFeature = \"keyboard-map\"\n\tPermissionsPolicyFeatureLanguageDetector               PermissionsPolicyFeature = \"language-detector\"\n\tPermissionsPolicyFeatureLanguageModel                  PermissionsPolicyFeature = \"language-model\"\n\tPermissionsPolicyFeatureLocalFonts                     PermissionsPolicyFeature = \"local-fonts\"\n\tPermissionsPolicyFeatureLocalNetworkAccess             PermissionsPolicyFeature = \"local-network-access\"\n\tPermissionsPolicyFeatureMagnetometer                   PermissionsPolicyFeature = \"magnetometer\"\n\tPermissionsPolicyFeatureMediaPlaybackWhileNotVisible   PermissionsPolicyFeature = \"media-playback-while-not-visible\"\n\tPermissionsPolicyFeatureMicrophone                     PermissionsPolicyFeature = \"microphone\"\n\tPermissionsPolicyFeatureMidi                           PermissionsPolicyFeature = \"midi\"\n\tPermissionsPolicyFeatureOnDeviceSpeechRecognition      PermissionsPolicyFeature = \"on-device-speech-recognition\"\n\tPermissionsPolicyFeatureOtpCredentials                 PermissionsPolicyFeature = \"otp-credentials\"\n\tPermissionsPolicyFeaturePayment                        PermissionsPolicyFeature = \"payment\"\n\tPermissionsPolicyFeaturePictureInPicture               PermissionsPolicyFeature = \"picture-in-picture\"\n\tPermissionsPolicyFeaturePopins                         PermissionsPolicyFeature = \"popins\"\n\tPermissionsPolicyFeaturePrivateAggregation             PermissionsPolicyFeature = \"private-aggregation\"\n\tPermissionsPolicyFeaturePrivateStateTokenIssuance      PermissionsPolicyFeature = \"private-state-token-issuance\"\n\tPermissionsPolicyFeaturePrivateStateTokenRedemption    PermissionsPolicyFeature = \"private-state-token-redemption\"\n\tPermissionsPolicyFeaturePublickeyCredentialsCreate     PermissionsPolicyFeature = \"publickey-credentials-create\"\n\tPermissionsPolicyFeaturePublickeyCredentialsGet        PermissionsPolicyFeature = \"publickey-credentials-get\"\n\tPermissionsPolicyFeatureRecordAdAuctionEvents          PermissionsPolicyFeature = \"record-ad-auction-events\"\n\tPermissionsPolicyFeatureRewriter                       PermissionsPolicyFeature = \"rewriter\"\n\tPermissionsPolicyFeatureRunAdAuction                   PermissionsPolicyFeature = \"run-ad-auction\"\n\tPermissionsPolicyFeatureScreenWakeLock                 PermissionsPolicyFeature = \"screen-wake-lock\"\n\tPermissionsPolicyFeatureSerial                         PermissionsPolicyFeature = \"serial\"\n\tPermissionsPolicyFeatureSharedAutofill                 PermissionsPolicyFeature = \"shared-autofill\"\n\tPermissionsPolicyFeatureSharedStorage                  PermissionsPolicyFeature = \"shared-storage\"\n\tPermissionsPolicyFeatureSharedStorageSelectURL         PermissionsPolicyFeature = \"shared-storage-select-url\"\n\tPermissionsPolicyFeatureSmartCard                      PermissionsPolicyFeature = \"smart-card\"\n\tPermissionsPolicyFeatureSpeakerSelection               PermissionsPolicyFeature = \"speaker-selection\"\n\tPermissionsPolicyFeatureStorageAccess                  PermissionsPolicyFeature = \"storage-access\"\n\tPermissionsPolicyFeatureSubApps                        PermissionsPolicyFeature = \"sub-apps\"\n\tPermissionsPolicyFeatureSummarizer                     PermissionsPolicyFeature = \"summarizer\"\n\tPermissionsPolicyFeatureSyncXhr                        PermissionsPolicyFeature = \"sync-xhr\"\n\tPermissionsPolicyFeatureTranslator                     PermissionsPolicyFeature = \"translator\"\n\tPermissionsPolicyFeatureUnload                         PermissionsPolicyFeature = \"unload\"\n\tPermissionsPolicyFeatureUsb                            PermissionsPolicyFeature = \"usb\"\n\tPermissionsPolicyFeatureUsbUnrestricted                PermissionsPolicyFeature = \"usb-unrestricted\"\n\tPermissionsPolicyFeatureVerticalScroll                 PermissionsPolicyFeature = \"vertical-scroll\"\n\tPermissionsPolicyFeatureWebAppInstallation             PermissionsPolicyFeature = \"web-app-installation\"\n\tPermissionsPolicyFeatureWebPrinting                    PermissionsPolicyFeature = \"web-printing\"\n\tPermissionsPolicyFeatureWebShare                       PermissionsPolicyFeature = \"web-share\"\n\tPermissionsPolicyFeatureWindowManagement               PermissionsPolicyFeature = \"window-management\"\n\tPermissionsPolicyFeatureWriter                         PermissionsPolicyFeature = \"writer\"\n\tPermissionsPolicyFeatureXrSpatialTracking              PermissionsPolicyFeature = \"xr-spatial-tracking\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PermissionsPolicyFeature) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PermissionsPolicyFeature(s) {\n\tcase PermissionsPolicyFeatureAccelerometer:\n\t\t*t = PermissionsPolicyFeatureAccelerometer\n\tcase PermissionsPolicyFeatureAllScreensCapture:\n\t\t*t = PermissionsPolicyFeatureAllScreensCapture\n\tcase PermissionsPolicyFeatureAmbientLightSensor:\n\t\t*t = PermissionsPolicyFeatureAmbientLightSensor\n\tcase PermissionsPolicyFeatureAriaNotify:\n\t\t*t = PermissionsPolicyFeatureAriaNotify\n\tcase PermissionsPolicyFeatureAttributionReporting:\n\t\t*t = PermissionsPolicyFeatureAttributionReporting\n\tcase PermissionsPolicyFeatureAutoplay:\n\t\t*t = PermissionsPolicyFeatureAutoplay\n\tcase PermissionsPolicyFeatureBluetooth:\n\t\t*t = PermissionsPolicyFeatureBluetooth\n\tcase PermissionsPolicyFeatureBrowsingTopics:\n\t\t*t = PermissionsPolicyFeatureBrowsingTopics\n\tcase PermissionsPolicyFeatureCamera:\n\t\t*t = PermissionsPolicyFeatureCamera\n\tcase PermissionsPolicyFeatureCapturedSurfaceControl:\n\t\t*t = PermissionsPolicyFeatureCapturedSurfaceControl\n\tcase PermissionsPolicyFeatureChDpr:\n\t\t*t = PermissionsPolicyFeatureChDpr\n\tcase PermissionsPolicyFeatureChDeviceMemory:\n\t\t*t = PermissionsPolicyFeatureChDeviceMemory\n\tcase PermissionsPolicyFeatureChDownlink:\n\t\t*t = PermissionsPolicyFeatureChDownlink\n\tcase PermissionsPolicyFeatureChEct:\n\t\t*t = PermissionsPolicyFeatureChEct\n\tcase PermissionsPolicyFeatureChPrefersColorScheme:\n\t\t*t = PermissionsPolicyFeatureChPrefersColorScheme\n\tcase PermissionsPolicyFeatureChPrefersReducedMotion:\n\t\t*t = PermissionsPolicyFeatureChPrefersReducedMotion\n\tcase PermissionsPolicyFeatureChPrefersReducedTransparency:\n\t\t*t = PermissionsPolicyFeatureChPrefersReducedTransparency\n\tcase PermissionsPolicyFeatureChRtt:\n\t\t*t = PermissionsPolicyFeatureChRtt\n\tcase PermissionsPolicyFeatureChSaveData:\n\t\t*t = PermissionsPolicyFeatureChSaveData\n\tcase PermissionsPolicyFeatureChUa:\n\t\t*t = PermissionsPolicyFeatureChUa\n\tcase PermissionsPolicyFeatureChUaArch:\n\t\t*t = PermissionsPolicyFeatureChUaArch\n\tcase PermissionsPolicyFeatureChUaBitness:\n\t\t*t = PermissionsPolicyFeatureChUaBitness\n\tcase PermissionsPolicyFeatureChUaHighEntropyValues:\n\t\t*t = PermissionsPolicyFeatureChUaHighEntropyValues\n\tcase PermissionsPolicyFeatureChUaPlatform:\n\t\t*t = PermissionsPolicyFeatureChUaPlatform\n\tcase PermissionsPolicyFeatureChUaModel:\n\t\t*t = PermissionsPolicyFeatureChUaModel\n\tcase PermissionsPolicyFeatureChUaMobile:\n\t\t*t = PermissionsPolicyFeatureChUaMobile\n\tcase PermissionsPolicyFeatureChUaFormFactors:\n\t\t*t = PermissionsPolicyFeatureChUaFormFactors\n\tcase PermissionsPolicyFeatureChUaFullVersion:\n\t\t*t = PermissionsPolicyFeatureChUaFullVersion\n\tcase PermissionsPolicyFeatureChUaFullVersionList:\n\t\t*t = PermissionsPolicyFeatureChUaFullVersionList\n\tcase PermissionsPolicyFeatureChUaPlatformVersion:\n\t\t*t = PermissionsPolicyFeatureChUaPlatformVersion\n\tcase PermissionsPolicyFeatureChUaWow64:\n\t\t*t = PermissionsPolicyFeatureChUaWow64\n\tcase PermissionsPolicyFeatureChViewportHeight:\n\t\t*t = PermissionsPolicyFeatureChViewportHeight\n\tcase PermissionsPolicyFeatureChViewportWidth:\n\t\t*t = PermissionsPolicyFeatureChViewportWidth\n\tcase PermissionsPolicyFeatureChWidth:\n\t\t*t = PermissionsPolicyFeatureChWidth\n\tcase PermissionsPolicyFeatureClipboardRead:\n\t\t*t = PermissionsPolicyFeatureClipboardRead\n\tcase PermissionsPolicyFeatureClipboardWrite:\n\t\t*t = PermissionsPolicyFeatureClipboardWrite\n\tcase PermissionsPolicyFeatureComputePressure:\n\t\t*t = PermissionsPolicyFeatureComputePressure\n\tcase PermissionsPolicyFeatureControlledFrame:\n\t\t*t = PermissionsPolicyFeatureControlledFrame\n\tcase PermissionsPolicyFeatureCrossOriginIsolated:\n\t\t*t = PermissionsPolicyFeatureCrossOriginIsolated\n\tcase PermissionsPolicyFeatureDeferredFetch:\n\t\t*t = PermissionsPolicyFeatureDeferredFetch\n\tcase PermissionsPolicyFeatureDeferredFetchMinimal:\n\t\t*t = PermissionsPolicyFeatureDeferredFetchMinimal\n\tcase PermissionsPolicyFeatureDeviceAttributes:\n\t\t*t = PermissionsPolicyFeatureDeviceAttributes\n\tcase PermissionsPolicyFeatureDigitalCredentialsGet:\n\t\t*t = PermissionsPolicyFeatureDigitalCredentialsGet\n\tcase PermissionsPolicyFeatureDirectSockets:\n\t\t*t = PermissionsPolicyFeatureDirectSockets\n\tcase PermissionsPolicyFeatureDirectSocketsPrivate:\n\t\t*t = PermissionsPolicyFeatureDirectSocketsPrivate\n\tcase PermissionsPolicyFeatureDisplayCapture:\n\t\t*t = PermissionsPolicyFeatureDisplayCapture\n\tcase PermissionsPolicyFeatureDocumentDomain:\n\t\t*t = PermissionsPolicyFeatureDocumentDomain\n\tcase PermissionsPolicyFeatureEncryptedMedia:\n\t\t*t = PermissionsPolicyFeatureEncryptedMedia\n\tcase PermissionsPolicyFeatureExecutionWhileOutOfViewport:\n\t\t*t = PermissionsPolicyFeatureExecutionWhileOutOfViewport\n\tcase PermissionsPolicyFeatureExecutionWhileNotRendered:\n\t\t*t = PermissionsPolicyFeatureExecutionWhileNotRendered\n\tcase PermissionsPolicyFeatureFencedUnpartitionedStorageRead:\n\t\t*t = PermissionsPolicyFeatureFencedUnpartitionedStorageRead\n\tcase PermissionsPolicyFeatureFocusWithoutUserActivation:\n\t\t*t = PermissionsPolicyFeatureFocusWithoutUserActivation\n\tcase PermissionsPolicyFeatureFullscreen:\n\t\t*t = PermissionsPolicyFeatureFullscreen\n\tcase PermissionsPolicyFeatureFrobulate:\n\t\t*t = PermissionsPolicyFeatureFrobulate\n\tcase PermissionsPolicyFeatureGamepad:\n\t\t*t = PermissionsPolicyFeatureGamepad\n\tcase PermissionsPolicyFeatureGeolocation:\n\t\t*t = PermissionsPolicyFeatureGeolocation\n\tcase PermissionsPolicyFeatureGyroscope:\n\t\t*t = PermissionsPolicyFeatureGyroscope\n\tcase PermissionsPolicyFeatureHid:\n\t\t*t = PermissionsPolicyFeatureHid\n\tcase PermissionsPolicyFeatureIdentityCredentialsGet:\n\t\t*t = PermissionsPolicyFeatureIdentityCredentialsGet\n\tcase PermissionsPolicyFeatureIdleDetection:\n\t\t*t = PermissionsPolicyFeatureIdleDetection\n\tcase PermissionsPolicyFeatureInterestCohort:\n\t\t*t = PermissionsPolicyFeatureInterestCohort\n\tcase PermissionsPolicyFeatureJoinAdInterestGroup:\n\t\t*t = PermissionsPolicyFeatureJoinAdInterestGroup\n\tcase PermissionsPolicyFeatureKeyboardMap:\n\t\t*t = PermissionsPolicyFeatureKeyboardMap\n\tcase PermissionsPolicyFeatureLanguageDetector:\n\t\t*t = PermissionsPolicyFeatureLanguageDetector\n\tcase PermissionsPolicyFeatureLanguageModel:\n\t\t*t = PermissionsPolicyFeatureLanguageModel\n\tcase PermissionsPolicyFeatureLocalFonts:\n\t\t*t = PermissionsPolicyFeatureLocalFonts\n\tcase PermissionsPolicyFeatureLocalNetworkAccess:\n\t\t*t = PermissionsPolicyFeatureLocalNetworkAccess\n\tcase PermissionsPolicyFeatureMagnetometer:\n\t\t*t = PermissionsPolicyFeatureMagnetometer\n\tcase PermissionsPolicyFeatureMediaPlaybackWhileNotVisible:\n\t\t*t = PermissionsPolicyFeatureMediaPlaybackWhileNotVisible\n\tcase PermissionsPolicyFeatureMicrophone:\n\t\t*t = PermissionsPolicyFeatureMicrophone\n\tcase PermissionsPolicyFeatureMidi:\n\t\t*t = PermissionsPolicyFeatureMidi\n\tcase PermissionsPolicyFeatureOnDeviceSpeechRecognition:\n\t\t*t = PermissionsPolicyFeatureOnDeviceSpeechRecognition\n\tcase PermissionsPolicyFeatureOtpCredentials:\n\t\t*t = PermissionsPolicyFeatureOtpCredentials\n\tcase PermissionsPolicyFeaturePayment:\n\t\t*t = PermissionsPolicyFeaturePayment\n\tcase PermissionsPolicyFeaturePictureInPicture:\n\t\t*t = PermissionsPolicyFeaturePictureInPicture\n\tcase PermissionsPolicyFeaturePopins:\n\t\t*t = PermissionsPolicyFeaturePopins\n\tcase PermissionsPolicyFeaturePrivateAggregation:\n\t\t*t = PermissionsPolicyFeaturePrivateAggregation\n\tcase PermissionsPolicyFeaturePrivateStateTokenIssuance:\n\t\t*t = PermissionsPolicyFeaturePrivateStateTokenIssuance\n\tcase PermissionsPolicyFeaturePrivateStateTokenRedemption:\n\t\t*t = PermissionsPolicyFeaturePrivateStateTokenRedemption\n\tcase PermissionsPolicyFeaturePublickeyCredentialsCreate:\n\t\t*t = PermissionsPolicyFeaturePublickeyCredentialsCreate\n\tcase PermissionsPolicyFeaturePublickeyCredentialsGet:\n\t\t*t = PermissionsPolicyFeaturePublickeyCredentialsGet\n\tcase PermissionsPolicyFeatureRecordAdAuctionEvents:\n\t\t*t = PermissionsPolicyFeatureRecordAdAuctionEvents\n\tcase PermissionsPolicyFeatureRewriter:\n\t\t*t = PermissionsPolicyFeatureRewriter\n\tcase PermissionsPolicyFeatureRunAdAuction:\n\t\t*t = PermissionsPolicyFeatureRunAdAuction\n\tcase PermissionsPolicyFeatureScreenWakeLock:\n\t\t*t = PermissionsPolicyFeatureScreenWakeLock\n\tcase PermissionsPolicyFeatureSerial:\n\t\t*t = PermissionsPolicyFeatureSerial\n\tcase PermissionsPolicyFeatureSharedAutofill:\n\t\t*t = PermissionsPolicyFeatureSharedAutofill\n\tcase PermissionsPolicyFeatureSharedStorage:\n\t\t*t = PermissionsPolicyFeatureSharedStorage\n\tcase PermissionsPolicyFeatureSharedStorageSelectURL:\n\t\t*t = PermissionsPolicyFeatureSharedStorageSelectURL\n\tcase PermissionsPolicyFeatureSmartCard:\n\t\t*t = PermissionsPolicyFeatureSmartCard\n\tcase PermissionsPolicyFeatureSpeakerSelection:\n\t\t*t = PermissionsPolicyFeatureSpeakerSelection\n\tcase PermissionsPolicyFeatureStorageAccess:\n\t\t*t = PermissionsPolicyFeatureStorageAccess\n\tcase PermissionsPolicyFeatureSubApps:\n\t\t*t = PermissionsPolicyFeatureSubApps\n\tcase PermissionsPolicyFeatureSummarizer:\n\t\t*t = PermissionsPolicyFeatureSummarizer\n\tcase PermissionsPolicyFeatureSyncXhr:\n\t\t*t = PermissionsPolicyFeatureSyncXhr\n\tcase PermissionsPolicyFeatureTranslator:\n\t\t*t = PermissionsPolicyFeatureTranslator\n\tcase PermissionsPolicyFeatureUnload:\n\t\t*t = PermissionsPolicyFeatureUnload\n\tcase PermissionsPolicyFeatureUsb:\n\t\t*t = PermissionsPolicyFeatureUsb\n\tcase PermissionsPolicyFeatureUsbUnrestricted:\n\t\t*t = PermissionsPolicyFeatureUsbUnrestricted\n\tcase PermissionsPolicyFeatureVerticalScroll:\n\t\t*t = PermissionsPolicyFeatureVerticalScroll\n\tcase PermissionsPolicyFeatureWebAppInstallation:\n\t\t*t = PermissionsPolicyFeatureWebAppInstallation\n\tcase PermissionsPolicyFeatureWebPrinting:\n\t\t*t = PermissionsPolicyFeatureWebPrinting\n\tcase PermissionsPolicyFeatureWebShare:\n\t\t*t = PermissionsPolicyFeatureWebShare\n\tcase PermissionsPolicyFeatureWindowManagement:\n\t\t*t = PermissionsPolicyFeatureWindowManagement\n\tcase PermissionsPolicyFeatureWriter:\n\t\t*t = PermissionsPolicyFeatureWriter\n\tcase PermissionsPolicyFeatureXrSpatialTracking:\n\t\t*t = PermissionsPolicyFeatureXrSpatialTracking\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PermissionsPolicyFeature value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PermissionsPolicyBlockReason reason for a permissions policy feature to be\n// disabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-PermissionsPolicyBlockReason\ntype PermissionsPolicyBlockReason string\n\n// String returns the PermissionsPolicyBlockReason as string value.\nfunc (t PermissionsPolicyBlockReason) String() string {\n\treturn string(t)\n}\n\n// PermissionsPolicyBlockReason values.\nconst (\n\tPermissionsPolicyBlockReasonHeader            PermissionsPolicyBlockReason = \"Header\"\n\tPermissionsPolicyBlockReasonIframeAttribute   PermissionsPolicyBlockReason = \"IframeAttribute\"\n\tPermissionsPolicyBlockReasonInFencedFrameTree PermissionsPolicyBlockReason = \"InFencedFrameTree\"\n\tPermissionsPolicyBlockReasonInIsolatedApp     PermissionsPolicyBlockReason = \"InIsolatedApp\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PermissionsPolicyBlockReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PermissionsPolicyBlockReason(s) {\n\tcase PermissionsPolicyBlockReasonHeader:\n\t\t*t = PermissionsPolicyBlockReasonHeader\n\tcase PermissionsPolicyBlockReasonIframeAttribute:\n\t\t*t = PermissionsPolicyBlockReasonIframeAttribute\n\tcase PermissionsPolicyBlockReasonInFencedFrameTree:\n\t\t*t = PermissionsPolicyBlockReasonInFencedFrameTree\n\tcase PermissionsPolicyBlockReasonInIsolatedApp:\n\t\t*t = PermissionsPolicyBlockReasonInIsolatedApp\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PermissionsPolicyBlockReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PermissionsPolicyBlockLocator [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-PermissionsPolicyBlockLocator\ntype PermissionsPolicyBlockLocator struct {\n\tFrameID     cdp.FrameID                  `json:\"frameId\"`\n\tBlockReason PermissionsPolicyBlockReason `json:\"blockReason\"`\n}\n\n// PermissionsPolicyFeatureState [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-PermissionsPolicyFeatureState\ntype PermissionsPolicyFeatureState struct {\n\tFeature PermissionsPolicyFeature       `json:\"feature\"`\n\tAllowed bool                           `json:\"allowed\"`\n\tLocator *PermissionsPolicyBlockLocator `json:\"locator,omitempty,omitzero\"`\n}\n\n// FrameResource information about the Resource on the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FrameResource\ntype FrameResource struct {\n\tURL          string               `json:\"url\"`                             // Resource URL.\n\tType         network.ResourceType `json:\"type\"`                            // Type of this resource.\n\tMimeType     string               `json:\"mimeType\"`                        // Resource mimeType as determined by the browser.\n\tLastModified *cdp.TimeSinceEpoch  `json:\"lastModified,omitempty,omitzero\"` // last-modified timestamp as reported by server.\n\tContentSize  float64              `json:\"contentSize,omitempty,omitzero\"`  // Resource content size.\n\tFailed       bool                 `json:\"failed\"`                          // True if the resource failed to load.\n\tCanceled     bool                 `json:\"canceled\"`                        // True if the resource was canceled during loading.\n}\n\n// FrameResourceTree information about the Frame hierarchy along with their\n// cached resources.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FrameResourceTree\ntype FrameResourceTree struct {\n\tFrame       *cdp.Frame           `json:\"frame\"`                          // Frame information for this tree item.\n\tChildFrames []*FrameResourceTree `json:\"childFrames,omitempty,omitzero\"` // Child frames.\n\tResources   []*FrameResource     `json:\"resources\"`                      // Information about frame resources.\n}\n\n// FrameTree information about the Frame hierarchy.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FrameTree\ntype FrameTree struct {\n\tFrame       *cdp.Frame   `json:\"frame\"`                          // Frame information for this tree item.\n\tChildFrames []*FrameTree `json:\"childFrames,omitempty,omitzero\"` // Child frames.\n}\n\n// ScriptIdentifier unique script identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ScriptIdentifier\ntype ScriptIdentifier string\n\n// String returns the ScriptIdentifier as string value.\nfunc (t ScriptIdentifier) String() string {\n\treturn string(t)\n}\n\n// TransitionType transition type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-TransitionType\ntype TransitionType string\n\n// String returns the TransitionType as string value.\nfunc (t TransitionType) String() string {\n\treturn string(t)\n}\n\n// TransitionType values.\nconst (\n\tTransitionTypeLink             TransitionType = \"link\"\n\tTransitionTypeTyped            TransitionType = \"typed\"\n\tTransitionTypeAddressBar       TransitionType = \"address_bar\"\n\tTransitionTypeAutoBookmark     TransitionType = \"auto_bookmark\"\n\tTransitionTypeAutoSubframe     TransitionType = \"auto_subframe\"\n\tTransitionTypeManualSubframe   TransitionType = \"manual_subframe\"\n\tTransitionTypeGenerated        TransitionType = \"generated\"\n\tTransitionTypeAutoToplevel     TransitionType = \"auto_toplevel\"\n\tTransitionTypeFormSubmit       TransitionType = \"form_submit\"\n\tTransitionTypeReload           TransitionType = \"reload\"\n\tTransitionTypeKeyword          TransitionType = \"keyword\"\n\tTransitionTypeKeywordGenerated TransitionType = \"keyword_generated\"\n\tTransitionTypeOther            TransitionType = \"other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TransitionType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch TransitionType(s) {\n\tcase TransitionTypeLink:\n\t\t*t = TransitionTypeLink\n\tcase TransitionTypeTyped:\n\t\t*t = TransitionTypeTyped\n\tcase TransitionTypeAddressBar:\n\t\t*t = TransitionTypeAddressBar\n\tcase TransitionTypeAutoBookmark:\n\t\t*t = TransitionTypeAutoBookmark\n\tcase TransitionTypeAutoSubframe:\n\t\t*t = TransitionTypeAutoSubframe\n\tcase TransitionTypeManualSubframe:\n\t\t*t = TransitionTypeManualSubframe\n\tcase TransitionTypeGenerated:\n\t\t*t = TransitionTypeGenerated\n\tcase TransitionTypeAutoToplevel:\n\t\t*t = TransitionTypeAutoToplevel\n\tcase TransitionTypeFormSubmit:\n\t\t*t = TransitionTypeFormSubmit\n\tcase TransitionTypeReload:\n\t\t*t = TransitionTypeReload\n\tcase TransitionTypeKeyword:\n\t\t*t = TransitionTypeKeyword\n\tcase TransitionTypeKeywordGenerated:\n\t\t*t = TransitionTypeKeywordGenerated\n\tcase TransitionTypeOther:\n\t\t*t = TransitionTypeOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown TransitionType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// NavigationEntry navigation history entry.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-NavigationEntry\ntype NavigationEntry struct {\n\tID             int64          `json:\"id\"`             // Unique id of the navigation history entry.\n\tURL            string         `json:\"url\"`            // URL of the navigation history entry.\n\tUserTypedURL   string         `json:\"userTypedURL\"`   // URL that the user typed in the url bar.\n\tTitle          string         `json:\"title\"`          // Title of the navigation history entry.\n\tTransitionType TransitionType `json:\"transitionType\"` // Transition type.\n}\n\n// ScreencastFrameMetadata screencast frame metadata.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ScreencastFrameMetadata\ntype ScreencastFrameMetadata struct {\n\tOffsetTop       float64             `json:\"offsetTop\"`                    // Top offset in DIP.\n\tPageScaleFactor float64             `json:\"pageScaleFactor\"`              // Page scale factor.\n\tDeviceWidth     float64             `json:\"deviceWidth\"`                  // Device screen width in DIP.\n\tDeviceHeight    float64             `json:\"deviceHeight\"`                 // Device screen height in DIP.\n\tScrollOffsetX   float64             `json:\"scrollOffsetX\"`                // Position of horizontal scroll in CSS pixels.\n\tScrollOffsetY   float64             `json:\"scrollOffsetY\"`                // Position of vertical scroll in CSS pixels.\n\tTimestamp       *cdp.TimeSinceEpoch `json:\"timestamp,omitempty,omitzero\"` // Frame swap timestamp.\n}\n\n// DialogType javascript dialog type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-DialogType\ntype DialogType string\n\n// String returns the DialogType as string value.\nfunc (t DialogType) String() string {\n\treturn string(t)\n}\n\n// DialogType values.\nconst (\n\tDialogTypeAlert        DialogType = \"alert\"\n\tDialogTypeConfirm      DialogType = \"confirm\"\n\tDialogTypePrompt       DialogType = \"prompt\"\n\tDialogTypeBeforeunload DialogType = \"beforeunload\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DialogType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DialogType(s) {\n\tcase DialogTypeAlert:\n\t\t*t = DialogTypeAlert\n\tcase DialogTypeConfirm:\n\t\t*t = DialogTypeConfirm\n\tcase DialogTypePrompt:\n\t\t*t = DialogTypePrompt\n\tcase DialogTypeBeforeunload:\n\t\t*t = DialogTypeBeforeunload\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DialogType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AppManifestError error while paring app manifest.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-AppManifestError\ntype AppManifestError struct {\n\tMessage  string `json:\"message\"`  // Error message.\n\tCritical int64  `json:\"critical\"` // If critical, this is a non-recoverable parse error.\n\tLine     int64  `json:\"line\"`     // Error line.\n\tColumn   int64  `json:\"column\"`   // Error column.\n}\n\n// AppManifestParsedProperties parsed app manifest properties.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-AppManifestParsedProperties\ntype AppManifestParsedProperties struct {\n\tScope string `json:\"scope\"` // Computed scope value\n}\n\n// LayoutViewport layout viewport position and dimensions.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-LayoutViewport\ntype LayoutViewport struct {\n\tPageX        int64 `json:\"pageX\"`        // Horizontal offset relative to the document (CSS pixels).\n\tPageY        int64 `json:\"pageY\"`        // Vertical offset relative to the document (CSS pixels).\n\tClientWidth  int64 `json:\"clientWidth\"`  // Width (CSS pixels), excludes scrollbar if present.\n\tClientHeight int64 `json:\"clientHeight\"` // Height (CSS pixels), excludes scrollbar if present.\n}\n\n// VisualViewport visual viewport position, dimensions, and scale.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-VisualViewport\ntype VisualViewport struct {\n\tOffsetX      float64 `json:\"offsetX\"`                 // Horizontal offset relative to the layout viewport (CSS pixels).\n\tOffsetY      float64 `json:\"offsetY\"`                 // Vertical offset relative to the layout viewport (CSS pixels).\n\tPageX        float64 `json:\"pageX\"`                   // Horizontal offset relative to the document (CSS pixels).\n\tPageY        float64 `json:\"pageY\"`                   // Vertical offset relative to the document (CSS pixels).\n\tClientWidth  float64 `json:\"clientWidth\"`             // Width (CSS pixels), excludes scrollbar if present.\n\tClientHeight float64 `json:\"clientHeight\"`            // Height (CSS pixels), excludes scrollbar if present.\n\tScale        float64 `json:\"scale\"`                   // Scale relative to the ideal viewport (size at width=device-width).\n\tZoom         float64 `json:\"zoom,omitempty,omitzero\"` // Page zoom factor (CSS to device independent pixels ratio).\n}\n\n// Viewport viewport for capturing screenshot.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-Viewport\ntype Viewport struct {\n\tX      float64 `json:\"x\"`      // X offset in device independent pixels (dip).\n\tY      float64 `json:\"y\"`      // Y offset in device independent pixels (dip).\n\tWidth  float64 `json:\"width\"`  // Rectangle width in device independent pixels (dip).\n\tHeight float64 `json:\"height\"` // Rectangle height in device independent pixels (dip).\n\tScale  float64 `json:\"scale\"`  // Page scale factor.\n}\n\n// FontFamilies generic font families collection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FontFamilies\ntype FontFamilies struct {\n\tStandard  string `json:\"standard,omitempty,omitzero\"`  // The standard font-family.\n\tFixed     string `json:\"fixed,omitempty,omitzero\"`     // The fixed font-family.\n\tSerif     string `json:\"serif,omitempty,omitzero\"`     // The serif font-family.\n\tSansSerif string `json:\"sansSerif,omitempty,omitzero\"` // The sansSerif font-family.\n\tCursive   string `json:\"cursive,omitempty,omitzero\"`   // The cursive font-family.\n\tFantasy   string `json:\"fantasy,omitempty,omitzero\"`   // The fantasy font-family.\n\tMath      string `json:\"math,omitempty,omitzero\"`      // The math font-family.\n}\n\n// ScriptFontFamilies font families collection for a script.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ScriptFontFamilies\ntype ScriptFontFamilies struct {\n\tScript       string        `json:\"script\"`       // Name of the script which these font families are defined for.\n\tFontFamilies *FontFamilies `json:\"fontFamilies\"` // Generic font families collection for the script.\n}\n\n// FontSizes default font sizes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FontSizes\ntype FontSizes struct {\n\tStandard int64 `json:\"standard,omitempty,omitzero\"` // Default standard font size.\n\tFixed    int64 `json:\"fixed,omitempty,omitzero\"`    // Default fixed font size.\n}\n\n// ClientNavigationReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ClientNavigationReason\ntype ClientNavigationReason string\n\n// String returns the ClientNavigationReason as string value.\nfunc (t ClientNavigationReason) String() string {\n\treturn string(t)\n}\n\n// ClientNavigationReason values.\nconst (\n\tClientNavigationReasonAnchorClick            ClientNavigationReason = \"anchorClick\"\n\tClientNavigationReasonFormSubmissionGet      ClientNavigationReason = \"formSubmissionGet\"\n\tClientNavigationReasonFormSubmissionPost     ClientNavigationReason = \"formSubmissionPost\"\n\tClientNavigationReasonHTTPHeaderRefresh      ClientNavigationReason = \"httpHeaderRefresh\"\n\tClientNavigationReasonInitialFrameNavigation ClientNavigationReason = \"initialFrameNavigation\"\n\tClientNavigationReasonMetaTagRefresh         ClientNavigationReason = \"metaTagRefresh\"\n\tClientNavigationReasonOther                  ClientNavigationReason = \"other\"\n\tClientNavigationReasonPageBlockInterstitial  ClientNavigationReason = \"pageBlockInterstitial\"\n\tClientNavigationReasonReload                 ClientNavigationReason = \"reload\"\n\tClientNavigationReasonScriptInitiated        ClientNavigationReason = \"scriptInitiated\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ClientNavigationReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ClientNavigationReason(s) {\n\tcase ClientNavigationReasonAnchorClick:\n\t\t*t = ClientNavigationReasonAnchorClick\n\tcase ClientNavigationReasonFormSubmissionGet:\n\t\t*t = ClientNavigationReasonFormSubmissionGet\n\tcase ClientNavigationReasonFormSubmissionPost:\n\t\t*t = ClientNavigationReasonFormSubmissionPost\n\tcase ClientNavigationReasonHTTPHeaderRefresh:\n\t\t*t = ClientNavigationReasonHTTPHeaderRefresh\n\tcase ClientNavigationReasonInitialFrameNavigation:\n\t\t*t = ClientNavigationReasonInitialFrameNavigation\n\tcase ClientNavigationReasonMetaTagRefresh:\n\t\t*t = ClientNavigationReasonMetaTagRefresh\n\tcase ClientNavigationReasonOther:\n\t\t*t = ClientNavigationReasonOther\n\tcase ClientNavigationReasonPageBlockInterstitial:\n\t\t*t = ClientNavigationReasonPageBlockInterstitial\n\tcase ClientNavigationReasonReload:\n\t\t*t = ClientNavigationReasonReload\n\tcase ClientNavigationReasonScriptInitiated:\n\t\t*t = ClientNavigationReasonScriptInitiated\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ClientNavigationReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ClientNavigationDisposition [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ClientNavigationDisposition\ntype ClientNavigationDisposition string\n\n// String returns the ClientNavigationDisposition as string value.\nfunc (t ClientNavigationDisposition) String() string {\n\treturn string(t)\n}\n\n// ClientNavigationDisposition values.\nconst (\n\tClientNavigationDispositionCurrentTab ClientNavigationDisposition = \"currentTab\"\n\tClientNavigationDispositionNewTab     ClientNavigationDisposition = \"newTab\"\n\tClientNavigationDispositionNewWindow  ClientNavigationDisposition = \"newWindow\"\n\tClientNavigationDispositionDownload   ClientNavigationDisposition = \"download\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ClientNavigationDisposition) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ClientNavigationDisposition(s) {\n\tcase ClientNavigationDispositionCurrentTab:\n\t\t*t = ClientNavigationDispositionCurrentTab\n\tcase ClientNavigationDispositionNewTab:\n\t\t*t = ClientNavigationDispositionNewTab\n\tcase ClientNavigationDispositionNewWindow:\n\t\t*t = ClientNavigationDispositionNewWindow\n\tcase ClientNavigationDispositionDownload:\n\t\t*t = ClientNavigationDispositionDownload\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ClientNavigationDisposition value: %v\", s)\n\t}\n\treturn nil\n}\n\n// InstallabilityErrorArgument [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-InstallabilityErrorArgument\ntype InstallabilityErrorArgument struct {\n\tName  string `json:\"name\"`  // Argument name (e.g. name:'minimum-icon-size-in-pixels').\n\tValue string `json:\"value\"` // Argument value (e.g. value:'64').\n}\n\n// InstallabilityError the installability error.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-InstallabilityError\ntype InstallabilityError struct {\n\tErrorID        string                         `json:\"errorId\"`        // The error id (e.g. 'manifest-missing-suitable-icon').\n\tErrorArguments []*InstallabilityErrorArgument `json:\"errorArguments\"` // The list of error arguments (e.g. {name:'minimum-icon-size-in-pixels', value:'64'}).\n}\n\n// ReferrerPolicy the referring-policy used for the navigation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ReferrerPolicy\ntype ReferrerPolicy string\n\n// String returns the ReferrerPolicy as string value.\nfunc (t ReferrerPolicy) String() string {\n\treturn string(t)\n}\n\n// ReferrerPolicy values.\nconst (\n\tReferrerPolicyNoReferrer                  ReferrerPolicy = \"noReferrer\"\n\tReferrerPolicyNoReferrerWhenDowngrade     ReferrerPolicy = \"noReferrerWhenDowngrade\"\n\tReferrerPolicyOrigin                      ReferrerPolicy = \"origin\"\n\tReferrerPolicyOriginWhenCrossOrigin       ReferrerPolicy = \"originWhenCrossOrigin\"\n\tReferrerPolicySameOrigin                  ReferrerPolicy = \"sameOrigin\"\n\tReferrerPolicyStrictOrigin                ReferrerPolicy = \"strictOrigin\"\n\tReferrerPolicyStrictOriginWhenCrossOrigin ReferrerPolicy = \"strictOriginWhenCrossOrigin\"\n\tReferrerPolicyUnsafeURL                   ReferrerPolicy = \"unsafeUrl\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ReferrerPolicy) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ReferrerPolicy(s) {\n\tcase ReferrerPolicyNoReferrer:\n\t\t*t = ReferrerPolicyNoReferrer\n\tcase ReferrerPolicyNoReferrerWhenDowngrade:\n\t\t*t = ReferrerPolicyNoReferrerWhenDowngrade\n\tcase ReferrerPolicyOrigin:\n\t\t*t = ReferrerPolicyOrigin\n\tcase ReferrerPolicyOriginWhenCrossOrigin:\n\t\t*t = ReferrerPolicyOriginWhenCrossOrigin\n\tcase ReferrerPolicySameOrigin:\n\t\t*t = ReferrerPolicySameOrigin\n\tcase ReferrerPolicyStrictOrigin:\n\t\t*t = ReferrerPolicyStrictOrigin\n\tcase ReferrerPolicyStrictOriginWhenCrossOrigin:\n\t\t*t = ReferrerPolicyStrictOriginWhenCrossOrigin\n\tcase ReferrerPolicyUnsafeURL:\n\t\t*t = ReferrerPolicyUnsafeURL\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ReferrerPolicy value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CompilationCacheParams per-script compilation cache parameters for\n// Page.produceCompilationCache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-CompilationCacheParams\ntype CompilationCacheParams struct {\n\tURL   string `json:\"url\"`   // The URL of the script to produce a compilation cache entry for.\n\tEager bool   `json:\"eager\"` // A hint to the backend whether eager compilation is recommended. (the actual compilation mode used is upon backend discretion).\n}\n\n// FileFilter [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FileFilter\ntype FileFilter struct {\n\tName    string   `json:\"name,omitempty,omitzero\"`\n\tAccepts []string `json:\"accepts,omitempty,omitzero\"`\n}\n\n// FileHandler [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-FileHandler\ntype FileHandler struct {\n\tAction     string           `json:\"action\"`\n\tName       string           `json:\"name\"`\n\tIcons      []*ImageResource `json:\"icons,omitempty,omitzero\"`\n\tAccepts    []*FileFilter    `json:\"accepts,omitempty,omitzero\"` // Mimic a map, name is the key, accepts is the value.\n\tLaunchType string           `json:\"launchType\"`                 // Won't repeat the enums, using string for easy comparison. Same as the other enums below.\n}\n\n// ImageResource the image definition used in both icon and screenshot.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ImageResource\ntype ImageResource struct {\n\tURL   string `json:\"url\"` // The src field in the definition, but changing to url in favor of consistency.\n\tSizes string `json:\"sizes,omitempty,omitzero\"`\n\tType  string `json:\"type,omitempty,omitzero\"`\n}\n\n// LaunchHandler [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-LaunchHandler\ntype LaunchHandler struct {\n\tClientMode string `json:\"clientMode\"`\n}\n\n// ProtocolHandler [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ProtocolHandler\ntype ProtocolHandler struct {\n\tProtocol string `json:\"protocol\"`\n\tURL      string `json:\"url\"`\n}\n\n// RelatedApplication [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-RelatedApplication\ntype RelatedApplication struct {\n\tID  string `json:\"id,omitempty,omitzero\"`\n\tURL string `json:\"url\"`\n}\n\n// ScopeExtension [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ScopeExtension\ntype ScopeExtension struct {\n\tOrigin            string `json:\"origin\"` // Instead of using tuple, this field always returns the serialized string for easy understanding and comparison.\n\tHasOriginWildcard bool   `json:\"hasOriginWildcard\"`\n}\n\n// Screenshot [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-Screenshot\ntype Screenshot struct {\n\tImage      *ImageResource `json:\"image\"`\n\tFormFactor string         `json:\"formFactor\"`\n\tLabel      string         `json:\"label,omitempty,omitzero\"`\n}\n\n// ShareTarget [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-ShareTarget\ntype ShareTarget struct {\n\tAction  string        `json:\"action\"`\n\tMethod  string        `json:\"method\"`\n\tEnctype string        `json:\"enctype\"`\n\tTitle   string        `json:\"title,omitempty,omitzero\"` // Embed the ShareTargetParams\n\tText    string        `json:\"text,omitempty,omitzero\"`\n\tURL     string        `json:\"url,omitempty,omitzero\"`\n\tFiles   []*FileFilter `json:\"files,omitempty,omitzero\"`\n}\n\n// Shortcut [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-Shortcut\ntype Shortcut struct {\n\tName string `json:\"name\"`\n\tURL  string `json:\"url\"`\n}\n\n// WebAppManifest [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-WebAppManifest\ntype WebAppManifest struct {\n\tBackgroundColor           string                `json:\"backgroundColor,omitempty,omitzero\"`\n\tDescription               string                `json:\"description,omitempty,omitzero\"` // The extra description provided by the manifest.\n\tDir                       string                `json:\"dir,omitempty,omitzero\"`\n\tDisplay                   string                `json:\"display,omitempty,omitzero\"`\n\tDisplayOverrides          []string              `json:\"displayOverrides,omitempty,omitzero\"` // The overrided display mode controlled by the user.\n\tFileHandlers              []*FileHandler        `json:\"fileHandlers,omitempty,omitzero\"`     // The handlers to open files.\n\tIcons                     []*ImageResource      `json:\"icons,omitempty,omitzero\"`\n\tID                        string                `json:\"id,omitempty,omitzero\"`\n\tLang                      string                `json:\"lang,omitempty,omitzero\"`\n\tLaunchHandler             *LaunchHandler        `json:\"launchHandler,omitempty,omitzero\"` // TODO(crbug.com/1231886): This field is non-standard and part of a Chrome experiment. See: https://github.com/WICG/web-app-launch/blob/main/launch_handler.md\n\tName                      string                `json:\"name,omitempty,omitzero\"`\n\tOrientation               string                `json:\"orientation,omitempty,omitzero\"`\n\tPreferRelatedApplications bool                  `json:\"preferRelatedApplications\"`\n\tProtocolHandlers          []*ProtocolHandler    `json:\"protocolHandlers,omitempty,omitzero\"` // The handlers to open protocols.\n\tRelatedApplications       []*RelatedApplication `json:\"relatedApplications,omitempty,omitzero\"`\n\tScope                     string                `json:\"scope,omitempty,omitzero\"`\n\tScopeExtensions           []*ScopeExtension     `json:\"scopeExtensions,omitempty,omitzero\"` // Non-standard, see https://github.com/WICG/manifest-incubations/blob/gh-pages/scope_extensions-explainer.md\n\tScreenshots               []*Screenshot         `json:\"screenshots,omitempty,omitzero\"`     // The screenshots used by chromium.\n\tShareTarget               *ShareTarget          `json:\"shareTarget,omitempty,omitzero\"`\n\tShortName                 string                `json:\"shortName,omitempty,omitzero\"`\n\tShortcuts                 []*Shortcut           `json:\"shortcuts,omitempty,omitzero\"`\n\tStartURL                  string                `json:\"startUrl,omitempty,omitzero\"`\n\tThemeColor                string                `json:\"themeColor,omitempty,omitzero\"`\n}\n\n// NavigationType the type of a frameNavigated event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-NavigationType\ntype NavigationType string\n\n// String returns the NavigationType as string value.\nfunc (t NavigationType) String() string {\n\treturn string(t)\n}\n\n// NavigationType values.\nconst (\n\tNavigationTypeNavigation              NavigationType = \"Navigation\"\n\tNavigationTypeBackForwardCacheRestore NavigationType = \"BackForwardCacheRestore\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *NavigationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch NavigationType(s) {\n\tcase NavigationTypeNavigation:\n\t\t*t = NavigationTypeNavigation\n\tcase NavigationTypeBackForwardCacheRestore:\n\t\t*t = NavigationTypeBackForwardCacheRestore\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown NavigationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// BackForwardCacheNotRestoredReason list of not restored reasons for\n// back-forward cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-BackForwardCacheNotRestoredReason\ntype BackForwardCacheNotRestoredReason string\n\n// String returns the BackForwardCacheNotRestoredReason as string value.\nfunc (t BackForwardCacheNotRestoredReason) String() string {\n\treturn string(t)\n}\n\n// BackForwardCacheNotRestoredReason values.\nconst (\n\tBackForwardCacheNotRestoredReasonNotPrimaryMainFrame                                      BackForwardCacheNotRestoredReason = \"NotPrimaryMainFrame\"\n\tBackForwardCacheNotRestoredReasonBackForwardCacheDisabled                                 BackForwardCacheNotRestoredReason = \"BackForwardCacheDisabled\"\n\tBackForwardCacheNotRestoredReasonRelatedActiveContentsExist                               BackForwardCacheNotRestoredReason = \"RelatedActiveContentsExist\"\n\tBackForwardCacheNotRestoredReasonHTTPSTatusNotOK                                          BackForwardCacheNotRestoredReason = \"HTTPStatusNotOK\"\n\tBackForwardCacheNotRestoredReasonSchemeNotHTTPOrHTTPS                                     BackForwardCacheNotRestoredReason = \"SchemeNotHTTPOrHTTPS\"\n\tBackForwardCacheNotRestoredReasonLoading                                                  BackForwardCacheNotRestoredReason = \"Loading\"\n\tBackForwardCacheNotRestoredReasonWasGrantedMediaAccess                                    BackForwardCacheNotRestoredReason = \"WasGrantedMediaAccess\"\n\tBackForwardCacheNotRestoredReasonDisableForRenderFrameHostCalled                          BackForwardCacheNotRestoredReason = \"DisableForRenderFrameHostCalled\"\n\tBackForwardCacheNotRestoredReasonDomainNotAllowed                                         BackForwardCacheNotRestoredReason = \"DomainNotAllowed\"\n\tBackForwardCacheNotRestoredReasonHTTPMethodNotGET                                         BackForwardCacheNotRestoredReason = \"HTTPMethodNotGET\"\n\tBackForwardCacheNotRestoredReasonSubframeIsNavigating                                     BackForwardCacheNotRestoredReason = \"SubframeIsNavigating\"\n\tBackForwardCacheNotRestoredReasonTimeout                                                  BackForwardCacheNotRestoredReason = \"Timeout\"\n\tBackForwardCacheNotRestoredReasonCacheLimit                                               BackForwardCacheNotRestoredReason = \"CacheLimit\"\n\tBackForwardCacheNotRestoredReasonJavaScriptExecution                                      BackForwardCacheNotRestoredReason = \"JavaScriptExecution\"\n\tBackForwardCacheNotRestoredReasonRendererProcessKilled                                    BackForwardCacheNotRestoredReason = \"RendererProcessKilled\"\n\tBackForwardCacheNotRestoredReasonRendererProcessCrashed                                   BackForwardCacheNotRestoredReason = \"RendererProcessCrashed\"\n\tBackForwardCacheNotRestoredReasonSchedulerTrackedFeatureUsed                              BackForwardCacheNotRestoredReason = \"SchedulerTrackedFeatureUsed\"\n\tBackForwardCacheNotRestoredReasonConflictingBrowsingInstance                              BackForwardCacheNotRestoredReason = \"ConflictingBrowsingInstance\"\n\tBackForwardCacheNotRestoredReasonCacheFlushed                                             BackForwardCacheNotRestoredReason = \"CacheFlushed\"\n\tBackForwardCacheNotRestoredReasonServiceWorkerVersionActivation                           BackForwardCacheNotRestoredReason = \"ServiceWorkerVersionActivation\"\n\tBackForwardCacheNotRestoredReasonSessionRestored                                          BackForwardCacheNotRestoredReason = \"SessionRestored\"\n\tBackForwardCacheNotRestoredReasonServiceWorkerPostMessage                                 BackForwardCacheNotRestoredReason = \"ServiceWorkerPostMessage\"\n\tBackForwardCacheNotRestoredReasonEnteredBackForwardCacheBeforeServiceWorkerHostAdded      BackForwardCacheNotRestoredReason = \"EnteredBackForwardCacheBeforeServiceWorkerHostAdded\"\n\tBackForwardCacheNotRestoredReasonRenderFrameHostReusedSameSite                            BackForwardCacheNotRestoredReason = \"RenderFrameHostReused_SameSite\"\n\tBackForwardCacheNotRestoredReasonRenderFrameHostReusedCrossSite                           BackForwardCacheNotRestoredReason = \"RenderFrameHostReused_CrossSite\"\n\tBackForwardCacheNotRestoredReasonServiceWorkerClaim                                       BackForwardCacheNotRestoredReason = \"ServiceWorkerClaim\"\n\tBackForwardCacheNotRestoredReasonIgnoreEventAndEvict                                      BackForwardCacheNotRestoredReason = \"IgnoreEventAndEvict\"\n\tBackForwardCacheNotRestoredReasonHaveInnerContents                                        BackForwardCacheNotRestoredReason = \"HaveInnerContents\"\n\tBackForwardCacheNotRestoredReasonTimeoutPuttingInCache                                    BackForwardCacheNotRestoredReason = \"TimeoutPuttingInCache\"\n\tBackForwardCacheNotRestoredReasonBackForwardCacheDisabledByLowMemory                      BackForwardCacheNotRestoredReason = \"BackForwardCacheDisabledByLowMemory\"\n\tBackForwardCacheNotRestoredReasonBackForwardCacheDisabledByCommandLine                    BackForwardCacheNotRestoredReason = \"BackForwardCacheDisabledByCommandLine\"\n\tBackForwardCacheNotRestoredReasonNetworkRequestDatapipeDrainedAsBytesConsumer             BackForwardCacheNotRestoredReason = \"NetworkRequestDatapipeDrainedAsBytesConsumer\"\n\tBackForwardCacheNotRestoredReasonNetworkRequestRedirected                                 BackForwardCacheNotRestoredReason = \"NetworkRequestRedirected\"\n\tBackForwardCacheNotRestoredReasonNetworkRequestTimeout                                    BackForwardCacheNotRestoredReason = \"NetworkRequestTimeout\"\n\tBackForwardCacheNotRestoredReasonNetworkExceedsBufferLimit                                BackForwardCacheNotRestoredReason = \"NetworkExceedsBufferLimit\"\n\tBackForwardCacheNotRestoredReasonNavigationCancelledWhileRestoring                        BackForwardCacheNotRestoredReason = \"NavigationCancelledWhileRestoring\"\n\tBackForwardCacheNotRestoredReasonNotMostRecentNavigationEntry                             BackForwardCacheNotRestoredReason = \"NotMostRecentNavigationEntry\"\n\tBackForwardCacheNotRestoredReasonBackForwardCacheDisabledForPrerender                     BackForwardCacheNotRestoredReason = \"BackForwardCacheDisabledForPrerender\"\n\tBackForwardCacheNotRestoredReasonUserAgentOverrideDiffers                                 BackForwardCacheNotRestoredReason = \"UserAgentOverrideDiffers\"\n\tBackForwardCacheNotRestoredReasonForegroundCacheLimit                                     BackForwardCacheNotRestoredReason = \"ForegroundCacheLimit\"\n\tBackForwardCacheNotRestoredReasonBrowsingInstanceNotSwapped                               BackForwardCacheNotRestoredReason = \"BrowsingInstanceNotSwapped\"\n\tBackForwardCacheNotRestoredReasonBackForwardCacheDisabledForDelegate                      BackForwardCacheNotRestoredReason = \"BackForwardCacheDisabledForDelegate\"\n\tBackForwardCacheNotRestoredReasonUnloadHandlerExistsInMainFrame                           BackForwardCacheNotRestoredReason = \"UnloadHandlerExistsInMainFrame\"\n\tBackForwardCacheNotRestoredReasonUnloadHandlerExistsInSubFrame                            BackForwardCacheNotRestoredReason = \"UnloadHandlerExistsInSubFrame\"\n\tBackForwardCacheNotRestoredReasonServiceWorkerUnregistration                              BackForwardCacheNotRestoredReason = \"ServiceWorkerUnregistration\"\n\tBackForwardCacheNotRestoredReasonCacheControlNoStore                                      BackForwardCacheNotRestoredReason = \"CacheControlNoStore\"\n\tBackForwardCacheNotRestoredReasonCacheControlNoStoreCookieModified                        BackForwardCacheNotRestoredReason = \"CacheControlNoStoreCookieModified\"\n\tBackForwardCacheNotRestoredReasonCacheControlNoStoreHTTPOnlyCookieModified                BackForwardCacheNotRestoredReason = \"CacheControlNoStoreHTTPOnlyCookieModified\"\n\tBackForwardCacheNotRestoredReasonNoResponseHead                                           BackForwardCacheNotRestoredReason = \"NoResponseHead\"\n\tBackForwardCacheNotRestoredReasonUnknown                                                  BackForwardCacheNotRestoredReason = \"Unknown\"\n\tBackForwardCacheNotRestoredReasonActivationNavigationsDisallowedForBug1234857             BackForwardCacheNotRestoredReason = \"ActivationNavigationsDisallowedForBug1234857\"\n\tBackForwardCacheNotRestoredReasonErrorDocument                                            BackForwardCacheNotRestoredReason = \"ErrorDocument\"\n\tBackForwardCacheNotRestoredReasonFencedFramesEmbedder                                     BackForwardCacheNotRestoredReason = \"FencedFramesEmbedder\"\n\tBackForwardCacheNotRestoredReasonCookieDisabled                                           BackForwardCacheNotRestoredReason = \"CookieDisabled\"\n\tBackForwardCacheNotRestoredReasonHTTPAuthRequired                                         BackForwardCacheNotRestoredReason = \"HTTPAuthRequired\"\n\tBackForwardCacheNotRestoredReasonCookieFlushed                                            BackForwardCacheNotRestoredReason = \"CookieFlushed\"\n\tBackForwardCacheNotRestoredReasonBroadcastChannelOnMessage                                BackForwardCacheNotRestoredReason = \"BroadcastChannelOnMessage\"\n\tBackForwardCacheNotRestoredReasonWebViewSettingsChanged                                   BackForwardCacheNotRestoredReason = \"WebViewSettingsChanged\"\n\tBackForwardCacheNotRestoredReasonWebViewJavaScriptObjectChanged                           BackForwardCacheNotRestoredReason = \"WebViewJavaScriptObjectChanged\"\n\tBackForwardCacheNotRestoredReasonWebViewMessageListenerInjected                           BackForwardCacheNotRestoredReason = \"WebViewMessageListenerInjected\"\n\tBackForwardCacheNotRestoredReasonWebViewSafeBrowsingAllowlistChanged                      BackForwardCacheNotRestoredReason = \"WebViewSafeBrowsingAllowlistChanged\"\n\tBackForwardCacheNotRestoredReasonWebViewDocumentStartJavascriptChanged                    BackForwardCacheNotRestoredReason = \"WebViewDocumentStartJavascriptChanged\"\n\tBackForwardCacheNotRestoredReasonWebSocket                                                BackForwardCacheNotRestoredReason = \"WebSocket\"\n\tBackForwardCacheNotRestoredReasonWebTransport                                             BackForwardCacheNotRestoredReason = \"WebTransport\"\n\tBackForwardCacheNotRestoredReasonWebRTC                                                   BackForwardCacheNotRestoredReason = \"WebRTC\"\n\tBackForwardCacheNotRestoredReasonMainResourceHasCacheControlNoStore                       BackForwardCacheNotRestoredReason = \"MainResourceHasCacheControlNoStore\"\n\tBackForwardCacheNotRestoredReasonMainResourceHasCacheControlNoCache                       BackForwardCacheNotRestoredReason = \"MainResourceHasCacheControlNoCache\"\n\tBackForwardCacheNotRestoredReasonSubresourceHasCacheControlNoStore                        BackForwardCacheNotRestoredReason = \"SubresourceHasCacheControlNoStore\"\n\tBackForwardCacheNotRestoredReasonSubresourceHasCacheControlNoCache                        BackForwardCacheNotRestoredReason = \"SubresourceHasCacheControlNoCache\"\n\tBackForwardCacheNotRestoredReasonContainsPlugins                                          BackForwardCacheNotRestoredReason = \"ContainsPlugins\"\n\tBackForwardCacheNotRestoredReasonDocumentLoaded                                           BackForwardCacheNotRestoredReason = \"DocumentLoaded\"\n\tBackForwardCacheNotRestoredReasonOutstandingNetworkRequestOthers                          BackForwardCacheNotRestoredReason = \"OutstandingNetworkRequestOthers\"\n\tBackForwardCacheNotRestoredReasonRequestedMIDIPermission                                  BackForwardCacheNotRestoredReason = \"RequestedMIDIPermission\"\n\tBackForwardCacheNotRestoredReasonRequestedAudioCapturePermission                          BackForwardCacheNotRestoredReason = \"RequestedAudioCapturePermission\"\n\tBackForwardCacheNotRestoredReasonRequestedVideoCapturePermission                          BackForwardCacheNotRestoredReason = \"RequestedVideoCapturePermission\"\n\tBackForwardCacheNotRestoredReasonRequestedBackForwardCacheBlockedSensors                  BackForwardCacheNotRestoredReason = \"RequestedBackForwardCacheBlockedSensors\"\n\tBackForwardCacheNotRestoredReasonRequestedBackgroundWorkPermission                        BackForwardCacheNotRestoredReason = \"RequestedBackgroundWorkPermission\"\n\tBackForwardCacheNotRestoredReasonBroadcastChannel                                         BackForwardCacheNotRestoredReason = \"BroadcastChannel\"\n\tBackForwardCacheNotRestoredReasonWebXR                                                    BackForwardCacheNotRestoredReason = \"WebXR\"\n\tBackForwardCacheNotRestoredReasonSharedWorker                                             BackForwardCacheNotRestoredReason = \"SharedWorker\"\n\tBackForwardCacheNotRestoredReasonSharedWorkerMessage                                      BackForwardCacheNotRestoredReason = \"SharedWorkerMessage\"\n\tBackForwardCacheNotRestoredReasonWebLocks                                                 BackForwardCacheNotRestoredReason = \"WebLocks\"\n\tBackForwardCacheNotRestoredReasonWebHID                                                   BackForwardCacheNotRestoredReason = \"WebHID\"\n\tBackForwardCacheNotRestoredReasonWebShare                                                 BackForwardCacheNotRestoredReason = \"WebShare\"\n\tBackForwardCacheNotRestoredReasonRequestedStorageAccessGrant                              BackForwardCacheNotRestoredReason = \"RequestedStorageAccessGrant\"\n\tBackForwardCacheNotRestoredReasonWebNfc                                                   BackForwardCacheNotRestoredReason = \"WebNfc\"\n\tBackForwardCacheNotRestoredReasonOutstandingNetworkRequestFetch                           BackForwardCacheNotRestoredReason = \"OutstandingNetworkRequestFetch\"\n\tBackForwardCacheNotRestoredReasonOutstandingNetworkRequestXHR                             BackForwardCacheNotRestoredReason = \"OutstandingNetworkRequestXHR\"\n\tBackForwardCacheNotRestoredReasonAppBanner                                                BackForwardCacheNotRestoredReason = \"AppBanner\"\n\tBackForwardCacheNotRestoredReasonPrinting                                                 BackForwardCacheNotRestoredReason = \"Printing\"\n\tBackForwardCacheNotRestoredReasonWebDatabase                                              BackForwardCacheNotRestoredReason = \"WebDatabase\"\n\tBackForwardCacheNotRestoredReasonPictureInPicture                                         BackForwardCacheNotRestoredReason = \"PictureInPicture\"\n\tBackForwardCacheNotRestoredReasonSpeechRecognizer                                         BackForwardCacheNotRestoredReason = \"SpeechRecognizer\"\n\tBackForwardCacheNotRestoredReasonIdleManager                                              BackForwardCacheNotRestoredReason = \"IdleManager\"\n\tBackForwardCacheNotRestoredReasonPaymentManager                                           BackForwardCacheNotRestoredReason = \"PaymentManager\"\n\tBackForwardCacheNotRestoredReasonSpeechSynthesis                                          BackForwardCacheNotRestoredReason = \"SpeechSynthesis\"\n\tBackForwardCacheNotRestoredReasonKeyboardLock                                             BackForwardCacheNotRestoredReason = \"KeyboardLock\"\n\tBackForwardCacheNotRestoredReasonWebOTPService                                            BackForwardCacheNotRestoredReason = \"WebOTPService\"\n\tBackForwardCacheNotRestoredReasonOutstandingNetworkRequestDirectSocket                    BackForwardCacheNotRestoredReason = \"OutstandingNetworkRequestDirectSocket\"\n\tBackForwardCacheNotRestoredReasonInjectedJavascript                                       BackForwardCacheNotRestoredReason = \"InjectedJavascript\"\n\tBackForwardCacheNotRestoredReasonInjectedStyleSheet                                       BackForwardCacheNotRestoredReason = \"InjectedStyleSheet\"\n\tBackForwardCacheNotRestoredReasonKeepaliveRequest                                         BackForwardCacheNotRestoredReason = \"KeepaliveRequest\"\n\tBackForwardCacheNotRestoredReasonIndexedDBEvent                                           BackForwardCacheNotRestoredReason = \"IndexedDBEvent\"\n\tBackForwardCacheNotRestoredReasonDummy                                                    BackForwardCacheNotRestoredReason = \"Dummy\"\n\tBackForwardCacheNotRestoredReasonJsNetworkRequestReceivedCacheControlNoStoreResource      BackForwardCacheNotRestoredReason = \"JsNetworkRequestReceivedCacheControlNoStoreResource\"\n\tBackForwardCacheNotRestoredReasonWebRTCSticky                                             BackForwardCacheNotRestoredReason = \"WebRTCSticky\"\n\tBackForwardCacheNotRestoredReasonWebTransportSticky                                       BackForwardCacheNotRestoredReason = \"WebTransportSticky\"\n\tBackForwardCacheNotRestoredReasonWebSocketSticky                                          BackForwardCacheNotRestoredReason = \"WebSocketSticky\"\n\tBackForwardCacheNotRestoredReasonSmartCard                                                BackForwardCacheNotRestoredReason = \"SmartCard\"\n\tBackForwardCacheNotRestoredReasonLiveMediaStreamTrack                                     BackForwardCacheNotRestoredReason = \"LiveMediaStreamTrack\"\n\tBackForwardCacheNotRestoredReasonUnloadHandler                                            BackForwardCacheNotRestoredReason = \"UnloadHandler\"\n\tBackForwardCacheNotRestoredReasonParserAborted                                            BackForwardCacheNotRestoredReason = \"ParserAborted\"\n\tBackForwardCacheNotRestoredReasonContentSecurityHandler                                   BackForwardCacheNotRestoredReason = \"ContentSecurityHandler\"\n\tBackForwardCacheNotRestoredReasonContentWebAuthenticationAPI                              BackForwardCacheNotRestoredReason = \"ContentWebAuthenticationAPI\"\n\tBackForwardCacheNotRestoredReasonContentFileChooser                                       BackForwardCacheNotRestoredReason = \"ContentFileChooser\"\n\tBackForwardCacheNotRestoredReasonContentSerial                                            BackForwardCacheNotRestoredReason = \"ContentSerial\"\n\tBackForwardCacheNotRestoredReasonContentFileSystemAccess                                  BackForwardCacheNotRestoredReason = \"ContentFileSystemAccess\"\n\tBackForwardCacheNotRestoredReasonContentMediaDevicesDispatcherHost                        BackForwardCacheNotRestoredReason = \"ContentMediaDevicesDispatcherHost\"\n\tBackForwardCacheNotRestoredReasonContentWebBluetooth                                      BackForwardCacheNotRestoredReason = \"ContentWebBluetooth\"\n\tBackForwardCacheNotRestoredReasonContentWebUSB                                            BackForwardCacheNotRestoredReason = \"ContentWebUSB\"\n\tBackForwardCacheNotRestoredReasonContentMediaSessionService                               BackForwardCacheNotRestoredReason = \"ContentMediaSessionService\"\n\tBackForwardCacheNotRestoredReasonContentScreenReader                                      BackForwardCacheNotRestoredReason = \"ContentScreenReader\"\n\tBackForwardCacheNotRestoredReasonContentDiscarded                                         BackForwardCacheNotRestoredReason = \"ContentDiscarded\"\n\tBackForwardCacheNotRestoredReasonEmbedderPopupBlockerTabHelper                            BackForwardCacheNotRestoredReason = \"EmbedderPopupBlockerTabHelper\"\n\tBackForwardCacheNotRestoredReasonEmbedderSafeBrowsingTriggeredPopupBlocker                BackForwardCacheNotRestoredReason = \"EmbedderSafeBrowsingTriggeredPopupBlocker\"\n\tBackForwardCacheNotRestoredReasonEmbedderSafeBrowsingThreatDetails                        BackForwardCacheNotRestoredReason = \"EmbedderSafeBrowsingThreatDetails\"\n\tBackForwardCacheNotRestoredReasonEmbedderAppBannerManager                                 BackForwardCacheNotRestoredReason = \"EmbedderAppBannerManager\"\n\tBackForwardCacheNotRestoredReasonEmbedderDomDistillerViewerSource                         BackForwardCacheNotRestoredReason = \"EmbedderDomDistillerViewerSource\"\n\tBackForwardCacheNotRestoredReasonEmbedderDomDistillerSelfDeletingRequestDelegate          BackForwardCacheNotRestoredReason = \"EmbedderDomDistillerSelfDeletingRequestDelegate\"\n\tBackForwardCacheNotRestoredReasonEmbedderOomInterventionTabHelper                         BackForwardCacheNotRestoredReason = \"EmbedderOomInterventionTabHelper\"\n\tBackForwardCacheNotRestoredReasonEmbedderOfflinePage                                      BackForwardCacheNotRestoredReason = \"EmbedderOfflinePage\"\n\tBackForwardCacheNotRestoredReasonEmbedderChromePasswordManagerClientBindCredentialManager BackForwardCacheNotRestoredReason = \"EmbedderChromePasswordManagerClientBindCredentialManager\"\n\tBackForwardCacheNotRestoredReasonEmbedderPermissionRequestManager                         BackForwardCacheNotRestoredReason = \"EmbedderPermissionRequestManager\"\n\tBackForwardCacheNotRestoredReasonEmbedderModalDialog                                      BackForwardCacheNotRestoredReason = \"EmbedderModalDialog\"\n\tBackForwardCacheNotRestoredReasonEmbedderExtensions                                       BackForwardCacheNotRestoredReason = \"EmbedderExtensions\"\n\tBackForwardCacheNotRestoredReasonEmbedderExtensionMessaging                               BackForwardCacheNotRestoredReason = \"EmbedderExtensionMessaging\"\n\tBackForwardCacheNotRestoredReasonEmbedderExtensionMessagingForOpenPort                    BackForwardCacheNotRestoredReason = \"EmbedderExtensionMessagingForOpenPort\"\n\tBackForwardCacheNotRestoredReasonEmbedderExtensionSentMessageToCachedFrame                BackForwardCacheNotRestoredReason = \"EmbedderExtensionSentMessageToCachedFrame\"\n\tBackForwardCacheNotRestoredReasonRequestedByWebViewClient                                 BackForwardCacheNotRestoredReason = \"RequestedByWebViewClient\"\n\tBackForwardCacheNotRestoredReasonPostMessageByWebViewClient                               BackForwardCacheNotRestoredReason = \"PostMessageByWebViewClient\"\n\tBackForwardCacheNotRestoredReasonCacheControlNoStoreDeviceBoundSessionTerminated          BackForwardCacheNotRestoredReason = \"CacheControlNoStoreDeviceBoundSessionTerminated\"\n\tBackForwardCacheNotRestoredReasonCacheLimitPrunedOnModerateMemoryPressure                 BackForwardCacheNotRestoredReason = \"CacheLimitPrunedOnModerateMemoryPressure\"\n\tBackForwardCacheNotRestoredReasonCacheLimitPrunedOnCriticalMemoryPressure                 BackForwardCacheNotRestoredReason = \"CacheLimitPrunedOnCriticalMemoryPressure\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *BackForwardCacheNotRestoredReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch BackForwardCacheNotRestoredReason(s) {\n\tcase BackForwardCacheNotRestoredReasonNotPrimaryMainFrame:\n\t\t*t = BackForwardCacheNotRestoredReasonNotPrimaryMainFrame\n\tcase BackForwardCacheNotRestoredReasonBackForwardCacheDisabled:\n\t\t*t = BackForwardCacheNotRestoredReasonBackForwardCacheDisabled\n\tcase BackForwardCacheNotRestoredReasonRelatedActiveContentsExist:\n\t\t*t = BackForwardCacheNotRestoredReasonRelatedActiveContentsExist\n\tcase BackForwardCacheNotRestoredReasonHTTPSTatusNotOK:\n\t\t*t = BackForwardCacheNotRestoredReasonHTTPSTatusNotOK\n\tcase BackForwardCacheNotRestoredReasonSchemeNotHTTPOrHTTPS:\n\t\t*t = BackForwardCacheNotRestoredReasonSchemeNotHTTPOrHTTPS\n\tcase BackForwardCacheNotRestoredReasonLoading:\n\t\t*t = BackForwardCacheNotRestoredReasonLoading\n\tcase BackForwardCacheNotRestoredReasonWasGrantedMediaAccess:\n\t\t*t = BackForwardCacheNotRestoredReasonWasGrantedMediaAccess\n\tcase BackForwardCacheNotRestoredReasonDisableForRenderFrameHostCalled:\n\t\t*t = BackForwardCacheNotRestoredReasonDisableForRenderFrameHostCalled\n\tcase BackForwardCacheNotRestoredReasonDomainNotAllowed:\n\t\t*t = BackForwardCacheNotRestoredReasonDomainNotAllowed\n\tcase BackForwardCacheNotRestoredReasonHTTPMethodNotGET:\n\t\t*t = BackForwardCacheNotRestoredReasonHTTPMethodNotGET\n\tcase BackForwardCacheNotRestoredReasonSubframeIsNavigating:\n\t\t*t = BackForwardCacheNotRestoredReasonSubframeIsNavigating\n\tcase BackForwardCacheNotRestoredReasonTimeout:\n\t\t*t = BackForwardCacheNotRestoredReasonTimeout\n\tcase BackForwardCacheNotRestoredReasonCacheLimit:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheLimit\n\tcase BackForwardCacheNotRestoredReasonJavaScriptExecution:\n\t\t*t = BackForwardCacheNotRestoredReasonJavaScriptExecution\n\tcase BackForwardCacheNotRestoredReasonRendererProcessKilled:\n\t\t*t = BackForwardCacheNotRestoredReasonRendererProcessKilled\n\tcase BackForwardCacheNotRestoredReasonRendererProcessCrashed:\n\t\t*t = BackForwardCacheNotRestoredReasonRendererProcessCrashed\n\tcase BackForwardCacheNotRestoredReasonSchedulerTrackedFeatureUsed:\n\t\t*t = BackForwardCacheNotRestoredReasonSchedulerTrackedFeatureUsed\n\tcase BackForwardCacheNotRestoredReasonConflictingBrowsingInstance:\n\t\t*t = BackForwardCacheNotRestoredReasonConflictingBrowsingInstance\n\tcase BackForwardCacheNotRestoredReasonCacheFlushed:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheFlushed\n\tcase BackForwardCacheNotRestoredReasonServiceWorkerVersionActivation:\n\t\t*t = BackForwardCacheNotRestoredReasonServiceWorkerVersionActivation\n\tcase BackForwardCacheNotRestoredReasonSessionRestored:\n\t\t*t = BackForwardCacheNotRestoredReasonSessionRestored\n\tcase BackForwardCacheNotRestoredReasonServiceWorkerPostMessage:\n\t\t*t = BackForwardCacheNotRestoredReasonServiceWorkerPostMessage\n\tcase BackForwardCacheNotRestoredReasonEnteredBackForwardCacheBeforeServiceWorkerHostAdded:\n\t\t*t = BackForwardCacheNotRestoredReasonEnteredBackForwardCacheBeforeServiceWorkerHostAdded\n\tcase BackForwardCacheNotRestoredReasonRenderFrameHostReusedSameSite:\n\t\t*t = BackForwardCacheNotRestoredReasonRenderFrameHostReusedSameSite\n\tcase BackForwardCacheNotRestoredReasonRenderFrameHostReusedCrossSite:\n\t\t*t = BackForwardCacheNotRestoredReasonRenderFrameHostReusedCrossSite\n\tcase BackForwardCacheNotRestoredReasonServiceWorkerClaim:\n\t\t*t = BackForwardCacheNotRestoredReasonServiceWorkerClaim\n\tcase BackForwardCacheNotRestoredReasonIgnoreEventAndEvict:\n\t\t*t = BackForwardCacheNotRestoredReasonIgnoreEventAndEvict\n\tcase BackForwardCacheNotRestoredReasonHaveInnerContents:\n\t\t*t = BackForwardCacheNotRestoredReasonHaveInnerContents\n\tcase BackForwardCacheNotRestoredReasonTimeoutPuttingInCache:\n\t\t*t = BackForwardCacheNotRestoredReasonTimeoutPuttingInCache\n\tcase BackForwardCacheNotRestoredReasonBackForwardCacheDisabledByLowMemory:\n\t\t*t = BackForwardCacheNotRestoredReasonBackForwardCacheDisabledByLowMemory\n\tcase BackForwardCacheNotRestoredReasonBackForwardCacheDisabledByCommandLine:\n\t\t*t = BackForwardCacheNotRestoredReasonBackForwardCacheDisabledByCommandLine\n\tcase BackForwardCacheNotRestoredReasonNetworkRequestDatapipeDrainedAsBytesConsumer:\n\t\t*t = BackForwardCacheNotRestoredReasonNetworkRequestDatapipeDrainedAsBytesConsumer\n\tcase BackForwardCacheNotRestoredReasonNetworkRequestRedirected:\n\t\t*t = BackForwardCacheNotRestoredReasonNetworkRequestRedirected\n\tcase BackForwardCacheNotRestoredReasonNetworkRequestTimeout:\n\t\t*t = BackForwardCacheNotRestoredReasonNetworkRequestTimeout\n\tcase BackForwardCacheNotRestoredReasonNetworkExceedsBufferLimit:\n\t\t*t = BackForwardCacheNotRestoredReasonNetworkExceedsBufferLimit\n\tcase BackForwardCacheNotRestoredReasonNavigationCancelledWhileRestoring:\n\t\t*t = BackForwardCacheNotRestoredReasonNavigationCancelledWhileRestoring\n\tcase BackForwardCacheNotRestoredReasonNotMostRecentNavigationEntry:\n\t\t*t = BackForwardCacheNotRestoredReasonNotMostRecentNavigationEntry\n\tcase BackForwardCacheNotRestoredReasonBackForwardCacheDisabledForPrerender:\n\t\t*t = BackForwardCacheNotRestoredReasonBackForwardCacheDisabledForPrerender\n\tcase BackForwardCacheNotRestoredReasonUserAgentOverrideDiffers:\n\t\t*t = BackForwardCacheNotRestoredReasonUserAgentOverrideDiffers\n\tcase BackForwardCacheNotRestoredReasonForegroundCacheLimit:\n\t\t*t = BackForwardCacheNotRestoredReasonForegroundCacheLimit\n\tcase BackForwardCacheNotRestoredReasonBrowsingInstanceNotSwapped:\n\t\t*t = BackForwardCacheNotRestoredReasonBrowsingInstanceNotSwapped\n\tcase BackForwardCacheNotRestoredReasonBackForwardCacheDisabledForDelegate:\n\t\t*t = BackForwardCacheNotRestoredReasonBackForwardCacheDisabledForDelegate\n\tcase BackForwardCacheNotRestoredReasonUnloadHandlerExistsInMainFrame:\n\t\t*t = BackForwardCacheNotRestoredReasonUnloadHandlerExistsInMainFrame\n\tcase BackForwardCacheNotRestoredReasonUnloadHandlerExistsInSubFrame:\n\t\t*t = BackForwardCacheNotRestoredReasonUnloadHandlerExistsInSubFrame\n\tcase BackForwardCacheNotRestoredReasonServiceWorkerUnregistration:\n\t\t*t = BackForwardCacheNotRestoredReasonServiceWorkerUnregistration\n\tcase BackForwardCacheNotRestoredReasonCacheControlNoStore:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheControlNoStore\n\tcase BackForwardCacheNotRestoredReasonCacheControlNoStoreCookieModified:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheControlNoStoreCookieModified\n\tcase BackForwardCacheNotRestoredReasonCacheControlNoStoreHTTPOnlyCookieModified:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheControlNoStoreHTTPOnlyCookieModified\n\tcase BackForwardCacheNotRestoredReasonNoResponseHead:\n\t\t*t = BackForwardCacheNotRestoredReasonNoResponseHead\n\tcase BackForwardCacheNotRestoredReasonUnknown:\n\t\t*t = BackForwardCacheNotRestoredReasonUnknown\n\tcase BackForwardCacheNotRestoredReasonActivationNavigationsDisallowedForBug1234857:\n\t\t*t = BackForwardCacheNotRestoredReasonActivationNavigationsDisallowedForBug1234857\n\tcase BackForwardCacheNotRestoredReasonErrorDocument:\n\t\t*t = BackForwardCacheNotRestoredReasonErrorDocument\n\tcase BackForwardCacheNotRestoredReasonFencedFramesEmbedder:\n\t\t*t = BackForwardCacheNotRestoredReasonFencedFramesEmbedder\n\tcase BackForwardCacheNotRestoredReasonCookieDisabled:\n\t\t*t = BackForwardCacheNotRestoredReasonCookieDisabled\n\tcase BackForwardCacheNotRestoredReasonHTTPAuthRequired:\n\t\t*t = BackForwardCacheNotRestoredReasonHTTPAuthRequired\n\tcase BackForwardCacheNotRestoredReasonCookieFlushed:\n\t\t*t = BackForwardCacheNotRestoredReasonCookieFlushed\n\tcase BackForwardCacheNotRestoredReasonBroadcastChannelOnMessage:\n\t\t*t = BackForwardCacheNotRestoredReasonBroadcastChannelOnMessage\n\tcase BackForwardCacheNotRestoredReasonWebViewSettingsChanged:\n\t\t*t = BackForwardCacheNotRestoredReasonWebViewSettingsChanged\n\tcase BackForwardCacheNotRestoredReasonWebViewJavaScriptObjectChanged:\n\t\t*t = BackForwardCacheNotRestoredReasonWebViewJavaScriptObjectChanged\n\tcase BackForwardCacheNotRestoredReasonWebViewMessageListenerInjected:\n\t\t*t = BackForwardCacheNotRestoredReasonWebViewMessageListenerInjected\n\tcase BackForwardCacheNotRestoredReasonWebViewSafeBrowsingAllowlistChanged:\n\t\t*t = BackForwardCacheNotRestoredReasonWebViewSafeBrowsingAllowlistChanged\n\tcase BackForwardCacheNotRestoredReasonWebViewDocumentStartJavascriptChanged:\n\t\t*t = BackForwardCacheNotRestoredReasonWebViewDocumentStartJavascriptChanged\n\tcase BackForwardCacheNotRestoredReasonWebSocket:\n\t\t*t = BackForwardCacheNotRestoredReasonWebSocket\n\tcase BackForwardCacheNotRestoredReasonWebTransport:\n\t\t*t = BackForwardCacheNotRestoredReasonWebTransport\n\tcase BackForwardCacheNotRestoredReasonWebRTC:\n\t\t*t = BackForwardCacheNotRestoredReasonWebRTC\n\tcase BackForwardCacheNotRestoredReasonMainResourceHasCacheControlNoStore:\n\t\t*t = BackForwardCacheNotRestoredReasonMainResourceHasCacheControlNoStore\n\tcase BackForwardCacheNotRestoredReasonMainResourceHasCacheControlNoCache:\n\t\t*t = BackForwardCacheNotRestoredReasonMainResourceHasCacheControlNoCache\n\tcase BackForwardCacheNotRestoredReasonSubresourceHasCacheControlNoStore:\n\t\t*t = BackForwardCacheNotRestoredReasonSubresourceHasCacheControlNoStore\n\tcase BackForwardCacheNotRestoredReasonSubresourceHasCacheControlNoCache:\n\t\t*t = BackForwardCacheNotRestoredReasonSubresourceHasCacheControlNoCache\n\tcase BackForwardCacheNotRestoredReasonContainsPlugins:\n\t\t*t = BackForwardCacheNotRestoredReasonContainsPlugins\n\tcase BackForwardCacheNotRestoredReasonDocumentLoaded:\n\t\t*t = BackForwardCacheNotRestoredReasonDocumentLoaded\n\tcase BackForwardCacheNotRestoredReasonOutstandingNetworkRequestOthers:\n\t\t*t = BackForwardCacheNotRestoredReasonOutstandingNetworkRequestOthers\n\tcase BackForwardCacheNotRestoredReasonRequestedMIDIPermission:\n\t\t*t = BackForwardCacheNotRestoredReasonRequestedMIDIPermission\n\tcase BackForwardCacheNotRestoredReasonRequestedAudioCapturePermission:\n\t\t*t = BackForwardCacheNotRestoredReasonRequestedAudioCapturePermission\n\tcase BackForwardCacheNotRestoredReasonRequestedVideoCapturePermission:\n\t\t*t = BackForwardCacheNotRestoredReasonRequestedVideoCapturePermission\n\tcase BackForwardCacheNotRestoredReasonRequestedBackForwardCacheBlockedSensors:\n\t\t*t = BackForwardCacheNotRestoredReasonRequestedBackForwardCacheBlockedSensors\n\tcase BackForwardCacheNotRestoredReasonRequestedBackgroundWorkPermission:\n\t\t*t = BackForwardCacheNotRestoredReasonRequestedBackgroundWorkPermission\n\tcase BackForwardCacheNotRestoredReasonBroadcastChannel:\n\t\t*t = BackForwardCacheNotRestoredReasonBroadcastChannel\n\tcase BackForwardCacheNotRestoredReasonWebXR:\n\t\t*t = BackForwardCacheNotRestoredReasonWebXR\n\tcase BackForwardCacheNotRestoredReasonSharedWorker:\n\t\t*t = BackForwardCacheNotRestoredReasonSharedWorker\n\tcase BackForwardCacheNotRestoredReasonSharedWorkerMessage:\n\t\t*t = BackForwardCacheNotRestoredReasonSharedWorkerMessage\n\tcase BackForwardCacheNotRestoredReasonWebLocks:\n\t\t*t = BackForwardCacheNotRestoredReasonWebLocks\n\tcase BackForwardCacheNotRestoredReasonWebHID:\n\t\t*t = BackForwardCacheNotRestoredReasonWebHID\n\tcase BackForwardCacheNotRestoredReasonWebShare:\n\t\t*t = BackForwardCacheNotRestoredReasonWebShare\n\tcase BackForwardCacheNotRestoredReasonRequestedStorageAccessGrant:\n\t\t*t = BackForwardCacheNotRestoredReasonRequestedStorageAccessGrant\n\tcase BackForwardCacheNotRestoredReasonWebNfc:\n\t\t*t = BackForwardCacheNotRestoredReasonWebNfc\n\tcase BackForwardCacheNotRestoredReasonOutstandingNetworkRequestFetch:\n\t\t*t = BackForwardCacheNotRestoredReasonOutstandingNetworkRequestFetch\n\tcase BackForwardCacheNotRestoredReasonOutstandingNetworkRequestXHR:\n\t\t*t = BackForwardCacheNotRestoredReasonOutstandingNetworkRequestXHR\n\tcase BackForwardCacheNotRestoredReasonAppBanner:\n\t\t*t = BackForwardCacheNotRestoredReasonAppBanner\n\tcase BackForwardCacheNotRestoredReasonPrinting:\n\t\t*t = BackForwardCacheNotRestoredReasonPrinting\n\tcase BackForwardCacheNotRestoredReasonWebDatabase:\n\t\t*t = BackForwardCacheNotRestoredReasonWebDatabase\n\tcase BackForwardCacheNotRestoredReasonPictureInPicture:\n\t\t*t = BackForwardCacheNotRestoredReasonPictureInPicture\n\tcase BackForwardCacheNotRestoredReasonSpeechRecognizer:\n\t\t*t = BackForwardCacheNotRestoredReasonSpeechRecognizer\n\tcase BackForwardCacheNotRestoredReasonIdleManager:\n\t\t*t = BackForwardCacheNotRestoredReasonIdleManager\n\tcase BackForwardCacheNotRestoredReasonPaymentManager:\n\t\t*t = BackForwardCacheNotRestoredReasonPaymentManager\n\tcase BackForwardCacheNotRestoredReasonSpeechSynthesis:\n\t\t*t = BackForwardCacheNotRestoredReasonSpeechSynthesis\n\tcase BackForwardCacheNotRestoredReasonKeyboardLock:\n\t\t*t = BackForwardCacheNotRestoredReasonKeyboardLock\n\tcase BackForwardCacheNotRestoredReasonWebOTPService:\n\t\t*t = BackForwardCacheNotRestoredReasonWebOTPService\n\tcase BackForwardCacheNotRestoredReasonOutstandingNetworkRequestDirectSocket:\n\t\t*t = BackForwardCacheNotRestoredReasonOutstandingNetworkRequestDirectSocket\n\tcase BackForwardCacheNotRestoredReasonInjectedJavascript:\n\t\t*t = BackForwardCacheNotRestoredReasonInjectedJavascript\n\tcase BackForwardCacheNotRestoredReasonInjectedStyleSheet:\n\t\t*t = BackForwardCacheNotRestoredReasonInjectedStyleSheet\n\tcase BackForwardCacheNotRestoredReasonKeepaliveRequest:\n\t\t*t = BackForwardCacheNotRestoredReasonKeepaliveRequest\n\tcase BackForwardCacheNotRestoredReasonIndexedDBEvent:\n\t\t*t = BackForwardCacheNotRestoredReasonIndexedDBEvent\n\tcase BackForwardCacheNotRestoredReasonDummy:\n\t\t*t = BackForwardCacheNotRestoredReasonDummy\n\tcase BackForwardCacheNotRestoredReasonJsNetworkRequestReceivedCacheControlNoStoreResource:\n\t\t*t = BackForwardCacheNotRestoredReasonJsNetworkRequestReceivedCacheControlNoStoreResource\n\tcase BackForwardCacheNotRestoredReasonWebRTCSticky:\n\t\t*t = BackForwardCacheNotRestoredReasonWebRTCSticky\n\tcase BackForwardCacheNotRestoredReasonWebTransportSticky:\n\t\t*t = BackForwardCacheNotRestoredReasonWebTransportSticky\n\tcase BackForwardCacheNotRestoredReasonWebSocketSticky:\n\t\t*t = BackForwardCacheNotRestoredReasonWebSocketSticky\n\tcase BackForwardCacheNotRestoredReasonSmartCard:\n\t\t*t = BackForwardCacheNotRestoredReasonSmartCard\n\tcase BackForwardCacheNotRestoredReasonLiveMediaStreamTrack:\n\t\t*t = BackForwardCacheNotRestoredReasonLiveMediaStreamTrack\n\tcase BackForwardCacheNotRestoredReasonUnloadHandler:\n\t\t*t = BackForwardCacheNotRestoredReasonUnloadHandler\n\tcase BackForwardCacheNotRestoredReasonParserAborted:\n\t\t*t = BackForwardCacheNotRestoredReasonParserAborted\n\tcase BackForwardCacheNotRestoredReasonContentSecurityHandler:\n\t\t*t = BackForwardCacheNotRestoredReasonContentSecurityHandler\n\tcase BackForwardCacheNotRestoredReasonContentWebAuthenticationAPI:\n\t\t*t = BackForwardCacheNotRestoredReasonContentWebAuthenticationAPI\n\tcase BackForwardCacheNotRestoredReasonContentFileChooser:\n\t\t*t = BackForwardCacheNotRestoredReasonContentFileChooser\n\tcase BackForwardCacheNotRestoredReasonContentSerial:\n\t\t*t = BackForwardCacheNotRestoredReasonContentSerial\n\tcase BackForwardCacheNotRestoredReasonContentFileSystemAccess:\n\t\t*t = BackForwardCacheNotRestoredReasonContentFileSystemAccess\n\tcase BackForwardCacheNotRestoredReasonContentMediaDevicesDispatcherHost:\n\t\t*t = BackForwardCacheNotRestoredReasonContentMediaDevicesDispatcherHost\n\tcase BackForwardCacheNotRestoredReasonContentWebBluetooth:\n\t\t*t = BackForwardCacheNotRestoredReasonContentWebBluetooth\n\tcase BackForwardCacheNotRestoredReasonContentWebUSB:\n\t\t*t = BackForwardCacheNotRestoredReasonContentWebUSB\n\tcase BackForwardCacheNotRestoredReasonContentMediaSessionService:\n\t\t*t = BackForwardCacheNotRestoredReasonContentMediaSessionService\n\tcase BackForwardCacheNotRestoredReasonContentScreenReader:\n\t\t*t = BackForwardCacheNotRestoredReasonContentScreenReader\n\tcase BackForwardCacheNotRestoredReasonContentDiscarded:\n\t\t*t = BackForwardCacheNotRestoredReasonContentDiscarded\n\tcase BackForwardCacheNotRestoredReasonEmbedderPopupBlockerTabHelper:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderPopupBlockerTabHelper\n\tcase BackForwardCacheNotRestoredReasonEmbedderSafeBrowsingTriggeredPopupBlocker:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderSafeBrowsingTriggeredPopupBlocker\n\tcase BackForwardCacheNotRestoredReasonEmbedderSafeBrowsingThreatDetails:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderSafeBrowsingThreatDetails\n\tcase BackForwardCacheNotRestoredReasonEmbedderAppBannerManager:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderAppBannerManager\n\tcase BackForwardCacheNotRestoredReasonEmbedderDomDistillerViewerSource:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderDomDistillerViewerSource\n\tcase BackForwardCacheNotRestoredReasonEmbedderDomDistillerSelfDeletingRequestDelegate:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderDomDistillerSelfDeletingRequestDelegate\n\tcase BackForwardCacheNotRestoredReasonEmbedderOomInterventionTabHelper:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderOomInterventionTabHelper\n\tcase BackForwardCacheNotRestoredReasonEmbedderOfflinePage:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderOfflinePage\n\tcase BackForwardCacheNotRestoredReasonEmbedderChromePasswordManagerClientBindCredentialManager:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderChromePasswordManagerClientBindCredentialManager\n\tcase BackForwardCacheNotRestoredReasonEmbedderPermissionRequestManager:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderPermissionRequestManager\n\tcase BackForwardCacheNotRestoredReasonEmbedderModalDialog:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderModalDialog\n\tcase BackForwardCacheNotRestoredReasonEmbedderExtensions:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderExtensions\n\tcase BackForwardCacheNotRestoredReasonEmbedderExtensionMessaging:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderExtensionMessaging\n\tcase BackForwardCacheNotRestoredReasonEmbedderExtensionMessagingForOpenPort:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderExtensionMessagingForOpenPort\n\tcase BackForwardCacheNotRestoredReasonEmbedderExtensionSentMessageToCachedFrame:\n\t\t*t = BackForwardCacheNotRestoredReasonEmbedderExtensionSentMessageToCachedFrame\n\tcase BackForwardCacheNotRestoredReasonRequestedByWebViewClient:\n\t\t*t = BackForwardCacheNotRestoredReasonRequestedByWebViewClient\n\tcase BackForwardCacheNotRestoredReasonPostMessageByWebViewClient:\n\t\t*t = BackForwardCacheNotRestoredReasonPostMessageByWebViewClient\n\tcase BackForwardCacheNotRestoredReasonCacheControlNoStoreDeviceBoundSessionTerminated:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheControlNoStoreDeviceBoundSessionTerminated\n\tcase BackForwardCacheNotRestoredReasonCacheLimitPrunedOnModerateMemoryPressure:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheLimitPrunedOnModerateMemoryPressure\n\tcase BackForwardCacheNotRestoredReasonCacheLimitPrunedOnCriticalMemoryPressure:\n\t\t*t = BackForwardCacheNotRestoredReasonCacheLimitPrunedOnCriticalMemoryPressure\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown BackForwardCacheNotRestoredReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// BackForwardCacheNotRestoredReasonType types of not restored reasons for\n// back-forward cache.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-BackForwardCacheNotRestoredReasonType\ntype BackForwardCacheNotRestoredReasonType string\n\n// String returns the BackForwardCacheNotRestoredReasonType as string value.\nfunc (t BackForwardCacheNotRestoredReasonType) String() string {\n\treturn string(t)\n}\n\n// BackForwardCacheNotRestoredReasonType values.\nconst (\n\tBackForwardCacheNotRestoredReasonTypeSupportPending    BackForwardCacheNotRestoredReasonType = \"SupportPending\"\n\tBackForwardCacheNotRestoredReasonTypePageSupportNeeded BackForwardCacheNotRestoredReasonType = \"PageSupportNeeded\"\n\tBackForwardCacheNotRestoredReasonTypeCircumstantial    BackForwardCacheNotRestoredReasonType = \"Circumstantial\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *BackForwardCacheNotRestoredReasonType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch BackForwardCacheNotRestoredReasonType(s) {\n\tcase BackForwardCacheNotRestoredReasonTypeSupportPending:\n\t\t*t = BackForwardCacheNotRestoredReasonTypeSupportPending\n\tcase BackForwardCacheNotRestoredReasonTypePageSupportNeeded:\n\t\t*t = BackForwardCacheNotRestoredReasonTypePageSupportNeeded\n\tcase BackForwardCacheNotRestoredReasonTypeCircumstantial:\n\t\t*t = BackForwardCacheNotRestoredReasonTypeCircumstantial\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown BackForwardCacheNotRestoredReasonType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// BackForwardCacheBlockingDetails [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-BackForwardCacheBlockingDetails\ntype BackForwardCacheBlockingDetails struct {\n\tURL          string `json:\"url,omitempty,omitzero\"`      // Url of the file where blockage happened. Optional because of tests.\n\tFunction     string `json:\"function,omitempty,omitzero\"` // Function name where blockage happened. Optional because of anonymous functions and tests.\n\tLineNumber   int64  `json:\"lineNumber\"`                  // Line number in the script (0-based).\n\tColumnNumber int64  `json:\"columnNumber\"`                // Column number in the script (0-based).\n}\n\n// BackForwardCacheNotRestoredExplanation [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-BackForwardCacheNotRestoredExplanation\ntype BackForwardCacheNotRestoredExplanation struct {\n\tType    BackForwardCacheNotRestoredReasonType `json:\"type\"`                       // Type of the reason\n\tReason  BackForwardCacheNotRestoredReason     `json:\"reason\"`                     // Not restored reason\n\tContext string                                `json:\"context,omitempty,omitzero\"` // Context associated with the reason. The meaning of this context is dependent on the reason: - EmbedderExtensionSentMessageToCachedFrame: the extension ID.\n\tDetails []*BackForwardCacheBlockingDetails    `json:\"details,omitempty,omitzero\"`\n}\n\n// BackForwardCacheNotRestoredExplanationTree [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#type-BackForwardCacheNotRestoredExplanationTree\ntype BackForwardCacheNotRestoredExplanationTree struct {\n\tURL          string                                        `json:\"url\"`          // URL of each frame\n\tExplanations []*BackForwardCacheNotRestoredExplanation     `json:\"explanations\"` // Not restored reasons of each frame\n\tChildren     []*BackForwardCacheNotRestoredExplanationTree `json:\"children\"`     // Array of children frame\n}\n\n// FileChooserOpenedMode input mode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-fileChooserOpened\ntype FileChooserOpenedMode string\n\n// String returns the FileChooserOpenedMode as string value.\nfunc (t FileChooserOpenedMode) String() string {\n\treturn string(t)\n}\n\n// FileChooserOpenedMode values.\nconst (\n\tFileChooserOpenedModeSelectSingle   FileChooserOpenedMode = \"selectSingle\"\n\tFileChooserOpenedModeSelectMultiple FileChooserOpenedMode = \"selectMultiple\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *FileChooserOpenedMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch FileChooserOpenedMode(s) {\n\tcase FileChooserOpenedModeSelectSingle:\n\t\t*t = FileChooserOpenedModeSelectSingle\n\tcase FileChooserOpenedModeSelectMultiple:\n\t\t*t = FileChooserOpenedModeSelectMultiple\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown FileChooserOpenedMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// FrameDetachedReason [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameDetached\ntype FrameDetachedReason string\n\n// String returns the FrameDetachedReason as string value.\nfunc (t FrameDetachedReason) String() string {\n\treturn string(t)\n}\n\n// FrameDetachedReason values.\nconst (\n\tFrameDetachedReasonRemove FrameDetachedReason = \"remove\"\n\tFrameDetachedReasonSwap   FrameDetachedReason = \"swap\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *FrameDetachedReason) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch FrameDetachedReason(s) {\n\tcase FrameDetachedReasonRemove:\n\t\t*t = FrameDetachedReasonRemove\n\tcase FrameDetachedReasonSwap:\n\t\t*t = FrameDetachedReasonSwap\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown FrameDetachedReason value: %v\", s)\n\t}\n\treturn nil\n}\n\n// FrameStartedNavigatingNavigationType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-frameStartedNavigating\ntype FrameStartedNavigatingNavigationType string\n\n// String returns the FrameStartedNavigatingNavigationType as string value.\nfunc (t FrameStartedNavigatingNavigationType) String() string {\n\treturn string(t)\n}\n\n// FrameStartedNavigatingNavigationType values.\nconst (\n\tFrameStartedNavigatingNavigationTypeReload                   FrameStartedNavigatingNavigationType = \"reload\"\n\tFrameStartedNavigatingNavigationTypeReloadBypassingCache     FrameStartedNavigatingNavigationType = \"reloadBypassingCache\"\n\tFrameStartedNavigatingNavigationTypeRestore                  FrameStartedNavigatingNavigationType = \"restore\"\n\tFrameStartedNavigatingNavigationTypeRestoreWithPost          FrameStartedNavigatingNavigationType = \"restoreWithPost\"\n\tFrameStartedNavigatingNavigationTypeHistorySameDocument      FrameStartedNavigatingNavigationType = \"historySameDocument\"\n\tFrameStartedNavigatingNavigationTypeHistoryDifferentDocument FrameStartedNavigatingNavigationType = \"historyDifferentDocument\"\n\tFrameStartedNavigatingNavigationTypeSameDocument             FrameStartedNavigatingNavigationType = \"sameDocument\"\n\tFrameStartedNavigatingNavigationTypeDifferentDocument        FrameStartedNavigatingNavigationType = \"differentDocument\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *FrameStartedNavigatingNavigationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch FrameStartedNavigatingNavigationType(s) {\n\tcase FrameStartedNavigatingNavigationTypeReload:\n\t\t*t = FrameStartedNavigatingNavigationTypeReload\n\tcase FrameStartedNavigatingNavigationTypeReloadBypassingCache:\n\t\t*t = FrameStartedNavigatingNavigationTypeReloadBypassingCache\n\tcase FrameStartedNavigatingNavigationTypeRestore:\n\t\t*t = FrameStartedNavigatingNavigationTypeRestore\n\tcase FrameStartedNavigatingNavigationTypeRestoreWithPost:\n\t\t*t = FrameStartedNavigatingNavigationTypeRestoreWithPost\n\tcase FrameStartedNavigatingNavigationTypeHistorySameDocument:\n\t\t*t = FrameStartedNavigatingNavigationTypeHistorySameDocument\n\tcase FrameStartedNavigatingNavigationTypeHistoryDifferentDocument:\n\t\t*t = FrameStartedNavigatingNavigationTypeHistoryDifferentDocument\n\tcase FrameStartedNavigatingNavigationTypeSameDocument:\n\t\t*t = FrameStartedNavigatingNavigationTypeSameDocument\n\tcase FrameStartedNavigatingNavigationTypeDifferentDocument:\n\t\t*t = FrameStartedNavigatingNavigationTypeDifferentDocument\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown FrameStartedNavigatingNavigationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// NavigatedWithinDocumentNavigationType navigation type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#event-navigatedWithinDocument\ntype NavigatedWithinDocumentNavigationType string\n\n// String returns the NavigatedWithinDocumentNavigationType as string value.\nfunc (t NavigatedWithinDocumentNavigationType) String() string {\n\treturn string(t)\n}\n\n// NavigatedWithinDocumentNavigationType values.\nconst (\n\tNavigatedWithinDocumentNavigationTypeFragment   NavigatedWithinDocumentNavigationType = \"fragment\"\n\tNavigatedWithinDocumentNavigationTypeHistoryAPI NavigatedWithinDocumentNavigationType = \"historyApi\"\n\tNavigatedWithinDocumentNavigationTypeOther      NavigatedWithinDocumentNavigationType = \"other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *NavigatedWithinDocumentNavigationType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch NavigatedWithinDocumentNavigationType(s) {\n\tcase NavigatedWithinDocumentNavigationTypeFragment:\n\t\t*t = NavigatedWithinDocumentNavigationTypeFragment\n\tcase NavigatedWithinDocumentNavigationTypeHistoryAPI:\n\t\t*t = NavigatedWithinDocumentNavigationTypeHistoryAPI\n\tcase NavigatedWithinDocumentNavigationTypeOther:\n\t\t*t = NavigatedWithinDocumentNavigationTypeOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown NavigatedWithinDocumentNavigationType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CaptureScreenshotFormat image compression format (defaults to png).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-captureScreenshot\ntype CaptureScreenshotFormat string\n\n// String returns the CaptureScreenshotFormat as string value.\nfunc (t CaptureScreenshotFormat) String() string {\n\treturn string(t)\n}\n\n// CaptureScreenshotFormat values.\nconst (\n\tCaptureScreenshotFormatJpeg CaptureScreenshotFormat = \"jpeg\"\n\tCaptureScreenshotFormatPng  CaptureScreenshotFormat = \"png\"\n\tCaptureScreenshotFormatWebp CaptureScreenshotFormat = \"webp\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CaptureScreenshotFormat) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CaptureScreenshotFormat(s) {\n\tcase CaptureScreenshotFormatJpeg:\n\t\t*t = CaptureScreenshotFormatJpeg\n\tcase CaptureScreenshotFormatPng:\n\t\t*t = CaptureScreenshotFormatPng\n\tcase CaptureScreenshotFormatWebp:\n\t\t*t = CaptureScreenshotFormatWebp\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CaptureScreenshotFormat value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CaptureSnapshotFormat format (defaults to mhtml).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-captureSnapshot\ntype CaptureSnapshotFormat string\n\n// String returns the CaptureSnapshotFormat as string value.\nfunc (t CaptureSnapshotFormat) String() string {\n\treturn string(t)\n}\n\n// CaptureSnapshotFormat values.\nconst (\n\tCaptureSnapshotFormatMhtml CaptureSnapshotFormat = \"mhtml\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CaptureSnapshotFormat) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CaptureSnapshotFormat(s) {\n\tcase CaptureSnapshotFormatMhtml:\n\t\t*t = CaptureSnapshotFormatMhtml\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CaptureSnapshotFormat value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PrintToPDFTransferMode return as stream.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-printToPDF\ntype PrintToPDFTransferMode string\n\n// String returns the PrintToPDFTransferMode as string value.\nfunc (t PrintToPDFTransferMode) String() string {\n\treturn string(t)\n}\n\n// PrintToPDFTransferMode values.\nconst (\n\tPrintToPDFTransferModeReturnAsBase64 PrintToPDFTransferMode = \"ReturnAsBase64\"\n\tPrintToPDFTransferModeReturnAsStream PrintToPDFTransferMode = \"ReturnAsStream\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PrintToPDFTransferMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PrintToPDFTransferMode(s) {\n\tcase PrintToPDFTransferModeReturnAsBase64:\n\t\t*t = PrintToPDFTransferModeReturnAsBase64\n\tcase PrintToPDFTransferModeReturnAsStream:\n\t\t*t = PrintToPDFTransferModeReturnAsStream\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PrintToPDFTransferMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ScreencastFormat image compression format.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-startScreencast\ntype ScreencastFormat string\n\n// String returns the ScreencastFormat as string value.\nfunc (t ScreencastFormat) String() string {\n\treturn string(t)\n}\n\n// ScreencastFormat values.\nconst (\n\tScreencastFormatJpeg ScreencastFormat = \"jpeg\"\n\tScreencastFormatPng  ScreencastFormat = \"png\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ScreencastFormat) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ScreencastFormat(s) {\n\tcase ScreencastFormatJpeg:\n\t\t*t = ScreencastFormatJpeg\n\tcase ScreencastFormatPng:\n\t\t*t = ScreencastFormatPng\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ScreencastFormat value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetWebLifecycleStateState target lifecycle state.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setWebLifecycleState\ntype SetWebLifecycleStateState string\n\n// String returns the SetWebLifecycleStateState as string value.\nfunc (t SetWebLifecycleStateState) String() string {\n\treturn string(t)\n}\n\n// SetWebLifecycleStateState values.\nconst (\n\tSetWebLifecycleStateStateFrozen SetWebLifecycleStateState = \"frozen\"\n\tSetWebLifecycleStateStateActive SetWebLifecycleStateState = \"active\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetWebLifecycleStateState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetWebLifecycleStateState(s) {\n\tcase SetWebLifecycleStateStateFrozen:\n\t\t*t = SetWebLifecycleStateStateFrozen\n\tcase SetWebLifecycleStateStateActive:\n\t\t*t = SetWebLifecycleStateStateActive\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetWebLifecycleStateState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetSPCTransactionModeMode [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setSPCTransactionMode\ntype SetSPCTransactionModeMode string\n\n// String returns the SetSPCTransactionModeMode as string value.\nfunc (t SetSPCTransactionModeMode) String() string {\n\treturn string(t)\n}\n\n// SetSPCTransactionModeMode values.\nconst (\n\tSetSPCTransactionModeModeNone                       SetSPCTransactionModeMode = \"none\"\n\tSetSPCTransactionModeModeAutoAccept                 SetSPCTransactionModeMode = \"autoAccept\"\n\tSetSPCTransactionModeModeAutoChooseToAuthAnotherWay SetSPCTransactionModeMode = \"autoChooseToAuthAnotherWay\"\n\tSetSPCTransactionModeModeAutoReject                 SetSPCTransactionModeMode = \"autoReject\"\n\tSetSPCTransactionModeModeAutoOptOut                 SetSPCTransactionModeMode = \"autoOptOut\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetSPCTransactionModeMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetSPCTransactionModeMode(s) {\n\tcase SetSPCTransactionModeModeNone:\n\t\t*t = SetSPCTransactionModeModeNone\n\tcase SetSPCTransactionModeModeAutoAccept:\n\t\t*t = SetSPCTransactionModeModeAutoAccept\n\tcase SetSPCTransactionModeModeAutoChooseToAuthAnotherWay:\n\t\t*t = SetSPCTransactionModeModeAutoChooseToAuthAnotherWay\n\tcase SetSPCTransactionModeModeAutoReject:\n\t\t*t = SetSPCTransactionModeModeAutoReject\n\tcase SetSPCTransactionModeModeAutoOptOut:\n\t\t*t = SetSPCTransactionModeModeAutoOptOut\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetSPCTransactionModeMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SetRPHRegistrationModeMode [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Page#method-setRPHRegistrationMode\ntype SetRPHRegistrationModeMode string\n\n// String returns the SetRPHRegistrationModeMode as string value.\nfunc (t SetRPHRegistrationModeMode) String() string {\n\treturn string(t)\n}\n\n// SetRPHRegistrationModeMode values.\nconst (\n\tSetRPHRegistrationModeModeNone       SetRPHRegistrationModeMode = \"none\"\n\tSetRPHRegistrationModeModeAutoAccept SetRPHRegistrationModeMode = \"autoAccept\"\n\tSetRPHRegistrationModeModeAutoReject SetRPHRegistrationModeMode = \"autoReject\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SetRPHRegistrationModeMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SetRPHRegistrationModeMode(s) {\n\tcase SetRPHRegistrationModeModeNone:\n\t\t*t = SetRPHRegistrationModeModeNone\n\tcase SetRPHRegistrationModeModeAutoAccept:\n\t\t*t = SetRPHRegistrationModeModeAutoAccept\n\tcase SetRPHRegistrationModeModeAutoReject:\n\t\t*t = SetRPHRegistrationModeModeAutoReject\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SetRPHRegistrationModeMode value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/performance/events.go",
    "content": "package performance\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventMetrics current values of the metrics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Performance#event-metrics\ntype EventMetrics struct {\n\tMetrics []*Metric `json:\"metrics\"` // Current values of the metrics.\n\tTitle   string    `json:\"title\"`   // Timestamp title.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/performance/performance.go",
    "content": "// Package performance provides the Chrome DevTools Protocol\n// commands, types, and events for the Performance domain.\n//\n// Generated by the cdproto-gen command.\npackage performance\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// DisableParams disable collecting and reporting metrics.\ntype DisableParams struct{}\n\n// Disable disable collecting and reporting metrics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Performance.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enable collecting and reporting metrics.\ntype EnableParams struct {\n\tTimeDomain EnableTimeDomain `json:\"timeDomain,omitempty,omitzero\"` // Time domain to use for collecting and reporting duration metrics.\n}\n\n// Enable enable collecting and reporting metrics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// WithTimeDomain time domain to use for collecting and reporting duration\n// metrics.\nfunc (p EnableParams) WithTimeDomain(timeDomain EnableTimeDomain) *EnableParams {\n\tp.TimeDomain = timeDomain\n\treturn &p\n}\n\n// Do executes Performance.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// GetMetricsParams retrieve current values of run-time metrics.\ntype GetMetricsParams struct{}\n\n// GetMetrics retrieve current values of run-time metrics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-getMetrics\nfunc GetMetrics() *GetMetricsParams {\n\treturn &GetMetricsParams{}\n}\n\n// GetMetricsReturns return values.\ntype GetMetricsReturns struct {\n\tMetrics []*Metric `json:\"metrics,omitempty,omitzero\"` // Current values for run-time metrics.\n}\n\n// Do executes Performance.getMetrics against the provided context.\n//\n// returns:\n//\n//\tmetrics - Current values for run-time metrics.\nfunc (p *GetMetricsParams) Do(ctx context.Context) (metrics []*Metric, err error) {\n\t// execute\n\tvar res GetMetricsReturns\n\terr = cdp.Execute(ctx, CommandGetMetrics, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Metrics, nil\n}\n\n// Command names.\nconst (\n\tCommandDisable    = \"Performance.disable\"\n\tCommandEnable     = \"Performance.enable\"\n\tCommandGetMetrics = \"Performance.getMetrics\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/performance/types.go",
    "content": "package performance\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// Metric run-time execution metric.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Performance#type-Metric\ntype Metric struct {\n\tName  string  `json:\"name\"`  // Metric name.\n\tValue float64 `json:\"value\"` // Metric value.\n}\n\n// EnableTimeDomain time domain to use for collecting and reporting duration\n// metrics.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Performance#method-enable\ntype EnableTimeDomain string\n\n// String returns the EnableTimeDomain as string value.\nfunc (t EnableTimeDomain) String() string {\n\treturn string(t)\n}\n\n// EnableTimeDomain values.\nconst (\n\tEnableTimeDomainTimeTicks   EnableTimeDomain = \"timeTicks\"\n\tEnableTimeDomainThreadTicks EnableTimeDomain = \"threadTicks\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *EnableTimeDomain) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch EnableTimeDomain(s) {\n\tcase EnableTimeDomainTimeTicks:\n\t\t*t = EnableTimeDomainTimeTicks\n\tcase EnableTimeDomainThreadTicks:\n\t\t*t = EnableTimeDomainThreadTicks\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown EnableTimeDomain value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/performancetimeline/events.go",
    "content": "package performancetimeline\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventTimelineEventAdded sent when a performance timeline event is added.\n// See reportPerformanceTimeline method.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#event-timelineEventAdded\ntype EventTimelineEventAdded struct {\n\tEvent *TimelineEvent `json:\"event\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/performancetimeline/performancetimeline.go",
    "content": "// Package performancetimeline provides the Chrome DevTools Protocol\n// commands, types, and events for the PerformanceTimeline domain.\n//\n// Reporting of performance timeline events, as specified in\n// https://w3c.github.io/performance-timeline/#dom-performanceobserver.\n//\n// Generated by the cdproto-gen command.\npackage performancetimeline\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams previously buffered events would be reported before method\n// returns. See also: timelineEventAdded.\ntype EnableParams struct {\n\tEventTypes []string `json:\"eventTypes\"` // The types of event to report, as specified in https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype The specified filter overrides any previous filters, passing empty filter disables recording. Note that not all types exposed to the web platform are currently supported.\n}\n\n// Enable previously buffered events would be reported before method returns.\n// See also: timelineEventAdded.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#method-enable\n//\n// parameters:\n//\n//\teventTypes - The types of event to report, as specified in https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype The specified filter overrides any previous filters, passing empty filter disables recording. Note that not all types exposed to the web platform are currently supported.\nfunc Enable(eventTypes []string) *EnableParams {\n\treturn &EnableParams{\n\t\tEventTypes: eventTypes,\n\t}\n}\n\n// Do executes PerformanceTimeline.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable = \"PerformanceTimeline.enable\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/performancetimeline/types.go",
    "content": "package performancetimeline\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/dom\"\n)\n\n// LargestContentfulPaint see https://github.com/WICG/LargestContentfulPaint\n// and largest_contentful_paint.idl.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-LargestContentfulPaint\ntype LargestContentfulPaint struct {\n\tRenderTime *cdp.TimeSinceEpoch `json:\"renderTime\"`\n\tLoadTime   *cdp.TimeSinceEpoch `json:\"loadTime\"`\n\tSize       float64             `json:\"size\"`                         // The number of pixels being painted.\n\tElementID  string              `json:\"elementId,omitempty,omitzero\"` // The id attribute of the element, if available.\n\tURL        string              `json:\"url,omitempty,omitzero\"`       // The URL of the image (may be trimmed).\n\tNodeID     cdp.BackendNodeID   `json:\"nodeId,omitempty,omitzero\"`\n}\n\n// LayoutShiftAttribution [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-LayoutShiftAttribution\ntype LayoutShiftAttribution struct {\n\tPreviousRect *dom.Rect         `json:\"previousRect\"`\n\tCurrentRect  *dom.Rect         `json:\"currentRect\"`\n\tNodeID       cdp.BackendNodeID `json:\"nodeId,omitempty,omitzero\"`\n}\n\n// LayoutShift see\n// https://wicg.github.io/layout-instability/#sec-layout-shift and\n// layout_shift.idl.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-LayoutShift\ntype LayoutShift struct {\n\tValue          float64                   `json:\"value\"` // Score increment produced by this event.\n\tHadRecentInput bool                      `json:\"hadRecentInput\"`\n\tLastInputTime  *cdp.TimeSinceEpoch       `json:\"lastInputTime\"`\n\tSources        []*LayoutShiftAttribution `json:\"sources\"`\n}\n\n// TimelineEvent [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PerformanceTimeline#type-TimelineEvent\ntype TimelineEvent struct {\n\tFrameID            cdp.FrameID             `json:\"frameId\"`                     // Identifies the frame that this event is related to. Empty for non-frame targets.\n\tType               string                  `json:\"type\"`                        // The event type, as specified in https://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype This determines which of the optional \"details\" fields is present.\n\tName               string                  `json:\"name\"`                        // Name may be empty depending on the type.\n\tTime               *cdp.TimeSinceEpoch     `json:\"time\"`                        // Time in seconds since Epoch, monotonically increasing within document lifetime.\n\tDuration           float64                 `json:\"duration,omitempty,omitzero\"` // Event duration, if applicable.\n\tLcpDetails         *LargestContentfulPaint `json:\"lcpDetails,omitempty,omitzero\"`\n\tLayoutShiftDetails *LayoutShift            `json:\"layoutShiftDetails,omitempty,omitzero\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/preload/events.go",
    "content": "package preload\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n)\n\n// EventRuleSetUpdated upsert. Currently, it is only emitted when a rule set\n// added.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#event-ruleSetUpdated\ntype EventRuleSetUpdated struct {\n\tRuleSet *RuleSet `json:\"ruleSet\"`\n}\n\n// EventRuleSetRemoved [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#event-ruleSetRemoved\ntype EventRuleSetRemoved struct {\n\tID RuleSetID `json:\"id\"`\n}\n\n// EventPreloadEnabledStateUpdated fired when a preload enabled state is\n// updated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#event-preloadEnabledStateUpdated\ntype EventPreloadEnabledStateUpdated struct {\n\tDisabledByPreference                        bool `json:\"disabledByPreference\"`\n\tDisabledByDataSaver                         bool `json:\"disabledByDataSaver\"`\n\tDisabledByBatterySaver                      bool `json:\"disabledByBatterySaver\"`\n\tDisabledByHoldbackPrefetchSpeculationRules  bool `json:\"disabledByHoldbackPrefetchSpeculationRules\"`\n\tDisabledByHoldbackPrerenderSpeculationRules bool `json:\"disabledByHoldbackPrerenderSpeculationRules\"`\n}\n\n// EventPrefetchStatusUpdated fired when a prefetch attempt is updated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#event-prefetchStatusUpdated\ntype EventPrefetchStatusUpdated struct {\n\tKey               *IngAttemptKey    `json:\"key\"`\n\tPipelineID        PipelineID        `json:\"pipelineId\"`\n\tInitiatingFrameID cdp.FrameID       `json:\"initiatingFrameId\"` // The frame id of the frame initiating prefetch.\n\tPrefetchURL       string            `json:\"prefetchUrl\"`\n\tStatus            IngStatus         `json:\"status\"`\n\tPrefetchStatus    PrefetchStatus    `json:\"prefetchStatus\"`\n\tRequestID         network.RequestID `json:\"requestId\"`\n}\n\n// EventPrerenderStatusUpdated fired when a prerender attempt is updated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#event-prerenderStatusUpdated\ntype EventPrerenderStatusUpdated struct {\n\tKey                     *IngAttemptKey                `json:\"key\"`\n\tPipelineID              PipelineID                    `json:\"pipelineId\"`\n\tStatus                  IngStatus                     `json:\"status\"`\n\tPrerenderStatus         PrerenderFinalStatus          `json:\"prerenderStatus,omitempty,omitzero\"`\n\tDisallowedMojoInterface string                        `json:\"disallowedMojoInterface,omitempty,omitzero\"` // This is used to give users more information about the name of Mojo interface that is incompatible with prerender and has caused the cancellation of the attempt.\n\tMismatchedHeaders       []*PrerenderMismatchedHeaders `json:\"mismatchedHeaders,omitempty,omitzero\"`\n}\n\n// EventPreloadingAttemptSourcesUpdated send a list of sources for all\n// preloading attempts in a document.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#event-preloadingAttemptSourcesUpdated\ntype EventPreloadingAttemptSourcesUpdated struct {\n\tLoaderID                 cdp.LoaderID        `json:\"loaderId\"`\n\tPreloadingAttemptSources []*IngAttemptSource `json:\"preloadingAttemptSources\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/preload/preload.go",
    "content": "// Package preload provides the Chrome DevTools Protocol\n// commands, types, and events for the Preload domain.\n//\n// Generated by the cdproto-gen command.\npackage preload\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams [no description].\ntype EnableParams struct{}\n\n// Enable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Preload.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// DisableParams [no description].\ntype DisableParams struct{}\n\n// Disable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Preload.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable  = \"Preload.enable\"\n\tCommandDisable = \"Preload.disable\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/preload/types.go",
    "content": "package preload\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n)\n\n// RuleSetID unique id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-RuleSetId\ntype RuleSetID string\n\n// String returns the RuleSetID as string value.\nfunc (t RuleSetID) String() string {\n\treturn string(t)\n}\n\n// RuleSet corresponds to SpeculationRuleSet.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-RuleSet\ntype RuleSet struct {\n\tID            RuleSetID         `json:\"id\"`\n\tLoaderID      cdp.LoaderID      `json:\"loaderId\"`                         // Identifies a document which the rule set is associated with.\n\tSourceText    string            `json:\"sourceText\"`                       // Source text of JSON representing the rule set. If it comes from <script> tag, it is the textContent of the node. Note that it is a JSON for valid case.  See also: - https://wicg.github.io/nav-speculation/speculation-rules.html - https://github.com/WICG/nav-speculation/blob/main/triggers.md\n\tBackendNodeID cdp.BackendNodeID `json:\"backendNodeId,omitempty,omitzero\"` // A speculation rule set is either added through an inline <script> tag or through an external resource via the 'Speculation-Rules' HTTP header. For the first case, we include the BackendNodeId of the relevant <script> tag. For the second case, we include the external URL where the rule set was loaded from, and also RequestId if Network domain is enabled.  See also: - https://wicg.github.io/nav-speculation/speculation-rules.html#speculation-rules-script - https://wicg.github.io/nav-speculation/speculation-rules.html#speculation-rules-header\n\tURL           string            `json:\"url,omitempty,omitzero\"`\n\tRequestID     network.RequestID `json:\"requestId,omitempty,omitzero\"`\n\tErrorType     RuleSetErrorType  `json:\"errorType,omitempty,omitzero\"` // Error information errorMessage is null iff errorType is null.\n}\n\n// RuleSetErrorType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-RuleSetErrorType\ntype RuleSetErrorType string\n\n// String returns the RuleSetErrorType as string value.\nfunc (t RuleSetErrorType) String() string {\n\treturn string(t)\n}\n\n// RuleSetErrorType values.\nconst (\n\tRuleSetErrorTypeSourceIsNotJSONObject  RuleSetErrorType = \"SourceIsNotJsonObject\"\n\tRuleSetErrorTypeInvalidRulesSkipped    RuleSetErrorType = \"InvalidRulesSkipped\"\n\tRuleSetErrorTypeInvalidRulesetLevelTag RuleSetErrorType = \"InvalidRulesetLevelTag\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *RuleSetErrorType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch RuleSetErrorType(s) {\n\tcase RuleSetErrorTypeSourceIsNotJSONObject:\n\t\t*t = RuleSetErrorTypeSourceIsNotJSONObject\n\tcase RuleSetErrorTypeInvalidRulesSkipped:\n\t\t*t = RuleSetErrorTypeInvalidRulesSkipped\n\tcase RuleSetErrorTypeInvalidRulesetLevelTag:\n\t\t*t = RuleSetErrorTypeInvalidRulesetLevelTag\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown RuleSetErrorType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SpeculationAction the type of preloading attempted. It corresponds to\n// mojom::SpeculationAction (although PrefetchWithSubresources is omitted as it\n// isn't being used by clients).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-SpeculationAction\ntype SpeculationAction string\n\n// String returns the SpeculationAction as string value.\nfunc (t SpeculationAction) String() string {\n\treturn string(t)\n}\n\n// SpeculationAction values.\nconst (\n\tSpeculationActionPrefetch  SpeculationAction = \"Prefetch\"\n\tSpeculationActionPrerender SpeculationAction = \"Prerender\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SpeculationAction) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SpeculationAction(s) {\n\tcase SpeculationActionPrefetch:\n\t\t*t = SpeculationActionPrefetch\n\tcase SpeculationActionPrerender:\n\t\t*t = SpeculationActionPrerender\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SpeculationAction value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SpeculationTargetHint corresponds to mojom::SpeculationTargetHint. See\n// https://github.com/WICG/nav-speculation/blob/main/triggers.md#window-name-targeting-hints.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-SpeculationTargetHint\ntype SpeculationTargetHint string\n\n// String returns the SpeculationTargetHint as string value.\nfunc (t SpeculationTargetHint) String() string {\n\treturn string(t)\n}\n\n// SpeculationTargetHint values.\nconst (\n\tSpeculationTargetHintBlank SpeculationTargetHint = \"Blank\"\n\tSpeculationTargetHintSelf  SpeculationTargetHint = \"Self\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SpeculationTargetHint) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SpeculationTargetHint(s) {\n\tcase SpeculationTargetHintBlank:\n\t\t*t = SpeculationTargetHintBlank\n\tcase SpeculationTargetHintSelf:\n\t\t*t = SpeculationTargetHintSelf\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SpeculationTargetHint value: %v\", s)\n\t}\n\treturn nil\n}\n\n// IngAttemptKey a key that identifies a preloading attempt. The url used is\n// the url specified by the trigger (i.e. the initial URL), and not the final\n// url that is navigated to. For example, prerendering allows same-origin main\n// frame navigations during the attempt, but the attempt is still keyed with the\n// initial URL.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-PreloadingAttemptKey\ntype IngAttemptKey struct {\n\tLoaderID   cdp.LoaderID          `json:\"loaderId\"`\n\tAction     SpeculationAction     `json:\"action\"`\n\tURL        string                `json:\"url\"`\n\tTargetHint SpeculationTargetHint `json:\"targetHint,omitempty,omitzero\"`\n}\n\n// IngAttemptSource lists sources for a preloading attempt, specifically the\n// ids of rule sets that had a speculation rule that triggered the attempt, and\n// the BackendNodeIds of <a href> or <area href> elements that triggered the\n// attempt (in the case of attempts triggered by a document rule). It is\n// possible for multiple rule sets and links to trigger a single attempt.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-PreloadingAttemptSource\ntype IngAttemptSource struct {\n\tKey        *IngAttemptKey      `json:\"key\"`\n\tRuleSetIDs []RuleSetID         `json:\"ruleSetIds\"`\n\tNodeIDs    []cdp.BackendNodeID `json:\"nodeIds\"`\n}\n\n// PipelineID chrome manages different types of preloads together using a\n// concept of preloading pipeline. For example, if a site uses a\n// SpeculationRules for prerender, Chrome first starts a prefetch and then\n// upgrades it to prerender. CDP events for them are emitted separately but they\n// share PreloadPipelineId.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-PreloadPipelineId\ntype PipelineID string\n\n// String returns the PipelineID as string value.\nfunc (t PipelineID) String() string {\n\treturn string(t)\n}\n\n// PrerenderFinalStatus list of FinalStatus reasons for Prerender2.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-PrerenderFinalStatus\ntype PrerenderFinalStatus string\n\n// String returns the PrerenderFinalStatus as string value.\nfunc (t PrerenderFinalStatus) String() string {\n\treturn string(t)\n}\n\n// PrerenderFinalStatus values.\nconst (\n\tPrerenderFinalStatusActivated                                                  PrerenderFinalStatus = \"Activated\"\n\tPrerenderFinalStatusDestroyed                                                  PrerenderFinalStatus = \"Destroyed\"\n\tPrerenderFinalStatusLowEndDevice                                               PrerenderFinalStatus = \"LowEndDevice\"\n\tPrerenderFinalStatusInvalidSchemeRedirect                                      PrerenderFinalStatus = \"InvalidSchemeRedirect\"\n\tPrerenderFinalStatusInvalidSchemeNavigation                                    PrerenderFinalStatus = \"InvalidSchemeNavigation\"\n\tPrerenderFinalStatusNavigationRequestBlockedByCsp                              PrerenderFinalStatus = \"NavigationRequestBlockedByCsp\"\n\tPrerenderFinalStatusMojoBinderPolicy                                           PrerenderFinalStatus = \"MojoBinderPolicy\"\n\tPrerenderFinalStatusRendererProcessCrashed                                     PrerenderFinalStatus = \"RendererProcessCrashed\"\n\tPrerenderFinalStatusRendererProcessKilled                                      PrerenderFinalStatus = \"RendererProcessKilled\"\n\tPrerenderFinalStatusDownload                                                   PrerenderFinalStatus = \"Download\"\n\tPrerenderFinalStatusTriggerDestroyed                                           PrerenderFinalStatus = \"TriggerDestroyed\"\n\tPrerenderFinalStatusNavigationNotCommitted                                     PrerenderFinalStatus = \"NavigationNotCommitted\"\n\tPrerenderFinalStatusNavigationBadHTTPStatus                                    PrerenderFinalStatus = \"NavigationBadHttpStatus\"\n\tPrerenderFinalStatusClientCertRequested                                        PrerenderFinalStatus = \"ClientCertRequested\"\n\tPrerenderFinalStatusNavigationRequestNetworkError                              PrerenderFinalStatus = \"NavigationRequestNetworkError\"\n\tPrerenderFinalStatusCancelAllHostsForTesting                                   PrerenderFinalStatus = \"CancelAllHostsForTesting\"\n\tPrerenderFinalStatusDidFailLoad                                                PrerenderFinalStatus = \"DidFailLoad\"\n\tPrerenderFinalStatusStop                                                       PrerenderFinalStatus = \"Stop\"\n\tPrerenderFinalStatusSslCertificateError                                        PrerenderFinalStatus = \"SslCertificateError\"\n\tPrerenderFinalStatusLoginAuthRequested                                         PrerenderFinalStatus = \"LoginAuthRequested\"\n\tPrerenderFinalStatusUaChangeRequiresReload                                     PrerenderFinalStatus = \"UaChangeRequiresReload\"\n\tPrerenderFinalStatusBlockedByClient                                            PrerenderFinalStatus = \"BlockedByClient\"\n\tPrerenderFinalStatusAudioOutputDeviceRequested                                 PrerenderFinalStatus = \"AudioOutputDeviceRequested\"\n\tPrerenderFinalStatusMixedContent                                               PrerenderFinalStatus = \"MixedContent\"\n\tPrerenderFinalStatusTriggerBackgrounded                                        PrerenderFinalStatus = \"TriggerBackgrounded\"\n\tPrerenderFinalStatusMemoryLimitExceeded                                        PrerenderFinalStatus = \"MemoryLimitExceeded\"\n\tPrerenderFinalStatusDataSaverEnabled                                           PrerenderFinalStatus = \"DataSaverEnabled\"\n\tPrerenderFinalStatusTriggerURLHasEffectiveURL                                  PrerenderFinalStatus = \"TriggerUrlHasEffectiveUrl\"\n\tPrerenderFinalStatusActivatedBeforeStarted                                     PrerenderFinalStatus = \"ActivatedBeforeStarted\"\n\tPrerenderFinalStatusInactivePageRestriction                                    PrerenderFinalStatus = \"InactivePageRestriction\"\n\tPrerenderFinalStatusStartFailed                                                PrerenderFinalStatus = \"StartFailed\"\n\tPrerenderFinalStatusTimeoutBackgrounded                                        PrerenderFinalStatus = \"TimeoutBackgrounded\"\n\tPrerenderFinalStatusCrossSiteRedirectInInitialNavigation                       PrerenderFinalStatus = \"CrossSiteRedirectInInitialNavigation\"\n\tPrerenderFinalStatusCrossSiteNavigationInInitialNavigation                     PrerenderFinalStatus = \"CrossSiteNavigationInInitialNavigation\"\n\tPrerenderFinalStatusSameSiteCrossOriginRedirectNotOptInInInitialNavigation     PrerenderFinalStatus = \"SameSiteCrossOriginRedirectNotOptInInInitialNavigation\"\n\tPrerenderFinalStatusSameSiteCrossOriginNavigationNotOptInInInitialNavigation   PrerenderFinalStatus = \"SameSiteCrossOriginNavigationNotOptInInInitialNavigation\"\n\tPrerenderFinalStatusActivationNavigationParameterMismatch                      PrerenderFinalStatus = \"ActivationNavigationParameterMismatch\"\n\tPrerenderFinalStatusActivatedInBackground                                      PrerenderFinalStatus = \"ActivatedInBackground\"\n\tPrerenderFinalStatusEmbedderHostDisallowed                                     PrerenderFinalStatus = \"EmbedderHostDisallowed\"\n\tPrerenderFinalStatusActivationNavigationDestroyedBeforeSuccess                 PrerenderFinalStatus = \"ActivationNavigationDestroyedBeforeSuccess\"\n\tPrerenderFinalStatusTabClosedByUserGesture                                     PrerenderFinalStatus = \"TabClosedByUserGesture\"\n\tPrerenderFinalStatusTabClosedWithoutUserGesture                                PrerenderFinalStatus = \"TabClosedWithoutUserGesture\"\n\tPrerenderFinalStatusPrimaryMainFrameRendererProcessCrashed                     PrerenderFinalStatus = \"PrimaryMainFrameRendererProcessCrashed\"\n\tPrerenderFinalStatusPrimaryMainFrameRendererProcessKilled                      PrerenderFinalStatus = \"PrimaryMainFrameRendererProcessKilled\"\n\tPrerenderFinalStatusActivationFramePolicyNotCompatible                         PrerenderFinalStatus = \"ActivationFramePolicyNotCompatible\"\n\tPrerenderFinalStatusPreloadingDisabled                                         PrerenderFinalStatus = \"PreloadingDisabled\"\n\tPrerenderFinalStatusBatterySaverEnabled                                        PrerenderFinalStatus = \"BatterySaverEnabled\"\n\tPrerenderFinalStatusActivatedDuringMainFrameNavigation                         PrerenderFinalStatus = \"ActivatedDuringMainFrameNavigation\"\n\tPrerenderFinalStatusPreloadingUnsupportedByWebContents                         PrerenderFinalStatus = \"PreloadingUnsupportedByWebContents\"\n\tPrerenderFinalStatusCrossSiteRedirectInMainFrameNavigation                     PrerenderFinalStatus = \"CrossSiteRedirectInMainFrameNavigation\"\n\tPrerenderFinalStatusCrossSiteNavigationInMainFrameNavigation                   PrerenderFinalStatus = \"CrossSiteNavigationInMainFrameNavigation\"\n\tPrerenderFinalStatusSameSiteCrossOriginRedirectNotOptInInMainFrameNavigation   PrerenderFinalStatus = \"SameSiteCrossOriginRedirectNotOptInInMainFrameNavigation\"\n\tPrerenderFinalStatusSameSiteCrossOriginNavigationNotOptInInMainFrameNavigation PrerenderFinalStatus = \"SameSiteCrossOriginNavigationNotOptInInMainFrameNavigation\"\n\tPrerenderFinalStatusMemoryPressureOnTrigger                                    PrerenderFinalStatus = \"MemoryPressureOnTrigger\"\n\tPrerenderFinalStatusMemoryPressureAfterTriggered                               PrerenderFinalStatus = \"MemoryPressureAfterTriggered\"\n\tPrerenderFinalStatusPrerenderingDisabledByDevTools                             PrerenderFinalStatus = \"PrerenderingDisabledByDevTools\"\n\tPrerenderFinalStatusSpeculationRuleRemoved                                     PrerenderFinalStatus = \"SpeculationRuleRemoved\"\n\tPrerenderFinalStatusActivatedWithAuxiliaryBrowsingContexts                     PrerenderFinalStatus = \"ActivatedWithAuxiliaryBrowsingContexts\"\n\tPrerenderFinalStatusMaxNumOfRunningEagerPrerendersExceeded                     PrerenderFinalStatus = \"MaxNumOfRunningEagerPrerendersExceeded\"\n\tPrerenderFinalStatusMaxNumOfRunningNonEagerPrerendersExceeded                  PrerenderFinalStatus = \"MaxNumOfRunningNonEagerPrerendersExceeded\"\n\tPrerenderFinalStatusMaxNumOfRunningEmbedderPrerendersExceeded                  PrerenderFinalStatus = \"MaxNumOfRunningEmbedderPrerendersExceeded\"\n\tPrerenderFinalStatusPrerenderingURLHasEffectiveURL                             PrerenderFinalStatus = \"PrerenderingUrlHasEffectiveUrl\"\n\tPrerenderFinalStatusRedirectedPrerenderingURLHasEffectiveURL                   PrerenderFinalStatus = \"RedirectedPrerenderingUrlHasEffectiveUrl\"\n\tPrerenderFinalStatusActivationURLHasEffectiveURL                               PrerenderFinalStatus = \"ActivationUrlHasEffectiveUrl\"\n\tPrerenderFinalStatusJavaScriptInterfaceAdded                                   PrerenderFinalStatus = \"JavaScriptInterfaceAdded\"\n\tPrerenderFinalStatusJavaScriptInterfaceRemoved                                 PrerenderFinalStatus = \"JavaScriptInterfaceRemoved\"\n\tPrerenderFinalStatusAllPrerenderingCanceled                                    PrerenderFinalStatus = \"AllPrerenderingCanceled\"\n\tPrerenderFinalStatusWindowClosed                                               PrerenderFinalStatus = \"WindowClosed\"\n\tPrerenderFinalStatusSlowNetwork                                                PrerenderFinalStatus = \"SlowNetwork\"\n\tPrerenderFinalStatusOtherPrerenderedPageActivated                              PrerenderFinalStatus = \"OtherPrerenderedPageActivated\"\n\tPrerenderFinalStatusV8optimizerDisabled                                        PrerenderFinalStatus = \"V8OptimizerDisabled\"\n\tPrerenderFinalStatusPrerenderFailedDuringPrefetch                              PrerenderFinalStatus = \"PrerenderFailedDuringPrefetch\"\n\tPrerenderFinalStatusBrowsingDataRemoved                                        PrerenderFinalStatus = \"BrowsingDataRemoved\"\n\tPrerenderFinalStatusPrerenderHostReused                                        PrerenderFinalStatus = \"PrerenderHostReused\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PrerenderFinalStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PrerenderFinalStatus(s) {\n\tcase PrerenderFinalStatusActivated:\n\t\t*t = PrerenderFinalStatusActivated\n\tcase PrerenderFinalStatusDestroyed:\n\t\t*t = PrerenderFinalStatusDestroyed\n\tcase PrerenderFinalStatusLowEndDevice:\n\t\t*t = PrerenderFinalStatusLowEndDevice\n\tcase PrerenderFinalStatusInvalidSchemeRedirect:\n\t\t*t = PrerenderFinalStatusInvalidSchemeRedirect\n\tcase PrerenderFinalStatusInvalidSchemeNavigation:\n\t\t*t = PrerenderFinalStatusInvalidSchemeNavigation\n\tcase PrerenderFinalStatusNavigationRequestBlockedByCsp:\n\t\t*t = PrerenderFinalStatusNavigationRequestBlockedByCsp\n\tcase PrerenderFinalStatusMojoBinderPolicy:\n\t\t*t = PrerenderFinalStatusMojoBinderPolicy\n\tcase PrerenderFinalStatusRendererProcessCrashed:\n\t\t*t = PrerenderFinalStatusRendererProcessCrashed\n\tcase PrerenderFinalStatusRendererProcessKilled:\n\t\t*t = PrerenderFinalStatusRendererProcessKilled\n\tcase PrerenderFinalStatusDownload:\n\t\t*t = PrerenderFinalStatusDownload\n\tcase PrerenderFinalStatusTriggerDestroyed:\n\t\t*t = PrerenderFinalStatusTriggerDestroyed\n\tcase PrerenderFinalStatusNavigationNotCommitted:\n\t\t*t = PrerenderFinalStatusNavigationNotCommitted\n\tcase PrerenderFinalStatusNavigationBadHTTPStatus:\n\t\t*t = PrerenderFinalStatusNavigationBadHTTPStatus\n\tcase PrerenderFinalStatusClientCertRequested:\n\t\t*t = PrerenderFinalStatusClientCertRequested\n\tcase PrerenderFinalStatusNavigationRequestNetworkError:\n\t\t*t = PrerenderFinalStatusNavigationRequestNetworkError\n\tcase PrerenderFinalStatusCancelAllHostsForTesting:\n\t\t*t = PrerenderFinalStatusCancelAllHostsForTesting\n\tcase PrerenderFinalStatusDidFailLoad:\n\t\t*t = PrerenderFinalStatusDidFailLoad\n\tcase PrerenderFinalStatusStop:\n\t\t*t = PrerenderFinalStatusStop\n\tcase PrerenderFinalStatusSslCertificateError:\n\t\t*t = PrerenderFinalStatusSslCertificateError\n\tcase PrerenderFinalStatusLoginAuthRequested:\n\t\t*t = PrerenderFinalStatusLoginAuthRequested\n\tcase PrerenderFinalStatusUaChangeRequiresReload:\n\t\t*t = PrerenderFinalStatusUaChangeRequiresReload\n\tcase PrerenderFinalStatusBlockedByClient:\n\t\t*t = PrerenderFinalStatusBlockedByClient\n\tcase PrerenderFinalStatusAudioOutputDeviceRequested:\n\t\t*t = PrerenderFinalStatusAudioOutputDeviceRequested\n\tcase PrerenderFinalStatusMixedContent:\n\t\t*t = PrerenderFinalStatusMixedContent\n\tcase PrerenderFinalStatusTriggerBackgrounded:\n\t\t*t = PrerenderFinalStatusTriggerBackgrounded\n\tcase PrerenderFinalStatusMemoryLimitExceeded:\n\t\t*t = PrerenderFinalStatusMemoryLimitExceeded\n\tcase PrerenderFinalStatusDataSaverEnabled:\n\t\t*t = PrerenderFinalStatusDataSaverEnabled\n\tcase PrerenderFinalStatusTriggerURLHasEffectiveURL:\n\t\t*t = PrerenderFinalStatusTriggerURLHasEffectiveURL\n\tcase PrerenderFinalStatusActivatedBeforeStarted:\n\t\t*t = PrerenderFinalStatusActivatedBeforeStarted\n\tcase PrerenderFinalStatusInactivePageRestriction:\n\t\t*t = PrerenderFinalStatusInactivePageRestriction\n\tcase PrerenderFinalStatusStartFailed:\n\t\t*t = PrerenderFinalStatusStartFailed\n\tcase PrerenderFinalStatusTimeoutBackgrounded:\n\t\t*t = PrerenderFinalStatusTimeoutBackgrounded\n\tcase PrerenderFinalStatusCrossSiteRedirectInInitialNavigation:\n\t\t*t = PrerenderFinalStatusCrossSiteRedirectInInitialNavigation\n\tcase PrerenderFinalStatusCrossSiteNavigationInInitialNavigation:\n\t\t*t = PrerenderFinalStatusCrossSiteNavigationInInitialNavigation\n\tcase PrerenderFinalStatusSameSiteCrossOriginRedirectNotOptInInInitialNavigation:\n\t\t*t = PrerenderFinalStatusSameSiteCrossOriginRedirectNotOptInInInitialNavigation\n\tcase PrerenderFinalStatusSameSiteCrossOriginNavigationNotOptInInInitialNavigation:\n\t\t*t = PrerenderFinalStatusSameSiteCrossOriginNavigationNotOptInInInitialNavigation\n\tcase PrerenderFinalStatusActivationNavigationParameterMismatch:\n\t\t*t = PrerenderFinalStatusActivationNavigationParameterMismatch\n\tcase PrerenderFinalStatusActivatedInBackground:\n\t\t*t = PrerenderFinalStatusActivatedInBackground\n\tcase PrerenderFinalStatusEmbedderHostDisallowed:\n\t\t*t = PrerenderFinalStatusEmbedderHostDisallowed\n\tcase PrerenderFinalStatusActivationNavigationDestroyedBeforeSuccess:\n\t\t*t = PrerenderFinalStatusActivationNavigationDestroyedBeforeSuccess\n\tcase PrerenderFinalStatusTabClosedByUserGesture:\n\t\t*t = PrerenderFinalStatusTabClosedByUserGesture\n\tcase PrerenderFinalStatusTabClosedWithoutUserGesture:\n\t\t*t = PrerenderFinalStatusTabClosedWithoutUserGesture\n\tcase PrerenderFinalStatusPrimaryMainFrameRendererProcessCrashed:\n\t\t*t = PrerenderFinalStatusPrimaryMainFrameRendererProcessCrashed\n\tcase PrerenderFinalStatusPrimaryMainFrameRendererProcessKilled:\n\t\t*t = PrerenderFinalStatusPrimaryMainFrameRendererProcessKilled\n\tcase PrerenderFinalStatusActivationFramePolicyNotCompatible:\n\t\t*t = PrerenderFinalStatusActivationFramePolicyNotCompatible\n\tcase PrerenderFinalStatusPreloadingDisabled:\n\t\t*t = PrerenderFinalStatusPreloadingDisabled\n\tcase PrerenderFinalStatusBatterySaverEnabled:\n\t\t*t = PrerenderFinalStatusBatterySaverEnabled\n\tcase PrerenderFinalStatusActivatedDuringMainFrameNavigation:\n\t\t*t = PrerenderFinalStatusActivatedDuringMainFrameNavigation\n\tcase PrerenderFinalStatusPreloadingUnsupportedByWebContents:\n\t\t*t = PrerenderFinalStatusPreloadingUnsupportedByWebContents\n\tcase PrerenderFinalStatusCrossSiteRedirectInMainFrameNavigation:\n\t\t*t = PrerenderFinalStatusCrossSiteRedirectInMainFrameNavigation\n\tcase PrerenderFinalStatusCrossSiteNavigationInMainFrameNavigation:\n\t\t*t = PrerenderFinalStatusCrossSiteNavigationInMainFrameNavigation\n\tcase PrerenderFinalStatusSameSiteCrossOriginRedirectNotOptInInMainFrameNavigation:\n\t\t*t = PrerenderFinalStatusSameSiteCrossOriginRedirectNotOptInInMainFrameNavigation\n\tcase PrerenderFinalStatusSameSiteCrossOriginNavigationNotOptInInMainFrameNavigation:\n\t\t*t = PrerenderFinalStatusSameSiteCrossOriginNavigationNotOptInInMainFrameNavigation\n\tcase PrerenderFinalStatusMemoryPressureOnTrigger:\n\t\t*t = PrerenderFinalStatusMemoryPressureOnTrigger\n\tcase PrerenderFinalStatusMemoryPressureAfterTriggered:\n\t\t*t = PrerenderFinalStatusMemoryPressureAfterTriggered\n\tcase PrerenderFinalStatusPrerenderingDisabledByDevTools:\n\t\t*t = PrerenderFinalStatusPrerenderingDisabledByDevTools\n\tcase PrerenderFinalStatusSpeculationRuleRemoved:\n\t\t*t = PrerenderFinalStatusSpeculationRuleRemoved\n\tcase PrerenderFinalStatusActivatedWithAuxiliaryBrowsingContexts:\n\t\t*t = PrerenderFinalStatusActivatedWithAuxiliaryBrowsingContexts\n\tcase PrerenderFinalStatusMaxNumOfRunningEagerPrerendersExceeded:\n\t\t*t = PrerenderFinalStatusMaxNumOfRunningEagerPrerendersExceeded\n\tcase PrerenderFinalStatusMaxNumOfRunningNonEagerPrerendersExceeded:\n\t\t*t = PrerenderFinalStatusMaxNumOfRunningNonEagerPrerendersExceeded\n\tcase PrerenderFinalStatusMaxNumOfRunningEmbedderPrerendersExceeded:\n\t\t*t = PrerenderFinalStatusMaxNumOfRunningEmbedderPrerendersExceeded\n\tcase PrerenderFinalStatusPrerenderingURLHasEffectiveURL:\n\t\t*t = PrerenderFinalStatusPrerenderingURLHasEffectiveURL\n\tcase PrerenderFinalStatusRedirectedPrerenderingURLHasEffectiveURL:\n\t\t*t = PrerenderFinalStatusRedirectedPrerenderingURLHasEffectiveURL\n\tcase PrerenderFinalStatusActivationURLHasEffectiveURL:\n\t\t*t = PrerenderFinalStatusActivationURLHasEffectiveURL\n\tcase PrerenderFinalStatusJavaScriptInterfaceAdded:\n\t\t*t = PrerenderFinalStatusJavaScriptInterfaceAdded\n\tcase PrerenderFinalStatusJavaScriptInterfaceRemoved:\n\t\t*t = PrerenderFinalStatusJavaScriptInterfaceRemoved\n\tcase PrerenderFinalStatusAllPrerenderingCanceled:\n\t\t*t = PrerenderFinalStatusAllPrerenderingCanceled\n\tcase PrerenderFinalStatusWindowClosed:\n\t\t*t = PrerenderFinalStatusWindowClosed\n\tcase PrerenderFinalStatusSlowNetwork:\n\t\t*t = PrerenderFinalStatusSlowNetwork\n\tcase PrerenderFinalStatusOtherPrerenderedPageActivated:\n\t\t*t = PrerenderFinalStatusOtherPrerenderedPageActivated\n\tcase PrerenderFinalStatusV8optimizerDisabled:\n\t\t*t = PrerenderFinalStatusV8optimizerDisabled\n\tcase PrerenderFinalStatusPrerenderFailedDuringPrefetch:\n\t\t*t = PrerenderFinalStatusPrerenderFailedDuringPrefetch\n\tcase PrerenderFinalStatusBrowsingDataRemoved:\n\t\t*t = PrerenderFinalStatusBrowsingDataRemoved\n\tcase PrerenderFinalStatusPrerenderHostReused:\n\t\t*t = PrerenderFinalStatusPrerenderHostReused\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PrerenderFinalStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// IngStatus preloading status values, see also PreloadingTriggeringOutcome.\n// This status is shared by prefetchStatusUpdated and prerenderStatusUpdated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-PreloadingStatus\ntype IngStatus string\n\n// String returns the IngStatus as string value.\nfunc (t IngStatus) String() string {\n\treturn string(t)\n}\n\n// IngStatus values.\nconst (\n\tIngStatusPending      IngStatus = \"Pending\"\n\tIngStatusRunning      IngStatus = \"Running\"\n\tIngStatusReady        IngStatus = \"Ready\"\n\tIngStatusSuccess      IngStatus = \"Success\"\n\tIngStatusFailure      IngStatus = \"Failure\"\n\tIngStatusNotSupported IngStatus = \"NotSupported\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *IngStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch IngStatus(s) {\n\tcase IngStatusPending:\n\t\t*t = IngStatusPending\n\tcase IngStatusRunning:\n\t\t*t = IngStatusRunning\n\tcase IngStatusReady:\n\t\t*t = IngStatusReady\n\tcase IngStatusSuccess:\n\t\t*t = IngStatusSuccess\n\tcase IngStatusFailure:\n\t\t*t = IngStatusFailure\n\tcase IngStatusNotSupported:\n\t\t*t = IngStatusNotSupported\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown IngStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PrefetchStatus tODO(https://crbug.com/1384419): revisit the list of\n// PrefetchStatus and filter out the ones that aren't necessary to the\n// developers.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-PrefetchStatus\ntype PrefetchStatus string\n\n// String returns the PrefetchStatus as string value.\nfunc (t PrefetchStatus) String() string {\n\treturn string(t)\n}\n\n// PrefetchStatus values.\nconst (\n\tPrefetchStatusPrefetchAllowed                                             PrefetchStatus = \"PrefetchAllowed\"\n\tPrefetchStatusPrefetchFailedIneligibleRedirect                            PrefetchStatus = \"PrefetchFailedIneligibleRedirect\"\n\tPrefetchStatusPrefetchFailedInvalidRedirect                               PrefetchStatus = \"PrefetchFailedInvalidRedirect\"\n\tPrefetchStatusPrefetchFailedMIMENotSupported                              PrefetchStatus = \"PrefetchFailedMIMENotSupported\"\n\tPrefetchStatusPrefetchFailedNetError                                      PrefetchStatus = \"PrefetchFailedNetError\"\n\tPrefetchStatusPrefetchFailedNon2xX                                        PrefetchStatus = \"PrefetchFailedNon2XX\"\n\tPrefetchStatusPrefetchEvictedAfterBrowsingDataRemoved                     PrefetchStatus = \"PrefetchEvictedAfterBrowsingDataRemoved\"\n\tPrefetchStatusPrefetchEvictedAfterCandidateRemoved                        PrefetchStatus = \"PrefetchEvictedAfterCandidateRemoved\"\n\tPrefetchStatusPrefetchEvictedForNewerPrefetch                             PrefetchStatus = \"PrefetchEvictedForNewerPrefetch\"\n\tPrefetchStatusPrefetchHeldback                                            PrefetchStatus = \"PrefetchHeldback\"\n\tPrefetchStatusPrefetchIneligibleRetryAfter                                PrefetchStatus = \"PrefetchIneligibleRetryAfter\"\n\tPrefetchStatusPrefetchIsPrivacyDecoy                                      PrefetchStatus = \"PrefetchIsPrivacyDecoy\"\n\tPrefetchStatusPrefetchIsStale                                             PrefetchStatus = \"PrefetchIsStale\"\n\tPrefetchStatusPrefetchNotEligibleBrowserContextOffTheRecord               PrefetchStatus = \"PrefetchNotEligibleBrowserContextOffTheRecord\"\n\tPrefetchStatusPrefetchNotEligibleDataSaverEnabled                         PrefetchStatus = \"PrefetchNotEligibleDataSaverEnabled\"\n\tPrefetchStatusPrefetchNotEligibleExistingProxy                            PrefetchStatus = \"PrefetchNotEligibleExistingProxy\"\n\tPrefetchStatusPrefetchNotEligibleHostIsNonUnique                          PrefetchStatus = \"PrefetchNotEligibleHostIsNonUnique\"\n\tPrefetchStatusPrefetchNotEligibleNonDefaultStoragePartition               PrefetchStatus = \"PrefetchNotEligibleNonDefaultStoragePartition\"\n\tPrefetchStatusPrefetchNotEligibleSameSiteCrossOriginPrefetchRequiredProxy PrefetchStatus = \"PrefetchNotEligibleSameSiteCrossOriginPrefetchRequiredProxy\"\n\tPrefetchStatusPrefetchNotEligibleSchemeIsNotHTTPS                         PrefetchStatus = \"PrefetchNotEligibleSchemeIsNotHttps\"\n\tPrefetchStatusPrefetchNotEligibleUserHasCookies                           PrefetchStatus = \"PrefetchNotEligibleUserHasCookies\"\n\tPrefetchStatusPrefetchNotEligibleUserHasServiceWorker                     PrefetchStatus = \"PrefetchNotEligibleUserHasServiceWorker\"\n\tPrefetchStatusPrefetchNotEligibleUserHasServiceWorkerNoFetchHandler       PrefetchStatus = \"PrefetchNotEligibleUserHasServiceWorkerNoFetchHandler\"\n\tPrefetchStatusPrefetchNotEligibleRedirectFromServiceWorker                PrefetchStatus = \"PrefetchNotEligibleRedirectFromServiceWorker\"\n\tPrefetchStatusPrefetchNotEligibleRedirectToServiceWorker                  PrefetchStatus = \"PrefetchNotEligibleRedirectToServiceWorker\"\n\tPrefetchStatusPrefetchNotEligibleBatterySaverEnabled                      PrefetchStatus = \"PrefetchNotEligibleBatterySaverEnabled\"\n\tPrefetchStatusPrefetchNotEligiblePreloadingDisabled                       PrefetchStatus = \"PrefetchNotEligiblePreloadingDisabled\"\n\tPrefetchStatusPrefetchNotFinishedInTime                                   PrefetchStatus = \"PrefetchNotFinishedInTime\"\n\tPrefetchStatusPrefetchNotStarted                                          PrefetchStatus = \"PrefetchNotStarted\"\n\tPrefetchStatusPrefetchNotUsedCookiesChanged                               PrefetchStatus = \"PrefetchNotUsedCookiesChanged\"\n\tPrefetchStatusPrefetchProxyNotAvailable                                   PrefetchStatus = \"PrefetchProxyNotAvailable\"\n\tPrefetchStatusPrefetchResponseUsed                                        PrefetchStatus = \"PrefetchResponseUsed\"\n\tPrefetchStatusPrefetchSuccessfulButNotUsed                                PrefetchStatus = \"PrefetchSuccessfulButNotUsed\"\n\tPrefetchStatusPrefetchNotUsedProbeFailed                                  PrefetchStatus = \"PrefetchNotUsedProbeFailed\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *PrefetchStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch PrefetchStatus(s) {\n\tcase PrefetchStatusPrefetchAllowed:\n\t\t*t = PrefetchStatusPrefetchAllowed\n\tcase PrefetchStatusPrefetchFailedIneligibleRedirect:\n\t\t*t = PrefetchStatusPrefetchFailedIneligibleRedirect\n\tcase PrefetchStatusPrefetchFailedInvalidRedirect:\n\t\t*t = PrefetchStatusPrefetchFailedInvalidRedirect\n\tcase PrefetchStatusPrefetchFailedMIMENotSupported:\n\t\t*t = PrefetchStatusPrefetchFailedMIMENotSupported\n\tcase PrefetchStatusPrefetchFailedNetError:\n\t\t*t = PrefetchStatusPrefetchFailedNetError\n\tcase PrefetchStatusPrefetchFailedNon2xX:\n\t\t*t = PrefetchStatusPrefetchFailedNon2xX\n\tcase PrefetchStatusPrefetchEvictedAfterBrowsingDataRemoved:\n\t\t*t = PrefetchStatusPrefetchEvictedAfterBrowsingDataRemoved\n\tcase PrefetchStatusPrefetchEvictedAfterCandidateRemoved:\n\t\t*t = PrefetchStatusPrefetchEvictedAfterCandidateRemoved\n\tcase PrefetchStatusPrefetchEvictedForNewerPrefetch:\n\t\t*t = PrefetchStatusPrefetchEvictedForNewerPrefetch\n\tcase PrefetchStatusPrefetchHeldback:\n\t\t*t = PrefetchStatusPrefetchHeldback\n\tcase PrefetchStatusPrefetchIneligibleRetryAfter:\n\t\t*t = PrefetchStatusPrefetchIneligibleRetryAfter\n\tcase PrefetchStatusPrefetchIsPrivacyDecoy:\n\t\t*t = PrefetchStatusPrefetchIsPrivacyDecoy\n\tcase PrefetchStatusPrefetchIsStale:\n\t\t*t = PrefetchStatusPrefetchIsStale\n\tcase PrefetchStatusPrefetchNotEligibleBrowserContextOffTheRecord:\n\t\t*t = PrefetchStatusPrefetchNotEligibleBrowserContextOffTheRecord\n\tcase PrefetchStatusPrefetchNotEligibleDataSaverEnabled:\n\t\t*t = PrefetchStatusPrefetchNotEligibleDataSaverEnabled\n\tcase PrefetchStatusPrefetchNotEligibleExistingProxy:\n\t\t*t = PrefetchStatusPrefetchNotEligibleExistingProxy\n\tcase PrefetchStatusPrefetchNotEligibleHostIsNonUnique:\n\t\t*t = PrefetchStatusPrefetchNotEligibleHostIsNonUnique\n\tcase PrefetchStatusPrefetchNotEligibleNonDefaultStoragePartition:\n\t\t*t = PrefetchStatusPrefetchNotEligibleNonDefaultStoragePartition\n\tcase PrefetchStatusPrefetchNotEligibleSameSiteCrossOriginPrefetchRequiredProxy:\n\t\t*t = PrefetchStatusPrefetchNotEligibleSameSiteCrossOriginPrefetchRequiredProxy\n\tcase PrefetchStatusPrefetchNotEligibleSchemeIsNotHTTPS:\n\t\t*t = PrefetchStatusPrefetchNotEligibleSchemeIsNotHTTPS\n\tcase PrefetchStatusPrefetchNotEligibleUserHasCookies:\n\t\t*t = PrefetchStatusPrefetchNotEligibleUserHasCookies\n\tcase PrefetchStatusPrefetchNotEligibleUserHasServiceWorker:\n\t\t*t = PrefetchStatusPrefetchNotEligibleUserHasServiceWorker\n\tcase PrefetchStatusPrefetchNotEligibleUserHasServiceWorkerNoFetchHandler:\n\t\t*t = PrefetchStatusPrefetchNotEligibleUserHasServiceWorkerNoFetchHandler\n\tcase PrefetchStatusPrefetchNotEligibleRedirectFromServiceWorker:\n\t\t*t = PrefetchStatusPrefetchNotEligibleRedirectFromServiceWorker\n\tcase PrefetchStatusPrefetchNotEligibleRedirectToServiceWorker:\n\t\t*t = PrefetchStatusPrefetchNotEligibleRedirectToServiceWorker\n\tcase PrefetchStatusPrefetchNotEligibleBatterySaverEnabled:\n\t\t*t = PrefetchStatusPrefetchNotEligibleBatterySaverEnabled\n\tcase PrefetchStatusPrefetchNotEligiblePreloadingDisabled:\n\t\t*t = PrefetchStatusPrefetchNotEligiblePreloadingDisabled\n\tcase PrefetchStatusPrefetchNotFinishedInTime:\n\t\t*t = PrefetchStatusPrefetchNotFinishedInTime\n\tcase PrefetchStatusPrefetchNotStarted:\n\t\t*t = PrefetchStatusPrefetchNotStarted\n\tcase PrefetchStatusPrefetchNotUsedCookiesChanged:\n\t\t*t = PrefetchStatusPrefetchNotUsedCookiesChanged\n\tcase PrefetchStatusPrefetchProxyNotAvailable:\n\t\t*t = PrefetchStatusPrefetchProxyNotAvailable\n\tcase PrefetchStatusPrefetchResponseUsed:\n\t\t*t = PrefetchStatusPrefetchResponseUsed\n\tcase PrefetchStatusPrefetchSuccessfulButNotUsed:\n\t\t*t = PrefetchStatusPrefetchSuccessfulButNotUsed\n\tcase PrefetchStatusPrefetchNotUsedProbeFailed:\n\t\t*t = PrefetchStatusPrefetchNotUsedProbeFailed\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown PrefetchStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// PrerenderMismatchedHeaders information of headers to be displayed when the\n// header mismatch occurred.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Preload#type-PrerenderMismatchedHeaders\ntype PrerenderMismatchedHeaders struct {\n\tHeaderName      string `json:\"headerName\"`\n\tInitialValue    string `json:\"initialValue,omitempty,omitzero\"`\n\tActivationValue string `json:\"activationValue,omitempty,omitzero\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/profiler/events.go",
    "content": "package profiler\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/debugger\"\n)\n\n// EventConsoleProfileFinished [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#event-consoleProfileFinished\ntype EventConsoleProfileFinished struct {\n\tID       string             `json:\"id\"`\n\tLocation *debugger.Location `json:\"location\"` // Location of console.profileEnd().\n\tProfile  *Profile           `json:\"profile\"`\n\tTitle    string             `json:\"title,omitempty,omitzero\"` // Profile title passed as an argument to console.profile().\n}\n\n// EventConsoleProfileStarted sent when new profile recording is started\n// using console.profile() call.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#event-consoleProfileStarted\ntype EventConsoleProfileStarted struct {\n\tID       string             `json:\"id\"`\n\tLocation *debugger.Location `json:\"location\"`                 // Location of console.profile().\n\tTitle    string             `json:\"title,omitempty,omitzero\"` // Profile title passed as an argument to console.profile().\n}\n\n// EventPreciseCoverageDeltaUpdate reports coverage delta since the last poll\n// (either from an event like this, or from takePreciseCoverage for the current\n// isolate. May only be sent if precise code coverage has been started. This\n// event can be trigged by the embedder to, for example, trigger collection of\n// coverage data immediately at a certain point in time.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#event-preciseCoverageDeltaUpdate\ntype EventPreciseCoverageDeltaUpdate struct {\n\tTimestamp float64           `json:\"timestamp\"` // Monotonically increasing time (in seconds) when the coverage update was taken in the backend.\n\tOccasion  string            `json:\"occasion\"`  // Identifier for distinguishing coverage events.\n\tResult    []*ScriptCoverage `json:\"result\"`    // Coverage data for the current isolate.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/profiler/profiler.go",
    "content": "// Package profiler provides the Chrome DevTools Protocol\n// commands, types, and events for the Profiler domain.\n//\n// Generated by the cdproto-gen command.\npackage profiler\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// DisableParams [no description].\ntype DisableParams struct{}\n\n// Disable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Profiler.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams [no description].\ntype EnableParams struct{}\n\n// Enable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Profiler.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// GetBestEffortCoverageParams collect coverage data for the current isolate.\n// The coverage data may be incomplete due to garbage collection.\ntype GetBestEffortCoverageParams struct{}\n\n// GetBestEffortCoverage collect coverage data for the current isolate. The\n// coverage data may be incomplete due to garbage collection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-getBestEffortCoverage\nfunc GetBestEffortCoverage() *GetBestEffortCoverageParams {\n\treturn &GetBestEffortCoverageParams{}\n}\n\n// GetBestEffortCoverageReturns return values.\ntype GetBestEffortCoverageReturns struct {\n\tResult []*ScriptCoverage `json:\"result,omitempty,omitzero\"` // Coverage data for the current isolate.\n}\n\n// Do executes Profiler.getBestEffortCoverage against the provided context.\n//\n// returns:\n//\n//\tresult - Coverage data for the current isolate.\nfunc (p *GetBestEffortCoverageParams) Do(ctx context.Context) (result []*ScriptCoverage, err error) {\n\t// execute\n\tvar res GetBestEffortCoverageReturns\n\terr = cdp.Execute(ctx, CommandGetBestEffortCoverage, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Result, nil\n}\n\n// SetSamplingIntervalParams changes CPU profiler sampling interval. Must be\n// called before CPU profiles recording started.\ntype SetSamplingIntervalParams struct {\n\tInterval int64 `json:\"interval\"` // New sampling interval in microseconds.\n}\n\n// SetSamplingInterval changes CPU profiler sampling interval. Must be called\n// before CPU profiles recording started.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-setSamplingInterval\n//\n// parameters:\n//\n//\tinterval - New sampling interval in microseconds.\nfunc SetSamplingInterval(interval int64) *SetSamplingIntervalParams {\n\treturn &SetSamplingIntervalParams{\n\t\tInterval: interval,\n\t}\n}\n\n// Do executes Profiler.setSamplingInterval against the provided context.\nfunc (p *SetSamplingIntervalParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSamplingInterval, p, nil)\n}\n\n// StartParams [no description].\ntype StartParams struct{}\n\n// Start [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-start\nfunc Start() *StartParams {\n\treturn &StartParams{}\n}\n\n// Do executes Profiler.start against the provided context.\nfunc (p *StartParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStart, nil, nil)\n}\n\n// StartPreciseCoverageParams enable precise code coverage. Coverage data for\n// JavaScript executed before enabling precise code coverage may be incomplete.\n// Enabling prevents running optimized code and resets execution counters.\ntype StartPreciseCoverageParams struct {\n\tCallCount             bool `json:\"callCount\"`             // Collect accurate call counts beyond simple 'covered' or 'not covered'.\n\tDetailed              bool `json:\"detailed\"`              // Collect block-based coverage.\n\tAllowTriggeredUpdates bool `json:\"allowTriggeredUpdates\"` // Allow the backend to send updates on its own initiative\n}\n\n// StartPreciseCoverage enable precise code coverage. Coverage data for\n// JavaScript executed before enabling precise code coverage may be incomplete.\n// Enabling prevents running optimized code and resets execution counters.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-startPreciseCoverage\n//\n// parameters:\nfunc StartPreciseCoverage() *StartPreciseCoverageParams {\n\treturn &StartPreciseCoverageParams{\n\t\tCallCount:             false,\n\t\tDetailed:              false,\n\t\tAllowTriggeredUpdates: false,\n\t}\n}\n\n// WithCallCount collect accurate call counts beyond simple 'covered' or 'not\n// covered'.\nfunc (p StartPreciseCoverageParams) WithCallCount(callCount bool) *StartPreciseCoverageParams {\n\tp.CallCount = callCount\n\treturn &p\n}\n\n// WithDetailed collect block-based coverage.\nfunc (p StartPreciseCoverageParams) WithDetailed(detailed bool) *StartPreciseCoverageParams {\n\tp.Detailed = detailed\n\treturn &p\n}\n\n// WithAllowTriggeredUpdates allow the backend to send updates on its own\n// initiative.\nfunc (p StartPreciseCoverageParams) WithAllowTriggeredUpdates(allowTriggeredUpdates bool) *StartPreciseCoverageParams {\n\tp.AllowTriggeredUpdates = allowTriggeredUpdates\n\treturn &p\n}\n\n// StartPreciseCoverageReturns return values.\ntype StartPreciseCoverageReturns struct {\n\tTimestamp float64 `json:\"timestamp,omitempty,omitzero\"` // Monotonically increasing time (in seconds) when the coverage update was taken in the backend.\n}\n\n// Do executes Profiler.startPreciseCoverage against the provided context.\n//\n// returns:\n//\n//\ttimestamp - Monotonically increasing time (in seconds) when the coverage update was taken in the backend.\nfunc (p *StartPreciseCoverageParams) Do(ctx context.Context) (timestamp float64, err error) {\n\t// execute\n\tvar res StartPreciseCoverageReturns\n\terr = cdp.Execute(ctx, CommandStartPreciseCoverage, p, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.Timestamp, nil\n}\n\n// StopParams [no description].\ntype StopParams struct{}\n\n// Stop [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-stop\nfunc Stop() *StopParams {\n\treturn &StopParams{}\n}\n\n// StopReturns return values.\ntype StopReturns struct {\n\tProfile *Profile `json:\"profile,omitempty,omitzero\"` // Recorded profile.\n}\n\n// Do executes Profiler.stop against the provided context.\n//\n// returns:\n//\n//\tprofile - Recorded profile.\nfunc (p *StopParams) Do(ctx context.Context) (profile *Profile, err error) {\n\t// execute\n\tvar res StopReturns\n\terr = cdp.Execute(ctx, CommandStop, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Profile, nil\n}\n\n// StopPreciseCoverageParams disable precise code coverage. Disabling\n// releases unnecessary execution count records and allows executing optimized\n// code.\ntype StopPreciseCoverageParams struct{}\n\n// StopPreciseCoverage disable precise code coverage. Disabling releases\n// unnecessary execution count records and allows executing optimized code.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-stopPreciseCoverage\nfunc StopPreciseCoverage() *StopPreciseCoverageParams {\n\treturn &StopPreciseCoverageParams{}\n}\n\n// Do executes Profiler.stopPreciseCoverage against the provided context.\nfunc (p *StopPreciseCoverageParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopPreciseCoverage, nil, nil)\n}\n\n// TakePreciseCoverageParams collect coverage data for the current isolate,\n// and resets execution counters. Precise code coverage needs to have started.\ntype TakePreciseCoverageParams struct{}\n\n// TakePreciseCoverage collect coverage data for the current isolate, and\n// resets execution counters. Precise code coverage needs to have started.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#method-takePreciseCoverage\nfunc TakePreciseCoverage() *TakePreciseCoverageParams {\n\treturn &TakePreciseCoverageParams{}\n}\n\n// TakePreciseCoverageReturns return values.\ntype TakePreciseCoverageReturns struct {\n\tResult    []*ScriptCoverage `json:\"result,omitempty,omitzero\"`    // Coverage data for the current isolate.\n\tTimestamp float64           `json:\"timestamp,omitempty,omitzero\"` // Monotonically increasing time (in seconds) when the coverage update was taken in the backend.\n}\n\n// Do executes Profiler.takePreciseCoverage against the provided context.\n//\n// returns:\n//\n//\tresult - Coverage data for the current isolate.\n//\ttimestamp - Monotonically increasing time (in seconds) when the coverage update was taken in the backend.\nfunc (p *TakePreciseCoverageParams) Do(ctx context.Context) (result []*ScriptCoverage, timestamp float64, err error) {\n\t// execute\n\tvar res TakePreciseCoverageReturns\n\terr = cdp.Execute(ctx, CommandTakePreciseCoverage, nil, &res)\n\tif err != nil {\n\t\treturn nil, 0, err\n\t}\n\n\treturn res.Result, res.Timestamp, nil\n}\n\n// Command names.\nconst (\n\tCommandDisable               = \"Profiler.disable\"\n\tCommandEnable                = \"Profiler.enable\"\n\tCommandGetBestEffortCoverage = \"Profiler.getBestEffortCoverage\"\n\tCommandSetSamplingInterval   = \"Profiler.setSamplingInterval\"\n\tCommandStart                 = \"Profiler.start\"\n\tCommandStartPreciseCoverage  = \"Profiler.startPreciseCoverage\"\n\tCommandStop                  = \"Profiler.stop\"\n\tCommandStopPreciseCoverage   = \"Profiler.stopPreciseCoverage\"\n\tCommandTakePreciseCoverage   = \"Profiler.takePreciseCoverage\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/profiler/types.go",
    "content": "package profiler\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/runtime\"\n)\n\n// ProfileNode profile node. Holds callsite information, execution statistics\n// and child nodes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ProfileNode\ntype ProfileNode struct {\n\tID            int64               `json:\"id\"`                               // Unique id of the node.\n\tCallFrame     *runtime.CallFrame  `json:\"callFrame\"`                        // Function location.\n\tHitCount      int64               `json:\"hitCount,omitempty,omitzero\"`      // Number of samples where this node was on top of the call stack.\n\tChildren      []int64             `json:\"children,omitempty,omitzero\"`      // Child node ids.\n\tDeoptReason   string              `json:\"deoptReason,omitempty,omitzero\"`   // The reason of being not optimized. The function may be deoptimized or marked as don't optimize.\n\tPositionTicks []*PositionTickInfo `json:\"positionTicks,omitempty,omitzero\"` // An array of source position ticks.\n}\n\n// Profile Profile.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-Profile\ntype Profile struct {\n\tNodes      []*ProfileNode `json:\"nodes\"`                         // The list of profile nodes. First item is the root node.\n\tStartTime  float64        `json:\"startTime\"`                     // Profiling start timestamp in microseconds.\n\tEndTime    float64        `json:\"endTime\"`                       // Profiling end timestamp in microseconds.\n\tSamples    []int64        `json:\"samples,omitempty,omitzero\"`    // Ids of samples top nodes.\n\tTimeDeltas []int64        `json:\"timeDeltas,omitempty,omitzero\"` // Time intervals between adjacent samples in microseconds. The first delta is relative to the profile startTime.\n}\n\n// PositionTickInfo specifies a number of samples attributed to a certain\n// source position.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-PositionTickInfo\ntype PositionTickInfo struct {\n\tLine  int64 `json:\"line\"`  // Source line number (1-based).\n\tTicks int64 `json:\"ticks\"` // Number of samples attributed to the source line.\n}\n\n// CoverageRange coverage data for a source range.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-CoverageRange\ntype CoverageRange struct {\n\tStartOffset int64 `json:\"startOffset\"` // JavaScript script source offset for the range start.\n\tEndOffset   int64 `json:\"endOffset\"`   // JavaScript script source offset for the range end.\n\tCount       int64 `json:\"count\"`       // Collected execution count of the source range.\n}\n\n// FunctionCoverage coverage data for a JavaScript function.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-FunctionCoverage\ntype FunctionCoverage struct {\n\tFunctionName    string           `json:\"functionName\"`    // JavaScript function name.\n\tRanges          []*CoverageRange `json:\"ranges\"`          // Source ranges inside the function with coverage data.\n\tIsBlockCoverage bool             `json:\"isBlockCoverage\"` // Whether coverage data for this function has block granularity.\n}\n\n// ScriptCoverage coverage data for a JavaScript script.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ScriptCoverage\ntype ScriptCoverage struct {\n\tScriptID  runtime.ScriptID    `json:\"scriptId\"`  // JavaScript script id.\n\tURL       string              `json:\"url\"`       // JavaScript script name or url.\n\tFunctions []*FunctionCoverage `json:\"functions\"` // Functions contained in the script that has coverage data.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/pwa/pwa.go",
    "content": "// Package pwa provides the Chrome DevTools Protocol\n// commands, types, and events for the PWA domain.\n//\n// This domain allows interacting with the browser to control PWAs.\n//\n// Generated by the cdproto-gen command.\npackage pwa\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/target\"\n)\n\n// GetOsAppStateParams returns the following OS state for the given manifest\n// id.\ntype GetOsAppStateParams struct {\n\tManifestID string `json:\"manifestId\"` // The id from the webapp's manifest file, commonly it's the url of the site installing the webapp. See https://web.dev/learn/pwa/web-app-manifest.\n}\n\n// GetOsAppState returns the following OS state for the given manifest id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#method-getOsAppState\n//\n// parameters:\n//\n//\tmanifestID - The id from the webapp's manifest file, commonly it's the url of the site installing the webapp. See https://web.dev/learn/pwa/web-app-manifest.\nfunc GetOsAppState(manifestID string) *GetOsAppStateParams {\n\treturn &GetOsAppStateParams{\n\t\tManifestID: manifestID,\n\t}\n}\n\n// GetOsAppStateReturns return values.\ntype GetOsAppStateReturns struct {\n\tBadgeCount   int64          `json:\"badgeCount,omitempty,omitzero\"`\n\tFileHandlers []*FileHandler `json:\"fileHandlers,omitempty,omitzero\"`\n}\n\n// Do executes PWA.getOsAppState against the provided context.\n//\n// returns:\n//\n//\tbadgeCount\n//\tfileHandlers\nfunc (p *GetOsAppStateParams) Do(ctx context.Context) (badgeCount int64, fileHandlers []*FileHandler, err error) {\n\t// execute\n\tvar res GetOsAppStateReturns\n\terr = cdp.Execute(ctx, CommandGetOsAppState, p, &res)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\n\treturn res.BadgeCount, res.FileHandlers, nil\n}\n\n// InstallParams installs the given manifest identity, optionally using the\n// given installUrlOrBundleUrl IWA-specific install description: manifestId\n// corresponds to isolated-app:// + web_package::SignedWebBundleId File\n// installation mode: The installUrlOrBundleUrl can be either file:// or\n// http(s):// pointing to a signed web bundle (.swbn). In this case\n// SignedWebBundleId must correspond to The .swbn file's signing key. Dev proxy\n// installation mode: installUrlOrBundleUrl must be http(s):// that serves dev\n// mode IWA. web_package::SignedWebBundleId must be of type dev proxy. The\n// advantage of dev proxy mode is that all changes to IWA automatically will be\n// reflected in the running app without reinstallation. To generate bundle id\n// for proxy mode: 1. Generate 32 random bytes. 2. Add a specific suffix 0x00 at\n// the end. 3. Encode the entire sequence using Base32 without padding. If\n// Chrome is not in IWA dev mode, the installation will fail, regardless of the\n// state of the allowlist.\ntype InstallParams struct {\n\tManifestID            string `json:\"manifestId\"`\n\tInstallURLOrBundleURL string `json:\"installUrlOrBundleUrl,omitempty,omitzero\"` // The location of the app or bundle overriding the one derived from the manifestId.\n}\n\n// Install installs the given manifest identity, optionally using the given\n// installUrlOrBundleUrl IWA-specific install description: manifestId\n// corresponds to isolated-app:// + web_package::SignedWebBundleId File\n// installation mode: The installUrlOrBundleUrl can be either file:// or\n// http(s):// pointing to a signed web bundle (.swbn). In this case\n// SignedWebBundleId must correspond to The .swbn file's signing key. Dev proxy\n// installation mode: installUrlOrBundleUrl must be http(s):// that serves dev\n// mode IWA. web_package::SignedWebBundleId must be of type dev proxy. The\n// advantage of dev proxy mode is that all changes to IWA automatically will be\n// reflected in the running app without reinstallation. To generate bundle id\n// for proxy mode: 1. Generate 32 random bytes. 2. Add a specific suffix 0x00 at\n// the end. 3. Encode the entire sequence using Base32 without padding. If\n// Chrome is not in IWA dev mode, the installation will fail, regardless of the\n// state of the allowlist.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#method-install\n//\n// parameters:\n//\n//\tmanifestID\nfunc Install(manifestID string) *InstallParams {\n\treturn &InstallParams{\n\t\tManifestID: manifestID,\n\t}\n}\n\n// WithInstallURLOrBundleURL the location of the app or bundle overriding the\n// one derived from the manifestId.\nfunc (p InstallParams) WithInstallURLOrBundleURL(installURLOrBundleURL string) *InstallParams {\n\tp.InstallURLOrBundleURL = installURLOrBundleURL\n\treturn &p\n}\n\n// Do executes PWA.install against the provided context.\nfunc (p *InstallParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandInstall, p, nil)\n}\n\n// UninstallParams uninstalls the given manifest_id and closes any opened app\n// windows.\ntype UninstallParams struct {\n\tManifestID string `json:\"manifestId\"`\n}\n\n// Uninstall uninstalls the given manifest_id and closes any opened app\n// windows.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#method-uninstall\n//\n// parameters:\n//\n//\tmanifestID\nfunc Uninstall(manifestID string) *UninstallParams {\n\treturn &UninstallParams{\n\t\tManifestID: manifestID,\n\t}\n}\n\n// Do executes PWA.uninstall against the provided context.\nfunc (p *UninstallParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUninstall, p, nil)\n}\n\n// LaunchParams launches the installed web app, or an url in the same web app\n// instead of the default start url if it is provided. Returns a page\n// Target.TargetID which can be used to attach to via Target.attachToTarget or\n// similar APIs.\ntype LaunchParams struct {\n\tManifestID string `json:\"manifestId\"`\n\tURL        string `json:\"url,omitempty,omitzero\"`\n}\n\n// Launch launches the installed web app, or an url in the same web app\n// instead of the default start url if it is provided. Returns a page\n// Target.TargetID which can be used to attach to via Target.attachToTarget or\n// similar APIs.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#method-launch\n//\n// parameters:\n//\n//\tmanifestID\nfunc Launch(manifestID string) *LaunchParams {\n\treturn &LaunchParams{\n\t\tManifestID: manifestID,\n\t}\n}\n\n// WithURL [no description].\nfunc (p LaunchParams) WithURL(url string) *LaunchParams {\n\tp.URL = url\n\treturn &p\n}\n\n// LaunchReturns return values.\ntype LaunchReturns struct {\n\tTargetID target.ID `json:\"targetId,omitempty,omitzero\"` // ID of the tab target created as a result.\n}\n\n// Do executes PWA.launch against the provided context.\n//\n// returns:\n//\n//\ttargetID - ID of the tab target created as a result.\nfunc (p *LaunchParams) Do(ctx context.Context) (targetID target.ID, err error) {\n\t// execute\n\tvar res LaunchReturns\n\terr = cdp.Execute(ctx, CommandLaunch, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.TargetID, nil\n}\n\n// LaunchFilesInAppParams opens one or more local files from an installed web\n// app identified by its manifestId. The web app needs to have file handlers\n// registered to process the files. The API returns one or more page\n// Target.TargetIDs which can be used to attach to via Target.attachToTarget or\n// similar APIs. If some files in the parameters cannot be handled by the web\n// app, they will be ignored. If none of the files can be handled, this API\n// returns an error. If no files are provided as the parameter, this API also\n// returns an error. According to the definition of the file handlers in the\n// manifest file, one Target.TargetID may represent a page handling one or more\n// files. The order of the returned Target.TargetIDs is not guaranteed.\n// TODO(crbug.com/339454034): Check the existences of the input files.\ntype LaunchFilesInAppParams struct {\n\tManifestID string   `json:\"manifestId\"`\n\tFiles      []string `json:\"files\"`\n}\n\n// LaunchFilesInApp opens one or more local files from an installed web app\n// identified by its manifestId. The web app needs to have file handlers\n// registered to process the files. The API returns one or more page\n// Target.TargetIDs which can be used to attach to via Target.attachToTarget or\n// similar APIs. If some files in the parameters cannot be handled by the web\n// app, they will be ignored. If none of the files can be handled, this API\n// returns an error. If no files are provided as the parameter, this API also\n// returns an error. According to the definition of the file handlers in the\n// manifest file, one Target.TargetID may represent a page handling one or more\n// files. The order of the returned Target.TargetIDs is not guaranteed.\n// TODO(crbug.com/339454034): Check the existences of the input files.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#method-launchFilesInApp\n//\n// parameters:\n//\n//\tmanifestID\n//\tfiles\nfunc LaunchFilesInApp(manifestID string, files []string) *LaunchFilesInAppParams {\n\treturn &LaunchFilesInAppParams{\n\t\tManifestID: manifestID,\n\t\tFiles:      files,\n\t}\n}\n\n// LaunchFilesInAppReturns return values.\ntype LaunchFilesInAppReturns struct {\n\tTargetIDs []target.ID `json:\"targetIds,omitempty,omitzero\"` // IDs of the tab targets created as the result.\n}\n\n// Do executes PWA.launchFilesInApp against the provided context.\n//\n// returns:\n//\n//\ttargetIDs - IDs of the tab targets created as the result.\nfunc (p *LaunchFilesInAppParams) Do(ctx context.Context) (targetIDs []target.ID, err error) {\n\t// execute\n\tvar res LaunchFilesInAppReturns\n\terr = cdp.Execute(ctx, CommandLaunchFilesInApp, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.TargetIDs, nil\n}\n\n// OpenCurrentPageInAppParams opens the current page in its web app\n// identified by the manifest id, needs to be called on a page target. This\n// function returns immediately without waiting for the app to finish loading.\ntype OpenCurrentPageInAppParams struct {\n\tManifestID string `json:\"manifestId\"`\n}\n\n// OpenCurrentPageInApp opens the current page in its web app identified by\n// the manifest id, needs to be called on a page target. This function returns\n// immediately without waiting for the app to finish loading.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#method-openCurrentPageInApp\n//\n// parameters:\n//\n//\tmanifestID\nfunc OpenCurrentPageInApp(manifestID string) *OpenCurrentPageInAppParams {\n\treturn &OpenCurrentPageInAppParams{\n\t\tManifestID: manifestID,\n\t}\n}\n\n// Do executes PWA.openCurrentPageInApp against the provided context.\nfunc (p *OpenCurrentPageInAppParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandOpenCurrentPageInApp, p, nil)\n}\n\n// ChangeAppUserSettingsParams changes user settings of the web app\n// identified by its manifestId. If the app was not installed, this command\n// returns an error. Unset parameters will be ignored; unrecognized values will\n// cause an error. Unlike the ones defined in the manifest files of the web\n// apps, these settings are provided by the browser and controlled by the users,\n// they impact the way the browser handling the web apps. See the comment of\n// each parameter.\ntype ChangeAppUserSettingsParams struct {\n\tManifestID    string      `json:\"manifestId\"`\n\tLinkCapturing bool        `json:\"linkCapturing\"` // If user allows the links clicked on by the user in the app's scope, or extended scope if the manifest has scope extensions and the flags DesktopPWAsLinkCapturingWithScopeExtensions and WebAppEnableScopeExtensions are enabled.  Note, the API does not support resetting the linkCapturing to the initial value, uninstalling and installing the web app again will reset it.  TODO(crbug.com/339453269): Setting this value on ChromeOS is not supported yet.\n\tDisplayMode   DisplayMode `json:\"displayMode,omitempty,omitzero\"`\n}\n\n// ChangeAppUserSettings changes user settings of the web app identified by\n// its manifestId. If the app was not installed, this command returns an error.\n// Unset parameters will be ignored; unrecognized values will cause an error.\n// Unlike the ones defined in the manifest files of the web apps, these settings\n// are provided by the browser and controlled by the users, they impact the way\n// the browser handling the web apps. See the comment of each parameter.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#method-changeAppUserSettings\n//\n// parameters:\n//\n//\tmanifestID\nfunc ChangeAppUserSettings(manifestID string) *ChangeAppUserSettingsParams {\n\treturn &ChangeAppUserSettingsParams{\n\t\tManifestID:    manifestID,\n\t\tLinkCapturing: false,\n\t}\n}\n\n// WithLinkCapturing if user allows the links clicked on by the user in the\n// app's scope, or extended scope if the manifest has scope extensions and the\n// flags DesktopPWAsLinkCapturingWithScopeExtensions and\n// WebAppEnableScopeExtensions are enabled. Note, the API does not support\n// resetting the linkCapturing to the initial value, uninstalling and installing\n// the web app again will reset it. TODO(crbug.com/339453269): Setting this\n// value on ChromeOS is not supported yet.\nfunc (p ChangeAppUserSettingsParams) WithLinkCapturing(linkCapturing bool) *ChangeAppUserSettingsParams {\n\tp.LinkCapturing = linkCapturing\n\treturn &p\n}\n\n// WithDisplayMode [no description].\nfunc (p ChangeAppUserSettingsParams) WithDisplayMode(displayMode DisplayMode) *ChangeAppUserSettingsParams {\n\tp.DisplayMode = displayMode\n\treturn &p\n}\n\n// Do executes PWA.changeAppUserSettings against the provided context.\nfunc (p *ChangeAppUserSettingsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandChangeAppUserSettings, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandGetOsAppState         = \"PWA.getOsAppState\"\n\tCommandInstall               = \"PWA.install\"\n\tCommandUninstall             = \"PWA.uninstall\"\n\tCommandLaunch                = \"PWA.launch\"\n\tCommandLaunchFilesInApp      = \"PWA.launchFilesInApp\"\n\tCommandOpenCurrentPageInApp  = \"PWA.openCurrentPageInApp\"\n\tCommandChangeAppUserSettings = \"PWA.changeAppUserSettings\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/pwa/types.go",
    "content": "package pwa\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// FileHandlerAccept the following types are the replica of\n// https://crsrc.org/c/chrome/browser/web_applications/proto/web_app_os_integration_state.proto;drc=9910d3be894c8f142c977ba1023f30a656bc13fc;l=67.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#type-FileHandlerAccept\ntype FileHandlerAccept struct {\n\tMediaType      string   `json:\"mediaType\"` // New name of the mimetype according to https://www.iana.org/assignments/media-types/media-types.xhtml\n\tFileExtensions []string `json:\"fileExtensions\"`\n}\n\n// FileHandler [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#type-FileHandler\ntype FileHandler struct {\n\tAction      string               `json:\"action\"`\n\tAccepts     []*FileHandlerAccept `json:\"accepts\"`\n\tDisplayName string               `json:\"displayName\"`\n}\n\n// DisplayMode if user prefers opening the app in browser or an app window.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/PWA#type-DisplayMode\ntype DisplayMode string\n\n// String returns the DisplayMode as string value.\nfunc (t DisplayMode) String() string {\n\treturn string(t)\n}\n\n// DisplayMode values.\nconst (\n\tDisplayModeStandalone DisplayMode = \"standalone\"\n\tDisplayModeBrowser    DisplayMode = \"browser\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DisplayMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DisplayMode(s) {\n\tcase DisplayModeStandalone:\n\t\t*t = DisplayModeStandalone\n\tcase DisplayModeBrowser:\n\t\t*t = DisplayModeBrowser\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DisplayMode value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/runtime/events.go",
    "content": "package runtime\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// EventBindingCalled notification is issued every time when binding is\n// called.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-bindingCalled\ntype EventBindingCalled struct {\n\tName               string             `json:\"name\"`\n\tPayload            string             `json:\"payload\"`\n\tExecutionContextID ExecutionContextID `json:\"executionContextId\"` // Identifier of the context where the call was made.\n}\n\n// EventConsoleAPICalled issued when console API was called.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-consoleAPICalled\ntype EventConsoleAPICalled struct {\n\tType               APIType            `json:\"type\"`                          // Type of the call.\n\tArgs               []*RemoteObject    `json:\"args\"`                          // Call arguments.\n\tExecutionContextID ExecutionContextID `json:\"executionContextId\"`            // Identifier of the context where the call was made.\n\tTimestamp          *Timestamp         `json:\"timestamp\"`                     // Call timestamp.\n\tStackTrace         *StackTrace        `json:\"stackTrace,omitempty,omitzero\"` // Stack trace captured when the call was made. The async stack chain is automatically reported for the following call types: assert, error, trace, warning. For other types the async call chain can be retrieved using Debugger.getStackTrace and stackTrace.parentId field.\n\tContext            string             `json:\"context,omitempty,omitzero\"`    // Console context descriptor for calls on non-default console context (not console.*): 'anonymous#unique-logger-id' for call on unnamed context, 'name#unique-logger-id' for call on named context.\n}\n\n// EventExceptionRevoked issued when unhandled exception was revoked.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-exceptionRevoked\ntype EventExceptionRevoked struct {\n\tReason      string `json:\"reason\"`      // Reason describing why exception was revoked.\n\tExceptionID int64  `json:\"exceptionId\"` // The id of revoked exception, as reported in exceptionThrown.\n}\n\n// EventExceptionThrown issued when exception was thrown and unhandled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-exceptionThrown\ntype EventExceptionThrown struct {\n\tTimestamp        *Timestamp        `json:\"timestamp\"` // Timestamp of the exception.\n\tExceptionDetails *ExceptionDetails `json:\"exceptionDetails\"`\n}\n\n// EventExecutionContextCreated issued when new execution context is created.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-executionContextCreated\ntype EventExecutionContextCreated struct {\n\tContext *ExecutionContextDescription `json:\"context\"` // A newly created execution context.\n}\n\n// EventExecutionContextDestroyed issued when execution context is destroyed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-executionContextDestroyed\ntype EventExecutionContextDestroyed struct {\n\tExecutionContextID       ExecutionContextID `json:\"executionContextId\"`       // Id of the destroyed context\n\tExecutionContextUniqueID string             `json:\"executionContextUniqueId\"` // Unique Id of the destroyed context\n}\n\n// EventExecutionContextsCleared issued when all executionContexts were\n// cleared in browser.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-executionContextsCleared\ntype EventExecutionContextsCleared struct{}\n\n// EventInspectRequested issued when object should be inspected (for example,\n// as a result of inspect() command line API call).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-inspectRequested\ntype EventInspectRequested struct {\n\tObject             *RemoteObject      `json:\"object\"`\n\tHints              jsontext.Value     `json:\"hints\"`\n\tExecutionContextID ExecutionContextID `json:\"executionContextId,omitempty,omitzero\"` // Identifier of the context where the call was made.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/runtime/runtime.go",
    "content": "// Package runtime provides the Chrome DevTools Protocol\n// commands, types, and events for the Runtime domain.\n//\n// Runtime domain exposes JavaScript runtime by means of remote evaluation\n// and mirror objects. Evaluation results are returned as mirror object that\n// expose object type, string representation and unique identifier that can be\n// used for further object reference. Original objects are maintained in memory\n// unless they are either explicitly released or are released along with the\n// other objects in their object group.\n//\n// Generated by the cdproto-gen command.\npackage runtime\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// AwaitPromiseParams add handler to promise with given promise object id.\ntype AwaitPromiseParams struct {\n\tPromiseObjectID RemoteObjectID `json:\"promiseObjectId\"` // Identifier of the promise.\n\tReturnByValue   bool           `json:\"returnByValue\"`   // Whether the result is expected to be a JSON object that should be sent by value.\n\tGeneratePreview bool           `json:\"generatePreview\"` // Whether preview should be generated for the result.\n}\n\n// AwaitPromise add handler to promise with given promise object id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-awaitPromise\n//\n// parameters:\n//\n//\tpromiseObjectID - Identifier of the promise.\nfunc AwaitPromise(promiseObjectID RemoteObjectID) *AwaitPromiseParams {\n\treturn &AwaitPromiseParams{\n\t\tPromiseObjectID: promiseObjectID,\n\t\tReturnByValue:   false,\n\t\tGeneratePreview: false,\n\t}\n}\n\n// WithReturnByValue whether the result is expected to be a JSON object that\n// should be sent by value.\nfunc (p AwaitPromiseParams) WithReturnByValue(returnByValue bool) *AwaitPromiseParams {\n\tp.ReturnByValue = returnByValue\n\treturn &p\n}\n\n// WithGeneratePreview whether preview should be generated for the result.\nfunc (p AwaitPromiseParams) WithGeneratePreview(generatePreview bool) *AwaitPromiseParams {\n\tp.GeneratePreview = generatePreview\n\treturn &p\n}\n\n// AwaitPromiseReturns return values.\ntype AwaitPromiseReturns struct {\n\tResult           *RemoteObject     `json:\"result,omitempty,omitzero\"`           // Promise result. Will contain rejected value if promise was rejected.\n\tExceptionDetails *ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"` // Exception details if stack strace is available.\n}\n\n// Do executes Runtime.awaitPromise against the provided context.\n//\n// returns:\n//\n//\tresult - Promise result. Will contain rejected value if promise was rejected.\n//\texceptionDetails - Exception details if stack strace is available.\nfunc (p *AwaitPromiseParams) Do(ctx context.Context) (result *RemoteObject, exceptionDetails *ExceptionDetails, err error) {\n\t// execute\n\tvar res AwaitPromiseReturns\n\terr = cdp.Execute(ctx, CommandAwaitPromise, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.Result, res.ExceptionDetails, nil\n}\n\n// CallFunctionOnParams calls function with given declaration on the given\n// object. Object group of the result is inherited from the target object.\ntype CallFunctionOnParams struct {\n\tFunctionDeclaration  string                `json:\"functionDeclaration\"`                     // Declaration of the function to call.\n\tObjectID             RemoteObjectID        `json:\"objectId,omitempty,omitzero\"`             // Identifier of the object to call function on. Either objectId or executionContextId should be specified.\n\tArguments            []*CallArgument       `json:\"arguments,omitempty,omitzero\"`            // Call arguments. All call arguments must belong to the same JavaScript world as the target object.\n\tSilent               bool                  `json:\"silent\"`                                  // In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state.\n\tReturnByValue        bool                  `json:\"returnByValue\"`                           // Whether the result is expected to be a JSON object which should be sent by value. Can be overridden by serializationOptions.\n\tGeneratePreview      bool                  `json:\"generatePreview\"`                         // Whether preview should be generated for the result.\n\tUserGesture          bool                  `json:\"userGesture\"`                             // Whether execution should be treated as initiated by user in the UI.\n\tAwaitPromise         bool                  `json:\"awaitPromise\"`                            // Whether execution should await for resulting value and return once awaited promise is resolved.\n\tExecutionContextID   ExecutionContextID    `json:\"executionContextId,omitempty,omitzero\"`   // Specifies execution context which global object will be used to call function on. Either executionContextId or objectId should be specified.\n\tObjectGroup          string                `json:\"objectGroup,omitempty,omitzero\"`          // Symbolic group name that can be used to release multiple objects. If objectGroup is not specified and objectId is, objectGroup will be inherited from object.\n\tThrowOnSideEffect    bool                  `json:\"throwOnSideEffect\"`                       // Whether to throw an exception if side effect cannot be ruled out during evaluation.\n\tUniqueContextID      string                `json:\"uniqueContextId,omitempty,omitzero\"`      // An alternative way to specify the execution context to call function on. Compared to contextId that may be reused across processes, this is guaranteed to be system-unique, so it can be used to prevent accidental function call in context different than intended (e.g. as a result of navigation across process boundaries). This is mutually exclusive with executionContextId.\n\tSerializationOptions *SerializationOptions `json:\"serializationOptions,omitempty,omitzero\"` // Specifies the result serialization. If provided, overrides generatePreview and returnByValue.\n}\n\n// CallFunctionOn calls function with given declaration on the given object.\n// Object group of the result is inherited from the target object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-callFunctionOn\n//\n// parameters:\n//\n//\tfunctionDeclaration - Declaration of the function to call.\nfunc CallFunctionOn(functionDeclaration string) *CallFunctionOnParams {\n\treturn &CallFunctionOnParams{\n\t\tFunctionDeclaration: functionDeclaration,\n\t\tSilent:              false,\n\t\tReturnByValue:       false,\n\t\tGeneratePreview:     false,\n\t\tUserGesture:         false,\n\t\tAwaitPromise:        false,\n\t\tThrowOnSideEffect:   false,\n\t}\n}\n\n// WithObjectID identifier of the object to call function on. Either objectId\n// or executionContextId should be specified.\nfunc (p CallFunctionOnParams) WithObjectID(objectID RemoteObjectID) *CallFunctionOnParams {\n\tp.ObjectID = objectID\n\treturn &p\n}\n\n// WithArguments call arguments. All call arguments must belong to the same\n// JavaScript world as the target object.\nfunc (p CallFunctionOnParams) WithArguments(arguments []*CallArgument) *CallFunctionOnParams {\n\tp.Arguments = arguments\n\treturn &p\n}\n\n// WithSilent in silent mode exceptions thrown during evaluation are not\n// reported and do not pause execution. Overrides setPauseOnException state.\nfunc (p CallFunctionOnParams) WithSilent(silent bool) *CallFunctionOnParams {\n\tp.Silent = silent\n\treturn &p\n}\n\n// WithReturnByValue whether the result is expected to be a JSON object which\n// should be sent by value. Can be overridden by serializationOptions.\nfunc (p CallFunctionOnParams) WithReturnByValue(returnByValue bool) *CallFunctionOnParams {\n\tp.ReturnByValue = returnByValue\n\treturn &p\n}\n\n// WithGeneratePreview whether preview should be generated for the result.\nfunc (p CallFunctionOnParams) WithGeneratePreview(generatePreview bool) *CallFunctionOnParams {\n\tp.GeneratePreview = generatePreview\n\treturn &p\n}\n\n// WithUserGesture whether execution should be treated as initiated by user\n// in the UI.\nfunc (p CallFunctionOnParams) WithUserGesture(userGesture bool) *CallFunctionOnParams {\n\tp.UserGesture = userGesture\n\treturn &p\n}\n\n// WithAwaitPromise whether execution should await for resulting value and\n// return once awaited promise is resolved.\nfunc (p CallFunctionOnParams) WithAwaitPromise(awaitPromise bool) *CallFunctionOnParams {\n\tp.AwaitPromise = awaitPromise\n\treturn &p\n}\n\n// WithExecutionContextID specifies execution context which global object\n// will be used to call function on. Either executionContextId or objectId\n// should be specified.\nfunc (p CallFunctionOnParams) WithExecutionContextID(executionContextID ExecutionContextID) *CallFunctionOnParams {\n\tp.ExecutionContextID = executionContextID\n\treturn &p\n}\n\n// WithObjectGroup symbolic group name that can be used to release multiple\n// objects. If objectGroup is not specified and objectId is, objectGroup will be\n// inherited from object.\nfunc (p CallFunctionOnParams) WithObjectGroup(objectGroup string) *CallFunctionOnParams {\n\tp.ObjectGroup = objectGroup\n\treturn &p\n}\n\n// WithThrowOnSideEffect whether to throw an exception if side effect cannot\n// be ruled out during evaluation.\nfunc (p CallFunctionOnParams) WithThrowOnSideEffect(throwOnSideEffect bool) *CallFunctionOnParams {\n\tp.ThrowOnSideEffect = throwOnSideEffect\n\treturn &p\n}\n\n// WithUniqueContextID an alternative way to specify the execution context to\n// call function on. Compared to contextId that may be reused across processes,\n// this is guaranteed to be system-unique, so it can be used to prevent\n// accidental function call in context different than intended (e.g. as a result\n// of navigation across process boundaries). This is mutually exclusive with\n// executionContextId.\nfunc (p CallFunctionOnParams) WithUniqueContextID(uniqueContextID string) *CallFunctionOnParams {\n\tp.UniqueContextID = uniqueContextID\n\treturn &p\n}\n\n// WithSerializationOptions specifies the result serialization. If provided,\n// overrides generatePreview and returnByValue.\nfunc (p CallFunctionOnParams) WithSerializationOptions(serializationOptions *SerializationOptions) *CallFunctionOnParams {\n\tp.SerializationOptions = serializationOptions\n\treturn &p\n}\n\n// CallFunctionOnReturns return values.\ntype CallFunctionOnReturns struct {\n\tResult           *RemoteObject     `json:\"result,omitempty,omitzero\"`           // Call result.\n\tExceptionDetails *ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"` // Exception details.\n}\n\n// Do executes Runtime.callFunctionOn against the provided context.\n//\n// returns:\n//\n//\tresult - Call result.\n//\texceptionDetails - Exception details.\nfunc (p *CallFunctionOnParams) Do(ctx context.Context) (result *RemoteObject, exceptionDetails *ExceptionDetails, err error) {\n\t// execute\n\tvar res CallFunctionOnReturns\n\terr = cdp.Execute(ctx, CommandCallFunctionOn, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.Result, res.ExceptionDetails, nil\n}\n\n// CompileScriptParams compiles expression.\ntype CompileScriptParams struct {\n\tExpression         string             `json:\"expression\"`                            // Expression to compile.\n\tSourceURL          string             `json:\"sourceURL\"`                             // Source url to be set for the script.\n\tPersistScript      bool               `json:\"persistScript\"`                         // Specifies whether the compiled script should be persisted.\n\tExecutionContextID ExecutionContextID `json:\"executionContextId,omitempty,omitzero\"` // Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page.\n}\n\n// CompileScript compiles expression.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-compileScript\n//\n// parameters:\n//\n//\texpression - Expression to compile.\n//\tsourceURL - Source url to be set for the script.\n//\tpersistScript - Specifies whether the compiled script should be persisted.\nfunc CompileScript(expression string, sourceURL string, persistScript bool) *CompileScriptParams {\n\treturn &CompileScriptParams{\n\t\tExpression:    expression,\n\t\tSourceURL:     sourceURL,\n\t\tPersistScript: persistScript,\n\t}\n}\n\n// WithExecutionContextID specifies in which execution context to perform\n// script run. If the parameter is omitted the evaluation will be performed in\n// the context of the inspected page.\nfunc (p CompileScriptParams) WithExecutionContextID(executionContextID ExecutionContextID) *CompileScriptParams {\n\tp.ExecutionContextID = executionContextID\n\treturn &p\n}\n\n// CompileScriptReturns return values.\ntype CompileScriptReturns struct {\n\tScriptID         ScriptID          `json:\"scriptId,omitempty,omitzero\"`         // Id of the script.\n\tExceptionDetails *ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"` // Exception details.\n}\n\n// Do executes Runtime.compileScript against the provided context.\n//\n// returns:\n//\n//\tscriptID - Id of the script.\n//\texceptionDetails - Exception details.\nfunc (p *CompileScriptParams) Do(ctx context.Context) (scriptID ScriptID, exceptionDetails *ExceptionDetails, err error) {\n\t// execute\n\tvar res CompileScriptReturns\n\terr = cdp.Execute(ctx, CommandCompileScript, p, &res)\n\tif err != nil {\n\t\treturn \"\", nil, err\n\t}\n\n\treturn res.ScriptID, res.ExceptionDetails, nil\n}\n\n// DisableParams disables reporting of execution contexts creation.\ntype DisableParams struct{}\n\n// Disable disables reporting of execution contexts creation.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Runtime.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// DiscardConsoleEntriesParams discards collected exceptions and console API\n// calls.\ntype DiscardConsoleEntriesParams struct{}\n\n// DiscardConsoleEntries discards collected exceptions and console API calls.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-discardConsoleEntries\nfunc DiscardConsoleEntries() *DiscardConsoleEntriesParams {\n\treturn &DiscardConsoleEntriesParams{}\n}\n\n// Do executes Runtime.discardConsoleEntries against the provided context.\nfunc (p *DiscardConsoleEntriesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDiscardConsoleEntries, nil, nil)\n}\n\n// EnableParams enables reporting of execution contexts creation by means of\n// executionContextCreated event. When the reporting gets enabled the event will\n// be sent immediately for each existing execution context.\ntype EnableParams struct{}\n\n// Enable enables reporting of execution contexts creation by means of\n// executionContextCreated event. When the reporting gets enabled the event will\n// be sent immediately for each existing execution context.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Runtime.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// EvaluateParams evaluates expression on global object.\ntype EvaluateParams struct {\n\tExpression                  string                `json:\"expression\"`                              // Expression to evaluate.\n\tObjectGroup                 string                `json:\"objectGroup,omitempty,omitzero\"`          // Symbolic group name that can be used to release multiple objects.\n\tIncludeCommandLineAPI       bool                  `json:\"includeCommandLineAPI\"`                   // Determines whether Command Line API should be available during the evaluation.\n\tSilent                      bool                  `json:\"silent\"`                                  // In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state.\n\tContextID                   ExecutionContextID    `json:\"contextId,omitempty,omitzero\"`            // Specifies in which execution context to perform evaluation. If the parameter is omitted the evaluation will be performed in the context of the inspected page. This is mutually exclusive with uniqueContextId, which offers an alternative way to identify the execution context that is more reliable in a multi-process environment.\n\tReturnByValue               bool                  `json:\"returnByValue\"`                           // Whether the result is expected to be a JSON object that should be sent by value.\n\tGeneratePreview             bool                  `json:\"generatePreview\"`                         // Whether preview should be generated for the result.\n\tUserGesture                 bool                  `json:\"userGesture\"`                             // Whether execution should be treated as initiated by user in the UI.\n\tAwaitPromise                bool                  `json:\"awaitPromise\"`                            // Whether execution should await for resulting value and return once awaited promise is resolved.\n\tThrowOnSideEffect           bool                  `json:\"throwOnSideEffect\"`                       // Whether to throw an exception if side effect cannot be ruled out during evaluation. This implies disableBreaks below.\n\tTimeout                     TimeDelta             `json:\"timeout,omitempty,omitzero\"`              // Terminate execution after timing out (number of milliseconds).\n\tDisableBreaks               bool                  `json:\"disableBreaks\"`                           // Disable breakpoints during execution.\n\tReplMode                    bool                  `json:\"replMode\"`                                // Setting this flag to true enables let re-declaration and top-level await. Note that let variables can only be re-declared if they originate from replMode themselves.\n\tAllowUnsafeEvalBlockedByCSP bool                  `json:\"allowUnsafeEvalBlockedByCSP\"`             // The Content Security Policy (CSP) for the target might block 'unsafe-eval' which includes eval(), Function(), setTimeout() and setInterval() when called with non-callable arguments. This flag bypasses CSP for this evaluation and allows unsafe-eval. Defaults to true.\n\tUniqueContextID             string                `json:\"uniqueContextId,omitempty,omitzero\"`      // An alternative way to specify the execution context to evaluate in. Compared to contextId that may be reused across processes, this is guaranteed to be system-unique, so it can be used to prevent accidental evaluation of the expression in context different than intended (e.g. as a result of navigation across process boundaries). This is mutually exclusive with contextId.\n\tSerializationOptions        *SerializationOptions `json:\"serializationOptions,omitempty,omitzero\"` // Specifies the result serialization. If provided, overrides generatePreview and returnByValue.\n}\n\n// Evaluate evaluates expression on global object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-evaluate\n//\n// parameters:\n//\n//\texpression - Expression to evaluate.\nfunc Evaluate(expression string) *EvaluateParams {\n\treturn &EvaluateParams{\n\t\tExpression:                  expression,\n\t\tIncludeCommandLineAPI:       false,\n\t\tSilent:                      false,\n\t\tReturnByValue:               false,\n\t\tGeneratePreview:             false,\n\t\tUserGesture:                 false,\n\t\tAwaitPromise:                false,\n\t\tThrowOnSideEffect:           false,\n\t\tDisableBreaks:               false,\n\t\tReplMode:                    false,\n\t\tAllowUnsafeEvalBlockedByCSP: true,\n\t}\n}\n\n// WithObjectGroup symbolic group name that can be used to release multiple\n// objects.\nfunc (p EvaluateParams) WithObjectGroup(objectGroup string) *EvaluateParams {\n\tp.ObjectGroup = objectGroup\n\treturn &p\n}\n\n// WithIncludeCommandLineAPI determines whether Command Line API should be\n// available during the evaluation.\nfunc (p EvaluateParams) WithIncludeCommandLineAPI(includeCommandLineAPI bool) *EvaluateParams {\n\tp.IncludeCommandLineAPI = includeCommandLineAPI\n\treturn &p\n}\n\n// WithSilent in silent mode exceptions thrown during evaluation are not\n// reported and do not pause execution. Overrides setPauseOnException state.\nfunc (p EvaluateParams) WithSilent(silent bool) *EvaluateParams {\n\tp.Silent = silent\n\treturn &p\n}\n\n// WithContextID specifies in which execution context to perform evaluation.\n// If the parameter is omitted the evaluation will be performed in the context\n// of the inspected page. This is mutually exclusive with uniqueContextId, which\n// offers an alternative way to identify the execution context that is more\n// reliable in a multi-process environment.\nfunc (p EvaluateParams) WithContextID(contextID ExecutionContextID) *EvaluateParams {\n\tp.ContextID = contextID\n\treturn &p\n}\n\n// WithReturnByValue whether the result is expected to be a JSON object that\n// should be sent by value.\nfunc (p EvaluateParams) WithReturnByValue(returnByValue bool) *EvaluateParams {\n\tp.ReturnByValue = returnByValue\n\treturn &p\n}\n\n// WithGeneratePreview whether preview should be generated for the result.\nfunc (p EvaluateParams) WithGeneratePreview(generatePreview bool) *EvaluateParams {\n\tp.GeneratePreview = generatePreview\n\treturn &p\n}\n\n// WithUserGesture whether execution should be treated as initiated by user\n// in the UI.\nfunc (p EvaluateParams) WithUserGesture(userGesture bool) *EvaluateParams {\n\tp.UserGesture = userGesture\n\treturn &p\n}\n\n// WithAwaitPromise whether execution should await for resulting value and\n// return once awaited promise is resolved.\nfunc (p EvaluateParams) WithAwaitPromise(awaitPromise bool) *EvaluateParams {\n\tp.AwaitPromise = awaitPromise\n\treturn &p\n}\n\n// WithThrowOnSideEffect whether to throw an exception if side effect cannot\n// be ruled out during evaluation. This implies disableBreaks below.\nfunc (p EvaluateParams) WithThrowOnSideEffect(throwOnSideEffect bool) *EvaluateParams {\n\tp.ThrowOnSideEffect = throwOnSideEffect\n\treturn &p\n}\n\n// WithTimeout terminate execution after timing out (number of milliseconds).\nfunc (p EvaluateParams) WithTimeout(timeout TimeDelta) *EvaluateParams {\n\tp.Timeout = timeout\n\treturn &p\n}\n\n// WithDisableBreaks disable breakpoints during execution.\nfunc (p EvaluateParams) WithDisableBreaks(disableBreaks bool) *EvaluateParams {\n\tp.DisableBreaks = disableBreaks\n\treturn &p\n}\n\n// WithReplMode setting this flag to true enables let re-declaration and\n// top-level await. Note that let variables can only be re-declared if they\n// originate from replMode themselves.\nfunc (p EvaluateParams) WithReplMode(replMode bool) *EvaluateParams {\n\tp.ReplMode = replMode\n\treturn &p\n}\n\n// WithAllowUnsafeEvalBlockedByCSP the Content Security Policy (CSP) for the\n// target might block 'unsafe-eval' which includes eval(), Function(),\n// setTimeout() and setInterval() when called with non-callable arguments. This\n// flag bypasses CSP for this evaluation and allows unsafe-eval. Defaults to\n// true.\nfunc (p EvaluateParams) WithAllowUnsafeEvalBlockedByCSP(allowUnsafeEvalBlockedByCSP bool) *EvaluateParams {\n\tp.AllowUnsafeEvalBlockedByCSP = allowUnsafeEvalBlockedByCSP\n\treturn &p\n}\n\n// WithUniqueContextID an alternative way to specify the execution context to\n// evaluate in. Compared to contextId that may be reused across processes, this\n// is guaranteed to be system-unique, so it can be used to prevent accidental\n// evaluation of the expression in context different than intended (e.g. as a\n// result of navigation across process boundaries). This is mutually exclusive\n// with contextId.\nfunc (p EvaluateParams) WithUniqueContextID(uniqueContextID string) *EvaluateParams {\n\tp.UniqueContextID = uniqueContextID\n\treturn &p\n}\n\n// WithSerializationOptions specifies the result serialization. If provided,\n// overrides generatePreview and returnByValue.\nfunc (p EvaluateParams) WithSerializationOptions(serializationOptions *SerializationOptions) *EvaluateParams {\n\tp.SerializationOptions = serializationOptions\n\treturn &p\n}\n\n// EvaluateReturns return values.\ntype EvaluateReturns struct {\n\tResult           *RemoteObject     `json:\"result,omitempty,omitzero\"`           // Evaluation result.\n\tExceptionDetails *ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"` // Exception details.\n}\n\n// Do executes Runtime.evaluate against the provided context.\n//\n// returns:\n//\n//\tresult - Evaluation result.\n//\texceptionDetails - Exception details.\nfunc (p *EvaluateParams) Do(ctx context.Context) (result *RemoteObject, exceptionDetails *ExceptionDetails, err error) {\n\t// execute\n\tvar res EvaluateReturns\n\terr = cdp.Execute(ctx, CommandEvaluate, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.Result, res.ExceptionDetails, nil\n}\n\n// GetIsolateIDParams returns the isolate id.\ntype GetIsolateIDParams struct{}\n\n// GetIsolateID returns the isolate id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-getIsolateId\nfunc GetIsolateID() *GetIsolateIDParams {\n\treturn &GetIsolateIDParams{}\n}\n\n// GetIsolateIDReturns return values.\ntype GetIsolateIDReturns struct {\n\tID string `json:\"id,omitempty,omitzero\"` // The isolate id.\n}\n\n// Do executes Runtime.getIsolateId against the provided context.\n//\n// returns:\n//\n//\tid - The isolate id.\nfunc (p *GetIsolateIDParams) Do(ctx context.Context) (id string, err error) {\n\t// execute\n\tvar res GetIsolateIDReturns\n\terr = cdp.Execute(ctx, CommandGetIsolateID, nil, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.ID, nil\n}\n\n// GetHeapUsageParams returns the JavaScript heap usage. It is the total\n// usage of the corresponding isolate not scoped to a particular Runtime.\ntype GetHeapUsageParams struct{}\n\n// GetHeapUsage returns the JavaScript heap usage. It is the total usage of\n// the corresponding isolate not scoped to a particular Runtime.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-getHeapUsage\nfunc GetHeapUsage() *GetHeapUsageParams {\n\treturn &GetHeapUsageParams{}\n}\n\n// GetHeapUsageReturns return values.\ntype GetHeapUsageReturns struct {\n\tUsedSize             float64 `json:\"usedSize,omitempty,omitzero\"`             // Used JavaScript heap size in bytes.\n\tTotalSize            float64 `json:\"totalSize,omitempty,omitzero\"`            // Allocated JavaScript heap size in bytes.\n\tEmbedderHeapUsedSize float64 `json:\"embedderHeapUsedSize,omitempty,omitzero\"` // Used size in bytes in the embedder's garbage-collected heap.\n\tBackingStorageSize   float64 `json:\"backingStorageSize,omitempty,omitzero\"`   // Size in bytes of backing storage for array buffers and external strings.\n}\n\n// Do executes Runtime.getHeapUsage against the provided context.\n//\n// returns:\n//\n//\tusedSize - Used JavaScript heap size in bytes.\n//\ttotalSize - Allocated JavaScript heap size in bytes.\n//\tembedderHeapUsedSize - Used size in bytes in the embedder's garbage-collected heap.\n//\tbackingStorageSize - Size in bytes of backing storage for array buffers and external strings.\nfunc (p *GetHeapUsageParams) Do(ctx context.Context) (usedSize float64, totalSize float64, embedderHeapUsedSize float64, backingStorageSize float64, err error) {\n\t// execute\n\tvar res GetHeapUsageReturns\n\terr = cdp.Execute(ctx, CommandGetHeapUsage, nil, &res)\n\tif err != nil {\n\t\treturn 0, 0, 0, 0, err\n\t}\n\n\treturn res.UsedSize, res.TotalSize, res.EmbedderHeapUsedSize, res.BackingStorageSize, nil\n}\n\n// GetPropertiesParams returns properties of a given object. Object group of\n// the result is inherited from the target object.\ntype GetPropertiesParams struct {\n\tObjectID                 RemoteObjectID `json:\"objectId\"`                 // Identifier of the object to return properties for.\n\tOwnProperties            bool           `json:\"ownProperties\"`            // If true, returns properties belonging only to the element itself, not to its prototype chain.\n\tAccessorPropertiesOnly   bool           `json:\"accessorPropertiesOnly\"`   // If true, returns accessor properties (with getter/setter) only; internal properties are not returned either.\n\tGeneratePreview          bool           `json:\"generatePreview\"`          // Whether preview should be generated for the results.\n\tNonIndexedPropertiesOnly bool           `json:\"nonIndexedPropertiesOnly\"` // If true, returns non-indexed properties only.\n}\n\n// GetProperties returns properties of a given object. Object group of the\n// result is inherited from the target object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-getProperties\n//\n// parameters:\n//\n//\tobjectID - Identifier of the object to return properties for.\nfunc GetProperties(objectID RemoteObjectID) *GetPropertiesParams {\n\treturn &GetPropertiesParams{\n\t\tObjectID:                 objectID,\n\t\tOwnProperties:            false,\n\t\tAccessorPropertiesOnly:   false,\n\t\tGeneratePreview:          false,\n\t\tNonIndexedPropertiesOnly: false,\n\t}\n}\n\n// WithOwnProperties if true, returns properties belonging only to the\n// element itself, not to its prototype chain.\nfunc (p GetPropertiesParams) WithOwnProperties(ownProperties bool) *GetPropertiesParams {\n\tp.OwnProperties = ownProperties\n\treturn &p\n}\n\n// WithAccessorPropertiesOnly if true, returns accessor properties (with\n// getter/setter) only; internal properties are not returned either.\nfunc (p GetPropertiesParams) WithAccessorPropertiesOnly(accessorPropertiesOnly bool) *GetPropertiesParams {\n\tp.AccessorPropertiesOnly = accessorPropertiesOnly\n\treturn &p\n}\n\n// WithGeneratePreview whether preview should be generated for the results.\nfunc (p GetPropertiesParams) WithGeneratePreview(generatePreview bool) *GetPropertiesParams {\n\tp.GeneratePreview = generatePreview\n\treturn &p\n}\n\n// WithNonIndexedPropertiesOnly if true, returns non-indexed properties only.\nfunc (p GetPropertiesParams) WithNonIndexedPropertiesOnly(nonIndexedPropertiesOnly bool) *GetPropertiesParams {\n\tp.NonIndexedPropertiesOnly = nonIndexedPropertiesOnly\n\treturn &p\n}\n\n// GetPropertiesReturns return values.\ntype GetPropertiesReturns struct {\n\tResult             []*PropertyDescriptor         `json:\"result,omitempty,omitzero\"`             // Object properties.\n\tInternalProperties []*InternalPropertyDescriptor `json:\"internalProperties,omitempty,omitzero\"` // Internal object properties (only of the element itself).\n\tPrivateProperties  []*PrivatePropertyDescriptor  `json:\"privateProperties,omitempty,omitzero\"`  // Object private properties.\n\tExceptionDetails   *ExceptionDetails             `json:\"exceptionDetails,omitempty,omitzero\"`   // Exception details.\n}\n\n// Do executes Runtime.getProperties against the provided context.\n//\n// returns:\n//\n//\tresult - Object properties.\n//\tinternalProperties - Internal object properties (only of the element itself).\n//\tprivateProperties - Object private properties.\n//\texceptionDetails - Exception details.\nfunc (p *GetPropertiesParams) Do(ctx context.Context) (result []*PropertyDescriptor, internalProperties []*InternalPropertyDescriptor, privateProperties []*PrivatePropertyDescriptor, exceptionDetails *ExceptionDetails, err error) {\n\t// execute\n\tvar res GetPropertiesReturns\n\terr = cdp.Execute(ctx, CommandGetProperties, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, nil, nil, err\n\t}\n\n\treturn res.Result, res.InternalProperties, res.PrivateProperties, res.ExceptionDetails, nil\n}\n\n// GlobalLexicalScopeNamesParams returns all let, const and class variables\n// from global scope.\ntype GlobalLexicalScopeNamesParams struct {\n\tExecutionContextID ExecutionContextID `json:\"executionContextId,omitempty,omitzero\"` // Specifies in which execution context to lookup global scope variables.\n}\n\n// GlobalLexicalScopeNames returns all let, const and class variables from\n// global scope.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-globalLexicalScopeNames\n//\n// parameters:\nfunc GlobalLexicalScopeNames() *GlobalLexicalScopeNamesParams {\n\treturn &GlobalLexicalScopeNamesParams{}\n}\n\n// WithExecutionContextID specifies in which execution context to lookup\n// global scope variables.\nfunc (p GlobalLexicalScopeNamesParams) WithExecutionContextID(executionContextID ExecutionContextID) *GlobalLexicalScopeNamesParams {\n\tp.ExecutionContextID = executionContextID\n\treturn &p\n}\n\n// GlobalLexicalScopeNamesReturns return values.\ntype GlobalLexicalScopeNamesReturns struct {\n\tNames []string `json:\"names,omitempty,omitzero\"`\n}\n\n// Do executes Runtime.globalLexicalScopeNames against the provided context.\n//\n// returns:\n//\n//\tnames\nfunc (p *GlobalLexicalScopeNamesParams) Do(ctx context.Context) (names []string, err error) {\n\t// execute\n\tvar res GlobalLexicalScopeNamesReturns\n\terr = cdp.Execute(ctx, CommandGlobalLexicalScopeNames, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Names, nil\n}\n\n// QueryObjectsParams [no description].\ntype QueryObjectsParams struct {\n\tPrototypeObjectID RemoteObjectID `json:\"prototypeObjectId\"`              // Identifier of the prototype to return objects for.\n\tObjectGroup       string         `json:\"objectGroup,omitempty,omitzero\"` // Symbolic group name that can be used to release the results.\n}\n\n// QueryObjects [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-queryObjects\n//\n// parameters:\n//\n//\tprototypeObjectID - Identifier of the prototype to return objects for.\nfunc QueryObjects(prototypeObjectID RemoteObjectID) *QueryObjectsParams {\n\treturn &QueryObjectsParams{\n\t\tPrototypeObjectID: prototypeObjectID,\n\t}\n}\n\n// WithObjectGroup symbolic group name that can be used to release the\n// results.\nfunc (p QueryObjectsParams) WithObjectGroup(objectGroup string) *QueryObjectsParams {\n\tp.ObjectGroup = objectGroup\n\treturn &p\n}\n\n// QueryObjectsReturns return values.\ntype QueryObjectsReturns struct {\n\tObjects *RemoteObject `json:\"objects,omitempty,omitzero\"` // Array with objects.\n}\n\n// Do executes Runtime.queryObjects against the provided context.\n//\n// returns:\n//\n//\tobjects - Array with objects.\nfunc (p *QueryObjectsParams) Do(ctx context.Context) (objects *RemoteObject, err error) {\n\t// execute\n\tvar res QueryObjectsReturns\n\terr = cdp.Execute(ctx, CommandQueryObjects, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Objects, nil\n}\n\n// ReleaseObjectParams releases remote object with given id.\ntype ReleaseObjectParams struct {\n\tObjectID RemoteObjectID `json:\"objectId\"` // Identifier of the object to release.\n}\n\n// ReleaseObject releases remote object with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-releaseObject\n//\n// parameters:\n//\n//\tobjectID - Identifier of the object to release.\nfunc ReleaseObject(objectID RemoteObjectID) *ReleaseObjectParams {\n\treturn &ReleaseObjectParams{\n\t\tObjectID: objectID,\n\t}\n}\n\n// Do executes Runtime.releaseObject against the provided context.\nfunc (p *ReleaseObjectParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandReleaseObject, p, nil)\n}\n\n// ReleaseObjectGroupParams releases all remote objects that belong to a\n// given group.\ntype ReleaseObjectGroupParams struct {\n\tObjectGroup string `json:\"objectGroup\"` // Symbolic object group name.\n}\n\n// ReleaseObjectGroup releases all remote objects that belong to a given\n// group.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-releaseObjectGroup\n//\n// parameters:\n//\n//\tobjectGroup - Symbolic object group name.\nfunc ReleaseObjectGroup(objectGroup string) *ReleaseObjectGroupParams {\n\treturn &ReleaseObjectGroupParams{\n\t\tObjectGroup: objectGroup,\n\t}\n}\n\n// Do executes Runtime.releaseObjectGroup against the provided context.\nfunc (p *ReleaseObjectGroupParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandReleaseObjectGroup, p, nil)\n}\n\n// RunIfWaitingForDebuggerParams tells inspected instance to run if it was\n// waiting for debugger to attach.\ntype RunIfWaitingForDebuggerParams struct{}\n\n// RunIfWaitingForDebugger tells inspected instance to run if it was waiting\n// for debugger to attach.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-runIfWaitingForDebugger\nfunc RunIfWaitingForDebugger() *RunIfWaitingForDebuggerParams {\n\treturn &RunIfWaitingForDebuggerParams{}\n}\n\n// Do executes Runtime.runIfWaitingForDebugger against the provided context.\nfunc (p *RunIfWaitingForDebuggerParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRunIfWaitingForDebugger, nil, nil)\n}\n\n// RunScriptParams runs script with given id in a given context.\ntype RunScriptParams struct {\n\tScriptID              ScriptID           `json:\"scriptId\"`                              // Id of the script to run.\n\tExecutionContextID    ExecutionContextID `json:\"executionContextId,omitempty,omitzero\"` // Specifies in which execution context to perform script run. If the parameter is omitted the evaluation will be performed in the context of the inspected page.\n\tObjectGroup           string             `json:\"objectGroup,omitempty,omitzero\"`        // Symbolic group name that can be used to release multiple objects.\n\tSilent                bool               `json:\"silent\"`                                // In silent mode exceptions thrown during evaluation are not reported and do not pause execution. Overrides setPauseOnException state.\n\tIncludeCommandLineAPI bool               `json:\"includeCommandLineAPI\"`                 // Determines whether Command Line API should be available during the evaluation.\n\tReturnByValue         bool               `json:\"returnByValue\"`                         // Whether the result is expected to be a JSON object which should be sent by value.\n\tGeneratePreview       bool               `json:\"generatePreview\"`                       // Whether preview should be generated for the result.\n\tAwaitPromise          bool               `json:\"awaitPromise\"`                          // Whether execution should await for resulting value and return once awaited promise is resolved.\n}\n\n// RunScript runs script with given id in a given context.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-runScript\n//\n// parameters:\n//\n//\tscriptID - Id of the script to run.\nfunc RunScript(scriptID ScriptID) *RunScriptParams {\n\treturn &RunScriptParams{\n\t\tScriptID:              scriptID,\n\t\tSilent:                false,\n\t\tIncludeCommandLineAPI: false,\n\t\tReturnByValue:         false,\n\t\tGeneratePreview:       false,\n\t\tAwaitPromise:          false,\n\t}\n}\n\n// WithExecutionContextID specifies in which execution context to perform\n// script run. If the parameter is omitted the evaluation will be performed in\n// the context of the inspected page.\nfunc (p RunScriptParams) WithExecutionContextID(executionContextID ExecutionContextID) *RunScriptParams {\n\tp.ExecutionContextID = executionContextID\n\treturn &p\n}\n\n// WithObjectGroup symbolic group name that can be used to release multiple\n// objects.\nfunc (p RunScriptParams) WithObjectGroup(objectGroup string) *RunScriptParams {\n\tp.ObjectGroup = objectGroup\n\treturn &p\n}\n\n// WithSilent in silent mode exceptions thrown during evaluation are not\n// reported and do not pause execution. Overrides setPauseOnException state.\nfunc (p RunScriptParams) WithSilent(silent bool) *RunScriptParams {\n\tp.Silent = silent\n\treturn &p\n}\n\n// WithIncludeCommandLineAPI determines whether Command Line API should be\n// available during the evaluation.\nfunc (p RunScriptParams) WithIncludeCommandLineAPI(includeCommandLineAPI bool) *RunScriptParams {\n\tp.IncludeCommandLineAPI = includeCommandLineAPI\n\treturn &p\n}\n\n// WithReturnByValue whether the result is expected to be a JSON object which\n// should be sent by value.\nfunc (p RunScriptParams) WithReturnByValue(returnByValue bool) *RunScriptParams {\n\tp.ReturnByValue = returnByValue\n\treturn &p\n}\n\n// WithGeneratePreview whether preview should be generated for the result.\nfunc (p RunScriptParams) WithGeneratePreview(generatePreview bool) *RunScriptParams {\n\tp.GeneratePreview = generatePreview\n\treturn &p\n}\n\n// WithAwaitPromise whether execution should await for resulting value and\n// return once awaited promise is resolved.\nfunc (p RunScriptParams) WithAwaitPromise(awaitPromise bool) *RunScriptParams {\n\tp.AwaitPromise = awaitPromise\n\treturn &p\n}\n\n// RunScriptReturns return values.\ntype RunScriptReturns struct {\n\tResult           *RemoteObject     `json:\"result,omitempty,omitzero\"`           // Run result.\n\tExceptionDetails *ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"` // Exception details.\n}\n\n// Do executes Runtime.runScript against the provided context.\n//\n// returns:\n//\n//\tresult - Run result.\n//\texceptionDetails - Exception details.\nfunc (p *RunScriptParams) Do(ctx context.Context) (result *RemoteObject, exceptionDetails *ExceptionDetails, err error) {\n\t// execute\n\tvar res RunScriptReturns\n\terr = cdp.Execute(ctx, CommandRunScript, p, &res)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\treturn res.Result, res.ExceptionDetails, nil\n}\n\n// SetCustomObjectFormatterEnabledParams [no description].\ntype SetCustomObjectFormatterEnabledParams struct {\n\tEnabled bool `json:\"enabled\"`\n}\n\n// SetCustomObjectFormatterEnabled [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-setCustomObjectFormatterEnabled\n//\n// parameters:\n//\n//\tenabled\nfunc SetCustomObjectFormatterEnabled(enabled bool) *SetCustomObjectFormatterEnabledParams {\n\treturn &SetCustomObjectFormatterEnabledParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Runtime.setCustomObjectFormatterEnabled against the provided context.\nfunc (p *SetCustomObjectFormatterEnabledParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCustomObjectFormatterEnabled, p, nil)\n}\n\n// SetMaxCallStackSizeToCaptureParams [no description].\ntype SetMaxCallStackSizeToCaptureParams struct {\n\tSize int64 `json:\"size\"`\n}\n\n// SetMaxCallStackSizeToCapture [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-setMaxCallStackSizeToCapture\n//\n// parameters:\n//\n//\tsize\nfunc SetMaxCallStackSizeToCapture(size int64) *SetMaxCallStackSizeToCaptureParams {\n\treturn &SetMaxCallStackSizeToCaptureParams{\n\t\tSize: size,\n\t}\n}\n\n// Do executes Runtime.setMaxCallStackSizeToCapture against the provided context.\nfunc (p *SetMaxCallStackSizeToCaptureParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetMaxCallStackSizeToCapture, p, nil)\n}\n\n// TerminateExecutionParams terminate current or next JavaScript execution.\n// Will cancel the termination when the outer-most script execution ends.\ntype TerminateExecutionParams struct{}\n\n// TerminateExecution terminate current or next JavaScript execution. Will\n// cancel the termination when the outer-most script execution ends.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-terminateExecution\nfunc TerminateExecution() *TerminateExecutionParams {\n\treturn &TerminateExecutionParams{}\n}\n\n// Do executes Runtime.terminateExecution against the provided context.\nfunc (p *TerminateExecutionParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTerminateExecution, nil, nil)\n}\n\n// AddBindingParams if executionContextId is empty, adds binding with the\n// given name on the global objects of all inspected contexts, including those\n// created later, bindings survive reloads. Binding function takes exactly one\n// argument, this argument should be string, in case of any other input,\n// function throws an exception. Each binding function call produces\n// Runtime.bindingCalled notification.\ntype AddBindingParams struct {\n\tName                 string `json:\"name\"`\n\tExecutionContextName string `json:\"executionContextName,omitempty,omitzero\"` // If specified, the binding is exposed to the executionContext with matching name, even for contexts created after the binding is added. See also ExecutionContext.name and worldName parameter to Page.addScriptToEvaluateOnNewDocument. This parameter is mutually exclusive with executionContextId.\n}\n\n// AddBinding if executionContextId is empty, adds binding with the given\n// name on the global objects of all inspected contexts, including those created\n// later, bindings survive reloads. Binding function takes exactly one argument,\n// this argument should be string, in case of any other input, function throws\n// an exception. Each binding function call produces Runtime.bindingCalled\n// notification.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-addBinding\n//\n// parameters:\n//\n//\tname\nfunc AddBinding(name string) *AddBindingParams {\n\treturn &AddBindingParams{\n\t\tName: name,\n\t}\n}\n\n// WithExecutionContextName if specified, the binding is exposed to the\n// executionContext with matching name, even for contexts created after the\n// binding is added. See also ExecutionContext.name and worldName parameter to\n// Page.addScriptToEvaluateOnNewDocument. This parameter is mutually exclusive\n// with executionContextId.\nfunc (p AddBindingParams) WithExecutionContextName(executionContextName string) *AddBindingParams {\n\tp.ExecutionContextName = executionContextName\n\treturn &p\n}\n\n// Do executes Runtime.addBinding against the provided context.\nfunc (p *AddBindingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandAddBinding, p, nil)\n}\n\n// RemoveBindingParams this method does not remove binding function from\n// global object but unsubscribes current runtime agent from\n// Runtime.bindingCalled notifications.\ntype RemoveBindingParams struct {\n\tName string `json:\"name\"`\n}\n\n// RemoveBinding this method does not remove binding function from global\n// object but unsubscribes current runtime agent from Runtime.bindingCalled\n// notifications.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-removeBinding\n//\n// parameters:\n//\n//\tname\nfunc RemoveBinding(name string) *RemoveBindingParams {\n\treturn &RemoveBindingParams{\n\t\tName: name,\n\t}\n}\n\n// Do executes Runtime.removeBinding against the provided context.\nfunc (p *RemoveBindingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveBinding, p, nil)\n}\n\n// GetExceptionDetailsParams this method tries to lookup and populate\n// exception details for a JavaScript Error object. Note that the stackTrace\n// portion of the resulting exceptionDetails will only be populated if the\n// Runtime domain was enabled at the time when the Error was thrown.\ntype GetExceptionDetailsParams struct {\n\tErrorObjectID RemoteObjectID `json:\"errorObjectId\"` // The error object for which to resolve the exception details.\n}\n\n// GetExceptionDetails this method tries to lookup and populate exception\n// details for a JavaScript Error object. Note that the stackTrace portion of\n// the resulting exceptionDetails will only be populated if the Runtime domain\n// was enabled at the time when the Error was thrown.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#method-getExceptionDetails\n//\n// parameters:\n//\n//\terrorObjectID - The error object for which to resolve the exception details.\nfunc GetExceptionDetails(errorObjectID RemoteObjectID) *GetExceptionDetailsParams {\n\treturn &GetExceptionDetailsParams{\n\t\tErrorObjectID: errorObjectID,\n\t}\n}\n\n// GetExceptionDetailsReturns return values.\ntype GetExceptionDetailsReturns struct {\n\tExceptionDetails *ExceptionDetails `json:\"exceptionDetails,omitempty,omitzero\"`\n}\n\n// Do executes Runtime.getExceptionDetails against the provided context.\n//\n// returns:\n//\n//\texceptionDetails\nfunc (p *GetExceptionDetailsParams) Do(ctx context.Context) (exceptionDetails *ExceptionDetails, err error) {\n\t// execute\n\tvar res GetExceptionDetailsReturns\n\terr = cdp.Execute(ctx, CommandGetExceptionDetails, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.ExceptionDetails, nil\n}\n\n// Command names.\nconst (\n\tCommandAwaitPromise                    = \"Runtime.awaitPromise\"\n\tCommandCallFunctionOn                  = \"Runtime.callFunctionOn\"\n\tCommandCompileScript                   = \"Runtime.compileScript\"\n\tCommandDisable                         = \"Runtime.disable\"\n\tCommandDiscardConsoleEntries           = \"Runtime.discardConsoleEntries\"\n\tCommandEnable                          = \"Runtime.enable\"\n\tCommandEvaluate                        = \"Runtime.evaluate\"\n\tCommandGetIsolateID                    = \"Runtime.getIsolateId\"\n\tCommandGetHeapUsage                    = \"Runtime.getHeapUsage\"\n\tCommandGetProperties                   = \"Runtime.getProperties\"\n\tCommandGlobalLexicalScopeNames         = \"Runtime.globalLexicalScopeNames\"\n\tCommandQueryObjects                    = \"Runtime.queryObjects\"\n\tCommandReleaseObject                   = \"Runtime.releaseObject\"\n\tCommandReleaseObjectGroup              = \"Runtime.releaseObjectGroup\"\n\tCommandRunIfWaitingForDebugger         = \"Runtime.runIfWaitingForDebugger\"\n\tCommandRunScript                       = \"Runtime.runScript\"\n\tCommandSetCustomObjectFormatterEnabled = \"Runtime.setCustomObjectFormatterEnabled\"\n\tCommandSetMaxCallStackSizeToCapture    = \"Runtime.setMaxCallStackSizeToCapture\"\n\tCommandTerminateExecution              = \"Runtime.terminateExecution\"\n\tCommandAddBinding                      = \"Runtime.addBinding\"\n\tCommandRemoveBinding                   = \"Runtime.removeBinding\"\n\tCommandGetExceptionDetails             = \"Runtime.getExceptionDetails\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/runtime/types.go",
    "content": "package runtime\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// ScriptID unique script identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-ScriptId\ntype ScriptID string\n\n// String returns the ScriptID as string value.\nfunc (t ScriptID) String() string {\n\treturn string(t)\n}\n\n// SerializationOptions represents options for serialization. Overrides\n// generatePreview and returnByValue.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-SerializationOptions\ntype SerializationOptions struct {\n\tSerialization        SerializationOptionsSerialization `json:\"serialization\"`\n\tMaxDepth             int64                             `json:\"maxDepth,omitempty,omitzero\"` // Deep serialization depth. Default is full depth. Respected only in deep serialization mode.\n\tAdditionalParameters jsontext.Value                    `json:\"additionalParameters,omitempty,omitzero\"`\n}\n\n// DeepSerializedValue represents deep serialized value.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-DeepSerializedValue\ntype DeepSerializedValue struct {\n\tType                     DeepSerializedValueType `json:\"type\"`\n\tValue                    jsontext.Value          `json:\"value,omitempty,omitzero\"`\n\tObjectID                 string                  `json:\"objectId,omitempty,omitzero\"`\n\tWeakLocalObjectReference int64                   `json:\"weakLocalObjectReference,omitempty,omitzero\"` // Set if value reference met more then once during serialization. In such case, value is provided only to one of the serialized values. Unique per value in the scope of one CDP call.\n}\n\n// RemoteObjectID unique object identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-RemoteObjectId\ntype RemoteObjectID string\n\n// String returns the RemoteObjectID as string value.\nfunc (t RemoteObjectID) String() string {\n\treturn string(t)\n}\n\n// UnserializableValue primitive value which cannot be JSON-stringified.\n// Includes values -0, NaN, Infinity, -Infinity, and bigint literals.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-UnserializableValue\ntype UnserializableValue string\n\n// String returns the UnserializableValue as string value.\nfunc (t UnserializableValue) String() string {\n\treturn string(t)\n}\n\n// RemoteObject mirror object referencing original JavaScript object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-RemoteObject\ntype RemoteObject struct {\n\tType                Type                 `json:\"type\"`                                   // Object type.\n\tSubtype             Subtype              `json:\"subtype,omitempty,omitzero\"`             // Object subtype hint. Specified for object type values only. NOTE: If you change anything here, make sure to also update subtype in ObjectPreview and PropertyPreview below.\n\tClassName           string               `json:\"className,omitempty,omitzero\"`           // Object class (constructor) name. Specified for object type values only.\n\tValue               jsontext.Value       `json:\"value,omitempty,omitzero\"`               // Remote object value in case of primitive values or JSON values (if it was requested).\n\tUnserializableValue UnserializableValue  `json:\"unserializableValue,omitempty,omitzero\"` // Primitive value which can not be JSON-stringified does not have value, but gets this property.\n\tDescription         string               `json:\"description,omitempty,omitzero\"`         // String representation of the object.\n\tDeepSerializedValue *DeepSerializedValue `json:\"deepSerializedValue,omitempty,omitzero\"` // Deep serialized value.\n\tObjectID            RemoteObjectID       `json:\"objectId,omitempty,omitzero\"`            // Unique object identifier (for non-primitive values).\n\tPreview             *ObjectPreview       `json:\"preview,omitempty,omitzero\"`             // Preview containing abbreviated property values. Specified for object type values only.\n\tCustomPreview       *CustomPreview       `json:\"customPreview,omitempty,omitzero\"`\n}\n\n// CustomPreview [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-CustomPreview\ntype CustomPreview struct {\n\tHeader       string         `json:\"header\"`                          // The JSON-stringified result of formatter.header(object, config) call. It contains json ML array that represents RemoteObject.\n\tBodyGetterID RemoteObjectID `json:\"bodyGetterId,omitempty,omitzero\"` // If formatter returns true as a result of formatter.hasBody call then bodyGetterId will contain RemoteObjectId for the function that returns result of formatter.body(object, config) call. The result value is json ML array.\n}\n\n// ObjectPreview object containing abbreviated remote object value.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-ObjectPreview\ntype ObjectPreview struct {\n\tType        Type               `json:\"type\"`                           // Object type.\n\tSubtype     Subtype            `json:\"subtype,omitempty,omitzero\"`     // Object subtype hint. Specified for object type values only.\n\tDescription string             `json:\"description,omitempty,omitzero\"` // String representation of the object.\n\tOverflow    bool               `json:\"overflow\"`                       // True iff some of the properties or entries of the original object did not fit.\n\tProperties  []*PropertyPreview `json:\"properties\"`                     // List of the properties.\n\tEntries     []*EntryPreview    `json:\"entries,omitempty,omitzero\"`     // List of the entries. Specified for map and set subtype values only.\n}\n\n// PropertyPreview [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-PropertyPreview\ntype PropertyPreview struct {\n\tName         string         `json:\"name\"`                            // Property name.\n\tType         Type           `json:\"type\"`                            // Object type. Accessor means that the property itself is an accessor property.\n\tValue        string         `json:\"value,omitempty,omitzero\"`        // User-friendly property value string.\n\tValuePreview *ObjectPreview `json:\"valuePreview,omitempty,omitzero\"` // Nested value preview.\n\tSubtype      Subtype        `json:\"subtype,omitempty,omitzero\"`      // Object subtype hint. Specified for object type values only.\n}\n\n// EntryPreview [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-EntryPreview\ntype EntryPreview struct {\n\tKey   *ObjectPreview `json:\"key,omitempty,omitzero\"` // Preview of the key. Specified for map-like collection entries.\n\tValue *ObjectPreview `json:\"value\"`                  // Preview of the value.\n}\n\n// PropertyDescriptor object property descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-PropertyDescriptor\ntype PropertyDescriptor struct {\n\tName         string        `json:\"name\"`                      // Property name or symbol description.\n\tValue        *RemoteObject `json:\"value,omitempty,omitzero\"`  // The value associated with the property.\n\tWritable     bool          `json:\"writable\"`                  // True if the value associated with the property may be changed (data descriptors only).\n\tGet          *RemoteObject `json:\"get,omitempty,omitzero\"`    // A function which serves as a getter for the property, or undefined if there is no getter (accessor descriptors only).\n\tSet          *RemoteObject `json:\"set,omitempty,omitzero\"`    // A function which serves as a setter for the property, or undefined if there is no setter (accessor descriptors only).\n\tConfigurable bool          `json:\"configurable\"`              // True if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.\n\tEnumerable   bool          `json:\"enumerable\"`                // True if this property shows up during enumeration of the properties on the corresponding object.\n\tWasThrown    bool          `json:\"wasThrown\"`                 // True if the result was thrown during the evaluation.\n\tIsOwn        bool          `json:\"isOwn\"`                     // True if the property is owned for the object.\n\tSymbol       *RemoteObject `json:\"symbol,omitempty,omitzero\"` // Property symbol object, if the property is of the symbol type.\n}\n\n// InternalPropertyDescriptor object internal property descriptor. This\n// property isn't normally visible in JavaScript code.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-InternalPropertyDescriptor\ntype InternalPropertyDescriptor struct {\n\tName  string        `json:\"name\"`                     // Conventional property name.\n\tValue *RemoteObject `json:\"value,omitempty,omitzero\"` // The value associated with the property.\n}\n\n// PrivatePropertyDescriptor object private field descriptor.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-PrivatePropertyDescriptor\ntype PrivatePropertyDescriptor struct {\n\tName  string        `json:\"name\"`                     // Private property name.\n\tValue *RemoteObject `json:\"value,omitempty,omitzero\"` // The value associated with the private property.\n\tGet   *RemoteObject `json:\"get,omitempty,omitzero\"`   // A function which serves as a getter for the private property, or undefined if there is no getter (accessor descriptors only).\n\tSet   *RemoteObject `json:\"set,omitempty,omitzero\"`   // A function which serves as a setter for the private property, or undefined if there is no setter (accessor descriptors only).\n}\n\n// CallArgument represents function call argument. Either remote object id\n// objectId, primitive value, unserializable primitive value or neither of (for\n// undefined) them should be specified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-CallArgument\ntype CallArgument struct {\n\tValue               jsontext.Value      `json:\"value,omitempty,omitzero\"`               // Primitive value or serializable javascript object.\n\tUnserializableValue UnserializableValue `json:\"unserializableValue,omitempty,omitzero\"` // Primitive value which can not be JSON-stringified.\n\tObjectID            RemoteObjectID      `json:\"objectId,omitempty,omitzero\"`            // Remote object handle.\n}\n\n// ExecutionContextID ID of an execution context.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-ExecutionContextId\ntype ExecutionContextID int64\n\n// Int64 returns the ExecutionContextID as int64 value.\nfunc (t ExecutionContextID) Int64() int64 {\n\treturn int64(t)\n}\n\n// ExecutionContextDescription description of an isolated world.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-ExecutionContextDescription\ntype ExecutionContextDescription struct {\n\tID       ExecutionContextID `json:\"id\"`       // Unique id of the execution context. It can be used to specify in which execution context script evaluation should be performed.\n\tOrigin   string             `json:\"origin\"`   // Execution context origin.\n\tName     string             `json:\"name\"`     // Human readable name describing given context.\n\tUniqueID string             `json:\"uniqueId\"` // A system-unique execution context identifier. Unlike the id, this is unique across multiple processes, so can be reliably used to identify specific context while backend performs a cross-process navigation.\n\tAuxData  jsontext.Value     `json:\"auxData,omitempty,omitzero\"`\n}\n\n// ExceptionDetails detailed information about exception (or error) that was\n// thrown during script compilation or execution.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-ExceptionDetails\ntype ExceptionDetails struct {\n\tExceptionID        int64              `json:\"exceptionId\"`                           // Exception id.\n\tText               string             `json:\"text\"`                                  // Exception text, which should be used together with exception object when available.\n\tLineNumber         int64              `json:\"lineNumber\"`                            // Line number of the exception location (0-based).\n\tColumnNumber       int64              `json:\"columnNumber\"`                          // Column number of the exception location (0-based).\n\tScriptID           ScriptID           `json:\"scriptId,omitempty,omitzero\"`           // Script ID of the exception location.\n\tURL                string             `json:\"url,omitempty,omitzero\"`                // URL of the exception location, to be used when the script was not reported.\n\tStackTrace         *StackTrace        `json:\"stackTrace,omitempty,omitzero\"`         // JavaScript stack trace if available.\n\tException          *RemoteObject      `json:\"exception,omitempty,omitzero\"`          // Exception object if available.\n\tExecutionContextID ExecutionContextID `json:\"executionContextId,omitempty,omitzero\"` // Identifier of the context where exception happened.\n\tExceptionMetaData  jsontext.Value     `json:\"exceptionMetaData,omitempty,omitzero\"`\n}\n\n// Error satisfies the error interface.\nfunc (e *ExceptionDetails) Error() string {\n\tvar b strings.Builder\n\t// TODO: watch script parsed events and match the ExceptionDetails.ScriptID\n\t// to the name/location of the actual code and display here\n\tfmt.Fprintf(&b, \"exception %q (%d:%d)\", e.Text, e.LineNumber, e.ColumnNumber)\n\tif obj := e.Exception; obj != nil {\n\t\tfmt.Fprintf(&b, \": %s\", obj.Description)\n\t}\n\treturn b.String()\n}\n\n// Timestamp number of milliseconds since epoch.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-Timestamp\ntype Timestamp time.Time\n\n// Time returns the Timestamp as time.Time value.\nfunc (t Timestamp) Time() time.Time {\n\treturn time.Time(t)\n}\n\n// MarshalJSON satisfies [json.Marshaler].\nfunc (t Timestamp) MarshalJSON() ([]byte, error) {\n\tv := float64(time.Time(t).UnixNano() / int64(time.Millisecond))\n\treturn strconv.AppendFloat(make([]byte, 0, 20), v, 'f', -1, 64), nil\n}\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Timestamp) UnmarshalJSON(buf []byte) error {\n\tf, err := strconv.ParseFloat(string(buf), 64)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*t = Timestamp(time.Unix(0, int64(f*float64(time.Millisecond))))\n\treturn nil\n}\n\n// TimeDelta number of milliseconds.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-TimeDelta\ntype TimeDelta float64\n\n// Float64 returns the TimeDelta as float64 value.\nfunc (t TimeDelta) Float64() float64 {\n\treturn float64(t)\n}\n\n// CallFrame stack entry for runtime errors and assertions.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-CallFrame\ntype CallFrame struct {\n\tFunctionName string   `json:\"functionName\"` // JavaScript function name.\n\tScriptID     ScriptID `json:\"scriptId\"`     // JavaScript script id.\n\tURL          string   `json:\"url\"`          // JavaScript script name or url.\n\tLineNumber   int64    `json:\"lineNumber\"`   // JavaScript script line number (0-based).\n\tColumnNumber int64    `json:\"columnNumber\"` // JavaScript script column number (0-based).\n}\n\n// StackTrace call frames for assertions or error messages.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-StackTrace\ntype StackTrace struct {\n\tDescription string        `json:\"description,omitempty,omitzero\"` // String label of this stack trace. For async traces this may be a name of the function that initiated the async call.\n\tCallFrames  []*CallFrame  `json:\"callFrames\"`                     // JavaScript function name.\n\tParent      *StackTrace   `json:\"parent,omitempty,omitzero\"`      // Asynchronous JavaScript stack trace that preceded this stack, if available.\n\tParentID    *StackTraceID `json:\"parentId,omitempty,omitzero\"`    // Asynchronous JavaScript stack trace that preceded this stack, if available.\n}\n\n// UniqueDebuggerID unique identifier of current debugger.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-UniqueDebuggerId\ntype UniqueDebuggerID string\n\n// String returns the UniqueDebuggerID as string value.\nfunc (t UniqueDebuggerID) String() string {\n\treturn string(t)\n}\n\n// StackTraceID if debuggerId is set stack trace comes from another debugger\n// and can be resolved there. This allows to track cross-debugger calls. See\n// Runtime.StackTrace and Debugger.paused for usages.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-StackTraceId\ntype StackTraceID struct {\n\tID         string           `json:\"id\"`\n\tDebuggerID UniqueDebuggerID `json:\"debuggerId,omitempty,omitzero\"`\n}\n\n// SerializationOptionsSerialization [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-SerializationOptions\ntype SerializationOptionsSerialization string\n\n// String returns the SerializationOptionsSerialization as string value.\nfunc (t SerializationOptionsSerialization) String() string {\n\treturn string(t)\n}\n\n// SerializationOptionsSerialization values.\nconst (\n\tSerializationOptionsSerializationDeep   SerializationOptionsSerialization = \"deep\"\n\tSerializationOptionsSerializationJSON   SerializationOptionsSerialization = \"json\"\n\tSerializationOptionsSerializationIDOnly SerializationOptionsSerialization = \"idOnly\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SerializationOptionsSerialization) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SerializationOptionsSerialization(s) {\n\tcase SerializationOptionsSerializationDeep:\n\t\t*t = SerializationOptionsSerializationDeep\n\tcase SerializationOptionsSerializationJSON:\n\t\t*t = SerializationOptionsSerializationJSON\n\tcase SerializationOptionsSerializationIDOnly:\n\t\t*t = SerializationOptionsSerializationIDOnly\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SerializationOptionsSerialization value: %v\", s)\n\t}\n\treturn nil\n}\n\n// DeepSerializedValueType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-DeepSerializedValue\ntype DeepSerializedValueType string\n\n// String returns the DeepSerializedValueType as string value.\nfunc (t DeepSerializedValueType) String() string {\n\treturn string(t)\n}\n\n// DeepSerializedValueType values.\nconst (\n\tDeepSerializedValueTypeUndefined   DeepSerializedValueType = \"undefined\"\n\tDeepSerializedValueTypeNull        DeepSerializedValueType = \"null\"\n\tDeepSerializedValueTypeString      DeepSerializedValueType = \"string\"\n\tDeepSerializedValueTypeNumber      DeepSerializedValueType = \"number\"\n\tDeepSerializedValueTypeBoolean     DeepSerializedValueType = \"boolean\"\n\tDeepSerializedValueTypeBigint      DeepSerializedValueType = \"bigint\"\n\tDeepSerializedValueTypeRegexp      DeepSerializedValueType = \"regexp\"\n\tDeepSerializedValueTypeDate        DeepSerializedValueType = \"date\"\n\tDeepSerializedValueTypeSymbol      DeepSerializedValueType = \"symbol\"\n\tDeepSerializedValueTypeArray       DeepSerializedValueType = \"array\"\n\tDeepSerializedValueTypeObject      DeepSerializedValueType = \"object\"\n\tDeepSerializedValueTypeFunction    DeepSerializedValueType = \"function\"\n\tDeepSerializedValueTypeMap         DeepSerializedValueType = \"map\"\n\tDeepSerializedValueTypeSet         DeepSerializedValueType = \"set\"\n\tDeepSerializedValueTypeWeakmap     DeepSerializedValueType = \"weakmap\"\n\tDeepSerializedValueTypeWeakset     DeepSerializedValueType = \"weakset\"\n\tDeepSerializedValueTypeError       DeepSerializedValueType = \"error\"\n\tDeepSerializedValueTypeProxy       DeepSerializedValueType = \"proxy\"\n\tDeepSerializedValueTypePromise     DeepSerializedValueType = \"promise\"\n\tDeepSerializedValueTypeTypedarray  DeepSerializedValueType = \"typedarray\"\n\tDeepSerializedValueTypeArraybuffer DeepSerializedValueType = \"arraybuffer\"\n\tDeepSerializedValueTypeNode        DeepSerializedValueType = \"node\"\n\tDeepSerializedValueTypeWindow      DeepSerializedValueType = \"window\"\n\tDeepSerializedValueTypeGenerator   DeepSerializedValueType = \"generator\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *DeepSerializedValueType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch DeepSerializedValueType(s) {\n\tcase DeepSerializedValueTypeUndefined:\n\t\t*t = DeepSerializedValueTypeUndefined\n\tcase DeepSerializedValueTypeNull:\n\t\t*t = DeepSerializedValueTypeNull\n\tcase DeepSerializedValueTypeString:\n\t\t*t = DeepSerializedValueTypeString\n\tcase DeepSerializedValueTypeNumber:\n\t\t*t = DeepSerializedValueTypeNumber\n\tcase DeepSerializedValueTypeBoolean:\n\t\t*t = DeepSerializedValueTypeBoolean\n\tcase DeepSerializedValueTypeBigint:\n\t\t*t = DeepSerializedValueTypeBigint\n\tcase DeepSerializedValueTypeRegexp:\n\t\t*t = DeepSerializedValueTypeRegexp\n\tcase DeepSerializedValueTypeDate:\n\t\t*t = DeepSerializedValueTypeDate\n\tcase DeepSerializedValueTypeSymbol:\n\t\t*t = DeepSerializedValueTypeSymbol\n\tcase DeepSerializedValueTypeArray:\n\t\t*t = DeepSerializedValueTypeArray\n\tcase DeepSerializedValueTypeObject:\n\t\t*t = DeepSerializedValueTypeObject\n\tcase DeepSerializedValueTypeFunction:\n\t\t*t = DeepSerializedValueTypeFunction\n\tcase DeepSerializedValueTypeMap:\n\t\t*t = DeepSerializedValueTypeMap\n\tcase DeepSerializedValueTypeSet:\n\t\t*t = DeepSerializedValueTypeSet\n\tcase DeepSerializedValueTypeWeakmap:\n\t\t*t = DeepSerializedValueTypeWeakmap\n\tcase DeepSerializedValueTypeWeakset:\n\t\t*t = DeepSerializedValueTypeWeakset\n\tcase DeepSerializedValueTypeError:\n\t\t*t = DeepSerializedValueTypeError\n\tcase DeepSerializedValueTypeProxy:\n\t\t*t = DeepSerializedValueTypeProxy\n\tcase DeepSerializedValueTypePromise:\n\t\t*t = DeepSerializedValueTypePromise\n\tcase DeepSerializedValueTypeTypedarray:\n\t\t*t = DeepSerializedValueTypeTypedarray\n\tcase DeepSerializedValueTypeArraybuffer:\n\t\t*t = DeepSerializedValueTypeArraybuffer\n\tcase DeepSerializedValueTypeNode:\n\t\t*t = DeepSerializedValueTypeNode\n\tcase DeepSerializedValueTypeWindow:\n\t\t*t = DeepSerializedValueTypeWindow\n\tcase DeepSerializedValueTypeGenerator:\n\t\t*t = DeepSerializedValueTypeGenerator\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown DeepSerializedValueType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Type object type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-RemoteObject\ntype Type string\n\n// String returns the Type as string value.\nfunc (t Type) String() string {\n\treturn string(t)\n}\n\n// Type values.\nconst (\n\tTypeObject    Type = \"object\"\n\tTypeFunction  Type = \"function\"\n\tTypeUndefined Type = \"undefined\"\n\tTypeString    Type = \"string\"\n\tTypeNumber    Type = \"number\"\n\tTypeBoolean   Type = \"boolean\"\n\tTypeSymbol    Type = \"symbol\"\n\tTypeBigint    Type = \"bigint\"\n\tTypeAccessor  Type = \"accessor\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Type) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Type(s) {\n\tcase TypeObject:\n\t\t*t = TypeObject\n\tcase TypeFunction:\n\t\t*t = TypeFunction\n\tcase TypeUndefined:\n\t\t*t = TypeUndefined\n\tcase TypeString:\n\t\t*t = TypeString\n\tcase TypeNumber:\n\t\t*t = TypeNumber\n\tcase TypeBoolean:\n\t\t*t = TypeBoolean\n\tcase TypeSymbol:\n\t\t*t = TypeSymbol\n\tcase TypeBigint:\n\t\t*t = TypeBigint\n\tcase TypeAccessor:\n\t\t*t = TypeAccessor\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Type value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Subtype object subtype hint. Specified for object type values only. NOTE:\n// If you change anything here, make sure to also update subtype in\n// ObjectPreview and PropertyPreview below.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-RemoteObject\ntype Subtype string\n\n// String returns the Subtype as string value.\nfunc (t Subtype) String() string {\n\treturn string(t)\n}\n\n// Subtype values.\nconst (\n\tSubtypeArray             Subtype = \"array\"\n\tSubtypeNull              Subtype = \"null\"\n\tSubtypeNode              Subtype = \"node\"\n\tSubtypeRegexp            Subtype = \"regexp\"\n\tSubtypeDate              Subtype = \"date\"\n\tSubtypeMap               Subtype = \"map\"\n\tSubtypeSet               Subtype = \"set\"\n\tSubtypeWeakmap           Subtype = \"weakmap\"\n\tSubtypeWeakset           Subtype = \"weakset\"\n\tSubtypeIterator          Subtype = \"iterator\"\n\tSubtypeGenerator         Subtype = \"generator\"\n\tSubtypeError             Subtype = \"error\"\n\tSubtypeProxy             Subtype = \"proxy\"\n\tSubtypePromise           Subtype = \"promise\"\n\tSubtypeTypedarray        Subtype = \"typedarray\"\n\tSubtypeArraybuffer       Subtype = \"arraybuffer\"\n\tSubtypeDataview          Subtype = \"dataview\"\n\tSubtypeWebassemblymemory Subtype = \"webassemblymemory\"\n\tSubtypeWasmvalue         Subtype = \"wasmvalue\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Subtype) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Subtype(s) {\n\tcase SubtypeArray:\n\t\t*t = SubtypeArray\n\tcase SubtypeNull:\n\t\t*t = SubtypeNull\n\tcase SubtypeNode:\n\t\t*t = SubtypeNode\n\tcase SubtypeRegexp:\n\t\t*t = SubtypeRegexp\n\tcase SubtypeDate:\n\t\t*t = SubtypeDate\n\tcase SubtypeMap:\n\t\t*t = SubtypeMap\n\tcase SubtypeSet:\n\t\t*t = SubtypeSet\n\tcase SubtypeWeakmap:\n\t\t*t = SubtypeWeakmap\n\tcase SubtypeWeakset:\n\t\t*t = SubtypeWeakset\n\tcase SubtypeIterator:\n\t\t*t = SubtypeIterator\n\tcase SubtypeGenerator:\n\t\t*t = SubtypeGenerator\n\tcase SubtypeError:\n\t\t*t = SubtypeError\n\tcase SubtypeProxy:\n\t\t*t = SubtypeProxy\n\tcase SubtypePromise:\n\t\t*t = SubtypePromise\n\tcase SubtypeTypedarray:\n\t\t*t = SubtypeTypedarray\n\tcase SubtypeArraybuffer:\n\t\t*t = SubtypeArraybuffer\n\tcase SubtypeDataview:\n\t\t*t = SubtypeDataview\n\tcase SubtypeWebassemblymemory:\n\t\t*t = SubtypeWebassemblymemory\n\tcase SubtypeWasmvalue:\n\t\t*t = SubtypeWasmvalue\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Subtype value: %v\", s)\n\t}\n\treturn nil\n}\n\n// APIType type of the call.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime#event-consoleAPICalled\ntype APIType string\n\n// String returns the APIType as string value.\nfunc (t APIType) String() string {\n\treturn string(t)\n}\n\n// APIType values.\nconst (\n\tAPITypeLog                 APIType = \"log\"\n\tAPITypeDebug               APIType = \"debug\"\n\tAPITypeInfo                APIType = \"info\"\n\tAPITypeError               APIType = \"error\"\n\tAPITypeWarning             APIType = \"warning\"\n\tAPITypeDir                 APIType = \"dir\"\n\tAPITypeDirxml              APIType = \"dirxml\"\n\tAPITypeTable               APIType = \"table\"\n\tAPITypeTrace               APIType = \"trace\"\n\tAPITypeClear               APIType = \"clear\"\n\tAPITypeStartGroup          APIType = \"startGroup\"\n\tAPITypeStartGroupCollapsed APIType = \"startGroupCollapsed\"\n\tAPITypeEndGroup            APIType = \"endGroup\"\n\tAPITypeAssert              APIType = \"assert\"\n\tAPITypeProfile             APIType = \"profile\"\n\tAPITypeProfileEnd          APIType = \"profileEnd\"\n\tAPITypeCount               APIType = \"count\"\n\tAPITypeTimeEnd             APIType = \"timeEnd\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *APIType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch APIType(s) {\n\tcase APITypeLog:\n\t\t*t = APITypeLog\n\tcase APITypeDebug:\n\t\t*t = APITypeDebug\n\tcase APITypeInfo:\n\t\t*t = APITypeInfo\n\tcase APITypeError:\n\t\t*t = APITypeError\n\tcase APITypeWarning:\n\t\t*t = APITypeWarning\n\tcase APITypeDir:\n\t\t*t = APITypeDir\n\tcase APITypeDirxml:\n\t\t*t = APITypeDirxml\n\tcase APITypeTable:\n\t\t*t = APITypeTable\n\tcase APITypeTrace:\n\t\t*t = APITypeTrace\n\tcase APITypeClear:\n\t\t*t = APITypeClear\n\tcase APITypeStartGroup:\n\t\t*t = APITypeStartGroup\n\tcase APITypeStartGroupCollapsed:\n\t\t*t = APITypeStartGroupCollapsed\n\tcase APITypeEndGroup:\n\t\t*t = APITypeEndGroup\n\tcase APITypeAssert:\n\t\t*t = APITypeAssert\n\tcase APITypeProfile:\n\t\t*t = APITypeProfile\n\tcase APITypeProfileEnd:\n\t\t*t = APITypeProfileEnd\n\tcase APITypeCount:\n\t\t*t = APITypeCount\n\tcase APITypeTimeEnd:\n\t\t*t = APITypeTimeEnd\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown APIType value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/security/events.go",
    "content": "package security\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventVisibleSecurityStateChanged the security state of the page changed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#event-visibleSecurityStateChanged\ntype EventVisibleSecurityStateChanged struct {\n\tVisibleSecurityState *VisibleSecurityState `json:\"visibleSecurityState\"` // Security state information about the page.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/security/security.go",
    "content": "// Package security provides the Chrome DevTools Protocol\n// commands, types, and events for the Security domain.\n//\n// Security.\n//\n// Generated by the cdproto-gen command.\npackage security\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// DisableParams disables tracking security state changes.\ntype DisableParams struct{}\n\n// Disable disables tracking security state changes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes Security.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// EnableParams enables tracking security state changes.\ntype EnableParams struct{}\n\n// Enable enables tracking security state changes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes Security.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// SetIgnoreCertificateErrorsParams enable/disable whether all certificate\n// errors should be ignored.\ntype SetIgnoreCertificateErrorsParams struct {\n\tIgnore bool `json:\"ignore\"` // If true, all certificate errors will be ignored.\n}\n\n// SetIgnoreCertificateErrors enable/disable whether all certificate errors\n// should be ignored.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#method-setIgnoreCertificateErrors\n//\n// parameters:\n//\n//\tignore - If true, all certificate errors will be ignored.\nfunc SetIgnoreCertificateErrors(ignore bool) *SetIgnoreCertificateErrorsParams {\n\treturn &SetIgnoreCertificateErrorsParams{\n\t\tIgnore: ignore,\n\t}\n}\n\n// Do executes Security.setIgnoreCertificateErrors against the provided context.\nfunc (p *SetIgnoreCertificateErrorsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetIgnoreCertificateErrors, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandDisable                    = \"Security.disable\"\n\tCommandEnable                     = \"Security.enable\"\n\tCommandSetIgnoreCertificateErrors = \"Security.setIgnoreCertificateErrors\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/security/types.go",
    "content": "package security\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// CertificateID an internal certificate ID value.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-CertificateId\ntype CertificateID int64\n\n// Int64 returns the CertificateID as int64 value.\nfunc (t CertificateID) Int64() int64 {\n\treturn int64(t)\n}\n\n// MixedContentType a description of mixed content (HTTP resources on HTTPS\n// pages), as defined by https://www.w3.org/TR/mixed-content/#categories.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-MixedContentType\ntype MixedContentType string\n\n// String returns the MixedContentType as string value.\nfunc (t MixedContentType) String() string {\n\treturn string(t)\n}\n\n// MixedContentType values.\nconst (\n\tMixedContentTypeBlockable           MixedContentType = \"blockable\"\n\tMixedContentTypeOptionallyBlockable MixedContentType = \"optionally-blockable\"\n\tMixedContentTypeNone                MixedContentType = \"none\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MixedContentType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch MixedContentType(s) {\n\tcase MixedContentTypeBlockable:\n\t\t*t = MixedContentTypeBlockable\n\tcase MixedContentTypeOptionallyBlockable:\n\t\t*t = MixedContentTypeOptionallyBlockable\n\tcase MixedContentTypeNone:\n\t\t*t = MixedContentTypeNone\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MixedContentType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// State the security level of a page or resource.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-SecurityState\ntype State string\n\n// String returns the State as string value.\nfunc (t State) String() string {\n\treturn string(t)\n}\n\n// State values.\nconst (\n\tStateUnknown        State = \"unknown\"\n\tStateNeutral        State = \"neutral\"\n\tStateInsecure       State = \"insecure\"\n\tStateSecure         State = \"secure\"\n\tStateInfo           State = \"info\"\n\tStateInsecureBroken State = \"insecure-broken\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *State) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch State(s) {\n\tcase StateUnknown:\n\t\t*t = StateUnknown\n\tcase StateNeutral:\n\t\t*t = StateNeutral\n\tcase StateInsecure:\n\t\t*t = StateInsecure\n\tcase StateSecure:\n\t\t*t = StateSecure\n\tcase StateInfo:\n\t\t*t = StateInfo\n\tcase StateInsecureBroken:\n\t\t*t = StateInsecureBroken\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown State value: %v\", s)\n\t}\n\treturn nil\n}\n\n// CertificateSecurityState details about the security state of the page\n// certificate.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-CertificateSecurityState\ntype CertificateSecurityState struct {\n\tProtocol                    string              `json:\"protocol\"`                                   // Protocol name (e.g. \"TLS 1.2\" or \"QUIC\").\n\tKeyExchange                 string              `json:\"keyExchange\"`                                // Key Exchange used by the connection, or the empty string if not applicable.\n\tKeyExchangeGroup            string              `json:\"keyExchangeGroup,omitempty,omitzero\"`        // (EC)DH group used by the connection, if applicable.\n\tCipher                      string              `json:\"cipher\"`                                     // Cipher name.\n\tMac                         string              `json:\"mac,omitempty,omitzero\"`                     // TLS MAC. Note that AEAD ciphers do not have separate MACs.\n\tCertificate                 []string            `json:\"certificate\"`                                // Page certificate.\n\tSubjectName                 string              `json:\"subjectName\"`                                // Certificate subject name.\n\tIssuer                      string              `json:\"issuer\"`                                     // Name of the issuing CA.\n\tValidFrom                   *cdp.TimeSinceEpoch `json:\"validFrom\"`                                  // Certificate valid from date.\n\tValidTo                     *cdp.TimeSinceEpoch `json:\"validTo\"`                                    // Certificate valid to (expiration) date\n\tCertificateNetworkError     string              `json:\"certificateNetworkError,omitempty,omitzero\"` // The highest priority network error code, if the certificate has an error.\n\tCertificateHasWeakSignature bool                `json:\"certificateHasWeakSignature\"`                // True if the certificate uses a weak signature algorithm.\n\tCertificateHasSha1signature bool                `json:\"certificateHasSha1Signature\"`                // True if the certificate has a SHA1 signature in the chain.\n\tModernSSL                   bool                `json:\"modernSSL\"`                                  // True if modern SSL\n\tObsoleteSslProtocol         bool                `json:\"obsoleteSslProtocol\"`                        // True if the connection is using an obsolete SSL protocol.\n\tObsoleteSslKeyExchange      bool                `json:\"obsoleteSslKeyExchange\"`                     // True if the connection is using an obsolete SSL key exchange.\n\tObsoleteSslCipher           bool                `json:\"obsoleteSslCipher\"`                          // True if the connection is using an obsolete SSL cipher.\n\tObsoleteSslSignature        bool                `json:\"obsoleteSslSignature\"`                       // True if the connection is using an obsolete SSL signature.\n}\n\n// SafetyTipStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-SafetyTipStatus\ntype SafetyTipStatus string\n\n// String returns the SafetyTipStatus as string value.\nfunc (t SafetyTipStatus) String() string {\n\treturn string(t)\n}\n\n// SafetyTipStatus values.\nconst (\n\tSafetyTipStatusBadReputation SafetyTipStatus = \"badReputation\"\n\tSafetyTipStatusLookalike     SafetyTipStatus = \"lookalike\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SafetyTipStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SafetyTipStatus(s) {\n\tcase SafetyTipStatusBadReputation:\n\t\t*t = SafetyTipStatusBadReputation\n\tcase SafetyTipStatusLookalike:\n\t\t*t = SafetyTipStatusLookalike\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SafetyTipStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SafetyTipInfo [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-SafetyTipInfo\ntype SafetyTipInfo struct {\n\tSafetyTipStatus SafetyTipStatus `json:\"safetyTipStatus\"`            // Describes whether the page triggers any safety tips or reputation warnings. Default is unknown.\n\tSafeURL         string          `json:\"safeUrl,omitempty,omitzero\"` // The URL the safety tip suggested (\"Did you mean?\"). Only filled in for lookalike matches.\n}\n\n// VisibleSecurityState security state information about the page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-VisibleSecurityState\ntype VisibleSecurityState struct {\n\tSecurityState            State                     `json:\"securityState\"`                               // The security level of the page.\n\tCertificateSecurityState *CertificateSecurityState `json:\"certificateSecurityState,omitempty,omitzero\"` // Security state details about the page certificate.\n\tSafetyTipInfo            *SafetyTipInfo            `json:\"safetyTipInfo,omitempty,omitzero\"`            // The type of Safety Tip triggered on the page. Note that this field will be set even if the Safety Tip UI was not actually shown.\n\tSecurityStateIssueIDs    []string                  `json:\"securityStateIssueIds\"`                       // Array of security state issues ids.\n}\n\n// StateExplanation an explanation of an factor contributing to the security\n// state.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-SecurityStateExplanation\ntype StateExplanation struct {\n\tSecurityState    State            `json:\"securityState\"`                      // Security state representing the severity of the factor being explained.\n\tTitle            string           `json:\"title\"`                              // Title describing the type of factor.\n\tSummary          string           `json:\"summary\"`                            // Short phrase describing the type of factor.\n\tDescription      string           `json:\"description\"`                        // Full text explanation of the factor.\n\tMixedContentType MixedContentType `json:\"mixedContentType\"`                   // The type of mixed content described by the explanation.\n\tCertificate      []string         `json:\"certificate\"`                        // Page certificate.\n\tRecommendations  []string         `json:\"recommendations,omitempty,omitzero\"` // Recommendations to fix any issues.\n}\n\n// CertificateErrorAction the action to take when a certificate error occurs.\n// continue will continue processing the request and cancel will cancel the\n// request.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Security#type-CertificateErrorAction\ntype CertificateErrorAction string\n\n// String returns the CertificateErrorAction as string value.\nfunc (t CertificateErrorAction) String() string {\n\treturn string(t)\n}\n\n// CertificateErrorAction values.\nconst (\n\tCertificateErrorActionContinue CertificateErrorAction = \"continue\"\n\tCertificateErrorActionCancel   CertificateErrorAction = \"cancel\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *CertificateErrorAction) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch CertificateErrorAction(s) {\n\tcase CertificateErrorActionContinue:\n\t\t*t = CertificateErrorActionContinue\n\tcase CertificateErrorActionCancel:\n\t\t*t = CertificateErrorActionCancel\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown CertificateErrorAction value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/serviceworker/events.go",
    "content": "package serviceworker\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventWorkerErrorReported [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#event-workerErrorReported\ntype EventWorkerErrorReported struct {\n\tErrorMessage *ErrorMessage `json:\"errorMessage\"`\n}\n\n// EventWorkerRegistrationUpdated [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#event-workerRegistrationUpdated\ntype EventWorkerRegistrationUpdated struct {\n\tRegistrations []*Registration `json:\"registrations\"`\n}\n\n// EventWorkerVersionUpdated [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#event-workerVersionUpdated\ntype EventWorkerVersionUpdated struct {\n\tVersions []*Version `json:\"versions\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/serviceworker/serviceworker.go",
    "content": "// Package serviceworker provides the Chrome DevTools Protocol\n// commands, types, and events for the ServiceWorker domain.\n//\n// Generated by the cdproto-gen command.\npackage serviceworker\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// DeliverPushMessageParams [no description].\ntype DeliverPushMessageParams struct {\n\tOrigin         string         `json:\"origin\"`\n\tRegistrationID RegistrationID `json:\"registrationId\"`\n\tData           string         `json:\"data\"`\n}\n\n// DeliverPushMessage [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-deliverPushMessage\n//\n// parameters:\n//\n//\torigin\n//\tregistrationID\n//\tdata\nfunc DeliverPushMessage(origin string, registrationID RegistrationID, data string) *DeliverPushMessageParams {\n\treturn &DeliverPushMessageParams{\n\t\tOrigin:         origin,\n\t\tRegistrationID: registrationID,\n\t\tData:           data,\n\t}\n}\n\n// Do executes ServiceWorker.deliverPushMessage against the provided context.\nfunc (p *DeliverPushMessageParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeliverPushMessage, p, nil)\n}\n\n// DisableParams [no description].\ntype DisableParams struct{}\n\n// Disable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes ServiceWorker.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// DispatchSyncEventParams [no description].\ntype DispatchSyncEventParams struct {\n\tOrigin         string         `json:\"origin\"`\n\tRegistrationID RegistrationID `json:\"registrationId\"`\n\tTag            string         `json:\"tag\"`\n\tLastChance     bool           `json:\"lastChance\"`\n}\n\n// DispatchSyncEvent [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-dispatchSyncEvent\n//\n// parameters:\n//\n//\torigin\n//\tregistrationID\n//\ttag\n//\tlastChance\nfunc DispatchSyncEvent(origin string, registrationID RegistrationID, tag string, lastChance bool) *DispatchSyncEventParams {\n\treturn &DispatchSyncEventParams{\n\t\tOrigin:         origin,\n\t\tRegistrationID: registrationID,\n\t\tTag:            tag,\n\t\tLastChance:     lastChance,\n\t}\n}\n\n// Do executes ServiceWorker.dispatchSyncEvent against the provided context.\nfunc (p *DispatchSyncEventParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDispatchSyncEvent, p, nil)\n}\n\n// DispatchPeriodicSyncEventParams [no description].\ntype DispatchPeriodicSyncEventParams struct {\n\tOrigin         string         `json:\"origin\"`\n\tRegistrationID RegistrationID `json:\"registrationId\"`\n\tTag            string         `json:\"tag\"`\n}\n\n// DispatchPeriodicSyncEvent [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-dispatchPeriodicSyncEvent\n//\n// parameters:\n//\n//\torigin\n//\tregistrationID\n//\ttag\nfunc DispatchPeriodicSyncEvent(origin string, registrationID RegistrationID, tag string) *DispatchPeriodicSyncEventParams {\n\treturn &DispatchPeriodicSyncEventParams{\n\t\tOrigin:         origin,\n\t\tRegistrationID: registrationID,\n\t\tTag:            tag,\n\t}\n}\n\n// Do executes ServiceWorker.dispatchPeriodicSyncEvent against the provided context.\nfunc (p *DispatchPeriodicSyncEventParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDispatchPeriodicSyncEvent, p, nil)\n}\n\n// EnableParams [no description].\ntype EnableParams struct{}\n\n// Enable [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes ServiceWorker.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// SetForceUpdateOnPageLoadParams [no description].\ntype SetForceUpdateOnPageLoadParams struct {\n\tForceUpdateOnPageLoad bool `json:\"forceUpdateOnPageLoad\"`\n}\n\n// SetForceUpdateOnPageLoad [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-setForceUpdateOnPageLoad\n//\n// parameters:\n//\n//\tforceUpdateOnPageLoad\nfunc SetForceUpdateOnPageLoad(forceUpdateOnPageLoad bool) *SetForceUpdateOnPageLoadParams {\n\treturn &SetForceUpdateOnPageLoadParams{\n\t\tForceUpdateOnPageLoad: forceUpdateOnPageLoad,\n\t}\n}\n\n// Do executes ServiceWorker.setForceUpdateOnPageLoad against the provided context.\nfunc (p *SetForceUpdateOnPageLoadParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetForceUpdateOnPageLoad, p, nil)\n}\n\n// SkipWaitingParams [no description].\ntype SkipWaitingParams struct {\n\tScopeURL string `json:\"scopeURL\"`\n}\n\n// SkipWaiting [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-skipWaiting\n//\n// parameters:\n//\n//\tscopeURL\nfunc SkipWaiting(scopeURL string) *SkipWaitingParams {\n\treturn &SkipWaitingParams{\n\t\tScopeURL: scopeURL,\n\t}\n}\n\n// Do executes ServiceWorker.skipWaiting against the provided context.\nfunc (p *SkipWaitingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSkipWaiting, p, nil)\n}\n\n// StartWorkerParams [no description].\ntype StartWorkerParams struct {\n\tScopeURL string `json:\"scopeURL\"`\n}\n\n// StartWorker [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-startWorker\n//\n// parameters:\n//\n//\tscopeURL\nfunc StartWorker(scopeURL string) *StartWorkerParams {\n\treturn &StartWorkerParams{\n\t\tScopeURL: scopeURL,\n\t}\n}\n\n// Do executes ServiceWorker.startWorker against the provided context.\nfunc (p *StartWorkerParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStartWorker, p, nil)\n}\n\n// StopAllWorkersParams [no description].\ntype StopAllWorkersParams struct{}\n\n// StopAllWorkers [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-stopAllWorkers\nfunc StopAllWorkers() *StopAllWorkersParams {\n\treturn &StopAllWorkersParams{}\n}\n\n// Do executes ServiceWorker.stopAllWorkers against the provided context.\nfunc (p *StopAllWorkersParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopAllWorkers, nil, nil)\n}\n\n// StopWorkerParams [no description].\ntype StopWorkerParams struct {\n\tVersionID string `json:\"versionId\"`\n}\n\n// StopWorker [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-stopWorker\n//\n// parameters:\n//\n//\tversionID\nfunc StopWorker(versionID string) *StopWorkerParams {\n\treturn &StopWorkerParams{\n\t\tVersionID: versionID,\n\t}\n}\n\n// Do executes ServiceWorker.stopWorker against the provided context.\nfunc (p *StopWorkerParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStopWorker, p, nil)\n}\n\n// UnregisterParams [no description].\ntype UnregisterParams struct {\n\tScopeURL string `json:\"scopeURL\"`\n}\n\n// Unregister [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-unregister\n//\n// parameters:\n//\n//\tscopeURL\nfunc Unregister(scopeURL string) *UnregisterParams {\n\treturn &UnregisterParams{\n\t\tScopeURL: scopeURL,\n\t}\n}\n\n// Do executes ServiceWorker.unregister against the provided context.\nfunc (p *UnregisterParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUnregister, p, nil)\n}\n\n// UpdateRegistrationParams [no description].\ntype UpdateRegistrationParams struct {\n\tScopeURL string `json:\"scopeURL\"`\n}\n\n// UpdateRegistration [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#method-updateRegistration\n//\n// parameters:\n//\n//\tscopeURL\nfunc UpdateRegistration(scopeURL string) *UpdateRegistrationParams {\n\treturn &UpdateRegistrationParams{\n\t\tScopeURL: scopeURL,\n\t}\n}\n\n// Do executes ServiceWorker.updateRegistration against the provided context.\nfunc (p *UpdateRegistrationParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUpdateRegistration, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandDeliverPushMessage        = \"ServiceWorker.deliverPushMessage\"\n\tCommandDisable                   = \"ServiceWorker.disable\"\n\tCommandDispatchSyncEvent         = \"ServiceWorker.dispatchSyncEvent\"\n\tCommandDispatchPeriodicSyncEvent = \"ServiceWorker.dispatchPeriodicSyncEvent\"\n\tCommandEnable                    = \"ServiceWorker.enable\"\n\tCommandSetForceUpdateOnPageLoad  = \"ServiceWorker.setForceUpdateOnPageLoad\"\n\tCommandSkipWaiting               = \"ServiceWorker.skipWaiting\"\n\tCommandStartWorker               = \"ServiceWorker.startWorker\"\n\tCommandStopAllWorkers            = \"ServiceWorker.stopAllWorkers\"\n\tCommandStopWorker                = \"ServiceWorker.stopWorker\"\n\tCommandUnregister                = \"ServiceWorker.unregister\"\n\tCommandUpdateRegistration        = \"ServiceWorker.updateRegistration\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/serviceworker/types.go",
    "content": "package serviceworker\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/target\"\n)\n\n// RegistrationID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-RegistrationID\ntype RegistrationID string\n\n// String returns the RegistrationID as string value.\nfunc (t RegistrationID) String() string {\n\treturn string(t)\n}\n\n// Registration serviceWorker registration.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerRegistration\ntype Registration struct {\n\tRegistrationID RegistrationID `json:\"registrationId\"`\n\tScopeURL       string         `json:\"scopeURL\"`\n\tIsDeleted      bool           `json:\"isDeleted\"`\n}\n\n// VersionRunningStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerVersionRunningStatus\ntype VersionRunningStatus string\n\n// String returns the VersionRunningStatus as string value.\nfunc (t VersionRunningStatus) String() string {\n\treturn string(t)\n}\n\n// VersionRunningStatus values.\nconst (\n\tVersionRunningStatusStopped  VersionRunningStatus = \"stopped\"\n\tVersionRunningStatusStarting VersionRunningStatus = \"starting\"\n\tVersionRunningStatusRunning  VersionRunningStatus = \"running\"\n\tVersionRunningStatusStopping VersionRunningStatus = \"stopping\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *VersionRunningStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch VersionRunningStatus(s) {\n\tcase VersionRunningStatusStopped:\n\t\t*t = VersionRunningStatusStopped\n\tcase VersionRunningStatusStarting:\n\t\t*t = VersionRunningStatusStarting\n\tcase VersionRunningStatusRunning:\n\t\t*t = VersionRunningStatusRunning\n\tcase VersionRunningStatusStopping:\n\t\t*t = VersionRunningStatusStopping\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown VersionRunningStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// VersionStatus [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerVersionStatus\ntype VersionStatus string\n\n// String returns the VersionStatus as string value.\nfunc (t VersionStatus) String() string {\n\treturn string(t)\n}\n\n// VersionStatus values.\nconst (\n\tVersionStatusNew        VersionStatus = \"new\"\n\tVersionStatusInstalling VersionStatus = \"installing\"\n\tVersionStatusInstalled  VersionStatus = \"installed\"\n\tVersionStatusActivating VersionStatus = \"activating\"\n\tVersionStatusActivated  VersionStatus = \"activated\"\n\tVersionStatusRedundant  VersionStatus = \"redundant\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *VersionStatus) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch VersionStatus(s) {\n\tcase VersionStatusNew:\n\t\t*t = VersionStatusNew\n\tcase VersionStatusInstalling:\n\t\t*t = VersionStatusInstalling\n\tcase VersionStatusInstalled:\n\t\t*t = VersionStatusInstalled\n\tcase VersionStatusActivating:\n\t\t*t = VersionStatusActivating\n\tcase VersionStatusActivated:\n\t\t*t = VersionStatusActivated\n\tcase VersionStatusRedundant:\n\t\t*t = VersionStatusRedundant\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown VersionStatus value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Version serviceWorker version.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerVersion\ntype Version struct {\n\tVersionID          string               `json:\"versionId\"`\n\tRegistrationID     RegistrationID       `json:\"registrationId\"`\n\tScriptURL          string               `json:\"scriptURL\"`\n\tRunningStatus      VersionRunningStatus `json:\"runningStatus\"`\n\tStatus             VersionStatus        `json:\"status\"`\n\tScriptLastModified float64              `json:\"scriptLastModified,omitempty,omitzero\"` // The Last-Modified header value of the main script.\n\tScriptResponseTime float64              `json:\"scriptResponseTime,omitempty,omitzero\"` // The time at which the response headers of the main script were received from the server. For cached script it is the last time the cache entry was validated.\n\tControlledClients  []target.ID          `json:\"controlledClients,omitempty,omitzero\"`\n\tTargetID           target.ID            `json:\"targetId,omitempty,omitzero\"`\n\tRouterRules        string               `json:\"routerRules,omitempty,omitzero\"`\n}\n\n// ErrorMessage serviceWorker error message.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/ServiceWorker#type-ServiceWorkerErrorMessage\ntype ErrorMessage struct {\n\tErrorMessage   string         `json:\"errorMessage\"`\n\tRegistrationID RegistrationID `json:\"registrationId\"`\n\tVersionID      string         `json:\"versionId\"`\n\tSourceURL      string         `json:\"sourceURL\"`\n\tLineNumber     int64          `json:\"lineNumber\"`\n\tColumnNumber   int64          `json:\"columnNumber\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/storage/events.go",
    "content": "package storage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/chromedp/cdproto/target\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// EventCacheStorageContentUpdated a cache's contents have been modified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-cacheStorageContentUpdated\ntype EventCacheStorageContentUpdated struct {\n\tOrigin     string `json:\"origin\"`     // Origin to update.\n\tStorageKey string `json:\"storageKey\"` // Storage key to update.\n\tBucketID   string `json:\"bucketId\"`   // Storage bucket to update.\n\tCacheName  string `json:\"cacheName\"`  // Name of cache in origin.\n}\n\n// EventCacheStorageListUpdated a cache has been added/deleted.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-cacheStorageListUpdated\ntype EventCacheStorageListUpdated struct {\n\tOrigin     string `json:\"origin\"`     // Origin to update.\n\tStorageKey string `json:\"storageKey\"` // Storage key to update.\n\tBucketID   string `json:\"bucketId\"`   // Storage bucket to update.\n}\n\n// EventIndexedDBContentUpdated the origin's IndexedDB object store has been\n// modified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-indexedDBContentUpdated\ntype EventIndexedDBContentUpdated struct {\n\tOrigin          string `json:\"origin\"`          // Origin to update.\n\tStorageKey      string `json:\"storageKey\"`      // Storage key to update.\n\tBucketID        string `json:\"bucketId\"`        // Storage bucket to update.\n\tDatabaseName    string `json:\"databaseName\"`    // Database to update.\n\tObjectStoreName string `json:\"objectStoreName\"` // ObjectStore to update.\n}\n\n// EventIndexedDBListUpdated the origin's IndexedDB database list has been\n// modified.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-indexedDBListUpdated\ntype EventIndexedDBListUpdated struct {\n\tOrigin     string `json:\"origin\"`     // Origin to update.\n\tStorageKey string `json:\"storageKey\"` // Storage key to update.\n\tBucketID   string `json:\"bucketId\"`   // Storage bucket to update.\n}\n\n// EventInterestGroupAccessed one of the interest groups was accessed. Note\n// that these events are global to all targets sharing an interest group store.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-interestGroupAccessed\ntype EventInterestGroupAccessed struct {\n\tAccessTime            *cdp.TimeSinceEpoch     `json:\"accessTime\"`\n\tType                  InterestGroupAccessType `json:\"type\"`\n\tOwnerOrigin           string                  `json:\"ownerOrigin\"`\n\tName                  string                  `json:\"name\"`\n\tComponentSellerOrigin string                  `json:\"componentSellerOrigin,omitempty,omitzero\"` // For topLevelBid/topLevelAdditionalBid, and when appropriate, win and additionalBidWin\n\tBid                   float64                 `json:\"bid,omitempty,omitzero\"`                   // For bid or somethingBid event, if done locally and not on a server.\n\tBidCurrency           string                  `json:\"bidCurrency,omitempty,omitzero\"`\n\tUniqueAuctionID       InterestGroupAuctionID  `json:\"uniqueAuctionId,omitempty,omitzero\"` // For non-global events --- links to interestGroupAuctionEvent\n}\n\n// EventInterestGroupAuctionEventOccurred an auction involving interest\n// groups is taking place. These events are target-specific.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-interestGroupAuctionEventOccurred\ntype EventInterestGroupAuctionEventOccurred struct {\n\tEventTime       *cdp.TimeSinceEpoch           `json:\"eventTime\"`\n\tType            InterestGroupAuctionEventType `json:\"type\"`\n\tUniqueAuctionID InterestGroupAuctionID        `json:\"uniqueAuctionId\"`\n\tParentAuctionID InterestGroupAuctionID        `json:\"parentAuctionId,omitempty,omitzero\"` // Set for child auctions.\n\tAuctionConfig   jsontext.Value                `json:\"auctionConfig,omitempty,omitzero\"`\n}\n\n// EventInterestGroupAuctionNetworkRequestCreated specifies which auctions a\n// particular network fetch may be related to, and in what role. Note that it is\n// not ordered with respect to Network.requestWillBeSent (but will happen before\n// loadingFinished loadingFailed).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-interestGroupAuctionNetworkRequestCreated\ntype EventInterestGroupAuctionNetworkRequestCreated struct {\n\tType      InterestGroupAuctionFetchType `json:\"type\"`\n\tRequestID network.RequestID             `json:\"requestId\"`\n\tAuctions  []InterestGroupAuctionID      `json:\"auctions\"` // This is the set of the auctions using the worklet that issued this request.  In the case of trusted signals, it's possible that only some of them actually care about the keys being queried.\n}\n\n// EventSharedStorageAccessed shared storage was accessed by the associated\n// page. The following parameters are included in all events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-sharedStorageAccessed\ntype EventSharedStorageAccessed struct {\n\tAccessTime  *cdp.TimeSinceEpoch        `json:\"accessTime\"`  // Time of the access.\n\tScope       SharedStorageAccessScope   `json:\"scope\"`       // Enum value indicating the access scope.\n\tMethod      SharedStorageAccessMethod  `json:\"method\"`      // Enum value indicating the Shared Storage API method invoked.\n\tMainFrameID cdp.FrameID                `json:\"mainFrameId\"` // DevTools Frame Token for the primary frame tree's root.\n\tOwnerOrigin string                     `json:\"ownerOrigin\"` // Serialization of the origin owning the Shared Storage data.\n\tOwnerSite   string                     `json:\"ownerSite\"`   // Serialization of the site owning the Shared Storage data.\n\tParams      *SharedStorageAccessParams `json:\"params\"`      // The sub-parameters wrapped by params are all optional and their presence/absence depends on type.\n}\n\n// EventSharedStorageWorkletOperationExecutionFinished a shared storage run\n// or selectURL operation finished its execution. The following parameters are\n// included in all events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-sharedStorageWorkletOperationExecutionFinished\ntype EventSharedStorageWorkletOperationExecutionFinished struct {\n\tFinishedTime    *cdp.TimeSinceEpoch       `json:\"finishedTime\"`    // Time that the operation finished.\n\tExecutionTime   int64                     `json:\"executionTime\"`   // Time, in microseconds, from start of shared storage JS API call until end of operation execution in the worklet.\n\tMethod          SharedStorageAccessMethod `json:\"method\"`          // Enum value indicating the Shared Storage API method invoked.\n\tOperationID     string                    `json:\"operationId\"`     // ID of the operation call.\n\tWorkletTargetID target.ID                 `json:\"workletTargetId\"` // Hex representation of the DevTools token used as the TargetID for the associated shared storage worklet.\n\tMainFrameID     cdp.FrameID               `json:\"mainFrameId\"`     // DevTools Frame Token for the primary frame tree's root.\n\tOwnerOrigin     string                    `json:\"ownerOrigin\"`     // Serialization of the origin owning the Shared Storage data.\n}\n\n// EventStorageBucketCreatedOrUpdated [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-storageBucketCreatedOrUpdated\ntype EventStorageBucketCreatedOrUpdated struct {\n\tBucketInfo *BucketInfo `json:\"bucketInfo\"`\n}\n\n// EventStorageBucketDeleted [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-storageBucketDeleted\ntype EventStorageBucketDeleted struct {\n\tBucketID string `json:\"bucketId\"`\n}\n\n// EventAttributionReportingSourceRegistered [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-attributionReportingSourceRegistered\ntype EventAttributionReportingSourceRegistered struct {\n\tRegistration *AttributionReportingSourceRegistration      `json:\"registration\"`\n\tResult       AttributionReportingSourceRegistrationResult `json:\"result\"`\n}\n\n// EventAttributionReportingTriggerRegistered [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-attributionReportingTriggerRegistered\ntype EventAttributionReportingTriggerRegistered struct {\n\tRegistration *AttributionReportingTriggerRegistration `json:\"registration\"`\n\tEventLevel   AttributionReportingEventLevelResult     `json:\"eventLevel\"`\n\tAggregatable AttributionReportingAggregatableResult   `json:\"aggregatable\"`\n}\n\n// EventAttributionReportingReportSent [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-attributionReportingReportSent\ntype EventAttributionReportingReportSent struct {\n\tURL            string                           `json:\"url\"`\n\tBody           jsontext.Value                   `json:\"body\"`\n\tResult         AttributionReportingReportResult `json:\"result\"`\n\tNetError       int64                            `json:\"netError,omitempty,omitzero\"` // If result is sent, populated with net/HTTP status.\n\tNetErrorName   string                           `json:\"netErrorName,omitempty,omitzero\"`\n\tHTTPStatusCode int64                            `json:\"httpStatusCode,omitempty,omitzero\"`\n}\n\n// EventAttributionReportingVerboseDebugReportSent [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#event-attributionReportingVerboseDebugReportSent\ntype EventAttributionReportingVerboseDebugReportSent struct {\n\tURL            string           `json:\"url\"`\n\tBody           []jsontext.Value `json:\"body,omitempty,omitzero\"`\n\tNetError       int64            `json:\"netError,omitempty,omitzero\"`\n\tNetErrorName   string           `json:\"netErrorName,omitempty,omitzero\"`\n\tHTTPStatusCode int64            `json:\"httpStatusCode,omitempty,omitzero\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/storage/storage.go",
    "content": "// Package storage provides the Chrome DevTools Protocol\n// commands, types, and events for the Storage domain.\n//\n// Generated by the cdproto-gen command.\npackage storage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/network\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// GetStorageKeyForFrameParams returns a storage key given a frame id.\ntype GetStorageKeyForFrameParams struct {\n\tFrameID cdp.FrameID `json:\"frameId\"`\n}\n\n// GetStorageKeyForFrame returns a storage key given a frame id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getStorageKeyForFrame\n//\n// parameters:\n//\n//\tframeID\nfunc GetStorageKeyForFrame(frameID cdp.FrameID) *GetStorageKeyForFrameParams {\n\treturn &GetStorageKeyForFrameParams{\n\t\tFrameID: frameID,\n\t}\n}\n\n// GetStorageKeyForFrameReturns return values.\ntype GetStorageKeyForFrameReturns struct {\n\tStorageKey SerializedStorageKey `json:\"storageKey,omitempty,omitzero\"`\n}\n\n// Do executes Storage.getStorageKeyForFrame against the provided context.\n//\n// returns:\n//\n//\tstorageKey\nfunc (p *GetStorageKeyForFrameParams) Do(ctx context.Context) (storageKey SerializedStorageKey, err error) {\n\t// execute\n\tvar res GetStorageKeyForFrameReturns\n\terr = cdp.Execute(ctx, CommandGetStorageKeyForFrame, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.StorageKey, nil\n}\n\n// ClearDataForOriginParams clears storage for origin.\ntype ClearDataForOriginParams struct {\n\tOrigin       string `json:\"origin\"`       // Security origin.\n\tStorageTypes string `json:\"storageTypes\"` // Comma separated list of StorageType to clear.\n}\n\n// ClearDataForOrigin clears storage for origin.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-clearDataForOrigin\n//\n// parameters:\n//\n//\torigin - Security origin.\n//\tstorageTypes - Comma separated list of StorageType to clear.\nfunc ClearDataForOrigin(origin string, storageTypes string) *ClearDataForOriginParams {\n\treturn &ClearDataForOriginParams{\n\t\tOrigin:       origin,\n\t\tStorageTypes: storageTypes,\n\t}\n}\n\n// Do executes Storage.clearDataForOrigin against the provided context.\nfunc (p *ClearDataForOriginParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearDataForOrigin, p, nil)\n}\n\n// ClearDataForStorageKeyParams clears storage for storage key.\ntype ClearDataForStorageKeyParams struct {\n\tStorageKey   string `json:\"storageKey\"`   // Storage key.\n\tStorageTypes string `json:\"storageTypes\"` // Comma separated list of StorageType to clear.\n}\n\n// ClearDataForStorageKey clears storage for storage key.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-clearDataForStorageKey\n//\n// parameters:\n//\n//\tstorageKey - Storage key.\n//\tstorageTypes - Comma separated list of StorageType to clear.\nfunc ClearDataForStorageKey(storageKey string, storageTypes string) *ClearDataForStorageKeyParams {\n\treturn &ClearDataForStorageKeyParams{\n\t\tStorageKey:   storageKey,\n\t\tStorageTypes: storageTypes,\n\t}\n}\n\n// Do executes Storage.clearDataForStorageKey against the provided context.\nfunc (p *ClearDataForStorageKeyParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearDataForStorageKey, p, nil)\n}\n\n// GetCookiesParams returns all browser cookies.\ntype GetCookiesParams struct {\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // Browser context to use when called on the browser endpoint.\n}\n\n// GetCookies returns all browser cookies.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getCookies\n//\n// parameters:\nfunc GetCookies() *GetCookiesParams {\n\treturn &GetCookiesParams{}\n}\n\n// WithBrowserContextID browser context to use when called on the browser\n// endpoint.\nfunc (p GetCookiesParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *GetCookiesParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// GetCookiesReturns return values.\ntype GetCookiesReturns struct {\n\tCookies []*network.Cookie `json:\"cookies,omitempty,omitzero\"` // Array of cookie objects.\n}\n\n// Do executes Storage.getCookies against the provided context.\n//\n// returns:\n//\n//\tcookies - Array of cookie objects.\nfunc (p *GetCookiesParams) Do(ctx context.Context) (cookies []*network.Cookie, err error) {\n\t// execute\n\tvar res GetCookiesReturns\n\terr = cdp.Execute(ctx, CommandGetCookies, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Cookies, nil\n}\n\n// SetCookiesParams sets given cookies.\ntype SetCookiesParams struct {\n\tCookies          []*network.CookieParam `json:\"cookies\"`                             // Cookies to be set.\n\tBrowserContextID cdp.BrowserContextID   `json:\"browserContextId,omitempty,omitzero\"` // Browser context to use when called on the browser endpoint.\n}\n\n// SetCookies sets given cookies.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setCookies\n//\n// parameters:\n//\n//\tcookies - Cookies to be set.\nfunc SetCookies(cookies []*network.CookieParam) *SetCookiesParams {\n\treturn &SetCookiesParams{\n\t\tCookies: cookies,\n\t}\n}\n\n// WithBrowserContextID browser context to use when called on the browser\n// endpoint.\nfunc (p SetCookiesParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *SetCookiesParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// Do executes Storage.setCookies against the provided context.\nfunc (p *SetCookiesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCookies, p, nil)\n}\n\n// ClearCookiesParams clears cookies.\ntype ClearCookiesParams struct {\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // Browser context to use when called on the browser endpoint.\n}\n\n// ClearCookies clears cookies.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-clearCookies\n//\n// parameters:\nfunc ClearCookies() *ClearCookiesParams {\n\treturn &ClearCookiesParams{}\n}\n\n// WithBrowserContextID browser context to use when called on the browser\n// endpoint.\nfunc (p ClearCookiesParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *ClearCookiesParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// Do executes Storage.clearCookies against the provided context.\nfunc (p *ClearCookiesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearCookies, p, nil)\n}\n\n// GetUsageAndQuotaParams returns usage and quota in bytes.\ntype GetUsageAndQuotaParams struct {\n\tOrigin string `json:\"origin\"` // Security origin.\n}\n\n// GetUsageAndQuota returns usage and quota in bytes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getUsageAndQuota\n//\n// parameters:\n//\n//\torigin - Security origin.\nfunc GetUsageAndQuota(origin string) *GetUsageAndQuotaParams {\n\treturn &GetUsageAndQuotaParams{\n\t\tOrigin: origin,\n\t}\n}\n\n// GetUsageAndQuotaReturns return values.\ntype GetUsageAndQuotaReturns struct {\n\tUsage          float64         `json:\"usage,omitempty,omitzero\"`          // Storage usage (bytes).\n\tQuota          float64         `json:\"quota,omitempty,omitzero\"`          // Storage quota (bytes).\n\tOverrideActive bool            `json:\"overrideActive\"`                    // Whether or not the origin has an active storage quota override\n\tUsageBreakdown []*UsageForType `json:\"usageBreakdown,omitempty,omitzero\"` // Storage usage per type (bytes).\n}\n\n// Do executes Storage.getUsageAndQuota against the provided context.\n//\n// returns:\n//\n//\tusage - Storage usage (bytes).\n//\tquota - Storage quota (bytes).\n//\toverrideActive - Whether or not the origin has an active storage quota override\n//\tusageBreakdown - Storage usage per type (bytes).\nfunc (p *GetUsageAndQuotaParams) Do(ctx context.Context) (usage float64, quota float64, overrideActive bool, usageBreakdown []*UsageForType, err error) {\n\t// execute\n\tvar res GetUsageAndQuotaReturns\n\terr = cdp.Execute(ctx, CommandGetUsageAndQuota, p, &res)\n\tif err != nil {\n\t\treturn 0, 0, false, nil, err\n\t}\n\n\treturn res.Usage, res.Quota, res.OverrideActive, res.UsageBreakdown, nil\n}\n\n// OverrideQuotaForOriginParams override quota for the specified origin.\ntype OverrideQuotaForOriginParams struct {\n\tOrigin    string  `json:\"origin\"`                       // Security origin.\n\tQuotaSize float64 `json:\"quotaSize,omitempty,omitzero\"` // The quota size (in bytes) to override the original quota with. If this is called multiple times, the overridden quota will be equal to the quotaSize provided in the final call. If this is called without specifying a quotaSize, the quota will be reset to the default value for the specified origin. If this is called multiple times with different origins, the override will be maintained for each origin until it is disabled (called without a quotaSize).\n}\n\n// OverrideQuotaForOrigin override quota for the specified origin.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-overrideQuotaForOrigin\n//\n// parameters:\n//\n//\torigin - Security origin.\nfunc OverrideQuotaForOrigin(origin string) *OverrideQuotaForOriginParams {\n\treturn &OverrideQuotaForOriginParams{\n\t\tOrigin: origin,\n\t}\n}\n\n// WithQuotaSize the quota size (in bytes) to override the original quota\n// with. If this is called multiple times, the overridden quota will be equal to\n// the quotaSize provided in the final call. If this is called without\n// specifying a quotaSize, the quota will be reset to the default value for the\n// specified origin. If this is called multiple times with different origins,\n// the override will be maintained for each origin until it is disabled (called\n// without a quotaSize).\nfunc (p OverrideQuotaForOriginParams) WithQuotaSize(quotaSize float64) *OverrideQuotaForOriginParams {\n\tp.QuotaSize = quotaSize\n\treturn &p\n}\n\n// Do executes Storage.overrideQuotaForOrigin against the provided context.\nfunc (p *OverrideQuotaForOriginParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandOverrideQuotaForOrigin, p, nil)\n}\n\n// TrackCacheStorageForOriginParams registers origin to be notified when an\n// update occurs to its cache storage list.\ntype TrackCacheStorageForOriginParams struct {\n\tOrigin string `json:\"origin\"` // Security origin.\n}\n\n// TrackCacheStorageForOrigin registers origin to be notified when an update\n// occurs to its cache storage list.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-trackCacheStorageForOrigin\n//\n// parameters:\n//\n//\torigin - Security origin.\nfunc TrackCacheStorageForOrigin(origin string) *TrackCacheStorageForOriginParams {\n\treturn &TrackCacheStorageForOriginParams{\n\t\tOrigin: origin,\n\t}\n}\n\n// Do executes Storage.trackCacheStorageForOrigin against the provided context.\nfunc (p *TrackCacheStorageForOriginParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTrackCacheStorageForOrigin, p, nil)\n}\n\n// TrackCacheStorageForStorageKeyParams registers storage key to be notified\n// when an update occurs to its cache storage list.\ntype TrackCacheStorageForStorageKeyParams struct {\n\tStorageKey string `json:\"storageKey\"` // Storage key.\n}\n\n// TrackCacheStorageForStorageKey registers storage key to be notified when\n// an update occurs to its cache storage list.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-trackCacheStorageForStorageKey\n//\n// parameters:\n//\n//\tstorageKey - Storage key.\nfunc TrackCacheStorageForStorageKey(storageKey string) *TrackCacheStorageForStorageKeyParams {\n\treturn &TrackCacheStorageForStorageKeyParams{\n\t\tStorageKey: storageKey,\n\t}\n}\n\n// Do executes Storage.trackCacheStorageForStorageKey against the provided context.\nfunc (p *TrackCacheStorageForStorageKeyParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTrackCacheStorageForStorageKey, p, nil)\n}\n\n// TrackIndexedDBForOriginParams registers origin to be notified when an\n// update occurs to its IndexedDB.\ntype TrackIndexedDBForOriginParams struct {\n\tOrigin string `json:\"origin\"` // Security origin.\n}\n\n// TrackIndexedDBForOrigin registers origin to be notified when an update\n// occurs to its IndexedDB.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-trackIndexedDBForOrigin\n//\n// parameters:\n//\n//\torigin - Security origin.\nfunc TrackIndexedDBForOrigin(origin string) *TrackIndexedDBForOriginParams {\n\treturn &TrackIndexedDBForOriginParams{\n\t\tOrigin: origin,\n\t}\n}\n\n// Do executes Storage.trackIndexedDBForOrigin against the provided context.\nfunc (p *TrackIndexedDBForOriginParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTrackIndexedDBForOrigin, p, nil)\n}\n\n// TrackIndexedDBForStorageKeyParams registers storage key to be notified\n// when an update occurs to its IndexedDB.\ntype TrackIndexedDBForStorageKeyParams struct {\n\tStorageKey string `json:\"storageKey\"` // Storage key.\n}\n\n// TrackIndexedDBForStorageKey registers storage key to be notified when an\n// update occurs to its IndexedDB.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-trackIndexedDBForStorageKey\n//\n// parameters:\n//\n//\tstorageKey - Storage key.\nfunc TrackIndexedDBForStorageKey(storageKey string) *TrackIndexedDBForStorageKeyParams {\n\treturn &TrackIndexedDBForStorageKeyParams{\n\t\tStorageKey: storageKey,\n\t}\n}\n\n// Do executes Storage.trackIndexedDBForStorageKey against the provided context.\nfunc (p *TrackIndexedDBForStorageKeyParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandTrackIndexedDBForStorageKey, p, nil)\n}\n\n// UntrackCacheStorageForOriginParams unregisters origin from receiving\n// notifications for cache storage.\ntype UntrackCacheStorageForOriginParams struct {\n\tOrigin string `json:\"origin\"` // Security origin.\n}\n\n// UntrackCacheStorageForOrigin unregisters origin from receiving\n// notifications for cache storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-untrackCacheStorageForOrigin\n//\n// parameters:\n//\n//\torigin - Security origin.\nfunc UntrackCacheStorageForOrigin(origin string) *UntrackCacheStorageForOriginParams {\n\treturn &UntrackCacheStorageForOriginParams{\n\t\tOrigin: origin,\n\t}\n}\n\n// Do executes Storage.untrackCacheStorageForOrigin against the provided context.\nfunc (p *UntrackCacheStorageForOriginParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUntrackCacheStorageForOrigin, p, nil)\n}\n\n// UntrackCacheStorageForStorageKeyParams unregisters storage key from\n// receiving notifications for cache storage.\ntype UntrackCacheStorageForStorageKeyParams struct {\n\tStorageKey string `json:\"storageKey\"` // Storage key.\n}\n\n// UntrackCacheStorageForStorageKey unregisters storage key from receiving\n// notifications for cache storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-untrackCacheStorageForStorageKey\n//\n// parameters:\n//\n//\tstorageKey - Storage key.\nfunc UntrackCacheStorageForStorageKey(storageKey string) *UntrackCacheStorageForStorageKeyParams {\n\treturn &UntrackCacheStorageForStorageKeyParams{\n\t\tStorageKey: storageKey,\n\t}\n}\n\n// Do executes Storage.untrackCacheStorageForStorageKey against the provided context.\nfunc (p *UntrackCacheStorageForStorageKeyParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUntrackCacheStorageForStorageKey, p, nil)\n}\n\n// UntrackIndexedDBForOriginParams unregisters origin from receiving\n// notifications for IndexedDB.\ntype UntrackIndexedDBForOriginParams struct {\n\tOrigin string `json:\"origin\"` // Security origin.\n}\n\n// UntrackIndexedDBForOrigin unregisters origin from receiving notifications\n// for IndexedDB.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-untrackIndexedDBForOrigin\n//\n// parameters:\n//\n//\torigin - Security origin.\nfunc UntrackIndexedDBForOrigin(origin string) *UntrackIndexedDBForOriginParams {\n\treturn &UntrackIndexedDBForOriginParams{\n\t\tOrigin: origin,\n\t}\n}\n\n// Do executes Storage.untrackIndexedDBForOrigin against the provided context.\nfunc (p *UntrackIndexedDBForOriginParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUntrackIndexedDBForOrigin, p, nil)\n}\n\n// UntrackIndexedDBForStorageKeyParams unregisters storage key from receiving\n// notifications for IndexedDB.\ntype UntrackIndexedDBForStorageKeyParams struct {\n\tStorageKey string `json:\"storageKey\"` // Storage key.\n}\n\n// UntrackIndexedDBForStorageKey unregisters storage key from receiving\n// notifications for IndexedDB.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-untrackIndexedDBForStorageKey\n//\n// parameters:\n//\n//\tstorageKey - Storage key.\nfunc UntrackIndexedDBForStorageKey(storageKey string) *UntrackIndexedDBForStorageKeyParams {\n\treturn &UntrackIndexedDBForStorageKeyParams{\n\t\tStorageKey: storageKey,\n\t}\n}\n\n// Do executes Storage.untrackIndexedDBForStorageKey against the provided context.\nfunc (p *UntrackIndexedDBForStorageKeyParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUntrackIndexedDBForStorageKey, p, nil)\n}\n\n// GetTrustTokensParams returns the number of stored Trust Tokens per issuer\n// for the current browsing context.\ntype GetTrustTokensParams struct{}\n\n// GetTrustTokens returns the number of stored Trust Tokens per issuer for\n// the current browsing context.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getTrustTokens\nfunc GetTrustTokens() *GetTrustTokensParams {\n\treturn &GetTrustTokensParams{}\n}\n\n// GetTrustTokensReturns return values.\ntype GetTrustTokensReturns struct {\n\tTokens []*TrustTokens `json:\"tokens,omitempty,omitzero\"`\n}\n\n// Do executes Storage.getTrustTokens against the provided context.\n//\n// returns:\n//\n//\ttokens\nfunc (p *GetTrustTokensParams) Do(ctx context.Context) (tokens []*TrustTokens, err error) {\n\t// execute\n\tvar res GetTrustTokensReturns\n\terr = cdp.Execute(ctx, CommandGetTrustTokens, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Tokens, nil\n}\n\n// ClearTrustTokensParams removes all Trust Tokens issued by the provided\n// issuerOrigin. Leaves other stored data, including the issuer's Redemption\n// Records, intact.\ntype ClearTrustTokensParams struct {\n\tIssuerOrigin string `json:\"issuerOrigin\"`\n}\n\n// ClearTrustTokens removes all Trust Tokens issued by the provided\n// issuerOrigin. Leaves other stored data, including the issuer's Redemption\n// Records, intact.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-clearTrustTokens\n//\n// parameters:\n//\n//\tissuerOrigin\nfunc ClearTrustTokens(issuerOrigin string) *ClearTrustTokensParams {\n\treturn &ClearTrustTokensParams{\n\t\tIssuerOrigin: issuerOrigin,\n\t}\n}\n\n// ClearTrustTokensReturns return values.\ntype ClearTrustTokensReturns struct {\n\tDidDeleteTokens bool `json:\"didDeleteTokens\"` // True if any tokens were deleted, false otherwise.\n}\n\n// Do executes Storage.clearTrustTokens against the provided context.\n//\n// returns:\n//\n//\tdidDeleteTokens - True if any tokens were deleted, false otherwise.\nfunc (p *ClearTrustTokensParams) Do(ctx context.Context) (didDeleteTokens bool, err error) {\n\t// execute\n\tvar res ClearTrustTokensReturns\n\terr = cdp.Execute(ctx, CommandClearTrustTokens, p, &res)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn res.DidDeleteTokens, nil\n}\n\n// GetInterestGroupDetailsParams gets details for a named interest group.\ntype GetInterestGroupDetailsParams struct {\n\tOwnerOrigin string `json:\"ownerOrigin\"`\n\tName        string `json:\"name\"`\n}\n\n// GetInterestGroupDetails gets details for a named interest group.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getInterestGroupDetails\n//\n// parameters:\n//\n//\townerOrigin\n//\tname\nfunc GetInterestGroupDetails(ownerOrigin string, name string) *GetInterestGroupDetailsParams {\n\treturn &GetInterestGroupDetailsParams{\n\t\tOwnerOrigin: ownerOrigin,\n\t\tName:        name,\n\t}\n}\n\n// GetInterestGroupDetailsReturns return values.\ntype GetInterestGroupDetailsReturns struct {\n\tDetails jsontext.Value `json:\"details,omitempty,omitzero\"`\n}\n\n// Do executes Storage.getInterestGroupDetails against the provided context.\n//\n// returns:\n//\n//\tdetails - This largely corresponds to: https://wicg.github.io/turtledove/#dictdef-generatebidinterestgroup but has absolute expirationTime instead of relative lifetimeMs and also adds joiningOrigin.\nfunc (p *GetInterestGroupDetailsParams) Do(ctx context.Context) (details jsontext.Value, err error) {\n\t// execute\n\tvar res GetInterestGroupDetailsReturns\n\terr = cdp.Execute(ctx, CommandGetInterestGroupDetails, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Details, nil\n}\n\n// SetInterestGroupTrackingParams enables/Disables issuing of\n// interestGroupAccessed events.\ntype SetInterestGroupTrackingParams struct {\n\tEnable bool `json:\"enable\"`\n}\n\n// SetInterestGroupTracking enables/Disables issuing of interestGroupAccessed\n// events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setInterestGroupTracking\n//\n// parameters:\n//\n//\tenable\nfunc SetInterestGroupTracking(enable bool) *SetInterestGroupTrackingParams {\n\treturn &SetInterestGroupTrackingParams{\n\t\tEnable: enable,\n\t}\n}\n\n// Do executes Storage.setInterestGroupTracking against the provided context.\nfunc (p *SetInterestGroupTrackingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetInterestGroupTracking, p, nil)\n}\n\n// SetInterestGroupAuctionTrackingParams enables/Disables issuing of\n// interestGroupAuctionEventOccurred and\n// interestGroupAuctionNetworkRequestCreated.\ntype SetInterestGroupAuctionTrackingParams struct {\n\tEnable bool `json:\"enable\"`\n}\n\n// SetInterestGroupAuctionTracking enables/Disables issuing of\n// interestGroupAuctionEventOccurred and\n// interestGroupAuctionNetworkRequestCreated.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setInterestGroupAuctionTracking\n//\n// parameters:\n//\n//\tenable\nfunc SetInterestGroupAuctionTracking(enable bool) *SetInterestGroupAuctionTrackingParams {\n\treturn &SetInterestGroupAuctionTrackingParams{\n\t\tEnable: enable,\n\t}\n}\n\n// Do executes Storage.setInterestGroupAuctionTracking against the provided context.\nfunc (p *SetInterestGroupAuctionTrackingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetInterestGroupAuctionTracking, p, nil)\n}\n\n// GetSharedStorageMetadataParams gets metadata for an origin's shared\n// storage.\ntype GetSharedStorageMetadataParams struct {\n\tOwnerOrigin string `json:\"ownerOrigin\"`\n}\n\n// GetSharedStorageMetadata gets metadata for an origin's shared storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getSharedStorageMetadata\n//\n// parameters:\n//\n//\townerOrigin\nfunc GetSharedStorageMetadata(ownerOrigin string) *GetSharedStorageMetadataParams {\n\treturn &GetSharedStorageMetadataParams{\n\t\tOwnerOrigin: ownerOrigin,\n\t}\n}\n\n// GetSharedStorageMetadataReturns return values.\ntype GetSharedStorageMetadataReturns struct {\n\tMetadata *SharedStorageMetadata `json:\"metadata,omitempty,omitzero\"`\n}\n\n// Do executes Storage.getSharedStorageMetadata against the provided context.\n//\n// returns:\n//\n//\tmetadata\nfunc (p *GetSharedStorageMetadataParams) Do(ctx context.Context) (metadata *SharedStorageMetadata, err error) {\n\t// execute\n\tvar res GetSharedStorageMetadataReturns\n\terr = cdp.Execute(ctx, CommandGetSharedStorageMetadata, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Metadata, nil\n}\n\n// GetSharedStorageEntriesParams gets the entries in an given origin's shared\n// storage.\ntype GetSharedStorageEntriesParams struct {\n\tOwnerOrigin string `json:\"ownerOrigin\"`\n}\n\n// GetSharedStorageEntries gets the entries in an given origin's shared\n// storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getSharedStorageEntries\n//\n// parameters:\n//\n//\townerOrigin\nfunc GetSharedStorageEntries(ownerOrigin string) *GetSharedStorageEntriesParams {\n\treturn &GetSharedStorageEntriesParams{\n\t\tOwnerOrigin: ownerOrigin,\n\t}\n}\n\n// GetSharedStorageEntriesReturns return values.\ntype GetSharedStorageEntriesReturns struct {\n\tEntries []*SharedStorageEntry `json:\"entries,omitempty,omitzero\"`\n}\n\n// Do executes Storage.getSharedStorageEntries against the provided context.\n//\n// returns:\n//\n//\tentries\nfunc (p *GetSharedStorageEntriesParams) Do(ctx context.Context) (entries []*SharedStorageEntry, err error) {\n\t// execute\n\tvar res GetSharedStorageEntriesReturns\n\terr = cdp.Execute(ctx, CommandGetSharedStorageEntries, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Entries, nil\n}\n\n// SetSharedStorageEntryParams sets entry with key and value for a given\n// origin's shared storage.\ntype SetSharedStorageEntryParams struct {\n\tOwnerOrigin     string `json:\"ownerOrigin\"`\n\tKey             string `json:\"key\"`\n\tValue           string `json:\"value\"`\n\tIgnoreIfPresent bool   `json:\"ignoreIfPresent\"` // If ignoreIfPresent is included and true, then only sets the entry if key doesn't already exist.\n}\n\n// SetSharedStorageEntry sets entry with key and value for a given origin's\n// shared storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setSharedStorageEntry\n//\n// parameters:\n//\n//\townerOrigin\n//\tkey\n//\tvalue\nfunc SetSharedStorageEntry(ownerOrigin string, key string, value string) *SetSharedStorageEntryParams {\n\treturn &SetSharedStorageEntryParams{\n\t\tOwnerOrigin:     ownerOrigin,\n\t\tKey:             key,\n\t\tValue:           value,\n\t\tIgnoreIfPresent: false,\n\t}\n}\n\n// WithIgnoreIfPresent if ignoreIfPresent is included and true, then only\n// sets the entry if key doesn't already exist.\nfunc (p SetSharedStorageEntryParams) WithIgnoreIfPresent(ignoreIfPresent bool) *SetSharedStorageEntryParams {\n\tp.IgnoreIfPresent = ignoreIfPresent\n\treturn &p\n}\n\n// Do executes Storage.setSharedStorageEntry against the provided context.\nfunc (p *SetSharedStorageEntryParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSharedStorageEntry, p, nil)\n}\n\n// DeleteSharedStorageEntryParams deletes entry for key (if it exists) for a\n// given origin's shared storage.\ntype DeleteSharedStorageEntryParams struct {\n\tOwnerOrigin string `json:\"ownerOrigin\"`\n\tKey         string `json:\"key\"`\n}\n\n// DeleteSharedStorageEntry deletes entry for key (if it exists) for a given\n// origin's shared storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-deleteSharedStorageEntry\n//\n// parameters:\n//\n//\townerOrigin\n//\tkey\nfunc DeleteSharedStorageEntry(ownerOrigin string, key string) *DeleteSharedStorageEntryParams {\n\treturn &DeleteSharedStorageEntryParams{\n\t\tOwnerOrigin: ownerOrigin,\n\t\tKey:         key,\n\t}\n}\n\n// Do executes Storage.deleteSharedStorageEntry against the provided context.\nfunc (p *DeleteSharedStorageEntryParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeleteSharedStorageEntry, p, nil)\n}\n\n// ClearSharedStorageEntriesParams clears all entries for a given origin's\n// shared storage.\ntype ClearSharedStorageEntriesParams struct {\n\tOwnerOrigin string `json:\"ownerOrigin\"`\n}\n\n// ClearSharedStorageEntries clears all entries for a given origin's shared\n// storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-clearSharedStorageEntries\n//\n// parameters:\n//\n//\townerOrigin\nfunc ClearSharedStorageEntries(ownerOrigin string) *ClearSharedStorageEntriesParams {\n\treturn &ClearSharedStorageEntriesParams{\n\t\tOwnerOrigin: ownerOrigin,\n\t}\n}\n\n// Do executes Storage.clearSharedStorageEntries against the provided context.\nfunc (p *ClearSharedStorageEntriesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearSharedStorageEntries, p, nil)\n}\n\n// ResetSharedStorageBudgetParams resets the budget for ownerOrigin by\n// clearing all budget withdrawals.\ntype ResetSharedStorageBudgetParams struct {\n\tOwnerOrigin string `json:\"ownerOrigin\"`\n}\n\n// ResetSharedStorageBudget resets the budget for ownerOrigin by clearing all\n// budget withdrawals.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-resetSharedStorageBudget\n//\n// parameters:\n//\n//\townerOrigin\nfunc ResetSharedStorageBudget(ownerOrigin string) *ResetSharedStorageBudgetParams {\n\treturn &ResetSharedStorageBudgetParams{\n\t\tOwnerOrigin: ownerOrigin,\n\t}\n}\n\n// Do executes Storage.resetSharedStorageBudget against the provided context.\nfunc (p *ResetSharedStorageBudgetParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandResetSharedStorageBudget, p, nil)\n}\n\n// SetSharedStorageTrackingParams enables/disables issuing of\n// sharedStorageAccessed events.\ntype SetSharedStorageTrackingParams struct {\n\tEnable bool `json:\"enable\"`\n}\n\n// SetSharedStorageTracking enables/disables issuing of sharedStorageAccessed\n// events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setSharedStorageTracking\n//\n// parameters:\n//\n//\tenable\nfunc SetSharedStorageTracking(enable bool) *SetSharedStorageTrackingParams {\n\treturn &SetSharedStorageTrackingParams{\n\t\tEnable: enable,\n\t}\n}\n\n// Do executes Storage.setSharedStorageTracking against the provided context.\nfunc (p *SetSharedStorageTrackingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetSharedStorageTracking, p, nil)\n}\n\n// SetStorageBucketTrackingParams set tracking for a storage key's buckets.\ntype SetStorageBucketTrackingParams struct {\n\tStorageKey string `json:\"storageKey\"`\n\tEnable     bool   `json:\"enable\"`\n}\n\n// SetStorageBucketTracking set tracking for a storage key's buckets.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setStorageBucketTracking\n//\n// parameters:\n//\n//\tstorageKey\n//\tenable\nfunc SetStorageBucketTracking(storageKey string, enable bool) *SetStorageBucketTrackingParams {\n\treturn &SetStorageBucketTrackingParams{\n\t\tStorageKey: storageKey,\n\t\tEnable:     enable,\n\t}\n}\n\n// Do executes Storage.setStorageBucketTracking against the provided context.\nfunc (p *SetStorageBucketTrackingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetStorageBucketTracking, p, nil)\n}\n\n// DeleteStorageBucketParams deletes the Storage Bucket with the given\n// storage key and bucket name.\ntype DeleteStorageBucketParams struct {\n\tBucket *Bucket `json:\"bucket\"`\n}\n\n// DeleteStorageBucket deletes the Storage Bucket with the given storage key\n// and bucket name.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-deleteStorageBucket\n//\n// parameters:\n//\n//\tbucket\nfunc DeleteStorageBucket(bucket *Bucket) *DeleteStorageBucketParams {\n\treturn &DeleteStorageBucketParams{\n\t\tBucket: bucket,\n\t}\n}\n\n// Do executes Storage.deleteStorageBucket against the provided context.\nfunc (p *DeleteStorageBucketParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDeleteStorageBucket, p, nil)\n}\n\n// RunBounceTrackingMitigationsParams deletes state for sites identified as\n// potential bounce trackers, immediately.\ntype RunBounceTrackingMitigationsParams struct{}\n\n// RunBounceTrackingMitigations deletes state for sites identified as\n// potential bounce trackers, immediately.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-runBounceTrackingMitigations\nfunc RunBounceTrackingMitigations() *RunBounceTrackingMitigationsParams {\n\treturn &RunBounceTrackingMitigationsParams{}\n}\n\n// RunBounceTrackingMitigationsReturns return values.\ntype RunBounceTrackingMitigationsReturns struct {\n\tDeletedSites []string `json:\"deletedSites,omitempty,omitzero\"`\n}\n\n// Do executes Storage.runBounceTrackingMitigations against the provided context.\n//\n// returns:\n//\n//\tdeletedSites\nfunc (p *RunBounceTrackingMitigationsParams) Do(ctx context.Context) (deletedSites []string, err error) {\n\t// execute\n\tvar res RunBounceTrackingMitigationsReturns\n\terr = cdp.Execute(ctx, CommandRunBounceTrackingMitigations, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.DeletedSites, nil\n}\n\n// SetAttributionReportingLocalTestingModeParams\n// https://wicg.github.io/attribution-reporting-api/.\ntype SetAttributionReportingLocalTestingModeParams struct {\n\tEnabled bool `json:\"enabled\"` // If enabled, noise is suppressed and reports are sent immediately.\n}\n\n// SetAttributionReportingLocalTestingMode\n// https://wicg.github.io/attribution-reporting-api/.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setAttributionReportingLocalTestingMode\n//\n// parameters:\n//\n//\tenabled - If enabled, noise is suppressed and reports are sent immediately.\nfunc SetAttributionReportingLocalTestingMode(enabled bool) *SetAttributionReportingLocalTestingModeParams {\n\treturn &SetAttributionReportingLocalTestingModeParams{\n\t\tEnabled: enabled,\n\t}\n}\n\n// Do executes Storage.setAttributionReportingLocalTestingMode against the provided context.\nfunc (p *SetAttributionReportingLocalTestingModeParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAttributionReportingLocalTestingMode, p, nil)\n}\n\n// SetAttributionReportingTrackingParams enables/disables issuing of\n// Attribution Reporting events.\ntype SetAttributionReportingTrackingParams struct {\n\tEnable bool `json:\"enable\"`\n}\n\n// SetAttributionReportingTracking enables/disables issuing of Attribution\n// Reporting events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setAttributionReportingTracking\n//\n// parameters:\n//\n//\tenable\nfunc SetAttributionReportingTracking(enable bool) *SetAttributionReportingTrackingParams {\n\treturn &SetAttributionReportingTrackingParams{\n\t\tEnable: enable,\n\t}\n}\n\n// Do executes Storage.setAttributionReportingTracking against the provided context.\nfunc (p *SetAttributionReportingTrackingParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAttributionReportingTracking, p, nil)\n}\n\n// SendPendingAttributionReportsParams sends all pending Attribution Reports\n// immediately, regardless of their scheduled report time.\ntype SendPendingAttributionReportsParams struct{}\n\n// SendPendingAttributionReports sends all pending Attribution Reports\n// immediately, regardless of their scheduled report time.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-sendPendingAttributionReports\nfunc SendPendingAttributionReports() *SendPendingAttributionReportsParams {\n\treturn &SendPendingAttributionReportsParams{}\n}\n\n// SendPendingAttributionReportsReturns return values.\ntype SendPendingAttributionReportsReturns struct {\n\tNumSent int64 `json:\"numSent,omitempty,omitzero\"` // The number of reports that were sent.\n}\n\n// Do executes Storage.sendPendingAttributionReports against the provided context.\n//\n// returns:\n//\n//\tnumSent - The number of reports that were sent.\nfunc (p *SendPendingAttributionReportsParams) Do(ctx context.Context) (numSent int64, err error) {\n\t// execute\n\tvar res SendPendingAttributionReportsReturns\n\terr = cdp.Execute(ctx, CommandSendPendingAttributionReports, nil, &res)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn res.NumSent, nil\n}\n\n// GetRelatedWebsiteSetsParams returns the effective Related Website Sets in\n// use by this profile for the browser session. The effective Related Website\n// Sets will not change during a browser session.\ntype GetRelatedWebsiteSetsParams struct{}\n\n// GetRelatedWebsiteSets returns the effective Related Website Sets in use by\n// this profile for the browser session. The effective Related Website Sets will\n// not change during a browser session.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getRelatedWebsiteSets\nfunc GetRelatedWebsiteSets() *GetRelatedWebsiteSetsParams {\n\treturn &GetRelatedWebsiteSetsParams{}\n}\n\n// GetRelatedWebsiteSetsReturns return values.\ntype GetRelatedWebsiteSetsReturns struct {\n\tSets []*RelatedWebsiteSet `json:\"sets,omitempty,omitzero\"`\n}\n\n// Do executes Storage.getRelatedWebsiteSets against the provided context.\n//\n// returns:\n//\n//\tsets\nfunc (p *GetRelatedWebsiteSetsParams) Do(ctx context.Context) (sets []*RelatedWebsiteSet, err error) {\n\t// execute\n\tvar res GetRelatedWebsiteSetsReturns\n\terr = cdp.Execute(ctx, CommandGetRelatedWebsiteSets, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Sets, nil\n}\n\n// GetAffectedURLsForThirdPartyCookieMetadataParams returns the list of URLs\n// from a page and its embedded resources that match existing grace period URL\n// pattern rules.\n// https://developers.google.com/privacy-sandbox/cookies/temporary-exceptions/grace-period.\ntype GetAffectedURLsForThirdPartyCookieMetadataParams struct {\n\tFirstPartyURL  string   `json:\"firstPartyUrl\"`  // The URL of the page currently being visited.\n\tThirdPartyURLs []string `json:\"thirdPartyUrls\"` // The list of embedded resource URLs from the page.\n}\n\n// GetAffectedURLsForThirdPartyCookieMetadata returns the list of URLs from a\n// page and its embedded resources that match existing grace period URL pattern\n// rules.\n// https://developers.google.com/privacy-sandbox/cookies/temporary-exceptions/grace-period.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-getAffectedUrlsForThirdPartyCookieMetadata\n//\n// parameters:\n//\n//\tfirstPartyURL - The URL of the page currently being visited.\n//\tthirdPartyURLs - The list of embedded resource URLs from the page.\nfunc GetAffectedURLsForThirdPartyCookieMetadata(firstPartyURL string, thirdPartyURLs []string) *GetAffectedURLsForThirdPartyCookieMetadataParams {\n\treturn &GetAffectedURLsForThirdPartyCookieMetadataParams{\n\t\tFirstPartyURL:  firstPartyURL,\n\t\tThirdPartyURLs: thirdPartyURLs,\n\t}\n}\n\n// GetAffectedURLsForThirdPartyCookieMetadataReturns return values.\ntype GetAffectedURLsForThirdPartyCookieMetadataReturns struct {\n\tMatchedURLs []string `json:\"matchedUrls,omitempty,omitzero\"` // Array of matching URLs. If there is a primary pattern match for the first- party URL, only the first-party URL is returned in the array.\n}\n\n// Do executes Storage.getAffectedUrlsForThirdPartyCookieMetadata against the provided context.\n//\n// returns:\n//\n//\tmatchedURLs - Array of matching URLs. If there is a primary pattern match for the first- party URL, only the first-party URL is returned in the array.\nfunc (p *GetAffectedURLsForThirdPartyCookieMetadataParams) Do(ctx context.Context) (matchedURLs []string, err error) {\n\t// execute\n\tvar res GetAffectedURLsForThirdPartyCookieMetadataReturns\n\terr = cdp.Execute(ctx, CommandGetAffectedURLsForThirdPartyCookieMetadata, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.MatchedURLs, nil\n}\n\n// SetProtectedAudienceKAnonymityParams [no description].\ntype SetProtectedAudienceKAnonymityParams struct {\n\tOwner  string   `json:\"owner\"`\n\tName   string   `json:\"name\"`\n\tHashes []string `json:\"hashes\"`\n}\n\n// SetProtectedAudienceKAnonymity [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#method-setProtectedAudienceKAnonymity\n//\n// parameters:\n//\n//\towner\n//\tname\n//\thashes\nfunc SetProtectedAudienceKAnonymity(owner string, name string, hashes []string) *SetProtectedAudienceKAnonymityParams {\n\treturn &SetProtectedAudienceKAnonymityParams{\n\t\tOwner:  owner,\n\t\tName:   name,\n\t\tHashes: hashes,\n\t}\n}\n\n// Do executes Storage.setProtectedAudienceKAnonymity against the provided context.\nfunc (p *SetProtectedAudienceKAnonymityParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetProtectedAudienceKAnonymity, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandGetStorageKeyForFrame                      = \"Storage.getStorageKeyForFrame\"\n\tCommandClearDataForOrigin                         = \"Storage.clearDataForOrigin\"\n\tCommandClearDataForStorageKey                     = \"Storage.clearDataForStorageKey\"\n\tCommandGetCookies                                 = \"Storage.getCookies\"\n\tCommandSetCookies                                 = \"Storage.setCookies\"\n\tCommandClearCookies                               = \"Storage.clearCookies\"\n\tCommandGetUsageAndQuota                           = \"Storage.getUsageAndQuota\"\n\tCommandOverrideQuotaForOrigin                     = \"Storage.overrideQuotaForOrigin\"\n\tCommandTrackCacheStorageForOrigin                 = \"Storage.trackCacheStorageForOrigin\"\n\tCommandTrackCacheStorageForStorageKey             = \"Storage.trackCacheStorageForStorageKey\"\n\tCommandTrackIndexedDBForOrigin                    = \"Storage.trackIndexedDBForOrigin\"\n\tCommandTrackIndexedDBForStorageKey                = \"Storage.trackIndexedDBForStorageKey\"\n\tCommandUntrackCacheStorageForOrigin               = \"Storage.untrackCacheStorageForOrigin\"\n\tCommandUntrackCacheStorageForStorageKey           = \"Storage.untrackCacheStorageForStorageKey\"\n\tCommandUntrackIndexedDBForOrigin                  = \"Storage.untrackIndexedDBForOrigin\"\n\tCommandUntrackIndexedDBForStorageKey              = \"Storage.untrackIndexedDBForStorageKey\"\n\tCommandGetTrustTokens                             = \"Storage.getTrustTokens\"\n\tCommandClearTrustTokens                           = \"Storage.clearTrustTokens\"\n\tCommandGetInterestGroupDetails                    = \"Storage.getInterestGroupDetails\"\n\tCommandSetInterestGroupTracking                   = \"Storage.setInterestGroupTracking\"\n\tCommandSetInterestGroupAuctionTracking            = \"Storage.setInterestGroupAuctionTracking\"\n\tCommandGetSharedStorageMetadata                   = \"Storage.getSharedStorageMetadata\"\n\tCommandGetSharedStorageEntries                    = \"Storage.getSharedStorageEntries\"\n\tCommandSetSharedStorageEntry                      = \"Storage.setSharedStorageEntry\"\n\tCommandDeleteSharedStorageEntry                   = \"Storage.deleteSharedStorageEntry\"\n\tCommandClearSharedStorageEntries                  = \"Storage.clearSharedStorageEntries\"\n\tCommandResetSharedStorageBudget                   = \"Storage.resetSharedStorageBudget\"\n\tCommandSetSharedStorageTracking                   = \"Storage.setSharedStorageTracking\"\n\tCommandSetStorageBucketTracking                   = \"Storage.setStorageBucketTracking\"\n\tCommandDeleteStorageBucket                        = \"Storage.deleteStorageBucket\"\n\tCommandRunBounceTrackingMitigations               = \"Storage.runBounceTrackingMitigations\"\n\tCommandSetAttributionReportingLocalTestingMode    = \"Storage.setAttributionReportingLocalTestingMode\"\n\tCommandSetAttributionReportingTracking            = \"Storage.setAttributionReportingTracking\"\n\tCommandSendPendingAttributionReports              = \"Storage.sendPendingAttributionReports\"\n\tCommandGetRelatedWebsiteSets                      = \"Storage.getRelatedWebsiteSets\"\n\tCommandGetAffectedURLsForThirdPartyCookieMetadata = \"Storage.getAffectedUrlsForThirdPartyCookieMetadata\"\n\tCommandSetProtectedAudienceKAnonymity             = \"Storage.setProtectedAudienceKAnonymity\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/storage/types.go",
    "content": "package storage\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n\t\"github.com/chromedp/cdproto/target\"\n)\n\n// SerializedStorageKey [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SerializedStorageKey\ntype SerializedStorageKey string\n\n// String returns the SerializedStorageKey as string value.\nfunc (t SerializedStorageKey) String() string {\n\treturn string(t)\n}\n\n// Type enum of possible storage types.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-StorageType\ntype Type string\n\n// String returns the Type as string value.\nfunc (t Type) String() string {\n\treturn string(t)\n}\n\n// Type values.\nconst (\n\tTypeCookies        Type = \"cookies\"\n\tTypeFileSystems    Type = \"file_systems\"\n\tTypeIndexeddb      Type = \"indexeddb\"\n\tTypeLocalStorage   Type = \"local_storage\"\n\tTypeShaderCache    Type = \"shader_cache\"\n\tTypeWebsql         Type = \"websql\"\n\tTypeServiceWorkers Type = \"service_workers\"\n\tTypeCacheStorage   Type = \"cache_storage\"\n\tTypeInterestGroups Type = \"interest_groups\"\n\tTypeSharedStorage  Type = \"shared_storage\"\n\tTypeStorageBuckets Type = \"storage_buckets\"\n\tTypeAll            Type = \"all\"\n\tTypeOther          Type = \"other\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Type) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Type(s) {\n\tcase TypeCookies:\n\t\t*t = TypeCookies\n\tcase TypeFileSystems:\n\t\t*t = TypeFileSystems\n\tcase TypeIndexeddb:\n\t\t*t = TypeIndexeddb\n\tcase TypeLocalStorage:\n\t\t*t = TypeLocalStorage\n\tcase TypeShaderCache:\n\t\t*t = TypeShaderCache\n\tcase TypeWebsql:\n\t\t*t = TypeWebsql\n\tcase TypeServiceWorkers:\n\t\t*t = TypeServiceWorkers\n\tcase TypeCacheStorage:\n\t\t*t = TypeCacheStorage\n\tcase TypeInterestGroups:\n\t\t*t = TypeInterestGroups\n\tcase TypeSharedStorage:\n\t\t*t = TypeSharedStorage\n\tcase TypeStorageBuckets:\n\t\t*t = TypeStorageBuckets\n\tcase TypeAll:\n\t\t*t = TypeAll\n\tcase TypeOther:\n\t\t*t = TypeOther\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Type value: %v\", s)\n\t}\n\treturn nil\n}\n\n// UsageForType usage for a storage type.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-UsageForType\ntype UsageForType struct {\n\tStorageType Type    `json:\"storageType\"` // Name of storage type.\n\tUsage       float64 `json:\"usage\"`       // Storage usage (bytes).\n}\n\n// TrustTokens pair of issuer origin and number of available (signed, but not\n// used) Trust Tokens from that issuer.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-TrustTokens\ntype TrustTokens struct {\n\tIssuerOrigin string  `json:\"issuerOrigin\"`\n\tCount        float64 `json:\"count\"`\n}\n\n// InterestGroupAuctionID protected audience interest group auction\n// identifier.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-InterestGroupAuctionId\ntype InterestGroupAuctionID string\n\n// String returns the InterestGroupAuctionID as string value.\nfunc (t InterestGroupAuctionID) String() string {\n\treturn string(t)\n}\n\n// InterestGroupAccessType enum of interest group access types.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-InterestGroupAccessType\ntype InterestGroupAccessType string\n\n// String returns the InterestGroupAccessType as string value.\nfunc (t InterestGroupAccessType) String() string {\n\treturn string(t)\n}\n\n// InterestGroupAccessType values.\nconst (\n\tInterestGroupAccessTypeJoin                  InterestGroupAccessType = \"join\"\n\tInterestGroupAccessTypeLeave                 InterestGroupAccessType = \"leave\"\n\tInterestGroupAccessTypeUpdate                InterestGroupAccessType = \"update\"\n\tInterestGroupAccessTypeLoaded                InterestGroupAccessType = \"loaded\"\n\tInterestGroupAccessTypeBid                   InterestGroupAccessType = \"bid\"\n\tInterestGroupAccessTypeWin                   InterestGroupAccessType = \"win\"\n\tInterestGroupAccessTypeAdditionalBid         InterestGroupAccessType = \"additionalBid\"\n\tInterestGroupAccessTypeAdditionalBidWin      InterestGroupAccessType = \"additionalBidWin\"\n\tInterestGroupAccessTypeTopLevelBid           InterestGroupAccessType = \"topLevelBid\"\n\tInterestGroupAccessTypeTopLevelAdditionalBid InterestGroupAccessType = \"topLevelAdditionalBid\"\n\tInterestGroupAccessTypeClear                 InterestGroupAccessType = \"clear\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InterestGroupAccessType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InterestGroupAccessType(s) {\n\tcase InterestGroupAccessTypeJoin:\n\t\t*t = InterestGroupAccessTypeJoin\n\tcase InterestGroupAccessTypeLeave:\n\t\t*t = InterestGroupAccessTypeLeave\n\tcase InterestGroupAccessTypeUpdate:\n\t\t*t = InterestGroupAccessTypeUpdate\n\tcase InterestGroupAccessTypeLoaded:\n\t\t*t = InterestGroupAccessTypeLoaded\n\tcase InterestGroupAccessTypeBid:\n\t\t*t = InterestGroupAccessTypeBid\n\tcase InterestGroupAccessTypeWin:\n\t\t*t = InterestGroupAccessTypeWin\n\tcase InterestGroupAccessTypeAdditionalBid:\n\t\t*t = InterestGroupAccessTypeAdditionalBid\n\tcase InterestGroupAccessTypeAdditionalBidWin:\n\t\t*t = InterestGroupAccessTypeAdditionalBidWin\n\tcase InterestGroupAccessTypeTopLevelBid:\n\t\t*t = InterestGroupAccessTypeTopLevelBid\n\tcase InterestGroupAccessTypeTopLevelAdditionalBid:\n\t\t*t = InterestGroupAccessTypeTopLevelAdditionalBid\n\tcase InterestGroupAccessTypeClear:\n\t\t*t = InterestGroupAccessTypeClear\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InterestGroupAccessType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// InterestGroupAuctionEventType enum of auction events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-InterestGroupAuctionEventType\ntype InterestGroupAuctionEventType string\n\n// String returns the InterestGroupAuctionEventType as string value.\nfunc (t InterestGroupAuctionEventType) String() string {\n\treturn string(t)\n}\n\n// InterestGroupAuctionEventType values.\nconst (\n\tInterestGroupAuctionEventTypeStarted        InterestGroupAuctionEventType = \"started\"\n\tInterestGroupAuctionEventTypeConfigResolved InterestGroupAuctionEventType = \"configResolved\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InterestGroupAuctionEventType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InterestGroupAuctionEventType(s) {\n\tcase InterestGroupAuctionEventTypeStarted:\n\t\t*t = InterestGroupAuctionEventTypeStarted\n\tcase InterestGroupAuctionEventTypeConfigResolved:\n\t\t*t = InterestGroupAuctionEventTypeConfigResolved\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InterestGroupAuctionEventType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// InterestGroupAuctionFetchType enum of network fetches auctions can do.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-InterestGroupAuctionFetchType\ntype InterestGroupAuctionFetchType string\n\n// String returns the InterestGroupAuctionFetchType as string value.\nfunc (t InterestGroupAuctionFetchType) String() string {\n\treturn string(t)\n}\n\n// InterestGroupAuctionFetchType values.\nconst (\n\tInterestGroupAuctionFetchTypeBidderJs             InterestGroupAuctionFetchType = \"bidderJs\"\n\tInterestGroupAuctionFetchTypeBidderWasm           InterestGroupAuctionFetchType = \"bidderWasm\"\n\tInterestGroupAuctionFetchTypeSellerJs             InterestGroupAuctionFetchType = \"sellerJs\"\n\tInterestGroupAuctionFetchTypeBidderTrustedSignals InterestGroupAuctionFetchType = \"bidderTrustedSignals\"\n\tInterestGroupAuctionFetchTypeSellerTrustedSignals InterestGroupAuctionFetchType = \"sellerTrustedSignals\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *InterestGroupAuctionFetchType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch InterestGroupAuctionFetchType(s) {\n\tcase InterestGroupAuctionFetchTypeBidderJs:\n\t\t*t = InterestGroupAuctionFetchTypeBidderJs\n\tcase InterestGroupAuctionFetchTypeBidderWasm:\n\t\t*t = InterestGroupAuctionFetchTypeBidderWasm\n\tcase InterestGroupAuctionFetchTypeSellerJs:\n\t\t*t = InterestGroupAuctionFetchTypeSellerJs\n\tcase InterestGroupAuctionFetchTypeBidderTrustedSignals:\n\t\t*t = InterestGroupAuctionFetchTypeBidderTrustedSignals\n\tcase InterestGroupAuctionFetchTypeSellerTrustedSignals:\n\t\t*t = InterestGroupAuctionFetchTypeSellerTrustedSignals\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown InterestGroupAuctionFetchType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SharedStorageAccessScope enum of shared storage access scopes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStorageAccessScope\ntype SharedStorageAccessScope string\n\n// String returns the SharedStorageAccessScope as string value.\nfunc (t SharedStorageAccessScope) String() string {\n\treturn string(t)\n}\n\n// SharedStorageAccessScope values.\nconst (\n\tSharedStorageAccessScopeWindow                   SharedStorageAccessScope = \"window\"\n\tSharedStorageAccessScopeSharedStorageWorklet     SharedStorageAccessScope = \"sharedStorageWorklet\"\n\tSharedStorageAccessScopeProtectedAudienceWorklet SharedStorageAccessScope = \"protectedAudienceWorklet\"\n\tSharedStorageAccessScopeHeader                   SharedStorageAccessScope = \"header\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SharedStorageAccessScope) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SharedStorageAccessScope(s) {\n\tcase SharedStorageAccessScopeWindow:\n\t\t*t = SharedStorageAccessScopeWindow\n\tcase SharedStorageAccessScopeSharedStorageWorklet:\n\t\t*t = SharedStorageAccessScopeSharedStorageWorklet\n\tcase SharedStorageAccessScopeProtectedAudienceWorklet:\n\t\t*t = SharedStorageAccessScopeProtectedAudienceWorklet\n\tcase SharedStorageAccessScopeHeader:\n\t\t*t = SharedStorageAccessScopeHeader\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SharedStorageAccessScope value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SharedStorageAccessMethod enum of shared storage access methods.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStorageAccessMethod\ntype SharedStorageAccessMethod string\n\n// String returns the SharedStorageAccessMethod as string value.\nfunc (t SharedStorageAccessMethod) String() string {\n\treturn string(t)\n}\n\n// SharedStorageAccessMethod values.\nconst (\n\tSharedStorageAccessMethodAddModule       SharedStorageAccessMethod = \"addModule\"\n\tSharedStorageAccessMethodCreateWorklet   SharedStorageAccessMethod = \"createWorklet\"\n\tSharedStorageAccessMethodSelectURL       SharedStorageAccessMethod = \"selectURL\"\n\tSharedStorageAccessMethodRun             SharedStorageAccessMethod = \"run\"\n\tSharedStorageAccessMethodBatchUpdate     SharedStorageAccessMethod = \"batchUpdate\"\n\tSharedStorageAccessMethodSet             SharedStorageAccessMethod = \"set\"\n\tSharedStorageAccessMethodAppend          SharedStorageAccessMethod = \"append\"\n\tSharedStorageAccessMethodDelete          SharedStorageAccessMethod = \"delete\"\n\tSharedStorageAccessMethodClear           SharedStorageAccessMethod = \"clear\"\n\tSharedStorageAccessMethodGet             SharedStorageAccessMethod = \"get\"\n\tSharedStorageAccessMethodKeys            SharedStorageAccessMethod = \"keys\"\n\tSharedStorageAccessMethodValues          SharedStorageAccessMethod = \"values\"\n\tSharedStorageAccessMethodEntries         SharedStorageAccessMethod = \"entries\"\n\tSharedStorageAccessMethodLength          SharedStorageAccessMethod = \"length\"\n\tSharedStorageAccessMethodRemainingBudget SharedStorageAccessMethod = \"remainingBudget\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SharedStorageAccessMethod) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SharedStorageAccessMethod(s) {\n\tcase SharedStorageAccessMethodAddModule:\n\t\t*t = SharedStorageAccessMethodAddModule\n\tcase SharedStorageAccessMethodCreateWorklet:\n\t\t*t = SharedStorageAccessMethodCreateWorklet\n\tcase SharedStorageAccessMethodSelectURL:\n\t\t*t = SharedStorageAccessMethodSelectURL\n\tcase SharedStorageAccessMethodRun:\n\t\t*t = SharedStorageAccessMethodRun\n\tcase SharedStorageAccessMethodBatchUpdate:\n\t\t*t = SharedStorageAccessMethodBatchUpdate\n\tcase SharedStorageAccessMethodSet:\n\t\t*t = SharedStorageAccessMethodSet\n\tcase SharedStorageAccessMethodAppend:\n\t\t*t = SharedStorageAccessMethodAppend\n\tcase SharedStorageAccessMethodDelete:\n\t\t*t = SharedStorageAccessMethodDelete\n\tcase SharedStorageAccessMethodClear:\n\t\t*t = SharedStorageAccessMethodClear\n\tcase SharedStorageAccessMethodGet:\n\t\t*t = SharedStorageAccessMethodGet\n\tcase SharedStorageAccessMethodKeys:\n\t\t*t = SharedStorageAccessMethodKeys\n\tcase SharedStorageAccessMethodValues:\n\t\t*t = SharedStorageAccessMethodValues\n\tcase SharedStorageAccessMethodEntries:\n\t\t*t = SharedStorageAccessMethodEntries\n\tcase SharedStorageAccessMethodLength:\n\t\t*t = SharedStorageAccessMethodLength\n\tcase SharedStorageAccessMethodRemainingBudget:\n\t\t*t = SharedStorageAccessMethodRemainingBudget\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SharedStorageAccessMethod value: %v\", s)\n\t}\n\treturn nil\n}\n\n// SharedStorageEntry struct for a single key-value pair in an origin's\n// shared storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStorageEntry\ntype SharedStorageEntry struct {\n\tKey   string `json:\"key\"`\n\tValue string `json:\"value\"`\n}\n\n// SharedStorageMetadata details for an origin's shared storage.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStorageMetadata\ntype SharedStorageMetadata struct {\n\tCreationTime    *cdp.TimeSinceEpoch `json:\"creationTime\"`    // Time when the origin's shared storage was last created.\n\tLength          int64               `json:\"length\"`          // Number of key-value pairs stored in origin's shared storage.\n\tRemainingBudget float64             `json:\"remainingBudget\"` // Current amount of bits of entropy remaining in the navigation budget.\n\tBytesUsed       int64               `json:\"bytesUsed\"`       // Total number of bytes stored as key-value pairs in origin's shared storage.\n}\n\n// SharedStoragePrivateAggregationConfig represents a dictionary object\n// passed in as privateAggregationConfig to run or selectURL.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStoragePrivateAggregationConfig\ntype SharedStoragePrivateAggregationConfig struct {\n\tAggregationCoordinatorOrigin string `json:\"aggregationCoordinatorOrigin,omitempty,omitzero\"` // The chosen aggregation service deployment.\n\tContextID                    string `json:\"contextId,omitempty,omitzero\"`                    // The context ID provided.\n\tFilteringIDMaxBytes          int64  `json:\"filteringIdMaxBytes\"`                             // Configures the maximum size allowed for filtering IDs.\n\tMaxContributions             int64  `json:\"maxContributions,omitempty,omitzero\"`             // The limit on the number of contributions in the final report.\n}\n\n// SharedStorageReportingMetadata pair of reporting metadata details for a\n// candidate URL for selectURL().\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStorageReportingMetadata\ntype SharedStorageReportingMetadata struct {\n\tEventType    string `json:\"eventType\"`\n\tReportingURL string `json:\"reportingUrl\"`\n}\n\n// SharedStorageURLWithMetadata bundles a candidate URL with its reporting\n// metadata.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStorageUrlWithMetadata\ntype SharedStorageURLWithMetadata struct {\n\tURL               string                            `json:\"url\"`               // Spec of candidate URL.\n\tReportingMetadata []*SharedStorageReportingMetadata `json:\"reportingMetadata\"` // Any associated reporting metadata.\n}\n\n// SharedStorageAccessParams bundles the parameters for shared storage access\n// events whose presence/absence can vary according to SharedStorageAccessType.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SharedStorageAccessParams\ntype SharedStorageAccessParams struct {\n\tScriptSourceURL          string                                 `json:\"scriptSourceUrl,omitempty,omitzero\"`          // Spec of the module script URL. Present only for SharedStorageAccessMethods: addModule and createWorklet.\n\tDataOrigin               string                                 `json:\"dataOrigin,omitempty,omitzero\"`               // String denoting \"context-origin\", \"script-origin\", or a custom origin to be used as the worklet's data origin. Present only for SharedStorageAccessMethod: createWorklet.\n\tOperationName            string                                 `json:\"operationName,omitempty,omitzero\"`            // Name of the registered operation to be run. Present only for SharedStorageAccessMethods: run and selectURL.\n\tOperationID              string                                 `json:\"operationId,omitempty,omitzero\"`              // ID of the operation call. Present only for SharedStorageAccessMethods: run and selectURL.\n\tKeepAlive                bool                                   `json:\"keepAlive\"`                                   // Whether or not to keep the worket alive for future run or selectURL calls. Present only for SharedStorageAccessMethods: run and selectURL.\n\tPrivateAggregationConfig *SharedStoragePrivateAggregationConfig `json:\"privateAggregationConfig,omitempty,omitzero\"` // Configures the private aggregation options. Present only for SharedStorageAccessMethods: run and selectURL.\n\tSerializedData           string                                 `json:\"serializedData,omitempty,omitzero\"`           // The operation's serialized data in bytes (converted to a string). Present only for SharedStorageAccessMethods: run and selectURL. TODO(crbug.com/401011862): Consider updating this parameter to binary.\n\tURLsWithMetadata         []*SharedStorageURLWithMetadata        `json:\"urlsWithMetadata,omitempty,omitzero\"`         // Array of candidate URLs' specs, along with any associated metadata. Present only for SharedStorageAccessMethod: selectURL.\n\tUrnUUID                  string                                 `json:\"urnUuid,omitempty,omitzero\"`                  // Spec of the URN:UUID generated for a selectURL call. Present only for SharedStorageAccessMethod: selectURL.\n\tKey                      string                                 `json:\"key,omitempty,omitzero\"`                      // Key for a specific entry in an origin's shared storage. Present only for SharedStorageAccessMethods: set, append, delete, and get.\n\tValue                    string                                 `json:\"value,omitempty,omitzero\"`                    // Value for a specific entry in an origin's shared storage. Present only for SharedStorageAccessMethods: set and append.\n\tIgnoreIfPresent          bool                                   `json:\"ignoreIfPresent\"`                             // Whether or not to set an entry for a key if that key is already present. Present only for SharedStorageAccessMethod: set.\n\tWorkletOrdinal           int64                                  `json:\"workletOrdinal,omitempty,omitzero\"`           // A number denoting the (0-based) order of the worklet's creation relative to all other shared storage worklets created by documents using the current storage partition. Present only for SharedStorageAccessMethods: addModule, createWorklet.\n\tWorkletTargetID          target.ID                              `json:\"workletTargetId,omitempty,omitzero\"`          // Hex representation of the DevTools token used as the TargetID for the associated shared storage worklet. Present only for SharedStorageAccessMethods: addModule, createWorklet, run, selectURL, and any other SharedStorageAccessMethod when the SharedStorageAccessScope is sharedStorageWorklet.\n\tWithLock                 string                                 `json:\"withLock,omitempty,omitzero\"`                 // Name of the lock to be acquired, if present. Optionally present only for SharedStorageAccessMethods: batchUpdate, set, append, delete, and clear.\n\tBatchUpdateID            string                                 `json:\"batchUpdateId,omitempty,omitzero\"`            // If the method has been called as part of a batchUpdate, then this number identifies the batch to which it belongs. Optionally present only for SharedStorageAccessMethods: batchUpdate (required), set, append, delete, and clear.\n\tBatchSize                int64                                  `json:\"batchSize,omitempty,omitzero\"`                // Number of modifier methods sent in batch. Present only for SharedStorageAccessMethod: batchUpdate.\n}\n\n// BucketsDurability [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-StorageBucketsDurability\ntype BucketsDurability string\n\n// String returns the BucketsDurability as string value.\nfunc (t BucketsDurability) String() string {\n\treturn string(t)\n}\n\n// BucketsDurability values.\nconst (\n\tBucketsDurabilityRelaxed BucketsDurability = \"relaxed\"\n\tBucketsDurabilityStrict  BucketsDurability = \"strict\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *BucketsDurability) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch BucketsDurability(s) {\n\tcase BucketsDurabilityRelaxed:\n\t\t*t = BucketsDurabilityRelaxed\n\tcase BucketsDurabilityStrict:\n\t\t*t = BucketsDurabilityStrict\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown BucketsDurability value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Bucket [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-StorageBucket\ntype Bucket struct {\n\tStorageKey SerializedStorageKey `json:\"storageKey\"`\n\tName       string               `json:\"name,omitempty,omitzero\"` // If not specified, it is the default bucket of the storageKey.\n}\n\n// BucketInfo [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-StorageBucketInfo\ntype BucketInfo struct {\n\tBucket     *Bucket             `json:\"bucket\"`\n\tID         string              `json:\"id\"`\n\tExpiration *cdp.TimeSinceEpoch `json:\"expiration\"`\n\tQuota      float64             `json:\"quota\"` // Storage quota (bytes).\n\tPersistent bool                `json:\"persistent\"`\n\tDurability BucketsDurability   `json:\"durability\"`\n}\n\n// AttributionReportingSourceType [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingSourceType\ntype AttributionReportingSourceType string\n\n// String returns the AttributionReportingSourceType as string value.\nfunc (t AttributionReportingSourceType) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingSourceType values.\nconst (\n\tAttributionReportingSourceTypeNavigation AttributionReportingSourceType = \"navigation\"\n\tAttributionReportingSourceTypeEvent      AttributionReportingSourceType = \"event\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingSourceType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingSourceType(s) {\n\tcase AttributionReportingSourceTypeNavigation:\n\t\t*t = AttributionReportingSourceTypeNavigation\n\tcase AttributionReportingSourceTypeEvent:\n\t\t*t = AttributionReportingSourceTypeEvent\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingSourceType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// UnsignedInt64asBase10 [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-UnsignedInt64AsBase10\ntype UnsignedInt64asBase10 string\n\n// String returns the UnsignedInt64asBase10 as string value.\nfunc (t UnsignedInt64asBase10) String() string {\n\treturn string(t)\n}\n\n// UnsignedInt128asBase16 [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-UnsignedInt128AsBase16\ntype UnsignedInt128asBase16 string\n\n// String returns the UnsignedInt128asBase16 as string value.\nfunc (t UnsignedInt128asBase16) String() string {\n\treturn string(t)\n}\n\n// SignedInt64asBase10 [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-SignedInt64AsBase10\ntype SignedInt64asBase10 string\n\n// String returns the SignedInt64asBase10 as string value.\nfunc (t SignedInt64asBase10) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingFilterDataEntry [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingFilterDataEntry\ntype AttributionReportingFilterDataEntry struct {\n\tKey    string   `json:\"key\"`\n\tValues []string `json:\"values\"`\n}\n\n// AttributionReportingFilterConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingFilterConfig\ntype AttributionReportingFilterConfig struct {\n\tFilterValues   []*AttributionReportingFilterDataEntry `json:\"filterValues\"`\n\tLookbackWindow int64                                  `json:\"lookbackWindow,omitempty,omitzero\"` // duration in seconds\n}\n\n// AttributionReportingFilterPair [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingFilterPair\ntype AttributionReportingFilterPair struct {\n\tFilters    []*AttributionReportingFilterConfig `json:\"filters\"`\n\tNotFilters []*AttributionReportingFilterConfig `json:\"notFilters\"`\n}\n\n// AttributionReportingAggregationKeysEntry [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregationKeysEntry\ntype AttributionReportingAggregationKeysEntry struct {\n\tKey   string                 `json:\"key\"`\n\tValue UnsignedInt128asBase16 `json:\"value\"`\n}\n\n// AttributionReportingEventReportWindows [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingEventReportWindows\ntype AttributionReportingEventReportWindows struct {\n\tStart int64   `json:\"start\"` // duration in seconds\n\tEnds  []int64 `json:\"ends\"`  // duration in seconds\n}\n\n// AttributionReportingTriggerDataMatching [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingTriggerDataMatching\ntype AttributionReportingTriggerDataMatching string\n\n// String returns the AttributionReportingTriggerDataMatching as string value.\nfunc (t AttributionReportingTriggerDataMatching) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingTriggerDataMatching values.\nconst (\n\tAttributionReportingTriggerDataMatchingExact   AttributionReportingTriggerDataMatching = \"exact\"\n\tAttributionReportingTriggerDataMatchingModulus AttributionReportingTriggerDataMatching = \"modulus\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingTriggerDataMatching) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingTriggerDataMatching(s) {\n\tcase AttributionReportingTriggerDataMatchingExact:\n\t\t*t = AttributionReportingTriggerDataMatchingExact\n\tcase AttributionReportingTriggerDataMatchingModulus:\n\t\t*t = AttributionReportingTriggerDataMatchingModulus\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingTriggerDataMatching value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AttributionReportingAggregatableDebugReportingData [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregatableDebugReportingData\ntype AttributionReportingAggregatableDebugReportingData struct {\n\tKeyPiece UnsignedInt128asBase16 `json:\"keyPiece\"`\n\tValue    float64                `json:\"value\"` // number instead of integer because not all uint32 can be represented by int\n\tTypes    []string               `json:\"types\"`\n}\n\n// AttributionReportingAggregatableDebugReportingConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregatableDebugReportingConfig\ntype AttributionReportingAggregatableDebugReportingConfig struct {\n\tBudget                       float64                                               `json:\"budget,omitempty,omitzero\"` // number instead of integer because not all uint32 can be represented by int, only present for source registrations\n\tKeyPiece                     UnsignedInt128asBase16                                `json:\"keyPiece\"`\n\tDebugData                    []*AttributionReportingAggregatableDebugReportingData `json:\"debugData\"`\n\tAggregationCoordinatorOrigin string                                                `json:\"aggregationCoordinatorOrigin,omitempty,omitzero\"`\n}\n\n// AttributionScopesData [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionScopesData\ntype AttributionScopesData struct {\n\tValues         []string `json:\"values\"`\n\tLimit          float64  `json:\"limit\"` // number instead of integer because not all uint32 can be represented by int\n\tMaxEventStates float64  `json:\"maxEventStates\"`\n}\n\n// AttributionReportingNamedBudgetDef [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingNamedBudgetDef\ntype AttributionReportingNamedBudgetDef struct {\n\tName   string `json:\"name\"`\n\tBudget int64  `json:\"budget\"`\n}\n\n// AttributionReportingSourceRegistration [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingSourceRegistration\ntype AttributionReportingSourceRegistration struct {\n\tTime                             *cdp.TimeSinceEpoch                                   `json:\"time\"`\n\tExpiry                           int64                                                 `json:\"expiry\"`      // duration in seconds\n\tTriggerData                      []float64                                             `json:\"triggerData\"` // number instead of integer because not all uint32 can be represented by int\n\tEventReportWindows               *AttributionReportingEventReportWindows               `json:\"eventReportWindows\"`\n\tAggregatableReportWindow         int64                                                 `json:\"aggregatableReportWindow\"` // duration in seconds\n\tType                             AttributionReportingSourceType                        `json:\"type\"`\n\tSourceOrigin                     string                                                `json:\"sourceOrigin\"`\n\tReportingOrigin                  string                                                `json:\"reportingOrigin\"`\n\tDestinationSites                 []string                                              `json:\"destinationSites\"`\n\tEventID                          UnsignedInt64asBase10                                 `json:\"eventId\"`\n\tPriority                         SignedInt64asBase10                                   `json:\"priority\"`\n\tFilterData                       []*AttributionReportingFilterDataEntry                `json:\"filterData\"`\n\tAggregationKeys                  []*AttributionReportingAggregationKeysEntry           `json:\"aggregationKeys\"`\n\tDebugKey                         UnsignedInt64asBase10                                 `json:\"debugKey,omitempty,omitzero\"`\n\tTriggerDataMatching              AttributionReportingTriggerDataMatching               `json:\"triggerDataMatching\"`\n\tDestinationLimitPriority         SignedInt64asBase10                                   `json:\"destinationLimitPriority\"`\n\tAggregatableDebugReportingConfig *AttributionReportingAggregatableDebugReportingConfig `json:\"aggregatableDebugReportingConfig\"`\n\tScopesData                       *AttributionScopesData                                `json:\"scopesData,omitempty,omitzero\"`\n\tMaxEventLevelReports             int64                                                 `json:\"maxEventLevelReports\"`\n\tNamedBudgets                     []*AttributionReportingNamedBudgetDef                 `json:\"namedBudgets\"`\n\tDebugReporting                   bool                                                  `json:\"debugReporting\"`\n\tEventLevelEpsilon                float64                                               `json:\"eventLevelEpsilon\"`\n}\n\n// AttributionReportingSourceRegistrationResult [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingSourceRegistrationResult\ntype AttributionReportingSourceRegistrationResult string\n\n// String returns the AttributionReportingSourceRegistrationResult as string value.\nfunc (t AttributionReportingSourceRegistrationResult) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingSourceRegistrationResult values.\nconst (\n\tAttributionReportingSourceRegistrationResultSuccess                                AttributionReportingSourceRegistrationResult = \"success\"\n\tAttributionReportingSourceRegistrationResultInternalError                          AttributionReportingSourceRegistrationResult = \"internalError\"\n\tAttributionReportingSourceRegistrationResultInsufficientSourceCapacity             AttributionReportingSourceRegistrationResult = \"insufficientSourceCapacity\"\n\tAttributionReportingSourceRegistrationResultInsufficientUniqueDestinationCapacity  AttributionReportingSourceRegistrationResult = \"insufficientUniqueDestinationCapacity\"\n\tAttributionReportingSourceRegistrationResultExcessiveReportingOrigins              AttributionReportingSourceRegistrationResult = \"excessiveReportingOrigins\"\n\tAttributionReportingSourceRegistrationResultProhibitedByBrowserPolicy              AttributionReportingSourceRegistrationResult = \"prohibitedByBrowserPolicy\"\n\tAttributionReportingSourceRegistrationResultSuccessNoised                          AttributionReportingSourceRegistrationResult = \"successNoised\"\n\tAttributionReportingSourceRegistrationResultDestinationReportingLimitReached       AttributionReportingSourceRegistrationResult = \"destinationReportingLimitReached\"\n\tAttributionReportingSourceRegistrationResultDestinationGlobalLimitReached          AttributionReportingSourceRegistrationResult = \"destinationGlobalLimitReached\"\n\tAttributionReportingSourceRegistrationResultDestinationBothLimitsReached           AttributionReportingSourceRegistrationResult = \"destinationBothLimitsReached\"\n\tAttributionReportingSourceRegistrationResultReportingOriginsPerSiteLimitReached    AttributionReportingSourceRegistrationResult = \"reportingOriginsPerSiteLimitReached\"\n\tAttributionReportingSourceRegistrationResultExceedsMaxChannelCapacity              AttributionReportingSourceRegistrationResult = \"exceedsMaxChannelCapacity\"\n\tAttributionReportingSourceRegistrationResultExceedsMaxScopesChannelCapacity        AttributionReportingSourceRegistrationResult = \"exceedsMaxScopesChannelCapacity\"\n\tAttributionReportingSourceRegistrationResultExceedsMaxTriggerStateCardinality      AttributionReportingSourceRegistrationResult = \"exceedsMaxTriggerStateCardinality\"\n\tAttributionReportingSourceRegistrationResultExceedsMaxEventStatesLimit             AttributionReportingSourceRegistrationResult = \"exceedsMaxEventStatesLimit\"\n\tAttributionReportingSourceRegistrationResultDestinationPerDayReportingLimitReached AttributionReportingSourceRegistrationResult = \"destinationPerDayReportingLimitReached\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingSourceRegistrationResult) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingSourceRegistrationResult(s) {\n\tcase AttributionReportingSourceRegistrationResultSuccess:\n\t\t*t = AttributionReportingSourceRegistrationResultSuccess\n\tcase AttributionReportingSourceRegistrationResultInternalError:\n\t\t*t = AttributionReportingSourceRegistrationResultInternalError\n\tcase AttributionReportingSourceRegistrationResultInsufficientSourceCapacity:\n\t\t*t = AttributionReportingSourceRegistrationResultInsufficientSourceCapacity\n\tcase AttributionReportingSourceRegistrationResultInsufficientUniqueDestinationCapacity:\n\t\t*t = AttributionReportingSourceRegistrationResultInsufficientUniqueDestinationCapacity\n\tcase AttributionReportingSourceRegistrationResultExcessiveReportingOrigins:\n\t\t*t = AttributionReportingSourceRegistrationResultExcessiveReportingOrigins\n\tcase AttributionReportingSourceRegistrationResultProhibitedByBrowserPolicy:\n\t\t*t = AttributionReportingSourceRegistrationResultProhibitedByBrowserPolicy\n\tcase AttributionReportingSourceRegistrationResultSuccessNoised:\n\t\t*t = AttributionReportingSourceRegistrationResultSuccessNoised\n\tcase AttributionReportingSourceRegistrationResultDestinationReportingLimitReached:\n\t\t*t = AttributionReportingSourceRegistrationResultDestinationReportingLimitReached\n\tcase AttributionReportingSourceRegistrationResultDestinationGlobalLimitReached:\n\t\t*t = AttributionReportingSourceRegistrationResultDestinationGlobalLimitReached\n\tcase AttributionReportingSourceRegistrationResultDestinationBothLimitsReached:\n\t\t*t = AttributionReportingSourceRegistrationResultDestinationBothLimitsReached\n\tcase AttributionReportingSourceRegistrationResultReportingOriginsPerSiteLimitReached:\n\t\t*t = AttributionReportingSourceRegistrationResultReportingOriginsPerSiteLimitReached\n\tcase AttributionReportingSourceRegistrationResultExceedsMaxChannelCapacity:\n\t\t*t = AttributionReportingSourceRegistrationResultExceedsMaxChannelCapacity\n\tcase AttributionReportingSourceRegistrationResultExceedsMaxScopesChannelCapacity:\n\t\t*t = AttributionReportingSourceRegistrationResultExceedsMaxScopesChannelCapacity\n\tcase AttributionReportingSourceRegistrationResultExceedsMaxTriggerStateCardinality:\n\t\t*t = AttributionReportingSourceRegistrationResultExceedsMaxTriggerStateCardinality\n\tcase AttributionReportingSourceRegistrationResultExceedsMaxEventStatesLimit:\n\t\t*t = AttributionReportingSourceRegistrationResultExceedsMaxEventStatesLimit\n\tcase AttributionReportingSourceRegistrationResultDestinationPerDayReportingLimitReached:\n\t\t*t = AttributionReportingSourceRegistrationResultDestinationPerDayReportingLimitReached\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingSourceRegistrationResult value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AttributionReportingSourceRegistrationTimeConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingSourceRegistrationTimeConfig\ntype AttributionReportingSourceRegistrationTimeConfig string\n\n// String returns the AttributionReportingSourceRegistrationTimeConfig as string value.\nfunc (t AttributionReportingSourceRegistrationTimeConfig) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingSourceRegistrationTimeConfig values.\nconst (\n\tAttributionReportingSourceRegistrationTimeConfigInclude AttributionReportingSourceRegistrationTimeConfig = \"include\"\n\tAttributionReportingSourceRegistrationTimeConfigExclude AttributionReportingSourceRegistrationTimeConfig = \"exclude\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingSourceRegistrationTimeConfig) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingSourceRegistrationTimeConfig(s) {\n\tcase AttributionReportingSourceRegistrationTimeConfigInclude:\n\t\t*t = AttributionReportingSourceRegistrationTimeConfigInclude\n\tcase AttributionReportingSourceRegistrationTimeConfigExclude:\n\t\t*t = AttributionReportingSourceRegistrationTimeConfigExclude\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingSourceRegistrationTimeConfig value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AttributionReportingAggregatableValueDictEntry [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregatableValueDictEntry\ntype AttributionReportingAggregatableValueDictEntry struct {\n\tKey         string                `json:\"key\"`\n\tValue       float64               `json:\"value\"` // number instead of integer because not all uint32 can be represented by int\n\tFilteringID UnsignedInt64asBase10 `json:\"filteringId\"`\n}\n\n// AttributionReportingAggregatableValueEntry [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregatableValueEntry\ntype AttributionReportingAggregatableValueEntry struct {\n\tValues  []*AttributionReportingAggregatableValueDictEntry `json:\"values\"`\n\tFilters *AttributionReportingFilterPair                   `json:\"filters\"`\n}\n\n// AttributionReportingEventTriggerData [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingEventTriggerData\ntype AttributionReportingEventTriggerData struct {\n\tData     UnsignedInt64asBase10           `json:\"data\"`\n\tPriority SignedInt64asBase10             `json:\"priority\"`\n\tDedupKey UnsignedInt64asBase10           `json:\"dedupKey,omitempty,omitzero\"`\n\tFilters  *AttributionReportingFilterPair `json:\"filters\"`\n}\n\n// AttributionReportingAggregatableTriggerData [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregatableTriggerData\ntype AttributionReportingAggregatableTriggerData struct {\n\tKeyPiece   UnsignedInt128asBase16          `json:\"keyPiece\"`\n\tSourceKeys []string                        `json:\"sourceKeys\"`\n\tFilters    *AttributionReportingFilterPair `json:\"filters\"`\n}\n\n// AttributionReportingAggregatableDedupKey [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregatableDedupKey\ntype AttributionReportingAggregatableDedupKey struct {\n\tDedupKey UnsignedInt64asBase10           `json:\"dedupKey,omitempty,omitzero\"`\n\tFilters  *AttributionReportingFilterPair `json:\"filters\"`\n}\n\n// AttributionReportingNamedBudgetCandidate [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingNamedBudgetCandidate\ntype AttributionReportingNamedBudgetCandidate struct {\n\tName    string                          `json:\"name,omitempty,omitzero\"`\n\tFilters *AttributionReportingFilterPair `json:\"filters\"`\n}\n\n// AttributionReportingTriggerRegistration [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingTriggerRegistration\ntype AttributionReportingTriggerRegistration struct {\n\tFilters                          *AttributionReportingFilterPair                       `json:\"filters\"`\n\tDebugKey                         UnsignedInt64asBase10                                 `json:\"debugKey,omitempty,omitzero\"`\n\tAggregatableDedupKeys            []*AttributionReportingAggregatableDedupKey           `json:\"aggregatableDedupKeys\"`\n\tEventTriggerData                 []*AttributionReportingEventTriggerData               `json:\"eventTriggerData\"`\n\tAggregatableTriggerData          []*AttributionReportingAggregatableTriggerData        `json:\"aggregatableTriggerData\"`\n\tAggregatableValues               []*AttributionReportingAggregatableValueEntry         `json:\"aggregatableValues\"`\n\tAggregatableFilteringIDMaxBytes  int64                                                 `json:\"aggregatableFilteringIdMaxBytes\"`\n\tDebugReporting                   bool                                                  `json:\"debugReporting\"`\n\tAggregationCoordinatorOrigin     string                                                `json:\"aggregationCoordinatorOrigin,omitempty,omitzero\"`\n\tSourceRegistrationTimeConfig     AttributionReportingSourceRegistrationTimeConfig      `json:\"sourceRegistrationTimeConfig\"`\n\tTriggerContextID                 string                                                `json:\"triggerContextId,omitempty,omitzero\"`\n\tAggregatableDebugReportingConfig *AttributionReportingAggregatableDebugReportingConfig `json:\"aggregatableDebugReportingConfig\"`\n\tScopes                           []string                                              `json:\"scopes\"`\n\tNamedBudgets                     []*AttributionReportingNamedBudgetCandidate           `json:\"namedBudgets\"`\n}\n\n// AttributionReportingEventLevelResult [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingEventLevelResult\ntype AttributionReportingEventLevelResult string\n\n// String returns the AttributionReportingEventLevelResult as string value.\nfunc (t AttributionReportingEventLevelResult) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingEventLevelResult values.\nconst (\n\tAttributionReportingEventLevelResultSuccess                             AttributionReportingEventLevelResult = \"success\"\n\tAttributionReportingEventLevelResultSuccessDroppedLowerPriority         AttributionReportingEventLevelResult = \"successDroppedLowerPriority\"\n\tAttributionReportingEventLevelResultInternalError                       AttributionReportingEventLevelResult = \"internalError\"\n\tAttributionReportingEventLevelResultNoCapacityForAttributionDestination AttributionReportingEventLevelResult = \"noCapacityForAttributionDestination\"\n\tAttributionReportingEventLevelResultNoMatchingSources                   AttributionReportingEventLevelResult = \"noMatchingSources\"\n\tAttributionReportingEventLevelResultDeduplicated                        AttributionReportingEventLevelResult = \"deduplicated\"\n\tAttributionReportingEventLevelResultExcessiveAttributions               AttributionReportingEventLevelResult = \"excessiveAttributions\"\n\tAttributionReportingEventLevelResultPriorityTooLow                      AttributionReportingEventLevelResult = \"priorityTooLow\"\n\tAttributionReportingEventLevelResultNeverAttributedSource               AttributionReportingEventLevelResult = \"neverAttributedSource\"\n\tAttributionReportingEventLevelResultExcessiveReportingOrigins           AttributionReportingEventLevelResult = \"excessiveReportingOrigins\"\n\tAttributionReportingEventLevelResultNoMatchingSourceFilterData          AttributionReportingEventLevelResult = \"noMatchingSourceFilterData\"\n\tAttributionReportingEventLevelResultProhibitedByBrowserPolicy           AttributionReportingEventLevelResult = \"prohibitedByBrowserPolicy\"\n\tAttributionReportingEventLevelResultNoMatchingConfigurations            AttributionReportingEventLevelResult = \"noMatchingConfigurations\"\n\tAttributionReportingEventLevelResultExcessiveReports                    AttributionReportingEventLevelResult = \"excessiveReports\"\n\tAttributionReportingEventLevelResultFalselyAttributedSource             AttributionReportingEventLevelResult = \"falselyAttributedSource\"\n\tAttributionReportingEventLevelResultReportWindowPassed                  AttributionReportingEventLevelResult = \"reportWindowPassed\"\n\tAttributionReportingEventLevelResultNotRegistered                       AttributionReportingEventLevelResult = \"notRegistered\"\n\tAttributionReportingEventLevelResultReportWindowNotStarted              AttributionReportingEventLevelResult = \"reportWindowNotStarted\"\n\tAttributionReportingEventLevelResultNoMatchingTriggerData               AttributionReportingEventLevelResult = \"noMatchingTriggerData\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingEventLevelResult) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingEventLevelResult(s) {\n\tcase AttributionReportingEventLevelResultSuccess:\n\t\t*t = AttributionReportingEventLevelResultSuccess\n\tcase AttributionReportingEventLevelResultSuccessDroppedLowerPriority:\n\t\t*t = AttributionReportingEventLevelResultSuccessDroppedLowerPriority\n\tcase AttributionReportingEventLevelResultInternalError:\n\t\t*t = AttributionReportingEventLevelResultInternalError\n\tcase AttributionReportingEventLevelResultNoCapacityForAttributionDestination:\n\t\t*t = AttributionReportingEventLevelResultNoCapacityForAttributionDestination\n\tcase AttributionReportingEventLevelResultNoMatchingSources:\n\t\t*t = AttributionReportingEventLevelResultNoMatchingSources\n\tcase AttributionReportingEventLevelResultDeduplicated:\n\t\t*t = AttributionReportingEventLevelResultDeduplicated\n\tcase AttributionReportingEventLevelResultExcessiveAttributions:\n\t\t*t = AttributionReportingEventLevelResultExcessiveAttributions\n\tcase AttributionReportingEventLevelResultPriorityTooLow:\n\t\t*t = AttributionReportingEventLevelResultPriorityTooLow\n\tcase AttributionReportingEventLevelResultNeverAttributedSource:\n\t\t*t = AttributionReportingEventLevelResultNeverAttributedSource\n\tcase AttributionReportingEventLevelResultExcessiveReportingOrigins:\n\t\t*t = AttributionReportingEventLevelResultExcessiveReportingOrigins\n\tcase AttributionReportingEventLevelResultNoMatchingSourceFilterData:\n\t\t*t = AttributionReportingEventLevelResultNoMatchingSourceFilterData\n\tcase AttributionReportingEventLevelResultProhibitedByBrowserPolicy:\n\t\t*t = AttributionReportingEventLevelResultProhibitedByBrowserPolicy\n\tcase AttributionReportingEventLevelResultNoMatchingConfigurations:\n\t\t*t = AttributionReportingEventLevelResultNoMatchingConfigurations\n\tcase AttributionReportingEventLevelResultExcessiveReports:\n\t\t*t = AttributionReportingEventLevelResultExcessiveReports\n\tcase AttributionReportingEventLevelResultFalselyAttributedSource:\n\t\t*t = AttributionReportingEventLevelResultFalselyAttributedSource\n\tcase AttributionReportingEventLevelResultReportWindowPassed:\n\t\t*t = AttributionReportingEventLevelResultReportWindowPassed\n\tcase AttributionReportingEventLevelResultNotRegistered:\n\t\t*t = AttributionReportingEventLevelResultNotRegistered\n\tcase AttributionReportingEventLevelResultReportWindowNotStarted:\n\t\t*t = AttributionReportingEventLevelResultReportWindowNotStarted\n\tcase AttributionReportingEventLevelResultNoMatchingTriggerData:\n\t\t*t = AttributionReportingEventLevelResultNoMatchingTriggerData\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingEventLevelResult value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AttributionReportingAggregatableResult [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingAggregatableResult\ntype AttributionReportingAggregatableResult string\n\n// String returns the AttributionReportingAggregatableResult as string value.\nfunc (t AttributionReportingAggregatableResult) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingAggregatableResult values.\nconst (\n\tAttributionReportingAggregatableResultSuccess                             AttributionReportingAggregatableResult = \"success\"\n\tAttributionReportingAggregatableResultInternalError                       AttributionReportingAggregatableResult = \"internalError\"\n\tAttributionReportingAggregatableResultNoCapacityForAttributionDestination AttributionReportingAggregatableResult = \"noCapacityForAttributionDestination\"\n\tAttributionReportingAggregatableResultNoMatchingSources                   AttributionReportingAggregatableResult = \"noMatchingSources\"\n\tAttributionReportingAggregatableResultExcessiveAttributions               AttributionReportingAggregatableResult = \"excessiveAttributions\"\n\tAttributionReportingAggregatableResultExcessiveReportingOrigins           AttributionReportingAggregatableResult = \"excessiveReportingOrigins\"\n\tAttributionReportingAggregatableResultNoHistograms                        AttributionReportingAggregatableResult = \"noHistograms\"\n\tAttributionReportingAggregatableResultInsufficientBudget                  AttributionReportingAggregatableResult = \"insufficientBudget\"\n\tAttributionReportingAggregatableResultInsufficientNamedBudget             AttributionReportingAggregatableResult = \"insufficientNamedBudget\"\n\tAttributionReportingAggregatableResultNoMatchingSourceFilterData          AttributionReportingAggregatableResult = \"noMatchingSourceFilterData\"\n\tAttributionReportingAggregatableResultNotRegistered                       AttributionReportingAggregatableResult = \"notRegistered\"\n\tAttributionReportingAggregatableResultProhibitedByBrowserPolicy           AttributionReportingAggregatableResult = \"prohibitedByBrowserPolicy\"\n\tAttributionReportingAggregatableResultDeduplicated                        AttributionReportingAggregatableResult = \"deduplicated\"\n\tAttributionReportingAggregatableResultReportWindowPassed                  AttributionReportingAggregatableResult = \"reportWindowPassed\"\n\tAttributionReportingAggregatableResultExcessiveReports                    AttributionReportingAggregatableResult = \"excessiveReports\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingAggregatableResult) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingAggregatableResult(s) {\n\tcase AttributionReportingAggregatableResultSuccess:\n\t\t*t = AttributionReportingAggregatableResultSuccess\n\tcase AttributionReportingAggregatableResultInternalError:\n\t\t*t = AttributionReportingAggregatableResultInternalError\n\tcase AttributionReportingAggregatableResultNoCapacityForAttributionDestination:\n\t\t*t = AttributionReportingAggregatableResultNoCapacityForAttributionDestination\n\tcase AttributionReportingAggregatableResultNoMatchingSources:\n\t\t*t = AttributionReportingAggregatableResultNoMatchingSources\n\tcase AttributionReportingAggregatableResultExcessiveAttributions:\n\t\t*t = AttributionReportingAggregatableResultExcessiveAttributions\n\tcase AttributionReportingAggregatableResultExcessiveReportingOrigins:\n\t\t*t = AttributionReportingAggregatableResultExcessiveReportingOrigins\n\tcase AttributionReportingAggregatableResultNoHistograms:\n\t\t*t = AttributionReportingAggregatableResultNoHistograms\n\tcase AttributionReportingAggregatableResultInsufficientBudget:\n\t\t*t = AttributionReportingAggregatableResultInsufficientBudget\n\tcase AttributionReportingAggregatableResultInsufficientNamedBudget:\n\t\t*t = AttributionReportingAggregatableResultInsufficientNamedBudget\n\tcase AttributionReportingAggregatableResultNoMatchingSourceFilterData:\n\t\t*t = AttributionReportingAggregatableResultNoMatchingSourceFilterData\n\tcase AttributionReportingAggregatableResultNotRegistered:\n\t\t*t = AttributionReportingAggregatableResultNotRegistered\n\tcase AttributionReportingAggregatableResultProhibitedByBrowserPolicy:\n\t\t*t = AttributionReportingAggregatableResultProhibitedByBrowserPolicy\n\tcase AttributionReportingAggregatableResultDeduplicated:\n\t\t*t = AttributionReportingAggregatableResultDeduplicated\n\tcase AttributionReportingAggregatableResultReportWindowPassed:\n\t\t*t = AttributionReportingAggregatableResultReportWindowPassed\n\tcase AttributionReportingAggregatableResultExcessiveReports:\n\t\t*t = AttributionReportingAggregatableResultExcessiveReports\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingAggregatableResult value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AttributionReportingReportResult [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-AttributionReportingReportResult\ntype AttributionReportingReportResult string\n\n// String returns the AttributionReportingReportResult as string value.\nfunc (t AttributionReportingReportResult) String() string {\n\treturn string(t)\n}\n\n// AttributionReportingReportResult values.\nconst (\n\tAttributionReportingReportResultSent             AttributionReportingReportResult = \"sent\"\n\tAttributionReportingReportResultProhibited       AttributionReportingReportResult = \"prohibited\"\n\tAttributionReportingReportResultFailedToAssemble AttributionReportingReportResult = \"failedToAssemble\"\n\tAttributionReportingReportResultExpired          AttributionReportingReportResult = \"expired\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AttributionReportingReportResult) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AttributionReportingReportResult(s) {\n\tcase AttributionReportingReportResultSent:\n\t\t*t = AttributionReportingReportResultSent\n\tcase AttributionReportingReportResultProhibited:\n\t\t*t = AttributionReportingReportResultProhibited\n\tcase AttributionReportingReportResultFailedToAssemble:\n\t\t*t = AttributionReportingReportResultFailedToAssemble\n\tcase AttributionReportingReportResultExpired:\n\t\t*t = AttributionReportingReportResultExpired\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AttributionReportingReportResult value: %v\", s)\n\t}\n\treturn nil\n}\n\n// RelatedWebsiteSet a single Related Website Set object.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Storage#type-RelatedWebsiteSet\ntype RelatedWebsiteSet struct {\n\tPrimarySites    []string `json:\"primarySites\"`    // The primary site of this set, along with the ccTLDs if there is any.\n\tAssociatedSites []string `json:\"associatedSites\"` // The associated sites of this set, along with the ccTLDs if there is any.\n\tServiceSites    []string `json:\"serviceSites\"`    // The service sites of this set, along with the ccTLDs if there is any.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/systeminfo/systeminfo.go",
    "content": "// Package systeminfo provides the Chrome DevTools Protocol\n// commands, types, and events for the SystemInfo domain.\n//\n// The SystemInfo domain defines methods and events for querying low-level\n// system information.\n//\n// Generated by the cdproto-gen command.\npackage systeminfo\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// GetInfoParams returns information about the system.\ntype GetInfoParams struct{}\n\n// GetInfo returns information about the system.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getInfo\nfunc GetInfo() *GetInfoParams {\n\treturn &GetInfoParams{}\n}\n\n// GetInfoReturns return values.\ntype GetInfoReturns struct {\n\tGPU          *GPUInfo `json:\"gpu,omitempty,omitzero\"`          // Information about the GPUs on the system.\n\tModelName    string   `json:\"modelName,omitempty,omitzero\"`    // A platform-dependent description of the model of the machine. On Mac OS, this is, for example, 'MacBookPro'. Will be the empty string if not supported.\n\tModelVersion string   `json:\"modelVersion,omitempty,omitzero\"` // A platform-dependent description of the version of the machine. On Mac OS, this is, for example, '10.1'. Will be the empty string if not supported.\n\tCommandLine  string   `json:\"commandLine,omitempty,omitzero\"`  // The command line string used to launch the browser. Will be the empty string if not supported.\n}\n\n// Do executes SystemInfo.getInfo against the provided context.\n//\n// returns:\n//\n//\tgpu - Information about the GPUs on the system.\n//\tmodelName - A platform-dependent description of the model of the machine. On Mac OS, this is, for example, 'MacBookPro'. Will be the empty string if not supported.\n//\tmodelVersion - A platform-dependent description of the version of the machine. On Mac OS, this is, for example, '10.1'. Will be the empty string if not supported.\n//\tcommandLine - The command line string used to launch the browser. Will be the empty string if not supported.\nfunc (p *GetInfoParams) Do(ctx context.Context) (gpu *GPUInfo, modelName string, modelVersion string, commandLine string, err error) {\n\t// execute\n\tvar res GetInfoReturns\n\terr = cdp.Execute(ctx, CommandGetInfo, nil, &res)\n\tif err != nil {\n\t\treturn nil, \"\", \"\", \"\", err\n\t}\n\n\treturn res.GPU, res.ModelName, res.ModelVersion, res.CommandLine, nil\n}\n\n// GetFeatureStateParams returns information about the feature state.\ntype GetFeatureStateParams struct {\n\tFeatureState string `json:\"featureState\"`\n}\n\n// GetFeatureState returns information about the feature state.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getFeatureState\n//\n// parameters:\n//\n//\tfeatureState\nfunc GetFeatureState(featureState string) *GetFeatureStateParams {\n\treturn &GetFeatureStateParams{\n\t\tFeatureState: featureState,\n\t}\n}\n\n// GetFeatureStateReturns return values.\ntype GetFeatureStateReturns struct {\n\tFeatureEnabled bool `json:\"featureEnabled\"`\n}\n\n// Do executes SystemInfo.getFeatureState against the provided context.\n//\n// returns:\n//\n//\tfeatureEnabled\nfunc (p *GetFeatureStateParams) Do(ctx context.Context) (featureEnabled bool, err error) {\n\t// execute\n\tvar res GetFeatureStateReturns\n\terr = cdp.Execute(ctx, CommandGetFeatureState, p, &res)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\treturn res.FeatureEnabled, nil\n}\n\n// GetProcessInfoParams returns information about all running processes.\ntype GetProcessInfoParams struct{}\n\n// GetProcessInfo returns information about all running processes.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#method-getProcessInfo\nfunc GetProcessInfo() *GetProcessInfoParams {\n\treturn &GetProcessInfoParams{}\n}\n\n// GetProcessInfoReturns return values.\ntype GetProcessInfoReturns struct {\n\tProcessInfo []*ProcessInfo `json:\"processInfo,omitempty,omitzero\"` // An array of process info blocks.\n}\n\n// Do executes SystemInfo.getProcessInfo against the provided context.\n//\n// returns:\n//\n//\tprocessInfo - An array of process info blocks.\nfunc (p *GetProcessInfoParams) Do(ctx context.Context) (processInfo []*ProcessInfo, err error) {\n\t// execute\n\tvar res GetProcessInfoReturns\n\terr = cdp.Execute(ctx, CommandGetProcessInfo, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.ProcessInfo, nil\n}\n\n// Command names.\nconst (\n\tCommandGetInfo         = \"SystemInfo.getInfo\"\n\tCommandGetFeatureState = \"SystemInfo.getFeatureState\"\n\tCommandGetProcessInfo  = \"SystemInfo.getProcessInfo\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/systeminfo/types.go",
    "content": "package systeminfo\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// GPUDevice describes a single graphics processor (GPU).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-GPUDevice\ntype GPUDevice struct {\n\tVendorID      float64 `json:\"vendorId\"`                    // PCI ID of the GPU vendor, if available; 0 otherwise.\n\tDeviceID      float64 `json:\"deviceId\"`                    // PCI ID of the GPU device, if available; 0 otherwise.\n\tSubSysID      float64 `json:\"subSysId,omitempty,omitzero\"` // Sub sys ID of the GPU, only available on Windows.\n\tRevision      float64 `json:\"revision,omitempty,omitzero\"` // Revision of the GPU, only available on Windows.\n\tVendorString  string  `json:\"vendorString\"`                // String description of the GPU vendor, if the PCI ID is not available.\n\tDeviceString  string  `json:\"deviceString\"`                // String description of the GPU device, if the PCI ID is not available.\n\tDriverVendor  string  `json:\"driverVendor\"`                // String description of the GPU driver vendor.\n\tDriverVersion string  `json:\"driverVersion\"`               // String description of the GPU driver version.\n}\n\n// Size describes the width and height dimensions of an entity.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-Size\ntype Size struct {\n\tWidth  int64 `json:\"width\"`  // Width in pixels.\n\tHeight int64 `json:\"height\"` // Height in pixels.\n}\n\n// VideoDecodeAcceleratorCapability describes a supported video decoding\n// profile with its associated minimum and maximum resolutions.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-VideoDecodeAcceleratorCapability\ntype VideoDecodeAcceleratorCapability struct {\n\tProfile       string `json:\"profile\"`       // Video codec profile that is supported, e.g. VP9 Profile 2.\n\tMaxResolution *Size  `json:\"maxResolution\"` // Maximum video dimensions in pixels supported for this |profile|.\n\tMinResolution *Size  `json:\"minResolution\"` // Minimum video dimensions in pixels supported for this |profile|.\n}\n\n// VideoEncodeAcceleratorCapability describes a supported video encoding\n// profile with its associated maximum resolution and maximum framerate.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-VideoEncodeAcceleratorCapability\ntype VideoEncodeAcceleratorCapability struct {\n\tProfile                 string `json:\"profile\"`               // Video codec profile that is supported, e.g H264 Main.\n\tMaxResolution           *Size  `json:\"maxResolution\"`         // Maximum video dimensions in pixels supported for this |profile|.\n\tMaxFramerateNumerator   int64  `json:\"maxFramerateNumerator\"` // Maximum encoding framerate in frames per second supported for this |profile|, as fraction's numerator and denominator, e.g. 24/1 fps, 24000/1001 fps, etc.\n\tMaxFramerateDenominator int64  `json:\"maxFramerateDenominator\"`\n}\n\n// SubsamplingFormat yUV subsampling type of the pixels of a given image.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-SubsamplingFormat\ntype SubsamplingFormat string\n\n// String returns the SubsamplingFormat as string value.\nfunc (t SubsamplingFormat) String() string {\n\treturn string(t)\n}\n\n// SubsamplingFormat values.\nconst (\n\tSubsamplingFormatYuv420 SubsamplingFormat = \"yuv420\"\n\tSubsamplingFormatYuv422 SubsamplingFormat = \"yuv422\"\n\tSubsamplingFormatYuv444 SubsamplingFormat = \"yuv444\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *SubsamplingFormat) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch SubsamplingFormat(s) {\n\tcase SubsamplingFormatYuv420:\n\t\t*t = SubsamplingFormatYuv420\n\tcase SubsamplingFormatYuv422:\n\t\t*t = SubsamplingFormatYuv422\n\tcase SubsamplingFormatYuv444:\n\t\t*t = SubsamplingFormatYuv444\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown SubsamplingFormat value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ImageType image format of a given image.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-ImageType\ntype ImageType string\n\n// String returns the ImageType as string value.\nfunc (t ImageType) String() string {\n\treturn string(t)\n}\n\n// ImageType values.\nconst (\n\tImageTypeJpeg    ImageType = \"jpeg\"\n\tImageTypeWebp    ImageType = \"webp\"\n\tImageTypeUnknown ImageType = \"unknown\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ImageType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ImageType(s) {\n\tcase ImageTypeJpeg:\n\t\t*t = ImageTypeJpeg\n\tcase ImageTypeWebp:\n\t\t*t = ImageTypeWebp\n\tcase ImageTypeUnknown:\n\t\t*t = ImageTypeUnknown\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ImageType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ImageDecodeAcceleratorCapability describes a supported image decoding\n// profile with its associated minimum and maximum resolutions and subsampling.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-ImageDecodeAcceleratorCapability\ntype ImageDecodeAcceleratorCapability struct {\n\tImageType     ImageType           `json:\"imageType\"`     // Image coded, e.g. Jpeg.\n\tMaxDimensions *Size               `json:\"maxDimensions\"` // Maximum supported dimensions of the image in pixels.\n\tMinDimensions *Size               `json:\"minDimensions\"` // Minimum supported dimensions of the image in pixels.\n\tSubsamplings  []SubsamplingFormat `json:\"subsamplings\"`  // Optional array of supported subsampling formats, e.g. 4:2:0, if known.\n}\n\n// GPUInfo provides information about the GPU(s) on the system.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-GPUInfo\ntype GPUInfo struct {\n\tDevices              []*GPUDevice                        `json:\"devices\"` // The graphics devices on the system. Element 0 is the primary GPU.\n\tAuxAttributes        jsontext.Value                      `json:\"auxAttributes,omitempty,omitzero\"`\n\tFeatureStatus        jsontext.Value                      `json:\"featureStatus,omitempty,omitzero\"`\n\tDriverBugWorkarounds []string                            `json:\"driverBugWorkarounds\"` // An optional array of GPU driver bug workarounds.\n\tVideoDecoding        []*VideoDecodeAcceleratorCapability `json:\"videoDecoding\"`        // Supported accelerated video decoding capabilities.\n\tVideoEncoding        []*VideoEncodeAcceleratorCapability `json:\"videoEncoding\"`        // Supported accelerated video encoding capabilities.\n\tImageDecoding        []*ImageDecodeAcceleratorCapability `json:\"imageDecoding\"`        // Supported accelerated image decoding capabilities.\n}\n\n// ProcessInfo represents process info.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/SystemInfo#type-ProcessInfo\ntype ProcessInfo struct {\n\tType    string  `json:\"type\"`    // Specifies process type.\n\tID      int64   `json:\"id\"`      // Specifies process id.\n\tCPUTime float64 `json:\"cpuTime\"` // Specifies cumulative CPU usage in seconds across all threads of the process since the process start.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/target/events.go",
    "content": "package target\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventAttachedToTarget issued when attached to target because of\n// auto-attach or attachToTarget command.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#event-attachedToTarget\ntype EventAttachedToTarget struct {\n\tSessionID          SessionID `json:\"sessionId\"` // Identifier assigned to the session used to send/receive messages.\n\tTargetInfo         *Info     `json:\"targetInfo\"`\n\tWaitingForDebugger bool      `json:\"waitingForDebugger\"`\n}\n\n// EventDetachedFromTarget issued when detached from target for any reason\n// (including detachFromTarget command). Can be issued multiple times per target\n// if multiple sessions have been attached to it.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#event-detachedFromTarget\ntype EventDetachedFromTarget struct {\n\tSessionID SessionID `json:\"sessionId\"` // Detached session identifier.\n}\n\n// EventReceivedMessageFromTarget notifies about a new protocol message\n// received from the session (as reported in attachedToTarget event).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#event-receivedMessageFromTarget\ntype EventReceivedMessageFromTarget struct {\n\tSessionID SessionID `json:\"sessionId\"` // Identifier of a session which sends a message.\n\tMessage   string    `json:\"message\"`\n}\n\n// EventTargetCreated issued when a possible inspection target is created.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#event-targetCreated\ntype EventTargetCreated struct {\n\tTargetInfo *Info `json:\"targetInfo\"`\n}\n\n// EventTargetDestroyed issued when a target is destroyed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#event-targetDestroyed\ntype EventTargetDestroyed struct {\n\tTargetID ID `json:\"targetId\"`\n}\n\n// EventTargetCrashed issued when a target has crashed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#event-targetCrashed\ntype EventTargetCrashed struct {\n\tTargetID  ID     `json:\"targetId\"`\n\tStatus    string `json:\"status\"`    // Termination status type.\n\tErrorCode int64  `json:\"errorCode\"` // Termination error code.\n}\n\n// EventTargetInfoChanged issued when some information about a target has\n// changed. This only happens between targetCreated and targetDestroyed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#event-targetInfoChanged\ntype EventTargetInfoChanged struct {\n\tTargetInfo *Info `json:\"targetInfo\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/target/target.go",
    "content": "// Package target provides the Chrome DevTools Protocol\n// commands, types, and events for the Target domain.\n//\n// Supports additional targets discovery and allows to attach to them.\n//\n// Generated by the cdproto-gen command.\npackage target\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// ActivateTargetParams activates (focuses) the target.\ntype ActivateTargetParams struct {\n\tTargetID ID `json:\"targetId\"`\n}\n\n// ActivateTarget activates (focuses) the target.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-activateTarget\n//\n// parameters:\n//\n//\ttargetID\nfunc ActivateTarget(targetID ID) *ActivateTargetParams {\n\treturn &ActivateTargetParams{\n\t\tTargetID: targetID,\n\t}\n}\n\n// Do executes Target.activateTarget against the provided context.\nfunc (p *ActivateTargetParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandActivateTarget, p, nil)\n}\n\n// AttachToTargetParams attaches to the target with given id.\ntype AttachToTargetParams struct {\n\tTargetID ID   `json:\"targetId\"`\n\tFlatten  bool `json:\"flatten\"` // Enables \"flat\" access to the session via specifying sessionId attribute in the commands. We plan to make this the default, deprecate non-flattened mode, and eventually retire it. See crbug.com/991325.\n}\n\n// AttachToTarget attaches to the target with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-attachToTarget\n//\n// parameters:\n//\n//\ttargetID\nfunc AttachToTarget(targetID ID) *AttachToTargetParams {\n\treturn &AttachToTargetParams{\n\t\tTargetID: targetID,\n\t\tFlatten:  false,\n\t}\n}\n\n// WithFlatten enables \"flat\" access to the session via specifying sessionId\n// attribute in the commands. We plan to make this the default, deprecate\n// non-flattened mode, and eventually retire it. See crbug.com/991325.\nfunc (p AttachToTargetParams) WithFlatten(flatten bool) *AttachToTargetParams {\n\tp.Flatten = flatten\n\treturn &p\n}\n\n// AttachToTargetReturns return values.\ntype AttachToTargetReturns struct {\n\tSessionID SessionID `json:\"sessionId,omitempty,omitzero\"` // Id assigned to the session.\n}\n\n// Do executes Target.attachToTarget against the provided context.\n//\n// returns:\n//\n//\tsessionID - Id assigned to the session.\nfunc (p *AttachToTargetParams) Do(ctx context.Context) (sessionID SessionID, err error) {\n\t// execute\n\tvar res AttachToTargetReturns\n\terr = cdp.Execute(ctx, CommandAttachToTarget, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.SessionID, nil\n}\n\n// AttachToBrowserTargetParams attaches to the browser target, only uses flat\n// sessionId mode.\ntype AttachToBrowserTargetParams struct{}\n\n// AttachToBrowserTarget attaches to the browser target, only uses flat\n// sessionId mode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-attachToBrowserTarget\nfunc AttachToBrowserTarget() *AttachToBrowserTargetParams {\n\treturn &AttachToBrowserTargetParams{}\n}\n\n// AttachToBrowserTargetReturns return values.\ntype AttachToBrowserTargetReturns struct {\n\tSessionID SessionID `json:\"sessionId,omitempty,omitzero\"` // Id assigned to the session.\n}\n\n// Do executes Target.attachToBrowserTarget against the provided context.\n//\n// returns:\n//\n//\tsessionID - Id assigned to the session.\nfunc (p *AttachToBrowserTargetParams) Do(ctx context.Context) (sessionID SessionID, err error) {\n\t// execute\n\tvar res AttachToBrowserTargetReturns\n\terr = cdp.Execute(ctx, CommandAttachToBrowserTarget, nil, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.SessionID, nil\n}\n\n// CloseTargetParams closes the target. If the target is a page that gets\n// closed too.\ntype CloseTargetParams struct {\n\tTargetID ID `json:\"targetId\"`\n}\n\n// CloseTarget closes the target. If the target is a page that gets closed\n// too.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-closeTarget\n//\n// parameters:\n//\n//\ttargetID\nfunc CloseTarget(targetID ID) *CloseTargetParams {\n\treturn &CloseTargetParams{\n\t\tTargetID: targetID,\n\t}\n}\n\n// Do executes Target.closeTarget against the provided context.\nfunc (p *CloseTargetParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandCloseTarget, p, nil)\n}\n\n// ExposeDevToolsProtocolParams inject object to the target's main frame that\n// provides a communication channel with browser target. Injected object will be\n// available as window[bindingName]. The object has the following API: -\n// binding.send(json) - a method to send messages over the remote debugging\n// protocol - binding.onmessage = json => handleMessage(json) - a callback that\n// will be called for the protocol notifications and command responses.\ntype ExposeDevToolsProtocolParams struct {\n\tTargetID           ID     `json:\"targetId\"`\n\tBindingName        string `json:\"bindingName,omitempty,omitzero\"` // Binding name, 'cdp' if not specified.\n\tInheritPermissions bool   `json:\"inheritPermissions\"`             // If true, inherits the current root session's permissions (default: false).\n}\n\n// ExposeDevToolsProtocol inject object to the target's main frame that\n// provides a communication channel with browser target. Injected object will be\n// available as window[bindingName]. The object has the following API: -\n// binding.send(json) - a method to send messages over the remote debugging\n// protocol - binding.onmessage = json => handleMessage(json) - a callback that\n// will be called for the protocol notifications and command responses.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-exposeDevToolsProtocol\n//\n// parameters:\n//\n//\ttargetID\nfunc ExposeDevToolsProtocol(targetID ID) *ExposeDevToolsProtocolParams {\n\treturn &ExposeDevToolsProtocolParams{\n\t\tTargetID:           targetID,\n\t\tInheritPermissions: false,\n\t}\n}\n\n// WithBindingName binding name, 'cdp' if not specified.\nfunc (p ExposeDevToolsProtocolParams) WithBindingName(bindingName string) *ExposeDevToolsProtocolParams {\n\tp.BindingName = bindingName\n\treturn &p\n}\n\n// WithInheritPermissions if true, inherits the current root session's\n// permissions (default: false).\nfunc (p ExposeDevToolsProtocolParams) WithInheritPermissions(inheritPermissions bool) *ExposeDevToolsProtocolParams {\n\tp.InheritPermissions = inheritPermissions\n\treturn &p\n}\n\n// Do executes Target.exposeDevToolsProtocol against the provided context.\nfunc (p *ExposeDevToolsProtocolParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandExposeDevToolsProtocol, p, nil)\n}\n\n// CreateBrowserContextParams creates a new empty BrowserContext. Similar to\n// an incognito profile but you can have more than one.\ntype CreateBrowserContextParams struct {\n\tDisposeOnDetach                   bool     `json:\"disposeOnDetach\"`                                      // If specified, disposes this context when debugging session disconnects.\n\tProxyServer                       string   `json:\"proxyServer,omitempty,omitzero\"`                       // Proxy server, similar to the one passed to --proxy-server\n\tProxyBypassList                   string   `json:\"proxyBypassList,omitempty,omitzero\"`                   // Proxy bypass list, similar to the one passed to --proxy-bypass-list\n\tOriginsWithUniversalNetworkAccess []string `json:\"originsWithUniversalNetworkAccess,omitempty,omitzero\"` // An optional list of origins to grant unlimited cross-origin access to. Parts of the URL other than those constituting origin are ignored.\n}\n\n// CreateBrowserContext creates a new empty BrowserContext. Similar to an\n// incognito profile but you can have more than one.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-createBrowserContext\n//\n// parameters:\nfunc CreateBrowserContext() *CreateBrowserContextParams {\n\treturn &CreateBrowserContextParams{\n\t\tDisposeOnDetach: false,\n\t}\n}\n\n// WithDisposeOnDetach if specified, disposes this context when debugging\n// session disconnects.\nfunc (p CreateBrowserContextParams) WithDisposeOnDetach(disposeOnDetach bool) *CreateBrowserContextParams {\n\tp.DisposeOnDetach = disposeOnDetach\n\treturn &p\n}\n\n// WithProxyServer proxy server, similar to the one passed to --proxy-server.\nfunc (p CreateBrowserContextParams) WithProxyServer(proxyServer string) *CreateBrowserContextParams {\n\tp.ProxyServer = proxyServer\n\treturn &p\n}\n\n// WithProxyBypassList proxy bypass list, similar to the one passed to\n// --proxy-bypass-list.\nfunc (p CreateBrowserContextParams) WithProxyBypassList(proxyBypassList string) *CreateBrowserContextParams {\n\tp.ProxyBypassList = proxyBypassList\n\treturn &p\n}\n\n// WithOriginsWithUniversalNetworkAccess an optional list of origins to grant\n// unlimited cross-origin access to. Parts of the URL other than those\n// constituting origin are ignored.\nfunc (p CreateBrowserContextParams) WithOriginsWithUniversalNetworkAccess(originsWithUniversalNetworkAccess []string) *CreateBrowserContextParams {\n\tp.OriginsWithUniversalNetworkAccess = originsWithUniversalNetworkAccess\n\treturn &p\n}\n\n// CreateBrowserContextReturns return values.\ntype CreateBrowserContextReturns struct {\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // The id of the context created.\n}\n\n// Do executes Target.createBrowserContext against the provided context.\n//\n// returns:\n//\n//\tbrowserContextID - The id of the context created.\nfunc (p *CreateBrowserContextParams) Do(ctx context.Context) (browserContextID cdp.BrowserContextID, err error) {\n\t// execute\n\tvar res CreateBrowserContextReturns\n\terr = cdp.Execute(ctx, CommandCreateBrowserContext, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.BrowserContextID, nil\n}\n\n// GetBrowserContextsParams returns all browser contexts created with\n// Target.createBrowserContext method.\ntype GetBrowserContextsParams struct{}\n\n// GetBrowserContexts returns all browser contexts created with\n// Target.createBrowserContext method.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-getBrowserContexts\nfunc GetBrowserContexts() *GetBrowserContextsParams {\n\treturn &GetBrowserContextsParams{}\n}\n\n// GetBrowserContextsReturns return values.\ntype GetBrowserContextsReturns struct {\n\tBrowserContextIDs []cdp.BrowserContextID `json:\"browserContextIds,omitempty,omitzero\"` // An array of browser context ids.\n}\n\n// Do executes Target.getBrowserContexts against the provided context.\n//\n// returns:\n//\n//\tbrowserContextIDs - An array of browser context ids.\nfunc (p *GetBrowserContextsParams) Do(ctx context.Context) (browserContextIDs []cdp.BrowserContextID, err error) {\n\t// execute\n\tvar res GetBrowserContextsReturns\n\terr = cdp.Execute(ctx, CommandGetBrowserContexts, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.BrowserContextIDs, nil\n}\n\n// CreateTargetParams creates a new page.\ntype CreateTargetParams struct {\n\tURL                     string               `json:\"url\"`                                 // The initial URL the page will be navigated to. An empty string indicates about:blank.\n\tLeft                    int64                `json:\"left,omitempty,omitzero\"`             // Frame left origin in DIP (requires newWindow to be true or headless shell).\n\tTop                     int64                `json:\"top,omitempty,omitzero\"`              // Frame top origin in DIP (requires newWindow to be true or headless shell).\n\tWidth                   int64                `json:\"width,omitempty,omitzero\"`            // Frame width in DIP (requires newWindow to be true or headless shell).\n\tHeight                  int64                `json:\"height,omitempty,omitzero\"`           // Frame height in DIP (requires newWindow to be true or headless shell).\n\tWindowState             WindowState          `json:\"windowState,omitempty,omitzero\"`      // Frame window state (requires newWindow to be true or headless shell). Default is normal.\n\tBrowserContextID        cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"` // The browser context to create the page in.\n\tEnableBeginFrameControl bool                 `json:\"enableBeginFrameControl\"`             // Whether BeginFrames for this target will be controlled via DevTools (headless shell only, not supported on MacOS yet, false by default).\n\tNewWindow               bool                 `json:\"newWindow\"`                           // Whether to create a new Window or Tab (false by default, not supported by headless shell).\n\tBackground              bool                 `json:\"background\"`                          // Whether to create the target in background or foreground (false by default, not supported by headless shell).\n\tForTab                  bool                 `json:\"forTab\"`                              // Whether to create the target of type \"tab\".\n\tHidden                  bool                 `json:\"hidden\"`                              // Whether to create a hidden target. The hidden target is observable via protocol, but not present in the tab UI strip. Cannot be created with forTab: true, newWindow: true or background: false. The life-time of the tab is limited to the life-time of the session.\n}\n\n// CreateTarget creates a new page.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-createTarget\n//\n// parameters:\n//\n//\turl - The initial URL the page will be navigated to. An empty string indicates about:blank.\nfunc CreateTarget(url string) *CreateTargetParams {\n\treturn &CreateTargetParams{\n\t\tURL:                     url,\n\t\tEnableBeginFrameControl: false,\n\t\tNewWindow:               false,\n\t\tBackground:              false,\n\t\tForTab:                  false,\n\t\tHidden:                  false,\n\t}\n}\n\n// WithLeft frame left origin in DIP (requires newWindow to be true or\n// headless shell).\nfunc (p CreateTargetParams) WithLeft(left int64) *CreateTargetParams {\n\tp.Left = left\n\treturn &p\n}\n\n// WithTop frame top origin in DIP (requires newWindow to be true or headless\n// shell).\nfunc (p CreateTargetParams) WithTop(top int64) *CreateTargetParams {\n\tp.Top = top\n\treturn &p\n}\n\n// WithWidth frame width in DIP (requires newWindow to be true or headless\n// shell).\nfunc (p CreateTargetParams) WithWidth(width int64) *CreateTargetParams {\n\tp.Width = width\n\treturn &p\n}\n\n// WithHeight frame height in DIP (requires newWindow to be true or headless\n// shell).\nfunc (p CreateTargetParams) WithHeight(height int64) *CreateTargetParams {\n\tp.Height = height\n\treturn &p\n}\n\n// WithWindowState frame window state (requires newWindow to be true or\n// headless shell). Default is normal.\nfunc (p CreateTargetParams) WithWindowState(windowState WindowState) *CreateTargetParams {\n\tp.WindowState = windowState\n\treturn &p\n}\n\n// WithBrowserContextID the browser context to create the page in.\nfunc (p CreateTargetParams) WithBrowserContextID(browserContextID cdp.BrowserContextID) *CreateTargetParams {\n\tp.BrowserContextID = browserContextID\n\treturn &p\n}\n\n// WithEnableBeginFrameControl whether BeginFrames for this target will be\n// controlled via DevTools (headless shell only, not supported on MacOS yet,\n// false by default).\nfunc (p CreateTargetParams) WithEnableBeginFrameControl(enableBeginFrameControl bool) *CreateTargetParams {\n\tp.EnableBeginFrameControl = enableBeginFrameControl\n\treturn &p\n}\n\n// WithNewWindow whether to create a new Window or Tab (false by default, not\n// supported by headless shell).\nfunc (p CreateTargetParams) WithNewWindow(newWindow bool) *CreateTargetParams {\n\tp.NewWindow = newWindow\n\treturn &p\n}\n\n// WithBackground whether to create the target in background or foreground\n// (false by default, not supported by headless shell).\nfunc (p CreateTargetParams) WithBackground(background bool) *CreateTargetParams {\n\tp.Background = background\n\treturn &p\n}\n\n// WithForTab whether to create the target of type \"tab\".\nfunc (p CreateTargetParams) WithForTab(forTab bool) *CreateTargetParams {\n\tp.ForTab = forTab\n\treturn &p\n}\n\n// WithHidden whether to create a hidden target. The hidden target is\n// observable via protocol, but not present in the tab UI strip. Cannot be\n// created with forTab: true, newWindow: true or background: false. The\n// life-time of the tab is limited to the life-time of the session.\nfunc (p CreateTargetParams) WithHidden(hidden bool) *CreateTargetParams {\n\tp.Hidden = hidden\n\treturn &p\n}\n\n// CreateTargetReturns return values.\ntype CreateTargetReturns struct {\n\tTargetID ID `json:\"targetId,omitempty,omitzero\"` // The id of the page opened.\n}\n\n// Do executes Target.createTarget against the provided context.\n//\n// returns:\n//\n//\ttargetID - The id of the page opened.\nfunc (p *CreateTargetParams) Do(ctx context.Context) (targetID ID, err error) {\n\t// execute\n\tvar res CreateTargetReturns\n\terr = cdp.Execute(ctx, CommandCreateTarget, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.TargetID, nil\n}\n\n// DetachFromTargetParams detaches session with given id.\ntype DetachFromTargetParams struct {\n\tSessionID SessionID `json:\"sessionId,omitempty,omitzero\"` // Session to detach.\n}\n\n// DetachFromTarget detaches session with given id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-detachFromTarget\n//\n// parameters:\nfunc DetachFromTarget() *DetachFromTargetParams {\n\treturn &DetachFromTargetParams{}\n}\n\n// WithSessionID session to detach.\nfunc (p DetachFromTargetParams) WithSessionID(sessionID SessionID) *DetachFromTargetParams {\n\tp.SessionID = sessionID\n\treturn &p\n}\n\n// Do executes Target.detachFromTarget against the provided context.\nfunc (p *DetachFromTargetParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDetachFromTarget, p, nil)\n}\n\n// DisposeBrowserContextParams deletes a BrowserContext. All the belonging\n// pages will be closed without calling their beforeunload hooks.\ntype DisposeBrowserContextParams struct {\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId\"`\n}\n\n// DisposeBrowserContext deletes a BrowserContext. All the belonging pages\n// will be closed without calling their beforeunload hooks.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-disposeBrowserContext\n//\n// parameters:\n//\n//\tbrowserContextID\nfunc DisposeBrowserContext(browserContextID cdp.BrowserContextID) *DisposeBrowserContextParams {\n\treturn &DisposeBrowserContextParams{\n\t\tBrowserContextID: browserContextID,\n\t}\n}\n\n// Do executes Target.disposeBrowserContext against the provided context.\nfunc (p *DisposeBrowserContextParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisposeBrowserContext, p, nil)\n}\n\n// GetTargetInfoParams returns information about a target.\ntype GetTargetInfoParams struct {\n\tTargetID ID `json:\"targetId,omitempty,omitzero\"`\n}\n\n// GetTargetInfo returns information about a target.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-getTargetInfo\n//\n// parameters:\nfunc GetTargetInfo() *GetTargetInfoParams {\n\treturn &GetTargetInfoParams{}\n}\n\n// WithTargetID [no description].\nfunc (p GetTargetInfoParams) WithTargetID(targetID ID) *GetTargetInfoParams {\n\tp.TargetID = targetID\n\treturn &p\n}\n\n// GetTargetInfoReturns return values.\ntype GetTargetInfoReturns struct {\n\tTargetInfo *Info `json:\"targetInfo,omitempty,omitzero\"`\n}\n\n// Do executes Target.getTargetInfo against the provided context.\n//\n// returns:\n//\n//\ttargetInfo\nfunc (p *GetTargetInfoParams) Do(ctx context.Context) (targetInfo *Info, err error) {\n\t// execute\n\tvar res GetTargetInfoReturns\n\terr = cdp.Execute(ctx, CommandGetTargetInfo, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.TargetInfo, nil\n}\n\n// GetTargetsParams retrieves a list of available targets.\ntype GetTargetsParams struct {\n\tFilter Filter `json:\"filter,omitempty,omitzero\"` // Only targets matching filter will be reported. If filter is not specified and target discovery is currently enabled, a filter used for target discovery is used for consistency.\n}\n\n// GetTargets retrieves a list of available targets.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-getTargets\n//\n// parameters:\nfunc GetTargets() *GetTargetsParams {\n\treturn &GetTargetsParams{}\n}\n\n// WithFilter only targets matching filter will be reported. If filter is not\n// specified and target discovery is currently enabled, a filter used for target\n// discovery is used for consistency.\nfunc (p GetTargetsParams) WithFilter(filter Filter) *GetTargetsParams {\n\tp.Filter = filter\n\treturn &p\n}\n\n// GetTargetsReturns return values.\ntype GetTargetsReturns struct {\n\tTargetInfos []*Info `json:\"targetInfos,omitempty,omitzero\"` // The list of targets.\n}\n\n// Do executes Target.getTargets against the provided context.\n//\n// returns:\n//\n//\ttargetInfos - The list of targets.\nfunc (p *GetTargetsParams) Do(ctx context.Context) (targetInfos []*Info, err error) {\n\t// execute\n\tvar res GetTargetsReturns\n\terr = cdp.Execute(ctx, CommandGetTargets, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.TargetInfos, nil\n}\n\n// SetAutoAttachParams controls whether to automatically attach to new\n// targets which are considered to be directly related to this one (for example,\n// iframes or workers). When turned on, attaches to all existing related targets\n// as well. When turned off, automatically detaches from all currently attached\n// targets. This also clears all targets added by autoAttachRelated from the\n// list of targets to watch for creation of related targets. You might want to\n// call this recursively for auto-attached targets to attach to all available\n// targets.\ntype SetAutoAttachParams struct {\n\tAutoAttach             bool   `json:\"autoAttach\"`                // Whether to auto-attach to related targets.\n\tWaitForDebuggerOnStart bool   `json:\"waitForDebuggerOnStart\"`    // Whether to pause new targets when attaching to them. Use Runtime.runIfWaitingForDebugger to run paused targets.\n\tFlatten                bool   `json:\"flatten\"`                   // Enables \"flat\" access to the session via specifying sessionId attribute in the commands. We plan to make this the default, deprecate non-flattened mode, and eventually retire it. See crbug.com/991325.\n\tFilter                 Filter `json:\"filter,omitempty,omitzero\"` // Only targets matching filter will be attached.\n}\n\n// SetAutoAttach controls whether to automatically attach to new targets\n// which are considered to be directly related to this one (for example, iframes\n// or workers). When turned on, attaches to all existing related targets as\n// well. When turned off, automatically detaches from all currently attached\n// targets. This also clears all targets added by autoAttachRelated from the\n// list of targets to watch for creation of related targets. You might want to\n// call this recursively for auto-attached targets to attach to all available\n// targets.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-setAutoAttach\n//\n// parameters:\n//\n//\tautoAttach - Whether to auto-attach to related targets.\n//\twaitForDebuggerOnStart - Whether to pause new targets when attaching to them. Use Runtime.runIfWaitingForDebugger to run paused targets.\nfunc SetAutoAttach(autoAttach bool, waitForDebuggerOnStart bool) *SetAutoAttachParams {\n\treturn &SetAutoAttachParams{\n\t\tAutoAttach:             autoAttach,\n\t\tWaitForDebuggerOnStart: waitForDebuggerOnStart,\n\t\tFlatten:                false,\n\t}\n}\n\n// WithFlatten enables \"flat\" access to the session via specifying sessionId\n// attribute in the commands. We plan to make this the default, deprecate\n// non-flattened mode, and eventually retire it. See crbug.com/991325.\nfunc (p SetAutoAttachParams) WithFlatten(flatten bool) *SetAutoAttachParams {\n\tp.Flatten = flatten\n\treturn &p\n}\n\n// WithFilter only targets matching filter will be attached.\nfunc (p SetAutoAttachParams) WithFilter(filter Filter) *SetAutoAttachParams {\n\tp.Filter = filter\n\treturn &p\n}\n\n// Do executes Target.setAutoAttach against the provided context.\nfunc (p *SetAutoAttachParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAutoAttach, p, nil)\n}\n\n// AutoAttachRelatedParams adds the specified target to the list of targets\n// that will be monitored for any related target creation (such as child frames,\n// child workers and new versions of service worker) and reported through\n// attachedToTarget. The specified target is also auto-attached. This cancels\n// the effect of any previous setAutoAttach and is also cancelled by subsequent\n// setAutoAttach. Only available at the Browser target.\ntype AutoAttachRelatedParams struct {\n\tTargetID               ID     `json:\"targetId\"`\n\tWaitForDebuggerOnStart bool   `json:\"waitForDebuggerOnStart\"`    // Whether to pause new targets when attaching to them. Use Runtime.runIfWaitingForDebugger to run paused targets.\n\tFilter                 Filter `json:\"filter,omitempty,omitzero\"` // Only targets matching filter will be attached.\n}\n\n// AutoAttachRelated adds the specified target to the list of targets that\n// will be monitored for any related target creation (such as child frames,\n// child workers and new versions of service worker) and reported through\n// attachedToTarget. The specified target is also auto-attached. This cancels\n// the effect of any previous setAutoAttach and is also cancelled by subsequent\n// setAutoAttach. Only available at the Browser target.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-autoAttachRelated\n//\n// parameters:\n//\n//\ttargetID\n//\twaitForDebuggerOnStart - Whether to pause new targets when attaching to them. Use Runtime.runIfWaitingForDebugger to run paused targets.\nfunc AutoAttachRelated(targetID ID, waitForDebuggerOnStart bool) *AutoAttachRelatedParams {\n\treturn &AutoAttachRelatedParams{\n\t\tTargetID:               targetID,\n\t\tWaitForDebuggerOnStart: waitForDebuggerOnStart,\n\t}\n}\n\n// WithFilter only targets matching filter will be attached.\nfunc (p AutoAttachRelatedParams) WithFilter(filter Filter) *AutoAttachRelatedParams {\n\tp.Filter = filter\n\treturn &p\n}\n\n// Do executes Target.autoAttachRelated against the provided context.\nfunc (p *AutoAttachRelatedParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandAutoAttachRelated, p, nil)\n}\n\n// SetDiscoverTargetsParams controls whether to discover available targets\n// and notify via targetCreated/targetInfoChanged/targetDestroyed events.\ntype SetDiscoverTargetsParams struct {\n\tDiscover bool   `json:\"discover\"`                  // Whether to discover available targets.\n\tFilter   Filter `json:\"filter,omitempty,omitzero\"` // Only targets matching filter will be attached. If discover is false, filter must be omitted or empty.\n}\n\n// SetDiscoverTargets controls whether to discover available targets and\n// notify via targetCreated/targetInfoChanged/targetDestroyed events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-setDiscoverTargets\n//\n// parameters:\n//\n//\tdiscover - Whether to discover available targets.\nfunc SetDiscoverTargets(discover bool) *SetDiscoverTargetsParams {\n\treturn &SetDiscoverTargetsParams{\n\t\tDiscover: discover,\n\t}\n}\n\n// WithFilter only targets matching filter will be attached. If discover is\n// false, filter must be omitted or empty.\nfunc (p SetDiscoverTargetsParams) WithFilter(filter Filter) *SetDiscoverTargetsParams {\n\tp.Filter = filter\n\treturn &p\n}\n\n// Do executes Target.setDiscoverTargets against the provided context.\nfunc (p *SetDiscoverTargetsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetDiscoverTargets, p, nil)\n}\n\n// SetRemoteLocationsParams enables target discovery for the specified\n// locations, when setDiscoverTargets was set to true.\ntype SetRemoteLocationsParams struct {\n\tLocations []*RemoteLocation `json:\"locations\"` // List of remote locations.\n}\n\n// SetRemoteLocations enables target discovery for the specified locations,\n// when setDiscoverTargets was set to true.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-setRemoteLocations\n//\n// parameters:\n//\n//\tlocations - List of remote locations.\nfunc SetRemoteLocations(locations []*RemoteLocation) *SetRemoteLocationsParams {\n\treturn &SetRemoteLocationsParams{\n\t\tLocations: locations,\n\t}\n}\n\n// Do executes Target.setRemoteLocations against the provided context.\nfunc (p *SetRemoteLocationsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetRemoteLocations, p, nil)\n}\n\n// OpenDevToolsParams opens a DevTools window for the target.\ntype OpenDevToolsParams struct {\n\tTargetID ID `json:\"targetId\"` // This can be the page or tab target ID.\n}\n\n// OpenDevTools opens a DevTools window for the target.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#method-openDevTools\n//\n// parameters:\n//\n//\ttargetID - This can be the page or tab target ID.\nfunc OpenDevTools(targetID ID) *OpenDevToolsParams {\n\treturn &OpenDevToolsParams{\n\t\tTargetID: targetID,\n\t}\n}\n\n// OpenDevToolsReturns return values.\ntype OpenDevToolsReturns struct {\n\tTargetID ID `json:\"targetId,omitempty,omitzero\"` // The targetId of DevTools page target.\n}\n\n// Do executes Target.openDevTools against the provided context.\n//\n// returns:\n//\n//\ttargetID - The targetId of DevTools page target.\nfunc (p *OpenDevToolsParams) Do(ctx context.Context) (targetID ID, err error) {\n\t// execute\n\tvar res OpenDevToolsReturns\n\terr = cdp.Execute(ctx, CommandOpenDevTools, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.TargetID, nil\n}\n\n// Command names.\nconst (\n\tCommandActivateTarget         = \"Target.activateTarget\"\n\tCommandAttachToTarget         = \"Target.attachToTarget\"\n\tCommandAttachToBrowserTarget  = \"Target.attachToBrowserTarget\"\n\tCommandCloseTarget            = \"Target.closeTarget\"\n\tCommandExposeDevToolsProtocol = \"Target.exposeDevToolsProtocol\"\n\tCommandCreateBrowserContext   = \"Target.createBrowserContext\"\n\tCommandGetBrowserContexts     = \"Target.getBrowserContexts\"\n\tCommandCreateTarget           = \"Target.createTarget\"\n\tCommandDetachFromTarget       = \"Target.detachFromTarget\"\n\tCommandDisposeBrowserContext  = \"Target.disposeBrowserContext\"\n\tCommandGetTargetInfo          = \"Target.getTargetInfo\"\n\tCommandGetTargets             = \"Target.getTargets\"\n\tCommandSetAutoAttach          = \"Target.setAutoAttach\"\n\tCommandAutoAttachRelated      = \"Target.autoAttachRelated\"\n\tCommandSetDiscoverTargets     = \"Target.setDiscoverTargets\"\n\tCommandSetRemoteLocations     = \"Target.setRemoteLocations\"\n\tCommandOpenDevTools           = \"Target.openDevTools\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/target/types.go",
    "content": "package target\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// ID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#type-TargetID\ntype ID string\n\n// String returns the ID as string value.\nfunc (t ID) String() string {\n\treturn string(t)\n}\n\n// SessionID unique identifier of attached debugging session.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#type-SessionID\ntype SessionID string\n\n// String returns the SessionID as string value.\nfunc (t SessionID) String() string {\n\treturn string(t)\n}\n\n// Info [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#type-TargetInfo\ntype Info struct {\n\tTargetID         ID                   `json:\"targetId\"`\n\tType             string               `json:\"type\"` // List of types: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/devtools_agent_host_impl.cc?ss=chromium&q=f:devtools%20-f:out%20%22::kTypeTab%5B%5D%22\n\tTitle            string               `json:\"title\"`\n\tURL              string               `json:\"url\"`\n\tAttached         bool                 `json:\"attached\"`                         // Whether the target has an attached client.\n\tOpenerID         ID                   `json:\"openerId,omitempty,omitzero\"`      // Opener target Id\n\tCanAccessOpener  bool                 `json:\"canAccessOpener\"`                  // Whether the target has access to the originating window.\n\tOpenerFrameID    cdp.FrameID          `json:\"openerFrameId,omitempty,omitzero\"` // Frame id of originating window (is only set if target has an opener).\n\tBrowserContextID cdp.BrowserContextID `json:\"browserContextId,omitempty,omitzero\"`\n\tSubtype          string               `json:\"subtype,omitempty,omitzero\"` // Provides additional details for specific target types. For example, for the type of \"page\", this may be set to \"prerender\".\n}\n\n// FilterEntry a filter used by target query/discovery/auto-attach\n// operations.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#type-FilterEntry\ntype FilterEntry struct {\n\tExclude bool   `json:\"exclude\"`                 // If set, causes exclusion of matching targets from the list.\n\tType    string `json:\"type,omitempty,omitzero\"` // If not present, matches any type.\n}\n\n// Filter the entries in TargetFilter are matched sequentially against\n// targets and the first entry that matches determines if the target is included\n// or not, depending on the value of exclude field in the entry. If filter is\n// not specified, the one assumed is [{type: \"browser\", exclude: true}, {type:\n// \"tab\", exclude: true}, {}] (i.e. include everything but browser and tab).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#type-TargetFilter\ntype Filter []struct {\n\tExclude bool   `json:\"exclude\"`                 // If set, causes exclusion of matching targets from the list.\n\tType    string `json:\"type,omitempty,omitzero\"` // If not present, matches any type.\n}\n\n// RemoteLocation [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#type-RemoteLocation\ntype RemoteLocation struct {\n\tHost string `json:\"host\"`\n\tPort int64  `json:\"port\"`\n}\n\n// WindowState the state of the target window.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Target#type-WindowState\ntype WindowState string\n\n// String returns the WindowState as string value.\nfunc (t WindowState) String() string {\n\treturn string(t)\n}\n\n// WindowState values.\nconst (\n\tWindowStateNormal     WindowState = \"normal\"\n\tWindowStateMinimized  WindowState = \"minimized\"\n\tWindowStateMaximized  WindowState = \"maximized\"\n\tWindowStateFullscreen WindowState = \"fullscreen\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *WindowState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch WindowState(s) {\n\tcase WindowStateNormal:\n\t\t*t = WindowStateNormal\n\tcase WindowStateMinimized:\n\t\t*t = WindowStateMinimized\n\tcase WindowStateMaximized:\n\t\t*t = WindowStateMaximized\n\tcase WindowStateFullscreen:\n\t\t*t = WindowStateFullscreen\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown WindowState value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/tethering/events.go",
    "content": "package tethering\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventAccepted informs that port was successfully bound and got a specified\n// connection id.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tethering#event-accepted\ntype EventAccepted struct {\n\tPort         int64  `json:\"port\"`         // Port number that was successfully bound.\n\tConnectionID string `json:\"connectionId\"` // Connection id to be used.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/tethering/tethering.go",
    "content": "// Package tethering provides the Chrome DevTools Protocol\n// commands, types, and events for the Tethering domain.\n//\n// The Tethering domain defines methods and events for browser port binding.\n//\n// Generated by the cdproto-gen command.\npackage tethering\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// BindParams request browser port binding.\ntype BindParams struct {\n\tPort int64 `json:\"port\"` // Port number to bind.\n}\n\n// Bind request browser port binding.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-bind\n//\n// parameters:\n//\n//\tport - Port number to bind.\nfunc Bind(port int64) *BindParams {\n\treturn &BindParams{\n\t\tPort: port,\n\t}\n}\n\n// Do executes Tethering.bind against the provided context.\nfunc (p *BindParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandBind, p, nil)\n}\n\n// UnbindParams request browser port unbinding.\ntype UnbindParams struct {\n\tPort int64 `json:\"port\"` // Port number to unbind.\n}\n\n// Unbind request browser port unbinding.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tethering#method-unbind\n//\n// parameters:\n//\n//\tport - Port number to unbind.\nfunc Unbind(port int64) *UnbindParams {\n\treturn &UnbindParams{\n\t\tPort: port,\n\t}\n}\n\n// Do executes Tethering.unbind against the provided context.\nfunc (p *UnbindParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandUnbind, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandBind   = \"Tethering.bind\"\n\tCommandUnbind = \"Tethering.unbind\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/tracing/events.go",
    "content": "package tracing\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"github.com/chromedp/cdproto/io\"\n\t\"github.com/go-json-experiment/json/jsontext\"\n)\n\n// EventBufferUsage [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#event-bufferUsage\ntype EventBufferUsage struct {\n\tPercentFull float64 `json:\"percentFull,omitempty,omitzero\"` // A number in range [0..1] that indicates the used size of event buffer as a fraction of its total size.\n\tEventCount  float64 `json:\"eventCount,omitempty,omitzero\"`  // An approximate number of events in the trace log.\n\tValue       float64 `json:\"value,omitempty,omitzero\"`       // A number in range [0..1] that indicates the used size of event buffer as a fraction of its total size.\n}\n\n// EventDataCollected contains a bucket of collected trace events. When\n// tracing is stopped collected events will be sent as a sequence of\n// dataCollected events followed by tracingComplete event.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#event-dataCollected\ntype EventDataCollected struct {\n\tValue []jsontext.Value `json:\"value\"`\n}\n\n// EventTracingComplete signals that tracing is stopped and there is no trace\n// buffers pending flush, all data were delivered via dataCollected events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#event-tracingComplete\ntype EventTracingComplete struct {\n\tDataLossOccurred  bool              `json:\"dataLossOccurred\"`                     // Indicates whether some trace data is known to have been lost, e.g. because the trace ring buffer wrapped around.\n\tStream            io.StreamHandle   `json:\"stream,omitempty,omitzero\"`            // A handle of the stream that holds resulting trace data.\n\tTraceFormat       StreamFormat      `json:\"traceFormat,omitempty,omitzero\"`       // Trace data format of returned stream.\n\tStreamCompression StreamCompression `json:\"streamCompression,omitempty,omitzero\"` // Compression format of returned stream.\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/tracing/tracing.go",
    "content": "// Package tracing provides the Chrome DevTools Protocol\n// commands, types, and events for the Tracing domain.\n//\n// Generated by the cdproto-gen command.\npackage tracing\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EndParams stop trace events collection.\ntype EndParams struct{}\n\n// End stop trace events collection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#method-end\nfunc End() *EndParams {\n\treturn &EndParams{}\n}\n\n// Do executes Tracing.end against the provided context.\nfunc (p *EndParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnd, nil, nil)\n}\n\n// GetCategoriesParams gets supported tracing categories.\ntype GetCategoriesParams struct{}\n\n// GetCategories gets supported tracing categories.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#method-getCategories\nfunc GetCategories() *GetCategoriesParams {\n\treturn &GetCategoriesParams{}\n}\n\n// GetCategoriesReturns return values.\ntype GetCategoriesReturns struct {\n\tCategories []string `json:\"categories,omitempty,omitzero\"` // A list of supported tracing categories.\n}\n\n// Do executes Tracing.getCategories against the provided context.\n//\n// returns:\n//\n//\tcategories - A list of supported tracing categories.\nfunc (p *GetCategoriesParams) Do(ctx context.Context) (categories []string, err error) {\n\t// execute\n\tvar res GetCategoriesReturns\n\terr = cdp.Execute(ctx, CommandGetCategories, nil, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Categories, nil\n}\n\n// RecordClockSyncMarkerParams record a clock sync marker in the trace.\ntype RecordClockSyncMarkerParams struct {\n\tSyncID string `json:\"syncId\"` // The ID of this clock sync marker\n}\n\n// RecordClockSyncMarker record a clock sync marker in the trace.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#method-recordClockSyncMarker\n//\n// parameters:\n//\n//\tsyncID - The ID of this clock sync marker\nfunc RecordClockSyncMarker(syncID string) *RecordClockSyncMarkerParams {\n\treturn &RecordClockSyncMarkerParams{\n\t\tSyncID: syncID,\n\t}\n}\n\n// Do executes Tracing.recordClockSyncMarker against the provided context.\nfunc (p *RecordClockSyncMarkerParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRecordClockSyncMarker, p, nil)\n}\n\n// RequestMemoryDumpParams request a global memory dump.\ntype RequestMemoryDumpParams struct {\n\tDeterministic bool                    `json:\"deterministic\"`                    // Enables more deterministic results by forcing garbage collection\n\tLevelOfDetail MemoryDumpLevelOfDetail `json:\"levelOfDetail,omitempty,omitzero\"` // Specifies level of details in memory dump. Defaults to \"detailed\".\n}\n\n// RequestMemoryDump request a global memory dump.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#method-requestMemoryDump\n//\n// parameters:\nfunc RequestMemoryDump() *RequestMemoryDumpParams {\n\treturn &RequestMemoryDumpParams{\n\t\tDeterministic: false,\n\t}\n}\n\n// WithDeterministic enables more deterministic results by forcing garbage\n// collection.\nfunc (p RequestMemoryDumpParams) WithDeterministic(deterministic bool) *RequestMemoryDumpParams {\n\tp.Deterministic = deterministic\n\treturn &p\n}\n\n// WithLevelOfDetail specifies level of details in memory dump. Defaults to\n// \"detailed\".\nfunc (p RequestMemoryDumpParams) WithLevelOfDetail(levelOfDetail MemoryDumpLevelOfDetail) *RequestMemoryDumpParams {\n\tp.LevelOfDetail = levelOfDetail\n\treturn &p\n}\n\n// RequestMemoryDumpReturns return values.\ntype RequestMemoryDumpReturns struct {\n\tDumpGUID string `json:\"dumpGuid,omitempty,omitzero\"` // GUID of the resulting global memory dump.\n\tSuccess  bool   `json:\"success\"`                     // True iff the global memory dump succeeded.\n}\n\n// Do executes Tracing.requestMemoryDump against the provided context.\n//\n// returns:\n//\n//\tdumpGUID - GUID of the resulting global memory dump.\n//\tsuccess - True iff the global memory dump succeeded.\nfunc (p *RequestMemoryDumpParams) Do(ctx context.Context) (dumpGUID string, success bool, err error) {\n\t// execute\n\tvar res RequestMemoryDumpReturns\n\terr = cdp.Execute(ctx, CommandRequestMemoryDump, p, &res)\n\tif err != nil {\n\t\treturn \"\", false, err\n\t}\n\n\treturn res.DumpGUID, res.Success, nil\n}\n\n// StartParams start trace events collection.\ntype StartParams struct {\n\tBufferUsageReportingInterval float64           `json:\"bufferUsageReportingInterval,omitempty,omitzero\"` // If set, the agent will issue bufferUsage events at this interval, specified in milliseconds\n\tTransferMode                 TransferMode      `json:\"transferMode,omitempty,omitzero\"`                 // Whether to report trace events as series of dataCollected events or to save trace to a stream (defaults to ReportEvents).\n\tStreamFormat                 StreamFormat      `json:\"streamFormat,omitempty,omitzero\"`                 // Trace data format to use. This only applies when using ReturnAsStream transfer mode (defaults to json).\n\tStreamCompression            StreamCompression `json:\"streamCompression,omitempty,omitzero\"`            // Compression format to use. This only applies when using ReturnAsStream transfer mode (defaults to none)\n\tTraceConfig                  *TraceConfig      `json:\"traceConfig,omitempty,omitzero\"`\n\tPerfettoConfig               string            `json:\"perfettoConfig,omitempty,omitzero\"` // Base64-encoded serialized perfetto.protos.TraceConfig protobuf message When specified, the parameters categories, options, traceConfig are ignored.\n\tTracingBackend               Backend           `json:\"tracingBackend,omitempty,omitzero\"` // Backend type (defaults to auto)\n}\n\n// Start start trace events collection.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#method-start\n//\n// parameters:\nfunc Start() *StartParams {\n\treturn &StartParams{}\n}\n\n// WithBufferUsageReportingInterval if set, the agent will issue bufferUsage\n// events at this interval, specified in milliseconds.\nfunc (p StartParams) WithBufferUsageReportingInterval(bufferUsageReportingInterval float64) *StartParams {\n\tp.BufferUsageReportingInterval = bufferUsageReportingInterval\n\treturn &p\n}\n\n// WithTransferMode whether to report trace events as series of dataCollected\n// events or to save trace to a stream (defaults to ReportEvents).\nfunc (p StartParams) WithTransferMode(transferMode TransferMode) *StartParams {\n\tp.TransferMode = transferMode\n\treturn &p\n}\n\n// WithStreamFormat trace data format to use. This only applies when using\n// ReturnAsStream transfer mode (defaults to json).\nfunc (p StartParams) WithStreamFormat(streamFormat StreamFormat) *StartParams {\n\tp.StreamFormat = streamFormat\n\treturn &p\n}\n\n// WithStreamCompression compression format to use. This only applies when\n// using ReturnAsStream transfer mode (defaults to none).\nfunc (p StartParams) WithStreamCompression(streamCompression StreamCompression) *StartParams {\n\tp.StreamCompression = streamCompression\n\treturn &p\n}\n\n// WithTraceConfig [no description].\nfunc (p StartParams) WithTraceConfig(traceConfig *TraceConfig) *StartParams {\n\tp.TraceConfig = traceConfig\n\treturn &p\n}\n\n// WithPerfettoConfig base64-encoded serialized perfetto.protos.TraceConfig\n// protobuf message When specified, the parameters categories, options,\n// traceConfig are ignored.\nfunc (p StartParams) WithPerfettoConfig(perfettoConfig string) *StartParams {\n\tp.PerfettoConfig = perfettoConfig\n\treturn &p\n}\n\n// WithTracingBackend backend type (defaults to auto).\nfunc (p StartParams) WithTracingBackend(tracingBackend Backend) *StartParams {\n\tp.TracingBackend = tracingBackend\n\treturn &p\n}\n\n// Do executes Tracing.start against the provided context.\nfunc (p *StartParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandStart, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnd                   = \"Tracing.end\"\n\tCommandGetCategories         = \"Tracing.getCategories\"\n\tCommandRecordClockSyncMarker = \"Tracing.recordClockSyncMarker\"\n\tCommandRequestMemoryDump     = \"Tracing.requestMemoryDump\"\n\tCommandStart                 = \"Tracing.start\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/tracing/types.go",
    "content": "package tracing\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// MemoryDumpConfig configuration for memory dump. Used only when\n// \"memory-infra\" category is enabled.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-MemoryDumpConfig\ntype MemoryDumpConfig struct{}\n\n// TraceConfig [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-TraceConfig\ntype TraceConfig struct {\n\tRecordMode           RecordMode        `json:\"recordMode,omitempty,omitzero\"`          // Controls how the trace buffer stores data. The default is recordUntilFull.\n\tTraceBufferSizeInKb  float64           `json:\"traceBufferSizeInKb,omitempty,omitzero\"` // Size of the trace buffer in kilobytes. If not specified or zero is passed, a default value of 200 MB would be used.\n\tEnableSampling       bool              `json:\"enableSampling\"`                         // Turns on JavaScript stack sampling.\n\tEnableSystrace       bool              `json:\"enableSystrace\"`                         // Turns on system tracing.\n\tEnableArgumentFilter bool              `json:\"enableArgumentFilter\"`                   // Turns on argument filter.\n\tIncludedCategories   []string          `json:\"includedCategories,omitempty,omitzero\"`  // Included category filters.\n\tExcludedCategories   []string          `json:\"excludedCategories,omitempty,omitzero\"`  // Excluded category filters.\n\tSyntheticDelays      []string          `json:\"syntheticDelays,omitempty,omitzero\"`     // Configuration to synthesize the delays in tracing.\n\tMemoryDumpConfig     *MemoryDumpConfig `json:\"memoryDumpConfig,omitempty,omitzero\"`    // Configuration for memory dump triggers. Used only when \"memory-infra\" category is enabled.\n}\n\n// StreamFormat data format of a trace. Can be either the legacy JSON format\n// or the protocol buffer format. Note that the JSON format will be deprecated\n// soon.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-StreamFormat\ntype StreamFormat string\n\n// String returns the StreamFormat as string value.\nfunc (t StreamFormat) String() string {\n\treturn string(t)\n}\n\n// StreamFormat values.\nconst (\n\tStreamFormatJSON  StreamFormat = \"json\"\n\tStreamFormatProto StreamFormat = \"proto\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *StreamFormat) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch StreamFormat(s) {\n\tcase StreamFormatJSON:\n\t\t*t = StreamFormatJSON\n\tcase StreamFormatProto:\n\t\t*t = StreamFormatProto\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown StreamFormat value: %v\", s)\n\t}\n\treturn nil\n}\n\n// StreamCompression compression type to use for traces returned via streams.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-StreamCompression\ntype StreamCompression string\n\n// String returns the StreamCompression as string value.\nfunc (t StreamCompression) String() string {\n\treturn string(t)\n}\n\n// StreamCompression values.\nconst (\n\tStreamCompressionNone StreamCompression = \"none\"\n\tStreamCompressionGzip StreamCompression = \"gzip\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *StreamCompression) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch StreamCompression(s) {\n\tcase StreamCompressionNone:\n\t\t*t = StreamCompressionNone\n\tcase StreamCompressionGzip:\n\t\t*t = StreamCompressionGzip\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown StreamCompression value: %v\", s)\n\t}\n\treturn nil\n}\n\n// MemoryDumpLevelOfDetail details exposed when memory request explicitly\n// declared. Keep consistent with memory_dump_request_args.h and\n// memory_instrumentation.mojom.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-MemoryDumpLevelOfDetail\ntype MemoryDumpLevelOfDetail string\n\n// String returns the MemoryDumpLevelOfDetail as string value.\nfunc (t MemoryDumpLevelOfDetail) String() string {\n\treturn string(t)\n}\n\n// MemoryDumpLevelOfDetail values.\nconst (\n\tMemoryDumpLevelOfDetailBackground MemoryDumpLevelOfDetail = \"background\"\n\tMemoryDumpLevelOfDetailLight      MemoryDumpLevelOfDetail = \"light\"\n\tMemoryDumpLevelOfDetailDetailed   MemoryDumpLevelOfDetail = \"detailed\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *MemoryDumpLevelOfDetail) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch MemoryDumpLevelOfDetail(s) {\n\tcase MemoryDumpLevelOfDetailBackground:\n\t\t*t = MemoryDumpLevelOfDetailBackground\n\tcase MemoryDumpLevelOfDetailLight:\n\t\t*t = MemoryDumpLevelOfDetailLight\n\tcase MemoryDumpLevelOfDetailDetailed:\n\t\t*t = MemoryDumpLevelOfDetailDetailed\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown MemoryDumpLevelOfDetail value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Backend backend type to use for tracing. chrome uses the Chrome-integrated\n// tracing service and is supported on all platforms. system is only supported\n// on Chrome OS and uses the Perfetto system tracing service. auto chooses\n// system when the perfettoConfig provided to Tracing.start specifies at least\n// one non-Chrome data source; otherwise uses chrome.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-TracingBackend\ntype Backend string\n\n// String returns the Backend as string value.\nfunc (t Backend) String() string {\n\treturn string(t)\n}\n\n// Backend values.\nconst (\n\tBackendAuto   Backend = \"auto\"\n\tBackendChrome Backend = \"chrome\"\n\tBackendSystem Backend = \"system\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Backend) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Backend(s) {\n\tcase BackendAuto:\n\t\t*t = BackendAuto\n\tcase BackendChrome:\n\t\t*t = BackendChrome\n\tcase BackendSystem:\n\t\t*t = BackendSystem\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Backend value: %v\", s)\n\t}\n\treturn nil\n}\n\n// RecordMode controls how the trace buffer stores data. The default is\n// recordUntilFull.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#type-TraceConfig\ntype RecordMode string\n\n// String returns the RecordMode as string value.\nfunc (t RecordMode) String() string {\n\treturn string(t)\n}\n\n// RecordMode values.\nconst (\n\tRecordModeRecordUntilFull        RecordMode = \"recordUntilFull\"\n\tRecordModeRecordContinuously     RecordMode = \"recordContinuously\"\n\tRecordModeRecordAsMuchAsPossible RecordMode = \"recordAsMuchAsPossible\"\n\tRecordModeEchoToConsole          RecordMode = \"echoToConsole\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *RecordMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch RecordMode(s) {\n\tcase RecordModeRecordUntilFull:\n\t\t*t = RecordModeRecordUntilFull\n\tcase RecordModeRecordContinuously:\n\t\t*t = RecordModeRecordContinuously\n\tcase RecordModeRecordAsMuchAsPossible:\n\t\t*t = RecordModeRecordAsMuchAsPossible\n\tcase RecordModeEchoToConsole:\n\t\t*t = RecordModeEchoToConsole\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown RecordMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// TransferMode whether to report trace events as series of dataCollected\n// events or to save trace to a stream (defaults to ReportEvents).\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/Tracing#method-start\ntype TransferMode string\n\n// String returns the TransferMode as string value.\nfunc (t TransferMode) String() string {\n\treturn string(t)\n}\n\n// TransferMode values.\nconst (\n\tTransferModeReportEvents   TransferMode = \"ReportEvents\"\n\tTransferModeReturnAsStream TransferMode = \"ReturnAsStream\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *TransferMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch TransferMode(s) {\n\tcase TransferModeReportEvents:\n\t\t*t = TransferModeReportEvents\n\tcase TransferModeReturnAsStream:\n\t\t*t = TransferModeReturnAsStream\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown TransferMode value: %v\", s)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/webaudio/events.go",
    "content": "package webaudio\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventContextCreated notifies that a new BaseAudioContext has been created.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-contextCreated\ntype EventContextCreated struct {\n\tContext *BaseAudioContext `json:\"context\"`\n}\n\n// EventContextWillBeDestroyed notifies that an existing BaseAudioContext\n// will be destroyed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-contextWillBeDestroyed\ntype EventContextWillBeDestroyed struct {\n\tContextID GraphObjectID `json:\"contextId\"`\n}\n\n// EventContextChanged notifies that existing BaseAudioContext has changed\n// some properties (id stays the same)..\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-contextChanged\ntype EventContextChanged struct {\n\tContext *BaseAudioContext `json:\"context\"`\n}\n\n// EventAudioListenerCreated notifies that the construction of an\n// AudioListener has finished.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-audioListenerCreated\ntype EventAudioListenerCreated struct {\n\tListener *AudioListener `json:\"listener\"`\n}\n\n// EventAudioListenerWillBeDestroyed notifies that a new AudioListener has\n// been created.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-audioListenerWillBeDestroyed\ntype EventAudioListenerWillBeDestroyed struct {\n\tContextID  GraphObjectID `json:\"contextId\"`\n\tListenerID GraphObjectID `json:\"listenerId\"`\n}\n\n// EventAudioNodeCreated notifies that a new AudioNode has been created.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-audioNodeCreated\ntype EventAudioNodeCreated struct {\n\tNode *AudioNode `json:\"node\"`\n}\n\n// EventAudioNodeWillBeDestroyed notifies that an existing AudioNode has been\n// destroyed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-audioNodeWillBeDestroyed\ntype EventAudioNodeWillBeDestroyed struct {\n\tContextID GraphObjectID `json:\"contextId\"`\n\tNodeID    GraphObjectID `json:\"nodeId\"`\n}\n\n// EventAudioParamCreated notifies that a new AudioParam has been created.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-audioParamCreated\ntype EventAudioParamCreated struct {\n\tParam *AudioParam `json:\"param\"`\n}\n\n// EventAudioParamWillBeDestroyed notifies that an existing AudioParam has\n// been destroyed.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-audioParamWillBeDestroyed\ntype EventAudioParamWillBeDestroyed struct {\n\tContextID GraphObjectID `json:\"contextId\"`\n\tNodeID    GraphObjectID `json:\"nodeId\"`\n\tParamID   GraphObjectID `json:\"paramId\"`\n}\n\n// EventNodesConnected notifies that two AudioNodes are connected.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-nodesConnected\ntype EventNodesConnected struct {\n\tContextID             GraphObjectID `json:\"contextId\"`\n\tSourceID              GraphObjectID `json:\"sourceId\"`\n\tDestinationID         GraphObjectID `json:\"destinationId\"`\n\tSourceOutputIndex     float64       `json:\"sourceOutputIndex,omitempty,omitzero\"`\n\tDestinationInputIndex float64       `json:\"destinationInputIndex,omitempty,omitzero\"`\n}\n\n// EventNodesDisconnected notifies that AudioNodes are disconnected. The\n// destination can be null, and it means all the outgoing connections from the\n// source are disconnected.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-nodesDisconnected\ntype EventNodesDisconnected struct {\n\tContextID             GraphObjectID `json:\"contextId\"`\n\tSourceID              GraphObjectID `json:\"sourceId\"`\n\tDestinationID         GraphObjectID `json:\"destinationId\"`\n\tSourceOutputIndex     float64       `json:\"sourceOutputIndex,omitempty,omitzero\"`\n\tDestinationInputIndex float64       `json:\"destinationInputIndex,omitempty,omitzero\"`\n}\n\n// EventNodeParamConnected notifies that an AudioNode is connected to an\n// AudioParam.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-nodeParamConnected\ntype EventNodeParamConnected struct {\n\tContextID         GraphObjectID `json:\"contextId\"`\n\tSourceID          GraphObjectID `json:\"sourceId\"`\n\tDestinationID     GraphObjectID `json:\"destinationId\"`\n\tSourceOutputIndex float64       `json:\"sourceOutputIndex,omitempty,omitzero\"`\n}\n\n// EventNodeParamDisconnected notifies that an AudioNode is disconnected to\n// an AudioParam.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#event-nodeParamDisconnected\ntype EventNodeParamDisconnected struct {\n\tContextID         GraphObjectID `json:\"contextId\"`\n\tSourceID          GraphObjectID `json:\"sourceId\"`\n\tDestinationID     GraphObjectID `json:\"destinationId\"`\n\tSourceOutputIndex float64       `json:\"sourceOutputIndex,omitempty,omitzero\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/webaudio/types.go",
    "content": "package webaudio\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// GraphObjectID an unique ID for a graph object (AudioContext, AudioNode,\n// AudioParam) in Web Audio API.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-GraphObjectId\ntype GraphObjectID string\n\n// String returns the GraphObjectID as string value.\nfunc (t GraphObjectID) String() string {\n\treturn string(t)\n}\n\n// ContextType enum of BaseAudioContext types.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-ContextType\ntype ContextType string\n\n// String returns the ContextType as string value.\nfunc (t ContextType) String() string {\n\treturn string(t)\n}\n\n// ContextType values.\nconst (\n\tContextTypeRealtime ContextType = \"realtime\"\n\tContextTypeOffline  ContextType = \"offline\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ContextType) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ContextType(s) {\n\tcase ContextTypeRealtime:\n\t\t*t = ContextTypeRealtime\n\tcase ContextTypeOffline:\n\t\t*t = ContextTypeOffline\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ContextType value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ContextState enum of AudioContextState from the spec.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-ContextState\ntype ContextState string\n\n// String returns the ContextState as string value.\nfunc (t ContextState) String() string {\n\treturn string(t)\n}\n\n// ContextState values.\nconst (\n\tContextStateSuspended   ContextState = \"suspended\"\n\tContextStateRunning     ContextState = \"running\"\n\tContextStateClosed      ContextState = \"closed\"\n\tContextStateInterrupted ContextState = \"interrupted\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ContextState) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ContextState(s) {\n\tcase ContextStateSuspended:\n\t\t*t = ContextStateSuspended\n\tcase ContextStateRunning:\n\t\t*t = ContextStateRunning\n\tcase ContextStateClosed:\n\t\t*t = ContextStateClosed\n\tcase ContextStateInterrupted:\n\t\t*t = ContextStateInterrupted\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ContextState value: %v\", s)\n\t}\n\treturn nil\n}\n\n// NodeType enum of AudioNode types.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-NodeType\ntype NodeType string\n\n// String returns the NodeType as string value.\nfunc (t NodeType) String() string {\n\treturn string(t)\n}\n\n// ChannelCountMode enum of AudioNode::ChannelCountMode from the spec.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-ChannelCountMode\ntype ChannelCountMode string\n\n// String returns the ChannelCountMode as string value.\nfunc (t ChannelCountMode) String() string {\n\treturn string(t)\n}\n\n// ChannelCountMode values.\nconst (\n\tChannelCountModeClampedMax ChannelCountMode = \"clamped-max\"\n\tChannelCountModeExplicit   ChannelCountMode = \"explicit\"\n\tChannelCountModeMax        ChannelCountMode = \"max\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ChannelCountMode) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ChannelCountMode(s) {\n\tcase ChannelCountModeClampedMax:\n\t\t*t = ChannelCountModeClampedMax\n\tcase ChannelCountModeExplicit:\n\t\t*t = ChannelCountModeExplicit\n\tcase ChannelCountModeMax:\n\t\t*t = ChannelCountModeMax\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ChannelCountMode value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ChannelInterpretation enum of AudioNode::ChannelInterpretation from the\n// spec.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-ChannelInterpretation\ntype ChannelInterpretation string\n\n// String returns the ChannelInterpretation as string value.\nfunc (t ChannelInterpretation) String() string {\n\treturn string(t)\n}\n\n// ChannelInterpretation values.\nconst (\n\tChannelInterpretationDiscrete ChannelInterpretation = \"discrete\"\n\tChannelInterpretationSpeakers ChannelInterpretation = \"speakers\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *ChannelInterpretation) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch ChannelInterpretation(s) {\n\tcase ChannelInterpretationDiscrete:\n\t\t*t = ChannelInterpretationDiscrete\n\tcase ChannelInterpretationSpeakers:\n\t\t*t = ChannelInterpretationSpeakers\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown ChannelInterpretation value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ParamType enum of AudioParam types.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-ParamType\ntype ParamType string\n\n// String returns the ParamType as string value.\nfunc (t ParamType) String() string {\n\treturn string(t)\n}\n\n// AutomationRate enum of AudioParam::AutomationRate from the spec.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-AutomationRate\ntype AutomationRate string\n\n// String returns the AutomationRate as string value.\nfunc (t AutomationRate) String() string {\n\treturn string(t)\n}\n\n// AutomationRate values.\nconst (\n\tAutomationRateARate AutomationRate = \"a-rate\"\n\tAutomationRateKRate AutomationRate = \"k-rate\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AutomationRate) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AutomationRate(s) {\n\tcase AutomationRateARate:\n\t\t*t = AutomationRateARate\n\tcase AutomationRateKRate:\n\t\t*t = AutomationRateKRate\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AutomationRate value: %v\", s)\n\t}\n\treturn nil\n}\n\n// ContextRealtimeData fields in AudioContext that change in real-time.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-ContextRealtimeData\ntype ContextRealtimeData struct {\n\tCurrentTime              float64 `json:\"currentTime\"`              // The current context time in second in BaseAudioContext.\n\tRenderCapacity           float64 `json:\"renderCapacity\"`           // The time spent on rendering graph divided by render quantum duration, and multiplied by 100. 100 means the audio renderer reached the full capacity and glitch may occur.\n\tCallbackIntervalMean     float64 `json:\"callbackIntervalMean\"`     // A running mean of callback interval.\n\tCallbackIntervalVariance float64 `json:\"callbackIntervalVariance\"` // A running variance of callback interval.\n}\n\n// BaseAudioContext protocol object for BaseAudioContext.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-BaseAudioContext\ntype BaseAudioContext struct {\n\tContextID             GraphObjectID        `json:\"contextId\"`\n\tContextType           ContextType          `json:\"contextType\"`\n\tContextState          ContextState         `json:\"contextState\"`\n\tRealtimeData          *ContextRealtimeData `json:\"realtimeData,omitempty,omitzero\"`\n\tCallbackBufferSize    float64              `json:\"callbackBufferSize\"`    // Platform-dependent callback buffer size.\n\tMaxOutputChannelCount float64              `json:\"maxOutputChannelCount\"` // Number of output channels supported by audio hardware in use.\n\tSampleRate            float64              `json:\"sampleRate\"`            // Context sample rate.\n}\n\n// AudioListener protocol object for AudioListener.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-AudioListener\ntype AudioListener struct {\n\tListenerID GraphObjectID `json:\"listenerId\"`\n\tContextID  GraphObjectID `json:\"contextId\"`\n}\n\n// AudioNode protocol object for AudioNode.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-AudioNode\ntype AudioNode struct {\n\tNodeID                GraphObjectID         `json:\"nodeId\"`\n\tContextID             GraphObjectID         `json:\"contextId\"`\n\tNodeType              cdp.NodeType          `json:\"nodeType\"`\n\tNumberOfInputs        float64               `json:\"numberOfInputs\"`\n\tNumberOfOutputs       float64               `json:\"numberOfOutputs\"`\n\tChannelCount          float64               `json:\"channelCount\"`\n\tChannelCountMode      ChannelCountMode      `json:\"channelCountMode\"`\n\tChannelInterpretation ChannelInterpretation `json:\"channelInterpretation\"`\n}\n\n// AudioParam protocol object for AudioParam.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#type-AudioParam\ntype AudioParam struct {\n\tParamID      GraphObjectID  `json:\"paramId\"`\n\tNodeID       GraphObjectID  `json:\"nodeId\"`\n\tContextID    GraphObjectID  `json:\"contextId\"`\n\tParamType    ParamType      `json:\"paramType\"`\n\tRate         AutomationRate `json:\"rate\"`\n\tDefaultValue float64        `json:\"defaultValue\"`\n\tMinValue     float64        `json:\"minValue\"`\n\tMaxValue     float64        `json:\"maxValue\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/webaudio/webaudio.go",
    "content": "// Package webaudio provides the Chrome DevTools Protocol\n// commands, types, and events for the WebAudio domain.\n//\n// This domain allows inspection of Web Audio API.\n// https://webaudio.github.io/web-audio-api/.\n//\n// Generated by the cdproto-gen command.\npackage webaudio\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams enables the WebAudio domain and starts sending context\n// lifetime events.\ntype EnableParams struct{}\n\n// Enable enables the WebAudio domain and starts sending context lifetime\n// events.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#method-enable\nfunc Enable() *EnableParams {\n\treturn &EnableParams{}\n}\n\n// Do executes WebAudio.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, nil, nil)\n}\n\n// DisableParams disables the WebAudio domain.\ntype DisableParams struct{}\n\n// Disable disables the WebAudio domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes WebAudio.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// GetRealtimeDataParams fetch the realtime data from the registered\n// contexts.\ntype GetRealtimeDataParams struct {\n\tContextID GraphObjectID `json:\"contextId\"`\n}\n\n// GetRealtimeData fetch the realtime data from the registered contexts.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAudio#method-getRealtimeData\n//\n// parameters:\n//\n//\tcontextID\nfunc GetRealtimeData(contextID GraphObjectID) *GetRealtimeDataParams {\n\treturn &GetRealtimeDataParams{\n\t\tContextID: contextID,\n\t}\n}\n\n// GetRealtimeDataReturns return values.\ntype GetRealtimeDataReturns struct {\n\tRealtimeData *ContextRealtimeData `json:\"realtimeData,omitempty,omitzero\"`\n}\n\n// Do executes WebAudio.getRealtimeData against the provided context.\n//\n// returns:\n//\n//\trealtimeData\nfunc (p *GetRealtimeDataParams) Do(ctx context.Context) (realtimeData *ContextRealtimeData, err error) {\n\t// execute\n\tvar res GetRealtimeDataReturns\n\terr = cdp.Execute(ctx, CommandGetRealtimeData, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.RealtimeData, nil\n}\n\n// Command names.\nconst (\n\tCommandEnable          = \"WebAudio.enable\"\n\tCommandDisable         = \"WebAudio.disable\"\n\tCommandGetRealtimeData = \"WebAudio.getRealtimeData\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/webauthn/events.go",
    "content": "package webauthn\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// EventCredentialAdded triggered when a credential is added to an\n// authenticator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#event-credentialAdded\ntype EventCredentialAdded struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tCredential      *Credential     `json:\"credential\"`\n}\n\n// EventCredentialDeleted triggered when a credential is deleted, e.g.\n// through PublicKeyCredential.signalUnknownCredential().\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#event-credentialDeleted\ntype EventCredentialDeleted struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tCredentialID    string          `json:\"credentialId\"`\n}\n\n// EventCredentialUpdated triggered when a credential is updated, e.g.\n// through PublicKeyCredential.signalCurrentUserDetails().\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#event-credentialUpdated\ntype EventCredentialUpdated struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tCredential      *Credential     `json:\"credential\"`\n}\n\n// EventCredentialAsserted triggered when a credential is used in a webauthn\n// assertion.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#event-credentialAsserted\ntype EventCredentialAsserted struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tCredential      *Credential     `json:\"credential\"`\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/webauthn/types.go",
    "content": "package webauthn\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\n// AuthenticatorID [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-AuthenticatorId\ntype AuthenticatorID string\n\n// String returns the AuthenticatorID as string value.\nfunc (t AuthenticatorID) String() string {\n\treturn string(t)\n}\n\n// AuthenticatorProtocol [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-AuthenticatorProtocol\ntype AuthenticatorProtocol string\n\n// String returns the AuthenticatorProtocol as string value.\nfunc (t AuthenticatorProtocol) String() string {\n\treturn string(t)\n}\n\n// AuthenticatorProtocol values.\nconst (\n\tAuthenticatorProtocolU2f   AuthenticatorProtocol = \"u2f\"\n\tAuthenticatorProtocolCtap2 AuthenticatorProtocol = \"ctap2\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AuthenticatorProtocol) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AuthenticatorProtocol(s) {\n\tcase AuthenticatorProtocolU2f:\n\t\t*t = AuthenticatorProtocolU2f\n\tcase AuthenticatorProtocolCtap2:\n\t\t*t = AuthenticatorProtocolCtap2\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AuthenticatorProtocol value: %v\", s)\n\t}\n\treturn nil\n}\n\n// Ctap2version [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-Ctap2Version\ntype Ctap2version string\n\n// String returns the Ctap2version as string value.\nfunc (t Ctap2version) String() string {\n\treturn string(t)\n}\n\n// Ctap2version values.\nconst (\n\tCtap2versionCtap20 Ctap2version = \"ctap2_0\"\n\tCtap2versionCtap21 Ctap2version = \"ctap2_1\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *Ctap2version) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch Ctap2version(s) {\n\tcase Ctap2versionCtap20:\n\t\t*t = Ctap2versionCtap20\n\tcase Ctap2versionCtap21:\n\t\t*t = Ctap2versionCtap21\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown Ctap2version value: %v\", s)\n\t}\n\treturn nil\n}\n\n// AuthenticatorTransport [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-AuthenticatorTransport\ntype AuthenticatorTransport string\n\n// String returns the AuthenticatorTransport as string value.\nfunc (t AuthenticatorTransport) String() string {\n\treturn string(t)\n}\n\n// AuthenticatorTransport values.\nconst (\n\tAuthenticatorTransportUsb      AuthenticatorTransport = \"usb\"\n\tAuthenticatorTransportNfc      AuthenticatorTransport = \"nfc\"\n\tAuthenticatorTransportBle      AuthenticatorTransport = \"ble\"\n\tAuthenticatorTransportCable    AuthenticatorTransport = \"cable\"\n\tAuthenticatorTransportInternal AuthenticatorTransport = \"internal\"\n)\n\n// UnmarshalJSON satisfies [json.Unmarshaler].\nfunc (t *AuthenticatorTransport) UnmarshalJSON(buf []byte) error {\n\ts := string(buf)\n\ts = strings.TrimSuffix(strings.TrimPrefix(s, `\"`), `\"`)\n\n\tswitch AuthenticatorTransport(s) {\n\tcase AuthenticatorTransportUsb:\n\t\t*t = AuthenticatorTransportUsb\n\tcase AuthenticatorTransportNfc:\n\t\t*t = AuthenticatorTransportNfc\n\tcase AuthenticatorTransportBle:\n\t\t*t = AuthenticatorTransportBle\n\tcase AuthenticatorTransportCable:\n\t\t*t = AuthenticatorTransportCable\n\tcase AuthenticatorTransportInternal:\n\t\t*t = AuthenticatorTransportInternal\n\tdefault:\n\t\treturn fmt.Errorf(\"unknown AuthenticatorTransport value: %v\", s)\n\t}\n\treturn nil\n}\n\n// VirtualAuthenticatorOptions [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-VirtualAuthenticatorOptions\ntype VirtualAuthenticatorOptions struct {\n\tProtocol                    AuthenticatorProtocol  `json:\"protocol\"`\n\tCtap2version                Ctap2version           `json:\"ctap2Version,omitempty,omitzero\"` // Defaults to ctap2_0. Ignored if |protocol| == u2f.\n\tTransport                   AuthenticatorTransport `json:\"transport\"`\n\tHasResidentKey              bool                   `json:\"hasResidentKey\"`              // Defaults to false.\n\tHasUserVerification         bool                   `json:\"hasUserVerification\"`         // Defaults to false.\n\tHasLargeBlob                bool                   `json:\"hasLargeBlob\"`                // If set to true, the authenticator will support the largeBlob extension. https://w3c.github.io/webauthn#largeBlob Defaults to false.\n\tHasCredBlob                 bool                   `json:\"hasCredBlob\"`                 // If set to true, the authenticator will support the credBlob extension. https://fidoalliance.org/specs/fido-v2.1-rd-20201208/fido-client-to-authenticator-protocol-v2.1-rd-20201208.html#sctn-credBlob-extension Defaults to false.\n\tHasMinPinLength             bool                   `json:\"hasMinPinLength\"`             // If set to true, the authenticator will support the minPinLength extension. https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-minpinlength-extension Defaults to false.\n\tHasPrf                      bool                   `json:\"hasPrf\"`                      // If set to true, the authenticator will support the prf extension. https://w3c.github.io/webauthn/#prf-extension Defaults to false.\n\tAutomaticPresenceSimulation bool                   `json:\"automaticPresenceSimulation\"` // If set to true, tests of user presence will succeed immediately. Otherwise, they will not be resolved. Defaults to true.\n\tIsUserVerified              bool                   `json:\"isUserVerified\"`              // Sets whether User Verification succeeds or fails for an authenticator. Defaults to false.\n\tDefaultBackupEligibility    bool                   `json:\"defaultBackupEligibility\"`    // Credentials created by this authenticator will have the backup eligibility (BE) flag set to this value. Defaults to false. https://w3c.github.io/webauthn/#sctn-credential-backup\n\tDefaultBackupState          bool                   `json:\"defaultBackupState\"`          // Credentials created by this authenticator will have the backup state (BS) flag set to this value. Defaults to false. https://w3c.github.io/webauthn/#sctn-credential-backup\n}\n\n// Credential [no description].\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#type-Credential\ntype Credential struct {\n\tCredentialID         string `json:\"credentialId\"`\n\tIsResidentCredential bool   `json:\"isResidentCredential\"`\n\tRpID                 string `json:\"rpId,omitempty,omitzero\"`            // Relying Party ID the credential is scoped to. Must be set when adding a credential.\n\tPrivateKey           string `json:\"privateKey\"`                         // The ECDSA P-256 private key in PKCS#8 format.\n\tUserHandle           string `json:\"userHandle,omitempty,omitzero\"`      // An opaque byte sequence with a maximum size of 64 bytes mapping the credential to a specific user.\n\tSignCount            int64  `json:\"signCount\"`                          // Signature counter. This is incremented by one for each successful assertion. See https://w3c.github.io/webauthn/#signature-counter\n\tLargeBlob            string `json:\"largeBlob,omitempty,omitzero\"`       // The large blob associated with the credential. See https://w3c.github.io/webauthn/#sctn-large-blob-extension\n\tBackupEligibility    bool   `json:\"backupEligibility\"`                  // Assertions returned by this credential will have the backup eligibility (BE) flag set to this value. Defaults to the authenticator's defaultBackupEligibility value.\n\tBackupState          bool   `json:\"backupState\"`                        // Assertions returned by this credential will have the backup state (BS) flag set to this value. Defaults to the authenticator's defaultBackupState value.\n\tUserName             string `json:\"userName,omitempty,omitzero\"`        // The credential's user.name property. Equivalent to empty if not set. https://w3c.github.io/webauthn/#dom-publickeycredentialentity-name\n\tUserDisplayName      string `json:\"userDisplayName,omitempty,omitzero\"` // The credential's user.displayName property. Equivalent to empty if not set. https://w3c.github.io/webauthn/#dom-publickeycredentialuserentity-displayname\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/cdproto/webauthn/webauthn.go",
    "content": "// Package webauthn provides the Chrome DevTools Protocol\n// commands, types, and events for the WebAuthn domain.\n//\n// This domain allows configuring virtual authenticators to test the WebAuthn\n// API.\n//\n// Generated by the cdproto-gen command.\npackage webauthn\n\n// Code generated by cdproto-gen. DO NOT EDIT.\n\nimport (\n\t\"context\"\n\n\t\"github.com/chromedp/cdproto/cdp\"\n)\n\n// EnableParams enable the WebAuthn domain and start intercepting credential\n// storage and retrieval with a virtual authenticator.\ntype EnableParams struct {\n\tEnableUI bool `json:\"enableUI\"` // Whether to enable the WebAuthn user interface. Enabling the UI is recommended for debugging and demo purposes, as it is closer to the real experience. Disabling the UI is recommended for automated testing. Supported at the embedder's discretion if UI is available. Defaults to false.\n}\n\n// Enable enable the WebAuthn domain and start intercepting credential\n// storage and retrieval with a virtual authenticator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-enable\n//\n// parameters:\nfunc Enable() *EnableParams {\n\treturn &EnableParams{\n\t\tEnableUI: false,\n\t}\n}\n\n// WithEnableUI whether to enable the WebAuthn user interface. Enabling the\n// UI is recommended for debugging and demo purposes, as it is closer to the\n// real experience. Disabling the UI is recommended for automated testing.\n// Supported at the embedder's discretion if UI is available. Defaults to false.\nfunc (p EnableParams) WithEnableUI(enableUI bool) *EnableParams {\n\tp.EnableUI = enableUI\n\treturn &p\n}\n\n// Do executes WebAuthn.enable against the provided context.\nfunc (p *EnableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandEnable, p, nil)\n}\n\n// DisableParams disable the WebAuthn domain.\ntype DisableParams struct{}\n\n// Disable disable the WebAuthn domain.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-disable\nfunc Disable() *DisableParams {\n\treturn &DisableParams{}\n}\n\n// Do executes WebAuthn.disable against the provided context.\nfunc (p *DisableParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandDisable, nil, nil)\n}\n\n// AddVirtualAuthenticatorParams creates and adds a virtual authenticator.\ntype AddVirtualAuthenticatorParams struct {\n\tOptions *VirtualAuthenticatorOptions `json:\"options\"`\n}\n\n// AddVirtualAuthenticator creates and adds a virtual authenticator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-addVirtualAuthenticator\n//\n// parameters:\n//\n//\toptions\nfunc AddVirtualAuthenticator(options *VirtualAuthenticatorOptions) *AddVirtualAuthenticatorParams {\n\treturn &AddVirtualAuthenticatorParams{\n\t\tOptions: options,\n\t}\n}\n\n// AddVirtualAuthenticatorReturns return values.\ntype AddVirtualAuthenticatorReturns struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId,omitempty,omitzero\"`\n}\n\n// Do executes WebAuthn.addVirtualAuthenticator against the provided context.\n//\n// returns:\n//\n//\tauthenticatorID\nfunc (p *AddVirtualAuthenticatorParams) Do(ctx context.Context) (authenticatorID AuthenticatorID, err error) {\n\t// execute\n\tvar res AddVirtualAuthenticatorReturns\n\terr = cdp.Execute(ctx, CommandAddVirtualAuthenticator, p, &res)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn res.AuthenticatorID, nil\n}\n\n// SetResponseOverrideBitsParams resets parameters isBogusSignature, isBadUV,\n// isBadUP to false if they are not present.\ntype SetResponseOverrideBitsParams struct {\n\tAuthenticatorID  AuthenticatorID `json:\"authenticatorId\"`\n\tIsBogusSignature bool            `json:\"isBogusSignature\"` // If isBogusSignature is set, overrides the signature in the authenticator response to be zero. Defaults to false.\n\tIsBadUV          bool            `json:\"isBadUV\"`          // If isBadUV is set, overrides the UV bit in the flags in the authenticator response to be zero. Defaults to false.\n\tIsBadUP          bool            `json:\"isBadUP\"`          // If isBadUP is set, overrides the UP bit in the flags in the authenticator response to be zero. Defaults to false.\n}\n\n// SetResponseOverrideBits resets parameters isBogusSignature, isBadUV,\n// isBadUP to false if they are not present.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-setResponseOverrideBits\n//\n// parameters:\n//\n//\tauthenticatorID\nfunc SetResponseOverrideBits(authenticatorID AuthenticatorID) *SetResponseOverrideBitsParams {\n\treturn &SetResponseOverrideBitsParams{\n\t\tAuthenticatorID:  authenticatorID,\n\t\tIsBogusSignature: false,\n\t\tIsBadUV:          false,\n\t\tIsBadUP:          false,\n\t}\n}\n\n// WithIsBogusSignature if isBogusSignature is set, overrides the signature\n// in the authenticator response to be zero. Defaults to false.\nfunc (p SetResponseOverrideBitsParams) WithIsBogusSignature(isBogusSignature bool) *SetResponseOverrideBitsParams {\n\tp.IsBogusSignature = isBogusSignature\n\treturn &p\n}\n\n// WithIsBadUV if isBadUV is set, overrides the UV bit in the flags in the\n// authenticator response to be zero. Defaults to false.\nfunc (p SetResponseOverrideBitsParams) WithIsBadUV(isBadUV bool) *SetResponseOverrideBitsParams {\n\tp.IsBadUV = isBadUV\n\treturn &p\n}\n\n// WithIsBadUP if isBadUP is set, overrides the UP bit in the flags in the\n// authenticator response to be zero. Defaults to false.\nfunc (p SetResponseOverrideBitsParams) WithIsBadUP(isBadUP bool) *SetResponseOverrideBitsParams {\n\tp.IsBadUP = isBadUP\n\treturn &p\n}\n\n// Do executes WebAuthn.setResponseOverrideBits against the provided context.\nfunc (p *SetResponseOverrideBitsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetResponseOverrideBits, p, nil)\n}\n\n// RemoveVirtualAuthenticatorParams removes the given authenticator.\ntype RemoveVirtualAuthenticatorParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n}\n\n// RemoveVirtualAuthenticator removes the given authenticator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-removeVirtualAuthenticator\n//\n// parameters:\n//\n//\tauthenticatorID\nfunc RemoveVirtualAuthenticator(authenticatorID AuthenticatorID) *RemoveVirtualAuthenticatorParams {\n\treturn &RemoveVirtualAuthenticatorParams{\n\t\tAuthenticatorID: authenticatorID,\n\t}\n}\n\n// Do executes WebAuthn.removeVirtualAuthenticator against the provided context.\nfunc (p *RemoveVirtualAuthenticatorParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveVirtualAuthenticator, p, nil)\n}\n\n// AddCredentialParams adds the credential to the specified authenticator.\ntype AddCredentialParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tCredential      *Credential     `json:\"credential\"`\n}\n\n// AddCredential adds the credential to the specified authenticator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-addCredential\n//\n// parameters:\n//\n//\tauthenticatorID\n//\tcredential\nfunc AddCredential(authenticatorID AuthenticatorID, credential *Credential) *AddCredentialParams {\n\treturn &AddCredentialParams{\n\t\tAuthenticatorID: authenticatorID,\n\t\tCredential:      credential,\n\t}\n}\n\n// Do executes WebAuthn.addCredential against the provided context.\nfunc (p *AddCredentialParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandAddCredential, p, nil)\n}\n\n// GetCredentialParams returns a single credential stored in the given\n// virtual authenticator that matches the credential ID.\ntype GetCredentialParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tCredentialID    string          `json:\"credentialId\"`\n}\n\n// GetCredential returns a single credential stored in the given virtual\n// authenticator that matches the credential ID.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-getCredential\n//\n// parameters:\n//\n//\tauthenticatorID\n//\tcredentialID\nfunc GetCredential(authenticatorID AuthenticatorID, credentialID string) *GetCredentialParams {\n\treturn &GetCredentialParams{\n\t\tAuthenticatorID: authenticatorID,\n\t\tCredentialID:    credentialID,\n\t}\n}\n\n// GetCredentialReturns return values.\ntype GetCredentialReturns struct {\n\tCredential *Credential `json:\"credential,omitempty,omitzero\"`\n}\n\n// Do executes WebAuthn.getCredential against the provided context.\n//\n// returns:\n//\n//\tcredential\nfunc (p *GetCredentialParams) Do(ctx context.Context) (credential *Credential, err error) {\n\t// execute\n\tvar res GetCredentialReturns\n\terr = cdp.Execute(ctx, CommandGetCredential, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Credential, nil\n}\n\n// GetCredentialsParams returns all the credentials stored in the given\n// virtual authenticator.\ntype GetCredentialsParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n}\n\n// GetCredentials returns all the credentials stored in the given virtual\n// authenticator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-getCredentials\n//\n// parameters:\n//\n//\tauthenticatorID\nfunc GetCredentials(authenticatorID AuthenticatorID) *GetCredentialsParams {\n\treturn &GetCredentialsParams{\n\t\tAuthenticatorID: authenticatorID,\n\t}\n}\n\n// GetCredentialsReturns return values.\ntype GetCredentialsReturns struct {\n\tCredentials []*Credential `json:\"credentials,omitempty,omitzero\"`\n}\n\n// Do executes WebAuthn.getCredentials against the provided context.\n//\n// returns:\n//\n//\tcredentials\nfunc (p *GetCredentialsParams) Do(ctx context.Context) (credentials []*Credential, err error) {\n\t// execute\n\tvar res GetCredentialsReturns\n\terr = cdp.Execute(ctx, CommandGetCredentials, p, &res)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn res.Credentials, nil\n}\n\n// RemoveCredentialParams removes a credential from the authenticator.\ntype RemoveCredentialParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tCredentialID    string          `json:\"credentialId\"`\n}\n\n// RemoveCredential removes a credential from the authenticator.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-removeCredential\n//\n// parameters:\n//\n//\tauthenticatorID\n//\tcredentialID\nfunc RemoveCredential(authenticatorID AuthenticatorID, credentialID string) *RemoveCredentialParams {\n\treturn &RemoveCredentialParams{\n\t\tAuthenticatorID: authenticatorID,\n\t\tCredentialID:    credentialID,\n\t}\n}\n\n// Do executes WebAuthn.removeCredential against the provided context.\nfunc (p *RemoveCredentialParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandRemoveCredential, p, nil)\n}\n\n// ClearCredentialsParams clears all the credentials from the specified\n// device.\ntype ClearCredentialsParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n}\n\n// ClearCredentials clears all the credentials from the specified device.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-clearCredentials\n//\n// parameters:\n//\n//\tauthenticatorID\nfunc ClearCredentials(authenticatorID AuthenticatorID) *ClearCredentialsParams {\n\treturn &ClearCredentialsParams{\n\t\tAuthenticatorID: authenticatorID,\n\t}\n}\n\n// Do executes WebAuthn.clearCredentials against the provided context.\nfunc (p *ClearCredentialsParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandClearCredentials, p, nil)\n}\n\n// SetUserVerifiedParams sets whether User Verification succeeds or fails for\n// an authenticator. The default is true.\ntype SetUserVerifiedParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tIsUserVerified  bool            `json:\"isUserVerified\"`\n}\n\n// SetUserVerified sets whether User Verification succeeds or fails for an\n// authenticator. The default is true.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-setUserVerified\n//\n// parameters:\n//\n//\tauthenticatorID\n//\tisUserVerified\nfunc SetUserVerified(authenticatorID AuthenticatorID, isUserVerified bool) *SetUserVerifiedParams {\n\treturn &SetUserVerifiedParams{\n\t\tAuthenticatorID: authenticatorID,\n\t\tIsUserVerified:  isUserVerified,\n\t}\n}\n\n// Do executes WebAuthn.setUserVerified against the provided context.\nfunc (p *SetUserVerifiedParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetUserVerified, p, nil)\n}\n\n// SetAutomaticPresenceSimulationParams sets whether tests of user presence\n// will succeed immediately (if true) or fail to resolve (if false) for an\n// authenticator. The default is true.\ntype SetAutomaticPresenceSimulationParams struct {\n\tAuthenticatorID AuthenticatorID `json:\"authenticatorId\"`\n\tEnabled         bool            `json:\"enabled\"`\n}\n\n// SetAutomaticPresenceSimulation sets whether tests of user presence will\n// succeed immediately (if true) or fail to resolve (if false) for an\n// authenticator. The default is true.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-setAutomaticPresenceSimulation\n//\n// parameters:\n//\n//\tauthenticatorID\n//\tenabled\nfunc SetAutomaticPresenceSimulation(authenticatorID AuthenticatorID, enabled bool) *SetAutomaticPresenceSimulationParams {\n\treturn &SetAutomaticPresenceSimulationParams{\n\t\tAuthenticatorID: authenticatorID,\n\t\tEnabled:         enabled,\n\t}\n}\n\n// Do executes WebAuthn.setAutomaticPresenceSimulation against the provided context.\nfunc (p *SetAutomaticPresenceSimulationParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetAutomaticPresenceSimulation, p, nil)\n}\n\n// SetCredentialPropertiesParams allows setting credential properties.\n// https://w3c.github.io/webauthn/#sctn-automation-set-credential-properties.\ntype SetCredentialPropertiesParams struct {\n\tAuthenticatorID   AuthenticatorID `json:\"authenticatorId\"`\n\tCredentialID      string          `json:\"credentialId\"`\n\tBackupEligibility bool            `json:\"backupEligibility\"`\n\tBackupState       bool            `json:\"backupState\"`\n}\n\n// SetCredentialProperties allows setting credential properties.\n// https://w3c.github.io/webauthn/#sctn-automation-set-credential-properties.\n//\n// See: https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn#method-setCredentialProperties\n//\n// parameters:\n//\n//\tauthenticatorID\n//\tcredentialID\nfunc SetCredentialProperties(authenticatorID AuthenticatorID, credentialID string) *SetCredentialPropertiesParams {\n\treturn &SetCredentialPropertiesParams{\n\t\tAuthenticatorID:   authenticatorID,\n\t\tCredentialID:      credentialID,\n\t\tBackupEligibility: false,\n\t\tBackupState:       false,\n\t}\n}\n\n// WithBackupEligibility [no description].\nfunc (p SetCredentialPropertiesParams) WithBackupEligibility(backupEligibility bool) *SetCredentialPropertiesParams {\n\tp.BackupEligibility = backupEligibility\n\treturn &p\n}\n\n// WithBackupState [no description].\nfunc (p SetCredentialPropertiesParams) WithBackupState(backupState bool) *SetCredentialPropertiesParams {\n\tp.BackupState = backupState\n\treturn &p\n}\n\n// Do executes WebAuthn.setCredentialProperties against the provided context.\nfunc (p *SetCredentialPropertiesParams) Do(ctx context.Context) (err error) {\n\treturn cdp.Execute(ctx, CommandSetCredentialProperties, p, nil)\n}\n\n// Command names.\nconst (\n\tCommandEnable                         = \"WebAuthn.enable\"\n\tCommandDisable                        = \"WebAuthn.disable\"\n\tCommandAddVirtualAuthenticator        = \"WebAuthn.addVirtualAuthenticator\"\n\tCommandSetResponseOverrideBits        = \"WebAuthn.setResponseOverrideBits\"\n\tCommandRemoveVirtualAuthenticator     = \"WebAuthn.removeVirtualAuthenticator\"\n\tCommandAddCredential                  = \"WebAuthn.addCredential\"\n\tCommandGetCredential                  = \"WebAuthn.getCredential\"\n\tCommandGetCredentials                 = \"WebAuthn.getCredentials\"\n\tCommandRemoveCredential               = \"WebAuthn.removeCredential\"\n\tCommandClearCredentials               = \"WebAuthn.clearCredentials\"\n\tCommandSetUserVerified                = \"WebAuthn.setUserVerified\"\n\tCommandSetAutomaticPresenceSimulation = \"WebAuthn.setAutomaticPresenceSimulation\"\n\tCommandSetCredentialProperties        = \"WebAuthn.setCredentialProperties\"\n)\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016-2017 Kenneth Shaw\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/sysutil.go",
    "content": "package sysutil\n\nimport (\n\t\"time\"\n)\n\nvar btime time.Time\n\n// BootTime returns the time the system was started.\nfunc BootTime() time.Time {\n\treturn btime\n}\n\n// Uptime returns the duration the system has been up.\nfunc Uptime() time.Duration {\n\treturn time.Since(btime)\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/sysutil_bsd.go",
    "content": "//go:build darwin || freebsd || openbsd || netbsd\n\npackage sysutil\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"syscall\"\n\t\"time\"\n)\n\nfunc init() {\n\t// get boot time\n\tres, err := syscall.Sysctl(\"kern.boottime\")\n\tif err != nil {\n\t\tbtime = time.Now()\n\t\treturn\n\t}\n\t// decode\n\tvar t timeval\n\tif err = binary.Read(bytes.NewBuffer([]byte(res)), binary.LittleEndian, &t); err != nil {\n\t\tbtime = time.Now()\n\t\treturn\n\t}\n\tbtime = time.Unix(int64(t.Sec), int64(t.Usec))\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/sysutil_linux.go",
    "content": "//go:build linux\n\npackage sysutil\n\nimport (\n\t\"bytes\"\n\t\"os\"\n\t\"strconv\"\n\t\"time\"\n)\n\nvar (\n\tbtimePrefix = []byte(\"btime \")\n\tlineEnd     = []byte(\"\\n\")\n)\n\nfunc init() {\n\tbuf, err := os.ReadFile(\"/proc/stat\")\n\tif err != nil {\n\t\tbtime = time.Now()\n\t\treturn\n\t}\n\tfor _, line := range bytes.SplitN(buf, lineEnd, -1) {\n\t\tif bytes.HasPrefix(line, btimePrefix) {\n\t\t\tt, err := strconv.ParseInt(string(line[len(btimePrefix):]), 10, 64)\n\t\t\tif err != nil {\n\t\t\t\tbtime = time.Now()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tbtime = time.Unix(t, 0)\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/sysutil_other.go",
    "content": "//go:build !linux && !windows && !darwin && !freebsd && !openbsd && !netbsd\n\npackage sysutil\n\nimport \"time\"\n\nfunc init() {\n\tbtime = time.Now()\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/sysutil_windows.go",
    "content": "//go:build windows\n\npackage sysutil\n\nimport (\n\t\"syscall\"\n\t\"time\"\n)\n\nvar (\n\tkernel32DLL        = syscall.MustLoadDLL(\"kernel32\")\n\tprocGetTickCount64 = kernel32DLL.MustFindProc(\"GetTickCount64\")\n)\n\nfunc init() {\n\tres, _, err := syscall.Syscall(procGetTickCount64.Addr(), 0, 0, 0, 0)\n\tif err != 0 {\n\t\tbtime = time.Now()\n\t\treturn\n\t}\n\tbtime = time.Now().Add(time.Duration(-res) * time.Millisecond)\n}\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/timeval.go",
    "content": "//go:build openbsd || netbsd\n\npackage sysutil\n\nimport (\n\t\"syscall\"\n)\n\ntype timeval syscall.Timeval\n"
  },
  {
    "path": "vendor/github.com/chromedp/sysutil/timeval32.go",
    "content": "//go:build darwin || freebsd\n\npackage sysutil\n\ntype timeval struct {\n\tSec  int32\n\tUsec int32\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/LICENSE",
    "content": "ISC License\n\nCopyright (c) 2012-2016 Dave Collins <dave@davec.name>\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/bypass.go",
    "content": "// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this software for any\n// purpose with or without fee is hereby granted, provided that the above\n// copyright notice and this permission notice appear in all copies.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n// NOTE: Due to the following build constraints, this file will only be compiled\n// when the code is not running on Google App Engine, compiled by GopherJS, and\n// \"-tags safe\" is not added to the go build command line.  The \"disableunsafe\"\n// tag is deprecated and thus should not be used.\n// Go versions prior to 1.4 are disabled because they use a different layout\n// for interfaces which make the implementation of unsafeReflectValue more complex.\n// +build !js,!appengine,!safe,!disableunsafe,go1.4\n\npackage spew\n\nimport (\n\t\"reflect\"\n\t\"unsafe\"\n)\n\nconst (\n\t// UnsafeDisabled is a build-time constant which specifies whether or\n\t// not access to the unsafe package is available.\n\tUnsafeDisabled = false\n\n\t// ptrSize is the size of a pointer on the current arch.\n\tptrSize = unsafe.Sizeof((*byte)(nil))\n)\n\ntype flag uintptr\n\nvar (\n\t// flagRO indicates whether the value field of a reflect.Value\n\t// is read-only.\n\tflagRO flag\n\n\t// flagAddr indicates whether the address of the reflect.Value's\n\t// value may be taken.\n\tflagAddr flag\n)\n\n// flagKindMask holds the bits that make up the kind\n// part of the flags field. In all the supported versions,\n// it is in the lower 5 bits.\nconst flagKindMask = flag(0x1f)\n\n// Different versions of Go have used different\n// bit layouts for the flags type. This table\n// records the known combinations.\nvar okFlags = []struct {\n\tro, addr flag\n}{{\n\t// From Go 1.4 to 1.5\n\tro:   1 << 5,\n\taddr: 1 << 7,\n}, {\n\t// Up to Go tip.\n\tro:   1<<5 | 1<<6,\n\taddr: 1 << 8,\n}}\n\nvar flagValOffset = func() uintptr {\n\tfield, ok := reflect.TypeOf(reflect.Value{}).FieldByName(\"flag\")\n\tif !ok {\n\t\tpanic(\"reflect.Value has no flag field\")\n\t}\n\treturn field.Offset\n}()\n\n// flagField returns a pointer to the flag field of a reflect.Value.\nfunc flagField(v *reflect.Value) *flag {\n\treturn (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))\n}\n\n// unsafeReflectValue converts the passed reflect.Value into a one that bypasses\n// the typical safety restrictions preventing access to unaddressable and\n// unexported data.  It works by digging the raw pointer to the underlying\n// value out of the protected value and generating a new unprotected (unsafe)\n// reflect.Value to it.\n//\n// This allows us to check for implementations of the Stringer and error\n// interfaces to be used for pretty printing ordinarily unaddressable and\n// inaccessible values such as unexported struct fields.\nfunc unsafeReflectValue(v reflect.Value) reflect.Value {\n\tif !v.IsValid() || (v.CanInterface() && v.CanAddr()) {\n\t\treturn v\n\t}\n\tflagFieldPtr := flagField(&v)\n\t*flagFieldPtr &^= flagRO\n\t*flagFieldPtr |= flagAddr\n\treturn v\n}\n\n// Sanity checks against future reflect package changes\n// to the type or semantics of the Value.flag field.\nfunc init() {\n\tfield, ok := reflect.TypeOf(reflect.Value{}).FieldByName(\"flag\")\n\tif !ok {\n\t\tpanic(\"reflect.Value has no flag field\")\n\t}\n\tif field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {\n\t\tpanic(\"reflect.Value flag field has changed kind\")\n\t}\n\ttype t0 int\n\tvar t struct {\n\t\tA t0\n\t\t// t0 will have flagEmbedRO set.\n\t\tt0\n\t\t// a will have flagStickyRO set\n\t\ta t0\n\t}\n\tvA := reflect.ValueOf(t).FieldByName(\"A\")\n\tva := reflect.ValueOf(t).FieldByName(\"a\")\n\tvt0 := reflect.ValueOf(t).FieldByName(\"t0\")\n\n\t// Infer flagRO from the difference between the flags\n\t// for the (otherwise identical) fields in t.\n\tflagPublic := *flagField(&vA)\n\tflagWithRO := *flagField(&va) | *flagField(&vt0)\n\tflagRO = flagPublic ^ flagWithRO\n\n\t// Infer flagAddr from the difference between a value\n\t// taken from a pointer and not.\n\tvPtrA := reflect.ValueOf(&t).Elem().FieldByName(\"A\")\n\tflagNoPtr := *flagField(&vA)\n\tflagPtr := *flagField(&vPtrA)\n\tflagAddr = flagNoPtr ^ flagPtr\n\n\t// Check that the inferred flags tally with one of the known versions.\n\tfor _, f := range okFlags {\n\t\tif flagRO == f.ro && flagAddr == f.addr {\n\t\t\treturn\n\t\t}\n\t}\n\tpanic(\"reflect.Value read-only flag has changed semantics\")\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/bypasssafe.go",
    "content": "// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this software for any\n// purpose with or without fee is hereby granted, provided that the above\n// copyright notice and this permission notice appear in all copies.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n// NOTE: Due to the following build constraints, this file will only be compiled\n// when the code is running on Google App Engine, compiled by GopherJS, or\n// \"-tags safe\" is added to the go build command line.  The \"disableunsafe\"\n// tag is deprecated and thus should not be used.\n// +build js appengine safe disableunsafe !go1.4\n\npackage spew\n\nimport \"reflect\"\n\nconst (\n\t// UnsafeDisabled is a build-time constant which specifies whether or\n\t// not access to the unsafe package is available.\n\tUnsafeDisabled = true\n)\n\n// unsafeReflectValue typically converts the passed reflect.Value into a one\n// that bypasses the typical safety restrictions preventing access to\n// unaddressable and unexported data.  However, doing this relies on access to\n// the unsafe package.  This is a stub version which simply returns the passed\n// reflect.Value when the unsafe package is not available.\nfunc unsafeReflectValue(v reflect.Value) reflect.Value {\n\treturn v\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/common.go",
    "content": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strconv\"\n)\n\n// Some constants in the form of bytes to avoid string overhead.  This mirrors\n// the technique used in the fmt package.\nvar (\n\tpanicBytes            = []byte(\"(PANIC=\")\n\tplusBytes             = []byte(\"+\")\n\tiBytes                = []byte(\"i\")\n\ttrueBytes             = []byte(\"true\")\n\tfalseBytes            = []byte(\"false\")\n\tinterfaceBytes        = []byte(\"(interface {})\")\n\tcommaNewlineBytes     = []byte(\",\\n\")\n\tnewlineBytes          = []byte(\"\\n\")\n\topenBraceBytes        = []byte(\"{\")\n\topenBraceNewlineBytes = []byte(\"{\\n\")\n\tcloseBraceBytes       = []byte(\"}\")\n\tasteriskBytes         = []byte(\"*\")\n\tcolonBytes            = []byte(\":\")\n\tcolonSpaceBytes       = []byte(\": \")\n\topenParenBytes        = []byte(\"(\")\n\tcloseParenBytes       = []byte(\")\")\n\tspaceBytes            = []byte(\" \")\n\tpointerChainBytes     = []byte(\"->\")\n\tnilAngleBytes         = []byte(\"<nil>\")\n\tmaxNewlineBytes       = []byte(\"<max depth reached>\\n\")\n\tmaxShortBytes         = []byte(\"<max>\")\n\tcircularBytes         = []byte(\"<already shown>\")\n\tcircularShortBytes    = []byte(\"<shown>\")\n\tinvalidAngleBytes     = []byte(\"<invalid>\")\n\topenBracketBytes      = []byte(\"[\")\n\tcloseBracketBytes     = []byte(\"]\")\n\tpercentBytes          = []byte(\"%\")\n\tprecisionBytes        = []byte(\".\")\n\topenAngleBytes        = []byte(\"<\")\n\tcloseAngleBytes       = []byte(\">\")\n\topenMapBytes          = []byte(\"map[\")\n\tcloseMapBytes         = []byte(\"]\")\n\tlenEqualsBytes        = []byte(\"len=\")\n\tcapEqualsBytes        = []byte(\"cap=\")\n)\n\n// hexDigits is used to map a decimal value to a hex digit.\nvar hexDigits = \"0123456789abcdef\"\n\n// catchPanic handles any panics that might occur during the handleMethods\n// calls.\nfunc catchPanic(w io.Writer, v reflect.Value) {\n\tif err := recover(); err != nil {\n\t\tw.Write(panicBytes)\n\t\tfmt.Fprintf(w, \"%v\", err)\n\t\tw.Write(closeParenBytes)\n\t}\n}\n\n// handleMethods attempts to call the Error and String methods on the underlying\n// type the passed reflect.Value represents and outputes the result to Writer w.\n//\n// It handles panics in any called methods by catching and displaying the error\n// as the formatted value.\nfunc handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {\n\t// We need an interface to check if the type implements the error or\n\t// Stringer interface.  However, the reflect package won't give us an\n\t// interface on certain things like unexported struct fields in order\n\t// to enforce visibility rules.  We use unsafe, when it's available,\n\t// to bypass these restrictions since this package does not mutate the\n\t// values.\n\tif !v.CanInterface() {\n\t\tif UnsafeDisabled {\n\t\t\treturn false\n\t\t}\n\n\t\tv = unsafeReflectValue(v)\n\t}\n\n\t// Choose whether or not to do error and Stringer interface lookups against\n\t// the base type or a pointer to the base type depending on settings.\n\t// Technically calling one of these methods with a pointer receiver can\n\t// mutate the value, however, types which choose to satisify an error or\n\t// Stringer interface with a pointer receiver should not be mutating their\n\t// state inside these interface methods.\n\tif !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {\n\t\tv = unsafeReflectValue(v)\n\t}\n\tif v.CanAddr() {\n\t\tv = v.Addr()\n\t}\n\n\t// Is it an error or Stringer?\n\tswitch iface := v.Interface().(type) {\n\tcase error:\n\t\tdefer catchPanic(w, v)\n\t\tif cs.ContinueOnMethod {\n\t\t\tw.Write(openParenBytes)\n\t\t\tw.Write([]byte(iface.Error()))\n\t\t\tw.Write(closeParenBytes)\n\t\t\tw.Write(spaceBytes)\n\t\t\treturn false\n\t\t}\n\n\t\tw.Write([]byte(iface.Error()))\n\t\treturn true\n\n\tcase fmt.Stringer:\n\t\tdefer catchPanic(w, v)\n\t\tif cs.ContinueOnMethod {\n\t\t\tw.Write(openParenBytes)\n\t\t\tw.Write([]byte(iface.String()))\n\t\t\tw.Write(closeParenBytes)\n\t\t\tw.Write(spaceBytes)\n\t\t\treturn false\n\t\t}\n\t\tw.Write([]byte(iface.String()))\n\t\treturn true\n\t}\n\treturn false\n}\n\n// printBool outputs a boolean value as true or false to Writer w.\nfunc printBool(w io.Writer, val bool) {\n\tif val {\n\t\tw.Write(trueBytes)\n\t} else {\n\t\tw.Write(falseBytes)\n\t}\n}\n\n// printInt outputs a signed integer value to Writer w.\nfunc printInt(w io.Writer, val int64, base int) {\n\tw.Write([]byte(strconv.FormatInt(val, base)))\n}\n\n// printUint outputs an unsigned integer value to Writer w.\nfunc printUint(w io.Writer, val uint64, base int) {\n\tw.Write([]byte(strconv.FormatUint(val, base)))\n}\n\n// printFloat outputs a floating point value using the specified precision,\n// which is expected to be 32 or 64bit, to Writer w.\nfunc printFloat(w io.Writer, val float64, precision int) {\n\tw.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))\n}\n\n// printComplex outputs a complex value using the specified float precision\n// for the real and imaginary parts to Writer w.\nfunc printComplex(w io.Writer, c complex128, floatPrecision int) {\n\tr := real(c)\n\tw.Write(openParenBytes)\n\tw.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))\n\ti := imag(c)\n\tif i >= 0 {\n\t\tw.Write(plusBytes)\n\t}\n\tw.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))\n\tw.Write(iBytes)\n\tw.Write(closeParenBytes)\n}\n\n// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'\n// prefix to Writer w.\nfunc printHexPtr(w io.Writer, p uintptr) {\n\t// Null pointer.\n\tnum := uint64(p)\n\tif num == 0 {\n\t\tw.Write(nilAngleBytes)\n\t\treturn\n\t}\n\n\t// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix\n\tbuf := make([]byte, 18)\n\n\t// It's simpler to construct the hex string right to left.\n\tbase := uint64(16)\n\ti := len(buf) - 1\n\tfor num >= base {\n\t\tbuf[i] = hexDigits[num%base]\n\t\tnum /= base\n\t\ti--\n\t}\n\tbuf[i] = hexDigits[num]\n\n\t// Add '0x' prefix.\n\ti--\n\tbuf[i] = 'x'\n\ti--\n\tbuf[i] = '0'\n\n\t// Strip unused leading bytes.\n\tbuf = buf[i:]\n\tw.Write(buf)\n}\n\n// valuesSorter implements sort.Interface to allow a slice of reflect.Value\n// elements to be sorted.\ntype valuesSorter struct {\n\tvalues  []reflect.Value\n\tstrings []string // either nil or same len and values\n\tcs      *ConfigState\n}\n\n// newValuesSorter initializes a valuesSorter instance, which holds a set of\n// surrogate keys on which the data should be sorted.  It uses flags in\n// ConfigState to decide if and how to populate those surrogate keys.\nfunc newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {\n\tvs := &valuesSorter{values: values, cs: cs}\n\tif canSortSimply(vs.values[0].Kind()) {\n\t\treturn vs\n\t}\n\tif !cs.DisableMethods {\n\t\tvs.strings = make([]string, len(values))\n\t\tfor i := range vs.values {\n\t\t\tb := bytes.Buffer{}\n\t\t\tif !handleMethods(cs, &b, vs.values[i]) {\n\t\t\t\tvs.strings = nil\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tvs.strings[i] = b.String()\n\t\t}\n\t}\n\tif vs.strings == nil && cs.SpewKeys {\n\t\tvs.strings = make([]string, len(values))\n\t\tfor i := range vs.values {\n\t\t\tvs.strings[i] = Sprintf(\"%#v\", vs.values[i].Interface())\n\t\t}\n\t}\n\treturn vs\n}\n\n// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted\n// directly, or whether it should be considered for sorting by surrogate keys\n// (if the ConfigState allows it).\nfunc canSortSimply(kind reflect.Kind) bool {\n\t// This switch parallels valueSortLess, except for the default case.\n\tswitch kind {\n\tcase reflect.Bool:\n\t\treturn true\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\treturn true\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\treturn true\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn true\n\tcase reflect.String:\n\t\treturn true\n\tcase reflect.Uintptr:\n\t\treturn true\n\tcase reflect.Array:\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Len returns the number of values in the slice.  It is part of the\n// sort.Interface implementation.\nfunc (s *valuesSorter) Len() int {\n\treturn len(s.values)\n}\n\n// Swap swaps the values at the passed indices.  It is part of the\n// sort.Interface implementation.\nfunc (s *valuesSorter) Swap(i, j int) {\n\ts.values[i], s.values[j] = s.values[j], s.values[i]\n\tif s.strings != nil {\n\t\ts.strings[i], s.strings[j] = s.strings[j], s.strings[i]\n\t}\n}\n\n// valueSortLess returns whether the first value should sort before the second\n// value.  It is used by valueSorter.Less as part of the sort.Interface\n// implementation.\nfunc valueSortLess(a, b reflect.Value) bool {\n\tswitch a.Kind() {\n\tcase reflect.Bool:\n\t\treturn !a.Bool() && b.Bool()\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\treturn a.Int() < b.Int()\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\treturn a.Uint() < b.Uint()\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn a.Float() < b.Float()\n\tcase reflect.String:\n\t\treturn a.String() < b.String()\n\tcase reflect.Uintptr:\n\t\treturn a.Uint() < b.Uint()\n\tcase reflect.Array:\n\t\t// Compare the contents of both arrays.\n\t\tl := a.Len()\n\t\tfor i := 0; i < l; i++ {\n\t\t\tav := a.Index(i)\n\t\t\tbv := b.Index(i)\n\t\t\tif av.Interface() == bv.Interface() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn valueSortLess(av, bv)\n\t\t}\n\t}\n\treturn a.String() < b.String()\n}\n\n// Less returns whether the value at index i should sort before the\n// value at index j.  It is part of the sort.Interface implementation.\nfunc (s *valuesSorter) Less(i, j int) bool {\n\tif s.strings == nil {\n\t\treturn valueSortLess(s.values[i], s.values[j])\n\t}\n\treturn s.strings[i] < s.strings[j]\n}\n\n// sortValues is a sort function that handles both native types and any type that\n// can be converted to error or Stringer.  Other inputs are sorted according to\n// their Value.String() value to ensure display stability.\nfunc sortValues(values []reflect.Value, cs *ConfigState) {\n\tif len(values) == 0 {\n\t\treturn\n\t}\n\tsort.Sort(newValuesSorter(values, cs))\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/config.go",
    "content": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n)\n\n// ConfigState houses the configuration options used by spew to format and\n// display values.  There is a global instance, Config, that is used to control\n// all top-level Formatter and Dump functionality.  Each ConfigState instance\n// provides methods equivalent to the top-level functions.\n//\n// The zero value for ConfigState provides no indentation.  You would typically\n// want to set it to a space or a tab.\n//\n// Alternatively, you can use NewDefaultConfig to get a ConfigState instance\n// with default settings.  See the documentation of NewDefaultConfig for default\n// values.\ntype ConfigState struct {\n\t// Indent specifies the string to use for each indentation level.  The\n\t// global config instance that all top-level functions use set this to a\n\t// single space by default.  If you would like more indentation, you might\n\t// set this to a tab with \"\\t\" or perhaps two spaces with \"  \".\n\tIndent string\n\n\t// MaxDepth controls the maximum number of levels to descend into nested\n\t// data structures.  The default, 0, means there is no limit.\n\t//\n\t// NOTE: Circular data structures are properly detected, so it is not\n\t// necessary to set this value unless you specifically want to limit deeply\n\t// nested data structures.\n\tMaxDepth int\n\n\t// DisableMethods specifies whether or not error and Stringer interfaces are\n\t// invoked for types that implement them.\n\tDisableMethods bool\n\n\t// DisablePointerMethods specifies whether or not to check for and invoke\n\t// error and Stringer interfaces on types which only accept a pointer\n\t// receiver when the current type is not a pointer.\n\t//\n\t// NOTE: This might be an unsafe action since calling one of these methods\n\t// with a pointer receiver could technically mutate the value, however,\n\t// in practice, types which choose to satisify an error or Stringer\n\t// interface with a pointer receiver should not be mutating their state\n\t// inside these interface methods.  As a result, this option relies on\n\t// access to the unsafe package, so it will not have any effect when\n\t// running in environments without access to the unsafe package such as\n\t// Google App Engine or with the \"safe\" build tag specified.\n\tDisablePointerMethods bool\n\n\t// DisablePointerAddresses specifies whether to disable the printing of\n\t// pointer addresses. This is useful when diffing data structures in tests.\n\tDisablePointerAddresses bool\n\n\t// DisableCapacities specifies whether to disable the printing of capacities\n\t// for arrays, slices, maps and channels. This is useful when diffing\n\t// data structures in tests.\n\tDisableCapacities bool\n\n\t// ContinueOnMethod specifies whether or not recursion should continue once\n\t// a custom error or Stringer interface is invoked.  The default, false,\n\t// means it will print the results of invoking the custom error or Stringer\n\t// interface and return immediately instead of continuing to recurse into\n\t// the internals of the data type.\n\t//\n\t// NOTE: This flag does not have any effect if method invocation is disabled\n\t// via the DisableMethods or DisablePointerMethods options.\n\tContinueOnMethod bool\n\n\t// SortKeys specifies map keys should be sorted before being printed. Use\n\t// this to have a more deterministic, diffable output.  Note that only\n\t// native types (bool, int, uint, floats, uintptr and string) and types\n\t// that support the error or Stringer interfaces (if methods are\n\t// enabled) are supported, with other types sorted according to the\n\t// reflect.Value.String() output which guarantees display stability.\n\tSortKeys bool\n\n\t// SpewKeys specifies that, as a last resort attempt, map keys should\n\t// be spewed to strings and sorted by those strings.  This is only\n\t// considered if SortKeys is true.\n\tSpewKeys bool\n}\n\n// Config is the active configuration of the top-level functions.\n// The configuration can be changed by modifying the contents of spew.Config.\nvar Config = ConfigState{Indent: \" \"}\n\n// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the formatted string as a value that satisfies error.  See NewFormatter\n// for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {\n\treturn fmt.Errorf(format, c.convertArgs(a)...)\n}\n\n// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprint(w, c.convertArgs(a)...)\n}\n\n// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintf(w, format, c.convertArgs(a)...)\n}\n\n// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it\n// passed with a Formatter interface returned by c.NewFormatter.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintln(w, c.convertArgs(a)...)\n}\n\n// Print is a wrapper for fmt.Print that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Print(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Print(a ...interface{}) (n int, err error) {\n\treturn fmt.Print(c.convertArgs(a)...)\n}\n\n// Printf is a wrapper for fmt.Printf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Printf(format, c.convertArgs(a)...)\n}\n\n// Println is a wrapper for fmt.Println that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Println(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Println(a ...interface{}) (n int, err error) {\n\treturn fmt.Println(c.convertArgs(a)...)\n}\n\n// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Sprint(a ...interface{}) string {\n\treturn fmt.Sprint(c.convertArgs(a)...)\n}\n\n// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were\n// passed with a Formatter interface returned by c.NewFormatter.  It returns\n// the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Sprintf(format string, a ...interface{}) string {\n\treturn fmt.Sprintf(format, c.convertArgs(a)...)\n}\n\n// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it\n// were passed with a Formatter interface returned by c.NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))\nfunc (c *ConfigState) Sprintln(a ...interface{}) string {\n\treturn fmt.Sprintln(c.convertArgs(a)...)\n}\n\n/*\nNewFormatter returns a custom formatter that satisfies the fmt.Formatter\ninterface.  As a result, it integrates cleanly with standard fmt package\nprinting functions.  The formatter is useful for inline printing of smaller data\ntypes similar to the standard %v format specifier.\n\nThe custom formatter only responds to the %v (most compact), %+v (adds pointer\naddresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb\ncombinations.  Any other verbs such as %x and %q will be sent to the the\nstandard fmt package for formatting.  In addition, the custom formatter ignores\nthe width and precision arguments (however they will still work on the format\nspecifiers not handled by the custom formatter).\n\nTypically this function shouldn't be called directly.  It is much easier to make\nuse of the custom formatter by calling one of the convenience functions such as\nc.Printf, c.Println, or c.Printf.\n*/\nfunc (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {\n\treturn newFormatter(c, v)\n}\n\n// Fdump formats and displays the passed arguments to io.Writer w.  It formats\n// exactly the same as Dump.\nfunc (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {\n\tfdump(c, w, a...)\n}\n\n/*\nDump displays the passed parameters to standard out with newlines, customizable\nindentation, and additional debug information such as complete types and all\npointer addresses used to indirect to the final value.  It provides the\nfollowing features over the built-in printing facilities provided by the fmt\npackage:\n\n\t* Pointers are dereferenced and followed\n\t* Circular data structures are detected and handled properly\n\t* Custom Stringer/error interfaces are optionally invoked, including\n\t  on unexported types\n\t* Custom types which only implement the Stringer/error interfaces via\n\t  a pointer receiver are optionally invoked when passing non-pointer\n\t  variables\n\t* Byte arrays and slices are dumped like the hexdump -C command which\n\t  includes offsets, byte values in hex, and ASCII output\n\nThe configuration options are controlled by modifying the public members\nof c.  See ConfigState for options documentation.\n\nSee Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to\nget the formatted result as a string.\n*/\nfunc (c *ConfigState) Dump(a ...interface{}) {\n\tfdump(c, os.Stdout, a...)\n}\n\n// Sdump returns a string with the passed arguments formatted exactly the same\n// as Dump.\nfunc (c *ConfigState) Sdump(a ...interface{}) string {\n\tvar buf bytes.Buffer\n\tfdump(c, &buf, a...)\n\treturn buf.String()\n}\n\n// convertArgs accepts a slice of arguments and returns a slice of the same\n// length with each argument converted to a spew Formatter interface using\n// the ConfigState associated with s.\nfunc (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {\n\tformatters = make([]interface{}, len(args))\n\tfor index, arg := range args {\n\t\tformatters[index] = newFormatter(c, arg)\n\t}\n\treturn formatters\n}\n\n// NewDefaultConfig returns a ConfigState with the following default settings.\n//\n// \tIndent: \" \"\n// \tMaxDepth: 0\n// \tDisableMethods: false\n// \tDisablePointerMethods: false\n// \tContinueOnMethod: false\n// \tSortKeys: false\nfunc NewDefaultConfig() *ConfigState {\n\treturn &ConfigState{Indent: \" \"}\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/doc.go",
    "content": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n/*\nPackage spew implements a deep pretty printer for Go data structures to aid in\ndebugging.\n\nA quick overview of the additional features spew provides over the built-in\nprinting facilities for Go data types are as follows:\n\n\t* Pointers are dereferenced and followed\n\t* Circular data structures are detected and handled properly\n\t* Custom Stringer/error interfaces are optionally invoked, including\n\t  on unexported types\n\t* Custom types which only implement the Stringer/error interfaces via\n\t  a pointer receiver are optionally invoked when passing non-pointer\n\t  variables\n\t* Byte arrays and slices are dumped like the hexdump -C command which\n\t  includes offsets, byte values in hex, and ASCII output (only when using\n\t  Dump style)\n\nThere are two different approaches spew allows for dumping Go data structures:\n\n\t* Dump style which prints with newlines, customizable indentation,\n\t  and additional debug information such as types and all pointer addresses\n\t  used to indirect to the final value\n\t* A custom Formatter interface that integrates cleanly with the standard fmt\n\t  package and replaces %v, %+v, %#v, and %#+v to provide inline printing\n\t  similar to the default %v while providing the additional functionality\n\t  outlined above and passing unsupported format verbs such as %x and %q\n\t  along to fmt\n\nQuick Start\n\nThis section demonstrates how to quickly get started with spew.  See the\nsections below for further details on formatting and configuration options.\n\nTo dump a variable with full newlines, indentation, type, and pointer\ninformation use Dump, Fdump, or Sdump:\n\tspew.Dump(myVar1, myVar2, ...)\n\tspew.Fdump(someWriter, myVar1, myVar2, ...)\n\tstr := spew.Sdump(myVar1, myVar2, ...)\n\nAlternatively, if you would prefer to use format strings with a compacted inline\nprinting style, use the convenience wrappers Printf, Fprintf, etc with\n%v (most compact), %+v (adds pointer addresses), %#v (adds types), or\n%#+v (adds types and pointer addresses):\n\tspew.Printf(\"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Printf(\"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\tspew.Fprintf(someWriter, \"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Fprintf(someWriter, \"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\nConfiguration Options\n\nConfiguration of spew is handled by fields in the ConfigState type.  For\nconvenience, all of the top-level functions use a global state available\nvia the spew.Config global.\n\nIt is also possible to create a ConfigState instance that provides methods\nequivalent to the top-level functions.  This allows concurrent configuration\noptions.  See the ConfigState documentation for more details.\n\nThe following configuration options are available:\n\t* Indent\n\t\tString to use for each indentation level for Dump functions.\n\t\tIt is a single space by default.  A popular alternative is \"\\t\".\n\n\t* MaxDepth\n\t\tMaximum number of levels to descend into nested data structures.\n\t\tThere is no limit by default.\n\n\t* DisableMethods\n\t\tDisables invocation of error and Stringer interface methods.\n\t\tMethod invocation is enabled by default.\n\n\t* DisablePointerMethods\n\t\tDisables invocation of error and Stringer interface methods on types\n\t\twhich only accept pointer receivers from non-pointer variables.\n\t\tPointer method invocation is enabled by default.\n\n\t* DisablePointerAddresses\n\t\tDisablePointerAddresses specifies whether to disable the printing of\n\t\tpointer addresses. This is useful when diffing data structures in tests.\n\n\t* DisableCapacities\n\t\tDisableCapacities specifies whether to disable the printing of\n\t\tcapacities for arrays, slices, maps and channels. This is useful when\n\t\tdiffing data structures in tests.\n\n\t* ContinueOnMethod\n\t\tEnables recursion into types after invoking error and Stringer interface\n\t\tmethods. Recursion after method invocation is disabled by default.\n\n\t* SortKeys\n\t\tSpecifies map keys should be sorted before being printed. Use\n\t\tthis to have a more deterministic, diffable output.  Note that\n\t\tonly native types (bool, int, uint, floats, uintptr and string)\n\t\tand types which implement error or Stringer interfaces are\n\t\tsupported with other types sorted according to the\n\t\treflect.Value.String() output which guarantees display\n\t\tstability.  Natural map order is used by default.\n\n\t* SpewKeys\n\t\tSpecifies that, as a last resort attempt, map keys should be\n\t\tspewed to strings and sorted by those strings.  This is only\n\t\tconsidered if SortKeys is true.\n\nDump Usage\n\nSimply call spew.Dump with a list of variables you want to dump:\n\n\tspew.Dump(myVar1, myVar2, ...)\n\nYou may also call spew.Fdump if you would prefer to output to an arbitrary\nio.Writer.  For example, to dump to standard error:\n\n\tspew.Fdump(os.Stderr, myVar1, myVar2, ...)\n\nA third option is to call spew.Sdump to get the formatted output as a string:\n\n\tstr := spew.Sdump(myVar1, myVar2, ...)\n\nSample Dump Output\n\nSee the Dump example for details on the setup of the types and variables being\nshown here.\n\n\t(main.Foo) {\n\t unexportedField: (*main.Bar)(0xf84002e210)({\n\t  flag: (main.Flag) flagTwo,\n\t  data: (uintptr) <nil>\n\t }),\n\t ExportedField: (map[interface {}]interface {}) (len=1) {\n\t  (string) (len=3) \"one\": (bool) true\n\t }\n\t}\n\nByte (and uint8) arrays and slices are displayed uniquely like the hexdump -C\ncommand as shown.\n\t([]uint8) (len=32 cap=32) {\n\t 00000000  11 12 13 14 15 16 17 18  19 1a 1b 1c 1d 1e 1f 20  |............... |\n\t 00000010  21 22 23 24 25 26 27 28  29 2a 2b 2c 2d 2e 2f 30  |!\"#$%&'()*+,-./0|\n\t 00000020  31 32                                             |12|\n\t}\n\nCustom Formatter\n\nSpew provides a custom formatter that implements the fmt.Formatter interface\nso that it integrates cleanly with standard fmt package printing functions. The\nformatter is useful for inline printing of smaller data types similar to the\nstandard %v format specifier.\n\nThe custom formatter only responds to the %v (most compact), %+v (adds pointer\naddresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb\ncombinations.  Any other verbs such as %x and %q will be sent to the the\nstandard fmt package for formatting.  In addition, the custom formatter ignores\nthe width and precision arguments (however they will still work on the format\nspecifiers not handled by the custom formatter).\n\nCustom Formatter Usage\n\nThe simplest way to make use of the spew custom formatter is to call one of the\nconvenience functions such as spew.Printf, spew.Println, or spew.Printf.  The\nfunctions have syntax you are most likely already familiar with:\n\n\tspew.Printf(\"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Printf(\"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\tspew.Println(myVar, myVar2)\n\tspew.Fprintf(os.Stderr, \"myVar1: %v -- myVar2: %+v\", myVar1, myVar2)\n\tspew.Fprintf(os.Stderr, \"myVar3: %#v -- myVar4: %#+v\", myVar3, myVar4)\n\nSee the Index for the full list convenience functions.\n\nSample Formatter Output\n\nDouble pointer to a uint8:\n\t  %v: <**>5\n\t %+v: <**>(0xf8400420d0->0xf8400420c8)5\n\t %#v: (**uint8)5\n\t%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5\n\nPointer to circular struct with a uint8 field and a pointer to itself:\n\t  %v: <*>{1 <*><shown>}\n\t %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}\n\t %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}\n\t%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}\n\nSee the Printf example for details on the setup of variables being shown\nhere.\n\nErrors\n\nSince it is possible for custom Stringer/error interfaces to panic, spew\ndetects them and handles them internally by printing the panic information\ninline with the output.  Since spew is intended to provide deep pretty printing\ncapabilities on structures, it intentionally does not return any errors.\n*/\npackage spew\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/dump.go",
    "content": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar (\n\t// uint8Type is a reflect.Type representing a uint8.  It is used to\n\t// convert cgo types to uint8 slices for hexdumping.\n\tuint8Type = reflect.TypeOf(uint8(0))\n\n\t// cCharRE is a regular expression that matches a cgo char.\n\t// It is used to detect character arrays to hexdump them.\n\tcCharRE = regexp.MustCompile(`^.*\\._Ctype_char$`)\n\n\t// cUnsignedCharRE is a regular expression that matches a cgo unsigned\n\t// char.  It is used to detect unsigned character arrays to hexdump\n\t// them.\n\tcUnsignedCharRE = regexp.MustCompile(`^.*\\._Ctype_unsignedchar$`)\n\n\t// cUint8tCharRE is a regular expression that matches a cgo uint8_t.\n\t// It is used to detect uint8_t arrays to hexdump them.\n\tcUint8tCharRE = regexp.MustCompile(`^.*\\._Ctype_uint8_t$`)\n)\n\n// dumpState contains information about the state of a dump operation.\ntype dumpState struct {\n\tw                io.Writer\n\tdepth            int\n\tpointers         map[uintptr]int\n\tignoreNextType   bool\n\tignoreNextIndent bool\n\tcs               *ConfigState\n}\n\n// indent performs indentation according to the depth level and cs.Indent\n// option.\nfunc (d *dumpState) indent() {\n\tif d.ignoreNextIndent {\n\t\td.ignoreNextIndent = false\n\t\treturn\n\t}\n\td.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))\n}\n\n// unpackValue returns values inside of non-nil interfaces when possible.\n// This is useful for data types like structs, arrays, slices, and maps which\n// can contain varying types packed inside an interface.\nfunc (d *dumpState) unpackValue(v reflect.Value) reflect.Value {\n\tif v.Kind() == reflect.Interface && !v.IsNil() {\n\t\tv = v.Elem()\n\t}\n\treturn v\n}\n\n// dumpPtr handles formatting of pointers by indirecting them as necessary.\nfunc (d *dumpState) dumpPtr(v reflect.Value) {\n\t// Remove pointers at or below the current depth from map used to detect\n\t// circular refs.\n\tfor k, depth := range d.pointers {\n\t\tif depth >= d.depth {\n\t\t\tdelete(d.pointers, k)\n\t\t}\n\t}\n\n\t// Keep list of all dereferenced pointers to show later.\n\tpointerChain := make([]uintptr, 0)\n\n\t// Figure out how many levels of indirection there are by dereferencing\n\t// pointers and unpacking interfaces down the chain while detecting circular\n\t// references.\n\tnilFound := false\n\tcycleFound := false\n\tindirects := 0\n\tve := v\n\tfor ve.Kind() == reflect.Ptr {\n\t\tif ve.IsNil() {\n\t\t\tnilFound = true\n\t\t\tbreak\n\t\t}\n\t\tindirects++\n\t\taddr := ve.Pointer()\n\t\tpointerChain = append(pointerChain, addr)\n\t\tif pd, ok := d.pointers[addr]; ok && pd < d.depth {\n\t\t\tcycleFound = true\n\t\t\tindirects--\n\t\t\tbreak\n\t\t}\n\t\td.pointers[addr] = d.depth\n\n\t\tve = ve.Elem()\n\t\tif ve.Kind() == reflect.Interface {\n\t\t\tif ve.IsNil() {\n\t\t\t\tnilFound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tve = ve.Elem()\n\t\t}\n\t}\n\n\t// Display type information.\n\td.w.Write(openParenBytes)\n\td.w.Write(bytes.Repeat(asteriskBytes, indirects))\n\td.w.Write([]byte(ve.Type().String()))\n\td.w.Write(closeParenBytes)\n\n\t// Display pointer information.\n\tif !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {\n\t\td.w.Write(openParenBytes)\n\t\tfor i, addr := range pointerChain {\n\t\t\tif i > 0 {\n\t\t\t\td.w.Write(pointerChainBytes)\n\t\t\t}\n\t\t\tprintHexPtr(d.w, addr)\n\t\t}\n\t\td.w.Write(closeParenBytes)\n\t}\n\n\t// Display dereferenced value.\n\td.w.Write(openParenBytes)\n\tswitch {\n\tcase nilFound:\n\t\td.w.Write(nilAngleBytes)\n\n\tcase cycleFound:\n\t\td.w.Write(circularBytes)\n\n\tdefault:\n\t\td.ignoreNextType = true\n\t\td.dump(ve)\n\t}\n\td.w.Write(closeParenBytes)\n}\n\n// dumpSlice handles formatting of arrays and slices.  Byte (uint8 under\n// reflection) arrays and slices are dumped in hexdump -C fashion.\nfunc (d *dumpState) dumpSlice(v reflect.Value) {\n\t// Determine whether this type should be hex dumped or not.  Also,\n\t// for types which should be hexdumped, try to use the underlying data\n\t// first, then fall back to trying to convert them to a uint8 slice.\n\tvar buf []uint8\n\tdoConvert := false\n\tdoHexDump := false\n\tnumEntries := v.Len()\n\tif numEntries > 0 {\n\t\tvt := v.Index(0).Type()\n\t\tvts := vt.String()\n\t\tswitch {\n\t\t// C types that need to be converted.\n\t\tcase cCharRE.MatchString(vts):\n\t\t\tfallthrough\n\t\tcase cUnsignedCharRE.MatchString(vts):\n\t\t\tfallthrough\n\t\tcase cUint8tCharRE.MatchString(vts):\n\t\t\tdoConvert = true\n\n\t\t// Try to use existing uint8 slices and fall back to converting\n\t\t// and copying if that fails.\n\t\tcase vt.Kind() == reflect.Uint8:\n\t\t\t// We need an addressable interface to convert the type\n\t\t\t// to a byte slice.  However, the reflect package won't\n\t\t\t// give us an interface on certain things like\n\t\t\t// unexported struct fields in order to enforce\n\t\t\t// visibility rules.  We use unsafe, when available, to\n\t\t\t// bypass these restrictions since this package does not\n\t\t\t// mutate the values.\n\t\t\tvs := v\n\t\t\tif !vs.CanInterface() || !vs.CanAddr() {\n\t\t\t\tvs = unsafeReflectValue(vs)\n\t\t\t}\n\t\t\tif !UnsafeDisabled {\n\t\t\t\tvs = vs.Slice(0, numEntries)\n\n\t\t\t\t// Use the existing uint8 slice if it can be\n\t\t\t\t// type asserted.\n\t\t\t\tiface := vs.Interface()\n\t\t\t\tif slice, ok := iface.([]uint8); ok {\n\t\t\t\t\tbuf = slice\n\t\t\t\t\tdoHexDump = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The underlying data needs to be converted if it can't\n\t\t\t// be type asserted to a uint8 slice.\n\t\t\tdoConvert = true\n\t\t}\n\n\t\t// Copy and convert the underlying type if needed.\n\t\tif doConvert && vt.ConvertibleTo(uint8Type) {\n\t\t\t// Convert and copy each element into a uint8 byte\n\t\t\t// slice.\n\t\t\tbuf = make([]uint8, numEntries)\n\t\t\tfor i := 0; i < numEntries; i++ {\n\t\t\t\tvv := v.Index(i)\n\t\t\t\tbuf[i] = uint8(vv.Convert(uint8Type).Uint())\n\t\t\t}\n\t\t\tdoHexDump = true\n\t\t}\n\t}\n\n\t// Hexdump the entire slice as needed.\n\tif doHexDump {\n\t\tindent := strings.Repeat(d.cs.Indent, d.depth)\n\t\tstr := indent + hex.Dump(buf)\n\t\tstr = strings.Replace(str, \"\\n\", \"\\n\"+indent, -1)\n\t\tstr = strings.TrimRight(str, d.cs.Indent)\n\t\td.w.Write([]byte(str))\n\t\treturn\n\t}\n\n\t// Recursively call dump for each item.\n\tfor i := 0; i < numEntries; i++ {\n\t\td.dump(d.unpackValue(v.Index(i)))\n\t\tif i < (numEntries - 1) {\n\t\t\td.w.Write(commaNewlineBytes)\n\t\t} else {\n\t\t\td.w.Write(newlineBytes)\n\t\t}\n\t}\n}\n\n// dump is the main workhorse for dumping a value.  It uses the passed reflect\n// value to figure out what kind of object we are dealing with and formats it\n// appropriately.  It is a recursive function, however circular data structures\n// are detected and handled properly.\nfunc (d *dumpState) dump(v reflect.Value) {\n\t// Handle invalid reflect values immediately.\n\tkind := v.Kind()\n\tif kind == reflect.Invalid {\n\t\td.w.Write(invalidAngleBytes)\n\t\treturn\n\t}\n\n\t// Handle pointers specially.\n\tif kind == reflect.Ptr {\n\t\td.indent()\n\t\td.dumpPtr(v)\n\t\treturn\n\t}\n\n\t// Print type information unless already handled elsewhere.\n\tif !d.ignoreNextType {\n\t\td.indent()\n\t\td.w.Write(openParenBytes)\n\t\td.w.Write([]byte(v.Type().String()))\n\t\td.w.Write(closeParenBytes)\n\t\td.w.Write(spaceBytes)\n\t}\n\td.ignoreNextType = false\n\n\t// Display length and capacity if the built-in len and cap functions\n\t// work with the value's kind and the len/cap itself is non-zero.\n\tvalueLen, valueCap := 0, 0\n\tswitch v.Kind() {\n\tcase reflect.Array, reflect.Slice, reflect.Chan:\n\t\tvalueLen, valueCap = v.Len(), v.Cap()\n\tcase reflect.Map, reflect.String:\n\t\tvalueLen = v.Len()\n\t}\n\tif valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {\n\t\td.w.Write(openParenBytes)\n\t\tif valueLen != 0 {\n\t\t\td.w.Write(lenEqualsBytes)\n\t\t\tprintInt(d.w, int64(valueLen), 10)\n\t\t}\n\t\tif !d.cs.DisableCapacities && valueCap != 0 {\n\t\t\tif valueLen != 0 {\n\t\t\t\td.w.Write(spaceBytes)\n\t\t\t}\n\t\t\td.w.Write(capEqualsBytes)\n\t\t\tprintInt(d.w, int64(valueCap), 10)\n\t\t}\n\t\td.w.Write(closeParenBytes)\n\t\td.w.Write(spaceBytes)\n\t}\n\n\t// Call Stringer/error interfaces if they exist and the handle methods flag\n\t// is enabled\n\tif !d.cs.DisableMethods {\n\t\tif (kind != reflect.Invalid) && (kind != reflect.Interface) {\n\t\t\tif handled := handleMethods(d.cs, d.w, v); handled {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch kind {\n\tcase reflect.Invalid:\n\t\t// Do nothing.  We should never get here since invalid has already\n\t\t// been handled above.\n\n\tcase reflect.Bool:\n\t\tprintBool(d.w, v.Bool())\n\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\tprintInt(d.w, v.Int(), 10)\n\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\tprintUint(d.w, v.Uint(), 10)\n\n\tcase reflect.Float32:\n\t\tprintFloat(d.w, v.Float(), 32)\n\n\tcase reflect.Float64:\n\t\tprintFloat(d.w, v.Float(), 64)\n\n\tcase reflect.Complex64:\n\t\tprintComplex(d.w, v.Complex(), 32)\n\n\tcase reflect.Complex128:\n\t\tprintComplex(d.w, v.Complex(), 64)\n\n\tcase reflect.Slice:\n\t\tif v.IsNil() {\n\t\t\td.w.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\t\tfallthrough\n\n\tcase reflect.Array:\n\t\td.w.Write(openBraceNewlineBytes)\n\t\td.depth++\n\t\tif (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {\n\t\t\td.indent()\n\t\t\td.w.Write(maxNewlineBytes)\n\t\t} else {\n\t\t\td.dumpSlice(v)\n\t\t}\n\t\td.depth--\n\t\td.indent()\n\t\td.w.Write(closeBraceBytes)\n\n\tcase reflect.String:\n\t\td.w.Write([]byte(strconv.Quote(v.String())))\n\n\tcase reflect.Interface:\n\t\t// The only time we should get here is for nil interfaces due to\n\t\t// unpackValue calls.\n\t\tif v.IsNil() {\n\t\t\td.w.Write(nilAngleBytes)\n\t\t}\n\n\tcase reflect.Ptr:\n\t\t// Do nothing.  We should never get here since pointers have already\n\t\t// been handled above.\n\n\tcase reflect.Map:\n\t\t// nil maps should be indicated as different than empty maps\n\t\tif v.IsNil() {\n\t\t\td.w.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\n\t\td.w.Write(openBraceNewlineBytes)\n\t\td.depth++\n\t\tif (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {\n\t\t\td.indent()\n\t\t\td.w.Write(maxNewlineBytes)\n\t\t} else {\n\t\t\tnumEntries := v.Len()\n\t\t\tkeys := v.MapKeys()\n\t\t\tif d.cs.SortKeys {\n\t\t\t\tsortValues(keys, d.cs)\n\t\t\t}\n\t\t\tfor i, key := range keys {\n\t\t\t\td.dump(d.unpackValue(key))\n\t\t\t\td.w.Write(colonSpaceBytes)\n\t\t\t\td.ignoreNextIndent = true\n\t\t\t\td.dump(d.unpackValue(v.MapIndex(key)))\n\t\t\t\tif i < (numEntries - 1) {\n\t\t\t\t\td.w.Write(commaNewlineBytes)\n\t\t\t\t} else {\n\t\t\t\t\td.w.Write(newlineBytes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\td.depth--\n\t\td.indent()\n\t\td.w.Write(closeBraceBytes)\n\n\tcase reflect.Struct:\n\t\td.w.Write(openBraceNewlineBytes)\n\t\td.depth++\n\t\tif (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {\n\t\t\td.indent()\n\t\t\td.w.Write(maxNewlineBytes)\n\t\t} else {\n\t\t\tvt := v.Type()\n\t\t\tnumFields := v.NumField()\n\t\t\tfor i := 0; i < numFields; i++ {\n\t\t\t\td.indent()\n\t\t\t\tvtf := vt.Field(i)\n\t\t\t\td.w.Write([]byte(vtf.Name))\n\t\t\t\td.w.Write(colonSpaceBytes)\n\t\t\t\td.ignoreNextIndent = true\n\t\t\t\td.dump(d.unpackValue(v.Field(i)))\n\t\t\t\tif i < (numFields - 1) {\n\t\t\t\t\td.w.Write(commaNewlineBytes)\n\t\t\t\t} else {\n\t\t\t\t\td.w.Write(newlineBytes)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\td.depth--\n\t\td.indent()\n\t\td.w.Write(closeBraceBytes)\n\n\tcase reflect.Uintptr:\n\t\tprintHexPtr(d.w, uintptr(v.Uint()))\n\n\tcase reflect.UnsafePointer, reflect.Chan, reflect.Func:\n\t\tprintHexPtr(d.w, v.Pointer())\n\n\t// There were not any other types at the time this code was written, but\n\t// fall back to letting the default fmt package handle it in case any new\n\t// types are added.\n\tdefault:\n\t\tif v.CanInterface() {\n\t\t\tfmt.Fprintf(d.w, \"%v\", v.Interface())\n\t\t} else {\n\t\t\tfmt.Fprintf(d.w, \"%v\", v.String())\n\t\t}\n\t}\n}\n\n// fdump is a helper function to consolidate the logic from the various public\n// methods which take varying writers and config states.\nfunc fdump(cs *ConfigState, w io.Writer, a ...interface{}) {\n\tfor _, arg := range a {\n\t\tif arg == nil {\n\t\t\tw.Write(interfaceBytes)\n\t\t\tw.Write(spaceBytes)\n\t\t\tw.Write(nilAngleBytes)\n\t\t\tw.Write(newlineBytes)\n\t\t\tcontinue\n\t\t}\n\n\t\td := dumpState{w: w, cs: cs}\n\t\td.pointers = make(map[uintptr]int)\n\t\td.dump(reflect.ValueOf(arg))\n\t\td.w.Write(newlineBytes)\n\t}\n}\n\n// Fdump formats and displays the passed arguments to io.Writer w.  It formats\n// exactly the same as Dump.\nfunc Fdump(w io.Writer, a ...interface{}) {\n\tfdump(&Config, w, a...)\n}\n\n// Sdump returns a string with the passed arguments formatted exactly the same\n// as Dump.\nfunc Sdump(a ...interface{}) string {\n\tvar buf bytes.Buffer\n\tfdump(&Config, &buf, a...)\n\treturn buf.String()\n}\n\n/*\nDump displays the passed parameters to standard out with newlines, customizable\nindentation, and additional debug information such as complete types and all\npointer addresses used to indirect to the final value.  It provides the\nfollowing features over the built-in printing facilities provided by the fmt\npackage:\n\n\t* Pointers are dereferenced and followed\n\t* Circular data structures are detected and handled properly\n\t* Custom Stringer/error interfaces are optionally invoked, including\n\t  on unexported types\n\t* Custom types which only implement the Stringer/error interfaces via\n\t  a pointer receiver are optionally invoked when passing non-pointer\n\t  variables\n\t* Byte arrays and slices are dumped like the hexdump -C command which\n\t  includes offsets, byte values in hex, and ASCII output\n\nThe configuration options are controlled by an exported package global,\nspew.Config.  See ConfigState for options documentation.\n\nSee Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to\nget the formatted result as a string.\n*/\nfunc Dump(a ...interface{}) {\n\tfdump(&Config, os.Stdout, a...)\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/format.go",
    "content": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// supportedFlags is a list of all the character flags supported by fmt package.\nconst supportedFlags = \"0-+# \"\n\n// formatState implements the fmt.Formatter interface and contains information\n// about the state of a formatting operation.  The NewFormatter function can\n// be used to get a new Formatter which can be used directly as arguments\n// in standard fmt package printing calls.\ntype formatState struct {\n\tvalue          interface{}\n\tfs             fmt.State\n\tdepth          int\n\tpointers       map[uintptr]int\n\tignoreNextType bool\n\tcs             *ConfigState\n}\n\n// buildDefaultFormat recreates the original format string without precision\n// and width information to pass in to fmt.Sprintf in the case of an\n// unrecognized type.  Unless new types are added to the language, this\n// function won't ever be called.\nfunc (f *formatState) buildDefaultFormat() (format string) {\n\tbuf := bytes.NewBuffer(percentBytes)\n\n\tfor _, flag := range supportedFlags {\n\t\tif f.fs.Flag(int(flag)) {\n\t\t\tbuf.WriteRune(flag)\n\t\t}\n\t}\n\n\tbuf.WriteRune('v')\n\n\tformat = buf.String()\n\treturn format\n}\n\n// constructOrigFormat recreates the original format string including precision\n// and width information to pass along to the standard fmt package.  This allows\n// automatic deferral of all format strings this package doesn't support.\nfunc (f *formatState) constructOrigFormat(verb rune) (format string) {\n\tbuf := bytes.NewBuffer(percentBytes)\n\n\tfor _, flag := range supportedFlags {\n\t\tif f.fs.Flag(int(flag)) {\n\t\t\tbuf.WriteRune(flag)\n\t\t}\n\t}\n\n\tif width, ok := f.fs.Width(); ok {\n\t\tbuf.WriteString(strconv.Itoa(width))\n\t}\n\n\tif precision, ok := f.fs.Precision(); ok {\n\t\tbuf.Write(precisionBytes)\n\t\tbuf.WriteString(strconv.Itoa(precision))\n\t}\n\n\tbuf.WriteRune(verb)\n\n\tformat = buf.String()\n\treturn format\n}\n\n// unpackValue returns values inside of non-nil interfaces when possible and\n// ensures that types for values which have been unpacked from an interface\n// are displayed when the show types flag is also set.\n// This is useful for data types like structs, arrays, slices, and maps which\n// can contain varying types packed inside an interface.\nfunc (f *formatState) unpackValue(v reflect.Value) reflect.Value {\n\tif v.Kind() == reflect.Interface {\n\t\tf.ignoreNextType = false\n\t\tif !v.IsNil() {\n\t\t\tv = v.Elem()\n\t\t}\n\t}\n\treturn v\n}\n\n// formatPtr handles formatting of pointers by indirecting them as necessary.\nfunc (f *formatState) formatPtr(v reflect.Value) {\n\t// Display nil if top level pointer is nil.\n\tshowTypes := f.fs.Flag('#')\n\tif v.IsNil() && (!showTypes || f.ignoreNextType) {\n\t\tf.fs.Write(nilAngleBytes)\n\t\treturn\n\t}\n\n\t// Remove pointers at or below the current depth from map used to detect\n\t// circular refs.\n\tfor k, depth := range f.pointers {\n\t\tif depth >= f.depth {\n\t\t\tdelete(f.pointers, k)\n\t\t}\n\t}\n\n\t// Keep list of all dereferenced pointers to possibly show later.\n\tpointerChain := make([]uintptr, 0)\n\n\t// Figure out how many levels of indirection there are by derferencing\n\t// pointers and unpacking interfaces down the chain while detecting circular\n\t// references.\n\tnilFound := false\n\tcycleFound := false\n\tindirects := 0\n\tve := v\n\tfor ve.Kind() == reflect.Ptr {\n\t\tif ve.IsNil() {\n\t\t\tnilFound = true\n\t\t\tbreak\n\t\t}\n\t\tindirects++\n\t\taddr := ve.Pointer()\n\t\tpointerChain = append(pointerChain, addr)\n\t\tif pd, ok := f.pointers[addr]; ok && pd < f.depth {\n\t\t\tcycleFound = true\n\t\t\tindirects--\n\t\t\tbreak\n\t\t}\n\t\tf.pointers[addr] = f.depth\n\n\t\tve = ve.Elem()\n\t\tif ve.Kind() == reflect.Interface {\n\t\t\tif ve.IsNil() {\n\t\t\t\tnilFound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tve = ve.Elem()\n\t\t}\n\t}\n\n\t// Display type or indirection level depending on flags.\n\tif showTypes && !f.ignoreNextType {\n\t\tf.fs.Write(openParenBytes)\n\t\tf.fs.Write(bytes.Repeat(asteriskBytes, indirects))\n\t\tf.fs.Write([]byte(ve.Type().String()))\n\t\tf.fs.Write(closeParenBytes)\n\t} else {\n\t\tif nilFound || cycleFound {\n\t\t\tindirects += strings.Count(ve.Type().String(), \"*\")\n\t\t}\n\t\tf.fs.Write(openAngleBytes)\n\t\tf.fs.Write([]byte(strings.Repeat(\"*\", indirects)))\n\t\tf.fs.Write(closeAngleBytes)\n\t}\n\n\t// Display pointer information depending on flags.\n\tif f.fs.Flag('+') && (len(pointerChain) > 0) {\n\t\tf.fs.Write(openParenBytes)\n\t\tfor i, addr := range pointerChain {\n\t\t\tif i > 0 {\n\t\t\t\tf.fs.Write(pointerChainBytes)\n\t\t\t}\n\t\t\tprintHexPtr(f.fs, addr)\n\t\t}\n\t\tf.fs.Write(closeParenBytes)\n\t}\n\n\t// Display dereferenced value.\n\tswitch {\n\tcase nilFound:\n\t\tf.fs.Write(nilAngleBytes)\n\n\tcase cycleFound:\n\t\tf.fs.Write(circularShortBytes)\n\n\tdefault:\n\t\tf.ignoreNextType = true\n\t\tf.format(ve)\n\t}\n}\n\n// format is the main workhorse for providing the Formatter interface.  It\n// uses the passed reflect value to figure out what kind of object we are\n// dealing with and formats it appropriately.  It is a recursive function,\n// however circular data structures are detected and handled properly.\nfunc (f *formatState) format(v reflect.Value) {\n\t// Handle invalid reflect values immediately.\n\tkind := v.Kind()\n\tif kind == reflect.Invalid {\n\t\tf.fs.Write(invalidAngleBytes)\n\t\treturn\n\t}\n\n\t// Handle pointers specially.\n\tif kind == reflect.Ptr {\n\t\tf.formatPtr(v)\n\t\treturn\n\t}\n\n\t// Print type information unless already handled elsewhere.\n\tif !f.ignoreNextType && f.fs.Flag('#') {\n\t\tf.fs.Write(openParenBytes)\n\t\tf.fs.Write([]byte(v.Type().String()))\n\t\tf.fs.Write(closeParenBytes)\n\t}\n\tf.ignoreNextType = false\n\n\t// Call Stringer/error interfaces if they exist and the handle methods\n\t// flag is enabled.\n\tif !f.cs.DisableMethods {\n\t\tif (kind != reflect.Invalid) && (kind != reflect.Interface) {\n\t\t\tif handled := handleMethods(f.cs, f.fs, v); handled {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch kind {\n\tcase reflect.Invalid:\n\t\t// Do nothing.  We should never get here since invalid has already\n\t\t// been handled above.\n\n\tcase reflect.Bool:\n\t\tprintBool(f.fs, v.Bool())\n\n\tcase reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:\n\t\tprintInt(f.fs, v.Int(), 10)\n\n\tcase reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:\n\t\tprintUint(f.fs, v.Uint(), 10)\n\n\tcase reflect.Float32:\n\t\tprintFloat(f.fs, v.Float(), 32)\n\n\tcase reflect.Float64:\n\t\tprintFloat(f.fs, v.Float(), 64)\n\n\tcase reflect.Complex64:\n\t\tprintComplex(f.fs, v.Complex(), 32)\n\n\tcase reflect.Complex128:\n\t\tprintComplex(f.fs, v.Complex(), 64)\n\n\tcase reflect.Slice:\n\t\tif v.IsNil() {\n\t\t\tf.fs.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\t\tfallthrough\n\n\tcase reflect.Array:\n\t\tf.fs.Write(openBracketBytes)\n\t\tf.depth++\n\t\tif (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {\n\t\t\tf.fs.Write(maxShortBytes)\n\t\t} else {\n\t\t\tnumEntries := v.Len()\n\t\t\tfor i := 0; i < numEntries; i++ {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tf.fs.Write(spaceBytes)\n\t\t\t\t}\n\t\t\t\tf.ignoreNextType = true\n\t\t\t\tf.format(f.unpackValue(v.Index(i)))\n\t\t\t}\n\t\t}\n\t\tf.depth--\n\t\tf.fs.Write(closeBracketBytes)\n\n\tcase reflect.String:\n\t\tf.fs.Write([]byte(v.String()))\n\n\tcase reflect.Interface:\n\t\t// The only time we should get here is for nil interfaces due to\n\t\t// unpackValue calls.\n\t\tif v.IsNil() {\n\t\t\tf.fs.Write(nilAngleBytes)\n\t\t}\n\n\tcase reflect.Ptr:\n\t\t// Do nothing.  We should never get here since pointers have already\n\t\t// been handled above.\n\n\tcase reflect.Map:\n\t\t// nil maps should be indicated as different than empty maps\n\t\tif v.IsNil() {\n\t\t\tf.fs.Write(nilAngleBytes)\n\t\t\tbreak\n\t\t}\n\n\t\tf.fs.Write(openMapBytes)\n\t\tf.depth++\n\t\tif (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {\n\t\t\tf.fs.Write(maxShortBytes)\n\t\t} else {\n\t\t\tkeys := v.MapKeys()\n\t\t\tif f.cs.SortKeys {\n\t\t\t\tsortValues(keys, f.cs)\n\t\t\t}\n\t\t\tfor i, key := range keys {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tf.fs.Write(spaceBytes)\n\t\t\t\t}\n\t\t\t\tf.ignoreNextType = true\n\t\t\t\tf.format(f.unpackValue(key))\n\t\t\t\tf.fs.Write(colonBytes)\n\t\t\t\tf.ignoreNextType = true\n\t\t\t\tf.format(f.unpackValue(v.MapIndex(key)))\n\t\t\t}\n\t\t}\n\t\tf.depth--\n\t\tf.fs.Write(closeMapBytes)\n\n\tcase reflect.Struct:\n\t\tnumFields := v.NumField()\n\t\tf.fs.Write(openBraceBytes)\n\t\tf.depth++\n\t\tif (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {\n\t\t\tf.fs.Write(maxShortBytes)\n\t\t} else {\n\t\t\tvt := v.Type()\n\t\t\tfor i := 0; i < numFields; i++ {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tf.fs.Write(spaceBytes)\n\t\t\t\t}\n\t\t\t\tvtf := vt.Field(i)\n\t\t\t\tif f.fs.Flag('+') || f.fs.Flag('#') {\n\t\t\t\t\tf.fs.Write([]byte(vtf.Name))\n\t\t\t\t\tf.fs.Write(colonBytes)\n\t\t\t\t}\n\t\t\t\tf.format(f.unpackValue(v.Field(i)))\n\t\t\t}\n\t\t}\n\t\tf.depth--\n\t\tf.fs.Write(closeBraceBytes)\n\n\tcase reflect.Uintptr:\n\t\tprintHexPtr(f.fs, uintptr(v.Uint()))\n\n\tcase reflect.UnsafePointer, reflect.Chan, reflect.Func:\n\t\tprintHexPtr(f.fs, v.Pointer())\n\n\t// There were not any other types at the time this code was written, but\n\t// fall back to letting the default fmt package handle it if any get added.\n\tdefault:\n\t\tformat := f.buildDefaultFormat()\n\t\tif v.CanInterface() {\n\t\t\tfmt.Fprintf(f.fs, format, v.Interface())\n\t\t} else {\n\t\t\tfmt.Fprintf(f.fs, format, v.String())\n\t\t}\n\t}\n}\n\n// Format satisfies the fmt.Formatter interface. See NewFormatter for usage\n// details.\nfunc (f *formatState) Format(fs fmt.State, verb rune) {\n\tf.fs = fs\n\n\t// Use standard formatting for verbs that are not v.\n\tif verb != 'v' {\n\t\tformat := f.constructOrigFormat(verb)\n\t\tfmt.Fprintf(fs, format, f.value)\n\t\treturn\n\t}\n\n\tif f.value == nil {\n\t\tif fs.Flag('#') {\n\t\t\tfs.Write(interfaceBytes)\n\t\t}\n\t\tfs.Write(nilAngleBytes)\n\t\treturn\n\t}\n\n\tf.format(reflect.ValueOf(f.value))\n}\n\n// newFormatter is a helper function to consolidate the logic from the various\n// public methods which take varying config states.\nfunc newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {\n\tfs := &formatState{value: v, cs: cs}\n\tfs.pointers = make(map[uintptr]int)\n\treturn fs\n}\n\n/*\nNewFormatter returns a custom formatter that satisfies the fmt.Formatter\ninterface.  As a result, it integrates cleanly with standard fmt package\nprinting functions.  The formatter is useful for inline printing of smaller data\ntypes similar to the standard %v format specifier.\n\nThe custom formatter only responds to the %v (most compact), %+v (adds pointer\naddresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb\ncombinations.  Any other verbs such as %x and %q will be sent to the the\nstandard fmt package for formatting.  In addition, the custom formatter ignores\nthe width and precision arguments (however they will still work on the format\nspecifiers not handled by the custom formatter).\n\nTypically this function shouldn't be called directly.  It is much easier to make\nuse of the custom formatter by calling one of the convenience functions such as\nPrintf, Println, or Fprintf.\n*/\nfunc NewFormatter(v interface{}) fmt.Formatter {\n\treturn newFormatter(&Config, v)\n}\n"
  },
  {
    "path": "vendor/github.com/davecgh/go-spew/spew/spew.go",
    "content": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\npackage spew\n\nimport (\n\t\"fmt\"\n\t\"io\"\n)\n\n// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the formatted string as a value that satisfies error.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Errorf(format string, a ...interface{}) (err error) {\n\treturn fmt.Errorf(format, convertArgs(a)...)\n}\n\n// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Fprint(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprint(w, convertArgs(a)...)\n}\n\n// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintf(w, format, convertArgs(a)...)\n}\n\n// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it\n// passed with a default Formatter interface returned by NewFormatter.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Fprintln(w io.Writer, a ...interface{}) (n int, err error) {\n\treturn fmt.Fprintln(w, convertArgs(a)...)\n}\n\n// Print is a wrapper for fmt.Print that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Print(a ...interface{}) (n int, err error) {\n\treturn fmt.Print(convertArgs(a)...)\n}\n\n// Printf is a wrapper for fmt.Printf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Printf(format string, a ...interface{}) (n int, err error) {\n\treturn fmt.Printf(format, convertArgs(a)...)\n}\n\n// Println is a wrapper for fmt.Println that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the number of bytes written and any write error encountered.  See\n// NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Println(a ...interface{}) (n int, err error) {\n\treturn fmt.Println(convertArgs(a)...)\n}\n\n// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Sprint(a ...interface{}) string {\n\treturn fmt.Sprint(convertArgs(a)...)\n}\n\n// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were\n// passed with a default Formatter interface returned by NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Sprintf(format string, a ...interface{}) string {\n\treturn fmt.Sprintf(format, convertArgs(a)...)\n}\n\n// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it\n// were passed with a default Formatter interface returned by NewFormatter.  It\n// returns the resulting string.  See NewFormatter for formatting details.\n//\n// This function is shorthand for the following syntax:\n//\n//\tfmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))\nfunc Sprintln(a ...interface{}) string {\n\treturn fmt.Sprintln(convertArgs(a)...)\n}\n\n// convertArgs accepts a slice of arguments and returns a slice of the same\n// length with each argument converted to a default spew Formatter interface.\nfunc convertArgs(args []interface{}) (formatters []interface{}) {\n\tformatters = make([]interface{}, len(args))\n\tfor index, arg := range args {\n\t\tformatters[index] = NewFormatter(arg)\n\t}\n\treturn formatters\n}\n"
  },
  {
    "path": "vendor/github.com/dgryski/go-rendezvous/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017-2020 Damian Gryski <damian@gryski.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/dgryski/go-rendezvous/rdv.go",
    "content": "package rendezvous\n\ntype Rendezvous struct {\n\tnodes map[string]int\n\tnstr  []string\n\tnhash []uint64\n\thash  Hasher\n}\n\ntype Hasher func(s string) uint64\n\nfunc New(nodes []string, hash Hasher) *Rendezvous {\n\tr := &Rendezvous{\n\t\tnodes: make(map[string]int, len(nodes)),\n\t\tnstr:  make([]string, len(nodes)),\n\t\tnhash: make([]uint64, len(nodes)),\n\t\thash:  hash,\n\t}\n\n\tfor i, n := range nodes {\n\t\tr.nodes[n] = i\n\t\tr.nstr[i] = n\n\t\tr.nhash[i] = hash(n)\n\t}\n\n\treturn r\n}\n\nfunc (r *Rendezvous) Lookup(k string) string {\n\t// short-circuit if we're empty\n\tif len(r.nodes) == 0 {\n\t\treturn \"\"\n\t}\n\n\tkhash := r.hash(k)\n\n\tvar midx int\n\tvar mhash = xorshiftMult64(khash ^ r.nhash[0])\n\n\tfor i, nhash := range r.nhash[1:] {\n\t\tif h := xorshiftMult64(khash ^ nhash); h > mhash {\n\t\t\tmidx = i + 1\n\t\t\tmhash = h\n\t\t}\n\t}\n\n\treturn r.nstr[midx]\n}\n\nfunc (r *Rendezvous) Add(node string) {\n\tr.nodes[node] = len(r.nstr)\n\tr.nstr = append(r.nstr, node)\n\tr.nhash = append(r.nhash, r.hash(node))\n}\n\nfunc (r *Rendezvous) Remove(node string) {\n\t// find index of node to remove\n\tnidx := r.nodes[node]\n\n\t// remove from the slices\n\tl := len(r.nstr)\n\tr.nstr[nidx] = r.nstr[l]\n\tr.nstr = r.nstr[:l]\n\n\tr.nhash[nidx] = r.nhash[l]\n\tr.nhash = r.nhash[:l]\n\n\t// update the map\n\tdelete(r.nodes, node)\n\tmoved := r.nstr[nidx]\n\tr.nodes[moved] = nidx\n}\n\nfunc xorshiftMult64(x uint64) uint64 {\n\tx ^= x >> 12 // a\n\tx ^= x << 25 // b\n\tx ^= x >> 27 // c\n\treturn x * 2685821657736338717\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/ATTRIB",
    "content": "============\nThese pieces of code were ported from dotnet/corefx:\n\nsyntax/charclass.go (from RegexCharClass.cs): ported to use the built-in Go unicode classes.  Canonicalize is \n    a direct port, but most of the other code required large changes because the C# implementation \n    used a string to represent the CharSet data structure and I cleaned that up in my implementation.\n\nsyntax/code.go (from RegexCode.cs): ported literally with various cleanups and layout to make it more Go-ish.\n\nsyntax/escape.go (from RegexParser.cs): ported Escape method and added some optimizations.  Unescape is inspired by \n    the C# implementation but couldn't be directly ported because of the lack of do-while syntax in Go.\n\nsyntax/parser.go (from RegexpParser.cs and RegexOptions.cs): ported parser struct and associated methods as \n    literally as possible. Several language differences required changes.  E.g. lack pre/post-fix increments as \n    expressions, lack of do-while loops, lack of overloads, etc.\n\nsyntax/prefix.go (from RegexFCD.cs and RegexBoyerMoore.cs): ported as literally as possible and added support\n    for unicode chars that are longer than the 16-bit char in C# for the 32-bit rune in Go.\n\nsyntax/replacerdata.go (from RegexReplacement.cs): conceptually ported and re-organized to handle differences \n    in charclass implementation, and fix odd code layout between RegexParser.cs, Regex.cs, and RegexReplacement.cs.\n\nsyntax/tree.go (from RegexTree.cs and RegexNode.cs): ported literally as possible.\n\nsyntax/writer.go (from RegexWriter.cs): ported literally with minor changes to make it more Go-ish.\n\nmatch.go (from RegexMatch.cs): ported, simplified, and changed to handle Go's lack of inheritence.\n\nregexp.go (from Regex.cs and RegexOptions.cs): conceptually serves the same \"starting point\", but is simplified \n    and changed to handle differences in C# strings and Go strings/runes.  \n\nreplace.go (from RegexReplacement.cs): ported closely and then cleaned up to combine the MatchEvaluator and \n    simple string replace implementations.\n\nrunner.go (from RegexRunner.cs): ported literally as possible.\n\nregexp_test.go (from CaptureTests.cs and GroupNamesAndNumbers.cs): conceptually ported, but the code was \n    manually structured like Go tests.\n\nreplace_test.go (from RegexReplaceStringTest0.cs): conceptually ported\n\nrtl_test.go (from RightToLeft.cs): conceptually ported\n---\ndotnet/corefx was released under this license:\n\nThe MIT License (MIT)\n\nCopyright (c) Microsoft Corporation\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n============\nThese pieces of code are copied from the Go framework:\n\n- The overall directory structure of regexp2 was inspired by the Go runtime regexp package.\n- The optimization in the escape method of syntax/escape.go is from the Go runtime QuoteMeta() func in regexp/regexp.go\n- The method signatures in regexp.go are designed to match the Go framework regexp methods closely\n- func regexp2.MustCompile and func quote are almost identifical to the regexp package versions\n- BenchmarkMatch* and TestProgramTooLong* funcs in regexp_performance_test.go were copied from the framework \n    regexp/exec_test.go\n---\nThe Go framework was released under this license:\n\nCopyright (c) 2012 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n   * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n   * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n============\nSome test data were gathered from the Mono project.\n\nregexp_mono_test.go: ported from https://github.com/mono/mono/blob/master/mcs/class/System/Test/System.Text.RegularExpressions/PerlTrials.cs\n---\nMono tests released under this license:\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) Doug Clark\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/fastclock.go",
    "content": "package regexp2\n\nimport (\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\n// fasttime holds a time value (ticks since clock initialization)\ntype fasttime int64\n\n// fastclock provides a fast clock implementation.\n//\n// A background goroutine periodically stores the current time\n// into an atomic variable.\n//\n// A deadline can be quickly checked for expiration by comparing\n// its value to the clock stored in the atomic variable.\n//\n// The goroutine automatically stops once clockEnd is reached.\n// (clockEnd covers the largest deadline seen so far + some\n// extra time). This ensures that if regexp2 with timeouts\n// stops being used we will stop background work.\ntype fastclock struct {\n\t// instances of atomicTime must be at the start of the struct (or at least 64-bit aligned)\n\t// otherwise 32-bit architectures will panic\n\n\tcurrent  atomicTime // Current time (approximate)\n\tclockEnd atomicTime // When clock updater is supposed to stop (>= any existing deadline)\n\n\t// current and clockEnd can be read via atomic loads.\n\t// Reads and writes of other fields require mu to be held.\n\tmu      sync.Mutex\n\tstart   time.Time // Time corresponding to fasttime(0)\n\trunning bool      // Is a clock updater running?\n}\n\nvar fast fastclock\n\n// reached returns true if current time is at or past t.\nfunc (t fasttime) reached() bool {\n\treturn fast.current.read() >= t\n}\n\n// makeDeadline returns a time that is approximately time.Now().Add(d)\nfunc makeDeadline(d time.Duration) fasttime {\n\t// Increase the deadline since the clock we are reading may be\n\t// just about to tick forwards.\n\tend := fast.current.read() + durationToTicks(d+clockPeriod)\n\n\t// Start or extend clock if necessary.\n\tif end > fast.clockEnd.read() {\n\t\t// If time.Since(last use) > timeout, there's a chance that\n\t\t// fast.current will no longer be updated, which can lead to\n\t\t// incorrect 'end' calculations that can trigger a false timeout\n\t\tfast.mu.Lock()\n\t\tif !fast.running && !fast.start.IsZero() {\n\t\t\t// update fast.current\n\t\t\tfast.current.write(durationToTicks(time.Since(fast.start)))\n\t\t\t// recalculate our end value\n\t\t\tend = fast.current.read() + durationToTicks(d+clockPeriod)\n\t\t}\n\t\tfast.mu.Unlock()\n\t\textendClock(end)\n\t}\n\n\treturn end\n}\n\n// extendClock ensures that clock is live and will run until at least end.\nfunc extendClock(end fasttime) {\n\tfast.mu.Lock()\n\tdefer fast.mu.Unlock()\n\n\tif fast.start.IsZero() {\n\t\tfast.start = time.Now()\n\t}\n\n\t// Extend the running time to cover end as well as a bit of slop.\n\tif shutdown := end + durationToTicks(time.Second); shutdown > fast.clockEnd.read() {\n\t\tfast.clockEnd.write(shutdown)\n\t}\n\n\t// Start clock if necessary\n\tif !fast.running {\n\t\tfast.running = true\n\t\tgo runClock()\n\t}\n}\n\n// stop the timeout clock in the background\n// should only used for unit tests to abandon the background goroutine\nfunc stopClock() {\n\tfast.mu.Lock()\n\tif fast.running {\n\t\tfast.clockEnd.write(fasttime(0))\n\t}\n\tfast.mu.Unlock()\n\n\t// pause until not running\n\t// get and release the lock\n\tisRunning := true\n\tfor isRunning {\n\t\ttime.Sleep(clockPeriod / 2)\n\t\tfast.mu.Lock()\n\t\tisRunning = fast.running\n\t\tfast.mu.Unlock()\n\t}\n}\n\nfunc durationToTicks(d time.Duration) fasttime {\n\t// Downscale nanoseconds to approximately a millisecond so that we can avoid\n\t// overflow even if the caller passes in math.MaxInt64.\n\treturn fasttime(d) >> 20\n}\n\nconst DefaultClockPeriod = 100 * time.Millisecond\n\n// clockPeriod is the approximate interval between updates of approximateClock.\nvar clockPeriod = DefaultClockPeriod\n\nfunc runClock() {\n\tfast.mu.Lock()\n\tdefer fast.mu.Unlock()\n\n\tfor fast.current.read() <= fast.clockEnd.read() {\n\t\t// Unlock while sleeping.\n\t\tfast.mu.Unlock()\n\t\ttime.Sleep(clockPeriod)\n\t\tfast.mu.Lock()\n\n\t\tnewTime := durationToTicks(time.Since(fast.start))\n\t\tfast.current.write(newTime)\n\t}\n\tfast.running = false\n}\n\ntype atomicTime struct{ v int64 } // Should change to atomic.Int64 when we can use go 1.19\n\nfunc (t *atomicTime) read() fasttime   { return fasttime(atomic.LoadInt64(&t.v)) }\nfunc (t *atomicTime) write(v fasttime) { atomic.StoreInt64(&t.v, int64(v)) }\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/match.go",
    "content": "package regexp2\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n)\n\n// Match is a single regex result match that contains groups and repeated captures\n//\n//\t\t-Groups\n//\t   -Capture\ntype Match struct {\n\tGroup //embeded group 0\n\n\tregex       *Regexp\n\totherGroups []Group\n\n\t// input to the match\n\ttextpos   int\n\ttextstart int\n\n\tcapcount   int\n\tcaps       []int\n\tsparseCaps map[int]int\n\n\t// output from the match\n\tmatches    [][]int\n\tmatchcount []int\n\n\t// whether we've done any balancing with this match.  If we\n\t// have done balancing, we'll need to do extra work in Tidy().\n\tbalancing bool\n}\n\n// Group is an explicit or implit (group 0) matched group within the pattern\ntype Group struct {\n\tCapture // the last capture of this group is embeded for ease of use\n\n\tName     string    // group name\n\tCaptures []Capture // captures of this group\n}\n\n// Capture is a single capture of text within the larger original string\ntype Capture struct {\n\t// the original string\n\ttext []rune\n\t// Index is the position in the underlying rune slice where the first character of\n\t// captured substring was found. Even if you pass in a string this will be in Runes.\n\tIndex int\n\t// Length is the number of runes in the captured substring.\n\tLength int\n}\n\n// String returns the captured text as a String\nfunc (c *Capture) String() string {\n\treturn string(c.text[c.Index : c.Index+c.Length])\n}\n\n// Runes returns the captured text as a rune slice\nfunc (c *Capture) Runes() []rune {\n\treturn c.text[c.Index : c.Index+c.Length]\n}\n\nfunc newMatch(regex *Regexp, capcount int, text []rune, startpos int) *Match {\n\tm := Match{\n\t\tregex:      regex,\n\t\tmatchcount: make([]int, capcount),\n\t\tmatches:    make([][]int, capcount),\n\t\ttextstart:  startpos,\n\t\tbalancing:  false,\n\t}\n\tm.Name = \"0\"\n\tm.text = text\n\tm.matches[0] = make([]int, 2)\n\treturn &m\n}\n\nfunc newMatchSparse(regex *Regexp, caps map[int]int, capcount int, text []rune, startpos int) *Match {\n\tm := newMatch(regex, capcount, text, startpos)\n\tm.sparseCaps = caps\n\treturn m\n}\n\nfunc (m *Match) reset(text []rune, textstart int) {\n\tm.text = text\n\tm.textstart = textstart\n\tfor i := 0; i < len(m.matchcount); i++ {\n\t\tm.matchcount[i] = 0\n\t}\n\tm.balancing = false\n}\n\nfunc (m *Match) tidy(textpos int) {\n\n\tinterval := m.matches[0]\n\tm.Index = interval[0]\n\tm.Length = interval[1]\n\tm.textpos = textpos\n\tm.capcount = m.matchcount[0]\n\t//copy our root capture to the list\n\tm.Group.Captures = []Capture{m.Group.Capture}\n\n\tif m.balancing {\n\t\t// The idea here is that we want to compact all of our unbalanced captures.  To do that we\n\t\t// use j basically as a count of how many unbalanced captures we have at any given time\n\t\t// (really j is an index, but j/2 is the count).  First we skip past all of the real captures\n\t\t// until we find a balance captures.  Then we check each subsequent entry.  If it's a balance\n\t\t// capture (it's negative), we decrement j.  If it's a real capture, we increment j and copy\n\t\t// it down to the last free position.\n\t\tfor cap := 0; cap < len(m.matchcount); cap++ {\n\t\t\tlimit := m.matchcount[cap] * 2\n\t\t\tmatcharray := m.matches[cap]\n\n\t\t\tvar i, j int\n\n\t\t\tfor i = 0; i < limit; i++ {\n\t\t\t\tif matcharray[i] < 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor j = i; i < limit; i++ {\n\t\t\t\tif matcharray[i] < 0 {\n\t\t\t\t\t// skip negative values\n\t\t\t\t\tj--\n\t\t\t\t} else {\n\t\t\t\t\t// but if we find something positive (an actual capture), copy it back to the last\n\t\t\t\t\t// unbalanced position.\n\t\t\t\t\tif i != j {\n\t\t\t\t\t\tmatcharray[j] = matcharray[i]\n\t\t\t\t\t}\n\t\t\t\t\tj++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tm.matchcount[cap] = j / 2\n\t\t}\n\n\t\tm.balancing = false\n\t}\n}\n\n// isMatched tells if a group was matched by capnum\nfunc (m *Match) isMatched(cap int) bool {\n\treturn cap < len(m.matchcount) && m.matchcount[cap] > 0 && m.matches[cap][m.matchcount[cap]*2-1] != (-3+1)\n}\n\n// matchIndex returns the index of the last specified matched group by capnum\nfunc (m *Match) matchIndex(cap int) int {\n\ti := m.matches[cap][m.matchcount[cap]*2-2]\n\tif i >= 0 {\n\t\treturn i\n\t}\n\n\treturn m.matches[cap][-3-i]\n}\n\n// matchLength returns the length of the last specified matched group by capnum\nfunc (m *Match) matchLength(cap int) int {\n\ti := m.matches[cap][m.matchcount[cap]*2-1]\n\tif i >= 0 {\n\t\treturn i\n\t}\n\n\treturn m.matches[cap][-3-i]\n}\n\n// Nonpublic builder: add a capture to the group specified by \"c\"\nfunc (m *Match) addMatch(c, start, l int) {\n\n\tif m.matches[c] == nil {\n\t\tm.matches[c] = make([]int, 2)\n\t}\n\n\tcapcount := m.matchcount[c]\n\n\tif capcount*2+2 > len(m.matches[c]) {\n\t\toldmatches := m.matches[c]\n\t\tnewmatches := make([]int, capcount*8)\n\t\tcopy(newmatches, oldmatches[:capcount*2])\n\t\tm.matches[c] = newmatches\n\t}\n\n\tm.matches[c][capcount*2] = start\n\tm.matches[c][capcount*2+1] = l\n\tm.matchcount[c] = capcount + 1\n\t//log.Printf(\"addMatch: c=%v, i=%v, l=%v ... matches: %v\", c, start, l, m.matches)\n}\n\n// Nonpublic builder: Add a capture to balance the specified group.  This is used by the\n//\n//\tbalanced match construct. (?<foo-foo2>...)\n//\n// If there were no such thing as backtracking, this would be as simple as calling RemoveMatch(c).\n// However, since we have backtracking, we need to keep track of everything.\nfunc (m *Match) balanceMatch(c int) {\n\tm.balancing = true\n\n\t// we'll look at the last capture first\n\tcapcount := m.matchcount[c]\n\ttarget := capcount*2 - 2\n\n\t// first see if it is negative, and therefore is a reference to the next available\n\t// capture group for balancing.  If it is, we'll reset target to point to that capture.\n\tif m.matches[c][target] < 0 {\n\t\ttarget = -3 - m.matches[c][target]\n\t}\n\n\t// move back to the previous capture\n\ttarget -= 2\n\n\t// if the previous capture is a reference, just copy that reference to the end.  Otherwise, point to it.\n\tif target >= 0 && m.matches[c][target] < 0 {\n\t\tm.addMatch(c, m.matches[c][target], m.matches[c][target+1])\n\t} else {\n\t\tm.addMatch(c, -3-target, -4-target /* == -3 - (target + 1) */)\n\t}\n}\n\n// Nonpublic builder: removes a group match by capnum\nfunc (m *Match) removeMatch(c int) {\n\tm.matchcount[c]--\n}\n\n// GroupCount returns the number of groups this match has matched\nfunc (m *Match) GroupCount() int {\n\treturn len(m.matchcount)\n}\n\n// GroupByName returns a group based on the name of the group, or nil if the group name does not exist\nfunc (m *Match) GroupByName(name string) *Group {\n\tnum := m.regex.GroupNumberFromName(name)\n\tif num < 0 {\n\t\treturn nil\n\t}\n\treturn m.GroupByNumber(num)\n}\n\n// GroupByNumber returns a group based on the number of the group, or nil if the group number does not exist\nfunc (m *Match) GroupByNumber(num int) *Group {\n\t// check our sparse map\n\tif m.sparseCaps != nil {\n\t\tif newNum, ok := m.sparseCaps[num]; ok {\n\t\t\tnum = newNum\n\t\t}\n\t}\n\tif num >= len(m.matchcount) || num < 0 {\n\t\treturn nil\n\t}\n\n\tif num == 0 {\n\t\treturn &m.Group\n\t}\n\n\tm.populateOtherGroups()\n\n\treturn &m.otherGroups[num-1]\n}\n\n// Groups returns all the capture groups, starting with group 0 (the full match)\nfunc (m *Match) Groups() []Group {\n\tm.populateOtherGroups()\n\tg := make([]Group, len(m.otherGroups)+1)\n\tg[0] = m.Group\n\tcopy(g[1:], m.otherGroups)\n\treturn g\n}\n\nfunc (m *Match) populateOtherGroups() {\n\t// Construct all the Group objects first time called\n\tif m.otherGroups == nil {\n\t\tm.otherGroups = make([]Group, len(m.matchcount)-1)\n\t\tfor i := 0; i < len(m.otherGroups); i++ {\n\t\t\tm.otherGroups[i] = newGroup(m.regex.GroupNameFromNumber(i+1), m.text, m.matches[i+1], m.matchcount[i+1])\n\t\t}\n\t}\n}\n\nfunc (m *Match) groupValueAppendToBuf(groupnum int, buf *bytes.Buffer) {\n\tc := m.matchcount[groupnum]\n\tif c == 0 {\n\t\treturn\n\t}\n\n\tmatches := m.matches[groupnum]\n\n\tindex := matches[(c-1)*2]\n\tlast := index + matches[(c*2)-1]\n\n\tfor ; index < last; index++ {\n\t\tbuf.WriteRune(m.text[index])\n\t}\n}\n\nfunc newGroup(name string, text []rune, caps []int, capcount int) Group {\n\tg := Group{}\n\tg.text = text\n\tif capcount > 0 {\n\t\tg.Index = caps[(capcount-1)*2]\n\t\tg.Length = caps[(capcount*2)-1]\n\t}\n\tg.Name = name\n\tg.Captures = make([]Capture, capcount)\n\tfor i := 0; i < capcount; i++ {\n\t\tg.Captures[i] = Capture{\n\t\t\ttext:   text,\n\t\t\tIndex:  caps[i*2],\n\t\t\tLength: caps[i*2+1],\n\t\t}\n\t}\n\t//log.Printf(\"newGroup! capcount %v, %+v\", capcount, g)\n\n\treturn g\n}\n\nfunc (m *Match) dump() string {\n\tbuf := &bytes.Buffer{}\n\tbuf.WriteRune('\\n')\n\tif len(m.sparseCaps) > 0 {\n\t\tfor k, v := range m.sparseCaps {\n\t\t\tfmt.Fprintf(buf, \"Slot %v -> %v\\n\", k, v)\n\t\t}\n\t}\n\n\tfor i, g := range m.Groups() {\n\t\tfmt.Fprintf(buf, \"Group %v (%v), %v caps:\\n\", i, g.Name, len(g.Captures))\n\n\t\tfor _, c := range g.Captures {\n\t\t\tfmt.Fprintf(buf, \"  (%v, %v) %v\\n\", c.Index, c.Length, c.String())\n\t\t}\n\t}\n\t/*\n\t\tfor i := 0; i < len(m.matchcount); i++ {\n\t\t\tfmt.Fprintf(buf, \"\\nGroup %v (%v):\\n\", i, m.regex.GroupNameFromNumber(i))\n\n\t\t\tfor j := 0; j < m.matchcount[i]; j++ {\n\t\t\t\ttext := \"\"\n\n\t\t\t\tif m.matches[i][j*2] >= 0 {\n\t\t\t\t\tstart := m.matches[i][j*2]\n\t\t\t\t\ttext = m.text[start : start+m.matches[i][j*2+1]]\n\t\t\t\t}\n\n\t\t\t\tfmt.Fprintf(buf, \"  (%v, %v) %v\\n\", m.matches[i][j*2], m.matches[i][j*2+1], text)\n\t\t\t}\n\t\t}\n\t*/\n\treturn buf.String()\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/regexp.go",
    "content": "/*\nPackage regexp2 is a regexp package that has an interface similar to Go's framework regexp engine but uses a\nmore feature full regex engine behind the scenes.\n\nIt doesn't have constant time guarantees, but it allows backtracking and is compatible with Perl5 and .NET.\nYou'll likely be better off with the RE2 engine from the regexp package and should only use this if you\nneed to write very complex patterns or require compatibility with .NET.\n*/\npackage regexp2\n\nimport (\n\t\"errors\"\n\t\"math\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/dlclark/regexp2/syntax\"\n)\n\nvar (\n\t// DefaultMatchTimeout used when running regexp matches -- \"forever\"\n\tDefaultMatchTimeout = time.Duration(math.MaxInt64)\n\t// DefaultUnmarshalOptions used when unmarshaling a regex from text\n\tDefaultUnmarshalOptions = None\n)\n\n// Regexp is the representation of a compiled regular expression.\n// A Regexp is safe for concurrent use by multiple goroutines.\ntype Regexp struct {\n\t// A match will time out if it takes (approximately) more than\n\t// MatchTimeout. This is a safety check in case the match\n\t// encounters catastrophic backtracking.  The default value\n\t// (DefaultMatchTimeout) causes all time out checking to be\n\t// suppressed.\n\tMatchTimeout time.Duration\n\n\t// read-only after Compile\n\tpattern string       // as passed to Compile\n\toptions RegexOptions // options\n\n\tcaps     map[int]int    // capnum->index\n\tcapnames map[string]int //capture group name -> index\n\tcapslist []string       //sorted list of capture group names\n\tcapsize  int            // size of the capture array\n\n\tcode *syntax.Code // compiled program\n\n\t// cache of machines for running regexp\n\tmuRun  *sync.Mutex\n\trunner []*runner\n}\n\n// Compile parses a regular expression and returns, if successful,\n// a Regexp object that can be used to match against text.\nfunc Compile(expr string, opt RegexOptions) (*Regexp, error) {\n\t// parse it\n\ttree, err := syntax.Parse(expr, syntax.RegexOptions(opt))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// translate it to code\n\tcode, err := syntax.Write(tree)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// return it\n\treturn &Regexp{\n\t\tpattern:      expr,\n\t\toptions:      opt,\n\t\tcaps:         code.Caps,\n\t\tcapnames:     tree.Capnames,\n\t\tcapslist:     tree.Caplist,\n\t\tcapsize:      code.Capsize,\n\t\tcode:         code,\n\t\tMatchTimeout: DefaultMatchTimeout,\n\t\tmuRun:        &sync.Mutex{},\n\t}, nil\n}\n\n// MustCompile is like Compile but panics if the expression cannot be parsed.\n// It simplifies safe initialization of global variables holding compiled regular\n// expressions.\nfunc MustCompile(str string, opt RegexOptions) *Regexp {\n\tregexp, error := Compile(str, opt)\n\tif error != nil {\n\t\tpanic(`regexp2: Compile(` + quote(str) + `): ` + error.Error())\n\t}\n\treturn regexp\n}\n\n// Escape adds backslashes to any special characters in the input string\nfunc Escape(input string) string {\n\treturn syntax.Escape(input)\n}\n\n// Unescape removes any backslashes from previously-escaped special characters in the input string\nfunc Unescape(input string) (string, error) {\n\treturn syntax.Unescape(input)\n}\n\n// SetTimeoutPeriod is a debug function that sets the frequency of the timeout goroutine's sleep cycle.\n// Defaults to 100ms. The only benefit of setting this lower is that the 1 background goroutine that manages\n// timeouts may exit slightly sooner after all the timeouts have expired. See Github issue #63\nfunc SetTimeoutCheckPeriod(d time.Duration) {\n\tclockPeriod = d\n}\n\n// StopTimeoutClock should only be used in unit tests to prevent the timeout clock goroutine\n// from appearing like a leaking goroutine\nfunc StopTimeoutClock() {\n\tstopClock()\n}\n\n// String returns the source text used to compile the regular expression.\nfunc (re *Regexp) String() string {\n\treturn re.pattern\n}\n\nfunc quote(s string) string {\n\tif strconv.CanBackquote(s) {\n\t\treturn \"`\" + s + \"`\"\n\t}\n\treturn strconv.Quote(s)\n}\n\n// RegexOptions impact the runtime and parsing behavior\n// for each specific regex.  They are setable in code as well\n// as in the regex pattern itself.\ntype RegexOptions int32\n\nconst (\n\tNone                    RegexOptions = 0x0\n\tIgnoreCase                           = 0x0001 // \"i\"\n\tMultiline                            = 0x0002 // \"m\"\n\tExplicitCapture                      = 0x0004 // \"n\"\n\tCompiled                             = 0x0008 // \"c\"\n\tSingleline                           = 0x0010 // \"s\"\n\tIgnorePatternWhitespace              = 0x0020 // \"x\"\n\tRightToLeft                          = 0x0040 // \"r\"\n\tDebug                                = 0x0080 // \"d\"\n\tECMAScript                           = 0x0100 // \"e\"\n\tRE2                                  = 0x0200 // RE2 (regexp package) compatibility mode\n\tUnicode                              = 0x0400 // \"u\"\n)\n\nfunc (re *Regexp) RightToLeft() bool {\n\treturn re.options&RightToLeft != 0\n}\n\nfunc (re *Regexp) Debug() bool {\n\treturn re.options&Debug != 0\n}\n\n// Replace searches the input string and replaces each match found with the replacement text.\n// Count will limit the number of matches attempted and startAt will allow\n// us to skip past possible matches at the start of the input (left or right depending on RightToLeft option).\n// Set startAt and count to -1 to go through the whole string\nfunc (re *Regexp) Replace(input, replacement string, startAt, count int) (string, error) {\n\tdata, err := syntax.NewReplacerData(replacement, re.caps, re.capsize, re.capnames, syntax.RegexOptions(re.options))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t//TODO: cache ReplacerData\n\n\treturn replace(re, data, nil, input, startAt, count)\n}\n\n// ReplaceFunc searches the input string and replaces each match found using the string from the evaluator\n// Count will limit the number of matches attempted and startAt will allow\n// us to skip past possible matches at the start of the input (left or right depending on RightToLeft option).\n// Set startAt and count to -1 to go through the whole string.\nfunc (re *Regexp) ReplaceFunc(input string, evaluator MatchEvaluator, startAt, count int) (string, error) {\n\treturn replace(re, nil, evaluator, input, startAt, count)\n}\n\n// FindStringMatch searches the input string for a Regexp match\nfunc (re *Regexp) FindStringMatch(s string) (*Match, error) {\n\t// convert string to runes\n\treturn re.run(false, -1, getRunes(s))\n}\n\n// FindRunesMatch searches the input rune slice for a Regexp match\nfunc (re *Regexp) FindRunesMatch(r []rune) (*Match, error) {\n\treturn re.run(false, -1, r)\n}\n\n// FindStringMatchStartingAt searches the input string for a Regexp match starting at the startAt index\nfunc (re *Regexp) FindStringMatchStartingAt(s string, startAt int) (*Match, error) {\n\tif startAt > len(s) {\n\t\treturn nil, errors.New(\"startAt must be less than the length of the input string\")\n\t}\n\tr, startAt := re.getRunesAndStart(s, startAt)\n\tif startAt == -1 {\n\t\t// we didn't find our start index in the string -- that's a problem\n\t\treturn nil, errors.New(\"startAt must align to the start of a valid rune in the input string\")\n\t}\n\n\treturn re.run(false, startAt, r)\n}\n\n// FindRunesMatchStartingAt searches the input rune slice for a Regexp match starting at the startAt index\nfunc (re *Regexp) FindRunesMatchStartingAt(r []rune, startAt int) (*Match, error) {\n\treturn re.run(false, startAt, r)\n}\n\n// FindNextMatch returns the next match in the same input string as the match parameter.\n// Will return nil if there is no next match or if given a nil match.\nfunc (re *Regexp) FindNextMatch(m *Match) (*Match, error) {\n\tif m == nil {\n\t\treturn nil, nil\n\t}\n\n\t// If previous match was empty, advance by one before matching to prevent\n\t// infinite loop\n\tstartAt := m.textpos\n\tif m.Length == 0 {\n\t\tif m.textpos == len(m.text) {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tif re.RightToLeft() {\n\t\t\tstartAt--\n\t\t} else {\n\t\t\tstartAt++\n\t\t}\n\t}\n\treturn re.run(false, startAt, m.text)\n}\n\n// MatchString return true if the string matches the regex\n// error will be set if a timeout occurs\nfunc (re *Regexp) MatchString(s string) (bool, error) {\n\tm, err := re.run(true, -1, getRunes(s))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn m != nil, nil\n}\n\nfunc (re *Regexp) getRunesAndStart(s string, startAt int) ([]rune, int) {\n\tif startAt < 0 {\n\t\tif re.RightToLeft() {\n\t\t\tr := getRunes(s)\n\t\t\treturn r, len(r)\n\t\t}\n\t\treturn getRunes(s), 0\n\t}\n\tret := make([]rune, len(s))\n\ti := 0\n\truneIdx := -1\n\tfor strIdx, r := range s {\n\t\tif strIdx == startAt {\n\t\t\truneIdx = i\n\t\t}\n\t\tret[i] = r\n\t\ti++\n\t}\n\tif startAt == len(s) {\n\t\truneIdx = i\n\t}\n\treturn ret[:i], runeIdx\n}\n\nfunc getRunes(s string) []rune {\n\treturn []rune(s)\n}\n\n// MatchRunes return true if the runes matches the regex\n// error will be set if a timeout occurs\nfunc (re *Regexp) MatchRunes(r []rune) (bool, error) {\n\tm, err := re.run(true, -1, r)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn m != nil, nil\n}\n\n// GetGroupNames Returns the set of strings used to name capturing groups in the expression.\nfunc (re *Regexp) GetGroupNames() []string {\n\tvar result []string\n\n\tif re.capslist == nil {\n\t\tresult = make([]string, re.capsize)\n\n\t\tfor i := 0; i < len(result); i++ {\n\t\t\tresult[i] = strconv.Itoa(i)\n\t\t}\n\t} else {\n\t\tresult = make([]string, len(re.capslist))\n\t\tcopy(result, re.capslist)\n\t}\n\n\treturn result\n}\n\n// GetGroupNumbers returns the integer group numbers corresponding to a group name.\nfunc (re *Regexp) GetGroupNumbers() []int {\n\tvar result []int\n\n\tif re.caps == nil {\n\t\tresult = make([]int, re.capsize)\n\n\t\tfor i := 0; i < len(result); i++ {\n\t\t\tresult[i] = i\n\t\t}\n\t} else {\n\t\tresult = make([]int, len(re.caps))\n\n\t\tfor k, v := range re.caps {\n\t\t\tresult[v] = k\n\t\t}\n\t}\n\n\treturn result\n}\n\n// GroupNameFromNumber retrieves a group name that corresponds to a group number.\n// It will return \"\" for and unknown group number.  Unnamed groups automatically\n// receive a name that is the decimal string equivalent of its number.\nfunc (re *Regexp) GroupNameFromNumber(i int) string {\n\tif re.capslist == nil {\n\t\tif i >= 0 && i < re.capsize {\n\t\t\treturn strconv.Itoa(i)\n\t\t}\n\n\t\treturn \"\"\n\t}\n\n\tif re.caps != nil {\n\t\tvar ok bool\n\t\tif i, ok = re.caps[i]; !ok {\n\t\t\treturn \"\"\n\t\t}\n\t}\n\n\tif i >= 0 && i < len(re.capslist) {\n\t\treturn re.capslist[i]\n\t}\n\n\treturn \"\"\n}\n\n// GroupNumberFromName returns a group number that corresponds to a group name.\n// Returns -1 if the name is not a recognized group name.  Numbered groups\n// automatically get a group name that is the decimal string equivalent of its number.\nfunc (re *Regexp) GroupNumberFromName(name string) int {\n\t// look up name if we have a hashtable of names\n\tif re.capnames != nil {\n\t\tif k, ok := re.capnames[name]; ok {\n\t\t\treturn k\n\t\t}\n\n\t\treturn -1\n\t}\n\n\t// convert to an int if it looks like a number\n\tresult := 0\n\tfor i := 0; i < len(name); i++ {\n\t\tch := name[i]\n\n\t\tif ch > '9' || ch < '0' {\n\t\t\treturn -1\n\t\t}\n\n\t\tresult *= 10\n\t\tresult += int(ch - '0')\n\t}\n\n\t// return int if it's in range\n\tif result >= 0 && result < re.capsize {\n\t\treturn result\n\t}\n\n\treturn -1\n}\n\n// MarshalText implements [encoding.TextMarshaler]. The output\n// matches that of calling the [Regexp.String] method.\nfunc (re *Regexp) MarshalText() ([]byte, error) {\n\treturn []byte(re.String()), nil\n}\n\n// UnmarshalText implements [encoding.TextUnmarshaler] by calling\n// [Compile] on the encoded value.\nfunc (re *Regexp) UnmarshalText(text []byte) error {\n\tnewRE, err := Compile(string(text), DefaultUnmarshalOptions)\n\tif err != nil {\n\t\treturn err\n\t}\n\t*re = *newRE\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/replace.go",
    "content": "package regexp2\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\n\t\"github.com/dlclark/regexp2/syntax\"\n)\n\nconst (\n\treplaceSpecials     = 4\n\treplaceLeftPortion  = -1\n\treplaceRightPortion = -2\n\treplaceLastGroup    = -3\n\treplaceWholeString  = -4\n)\n\n// MatchEvaluator is a function that takes a match and returns a replacement string to be used\ntype MatchEvaluator func(Match) string\n\n// Three very similar algorithms appear below: replace (pattern),\n// replace (evaluator), and split.\n\n// Replace Replaces all occurrences of the regex in the string with the\n// replacement pattern.\n//\n// Note that the special case of no matches is handled on its own:\n// with no matches, the input string is returned unchanged.\n// The right-to-left case is split out because StringBuilder\n// doesn't handle right-to-left string building directly very well.\nfunc replace(regex *Regexp, data *syntax.ReplacerData, evaluator MatchEvaluator, input string, startAt, count int) (string, error) {\n\tif count < -1 {\n\t\treturn \"\", errors.New(\"Count too small\")\n\t}\n\tif count == 0 {\n\t\treturn \"\", nil\n\t}\n\n\tm, err := regex.FindStringMatchStartingAt(input, startAt)\n\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif m == nil {\n\t\treturn input, nil\n\t}\n\n\tbuf := &bytes.Buffer{}\n\ttext := m.text\n\n\tif !regex.RightToLeft() {\n\t\tprevat := 0\n\t\tfor m != nil {\n\t\t\tif m.Index != prevat {\n\t\t\t\tbuf.WriteString(string(text[prevat:m.Index]))\n\t\t\t}\n\t\t\tprevat = m.Index + m.Length\n\t\t\tif evaluator == nil {\n\t\t\t\treplacementImpl(data, buf, m)\n\t\t\t} else {\n\t\t\t\tbuf.WriteString(evaluator(*m))\n\t\t\t}\n\n\t\t\tcount--\n\t\t\tif count == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tm, err = regex.FindNextMatch(m)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\t\t}\n\n\t\tif prevat < len(text) {\n\t\t\tbuf.WriteString(string(text[prevat:]))\n\t\t}\n\t} else {\n\t\tprevat := len(text)\n\t\tvar al []string\n\n\t\tfor m != nil {\n\t\t\tif m.Index+m.Length != prevat {\n\t\t\t\tal = append(al, string(text[m.Index+m.Length:prevat]))\n\t\t\t}\n\t\t\tprevat = m.Index\n\t\t\tif evaluator == nil {\n\t\t\t\treplacementImplRTL(data, &al, m)\n\t\t\t} else {\n\t\t\t\tal = append(al, evaluator(*m))\n\t\t\t}\n\n\t\t\tcount--\n\t\t\tif count == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tm, err = regex.FindNextMatch(m)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", nil\n\t\t\t}\n\t\t}\n\n\t\tif prevat > 0 {\n\t\t\tbuf.WriteString(string(text[:prevat]))\n\t\t}\n\n\t\tfor i := len(al) - 1; i >= 0; i-- {\n\t\t\tbuf.WriteString(al[i])\n\t\t}\n\t}\n\n\treturn buf.String(), nil\n}\n\n// Given a Match, emits into the StringBuilder the evaluated\n// substitution pattern.\nfunc replacementImpl(data *syntax.ReplacerData, buf *bytes.Buffer, m *Match) {\n\tfor _, r := range data.Rules {\n\n\t\tif r >= 0 { // string lookup\n\t\t\tbuf.WriteString(data.Strings[r])\n\t\t} else if r < -replaceSpecials { // group lookup\n\t\t\tm.groupValueAppendToBuf(-replaceSpecials-1-r, buf)\n\t\t} else {\n\t\t\tswitch -replaceSpecials - 1 - r { // special insertion patterns\n\t\t\tcase replaceLeftPortion:\n\t\t\t\tfor i := 0; i < m.Index; i++ {\n\t\t\t\t\tbuf.WriteRune(m.text[i])\n\t\t\t\t}\n\t\t\tcase replaceRightPortion:\n\t\t\t\tfor i := m.Index + m.Length; i < len(m.text); i++ {\n\t\t\t\t\tbuf.WriteRune(m.text[i])\n\t\t\t\t}\n\t\t\tcase replaceLastGroup:\n\t\t\t\tm.groupValueAppendToBuf(m.GroupCount()-1, buf)\n\t\t\tcase replaceWholeString:\n\t\t\t\tfor i := 0; i < len(m.text); i++ {\n\t\t\t\t\tbuf.WriteRune(m.text[i])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc replacementImplRTL(data *syntax.ReplacerData, al *[]string, m *Match) {\n\tl := *al\n\tbuf := &bytes.Buffer{}\n\n\tfor _, r := range data.Rules {\n\t\tbuf.Reset()\n\t\tif r >= 0 { // string lookup\n\t\t\tl = append(l, data.Strings[r])\n\t\t} else if r < -replaceSpecials { // group lookup\n\t\t\tm.groupValueAppendToBuf(-replaceSpecials-1-r, buf)\n\t\t\tl = append(l, buf.String())\n\t\t} else {\n\t\t\tswitch -replaceSpecials - 1 - r { // special insertion patterns\n\t\t\tcase replaceLeftPortion:\n\t\t\t\tfor i := 0; i < m.Index; i++ {\n\t\t\t\t\tbuf.WriteRune(m.text[i])\n\t\t\t\t}\n\t\t\tcase replaceRightPortion:\n\t\t\t\tfor i := m.Index + m.Length; i < len(m.text); i++ {\n\t\t\t\t\tbuf.WriteRune(m.text[i])\n\t\t\t\t}\n\t\t\tcase replaceLastGroup:\n\t\t\t\tm.groupValueAppendToBuf(m.GroupCount()-1, buf)\n\t\t\tcase replaceWholeString:\n\t\t\t\tfor i := 0; i < len(m.text); i++ {\n\t\t\t\t\tbuf.WriteRune(m.text[i])\n\t\t\t\t}\n\t\t\t}\n\t\t\tl = append(l, buf.String())\n\t\t}\n\t}\n\n\t*al = l\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/runner.go",
    "content": "package regexp2\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\t\"unicode\"\n\n\t\"github.com/dlclark/regexp2/syntax\"\n)\n\ntype runner struct {\n\tre   *Regexp\n\tcode *syntax.Code\n\n\truntextstart int // starting point for search\n\n\truntext    []rune // text to search\n\truntextpos int    // current position in text\n\truntextend int\n\n\t// The backtracking stack.  Opcodes use this to store data regarding\n\t// what they have matched and where to backtrack to.  Each \"frame\" on\n\t// the stack takes the form of [CodePosition Data1 Data2...], where\n\t// CodePosition is the position of the current opcode and\n\t// the data values are all optional.  The CodePosition can be negative, and\n\t// these values (also called \"back2\") are used by the BranchMark family of opcodes\n\t// to indicate whether they are backtracking after a successful or failed\n\t// match.\n\t// When we backtrack, we pop the CodePosition off the stack, set the current\n\t// instruction pointer to that code position, and mark the opcode\n\t// with a backtracking flag (\"Back\").  Each opcode then knows how to\n\t// handle its own data.\n\truntrack    []int\n\truntrackpos int\n\n\t// This stack is used to track text positions across different opcodes.\n\t// For example, in /(a*b)+/, the parentheses result in a SetMark/CaptureMark\n\t// pair. SetMark records the text position before we match a*b.  Then\n\t// CaptureMark uses that position to figure out where the capture starts.\n\t// Opcodes which push onto this stack are always paired with other opcodes\n\t// which will pop the value from it later.  A successful match should mean\n\t// that this stack is empty.\n\trunstack    []int\n\trunstackpos int\n\n\t// The crawl stack is used to keep track of captures.  Every time a group\n\t// has a capture, we push its group number onto the runcrawl stack.  In\n\t// the case of a balanced match, we push BOTH groups onto the stack.\n\truncrawl    []int\n\truncrawlpos int\n\n\truntrackcount int // count of states that may do backtracking\n\n\trunmatch *Match // result object\n\n\tignoreTimeout bool\n\ttimeout       time.Duration // timeout in milliseconds (needed for actual)\n\tdeadline      fasttime\n\n\toperator        syntax.InstOp\n\tcodepos         int\n\trightToLeft     bool\n\tcaseInsensitive bool\n}\n\n// run searches for matches and can continue from the previous match\n//\n// quick is usually false, but can be true to not return matches, just put it in caches\n// textstart is -1 to start at the \"beginning\" (depending on Right-To-Left), otherwise an index in input\n// input is the string to search for our regex pattern\nfunc (re *Regexp) run(quick bool, textstart int, input []rune) (*Match, error) {\n\n\t// get a cached runner\n\trunner := re.getRunner()\n\tdefer re.putRunner(runner)\n\n\tif textstart < 0 {\n\t\tif re.RightToLeft() {\n\t\t\ttextstart = len(input)\n\t\t} else {\n\t\t\ttextstart = 0\n\t\t}\n\t}\n\n\treturn runner.scan(input, textstart, quick, re.MatchTimeout)\n}\n\n// Scans the string to find the first match. Uses the Match object\n// both to feed text in and as a place to store matches that come out.\n//\n// All the action is in the Go() method. Our\n// responsibility is to load up the class members before\n// calling Go.\n//\n// The optimizer can compute a set of candidate starting characters,\n// and we could use a separate method Skip() that will quickly scan past\n// any characters that we know can't match.\nfunc (r *runner) scan(rt []rune, textstart int, quick bool, timeout time.Duration) (*Match, error) {\n\tr.timeout = timeout\n\tr.ignoreTimeout = (time.Duration(math.MaxInt64) == timeout)\n\tr.runtextstart = textstart\n\tr.runtext = rt\n\tr.runtextend = len(rt)\n\n\tstoppos := r.runtextend\n\tbump := 1\n\n\tif r.re.RightToLeft() {\n\t\tbump = -1\n\t\tstoppos = 0\n\t}\n\n\tr.runtextpos = textstart\n\tinitted := false\n\n\tr.startTimeoutWatch()\n\tfor {\n\t\tif r.re.Debug() {\n\t\t\t//fmt.Printf(\"\\nSearch content: %v\\n\", string(r.runtext))\n\t\t\tfmt.Printf(\"\\nSearch range: from 0 to %v\\n\", r.runtextend)\n\t\t\tfmt.Printf(\"Firstchar search starting at %v stopping at %v\\n\", r.runtextpos, stoppos)\n\t\t}\n\n\t\tif r.findFirstChar() {\n\t\t\tif err := r.checkTimeout(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif !initted {\n\t\t\t\tr.initMatch()\n\t\t\t\tinitted = true\n\t\t\t}\n\n\t\t\tif r.re.Debug() {\n\t\t\t\tfmt.Printf(\"Executing engine starting at %v\\n\\n\", r.runtextpos)\n\t\t\t}\n\n\t\t\tif err := r.execute(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif r.runmatch.matchcount[0] > 0 {\n\t\t\t\t// We'll return a match even if it touches a previous empty match\n\t\t\t\treturn r.tidyMatch(quick), nil\n\t\t\t}\n\n\t\t\t// reset state for another go\n\t\t\tr.runtrackpos = len(r.runtrack)\n\t\t\tr.runstackpos = len(r.runstack)\n\t\t\tr.runcrawlpos = len(r.runcrawl)\n\t\t}\n\n\t\t// failure!\n\n\t\tif r.runtextpos == stoppos {\n\t\t\tr.tidyMatch(true)\n\t\t\treturn nil, nil\n\t\t}\n\n\t\t// Recognize leading []* and various anchors, and bump on failure accordingly\n\n\t\t// r.bump by one and start again\n\n\t\tr.runtextpos += bump\n\t}\n\t// We never get here\n}\n\nfunc (r *runner) execute() error {\n\n\tr.goTo(0)\n\n\tfor {\n\n\t\tif r.re.Debug() {\n\t\t\tr.dumpState()\n\t\t}\n\n\t\tif err := r.checkTimeout(); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tswitch r.operator {\n\t\tcase syntax.Stop:\n\t\t\treturn nil\n\n\t\tcase syntax.Nothing:\n\t\t\tbreak\n\n\t\tcase syntax.Goto:\n\t\t\tr.goTo(r.operand(0))\n\t\t\tcontinue\n\n\t\tcase syntax.Testref:\n\t\t\tif !r.runmatch.isMatched(r.operand(0)) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Lazybranch:\n\t\t\tr.trackPush1(r.textPos())\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Lazybranch | syntax.Back:\n\t\t\tr.trackPop()\n\t\t\tr.textto(r.trackPeek())\n\t\t\tr.goTo(r.operand(0))\n\t\t\tcontinue\n\n\t\tcase syntax.Setmark:\n\t\t\tr.stackPush(r.textPos())\n\t\t\tr.trackPush()\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Nullmark:\n\t\t\tr.stackPush(-1)\n\t\t\tr.trackPush()\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Setmark | syntax.Back, syntax.Nullmark | syntax.Back:\n\t\t\tr.stackPop()\n\t\t\tbreak\n\n\t\tcase syntax.Getmark:\n\t\t\tr.stackPop()\n\t\t\tr.trackPush1(r.stackPeek())\n\t\t\tr.textto(r.stackPeek())\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Getmark | syntax.Back:\n\t\t\tr.trackPop()\n\t\t\tr.stackPush(r.trackPeek())\n\t\t\tbreak\n\n\t\tcase syntax.Capturemark:\n\t\t\tif r.operand(1) != -1 && !r.runmatch.isMatched(r.operand(1)) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.stackPop()\n\t\t\tif r.operand(1) != -1 {\n\t\t\t\tr.transferCapture(r.operand(0), r.operand(1), r.stackPeek(), r.textPos())\n\t\t\t} else {\n\t\t\t\tr.capture(r.operand(0), r.stackPeek(), r.textPos())\n\t\t\t}\n\t\t\tr.trackPush1(r.stackPeek())\n\n\t\t\tr.advance(2)\n\n\t\t\tcontinue\n\n\t\tcase syntax.Capturemark | syntax.Back:\n\t\t\tr.trackPop()\n\t\t\tr.stackPush(r.trackPeek())\n\t\t\tr.uncapture()\n\t\t\tif r.operand(0) != -1 && r.operand(1) != -1 {\n\t\t\t\tr.uncapture()\n\t\t\t}\n\n\t\t\tbreak\n\n\t\tcase syntax.Branchmark:\n\t\t\tr.stackPop()\n\n\t\t\tmatched := r.textPos() - r.stackPeek()\n\n\t\t\tif matched != 0 { // Nonempty match -> loop now\n\t\t\t\tr.trackPush2(r.stackPeek(), r.textPos()) // Save old mark, textpos\n\t\t\t\tr.stackPush(r.textPos())                 // Make new mark\n\t\t\t\tr.goTo(r.operand(0))                     // Loop\n\t\t\t} else { // Empty match -> straight now\n\t\t\t\tr.trackPushNeg1(r.stackPeek()) // Save old mark\n\t\t\t\tr.advance(1)                   // Straight\n\t\t\t}\n\t\t\tcontinue\n\n\t\tcase syntax.Branchmark | syntax.Back:\n\t\t\tr.trackPopN(2)\n\t\t\tr.stackPop()\n\t\t\tr.textto(r.trackPeekN(1))      // Recall position\n\t\t\tr.trackPushNeg1(r.trackPeek()) // Save old mark\n\t\t\tr.advance(1)                   // Straight\n\t\t\tcontinue\n\n\t\tcase syntax.Branchmark | syntax.Back2:\n\t\t\tr.trackPop()\n\t\t\tr.stackPush(r.trackPeek()) // Recall old mark\n\t\t\tbreak                      // Backtrack\n\n\t\tcase syntax.Lazybranchmark:\n\t\t\t{\n\t\t\t\t// We hit this the first time through a lazy loop and after each\n\t\t\t\t// successful match of the inner expression.  It simply continues\n\t\t\t\t// on and doesn't loop.\n\t\t\t\tr.stackPop()\n\n\t\t\t\toldMarkPos := r.stackPeek()\n\n\t\t\t\tif r.textPos() != oldMarkPos { // Nonempty match -> try to loop again by going to 'back' state\n\t\t\t\t\tif oldMarkPos != -1 {\n\t\t\t\t\t\tr.trackPush2(oldMarkPos, r.textPos()) // Save old mark, textpos\n\t\t\t\t\t} else {\n\t\t\t\t\t\tr.trackPush2(r.textPos(), r.textPos())\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// The inner expression found an empty match, so we'll go directly to 'back2' if we\n\t\t\t\t\t// backtrack.  In this case, we need to push something on the stack, since back2 pops.\n\t\t\t\t\t// However, in the case of ()+? or similar, this empty match may be legitimate, so push the text\n\t\t\t\t\t// position associated with that empty match.\n\t\t\t\t\tr.stackPush(oldMarkPos)\n\n\t\t\t\t\tr.trackPushNeg1(r.stackPeek()) // Save old mark\n\t\t\t\t}\n\t\t\t\tr.advance(1)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\tcase syntax.Lazybranchmark | syntax.Back:\n\n\t\t\t// After the first time, Lazybranchmark | syntax.Back occurs\n\t\t\t// with each iteration of the loop, and therefore with every attempted\n\t\t\t// match of the inner expression.  We'll try to match the inner expression,\n\t\t\t// then go back to Lazybranchmark if successful.  If the inner expression\n\t\t\t// fails, we go to Lazybranchmark | syntax.Back2\n\n\t\t\tr.trackPopN(2)\n\t\t\tpos := r.trackPeekN(1)\n\t\t\tr.trackPushNeg1(r.trackPeek()) // Save old mark\n\t\t\tr.stackPush(pos)               // Make new mark\n\t\t\tr.textto(pos)                  // Recall position\n\t\t\tr.goTo(r.operand(0))           // Loop\n\t\t\tcontinue\n\n\t\tcase syntax.Lazybranchmark | syntax.Back2:\n\t\t\t// The lazy loop has failed.  We'll do a true backtrack and\n\t\t\t// start over before the lazy loop.\n\t\t\tr.stackPop()\n\t\t\tr.trackPop()\n\t\t\tr.stackPush(r.trackPeek()) // Recall old mark\n\t\t\tbreak\n\n\t\tcase syntax.Setcount:\n\t\t\tr.stackPush2(r.textPos(), r.operand(0))\n\t\t\tr.trackPush()\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Nullcount:\n\t\t\tr.stackPush2(-1, r.operand(0))\n\t\t\tr.trackPush()\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Setcount | syntax.Back:\n\t\t\tr.stackPopN(2)\n\t\t\tbreak\n\n\t\tcase syntax.Nullcount | syntax.Back:\n\t\t\tr.stackPopN(2)\n\t\t\tbreak\n\n\t\tcase syntax.Branchcount:\n\t\t\t// r.stackPush:\n\t\t\t//  0: Mark\n\t\t\t//  1: Count\n\n\t\t\tr.stackPopN(2)\n\t\t\tmark := r.stackPeek()\n\t\t\tcount := r.stackPeekN(1)\n\t\t\tmatched := r.textPos() - mark\n\n\t\t\tif count >= r.operand(1) || (matched == 0 && count >= 0) { // Max loops or empty match -> straight now\n\t\t\t\tr.trackPushNeg2(mark, count) // Save old mark, count\n\t\t\t\tr.advance(2)                 // Straight\n\t\t\t} else { // Nonempty match -> count+loop now\n\t\t\t\tr.trackPush1(mark)                 // remember mark\n\t\t\t\tr.stackPush2(r.textPos(), count+1) // Make new mark, incr count\n\t\t\t\tr.goTo(r.operand(0))               // Loop\n\t\t\t}\n\t\t\tcontinue\n\n\t\tcase syntax.Branchcount | syntax.Back:\n\t\t\t// r.trackPush:\n\t\t\t//  0: Previous mark\n\t\t\t// r.stackPush:\n\t\t\t//  0: Mark (= current pos, discarded)\n\t\t\t//  1: Count\n\t\t\tr.trackPop()\n\t\t\tr.stackPopN(2)\n\t\t\tif r.stackPeekN(1) > 0 { // Positive -> can go straight\n\t\t\t\tr.textto(r.stackPeek())                           // Zap to mark\n\t\t\t\tr.trackPushNeg2(r.trackPeek(), r.stackPeekN(1)-1) // Save old mark, old count\n\t\t\t\tr.advance(2)                                      // Straight\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tr.stackPush2(r.trackPeek(), r.stackPeekN(1)-1) // recall old mark, old count\n\t\t\tbreak\n\n\t\tcase syntax.Branchcount | syntax.Back2:\n\t\t\t// r.trackPush:\n\t\t\t//  0: Previous mark\n\t\t\t//  1: Previous count\n\t\t\tr.trackPopN(2)\n\t\t\tr.stackPush2(r.trackPeek(), r.trackPeekN(1)) // Recall old mark, old count\n\t\t\tbreak                                        // Backtrack\n\n\t\tcase syntax.Lazybranchcount:\n\t\t\t// r.stackPush:\n\t\t\t//  0: Mark\n\t\t\t//  1: Count\n\n\t\t\tr.stackPopN(2)\n\t\t\tmark := r.stackPeek()\n\t\t\tcount := r.stackPeekN(1)\n\n\t\t\tif count < 0 { // Negative count -> loop now\n\t\t\t\tr.trackPushNeg1(mark)              // Save old mark\n\t\t\t\tr.stackPush2(r.textPos(), count+1) // Make new mark, incr count\n\t\t\t\tr.goTo(r.operand(0))               // Loop\n\t\t\t} else { // Nonneg count -> straight now\n\t\t\t\tr.trackPush3(mark, count, r.textPos()) // Save mark, count, position\n\t\t\t\tr.advance(2)                           // Straight\n\t\t\t}\n\t\t\tcontinue\n\n\t\tcase syntax.Lazybranchcount | syntax.Back:\n\t\t\t// r.trackPush:\n\t\t\t//  0: Mark\n\t\t\t//  1: Count\n\t\t\t//  2: r.textPos\n\n\t\t\tr.trackPopN(3)\n\t\t\tmark := r.trackPeek()\n\t\t\ttextpos := r.trackPeekN(2)\n\n\t\t\tif r.trackPeekN(1) < r.operand(1) && textpos != mark { // Under limit and not empty match -> loop\n\t\t\t\tr.textto(textpos)                        // Recall position\n\t\t\t\tr.stackPush2(textpos, r.trackPeekN(1)+1) // Make new mark, incr count\n\t\t\t\tr.trackPushNeg1(mark)                    // Save old mark\n\t\t\t\tr.goTo(r.operand(0))                     // Loop\n\t\t\t\tcontinue\n\t\t\t} else { // Max loops or empty match -> backtrack\n\t\t\t\tr.stackPush2(r.trackPeek(), r.trackPeekN(1)) // Recall old mark, count\n\t\t\t\tbreak                                        // backtrack\n\t\t\t}\n\n\t\tcase syntax.Lazybranchcount | syntax.Back2:\n\t\t\t// r.trackPush:\n\t\t\t//  0: Previous mark\n\t\t\t// r.stackPush:\n\t\t\t//  0: Mark (== current pos, discarded)\n\t\t\t//  1: Count\n\t\t\tr.trackPop()\n\t\t\tr.stackPopN(2)\n\t\t\tr.stackPush2(r.trackPeek(), r.stackPeekN(1)-1) // Recall old mark, count\n\t\t\tbreak                                          // Backtrack\n\n\t\tcase syntax.Setjump:\n\t\t\tr.stackPush2(r.trackpos(), r.crawlpos())\n\t\t\tr.trackPush()\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Setjump | syntax.Back:\n\t\t\tr.stackPopN(2)\n\t\t\tbreak\n\n\t\tcase syntax.Backjump:\n\t\t\t// r.stackPush:\n\t\t\t//  0: Saved trackpos\n\t\t\t//  1: r.crawlpos\n\t\t\tr.stackPopN(2)\n\t\t\tr.trackto(r.stackPeek())\n\n\t\t\tfor r.crawlpos() != r.stackPeekN(1) {\n\t\t\t\tr.uncapture()\n\t\t\t}\n\n\t\t\tbreak\n\n\t\tcase syntax.Forejump:\n\t\t\t// r.stackPush:\n\t\t\t//  0: Saved trackpos\n\t\t\t//  1: r.crawlpos\n\t\t\tr.stackPopN(2)\n\t\t\tr.trackto(r.stackPeek())\n\t\t\tr.trackPush1(r.stackPeekN(1))\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Forejump | syntax.Back:\n\t\t\t// r.trackPush:\n\t\t\t//  0: r.crawlpos\n\t\t\tr.trackPop()\n\n\t\t\tfor r.crawlpos() != r.trackPeek() {\n\t\t\t\tr.uncapture()\n\t\t\t}\n\n\t\t\tbreak\n\n\t\tcase syntax.Bol:\n\t\t\tif r.leftchars() > 0 && r.charAt(r.textPos()-1) != '\\n' {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Eol:\n\t\t\tif r.rightchars() > 0 && r.charAt(r.textPos()) != '\\n' {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Boundary:\n\t\t\tif !r.isBoundary(r.textPos(), 0, r.runtextend) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Nonboundary:\n\t\t\tif r.isBoundary(r.textPos(), 0, r.runtextend) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.ECMABoundary:\n\t\t\tif !r.isECMABoundary(r.textPos(), 0, r.runtextend) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.NonECMABoundary:\n\t\t\tif r.isECMABoundary(r.textPos(), 0, r.runtextend) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Beginning:\n\t\t\tif r.leftchars() > 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.Start:\n\t\t\tif r.textPos() != r.textstart() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.EndZ:\n\t\t\trchars := r.rightchars()\n\t\t\tif rchars > 1 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// RE2 and EcmaScript define $ as \"asserts position at the end of the string\"\n\t\t\t// PCRE/.NET adds \"or before the line terminator right at the end of the string (if any)\"\n\t\t\tif (r.re.options & (RE2 | ECMAScript)) != 0 {\n\t\t\t\t// RE2/Ecmascript mode\n\t\t\t\tif rchars > 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else if rchars == 1 && r.charAt(r.textPos()) != '\\n' {\n\t\t\t\t// \"regular\" mode\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.End:\n\t\t\tif r.rightchars() > 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.advance(0)\n\t\t\tcontinue\n\n\t\tcase syntax.One:\n\t\t\tif r.forwardchars() < 1 || r.forwardcharnext() != rune(r.operand(0)) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Notone:\n\t\t\tif r.forwardchars() < 1 || r.forwardcharnext() == rune(r.operand(0)) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Set:\n\n\t\t\tif r.forwardchars() < 1 || !r.code.Sets[r.operand(0)].CharIn(r.forwardcharnext()) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Multi:\n\t\t\tif !r.runematch(r.code.Strings[r.operand(0)]) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Ref:\n\n\t\t\tcapnum := r.operand(0)\n\n\t\t\tif r.runmatch.isMatched(capnum) {\n\t\t\t\tif !r.refmatch(r.runmatch.matchIndex(capnum), r.runmatch.matchLength(capnum)) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (r.re.options & ECMAScript) == 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tr.advance(1)\n\t\t\tcontinue\n\n\t\tcase syntax.Onerep:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif r.forwardchars() < c {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tch := rune(r.operand(0))\n\n\t\t\tfor c > 0 {\n\t\t\t\tif r.forwardcharnext() != ch {\n\t\t\t\t\tgoto BreakBackward\n\t\t\t\t}\n\t\t\t\tc--\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Notonerep:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif r.forwardchars() < c {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tch := rune(r.operand(0))\n\n\t\t\tfor c > 0 {\n\t\t\t\tif r.forwardcharnext() == ch {\n\t\t\t\t\tgoto BreakBackward\n\t\t\t\t}\n\t\t\t\tc--\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Setrep:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif r.forwardchars() < c {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tset := r.code.Sets[r.operand(0)]\n\n\t\t\tfor c > 0 {\n\t\t\t\tif !set.CharIn(r.forwardcharnext()) {\n\t\t\t\t\tgoto BreakBackward\n\t\t\t\t}\n\t\t\t\tc--\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Oneloop:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif c > r.forwardchars() {\n\t\t\t\tc = r.forwardchars()\n\t\t\t}\n\n\t\t\tch := rune(r.operand(0))\n\t\t\ti := c\n\n\t\t\tfor ; i > 0; i-- {\n\t\t\t\tif r.forwardcharnext() != ch {\n\t\t\t\t\tr.backwardnext()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif c > i {\n\t\t\t\tr.trackPush2(c-i-1, r.textPos()-r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Notoneloop:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif c > r.forwardchars() {\n\t\t\t\tc = r.forwardchars()\n\t\t\t}\n\n\t\t\tch := rune(r.operand(0))\n\t\t\ti := c\n\n\t\t\tfor ; i > 0; i-- {\n\t\t\t\tif r.forwardcharnext() == ch {\n\t\t\t\t\tr.backwardnext()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif c > i {\n\t\t\t\tr.trackPush2(c-i-1, r.textPos()-r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Setloop:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif c > r.forwardchars() {\n\t\t\t\tc = r.forwardchars()\n\t\t\t}\n\n\t\t\tset := r.code.Sets[r.operand(0)]\n\t\t\ti := c\n\n\t\t\tfor ; i > 0; i-- {\n\t\t\t\tif !set.CharIn(r.forwardcharnext()) {\n\t\t\t\t\tr.backwardnext()\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif c > i {\n\t\t\t\tr.trackPush2(c-i-1, r.textPos()-r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Oneloop | syntax.Back, syntax.Notoneloop | syntax.Back:\n\n\t\t\tr.trackPopN(2)\n\t\t\ti := r.trackPeek()\n\t\t\tpos := r.trackPeekN(1)\n\n\t\t\tr.textto(pos)\n\n\t\t\tif i > 0 {\n\t\t\t\tr.trackPush2(i-1, pos-r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Setloop | syntax.Back:\n\n\t\t\tr.trackPopN(2)\n\t\t\ti := r.trackPeek()\n\t\t\tpos := r.trackPeekN(1)\n\n\t\t\tr.textto(pos)\n\n\t\t\tif i > 0 {\n\t\t\t\tr.trackPush2(i-1, pos-r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Onelazy, syntax.Notonelazy:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif c > r.forwardchars() {\n\t\t\t\tc = r.forwardchars()\n\t\t\t}\n\n\t\t\tif c > 0 {\n\t\t\t\tr.trackPush2(c-1, r.textPos())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Setlazy:\n\n\t\t\tc := r.operand(1)\n\n\t\t\tif c > r.forwardchars() {\n\t\t\t\tc = r.forwardchars()\n\t\t\t}\n\n\t\t\tif c > 0 {\n\t\t\t\tr.trackPush2(c-1, r.textPos())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Onelazy | syntax.Back:\n\n\t\t\tr.trackPopN(2)\n\t\t\tpos := r.trackPeekN(1)\n\t\t\tr.textto(pos)\n\n\t\t\tif r.forwardcharnext() != rune(r.operand(0)) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ti := r.trackPeek()\n\n\t\t\tif i > 0 {\n\t\t\t\tr.trackPush2(i-1, pos+r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Notonelazy | syntax.Back:\n\n\t\t\tr.trackPopN(2)\n\t\t\tpos := r.trackPeekN(1)\n\t\t\tr.textto(pos)\n\n\t\t\tif r.forwardcharnext() == rune(r.operand(0)) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ti := r.trackPeek()\n\n\t\t\tif i > 0 {\n\t\t\t\tr.trackPush2(i-1, pos+r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tcase syntax.Setlazy | syntax.Back:\n\n\t\t\tr.trackPopN(2)\n\t\t\tpos := r.trackPeekN(1)\n\t\t\tr.textto(pos)\n\n\t\t\tif !r.code.Sets[r.operand(0)].CharIn(r.forwardcharnext()) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ti := r.trackPeek()\n\n\t\t\tif i > 0 {\n\t\t\t\tr.trackPush2(i-1, pos+r.bump())\n\t\t\t}\n\n\t\t\tr.advance(2)\n\t\t\tcontinue\n\n\t\tdefault:\n\t\t\treturn errors.New(\"unknown state in regex runner\")\n\t\t}\n\n\tBreakBackward:\n\t\t;\n\n\t\t// \"break Backward\" comes here:\n\t\tr.backtrack()\n\t}\n}\n\n// increase the size of stack and track storage\nfunc (r *runner) ensureStorage() {\n\tif r.runstackpos < r.runtrackcount*4 {\n\t\tdoubleIntSlice(&r.runstack, &r.runstackpos)\n\t}\n\tif r.runtrackpos < r.runtrackcount*4 {\n\t\tdoubleIntSlice(&r.runtrack, &r.runtrackpos)\n\t}\n}\n\nfunc doubleIntSlice(s *[]int, pos *int) {\n\toldLen := len(*s)\n\tnewS := make([]int, oldLen*2)\n\n\tcopy(newS[oldLen:], *s)\n\t*pos += oldLen\n\t*s = newS\n}\n\n// Save a number on the longjump unrolling stack\nfunc (r *runner) crawl(i int) {\n\tif r.runcrawlpos == 0 {\n\t\tdoubleIntSlice(&r.runcrawl, &r.runcrawlpos)\n\t}\n\tr.runcrawlpos--\n\tr.runcrawl[r.runcrawlpos] = i\n}\n\n// Remove a number from the longjump unrolling stack\nfunc (r *runner) popcrawl() int {\n\tval := r.runcrawl[r.runcrawlpos]\n\tr.runcrawlpos++\n\treturn val\n}\n\n// Get the height of the stack\nfunc (r *runner) crawlpos() int {\n\treturn len(r.runcrawl) - r.runcrawlpos\n}\n\nfunc (r *runner) advance(i int) {\n\tr.codepos += (i + 1)\n\tr.setOperator(r.code.Codes[r.codepos])\n}\n\nfunc (r *runner) goTo(newpos int) {\n\t// when branching backward or in place, ensure storage\n\tif newpos <= r.codepos {\n\t\tr.ensureStorage()\n\t}\n\n\tr.setOperator(r.code.Codes[newpos])\n\tr.codepos = newpos\n}\n\nfunc (r *runner) textto(newpos int) {\n\tr.runtextpos = newpos\n}\n\nfunc (r *runner) trackto(newpos int) {\n\tr.runtrackpos = len(r.runtrack) - newpos\n}\n\nfunc (r *runner) textstart() int {\n\treturn r.runtextstart\n}\n\nfunc (r *runner) textPos() int {\n\treturn r.runtextpos\n}\n\n// push onto the backtracking stack\nfunc (r *runner) trackpos() int {\n\treturn len(r.runtrack) - r.runtrackpos\n}\n\nfunc (r *runner) trackPush() {\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = r.codepos\n}\n\nfunc (r *runner) trackPush1(I1 int) {\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I1\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = r.codepos\n}\n\nfunc (r *runner) trackPush2(I1, I2 int) {\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I1\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I2\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = r.codepos\n}\n\nfunc (r *runner) trackPush3(I1, I2, I3 int) {\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I1\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I2\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I3\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = r.codepos\n}\n\nfunc (r *runner) trackPushNeg1(I1 int) {\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I1\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = -r.codepos\n}\n\nfunc (r *runner) trackPushNeg2(I1, I2 int) {\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I1\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = I2\n\tr.runtrackpos--\n\tr.runtrack[r.runtrackpos] = -r.codepos\n}\n\nfunc (r *runner) backtrack() {\n\tnewpos := r.runtrack[r.runtrackpos]\n\tr.runtrackpos++\n\n\tif r.re.Debug() {\n\t\tif newpos < 0 {\n\t\t\tfmt.Printf(\"       Backtracking (back2) to code position %v\\n\", -newpos)\n\t\t} else {\n\t\t\tfmt.Printf(\"       Backtracking to code position %v\\n\", newpos)\n\t\t}\n\t}\n\n\tif newpos < 0 {\n\t\tnewpos = -newpos\n\t\tr.setOperator(r.code.Codes[newpos] | syntax.Back2)\n\t} else {\n\t\tr.setOperator(r.code.Codes[newpos] | syntax.Back)\n\t}\n\n\t// When branching backward, ensure storage\n\tif newpos < r.codepos {\n\t\tr.ensureStorage()\n\t}\n\n\tr.codepos = newpos\n}\n\nfunc (r *runner) setOperator(op int) {\n\tr.caseInsensitive = (0 != (op & syntax.Ci))\n\tr.rightToLeft = (0 != (op & syntax.Rtl))\n\tr.operator = syntax.InstOp(op & ^(syntax.Rtl | syntax.Ci))\n}\n\nfunc (r *runner) trackPop() {\n\tr.runtrackpos++\n}\n\n// pop framesize items from the backtracking stack\nfunc (r *runner) trackPopN(framesize int) {\n\tr.runtrackpos += framesize\n}\n\n// Technically we are actually peeking at items already popped.  So if you want to\n// get and pop the top item from the stack, you do\n// r.trackPop();\n// r.trackPeek();\nfunc (r *runner) trackPeek() int {\n\treturn r.runtrack[r.runtrackpos-1]\n}\n\n// get the ith element down on the backtracking stack\nfunc (r *runner) trackPeekN(i int) int {\n\treturn r.runtrack[r.runtrackpos-i-1]\n}\n\n// Push onto the grouping stack\nfunc (r *runner) stackPush(I1 int) {\n\tr.runstackpos--\n\tr.runstack[r.runstackpos] = I1\n}\n\nfunc (r *runner) stackPush2(I1, I2 int) {\n\tr.runstackpos--\n\tr.runstack[r.runstackpos] = I1\n\tr.runstackpos--\n\tr.runstack[r.runstackpos] = I2\n}\n\nfunc (r *runner) stackPop() {\n\tr.runstackpos++\n}\n\n// pop framesize items from the grouping stack\nfunc (r *runner) stackPopN(framesize int) {\n\tr.runstackpos += framesize\n}\n\n// Technically we are actually peeking at items already popped.  So if you want to\n// get and pop the top item from the stack, you do\n// r.stackPop();\n// r.stackPeek();\nfunc (r *runner) stackPeek() int {\n\treturn r.runstack[r.runstackpos-1]\n}\n\n// get the ith element down on the grouping stack\nfunc (r *runner) stackPeekN(i int) int {\n\treturn r.runstack[r.runstackpos-i-1]\n}\n\nfunc (r *runner) operand(i int) int {\n\treturn r.code.Codes[r.codepos+i+1]\n}\n\nfunc (r *runner) leftchars() int {\n\treturn r.runtextpos\n}\n\nfunc (r *runner) rightchars() int {\n\treturn r.runtextend - r.runtextpos\n}\n\nfunc (r *runner) bump() int {\n\tif r.rightToLeft {\n\t\treturn -1\n\t}\n\treturn 1\n}\n\nfunc (r *runner) forwardchars() int {\n\tif r.rightToLeft {\n\t\treturn r.runtextpos\n\t}\n\treturn r.runtextend - r.runtextpos\n}\n\nfunc (r *runner) forwardcharnext() rune {\n\tvar ch rune\n\tif r.rightToLeft {\n\t\tr.runtextpos--\n\t\tch = r.runtext[r.runtextpos]\n\t} else {\n\t\tch = r.runtext[r.runtextpos]\n\t\tr.runtextpos++\n\t}\n\n\tif r.caseInsensitive {\n\t\treturn unicode.ToLower(ch)\n\t}\n\treturn ch\n}\n\nfunc (r *runner) runematch(str []rune) bool {\n\tvar pos int\n\n\tc := len(str)\n\tif !r.rightToLeft {\n\t\tif r.runtextend-r.runtextpos < c {\n\t\t\treturn false\n\t\t}\n\n\t\tpos = r.runtextpos + c\n\t} else {\n\t\tif r.runtextpos-0 < c {\n\t\t\treturn false\n\t\t}\n\n\t\tpos = r.runtextpos\n\t}\n\n\tif !r.caseInsensitive {\n\t\tfor c != 0 {\n\t\t\tc--\n\t\t\tpos--\n\t\t\tif str[c] != r.runtext[pos] {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor c != 0 {\n\t\t\tc--\n\t\t\tpos--\n\t\t\tif str[c] != unicode.ToLower(r.runtext[pos]) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tif !r.rightToLeft {\n\t\tpos += len(str)\n\t}\n\n\tr.runtextpos = pos\n\n\treturn true\n}\n\nfunc (r *runner) refmatch(index, len int) bool {\n\tvar c, pos, cmpos int\n\n\tif !r.rightToLeft {\n\t\tif r.runtextend-r.runtextpos < len {\n\t\t\treturn false\n\t\t}\n\n\t\tpos = r.runtextpos + len\n\t} else {\n\t\tif r.runtextpos-0 < len {\n\t\t\treturn false\n\t\t}\n\n\t\tpos = r.runtextpos\n\t}\n\tcmpos = index + len\n\n\tc = len\n\n\tif !r.caseInsensitive {\n\t\tfor c != 0 {\n\t\t\tc--\n\t\t\tcmpos--\n\t\t\tpos--\n\t\t\tif r.runtext[cmpos] != r.runtext[pos] {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t}\n\t} else {\n\t\tfor c != 0 {\n\t\t\tc--\n\t\t\tcmpos--\n\t\t\tpos--\n\n\t\t\tif unicode.ToLower(r.runtext[cmpos]) != unicode.ToLower(r.runtext[pos]) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\tif !r.rightToLeft {\n\t\tpos += len\n\t}\n\n\tr.runtextpos = pos\n\n\treturn true\n}\n\nfunc (r *runner) backwardnext() {\n\tif r.rightToLeft {\n\t\tr.runtextpos++\n\t} else {\n\t\tr.runtextpos--\n\t}\n}\n\nfunc (r *runner) charAt(j int) rune {\n\treturn r.runtext[j]\n}\n\nfunc (r *runner) findFirstChar() bool {\n\n\tif 0 != (r.code.Anchors & (syntax.AnchorBeginning | syntax.AnchorStart | syntax.AnchorEndZ | syntax.AnchorEnd)) {\n\t\tif !r.code.RightToLeft {\n\t\t\tif (0 != (r.code.Anchors&syntax.AnchorBeginning) && r.runtextpos > 0) ||\n\t\t\t\t(0 != (r.code.Anchors&syntax.AnchorStart) && r.runtextpos > r.runtextstart) {\n\t\t\t\tr.runtextpos = r.runtextend\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif 0 != (r.code.Anchors&syntax.AnchorEndZ) && r.runtextpos < r.runtextend-1 {\n\t\t\t\tr.runtextpos = r.runtextend - 1\n\t\t\t} else if 0 != (r.code.Anchors&syntax.AnchorEnd) && r.runtextpos < r.runtextend {\n\t\t\t\tr.runtextpos = r.runtextend\n\t\t\t}\n\t\t} else {\n\t\t\tif (0 != (r.code.Anchors&syntax.AnchorEnd) && r.runtextpos < r.runtextend) ||\n\t\t\t\t(0 != (r.code.Anchors&syntax.AnchorEndZ) && (r.runtextpos < r.runtextend-1 ||\n\t\t\t\t\t(r.runtextpos == r.runtextend-1 && r.charAt(r.runtextpos) != '\\n'))) ||\n\t\t\t\t(0 != (r.code.Anchors&syntax.AnchorStart) && r.runtextpos < r.runtextstart) {\n\t\t\t\tr.runtextpos = 0\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif 0 != (r.code.Anchors&syntax.AnchorBeginning) && r.runtextpos > 0 {\n\t\t\t\tr.runtextpos = 0\n\t\t\t}\n\t\t}\n\n\t\tif r.code.BmPrefix != nil {\n\t\t\treturn r.code.BmPrefix.IsMatch(r.runtext, r.runtextpos, 0, r.runtextend)\n\t\t}\n\n\t\treturn true // found a valid start or end anchor\n\t} else if r.code.BmPrefix != nil {\n\t\tr.runtextpos = r.code.BmPrefix.Scan(r.runtext, r.runtextpos, 0, r.runtextend)\n\n\t\tif r.runtextpos == -1 {\n\t\t\tif r.code.RightToLeft {\n\t\t\t\tr.runtextpos = 0\n\t\t\t} else {\n\t\t\t\tr.runtextpos = r.runtextend\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t} else if r.code.FcPrefix == nil {\n\t\treturn true\n\t}\n\n\tr.rightToLeft = r.code.RightToLeft\n\tr.caseInsensitive = r.code.FcPrefix.CaseInsensitive\n\n\tset := r.code.FcPrefix.PrefixSet\n\tif set.IsSingleton() {\n\t\tch := set.SingletonChar()\n\t\tfor i := r.forwardchars(); i > 0; i-- {\n\t\t\tif ch == r.forwardcharnext() {\n\t\t\t\tr.backwardnext()\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor i := r.forwardchars(); i > 0; i-- {\n\t\t\tn := r.forwardcharnext()\n\t\t\t//fmt.Printf(\"%v in %v: %v\\n\", string(n), set.String(), set.CharIn(n))\n\t\t\tif set.CharIn(n) {\n\t\t\t\tr.backwardnext()\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (r *runner) initMatch() {\n\t// Use a hashtable'ed Match object if the capture numbers are sparse\n\n\tif r.runmatch == nil {\n\t\tif r.re.caps != nil {\n\t\t\tr.runmatch = newMatchSparse(r.re, r.re.caps, r.re.capsize, r.runtext, r.runtextstart)\n\t\t} else {\n\t\t\tr.runmatch = newMatch(r.re, r.re.capsize, r.runtext, r.runtextstart)\n\t\t}\n\t} else {\n\t\tr.runmatch.reset(r.runtext, r.runtextstart)\n\t}\n\n\t// note we test runcrawl, because it is the last one to be allocated\n\t// If there is an alloc failure in the middle of the three allocations,\n\t// we may still return to reuse this instance, and we want to behave\n\t// as if the allocations didn't occur. (we used to test _trackcount != 0)\n\n\tif r.runcrawl != nil {\n\t\tr.runtrackpos = len(r.runtrack)\n\t\tr.runstackpos = len(r.runstack)\n\t\tr.runcrawlpos = len(r.runcrawl)\n\t\treturn\n\t}\n\n\tr.initTrackCount()\n\n\ttracksize := r.runtrackcount * 8\n\tstacksize := r.runtrackcount * 8\n\n\tif tracksize < 32 {\n\t\ttracksize = 32\n\t}\n\tif stacksize < 16 {\n\t\tstacksize = 16\n\t}\n\n\tr.runtrack = make([]int, tracksize)\n\tr.runtrackpos = tracksize\n\n\tr.runstack = make([]int, stacksize)\n\tr.runstackpos = stacksize\n\n\tr.runcrawl = make([]int, 32)\n\tr.runcrawlpos = 32\n}\n\nfunc (r *runner) tidyMatch(quick bool) *Match {\n\tif !quick {\n\t\tmatch := r.runmatch\n\n\t\tr.runmatch = nil\n\n\t\tmatch.tidy(r.runtextpos)\n\t\treturn match\n\t} else {\n\t\t// send back our match -- it's not leaving the package, so it's safe to not clean it up\n\t\t// this reduces allocs for frequent calls to the \"IsMatch\" bool-only functions\n\t\treturn r.runmatch\n\t}\n}\n\n// capture captures a subexpression. Note that the\n// capnum used here has already been mapped to a non-sparse\n// index (by the code generator RegexWriter).\nfunc (r *runner) capture(capnum, start, end int) {\n\tif end < start {\n\t\tT := end\n\t\tend = start\n\t\tstart = T\n\t}\n\n\tr.crawl(capnum)\n\tr.runmatch.addMatch(capnum, start, end-start)\n}\n\n// transferCapture captures a subexpression. Note that the\n// capnum used here has already been mapped to a non-sparse\n// index (by the code generator RegexWriter).\nfunc (r *runner) transferCapture(capnum, uncapnum, start, end int) {\n\tvar start2, end2 int\n\n\t// these are the two intervals that are cancelling each other\n\n\tif end < start {\n\t\tT := end\n\t\tend = start\n\t\tstart = T\n\t}\n\n\tstart2 = r.runmatch.matchIndex(uncapnum)\n\tend2 = start2 + r.runmatch.matchLength(uncapnum)\n\n\t// The new capture gets the innermost defined interval\n\n\tif start >= end2 {\n\t\tend = start\n\t\tstart = end2\n\t} else if end <= start2 {\n\t\tstart = start2\n\t} else {\n\t\tif end > end2 {\n\t\t\tend = end2\n\t\t}\n\t\tif start2 > start {\n\t\t\tstart = start2\n\t\t}\n\t}\n\n\tr.crawl(uncapnum)\n\tr.runmatch.balanceMatch(uncapnum)\n\n\tif capnum != -1 {\n\t\tr.crawl(capnum)\n\t\tr.runmatch.addMatch(capnum, start, end-start)\n\t}\n}\n\n// revert the last capture\nfunc (r *runner) uncapture() {\n\tcapnum := r.popcrawl()\n\tr.runmatch.removeMatch(capnum)\n}\n\n//debug\n\nfunc (r *runner) dumpState() {\n\tback := \"\"\n\tif r.operator&syntax.Back != 0 {\n\t\tback = \" Back\"\n\t}\n\tif r.operator&syntax.Back2 != 0 {\n\t\tback += \" Back2\"\n\t}\n\tfmt.Printf(\"Text:  %v\\nTrack: %v\\nStack: %v\\n       %s%s\\n\\n\",\n\t\tr.textposDescription(),\n\t\tr.stackDescription(r.runtrack, r.runtrackpos),\n\t\tr.stackDescription(r.runstack, r.runstackpos),\n\t\tr.code.OpcodeDescription(r.codepos),\n\t\tback)\n}\n\nfunc (r *runner) stackDescription(a []int, index int) string {\n\tbuf := &bytes.Buffer{}\n\n\tfmt.Fprintf(buf, \"%v/%v\", len(a)-index, len(a))\n\tif buf.Len() < 8 {\n\t\tbuf.WriteString(strings.Repeat(\" \", 8-buf.Len()))\n\t}\n\n\tbuf.WriteRune('(')\n\tfor i := index; i < len(a); i++ {\n\t\tif i > index {\n\t\t\tbuf.WriteRune(' ')\n\t\t}\n\n\t\tbuf.WriteString(strconv.Itoa(a[i]))\n\t}\n\n\tbuf.WriteRune(')')\n\n\treturn buf.String()\n}\n\nfunc (r *runner) textposDescription() string {\n\tbuf := &bytes.Buffer{}\n\n\tbuf.WriteString(strconv.Itoa(r.runtextpos))\n\n\tif buf.Len() < 8 {\n\t\tbuf.WriteString(strings.Repeat(\" \", 8-buf.Len()))\n\t}\n\n\tif r.runtextpos > 0 {\n\t\tbuf.WriteString(syntax.CharDescription(r.runtext[r.runtextpos-1]))\n\t} else {\n\t\tbuf.WriteRune('^')\n\t}\n\n\tbuf.WriteRune('>')\n\n\tfor i := r.runtextpos; i < r.runtextend; i++ {\n\t\tbuf.WriteString(syntax.CharDescription(r.runtext[i]))\n\t}\n\tif buf.Len() >= 64 {\n\t\tbuf.Truncate(61)\n\t\tbuf.WriteString(\"...\")\n\t} else {\n\t\tbuf.WriteRune('$')\n\t}\n\n\treturn buf.String()\n}\n\n// decide whether the pos\n// at the specified index is a boundary or not. It's just not worth\n// emitting inline code for this logic.\nfunc (r *runner) isBoundary(index, startpos, endpos int) bool {\n\treturn (index > startpos && syntax.IsWordChar(r.runtext[index-1])) !=\n\t\t(index < endpos && syntax.IsWordChar(r.runtext[index]))\n}\n\nfunc (r *runner) isECMABoundary(index, startpos, endpos int) bool {\n\treturn (index > startpos && syntax.IsECMAWordChar(r.runtext[index-1])) !=\n\t\t(index < endpos && syntax.IsECMAWordChar(r.runtext[index]))\n}\n\nfunc (r *runner) startTimeoutWatch() {\n\tif r.ignoreTimeout {\n\t\treturn\n\t}\n\tr.deadline = makeDeadline(r.timeout)\n}\n\nfunc (r *runner) checkTimeout() error {\n\tif r.ignoreTimeout || !r.deadline.reached() {\n\t\treturn nil\n\t}\n\n\tif r.re.Debug() {\n\t\t//Debug.WriteLine(\"\")\n\t\t//Debug.WriteLine(\"RegEx match timeout occurred!\")\n\t\t//Debug.WriteLine(\"Specified timeout:       \" + TimeSpan.FromMilliseconds(_timeout).ToString())\n\t\t//Debug.WriteLine(\"Timeout check frequency: \" + TimeoutCheckFrequency)\n\t\t//Debug.WriteLine(\"Search pattern:          \" + _runregex._pattern)\n\t\t//Debug.WriteLine(\"Input:                   \" + r.runtext)\n\t\t//Debug.WriteLine(\"About to throw RegexMatchTimeoutException.\")\n\t}\n\n\treturn fmt.Errorf(\"match timeout after %v on input `%v`\", r.timeout, string(r.runtext))\n}\n\nfunc (r *runner) initTrackCount() {\n\tr.runtrackcount = r.code.TrackCount\n}\n\n// getRunner returns a run to use for matching re.\n// It uses the re's runner cache if possible, to avoid\n// unnecessary allocation.\nfunc (re *Regexp) getRunner() *runner {\n\tre.muRun.Lock()\n\tif n := len(re.runner); n > 0 {\n\t\tz := re.runner[n-1]\n\t\tre.runner = re.runner[:n-1]\n\t\tre.muRun.Unlock()\n\t\treturn z\n\t}\n\tre.muRun.Unlock()\n\tz := &runner{\n\t\tre:   re,\n\t\tcode: re.code,\n\t}\n\treturn z\n}\n\n// putRunner returns a runner to the re's cache.\n// There is no attempt to limit the size of the cache, so it will\n// grow to the maximum number of simultaneous matches\n// run using re.  (The cache empties when re gets garbage collected.)\nfunc (re *Regexp) putRunner(r *runner) {\n\tre.muRun.Lock()\n\tr.runtext = nil\n\tif r.runmatch != nil {\n\t\tr.runmatch.text = nil\n\t}\n\tre.runner = append(re.runner, r)\n\tre.muRun.Unlock()\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/charclass.go",
    "content": "package syntax\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"sort\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\n// CharSet combines start-end rune ranges and unicode categories representing a set of characters\ntype CharSet struct {\n\tranges     []singleRange\n\tcategories []category\n\tsub        *CharSet //optional subtractor\n\tnegate     bool\n\tanything   bool\n}\n\ntype category struct {\n\tnegate bool\n\tcat    string\n}\n\ntype singleRange struct {\n\tfirst rune\n\tlast  rune\n}\n\nconst (\n\tspaceCategoryText = \" \"\n\twordCategoryText  = \"W\"\n)\n\nvar (\n\tecmaSpace = []rune{0x0009, 0x000e, 0x0020, 0x0021, 0x00a0, 0x00a1, 0x1680, 0x1681, 0x2000, 0x200b, 0x2028, 0x202a, 0x202f, 0x2030, 0x205f, 0x2060, 0x3000, 0x3001, 0xfeff, 0xff00}\n\tecmaWord  = []rune{0x0030, 0x003a, 0x0041, 0x005b, 0x005f, 0x0060, 0x0061, 0x007b}\n\tecmaDigit = []rune{0x0030, 0x003a}\n\n\tre2Space = []rune{0x0009, 0x000b, 0x000c, 0x000e, 0x0020, 0x0021}\n)\n\nvar (\n\tAnyClass          = getCharSetFromOldString([]rune{0}, false)\n\tECMAAnyClass      = getCharSetFromOldString([]rune{0, 0x000a, 0x000b, 0x000d, 0x000e}, false)\n\tNoneClass         = getCharSetFromOldString(nil, false)\n\tECMAWordClass     = getCharSetFromOldString(ecmaWord, false)\n\tNotECMAWordClass  = getCharSetFromOldString(ecmaWord, true)\n\tECMASpaceClass    = getCharSetFromOldString(ecmaSpace, false)\n\tNotECMASpaceClass = getCharSetFromOldString(ecmaSpace, true)\n\tECMADigitClass    = getCharSetFromOldString(ecmaDigit, false)\n\tNotECMADigitClass = getCharSetFromOldString(ecmaDigit, true)\n\n\tWordClass     = getCharSetFromCategoryString(false, false, wordCategoryText)\n\tNotWordClass  = getCharSetFromCategoryString(true, false, wordCategoryText)\n\tSpaceClass    = getCharSetFromCategoryString(false, false, spaceCategoryText)\n\tNotSpaceClass = getCharSetFromCategoryString(true, false, spaceCategoryText)\n\tDigitClass    = getCharSetFromCategoryString(false, false, \"Nd\")\n\tNotDigitClass = getCharSetFromCategoryString(false, true, \"Nd\")\n\n\tRE2SpaceClass    = getCharSetFromOldString(re2Space, false)\n\tNotRE2SpaceClass = getCharSetFromOldString(re2Space, true)\n)\n\nvar unicodeCategories = func() map[string]*unicode.RangeTable {\n\tretVal := make(map[string]*unicode.RangeTable)\n\tfor k, v := range unicode.Scripts {\n\t\tretVal[k] = v\n\t}\n\tfor k, v := range unicode.Categories {\n\t\tretVal[k] = v\n\t}\n\tfor k, v := range unicode.Properties {\n\t\tretVal[k] = v\n\t}\n\treturn retVal\n}()\n\nfunc getCharSetFromCategoryString(negateSet bool, negateCat bool, cats ...string) func() *CharSet {\n\tif negateCat && negateSet {\n\t\tpanic(\"BUG!  You should only negate the set OR the category in a constant setup, but not both\")\n\t}\n\n\tc := CharSet{negate: negateSet}\n\n\tc.categories = make([]category, len(cats))\n\tfor i, cat := range cats {\n\t\tc.categories[i] = category{cat: cat, negate: negateCat}\n\t}\n\treturn func() *CharSet {\n\t\t//make a copy each time\n\t\tlocal := c\n\t\t//return that address\n\t\treturn &local\n\t}\n}\n\nfunc getCharSetFromOldString(setText []rune, negate bool) func() *CharSet {\n\tc := CharSet{}\n\tif len(setText) > 0 {\n\t\tfillFirst := false\n\t\tl := len(setText)\n\t\tif negate {\n\t\t\tif setText[0] == 0 {\n\t\t\t\tsetText = setText[1:]\n\t\t\t} else {\n\t\t\t\tl++\n\t\t\t\tfillFirst = true\n\t\t\t}\n\t\t}\n\n\t\tif l%2 == 0 {\n\t\t\tc.ranges = make([]singleRange, l/2)\n\t\t} else {\n\t\t\tc.ranges = make([]singleRange, l/2+1)\n\t\t}\n\n\t\tfirst := true\n\t\tif fillFirst {\n\t\t\tc.ranges[0] = singleRange{first: 0}\n\t\t\tfirst = false\n\t\t}\n\n\t\ti := 0\n\t\tfor _, r := range setText {\n\t\t\tif first {\n\t\t\t\t// lower bound in a new range\n\t\t\t\tc.ranges[i] = singleRange{first: r}\n\t\t\t\tfirst = false\n\t\t\t} else {\n\t\t\t\tc.ranges[i].last = r - 1\n\t\t\t\ti++\n\t\t\t\tfirst = true\n\t\t\t}\n\t\t}\n\t\tif !first {\n\t\t\tc.ranges[i].last = utf8.MaxRune\n\t\t}\n\t}\n\n\treturn func() *CharSet {\n\t\tlocal := c\n\t\treturn &local\n\t}\n}\n\n// Copy makes a deep copy to prevent accidental mutation of a set\nfunc (c CharSet) Copy() CharSet {\n\tret := CharSet{\n\t\tanything: c.anything,\n\t\tnegate:   c.negate,\n\t}\n\n\tret.ranges = append(ret.ranges, c.ranges...)\n\tret.categories = append(ret.categories, c.categories...)\n\n\tif c.sub != nil {\n\t\tsub := c.sub.Copy()\n\t\tret.sub = &sub\n\t}\n\n\treturn ret\n}\n\n// gets a human-readable description for a set string\nfunc (c CharSet) String() string {\n\tbuf := &bytes.Buffer{}\n\tbuf.WriteRune('[')\n\n\tif c.IsNegated() {\n\t\tbuf.WriteRune('^')\n\t}\n\n\tfor _, r := range c.ranges {\n\n\t\tbuf.WriteString(CharDescription(r.first))\n\t\tif r.first != r.last {\n\t\t\tif r.last-r.first != 1 {\n\t\t\t\t//groups that are 1 char apart skip the dash\n\t\t\t\tbuf.WriteRune('-')\n\t\t\t}\n\t\t\tbuf.WriteString(CharDescription(r.last))\n\t\t}\n\t}\n\n\tfor _, c := range c.categories {\n\t\tbuf.WriteString(c.String())\n\t}\n\n\tif c.sub != nil {\n\t\tbuf.WriteRune('-')\n\t\tbuf.WriteString(c.sub.String())\n\t}\n\n\tbuf.WriteRune(']')\n\n\treturn buf.String()\n}\n\n// mapHashFill converts a charset into a buffer for use in maps\nfunc (c CharSet) mapHashFill(buf *bytes.Buffer) {\n\tif c.negate {\n\t\tbuf.WriteByte(0)\n\t} else {\n\t\tbuf.WriteByte(1)\n\t}\n\n\tbinary.Write(buf, binary.LittleEndian, len(c.ranges))\n\tbinary.Write(buf, binary.LittleEndian, len(c.categories))\n\tfor _, r := range c.ranges {\n\t\tbuf.WriteRune(r.first)\n\t\tbuf.WriteRune(r.last)\n\t}\n\tfor _, ct := range c.categories {\n\t\tbuf.WriteString(ct.cat)\n\t\tif ct.negate {\n\t\t\tbuf.WriteByte(1)\n\t\t} else {\n\t\t\tbuf.WriteByte(0)\n\t\t}\n\t}\n\n\tif c.sub != nil {\n\t\tc.sub.mapHashFill(buf)\n\t}\n}\n\n// CharIn returns true if the rune is in our character set (either ranges or categories).\n// It handles negations and subtracted sub-charsets.\nfunc (c CharSet) CharIn(ch rune) bool {\n\tval := false\n\t// in s && !s.subtracted\n\n\t//check ranges\n\tfor _, r := range c.ranges {\n\t\tif ch < r.first {\n\t\t\tcontinue\n\t\t}\n\t\tif ch <= r.last {\n\t\t\tval = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\t//check categories if we haven't already found a range\n\tif !val && len(c.categories) > 0 {\n\t\tfor _, ct := range c.categories {\n\t\t\t// special categories...then unicode\n\t\t\tif ct.cat == spaceCategoryText {\n\t\t\t\tif unicode.IsSpace(ch) {\n\t\t\t\t\t// we found a space so we're done\n\t\t\t\t\t// negate means this is a \"bad\" thing\n\t\t\t\t\tval = !ct.negate\n\t\t\t\t\tbreak\n\t\t\t\t} else if ct.negate {\n\t\t\t\t\tval = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else if ct.cat == wordCategoryText {\n\t\t\t\tif IsWordChar(ch) {\n\t\t\t\t\tval = !ct.negate\n\t\t\t\t\tbreak\n\t\t\t\t} else if ct.negate {\n\t\t\t\t\tval = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t} else if unicode.Is(unicodeCategories[ct.cat], ch) {\n\t\t\t\t// if we're in this unicode category then we're done\n\t\t\t\t// if negate=true on this category then we \"failed\" our test\n\t\t\t\t// otherwise we're good that we found it\n\t\t\t\tval = !ct.negate\n\t\t\t\tbreak\n\t\t\t} else if ct.negate {\n\t\t\t\tval = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// negate the whole char set\n\tif c.negate {\n\t\tval = !val\n\t}\n\n\t// get subtracted recurse\n\tif val && c.sub != nil {\n\t\tval = !c.sub.CharIn(ch)\n\t}\n\n\t//log.Printf(\"Char '%v' in %v == %v\", string(ch), c.String(), val)\n\treturn val\n}\n\nfunc (c category) String() string {\n\tswitch c.cat {\n\tcase spaceCategoryText:\n\t\tif c.negate {\n\t\t\treturn \"\\\\S\"\n\t\t}\n\t\treturn \"\\\\s\"\n\tcase wordCategoryText:\n\t\tif c.negate {\n\t\t\treturn \"\\\\W\"\n\t\t}\n\t\treturn \"\\\\w\"\n\t}\n\tif _, ok := unicodeCategories[c.cat]; ok {\n\n\t\tif c.negate {\n\t\t\treturn \"\\\\P{\" + c.cat + \"}\"\n\t\t}\n\t\treturn \"\\\\p{\" + c.cat + \"}\"\n\t}\n\treturn \"Unknown category: \" + c.cat\n}\n\n// CharDescription Produces a human-readable description for a single character.\nfunc CharDescription(ch rune) string {\n\t/*if ch == '\\\\' {\n\t\treturn \"\\\\\\\\\"\n\t}\n\n\tif ch > ' ' && ch <= '~' {\n\t\treturn string(ch)\n\t} else if ch == '\\n' {\n\t\treturn \"\\\\n\"\n\t} else if ch == ' ' {\n\t\treturn \"\\\\ \"\n\t}*/\n\n\tb := &bytes.Buffer{}\n\tescape(b, ch, false) //fmt.Sprintf(\"%U\", ch)\n\treturn b.String()\n}\n\n// According to UTS#18 Unicode Regular Expressions (http://www.unicode.org/reports/tr18/)\n// RL 1.4 Simple Word Boundaries  The class of <word_character> includes all Alphabetic\n// values from the Unicode character database, from UnicodeData.txt [UData], plus the U+200C\n// ZERO WIDTH NON-JOINER and U+200D ZERO WIDTH JOINER.\nfunc IsWordChar(r rune) bool {\n\t//\"L\", \"Mn\", \"Nd\", \"Pc\"\n\treturn unicode.In(r,\n\t\tunicode.Categories[\"L\"], unicode.Categories[\"Mn\"],\n\t\tunicode.Categories[\"Nd\"], unicode.Categories[\"Pc\"]) || r == '\\u200D' || r == '\\u200C'\n\t//return 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' || '0' <= r && r <= '9' || r == '_'\n}\n\nfunc IsECMAWordChar(r rune) bool {\n\treturn unicode.In(r,\n\t\tunicode.Categories[\"L\"], unicode.Categories[\"Mn\"],\n\t\tunicode.Categories[\"Nd\"], unicode.Categories[\"Pc\"])\n\n\t//return 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' || '0' <= r && r <= '9' || r == '_'\n}\n\n// SingletonChar will return the char from the first range without validation.\n// It assumes you have checked for IsSingleton or IsSingletonInverse and will panic given bad input\nfunc (c CharSet) SingletonChar() rune {\n\treturn c.ranges[0].first\n}\n\nfunc (c CharSet) IsSingleton() bool {\n\treturn !c.negate && //negated is multiple chars\n\t\tlen(c.categories) == 0 && len(c.ranges) == 1 && // multiple ranges and unicode classes represent multiple chars\n\t\tc.sub == nil && // subtraction means we've got multiple chars\n\t\tc.ranges[0].first == c.ranges[0].last // first and last equal means we're just 1 char\n}\n\nfunc (c CharSet) IsSingletonInverse() bool {\n\treturn c.negate && //same as above, but requires negated\n\t\tlen(c.categories) == 0 && len(c.ranges) == 1 && // multiple ranges and unicode classes represent multiple chars\n\t\tc.sub == nil && // subtraction means we've got multiple chars\n\t\tc.ranges[0].first == c.ranges[0].last // first and last equal means we're just 1 char\n}\n\nfunc (c CharSet) IsMergeable() bool {\n\treturn !c.IsNegated() && !c.HasSubtraction()\n}\n\nfunc (c CharSet) IsNegated() bool {\n\treturn c.negate\n}\n\nfunc (c CharSet) HasSubtraction() bool {\n\treturn c.sub != nil\n}\n\nfunc (c CharSet) IsEmpty() bool {\n\treturn len(c.ranges) == 0 && len(c.categories) == 0 && c.sub == nil\n}\n\nfunc (c *CharSet) addDigit(ecma, negate bool, pattern string) {\n\tif ecma {\n\t\tif negate {\n\t\t\tc.addRanges(NotECMADigitClass().ranges)\n\t\t} else {\n\t\t\tc.addRanges(ECMADigitClass().ranges)\n\t\t}\n\t} else {\n\t\tc.addCategories(category{cat: \"Nd\", negate: negate})\n\t}\n}\n\nfunc (c *CharSet) addChar(ch rune) {\n\tc.addRange(ch, ch)\n}\n\nfunc (c *CharSet) addSpace(ecma, re2, negate bool) {\n\tif ecma {\n\t\tif negate {\n\t\t\tc.addRanges(NotECMASpaceClass().ranges)\n\t\t} else {\n\t\t\tc.addRanges(ECMASpaceClass().ranges)\n\t\t}\n\t} else if re2 {\n\t\tif negate {\n\t\t\tc.addRanges(NotRE2SpaceClass().ranges)\n\t\t} else {\n\t\t\tc.addRanges(RE2SpaceClass().ranges)\n\t\t}\n\t} else {\n\t\tc.addCategories(category{cat: spaceCategoryText, negate: negate})\n\t}\n}\n\nfunc (c *CharSet) addWord(ecma, negate bool) {\n\tif ecma {\n\t\tif negate {\n\t\t\tc.addRanges(NotECMAWordClass().ranges)\n\t\t} else {\n\t\t\tc.addRanges(ECMAWordClass().ranges)\n\t\t}\n\t} else {\n\t\tc.addCategories(category{cat: wordCategoryText, negate: negate})\n\t}\n}\n\n// Add set ranges and categories into ours -- no deduping or anything\nfunc (c *CharSet) addSet(set CharSet) {\n\tif c.anything {\n\t\treturn\n\t}\n\tif set.anything {\n\t\tc.makeAnything()\n\t\treturn\n\t}\n\t// just append here to prevent double-canon\n\tc.ranges = append(c.ranges, set.ranges...)\n\tc.addCategories(set.categories...)\n\tc.canonicalize()\n}\n\nfunc (c *CharSet) makeAnything() {\n\tc.anything = true\n\tc.categories = []category{}\n\tc.ranges = AnyClass().ranges\n}\n\nfunc (c *CharSet) addCategories(cats ...category) {\n\t// don't add dupes and remove positive+negative\n\tif c.anything {\n\t\t// if we've had a previous positive+negative group then\n\t\t// just return, we're as broad as we can get\n\t\treturn\n\t}\n\n\tfor _, ct := range cats {\n\t\tfound := false\n\t\tfor _, ct2 := range c.categories {\n\t\t\tif ct.cat == ct2.cat {\n\t\t\t\tif ct.negate != ct2.negate {\n\t\t\t\t\t// oposite negations...this mean we just\n\t\t\t\t\t// take us as anything and move on\n\t\t\t\t\tc.makeAnything()\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !found {\n\t\t\tc.categories = append(c.categories, ct)\n\t\t}\n\t}\n}\n\n// Merges new ranges to our own\nfunc (c *CharSet) addRanges(ranges []singleRange) {\n\tif c.anything {\n\t\treturn\n\t}\n\tc.ranges = append(c.ranges, ranges...)\n\tc.canonicalize()\n}\n\n// Merges everything but the new ranges into our own\nfunc (c *CharSet) addNegativeRanges(ranges []singleRange) {\n\tif c.anything {\n\t\treturn\n\t}\n\n\tvar hi rune\n\n\t// convert incoming ranges into opposites, assume they are in order\n\tfor _, r := range ranges {\n\t\tif hi < r.first {\n\t\t\tc.ranges = append(c.ranges, singleRange{hi, r.first - 1})\n\t\t}\n\t\thi = r.last + 1\n\t}\n\n\tif hi < utf8.MaxRune {\n\t\tc.ranges = append(c.ranges, singleRange{hi, utf8.MaxRune})\n\t}\n\n\tc.canonicalize()\n}\n\nfunc isValidUnicodeCat(catName string) bool {\n\t_, ok := unicodeCategories[catName]\n\treturn ok\n}\n\nfunc (c *CharSet) addCategory(categoryName string, negate, caseInsensitive bool, pattern string) {\n\tif !isValidUnicodeCat(categoryName) {\n\t\t// unknown unicode category, script, or property \"blah\"\n\t\tpanic(fmt.Errorf(\"Unknown unicode category, script, or property '%v'\", categoryName))\n\n\t}\n\n\tif caseInsensitive && (categoryName == \"Ll\" || categoryName == \"Lu\" || categoryName == \"Lt\") {\n\t\t// when RegexOptions.IgnoreCase is specified then {Ll} {Lu} and {Lt} cases should all match\n\t\tc.addCategories(\n\t\t\tcategory{cat: \"Ll\", negate: negate},\n\t\t\tcategory{cat: \"Lu\", negate: negate},\n\t\t\tcategory{cat: \"Lt\", negate: negate})\n\t}\n\tc.addCategories(category{cat: categoryName, negate: negate})\n}\n\nfunc (c *CharSet) addSubtraction(sub *CharSet) {\n\tc.sub = sub\n}\n\nfunc (c *CharSet) addRange(chMin, chMax rune) {\n\tc.ranges = append(c.ranges, singleRange{first: chMin, last: chMax})\n\tc.canonicalize()\n}\n\nfunc (c *CharSet) addNamedASCII(name string, negate bool) bool {\n\tvar rs []singleRange\n\n\tswitch name {\n\tcase \"alnum\":\n\t\trs = []singleRange{singleRange{'0', '9'}, singleRange{'A', 'Z'}, singleRange{'a', 'z'}}\n\tcase \"alpha\":\n\t\trs = []singleRange{singleRange{'A', 'Z'}, singleRange{'a', 'z'}}\n\tcase \"ascii\":\n\t\trs = []singleRange{singleRange{0, 0x7f}}\n\tcase \"blank\":\n\t\trs = []singleRange{singleRange{'\\t', '\\t'}, singleRange{' ', ' '}}\n\tcase \"cntrl\":\n\t\trs = []singleRange{singleRange{0, 0x1f}, singleRange{0x7f, 0x7f}}\n\tcase \"digit\":\n\t\tc.addDigit(false, negate, \"\")\n\tcase \"graph\":\n\t\trs = []singleRange{singleRange{'!', '~'}}\n\tcase \"lower\":\n\t\trs = []singleRange{singleRange{'a', 'z'}}\n\tcase \"print\":\n\t\trs = []singleRange{singleRange{' ', '~'}}\n\tcase \"punct\": //[!-/:-@[-`{-~]\n\t\trs = []singleRange{singleRange{'!', '/'}, singleRange{':', '@'}, singleRange{'[', '`'}, singleRange{'{', '~'}}\n\tcase \"space\":\n\t\tc.addSpace(true, false, negate)\n\tcase \"upper\":\n\t\trs = []singleRange{singleRange{'A', 'Z'}}\n\tcase \"word\":\n\t\tc.addWord(true, negate)\n\tcase \"xdigit\":\n\t\trs = []singleRange{singleRange{'0', '9'}, singleRange{'A', 'F'}, singleRange{'a', 'f'}}\n\tdefault:\n\t\treturn false\n\t}\n\n\tif len(rs) > 0 {\n\t\tif negate {\n\t\t\tc.addNegativeRanges(rs)\n\t\t} else {\n\t\t\tc.addRanges(rs)\n\t\t}\n\t}\n\n\treturn true\n}\n\ntype singleRangeSorter []singleRange\n\nfunc (p singleRangeSorter) Len() int           { return len(p) }\nfunc (p singleRangeSorter) Less(i, j int) bool { return p[i].first < p[j].first }\nfunc (p singleRangeSorter) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }\n\n// Logic to reduce a character class to a unique, sorted form.\nfunc (c *CharSet) canonicalize() {\n\tvar i, j int\n\tvar last rune\n\n\t//\n\t// Find and eliminate overlapping or abutting ranges\n\t//\n\n\tif len(c.ranges) > 1 {\n\t\tsort.Sort(singleRangeSorter(c.ranges))\n\n\t\tdone := false\n\n\t\tfor i, j = 1, 0; ; i++ {\n\t\t\tfor last = c.ranges[j].last; ; i++ {\n\t\t\t\tif i == len(c.ranges) || last == utf8.MaxRune {\n\t\t\t\t\tdone = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tCurrentRange := c.ranges[i]\n\t\t\t\tif CurrentRange.first > last+1 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif last < CurrentRange.last {\n\t\t\t\t\tlast = CurrentRange.last\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tc.ranges[j] = singleRange{first: c.ranges[j].first, last: last}\n\n\t\t\tj++\n\n\t\t\tif done {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif j < i {\n\t\t\t\tc.ranges[j] = c.ranges[i]\n\t\t\t}\n\t\t}\n\n\t\tc.ranges = append(c.ranges[:j], c.ranges[len(c.ranges):]...)\n\t}\n}\n\n// Adds to the class any lowercase versions of characters already\n// in the class. Used for case-insensitivity.\nfunc (c *CharSet) addLowercase() {\n\tif c.anything {\n\t\treturn\n\t}\n\ttoAdd := []singleRange{}\n\tfor i := 0; i < len(c.ranges); i++ {\n\t\tr := c.ranges[i]\n\t\tif r.first == r.last {\n\t\t\tlower := unicode.ToLower(r.first)\n\t\t\tc.ranges[i] = singleRange{first: lower, last: lower}\n\t\t} else {\n\t\t\ttoAdd = append(toAdd, r)\n\t\t}\n\t}\n\n\tfor _, r := range toAdd {\n\t\tc.addLowercaseRange(r.first, r.last)\n\t}\n\tc.canonicalize()\n}\n\n/**************************************************************************\n    Let U be the set of Unicode character values and let L be the lowercase\n    function, mapping from U to U. To perform case insensitive matching of\n    character sets, we need to be able to map an interval I in U, say\n\n        I = [chMin, chMax] = { ch : chMin <= ch <= chMax }\n\n    to a set A such that A contains L(I) and A is contained in the union of\n    I and L(I).\n\n    The table below partitions U into intervals on which L is non-decreasing.\n    Thus, for any interval J = [a, b] contained in one of these intervals,\n    L(J) is contained in [L(a), L(b)].\n\n    It is also true that for any such J, [L(a), L(b)] is contained in the\n    union of J and L(J). This does not follow from L being non-decreasing on\n    these intervals. It follows from the nature of the L on each interval.\n    On each interval, L has one of the following forms:\n\n        (1) L(ch) = constant            (LowercaseSet)\n        (2) L(ch) = ch + offset         (LowercaseAdd)\n        (3) L(ch) = ch | 1              (LowercaseBor)\n        (4) L(ch) = ch + (ch & 1)       (LowercaseBad)\n\n    It is easy to verify that for any of these forms [L(a), L(b)] is\n    contained in the union of [a, b] and L([a, b]).\n***************************************************************************/\n\nconst (\n\tLowercaseSet = 0 // Set to arg.\n\tLowercaseAdd = 1 // Add arg.\n\tLowercaseBor = 2 // Bitwise or with 1.\n\tLowercaseBad = 3 // Bitwise and with 1 and add original.\n)\n\ntype lcMap struct {\n\tchMin, chMax rune\n\top, data     int32\n}\n\nvar lcTable = []lcMap{\n\tlcMap{'\\u0041', '\\u005A', LowercaseAdd, 32},\n\tlcMap{'\\u00C0', '\\u00DE', LowercaseAdd, 32},\n\tlcMap{'\\u0100', '\\u012E', LowercaseBor, 0},\n\tlcMap{'\\u0130', '\\u0130', LowercaseSet, 0x0069},\n\tlcMap{'\\u0132', '\\u0136', LowercaseBor, 0},\n\tlcMap{'\\u0139', '\\u0147', LowercaseBad, 0},\n\tlcMap{'\\u014A', '\\u0176', LowercaseBor, 0},\n\tlcMap{'\\u0178', '\\u0178', LowercaseSet, 0x00FF},\n\tlcMap{'\\u0179', '\\u017D', LowercaseBad, 0},\n\tlcMap{'\\u0181', '\\u0181', LowercaseSet, 0x0253},\n\tlcMap{'\\u0182', '\\u0184', LowercaseBor, 0},\n\tlcMap{'\\u0186', '\\u0186', LowercaseSet, 0x0254},\n\tlcMap{'\\u0187', '\\u0187', LowercaseSet, 0x0188},\n\tlcMap{'\\u0189', '\\u018A', LowercaseAdd, 205},\n\tlcMap{'\\u018B', '\\u018B', LowercaseSet, 0x018C},\n\tlcMap{'\\u018E', '\\u018E', LowercaseSet, 0x01DD},\n\tlcMap{'\\u018F', '\\u018F', LowercaseSet, 0x0259},\n\tlcMap{'\\u0190', '\\u0190', LowercaseSet, 0x025B},\n\tlcMap{'\\u0191', '\\u0191', LowercaseSet, 0x0192},\n\tlcMap{'\\u0193', '\\u0193', LowercaseSet, 0x0260},\n\tlcMap{'\\u0194', '\\u0194', LowercaseSet, 0x0263},\n\tlcMap{'\\u0196', '\\u0196', LowercaseSet, 0x0269},\n\tlcMap{'\\u0197', '\\u0197', LowercaseSet, 0x0268},\n\tlcMap{'\\u0198', '\\u0198', LowercaseSet, 0x0199},\n\tlcMap{'\\u019C', '\\u019C', LowercaseSet, 0x026F},\n\tlcMap{'\\u019D', '\\u019D', LowercaseSet, 0x0272},\n\tlcMap{'\\u019F', '\\u019F', LowercaseSet, 0x0275},\n\tlcMap{'\\u01A0', '\\u01A4', LowercaseBor, 0},\n\tlcMap{'\\u01A7', '\\u01A7', LowercaseSet, 0x01A8},\n\tlcMap{'\\u01A9', '\\u01A9', LowercaseSet, 0x0283},\n\tlcMap{'\\u01AC', '\\u01AC', LowercaseSet, 0x01AD},\n\tlcMap{'\\u01AE', '\\u01AE', LowercaseSet, 0x0288},\n\tlcMap{'\\u01AF', '\\u01AF', LowercaseSet, 0x01B0},\n\tlcMap{'\\u01B1', '\\u01B2', LowercaseAdd, 217},\n\tlcMap{'\\u01B3', '\\u01B5', LowercaseBad, 0},\n\tlcMap{'\\u01B7', '\\u01B7', LowercaseSet, 0x0292},\n\tlcMap{'\\u01B8', '\\u01B8', LowercaseSet, 0x01B9},\n\tlcMap{'\\u01BC', '\\u01BC', LowercaseSet, 0x01BD},\n\tlcMap{'\\u01C4', '\\u01C5', LowercaseSet, 0x01C6},\n\tlcMap{'\\u01C7', '\\u01C8', LowercaseSet, 0x01C9},\n\tlcMap{'\\u01CA', '\\u01CB', LowercaseSet, 0x01CC},\n\tlcMap{'\\u01CD', '\\u01DB', LowercaseBad, 0},\n\tlcMap{'\\u01DE', '\\u01EE', LowercaseBor, 0},\n\tlcMap{'\\u01F1', '\\u01F2', LowercaseSet, 0x01F3},\n\tlcMap{'\\u01F4', '\\u01F4', LowercaseSet, 0x01F5},\n\tlcMap{'\\u01FA', '\\u0216', LowercaseBor, 0},\n\tlcMap{'\\u0386', '\\u0386', LowercaseSet, 0x03AC},\n\tlcMap{'\\u0388', '\\u038A', LowercaseAdd, 37},\n\tlcMap{'\\u038C', '\\u038C', LowercaseSet, 0x03CC},\n\tlcMap{'\\u038E', '\\u038F', LowercaseAdd, 63},\n\tlcMap{'\\u0391', '\\u03AB', LowercaseAdd, 32},\n\tlcMap{'\\u03E2', '\\u03EE', LowercaseBor, 0},\n\tlcMap{'\\u0401', '\\u040F', LowercaseAdd, 80},\n\tlcMap{'\\u0410', '\\u042F', LowercaseAdd, 32},\n\tlcMap{'\\u0460', '\\u0480', LowercaseBor, 0},\n\tlcMap{'\\u0490', '\\u04BE', LowercaseBor, 0},\n\tlcMap{'\\u04C1', '\\u04C3', LowercaseBad, 0},\n\tlcMap{'\\u04C7', '\\u04C7', LowercaseSet, 0x04C8},\n\tlcMap{'\\u04CB', '\\u04CB', LowercaseSet, 0x04CC},\n\tlcMap{'\\u04D0', '\\u04EA', LowercaseBor, 0},\n\tlcMap{'\\u04EE', '\\u04F4', LowercaseBor, 0},\n\tlcMap{'\\u04F8', '\\u04F8', LowercaseSet, 0x04F9},\n\tlcMap{'\\u0531', '\\u0556', LowercaseAdd, 48},\n\tlcMap{'\\u10A0', '\\u10C5', LowercaseAdd, 48},\n\tlcMap{'\\u1E00', '\\u1EF8', LowercaseBor, 0},\n\tlcMap{'\\u1F08', '\\u1F0F', LowercaseAdd, -8},\n\tlcMap{'\\u1F18', '\\u1F1F', LowercaseAdd, -8},\n\tlcMap{'\\u1F28', '\\u1F2F', LowercaseAdd, -8},\n\tlcMap{'\\u1F38', '\\u1F3F', LowercaseAdd, -8},\n\tlcMap{'\\u1F48', '\\u1F4D', LowercaseAdd, -8},\n\tlcMap{'\\u1F59', '\\u1F59', LowercaseSet, 0x1F51},\n\tlcMap{'\\u1F5B', '\\u1F5B', LowercaseSet, 0x1F53},\n\tlcMap{'\\u1F5D', '\\u1F5D', LowercaseSet, 0x1F55},\n\tlcMap{'\\u1F5F', '\\u1F5F', LowercaseSet, 0x1F57},\n\tlcMap{'\\u1F68', '\\u1F6F', LowercaseAdd, -8},\n\tlcMap{'\\u1F88', '\\u1F8F', LowercaseAdd, -8},\n\tlcMap{'\\u1F98', '\\u1F9F', LowercaseAdd, -8},\n\tlcMap{'\\u1FA8', '\\u1FAF', LowercaseAdd, -8},\n\tlcMap{'\\u1FB8', '\\u1FB9', LowercaseAdd, -8},\n\tlcMap{'\\u1FBA', '\\u1FBB', LowercaseAdd, -74},\n\tlcMap{'\\u1FBC', '\\u1FBC', LowercaseSet, 0x1FB3},\n\tlcMap{'\\u1FC8', '\\u1FCB', LowercaseAdd, -86},\n\tlcMap{'\\u1FCC', '\\u1FCC', LowercaseSet, 0x1FC3},\n\tlcMap{'\\u1FD8', '\\u1FD9', LowercaseAdd, -8},\n\tlcMap{'\\u1FDA', '\\u1FDB', LowercaseAdd, -100},\n\tlcMap{'\\u1FE8', '\\u1FE9', LowercaseAdd, -8},\n\tlcMap{'\\u1FEA', '\\u1FEB', LowercaseAdd, -112},\n\tlcMap{'\\u1FEC', '\\u1FEC', LowercaseSet, 0x1FE5},\n\tlcMap{'\\u1FF8', '\\u1FF9', LowercaseAdd, -128},\n\tlcMap{'\\u1FFA', '\\u1FFB', LowercaseAdd, -126},\n\tlcMap{'\\u1FFC', '\\u1FFC', LowercaseSet, 0x1FF3},\n\tlcMap{'\\u2160', '\\u216F', LowercaseAdd, 16},\n\tlcMap{'\\u24B6', '\\u24D0', LowercaseAdd, 26},\n\tlcMap{'\\uFF21', '\\uFF3A', LowercaseAdd, 32},\n}\n\nfunc (c *CharSet) addLowercaseRange(chMin, chMax rune) {\n\tvar i, iMax, iMid int\n\tvar chMinT, chMaxT rune\n\tvar lc lcMap\n\n\tfor i, iMax = 0, len(lcTable); i < iMax; {\n\t\tiMid = (i + iMax) / 2\n\t\tif lcTable[iMid].chMax < chMin {\n\t\t\ti = iMid + 1\n\t\t} else {\n\t\t\tiMax = iMid\n\t\t}\n\t}\n\n\tfor ; i < len(lcTable); i++ {\n\t\tlc = lcTable[i]\n\t\tif lc.chMin > chMax {\n\t\t\treturn\n\t\t}\n\t\tchMinT = lc.chMin\n\t\tif chMinT < chMin {\n\t\t\tchMinT = chMin\n\t\t}\n\n\t\tchMaxT = lc.chMax\n\t\tif chMaxT > chMax {\n\t\t\tchMaxT = chMax\n\t\t}\n\n\t\tswitch lc.op {\n\t\tcase LowercaseSet:\n\t\t\tchMinT = rune(lc.data)\n\t\t\tchMaxT = rune(lc.data)\n\t\t\tbreak\n\t\tcase LowercaseAdd:\n\t\t\tchMinT += lc.data\n\t\t\tchMaxT += lc.data\n\t\t\tbreak\n\t\tcase LowercaseBor:\n\t\t\tchMinT |= 1\n\t\t\tchMaxT |= 1\n\t\t\tbreak\n\t\tcase LowercaseBad:\n\t\t\tchMinT += (chMinT & 1)\n\t\t\tchMaxT += (chMaxT & 1)\n\t\t\tbreak\n\t\t}\n\n\t\tif chMinT < chMin || chMaxT > chMax {\n\t\t\tc.addRange(chMinT, chMaxT)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/code.go",
    "content": "package syntax\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n)\n\n// similar to prog.go in the go regex package...also with comment 'may not belong in this package'\n\n// File provides operator constants for use by the Builder and the Machine.\n\n// Implementation notes:\n//\n// Regexps are built into RegexCodes, which contain an operation array,\n// a string table, and some constants.\n//\n// Each operation is one of the codes below, followed by the integer\n// operands specified for each op.\n//\n// Strings and sets are indices into a string table.\n\ntype InstOp int\n\nconst (\n\t// \t\t\t\t\t    lef/back operands        description\n\n\tOnerep    InstOp = 0 // lef,back char,min,max    a {n}\n\tNotonerep        = 1 // lef,back char,min,max    .{n}\n\tSetrep           = 2 // lef,back set,min,max     [\\d]{n}\n\n\tOneloop    = 3 // lef,back char,min,max    a {,n}\n\tNotoneloop = 4 // lef,back char,min,max    .{,n}\n\tSetloop    = 5 // lef,back set,min,max     [\\d]{,n}\n\n\tOnelazy    = 6 // lef,back char,min,max    a {,n}?\n\tNotonelazy = 7 // lef,back char,min,max    .{,n}?\n\tSetlazy    = 8 // lef,back set,min,max     [\\d]{,n}?\n\n\tOne    = 9  // lef      char            a\n\tNotone = 10 // lef      char            [^a]\n\tSet    = 11 // lef      set             [a-z\\s]  \\w \\s \\d\n\n\tMulti = 12 // lef      string          abcd\n\tRef   = 13 // lef      group           \\#\n\n\tBol         = 14 //                          ^\n\tEol         = 15 //                          $\n\tBoundary    = 16 //                          \\b\n\tNonboundary = 17 //                          \\B\n\tBeginning   = 18 //                          \\A\n\tStart       = 19 //                          \\G\n\tEndZ        = 20 //                          \\Z\n\tEnd         = 21 //                          \\Z\n\n\tNothing = 22 //                          Reject!\n\n\t// Primitive control structures\n\n\tLazybranch      = 23 // back     jump            straight first\n\tBranchmark      = 24 // back     jump            branch first for loop\n\tLazybranchmark  = 25 // back     jump            straight first for loop\n\tNullcount       = 26 // back     val             set counter, null mark\n\tSetcount        = 27 // back     val             set counter, make mark\n\tBranchcount     = 28 // back     jump,limit      branch++ if zero<=c<limit\n\tLazybranchcount = 29 // back     jump,limit      same, but straight first\n\tNullmark        = 30 // back                     save position\n\tSetmark         = 31 // back                     save position\n\tCapturemark     = 32 // back     group           define group\n\tGetmark         = 33 // back                     recall position\n\tSetjump         = 34 // back                     save backtrack state\n\tBackjump        = 35 //                          zap back to saved state\n\tForejump        = 36 //                          zap backtracking state\n\tTestref         = 37 //                          backtrack if ref undefined\n\tGoto            = 38 //          jump            just go\n\n\tPrune = 39 //                          prune it baby\n\tStop  = 40 //                          done!\n\n\tECMABoundary    = 41 //                          \\b\n\tNonECMABoundary = 42 //                          \\B\n\n\t// Modifiers for alternate modes\n\n\tMask  = 63  // Mask to get unmodified ordinary operator\n\tRtl   = 64  // bit to indicate that we're reverse scanning.\n\tBack  = 128 // bit to indicate that we're backtracking.\n\tBack2 = 256 // bit to indicate that we're backtracking on a second branch.\n\tCi    = 512 // bit to indicate that we're case-insensitive.\n)\n\ntype Code struct {\n\tCodes       []int       // the code\n\tStrings     [][]rune    // string table\n\tSets        []*CharSet  //character set table\n\tTrackCount  int         // how many instructions use backtracking\n\tCaps        map[int]int // mapping of user group numbers -> impl group slots\n\tCapsize     int         // number of impl group slots\n\tFcPrefix    *Prefix     // the set of candidate first characters (may be null)\n\tBmPrefix    *BmPrefix   // the fixed prefix string as a Boyer-Moore machine (may be null)\n\tAnchors     AnchorLoc   // the set of zero-length start anchors (RegexFCD.Bol, etc)\n\tRightToLeft bool        // true if right to left\n}\n\nfunc opcodeBacktracks(op InstOp) bool {\n\top &= Mask\n\n\tswitch op {\n\tcase Oneloop, Notoneloop, Setloop, Onelazy, Notonelazy, Setlazy, Lazybranch, Branchmark, Lazybranchmark,\n\t\tNullcount, Setcount, Branchcount, Lazybranchcount, Setmark, Capturemark, Getmark, Setjump, Backjump,\n\t\tForejump, Goto:\n\t\treturn true\n\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc opcodeSize(op InstOp) int {\n\top &= Mask\n\n\tswitch op {\n\tcase Nothing, Bol, Eol, Boundary, Nonboundary, ECMABoundary, NonECMABoundary, Beginning, Start, EndZ,\n\t\tEnd, Nullmark, Setmark, Getmark, Setjump, Backjump, Forejump, Stop:\n\t\treturn 1\n\n\tcase One, Notone, Multi, Ref, Testref, Goto, Nullcount, Setcount, Lazybranch, Branchmark, Lazybranchmark,\n\t\tPrune, Set:\n\t\treturn 2\n\n\tcase Capturemark, Branchcount, Lazybranchcount, Onerep, Notonerep, Oneloop, Notoneloop, Onelazy, Notonelazy,\n\t\tSetlazy, Setrep, Setloop:\n\t\treturn 3\n\n\tdefault:\n\t\tpanic(fmt.Errorf(\"Unexpected op code: %v\", op))\n\t}\n}\n\nvar codeStr = []string{\n\t\"Onerep\", \"Notonerep\", \"Setrep\",\n\t\"Oneloop\", \"Notoneloop\", \"Setloop\",\n\t\"Onelazy\", \"Notonelazy\", \"Setlazy\",\n\t\"One\", \"Notone\", \"Set\",\n\t\"Multi\", \"Ref\",\n\t\"Bol\", \"Eol\", \"Boundary\", \"Nonboundary\", \"Beginning\", \"Start\", \"EndZ\", \"End\",\n\t\"Nothing\",\n\t\"Lazybranch\", \"Branchmark\", \"Lazybranchmark\",\n\t\"Nullcount\", \"Setcount\", \"Branchcount\", \"Lazybranchcount\",\n\t\"Nullmark\", \"Setmark\", \"Capturemark\", \"Getmark\",\n\t\"Setjump\", \"Backjump\", \"Forejump\", \"Testref\", \"Goto\",\n\t\"Prune\", \"Stop\",\n\t\"ECMABoundary\", \"NonECMABoundary\",\n}\n\nfunc operatorDescription(op InstOp) string {\n\tdesc := codeStr[op&Mask]\n\tif (op & Ci) != 0 {\n\t\tdesc += \"-Ci\"\n\t}\n\tif (op & Rtl) != 0 {\n\t\tdesc += \"-Rtl\"\n\t}\n\tif (op & Back) != 0 {\n\t\tdesc += \"-Back\"\n\t}\n\tif (op & Back2) != 0 {\n\t\tdesc += \"-Back2\"\n\t}\n\n\treturn desc\n}\n\n// OpcodeDescription is a humman readable string of the specific offset\nfunc (c *Code) OpcodeDescription(offset int) string {\n\tbuf := &bytes.Buffer{}\n\n\top := InstOp(c.Codes[offset])\n\tfmt.Fprintf(buf, \"%06d \", offset)\n\n\tif opcodeBacktracks(op & Mask) {\n\t\tbuf.WriteString(\"*\")\n\t} else {\n\t\tbuf.WriteString(\" \")\n\t}\n\tbuf.WriteString(operatorDescription(op))\n\tbuf.WriteString(\"(\")\n\top &= Mask\n\n\tswitch op {\n\tcase One, Notone, Onerep, Notonerep, Oneloop, Notoneloop, Onelazy, Notonelazy:\n\t\tbuf.WriteString(\"Ch = \")\n\t\tbuf.WriteString(CharDescription(rune(c.Codes[offset+1])))\n\n\tcase Set, Setrep, Setloop, Setlazy:\n\t\tbuf.WriteString(\"Set = \")\n\t\tbuf.WriteString(c.Sets[c.Codes[offset+1]].String())\n\n\tcase Multi:\n\t\tfmt.Fprintf(buf, \"String = %s\", string(c.Strings[c.Codes[offset+1]]))\n\n\tcase Ref, Testref:\n\t\tfmt.Fprintf(buf, \"Index = %d\", c.Codes[offset+1])\n\n\tcase Capturemark:\n\t\tfmt.Fprintf(buf, \"Index = %d\", c.Codes[offset+1])\n\t\tif c.Codes[offset+2] != -1 {\n\t\t\tfmt.Fprintf(buf, \", Unindex = %d\", c.Codes[offset+2])\n\t\t}\n\n\tcase Nullcount, Setcount:\n\t\tfmt.Fprintf(buf, \"Value = %d\", c.Codes[offset+1])\n\n\tcase Goto, Lazybranch, Branchmark, Lazybranchmark, Branchcount, Lazybranchcount:\n\t\tfmt.Fprintf(buf, \"Addr = %d\", c.Codes[offset+1])\n\t}\n\n\tswitch op {\n\tcase Onerep, Notonerep, Oneloop, Notoneloop, Onelazy, Notonelazy, Setrep, Setloop, Setlazy:\n\t\tbuf.WriteString(\", Rep = \")\n\t\tif c.Codes[offset+2] == math.MaxInt32 {\n\t\t\tbuf.WriteString(\"inf\")\n\t\t} else {\n\t\t\tfmt.Fprintf(buf, \"%d\", c.Codes[offset+2])\n\t\t}\n\n\tcase Branchcount, Lazybranchcount:\n\t\tbuf.WriteString(\", Limit = \")\n\t\tif c.Codes[offset+2] == math.MaxInt32 {\n\t\t\tbuf.WriteString(\"inf\")\n\t\t} else {\n\t\t\tfmt.Fprintf(buf, \"%d\", c.Codes[offset+2])\n\t\t}\n\n\t}\n\n\tbuf.WriteString(\")\")\n\n\treturn buf.String()\n}\n\nfunc (c *Code) Dump() string {\n\tbuf := &bytes.Buffer{}\n\n\tif c.RightToLeft {\n\t\tfmt.Fprintln(buf, \"Direction:  right-to-left\")\n\t} else {\n\t\tfmt.Fprintln(buf, \"Direction:  left-to-right\")\n\t}\n\tif c.FcPrefix == nil {\n\t\tfmt.Fprintln(buf, \"Firstchars: n/a\")\n\t} else {\n\t\tfmt.Fprintf(buf, \"Firstchars: %v\\n\", c.FcPrefix.PrefixSet.String())\n\t}\n\n\tif c.BmPrefix == nil {\n\t\tfmt.Fprintln(buf, \"Prefix:     n/a\")\n\t} else {\n\t\tfmt.Fprintf(buf, \"Prefix:     %v\\n\", Escape(c.BmPrefix.String()))\n\t}\n\n\tfmt.Fprintf(buf, \"Anchors:    %v\\n\", c.Anchors)\n\tfmt.Fprintln(buf)\n\n\tif c.BmPrefix != nil {\n\t\tfmt.Fprintln(buf, \"BoyerMoore:\")\n\t\tfmt.Fprintln(buf, c.BmPrefix.Dump(\"    \"))\n\t}\n\tfor i := 0; i < len(c.Codes); i += opcodeSize(InstOp(c.Codes[i])) {\n\t\tfmt.Fprintln(buf, c.OpcodeDescription(i))\n\t}\n\n\treturn buf.String()\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/escape.go",
    "content": "package syntax\n\nimport (\n\t\"bytes\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n)\n\nfunc Escape(input string) string {\n\tb := &bytes.Buffer{}\n\tfor _, r := range input {\n\t\tescape(b, r, false)\n\t}\n\treturn b.String()\n}\n\nconst meta = `\\.+*?()|[]{}^$# `\n\nfunc escape(b *bytes.Buffer, r rune, force bool) {\n\tif unicode.IsPrint(r) {\n\t\tif strings.IndexRune(meta, r) >= 0 || force {\n\t\t\tb.WriteRune('\\\\')\n\t\t}\n\t\tb.WriteRune(r)\n\t\treturn\n\t}\n\n\tswitch r {\n\tcase '\\a':\n\t\tb.WriteString(`\\a`)\n\tcase '\\f':\n\t\tb.WriteString(`\\f`)\n\tcase '\\n':\n\t\tb.WriteString(`\\n`)\n\tcase '\\r':\n\t\tb.WriteString(`\\r`)\n\tcase '\\t':\n\t\tb.WriteString(`\\t`)\n\tcase '\\v':\n\t\tb.WriteString(`\\v`)\n\tdefault:\n\t\tif r < 0x100 {\n\t\t\tb.WriteString(`\\x`)\n\t\t\ts := strconv.FormatInt(int64(r), 16)\n\t\t\tif len(s) == 1 {\n\t\t\t\tb.WriteRune('0')\n\t\t\t}\n\t\t\tb.WriteString(s)\n\t\t\tbreak\n\t\t}\n\t\tb.WriteString(`\\u`)\n\t\tb.WriteString(strconv.FormatInt(int64(r), 16))\n\t}\n}\n\nfunc Unescape(input string) (string, error) {\n\tidx := strings.IndexRune(input, '\\\\')\n\t// no slashes means no unescape needed\n\tif idx == -1 {\n\t\treturn input, nil\n\t}\n\n\tbuf := bytes.NewBufferString(input[:idx])\n\t// get the runes for the rest of the string -- we're going full parser scan on this\n\n\tp := parser{}\n\tp.setPattern(input[idx+1:])\n\tfor {\n\t\tif p.rightMost() {\n\t\t\treturn \"\", p.getErr(ErrIllegalEndEscape)\n\t\t}\n\t\tr, err := p.scanCharEscape()\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tbuf.WriteRune(r)\n\t\t// are we done?\n\t\tif p.rightMost() {\n\t\t\treturn buf.String(), nil\n\t\t}\n\n\t\tr = p.moveRightGetChar()\n\t\tfor r != '\\\\' {\n\t\t\tbuf.WriteRune(r)\n\t\t\tif p.rightMost() {\n\t\t\t\t// we're done, no more slashes\n\t\t\t\treturn buf.String(), nil\n\t\t\t}\n\t\t\t// keep scanning until we get another slash\n\t\t\tr = p.moveRightGetChar()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/fuzz.go",
    "content": "// +build gofuzz\n\npackage syntax\n\n// Fuzz is the input point for go-fuzz\nfunc Fuzz(data []byte) int {\n\tsdata := string(data)\n\ttree, err := Parse(sdata, RegexOptions(0))\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\t// translate it to code\n\t_, err = Write(tree)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\treturn 1\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/parser.go",
    "content": "package syntax\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"sort\"\n\t\"strconv\"\n\t\"unicode\"\n)\n\ntype RegexOptions int32\n\nconst (\n\tIgnoreCase              RegexOptions = 0x0001 // \"i\"\n\tMultiline                            = 0x0002 // \"m\"\n\tExplicitCapture                      = 0x0004 // \"n\"\n\tCompiled                             = 0x0008 // \"c\"\n\tSingleline                           = 0x0010 // \"s\"\n\tIgnorePatternWhitespace              = 0x0020 // \"x\"\n\tRightToLeft                          = 0x0040 // \"r\"\n\tDebug                                = 0x0080 // \"d\"\n\tECMAScript                           = 0x0100 // \"e\"\n\tRE2                                  = 0x0200 // RE2 compat mode\n\tUnicode                              = 0x0400 // \"u\"\n)\n\nfunc optionFromCode(ch rune) RegexOptions {\n\t// case-insensitive\n\tswitch ch {\n\tcase 'i', 'I':\n\t\treturn IgnoreCase\n\tcase 'r', 'R':\n\t\treturn RightToLeft\n\tcase 'm', 'M':\n\t\treturn Multiline\n\tcase 'n', 'N':\n\t\treturn ExplicitCapture\n\tcase 's', 'S':\n\t\treturn Singleline\n\tcase 'x', 'X':\n\t\treturn IgnorePatternWhitespace\n\tcase 'd', 'D':\n\t\treturn Debug\n\tcase 'e', 'E':\n\t\treturn ECMAScript\n\tcase 'u', 'U':\n\t\treturn Unicode\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// An Error describes a failure to parse a regular expression\n// and gives the offending expression.\ntype Error struct {\n\tCode ErrorCode\n\tExpr string\n\tArgs []interface{}\n}\n\nfunc (e *Error) Error() string {\n\tif len(e.Args) == 0 {\n\t\treturn \"error parsing regexp: \" + e.Code.String() + \" in `\" + e.Expr + \"`\"\n\t}\n\treturn \"error parsing regexp: \" + fmt.Sprintf(e.Code.String(), e.Args...) + \" in `\" + e.Expr + \"`\"\n}\n\n// An ErrorCode describes a failure to parse a regular expression.\ntype ErrorCode string\n\nconst (\n\t// internal issue\n\tErrInternalError ErrorCode = \"regexp/syntax: internal error\"\n\t// Parser errors\n\tErrUnterminatedComment        = \"unterminated comment\"\n\tErrInvalidCharRange           = \"invalid character class range\"\n\tErrInvalidRepeatSize          = \"invalid repeat count\"\n\tErrInvalidUTF8                = \"invalid UTF-8\"\n\tErrCaptureGroupOutOfRange     = \"capture group number out of range\"\n\tErrUnexpectedParen            = \"unexpected )\"\n\tErrMissingParen               = \"missing closing )\"\n\tErrMissingBrace               = \"missing closing }\"\n\tErrInvalidRepeatOp            = \"invalid nested repetition operator\"\n\tErrMissingRepeatArgument      = \"missing argument to repetition operator\"\n\tErrConditionalExpression      = \"illegal conditional (?(...)) expression\"\n\tErrTooManyAlternates          = \"too many | in (?()|)\"\n\tErrUnrecognizedGrouping       = \"unrecognized grouping construct: (%v\"\n\tErrInvalidGroupName           = \"invalid group name: group names must begin with a word character and have a matching terminator\"\n\tErrCapNumNotZero              = \"capture number cannot be zero\"\n\tErrUndefinedBackRef           = \"reference to undefined group number %v\"\n\tErrUndefinedNameRef           = \"reference to undefined group name %v\"\n\tErrAlternationCantCapture     = \"alternation conditions do not capture and cannot be named\"\n\tErrAlternationCantHaveComment = \"alternation conditions cannot be comments\"\n\tErrMalformedReference         = \"(?(%v) ) malformed\"\n\tErrUndefinedReference         = \"(?(%v) ) reference to undefined group\"\n\tErrIllegalEndEscape           = \"illegal \\\\ at end of pattern\"\n\tErrMalformedSlashP            = \"malformed \\\\p{X} character escape\"\n\tErrIncompleteSlashP           = \"incomplete \\\\p{X} character escape\"\n\tErrUnknownSlashP              = \"unknown unicode category, script, or property '%v'\"\n\tErrUnrecognizedEscape         = \"unrecognized escape sequence \\\\%v\"\n\tErrMissingControl             = \"missing control character\"\n\tErrUnrecognizedControl        = \"unrecognized control character\"\n\tErrTooFewHex                  = \"insufficient hexadecimal digits\"\n\tErrInvalidHex                 = \"hex values may not be larger than 0x10FFFF\"\n\tErrMalformedNameRef           = \"malformed \\\\k<...> named back reference\"\n\tErrBadClassInCharRange        = \"cannot include class \\\\%v in character range\"\n\tErrUnterminatedBracket        = \"unterminated [] set\"\n\tErrSubtractionMustBeLast      = \"a subtraction must be the last element in a character class\"\n\tErrReversedCharRange          = \"[%c-%c] range in reverse order\"\n)\n\nfunc (e ErrorCode) String() string {\n\treturn string(e)\n}\n\ntype parser struct {\n\tstack         *regexNode\n\tgroup         *regexNode\n\talternation   *regexNode\n\tconcatenation *regexNode\n\tunit          *regexNode\n\n\tpatternRaw string\n\tpattern    []rune\n\n\tcurrentPos  int\n\tspecialCase *unicode.SpecialCase\n\n\tautocap  int\n\tcapcount int\n\tcaptop   int\n\tcapsize  int\n\n\tcaps     map[int]int\n\tcapnames map[string]int\n\n\tcapnumlist  []int\n\tcapnamelist []string\n\n\toptions         RegexOptions\n\toptionsStack    []RegexOptions\n\tignoreNextParen bool\n}\n\nconst (\n\tmaxValueDiv10 int = math.MaxInt32 / 10\n\tmaxValueMod10     = math.MaxInt32 % 10\n)\n\n// Parse converts a regex string into a parse tree\nfunc Parse(re string, op RegexOptions) (*RegexTree, error) {\n\tp := parser{\n\t\toptions: op,\n\t\tcaps:    make(map[int]int),\n\t}\n\tp.setPattern(re)\n\n\tif err := p.countCaptures(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tp.reset(op)\n\troot, err := p.scanRegex()\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttree := &RegexTree{\n\t\troot:       root,\n\t\tcaps:       p.caps,\n\t\tcapnumlist: p.capnumlist,\n\t\tcaptop:     p.captop,\n\t\tCapnames:   p.capnames,\n\t\tCaplist:    p.capnamelist,\n\t\toptions:    op,\n\t}\n\n\tif tree.options&Debug > 0 {\n\t\tos.Stdout.WriteString(tree.Dump())\n\t}\n\n\treturn tree, nil\n}\n\nfunc (p *parser) setPattern(pattern string) {\n\tp.patternRaw = pattern\n\tp.pattern = make([]rune, 0, len(pattern))\n\n\t//populate our rune array to handle utf8 encoding\n\tfor _, r := range pattern {\n\t\tp.pattern = append(p.pattern, r)\n\t}\n}\nfunc (p *parser) getErr(code ErrorCode, args ...interface{}) error {\n\treturn &Error{Code: code, Expr: p.patternRaw, Args: args}\n}\n\nfunc (p *parser) noteCaptureSlot(i, pos int) {\n\tif _, ok := p.caps[i]; !ok {\n\t\t// the rhs of the hashtable isn't used in the parser\n\t\tp.caps[i] = pos\n\t\tp.capcount++\n\n\t\tif p.captop <= i {\n\t\t\tif i == math.MaxInt32 {\n\t\t\t\tp.captop = i\n\t\t\t} else {\n\t\t\t\tp.captop = i + 1\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (p *parser) noteCaptureName(name string, pos int) {\n\tif p.capnames == nil {\n\t\tp.capnames = make(map[string]int)\n\t}\n\n\tif _, ok := p.capnames[name]; !ok {\n\t\tp.capnames[name] = pos\n\t\tp.capnamelist = append(p.capnamelist, name)\n\t}\n}\n\nfunc (p *parser) assignNameSlots() {\n\tif p.capnames != nil {\n\t\tfor _, name := range p.capnamelist {\n\t\t\tfor p.isCaptureSlot(p.autocap) {\n\t\t\t\tp.autocap++\n\t\t\t}\n\t\t\tpos := p.capnames[name]\n\t\t\tp.capnames[name] = p.autocap\n\t\t\tp.noteCaptureSlot(p.autocap, pos)\n\n\t\t\tp.autocap++\n\t\t}\n\t}\n\n\t// if the caps array has at least one gap, construct the list of used slots\n\tif p.capcount < p.captop {\n\t\tp.capnumlist = make([]int, p.capcount)\n\t\ti := 0\n\n\t\tfor k := range p.caps {\n\t\t\tp.capnumlist[i] = k\n\t\t\ti++\n\t\t}\n\n\t\tsort.Ints(p.capnumlist)\n\t}\n\n\t// merge capsnumlist into capnamelist\n\tif p.capnames != nil || p.capnumlist != nil {\n\t\tvar oldcapnamelist []string\n\t\tvar next int\n\t\tvar k int\n\n\t\tif p.capnames == nil {\n\t\t\toldcapnamelist = nil\n\t\t\tp.capnames = make(map[string]int)\n\t\t\tp.capnamelist = []string{}\n\t\t\tnext = -1\n\t\t} else {\n\t\t\toldcapnamelist = p.capnamelist\n\t\t\tp.capnamelist = []string{}\n\t\t\tnext = p.capnames[oldcapnamelist[0]]\n\t\t}\n\n\t\tfor i := 0; i < p.capcount; i++ {\n\t\t\tj := i\n\t\t\tif p.capnumlist != nil {\n\t\t\t\tj = p.capnumlist[i]\n\t\t\t}\n\n\t\t\tif next == j {\n\t\t\t\tp.capnamelist = append(p.capnamelist, oldcapnamelist[k])\n\t\t\t\tk++\n\n\t\t\t\tif k == len(oldcapnamelist) {\n\t\t\t\t\tnext = -1\n\t\t\t\t} else {\n\t\t\t\t\tnext = p.capnames[oldcapnamelist[k]]\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\t//feature: culture?\n\t\t\t\tstr := strconv.Itoa(j)\n\t\t\t\tp.capnamelist = append(p.capnamelist, str)\n\t\t\t\tp.capnames[str] = j\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (p *parser) consumeAutocap() int {\n\tr := p.autocap\n\tp.autocap++\n\treturn r\n}\n\n// CountCaptures is a prescanner for deducing the slots used for\n// captures by doing a partial tokenization of the pattern.\nfunc (p *parser) countCaptures() error {\n\tvar ch rune\n\n\tp.noteCaptureSlot(0, 0)\n\n\tp.autocap = 1\n\n\tfor p.charsRight() > 0 {\n\t\tpos := p.textpos()\n\t\tch = p.moveRightGetChar()\n\t\tswitch ch {\n\t\tcase '\\\\':\n\t\t\tif p.charsRight() > 0 {\n\t\t\t\tp.scanBackslash(true)\n\t\t\t}\n\n\t\tcase '#':\n\t\t\tif p.useOptionX() {\n\t\t\t\tp.moveLeft()\n\t\t\t\tp.scanBlank()\n\t\t\t}\n\n\t\tcase '[':\n\t\t\tp.scanCharSet(false, true)\n\n\t\tcase ')':\n\t\t\tif !p.emptyOptionsStack() {\n\t\t\t\tp.popOptions()\n\t\t\t}\n\n\t\tcase '(':\n\t\t\tif p.charsRight() >= 2 && p.rightChar(1) == '#' && p.rightChar(0) == '?' {\n\t\t\t\tp.moveLeft()\n\t\t\t\tp.scanBlank()\n\t\t\t} else {\n\t\t\t\tp.pushOptions()\n\t\t\t\tif p.charsRight() > 0 && p.rightChar(0) == '?' {\n\t\t\t\t\t// we have (?...\n\t\t\t\t\tp.moveRight(1)\n\n\t\t\t\t\tif p.charsRight() > 1 && (p.rightChar(0) == '<' || p.rightChar(0) == '\\'') {\n\t\t\t\t\t\t// named group: (?<... or (?'...\n\n\t\t\t\t\t\tp.moveRight(1)\n\t\t\t\t\t\tch = p.rightChar(0)\n\n\t\t\t\t\t\tif ch != '0' && IsWordChar(ch) {\n\t\t\t\t\t\t\tif ch >= '1' && ch <= '9' {\n\t\t\t\t\t\t\t\tdec, err := p.scanDecimal()\n\t\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tp.noteCaptureSlot(dec, pos)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tp.noteCaptureName(p.scanCapname(), pos)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if p.useRE2() && p.charsRight() > 2 && (p.rightChar(0) == 'P' && p.rightChar(1) == '<') {\n\t\t\t\t\t\t// RE2-compat (?P<)\n\t\t\t\t\t\tp.moveRight(2)\n\t\t\t\t\t\tch = p.rightChar(0)\n\t\t\t\t\t\tif IsWordChar(ch) {\n\t\t\t\t\t\t\tp.noteCaptureName(p.scanCapname(), pos)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// (?...\n\n\t\t\t\t\t\t// get the options if it's an option construct (?cimsx-cimsx...)\n\t\t\t\t\t\tp.scanOptions()\n\n\t\t\t\t\t\tif p.charsRight() > 0 {\n\t\t\t\t\t\t\tif p.rightChar(0) == ')' {\n\t\t\t\t\t\t\t\t// (?cimsx-cimsx)\n\t\t\t\t\t\t\t\tp.moveRight(1)\n\t\t\t\t\t\t\t\tp.popKeepOptions()\n\t\t\t\t\t\t\t} else if p.rightChar(0) == '(' {\n\t\t\t\t\t\t\t\t// alternation construct: (?(foo)yes|no)\n\t\t\t\t\t\t\t\t// ignore the next paren so we don't capture the condition\n\t\t\t\t\t\t\t\tp.ignoreNextParen = true\n\n\t\t\t\t\t\t\t\t// break from here so we don't reset ignoreNextParen\n\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif !p.useOptionN() && !p.ignoreNextParen {\n\t\t\t\t\t\tp.noteCaptureSlot(p.consumeAutocap(), pos)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tp.ignoreNextParen = false\n\n\t\t}\n\t}\n\n\tp.assignNameSlots()\n\treturn nil\n}\n\nfunc (p *parser) reset(topopts RegexOptions) {\n\tp.currentPos = 0\n\tp.autocap = 1\n\tp.ignoreNextParen = false\n\n\tif len(p.optionsStack) > 0 {\n\t\tp.optionsStack = p.optionsStack[:0]\n\t}\n\n\tp.options = topopts\n\tp.stack = nil\n}\n\nfunc (p *parser) scanRegex() (*regexNode, error) {\n\tch := '@' // nonspecial ch, means at beginning\n\tisQuant := false\n\n\tp.startGroup(newRegexNodeMN(ntCapture, p.options, 0, -1))\n\n\tfor p.charsRight() > 0 {\n\t\twasPrevQuantifier := isQuant\n\t\tisQuant = false\n\n\t\tif err := p.scanBlank(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tstartpos := p.textpos()\n\n\t\t// move past all of the normal characters.  We'll stop when we hit some kind of control character,\n\t\t// or if IgnorePatternWhiteSpace is on, we'll stop when we see some whitespace.\n\t\tif p.useOptionX() {\n\t\t\tfor p.charsRight() > 0 {\n\t\t\t\tch = p.rightChar(0)\n\t\t\t\t//UGLY: clean up, this is ugly\n\t\t\t\tif !(!isStopperX(ch) || (ch == '{' && !p.isTrueQuantifier())) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tp.moveRight(1)\n\t\t\t}\n\t\t} else {\n\t\t\tfor p.charsRight() > 0 {\n\t\t\t\tch = p.rightChar(0)\n\t\t\t\tif !(!isSpecial(ch) || ch == '{' && !p.isTrueQuantifier()) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tp.moveRight(1)\n\t\t\t}\n\t\t}\n\n\t\tendpos := p.textpos()\n\n\t\tp.scanBlank()\n\n\t\tif p.charsRight() == 0 {\n\t\t\tch = '!' // nonspecial, means at end\n\t\t} else if ch = p.rightChar(0); isSpecial(ch) {\n\t\t\tisQuant = isQuantifier(ch)\n\t\t\tp.moveRight(1)\n\t\t} else {\n\t\t\tch = ' ' // nonspecial, means at ordinary char\n\t\t}\n\n\t\tif startpos < endpos {\n\t\t\tcchUnquantified := endpos - startpos\n\t\t\tif isQuant {\n\t\t\t\tcchUnquantified--\n\t\t\t}\n\t\t\twasPrevQuantifier = false\n\n\t\t\tif cchUnquantified > 0 {\n\t\t\t\tp.addToConcatenate(startpos, cchUnquantified, false)\n\t\t\t}\n\n\t\t\tif isQuant {\n\t\t\t\tp.addUnitOne(p.charAt(endpos - 1))\n\t\t\t}\n\t\t}\n\n\t\tswitch ch {\n\t\tcase '!':\n\t\t\tgoto BreakOuterScan\n\n\t\tcase ' ':\n\t\t\tgoto ContinueOuterScan\n\n\t\tcase '[':\n\t\t\tcc, err := p.scanCharSet(p.useOptionI(), false)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tp.addUnitSet(cc)\n\n\t\tcase '(':\n\t\t\tp.pushOptions()\n\n\t\t\tif grouper, err := p.scanGroupOpen(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t} else if grouper == nil {\n\t\t\t\tp.popKeepOptions()\n\t\t\t} else {\n\t\t\t\tp.pushGroup()\n\t\t\t\tp.startGroup(grouper)\n\t\t\t}\n\n\t\t\tcontinue\n\n\t\tcase '|':\n\t\t\tp.addAlternate()\n\t\t\tgoto ContinueOuterScan\n\n\t\tcase ')':\n\t\t\tif p.emptyStack() {\n\t\t\t\treturn nil, p.getErr(ErrUnexpectedParen)\n\t\t\t}\n\n\t\t\tif err := p.addGroup(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif err := p.popGroup(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tp.popOptions()\n\n\t\t\tif p.unit == nil {\n\t\t\t\tgoto ContinueOuterScan\n\t\t\t}\n\n\t\tcase '\\\\':\n\t\t\tn, err := p.scanBackslash(false)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tp.addUnitNode(n)\n\n\t\tcase '^':\n\t\t\tif p.useOptionM() {\n\t\t\t\tp.addUnitType(ntBol)\n\t\t\t} else {\n\t\t\t\tp.addUnitType(ntBeginning)\n\t\t\t}\n\n\t\tcase '$':\n\t\t\tif p.useOptionM() {\n\t\t\t\tp.addUnitType(ntEol)\n\t\t\t} else {\n\t\t\t\tp.addUnitType(ntEndZ)\n\t\t\t}\n\n\t\tcase '.':\n\t\t\tif p.useOptionS() {\n\t\t\t\tp.addUnitSet(AnyClass())\n\t\t\t} else if p.useOptionE() {\n\t\t\t\tp.addUnitSet(ECMAAnyClass())\n\t\t\t} else {\n\t\t\t\tp.addUnitNotone('\\n')\n\t\t\t}\n\n\t\tcase '{', '*', '+', '?':\n\t\t\tif p.unit == nil {\n\t\t\t\tif wasPrevQuantifier {\n\t\t\t\t\treturn nil, p.getErr(ErrInvalidRepeatOp)\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, p.getErr(ErrMissingRepeatArgument)\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.moveLeft()\n\n\t\tdefault:\n\t\t\treturn nil, p.getErr(ErrInternalError)\n\t\t}\n\n\t\tif err := p.scanBlank(); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif p.charsRight() > 0 {\n\t\t\tisQuant = p.isTrueQuantifier()\n\t\t}\n\t\tif p.charsRight() == 0 || !isQuant {\n\t\t\t//maintain odd C# assignment order -- not sure if required, could clean up?\n\t\t\tp.addConcatenate()\n\t\t\tgoto ContinueOuterScan\n\t\t}\n\n\t\tch = p.moveRightGetChar()\n\n\t\t// Handle quantifiers\n\t\tfor p.unit != nil {\n\t\t\tvar min, max int\n\t\t\tvar lazy bool\n\n\t\t\tswitch ch {\n\t\t\tcase '*':\n\t\t\t\tmin = 0\n\t\t\t\tmax = math.MaxInt32\n\n\t\t\tcase '?':\n\t\t\t\tmin = 0\n\t\t\t\tmax = 1\n\n\t\t\tcase '+':\n\t\t\t\tmin = 1\n\t\t\t\tmax = math.MaxInt32\n\n\t\t\tcase '{':\n\t\t\t\t{\n\t\t\t\t\tvar err error\n\t\t\t\t\tstartpos = p.textpos()\n\t\t\t\t\tif min, err = p.scanDecimal(); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tmax = min\n\t\t\t\t\tif startpos < p.textpos() {\n\t\t\t\t\t\tif p.charsRight() > 0 && p.rightChar(0) == ',' {\n\t\t\t\t\t\t\tp.moveRight(1)\n\t\t\t\t\t\t\tif p.charsRight() == 0 || p.rightChar(0) == '}' {\n\t\t\t\t\t\t\t\tmax = math.MaxInt32\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif max, err = p.scanDecimal(); err != nil {\n\t\t\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif startpos == p.textpos() || p.charsRight() == 0 || p.moveRightGetChar() != '}' {\n\t\t\t\t\t\tp.addConcatenate()\n\t\t\t\t\t\tp.textto(startpos - 1)\n\t\t\t\t\t\tgoto ContinueOuterScan\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\treturn nil, p.getErr(ErrInternalError)\n\t\t\t}\n\n\t\t\tif err := p.scanBlank(); err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tif p.charsRight() == 0 || p.rightChar(0) != '?' {\n\t\t\t\tlazy = false\n\t\t\t} else {\n\t\t\t\tp.moveRight(1)\n\t\t\t\tlazy = true\n\t\t\t}\n\n\t\t\tif min > max {\n\t\t\t\treturn nil, p.getErr(ErrInvalidRepeatSize)\n\t\t\t}\n\n\t\t\tp.addConcatenate3(lazy, min, max)\n\t\t}\n\n\tContinueOuterScan:\n\t}\n\nBreakOuterScan:\n\t;\n\n\tif !p.emptyStack() {\n\t\treturn nil, p.getErr(ErrMissingParen)\n\t}\n\n\tif err := p.addGroup(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn p.unit, nil\n\n}\n\n/*\n * Simple parsing for replacement patterns\n */\nfunc (p *parser) scanReplacement() (*regexNode, error) {\n\tvar c, startpos int\n\n\tp.concatenation = newRegexNode(ntConcatenate, p.options)\n\n\tfor {\n\t\tc = p.charsRight()\n\t\tif c == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tstartpos = p.textpos()\n\n\t\tfor c > 0 && p.rightChar(0) != '$' {\n\t\t\tp.moveRight(1)\n\t\t\tc--\n\t\t}\n\n\t\tp.addToConcatenate(startpos, p.textpos()-startpos, true)\n\n\t\tif c > 0 {\n\t\t\tif p.moveRightGetChar() == '$' {\n\t\t\t\tn, err := p.scanDollar()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tp.addUnitNode(n)\n\t\t\t}\n\t\t\tp.addConcatenate()\n\t\t}\n\t}\n\n\treturn p.concatenation, nil\n}\n\n/*\n * Scans $ patterns recognized within replacement patterns\n */\nfunc (p *parser) scanDollar() (*regexNode, error) {\n\tif p.charsRight() == 0 {\n\t\treturn newRegexNodeCh(ntOne, p.options, '$'), nil\n\t}\n\n\tch := p.rightChar(0)\n\tangled := false\n\tbackpos := p.textpos()\n\tlastEndPos := backpos\n\n\t// Note angle\n\n\tif ch == '{' && p.charsRight() > 1 {\n\t\tangled = true\n\t\tp.moveRight(1)\n\t\tch = p.rightChar(0)\n\t}\n\n\t// Try to parse backreference: \\1 or \\{1} or \\{cap}\n\n\tif ch >= '0' && ch <= '9' {\n\t\tif !angled && p.useOptionE() {\n\t\t\tcapnum := -1\n\t\t\tnewcapnum := int(ch - '0')\n\t\t\tp.moveRight(1)\n\t\t\tif p.isCaptureSlot(newcapnum) {\n\t\t\t\tcapnum = newcapnum\n\t\t\t\tlastEndPos = p.textpos()\n\t\t\t}\n\n\t\t\tfor p.charsRight() > 0 {\n\t\t\t\tch = p.rightChar(0)\n\t\t\t\tif ch < '0' || ch > '9' {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tdigit := int(ch - '0')\n\t\t\t\tif newcapnum > maxValueDiv10 || (newcapnum == maxValueDiv10 && digit > maxValueMod10) {\n\t\t\t\t\treturn nil, p.getErr(ErrCaptureGroupOutOfRange)\n\t\t\t\t}\n\n\t\t\t\tnewcapnum = newcapnum*10 + digit\n\n\t\t\t\tp.moveRight(1)\n\t\t\t\tif p.isCaptureSlot(newcapnum) {\n\t\t\t\t\tcapnum = newcapnum\n\t\t\t\t\tlastEndPos = p.textpos()\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.textto(lastEndPos)\n\t\t\tif capnum >= 0 {\n\t\t\t\treturn newRegexNodeM(ntRef, p.options, capnum), nil\n\t\t\t}\n\t\t} else {\n\t\t\tcapnum, err := p.scanDecimal()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif !angled || p.charsRight() > 0 && p.moveRightGetChar() == '}' {\n\t\t\t\tif p.isCaptureSlot(capnum) {\n\t\t\t\t\treturn newRegexNodeM(ntRef, p.options, capnum), nil\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else if angled && IsWordChar(ch) {\n\t\tcapname := p.scanCapname()\n\n\t\tif p.charsRight() > 0 && p.moveRightGetChar() == '}' {\n\t\t\tif p.isCaptureName(capname) {\n\t\t\t\treturn newRegexNodeM(ntRef, p.options, p.captureSlotFromName(capname)), nil\n\t\t\t}\n\t\t}\n\t} else if !angled {\n\t\tcapnum := 1\n\n\t\tswitch ch {\n\t\tcase '$':\n\t\t\tp.moveRight(1)\n\t\t\treturn newRegexNodeCh(ntOne, p.options, '$'), nil\n\t\tcase '&':\n\t\t\tcapnum = 0\n\t\tcase '`':\n\t\t\tcapnum = replaceLeftPortion\n\t\tcase '\\'':\n\t\t\tcapnum = replaceRightPortion\n\t\tcase '+':\n\t\t\tcapnum = replaceLastGroup\n\t\tcase '_':\n\t\t\tcapnum = replaceWholeString\n\t\t}\n\n\t\tif capnum != 1 {\n\t\t\tp.moveRight(1)\n\t\t\treturn newRegexNodeM(ntRef, p.options, capnum), nil\n\t\t}\n\t}\n\n\t// unrecognized $: literalize\n\n\tp.textto(backpos)\n\treturn newRegexNodeCh(ntOne, p.options, '$'), nil\n}\n\n// scanGroupOpen scans chars following a '(' (not counting the '('), and returns\n// a RegexNode for the type of group scanned, or nil if the group\n// simply changed options (?cimsx-cimsx) or was a comment (#...).\nfunc (p *parser) scanGroupOpen() (*regexNode, error) {\n\tvar ch rune\n\tvar nt nodeType\n\tvar err error\n\tclose := '>'\n\tstart := p.textpos()\n\n\t// just return a RegexNode if we have:\n\t// 1. \"(\" followed by nothing\n\t// 2. \"(x\" where x != ?\n\t// 3. \"(?)\"\n\tif p.charsRight() == 0 || p.rightChar(0) != '?' || (p.rightChar(0) == '?' && (p.charsRight() > 1 && p.rightChar(1) == ')')) {\n\t\tif p.useOptionN() || p.ignoreNextParen {\n\t\t\tp.ignoreNextParen = false\n\t\t\treturn newRegexNode(ntGroup, p.options), nil\n\t\t}\n\t\treturn newRegexNodeMN(ntCapture, p.options, p.consumeAutocap(), -1), nil\n\t}\n\n\tp.moveRight(1)\n\n\tfor {\n\t\tif p.charsRight() == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tswitch ch = p.moveRightGetChar(); ch {\n\t\tcase ':':\n\t\t\tnt = ntGroup\n\n\t\tcase '=':\n\t\t\tp.options &= ^RightToLeft\n\t\t\tnt = ntRequire\n\n\t\tcase '!':\n\t\t\tp.options &= ^RightToLeft\n\t\t\tnt = ntPrevent\n\n\t\tcase '>':\n\t\t\tnt = ntGreedy\n\n\t\tcase '\\'':\n\t\t\tclose = '\\''\n\t\t\tfallthrough\n\n\t\tcase '<':\n\t\t\tif p.charsRight() == 0 {\n\t\t\t\tgoto BreakRecognize\n\t\t\t}\n\n\t\t\tswitch ch = p.moveRightGetChar(); ch {\n\t\t\tcase '=':\n\t\t\t\tif close == '\\'' {\n\t\t\t\t\tgoto BreakRecognize\n\t\t\t\t}\n\n\t\t\t\tp.options |= RightToLeft\n\t\t\t\tnt = ntRequire\n\n\t\t\tcase '!':\n\t\t\t\tif close == '\\'' {\n\t\t\t\t\tgoto BreakRecognize\n\t\t\t\t}\n\n\t\t\t\tp.options |= RightToLeft\n\t\t\t\tnt = ntPrevent\n\n\t\t\tdefault:\n\t\t\t\tp.moveLeft()\n\t\t\t\tcapnum := -1\n\t\t\t\tuncapnum := -1\n\t\t\t\tproceed := false\n\n\t\t\t\t// grab part before -\n\n\t\t\t\tif ch >= '0' && ch <= '9' {\n\t\t\t\t\tif capnum, err = p.scanDecimal(); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\n\t\t\t\t\tif !p.isCaptureSlot(capnum) {\n\t\t\t\t\t\tcapnum = -1\n\t\t\t\t\t}\n\n\t\t\t\t\t// check if we have bogus characters after the number\n\t\t\t\t\tif p.charsRight() > 0 && !(p.rightChar(0) == close || p.rightChar(0) == '-') {\n\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t\t}\n\t\t\t\t\tif capnum == 0 {\n\t\t\t\t\t\treturn nil, p.getErr(ErrCapNumNotZero)\n\t\t\t\t\t}\n\t\t\t\t} else if IsWordChar(ch) {\n\t\t\t\t\tcapname := p.scanCapname()\n\n\t\t\t\t\tif p.isCaptureName(capname) {\n\t\t\t\t\t\tcapnum = p.captureSlotFromName(capname)\n\t\t\t\t\t}\n\n\t\t\t\t\t// check if we have bogus character after the name\n\t\t\t\t\tif p.charsRight() > 0 && !(p.rightChar(0) == close || p.rightChar(0) == '-') {\n\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t\t}\n\t\t\t\t} else if ch == '-' {\n\t\t\t\t\tproceed = true\n\t\t\t\t} else {\n\t\t\t\t\t// bad group name - starts with something other than a word character and isn't a number\n\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t}\n\n\t\t\t\t// grab part after - if any\n\n\t\t\t\tif (capnum != -1 || proceed == true) && p.charsRight() > 0 && p.rightChar(0) == '-' {\n\t\t\t\t\tp.moveRight(1)\n\n\t\t\t\t\t//no more chars left, no closing char, etc\n\t\t\t\t\tif p.charsRight() == 0 {\n\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t\t}\n\n\t\t\t\t\tch = p.rightChar(0)\n\t\t\t\t\tif ch >= '0' && ch <= '9' {\n\t\t\t\t\t\tif uncapnum, err = p.scanDecimal(); err != nil {\n\t\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif !p.isCaptureSlot(uncapnum) {\n\t\t\t\t\t\t\treturn nil, p.getErr(ErrUndefinedBackRef, uncapnum)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// check if we have bogus characters after the number\n\t\t\t\t\t\tif p.charsRight() > 0 && p.rightChar(0) != close {\n\t\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if IsWordChar(ch) {\n\t\t\t\t\t\tuncapname := p.scanCapname()\n\n\t\t\t\t\t\tif !p.isCaptureName(uncapname) {\n\t\t\t\t\t\t\treturn nil, p.getErr(ErrUndefinedNameRef, uncapname)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tuncapnum = p.captureSlotFromName(uncapname)\n\n\t\t\t\t\t\t// check if we have bogus character after the name\n\t\t\t\t\t\tif p.charsRight() > 0 && p.rightChar(0) != close {\n\t\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// bad group name - starts with something other than a word character and isn't a number\n\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// actually make the node\n\n\t\t\t\tif (capnum != -1 || uncapnum != -1) && p.charsRight() > 0 && p.moveRightGetChar() == close {\n\t\t\t\t\treturn newRegexNodeMN(ntCapture, p.options, capnum, uncapnum), nil\n\t\t\t\t}\n\t\t\t\tgoto BreakRecognize\n\t\t\t}\n\n\t\tcase '(':\n\t\t\t// alternation construct (?(...) | )\n\n\t\t\tparenPos := p.textpos()\n\t\t\tif p.charsRight() > 0 {\n\t\t\t\tch = p.rightChar(0)\n\n\t\t\t\t// check if the alternation condition is a backref\n\t\t\t\tif ch >= '0' && ch <= '9' {\n\t\t\t\t\tvar capnum int\n\t\t\t\t\tif capnum, err = p.scanDecimal(); err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tif p.charsRight() > 0 && p.moveRightGetChar() == ')' {\n\t\t\t\t\t\tif p.isCaptureSlot(capnum) {\n\t\t\t\t\t\t\treturn newRegexNodeM(ntTestref, p.options, capnum), nil\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil, p.getErr(ErrUndefinedReference, capnum)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil, p.getErr(ErrMalformedReference, capnum)\n\n\t\t\t\t} else if IsWordChar(ch) {\n\t\t\t\t\tcapname := p.scanCapname()\n\n\t\t\t\t\tif p.isCaptureName(capname) && p.charsRight() > 0 && p.moveRightGetChar() == ')' {\n\t\t\t\t\t\treturn newRegexNodeM(ntTestref, p.options, p.captureSlotFromName(capname)), nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// not a backref\n\t\t\tnt = ntTestgroup\n\t\t\tp.textto(parenPos - 1)   // jump to the start of the parentheses\n\t\t\tp.ignoreNextParen = true // but make sure we don't try to capture the insides\n\n\t\t\tcharsRight := p.charsRight()\n\t\t\tif charsRight >= 3 && p.rightChar(1) == '?' {\n\t\t\t\trightchar2 := p.rightChar(2)\n\t\t\t\t// disallow comments in the condition\n\t\t\t\tif rightchar2 == '#' {\n\t\t\t\t\treturn nil, p.getErr(ErrAlternationCantHaveComment)\n\t\t\t\t}\n\n\t\t\t\t// disallow named capture group (?<..>..) in the condition\n\t\t\t\tif rightchar2 == '\\'' {\n\t\t\t\t\treturn nil, p.getErr(ErrAlternationCantCapture)\n\t\t\t\t}\n\n\t\t\t\tif charsRight >= 4 && (rightchar2 == '<' && p.rightChar(3) != '!' && p.rightChar(3) != '=') {\n\t\t\t\t\treturn nil, p.getErr(ErrAlternationCantCapture)\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase 'P':\n\t\t\tif p.useRE2() {\n\t\t\t\t// support for P<name> syntax\n\t\t\t\tif p.charsRight() < 3 {\n\t\t\t\t\tgoto BreakRecognize\n\t\t\t\t}\n\n\t\t\t\tch = p.moveRightGetChar()\n\t\t\t\tif ch != '<' {\n\t\t\t\t\tgoto BreakRecognize\n\t\t\t\t}\n\n\t\t\t\tch = p.moveRightGetChar()\n\t\t\t\tp.moveLeft()\n\n\t\t\t\tif IsWordChar(ch) {\n\t\t\t\t\tcapnum := -1\n\t\t\t\t\tcapname := p.scanCapname()\n\n\t\t\t\t\tif p.isCaptureName(capname) {\n\t\t\t\t\t\tcapnum = p.captureSlotFromName(capname)\n\t\t\t\t\t}\n\n\t\t\t\t\t// check if we have bogus character after the name\n\t\t\t\t\tif p.charsRight() > 0 && p.rightChar(0) != '>' {\n\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t\t}\n\n\t\t\t\t\t// actually make the node\n\n\t\t\t\t\tif capnum != -1 && p.charsRight() > 0 && p.moveRightGetChar() == '>' {\n\t\t\t\t\t\treturn newRegexNodeMN(ntCapture, p.options, capnum, -1), nil\n\t\t\t\t\t}\n\t\t\t\t\tgoto BreakRecognize\n\n\t\t\t\t} else {\n\t\t\t\t\t// bad group name - starts with something other than a word character and isn't a number\n\t\t\t\t\treturn nil, p.getErr(ErrInvalidGroupName)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// if we're not using RE2 compat mode then\n\t\t\t// we just behave like normal\n\t\t\tfallthrough\n\n\t\tdefault:\n\t\t\tp.moveLeft()\n\n\t\t\tnt = ntGroup\n\t\t\t// disallow options in the children of a testgroup node\n\t\t\tif p.group.t != ntTestgroup {\n\t\t\t\tp.scanOptions()\n\t\t\t}\n\t\t\tif p.charsRight() == 0 {\n\t\t\t\tgoto BreakRecognize\n\t\t\t}\n\n\t\t\tif ch = p.moveRightGetChar(); ch == ')' {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\n\t\t\tif ch != ':' {\n\t\t\t\tgoto BreakRecognize\n\t\t\t}\n\n\t\t}\n\n\t\treturn newRegexNode(nt, p.options), nil\n\t}\n\nBreakRecognize:\n\n\t// break Recognize comes here\n\n\treturn nil, p.getErr(ErrUnrecognizedGrouping, string(p.pattern[start:p.textpos()]))\n}\n\n// scans backslash specials and basics\nfunc (p *parser) scanBackslash(scanOnly bool) (*regexNode, error) {\n\n\tif p.charsRight() == 0 {\n\t\treturn nil, p.getErr(ErrIllegalEndEscape)\n\t}\n\n\tswitch ch := p.rightChar(0); ch {\n\tcase 'b', 'B', 'A', 'G', 'Z', 'z':\n\t\tp.moveRight(1)\n\t\treturn newRegexNode(p.typeFromCode(ch), p.options), nil\n\n\tcase 'w':\n\t\tp.moveRight(1)\n\t\tif p.useOptionE() || p.useRE2() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, ECMAWordClass()), nil\n\t\t}\n\t\treturn newRegexNodeSet(ntSet, p.options, WordClass()), nil\n\n\tcase 'W':\n\t\tp.moveRight(1)\n\t\tif p.useOptionE() || p.useRE2() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, NotECMAWordClass()), nil\n\t\t}\n\t\treturn newRegexNodeSet(ntSet, p.options, NotWordClass()), nil\n\n\tcase 's':\n\t\tp.moveRight(1)\n\t\tif p.useOptionE() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, ECMASpaceClass()), nil\n\t\t} else if p.useRE2() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, RE2SpaceClass()), nil\n\t\t}\n\t\treturn newRegexNodeSet(ntSet, p.options, SpaceClass()), nil\n\n\tcase 'S':\n\t\tp.moveRight(1)\n\t\tif p.useOptionE() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, NotECMASpaceClass()), nil\n\t\t} else if p.useRE2() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, NotRE2SpaceClass()), nil\n\t\t}\n\t\treturn newRegexNodeSet(ntSet, p.options, NotSpaceClass()), nil\n\n\tcase 'd':\n\t\tp.moveRight(1)\n\t\tif p.useOptionE() || p.useRE2() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, ECMADigitClass()), nil\n\t\t}\n\t\treturn newRegexNodeSet(ntSet, p.options, DigitClass()), nil\n\n\tcase 'D':\n\t\tp.moveRight(1)\n\t\tif p.useOptionE() || p.useRE2() {\n\t\t\treturn newRegexNodeSet(ntSet, p.options, NotECMADigitClass()), nil\n\t\t}\n\t\treturn newRegexNodeSet(ntSet, p.options, NotDigitClass()), nil\n\n\tcase 'p', 'P':\n\t\tp.moveRight(1)\n\t\tprop, err := p.parseProperty()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcc := &CharSet{}\n\t\tcc.addCategory(prop, (ch != 'p'), p.useOptionI(), p.patternRaw)\n\t\tif p.useOptionI() {\n\t\t\tcc.addLowercase()\n\t\t}\n\n\t\treturn newRegexNodeSet(ntSet, p.options, cc), nil\n\n\tdefault:\n\t\treturn p.scanBasicBackslash(scanOnly)\n\t}\n}\n\n// Scans \\-style backreferences and character escapes\nfunc (p *parser) scanBasicBackslash(scanOnly bool) (*regexNode, error) {\n\tif p.charsRight() == 0 {\n\t\treturn nil, p.getErr(ErrIllegalEndEscape)\n\t}\n\tangled := false\n\tk := false\n\tclose := '\\x00'\n\n\tbackpos := p.textpos()\n\tch := p.rightChar(0)\n\n\t// Allow \\k<foo> instead of \\<foo>, which is now deprecated.\n\n\t// According to ECMAScript specification, \\k<name> is only parsed as a named group reference if\n\t// there is at least one group name in the regexp.\n\t// See https://www.ecma-international.org/ecma-262/#sec-isvalidregularexpressionliteral, step 7.\n\t// Note, during the first (scanOnly) run we may not have all group names scanned, but that's ok.\n\tif ch == 'k' && (!p.useOptionE() || len(p.capnames) > 0) {\n\t\tif p.charsRight() >= 2 {\n\t\t\tp.moveRight(1)\n\t\t\tch = p.moveRightGetChar()\n\n\t\t\tif ch == '<' || (!p.useOptionE() && ch == '\\'') { // No support for \\k'name' in ECMAScript\n\t\t\t\tangled = true\n\t\t\t\tif ch == '\\'' {\n\t\t\t\t\tclose = '\\''\n\t\t\t\t} else {\n\t\t\t\t\tclose = '>'\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif !angled || p.charsRight() <= 0 {\n\t\t\treturn nil, p.getErr(ErrMalformedNameRef)\n\t\t}\n\n\t\tch = p.rightChar(0)\n\t\tk = true\n\n\t} else if !p.useOptionE() && (ch == '<' || ch == '\\'') && p.charsRight() > 1 { // Note angle without \\g\n\t\tangled = true\n\t\tif ch == '\\'' {\n\t\t\tclose = '\\''\n\t\t} else {\n\t\t\tclose = '>'\n\t\t}\n\n\t\tp.moveRight(1)\n\t\tch = p.rightChar(0)\n\t}\n\n\t// Try to parse backreference: \\<1> or \\<cap>\n\n\tif angled && ch >= '0' && ch <= '9' {\n\t\tcapnum, err := p.scanDecimal()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif p.charsRight() > 0 && p.moveRightGetChar() == close {\n\t\t\tif p.isCaptureSlot(capnum) {\n\t\t\t\treturn newRegexNodeM(ntRef, p.options, capnum), nil\n\t\t\t}\n\t\t\treturn nil, p.getErr(ErrUndefinedBackRef, capnum)\n\t\t}\n\t} else if !angled && ch >= '1' && ch <= '9' { // Try to parse backreference or octal: \\1\n\t\tcapnum, err := p.scanDecimal()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif scanOnly {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\tif p.isCaptureSlot(capnum) {\n\t\t\treturn newRegexNodeM(ntRef, p.options, capnum), nil\n\t\t}\n\t\tif capnum <= 9 && !p.useOptionE() {\n\t\t\treturn nil, p.getErr(ErrUndefinedBackRef, capnum)\n\t\t}\n\n\t} else if angled {\n\t\tcapname := p.scanCapname()\n\n\t\tif capname != \"\" && p.charsRight() > 0 && p.moveRightGetChar() == close {\n\n\t\t\tif scanOnly {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\n\t\t\tif p.isCaptureName(capname) {\n\t\t\t\treturn newRegexNodeM(ntRef, p.options, p.captureSlotFromName(capname)), nil\n\t\t\t}\n\t\t\treturn nil, p.getErr(ErrUndefinedNameRef, capname)\n\t\t} else {\n\t\t\tif k {\n\t\t\t\treturn nil, p.getErr(ErrMalformedNameRef)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Not backreference: must be char code\n\n\tp.textto(backpos)\n\tch, err := p.scanCharEscape()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif scanOnly {\n\t\treturn nil, nil\n\t}\n\n\tif p.useOptionI() {\n\t\tch = unicode.ToLower(ch)\n\t}\n\n\treturn newRegexNodeCh(ntOne, p.options, ch), nil\n}\n\n// Scans X for \\p{X} or \\P{X}\nfunc (p *parser) parseProperty() (string, error) {\n\t// RE2 and PCRE supports \\pX syntax (no {} and only 1 letter unicode cats supported)\n\t// since this is purely additive syntax it's not behind a flag\n\tif p.charsRight() >= 1 && p.rightChar(0) != '{' {\n\t\tch := string(p.moveRightGetChar())\n\t\t// check if it's a valid cat\n\t\tif !isValidUnicodeCat(ch) {\n\t\t\treturn \"\", p.getErr(ErrUnknownSlashP, ch)\n\t\t}\n\t\treturn ch, nil\n\t}\n\n\tif p.charsRight() < 3 {\n\t\treturn \"\", p.getErr(ErrIncompleteSlashP)\n\t}\n\tch := p.moveRightGetChar()\n\tif ch != '{' {\n\t\treturn \"\", p.getErr(ErrMalformedSlashP)\n\t}\n\n\tstartpos := p.textpos()\n\tfor p.charsRight() > 0 {\n\t\tch = p.moveRightGetChar()\n\t\tif !(IsWordChar(ch) || ch == '-') {\n\t\t\tp.moveLeft()\n\t\t\tbreak\n\t\t}\n\t}\n\tcapname := string(p.pattern[startpos:p.textpos()])\n\n\tif p.charsRight() == 0 || p.moveRightGetChar() != '}' {\n\t\treturn \"\", p.getErr(ErrIncompleteSlashP)\n\t}\n\n\tif !isValidUnicodeCat(capname) {\n\t\treturn \"\", p.getErr(ErrUnknownSlashP, capname)\n\t}\n\n\treturn capname, nil\n}\n\n// Returns ReNode type for zero-length assertions with a \\ code.\nfunc (p *parser) typeFromCode(ch rune) nodeType {\n\tswitch ch {\n\tcase 'b':\n\t\tif p.useOptionE() {\n\t\t\treturn ntECMABoundary\n\t\t}\n\t\treturn ntBoundary\n\tcase 'B':\n\t\tif p.useOptionE() {\n\t\t\treturn ntNonECMABoundary\n\t\t}\n\t\treturn ntNonboundary\n\tcase 'A':\n\t\treturn ntBeginning\n\tcase 'G':\n\t\treturn ntStart\n\tcase 'Z':\n\t\treturn ntEndZ\n\tcase 'z':\n\t\treturn ntEnd\n\tdefault:\n\t\treturn ntNothing\n\t}\n}\n\n// Scans whitespace or x-mode comments.\nfunc (p *parser) scanBlank() error {\n\tif p.useOptionX() {\n\t\tfor {\n\t\t\tfor p.charsRight() > 0 && isSpace(p.rightChar(0)) {\n\t\t\t\tp.moveRight(1)\n\t\t\t}\n\n\t\t\tif p.charsRight() == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif p.rightChar(0) == '#' {\n\t\t\t\tfor p.charsRight() > 0 && p.rightChar(0) != '\\n' {\n\t\t\t\t\tp.moveRight(1)\n\t\t\t\t}\n\t\t\t} else if p.charsRight() >= 3 && p.rightChar(2) == '#' &&\n\t\t\t\tp.rightChar(1) == '?' && p.rightChar(0) == '(' {\n\t\t\t\tfor p.charsRight() > 0 && p.rightChar(0) != ')' {\n\t\t\t\t\tp.moveRight(1)\n\t\t\t\t}\n\t\t\t\tif p.charsRight() == 0 {\n\t\t\t\t\treturn p.getErr(ErrUnterminatedComment)\n\t\t\t\t}\n\t\t\t\tp.moveRight(1)\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor {\n\t\t\tif p.charsRight() < 3 || p.rightChar(2) != '#' ||\n\t\t\t\tp.rightChar(1) != '?' || p.rightChar(0) != '(' {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\tfor p.charsRight() > 0 && p.rightChar(0) != ')' {\n\t\t\t\tp.moveRight(1)\n\t\t\t}\n\t\t\tif p.charsRight() == 0 {\n\t\t\t\treturn p.getErr(ErrUnterminatedComment)\n\t\t\t}\n\t\t\tp.moveRight(1)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (p *parser) scanCapname() string {\n\tstartpos := p.textpos()\n\n\tfor p.charsRight() > 0 {\n\t\tif !IsWordChar(p.moveRightGetChar()) {\n\t\t\tp.moveLeft()\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn string(p.pattern[startpos:p.textpos()])\n}\n\n// Scans contents of [] (not including []'s), and converts to a set.\nfunc (p *parser) scanCharSet(caseInsensitive, scanOnly bool) (*CharSet, error) {\n\tch := '\\x00'\n\tchPrev := '\\x00'\n\tinRange := false\n\tfirstChar := true\n\tclosed := false\n\n\tvar cc *CharSet\n\tif !scanOnly {\n\t\tcc = &CharSet{}\n\t}\n\n\tif p.charsRight() > 0 && p.rightChar(0) == '^' {\n\t\tp.moveRight(1)\n\t\tif !scanOnly {\n\t\t\tcc.negate = true\n\t\t}\n\t}\n\n\tfor ; p.charsRight() > 0; firstChar = false {\n\t\tfTranslatedChar := false\n\t\tch = p.moveRightGetChar()\n\t\tif ch == ']' {\n\t\t\tif !firstChar {\n\t\t\t\tclosed = true\n\t\t\t\tbreak\n\t\t\t} else if p.useOptionE() {\n\t\t\t\tif !scanOnly {\n\t\t\t\t\tcc.addRanges(NoneClass().ranges)\n\t\t\t\t}\n\t\t\t\tclosed = true\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t} else if ch == '\\\\' && p.charsRight() > 0 {\n\t\t\tswitch ch = p.moveRightGetChar(); ch {\n\t\t\tcase 'D', 'd':\n\t\t\t\tif !scanOnly {\n\t\t\t\t\tif inRange {\n\t\t\t\t\t\treturn nil, p.getErr(ErrBadClassInCharRange, ch)\n\t\t\t\t\t}\n\t\t\t\t\tcc.addDigit(p.useOptionE() || p.useRE2(), ch == 'D', p.patternRaw)\n\t\t\t\t}\n\t\t\t\tcontinue\n\n\t\t\tcase 'S', 's':\n\t\t\t\tif !scanOnly {\n\t\t\t\t\tif inRange {\n\t\t\t\t\t\treturn nil, p.getErr(ErrBadClassInCharRange, ch)\n\t\t\t\t\t}\n\t\t\t\t\tcc.addSpace(p.useOptionE(), p.useRE2(), ch == 'S')\n\t\t\t\t}\n\t\t\t\tcontinue\n\n\t\t\tcase 'W', 'w':\n\t\t\t\tif !scanOnly {\n\t\t\t\t\tif inRange {\n\t\t\t\t\t\treturn nil, p.getErr(ErrBadClassInCharRange, ch)\n\t\t\t\t\t}\n\n\t\t\t\t\tcc.addWord(p.useOptionE() || p.useRE2(), ch == 'W')\n\t\t\t\t}\n\t\t\t\tcontinue\n\n\t\t\tcase 'p', 'P':\n\t\t\t\tif !scanOnly {\n\t\t\t\t\tif inRange {\n\t\t\t\t\t\treturn nil, p.getErr(ErrBadClassInCharRange, ch)\n\t\t\t\t\t}\n\t\t\t\t\tprop, err := p.parseProperty()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tcc.addCategory(prop, (ch != 'p'), caseInsensitive, p.patternRaw)\n\t\t\t\t} else {\n\t\t\t\t\tp.parseProperty()\n\t\t\t\t}\n\n\t\t\t\tcontinue\n\n\t\t\tcase '-':\n\t\t\t\tif !scanOnly {\n\t\t\t\t\tcc.addRange(ch, ch)\n\t\t\t\t}\n\t\t\t\tcontinue\n\n\t\t\tdefault:\n\t\t\t\tp.moveLeft()\n\t\t\t\tvar err error\n\t\t\t\tch, err = p.scanCharEscape() // non-literal character\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tfTranslatedChar = true\n\t\t\t\tbreak // this break will only break out of the switch\n\t\t\t}\n\t\t} else if ch == '[' {\n\t\t\t// This is code for Posix style properties - [:Ll:] or [:IsTibetan:].\n\t\t\t// It currently doesn't do anything other than skip the whole thing!\n\t\t\tif p.charsRight() > 0 && p.rightChar(0) == ':' && !inRange {\n\t\t\t\tsavePos := p.textpos()\n\n\t\t\t\tp.moveRight(1)\n\t\t\t\tnegate := false\n\t\t\t\tif p.charsRight() > 1 && p.rightChar(0) == '^' {\n\t\t\t\t\tnegate = true\n\t\t\t\t\tp.moveRight(1)\n\t\t\t\t}\n\n\t\t\t\tnm := p.scanCapname() // snag the name\n\t\t\t\tif !scanOnly && p.useRE2() {\n\t\t\t\t\t// look up the name since these are valid for RE2\n\t\t\t\t\t// add the group based on the name\n\t\t\t\t\tif ok := cc.addNamedASCII(nm, negate); !ok {\n\t\t\t\t\t\treturn nil, p.getErr(ErrInvalidCharRange)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif p.charsRight() < 2 || p.moveRightGetChar() != ':' || p.moveRightGetChar() != ']' {\n\t\t\t\t\tp.textto(savePos)\n\t\t\t\t} else if p.useRE2() {\n\t\t\t\t\t// move on\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif inRange {\n\t\t\tinRange = false\n\t\t\tif !scanOnly {\n\t\t\t\tif ch == '[' && !fTranslatedChar && !firstChar {\n\t\t\t\t\t// We thought we were in a range, but we're actually starting a subtraction.\n\t\t\t\t\t// In that case, we'll add chPrev to our char class, skip the opening [, and\n\t\t\t\t\t// scan the new character class recursively.\n\t\t\t\t\tcc.addChar(chPrev)\n\t\t\t\t\tsub, err := p.scanCharSet(caseInsensitive, false)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn nil, err\n\t\t\t\t\t}\n\t\t\t\t\tcc.addSubtraction(sub)\n\n\t\t\t\t\tif p.charsRight() > 0 && p.rightChar(0) != ']' {\n\t\t\t\t\t\treturn nil, p.getErr(ErrSubtractionMustBeLast)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// a regular range, like a-z\n\t\t\t\t\tif chPrev > ch {\n\t\t\t\t\t\treturn nil, p.getErr(ErrReversedCharRange, chPrev, ch)\n\t\t\t\t\t}\n\t\t\t\t\tcc.addRange(chPrev, ch)\n\t\t\t\t}\n\t\t\t}\n\t\t} else if p.charsRight() >= 2 && p.rightChar(0) == '-' && p.rightChar(1) != ']' {\n\t\t\t// this could be the start of a range\n\t\t\tchPrev = ch\n\t\t\tinRange = true\n\t\t\tp.moveRight(1)\n\t\t} else if p.charsRight() >= 1 && ch == '-' && !fTranslatedChar && p.rightChar(0) == '[' && !firstChar {\n\t\t\t// we aren't in a range, and now there is a subtraction.  Usually this happens\n\t\t\t// only when a subtraction follows a range, like [a-z-[b]]\n\t\t\tif !scanOnly {\n\t\t\t\tp.moveRight(1)\n\t\t\t\tsub, err := p.scanCharSet(caseInsensitive, false)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tcc.addSubtraction(sub)\n\n\t\t\t\tif p.charsRight() > 0 && p.rightChar(0) != ']' {\n\t\t\t\t\treturn nil, p.getErr(ErrSubtractionMustBeLast)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tp.moveRight(1)\n\t\t\t\tp.scanCharSet(caseInsensitive, true)\n\t\t\t}\n\t\t} else {\n\t\t\tif !scanOnly {\n\t\t\t\tcc.addRange(ch, ch)\n\t\t\t}\n\t\t}\n\t}\n\n\tif !closed {\n\t\treturn nil, p.getErr(ErrUnterminatedBracket)\n\t}\n\n\tif !scanOnly && caseInsensitive {\n\t\tcc.addLowercase()\n\t}\n\n\treturn cc, nil\n}\n\n// Scans any number of decimal digits (pegs value at 2^31-1 if too large)\nfunc (p *parser) scanDecimal() (int, error) {\n\ti := 0\n\tvar d int\n\n\tfor p.charsRight() > 0 {\n\t\td = int(p.rightChar(0) - '0')\n\t\tif d < 0 || d > 9 {\n\t\t\tbreak\n\t\t}\n\t\tp.moveRight(1)\n\n\t\tif i > maxValueDiv10 || (i == maxValueDiv10 && d > maxValueMod10) {\n\t\t\treturn 0, p.getErr(ErrCaptureGroupOutOfRange)\n\t\t}\n\n\t\ti *= 10\n\t\ti += d\n\t}\n\n\treturn int(i), nil\n}\n\n// Returns true for options allowed only at the top level\nfunc isOnlyTopOption(option RegexOptions) bool {\n\treturn option == RightToLeft || option == ECMAScript || option == RE2\n}\n\n// Scans cimsx-cimsx option string, stops at the first unrecognized char.\nfunc (p *parser) scanOptions() {\n\n\tfor off := false; p.charsRight() > 0; p.moveRight(1) {\n\t\tch := p.rightChar(0)\n\n\t\tif ch == '-' {\n\t\t\toff = true\n\t\t} else if ch == '+' {\n\t\t\toff = false\n\t\t} else {\n\t\t\toption := optionFromCode(ch)\n\t\t\tif option == 0 || isOnlyTopOption(option) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif off {\n\t\t\t\tp.options &= ^option\n\t\t\t} else {\n\t\t\t\tp.options |= option\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Scans \\ code for escape codes that map to single unicode chars.\nfunc (p *parser) scanCharEscape() (r rune, err error) {\n\n\tch := p.moveRightGetChar()\n\n\tif ch >= '0' && ch <= '7' {\n\t\tp.moveLeft()\n\t\treturn p.scanOctal(), nil\n\t}\n\n\tpos := p.textpos()\n\n\tswitch ch {\n\tcase 'x':\n\t\t// support for \\x{HEX} syntax from Perl and PCRE\n\t\tif p.charsRight() > 0 && p.rightChar(0) == '{' {\n\t\t\tif p.useOptionE() {\n\t\t\t\treturn ch, nil\n\t\t\t}\n\t\t\tp.moveRight(1)\n\t\t\treturn p.scanHexUntilBrace()\n\t\t} else {\n\t\t\tr, err = p.scanHex(2)\n\t\t}\n\tcase 'u':\n\t\t// ECMAscript suppot \\u{HEX} only if `u` is also set\n\t\tif p.useOptionE() && p.useOptionU() && p.charsRight() > 0 && p.rightChar(0) == '{' {\n\t\t\tp.moveRight(1)\n\t\t\treturn p.scanHexUntilBrace()\n\t\t} else {\n\t\t\tr, err = p.scanHex(4)\n\t\t}\n\tcase 'a':\n\t\treturn '\\u0007', nil\n\tcase 'b':\n\t\treturn '\\b', nil\n\tcase 'e':\n\t\treturn '\\u001B', nil\n\tcase 'f':\n\t\treturn '\\f', nil\n\tcase 'n':\n\t\treturn '\\n', nil\n\tcase 'r':\n\t\treturn '\\r', nil\n\tcase 't':\n\t\treturn '\\t', nil\n\tcase 'v':\n\t\treturn '\\u000B', nil\n\tcase 'c':\n\t\tr, err = p.scanControl()\n\tdefault:\n\t\tif !p.useOptionE() && !p.useRE2() && IsWordChar(ch) {\n\t\t\treturn 0, p.getErr(ErrUnrecognizedEscape, string(ch))\n\t\t}\n\t\treturn ch, nil\n\t}\n\tif err != nil && p.useOptionE() {\n\t\tp.textto(pos)\n\t\treturn ch, nil\n\t}\n\treturn\n}\n\n// Grabs and converts an ascii control character\nfunc (p *parser) scanControl() (rune, error) {\n\tif p.charsRight() <= 0 {\n\t\treturn 0, p.getErr(ErrMissingControl)\n\t}\n\n\tch := p.moveRightGetChar()\n\n\t// \\ca interpreted as \\cA\n\n\tif ch >= 'a' && ch <= 'z' {\n\t\tch = (ch - ('a' - 'A'))\n\t}\n\tch = (ch - '@')\n\tif ch >= 0 && ch < ' ' {\n\t\treturn ch, nil\n\t}\n\n\treturn 0, p.getErr(ErrUnrecognizedControl)\n\n}\n\n// Scan hex digits until we hit a closing brace.\n// Non-hex digits, hex value too large for UTF-8, or running out of chars are errors\nfunc (p *parser) scanHexUntilBrace() (rune, error) {\n\t// PCRE spec reads like unlimited hex digits are allowed, but unicode has a limit\n\t// so we can enforce that\n\ti := 0\n\thasContent := false\n\n\tfor p.charsRight() > 0 {\n\t\tch := p.moveRightGetChar()\n\t\tif ch == '}' {\n\t\t\t// hit our close brace, we're done here\n\t\t\t// prevent \\x{}\n\t\t\tif !hasContent {\n\t\t\t\treturn 0, p.getErr(ErrTooFewHex)\n\t\t\t}\n\t\t\treturn rune(i), nil\n\t\t}\n\t\thasContent = true\n\t\t// no brace needs to be hex digit\n\t\td := hexDigit(ch)\n\t\tif d < 0 {\n\t\t\treturn 0, p.getErr(ErrMissingBrace)\n\t\t}\n\n\t\ti *= 0x10\n\t\ti += d\n\n\t\tif i > unicode.MaxRune {\n\t\t\treturn 0, p.getErr(ErrInvalidHex)\n\t\t}\n\t}\n\n\t// we only make it here if we run out of digits without finding the brace\n\treturn 0, p.getErr(ErrMissingBrace)\n}\n\n// Scans exactly c hex digits (c=2 for \\xFF, c=4 for \\uFFFF)\nfunc (p *parser) scanHex(c int) (rune, error) {\n\n\ti := 0\n\n\tif p.charsRight() >= c {\n\t\tfor c > 0 {\n\t\t\td := hexDigit(p.moveRightGetChar())\n\t\t\tif d < 0 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ti *= 0x10\n\t\t\ti += d\n\t\t\tc--\n\t\t}\n\t}\n\n\tif c > 0 {\n\t\treturn 0, p.getErr(ErrTooFewHex)\n\t}\n\n\treturn rune(i), nil\n}\n\n// Returns n <= 0xF for a hex digit.\nfunc hexDigit(ch rune) int {\n\n\tif d := uint(ch - '0'); d <= 9 {\n\t\treturn int(d)\n\t}\n\n\tif d := uint(ch - 'a'); d <= 5 {\n\t\treturn int(d + 0xa)\n\t}\n\n\tif d := uint(ch - 'A'); d <= 5 {\n\t\treturn int(d + 0xa)\n\t}\n\n\treturn -1\n}\n\n// Scans up to three octal digits (stops before exceeding 0377).\nfunc (p *parser) scanOctal() rune {\n\t// Consume octal chars only up to 3 digits and value 0377\n\n\tc := 3\n\n\tif c > p.charsRight() {\n\t\tc = p.charsRight()\n\t}\n\n\t//we know the first char is good because the caller had to check\n\ti := 0\n\td := int(p.rightChar(0) - '0')\n\tfor c > 0 && d <= 7 && d >= 0 {\n\t\tif i >= 0x20 && p.useOptionE() {\n\t\t\tbreak\n\t\t}\n\t\ti *= 8\n\t\ti += d\n\t\tc--\n\n\t\tp.moveRight(1)\n\t\tif !p.rightMost() {\n\t\t\td = int(p.rightChar(0) - '0')\n\t\t}\n\t}\n\n\t// Octal codes only go up to 255.  Any larger and the behavior that Perl follows\n\t// is simply to truncate the high bits.\n\ti &= 0xFF\n\n\treturn rune(i)\n}\n\n// Returns the current parsing position.\nfunc (p *parser) textpos() int {\n\treturn p.currentPos\n}\n\n// Zaps to a specific parsing position.\nfunc (p *parser) textto(pos int) {\n\tp.currentPos = pos\n}\n\n// Returns the char at the right of the current parsing position and advances to the right.\nfunc (p *parser) moveRightGetChar() rune {\n\tch := p.pattern[p.currentPos]\n\tp.currentPos++\n\treturn ch\n}\n\n// Moves the current position to the right.\nfunc (p *parser) moveRight(i int) {\n\t// default would be 1\n\tp.currentPos += i\n}\n\n// Moves the current parsing position one to the left.\nfunc (p *parser) moveLeft() {\n\tp.currentPos--\n}\n\n// Returns the char left of the current parsing position.\nfunc (p *parser) charAt(i int) rune {\n\treturn p.pattern[i]\n}\n\n// Returns the char i chars right of the current parsing position.\nfunc (p *parser) rightChar(i int) rune {\n\t// default would be 0\n\treturn p.pattern[p.currentPos+i]\n}\n\n// Number of characters to the right of the current parsing position.\nfunc (p *parser) charsRight() int {\n\treturn len(p.pattern) - p.currentPos\n}\n\nfunc (p *parser) rightMost() bool {\n\treturn p.currentPos == len(p.pattern)\n}\n\n// Looks up the slot number for a given name\nfunc (p *parser) captureSlotFromName(capname string) int {\n\treturn p.capnames[capname]\n}\n\n// True if the capture slot was noted\nfunc (p *parser) isCaptureSlot(i int) bool {\n\tif p.caps != nil {\n\t\t_, ok := p.caps[i]\n\t\treturn ok\n\t}\n\n\treturn (i >= 0 && i < p.capsize)\n}\n\n// Looks up the slot number for a given name\nfunc (p *parser) isCaptureName(capname string) bool {\n\tif p.capnames == nil {\n\t\treturn false\n\t}\n\n\t_, ok := p.capnames[capname]\n\treturn ok\n}\n\n// option shortcuts\n\n// True if N option disabling '(' autocapture is on.\nfunc (p *parser) useOptionN() bool {\n\treturn (p.options & ExplicitCapture) != 0\n}\n\n// True if I option enabling case-insensitivity is on.\nfunc (p *parser) useOptionI() bool {\n\treturn (p.options & IgnoreCase) != 0\n}\n\n// True if M option altering meaning of $ and ^ is on.\nfunc (p *parser) useOptionM() bool {\n\treturn (p.options & Multiline) != 0\n}\n\n// True if S option altering meaning of . is on.\nfunc (p *parser) useOptionS() bool {\n\treturn (p.options & Singleline) != 0\n}\n\n// True if X option enabling whitespace/comment mode is on.\nfunc (p *parser) useOptionX() bool {\n\treturn (p.options & IgnorePatternWhitespace) != 0\n}\n\n// True if E option enabling ECMAScript behavior on.\nfunc (p *parser) useOptionE() bool {\n\treturn (p.options & ECMAScript) != 0\n}\n\n// true to use RE2 compatibility parsing behavior.\nfunc (p *parser) useRE2() bool {\n\treturn (p.options & RE2) != 0\n}\n\n// True if U option enabling ECMAScript's Unicode behavior on.\nfunc (p *parser) useOptionU() bool {\n\treturn (p.options & Unicode) != 0\n}\n\n// True if options stack is empty.\nfunc (p *parser) emptyOptionsStack() bool {\n\treturn len(p.optionsStack) == 0\n}\n\n// Finish the current quantifiable (when a quantifier is not found or is not possible)\nfunc (p *parser) addConcatenate() {\n\t// The first (| inside a Testgroup group goes directly to the group\n\tp.concatenation.addChild(p.unit)\n\tp.unit = nil\n}\n\n// Finish the current quantifiable (when a quantifier is found)\nfunc (p *parser) addConcatenate3(lazy bool, min, max int) {\n\tp.concatenation.addChild(p.unit.makeQuantifier(lazy, min, max))\n\tp.unit = nil\n}\n\n// Sets the current unit to a single char node\nfunc (p *parser) addUnitOne(ch rune) {\n\tif p.useOptionI() {\n\t\tch = unicode.ToLower(ch)\n\t}\n\n\tp.unit = newRegexNodeCh(ntOne, p.options, ch)\n}\n\n// Sets the current unit to a single inverse-char node\nfunc (p *parser) addUnitNotone(ch rune) {\n\tif p.useOptionI() {\n\t\tch = unicode.ToLower(ch)\n\t}\n\n\tp.unit = newRegexNodeCh(ntNotone, p.options, ch)\n}\n\n// Sets the current unit to a single set node\nfunc (p *parser) addUnitSet(set *CharSet) {\n\tp.unit = newRegexNodeSet(ntSet, p.options, set)\n}\n\n// Sets the current unit to a subtree\nfunc (p *parser) addUnitNode(node *regexNode) {\n\tp.unit = node\n}\n\n// Sets the current unit to an assertion of the specified type\nfunc (p *parser) addUnitType(t nodeType) {\n\tp.unit = newRegexNode(t, p.options)\n}\n\n// Finish the current group (in response to a ')' or end)\nfunc (p *parser) addGroup() error {\n\tif p.group.t == ntTestgroup || p.group.t == ntTestref {\n\t\tp.group.addChild(p.concatenation.reverseLeft())\n\t\tif (p.group.t == ntTestref && len(p.group.children) > 2) || len(p.group.children) > 3 {\n\t\t\treturn p.getErr(ErrTooManyAlternates)\n\t\t}\n\t} else {\n\t\tp.alternation.addChild(p.concatenation.reverseLeft())\n\t\tp.group.addChild(p.alternation)\n\t}\n\n\tp.unit = p.group\n\treturn nil\n}\n\n// Pops the option stack, but keeps the current options unchanged.\nfunc (p *parser) popKeepOptions() {\n\tlastIdx := len(p.optionsStack) - 1\n\tp.optionsStack = p.optionsStack[:lastIdx]\n}\n\n// Recalls options from the stack.\nfunc (p *parser) popOptions() {\n\tlastIdx := len(p.optionsStack) - 1\n\t// get the last item on the stack and then remove it by reslicing\n\tp.options = p.optionsStack[lastIdx]\n\tp.optionsStack = p.optionsStack[:lastIdx]\n}\n\n// Saves options on a stack.\nfunc (p *parser) pushOptions() {\n\tp.optionsStack = append(p.optionsStack, p.options)\n}\n\n// Add a string to the last concatenate.\nfunc (p *parser) addToConcatenate(pos, cch int, isReplacement bool) {\n\tvar node *regexNode\n\n\tif cch == 0 {\n\t\treturn\n\t}\n\n\tif cch > 1 {\n\t\tstr := make([]rune, cch)\n\t\tcopy(str, p.pattern[pos:pos+cch])\n\n\t\tif p.useOptionI() && !isReplacement {\n\t\t\t// We do the ToLower character by character for consistency.  With surrogate chars, doing\n\t\t\t// a ToLower on the entire string could actually change the surrogate pair.  This is more correct\n\t\t\t// linguistically, but since Regex doesn't support surrogates, it's more important to be\n\t\t\t// consistent.\n\t\t\tfor i := 0; i < len(str); i++ {\n\t\t\t\tstr[i] = unicode.ToLower(str[i])\n\t\t\t}\n\t\t}\n\n\t\tnode = newRegexNodeStr(ntMulti, p.options, str)\n\t} else {\n\t\tch := p.charAt(pos)\n\n\t\tif p.useOptionI() && !isReplacement {\n\t\t\tch = unicode.ToLower(ch)\n\t\t}\n\n\t\tnode = newRegexNodeCh(ntOne, p.options, ch)\n\t}\n\n\tp.concatenation.addChild(node)\n}\n\n// Push the parser state (in response to an open paren)\nfunc (p *parser) pushGroup() {\n\tp.group.next = p.stack\n\tp.alternation.next = p.group\n\tp.concatenation.next = p.alternation\n\tp.stack = p.concatenation\n}\n\n// Remember the pushed state (in response to a ')')\nfunc (p *parser) popGroup() error {\n\tp.concatenation = p.stack\n\tp.alternation = p.concatenation.next\n\tp.group = p.alternation.next\n\tp.stack = p.group.next\n\n\t// The first () inside a Testgroup group goes directly to the group\n\tif p.group.t == ntTestgroup && len(p.group.children) == 0 {\n\t\tif p.unit == nil {\n\t\t\treturn p.getErr(ErrConditionalExpression)\n\t\t}\n\n\t\tp.group.addChild(p.unit)\n\t\tp.unit = nil\n\t}\n\treturn nil\n}\n\n// True if the group stack is empty.\nfunc (p *parser) emptyStack() bool {\n\treturn p.stack == nil\n}\n\n// Start a new round for the parser state (in response to an open paren or string start)\nfunc (p *parser) startGroup(openGroup *regexNode) {\n\tp.group = openGroup\n\tp.alternation = newRegexNode(ntAlternate, p.options)\n\tp.concatenation = newRegexNode(ntConcatenate, p.options)\n}\n\n// Finish the current concatenation (in response to a |)\nfunc (p *parser) addAlternate() {\n\t// The | parts inside a Testgroup group go directly to the group\n\n\tif p.group.t == ntTestgroup || p.group.t == ntTestref {\n\t\tp.group.addChild(p.concatenation.reverseLeft())\n\t} else {\n\t\tp.alternation.addChild(p.concatenation.reverseLeft())\n\t}\n\n\tp.concatenation = newRegexNode(ntConcatenate, p.options)\n}\n\n// For categorizing ascii characters.\n\nconst (\n\tQ byte = 5 // quantifier\n\tS      = 4 // ordinary stopper\n\tZ      = 3 // ScanBlank stopper\n\tX      = 2 // whitespace\n\tE      = 1 // should be escaped\n)\n\nvar _category = []byte{\n\t//01  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n\t// !  \"  #  $  %  &  '  (  )  *  +  ,  -  .  /  0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?\n\tX, 0, 0, Z, S, 0, 0, 0, S, S, Q, Q, 0, 0, S, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Q,\n\t//@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  [  \\  ]  ^  _\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, S, 0,\n\t//'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  {  |  }  ~\n\t0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Q, S, 0, 0, 0,\n}\n\nfunc isSpace(ch rune) bool {\n\treturn (ch <= ' ' && _category[ch] == X)\n}\n\n// Returns true for those characters that terminate a string of ordinary chars.\nfunc isSpecial(ch rune) bool {\n\treturn (ch <= '|' && _category[ch] >= S)\n}\n\n// Returns true for those characters that terminate a string of ordinary chars.\nfunc isStopperX(ch rune) bool {\n\treturn (ch <= '|' && _category[ch] >= X)\n}\n\n// Returns true for those characters that begin a quantifier.\nfunc isQuantifier(ch rune) bool {\n\treturn (ch <= '{' && _category[ch] >= Q)\n}\n\nfunc (p *parser) isTrueQuantifier() bool {\n\tnChars := p.charsRight()\n\tif nChars == 0 {\n\t\treturn false\n\t}\n\n\tstartpos := p.textpos()\n\tch := p.charAt(startpos)\n\tif ch != '{' {\n\t\treturn ch <= '{' && _category[ch] >= Q\n\t}\n\n\t//UGLY: this is ugly -- the original code was ugly too\n\tpos := startpos\n\tfor {\n\t\tnChars--\n\t\tif nChars <= 0 {\n\t\t\tbreak\n\t\t}\n\t\tpos++\n\t\tch = p.charAt(pos)\n\t\tif ch < '0' || ch > '9' {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif nChars == 0 || pos-startpos == 1 {\n\t\treturn false\n\t}\n\tif ch == '}' {\n\t\treturn true\n\t}\n\tif ch != ',' {\n\t\treturn false\n\t}\n\tfor {\n\t\tnChars--\n\t\tif nChars <= 0 {\n\t\t\tbreak\n\t\t}\n\t\tpos++\n\t\tch = p.charAt(pos)\n\t\tif ch < '0' || ch > '9' {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn nChars > 0 && ch == '}'\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/prefix.go",
    "content": "package syntax\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\ntype Prefix struct {\n\tPrefixStr       []rune\n\tPrefixSet       CharSet\n\tCaseInsensitive bool\n}\n\n// It takes a RegexTree and computes the set of chars that can start it.\nfunc getFirstCharsPrefix(tree *RegexTree) *Prefix {\n\ts := regexFcd{\n\t\tfcStack:  make([]regexFc, 32),\n\t\tintStack: make([]int, 32),\n\t}\n\tfc := s.regexFCFromRegexTree(tree)\n\n\tif fc == nil || fc.nullable || fc.cc.IsEmpty() {\n\t\treturn nil\n\t}\n\tfcSet := fc.getFirstChars()\n\treturn &Prefix{PrefixSet: fcSet, CaseInsensitive: fc.caseInsensitive}\n}\n\ntype regexFcd struct {\n\tintStack        []int\n\tintDepth        int\n\tfcStack         []regexFc\n\tfcDepth         int\n\tskipAllChildren bool // don't process any more children at the current level\n\tskipchild       bool // don't process the current child.\n\tfailed          bool\n}\n\n/*\n * The main FC computation. It does a shortcutted depth-first walk\n * through the tree and calls CalculateFC to emits code before\n * and after each child of an interior node, and at each leaf.\n */\nfunc (s *regexFcd) regexFCFromRegexTree(tree *RegexTree) *regexFc {\n\tcurNode := tree.root\n\tcurChild := 0\n\n\tfor {\n\t\tif len(curNode.children) == 0 {\n\t\t\t// This is a leaf node\n\t\t\ts.calculateFC(curNode.t, curNode, 0)\n\t\t} else if curChild < len(curNode.children) && !s.skipAllChildren {\n\t\t\t// This is an interior node, and we have more children to analyze\n\t\t\ts.calculateFC(curNode.t|beforeChild, curNode, curChild)\n\n\t\t\tif !s.skipchild {\n\t\t\t\tcurNode = curNode.children[curChild]\n\t\t\t\t// this stack is how we get a depth first walk of the tree.\n\t\t\t\ts.pushInt(curChild)\n\t\t\t\tcurChild = 0\n\t\t\t} else {\n\t\t\t\tcurChild++\n\t\t\t\ts.skipchild = false\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// This is an interior node where we've finished analyzing all the children, or\n\t\t// the end of a leaf node.\n\t\ts.skipAllChildren = false\n\n\t\tif s.intIsEmpty() {\n\t\t\tbreak\n\t\t}\n\n\t\tcurChild = s.popInt()\n\t\tcurNode = curNode.next\n\n\t\ts.calculateFC(curNode.t|afterChild, curNode, curChild)\n\t\tif s.failed {\n\t\t\treturn nil\n\t\t}\n\n\t\tcurChild++\n\t}\n\n\tif s.fcIsEmpty() {\n\t\treturn nil\n\t}\n\n\treturn s.popFC()\n}\n\n// To avoid recursion, we use a simple integer stack.\n// This is the push.\nfunc (s *regexFcd) pushInt(I int) {\n\tif s.intDepth >= len(s.intStack) {\n\t\texpanded := make([]int, s.intDepth*2)\n\t\tcopy(expanded, s.intStack)\n\t\ts.intStack = expanded\n\t}\n\n\ts.intStack[s.intDepth] = I\n\ts.intDepth++\n}\n\n// True if the stack is empty.\nfunc (s *regexFcd) intIsEmpty() bool {\n\treturn s.intDepth == 0\n}\n\n// This is the pop.\nfunc (s *regexFcd) popInt() int {\n\ts.intDepth--\n\treturn s.intStack[s.intDepth]\n}\n\n// We also use a stack of RegexFC objects.\n// This is the push.\nfunc (s *regexFcd) pushFC(fc regexFc) {\n\tif s.fcDepth >= len(s.fcStack) {\n\t\texpanded := make([]regexFc, s.fcDepth*2)\n\t\tcopy(expanded, s.fcStack)\n\t\ts.fcStack = expanded\n\t}\n\n\ts.fcStack[s.fcDepth] = fc\n\ts.fcDepth++\n}\n\n// True if the stack is empty.\nfunc (s *regexFcd) fcIsEmpty() bool {\n\treturn s.fcDepth == 0\n}\n\n// This is the pop.\nfunc (s *regexFcd) popFC() *regexFc {\n\ts.fcDepth--\n\treturn &s.fcStack[s.fcDepth]\n}\n\n// This is the top.\nfunc (s *regexFcd) topFC() *regexFc {\n\treturn &s.fcStack[s.fcDepth-1]\n}\n\n// Called in Beforechild to prevent further processing of the current child\nfunc (s *regexFcd) skipChild() {\n\ts.skipchild = true\n}\n\n// FC computation and shortcut cases for each node type\nfunc (s *regexFcd) calculateFC(nt nodeType, node *regexNode, CurIndex int) {\n\t//fmt.Printf(\"NodeType: %v, CurIndex: %v, Desc: %v\\n\", nt, CurIndex, node.description())\n\tci := false\n\trtl := false\n\n\tif nt <= ntRef {\n\t\tif (node.options & IgnoreCase) != 0 {\n\t\t\tci = true\n\t\t}\n\t\tif (node.options & RightToLeft) != 0 {\n\t\t\trtl = true\n\t\t}\n\t}\n\n\tswitch nt {\n\tcase ntConcatenate | beforeChild, ntAlternate | beforeChild, ntTestref | beforeChild, ntLoop | beforeChild, ntLazyloop | beforeChild:\n\t\tbreak\n\n\tcase ntTestgroup | beforeChild:\n\t\tif CurIndex == 0 {\n\t\t\ts.skipChild()\n\t\t}\n\t\tbreak\n\n\tcase ntEmpty:\n\t\ts.pushFC(regexFc{nullable: true})\n\t\tbreak\n\n\tcase ntConcatenate | afterChild:\n\t\tif CurIndex != 0 {\n\t\t\tchild := s.popFC()\n\t\t\tcumul := s.topFC()\n\n\t\t\ts.failed = !cumul.addFC(*child, true)\n\t\t}\n\n\t\tfc := s.topFC()\n\t\tif !fc.nullable {\n\t\t\ts.skipAllChildren = true\n\t\t}\n\t\tbreak\n\n\tcase ntTestgroup | afterChild:\n\t\tif CurIndex > 1 {\n\t\t\tchild := s.popFC()\n\t\t\tcumul := s.topFC()\n\n\t\t\ts.failed = !cumul.addFC(*child, false)\n\t\t}\n\t\tbreak\n\n\tcase ntAlternate | afterChild, ntTestref | afterChild:\n\t\tif CurIndex != 0 {\n\t\t\tchild := s.popFC()\n\t\t\tcumul := s.topFC()\n\n\t\t\ts.failed = !cumul.addFC(*child, false)\n\t\t}\n\t\tbreak\n\n\tcase ntLoop | afterChild, ntLazyloop | afterChild:\n\t\tif node.m == 0 {\n\t\t\tfc := s.topFC()\n\t\t\tfc.nullable = true\n\t\t}\n\t\tbreak\n\n\tcase ntGroup | beforeChild, ntGroup | afterChild, ntCapture | beforeChild, ntCapture | afterChild, ntGreedy | beforeChild, ntGreedy | afterChild:\n\t\tbreak\n\n\tcase ntRequire | beforeChild, ntPrevent | beforeChild:\n\t\ts.skipChild()\n\t\ts.pushFC(regexFc{nullable: true})\n\t\tbreak\n\n\tcase ntRequire | afterChild, ntPrevent | afterChild:\n\t\tbreak\n\n\tcase ntOne, ntNotone:\n\t\ts.pushFC(newRegexFc(node.ch, nt == ntNotone, false, ci))\n\t\tbreak\n\n\tcase ntOneloop, ntOnelazy:\n\t\ts.pushFC(newRegexFc(node.ch, false, node.m == 0, ci))\n\t\tbreak\n\n\tcase ntNotoneloop, ntNotonelazy:\n\t\ts.pushFC(newRegexFc(node.ch, true, node.m == 0, ci))\n\t\tbreak\n\n\tcase ntMulti:\n\t\tif len(node.str) == 0 {\n\t\t\ts.pushFC(regexFc{nullable: true})\n\t\t} else if !rtl {\n\t\t\ts.pushFC(newRegexFc(node.str[0], false, false, ci))\n\t\t} else {\n\t\t\ts.pushFC(newRegexFc(node.str[len(node.str)-1], false, false, ci))\n\t\t}\n\t\tbreak\n\n\tcase ntSet:\n\t\ts.pushFC(regexFc{cc: node.set.Copy(), nullable: false, caseInsensitive: ci})\n\t\tbreak\n\n\tcase ntSetloop, ntSetlazy:\n\t\ts.pushFC(regexFc{cc: node.set.Copy(), nullable: node.m == 0, caseInsensitive: ci})\n\t\tbreak\n\n\tcase ntRef:\n\t\ts.pushFC(regexFc{cc: *AnyClass(), nullable: true, caseInsensitive: false})\n\t\tbreak\n\n\tcase ntNothing, ntBol, ntEol, ntBoundary, ntNonboundary, ntECMABoundary, ntNonECMABoundary, ntBeginning, ntStart, ntEndZ, ntEnd:\n\t\ts.pushFC(regexFc{nullable: true})\n\t\tbreak\n\n\tdefault:\n\t\tpanic(fmt.Sprintf(\"unexpected op code: %v\", nt))\n\t}\n}\n\ntype regexFc struct {\n\tcc              CharSet\n\tnullable        bool\n\tcaseInsensitive bool\n}\n\nfunc newRegexFc(ch rune, not, nullable, caseInsensitive bool) regexFc {\n\tr := regexFc{\n\t\tcaseInsensitive: caseInsensitive,\n\t\tnullable:        nullable,\n\t}\n\tif not {\n\t\tif ch > 0 {\n\t\t\tr.cc.addRange('\\x00', ch-1)\n\t\t}\n\t\tif ch < 0xFFFF {\n\t\t\tr.cc.addRange(ch+1, utf8.MaxRune)\n\t\t}\n\t} else {\n\t\tr.cc.addRange(ch, ch)\n\t}\n\treturn r\n}\n\nfunc (r *regexFc) getFirstChars() CharSet {\n\tif r.caseInsensitive {\n\t\tr.cc.addLowercase()\n\t}\n\n\treturn r.cc\n}\n\nfunc (r *regexFc) addFC(fc regexFc, concatenate bool) bool {\n\tif !r.cc.IsMergeable() || !fc.cc.IsMergeable() {\n\t\treturn false\n\t}\n\n\tif concatenate {\n\t\tif !r.nullable {\n\t\t\treturn true\n\t\t}\n\n\t\tif !fc.nullable {\n\t\t\tr.nullable = false\n\t\t}\n\t} else {\n\t\tif fc.nullable {\n\t\t\tr.nullable = true\n\t\t}\n\t}\n\n\tr.caseInsensitive = r.caseInsensitive || fc.caseInsensitive\n\tr.cc.addSet(fc.cc)\n\n\treturn true\n}\n\n// This is a related computation: it takes a RegexTree and computes the\n// leading substring if it sees one. It's quite trivial and gives up easily.\nfunc getPrefix(tree *RegexTree) *Prefix {\n\tvar concatNode *regexNode\n\tnextChild := 0\n\n\tcurNode := tree.root\n\n\tfor {\n\t\tswitch curNode.t {\n\t\tcase ntConcatenate:\n\t\t\tif len(curNode.children) > 0 {\n\t\t\t\tconcatNode = curNode\n\t\t\t\tnextChild = 0\n\t\t\t}\n\n\t\tcase ntGreedy, ntCapture:\n\t\t\tcurNode = curNode.children[0]\n\t\t\tconcatNode = nil\n\t\t\tcontinue\n\n\t\tcase ntOneloop, ntOnelazy:\n\t\t\tif curNode.m > 0 {\n\t\t\t\treturn &Prefix{\n\t\t\t\t\tPrefixStr:       repeat(curNode.ch, curNode.m),\n\t\t\t\t\tCaseInsensitive: (curNode.options & IgnoreCase) != 0,\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nil\n\n\t\tcase ntOne:\n\t\t\treturn &Prefix{\n\t\t\t\tPrefixStr:       []rune{curNode.ch},\n\t\t\t\tCaseInsensitive: (curNode.options & IgnoreCase) != 0,\n\t\t\t}\n\n\t\tcase ntMulti:\n\t\t\treturn &Prefix{\n\t\t\t\tPrefixStr:       curNode.str,\n\t\t\t\tCaseInsensitive: (curNode.options & IgnoreCase) != 0,\n\t\t\t}\n\n\t\tcase ntBol, ntEol, ntBoundary, ntECMABoundary, ntBeginning, ntStart,\n\t\t\tntEndZ, ntEnd, ntEmpty, ntRequire, ntPrevent:\n\n\t\tdefault:\n\t\t\treturn nil\n\t\t}\n\n\t\tif concatNode == nil || nextChild >= len(concatNode.children) {\n\t\t\treturn nil\n\t\t}\n\n\t\tcurNode = concatNode.children[nextChild]\n\t\tnextChild++\n\t}\n}\n\n// repeat the rune r, c times... up to the max of MaxPrefixSize\nfunc repeat(r rune, c int) []rune {\n\tif c > MaxPrefixSize {\n\t\tc = MaxPrefixSize\n\t}\n\n\tret := make([]rune, c)\n\n\t// binary growth using copy for speed\n\tret[0] = r\n\tbp := 1\n\tfor bp < len(ret) {\n\t\tcopy(ret[bp:], ret[:bp])\n\t\tbp *= 2\n\t}\n\n\treturn ret\n}\n\n// BmPrefix precomputes the Boyer-Moore\n// tables for fast string scanning. These tables allow\n// you to scan for the first occurrence of a string within\n// a large body of text without examining every character.\n// The performance of the heuristic depends on the actual\n// string and the text being searched, but usually, the longer\n// the string that is being searched for, the fewer characters\n// need to be examined.\ntype BmPrefix struct {\n\tpositive        []int\n\tnegativeASCII   []int\n\tnegativeUnicode [][]int\n\tpattern         []rune\n\tlowASCII        rune\n\thighASCII       rune\n\trightToLeft     bool\n\tcaseInsensitive bool\n}\n\nfunc newBmPrefix(pattern []rune, caseInsensitive, rightToLeft bool) *BmPrefix {\n\n\tb := &BmPrefix{\n\t\trightToLeft:     rightToLeft,\n\t\tcaseInsensitive: caseInsensitive,\n\t\tpattern:         pattern,\n\t}\n\n\tif caseInsensitive {\n\t\tfor i := 0; i < len(b.pattern); i++ {\n\t\t\t// We do the ToLower character by character for consistency.  With surrogate chars, doing\n\t\t\t// a ToLower on the entire string could actually change the surrogate pair.  This is more correct\n\t\t\t// linguistically, but since Regex doesn't support surrogates, it's more important to be\n\t\t\t// consistent.\n\n\t\t\tb.pattern[i] = unicode.ToLower(b.pattern[i])\n\t\t}\n\t}\n\n\tvar beforefirst, last, bump int\n\tvar scan, match int\n\n\tif !rightToLeft {\n\t\tbeforefirst = -1\n\t\tlast = len(b.pattern) - 1\n\t\tbump = 1\n\t} else {\n\t\tbeforefirst = len(b.pattern)\n\t\tlast = 0\n\t\tbump = -1\n\t}\n\n\t// PART I - the good-suffix shift table\n\t//\n\t// compute the positive requirement:\n\t// if char \"i\" is the first one from the right that doesn't match,\n\t// then we know the matcher can advance by _positive[i].\n\t//\n\t// This algorithm is a simplified variant of the standard\n\t// Boyer-Moore good suffix calculation.\n\n\tb.positive = make([]int, len(b.pattern))\n\n\texamine := last\n\tch := b.pattern[examine]\n\tb.positive[examine] = bump\n\texamine -= bump\n\nOuterloop:\n\tfor {\n\t\t// find an internal char (examine) that matches the tail\n\n\t\tfor {\n\t\t\tif examine == beforefirst {\n\t\t\t\tbreak Outerloop\n\t\t\t}\n\t\t\tif b.pattern[examine] == ch {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\texamine -= bump\n\t\t}\n\n\t\tmatch = last\n\t\tscan = examine\n\n\t\t// find the length of the match\n\t\tfor {\n\t\t\tif scan == beforefirst || b.pattern[match] != b.pattern[scan] {\n\t\t\t\t// at the end of the match, note the difference in _positive\n\t\t\t\t// this is not the length of the match, but the distance from the internal match\n\t\t\t\t// to the tail suffix.\n\t\t\t\tif b.positive[match] == 0 {\n\t\t\t\t\tb.positive[match] = match - scan\n\t\t\t\t}\n\n\t\t\t\t// System.Diagnostics.Debug.WriteLine(\"Set positive[\" + match + \"] to \" + (match - scan));\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tscan -= bump\n\t\t\tmatch -= bump\n\t\t}\n\n\t\texamine -= bump\n\t}\n\n\tmatch = last - bump\n\n\t// scan for the chars for which there are no shifts that yield a different candidate\n\n\t// The inside of the if statement used to say\n\t// \"_positive[match] = last - beforefirst;\"\n\t// This is slightly less aggressive in how much we skip, but at worst it\n\t// should mean a little more work rather than skipping a potential match.\n\tfor match != beforefirst {\n\t\tif b.positive[match] == 0 {\n\t\t\tb.positive[match] = bump\n\t\t}\n\n\t\tmatch -= bump\n\t}\n\n\t// PART II - the bad-character shift table\n\t//\n\t// compute the negative requirement:\n\t// if char \"ch\" is the reject character when testing position \"i\",\n\t// we can slide up by _negative[ch];\n\t// (_negative[ch] = str.Length - 1 - str.LastIndexOf(ch))\n\t//\n\t// the lookup table is divided into ASCII and Unicode portions;\n\t// only those parts of the Unicode 16-bit code set that actually\n\t// appear in the string are in the table. (Maximum size with\n\t// Unicode is 65K; ASCII only case is 512 bytes.)\n\n\tb.negativeASCII = make([]int, 128)\n\n\tfor i := 0; i < len(b.negativeASCII); i++ {\n\t\tb.negativeASCII[i] = last - beforefirst\n\t}\n\n\tb.lowASCII = 127\n\tb.highASCII = 0\n\n\tfor examine = last; examine != beforefirst; examine -= bump {\n\t\tch = b.pattern[examine]\n\n\t\tswitch {\n\t\tcase ch < 128:\n\t\t\tif b.lowASCII > ch {\n\t\t\t\tb.lowASCII = ch\n\t\t\t}\n\n\t\t\tif b.highASCII < ch {\n\t\t\t\tb.highASCII = ch\n\t\t\t}\n\n\t\t\tif b.negativeASCII[ch] == last-beforefirst {\n\t\t\t\tb.negativeASCII[ch] = last - examine\n\t\t\t}\n\t\tcase ch <= 0xffff:\n\t\t\ti, j := ch>>8, ch&0xFF\n\n\t\t\tif b.negativeUnicode == nil {\n\t\t\t\tb.negativeUnicode = make([][]int, 256)\n\t\t\t}\n\n\t\t\tif b.negativeUnicode[i] == nil {\n\t\t\t\tnewarray := make([]int, 256)\n\n\t\t\t\tfor k := 0; k < len(newarray); k++ {\n\t\t\t\t\tnewarray[k] = last - beforefirst\n\t\t\t\t}\n\n\t\t\t\tif i == 0 {\n\t\t\t\t\tcopy(newarray, b.negativeASCII)\n\t\t\t\t\t//TODO: this line needed?\n\t\t\t\t\tb.negativeASCII = newarray\n\t\t\t\t}\n\n\t\t\t\tb.negativeUnicode[i] = newarray\n\t\t\t}\n\n\t\t\tif b.negativeUnicode[i][j] == last-beforefirst {\n\t\t\t\tb.negativeUnicode[i][j] = last - examine\n\t\t\t}\n\t\tdefault:\n\t\t\t// we can't do the filter because this algo doesn't support\n\t\t\t// unicode chars >0xffff\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn b\n}\n\nfunc (b *BmPrefix) String() string {\n\treturn string(b.pattern)\n}\n\n// Dump returns the contents of the filter as a human readable string\nfunc (b *BmPrefix) Dump(indent string) string {\n\tbuf := &bytes.Buffer{}\n\n\tfmt.Fprintf(buf, \"%sBM Pattern: %s\\n%sPositive: \", indent, string(b.pattern), indent)\n\tfor i := 0; i < len(b.positive); i++ {\n\t\tbuf.WriteString(strconv.Itoa(b.positive[i]))\n\t\tbuf.WriteRune(' ')\n\t}\n\tbuf.WriteRune('\\n')\n\n\tif b.negativeASCII != nil {\n\t\tbuf.WriteString(indent)\n\t\tbuf.WriteString(\"Negative table\\n\")\n\t\tfor i := 0; i < len(b.negativeASCII); i++ {\n\t\t\tif b.negativeASCII[i] != len(b.pattern) {\n\t\t\t\tfmt.Fprintf(buf, \"%s  %s %s\\n\", indent, Escape(string(rune(i))), strconv.Itoa(b.negativeASCII[i]))\n\t\t\t}\n\t\t}\n\t}\n\n\treturn buf.String()\n}\n\n// Scan uses the Boyer-Moore algorithm to find the first occurrence\n// of the specified string within text, beginning at index, and\n// constrained within beglimit and endlimit.\n//\n// The direction and case-sensitivity of the match is determined\n// by the arguments to the RegexBoyerMoore constructor.\nfunc (b *BmPrefix) Scan(text []rune, index, beglimit, endlimit int) int {\n\tvar (\n\t\tdefadv, test, test2         int\n\t\tmatch, startmatch, endmatch int\n\t\tbump, advance               int\n\t\tchTest                      rune\n\t\tunicodeLookup               []int\n\t)\n\n\tif !b.rightToLeft {\n\t\tdefadv = len(b.pattern)\n\t\tstartmatch = len(b.pattern) - 1\n\t\tendmatch = 0\n\t\ttest = index + defadv - 1\n\t\tbump = 1\n\t} else {\n\t\tdefadv = -len(b.pattern)\n\t\tstartmatch = 0\n\t\tendmatch = -defadv - 1\n\t\ttest = index + defadv\n\t\tbump = -1\n\t}\n\n\tchMatch := b.pattern[startmatch]\n\n\tfor {\n\t\tif test >= endlimit || test < beglimit {\n\t\t\treturn -1\n\t\t}\n\n\t\tchTest = text[test]\n\n\t\tif b.caseInsensitive {\n\t\t\tchTest = unicode.ToLower(chTest)\n\t\t}\n\n\t\tif chTest != chMatch {\n\t\t\tif chTest < 128 {\n\t\t\t\tadvance = b.negativeASCII[chTest]\n\t\t\t} else if chTest < 0xffff && len(b.negativeUnicode) > 0 {\n\t\t\t\tunicodeLookup = b.negativeUnicode[chTest>>8]\n\t\t\t\tif len(unicodeLookup) > 0 {\n\t\t\t\t\tadvance = unicodeLookup[chTest&0xFF]\n\t\t\t\t} else {\n\t\t\t\t\tadvance = defadv\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tadvance = defadv\n\t\t\t}\n\n\t\t\ttest += advance\n\t\t} else { // if (chTest == chMatch)\n\t\t\ttest2 = test\n\t\t\tmatch = startmatch\n\n\t\t\tfor {\n\t\t\t\tif match == endmatch {\n\t\t\t\t\tif b.rightToLeft {\n\t\t\t\t\t\treturn test2 + 1\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn test2\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmatch -= bump\n\t\t\t\ttest2 -= bump\n\n\t\t\t\tchTest = text[test2]\n\n\t\t\t\tif b.caseInsensitive {\n\t\t\t\t\tchTest = unicode.ToLower(chTest)\n\t\t\t\t}\n\n\t\t\t\tif chTest != b.pattern[match] {\n\t\t\t\t\tadvance = b.positive[match]\n\t\t\t\t\tif chTest < 128 {\n\t\t\t\t\t\ttest2 = (match - startmatch) + b.negativeASCII[chTest]\n\t\t\t\t\t} else if chTest < 0xffff && len(b.negativeUnicode) > 0 {\n\t\t\t\t\t\tunicodeLookup = b.negativeUnicode[chTest>>8]\n\t\t\t\t\t\tif len(unicodeLookup) > 0 {\n\t\t\t\t\t\t\ttest2 = (match - startmatch) + unicodeLookup[chTest&0xFF]\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttest += advance\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttest += advance\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\tif b.rightToLeft {\n\t\t\t\t\t\tif test2 < advance {\n\t\t\t\t\t\t\tadvance = test2\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if test2 > advance {\n\t\t\t\t\t\tadvance = test2\n\t\t\t\t\t}\n\n\t\t\t\t\ttest += advance\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// When a regex is anchored, we can do a quick IsMatch test instead of a Scan\nfunc (b *BmPrefix) IsMatch(text []rune, index, beglimit, endlimit int) bool {\n\tif !b.rightToLeft {\n\t\tif index < beglimit || endlimit-index < len(b.pattern) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn b.matchPattern(text, index)\n\t} else {\n\t\tif index > endlimit || index-beglimit < len(b.pattern) {\n\t\t\treturn false\n\t\t}\n\n\t\treturn b.matchPattern(text, index-len(b.pattern))\n\t}\n}\n\nfunc (b *BmPrefix) matchPattern(text []rune, index int) bool {\n\tif len(text)-index < len(b.pattern) {\n\t\treturn false\n\t}\n\n\tif b.caseInsensitive {\n\t\tfor i := 0; i < len(b.pattern); i++ {\n\t\t\t//Debug.Assert(textinfo.ToLower(_pattern[i]) == _pattern[i], \"pattern should be converted to lower case in constructor!\");\n\t\t\tif unicode.ToLower(text[index+i]) != b.pattern[i] {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t} else {\n\t\tfor i := 0; i < len(b.pattern); i++ {\n\t\t\tif text[index+i] != b.pattern[i] {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n}\n\ntype AnchorLoc int16\n\n// where the regex can be pegged\nconst (\n\tAnchorBeginning    AnchorLoc = 0x0001\n\tAnchorBol                    = 0x0002\n\tAnchorStart                  = 0x0004\n\tAnchorEol                    = 0x0008\n\tAnchorEndZ                   = 0x0010\n\tAnchorEnd                    = 0x0020\n\tAnchorBoundary               = 0x0040\n\tAnchorECMABoundary           = 0x0080\n)\n\nfunc getAnchors(tree *RegexTree) AnchorLoc {\n\n\tvar concatNode *regexNode\n\tnextChild, result := 0, AnchorLoc(0)\n\n\tcurNode := tree.root\n\n\tfor {\n\t\tswitch curNode.t {\n\t\tcase ntConcatenate:\n\t\t\tif len(curNode.children) > 0 {\n\t\t\t\tconcatNode = curNode\n\t\t\t\tnextChild = 0\n\t\t\t}\n\n\t\tcase ntGreedy, ntCapture:\n\t\t\tcurNode = curNode.children[0]\n\t\t\tconcatNode = nil\n\t\t\tcontinue\n\n\t\tcase ntBol, ntEol, ntBoundary, ntECMABoundary, ntBeginning,\n\t\t\tntStart, ntEndZ, ntEnd:\n\t\t\treturn result | anchorFromType(curNode.t)\n\n\t\tcase ntEmpty, ntRequire, ntPrevent:\n\n\t\tdefault:\n\t\t\treturn result\n\t\t}\n\n\t\tif concatNode == nil || nextChild >= len(concatNode.children) {\n\t\t\treturn result\n\t\t}\n\n\t\tcurNode = concatNode.children[nextChild]\n\t\tnextChild++\n\t}\n}\n\nfunc anchorFromType(t nodeType) AnchorLoc {\n\tswitch t {\n\tcase ntBol:\n\t\treturn AnchorBol\n\tcase ntEol:\n\t\treturn AnchorEol\n\tcase ntBoundary:\n\t\treturn AnchorBoundary\n\tcase ntECMABoundary:\n\t\treturn AnchorECMABoundary\n\tcase ntBeginning:\n\t\treturn AnchorBeginning\n\tcase ntStart:\n\t\treturn AnchorStart\n\tcase ntEndZ:\n\t\treturn AnchorEndZ\n\tcase ntEnd:\n\t\treturn AnchorEnd\n\tdefault:\n\t\treturn 0\n\t}\n}\n\n// anchorDescription returns a human-readable description of the anchors\nfunc (anchors AnchorLoc) String() string {\n\tbuf := &bytes.Buffer{}\n\n\tif 0 != (anchors & AnchorBeginning) {\n\t\tbuf.WriteString(\", Beginning\")\n\t}\n\tif 0 != (anchors & AnchorStart) {\n\t\tbuf.WriteString(\", Start\")\n\t}\n\tif 0 != (anchors & AnchorBol) {\n\t\tbuf.WriteString(\", Bol\")\n\t}\n\tif 0 != (anchors & AnchorBoundary) {\n\t\tbuf.WriteString(\", Boundary\")\n\t}\n\tif 0 != (anchors & AnchorECMABoundary) {\n\t\tbuf.WriteString(\", ECMABoundary\")\n\t}\n\tif 0 != (anchors & AnchorEol) {\n\t\tbuf.WriteString(\", Eol\")\n\t}\n\tif 0 != (anchors & AnchorEnd) {\n\t\tbuf.WriteString(\", End\")\n\t}\n\tif 0 != (anchors & AnchorEndZ) {\n\t\tbuf.WriteString(\", EndZ\")\n\t}\n\n\t// trim off comma\n\tif buf.Len() >= 2 {\n\t\treturn buf.String()[2:]\n\t}\n\treturn \"None\"\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/replacerdata.go",
    "content": "package syntax\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n)\n\ntype ReplacerData struct {\n\tRep     string\n\tStrings []string\n\tRules   []int\n}\n\nconst (\n\treplaceSpecials     = 4\n\treplaceLeftPortion  = -1\n\treplaceRightPortion = -2\n\treplaceLastGroup    = -3\n\treplaceWholeString  = -4\n)\n\n//ErrReplacementError is a general error during parsing the replacement text\nvar ErrReplacementError = errors.New(\"Replacement pattern error.\")\n\n// NewReplacerData will populate a reusable replacer data struct based on the given replacement string\n// and the capture group data from a regexp\nfunc NewReplacerData(rep string, caps map[int]int, capsize int, capnames map[string]int, op RegexOptions) (*ReplacerData, error) {\n\tp := parser{\n\t\toptions:  op,\n\t\tcaps:     caps,\n\t\tcapsize:  capsize,\n\t\tcapnames: capnames,\n\t}\n\tp.setPattern(rep)\n\tconcat, err := p.scanReplacement()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif concat.t != ntConcatenate {\n\t\tpanic(ErrReplacementError)\n\t}\n\n\tsb := &bytes.Buffer{}\n\tvar (\n\t\tstrings []string\n\t\trules   []int\n\t)\n\n\tfor _, child := range concat.children {\n\t\tswitch child.t {\n\t\tcase ntMulti:\n\t\t\tchild.writeStrToBuf(sb)\n\n\t\tcase ntOne:\n\t\t\tsb.WriteRune(child.ch)\n\n\t\tcase ntRef:\n\t\t\tif sb.Len() > 0 {\n\t\t\t\trules = append(rules, len(strings))\n\t\t\t\tstrings = append(strings, sb.String())\n\t\t\t\tsb.Reset()\n\t\t\t}\n\t\t\tslot := child.m\n\n\t\t\tif len(caps) > 0 && slot >= 0 {\n\t\t\t\tslot = caps[slot]\n\t\t\t}\n\n\t\t\trules = append(rules, -replaceSpecials-1-slot)\n\n\t\tdefault:\n\t\t\tpanic(ErrReplacementError)\n\t\t}\n\t}\n\n\tif sb.Len() > 0 {\n\t\trules = append(rules, len(strings))\n\t\tstrings = append(strings, sb.String())\n\t}\n\n\treturn &ReplacerData{\n\t\tRep:     rep,\n\t\tStrings: strings,\n\t\tRules:   rules,\n\t}, nil\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/tree.go",
    "content": "package syntax\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n)\n\ntype RegexTree struct {\n\troot       *regexNode\n\tcaps       map[int]int\n\tcapnumlist []int\n\tcaptop     int\n\tCapnames   map[string]int\n\tCaplist    []string\n\toptions    RegexOptions\n}\n\n// It is built into a parsed tree for a regular expression.\n\n// Implementation notes:\n//\n// Since the node tree is a temporary data structure only used\n// during compilation of the regexp to integer codes, it's\n// designed for clarity and convenience rather than\n// space efficiency.\n//\n// RegexNodes are built into a tree, linked by the n.children list.\n// Each node also has a n.parent and n.ichild member indicating\n// its parent and which child # it is in its parent's list.\n//\n// RegexNodes come in as many types as there are constructs in\n// a regular expression, for example, \"concatenate\", \"alternate\",\n// \"one\", \"rept\", \"group\". There are also node types for basic\n// peephole optimizations, e.g., \"onerep\", \"notsetrep\", etc.\n//\n// Because perl 5 allows \"lookback\" groups that scan backwards,\n// each node also gets a \"direction\". Normally the value of\n// boolean n.backward = false.\n//\n// During parsing, top-level nodes are also stacked onto a parse\n// stack (a stack of trees). For this purpose we have a n.next\n// pointer. [Note that to save a few bytes, we could overload the\n// n.parent pointer instead.]\n//\n// On the parse stack, each tree has a \"role\" - basically, the\n// nonterminal in the grammar that the parser has currently\n// assigned to the tree. That code is stored in n.role.\n//\n// Finally, some of the different kinds of nodes have data.\n// Two integers (for the looping constructs) are stored in\n// n.operands, an an object (either a string or a set)\n// is stored in n.data\ntype regexNode struct {\n\tt        nodeType\n\tchildren []*regexNode\n\tstr      []rune\n\tset      *CharSet\n\tch       rune\n\tm        int\n\tn        int\n\toptions  RegexOptions\n\tnext     *regexNode\n}\n\ntype nodeType int32\n\nconst (\n\t// The following are leaves, and correspond to primitive operations\n\n\tntOnerep      nodeType = 0  // lef,back char,min,max    a {n}\n\tntNotonerep            = 1  // lef,back char,min,max    .{n}\n\tntSetrep               = 2  // lef,back set,min,max     [\\d]{n}\n\tntOneloop              = 3  // lef,back char,min,max    a {,n}\n\tntNotoneloop           = 4  // lef,back char,min,max    .{,n}\n\tntSetloop              = 5  // lef,back set,min,max     [\\d]{,n}\n\tntOnelazy              = 6  // lef,back char,min,max    a {,n}?\n\tntNotonelazy           = 7  // lef,back char,min,max    .{,n}?\n\tntSetlazy              = 8  // lef,back set,min,max     [\\d]{,n}?\n\tntOne                  = 9  // lef      char            a\n\tntNotone               = 10 // lef      char            [^a]\n\tntSet                  = 11 // lef      set             [a-z\\s]  \\w \\s \\d\n\tntMulti                = 12 // lef      string          abcd\n\tntRef                  = 13 // lef      group           \\#\n\tntBol                  = 14 //                          ^\n\tntEol                  = 15 //                          $\n\tntBoundary             = 16 //                          \\b\n\tntNonboundary          = 17 //                          \\B\n\tntBeginning            = 18 //                          \\A\n\tntStart                = 19 //                          \\G\n\tntEndZ                 = 20 //                          \\Z\n\tntEnd                  = 21 //                          \\Z\n\n\t// Interior nodes do not correspond to primitive operations, but\n\t// control structures compositing other operations\n\n\t// Concat and alternate take n children, and can run forward or backwards\n\n\tntNothing     = 22 //          []\n\tntEmpty       = 23 //          ()\n\tntAlternate   = 24 //          a|b\n\tntConcatenate = 25 //          ab\n\tntLoop        = 26 // m,x      * + ? {,}\n\tntLazyloop    = 27 // m,x      *? +? ?? {,}?\n\tntCapture     = 28 // n        ()\n\tntGroup       = 29 //          (?:)\n\tntRequire     = 30 //          (?=) (?<=)\n\tntPrevent     = 31 //          (?!) (?<!)\n\tntGreedy      = 32 //          (?>) (?<)\n\tntTestref     = 33 //          (?(n) | )\n\tntTestgroup   = 34 //          (?(...) | )\n\n\tntECMABoundary    = 41 //                          \\b\n\tntNonECMABoundary = 42 //                          \\B\n)\n\nfunc newRegexNode(t nodeType, opt RegexOptions) *regexNode {\n\treturn &regexNode{\n\t\tt:       t,\n\t\toptions: opt,\n\t}\n}\n\nfunc newRegexNodeCh(t nodeType, opt RegexOptions, ch rune) *regexNode {\n\treturn &regexNode{\n\t\tt:       t,\n\t\toptions: opt,\n\t\tch:      ch,\n\t}\n}\n\nfunc newRegexNodeStr(t nodeType, opt RegexOptions, str []rune) *regexNode {\n\treturn &regexNode{\n\t\tt:       t,\n\t\toptions: opt,\n\t\tstr:     str,\n\t}\n}\n\nfunc newRegexNodeSet(t nodeType, opt RegexOptions, set *CharSet) *regexNode {\n\treturn &regexNode{\n\t\tt:       t,\n\t\toptions: opt,\n\t\tset:     set,\n\t}\n}\n\nfunc newRegexNodeM(t nodeType, opt RegexOptions, m int) *regexNode {\n\treturn &regexNode{\n\t\tt:       t,\n\t\toptions: opt,\n\t\tm:       m,\n\t}\n}\nfunc newRegexNodeMN(t nodeType, opt RegexOptions, m, n int) *regexNode {\n\treturn &regexNode{\n\t\tt:       t,\n\t\toptions: opt,\n\t\tm:       m,\n\t\tn:       n,\n\t}\n}\n\nfunc (n *regexNode) writeStrToBuf(buf *bytes.Buffer) {\n\tfor i := 0; i < len(n.str); i++ {\n\t\tbuf.WriteRune(n.str[i])\n\t}\n}\n\nfunc (n *regexNode) addChild(child *regexNode) {\n\treduced := child.reduce()\n\tn.children = append(n.children, reduced)\n\treduced.next = n\n}\n\nfunc (n *regexNode) insertChildren(afterIndex int, nodes []*regexNode) {\n\tnewChildren := make([]*regexNode, 0, len(n.children)+len(nodes))\n\tn.children = append(append(append(newChildren, n.children[:afterIndex]...), nodes...), n.children[afterIndex:]...)\n}\n\n// removes children including the start but not the end index\nfunc (n *regexNode) removeChildren(startIndex, endIndex int) {\n\tn.children = append(n.children[:startIndex], n.children[endIndex:]...)\n}\n\n// Pass type as OneLazy or OneLoop\nfunc (n *regexNode) makeRep(t nodeType, min, max int) {\n\tn.t += (t - ntOne)\n\tn.m = min\n\tn.n = max\n}\n\nfunc (n *regexNode) reduce() *regexNode {\n\tswitch n.t {\n\tcase ntAlternate:\n\t\treturn n.reduceAlternation()\n\n\tcase ntConcatenate:\n\t\treturn n.reduceConcatenation()\n\n\tcase ntLoop, ntLazyloop:\n\t\treturn n.reduceRep()\n\n\tcase ntGroup:\n\t\treturn n.reduceGroup()\n\n\tcase ntSet, ntSetloop:\n\t\treturn n.reduceSet()\n\n\tdefault:\n\t\treturn n\n\t}\n}\n\n// Basic optimization. Single-letter alternations can be replaced\n// by faster set specifications, and nested alternations with no\n// intervening operators can be flattened:\n//\n// a|b|c|def|g|h -> [a-c]|def|[gh]\n// apple|(?:orange|pear)|grape -> apple|orange|pear|grape\nfunc (n *regexNode) reduceAlternation() *regexNode {\n\tif len(n.children) == 0 {\n\t\treturn newRegexNode(ntNothing, n.options)\n\t}\n\n\twasLastSet := false\n\tlastNodeCannotMerge := false\n\tvar optionsLast RegexOptions\n\tvar i, j int\n\n\tfor i, j = 0, 0; i < len(n.children); i, j = i+1, j+1 {\n\t\tat := n.children[i]\n\n\t\tif j < i {\n\t\t\tn.children[j] = at\n\t\t}\n\n\t\tfor {\n\t\t\tif at.t == ntAlternate {\n\t\t\t\tfor k := 0; k < len(at.children); k++ {\n\t\t\t\t\tat.children[k].next = n\n\t\t\t\t}\n\t\t\t\tn.insertChildren(i+1, at.children)\n\n\t\t\t\tj--\n\t\t\t} else if at.t == ntSet || at.t == ntOne {\n\t\t\t\t// Cannot merge sets if L or I options differ, or if either are negated.\n\t\t\t\toptionsAt := at.options & (RightToLeft | IgnoreCase)\n\n\t\t\t\tif at.t == ntSet {\n\t\t\t\t\tif !wasLastSet || optionsLast != optionsAt || lastNodeCannotMerge || !at.set.IsMergeable() {\n\t\t\t\t\t\twasLastSet = true\n\t\t\t\t\t\tlastNodeCannotMerge = !at.set.IsMergeable()\n\t\t\t\t\t\toptionsLast = optionsAt\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t} else if !wasLastSet || optionsLast != optionsAt || lastNodeCannotMerge {\n\t\t\t\t\twasLastSet = true\n\t\t\t\t\tlastNodeCannotMerge = false\n\t\t\t\t\toptionsLast = optionsAt\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// The last node was a Set or a One, we're a Set or One and our options are the same.\n\t\t\t\t// Merge the two nodes.\n\t\t\t\tj--\n\t\t\t\tprev := n.children[j]\n\n\t\t\t\tvar prevCharClass *CharSet\n\t\t\t\tif prev.t == ntOne {\n\t\t\t\t\tprevCharClass = &CharSet{}\n\t\t\t\t\tprevCharClass.addChar(prev.ch)\n\t\t\t\t} else {\n\t\t\t\t\tprevCharClass = prev.set\n\t\t\t\t}\n\n\t\t\t\tif at.t == ntOne {\n\t\t\t\t\tprevCharClass.addChar(at.ch)\n\t\t\t\t} else {\n\t\t\t\t\tprevCharClass.addSet(*at.set)\n\t\t\t\t}\n\n\t\t\t\tprev.t = ntSet\n\t\t\t\tprev.set = prevCharClass\n\t\t\t} else if at.t == ntNothing {\n\t\t\t\tj--\n\t\t\t} else {\n\t\t\t\twasLastSet = false\n\t\t\t\tlastNodeCannotMerge = false\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif j < i {\n\t\tn.removeChildren(j, i)\n\t}\n\n\treturn n.stripEnation(ntNothing)\n}\n\n// Basic optimization. Adjacent strings can be concatenated.\n//\n// (?:abc)(?:def) -> abcdef\nfunc (n *regexNode) reduceConcatenation() *regexNode {\n\t// Eliminate empties and concat adjacent strings/chars\n\n\tvar optionsLast RegexOptions\n\tvar optionsAt RegexOptions\n\tvar i, j int\n\n\tif len(n.children) == 0 {\n\t\treturn newRegexNode(ntEmpty, n.options)\n\t}\n\n\twasLastString := false\n\n\tfor i, j = 0, 0; i < len(n.children); i, j = i+1, j+1 {\n\t\tvar at, prev *regexNode\n\n\t\tat = n.children[i]\n\n\t\tif j < i {\n\t\t\tn.children[j] = at\n\t\t}\n\n\t\tif at.t == ntConcatenate &&\n\t\t\t((at.options & RightToLeft) == (n.options & RightToLeft)) {\n\t\t\tfor k := 0; k < len(at.children); k++ {\n\t\t\t\tat.children[k].next = n\n\t\t\t}\n\n\t\t\t//insert at.children at i+1 index in n.children\n\t\t\tn.insertChildren(i+1, at.children)\n\n\t\t\tj--\n\t\t} else if at.t == ntMulti || at.t == ntOne {\n\t\t\t// Cannot merge strings if L or I options differ\n\t\t\toptionsAt = at.options & (RightToLeft | IgnoreCase)\n\n\t\t\tif !wasLastString || optionsLast != optionsAt {\n\t\t\t\twasLastString = true\n\t\t\t\toptionsLast = optionsAt\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tj--\n\t\t\tprev = n.children[j]\n\n\t\t\tif prev.t == ntOne {\n\t\t\t\tprev.t = ntMulti\n\t\t\t\tprev.str = []rune{prev.ch}\n\t\t\t}\n\n\t\t\tif (optionsAt & RightToLeft) == 0 {\n\t\t\t\tif at.t == ntOne {\n\t\t\t\t\tprev.str = append(prev.str, at.ch)\n\t\t\t\t} else {\n\t\t\t\t\tprev.str = append(prev.str, at.str...)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif at.t == ntOne {\n\t\t\t\t\t// insert at the front by expanding our slice, copying the data over, and then setting the value\n\t\t\t\t\tprev.str = append(prev.str, 0)\n\t\t\t\t\tcopy(prev.str[1:], prev.str)\n\t\t\t\t\tprev.str[0] = at.ch\n\t\t\t\t} else {\n\t\t\t\t\t//insert at the front...this one we'll make a new slice and copy both into it\n\t\t\t\t\tmerge := make([]rune, len(prev.str)+len(at.str))\n\t\t\t\t\tcopy(merge, at.str)\n\t\t\t\t\tcopy(merge[len(at.str):], prev.str)\n\t\t\t\t\tprev.str = merge\n\t\t\t\t}\n\t\t\t}\n\t\t} else if at.t == ntEmpty {\n\t\t\tj--\n\t\t} else {\n\t\t\twasLastString = false\n\t\t}\n\t}\n\n\tif j < i {\n\t\t// remove indices j through i from the children\n\t\tn.removeChildren(j, i)\n\t}\n\n\treturn n.stripEnation(ntEmpty)\n}\n\n// Nested repeaters just get multiplied with each other if they're not\n// too lumpy\nfunc (n *regexNode) reduceRep() *regexNode {\n\n\tu := n\n\tt := n.t\n\tmin := n.m\n\tmax := n.n\n\n\tfor {\n\t\tif len(u.children) == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\tchild := u.children[0]\n\n\t\t// multiply reps of the same type only\n\t\tif child.t != t {\n\t\t\tchildType := child.t\n\n\t\t\tif !(childType >= ntOneloop && childType <= ntSetloop && t == ntLoop ||\n\t\t\t\tchildType >= ntOnelazy && childType <= ntSetlazy && t == ntLazyloop) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t// child can be too lumpy to blur, e.g., (a {100,105}) {3} or (a {2,})?\n\t\t// [but things like (a {2,})+ are not too lumpy...]\n\t\tif u.m == 0 && child.m > 1 || child.n < child.m*2 {\n\t\t\tbreak\n\t\t}\n\n\t\tu = child\n\t\tif u.m > 0 {\n\t\t\tif (math.MaxInt32-1)/u.m < min {\n\t\t\t\tu.m = math.MaxInt32\n\t\t\t} else {\n\t\t\t\tu.m = u.m * min\n\t\t\t}\n\t\t}\n\t\tif u.n > 0 {\n\t\t\tif (math.MaxInt32-1)/u.n < max {\n\t\t\t\tu.n = math.MaxInt32\n\t\t\t} else {\n\t\t\t\tu.n = u.n * max\n\t\t\t}\n\t\t}\n\t}\n\n\tif math.MaxInt32 == min {\n\t\treturn newRegexNode(ntNothing, n.options)\n\t}\n\treturn u\n\n}\n\n// Simple optimization. If a concatenation or alternation has only\n// one child strip out the intermediate node. If it has zero children,\n// turn it into an empty.\nfunc (n *regexNode) stripEnation(emptyType nodeType) *regexNode {\n\tswitch len(n.children) {\n\tcase 0:\n\t\treturn newRegexNode(emptyType, n.options)\n\tcase 1:\n\t\treturn n.children[0]\n\tdefault:\n\t\treturn n\n\t}\n}\n\nfunc (n *regexNode) reduceGroup() *regexNode {\n\tu := n\n\n\tfor u.t == ntGroup {\n\t\tu = u.children[0]\n\t}\n\n\treturn u\n}\n\n// Simple optimization. If a set is a singleton, an inverse singleton,\n// or empty, it's transformed accordingly.\nfunc (n *regexNode) reduceSet() *regexNode {\n\t// Extract empty-set, one and not-one case as special\n\n\tif n.set == nil {\n\t\tn.t = ntNothing\n\t} else if n.set.IsSingleton() {\n\t\tn.ch = n.set.SingletonChar()\n\t\tn.set = nil\n\t\tn.t += (ntOne - ntSet)\n\t} else if n.set.IsSingletonInverse() {\n\t\tn.ch = n.set.SingletonChar()\n\t\tn.set = nil\n\t\tn.t += (ntNotone - ntSet)\n\t}\n\n\treturn n\n}\n\nfunc (n *regexNode) reverseLeft() *regexNode {\n\tif n.options&RightToLeft != 0 && n.t == ntConcatenate && len(n.children) > 0 {\n\t\t//reverse children order\n\t\tfor left, right := 0, len(n.children)-1; left < right; left, right = left+1, right-1 {\n\t\t\tn.children[left], n.children[right] = n.children[right], n.children[left]\n\t\t}\n\t}\n\n\treturn n\n}\n\nfunc (n *regexNode) makeQuantifier(lazy bool, min, max int) *regexNode {\n\tif min == 0 && max == 0 {\n\t\treturn newRegexNode(ntEmpty, n.options)\n\t}\n\n\tif min == 1 && max == 1 {\n\t\treturn n\n\t}\n\n\tswitch n.t {\n\tcase ntOne, ntNotone, ntSet:\n\t\tif lazy {\n\t\t\tn.makeRep(Onelazy, min, max)\n\t\t} else {\n\t\t\tn.makeRep(Oneloop, min, max)\n\t\t}\n\t\treturn n\n\n\tdefault:\n\t\tvar t nodeType\n\t\tif lazy {\n\t\t\tt = ntLazyloop\n\t\t} else {\n\t\t\tt = ntLoop\n\t\t}\n\t\tresult := newRegexNodeMN(t, n.options, min, max)\n\t\tresult.addChild(n)\n\t\treturn result\n\t}\n}\n\n// debug functions\n\nvar typeStr = []string{\n\t\"Onerep\", \"Notonerep\", \"Setrep\",\n\t\"Oneloop\", \"Notoneloop\", \"Setloop\",\n\t\"Onelazy\", \"Notonelazy\", \"Setlazy\",\n\t\"One\", \"Notone\", \"Set\",\n\t\"Multi\", \"Ref\",\n\t\"Bol\", \"Eol\", \"Boundary\", \"Nonboundary\",\n\t\"Beginning\", \"Start\", \"EndZ\", \"End\",\n\t\"Nothing\", \"Empty\",\n\t\"Alternate\", \"Concatenate\",\n\t\"Loop\", \"Lazyloop\",\n\t\"Capture\", \"Group\", \"Require\", \"Prevent\", \"Greedy\",\n\t\"Testref\", \"Testgroup\",\n\t\"Unknown\", \"Unknown\", \"Unknown\",\n\t\"Unknown\", \"Unknown\", \"Unknown\",\n\t\"ECMABoundary\", \"NonECMABoundary\",\n}\n\nfunc (n *regexNode) description() string {\n\tbuf := &bytes.Buffer{}\n\n\tbuf.WriteString(typeStr[n.t])\n\n\tif (n.options & ExplicitCapture) != 0 {\n\t\tbuf.WriteString(\"-C\")\n\t}\n\tif (n.options & IgnoreCase) != 0 {\n\t\tbuf.WriteString(\"-I\")\n\t}\n\tif (n.options & RightToLeft) != 0 {\n\t\tbuf.WriteString(\"-L\")\n\t}\n\tif (n.options & Multiline) != 0 {\n\t\tbuf.WriteString(\"-M\")\n\t}\n\tif (n.options & Singleline) != 0 {\n\t\tbuf.WriteString(\"-S\")\n\t}\n\tif (n.options & IgnorePatternWhitespace) != 0 {\n\t\tbuf.WriteString(\"-X\")\n\t}\n\tif (n.options & ECMAScript) != 0 {\n\t\tbuf.WriteString(\"-E\")\n\t}\n\n\tswitch n.t {\n\tcase ntOneloop, ntNotoneloop, ntOnelazy, ntNotonelazy, ntOne, ntNotone:\n\t\tbuf.WriteString(\"(Ch = \" + CharDescription(n.ch) + \")\")\n\t\tbreak\n\tcase ntCapture:\n\t\tbuf.WriteString(\"(index = \" + strconv.Itoa(n.m) + \", unindex = \" + strconv.Itoa(n.n) + \")\")\n\t\tbreak\n\tcase ntRef, ntTestref:\n\t\tbuf.WriteString(\"(index = \" + strconv.Itoa(n.m) + \")\")\n\t\tbreak\n\tcase ntMulti:\n\t\tfmt.Fprintf(buf, \"(String = %s)\", string(n.str))\n\t\tbreak\n\tcase ntSet, ntSetloop, ntSetlazy:\n\t\tbuf.WriteString(\"(Set = \" + n.set.String() + \")\")\n\t\tbreak\n\t}\n\n\tswitch n.t {\n\tcase ntOneloop, ntNotoneloop, ntOnelazy, ntNotonelazy, ntSetloop, ntSetlazy, ntLoop, ntLazyloop:\n\t\tbuf.WriteString(\"(Min = \")\n\t\tbuf.WriteString(strconv.Itoa(n.m))\n\t\tbuf.WriteString(\", Max = \")\n\t\tif n.n == math.MaxInt32 {\n\t\t\tbuf.WriteString(\"inf\")\n\t\t} else {\n\t\t\tbuf.WriteString(strconv.Itoa(n.n))\n\t\t}\n\t\tbuf.WriteString(\")\")\n\n\t\tbreak\n\t}\n\n\treturn buf.String()\n}\n\nvar padSpace = []byte(\"                                \")\n\nfunc (t *RegexTree) Dump() string {\n\treturn t.root.dump()\n}\n\nfunc (n *regexNode) dump() string {\n\tvar stack []int\n\tCurNode := n\n\tCurChild := 0\n\n\tbuf := bytes.NewBufferString(CurNode.description())\n\tbuf.WriteRune('\\n')\n\n\tfor {\n\t\tif CurNode.children != nil && CurChild < len(CurNode.children) {\n\t\t\tstack = append(stack, CurChild+1)\n\t\t\tCurNode = CurNode.children[CurChild]\n\t\t\tCurChild = 0\n\n\t\t\tDepth := len(stack)\n\t\t\tif Depth > 32 {\n\t\t\t\tDepth = 32\n\t\t\t}\n\t\t\tbuf.Write(padSpace[:Depth])\n\t\t\tbuf.WriteString(CurNode.description())\n\t\t\tbuf.WriteRune('\\n')\n\t\t} else {\n\t\t\tif len(stack) == 0 {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tCurChild = stack[len(stack)-1]\n\t\t\tstack = stack[:len(stack)-1]\n\t\t\tCurNode = CurNode.next\n\t\t}\n\t}\n\treturn buf.String()\n}\n"
  },
  {
    "path": "vendor/github.com/dlclark/regexp2/syntax/writer.go",
    "content": "package syntax\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n)\n\nfunc Write(tree *RegexTree) (*Code, error) {\n\tw := writer{\n\t\tintStack:   make([]int, 0, 32),\n\t\temitted:    make([]int, 2),\n\t\tstringhash: make(map[string]int),\n\t\tsethash:    make(map[string]int),\n\t}\n\n\tcode, err := w.codeFromTree(tree)\n\n\tif tree.options&Debug > 0 && code != nil {\n\t\tos.Stdout.WriteString(code.Dump())\n\t\tos.Stdout.WriteString(\"\\n\")\n\t}\n\n\treturn code, err\n}\n\ntype writer struct {\n\temitted []int\n\n\tintStack    []int\n\tcurpos      int\n\tstringhash  map[string]int\n\tstringtable [][]rune\n\tsethash     map[string]int\n\tsettable    []*CharSet\n\tcounting    bool\n\tcount       int\n\ttrackcount  int\n\tcaps        map[int]int\n}\n\nconst (\n\tbeforeChild nodeType = 64\n\tafterChild           = 128\n\t//MaxPrefixSize is the largest number of runes we'll use for a BoyerMoyer prefix\n\tMaxPrefixSize = 50\n)\n\n// The top level RegexCode generator. It does a depth-first walk\n// through the tree and calls EmitFragment to emits code before\n// and after each child of an interior node, and at each leaf.\n//\n// It runs two passes, first to count the size of the generated\n// code, and second to generate the code.\n//\n// We should time it against the alternative, which is\n// to just generate the code and grow the array as we go.\nfunc (w *writer) codeFromTree(tree *RegexTree) (*Code, error) {\n\tvar (\n\t\tcurNode  *regexNode\n\t\tcurChild int\n\t\tcapsize  int\n\t)\n\t// construct sparse capnum mapping if some numbers are unused\n\n\tif tree.capnumlist == nil || tree.captop == len(tree.capnumlist) {\n\t\tcapsize = tree.captop\n\t\tw.caps = nil\n\t} else {\n\t\tcapsize = len(tree.capnumlist)\n\t\tw.caps = tree.caps\n\t\tfor i := 0; i < len(tree.capnumlist); i++ {\n\t\t\tw.caps[tree.capnumlist[i]] = i\n\t\t}\n\t}\n\n\tw.counting = true\n\n\tfor {\n\t\tif !w.counting {\n\t\t\tw.emitted = make([]int, w.count)\n\t\t}\n\n\t\tcurNode = tree.root\n\t\tcurChild = 0\n\n\t\tw.emit1(Lazybranch, 0)\n\n\t\tfor {\n\t\t\tif len(curNode.children) == 0 {\n\t\t\t\tw.emitFragment(curNode.t, curNode, 0)\n\t\t\t} else if curChild < len(curNode.children) {\n\t\t\t\tw.emitFragment(curNode.t|beforeChild, curNode, curChild)\n\n\t\t\t\tcurNode = curNode.children[curChild]\n\n\t\t\t\tw.pushInt(curChild)\n\t\t\t\tcurChild = 0\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif w.emptyStack() {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tcurChild = w.popInt()\n\t\t\tcurNode = curNode.next\n\n\t\t\tw.emitFragment(curNode.t|afterChild, curNode, curChild)\n\t\t\tcurChild++\n\t\t}\n\n\t\tw.patchJump(0, w.curPos())\n\t\tw.emit(Stop)\n\n\t\tif !w.counting {\n\t\t\tbreak\n\t\t}\n\n\t\tw.counting = false\n\t}\n\n\tfcPrefix := getFirstCharsPrefix(tree)\n\tprefix := getPrefix(tree)\n\trtl := (tree.options & RightToLeft) != 0\n\n\tvar bmPrefix *BmPrefix\n\t//TODO: benchmark string prefixes\n\tif prefix != nil && len(prefix.PrefixStr) > 0 && MaxPrefixSize > 0 {\n\t\tif len(prefix.PrefixStr) > MaxPrefixSize {\n\t\t\t// limit prefix changes to 10k\n\t\t\tprefix.PrefixStr = prefix.PrefixStr[:MaxPrefixSize]\n\t\t}\n\t\tbmPrefix = newBmPrefix(prefix.PrefixStr, prefix.CaseInsensitive, rtl)\n\t} else {\n\t\tbmPrefix = nil\n\t}\n\n\treturn &Code{\n\t\tCodes:       w.emitted,\n\t\tStrings:     w.stringtable,\n\t\tSets:        w.settable,\n\t\tTrackCount:  w.trackcount,\n\t\tCaps:        w.caps,\n\t\tCapsize:     capsize,\n\t\tFcPrefix:    fcPrefix,\n\t\tBmPrefix:    bmPrefix,\n\t\tAnchors:     getAnchors(tree),\n\t\tRightToLeft: rtl,\n\t}, nil\n}\n\n// The main RegexCode generator. It does a depth-first walk\n// through the tree and calls EmitFragment to emits code before\n// and after each child of an interior node, and at each leaf.\nfunc (w *writer) emitFragment(nodetype nodeType, node *regexNode, curIndex int) error {\n\tbits := InstOp(0)\n\n\tif nodetype <= ntRef {\n\t\tif (node.options & RightToLeft) != 0 {\n\t\t\tbits |= Rtl\n\t\t}\n\t\tif (node.options & IgnoreCase) != 0 {\n\t\t\tbits |= Ci\n\t\t}\n\t}\n\tntBits := nodeType(bits)\n\n\tswitch nodetype {\n\tcase ntConcatenate | beforeChild, ntConcatenate | afterChild, ntEmpty:\n\t\tbreak\n\n\tcase ntAlternate | beforeChild:\n\t\tif curIndex < len(node.children)-1 {\n\t\t\tw.pushInt(w.curPos())\n\t\t\tw.emit1(Lazybranch, 0)\n\t\t}\n\n\tcase ntAlternate | afterChild:\n\t\tif curIndex < len(node.children)-1 {\n\t\t\tlbPos := w.popInt()\n\t\t\tw.pushInt(w.curPos())\n\t\t\tw.emit1(Goto, 0)\n\t\t\tw.patchJump(lbPos, w.curPos())\n\t\t} else {\n\t\t\tfor i := 0; i < curIndex; i++ {\n\t\t\t\tw.patchJump(w.popInt(), w.curPos())\n\t\t\t}\n\t\t}\n\t\tbreak\n\n\tcase ntTestref | beforeChild:\n\t\tif curIndex == 0 {\n\t\t\tw.emit(Setjump)\n\t\t\tw.pushInt(w.curPos())\n\t\t\tw.emit1(Lazybranch, 0)\n\t\t\tw.emit1(Testref, w.mapCapnum(node.m))\n\t\t\tw.emit(Forejump)\n\t\t}\n\n\tcase ntTestref | afterChild:\n\t\tif curIndex == 0 {\n\t\t\tbranchpos := w.popInt()\n\t\t\tw.pushInt(w.curPos())\n\t\t\tw.emit1(Goto, 0)\n\t\t\tw.patchJump(branchpos, w.curPos())\n\t\t\tw.emit(Forejump)\n\t\t\tif len(node.children) <= 1 {\n\t\t\t\tw.patchJump(w.popInt(), w.curPos())\n\t\t\t}\n\t\t} else if curIndex == 1 {\n\t\t\tw.patchJump(w.popInt(), w.curPos())\n\t\t}\n\n\tcase ntTestgroup | beforeChild:\n\t\tif curIndex == 0 {\n\t\t\tw.emit(Setjump)\n\t\t\tw.emit(Setmark)\n\t\t\tw.pushInt(w.curPos())\n\t\t\tw.emit1(Lazybranch, 0)\n\t\t}\n\n\tcase ntTestgroup | afterChild:\n\t\tif curIndex == 0 {\n\t\t\tw.emit(Getmark)\n\t\t\tw.emit(Forejump)\n\t\t} else if curIndex == 1 {\n\t\t\tBranchpos := w.popInt()\n\t\t\tw.pushInt(w.curPos())\n\t\t\tw.emit1(Goto, 0)\n\t\t\tw.patchJump(Branchpos, w.curPos())\n\t\t\tw.emit(Getmark)\n\t\t\tw.emit(Forejump)\n\t\t\tif len(node.children) <= 2 {\n\t\t\t\tw.patchJump(w.popInt(), w.curPos())\n\t\t\t}\n\t\t} else if curIndex == 2 {\n\t\t\tw.patchJump(w.popInt(), w.curPos())\n\t\t}\n\n\tcase ntLoop | beforeChild, ntLazyloop | beforeChild:\n\n\t\tif node.n < math.MaxInt32 || node.m > 1 {\n\t\t\tif node.m == 0 {\n\t\t\t\tw.emit1(Nullcount, 0)\n\t\t\t} else {\n\t\t\t\tw.emit1(Setcount, 1-node.m)\n\t\t\t}\n\t\t} else if node.m == 0 {\n\t\t\tw.emit(Nullmark)\n\t\t} else {\n\t\t\tw.emit(Setmark)\n\t\t}\n\n\t\tif node.m == 0 {\n\t\t\tw.pushInt(w.curPos())\n\t\t\tw.emit1(Goto, 0)\n\t\t}\n\t\tw.pushInt(w.curPos())\n\n\tcase ntLoop | afterChild, ntLazyloop | afterChild:\n\n\t\tstartJumpPos := w.curPos()\n\t\tlazy := (nodetype - (ntLoop | afterChild))\n\n\t\tif node.n < math.MaxInt32 || node.m > 1 {\n\t\t\tif node.n == math.MaxInt32 {\n\t\t\t\tw.emit2(InstOp(Branchcount+lazy), w.popInt(), math.MaxInt32)\n\t\t\t} else {\n\t\t\t\tw.emit2(InstOp(Branchcount+lazy), w.popInt(), node.n-node.m)\n\t\t\t}\n\t\t} else {\n\t\t\tw.emit1(InstOp(Branchmark+lazy), w.popInt())\n\t\t}\n\n\t\tif node.m == 0 {\n\t\t\tw.patchJump(w.popInt(), startJumpPos)\n\t\t}\n\n\tcase ntGroup | beforeChild, ntGroup | afterChild:\n\n\tcase ntCapture | beforeChild:\n\t\tw.emit(Setmark)\n\n\tcase ntCapture | afterChild:\n\t\tw.emit2(Capturemark, w.mapCapnum(node.m), w.mapCapnum(node.n))\n\n\tcase ntRequire | beforeChild:\n\t\t// NOTE: the following line causes lookahead/lookbehind to be\n\t\t// NON-BACKTRACKING. It can be commented out with (*)\n\t\tw.emit(Setjump)\n\n\t\tw.emit(Setmark)\n\n\tcase ntRequire | afterChild:\n\t\tw.emit(Getmark)\n\n\t\t// NOTE: the following line causes lookahead/lookbehind to be\n\t\t// NON-BACKTRACKING. It can be commented out with (*)\n\t\tw.emit(Forejump)\n\n\tcase ntPrevent | beforeChild:\n\t\tw.emit(Setjump)\n\t\tw.pushInt(w.curPos())\n\t\tw.emit1(Lazybranch, 0)\n\n\tcase ntPrevent | afterChild:\n\t\tw.emit(Backjump)\n\t\tw.patchJump(w.popInt(), w.curPos())\n\t\tw.emit(Forejump)\n\n\tcase ntGreedy | beforeChild:\n\t\tw.emit(Setjump)\n\n\tcase ntGreedy | afterChild:\n\t\tw.emit(Forejump)\n\n\tcase ntOne, ntNotone:\n\t\tw.emit1(InstOp(node.t|ntBits), int(node.ch))\n\n\tcase ntNotoneloop, ntNotonelazy, ntOneloop, ntOnelazy:\n\t\tif node.m > 0 {\n\t\t\tif node.t == ntOneloop || node.t == ntOnelazy {\n\t\t\t\tw.emit2(Onerep|bits, int(node.ch), node.m)\n\t\t\t} else {\n\t\t\t\tw.emit2(Notonerep|bits, int(node.ch), node.m)\n\t\t\t}\n\t\t}\n\t\tif node.n > node.m {\n\t\t\tif node.n == math.MaxInt32 {\n\t\t\t\tw.emit2(InstOp(node.t|ntBits), int(node.ch), math.MaxInt32)\n\t\t\t} else {\n\t\t\t\tw.emit2(InstOp(node.t|ntBits), int(node.ch), node.n-node.m)\n\t\t\t}\n\t\t}\n\n\tcase ntSetloop, ntSetlazy:\n\t\tif node.m > 0 {\n\t\t\tw.emit2(Setrep|bits, w.setCode(node.set), node.m)\n\t\t}\n\t\tif node.n > node.m {\n\t\t\tif node.n == math.MaxInt32 {\n\t\t\t\tw.emit2(InstOp(node.t|ntBits), w.setCode(node.set), math.MaxInt32)\n\t\t\t} else {\n\t\t\t\tw.emit2(InstOp(node.t|ntBits), w.setCode(node.set), node.n-node.m)\n\t\t\t}\n\t\t}\n\n\tcase ntMulti:\n\t\tw.emit1(InstOp(node.t|ntBits), w.stringCode(node.str))\n\n\tcase ntSet:\n\t\tw.emit1(InstOp(node.t|ntBits), w.setCode(node.set))\n\n\tcase ntRef:\n\t\tw.emit1(InstOp(node.t|ntBits), w.mapCapnum(node.m))\n\n\tcase ntNothing, ntBol, ntEol, ntBoundary, ntNonboundary, ntECMABoundary, ntNonECMABoundary, ntBeginning, ntStart, ntEndZ, ntEnd:\n\t\tw.emit(InstOp(node.t))\n\n\tdefault:\n\t\treturn fmt.Errorf(\"unexpected opcode in regular expression generation: %v\", nodetype)\n\t}\n\n\treturn nil\n}\n\n// To avoid recursion, we use a simple integer stack.\n// This is the push.\nfunc (w *writer) pushInt(i int) {\n\tw.intStack = append(w.intStack, i)\n}\n\n// Returns true if the stack is empty.\nfunc (w *writer) emptyStack() bool {\n\treturn len(w.intStack) == 0\n}\n\n// This is the pop.\nfunc (w *writer) popInt() int {\n\t//get our item\n\tidx := len(w.intStack) - 1\n\ti := w.intStack[idx]\n\t//trim our slice\n\tw.intStack = w.intStack[:idx]\n\treturn i\n}\n\n// Returns the current position in the emitted code.\nfunc (w *writer) curPos() int {\n\treturn w.curpos\n}\n\n// Fixes up a jump instruction at the specified offset\n// so that it jumps to the specified jumpDest.\nfunc (w *writer) patchJump(offset, jumpDest int) {\n\tw.emitted[offset+1] = jumpDest\n}\n\n// Returns an index in the set table for a charset\n// uses a map to eliminate duplicates.\nfunc (w *writer) setCode(set *CharSet) int {\n\tif w.counting {\n\t\treturn 0\n\t}\n\n\tbuf := &bytes.Buffer{}\n\n\tset.mapHashFill(buf)\n\thash := buf.String()\n\ti, ok := w.sethash[hash]\n\tif !ok {\n\t\ti = len(w.sethash)\n\t\tw.sethash[hash] = i\n\t\tw.settable = append(w.settable, set)\n\t}\n\treturn i\n}\n\n// Returns an index in the string table for a string.\n// uses a map to eliminate duplicates.\nfunc (w *writer) stringCode(str []rune) int {\n\tif w.counting {\n\t\treturn 0\n\t}\n\n\thash := string(str)\n\ti, ok := w.stringhash[hash]\n\tif !ok {\n\t\ti = len(w.stringhash)\n\t\tw.stringhash[hash] = i\n\t\tw.stringtable = append(w.stringtable, str)\n\t}\n\n\treturn i\n}\n\n// When generating code on a regex that uses a sparse set\n// of capture slots, we hash them to a dense set of indices\n// for an array of capture slots. Instead of doing the hash\n// at match time, it's done at compile time, here.\nfunc (w *writer) mapCapnum(capnum int) int {\n\tif capnum == -1 {\n\t\treturn -1\n\t}\n\n\tif w.caps != nil {\n\t\treturn w.caps[capnum]\n\t}\n\n\treturn capnum\n}\n\n// Emits a zero-argument operation. Note that the emit\n// functions all run in two modes: they can emit code, or\n// they can just count the size of the code.\nfunc (w *writer) emit(op InstOp) {\n\tif w.counting {\n\t\tw.count++\n\t\tif opcodeBacktracks(op) {\n\t\t\tw.trackcount++\n\t\t}\n\t\treturn\n\t}\n\tw.emitted[w.curpos] = int(op)\n\tw.curpos++\n}\n\n// Emits a one-argument operation.\nfunc (w *writer) emit1(op InstOp, opd1 int) {\n\tif w.counting {\n\t\tw.count += 2\n\t\tif opcodeBacktracks(op) {\n\t\t\tw.trackcount++\n\t\t}\n\t\treturn\n\t}\n\tw.emitted[w.curpos] = int(op)\n\tw.curpos++\n\tw.emitted[w.curpos] = opd1\n\tw.curpos++\n}\n\n// Emits a two-argument operation.\nfunc (w *writer) emit2(op InstOp, opd1, opd2 int) {\n\tif w.counting {\n\t\tw.count += 3\n\t\tif opcodeBacktracks(op) {\n\t\t\tw.trackcount++\n\t\t}\n\t\treturn\n\t}\n\tw.emitted[w.curpos] = int(op)\n\tw.curpos++\n\tw.emitted[w.curpos] = opd1\n\tw.curpos++\n\tw.emitted[w.curpos] = opd2\n\tw.curpos++\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2020 Evan Wallace\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/api_helpers/use_timer.go",
    "content": "package api_helpers\n\n// This flag is set by the CLI to activate the timer. It's put here instead of\n// by the timer to discourage code from checking this flag. Only the code that\n// creates the root timer should check this flag. Other code should check that\n// the timer is not null to detect if the timer is being used or not.\nvar UseTimer bool\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/ast/ast.go",
    "content": "package ast\n\n// This file contains data structures that are used with the AST packages for\n// both JavaScript and CSS. This helps the bundler treat both AST formats in\n// a somewhat format-agnostic manner.\n\nimport (\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\ntype ImportKind uint8\n\nconst (\n\t// An entry point provided by the user\n\tImportEntryPoint ImportKind = iota\n\n\t// An ES6 import or re-export statement\n\tImportStmt\n\n\t// A call to \"require()\"\n\tImportRequire\n\n\t// An \"import()\" expression with a string argument\n\tImportDynamic\n\n\t// A call to \"require.resolve()\"\n\tImportRequireResolve\n\n\t// A CSS \"@import\" rule\n\tImportAt\n\n\t// A CSS \"composes\" declaration\n\tImportComposesFrom\n\n\t// A CSS \"url(...)\" token\n\tImportURL\n)\n\nfunc (kind ImportKind) StringForMetafile() string {\n\tswitch kind {\n\tcase ImportStmt:\n\t\treturn \"import-statement\"\n\tcase ImportRequire:\n\t\treturn \"require-call\"\n\tcase ImportDynamic:\n\t\treturn \"dynamic-import\"\n\tcase ImportRequireResolve:\n\t\treturn \"require-resolve\"\n\tcase ImportAt:\n\t\treturn \"import-rule\"\n\tcase ImportComposesFrom:\n\t\treturn \"composes-from\"\n\tcase ImportURL:\n\t\treturn \"url-token\"\n\tcase ImportEntryPoint:\n\t\treturn \"entry-point\"\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\nfunc (kind ImportKind) IsFromCSS() bool {\n\tswitch kind {\n\tcase ImportAt, ImportComposesFrom, ImportURL:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (kind ImportKind) MustResolveToCSS() bool {\n\tswitch kind {\n\tcase ImportAt, ImportComposesFrom:\n\t\treturn true\n\t}\n\treturn false\n}\n\ntype ImportPhase uint8\n\nconst (\n\tEvaluationPhase ImportPhase = iota\n\n\t// See: https://github.com/tc39/proposal-defer-import-eval\n\tDeferPhase\n\n\t// See: https://github.com/tc39/proposal-source-phase-imports\n\tSourcePhase\n)\n\ntype ImportRecordFlags uint16\n\nconst (\n\t// Sometimes the parser creates an import record and decides it isn't needed.\n\t// For example, TypeScript code may have import statements that later turn\n\t// out to be type-only imports after analyzing the whole file.\n\tIsUnused ImportRecordFlags = 1 << iota\n\n\t// If this is true, the import contains syntax like \"* as ns\". This is used\n\t// to determine whether modules that have no exports need to be wrapped in a\n\t// CommonJS wrapper or not.\n\tContainsImportStar\n\n\t// If this is true, the import contains an import for the alias \"default\",\n\t// either via the \"import x from\" or \"import {default as x} from\" syntax.\n\tContainsDefaultAlias\n\n\t// If this is true, the import contains an import for the alias \"__esModule\",\n\t// via the \"import {__esModule} from\" syntax.\n\tContainsESModuleAlias\n\n\t// If true, this \"export * from 'path'\" statement is evaluated at run-time by\n\t// calling the \"__reExport()\" helper function\n\tCallsRunTimeReExportFn\n\n\t// Tell the printer to wrap this call to \"require()\" in \"__toESM(...)\"\n\tWrapWithToESM\n\n\t// Tell the printer to wrap this ESM exports object in \"__toCJS(...)\"\n\tWrapWithToCJS\n\n\t// Tell the printer to use the runtime \"__require()\" instead of \"require()\"\n\tCallRuntimeRequire\n\n\t// True for the following cases:\n\t//\n\t//   try { require('x') } catch { handle }\n\t//   try { await import('x') } catch { handle }\n\t//   try { require.resolve('x') } catch { handle }\n\t//   import('x').catch(handle)\n\t//   import('x').then(_, handle)\n\t//\n\t// In these cases we shouldn't generate an error if the path could not be\n\t// resolved.\n\tHandlesImportErrors\n\n\t// If true, this was originally written as a bare \"import 'file'\" statement\n\tWasOriginallyBareImport\n\n\t// If true, this import can be removed if it's unused\n\tIsExternalWithoutSideEffects\n\n\t// If true, \"assert { type: 'json' }\" was present\n\tAssertTypeJSON\n\n\t// If true, do not generate \"external\": true in the metafile\n\tShouldNotBeExternalInMetafile\n\n\t// CSS \"@import\" of an empty file should be removed\n\tWasLoadedWithEmptyLoader\n\n\t// Unique keys are randomly-generated strings that are used to replace paths\n\t// in the source code after it's printed. These must not ever be split apart.\n\tContainsUniqueKey\n)\n\nfunc (flags ImportRecordFlags) Has(flag ImportRecordFlags) bool {\n\treturn (flags & flag) != 0\n}\n\ntype ImportRecord struct {\n\tAssertOrWith *ImportAssertOrWith\n\tGlobPattern  *GlobPattern\n\tPath         logger.Path\n\tRange        logger.Range\n\n\t// If the \"HandlesImportErrors\" flag is present, then this is the location\n\t// of the error handler. This is used for error reporting.\n\tErrorHandlerLoc logger.Loc\n\n\t// The resolved source index for an internal import (within the bundle) or\n\t// invalid for an external import (not included in the bundle)\n\tSourceIndex Index32\n\n\t// Files imported via the \"copy\" loader use this instead of \"SourceIndex\"\n\t// because they are sort of like external imports, and are not bundled.\n\tCopySourceIndex Index32\n\n\tFlags ImportRecordFlags\n\tPhase ImportPhase\n\tKind  ImportKind\n}\n\ntype AssertOrWithKeyword uint8\n\nconst (\n\tAssertKeyword AssertOrWithKeyword = iota\n\tWithKeyword\n)\n\nfunc (kw AssertOrWithKeyword) String() string {\n\tif kw == AssertKeyword {\n\t\treturn \"assert\"\n\t}\n\treturn \"with\"\n}\n\ntype ImportAssertOrWith struct {\n\tEntries            []AssertOrWithEntry\n\tKeywordLoc         logger.Loc\n\tInnerOpenBraceLoc  logger.Loc\n\tInnerCloseBraceLoc logger.Loc\n\tOuterOpenBraceLoc  logger.Loc\n\tOuterCloseBraceLoc logger.Loc\n\tKeyword            AssertOrWithKeyword\n}\n\ntype AssertOrWithEntry struct {\n\tKey             []uint16 // An identifier or a string\n\tValue           []uint16 // Always a string\n\tKeyLoc          logger.Loc\n\tValueLoc        logger.Loc\n\tPreferQuotedKey bool\n}\n\nfunc FindAssertOrWithEntry(assertions []AssertOrWithEntry, name string) *AssertOrWithEntry {\n\tfor _, assertion := range assertions {\n\t\tif helpers.UTF16EqualsString(assertion.Key, name) {\n\t\t\treturn &assertion\n\t\t}\n\t}\n\treturn nil\n}\n\ntype GlobPattern struct {\n\tParts       []helpers.GlobPart\n\tExportAlias string\n\tKind        ImportKind\n}\n\n// This stores a 32-bit index where the zero value is an invalid index. This is\n// a better alternative to storing the index as a pointer since that has the\n// same properties but takes up more space and costs an extra pointer traversal.\ntype Index32 struct {\n\tflippedBits uint32\n}\n\nfunc MakeIndex32(index uint32) Index32 {\n\treturn Index32{flippedBits: ^index}\n}\n\nfunc (i Index32) IsValid() bool {\n\treturn i.flippedBits != 0\n}\n\nfunc (i Index32) GetIndex() uint32 {\n\treturn ^i.flippedBits\n}\n\ntype SymbolKind uint8\n\nconst (\n\t// An unbound symbol is one that isn't declared in the file it's referenced\n\t// in. For example, using \"window\" without declaring it will be unbound.\n\tSymbolUnbound SymbolKind = iota\n\n\t// This has special merging behavior. You're allowed to re-declare these\n\t// symbols more than once in the same scope. These symbols are also hoisted\n\t// out of the scope they are declared in to the closest containing function\n\t// or module scope. These are the symbols with this kind:\n\t//\n\t// - Function arguments\n\t// - Function statements\n\t// - Variables declared using \"var\"\n\t//\n\tSymbolHoisted\n\tSymbolHoistedFunction\n\n\t// There's a weird special case where catch variables declared using a simple\n\t// identifier (i.e. not a binding pattern) block hoisted variables instead of\n\t// becoming an error:\n\t//\n\t//   var e = 0;\n\t//   try { throw 1 } catch (e) {\n\t//     print(e) // 1\n\t//     var e = 2\n\t//     print(e) // 2\n\t//   }\n\t//   print(e) // 0 (since the hoisting stops at the catch block boundary)\n\t//\n\t// However, other forms are still a syntax error:\n\t//\n\t//   try {} catch (e) { let e }\n\t//   try {} catch ({e}) { var e }\n\t//\n\t// This symbol is for handling this weird special case.\n\tSymbolCatchIdentifier\n\n\t// Generator and async functions are not hoisted, but still have special\n\t// properties such as being able to overwrite previous functions with the\n\t// same name\n\tSymbolGeneratorOrAsyncFunction\n\n\t// This is the special \"arguments\" variable inside functions\n\tSymbolArguments\n\n\t// Classes can merge with TypeScript namespaces.\n\tSymbolClass\n\n\t// Class names are not allowed to be referenced by computed property keys\n\tSymbolClassInComputedPropertyKey\n\n\t// A class-private identifier (i.e. \"#foo\").\n\tSymbolPrivateField\n\tSymbolPrivateMethod\n\tSymbolPrivateGet\n\tSymbolPrivateSet\n\tSymbolPrivateGetSetPair\n\tSymbolPrivateStaticField\n\tSymbolPrivateStaticMethod\n\tSymbolPrivateStaticGet\n\tSymbolPrivateStaticSet\n\tSymbolPrivateStaticGetSetPair\n\n\t// Labels are in their own namespace\n\tSymbolLabel\n\n\t// TypeScript enums can merge with TypeScript namespaces and other TypeScript\n\t// enums.\n\tSymbolTSEnum\n\n\t// TypeScript namespaces can merge with classes, functions, TypeScript enums,\n\t// and other TypeScript namespaces.\n\tSymbolTSNamespace\n\n\t// In TypeScript, imports are allowed to silently collide with symbols within\n\t// the module. Presumably this is because the imports may be type-only.\n\tSymbolImport\n\n\t// Assigning to a \"const\" symbol will throw a TypeError at runtime\n\tSymbolConst\n\n\t// Injected symbols can be overridden by provided defines\n\tSymbolInjected\n\n\t// Properties can optionally be renamed to shorter names\n\tSymbolMangledProp\n\n\t// CSS identifiers that are never renamed\n\tSymbolGlobalCSS\n\n\t// CSS identifiers that are renamed to be unique to the file they are in\n\tSymbolLocalCSS\n\n\t// This annotates all other symbols that don't have special behavior\n\tSymbolOther\n)\n\nfunc (kind SymbolKind) IsPrivate() bool {\n\treturn kind >= SymbolPrivateField && kind <= SymbolPrivateStaticGetSetPair\n}\n\nfunc (kind SymbolKind) IsHoisted() bool {\n\treturn kind == SymbolHoisted || kind == SymbolHoistedFunction\n}\n\nfunc (kind SymbolKind) IsHoistedOrFunction() bool {\n\treturn kind.IsHoisted() || kind == SymbolGeneratorOrAsyncFunction\n}\n\nfunc (kind SymbolKind) IsFunction() bool {\n\treturn kind == SymbolHoistedFunction || kind == SymbolGeneratorOrAsyncFunction\n}\n\nfunc (kind SymbolKind) IsUnboundOrInjected() bool {\n\treturn kind == SymbolUnbound || kind == SymbolInjected\n}\n\nvar InvalidRef Ref = Ref{^uint32(0), ^uint32(0)}\n\n// Files are parsed in parallel for speed. We want to allow each parser to\n// generate symbol IDs that won't conflict with each other. We also want to be\n// able to quickly merge symbol tables from all files into one giant symbol\n// table.\n//\n// We can accomplish both goals by giving each symbol ID two parts: a source\n// index that is unique to the parser goroutine, and an inner index that\n// increments as the parser generates new symbol IDs. Then a symbol map can\n// be an array of arrays indexed first by source index, then by inner index.\n// The maps can be merged quickly by creating a single outer array containing\n// all inner arrays from all parsed files.\ntype Ref struct {\n\tSourceIndex uint32\n\tInnerIndex  uint32\n}\n\ntype LocRef struct {\n\tLoc logger.Loc\n\tRef Ref\n}\n\ntype ImportItemStatus uint8\n\nconst (\n\tImportItemNone ImportItemStatus = iota\n\n\t// The linker doesn't report import/export mismatch errors\n\tImportItemGenerated\n\n\t// The printer will replace this import with \"undefined\"\n\tImportItemMissing\n)\n\ntype SymbolFlags uint16\n\nconst (\n\t// Certain symbols must not be renamed or minified. For example, the\n\t// \"arguments\" variable is declared by the runtime for every function.\n\t// Renaming can also break any identifier used inside a \"with\" statement.\n\tMustNotBeRenamed SymbolFlags = 1 << iota\n\n\t// In React's version of JSX, lower-case names are strings while upper-case\n\t// names are identifiers. If we are preserving JSX syntax (i.e. not\n\t// transforming it), then we need to be careful to name the identifiers\n\t// something with a capital letter so further JSX processing doesn't treat\n\t// them as strings instead.\n\tMustStartWithCapitalLetterForJSX\n\n\t// If true, this symbol is the target of a \"__name\" helper function call.\n\t// This call is special because it deliberately doesn't count as a use\n\t// of the symbol (otherwise keeping names would disable tree shaking)\n\t// so \"UseCountEstimate\" is not incremented. This flag helps us know to\n\t// avoid optimizing this symbol when \"UseCountEstimate\" is 1 in this case.\n\tDidKeepName\n\n\t// Sometimes we lower private symbols even if they are supported. For example,\n\t// consider the following TypeScript code:\n\t//\n\t//   class Foo {\n\t//     #foo = 123\n\t//     bar = this.#foo\n\t//   }\n\t//\n\t// If \"useDefineForClassFields: false\" is set in \"tsconfig.json\", then \"bar\"\n\t// must use assignment semantics instead of define semantics. We can compile\n\t// that to this code:\n\t//\n\t//   class Foo {\n\t//     constructor() {\n\t//       this.#foo = 123;\n\t//       this.bar = this.#foo;\n\t//     }\n\t//     #foo;\n\t//   }\n\t//\n\t// However, we can't do the same for static fields:\n\t//\n\t//   class Foo {\n\t//     static #foo = 123\n\t//     static bar = this.#foo\n\t//   }\n\t//\n\t// Compiling these static fields to something like this would be invalid:\n\t//\n\t//   class Foo {\n\t//     static #foo;\n\t//   }\n\t//   Foo.#foo = 123;\n\t//   Foo.bar = Foo.#foo;\n\t//\n\t// Thus \"#foo\" must be lowered even though it's supported. Another case is\n\t// when we're converting top-level class declarations to class expressions\n\t// to avoid the TDZ and the class shadowing symbol is referenced within the\n\t// class body:\n\t//\n\t//   class Foo {\n\t//     static #foo = Foo\n\t//   }\n\t//\n\t// This cannot be converted into something like this:\n\t//\n\t//   var Foo = class {\n\t//     static #foo;\n\t//   };\n\t//   Foo.#foo = Foo;\n\t//\n\tPrivateSymbolMustBeLowered\n\n\t// This is used to remove the all but the last function re-declaration if a\n\t// function is re-declared multiple times like this:\n\t//\n\t//   function foo() { console.log(1) }\n\t//   function foo() { console.log(2) }\n\t//\n\tRemoveOverwrittenFunctionDeclaration\n\n\t// This flag is to avoid warning about this symbol more than once. It only\n\t// applies to the \"module\" and \"exports\" unbound symbols.\n\tDidWarnAboutCommonJSInESM\n\n\t// If this is present, the symbol could potentially be overwritten. This means\n\t// it's not safe to make assumptions about this symbol from the initializer.\n\tCouldPotentiallyBeMutated\n\n\t// This flags all symbols that were exported from the module using the ES6\n\t// \"export\" keyword, either directly on the declaration or using \"export {}\".\n\tWasExported\n\n\t// This means the symbol is a normal function that has no body statements.\n\tIsEmptyFunction\n\n\t// This means the symbol is a normal function that takes a single argument\n\t// and returns that argument.\n\tIsIdentityFunction\n\n\t// If true, calls to this symbol can be unwrapped (i.e. removed except for\n\t// argument side effects) if the result is unused.\n\tCallCanBeUnwrappedIfUnused\n)\n\nfunc (flags SymbolFlags) Has(flag SymbolFlags) bool {\n\treturn (flags & flag) != 0\n}\n\n// Note: the order of values in this struct matters to reduce struct size.\ntype Symbol struct {\n\t// This is used for symbols that represent items in the import clause of an\n\t// ES6 import statement. These should always be referenced by EImportIdentifier\n\t// instead of an EIdentifier. When this is present, the expression should\n\t// be printed as a property access off the namespace instead of as a bare\n\t// identifier.\n\t//\n\t// For correctness, this must be stored on the symbol instead of indirectly\n\t// associated with the Ref for the symbol somehow. In ES6 \"flat bundling\"\n\t// mode, re-exported symbols are collapsed using MergeSymbols() and renamed\n\t// symbols from other files that end up at this symbol must be able to tell\n\t// if it has a namespace alias.\n\tNamespaceAlias *NamespaceAlias\n\n\t// This is the name that came from the parser. Printed names may be renamed\n\t// during minification or to avoid name collisions. Do not use the original\n\t// name during printing.\n\tOriginalName string\n\n\t// Used by the parser for single pass parsing. Symbols that have been merged\n\t// form a linked-list where the last link is the symbol to use. This link is\n\t// an invalid ref if it's the last link. If this isn't invalid, you need to\n\t// FollowSymbols to get the real one.\n\tLink Ref\n\n\t// An estimate of the number of uses of this symbol. This is used to detect\n\t// whether a symbol is used or not. For example, TypeScript imports that are\n\t// unused must be removed because they are probably type-only imports. This\n\t// is an estimate and may not be completely accurate due to oversights in the\n\t// code. But it should always be non-zero when the symbol is used.\n\tUseCountEstimate uint32\n\n\t// This is for generating cross-chunk imports and exports for code splitting.\n\tChunkIndex Index32\n\n\t// This is used for minification. Symbols that are declared in sibling scopes\n\t// can share a name. A good heuristic (from Google Closure Compiler) is to\n\t// assign names to symbols from sibling scopes in declaration order. That way\n\t// local variable names are reused in each global function like this, which\n\t// improves gzip compression:\n\t//\n\t//   function x(a, b) { ... }\n\t//   function y(a, b, c) { ... }\n\t//\n\t// The parser fills this in for symbols inside nested scopes. There are three\n\t// slot namespaces: regular symbols, label symbols, and private symbols.\n\tNestedScopeSlot Index32\n\n\t// Boolean values should all be flags instead to save space\n\tFlags SymbolFlags\n\n\tKind SymbolKind\n\n\t// We automatically generate import items for property accesses off of\n\t// namespace imports. This lets us remove the expensive namespace imports\n\t// while bundling in many cases, replacing them with a cheap import item\n\t// instead:\n\t//\n\t//   import * as ns from 'path'\n\t//   ns.foo()\n\t//\n\t// That can often be replaced by this, which avoids needing the namespace:\n\t//\n\t//   import {foo} from 'path'\n\t//   foo()\n\t//\n\t// However, if the import is actually missing then we don't want to report a\n\t// compile-time error like we do for real import items. This status lets us\n\t// avoid this. We also need to be able to replace such import items with\n\t// undefined, which this status is also used for.\n\tImportItemStatus ImportItemStatus\n}\n\n// You should call \"MergeSymbols\" instead of calling this directly\nfunc (newSymbol *Symbol) MergeContentsWith(oldSymbol *Symbol) {\n\tnewSymbol.UseCountEstimate += oldSymbol.UseCountEstimate\n\tif oldSymbol.Flags.Has(MustNotBeRenamed) && !newSymbol.Flags.Has(MustNotBeRenamed) {\n\t\tnewSymbol.OriginalName = oldSymbol.OriginalName\n\t\tnewSymbol.Flags |= MustNotBeRenamed\n\t}\n\tif oldSymbol.Flags.Has(MustStartWithCapitalLetterForJSX) {\n\t\tnewSymbol.Flags |= MustStartWithCapitalLetterForJSX\n\t}\n}\n\ntype SlotNamespace uint8\n\nconst (\n\tSlotDefault SlotNamespace = iota\n\tSlotLabel\n\tSlotPrivateName\n\tSlotMangledProp\n\tSlotMustNotBeRenamed\n)\n\nfunc (s *Symbol) SlotNamespace() SlotNamespace {\n\tif s.Kind == SymbolUnbound || s.Flags.Has(MustNotBeRenamed) {\n\t\treturn SlotMustNotBeRenamed\n\t}\n\tif s.Kind.IsPrivate() {\n\t\treturn SlotPrivateName\n\t}\n\tif s.Kind == SymbolLabel {\n\t\treturn SlotLabel\n\t}\n\tif s.Kind == SymbolMangledProp {\n\t\treturn SlotMangledProp\n\t}\n\treturn SlotDefault\n}\n\ntype SlotCounts [4]uint32\n\nfunc (a *SlotCounts) UnionMax(b SlotCounts) {\n\tfor i := range *a {\n\t\tai := &(*a)[i]\n\t\tbi := b[i]\n\t\tif *ai < bi {\n\t\t\t*ai = bi\n\t\t}\n\t}\n}\n\ntype NamespaceAlias struct {\n\tAlias        string\n\tNamespaceRef Ref\n}\n\ntype SymbolMap struct {\n\t// This could be represented as a \"map[Ref]Symbol\" but a two-level array was\n\t// more efficient in profiles. This appears to be because it doesn't involve\n\t// a hash. This representation also makes it trivial to quickly merge symbol\n\t// maps from multiple files together. Each file only generates symbols in a\n\t// single inner array, so you can join the maps together by just make a\n\t// single outer array containing all of the inner arrays. See the comment on\n\t// \"Ref\" for more detail.\n\tSymbolsForSource [][]Symbol\n}\n\nfunc NewSymbolMap(sourceCount int) SymbolMap {\n\treturn SymbolMap{make([][]Symbol, sourceCount)}\n}\n\nfunc (sm SymbolMap) Get(ref Ref) *Symbol {\n\treturn &sm.SymbolsForSource[ref.SourceIndex][ref.InnerIndex]\n}\n\n// Returns the canonical ref that represents the ref for the provided symbol.\n// This may not be the provided ref if the symbol has been merged with another\n// symbol.\nfunc FollowSymbols(symbols SymbolMap, ref Ref) Ref {\n\tsymbol := symbols.Get(ref)\n\tif symbol.Link == InvalidRef {\n\t\treturn ref\n\t}\n\n\tlink := FollowSymbols(symbols, symbol.Link)\n\n\t// Only write if needed to avoid concurrent map update hazards\n\tif symbol.Link != link {\n\t\tsymbol.Link = link\n\t}\n\n\treturn link\n}\n\n// Use this before calling \"FollowSymbols\" from separate threads to avoid\n// concurrent map update hazards. In Go, mutating a map is not threadsafe\n// but reading from a map is. Calling \"FollowAllSymbols\" first ensures that\n// all mutation is done up front.\nfunc FollowAllSymbols(symbols SymbolMap) {\n\tfor sourceIndex, inner := range symbols.SymbolsForSource {\n\t\tfor symbolIndex := range inner {\n\t\t\tFollowSymbols(symbols, Ref{uint32(sourceIndex), uint32(symbolIndex)})\n\t\t}\n\t}\n}\n\n// Makes \"old\" point to \"new\" by joining the linked lists for the two symbols\n// together. That way \"FollowSymbols\" on both \"old\" and \"new\" will result in\n// the same ref.\nfunc MergeSymbols(symbols SymbolMap, old Ref, new Ref) Ref {\n\tif old == new {\n\t\treturn new\n\t}\n\n\toldSymbol := symbols.Get(old)\n\tif oldSymbol.Link != InvalidRef {\n\t\toldSymbol.Link = MergeSymbols(symbols, oldSymbol.Link, new)\n\t\treturn oldSymbol.Link\n\t}\n\n\tnewSymbol := symbols.Get(new)\n\tif newSymbol.Link != InvalidRef {\n\t\tnewSymbol.Link = MergeSymbols(symbols, old, newSymbol.Link)\n\t\treturn newSymbol.Link\n\t}\n\n\toldSymbol.Link = new\n\tnewSymbol.MergeContentsWith(oldSymbol)\n\treturn new\n}\n\n// This is a histogram of character frequencies for minification\ntype CharFreq [64]int32\n\nfunc (freq *CharFreq) Scan(text string, delta int32) {\n\tif delta == 0 {\n\t\treturn\n\t}\n\n\t// This matches the order in \"DefaultNameMinifier\"\n\tfor i, n := 0, len(text); i < n; i++ {\n\t\tc := text[i]\n\t\tswitch {\n\t\tcase c >= 'a' && c <= 'z':\n\t\t\t(*freq)[c-'a'] += delta\n\t\tcase c >= 'A' && c <= 'Z':\n\t\t\t(*freq)[c-('A'-26)] += delta\n\t\tcase c >= '0' && c <= '9':\n\t\t\t(*freq)[c+(52-'0')] += delta\n\t\tcase c == '_':\n\t\t\t(*freq)[62] += delta\n\t\tcase c == '$':\n\t\t\t(*freq)[63] += delta\n\t\t}\n\t}\n}\n\nfunc (freq *CharFreq) Include(other *CharFreq) {\n\tfor i := 0; i < 64; i++ {\n\t\t(*freq)[i] += (*other)[i]\n\t}\n}\n\ntype NameMinifier struct {\n\thead string\n\ttail string\n}\n\nvar DefaultNameMinifierJS = NameMinifier{\n\thead: \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$\",\n\ttail: \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$\",\n}\n\nvar DefaultNameMinifierCSS = NameMinifier{\n\thead: \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_\",\n\ttail: \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_\",\n}\n\ntype charAndCount struct {\n\tchar  string\n\tcount int32\n\tindex byte\n}\n\n// This type is just so we can use Go's native sort function\ntype charAndCountArray []charAndCount\n\nfunc (a charAndCountArray) Len() int          { return len(a) }\nfunc (a charAndCountArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }\n\nfunc (a charAndCountArray) Less(i int, j int) bool {\n\tai := a[i]\n\taj := a[j]\n\treturn ai.count > aj.count || (ai.count == aj.count && ai.index < aj.index)\n}\n\nfunc (source NameMinifier) ShuffleByCharFreq(freq CharFreq) NameMinifier {\n\t// Sort the histogram in descending order by count\n\tarray := make(charAndCountArray, 64)\n\tfor i := 0; i < len(source.tail); i++ {\n\t\tarray[i] = charAndCount{\n\t\t\tchar:  source.tail[i : i+1],\n\t\t\tindex: byte(i),\n\t\t\tcount: freq[i],\n\t\t}\n\t}\n\tsort.Sort(array)\n\n\t// Compute the identifier start and identifier continue sequences\n\tminifier := NameMinifier{}\n\tfor _, item := range array {\n\t\tif item.char < \"0\" || item.char > \"9\" {\n\t\t\tminifier.head += item.char\n\t\t}\n\t\tminifier.tail += item.char\n\t}\n\treturn minifier\n}\n\nfunc (minifier NameMinifier) NumberToMinifiedName(i int) string {\n\tn_head := len(minifier.head)\n\tn_tail := len(minifier.tail)\n\n\tj := i % n_head\n\tvar name strings.Builder\n\tname.WriteString(minifier.head[j : j+1])\n\ti = i / n_head\n\n\tfor i > 0 {\n\t\ti--\n\t\tj := i % n_tail\n\t\tname.WriteString(minifier.tail[j : j+1])\n\t\ti = i / n_tail\n\t}\n\n\treturn name.String()\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/bundler/bundler.go",
    "content": "package bundler\n\n// The bundler is the core of the \"build\" and \"transform\" API calls. Each\n// operation has two phases. The first phase scans the module graph, and is\n// represented by the \"ScanBundle\" function. The second phase generates the\n// output files from the module graph, and is implemented by the \"Compile\"\n// function.\n\nimport (\n\t\"bytes\"\n\t\"encoding/base32\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/cache\"\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/config\"\n\t\"github.com/evanw/esbuild/internal/css_parser\"\n\t\"github.com/evanw/esbuild/internal/fs\"\n\t\"github.com/evanw/esbuild/internal/graph\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/js_lexer\"\n\t\"github.com/evanw/esbuild/internal/js_parser\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n\t\"github.com/evanw/esbuild/internal/resolver\"\n\t\"github.com/evanw/esbuild/internal/runtime\"\n\t\"github.com/evanw/esbuild/internal/sourcemap\"\n\t\"github.com/evanw/esbuild/internal/xxhash\"\n)\n\ntype scannerFile struct {\n\t// If \"AbsMetadataFile\" is present, this will be filled out with information\n\t// about this file in JSON format. This is a partial JSON file that will be\n\t// fully assembled later.\n\tjsonMetadataChunk string\n\n\tpluginData interface{}\n\tinputFile  graph.InputFile\n}\n\n// This is data related to source maps. It's computed in parallel with linking\n// and must be ready by the time printing happens. This is beneficial because\n// it is somewhat expensive to produce.\ntype DataForSourceMap struct {\n\t// This data is for the printer. It maps from byte offsets in the file (which\n\t// are stored at every AST node) to UTF-16 column offsets (required by source\n\t// maps).\n\tLineOffsetTables []sourcemap.LineOffsetTable\n\n\t// This contains the quoted contents of the original source file. It's what\n\t// needs to be embedded in the \"sourcesContent\" array in the final source\n\t// map. Quoting is precomputed because it's somewhat expensive.\n\tQuotedContents [][]byte\n}\n\ntype Bundle struct {\n\t// The unique key prefix is a random string that is unique to every bundling\n\t// operation. It is used as a prefix for the unique keys assigned to every\n\t// chunk during linking. These unique keys are used to identify each chunk\n\t// before the final output paths have been computed.\n\tuniqueKeyPrefix string\n\n\tfs          fs.FS\n\tres         *resolver.Resolver\n\tfiles       []scannerFile\n\tentryPoints []graph.EntryPoint\n\toptions     config.Options\n}\n\ntype parseArgs struct {\n\tfs              fs.FS\n\tlog             logger.Log\n\tres             *resolver.Resolver\n\tcaches          *cache.CacheSet\n\tprettyPaths     logger.PrettyPaths\n\timportSource    *logger.Source\n\timportWith      *ast.ImportAssertOrWith\n\tsideEffects     graph.SideEffects\n\tpluginData      interface{}\n\tresults         chan parseResult\n\tinject          chan config.InjectedFile\n\tuniqueKeyPrefix string\n\tkeyPath         logger.Path\n\toptions         config.Options\n\timportPathRange logger.Range\n\tsourceIndex     uint32\n\tskipResolve     bool\n}\n\ntype parseResult struct {\n\tresolveResults     []*resolver.ResolveResult\n\tglobResolveResults map[uint32]globResolveResult\n\tfile               scannerFile\n\ttlaCheck           tlaCheck\n\tok                 bool\n}\n\ntype globResolveResult struct {\n\tresolveResults map[string]resolver.ResolveResult\n\tabsPath        string\n\tprettyPaths    logger.PrettyPaths\n\texportAlias    string\n}\n\ntype tlaCheck struct {\n\tparent            ast.Index32\n\tdepth             uint32\n\timportRecordIndex uint32\n}\n\nfunc parseFile(args parseArgs) {\n\tpathForIdentifierName := args.keyPath.Text\n\n\t// Identifier name generation may use the name of the parent folder if the\n\t// file name starts with \"index\". However, this is problematic when the\n\t// parent folder includes the parent directory of what the developer\n\t// considers to be the root of the source tree. If that happens, strip the\n\t// parent folder to avoid including it in the generated name.\n\tif relative, ok := args.fs.Rel(args.options.AbsOutputBase, pathForIdentifierName); ok {\n\t\tfor {\n\t\t\tnext := strings.TrimPrefix(strings.TrimPrefix(relative, \"../\"), \"..\\\\\")\n\t\t\tif relative == next {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\trelative = next\n\t\t}\n\t\tpathForIdentifierName = relative\n\t}\n\n\tsource := logger.Source{\n\t\tIndex:          args.sourceIndex,\n\t\tKeyPath:        args.keyPath,\n\t\tPrettyPaths:    args.prettyPaths,\n\t\tIdentifierName: js_ast.GenerateNonUniqueNameFromPath(pathForIdentifierName),\n\t}\n\n\tvar loader config.Loader\n\tvar absResolveDir string\n\tvar pluginName string\n\tvar pluginData interface{}\n\n\tif stdin := args.options.Stdin; stdin != nil {\n\t\t// Special-case stdin\n\t\tsource.Contents = stdin.Contents\n\t\tloader = stdin.Loader\n\t\tif loader == config.LoaderNone {\n\t\t\tloader = config.LoaderJS\n\t\t}\n\t\tabsResolveDir = args.options.Stdin.AbsResolveDir\n\t} else {\n\t\tresult, ok := runOnLoadPlugins(\n\t\t\targs.options.Plugins,\n\t\t\targs.fs,\n\t\t\t&args.caches.FSCache,\n\t\t\targs.log,\n\t\t\t&source,\n\t\t\targs.importSource,\n\t\t\targs.importPathRange,\n\t\t\targs.pluginData,\n\t\t\targs.options.WatchMode,\n\t\t\targs.options.LogPathStyle,\n\t\t)\n\t\tif !ok {\n\t\t\tif args.inject != nil {\n\t\t\t\targs.inject <- config.InjectedFile{\n\t\t\t\t\tSource: source,\n\t\t\t\t}\n\t\t\t}\n\t\t\targs.results <- parseResult{}\n\t\t\treturn\n\t\t}\n\t\tloader = result.loader\n\t\tabsResolveDir = result.absResolveDir\n\t\tpluginName = result.pluginName\n\t\tpluginData = result.pluginData\n\t}\n\n\t_, base, ext := logger.PlatformIndependentPathDirBaseExt(source.KeyPath.Text)\n\n\t// The special \"default\" loader determines the loader from the file path\n\tif loader == config.LoaderDefault {\n\t\tloader = config.LoaderFromFileExtension(args.options.ExtensionToLoader, base+ext)\n\t}\n\n\t// Reject unsupported import attributes when the loader isn't \"copy\" (since\n\t// \"copy\" is kind of like \"external\"). But only do this if this file was not\n\t// loaded by a plugin. Plugins are allowed to assign whatever semantics they\n\t// want to import attributes.\n\tif loader != config.LoaderCopy && pluginName == \"\" {\n\t\tfor _, attr := range source.KeyPath.ImportAttributes.DecodeIntoArray() {\n\t\t\tvar errorText string\n\t\t\tvar errorRange js_lexer.KeyOrValue\n\n\t\t\t// We only currently handle \"type: json\" and \"type: bytes\"\n\t\t\tif attr.Key != \"type\" {\n\t\t\t\terrorText = fmt.Sprintf(\"Importing with the %q attribute is not supported\", attr.Key)\n\t\t\t\terrorRange = js_lexer.KeyRange\n\t\t\t} else if attr.Value == \"json\" {\n\t\t\t\tloader = config.LoaderWithTypeJSON\n\t\t\t\tcontinue\n\t\t\t} else if attr.Value == \"bytes\" {\n\t\t\t\tloader = config.LoaderBinary\n\t\t\t\tcontinue\n\t\t\t} else {\n\t\t\t\terrorText = fmt.Sprintf(\"Importing with a type attribute of %q is not supported\", attr.Value)\n\t\t\t\terrorRange = js_lexer.ValueRange\n\t\t\t}\n\n\t\t\t// Everything else is an error\n\t\t\tr := args.importPathRange\n\t\t\tif args.importWith != nil {\n\t\t\t\tr = js_lexer.RangeOfImportAssertOrWith(*args.importSource, *ast.FindAssertOrWithEntry(args.importWith.Entries, attr.Key), errorRange)\n\t\t\t}\n\t\t\ttracker := logger.MakeLineColumnTracker(args.importSource)\n\t\t\targs.log.AddError(&tracker, r, errorText)\n\t\t\tif args.inject != nil {\n\t\t\t\targs.inject <- config.InjectedFile{\n\t\t\t\t\tSource: source,\n\t\t\t\t}\n\t\t\t}\n\t\t\targs.results <- parseResult{}\n\t\t\treturn\n\t\t}\n\t}\n\n\tif loader == config.LoaderEmpty {\n\t\tsource.Contents = \"\"\n\t}\n\n\tresult := parseResult{\n\t\tfile: scannerFile{\n\t\t\tinputFile: graph.InputFile{\n\t\t\t\tSource:      source,\n\t\t\t\tLoader:      loader,\n\t\t\t\tSideEffects: args.sideEffects,\n\t\t\t},\n\t\t\tpluginData: pluginData,\n\t\t},\n\t}\n\n\tdefer func() {\n\t\tr := recover()\n\t\tif r != nil {\n\t\t\targs.log.AddErrorWithNotes(nil, logger.Range{},\n\t\t\t\tfmt.Sprintf(\"panic: %v (while parsing %q)\", r, source.PrettyPaths.Select(args.options.LogPathStyle)),\n\t\t\t\t[]logger.MsgData{{Text: helpers.PrettyPrintedStack()}})\n\t\t\targs.results <- result\n\t\t}\n\t}()\n\n\tswitch loader {\n\tcase config.LoaderJS, config.LoaderEmpty:\n\t\tast, ok := args.caches.JSCache.Parse(args.log, source, js_parser.OptionsFromConfig(&args.options))\n\t\tif len(ast.Parts) <= 1 { // Ignore the implicitly-generated namespace export part\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_EmptyAST\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = ok\n\n\tcase config.LoaderJSX:\n\t\targs.options.JSX.Parse = true\n\t\tast, ok := args.caches.JSCache.Parse(args.log, source, js_parser.OptionsFromConfig(&args.options))\n\t\tif len(ast.Parts) <= 1 { // Ignore the implicitly-generated namespace export part\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_EmptyAST\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = ok\n\n\tcase config.LoaderTS, config.LoaderTSNoAmbiguousLessThan:\n\t\targs.options.TS.Parse = true\n\t\targs.options.TS.NoAmbiguousLessThan = loader == config.LoaderTSNoAmbiguousLessThan\n\t\tast, ok := args.caches.JSCache.Parse(args.log, source, js_parser.OptionsFromConfig(&args.options))\n\t\tif len(ast.Parts) <= 1 { // Ignore the implicitly-generated namespace export part\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_EmptyAST\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = ok\n\n\tcase config.LoaderTSX:\n\t\targs.options.TS.Parse = true\n\t\targs.options.JSX.Parse = true\n\t\tast, ok := args.caches.JSCache.Parse(args.log, source, js_parser.OptionsFromConfig(&args.options))\n\t\tif len(ast.Parts) <= 1 { // Ignore the implicitly-generated namespace export part\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_EmptyAST\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = ok\n\n\tcase config.LoaderCSS, config.LoaderGlobalCSS, config.LoaderLocalCSS:\n\t\tast := args.caches.CSSCache.Parse(args.log, source, css_parser.OptionsFromConfig(loader, &args.options))\n\t\tresult.file.inputFile.Repr = &graph.CSSRepr{AST: ast}\n\t\tresult.ok = true\n\n\tcase config.LoaderJSON, config.LoaderWithTypeJSON:\n\t\texpr, ok := args.caches.JSONCache.Parse(args.log, source, js_parser.JSONOptions{\n\t\t\tUnsupportedJSFeatures: args.options.UnsupportedJSFeatures,\n\t\t})\n\t\tast := js_parser.LazyExportAST(args.log, source, js_parser.OptionsFromConfig(&args.options), expr, nil)\n\t\tif loader == config.LoaderWithTypeJSON {\n\t\t\t// The exports kind defaults to \"none\", in which case the linker picks\n\t\t\t// either ESM or CommonJS depending on the situation. Dynamic imports\n\t\t\t// causes the linker to pick CommonJS which uses \"require()\" and then\n\t\t\t// converts the return value to ESM, which adds extra properties that\n\t\t\t// aren't supposed to be there when \"{ with: { type: 'json' } }\" is\n\t\t\t// present. So if there's an import attribute, we force the type to\n\t\t\t// be ESM to avoid this.\n\t\t\tast.ExportsKind = js_ast.ExportsESM\n\t\t}\n\t\tif pluginName != \"\" {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData_FromPlugin\n\t\t} else {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = ok\n\n\tcase config.LoaderText:\n\t\tsource.Contents = strings.TrimPrefix(source.Contents, \"\\xEF\\xBB\\xBF\") // Strip any UTF-8 BOM from the text\n\t\tencoded := base64.StdEncoding.EncodeToString([]byte(source.Contents))\n\t\texpr := js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(source.Contents)}}\n\t\tast := js_parser.LazyExportAST(args.log, source, js_parser.OptionsFromConfig(&args.options), expr, nil)\n\t\tast.URLForCSS = \"data:text/plain;base64,\" + encoded\n\t\tif pluginName != \"\" {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData_FromPlugin\n\t\t} else {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = true\n\n\tcase config.LoaderBase64:\n\t\tmimeType := guessMimeType(ext, source.Contents)\n\t\tencoded := base64.StdEncoding.EncodeToString([]byte(source.Contents))\n\t\texpr := js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(encoded)}}\n\t\tast := js_parser.LazyExportAST(args.log, source, js_parser.OptionsFromConfig(&args.options), expr, nil)\n\t\tast.URLForCSS = \"data:\" + mimeType + \";base64,\" + encoded\n\t\tif pluginName != \"\" {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData_FromPlugin\n\t\t} else {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = true\n\n\tcase config.LoaderBinary:\n\t\tencoded := base64.StdEncoding.EncodeToString([]byte(source.Contents))\n\t\texpr := js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(encoded)}}\n\t\tvar helper *js_parser.HelperCall\n\t\tif args.options.UnsupportedJSFeatures.Has(compat.FromBase64) {\n\t\t\tif args.options.Platform == config.PlatformNode {\n\t\t\t\thelper = &js_parser.HelperCall{Runtime: \"__toBinaryNode\"}\n\t\t\t} else {\n\t\t\t\thelper = &js_parser.HelperCall{Runtime: \"__toBinary\"}\n\t\t\t}\n\t\t} else {\n\t\t\thelper = &js_parser.HelperCall{Global: []string{\"Uint8Array\", \"fromBase64\"}}\n\t\t}\n\t\tast := js_parser.LazyExportAST(args.log, source, js_parser.OptionsFromConfig(&args.options), expr, helper)\n\t\tast.URLForCSS = \"data:application/octet-stream;base64,\" + encoded\n\t\tif pluginName != \"\" {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData_FromPlugin\n\t\t} else {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = true\n\n\tcase config.LoaderDataURL:\n\t\tmimeType := guessMimeType(ext, source.Contents)\n\t\turl := helpers.EncodeStringAsShortestDataURL(mimeType, source.Contents)\n\t\texpr := js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(url)}}\n\t\tast := js_parser.LazyExportAST(args.log, source, js_parser.OptionsFromConfig(&args.options), expr, nil)\n\t\tast.URLForCSS = url\n\t\tif pluginName != \"\" {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData_FromPlugin\n\t\t} else {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = true\n\n\tcase config.LoaderFile:\n\t\tuniqueKey := fmt.Sprintf(\"%sA%08d\", args.uniqueKeyPrefix, args.sourceIndex)\n\t\tuniqueKeyPath := uniqueKey + source.KeyPath.IgnoredSuffix\n\t\texpr := js_ast.Expr{Data: &js_ast.EString{\n\t\t\tValue:             helpers.StringToUTF16(uniqueKeyPath),\n\t\t\tContainsUniqueKey: true,\n\t\t}}\n\t\tast := js_parser.LazyExportAST(args.log, source, js_parser.OptionsFromConfig(&args.options), expr, nil)\n\t\tast.URLForCSS = uniqueKeyPath\n\t\tif pluginName != \"\" {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData_FromPlugin\n\t\t} else {\n\t\t\tresult.file.inputFile.SideEffects.Kind = graph.NoSideEffects_PureData\n\t\t}\n\t\tresult.file.inputFile.Repr = &graph.JSRepr{AST: ast}\n\t\tresult.ok = true\n\n\t\t// Mark that this file is from the \"file\" loader\n\t\tresult.file.inputFile.UniqueKeyForAdditionalFile = uniqueKey\n\n\tcase config.LoaderCopy:\n\t\tuniqueKey := fmt.Sprintf(\"%sA%08d\", args.uniqueKeyPrefix, args.sourceIndex)\n\t\tuniqueKeyPath := uniqueKey + source.KeyPath.IgnoredSuffix\n\t\tresult.file.inputFile.Repr = &graph.CopyRepr{\n\t\t\tURLForCode: uniqueKeyPath,\n\t\t}\n\t\tresult.ok = true\n\n\t\t// Mark that this file is from the \"copy\" loader\n\t\tresult.file.inputFile.UniqueKeyForAdditionalFile = uniqueKey\n\n\tdefault:\n\t\tvar message string\n\t\tif source.KeyPath.Namespace == \"file\" && ext != \"\" {\n\t\t\tmessage = fmt.Sprintf(\"No loader is configured for %q files: %s\", ext, source.PrettyPaths.Select(args.options.LogPathStyle))\n\t\t} else {\n\t\t\tmessage = fmt.Sprintf(\"Do not know how to load path: %s\", source.PrettyPaths.Select(args.options.LogPathStyle))\n\t\t}\n\t\ttracker := logger.MakeLineColumnTracker(args.importSource)\n\t\targs.log.AddError(&tracker, args.importPathRange, message)\n\t}\n\n\t// Only continue now if parsing was successful\n\tif result.ok {\n\t\t// Run the resolver on the parse thread so it's not run on the main thread.\n\t\t// That way the main thread isn't blocked if the resolver takes a while.\n\t\tif recordsPtr := result.file.inputFile.Repr.ImportRecords(); args.options.Mode == config.ModeBundle && !args.skipResolve && recordsPtr != nil {\n\t\t\t// Clone the import records because they will be mutated later\n\t\t\trecords := append([]ast.ImportRecord{}, *recordsPtr...)\n\t\t\t*recordsPtr = records\n\t\t\tresult.resolveResults = make([]*resolver.ResolveResult, len(records))\n\n\t\t\tif len(records) > 0 {\n\t\t\t\ttype cacheEntry struct {\n\t\t\t\t\tresolveResult *resolver.ResolveResult\n\t\t\t\t\tdebug         resolver.DebugMeta\n\t\t\t\t\tdidLogError   bool\n\t\t\t\t}\n\n\t\t\t\ttype cacheKey struct {\n\t\t\t\t\tkind  ast.ImportKind\n\t\t\t\t\tpath  string\n\t\t\t\t\tattrs logger.ImportAttributes\n\t\t\t\t}\n\t\t\t\tresolverCache := make(map[cacheKey]cacheEntry)\n\t\t\t\ttracker := logger.MakeLineColumnTracker(&source)\n\n\t\t\t\tfor importRecordIndex := range records {\n\t\t\t\t\t// Don't try to resolve imports that are already resolved\n\t\t\t\t\trecord := &records[importRecordIndex]\n\t\t\t\t\tif record.SourceIndex.IsValid() {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// Encode the import attributes\n\t\t\t\t\tvar attrs logger.ImportAttributes\n\t\t\t\t\tif record.AssertOrWith != nil && record.AssertOrWith.Keyword == ast.WithKeyword {\n\t\t\t\t\t\tdata := make(map[string]string, len(record.AssertOrWith.Entries))\n\t\t\t\t\t\tfor _, entry := range record.AssertOrWith.Entries {\n\t\t\t\t\t\t\tdata[helpers.UTF16ToString(entry.Key)] = helpers.UTF16ToString(entry.Value)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tattrs = logger.EncodeImportAttributes(data)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Special-case glob pattern imports\n\t\t\t\t\tif record.GlobPattern != nil {\n\t\t\t\t\t\tprettyPath := helpers.GlobPatternToString(record.GlobPattern.Parts)\n\t\t\t\t\t\tphase := \"\"\n\t\t\t\t\t\tswitch record.Phase {\n\t\t\t\t\t\tcase ast.DeferPhase:\n\t\t\t\t\t\t\tphase = \".defer\"\n\t\t\t\t\t\tcase ast.SourcePhase:\n\t\t\t\t\t\t\tphase = \".source\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\tswitch record.GlobPattern.Kind {\n\t\t\t\t\t\tcase ast.ImportRequire:\n\t\t\t\t\t\t\tprettyPath = fmt.Sprintf(\"require%s(%q)\", phase, prettyPath)\n\t\t\t\t\t\tcase ast.ImportDynamic:\n\t\t\t\t\t\t\tprettyPath = fmt.Sprintf(\"import%s(%q)\", phase, prettyPath)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif results, msg := args.res.ResolveGlob(absResolveDir, record.GlobPattern.Parts, record.GlobPattern.Kind, prettyPath); results != nil {\n\t\t\t\t\t\t\tif msg != nil {\n\t\t\t\t\t\t\t\targs.log.AddID(msg.ID, msg.Kind, &tracker, record.Range, msg.Data.Text)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif result.globResolveResults == nil {\n\t\t\t\t\t\t\t\tresult.globResolveResults = make(map[uint32]globResolveResult)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tallAreExternal := true\n\t\t\t\t\t\t\tfor key, result := range results {\n\t\t\t\t\t\t\t\tif !result.PathPair.IsExternal {\n\t\t\t\t\t\t\t\t\tallAreExternal = false\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresult.PathPair.Primary.ImportAttributes = attrs\n\t\t\t\t\t\t\t\tif result.PathPair.HasSecondary() {\n\t\t\t\t\t\t\t\t\tresult.PathPair.Secondary.ImportAttributes = attrs\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tresults[key] = result\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult.globResolveResults[uint32(importRecordIndex)] = globResolveResult{\n\t\t\t\t\t\t\t\tresolveResults: results,\n\t\t\t\t\t\t\t\tabsPath:        args.fs.Join(absResolveDir, \"(glob)\"),\n\t\t\t\t\t\t\t\tprettyPaths: logger.PrettyPaths{\n\t\t\t\t\t\t\t\t\tAbs: fmt.Sprintf(\"%s in %s\", prettyPath, result.file.inputFile.Source.PrettyPaths.Abs),\n\t\t\t\t\t\t\t\t\tRel: fmt.Sprintf(\"%s in %s\", prettyPath, result.file.inputFile.Source.PrettyPaths.Rel),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\texportAlias: record.GlobPattern.ExportAlias,\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Forbid bundling of imports with explicit phases\n\t\t\t\t\t\t\tif record.Phase != ast.EvaluationPhase {\n\t\t\t\t\t\t\t\treportExplicitPhaseImport(args.log, &tracker, record.Range,\n\t\t\t\t\t\t\t\t\trecord.Phase, allAreExternal, args.options.OutputFormat)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\targs.log.AddError(&tracker, record.Range, fmt.Sprintf(\"Could not resolve %s\", prettyPath))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// Ignore records that the parser has discarded. This is used to remove\n\t\t\t\t\t// type-only imports in TypeScript files.\n\t\t\t\t\tif record.Flags.Has(ast.IsUnused) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// Cache the path in case it's imported multiple times in this file\n\t\t\t\t\tcacheKey := cacheKey{\n\t\t\t\t\t\tkind:  record.Kind,\n\t\t\t\t\t\tpath:  record.Path.Text,\n\t\t\t\t\t\tattrs: attrs,\n\t\t\t\t\t}\n\t\t\t\t\tentry, ok := resolverCache[cacheKey]\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tresult.resolveResults[importRecordIndex] = entry.resolveResult\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Run the resolver and log an error if the path couldn't be resolved\n\t\t\t\t\t\tresolveResult, didLogError, debug := RunOnResolvePlugins(\n\t\t\t\t\t\t\targs.options.Plugins,\n\t\t\t\t\t\t\targs.res,\n\t\t\t\t\t\t\targs.log,\n\t\t\t\t\t\t\targs.fs,\n\t\t\t\t\t\t\t&args.caches.FSCache,\n\t\t\t\t\t\t\t&source,\n\t\t\t\t\t\t\trecord.Range,\n\t\t\t\t\t\t\tsource.KeyPath,\n\t\t\t\t\t\t\trecord.Path.Text,\n\t\t\t\t\t\t\tattrs,\n\t\t\t\t\t\t\trecord.Kind,\n\t\t\t\t\t\t\tabsResolveDir,\n\t\t\t\t\t\t\tpluginData,\n\t\t\t\t\t\t\targs.options.LogPathStyle,\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif resolveResult != nil {\n\t\t\t\t\t\t\tresolveResult.PathPair.Primary.ImportAttributes = attrs\n\t\t\t\t\t\t\tif resolveResult.PathPair.HasSecondary() {\n\t\t\t\t\t\t\t\tresolveResult.PathPair.Secondary.ImportAttributes = attrs\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tentry = cacheEntry{\n\t\t\t\t\t\t\tresolveResult: resolveResult,\n\t\t\t\t\t\t\tdebug:         debug,\n\t\t\t\t\t\t\tdidLogError:   didLogError,\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolverCache[cacheKey] = entry\n\n\t\t\t\t\t\t// All \"require.resolve()\" imports should be external because we don't\n\t\t\t\t\t\t// want to waste effort traversing into them\n\t\t\t\t\t\tif record.Kind == ast.ImportRequireResolve {\n\t\t\t\t\t\t\tif resolveResult != nil && resolveResult.PathPair.IsExternal {\n\t\t\t\t\t\t\t\t// Allow path substitution as long as the result is external\n\t\t\t\t\t\t\t\tresult.resolveResults[importRecordIndex] = resolveResult\n\t\t\t\t\t\t\t} else if !record.Flags.Has(ast.HandlesImportErrors) {\n\t\t\t\t\t\t\t\targs.log.AddID(logger.MsgID_Bundler_RequireResolveNotExternal, logger.Warning, &tracker, record.Range,\n\t\t\t\t\t\t\t\t\tfmt.Sprintf(\"%q should be marked as external for use with \\\"require.resolve\\\"\", record.Path.Text))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check whether we should log an error every time the result is nil,\n\t\t\t\t\t// even if it's from the cache. Do this because the error may not\n\t\t\t\t\t// have been logged for nil entries if the previous instances had\n\t\t\t\t\t// the \"HandlesImportErrors\" flag.\n\t\t\t\t\tif entry.resolveResult == nil {\n\t\t\t\t\t\t// Failed imports inside a try/catch are silently turned into\n\t\t\t\t\t\t// external imports instead of causing errors. This matches a common\n\t\t\t\t\t\t// code pattern for conditionally importing a module with a graceful\n\t\t\t\t\t\t// fallback.\n\t\t\t\t\t\tif !entry.didLogError && !record.Flags.Has(ast.HandlesImportErrors) {\n\t\t\t\t\t\t\t// Report an error\n\t\t\t\t\t\t\ttext, suggestion, notes := ResolveFailureErrorTextSuggestionNotes(\n\t\t\t\t\t\t\t\targs.res, record.Path.Text, record.Kind, pluginName, args.fs, absResolveDir, args.options.Platform,\n\t\t\t\t\t\t\t\tsource.PrettyPaths, entry.debug.ModifiedImportPath, args.options.LogPathStyle)\n\t\t\t\t\t\t\tentry.debug.LogErrorMsg(args.log, &source, record.Range, text, suggestion, notes)\n\n\t\t\t\t\t\t\t// Only report this error once per unique import path in the file\n\t\t\t\t\t\t\tentry.didLogError = true\n\t\t\t\t\t\t\tresolverCache[cacheKey] = entry\n\t\t\t\t\t\t} else if !entry.didLogError && record.Flags.Has(ast.HandlesImportErrors) {\n\t\t\t\t\t\t\t// Report a debug message about why there was no error\n\t\t\t\t\t\t\targs.log.AddIDWithNotes(logger.MsgID_Bundler_IgnoredDynamicImport, logger.Debug, &tracker, record.Range,\n\t\t\t\t\t\t\t\tfmt.Sprintf(\"Importing %q was allowed even though it could not be resolved because dynamic import failures appear to be handled here:\",\n\t\t\t\t\t\t\t\t\trecord.Path.Text), []logger.MsgData{tracker.MsgData(js_lexer.RangeOfIdentifier(source, record.ErrorHandlerLoc),\n\t\t\t\t\t\t\t\t\t\"The handler for dynamic import failures is here:\")})\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// Forbid bundling of imports with explicit phases\n\t\t\t\t\tif record.Phase != ast.EvaluationPhase {\n\t\t\t\t\t\treportExplicitPhaseImport(args.log, &tracker, record.Range,\n\t\t\t\t\t\t\trecord.Phase, entry.resolveResult.PathPair.IsExternal, args.options.OutputFormat)\n\t\t\t\t\t}\n\n\t\t\t\t\tresult.resolveResults[importRecordIndex] = entry.resolveResult\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Attempt to parse the source map if present\n\t\tif loader.CanHaveSourceMap() && args.options.SourceMap != config.SourceMapNone {\n\t\t\tvar sourceMapComment logger.Span\n\t\t\tswitch repr := result.file.inputFile.Repr.(type) {\n\t\t\tcase *graph.JSRepr:\n\t\t\t\tsourceMapComment = repr.AST.SourceMapComment\n\t\t\tcase *graph.CSSRepr:\n\t\t\t\tsourceMapComment = repr.AST.SourceMapComment\n\t\t\t}\n\n\t\t\tif sourceMapComment.Text != \"\" {\n\t\t\t\ttracker := logger.MakeLineColumnTracker(&source)\n\n\t\t\t\tif path, contents := extractSourceMapFromComment(args.log, args.fs, &args.caches.FSCache,\n\t\t\t\t\t&source, &tracker, sourceMapComment, absResolveDir, args.options.LogPathStyle); contents != nil {\n\t\t\t\t\tprettyPaths := resolver.MakePrettyPaths(args.fs, path)\n\t\t\t\t\tlog := logger.NewDeferLog(logger.DeferLogNoVerboseOrDebug, args.log.Overrides)\n\n\t\t\t\t\tsourceMap := js_parser.ParseSourceMap(log, logger.Source{\n\t\t\t\t\t\tKeyPath:     path,\n\t\t\t\t\t\tPrettyPaths: prettyPaths,\n\t\t\t\t\t\tContents:    *contents,\n\t\t\t\t\t})\n\n\t\t\t\t\tif msgs := log.Done(); len(msgs) > 0 {\n\t\t\t\t\t\tvar text string\n\t\t\t\t\t\tif path.Namespace == \"file\" {\n\t\t\t\t\t\t\ttext = fmt.Sprintf(\"The source map %q was referenced by the file %q here:\",\n\t\t\t\t\t\t\t\tprettyPaths.Select(args.options.LogPathStyle),\n\t\t\t\t\t\t\t\targs.prettyPaths.Select(args.options.LogPathStyle))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttext = fmt.Sprintf(\"This source map came from the file %q here:\",\n\t\t\t\t\t\t\t\targs.prettyPaths.Select(args.options.LogPathStyle))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnote := tracker.MsgData(sourceMapComment.Range, text)\n\t\t\t\t\t\tfor _, msg := range msgs {\n\t\t\t\t\t\t\tmsg.Notes = append(msg.Notes, note)\n\t\t\t\t\t\t\targs.log.AddMsg(msg)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// If \"sourcesContent\" entries aren't present, try filling them in\n\t\t\t\t\t// using the file system. This includes both generating the entire\n\t\t\t\t\t// \"sourcesContent\" array if it's absent as well as filling in\n\t\t\t\t\t// individual null entries in the array if the array is present.\n\t\t\t\t\tif sourceMap != nil && !args.options.ExcludeSourcesContent {\n\t\t\t\t\t\t// Make sure \"sourcesContent\" is big enough\n\t\t\t\t\t\tif len(sourceMap.SourcesContent) < len(sourceMap.Sources) {\n\t\t\t\t\t\t\tslice := make([]sourcemap.SourceContent, len(sourceMap.Sources))\n\t\t\t\t\t\t\tcopy(slice, sourceMap.SourcesContent)\n\t\t\t\t\t\t\tsourceMap.SourcesContent = slice\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor i, source := range sourceMap.Sources {\n\t\t\t\t\t\t\t// Convert absolute paths to \"file://\" URLs, which is especially important\n\t\t\t\t\t\t\t// for Windows where file paths don't look like URLs at all (they use \"\\\"\n\t\t\t\t\t\t\t// as a path separator and start with a \"C:\\\" volume label instead of \"/\").\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// The new source map specification (https://tc39.es/ecma426/) says that\n\t\t\t\t\t\t\t// each source is \"a string that is a (potentially relative) URL\". So we\n\t\t\t\t\t\t\t// should technically not be finding absolute paths here in the first place.\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// However, for a long time source maps was poorly-specified. The old source\n\t\t\t\t\t\t\t// map specification (https://sourcemaps.info/spec.html) only says \"sources\"\n\t\t\t\t\t\t\t// is \"a list of original sources used by the mappings entry\" which could\n\t\t\t\t\t\t\t// be anything, really.\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// So it makes sense that software which predates the formal specification\n\t\t\t\t\t\t\t// of source maps might fill in the sources array with absolute file paths\n\t\t\t\t\t\t\t// instead of URLs. Here are some cases where that happened:\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// - https://github.com/mozilla/source-map/issues/355\n\t\t\t\t\t\t\t// - https://github.com/webpack/webpack/issues/8226\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\tif path.Namespace == \"file\" && args.fs.IsAbs(source) {\n\t\t\t\t\t\t\t\tsource = helpers.FileURLFromFilePath(source).String()\n\t\t\t\t\t\t\t\tsourceMap.Sources[i] = source\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Attempt to fill in null entries using the file system\n\t\t\t\t\t\t\tif sourceMap.SourcesContent[i].Value == nil {\n\t\t\t\t\t\t\t\tif sourceURL, err := url.Parse(source); err == nil && helpers.IsFileURL(sourceURL) {\n\t\t\t\t\t\t\t\t\tif contents, err, _ := args.caches.FSCache.ReadFile(args.fs, helpers.FilePathFromFileURL(args.fs, sourceURL)); err == nil {\n\t\t\t\t\t\t\t\t\t\tsourceMap.SourcesContent[i].Value = helpers.StringToUTF16(contents)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tresult.file.inputFile.InputSourceMap = sourceMap\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Note: We must always send on the \"inject\" channel before we send on the\n\t// \"results\" channel to avoid deadlock\n\tif args.inject != nil {\n\t\tvar exports []config.InjectableExport\n\n\t\tif repr, ok := result.file.inputFile.Repr.(*graph.JSRepr); ok {\n\t\t\taliases := make([]string, 0, len(repr.AST.NamedExports))\n\t\t\tfor alias := range repr.AST.NamedExports {\n\t\t\t\taliases = append(aliases, alias)\n\t\t\t}\n\t\t\tsort.Strings(aliases) // Sort for determinism\n\t\t\texports = make([]config.InjectableExport, len(aliases))\n\t\t\tfor i, alias := range aliases {\n\t\t\t\texports[i] = config.InjectableExport{\n\t\t\t\t\tAlias: alias,\n\t\t\t\t\tLoc:   repr.AST.NamedExports[alias].AliasLoc,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Once we send on the \"inject\" channel, the main thread may mutate the\n\t\t// \"options\" object to populate the \"InjectedFiles\" field. So we must\n\t\t// only send on the \"inject\" channel after we're done using the \"options\"\n\t\t// object so we don't introduce a data race.\n\t\tisCopyLoader := loader == config.LoaderCopy\n\t\tif isCopyLoader && args.skipResolve {\n\t\t\t// This is not allowed because the import path would have to be rewritten,\n\t\t\t// but import paths are not rewritten when bundling isn't enabled.\n\t\t\targs.log.AddError(nil, logger.Range{},\n\t\t\t\tfmt.Sprintf(\"Cannot inject %q with the \\\"copy\\\" loader without bundling enabled\",\n\t\t\t\t\tsource.PrettyPaths.Select(args.options.LogPathStyle)))\n\t\t}\n\t\targs.inject <- config.InjectedFile{\n\t\t\tSource:       source,\n\t\t\tExports:      exports,\n\t\t\tIsCopyLoader: isCopyLoader,\n\t\t}\n\t}\n\n\targs.results <- result\n}\n\nfunc reportExplicitPhaseImport(\n\tlog logger.Log,\n\ttracker *logger.LineColumnTracker,\n\tr logger.Range,\n\tphase ast.ImportPhase,\n\tisExternal bool,\n\tformat config.Format,\n) {\n\tvar phaseText string\n\tswitch phase {\n\tcase ast.DeferPhase:\n\t\tphaseText = \"deferred\"\n\tcase ast.SourcePhase:\n\t\tphaseText = \"source phase\"\n\tdefault:\n\t\treturn\n\t}\n\tif format != config.FormatESModule {\n\t\tlog.AddError(tracker, r, fmt.Sprintf(\"Bundling %s imports with the %q output format is not supported\", phaseText, format.String()))\n\t} else if !isExternal {\n\t\tlog.AddError(tracker, r, fmt.Sprintf(\"Bundling with %s imports is not supported unless they are external\", phaseText))\n\t}\n}\n\nfunc ResolveFailureErrorTextSuggestionNotes(\n\tres *resolver.Resolver,\n\tpath string,\n\tkind ast.ImportKind,\n\tpluginName string,\n\tfs fs.FS,\n\tabsResolveDir string,\n\tplatform config.Platform,\n\toriginatingFilePaths logger.PrettyPaths,\n\tmodifiedImportPath string,\n\tlogPathStyle logger.PathStyle,\n) (text string, suggestion string, notes []logger.MsgData) {\n\tif modifiedImportPath != \"\" {\n\t\ttext = fmt.Sprintf(\"Could not resolve %q (originally %q)\", modifiedImportPath, path)\n\t\tnotes = append(notes, logger.MsgData{Text: fmt.Sprintf(\n\t\t\t\"The path %q was remapped to %q using the alias feature, which then couldn't be resolved. \"+\n\t\t\t\t\"Keep in mind that import path aliases are resolved in the current working directory.\",\n\t\t\tpath, modifiedImportPath)})\n\t\tpath = modifiedImportPath\n\t} else {\n\t\ttext = fmt.Sprintf(\"Could not resolve %q\", path)\n\t}\n\thint := \"\"\n\n\tif resolver.IsPackagePath(path) && !fs.IsAbs(path) {\n\t\thint = fmt.Sprintf(\"You can mark the path %q as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.\", path)\n\t\tif kind == ast.ImportRequire {\n\t\t\thint += \" You can also surround this \\\"require\\\" call with a try/catch block to handle this failure at run-time instead of bundle-time.\"\n\t\t} else if kind == ast.ImportDynamic {\n\t\t\thint += \" You can also add \\\".catch()\\\" here to handle this failure at run-time instead of bundle-time.\"\n\t\t}\n\t\tif pluginName == \"\" && !fs.IsAbs(path) {\n\t\t\tif query, _ := res.ProbeResolvePackageAsRelative(absResolveDir, path, kind); query != nil {\n\t\t\t\tprettyPaths := resolver.MakePrettyPaths(fs, query.PathPair.Primary)\n\t\t\t\thint = fmt.Sprintf(\"Use the relative path %q to reference the file %q. \"+\n\t\t\t\t\t\"Without the leading \\\"./\\\", the path %q is being interpreted as a package path instead.\",\n\t\t\t\t\t\"./\"+path, prettyPaths.Select(logPathStyle), path)\n\t\t\t\tsuggestion = string(helpers.QuoteForJSON(\"./\"+path, false))\n\t\t\t}\n\t\t}\n\t}\n\n\tif platform != config.PlatformNode {\n\t\tpkg := strings.TrimPrefix(path, \"node:\")\n\t\tif resolver.BuiltInNodeModules[pkg] {\n\t\t\tvar how string\n\t\t\tswitch logger.API {\n\t\t\tcase logger.CLIAPI:\n\t\t\t\thow = \"--platform=node\"\n\t\t\tcase logger.JSAPI:\n\t\t\t\thow = \"platform: 'node'\"\n\t\t\tcase logger.GoAPI:\n\t\t\t\thow = \"Platform: api.PlatformNode\"\n\t\t\t}\n\t\t\thint = fmt.Sprintf(\"The package %q wasn't found on the file system but is built into node. \"+\n\t\t\t\t\"Are you trying to bundle for node? You can use %q to do that, which will remove this error.\", path, how)\n\t\t}\n\t}\n\n\tif absResolveDir == \"\" && pluginName != \"\" {\n\t\twhere := \"\"\n\t\tif originatingFilePaths != (logger.PrettyPaths{}) {\n\t\t\twhere = fmt.Sprintf(\" for the file %q\", originatingFilePaths.Select(logPathStyle))\n\t\t}\n\t\thint = fmt.Sprintf(\"The plugin %q didn't set a resolve directory%s, \"+\n\t\t\t\"so esbuild did not search for %q on the file system.\", pluginName, where, path)\n\t}\n\n\tif hint != \"\" {\n\t\tif modifiedImportPath != \"\" {\n\t\t\t// Add a newline if there's already a paragraph of text\n\t\t\tnotes = append(notes, logger.MsgData{})\n\n\t\t\t// Don't add a suggestion if the path was rewritten using an alias\n\t\t\tsuggestion = \"\"\n\t\t}\n\t\tnotes = append(notes, logger.MsgData{Text: hint})\n\t}\n\treturn\n}\n\nfunc isASCIIOnly(text string) bool {\n\tfor _, c := range text {\n\t\tif c < 0x20 || c > 0x7E {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc guessMimeType(extension string, contents string) string {\n\tmimeType := helpers.MimeTypeByExtension(extension)\n\tif mimeType == \"\" {\n\t\tmimeType = http.DetectContentType([]byte(contents))\n\t}\n\n\t// Turn \"text/plain; charset=utf-8\" into \"text/plain;charset=utf-8\"\n\treturn strings.ReplaceAll(mimeType, \"; \", \";\")\n}\n\nfunc extractSourceMapFromComment(\n\tlog logger.Log,\n\tfs fs.FS,\n\tfsCache *cache.FSCache,\n\tsource *logger.Source,\n\ttracker *logger.LineColumnTracker,\n\tcomment logger.Span,\n\tabsResolveDir string,\n\tlogPathStyle logger.PathStyle,\n) (logger.Path, *string) {\n\t// Support data URLs\n\tif parsed, ok := resolver.ParseDataURL(comment.Text); ok {\n\t\tcontents, err := parsed.DecodeData()\n\t\tif err != nil {\n\t\t\tlog.AddID(logger.MsgID_SourceMap_UnsupportedSourceMapComment, logger.Warning, tracker, comment.Range,\n\t\t\t\tfmt.Sprintf(\"Unsupported source map comment: %s\", err.Error()))\n\t\t\treturn logger.Path{}, nil\n\t\t}\n\t\tpath := source.KeyPath\n\t\tpath.IgnoredSuffix = \"#sourceMappingURL\"\n\t\treturn path, &contents\n\t}\n\n\t// Support file URLs of two forms:\n\t//\n\t//   Relative: \"./foo.js.map\"\n\t//   Absolute: \"file:///Users/User/Desktop/foo.js.map\"\n\t//\n\tvar absPath string\n\tif commentURL, err := url.Parse(comment.Text); err != nil {\n\t\t// Show a warning if the comment can't be parsed as a URL\n\t\tlog.AddID(logger.MsgID_SourceMap_UnsupportedSourceMapComment, logger.Warning, tracker, comment.Range,\n\t\t\tfmt.Sprintf(\"Unsupported source map comment: %s\", err.Error()))\n\t\treturn logger.Path{}, nil\n\t} else if commentURL.Scheme != \"\" && commentURL.Scheme != \"file\" {\n\t\t// URLs with schemes other than \"file\" are unsupported (e.g. \"https\"),\n\t\t// but don't warn the user about this because it's not a bug they can fix\n\t\tlog.AddID(logger.MsgID_SourceMap_UnsupportedSourceMapComment, logger.Debug, tracker, comment.Range,\n\t\t\tfmt.Sprintf(\"Unsupported source map comment: Unsupported URL scheme %q\", commentURL.Scheme))\n\t\treturn logger.Path{}, nil\n\t} else if commentURL.Host != \"\" && commentURL.Host != \"localhost\" {\n\t\t// File URLs with hosts are unsupported (e.g. \"file://foo.js.map\")\n\t\tlog.AddID(logger.MsgID_SourceMap_UnsupportedSourceMapComment, logger.Warning, tracker, comment.Range,\n\t\t\tfmt.Sprintf(\"Unsupported source map comment: Unsupported host %q in file URL\", commentURL.Host))\n\t\treturn logger.Path{}, nil\n\t} else if helpers.IsFileURL(commentURL) {\n\t\t// Handle absolute file URLs\n\t\tabsPath = helpers.FilePathFromFileURL(fs, commentURL)\n\t} else if absResolveDir == \"\" {\n\t\t// Fail if plugins don't set a resolve directory\n\t\tlog.AddID(logger.MsgID_SourceMap_UnsupportedSourceMapComment, logger.Debug, tracker, comment.Range,\n\t\t\t\"Unsupported source map comment: Cannot resolve relative URL without a resolve directory\")\n\t\treturn logger.Path{}, nil\n\t} else {\n\t\t// Join the (potentially relative) URL path from the comment text\n\t\t// to the resolve directory path to form the final absolute path\n\t\tabsResolveURL := helpers.FileURLFromFilePath(absResolveDir)\n\t\tif !strings.HasSuffix(absResolveURL.Path, \"/\") {\n\t\t\tabsResolveURL.Path += \"/\"\n\t\t}\n\t\tabsPath = helpers.FilePathFromFileURL(fs, absResolveURL.ResolveReference(commentURL))\n\t}\n\n\t// Try to read the file contents\n\tpath := logger.Path{Text: absPath, Namespace: \"file\"}\n\tif contents, err, _ := fsCache.ReadFile(fs, absPath); err == syscall.ENOENT {\n\t\tlog.AddID(logger.MsgID_SourceMap_MissingSourceMap, logger.Debug, tracker, comment.Range,\n\t\t\tfmt.Sprintf(\"Cannot read file: %s\", absPath))\n\t\treturn logger.Path{}, nil\n\t} else if err != nil {\n\t\tprettyPaths := resolver.MakePrettyPaths(fs, path)\n\t\tlog.AddID(logger.MsgID_SourceMap_MissingSourceMap, logger.Warning, tracker, comment.Range,\n\t\t\tfmt.Sprintf(\"Cannot read file %q: %s\", prettyPaths.Select(logPathStyle), err.Error()))\n\t\treturn logger.Path{}, nil\n\t} else {\n\t\treturn path, &contents\n\t}\n}\n\nfunc sanitizeLocation(fs fs.FS, loc *logger.MsgLocation) {\n\tif loc != nil {\n\t\tif loc.Namespace == \"\" {\n\t\t\tloc.Namespace = \"file\"\n\t\t}\n\t\tif loc.File != (logger.PrettyPaths{}) {\n\t\t\tloc.File = resolver.MakePrettyPaths(fs, logger.Path{Text: loc.File.Abs, Namespace: loc.Namespace})\n\t\t}\n\t}\n}\n\nfunc logPluginMessages(\n\tfs fs.FS,\n\tlog logger.Log,\n\tname string,\n\tmsgs []logger.Msg,\n\tthrown error,\n\timportSource *logger.Source,\n\timportPathRange logger.Range,\n) bool {\n\tdidLogError := false\n\ttracker := logger.MakeLineColumnTracker(importSource)\n\n\t// Report errors and warnings generated by the plugin\n\tfor _, msg := range msgs {\n\t\tif msg.PluginName == \"\" {\n\t\t\tmsg.PluginName = name\n\t\t}\n\t\tif msg.Kind == logger.Error {\n\t\t\tdidLogError = true\n\t\t}\n\n\t\t// Sanitize the locations\n\t\tfor _, note := range msg.Notes {\n\t\t\tsanitizeLocation(fs, note.Location)\n\t\t}\n\t\tif msg.Data.Location == nil {\n\t\t\tmsg.Data.Location = tracker.MsgLocationOrNil(importPathRange)\n\t\t} else {\n\t\t\tsanitizeLocation(fs, msg.Data.Location)\n\t\t\tif importSource != nil {\n\t\t\t\tif msg.Data.Location.File == (logger.PrettyPaths{}) {\n\t\t\t\t\tmsg.Data.Location.File = importSource.PrettyPaths\n\t\t\t\t}\n\t\t\t\tmsg.Notes = append(msg.Notes, tracker.MsgData(importPathRange,\n\t\t\t\t\tfmt.Sprintf(\"The plugin %q was triggered by this import\", name)))\n\t\t\t}\n\t\t}\n\n\t\tlog.AddMsg(msg)\n\t}\n\n\t// Report errors thrown by the plugin itself\n\tif thrown != nil {\n\t\tdidLogError = true\n\t\ttext := thrown.Error()\n\t\tlog.AddMsg(logger.Msg{\n\t\t\tPluginName: name,\n\t\t\tKind:       logger.Error,\n\t\t\tData: logger.MsgData{\n\t\t\t\tText:       text,\n\t\t\t\tLocation:   tracker.MsgLocationOrNil(importPathRange),\n\t\t\t\tUserDetail: thrown,\n\t\t\t},\n\t\t})\n\t}\n\n\treturn didLogError\n}\n\nfunc RunOnResolvePlugins(\n\tplugins []config.Plugin,\n\tres *resolver.Resolver,\n\tlog logger.Log,\n\tfs fs.FS,\n\tfsCache *cache.FSCache,\n\timportSource *logger.Source,\n\timportPathRange logger.Range,\n\timporter logger.Path,\n\tpath string,\n\timportAttributes logger.ImportAttributes,\n\tkind ast.ImportKind,\n\tabsResolveDir string,\n\tpluginData interface{},\n\tlogPathStyle logger.PathStyle,\n) (*resolver.ResolveResult, bool, resolver.DebugMeta) {\n\tresolverArgs := config.OnResolveArgs{\n\t\tPath:       path,\n\t\tResolveDir: absResolveDir,\n\t\tKind:       kind,\n\t\tPluginData: pluginData,\n\t\tImporter:   importer,\n\t\tWith:       importAttributes,\n\t}\n\tapplyPath := logger.Path{\n\t\tText:      path,\n\t\tNamespace: importer.Namespace,\n\t}\n\ttracker := logger.MakeLineColumnTracker(importSource)\n\n\t// Apply resolver plugins in order until one succeeds\n\tfor _, plugin := range plugins {\n\t\tfor _, onResolve := range plugin.OnResolve {\n\t\t\tif !config.PluginAppliesToPath(applyPath, onResolve.Filter, onResolve.Namespace) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tresult := onResolve.Callback(resolverArgs)\n\t\t\tpluginName := result.PluginName\n\t\t\tif pluginName == \"\" {\n\t\t\t\tpluginName = plugin.Name\n\t\t\t}\n\t\t\tdidLogError := logPluginMessages(fs, log, pluginName, result.Msgs, result.ThrownError, importSource, importPathRange)\n\n\t\t\t// Plugins can also provide additional file system paths to watch\n\t\t\tfor _, file := range result.AbsWatchFiles {\n\t\t\t\tfsCache.ReadFile(fs, file)\n\t\t\t}\n\t\t\tfor _, dir := range result.AbsWatchDirs {\n\t\t\t\tif entries, err, _ := fs.ReadDirectory(dir); err == nil {\n\t\t\t\t\tentries.SortedKeys()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Stop now if there was an error\n\t\t\tif didLogError {\n\t\t\t\treturn nil, true, resolver.DebugMeta{}\n\t\t\t}\n\n\t\t\t// The \"file\" namespace is the default for non-external paths, but not\n\t\t\t// for external paths. External paths must explicitly specify the \"file\"\n\t\t\t// namespace.\n\t\t\tnsFromPlugin := result.Path.Namespace\n\t\t\tif result.Path.Namespace == \"\" && !result.External {\n\t\t\t\tresult.Path.Namespace = \"file\"\n\t\t\t}\n\n\t\t\t// Otherwise, continue on to the next resolver if this loader didn't succeed\n\t\t\tif result.Path.Text == \"\" {\n\t\t\t\tif result.External {\n\t\t\t\t\tresult.Path = logger.Path{Text: path}\n\t\t\t\t} else {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Paths in the file namespace must be absolute paths\n\t\t\tif result.Path.Namespace == \"file\" && !fs.IsAbs(result.Path.Text) {\n\t\t\t\tif nsFromPlugin == \"file\" {\n\t\t\t\t\tlog.AddError(&tracker, importPathRange,\n\t\t\t\t\t\tfmt.Sprintf(\"Plugin %q returned a path in the \\\"file\\\" namespace that is not an absolute path: %s\", pluginName, result.Path.Text))\n\t\t\t\t} else {\n\t\t\t\t\tlog.AddError(&tracker, importPathRange,\n\t\t\t\t\t\tfmt.Sprintf(\"Plugin %q returned a non-absolute path: %s (set a namespace if this is not a file path)\", pluginName, result.Path.Text))\n\t\t\t\t}\n\t\t\t\treturn nil, true, resolver.DebugMeta{}\n\t\t\t}\n\n\t\t\tvar sideEffectsData *resolver.SideEffectsData\n\t\t\tif result.IsSideEffectFree {\n\t\t\t\tsideEffectsData = &resolver.SideEffectsData{\n\t\t\t\t\tPluginName: pluginName,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn &resolver.ResolveResult{\n\t\t\t\tPathPair:               resolver.PathPair{Primary: result.Path, IsExternal: result.External},\n\t\t\t\tPluginData:             result.PluginData,\n\t\t\t\tPrimarySideEffectsData: sideEffectsData,\n\t\t\t}, false, resolver.DebugMeta{}\n\t\t}\n\t}\n\n\t// Resolve relative to the resolve directory by default. All paths in the\n\t// \"file\" namespace automatically have a resolve directory. Loader plugins\n\t// can also configure a custom resolve directory for files in other namespaces.\n\tresult, debug := res.Resolve(absResolveDir, path, kind)\n\n\t// Warn when the case used for importing differs from the actual file name\n\tif result != nil && result.DifferentCase != nil && !helpers.IsInsideNodeModules(absResolveDir) {\n\t\tdiffCase := *result.DifferentCase\n\t\tactualPaths := resolver.MakePrettyPaths(fs, logger.Path{Text: fs.Join(diffCase.Dir, diffCase.Actual), Namespace: \"file\"})\n\t\tqueryPaths := resolver.MakePrettyPaths(fs, logger.Path{Text: fs.Join(diffCase.Dir, diffCase.Query), Namespace: \"file\"})\n\t\tlog.AddID(logger.MsgID_Bundler_DifferentPathCase, logger.Warning, &tracker, importPathRange, fmt.Sprintf(\n\t\t\t\"Use %q instead of %q to avoid issues with case-sensitive file systems\",\n\t\t\tactualPaths.Select(logPathStyle),\n\t\t\tqueryPaths.Select(logPathStyle),\n\t\t))\n\t}\n\n\treturn result, false, debug\n}\n\ntype loaderPluginResult struct {\n\tpluginData    interface{}\n\tabsResolveDir string\n\tpluginName    string\n\tloader        config.Loader\n}\n\nfunc runOnLoadPlugins(\n\tplugins []config.Plugin,\n\tfs fs.FS,\n\tfsCache *cache.FSCache,\n\tlog logger.Log,\n\tsource *logger.Source,\n\timportSource *logger.Source,\n\timportPathRange logger.Range,\n\tpluginData interface{},\n\tisWatchMode bool,\n\tlogPathStyle logger.PathStyle,\n) (loaderPluginResult, bool) {\n\tloaderArgs := config.OnLoadArgs{\n\t\tPath:       source.KeyPath,\n\t\tPluginData: pluginData,\n\t}\n\ttracker := logger.MakeLineColumnTracker(importSource)\n\n\t// Apply loader plugins in order until one succeeds\n\tfor _, plugin := range plugins {\n\t\tfor _, onLoad := range plugin.OnLoad {\n\t\t\tif !config.PluginAppliesToPath(source.KeyPath, onLoad.Filter, onLoad.Namespace) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tresult := onLoad.Callback(loaderArgs)\n\t\t\tpluginName := result.PluginName\n\t\t\tif pluginName == \"\" {\n\t\t\t\tpluginName = plugin.Name\n\t\t\t}\n\t\t\tdidLogError := logPluginMessages(fs, log, pluginName, result.Msgs, result.ThrownError, importSource, importPathRange)\n\n\t\t\t// Plugins can also provide additional file system paths to watch\n\t\t\tfor _, file := range result.AbsWatchFiles {\n\t\t\t\tfsCache.ReadFile(fs, file)\n\t\t\t}\n\t\t\tfor _, dir := range result.AbsWatchDirs {\n\t\t\t\tif entries, err, _ := fs.ReadDirectory(dir); err == nil {\n\t\t\t\t\tentries.SortedKeys()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Stop now if there was an error\n\t\t\tif didLogError {\n\t\t\t\tif isWatchMode && source.KeyPath.Namespace == \"file\" {\n\t\t\t\t\tfsCache.ReadFile(fs, source.KeyPath.Text) // Read the file for watch mode tracking\n\t\t\t\t}\n\t\t\t\treturn loaderPluginResult{}, false\n\t\t\t}\n\n\t\t\t// Otherwise, continue on to the next loader if this loader didn't succeed\n\t\t\tif result.Contents == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsource.Contents = *result.Contents\n\t\t\tloader := result.Loader\n\t\t\tif loader == config.LoaderNone {\n\t\t\t\tloader = config.LoaderJS\n\t\t\t}\n\t\t\tif result.AbsResolveDir == \"\" && source.KeyPath.Namespace == \"file\" {\n\t\t\t\tresult.AbsResolveDir = fs.Dir(source.KeyPath.Text)\n\t\t\t}\n\t\t\tif isWatchMode && source.KeyPath.Namespace == \"file\" {\n\t\t\t\tfsCache.ReadFile(fs, source.KeyPath.Text) // Read the file for watch mode tracking\n\t\t\t}\n\t\t\treturn loaderPluginResult{\n\t\t\t\tloader:        loader,\n\t\t\t\tabsResolveDir: result.AbsResolveDir,\n\t\t\t\tpluginName:    pluginName,\n\t\t\t\tpluginData:    result.PluginData,\n\t\t\t}, true\n\t\t}\n\t}\n\n\t// Force disabled modules to be empty\n\tif source.KeyPath.IsDisabled() {\n\t\treturn loaderPluginResult{loader: config.LoaderEmpty}, true\n\t}\n\n\t// Read normal modules from disk\n\tif source.KeyPath.Namespace == \"file\" {\n\t\tif contents, err, _ := fsCache.ReadFile(fs, source.KeyPath.Text); err == nil {\n\t\t\tsource.Contents = contents\n\t\t\treturn loaderPluginResult{\n\t\t\t\tloader:        config.LoaderDefault,\n\t\t\t\tabsResolveDir: fs.Dir(source.KeyPath.Text),\n\t\t\t}, true\n\t\t} else {\n\t\t\tif err == syscall.ENOENT {\n\t\t\t\tlog.AddError(&tracker, importPathRange,\n\t\t\t\t\tfmt.Sprintf(\"Cannot read file: %s\", source.KeyPath.Text))\n\t\t\t\treturn loaderPluginResult{}, false\n\t\t\t} else {\n\t\t\t\tprettyPaths := resolver.MakePrettyPaths(fs, source.KeyPath)\n\t\t\t\tlog.AddError(&tracker, importPathRange,\n\t\t\t\t\tfmt.Sprintf(\"Cannot read file %q: %s\", prettyPaths.Select(logPathStyle), err.Error()))\n\t\t\t\treturn loaderPluginResult{}, false\n\t\t\t}\n\t\t}\n\t}\n\n\t// Native support for data URLs. This is supported natively by node:\n\t// https://nodejs.org/docs/latest/api/esm.html#esm_data_imports\n\tif source.KeyPath.Namespace == \"dataurl\" {\n\t\tif parsed, ok := resolver.ParseDataURL(source.KeyPath.Text); ok {\n\t\t\tif contents, err := parsed.DecodeData(); err != nil {\n\t\t\t\tlog.AddError(&tracker, importPathRange,\n\t\t\t\t\tfmt.Sprintf(\"Could not load data URL: %s\", err.Error()))\n\t\t\t\treturn loaderPluginResult{loader: config.LoaderNone}, true\n\t\t\t} else {\n\t\t\t\tsource.Contents = contents\n\t\t\t\tif mimeType := parsed.DecodeMIMEType(); mimeType != resolver.MIMETypeUnsupported {\n\t\t\t\t\tswitch mimeType {\n\t\t\t\t\tcase resolver.MIMETypeTextCSS:\n\t\t\t\t\t\treturn loaderPluginResult{loader: config.LoaderCSS}, true\n\t\t\t\t\tcase resolver.MIMETypeTextJavaScript:\n\t\t\t\t\t\treturn loaderPluginResult{loader: config.LoaderJS}, true\n\t\t\t\t\tcase resolver.MIMETypeApplicationJSON:\n\t\t\t\t\t\treturn loaderPluginResult{loader: config.LoaderJSON}, true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Otherwise, fail to load the path\n\treturn loaderPluginResult{loader: config.LoaderNone}, true\n}\n\n// Identify the path by its lowercase absolute path name with Windows-specific\n// slashes substituted for standard slashes. This should hopefully avoid path\n// issues on Windows where multiple different paths can refer to the same\n// underlying file.\nfunc canonicalFileSystemPathForWindows(absPath string) string {\n\treturn strings.ReplaceAll(strings.ToLower(absPath), \"\\\\\", \"/\")\n}\n\nfunc HashForFileName(hashBytes []byte) string {\n\treturn base32.StdEncoding.EncodeToString(hashBytes)[:8]\n}\n\ntype scanner struct {\n\tlog             logger.Log\n\tfs              fs.FS\n\tres             *resolver.Resolver\n\tcaches          *cache.CacheSet\n\ttimer           *helpers.Timer\n\tuniqueKeyPrefix string\n\n\t// These are not guarded by a mutex because it's only ever modified by a single\n\t// thread. Note that not all results in the \"results\" array are necessarily\n\t// valid. Make sure to check the \"ok\" flag before using them.\n\tresults       []parseResult\n\tvisited       map[logger.Path]visitedFile\n\tresultChannel chan parseResult\n\n\toptions config.Options\n\n\t// Also not guarded by a mutex for the same reason\n\tremaining int\n}\n\ntype visitedFile struct {\n\tsourceIndex uint32\n}\n\ntype EntryPoint struct {\n\tInputPath                string\n\tOutputPath               string\n\tInputPathInFileNamespace bool\n}\n\nfunc generateUniqueKeyPrefix() (string, error) {\n\tvar data [12]byte\n\trand.Seed(time.Now().UnixNano())\n\tif _, err := rand.Read(data[:]); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// This is 16 bytes and shouldn't generate escape characters when put into strings\n\treturn base64.URLEncoding.EncodeToString(data[:]), nil\n}\n\n// This creates a bundle by scanning over the whole module graph starting from\n// the entry points until all modules are reached. Each module has some number\n// of import paths which are resolved to module identifiers (i.e. \"onResolve\"\n// in the plugin API). Each unique module identifier is loaded once (i.e.\n// \"onLoad\" in the plugin API).\nfunc ScanBundle(\n\tcall config.APICall,\n\tlog logger.Log,\n\tfs fs.FS,\n\tcaches *cache.CacheSet,\n\tentryPoints []EntryPoint,\n\toptions config.Options,\n\ttimer *helpers.Timer,\n) Bundle {\n\ttimer.Begin(\"Scan phase\")\n\tdefer timer.End(\"Scan phase\")\n\n\tapplyOptionDefaults(&options)\n\n\t// Run \"onStart\" plugins in parallel. IMPORTANT: We always need to run all\n\t// \"onStart\" callbacks even when the build is cancelled, because plugins may\n\t// rely on invariants that are started in \"onStart\" and ended in \"onEnd\".\n\t// This works because \"onEnd\" callbacks are always run as well.\n\ttimer.Begin(\"On-start callbacks\")\n\tonStartWaitGroup := sync.WaitGroup{}\n\tfor _, plugin := range options.Plugins {\n\t\tfor _, onStart := range plugin.OnStart {\n\t\t\tonStartWaitGroup.Add(1)\n\t\t\tgo func(plugin config.Plugin, onStart config.OnStart) {\n\t\t\t\tresult := onStart.Callback()\n\t\t\t\tlogPluginMessages(fs, log, plugin.Name, result.Msgs, result.ThrownError, nil, logger.Range{})\n\t\t\t\tonStartWaitGroup.Done()\n\t\t\t}(plugin, onStart)\n\t\t}\n\t}\n\n\t// Each bundling operation gets a separate unique key\n\tuniqueKeyPrefix, err := generateUniqueKeyPrefix()\n\tif err != nil {\n\t\tlog.AddError(nil, logger.Range{}, fmt.Sprintf(\"Failed to read from randomness source: %s\", err.Error()))\n\t}\n\n\t// This may mutate \"options\" by the \"tsconfig.json\" override settings\n\tres := resolver.NewResolver(call, fs, log, caches, &options)\n\n\ts := scanner{\n\t\tlog:             log,\n\t\tfs:              fs,\n\t\tres:             res,\n\t\tcaches:          caches,\n\t\toptions:         options,\n\t\ttimer:           timer,\n\t\tresults:         make([]parseResult, 0, caches.SourceIndexCache.LenHint()),\n\t\tvisited:         make(map[logger.Path]visitedFile),\n\t\tresultChannel:   make(chan parseResult),\n\t\tuniqueKeyPrefix: uniqueKeyPrefix,\n\t}\n\n\t// Always start by parsing the runtime file\n\ts.results = append(s.results, parseResult{})\n\ts.remaining++\n\tgo func() {\n\t\tsource, ast, ok := globalRuntimeCache.parseRuntime(&options)\n\t\ts.resultChannel <- parseResult{\n\t\t\tfile: scannerFile{\n\t\t\t\tinputFile: graph.InputFile{\n\t\t\t\t\tSource: source,\n\t\t\t\t\tRepr: &graph.JSRepr{\n\t\t\t\t\t\tAST: ast,\n\t\t\t\t\t},\n\t\t\t\t\tOmitFromSourceMapsAndMetafile: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\tok: ok,\n\t\t}\n\t}()\n\n\t// Always consume all unused results. Failing to do so could cause a memory\n\t// leak if a build is cancelled. We can't cancel the producers by closing the\n\t// channel because doing so in Go causes a panic (which is arguably a design\n\t// bug with Go).\n\tdefer func() {\n\t\tfor s.remaining > 0 {\n\t\t\t<-s.resultChannel\n\t\t\ts.remaining--\n\t\t}\n\t}()\n\n\t// Wait for all \"onStart\" plugins here before continuing. People sometimes run\n\t// setup code in \"onStart\" that \"onLoad\" expects to be able to use without\n\t// \"onLoad\" needing to block on the completion of their \"onStart\" callback.\n\t//\n\t// We want to enable this:\n\t//\n\t//   let plugin = {\n\t//     name: 'example',\n\t//     setup(build) {\n\t//       let started = false\n\t//       build.onStart(() => started = true)\n\t//       build.onLoad({ filter: /.*/ }, () => {\n\t//         assert(started === true)\n\t//       })\n\t//     },\n\t//   }\n\t//\n\t// without people having to write something like this:\n\t//\n\t//   let plugin = {\n\t//     name: 'example',\n\t//     setup(build) {\n\t//       let started = {}\n\t//       started.promise = new Promise(resolve => {\n\t//         started.resolve = resolve\n\t//       })\n\t//       build.onStart(() => {\n\t//         started.resolve(true)\n\t//       })\n\t//       build.onLoad({ filter: /.*/ }, async () => {\n\t//         assert(await started.promise === true)\n\t//       })\n\t//     },\n\t//   }\n\t//\n\tonStartWaitGroup.Wait()\n\ttimer.End(\"On-start callbacks\")\n\n\t// We can check the cancel flag now that all \"onStart\" callbacks are done\n\tif options.CancelFlag.DidCancel() {\n\t\treturn Bundle{options: options}\n\t}\n\n\ts.preprocessInjectedFiles()\n\n\tif options.CancelFlag.DidCancel() {\n\t\treturn Bundle{options: options}\n\t}\n\n\tentryPointMeta := s.addEntryPoints(entryPoints)\n\n\tif options.CancelFlag.DidCancel() {\n\t\treturn Bundle{options: options}\n\t}\n\n\ts.scanAllDependencies()\n\n\tif options.CancelFlag.DidCancel() {\n\t\treturn Bundle{options: options}\n\t}\n\n\tfiles := s.processScannedFiles(entryPointMeta)\n\n\tif options.CancelFlag.DidCancel() {\n\t\treturn Bundle{options: options}\n\t}\n\n\treturn Bundle{\n\t\tfs:              fs,\n\t\tres:             s.res,\n\t\tfiles:           files,\n\t\tentryPoints:     entryPointMeta,\n\t\tuniqueKeyPrefix: uniqueKeyPrefix,\n\t\toptions:         s.options,\n\t}\n}\n\ntype inputKind uint8\n\nconst (\n\tinputKindNormal inputKind = iota\n\tinputKindEntryPoint\n\tinputKindStdin\n)\n\n// This returns the source index of the resulting file\nfunc (s *scanner) maybeParseFile(\n\tresolveResult resolver.ResolveResult,\n\tprettyPaths logger.PrettyPaths,\n\timportSource *logger.Source,\n\timportPathRange logger.Range,\n\timportWith *ast.ImportAssertOrWith,\n\tkind inputKind,\n\tinject chan config.InjectedFile,\n) uint32 {\n\tpath := resolveResult.PathPair.Primary\n\tvisitedKey := path\n\tif visitedKey.Namespace == \"file\" {\n\t\tvisitedKey.Text = canonicalFileSystemPathForWindows(visitedKey.Text)\n\t}\n\n\t// Only parse a given file path once\n\tvisited, ok := s.visited[visitedKey]\n\tif ok {\n\t\tif inject != nil {\n\t\t\tinject <- config.InjectedFile{}\n\t\t}\n\t\treturn visited.sourceIndex\n\t}\n\n\tvisited = visitedFile{\n\t\tsourceIndex: s.allocateSourceIndex(visitedKey, cache.SourceIndexNormal),\n\t}\n\ts.visited[visitedKey] = visited\n\ts.remaining++\n\toptionsClone := s.options\n\tif kind != inputKindStdin {\n\t\toptionsClone.Stdin = nil\n\t}\n\n\t// Allow certain properties to be overridden by \"tsconfig.json\"\n\tresolveResult.TSConfigJSX.ApplyTo(&optionsClone.JSX)\n\tif resolveResult.TSConfig != nil {\n\t\toptionsClone.TS.Config = *resolveResult.TSConfig\n\t}\n\tif resolveResult.TSAlwaysStrict != nil {\n\t\toptionsClone.TSAlwaysStrict = resolveResult.TSAlwaysStrict\n\t}\n\n\t// Set the module type preference using node's module type rules\n\tif strings.HasSuffix(path.Text, \".mjs\") {\n\t\toptionsClone.ModuleTypeData.Type = js_ast.ModuleESM_MJS\n\t} else if strings.HasSuffix(path.Text, \".mts\") {\n\t\toptionsClone.ModuleTypeData.Type = js_ast.ModuleESM_MTS\n\t} else if strings.HasSuffix(path.Text, \".cjs\") {\n\t\toptionsClone.ModuleTypeData.Type = js_ast.ModuleCommonJS_CJS\n\t} else if strings.HasSuffix(path.Text, \".cts\") {\n\t\toptionsClone.ModuleTypeData.Type = js_ast.ModuleCommonJS_CTS\n\t} else if strings.HasSuffix(path.Text, \".js\") || strings.HasSuffix(path.Text, \".jsx\") ||\n\t\tstrings.HasSuffix(path.Text, \".ts\") || strings.HasSuffix(path.Text, \".tsx\") {\n\t\toptionsClone.ModuleTypeData = resolveResult.ModuleTypeData\n\t} else {\n\t\t// The \"type\" setting in \"package.json\" only applies to \".js\" files\n\t\toptionsClone.ModuleTypeData.Type = js_ast.ModuleUnknown\n\t}\n\n\t// Enable bundling for injected files so we always do tree shaking. We\n\t// never want to include unnecessary code from injected files since they\n\t// are essentially bundled. However, if we do this we should skip the\n\t// resolving step when we're not bundling. It'd be strange to get\n\t// resolution errors when the top-level bundling controls are disabled.\n\tskipResolve := false\n\tif inject != nil && optionsClone.Mode != config.ModeBundle {\n\t\toptionsClone.Mode = config.ModeBundle\n\t\tskipResolve = true\n\t}\n\n\t// Special-case pretty-printed paths for data URLs\n\tif path.Namespace == \"dataurl\" {\n\t\tif _, ok := resolver.ParseDataURL(path.Text); ok {\n\t\t\tprettyPath := path.Text\n\t\t\tif len(prettyPath) > 65 {\n\t\t\t\tprettyPath = prettyPath[:65]\n\t\t\t}\n\t\t\tprettyPath = strings.ReplaceAll(prettyPath, \"\\n\", \"\\\\n\")\n\t\t\tif len(prettyPath) > 64 {\n\t\t\t\tprettyPath = prettyPath[:64] + \"...\"\n\t\t\t}\n\t\t\tprettyPath = fmt.Sprintf(\"<%s>\", prettyPath)\n\t\t\tprettyPaths.Abs = prettyPath\n\t\t\tprettyPaths.Rel = prettyPath\n\t\t}\n\t}\n\n\tvar sideEffects graph.SideEffects\n\tif resolveResult.PrimarySideEffectsData != nil {\n\t\tsideEffects.Kind = graph.NoSideEffects_PackageJSON\n\t\tsideEffects.Data = resolveResult.PrimarySideEffectsData\n\t}\n\n\tgo parseFile(parseArgs{\n\t\tfs:              s.fs,\n\t\tlog:             s.log,\n\t\tres:             s.res,\n\t\tcaches:          s.caches,\n\t\tkeyPath:         path,\n\t\tprettyPaths:     prettyPaths,\n\t\tsourceIndex:     visited.sourceIndex,\n\t\timportSource:    importSource,\n\t\tsideEffects:     sideEffects,\n\t\timportPathRange: importPathRange,\n\t\timportWith:      importWith,\n\t\tpluginData:      resolveResult.PluginData,\n\t\toptions:         optionsClone,\n\t\tresults:         s.resultChannel,\n\t\tinject:          inject,\n\t\tskipResolve:     skipResolve,\n\t\tuniqueKeyPrefix: s.uniqueKeyPrefix,\n\t})\n\n\treturn visited.sourceIndex\n}\n\nfunc (s *scanner) allocateSourceIndex(path logger.Path, kind cache.SourceIndexKind) uint32 {\n\t// Allocate a source index using the shared source index cache so that\n\t// subsequent builds reuse the same source index and therefore use the\n\t// cached parse results for increased speed.\n\tsourceIndex := s.caches.SourceIndexCache.Get(path, kind)\n\n\t// Grow the results array to fit this source index\n\tif newLen := int(sourceIndex) + 1; len(s.results) < newLen {\n\t\t// Reallocate to a bigger array\n\t\tif cap(s.results) < newLen {\n\t\t\ts.results = append(make([]parseResult, 0, 2*newLen), s.results...)\n\t\t}\n\n\t\t// Grow in place\n\t\ts.results = s.results[:newLen]\n\t}\n\n\treturn sourceIndex\n}\n\nfunc (s *scanner) allocateGlobSourceIndex(parentSourceIndex uint32, globIndex uint32) uint32 {\n\t// Allocate a source index using the shared source index cache so that\n\t// subsequent builds reuse the same source index and therefore use the\n\t// cached parse results for increased speed.\n\tsourceIndex := s.caches.SourceIndexCache.GetGlob(parentSourceIndex, globIndex)\n\n\t// Grow the results array to fit this source index\n\tif newLen := int(sourceIndex) + 1; len(s.results) < newLen {\n\t\t// Reallocate to a bigger array\n\t\tif cap(s.results) < newLen {\n\t\t\ts.results = append(make([]parseResult, 0, 2*newLen), s.results...)\n\t\t}\n\n\t\t// Grow in place\n\t\ts.results = s.results[:newLen]\n\t}\n\n\treturn sourceIndex\n}\n\nfunc (s *scanner) preprocessInjectedFiles() {\n\ts.timer.Begin(\"Preprocess injected files\")\n\tdefer s.timer.End(\"Preprocess injected files\")\n\n\tinjectedFiles := make([]config.InjectedFile, 0, len(s.options.InjectedDefines)+len(s.options.InjectPaths))\n\n\t// These are virtual paths that are generated for compound \"--define\" values.\n\t// They are special-cased and are not available for plugins to intercept.\n\tfor _, define := range s.options.InjectedDefines {\n\t\t// These should be unique by construction so no need to check for collisions\n\t\tvisitedKey := logger.Path{Text: fmt.Sprintf(\"<define:%s>\", define.Name)}\n\t\tsourceIndex := s.allocateSourceIndex(visitedKey, cache.SourceIndexNormal)\n\t\ts.visited[visitedKey] = visitedFile{sourceIndex: sourceIndex}\n\t\tsource := logger.Source{\n\t\t\tIndex:          sourceIndex,\n\t\t\tKeyPath:        visitedKey,\n\t\t\tPrettyPaths:    resolver.MakePrettyPaths(s.fs, visitedKey),\n\t\t\tIdentifierName: js_ast.EnsureValidIdentifier(visitedKey.Text),\n\t\t\tContents:       define.Source.Contents,\n\t\t}\n\n\t\t// The first \"len(InjectedDefine)\" injected files intentionally line up\n\t\t// with the injected defines by index. The index will be used to import\n\t\t// references to them in the parser.\n\t\tinjectedFiles = append(injectedFiles, config.InjectedFile{\n\t\t\tSource:     source,\n\t\t\tDefineName: define.Name,\n\t\t})\n\n\t\t// Generate the file inline here since it has already been parsed\n\t\texpr := js_ast.Expr{Data: define.Data}\n\t\tast := js_parser.LazyExportAST(s.log, source, js_parser.OptionsFromConfig(&s.options), expr, nil)\n\t\tresult := parseResult{\n\t\t\tok: true,\n\t\t\tfile: scannerFile{\n\t\t\t\tinputFile: graph.InputFile{\n\t\t\t\t\tSource: source,\n\t\t\t\t\tRepr:   &graph.JSRepr{AST: ast},\n\t\t\t\t\tLoader: config.LoaderJSON,\n\t\t\t\t\tSideEffects: graph.SideEffects{\n\t\t\t\t\t\tKind: graph.NoSideEffects_PureData,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\n\t\t// Append to the channel on a goroutine in case it blocks due to capacity\n\t\ts.remaining++\n\t\tgo func() { s.resultChannel <- result }()\n\t}\n\n\t// Add user-specified injected files. Run resolver plugins on these files\n\t// so plugins can alter where they resolve to. These are run in parallel in\n\t// case any of these plugins block.\n\tinjectResolveResults := make([]*resolver.ResolveResult, len(s.options.InjectPaths))\n\tinjectAbsResolveDir := s.fs.Cwd()\n\tinjectResolveWaitGroup := sync.WaitGroup{}\n\tinjectResolveWaitGroup.Add(len(s.options.InjectPaths))\n\tfor i, importPath := range s.options.InjectPaths {\n\t\tgo func(i int, importPath string) {\n\t\t\tvar importer logger.Path\n\n\t\t\t// Add a leading \"./\" if it's missing, similar to entry points\n\t\t\tabsPath := importPath\n\t\t\tif !s.fs.IsAbs(absPath) {\n\t\t\t\tabsPath = s.fs.Join(injectAbsResolveDir, absPath)\n\t\t\t}\n\t\t\tdir := s.fs.Dir(absPath)\n\t\t\tbase := s.fs.Base(absPath)\n\t\t\tif entries, err, originalError := s.fs.ReadDirectory(dir); err == nil {\n\t\t\t\tif entry, _ := entries.Get(base); entry != nil && entry.Kind(s.fs) == fs.FileEntry {\n\t\t\t\t\timporter.Namespace = \"file\"\n\t\t\t\t\tif !s.fs.IsAbs(importPath) && resolver.IsPackagePath(importPath) {\n\t\t\t\t\t\timportPath = \"./\" + importPath\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if s.log.Level <= logger.LevelDebug && originalError != nil {\n\t\t\t\ts.log.AddID(logger.MsgID_None, logger.Debug, nil, logger.Range{}, fmt.Sprintf(\"Failed to read directory %q: %s\", absPath, originalError.Error()))\n\t\t\t}\n\n\t\t\t// Run the resolver and log an error if the path couldn't be resolved\n\t\t\tresolveResult, didLogError, debug := RunOnResolvePlugins(\n\t\t\t\ts.options.Plugins,\n\t\t\t\ts.res,\n\t\t\t\ts.log,\n\t\t\t\ts.fs,\n\t\t\t\t&s.caches.FSCache,\n\t\t\t\tnil,\n\t\t\t\tlogger.Range{},\n\t\t\t\timporter,\n\t\t\t\timportPath,\n\t\t\t\tlogger.ImportAttributes{},\n\t\t\t\tast.ImportEntryPoint,\n\t\t\t\tinjectAbsResolveDir,\n\t\t\t\tnil,\n\t\t\t\ts.options.LogPathStyle,\n\t\t\t)\n\t\t\tif resolveResult != nil {\n\t\t\t\tif resolveResult.PathPair.IsExternal {\n\t\t\t\t\ts.log.AddError(nil, logger.Range{}, fmt.Sprintf(\"The injected path %q cannot be marked as external\", importPath))\n\t\t\t\t} else {\n\t\t\t\t\tinjectResolveResults[i] = resolveResult\n\t\t\t\t}\n\t\t\t} else if !didLogError {\n\t\t\t\tdebug.LogErrorMsg(s.log, nil, logger.Range{}, fmt.Sprintf(\"Could not resolve %q\", importPath), \"\", nil)\n\t\t\t}\n\t\t\tinjectResolveWaitGroup.Done()\n\t\t}(i, importPath)\n\t}\n\tinjectResolveWaitGroup.Wait()\n\n\tif s.options.CancelFlag.DidCancel() {\n\t\treturn\n\t}\n\n\t// Parse all entry points that were resolved successfully\n\tresults := make([]config.InjectedFile, len(s.options.InjectPaths))\n\tj := 0\n\tvar injectWaitGroup sync.WaitGroup\n\tfor _, resolveResult := range injectResolveResults {\n\t\tif resolveResult != nil {\n\t\t\tchannel := make(chan config.InjectedFile, 1)\n\t\t\ts.maybeParseFile(*resolveResult, resolver.MakePrettyPaths(s.fs, resolveResult.PathPair.Primary), nil, logger.Range{}, nil, inputKindNormal, channel)\n\t\t\tinjectWaitGroup.Add(1)\n\n\t\t\t// Wait for the results in parallel. The results slice is large enough so\n\t\t\t// it is not reallocated during the computations.\n\t\t\tgo func(i int) {\n\t\t\t\tresults[i] = <-channel\n\t\t\t\tinjectWaitGroup.Done()\n\t\t\t}(j)\n\t\t\tj++\n\t\t}\n\t}\n\tinjectWaitGroup.Wait()\n\tinjectedFiles = append(injectedFiles, results[:j]...)\n\n\t// It's safe to mutate the options object to add the injected files here\n\t// because there aren't any concurrent \"parseFile\" goroutines at this point.\n\t// The only ones that were created by this point are the ones we created\n\t// above, and we've already waited for all of them to finish using the\n\t// \"options\" object.\n\ts.options.InjectedFiles = injectedFiles\n}\n\nfunc (s *scanner) addEntryPoints(entryPoints []EntryPoint) []graph.EntryPoint {\n\ts.timer.Begin(\"Add entry points\")\n\tdefer s.timer.End(\"Add entry points\")\n\n\t// Reserve a slot for each entry point\n\tentryMetas := make([]graph.EntryPoint, 0, len(entryPoints)+1)\n\n\t// Treat stdin as an extra entry point\n\tif stdin := s.options.Stdin; stdin != nil {\n\t\tstdinPath := logger.Path{Text: \"<stdin>\"}\n\t\tif stdin.SourceFile != \"\" {\n\t\t\tif stdin.AbsResolveDir == \"\" {\n\t\t\t\tstdinPath = logger.Path{Text: stdin.SourceFile}\n\t\t\t} else if s.fs.IsAbs(stdin.SourceFile) {\n\t\t\t\tstdinPath = logger.Path{Text: stdin.SourceFile, Namespace: \"file\"}\n\t\t\t} else {\n\t\t\t\tstdinPath = logger.Path{Text: s.fs.Join(stdin.AbsResolveDir, stdin.SourceFile), Namespace: \"file\"}\n\t\t\t}\n\t\t}\n\t\tresolveResult := resolver.ResolveResult{PathPair: resolver.PathPair{Primary: stdinPath}}\n\t\tsourceIndex := s.maybeParseFile(resolveResult, resolver.MakePrettyPaths(s.fs, stdinPath), nil, logger.Range{}, nil, inputKindStdin, nil)\n\t\tentryMetas = append(entryMetas, graph.EntryPoint{\n\t\t\tOutputPath:  \"stdin\",\n\t\t\tSourceIndex: sourceIndex,\n\t\t})\n\t}\n\n\tif s.options.CancelFlag.DidCancel() {\n\t\treturn nil\n\t}\n\n\t// Check each entry point ahead of time to see if it's a real file\n\tentryPointAbsResolveDir := s.fs.Cwd()\n\tfor i := range entryPoints {\n\t\tentryPoint := &entryPoints[i]\n\t\tabsPath := entryPoint.InputPath\n\t\tif strings.ContainsRune(absPath, '*') {\n\t\t\tcontinue // Ignore glob patterns\n\t\t}\n\t\tif !s.fs.IsAbs(absPath) {\n\t\t\tabsPath = s.fs.Join(entryPointAbsResolveDir, absPath)\n\t\t}\n\t\tdir := s.fs.Dir(absPath)\n\t\tbase := s.fs.Base(absPath)\n\t\tif entries, err, originalError := s.fs.ReadDirectory(dir); err == nil {\n\t\t\tif entry, _ := entries.Get(base); entry != nil && entry.Kind(s.fs) == fs.FileEntry {\n\t\t\t\tentryPoint.InputPathInFileNamespace = true\n\n\t\t\t\t// Entry point paths without a leading \"./\" are interpreted as package\n\t\t\t\t// paths. This happens because they go through general path resolution\n\t\t\t\t// like all other import paths so that plugins can run on them. Requiring\n\t\t\t\t// a leading \"./\" for a relative path simplifies writing plugins because\n\t\t\t\t// entry points aren't a special case.\n\t\t\t\t//\n\t\t\t\t// However, requiring a leading \"./\" also breaks backward compatibility\n\t\t\t\t// and makes working with the CLI more difficult. So attempt to insert\n\t\t\t\t// \"./\" automatically when needed. We don't want to unconditionally insert\n\t\t\t\t// a leading \"./\" because the path may not be a file system path. For\n\t\t\t\t// example, it may be a URL. So only insert a leading \"./\" when the path\n\t\t\t\t// is an exact match for an existing file.\n\t\t\t\tif !s.fs.IsAbs(entryPoint.InputPath) && resolver.IsPackagePath(entryPoint.InputPath) {\n\t\t\t\t\tentryPoint.InputPath = \"./\" + entryPoint.InputPath\n\t\t\t\t}\n\t\t\t}\n\t\t} else if s.log.Level <= logger.LevelDebug && originalError != nil {\n\t\t\ts.log.AddID(logger.MsgID_None, logger.Debug, nil, logger.Range{}, fmt.Sprintf(\"Failed to read directory %q: %s\", absPath, originalError.Error()))\n\t\t}\n\t}\n\n\tif s.options.CancelFlag.DidCancel() {\n\t\treturn nil\n\t}\n\n\t// Add any remaining entry points. Run resolver plugins on these entry points\n\t// so plugins can alter where they resolve to. These are run in parallel in\n\t// case any of these plugins block.\n\ttype entryPointInfo struct {\n\t\tresults []resolver.ResolveResult\n\t\tisGlob  bool\n\t}\n\tentryPointInfos := make([]entryPointInfo, len(entryPoints))\n\tentryPointWaitGroup := sync.WaitGroup{}\n\tentryPointWaitGroup.Add(len(entryPoints))\n\tfor i, entryPoint := range entryPoints {\n\t\tgo func(i int, entryPoint EntryPoint) {\n\t\t\tvar importer logger.Path\n\t\t\tif entryPoint.InputPathInFileNamespace {\n\t\t\t\timporter.Namespace = \"file\"\n\t\t\t}\n\n\t\t\t// Special-case glob patterns here\n\t\t\tif strings.ContainsRune(entryPoint.InputPath, '*') {\n\t\t\t\tif pattern := helpers.ParseGlobPattern(entryPoint.InputPath); len(pattern) > 1 {\n\t\t\t\t\tprettyPattern := fmt.Sprintf(\"%q\", entryPoint.InputPath)\n\t\t\t\t\tif results, msg := s.res.ResolveGlob(entryPointAbsResolveDir, pattern, ast.ImportEntryPoint, prettyPattern); results != nil {\n\t\t\t\t\t\tkeys := make([]string, 0, len(results))\n\t\t\t\t\t\tfor key := range results {\n\t\t\t\t\t\t\tkeys = append(keys, key)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsort.Strings(keys)\n\t\t\t\t\t\tinfo := entryPointInfo{isGlob: true}\n\t\t\t\t\t\tfor _, key := range keys {\n\t\t\t\t\t\t\tinfo.results = append(info.results, results[key])\n\t\t\t\t\t\t}\n\t\t\t\t\t\tentryPointInfos[i] = info\n\t\t\t\t\t\tif msg != nil {\n\t\t\t\t\t\t\ts.log.AddID(msg.ID, msg.Kind, nil, logger.Range{}, msg.Data.Text)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\ts.log.AddError(nil, logger.Range{}, fmt.Sprintf(\"Could not resolve %q\", entryPoint.InputPath))\n\t\t\t\t\t}\n\t\t\t\t\tentryPointWaitGroup.Done()\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Run the resolver and log an error if the path couldn't be resolved\n\t\t\tresolveResult, didLogError, debug := RunOnResolvePlugins(\n\t\t\t\ts.options.Plugins,\n\t\t\t\ts.res,\n\t\t\t\ts.log,\n\t\t\t\ts.fs,\n\t\t\t\t&s.caches.FSCache,\n\t\t\t\tnil,\n\t\t\t\tlogger.Range{},\n\t\t\t\timporter,\n\t\t\t\tentryPoint.InputPath,\n\t\t\t\tlogger.ImportAttributes{},\n\t\t\t\tast.ImportEntryPoint,\n\t\t\t\tentryPointAbsResolveDir,\n\t\t\t\tnil,\n\t\t\t\ts.options.LogPathStyle,\n\t\t\t)\n\t\t\tif resolveResult != nil {\n\t\t\t\tif resolveResult.PathPair.IsExternal {\n\t\t\t\t\ts.log.AddError(nil, logger.Range{}, fmt.Sprintf(\"The entry point %q cannot be marked as external\", entryPoint.InputPath))\n\t\t\t\t} else {\n\t\t\t\t\tentryPointInfos[i] = entryPointInfo{results: []resolver.ResolveResult{*resolveResult}}\n\t\t\t\t}\n\t\t\t} else if !didLogError {\n\t\t\t\tvar notes []logger.MsgData\n\t\t\t\tif !s.fs.IsAbs(entryPoint.InputPath) {\n\t\t\t\t\tif query, _ := s.res.ProbeResolvePackageAsRelative(entryPointAbsResolveDir, entryPoint.InputPath, ast.ImportEntryPoint); query != nil {\n\t\t\t\t\t\tprettyPaths := resolver.MakePrettyPaths(s.fs, query.PathPair.Primary)\n\t\t\t\t\t\tnotes = append(notes, logger.MsgData{\n\t\t\t\t\t\t\tText: fmt.Sprintf(\"Use the relative path %q to reference the file %q. \"+\n\t\t\t\t\t\t\t\t\"Without the leading \\\"./\\\", the path %q is being interpreted as a package path instead.\",\n\t\t\t\t\t\t\t\t\"./\"+entryPoint.InputPath, prettyPaths.Select(s.options.LogPathStyle), entryPoint.InputPath),\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdebug.LogErrorMsg(s.log, nil, logger.Range{}, fmt.Sprintf(\"Could not resolve %q\", entryPoint.InputPath), \"\", notes)\n\t\t\t}\n\t\t\tentryPointWaitGroup.Done()\n\t\t}(i, entryPoint)\n\t}\n\tentryPointWaitGroup.Wait()\n\n\tif s.options.CancelFlag.DidCancel() {\n\t\treturn nil\n\t}\n\n\t// Determine output paths for all entry points that were resolved successfully\n\ttype entryPointToParse struct {\n\t\tindex int\n\t\tparse func() uint32\n\t}\n\tvar entryPointsToParse []entryPointToParse\n\tfor i, info := range entryPointInfos {\n\t\tif info.results == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, resolveResult := range info.results {\n\t\t\tresolveResult := resolveResult\n\t\t\tprettyPaths := resolver.MakePrettyPaths(s.fs, resolveResult.PathPair.Primary)\n\t\t\toutputPath := entryPoints[i].OutputPath\n\t\t\toutputPathWasAutoGenerated := false\n\n\t\t\t// If the output path is missing, automatically generate one from the input path\n\t\t\tif outputPath == \"\" {\n\t\t\t\tif info.isGlob {\n\t\t\t\t\toutputPath = prettyPaths.Rel\n\t\t\t\t} else {\n\t\t\t\t\toutputPath = entryPoints[i].InputPath\n\t\t\t\t}\n\t\t\t\twindowsVolumeLabel := \"\"\n\n\t\t\t\t// The \":\" character is invalid in file paths on Windows except when\n\t\t\t\t// it's used as a volume separator. Special-case that here so volume\n\t\t\t\t// labels don't break on Windows.\n\t\t\t\tif s.fs.IsAbs(outputPath) && len(outputPath) >= 3 && outputPath[1] == ':' {\n\t\t\t\t\tif c := outputPath[0]; (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') {\n\t\t\t\t\t\tif c := outputPath[2]; c == '/' || c == '\\\\' {\n\t\t\t\t\t\t\twindowsVolumeLabel = outputPath[:3]\n\t\t\t\t\t\t\toutputPath = outputPath[3:]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// For cross-platform robustness, do not allow characters in the output\n\t\t\t\t// path that are invalid on Windows. This is especially relevant when\n\t\t\t\t// the input path is something other than a file path, such as a URL.\n\t\t\t\toutputPath = sanitizeFilePathForVirtualModulePath(outputPath)\n\t\t\t\tif windowsVolumeLabel != \"\" {\n\t\t\t\t\toutputPath = windowsVolumeLabel + outputPath\n\t\t\t\t}\n\t\t\t\toutputPathWasAutoGenerated = true\n\t\t\t}\n\n\t\t\t// Defer parsing for this entry point until later\n\t\t\tentryPointsToParse = append(entryPointsToParse, entryPointToParse{\n\t\t\t\tindex: len(entryMetas),\n\t\t\t\tparse: func() uint32 {\n\t\t\t\t\treturn s.maybeParseFile(resolveResult, prettyPaths, nil, logger.Range{}, nil, inputKindEntryPoint, nil)\n\t\t\t\t},\n\t\t\t})\n\n\t\t\tentryMetas = append(entryMetas, graph.EntryPoint{\n\t\t\t\tOutputPath:                 outputPath,\n\t\t\t\tSourceIndex:                ast.InvalidRef.SourceIndex,\n\t\t\t\tOutputPathWasAutoGenerated: outputPathWasAutoGenerated,\n\t\t\t})\n\t\t}\n\t}\n\n\t// Turn all automatically-generated output paths into absolute paths\n\tfor i := range entryMetas {\n\t\tentryPoint := &entryMetas[i]\n\t\tif entryPoint.OutputPathWasAutoGenerated && !s.fs.IsAbs(entryPoint.OutputPath) {\n\t\t\tentryPoint.OutputPath = s.fs.Join(entryPointAbsResolveDir, entryPoint.OutputPath)\n\t\t}\n\t}\n\n\t// Automatically compute \"outbase\" if it wasn't provided\n\tif s.options.AbsOutputBase == \"\" {\n\t\ts.options.AbsOutputBase = lowestCommonAncestorDirectory(s.fs, entryMetas)\n\t\tif s.options.AbsOutputBase == \"\" {\n\t\t\ts.options.AbsOutputBase = entryPointAbsResolveDir\n\t\t}\n\t}\n\n\t// Only parse entry points after \"AbsOutputBase\" has been determined\n\tfor _, toParse := range entryPointsToParse {\n\t\tentryMetas[toParse.index].SourceIndex = toParse.parse()\n\t}\n\n\t// Turn all output paths back into relative paths, but this time relative to\n\t// the \"outbase\" value we computed above\n\tfor i := range entryMetas {\n\t\tentryPoint := &entryMetas[i]\n\t\tif s.fs.IsAbs(entryPoint.OutputPath) {\n\t\t\tif !entryPoint.OutputPathWasAutoGenerated {\n\t\t\t\t// If an explicit absolute output path was specified, use the path\n\t\t\t\t// relative to the \"outdir\" directory\n\t\t\t\tif relPath, ok := s.fs.Rel(s.options.AbsOutputDir, entryPoint.OutputPath); ok {\n\t\t\t\t\tentryPoint.OutputPath = relPath\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Otherwise if the absolute output path was derived from the input\n\t\t\t\t// path, use the path relative to the \"outbase\" directory\n\t\t\t\tif relPath, ok := s.fs.Rel(s.options.AbsOutputBase, entryPoint.OutputPath); ok {\n\t\t\t\t\tentryPoint.OutputPath = relPath\n\t\t\t\t}\n\n\t\t\t\t// Strip the file extension from the output path if there is one so the\n\t\t\t\t// \"out extension\" setting is used instead\n\t\t\t\tif last := strings.LastIndexAny(entryPoint.OutputPath, \"/.\\\\\"); last != -1 && entryPoint.OutputPath[last] == '.' {\n\t\t\t\t\tentryPoint.OutputPath = entryPoint.OutputPath[:last]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn entryMetas\n}\n\nfunc lowestCommonAncestorDirectory(fs fs.FS, entryPoints []graph.EntryPoint) string {\n\t// Ignore any explicitly-specified output paths\n\tabsPaths := make([]string, 0, len(entryPoints))\n\tfor _, entryPoint := range entryPoints {\n\t\tif entryPoint.OutputPathWasAutoGenerated {\n\t\t\tabsPaths = append(absPaths, entryPoint.OutputPath)\n\t\t}\n\t}\n\n\tif len(absPaths) == 0 {\n\t\treturn \"\"\n\t}\n\n\tlowestAbsDir := fs.Dir(absPaths[0])\n\n\tfor _, absPath := range absPaths[1:] {\n\t\tabsDir := fs.Dir(absPath)\n\t\tlastSlash := 0\n\t\ta := 0\n\t\tb := 0\n\n\t\tfor {\n\t\t\truneA, widthA := utf8.DecodeRuneInString(absDir[a:])\n\t\t\truneB, widthB := utf8.DecodeRuneInString(lowestAbsDir[b:])\n\t\t\tboundaryA := widthA == 0 || runeA == '/' || runeA == '\\\\'\n\t\t\tboundaryB := widthB == 0 || runeB == '/' || runeB == '\\\\'\n\n\t\t\tif boundaryA && boundaryB {\n\t\t\t\tif widthA == 0 || widthB == 0 {\n\t\t\t\t\t// Truncate to the smaller path if one path is a prefix of the other\n\t\t\t\t\tlowestAbsDir = absDir[:a]\n\t\t\t\t\tbreak\n\t\t\t\t} else {\n\t\t\t\t\t// Track the longest common directory so far\n\t\t\t\t\tlastSlash = a\n\t\t\t\t}\n\t\t\t} else if boundaryA != boundaryB || unicode.ToLower(runeA) != unicode.ToLower(runeB) {\n\t\t\t\t// If we're at the top-level directory, then keep the slash\n\t\t\t\tif lastSlash < len(absDir) && !strings.ContainsAny(absDir[:lastSlash], \"\\\\/\") {\n\t\t\t\t\tlastSlash++\n\t\t\t\t}\n\n\t\t\t\t// If both paths are different at this point, stop and set the lowest so\n\t\t\t\t// far to the common parent directory. Compare using a case-insensitive\n\t\t\t\t// comparison to handle paths on Windows.\n\t\t\t\tlowestAbsDir = absDir[:lastSlash]\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\ta += widthA\n\t\t\tb += widthB\n\t\t}\n\t}\n\n\treturn lowestAbsDir\n}\n\nfunc (s *scanner) scanAllDependencies() {\n\ts.timer.Begin(\"Scan all dependencies\")\n\tdefer s.timer.End(\"Scan all dependencies\")\n\n\t// Continue scanning until all dependencies have been discovered\n\tfor s.remaining > 0 {\n\t\tif s.options.CancelFlag.DidCancel() {\n\t\t\treturn\n\t\t}\n\n\t\tresult := <-s.resultChannel\n\t\ts.remaining--\n\t\tif !result.ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Don't try to resolve paths if we're not bundling\n\t\tif recordsPtr := result.file.inputFile.Repr.ImportRecords(); s.options.Mode == config.ModeBundle && recordsPtr != nil {\n\t\t\trecords := *recordsPtr\n\t\t\tfor importRecordIndex := range records {\n\t\t\t\trecord := &records[importRecordIndex]\n\n\t\t\t\t// This is used for error messages\n\t\t\t\tvar with *ast.ImportAssertOrWith\n\t\t\t\tif record.AssertOrWith != nil && record.AssertOrWith.Keyword == ast.WithKeyword {\n\t\t\t\t\twith = record.AssertOrWith\n\t\t\t\t}\n\n\t\t\t\t// Skip this import record if the previous resolver call failed\n\t\t\t\tresolveResult := result.resolveResults[importRecordIndex]\n\t\t\t\tif resolveResult == nil {\n\t\t\t\t\tif globResults := result.globResolveResults[uint32(importRecordIndex)]; globResults.resolveResults != nil {\n\t\t\t\t\t\tsourceIndex := s.allocateGlobSourceIndex(result.file.inputFile.Source.Index, uint32(importRecordIndex))\n\t\t\t\t\t\trecord.SourceIndex = ast.MakeIndex32(sourceIndex)\n\t\t\t\t\t\ts.results[sourceIndex] = s.generateResultForGlobResolve(sourceIndex, globResults.absPath,\n\t\t\t\t\t\t\t&result.file.inputFile.Source, record.Range, with, record.GlobPattern.Kind, record.Phase, globResults, record.AssertOrWith)\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tpath := resolveResult.PathPair.Primary\n\t\t\t\tif !resolveResult.PathPair.IsExternal {\n\t\t\t\t\t// Handle a path within the bundle\n\t\t\t\t\tsourceIndex := s.maybeParseFile(*resolveResult, resolver.MakePrettyPaths(s.fs, path),\n\t\t\t\t\t\t&result.file.inputFile.Source, record.Range, with, inputKindNormal, nil)\n\t\t\t\t\trecord.SourceIndex = ast.MakeIndex32(sourceIndex)\n\t\t\t\t} else {\n\t\t\t\t\t// Allow this import statement to be removed if something marked it as \"sideEffects: false\"\n\t\t\t\t\tif resolveResult.PrimarySideEffectsData != nil {\n\t\t\t\t\t\trecord.Flags |= ast.IsExternalWithoutSideEffects\n\t\t\t\t\t}\n\n\t\t\t\t\t// If the path to the external module is relative to the source\n\t\t\t\t\t// file, rewrite the path to be relative to the working directory\n\t\t\t\t\tif path.Namespace == \"file\" {\n\t\t\t\t\t\tif relPath, ok := s.fs.Rel(s.options.AbsOutputDir, path.Text); ok {\n\t\t\t\t\t\t\t// Prevent issues with path separators being different on Windows\n\t\t\t\t\t\t\trelPath = strings.ReplaceAll(relPath, \"\\\\\", \"/\")\n\t\t\t\t\t\t\tif resolver.IsPackagePath(relPath) {\n\t\t\t\t\t\t\t\trelPath = \"./\" + relPath\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\trecord.Path.Text = relPath\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trecord.Path = path\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\trecord.Path = path\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ts.results[result.file.inputFile.Source.Index] = result\n\t}\n}\n\nfunc (s *scanner) generateResultForGlobResolve(\n\tsourceIndex uint32,\n\tfakeSourcePath string,\n\timportSource *logger.Source,\n\timportRange logger.Range,\n\timportWith *ast.ImportAssertOrWith,\n\tkind ast.ImportKind,\n\tphase ast.ImportPhase,\n\tresult globResolveResult,\n\tassertions *ast.ImportAssertOrWith,\n) parseResult {\n\tkeys := make([]string, 0, len(result.resolveResults))\n\tfor key := range result.resolveResults {\n\t\tkeys = append(keys, key)\n\t}\n\tsort.Strings(keys)\n\n\tobject := js_ast.EObject{Properties: make([]js_ast.Property, 0, len(result.resolveResults))}\n\timportRecords := make([]ast.ImportRecord, 0, len(result.resolveResults))\n\tresolveResults := make([]*resolver.ResolveResult, 0, len(result.resolveResults))\n\n\tfor _, key := range keys {\n\t\tresolveResult := result.resolveResults[key]\n\t\tvar value js_ast.Expr\n\n\t\timportRecordIndex := uint32(len(importRecords))\n\t\tvar sourceIndex ast.Index32\n\n\t\tif !resolveResult.PathPair.IsExternal {\n\t\t\tsourceIndex = ast.MakeIndex32(s.maybeParseFile(\n\t\t\t\tresolveResult,\n\t\t\t\tresolver.MakePrettyPaths(s.fs, resolveResult.PathPair.Primary),\n\t\t\t\timportSource,\n\t\t\t\timportRange,\n\t\t\t\timportWith,\n\t\t\t\tinputKindNormal,\n\t\t\t\tnil,\n\t\t\t))\n\t\t}\n\n\t\tpath := resolveResult.PathPair.Primary\n\n\t\t// If the path to the external module is relative to the source\n\t\t// file, rewrite the path to be relative to the working directory\n\t\tif path.Namespace == \"file\" {\n\t\t\tif relPath, ok := s.fs.Rel(s.options.AbsOutputDir, path.Text); ok {\n\t\t\t\t// Prevent issues with path separators being different on Windows\n\t\t\t\trelPath = strings.ReplaceAll(relPath, \"\\\\\", \"/\")\n\t\t\t\tif resolver.IsPackagePath(relPath) {\n\t\t\t\t\trelPath = \"./\" + relPath\n\t\t\t\t}\n\t\t\t\tpath.Text = relPath\n\t\t\t}\n\t\t}\n\n\t\tresolveResults = append(resolveResults, &resolveResult)\n\t\timportRecords = append(importRecords, ast.ImportRecord{\n\t\t\tPath:         path,\n\t\t\tSourceIndex:  sourceIndex,\n\t\t\tAssertOrWith: assertions,\n\t\t\tKind:         kind,\n\t\t\tPhase:        phase,\n\t\t})\n\n\t\tswitch kind {\n\t\tcase ast.ImportDynamic:\n\t\t\tvalue.Data = &js_ast.EImportString{ImportRecordIndex: importRecordIndex}\n\t\tcase ast.ImportRequire:\n\t\t\tvalue.Data = &js_ast.ERequireString{ImportRecordIndex: importRecordIndex}\n\t\tdefault:\n\t\t\tpanic(\"Internal error\")\n\t\t}\n\n\t\tobject.Properties = append(object.Properties, js_ast.Property{\n\t\t\tKey: js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(key)}},\n\t\t\tValueOrNil: js_ast.Expr{Data: &js_ast.EArrow{\n\t\t\t\tBody:       js_ast.FnBody{Block: js_ast.SBlock{Stmts: []js_ast.Stmt{{Data: &js_ast.SReturn{ValueOrNil: value}}}}},\n\t\t\t\tPreferExpr: true,\n\t\t\t}},\n\t\t})\n\t}\n\n\tsource := logger.Source{\n\t\tKeyPath:     logger.Path{Text: fakeSourcePath, Namespace: \"file\"},\n\t\tPrettyPaths: result.prettyPaths,\n\t\tIndex:       sourceIndex,\n\t}\n\tast := js_parser.GlobResolveAST(s.log, source, importRecords, &object, result.exportAlias)\n\n\t// Fill out \"nil\" for any additional imports (i.e. from the runtime)\n\tfor len(resolveResults) < len(ast.ImportRecords) {\n\t\tresolveResults = append(resolveResults, nil)\n\t}\n\n\treturn parseResult{\n\t\tresolveResults: resolveResults,\n\t\tfile: scannerFile{\n\t\t\tinputFile: graph.InputFile{\n\t\t\t\tSource: source,\n\t\t\t\tRepr: &graph.JSRepr{\n\t\t\t\t\tAST: ast,\n\t\t\t\t},\n\t\t\t\tOmitFromSourceMapsAndMetafile: true,\n\t\t\t},\n\t\t},\n\t\tok: true,\n\t}\n}\n\nfunc (s *scanner) processScannedFiles(entryPointMeta []graph.EntryPoint) []scannerFile {\n\ts.timer.Begin(\"Process scanned files\")\n\tdefer s.timer.End(\"Process scanned files\")\n\n\t// Build a set of entry point source indices for quick lookup\n\tentryPointSourceIndexToMetaIndex := make(map[uint32]uint32, len(entryPointMeta))\n\tfor i, meta := range entryPointMeta {\n\t\tentryPointSourceIndexToMetaIndex[meta.SourceIndex] = uint32(i)\n\t}\n\n\t// Check for pretty-printed path collisions\n\timportAttributeNameCollisions := make(map[logger.PrettyPaths][]uint32)\n\tfor sourceIndex := range s.results {\n\t\tif result := &s.results[sourceIndex]; result.ok {\n\t\t\tprettyPaths := result.file.inputFile.Source.PrettyPaths\n\t\t\timportAttributeNameCollisions[prettyPaths] = append(importAttributeNameCollisions[prettyPaths], uint32(sourceIndex))\n\t\t}\n\t}\n\n\t// Import attributes can result in the same file being imported multiple\n\t// times in different ways. If that happens, append the import attributes\n\t// to the pretty-printed file names to disambiguate them. This renaming\n\t// must happen before we construct the metafile JSON chunks below.\n\tfor _, sourceIndices := range importAttributeNameCollisions {\n\t\tif len(sourceIndices) == 1 {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, sourceIndex := range sourceIndices {\n\t\t\tsource := &s.results[sourceIndex].file.inputFile.Source\n\t\t\tattrs := source.KeyPath.ImportAttributes.DecodeIntoArray()\n\t\t\tif len(attrs) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tvar sb strings.Builder\n\t\t\tsb.WriteString(\" with {\")\n\t\t\tfor i, attr := range attrs {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tsb.WriteByte(',')\n\t\t\t\t}\n\t\t\t\tsb.WriteByte(' ')\n\t\t\t\tif js_ast.IsIdentifier(attr.Key) {\n\t\t\t\t\tsb.WriteString(attr.Key)\n\t\t\t\t} else {\n\t\t\t\t\tsb.Write(helpers.QuoteSingle(attr.Key, false))\n\t\t\t\t}\n\t\t\t\tsb.WriteString(\": \")\n\t\t\t\tsb.Write(helpers.QuoteSingle(attr.Value, false))\n\t\t\t}\n\t\t\tsb.WriteString(\" }\")\n\t\t\tsuffix := sb.String()\n\t\t\tsource.PrettyPaths.Abs += suffix\n\t\t\tsource.PrettyPaths.Rel += suffix\n\t\t}\n\t}\n\n\t// Now that all files have been scanned, process the final file import records\n\tfor sourceIndex, result := range s.results {\n\t\tif !result.ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tsb := strings.Builder{}\n\t\tisFirstImport := true\n\n\t\t// Begin the metadata chunk\n\t\tif s.options.NeedsMetafile {\n\t\t\tsb.Write(helpers.QuoteForJSON(result.file.inputFile.Source.PrettyPaths.Select(s.options.MetafilePathStyle), s.options.ASCIIOnly))\n\t\t\tsb.WriteString(fmt.Sprintf(\": {\\n      \\\"bytes\\\": %d,\\n      \\\"imports\\\": [\", len(result.file.inputFile.Source.Contents)))\n\t\t}\n\n\t\t// Don't try to resolve paths if we're not bundling\n\t\tif recordsPtr := result.file.inputFile.Repr.ImportRecords(); s.options.Mode == config.ModeBundle && recordsPtr != nil {\n\t\t\trecords := *recordsPtr\n\t\t\ttracker := logger.MakeLineColumnTracker(&result.file.inputFile.Source)\n\n\t\t\tfor importRecordIndex := range records {\n\t\t\t\trecord := &records[importRecordIndex]\n\n\t\t\t\t// Save the import attributes to the metafile\n\t\t\t\tvar metafileWith string\n\t\t\t\tif s.options.NeedsMetafile {\n\t\t\t\t\tif with := record.AssertOrWith; with != nil && with.Keyword == ast.WithKeyword && len(with.Entries) > 0 {\n\t\t\t\t\t\tdata := strings.Builder{}\n\t\t\t\t\t\tdata.WriteString(\",\\n          \\\"with\\\": {\")\n\t\t\t\t\t\tfor i, entry := range with.Entries {\n\t\t\t\t\t\t\tif i > 0 {\n\t\t\t\t\t\t\t\tdata.WriteByte(',')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdata.WriteString(\"\\n            \")\n\t\t\t\t\t\t\tdata.Write(helpers.QuoteForJSON(helpers.UTF16ToString(entry.Key), s.options.ASCIIOnly))\n\t\t\t\t\t\t\tdata.WriteString(\": \")\n\t\t\t\t\t\t\tdata.Write(helpers.QuoteForJSON(helpers.UTF16ToString(entry.Value), s.options.ASCIIOnly))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata.WriteString(\"\\n          }\")\n\t\t\t\t\t\tmetafileWith = data.String()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Skip this import record if the previous resolver call failed\n\t\t\t\tresolveResult := result.resolveResults[importRecordIndex]\n\t\t\t\tif resolveResult == nil || !record.SourceIndex.IsValid() {\n\t\t\t\t\tif s.options.NeedsMetafile {\n\t\t\t\t\t\tif isFirstImport {\n\t\t\t\t\t\t\tisFirstImport = false\n\t\t\t\t\t\t\tsb.WriteString(\"\\n        \")\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsb.WriteString(\",\\n        \")\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsb.WriteString(fmt.Sprintf(\"{\\n          \\\"path\\\": %s,\\n          \\\"kind\\\": %s,\\n          \\\"external\\\": true%s\\n        }\",\n\t\t\t\t\t\t\thelpers.QuoteForJSON(record.Path.Text, s.options.ASCIIOnly),\n\t\t\t\t\t\t\thelpers.QuoteForJSON(record.Kind.StringForMetafile(), s.options.ASCIIOnly),\n\t\t\t\t\t\t\tmetafileWith))\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Now that all files have been scanned, look for packages that are imported\n\t\t\t\t// both with \"import\" and \"require\". Rewrite any imports that reference the\n\t\t\t\t// \"module\" package.json field to the \"main\" package.json field instead.\n\t\t\t\t//\n\t\t\t\t// This attempts to automatically avoid the \"dual package hazard\" where a\n\t\t\t\t// package has both a CommonJS module version and an ECMAScript module\n\t\t\t\t// version and exports a non-object in CommonJS (often a function). If we\n\t\t\t\t// pick the \"module\" field and the package is imported with \"require\" then\n\t\t\t\t// code expecting a function will crash.\n\t\t\t\tif resolveResult.PathPair.HasSecondary() {\n\t\t\t\t\tsecondaryKey := resolveResult.PathPair.Secondary\n\t\t\t\t\tif secondaryKey.Namespace == \"file\" {\n\t\t\t\t\t\tsecondaryKey.Text = canonicalFileSystemPathForWindows(secondaryKey.Text)\n\t\t\t\t\t}\n\t\t\t\t\tif secondaryVisited, ok := s.visited[secondaryKey]; ok {\n\t\t\t\t\t\trecord.SourceIndex = ast.MakeIndex32(secondaryVisited.sourceIndex)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Generate metadata about each import\n\t\t\t\totherResult := &s.results[record.SourceIndex.GetIndex()]\n\t\t\t\totherFile := &otherResult.file\n\t\t\t\tif s.options.NeedsMetafile {\n\t\t\t\t\tif isFirstImport {\n\t\t\t\t\t\tisFirstImport = false\n\t\t\t\t\t\tsb.WriteString(\"\\n        \")\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsb.WriteString(\",\\n        \")\n\t\t\t\t\t}\n\t\t\t\t\tsb.WriteString(fmt.Sprintf(\"{\\n          \\\"path\\\": %s,\\n          \\\"kind\\\": %s,\\n          \\\"original\\\": %s%s\\n        }\",\n\t\t\t\t\t\thelpers.QuoteForJSON(otherFile.inputFile.Source.PrettyPaths.Select(s.options.MetafilePathStyle), s.options.ASCIIOnly),\n\t\t\t\t\t\thelpers.QuoteForJSON(record.Kind.StringForMetafile(), s.options.ASCIIOnly),\n\t\t\t\t\t\thelpers.QuoteForJSON(record.Path.Text, s.options.ASCIIOnly),\n\t\t\t\t\t\tmetafileWith))\n\t\t\t\t}\n\n\t\t\t\t// Validate that imports with \"assert { type: 'json' }\" were imported\n\t\t\t\t// with the JSON loader. This is done to match the behavior of these\n\t\t\t\t// import assertions in a real JavaScript runtime. In addition, we also\n\t\t\t\t// allow the copy loader since this is sort of like marking the path\n\t\t\t\t// as external (the import assertions are kept and the real JavaScript\n\t\t\t\t// runtime evaluates them, not us).\n\t\t\t\tif record.Flags.Has(ast.AssertTypeJSON) && otherResult.ok && otherFile.inputFile.Loader != config.LoaderJSON && otherFile.inputFile.Loader != config.LoaderCopy {\n\t\t\t\t\ts.log.AddErrorWithNotes(&tracker, record.Range,\n\t\t\t\t\t\tfmt.Sprintf(\"The file %q was loaded with the %q loader\",\n\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle),\n\t\t\t\t\t\t\tconfig.LoaderToString[otherFile.inputFile.Loader]),\n\t\t\t\t\t\t[]logger.MsgData{\n\t\t\t\t\t\t\ttracker.MsgData(js_lexer.RangeOfImportAssertOrWith(result.file.inputFile.Source,\n\t\t\t\t\t\t\t\t*ast.FindAssertOrWithEntry(record.AssertOrWith.Entries, \"type\"), js_lexer.KeyAndValueRange),\n\t\t\t\t\t\t\t\t\"This import assertion requires the loader to be \\\"json\\\" instead:\"),\n\t\t\t\t\t\t\t{Text: \"You need to either reconfigure esbuild to ensure that the loader for this file is \\\"json\\\" or you need to remove this import assertion.\"}})\n\t\t\t\t}\n\n\t\t\t\tswitch record.Kind {\n\t\t\t\tcase ast.ImportComposesFrom:\n\t\t\t\t\t// Using a JavaScript file with CSS \"composes\" is not allowed\n\t\t\t\t\tif _, ok := otherFile.inputFile.Repr.(*graph.JSRepr); ok && otherFile.inputFile.Loader != config.LoaderEmpty {\n\t\t\t\t\t\ts.log.AddErrorWithNotes(&tracker, record.Range,\n\t\t\t\t\t\t\tfmt.Sprintf(\"Cannot use \\\"composes\\\" with %q\",\n\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle)),\n\t\t\t\t\t\t\t[]logger.MsgData{{Text: fmt.Sprintf(\n\t\t\t\t\t\t\t\t\"You can only use \\\"composes\\\" with CSS files and %q is not a CSS file (it was loaded with the %q loader).\",\n\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle),\n\t\t\t\t\t\t\t\tconfig.LoaderToString[otherFile.inputFile.Loader])}})\n\t\t\t\t\t}\n\n\t\t\t\tcase ast.ImportAt:\n\t\t\t\t\t// Using a JavaScript file with CSS \"@import\" is not allowed\n\t\t\t\t\tif _, ok := otherFile.inputFile.Repr.(*graph.JSRepr); ok && otherFile.inputFile.Loader != config.LoaderEmpty {\n\t\t\t\t\t\ts.log.AddErrorWithNotes(&tracker, record.Range,\n\t\t\t\t\t\t\tfmt.Sprintf(\"Cannot import %q into a CSS file\",\n\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle)),\n\t\t\t\t\t\t\t[]logger.MsgData{{Text: fmt.Sprintf(\n\t\t\t\t\t\t\t\t\"An \\\"@import\\\" rule can only be used to import another CSS file and %q is not a CSS file (it was loaded with the %q loader).\",\n\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle),\n\t\t\t\t\t\t\t\tconfig.LoaderToString[otherFile.inputFile.Loader])}})\n\t\t\t\t\t}\n\n\t\t\t\tcase ast.ImportURL:\n\t\t\t\t\t// Using a JavaScript or CSS file with CSS \"url()\" is not allowed\n\t\t\t\t\tswitch otherRepr := otherFile.inputFile.Repr.(type) {\n\t\t\t\t\tcase *graph.CSSRepr:\n\t\t\t\t\t\ts.log.AddErrorWithNotes(&tracker, record.Range,\n\t\t\t\t\t\t\tfmt.Sprintf(\"Cannot use %q as a URL\",\n\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle)),\n\t\t\t\t\t\t\t[]logger.MsgData{{Text: fmt.Sprintf(\n\t\t\t\t\t\t\t\t\"You can't use a \\\"url()\\\" token to reference a CSS file, and %q is a CSS file (it was loaded with the %q loader).\",\n\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle),\n\t\t\t\t\t\t\t\tconfig.LoaderToString[otherFile.inputFile.Loader])}})\n\n\t\t\t\t\tcase *graph.JSRepr:\n\t\t\t\t\t\tif otherRepr.AST.URLForCSS == \"\" && otherFile.inputFile.Loader != config.LoaderEmpty {\n\t\t\t\t\t\t\ts.log.AddErrorWithNotes(&tracker, record.Range,\n\t\t\t\t\t\t\t\tfmt.Sprintf(\"Cannot use %q as a URL\",\n\t\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle)),\n\t\t\t\t\t\t\t\t[]logger.MsgData{{Text: fmt.Sprintf(\n\t\t\t\t\t\t\t\t\t\"You can't use a \\\"url()\\\" token to reference the file %q because it was loaded with the %q loader, which doesn't provide a URL to embed in the resulting CSS.\",\n\t\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle),\n\t\t\t\t\t\t\t\t\tconfig.LoaderToString[otherFile.inputFile.Loader])}})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If the imported file uses the \"copy\" loader, then move it from\n\t\t\t\t// \"SourceIndex\" to \"CopySourceIndex\" so we don't end up bundling it.\n\t\t\t\tif _, ok := otherFile.inputFile.Repr.(*graph.CopyRepr); ok {\n\t\t\t\t\trecord.CopySourceIndex = record.SourceIndex\n\t\t\t\t\trecord.SourceIndex = ast.Index32{}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// If an import from a JavaScript file targets a CSS file, generate a\n\t\t\t\t// JavaScript stub to ensure that JavaScript files only ever import\n\t\t\t\t// other JavaScript files.\n\t\t\t\tif _, ok := result.file.inputFile.Repr.(*graph.JSRepr); ok {\n\t\t\t\t\tif css, ok := otherFile.inputFile.Repr.(*graph.CSSRepr); ok {\n\t\t\t\t\t\tif s.options.WriteToStdout {\n\t\t\t\t\t\t\ts.log.AddError(&tracker, record.Range,\n\t\t\t\t\t\t\t\tfmt.Sprintf(\"Cannot import %q into a JavaScript file without an output path configured\",\n\t\t\t\t\t\t\t\t\totherFile.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle)))\n\t\t\t\t\t\t} else if !css.JSSourceIndex.IsValid() {\n\t\t\t\t\t\t\tstubKey := otherFile.inputFile.Source.KeyPath\n\t\t\t\t\t\t\tif stubKey.Namespace == \"file\" {\n\t\t\t\t\t\t\t\tstubKey.Text = canonicalFileSystemPathForWindows(stubKey.Text)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsourceIndex := s.allocateSourceIndex(stubKey, cache.SourceIndexJSStubForCSS)\n\t\t\t\t\t\t\tsource := otherFile.inputFile.Source\n\t\t\t\t\t\t\tsource.Index = sourceIndex\n\t\t\t\t\t\t\ts.results[sourceIndex] = parseResult{\n\t\t\t\t\t\t\t\tfile: scannerFile{\n\t\t\t\t\t\t\t\t\tinputFile: graph.InputFile{\n\t\t\t\t\t\t\t\t\t\tSource: source,\n\t\t\t\t\t\t\t\t\t\tLoader: otherFile.inputFile.Loader,\n\t\t\t\t\t\t\t\t\t\tRepr: &graph.JSRepr{\n\t\t\t\t\t\t\t\t\t\t\t// Note: The actual export object will be filled in by the linker\n\t\t\t\t\t\t\t\t\t\t\tAST: js_parser.LazyExportAST(s.log, source,\n\t\t\t\t\t\t\t\t\t\t\t\tjs_parser.OptionsFromConfig(&s.options), js_ast.Expr{Data: js_ast.ENullShared}, nil),\n\t\t\t\t\t\t\t\t\t\t\tCSSSourceIndex: ast.MakeIndex32(record.SourceIndex.GetIndex()),\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tok: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcss.JSSourceIndex = ast.MakeIndex32(sourceIndex)\n\t\t\t\t\t\t}\n\t\t\t\t\t\trecord.SourceIndex = css.JSSourceIndex\n\t\t\t\t\t\tif !css.JSSourceIndex.IsValid() {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Warn about this import if it's a bare import statement without any\n\t\t\t\t// imported names (i.e. a side-effect-only import) and the module has\n\t\t\t\t// been marked as having no side effects.\n\t\t\t\t//\n\t\t\t\t// Except don't do this if this file is inside \"node_modules\" since\n\t\t\t\t// it's a bug in the package and the user won't be able to do anything\n\t\t\t\t// about it. Note that this can result in esbuild silently generating\n\t\t\t\t// broken code. If this actually happens for people, it's probably worth\n\t\t\t\t// re-enabling the warning about code inside \"node_modules\".\n\t\t\t\tif record.Flags.Has(ast.WasOriginallyBareImport) && !s.options.IgnoreDCEAnnotations &&\n\t\t\t\t\t!helpers.IsInsideNodeModules(result.file.inputFile.Source.KeyPath.Text) {\n\t\t\t\t\tif otherModule := &s.results[record.SourceIndex.GetIndex()].file.inputFile; otherModule.SideEffects.Kind != graph.HasSideEffects &&\n\t\t\t\t\t\t// Do not warn if this is from a plugin, since removing the import\n\t\t\t\t\t\t// would cause the plugin to not run, and running a plugin is a side\n\t\t\t\t\t\t// effect.\n\t\t\t\t\t\totherModule.SideEffects.Kind != graph.NoSideEffects_PureData_FromPlugin &&\n\n\t\t\t\t\t\t// Do not warn if this has no side effects because the parsed AST\n\t\t\t\t\t\t// is empty. This is the case for \".d.ts\" files, for example.\n\t\t\t\t\t\totherModule.SideEffects.Kind != graph.NoSideEffects_EmptyAST {\n\n\t\t\t\t\t\tvar notes []logger.MsgData\n\t\t\t\t\t\tvar by string\n\t\t\t\t\t\tif data := otherModule.SideEffects.Data; data != nil {\n\t\t\t\t\t\t\tif data.PluginName != \"\" {\n\t\t\t\t\t\t\t\tby = fmt.Sprintf(\" by plugin %q\", data.PluginName)\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tvar text string\n\t\t\t\t\t\t\t\tif data.IsSideEffectsArrayInJSON {\n\t\t\t\t\t\t\t\t\ttext = \"It was excluded from the \\\"sideEffects\\\" array in the enclosing \\\"package.json\\\" file:\"\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\ttext = \"\\\"sideEffects\\\" is false in the enclosing \\\"package.json\\\" file:\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttracker := logger.MakeLineColumnTracker(data.Source)\n\t\t\t\t\t\t\t\tnotes = append(notes, tracker.MsgData(data.Range, text))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\ts.log.AddIDWithNotes(logger.MsgID_Bundler_IgnoredBareImport, logger.Warning, &tracker, record.Range,\n\t\t\t\t\t\t\tfmt.Sprintf(\"Ignoring this import because %q was marked as having no side effects%s\",\n\t\t\t\t\t\t\t\totherModule.Source.PrettyPaths.Select(s.options.LogPathStyle), by), notes)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// End the metadata chunk\n\t\tif s.options.NeedsMetafile {\n\t\t\tif !isFirstImport {\n\t\t\t\tsb.WriteString(\"\\n      \")\n\t\t\t}\n\t\t\tif repr, ok := result.file.inputFile.Repr.(*graph.JSRepr); ok &&\n\t\t\t\t(repr.AST.ExportsKind == js_ast.ExportsCommonJS || repr.AST.ExportsKind == js_ast.ExportsESM) {\n\t\t\t\tformat := \"cjs\"\n\t\t\t\tif repr.AST.ExportsKind == js_ast.ExportsESM {\n\t\t\t\t\tformat = \"esm\"\n\t\t\t\t}\n\t\t\t\tsb.WriteString(fmt.Sprintf(\"],\\n      \\\"format\\\": %q\", format))\n\t\t\t} else {\n\t\t\t\tsb.WriteString(\"]\")\n\t\t\t}\n\t\t\tif attrs := result.file.inputFile.Source.KeyPath.ImportAttributes.DecodeIntoArray(); len(attrs) > 0 {\n\t\t\t\tsb.WriteString(\",\\n      \\\"with\\\": {\")\n\t\t\t\tfor i, attr := range attrs {\n\t\t\t\t\tif i > 0 {\n\t\t\t\t\t\tsb.WriteByte(',')\n\t\t\t\t\t}\n\t\t\t\t\tsb.WriteString(fmt.Sprintf(\"\\n        %s: %s\",\n\t\t\t\t\t\thelpers.QuoteForJSON(attr.Key, s.options.ASCIIOnly),\n\t\t\t\t\t\thelpers.QuoteForJSON(attr.Value, s.options.ASCIIOnly),\n\t\t\t\t\t))\n\t\t\t\t}\n\t\t\t\tsb.WriteString(\"\\n      }\")\n\t\t\t}\n\t\t\tsb.WriteString(\"\\n    }\")\n\t\t}\n\n\t\tresult.file.jsonMetadataChunk = sb.String()\n\n\t\t// If this file is from the \"file\" or \"copy\" loaders, generate an additional file\n\t\tif result.file.inputFile.UniqueKeyForAdditionalFile != \"\" {\n\t\t\tbytes := []byte(result.file.inputFile.Source.Contents)\n\t\t\ttemplate := s.options.AssetPathTemplate\n\n\t\t\t// Use the entry path template instead of the asset path template if this\n\t\t\t// file is an entry point and uses the \"copy\" loader. With the \"file\" loader\n\t\t\t// the JS stub is the entry point, but with the \"copy\" loader the file is\n\t\t\t// the entry point itself.\n\t\t\tcustomFilePath := \"\"\n\t\t\tuseOutputFile := false\n\t\t\tisEntryPoint := false\n\t\t\tif result.file.inputFile.Loader == config.LoaderCopy {\n\t\t\t\tif metaIndex, ok := entryPointSourceIndexToMetaIndex[uint32(sourceIndex)]; ok {\n\t\t\t\t\ttemplate = s.options.EntryPathTemplate\n\t\t\t\t\tcustomFilePath = entryPointMeta[metaIndex].OutputPath\n\t\t\t\t\tuseOutputFile = s.options.AbsOutputFile != \"\"\n\t\t\t\t\tisEntryPoint = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add a hash to the file name to prevent multiple files with the same name\n\t\t\t// but different contents from colliding\n\t\t\tvar hash string\n\t\t\tif config.HasPlaceholder(template, config.HashPlaceholder) {\n\t\t\t\th := xxhash.New()\n\t\t\t\th.Write(bytes)\n\t\t\t\thash = HashForFileName(h.Sum(nil))\n\t\t\t}\n\n\t\t\t// This should use similar logic to how the linker computes output paths\n\t\t\tvar dir, base, ext string\n\t\t\tif useOutputFile {\n\t\t\t\t// If the output path was configured explicitly, use it verbatim\n\t\t\t\tdir = \"/\"\n\t\t\t\tbase = s.fs.Base(s.options.AbsOutputFile)\n\t\t\t\text = s.fs.Ext(base)\n\t\t\t\tbase = base[:len(base)-len(ext)]\n\t\t\t} else {\n\t\t\t\t// Otherwise, derive the output path from the input path\n\t\t\t\t// Generate the input for the template\n\t\t\t\t_, _, originalExt := logger.PlatformIndependentPathDirBaseExt(result.file.inputFile.Source.KeyPath.Text)\n\t\t\t\tdir, base = PathRelativeToOutbase(\n\t\t\t\t\t&result.file.inputFile,\n\t\t\t\t\t&s.options,\n\t\t\t\t\ts.fs,\n\t\t\t\t\t/* avoidIndex */ false,\n\t\t\t\t\tcustomFilePath,\n\t\t\t\t)\n\t\t\t\text = originalExt\n\t\t\t}\n\n\t\t\t// Apply the path template\n\t\t\ttemplateExt := strings.TrimPrefix(ext, \".\")\n\t\t\trelPath := config.TemplateToString(config.SubstituteTemplate(template, config.PathPlaceholders{\n\t\t\t\tDir:  &dir,\n\t\t\t\tName: &base,\n\t\t\t\tHash: &hash,\n\t\t\t\tExt:  &templateExt,\n\t\t\t})) + ext\n\n\t\t\t// Optionally add metadata about the file\n\t\t\tvar jsonMetadataChunk string\n\t\t\tif s.options.NeedsMetafile {\n\t\t\t\tinputs := fmt.Sprintf(\"{\\n        %s: {\\n          \\\"bytesInOutput\\\": %d\\n        }\\n      }\",\n\t\t\t\t\thelpers.QuoteForJSON(result.file.inputFile.Source.PrettyPaths.Select(s.options.MetafilePathStyle), s.options.ASCIIOnly),\n\t\t\t\t\tlen(bytes),\n\t\t\t\t)\n\t\t\t\tentryPointJSON := \"\"\n\t\t\t\tif isEntryPoint {\n\t\t\t\t\tentryPointJSON = fmt.Sprintf(\"\\\"entryPoint\\\": %s,\\n      \",\n\t\t\t\t\t\thelpers.QuoteForJSON(result.file.inputFile.Source.PrettyPaths.Select(s.options.MetafilePathStyle), s.options.ASCIIOnly))\n\t\t\t\t}\n\t\t\t\tjsonMetadataChunk = fmt.Sprintf(\n\t\t\t\t\t\"{\\n      \\\"imports\\\": [],\\n      \\\"exports\\\": [],\\n      %s\\\"inputs\\\": %s,\\n      \\\"bytes\\\": %d\\n    }\",\n\t\t\t\t\tentryPointJSON,\n\t\t\t\t\tinputs,\n\t\t\t\t\tlen(bytes),\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Generate the additional file to copy into the output directory\n\t\t\tresult.file.inputFile.AdditionalFiles = []graph.OutputFile{{\n\t\t\t\tAbsPath:           s.fs.Join(s.options.AbsOutputDir, relPath),\n\t\t\t\tContents:          bytes,\n\t\t\t\tJSONMetadataChunk: jsonMetadataChunk,\n\t\t\t}}\n\t\t}\n\n\t\ts.results[sourceIndex] = result\n\t}\n\n\t// The linker operates on an array of files, so construct that now. This\n\t// can't be constructed earlier because we generate new parse results for\n\t// JavaScript stub files for CSS imports above.\n\tfiles := make([]scannerFile, len(s.results))\n\tfor sourceIndex := range s.results {\n\t\tif result := &s.results[sourceIndex]; result.ok {\n\t\t\ts.validateTLA(uint32(sourceIndex))\n\t\t\tfiles[sourceIndex] = result.file\n\t\t}\n\t}\n\n\treturn files\n}\n\nfunc (s *scanner) validateTLA(sourceIndex uint32) tlaCheck {\n\tresult := &s.results[sourceIndex]\n\n\tif result.ok && result.tlaCheck.depth == 0 {\n\t\tif repr, ok := result.file.inputFile.Repr.(*graph.JSRepr); ok {\n\t\t\tresult.tlaCheck.depth = 1\n\t\t\tif repr.AST.LiveTopLevelAwaitKeyword.Len > 0 {\n\t\t\t\tresult.tlaCheck.parent = ast.MakeIndex32(sourceIndex)\n\t\t\t}\n\n\t\t\tfor importRecordIndex, record := range repr.AST.ImportRecords {\n\t\t\t\tif record.SourceIndex.IsValid() && (record.Kind == ast.ImportRequire || record.Kind == ast.ImportStmt) {\n\t\t\t\t\tparent := s.validateTLA(record.SourceIndex.GetIndex())\n\t\t\t\t\tif !parent.parent.IsValid() {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// Follow any import chains\n\t\t\t\t\tif record.Kind == ast.ImportStmt && (!result.tlaCheck.parent.IsValid() || parent.depth < result.tlaCheck.depth) {\n\t\t\t\t\t\tresult.tlaCheck.depth = parent.depth + 1\n\t\t\t\t\t\tresult.tlaCheck.parent = record.SourceIndex\n\t\t\t\t\t\tresult.tlaCheck.importRecordIndex = uint32(importRecordIndex)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\t\t// Require of a top-level await chain is forbidden\n\t\t\t\t\tif record.Kind == ast.ImportRequire {\n\t\t\t\t\t\tvar notes []logger.MsgData\n\t\t\t\t\t\tvar tlaPrettyPaths logger.PrettyPaths\n\t\t\t\t\t\totherSourceIndex := record.SourceIndex.GetIndex()\n\n\t\t\t\t\t\t// Build up a chain of relevant notes for all of the imports\n\t\t\t\t\t\tfor {\n\t\t\t\t\t\t\tparentResult := &s.results[otherSourceIndex]\n\t\t\t\t\t\t\tparentRepr := parentResult.file.inputFile.Repr.(*graph.JSRepr)\n\n\t\t\t\t\t\t\tif parentRepr.AST.LiveTopLevelAwaitKeyword.Len > 0 {\n\t\t\t\t\t\t\t\ttlaPrettyPaths = parentResult.file.inputFile.Source.PrettyPaths\n\t\t\t\t\t\t\t\ttracker := logger.MakeLineColumnTracker(&parentResult.file.inputFile.Source)\n\t\t\t\t\t\t\t\tnotes = append(notes, tracker.MsgData(parentRepr.AST.LiveTopLevelAwaitKeyword,\n\t\t\t\t\t\t\t\t\tfmt.Sprintf(\"The top-level await in %q is here:\",\n\t\t\t\t\t\t\t\t\t\ttlaPrettyPaths.Select(s.options.LogPathStyle))))\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif !parentResult.tlaCheck.parent.IsValid() {\n\t\t\t\t\t\t\t\tnotes = append(notes, logger.MsgData{Text: \"unexpected invalid index\"})\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\totherSourceIndex = parentResult.tlaCheck.parent.GetIndex()\n\n\t\t\t\t\t\t\ttracker := logger.MakeLineColumnTracker(&parentResult.file.inputFile.Source)\n\t\t\t\t\t\t\tnotes = append(notes, tracker.MsgData(\n\t\t\t\t\t\t\t\tparentRepr.AST.ImportRecords[parentResult.tlaCheck.importRecordIndex].Range,\n\t\t\t\t\t\t\t\tfmt.Sprintf(\"The file %q imports the file %q here:\",\n\t\t\t\t\t\t\t\t\tparentResult.file.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle),\n\t\t\t\t\t\t\t\t\ts.results[otherSourceIndex].file.inputFile.Source.PrettyPaths.Select(s.options.LogPathStyle))))\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tvar text string\n\t\t\t\t\t\timportedPrettyPaths := s.results[record.SourceIndex.GetIndex()].file.inputFile.Source.PrettyPaths\n\n\t\t\t\t\t\tif importedPrettyPaths == tlaPrettyPaths {\n\t\t\t\t\t\t\ttext = fmt.Sprintf(\"This require call is not allowed because the imported file %q contains a top-level await\",\n\t\t\t\t\t\t\t\timportedPrettyPaths.Select(s.options.LogPathStyle))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttext = fmt.Sprintf(\"This require call is not allowed because the transitive dependency %q contains a top-level await\",\n\t\t\t\t\t\t\t\ttlaPrettyPaths.Select(s.options.LogPathStyle))\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttracker := logger.MakeLineColumnTracker(&result.file.inputFile.Source)\n\t\t\t\t\t\ts.log.AddErrorWithNotes(&tracker, record.Range, text, notes)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Make sure that if we wrap this module in a closure, the closure is also\n\t\t\t// async. This happens when you call \"import()\" on this module and code\n\t\t\t// splitting is off.\n\t\t\tif result.tlaCheck.parent.IsValid() {\n\t\t\t\trepr.Meta.IsAsyncOrHasAsyncDependency = true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.tlaCheck\n}\n\nfunc DefaultExtensionToLoaderMap() map[string]config.Loader {\n\treturn map[string]config.Loader{\n\t\t\"\":            config.LoaderJS, // This represents files without an extension\n\t\t\".js\":         config.LoaderJS,\n\t\t\".mjs\":        config.LoaderJS,\n\t\t\".cjs\":        config.LoaderJS,\n\t\t\".jsx\":        config.LoaderJSX,\n\t\t\".ts\":         config.LoaderTS,\n\t\t\".cts\":        config.LoaderTSNoAmbiguousLessThan,\n\t\t\".mts\":        config.LoaderTSNoAmbiguousLessThan,\n\t\t\".tsx\":        config.LoaderTSX,\n\t\t\".css\":        config.LoaderCSS,\n\t\t\".module.css\": config.LoaderLocalCSS,\n\t\t\".json\":       config.LoaderJSON,\n\t\t\".txt\":        config.LoaderText,\n\t}\n}\n\nfunc applyOptionDefaults(options *config.Options) {\n\tif options.ExtensionToLoader == nil {\n\t\toptions.ExtensionToLoader = DefaultExtensionToLoaderMap()\n\t}\n\tif options.OutputExtensionJS == \"\" {\n\t\toptions.OutputExtensionJS = \".js\"\n\t}\n\tif options.OutputExtensionCSS == \"\" {\n\t\toptions.OutputExtensionCSS = \".css\"\n\t}\n\n\t// Configure default path templates\n\tif len(options.EntryPathTemplate) == 0 {\n\t\toptions.EntryPathTemplate = []config.PathTemplate{\n\t\t\t{Data: \"./\", Placeholder: config.DirPlaceholder},\n\t\t\t{Data: \"/\", Placeholder: config.NamePlaceholder},\n\t\t}\n\t}\n\tif len(options.ChunkPathTemplate) == 0 {\n\t\toptions.ChunkPathTemplate = []config.PathTemplate{\n\t\t\t{Data: \"./\", Placeholder: config.NamePlaceholder},\n\t\t\t{Data: \"-\", Placeholder: config.HashPlaceholder},\n\t\t}\n\t}\n\tif len(options.AssetPathTemplate) == 0 {\n\t\toptions.AssetPathTemplate = []config.PathTemplate{\n\t\t\t{Data: \"./\", Placeholder: config.NamePlaceholder},\n\t\t\t{Data: \"-\", Placeholder: config.HashPlaceholder},\n\t\t}\n\t}\n\n\toptions.ProfilerNames = !options.MinifyIdentifiers\n\n\t// Automatically fix invalid configurations of unsupported features\n\tfixInvalidUnsupportedJSFeatureOverrides(options, compat.AsyncAwait, compat.AsyncGenerator|compat.ForAwait|compat.TopLevelAwait)\n\tfixInvalidUnsupportedJSFeatureOverrides(options, compat.Generator, compat.AsyncGenerator)\n\tfixInvalidUnsupportedJSFeatureOverrides(options, compat.ObjectAccessors, compat.ClassPrivateAccessor|compat.ClassPrivateStaticAccessor)\n\tfixInvalidUnsupportedJSFeatureOverrides(options, compat.ClassField, compat.ClassPrivateField)\n\tfixInvalidUnsupportedJSFeatureOverrides(options, compat.ClassStaticField, compat.ClassPrivateStaticField)\n\tfixInvalidUnsupportedJSFeatureOverrides(options, compat.Class,\n\t\tcompat.ClassField|compat.ClassPrivateAccessor|compat.ClassPrivateBrandCheck|compat.ClassPrivateField|\n\t\t\tcompat.ClassPrivateMethod|compat.ClassPrivateStaticAccessor|compat.ClassPrivateStaticField|\n\t\t\tcompat.ClassPrivateStaticMethod|compat.ClassStaticBlocks|compat.ClassStaticField)\n\n\t// If we're not building for the browser, automatically disable support for\n\t// inline </script> and </style> tags if there aren't currently any overrides\n\tif options.Platform != config.PlatformBrowser {\n\t\tif !options.UnsupportedJSFeatureOverridesMask.Has(compat.InlineScript) {\n\t\t\toptions.UnsupportedJSFeatures |= compat.InlineScript\n\t\t}\n\t\tif !options.UnsupportedCSSFeatureOverridesMask.Has(compat.InlineStyle) {\n\t\t\toptions.UnsupportedCSSFeatures |= compat.InlineStyle\n\t\t}\n\t}\n}\n\nfunc fixInvalidUnsupportedJSFeatureOverrides(options *config.Options, implies compat.JSFeature, implied compat.JSFeature) {\n\t// If this feature is unsupported, that implies that the other features must also be unsupported\n\tif options.UnsupportedJSFeatureOverrides.Has(implies) {\n\t\toptions.UnsupportedJSFeatures |= implied\n\t\toptions.UnsupportedJSFeatureOverrides |= implied\n\t\toptions.UnsupportedJSFeatureOverridesMask |= implied\n\t}\n}\n\ntype Linker func(\n\toptions *config.Options,\n\ttimer *helpers.Timer,\n\tlog logger.Log,\n\tfs fs.FS,\n\tres *resolver.Resolver,\n\tinputFiles []graph.InputFile,\n\tentryPoints []graph.EntryPoint,\n\tuniqueKeyPrefix string,\n\treachableFiles []uint32,\n\tdataForSourceMaps func() []DataForSourceMap,\n) []graph.OutputFile\n\nfunc (b *Bundle) Compile(log logger.Log, timer *helpers.Timer, mangleCache map[string]interface{}, link Linker) ([]graph.OutputFile, string) {\n\ttimer.Begin(\"Compile phase\")\n\tdefer timer.End(\"Compile phase\")\n\n\tif b.options.CancelFlag.DidCancel() {\n\t\treturn nil, \"\"\n\t}\n\n\toptions := b.options\n\n\t// In most cases we don't need synchronized access to the mangle cache\n\tcssUsedLocalNames := make(map[string]bool)\n\toptions.ExclusiveMangleCacheUpdate = func(cb func(\n\t\tmangleCache map[string]interface{},\n\t\tcssUsedLocalNames map[string]bool,\n\t)) {\n\t\tcb(mangleCache, cssUsedLocalNames)\n\t}\n\n\tfiles := make([]graph.InputFile, len(b.files))\n\tfor i, file := range b.files {\n\t\tfiles[i] = file.inputFile\n\t}\n\n\t// Get the base path from the options or choose the lowest common ancestor of all entry points\n\tallReachableFiles := findReachableFiles(files, b.entryPoints)\n\n\t// Compute source map data in parallel with linking\n\ttimer.Begin(\"Spawn source map tasks\")\n\tdataForSourceMaps := b.computeDataForSourceMapsInParallel(&options, allReachableFiles)\n\ttimer.End(\"Spawn source map tasks\")\n\n\tvar resultGroups [][]graph.OutputFile\n\tif options.CodeSplitting || len(b.entryPoints) == 1 {\n\t\t// If code splitting is enabled or if there's only one entry point, link all entry points together\n\t\tresultGroups = [][]graph.OutputFile{link(&options, timer, log, b.fs, b.res,\n\t\t\tfiles, b.entryPoints, b.uniqueKeyPrefix, allReachableFiles, dataForSourceMaps)}\n\t} else {\n\t\t// Otherwise, link each entry point with the runtime file separately\n\t\twaitGroup := sync.WaitGroup{}\n\t\tresultGroups = make([][]graph.OutputFile, len(b.entryPoints))\n\t\tserializer := helpers.MakeSerializer(len(b.entryPoints))\n\t\tfor i, entryPoint := range b.entryPoints {\n\t\t\twaitGroup.Add(1)\n\t\t\tgo func(i int, entryPoint graph.EntryPoint) {\n\t\t\t\tentryPoints := []graph.EntryPoint{entryPoint}\n\t\t\t\tforked := timer.Fork()\n\n\t\t\t\t// Each goroutine needs a separate options object\n\t\t\t\toptionsClone := options\n\t\t\t\toptionsClone.ExclusiveMangleCacheUpdate = func(cb func(\n\t\t\t\t\tmangleCache map[string]interface{},\n\t\t\t\t\tcssUsedLocalNames map[string]bool,\n\t\t\t\t)) {\n\t\t\t\t\t// Serialize all accesses to the mangle cache in entry point order for determinism\n\t\t\t\t\tserializer.Enter(i)\n\t\t\t\t\tdefer serializer.Leave(i)\n\t\t\t\t\tcb(mangleCache, cssUsedLocalNames)\n\t\t\t\t}\n\n\t\t\t\tresultGroups[i] = link(&optionsClone, forked, log, b.fs, b.res, files, entryPoints,\n\t\t\t\t\tb.uniqueKeyPrefix, findReachableFiles(files, entryPoints), dataForSourceMaps)\n\t\t\t\ttimer.Join(forked)\n\t\t\t\twaitGroup.Done()\n\t\t\t}(i, entryPoint)\n\t\t}\n\t\twaitGroup.Wait()\n\t}\n\n\t// Join the results in entry point order for determinism\n\tvar outputFiles []graph.OutputFile\n\tfor _, group := range resultGroups {\n\t\toutputFiles = append(outputFiles, group...)\n\t}\n\n\t// Also generate the metadata file if necessary\n\tvar metafileJSON string\n\tif options.NeedsMetafile {\n\t\ttimer.Begin(\"Generate metadata JSON\")\n\t\tmetafileJSON = b.generateMetadataJSON(outputFiles, allReachableFiles, options.ASCIIOnly)\n\t\ttimer.End(\"Generate metadata JSON\")\n\t}\n\n\tif !options.WriteToStdout {\n\t\t// Make sure an output file never overwrites an input file\n\t\tif !options.AllowOverwrite {\n\t\t\tsourceAbsPaths := make(map[string]uint32)\n\t\t\tfor _, sourceIndex := range allReachableFiles {\n\t\t\t\tkeyPath := b.files[sourceIndex].inputFile.Source.KeyPath\n\t\t\t\tif keyPath.Namespace == \"file\" {\n\t\t\t\t\tabsPathKey := canonicalFileSystemPathForWindows(keyPath.Text)\n\t\t\t\t\tsourceAbsPaths[absPathKey] = sourceIndex\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor _, outputFile := range outputFiles {\n\t\t\t\tabsPathKey := canonicalFileSystemPathForWindows(outputFile.AbsPath)\n\t\t\t\tif sourceIndex, ok := sourceAbsPaths[absPathKey]; ok {\n\t\t\t\t\thint := \"\"\n\t\t\t\t\tswitch logger.API {\n\t\t\t\t\tcase logger.CLIAPI:\n\t\t\t\t\t\thint = \" (use \\\"--allow-overwrite\\\" to allow this)\"\n\t\t\t\t\tcase logger.JSAPI:\n\t\t\t\t\t\thint = \" (use \\\"allowOverwrite: true\\\" to allow this)\"\n\t\t\t\t\tcase logger.GoAPI:\n\t\t\t\t\t\thint = \" (use \\\"AllowOverwrite: true\\\" to allow this)\"\n\t\t\t\t\t}\n\t\t\t\t\tlog.AddError(nil, logger.Range{},\n\t\t\t\t\t\tfmt.Sprintf(\"Refusing to overwrite input file %q%s\",\n\t\t\t\t\t\t\tb.files[sourceIndex].inputFile.Source.PrettyPaths.Select(options.LogPathStyle), hint))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Make sure an output file never overwrites another output file. This\n\t\t// is almost certainly unintentional and would otherwise happen silently.\n\t\t//\n\t\t// Make an exception for files that have identical contents. In that case\n\t\t// the duplicate is just silently filtered out. This can happen with the\n\t\t// \"file\" loader, for example.\n\t\toutputFileMap := make(map[string][]byte)\n\t\tend := 0\n\t\tfor _, outputFile := range outputFiles {\n\t\t\tabsPathKey := canonicalFileSystemPathForWindows(outputFile.AbsPath)\n\t\t\tcontents, ok := outputFileMap[absPathKey]\n\n\t\t\t// If this isn't a duplicate, keep the output file\n\t\t\tif !ok {\n\t\t\t\toutputFileMap[absPathKey] = outputFile.Contents\n\t\t\t\toutputFiles[end] = outputFile\n\t\t\t\tend++\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// If the names and contents are both the same, only keep the first one\n\t\t\tif bytes.Equal(contents, outputFile.Contents) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Otherwise, generate an error\n\t\t\toutputPath := outputFile.AbsPath\n\t\t\tif relPath, ok := b.fs.Rel(b.fs.Cwd(), outputPath); ok {\n\t\t\t\toutputPath = relPath\n\t\t\t}\n\t\t\tlog.AddError(nil, logger.Range{}, \"Two output files share the same path but have different contents: \"+outputPath)\n\t\t}\n\t\toutputFiles = outputFiles[:end]\n\t}\n\n\treturn outputFiles, metafileJSON\n}\n\n// Find all files reachable from all entry points. This order should be\n// deterministic given that the entry point order is deterministic, since the\n// returned order is the postorder of the graph traversal and import record\n// order within a given file is deterministic.\nfunc findReachableFiles(files []graph.InputFile, entryPoints []graph.EntryPoint) []uint32 {\n\tvisited := make(map[uint32]bool)\n\tvar order []uint32\n\tvar visit func(uint32)\n\n\t// Include this file and all files it imports\n\tvisit = func(sourceIndex uint32) {\n\t\tif !visited[sourceIndex] {\n\t\t\tvisited[sourceIndex] = true\n\t\t\tfile := &files[sourceIndex]\n\t\t\tif repr, ok := file.Repr.(*graph.JSRepr); ok && repr.CSSSourceIndex.IsValid() {\n\t\t\t\tvisit(repr.CSSSourceIndex.GetIndex())\n\t\t\t}\n\t\t\tif recordsPtr := file.Repr.ImportRecords(); recordsPtr != nil {\n\t\t\t\tfor _, record := range *recordsPtr {\n\t\t\t\t\tif record.SourceIndex.IsValid() {\n\t\t\t\t\t\tvisit(record.SourceIndex.GetIndex())\n\t\t\t\t\t} else if record.CopySourceIndex.IsValid() {\n\t\t\t\t\t\tvisit(record.CopySourceIndex.GetIndex())\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Each file must come after its dependencies\n\t\t\torder = append(order, sourceIndex)\n\t\t}\n\t}\n\n\t// The runtime is always included in case it's needed\n\tvisit(runtime.SourceIndex)\n\n\t// Include all files reachable from any entry point\n\tfor _, entryPoint := range entryPoints {\n\t\tvisit(entryPoint.SourceIndex)\n\t}\n\n\treturn order\n}\n\n// This is done in parallel with linking because linking is a mostly serial\n// phase and there are extra resources for parallelism. This could also be done\n// during parsing but that would slow down parsing and delay the start of the\n// linking phase, which then delays the whole bundling process.\n//\n// However, doing this during parsing would allow it to be cached along with\n// the parsed ASTs which would then speed up incremental builds. In the future\n// it could be good to optionally have this be computed during the parsing\n// phase when incremental builds are active but otherwise still have it be\n// computed during linking for optimal speed during non-incremental builds.\nfunc (b *Bundle) computeDataForSourceMapsInParallel(options *config.Options, reachableFiles []uint32) func() []DataForSourceMap {\n\tif options.SourceMap == config.SourceMapNone {\n\t\treturn func() []DataForSourceMap {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\tvar waitGroup sync.WaitGroup\n\tresults := make([]DataForSourceMap, len(b.files))\n\n\tfor _, sourceIndex := range reachableFiles {\n\t\tif f := &b.files[sourceIndex]; f.inputFile.Loader.CanHaveSourceMap() {\n\t\t\tvar approximateLineCount int32\n\t\t\tswitch repr := f.inputFile.Repr.(type) {\n\t\t\tcase *graph.JSRepr:\n\t\t\t\tapproximateLineCount = repr.AST.ApproximateLineCount\n\t\t\tcase *graph.CSSRepr:\n\t\t\t\tapproximateLineCount = repr.AST.ApproximateLineCount\n\t\t\t}\n\t\t\twaitGroup.Add(1)\n\t\t\tgo func(sourceIndex uint32, f *scannerFile, approximateLineCount int32) {\n\t\t\t\tresult := &results[sourceIndex]\n\t\t\t\tresult.LineOffsetTables = sourcemap.GenerateLineOffsetTables(f.inputFile.Source.Contents, approximateLineCount)\n\t\t\t\tsm := f.inputFile.InputSourceMap\n\t\t\t\tif !options.ExcludeSourcesContent {\n\t\t\t\t\tif sm == nil {\n\t\t\t\t\t\t// Simple case: no nested source map\n\t\t\t\t\t\tresult.QuotedContents = [][]byte{helpers.QuoteForJSON(f.inputFile.Source.Contents, options.ASCIIOnly)}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Complex case: nested source map\n\t\t\t\t\t\tresult.QuotedContents = make([][]byte, len(sm.Sources))\n\t\t\t\t\t\tnullContents := []byte(\"null\")\n\t\t\t\t\t\tfor i := range sm.Sources {\n\t\t\t\t\t\t\t// Missing contents become a \"null\" literal\n\t\t\t\t\t\t\tquotedContents := nullContents\n\t\t\t\t\t\t\tif i < len(sm.SourcesContent) {\n\t\t\t\t\t\t\t\tif value := sm.SourcesContent[i]; value.Quoted != \"\" && (!options.ASCIIOnly || !isASCIIOnly(value.Quoted)) {\n\t\t\t\t\t\t\t\t\t// Just use the value directly from the input file\n\t\t\t\t\t\t\t\t\tquotedContents = []byte(value.Quoted)\n\t\t\t\t\t\t\t\t} else if value.Value != nil {\n\t\t\t\t\t\t\t\t\t// Re-quote non-ASCII values if output is ASCII-only.\n\t\t\t\t\t\t\t\t\t// Also quote values that haven't been quoted yet\n\t\t\t\t\t\t\t\t\t// (happens when the entire \"sourcesContent\" array is\n\t\t\t\t\t\t\t\t\t// absent and the source has been found on the file\n\t\t\t\t\t\t\t\t\t// system using the \"sources\" array).\n\t\t\t\t\t\t\t\t\tquotedContents = helpers.QuoteForJSON(helpers.UTF16ToString(value.Value), options.ASCIIOnly)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult.QuotedContents[i] = quotedContents\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twaitGroup.Done()\n\t\t\t}(sourceIndex, f, approximateLineCount)\n\t\t}\n\t}\n\n\treturn func() []DataForSourceMap {\n\t\twaitGroup.Wait()\n\t\treturn results\n\t}\n}\n\nfunc (b *Bundle) generateMetadataJSON(results []graph.OutputFile, allReachableFiles []uint32, asciiOnly bool) string {\n\tsb := strings.Builder{}\n\tsb.WriteString(\"{\\n  \\\"inputs\\\": {\")\n\n\t// Write inputs\n\tisFirst := true\n\tfor _, sourceIndex := range allReachableFiles {\n\t\tif b.files[sourceIndex].inputFile.OmitFromSourceMapsAndMetafile {\n\t\t\tcontinue\n\t\t}\n\t\tif file := &b.files[sourceIndex]; len(file.jsonMetadataChunk) > 0 {\n\t\t\tif isFirst {\n\t\t\t\tisFirst = false\n\t\t\t\tsb.WriteString(\"\\n    \")\n\t\t\t} else {\n\t\t\t\tsb.WriteString(\",\\n    \")\n\t\t\t}\n\t\t\tsb.WriteString(file.jsonMetadataChunk)\n\t\t}\n\t}\n\n\tsb.WriteString(\"\\n  },\\n  \\\"outputs\\\": {\")\n\n\t// Write outputs\n\tisFirst = true\n\tpathMap := make(map[string]struct{})\n\tfor _, result := range results {\n\t\tif len(result.JSONMetadataChunk) > 0 {\n\t\t\tprettyPaths := resolver.MakePrettyPaths(b.fs, logger.Path{Text: result.AbsPath, Namespace: \"file\"})\n\t\t\tpath := prettyPaths.Select(b.options.MetafilePathStyle)\n\t\t\tif _, ok := pathMap[path]; ok {\n\t\t\t\t// Don't write out the same path twice (can happen with the \"file\" loader)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif isFirst {\n\t\t\t\tisFirst = false\n\t\t\t\tsb.WriteString(\"\\n    \")\n\t\t\t} else {\n\t\t\t\tsb.WriteString(\",\\n    \")\n\t\t\t}\n\t\t\tpathMap[path] = struct{}{}\n\t\t\tsb.WriteString(fmt.Sprintf(\"%s: \", helpers.QuoteForJSON(path, asciiOnly)))\n\t\t\tsb.WriteString(result.JSONMetadataChunk)\n\t\t}\n\t}\n\n\tsb.WriteString(\"\\n  }\\n}\\n\")\n\treturn sb.String()\n}\n\ntype runtimeCacheKey struct {\n\tunsupportedJSFeatures compat.JSFeature\n\tminifySyntax          bool\n\tminifyIdentifiers     bool\n}\n\ntype runtimeCache struct {\n\tastMap   map[runtimeCacheKey]js_ast.AST\n\tastMutex sync.Mutex\n}\n\nvar globalRuntimeCache runtimeCache\n\nfunc (cache *runtimeCache) parseRuntime(options *config.Options) (source logger.Source, runtimeAST js_ast.AST, ok bool) {\n\tkey := runtimeCacheKey{\n\t\t// All configuration options that the runtime code depends on must go here\n\t\tunsupportedJSFeatures: options.UnsupportedJSFeatures,\n\t\tminifySyntax:          options.MinifySyntax,\n\t\tminifyIdentifiers:     options.MinifyIdentifiers,\n\t}\n\n\t// Determine which source to use\n\tsource = runtime.Source(key.unsupportedJSFeatures)\n\n\t// Cache hit?\n\t(func() {\n\t\tcache.astMutex.Lock()\n\t\tdefer cache.astMutex.Unlock()\n\t\tif cache.astMap != nil {\n\t\t\truntimeAST, ok = cache.astMap[key]\n\t\t}\n\t})()\n\tif ok {\n\t\treturn\n\t}\n\n\t// Cache miss\n\tlog := logger.NewDeferLog(logger.DeferLogAll, nil)\n\truntimeAST, ok = js_parser.Parse(log, source, js_parser.OptionsFromConfig(&config.Options{\n\t\t// These configuration options must only depend on the key\n\t\tUnsupportedJSFeatures: key.unsupportedJSFeatures,\n\t\tMinifySyntax:          key.minifySyntax,\n\t\tMinifyIdentifiers:     key.minifyIdentifiers,\n\n\t\t// Always do tree shaking for the runtime because we never want to\n\t\t// include unnecessary runtime code\n\t\tTreeShaking: true,\n\t}))\n\tif log.HasErrors() {\n\t\tmsgs := \"Internal error: failed to parse runtime:\\n\"\n\t\tfor _, msg := range log.Done() {\n\t\t\tmsgs += msg.String(logger.OutputOptions{IncludeSource: true}, logger.TerminalInfo{})\n\t\t}\n\t\tpanic(msgs[:len(msgs)-1])\n\t}\n\n\t// Cache for next time\n\tif ok {\n\t\tcache.astMutex.Lock()\n\t\tdefer cache.astMutex.Unlock()\n\t\tif cache.astMap == nil {\n\t\t\tcache.astMap = make(map[runtimeCacheKey]js_ast.AST)\n\t\t}\n\t\tcache.astMap[key] = runtimeAST\n\t}\n\treturn\n}\n\n// Returns the path of this file relative to \"outbase\", which is then ready to\n// be joined with the absolute output directory path. The directory and name\n// components are returned separately for convenience.\nfunc PathRelativeToOutbase(\n\tinputFile *graph.InputFile,\n\toptions *config.Options,\n\tfs fs.FS,\n\tavoidIndex bool,\n\tcustomFilePath string,\n) (relDir string, baseName string) {\n\trelDir = \"/\"\n\tabsPath := inputFile.Source.KeyPath.Text\n\n\tif customFilePath != \"\" {\n\t\t// Use the configured output path if present\n\t\tabsPath = customFilePath\n\t\tif !fs.IsAbs(absPath) {\n\t\t\tabsPath = fs.Join(options.AbsOutputBase, absPath)\n\t\t}\n\t} else if inputFile.Source.KeyPath.Namespace != \"file\" {\n\t\t// Come up with a path for virtual paths (i.e. non-file-system paths)\n\t\tdir, base, _ := logger.PlatformIndependentPathDirBaseExt(absPath)\n\t\tif avoidIndex && base == \"index\" {\n\t\t\t_, base, _ = logger.PlatformIndependentPathDirBaseExt(dir)\n\t\t}\n\t\tbaseName = sanitizeFilePathForVirtualModulePath(base)\n\t\treturn\n\t} else {\n\t\t// Heuristic: If the file is named something like \"index.js\", then use\n\t\t// the name of the parent directory instead. This helps avoid the\n\t\t// situation where many chunks are named \"index\" because of people\n\t\t// dynamically-importing npm packages that make use of node's implicit\n\t\t// \"index\" file name feature.\n\t\tif avoidIndex {\n\t\t\tbase := fs.Base(absPath)\n\t\t\tbase = base[:len(base)-len(fs.Ext(base))]\n\t\t\tif base == \"index\" {\n\t\t\t\tabsPath = fs.Dir(absPath)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Try to get a relative path to the base directory\n\trelPath, ok := fs.Rel(options.AbsOutputBase, absPath)\n\tif !ok {\n\t\t// This can fail in some situations such as on different drives on\n\t\t// Windows. In that case we just use the file name.\n\t\tbaseName = fs.Base(absPath)\n\t} else {\n\t\t// Now we finally have a relative path\n\t\trelDir = fs.Dir(relPath) + \"/\"\n\t\tbaseName = fs.Base(relPath)\n\n\t\t// Use platform-independent slashes\n\t\trelDir = strings.ReplaceAll(relDir, \"\\\\\", \"/\")\n\n\t\t// Replace leading \"../\" so we don't try to write outside of the output\n\t\t// directory. This normally can't happen because \"AbsOutputBase\" is\n\t\t// automatically computed to contain all entry point files, but it can\n\t\t// happen if someone sets it manually via the \"outbase\" API option.\n\t\t//\n\t\t// Note that we can't just strip any leading \"../\" because that could\n\t\t// cause two separate entry point paths to collide. For example, there\n\t\t// could be both \"src/index.js\" and \"../src/index.js\" as entry points.\n\t\tdotDotCount := 0\n\t\tfor strings.HasPrefix(relDir[dotDotCount*3:], \"../\") {\n\t\t\tdotDotCount++\n\t\t}\n\t\tif dotDotCount > 0 {\n\t\t\t// The use of \"_.._\" here is somewhat arbitrary but it is unlikely to\n\t\t\t// collide with a folder named by a human and it works on Windows\n\t\t\t// (Windows doesn't like names that end with a \".\"). And not starting\n\t\t\t// with a \".\" means that it will not be hidden on Unix.\n\t\t\trelDir = strings.Repeat(\"_.._/\", dotDotCount) + relDir[dotDotCount*3:]\n\t\t}\n\t\tfor strings.HasSuffix(relDir, \"/\") {\n\t\t\trelDir = relDir[:len(relDir)-1]\n\t\t}\n\t\trelDir = \"/\" + relDir\n\t\tif strings.HasSuffix(relDir, \"/.\") {\n\t\t\trelDir = relDir[:len(relDir)-1]\n\t\t}\n\t}\n\n\t// Strip the file extension if the output path is an input file\n\tif customFilePath == \"\" {\n\t\text := fs.Ext(baseName)\n\t\tbaseName = baseName[:len(baseName)-len(ext)]\n\t}\n\treturn\n}\n\nfunc sanitizeFilePathForVirtualModulePath(path string) string {\n\t// Convert it to a safe file path. See: https://stackoverflow.com/a/31976060\n\tsb := strings.Builder{}\n\tneedsGap := false\n\tfor _, c := range path {\n\t\tswitch c {\n\t\tcase 0:\n\t\t\t// These characters are forbidden on Unix and Windows\n\n\t\tcase '<', '>', ':', '\"', '|', '?', '*':\n\t\t\t// These characters are forbidden on Windows\n\n\t\tdefault:\n\t\t\tif c < 0x20 {\n\t\t\t\t// These characters are forbidden on Windows\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// Turn runs of invalid characters into a '_'\n\t\t\tif needsGap {\n\t\t\t\tsb.WriteByte('_')\n\t\t\t\tneedsGap = false\n\t\t\t}\n\n\t\t\tsb.WriteRune(c)\n\t\t\tcontinue\n\t\t}\n\n\t\tif sb.Len() > 0 {\n\t\t\tneedsGap = true\n\t\t}\n\t}\n\n\t// Make sure the name isn't empty\n\tif sb.Len() == 0 {\n\t\treturn \"_\"\n\t}\n\n\t// Note: An extension will be added to this base name, so there is no need to\n\t// avoid forbidden file names such as \"..\" since \".js\" is a valid file name.\n\treturn sb.String()\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/cache/cache.go",
    "content": "package cache\n\nimport (\n\t\"sync\"\n\n\t\"github.com/evanw/esbuild/internal/logger\"\n\t\"github.com/evanw/esbuild/internal/runtime\"\n)\n\n// This is a cache of the parsed contents of a set of files. The idea is to be\n// able to reuse the results of parsing between builds and make subsequent\n// builds faster by avoiding redundant parsing work. This only works if:\n//\n//   - The AST information in the cache must be considered immutable. There is\n//     no way to enforce this in Go, but please be disciplined about this. The\n//     ASTs are shared in between builds. Any information that must be mutated\n//     in the AST during a build must be done on a shallow clone of the data if\n//     the mutation happens after parsing (i.e. a clone that clones everything\n//     that will be mutated and shares only the parts that won't be mutated).\n//\n//   - The information in the cache must not depend at all on the contents of\n//     any file other than the file being cached. Invalidating an entry in the\n//     cache does not also invalidate any entries that depend on that file, so\n//     caching information that depends on other files can result in incorrect\n//     results due to reusing stale data. For example, do not \"bake in\" some\n//     value imported from another file.\n//\n//   - Cached ASTs must only be reused if the parsing options are identical\n//     between builds. For example, it would be bad if the AST parser depended\n//     on options inherited from a nearby \"package.json\" file but those options\n//     were not part of the cache key. Then the cached AST could incorrectly be\n//     reused even if the contents of that \"package.json\" file have changed.\ntype CacheSet struct {\n\tFSCache          FSCache\n\tCSSCache         CSSCache\n\tJSONCache        JSONCache\n\tJSCache          JSCache\n\tSourceIndexCache SourceIndexCache\n}\n\nfunc MakeCacheSet() *CacheSet {\n\treturn &CacheSet{\n\t\tSourceIndexCache: SourceIndexCache{\n\t\t\tglobEntries:     make(map[uint64]uint32),\n\t\t\tentries:         make(map[sourceIndexKey]uint32),\n\t\t\tnextSourceIndex: runtime.SourceIndex + 1,\n\t\t},\n\t\tFSCache: FSCache{\n\t\t\tentries: make(map[string]*fsEntry),\n\t\t},\n\t\tCSSCache: CSSCache{\n\t\t\tentries: make(map[logger.Path]*cssCacheEntry),\n\t\t},\n\t\tJSONCache: JSONCache{\n\t\t\tentries: make(map[logger.Path]*jsonCacheEntry),\n\t\t},\n\t\tJSCache: JSCache{\n\t\t\tentries: make(map[logger.Path]*jsCacheEntry),\n\t\t},\n\t}\n}\n\ntype SourceIndexCache struct {\n\tglobEntries     map[uint64]uint32\n\tentries         map[sourceIndexKey]uint32\n\tmutex           sync.Mutex\n\tnextSourceIndex uint32\n}\n\ntype SourceIndexKind uint8\n\nconst (\n\tSourceIndexNormal SourceIndexKind = iota\n\tSourceIndexJSStubForCSS\n)\n\ntype sourceIndexKey struct {\n\tpath logger.Path\n\tkind SourceIndexKind\n}\n\nfunc (c *SourceIndexCache) LenHint() uint32 {\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\n\t// Add some extra room at the end for a new file or two without reallocating\n\tconst someExtraRoom = 16\n\treturn c.nextSourceIndex + someExtraRoom\n}\n\nfunc (c *SourceIndexCache) Get(path logger.Path, kind SourceIndexKind) uint32 {\n\tkey := sourceIndexKey{path: path, kind: kind}\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\tif sourceIndex, ok := c.entries[key]; ok {\n\t\treturn sourceIndex\n\t}\n\tsourceIndex := c.nextSourceIndex\n\tc.nextSourceIndex++\n\tc.entries[key] = sourceIndex\n\treturn sourceIndex\n}\n\nfunc (c *SourceIndexCache) GetGlob(parentSourceIndex uint32, globIndex uint32) uint32 {\n\tkey := (uint64(parentSourceIndex) << 32) | uint64(globIndex)\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\tif sourceIndex, ok := c.globEntries[key]; ok {\n\t\treturn sourceIndex\n\t}\n\tsourceIndex := c.nextSourceIndex\n\tc.nextSourceIndex++\n\tc.globEntries[key] = sourceIndex\n\treturn sourceIndex\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/cache/cache_ast.go",
    "content": "package cache\n\nimport (\n\t\"sync\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_parser\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/js_parser\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\n// This cache intends to avoid unnecessarily re-parsing files in subsequent\n// builds. For a given path, parsing can be avoided if the contents of the file\n// and the options for the parser are the same as last time. Even if the\n// contents of the file are the same, the options for the parser may have\n// changed if they depend on some other file (\"package.json\" for example).\n//\n// This cache checks if the file contents have changed even though we have\n// the ability to detect if a file has changed on the file system by reading\n// its metadata. First of all, if the file contents are cached then they should\n// be the same pointer, which makes the comparison trivial. Also we want to\n// cache the AST for plugins in the common case that the plugin output stays\n// the same.\n\n////////////////////////////////////////////////////////////////////////////////\n// CSS\n\ntype CSSCache struct {\n\tentries map[logger.Path]*cssCacheEntry\n\tmutex   sync.Mutex\n}\n\ntype cssCacheEntry struct {\n\tsource  logger.Source\n\tmsgs    []logger.Msg\n\tast     css_ast.AST\n\toptions css_parser.Options\n}\n\nfunc (c *CSSCache) Parse(log logger.Log, source logger.Source, options css_parser.Options) css_ast.AST {\n\t// Check the cache\n\tentry := func() *cssCacheEntry {\n\t\tc.mutex.Lock()\n\t\tdefer c.mutex.Unlock()\n\t\treturn c.entries[source.KeyPath]\n\t}()\n\n\t// Cache hit\n\tif entry != nil && entry.source == source && entry.options.Equal(&options) {\n\t\tfor _, msg := range entry.msgs {\n\t\t\tlog.AddMsg(msg)\n\t\t}\n\t\treturn entry.ast\n\t}\n\n\t// Cache miss\n\ttempLog := logger.NewDeferLog(logger.DeferLogAll, log.Overrides)\n\tast := css_parser.Parse(tempLog, source, options)\n\tmsgs := tempLog.Done()\n\tfor _, msg := range msgs {\n\t\tlog.AddMsg(msg)\n\t}\n\n\t// Create the cache entry\n\tentry = &cssCacheEntry{\n\t\tsource:  source,\n\t\toptions: options,\n\t\tast:     ast,\n\t\tmsgs:    msgs,\n\t}\n\n\t// Save for next time\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\tc.entries[source.KeyPath] = entry\n\treturn ast\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// JSON\n\ntype JSONCache struct {\n\tentries map[logger.Path]*jsonCacheEntry\n\tmutex   sync.Mutex\n}\n\ntype jsonCacheEntry struct {\n\texpr    js_ast.Expr\n\tmsgs    []logger.Msg\n\tsource  logger.Source\n\toptions js_parser.JSONOptions\n\tok      bool\n}\n\nfunc (c *JSONCache) Parse(log logger.Log, source logger.Source, options js_parser.JSONOptions) (js_ast.Expr, bool) {\n\t// Check the cache\n\tentry := func() *jsonCacheEntry {\n\t\tc.mutex.Lock()\n\t\tdefer c.mutex.Unlock()\n\t\treturn c.entries[source.KeyPath]\n\t}()\n\n\t// Cache hit\n\tif entry != nil && entry.source == source && entry.options == options {\n\t\tfor _, msg := range entry.msgs {\n\t\t\tlog.AddMsg(msg)\n\t\t}\n\t\treturn entry.expr, entry.ok\n\t}\n\n\t// Cache miss\n\ttempLog := logger.NewDeferLog(logger.DeferLogAll, log.Overrides)\n\texpr, ok := js_parser.ParseJSON(tempLog, source, options)\n\tmsgs := tempLog.Done()\n\tfor _, msg := range msgs {\n\t\tlog.AddMsg(msg)\n\t}\n\n\t// Create the cache entry\n\tentry = &jsonCacheEntry{\n\t\tsource:  source,\n\t\toptions: options,\n\t\texpr:    expr,\n\t\tok:      ok,\n\t\tmsgs:    msgs,\n\t}\n\n\t// Save for next time\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\tc.entries[source.KeyPath] = entry\n\treturn expr, ok\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// JS\n\ntype JSCache struct {\n\tentries map[logger.Path]*jsCacheEntry\n\tmutex   sync.Mutex\n}\n\ntype jsCacheEntry struct {\n\tsource  logger.Source\n\tmsgs    []logger.Msg\n\toptions js_parser.Options\n\tast     js_ast.AST\n\tok      bool\n}\n\nfunc (c *JSCache) Parse(log logger.Log, source logger.Source, options js_parser.Options) (js_ast.AST, bool) {\n\t// Check the cache\n\tentry := func() *jsCacheEntry {\n\t\tc.mutex.Lock()\n\t\tdefer c.mutex.Unlock()\n\t\treturn c.entries[source.KeyPath]\n\t}()\n\n\t// Cache hit\n\tif entry != nil && entry.source == source && entry.options.Equal(&options) {\n\t\tfor _, msg := range entry.msgs {\n\t\t\tlog.AddMsg(msg)\n\t\t}\n\t\treturn entry.ast, entry.ok\n\t}\n\n\t// Cache miss\n\ttempLog := logger.NewDeferLog(logger.DeferLogAll, log.Overrides)\n\tast, ok := js_parser.Parse(tempLog, source, options)\n\tmsgs := tempLog.Done()\n\tfor _, msg := range msgs {\n\t\tlog.AddMsg(msg)\n\t}\n\n\t// Create the cache entry\n\tentry = &jsCacheEntry{\n\t\tsource:  source,\n\t\toptions: options,\n\t\tast:     ast,\n\t\tok:      ok,\n\t\tmsgs:    msgs,\n\t}\n\n\t// Save for next time\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\tc.entries[source.KeyPath] = entry\n\treturn ast, ok\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/cache/cache_fs.go",
    "content": "package cache\n\nimport (\n\t\"sync\"\n\n\t\"github.com/evanw/esbuild/internal/fs\"\n)\n\n// This cache uses information from the \"stat\" syscall to try to avoid re-\n// reading files from the file system during subsequent builds if the file\n// hasn't changed. The assumption is reading the file metadata is faster than\n// reading the file contents.\n\ntype FSCache struct {\n\tentries map[string]*fsEntry\n\tmutex   sync.Mutex\n}\n\ntype fsEntry struct {\n\tcontents       string\n\tmodKey         fs.ModKey\n\tisModKeyUsable bool\n}\n\nfunc (c *FSCache) ReadFile(fs fs.FS, path string) (contents string, canonicalError error, originalError error) {\n\tentry := func() *fsEntry {\n\t\tc.mutex.Lock()\n\t\tdefer c.mutex.Unlock()\n\t\treturn c.entries[path]\n\t}()\n\n\t// If the file's modification key hasn't changed since it was cached, assume\n\t// the contents of the file are also the same and skip reading the file.\n\tmodKey, modKeyErr := fs.ModKey(path)\n\tif entry != nil && entry.isModKeyUsable && modKeyErr == nil && entry.modKey == modKey {\n\t\treturn entry.contents, nil, nil\n\t}\n\n\tcontents, err, originalError := fs.ReadFile(path)\n\tif err != nil {\n\t\treturn \"\", err, originalError\n\t}\n\n\tc.mutex.Lock()\n\tdefer c.mutex.Unlock()\n\tc.entries[path] = &fsEntry{\n\t\tcontents:       contents,\n\t\tmodKey:         modKey,\n\t\tisModKeyUsable: modKeyErr == nil,\n\t}\n\treturn contents, nil, nil\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/compat/compat.go",
    "content": "package compat\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n)\n\ntype v struct {\n\tmajor uint16\n\tminor uint8\n\tpatch uint8\n}\n\ntype Semver struct {\n\t// \"1.2.3-alpha\" => { Parts: {1, 2, 3}, PreRelease: \"-alpha\" }\n\tParts      []int\n\tPreRelease string\n}\n\nfunc (v Semver) String() string {\n\tb := strings.Builder{}\n\tfor _, part := range v.Parts {\n\t\tif b.Len() > 0 {\n\t\t\tb.WriteRune('.')\n\t\t}\n\t\tb.WriteString(strconv.Itoa(part))\n\t}\n\tb.WriteString(v.PreRelease)\n\treturn b.String()\n}\n\n// Returns <0 if \"a < b\"\n// Returns 0 if \"a == b\"\n// Returns >0 if \"a > b\"\nfunc compareVersions(a v, b Semver) int {\n\tdiff := int(a.major)\n\tif len(b.Parts) > 0 {\n\t\tdiff -= b.Parts[0]\n\t}\n\tif diff == 0 {\n\t\tdiff = int(a.minor)\n\t\tif len(b.Parts) > 1 {\n\t\t\tdiff -= b.Parts[1]\n\t\t}\n\t}\n\tif diff == 0 {\n\t\tdiff = int(a.patch)\n\t\tif len(b.Parts) > 2 {\n\t\t\tdiff -= b.Parts[2]\n\t\t}\n\t}\n\tif diff == 0 && len(b.PreRelease) != 0 {\n\t\treturn 1 // \"1.0.0\" > \"1.0.0-alpha\"\n\t}\n\treturn diff\n}\n\n// The start is inclusive and the end is exclusive\ntype versionRange struct {\n\tstart v\n\tend   v // Use 0.0.0 for \"no end\"\n}\n\nfunc isVersionSupported(ranges []versionRange, version Semver) bool {\n\tfor _, r := range ranges {\n\t\tif compareVersions(r.start, version) <= 0 && (r.end == (v{}) || compareVersions(r.end, version) > 0) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc SymbolFeature(kind ast.SymbolKind) JSFeature {\n\tswitch kind {\n\tcase ast.SymbolPrivateField:\n\t\treturn ClassPrivateField\n\tcase ast.SymbolPrivateMethod:\n\t\treturn ClassPrivateMethod\n\tcase ast.SymbolPrivateGet, ast.SymbolPrivateSet, ast.SymbolPrivateGetSetPair:\n\t\treturn ClassPrivateAccessor\n\tcase ast.SymbolPrivateStaticField:\n\t\treturn ClassPrivateStaticField\n\tcase ast.SymbolPrivateStaticMethod:\n\t\treturn ClassPrivateStaticMethod\n\tcase ast.SymbolPrivateStaticGet, ast.SymbolPrivateStaticSet, ast.SymbolPrivateStaticGetSetPair:\n\t\treturn ClassPrivateStaticAccessor\n\tdefault:\n\t\treturn 0\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/compat/css_table.go",
    "content": "// This file was automatically generated by \"css_table.ts\"\n\npackage compat\n\nimport (\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n)\n\ntype CSSFeature uint16\n\nconst (\n\tColorFunctions CSSFeature = 1 << iota\n\tGradientDoublePosition\n\tGradientInterpolation\n\tGradientMidpoints\n\tHWB\n\tHexRGBA\n\tInlineStyle\n\tInsetProperty\n\tIsPseudoClass\n\tMediaRange\n\tModern_RGB_HSL\n\tNesting\n\tRebeccaPurple\n)\n\nvar StringToCSSFeature = map[string]CSSFeature{\n\t\"color-functions\":          ColorFunctions,\n\t\"gradient-double-position\": GradientDoublePosition,\n\t\"gradient-interpolation\":   GradientInterpolation,\n\t\"gradient-midpoints\":       GradientMidpoints,\n\t\"hwb\":                      HWB,\n\t\"hex-rgba\":                 HexRGBA,\n\t\"inline-style\":             InlineStyle,\n\t\"inset-property\":           InsetProperty,\n\t\"is-pseudo-class\":          IsPseudoClass,\n\t\"media-range\":              MediaRange,\n\t\"modern-rgb-hsl\":           Modern_RGB_HSL,\n\t\"nesting\":                  Nesting,\n\t\"rebecca-purple\":           RebeccaPurple,\n}\n\nfunc (features CSSFeature) Has(feature CSSFeature) bool {\n\treturn (features & feature) != 0\n}\n\nfunc (features CSSFeature) ApplyOverrides(overrides CSSFeature, mask CSSFeature) CSSFeature {\n\treturn (features & ^mask) | (overrides & mask)\n}\n\nvar cssTable = map[CSSFeature]map[Engine][]versionRange{\n\tColorFunctions: {\n\t\tChrome:  {{start: v{111, 0, 0}}},\n\t\tEdge:    {{start: v{111, 0, 0}}},\n\t\tFirefox: {{start: v{113, 0, 0}}},\n\t\tIOS:     {{start: v{15, 4, 0}}},\n\t\tOpera:   {{start: v{97, 0, 0}}},\n\t\tSafari:  {{start: v{15, 4, 0}}},\n\t},\n\tGradientDoublePosition: {\n\t\tChrome:  {{start: v{72, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tFirefox: {{start: v{83, 0, 0}}},\n\t\tIOS:     {{start: v{12, 2, 0}}},\n\t\tOpera:   {{start: v{60, 0, 0}}},\n\t\tSafari:  {{start: v{12, 1, 0}}},\n\t},\n\tGradientInterpolation: {\n\t\tChrome: {{start: v{111, 0, 0}}},\n\t\tEdge:   {{start: v{111, 0, 0}}},\n\t\tIOS:    {{start: v{16, 2, 0}}},\n\t\tOpera:  {{start: v{97, 0, 0}}},\n\t\tSafari: {{start: v{16, 2, 0}}},\n\t},\n\tGradientMidpoints: {\n\t\tChrome:  {{start: v{40, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tFirefox: {{start: v{36, 0, 0}}},\n\t\tIOS:     {{start: v{7, 0, 0}}},\n\t\tOpera:   {{start: v{27, 0, 0}}},\n\t\tSafari:  {{start: v{7, 0, 0}}},\n\t},\n\tHWB: {\n\t\tChrome:  {{start: v{101, 0, 0}}},\n\t\tEdge:    {{start: v{101, 0, 0}}},\n\t\tFirefox: {{start: v{96, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tOpera:   {{start: v{87, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tHexRGBA: {\n\t\tChrome:  {{start: v{62, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tFirefox: {{start: v{49, 0, 0}}},\n\t\tIOS:     {{start: v{9, 3, 0}}},\n\t\tOpera:   {{start: v{49, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tInlineStyle: {},\n\tInsetProperty: {\n\t\tChrome:  {{start: v{87, 0, 0}}},\n\t\tEdge:    {{start: v{87, 0, 0}}},\n\t\tFirefox: {{start: v{66, 0, 0}}},\n\t\tIOS:     {{start: v{14, 5, 0}}},\n\t\tOpera:   {{start: v{73, 0, 0}}},\n\t\tSafari:  {{start: v{14, 1, 0}}},\n\t},\n\tIsPseudoClass: {\n\t\tChrome:  {{start: v{88, 0, 0}}},\n\t\tEdge:    {{start: v{88, 0, 0}}},\n\t\tFirefox: {{start: v{78, 0, 0}}},\n\t\tIOS:     {{start: v{14, 0, 0}}},\n\t\tOpera:   {{start: v{75, 0, 0}}},\n\t\tSafari:  {{start: v{14, 0, 0}}},\n\t},\n\tMediaRange: {\n\t\tChrome:  {{start: v{104, 0, 0}}},\n\t\tEdge:    {{start: v{104, 0, 0}}},\n\t\tFirefox: {{start: v{63, 0, 0}}},\n\t\tIOS:     {{start: v{16, 4, 0}}},\n\t\tOpera:   {{start: v{91, 0, 0}}},\n\t\tSafari:  {{start: v{16, 4, 0}}},\n\t},\n\tModern_RGB_HSL: {\n\t\tChrome:  {{start: v{66, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tFirefox: {{start: v{52, 0, 0}}},\n\t\tIOS:     {{start: v{12, 2, 0}}},\n\t\tOpera:   {{start: v{53, 0, 0}}},\n\t\tSafari:  {{start: v{12, 1, 0}}},\n\t},\n\tNesting: {\n\t\tChrome:  {{start: v{120, 0, 0}}},\n\t\tEdge:    {{start: v{120, 0, 0}}},\n\t\tFirefox: {{start: v{117, 0, 0}}},\n\t\tIOS:     {{start: v{17, 2, 0}}},\n\t\tOpera:   {{start: v{106, 0, 0}}},\n\t\tSafari:  {{start: v{17, 2, 0}}},\n\t},\n\tRebeccaPurple: {\n\t\tChrome:  {{start: v{38, 0, 0}}},\n\t\tEdge:    {{start: v{12, 0, 0}}},\n\t\tFirefox: {{start: v{33, 0, 0}}},\n\t\tIE:      {{start: v{11, 0, 0}}},\n\t\tIOS:     {{start: v{8, 0, 0}}},\n\t\tOpera:   {{start: v{25, 0, 0}}},\n\t\tSafari:  {{start: v{9, 0, 0}}},\n\t},\n}\n\n// Return all features that are not available in at least one environment\nfunc UnsupportedCSSFeatures(constraints map[Engine]Semver) (unsupported CSSFeature) {\n\tfor feature, engines := range cssTable {\n\t\tif feature == InlineStyle {\n\t\t\tcontinue // This is purely user-specified\n\t\t}\n\t\tfor engine, version := range constraints {\n\t\t\tif !engine.IsBrowser() {\n\t\t\t\t// Specifying \"--target=es2020\" shouldn't affect CSS\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif versionRanges, ok := engines[engine]; !ok || !isVersionSupported(versionRanges, version) {\n\t\t\t\tunsupported |= feature\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\ntype CSSPrefix uint8\n\nconst (\n\tKhtmlPrefix CSSPrefix = 1 << iota\n\tMozPrefix\n\tMsPrefix\n\tOPrefix\n\tWebkitPrefix\n\n\tNoPrefix CSSPrefix = 0\n)\n\ntype prefixData struct {\n\t// Note: In some cases, earlier versions did not require a prefix but later\n\t// ones do. This is the case for Microsoft Edge for example, which switched\n\t// the underlying browser engine from a custom one to the one from Chrome.\n\t// However, we assume that users specifying a browser version for CSS mean\n\t// \"works in this version or newer\", so we still add a prefix when a target\n\t// is an old Edge version.\n\tengine        Engine\n\twithoutPrefix v\n\tprefix        CSSPrefix\n}\n\nvar cssPrefixTable = map[css_ast.D][]prefixData{\n\tcss_ast.DAppearance: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{84, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{84, 0, 0}},\n\t\t{engine: Firefox, prefix: MozPrefix, withoutPrefix: v{80, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{73, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DBackdropFilter: {\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{18, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{18, 0, 0}},\n\t},\n\tcss_ast.DBackgroundClip: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: MsPrefix, withoutPrefix: v{15, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{106, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{5, 0, 0}},\n\t},\n\tcss_ast.DBoxDecorationBreak: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{130, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{130, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{116, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DClipPath: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{55, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{13, 0, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{42, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{13, 1, 0}},\n\t},\n\tcss_ast.DFontKerning: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{33, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{12, 0, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{20, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{9, 1, 0}},\n\t},\n\tcss_ast.DHeight: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Firefox, prefix: WebkitPrefix},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{122, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DHyphens: {\n\t\t{engine: Edge, prefix: MsPrefix, withoutPrefix: v{79, 0, 0}},\n\t\t{engine: Firefox, prefix: MozPrefix, withoutPrefix: v{43, 0, 0}},\n\t\t{engine: IE, prefix: MsPrefix},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{17, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{17, 0, 0}},\n\t},\n\tcss_ast.DInitialLetter: {\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DMask: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{106, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DMaskComposite: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{106, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DMaskImage: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DMaskOrigin: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{106, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DMaskPosition: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{106, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DMaskRepeat: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{106, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DMaskSize: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{120, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{106, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DMaxHeight: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{122, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DMaxWidth: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{122, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DMinHeight: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{122, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DMinWidth: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{122, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DPosition: {\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{13, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{13, 0, 0}},\n\t},\n\tcss_ast.DPrintColorAdjust: {\n\t\t{engine: Chrome, prefix: WebkitPrefix},\n\t\t{engine: Edge, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{15, 4, 0}},\n\t},\n\tcss_ast.DTabSize: {\n\t\t{engine: Firefox, prefix: MozPrefix, withoutPrefix: v{91, 0, 0}},\n\t\t{engine: Opera, prefix: OPrefix, withoutPrefix: v{15, 0, 0}},\n\t},\n\tcss_ast.DTextDecorationColor: {\n\t\t{engine: Firefox, prefix: MozPrefix, withoutPrefix: v{36, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{12, 2, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{12, 1, 0}},\n\t},\n\tcss_ast.DTextDecorationLine: {\n\t\t{engine: Firefox, prefix: MozPrefix, withoutPrefix: v{36, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{12, 2, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{12, 1, 0}},\n\t},\n\tcss_ast.DTextDecorationSkip: {\n\t\t{engine: IOS, prefix: WebkitPrefix, withoutPrefix: v{12, 2, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{12, 1, 0}},\n\t},\n\tcss_ast.DTextEmphasisColor: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{99, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{99, 0, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{85, 0, 0}},\n\t},\n\tcss_ast.DTextEmphasisPosition: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{99, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{99, 0, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{85, 0, 0}},\n\t},\n\tcss_ast.DTextEmphasisStyle: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{99, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{99, 0, 0}},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{85, 0, 0}},\n\t},\n\tcss_ast.DTextOrientation: {\n\t\t{engine: Safari, prefix: WebkitPrefix, withoutPrefix: v{14, 0, 0}},\n\t},\n\tcss_ast.DTextSizeAdjust: {\n\t\t{engine: Edge, prefix: MsPrefix, withoutPrefix: v{79, 0, 0}},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DUserSelect: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{54, 0, 0}},\n\t\t{engine: Edge, prefix: MsPrefix, withoutPrefix: v{79, 0, 0}},\n\t\t{engine: Firefox, prefix: MozPrefix, withoutPrefix: v{69, 0, 0}},\n\t\t{engine: IE, prefix: MsPrefix},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{41, 0, 0}},\n\t\t{engine: Safari, prefix: KhtmlPrefix, withoutPrefix: v{3, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n\tcss_ast.DWidth: {\n\t\t{engine: Chrome, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Edge, prefix: WebkitPrefix, withoutPrefix: v{138, 0, 0}},\n\t\t{engine: Firefox, prefix: WebkitPrefix},\n\t\t{engine: IOS, prefix: WebkitPrefix},\n\t\t{engine: Opera, prefix: WebkitPrefix, withoutPrefix: v{122, 0, 0}},\n\t\t{engine: Safari, prefix: WebkitPrefix},\n\t},\n}\n\nfunc CSSPrefixData(constraints map[Engine]Semver) (entries map[css_ast.D]CSSPrefix) {\n\tfor property, items := range cssPrefixTable {\n\t\tprefixes := NoPrefix\n\t\tfor engine, version := range constraints {\n\t\t\tif !engine.IsBrowser() {\n\t\t\t\t// Specifying \"--target=es2020\" shouldn't affect CSS\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tfor _, item := range items {\n\t\t\t\tif item.engine == engine && (item.withoutPrefix == v{} || compareVersions(item.withoutPrefix, version) > 0) {\n\t\t\t\t\tprefixes |= item.prefix\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif prefixes != NoPrefix {\n\t\t\tif entries == nil {\n\t\t\t\tentries = make(map[css_ast.D]CSSPrefix)\n\t\t\t}\n\t\t\tentries[property] = prefixes\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/compat/js_table.go",
    "content": "// This file was automatically generated by \"js_table.ts\"\n\npackage compat\n\ntype Engine uint8\n\nconst (\n\tChrome Engine = iota\n\tDeno\n\tEdge\n\tES\n\tFirefox\n\tHermes\n\tIE\n\tIOS\n\tNode\n\tOpera\n\tRhino\n\tSafari\n)\n\nfunc (e Engine) String() string {\n\tswitch e {\n\tcase Chrome:\n\t\treturn \"chrome\"\n\tcase Deno:\n\t\treturn \"deno\"\n\tcase Edge:\n\t\treturn \"edge\"\n\tcase ES:\n\t\treturn \"es\"\n\tcase Firefox:\n\t\treturn \"firefox\"\n\tcase Hermes:\n\t\treturn \"hermes\"\n\tcase IE:\n\t\treturn \"ie\"\n\tcase IOS:\n\t\treturn \"ios\"\n\tcase Node:\n\t\treturn \"node\"\n\tcase Opera:\n\t\treturn \"opera\"\n\tcase Rhino:\n\t\treturn \"rhino\"\n\tcase Safari:\n\t\treturn \"safari\"\n\t}\n\treturn \"\"\n}\n\nfunc (e Engine) IsBrowser() bool {\n\tswitch e {\n\tcase Chrome, Edge, Firefox, IE, IOS, Opera, Safari:\n\t\treturn true\n\t}\n\treturn false\n}\n\ntype JSFeature uint64\n\nconst (\n\tArbitraryModuleNamespaceNames JSFeature = 1 << iota\n\tArraySpread\n\tArrow\n\tAsyncAwait\n\tAsyncGenerator\n\tBigint\n\tClass\n\tClassField\n\tClassPrivateAccessor\n\tClassPrivateBrandCheck\n\tClassPrivateField\n\tClassPrivateMethod\n\tClassPrivateStaticAccessor\n\tClassPrivateStaticField\n\tClassPrivateStaticMethod\n\tClassStaticBlocks\n\tClassStaticField\n\tConstAndLet\n\tDecorators\n\tDefaultArgument\n\tDestructuring\n\tDynamicImport\n\tExponentOperator\n\tExportStarAs\n\tForAwait\n\tForOf\n\tFromBase64\n\tFunctionNameConfigurable\n\tFunctionOrClassPropertyAccess\n\tGenerator\n\tHashbang\n\tImportAssertions\n\tImportAttributes\n\tImportDefer\n\tImportMeta\n\tImportSource\n\tInlineScript\n\tLogicalAssignment\n\tNestedRestBinding\n\tNewTarget\n\tNodeColonPrefixImport\n\tNodeColonPrefixRequire\n\tNullishCoalescing\n\tObjectAccessors\n\tObjectExtensions\n\tObjectRestSpread\n\tOptionalCatchBinding\n\tOptionalChain\n\tRegexpDotAllFlag\n\tRegexpLookbehindAssertions\n\tRegexpMatchIndices\n\tRegexpNamedCaptureGroups\n\tRegexpSetNotation\n\tRegexpStickyAndUnicodeFlags\n\tRegexpUnicodePropertyEscapes\n\tRestArgument\n\tTemplateLiteral\n\tTopLevelAwait\n\tTypeofExoticObjectIsObject\n\tUnicodeEscapes\n\tUsing\n)\n\nvar StringToJSFeature = map[string]JSFeature{\n\t\"arbitrary-module-namespace-names\":  ArbitraryModuleNamespaceNames,\n\t\"array-spread\":                      ArraySpread,\n\t\"arrow\":                             Arrow,\n\t\"async-await\":                       AsyncAwait,\n\t\"async-generator\":                   AsyncGenerator,\n\t\"bigint\":                            Bigint,\n\t\"class\":                             Class,\n\t\"class-field\":                       ClassField,\n\t\"class-private-accessor\":            ClassPrivateAccessor,\n\t\"class-private-brand-check\":         ClassPrivateBrandCheck,\n\t\"class-private-field\":               ClassPrivateField,\n\t\"class-private-method\":              ClassPrivateMethod,\n\t\"class-private-static-accessor\":     ClassPrivateStaticAccessor,\n\t\"class-private-static-field\":        ClassPrivateStaticField,\n\t\"class-private-static-method\":       ClassPrivateStaticMethod,\n\t\"class-static-blocks\":               ClassStaticBlocks,\n\t\"class-static-field\":                ClassStaticField,\n\t\"const-and-let\":                     ConstAndLet,\n\t\"decorators\":                        Decorators,\n\t\"default-argument\":                  DefaultArgument,\n\t\"destructuring\":                     Destructuring,\n\t\"dynamic-import\":                    DynamicImport,\n\t\"exponent-operator\":                 ExponentOperator,\n\t\"export-star-as\":                    ExportStarAs,\n\t\"for-await\":                         ForAwait,\n\t\"for-of\":                            ForOf,\n\t\"from-base64\":                       FromBase64,\n\t\"function-name-configurable\":        FunctionNameConfigurable,\n\t\"function-or-class-property-access\": FunctionOrClassPropertyAccess,\n\t\"generator\":                         Generator,\n\t\"hashbang\":                          Hashbang,\n\t\"import-assertions\":                 ImportAssertions,\n\t\"import-attributes\":                 ImportAttributes,\n\t\"import-defer\":                      ImportDefer,\n\t\"import-meta\":                       ImportMeta,\n\t\"import-source\":                     ImportSource,\n\t\"inline-script\":                     InlineScript,\n\t\"logical-assignment\":                LogicalAssignment,\n\t\"nested-rest-binding\":               NestedRestBinding,\n\t\"new-target\":                        NewTarget,\n\t\"node-colon-prefix-import\":          NodeColonPrefixImport,\n\t\"node-colon-prefix-require\":         NodeColonPrefixRequire,\n\t\"nullish-coalescing\":                NullishCoalescing,\n\t\"object-accessors\":                  ObjectAccessors,\n\t\"object-extensions\":                 ObjectExtensions,\n\t\"object-rest-spread\":                ObjectRestSpread,\n\t\"optional-catch-binding\":            OptionalCatchBinding,\n\t\"optional-chain\":                    OptionalChain,\n\t\"regexp-dot-all-flag\":               RegexpDotAllFlag,\n\t\"regexp-lookbehind-assertions\":      RegexpLookbehindAssertions,\n\t\"regexp-match-indices\":              RegexpMatchIndices,\n\t\"regexp-named-capture-groups\":       RegexpNamedCaptureGroups,\n\t\"regexp-set-notation\":               RegexpSetNotation,\n\t\"regexp-sticky-and-unicode-flags\":   RegexpStickyAndUnicodeFlags,\n\t\"regexp-unicode-property-escapes\":   RegexpUnicodePropertyEscapes,\n\t\"rest-argument\":                     RestArgument,\n\t\"template-literal\":                  TemplateLiteral,\n\t\"top-level-await\":                   TopLevelAwait,\n\t\"typeof-exotic-object-is-object\":    TypeofExoticObjectIsObject,\n\t\"unicode-escapes\":                   UnicodeEscapes,\n\t\"using\":                             Using,\n}\n\nfunc (features JSFeature) Has(feature JSFeature) bool {\n\treturn (features & feature) != 0\n}\n\nfunc (features JSFeature) ApplyOverrides(overrides JSFeature, mask JSFeature) JSFeature {\n\treturn (features & ^mask) | (overrides & mask)\n}\n\nvar jsTable = map[JSFeature]map[Engine][]versionRange{\n\tArbitraryModuleNamespaceNames: {\n\t\tChrome:  {{start: v{90, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{87, 0, 0}}},\n\t\tIOS:     {{start: v{14, 5, 0}}},\n\t\tNode:    {{start: v{16, 0, 0}}},\n\t\tSafari:  {{start: v{14, 1, 0}}},\n\t},\n\tArraySpread: {\n\t\t// Note: The latest version of \"IE\" failed 15 tests including: spread syntax for iterable objects: spreading non-iterables is a runtime error\n\t\t// Note: The latest version of \"Rhino\" failed 15 tests including: spread syntax for iterable objects: spreading non-iterables is a runtime error\n\t\tChrome:  {{start: v{46, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{13, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{36, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{5, 0, 0}}},\n\t\tOpera:   {{start: v{33, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tArrow: {\n\t\t// Note: The latest version of \"Hermes\" failed 3 tests including: arrow functions: lexical \"super\" binding in constructors\n\t\t// Note: The latest version of \"IE\" failed 13 tests including: arrow functions: \"this\" unchanged by call or apply\n\t\t// Note: The latest version of \"Rhino\" failed 3 tests including: arrow functions: lexical \"new.target\" binding\n\t\tChrome:  {{start: v{49, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{13, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{45, 0, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{36, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tAsyncAwait: {\n\t\t// Note: The latest version of \"Hermes\" failed 4 tests including: async functions: async arrow functions\n\t\t// Note: The latest version of \"IE\" failed 16 tests including: async functions: async arrow functions\n\t\t// Note: The latest version of \"Rhino\" failed 16 tests including: async functions: async arrow functions\n\t\tChrome:  {{start: v{55, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{15, 0, 0}}},\n\t\tES:      {{start: v{2017, 0, 0}}},\n\t\tFirefox: {{start: v{52, 0, 0}}},\n\t\tIOS:     {{start: v{11, 0, 0}}},\n\t\tNode:    {{start: v{7, 6, 0}}},\n\t\tOpera:   {{start: v{42, 0, 0}}},\n\t\tSafari:  {{start: v{11, 0, 0}}},\n\t},\n\tAsyncGenerator: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: Asynchronous Iterators: async generators\n\t\t// Note: The latest version of \"IE\" failed this test: Asynchronous Iterators: async generators\n\t\t// Note: The latest version of \"Rhino\" failed this test: Asynchronous Iterators: async generators\n\t\tChrome:  {{start: v{63, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2018, 0, 0}}},\n\t\tFirefox: {{start: v{57, 0, 0}}},\n\t\tIOS:     {{start: v{12, 0, 0}}},\n\t\tNode:    {{start: v{10, 0, 0}}},\n\t\tOpera:   {{start: v{50, 0, 0}}},\n\t\tSafari:  {{start: v{12, 0, 0}}},\n\t},\n\tBigint: {\n\t\t// Note: The latest version of \"IE\" failed this test: BigInt: basic functionality\n\t\tChrome:  {{start: v{67, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2020, 0, 0}}},\n\t\tFirefox: {{start: v{68, 0, 0}}},\n\t\tHermes:  {{start: v{0, 12, 0}}},\n\t\tIOS:     {{start: v{14, 0, 0}}},\n\t\tNode:    {{start: v{10, 4, 0}}},\n\t\tOpera:   {{start: v{54, 0, 0}}},\n\t\tRhino:   {{start: v{1, 7, 14}}},\n\t\tSafari:  {{start: v{14, 0, 0}}},\n\t},\n\tClass: {\n\t\t// Note: The latest version of \"Hermes\" failed 24 tests including: class: accessor properties\n\t\t// Note: The latest version of \"IE\" failed 24 tests including: class: accessor properties\n\t\t// Note: The latest version of \"Rhino\" failed 24 tests including: class: accessor properties\n\t\tChrome:  {{start: v{49, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{13, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{45, 0, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{36, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tClassField: {\n\t\t// Note: The latest version of \"Hermes\" failed 2 tests including: instance class fields: computed instance class fields\n\t\t// Note: The latest version of \"IE\" failed 2 tests including: instance class fields: computed instance class fields\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: instance class fields: computed instance class fields\n\t\tChrome:  {{start: v{73, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{69, 0, 0}}},\n\t\tIOS:     {{start: v{14, 0, 0}}},\n\t\tNode:    {{start: v{12, 0, 0}}},\n\t\tOpera:   {{start: v{60, 0, 0}}},\n\t\tSafari:  {{start: v{14, 0, 0}}},\n\t},\n\tClassPrivateAccessor: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: private class methods: private accessor properties\n\t\t// Note: The latest version of \"IE\" failed this test: private class methods: private accessor properties\n\t\t// Note: The latest version of \"Rhino\" failed this test: private class methods: private accessor properties\n\t\tChrome:  {{start: v{84, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{84, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{90, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tNode:    {{start: v{14, 6, 0}}},\n\t\tOpera:   {{start: v{70, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tClassPrivateBrandCheck: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: Ergonomic brand checks for private fields\n\t\t// Note: The latest version of \"IE\" failed this test: Ergonomic brand checks for private fields\n\t\t// Note: The latest version of \"Rhino\" failed this test: Ergonomic brand checks for private fields\n\t\tChrome:  {{start: v{91, 0, 0}}},\n\t\tDeno:    {{start: v{1, 9, 0}}},\n\t\tEdge:    {{start: v{91, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{90, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tNode:    {{start: v{16, 4, 0}}},\n\t\tOpera:   {{start: v{77, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tClassPrivateField: {\n\t\t// Note: The latest version of \"Hermes\" failed 4 tests including: instance class fields: optional deep private instance class fields access\n\t\t// Note: The latest version of \"IE\" failed 4 tests including: instance class fields: optional deep private instance class fields access\n\t\t// Note: The latest version of \"Rhino\" failed 4 tests including: instance class fields: optional deep private instance class fields access\n\t\tChrome:  {{start: v{84, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{84, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{90, 0, 0}}},\n\t\tIOS:     {{start: v{14, 5, 0}}},\n\t\tNode:    {{start: v{14, 6, 0}}},\n\t\tOpera:   {{start: v{70, 0, 0}}},\n\t\tSafari:  {{start: v{14, 1, 0}}},\n\t},\n\tClassPrivateMethod: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: private class methods: private instance methods\n\t\t// Note: The latest version of \"IE\" failed this test: private class methods: private instance methods\n\t\t// Note: The latest version of \"Rhino\" failed this test: private class methods: private instance methods\n\t\tChrome:  {{start: v{84, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{84, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{90, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tNode:    {{start: v{14, 6, 0}}},\n\t\tOpera:   {{start: v{70, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tClassPrivateStaticAccessor: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: private class methods: private static accessor properties\n\t\t// Note: The latest version of \"IE\" failed this test: private class methods: private static accessor properties\n\t\t// Note: The latest version of \"Rhino\" failed this test: private class methods: private static accessor properties\n\t\tChrome:  {{start: v{84, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{84, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{90, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tNode:    {{start: v{14, 6, 0}}},\n\t\tOpera:   {{start: v{70, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tClassPrivateStaticField: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: static class fields: private static class fields\n\t\t// Note: The latest version of \"IE\" failed this test: static class fields: private static class fields\n\t\t// Note: The latest version of \"Rhino\" failed this test: static class fields: private static class fields\n\t\tChrome:  {{start: v{74, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{90, 0, 0}}},\n\t\tIOS:     {{start: v{14, 5, 0}}},\n\t\tNode:    {{start: v{12, 0, 0}}},\n\t\tOpera:   {{start: v{62, 0, 0}}},\n\t\tSafari:  {{start: v{14, 1, 0}}},\n\t},\n\tClassPrivateStaticMethod: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: private class methods: private static methods\n\t\t// Note: The latest version of \"IE\" failed this test: private class methods: private static methods\n\t\t// Note: The latest version of \"Rhino\" failed this test: private class methods: private static methods\n\t\tChrome:  {{start: v{84, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{84, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{90, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tNode:    {{start: v{14, 6, 0}}},\n\t\tOpera:   {{start: v{70, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tClassStaticBlocks: {\n\t\tChrome:  {{start: v{91, 0, 0}}},\n\t\tDeno:    {{start: v{1, 14, 0}}},\n\t\tEdge:    {{start: v{94, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{93, 0, 0}}},\n\t\tIOS:     {{start: v{16, 4, 0}}},\n\t\tNode:    {{start: v{16, 11, 0}}},\n\t\tOpera:   {{start: v{80, 0, 0}}},\n\t\tSafari:  {{start: v{16, 4, 0}}},\n\t},\n\tClassStaticField: {\n\t\t// Note: The latest version of \"Hermes\" failed 2 tests including: static class fields: computed static class fields\n\t\t// Note: The latest version of \"IE\" failed 2 tests including: static class fields: computed static class fields\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: static class fields: computed static class fields\n\t\tChrome:  {{start: v{73, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{75, 0, 0}}},\n\t\tIOS:     {{start: v{14, 5, 0}}},\n\t\tNode:    {{start: v{12, 0, 0}}},\n\t\tOpera:   {{start: v{60, 0, 0}}},\n\t\tSafari:  {{start: v{14, 1, 0}}},\n\t},\n\tConstAndLet: {\n\t\t// Note: The latest version of \"Hermes\" failed 20 tests including: const: for loop statement scope\n\t\t// Note: The latest version of \"IE\" failed 6 tests including: const: for-in loop iteration scope\n\t\t// Note: The latest version of \"Rhino\" failed 22 tests including: const: cannot be in statements\n\t\tChrome:  {{start: v{49, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{14, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{51, 0, 0}}},\n\t\tIOS:     {{start: v{11, 0, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{36, 0, 0}}},\n\t\tSafari:  {{start: v{11, 0, 0}}},\n\t},\n\tDecorators: {},\n\tDefaultArgument: {\n\t\t// Note: The latest version of \"Hermes\" failed 2 tests including: default function parameters: separate scope\n\t\t// Note: The latest version of \"IE\" failed 7 tests including: default function parameters: arguments object interaction\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: default function parameters: separate scope\n\t\tChrome:  {{start: v{49, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{14, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{53, 0, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{36, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tDestructuring: {\n\t\t// Note: The latest version of \"Hermes\" failed 3 tests including: destructuring, declarations: defaults, let temporal dead zone\n\t\t// Note: The latest version of \"IE\" failed 71 tests including: destructuring, assignment: chained iterable destructuring\n\t\t// Note: The latest version of \"Rhino\" failed 28 tests including: destructuring, assignment: computed properties\n\t\tChrome:  {{start: v{51, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{18, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{53, 0, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{6, 5, 0}}},\n\t\tOpera:   {{start: v{38, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tDynamicImport: {\n\t\tChrome:  {{start: v{63, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{67, 0, 0}}},\n\t\tIOS:     {{start: v{11, 0, 0}}},\n\t\tNode:    {{start: v{12, 20, 0}, end: v{13, 0, 0}}, {start: v{13, 2, 0}}},\n\t\tOpera:   {{start: v{50, 0, 0}}},\n\t\tSafari:  {{start: v{11, 1, 0}}},\n\t},\n\tExponentOperator: {\n\t\t// Note: The latest version of \"IE\" failed 3 tests including: exponentiation (**) operator: assignment\n\t\tChrome:  {{start: v{52, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{14, 0, 0}}},\n\t\tES:      {{start: v{2016, 0, 0}}},\n\t\tFirefox: {{start: v{52, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{10, 3, 0}}},\n\t\tNode:    {{start: v{7, 0, 0}}},\n\t\tOpera:   {{start: v{39, 0, 0}}},\n\t\tRhino:   {{start: v{1, 7, 14}}},\n\t\tSafari:  {{start: v{10, 1, 0}}},\n\t},\n\tExportStarAs: {\n\t\tChrome:  {{start: v{72, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2020, 0, 0}}},\n\t\tFirefox: {{start: v{80, 0, 0}}},\n\t\tIOS:     {{start: v{14, 5, 0}}},\n\t\tNode:    {{start: v{13, 2, 0}}},\n\t\tOpera:   {{start: v{60, 0, 0}}},\n\t\tSafari:  {{start: v{14, 1, 0}}},\n\t},\n\tForAwait: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: Asynchronous Iterators: for-await-of loops\n\t\t// Note: The latest version of \"IE\" failed this test: Asynchronous Iterators: for-await-of loops\n\t\t// Note: The latest version of \"Rhino\" failed this test: Asynchronous Iterators: for-await-of loops\n\t\tChrome:  {{start: v{63, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2018, 0, 0}}},\n\t\tFirefox: {{start: v{57, 0, 0}}},\n\t\tIOS:     {{start: v{12, 0, 0}}},\n\t\tNode:    {{start: v{10, 0, 0}}},\n\t\tOpera:   {{start: v{50, 0, 0}}},\n\t\tSafari:  {{start: v{12, 0, 0}}},\n\t},\n\tForOf: {\n\t\t// Note: The latest version of \"IE\" failed 9 tests including: for..of loops: iterator closing, break\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: for..of loops: iterator closing, break\n\t\tChrome:  {{start: v{51, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{15, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{53, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{6, 5, 0}}},\n\t\tOpera:   {{start: v{38, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tFromBase64: {\n\t\tChrome:  {{start: v{140, 0, 0}}},\n\t\tDeno:    {{start: v{2, 5, 0}}},\n\t\tEdge:    {{start: v{140, 0, 0}}},\n\t\tFirefox: {{start: v{133, 0, 0}}},\n\t\tIOS:     {{start: v{18, 2, 0}}},\n\t\tNode:    {{start: v{25, 0, 0}}},\n\t\tOpera:   {{start: v{124, 0, 0}}},\n\t\tSafari:  {{start: v{18, 2, 0}}},\n\t},\n\tFunctionNameConfigurable: {\n\t\t// Note: The latest version of \"IE\" failed this test: function \"name\" property: isn't writable, is configurable\n\t\tChrome:  {{start: v{43, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{12, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{38, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{4, 0, 0}}},\n\t\tOpera:   {{start: v{30, 0, 0}}},\n\t\tRhino:   {{start: v{1, 7, 15}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tFunctionOrClassPropertyAccess: {\n\t\tChrome:  {{start: v{0, 0, 0}}},\n\t\tDeno:    {{start: v{0, 0, 0}}},\n\t\tEdge:    {{start: v{0, 0, 0}}},\n\t\tES:      {{start: v{0, 0, 0}}},\n\t\tFirefox: {{start: v{0, 0, 0}}},\n\t\tHermes:  {{start: v{0, 0, 0}}},\n\t\tIE:      {{start: v{0, 0, 0}}},\n\t\tIOS:     {{start: v{0, 0, 0}}},\n\t\tNode:    {{start: v{0, 0, 0}}},\n\t\tOpera:   {{start: v{0, 0, 0}}},\n\t\tRhino:   {{start: v{0, 0, 0}}},\n\t\tSafari:  {{start: v{16, 3, 0}}},\n\t},\n\tGenerator: {\n\t\t// Note: The latest version of \"Hermes\" failed 3 tests including: generators: computed shorthand generators, classes\n\t\t// Note: The latest version of \"IE\" failed 27 tests including: generators: %GeneratorPrototype%\n\t\t// Note: The latest version of \"Rhino\" failed 8 tests including: generators: %GeneratorPrototype%\n\t\tChrome:  {{start: v{50, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{13, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{53, 0, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{37, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tHashbang: {\n\t\t// Note: The latest version of \"IE\" failed this test: Hashbang Grammar\n\t\tChrome:  {{start: v{74, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2023, 0, 0}}},\n\t\tFirefox: {{start: v{67, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{13, 4, 0}}},\n\t\tNode:    {{start: v{12, 5, 0}}},\n\t\tOpera:   {{start: v{62, 0, 0}}},\n\t\tRhino:   {{start: v{1, 7, 15}}},\n\t\tSafari:  {{start: v{13, 1, 0}}},\n\t},\n\tImportAssertions: {\n\t\tChrome: {{start: v{91, 0, 0}}},\n\t\tDeno:   {{start: v{1, 17, 0}}},\n\t\tEdge:   {{start: v{91, 0, 0}}},\n\t\tNode:   {{start: v{16, 14, 0}, end: v{22, 0, 0}}},\n\t},\n\tImportAttributes: {\n\t\tChrome:  {{start: v{123, 0, 0}}},\n\t\tDeno:    {{start: v{1, 37, 0}}},\n\t\tEdge:    {{start: v{123, 0, 0}}},\n\t\tFirefox: {{start: v{138, 0, 0}}},\n\t\tIOS:     {{start: v{17, 2, 0}}},\n\t\tNode:    {{start: v{18, 20, 0}, end: v{19, 0, 0}}, {start: v{20, 10, 0}}},\n\t\tOpera:   {{start: v{109, 0, 0}}},\n\t\tSafari:  {{start: v{17, 2, 0}}},\n\t},\n\tImportDefer: {},\n\tImportMeta: {\n\t\tChrome:  {{start: v{64, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2020, 0, 0}}},\n\t\tFirefox: {{start: v{62, 0, 0}}},\n\t\tIOS:     {{start: v{12, 0, 0}}},\n\t\tNode:    {{start: v{10, 4, 0}}},\n\t\tOpera:   {{start: v{51, 0, 0}}},\n\t\tSafari:  {{start: v{11, 1, 0}}},\n\t},\n\tImportSource: {},\n\tInlineScript: {},\n\tLogicalAssignment: {\n\t\t// Note: The latest version of \"IE\" failed 9 tests including: Logical Assignment: &&= basic support\n\t\t// Note: The latest version of \"Rhino\" failed 3 tests including: Logical Assignment: &&= setter not unecessarily invoked\n\t\tChrome:  {{start: v{85, 0, 0}}},\n\t\tDeno:    {{start: v{1, 2, 0}}},\n\t\tEdge:    {{start: v{85, 0, 0}}},\n\t\tES:      {{start: v{2021, 0, 0}}},\n\t\tFirefox: {{start: v{79, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{14, 0, 0}}},\n\t\tNode:    {{start: v{15, 0, 0}}},\n\t\tOpera:   {{start: v{71, 0, 0}}},\n\t\tSafari:  {{start: v{14, 0, 0}}},\n\t},\n\tNestedRestBinding: {\n\t\t// Note: The latest version of \"IE\" failed 2 tests including: nested rest destructuring, declarations\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: nested rest destructuring, declarations\n\t\tChrome:  {{start: v{49, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{14, 0, 0}}},\n\t\tES:      {{start: v{2016, 0, 0}}},\n\t\tFirefox: {{start: v{47, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{10, 3, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{36, 0, 0}}},\n\t\tSafari:  {{start: v{10, 1, 0}}},\n\t},\n\tNewTarget: {\n\t\t// Note: The latest version of \"IE\" failed 2 tests including: new.target: assignment is an early error\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: new.target: assignment is an early error\n\t\tChrome:  {{start: v{46, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{14, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{41, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{5, 0, 0}}},\n\t\tOpera:   {{start: v{33, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tNodeColonPrefixImport: {\n\t\tES:   {{start: v{0, 0, 0}}},\n\t\tNode: {{start: v{12, 20, 0}, end: v{13, 0, 0}}, {start: v{14, 13, 1}}},\n\t},\n\tNodeColonPrefixRequire: {\n\t\tES:   {{start: v{0, 0, 0}}},\n\t\tNode: {{start: v{14, 18, 0}, end: v{15, 0, 0}}, {start: v{16, 0, 0}}},\n\t},\n\tNullishCoalescing: {\n\t\t// Note: The latest version of \"IE\" failed this test: nullish coalescing operator (??)\n\t\tChrome:  {{start: v{80, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{80, 0, 0}}},\n\t\tES:      {{start: v{2020, 0, 0}}},\n\t\tFirefox: {{start: v{72, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{13, 4, 0}}},\n\t\tNode:    {{start: v{14, 0, 0}}},\n\t\tOpera:   {{start: v{67, 0, 0}}},\n\t\tRhino:   {{start: v{1, 8, 0}}},\n\t\tSafari:  {{start: v{13, 1, 0}}},\n\t},\n\tObjectAccessors: {\n\t\tChrome:  {{start: v{5, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{12, 0, 0}}},\n\t\tES:      {{start: v{5, 0, 0}}},\n\t\tFirefox: {{start: v{2, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIE:      {{start: v{9, 0, 0}}},\n\t\tIOS:     {{start: v{6, 0, 0}}},\n\t\tNode:    {{start: v{0, 4, 0}}},\n\t\tOpera:   {{start: v{10, 10, 0}}},\n\t\tRhino:   {{start: v{1, 7, 13}}},\n\t\tSafari:  {{start: v{3, 1, 0}}},\n\t},\n\tObjectExtensions: {\n\t\t// Note: The latest version of \"IE\" failed 6 tests including: object literal extensions: computed accessors\n\t\tChrome:  {{start: v{44, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{12, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{34, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{4, 0, 0}}},\n\t\tOpera:   {{start: v{31, 0, 0}}},\n\t\tRhino:   {{start: v{1, 8, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tObjectRestSpread: {\n\t\t// Note: The latest version of \"IE\" failed 2 tests including: object rest/spread properties: object rest properties\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: object rest/spread properties: object rest properties\n\t\tChrome:  {{start: v{60, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2018, 0, 0}}},\n\t\tFirefox: {{start: v{55, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{11, 3, 0}}},\n\t\tNode:    {{start: v{8, 3, 0}}},\n\t\tOpera:   {{start: v{47, 0, 0}}},\n\t\tSafari:  {{start: v{11, 1, 0}}},\n\t},\n\tOptionalCatchBinding: {\n\t\t// Note: The latest version of \"IE\" failed 3 tests including: optional catch binding: await\n\t\t// Note: The latest version of \"Rhino\" failed this test: optional catch binding: await\n\t\tChrome:  {{start: v{66, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2019, 0, 0}}},\n\t\tFirefox: {{start: v{58, 0, 0}}},\n\t\tHermes:  {{start: v{0, 12, 0}}},\n\t\tIOS:     {{start: v{11, 3, 0}}},\n\t\tNode:    {{start: v{10, 0, 0}}},\n\t\tOpera:   {{start: v{53, 0, 0}}},\n\t\tSafari:  {{start: v{11, 1, 0}}},\n\t},\n\tOptionalChain: {\n\t\t// Note: The latest version of \"IE\" failed 5 tests including: optional chaining operator (?.): optional bracket access\n\t\t// Note: The latest version of \"Rhino\" failed this test: optional chaining operator (?.): spread parameters after optional chaining\n\t\tChrome:  {{start: v{91, 0, 0}}},\n\t\tDeno:    {{start: v{1, 9, 0}}},\n\t\tEdge:    {{start: v{91, 0, 0}}},\n\t\tES:      {{start: v{2020, 0, 0}}},\n\t\tFirefox: {{start: v{74, 0, 0}}},\n\t\tHermes:  {{start: v{0, 12, 0}}},\n\t\tIOS:     {{start: v{13, 4, 0}}},\n\t\tNode:    {{start: v{16, 1, 0}}},\n\t\tOpera:   {{start: v{77, 0, 0}}},\n\t\tSafari:  {{start: v{13, 1, 0}}},\n\t},\n\tRegexpDotAllFlag: {\n\t\t// Note: The latest version of \"IE\" failed this test: s (dotAll) flag for regular expressions\n\t\tChrome:  {{start: v{62, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2018, 0, 0}}},\n\t\tFirefox: {{start: v{78, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{11, 3, 0}}},\n\t\tNode:    {{start: v{8, 10, 0}}},\n\t\tOpera:   {{start: v{49, 0, 0}}},\n\t\tRhino:   {{start: v{1, 7, 15}}},\n\t\tSafari:  {{start: v{11, 1, 0}}},\n\t},\n\tRegexpLookbehindAssertions: {\n\t\t// Note: The latest version of \"IE\" failed this test: RegExp Lookbehind Assertions\n\t\t// Note: The latest version of \"Rhino\" failed this test: RegExp Lookbehind Assertions\n\t\tChrome:  {{start: v{62, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2018, 0, 0}}},\n\t\tFirefox: {{start: v{78, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{16, 4, 0}}},\n\t\tNode:    {{start: v{8, 10, 0}}},\n\t\tOpera:   {{start: v{49, 0, 0}}},\n\t\tSafari:  {{start: v{16, 4, 0}}},\n\t},\n\tRegexpMatchIndices: {\n\t\tChrome:  {{start: v{90, 0, 0}}},\n\t\tDeno:    {{start: v{1, 8, 0}}},\n\t\tEdge:    {{start: v{90, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{88, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tNode:    {{start: v{16, 0, 0}}},\n\t\tOpera:   {{start: v{76, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tRegexpNamedCaptureGroups: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: RegExp named capture groups\n\t\t// Note: The latest version of \"IE\" failed this test: RegExp named capture groups\n\t\t// Note: The latest version of \"Rhino\" failed this test: RegExp named capture groups\n\t\tChrome:  {{start: v{64, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2018, 0, 0}}},\n\t\tFirefox: {{start: v{78, 0, 0}}},\n\t\tIOS:     {{start: v{11, 3, 0}}},\n\t\tNode:    {{start: v{10, 0, 0}}},\n\t\tOpera:   {{start: v{51, 0, 0}}},\n\t\tSafari:  {{start: v{11, 1, 0}}},\n\t},\n\tRegexpSetNotation: {\n\t\tES: {{start: v{2024, 0, 0}}},\n\t},\n\tRegexpStickyAndUnicodeFlags: {\n\t\t// Note: The latest version of \"IE\" failed 6 tests including: RegExp \"y\" and \"u\" flags: \"u\" flag\n\t\t// Note: The latest version of \"Rhino\" failed 4 tests including: RegExp \"y\" and \"u\" flags: \"u\" flag\n\t\tChrome:  {{start: v{50, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{13, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{46, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{12, 0, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{37, 0, 0}}},\n\t\tSafari:  {{start: v{12, 0, 0}}},\n\t},\n\tRegexpUnicodePropertyEscapes: {\n\t\t// Note: The latest version of \"Chrome\" failed 2 tests including: RegExp Unicode Property Escapes: Unicode 16.0\n\t\t// Note: The latest version of \"Edge\" failed 2 tests including: RegExp Unicode Property Escapes: Unicode 16.0\n\t\t// Note: The latest version of \"Firefox\" failed this test: RegExp Unicode Property Escapes: Unicode 17.0\n\t\t// Note: The latest version of \"Hermes\" failed 8 tests including: RegExp Unicode Property Escapes: Unicode 11\n\t\t// Note: The latest version of \"IE\" failed 8 tests including: RegExp Unicode Property Escapes: Unicode 11\n\t\t// Note: The latest version of \"IOS\" failed this test: RegExp Unicode Property Escapes: Unicode 17.0\n\t\t// Note: The latest version of \"Node\" failed this test: RegExp Unicode Property Escapes: Unicode 17.0\n\t\t// Note: The latest version of \"Rhino\" failed 9 tests including: RegExp Unicode Property Escapes: Unicode 11\n\t\t// Note: The latest version of \"Safari\" failed this test: RegExp Unicode Property Escapes: Unicode 17.0\n\t\tES: {{start: v{2018, 0, 0}}},\n\t},\n\tRestArgument: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: rest parameters: function 'length' property\n\t\t// Note: The latest version of \"IE\" failed 5 tests including: rest parameters: arguments object interaction\n\t\t// Note: The latest version of \"Rhino\" failed 2 tests including: rest parameters: arguments object interaction\n\t\tChrome:  {{start: v{47, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{12, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{43, 0, 0}}},\n\t\tIOS:     {{start: v{10, 0, 0}}},\n\t\tNode:    {{start: v{6, 0, 0}}},\n\t\tOpera:   {{start: v{34, 0, 0}}},\n\t\tSafari:  {{start: v{10, 0, 0}}},\n\t},\n\tTemplateLiteral: {\n\t\t// Note: The latest version of \"Hermes\" failed this test: template literals: TemplateStrings call site caching\n\t\t// Note: The latest version of \"IE\" failed 7 tests including: template literals: TemplateStrings call site caching\n\t\t// Note: The latest version of \"Rhino\" failed this test: template literals: toString conversion\n\t\tChrome:  {{start: v{62, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{79, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{53, 0, 0}}},\n\t\tIOS:     {{start: v{13, 0, 0}}},\n\t\tNode:    {{start: v{10, 0, 0}}},\n\t\tOpera:   {{start: v{49, 0, 0}}},\n\t\tSafari:  {{start: v{13, 0, 0}}},\n\t},\n\tTopLevelAwait: {\n\t\tChrome:  {{start: v{89, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{89, 0, 0}}},\n\t\tES:      {{start: v{2022, 0, 0}}},\n\t\tFirefox: {{start: v{89, 0, 0}}},\n\t\tIOS:     {{start: v{15, 0, 0}}},\n\t\tNode:    {{start: v{14, 8, 0}}},\n\t\tOpera:   {{start: v{75, 0, 0}}},\n\t\tSafari:  {{start: v{15, 0, 0}}},\n\t},\n\tTypeofExoticObjectIsObject: {\n\t\tChrome:  {{start: v{0, 0, 0}}},\n\t\tDeno:    {{start: v{0, 0, 0}}},\n\t\tEdge:    {{start: v{0, 0, 0}}},\n\t\tES:      {{start: v{2020, 0, 0}}},\n\t\tFirefox: {{start: v{0, 0, 0}}},\n\t\tHermes:  {{start: v{0, 0, 0}}},\n\t\tIOS:     {{start: v{0, 0, 0}}},\n\t\tNode:    {{start: v{0, 0, 0}}},\n\t\tOpera:   {{start: v{0, 0, 0}}},\n\t\tRhino:   {{start: v{0, 0, 0}}},\n\t\tSafari:  {{start: v{0, 0, 0}}},\n\t},\n\tUnicodeEscapes: {\n\t\t// Note: The latest version of \"IE\" failed 2 tests including: Unicode code point escapes: in identifiers\n\t\tChrome:  {{start: v{44, 0, 0}}},\n\t\tDeno:    {{start: v{1, 0, 0}}},\n\t\tEdge:    {{start: v{12, 0, 0}}},\n\t\tES:      {{start: v{2015, 0, 0}}},\n\t\tFirefox: {{start: v{53, 0, 0}}},\n\t\tHermes:  {{start: v{0, 7, 0}}},\n\t\tIOS:     {{start: v{9, 0, 0}}},\n\t\tNode:    {{start: v{4, 0, 0}}},\n\t\tOpera:   {{start: v{31, 0, 0}}},\n\t\tRhino:   {{start: v{1, 7, 15}}},\n\t\tSafari:  {{start: v{9, 0, 0}}},\n\t},\n\tUsing: {},\n}\n\n// Return all features that are not available in at least one environment\nfunc UnsupportedJSFeatures(constraints map[Engine]Semver) (unsupported JSFeature) {\n\tfor feature, engines := range jsTable {\n\t\tif feature == InlineScript {\n\t\t\tcontinue // This is purely user-specified\n\t\t}\n\t\tfor engine, version := range constraints {\n\t\t\tif versionRanges, ok := engines[engine]; !ok || !isVersionSupported(versionRanges, version) {\n\t\t\t\tunsupported |= feature\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/config/config.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\ntype JSXOptions struct {\n\tFactory          DefineExpr\n\tFragment         DefineExpr\n\tParse            bool\n\tPreserve         bool\n\tAutomaticRuntime bool\n\tImportSource     string\n\tDevelopment      bool\n\tSideEffects      bool\n}\n\ntype TSJSX uint8\n\nconst (\n\tTSJSXNone TSJSX = iota\n\tTSJSXPreserve\n\tTSJSXReactNative\n\tTSJSXReact\n\tTSJSXReactJSX\n\tTSJSXReactJSXDev\n)\n\ntype TSOptions struct {\n\tConfig              TSConfig\n\tParse               bool\n\tNoAmbiguousLessThan bool\n}\n\ntype TSConfigJSX struct {\n\t// If not empty, these should override the default values\n\tJSXFactory         []string // Default if empty: \"React.createElement\"\n\tJSXFragmentFactory []string // Default if empty: \"React.Fragment\"\n\tJSXImportSource    *string  // Default if empty: \"react\"\n\tJSX                TSJSX\n}\n\n// This is used for \"extends\" in \"tsconfig.json\"\nfunc (derived *TSConfigJSX) ApplyExtendedConfig(base TSConfigJSX) {\n\tif base.JSXFactory != nil {\n\t\tderived.JSXFactory = base.JSXFactory\n\t}\n\tif base.JSXFragmentFactory != nil {\n\t\tderived.JSXFragmentFactory = base.JSXFragmentFactory\n\t}\n\tif base.JSXImportSource != nil {\n\t\tderived.JSXImportSource = base.JSXImportSource\n\t}\n\tif base.JSX != TSJSXNone {\n\t\tderived.JSX = base.JSX\n\t}\n}\n\nfunc (tsConfig *TSConfigJSX) ApplyTo(jsxOptions *JSXOptions) {\n\tswitch tsConfig.JSX {\n\tcase TSJSXPreserve, TSJSXReactNative:\n\t\t// Deliberately don't set \"Preserve = true\" here. Some tools from Vercel\n\t\t// apparently automatically set \"jsx\": \"preserve\" in \"tsconfig.json\" and\n\t\t// people are then confused when esbuild preserves their JSX. Ignoring this\n\t\t// value means you now have to explicitly pass \"--jsx=preserve\" to esbuild\n\t\t// to get this behavior.\n\n\tcase TSJSXReact:\n\t\tjsxOptions.AutomaticRuntime = false\n\t\tjsxOptions.Development = false\n\n\tcase TSJSXReactJSX:\n\t\tjsxOptions.AutomaticRuntime = true\n\t\t// Deliberately don't set \"Development = false\" here. People want to be\n\t\t// able to have \"react-jsx\" in their \"tsconfig.json\" file and then swap\n\t\t// that to \"react-jsxdev\" by passing \"--jsx-dev\" to esbuild.\n\n\tcase TSJSXReactJSXDev:\n\t\tjsxOptions.AutomaticRuntime = true\n\t\tjsxOptions.Development = true\n\t}\n\n\tif len(tsConfig.JSXFactory) > 0 {\n\t\tjsxOptions.Factory = DefineExpr{Parts: tsConfig.JSXFactory}\n\t}\n\n\tif len(tsConfig.JSXFragmentFactory) > 0 {\n\t\tjsxOptions.Fragment = DefineExpr{Parts: tsConfig.JSXFragmentFactory}\n\t}\n\n\tif tsConfig.JSXImportSource != nil {\n\t\tjsxOptions.ImportSource = *tsConfig.JSXImportSource\n\t}\n}\n\n// Note: This can currently only contain primitive values. It's compared\n// for equality using a structural equality comparison by the JS parser.\ntype TSConfig struct {\n\tExperimentalDecorators  MaybeBool\n\tImportsNotUsedAsValues  TSImportsNotUsedAsValues\n\tPreserveValueImports    MaybeBool\n\tTarget                  TSTarget\n\tUseDefineForClassFields MaybeBool\n\tVerbatimModuleSyntax    MaybeBool\n}\n\n// This is used for \"extends\" in \"tsconfig.json\"\nfunc (derived *TSConfig) ApplyExtendedConfig(base TSConfig) {\n\tif base.ExperimentalDecorators != Unspecified {\n\t\tderived.ExperimentalDecorators = base.ExperimentalDecorators\n\t}\n\tif base.ImportsNotUsedAsValues != TSImportsNotUsedAsValues_None {\n\t\tderived.ImportsNotUsedAsValues = base.ImportsNotUsedAsValues\n\t}\n\tif base.PreserveValueImports != Unspecified {\n\t\tderived.PreserveValueImports = base.PreserveValueImports\n\t}\n\tif base.Target != TSTargetUnspecified {\n\t\tderived.Target = base.Target\n\t}\n\tif base.UseDefineForClassFields != Unspecified {\n\t\tderived.UseDefineForClassFields = base.UseDefineForClassFields\n\t}\n\tif base.VerbatimModuleSyntax != Unspecified {\n\t\tderived.VerbatimModuleSyntax = base.VerbatimModuleSyntax\n\t}\n}\n\nfunc (cfg *TSConfig) UnusedImportFlags() (flags TSUnusedImportFlags) {\n\tif cfg.VerbatimModuleSyntax == True {\n\t\treturn TSUnusedImport_KeepStmt | TSUnusedImport_KeepValues\n\t}\n\tif cfg.PreserveValueImports == True {\n\t\tflags |= TSUnusedImport_KeepValues\n\t}\n\tif cfg.ImportsNotUsedAsValues == TSImportsNotUsedAsValues_Preserve || cfg.ImportsNotUsedAsValues == TSImportsNotUsedAsValues_Error {\n\t\tflags |= TSUnusedImport_KeepStmt\n\t}\n\treturn\n}\n\ntype Platform uint8\n\nconst (\n\tPlatformBrowser Platform = iota\n\tPlatformNode\n\tPlatformNeutral\n)\n\ntype SourceMap uint8\n\nconst (\n\tSourceMapNone SourceMap = iota\n\tSourceMapInline\n\tSourceMapLinkedWithComment\n\tSourceMapExternalWithoutComment\n\tSourceMapInlineAndExternal\n)\n\ntype LegalComments uint8\n\nconst (\n\tLegalCommentsInline LegalComments = iota\n\tLegalCommentsNone\n\tLegalCommentsEndOfFile\n\tLegalCommentsLinkedWithComment\n\tLegalCommentsExternalWithoutComment\n)\n\nfunc (lc LegalComments) HasExternalFile() bool {\n\treturn lc == LegalCommentsLinkedWithComment || lc == LegalCommentsExternalWithoutComment\n}\n\ntype Loader uint8\n\nconst (\n\tLoaderNone Loader = iota\n\tLoaderBase64\n\tLoaderBinary\n\tLoaderCopy\n\tLoaderCSS\n\tLoaderDataURL\n\tLoaderDefault\n\tLoaderEmpty\n\tLoaderFile\n\tLoaderGlobalCSS\n\tLoaderJS\n\tLoaderJSON\n\tLoaderWithTypeJSON // Has a \"with { type: 'json' }\" attribute\n\tLoaderJSX\n\tLoaderLocalCSS\n\tLoaderText\n\tLoaderTS\n\tLoaderTSNoAmbiguousLessThan // Used with \".mts\" and \".cts\"\n\tLoaderTSX\n)\n\nvar LoaderToString = []string{\n\t\"none\",\n\t\"base64\",\n\t\"binary\",\n\t\"copy\",\n\t\"css\",\n\t\"dataurl\",\n\t\"default\",\n\t\"empty\",\n\t\"file\",\n\t\"global-css\",\n\t\"js\",\n\t\"json\",\n\t\"json\",\n\t\"jsx\",\n\t\"local-css\",\n\t\"text\",\n\t\"ts\",\n\t\"ts\",\n\t\"tsx\",\n}\n\nfunc (loader Loader) IsTypeScript() bool {\n\tswitch loader {\n\tcase LoaderTS, LoaderTSNoAmbiguousLessThan, LoaderTSX:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (loader Loader) IsCSS() bool {\n\tswitch loader {\n\tcase\n\t\tLoaderCSS, LoaderGlobalCSS, LoaderLocalCSS:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (loader Loader) CanHaveSourceMap() bool {\n\tswitch loader {\n\tcase\n\t\tLoaderJS, LoaderJSX,\n\t\tLoaderTS, LoaderTSNoAmbiguousLessThan, LoaderTSX,\n\t\tLoaderCSS, LoaderGlobalCSS, LoaderLocalCSS,\n\t\tLoaderJSON, LoaderWithTypeJSON, LoaderText:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc LoaderFromFileExtension(extensionToLoader map[string]Loader, base string) Loader {\n\t// Pick the loader with the longest matching extension. So if there's an\n\t// extension for \".css\" and for \".module.css\", we want to match the one for\n\t// \".module.css\" before the one for \".css\".\n\tif i := strings.IndexByte(base, '.'); i != -1 {\n\t\tfor {\n\t\t\tif loader, ok := extensionToLoader[base[i:]]; ok {\n\t\t\t\treturn loader\n\t\t\t}\n\t\t\tbase = base[i+1:]\n\t\t\ti = strings.IndexByte(base, '.')\n\t\t\tif i == -1 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// If there's no extension, explicitly check for an extensionless loader\n\t\tif loader, ok := extensionToLoader[\"\"]; ok {\n\t\t\treturn loader\n\t\t}\n\t}\n\treturn LoaderNone\n}\n\ntype Format uint8\n\nconst (\n\t// This is used when not bundling. It means to preserve whatever form the\n\t// import or export was originally in. ES6 syntax stays ES6 syntax and\n\t// CommonJS syntax stays CommonJS syntax.\n\tFormatPreserve Format = iota\n\n\t// IIFE stands for immediately-invoked function expression. That looks like\n\t// this:\n\t//\n\t//   (() => {\n\t//     ... bundled code ...\n\t//   })();\n\t//\n\t// If the optional GlobalName is configured, then we'll write out this:\n\t//\n\t//   let globalName = (() => {\n\t//     ... bundled code ...\n\t//     return exports;\n\t//   })();\n\t//\n\tFormatIIFE\n\n\t// The CommonJS format looks like this:\n\t//\n\t//   ... bundled code ...\n\t//   module.exports = exports;\n\t//\n\tFormatCommonJS\n\n\t// The ES module format looks like this:\n\t//\n\t//   ... bundled code ...\n\t//   export {...};\n\t//\n\tFormatESModule\n)\n\nfunc (f Format) KeepESMImportExportSyntax() bool {\n\treturn f == FormatPreserve || f == FormatESModule\n}\n\nfunc (f Format) String() string {\n\tswitch f {\n\tcase FormatIIFE:\n\t\treturn \"iife\"\n\tcase FormatCommonJS:\n\t\treturn \"cjs\"\n\tcase FormatESModule:\n\t\treturn \"esm\"\n\t}\n\treturn \"\"\n}\n\ntype StdinInfo struct {\n\tContents      string\n\tSourceFile    string\n\tAbsResolveDir string\n\tLoader        Loader\n}\n\ntype WildcardPattern struct {\n\tPrefix string\n\tSuffix string\n}\n\ntype ExternalMatchers struct {\n\tExact    map[string]bool\n\tPatterns []WildcardPattern\n}\n\nfunc (matchers ExternalMatchers) HasMatchers() bool {\n\treturn len(matchers.Exact) > 0 || len(matchers.Patterns) > 0\n}\n\ntype ExternalSettings struct {\n\tPreResolve  ExternalMatchers\n\tPostResolve ExternalMatchers\n}\n\ntype APICall uint8\n\nconst (\n\tBuildCall APICall = iota\n\tTransformCall\n)\n\ntype Mode uint8\n\nconst (\n\tModePassThrough Mode = iota\n\tModeConvertFormat\n\tModeBundle\n)\n\ntype MaybeBool uint8\n\nconst (\n\tUnspecified MaybeBool = iota\n\tTrue\n\tFalse\n)\n\ntype CancelFlag struct {\n\tuint32\n}\n\nfunc (flag *CancelFlag) Cancel() {\n\tatomic.StoreUint32(&flag.uint32, 1)\n}\n\n// This checks for nil in one place so we don't have to do that everywhere\nfunc (flag *CancelFlag) DidCancel() bool {\n\treturn flag != nil && atomic.LoadUint32(&flag.uint32) != 0\n}\n\ntype Options struct {\n\tModuleTypeData js_ast.ModuleTypeData\n\tDefines        *ProcessedDefines\n\tTSAlwaysStrict *TSAlwaysStrict\n\tMangleProps    *regexp.Regexp\n\tReserveProps   *regexp.Regexp\n\tCancelFlag     *CancelFlag\n\n\t// When mangling property names, call this function with a callback and do\n\t// the property name mangling inside the callback. The callback takes an\n\t// argument which is the mangle cache map to mutate. These callbacks are\n\t// serialized so mutating the map does not require extra synchronization.\n\t//\n\t// This is a callback for determinism reasons. We may be building multiple\n\t// entry points in parallel that are supposed to share a single cache. We\n\t// don't want the order that each entry point mangles properties in to cause\n\t// the output to change, so we serialize the property mangling over all entry\n\t// points in entry point order. However, we still want to link everything in\n\t// parallel so only property mangling is serialized, which is implemented by\n\t// this function blocking until the previous entry point's property mangling\n\t// has finished.\n\tExclusiveMangleCacheUpdate func(cb func(\n\t\tmangleCache map[string]interface{},\n\t\tcssUsedLocalNames map[string]bool,\n\t))\n\n\t// This is the original information that was used to generate the\n\t// unsupported feature sets above. It's used for error messages.\n\tOriginalTargetEnv string\n\n\tDropLabels       []string\n\tExtensionOrder   []string\n\tMainFields       []string\n\tConditions       []string\n\tAbsNodePaths     []string // The \"NODE_PATH\" variable from Node.js\n\tExternalSettings ExternalSettings\n\tExternalPackages bool\n\tPackageAliases   map[string]string\n\n\tAbsOutputFile      string\n\tAbsOutputDir       string\n\tAbsOutputBase      string\n\tOutputExtensionJS  string\n\tOutputExtensionCSS string\n\tGlobalName         []string\n\tTSConfigPath       string\n\tTSConfigRaw        string\n\tExtensionToLoader  map[string]Loader\n\n\tPublicPath      string\n\tInjectPaths     []string\n\tInjectedDefines []InjectedDefine\n\tInjectedFiles   []InjectedFile\n\n\tJSBanner  string\n\tJSFooter  string\n\tCSSBanner string\n\tCSSFooter string\n\n\tEntryPathTemplate []PathTemplate\n\tChunkPathTemplate []PathTemplate\n\tAssetPathTemplate []PathTemplate\n\n\tPlugins    []Plugin\n\tSourceRoot string\n\tStdin      *StdinInfo\n\tJSX        JSXOptions\n\tLineLimit  int\n\n\tCSSPrefixData          map[css_ast.D]compat.CSSPrefix\n\tUnsupportedJSFeatures  compat.JSFeature\n\tUnsupportedCSSFeatures compat.CSSFeature\n\n\tUnsupportedJSFeatureOverrides      compat.JSFeature\n\tUnsupportedJSFeatureOverridesMask  compat.JSFeature\n\tUnsupportedCSSFeatureOverrides     compat.CSSFeature\n\tUnsupportedCSSFeatureOverridesMask compat.CSSFeature\n\n\tTS                TSOptions\n\tMode              Mode\n\tPreserveSymlinks  bool\n\tMinifyWhitespace  bool\n\tMinifyIdentifiers bool\n\tMinifySyntax      bool\n\tProfilerNames     bool\n\tCodeSplitting     bool\n\tWatchMode         bool\n\tAllowOverwrite    bool\n\tLegalComments     LegalComments\n\n\tLogPathStyle       logger.PathStyle\n\tCodePathStyle      logger.PathStyle\n\tMetafilePathStyle  logger.PathStyle\n\tSourcemapPathStyle logger.PathStyle\n\n\t// If true, make sure to generate a single file that can be written to stdout\n\tWriteToStdout bool\n\n\tOmitRuntimeForTests    bool\n\tOmitJSXRuntimeForTests bool\n\tASCIIOnly              bool\n\tKeepNames              bool\n\tIgnoreDCEAnnotations   bool\n\tTreeShaking            bool\n\tDropDebugger           bool\n\tMangleQuoted           bool\n\tPlatform               Platform\n\tOutputFormat           Format\n\tNeedsMetafile          bool\n\tSourceMap              SourceMap\n\tExcludeSourcesContent  bool\n}\n\ntype TSImportsNotUsedAsValues uint8\n\nconst (\n\tTSImportsNotUsedAsValues_None TSImportsNotUsedAsValues = iota\n\tTSImportsNotUsedAsValues_Remove\n\tTSImportsNotUsedAsValues_Preserve\n\tTSImportsNotUsedAsValues_Error\n)\n\n// These flags represent the following separate \"tsconfig.json\" settings:\n//\n// - importsNotUsedAsValues\n// - preserveValueImports\n// - verbatimModuleSyntax\n//\n// TypeScript prefers for people to use \"verbatimModuleSyntax\" and has\n// deprecated the other two settings, but we must still support them.\n// All settings are combined into these two behavioral flags for us.\ntype TSUnusedImportFlags uint8\n\n// With !TSUnusedImport_KeepStmt && !TSUnusedImport_KeepValues:\n//\n//\t\"import 'foo'\"                      => \"import 'foo'\"\n//\t\"import * as unused from 'foo'\"     => \"\"\n//\t\"import { unused } from 'foo'\"      => \"\"\n//\t\"import { type unused } from 'foo'\" => \"\"\n//\n// With TSUnusedImport_KeepStmt && !TSUnusedImport_KeepValues:\n//\n//\t\"import 'foo'\"                      => \"import 'foo'\"\n//\t\"import * as unused from 'foo'\"     => \"import 'foo'\"\n//\t\"import { unused } from 'foo'\"      => \"import 'foo'\"\n//\t\"import { type unused } from 'foo'\" => \"import 'foo'\"\n//\n// With !TSUnusedImport_KeepStmt && TSUnusedImport_KeepValues:\n//\n//\t\"import 'foo'\"                      => \"import 'foo'\"\n//\t\"import * as unused from 'foo'\"     => \"import * as unused from 'foo'\"\n//\t\"import { unused } from 'foo'\"      => \"import { unused } from 'foo'\"\n//\t\"import { type unused } from 'foo'\" => \"\"\n//\n// With TSUnusedImport_KeepStmt && TSUnusedImport_KeepValues:\n//\n//\t\"import 'foo'\"                      => \"import 'foo'\"\n//\t\"import * as unused from 'foo'\"     => \"import * as unused from 'foo'\"\n//\t\"import { unused } from 'foo'\"      => \"import { unused } from 'foo'\"\n//\t\"import { type unused } from 'foo'\" => \"import {} from 'foo'\"\nconst (\n\tTSUnusedImport_KeepStmt   TSUnusedImportFlags = 1 << iota // \"importsNotUsedAsValues\" != \"remove\"\n\tTSUnusedImport_KeepValues                                 // \"preserveValueImports\" == true\n)\n\ntype TSTarget uint8\n\nconst (\n\tTSTargetUnspecified     TSTarget = iota\n\tTSTargetBelowES2022              // \"useDefineForClassFields\" defaults to false\n\tTSTargetAtOrAboveES2022          // \"useDefineForClassFields\" defaults to true\n)\n\ntype TSAlwaysStrict struct {\n\t// This information is only used for error messages\n\tName   string\n\tSource logger.Source\n\tRange  logger.Range\n\n\t// This information can affect code transformation\n\tValue bool\n}\n\ntype PathPlaceholder uint8\n\nconst (\n\tNoPlaceholder PathPlaceholder = iota\n\n\t// The relative path from the original parent directory to the configured\n\t// \"outbase\" directory, or to the lowest common ancestor directory\n\tDirPlaceholder\n\n\t// The original name of the file, or the manual chunk name, or the name of\n\t// the type of output file (\"entry\" or \"chunk\" or \"asset\")\n\tNamePlaceholder\n\n\t// A hash of the contents of this file, and the contents and output paths of\n\t// all dependencies (except for their hash placeholders)\n\tHashPlaceholder\n\n\t// The original extension of the file, or the name of the output file\n\t// (e.g. \"css\", \"svg\", \"png\")\n\tExtPlaceholder\n)\n\ntype PathTemplate struct {\n\tData        string\n\tPlaceholder PathPlaceholder\n}\n\ntype PathPlaceholders struct {\n\tDir  *string\n\tName *string\n\tHash *string\n\tExt  *string\n}\n\nfunc (placeholders PathPlaceholders) Get(placeholder PathPlaceholder) *string {\n\tswitch placeholder {\n\tcase DirPlaceholder:\n\t\treturn placeholders.Dir\n\tcase NamePlaceholder:\n\t\treturn placeholders.Name\n\tcase HashPlaceholder:\n\t\treturn placeholders.Hash\n\tcase ExtPlaceholder:\n\t\treturn placeholders.Ext\n\t}\n\treturn nil\n}\n\nfunc TemplateToString(template []PathTemplate) string {\n\tif len(template) == 1 && template[0].Placeholder == NoPlaceholder {\n\t\t// Avoid allocations in this case\n\t\treturn template[0].Data\n\t}\n\tsb := strings.Builder{}\n\tfor _, part := range template {\n\t\tsb.WriteString(part.Data)\n\t\tswitch part.Placeholder {\n\t\tcase DirPlaceholder:\n\t\t\tsb.WriteString(\"[dir]\")\n\t\tcase NamePlaceholder:\n\t\t\tsb.WriteString(\"[name]\")\n\t\tcase HashPlaceholder:\n\t\t\tsb.WriteString(\"[hash]\")\n\t\tcase ExtPlaceholder:\n\t\t\tsb.WriteString(\"[ext]\")\n\t\t}\n\t}\n\treturn sb.String()\n}\n\nfunc HasPlaceholder(template []PathTemplate, placeholder PathPlaceholder) bool {\n\tfor _, part := range template {\n\t\tif part.Placeholder == placeholder {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc SubstituteTemplate(template []PathTemplate, placeholders PathPlaceholders) []PathTemplate {\n\t// Don't allocate if no substitution is possible and the template is already minimal\n\tshouldSubstitute := false\n\tfor i, part := range template {\n\t\tif placeholders.Get(part.Placeholder) != nil || (part.Placeholder == NoPlaceholder && i+1 < len(template)) {\n\t\t\tshouldSubstitute = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !shouldSubstitute {\n\t\treturn template\n\t}\n\n\t// Otherwise, substitute and merge as appropriate\n\tresult := make([]PathTemplate, 0, len(template))\n\tfor _, part := range template {\n\t\tif sub := placeholders.Get(part.Placeholder); sub != nil {\n\t\t\tpart.Data += *sub\n\t\t\tpart.Placeholder = NoPlaceholder\n\t\t}\n\t\tif last := len(result) - 1; last >= 0 && result[last].Placeholder == NoPlaceholder {\n\t\t\tlast := &result[last]\n\t\t\tlast.Data += part.Data\n\t\t\tlast.Placeholder = part.Placeholder\n\t\t} else {\n\t\t\tresult = append(result, part)\n\t\t}\n\t}\n\treturn result\n}\n\nfunc ShouldCallRuntimeRequire(mode Mode, outputFormat Format) bool {\n\treturn mode == ModeBundle && outputFormat != FormatCommonJS\n}\n\ntype InjectedDefine struct {\n\tData   js_ast.E\n\tName   string\n\tSource logger.Source\n}\n\ntype InjectedFile struct {\n\tExports      []InjectableExport\n\tDefineName   string // For injected files generated when you \"--define\" a non-literal\n\tSource       logger.Source\n\tIsCopyLoader bool // If you set the loader to \"copy\" (see https://github.com/evanw/esbuild/issues/3041)\n}\n\ntype InjectableExport struct {\n\tAlias string\n\tLoc   logger.Loc\n}\n\nvar filterMutex sync.Mutex\nvar filterCache map[string]*regexp.Regexp\n\nfunc compileFilter(filter string) (result *regexp.Regexp) {\n\tif filter == \"\" {\n\t\t// Must provide a filter\n\t\treturn nil\n\t}\n\tok := false\n\n\t// Cache hit?\n\t(func() {\n\t\tfilterMutex.Lock()\n\t\tdefer filterMutex.Unlock()\n\t\tif filterCache != nil {\n\t\t\tresult, ok = filterCache[filter]\n\t\t}\n\t})()\n\tif ok {\n\t\treturn\n\t}\n\n\t// Cache miss\n\tresult, err := regexp.Compile(filter)\n\tif err != nil {\n\t\treturn nil\n\t}\n\n\t// Cache for next time\n\tfilterMutex.Lock()\n\tdefer filterMutex.Unlock()\n\tif filterCache == nil {\n\t\tfilterCache = make(map[string]*regexp.Regexp)\n\t}\n\tfilterCache[filter] = result\n\treturn\n}\n\nfunc CompileFilterForPlugin(pluginName string, kind string, filter string) (*regexp.Regexp, error) {\n\tif filter == \"\" {\n\t\treturn nil, fmt.Errorf(\"[%s] %q is missing a filter\", pluginName, kind)\n\t}\n\n\tresult := compileFilter(filter)\n\tif result == nil {\n\t\treturn nil, fmt.Errorf(\"[%s] %q filter is not a valid Go regular expression: %q\", pluginName, kind, filter)\n\t}\n\n\treturn result, nil\n}\n\nfunc PluginAppliesToPath(path logger.Path, filter *regexp.Regexp, namespace string) bool {\n\treturn (namespace == \"\" || path.Namespace == namespace) && filter.MatchString(path.Text)\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// Plugin API\n\ntype Plugin struct {\n\tName      string\n\tOnStart   []OnStart\n\tOnResolve []OnResolve\n\tOnLoad    []OnLoad\n}\n\ntype OnStart struct {\n\tCallback func() OnStartResult\n\tName     string\n}\n\ntype OnStartResult struct {\n\tThrownError error\n\tMsgs        []logger.Msg\n}\n\ntype OnResolve struct {\n\tFilter    *regexp.Regexp\n\tCallback  func(OnResolveArgs) OnResolveResult\n\tName      string\n\tNamespace string\n}\n\ntype OnResolveArgs struct {\n\tPath       string\n\tResolveDir string\n\tPluginData interface{}\n\tImporter   logger.Path\n\tKind       ast.ImportKind\n\tWith       logger.ImportAttributes\n}\n\ntype OnResolveResult struct {\n\tPluginName string\n\n\tMsgs        []logger.Msg\n\tThrownError error\n\n\tAbsWatchFiles []string\n\tAbsWatchDirs  []string\n\n\tPluginData       interface{}\n\tPath             logger.Path\n\tExternal         bool\n\tIsSideEffectFree bool\n}\n\ntype OnLoad struct {\n\tFilter    *regexp.Regexp\n\tCallback  func(OnLoadArgs) OnLoadResult\n\tName      string\n\tNamespace string\n}\n\ntype OnLoadArgs struct {\n\tPluginData interface{}\n\tPath       logger.Path\n}\n\ntype OnLoadResult struct {\n\tPluginName string\n\n\tContents      *string\n\tAbsResolveDir string\n\tPluginData    interface{}\n\n\tMsgs        []logger.Msg\n\tThrownError error\n\n\tAbsWatchFiles []string\n\tAbsWatchDirs  []string\n\n\tLoader Loader\n}\n\nfunc PrettyPrintTargetEnvironment(originalTargetEnv string, unsupportedJSFeatureOverridesMask compat.JSFeature) (where string) {\n\twhere = \"the configured target environment\"\n\toverrides := \"\"\n\tif unsupportedJSFeatureOverridesMask != 0 {\n\t\tcount := 0\n\t\tmask := unsupportedJSFeatureOverridesMask\n\t\tfor mask != 0 {\n\t\t\tif (mask & 1) != 0 {\n\t\t\t\tcount++\n\t\t\t}\n\t\t\tmask >>= 1\n\t\t}\n\t\ts := \"s\"\n\t\tif count == 1 {\n\t\t\ts = \"\"\n\t\t}\n\t\toverrides = fmt.Sprintf(\" + %d override%s\", count, s)\n\t}\n\tif originalTargetEnv != \"\" {\n\t\twhere = fmt.Sprintf(\"%s (%s%s)\", where, originalTargetEnv, overrides)\n\t}\n\treturn\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/config/globals.go",
    "content": "package config\n\nimport (\n\t\"math\"\n\t\"sync\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n)\n\nvar processedGlobalsMutex sync.Mutex\nvar processedGlobals *ProcessedDefines\n\n// If something is in this list, then a direct identifier expression or property\n// access chain matching this will be assumed to have no side effects and will\n// be removed.\n//\n// This also means code is allowed to be reordered past things in this list. For\n// example, if \"console.log\" is in this list, permitting reordering allows for\n// \"if (a) console.log(b); else console.log(c)\" to be reordered and transformed\n// into \"console.log(a ? b : c)\". Notice that \"a\" and \"console.log\" are in a\n// different order, which can only happen if evaluating the \"console.log\"\n// property access can be assumed to not change the value of \"a\".\n//\n// Note that membership in this list says nothing about whether calling any of\n// these functions has any side effects. It only says something about\n// referencing these function without calling them.\nvar knownGlobals = [][]string{\n\t// Array: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#static_methods\n\t{\"Array\", \"from\"},\n\t{\"Array\", \"fromAsync\"},\n\t{\"Array\", \"isArray\"},\n\t{\"Array\", \"of\"},\n\n\t// RegExp: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#static_methods\n\t{\"RegExp\", \"escape\"},\n\n\t// Map: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#static_methods\n\t{\"Map\", \"groupBy\"},\n\n\t// Object: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#static_methods\n\t{\"Object\", \"assign\"},\n\t{\"Object\", \"create\"},\n\t{\"Object\", \"defineProperties\"},\n\t{\"Object\", \"defineProperty\"},\n\t{\"Object\", \"entries\"},\n\t{\"Object\", \"freeze\"},\n\t{\"Object\", \"fromEntries\"},\n\t{\"Object\", \"getOwnPropertyDescriptor\"},\n\t{\"Object\", \"getOwnPropertyDescriptors\"},\n\t{\"Object\", \"getOwnPropertyNames\"},\n\t{\"Object\", \"getOwnPropertySymbols\"},\n\t{\"Object\", \"getPrototypeOf\"},\n\t{\"Object\", \"is\"},\n\t{\"Object\", \"isExtensible\"},\n\t{\"Object\", \"isFrozen\"},\n\t{\"Object\", \"isSealed\"},\n\t{\"Object\", \"keys\"},\n\t{\"Object\", \"preventExtensions\"},\n\t{\"Object\", \"seal\"},\n\t{\"Object\", \"setPrototypeOf\"},\n\t{\"Object\", \"values\"},\n\n\t// Object: Instance methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#instance_methods\n\t{\"Object\", \"prototype\", \"__defineGetter__\"},\n\t{\"Object\", \"prototype\", \"__defineSetter__\"},\n\t{\"Object\", \"prototype\", \"__lookupGetter__\"},\n\t{\"Object\", \"prototype\", \"__lookupSetter__\"},\n\t{\"Object\", \"prototype\", \"hasOwnProperty\"},\n\t{\"Object\", \"prototype\", \"isPrototypeOf\"},\n\t{\"Object\", \"prototype\", \"propertyIsEnumerable\"},\n\t{\"Object\", \"prototype\", \"toLocaleString\"},\n\t{\"Object\", \"prototype\", \"toString\"},\n\t{\"Object\", \"prototype\", \"unwatch\"},\n\t{\"Object\", \"prototype\", \"valueOf\"},\n\t{\"Object\", \"prototype\", \"watch\"},\n\n\t// Symbol: Static properties\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#static_properties\n\t{\"Symbol\", \"asyncDispose\"},\n\t{\"Symbol\", \"asyncIterator\"},\n\t{\"Symbol\", \"dispose\"},\n\t{\"Symbol\", \"hasInstance\"},\n\t{\"Symbol\", \"isConcatSpreadable\"},\n\t{\"Symbol\", \"iterator\"},\n\t{\"Symbol\", \"match\"},\n\t{\"Symbol\", \"matchAll\"},\n\t{\"Symbol\", \"replace\"},\n\t{\"Symbol\", \"search\"},\n\t{\"Symbol\", \"species\"},\n\t{\"Symbol\", \"split\"},\n\t{\"Symbol\", \"toPrimitive\"},\n\t{\"Symbol\", \"toStringTag\"},\n\t{\"Symbol\", \"unscopables\"},\n\n\t// Math: Static properties\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math#static_properties\n\t{\"Math\", \"E\"},\n\t{\"Math\", \"LN10\"},\n\t{\"Math\", \"LN2\"},\n\t{\"Math\", \"LOG10E\"},\n\t{\"Math\", \"LOG2E\"},\n\t{\"Math\", \"PI\"},\n\t{\"Math\", \"SQRT1_2\"},\n\t{\"Math\", \"SQRT2\"},\n\n\t// Math: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math#static_methods\n\t{\"Math\", \"abs\"},\n\t{\"Math\", \"acos\"},\n\t{\"Math\", \"acosh\"},\n\t{\"Math\", \"asin\"},\n\t{\"Math\", \"asinh\"},\n\t{\"Math\", \"atan\"},\n\t{\"Math\", \"atan2\"},\n\t{\"Math\", \"atanh\"},\n\t{\"Math\", \"cbrt\"},\n\t{\"Math\", \"ceil\"},\n\t{\"Math\", \"clz32\"},\n\t{\"Math\", \"cos\"},\n\t{\"Math\", \"cosh\"},\n\t{\"Math\", \"exp\"},\n\t{\"Math\", \"expm1\"},\n\t{\"Math\", \"floor\"},\n\t{\"Math\", \"fround\"},\n\t{\"Math\", \"hypot\"},\n\t{\"Math\", \"imul\"},\n\t{\"Math\", \"log\"},\n\t{\"Math\", \"log10\"},\n\t{\"Math\", \"log1p\"},\n\t{\"Math\", \"log2\"},\n\t{\"Math\", \"max\"},\n\t{\"Math\", \"min\"},\n\t{\"Math\", \"pow\"},\n\t{\"Math\", \"random\"},\n\t{\"Math\", \"round\"},\n\t{\"Math\", \"sign\"},\n\t{\"Math\", \"sin\"},\n\t{\"Math\", \"sinh\"},\n\t{\"Math\", \"sqrt\"},\n\t{\"Math\", \"tan\"},\n\t{\"Math\", \"tanh\"},\n\t{\"Math\", \"trunc\"},\n\n\t// Reflect: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect#static_methods\n\t{\"Reflect\", \"apply\"},\n\t{\"Reflect\", \"construct\"},\n\t{\"Reflect\", \"defineProperty\"},\n\t{\"Reflect\", \"deleteProperty\"},\n\t{\"Reflect\", \"get\"},\n\t{\"Reflect\", \"getOwnPropertyDescriptor\"},\n\t{\"Reflect\", \"getPrototypeOf\"},\n\t{\"Reflect\", \"has\"},\n\t{\"Reflect\", \"isExtensible\"},\n\t{\"Reflect\", \"ownKeys\"},\n\t{\"Reflect\", \"preventExtensions\"},\n\t{\"Reflect\", \"set\"},\n\t{\"Reflect\", \"setPrototypeOf\"},\n\n\t// JSON: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON#static_methods\n\t{\"JSON\", \"parse\"},\n\t{\"JSON\", \"stringify\"},\n\n\t// TypedArray: Static methods\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#static_methods\n\t{\"BigInt64Array\", \"from\"},\n\t{\"BigInt64Array\", \"of\"},\n\t{\"BigUint64Array\", \"from\"},\n\t{\"BigUint64Array\", \"of\"},\n\t{\"Float16Array\", \"from\"},\n\t{\"Float16Array\", \"of\"},\n\t{\"Float32Array\", \"from\"},\n\t{\"Float32Array\", \"of\"},\n\t{\"Float64Array\", \"from\"},\n\t{\"Float64Array\", \"of\"},\n\t{\"Int16Array\", \"from\"},\n\t{\"Int16Array\", \"of\"},\n\t{\"Int32Array\", \"from\"},\n\t{\"Int32Array\", \"of\"},\n\t{\"Int8Array\", \"from\"},\n\t{\"Int8Array\", \"of\"},\n\t{\"Uint16Array\", \"from\"},\n\t{\"Uint16Array\", \"of\"},\n\t{\"Uint32Array\", \"from\"},\n\t{\"Uint32Array\", \"of\"},\n\t{\"Uint8Array\", \"from\"},\n\t{\"Uint8Array\", \"fromBase64\"},\n\t{\"Uint8Array\", \"fromHex\"},\n\t{\"Uint8Array\", \"of\"},\n\t{\"Uint8ClampedArray\", \"from\"},\n\t{\"Uint8ClampedArray\", \"of\"},\n\n\t// Other globals present in both the browser and node. This should include at\n\t// least the following properties:\n\t// https://tc39.es/ecma262/multipage/global-object.html#sec-constructor-properties-of-the-global-object\n\t//\n\t// Exceptions:\n\t// - Don't include \"eval\" because it has special behavior\n\t// - Don't include \"NaN\", \"Infinity\", and \"undefined\" because esbuild treats\n\t//   these as automatically-inlined constants instead of identifiers\n\t{\"AbortController\"},\n\t{\"AbortSignal\"},\n\t{\"AggregateError\"},\n\t{\"Array\"},\n\t{\"ArrayBuffer\"},\n\t{\"Atomics\"},\n\t{\"BigInt\"},\n\t{\"BigInt64Array\"},\n\t{\"BigUint64Array\"},\n\t{\"Boolean\"},\n\t{\"DataView\"},\n\t{\"Date\"},\n\t{\"Error\"},\n\t{\"EvalError\"},\n\t{\"Event\"},\n\t{\"EventTarget\"},\n\t{\"FinalizationRegistry\"},\n\t{\"Float16Array\"},\n\t{\"Float32Array\"},\n\t{\"Float64Array\"},\n\t{\"Function\"},\n\t{\"Int16Array\"},\n\t{\"Int32Array\"},\n\t{\"Int8Array\"},\n\t{\"Intl\"},\n\t{\"Iterator\"},\n\t{\"JSON\"},\n\t{\"Map\"},\n\t{\"Math\"},\n\t{\"MessageChannel\"},\n\t{\"MessageEvent\"},\n\t{\"MessagePort\"},\n\t{\"Number\"},\n\t{\"Object\"},\n\t{\"Promise\"},\n\t{\"Proxy\"},\n\t{\"RangeError\"},\n\t{\"ReferenceError\"},\n\t{\"Reflect\"},\n\t{\"RegExp\"},\n\t{\"Set\"},\n\t{\"SharedArrayBuffer\"},\n\t{\"String\"},\n\t{\"Symbol\"},\n\t{\"SyntaxError\"},\n\t{\"TextDecoder\"},\n\t{\"TextEncoder\"},\n\t{\"TypeError\"},\n\t{\"URIError\"},\n\t{\"URL\"},\n\t{\"URLSearchParams\"},\n\t{\"Uint16Array\"},\n\t{\"Uint32Array\"},\n\t{\"Uint8Array\"},\n\t{\"Uint8ClampedArray\"},\n\t{\"WeakMap\"},\n\t{\"WeakRef\"},\n\t{\"WeakSet\"},\n\t{\"WebAssembly\"},\n\t{\"clearInterval\"},\n\t{\"clearTimeout\"},\n\t{\"console\"},\n\t{\"decodeURI\"},\n\t{\"decodeURIComponent\"},\n\t{\"encodeURI\"},\n\t{\"encodeURIComponent\"},\n\t{\"escape\"},\n\t{\"globalThis\"},\n\t{\"isFinite\"},\n\t{\"isNaN\"},\n\t{\"parseFloat\"},\n\t{\"parseInt\"},\n\t{\"queueMicrotask\"},\n\t{\"setInterval\"},\n\t{\"setTimeout\"},\n\t{\"unescape\"},\n\n\t// Console method references are assumed to have no side effects\n\t// https://developer.mozilla.org/en-US/docs/Web/API/console\n\t{\"console\", \"assert\"},\n\t{\"console\", \"clear\"},\n\t{\"console\", \"count\"},\n\t{\"console\", \"countReset\"},\n\t{\"console\", \"debug\"},\n\t{\"console\", \"dir\"},\n\t{\"console\", \"dirxml\"},\n\t{\"console\", \"error\"},\n\t{\"console\", \"group\"},\n\t{\"console\", \"groupCollapsed\"},\n\t{\"console\", \"groupEnd\"},\n\t{\"console\", \"info\"},\n\t{\"console\", \"log\"},\n\t{\"console\", \"table\"},\n\t{\"console\", \"time\"},\n\t{\"console\", \"timeEnd\"},\n\t{\"console\", \"timeLog\"},\n\t{\"console\", \"trace\"},\n\t{\"console\", \"warn\"},\n\n\t// CSSOM APIs\n\t{\"CSSAnimation\"},\n\t{\"CSSFontFaceRule\"},\n\t{\"CSSImportRule\"},\n\t{\"CSSKeyframeRule\"},\n\t{\"CSSKeyframesRule\"},\n\t{\"CSSMediaRule\"},\n\t{\"CSSNamespaceRule\"},\n\t{\"CSSPageRule\"},\n\t{\"CSSRule\"},\n\t{\"CSSRuleList\"},\n\t{\"CSSStyleDeclaration\"},\n\t{\"CSSStyleRule\"},\n\t{\"CSSStyleSheet\"},\n\t{\"CSSSupportsRule\"},\n\t{\"CSSTransition\"},\n\n\t// SVG DOM\n\t{\"SVGAElement\"},\n\t{\"SVGAngle\"},\n\t{\"SVGAnimateElement\"},\n\t{\"SVGAnimateMotionElement\"},\n\t{\"SVGAnimateTransformElement\"},\n\t{\"SVGAnimatedAngle\"},\n\t{\"SVGAnimatedBoolean\"},\n\t{\"SVGAnimatedEnumeration\"},\n\t{\"SVGAnimatedInteger\"},\n\t{\"SVGAnimatedLength\"},\n\t{\"SVGAnimatedLengthList\"},\n\t{\"SVGAnimatedNumber\"},\n\t{\"SVGAnimatedNumberList\"},\n\t{\"SVGAnimatedPreserveAspectRatio\"},\n\t{\"SVGAnimatedRect\"},\n\t{\"SVGAnimatedString\"},\n\t{\"SVGAnimatedTransformList\"},\n\t{\"SVGAnimationElement\"},\n\t{\"SVGCircleElement\"},\n\t{\"SVGClipPathElement\"},\n\t{\"SVGComponentTransferFunctionElement\"},\n\t{\"SVGDefsElement\"},\n\t{\"SVGDescElement\"},\n\t{\"SVGElement\"},\n\t{\"SVGEllipseElement\"},\n\t{\"SVGFEBlendElement\"},\n\t{\"SVGFEColorMatrixElement\"},\n\t{\"SVGFEComponentTransferElement\"},\n\t{\"SVGFECompositeElement\"},\n\t{\"SVGFEConvolveMatrixElement\"},\n\t{\"SVGFEDiffuseLightingElement\"},\n\t{\"SVGFEDisplacementMapElement\"},\n\t{\"SVGFEDistantLightElement\"},\n\t{\"SVGFEDropShadowElement\"},\n\t{\"SVGFEFloodElement\"},\n\t{\"SVGFEFuncAElement\"},\n\t{\"SVGFEFuncBElement\"},\n\t{\"SVGFEFuncGElement\"},\n\t{\"SVGFEFuncRElement\"},\n\t{\"SVGFEGaussianBlurElement\"},\n\t{\"SVGFEImageElement\"},\n\t{\"SVGFEMergeElement\"},\n\t{\"SVGFEMergeNodeElement\"},\n\t{\"SVGFEMorphologyElement\"},\n\t{\"SVGFEOffsetElement\"},\n\t{\"SVGFEPointLightElement\"},\n\t{\"SVGFESpecularLightingElement\"},\n\t{\"SVGFESpotLightElement\"},\n\t{\"SVGFETileElement\"},\n\t{\"SVGFETurbulenceElement\"},\n\t{\"SVGFilterElement\"},\n\t{\"SVGForeignObjectElement\"},\n\t{\"SVGGElement\"},\n\t{\"SVGGeometryElement\"},\n\t{\"SVGGradientElement\"},\n\t{\"SVGGraphicsElement\"},\n\t{\"SVGImageElement\"},\n\t{\"SVGLength\"},\n\t{\"SVGLengthList\"},\n\t{\"SVGLineElement\"},\n\t{\"SVGLinearGradientElement\"},\n\t{\"SVGMPathElement\"},\n\t{\"SVGMarkerElement\"},\n\t{\"SVGMaskElement\"},\n\t{\"SVGMatrix\"},\n\t{\"SVGMetadataElement\"},\n\t{\"SVGNumber\"},\n\t{\"SVGNumberList\"},\n\t{\"SVGPathElement\"},\n\t{\"SVGPatternElement\"},\n\t{\"SVGPoint\"},\n\t{\"SVGPointList\"},\n\t{\"SVGPolygonElement\"},\n\t{\"SVGPolylineElement\"},\n\t{\"SVGPreserveAspectRatio\"},\n\t{\"SVGRadialGradientElement\"},\n\t{\"SVGRect\"},\n\t{\"SVGRectElement\"},\n\t{\"SVGSVGElement\"},\n\t{\"SVGScriptElement\"},\n\t{\"SVGSetElement\"},\n\t{\"SVGStopElement\"},\n\t{\"SVGStringList\"},\n\t{\"SVGStyleElement\"},\n\t{\"SVGSwitchElement\"},\n\t{\"SVGSymbolElement\"},\n\t{\"SVGTSpanElement\"},\n\t{\"SVGTextContentElement\"},\n\t{\"SVGTextElement\"},\n\t{\"SVGTextPathElement\"},\n\t{\"SVGTextPositioningElement\"},\n\t{\"SVGTitleElement\"},\n\t{\"SVGTransform\"},\n\t{\"SVGTransformList\"},\n\t{\"SVGUnitTypes\"},\n\t{\"SVGUseElement\"},\n\t{\"SVGViewElement\"},\n\n\t// Other browser APIs\n\t//\n\t// This list contains all globals present in modern versions of Chrome, Safari,\n\t// and Firefox except for the following properties, since they have a side effect\n\t// of triggering layout (https://gist.github.com/paulirish/5d52fb081b3570c81e3a):\n\t//\n\t//   - scrollX\n\t//   - scrollY\n\t//   - innerWidth\n\t//   - innerHeight\n\t//   - pageXOffset\n\t//   - pageYOffset\n\t//\n\t// The following globals have also been removed since they sometimes throw an\n\t// exception when accessed, which is a side effect (for more information see\n\t// https://stackoverflow.com/a/33047477):\n\t//\n\t//   - localStorage\n\t//   - sessionStorage\n\t//\n\t{\"AnalyserNode\"},\n\t{\"Animation\"},\n\t{\"AnimationEffect\"},\n\t{\"AnimationEvent\"},\n\t{\"AnimationPlaybackEvent\"},\n\t{\"AnimationTimeline\"},\n\t{\"Attr\"},\n\t{\"Audio\"},\n\t{\"AudioBuffer\"},\n\t{\"AudioBufferSourceNode\"},\n\t{\"AudioDestinationNode\"},\n\t{\"AudioListener\"},\n\t{\"AudioNode\"},\n\t{\"AudioParam\"},\n\t{\"AudioProcessingEvent\"},\n\t{\"AudioScheduledSourceNode\"},\n\t{\"BarProp\"},\n\t{\"BeforeUnloadEvent\"},\n\t{\"BiquadFilterNode\"},\n\t{\"Blob\"},\n\t{\"BlobEvent\"},\n\t{\"ByteLengthQueuingStrategy\"},\n\t{\"CDATASection\"},\n\t{\"CSS\"},\n\t{\"CanvasGradient\"},\n\t{\"CanvasPattern\"},\n\t{\"CanvasRenderingContext2D\"},\n\t{\"ChannelMergerNode\"},\n\t{\"ChannelSplitterNode\"},\n\t{\"CharacterData\"},\n\t{\"ClipboardEvent\"},\n\t{\"CloseEvent\"},\n\t{\"Comment\"},\n\t{\"CompositionEvent\"},\n\t{\"ConvolverNode\"},\n\t{\"CountQueuingStrategy\"},\n\t{\"Crypto\"},\n\t{\"CustomElementRegistry\"},\n\t{\"CustomEvent\"},\n\t{\"DOMException\"},\n\t{\"DOMImplementation\"},\n\t{\"DOMMatrix\"},\n\t{\"DOMMatrixReadOnly\"},\n\t{\"DOMParser\"},\n\t{\"DOMPoint\"},\n\t{\"DOMPointReadOnly\"},\n\t{\"DOMQuad\"},\n\t{\"DOMRect\"},\n\t{\"DOMRectList\"},\n\t{\"DOMRectReadOnly\"},\n\t{\"DOMStringList\"},\n\t{\"DOMStringMap\"},\n\t{\"DOMTokenList\"},\n\t{\"DataTransfer\"},\n\t{\"DataTransferItem\"},\n\t{\"DataTransferItemList\"},\n\t{\"DelayNode\"},\n\t{\"Document\"},\n\t{\"DocumentFragment\"},\n\t{\"DocumentTimeline\"},\n\t{\"DocumentType\"},\n\t{\"DragEvent\"},\n\t{\"DynamicsCompressorNode\"},\n\t{\"Element\"},\n\t{\"ErrorEvent\"},\n\t{\"EventSource\"},\n\t{\"File\"},\n\t{\"FileList\"},\n\t{\"FileReader\"},\n\t{\"FocusEvent\"},\n\t{\"FontFace\"},\n\t{\"FormData\"},\n\t{\"GainNode\"},\n\t{\"Gamepad\"},\n\t{\"GamepadButton\"},\n\t{\"GamepadEvent\"},\n\t{\"Geolocation\"},\n\t{\"GeolocationPositionError\"},\n\t{\"HTMLAllCollection\"},\n\t{\"HTMLAnchorElement\"},\n\t{\"HTMLAreaElement\"},\n\t{\"HTMLAudioElement\"},\n\t{\"HTMLBRElement\"},\n\t{\"HTMLBaseElement\"},\n\t{\"HTMLBodyElement\"},\n\t{\"HTMLButtonElement\"},\n\t{\"HTMLCanvasElement\"},\n\t{\"HTMLCollection\"},\n\t{\"HTMLDListElement\"},\n\t{\"HTMLDataElement\"},\n\t{\"HTMLDataListElement\"},\n\t{\"HTMLDetailsElement\"},\n\t{\"HTMLDirectoryElement\"},\n\t{\"HTMLDivElement\"},\n\t{\"HTMLDocument\"},\n\t{\"HTMLElement\"},\n\t{\"HTMLEmbedElement\"},\n\t{\"HTMLFieldSetElement\"},\n\t{\"HTMLFontElement\"},\n\t{\"HTMLFormControlsCollection\"},\n\t{\"HTMLFormElement\"},\n\t{\"HTMLFrameElement\"},\n\t{\"HTMLFrameSetElement\"},\n\t{\"HTMLHRElement\"},\n\t{\"HTMLHeadElement\"},\n\t{\"HTMLHeadingElement\"},\n\t{\"HTMLHtmlElement\"},\n\t{\"HTMLIFrameElement\"},\n\t{\"HTMLImageElement\"},\n\t{\"HTMLInputElement\"},\n\t{\"HTMLLIElement\"},\n\t{\"HTMLLabelElement\"},\n\t{\"HTMLLegendElement\"},\n\t{\"HTMLLinkElement\"},\n\t{\"HTMLMapElement\"},\n\t{\"HTMLMarqueeElement\"},\n\t{\"HTMLMediaElement\"},\n\t{\"HTMLMenuElement\"},\n\t{\"HTMLMetaElement\"},\n\t{\"HTMLMeterElement\"},\n\t{\"HTMLModElement\"},\n\t{\"HTMLOListElement\"},\n\t{\"HTMLObjectElement\"},\n\t{\"HTMLOptGroupElement\"},\n\t{\"HTMLOptionElement\"},\n\t{\"HTMLOptionsCollection\"},\n\t{\"HTMLOutputElement\"},\n\t{\"HTMLParagraphElement\"},\n\t{\"HTMLParamElement\"},\n\t{\"HTMLPictureElement\"},\n\t{\"HTMLPreElement\"},\n\t{\"HTMLProgressElement\"},\n\t{\"HTMLQuoteElement\"},\n\t{\"HTMLScriptElement\"},\n\t{\"HTMLSelectElement\"},\n\t{\"HTMLSlotElement\"},\n\t{\"HTMLSourceElement\"},\n\t{\"HTMLSpanElement\"},\n\t{\"HTMLStyleElement\"},\n\t{\"HTMLTableCaptionElement\"},\n\t{\"HTMLTableCellElement\"},\n\t{\"HTMLTableColElement\"},\n\t{\"HTMLTableElement\"},\n\t{\"HTMLTableRowElement\"},\n\t{\"HTMLTableSectionElement\"},\n\t{\"HTMLTemplateElement\"},\n\t{\"HTMLTextAreaElement\"},\n\t{\"HTMLTimeElement\"},\n\t{\"HTMLTitleElement\"},\n\t{\"HTMLTrackElement\"},\n\t{\"HTMLUListElement\"},\n\t{\"HTMLUnknownElement\"},\n\t{\"HTMLVideoElement\"},\n\t{\"HashChangeEvent\"},\n\t{\"Headers\"},\n\t{\"History\"},\n\t{\"IDBCursor\"},\n\t{\"IDBCursorWithValue\"},\n\t{\"IDBDatabase\"},\n\t{\"IDBFactory\"},\n\t{\"IDBIndex\"},\n\t{\"IDBKeyRange\"},\n\t{\"IDBObjectStore\"},\n\t{\"IDBOpenDBRequest\"},\n\t{\"IDBRequest\"},\n\t{\"IDBTransaction\"},\n\t{\"IDBVersionChangeEvent\"},\n\t{\"Image\"},\n\t{\"ImageData\"},\n\t{\"InputEvent\"},\n\t{\"IntersectionObserver\"},\n\t{\"IntersectionObserverEntry\"},\n\t{\"KeyboardEvent\"},\n\t{\"KeyframeEffect\"},\n\t{\"Location\"},\n\t{\"MediaCapabilities\"},\n\t{\"MediaElementAudioSourceNode\"},\n\t{\"MediaEncryptedEvent\"},\n\t{\"MediaError\"},\n\t{\"MediaList\"},\n\t{\"MediaQueryList\"},\n\t{\"MediaQueryListEvent\"},\n\t{\"MediaRecorder\"},\n\t{\"MediaSource\"},\n\t{\"MediaStream\"},\n\t{\"MediaStreamAudioDestinationNode\"},\n\t{\"MediaStreamAudioSourceNode\"},\n\t{\"MediaStreamTrack\"},\n\t{\"MediaStreamTrackEvent\"},\n\t{\"MimeType\"},\n\t{\"MimeTypeArray\"},\n\t{\"MouseEvent\"},\n\t{\"MutationEvent\"},\n\t{\"MutationObserver\"},\n\t{\"MutationRecord\"},\n\t{\"NamedNodeMap\"},\n\t{\"Navigator\"},\n\t{\"Node\"},\n\t{\"NodeFilter\"},\n\t{\"NodeIterator\"},\n\t{\"NodeList\"},\n\t{\"Notification\"},\n\t{\"OfflineAudioCompletionEvent\"},\n\t{\"Option\"},\n\t{\"OscillatorNode\"},\n\t{\"PageTransitionEvent\"},\n\t{\"Path2D\"},\n\t{\"Performance\"},\n\t{\"PerformanceEntry\"},\n\t{\"PerformanceMark\"},\n\t{\"PerformanceMeasure\"},\n\t{\"PerformanceNavigation\"},\n\t{\"PerformanceObserver\"},\n\t{\"PerformanceObserverEntryList\"},\n\t{\"PerformanceResourceTiming\"},\n\t{\"PerformanceTiming\"},\n\t{\"PeriodicWave\"},\n\t{\"Plugin\"},\n\t{\"PluginArray\"},\n\t{\"PointerEvent\"},\n\t{\"PopStateEvent\"},\n\t{\"ProcessingInstruction\"},\n\t{\"ProgressEvent\"},\n\t{\"PromiseRejectionEvent\"},\n\t{\"RTCCertificate\"},\n\t{\"RTCDTMFSender\"},\n\t{\"RTCDTMFToneChangeEvent\"},\n\t{\"RTCDataChannel\"},\n\t{\"RTCDataChannelEvent\"},\n\t{\"RTCIceCandidate\"},\n\t{\"RTCPeerConnection\"},\n\t{\"RTCPeerConnectionIceEvent\"},\n\t{\"RTCRtpReceiver\"},\n\t{\"RTCRtpSender\"},\n\t{\"RTCRtpTransceiver\"},\n\t{\"RTCSessionDescription\"},\n\t{\"RTCStatsReport\"},\n\t{\"RTCTrackEvent\"},\n\t{\"RadioNodeList\"},\n\t{\"Range\"},\n\t{\"ReadableStream\"},\n\t{\"Request\"},\n\t{\"ResizeObserver\"},\n\t{\"ResizeObserverEntry\"},\n\t{\"Response\"},\n\t{\"Screen\"},\n\t{\"ScriptProcessorNode\"},\n\t{\"SecurityPolicyViolationEvent\"},\n\t{\"Selection\"},\n\t{\"ShadowRoot\"},\n\t{\"SourceBuffer\"},\n\t{\"SourceBufferList\"},\n\t{\"SpeechSynthesisEvent\"},\n\t{\"SpeechSynthesisUtterance\"},\n\t{\"StaticRange\"},\n\t{\"Storage\"},\n\t{\"StorageEvent\"},\n\t{\"StyleSheet\"},\n\t{\"StyleSheetList\"},\n\t{\"Text\"},\n\t{\"TextMetrics\"},\n\t{\"TextTrack\"},\n\t{\"TextTrackCue\"},\n\t{\"TextTrackCueList\"},\n\t{\"TextTrackList\"},\n\t{\"TimeRanges\"},\n\t{\"TrackEvent\"},\n\t{\"TransitionEvent\"},\n\t{\"TreeWalker\"},\n\t{\"UIEvent\"},\n\t{\"VTTCue\"},\n\t{\"ValidityState\"},\n\t{\"VisualViewport\"},\n\t{\"WaveShaperNode\"},\n\t{\"WebGLActiveInfo\"},\n\t{\"WebGLBuffer\"},\n\t{\"WebGLContextEvent\"},\n\t{\"WebGLFramebuffer\"},\n\t{\"WebGLProgram\"},\n\t{\"WebGLQuery\"},\n\t{\"WebGLRenderbuffer\"},\n\t{\"WebGLRenderingContext\"},\n\t{\"WebGLSampler\"},\n\t{\"WebGLShader\"},\n\t{\"WebGLShaderPrecisionFormat\"},\n\t{\"WebGLSync\"},\n\t{\"WebGLTexture\"},\n\t{\"WebGLUniformLocation\"},\n\t{\"WebKitCSSMatrix\"},\n\t{\"WebSocket\"},\n\t{\"WheelEvent\"},\n\t{\"Window\"},\n\t{\"Worker\"},\n\t{\"XMLDocument\"},\n\t{\"XMLHttpRequest\"},\n\t{\"XMLHttpRequestEventTarget\"},\n\t{\"XMLHttpRequestUpload\"},\n\t{\"XMLSerializer\"},\n\t{\"XPathEvaluator\"},\n\t{\"XPathExpression\"},\n\t{\"XPathResult\"},\n\t{\"XSLTProcessor\"},\n\t{\"alert\"},\n\t{\"atob\"},\n\t{\"blur\"},\n\t{\"btoa\"},\n\t{\"cancelAnimationFrame\"},\n\t{\"captureEvents\"},\n\t{\"close\"},\n\t{\"closed\"},\n\t{\"confirm\"},\n\t{\"customElements\"},\n\t{\"devicePixelRatio\"},\n\t{\"document\"},\n\t{\"event\"},\n\t{\"fetch\"},\n\t{\"find\"},\n\t{\"focus\"},\n\t{\"frameElement\"},\n\t{\"frames\"},\n\t{\"getComputedStyle\"},\n\t{\"getSelection\"},\n\t{\"history\"},\n\t{\"indexedDB\"},\n\t{\"isSecureContext\"},\n\t{\"length\"},\n\t{\"location\"},\n\t{\"locationbar\"},\n\t{\"matchMedia\"},\n\t{\"menubar\"},\n\t{\"moveBy\"},\n\t{\"moveTo\"},\n\t{\"name\"},\n\t{\"navigator\"},\n\t{\"onabort\"},\n\t{\"onafterprint\"},\n\t{\"onanimationend\"},\n\t{\"onanimationiteration\"},\n\t{\"onanimationstart\"},\n\t{\"onbeforeprint\"},\n\t{\"onbeforeunload\"},\n\t{\"onblur\"},\n\t{\"oncanplay\"},\n\t{\"oncanplaythrough\"},\n\t{\"onchange\"},\n\t{\"onclick\"},\n\t{\"oncontextmenu\"},\n\t{\"oncuechange\"},\n\t{\"ondblclick\"},\n\t{\"ondrag\"},\n\t{\"ondragend\"},\n\t{\"ondragenter\"},\n\t{\"ondragleave\"},\n\t{\"ondragover\"},\n\t{\"ondragstart\"},\n\t{\"ondrop\"},\n\t{\"ondurationchange\"},\n\t{\"onemptied\"},\n\t{\"onended\"},\n\t{\"onerror\"},\n\t{\"onfocus\"},\n\t{\"ongotpointercapture\"},\n\t{\"onhashchange\"},\n\t{\"oninput\"},\n\t{\"oninvalid\"},\n\t{\"onkeydown\"},\n\t{\"onkeypress\"},\n\t{\"onkeyup\"},\n\t{\"onlanguagechange\"},\n\t{\"onload\"},\n\t{\"onloadeddata\"},\n\t{\"onloadedmetadata\"},\n\t{\"onloadstart\"},\n\t{\"onlostpointercapture\"},\n\t{\"onmessage\"},\n\t{\"onmousedown\"},\n\t{\"onmouseenter\"},\n\t{\"onmouseleave\"},\n\t{\"onmousemove\"},\n\t{\"onmouseout\"},\n\t{\"onmouseover\"},\n\t{\"onmouseup\"},\n\t{\"onoffline\"},\n\t{\"ononline\"},\n\t{\"onpagehide\"},\n\t{\"onpageshow\"},\n\t{\"onpause\"},\n\t{\"onplay\"},\n\t{\"onplaying\"},\n\t{\"onpointercancel\"},\n\t{\"onpointerdown\"},\n\t{\"onpointerenter\"},\n\t{\"onpointerleave\"},\n\t{\"onpointermove\"},\n\t{\"onpointerout\"},\n\t{\"onpointerover\"},\n\t{\"onpointerup\"},\n\t{\"onpopstate\"},\n\t{\"onprogress\"},\n\t{\"onratechange\"},\n\t{\"onrejectionhandled\"},\n\t{\"onreset\"},\n\t{\"onresize\"},\n\t{\"onscroll\"},\n\t{\"onseeked\"},\n\t{\"onseeking\"},\n\t{\"onselect\"},\n\t{\"onstalled\"},\n\t{\"onstorage\"},\n\t{\"onsubmit\"},\n\t{\"onsuspend\"},\n\t{\"ontimeupdate\"},\n\t{\"ontoggle\"},\n\t{\"ontransitioncancel\"},\n\t{\"ontransitionend\"},\n\t{\"ontransitionrun\"},\n\t{\"ontransitionstart\"},\n\t{\"onunhandledrejection\"},\n\t{\"onunload\"},\n\t{\"onvolumechange\"},\n\t{\"onwaiting\"},\n\t{\"onwebkitanimationend\"},\n\t{\"onwebkitanimationiteration\"},\n\t{\"onwebkitanimationstart\"},\n\t{\"onwebkittransitionend\"},\n\t{\"onwheel\"},\n\t{\"open\"},\n\t{\"opener\"},\n\t{\"origin\"},\n\t{\"outerHeight\"},\n\t{\"outerWidth\"},\n\t{\"parent\"},\n\t{\"performance\"},\n\t{\"personalbar\"},\n\t{\"postMessage\"},\n\t{\"print\"},\n\t{\"prompt\"},\n\t{\"releaseEvents\"},\n\t{\"requestAnimationFrame\"},\n\t{\"resizeBy\"},\n\t{\"resizeTo\"},\n\t{\"screen\"},\n\t{\"screenLeft\"},\n\t{\"screenTop\"},\n\t{\"screenX\"},\n\t{\"screenY\"},\n\t{\"scroll\"},\n\t{\"scrollBy\"},\n\t{\"scrollTo\"},\n\t{\"scrollbars\"},\n\t{\"self\"},\n\t{\"speechSynthesis\"},\n\t{\"status\"},\n\t{\"statusbar\"},\n\t{\"stop\"},\n\t{\"toolbar\"},\n\t{\"top\"},\n\t{\"webkitURL\"},\n\t{\"window\"},\n}\n\n// We currently only support compile-time replacement with certain expressions:\n//\n//   - Primitive literals\n//   - Identifiers\n//   - \"Entity names\" which are identifiers followed by property accesses\n//\n// We don't support arbitrary expressions because arbitrary expressions may\n// require the full AST. For example, there could be \"import()\" or \"require()\"\n// expressions that need an import record. We also need to re-generate some\n// nodes such as identifiers within the injected context so that they can\n// bind to symbols in that context. Other expressions such as \"this\" may\n// also be contextual.\ntype DefineExpr struct {\n\tConstant            js_ast.E\n\tParts               []string\n\tInjectedDefineIndex ast.Index32\n}\n\ntype DefineData struct {\n\tKeyParts   []string\n\tDefineExpr *DefineExpr\n\tFlags      DefineFlags\n}\n\ntype DefineFlags uint8\n\nconst (\n\t// True if accessing this value is known to not have any side effects. For\n\t// example, a bare reference to \"Object.create\" can be removed because it\n\t// does not have any observable side effects.\n\tCanBeRemovedIfUnused DefineFlags = 1 << iota\n\n\t// True if a call to this value is known to not have any side effects. For\n\t// example, a bare call to \"Object()\" can be removed because it does not\n\t// have any observable side effects.\n\tCallCanBeUnwrappedIfUnused\n\n\t// If true, the user has indicated that every direct calls to a property on\n\t// this object and all of that call's arguments are to be removed from the\n\t// output, even when the arguments have side effects. This is used to\n\t// implement the \"--drop:console\" flag.\n\tMethodCallsMustBeReplacedWithUndefined\n\n\t// Symbol values are known to not have side effects when used as property\n\t// names in class declarations and object literals.\n\tIsSymbolInstance\n)\n\nfunc (flags DefineFlags) Has(flag DefineFlags) bool {\n\treturn (flags & flag) != 0\n}\n\nfunc mergeDefineData(old DefineData, new DefineData) DefineData {\n\tnew.Flags |= old.Flags\n\treturn new\n}\n\ntype ProcessedDefines struct {\n\tIdentifierDefines map[string]DefineData\n\tDotDefines        map[string][]DefineData\n}\n\n// This transformation is expensive, so we only want to do it once. Make sure\n// to only call processDefines() once per compilation. Unfortunately Golang\n// doesn't have an efficient way to copy a map and the overhead of copying\n// all of the properties into a new map once for every new parser noticeably\n// slows down our benchmarks.\nfunc ProcessDefines(userDefines []DefineData) ProcessedDefines {\n\t// Optimization: reuse known globals if there are no user-specified defines\n\thasUserDefines := len(userDefines) != 0\n\tif !hasUserDefines {\n\t\tprocessedGlobalsMutex.Lock()\n\t\tif processedGlobals != nil {\n\t\t\tdefer processedGlobalsMutex.Unlock()\n\t\t\treturn *processedGlobals\n\t\t}\n\t\tprocessedGlobalsMutex.Unlock()\n\t}\n\n\tresult := ProcessedDefines{\n\t\tIdentifierDefines: make(map[string]DefineData),\n\t\tDotDefines:        make(map[string][]DefineData),\n\t}\n\n\t// Mark these property accesses as free of side effects. That means they can\n\t// be removed if their result is unused. We can't just remove all unused\n\t// property accesses since property accesses can have side effects. For\n\t// example, the property access \"a.b.c\" has the side effect of throwing an\n\t// exception if \"a.b\" is undefined.\n\tfor _, parts := range knownGlobals {\n\t\ttail := parts[len(parts)-1]\n\t\tif len(parts) == 1 {\n\t\t\tresult.IdentifierDefines[tail] = DefineData{Flags: CanBeRemovedIfUnused}\n\t\t} else {\n\t\t\tflags := CanBeRemovedIfUnused\n\n\t\t\t// All properties on the \"Symbol\" global are currently symbol instances\n\t\t\t// (i.e. \"typeof Symbol.iterator === 'symbol'\"). This is used to avoid\n\t\t\t// treating properties with these names as having side effects.\n\t\t\tif parts[0] == \"Symbol\" {\n\t\t\t\tflags |= IsSymbolInstance\n\t\t\t}\n\n\t\t\tresult.DotDefines[tail] = append(result.DotDefines[tail], DefineData{KeyParts: parts, Flags: flags})\n\t\t}\n\t}\n\n\t// Swap in certain literal values because those can be constant folded\n\tresult.IdentifierDefines[\"undefined\"] = DefineData{\n\t\tDefineExpr: &DefineExpr{Constant: js_ast.EUndefinedShared},\n\t}\n\tresult.IdentifierDefines[\"NaN\"] = DefineData{\n\t\tDefineExpr: &DefineExpr{Constant: &js_ast.ENumber{Value: math.NaN()}},\n\t}\n\tresult.IdentifierDefines[\"Infinity\"] = DefineData{\n\t\tDefineExpr: &DefineExpr{Constant: &js_ast.ENumber{Value: math.Inf(1)}},\n\t}\n\n\t// Then copy the user-specified defines in afterwards, which will overwrite\n\t// any known globals above.\n\tfor _, data := range userDefines {\n\t\t// Identifier defines are special-cased\n\t\tif len(data.KeyParts) == 1 {\n\t\t\tname := data.KeyParts[0]\n\t\t\tresult.IdentifierDefines[name] = mergeDefineData(result.IdentifierDefines[name], data)\n\t\t\tcontinue\n\t\t}\n\n\t\ttail := data.KeyParts[len(data.KeyParts)-1]\n\t\tdotDefines := result.DotDefines[tail]\n\t\tfound := false\n\n\t\t// Try to merge with existing dot defines first\n\t\tfor i, define := range dotDefines {\n\t\t\tif helpers.StringArraysEqual(data.KeyParts, define.KeyParts) {\n\t\t\t\tdotDefines[i] = mergeDefineData(dotDefines[i], data)\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif !found {\n\t\t\tdotDefines = append(dotDefines, data)\n\t\t}\n\t\tresult.DotDefines[tail] = dotDefines\n\t}\n\n\t// Potentially cache the result for next time\n\tif !hasUserDefines {\n\t\tprocessedGlobalsMutex.Lock()\n\t\tdefer processedGlobalsMutex.Unlock()\n\t\tif processedGlobals == nil {\n\t\t\tprocessedGlobals = &result\n\t\t}\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_ast/css_ast.go",
    "content": "package css_ast\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\n// CSS syntax comes in two layers: a minimal syntax that generally accepts\n// anything that looks vaguely like CSS, and a large set of built-in rules\n// (the things browsers actually interpret). That way CSS parsers can read\n// unknown rules and skip over them without having to stop due to errors.\n//\n// This AST format is mostly just the minimal syntax. It parses unknown rules\n// into a tree with enough information that it can write them back out again.\n// There are some additional layers of syntax including selectors and @-rules\n// which allow for better pretty-printing and minification.\n//\n// Most of the AST just references ranges of the original file by keeping the\n// original \"Token\" values around from the lexer. This is a memory-efficient\n// representation that helps provide good parsing and printing performance.\n\ntype AST struct {\n\tSymbols              []ast.Symbol\n\tCharFreq             *ast.CharFreq\n\tImportRecords        []ast.ImportRecord\n\tRules                []Rule\n\tSourceMapComment     logger.Span\n\tApproximateLineCount int32\n\tLocalSymbols         []ast.LocRef\n\tLocalScope           map[string]ast.LocRef\n\tGlobalScope          map[string]ast.LocRef\n\tComposes             map[ast.Ref]*Composes\n\n\t// These contain all layer names in the file. It can be used to replace the\n\t// layer-related side effects of importing this file. They are split into two\n\t// groups (those before and after \"@import\" rules) so that the linker can put\n\t// them in the right places.\n\tLayersPreImport  [][]string\n\tLayersPostImport [][]string\n}\n\ntype Composes struct {\n\t// Note that each of these can be either local or global. Local examples:\n\t//\n\t//   .foo { composes: bar }\n\t//   .bar { color: red }\n\t//\n\t// Global examples:\n\t//\n\t//   .foo { composes: bar from global }\n\t//   .foo :global { composes: bar }\n\t//   .foo { :global { composes: bar } }\n\t//   :global .bar { color: red }\n\t//\n\tNames []ast.LocRef\n\n\t// Each of these is local in another file. For example:\n\t//\n\t//   .foo { composes: bar from \"bar.css\" }\n\t//   .foo { composes: bar from url(bar.css) }\n\t//\n\tImportedNames []ImportedComposesName\n\n\t// This tracks what CSS properties each class uses so that we can warn when\n\t// \"composes\" is used incorrectly to compose two classes from separate files\n\t// that declare the same CSS properties.\n\tProperties map[string]logger.Loc\n}\n\ntype ImportedComposesName struct {\n\tAlias             string\n\tAliasLoc          logger.Loc\n\tImportRecordIndex uint32\n}\n\n// We create a lot of tokens, so make sure this layout is memory-efficient.\n// The layout here isn't optimal because it biases for convenience (e.g.\n// \"string\" could be shorter) but at least the ordering of fields was\n// deliberately chosen to minimize size.\ntype Token struct {\n\t// Contains the child tokens for component values that are simple blocks.\n\t// These are either \"(\", \"{\", \"[\", or function tokens. The closing token is\n\t// implicit and is not stored.\n\tChildren *[]Token // 8 bytes\n\n\t// This is the raw contents of the token most of the time. However, it\n\t// contains the decoded string contents for \"TString\" tokens.\n\tText string // 16 bytes\n\n\t// The source location at the start of the token\n\tLoc logger.Loc // 4 bytes\n\n\t// URL tokens have an associated import record at the top-level of the AST.\n\t// This index points to that import record.\n\t//\n\t// Symbol tokens have an associated symbol. This index is the \"InnerIndex\"\n\t// of the \"Ref\" for this symbol. The \"SourceIndex\" for the \"Ref\" is just\n\t// the source index of the file for this AST.\n\tPayloadIndex uint32 // 4 bytes\n\n\t// The division between the number and the unit for \"TDimension\" tokens.\n\tUnitOffset uint16 // 2 bytes\n\n\t// This will never be \"TWhitespace\" because whitespace isn't stored as a\n\t// token directly. Instead it is stored in \"HasWhitespaceAfter\" on the\n\t// previous token. This is to make it easier to pattern-match against\n\t// tokens when handling CSS rules, since whitespace almost always doesn't\n\t// matter. That way you can pattern match against e.g. \"rgb(r, g, b)\" and\n\t// not have to handle all possible combinations of embedded whitespace\n\t// tokens.\n\t//\n\t// There is one exception to this: when in verbatim whitespace mode and\n\t// the token list is non-empty and is only whitespace tokens. In that case\n\t// a single whitespace token is emitted. This is because otherwise there\n\t// would be no tokens to attach the whitespace before/after flags to.\n\tKind css_lexer.T // 1 byte\n\n\t// These flags indicate the presence of a \"TWhitespace\" token before or after\n\t// this token. There should be whitespace printed between two tokens if either\n\t// token indicates that there should be whitespace. Note that whitespace may\n\t// be altered by processing in certain situations (e.g. minification).\n\tWhitespace WhitespaceFlags // 1 byte\n}\n\ntype WhitespaceFlags uint8\n\nconst (\n\tWhitespaceBefore WhitespaceFlags = 1 << iota\n\tWhitespaceAfter\n)\n\n// This is necessary when comparing tokens between two different files\ntype CrossFileEqualityCheck struct {\n\tImportRecordsA []ast.ImportRecord\n\tImportRecordsB []ast.ImportRecord\n\tSymbols        ast.SymbolMap\n\tSourceIndexA   uint32\n\tSourceIndexB   uint32\n}\n\nfunc (check *CrossFileEqualityCheck) RefsAreEquivalent(a ast.Ref, b ast.Ref) bool {\n\tif a == b {\n\t\treturn true\n\t}\n\tif check == nil || check.Symbols.SymbolsForSource == nil {\n\t\treturn false\n\t}\n\ta = ast.FollowSymbols(check.Symbols, a)\n\tb = ast.FollowSymbols(check.Symbols, b)\n\tif a == b {\n\t\treturn true\n\t}\n\tsymbolA := check.Symbols.Get(a)\n\tsymbolB := check.Symbols.Get(b)\n\treturn symbolA.Kind == ast.SymbolGlobalCSS && symbolB.Kind == ast.SymbolGlobalCSS && symbolA.OriginalName == symbolB.OriginalName\n}\n\nfunc (a Token) Equal(b Token, check *CrossFileEqualityCheck) bool {\n\tif a.Kind == b.Kind && a.Text == b.Text && a.Whitespace == b.Whitespace {\n\t\t// URLs should be compared based on the text of the associated import record\n\t\t// (which is what will actually be printed) instead of the original text\n\t\tif a.Kind == css_lexer.TURL {\n\t\t\tif check == nil {\n\t\t\t\t// If both tokens are in the same file, just compare the index\n\t\t\t\tif a.PayloadIndex != b.PayloadIndex {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If the tokens come from separate files, compare the import records\n\t\t\t\t// themselves instead of comparing the indices. This can happen when\n\t\t\t\t// the linker runs a \"DuplicateRuleRemover\" during bundling. This\n\t\t\t\t// doesn't compare the source indices because at this point during\n\t\t\t\t// linking, paths inside the bundle (e.g. due to the \"copy\" loader)\n\t\t\t\t// should have already been converted into text (e.g. the \"unique key\"\n\t\t\t\t// string).\n\t\t\t\tif check.ImportRecordsA[a.PayloadIndex].Path.Text !=\n\t\t\t\t\tcheck.ImportRecordsB[b.PayloadIndex].Path.Text {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Symbols should be compared based on the symbol reference instead of the\n\t\t// original text\n\t\tif a.Kind == css_lexer.TSymbol {\n\t\t\tif check == nil {\n\t\t\t\t// If both tokens are in the same file, just compare the index\n\t\t\t\tif a.PayloadIndex != b.PayloadIndex {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If the tokens come from separate files, compare the symbols themselves\n\t\t\t\trefA := ast.Ref{SourceIndex: check.SourceIndexA, InnerIndex: a.PayloadIndex}\n\t\t\t\trefB := ast.Ref{SourceIndex: check.SourceIndexB, InnerIndex: b.PayloadIndex}\n\t\t\t\tif !check.RefsAreEquivalent(refA, refB) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif a.Children == nil && b.Children == nil {\n\t\t\treturn true\n\t\t}\n\n\t\tif a.Children != nil && b.Children != nil && TokensEqual(*a.Children, *b.Children, check) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc TokensEqual(a []Token, b []Token, check *CrossFileEqualityCheck) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, ai := range a {\n\t\tif !ai.Equal(b[i], check) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc HashTokens(hash uint32, tokens []Token) uint32 {\n\thash = helpers.HashCombine(hash, uint32(len(tokens)))\n\n\tfor _, t := range tokens {\n\t\thash = helpers.HashCombine(hash, uint32(t.Kind))\n\t\tif t.Kind != css_lexer.TURL {\n\t\t\thash = helpers.HashCombineString(hash, t.Text)\n\t\t}\n\t\tif t.Children != nil {\n\t\t\thash = HashTokens(hash, *t.Children)\n\t\t}\n\t}\n\n\treturn hash\n}\n\nfunc (a Token) EqualIgnoringWhitespace(b Token) bool {\n\tif a.Kind == b.Kind && a.Text == b.Text && a.PayloadIndex == b.PayloadIndex {\n\t\tif a.Children == nil && b.Children == nil {\n\t\t\treturn true\n\t\t}\n\n\t\tif a.Children != nil && b.Children != nil && TokensEqualIgnoringWhitespace(*a.Children, *b.Children) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc TokensEqualIgnoringWhitespace(a []Token, b []Token) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, c := range a {\n\t\tif !c.EqualIgnoringWhitespace(b[i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc TokensAreCommaSeparated(tokens []Token) bool {\n\tif n := len(tokens); (n & 1) != 0 {\n\t\tfor i := 1; i < n; i += 2 {\n\t\t\tif tokens[i].Kind != css_lexer.TComma {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\ntype PercentageFlags uint8\n\nconst (\n\tAllowPercentageBelow0 PercentageFlags = 1 << iota\n\tAllowPercentageAbove100\n\tAllowAnyPercentage = AllowPercentageBelow0 | AllowPercentageAbove100\n)\n\nfunc (t Token) NumberOrFractionForPercentage(percentReferenceRange float64, flags PercentageFlags) (float64, bool) {\n\tswitch t.Kind {\n\tcase css_lexer.TNumber:\n\t\tif f, err := strconv.ParseFloat(t.Text, 64); err == nil {\n\t\t\treturn f, true\n\t\t}\n\n\tcase css_lexer.TPercentage:\n\t\tif f, err := strconv.ParseFloat(t.PercentageValue(), 64); err == nil {\n\t\t\tif (flags&AllowPercentageBelow0) == 0 && f < 0 {\n\t\t\t\treturn 0, true\n\t\t\t}\n\t\t\tif (flags&AllowPercentageAbove100) == 0 && f > 100 {\n\t\t\t\treturn percentReferenceRange, true\n\t\t\t}\n\t\t\treturn f / 100 * percentReferenceRange, true\n\t\t}\n\t}\n\n\treturn 0, false\n}\n\nfunc (t Token) ClampedFractionForPercentage() (float64, bool) {\n\tif t.Kind == css_lexer.TPercentage {\n\t\tif f, err := strconv.ParseFloat(t.PercentageValue(), 64); err == nil {\n\t\t\tif f < 0 {\n\t\t\t\treturn 0, true\n\t\t\t}\n\t\t\tif f > 100 {\n\t\t\t\treturn 1, true\n\t\t\t}\n\t\t\treturn f / 100, true\n\t\t}\n\t}\n\n\treturn 0, false\n}\n\n// https://drafts.csswg.org/css-values-3/#lengths\n// For zero lengths the unit identifier is optional\n// (i.e. can be syntactically represented as the <number> 0).\nfunc (t *Token) TurnLengthIntoNumberIfZero() bool {\n\tif t.Kind == css_lexer.TDimension && t.DimensionValue() == \"0\" {\n\t\tt.Kind = css_lexer.TNumber\n\t\tt.Text = \"0\"\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (t *Token) TurnLengthOrPercentageIntoNumberIfZero() bool {\n\tif t.Kind == css_lexer.TPercentage && t.PercentageValue() == \"0\" {\n\t\tt.Kind = css_lexer.TNumber\n\t\tt.Text = \"0\"\n\t\treturn true\n\t}\n\treturn t.TurnLengthIntoNumberIfZero()\n}\n\nfunc (t Token) PercentageValue() string {\n\treturn t.Text[:len(t.Text)-1]\n}\n\nfunc (t Token) DimensionValue() string {\n\treturn t.Text[:t.UnitOffset]\n}\n\nfunc (t Token) DimensionUnit() string {\n\treturn t.Text[t.UnitOffset:]\n}\n\nfunc (t Token) DimensionUnitIsSafeLength() bool {\n\tswitch strings.ToLower(t.DimensionUnit()) {\n\t// These units can be reasonably expected to be supported everywhere.\n\t// Information used: https://developer.mozilla.org/en-US/docs/Web/CSS/length\n\tcase \"cm\", \"em\", \"in\", \"mm\", \"pc\", \"pt\", \"px\":\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (t Token) IsZero() bool {\n\treturn t.Kind == css_lexer.TNumber && t.Text == \"0\"\n}\n\nfunc (t Token) IsOne() bool {\n\treturn t.Kind == css_lexer.TNumber && t.Text == \"1\"\n}\n\nfunc (t Token) IsAngle() bool {\n\tif t.Kind == css_lexer.TDimension {\n\t\tunit := strings.ToLower(t.DimensionUnit())\n\t\treturn unit == \"deg\" || unit == \"grad\" || unit == \"rad\" || unit == \"turn\"\n\t}\n\treturn false\n}\n\nfunc CloneTokensWithoutImportRecords(tokensIn []Token) (tokensOut []Token) {\n\tfor _, t := range tokensIn {\n\t\tif t.Children != nil {\n\t\t\tchildren := CloneTokensWithoutImportRecords(*t.Children)\n\t\t\tt.Children = &children\n\t\t}\n\t\ttokensOut = append(tokensOut, t)\n\t}\n\treturn\n}\n\nfunc CloneTokensWithImportRecords(\n\ttokensIn []Token, importRecordsIn []ast.ImportRecord,\n\ttokensOut []Token, importRecordsOut []ast.ImportRecord,\n) ([]Token, []ast.ImportRecord) {\n\t// Preallocate the output array if we can\n\tif tokensOut == nil {\n\t\ttokensOut = make([]Token, 0, len(tokensIn))\n\t}\n\n\tfor _, t := range tokensIn {\n\t\t// Clear the source mapping if this token is being used in another file\n\t\tt.Loc.Start = 0\n\n\t\t// If this is a URL token, also clone the import record\n\t\tif t.Kind == css_lexer.TURL {\n\t\t\timportRecordIndex := uint32(len(importRecordsOut))\n\t\t\timportRecordsOut = append(importRecordsOut, importRecordsIn[t.PayloadIndex])\n\t\t\tt.PayloadIndex = importRecordIndex\n\t\t}\n\n\t\t// Also search for URL tokens in this token's children\n\t\tif t.Children != nil {\n\t\t\tvar children []Token\n\t\t\tchildren, importRecordsOut = CloneTokensWithImportRecords(*t.Children, importRecordsIn, children, importRecordsOut)\n\t\t\tt.Children = &children\n\t\t}\n\n\t\ttokensOut = append(tokensOut, t)\n\t}\n\n\treturn tokensOut, importRecordsOut\n}\n\nfunc CloneMediaQueriesWithImportRecords(\n\tqueriesIn []MediaQuery, importRecordsIn []ast.ImportRecord,\n\tqueriesOut []MediaQuery, importRecordsOut []ast.ImportRecord,\n) ([]MediaQuery, []ast.ImportRecord) {\n\t// Preallocate the output array if we can\n\tif queriesOut == nil {\n\t\tqueriesOut = make([]MediaQuery, 0, len(queriesIn))\n\t}\n\n\t// Recursively clone each query\n\tfor _, query := range queriesIn {\n\t\tquery.Data, importRecordsOut = query.Data.CloneWithImportRecords(importRecordsIn, importRecordsOut)\n\t\tqueriesOut = append(queriesOut, query)\n\t}\n\n\treturn queriesOut, importRecordsOut\n}\n\ntype Rule struct {\n\tData R\n\tLoc  logger.Loc\n}\n\ntype R interface {\n\tEqual(rule R, check *CrossFileEqualityCheck) bool\n\tHash() (uint32, bool)\n}\n\nfunc RulesEqual(a []Rule, b []Rule, check *CrossFileEqualityCheck) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, ai := range a {\n\t\tif !ai.Data.Equal(b[i].Data, check) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc HashRules(hash uint32, rules []Rule) uint32 {\n\thash = helpers.HashCombine(hash, uint32(len(rules)))\n\tfor _, child := range rules {\n\t\tif childHash, ok := child.Data.Hash(); ok {\n\t\t\thash = helpers.HashCombine(hash, childHash)\n\t\t} else {\n\t\t\thash = helpers.HashCombine(hash, 0)\n\t\t}\n\t}\n\treturn hash\n}\n\ntype RAtCharset struct {\n\tEncoding string\n}\n\nfunc (a *RAtCharset) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RAtCharset)\n\treturn ok && a.Encoding == b.Encoding\n}\n\nfunc (r *RAtCharset) Hash() (uint32, bool) {\n\thash := uint32(1)\n\thash = helpers.HashCombineString(hash, r.Encoding)\n\treturn hash, true\n}\n\ntype ImportConditions struct {\n\t// The syntax for \"@import\" has been extended with optional conditions that\n\t// behave as if the imported file was wrapped in a \"@layer\", \"@supports\",\n\t// and/or \"@media\" rule. The possible syntax combinations are as follows:\n\t//\n\t//   @import url(...);\n\t//   @import url(...) layer;\n\t//   @import url(...) layer(layer-name);\n\t//   @import url(...) layer(layer-name) supports(supports-condition);\n\t//   @import url(...) layer(layer-name) supports(supports-condition) list-of-media-queries;\n\t//   @import url(...) layer(layer-name) list-of-media-queries;\n\t//   @import url(...) supports(supports-condition);\n\t//   @import url(...) supports(supports-condition) list-of-media-queries;\n\t//   @import url(...) list-of-media-queries;\n\t//\n\t// From: https://developer.mozilla.org/en-US/docs/Web/CSS/@import#syntax\n\tQueries []MediaQuery\n\n\t// These two fields will only ever have zero or one tokens. However, they are\n\t// implemented as arrays for convenience because most of esbuild's helper\n\t// functions that operate on tokens take arrays instead of individual tokens.\n\tLayers   []Token\n\tSupports []Token\n}\n\nfunc (c *ImportConditions) CloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (ImportConditions, []ast.ImportRecord) {\n\tresult := ImportConditions{}\n\tresult.Layers, importRecordsOut = CloneTokensWithImportRecords(c.Layers, importRecordsIn, nil, importRecordsOut)\n\tresult.Supports, importRecordsOut = CloneTokensWithImportRecords(c.Supports, importRecordsIn, nil, importRecordsOut)\n\tresult.Queries, importRecordsOut = CloneMediaQueriesWithImportRecords(c.Queries, importRecordsIn, nil, importRecordsOut)\n\treturn result, importRecordsOut\n}\n\ntype RAtImport struct {\n\tImportConditions  *ImportConditions\n\tImportRecordIndex uint32\n}\n\nfunc (*RAtImport) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\treturn false\n}\n\nfunc (r *RAtImport) Hash() (uint32, bool) {\n\treturn 0, false\n}\n\ntype RAtKeyframes struct {\n\tAtToken       string\n\tName          ast.LocRef\n\tBlocks        []KeyframeBlock\n\tCloseBraceLoc logger.Loc\n}\n\ntype KeyframeBlock struct {\n\tSelectors     []string\n\tRules         []Rule\n\tLoc           logger.Loc\n\tCloseBraceLoc logger.Loc\n}\n\nfunc (a *RAtKeyframes) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tif b, ok := rule.(*RAtKeyframes); ok && strings.EqualFold(a.AtToken, b.AtToken) && check.RefsAreEquivalent(a.Name.Ref, b.Name.Ref) && len(a.Blocks) == len(b.Blocks) {\n\t\tfor i, ai := range a.Blocks {\n\t\t\tbi := b.Blocks[i]\n\t\t\tif len(ai.Selectors) != len(bi.Selectors) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfor j, aj := range ai.Selectors {\n\t\t\t\tif aj != bi.Selectors[j] {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !RulesEqual(ai.Rules, bi.Rules, check) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (r *RAtKeyframes) Hash() (uint32, bool) {\n\thash := uint32(2)\n\thash = helpers.HashCombineString(hash, r.AtToken)\n\thash = helpers.HashCombine(hash, uint32(len(r.Blocks)))\n\tfor _, block := range r.Blocks {\n\t\thash = helpers.HashCombine(hash, uint32(len(block.Selectors)))\n\t\tfor _, sel := range block.Selectors {\n\t\t\thash = helpers.HashCombineString(hash, sel)\n\t\t}\n\t\thash = HashRules(hash, block.Rules)\n\t}\n\treturn hash, true\n}\n\ntype RKnownAt struct {\n\tAtToken       string\n\tPrelude       []Token\n\tRules         []Rule\n\tCloseBraceLoc logger.Loc\n}\n\nfunc (a *RKnownAt) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RKnownAt)\n\treturn ok && strings.EqualFold(a.AtToken, b.AtToken) && TokensEqual(a.Prelude, b.Prelude, check) && RulesEqual(a.Rules, b.Rules, check)\n}\n\nfunc (r *RKnownAt) Hash() (uint32, bool) {\n\thash := uint32(3)\n\thash = helpers.HashCombineString(hash, r.AtToken)\n\thash = HashTokens(hash, r.Prelude)\n\thash = HashRules(hash, r.Rules)\n\treturn hash, true\n}\n\ntype RUnknownAt struct {\n\tAtToken string\n\tPrelude []Token\n\tBlock   []Token\n}\n\nfunc (a *RUnknownAt) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RUnknownAt)\n\treturn ok && strings.EqualFold(a.AtToken, b.AtToken) && TokensEqual(a.Prelude, b.Prelude, check) && TokensEqual(a.Block, b.Block, check)\n}\n\nfunc (r *RUnknownAt) Hash() (uint32, bool) {\n\thash := uint32(4)\n\thash = helpers.HashCombineString(hash, r.AtToken)\n\thash = HashTokens(hash, r.Prelude)\n\thash = HashTokens(hash, r.Block)\n\treturn hash, true\n}\n\ntype RSelector struct {\n\tSelectors     []ComplexSelector\n\tRules         []Rule\n\tCloseBraceLoc logger.Loc\n}\n\nfunc (a *RSelector) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RSelector)\n\treturn ok && ComplexSelectorsEqual(a.Selectors, b.Selectors, check) && RulesEqual(a.Rules, b.Rules, check)\n}\n\nfunc (r *RSelector) Hash() (uint32, bool) {\n\thash := uint32(5)\n\thash = helpers.HashCombine(hash, uint32(len(r.Selectors)))\n\thash = HashComplexSelectors(hash, r.Selectors)\n\thash = HashRules(hash, r.Rules)\n\treturn hash, true\n}\n\ntype RQualified struct {\n\tPrelude       []Token\n\tRules         []Rule\n\tCloseBraceLoc logger.Loc\n}\n\nfunc (a *RQualified) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RQualified)\n\treturn ok && TokensEqual(a.Prelude, b.Prelude, check) && RulesEqual(a.Rules, b.Rules, check)\n}\n\nfunc (r *RQualified) Hash() (uint32, bool) {\n\thash := uint32(6)\n\thash = HashTokens(hash, r.Prelude)\n\thash = HashRules(hash, r.Rules)\n\treturn hash, true\n}\n\ntype RDeclaration struct {\n\tKeyText   string\n\tValue     []Token\n\tKeyRange  logger.Range\n\tKey       D // Compare using this instead of \"Key\" for speed\n\tImportant bool\n}\n\nfunc (a *RDeclaration) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RDeclaration)\n\treturn ok && a.KeyText == b.KeyText && TokensEqual(a.Value, b.Value, check) && a.Important == b.Important\n}\n\nfunc (r *RDeclaration) Hash() (uint32, bool) {\n\tvar hash uint32\n\tif r.Key == DUnknown {\n\t\tif r.Important {\n\t\t\thash = uint32(7)\n\t\t} else {\n\t\t\thash = uint32(8)\n\t\t}\n\t\thash = helpers.HashCombineString(hash, r.KeyText)\n\t} else {\n\t\tif r.Important {\n\t\t\thash = uint32(9)\n\t\t} else {\n\t\t\thash = uint32(10)\n\t\t}\n\t\thash = helpers.HashCombine(hash, uint32(r.Key))\n\t}\n\thash = HashTokens(hash, r.Value)\n\treturn hash, true\n}\n\ntype RBadDeclaration struct {\n\tTokens []Token\n}\n\nfunc (a *RBadDeclaration) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RBadDeclaration)\n\treturn ok && TokensEqual(a.Tokens, b.Tokens, check)\n}\n\nfunc (r *RBadDeclaration) Hash() (uint32, bool) {\n\thash := uint32(7)\n\thash = HashTokens(hash, r.Tokens)\n\treturn hash, true\n}\n\ntype RComment struct {\n\tText string\n}\n\nfunc (a *RComment) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RComment)\n\treturn ok && a.Text == b.Text\n}\n\nfunc (r *RComment) Hash() (uint32, bool) {\n\thash := uint32(8)\n\thash = helpers.HashCombineString(hash, r.Text)\n\treturn hash, true\n}\n\ntype RAtLayer struct {\n\tNames         [][]string\n\tRules         []Rule\n\tCloseBraceLoc logger.Loc\n}\n\nfunc (a *RAtLayer) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tif b, ok := rule.(*RAtLayer); ok && len(a.Names) == len(b.Names) && len(a.Rules) == len(b.Rules) {\n\t\tfor i, ai := range a.Names {\n\t\t\tbi := b.Names[i]\n\t\t\tif len(ai) != len(bi) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tfor j, aj := range ai {\n\t\t\t\tif aj != bi[j] {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif !RulesEqual(a.Rules, b.Rules, check) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (r *RAtLayer) Hash() (uint32, bool) {\n\thash := uint32(9)\n\thash = helpers.HashCombine(hash, uint32(len(r.Names)))\n\tfor _, parts := range r.Names {\n\t\thash = helpers.HashCombine(hash, uint32(len(parts)))\n\t\tfor _, part := range parts {\n\t\t\thash = helpers.HashCombineString(hash, part)\n\t\t}\n\t}\n\thash = HashRules(hash, r.Rules)\n\treturn hash, true\n}\n\ntype RAtMedia struct {\n\tQueries       []MediaQuery\n\tRules         []Rule\n\tCloseBraceLoc logger.Loc\n}\n\nfunc (a *RAtMedia) Equal(rule R, check *CrossFileEqualityCheck) bool {\n\tb, ok := rule.(*RAtMedia)\n\treturn ok && MediaQueriesEqual(a.Queries, b.Queries, check) && RulesEqual(a.Rules, b.Rules, check)\n}\n\nfunc (r *RAtMedia) Hash() (uint32, bool) {\n\thash := uint32(10)\n\thash = HashMediaQueries(hash, r.Queries)\n\thash = HashRules(hash, r.Rules)\n\treturn hash, true\n}\n\ntype MediaQuery struct {\n\tLoc  logger.Loc\n\tData MQ\n}\n\ntype MQ interface {\n\tEqual(query MQ, check *CrossFileEqualityCheck) bool\n\tEqualIgnoringWhitespace(query MQ) bool\n\tHash() uint32\n\tCloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (MQ, []ast.ImportRecord)\n}\n\nfunc MediaQueriesEqual(a []MediaQuery, b []MediaQuery, check *CrossFileEqualityCheck) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, ai := range a {\n\t\tif !ai.Data.Equal(b[i].Data, check) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc MediaQueriesEqualIgnoringWhitespace(a []MediaQuery, b []MediaQuery) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, ai := range a {\n\t\tif !ai.Data.EqualIgnoringWhitespace(b[i].Data) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc HashMediaQueries(hash uint32, queries []MediaQuery) uint32 {\n\thash = helpers.HashCombine(hash, uint32(len(queries)))\n\tfor _, q := range queries {\n\t\thash = helpers.HashCombine(hash, q.Data.Hash())\n\t}\n\treturn hash\n}\n\ntype MQTypeOp uint8\n\nconst (\n\tMQTypeOpNone MQTypeOp = iota\n\tMQTypeOpNot\n\tMQTypeOpOnly\n)\n\ntype MQType struct {\n\tOp        MQTypeOp\n\tType      string\n\tAndOrNull MediaQuery\n}\n\nfunc (q *MQType) Equal(query MQ, check *CrossFileEqualityCheck) bool {\n\tif p, ok := query.(*MQType); ok && q.Op == p.Op && q.Type == p.Type {\n\t\treturn (q.AndOrNull.Data == nil && p.AndOrNull.Data == nil) ||\n\t\t\t(q.AndOrNull.Data != nil && p.AndOrNull.Data != nil && q.AndOrNull.Data.Equal(p.AndOrNull.Data, check))\n\t}\n\treturn false\n}\n\nfunc (q *MQType) EqualIgnoringWhitespace(query MQ) bool {\n\tif p, ok := query.(*MQType); ok && q.Op == p.Op && q.Type == p.Type {\n\t\treturn (q.AndOrNull.Data == nil && p.AndOrNull.Data == nil) ||\n\t\t\t(q.AndOrNull.Data != nil && p.AndOrNull.Data != nil && q.AndOrNull.Data.EqualIgnoringWhitespace(p.AndOrNull.Data))\n\t}\n\treturn false\n}\n\nfunc (q *MQType) Hash() uint32 {\n\thash := uint32(0)\n\thash = helpers.HashCombine(hash, uint32(q.Op))\n\thash = helpers.HashCombineString(hash, q.Type)\n\tif q.AndOrNull.Data != nil {\n\t\thash = helpers.HashCombine(hash, q.AndOrNull.Data.Hash())\n\t}\n\treturn hash\n}\n\nfunc (q *MQType) CloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (MQ, []ast.ImportRecord) {\n\tvar andOrNull MQ\n\tif q.AndOrNull.Data != nil {\n\t\tandOrNull, importRecordsOut = q.AndOrNull.Data.CloneWithImportRecords(importRecordsIn, importRecordsOut)\n\t}\n\treturn &MQType{Op: q.Op, Type: q.Type, AndOrNull: MediaQuery{Data: andOrNull}}, importRecordsOut\n}\n\ntype MQNot struct {\n\tInner MediaQuery\n}\n\nfunc (q *MQNot) Equal(query MQ, check *CrossFileEqualityCheck) bool {\n\tp, ok := query.(*MQNot)\n\treturn ok && q.Inner.Data.Equal(p.Inner.Data, check)\n}\n\nfunc (q *MQNot) EqualIgnoringWhitespace(query MQ) bool {\n\tp, ok := query.(*MQNot)\n\treturn ok && q.Inner.Data.EqualIgnoringWhitespace(p.Inner.Data)\n}\n\nfunc (q *MQNot) Hash() uint32 {\n\thash := uint32(1)\n\thash = helpers.HashCombine(hash, q.Inner.Data.Hash())\n\treturn hash\n}\n\nfunc (q *MQNot) CloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (MQ, []ast.ImportRecord) {\n\tinner, importRecordsOut := q.Inner.Data.CloneWithImportRecords(importRecordsIn, importRecordsOut)\n\treturn &MQNot{Inner: MediaQuery{Data: inner}}, importRecordsOut\n}\n\ntype MQBinaryOp uint8\n\nconst (\n\tMQBinaryOpAnd MQBinaryOp = iota\n\tMQBinaryOpOr\n)\n\ntype MQBinary struct {\n\tOp    MQBinaryOp\n\tTerms []MediaQuery\n}\n\nfunc (q *MQBinary) Equal(query MQ, check *CrossFileEqualityCheck) bool {\n\tp, ok := query.(*MQBinary)\n\treturn ok && q.Op == p.Op && MediaQueriesEqual(q.Terms, p.Terms, check)\n}\n\nfunc (q *MQBinary) EqualIgnoringWhitespace(query MQ) bool {\n\tp, ok := query.(*MQBinary)\n\treturn ok && q.Op == p.Op && MediaQueriesEqualIgnoringWhitespace(q.Terms, p.Terms)\n}\n\nfunc (q *MQBinary) Hash() uint32 {\n\thash := uint32(2)\n\thash = helpers.HashCombine(hash, uint32(q.Op))\n\thash = HashMediaQueries(hash, q.Terms)\n\treturn hash\n}\n\nfunc (q *MQBinary) CloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (MQ, []ast.ImportRecord) {\n\tterms := make([]MediaQuery, 0, len(q.Terms))\n\tfor _, term := range q.Terms {\n\t\tvar clone MQ\n\t\tclone, importRecordsOut = term.Data.CloneWithImportRecords(importRecordsIn, importRecordsOut)\n\t\tterms = append(terms, MediaQuery{Data: clone})\n\t}\n\treturn &MQBinary{Op: q.Op, Terms: terms}, importRecordsOut\n}\n\ntype MQArbitraryTokens struct {\n\tTokens []Token\n}\n\nfunc (q *MQArbitraryTokens) Equal(query MQ, check *CrossFileEqualityCheck) bool {\n\tp, ok := query.(*MQArbitraryTokens)\n\treturn ok && TokensEqual(q.Tokens, p.Tokens, check)\n}\n\nfunc (q *MQArbitraryTokens) EqualIgnoringWhitespace(query MQ) bool {\n\tp, ok := query.(*MQArbitraryTokens)\n\treturn ok && TokensEqualIgnoringWhitespace(q.Tokens, p.Tokens)\n}\n\nfunc (q *MQArbitraryTokens) Hash() uint32 {\n\thash := uint32(3)\n\thash = HashTokens(hash, q.Tokens)\n\treturn hash\n}\n\nfunc (q *MQArbitraryTokens) CloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (MQ, []ast.ImportRecord) {\n\ttokens, importRecordsOut := CloneTokensWithImportRecords(q.Tokens, importRecordsIn, nil, importRecordsOut)\n\treturn &MQArbitraryTokens{Tokens: tokens}, importRecordsOut\n}\n\ntype MQPlainOrBoolean struct {\n\tName       string\n\tValueOrNil []Token\n}\n\nfunc (q *MQPlainOrBoolean) Equal(query MQ, check *CrossFileEqualityCheck) bool {\n\tp, ok := query.(*MQPlainOrBoolean)\n\treturn ok && q.Name == p.Name && TokensEqual(q.ValueOrNil, p.ValueOrNil, check)\n}\n\nfunc (q *MQPlainOrBoolean) EqualIgnoringWhitespace(query MQ) bool {\n\tp, ok := query.(*MQPlainOrBoolean)\n\treturn ok && q.Name == p.Name && TokensEqualIgnoringWhitespace(q.ValueOrNil, p.ValueOrNil)\n}\n\nfunc (q *MQPlainOrBoolean) Hash() uint32 {\n\thash := uint32(4)\n\thash = helpers.HashCombineString(hash, q.Name)\n\thash = HashTokens(hash, q.ValueOrNil)\n\treturn hash\n}\n\nfunc (q *MQPlainOrBoolean) CloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (MQ, []ast.ImportRecord) {\n\tvar valueOrNil []Token\n\tif q.ValueOrNil != nil {\n\t\tvalueOrNil, importRecordsOut = CloneTokensWithImportRecords(q.ValueOrNil, importRecordsIn, nil, importRecordsOut)\n\t}\n\treturn &MQPlainOrBoolean{Name: q.Name, ValueOrNil: valueOrNil}, importRecordsOut\n}\n\ntype MQRange struct {\n\tBefore    []Token\n\tName      string\n\tAfter     []Token\n\tNameLoc   logger.Loc\n\tBeforeCmp MQCmp\n\tAfterCmp  MQCmp\n}\n\nfunc (q *MQRange) Equal(query MQ, check *CrossFileEqualityCheck) bool {\n\tp, ok := query.(*MQRange)\n\treturn ok && q.BeforeCmp == p.BeforeCmp && q.AfterCmp == p.AfterCmp && q.Name == p.Name &&\n\t\tTokensEqual(q.Before, p.Before, check) && TokensEqual(q.After, p.After, check)\n}\n\nfunc (q *MQRange) EqualIgnoringWhitespace(query MQ) bool {\n\tp, ok := query.(*MQRange)\n\treturn ok && q.BeforeCmp == p.BeforeCmp && q.AfterCmp == p.AfterCmp && q.Name == p.Name &&\n\t\tTokensEqualIgnoringWhitespace(q.Before, p.Before) && TokensEqualIgnoringWhitespace(q.After, p.After)\n}\n\nfunc (q *MQRange) Hash() uint32 {\n\thash := uint32(5)\n\thash = HashTokens(hash, q.Before)\n\thash = helpers.HashCombine(hash, uint32(q.BeforeCmp))\n\thash = helpers.HashCombineString(hash, q.Name)\n\thash = helpers.HashCombine(hash, uint32(q.AfterCmp))\n\thash = HashTokens(hash, q.After)\n\treturn hash\n}\n\nfunc (q *MQRange) CloneWithImportRecords(importRecordsIn []ast.ImportRecord, importRecordsOut []ast.ImportRecord) (MQ, []ast.ImportRecord) {\n\tbefore, importRecordsOut := CloneTokensWithImportRecords(q.Before, importRecordsIn, nil, importRecordsOut)\n\tafter, importRecordsOut := CloneTokensWithImportRecords(q.After, importRecordsIn, nil, importRecordsOut)\n\treturn &MQRange{\n\t\tBefore:    before,\n\t\tBeforeCmp: q.BeforeCmp,\n\t\tName:      q.Name,\n\t\tAfterCmp:  q.AfterCmp,\n\t\tAfter:     after,\n\t}, importRecordsOut\n}\n\ntype MQCmp uint8\n\nconst (\n\tMQCmpNone MQCmp = iota\n\tMQCmpEq\n\tMQCmpLt\n\tMQCmpLe\n\tMQCmpGt\n\tMQCmpGe\n)\n\nfunc (cmp MQCmp) String() string {\n\tswitch cmp {\n\tcase MQCmpLt:\n\t\treturn \"<\"\n\tcase MQCmpLe:\n\t\treturn \"<=\"\n\tcase MQCmpGt:\n\t\treturn \">\"\n\tcase MQCmpGe:\n\t\treturn \">=\"\n\t}\n\treturn \"=\"\n}\n\nfunc (cmp MQCmp) Dir() int {\n\tswitch cmp {\n\tcase MQCmpLt, MQCmpLe:\n\t\treturn -1\n\tcase MQCmpGt, MQCmpGe:\n\t\treturn 1\n\t}\n\treturn 0\n}\n\nfunc (cmp MQCmp) Flip() MQCmp {\n\tswitch cmp {\n\tcase MQCmpLt:\n\t\treturn MQCmpGe\n\tcase MQCmpLe:\n\t\treturn MQCmpGt\n\tcase MQCmpGt:\n\t\treturn MQCmpLe\n\tcase MQCmpGe:\n\t\treturn MQCmpLt\n\t}\n\treturn cmp\n}\n\nfunc (cmp MQCmp) Reverse() MQCmp {\n\tswitch cmp {\n\tcase MQCmpLt:\n\t\treturn MQCmpGt\n\tcase MQCmpLe:\n\t\treturn MQCmpGe\n\tcase MQCmpGt:\n\t\treturn MQCmpLt\n\tcase MQCmpGe:\n\t\treturn MQCmpLe\n\t}\n\treturn cmp\n}\n\ntype ComplexSelector struct {\n\tSelectors []CompoundSelector\n}\n\nfunc ComplexSelectorsEqual(a []ComplexSelector, b []ComplexSelector, check *CrossFileEqualityCheck) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, ai := range a {\n\t\tif !ai.Equal(b[i], check) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc HashComplexSelectors(hash uint32, selectors []ComplexSelector) uint32 {\n\tfor _, complex := range selectors {\n\t\thash = helpers.HashCombine(hash, uint32(len(complex.Selectors)))\n\t\tfor _, sel := range complex.Selectors {\n\t\t\tif sel.TypeSelector != nil {\n\t\t\t\thash = helpers.HashCombineString(hash, sel.TypeSelector.Name.Text)\n\t\t\t} else {\n\t\t\t\thash = helpers.HashCombine(hash, 0)\n\t\t\t}\n\t\t\thash = helpers.HashCombine(hash, uint32(len(sel.SubclassSelectors)))\n\t\t\tfor _, ss := range sel.SubclassSelectors {\n\t\t\t\thash = helpers.HashCombine(hash, ss.Data.Hash())\n\t\t\t}\n\t\t\thash = helpers.HashCombine(hash, uint32(sel.Combinator.Byte))\n\t\t}\n\t}\n\treturn hash\n}\n\nfunc (s ComplexSelector) Clone() ComplexSelector {\n\tclone := ComplexSelector{Selectors: make([]CompoundSelector, len(s.Selectors))}\n\tfor i, sel := range s.Selectors {\n\t\tclone.Selectors[i] = sel.Clone()\n\t}\n\treturn clone\n}\n\nfunc (sel ComplexSelector) ContainsNestingCombinator() bool {\n\tfor _, inner := range sel.Selectors {\n\t\tif len(inner.NestingSelectorLocs) > 0 {\n\t\t\treturn true\n\t\t}\n\t\tfor _, ss := range inner.SubclassSelectors {\n\t\t\tif pseudo, ok := ss.Data.(*SSPseudoClassWithSelectorList); ok {\n\t\t\t\tfor _, nested := range pseudo.Selectors {\n\t\t\t\t\tif nested.ContainsNestingCombinator() {\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (sel ComplexSelector) IsRelative() bool {\n\t// https://www.w3.org/TR/css-nesting-1/#syntax\n\t// \"If a selector in the <relative-selector-list> does not start with a\n\t// combinator but does contain the nesting selector, it is interpreted\n\t// as a non-relative selector.\"\n\tif sel.Selectors[0].Combinator.Byte == 0 && sel.ContainsNestingCombinator() {\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc tokensContainAmpersandRecursive(tokens []Token) bool {\n\tfor _, t := range tokens {\n\t\tif t.Kind == css_lexer.TDelimAmpersand {\n\t\t\treturn true\n\t\t}\n\t\tif children := t.Children; children != nil && tokensContainAmpersandRecursive(*children) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (sel ComplexSelector) UsesPseudoElement() bool {\n\tfor _, sel := range sel.Selectors {\n\t\tfor _, ss := range sel.SubclassSelectors {\n\t\t\tif class, ok := ss.Data.(*SSPseudoClass); ok {\n\t\t\t\tif class.IsElement {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\t\t// https://www.w3.org/TR/selectors-4/#single-colon-pseudos\n\t\t\t\t// The four Level 2 pseudo-elements (::before, ::after, ::first-line,\n\t\t\t\t// and ::first-letter) may, for legacy reasons, be represented using\n\t\t\t\t// the <pseudo-class-selector> grammar, with only a single \":\"\n\t\t\t\t// character at their start.\n\t\t\t\tswitch class.Name {\n\t\t\t\tcase \"before\", \"after\", \"first-line\", \"first-letter\":\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a ComplexSelector) Equal(b ComplexSelector, check *CrossFileEqualityCheck) bool {\n\tif len(a.Selectors) != len(b.Selectors) {\n\t\treturn false\n\t}\n\n\tfor i, ai := range a.Selectors {\n\t\tbi := b.Selectors[i]\n\t\tif len(ai.NestingSelectorLocs) != len(bi.NestingSelectorLocs) || ai.Combinator.Byte != bi.Combinator.Byte {\n\t\t\treturn false\n\t\t}\n\n\t\tif ats, bts := ai.TypeSelector, bi.TypeSelector; (ats == nil) != (bts == nil) {\n\t\t\treturn false\n\t\t} else if ats != nil && bts != nil && !ats.Equal(*bts) {\n\t\t\treturn false\n\t\t}\n\n\t\tif len(ai.SubclassSelectors) != len(bi.SubclassSelectors) {\n\t\t\treturn false\n\t\t}\n\t\tfor j, aj := range ai.SubclassSelectors {\n\t\t\tif !aj.Data.Equal(bi.SubclassSelectors[j].Data, check) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\ntype Combinator struct {\n\tLoc  logger.Loc\n\tByte uint8 // Optional, may be 0 for no combinator\n}\n\ntype CompoundSelector struct {\n\tTypeSelector        *NamespacedName\n\tSubclassSelectors   []SubclassSelector\n\tNestingSelectorLocs []logger.Loc // \"&\" vs. \"&&\" is different specificity\n\tCombinator          Combinator   // Optional, may be 0\n\n\t// If this is true, this is a \"&\" that was generated by a bare \":local\" or \":global\"\n\tWasEmptyFromLocalOrGlobal bool\n}\n\nfunc (sel CompoundSelector) IsSingleAmpersand() bool {\n\treturn len(sel.NestingSelectorLocs) == 1 && sel.Combinator.Byte == 0 && sel.TypeSelector == nil && len(sel.SubclassSelectors) == 0\n}\n\nfunc (sel CompoundSelector) IsInvalidBecauseEmpty() bool {\n\treturn len(sel.NestingSelectorLocs) == 0 && sel.TypeSelector == nil && len(sel.SubclassSelectors) == 0\n}\n\nfunc (sel CompoundSelector) Range() (r logger.Range) {\n\tif sel.Combinator.Byte != 0 {\n\t\tr = logger.Range{Loc: sel.Combinator.Loc, Len: 1}\n\t}\n\tif sel.TypeSelector != nil {\n\t\tr.ExpandBy(sel.TypeSelector.Range())\n\t}\n\tfor _, loc := range sel.NestingSelectorLocs {\n\t\tr.ExpandBy(logger.Range{Loc: loc, Len: 1})\n\t}\n\tif len(sel.SubclassSelectors) > 0 {\n\t\tfor _, ss := range sel.SubclassSelectors {\n\t\t\tr.ExpandBy(ss.Range)\n\t\t}\n\t}\n\treturn\n}\n\nfunc (sel CompoundSelector) Clone() CompoundSelector {\n\tclone := sel\n\n\tif sel.TypeSelector != nil {\n\t\tt := sel.TypeSelector.Clone()\n\t\tclone.TypeSelector = &t\n\t}\n\n\tif sel.SubclassSelectors != nil {\n\t\tselectors := make([]SubclassSelector, len(sel.SubclassSelectors))\n\t\tfor i, ss := range sel.SubclassSelectors {\n\t\t\tss.Data = ss.Data.Clone()\n\t\t\tselectors[i] = ss\n\t\t}\n\t\tclone.SubclassSelectors = selectors\n\t}\n\n\treturn clone\n}\n\ntype NameToken struct {\n\tText  string\n\tRange logger.Range\n\tKind  css_lexer.T\n}\n\nfunc (a NameToken) Equal(b NameToken) bool {\n\treturn a.Text == b.Text && a.Kind == b.Kind\n}\n\ntype NamespacedName struct {\n\t// If present, this is an identifier or \"*\" and is followed by a \"|\" character\n\tNamespacePrefix *NameToken\n\n\t// This is an identifier or \"*\"\n\tName NameToken\n}\n\nfunc (n NamespacedName) Range() logger.Range {\n\tif n.NamespacePrefix != nil {\n\t\tloc := n.NamespacePrefix.Range.Loc\n\t\treturn logger.Range{Loc: loc, Len: n.Name.Range.End() - loc.Start}\n\t}\n\treturn n.Name.Range\n}\n\nfunc (n NamespacedName) Clone() NamespacedName {\n\tclone := n\n\tif n.NamespacePrefix != nil {\n\t\tprefix := *n.NamespacePrefix\n\t\tclone.NamespacePrefix = &prefix\n\t}\n\treturn clone\n}\n\nfunc (a NamespacedName) Equal(b NamespacedName) bool {\n\treturn a.Name.Equal(b.Name) && (a.NamespacePrefix == nil) == (b.NamespacePrefix == nil) &&\n\t\t(a.NamespacePrefix == nil || b.NamespacePrefix == nil || a.NamespacePrefix.Equal(b.Name))\n}\n\ntype SubclassSelector struct {\n\tData  SS\n\tRange logger.Range\n}\n\ntype SS interface {\n\tEqual(ss SS, check *CrossFileEqualityCheck) bool\n\tHash() uint32\n\tClone() SS\n}\n\ntype SSHash struct {\n\tName ast.LocRef\n}\n\nfunc (a *SSHash) Equal(ss SS, check *CrossFileEqualityCheck) bool {\n\tb, ok := ss.(*SSHash)\n\treturn ok && check.RefsAreEquivalent(a.Name.Ref, b.Name.Ref)\n}\n\nfunc (ss *SSHash) Hash() uint32 {\n\thash := uint32(1)\n\treturn hash\n}\n\nfunc (ss *SSHash) Clone() SS {\n\tclone := *ss\n\treturn &clone\n}\n\ntype SSClass struct {\n\tName ast.LocRef\n}\n\nfunc (a *SSClass) Equal(ss SS, check *CrossFileEqualityCheck) bool {\n\tb, ok := ss.(*SSClass)\n\treturn ok && check.RefsAreEquivalent(a.Name.Ref, b.Name.Ref)\n}\n\nfunc (ss *SSClass) Hash() uint32 {\n\thash := uint32(2)\n\treturn hash\n}\n\nfunc (ss *SSClass) Clone() SS {\n\tclone := *ss\n\treturn &clone\n}\n\ntype SSAttribute struct {\n\tMatcherOp       string // Either \"\" or one of: \"=\" \"~=\" \"|=\" \"^=\" \"$=\" \"*=\"\n\tMatcherValue    string\n\tNamespacedName  NamespacedName\n\tMatcherModifier byte // Either 0 or one of: 'i' 'I' 's' 'S'\n}\n\nfunc (a *SSAttribute) Equal(ss SS, check *CrossFileEqualityCheck) bool {\n\tb, ok := ss.(*SSAttribute)\n\treturn ok && a.NamespacedName.Equal(b.NamespacedName) && a.MatcherOp == b.MatcherOp &&\n\t\ta.MatcherValue == b.MatcherValue && a.MatcherModifier == b.MatcherModifier\n}\n\nfunc (ss *SSAttribute) Hash() uint32 {\n\thash := uint32(3)\n\thash = helpers.HashCombineString(hash, ss.NamespacedName.Name.Text)\n\thash = helpers.HashCombineString(hash, ss.MatcherOp)\n\thash = helpers.HashCombineString(hash, ss.MatcherValue)\n\treturn hash\n}\n\nfunc (ss *SSAttribute) Clone() SS {\n\tclone := *ss\n\tclone.NamespacedName = ss.NamespacedName.Clone()\n\treturn &clone\n}\n\ntype SSPseudoClass struct {\n\tName      string\n\tArgs      []Token\n\tIsElement bool // If true, this is prefixed by \"::\" instead of \":\"\n}\n\nfunc (a *SSPseudoClass) Equal(ss SS, check *CrossFileEqualityCheck) bool {\n\tb, ok := ss.(*SSPseudoClass)\n\treturn ok && a.Name == b.Name && TokensEqual(a.Args, b.Args, check) && a.IsElement == b.IsElement\n}\n\nfunc (ss *SSPseudoClass) Hash() uint32 {\n\thash := uint32(4)\n\thash = helpers.HashCombineString(hash, ss.Name)\n\thash = HashTokens(hash, ss.Args)\n\treturn hash\n}\n\nfunc (ss *SSPseudoClass) Clone() SS {\n\tclone := *ss\n\tif ss.Args != nil {\n\t\tss.Args = CloneTokensWithoutImportRecords(ss.Args)\n\t}\n\treturn &clone\n}\n\ntype PseudoClassKind uint8\n\nconst (\n\tPseudoClassGlobal PseudoClassKind = iota\n\tPseudoClassHas\n\tPseudoClassIs\n\tPseudoClassLocal\n\tPseudoClassNot\n\tPseudoClassNthChild\n\tPseudoClassNthLastChild\n\tPseudoClassNthLastOfType\n\tPseudoClassNthOfType\n\tPseudoClassWhere\n)\n\nfunc (kind PseudoClassKind) HasNthIndex() bool {\n\treturn kind >= PseudoClassNthChild && kind <= PseudoClassNthOfType\n}\n\nfunc (kind PseudoClassKind) String() string {\n\tswitch kind {\n\tcase PseudoClassGlobal:\n\t\treturn \"global\"\n\tcase PseudoClassHas:\n\t\treturn \"has\"\n\tcase PseudoClassIs:\n\t\treturn \"is\"\n\tcase PseudoClassLocal:\n\t\treturn \"local\"\n\tcase PseudoClassNot:\n\t\treturn \"not\"\n\tcase PseudoClassNthChild:\n\t\treturn \"nth-child\"\n\tcase PseudoClassNthLastChild:\n\t\treturn \"nth-last-child\"\n\tcase PseudoClassNthLastOfType:\n\t\treturn \"nth-last-of-type\"\n\tcase PseudoClassNthOfType:\n\t\treturn \"nth-of-type\"\n\tcase PseudoClassWhere:\n\t\treturn \"where\"\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\n// This is the \"An+B\" syntax\ntype NthIndex struct {\n\tA string\n\tB string // May be \"even\" or \"odd\"\n}\n\nfunc (index *NthIndex) Minify() {\n\t// \"even\" => \"2n\"\n\tif index.B == \"even\" {\n\t\tindex.A = \"2\"\n\t\tindex.B = \"\"\n\t\treturn\n\t}\n\n\t// \"2n+1\" => \"odd\"\n\tif index.A == \"2\" && index.B == \"1\" {\n\t\tindex.A = \"\"\n\t\tindex.B = \"odd\"\n\t\treturn\n\t}\n\n\t// \"0n+1\" => \"1\"\n\tif index.A == \"0\" {\n\t\tindex.A = \"\"\n\t\tif index.B == \"\" {\n\t\t\t// \"0n\" => \"0\"\n\t\t\tindex.B = \"0\"\n\t\t}\n\t\treturn\n\t}\n\n\t// \"1n+0\" => \"1n\"\n\tif index.B == \"0\" && index.A != \"\" {\n\t\tindex.B = \"\"\n\t}\n}\n\n// See https://drafts.csswg.org/selectors/#grouping\ntype SSPseudoClassWithSelectorList struct {\n\tSelectors []ComplexSelector\n\tIndex     NthIndex\n\tKind      PseudoClassKind\n}\n\nfunc (a *SSPseudoClassWithSelectorList) Equal(ss SS, check *CrossFileEqualityCheck) bool {\n\tb, ok := ss.(*SSPseudoClassWithSelectorList)\n\treturn ok && a.Kind == b.Kind && a.Index == b.Index && ComplexSelectorsEqual(a.Selectors, b.Selectors, check)\n}\n\nfunc (ss *SSPseudoClassWithSelectorList) Hash() uint32 {\n\thash := uint32(5)\n\thash = helpers.HashCombine(hash, uint32(ss.Kind))\n\thash = helpers.HashCombineString(hash, ss.Index.A)\n\thash = helpers.HashCombineString(hash, ss.Index.B)\n\thash = HashComplexSelectors(hash, ss.Selectors)\n\treturn hash\n}\n\nfunc (ss *SSPseudoClassWithSelectorList) Clone() SS {\n\tclone := *ss\n\tclone.Selectors = make([]ComplexSelector, len(ss.Selectors))\n\tfor i, sel := range ss.Selectors {\n\t\tclone.Selectors[i] = sel.Clone()\n\t}\n\treturn &clone\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_ast/css_decl_table.go",
    "content": "package css_ast\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/evanw/esbuild/internal/helpers\"\n)\n\ntype D uint16\n\nconst (\n\tDUnknown D = iota\n\tDAlignContent\n\tDAlignItems\n\tDAlignSelf\n\tDAlignmentBaseline\n\tDAll\n\tDAnimation\n\tDAnimationDelay\n\tDAnimationDirection\n\tDAnimationDuration\n\tDAnimationFillMode\n\tDAnimationIterationCount\n\tDAnimationName\n\tDAnimationPlayState\n\tDAnimationTimingFunction\n\tDAppearance\n\tDBackdropFilter\n\tDBackfaceVisibility\n\tDBackground\n\tDBackgroundAttachment\n\tDBackgroundClip\n\tDBackgroundColor\n\tDBackgroundImage\n\tDBackgroundOrigin\n\tDBackgroundPosition\n\tDBackgroundPositionX\n\tDBackgroundPositionY\n\tDBackgroundRepeat\n\tDBackgroundSize\n\tDBaselineShift\n\tDBlockSize\n\tDBorder\n\tDBorderBlockEnd\n\tDBorderBlockEndColor\n\tDBorderBlockEndStyle\n\tDBorderBlockEndWidth\n\tDBorderBlockStart\n\tDBorderBlockStartColor\n\tDBorderBlockStartStyle\n\tDBorderBlockStartWidth\n\tDBorderBottom\n\tDBorderBottomColor\n\tDBorderBottomLeftRadius\n\tDBorderBottomRightRadius\n\tDBorderBottomStyle\n\tDBorderBottomWidth\n\tDBorderCollapse\n\tDBorderColor\n\tDBorderImage\n\tDBorderImageOutset\n\tDBorderImageRepeat\n\tDBorderImageSlice\n\tDBorderImageSource\n\tDBorderImageWidth\n\tDBorderInlineEnd\n\tDBorderInlineEndColor\n\tDBorderInlineEndStyle\n\tDBorderInlineEndWidth\n\tDBorderInlineStart\n\tDBorderInlineStartColor\n\tDBorderInlineStartStyle\n\tDBorderInlineStartWidth\n\tDBorderLeft\n\tDBorderLeftColor\n\tDBorderLeftStyle\n\tDBorderLeftWidth\n\tDBorderRadius\n\tDBorderRight\n\tDBorderRightColor\n\tDBorderRightStyle\n\tDBorderRightWidth\n\tDBorderSpacing\n\tDBorderStyle\n\tDBorderTop\n\tDBorderTopColor\n\tDBorderTopLeftRadius\n\tDBorderTopRightRadius\n\tDBorderTopStyle\n\tDBorderTopWidth\n\tDBorderWidth\n\tDBottom\n\tDBoxDecorationBreak\n\tDBoxShadow\n\tDBoxSizing\n\tDBreakAfter\n\tDBreakBefore\n\tDBreakInside\n\tDCaptionSide\n\tDCaretColor\n\tDClear\n\tDClip\n\tDClipPath\n\tDClipRule\n\tDColor\n\tDColorInterpolation\n\tDColorInterpolationFilters\n\tDColumnCount\n\tDColumnFill\n\tDColumnGap\n\tDColumnRule\n\tDColumnRuleColor\n\tDColumnRuleStyle\n\tDColumnRuleWidth\n\tDColumnSpan\n\tDColumnWidth\n\tDColumns\n\tDComposes\n\tDContainer\n\tDContainerName\n\tDContainerType\n\tDContent\n\tDCounterIncrement\n\tDCounterReset\n\tDCssFloat\n\tDCssText\n\tDCursor\n\tDDirection\n\tDDisplay\n\tDDominantBaseline\n\tDEmptyCells\n\tDFill\n\tDFillOpacity\n\tDFillRule\n\tDFilter\n\tDFlex\n\tDFlexBasis\n\tDFlexDirection\n\tDFlexFlow\n\tDFlexGrow\n\tDFlexShrink\n\tDFlexWrap\n\tDFloat\n\tDFloodColor\n\tDFloodOpacity\n\tDFont\n\tDFontFamily\n\tDFontFeatureSettings\n\tDFontKerning\n\tDFontSize\n\tDFontSizeAdjust\n\tDFontStretch\n\tDFontStyle\n\tDFontSynthesis\n\tDFontVariant\n\tDFontVariantCaps\n\tDFontVariantEastAsian\n\tDFontVariantLigatures\n\tDFontVariantNumeric\n\tDFontVariantPosition\n\tDFontWeight\n\tDGap\n\tDGlyphOrientationVertical\n\tDGrid\n\tDGridArea\n\tDGridAutoColumns\n\tDGridAutoFlow\n\tDGridAutoRows\n\tDGridColumn\n\tDGridColumnEnd\n\tDGridColumnGap\n\tDGridColumnStart\n\tDGridGap\n\tDGridRow\n\tDGridRowEnd\n\tDGridRowGap\n\tDGridRowStart\n\tDGridTemplate\n\tDGridTemplateAreas\n\tDGridTemplateColumns\n\tDGridTemplateRows\n\tDHeight\n\tDHyphens\n\tDImageOrientation\n\tDImageRendering\n\tDInitialLetter\n\tDInlineSize\n\tDInset\n\tDJustifyContent\n\tDJustifyItems\n\tDJustifySelf\n\tDLeft\n\tDLetterSpacing\n\tDLightingColor\n\tDLineBreak\n\tDLineHeight\n\tDListStyle\n\tDListStyleImage\n\tDListStylePosition\n\tDListStyleType\n\tDMargin\n\tDMarginBlockEnd\n\tDMarginBlockStart\n\tDMarginBottom\n\tDMarginInlineEnd\n\tDMarginInlineStart\n\tDMarginLeft\n\tDMarginRight\n\tDMarginTop\n\tDMarker\n\tDMarkerEnd\n\tDMarkerMid\n\tDMarkerStart\n\tDMask\n\tDMaskComposite\n\tDMaskImage\n\tDMaskOrigin\n\tDMaskPosition\n\tDMaskRepeat\n\tDMaskSize\n\tDMaskType\n\tDMaxBlockSize\n\tDMaxHeight\n\tDMaxInlineSize\n\tDMaxWidth\n\tDMinBlockSize\n\tDMinHeight\n\tDMinInlineSize\n\tDMinWidth\n\tDObjectFit\n\tDObjectPosition\n\tDOpacity\n\tDOrder\n\tDOrphans\n\tDOutline\n\tDOutlineColor\n\tDOutlineOffset\n\tDOutlineStyle\n\tDOutlineWidth\n\tDOverflow\n\tDOverflowAnchor\n\tDOverflowWrap\n\tDOverflowX\n\tDOverflowY\n\tDOverscrollBehavior\n\tDOverscrollBehaviorBlock\n\tDOverscrollBehaviorInline\n\tDOverscrollBehaviorX\n\tDOverscrollBehaviorY\n\tDPadding\n\tDPaddingBlockEnd\n\tDPaddingBlockStart\n\tDPaddingBottom\n\tDPaddingInlineEnd\n\tDPaddingInlineStart\n\tDPaddingLeft\n\tDPaddingRight\n\tDPaddingTop\n\tDPageBreakAfter\n\tDPageBreakBefore\n\tDPageBreakInside\n\tDPaintOrder\n\tDPerspective\n\tDPerspectiveOrigin\n\tDPlaceContent\n\tDPlaceItems\n\tDPlaceSelf\n\tDPointerEvents\n\tDPosition\n\tDPrintColorAdjust\n\tDQuotes\n\tDResize\n\tDRight\n\tDRotate\n\tDRowGap\n\tDRubyAlign\n\tDRubyPosition\n\tDScale\n\tDScrollBehavior\n\tDShapeRendering\n\tDStopColor\n\tDStopOpacity\n\tDStroke\n\tDStrokeDasharray\n\tDStrokeDashoffset\n\tDStrokeLinecap\n\tDStrokeLinejoin\n\tDStrokeMiterlimit\n\tDStrokeOpacity\n\tDStrokeWidth\n\tDTabSize\n\tDTableLayout\n\tDTextAlign\n\tDTextAlignLast\n\tDTextAnchor\n\tDTextCombineUpright\n\tDTextDecoration\n\tDTextDecorationColor\n\tDTextDecorationLine\n\tDTextDecorationSkip\n\tDTextDecorationStyle\n\tDTextEmphasis\n\tDTextEmphasisColor\n\tDTextEmphasisPosition\n\tDTextEmphasisStyle\n\tDTextIndent\n\tDTextJustify\n\tDTextOrientation\n\tDTextOverflow\n\tDTextRendering\n\tDTextShadow\n\tDTextSizeAdjust\n\tDTextTransform\n\tDTextUnderlinePosition\n\tDTop\n\tDTouchAction\n\tDTransform\n\tDTransformBox\n\tDTransformOrigin\n\tDTransformStyle\n\tDTransition\n\tDTransitionDelay\n\tDTransitionDuration\n\tDTransitionProperty\n\tDTransitionTimingFunction\n\tDTranslate\n\tDUnicodeBidi\n\tDUserSelect\n\tDVerticalAlign\n\tDVisibility\n\tDWhiteSpace\n\tDWidows\n\tDWidth\n\tDWillChange\n\tDWordBreak\n\tDWordSpacing\n\tDWordWrap\n\tDWritingMode\n\tDZIndex\n\tDZoom\n)\n\nvar KnownDeclarations = map[string]D{\n\t\"align-content\":               DAlignContent,\n\t\"align-items\":                 DAlignItems,\n\t\"align-self\":                  DAlignSelf,\n\t\"alignment-baseline\":          DAlignmentBaseline,\n\t\"all\":                         DAll,\n\t\"animation\":                   DAnimation,\n\t\"animation-delay\":             DAnimationDelay,\n\t\"animation-direction\":         DAnimationDirection,\n\t\"animation-duration\":          DAnimationDuration,\n\t\"animation-fill-mode\":         DAnimationFillMode,\n\t\"animation-iteration-count\":   DAnimationIterationCount,\n\t\"animation-name\":              DAnimationName,\n\t\"animation-play-state\":        DAnimationPlayState,\n\t\"animation-timing-function\":   DAnimationTimingFunction,\n\t\"appearance\":                  DAppearance,\n\t\"backdrop-filter\":             DBackdropFilter,\n\t\"backface-visibility\":         DBackfaceVisibility,\n\t\"background\":                  DBackground,\n\t\"background-attachment\":       DBackgroundAttachment,\n\t\"background-clip\":             DBackgroundClip,\n\t\"background-color\":            DBackgroundColor,\n\t\"background-image\":            DBackgroundImage,\n\t\"background-origin\":           DBackgroundOrigin,\n\t\"background-position\":         DBackgroundPosition,\n\t\"background-position-x\":       DBackgroundPositionX,\n\t\"background-position-y\":       DBackgroundPositionY,\n\t\"background-repeat\":           DBackgroundRepeat,\n\t\"background-size\":             DBackgroundSize,\n\t\"baseline-shift\":              DBaselineShift,\n\t\"block-size\":                  DBlockSize,\n\t\"border\":                      DBorder,\n\t\"border-block-end\":            DBorderBlockEnd,\n\t\"border-block-end-color\":      DBorderBlockEndColor,\n\t\"border-block-end-style\":      DBorderBlockEndStyle,\n\t\"border-block-end-width\":      DBorderBlockEndWidth,\n\t\"border-block-start\":          DBorderBlockStart,\n\t\"border-block-start-color\":    DBorderBlockStartColor,\n\t\"border-block-start-style\":    DBorderBlockStartStyle,\n\t\"border-block-start-width\":    DBorderBlockStartWidth,\n\t\"border-bottom\":               DBorderBottom,\n\t\"border-bottom-color\":         DBorderBottomColor,\n\t\"border-bottom-left-radius\":   DBorderBottomLeftRadius,\n\t\"border-bottom-right-radius\":  DBorderBottomRightRadius,\n\t\"border-bottom-style\":         DBorderBottomStyle,\n\t\"border-bottom-width\":         DBorderBottomWidth,\n\t\"border-collapse\":             DBorderCollapse,\n\t\"border-color\":                DBorderColor,\n\t\"border-image\":                DBorderImage,\n\t\"border-image-outset\":         DBorderImageOutset,\n\t\"border-image-repeat\":         DBorderImageRepeat,\n\t\"border-image-slice\":          DBorderImageSlice,\n\t\"border-image-source\":         DBorderImageSource,\n\t\"border-image-width\":          DBorderImageWidth,\n\t\"border-inline-end\":           DBorderInlineEnd,\n\t\"border-inline-end-color\":     DBorderInlineEndColor,\n\t\"border-inline-end-style\":     DBorderInlineEndStyle,\n\t\"border-inline-end-width\":     DBorderInlineEndWidth,\n\t\"border-inline-start\":         DBorderInlineStart,\n\t\"border-inline-start-color\":   DBorderInlineStartColor,\n\t\"border-inline-start-style\":   DBorderInlineStartStyle,\n\t\"border-inline-start-width\":   DBorderInlineStartWidth,\n\t\"border-left\":                 DBorderLeft,\n\t\"border-left-color\":           DBorderLeftColor,\n\t\"border-left-style\":           DBorderLeftStyle,\n\t\"border-left-width\":           DBorderLeftWidth,\n\t\"border-radius\":               DBorderRadius,\n\t\"border-right\":                DBorderRight,\n\t\"border-right-color\":          DBorderRightColor,\n\t\"border-right-style\":          DBorderRightStyle,\n\t\"border-right-width\":          DBorderRightWidth,\n\t\"border-spacing\":              DBorderSpacing,\n\t\"border-style\":                DBorderStyle,\n\t\"border-top\":                  DBorderTop,\n\t\"border-top-color\":            DBorderTopColor,\n\t\"border-top-left-radius\":      DBorderTopLeftRadius,\n\t\"border-top-right-radius\":     DBorderTopRightRadius,\n\t\"border-top-style\":            DBorderTopStyle,\n\t\"border-top-width\":            DBorderTopWidth,\n\t\"border-width\":                DBorderWidth,\n\t\"bottom\":                      DBottom,\n\t\"box-decoration-break\":        DBoxDecorationBreak,\n\t\"box-shadow\":                  DBoxShadow,\n\t\"box-sizing\":                  DBoxSizing,\n\t\"break-after\":                 DBreakAfter,\n\t\"break-before\":                DBreakBefore,\n\t\"break-inside\":                DBreakInside,\n\t\"caption-side\":                DCaptionSide,\n\t\"caret-color\":                 DCaretColor,\n\t\"clear\":                       DClear,\n\t\"clip\":                        DClip,\n\t\"clip-path\":                   DClipPath,\n\t\"clip-rule\":                   DClipRule,\n\t\"color\":                       DColor,\n\t\"color-interpolation\":         DColorInterpolation,\n\t\"color-interpolation-filters\": DColorInterpolationFilters,\n\t\"column-count\":                DColumnCount,\n\t\"column-fill\":                 DColumnFill,\n\t\"column-gap\":                  DColumnGap,\n\t\"column-rule\":                 DColumnRule,\n\t\"column-rule-color\":           DColumnRuleColor,\n\t\"column-rule-style\":           DColumnRuleStyle,\n\t\"column-rule-width\":           DColumnRuleWidth,\n\t\"column-span\":                 DColumnSpan,\n\t\"column-width\":                DColumnWidth,\n\t\"columns\":                     DColumns,\n\t\"composes\":                    DComposes,\n\t\"container\":                   DContainer,\n\t\"container-name\":              DContainerName,\n\t\"container-type\":              DContainerType,\n\t\"content\":                     DContent,\n\t\"counter-increment\":           DCounterIncrement,\n\t\"counter-reset\":               DCounterReset,\n\t\"css-float\":                   DCssFloat,\n\t\"css-text\":                    DCssText,\n\t\"cursor\":                      DCursor,\n\t\"direction\":                   DDirection,\n\t\"display\":                     DDisplay,\n\t\"dominant-baseline\":           DDominantBaseline,\n\t\"empty-cells\":                 DEmptyCells,\n\t\"fill\":                        DFill,\n\t\"fill-opacity\":                DFillOpacity,\n\t\"fill-rule\":                   DFillRule,\n\t\"filter\":                      DFilter,\n\t\"flex\":                        DFlex,\n\t\"flex-basis\":                  DFlexBasis,\n\t\"flex-direction\":              DFlexDirection,\n\t\"flex-flow\":                   DFlexFlow,\n\t\"flex-grow\":                   DFlexGrow,\n\t\"flex-shrink\":                 DFlexShrink,\n\t\"flex-wrap\":                   DFlexWrap,\n\t\"float\":                       DFloat,\n\t\"flood-color\":                 DFloodColor,\n\t\"flood-opacity\":               DFloodOpacity,\n\t\"font\":                        DFont,\n\t\"font-family\":                 DFontFamily,\n\t\"font-feature-settings\":       DFontFeatureSettings,\n\t\"font-kerning\":                DFontKerning,\n\t\"font-size\":                   DFontSize,\n\t\"font-size-adjust\":            DFontSizeAdjust,\n\t\"font-stretch\":                DFontStretch,\n\t\"font-style\":                  DFontStyle,\n\t\"font-synthesis\":              DFontSynthesis,\n\t\"font-variant\":                DFontVariant,\n\t\"font-variant-caps\":           DFontVariantCaps,\n\t\"font-variant-east-asian\":     DFontVariantEastAsian,\n\t\"font-variant-ligatures\":      DFontVariantLigatures,\n\t\"font-variant-numeric\":        DFontVariantNumeric,\n\t\"font-variant-position\":       DFontVariantPosition,\n\t\"font-weight\":                 DFontWeight,\n\t\"gap\":                         DGap,\n\t\"glyph-orientation-vertical\":  DGlyphOrientationVertical,\n\t\"grid\":                        DGrid,\n\t\"grid-area\":                   DGridArea,\n\t\"grid-auto-columns\":           DGridAutoColumns,\n\t\"grid-auto-flow\":              DGridAutoFlow,\n\t\"grid-auto-rows\":              DGridAutoRows,\n\t\"grid-column\":                 DGridColumn,\n\t\"grid-column-end\":             DGridColumnEnd,\n\t\"grid-column-gap\":             DGridColumnGap,\n\t\"grid-column-start\":           DGridColumnStart,\n\t\"grid-gap\":                    DGridGap,\n\t\"grid-row\":                    DGridRow,\n\t\"grid-row-end\":                DGridRowEnd,\n\t\"grid-row-gap\":                DGridRowGap,\n\t\"grid-row-start\":              DGridRowStart,\n\t\"grid-template\":               DGridTemplate,\n\t\"grid-template-areas\":         DGridTemplateAreas,\n\t\"grid-template-columns\":       DGridTemplateColumns,\n\t\"grid-template-rows\":          DGridTemplateRows,\n\t\"height\":                      DHeight,\n\t\"hyphens\":                     DHyphens,\n\t\"image-orientation\":           DImageOrientation,\n\t\"image-rendering\":             DImageRendering,\n\t\"initial-letter\":              DInitialLetter,\n\t\"inline-size\":                 DInlineSize,\n\t\"inset\":                       DInset,\n\t\"justify-content\":             DJustifyContent,\n\t\"justify-items\":               DJustifyItems,\n\t\"justify-self\":                DJustifySelf,\n\t\"left\":                        DLeft,\n\t\"letter-spacing\":              DLetterSpacing,\n\t\"lighting-color\":              DLightingColor,\n\t\"line-break\":                  DLineBreak,\n\t\"line-height\":                 DLineHeight,\n\t\"list-style\":                  DListStyle,\n\t\"list-style-image\":            DListStyleImage,\n\t\"list-style-position\":         DListStylePosition,\n\t\"list-style-type\":             DListStyleType,\n\t\"margin\":                      DMargin,\n\t\"margin-block-end\":            DMarginBlockEnd,\n\t\"margin-block-start\":          DMarginBlockStart,\n\t\"margin-bottom\":               DMarginBottom,\n\t\"margin-inline-end\":           DMarginInlineEnd,\n\t\"margin-inline-start\":         DMarginInlineStart,\n\t\"margin-left\":                 DMarginLeft,\n\t\"margin-right\":                DMarginRight,\n\t\"margin-top\":                  DMarginTop,\n\t\"marker\":                      DMarker,\n\t\"marker-end\":                  DMarkerEnd,\n\t\"marker-mid\":                  DMarkerMid,\n\t\"marker-start\":                DMarkerStart,\n\t\"mask\":                        DMask,\n\t\"mask-composite\":              DMaskComposite,\n\t\"mask-image\":                  DMaskImage,\n\t\"mask-origin\":                 DMaskOrigin,\n\t\"mask-position\":               DMaskPosition,\n\t\"mask-repeat\":                 DMaskRepeat,\n\t\"mask-size\":                   DMaskSize,\n\t\"mask-type\":                   DMaskType,\n\t\"max-block-size\":              DMaxBlockSize,\n\t\"max-height\":                  DMaxHeight,\n\t\"max-inline-size\":             DMaxInlineSize,\n\t\"max-width\":                   DMaxWidth,\n\t\"min-block-size\":              DMinBlockSize,\n\t\"min-height\":                  DMinHeight,\n\t\"min-inline-size\":             DMinInlineSize,\n\t\"min-width\":                   DMinWidth,\n\t\"object-fit\":                  DObjectFit,\n\t\"object-position\":             DObjectPosition,\n\t\"opacity\":                     DOpacity,\n\t\"order\":                       DOrder,\n\t\"orphans\":                     DOrphans,\n\t\"outline\":                     DOutline,\n\t\"outline-color\":               DOutlineColor,\n\t\"outline-offset\":              DOutlineOffset,\n\t\"outline-style\":               DOutlineStyle,\n\t\"outline-width\":               DOutlineWidth,\n\t\"overflow\":                    DOverflow,\n\t\"overflow-anchor\":             DOverflowAnchor,\n\t\"overflow-wrap\":               DOverflowWrap,\n\t\"overflow-x\":                  DOverflowX,\n\t\"overflow-y\":                  DOverflowY,\n\t\"overscroll-behavior\":         DOverscrollBehavior,\n\t\"overscroll-behavior-block\":   DOverscrollBehaviorBlock,\n\t\"overscroll-behavior-inline\":  DOverscrollBehaviorInline,\n\t\"overscroll-behavior-x\":       DOverscrollBehaviorX,\n\t\"overscroll-behavior-y\":       DOverscrollBehaviorY,\n\t\"padding\":                     DPadding,\n\t\"padding-block-end\":           DPaddingBlockEnd,\n\t\"padding-block-start\":         DPaddingBlockStart,\n\t\"padding-bottom\":              DPaddingBottom,\n\t\"padding-inline-end\":          DPaddingInlineEnd,\n\t\"padding-inline-start\":        DPaddingInlineStart,\n\t\"padding-left\":                DPaddingLeft,\n\t\"padding-right\":               DPaddingRight,\n\t\"padding-top\":                 DPaddingTop,\n\t\"page-break-after\":            DPageBreakAfter,\n\t\"page-break-before\":           DPageBreakBefore,\n\t\"page-break-inside\":           DPageBreakInside,\n\t\"paint-order\":                 DPaintOrder,\n\t\"perspective\":                 DPerspective,\n\t\"perspective-origin\":          DPerspectiveOrigin,\n\t\"place-content\":               DPlaceContent,\n\t\"place-items\":                 DPlaceItems,\n\t\"place-self\":                  DPlaceSelf,\n\t\"pointer-events\":              DPointerEvents,\n\t\"position\":                    DPosition,\n\t\"print-color-adjust\":          DPrintColorAdjust,\n\t\"quotes\":                      DQuotes,\n\t\"resize\":                      DResize,\n\t\"right\":                       DRight,\n\t\"rotate\":                      DRotate,\n\t\"row-gap\":                     DRowGap,\n\t\"ruby-align\":                  DRubyAlign,\n\t\"ruby-position\":               DRubyPosition,\n\t\"scale\":                       DScale,\n\t\"scroll-behavior\":             DScrollBehavior,\n\t\"shape-rendering\":             DShapeRendering,\n\t\"stop-color\":                  DStopColor,\n\t\"stop-opacity\":                DStopOpacity,\n\t\"stroke\":                      DStroke,\n\t\"stroke-dasharray\":            DStrokeDasharray,\n\t\"stroke-dashoffset\":           DStrokeDashoffset,\n\t\"stroke-linecap\":              DStrokeLinecap,\n\t\"stroke-linejoin\":             DStrokeLinejoin,\n\t\"stroke-miterlimit\":           DStrokeMiterlimit,\n\t\"stroke-opacity\":              DStrokeOpacity,\n\t\"stroke-width\":                DStrokeWidth,\n\t\"tab-size\":                    DTabSize,\n\t\"table-layout\":                DTableLayout,\n\t\"text-align\":                  DTextAlign,\n\t\"text-align-last\":             DTextAlignLast,\n\t\"text-anchor\":                 DTextAnchor,\n\t\"text-combine-upright\":        DTextCombineUpright,\n\t\"text-decoration\":             DTextDecoration,\n\t\"text-decoration-color\":       DTextDecorationColor,\n\t\"text-decoration-line\":        DTextDecorationLine,\n\t\"text-decoration-skip\":        DTextDecorationSkip,\n\t\"text-decoration-style\":       DTextDecorationStyle,\n\t\"text-emphasis\":               DTextEmphasis,\n\t\"text-emphasis-color\":         DTextEmphasisColor,\n\t\"text-emphasis-position\":      DTextEmphasisPosition,\n\t\"text-emphasis-style\":         DTextEmphasisStyle,\n\t\"text-indent\":                 DTextIndent,\n\t\"text-justify\":                DTextJustify,\n\t\"text-orientation\":            DTextOrientation,\n\t\"text-overflow\":               DTextOverflow,\n\t\"text-rendering\":              DTextRendering,\n\t\"text-shadow\":                 DTextShadow,\n\t\"text-size-adjust\":            DTextSizeAdjust,\n\t\"text-transform\":              DTextTransform,\n\t\"text-underline-position\":     DTextUnderlinePosition,\n\t\"top\":                         DTop,\n\t\"touch-action\":                DTouchAction,\n\t\"transform\":                   DTransform,\n\t\"transform-box\":               DTransformBox,\n\t\"transform-origin\":            DTransformOrigin,\n\t\"transform-style\":             DTransformStyle,\n\t\"transition\":                  DTransition,\n\t\"transition-delay\":            DTransitionDelay,\n\t\"transition-duration\":         DTransitionDuration,\n\t\"transition-property\":         DTransitionProperty,\n\t\"transition-timing-function\":  DTransitionTimingFunction,\n\t\"translate\":                   DTranslate,\n\t\"unicode-bidi\":                DUnicodeBidi,\n\t\"user-select\":                 DUserSelect,\n\t\"vertical-align\":              DVerticalAlign,\n\t\"visibility\":                  DVisibility,\n\t\"white-space\":                 DWhiteSpace,\n\t\"widows\":                      DWidows,\n\t\"width\":                       DWidth,\n\t\"will-change\":                 DWillChange,\n\t\"word-break\":                  DWordBreak,\n\t\"word-spacing\":                DWordSpacing,\n\t\"word-wrap\":                   DWordWrap,\n\t\"writing-mode\":                DWritingMode,\n\t\"z-index\":                     DZIndex,\n\t\"zoom\":                        DZoom,\n}\n\nvar typoDetector *helpers.TypoDetector\nvar typoDetectorMutex sync.Mutex\n\nfunc MaybeCorrectDeclarationTypo(text string) (string, bool) {\n\t// Ignore CSS variables, which should not be corrected to CSS properties\n\tif strings.HasPrefix(text, \"--\") {\n\t\treturn \"\", false\n\t}\n\n\ttypoDetectorMutex.Lock()\n\tdefer typoDetectorMutex.Unlock()\n\n\t// Lazily-initialize the typo detector for speed when it's not needed\n\tif typoDetector == nil {\n\t\tvalid := make([]string, 0, len(KnownDeclarations))\n\t\tfor key := range KnownDeclarations {\n\t\t\tvalid = append(valid, key)\n\t\t}\n\t\tdetector := helpers.MakeTypoDetector(valid)\n\t\ttypoDetector = &detector\n\t}\n\n\treturn typoDetector.MaybeCorrectTypo(text)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_lexer/css_lexer.go",
    "content": "package css_lexer\n\nimport (\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\n// The lexer converts a source file to a stream of tokens. Unlike esbuild's\n// JavaScript lexer, this CSS lexer runs to completion before the CSS parser\n// begins, resulting in a single array of all tokens in the file.\n\ntype T uint8\n\nconst eof = -1\n\nconst (\n\tTEndOfFile T = iota\n\n\tTAtKeyword\n\tTUnterminatedString\n\tTBadURL\n\tTCDC // \"-->\"\n\tTCDO // \"<!--\"\n\tTCloseBrace\n\tTCloseBracket\n\tTCloseParen\n\tTColon\n\tTComma\n\tTDelim\n\tTDelimAmpersand\n\tTDelimAsterisk\n\tTDelimBar\n\tTDelimCaret\n\tTDelimDollar\n\tTDelimDot\n\tTDelimEquals\n\tTDelimExclamation\n\tTDelimGreaterThan\n\tTDelimLessThan\n\tTDelimMinus\n\tTDelimPlus\n\tTDelimSlash\n\tTDelimTilde\n\tTDimension\n\tTFunction\n\tTHash\n\tTIdent\n\tTNumber\n\tTOpenBrace\n\tTOpenBracket\n\tTOpenParen\n\tTPercentage\n\tTSemicolon\n\tTString\n\tTURL\n\tTWhitespace\n\n\t// This is never something that the lexer generates directly. Instead this is\n\t// an esbuild-specific token for global/local names that \"TIdent\" tokens may\n\t// be changed into.\n\tTSymbol\n)\n\nvar tokenToString = []string{\n\t\"end of file\",\n\t\"@-keyword\",\n\t\"bad string token\",\n\t\"bad URL token\",\n\t\"\\\"-->\\\"\",\n\t\"\\\"<!--\\\"\",\n\t\"\\\"}\\\"\",\n\t\"\\\"]\\\"\",\n\t\"\\\")\\\"\",\n\t\"\\\":\\\"\",\n\t\"\\\",\\\"\",\n\t\"delimiter\",\n\t\"\\\"&\\\"\",\n\t\"\\\"*\\\"\",\n\t\"\\\"|\\\"\",\n\t\"\\\"^\\\"\",\n\t\"\\\"$\\\"\",\n\t\"\\\".\\\"\",\n\t\"\\\"=\\\"\",\n\t\"\\\"!\\\"\",\n\t\"\\\">\\\"\",\n\t\"\\\"<\\\"\",\n\t\"\\\"-\\\"\",\n\t\"\\\"+\\\"\",\n\t\"\\\"/\\\"\",\n\t\"\\\"~\\\"\",\n\t\"dimension\",\n\t\"function token\",\n\t\"hash token\",\n\t\"identifier\",\n\t\"number\",\n\t\"\\\"{\\\"\",\n\t\"\\\"[\\\"\",\n\t\"\\\"(\\\"\",\n\t\"percentage\",\n\t\"\\\";\\\"\",\n\t\"string token\",\n\t\"URL token\",\n\t\"whitespace\",\n\n\t\"identifier\",\n}\n\nfunc (t T) String() string {\n\treturn tokenToString[t]\n}\n\nfunc (t T) IsNumeric() bool {\n\treturn t == TNumber || t == TPercentage || t == TDimension\n}\n\ntype TokenFlags uint8\n\nconst (\n\tIsID TokenFlags = 1 << iota\n\tDidWarnAboutSingleLineComment\n)\n\n// This token struct is designed to be memory-efficient. It just references a\n// range in the input file instead of directly containing the substring of text\n// since a range takes up less memory than a string.\ntype Token struct {\n\tRange      logger.Range // 8 bytes\n\tUnitOffset uint16       // 2 bytes\n\tKind       T            // 1 byte\n\tFlags      TokenFlags   // 1 byte\n}\n\nfunc (token Token) DecodedText(contents string) string {\n\traw := contents[token.Range.Loc.Start:token.Range.End()]\n\n\tswitch token.Kind {\n\tcase TIdent, TDimension:\n\t\treturn decodeEscapesInToken(raw)\n\n\tcase TAtKeyword, THash:\n\t\treturn decodeEscapesInToken(raw[1:])\n\n\tcase TFunction:\n\t\treturn decodeEscapesInToken(raw[:len(raw)-1])\n\n\tcase TString:\n\t\treturn decodeEscapesInToken(raw[1 : len(raw)-1])\n\n\tcase TURL:\n\t\tstart := 4\n\t\tend := len(raw)\n\n\t\t// Note: URL tokens with syntax errors may not have a trailing \")\"\n\t\tif raw[end-1] == ')' {\n\t\t\tend--\n\t\t}\n\n\t\t// Trim leading and trailing whitespace\n\t\tfor start < end && isWhitespace(rune(raw[start])) {\n\t\t\tstart++\n\t\t}\n\t\tfor start < end && isWhitespace(rune(raw[end-1])) {\n\t\t\tend--\n\t\t}\n\n\t\treturn decodeEscapesInToken(raw[start:end])\n\t}\n\n\treturn raw\n}\n\ntype lexer struct {\n\tOptions\n\tlog                     logger.Log\n\tsource                  logger.Source\n\tallComments             []logger.Range\n\tlegalCommentsBefore     []Comment\n\tsourceMappingURL        logger.Span\n\ttracker                 logger.LineColumnTracker\n\tapproximateNewlineCount int\n\tcurrent                 int\n\toldSingleLineCommentEnd logger.Loc\n\tcodePoint               rune\n\tToken                   Token\n}\n\ntype Comment struct {\n\tText            string\n\tLoc             logger.Loc\n\tTokenIndexAfter uint32\n}\n\ntype TokenizeResult struct {\n\tTokens               []Token\n\tAllComments          []logger.Range\n\tLegalComments        []Comment\n\tSourceMapComment     logger.Span\n\tApproximateLineCount int32\n}\n\ntype Options struct {\n\tRecordAllComments bool\n}\n\nfunc Tokenize(log logger.Log, source logger.Source, options Options) TokenizeResult {\n\tlexer := lexer{\n\t\tOptions: options,\n\t\tlog:     log,\n\t\tsource:  source,\n\t\ttracker: logger.MakeLineColumnTracker(&source),\n\t}\n\tlexer.step()\n\n\t// The U+FEFF character is usually a zero-width non-breaking space. However,\n\t// when it's used at the start of a text stream it is called a BOM (byte order\n\t// mark) instead and indicates that the text stream is UTF-8 encoded. This is\n\t// problematic for us because CSS does not treat U+FEFF as whitespace. Only\n\t// \" \\t\\r\\n\\f\" characters are treated as whitespace. Skip over the BOM if it\n\t// is present so it doesn't cause us trouble when we try to parse it.\n\tif lexer.codePoint == '\\uFEFF' {\n\t\tlexer.step()\n\t}\n\n\tlexer.next()\n\tvar tokens []Token\n\tvar legalComments []Comment\n\tfor lexer.Token.Kind != TEndOfFile {\n\t\tif lexer.legalCommentsBefore != nil {\n\t\t\tfor _, comment := range lexer.legalCommentsBefore {\n\t\t\t\tcomment.TokenIndexAfter = uint32(len(tokens))\n\t\t\t\tlegalComments = append(legalComments, comment)\n\t\t\t}\n\t\t\tlexer.legalCommentsBefore = nil\n\t\t}\n\t\ttokens = append(tokens, lexer.Token)\n\t\tlexer.next()\n\t}\n\tif lexer.legalCommentsBefore != nil {\n\t\tfor _, comment := range lexer.legalCommentsBefore {\n\t\t\tcomment.TokenIndexAfter = uint32(len(tokens))\n\t\t\tlegalComments = append(legalComments, comment)\n\t\t}\n\t\tlexer.legalCommentsBefore = nil\n\t}\n\treturn TokenizeResult{\n\t\tTokens:               tokens,\n\t\tAllComments:          lexer.allComments,\n\t\tLegalComments:        legalComments,\n\t\tApproximateLineCount: int32(lexer.approximateNewlineCount) + 1,\n\t\tSourceMapComment:     lexer.sourceMappingURL,\n\t}\n}\n\nfunc (lexer *lexer) step() {\n\tcodePoint, width := utf8.DecodeRuneInString(lexer.source.Contents[lexer.current:])\n\n\t// Use -1 to indicate the end of the file\n\tif width == 0 {\n\t\tcodePoint = eof\n\t}\n\n\t// Track the approximate number of newlines in the file so we can preallocate\n\t// the line offset table in the printer for source maps. The line offset table\n\t// is the #1 highest allocation in the heap profile, so this is worth doing.\n\t// This count is approximate because it handles \"\\n\" and \"\\r\\n\" (the common\n\t// cases) but not \"\\r\" or \"\\u2028\" or \"\\u2029\". Getting this wrong is harmless\n\t// because it's only a preallocation. The array will just grow if it's too small.\n\tif codePoint == '\\n' {\n\t\tlexer.approximateNewlineCount++\n\t}\n\n\tlexer.codePoint = codePoint\n\tlexer.Token.Range.Len = int32(lexer.current) - lexer.Token.Range.Loc.Start\n\tlexer.current += width\n}\n\nfunc (lexer *lexer) next() {\n\t// Reference: https://www.w3.org/TR/css-syntax-3/\n\n\tfor {\n\t\tlexer.Token = Token{Range: logger.Range{Loc: logger.Loc{Start: lexer.Token.Range.End()}}}\n\n\t\tswitch lexer.codePoint {\n\t\tcase eof:\n\t\t\tlexer.Token.Kind = TEndOfFile\n\n\t\tcase '/':\n\t\t\tlexer.step()\n\t\t\tswitch lexer.codePoint {\n\t\t\tcase '*':\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.consumeToEndOfMultiLineComment(lexer.Token.Range)\n\t\t\t\tcontinue\n\t\t\tcase '/':\n\t\t\t\t// Warn when people use \"//\" comments, which are invalid in CSS\n\t\t\t\tloc := lexer.Token.Range.Loc\n\t\t\t\tif loc.Start >= lexer.oldSingleLineCommentEnd.Start {\n\t\t\t\t\tcontents := lexer.source.Contents\n\t\t\t\t\tend := lexer.current\n\t\t\t\t\tfor end < len(contents) && !isNewline(rune(contents[end])) {\n\t\t\t\t\t\tend++\n\t\t\t\t\t}\n\t\t\t\t\tlexer.log.AddID(logger.MsgID_CSS_JSCommentInCSS, logger.Warning, &lexer.tracker, logger.Range{Loc: loc, Len: 2},\n\t\t\t\t\t\t\"Comments in CSS use \\\"/* ... */\\\" instead of \\\"//\\\"\")\n\t\t\t\t\tlexer.oldSingleLineCommentEnd.Start = int32(end)\n\t\t\t\t\tlexer.Token.Flags |= DidWarnAboutSingleLineComment\n\t\t\t\t}\n\t\t\t}\n\t\t\tlexer.Token.Kind = TDelimSlash\n\n\t\tcase ' ', '\\t', '\\n', '\\r', '\\f':\n\t\t\tlexer.step()\n\t\t\tfor {\n\t\t\t\tif isWhitespace(lexer.codePoint) {\n\t\t\t\t\tlexer.step()\n\t\t\t\t} else if lexer.codePoint == '/' && lexer.current < len(lexer.source.Contents) && lexer.source.Contents[lexer.current] == '*' {\n\t\t\t\t\tstartRange := logger.Range{Loc: logger.Loc{Start: lexer.Token.Range.End()}, Len: 2}\n\t\t\t\t\tlexer.step()\n\t\t\t\t\tlexer.step()\n\t\t\t\t\tlexer.consumeToEndOfMultiLineComment(startRange)\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tlexer.Token.Kind = TWhitespace\n\n\t\tcase '\"', '\\'':\n\t\t\tlexer.Token.Kind = lexer.consumeString()\n\n\t\tcase '#':\n\t\t\tlexer.step()\n\t\t\tif IsNameContinue(lexer.codePoint) || lexer.isValidEscape() {\n\t\t\t\tlexer.Token.Kind = THash\n\t\t\t\tif lexer.wouldStartIdentifier() {\n\t\t\t\t\tlexer.Token.Flags |= IsID\n\t\t\t\t}\n\t\t\t\tlexer.consumeName()\n\t\t\t} else {\n\t\t\t\tlexer.Token.Kind = TDelim\n\t\t\t}\n\n\t\tcase '(':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TOpenParen\n\n\t\tcase ')':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TCloseParen\n\n\t\tcase '[':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TOpenBracket\n\n\t\tcase ']':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TCloseBracket\n\n\t\tcase '{':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TOpenBrace\n\n\t\tcase '}':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TCloseBrace\n\n\t\tcase ',':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TComma\n\n\t\tcase ':':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TColon\n\n\t\tcase ';':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TSemicolon\n\n\t\tcase '+':\n\t\t\tif lexer.wouldStartNumber() {\n\t\t\t\tlexer.Token.Kind = lexer.consumeNumeric()\n\t\t\t} else {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.Token.Kind = TDelimPlus\n\t\t\t}\n\n\t\tcase '.':\n\t\t\tif lexer.wouldStartNumber() {\n\t\t\t\tlexer.Token.Kind = lexer.consumeNumeric()\n\t\t\t} else {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.Token.Kind = TDelimDot\n\t\t\t}\n\n\t\tcase '-':\n\t\t\tif lexer.wouldStartNumber() {\n\t\t\t\tlexer.Token.Kind = lexer.consumeNumeric()\n\t\t\t} else if lexer.current+2 <= len(lexer.source.Contents) && lexer.source.Contents[lexer.current:lexer.current+2] == \"->\" {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.Token.Kind = TCDC\n\t\t\t} else if lexer.wouldStartIdentifier() {\n\t\t\t\tlexer.Token.Kind = lexer.consumeIdentLike()\n\t\t\t} else {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.Token.Kind = TDelimMinus\n\t\t\t}\n\n\t\tcase '<':\n\t\t\tif lexer.current+3 <= len(lexer.source.Contents) && lexer.source.Contents[lexer.current:lexer.current+3] == \"!--\" {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.Token.Kind = TCDO\n\t\t\t} else {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.Token.Kind = TDelimLessThan\n\t\t\t}\n\n\t\tcase '@':\n\t\t\tlexer.step()\n\t\t\tif lexer.wouldStartIdentifier() {\n\t\t\t\tlexer.consumeName()\n\t\t\t\tlexer.Token.Kind = TAtKeyword\n\t\t\t} else {\n\t\t\t\tlexer.Token.Kind = TDelim\n\t\t\t}\n\n\t\tcase '\\\\':\n\t\t\tif lexer.isValidEscape() {\n\t\t\t\tlexer.Token.Kind = lexer.consumeIdentLike()\n\t\t\t} else {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.log.AddError(&lexer.tracker, lexer.Token.Range, \"Invalid escape\")\n\t\t\t\tlexer.Token.Kind = TDelim\n\t\t\t}\n\n\t\tcase '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':\n\t\t\tlexer.Token.Kind = lexer.consumeNumeric()\n\n\t\tcase '>':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimGreaterThan\n\n\t\tcase '~':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimTilde\n\n\t\tcase '&':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimAmpersand\n\n\t\tcase '*':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimAsterisk\n\n\t\tcase '|':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimBar\n\n\t\tcase '!':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimExclamation\n\n\t\tcase '=':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimEquals\n\n\t\tcase '^':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimCaret\n\n\t\tcase '$':\n\t\t\tlexer.step()\n\t\t\tlexer.Token.Kind = TDelimDollar\n\n\t\tdefault:\n\t\t\tif IsNameStart(lexer.codePoint) {\n\t\t\t\tlexer.Token.Kind = lexer.consumeIdentLike()\n\t\t\t} else {\n\t\t\t\tlexer.step()\n\t\t\t\tlexer.Token.Kind = TDelim\n\t\t\t}\n\t\t}\n\n\t\treturn\n\t}\n}\n\nfunc (lexer *lexer) consumeToEndOfMultiLineComment(startRange logger.Range) {\n\tstartOfSourceMappingURL := 0\n\tisLegalComment := false\n\n\tswitch lexer.codePoint {\n\tcase '#', '@':\n\t\t// Keep track of the contents of the \"sourceMappingURL=\" comment\n\t\tif strings.HasPrefix(lexer.source.Contents[lexer.current:], \" sourceMappingURL=\") {\n\t\t\tstartOfSourceMappingURL = lexer.current + len(\" sourceMappingURL=\")\n\t\t}\n\n\tcase '!':\n\t\t// Remember if this is a legal comment\n\t\tisLegalComment = true\n\t}\n\n\tfor {\n\t\tswitch lexer.codePoint {\n\t\tcase '*':\n\t\t\tendOfSourceMappingURL := lexer.current - 1\n\t\t\tlexer.step()\n\t\t\tif lexer.codePoint == '/' {\n\t\t\t\tcommentEnd := lexer.current\n\t\t\t\tlexer.step()\n\n\t\t\t\t// Record the source mapping URL\n\t\t\t\tif startOfSourceMappingURL != 0 {\n\t\t\t\t\tr := logger.Range{Loc: logger.Loc{Start: int32(startOfSourceMappingURL)}}\n\t\t\t\t\ttext := lexer.source.Contents[startOfSourceMappingURL:endOfSourceMappingURL]\n\t\t\t\t\tfor int(r.Len) < len(text) && !isWhitespace(rune(text[r.Len])) {\n\t\t\t\t\t\tr.Len++\n\t\t\t\t\t}\n\t\t\t\t\tlexer.sourceMappingURL = logger.Span{Text: text[:r.Len], Range: r}\n\t\t\t\t}\n\n\t\t\t\t// Record all comments\n\t\t\t\tcommentRange := logger.Range{Loc: startRange.Loc, Len: int32(commentEnd) - startRange.Loc.Start}\n\t\t\t\tif lexer.RecordAllComments {\n\t\t\t\t\tlexer.allComments = append(lexer.allComments, commentRange)\n\t\t\t\t}\n\n\t\t\t\t// Record legal comments\n\t\t\t\tif text := lexer.source.Contents[startRange.Loc.Start:commentEnd]; isLegalComment || containsAtPreserveOrAtLicense(text) {\n\t\t\t\t\ttext = lexer.source.CommentTextWithoutIndent(commentRange)\n\t\t\t\t\tlexer.legalCommentsBefore = append(lexer.legalCommentsBefore, Comment{Loc: startRange.Loc, Text: text})\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\n\t\tcase eof: // This indicates the end of the file\n\t\t\tlexer.log.AddErrorWithNotes(&lexer.tracker, logger.Range{Loc: logger.Loc{Start: lexer.Token.Range.End()}},\n\t\t\t\t\"Expected \\\"*/\\\" to terminate multi-line comment\",\n\t\t\t\t[]logger.MsgData{lexer.tracker.MsgData(startRange, \"The multi-line comment starts here:\")})\n\t\t\treturn\n\n\t\tdefault:\n\t\t\tlexer.step()\n\t\t}\n\t}\n}\n\nfunc containsAtPreserveOrAtLicense(text string) bool {\n\tfor i, c := range text {\n\t\tif c == '@' && (strings.HasPrefix(text[i+1:], \"preserve\") || strings.HasPrefix(text[i+1:], \"license\")) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (lexer *lexer) isValidEscape() bool {\n\tif lexer.codePoint != '\\\\' {\n\t\treturn false\n\t}\n\tc, _ := utf8.DecodeRuneInString(lexer.source.Contents[lexer.current:])\n\treturn !isNewline(c)\n}\n\nfunc (lexer *lexer) wouldStartIdentifier() bool {\n\tif IsNameStart(lexer.codePoint) {\n\t\treturn true\n\t}\n\n\tif lexer.codePoint == '-' {\n\t\tc, width := utf8.DecodeRuneInString(lexer.source.Contents[lexer.current:])\n\t\tif c == utf8.RuneError && width <= 1 {\n\t\t\treturn false // Decoding error\n\t\t}\n\t\tif IsNameStart(c) || c == '-' {\n\t\t\treturn true\n\t\t}\n\t\tif c == '\\\\' {\n\t\t\tc2, _ := utf8.DecodeRuneInString(lexer.source.Contents[lexer.current+width:])\n\t\t\treturn !isNewline(c2)\n\t\t}\n\t\treturn false\n\t}\n\n\treturn lexer.isValidEscape()\n}\n\nfunc WouldStartIdentifierWithoutEscapes(text string) bool {\n\tc, width := utf8.DecodeRuneInString(text)\n\tif c == utf8.RuneError && width <= 1 {\n\t\treturn false // Decoding error\n\t}\n\tif IsNameStart(c) {\n\t\treturn true\n\t}\n\n\tif c == '-' {\n\t\tc2, width2 := utf8.DecodeRuneInString(text[width:])\n\t\tif c2 == utf8.RuneError && width2 <= 1 {\n\t\t\treturn false // Decoding error\n\t\t}\n\t\tif IsNameStart(c2) || c2 == '-' {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc RangeOfIdentifier(source logger.Source, loc logger.Loc) logger.Range {\n\ttext := source.Contents[loc.Start:]\n\tif len(text) == 0 {\n\t\treturn logger.Range{Loc: loc, Len: 0}\n\t}\n\n\ti := 0\n\tn := len(text)\n\n\tfor {\n\t\tc, width := utf8.DecodeRuneInString(text[i:])\n\t\tif IsNameContinue(c) {\n\t\t\ti += width\n\t\t\tcontinue\n\t\t}\n\n\t\t// Handle an escape\n\t\tif c == '\\\\' && i+1 < n && !isNewline(rune(text[i+1])) {\n\t\t\ti += width // Skip the backslash\n\t\t\tc, width = utf8.DecodeRuneInString(text[i:])\n\t\t\tif _, ok := isHex(c); ok {\n\t\t\t\ti += width\n\t\t\t\tc, width = utf8.DecodeRuneInString(text[i:])\n\t\t\t\tfor j := 0; j < 5; j++ {\n\t\t\t\t\tif _, ok := isHex(c); !ok {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ti += width\n\t\t\t\t\tc, width = utf8.DecodeRuneInString(text[i:])\n\t\t\t\t}\n\t\t\t\tif isWhitespace(c) {\n\t\t\t\t\ti += width\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tbreak\n\t}\n\n\t// Don't end with a whitespace\n\tif i > 0 && isWhitespace(rune(text[i-1])) {\n\t\ti--\n\t}\n\n\treturn logger.Range{Loc: loc, Len: int32(i)}\n}\n\nfunc (lexer *lexer) wouldStartNumber() bool {\n\tif lexer.codePoint >= '0' && lexer.codePoint <= '9' {\n\t\treturn true\n\t} else if lexer.codePoint == '.' {\n\t\tcontents := lexer.source.Contents\n\t\tif lexer.current < len(contents) {\n\t\t\tc := contents[lexer.current]\n\t\t\treturn c >= '0' && c <= '9'\n\t\t}\n\t} else if lexer.codePoint == '+' || lexer.codePoint == '-' {\n\t\tcontents := lexer.source.Contents\n\t\tn := len(contents)\n\t\tif lexer.current < n {\n\t\t\tc := contents[lexer.current]\n\t\t\tif c >= '0' && c <= '9' {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif c == '.' && lexer.current+1 < n {\n\t\t\t\tc = contents[lexer.current+1]\n\t\t\t\treturn c >= '0' && c <= '9'\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// Note: This function is hot in profiles\nfunc (lexer *lexer) consumeName() string {\n\t// Common case: no escapes, identifier is a substring of the input. Doing this\n\t// in a tight loop that avoids UTF-8 decoding and that increments a single\n\t// number instead of doing \"step()\" is noticeably faster. For example, doing\n\t// this sped up end-to-end parsing and printing of a large CSS file from 97ms\n\t// to 84ms (around 15% faster).\n\tcontents := lexer.source.Contents\n\tif IsNameContinue(lexer.codePoint) {\n\t\tn := len(contents)\n\t\ti := lexer.current\n\t\tfor i < n && IsNameContinue(rune(contents[i])) {\n\t\t\ti++\n\t\t}\n\t\tlexer.current = i\n\t\tlexer.step()\n\t}\n\traw := contents[lexer.Token.Range.Loc.Start:lexer.Token.Range.End()]\n\tif !lexer.isValidEscape() {\n\t\treturn raw\n\t}\n\n\t// Uncommon case: escapes, identifier is allocated\n\tsb := strings.Builder{}\n\tsb.WriteString(raw)\n\tsb.WriteRune(lexer.consumeEscape())\n\tfor {\n\t\tif IsNameContinue(lexer.codePoint) {\n\t\t\tsb.WriteRune(lexer.codePoint)\n\t\t\tlexer.step()\n\t\t} else if lexer.isValidEscape() {\n\t\t\tsb.WriteRune(lexer.consumeEscape())\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\treturn sb.String()\n}\n\nfunc (lexer *lexer) consumeEscape() rune {\n\tlexer.step() // Skip the backslash\n\tc := lexer.codePoint\n\n\tif hex, ok := isHex(c); ok {\n\t\tlexer.step()\n\t\tfor i := 0; i < 5; i++ {\n\t\t\tif next, ok := isHex(lexer.codePoint); ok {\n\t\t\t\tlexer.step()\n\t\t\t\thex = hex*16 + next\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif isWhitespace(lexer.codePoint) {\n\t\t\tlexer.step()\n\t\t}\n\t\tif hex == 0 || (hex >= 0xD800 && hex <= 0xDFFF) || hex > 0x10FFFF {\n\t\t\treturn utf8.RuneError\n\t\t}\n\t\treturn rune(hex)\n\t}\n\n\tif c == eof {\n\t\treturn utf8.RuneError\n\t}\n\n\tlexer.step()\n\treturn c\n}\n\nfunc (lexer *lexer) consumeIdentLike() T {\n\tname := lexer.consumeName()\n\n\tif lexer.codePoint == '(' {\n\t\tmatchingLoc := logger.Loc{Start: lexer.Token.Range.End()}\n\t\tlexer.step()\n\t\tif len(name) == 3 {\n\t\t\tu, r, l := name[0], name[1], name[2]\n\t\t\tif (u == 'u' || u == 'U') && (r == 'r' || r == 'R') && (l == 'l' || l == 'L') {\n\t\t\t\t// Save state\n\t\t\t\tapproximateNewlineCount := lexer.approximateNewlineCount\n\t\t\t\tcodePoint := lexer.codePoint\n\t\t\t\ttokenRangeLen := lexer.Token.Range.Len\n\t\t\t\tcurrent := lexer.current\n\n\t\t\t\t// Check to see if this is a URL token instead of a function\n\t\t\t\tfor isWhitespace(lexer.codePoint) {\n\t\t\t\t\tlexer.step()\n\t\t\t\t}\n\t\t\t\tif lexer.codePoint != '\"' && lexer.codePoint != '\\'' {\n\t\t\t\t\treturn lexer.consumeURL(matchingLoc)\n\t\t\t\t}\n\n\t\t\t\t// Restore state (i.e. backtrack)\n\t\t\t\tlexer.approximateNewlineCount = approximateNewlineCount\n\t\t\t\tlexer.codePoint = codePoint\n\t\t\t\tlexer.Token.Range.Len = tokenRangeLen\n\t\t\t\tlexer.current = current\n\t\t\t}\n\t\t}\n\t\treturn TFunction\n\t}\n\n\treturn TIdent\n}\n\nfunc (lexer *lexer) consumeURL(matchingLoc logger.Loc) T {\nvalidURL:\n\tfor {\n\t\tswitch lexer.codePoint {\n\t\tcase ')':\n\t\t\tlexer.step()\n\t\t\treturn TURL\n\n\t\tcase eof:\n\t\t\tloc := logger.Loc{Start: lexer.Token.Range.End()}\n\t\t\tlexer.log.AddIDWithNotes(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &lexer.tracker, logger.Range{Loc: loc}, \"Expected \\\")\\\" to end URL token\",\n\t\t\t\t[]logger.MsgData{lexer.tracker.MsgData(logger.Range{Loc: matchingLoc, Len: 1}, \"The unbalanced \\\"(\\\" is here:\")})\n\t\t\treturn TURL\n\n\t\tcase ' ', '\\t', '\\n', '\\r', '\\f':\n\t\t\tlexer.step()\n\t\t\tfor isWhitespace(lexer.codePoint) {\n\t\t\t\tlexer.step()\n\t\t\t}\n\t\t\tif lexer.codePoint != ')' {\n\t\t\t\tloc := logger.Loc{Start: lexer.Token.Range.End()}\n\t\t\t\tlexer.log.AddIDWithNotes(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &lexer.tracker, logger.Range{Loc: loc}, \"Expected \\\")\\\" to end URL token\",\n\t\t\t\t\t[]logger.MsgData{lexer.tracker.MsgData(logger.Range{Loc: matchingLoc, Len: 1}, \"The unbalanced \\\"(\\\" is here:\")})\n\t\t\t\tif lexer.codePoint == eof {\n\t\t\t\t\treturn TURL\n\t\t\t\t}\n\t\t\t\tbreak validURL\n\t\t\t}\n\t\t\tlexer.step()\n\t\t\treturn TURL\n\n\t\tcase '\"', '\\'', '(':\n\t\t\tr := logger.Range{Loc: logger.Loc{Start: lexer.Token.Range.End()}, Len: 1}\n\t\t\tlexer.log.AddIDWithNotes(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &lexer.tracker, r, \"Expected \\\")\\\" to end URL token\",\n\t\t\t\t[]logger.MsgData{lexer.tracker.MsgData(logger.Range{Loc: matchingLoc, Len: 1}, \"The unbalanced \\\"(\\\" is here:\")})\n\t\t\tbreak validURL\n\n\t\tcase '\\\\':\n\t\t\tif !lexer.isValidEscape() {\n\t\t\t\tr := logger.Range{Loc: logger.Loc{Start: lexer.Token.Range.End()}, Len: 1}\n\t\t\t\tlexer.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &lexer.tracker, r, \"Invalid escape\")\n\t\t\t\tbreak validURL\n\t\t\t}\n\t\t\tlexer.consumeEscape()\n\n\t\tdefault:\n\t\t\tif isNonPrintable(lexer.codePoint) {\n\t\t\t\tr := logger.Range{Loc: logger.Loc{Start: lexer.Token.Range.End()}, Len: 1}\n\t\t\t\tlexer.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &lexer.tracker, r, \"Unexpected non-printable character in URL token\")\n\t\t\t\tbreak validURL\n\t\t\t}\n\t\t\tlexer.step()\n\t\t}\n\t}\n\n\t// Consume the remnants of a bad url\n\tfor {\n\t\tswitch lexer.codePoint {\n\t\tcase ')', eof:\n\t\t\tlexer.step()\n\t\t\treturn TBadURL\n\n\t\tcase '\\\\':\n\t\t\tif lexer.isValidEscape() {\n\t\t\t\tlexer.consumeEscape()\n\t\t\t}\n\t\t}\n\t\tlexer.step()\n\t}\n}\n\nfunc (lexer *lexer) consumeString() T {\n\tquote := lexer.codePoint\n\tlexer.step()\n\n\tfor {\n\t\tswitch lexer.codePoint {\n\t\tcase '\\\\':\n\t\t\tlexer.step()\n\n\t\t\t// Handle Windows CRLF\n\t\t\tif lexer.codePoint == '\\r' {\n\t\t\t\tlexer.step()\n\t\t\t\tif lexer.codePoint == '\\n' {\n\t\t\t\t\tlexer.step()\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Otherwise, fall through to ignore the character after the backslash\n\n\t\tcase eof, '\\n', '\\r', '\\f':\n\t\t\tlexer.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &lexer.tracker,\n\t\t\t\tlogger.Range{Loc: logger.Loc{Start: lexer.Token.Range.End()}},\n\t\t\t\t\"Unterminated string token\")\n\t\t\treturn TUnterminatedString\n\n\t\tcase quote:\n\t\t\tlexer.step()\n\t\t\treturn TString\n\t\t}\n\t\tlexer.step()\n\t}\n}\n\nfunc (lexer *lexer) consumeNumeric() T {\n\t// Skip over leading sign\n\tif lexer.codePoint == '+' || lexer.codePoint == '-' {\n\t\tlexer.step()\n\t}\n\n\t// Skip over leading digits\n\tfor lexer.codePoint >= '0' && lexer.codePoint <= '9' {\n\t\tlexer.step()\n\t}\n\n\t// Skip over digits after dot\n\tif lexer.codePoint == '.' {\n\t\tlexer.step()\n\t\tfor lexer.codePoint >= '0' && lexer.codePoint <= '9' {\n\t\t\tlexer.step()\n\t\t}\n\t}\n\n\t// Skip over exponent\n\tif lexer.codePoint == 'e' || lexer.codePoint == 'E' {\n\t\tcontents := lexer.source.Contents\n\n\t\t// Look ahead before advancing to make sure this is an exponent, not a unit\n\t\tif lexer.current < len(contents) {\n\t\t\tc := contents[lexer.current]\n\t\t\tif (c == '+' || c == '-') && lexer.current+1 < len(contents) {\n\t\t\t\tc = contents[lexer.current+1]\n\t\t\t}\n\n\t\t\t// Only consume this if it's an exponent\n\t\t\tif c >= '0' && c <= '9' {\n\t\t\t\tlexer.step()\n\t\t\t\tif lexer.codePoint == '+' || lexer.codePoint == '-' {\n\t\t\t\t\tlexer.step()\n\t\t\t\t}\n\t\t\t\tfor lexer.codePoint >= '0' && lexer.codePoint <= '9' {\n\t\t\t\t\tlexer.step()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Determine the numeric type\n\tif lexer.wouldStartIdentifier() {\n\t\tlexer.Token.UnitOffset = uint16(lexer.Token.Range.Len)\n\t\tlexer.consumeName()\n\t\treturn TDimension\n\t}\n\tif lexer.codePoint == '%' {\n\t\tlexer.step()\n\t\treturn TPercentage\n\t}\n\treturn TNumber\n}\n\nfunc IsNameStart(c rune) bool {\n\treturn (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c >= 0x80 || c == '\\x00'\n}\n\nfunc IsNameContinue(c rune) bool {\n\treturn IsNameStart(c) || (c >= '0' && c <= '9') || c == '-'\n}\n\nfunc isNewline(c rune) bool {\n\tswitch c {\n\tcase '\\n', '\\r', '\\f':\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc isWhitespace(c rune) bool {\n\tswitch c {\n\tcase ' ', '\\t', '\\n', '\\r', '\\f':\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc isHex(c rune) (int, bool) {\n\tif c >= '0' && c <= '9' {\n\t\treturn int(c - '0'), true\n\t}\n\tif c >= 'a' && c <= 'f' {\n\t\treturn int(c + (10 - 'a')), true\n\t}\n\tif c >= 'A' && c <= 'F' {\n\t\treturn int(c + (10 - 'A')), true\n\t}\n\treturn 0, false\n}\n\nfunc isNonPrintable(c rune) bool {\n\treturn c <= 0x08 || c == 0x0B || (c >= 0x0E && c <= 0x1F) || c == 0x7F\n}\n\nfunc decodeEscapesInToken(inner string) string {\n\ti := 0\n\n\tfor i < len(inner) {\n\t\tif c := inner[i]; c == '\\\\' || c == '\\x00' {\n\t\t\tbreak\n\t\t}\n\t\ti++\n\t}\n\n\tif i == len(inner) {\n\t\treturn inner\n\t}\n\n\tsb := strings.Builder{}\n\tsb.WriteString(inner[:i])\n\tinner = inner[i:]\n\n\tfor len(inner) > 0 {\n\t\tc, width := utf8.DecodeRuneInString(inner)\n\t\tinner = inner[width:]\n\n\t\tif c != '\\\\' {\n\t\t\tif c == '\\x00' {\n\t\t\t\tc = utf8.RuneError\n\t\t\t}\n\t\t\tsb.WriteRune(c)\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(inner) == 0 {\n\t\t\tsb.WriteRune(utf8.RuneError)\n\t\t\tcontinue\n\t\t}\n\n\t\tc, width = utf8.DecodeRuneInString(inner)\n\t\tinner = inner[width:]\n\t\thex, ok := isHex(c)\n\n\t\tif !ok {\n\t\t\tif c == '\\n' || c == '\\f' {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Handle Windows CRLF\n\t\t\tif c == '\\r' {\n\t\t\t\tc, width = utf8.DecodeRuneInString(inner)\n\t\t\t\tif c == '\\n' {\n\t\t\t\t\tinner = inner[width:]\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// If we get here, this is not a valid escape. However, this is still\n\t\t\t// allowed. In this case the backslash is just ignored.\n\t\t\tsb.WriteRune(c)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Parse up to five additional hex characters (so six in total)\n\t\tfor i := 0; i < 5 && len(inner) > 0; i++ {\n\t\t\tc, width = utf8.DecodeRuneInString(inner)\n\t\t\tif next, ok := isHex(c); ok {\n\t\t\t\tinner = inner[width:]\n\t\t\t\thex = hex*16 + next\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif len(inner) > 0 {\n\t\t\tc, width = utf8.DecodeRuneInString(inner)\n\t\t\tif isWhitespace(c) {\n\t\t\t\tinner = inner[width:]\n\t\t\t}\n\t\t}\n\n\t\tif hex == 0 || (hex >= 0xD800 && hex <= 0xDFFF) || hex > 0x10FFFF {\n\t\t\tsb.WriteRune(utf8.RuneError)\n\t\t\tcontinue\n\t\t}\n\n\t\tsb.WriteRune(rune(hex))\n\t}\n\n\treturn sb.String()\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_color_spaces.go",
    "content": "package css_parser\n\nimport (\n\t\"math\"\n\n\t\"github.com/evanw/esbuild/internal/helpers\"\n)\n\n// Wrap float64 math to avoid compiler optimizations that break determinism\ntype F64 = helpers.F64\n\n// Reference: https://drafts.csswg.org/css-color/#color-conversion-code\n\ntype colorSpace uint8\n\nconst (\n\tcolorSpace_a98_rgb colorSpace = iota\n\tcolorSpace_display_p3\n\tcolorSpace_hsl\n\tcolorSpace_hwb\n\tcolorSpace_lab\n\tcolorSpace_lch\n\tcolorSpace_oklab\n\tcolorSpace_oklch\n\tcolorSpace_prophoto_rgb\n\tcolorSpace_rec2020\n\tcolorSpace_srgb\n\tcolorSpace_srgb_linear\n\tcolorSpace_xyz\n\tcolorSpace_xyz_d50\n\tcolorSpace_xyz_d65\n)\n\nfunc (colorSpace colorSpace) isPolar() bool {\n\tswitch colorSpace {\n\tcase colorSpace_hsl, colorSpace_hwb, colorSpace_lch, colorSpace_oklch:\n\t\treturn true\n\t}\n\treturn false\n}\n\ntype hueMethod uint8\n\nconst (\n\tshorterHue hueMethod = iota\n\tlongerHue\n\tincreasingHue\n\tdecreasingHue\n)\n\nfunc lin_srgb(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\tif abs := val.Abs(); abs.Value() < 0.04045 {\n\t\t\treturn val.DivConst(12.92)\n\t\t} else {\n\t\t\treturn abs.AddConst(0.055).DivConst(1.055).PowConst(2.4).WithSignFrom(val)\n\t\t}\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc gam_srgb(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\tif abs := val.Abs(); abs.Value() > 0.0031308 {\n\t\t\treturn abs.PowConst(1 / 2.4).MulConst(1.055).SubConst(0.055).WithSignFrom(val)\n\t\t} else {\n\t\t\treturn val.MulConst(12.92)\n\t\t}\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc lin_srgb_to_xyz(r F64, g F64, b F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t506752.0 / 1228815, 87881.0 / 245763, 12673.0 / 70218,\n\t\t87098.0 / 409605, 175762.0 / 245763, 12673.0 / 175545,\n\t\t7918.0 / 409605, 87881.0 / 737289, 1001167.0 / 1053270,\n\t}\n\treturn multiplyMatrices(M, r, g, b)\n}\n\nfunc xyz_to_lin_srgb(x F64, y F64, z F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t12831.0 / 3959, -329.0 / 214, -1974.0 / 3959,\n\t\t-851781.0 / 878810, 1648619.0 / 878810, 36519.0 / 878810,\n\t\t705.0 / 12673, -2585.0 / 12673, 705.0 / 667,\n\t}\n\treturn multiplyMatrices(M, x, y, z)\n}\n\nfunc lin_p3(r F64, g F64, b F64) (F64, F64, F64) {\n\treturn lin_srgb(r, g, b)\n}\n\nfunc gam_p3(r F64, g F64, b F64) (F64, F64, F64) {\n\treturn gam_srgb(r, g, b)\n}\n\nfunc lin_p3_to_xyz(r F64, g F64, b F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t608311.0 / 1250200, 189793.0 / 714400, 198249.0 / 1000160,\n\t\t35783.0 / 156275, 247089.0 / 357200, 198249.0 / 2500400,\n\t\t0.0 / 1, 32229.0 / 714400, 5220557.0 / 5000800,\n\t}\n\treturn multiplyMatrices(M, r, g, b)\n}\n\nfunc xyz_to_lin_p3(x F64, y F64, z F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t446124.0 / 178915, -333277.0 / 357830, -72051.0 / 178915,\n\t\t-14852.0 / 17905, 63121.0 / 35810, 423.0 / 17905,\n\t\t11844.0 / 330415, -50337.0 / 660830, 316169.0 / 330415,\n\t}\n\treturn multiplyMatrices(M, x, y, z)\n}\n\nfunc lin_prophoto(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\tconst Et2 = 16.0 / 512\n\t\tif abs := val.Abs(); abs.Value() <= Et2 {\n\t\t\treturn val.DivConst(16)\n\t\t} else {\n\t\t\treturn abs.PowConst(1.8).WithSignFrom(val)\n\t\t}\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc gam_prophoto(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\tconst Et = 1.0 / 512\n\t\tif abs := val.Abs(); abs.Value() >= Et {\n\t\t\treturn abs.PowConst(1 / 1.8).WithSignFrom(val)\n\t\t} else {\n\t\t\treturn val.MulConst(16)\n\t\t}\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc lin_prophoto_to_xyz(r F64, g F64, b F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t0.7977604896723027, 0.13518583717574031, 0.0313493495815248,\n\t\t0.2880711282292934, 0.7118432178101014, 0.00008565396060525902,\n\t\t0.0, 0.0, 0.8251046025104601,\n\t}\n\treturn multiplyMatrices(M, r, g, b)\n}\n\nfunc xyz_to_lin_prophoto(x F64, y F64, z F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t1.3457989731028281, -0.25558010007997534, -0.05110628506753401,\n\t\t-0.5446224939028347, 1.5082327413132781, 0.02053603239147973,\n\t\t0.0, 0.0, 1.2119675456389454,\n\t}\n\treturn multiplyMatrices(M, x, y, z)\n}\n\nfunc lin_a98rgb(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\treturn val.Abs().PowConst(563.0 / 256).WithSignFrom(val)\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc gam_a98rgb(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\treturn val.Abs().PowConst(256.0 / 563).WithSignFrom(val)\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc lin_a98rgb_to_xyz(r F64, g F64, b F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t573536.0 / 994567, 263643.0 / 1420810, 187206.0 / 994567,\n\t\t591459.0 / 1989134, 6239551.0 / 9945670, 374412.0 / 4972835,\n\t\t53769.0 / 1989134, 351524.0 / 4972835, 4929758.0 / 4972835,\n\t}\n\treturn multiplyMatrices(M, r, g, b)\n}\n\nfunc xyz_to_lin_a98rgb(x F64, y F64, z F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t1829569.0 / 896150, -506331.0 / 896150, -308931.0 / 896150,\n\t\t-851781.0 / 878810, 1648619.0 / 878810, 36519.0 / 878810,\n\t\t16779.0 / 1248040, -147721.0 / 1248040, 1266979.0 / 1248040,\n\t}\n\treturn multiplyMatrices(M, x, y, z)\n}\n\nfunc lin_2020(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\tconst α = 1.09929682680944\n\t\tconst β = 0.018053968510807\n\t\tif abs := val.Abs(); abs.Value() < β*4.5 {\n\t\t\treturn val.DivConst(4.5)\n\t\t} else {\n\t\t\treturn abs.AddConst(α - 1).DivConst(α).PowConst(1 / 0.45).WithSignFrom(val)\n\t\t}\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc gam_2020(r F64, g F64, b F64) (F64, F64, F64) {\n\tf := func(val F64) F64 {\n\t\tconst α = 1.09929682680944\n\t\tconst β = 0.018053968510807\n\t\tif abs := val.Abs(); abs.Value() > β {\n\t\t\treturn abs.PowConst(0.45).MulConst(α).SubConst(α - 1).WithSignFrom(val)\n\t\t} else {\n\t\t\treturn val.MulConst(4.5)\n\t\t}\n\t}\n\treturn f(r), f(g), f(b)\n}\n\nfunc lin_2020_to_xyz(r F64, g F64, b F64) (F64, F64, F64) {\n\tvar M = [9]float64{\n\t\t63426534.0 / 99577255, 20160776.0 / 139408157, 47086771.0 / 278816314,\n\t\t26158966.0 / 99577255, 472592308.0 / 697040785, 8267143.0 / 139408157,\n\t\t0.0 / 1, 19567812.0 / 697040785, 295819943.0 / 278816314,\n\t}\n\treturn multiplyMatrices(M, r, g, b)\n}\n\nfunc xyz_to_lin_2020(x F64, y F64, z F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t30757411.0 / 17917100, -6372589.0 / 17917100, -4539589.0 / 17917100,\n\t\t-19765991.0 / 29648200, 47925759.0 / 29648200, 467509.0 / 29648200,\n\t\t792561.0 / 44930125, -1921689.0 / 44930125, 42328811.0 / 44930125,\n\t}\n\treturn multiplyMatrices(M, x, y, z)\n}\n\nfunc d65_to_d50(x F64, y F64, z F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t1.0479297925449969, 0.022946870601609652, -0.05019226628920524,\n\t\t0.02962780877005599, 0.9904344267538799, -0.017073799063418826,\n\t\t-0.009243040646204504, 0.015055191490298152, 0.7518742814281371,\n\t}\n\treturn multiplyMatrices(M, x, y, z)\n}\n\nfunc d50_to_d65(x F64, y F64, z F64) (F64, F64, F64) {\n\tM := [9]float64{\n\t\t0.955473421488075, -0.02309845494876471, 0.06325924320057072,\n\t\t-0.0283697093338637, 1.0099953980813041, 0.021041441191917323,\n\t\t0.012314014864481998, -0.020507649298898964, 1.330365926242124,\n\t}\n\treturn multiplyMatrices(M, x, y, z)\n}\n\nconst d50_x = 0.3457 / 0.3585\nconst d50_z = (1.0 - 0.3457 - 0.3585) / 0.3585\n\nfunc xyz_to_lab(x F64, y F64, z F64) (F64, F64, F64) {\n\tconst ε = 216.0 / 24389\n\tconst κ = 24389.0 / 27\n\n\tx = x.DivConst(d50_x)\n\tz = z.DivConst(d50_z)\n\n\tvar f0, f1, f2 F64\n\tif x.Value() > ε {\n\t\tf0 = x.Cbrt()\n\t} else {\n\t\tf0 = x.MulConst(κ).AddConst(16).DivConst(116)\n\t}\n\tif y.Value() > ε {\n\t\tf1 = y.Cbrt()\n\t} else {\n\t\tf1 = y.MulConst(κ).AddConst(16).DivConst(116)\n\t}\n\tif z.Value() > ε {\n\t\tf2 = z.Cbrt()\n\t} else {\n\t\tf2 = z.MulConst(κ).AddConst(16).DivConst(116)\n\t}\n\n\treturn f1.MulConst(116).SubConst(16),\n\t\tf0.Sub(f1).MulConst(500),\n\t\tf1.Sub(f2).MulConst(200)\n}\n\nfunc lab_to_xyz(l F64, a F64, b F64) (x F64, y F64, z F64) {\n\tconst κ = 24389.0 / 27\n\tconst ε = 216.0 / 24389\n\n\tf1 := l.AddConst(16).DivConst(116)\n\tf0 := a.DivConst(500).Add(f1)\n\tf2 := f1.Sub(b.DivConst(200))\n\n\tf0_3 := f0.Cubed()\n\tf2_3 := f2.Cubed()\n\n\tif f0_3.Value() > ε {\n\t\tx = f0_3\n\t} else {\n\t\tx = f0.MulConst(116).SubConst(16).DivConst(κ)\n\t}\n\tif l.Value() > κ*ε {\n\t\ty = l.AddConst(16).DivConst(116)\n\t\ty = y.Cubed()\n\t} else {\n\t\ty = l.DivConst(κ)\n\t}\n\tif f2_3.Value() > ε {\n\t\tz = f2_3\n\t} else {\n\t\tz = f2.MulConst(116).SubConst(16).DivConst(κ)\n\t}\n\n\treturn x.MulConst(d50_x), y, z.MulConst(d50_z)\n}\n\nfunc lab_to_lch(l F64, a F64, b F64) (F64, F64, F64) {\n\thue := b.Atan2(a).MulConst(180 / math.Pi)\n\tif hue.Value() < 0 {\n\t\thue = hue.AddConst(360)\n\t}\n\treturn l,\n\t\ta.Squared().Add(b.Squared()).Sqrt(),\n\t\thue\n}\n\nfunc lch_to_lab(l F64, c F64, h F64) (F64, F64, F64) {\n\treturn l,\n\t\th.MulConst(math.Pi / 180).Cos().Mul(c),\n\t\th.MulConst(math.Pi / 180).Sin().Mul(c)\n}\n\nfunc xyz_to_oklab(x F64, y F64, z F64) (F64, F64, F64) {\n\tXYZtoLMS := [9]float64{\n\t\t0.8190224432164319, 0.3619062562801221, -0.12887378261216414,\n\t\t0.0329836671980271, 0.9292868468965546, 0.03614466816999844,\n\t\t0.048177199566046255, 0.26423952494422764, 0.6335478258136937,\n\t}\n\tLMStoOKLab := [9]float64{\n\t\t0.2104542553, 0.7936177850, -0.0040720468,\n\t\t1.9779984951, -2.4285922050, 0.4505937099,\n\t\t0.0259040371, 0.7827717662, -0.8086757660,\n\t}\n\tl, m, s := multiplyMatrices(XYZtoLMS, x, y, z)\n\treturn multiplyMatrices(LMStoOKLab, l.Cbrt(), m.Cbrt(), s.Cbrt())\n}\n\nfunc oklab_to_xyz(l F64, a F64, b F64) (F64, F64, F64) {\n\tLMStoXYZ := [9]float64{\n\t\t1.2268798733741557, -0.5578149965554813, 0.28139105017721583,\n\t\t-0.04057576262431372, 1.1122868293970594, -0.07171106666151701,\n\t\t-0.07637294974672142, -0.4214933239627914, 1.5869240244272418,\n\t}\n\tOKLabtoLMS := [9]float64{\n\t\t0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339,\n\t\t1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402,\n\t\t1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399,\n\t}\n\tl, m, s := multiplyMatrices(OKLabtoLMS, l, a, b)\n\treturn multiplyMatrices(LMStoXYZ, l.Cubed(), m.Cubed(), s.Cubed())\n}\n\nfunc oklab_to_oklch(l F64, a F64, b F64) (F64, F64, F64) {\n\treturn lab_to_lch(l, a, b)\n}\n\nfunc oklch_to_oklab(l F64, c F64, h F64) (F64, F64, F64) {\n\treturn lch_to_lab(l, c, h)\n}\n\nfunc multiplyMatrices(A [9]float64, b0 F64, b1 F64, b2 F64) (F64, F64, F64) {\n\treturn b0.MulConst(A[0]).Add(b1.MulConst(A[1])).Add(b2.MulConst(A[2])),\n\t\tb0.MulConst(A[3]).Add(b1.MulConst(A[4])).Add(b2.MulConst(A[5])),\n\t\tb0.MulConst(A[6]).Add(b1.MulConst(A[7])).Add(b2.MulConst(A[8]))\n}\n\nfunc delta_eok(L1 F64, a1 F64, b1 F64, L2 F64, a2 F64, b2 F64) F64 {\n\tΔL_sq := L1.Sub(L2).Squared()\n\tΔa_sq := a1.Sub(a2).Squared()\n\tΔb_sq := b1.Sub(b2).Squared()\n\treturn ΔL_sq.Add(Δa_sq).Add(Δb_sq).Sqrt()\n}\n\nfunc gamut_mapping_xyz_to_srgb(x F64, y F64, z F64) (F64, F64, F64) {\n\torigin_l, origin_c, origin_h := oklab_to_oklch(xyz_to_oklab(x, y, z))\n\n\tif origin_l.Value() >= 1 || origin_l.Value() <= 0 {\n\t\treturn origin_l, origin_l, origin_l\n\t}\n\n\toklch_to_srgb := func(l F64, c F64, h F64) (F64, F64, F64) {\n\t\tl, a, b := oklch_to_oklab(l, c, h)\n\t\tx, y, z := oklab_to_xyz(l, a, b)\n\t\tr, g, b := xyz_to_lin_srgb(x, y, z)\n\t\treturn gam_srgb(r, g, b)\n\t}\n\n\tsrgb_to_oklab := func(r F64, g F64, b F64) (F64, F64, F64) {\n\t\tr, g, b = lin_srgb(r, g, b)\n\t\tx, y, z := lin_srgb_to_xyz(r, g, b)\n\t\treturn xyz_to_oklab(x, y, z)\n\t}\n\n\tinGamut := func(r F64, g F64, b F64) bool {\n\t\treturn r.Value() >= 0 && r.Value() <= 1 &&\n\t\t\tg.Value() >= 0 && g.Value() <= 1 &&\n\t\t\tb.Value() >= 0 && b.Value() <= 1\n\t}\n\n\tr, g, b := oklch_to_srgb(origin_l, origin_c, origin_h)\n\tif inGamut(r, g, b) {\n\t\treturn r, g, b\n\t}\n\n\tconst JND = 0.02\n\tconst epsilon = 0.0001\n\tmin := helpers.NewF64(0.0)\n\tmax := origin_c\n\n\tclip := func(x F64) F64 {\n\t\tif x.Value() < 0 {\n\t\t\treturn helpers.NewF64(0)\n\t\t}\n\t\tif x.Value() > 1 {\n\t\t\treturn helpers.NewF64(1)\n\t\t}\n\t\treturn x\n\t}\n\n\tfor max.Sub(min).Value() > epsilon {\n\t\tchroma := min.Add(max).DivConst(2)\n\t\torigin_c = chroma\n\n\t\tr, g, b = oklch_to_srgb(origin_l, origin_c, origin_h)\n\t\tif inGamut(r, g, b) {\n\t\t\tmin = chroma\n\t\t\tcontinue\n\t\t}\n\n\t\tclipped_r, clipped_g, clipped_b := clip(r), clip(g), clip(b)\n\t\tL1, a1, b1 := srgb_to_oklab(clipped_r, clipped_b, clipped_g)\n\t\tL2, a2, b2 := srgb_to_oklab(r, g, b)\n\t\tE := delta_eok(L1, a1, b1, L2, a2, b2)\n\t\tif E.Value() < JND {\n\t\t\treturn clipped_r, clipped_g, clipped_b\n\t\t}\n\n\t\tmax = chroma\n\t}\n\n\treturn r, g, b\n}\n\nfunc hsl_to_rgb(hue F64, sat F64, light F64) (F64, F64, F64) {\n\thue = hue.DivConst(360)\n\thue = hue.Sub(hue.Floor())\n\thue = hue.MulConst(360)\n\n\tsat = sat.DivConst(100)\n\tlight = light.DivConst(100)\n\n\tf := func(n float64) F64 {\n\t\tk := hue.DivConst(30).AddConst(n)\n\t\tk = k.DivConst(12)\n\t\tk = k.Sub(k.Floor())\n\t\tk = k.MulConst(12)\n\t\ta := helpers.Min2(light, light.Neg().AddConst(1)).Mul(sat)\n\t\treturn light.Sub(helpers.Max2(helpers.NewF64(-1), helpers.Min3(k.SubConst(3), k.Neg().AddConst(9), helpers.NewF64(1))).Mul(a))\n\t}\n\n\treturn f(0), f(8), f(4)\n}\n\nfunc rgb_to_hsl(red F64, green F64, blue F64) (F64, F64, F64) {\n\tmax := helpers.Max3(red, green, blue)\n\tmin := helpers.Min3(red, green, blue)\n\thue, sat, light := helpers.NewF64(math.NaN()), helpers.NewF64(0.0), min.Add(max).DivConst(2)\n\td := max.Sub(min)\n\n\tif d.Value() != 0 {\n\t\tif div := helpers.Min2(light, light.Neg().AddConst(1)); div.Value() != 0 {\n\t\t\tsat = max.Sub(light).Div(div)\n\t\t}\n\n\t\tswitch max {\n\t\tcase red:\n\t\t\thue = green.Sub(blue).Div(d)\n\t\t\tif green.Value() < blue.Value() {\n\t\t\t\thue = hue.AddConst(6)\n\t\t\t}\n\t\tcase green:\n\t\t\thue = blue.Sub(red).Div(d).AddConst(2)\n\t\tcase blue:\n\t\t\thue = red.Sub(green).Div(d).AddConst(4)\n\t\t}\n\n\t\thue = hue.MulConst(60)\n\t}\n\n\treturn hue, sat.MulConst(100), light.MulConst(100)\n}\n\nfunc hwb_to_rgb(hue F64, white F64, black F64) (F64, F64, F64) {\n\twhite = white.DivConst(100)\n\tblack = black.DivConst(100)\n\tif white.Add(black).Value() >= 1 {\n\t\tgray := white.Div(white.Add(black))\n\t\treturn gray, gray, gray\n\t}\n\tdelta := white.Add(black).Neg().AddConst(1)\n\tr, g, b := hsl_to_rgb(hue, helpers.NewF64(100), helpers.NewF64(50))\n\tr = delta.Mul(r).Add(white)\n\tg = delta.Mul(g).Add(white)\n\tb = delta.Mul(b).Add(white)\n\treturn r, g, b\n}\n\nfunc rgb_to_hwb(red F64, green F64, blue F64) (F64, F64, F64) {\n\th, _, _ := rgb_to_hsl(red, green, blue)\n\twhite := helpers.Min3(red, green, blue)\n\tblack := helpers.Max3(red, green, blue).Neg().AddConst(1)\n\treturn h, white.MulConst(100), black.MulConst(100)\n}\n\nfunc xyz_to_colorSpace(x F64, y F64, z F64, colorSpace colorSpace) (F64, F64, F64) {\n\tswitch colorSpace {\n\tcase colorSpace_a98_rgb:\n\t\treturn gam_a98rgb(xyz_to_lin_a98rgb(x, y, z))\n\n\tcase colorSpace_display_p3:\n\t\treturn gam_p3(xyz_to_lin_p3(x, y, z))\n\n\tcase colorSpace_hsl:\n\t\treturn rgb_to_hsl(gam_srgb(xyz_to_lin_srgb(x, y, z)))\n\n\tcase colorSpace_hwb:\n\t\treturn rgb_to_hwb(gam_srgb(xyz_to_lin_srgb(x, y, z)))\n\n\tcase colorSpace_lab:\n\t\treturn xyz_to_lab(d65_to_d50(x, y, z))\n\n\tcase colorSpace_lch:\n\t\treturn lab_to_lch(xyz_to_lab(d65_to_d50(x, y, z)))\n\n\tcase colorSpace_oklab:\n\t\treturn xyz_to_oklab(x, y, z)\n\n\tcase colorSpace_oklch:\n\t\treturn oklab_to_oklch(xyz_to_oklab(x, y, z))\n\n\tcase colorSpace_prophoto_rgb:\n\t\treturn gam_prophoto(xyz_to_lin_prophoto(d65_to_d50(x, y, z)))\n\n\tcase colorSpace_rec2020:\n\t\treturn gam_2020(xyz_to_lin_2020(x, y, z))\n\n\tcase colorSpace_srgb:\n\t\treturn gam_srgb(xyz_to_lin_srgb(x, y, z))\n\n\tcase colorSpace_srgb_linear:\n\t\treturn xyz_to_lin_srgb(x, y, z)\n\n\tcase colorSpace_xyz, colorSpace_xyz_d65:\n\t\treturn x, y, z\n\n\tcase colorSpace_xyz_d50:\n\t\treturn d65_to_d50(x, y, z)\n\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\nfunc colorSpace_to_xyz(v0 F64, v1 F64, v2 F64, colorSpace colorSpace) (F64, F64, F64) {\n\tswitch colorSpace {\n\tcase colorSpace_a98_rgb:\n\t\treturn lin_a98rgb_to_xyz(lin_a98rgb(v0, v1, v2))\n\n\tcase colorSpace_display_p3:\n\t\treturn lin_p3_to_xyz(lin_p3(v0, v1, v2))\n\n\tcase colorSpace_hsl:\n\t\treturn lin_srgb_to_xyz(lin_srgb(hsl_to_rgb(v0, v1, v2)))\n\n\tcase colorSpace_hwb:\n\t\treturn lin_srgb_to_xyz(lin_srgb(hwb_to_rgb(v0, v1, v2)))\n\n\tcase colorSpace_lab:\n\t\treturn d50_to_d65(lab_to_xyz(v0, v1, v2))\n\n\tcase colorSpace_lch:\n\t\treturn d50_to_d65(lab_to_xyz(lch_to_lab(v0, v1, v2)))\n\n\tcase colorSpace_oklab:\n\t\treturn oklab_to_xyz(v0, v1, v2)\n\n\tcase colorSpace_oklch:\n\t\treturn oklab_to_xyz(oklch_to_oklab(v0, v1, v2))\n\n\tcase colorSpace_prophoto_rgb:\n\t\treturn d50_to_d65(lin_prophoto_to_xyz(lin_prophoto(v0, v1, v2)))\n\n\tcase colorSpace_rec2020:\n\t\treturn lin_2020_to_xyz(lin_2020(v0, v1, v2))\n\n\tcase colorSpace_srgb:\n\t\treturn lin_srgb_to_xyz(lin_srgb(v0, v1, v2))\n\n\tcase colorSpace_srgb_linear:\n\t\treturn lin_srgb_to_xyz(v0, v1, v2)\n\n\tcase colorSpace_xyz, colorSpace_xyz_d65:\n\t\treturn v0, v1, v2\n\n\tcase colorSpace_xyz_d50:\n\t\treturn d50_to_d65(v0, v1, v2)\n\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\nfunc (p *parser) commaToken(loc logger.Loc) css_ast.Token {\n\tt := css_ast.Token{\n\t\tLoc:  loc,\n\t\tKind: css_lexer.TComma,\n\t\tText: \",\",\n\t}\n\tif !p.options.minifyWhitespace {\n\t\tt.Whitespace = css_ast.WhitespaceAfter\n\t}\n\treturn t\n}\n\nfunc expandTokenQuad(tokens []css_ast.Token, allowedIdent string) (result [4]css_ast.Token, ok bool) {\n\tn := len(tokens)\n\tif n < 1 || n > 4 {\n\t\treturn\n\t}\n\n\t// Don't do this if we encounter any unexpected tokens such as \"var()\"\n\tfor i := 0; i < n; i++ {\n\t\tif t := tokens[i]; !t.Kind.IsNumeric() && (t.Kind != css_lexer.TIdent || allowedIdent == \"\" || t.Text != allowedIdent) {\n\t\t\treturn\n\t\t}\n\t}\n\n\tresult[0] = tokens[0]\n\tif n > 1 {\n\t\tresult[1] = tokens[1]\n\t} else {\n\t\tresult[1] = result[0]\n\t}\n\tif n > 2 {\n\t\tresult[2] = tokens[2]\n\t} else {\n\t\tresult[2] = result[0]\n\t}\n\tif n > 3 {\n\t\tresult[3] = tokens[3]\n\t} else {\n\t\tresult[3] = result[1]\n\t}\n\n\tok = true\n\treturn\n}\n\nfunc compactTokenQuad(a css_ast.Token, b css_ast.Token, c css_ast.Token, d css_ast.Token, minifyWhitespace bool) []css_ast.Token {\n\ttokens := []css_ast.Token{a, b, c, d}\n\tif tokens[3].EqualIgnoringWhitespace(tokens[1]) {\n\t\tif tokens[2].EqualIgnoringWhitespace(tokens[0]) {\n\t\t\tif tokens[1].EqualIgnoringWhitespace(tokens[0]) {\n\t\t\t\ttokens = tokens[:1]\n\t\t\t} else {\n\t\t\t\ttokens = tokens[:2]\n\t\t\t}\n\t\t} else {\n\t\t\ttokens = tokens[:3]\n\t\t}\n\t}\n\tfor i := range tokens {\n\t\tvar whitespace css_ast.WhitespaceFlags\n\t\tif !minifyWhitespace || i > 0 {\n\t\t\twhitespace |= css_ast.WhitespaceBefore\n\t\t}\n\t\tif i+1 < len(tokens) {\n\t\t\twhitespace |= css_ast.WhitespaceAfter\n\t\t}\n\t\ttokens[i].Whitespace = whitespace\n\t}\n\treturn tokens\n}\n\nfunc (p *parser) processDeclarations(rules []css_ast.Rule, composesContext *composesContext) (rewrittenRules []css_ast.Rule) {\n\tmargin := boxTracker{key: css_ast.DMargin, keyText: \"margin\", allowAuto: true}\n\tpadding := boxTracker{key: css_ast.DPadding, keyText: \"padding\", allowAuto: false}\n\tinset := boxTracker{key: css_ast.DInset, keyText: \"inset\", allowAuto: true}\n\tborderRadius := borderRadiusTracker{}\n\trewrittenRules = make([]css_ast.Rule, 0, len(rules))\n\tdidWarnAboutComposes := false\n\twouldClipColorFlag := false\n\tvar declarationKeys map[string]struct{}\n\n\t// Don't automatically generate the \"inset\" property if it's not supported\n\tif p.options.unsupportedCSSFeatures.Has(compat.InsetProperty) {\n\t\tinset.key = css_ast.DUnknown\n\t\tinset.keyText = \"\"\n\t}\n\n\t// If this is a local class selector, track which CSS properties it declares.\n\t// This is used to warn when CSS \"composes\" is used incorrectly.\n\tif composesContext != nil {\n\t\tfor _, ref := range composesContext.parentRefs {\n\t\t\tcomposes, ok := p.composes[ref]\n\t\t\tif !ok {\n\t\t\t\tcomposes = &css_ast.Composes{}\n\t\t\t\tp.composes[ref] = composes\n\t\t\t}\n\t\t\tproperties := composes.Properties\n\t\t\tif properties == nil {\n\t\t\t\tproperties = make(map[string]logger.Loc)\n\t\t\t\tcomposes.Properties = properties\n\t\t\t}\n\t\t\tfor _, rule := range rules {\n\t\t\t\tif decl, ok := rule.Data.(*css_ast.RDeclaration); ok && decl.Key != css_ast.DComposes {\n\t\t\t\t\tproperties[decl.KeyText] = decl.KeyRange.Loc\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor i := 0; i < len(rules); i++ {\n\t\trule := rules[i]\n\t\trewrittenRules = append(rewrittenRules, rule)\n\t\tdecl, ok := rule.Data.(*css_ast.RDeclaration)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\n\t\t// If the previous loop iteration would have clipped a color, we will\n\t\t// duplicate it and insert the clipped copy before the unclipped copy\n\t\tvar wouldClipColor *bool\n\t\tif wouldClipColorFlag {\n\t\t\twouldClipColorFlag = false\n\t\t\tclone := *decl\n\t\t\tclone.Value = css_ast.CloneTokensWithoutImportRecords(clone.Value)\n\t\t\tdecl = &clone\n\t\t\trule.Data = decl\n\t\t\tn := len(rewrittenRules) - 2\n\t\t\trewrittenRules = append(rewrittenRules[:n], rule, rewrittenRules[n])\n\t\t} else {\n\t\t\twouldClipColor = &wouldClipColorFlag\n\t\t}\n\n\t\tswitch decl.Key {\n\t\tcase css_ast.DComposes:\n\t\t\t// Only process \"composes\" directives if we're in \"local-css\" or\n\t\t\t// \"global-css\" mode. In these cases, \"composes\" directives will always\n\t\t\t// be removed (because they are being processed) even if they contain\n\t\t\t// errors. Otherwise we leave \"composes\" directives there untouched and\n\t\t\t// don't check them for errors.\n\t\t\tif p.options.symbolMode != symbolModeDisabled {\n\t\t\t\tif composesContext == nil {\n\t\t\t\t\tif !didWarnAboutComposes {\n\t\t\t\t\t\tdidWarnAboutComposes = true\n\t\t\t\t\t\tp.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, decl.KeyRange, \"\\\"composes\\\" is not valid here\")\n\t\t\t\t\t}\n\t\t\t\t} else if composesContext.problemRange.Len > 0 {\n\t\t\t\t\tif !didWarnAboutComposes {\n\t\t\t\t\t\tdidWarnAboutComposes = true\n\t\t\t\t\t\tp.log.AddIDWithNotes(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, decl.KeyRange, \"\\\"composes\\\" only works inside single class selectors\",\n\t\t\t\t\t\t\t[]logger.MsgData{p.tracker.MsgData(composesContext.problemRange, \"The parent selector is not a single class selector because of the syntax here:\")})\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tp.handleComposesPragma(*composesContext, decl.Value)\n\t\t\t\t}\n\t\t\t\trewrittenRules = rewrittenRules[:len(rewrittenRules)-1]\n\t\t\t}\n\n\t\tcase css_ast.DBackground:\n\t\t\tfor i, t := range decl.Value {\n\t\t\t\tt = p.lowerAndMinifyColor(t, wouldClipColor)\n\t\t\t\tt = p.lowerAndMinifyGradient(t, wouldClipColor)\n\t\t\t\tdecl.Value[i] = t\n\t\t\t}\n\n\t\tcase css_ast.DBackgroundImage,\n\t\t\tcss_ast.DBorderImage,\n\t\t\tcss_ast.DMaskImage:\n\n\t\t\tfor i, t := range decl.Value {\n\t\t\t\tt = p.lowerAndMinifyGradient(t, wouldClipColor)\n\t\t\t\tdecl.Value[i] = t\n\t\t\t}\n\n\t\tcase css_ast.DBackgroundColor,\n\t\t\tcss_ast.DBorderBlockEndColor,\n\t\t\tcss_ast.DBorderBlockStartColor,\n\t\t\tcss_ast.DBorderBottomColor,\n\t\t\tcss_ast.DBorderColor,\n\t\t\tcss_ast.DBorderInlineEndColor,\n\t\t\tcss_ast.DBorderInlineStartColor,\n\t\t\tcss_ast.DBorderLeftColor,\n\t\t\tcss_ast.DBorderRightColor,\n\t\t\tcss_ast.DBorderTopColor,\n\t\t\tcss_ast.DCaretColor,\n\t\t\tcss_ast.DColor,\n\t\t\tcss_ast.DColumnRuleColor,\n\t\t\tcss_ast.DFill,\n\t\t\tcss_ast.DFloodColor,\n\t\t\tcss_ast.DLightingColor,\n\t\t\tcss_ast.DOutlineColor,\n\t\t\tcss_ast.DStopColor,\n\t\t\tcss_ast.DStroke,\n\t\t\tcss_ast.DTextDecorationColor,\n\t\t\tcss_ast.DTextEmphasisColor:\n\n\t\t\tif len(decl.Value) == 1 {\n\t\t\t\tdecl.Value[0] = p.lowerAndMinifyColor(decl.Value[0], wouldClipColor)\n\t\t\t}\n\n\t\tcase css_ast.DTransform:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tdecl.Value = p.mangleTransforms(decl.Value)\n\t\t\t}\n\n\t\tcase css_ast.DBoxShadow:\n\t\t\tdecl.Value = p.lowerAndMangleBoxShadows(decl.Value, wouldClipColor)\n\n\t\t// Container name\n\t\tcase css_ast.DContainer:\n\t\t\tp.processContainerShorthand(decl.Value)\n\t\tcase css_ast.DContainerName:\n\t\t\tp.processContainerName(decl.Value)\n\n\t\t// Animation name\n\t\tcase css_ast.DAnimation:\n\t\t\tp.processAnimationShorthand(decl.Value)\n\t\tcase css_ast.DAnimationName:\n\t\t\tp.processAnimationName(decl.Value)\n\n\t\t// List style\n\t\tcase css_ast.DListStyle:\n\t\t\tp.processListStyleShorthand(decl.Value)\n\t\tcase css_ast.DListStyleType:\n\t\t\tif len(decl.Value) == 1 {\n\t\t\t\tp.processListStyleType(&decl.Value[0])\n\t\t\t}\n\n\t\t// Font\n\t\tcase css_ast.DFont:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tdecl.Value = p.mangleFont(decl.Value)\n\t\t\t}\n\t\tcase css_ast.DFontFamily:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tif value, ok := p.mangleFontFamily(decl.Value); ok {\n\t\t\t\t\tdecl.Value = value\n\t\t\t\t}\n\t\t\t}\n\t\tcase css_ast.DFontWeight:\n\t\t\tif len(decl.Value) == 1 && p.options.minifySyntax {\n\t\t\t\tdecl.Value[0] = p.mangleFontWeight(decl.Value[0])\n\t\t\t}\n\n\t\t// Margin\n\t\tcase css_ast.DMargin:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tmargin.mangleSides(rewrittenRules, decl, p.options.minifyWhitespace)\n\t\t\t}\n\t\tcase css_ast.DMarginTop:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tmargin.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxTop)\n\t\t\t}\n\t\tcase css_ast.DMarginRight:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tmargin.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxRight)\n\t\t\t}\n\t\tcase css_ast.DMarginBottom:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tmargin.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxBottom)\n\t\t\t}\n\t\tcase css_ast.DMarginLeft:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tmargin.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxLeft)\n\t\t\t}\n\n\t\t// Padding\n\t\tcase css_ast.DPadding:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tpadding.mangleSides(rewrittenRules, decl, p.options.minifyWhitespace)\n\t\t\t}\n\t\tcase css_ast.DPaddingTop:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tpadding.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxTop)\n\t\t\t}\n\t\tcase css_ast.DPaddingRight:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tpadding.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxRight)\n\t\t\t}\n\t\tcase css_ast.DPaddingBottom:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tpadding.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxBottom)\n\t\t\t}\n\t\tcase css_ast.DPaddingLeft:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tpadding.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxLeft)\n\t\t\t}\n\n\t\t// Inset\n\t\tcase css_ast.DInset:\n\t\t\tif p.options.unsupportedCSSFeatures.Has(compat.InsetProperty) {\n\t\t\t\tif decls, ok := p.lowerInset(rule.Loc, decl); ok {\n\t\t\t\t\trewrittenRules = rewrittenRules[:len(rewrittenRules)-1]\n\t\t\t\t\tfor i := range decls {\n\t\t\t\t\t\trewrittenRules = append(rewrittenRules, decls[i])\n\t\t\t\t\t\tif p.options.minifySyntax {\n\t\t\t\t\t\t\tinset.mangleSide(rewrittenRules, decls[i].Data.(*css_ast.RDeclaration), p.options.minifyWhitespace, i)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tinset.mangleSides(rewrittenRules, decl, p.options.minifyWhitespace)\n\t\t\t}\n\t\tcase css_ast.DTop:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tinset.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxTop)\n\t\t\t}\n\t\tcase css_ast.DRight:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tinset.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxRight)\n\t\t\t}\n\t\tcase css_ast.DBottom:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tinset.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxBottom)\n\t\t\t}\n\t\tcase css_ast.DLeft:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tinset.mangleSide(rewrittenRules, decl, p.options.minifyWhitespace, boxLeft)\n\t\t\t}\n\n\t\t// Border radius\n\t\tcase css_ast.DBorderRadius:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tborderRadius.mangleCorners(rewrittenRules, decl, p.options.minifyWhitespace)\n\t\t\t}\n\t\tcase css_ast.DBorderTopLeftRadius:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tborderRadius.mangleCorner(rewrittenRules, decl, p.options.minifyWhitespace, borderRadiusTopLeft)\n\t\t\t}\n\t\tcase css_ast.DBorderTopRightRadius:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tborderRadius.mangleCorner(rewrittenRules, decl, p.options.minifyWhitespace, borderRadiusTopRight)\n\t\t\t}\n\t\tcase css_ast.DBorderBottomRightRadius:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tborderRadius.mangleCorner(rewrittenRules, decl, p.options.minifyWhitespace, borderRadiusBottomRight)\n\t\t\t}\n\t\tcase css_ast.DBorderBottomLeftRadius:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tborderRadius.mangleCorner(rewrittenRules, decl, p.options.minifyWhitespace, borderRadiusBottomLeft)\n\t\t\t}\n\t\t}\n\n\t\tif prefixes, ok := p.options.cssPrefixData[decl.Key]; ok {\n\t\t\tif declarationKeys == nil {\n\t\t\t\t// Only generate this map if it's needed\n\t\t\t\tdeclarationKeys = make(map[string]struct{})\n\t\t\t\tfor _, rule := range rules {\n\t\t\t\t\tif decl, ok := rule.Data.(*css_ast.RDeclaration); ok {\n\t\t\t\t\t\tdeclarationKeys[decl.KeyText] = struct{}{}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (prefixes & compat.WebkitPrefix) != 0 {\n\t\t\t\trewrittenRules = p.insertPrefixedDeclaration(rewrittenRules, \"-webkit-\", rule.Loc, decl, declarationKeys)\n\t\t\t}\n\t\t\tif (prefixes & compat.KhtmlPrefix) != 0 {\n\t\t\t\trewrittenRules = p.insertPrefixedDeclaration(rewrittenRules, \"-khtml-\", rule.Loc, decl, declarationKeys)\n\t\t\t}\n\t\t\tif (prefixes & compat.MozPrefix) != 0 {\n\t\t\t\trewrittenRules = p.insertPrefixedDeclaration(rewrittenRules, \"-moz-\", rule.Loc, decl, declarationKeys)\n\t\t\t}\n\t\t\tif (prefixes & compat.MsPrefix) != 0 {\n\t\t\t\trewrittenRules = p.insertPrefixedDeclaration(rewrittenRules, \"-ms-\", rule.Loc, decl, declarationKeys)\n\t\t\t}\n\t\t\tif (prefixes & compat.OPrefix) != 0 {\n\t\t\t\trewrittenRules = p.insertPrefixedDeclaration(rewrittenRules, \"-o-\", rule.Loc, decl, declarationKeys)\n\t\t\t}\n\t\t}\n\n\t\t// If this loop iteration would have clipped a color, the out-of-gamut\n\t\t// colors will not be clipped and this flag will be set. We then set up the\n\t\t// next iteration of the loop to duplicate this rule and process it again\n\t\t// with color clipping enabled.\n\t\tif wouldClipColorFlag {\n\t\t\tif p.options.unsupportedCSSFeatures.Has(compat.ColorFunctions) {\n\t\t\t\t// Only do this if there was no previous instance of that property so\n\t\t\t\t// we avoid overwriting any manually-specified fallback values\n\t\t\t\tfor j := len(rewrittenRules) - 2; j >= 0; j-- {\n\t\t\t\t\tif prev, ok := rewrittenRules[j].Data.(*css_ast.RDeclaration); ok && prev.Key == decl.Key {\n\t\t\t\t\t\twouldClipColorFlag = false\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif wouldClipColorFlag {\n\t\t\t\t\t// If the code above would have clipped a color outside of the sRGB gamut,\n\t\t\t\t\t// process this rule again so we can generate the clipped version next time\n\t\t\t\t\ti -= 1\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\twouldClipColorFlag = false\n\t\t}\n\t}\n\n\t// Compact removed rules\n\tif p.options.minifySyntax {\n\t\tend := 0\n\t\tfor _, rule := range rewrittenRules {\n\t\t\tif rule.Data != nil {\n\t\t\t\trewrittenRules[end] = rule\n\t\t\t\tend++\n\t\t\t}\n\t\t}\n\t\trewrittenRules = rewrittenRules[:end]\n\t}\n\n\treturn\n}\n\nfunc (p *parser) insertPrefixedDeclaration(rules []css_ast.Rule, prefix string, loc logger.Loc, decl *css_ast.RDeclaration, declarationKeys map[string]struct{}) []css_ast.Rule {\n\tkeyText := prefix + decl.KeyText\n\n\t// Don't insert a prefixed declaration if there already is one\n\tif _, ok := declarationKeys[keyText]; ok {\n\t\t// We found a previous declaration with a matching prefixed property.\n\t\t// The value is ignored, which matches the behavior of \"autoprefixer\".\n\t\treturn rules\n\t}\n\n\t// Additional special cases for when the prefix applies\n\tswitch decl.Key {\n\tcase css_ast.DBackgroundClip:\n\t\t// The prefix is only needed for \"background-clip: text\"\n\t\tif len(decl.Value) != 1 || decl.Value[0].Kind != css_lexer.TIdent || !strings.EqualFold(decl.Value[0].Text, \"text\") {\n\t\t\treturn rules\n\t\t}\n\n\tcase css_ast.DPosition:\n\t\t// The prefix is only needed for \"position: sticky\"\n\t\tif len(decl.Value) != 1 || decl.Value[0].Kind != css_lexer.TIdent || !strings.EqualFold(decl.Value[0].Text, \"sticky\") {\n\t\t\treturn rules\n\t\t}\n\n\tcase css_ast.DWidth, css_ast.DMinWidth, css_ast.DMaxWidth,\n\t\tcss_ast.DHeight, css_ast.DMinHeight, css_ast.DMaxHeight:\n\t\t// The prefix is only needed for \"width: stretch\"\n\t\tif len(decl.Value) != 1 || decl.Value[0].Kind != css_lexer.TIdent || !strings.EqualFold(decl.Value[0].Text, \"stretch\") {\n\t\t\treturn rules\n\t\t}\n\t}\n\n\tvalue := css_ast.CloneTokensWithoutImportRecords(decl.Value)\n\n\t// Additional special cases for how to transform the contents\n\tswitch decl.Key {\n\tcase css_ast.DPosition:\n\t\t// The prefix applies to the value, not the property\n\t\tkeyText = decl.KeyText\n\t\tvalue[0].Text = \"-webkit-sticky\"\n\n\tcase css_ast.DWidth, css_ast.DMinWidth, css_ast.DMaxWidth,\n\t\tcss_ast.DHeight, css_ast.DMinHeight, css_ast.DMaxHeight:\n\t\t// The prefix applies to the value, not the property\n\t\tkeyText = decl.KeyText\n\n\t\t// This currently only applies to \"stretch\" (already checked above)\n\t\tswitch prefix {\n\t\tcase \"-webkit-\":\n\t\t\tvalue[0].Text = \"-webkit-fill-available\"\n\t\tcase \"-moz-\":\n\t\t\tvalue[0].Text = \"-moz-available\"\n\t\t}\n\n\tcase css_ast.DUserSelect:\n\t\t// The prefix applies to the value as well as the property\n\t\tif prefix == \"-moz-\" && len(value) == 1 && value[0].Kind == css_lexer.TIdent && strings.EqualFold(value[0].Text, \"none\") {\n\t\t\tvalue[0].Text = \"-moz-none\"\n\t\t}\n\n\tcase css_ast.DMaskComposite:\n\t\t// WebKit uses different names for these values\n\t\tif prefix == \"-webkit-\" {\n\t\t\tfor i, token := range value {\n\t\t\t\tif token.Kind == css_lexer.TIdent {\n\t\t\t\t\tswitch token.Text {\n\t\t\t\t\tcase \"add\":\n\t\t\t\t\t\tvalue[i].Text = \"source-over\"\n\t\t\t\t\tcase \"subtract\":\n\t\t\t\t\t\tvalue[i].Text = \"source-out\"\n\t\t\t\t\tcase \"intersect\":\n\t\t\t\t\t\tvalue[i].Text = \"source-in\"\n\t\t\t\t\tcase \"exclude\":\n\t\t\t\t\t\tvalue[i].Text = \"xor\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// If we didn't change the key, manually search for a previous duplicate rule\n\tif keyText == decl.KeyText {\n\t\tfor _, rule := range rules {\n\t\t\tif prevDecl, ok := rule.Data.(*css_ast.RDeclaration); ok && prevDecl.KeyText == keyText && css_ast.TokensEqual(prevDecl.Value, value, nil) {\n\t\t\t\treturn rules\n\t\t\t}\n\t\t}\n\t}\n\n\t// Overwrite the latest declaration with the prefixed declaration\n\trules[len(rules)-1] = css_ast.Rule{Loc: loc, Data: &css_ast.RDeclaration{\n\t\tKeyText:   keyText,\n\t\tKeyRange:  decl.KeyRange,\n\t\tValue:     value,\n\t\tImportant: decl.Important,\n\t}}\n\n\t// Re-add the latest declaration after the inserted declaration\n\trules = append(rules, css_ast.Rule{Loc: loc, Data: decl})\n\treturn rules\n}\n\nfunc (p *parser) lowerInset(loc logger.Loc, decl *css_ast.RDeclaration) ([]css_ast.Rule, bool) {\n\tif tokens, ok := expandTokenQuad(decl.Value, \"\"); ok {\n\t\tmask := ^css_ast.WhitespaceAfter\n\t\tif p.options.minifyWhitespace {\n\t\t\tmask = 0\n\t\t}\n\t\tfor i := range tokens {\n\t\t\ttokens[i].Whitespace &= mask\n\t\t}\n\t\treturn []css_ast.Rule{\n\t\t\t{Loc: loc, Data: &css_ast.RDeclaration{\n\t\t\t\tKeyText:   \"top\",\n\t\t\t\tKeyRange:  decl.KeyRange,\n\t\t\t\tKey:       css_ast.DTop,\n\t\t\t\tValue:     tokens[0:1],\n\t\t\t\tImportant: decl.Important,\n\t\t\t}},\n\t\t\t{Loc: loc, Data: &css_ast.RDeclaration{\n\t\t\t\tKeyText:   \"right\",\n\t\t\t\tKeyRange:  decl.KeyRange,\n\t\t\t\tKey:       css_ast.DRight,\n\t\t\t\tValue:     tokens[1:2],\n\t\t\t\tImportant: decl.Important,\n\t\t\t}},\n\t\t\t{Loc: loc, Data: &css_ast.RDeclaration{\n\t\t\t\tKeyText:   \"bottom\",\n\t\t\t\tKeyRange:  decl.KeyRange,\n\t\t\t\tKey:       css_ast.DBottom,\n\t\t\t\tValue:     tokens[2:3],\n\t\t\t\tImportant: decl.Important,\n\t\t\t}},\n\t\t\t{Loc: loc, Data: &css_ast.RDeclaration{\n\t\t\t\tKeyText:   \"left\",\n\t\t\t\tKeyRange:  decl.KeyRange,\n\t\t\t\tKey:       css_ast.DLeft,\n\t\t\t\tValue:     tokens[3:4],\n\t\t\t\tImportant: decl.Important,\n\t\t\t}},\n\t\t}, true\n\t}\n\treturn nil, false\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_animation.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\n// Scan for animation names in the \"animation\" shorthand property\nfunc (p *parser) processAnimationShorthand(tokens []css_ast.Token) {\n\ttype foundFlags struct {\n\t\ttimingFunction bool\n\t\titerationCount bool\n\t\tdirection      bool\n\t\tfillMode       bool\n\t\tplayState      bool\n\t\tname           bool\n\t}\n\n\tfound := foundFlags{}\n\n\tfor i, t := range tokens {\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TComma:\n\t\t\t// Reset the flags when we encounter a comma\n\t\t\tfound = foundFlags{}\n\n\t\tcase css_lexer.TNumber:\n\t\t\tif !found.iterationCount {\n\t\t\t\tfound.iterationCount = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\tcase css_lexer.TIdent:\n\t\t\tif !found.timingFunction {\n\t\t\t\tswitch strings.ToLower(t.Text) {\n\t\t\t\tcase \"linear\", \"ease\", \"ease-in\", \"ease-out\", \"ease-in-out\", \"step-start\", \"step-end\":\n\t\t\t\t\tfound.timingFunction = true\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !found.iterationCount && strings.ToLower(t.Text) == \"infinite\" {\n\t\t\t\tfound.iterationCount = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !found.direction {\n\t\t\t\tswitch strings.ToLower(t.Text) {\n\t\t\t\tcase \"normal\", \"reverse\", \"alternate\", \"alternate-reverse\":\n\t\t\t\t\tfound.direction = true\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !found.fillMode {\n\t\t\t\tswitch strings.ToLower(t.Text) {\n\t\t\t\tcase \"none\", \"forwards\", \"backwards\", \"both\":\n\t\t\t\t\tfound.fillMode = true\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !found.playState {\n\t\t\t\tswitch strings.ToLower(t.Text) {\n\t\t\t\tcase \"running\", \"paused\":\n\t\t\t\t\tfound.playState = true\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !found.name {\n\t\t\t\tp.handleSingleAnimationName(&tokens[i])\n\t\t\t\tfound.name = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\tcase css_lexer.TString:\n\t\t\tif !found.name {\n\t\t\t\tp.handleSingleAnimationName(&tokens[i])\n\t\t\t\tfound.name = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (p *parser) processAnimationName(tokens []css_ast.Token) {\n\tfor i, t := range tokens {\n\t\tif t.Kind == css_lexer.TIdent || t.Kind == css_lexer.TString {\n\t\t\tp.handleSingleAnimationName(&tokens[i])\n\t\t}\n\t}\n}\n\nfunc (p *parser) handleSingleAnimationName(token *css_ast.Token) {\n\t// Do not transform CSS keywords into symbols because they have special\n\t// meaning in declarations. For example, \"animation-name: none\" clears\n\t// the animation name. It does not set it to the animation named \"none\".\n\t// You need to use \"animation-name: 'none'\" to do that.\n\t//\n\t// Also don't transform strings containing CSS keywords into global symbols\n\t// because global symbols are passed through without being renamed, which\n\t// will print them as keywords. However, we still want to unconditionally\n\t// transform strings into local symbols because local symbols are always\n\t// renamed, so they will never be printed as keywords.\n\tif (token.Kind == css_lexer.TIdent || (token.Kind == css_lexer.TString && !p.makeLocalSymbols)) && isInvalidAnimationName(token.Text) {\n\t\treturn\n\t}\n\n\ttoken.Kind = css_lexer.TSymbol\n\ttoken.PayloadIndex = p.symbolForName(token.Loc, token.Text).Ref.InnerIndex\n}\n\nfunc isInvalidAnimationName(text string) bool {\n\tlower := strings.ToLower(text)\n\treturn lower == \"none\" || cssWideAndReservedKeywords[lower]\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_border_radius.go",
    "content": "package css_parser\n\nimport (\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\nconst (\n\tborderRadiusTopLeft = iota\n\tborderRadiusTopRight\n\tborderRadiusBottomRight\n\tborderRadiusBottomLeft\n)\n\ntype borderRadiusCorner struct {\n\tfirstToken    css_ast.Token\n\tsecondToken   css_ast.Token\n\tunitSafety    unitSafetyTracker\n\truleIndex     uint32 // The index of the originating rule in the rules array\n\twasSingleRule bool   // True if the originating rule was just for this side\n}\n\ntype borderRadiusTracker struct {\n\tcorners   [4]borderRadiusCorner\n\timportant bool // True if all active rules were flagged as \"!important\"\n}\n\nfunc (borderRadius *borderRadiusTracker) updateCorner(rules []css_ast.Rule, corner int, new borderRadiusCorner) {\n\tif old := borderRadius.corners[corner]; old.firstToken.Kind != css_lexer.TEndOfFile &&\n\t\t(!new.wasSingleRule || old.wasSingleRule) &&\n\t\told.unitSafety.status == unitSafe && new.unitSafety.status == unitSafe {\n\t\trules[old.ruleIndex] = css_ast.Rule{}\n\t}\n\tborderRadius.corners[corner] = new\n}\n\nfunc (borderRadius *borderRadiusTracker) mangleCorners(rules []css_ast.Rule, decl *css_ast.RDeclaration, minifyWhitespace bool) {\n\t// Reset if we see a change in the \"!important\" flag\n\tif borderRadius.important != decl.Important {\n\t\tborderRadius.corners = [4]borderRadiusCorner{}\n\t\tborderRadius.important = decl.Important\n\t}\n\n\ttokens := decl.Value\n\tbeforeSplit := len(tokens)\n\tafterSplit := len(tokens)\n\n\t// Search for the single slash if present\n\tfor i, t := range tokens {\n\t\tif t.Kind == css_lexer.TDelimSlash {\n\t\t\tif beforeSplit == len(tokens) {\n\t\t\t\tbeforeSplit = i\n\t\t\t\tafterSplit = i + 1\n\t\t\t} else {\n\t\t\t\t// Multiple slashes are an error\n\t\t\t\tborderRadius.corners = [4]borderRadiusCorner{}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Use a single tracker for the whole rule\n\tunitSafety := unitSafetyTracker{}\n\tfor _, t := range tokens[:beforeSplit] {\n\t\tunitSafety.includeUnitOf(t)\n\t}\n\tfor _, t := range tokens[afterSplit:] {\n\t\tunitSafety.includeUnitOf(t)\n\t}\n\n\tfirstRadii, firstRadiiOk := expandTokenQuad(tokens[:beforeSplit], \"\")\n\tlastRadii, lastRadiiOk := expandTokenQuad(tokens[afterSplit:], \"\")\n\n\t// Stop now if the pattern wasn't matched\n\tif !firstRadiiOk || (beforeSplit < afterSplit && !lastRadiiOk) {\n\t\tborderRadius.corners = [4]borderRadiusCorner{}\n\t\treturn\n\t}\n\n\t// Handle the first radii\n\tfor corner, t := range firstRadii {\n\t\tif unitSafety.status == unitSafe {\n\t\t\tt.TurnLengthIntoNumberIfZero()\n\t\t}\n\t\tborderRadius.updateCorner(rules, corner, borderRadiusCorner{\n\t\t\tfirstToken:  t,\n\t\t\tsecondToken: t,\n\t\t\tunitSafety:  unitSafety,\n\t\t\truleIndex:   uint32(len(rules) - 1),\n\t\t})\n\t}\n\n\t// Handle the last radii\n\tif lastRadiiOk {\n\t\tfor corner, t := range lastRadii {\n\t\t\tif unitSafety.status == unitSafe {\n\t\t\t\tt.TurnLengthIntoNumberIfZero()\n\t\t\t}\n\t\t\tborderRadius.corners[corner].secondToken = t\n\t\t}\n\t}\n\n\t// Success\n\tborderRadius.compactRules(rules, decl.KeyRange, minifyWhitespace)\n}\n\nfunc (borderRadius *borderRadiusTracker) mangleCorner(rules []css_ast.Rule, decl *css_ast.RDeclaration, minifyWhitespace bool, corner int) {\n\t// Reset if we see a change in the \"!important\" flag\n\tif borderRadius.important != decl.Important {\n\t\tborderRadius.corners = [4]borderRadiusCorner{}\n\t\tborderRadius.important = decl.Important\n\t}\n\n\tif tokens := decl.Value; (len(tokens) == 1 && tokens[0].Kind.IsNumeric()) ||\n\t\t(len(tokens) == 2 && tokens[0].Kind.IsNumeric() && tokens[1].Kind.IsNumeric()) {\n\t\tfirstToken := tokens[0]\n\t\tsecondToken := firstToken\n\t\tif len(tokens) == 2 {\n\t\t\tsecondToken = tokens[1]\n\t\t}\n\n\t\t// Check to see if these units are safe to use in every browser\n\t\tunitSafety := unitSafetyTracker{}\n\t\tunitSafety.includeUnitOf(firstToken)\n\t\tunitSafety.includeUnitOf(secondToken)\n\n\t\t// Only collapse \"0unit\" into \"0\" if the unit is safe\n\t\tif unitSafety.status == unitSafe && firstToken.TurnLengthIntoNumberIfZero() {\n\t\t\ttokens[0] = firstToken\n\t\t}\n\t\tif len(tokens) == 2 {\n\t\t\tif unitSafety.status == unitSafe && secondToken.TurnLengthIntoNumberIfZero() {\n\t\t\t\ttokens[1] = secondToken\n\t\t\t}\n\n\t\t\t// If both tokens are equal, merge them into one\n\t\t\tif firstToken.EqualIgnoringWhitespace(secondToken) {\n\t\t\t\ttokens[0].Whitespace &= ^css_ast.WhitespaceAfter\n\t\t\t\tdecl.Value = tokens[:1]\n\t\t\t}\n\t\t}\n\n\t\tborderRadius.updateCorner(rules, corner, borderRadiusCorner{\n\t\t\tfirstToken:    firstToken,\n\t\t\tsecondToken:   secondToken,\n\t\t\tunitSafety:    unitSafety,\n\t\t\truleIndex:     uint32(len(rules) - 1),\n\t\t\twasSingleRule: true,\n\t\t})\n\t\tborderRadius.compactRules(rules, decl.KeyRange, minifyWhitespace)\n\t} else {\n\t\tborderRadius.corners = [4]borderRadiusCorner{}\n\t}\n}\n\nfunc (borderRadius *borderRadiusTracker) compactRules(rules []css_ast.Rule, keyRange logger.Range, minifyWhitespace bool) {\n\t// All tokens must be present\n\tif eof := css_lexer.TEndOfFile; borderRadius.corners[0].firstToken.Kind == eof || borderRadius.corners[1].firstToken.Kind == eof ||\n\t\tborderRadius.corners[2].firstToken.Kind == eof || borderRadius.corners[3].firstToken.Kind == eof {\n\t\treturn\n\t}\n\n\t// All tokens must have the same unit\n\tfor _, side := range borderRadius.corners[1:] {\n\t\tif !side.unitSafety.isSafeWith(borderRadius.corners[0].unitSafety) {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Generate the most minimal representation\n\ttokens := compactTokenQuad(\n\t\tborderRadius.corners[0].firstToken,\n\t\tborderRadius.corners[1].firstToken,\n\t\tborderRadius.corners[2].firstToken,\n\t\tborderRadius.corners[3].firstToken,\n\t\tminifyWhitespace,\n\t)\n\tsecondTokens := compactTokenQuad(\n\t\tborderRadius.corners[0].secondToken,\n\t\tborderRadius.corners[1].secondToken,\n\t\tborderRadius.corners[2].secondToken,\n\t\tborderRadius.corners[3].secondToken,\n\t\tminifyWhitespace,\n\t)\n\tif !css_ast.TokensEqualIgnoringWhitespace(tokens, secondTokens) {\n\t\tvar whitespace css_ast.WhitespaceFlags\n\t\tif !minifyWhitespace {\n\t\t\twhitespace = css_ast.WhitespaceBefore | css_ast.WhitespaceAfter\n\t\t}\n\t\ttokens = append(tokens, css_ast.Token{\n\t\t\tLoc:        tokens[len(tokens)-1].Loc,\n\t\t\tKind:       css_lexer.TDelimSlash,\n\t\t\tText:       \"/\",\n\t\t\tWhitespace: whitespace,\n\t\t})\n\t\ttokens = append(tokens, secondTokens...)\n\t}\n\n\t// Remove all of the existing declarations\n\tvar minLoc logger.Loc\n\tfor i, corner := range borderRadius.corners {\n\t\tif loc := rules[corner.ruleIndex].Loc; i == 0 || loc.Start < minLoc.Start {\n\t\t\tminLoc = loc\n\t\t}\n\t\trules[corner.ruleIndex] = css_ast.Rule{}\n\t}\n\n\t// Insert the combined declaration where the last rule was\n\trules[borderRadius.corners[3].ruleIndex] = css_ast.Rule{Loc: minLoc, Data: &css_ast.RDeclaration{\n\t\tKey:       css_ast.DBorderRadius,\n\t\tKeyText:   \"border-radius\",\n\t\tValue:     tokens,\n\t\tKeyRange:  keyRange,\n\t\tImportant: borderRadius.important,\n\t}}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_box.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\nconst (\n\tboxTop = iota\n\tboxRight\n\tboxBottom\n\tboxLeft\n)\n\ntype boxSide struct {\n\ttoken         css_ast.Token\n\tunitSafety    unitSafetyTracker\n\truleIndex     uint32 // The index of the originating rule in the rules array\n\twasSingleRule bool   // True if the originating rule was just for this side\n}\n\ntype boxTracker struct {\n\tkeyText   string\n\tsides     [4]boxSide\n\tallowAuto bool // If true, allow the \"auto\" keyword\n\timportant bool // True if all active rules were flagged as \"!important\"\n\tkey       css_ast.D\n}\n\ntype unitSafetyStatus uint8\n\nconst (\n\tunitSafe         unitSafetyStatus = iota // \"margin: 0 1px 2cm 3%;\"\n\tunitUnsafeSingle                         // \"margin: 0 1vw 2vw 3vw;\"\n\tunitUnsafeMixed                          // \"margin: 0 1vw 2vh 3ch;\"\n)\n\n// We can only compact rules together if they have the same unit safety level.\n// We want to avoid a situation where the browser treats some of the original\n// rules as valid and others as invalid.\n//\n//\tSafe:\n//\t  top: 1px; left: 0; bottom: 1px; right: 0;\n//\t  top: 1Q; left: 2Q; bottom: 3Q; right: 4Q;\n//\n//\tUnsafe:\n//\t  top: 1vh; left: 2vw; bottom: 3vh; right: 4vw;\n//\t  top: 1Q; left: 2Q; bottom: 3Q; right: 0;\n//\t  inset: 1Q 0 0 0; top: 0;\ntype unitSafetyTracker struct {\n\tunit   string\n\tstatus unitSafetyStatus\n}\n\nfunc (a unitSafetyTracker) isSafeWith(b unitSafetyTracker) bool {\n\treturn a.status == b.status && a.status != unitUnsafeMixed && (a.status != unitUnsafeSingle || a.unit == b.unit)\n}\n\nfunc (t *unitSafetyTracker) includeUnitOf(token css_ast.Token) {\n\tswitch token.Kind {\n\tcase css_lexer.TNumber:\n\t\tif token.Text == \"0\" {\n\t\t\treturn\n\t\t}\n\n\tcase css_lexer.TPercentage:\n\t\treturn\n\n\tcase css_lexer.TDimension:\n\t\tif token.DimensionUnitIsSafeLength() {\n\t\t\treturn\n\t\t} else if unit := token.DimensionUnit(); t.status == unitSafe {\n\t\t\tt.status = unitUnsafeSingle\n\t\t\tt.unit = unit\n\t\t\treturn\n\t\t} else if t.status == unitUnsafeSingle && t.unit == unit {\n\t\t\treturn\n\t\t}\n\t}\n\n\tt.status = unitUnsafeMixed\n}\n\nfunc (box *boxTracker) updateSide(rules []css_ast.Rule, side int, new boxSide) {\n\tif old := box.sides[side]; old.token.Kind != css_lexer.TEndOfFile &&\n\t\t(!new.wasSingleRule || old.wasSingleRule) &&\n\t\told.unitSafety.status == unitSafe && new.unitSafety.status == unitSafe {\n\t\trules[old.ruleIndex] = css_ast.Rule{}\n\t}\n\tbox.sides[side] = new\n}\n\nfunc (box *boxTracker) mangleSides(rules []css_ast.Rule, decl *css_ast.RDeclaration, minifyWhitespace bool) {\n\t// Reset if we see a change in the \"!important\" flag\n\tif box.important != decl.Important {\n\t\tbox.sides = [4]boxSide{}\n\t\tbox.important = decl.Important\n\t}\n\n\tallowedIdent := \"\"\n\tif box.allowAuto {\n\t\tallowedIdent = \"auto\"\n\t}\n\tif quad, ok := expandTokenQuad(decl.Value, allowedIdent); ok {\n\t\t// Use a single tracker for the whole rule\n\t\tunitSafety := unitSafetyTracker{}\n\t\tfor _, t := range quad {\n\t\t\tif !box.allowAuto || t.Kind.IsNumeric() {\n\t\t\t\tunitSafety.includeUnitOf(t)\n\t\t\t}\n\t\t}\n\t\tfor side, t := range quad {\n\t\t\tif unitSafety.status == unitSafe {\n\t\t\t\tt.TurnLengthIntoNumberIfZero()\n\t\t\t}\n\t\t\tbox.updateSide(rules, side, boxSide{\n\t\t\t\ttoken:      t,\n\t\t\t\truleIndex:  uint32(len(rules) - 1),\n\t\t\t\tunitSafety: unitSafety,\n\t\t\t})\n\t\t}\n\t\tbox.compactRules(rules, decl.KeyRange, minifyWhitespace)\n\t} else {\n\t\tbox.sides = [4]boxSide{}\n\t}\n}\n\nfunc (box *boxTracker) mangleSide(rules []css_ast.Rule, decl *css_ast.RDeclaration, minifyWhitespace bool, side int) {\n\t// Reset if we see a change in the \"!important\" flag\n\tif box.important != decl.Important {\n\t\tbox.sides = [4]boxSide{}\n\t\tbox.important = decl.Important\n\t}\n\n\tif tokens := decl.Value; len(tokens) == 1 {\n\t\tif t := tokens[0]; t.Kind.IsNumeric() || (t.Kind == css_lexer.TIdent && box.allowAuto && strings.EqualFold(t.Text, \"auto\")) {\n\t\t\tunitSafety := unitSafetyTracker{}\n\t\t\tif !box.allowAuto || t.Kind.IsNumeric() {\n\t\t\t\tunitSafety.includeUnitOf(t)\n\t\t\t}\n\t\t\tif unitSafety.status == unitSafe && t.TurnLengthIntoNumberIfZero() {\n\t\t\t\ttokens[0] = t\n\t\t\t}\n\t\t\tbox.updateSide(rules, side, boxSide{\n\t\t\t\ttoken:         t,\n\t\t\t\truleIndex:     uint32(len(rules) - 1),\n\t\t\t\twasSingleRule: true,\n\t\t\t\tunitSafety:    unitSafety,\n\t\t\t})\n\t\t\tbox.compactRules(rules, decl.KeyRange, minifyWhitespace)\n\t\t\treturn\n\t\t}\n\t}\n\n\tbox.sides = [4]boxSide{}\n}\n\nfunc (box *boxTracker) compactRules(rules []css_ast.Rule, keyRange logger.Range, minifyWhitespace bool) {\n\t// Don't compact if the shorthand form is unsupported\n\tif box.key == css_ast.DUnknown {\n\t\treturn\n\t}\n\n\t// All tokens must be present\n\tif eof := css_lexer.TEndOfFile; box.sides[0].token.Kind == eof || box.sides[1].token.Kind == eof ||\n\t\tbox.sides[2].token.Kind == eof || box.sides[3].token.Kind == eof {\n\t\treturn\n\t}\n\n\t// All tokens must have the same unit\n\tfor _, side := range box.sides[1:] {\n\t\tif !side.unitSafety.isSafeWith(box.sides[0].unitSafety) {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Generate the most minimal representation\n\ttokens := compactTokenQuad(\n\t\tbox.sides[0].token,\n\t\tbox.sides[1].token,\n\t\tbox.sides[2].token,\n\t\tbox.sides[3].token,\n\t\tminifyWhitespace,\n\t)\n\n\t// Remove all of the existing declarations\n\tvar minLoc logger.Loc\n\tfor i, side := range box.sides {\n\t\tif loc := rules[side.ruleIndex].Loc; i == 0 || loc.Start < minLoc.Start {\n\t\t\tminLoc = loc\n\t\t}\n\t\trules[side.ruleIndex] = css_ast.Rule{}\n\t}\n\n\t// Insert the combined declaration where the last rule was\n\trules[box.sides[3].ruleIndex] = css_ast.Rule{Loc: minLoc, Data: &css_ast.RDeclaration{\n\t\tKey:       box.key,\n\t\tKeyText:   box.keyText,\n\t\tValue:     tokens,\n\t\tKeyRange:  keyRange,\n\t\tImportant: box.important,\n\t}}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_box_shadow.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\nfunc (p *parser) lowerAndMangleBoxShadow(tokens []css_ast.Token, wouldClipColor *bool) []css_ast.Token {\n\tinsetCount := 0\n\tcolorCount := 0\n\tnumbersBegin := 0\n\tnumbersCount := 0\n\tnumbersDone := false\n\tfoundUnexpectedToken := false\n\n\tfor i, t := range tokens {\n\t\tif t.Kind == css_lexer.TNumber || t.Kind == css_lexer.TDimension {\n\t\t\tif numbersDone {\n\t\t\t\t// Track if we found a non-number in between two numbers\n\t\t\t\tfoundUnexpectedToken = true\n\t\t\t}\n\t\t\tif p.options.minifySyntax && t.TurnLengthIntoNumberIfZero() {\n\t\t\t\t// \"0px\" => \"0\"\n\t\t\t\ttokens[i] = t\n\t\t\t}\n\t\t\tif numbersCount == 0 {\n\t\t\t\t// Track the index of the first number\n\t\t\t\tnumbersBegin = i\n\t\t\t}\n\t\t\tnumbersCount++\n\t\t} else {\n\t\t\tif numbersCount != 0 {\n\t\t\t\t// Track when we find a non-number after a number\n\t\t\t\tnumbersDone = true\n\t\t\t}\n\n\t\t\tif looksLikeColor(t) {\n\t\t\t\tcolorCount++\n\t\t\t\ttokens[i] = p.lowerAndMinifyColor(t, wouldClipColor)\n\t\t\t} else if t.Kind == css_lexer.TIdent && strings.EqualFold(t.Text, \"inset\") {\n\t\t\t\tinsetCount++\n\t\t\t} else {\n\t\t\t\t// Track if we found a token other than a number, a color, or \"inset\"\n\t\t\t\tfoundUnexpectedToken = true\n\t\t\t}\n\t\t}\n\t}\n\n\t// If everything looks like a valid rule, trim trailing zeros off the numbers.\n\t// There are three valid configurations of numbers:\n\t//\n\t//   offset-x | offset-y\n\t//   offset-x | offset-y | blur-radius\n\t//   offset-x | offset-y | blur-radius | spread-radius\n\t//\n\t// If omitted, blur-radius and spread-radius are implied to be zero.\n\tif p.options.minifySyntax && insetCount <= 1 && colorCount <= 1 && numbersCount > 2 && numbersCount <= 4 && !foundUnexpectedToken {\n\t\tnumbersEnd := numbersBegin + numbersCount\n\t\tfor numbersCount > 2 && tokens[numbersBegin+numbersCount-1].IsZero() {\n\t\t\tnumbersCount--\n\t\t}\n\t\ttokens = append(tokens[:numbersBegin+numbersCount], tokens[numbersEnd:]...)\n\t}\n\n\t// Set the whitespace flags\n\tfor i := range tokens {\n\t\tvar whitespace css_ast.WhitespaceFlags\n\t\tif i > 0 || !p.options.minifyWhitespace {\n\t\t\twhitespace |= css_ast.WhitespaceBefore\n\t\t}\n\t\tif i+1 < len(tokens) {\n\t\t\twhitespace |= css_ast.WhitespaceAfter\n\t\t}\n\t\ttokens[i].Whitespace = whitespace\n\t}\n\treturn tokens\n}\n\nfunc (p *parser) lowerAndMangleBoxShadows(tokens []css_ast.Token, wouldClipColor *bool) []css_ast.Token {\n\tn := len(tokens)\n\tend := 0\n\ti := 0\n\n\tfor i < n {\n\t\t// Find the comma or the end of the token list\n\t\tcomma := i\n\t\tfor comma < n && tokens[comma].Kind != css_lexer.TComma {\n\t\t\tcomma++\n\t\t}\n\n\t\t// Mangle this individual shadow\n\t\tend += copy(tokens[end:], p.lowerAndMangleBoxShadow(tokens[i:comma], wouldClipColor))\n\n\t\t// Skip over the comma\n\t\tif comma < n {\n\t\t\ttokens[end] = tokens[comma]\n\t\t\tend++\n\t\t\tcomma++\n\t\t}\n\t\ti = comma\n\t}\n\n\treturn tokens[:end]\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_color.go",
    "content": "package css_parser\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n)\n\n// These names are shorter than their hex codes\nvar shortColorName = map[uint32]string{\n\t0x000080ff: \"navy\",\n\t0x008000ff: \"green\",\n\t0x008080ff: \"teal\",\n\t0x4b0082ff: \"indigo\",\n\t0x800000ff: \"maroon\",\n\t0x800080ff: \"purple\",\n\t0x808000ff: \"olive\",\n\t0x808080ff: \"gray\",\n\t0xa0522dff: \"sienna\",\n\t0xa52a2aff: \"brown\",\n\t0xc0c0c0ff: \"silver\",\n\t0xcd853fff: \"peru\",\n\t0xd2b48cff: \"tan\",\n\t0xda70d6ff: \"orchid\",\n\t0xdda0ddff: \"plum\",\n\t0xee82eeff: \"violet\",\n\t0xf0e68cff: \"khaki\",\n\t0xf0ffffff: \"azure\",\n\t0xf5deb3ff: \"wheat\",\n\t0xf5f5dcff: \"beige\",\n\t0xfa8072ff: \"salmon\",\n\t0xfaf0e6ff: \"linen\",\n\t0xff0000ff: \"red\",\n\t0xff6347ff: \"tomato\",\n\t0xff7f50ff: \"coral\",\n\t0xffa500ff: \"orange\",\n\t0xffc0cbff: \"pink\",\n\t0xffd700ff: \"gold\",\n\t0xffe4c4ff: \"bisque\",\n\t0xfffafaff: \"snow\",\n\t0xfffff0ff: \"ivory\",\n}\n\nvar colorNameToHex = map[string]uint32{\n\t\"black\":                0x000000ff,\n\t\"silver\":               0xc0c0c0ff,\n\t\"gray\":                 0x808080ff,\n\t\"white\":                0xffffffff,\n\t\"maroon\":               0x800000ff,\n\t\"red\":                  0xff0000ff,\n\t\"purple\":               0x800080ff,\n\t\"fuchsia\":              0xff00ffff,\n\t\"green\":                0x008000ff,\n\t\"lime\":                 0x00ff00ff,\n\t\"olive\":                0x808000ff,\n\t\"yellow\":               0xffff00ff,\n\t\"navy\":                 0x000080ff,\n\t\"blue\":                 0x0000ffff,\n\t\"teal\":                 0x008080ff,\n\t\"aqua\":                 0x00ffffff,\n\t\"orange\":               0xffa500ff,\n\t\"aliceblue\":            0xf0f8ffff,\n\t\"antiquewhite\":         0xfaebd7ff,\n\t\"aquamarine\":           0x7fffd4ff,\n\t\"azure\":                0xf0ffffff,\n\t\"beige\":                0xf5f5dcff,\n\t\"bisque\":               0xffe4c4ff,\n\t\"blanchedalmond\":       0xffebcdff,\n\t\"blueviolet\":           0x8a2be2ff,\n\t\"brown\":                0xa52a2aff,\n\t\"burlywood\":            0xdeb887ff,\n\t\"cadetblue\":            0x5f9ea0ff,\n\t\"chartreuse\":           0x7fff00ff,\n\t\"chocolate\":            0xd2691eff,\n\t\"coral\":                0xff7f50ff,\n\t\"cornflowerblue\":       0x6495edff,\n\t\"cornsilk\":             0xfff8dcff,\n\t\"crimson\":              0xdc143cff,\n\t\"cyan\":                 0x00ffffff,\n\t\"darkblue\":             0x00008bff,\n\t\"darkcyan\":             0x008b8bff,\n\t\"darkgoldenrod\":        0xb8860bff,\n\t\"darkgray\":             0xa9a9a9ff,\n\t\"darkgreen\":            0x006400ff,\n\t\"darkgrey\":             0xa9a9a9ff,\n\t\"darkkhaki\":            0xbdb76bff,\n\t\"darkmagenta\":          0x8b008bff,\n\t\"darkolivegreen\":       0x556b2fff,\n\t\"darkorange\":           0xff8c00ff,\n\t\"darkorchid\":           0x9932ccff,\n\t\"darkred\":              0x8b0000ff,\n\t\"darksalmon\":           0xe9967aff,\n\t\"darkseagreen\":         0x8fbc8fff,\n\t\"darkslateblue\":        0x483d8bff,\n\t\"darkslategray\":        0x2f4f4fff,\n\t\"darkslategrey\":        0x2f4f4fff,\n\t\"darkturquoise\":        0x00ced1ff,\n\t\"darkviolet\":           0x9400d3ff,\n\t\"deeppink\":             0xff1493ff,\n\t\"deepskyblue\":          0x00bfffff,\n\t\"dimgray\":              0x696969ff,\n\t\"dimgrey\":              0x696969ff,\n\t\"dodgerblue\":           0x1e90ffff,\n\t\"firebrick\":            0xb22222ff,\n\t\"floralwhite\":          0xfffaf0ff,\n\t\"forestgreen\":          0x228b22ff,\n\t\"gainsboro\":            0xdcdcdcff,\n\t\"ghostwhite\":           0xf8f8ffff,\n\t\"gold\":                 0xffd700ff,\n\t\"goldenrod\":            0xdaa520ff,\n\t\"greenyellow\":          0xadff2fff,\n\t\"grey\":                 0x808080ff,\n\t\"honeydew\":             0xf0fff0ff,\n\t\"hotpink\":              0xff69b4ff,\n\t\"indianred\":            0xcd5c5cff,\n\t\"indigo\":               0x4b0082ff,\n\t\"ivory\":                0xfffff0ff,\n\t\"khaki\":                0xf0e68cff,\n\t\"lavender\":             0xe6e6faff,\n\t\"lavenderblush\":        0xfff0f5ff,\n\t\"lawngreen\":            0x7cfc00ff,\n\t\"lemonchiffon\":         0xfffacdff,\n\t\"lightblue\":            0xadd8e6ff,\n\t\"lightcoral\":           0xf08080ff,\n\t\"lightcyan\":            0xe0ffffff,\n\t\"lightgoldenrodyellow\": 0xfafad2ff,\n\t\"lightgray\":            0xd3d3d3ff,\n\t\"lightgreen\":           0x90ee90ff,\n\t\"lightgrey\":            0xd3d3d3ff,\n\t\"lightpink\":            0xffb6c1ff,\n\t\"lightsalmon\":          0xffa07aff,\n\t\"lightseagreen\":        0x20b2aaff,\n\t\"lightskyblue\":         0x87cefaff,\n\t\"lightslategray\":       0x778899ff,\n\t\"lightslategrey\":       0x778899ff,\n\t\"lightsteelblue\":       0xb0c4deff,\n\t\"lightyellow\":          0xffffe0ff,\n\t\"limegreen\":            0x32cd32ff,\n\t\"linen\":                0xfaf0e6ff,\n\t\"magenta\":              0xff00ffff,\n\t\"mediumaquamarine\":     0x66cdaaff,\n\t\"mediumblue\":           0x0000cdff,\n\t\"mediumorchid\":         0xba55d3ff,\n\t\"mediumpurple\":         0x9370dbff,\n\t\"mediumseagreen\":       0x3cb371ff,\n\t\"mediumslateblue\":      0x7b68eeff,\n\t\"mediumspringgreen\":    0x00fa9aff,\n\t\"mediumturquoise\":      0x48d1ccff,\n\t\"mediumvioletred\":      0xc71585ff,\n\t\"midnightblue\":         0x191970ff,\n\t\"mintcream\":            0xf5fffaff,\n\t\"mistyrose\":            0xffe4e1ff,\n\t\"moccasin\":             0xffe4b5ff,\n\t\"navajowhite\":          0xffdeadff,\n\t\"oldlace\":              0xfdf5e6ff,\n\t\"olivedrab\":            0x6b8e23ff,\n\t\"orangered\":            0xff4500ff,\n\t\"orchid\":               0xda70d6ff,\n\t\"palegoldenrod\":        0xeee8aaff,\n\t\"palegreen\":            0x98fb98ff,\n\t\"paleturquoise\":        0xafeeeeff,\n\t\"palevioletred\":        0xdb7093ff,\n\t\"papayawhip\":           0xffefd5ff,\n\t\"peachpuff\":            0xffdab9ff,\n\t\"peru\":                 0xcd853fff,\n\t\"pink\":                 0xffc0cbff,\n\t\"plum\":                 0xdda0ddff,\n\t\"powderblue\":           0xb0e0e6ff,\n\t\"rosybrown\":            0xbc8f8fff,\n\t\"royalblue\":            0x4169e1ff,\n\t\"saddlebrown\":          0x8b4513ff,\n\t\"salmon\":               0xfa8072ff,\n\t\"sandybrown\":           0xf4a460ff,\n\t\"seagreen\":             0x2e8b57ff,\n\t\"seashell\":             0xfff5eeff,\n\t\"sienna\":               0xa0522dff,\n\t\"skyblue\":              0x87ceebff,\n\t\"slateblue\":            0x6a5acdff,\n\t\"slategray\":            0x708090ff,\n\t\"slategrey\":            0x708090ff,\n\t\"snow\":                 0xfffafaff,\n\t\"springgreen\":          0x00ff7fff,\n\t\"steelblue\":            0x4682b4ff,\n\t\"tan\":                  0xd2b48cff,\n\t\"thistle\":              0xd8bfd8ff,\n\t\"tomato\":               0xff6347ff,\n\t\"turquoise\":            0x40e0d0ff,\n\t\"violet\":               0xee82eeff,\n\t\"wheat\":                0xf5deb3ff,\n\t\"whitesmoke\":           0xf5f5f5ff,\n\t\"yellowgreen\":          0x9acd32ff,\n\t\"rebeccapurple\":        0x663399ff,\n}\n\nfunc parseHex(text string) (uint32, bool) {\n\thex := uint32(0)\n\tfor _, c := range text {\n\t\thex <<= 4\n\t\tswitch {\n\t\tcase c >= '0' && c <= '9':\n\t\t\thex |= uint32(c) - '0'\n\t\tcase c >= 'a' && c <= 'f':\n\t\t\thex |= uint32(c) - ('a' - 10)\n\t\tcase c >= 'A' && c <= 'F':\n\t\t\thex |= uint32(c) - ('A' - 10)\n\t\tdefault:\n\t\t\treturn 0, false\n\t\t}\n\t}\n\treturn hex, true\n}\n\n// 0xAABBCCDD => 0xABCD\nfunc compactHex(v uint32) uint32 {\n\treturn ((v & 0x0FF00000) >> 12) | ((v & 0x00000FF0) >> 4)\n}\n\n// 0xABCD => 0xAABBCCDD\nfunc expandHex(v uint32) uint32 {\n\treturn ((v & 0xF000) << 16) | ((v & 0xFF00) << 12) | ((v & 0x0FF0) << 8) | ((v & 0x00FF) << 4) | (v & 0x000F)\n}\n\nfunc hexR(v uint32) int { return int(v >> 24) }\nfunc hexG(v uint32) int { return int((v >> 16) & 255) }\nfunc hexB(v uint32) int { return int((v >> 8) & 255) }\nfunc hexA(v uint32) int { return int(v & 255) }\n\nfunc floatToStringForColor(a float64) string {\n\ttext := fmt.Sprintf(\"%.03f\", a)\n\tfor text[len(text)-1] == '0' {\n\t\ttext = text[:len(text)-1]\n\t}\n\tif text[len(text)-1] == '.' {\n\t\ttext = text[:len(text)-1]\n\t}\n\treturn text\n}\n\nfunc degreesForAngle(token css_ast.Token) (float64, bool) {\n\tswitch token.Kind {\n\tcase css_lexer.TNumber:\n\t\tif value, err := strconv.ParseFloat(token.Text, 64); err == nil {\n\t\t\treturn value, true\n\t\t}\n\n\tcase css_lexer.TDimension:\n\t\tif value, err := strconv.ParseFloat(token.DimensionValue(), 64); err == nil {\n\t\t\tswitch token.DimensionUnit() {\n\t\t\tcase \"deg\":\n\t\t\t\treturn value, true\n\t\t\tcase \"grad\":\n\t\t\t\treturn value * (360.0 / 400.0), true\n\t\t\tcase \"rad\":\n\t\t\t\treturn value * (180.0 / math.Pi), true\n\t\t\tcase \"turn\":\n\t\t\t\treturn value * 360.0, true\n\t\t\t}\n\t\t}\n\t}\n\treturn 0, false\n}\n\nfunc lowerAlphaPercentageToNumber(token css_ast.Token) css_ast.Token {\n\tif token.Kind == css_lexer.TPercentage {\n\t\tif value, err := strconv.ParseFloat(token.Text[:len(token.Text)-1], 64); err == nil {\n\t\t\ttoken.Kind = css_lexer.TNumber\n\t\t\ttoken.Text = floatToStringForColor(value / 100.0)\n\t\t}\n\t}\n\treturn token\n}\n\n// Convert newer color syntax to older color syntax for older browsers\nfunc (p *parser) lowerAndMinifyColor(token css_ast.Token, wouldClipColor *bool) css_ast.Token {\n\ttext := token.Text\n\n\tswitch token.Kind {\n\tcase css_lexer.THash:\n\t\tif p.options.unsupportedCSSFeatures.Has(compat.HexRGBA) {\n\t\t\tswitch len(text) {\n\t\t\tcase 4:\n\t\t\t\t// \"#1234\" => \"rgba(1, 2, 3, 0.004)\"\n\t\t\t\tif hex, ok := parseHex(text); ok {\n\t\t\t\t\thex = expandHex(hex)\n\t\t\t\t\treturn p.tryToGenerateColor(token, parsedColor{hex: hex}, nil)\n\t\t\t\t}\n\n\t\t\tcase 8:\n\t\t\t\t// \"#12345678\" => \"rgba(18, 52, 86, 0.47)\"\n\t\t\t\tif hex, ok := parseHex(text); ok {\n\t\t\t\t\treturn p.tryToGenerateColor(token, parsedColor{hex: hex}, nil)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tcase css_lexer.TIdent:\n\t\tif p.options.unsupportedCSSFeatures.Has(compat.RebeccaPurple) && strings.EqualFold(text, \"rebeccapurple\") {\n\t\t\ttoken.Kind = css_lexer.THash\n\t\t\ttoken.Text = \"663399\"\n\t\t}\n\n\tcase css_lexer.TFunction:\n\t\tswitch strings.ToLower(text) {\n\t\tcase \"rgb\", \"rgba\", \"hsl\", \"hsla\":\n\t\t\tif p.options.unsupportedCSSFeatures.Has(compat.Modern_RGB_HSL) {\n\t\t\t\targs := *token.Children\n\t\t\t\tremoveAlpha := false\n\t\t\t\taddAlpha := false\n\n\t\t\t\t// \"hsl(1deg, 2%, 3%)\" => \"hsl(1, 2%, 3%)\"\n\t\t\t\tif (text == \"hsl\" || text == \"hsla\") && len(args) > 0 {\n\t\t\t\t\tif degrees, ok := degreesForAngle(args[0]); ok {\n\t\t\t\t\t\targs[0].Kind = css_lexer.TNumber\n\t\t\t\t\t\targs[0].Text = floatToStringForColor(degrees)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// These check for \"IsNumeric\" to reject \"var()\" since a single \"var()\"\n\t\t\t\t// can substitute for multiple tokens and that messes up pattern matching\n\t\t\t\tswitch len(args) {\n\t\t\t\tcase 3:\n\t\t\t\t\t// \"rgba(1 2 3)\" => \"rgb(1, 2, 3)\"\n\t\t\t\t\t// \"hsla(1 2% 3%)\" => \"hsl(1, 2%, 3%)\"\n\t\t\t\t\tif args[0].Kind.IsNumeric() && args[1].Kind.IsNumeric() && args[2].Kind.IsNumeric() {\n\t\t\t\t\t\tremoveAlpha = true\n\t\t\t\t\t\targs[0].Whitespace = 0\n\t\t\t\t\t\targs[1].Whitespace = 0\n\t\t\t\t\t\tcommaToken := p.commaToken(token.Loc)\n\t\t\t\t\t\ttoken.Children = &[]css_ast.Token{\n\t\t\t\t\t\t\targs[0], commaToken,\n\t\t\t\t\t\t\targs[1], commaToken,\n\t\t\t\t\t\t\targs[2],\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 5:\n\t\t\t\t\t// \"rgba(1, 2, 3)\" => \"rgb(1, 2, 3)\"\n\t\t\t\t\t// \"hsla(1, 2%, 3%)\" => \"hsl(1%, 2%, 3%)\"\n\t\t\t\t\tif args[0].Kind.IsNumeric() && args[1].Kind == css_lexer.TComma &&\n\t\t\t\t\t\targs[2].Kind.IsNumeric() && args[3].Kind == css_lexer.TComma &&\n\t\t\t\t\t\targs[4].Kind.IsNumeric() {\n\t\t\t\t\t\tremoveAlpha = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\t// \"rgb(1 2 3 / 4%)\" => \"rgba(1, 2, 3, 0.04)\"\n\t\t\t\t\t// \"hsl(1 2% 3% / 4%)\" => \"hsla(1, 2%, 3%, 0.04)\"\n\t\t\t\t\tif args[0].Kind.IsNumeric() && args[1].Kind.IsNumeric() && args[2].Kind.IsNumeric() &&\n\t\t\t\t\t\targs[3].Kind == css_lexer.TDelimSlash && args[4].Kind.IsNumeric() {\n\t\t\t\t\t\taddAlpha = true\n\t\t\t\t\t\targs[0].Whitespace = 0\n\t\t\t\t\t\targs[1].Whitespace = 0\n\t\t\t\t\t\targs[2].Whitespace = 0\n\t\t\t\t\t\tcommaToken := p.commaToken(token.Loc)\n\t\t\t\t\t\ttoken.Children = &[]css_ast.Token{\n\t\t\t\t\t\t\targs[0], commaToken,\n\t\t\t\t\t\t\targs[1], commaToken,\n\t\t\t\t\t\t\targs[2], commaToken,\n\t\t\t\t\t\t\tlowerAlphaPercentageToNumber(args[4]),\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase 7:\n\t\t\t\t\t// \"rgb(1%, 2%, 3%, 4%)\" => \"rgba(1%, 2%, 3%, 0.04)\"\n\t\t\t\t\t// \"hsl(1, 2%, 3%, 4%)\" => \"hsla(1, 2%, 3%, 0.04)\"\n\t\t\t\t\tif args[0].Kind.IsNumeric() && args[1].Kind == css_lexer.TComma &&\n\t\t\t\t\t\targs[2].Kind.IsNumeric() && args[3].Kind == css_lexer.TComma &&\n\t\t\t\t\t\targs[4].Kind.IsNumeric() && args[5].Kind == css_lexer.TComma &&\n\t\t\t\t\t\targs[6].Kind.IsNumeric() {\n\t\t\t\t\t\taddAlpha = true\n\t\t\t\t\t\targs[6] = lowerAlphaPercentageToNumber(args[6])\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif removeAlpha {\n\t\t\t\t\tif strings.EqualFold(text, \"rgba\") {\n\t\t\t\t\t\ttoken.Text = \"rgb\"\n\t\t\t\t\t} else if strings.EqualFold(text, \"hsla\") {\n\t\t\t\t\t\ttoken.Text = \"hsl\"\n\t\t\t\t\t}\n\t\t\t\t} else if addAlpha {\n\t\t\t\t\tif strings.EqualFold(text, \"rgb\") {\n\t\t\t\t\t\ttoken.Text = \"rgba\"\n\t\t\t\t\t} else if strings.EqualFold(text, \"hsl\") {\n\t\t\t\t\t\ttoken.Text = \"hsla\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase \"hwb\":\n\t\t\tif p.options.unsupportedCSSFeatures.Has(compat.HWB) {\n\t\t\t\tif color, ok := parseColor(token); ok {\n\t\t\t\t\treturn p.tryToGenerateColor(token, color, wouldClipColor)\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase \"color\", \"lab\", \"lch\", \"oklab\", \"oklch\":\n\t\t\tif p.options.unsupportedCSSFeatures.Has(compat.ColorFunctions) {\n\t\t\t\tif color, ok := parseColor(token); ok {\n\t\t\t\t\treturn p.tryToGenerateColor(token, color, wouldClipColor)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// When minifying, try to parse the color and print it back out. This minifies\n\t// the color because we always print it out using the shortest encoding.\n\tif p.options.minifySyntax {\n\t\tif hex, ok := parseColor(token); ok {\n\t\t\ttoken = p.tryToGenerateColor(token, hex, wouldClipColor)\n\t\t}\n\t}\n\n\treturn token\n}\n\ntype parsedColor struct {\n\tx, y, z       F64    // color if hasColorSpace == true\n\thex           uint32 // color and alpha if hasColorSpace == false, alpha if hasColorSpace == true\n\thasColorSpace bool\n}\n\nfunc looksLikeColor(token css_ast.Token) bool {\n\tswitch token.Kind {\n\tcase css_lexer.TIdent:\n\t\tif _, ok := colorNameToHex[strings.ToLower(token.Text)]; ok {\n\t\t\treturn true\n\t\t}\n\n\tcase css_lexer.THash:\n\t\tswitch len(token.Text) {\n\t\tcase 3, 4, 6, 8:\n\t\t\tif _, ok := parseHex(token.Text); ok {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\tcase css_lexer.TFunction:\n\t\tswitch strings.ToLower(token.Text) {\n\t\tcase\n\t\t\t\"color-mix\",\n\t\t\t\"color\",\n\t\t\t\"hsl\",\n\t\t\t\"hsla\",\n\t\t\t\"hwb\",\n\t\t\t\"lab\",\n\t\t\t\"lch\",\n\t\t\t\"oklab\",\n\t\t\t\"oklch\",\n\t\t\t\"rgb\",\n\t\t\t\"rgba\":\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc parseColor(token css_ast.Token) (parsedColor, bool) {\n\ttext := token.Text\n\n\tswitch token.Kind {\n\tcase css_lexer.TIdent:\n\t\tif hex, ok := colorNameToHex[strings.ToLower(text)]; ok {\n\t\t\treturn parsedColor{hex: hex}, true\n\t\t}\n\n\tcase css_lexer.THash:\n\t\tswitch len(text) {\n\t\tcase 3:\n\t\t\t// \"#123\"\n\t\t\tif hex, ok := parseHex(text); ok {\n\t\t\t\treturn parsedColor{hex: (expandHex(hex) << 8) | 0xFF}, true\n\t\t\t}\n\n\t\tcase 4:\n\t\t\t// \"#1234\"\n\t\t\tif hex, ok := parseHex(text); ok {\n\t\t\t\treturn parsedColor{hex: expandHex(hex)}, true\n\t\t\t}\n\n\t\tcase 6:\n\t\t\t// \"#112233\"\n\t\t\tif hex, ok := parseHex(text); ok {\n\t\t\t\treturn parsedColor{hex: (hex << 8) | 0xFF}, true\n\t\t\t}\n\n\t\tcase 8:\n\t\t\t// \"#11223344\"\n\t\t\tif hex, ok := parseHex(text); ok {\n\t\t\t\treturn parsedColor{hex: hex}, true\n\t\t\t}\n\t\t}\n\n\tcase css_lexer.TFunction:\n\t\tlowerText := strings.ToLower(text)\n\t\tswitch lowerText {\n\t\tcase \"rgb\", \"rgba\":\n\t\t\targs := *token.Children\n\t\t\tvar r, g, b, a css_ast.Token\n\n\t\t\tswitch len(args) {\n\t\t\tcase 3:\n\t\t\t\t// \"rgb(1 2 3)\"\n\t\t\t\tr, g, b = args[0], args[1], args[2]\n\n\t\t\tcase 5:\n\t\t\t\t// \"rgba(1, 2, 3)\"\n\t\t\t\tif args[1].Kind == css_lexer.TComma && args[3].Kind == css_lexer.TComma {\n\t\t\t\t\tr, g, b = args[0], args[2], args[4]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// \"rgb(1 2 3 / 4%)\"\n\t\t\t\tif args[3].Kind == css_lexer.TDelimSlash {\n\t\t\t\t\tr, g, b, a = args[0], args[1], args[2], args[4]\n\t\t\t\t}\n\n\t\t\tcase 7:\n\t\t\t\t// \"rgb(1%, 2%, 3%, 4%)\"\n\t\t\t\tif args[1].Kind == css_lexer.TComma && args[3].Kind == css_lexer.TComma && args[5].Kind == css_lexer.TComma {\n\t\t\t\t\tr, g, b, a = args[0], args[2], args[4], args[6]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif r, ok := parseColorByte(r, 1); ok {\n\t\t\t\tif g, ok := parseColorByte(g, 1); ok {\n\t\t\t\t\tif b, ok := parseColorByte(b, 1); ok {\n\t\t\t\t\t\tif a, ok := parseAlphaByte(a); ok {\n\t\t\t\t\t\t\treturn parsedColor{hex: (r << 24) | (g << 16) | (b << 8) | a}, true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase \"hsl\", \"hsla\":\n\t\t\targs := *token.Children\n\t\t\tvar h, s, l, a css_ast.Token\n\n\t\t\tswitch len(args) {\n\t\t\tcase 3:\n\t\t\t\t// \"hsl(1 2 3)\"\n\t\t\t\th, s, l = args[0], args[1], args[2]\n\n\t\t\tcase 5:\n\t\t\t\t// \"hsla(1, 2, 3)\"\n\t\t\t\tif args[1].Kind == css_lexer.TComma && args[3].Kind == css_lexer.TComma {\n\t\t\t\t\th, s, l = args[0], args[2], args[4]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// \"hsl(1 2 3 / 4%)\"\n\t\t\t\tif args[3].Kind == css_lexer.TDelimSlash {\n\t\t\t\t\th, s, l, a = args[0], args[1], args[2], args[4]\n\t\t\t\t}\n\n\t\t\tcase 7:\n\t\t\t\t// \"hsl(1%, 2%, 3%, 4%)\"\n\t\t\t\tif args[1].Kind == css_lexer.TComma && args[3].Kind == css_lexer.TComma && args[5].Kind == css_lexer.TComma {\n\t\t\t\t\th, s, l, a = args[0], args[2], args[4], args[6]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// HSL => RGB\n\t\t\tif h, ok := degreesForAngle(h); ok {\n\t\t\t\tif s, ok := s.ClampedFractionForPercentage(); ok {\n\t\t\t\t\tif l, ok := l.ClampedFractionForPercentage(); ok {\n\t\t\t\t\t\tif a, ok := parseAlphaByte(a); ok {\n\t\t\t\t\t\t\tr, g, b := hslToRgb(helpers.NewF64(h), helpers.NewF64(s), helpers.NewF64(l))\n\t\t\t\t\t\t\treturn parsedColor{hex: packRGBA(r, g, b, a)}, true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase \"hwb\":\n\t\t\targs := *token.Children\n\t\t\tvar h, s, l, a css_ast.Token\n\n\t\t\tswitch len(args) {\n\t\t\tcase 3:\n\t\t\t\t// \"hwb(1 2 3)\"\n\t\t\t\th, s, l = args[0], args[1], args[2]\n\n\t\t\tcase 5:\n\t\t\t\t// \"hwb(1 2 3 / 4%)\"\n\t\t\t\tif args[3].Kind == css_lexer.TDelimSlash {\n\t\t\t\t\th, s, l, a = args[0], args[1], args[2], args[4]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// HWB => RGB\n\t\t\tif h, ok := degreesForAngle(h); ok {\n\t\t\t\tif white, ok := s.ClampedFractionForPercentage(); ok {\n\t\t\t\t\tif black, ok := l.ClampedFractionForPercentage(); ok {\n\t\t\t\t\t\tif a, ok := parseAlphaByte(a); ok {\n\t\t\t\t\t\t\tr, g, b := hwbToRgb(helpers.NewF64(h), helpers.NewF64(white), helpers.NewF64(black))\n\t\t\t\t\t\t\treturn parsedColor{hex: packRGBA(r, g, b, a)}, true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase \"color\":\n\t\t\targs := *token.Children\n\t\t\tvar colorSpace, alpha css_ast.Token\n\n\t\t\tswitch len(args) {\n\t\t\tcase 4:\n\t\t\t\t// \"color(xyz 1 2 3)\"\n\t\t\t\tcolorSpace = args[0]\n\n\t\t\tcase 6:\n\t\t\t\t// \"color(xyz 1 2 3 / 50%)\"\n\t\t\t\tif args[4].Kind == css_lexer.TDelimSlash {\n\t\t\t\t\tcolorSpace, alpha = args[0], args[5]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif colorSpace.Kind == css_lexer.TIdent {\n\t\t\t\tif v0, ok := args[1].NumberOrFractionForPercentage(1, 0); ok {\n\t\t\t\t\tif v1, ok := args[2].NumberOrFractionForPercentage(1, 0); ok {\n\t\t\t\t\t\tif v2, ok := args[3].NumberOrFractionForPercentage(1, 0); ok {\n\t\t\t\t\t\t\tif a, ok := parseAlphaByte(alpha); ok {\n\t\t\t\t\t\t\t\tv0, v1, v2 := helpers.NewF64(v0), helpers.NewF64(v1), helpers.NewF64(v2)\n\t\t\t\t\t\t\t\tswitch strings.ToLower(colorSpace.Text) {\n\t\t\t\t\t\t\t\tcase \"a98-rgb\":\n\t\t\t\t\t\t\t\t\tr, g, b := lin_a98rgb(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z := lin_a98rgb_to_xyz(r, g, b)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: a}, true\n\n\t\t\t\t\t\t\t\tcase \"display-p3\":\n\t\t\t\t\t\t\t\t\tr, g, b := lin_p3(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z := lin_p3_to_xyz(r, g, b)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: a}, true\n\n\t\t\t\t\t\t\t\tcase \"prophoto-rgb\":\n\t\t\t\t\t\t\t\t\tr, g, b := lin_prophoto(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z := lin_prophoto_to_xyz(r, g, b)\n\t\t\t\t\t\t\t\t\tx, y, z = d50_to_d65(x, y, z)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: a}, true\n\n\t\t\t\t\t\t\t\tcase \"rec2020\":\n\t\t\t\t\t\t\t\t\tr, g, b := lin_2020(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z := lin_2020_to_xyz(r, g, b)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: a}, true\n\n\t\t\t\t\t\t\t\tcase \"srgb\":\n\t\t\t\t\t\t\t\t\tr, g, b := lin_srgb(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z := lin_srgb_to_xyz(r, g, b)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: a}, true\n\n\t\t\t\t\t\t\t\tcase \"srgb-linear\":\n\t\t\t\t\t\t\t\t\tx, y, z := lin_srgb_to_xyz(v0, v1, v2)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: a}, true\n\n\t\t\t\t\t\t\t\tcase \"xyz\", \"xyz-d65\":\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: v0, y: v1, z: v2, hex: a}, true\n\n\t\t\t\t\t\t\t\tcase \"xyz-d50\":\n\t\t\t\t\t\t\t\t\tx, y, z := d50_to_d65(v0, v1, v2)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: a}, true\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase \"lab\", \"lch\", \"oklab\", \"oklch\":\n\t\t\targs := *token.Children\n\t\t\tvar v0, v1, v2, alpha css_ast.Token\n\n\t\t\tswitch len(args) {\n\t\t\tcase 3:\n\t\t\t\t// \"lab(1 2 3)\"\n\t\t\t\tv0, v1, v2 = args[0], args[1], args[2]\n\n\t\t\tcase 5:\n\t\t\t\t// \"lab(1 2 3 / 50%)\"\n\t\t\t\tif args[3].Kind == css_lexer.TDelimSlash {\n\t\t\t\t\tv0, v1, v2, alpha = args[0], args[1], args[2], args[4]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif v0.Kind != css_lexer.T(0) {\n\t\t\t\tif alpha, ok := parseAlphaByte(alpha); ok {\n\t\t\t\t\tswitch lowerText {\n\t\t\t\t\tcase \"lab\":\n\t\t\t\t\t\tif v0, ok := v0.NumberOrFractionForPercentage(100, 0); ok {\n\t\t\t\t\t\t\tif v1, ok := v1.NumberOrFractionForPercentage(125, css_ast.AllowAnyPercentage); ok {\n\t\t\t\t\t\t\t\tif v2, ok := v2.NumberOrFractionForPercentage(125, css_ast.AllowAnyPercentage); ok {\n\t\t\t\t\t\t\t\t\tv0, v1, v2 := helpers.NewF64(v0), helpers.NewF64(v1), helpers.NewF64(v2)\n\t\t\t\t\t\t\t\t\tx, y, z := lab_to_xyz(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z = d50_to_d65(x, y, z)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: alpha}, true\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase \"lch\":\n\t\t\t\t\t\tif v0, ok := v0.NumberOrFractionForPercentage(100, 0); ok {\n\t\t\t\t\t\t\tif v1, ok := v1.NumberOrFractionForPercentage(125, css_ast.AllowPercentageAbove100); ok {\n\t\t\t\t\t\t\t\tif v2, ok := degreesForAngle(v2); ok {\n\t\t\t\t\t\t\t\t\tv0, v1, v2 := helpers.NewF64(v0), helpers.NewF64(v1), helpers.NewF64(v2)\n\t\t\t\t\t\t\t\t\tl, a, b := lch_to_lab(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z := lab_to_xyz(l, a, b)\n\t\t\t\t\t\t\t\t\tx, y, z = d50_to_d65(x, y, z)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: alpha}, true\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase \"oklab\":\n\t\t\t\t\t\tif v0, ok := v0.NumberOrFractionForPercentage(1, 0); ok {\n\t\t\t\t\t\t\tif v1, ok := v1.NumberOrFractionForPercentage(0.4, css_ast.AllowAnyPercentage); ok {\n\t\t\t\t\t\t\t\tif v2, ok := v2.NumberOrFractionForPercentage(0.4, css_ast.AllowAnyPercentage); ok {\n\t\t\t\t\t\t\t\t\tv0, v1, v2 := helpers.NewF64(v0), helpers.NewF64(v1), helpers.NewF64(v2)\n\t\t\t\t\t\t\t\t\tx, y, z := oklab_to_xyz(v0, v1, v2)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: alpha}, true\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase \"oklch\":\n\t\t\t\t\t\tif v0, ok := v0.NumberOrFractionForPercentage(1, 0); ok {\n\t\t\t\t\t\t\tif v1, ok := v1.NumberOrFractionForPercentage(0.4, css_ast.AllowPercentageAbove100); ok {\n\t\t\t\t\t\t\t\tif v2, ok := degreesForAngle(v2); ok {\n\t\t\t\t\t\t\t\t\tv0, v1, v2 := helpers.NewF64(v0), helpers.NewF64(v1), helpers.NewF64(v2)\n\t\t\t\t\t\t\t\t\tl, a, b := oklch_to_oklab(v0, v1, v2)\n\t\t\t\t\t\t\t\t\tx, y, z := oklab_to_xyz(l, a, b)\n\t\t\t\t\t\t\t\t\treturn parsedColor{hasColorSpace: true, x: x, y: y, z: z, hex: alpha}, true\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn parsedColor{}, false\n}\n\n// Reference: https://drafts.csswg.org/css-color/#hwb-to-rgb\nfunc hwbToRgb(hue F64, white F64, black F64) (r F64, g F64, b F64) {\n\tif white.Add(black).Value() >= 1 {\n\t\tgray := white.Div(white.Add(black))\n\t\treturn gray, gray, gray\n\t}\n\tdelta := white.Add(black).Neg().AddConst(1)\n\tr, g, b = hslToRgb(hue, helpers.NewF64(1), helpers.NewF64(0.5))\n\tr = delta.Mul(r).Add(white)\n\tg = delta.Mul(g).Add(white)\n\tb = delta.Mul(b).Add(white)\n\treturn\n}\n\n// Reference https://drafts.csswg.org/css-color/#hsl-to-rgb\nfunc hslToRgb(hue F64, sat F64, light F64) (r F64, g F64, b F64) {\n\thue = hue.DivConst(360.0)\n\tvar t2 F64\n\tif light.Value() <= 0.5 {\n\t\tt2 = sat.AddConst(1).Mul(light)\n\t} else {\n\t\tt2 = light.Add(sat).Sub(light.Mul(sat))\n\t}\n\tt1 := light.MulConst(2).Sub(t2)\n\tr = hueToRgb(t1, t2, hue.AddConst(1.0/3.0))\n\tg = hueToRgb(t1, t2, hue)\n\tb = hueToRgb(t1, t2, hue.SubConst(1.0/3.0))\n\treturn\n}\n\nfunc hueToRgb(t1 F64, t2 F64, hue F64) F64 {\n\thue = hue.Sub(hue.Floor())\n\thue = hue.MulConst(6)\n\tvar f F64\n\tif hue.Value() < 1 {\n\t\tf = helpers.Lerp(t1, t2, hue)\n\t} else if hue.Value() < 3 {\n\t\tf = t2\n\t} else if hue.Value() < 4 {\n\t\tf = helpers.Lerp(t1, t2, hue.Neg().AddConst(4))\n\t} else {\n\t\tf = t1\n\t}\n\treturn f\n}\n\nfunc packRGBA(rf F64, gf F64, bf F64, a uint32) uint32 {\n\tr := floatToByte(rf.Value())\n\tg := floatToByte(gf.Value())\n\tb := floatToByte(bf.Value())\n\treturn (r << 24) | (g << 16) | (b << 8) | a\n}\n\nfunc floatToByte(f float64) uint32 {\n\ti := int(math.Round(f * 255))\n\tif i < 0 {\n\t\ti = 0\n\t} else if i > 255 {\n\t\ti = 255\n\t}\n\treturn uint32(i)\n}\n\nfunc parseAlphaByte(token css_ast.Token) (uint32, bool) {\n\tif token.Kind == css_lexer.T(0) {\n\t\treturn 255, true\n\t}\n\treturn parseColorByte(token, 255)\n}\n\nfunc parseColorByte(token css_ast.Token, scale float64) (uint32, bool) {\n\tvar i int\n\tvar ok bool\n\n\tswitch token.Kind {\n\tcase css_lexer.TNumber:\n\t\tif f, err := strconv.ParseFloat(token.Text, 64); err == nil {\n\t\t\ti = int(math.Round(f * scale))\n\t\t\tok = true\n\t\t}\n\n\tcase css_lexer.TPercentage:\n\t\tif f, err := strconv.ParseFloat(token.PercentageValue(), 64); err == nil {\n\t\t\ti = int(math.Round(f * (255.0 / 100.0)))\n\t\t\tok = true\n\t\t}\n\t}\n\n\tif i < 0 {\n\t\ti = 0\n\t} else if i > 255 {\n\t\ti = 255\n\t}\n\treturn uint32(i), ok\n}\n\nfunc tryToConvertToHexWithoutClipping(x F64, y F64, z F64, a uint32) (uint32, bool) {\n\tr, g, b := gam_srgb(xyz_to_lin_srgb(x, y, z))\n\tif r.Value() < -0.5/255 || r.Value() > 255.5/255 ||\n\t\tg.Value() < -0.5/255 || g.Value() > 255.5/255 ||\n\t\tb.Value() < -0.5/255 || b.Value() > 255.5/255 {\n\t\treturn 0, false\n\t}\n\treturn packRGBA(r, g, b, a), true\n}\n\nfunc (p *parser) tryToGenerateColor(token css_ast.Token, color parsedColor, wouldClipColor *bool) css_ast.Token {\n\t// Note: Do NOT remove color information from fully transparent colors.\n\t// Safari behaves differently than other browsers for color interpolation:\n\t// https://css-tricks.com/thing-know-gradients-transparent-black/\n\n\t// Attempt to convert other color spaces to sRGB, and only continue if the\n\t// result (rounded to the nearest byte) will be in the 0-to-1 sRGB range\n\tvar hex uint32\n\tif !color.hasColorSpace {\n\t\thex = color.hex\n\t} else if result, ok := tryToConvertToHexWithoutClipping(color.x, color.y, color.z, color.hex); ok {\n\t\thex = result\n\t} else if wouldClipColor != nil {\n\t\t*wouldClipColor = true\n\t\treturn token\n\t} else {\n\t\tr, g, b := gamut_mapping_xyz_to_srgb(color.x, color.y, color.z)\n\t\thex = packRGBA(r, g, b, color.hex)\n\t}\n\n\tif hexA(hex) == 255 {\n\t\ttoken.Children = nil\n\t\tif name, ok := shortColorName[hex]; ok && p.options.minifySyntax {\n\t\t\ttoken.Kind = css_lexer.TIdent\n\t\t\ttoken.Text = name\n\t\t} else {\n\t\t\ttoken.Kind = css_lexer.THash\n\t\t\thex >>= 8\n\t\t\tcompact := compactHex(hex)\n\t\t\tif p.options.minifySyntax && hex == expandHex(compact) {\n\t\t\t\ttoken.Text = fmt.Sprintf(\"%03x\", compact)\n\t\t\t} else {\n\t\t\t\ttoken.Text = fmt.Sprintf(\"%06x\", hex)\n\t\t\t}\n\t\t}\n\t} else if !p.options.unsupportedCSSFeatures.Has(compat.HexRGBA) {\n\t\ttoken.Children = nil\n\t\ttoken.Kind = css_lexer.THash\n\t\tcompact := compactHex(hex)\n\t\tif p.options.minifySyntax && hex == expandHex(compact) {\n\t\t\ttoken.Text = fmt.Sprintf(\"%04x\", compact)\n\t\t} else {\n\t\t\ttoken.Text = fmt.Sprintf(\"%08x\", hex)\n\t\t}\n\t} else {\n\t\ttoken.Kind = css_lexer.TFunction\n\t\ttoken.Text = \"rgba\"\n\t\tcommaToken := p.commaToken(token.Loc)\n\t\tindex := hexA(hex) * 4\n\t\talpha := alphaFractionTable[index : index+4]\n\t\tif space := strings.IndexByte(alpha, ' '); space != -1 {\n\t\t\talpha = alpha[:space]\n\t\t}\n\t\ttoken.Children = &[]css_ast.Token{\n\t\t\t{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexR(hex))}, commaToken,\n\t\t\t{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexG(hex))}, commaToken,\n\t\t\t{Loc: token.Loc, Kind: css_lexer.TNumber, Text: strconv.Itoa(hexB(hex))}, commaToken,\n\t\t\t{Loc: token.Loc, Kind: css_lexer.TNumber, Text: alpha},\n\t\t}\n\t}\n\n\treturn token\n}\n\n// Every four characters in this table is the fraction for that index\nconst alphaFractionTable string = \"\" +\n\t\"0   .004.008.01 .016.02 .024.027.03 .035.04 .043.047.05 .055.06 \" +\n\t\".063.067.07 .075.08 .082.086.09 .094.098.1  .106.11 .114.118.12 \" +\n\t\".125.13 .133.137.14 .145.15 .153.157.16 .165.17 .173.176.18 .184\" +\n\t\".19 .192.196.2  .204.208.21 .216.22 .224.227.23 .235.24 .243.247\" +\n\t\".25 .255.26 .263.267.27 .275.28 .282.286.29 .294.298.3  .306.31 \" +\n\t\".314.318.32 .325.33 .333.337.34 .345.35 .353.357.36 .365.37 .373\" +\n\t\".376.38 .384.39 .392.396.4  .404.408.41 .416.42 .424.427.43 .435\" +\n\t\".44 .443.447.45 .455.46 .463.467.47 .475.48 .482.486.49 .494.498\" +\n\t\".5  .506.51 .514.518.52 .525.53 .533.537.54 .545.55 .553.557.56 \" +\n\t\".565.57 .573.576.58 .584.59 .592.596.6  .604.608.61 .616.62 .624\" +\n\t\".627.63 .635.64 .643.647.65 .655.66 .663.667.67 .675.68 .682.686\" +\n\t\".69 .694.698.7  .706.71 .714.718.72 .725.73 .733.737.74 .745.75 \" +\n\t\".753.757.76 .765.77 .773.776.78 .784.79 .792.796.8  .804.808.81 \" +\n\t\".816.82 .824.827.83 .835.84 .843.847.85 .855.86 .863.867.87 .875\" +\n\t\".88 .882.886.89 .894.898.9  .906.91 .914.918.92 .925.93 .933.937\" +\n\t\".94 .945.95 .953.957.96 .965.97 .973.976.98 .984.99 .992.9961   \"\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_composes.go",
    "content": "package css_parser\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\ntype composesContext struct {\n\tparentRefs   []ast.Ref\n\tparentRange  logger.Range\n\tproblemRange logger.Range\n}\n\nfunc (p *parser) handleComposesPragma(context composesContext, tokens []css_ast.Token) {\n\ttype nameWithLoc struct {\n\t\tloc  logger.Loc\n\t\ttext string\n\t}\n\tvar names []nameWithLoc\n\tfromGlobal := false\n\n\tfor i, t := range tokens {\n\t\tif t.Kind == css_lexer.TIdent {\n\t\t\t// Check for a \"from\" clause at the end\n\t\t\tif strings.EqualFold(t.Text, \"from\") && i+2 == len(tokens) {\n\t\t\t\tlast := tokens[i+1]\n\n\t\t\t\t// A string or a URL is an external file\n\t\t\t\tif last.Kind == css_lexer.TString || last.Kind == css_lexer.TURL {\n\t\t\t\t\tvar importRecordIndex uint32\n\t\t\t\t\tif last.Kind == css_lexer.TString {\n\t\t\t\t\t\timportRecordIndex = uint32(len(p.importRecords))\n\t\t\t\t\t\tp.importRecords = append(p.importRecords, ast.ImportRecord{\n\t\t\t\t\t\t\tKind:  ast.ImportComposesFrom,\n\t\t\t\t\t\t\tPath:  logger.Path{Text: last.Text},\n\t\t\t\t\t\t\tRange: p.source.RangeOfString(last.Loc),\n\t\t\t\t\t\t})\n\t\t\t\t\t} else {\n\t\t\t\t\t\timportRecordIndex = last.PayloadIndex\n\t\t\t\t\t\tp.importRecords[importRecordIndex].Kind = ast.ImportComposesFrom\n\t\t\t\t\t}\n\t\t\t\t\tfor _, parentRef := range context.parentRefs {\n\t\t\t\t\t\tcomposes := p.composes[parentRef]\n\t\t\t\t\t\tfor _, name := range names {\n\t\t\t\t\t\t\tcomposes.ImportedNames = append(composes.ImportedNames, css_ast.ImportedComposesName{\n\t\t\t\t\t\t\t\tImportRecordIndex: importRecordIndex,\n\t\t\t\t\t\t\t\tAlias:             name.text,\n\t\t\t\t\t\t\t\tAliasLoc:          name.loc,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t// An identifier must be \"global\"\n\t\t\t\tif last.Kind == css_lexer.TIdent {\n\t\t\t\t\tif strings.EqualFold(last.Text, \"global\") {\n\t\t\t\t\t\tfromGlobal = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\tp.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, css_lexer.RangeOfIdentifier(p.source, last.Loc),\n\t\t\t\t\t\tfmt.Sprintf(\"\\\"composes\\\" declaration uses invalid location %q\", last.Text))\n\t\t\t\t\tp.prevError = t.Loc\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnames = append(names, nameWithLoc{t.Loc, t.Text})\n\t\t\tcontinue\n\t\t}\n\n\t\t// Any unexpected tokens are a syntax error\n\t\tvar text string\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TURL, css_lexer.TBadURL, css_lexer.TString, css_lexer.TUnterminatedString:\n\t\t\ttext = fmt.Sprintf(\"Unexpected %s\", t.Kind.String())\n\t\tdefault:\n\t\t\ttext = fmt.Sprintf(\"Unexpected %q\", t.Text)\n\t\t}\n\t\tp.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, logger.Range{Loc: t.Loc}, text)\n\t\tp.prevError = t.Loc\n\t\treturn\n\t}\n\n\t// If we get here, all of these names are not references to another file\n\told := p.makeLocalSymbols\n\tif fromGlobal {\n\t\tp.makeLocalSymbols = false\n\t}\n\tfor _, parentRef := range context.parentRefs {\n\t\tcomposes := p.composes[parentRef]\n\t\tfor _, name := range names {\n\t\t\tcomposes.Names = append(composes.Names, p.symbolForName(name.loc, name.text))\n\t\t}\n\t}\n\tp.makeLocalSymbols = old\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_container.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\n// Scan for container names in the \"container\" shorthand property\nfunc (p *parser) processContainerShorthand(tokens []css_ast.Token) {\n\t// Validate the syntax\n\tfor i, t := range tokens {\n\t\tif t.Kind == css_lexer.TIdent {\n\t\t\tcontinue\n\t\t}\n\t\tif t.Kind == css_lexer.TDelimSlash && i+2 == len(tokens) && tokens[i+1].Kind == css_lexer.TIdent {\n\t\t\tbreak\n\t\t}\n\t\treturn\n\t}\n\n\t// Convert any local names\n\tfor i, t := range tokens {\n\t\tif t.Kind != css_lexer.TIdent {\n\t\t\tbreak\n\t\t}\n\t\tp.handleSingleContainerName(&tokens[i])\n\t}\n}\n\nfunc (p *parser) processContainerName(tokens []css_ast.Token) {\n\t// Validate the syntax\n\tfor _, t := range tokens {\n\t\tif t.Kind != css_lexer.TIdent {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Convert any local names\n\tfor i := range tokens {\n\t\tp.handleSingleContainerName(&tokens[i])\n\t}\n}\n\nfunc (p *parser) handleSingleContainerName(token *css_ast.Token) {\n\tif lower := strings.ToLower(token.Text); lower == \"none\" || cssWideAndReservedKeywords[lower] {\n\t\treturn\n\t}\n\n\ttoken.Kind = css_lexer.TSymbol\n\ttoken.PayloadIndex = p.symbolForName(token.Loc, token.Text).Ref.InnerIndex\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_font.go",
    "content": "package css_parser\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\n// Specification: https://drafts.csswg.org/css-fonts/#font-prop\n// [ <font-style> || <font-variant-css2> || <font-weight> || <font-stretch-css3> ]? <font-size> [ / <line-height> ]? <font-family>\nfunc (p *parser) mangleFont(tokens []css_ast.Token) []css_ast.Token {\n\tvar result []css_ast.Token\n\n\t// Scan up to the font size\n\tpos := 0\n\tfor ; pos < len(tokens); pos++ {\n\t\ttoken := tokens[pos]\n\t\tif isFontSize(token) {\n\t\t\tbreak\n\t\t}\n\n\t\tswitch token.Kind {\n\t\tcase css_lexer.TIdent:\n\t\t\tswitch strings.ToLower(token.Text) {\n\t\t\tcase \"normal\":\n\t\t\t\t// \"All subproperties of the font property are first reset to their initial values\"\n\t\t\t\t// This implies that \"normal\" doesn't do anything. Also all of the optional values\n\t\t\t\t// contain \"normal\" as an option and they are unordered so it's impossible to say\n\t\t\t\t// what property \"normal\" corresponds to. Just drop these tokens to save space.\n\t\t\t\tcontinue\n\n\t\t\t// <font-style>\n\t\t\tcase \"italic\":\n\t\t\tcase \"oblique\":\n\t\t\t\tif pos+1 < len(tokens) && tokens[pos+1].IsAngle() {\n\t\t\t\t\tresult = append(result, token, tokens[pos+1])\n\t\t\t\t\tpos++\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t// <font-variant-css2>\n\t\t\tcase \"small-caps\":\n\n\t\t\t// <font-weight>\n\t\t\tcase \"bold\", \"bolder\", \"lighter\":\n\t\t\t\tresult = append(result, p.mangleFontWeight(token))\n\t\t\t\tcontinue\n\n\t\t\t// <font-stretch-css3>\n\t\t\tcase \"ultra-condensed\", \"extra-condensed\", \"condensed\", \"semi-condensed\",\n\t\t\t\t\"semi-expanded\", \"expanded\", \"extra-expanded\", \"ultra-expanded\":\n\n\t\t\tdefault:\n\t\t\t\t// All other tokens are unrecognized, so we bail if we hit one\n\t\t\t\treturn tokens\n\t\t\t}\n\t\t\tresult = append(result, token)\n\n\t\tcase css_lexer.TNumber:\n\t\t\t// \"Only values greater than or equal to 1, and less than or equal to\n\t\t\t// 1000, are valid, and all other values are invalid.\"\n\t\t\tif value, err := strconv.ParseFloat(token.Text, 64); err != nil || value < 1 || value > 1000 {\n\t\t\t\treturn tokens\n\t\t\t}\n\t\t\tresult = append(result, token)\n\n\t\tdefault:\n\t\t\t// All other tokens are unrecognized, so we bail if we hit one\n\t\t\treturn tokens\n\t\t}\n\t}\n\n\t// <font-size>\n\tif pos == len(tokens) {\n\t\treturn tokens\n\t}\n\tresult = append(result, tokens[pos])\n\tpos++\n\n\t// / <line-height>\n\tif pos < len(tokens) && tokens[pos].Kind == css_lexer.TDelimSlash {\n\t\tif pos+1 == len(tokens) {\n\t\t\treturn tokens\n\t\t}\n\t\tresult = append(result, tokens[pos], tokens[pos+1])\n\t\tpos += 2\n\n\t\t// Remove the whitespace around the \"/\" character\n\t\tif p.options.minifyWhitespace {\n\t\t\tresult[len(result)-3].Whitespace &= ^css_ast.WhitespaceAfter\n\t\t\tresult[len(result)-2].Whitespace = 0\n\t\t\tresult[len(result)-1].Whitespace &= ^css_ast.WhitespaceBefore\n\t\t}\n\t}\n\n\t// <font-family>\n\tif family, ok := p.mangleFontFamily(tokens[pos:]); ok {\n\t\tif len(result) > 0 && len(family) > 0 && family[0].Kind != css_lexer.TString {\n\t\t\tfamily[0].Whitespace |= css_ast.WhitespaceBefore\n\t\t}\n\t\treturn append(result, family...)\n\t}\n\treturn tokens\n}\n\nvar fontSizeKeywords = map[string]bool{\n\t// <absolute-size>: https://drafts.csswg.org/css-fonts/#valdef-font-size-absolute-size\n\t\"xx-small\":  true,\n\t\"x-small\":   true,\n\t\"small\":     true,\n\t\"medium\":    true,\n\t\"large\":     true,\n\t\"x-large\":   true,\n\t\"xx-large\":  true,\n\t\"xxx-large\": true,\n\n\t// <relative-size>: https://drafts.csswg.org/css-fonts/#valdef-font-size-relative-size\n\t\"larger\":  true,\n\t\"smaller\": true,\n}\n\n// Specification: https://drafts.csswg.org/css-fonts/#font-size-prop\nfunc isFontSize(token css_ast.Token) bool {\n\t// <length-percentage>\n\tif token.Kind == css_lexer.TDimension || token.Kind == css_lexer.TPercentage {\n\t\treturn true\n\t}\n\n\t// <absolute-size> or <relative-size>\n\tif token.Kind == css_lexer.TIdent {\n\t\t_, ok := fontSizeKeywords[strings.ToLower(token.Text)]\n\t\treturn ok\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_font_family.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\n// These keywords usually require special handling when parsing.\n\n// Declaring a property to have these values explicitly specifies a particular\n// defaulting behavior instead of setting the property to that identifier value.\n// As specified in CSS Values and Units Level 3, all CSS properties can accept\n// these values.\n//\n// For example, \"font-family: 'inherit'\" sets the font family to the font named\n// \"inherit\" while \"font-family: inherit\" sets the font family to the inherited\n// value.\n//\n// Note that other CSS specifications can define additional CSS-wide keywords,\n// which we should copy here whenever new ones are created so we can quote those\n// identifiers to avoid collisions with any newly-created CSS-wide keywords.\nvar cssWideAndReservedKeywords = map[string]bool{\n\t// CSS Values and Units Level 3: https://drafts.csswg.org/css-values-3/#common-keywords\n\t\"initial\": true, // CSS-wide keyword\n\t\"inherit\": true, // CSS-wide keyword\n\t\"unset\":   true, // CSS-wide keyword\n\t\"default\": true, // CSS reserved keyword\n\n\t// CSS Cascading and Inheritance Level 5: https://drafts.csswg.org/css-cascade-5/#defaulting-keywords\n\t\"revert\":       true, // Cascade-dependent keyword\n\t\"revert-layer\": true, // Cascade-dependent keyword\n}\n\n// Font family names that happen to be the same as a keyword value must be\n// quoted to prevent confusion with the keywords with the same names. UAs must\n// not consider these keywords as matching the <family-name> type.\n// Specification: https://drafts.csswg.org/css-fonts/#generic-font-families\nvar genericFamilyNames = map[string]bool{\n\t\"serif\":         true,\n\t\"sans-serif\":    true,\n\t\"cursive\":       true,\n\t\"fantasy\":       true,\n\t\"monospace\":     true,\n\t\"system-ui\":     true,\n\t\"emoji\":         true,\n\t\"math\":          true,\n\t\"fangsong\":      true,\n\t\"ui-serif\":      true,\n\t\"ui-sans-serif\": true,\n\t\"ui-monospace\":  true,\n\t\"ui-rounded\":    true,\n}\n\n// Specification: https://drafts.csswg.org/css-fonts/#font-family-prop\nfunc (p *parser) mangleFontFamily(tokens []css_ast.Token) ([]css_ast.Token, bool) {\n\tresult, rest, ok := p.mangleFamilyNameOrGenericName(nil, tokens)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tfor len(rest) > 0 && rest[0].Kind == css_lexer.TComma {\n\t\tresult, rest, ok = p.mangleFamilyNameOrGenericName(append(result, rest[0]), rest[1:])\n\t\tif !ok {\n\t\t\treturn nil, false\n\t\t}\n\t}\n\n\tif len(rest) > 0 {\n\t\treturn nil, false\n\t}\n\n\treturn result, true\n}\n\nfunc (p *parser) mangleFamilyNameOrGenericName(result []css_ast.Token, tokens []css_ast.Token) ([]css_ast.Token, []css_ast.Token, bool) {\n\tif len(tokens) > 0 {\n\t\tt := tokens[0]\n\n\t\t// Handle <generic-family>\n\t\tif t.Kind == css_lexer.TIdent && genericFamilyNames[t.Text] {\n\t\t\treturn append(result, t), tokens[1:], true\n\t\t}\n\n\t\t// Handle <family-name>\n\t\tif t.Kind == css_lexer.TString {\n\t\t\t// \"If a sequence of identifiers is given as a <family-name>, the computed\n\t\t\t// value is the name converted to a string by joining all the identifiers\n\t\t\t// in the sequence by single spaces.\"\n\t\t\t//\n\t\t\t// More information: https://mathiasbynens.be/notes/unquoted-font-family\n\t\t\tnames := strings.Split(t.Text, \" \")\n\t\t\tfor _, name := range names {\n\t\t\t\tif !isValidCustomIdent(name, genericFamilyNames) {\n\t\t\t\t\treturn append(result, t), tokens[1:], true\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor i, name := range names {\n\t\t\t\tvar whitespace css_ast.WhitespaceFlags\n\t\t\t\tif i != 0 || !p.options.minifyWhitespace {\n\t\t\t\t\twhitespace = css_ast.WhitespaceBefore\n\t\t\t\t}\n\t\t\t\tresult = append(result, css_ast.Token{\n\t\t\t\t\tLoc:        t.Loc,\n\t\t\t\t\tKind:       css_lexer.TIdent,\n\t\t\t\t\tText:       name,\n\t\t\t\t\tWhitespace: whitespace,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn result, tokens[1:], true\n\t\t}\n\n\t\t// \"Font family names other than generic families must either be given\n\t\t// quoted as <string>s, or unquoted as a sequence of one or more\n\t\t// <custom-ident>.\"\n\t\tif t.Kind == css_lexer.TIdent {\n\t\t\tfor {\n\t\t\t\tif !isValidCustomIdent(t.Text, genericFamilyNames) {\n\t\t\t\t\treturn nil, nil, false\n\t\t\t\t}\n\t\t\t\tresult = append(result, t)\n\t\t\t\ttokens = tokens[1:]\n\t\t\t\tif len(tokens) == 0 || tokens[0].Kind != css_lexer.TIdent {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tt = tokens[0]\n\t\t\t}\n\t\t\treturn result, tokens, true\n\t\t}\n\t}\n\n\t// Anything other than the cases listed above causes us to bail\n\treturn nil, nil, false\n}\n\n// Specification: https://drafts.csswg.org/css-values-4/#custom-idents\nfunc isValidCustomIdent(text string, predefinedKeywords map[string]bool) bool {\n\tloweredText := strings.ToLower(text)\n\n\tif predefinedKeywords[loweredText] {\n\t\treturn false\n\t}\n\tif cssWideAndReservedKeywords[loweredText] {\n\t\treturn false\n\t}\n\tif loweredText == \"\" {\n\t\treturn false\n\t}\n\n\t// validate if it contains characters which needs to be escaped\n\tif !css_lexer.WouldStartIdentifierWithoutEscapes(text) {\n\t\treturn false\n\t}\n\tfor _, c := range text {\n\t\tif !css_lexer.IsNameContinue(c) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_font_weight.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\nfunc (p *parser) mangleFontWeight(token css_ast.Token) css_ast.Token {\n\tif token.Kind != css_lexer.TIdent {\n\t\treturn token\n\t}\n\n\tswitch strings.ToLower(token.Text) {\n\tcase \"normal\":\n\t\ttoken.Text = \"400\"\n\t\ttoken.Kind = css_lexer.TNumber\n\tcase \"bold\":\n\t\ttoken.Text = \"700\"\n\t\ttoken.Kind = css_lexer.TNumber\n\t}\n\n\treturn token\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_gradient.go",
    "content": "package css_parser\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\ntype gradientKind uint8\n\nconst (\n\tlinearGradient gradientKind = iota\n\tradialGradient\n\tconicGradient\n)\n\ntype parsedGradient struct {\n\tleadingTokens []css_ast.Token\n\tcolorStops    []colorStop\n\tkind          gradientKind\n\trepeating     bool\n}\n\ntype colorStop struct {\n\tpositions []css_ast.Token\n\tcolor     css_ast.Token\n\tmidpoint  css_ast.Token // Absent if \"midpoint.Kind == css_lexer.T(0)\"\n}\n\nfunc parseGradient(token css_ast.Token) (gradient parsedGradient, success bool) {\n\tif token.Kind != css_lexer.TFunction {\n\t\treturn\n\t}\n\n\tswitch strings.ToLower(token.Text) {\n\tcase \"linear-gradient\":\n\t\tgradient.kind = linearGradient\n\n\tcase \"radial-gradient\":\n\t\tgradient.kind = radialGradient\n\n\tcase \"conic-gradient\":\n\t\tgradient.kind = conicGradient\n\n\tcase \"repeating-linear-gradient\":\n\t\tgradient.kind = linearGradient\n\t\tgradient.repeating = true\n\n\tcase \"repeating-radial-gradient\":\n\t\tgradient.kind = radialGradient\n\t\tgradient.repeating = true\n\n\tcase \"repeating-conic-gradient\":\n\t\tgradient.kind = conicGradient\n\t\tgradient.repeating = true\n\n\tdefault:\n\t\treturn\n\t}\n\n\t// Bail if any token is a \"var()\" since it may introduce commas\n\ttokens := *token.Children\n\tfor _, t := range tokens {\n\t\tif t.Kind == css_lexer.TFunction && strings.EqualFold(t.Text, \"var\") {\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Try to strip the initial tokens\n\tif len(tokens) > 0 && !looksLikeColor(tokens[0]) {\n\t\ti := 0\n\t\tfor i < len(tokens) && tokens[i].Kind != css_lexer.TComma {\n\t\t\ti++\n\t\t}\n\t\tgradient.leadingTokens = tokens[:i]\n\t\tif i < len(tokens) {\n\t\t\ttokens = tokens[i+1:]\n\t\t} else {\n\t\t\ttokens = nil\n\t\t}\n\t}\n\n\t// Try to parse the color stops\n\tfor len(tokens) > 0 {\n\t\t// Parse the color\n\t\tcolor := tokens[0]\n\t\tif !looksLikeColor(color) {\n\t\t\treturn\n\t\t}\n\t\ttokens = tokens[1:]\n\n\t\t// Parse up to two positions\n\t\tvar positions []css_ast.Token\n\t\tfor len(positions) < 2 && len(tokens) > 0 {\n\t\t\tposition := tokens[0]\n\t\t\tif position.Kind.IsNumeric() || (position.Kind == css_lexer.TFunction && strings.EqualFold(position.Text, \"calc\")) {\n\t\t\t\tpositions = append(positions, position)\n\t\t\t} else {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttokens = tokens[1:]\n\t\t}\n\n\t\t// Parse the comma\n\t\tvar midpoint css_ast.Token\n\t\tif len(tokens) > 0 {\n\t\t\tif tokens[0].Kind != css_lexer.TComma {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttokens = tokens[1:]\n\t\t\tif len(tokens) == 0 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Parse the midpoint, if any\n\t\t\tif len(tokens) > 0 && tokens[0].Kind.IsNumeric() {\n\t\t\t\tmidpoint = tokens[0]\n\t\t\t\ttokens = tokens[1:]\n\n\t\t\t\t// Followed by a mandatory comma\n\t\t\t\tif len(tokens) == 0 || tokens[0].Kind != css_lexer.TComma {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\ttokens = tokens[1:]\n\t\t\t}\n\t\t}\n\n\t\t// Add the color stop\n\t\tgradient.colorStops = append(gradient.colorStops, colorStop{\n\t\t\tcolor:     color,\n\t\t\tpositions: positions,\n\t\t\tmidpoint:  midpoint,\n\t\t})\n\t}\n\n\tsuccess = true\n\treturn\n}\n\nfunc (p *parser) generateGradient(token css_ast.Token, gradient parsedGradient) css_ast.Token {\n\tvar children []css_ast.Token\n\tcommaToken := p.commaToken(token.Loc)\n\n\tchildren = append(children, gradient.leadingTokens...)\n\tfor _, stop := range gradient.colorStops {\n\t\tif len(children) > 0 {\n\t\t\tchildren = append(children, commaToken)\n\t\t}\n\t\tif len(stop.positions) == 0 && stop.midpoint.Kind == css_lexer.T(0) {\n\t\t\tstop.color.Whitespace &= ^css_ast.WhitespaceAfter\n\t\t}\n\t\tchildren = append(children, stop.color)\n\t\tchildren = append(children, stop.positions...)\n\t\tif stop.midpoint.Kind != css_lexer.T(0) {\n\t\t\tchildren = append(children, commaToken, stop.midpoint)\n\t\t}\n\t}\n\n\ttoken.Children = &children\n\treturn token\n}\n\nfunc (p *parser) lowerAndMinifyGradient(token css_ast.Token, wouldClipColor *bool) css_ast.Token {\n\tgradient, ok := parseGradient(token)\n\tif !ok {\n\t\treturn token\n\t}\n\n\tlowerMidpoints := p.options.unsupportedCSSFeatures.Has(compat.GradientMidpoints)\n\tlowerColorSpaces := p.options.unsupportedCSSFeatures.Has(compat.ColorFunctions)\n\tlowerInterpolation := p.options.unsupportedCSSFeatures.Has(compat.GradientInterpolation)\n\n\t// Assume that if the browser doesn't support color spaces in gradients, then\n\t// it doesn't correctly interpolate non-sRGB colors even when a color space\n\t// is not specified. This is the case for Firefox 120, for example, which has\n\t// support for the \"color()\" syntax but not for color spaces in gradients.\n\t// There is no entry in our feature support matrix for this edge case so we\n\t// make this assumption instead.\n\t//\n\t// Note that this edge case means we have to _replace_ the original gradient\n\t// with the expanded one instead of inserting a fallback before it. Otherwise\n\t// Firefox 120 would use the original gradient instead of the fallback because\n\t// it supports the syntax, but just renders it incorrectly.\n\tif lowerInterpolation {\n\t\tlowerColorSpaces = true\n\t}\n\n\t// Potentially expand the gradient to handle unsupported features\n\tdidExpand := false\n\tif lowerMidpoints || lowerColorSpaces || lowerInterpolation {\n\t\tif colorStops, ok := tryToParseColorStops(gradient); ok {\n\t\t\thasColorSpace := false\n\t\t\thasMidpoint := false\n\t\t\tfor _, stop := range colorStops {\n\t\t\t\tif stop.hasColorSpace {\n\t\t\t\t\thasColorSpace = true\n\t\t\t\t}\n\t\t\t\tif stop.midpoint != nil {\n\t\t\t\t\thasMidpoint = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tremaining, colorSpace, hueMethod, hasInterpolation := removeColorInterpolation(gradient.leadingTokens)\n\t\t\tif (hasInterpolation && lowerInterpolation) || (hasColorSpace && lowerColorSpaces) || (hasMidpoint && lowerMidpoints) {\n\t\t\t\tif hasInterpolation {\n\t\t\t\t\ttryToExpandGradient(token.Loc, &gradient, colorStops, remaining, colorSpace, hueMethod)\n\t\t\t\t} else {\n\t\t\t\t\tif hasColorSpace {\n\t\t\t\t\t\tcolorSpace = colorSpace_oklab\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcolorSpace = colorSpace_srgb\n\t\t\t\t\t}\n\t\t\t\t\ttryToExpandGradient(token.Loc, &gradient, colorStops, gradient.leadingTokens, colorSpace, shorterHue)\n\t\t\t\t}\n\t\t\t\tdidExpand = true\n\t\t\t}\n\t\t}\n\t}\n\n\t// Lower all colors in the gradient stop\n\tfor i, stop := range gradient.colorStops {\n\t\tgradient.colorStops[i].color = p.lowerAndMinifyColor(stop.color, wouldClipColor)\n\t}\n\n\tif p.options.unsupportedCSSFeatures.Has(compat.GradientDoublePosition) {\n\t\t// Replace double positions with duplicated single positions\n\t\tfor _, stop := range gradient.colorStops {\n\t\t\tif len(stop.positions) > 1 {\n\t\t\t\tgradient.colorStops = switchToSinglePositions(gradient.colorStops)\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t} else if p.options.minifySyntax {\n\t\t// Replace duplicated single positions with double positions\n\t\tfor i, stop := range gradient.colorStops {\n\t\t\tif i > 0 && len(stop.positions) == 1 {\n\t\t\t\tif prev := gradient.colorStops[i-1]; len(prev.positions) == 1 && prev.midpoint.Kind == css_lexer.T(0) &&\n\t\t\t\t\tcss_ast.TokensEqual([]css_ast.Token{prev.color}, []css_ast.Token{stop.color}, nil) {\n\t\t\t\t\tgradient.colorStops = switchToDoublePositions(gradient.colorStops)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif p.options.minifySyntax || didExpand {\n\t\tgradient.colorStops = removeImpliedPositions(gradient.kind, gradient.colorStops)\n\t}\n\n\treturn p.generateGradient(token, gradient)\n}\n\nfunc removeImpliedPositions(kind gradientKind, colorStops []colorStop) []colorStop {\n\tif len(colorStops) == 0 {\n\t\treturn colorStops\n\t}\n\n\tpositions := make([]valueWithUnit, len(colorStops))\n\tfor i, stop := range colorStops {\n\t\tif len(stop.positions) == 1 {\n\t\t\tif pos, ok := tryToParseValue(stop.positions[0], kind); ok {\n\t\t\t\tpositions[i] = pos\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tpositions[i].value = helpers.NewF64(math.NaN())\n\t}\n\n\tstart := 0\n\tfor start < len(colorStops) {\n\t\tif startPos := positions[start]; !startPos.value.IsNaN() {\n\t\t\tend := start + 1\n\t\trun:\n\t\t\tfor colorStops[end-1].midpoint.Kind == css_lexer.T(0) && end < len(colorStops) {\n\t\t\t\tendPos := positions[end]\n\t\t\t\tif endPos.value.IsNaN() || endPos.unit != startPos.unit {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// Check that all values in this run are implied. Interpolation is done\n\t\t\t\t// using the start and end positions instead of the first and second\n\t\t\t\t// positions because it's more accurate.\n\t\t\t\tfor i := start + 1; i < end; i++ {\n\t\t\t\t\tt := helpers.NewF64(float64(i - start)).DivConst(float64(end - start))\n\t\t\t\t\timpliedValue := helpers.Lerp(startPos.value, endPos.value, t)\n\t\t\t\t\tif positions[i].value.Sub(impliedValue).Abs().Value() > 0.01 {\n\t\t\t\t\t\tbreak run\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tend++\n\t\t\t}\n\n\t\t\t// Clear out all implied values\n\t\t\tif end-start > 1 {\n\t\t\t\tfor i := start + 1; i+1 < end; i++ {\n\t\t\t\t\tcolorStops[i].positions = nil\n\t\t\t\t}\n\t\t\t\tstart = end - 1\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tstart++\n\t}\n\n\tif first := colorStops[0].positions; len(first) == 1 &&\n\t\t((first[0].Kind == css_lexer.TPercentage && first[0].PercentageValue() == \"0\") ||\n\t\t\t(first[0].Kind == css_lexer.TDimension && first[0].DimensionValue() == \"0\")) {\n\t\tcolorStops[0].positions = nil\n\t}\n\n\tif last := colorStops[len(colorStops)-1].positions; len(last) == 1 &&\n\t\tlast[0].Kind == css_lexer.TPercentage && last[0].PercentageValue() == \"100\" {\n\t\tcolorStops[len(colorStops)-1].positions = nil\n\t}\n\n\treturn colorStops\n}\n\nfunc switchToSinglePositions(double []colorStop) (single []colorStop) {\n\tfor _, stop := range double {\n\t\tfor i := range stop.positions {\n\t\t\tstop.positions[i].Whitespace = css_ast.WhitespaceBefore\n\t\t}\n\t\tfor len(stop.positions) > 1 {\n\t\t\tclone := stop\n\t\t\tclone.positions = stop.positions[:1]\n\t\t\tclone.midpoint = css_ast.Token{}\n\t\t\tsingle = append(single, clone)\n\t\t\tstop.positions = stop.positions[1:]\n\t\t}\n\t\tsingle = append(single, stop)\n\t}\n\treturn\n}\n\nfunc switchToDoublePositions(single []colorStop) (double []colorStop) {\n\tfor i := 0; i < len(single); i++ {\n\t\tstop := single[i]\n\t\tif i+1 < len(single) && len(stop.positions) == 1 && stop.midpoint.Kind == css_lexer.T(0) {\n\t\t\tif next := single[i+1]; len(next.positions) == 1 &&\n\t\t\t\tcss_ast.TokensEqual([]css_ast.Token{stop.color}, []css_ast.Token{next.color}, nil) {\n\t\t\t\tdouble = append(double, colorStop{\n\t\t\t\t\tcolor:     stop.color,\n\t\t\t\t\tpositions: []css_ast.Token{stop.positions[0], next.positions[0]},\n\t\t\t\t\tmidpoint:  next.midpoint,\n\t\t\t\t})\n\t\t\t\ti++\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tdouble = append(double, stop)\n\t}\n\treturn\n}\n\nfunc removeColorInterpolation(tokens []css_ast.Token) ([]css_ast.Token, colorSpace, hueMethod, bool) {\n\tfor i := 0; i+1 < len(tokens); i++ {\n\t\tif in := tokens[i]; in.Kind == css_lexer.TIdent && strings.EqualFold(in.Text, \"in\") {\n\t\t\tif space := tokens[i+1]; space.Kind == css_lexer.TIdent {\n\t\t\t\tvar colorSpace colorSpace\n\t\t\t\thueMethod := shorterHue\n\t\t\t\tstart := i\n\t\t\t\tend := i + 2\n\n\t\t\t\t// Parse the color space\n\t\t\t\tswitch strings.ToLower(space.Text) {\n\t\t\t\tcase \"a98-rgb\":\n\t\t\t\t\tcolorSpace = colorSpace_a98_rgb\n\t\t\t\tcase \"display-p3\":\n\t\t\t\t\tcolorSpace = colorSpace_display_p3\n\t\t\t\tcase \"hsl\":\n\t\t\t\t\tcolorSpace = colorSpace_hsl\n\t\t\t\tcase \"hwb\":\n\t\t\t\t\tcolorSpace = colorSpace_hwb\n\t\t\t\tcase \"lab\":\n\t\t\t\t\tcolorSpace = colorSpace_lab\n\t\t\t\tcase \"lch\":\n\t\t\t\t\tcolorSpace = colorSpace_lch\n\t\t\t\tcase \"oklab\":\n\t\t\t\t\tcolorSpace = colorSpace_oklab\n\t\t\t\tcase \"oklch\":\n\t\t\t\t\tcolorSpace = colorSpace_oklch\n\t\t\t\tcase \"prophoto-rgb\":\n\t\t\t\t\tcolorSpace = colorSpace_prophoto_rgb\n\t\t\t\tcase \"rec2020\":\n\t\t\t\t\tcolorSpace = colorSpace_rec2020\n\t\t\t\tcase \"srgb\":\n\t\t\t\t\tcolorSpace = colorSpace_srgb\n\t\t\t\tcase \"srgb-linear\":\n\t\t\t\t\tcolorSpace = colorSpace_srgb_linear\n\t\t\t\tcase \"xyz\":\n\t\t\t\t\tcolorSpace = colorSpace_xyz\n\t\t\t\tcase \"xyz-d50\":\n\t\t\t\t\tcolorSpace = colorSpace_xyz_d50\n\t\t\t\tcase \"xyz-d65\":\n\t\t\t\t\tcolorSpace = colorSpace_xyz_d65\n\t\t\t\tdefault:\n\t\t\t\t\treturn nil, 0, 0, false\n\t\t\t\t}\n\n\t\t\t\t// Parse the optional hue mode for polar color spaces\n\t\t\t\tif colorSpace.isPolar() && i+3 < len(tokens) {\n\t\t\t\t\tif hue := tokens[i+3]; hue.Kind == css_lexer.TIdent && strings.EqualFold(hue.Text, \"hue\") {\n\t\t\t\t\t\tif method := tokens[i+2]; method.Kind == css_lexer.TIdent {\n\t\t\t\t\t\t\tswitch strings.ToLower(method.Text) {\n\t\t\t\t\t\t\tcase \"shorter\":\n\t\t\t\t\t\t\t\thueMethod = shorterHue\n\t\t\t\t\t\t\tcase \"longer\":\n\t\t\t\t\t\t\t\thueMethod = longerHue\n\t\t\t\t\t\t\tcase \"increasing\":\n\t\t\t\t\t\t\t\thueMethod = increasingHue\n\t\t\t\t\t\t\tcase \"decreasing\":\n\t\t\t\t\t\t\t\thueMethod = decreasingHue\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\treturn nil, 0, 0, false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tend = i + 4\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Remove all parsed tokens\n\t\t\t\tremaining := append(append([]css_ast.Token{}, tokens[:start]...), tokens[end:]...)\n\t\t\t\tif n := len(remaining); n > 0 {\n\t\t\t\t\tremaining[0].Whitespace &= ^css_ast.WhitespaceBefore\n\t\t\t\t\tremaining[n-1].Whitespace &= ^css_ast.WhitespaceAfter\n\t\t\t\t}\n\t\t\t\treturn remaining, colorSpace, hueMethod, true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil, 0, 0, false\n}\n\ntype valueWithUnit struct {\n\tunit  string\n\tvalue F64\n}\n\ntype parsedColorStop struct {\n\t// Position information (may be a sum of two different units)\n\tpositionTerms []valueWithUnit\n\n\t// Color midpoint (a.k.a. transition hint) information\n\tmidpoint *valueWithUnit\n\n\t// Non-premultiplied color information in XYZ space\n\tx, y, z, alpha F64\n\n\t// Non-premultiplied color information in sRGB space\n\tr, g, b F64\n\n\t// Premultiplied color information in the interpolation color space\n\tv0, v1, v2 F64\n\n\t// True if the original color has a color space\n\thasColorSpace bool\n}\n\nfunc tryToParseColorStops(gradient parsedGradient) ([]parsedColorStop, bool) {\n\tvar colorStops []parsedColorStop\n\n\tfor _, stop := range gradient.colorStops {\n\t\tcolor, ok := parseColor(stop.color)\n\t\tif !ok {\n\t\t\treturn nil, false\n\t\t}\n\t\tvar r, g, b F64\n\t\tif !color.hasColorSpace {\n\t\t\tr = helpers.NewF64(float64(hexR(color.hex))).DivConst(255)\n\t\t\tg = helpers.NewF64(float64(hexG(color.hex))).DivConst(255)\n\t\t\tb = helpers.NewF64(float64(hexB(color.hex))).DivConst(255)\n\t\t\tcolor.x, color.y, color.z = lin_srgb_to_xyz(lin_srgb(r, g, b))\n\t\t} else {\n\t\t\tr, g, b = gam_srgb(xyz_to_lin_srgb(color.x, color.y, color.z))\n\t\t}\n\t\tparsedStop := parsedColorStop{\n\t\t\tx:             color.x,\n\t\t\ty:             color.y,\n\t\t\tz:             color.z,\n\t\t\tr:             r,\n\t\t\tg:             g,\n\t\t\tb:             b,\n\t\t\talpha:         helpers.NewF64(float64(hexA(color.hex))).DivConst(255),\n\t\t\thasColorSpace: color.hasColorSpace,\n\t\t}\n\n\t\tfor i, position := range stop.positions {\n\t\t\tif position, ok := tryToParseValue(position, gradient.kind); ok {\n\t\t\t\tparsedStop.positionTerms = []valueWithUnit{position}\n\t\t\t} else {\n\t\t\t\treturn nil, false\n\t\t\t}\n\n\t\t\t// Expand double positions\n\t\t\tif i+1 < len(stop.positions) {\n\t\t\t\tcolorStops = append(colorStops, parsedStop)\n\t\t\t}\n\t\t}\n\n\t\tif stop.midpoint.Kind != css_lexer.T(0) {\n\t\t\tif midpoint, ok := tryToParseValue(stop.midpoint, gradient.kind); ok {\n\t\t\t\tparsedStop.midpoint = &midpoint\n\t\t\t} else {\n\t\t\t\treturn nil, false\n\t\t\t}\n\t\t}\n\n\t\tcolorStops = append(colorStops, parsedStop)\n\t}\n\n\t// Automatically fill in missing positions\n\tif len(colorStops) > 0 {\n\t\ttype stopInfo struct {\n\t\t\tfromPos   valueWithUnit\n\t\t\ttoPos     valueWithUnit\n\t\t\tfromCount int32\n\t\t\ttoCount   int32\n\t\t}\n\n\t\t// Fill in missing positions for the endpoints first\n\t\tif first := &colorStops[0]; len(first.positionTerms) == 0 {\n\t\t\tfirst.positionTerms = []valueWithUnit{{value: helpers.NewF64(0), unit: \"%\"}}\n\t\t}\n\t\tif last := &colorStops[len(colorStops)-1]; len(last.positionTerms) == 0 {\n\t\t\tlast.positionTerms = []valueWithUnit{{value: helpers.NewF64(100), unit: \"%\"}}\n\t\t}\n\n\t\t// Set all positions to be greater than the position before them\n\t\tfor i, stop := range colorStops {\n\t\t\tvar prevPos valueWithUnit\n\t\t\tfor j := i - 1; j >= 0; j-- {\n\t\t\t\tprev := colorStops[j]\n\t\t\t\tif prev.midpoint != nil {\n\t\t\t\t\tprevPos = *prev.midpoint\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif len(prev.positionTerms) == 1 {\n\t\t\t\t\tprevPos = prev.positionTerms[0]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(stop.positionTerms) == 1 {\n\t\t\t\tif prevPos.unit == stop.positionTerms[0].unit {\n\t\t\t\t\tstop.positionTerms[0].value = helpers.Max2(prevPos.value, stop.positionTerms[0].value)\n\t\t\t\t}\n\t\t\t\tprevPos = stop.positionTerms[0]\n\t\t\t}\n\t\t\tif stop.midpoint != nil && prevPos.unit == stop.midpoint.unit {\n\t\t\t\tstop.midpoint.value = helpers.Max2(prevPos.value, stop.midpoint.value)\n\t\t\t}\n\t\t}\n\n\t\t// Scan over all other stops with missing positions\n\t\tinfos := make([]stopInfo, len(colorStops))\n\t\tfor i, stop := range colorStops {\n\t\t\tif len(stop.positionTerms) == 1 {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tinfo := &infos[i]\n\n\t\t\t// Scan backward\n\t\t\tfor from := i - 1; from >= 0; from-- {\n\t\t\t\tfromStop := colorStops[from]\n\t\t\t\tinfo.fromCount++\n\t\t\t\tif fromStop.midpoint != nil {\n\t\t\t\t\tinfo.fromPos = *fromStop.midpoint\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif len(fromStop.positionTerms) == 1 {\n\t\t\t\t\tinfo.fromPos = fromStop.positionTerms[0]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Scan forward\n\t\t\tfor to := i; to < len(colorStops); to++ {\n\t\t\t\tinfo.toCount++\n\t\t\t\tif toStop := colorStops[to]; toStop.midpoint != nil {\n\t\t\t\t\tinfo.toPos = *toStop.midpoint\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif to+1 < len(colorStops) {\n\t\t\t\t\tif toStop := colorStops[to+1]; len(toStop.positionTerms) == 1 {\n\t\t\t\t\t\tinfo.toPos = toStop.positionTerms[0]\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Then fill in all other missing positions\n\t\tfor i, stop := range colorStops {\n\t\t\tif len(stop.positionTerms) != 1 {\n\t\t\t\tinfo := infos[i]\n\t\t\t\tt := helpers.NewF64(float64(info.fromCount)).DivConst(float64(info.fromCount + info.toCount))\n\t\t\t\tif info.fromPos.unit == info.toPos.unit {\n\t\t\t\t\tcolorStops[i].positionTerms = []valueWithUnit{{\n\t\t\t\t\t\tvalue: helpers.Lerp(info.fromPos.value, info.toPos.value, t),\n\t\t\t\t\t\tunit:  info.fromPos.unit,\n\t\t\t\t\t}}\n\t\t\t\t} else {\n\t\t\t\t\tcolorStops[i].positionTerms = []valueWithUnit{{\n\t\t\t\t\t\tvalue: t.Neg().AddConst(1).Mul(info.fromPos.value),\n\t\t\t\t\t\tunit:  info.fromPos.unit,\n\t\t\t\t\t}, {\n\t\t\t\t\t\tvalue: t.Mul(info.toPos.value),\n\t\t\t\t\t\tunit:  info.toPos.unit,\n\t\t\t\t\t}}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Midpoints are only supported if they use the same units as their neighbors\n\t\tfor i, stop := range colorStops {\n\t\t\tif stop.midpoint != nil {\n\t\t\t\tnext := colorStops[i+1]\n\t\t\t\tif len(stop.positionTerms) != 1 || stop.midpoint.unit != stop.positionTerms[0].unit ||\n\t\t\t\t\tlen(next.positionTerms) != 1 || stop.midpoint.unit != next.positionTerms[0].unit {\n\t\t\t\t\treturn nil, false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn colorStops, true\n}\n\nfunc tryToParseValue(token css_ast.Token, kind gradientKind) (result valueWithUnit, success bool) {\n\tif kind == conicGradient {\n\t\t// <angle-percentage>\n\t\tswitch token.Kind {\n\t\tcase css_lexer.TDimension:\n\t\t\tdegrees, ok := degreesForAngle(token)\n\t\t\tif !ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresult.value = helpers.NewF64(degrees).MulConst(100.0 / 360)\n\t\t\tresult.unit = \"%\"\n\n\t\tcase css_lexer.TPercentage:\n\t\t\tpercent, err := strconv.ParseFloat(token.PercentageValue(), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresult.value = helpers.NewF64(percent)\n\t\t\tresult.unit = \"%\"\n\n\t\tdefault:\n\t\t\treturn\n\t\t}\n\t} else {\n\t\t// <length-percentage>\n\t\tswitch token.Kind {\n\t\tcase css_lexer.TNumber:\n\t\t\tzero, err := strconv.ParseFloat(token.Text, 64)\n\t\t\tif err != nil || zero != 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresult.value = helpers.NewF64(0)\n\t\t\tresult.unit = \"%\"\n\n\t\tcase css_lexer.TDimension:\n\t\t\tdimensionValue, err := strconv.ParseFloat(token.DimensionValue(), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresult.value = helpers.NewF64(dimensionValue)\n\t\t\tresult.unit = token.DimensionUnit()\n\n\t\tcase css_lexer.TPercentage:\n\t\t\tpercentageValue, err := strconv.ParseFloat(token.PercentageValue(), 64)\n\t\t\tif err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tresult.value = helpers.NewF64(percentageValue)\n\t\t\tresult.unit = \"%\"\n\n\t\tdefault:\n\t\t\treturn\n\t\t}\n\t}\n\n\tsuccess = true\n\treturn\n}\n\nfunc tryToExpandGradient(\n\tloc logger.Loc,\n\tgradient *parsedGradient,\n\tcolorStops []parsedColorStop,\n\tremaining []css_ast.Token,\n\tcolorSpace colorSpace,\n\thueMethod hueMethod,\n) bool {\n\t// Convert color stops into the interpolation color space\n\tfor i := range colorStops {\n\t\tstop := &colorStops[i]\n\t\tv0, v1, v2 := xyz_to_colorSpace(stop.x, stop.y, stop.z, colorSpace)\n\t\tstop.v0, stop.v1, stop.v2 = premultiply(v0, v1, v2, stop.alpha, colorSpace)\n\t}\n\n\t// Duplicate the endpoints if they should wrap around to themselves\n\tif hueMethod == longerHue && colorSpace.isPolar() && len(colorStops) > 0 {\n\t\tif first := colorStops[0]; len(first.positionTerms) == 1 {\n\t\t\tif first.positionTerms[0].value.Value() < 0 {\n\t\t\t\tcolorStops[0].positionTerms[0].value = helpers.NewF64(0)\n\t\t\t} else if first.positionTerms[0].value.Value() > 0 {\n\t\t\t\tfirst.midpoint = nil\n\t\t\t\tfirst.positionTerms = []valueWithUnit{{value: helpers.NewF64(0), unit: first.positionTerms[0].unit}}\n\t\t\t\tcolorStops = append([]parsedColorStop{first}, colorStops...)\n\t\t\t}\n\t\t}\n\t\tif last := colorStops[len(colorStops)-1]; len(last.positionTerms) == 1 {\n\t\t\tif last.positionTerms[0].unit != \"%\" || last.positionTerms[0].value.Value() < 100 {\n\t\t\t\tlast.positionTerms = []valueWithUnit{{value: helpers.NewF64(100), unit: \"%\"}}\n\t\t\t\tcolorStops = append(colorStops, last)\n\t\t\t}\n\t\t}\n\t}\n\n\tvar newColorStops []colorStop\n\tvar generateColorStops func(\n\t\tint, parsedColorStop, parsedColorStop,\n\t\tF64, F64, F64, F64, F64, F64, F64, F64,\n\t\tF64, F64, F64, F64, F64, F64, F64, F64,\n\t)\n\n\tgenerateColorStops = func(\n\t\tdepth int,\n\t\tfrom parsedColorStop, to parsedColorStop,\n\t\tprevX, prevY, prevZ, prevR, prevG, prevB, prevA, prevT F64,\n\t\tnextX, nextY, nextZ, nextR, nextG, nextB, nextA, nextT F64,\n\t) {\n\t\tif depth > 4 {\n\t\t\treturn\n\t\t}\n\n\t\tt := prevT.Add(nextT).DivConst(2)\n\t\tpositionT := t\n\n\t\t// Handle midpoints (which we have already checked uses the same units)\n\t\tif from.midpoint != nil {\n\t\t\tfromPos := from.positionTerms[0].value\n\t\t\ttoPos := to.positionTerms[0].value\n\t\t\tstopPos := helpers.Lerp(fromPos, toPos, t)\n\t\t\tH := from.midpoint.value.Sub(fromPos).Div(toPos.Sub(fromPos))\n\t\t\tP := stopPos.Sub(fromPos).Div(toPos.Sub(fromPos))\n\t\t\tif H.Value() <= 0 {\n\t\t\t\tpositionT = helpers.NewF64(1)\n\t\t\t} else if H.Value() >= 1 {\n\t\t\t\tpositionT = helpers.NewF64(0)\n\t\t\t} else {\n\t\t\t\tpositionT = P.Pow(helpers.NewF64(-1).Div(H.Log2()))\n\t\t\t}\n\t\t}\n\n\t\tv0, v1, v2 := interpolateColors(from.v0, from.v1, from.v2, to.v0, to.v1, to.v2, colorSpace, hueMethod, positionT)\n\t\ta := helpers.Lerp(from.alpha, to.alpha, positionT)\n\t\tv0, v1, v2 = unpremultiply(v0, v1, v2, a, colorSpace)\n\t\tx, y, z := colorSpace_to_xyz(v0, v1, v2, colorSpace)\n\n\t\t// Stop when the color is similar enough to the sRGB midpoint\n\t\tconst epsilon = 4.0 / 255\n\t\tr, g, b := gam_srgb(xyz_to_lin_srgb(x, y, z))\n\t\tdr := r.Mul(a).Sub(prevR.Mul(prevA).Add(nextR.Mul(nextA)).DivConst(2))\n\t\tdg := g.Mul(a).Sub(prevG.Mul(prevA).Add(nextG.Mul(nextA)).DivConst(2))\n\t\tdb := b.Mul(a).Sub(prevB.Mul(prevA).Add(nextB.Mul(nextA)).DivConst(2))\n\t\tif d := dr.Squared().Add(dg.Squared()).Add(db.Squared()); d.Value() < epsilon*epsilon {\n\t\t\treturn\n\t\t}\n\n\t\t// Recursive split before this stop\n\t\tgenerateColorStops(depth+1, from, to,\n\t\t\tprevX, prevY, prevZ, prevR, prevG, prevB, prevA, prevT,\n\t\t\tx, y, z, r, g, b, a, t)\n\n\t\t// Generate this stop\n\t\tcolor := makeColorToken(loc, x, y, z, a)\n\t\tpositionTerms := interpolatePositions(from.positionTerms, to.positionTerms, t)\n\t\tposition := makePositionToken(loc, positionTerms)\n\t\tposition.Whitespace = css_ast.WhitespaceBefore\n\t\tnewColorStops = append(newColorStops, colorStop{\n\t\t\tcolor:     color,\n\t\t\tpositions: []css_ast.Token{position},\n\t\t})\n\n\t\t// Recursive split after this stop\n\t\tgenerateColorStops(depth+1, from, to,\n\t\t\tx, y, z, r, g, b, a, t,\n\t\t\tnextX, nextY, nextZ, nextR, nextG, nextB, nextA, nextT)\n\t}\n\n\tfor i, stop := range colorStops {\n\t\tcolor := makeColorToken(loc, stop.x, stop.y, stop.z, stop.alpha)\n\t\tposition := makePositionToken(loc, stop.positionTerms)\n\t\tposition.Whitespace = css_ast.WhitespaceBefore\n\t\tnewColorStops = append(newColorStops, colorStop{\n\t\t\tcolor:     color,\n\t\t\tpositions: []css_ast.Token{position},\n\t\t})\n\n\t\t// Generate new color stops in between as needed\n\t\tif i+1 < len(colorStops) {\n\t\t\tnext := colorStops[i+1]\n\t\t\tgenerateColorStops(0, stop, next,\n\t\t\t\tstop.x, stop.y, stop.z, stop.r, stop.g, stop.b, stop.alpha, helpers.NewF64(0),\n\t\t\t\tnext.x, next.y, next.z, next.r, next.g, next.b, next.alpha, helpers.NewF64(1))\n\t\t}\n\t}\n\n\tgradient.leadingTokens = remaining\n\tgradient.colorStops = newColorStops\n\treturn true\n}\n\nfunc formatFloat(value F64, decimals int) string {\n\treturn strings.TrimSuffix(strings.TrimRight(strconv.FormatFloat(value.Value(), 'f', decimals, 64), \"0\"), \".\")\n}\n\nfunc makeDimensionOrPercentToken(loc logger.Loc, value F64, unit string) (token css_ast.Token) {\n\ttoken.Loc = loc\n\ttoken.Text = formatFloat(value, 2)\n\tif unit == \"%\" {\n\t\ttoken.Kind = css_lexer.TPercentage\n\t} else {\n\t\ttoken.Kind = css_lexer.TDimension\n\t\ttoken.UnitOffset = uint16(len(token.Text))\n\t}\n\ttoken.Text += unit\n\treturn\n}\n\nfunc makePositionToken(loc logger.Loc, positionTerms []valueWithUnit) css_ast.Token {\n\tif len(positionTerms) == 1 {\n\t\treturn makeDimensionOrPercentToken(loc, positionTerms[0].value, positionTerms[0].unit)\n\t}\n\n\tchildren := make([]css_ast.Token, 0, 1+2*len(positionTerms))\n\tfor i, term := range positionTerms {\n\t\tif i > 0 {\n\t\t\tchildren = append(children, css_ast.Token{\n\t\t\t\tLoc:        loc,\n\t\t\t\tKind:       css_lexer.TDelimPlus,\n\t\t\t\tText:       \"+\",\n\t\t\t\tWhitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter,\n\t\t\t})\n\t\t}\n\t\tchildren = append(children, makeDimensionOrPercentToken(loc, term.value, term.unit))\n\t}\n\n\treturn css_ast.Token{\n\t\tLoc:      loc,\n\t\tKind:     css_lexer.TFunction,\n\t\tText:     \"calc\",\n\t\tChildren: &children,\n\t}\n}\n\nfunc makeColorToken(loc logger.Loc, x F64, y F64, z F64, a F64) (color css_ast.Token) {\n\tcolor.Loc = loc\n\talpha := uint32(a.MulConst(255).Round().Value())\n\tif hex, ok := tryToConvertToHexWithoutClipping(x, y, z, alpha); ok {\n\t\tcolor.Kind = css_lexer.THash\n\t\tif alpha == 255 {\n\t\t\tcolor.Text = fmt.Sprintf(\"%06x\", hex>>8)\n\t\t} else {\n\t\t\tcolor.Text = fmt.Sprintf(\"%08x\", hex)\n\t\t}\n\t} else {\n\t\tchildren := []css_ast.Token{\n\t\t\t{\n\t\t\t\tLoc:        loc,\n\t\t\t\tKind:       css_lexer.TIdent,\n\t\t\t\tText:       \"xyz\",\n\t\t\t\tWhitespace: css_ast.WhitespaceAfter,\n\t\t\t},\n\t\t\t{\n\t\t\t\tLoc:        loc,\n\t\t\t\tKind:       css_lexer.TNumber,\n\t\t\t\tText:       formatFloat(x, 3),\n\t\t\t\tWhitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter,\n\t\t\t},\n\t\t\t{\n\t\t\t\tLoc:        loc,\n\t\t\t\tKind:       css_lexer.TNumber,\n\t\t\t\tText:       formatFloat(y, 3),\n\t\t\t\tWhitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter,\n\t\t\t},\n\t\t\t{\n\t\t\t\tLoc:        loc,\n\t\t\t\tKind:       css_lexer.TNumber,\n\t\t\t\tText:       formatFloat(z, 3),\n\t\t\t\tWhitespace: css_ast.WhitespaceBefore,\n\t\t\t},\n\t\t}\n\t\tif a.Value() < 1 {\n\t\t\tchildren = append(children,\n\t\t\t\tcss_ast.Token{\n\t\t\t\t\tLoc:        loc,\n\t\t\t\t\tKind:       css_lexer.TDelimSlash,\n\t\t\t\t\tText:       \"/\",\n\t\t\t\t\tWhitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter,\n\t\t\t\t},\n\t\t\t\tcss_ast.Token{\n\t\t\t\t\tLoc:        loc,\n\t\t\t\t\tKind:       css_lexer.TNumber,\n\t\t\t\t\tText:       formatFloat(a, 3),\n\t\t\t\t\tWhitespace: css_ast.WhitespaceBefore,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t\tcolor.Kind = css_lexer.TFunction\n\t\tcolor.Text = \"color\"\n\t\tcolor.Children = &children\n\t}\n\treturn\n}\n\nfunc interpolateHues(a, b, t F64, hueMethod hueMethod) F64 {\n\ta = a.DivConst(360)\n\tb = b.DivConst(360)\n\ta = a.Sub(a.Floor())\n\tb = b.Sub(b.Floor())\n\n\tswitch hueMethod {\n\tcase shorterHue:\n\t\tdelta := b.Sub(a)\n\t\tif delta.Value() > 0.5 {\n\t\t\ta = a.AddConst(1)\n\t\t}\n\t\tif delta.Value() < -0.5 {\n\t\t\tb = b.AddConst(1)\n\t\t}\n\n\tcase longerHue:\n\t\tdelta := b.Sub(a)\n\t\tif delta.Value() > 0 && delta.Value() < 0.5 {\n\t\t\ta = a.AddConst(1)\n\t\t}\n\t\tif delta.Value() > -0.5 && delta.Value() <= 0 {\n\t\t\tb = b.AddConst(1)\n\t\t}\n\n\tcase increasingHue:\n\t\tif b.Value() < a.Value() {\n\t\t\tb = b.AddConst(1)\n\t\t}\n\n\tcase decreasingHue:\n\t\tif a.Value() < b.Value() {\n\t\t\ta = a.AddConst(1)\n\t\t}\n\t}\n\n\treturn helpers.Lerp(a, b, t).MulConst(360)\n}\n\nfunc interpolateColors(\n\ta0, a1, a2 F64, b0, b1, b2 F64,\n\tcolorSpace colorSpace, hueMethod hueMethod, t F64,\n) (v0 F64, v1 F64, v2 F64) {\n\tv1 = helpers.Lerp(a1, b1, t)\n\n\tswitch colorSpace {\n\tcase colorSpace_hsl, colorSpace_hwb:\n\t\tv2 = helpers.Lerp(a2, b2, t)\n\t\tv0 = interpolateHues(a0, b0, t, hueMethod)\n\n\tcase colorSpace_lch, colorSpace_oklch:\n\t\tv0 = helpers.Lerp(a0, b0, t)\n\t\tv2 = interpolateHues(a2, b2, t, hueMethod)\n\n\tdefault:\n\t\tv0 = helpers.Lerp(a0, b0, t)\n\t\tv2 = helpers.Lerp(a2, b2, t)\n\t}\n\n\treturn v0, v1, v2\n}\n\nfunc interpolatePositions(a []valueWithUnit, b []valueWithUnit, t F64) (result []valueWithUnit) {\n\tfindUnit := func(unit string) int {\n\t\tfor i, x := range result {\n\t\t\tif x.unit == unit {\n\t\t\t\treturn i\n\t\t\t}\n\t\t}\n\t\tresult = append(result, valueWithUnit{unit: unit})\n\t\treturn len(result) - 1\n\t}\n\n\t// \"result += a * (1 - t)\"\n\tfor _, term := range a {\n\t\tptr := &result[findUnit(term.unit)]\n\t\tptr.value = t.Neg().AddConst(1).Mul(term.value).Add(ptr.value)\n\t}\n\n\t// \"result += b * t\"\n\tfor _, term := range b {\n\t\tptr := &result[findUnit(term.unit)]\n\t\tptr.value = t.Mul(term.value).Add(ptr.value)\n\t}\n\n\t// Remove an extra zero value for neatness. We don't remove all\n\t// of them because it may be important to retain a single zero.\n\tif len(result) > 1 {\n\t\tfor i, term := range result {\n\t\t\tif term.value.Value() == 0 {\n\t\t\t\tcopy(result[i:], result[i+1:])\n\t\t\t\tresult = result[:len(result)-1]\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc premultiply(v0, v1, v2, alpha F64, colorSpace colorSpace) (F64, F64, F64) {\n\tif alpha.Value() < 1 {\n\t\tswitch colorSpace {\n\t\tcase colorSpace_hsl, colorSpace_hwb:\n\t\t\tv2 = v2.Mul(alpha)\n\t\tcase colorSpace_lch, colorSpace_oklch:\n\t\t\tv0 = v0.Mul(alpha)\n\t\tdefault:\n\t\t\tv0 = v0.Mul(alpha)\n\t\t\tv2 = v2.Mul(alpha)\n\t\t}\n\t\tv1 = v1.Mul(alpha)\n\t}\n\treturn v0, v1, v2\n}\n\nfunc unpremultiply(v0, v1, v2, alpha F64, colorSpace colorSpace) (F64, F64, F64) {\n\tif alpha.Value() > 0 && alpha.Value() < 1 {\n\t\tswitch colorSpace {\n\t\tcase colorSpace_hsl, colorSpace_hwb:\n\t\t\tv2 = v2.Div(alpha)\n\t\tcase colorSpace_lch, colorSpace_oklch:\n\t\t\tv0 = v0.Div(alpha)\n\t\tdefault:\n\t\t\tv0 = v0.Div(alpha)\n\t\t\tv2 = v2.Div(alpha)\n\t\t}\n\t\tv1 = v1.Div(alpha)\n\t}\n\treturn v0, v1, v2\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_list_style.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\n// list-style-image: <image> | none\n// <image>: <url> | <gradient>\n// <url>: <url()> | <src()>\n// <gradient>: <linear-gradient()> | <repeating-linear-gradient()> | <radial-gradient()> | <repeating-radial-gradient()>\n//\n// list-style-type: <counter-style> | <string> | none (where the string is a literal bullet marker)\n// <counter-style>: <counter-style-name> | <symbols()>\n// <counter-style-name>: not: decimal | disc | square | circle | disclosure-open | disclosure-closed | <wide keyword>\n// when parsing a <custom-ident> with conflicts, only parse one if no other thing can claim it\n\nfunc (p *parser) processListStyleShorthand(tokens []css_ast.Token) {\n\tif len(tokens) < 1 || len(tokens) > 3 {\n\t\treturn\n\t}\n\n\tfoundImage := false\n\tfoundPosition := false\n\ttypeIndex := -1\n\tnoneCount := 0\n\n\tfor i, t := range tokens {\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TString:\n\t\t\t// \"list-style-type\" is definitely not a <custom-ident>\n\t\t\treturn\n\n\t\tcase css_lexer.TURL:\n\t\t\tif !foundImage {\n\t\t\t\tfoundImage = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\tcase css_lexer.TFunction:\n\t\t\tif !foundImage {\n\t\t\t\tswitch strings.ToLower(t.Text) {\n\t\t\t\tcase \"src\", \"linear-gradient\", \"repeating-linear-gradient\", \"radial-gradient\", \"radial-linear-gradient\":\n\t\t\t\t\tfoundImage = true\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase css_lexer.TIdent:\n\t\t\tlower := strings.ToLower(t.Text)\n\n\t\t\t// Note: If \"none\" is present, it's ambiguous whether it applies to\n\t\t\t// \"list-style-image\" or \"list-style-type\". To resolve ambiguity it's\n\t\t\t// applied at the end to whichever property isn't otherwise set.\n\t\t\tif lower == \"none\" {\n\t\t\t\tnoneCount++\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif !foundPosition && (lower == \"inside\" || lower == \"outside\") {\n\t\t\t\tfoundPosition = true\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif typeIndex == -1 {\n\t\t\t\tif cssWideAndReservedKeywords[lower] || predefinedCounterStyles[lower] {\n\t\t\t\t\t// \"list-style-type\" is definitely not a <custom-ident>\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\ttypeIndex = i\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Bail if we hit an unexpected token\n\t\treturn\n\t}\n\n\tif typeIndex != -1 {\n\t\t// The first \"none\" applies to \"list-style-image\" if it's missing\n\t\tif !foundImage && noneCount > 0 {\n\t\t\tnoneCount--\n\t\t}\n\n\t\tif noneCount > 0 {\n\t\t\t// \"list-style-type\" is \"none\", not a <custom-ident>\n\t\t\treturn\n\t\t}\n\n\t\tif t := &tokens[typeIndex]; t.Kind == css_lexer.TIdent {\n\t\t\tt.Kind = css_lexer.TSymbol\n\t\t\tt.PayloadIndex = p.symbolForName(t.Loc, t.Text).Ref.InnerIndex\n\t\t}\n\t}\n}\n\nfunc (p *parser) processListStyleType(t *css_ast.Token) {\n\tif t.Kind == css_lexer.TIdent {\n\t\tif lower := strings.ToLower(t.Text); lower != \"none\" && !cssWideAndReservedKeywords[lower] && !predefinedCounterStyles[lower] {\n\t\t\tt.Kind = css_lexer.TSymbol\n\t\t\tt.PayloadIndex = p.symbolForName(t.Loc, t.Text).Ref.InnerIndex\n\t\t}\n\t}\n}\n\n// https://drafts.csswg.org/css-counter-styles-3/#predefined-counters\nvar predefinedCounterStyles = map[string]bool{\n\t// 6.1. Numeric:\n\t\"arabic-indic\":         true,\n\t\"armenian\":             true,\n\t\"bengali\":              true,\n\t\"cambodian\":            true,\n\t\"cjk-decimal\":          true,\n\t\"decimal-leading-zero\": true,\n\t\"decimal\":              true,\n\t\"devanagari\":           true,\n\t\"georgian\":             true,\n\t\"gujarati\":             true,\n\t\"gurmukhi\":             true,\n\t\"hebrew\":               true,\n\t\"kannada\":              true,\n\t\"khmer\":                true,\n\t\"lao\":                  true,\n\t\"lower-armenian\":       true,\n\t\"lower-roman\":          true,\n\t\"malayalam\":            true,\n\t\"mongolian\":            true,\n\t\"myanmar\":              true,\n\t\"oriya\":                true,\n\t\"persian\":              true,\n\t\"tamil\":                true,\n\t\"telugu\":               true,\n\t\"thai\":                 true,\n\t\"tibetan\":              true,\n\t\"upper-armenian\":       true,\n\t\"upper-roman\":          true,\n\n\t// 6.2. Alphabetic:\n\t\"hiragana-iroha\": true,\n\t\"hiragana\":       true,\n\t\"katakana-iroha\": true,\n\t\"katakana\":       true,\n\t\"lower-alpha\":    true,\n\t\"lower-greek\":    true,\n\t\"lower-latin\":    true,\n\t\"upper-alpha\":    true,\n\t\"upper-latin\":    true,\n\n\t// 6.3. Symbolic:\n\t\"circle\":            true,\n\t\"disc\":              true,\n\t\"disclosure-closed\": true,\n\t\"disclosure-open\":   true,\n\t\"square\":            true,\n\n\t// 6.4. Fixed:\n\t\"cjk-earthly-branch\": true,\n\t\"cjk-heavenly-stem\":  true,\n\n\t// 7.1.1. Japanese:\n\t\"japanese-formal\":   true,\n\t\"japanese-informal\": true,\n\n\t// 7.1.2. Korean:\n\t\"korean-hangul-formal\":  true,\n\t\"korean-hanja-formal\":   true,\n\t\"korean-hanja-informal\": true,\n\n\t// 7.1.3. Chinese:\n\t\"simp-chinese-formal\":   true,\n\t\"simp-chinese-informal\": true,\n\t\"trad-chinese-formal\":   true,\n\t\"trad-chinese-informal\": true,\n\n\t// 7.2. Ethiopic Numeric Counter Style:\n\t\"ethiopic-numeric\": true,\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_decls_transform.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n)\n\nfunc turnPercentIntoNumberIfShorter(t *css_ast.Token) {\n\tif t.Kind == css_lexer.TPercentage {\n\t\tif shifted, ok := shiftDot(t.PercentageValue(), -2); ok && len(shifted) < len(t.Text) {\n\t\t\tt.Kind = css_lexer.TNumber\n\t\t\tt.Text = shifted\n\t\t}\n\t}\n}\n\n// https://www.w3.org/TR/css-transforms-1/#two-d-transform-functions\n// https://drafts.csswg.org/css-transforms-2/#transform-functions\nfunc (p *parser) mangleTransforms(tokens []css_ast.Token) []css_ast.Token {\n\tfor i := range tokens {\n\t\tif token := &tokens[i]; token.Kind == css_lexer.TFunction {\n\t\t\tif args := *token.Children; css_ast.TokensAreCommaSeparated(args) {\n\t\t\t\tn := len(args)\n\n\t\t\t\tswitch strings.ToLower(token.Text) {\n\t\t\t\t////////////////////////////////////////////////////////////////////////////////\n\t\t\t\t// 2D transforms\n\n\t\t\t\tcase \"matrix\":\n\t\t\t\t\t// specifies a 2D transformation in the form of a transformation\n\t\t\t\t\t// matrix of the six values a, b, c, d, e, f.\n\t\t\t\t\tif n == 11 {\n\t\t\t\t\t\t// | a c 0 e |\n\t\t\t\t\t\t// | b d 0 f |\n\t\t\t\t\t\t// | 0 0 1 0 |\n\t\t\t\t\t\t// | 0 0 0 1 |\n\t\t\t\t\t\ta, b, c, d, e, f := args[0], args[2], args[4], args[6], args[8], args[10]\n\t\t\t\t\t\tif b.IsZero() && c.IsZero() && e.IsZero() && f.IsZero() {\n\t\t\t\t\t\t\t// | a 0 0 0 |\n\t\t\t\t\t\t\t// | 0 d 0 0 |\n\t\t\t\t\t\t\t// | 0 0 1 0 |\n\t\t\t\t\t\t\t// | 0 0 0 1 |\n\t\t\t\t\t\t\tif a.EqualIgnoringWhitespace(d) {\n\t\t\t\t\t\t\t\t// \"matrix(a, 0, 0, a, 0, 0)\" => \"scale(a)\"\n\t\t\t\t\t\t\t\ttoken.Text = \"scale\"\n\t\t\t\t\t\t\t\t*token.Children = args[:1]\n\t\t\t\t\t\t\t} else if d.IsOne() {\n\t\t\t\t\t\t\t\t// \"matrix(a, 0, 0, 1, 0, 0)\" => \"scaleX(a)\"\n\t\t\t\t\t\t\t\ttoken.Text = \"scaleX\"\n\t\t\t\t\t\t\t\t*token.Children = args[:1]\n\t\t\t\t\t\t\t} else if a.IsOne() {\n\t\t\t\t\t\t\t\t// \"matrix(1, 0, 0, d, 0, 0)\" => \"scaleY(d)\"\n\t\t\t\t\t\t\t\ttoken.Text = \"scaleY\"\n\t\t\t\t\t\t\t\t*token.Children = args[6:7]\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t// \"matrix(a, 0, 0, d, 0, 0)\" => \"scale(a, d)\"\n\t\t\t\t\t\t\t\ttoken.Text = \"scale\"\n\t\t\t\t\t\t\t\t*token.Children = append(args[:2], d)\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Note: A \"matrix\" cannot be directly converted into a \"translate\"\n\t\t\t\t\t\t\t// because \"translate\" requires units while \"matrix\" requires no\n\t\t\t\t\t\t\t// units. I'm not sure exactly what the semantics are so I'm not\n\t\t\t\t\t\t\t// sure if you can just add \"px\" or not. Even if that did work,\n\t\t\t\t\t\t\t// you still couldn't substitute values containing \"var()\" since\n\t\t\t\t\t\t\t// units would still not be substituted in that case.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase \"translate\":\n\t\t\t\t\t// specifies a 2D translation by the vector [tx, ty], where tx is the\n\t\t\t\t\t// first translation-value parameter and ty is the optional second\n\t\t\t\t\t// translation-value parameter. If <ty> is not provided, ty has zero\n\t\t\t\t\t// as a value.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthOrPercentageIntoNumberIfZero()\n\t\t\t\t\t} else if n == 3 {\n\t\t\t\t\t\ttx, ty := &args[0], &args[2]\n\t\t\t\t\t\ttx.TurnLengthOrPercentageIntoNumberIfZero()\n\t\t\t\t\t\tty.TurnLengthOrPercentageIntoNumberIfZero()\n\t\t\t\t\t\tif ty.IsZero() {\n\t\t\t\t\t\t\t// \"translate(tx, 0)\" => \"translate(tx)\"\n\t\t\t\t\t\t\t*token.Children = args[:1]\n\t\t\t\t\t\t} else if tx.IsZero() {\n\t\t\t\t\t\t\t// \"translate(0, ty)\" => \"translateY(ty)\"\n\t\t\t\t\t\t\ttoken.Text = \"translateY\"\n\t\t\t\t\t\t\t*token.Children = args[2:]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase \"translatex\":\n\t\t\t\t\t// specifies a translation by the given amount in the X direction.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\t// \"translateX(tx)\" => \"translate(tx)\"\n\t\t\t\t\t\ttoken.Text = \"translate\"\n\t\t\t\t\t\targs[0].TurnLengthOrPercentageIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\tcase \"translatey\":\n\t\t\t\t\t// specifies a translation by the given amount in the Y direction.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthOrPercentageIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\tcase \"scale\":\n\t\t\t\t\t// specifies a 2D scale operation by the [sx,sy] scaling vector\n\t\t\t\t\t// described by the 2 parameters. If the second parameter is not\n\t\t\t\t\t// provided, it takes a value equal to the first. For example,\n\t\t\t\t\t// scale(1, 1) would leave an element unchanged, while scale(2, 2)\n\t\t\t\t\t// would cause it to appear twice as long in both the X and Y axes,\n\t\t\t\t\t// or four times its typical geometric size.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(&args[0])\n\t\t\t\t\t} else if n == 3 {\n\t\t\t\t\t\tsx, sy := &args[0], &args[2]\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(sx)\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(sy)\n\t\t\t\t\t\tif sx.EqualIgnoringWhitespace(*sy) {\n\t\t\t\t\t\t\t// \"scale(s, s)\" => \"scale(s)\"\n\t\t\t\t\t\t\t*token.Children = args[:1]\n\t\t\t\t\t\t} else if sy.IsOne() {\n\t\t\t\t\t\t\t// \"scale(s, 1)\" => \"scaleX(s)\"\n\t\t\t\t\t\t\ttoken.Text = \"scaleX\"\n\t\t\t\t\t\t\t*token.Children = args[:1]\n\t\t\t\t\t\t} else if sx.IsOne() {\n\t\t\t\t\t\t\t// \"scale(1, s)\" => \"scaleY(s)\"\n\t\t\t\t\t\t\ttoken.Text = \"scaleY\"\n\t\t\t\t\t\t\t*token.Children = args[2:]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase \"scalex\":\n\t\t\t\t\t// specifies a 2D scale operation using the [sx,1] scaling vector,\n\t\t\t\t\t// where sx is given as the parameter.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(&args[0])\n\t\t\t\t\t}\n\n\t\t\t\tcase \"scaley\":\n\t\t\t\t\t// specifies a 2D scale operation using the [1,sy] scaling vector,\n\t\t\t\t\t// where sy is given as the parameter.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(&args[0])\n\t\t\t\t\t}\n\n\t\t\t\tcase \"rotate\":\n\t\t\t\t\t// specifies a 2D rotation by the angle specified in the parameter\n\t\t\t\t\t// about the origin of the element, as defined by the\n\t\t\t\t\t// transform-origin property. For example, rotate(90deg) would\n\t\t\t\t\t// cause elements to appear rotated one-quarter of a turn in the\n\t\t\t\t\t// clockwise direction.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\t// Note: This is considered a 2D transform even though it's specified\n\t\t\t\t// in terms of a 3D transform because it doesn't trigger Safari's 3D\n\t\t\t\t// transform bugs.\n\t\t\t\tcase \"rotatez\":\n\t\t\t\t\t// same as rotate3d(0, 0, 1, <angle>), which is a 3d transform\n\t\t\t\t\t// equivalent to the 2d transform rotate(<angle>).\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\t// \"rotateZ(angle)\" => \"rotate(angle)\"\n\t\t\t\t\t\ttoken.Text = \"rotate\"\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\tcase \"skew\":\n\t\t\t\t\t// specifies a 2D skew by [ax,ay] for X and Y. If the second\n\t\t\t\t\t// parameter is not provided, it has a zero value.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t} else if n == 3 {\n\t\t\t\t\t\tax, ay := &args[0], &args[2]\n\t\t\t\t\t\tax.TurnLengthIntoNumberIfZero()\n\t\t\t\t\t\tay.TurnLengthIntoNumberIfZero()\n\t\t\t\t\t\tif ay.IsZero() {\n\t\t\t\t\t\t\t// \"skew(ax, 0)\" => \"skew(ax)\"\n\t\t\t\t\t\t\t*token.Children = args[:1]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase \"skewx\":\n\t\t\t\t\t// specifies a 2D skew transformation along the X axis by the given\n\t\t\t\t\t// angle.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\t// \"skewX(ax)\" => \"skew(ax)\"\n\t\t\t\t\t\ttoken.Text = \"skew\"\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\tcase \"skewy\":\n\t\t\t\t\t// specifies a 2D skew transformation along the Y axis by the given\n\t\t\t\t\t// angle.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\t\t////////////////////////////////////////////////////////////////////////////////\n\t\t\t\t\t// 3D transforms\n\n\t\t\t\t\t// Note: Safari has a bug where 3D transforms render differently than\n\t\t\t\t\t// other transforms. This means we should not minify a 3D transform\n\t\t\t\t\t// into a 2D transform or it will cause a rendering difference in\n\t\t\t\t\t// Safari.\n\n\t\t\t\tcase \"matrix3d\":\n\t\t\t\t\t// specifies a 3D transformation as a 4x4 homogeneous matrix of 16\n\t\t\t\t\t// values in column-major order.\n\t\t\t\t\tif n == 31 {\n\t\t\t\t\t\t// | m0 m4 m8  m12 |\n\t\t\t\t\t\t// | m1 m5 m9  m13 |\n\t\t\t\t\t\t// | m2 m6 m10 m14 |\n\t\t\t\t\t\t// | m3 m7 m11 m15 |\n\t\t\t\t\t\tmask := uint32(0)\n\t\t\t\t\t\tfor i := 0; i < 16; i++ {\n\t\t\t\t\t\t\tif arg := args[i*2]; arg.IsZero() {\n\t\t\t\t\t\t\t\tmask |= 1 << i\n\t\t\t\t\t\t\t} else if arg.IsOne() {\n\t\t\t\t\t\t\t\tmask |= (1 << 16) << i\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst onlyScale = 0b1000_0000_0000_0000_0111_1011_1101_1110\n\t\t\t\t\t\tif (mask & onlyScale) == onlyScale {\n\t\t\t\t\t\t\t// | m0 0  0   0 |\n\t\t\t\t\t\t\t// | 0  m5 0   0 |\n\t\t\t\t\t\t\t// | 0  0  m10 0 |\n\t\t\t\t\t\t\t// | 0  0  0   1 |\n\t\t\t\t\t\t\tsx, sy := args[0], args[10]\n\t\t\t\t\t\t\tif sx.IsOne() && sy.IsOne() {\n\t\t\t\t\t\t\t\ttoken.Text = \"scaleZ\"\n\t\t\t\t\t\t\t\t*token.Children = args[20:21]\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\ttoken.Text = \"scale3d\"\n\t\t\t\t\t\t\t\t*token.Children = append(append(args[0:2], args[10:12]...), args[20])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Note: A \"matrix3d\" cannot be directly converted into a \"translate3d\"\n\t\t\t\t\t\t// because \"translate3d\" requires units while \"matrix3d\" requires no\n\t\t\t\t\t\t// units. I'm not sure exactly what the semantics are so I'm not\n\t\t\t\t\t\t// sure if you can just add \"px\" or not. Even if that did work,\n\t\t\t\t\t\t// you still couldn't substitute values containing \"var()\" since\n\t\t\t\t\t\t// units would still not be substituted in that case.\n\t\t\t\t\t}\n\n\t\t\t\tcase \"translate3d\":\n\t\t\t\t\t// specifies a 3D translation by the vector [tx,ty,tz], with tx,\n\t\t\t\t\t// ty and tz being the first, second and third translation-value\n\t\t\t\t\t// parameters respectively.\n\t\t\t\t\tif n == 5 {\n\t\t\t\t\t\ttx, ty, tz := &args[0], &args[2], &args[4]\n\t\t\t\t\t\ttx.TurnLengthOrPercentageIntoNumberIfZero()\n\t\t\t\t\t\tty.TurnLengthOrPercentageIntoNumberIfZero()\n\t\t\t\t\t\ttz.TurnLengthIntoNumberIfZero()\n\t\t\t\t\t\tif tx.IsZero() && ty.IsZero() {\n\t\t\t\t\t\t\t// \"translate3d(0, 0, tz)\" => \"translateZ(tz)\"\n\t\t\t\t\t\t\ttoken.Text = \"translateZ\"\n\t\t\t\t\t\t\t*token.Children = args[4:]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase \"translatez\":\n\t\t\t\t\t// specifies a 3D translation by the vector [0,0,tz] with the given\n\t\t\t\t\t// amount in the Z direction.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\tcase \"scale3d\":\n\t\t\t\t\t// specifies a 3D scale operation by the [sx,sy,sz] scaling vector\n\t\t\t\t\t// described by the 3 parameters.\n\t\t\t\t\tif n == 5 {\n\t\t\t\t\t\tsx, sy, sz := &args[0], &args[2], &args[4]\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(sx)\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(sy)\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(sz)\n\t\t\t\t\t\tif sx.IsOne() && sy.IsOne() {\n\t\t\t\t\t\t\t// \"scale3d(1, 1, sz)\" => \"scaleZ(sz)\"\n\t\t\t\t\t\t\ttoken.Text = \"scaleZ\"\n\t\t\t\t\t\t\t*token.Children = args[4:]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase \"scalez\":\n\t\t\t\t\t// specifies a 3D scale operation using the [1,1,sz] scaling vector,\n\t\t\t\t\t// where sz is given as the parameter.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\tturnPercentIntoNumberIfShorter(&args[0])\n\t\t\t\t\t}\n\n\t\t\t\tcase \"rotate3d\":\n\t\t\t\t\t// specifies a 3D rotation by the angle specified in last parameter\n\t\t\t\t\t// about the [x,y,z] direction vector described by the first three\n\t\t\t\t\t// parameters. A direction vector that cannot be normalized, such as\n\t\t\t\t\t// [0,0,0], will cause the rotation to not be applied.\n\t\t\t\t\tif n == 7 {\n\t\t\t\t\t\tx, y, z, angle := &args[0], &args[2], &args[4], &args[6]\n\t\t\t\t\t\tangle.TurnLengthIntoNumberIfZero()\n\t\t\t\t\t\tif x.IsOne() && y.IsZero() && z.IsZero() {\n\t\t\t\t\t\t\t// \"rotate3d(1, 0, 0, angle)\" => \"rotateX(angle)\"\n\t\t\t\t\t\t\ttoken.Text = \"rotateX\"\n\t\t\t\t\t\t\t*token.Children = args[6:]\n\t\t\t\t\t\t} else if x.IsZero() && y.IsOne() && z.IsZero() {\n\t\t\t\t\t\t\t// \"rotate3d(0, 1, 0, angle)\" => \"rotateY(angle)\"\n\t\t\t\t\t\t\ttoken.Text = \"rotateY\"\n\t\t\t\t\t\t\t*token.Children = args[6:]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tcase \"rotatex\":\n\t\t\t\t\t// same as rotate3d(1, 0, 0, <angle>).\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\tcase \"rotatey\":\n\t\t\t\t\t// same as rotate3d(0, 1, 0, <angle>).\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\n\t\t\t\tcase \"perspective\":\n\t\t\t\t\t// specifies a perspective projection matrix. This matrix scales\n\t\t\t\t\t// points in X and Y based on their Z value, scaling points with\n\t\t\t\t\t// positive Z values away from the origin, and those with negative Z\n\t\t\t\t\t// values towards the origin. Points on the z=0 plane are unchanged.\n\t\t\t\t\t// The parameter represents the distance of the z=0 plane from the\n\t\t\t\t\t// viewer.\n\t\t\t\t\tif n == 1 {\n\t\t\t\t\t\targs[0].TurnLengthIntoNumberIfZero()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Trim whitespace at the ends\n\t\t\t\tif args := *token.Children; len(args) > 0 {\n\t\t\t\t\targs[0].Whitespace &= ^css_ast.WhitespaceBefore\n\t\t\t\t\targs[len(args)-1].Whitespace &= ^css_ast.WhitespaceAfter\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn tokens\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_nesting.go",
    "content": "package css_parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\nfunc (p *parser) lowerNestingInRule(rule css_ast.Rule, results []css_ast.Rule) []css_ast.Rule {\n\tswitch r := rule.Data.(type) {\n\tcase *css_ast.RSelector:\n\t\tscope := func(loc logger.Loc) css_ast.ComplexSelector {\n\t\t\treturn css_ast.ComplexSelector{\n\t\t\t\tSelectors: []css_ast.CompoundSelector{{\n\t\t\t\t\tSubclassSelectors: []css_ast.SubclassSelector{{\n\t\t\t\t\t\tRange: logger.Range{Loc: loc},\n\t\t\t\t\t\tData:  &css_ast.SSPseudoClass{Name: \"scope\"},\n\t\t\t\t\t}},\n\t\t\t\t}},\n\t\t\t}\n\t\t}\n\n\t\tparentSelectorsWithPseudo := make([]css_ast.ComplexSelector, 0, len(r.Selectors))\n\t\tparentSelectorsNoPseudo := make([]css_ast.ComplexSelector, 0, len(r.Selectors))\n\t\tfor i, sel := range r.Selectors {\n\t\t\t// Top-level \"&\" should be replaced with \":scope\" to avoid recursion.\n\t\t\t// From https://www.w3.org/TR/css-nesting-1/#nest-selector:\n\t\t\t//\n\t\t\t//   \"When used in the selector of a nested style rule, the nesting\n\t\t\t//   selector represents the elements matched by the parent rule. When\n\t\t\t//   used in any other context, it represents the same elements as\n\t\t\t//   :scope in that context (unless otherwise defined).\"\n\t\t\t//\n\t\t\tsubstituted := make([]css_ast.CompoundSelector, 0, len(sel.Selectors))\n\t\t\tfor _, x := range sel.Selectors {\n\t\t\t\tsubstituted = p.substituteAmpersandsInCompoundSelector(x, scope, substituted, keepLeadingCombinator)\n\t\t\t}\n\t\t\tr.Selectors[i] = css_ast.ComplexSelector{Selectors: substituted}\n\n\t\t\t// Filter out pseudo elements because they are ignored by nested style\n\t\t\t// rules. This is because pseudo-elements are not valid within :is():\n\t\t\t// https://www.w3.org/TR/selectors-4/#matches-pseudo. This restriction\n\t\t\t// may be relaxed in the future, but this restriction has shipped so\n\t\t\t// we're stuck with it: https://github.com/w3c/csswg-drafts/issues/7433.\n\t\t\t//\n\t\t\t// Note: This is only for the parent selector list that is used to\n\t\t\t// substitute \"&\" within child rules. Do not filter out the pseudo\n\t\t\t// element from the top-level selector list.\n\t\t\tif !sel.UsesPseudoElement() {\n\t\t\t\tparentSelectorsNoPseudo = append(parentSelectorsNoPseudo, css_ast.ComplexSelector{Selectors: substituted})\n\t\t\t}\n\n\t\t\t// This filtering is only done conditionally because it seems to only\n\t\t\t// apply sometimes. Specifically it doesn't seem to apply when the\n\t\t\t// nested rule is an at-rule. So we use the unfiltered list in that\n\t\t\t// case. See: https://github.com/evanw/esbuild/issues/4265\n\t\t\tparentSelectorsWithPseudo = append(parentSelectorsWithPseudo, css_ast.ComplexSelector{Selectors: substituted})\n\t\t}\n\n\t\t// Emit this selector before its nested children\n\t\tstart := len(results)\n\t\tresults = append(results, rule)\n\n\t\t// Lower all children and filter out ones that become empty\n\t\tcontext := lowerNestingContext{\n\t\t\tparentSelectorsWithPseudo: parentSelectorsWithPseudo,\n\t\t\tparentSelectorsNoPseudo:   parentSelectorsNoPseudo,\n\t\t\tloweredRules:              results,\n\t\t}\n\t\tr.Rules = p.lowerNestingInRulesAndReturnRemaining(r.Rules, &context)\n\n\t\t// Omit this selector entirely if it's now empty\n\t\tif len(r.Rules) == 0 {\n\t\t\tcopy(context.loweredRules[start:], context.loweredRules[start+1:])\n\t\t\tcontext.loweredRules = context.loweredRules[:len(context.loweredRules)-1]\n\t\t}\n\t\treturn context.loweredRules\n\n\tcase *css_ast.RKnownAt:\n\t\tvar rules []css_ast.Rule\n\t\tfor _, child := range r.Rules {\n\t\t\trules = p.lowerNestingInRule(child, rules)\n\t\t}\n\t\tr.Rules = rules\n\n\tcase *css_ast.RAtLayer:\n\t\tvar rules []css_ast.Rule\n\t\tfor _, child := range r.Rules {\n\t\t\trules = p.lowerNestingInRule(child, rules)\n\t\t}\n\t\tr.Rules = rules\n\n\tcase *css_ast.RAtMedia:\n\t\tvar rules []css_ast.Rule\n\t\tfor _, child := range r.Rules {\n\t\t\trules = p.lowerNestingInRule(child, rules)\n\t\t}\n\t\tr.Rules = rules\n\t}\n\n\treturn append(results, rule)\n}\n\n// Lower all children and filter out ones that become empty\nfunc (p *parser) lowerNestingInRulesAndReturnRemaining(rules []css_ast.Rule, context *lowerNestingContext) []css_ast.Rule {\n\tn := 0\n\tfor _, child := range rules {\n\t\tchild = p.lowerNestingInRuleWithContext(child, context)\n\t\tif child.Data != nil {\n\t\t\trules[n] = child\n\t\t\tn++\n\t\t}\n\t}\n\treturn rules[:n]\n}\n\nfunc compoundSelectorTermCount(sel css_ast.CompoundSelector) int {\n\tcount := 0\n\tfor _, ss := range sel.SubclassSelectors {\n\t\tcount++\n\t\tif list, ok := ss.Data.(*css_ast.SSPseudoClassWithSelectorList); ok {\n\t\t\tcount += complexSelectorTermCount(list.Selectors)\n\t\t}\n\t}\n\treturn count\n}\n\nfunc complexSelectorTermCount(selectors []css_ast.ComplexSelector) int {\n\tcount := 0\n\tfor _, sel := range selectors {\n\t\tfor _, inner := range sel.Selectors {\n\t\t\tcount += compoundSelectorTermCount(inner)\n\t\t}\n\t}\n\treturn count\n}\n\nfunc (p *parser) addExpansionError(loc logger.Loc, n int) {\n\tp.log.AddErrorWithNotes(&p.tracker, logger.Range{Loc: loc}, \"CSS nesting is causing too much expansion\",\n\t\t[]logger.MsgData{{Text: fmt.Sprintf(\"CSS nesting expansion was terminated because a rule was generated with %d selectors. \"+\n\t\t\t\"This limit exists to prevent esbuild from using too much time and/or memory. \"+\n\t\t\t\"Please change your CSS to use fewer levels of nesting.\", n)}})\n}\n\ntype lowerNestingContext struct {\n\tparentSelectorsWithPseudo []css_ast.ComplexSelector\n\tparentSelectorsNoPseudo   []css_ast.ComplexSelector\n\tloweredRules              []css_ast.Rule\n}\n\nfunc (p *parser) lowerNestingInRuleWithContext(rule css_ast.Rule, context *lowerNestingContext) css_ast.Rule {\n\tswitch r := rule.Data.(type) {\n\tcase *css_ast.RSelector:\n\t\toldSelectorsLen := len(r.Selectors)\n\t\toldSelectorsComplexity := complexSelectorTermCount(r.Selectors)\n\n\t\t// \"a { & b {} }\" => \"a b {}\"\n\t\t// \"a { &b {} }\" => \"a:is(b) {}\"\n\t\t// \"a { &:hover {} }\" => \"a:hover {}\"\n\t\t// \".x { &b {} }\" => \"b.x {}\"\n\t\t// \"a, b { .c, d {} }\" => \":is(a, b) :is(.c, d) {}\"\n\t\t// \"a, b { &.c, & d, e & {} }\" => \":is(a, b).c, :is(a, b) d, e :is(a, b) {}\"\n\n\t\t// Pass 1: Canonicalize and analyze our selectors\n\t\tfor i := range r.Selectors {\n\t\t\tsel := &r.Selectors[i]\n\n\t\t\t// Inject the implicit \"&\" now for simplicity later on\n\t\t\tif sel.IsRelative() {\n\t\t\t\tsel.Selectors = append([]css_ast.CompoundSelector{{NestingSelectorLocs: []logger.Loc{rule.Loc}}}, sel.Selectors...)\n\t\t\t}\n\t\t}\n\n\t\t// Pass 2: Substitute \"&\" for the parent selector\n\t\tif !p.options.unsupportedCSSFeatures.Has(compat.IsPseudoClass) || len(context.parentSelectorsNoPseudo) <= 1 {\n\t\t\t// If we can use \":is\", or we don't have to because there's only one\n\t\t\t// parent selector, or we are using \":is()\" to match zero parent selectors\n\t\t\t// (even if \":is\" is unsupported), then substituting \"&\" for the parent\n\t\t\t// selector is easy.\n\t\t\tfor i := range r.Selectors {\n\t\t\t\tcomplex := &r.Selectors[i]\n\t\t\t\tresults := make([]css_ast.CompoundSelector, 0, len(complex.Selectors))\n\t\t\t\tparent := p.multipleComplexSelectorsToSingleComplexSelector(context.parentSelectorsNoPseudo)\n\t\t\t\tfor _, compound := range complex.Selectors {\n\t\t\t\t\tresults = p.substituteAmpersandsInCompoundSelector(compound, parent, results, keepLeadingCombinator)\n\t\t\t\t}\n\t\t\t\tcomplex.Selectors = results\n\t\t\t}\n\t\t} else {\n\t\t\t// Otherwise if we can't use \":is\", the transform is more complicated.\n\t\t\t// Avoiding \":is\" can lead to a combinatorial explosion of cases so we\n\t\t\t// want to avoid this if possible. For example:\n\t\t\t//\n\t\t\t//   .first, .second, .third {\n\t\t\t//     & > & {\n\t\t\t//       color: red;\n\t\t\t//     }\n\t\t\t//   }\n\t\t\t//\n\t\t\t// If we can use \":is\" (the easy case above) then we can do this:\n\t\t\t//\n\t\t\t//   :is(.first, .second, .third) > :is(.first, .second, .third) {\n\t\t\t//     color: red;\n\t\t\t//   }\n\t\t\t//\n\t\t\t// But if we can't use \":is\" then we have to do this instead:\n\t\t\t//\n\t\t\t//   .first > .first,\n\t\t\t//   .first > .second,\n\t\t\t//   .first > .third,\n\t\t\t//   .second > .first,\n\t\t\t//   .second > .second,\n\t\t\t//   .second > .third,\n\t\t\t//   .third > .first,\n\t\t\t//   .third > .second,\n\t\t\t//   .third > .third {\n\t\t\t//     color: red;\n\t\t\t//   }\n\t\t\t//\n\t\t\t// That combinatorial explosion is what the loop below implements. Note\n\t\t\t// that PostCSS's implementation of nesting gets this wrong. It generates\n\t\t\t// this instead:\n\t\t\t//\n\t\t\t//   .first > .first,\n\t\t\t//   .second > .second,\n\t\t\t//   .third > .third {\n\t\t\t//     color: red;\n\t\t\t//   }\n\t\t\t//\n\t\t\t// That's not equivalent, so that's an incorrect transformation.\n\t\t\tvar selectors []css_ast.ComplexSelector\n\t\t\tvar indices []int\n\t\t\tfor {\n\t\t\t\t// Every time we encounter another \"&\", add another dimension\n\t\t\t\toffset := 0\n\t\t\t\tparent := func(loc logger.Loc) css_ast.ComplexSelector {\n\t\t\t\t\tif offset == len(indices) {\n\t\t\t\t\t\tindices = append(indices, 0)\n\t\t\t\t\t}\n\t\t\t\t\tindex := indices[offset]\n\t\t\t\t\toffset++\n\t\t\t\t\treturn context.parentSelectorsNoPseudo[index]\n\t\t\t\t}\n\n\t\t\t\t// Do the substitution for this particular combination\n\t\t\t\tfor i := range r.Selectors {\n\t\t\t\t\tcomplex := r.Selectors[i]\n\t\t\t\t\tresults := make([]css_ast.CompoundSelector, 0, len(complex.Selectors))\n\t\t\t\t\tfor _, compound := range complex.Selectors {\n\t\t\t\t\t\tresults = p.substituteAmpersandsInCompoundSelector(compound, parent, results, keepLeadingCombinator)\n\t\t\t\t\t}\n\t\t\t\t\tcomplex.Selectors = results\n\t\t\t\t\tselectors = append(selectors, complex)\n\t\t\t\t\toffset = 0\n\t\t\t\t}\n\n\t\t\t\t// Do addition with carry on the indices across dimensions\n\t\t\t\tcarry := len(indices)\n\t\t\t\tfor carry > 0 {\n\t\t\t\t\tindex := &indices[carry-1]\n\t\t\t\t\tif *index+1 < len(context.parentSelectorsNoPseudo) {\n\t\t\t\t\t\t*index++\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\t*index = 0\n\t\t\t\t\tcarry--\n\t\t\t\t}\n\t\t\t\tif carry == 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tr.Selectors = selectors\n\t\t}\n\n\t\t// Put limits on the combinatorial explosion to avoid using too much time and/or memory\n\t\tif n := len(r.Selectors); n > oldSelectorsLen && n > 0xFF00 {\n\t\t\tp.addExpansionError(rule.Loc, n)\n\t\t\treturn css_ast.Rule{}\n\t\t}\n\t\tif n := complexSelectorTermCount(r.Selectors); n > oldSelectorsComplexity && n > 0xFF00 {\n\t\t\tp.addExpansionError(rule.Loc, n)\n\t\t\treturn css_ast.Rule{}\n\t\t}\n\n\t\t// Lower all child rules using our newly substituted selector\n\t\tcontext.loweredRules = p.lowerNestingInRule(rule, context.loweredRules)\n\t\treturn css_ast.Rule{}\n\n\tcase *css_ast.RKnownAt:\n\t\tchildContext := lowerNestingContext{\n\t\t\tparentSelectorsWithPseudo: context.parentSelectorsWithPseudo,\n\t\t\tparentSelectorsNoPseudo:   context.parentSelectorsNoPseudo,\n\t\t}\n\t\tr.Rules = p.lowerNestingInRulesAndReturnRemaining(r.Rules, &childContext)\n\n\t\t// \"div { @supports (color: red) { color: red } }\" \"@supports (color: red) { div { color: red } }\"\n\t\tif len(r.Rules) > 0 {\n\t\t\tchildContext.loweredRules = append([]css_ast.Rule{{Loc: rule.Loc, Data: &css_ast.RSelector{\n\t\t\t\tSelectors: context.parentSelectorsWithPseudo,\n\t\t\t\tRules:     r.Rules,\n\t\t\t}}}, childContext.loweredRules...)\n\t\t}\n\n\t\t// \"div { @supports (color: red) { &:hover { color: red } } }\" \"@supports (color: red) { div:hover { color: red } }\"\n\t\tif len(childContext.loweredRules) > 0 {\n\t\t\tr.Rules = childContext.loweredRules\n\t\t\tcontext.loweredRules = append(context.loweredRules, rule)\n\t\t}\n\n\t\treturn css_ast.Rule{}\n\n\tcase *css_ast.RAtMedia:\n\t\tchildContext := lowerNestingContext{\n\t\t\tparentSelectorsWithPseudo: context.parentSelectorsWithPseudo,\n\t\t\tparentSelectorsNoPseudo:   context.parentSelectorsNoPseudo,\n\t\t}\n\t\tr.Rules = p.lowerNestingInRulesAndReturnRemaining(r.Rules, &childContext)\n\n\t\t// \"div { @media screen { color: red } }\" \"@media screen { div { color: red } }\"\n\t\tif len(r.Rules) > 0 {\n\t\t\tchildContext.loweredRules = append([]css_ast.Rule{{Loc: rule.Loc, Data: &css_ast.RSelector{\n\t\t\t\tSelectors: context.parentSelectorsWithPseudo,\n\t\t\t\tRules:     r.Rules,\n\t\t\t}}}, childContext.loweredRules...)\n\t\t}\n\n\t\t// \"div { @media screen { &:hover { color: red } } }\" \"@media screen { div:hover { color: red } }\"\n\t\tif len(childContext.loweredRules) > 0 {\n\t\t\tr.Rules = childContext.loweredRules\n\t\t\tcontext.loweredRules = append(context.loweredRules, rule)\n\t\t}\n\n\t\treturn css_ast.Rule{}\n\n\tcase *css_ast.RAtLayer:\n\t\t// Lower all children and filter out ones that become empty\n\t\tchildContext := lowerNestingContext{\n\t\t\tparentSelectorsWithPseudo: context.parentSelectorsWithPseudo,\n\t\t\tparentSelectorsNoPseudo:   context.parentSelectorsNoPseudo,\n\t\t}\n\t\tr.Rules = p.lowerNestingInRulesAndReturnRemaining(r.Rules, &childContext)\n\n\t\t// \"div { @layer foo { color: red } }\" \"@layer foo { div { color: red } }\"\n\t\tif len(r.Rules) > 0 {\n\t\t\tchildContext.loweredRules = append([]css_ast.Rule{{Loc: rule.Loc, Data: &css_ast.RSelector{\n\t\t\t\tSelectors: context.parentSelectorsWithPseudo,\n\t\t\t\tRules:     r.Rules,\n\t\t\t}}}, childContext.loweredRules...)\n\t\t}\n\n\t\t// \"div { @layer foo { &:hover { color: red } } }\" \"@layer foo { div:hover { color: red } }\"\n\t\t// \"div { @layer foo {} }\" => \"@layer foo {}\" (layers have side effects, so don't remove empty ones)\n\t\tr.Rules = childContext.loweredRules\n\t\tcontext.loweredRules = append(context.loweredRules, rule)\n\t\treturn css_ast.Rule{}\n\t}\n\n\treturn rule\n}\n\ntype leadingCombinatorStrip uint8\n\nconst (\n\tkeepLeadingCombinator leadingCombinatorStrip = iota\n\tstripLeadingCombinator\n)\n\nfunc (p *parser) substituteAmpersandsInCompoundSelector(\n\tsel css_ast.CompoundSelector,\n\treplacementFn func(logger.Loc) css_ast.ComplexSelector,\n\tresults []css_ast.CompoundSelector,\n\tstrip leadingCombinatorStrip,\n) []css_ast.CompoundSelector {\n\tfor _, nestingSelectorLoc := range sel.NestingSelectorLocs {\n\t\treplacement := replacementFn(nestingSelectorLoc)\n\n\t\t// Convert the replacement to a single compound selector\n\t\tvar single css_ast.CompoundSelector\n\t\tif sel.Combinator.Byte == 0 && (len(replacement.Selectors) == 1 || len(results) == 0) {\n\t\t\t// \".foo { :hover & {} }\" => \":hover .foo {}\"\n\t\t\t// \".foo .bar { &:hover {} }\" => \".foo .bar:hover {}\"\n\t\t\tlast := len(replacement.Selectors) - 1\n\t\t\tresults = append(results, replacement.Selectors[:last]...)\n\t\t\tsingle = replacement.Selectors[last]\n\t\t\tif strip == stripLeadingCombinator {\n\t\t\t\tsingle.Combinator = css_ast.Combinator{}\n\t\t\t}\n\t\t\tsel.Combinator = single.Combinator\n\t\t} else if len(replacement.Selectors) == 1 {\n\t\t\t// \".foo { > &:hover {} }\" => \".foo > .foo:hover {}\"\n\t\t\tsingle = replacement.Selectors[0]\n\t\t\tif strip == stripLeadingCombinator {\n\t\t\t\tsingle.Combinator = css_ast.Combinator{}\n\t\t\t}\n\t\t} else {\n\t\t\t// \".foo .bar { :hover & {} }\" => \":hover :is(.foo .bar) {}\"\n\t\t\t// \".foo .bar { > &:hover {} }\" => \".foo .bar > :is(.foo .bar):hover {}\"\n\t\t\tp.reportNestingWithGeneratedPseudoClassIs(nestingSelectorLoc)\n\t\t\tsingle = css_ast.CompoundSelector{\n\t\t\t\tSubclassSelectors: []css_ast.SubclassSelector{{\n\t\t\t\t\tRange: logger.Range{Loc: nestingSelectorLoc},\n\t\t\t\t\tData: &css_ast.SSPseudoClassWithSelectorList{\n\t\t\t\t\t\tKind:      css_ast.PseudoClassIs,\n\t\t\t\t\t\tSelectors: []css_ast.ComplexSelector{replacement.Clone()},\n\t\t\t\t\t},\n\t\t\t\t}},\n\t\t\t}\n\t\t}\n\n\t\tvar subclassSelectorPrefix []css_ast.SubclassSelector\n\n\t\t// Insert the type selector\n\t\tif single.TypeSelector != nil {\n\t\t\tif sel.TypeSelector != nil {\n\t\t\t\tp.reportNestingWithGeneratedPseudoClassIs(nestingSelectorLoc)\n\t\t\t\tsubclassSelectorPrefix = append(subclassSelectorPrefix, css_ast.SubclassSelector{\n\t\t\t\t\tRange: sel.TypeSelector.Range(),\n\t\t\t\t\tData: &css_ast.SSPseudoClassWithSelectorList{\n\t\t\t\t\t\tKind:      css_ast.PseudoClassIs,\n\t\t\t\t\t\tSelectors: []css_ast.ComplexSelector{{Selectors: []css_ast.CompoundSelector{{TypeSelector: sel.TypeSelector}}}},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\t\t\tsel.TypeSelector = single.TypeSelector\n\t\t}\n\n\t\t// Insert the subclass selectors\n\t\tsubclassSelectorPrefix = append(subclassSelectorPrefix, single.SubclassSelectors...)\n\n\t\t// Write the changes back\n\t\tif len(subclassSelectorPrefix) > 0 {\n\t\t\tsel.SubclassSelectors = append(subclassSelectorPrefix, sel.SubclassSelectors...)\n\t\t}\n\t}\n\tsel.NestingSelectorLocs = nil\n\n\t// \"div { :is(&.foo) {} }\" => \":is(div.foo) {}\"\n\tfor _, ss := range sel.SubclassSelectors {\n\t\tif class, ok := ss.Data.(*css_ast.SSPseudoClassWithSelectorList); ok {\n\t\t\touter := make([]css_ast.ComplexSelector, 0, len(class.Selectors))\n\t\t\tfor _, complex := range class.Selectors {\n\t\t\t\tinner := make([]css_ast.CompoundSelector, 0, len(complex.Selectors))\n\t\t\t\tfor _, sel := range complex.Selectors {\n\t\t\t\t\tinner = p.substituteAmpersandsInCompoundSelector(sel, replacementFn, inner, stripLeadingCombinator)\n\t\t\t\t}\n\t\t\t\touter = append(outer, css_ast.ComplexSelector{Selectors: inner})\n\t\t\t}\n\t\t\tclass.Selectors = outer\n\t\t}\n\t}\n\n\treturn append(results, sel)\n}\n\n// Turn the list of selectors into a single selector by wrapping lists\n// without a single element with \":is(...)\". Note that this may result\n// in an empty \":is()\" selector (which matches nothing).\nfunc (p *parser) multipleComplexSelectorsToSingleComplexSelector(selectors []css_ast.ComplexSelector) func(logger.Loc) css_ast.ComplexSelector {\n\tif len(selectors) == 1 {\n\t\treturn func(logger.Loc) css_ast.ComplexSelector {\n\t\t\treturn selectors[0]\n\t\t}\n\t}\n\n\tvar leadingCombinator css_ast.Combinator\n\tclones := make([]css_ast.ComplexSelector, len(selectors))\n\n\tfor i, sel := range selectors {\n\t\t// \"> a, > b\" => \"> :is(a, b)\" (the caller should have already checked that all leading combinators are the same)\n\t\tleadingCombinator = sel.Selectors[0].Combinator\n\t\tclones[i] = sel.Clone()\n\t}\n\n\treturn func(loc logger.Loc) css_ast.ComplexSelector {\n\t\treturn css_ast.ComplexSelector{\n\t\t\tSelectors: []css_ast.CompoundSelector{{\n\t\t\t\tCombinator: leadingCombinator,\n\t\t\t\tSubclassSelectors: []css_ast.SubclassSelector{{\n\t\t\t\t\tRange: logger.Range{Loc: loc},\n\t\t\t\t\tData: &css_ast.SSPseudoClassWithSelectorList{\n\t\t\t\t\t\tKind:      css_ast.PseudoClassIs,\n\t\t\t\t\t\tSelectors: clones,\n\t\t\t\t\t},\n\t\t\t\t}},\n\t\t\t}},\n\t\t}\n\t}\n}\n\nfunc (p *parser) reportNestingWithGeneratedPseudoClassIs(nestingSelectorLoc logger.Loc) {\n\tif p.options.unsupportedCSSFeatures.Has(compat.IsPseudoClass) {\n\t\t_, didWarn := p.nestingWarnings[nestingSelectorLoc]\n\t\tif didWarn {\n\t\t\t// Only warn at each location once\n\t\t\treturn\n\t\t}\n\t\tif p.nestingWarnings == nil {\n\t\t\tp.nestingWarnings = make(map[logger.Loc]struct{})\n\t\t}\n\t\tp.nestingWarnings[nestingSelectorLoc] = struct{}{}\n\t\ttext := \"Transforming this CSS nesting syntax is not supported in the configured target environment\"\n\t\tif p.options.originalTargetEnv != \"\" {\n\t\t\ttext = fmt.Sprintf(\"%s (%s)\", text, p.options.originalTargetEnv)\n\t\t}\n\t\tr := logger.Range{Loc: nestingSelectorLoc, Len: 1}\n\t\tp.log.AddIDWithNotes(logger.MsgID_CSS_UnsupportedCSSNesting, logger.Warning, &p.tracker, r, text, []logger.MsgData{{\n\t\t\tText: \"The nesting transform for this case must generate an \\\":is(...)\\\" but the configured target environment does not support the \\\":is\\\" pseudo-class.\"}})\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_parser.go",
    "content": "package css_parser\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/config\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\n// This is mostly a normal CSS parser with one exception: the addition of\n// support for parsing https://drafts.csswg.org/css-nesting-1/.\n\ntype parser struct {\n\tlog               logger.Log\n\tsource            logger.Source\n\ttokens            []css_lexer.Token\n\tallComments       []logger.Range\n\tlegalComments     []css_lexer.Comment\n\tstack             []css_lexer.T\n\timportRecords     []ast.ImportRecord\n\tsymbols           []ast.Symbol\n\tcomposes          map[ast.Ref]*css_ast.Composes\n\tlocalSymbols      []ast.LocRef\n\tlocalScope        map[string]ast.LocRef\n\tglobalScope       map[string]ast.LocRef\n\tnestingWarnings   map[logger.Loc]struct{}\n\ttracker           logger.LineColumnTracker\n\tenclosingAtMedia  [][]css_ast.MediaQuery\n\tlayersPreImport   [][]string\n\tlayersPostImport  [][]string\n\tenclosingLayer    []string\n\tanonLayerCount    int\n\tindex             int\n\tlegalCommentIndex int\n\tinSelectorSubtree int\n\tprevError         logger.Loc\n\toptions           Options\n\tnestingIsPresent  bool\n\tmakeLocalSymbols  bool\n\thasSeenAtImport   bool\n}\n\ntype Options struct {\n\tcssPrefixData map[css_ast.D]compat.CSSPrefix\n\n\t// This is an embedded struct. Always access these directly instead of off\n\t// the name \"optionsThatSupportStructuralEquality\". This is only grouped like\n\t// this to make the equality comparison easier and safer (and hopefully faster).\n\toptionsThatSupportStructuralEquality\n}\n\ntype symbolMode uint8\n\nconst (\n\tsymbolModeDisabled symbolMode = iota\n\tsymbolModeGlobal\n\tsymbolModeLocal\n)\n\ntype optionsThatSupportStructuralEquality struct {\n\toriginalTargetEnv      string\n\tunsupportedCSSFeatures compat.CSSFeature\n\tminifySyntax           bool\n\tminifyWhitespace       bool\n\tminifyIdentifiers      bool\n\tsymbolMode             symbolMode\n}\n\nfunc OptionsFromConfig(loader config.Loader, options *config.Options) Options {\n\tvar symbolMode symbolMode\n\tswitch loader {\n\tcase config.LoaderGlobalCSS:\n\t\tsymbolMode = symbolModeGlobal\n\tcase config.LoaderLocalCSS:\n\t\tsymbolMode = symbolModeLocal\n\t}\n\n\treturn Options{\n\t\tcssPrefixData: options.CSSPrefixData,\n\n\t\toptionsThatSupportStructuralEquality: optionsThatSupportStructuralEquality{\n\t\t\tminifySyntax:           options.MinifySyntax,\n\t\t\tminifyWhitespace:       options.MinifyWhitespace,\n\t\t\tminifyIdentifiers:      options.MinifyIdentifiers,\n\t\t\tunsupportedCSSFeatures: options.UnsupportedCSSFeatures,\n\t\t\toriginalTargetEnv:      options.OriginalTargetEnv,\n\t\t\tsymbolMode:             symbolMode,\n\t\t},\n\t}\n}\n\nfunc (a *Options) Equal(b *Options) bool {\n\t// Compare \"optionsThatSupportStructuralEquality\"\n\tif a.optionsThatSupportStructuralEquality != b.optionsThatSupportStructuralEquality {\n\t\treturn false\n\t}\n\n\t// Compare \"cssPrefixData\"\n\tif len(a.cssPrefixData) != len(b.cssPrefixData) {\n\t\treturn false\n\t}\n\tfor k, va := range a.cssPrefixData {\n\t\tvb, ok := b.cssPrefixData[k]\n\t\tif !ok || va != vb {\n\t\t\treturn false\n\t\t}\n\t}\n\tfor k := range b.cssPrefixData {\n\t\tif _, ok := b.cssPrefixData[k]; !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc Parse(log logger.Log, source logger.Source, options Options) css_ast.AST {\n\tresult := css_lexer.Tokenize(log, source, css_lexer.Options{\n\t\tRecordAllComments: options.minifyIdentifiers,\n\t})\n\tp := parser{\n\t\tlog:              log,\n\t\tsource:           source,\n\t\ttracker:          logger.MakeLineColumnTracker(&source),\n\t\toptions:          options,\n\t\ttokens:           result.Tokens,\n\t\tallComments:      result.AllComments,\n\t\tlegalComments:    result.LegalComments,\n\t\tprevError:        logger.Loc{Start: -1},\n\t\tcomposes:         make(map[ast.Ref]*css_ast.Composes),\n\t\tlocalScope:       make(map[string]ast.LocRef),\n\t\tglobalScope:      make(map[string]ast.LocRef),\n\t\tmakeLocalSymbols: options.symbolMode == symbolModeLocal,\n\t}\n\trules := p.parseListOfRules(ruleContext{\n\t\tisTopLevel:     true,\n\t\tparseSelectors: true,\n\t})\n\tp.expect(css_lexer.TEndOfFile)\n\treturn css_ast.AST{\n\t\tRules:                rules,\n\t\tCharFreq:             p.computeCharacterFrequency(),\n\t\tSymbols:              p.symbols,\n\t\tImportRecords:        p.importRecords,\n\t\tApproximateLineCount: result.ApproximateLineCount,\n\t\tSourceMapComment:     result.SourceMapComment,\n\t\tLocalSymbols:         p.localSymbols,\n\t\tLocalScope:           p.localScope,\n\t\tGlobalScope:          p.globalScope,\n\t\tComposes:             p.composes,\n\t\tLayersPreImport:      p.layersPreImport,\n\t\tLayersPostImport:     p.layersPostImport,\n\t}\n}\n\n// Compute a character frequency histogram for everything that's not a bound\n// symbol. This is used to modify how minified names are generated for slightly\n// better gzip compression. Even though it's a very small win, we still do it\n// because it's simple to do and very cheap to compute.\nfunc (p *parser) computeCharacterFrequency() *ast.CharFreq {\n\tif !p.options.minifyIdentifiers {\n\t\treturn nil\n\t}\n\n\t// Add everything in the file to the histogram\n\tcharFreq := &ast.CharFreq{}\n\tcharFreq.Scan(p.source.Contents, 1)\n\n\t// Subtract out all comments\n\tfor _, commentRange := range p.allComments {\n\t\tcharFreq.Scan(p.source.TextForRange(commentRange), -1)\n\t}\n\n\t// Subtract out all import paths\n\tfor _, record := range p.importRecords {\n\t\tif !record.SourceIndex.IsValid() {\n\t\t\tcharFreq.Scan(record.Path.Text, -1)\n\t\t}\n\t}\n\n\t// Subtract out all symbols that will be minified\n\tfor _, symbol := range p.symbols {\n\t\tif symbol.Kind == ast.SymbolLocalCSS {\n\t\t\tcharFreq.Scan(symbol.OriginalName, -int32(symbol.UseCountEstimate))\n\t\t}\n\t}\n\n\treturn charFreq\n}\n\nfunc (p *parser) advance() {\n\tif p.index < len(p.tokens) {\n\t\tp.index++\n\t}\n}\n\nfunc (p *parser) at(index int) css_lexer.Token {\n\tif index < len(p.tokens) {\n\t\treturn p.tokens[index]\n\t}\n\treturn css_lexer.Token{\n\t\tKind:  css_lexer.TEndOfFile,\n\t\tRange: logger.Range{Loc: logger.Loc{Start: int32(len(p.source.Contents))}},\n\t}\n}\n\nfunc (p *parser) current() css_lexer.Token {\n\treturn p.at(p.index)\n}\n\nfunc (p *parser) next() css_lexer.Token {\n\treturn p.at(p.index + 1)\n}\n\nfunc (p *parser) raw() string {\n\tt := p.current()\n\treturn p.source.Contents[t.Range.Loc.Start:t.Range.End()]\n}\n\nfunc (p *parser) decoded() string {\n\treturn p.current().DecodedText(p.source.Contents)\n}\n\nfunc (p *parser) peek(kind css_lexer.T) bool {\n\treturn kind == p.current().Kind\n}\n\nfunc (p *parser) eat(kind css_lexer.T) bool {\n\tif p.peek(kind) {\n\t\tp.advance()\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (p *parser) expect(kind css_lexer.T) bool {\n\treturn p.expectWithMatchingLoc(kind, logger.Loc{Start: -1})\n}\n\nfunc (p *parser) expectWithMatchingLoc(kind css_lexer.T, matchingLoc logger.Loc) bool {\n\tif p.eat(kind) {\n\t\treturn true\n\t}\n\tt := p.current()\n\tif (t.Flags & css_lexer.DidWarnAboutSingleLineComment) != 0 {\n\t\treturn false\n\t}\n\n\tvar text string\n\tvar suggestion string\n\tvar notes []logger.MsgData\n\n\texpected := kind.String()\n\tif strings.HasPrefix(expected, \"\\\"\") && strings.HasSuffix(expected, \"\\\"\") {\n\t\tsuggestion = expected[1 : len(expected)-1]\n\t}\n\n\tif (kind == css_lexer.TSemicolon || kind == css_lexer.TColon) && p.index > 0 && p.at(p.index-1).Kind == css_lexer.TWhitespace {\n\t\t// Have a nice error message for forgetting a trailing semicolon or colon\n\t\ttext = fmt.Sprintf(\"Expected %s\", expected)\n\t\tt = p.at(p.index - 1)\n\t} else if (kind == css_lexer.TCloseBrace || kind == css_lexer.TCloseBracket || kind == css_lexer.TCloseParen) &&\n\t\tmatchingLoc.Start != -1 && int(matchingLoc.Start)+1 <= len(p.source.Contents) {\n\t\t// Have a nice error message for forgetting a closing brace/bracket/parenthesis\n\t\tc := p.source.Contents[matchingLoc.Start : matchingLoc.Start+1]\n\t\ttext = fmt.Sprintf(\"Expected %s to go with %q\", expected, c)\n\t\tnotes = append(notes, p.tracker.MsgData(logger.Range{Loc: matchingLoc, Len: 1}, fmt.Sprintf(\"The unbalanced %q is here:\", c)))\n\t} else {\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TEndOfFile, css_lexer.TWhitespace:\n\t\t\ttext = fmt.Sprintf(\"Expected %s but found %s\", expected, t.Kind.String())\n\t\t\tt.Range.Len = 0\n\t\tcase css_lexer.TBadURL, css_lexer.TUnterminatedString:\n\t\t\ttext = fmt.Sprintf(\"Expected %s but found %s\", expected, t.Kind.String())\n\t\tdefault:\n\t\t\ttext = fmt.Sprintf(\"Expected %s but found %q\", expected, p.raw())\n\t\t}\n\t}\n\n\tif t.Range.Loc.Start > p.prevError.Start {\n\t\tdata := p.tracker.MsgData(t.Range, text)\n\t\tdata.Location.Suggestion = suggestion\n\t\tp.log.AddMsgID(logger.MsgID_CSS_CSSSyntaxError, logger.Msg{Kind: logger.Warning, Data: data, Notes: notes})\n\t\tp.prevError = t.Range.Loc\n\t}\n\treturn false\n}\n\nfunc (p *parser) unexpected() {\n\tif t := p.current(); t.Range.Loc.Start > p.prevError.Start && (t.Flags&css_lexer.DidWarnAboutSingleLineComment) == 0 {\n\t\tvar text string\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TEndOfFile, css_lexer.TWhitespace:\n\t\t\ttext = fmt.Sprintf(\"Unexpected %s\", t.Kind.String())\n\t\t\tt.Range.Len = 0\n\t\tcase css_lexer.TBadURL, css_lexer.TUnterminatedString:\n\t\t\ttext = fmt.Sprintf(\"Unexpected %s\", t.Kind.String())\n\t\tdefault:\n\t\t\ttext = fmt.Sprintf(\"Unexpected %q\", p.raw())\n\t\t}\n\t\tp.log.AddID(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, t.Range, text)\n\t\tp.prevError = t.Range.Loc\n\t}\n}\n\nfunc (p *parser) symbolForName(loc logger.Loc, name string) ast.LocRef {\n\tvar kind ast.SymbolKind\n\tvar scope map[string]ast.LocRef\n\n\tif p.makeLocalSymbols {\n\t\tkind = ast.SymbolLocalCSS\n\t\tscope = p.localScope\n\t} else {\n\t\tkind = ast.SymbolGlobalCSS\n\t\tscope = p.globalScope\n\t}\n\n\tentry, ok := scope[name]\n\tif !ok {\n\t\tentry = ast.LocRef{\n\t\t\tLoc: loc,\n\t\t\tRef: ast.Ref{\n\t\t\t\tSourceIndex: p.source.Index,\n\t\t\t\tInnerIndex:  uint32(len(p.symbols)),\n\t\t\t},\n\t\t}\n\t\tp.symbols = append(p.symbols, ast.Symbol{\n\t\t\tKind:         kind,\n\t\t\tOriginalName: name,\n\t\t\tLink:         ast.InvalidRef,\n\t\t})\n\t\tscope[name] = entry\n\t\tif kind == ast.SymbolLocalCSS {\n\t\t\tp.localSymbols = append(p.localSymbols, entry)\n\t\t}\n\t}\n\n\tp.symbols[entry.Ref.InnerIndex].UseCountEstimate++\n\treturn entry\n}\n\nfunc (p *parser) recordAtLayerRule(layers [][]string) {\n\tif p.anonLayerCount > 0 {\n\t\treturn\n\t}\n\n\tfor _, layer := range layers {\n\t\tif len(p.enclosingLayer) > 0 {\n\t\t\tclone := make([]string, 0, len(p.enclosingLayer)+len(layer))\n\t\t\tlayer = append(append(clone, p.enclosingLayer...), layer...)\n\t\t}\n\t\tp.layersPostImport = append(p.layersPostImport, layer)\n\t}\n}\n\ntype ruleContext struct {\n\tisTopLevel     bool\n\tparseSelectors bool\n}\n\nfunc (p *parser) parseListOfRules(context ruleContext) []css_ast.Rule {\n\tatRuleContext := atRuleContext{}\n\tif context.isTopLevel {\n\t\tatRuleContext.charsetValidity = atRuleValid\n\t\tatRuleContext.importValidity = atRuleValid\n\t\tatRuleContext.isTopLevel = true\n\t}\n\trules := []css_ast.Rule{}\n\tdidFindAtImport := false\n\nloop:\n\tfor {\n\t\tif context.isTopLevel {\n\t\t\tp.nestingIsPresent = false\n\t\t}\n\n\t\t// If there are any legal comments immediately before the current token,\n\t\t// turn them all into comment rules and append them to the current rule list\n\t\tfor p.legalCommentIndex < len(p.legalComments) {\n\t\t\tcomment := p.legalComments[p.legalCommentIndex]\n\t\t\tif comment.TokenIndexAfter > uint32(p.index) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif comment.TokenIndexAfter == uint32(p.index) {\n\t\t\t\trules = append(rules, css_ast.Rule{Loc: comment.Loc, Data: &css_ast.RComment{Text: comment.Text}})\n\t\t\t}\n\t\t\tp.legalCommentIndex++\n\t\t}\n\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TEndOfFile:\n\t\t\tbreak loop\n\n\t\tcase css_lexer.TCloseBrace:\n\t\t\tif !context.isTopLevel {\n\t\t\t\tbreak loop\n\t\t\t}\n\n\t\tcase css_lexer.TWhitespace:\n\t\t\tp.advance()\n\t\t\tcontinue\n\n\t\tcase css_lexer.TAtKeyword:\n\t\t\trule := p.parseAtRule(atRuleContext)\n\n\t\t\t// Disallow \"@charset\" and \"@import\" after other rules\n\t\t\tif context.isTopLevel {\n\t\t\t\tswitch r := rule.Data.(type) {\n\t\t\t\tcase *css_ast.RAtCharset:\n\t\t\t\t\t// This doesn't invalidate anything because it always comes first\n\n\t\t\t\tcase *css_ast.RAtImport:\n\t\t\t\t\tdidFindAtImport = true\n\t\t\t\t\tif atRuleContext.charsetValidity == atRuleValid {\n\t\t\t\t\t\tatRuleContext.afterLoc = rule.Loc\n\t\t\t\t\t\tatRuleContext.charsetValidity = atRuleInvalidAfter\n\t\t\t\t\t}\n\n\t\t\t\tcase *css_ast.RAtLayer:\n\t\t\t\t\tif atRuleContext.charsetValidity == atRuleValid {\n\t\t\t\t\t\tatRuleContext.afterLoc = rule.Loc\n\t\t\t\t\t\tatRuleContext.charsetValidity = atRuleInvalidAfter\n\t\t\t\t\t}\n\n\t\t\t\t\t// From the specification: \"Note: No @layer rules are allowed between\n\t\t\t\t\t// @import and @namespace rules. Any @layer rule that comes after an\n\t\t\t\t\t// @import or @namespace rule will cause any subsequent @import or\n\t\t\t\t\t// @namespace rules to be ignored.\"\n\t\t\t\t\tif atRuleContext.importValidity == atRuleValid && (r.Rules != nil || didFindAtImport) {\n\t\t\t\t\t\tatRuleContext.afterLoc = rule.Loc\n\t\t\t\t\t\tatRuleContext.charsetValidity = atRuleInvalidAfter\n\t\t\t\t\t\tatRuleContext.importValidity = atRuleInvalidAfter\n\t\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\tif atRuleContext.importValidity == atRuleValid {\n\t\t\t\t\t\tatRuleContext.afterLoc = rule.Loc\n\t\t\t\t\t\tatRuleContext.charsetValidity = atRuleInvalidAfter\n\t\t\t\t\t\tatRuleContext.importValidity = atRuleInvalidAfter\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Lower CSS nesting if it's not supported (but only at the top level)\n\t\t\tif p.nestingIsPresent && p.options.unsupportedCSSFeatures.Has(compat.Nesting) && context.isTopLevel {\n\t\t\t\trules = p.lowerNestingInRule(rule, rules)\n\t\t\t} else {\n\t\t\t\trules = append(rules, rule)\n\t\t\t}\n\t\t\tcontinue\n\n\t\tcase css_lexer.TCDO, css_lexer.TCDC:\n\t\t\tif context.isTopLevel {\n\t\t\t\tp.advance()\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif atRuleContext.importValidity == atRuleValid {\n\t\t\tatRuleContext.afterLoc = p.current().Range.Loc\n\t\t\tatRuleContext.charsetValidity = atRuleInvalidAfter\n\t\t\tatRuleContext.importValidity = atRuleInvalidAfter\n\t\t}\n\n\t\t// Note: CSS recently changed to parse and discard declarations\n\t\t// here instead of treating them as the start of a qualified rule.\n\t\t// See also: https://github.com/w3c/csswg-drafts/issues/8834\n\t\tif !context.isTopLevel {\n\t\t\tif scan, index := p.scanForEndOfRule(); scan == endOfRuleSemicolon {\n\t\t\t\ttokens := p.convertTokens(p.tokens[p.index:index])\n\t\t\t\trules = append(rules, css_ast.Rule{Loc: p.current().Range.Loc, Data: &css_ast.RBadDeclaration{Tokens: tokens}})\n\t\t\t\tp.index = index + 1\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tvar rule css_ast.Rule\n\t\tif context.parseSelectors {\n\t\t\trule = p.parseSelectorRule(context.isTopLevel, parseSelectorOpts{})\n\t\t} else {\n\t\t\trule = p.parseQualifiedRule(parseQualifiedRuleOpts{isTopLevel: context.isTopLevel})\n\t\t}\n\n\t\t// Lower CSS nesting if it's not supported (but only at the top level)\n\t\tif p.nestingIsPresent && p.options.unsupportedCSSFeatures.Has(compat.Nesting) && context.isTopLevel {\n\t\t\trules = p.lowerNestingInRule(rule, rules)\n\t\t} else {\n\t\t\trules = append(rules, rule)\n\t\t}\n\t}\n\n\tif p.options.minifySyntax {\n\t\trules = p.mangleRules(rules, context.isTopLevel)\n\t}\n\treturn rules\n}\n\ntype listOfDeclarationsOpts struct {\n\tcomposesContext      *composesContext\n\tcanInlineNoOpNesting bool\n}\n\nfunc (p *parser) parseListOfDeclarations(opts listOfDeclarationsOpts) (list []css_ast.Rule) {\n\tlist = []css_ast.Rule{}\n\tfoundNesting := false\n\n\tfor {\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TWhitespace, css_lexer.TSemicolon:\n\t\t\tp.advance()\n\n\t\tcase css_lexer.TEndOfFile, css_lexer.TCloseBrace:\n\t\t\tlist = p.processDeclarations(list, opts.composesContext)\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tlist = p.mangleRules(list, false /* isTopLevel */)\n\n\t\t\t\t// Pull out all unnecessarily-nested declarations and stick them at the end\n\t\t\t\tif opts.canInlineNoOpNesting {\n\t\t\t\t\t// \"a { & { x: y } }\" => \"a { x: y }\"\n\t\t\t\t\t// \"a { & { b: c } d: e }\" => \"a { d: e; b: c }\"\n\t\t\t\t\tif foundNesting {\n\t\t\t\t\t\tvar inlineDecls []css_ast.Rule\n\t\t\t\t\t\tn := 0\n\t\t\t\t\t\tfor _, rule := range list {\n\t\t\t\t\t\t\tif rule, ok := rule.Data.(*css_ast.RSelector); ok && len(rule.Selectors) == 1 {\n\t\t\t\t\t\t\t\tif sel := rule.Selectors[0]; len(sel.Selectors) == 1 && sel.Selectors[0].IsSingleAmpersand() {\n\t\t\t\t\t\t\t\t\tinlineDecls = append(inlineDecls, rule.Rules...)\n\t\t\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlist[n] = rule\n\t\t\t\t\t\t\tn++\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlist = append(list[:n], inlineDecls...)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// \"a, b::before { & { x: y } }\" => \"a, b::before { & { x: y } }\"\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\n\t\tcase css_lexer.TAtKeyword:\n\t\t\tif p.inSelectorSubtree > 0 {\n\t\t\t\tp.nestingIsPresent = true\n\t\t\t}\n\t\t\tlist = append(list, p.parseAtRule(atRuleContext{\n\t\t\t\tisDeclarationList:    true,\n\t\t\t\tcanInlineNoOpNesting: opts.canInlineNoOpNesting,\n\t\t\t}))\n\n\t\t// Reference: https://drafts.csswg.org/css-nesting-1/\n\t\tdefault:\n\t\t\tif scan, _ := p.scanForEndOfRule(); scan == endOfRuleOpenBrace {\n\t\t\t\tp.nestingIsPresent = true\n\t\t\t\tfoundNesting = true\n\t\t\t\trule := p.parseSelectorRule(false, parseSelectorOpts{\n\t\t\t\t\tisDeclarationContext: true,\n\t\t\t\t\tcomposesContext:      opts.composesContext,\n\t\t\t\t})\n\n\t\t\t\t// If this rule was a single \":global\" or \":local\", inline it here. This\n\t\t\t\t// is handled differently than a bare \"&\" with normal CSS nesting because\n\t\t\t\t// that would be inlined at the end of the parent rule's body instead,\n\t\t\t\t// which is probably unexpected (e.g. it would trip people up when trying\n\t\t\t\t// to write rules in a specific order).\n\t\t\t\tif sel, ok := rule.Data.(*css_ast.RSelector); ok && len(sel.Selectors) == 1 {\n\t\t\t\t\tif first := sel.Selectors[0]; len(first.Selectors) == 1 {\n\t\t\t\t\t\tif first := first.Selectors[0]; first.WasEmptyFromLocalOrGlobal && first.IsSingleAmpersand() {\n\t\t\t\t\t\t\tlist = append(list, sel.Rules...)\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlist = append(list, rule)\n\t\t\t} else {\n\t\t\t\tlist = append(list, p.parseDeclaration())\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (p *parser) mangleRules(rules []css_ast.Rule, isTopLevel bool) []css_ast.Rule {\n\t// Remove empty rules\n\tmangledRules := make([]css_ast.Rule, 0, len(rules))\n\tvar prevNonComment css_ast.R\nnext:\n\tfor _, rule := range rules {\n\t\tnextNonComment := rule.Data\n\n\t\tswitch r := rule.Data.(type) {\n\t\tcase *css_ast.RAtKeyframes:\n\t\t\t// Do not remove empty \"@keyframe foo {}\" rules. Even empty rules still\n\t\t\t// dispatch JavaScript animation events, so removing them changes\n\t\t\t// behavior: https://bugzilla.mozilla.org/show_bug.cgi?id=1004377.\n\n\t\tcase *css_ast.RAtLayer:\n\t\t\tif len(r.Rules) == 0 && len(r.Names) > 0 {\n\t\t\t\t// Do not remove empty \"@layer foo {}\" rules. The specification says:\n\t\t\t\t// \"Cascade layers are sorted by the order in which they first are\n\t\t\t\t// declared, with nested layers grouped within their parent layers\n\t\t\t\t// before any unlayered rules.\" So removing empty rules could change\n\t\t\t\t// the order in which they are first declared, and is therefore invalid.\n\t\t\t\t//\n\t\t\t\t// We can turn \"@layer foo {}\" into \"@layer foo;\" to be shorter. But\n\t\t\t\t// don't collapse anonymous \"@layer {}\" into \"@layer;\" because that is\n\t\t\t\t// a syntax error.\n\t\t\t\tr.Rules = nil\n\t\t\t} else if len(r.Rules) == 1 && len(r.Names) == 1 {\n\t\t\t\t// Only collapse layers if each layer has exactly one name\n\t\t\t\tif r2, ok := r.Rules[0].Data.(*css_ast.RAtLayer); ok && len(r2.Names) == 1 {\n\t\t\t\t\t// \"@layer a { @layer b {} }\" => \"@layer a.b;\"\n\t\t\t\t\t// \"@layer a { @layer b { c {} } }\" => \"@layer a.b { c {} }\"\n\t\t\t\t\tr.Names[0] = append(r.Names[0], r2.Names[0]...)\n\t\t\t\t\tr.Rules = r2.Rules\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *css_ast.RKnownAt:\n\t\t\tif len(r.Rules) == 0 && atKnownRuleCanBeRemovedIfEmpty[r.AtToken] {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\tcase *css_ast.RAtMedia:\n\t\t\tif len(r.Rules) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Unwrap \"@media\" rules that duplicate conditions from a parent \"@media\"\n\t\t\t// rule. This is unlikely to be authored manually but can be automatically\n\t\t\t// generated when using a CSS framework such as Tailwind.\n\t\t\t//\n\t\t\t//   @media (min-width: 1024px) {\n\t\t\t//     .md\\:class {\n\t\t\t//       color: red;\n\t\t\t//     }\n\t\t\t//     @media (min-width: 1024px) {\n\t\t\t//       .md\\:class {\n\t\t\t//         color: red;\n\t\t\t//       }\n\t\t\t//     }\n\t\t\t//   }\n\t\t\t//\n\t\t\t// This converts that code into the following:\n\t\t\t//\n\t\t\t//   @media (min-width: 1024px) {\n\t\t\t//     .md\\:class {\n\t\t\t//       color: red;\n\t\t\t//     }\n\t\t\t//     .md\\:class {\n\t\t\t//       color: red;\n\t\t\t//     }\n\t\t\t//   }\n\t\t\t//\n\t\t\t// Which can then be mangled further.\n\t\t\tfor _, queries := range p.enclosingAtMedia {\n\t\t\t\tif css_ast.MediaQueriesEqual(r.Queries, queries, nil) {\n\t\t\t\t\tmangledRules = append(mangledRules, r.Rules...)\n\t\t\t\t\tcontinue next\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *css_ast.RSelector:\n\t\t\tif len(r.Rules) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Merge adjacent selectors with the same content\n\t\t\t// \"a { color: red; } b { color: red; }\" => \"a, b { color: red; }\"\n\t\t\tif prevNonComment != nil {\n\t\t\t\tif r, ok := rule.Data.(*css_ast.RSelector); ok {\n\t\t\t\t\tif prev, ok := prevNonComment.(*css_ast.RSelector); ok && css_ast.RulesEqual(r.Rules, prev.Rules, nil) &&\n\t\t\t\t\t\tisSafeSelectors(r.Selectors) && isSafeSelectors(prev.Selectors) {\n\t\t\t\t\tnextSelector:\n\t\t\t\t\t\tfor _, sel := range r.Selectors {\n\t\t\t\t\t\t\tfor _, prevSel := range prev.Selectors {\n\t\t\t\t\t\t\t\tif sel.Equal(prevSel, nil) {\n\t\t\t\t\t\t\t\t\t// Don't add duplicate selectors more than once\n\t\t\t\t\t\t\t\t\tcontinue nextSelector\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tprev.Selectors = append(prev.Selectors, sel)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *css_ast.RComment:\n\t\t\tnextNonComment = nil\n\t\t}\n\n\t\tif nextNonComment != nil {\n\t\t\tprevNonComment = nextNonComment\n\t\t}\n\n\t\tmangledRules = append(mangledRules, rule)\n\t}\n\n\t// Mangle non-top-level rules using a back-to-front pass. Top-level rules\n\t// will be mangled by the linker instead for cross-file rule mangling.\n\tif !isTopLevel {\n\t\tremover := MakeDeadRuleMangler(ast.SymbolMap{})\n\t\tmangledRules = remover.RemoveDeadRulesInPlace(p.source.Index, mangledRules, p.importRecords)\n\t}\n\n\treturn mangledRules\n}\n\ntype ruleEntry struct {\n\tdata        css_ast.R\n\tcallCounter uint32\n}\n\ntype hashEntry struct {\n\trules []ruleEntry\n}\n\ntype callEntry struct {\n\timportRecords []ast.ImportRecord\n\tsourceIndex   uint32\n}\n\ntype DeadRuleRemover struct {\n\tentries map[uint32]hashEntry\n\tcalls   []callEntry\n\tcheck   css_ast.CrossFileEqualityCheck\n}\n\nfunc MakeDeadRuleMangler(symbols ast.SymbolMap) DeadRuleRemover {\n\treturn DeadRuleRemover{\n\t\tentries: make(map[uint32]hashEntry),\n\t\tcheck:   css_ast.CrossFileEqualityCheck{Symbols: symbols},\n\t}\n}\n\nfunc (remover *DeadRuleRemover) RemoveDeadRulesInPlace(sourceIndex uint32, rules []css_ast.Rule, importRecords []ast.ImportRecord) []css_ast.Rule {\n\t// The caller may call this function multiple times, each with a different\n\t// set of import records. Remember each set of import records for equality\n\t// checks later.\n\tcallCounter := uint32(len(remover.calls))\n\tremover.calls = append(remover.calls, callEntry{importRecords, sourceIndex})\n\n\t// Remove duplicate rules, scanning from the back so we keep the last\n\t// duplicate. Note that the linker calls this, so we do not want to do\n\t// anything that modifies the rules themselves. One reason is that ASTs\n\t// are immutable at the linking stage. Another reason is that merging\n\t// CSS ASTs from separate files will mess up source maps because a single\n\t// AST cannot simultaneously represent offsets from multiple files.\n\tn := len(rules)\n\tstart := n\nskipRule:\n\tfor i := n - 1; i >= 0; i-- {\n\t\trule := rules[i]\n\n\t\t// Remove rules with selectors that don't apply to anything (e.g. \":is()\")\n\t\tif r, ok := rule.Data.(*css_ast.RSelector); ok && allSelectorsAreDead(r.Selectors) {\n\t\t\tcontinue skipRule\n\t\t}\n\n\t\t// For duplicate rules, omit all but the last copy\n\t\tif hash, ok := rule.Data.Hash(); ok {\n\t\t\tentry := remover.entries[hash]\n\t\t\tfor _, current := range entry.rules {\n\t\t\t\tvar check *css_ast.CrossFileEqualityCheck\n\n\t\t\t\t// If this rule was from another file, then pass along both arrays\n\t\t\t\t// of import records so that the equality check for \"url()\" tokens\n\t\t\t\t// can use them to check for equality.\n\t\t\t\tif current.callCounter != callCounter {\n\t\t\t\t\t// Reuse the same memory allocation\n\t\t\t\t\tcheck = &remover.check\n\t\t\t\t\tcall := remover.calls[current.callCounter]\n\t\t\t\t\tcheck.ImportRecordsA = importRecords\n\t\t\t\t\tcheck.ImportRecordsB = call.importRecords\n\t\t\t\t\tcheck.SourceIndexA = sourceIndex\n\t\t\t\t\tcheck.SourceIndexB = call.sourceIndex\n\t\t\t\t}\n\n\t\t\t\tif rule.Data.Equal(current.data, check) {\n\t\t\t\t\tcontinue skipRule\n\t\t\t\t}\n\t\t\t}\n\t\t\tentry.rules = append(entry.rules, ruleEntry{\n\t\t\t\tdata:        rule.Data,\n\t\t\t\tcallCounter: callCounter,\n\t\t\t})\n\t\t\tremover.entries[hash] = entry\n\t\t}\n\n\t\tstart--\n\t\trules[start] = rule\n\t}\n\n\treturn rules[start:]\n}\n\nfunc containsDeadSelectors(selectors []css_ast.CompoundSelector) bool {\n\tfor _, sel := range selectors {\n\t\tfor _, ss := range sel.SubclassSelectors {\n\t\t\tif pseudo, ok := ss.Data.(*css_ast.SSPseudoClassWithSelectorList); ok && len(pseudo.Selectors) == 0 &&\n\t\t\t\t(pseudo.Kind == css_ast.PseudoClassIs || pseudo.Kind == css_ast.PseudoClassWhere) {\n\t\t\t\t// \":is()\" and \":where()\" never match anything when empty\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc allSelectorsAreDead(selectors []css_ast.ComplexSelector) bool {\n\tfor _, sel := range selectors {\n\t\tif !containsDeadSelectors(sel.Selectors) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element\nvar nonDeprecatedElementsSupportedByIE7 = map[string]bool{\n\t\"a\":          true,\n\t\"abbr\":       true,\n\t\"address\":    true,\n\t\"area\":       true,\n\t\"b\":          true,\n\t\"base\":       true,\n\t\"blockquote\": true,\n\t\"body\":       true,\n\t\"br\":         true,\n\t\"button\":     true,\n\t\"caption\":    true,\n\t\"cite\":       true,\n\t\"code\":       true,\n\t\"col\":        true,\n\t\"colgroup\":   true,\n\t\"dd\":         true,\n\t\"del\":        true,\n\t\"dfn\":        true,\n\t\"div\":        true,\n\t\"dl\":         true,\n\t\"dt\":         true,\n\t\"em\":         true,\n\t\"embed\":      true,\n\t\"fieldset\":   true,\n\t\"form\":       true,\n\t\"h1\":         true,\n\t\"h2\":         true,\n\t\"h3\":         true,\n\t\"h4\":         true,\n\t\"h5\":         true,\n\t\"h6\":         true,\n\t\"head\":       true,\n\t\"hr\":         true,\n\t\"html\":       true,\n\t\"i\":          true,\n\t\"iframe\":     true,\n\t\"img\":        true,\n\t\"input\":      true,\n\t\"ins\":        true,\n\t\"kbd\":        true,\n\t\"label\":      true,\n\t\"legend\":     true,\n\t\"li\":         true,\n\t\"link\":       true,\n\t\"map\":        true,\n\t\"menu\":       true,\n\t\"meta\":       true,\n\t\"noscript\":   true,\n\t\"object\":     true,\n\t\"ol\":         true,\n\t\"optgroup\":   true,\n\t\"option\":     true,\n\t\"p\":          true,\n\t\"param\":      true,\n\t\"pre\":        true,\n\t\"q\":          true,\n\t\"ruby\":       true,\n\t\"s\":          true,\n\t\"samp\":       true,\n\t\"script\":     true,\n\t\"select\":     true,\n\t\"small\":      true,\n\t\"span\":       true,\n\t\"strong\":     true,\n\t\"style\":      true,\n\t\"sub\":        true,\n\t\"sup\":        true,\n\t\"table\":      true,\n\t\"tbody\":      true,\n\t\"td\":         true,\n\t\"textarea\":   true,\n\t\"tfoot\":      true,\n\t\"th\":         true,\n\t\"thead\":      true,\n\t\"title\":      true,\n\t\"tr\":         true,\n\t\"u\":          true,\n\t\"ul\":         true,\n\t\"var\":        true,\n}\n\n// This only returns true if all of these selectors are considered \"safe\" which\n// means that they are very likely to work in any browser a user might reasonably\n// be using. We do NOT want to merge adjacent qualified rules with the same body\n// if any of the selectors are unsafe, since then browsers which don't support\n// that particular feature would ignore the entire merged qualified rule:\n//\n//\tInput:\n//\t  a { color: red }\n//\t  b { color: red }\n//\t  input::-moz-placeholder { color: red }\n//\n//\tValid output:\n//\t  a, b { color: red }\n//\t  input::-moz-placeholder { color: red }\n//\n//\tInvalid output:\n//\t  a, b, input::-moz-placeholder { color: red }\n//\n// This considers IE 7 and above to be a browser that a user could possibly use.\n// Versions of IE less than 6 are not considered.\nfunc isSafeSelectors(complexSelectors []css_ast.ComplexSelector) bool {\n\tfor _, complex := range complexSelectors {\n\t\tfor _, compound := range complex.Selectors {\n\t\t\tif len(compound.NestingSelectorLocs) > 0 {\n\t\t\t\t// Bail because this is an extension: https://drafts.csswg.org/css-nesting-1/\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif compound.Combinator.Byte != 0 {\n\t\t\t\t// \"Before Internet Explorer 10, the combinator only works in standards mode\"\n\t\t\t\t// Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif compound.TypeSelector != nil {\n\t\t\t\tif compound.TypeSelector.NamespacePrefix != nil {\n\t\t\t\t\t// Bail if we hit a namespace, which doesn't work in IE before version 9\n\t\t\t\t\t// Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\tif compound.TypeSelector.Name.Kind == css_lexer.TIdent && !nonDeprecatedElementsSupportedByIE7[compound.TypeSelector.Name.Text] {\n\t\t\t\t\t// Bail if this element is either deprecated or not supported in IE 7\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, ss := range compound.SubclassSelectors {\n\t\t\t\tswitch s := ss.Data.(type) {\n\t\t\t\tcase *css_ast.SSAttribute:\n\t\t\t\t\tif s.MatcherModifier != 0 {\n\t\t\t\t\t\t// Bail if we hit a case modifier, which doesn't work in IE at all\n\t\t\t\t\t\t// Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\n\t\t\t\tcase *css_ast.SSPseudoClass:\n\t\t\t\t\t// Bail if this pseudo class doesn't match a hard-coded list that's\n\t\t\t\t\t// known to work everywhere. For example, \":focus\" doesn't work in IE 7.\n\t\t\t\t\t// Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes\n\t\t\t\t\tif s.Args == nil && !s.IsElement {\n\t\t\t\t\t\tswitch s.Name {\n\t\t\t\t\t\tcase \"active\", \"first-child\", \"hover\", \"link\", \"visited\":\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn false\n\n\t\t\t\tcase *css_ast.SSPseudoClassWithSelectorList:\n\t\t\t\t\t// These definitely don't work in IE 7\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\nfunc (p *parser) parseURLOrString() (string, logger.Range, bool) {\n\tt := p.current()\n\tswitch t.Kind {\n\tcase css_lexer.TString:\n\t\ttext := p.decoded()\n\t\tp.advance()\n\t\treturn text, t.Range, true\n\n\tcase css_lexer.TURL:\n\t\ttext := p.decoded()\n\t\tp.advance()\n\t\treturn text, t.Range, true\n\n\tcase css_lexer.TFunction:\n\t\tif strings.EqualFold(p.decoded(), \"url\") {\n\t\t\tmatchingLoc := logger.Loc{Start: p.current().Range.End() - 1}\n\t\t\ti := p.index + 1\n\n\t\t\t// Skip over whitespace\n\t\t\tfor p.at(i).Kind == css_lexer.TWhitespace {\n\t\t\t\ti++\n\t\t\t}\n\n\t\t\t// Consume a string\n\t\t\tif p.at(i).Kind == css_lexer.TString {\n\t\t\t\tstringIndex := i\n\t\t\t\ti++\n\n\t\t\t\t// Skip over whitespace\n\t\t\t\tfor p.at(i).Kind == css_lexer.TWhitespace {\n\t\t\t\t\ti++\n\t\t\t\t}\n\n\t\t\t\t// Consume a closing parenthesis\n\t\t\t\tif close := p.at(i).Kind; close == css_lexer.TCloseParen || close == css_lexer.TEndOfFile {\n\t\t\t\t\tt := p.at(stringIndex)\n\t\t\t\t\ttext := t.DecodedText(p.source.Contents)\n\t\t\t\t\tp.index = i\n\t\t\t\t\tp.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc)\n\t\t\t\t\treturn text, t.Range, true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\", logger.Range{}, false\n}\n\nfunc (p *parser) expectURLOrString() (url string, r logger.Range, ok bool) {\n\turl, r, ok = p.parseURLOrString()\n\tif !ok {\n\t\tp.expect(css_lexer.TURL)\n\t}\n\treturn\n}\n\ntype atRuleKind uint8\n\nconst (\n\tatRuleUnknown atRuleKind = iota\n\tatRuleDeclarations\n\tatRuleInheritContext\n\tatRuleQualifiedOrEmpty\n\tatRuleEmpty\n)\n\nvar specialAtRules = map[string]atRuleKind{\n\t\"media\":    atRuleInheritContext,\n\t\"supports\": atRuleInheritContext,\n\n\t\"font-face\": atRuleDeclarations,\n\t\"page\":      atRuleDeclarations,\n\n\t// These go inside \"@page\": https://www.w3.org/TR/css-page-3/#syntax-page-selector\n\t\"bottom-center\":       atRuleDeclarations,\n\t\"bottom-left-corner\":  atRuleDeclarations,\n\t\"bottom-left\":         atRuleDeclarations,\n\t\"bottom-right-corner\": atRuleDeclarations,\n\t\"bottom-right\":        atRuleDeclarations,\n\t\"left-bottom\":         atRuleDeclarations,\n\t\"left-middle\":         atRuleDeclarations,\n\t\"left-top\":            atRuleDeclarations,\n\t\"right-bottom\":        atRuleDeclarations,\n\t\"right-middle\":        atRuleDeclarations,\n\t\"right-top\":           atRuleDeclarations,\n\t\"top-center\":          atRuleDeclarations,\n\t\"top-left-corner\":     atRuleDeclarations,\n\t\"top-left\":            atRuleDeclarations,\n\t\"top-right-corner\":    atRuleDeclarations,\n\t\"top-right\":           atRuleDeclarations,\n\n\t// These properties are very deprecated and appear to only be useful for\n\t// mobile versions of internet explorer (which may no longer exist?), but\n\t// they are used by the https://ant.design/ design system so we recognize\n\t// them to avoid the warning.\n\t//\n\t//   Documentation: https://developer.mozilla.org/en-US/docs/Web/CSS/@viewport\n\t//   Discussion: https://github.com/w3c/csswg-drafts/issues/4766\n\t//\n\t\"viewport\":     atRuleDeclarations,\n\t\"-ms-viewport\": atRuleDeclarations,\n\n\t// This feature has been removed from the web because it's actively harmful.\n\t// However, there is one exception where \"@-moz-document url-prefix() {\" is\n\t// accepted by Firefox to basically be an \"if Firefox\" conditional rule.\n\t//\n\t//   Documentation: https://developer.mozilla.org/en-US/docs/Web/CSS/@document\n\t//   Discussion: https://bugzilla.mozilla.org/show_bug.cgi?id=1035091\n\t//\n\t\"document\":      atRuleInheritContext,\n\t\"-moz-document\": atRuleInheritContext,\n\n\t// This is a new feature that changes how the CSS rule cascade works. It can\n\t// end in either a \"{}\" block or a \";\" rule terminator so we need this special\n\t// case to support both.\n\t//\n\t//   Documentation: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer\n\t//   Motivation: https://developer.chrome.com/blog/cascade-layers/\n\t//\n\t\"layer\": atRuleQualifiedOrEmpty,\n\n\t// Reference: https://drafts.csswg.org/css-cascade-6/#scoped-styles\n\t\"scope\": atRuleInheritContext,\n\n\t// Reference: https://drafts.csswg.org/css-fonts-4/#font-palette-values\n\t\"font-palette-values\": atRuleDeclarations,\n\n\t// Documentation: https://developer.mozilla.org/en-US/docs/Web/CSS/@counter-style\n\t// Reference: https://drafts.csswg.org/css-counter-styles/#the-counter-style-rule\n\t\"counter-style\": atRuleDeclarations,\n\n\t// Documentation: https://developer.mozilla.org/en-US/docs/Web/CSS/@font-feature-values\n\t// Reference: https://drafts.csswg.org/css-fonts/#font-feature-values\n\t\"font-feature-values\": atRuleDeclarations,\n\t\"annotation\":          atRuleDeclarations,\n\t\"character-variant\":   atRuleDeclarations,\n\t\"historical-forms\":    atRuleDeclarations,\n\t\"ornaments\":           atRuleDeclarations,\n\t\"styleset\":            atRuleDeclarations,\n\t\"stylistic\":           atRuleDeclarations,\n\t\"swash\":               atRuleDeclarations,\n\n\t// Container Queries\n\t// Reference: https://drafts.csswg.org/css-contain-3/#container-rule\n\t\"container\": atRuleInheritContext,\n\n\t// Defining before-change style: the @starting-style rule\n\t// Reference: https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule\n\t\"starting-style\": atRuleInheritContext,\n\n\t// Anchor Positioning\n\t// Reference: https://drafts.csswg.org/css-anchor-position-1/#at-ruledef-position-try\n\t\"position-try\": atRuleDeclarations,\n\n\t// @view-transition\n\t// Reference: https://drafts.csswg.org/css-view-transitions-2/#view-transition-rule\n\t\"view-transition\": atRuleDeclarations,\n}\n\nvar atKnownRuleCanBeRemovedIfEmpty = map[string]bool{\n\t\"media\":     true,\n\t\"supports\":  true,\n\t\"font-face\": true,\n\t\"page\":      true,\n\n\t// https://www.w3.org/TR/css-page-3/#syntax-page-selector\n\t\"bottom-center\":       true,\n\t\"bottom-left-corner\":  true,\n\t\"bottom-left\":         true,\n\t\"bottom-right-corner\": true,\n\t\"bottom-right\":        true,\n\t\"left-bottom\":         true,\n\t\"left-middle\":         true,\n\t\"left-top\":            true,\n\t\"right-bottom\":        true,\n\t\"right-middle\":        true,\n\t\"right-top\":           true,\n\t\"top-center\":          true,\n\t\"top-left-corner\":     true,\n\t\"top-left\":            true,\n\t\"top-right-corner\":    true,\n\t\"top-right\":           true,\n\n\t// https://drafts.csswg.org/css-cascade-6/#scoped-styles\n\t\"scope\": true,\n\n\t// https://drafts.csswg.org/css-fonts-4/#font-palette-values\n\t\"font-palette-values\": true,\n\n\t// https://drafts.csswg.org/css-contain-3/#container-rule\n\t\"container\": true,\n}\n\ntype atRuleValidity uint8\n\nconst (\n\tatRuleInvalid atRuleValidity = iota\n\tatRuleValid\n\tatRuleInvalidAfter\n)\n\ntype atRuleContext struct {\n\tafterLoc             logger.Loc\n\tcharsetValidity      atRuleValidity\n\timportValidity       atRuleValidity\n\tcanInlineNoOpNesting bool\n\tisDeclarationList    bool\n\tisTopLevel           bool\n}\n\nfunc (p *parser) parseAtRule(context atRuleContext) css_ast.Rule {\n\t// Parse the name\n\tatToken := p.decoded()\n\tatRange := p.current().Range\n\tlowerAtToken := strings.ToLower(atToken)\n\tkind := specialAtRules[lowerAtToken]\n\tp.advance()\n\n\t// Parse the prelude\n\tpreludeStart := p.index\nabortRuleParser:\n\tswitch lowerAtToken {\n\tcase \"charset\":\n\t\tswitch context.charsetValidity {\n\t\tcase atRuleInvalid:\n\t\t\tp.log.AddID(logger.MsgID_CSS_InvalidAtCharset, logger.Warning, &p.tracker, atRange, \"\\\"@charset\\\" must be the first rule in the file\")\n\n\t\tcase atRuleInvalidAfter:\n\t\t\tp.log.AddIDWithNotes(logger.MsgID_CSS_InvalidAtCharset, logger.Warning, &p.tracker, atRange,\n\t\t\t\t\"\\\"@charset\\\" must be the first rule in the file\",\n\t\t\t\t[]logger.MsgData{p.tracker.MsgData(logger.Range{Loc: context.afterLoc},\n\t\t\t\t\t\"This rule cannot come before a \\\"@charset\\\" rule\")})\n\n\t\tcase atRuleValid:\n\t\t\tkind = atRuleEmpty\n\t\t\tp.expect(css_lexer.TWhitespace)\n\t\t\tif p.peek(css_lexer.TString) {\n\t\t\t\tencoding := p.decoded()\n\t\t\t\tif !strings.EqualFold(encoding, \"UTF-8\") {\n\t\t\t\t\tp.log.AddID(logger.MsgID_CSS_UnsupportedAtCharset, logger.Warning, &p.tracker, p.current().Range,\n\t\t\t\t\t\tfmt.Sprintf(\"\\\"UTF-8\\\" will be used instead of unsupported charset %q\", encoding))\n\t\t\t\t}\n\t\t\t\tp.advance()\n\t\t\t\tp.expect(css_lexer.TSemicolon)\n\t\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtCharset{Encoding: encoding}}\n\t\t\t}\n\t\t\tp.expect(css_lexer.TString)\n\t\t}\n\n\tcase \"import\":\n\t\tswitch context.importValidity {\n\t\tcase atRuleInvalid:\n\t\t\tp.log.AddID(logger.MsgID_CSS_InvalidAtImport, logger.Warning, &p.tracker, atRange, \"\\\"@import\\\" is only valid at the top level\")\n\n\t\tcase atRuleInvalidAfter:\n\t\t\tp.log.AddIDWithNotes(logger.MsgID_CSS_InvalidAtImport, logger.Warning, &p.tracker, atRange,\n\t\t\t\t\"All \\\"@import\\\" rules must come first\",\n\t\t\t\t[]logger.MsgData{p.tracker.MsgData(logger.Range{Loc: context.afterLoc},\n\t\t\t\t\t\"This rule cannot come before an \\\"@import\\\" rule\")})\n\n\t\tcase atRuleValid:\n\t\t\tkind = atRuleEmpty\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\tif path, r, ok := p.expectURLOrString(); ok {\n\t\t\t\tvar conditions css_ast.ImportConditions\n\t\t\t\timportConditionsStart := p.index\n\n\t\t\t\t// Parse the optional \"layer()\"\n\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\tif (p.peek(css_lexer.TIdent) || p.peek(css_lexer.TFunction)) && strings.EqualFold(p.decoded(), \"layer\") {\n\t\t\t\t\tp.parseComponentValue()\n\t\t\t\t\tconditions.Layers = p.convertTokens(p.tokens[importConditionsStart:p.index])\n\t\t\t\t\timportConditionsStart = p.index\n\n\t\t\t\t\t// Remove leading and trailing whitespace\n\t\t\t\t\tif len(conditions.Layers) > 0 {\n\t\t\t\t\t\tconditions.Layers[0].Whitespace &= ^(css_ast.WhitespaceBefore | css_ast.WhitespaceAfter)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse the optional \"supports()\"\n\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\tif p.peek(css_lexer.TFunction) && strings.EqualFold(p.decoded(), \"supports\") {\n\t\t\t\t\tp.parseComponentValue()\n\t\t\t\t\tconditions.Supports = p.convertTokens(p.tokens[importConditionsStart:p.index])\n\t\t\t\t\timportConditionsStart = p.index\n\n\t\t\t\t\t// Remove leading and trailing whitespace\n\t\t\t\t\tif len(conditions.Supports) > 0 {\n\t\t\t\t\t\tconditions.Supports[0].Whitespace &= ^(css_ast.WhitespaceBefore | css_ast.WhitespaceAfter)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Parse the optional media query list\n\t\t\t\tconditions.Queries = p.parseMediaQueryListUntil(func(kind css_lexer.T) bool {\n\t\t\t\t\treturn kind == css_lexer.TSemicolon || kind == css_lexer.TOpenBrace ||\n\t\t\t\t\t\tkind == css_lexer.TCloseBrace || kind == css_lexer.TEndOfFile\n\t\t\t\t})\n\t\t\t\tif p.peek(css_lexer.TOpenBrace) {\n\t\t\t\t\tbreak // Avoid parsing an invalid \"@import\" rule\n\t\t\t\t}\n\n\t\t\t\t// Check whether any import conditions are present\n\t\t\t\tvar importConditions *css_ast.ImportConditions\n\t\t\t\tif len(conditions.Layers) > 0 || len(conditions.Supports) > 0 || len(conditions.Queries) > 0 {\n\t\t\t\t\timportConditions = &conditions\n\t\t\t\t}\n\n\t\t\t\tp.expect(css_lexer.TSemicolon)\n\t\t\t\timportRecordIndex := uint32(len(p.importRecords))\n\t\t\t\tp.importRecords = append(p.importRecords, ast.ImportRecord{\n\t\t\t\t\tKind:  ast.ImportAt,\n\t\t\t\t\tPath:  logger.Path{Text: path},\n\t\t\t\t\tRange: r,\n\t\t\t\t})\n\n\t\t\t\t// Fill in the pre-import layers once we see the first \"@import\"\n\t\t\t\tif !p.hasSeenAtImport {\n\t\t\t\t\tp.hasSeenAtImport = true\n\t\t\t\t\tp.layersPreImport = p.layersPostImport\n\t\t\t\t\tp.layersPostImport = nil\n\t\t\t\t}\n\n\t\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtImport{\n\t\t\t\t\tImportRecordIndex: importRecordIndex,\n\t\t\t\t\tImportConditions:  importConditions,\n\t\t\t\t}}\n\t\t\t}\n\t\t}\n\n\tcase \"keyframes\", \"-webkit-keyframes\", \"-moz-keyframes\", \"-ms-keyframes\", \"-o-keyframes\":\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tnameLoc := p.current().Range.Loc\n\t\tvar name string\n\n\t\tif p.peek(css_lexer.TIdent) {\n\t\t\tname = p.decoded()\n\t\t\tif isInvalidAnimationName(name) {\n\t\t\t\tmsg := logger.Msg{\n\t\t\t\t\tID:    logger.MsgID_CSS_CSSSyntaxError,\n\t\t\t\t\tKind:  logger.Warning,\n\t\t\t\t\tData:  p.tracker.MsgData(p.current().Range, fmt.Sprintf(\"Cannot use %q as a name for \\\"@keyframes\\\" without quotes\", name)),\n\t\t\t\t\tNotes: []logger.MsgData{{Text: fmt.Sprintf(\"You can put %q in quotes to prevent it from becoming a CSS keyword.\", name)}},\n\t\t\t\t}\n\t\t\t\tmsg.Data.Location.Suggestion = fmt.Sprintf(\"%q\", name)\n\t\t\t\tp.log.AddMsg(msg)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tp.advance()\n\t\t} else if p.peek(css_lexer.TString) {\n\t\t\t// Note: Strings as names is allowed in the CSS specification and works in\n\t\t\t// Firefox and Safari but Chrome has strangely decided to deliberately not\n\t\t\t// support this. We always turn all string names into identifiers to avoid\n\t\t\t// them silently breaking in Chrome.\n\t\t\tname = p.decoded()\n\t\t\tp.advance()\n\t\t\tif !p.makeLocalSymbols && isInvalidAnimationName(name) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t} else if !p.expect(css_lexer.TIdent) {\n\t\t\tbreak\n\t\t}\n\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tblockStart := p.index\n\n\t\tmatchingLoc := p.current().Range.Loc\n\t\tif p.expect(css_lexer.TOpenBrace) {\n\t\t\tvar blocks []css_ast.KeyframeBlock\n\n\t\tbadSyntax:\n\t\t\tfor {\n\t\t\t\tswitch p.current().Kind {\n\t\t\t\tcase css_lexer.TWhitespace:\n\t\t\t\t\tp.advance()\n\t\t\t\t\tcontinue\n\n\t\t\t\tcase css_lexer.TCloseBrace:\n\t\t\t\t\tcloseBraceLoc := p.current().Range.Loc\n\t\t\t\t\tp.advance()\n\t\t\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtKeyframes{\n\t\t\t\t\t\tAtToken:       atToken,\n\t\t\t\t\t\tName:          p.symbolForName(nameLoc, name),\n\t\t\t\t\t\tBlocks:        blocks,\n\t\t\t\t\t\tCloseBraceLoc: closeBraceLoc,\n\t\t\t\t\t}}\n\n\t\t\t\tcase css_lexer.TEndOfFile:\n\t\t\t\t\tbreak badSyntax\n\n\t\t\t\tcase css_lexer.TOpenBrace:\n\t\t\t\t\tp.expect(css_lexer.TPercentage)\n\t\t\t\t\tbreak badSyntax\n\n\t\t\t\tdefault:\n\t\t\t\t\tvar selectors []string\n\t\t\t\t\tvar firstSelectorLoc logger.Loc\n\n\t\t\t\tselectors:\n\t\t\t\t\tfor {\n\t\t\t\t\t\tt := p.current()\n\t\t\t\t\t\tswitch t.Kind {\n\t\t\t\t\t\tcase css_lexer.TWhitespace:\n\t\t\t\t\t\t\tp.advance()\n\t\t\t\t\t\t\tcontinue\n\n\t\t\t\t\t\tcase css_lexer.TOpenBrace:\n\t\t\t\t\t\t\tblockMatchingLoc := p.current().Range.Loc\n\t\t\t\t\t\t\tp.advance()\n\t\t\t\t\t\t\trules := p.parseListOfDeclarations(listOfDeclarationsOpts{})\n\t\t\t\t\t\t\tcloseBraceLoc := p.current().Range.Loc\n\t\t\t\t\t\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseBrace, blockMatchingLoc) {\n\t\t\t\t\t\t\t\tcloseBraceLoc = logger.Loc{}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// \"@keyframes { from {} to { color: red } }\" => \"@keyframes { to { color: red } }\"\n\t\t\t\t\t\t\tif !p.options.minifySyntax || len(rules) > 0 {\n\t\t\t\t\t\t\t\tblocks = append(blocks, css_ast.KeyframeBlock{\n\t\t\t\t\t\t\t\t\tSelectors:     selectors,\n\t\t\t\t\t\t\t\t\tRules:         rules,\n\t\t\t\t\t\t\t\t\tLoc:           firstSelectorLoc,\n\t\t\t\t\t\t\t\t\tCloseBraceLoc: closeBraceLoc,\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak selectors\n\n\t\t\t\t\t\tcase css_lexer.TCloseBrace, css_lexer.TEndOfFile:\n\t\t\t\t\t\t\tp.expect(css_lexer.TOpenBrace)\n\t\t\t\t\t\t\tbreak badSyntax\n\n\t\t\t\t\t\tcase css_lexer.TIdent, css_lexer.TPercentage:\n\t\t\t\t\t\t\tif firstSelectorLoc.Start == 0 {\n\t\t\t\t\t\t\t\tfirstSelectorLoc = p.current().Range.Loc\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttext := p.decoded()\n\t\t\t\t\t\t\tif t.Kind == css_lexer.TIdent {\n\t\t\t\t\t\t\t\tif strings.EqualFold(text, \"from\") {\n\t\t\t\t\t\t\t\t\tif p.options.minifySyntax {\n\t\t\t\t\t\t\t\t\t\ttext = \"0%\" // \"0%\" is equivalent to but shorter than \"from\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else if !strings.EqualFold(text, \"to\") {\n\t\t\t\t\t\t\t\t\tp.expect(css_lexer.TPercentage)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if p.options.minifySyntax && text == \"100%\" {\n\t\t\t\t\t\t\t\ttext = \"to\" // \"to\" is equivalent to but shorter than \"100%\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tselectors = append(selectors, text)\n\t\t\t\t\t\t\tp.advance()\n\n\t\t\t\t\t\t\t// Keyframe selectors are comma-separated\n\t\t\t\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\t\t\t\tif p.eat(css_lexer.TComma) {\n\t\t\t\t\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\t\t\t\t\tif k := p.current().Kind; k != css_lexer.TIdent && k != css_lexer.TPercentage {\n\t\t\t\t\t\t\t\t\tp.expect(css_lexer.TPercentage)\n\t\t\t\t\t\t\t\t\tbreak badSyntax\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if k := p.current().Kind; k != css_lexer.TOpenBrace && k != css_lexer.TCloseBrace && k != css_lexer.TEndOfFile {\n\t\t\t\t\t\t\t\tp.expect(css_lexer.TComma)\n\t\t\t\t\t\t\t\tbreak badSyntax\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tp.expect(css_lexer.TPercentage)\n\t\t\t\t\t\t\tbreak badSyntax\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Otherwise, finish parsing the body and return an unknown rule\n\t\t\tfor !p.peek(css_lexer.TCloseBrace) && !p.peek(css_lexer.TEndOfFile) {\n\t\t\t\tp.parseComponentValue()\n\t\t\t}\n\t\t\tp.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc)\n\t\t\tprelude := p.convertTokens(p.tokens[preludeStart:blockStart])\n\t\t\tblock, _ := p.convertTokensHelper(p.tokens[blockStart:p.index], css_lexer.TEndOfFile, convertTokensOpts{allowImports: true})\n\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RUnknownAt{AtToken: atToken, Prelude: prelude, Block: block}}\n\t\t}\n\n\tcase \"layer\":\n\t\t// Reference: https://developer.mozilla.org/en-US/docs/Web/CSS/@layer\n\n\t\t// Read the layer name list\n\t\tvar names [][]string\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tif p.peek(css_lexer.TIdent) {\n\t\t\tfor {\n\t\t\t\tident, ok := p.expectValidLayerNameIdent()\n\t\t\t\tif !ok {\n\t\t\t\t\tbreak abortRuleParser\n\t\t\t\t}\n\t\t\t\tname := []string{ident}\n\t\t\t\tfor {\n\t\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\t\tif !p.eat(css_lexer.TDelimDot) {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\t\tident, ok := p.expectValidLayerNameIdent()\n\t\t\t\t\tif !ok {\n\t\t\t\t\t\tbreak abortRuleParser\n\t\t\t\t\t}\n\t\t\t\t\tname = append(name, ident)\n\t\t\t\t}\n\t\t\t\tnames = append(names, name)\n\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\tif !p.eat(css_lexer.TComma) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t}\n\t\t}\n\n\t\t// Read the optional block\n\t\tmatchingLoc := p.current().Range.Loc\n\t\tif len(names) <= 1 && p.eat(css_lexer.TOpenBrace) {\n\t\t\tp.recordAtLayerRule(names)\n\t\t\toldEnclosingLayer := p.enclosingLayer\n\t\t\tif len(names) == 1 {\n\t\t\t\tp.enclosingLayer = append(p.enclosingLayer, names[0]...)\n\t\t\t} else {\n\t\t\t\tp.anonLayerCount++\n\t\t\t}\n\t\t\tvar rules []css_ast.Rule\n\t\t\tif context.isDeclarationList {\n\t\t\t\trules = p.parseListOfDeclarations(listOfDeclarationsOpts{\n\t\t\t\t\tcanInlineNoOpNesting: context.canInlineNoOpNesting,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\trules = p.parseListOfRules(ruleContext{\n\t\t\t\t\tparseSelectors: true,\n\t\t\t\t})\n\t\t\t}\n\t\t\tif len(names) != 1 {\n\t\t\t\tp.anonLayerCount--\n\t\t\t}\n\t\t\tp.enclosingLayer = oldEnclosingLayer\n\t\t\tcloseBraceLoc := p.current().Range.Loc\n\t\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc) {\n\t\t\t\tcloseBraceLoc = logger.Loc{}\n\t\t\t}\n\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtLayer{Names: names, Rules: rules, CloseBraceLoc: closeBraceLoc}}\n\t\t}\n\n\t\t// Handle lack of a block\n\t\tif len(names) >= 1 && p.eat(css_lexer.TSemicolon) {\n\t\t\tp.recordAtLayerRule(names)\n\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtLayer{Names: names}}\n\t\t}\n\n\t\t// Otherwise there's some kind of syntax error\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TEndOfFile:\n\t\t\tp.expect(css_lexer.TSemicolon)\n\t\t\tp.recordAtLayerRule(names)\n\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtLayer{Names: names}}\n\n\t\tcase css_lexer.TCloseBrace:\n\t\t\tp.expect(css_lexer.TSemicolon)\n\t\t\tif !context.isTopLevel {\n\t\t\t\tp.recordAtLayerRule(names)\n\t\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtLayer{Names: names}}\n\t\t\t}\n\n\t\tcase css_lexer.TOpenBrace:\n\t\t\tp.expect(css_lexer.TSemicolon)\n\n\t\tdefault:\n\t\t\tp.unexpected()\n\t\t}\n\n\tcase \"media\":\n\t\tqueries := p.parseMediaQueryListUntil(func(kind css_lexer.T) bool {\n\t\t\treturn kind == css_lexer.TOpenBrace\n\t\t})\n\n\t\t// Expect a block after the query\n\t\tmatchingLoc := p.current().Range.Loc\n\t\tif !p.expect(css_lexer.TOpenBrace) {\n\t\t\tbreak\n\t\t}\n\t\tvar rules []css_ast.Rule\n\n\t\t// Push the \"@media\" conditions\n\t\tp.enclosingAtMedia = append(p.enclosingAtMedia, queries)\n\n\t\t// Parse the block for this rule\n\t\tif context.isDeclarationList {\n\t\t\trules = p.parseListOfDeclarations(listOfDeclarationsOpts{\n\t\t\t\tcanInlineNoOpNesting: context.canInlineNoOpNesting,\n\t\t\t})\n\t\t} else {\n\t\t\trules = p.parseListOfRules(ruleContext{\n\t\t\t\tparseSelectors: true,\n\t\t\t})\n\t\t}\n\n\t\t// Pop the \"@media\" conditions\n\t\tp.enclosingAtMedia = p.enclosingAtMedia[:len(p.enclosingAtMedia)-1]\n\n\t\tcloseBraceLoc := p.current().Range.Loc\n\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc) {\n\t\t\tcloseBraceLoc = logger.Loc{}\n\t\t}\n\n\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RAtMedia{Queries: queries, Rules: rules, CloseBraceLoc: closeBraceLoc}}\n\n\tdefault:\n\t\tif kind == atRuleUnknown && lowerAtToken == \"namespace\" {\n\t\t\t// CSS namespaces are a weird feature that appears to only really be\n\t\t\t// useful for styling XML. And the world has moved on from XHTML to\n\t\t\t// HTML5 so pretty much no one uses CSS namespaces anymore. They are\n\t\t\t// also complicated to support in a bundler because CSS namespaces are\n\t\t\t// file-scoped, which means:\n\t\t\t//\n\t\t\t// * Default namespaces can be different in different files, in which\n\t\t\t//   case some default namespaces would have to be converted to prefixed\n\t\t\t//   namespaces to avoid collisions.\n\t\t\t//\n\t\t\t// * Prefixed namespaces from different files can use the same name, in\n\t\t\t//   which case some prefixed namespaces would need to be renamed to\n\t\t\t//   avoid collisions.\n\t\t\t//\n\t\t\t// Instead of implementing all of that for an extremely obscure feature,\n\t\t\t// CSS namespaces are just explicitly not supported.\n\t\t\tp.log.AddID(logger.MsgID_CSS_UnsupportedAtNamespace, logger.Warning, &p.tracker, atRange, \"\\\"@namespace\\\" rules are not supported\")\n\t\t}\n\t}\n\n\t// Parse an unknown prelude\nprelude:\n\tfor {\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TOpenBrace, css_lexer.TEndOfFile:\n\t\t\tbreak prelude\n\n\t\tcase css_lexer.TSemicolon, css_lexer.TCloseBrace:\n\t\t\tprelude := p.convertTokens(p.tokens[preludeStart:p.index])\n\n\t\t\tswitch kind {\n\t\t\tcase atRuleQualifiedOrEmpty:\n\t\t\t\t// Parse a known at rule below\n\t\t\t\tbreak prelude\n\n\t\t\tcase atRuleEmpty, atRuleUnknown:\n\t\t\t\t// Parse an unknown at rule\n\t\t\t\tp.expect(css_lexer.TSemicolon)\n\t\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RUnknownAt{AtToken: atToken, Prelude: prelude}}\n\n\t\t\tdefault:\n\t\t\t\t// Report an error for rules that should have blocks\n\t\t\t\tp.expect(css_lexer.TOpenBrace)\n\t\t\t\tp.eat(css_lexer.TSemicolon)\n\t\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RUnknownAt{AtToken: atToken, Prelude: prelude}}\n\t\t\t}\n\n\t\tdefault:\n\t\t\tp.parseComponentValue()\n\t\t}\n\t}\n\tprelude := p.convertTokens(p.tokens[preludeStart:p.index])\n\tblockStart := p.index\n\n\tswitch kind {\n\tcase atRuleEmpty:\n\t\t// Report an error for rules that shouldn't have blocks\n\t\tp.expect(css_lexer.TSemicolon)\n\t\tp.parseBlock(css_lexer.TOpenBrace, css_lexer.TCloseBrace)\n\t\tblock := p.convertTokens(p.tokens[blockStart:p.index])\n\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RUnknownAt{AtToken: atToken, Prelude: prelude, Block: block}}\n\n\tcase atRuleDeclarations:\n\t\t// Parse known rules whose blocks always consist of declarations\n\t\tmatchingLoc := p.current().Range.Loc\n\t\tp.expect(css_lexer.TOpenBrace)\n\t\trules := p.parseListOfDeclarations(listOfDeclarationsOpts{})\n\t\tcloseBraceLoc := p.current().Range.Loc\n\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc) {\n\t\t\tcloseBraceLoc = logger.Loc{}\n\t\t}\n\n\t\t// Handle local names for \"@counter-style\"\n\t\tif len(prelude) == 1 && lowerAtToken == \"counter-style\" {\n\t\t\tif t := &prelude[0]; t.Kind == css_lexer.TIdent {\n\t\t\t\tt.Kind = css_lexer.TSymbol\n\t\t\t\tt.PayloadIndex = p.symbolForName(t.Loc, t.Text).Ref.InnerIndex\n\t\t\t}\n\t\t}\n\n\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RKnownAt{AtToken: atToken, Prelude: prelude, Rules: rules, CloseBraceLoc: closeBraceLoc}}\n\n\tcase atRuleInheritContext:\n\t\t// Parse known rules whose blocks consist of whatever the current context is\n\t\tmatchingLoc := p.current().Range.Loc\n\t\tp.expect(css_lexer.TOpenBrace)\n\t\tvar rules []css_ast.Rule\n\n\t\t// Parse the block for this rule\n\t\tif context.isDeclarationList {\n\t\t\trules = p.parseListOfDeclarations(listOfDeclarationsOpts{\n\t\t\t\tcanInlineNoOpNesting: context.canInlineNoOpNesting,\n\t\t\t})\n\t\t} else {\n\t\t\trules = p.parseListOfRules(ruleContext{\n\t\t\t\tparseSelectors: true,\n\t\t\t})\n\t\t}\n\n\t\tcloseBraceLoc := p.current().Range.Loc\n\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc) {\n\t\t\tcloseBraceLoc = logger.Loc{}\n\t\t}\n\n\t\t// Handle local names for \"@container\"\n\t\tif len(prelude) >= 1 && lowerAtToken == \"container\" {\n\t\t\tif t := &prelude[0]; t.Kind == css_lexer.TIdent && strings.ToLower(t.Text) != \"not\" {\n\t\t\t\tt.Kind = css_lexer.TSymbol\n\t\t\t\tt.PayloadIndex = p.symbolForName(t.Loc, t.Text).Ref.InnerIndex\n\t\t\t}\n\t\t}\n\n\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RKnownAt{AtToken: atToken, Prelude: prelude, Rules: rules, CloseBraceLoc: closeBraceLoc}}\n\n\tcase atRuleQualifiedOrEmpty:\n\t\tmatchingLoc := p.current().Range.Loc\n\t\tif p.eat(css_lexer.TOpenBrace) {\n\t\t\trules := p.parseListOfRules(ruleContext{\n\t\t\t\tparseSelectors: true,\n\t\t\t})\n\t\t\tcloseBraceLoc := p.current().Range.Loc\n\t\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc) {\n\t\t\t\tcloseBraceLoc = logger.Loc{}\n\t\t\t}\n\t\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RKnownAt{AtToken: atToken, Prelude: prelude, Rules: rules, CloseBraceLoc: closeBraceLoc}}\n\t\t}\n\t\tp.expect(css_lexer.TSemicolon)\n\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RKnownAt{AtToken: atToken, Prelude: prelude}}\n\n\tdefault:\n\t\t// Otherwise, parse an unknown rule\n\t\tp.parseBlock(css_lexer.TOpenBrace, css_lexer.TCloseBrace)\n\t\tblock, _ := p.convertTokensHelper(p.tokens[blockStart:p.index], css_lexer.TEndOfFile, convertTokensOpts{allowImports: true})\n\t\treturn css_ast.Rule{Loc: atRange.Loc, Data: &css_ast.RUnknownAt{AtToken: atToken, Prelude: prelude, Block: block}}\n\t}\n}\n\nfunc (p *parser) expectValidLayerNameIdent() (string, bool) {\n\tr := p.current().Range\n\ttext := p.decoded()\n\tif !p.expect(css_lexer.TIdent) {\n\t\treturn \"\", false\n\t}\n\tswitch text {\n\tcase \"initial\", \"inherit\", \"unset\":\n\t\tp.log.AddID(logger.MsgID_CSS_InvalidAtLayer, logger.Warning, &p.tracker, r, fmt.Sprintf(\"%q cannot be used as a layer name\", text))\n\t\tp.prevError = r.Loc\n\t\treturn \"\", false\n\t}\n\treturn text, true\n}\n\nfunc (p *parser) convertTokens(tokens []css_lexer.Token) []css_ast.Token {\n\tresult, _ := p.convertTokensHelper(tokens, css_lexer.TEndOfFile, convertTokensOpts{})\n\treturn result\n}\n\ntype convertTokensOpts struct {\n\tallowImports         bool\n\tverbatimWhitespace   bool\n\tisInsideCalcFunction bool\n}\n\nfunc (p *parser) convertTokensHelper(tokens []css_lexer.Token, close css_lexer.T, opts convertTokensOpts) ([]css_ast.Token, []css_lexer.Token) {\n\tresult := []css_ast.Token{}\n\tvar nextWhitespace css_ast.WhitespaceFlags\n\n\t// Enable verbatim whitespace mode when the first two non-whitespace tokens\n\t// are a CSS variable name followed by a colon. This is because it could be\n\t// a form of CSS variable usage, and removing whitespace could potentially\n\t// break this usage. For example, the following CSS is ignored by Chrome if\n\t// the whitespace isn't preserved:\n\t//\n\t//   @supports (--foo: ) {\n\t//     html { background: green; }\n\t//   }\n\t//\n\t// Strangely whitespace removal doesn't cause the declaration to be ignored\n\t// in Firefox or Safari, so there's definitely a browser bug somewhere.\n\tif !opts.verbatimWhitespace {\n\t\tfor i, t := range tokens {\n\t\t\tif t.Kind == css_lexer.TWhitespace {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif t.Kind == css_lexer.TIdent && strings.HasPrefix(t.DecodedText(p.source.Contents), \"--\") {\n\t\t\t\tfor _, t := range tokens[i+1:] {\n\t\t\t\t\tif t.Kind == css_lexer.TWhitespace {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif t.Kind == css_lexer.TColon {\n\t\t\t\t\t\topts.verbatimWhitespace = true\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\nloop:\n\tfor len(tokens) > 0 {\n\t\tt := tokens[0]\n\t\ttokens = tokens[1:]\n\t\tif t.Kind == close {\n\t\t\tbreak loop\n\t\t}\n\t\ttoken := css_ast.Token{\n\t\t\tLoc:        t.Range.Loc,\n\t\t\tKind:       t.Kind,\n\t\t\tText:       t.DecodedText(p.source.Contents),\n\t\t\tWhitespace: nextWhitespace,\n\t\t}\n\t\tnextWhitespace = 0\n\n\t\t// Warn about invalid \"+\" and \"-\" operators that break the containing \"calc()\"\n\t\tif opts.isInsideCalcFunction && t.Kind.IsNumeric() && len(result) > 0 && result[len(result)-1].Kind.IsNumeric() &&\n\t\t\t(strings.HasPrefix(token.Text, \"+\") || strings.HasPrefix(token.Text, \"-\")) {\n\t\t\t// \"calc(1+2)\" and \"calc(1-2)\" are invalid\n\t\t\tp.log.AddID(logger.MsgID_CSS_InvalidCalc, logger.Warning, &p.tracker, logger.Range{Loc: t.Range.Loc, Len: 1},\n\t\t\t\tfmt.Sprintf(\"The %q operator only works if there is whitespace on both sides\", token.Text[:1]))\n\t\t}\n\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TWhitespace:\n\t\t\tif last := len(result) - 1; last >= 0 {\n\t\t\t\tresult[last].Whitespace |= css_ast.WhitespaceAfter\n\t\t\t}\n\t\t\tnextWhitespace = css_ast.WhitespaceBefore\n\t\t\tcontinue\n\n\t\tcase css_lexer.TDelimPlus, css_lexer.TDelimMinus:\n\t\t\t// Warn about invalid \"+\" and \"-\" operators that break the containing \"calc()\"\n\t\t\tif opts.isInsideCalcFunction && len(tokens) > 0 {\n\t\t\t\tif len(result) == 0 || result[len(result)-1].Kind == css_lexer.TComma {\n\t\t\t\t\t// \"calc(-(1 + 2))\" is invalid\n\t\t\t\t\tp.log.AddID(logger.MsgID_CSS_InvalidCalc, logger.Warning, &p.tracker, t.Range,\n\t\t\t\t\t\tfmt.Sprintf(\"%q can only be used as an infix operator, not a prefix operator\", token.Text))\n\t\t\t\t} else if token.Whitespace != css_ast.WhitespaceBefore || tokens[0].Kind != css_lexer.TWhitespace {\n\t\t\t\t\t// \"calc(1- 2)\" and \"calc(1 -(2))\" are invalid\n\t\t\t\t\tp.log.AddID(logger.MsgID_CSS_InvalidCalc, logger.Warning, &p.tracker, t.Range,\n\t\t\t\t\t\tfmt.Sprintf(\"The %q operator only works if there is whitespace on both sides\", token.Text))\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase css_lexer.TNumber:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tif text, ok := mangleNumber(token.Text); ok {\n\t\t\t\t\ttoken.Text = text\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase css_lexer.TPercentage:\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tif text, ok := mangleNumber(token.PercentageValue()); ok {\n\t\t\t\t\ttoken.Text = text + \"%\"\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase css_lexer.TDimension:\n\t\t\ttoken.UnitOffset = t.UnitOffset\n\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tif text, ok := mangleNumber(token.DimensionValue()); ok {\n\t\t\t\t\ttoken.Text = text + token.DimensionUnit()\n\t\t\t\t\ttoken.UnitOffset = uint16(len(text))\n\t\t\t\t}\n\n\t\t\t\tif value, unit, ok := mangleDimension(token.DimensionValue(), token.DimensionUnit()); ok {\n\t\t\t\t\ttoken.Text = value + unit\n\t\t\t\t\ttoken.UnitOffset = uint16(len(value))\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase css_lexer.TURL:\n\t\t\ttoken.PayloadIndex = uint32(len(p.importRecords))\n\t\t\tvar flags ast.ImportRecordFlags\n\t\t\tif !opts.allowImports {\n\t\t\t\tflags |= ast.IsUnused\n\t\t\t}\n\t\t\tp.importRecords = append(p.importRecords, ast.ImportRecord{\n\t\t\t\tKind:  ast.ImportURL,\n\t\t\t\tPath:  logger.Path{Text: token.Text},\n\t\t\t\tRange: t.Range,\n\t\t\t\tFlags: flags,\n\t\t\t})\n\t\t\ttoken.Text = \"\"\n\n\t\tcase css_lexer.TFunction:\n\t\t\tvar nested []css_ast.Token\n\t\t\toriginal := tokens\n\t\t\tnestedOpts := opts\n\t\t\tif strings.EqualFold(token.Text, \"var\") {\n\t\t\t\t// CSS variables require verbatim whitespace for correctness\n\t\t\t\tnestedOpts.verbatimWhitespace = true\n\t\t\t}\n\t\t\tif strings.EqualFold(token.Text, \"calc\") {\n\t\t\t\tnestedOpts.isInsideCalcFunction = true\n\t\t\t}\n\t\t\tnested, tokens = p.convertTokensHelper(tokens, css_lexer.TCloseParen, nestedOpts)\n\t\t\ttoken.Children = &nested\n\n\t\t\t// Apply \"calc\" simplification rules when minifying\n\t\t\tif p.options.minifySyntax && strings.EqualFold(token.Text, \"calc\") {\n\t\t\t\ttoken = p.tryToReduceCalcExpression(token)\n\t\t\t}\n\n\t\t\t// Treat a URL function call with a string just like a URL token\n\t\t\tif strings.EqualFold(token.Text, \"url\") && len(nested) == 1 && nested[0].Kind == css_lexer.TString {\n\t\t\t\ttoken.Kind = css_lexer.TURL\n\t\t\t\ttoken.Text = \"\"\n\t\t\t\ttoken.Children = nil\n\t\t\t\ttoken.PayloadIndex = uint32(len(p.importRecords))\n\t\t\t\tvar flags ast.ImportRecordFlags\n\t\t\t\tif !opts.allowImports {\n\t\t\t\t\tflags |= ast.IsUnused\n\t\t\t\t}\n\t\t\t\tp.importRecords = append(p.importRecords, ast.ImportRecord{\n\t\t\t\t\tKind:  ast.ImportURL,\n\t\t\t\t\tPath:  logger.Path{Text: nested[0].Text},\n\t\t\t\t\tRange: original[0].Range,\n\t\t\t\t\tFlags: flags,\n\t\t\t\t})\n\t\t\t}\n\n\t\tcase css_lexer.TOpenParen:\n\t\t\tvar nested []css_ast.Token\n\t\t\tnested, tokens = p.convertTokensHelper(tokens, css_lexer.TCloseParen, opts)\n\t\t\ttoken.Children = &nested\n\n\t\tcase css_lexer.TOpenBrace:\n\t\t\tvar nested []css_ast.Token\n\t\t\tnested, tokens = p.convertTokensHelper(tokens, css_lexer.TCloseBrace, opts)\n\n\t\t\t// Pretty-printing: insert leading and trailing whitespace when not minifying\n\t\t\tif !opts.verbatimWhitespace && !p.options.minifyWhitespace && len(nested) > 0 {\n\t\t\t\tnested[0].Whitespace |= css_ast.WhitespaceBefore\n\t\t\t\tnested[len(nested)-1].Whitespace |= css_ast.WhitespaceAfter\n\t\t\t}\n\n\t\t\ttoken.Children = &nested\n\n\t\tcase css_lexer.TOpenBracket:\n\t\t\tvar nested []css_ast.Token\n\t\t\tnested, tokens = p.convertTokensHelper(tokens, css_lexer.TCloseBracket, opts)\n\t\t\ttoken.Children = &nested\n\t\t}\n\n\t\tresult = append(result, token)\n\t}\n\n\tif !opts.verbatimWhitespace {\n\t\tfor i := range result {\n\t\t\ttoken := &result[i]\n\n\t\t\t// Always remove leading and trailing whitespace\n\t\t\tif i == 0 {\n\t\t\t\ttoken.Whitespace &= ^css_ast.WhitespaceBefore\n\t\t\t}\n\t\t\tif i+1 == len(result) {\n\t\t\t\ttoken.Whitespace &= ^css_ast.WhitespaceAfter\n\t\t\t}\n\n\t\t\tswitch token.Kind {\n\t\t\tcase css_lexer.TComma:\n\t\t\t\t// Assume that whitespace can always be removed before a comma\n\t\t\t\ttoken.Whitespace &= ^css_ast.WhitespaceBefore\n\t\t\t\tif i > 0 {\n\t\t\t\t\tresult[i-1].Whitespace &= ^css_ast.WhitespaceAfter\n\t\t\t\t}\n\n\t\t\t\t// Assume whitespace can always be added after a comma\n\t\t\t\tif p.options.minifyWhitespace {\n\t\t\t\t\ttoken.Whitespace &= ^css_ast.WhitespaceAfter\n\t\t\t\t\tif i+1 < len(result) {\n\t\t\t\t\t\tresult[i+1].Whitespace &= ^css_ast.WhitespaceBefore\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttoken.Whitespace |= css_ast.WhitespaceAfter\n\t\t\t\t\tif i+1 < len(result) {\n\t\t\t\t\t\tresult[i+1].Whitespace |= css_ast.WhitespaceBefore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Insert an explicit whitespace token if we're in verbatim mode and all\n\t// tokens were whitespace. In this case there is no token to attach the\n\t// whitespace before/after flags so this is the only way to represent this.\n\t// This is the only case where this function generates an explicit whitespace\n\t// token. It represents whitespace as flags in all other cases.\n\tif opts.verbatimWhitespace && len(result) == 0 && nextWhitespace == css_ast.WhitespaceBefore {\n\t\tresult = append(result, css_ast.Token{\n\t\t\tKind: css_lexer.TWhitespace,\n\t\t})\n\t}\n\n\treturn result, tokens\n}\n\nfunc shiftDot(text string, dotOffset int) (string, bool) {\n\t// This doesn't handle numbers with exponents\n\tif strings.ContainsAny(text, \"eE\") {\n\t\treturn \"\", false\n\t}\n\n\t// Handle a leading sign\n\tsign := \"\"\n\tif len(text) > 0 && (text[0] == '-' || text[0] == '+') {\n\t\tsign = text[:1]\n\t\ttext = text[1:]\n\t}\n\n\t// Remove the dot\n\tdot := strings.IndexByte(text, '.')\n\tif dot == -1 {\n\t\tdot = len(text)\n\t} else {\n\t\ttext = text[:dot] + text[dot+1:]\n\t}\n\n\t// Move the dot\n\tdot += dotOffset\n\n\t// Remove any leading zeros before the dot\n\tfor len(text) > 0 && dot > 0 && text[0] == '0' {\n\t\ttext = text[1:]\n\t\tdot--\n\t}\n\n\t// Remove any trailing zeros after the dot\n\tfor len(text) > 0 && len(text) > dot && text[len(text)-1] == '0' {\n\t\ttext = text[:len(text)-1]\n\t}\n\n\t// Does this number have no fractional component?\n\tif dot >= len(text) {\n\t\ttrailingZeros := strings.Repeat(\"0\", dot-len(text))\n\t\treturn fmt.Sprintf(\"%s%s%s\", sign, text, trailingZeros), true\n\t}\n\n\t// Potentially add leading zeros\n\tif dot < 0 {\n\t\ttext = strings.Repeat(\"0\", -dot) + text\n\t\tdot = 0\n\t}\n\n\t// Insert the dot again\n\treturn fmt.Sprintf(\"%s%s.%s\", sign, text[:dot], text[dot:]), true\n}\n\nfunc mangleDimension(value string, unit string) (string, string, bool) {\n\tconst msLen = 2\n\tconst sLen = 1\n\n\t// Mangle times: https://developer.mozilla.org/en-US/docs/Web/CSS/time\n\tif strings.EqualFold(unit, \"ms\") {\n\t\tif shifted, ok := shiftDot(value, -3); ok && len(shifted)+sLen < len(value)+msLen {\n\t\t\t// Convert \"ms\" to \"s\" if shorter\n\t\t\treturn shifted, \"s\", true\n\t\t}\n\t}\n\tif strings.EqualFold(unit, \"s\") {\n\t\tif shifted, ok := shiftDot(value, 3); ok && len(shifted)+msLen < len(value)+sLen {\n\t\t\t// Convert \"s\" to \"ms\" if shorter\n\t\t\treturn shifted, \"ms\", true\n\t\t}\n\t}\n\n\treturn \"\", \"\", false\n}\n\nfunc mangleNumber(t string) (string, bool) {\n\toriginal := t\n\n\tif dot := strings.IndexByte(t, '.'); dot != -1 {\n\t\t// Remove trailing zeros\n\t\tfor len(t) > 0 && t[len(t)-1] == '0' {\n\t\t\tt = t[:len(t)-1]\n\t\t}\n\n\t\t// Remove the decimal point if it's unnecessary\n\t\tif dot+1 == len(t) {\n\t\t\tt = t[:dot]\n\t\t\tif t == \"\" || t == \"+\" || t == \"-\" {\n\t\t\t\tt += \"0\"\n\t\t\t}\n\t\t} else {\n\t\t\t// Remove a leading zero\n\t\t\tif len(t) >= 3 && t[0] == '0' && t[1] == '.' && t[2] >= '0' && t[2] <= '9' {\n\t\t\t\tt = t[1:]\n\t\t\t} else if len(t) >= 4 && (t[0] == '+' || t[0] == '-') && t[1] == '0' && t[2] == '.' && t[3] >= '0' && t[3] <= '9' {\n\t\t\t\tt = t[0:1] + t[2:]\n\t\t\t}\n\t\t}\n\t}\n\n\treturn t, t != original\n}\n\nfunc (p *parser) parseSelectorRule(isTopLevel bool, opts parseSelectorOpts) css_ast.Rule {\n\t// Save and restore the local symbol state in case there are any bare\n\t// \":global\" or \":local\" annotations. The effect of these should be scoped\n\t// to within the selector rule.\n\tlocal := p.makeLocalSymbols\n\tpreludeStart := p.index\n\n\t// Try parsing the prelude as a selector list\n\tif list, ok := p.parseSelectorList(opts); ok {\n\t\tcanInlineNoOpNesting := true\n\t\tfor _, sel := range list {\n\t\t\t// We cannot transform the CSS \"a, b::before { & { color: red } }\" into\n\t\t\t// \"a, b::before { color: red }\" because it's basically equivalent to\n\t\t\t// \":is(a, b::before) { color: red }\" which only applies to \"a\", not to\n\t\t\t// \"b::before\" because pseudo-elements are not valid within :is():\n\t\t\t// https://www.w3.org/TR/selectors-4/#matches-pseudo. This restriction\n\t\t\t// may be relaxed in the future, but this restriction hash shipped so\n\t\t\t// we're stuck with it: https://github.com/w3c/csswg-drafts/issues/7433.\n\t\t\tif sel.UsesPseudoElement() {\n\t\t\t\tcanInlineNoOpNesting = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tselector := css_ast.RSelector{Selectors: list}\n\t\tmatchingLoc := p.current().Range.Loc\n\t\tif p.expect(css_lexer.TOpenBrace) {\n\t\t\tp.inSelectorSubtree++\n\t\t\tdeclOpts := listOfDeclarationsOpts{\n\t\t\t\tcanInlineNoOpNesting: canInlineNoOpNesting,\n\t\t\t}\n\n\t\t\t// Prepare for \"composes\" declarations\n\t\t\tif opts.composesContext != nil && len(list) == 1 && len(list[0].Selectors) == 1 && list[0].Selectors[0].IsSingleAmpersand() {\n\t\t\t\t// Support code like this:\n\t\t\t\t//\n\t\t\t\t//   .foo {\n\t\t\t\t//     :local { composes: bar }\n\t\t\t\t//     :global { composes: baz }\n\t\t\t\t//   }\n\t\t\t\t//\n\t\t\t\tdeclOpts.composesContext = opts.composesContext\n\t\t\t} else {\n\t\t\t\tcomposesContext := composesContext{parentRange: list[0].Selectors[0].Range()}\n\t\t\t\tif opts.composesContext != nil {\n\t\t\t\t\tcomposesContext.problemRange = opts.composesContext.parentRange\n\t\t\t\t}\n\t\t\t\tfor _, sel := range list {\n\t\t\t\t\tfirst := sel.Selectors[0]\n\t\t\t\t\tif first.Combinator.Byte != 0 {\n\t\t\t\t\t\tcomposesContext.problemRange = logger.Range{Loc: first.Combinator.Loc, Len: 1}\n\t\t\t\t\t} else if first.TypeSelector != nil {\n\t\t\t\t\t\tcomposesContext.problemRange = first.TypeSelector.Range()\n\t\t\t\t\t} else if len(first.NestingSelectorLocs) > 0 {\n\t\t\t\t\t\tcomposesContext.problemRange = logger.Range{Loc: first.NestingSelectorLocs[0], Len: 1}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor i, ss := range first.SubclassSelectors {\n\t\t\t\t\t\t\tclass, ok := ss.Data.(*css_ast.SSClass)\n\t\t\t\t\t\t\tif i > 0 || !ok {\n\t\t\t\t\t\t\t\tcomposesContext.problemRange = ss.Range\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomposesContext.parentRefs = append(composesContext.parentRefs, class.Name.Ref)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif composesContext.problemRange.Len > 0 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tif len(sel.Selectors) > 1 {\n\t\t\t\t\t\tcomposesContext.problemRange = sel.Selectors[1].Range()\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdeclOpts.composesContext = &composesContext\n\t\t\t}\n\n\t\t\tselector.Rules = p.parseListOfDeclarations(declOpts)\n\t\t\tp.inSelectorSubtree--\n\t\t\tcloseBraceLoc := p.current().Range.Loc\n\t\t\tif p.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc) {\n\t\t\t\tselector.CloseBraceLoc = closeBraceLoc\n\t\t\t}\n\t\t\tp.makeLocalSymbols = local\n\t\t\treturn css_ast.Rule{Loc: p.tokens[preludeStart].Range.Loc, Data: &selector}\n\t\t}\n\t}\n\n\tp.makeLocalSymbols = local\n\tp.index = preludeStart\n\n\t// Otherwise, parse a generic qualified rule\n\treturn p.parseQualifiedRule(parseQualifiedRuleOpts{\n\t\tisAlreadyInvalid:     true,\n\t\tisTopLevel:           isTopLevel,\n\t\tisDeclarationContext: opts.isDeclarationContext,\n\t})\n}\n\ntype parseQualifiedRuleOpts struct {\n\tisAlreadyInvalid     bool\n\tisTopLevel           bool\n\tisDeclarationContext bool\n}\n\nfunc (p *parser) parseQualifiedRule(opts parseQualifiedRuleOpts) css_ast.Rule {\n\tpreludeStart := p.index\n\tpreludeLoc := p.current().Range.Loc\n\nloop:\n\tfor {\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TOpenBrace, css_lexer.TEndOfFile:\n\t\t\tbreak loop\n\n\t\tcase css_lexer.TCloseBrace:\n\t\t\tif !opts.isTopLevel {\n\t\t\t\tbreak loop\n\t\t\t}\n\n\t\tcase css_lexer.TSemicolon:\n\t\t\tif opts.isDeclarationContext {\n\t\t\t\treturn css_ast.Rule{Loc: preludeLoc, Data: &css_ast.RBadDeclaration{\n\t\t\t\t\tTokens: p.convertTokens(p.tokens[preludeStart:p.index]),\n\t\t\t\t}}\n\t\t\t}\n\t\t}\n\n\t\tp.parseComponentValue()\n\t}\n\n\tqualified := css_ast.RQualified{\n\t\tPrelude: p.convertTokens(p.tokens[preludeStart:p.index]),\n\t}\n\n\tmatchingLoc := p.current().Range.Loc\n\tif p.eat(css_lexer.TOpenBrace) {\n\t\tqualified.Rules = p.parseListOfDeclarations(listOfDeclarationsOpts{})\n\t\tcloseBraceLoc := p.current().Range.Loc\n\t\tif p.expectWithMatchingLoc(css_lexer.TCloseBrace, matchingLoc) {\n\t\t\tqualified.CloseBraceLoc = closeBraceLoc\n\t\t}\n\t} else if !opts.isAlreadyInvalid {\n\t\tp.expect(css_lexer.TOpenBrace)\n\t}\n\n\treturn css_ast.Rule{Loc: preludeLoc, Data: &qualified}\n}\n\ntype endOfRuleScan uint8\n\nconst (\n\tendOfRuleUnknown endOfRuleScan = iota\n\tendOfRuleSemicolon\n\tendOfRuleOpenBrace\n)\n\n// Note: This was a late change to the CSS nesting syntax.\n// See also: https://github.com/w3c/csswg-drafts/issues/7961\nfunc (p *parser) scanForEndOfRule() (endOfRuleScan, int) {\n\tvar initialStack [4]css_lexer.T\n\tstack := initialStack[:0]\n\n\tfor i, t := range p.tokens[p.index:] {\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TSemicolon:\n\t\t\tif len(stack) == 0 {\n\t\t\t\treturn endOfRuleSemicolon, p.index + i\n\t\t\t}\n\n\t\tcase css_lexer.TFunction, css_lexer.TOpenParen:\n\t\t\tstack = append(stack, css_lexer.TCloseParen)\n\n\t\tcase css_lexer.TOpenBracket:\n\t\t\tstack = append(stack, css_lexer.TCloseBracket)\n\n\t\tcase css_lexer.TOpenBrace:\n\t\t\tif len(stack) == 0 {\n\t\t\t\treturn endOfRuleOpenBrace, p.index + i\n\t\t\t}\n\t\t\tstack = append(stack, css_lexer.TCloseBrace)\n\n\t\tcase css_lexer.TCloseParen, css_lexer.TCloseBracket:\n\t\t\tif n := len(stack); n > 0 && t.Kind == stack[n-1] {\n\t\t\t\tstack = stack[:n-1]\n\t\t\t}\n\n\t\tcase css_lexer.TCloseBrace:\n\t\t\tif n := len(stack); n > 0 && t.Kind == stack[n-1] {\n\t\t\t\tstack = stack[:n-1]\n\t\t\t} else {\n\t\t\t\treturn endOfRuleUnknown, -1\n\t\t\t}\n\t\t}\n\t}\n\n\treturn endOfRuleUnknown, -1\n}\n\nfunc (p *parser) parseDeclaration() css_ast.Rule {\n\t// Parse the key\n\tkeyStart := p.index\n\tkeyRange := p.tokens[keyStart].Range\n\tkeyIsIdent := p.expect(css_lexer.TIdent)\n\tok := false\n\tif keyIsIdent {\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tok = p.eat(css_lexer.TColon)\n\t}\n\n\t// Parse the value\n\tvalueStart := p.index\nstop:\n\tfor {\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TEndOfFile, css_lexer.TSemicolon, css_lexer.TCloseBrace:\n\t\t\tbreak stop\n\n\t\tdefault:\n\t\t\tp.parseComponentValue()\n\t\t}\n\t}\n\n\t// Stop now if this is not a valid declaration\n\tif !ok {\n\t\tif keyIsIdent {\n\t\t\tif end := keyRange.End(); end > p.prevError.Start {\n\t\t\t\tp.prevError.Start = end\n\t\t\t\tdata := p.tracker.MsgData(logger.Range{Loc: logger.Loc{Start: end}}, \"Expected \\\":\\\"\")\n\t\t\t\tdata.Location.Suggestion = \":\"\n\t\t\t\tp.log.AddMsgID(logger.MsgID_CSS_CSSSyntaxError, logger.Msg{\n\t\t\t\t\tKind: logger.Warning,\n\t\t\t\t\tData: data,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\treturn css_ast.Rule{Loc: keyRange.Loc, Data: &css_ast.RBadDeclaration{\n\t\t\tTokens: p.convertTokens(p.tokens[keyStart:p.index]),\n\t\t}}\n\t}\n\n\tkeyToken := p.tokens[keyStart]\n\tkeyText := keyToken.DecodedText(p.source.Contents)\n\tvalue := p.tokens[valueStart:p.index]\n\tverbatimWhitespace := strings.HasPrefix(keyText, \"--\")\n\n\t// Remove trailing \"!important\"\n\timportant := false\n\ti := len(value) - 1\n\tif i >= 0 && value[i].Kind == css_lexer.TWhitespace {\n\t\ti--\n\t}\n\tif i >= 0 && value[i].Kind == css_lexer.TIdent && strings.EqualFold(value[i].DecodedText(p.source.Contents), \"important\") {\n\t\ti--\n\t\tif i >= 0 && value[i].Kind == css_lexer.TWhitespace {\n\t\t\ti--\n\t\t}\n\t\tif i >= 0 && value[i].Kind == css_lexer.TDelimExclamation {\n\t\t\tvalue = value[:i]\n\t\t\timportant = true\n\t\t}\n\t}\n\n\tresult, _ := p.convertTokensHelper(value, css_lexer.TEndOfFile, convertTokensOpts{\n\t\tallowImports: true,\n\n\t\t// CSS variables require verbatim whitespace for correctness\n\t\tverbatimWhitespace: verbatimWhitespace,\n\t})\n\n\t// Insert or remove whitespace before the first token\n\tif !verbatimWhitespace && len(result) > 0 {\n\t\tif p.options.minifyWhitespace {\n\t\t\tresult[0].Whitespace &= ^css_ast.WhitespaceBefore\n\t\t} else {\n\t\t\tresult[0].Whitespace |= css_ast.WhitespaceBefore\n\t\t}\n\t}\n\n\tlowerKeyText := strings.ToLower(keyText)\n\tkey := css_ast.KnownDeclarations[lowerKeyText]\n\n\t// Attempt to point out trivial typos\n\tif key == css_ast.DUnknown {\n\t\tif corrected, ok := css_ast.MaybeCorrectDeclarationTypo(lowerKeyText); ok {\n\t\t\tdata := p.tracker.MsgData(keyToken.Range, fmt.Sprintf(\"%q is not a known CSS property\", keyText))\n\t\t\tdata.Location.Suggestion = corrected\n\t\t\tp.log.AddMsgID(logger.MsgID_CSS_UnsupportedCSSProperty, logger.Msg{Kind: logger.Warning, Data: data,\n\t\t\t\tNotes: []logger.MsgData{{Text: fmt.Sprintf(\"Did you mean %q instead?\", corrected)}}})\n\t\t}\n\t}\n\n\treturn css_ast.Rule{Loc: keyRange.Loc, Data: &css_ast.RDeclaration{\n\t\tKey:       key,\n\t\tKeyText:   keyText,\n\t\tKeyRange:  keyToken.Range,\n\t\tValue:     result,\n\t\tImportant: important,\n\t}}\n}\n\nfunc (p *parser) parseComponentValue() {\n\tswitch p.current().Kind {\n\tcase css_lexer.TFunction:\n\t\tp.parseBlock(css_lexer.TFunction, css_lexer.TCloseParen)\n\n\tcase css_lexer.TOpenParen:\n\t\tp.parseBlock(css_lexer.TOpenParen, css_lexer.TCloseParen)\n\n\tcase css_lexer.TOpenBrace:\n\t\tp.parseBlock(css_lexer.TOpenBrace, css_lexer.TCloseBrace)\n\n\tcase css_lexer.TOpenBracket:\n\t\tp.parseBlock(css_lexer.TOpenBracket, css_lexer.TCloseBracket)\n\n\tcase css_lexer.TEndOfFile:\n\t\tp.unexpected()\n\n\tdefault:\n\t\tp.advance()\n\t}\n}\n\nfunc (p *parser) parseBlock(open css_lexer.T, close css_lexer.T) {\n\tcurrent := p.current()\n\tmatchingStart := current.Range.End() - 1\n\tif p.expect(open) {\n\t\tfor !p.eat(close) {\n\t\t\tif p.peek(css_lexer.TEndOfFile) {\n\t\t\t\tp.expectWithMatchingLoc(close, logger.Loc{Start: matchingStart})\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tp.parseComponentValue()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_parser_media.go",
    "content": "package css_parser\n\nimport (\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\n// Reference: https://drafts.csswg.org/mediaqueries-4/\nfunc (p *parser) parseMediaQueryListUntil(stop func(css_lexer.T) bool) []css_ast.MediaQuery {\n\tvar queries []css_ast.MediaQuery\n\tp.eat(css_lexer.TWhitespace)\n\tfor !p.peek(css_lexer.TEndOfFile) && !stop(p.current().Kind) {\n\t\tstart := p.index\n\t\tquery, ok := p.parseMediaQuery()\n\t\tif !ok {\n\t\t\t// If parsing failed, parse an arbitrary sequence of tokens instead\n\t\t\tp.index = start\n\t\t\tloc := p.current().Range.Loc\n\t\t\tfor !p.peek(css_lexer.TEndOfFile) && !stop(p.current().Kind) && !p.peek(css_lexer.TComma) {\n\t\t\t\tp.parseComponentValue()\n\t\t\t}\n\t\t\ttokens := p.convertTokens(p.tokens[start:p.index])\n\t\t\tquery = css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQArbitraryTokens{Tokens: tokens}}\n\t\t}\n\t\tqueries = append(queries, query)\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tif !p.eat(css_lexer.TComma) {\n\t\t\tbreak\n\t\t}\n\t\tp.eat(css_lexer.TWhitespace)\n\t}\n\treturn queries\n}\n\nfunc (p *parser) parseMediaQuery() (css_ast.MediaQuery, bool) {\n\tloc := p.current().Range.Loc\n\n\t// Check for a media condition first\n\tif p.looksLikeMediaCondition() {\n\t\treturn p.parseMediaCondition(mediaWithOr)\n\t}\n\n\t// Parse the media type and potentially the leading \"not\" or \"only\" keyword\n\tmediaType := p.decoded()\n\tif !p.peek(css_lexer.TIdent) {\n\t\tp.expect(css_lexer.TIdent)\n\t\treturn css_ast.MediaQuery{}, false\n\t}\n\top := css_ast.MQTypeOpNone\n\tif strings.EqualFold(mediaType, \"not\") {\n\t\top = css_ast.MQTypeOpNot\n\t} else if strings.EqualFold(mediaType, \"only\") {\n\t\top = css_ast.MQTypeOpOnly\n\t}\n\tif op != css_ast.MQTypeOpNone {\n\t\tp.advance()\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tmediaType = p.decoded()\n\t\tif !p.peek(css_lexer.TIdent) {\n\t\t\tp.expect(css_lexer.TIdent)\n\t\t\treturn css_ast.MediaQuery{}, false\n\t\t}\n\t}\n\n\t// The <media-type> production does not include the keywords \"only\", \"not\", \"and\", \"or\", and \"layer\".\n\tif strings.EqualFold(mediaType, \"only\") ||\n\t\tstrings.EqualFold(mediaType, \"not\") ||\n\t\tstrings.EqualFold(mediaType, \"and\") ||\n\t\tstrings.EqualFold(mediaType, \"or\") ||\n\t\tstrings.EqualFold(mediaType, \"layer\") {\n\t\tp.unexpected()\n\t\treturn css_ast.MediaQuery{}, false\n\t}\n\tp.advance()\n\tp.eat(css_lexer.TWhitespace)\n\n\t// Potentially parse a chain of \"and\" operators\n\tvar andOrNull css_ast.MediaQuery\n\tif p.peek(css_lexer.TIdent) && strings.EqualFold(p.decoded(), \"and\") {\n\t\tp.advance()\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tvar ok bool\n\t\tandOrNull, ok = p.parseMediaCondition(mediaWithoutOr)\n\t\tif !ok {\n\t\t\treturn css_ast.MediaQuery{}, false\n\t\t}\n\t}\n\n\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQType{Op: op, Type: mediaType, AndOrNull: andOrNull}}, true\n}\n\nfunc (p *parser) looksLikeMediaCondition() bool {\n\tkind := p.current().Kind\n\treturn kind == css_lexer.TOpenParen || kind == css_lexer.TFunction ||\n\t\t(kind == css_lexer.TIdent && strings.EqualFold(p.decoded(), \"not\") &&\n\t\t\tp.next().Kind == css_lexer.TWhitespace &&\n\t\t\tp.at(p.index+2).Kind == css_lexer.TOpenParen)\n}\n\ntype mediaOr uint8\n\nconst (\n\tmediaWithOr mediaOr = iota\n\tmediaWithoutOr\n)\n\nfunc (p *parser) parseMediaCondition(or mediaOr) (css_ast.MediaQuery, bool) {\n\tloc := p.current().Range.Loc\n\n\t// Handle a leading \"not\"\n\tif p.peek(css_lexer.TIdent) && strings.EqualFold(p.decoded(), \"not\") {\n\t\tp.advance()\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tif inner, ok := p.parseMediaInParens(); !ok {\n\t\t\treturn css_ast.MediaQuery{}, false\n\t\t} else {\n\t\t\treturn p.maybeSimplifyMediaNot(loc, inner), true\n\t\t}\n\t}\n\n\t// Parse the first term\n\tfirst, ok := p.parseMediaInParens()\n\tif !ok {\n\t\treturn css_ast.MediaQuery{}, false\n\t}\n\tp.eat(css_lexer.TWhitespace)\n\n\t// Potentially parse a chain of \"and\" or \"or\" operators\n\tif p.peek(css_lexer.TIdent) {\n\t\tif keyword := p.decoded(); strings.EqualFold(keyword, \"and\") || (or == mediaWithOr && strings.EqualFold(keyword, \"or\")) {\n\t\t\top := css_ast.MQBinaryOpAnd\n\t\t\tif len(keyword) == 2 {\n\t\t\t\top = css_ast.MQBinaryOpOr\n\t\t\t}\n\t\t\tinner := p.appendMediaTerm([]css_ast.MediaQuery{}, first, op)\n\t\t\tfor {\n\t\t\t\tp.advance()\n\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\tnext, ok := p.parseMediaInParens()\n\t\t\t\tif !ok {\n\t\t\t\t\treturn css_ast.MediaQuery{}, false\n\t\t\t\t}\n\t\t\t\tinner = p.appendMediaTerm(inner, next, op)\n\t\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\t\tif !p.peek(css_lexer.TIdent) || !strings.EqualFold(p.decoded(), keyword) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQBinary{Op: op, Terms: inner}}, true\n\t\t}\n\t}\n\n\treturn first, true\n}\n\nfunc (p *parser) appendMediaTerm(inner []css_ast.MediaQuery, term css_ast.MediaQuery, op css_ast.MQBinaryOp) []css_ast.MediaQuery {\n\t// \"(a and b) and c\" => \"a and b and c\"\n\t// \"(a or b) or c\" => \"a or b or c\"\n\tif binary, ok := term.Data.(*css_ast.MQBinary); ok && binary.Op == op && p.options.minifySyntax {\n\t\treturn append(inner, binary.Terms...)\n\t} else {\n\t\treturn append(inner, term)\n\t}\n}\n\nfunc (p *parser) parseMediaInParens() (css_ast.MediaQuery, bool) {\n\tp.eat(css_lexer.TWhitespace)\n\tstart := p.index\n\n\t// Consume the opening token\n\tisFunction := p.eat(css_lexer.TFunction)\n\tif !isFunction && !p.expect(css_lexer.TOpenParen) {\n\t\treturn css_ast.MediaQuery{}, false\n\t}\n\tp.eat(css_lexer.TWhitespace)\n\n\t// Handle a media condition\n\tif !isFunction && p.looksLikeMediaCondition() {\n\t\tif inner, ok := p.parseMediaCondition(mediaWithOr); !ok {\n\t\t\treturn css_ast.MediaQuery{}, false\n\t\t} else {\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\tif !p.expect(css_lexer.TCloseParen) {\n\t\t\t\treturn css_ast.MediaQuery{}, false\n\t\t\t}\n\t\t\treturn inner, ok\n\t\t}\n\t}\n\n\t// Scan over the remaining tokens\n\tfor !p.peek(css_lexer.TCloseParen) && !p.peek(css_lexer.TEndOfFile) {\n\t\tp.parseComponentValue()\n\t}\n\tend := p.index\n\tif !p.expect(css_lexer.TCloseParen) {\n\t\treturn css_ast.MediaQuery{}, false\n\t}\n\ttokens := p.convertTokens(p.tokens[start:end])\n\tloc := tokens[0].Loc\n\n\t// Potentially pattern-match the tokens inside the parentheses\n\tif !isFunction && len(tokens) == 1 {\n\t\tif children := tokens[0].Children; children != nil {\n\t\t\tif term, ok := parsePlainOrBooleanMediaFeature(*children); ok {\n\t\t\t\treturn css_ast.MediaQuery{Loc: loc, Data: term}, true\n\t\t\t}\n\t\t\tif term, ok := parseRangeMediaFeature(*children); ok {\n\t\t\t\tif p.options.unsupportedCSSFeatures.Has(compat.MediaRange) {\n\t\t\t\t\tvar terms []css_ast.MediaQuery\n\t\t\t\t\tif term.BeforeCmp != css_ast.MQCmpNone {\n\t\t\t\t\t\tterms = append(terms, lowerMediaRange(term.NameLoc, term.Name, term.BeforeCmp.Reverse(), term.Before))\n\t\t\t\t\t}\n\t\t\t\t\tif term.AfterCmp != css_ast.MQCmpNone {\n\t\t\t\t\t\tterms = append(terms, lowerMediaRange(term.NameLoc, term.Name, term.AfterCmp, term.After))\n\t\t\t\t\t}\n\t\t\t\t\tif len(terms) == 1 {\n\t\t\t\t\t\treturn terms[0], true\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQBinary{Op: css_ast.MQBinaryOpAnd, Terms: terms}}, true\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn css_ast.MediaQuery{Loc: loc, Data: term}, true\n\t\t\t}\n\t\t}\n\t}\n\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQArbitraryTokens{Tokens: tokens}}, true\n}\n\nfunc lowerMediaRange(loc logger.Loc, name string, cmp css_ast.MQCmp, value []css_ast.Token) css_ast.MediaQuery {\n\tswitch cmp {\n\tcase css_ast.MQCmpLe:\n\t\t// \"foo <= 123\" => \"max-foo: 123\"\n\t\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQPlainOrBoolean{Name: \"max-\" + name, ValueOrNil: value}}\n\n\tcase css_ast.MQCmpGe:\n\t\t// \"foo >= 123\" => \"min-foo: 123\"\n\t\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQPlainOrBoolean{Name: \"min-\" + name, ValueOrNil: value}}\n\n\tcase css_ast.MQCmpLt:\n\t\t// \"foo < 123\" => \"not (min-foo: 123)\"\n\t\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQNot{\n\t\t\tInner: css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQPlainOrBoolean{Name: \"min-\" + name, ValueOrNil: value}},\n\t\t}}\n\n\tcase css_ast.MQCmpGt:\n\t\t// \"foo > 123\" => \"not (max-foo: 123)\"\n\t\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQNot{\n\t\t\tInner: css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQPlainOrBoolean{Name: \"max-\" + name, ValueOrNil: value}},\n\t\t}}\n\n\tdefault:\n\t\t// \"foo = 123\" => \"foo: 123\"\n\t\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQPlainOrBoolean{Name: name, ValueOrNil: value}}\n\t}\n}\n\nfunc parsePlainOrBooleanMediaFeature(tokens []css_ast.Token) (*css_ast.MQPlainOrBoolean, bool) {\n\tif len(tokens) == 1 && tokens[0].Kind == css_lexer.TIdent {\n\t\treturn &css_ast.MQPlainOrBoolean{Name: tokens[0].Text}, true\n\t}\n\tif len(tokens) >= 3 && tokens[0].Kind == css_lexer.TIdent && tokens[1].Kind == css_lexer.TColon {\n\t\tif value, rest := scanMediaValue(tokens[2:]); len(rest) == 0 {\n\t\t\treturn &css_ast.MQPlainOrBoolean{Name: tokens[0].Text, ValueOrNil: value}, true\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc parseRangeMediaFeature(tokens []css_ast.Token) (*css_ast.MQRange, bool) {\n\tif first, tokens := scanMediaValue(tokens); len(first) > 0 {\n\t\tif firstCmp, tokens := scanMediaComparison(tokens); firstCmp != css_ast.MQCmpNone {\n\t\t\tif second, tokens := scanMediaValue(tokens); len(second) > 0 {\n\t\t\t\tif len(tokens) == 0 {\n\t\t\t\t\tif name, nameLoc, ok := isSingleIdent(first); ok {\n\t\t\t\t\t\treturn &css_ast.MQRange{\n\t\t\t\t\t\t\tName:     name,\n\t\t\t\t\t\t\tNameLoc:  nameLoc,\n\t\t\t\t\t\t\tAfterCmp: firstCmp,\n\t\t\t\t\t\t\tAfter:    second,\n\t\t\t\t\t\t}, true\n\t\t\t\t\t} else if name, nameLoc, ok := isSingleIdent(second); ok {\n\t\t\t\t\t\treturn &css_ast.MQRange{\n\t\t\t\t\t\t\tBefore:    first,\n\t\t\t\t\t\t\tBeforeCmp: firstCmp,\n\t\t\t\t\t\t\tName:      name,\n\t\t\t\t\t\t\tNameLoc:   nameLoc,\n\t\t\t\t\t\t}, true\n\t\t\t\t\t}\n\t\t\t\t} else if name, nameLoc, ok := isSingleIdent(second); ok {\n\t\t\t\t\tif secondCmp, tokens := scanMediaComparison(tokens); secondCmp != css_ast.MQCmpNone {\n\t\t\t\t\t\tif f, s := firstCmp.Dir(), secondCmp.Dir(); (f < 0 && s < 0) || (f > 0 && s > 0) {\n\t\t\t\t\t\t\tif third, tokens := scanMediaValue(tokens); len(third) > 0 && len(tokens) == 0 {\n\t\t\t\t\t\t\t\treturn &css_ast.MQRange{\n\t\t\t\t\t\t\t\t\tBefore:    first,\n\t\t\t\t\t\t\t\t\tBeforeCmp: firstCmp,\n\t\t\t\t\t\t\t\t\tName:      name,\n\t\t\t\t\t\t\t\t\tNameLoc:   nameLoc,\n\t\t\t\t\t\t\t\t\tAfterCmp:  secondCmp,\n\t\t\t\t\t\t\t\t\tAfter:     third,\n\t\t\t\t\t\t\t\t}, true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn nil, false\n}\n\nfunc (p *parser) maybeSimplifyMediaNot(loc logger.Loc, inner css_ast.MediaQuery) css_ast.MediaQuery {\n\tif p.options.minifySyntax {\n\t\tswitch data := inner.Data.(type) {\n\t\tcase *css_ast.MQNot:\n\t\t\t// \"not (not a)\" => \"a\"\n\t\t\t// \"not (not (not a))\" => \"not a\"\n\t\t\treturn data.Inner\n\n\t\tcase *css_ast.MQBinary:\n\t\t\t// \"not ((not a) and (not b))\" => \"a or b\"\n\t\t\t// \"not ((not a) or (not b))\" => \"a and b\"\n\t\t\tterms := make([]css_ast.MediaQuery, 0, len(data.Terms))\n\t\t\tfor _, term := range data.Terms {\n\t\t\t\tif not, ok := term.Data.(*css_ast.MQNot); ok {\n\t\t\t\t\tterms = append(terms, not.Inner)\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(terms) == len(data.Terms) {\n\t\t\t\tdata.Op ^= 1\n\t\t\t\tdata.Terms = terms\n\t\t\t\treturn inner\n\t\t\t}\n\n\t\tcase *css_ast.MQRange:\n\t\t\tif (data.BeforeCmp == css_ast.MQCmpNone && data.AfterCmp != css_ast.MQCmpEq) ||\n\t\t\t\t(data.AfterCmp == css_ast.MQCmpNone && data.BeforeCmp != css_ast.MQCmpEq) {\n\t\t\t\tdata.BeforeCmp = data.BeforeCmp.Flip()\n\t\t\t\tdata.AfterCmp = data.AfterCmp.Flip()\n\t\t\t\treturn inner\n\t\t\t}\n\t\t}\n\t}\n\treturn css_ast.MediaQuery{Loc: loc, Data: &css_ast.MQNot{Inner: inner}}\n}\n\nfunc isSingleIdent(tokens []css_ast.Token) (string, logger.Loc, bool) {\n\tif len(tokens) == 1 && tokens[0].Kind == css_lexer.TIdent {\n\t\treturn tokens[0].Text, tokens[0].Loc, true\n\t} else {\n\t\treturn \"\", logger.Loc{}, false\n\t}\n}\n\nfunc scanMediaComparison(tokens []css_ast.Token) (css_ast.MQCmp, []css_ast.Token) {\n\tif len(tokens) >= 1 {\n\t\tswitch tokens[0].Kind {\n\t\tcase css_lexer.TDelimEquals:\n\t\t\treturn css_ast.MQCmpEq, tokens[1:]\n\n\t\tcase css_lexer.TDelimLessThan:\n\t\t\t// Handle \"<=\" or \"<\"\n\t\t\tif len(tokens) >= 2 && tokens[1].Kind == css_lexer.TDelimEquals &&\n\t\t\t\t((tokens[0].Whitespace&css_ast.WhitespaceAfter)|(tokens[1].Whitespace&css_ast.WhitespaceBefore)) == 0 {\n\t\t\t\treturn css_ast.MQCmpLe, tokens[2:]\n\t\t\t}\n\t\t\treturn css_ast.MQCmpLt, tokens[1:]\n\n\t\tcase css_lexer.TDelimGreaterThan:\n\t\t\t// Handle \">=\" or \">\"\n\t\t\tif len(tokens) >= 2 && tokens[1].Kind == css_lexer.TDelimEquals &&\n\t\t\t\t((tokens[0].Whitespace&css_ast.WhitespaceAfter)|(tokens[1].Whitespace&css_ast.WhitespaceBefore)) == 0 {\n\t\t\t\treturn css_ast.MQCmpGe, tokens[2:]\n\t\t\t}\n\t\t\treturn css_ast.MQCmpGt, tokens[1:]\n\t\t}\n\t}\n\n\treturn css_ast.MQCmpNone, tokens\n}\n\nfunc scanMediaValue(tokens []css_ast.Token) ([]css_ast.Token, []css_ast.Token) {\n\tn := 0\n\n\tif len(tokens) >= 1 {\n\t\tswitch tokens[0].Kind {\n\t\tcase css_lexer.TDimension, css_lexer.TIdent:\n\t\t\tn = 1\n\n\t\tcase css_lexer.TNumber:\n\t\t\t// Potentially recognize a ratio which is \"<number> / <number>\"\n\t\t\tif len(tokens) >= 3 && tokens[1].Kind == css_lexer.TDelimSlash && tokens[2].Kind == css_lexer.TNumber {\n\t\t\t\tn = 3\n\t\t\t} else {\n\t\t\t\tn = 1\n\t\t\t}\n\t\t}\n\t}\n\n\t// Trim whitespace at the endpoints\n\tif n > 0 {\n\t\ttokens[0].Whitespace &= ^css_ast.WhitespaceBefore\n\t\ttokens[n-1].Whitespace &= ^css_ast.WhitespaceAfter\n\t}\n\n\treturn tokens[:n], tokens[n:]\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_parser_selector.go",
    "content": "package css_parser\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\ntype parseSelectorOpts struct {\n\tcomposesContext         *composesContext\n\tpseudoClassKind         css_ast.PseudoClassKind\n\tisDeclarationContext    bool\n\tstopOnCloseParen        bool\n\tonlyOneComplexSelector  bool\n\tisForgivingSelectorList bool\n\tnoLeadingCombinator     bool\n}\n\nfunc (p *parser) parseSelectorList(opts parseSelectorOpts) (list []css_ast.ComplexSelector, ok bool) {\n\t// Potentially parse an empty list for \":is()\" and \":where()\"\n\tif opts.isForgivingSelectorList && opts.stopOnCloseParen && p.peek(css_lexer.TCloseParen) {\n\t\tok = true\n\t\treturn\n\t}\n\n\t// Parse the first selector\n\tsel, good := p.parseComplexSelector(parseComplexSelectorOpts{\n\t\tparseSelectorOpts: opts,\n\t\tisFirst:           true,\n\t})\n\tif !good {\n\t\treturn\n\t}\n\tlist = p.flattenLocalAndGlobalSelectors(list, sel)\n\n\t// Parse the remaining selectors\n\tif opts.onlyOneComplexSelector {\n\t\tif t := p.current(); t.Kind == css_lexer.TComma {\n\t\t\tp.prevError = t.Range.Loc\n\t\t\tkind := fmt.Sprintf(\":%s(...)\", opts.pseudoClassKind.String())\n\t\t\tp.log.AddIDWithNotes(logger.MsgID_CSS_CSSSyntaxError, logger.Warning, &p.tracker, t.Range,\n\t\t\t\tfmt.Sprintf(\"Unexpected \\\",\\\" inside %q\", kind),\n\t\t\t\t[]logger.MsgData{{Text: fmt.Sprintf(\"Different CSS tools behave differently in this case, so esbuild doesn't allow it. \"+\n\t\t\t\t\t\"Either remove this comma or split this selector up into multiple comma-separated %q selectors instead.\", kind)}})\n\t\t\treturn\n\t\t}\n\t} else {\n\tskip:\n\t\tfor {\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\tif !p.eat(css_lexer.TComma) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\tsel, good := p.parseComplexSelector(parseComplexSelectorOpts{\n\t\t\t\tparseSelectorOpts: opts,\n\t\t\t})\n\t\t\tif !good {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Omit duplicate selectors\n\t\t\tif p.options.minifySyntax {\n\t\t\t\tfor _, existing := range list {\n\t\t\t\t\tif sel.Equal(existing, nil) {\n\t\t\t\t\t\tcontinue skip\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlist = p.flattenLocalAndGlobalSelectors(list, sel)\n\t\t}\n\t}\n\n\t// Remove the leading ampersand when minifying and it can be implied:\n\t//\n\t//   \"a { & b {} }\" => \"a { b {} }\"\n\t//\n\t// It can't be implied if it's not at the beginning, if there are multiple of\n\t// them, or if the selector list is inside of a pseudo-class selector:\n\t//\n\t//   \"a { b & {} }\"\n\t//   \"a { & b & {} }\"\n\t//   \"a { :has(& b) {} }\"\n\t//\n\tif p.options.minifySyntax && !opts.stopOnCloseParen {\n\t\tfor i := 1; i < len(list); i++ {\n\t\t\tif analyzeLeadingAmpersand(list[i], opts.isDeclarationContext) != cannotRemoveLeadingAmpersand {\n\t\t\t\tlist[i].Selectors = list[i].Selectors[1:]\n\t\t\t}\n\t\t}\n\n\t\tswitch analyzeLeadingAmpersand(list[0], opts.isDeclarationContext) {\n\t\tcase canAlwaysRemoveLeadingAmpersand:\n\t\t\tlist[0].Selectors = list[0].Selectors[1:]\n\n\t\tcase canRemoveLeadingAmpersandIfNotFirst:\n\t\t\tfor i := 1; i < len(list); i++ {\n\t\t\t\tif sel := list[i].Selectors[0]; len(sel.NestingSelectorLocs) == 0 && (sel.Combinator.Byte != 0 || sel.TypeSelector == nil) {\n\t\t\t\t\tlist[0].Selectors = list[0].Selectors[1:]\n\t\t\t\t\tlist[0], list[i] = list[i], list[0]\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tok = true\n\treturn\n}\n\nfunc mergeCompoundSelectors(target *css_ast.CompoundSelector, source css_ast.CompoundSelector) {\n\t// \".foo:local(&)\" => \"&.foo\"\n\tif len(source.NestingSelectorLocs) > 0 && len(target.NestingSelectorLocs) == 0 {\n\t\ttarget.NestingSelectorLocs = source.NestingSelectorLocs\n\t}\n\n\tif source.TypeSelector != nil {\n\t\tif target.TypeSelector == nil {\n\t\t\t// \".foo:local(div)\" => \"div.foo\"\n\t\t\ttarget.TypeSelector = source.TypeSelector\n\t\t} else {\n\t\t\t// \"div:local(span)\" => \"div:is(span)\"\n\t\t\t//\n\t\t\t// Note: All other implementations of this (Lightning CSS, PostCSS, and\n\t\t\t// Webpack) do something really weird here. They do this instead:\n\t\t\t//\n\t\t\t// \"div:local(span)\" => \"divspan\"\n\t\t\t//\n\t\t\t// But that just seems so obviously wrong that I'm not going to do that.\n\t\t\ttarget.SubclassSelectors = append(target.SubclassSelectors, css_ast.SubclassSelector{\n\t\t\t\tRange: source.TypeSelector.Range(),\n\t\t\t\tData: &css_ast.SSPseudoClassWithSelectorList{\n\t\t\t\t\tKind:      css_ast.PseudoClassIs,\n\t\t\t\t\tSelectors: []css_ast.ComplexSelector{{Selectors: []css_ast.CompoundSelector{{TypeSelector: source.TypeSelector}}}},\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\n\t// \".foo:local(.bar)\" => \".foo.bar\"\n\ttarget.SubclassSelectors = append(target.SubclassSelectors, source.SubclassSelectors...)\n}\n\nfunc containsLocalOrGlobalSelector(sel css_ast.ComplexSelector) bool {\n\tfor _, s := range sel.Selectors {\n\t\tfor _, ss := range s.SubclassSelectors {\n\t\t\tswitch pseudo := ss.Data.(type) {\n\t\t\tcase *css_ast.SSPseudoClass:\n\t\t\t\tif pseudo.Name == \"global\" || pseudo.Name == \"local\" {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\n\t\t\tcase *css_ast.SSPseudoClassWithSelectorList:\n\t\t\t\tif pseudo.Kind == css_ast.PseudoClassGlobal || pseudo.Kind == css_ast.PseudoClassLocal {\n\t\t\t\t\treturn true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\n// This handles the \":local()\" and \":global()\" annotations from CSS modules\nfunc (p *parser) flattenLocalAndGlobalSelectors(list []css_ast.ComplexSelector, sel css_ast.ComplexSelector) []css_ast.ComplexSelector {\n\t// Only do the work to flatten the whole list if there's a \":local\" or a \":global\"\n\tif p.options.symbolMode != symbolModeDisabled && containsLocalOrGlobalSelector(sel) {\n\t\tvar selectors []css_ast.CompoundSelector\n\n\t\tfor _, s := range sel.Selectors {\n\t\t\toldSubclassSelectors := s.SubclassSelectors\n\t\t\ts.SubclassSelectors = make([]css_ast.SubclassSelector, 0, len(oldSubclassSelectors))\n\n\t\t\tfor _, ss := range oldSubclassSelectors {\n\t\t\t\tswitch pseudo := ss.Data.(type) {\n\t\t\t\tcase *css_ast.SSPseudoClass:\n\t\t\t\t\tif pseudo.Name == \"global\" || pseudo.Name == \"local\" {\n\t\t\t\t\t\t// Remove bare \":global\" and \":local\" pseudo-classes\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\n\t\t\t\tcase *css_ast.SSPseudoClassWithSelectorList:\n\t\t\t\t\tif pseudo.Kind == css_ast.PseudoClassGlobal || pseudo.Kind == css_ast.PseudoClassLocal {\n\t\t\t\t\t\tinner := pseudo.Selectors[0].Selectors\n\n\t\t\t\t\t\t// Replace this pseudo-class with all inner compound selectors.\n\t\t\t\t\t\t// The first inner compound selector is merged with the compound\n\t\t\t\t\t\t// selector before it and the last inner compound selector is\n\t\t\t\t\t\t// merged with the compound selector after it:\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// \"div:local(.a .b):hover\" => \"div.a b:hover\"\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// This behavior is really strange since this is not how anything\n\t\t\t\t\t\t// involving pseudo-classes in real CSS works at all. However, all\n\t\t\t\t\t\t// other implementations (Lightning CSS, PostCSS, and Webpack) are\n\t\t\t\t\t\t// consistent with this strange behavior, so we do it too.\n\t\t\t\t\t\tif inner[0].Combinator.Byte == 0 {\n\t\t\t\t\t\t\tmergeCompoundSelectors(&s, inner[0])\n\t\t\t\t\t\t\tinner = inner[1:]\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// \"div:local(+ .foo):hover\" => \"div + .foo:hover\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif n := len(inner); n > 0 {\n\t\t\t\t\t\t\tif !s.IsInvalidBecauseEmpty() {\n\t\t\t\t\t\t\t\t// Don't add this selector if it consisted only of a bare \":global\" or \":local\"\n\t\t\t\t\t\t\t\tselectors = append(selectors, s)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tselectors = append(selectors, inner[:n-1]...)\n\t\t\t\t\t\t\ts = inner[n-1]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ts.SubclassSelectors = append(s.SubclassSelectors, ss)\n\t\t\t}\n\n\t\t\tif !s.IsInvalidBecauseEmpty() {\n\t\t\t\t// Don't add this selector if it consisted only of a bare \":global\" or \":local\"\n\t\t\t\tselectors = append(selectors, s)\n\t\t\t}\n\t\t}\n\n\t\tif len(selectors) == 0 {\n\t\t\t// Treat a bare \":global\" or \":local\" as a bare \"&\" nesting selector\n\t\t\tselectors = append(selectors, css_ast.CompoundSelector{\n\t\t\t\tNestingSelectorLocs:       []logger.Loc{sel.Selectors[0].Range().Loc},\n\t\t\t\tWasEmptyFromLocalOrGlobal: true,\n\t\t\t})\n\n\t\t\t// Make sure we report that nesting is present so that it can be lowered\n\t\t\tp.nestingIsPresent = true\n\t\t}\n\n\t\tsel.Selectors = selectors\n\t}\n\n\treturn append(list, sel)\n}\n\ntype leadingAmpersand uint8\n\nconst (\n\tcannotRemoveLeadingAmpersand leadingAmpersand = iota\n\tcanAlwaysRemoveLeadingAmpersand\n\tcanRemoveLeadingAmpersandIfNotFirst\n)\n\nfunc analyzeLeadingAmpersand(sel css_ast.ComplexSelector, isDeclarationContext bool) leadingAmpersand {\n\tif len(sel.Selectors) > 1 {\n\t\tif first := sel.Selectors[0]; first.IsSingleAmpersand() {\n\t\t\tif second := sel.Selectors[1]; second.Combinator.Byte == 0 && len(second.NestingSelectorLocs) > 0 {\n\t\t\t\t// \".foo { & &.bar {} }\" => \".foo { & &.bar {} }\"\n\t\t\t} else if second.Combinator.Byte != 0 || second.TypeSelector == nil || !isDeclarationContext {\n\t\t\t\t// \"& + div {}\" => \"+ div {}\"\n\t\t\t\t// \"& div {}\" => \"div {}\"\n\t\t\t\t// \".foo { & + div {} }\" => \".foo { + div {} }\"\n\t\t\t\t// \".foo { & + &.bar {} }\" => \".foo { + &.bar {} }\"\n\t\t\t\t// \".foo { & :hover {} }\" => \".foo { :hover {} }\"\n\t\t\t\treturn canAlwaysRemoveLeadingAmpersand\n\t\t\t} else {\n\t\t\t\t// \".foo { & div {} }\"\n\t\t\t\t// \".foo { .bar, & div {} }\" => \".foo { .bar, div {} }\"\n\t\t\t\treturn canRemoveLeadingAmpersandIfNotFirst\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// \"& {}\" => \"& {}\"\n\t}\n\treturn cannotRemoveLeadingAmpersand\n}\n\ntype parseComplexSelectorOpts struct {\n\tparseSelectorOpts\n\tisFirst bool\n}\n\nfunc (p *parser) parseComplexSelector(opts parseComplexSelectorOpts) (result css_ast.ComplexSelector, ok bool) {\n\t// This is an extension: https://drafts.csswg.org/css-nesting-1/\n\tvar combinator css_ast.Combinator\n\tif !opts.noLeadingCombinator {\n\t\tcombinator = p.parseCombinator()\n\t\tif combinator.Byte != 0 {\n\t\t\tp.nestingIsPresent = true\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t}\n\t}\n\n\t// Parent\n\tsel, good := p.parseCompoundSelector(parseComplexSelectorOpts{\n\t\tparseSelectorOpts: opts.parseSelectorOpts,\n\t\tisFirst:           opts.isFirst,\n\t})\n\tif !good {\n\t\treturn\n\t}\n\tsel.Combinator = combinator\n\tresult.Selectors = append(result.Selectors, sel)\n\n\tstop := css_lexer.TOpenBrace\n\tif opts.stopOnCloseParen {\n\t\tstop = css_lexer.TCloseParen\n\t}\n\tfor {\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tif p.peek(css_lexer.TEndOfFile) || p.peek(css_lexer.TComma) || p.peek(stop) {\n\t\t\tbreak\n\t\t}\n\n\t\t// Optional combinator\n\t\tcombinator := p.parseCombinator()\n\t\tif combinator.Byte != 0 {\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t}\n\n\t\t// Child\n\t\tsel, good := p.parseCompoundSelector(parseComplexSelectorOpts{\n\t\t\tparseSelectorOpts: opts.parseSelectorOpts,\n\t\t})\n\t\tif !good {\n\t\t\treturn\n\t\t}\n\t\tsel.Combinator = combinator\n\t\tresult.Selectors = append(result.Selectors, sel)\n\t}\n\n\tok = true\n\treturn\n}\n\nfunc (p *parser) nameToken() css_ast.NameToken {\n\tt := p.current()\n\treturn css_ast.NameToken{\n\t\tKind:  t.Kind,\n\t\tRange: t.Range,\n\t\tText:  p.decoded(),\n\t}\n}\n\nfunc (p *parser) parseCompoundSelector(opts parseComplexSelectorOpts) (sel css_ast.CompoundSelector, ok bool) {\n\tstartLoc := p.current().Range.Loc\n\n\t// This is an extension: https://drafts.csswg.org/css-nesting-1/\n\thasLeadingNestingSelector := p.peek(css_lexer.TDelimAmpersand)\n\tif hasLeadingNestingSelector {\n\t\tp.nestingIsPresent = true\n\t\tsel.NestingSelectorLocs = append(sel.NestingSelectorLocs, startLoc)\n\t\tp.advance()\n\t}\n\n\t// Parse the type selector\n\ttypeSelectorLoc := p.current().Range.Loc\n\tswitch p.current().Kind {\n\tcase css_lexer.TDelimBar, css_lexer.TIdent, css_lexer.TDelimAsterisk:\n\t\tnsName := css_ast.NamespacedName{}\n\t\tif !p.peek(css_lexer.TDelimBar) {\n\t\t\tnsName.Name = p.nameToken()\n\t\t\tp.advance()\n\t\t} else {\n\t\t\t// Hack: Create an empty \"identifier\" to represent this\n\t\t\tnsName.Name.Kind = css_lexer.TIdent\n\t\t}\n\t\tif p.eat(css_lexer.TDelimBar) {\n\t\t\tif !p.peek(css_lexer.TIdent) && !p.peek(css_lexer.TDelimAsterisk) {\n\t\t\t\tp.expect(css_lexer.TIdent)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tprefix := nsName.Name\n\t\t\tnsName.NamespacePrefix = &prefix\n\t\t\tnsName.Name = p.nameToken()\n\t\t\tp.advance()\n\t\t}\n\t\tsel.TypeSelector = &nsName\n\t}\n\n\t// Parse the subclass selectors\nsubclassSelectors:\n\tfor {\n\t\tsubclassToken := p.current()\n\n\t\tswitch subclassToken.Kind {\n\t\tcase css_lexer.THash:\n\t\t\tif (subclassToken.Flags & css_lexer.IsID) == 0 {\n\t\t\t\tbreak subclassSelectors\n\t\t\t}\n\t\t\tnameLoc := logger.Loc{Start: subclassToken.Range.Loc.Start + 1}\n\t\t\tname := p.decoded()\n\t\t\tsel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{\n\t\t\t\tRange: subclassToken.Range,\n\t\t\t\tData: &css_ast.SSHash{\n\t\t\t\t\tName: p.symbolForName(nameLoc, name),\n\t\t\t\t},\n\t\t\t})\n\t\t\tp.advance()\n\n\t\tcase css_lexer.TDelimDot:\n\t\t\tp.advance()\n\t\t\tnameRange := p.current().Range\n\t\t\tname := p.decoded()\n\t\t\tsel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{\n\t\t\t\tRange: logger.Range{Loc: subclassToken.Range.Loc, Len: nameRange.End() - subclassToken.Range.Loc.Start},\n\t\t\t\tData: &css_ast.SSClass{\n\t\t\t\t\tName: p.symbolForName(nameRange.Loc, name),\n\t\t\t\t},\n\t\t\t})\n\t\t\tif !p.expect(css_lexer.TIdent) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\tcase css_lexer.TOpenBracket:\n\t\t\tattr, r := p.parseAttributeSelector()\n\t\t\tif r.Len == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tsel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{\n\t\t\t\tRange: r,\n\t\t\t\tData:  &attr,\n\t\t\t})\n\n\t\tcase css_lexer.TColon:\n\t\t\tif p.next().Kind == css_lexer.TColon {\n\t\t\t\t// Special-case the start of the pseudo-element selector section\n\t\t\t\tfor p.peek(css_lexer.TColon) {\n\t\t\t\t\tfirstColonLoc := p.current().Range.Loc\n\t\t\t\t\tisElement := p.next().Kind == css_lexer.TColon\n\t\t\t\t\tif isElement {\n\t\t\t\t\t\tp.advance()\n\t\t\t\t\t}\n\t\t\t\t\tpseudo, r := p.parsePseudoClassSelector(firstColonLoc, isElement)\n\n\t\t\t\t\t// https://www.w3.org/TR/selectors-4/#single-colon-pseudos\n\t\t\t\t\t// The four Level 2 pseudo-elements (::before, ::after, ::first-line,\n\t\t\t\t\t// and ::first-letter) may, for legacy reasons, be represented using\n\t\t\t\t\t// the <pseudo-class-selector> grammar, with only a single \":\"\n\t\t\t\t\t// character at their start.\n\t\t\t\t\tif p.options.minifySyntax && isElement {\n\t\t\t\t\t\tif pseudo, ok := pseudo.(*css_ast.SSPseudoClass); ok && len(pseudo.Args) == 0 {\n\t\t\t\t\t\t\tswitch pseudo.Name {\n\t\t\t\t\t\t\tcase \"before\", \"after\", \"first-line\", \"first-letter\":\n\t\t\t\t\t\t\t\tpseudo.IsElement = false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{\n\t\t\t\t\t\tRange: r,\n\t\t\t\t\t\tData:  pseudo,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tbreak subclassSelectors\n\t\t\t}\n\n\t\t\tpseudo, r := p.parsePseudoClassSelector(subclassToken.Range.Loc, false)\n\t\t\tsel.SubclassSelectors = append(sel.SubclassSelectors, css_ast.SubclassSelector{\n\t\t\t\tRange: r,\n\t\t\t\tData:  pseudo,\n\t\t\t})\n\n\t\tcase css_lexer.TDelimAmpersand:\n\t\t\t// This is an extension: https://drafts.csswg.org/css-nesting-1/\n\t\t\tp.nestingIsPresent = true\n\t\t\tsel.NestingSelectorLocs = append(sel.NestingSelectorLocs, subclassToken.Range.Loc)\n\t\t\tp.advance()\n\n\t\tdefault:\n\t\t\tbreak subclassSelectors\n\t\t}\n\t}\n\n\t// The compound selector must be non-empty\n\tif sel.IsInvalidBecauseEmpty() {\n\t\tp.unexpected()\n\t\treturn\n\t}\n\n\t// Note: \"&div {}\" was originally valid, but is now an invalid selector:\n\t// https://github.com/w3c/csswg-drafts/issues/8662#issuecomment-1514977935.\n\t// This is because SASS already uses that syntax to mean something very\n\t// different, so that syntax has been removed to avoid mistakes.\n\tif hasLeadingNestingSelector && sel.TypeSelector != nil {\n\t\tr := logger.Range{Loc: typeSelectorLoc, Len: p.at(p.index-1).Range.End() - typeSelectorLoc.Start}\n\t\ttext := sel.TypeSelector.Name.Text\n\t\tif sel.TypeSelector.NamespacePrefix != nil {\n\t\t\ttext = fmt.Sprintf(\"%s|%s\", sel.TypeSelector.NamespacePrefix.Text, text)\n\t\t}\n\t\tvar howToFix string\n\t\tsuggestion := p.source.TextForRange(r)\n\t\tif opts.isFirst {\n\t\t\tsuggestion = fmt.Sprintf(\":is(%s)\", suggestion)\n\t\t\thowToFix = \"You can wrap this selector in \\\":is(...)\\\" as a workaround. \"\n\t\t} else {\n\t\t\tr = logger.Range{Loc: startLoc, Len: r.End() - startLoc.Start}\n\t\t\tsuggestion += \"&\"\n\t\t\thowToFix = \"You can move the \\\"&\\\" to the end of this selector as a workaround. \"\n\t\t}\n\t\tmsg := logger.Msg{\n\t\t\tKind: logger.Warning,\n\t\t\tData: p.tracker.MsgData(r, fmt.Sprintf(\"Cannot use type selector %q directly after nesting selector \\\"&\\\"\", text)),\n\t\t\tNotes: []logger.MsgData{{Text: \"CSS nesting syntax does not allow the \\\"&\\\" selector to come before a type selector. \" +\n\t\t\t\thowToFix +\n\t\t\t\t\"This restriction exists to avoid problems with SASS nesting, where the same syntax means something very different \" +\n\t\t\t\t\"that has no equivalent in real CSS (appending a suffix to the parent selector).\"}},\n\t\t}\n\t\tmsg.Data.Location.Suggestion = suggestion\n\t\tp.log.AddMsgID(logger.MsgID_CSS_CSSSyntaxError, msg)\n\t\treturn\n\t}\n\n\t// The type selector must always come first\n\tswitch p.current().Kind {\n\tcase css_lexer.TDelimBar, css_lexer.TIdent, css_lexer.TDelimAsterisk:\n\t\tp.unexpected()\n\t\treturn\n\t}\n\n\tok = true\n\treturn\n}\n\nfunc (p *parser) parseAttributeSelector() (attr css_ast.SSAttribute, r logger.Range) {\n\tmatchingLoc := p.current().Range.Loc\n\tp.advance()\n\n\t// Parse the namespaced name\n\tswitch p.current().Kind {\n\tcase css_lexer.TDelimBar, css_lexer.TDelimAsterisk:\n\t\t// \"[|x]\"\n\t\t// \"[*|x]\"\n\t\tif p.peek(css_lexer.TDelimAsterisk) {\n\t\t\tprefix := p.nameToken()\n\t\t\tp.advance()\n\t\t\tattr.NamespacedName.NamespacePrefix = &prefix\n\t\t} else {\n\t\t\t// \"[|attr]\" is equivalent to \"[attr]\". From the specification:\n\t\t\t// \"In keeping with the Namespaces in the XML recommendation, default\n\t\t\t// namespaces do not apply to attributes, therefore attribute selectors\n\t\t\t// without a namespace component apply only to attributes that have no\n\t\t\t// namespace (equivalent to |attr).\"\n\t\t}\n\t\tif !p.expect(css_lexer.TDelimBar) {\n\t\t\treturn\n\t\t}\n\t\tattr.NamespacedName.Name = p.nameToken()\n\t\tif !p.expect(css_lexer.TIdent) {\n\t\t\treturn\n\t\t}\n\n\tdefault:\n\t\t// \"[x]\"\n\t\t// \"[x|y]\"\n\t\tattr.NamespacedName.Name = p.nameToken()\n\t\tif !p.expect(css_lexer.TIdent) {\n\t\t\treturn\n\t\t}\n\t\tif p.next().Kind != css_lexer.TDelimEquals && p.eat(css_lexer.TDelimBar) {\n\t\t\tprefix := attr.NamespacedName.Name\n\t\t\tattr.NamespacedName.NamespacePrefix = &prefix\n\t\t\tattr.NamespacedName.Name = p.nameToken()\n\t\t\tif !p.expect(css_lexer.TIdent) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Parse the optional matcher operator\n\tp.eat(css_lexer.TWhitespace)\n\tif p.eat(css_lexer.TDelimEquals) {\n\t\tattr.MatcherOp = \"=\"\n\t} else {\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TDelimTilde:\n\t\t\tattr.MatcherOp = \"~=\"\n\t\tcase css_lexer.TDelimBar:\n\t\t\tattr.MatcherOp = \"|=\"\n\t\tcase css_lexer.TDelimCaret:\n\t\t\tattr.MatcherOp = \"^=\"\n\t\tcase css_lexer.TDelimDollar:\n\t\t\tattr.MatcherOp = \"$=\"\n\t\tcase css_lexer.TDelimAsterisk:\n\t\t\tattr.MatcherOp = \"*=\"\n\t\t}\n\t\tif attr.MatcherOp != \"\" {\n\t\t\tp.advance()\n\t\t\tif !p.expect(css_lexer.TDelimEquals) {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Parse the optional matcher value\n\tif attr.MatcherOp != \"\" {\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tif !p.peek(css_lexer.TString) && !p.peek(css_lexer.TIdent) {\n\t\t\tp.unexpected()\n\t\t}\n\t\tattr.MatcherValue = p.decoded()\n\t\tp.advance()\n\t\tp.eat(css_lexer.TWhitespace)\n\t\tif p.peek(css_lexer.TIdent) {\n\t\t\tif modifier := p.decoded(); len(modifier) == 1 {\n\t\t\t\tif c := modifier[0]; c == 'i' || c == 'I' || c == 's' || c == 'S' {\n\t\t\t\t\tattr.MatcherModifier = c\n\t\t\t\t\tp.advance()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tcloseRange := p.current().Range\n\tif !p.expectWithMatchingLoc(css_lexer.TCloseBracket, matchingLoc) {\n\t\tcloseRange.Len = 0\n\t}\n\tr = logger.Range{Loc: matchingLoc, Len: closeRange.End() - matchingLoc.Start}\n\treturn\n}\n\nfunc (p *parser) parsePseudoClassSelector(loc logger.Loc, isElement bool) (css_ast.SS, logger.Range) {\n\tp.advance()\n\n\tif p.peek(css_lexer.TFunction) {\n\t\ttext := p.decoded()\n\t\tmatchingLoc := logger.Loc{Start: p.current().Range.End() - 1}\n\t\tp.advance()\n\n\t\t// Potentially parse a pseudo-class with a selector list\n\t\tif !isElement {\n\t\t\tvar kind css_ast.PseudoClassKind\n\t\t\tlocal := p.makeLocalSymbols\n\t\t\tok := true\n\t\t\tswitch text {\n\t\t\tcase \"global\":\n\t\t\t\tkind = css_ast.PseudoClassGlobal\n\t\t\t\tif p.options.symbolMode != symbolModeDisabled {\n\t\t\t\t\tlocal = false\n\t\t\t\t}\n\t\t\tcase \"has\":\n\t\t\t\tkind = css_ast.PseudoClassHas\n\t\t\tcase \"is\":\n\t\t\t\tkind = css_ast.PseudoClassIs\n\t\t\tcase \"local\":\n\t\t\t\tkind = css_ast.PseudoClassLocal\n\t\t\t\tif p.options.symbolMode != symbolModeDisabled {\n\t\t\t\t\tlocal = true\n\t\t\t\t}\n\t\t\tcase \"not\":\n\t\t\t\tkind = css_ast.PseudoClassNot\n\t\t\tcase \"nth-child\":\n\t\t\t\tkind = css_ast.PseudoClassNthChild\n\t\t\tcase \"nth-last-child\":\n\t\t\t\tkind = css_ast.PseudoClassNthLastChild\n\t\t\tcase \"nth-of-type\":\n\t\t\t\tkind = css_ast.PseudoClassNthOfType\n\t\t\tcase \"nth-last-of-type\":\n\t\t\t\tkind = css_ast.PseudoClassNthLastOfType\n\t\t\tcase \"where\":\n\t\t\t\tkind = css_ast.PseudoClassWhere\n\t\t\tdefault:\n\t\t\t\tok = false\n\t\t\t}\n\t\t\tif ok {\n\t\t\t\told := p.index\n\t\t\t\tif kind.HasNthIndex() {\n\t\t\t\t\tp.eat(css_lexer.TWhitespace)\n\n\t\t\t\t\t// Parse the \"An+B\" syntax\n\t\t\t\t\tif index, ok := p.parseNthIndex(); ok {\n\t\t\t\t\t\tvar selectors []css_ast.ComplexSelector\n\n\t\t\t\t\t\t// Parse the optional \"of\" clause\n\t\t\t\t\t\tif (kind == css_ast.PseudoClassNthChild || kind == css_ast.PseudoClassNthLastChild) &&\n\t\t\t\t\t\t\tp.peek(css_lexer.TIdent) && strings.EqualFold(p.decoded(), \"of\") {\n\t\t\t\t\t\t\tp.advance()\n\t\t\t\t\t\t\tp.eat(css_lexer.TWhitespace)\n\n\t\t\t\t\t\t\t// Contain the effects of \":local\" and \":global\"\n\t\t\t\t\t\t\toldLocal := p.makeLocalSymbols\n\t\t\t\t\t\t\tselectors, ok = p.parseSelectorList(parseSelectorOpts{\n\t\t\t\t\t\t\t\tstopOnCloseParen:    true,\n\t\t\t\t\t\t\t\tnoLeadingCombinator: true,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tp.makeLocalSymbols = oldLocal\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// \"2n+0\" => \"2n\"\n\t\t\t\t\t\tif p.options.minifySyntax {\n\t\t\t\t\t\t\tindex.Minify()\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Match the closing \")\"\n\t\t\t\t\t\tif ok {\n\t\t\t\t\t\t\tcloseRange := p.current().Range\n\t\t\t\t\t\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {\n\t\t\t\t\t\t\t\tcloseRange.Len = 0\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn &css_ast.SSPseudoClassWithSelectorList{Kind: kind, Selectors: selectors, Index: index},\n\t\t\t\t\t\t\t\tlogger.Range{Loc: loc, Len: closeRange.End() - loc.Start}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tp.eat(css_lexer.TWhitespace)\n\n\t\t\t\t\t// \":local\" forces local names and \":global\" forces global names\n\t\t\t\t\toldLocal := p.makeLocalSymbols\n\t\t\t\t\tp.makeLocalSymbols = local\n\t\t\t\t\tselectors, ok := p.parseSelectorList(parseSelectorOpts{\n\t\t\t\t\t\tpseudoClassKind:         kind,\n\t\t\t\t\t\tstopOnCloseParen:        true,\n\t\t\t\t\t\tonlyOneComplexSelector:  kind == css_ast.PseudoClassGlobal || kind == css_ast.PseudoClassLocal,\n\t\t\t\t\t\tisForgivingSelectorList: kind == css_ast.PseudoClassIs || kind == css_ast.PseudoClassWhere,\n\t\t\t\t\t})\n\t\t\t\t\tp.makeLocalSymbols = oldLocal\n\n\t\t\t\t\t// Match the closing \")\"\n\t\t\t\t\tif ok {\n\t\t\t\t\t\tcloseRange := p.current().Range\n\t\t\t\t\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {\n\t\t\t\t\t\t\tcloseRange.Len = 0\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn &css_ast.SSPseudoClassWithSelectorList{Kind: kind, Selectors: selectors},\n\t\t\t\t\t\t\tlogger.Range{Loc: loc, Len: closeRange.End() - loc.Start}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tp.index = old\n\t\t\t}\n\t\t}\n\n\t\targs := p.convertTokens(p.parseAnyValue())\n\t\tcloseRange := p.current().Range\n\t\tif !p.expectWithMatchingLoc(css_lexer.TCloseParen, matchingLoc) {\n\t\t\tcloseRange.Len = 0\n\t\t}\n\t\treturn &css_ast.SSPseudoClass{IsElement: isElement, Name: text, Args: args},\n\t\t\tlogger.Range{Loc: loc, Len: closeRange.End() - loc.Start}\n\t}\n\n\tnameRange := p.current().Range\n\tname := p.decoded()\n\tsel := css_ast.SSPseudoClass{IsElement: isElement}\n\tif p.expect(css_lexer.TIdent) {\n\t\tsel.Name = name\n\n\t\t// \":local .local_name :global .global_name {}\"\n\t\t// \":local { .local_name { :global { .global_name {} } }\"\n\t\tif p.options.symbolMode != symbolModeDisabled {\n\t\t\tswitch name {\n\t\t\tcase \"local\":\n\t\t\t\tp.makeLocalSymbols = true\n\t\t\tcase \"global\":\n\t\t\t\tp.makeLocalSymbols = false\n\t\t\t}\n\t\t}\n\t} else {\n\t\tnameRange.Len = 0\n\t}\n\treturn &sel, logger.Range{Loc: loc, Len: nameRange.End() - loc.Start}\n}\n\nfunc (p *parser) parseAnyValue() []css_lexer.Token {\n\t// Reference: https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value\n\n\tp.stack = p.stack[:0] // Reuse allocated memory\n\tstart := p.index\n\nloop:\n\tfor {\n\t\tswitch p.current().Kind {\n\t\tcase css_lexer.TCloseParen, css_lexer.TCloseBracket, css_lexer.TCloseBrace:\n\t\t\tlast := len(p.stack) - 1\n\t\t\tif last < 0 || !p.peek(p.stack[last]) {\n\t\t\t\tbreak loop\n\t\t\t}\n\t\t\tp.stack = p.stack[:last]\n\n\t\tcase css_lexer.TSemicolon, css_lexer.TDelimExclamation:\n\t\t\tif len(p.stack) == 0 {\n\t\t\t\tbreak loop\n\t\t\t}\n\n\t\tcase css_lexer.TOpenParen, css_lexer.TFunction:\n\t\t\tp.stack = append(p.stack, css_lexer.TCloseParen)\n\n\t\tcase css_lexer.TOpenBracket:\n\t\t\tp.stack = append(p.stack, css_lexer.TCloseBracket)\n\n\t\tcase css_lexer.TOpenBrace:\n\t\t\tp.stack = append(p.stack, css_lexer.TCloseBrace)\n\n\t\tcase css_lexer.TEndOfFile:\n\t\t\tbreak loop\n\t\t}\n\n\t\tp.advance()\n\t}\n\n\ttokens := p.tokens[start:p.index]\n\tif len(tokens) == 0 {\n\t\tp.unexpected()\n\t}\n\treturn tokens\n}\n\nfunc (p *parser) parseCombinator() css_ast.Combinator {\n\tt := p.current()\n\n\tswitch t.Kind {\n\tcase css_lexer.TDelimGreaterThan:\n\t\tp.advance()\n\t\treturn css_ast.Combinator{Loc: t.Range.Loc, Byte: '>'}\n\n\tcase css_lexer.TDelimPlus:\n\t\tp.advance()\n\t\treturn css_ast.Combinator{Loc: t.Range.Loc, Byte: '+'}\n\n\tcase css_lexer.TDelimTilde:\n\t\tp.advance()\n\t\treturn css_ast.Combinator{Loc: t.Range.Loc, Byte: '~'}\n\n\tdefault:\n\t\treturn css_ast.Combinator{}\n\t}\n}\n\nfunc parseInteger(text string) (string, bool) {\n\tn := len(text)\n\tif n == 0 {\n\t\treturn \"\", false\n\t}\n\n\t// Trim leading zeros\n\tstart := 0\n\tfor start < n && text[start] == '0' {\n\t\tstart++\n\t}\n\n\t// Make sure remaining characters are digits\n\tif start == n {\n\t\treturn \"0\", true\n\t}\n\tfor i := start; i < n; i++ {\n\t\tif c := text[i]; c < '0' || c > '9' {\n\t\t\treturn \"\", false\n\t\t}\n\t}\n\treturn text[start:], true\n}\n\nfunc (p *parser) parseNthIndex() (css_ast.NthIndex, bool) {\n\ttype sign uint8\n\tconst (\n\t\tnone sign = iota\n\t\tnegative\n\t\tpositive\n\t)\n\n\t// Reference: https://drafts.csswg.org/css-syntax-3/#anb-microsyntax\n\tt0 := p.current()\n\ttext0 := p.decoded()\n\n\t// Handle \"even\" and \"odd\"\n\tif t0.Kind == css_lexer.TIdent && (text0 == \"even\" || text0 == \"odd\") {\n\t\tp.advance()\n\t\tp.eat(css_lexer.TWhitespace)\n\t\treturn css_ast.NthIndex{B: text0}, true\n\t}\n\n\t// Handle a single number\n\tif t0.Kind == css_lexer.TNumber {\n\t\tbNeg := false\n\t\tif strings.HasPrefix(text0, \"-\") {\n\t\t\tbNeg = true\n\t\t\ttext0 = text0[1:]\n\t\t} else {\n\t\t\ttext0 = strings.TrimPrefix(text0, \"+\")\n\t\t}\n\t\tif b, ok := parseInteger(text0); ok {\n\t\t\tif bNeg {\n\t\t\t\tb = \"-\" + b\n\t\t\t}\n\t\t\tp.advance()\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\treturn css_ast.NthIndex{B: b}, true\n\t\t}\n\t\tp.unexpected()\n\t\treturn css_ast.NthIndex{}, false\n\t}\n\n\taSign := none\n\tif p.eat(css_lexer.TDelimPlus) {\n\t\taSign = positive\n\t\tt0 = p.current()\n\t\ttext0 = p.decoded()\n\t}\n\n\t// Everything from here must be able to contain an \"n\"\n\tif t0.Kind != css_lexer.TIdent && t0.Kind != css_lexer.TDimension {\n\t\tp.unexpected()\n\t\treturn css_ast.NthIndex{}, false\n\t}\n\n\t// Check for a leading sign\n\tif aSign == none {\n\t\tif strings.HasPrefix(text0, \"-\") {\n\t\t\taSign = negative\n\t\t\ttext0 = text0[1:]\n\t\t} else {\n\t\t\ttext0 = strings.TrimPrefix(text0, \"+\")\n\t\t}\n\t}\n\n\t// The string must contain an \"n\"\n\tn := strings.IndexByte(text0, 'n')\n\tif n < 0 {\n\t\tp.unexpected()\n\t\treturn css_ast.NthIndex{}, false\n\t}\n\n\t// Parse the number before the \"n\"\n\tvar a string\n\tif n == 0 {\n\t\tif aSign == negative {\n\t\t\ta = \"-1\"\n\t\t} else {\n\t\t\ta = \"1\"\n\t\t}\n\t} else if aInt, ok := parseInteger(text0[:n]); ok {\n\t\tif aSign == negative {\n\t\t\taInt = \"-\" + aInt\n\t\t}\n\t\ta = aInt\n\t} else {\n\t\tp.unexpected()\n\t\treturn css_ast.NthIndex{}, false\n\t}\n\ttext0 = text0[n+1:]\n\n\t// Parse the stuff after the \"n\"\n\tbSign := none\n\tif strings.HasPrefix(text0, \"-\") {\n\t\ttext0 = text0[1:]\n\t\tif b, ok := parseInteger(text0); ok {\n\t\t\tp.advance()\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\treturn css_ast.NthIndex{A: a, B: \"-\" + b}, true\n\t\t}\n\t\tbSign = negative\n\t}\n\tif text0 != \"\" {\n\t\tp.unexpected()\n\t\treturn css_ast.NthIndex{}, false\n\t}\n\tp.advance()\n\tp.eat(css_lexer.TWhitespace)\n\n\t// Parse an optional sign delimiter\n\tif bSign == none {\n\t\tif p.eat(css_lexer.TDelimMinus) {\n\t\t\tbSign = negative\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t} else if p.eat(css_lexer.TDelimPlus) {\n\t\t\tbSign = positive\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t}\n\t}\n\n\t// Parse an optional trailing number\n\tt1 := p.current()\n\ttext1 := p.decoded()\n\tif t1.Kind == css_lexer.TNumber {\n\t\tif bSign == none {\n\t\t\tif strings.HasPrefix(text1, \"-\") {\n\t\t\t\tbSign = negative\n\t\t\t\ttext1 = text1[1:]\n\t\t\t} else if strings.HasPrefix(text1, \"+\") {\n\t\t\t\ttext1 = text1[1:]\n\t\t\t}\n\t\t}\n\t\tif b, ok := parseInteger(text1); ok {\n\t\t\tif bSign == negative {\n\t\t\t\tb = \"-\" + b\n\t\t\t}\n\t\t\tp.advance()\n\t\t\tp.eat(css_lexer.TWhitespace)\n\t\t\treturn css_ast.NthIndex{A: a, B: b}, true\n\t\t}\n\t}\n\n\t// If there is a trailing sign, then there must also be a trailing number\n\tif bSign != none {\n\t\tp.expect(css_lexer.TNumber)\n\t\treturn css_ast.NthIndex{}, false\n\t}\n\n\treturn css_ast.NthIndex{A: a}, true\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_parser/css_reduce_calc.go",
    "content": "package css_parser\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\nfunc (p *parser) tryToReduceCalcExpression(token css_ast.Token) css_ast.Token {\n\tif term := tryToParseCalcTerm(*token.Children); term != nil {\n\t\twhitespace := css_ast.WhitespaceBefore | css_ast.WhitespaceAfter\n\t\tif p.options.minifyWhitespace {\n\t\t\twhitespace = 0\n\t\t}\n\t\tterm = term.partiallySimplify()\n\t\tif result, ok := term.convertToToken(whitespace); ok {\n\t\t\tif result.Kind == css_lexer.TOpenParen {\n\t\t\t\tresult.Kind = css_lexer.TFunction\n\t\t\t\tresult.Text = \"calc\"\n\t\t\t}\n\t\t\tresult.Loc = token.Loc\n\t\t\tresult.Whitespace = css_ast.WhitespaceBefore | css_ast.WhitespaceAfter\n\t\t\treturn result\n\t\t}\n\t}\n\treturn token\n}\n\ntype calcTermWithOp struct {\n\tdata  calcTerm\n\topLoc logger.Loc\n}\n\n// See: https://www.w3.org/TR/css-values-4/#calc-internal\ntype calcTerm interface {\n\tconvertToToken(whitespace css_ast.WhitespaceFlags) (css_ast.Token, bool)\n\tpartiallySimplify() calcTerm\n}\n\ntype calcSum struct {\n\tterms []calcTermWithOp\n}\n\ntype calcProduct struct {\n\tterms []calcTermWithOp\n}\n\ntype calcNegate struct {\n\tterm calcTermWithOp\n}\n\ntype calcInvert struct {\n\tterm calcTermWithOp\n}\n\ntype calcNumeric struct {\n\tunit   string\n\tnumber float64\n\tloc    logger.Loc\n}\n\ntype calcValue struct {\n\ttoken                css_ast.Token\n\tisInvalidPlusOrMinus bool\n}\n\nfunc floatToStringForCalc(a float64) (string, bool) {\n\t// Handle non-finite cases\n\tif math.IsNaN(a) || math.IsInf(a, 0) {\n\t\treturn \"\", false\n\t}\n\n\t// Print the number as a string\n\ttext := fmt.Sprintf(\"%.05f\", a)\n\tfor text[len(text)-1] == '0' {\n\t\ttext = text[:len(text)-1]\n\t}\n\tif text[len(text)-1] == '.' {\n\t\ttext = text[:len(text)-1]\n\t}\n\tif strings.HasPrefix(text, \"0.\") {\n\t\ttext = text[1:]\n\t} else if strings.HasPrefix(text, \"-0.\") {\n\t\ttext = \"-\" + text[2:]\n\t}\n\n\t// Bail if the number is not exactly represented\n\tif number, err := strconv.ParseFloat(text, 64); err != nil || number != a {\n\t\treturn \"\", false\n\t}\n\n\treturn text, true\n}\n\nfunc (c *calcSum) convertToToken(whitespace css_ast.WhitespaceFlags) (css_ast.Token, bool) {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-serialize\n\ttokens := make([]css_ast.Token, 0, len(c.terms)*2)\n\n\t// ALGORITHM DEVIATION: Avoid parenthesizing product nodes inside sum nodes\n\tif product, ok := c.terms[0].data.(*calcProduct); ok {\n\t\ttoken, ok := product.convertToToken(whitespace)\n\t\tif !ok {\n\t\t\treturn css_ast.Token{}, false\n\t\t}\n\t\ttokens = append(tokens, *token.Children...)\n\t} else {\n\t\ttoken, ok := c.terms[0].data.convertToToken(whitespace)\n\t\tif !ok {\n\t\t\treturn css_ast.Token{}, false\n\t\t}\n\t\ttokens = append(tokens, token)\n\t}\n\n\tfor _, term := range c.terms[1:] {\n\t\t// If child is a Negate node, append \" - \" to s, then serialize the Negate’s child and append the result to s.\n\t\tif negate, ok := term.data.(*calcNegate); ok {\n\t\t\ttoken, ok := negate.term.data.convertToToken(whitespace)\n\t\t\tif !ok {\n\t\t\t\treturn css_ast.Token{}, false\n\t\t\t}\n\t\t\ttokens = append(tokens, css_ast.Token{\n\t\t\t\tLoc:        term.opLoc,\n\t\t\t\tKind:       css_lexer.TDelimMinus,\n\t\t\t\tText:       \"-\",\n\t\t\t\tWhitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter,\n\t\t\t}, token)\n\t\t\tcontinue\n\t\t}\n\n\t\t// If child is a negative numeric value, append \" - \" to s, then serialize the negation of child as normal and append the result to s.\n\t\tif numeric, ok := term.data.(*calcNumeric); ok && numeric.number < 0 {\n\t\t\tclone := *numeric\n\t\t\tclone.number = -clone.number\n\t\t\ttoken, ok := clone.convertToToken(whitespace)\n\t\t\tif !ok {\n\t\t\t\treturn css_ast.Token{}, false\n\t\t\t}\n\t\t\ttokens = append(tokens, css_ast.Token{\n\t\t\t\tLoc:        term.opLoc,\n\t\t\t\tKind:       css_lexer.TDelimMinus,\n\t\t\t\tText:       \"-\",\n\t\t\t\tWhitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter,\n\t\t\t}, token)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Otherwise, append \" + \" to s, then serialize child and append the result to s.\n\t\ttokens = append(tokens, css_ast.Token{\n\t\t\tLoc:        term.opLoc,\n\t\t\tKind:       css_lexer.TDelimPlus,\n\t\t\tText:       \"+\",\n\t\t\tWhitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter,\n\t\t})\n\n\t\t// ALGORITHM DEVIATION: Avoid parenthesizing product nodes inside sum nodes\n\t\tif product, ok := term.data.(*calcProduct); ok {\n\t\t\ttoken, ok := product.convertToToken(whitespace)\n\t\t\tif !ok {\n\t\t\t\treturn css_ast.Token{}, false\n\t\t\t}\n\t\t\ttokens = append(tokens, *token.Children...)\n\t\t} else {\n\t\t\ttoken, ok := term.data.convertToToken(whitespace)\n\t\t\tif !ok {\n\t\t\t\treturn css_ast.Token{}, false\n\t\t\t}\n\t\t\ttokens = append(tokens, token)\n\t\t}\n\t}\n\n\treturn css_ast.Token{\n\t\tLoc:      tokens[0].Loc,\n\t\tKind:     css_lexer.TOpenParen,\n\t\tText:     \"(\",\n\t\tChildren: &tokens,\n\t}, true\n}\n\nfunc (c *calcProduct) convertToToken(whitespace css_ast.WhitespaceFlags) (css_ast.Token, bool) {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-serialize\n\ttokens := make([]css_ast.Token, 0, len(c.terms)*2)\n\ttoken, ok := c.terms[0].data.convertToToken(whitespace)\n\tif !ok {\n\t\treturn css_ast.Token{}, false\n\t}\n\ttokens = append(tokens, token)\n\n\tfor _, term := range c.terms[1:] {\n\t\t// If child is an Invert node, append \" / \" to s, then serialize the Invert’s child and append the result to s.\n\t\tif invert, ok := term.data.(*calcInvert); ok {\n\t\t\ttoken, ok := invert.term.data.convertToToken(whitespace)\n\t\t\tif !ok {\n\t\t\t\treturn css_ast.Token{}, false\n\t\t\t}\n\t\t\ttokens = append(tokens, css_ast.Token{\n\t\t\t\tLoc:        term.opLoc,\n\t\t\t\tKind:       css_lexer.TDelimSlash,\n\t\t\t\tText:       \"/\",\n\t\t\t\tWhitespace: whitespace,\n\t\t\t}, token)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Otherwise, append \" * \" to s, then serialize child and append the result to s.\n\t\ttoken, ok := term.data.convertToToken(whitespace)\n\t\tif !ok {\n\t\t\treturn css_ast.Token{}, false\n\t\t}\n\t\ttokens = append(tokens, css_ast.Token{\n\t\t\tLoc:        term.opLoc,\n\t\t\tKind:       css_lexer.TDelimAsterisk,\n\t\t\tText:       \"*\",\n\t\t\tWhitespace: whitespace,\n\t\t}, token)\n\t}\n\n\treturn css_ast.Token{\n\t\tLoc:      tokens[0].Loc,\n\t\tKind:     css_lexer.TOpenParen,\n\t\tText:     \"(\",\n\t\tChildren: &tokens,\n\t}, true\n}\n\nfunc (c *calcNegate) convertToToken(whitespace css_ast.WhitespaceFlags) (css_ast.Token, bool) {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-serialize\n\ttoken, ok := c.term.data.convertToToken(whitespace)\n\tif !ok {\n\t\treturn css_ast.Token{}, false\n\t}\n\treturn css_ast.Token{\n\t\tKind: css_lexer.TOpenParen,\n\t\tText: \"(\",\n\t\tChildren: &[]css_ast.Token{\n\t\t\t{Loc: c.term.opLoc, Kind: css_lexer.TNumber, Text: \"-1\"},\n\t\t\t{Loc: c.term.opLoc, Kind: css_lexer.TDelimSlash, Text: \"*\", Whitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter},\n\t\t\ttoken,\n\t\t},\n\t}, true\n}\n\nfunc (c *calcInvert) convertToToken(whitespace css_ast.WhitespaceFlags) (css_ast.Token, bool) {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-serialize\n\ttoken, ok := c.term.data.convertToToken(whitespace)\n\tif !ok {\n\t\treturn css_ast.Token{}, false\n\t}\n\treturn css_ast.Token{\n\t\tKind: css_lexer.TOpenParen,\n\t\tText: \"(\",\n\t\tChildren: &[]css_ast.Token{\n\t\t\t{Loc: c.term.opLoc, Kind: css_lexer.TNumber, Text: \"1\"},\n\t\t\t{Loc: c.term.opLoc, Kind: css_lexer.TDelimSlash, Text: \"/\", Whitespace: css_ast.WhitespaceBefore | css_ast.WhitespaceAfter},\n\t\t\ttoken,\n\t\t},\n\t}, true\n}\n\nfunc (c *calcNumeric) convertToToken(whitespace css_ast.WhitespaceFlags) (css_ast.Token, bool) {\n\ttext, ok := floatToStringForCalc(c.number)\n\tif !ok {\n\t\treturn css_ast.Token{}, false\n\t}\n\tif c.unit == \"\" {\n\t\treturn css_ast.Token{\n\t\t\tLoc:  c.loc,\n\t\t\tKind: css_lexer.TNumber,\n\t\t\tText: text,\n\t\t}, true\n\t}\n\tif c.unit == \"%\" {\n\t\treturn css_ast.Token{\n\t\t\tLoc:  c.loc,\n\t\t\tKind: css_lexer.TPercentage,\n\t\t\tText: text + \"%\",\n\t\t}, true\n\t}\n\treturn css_ast.Token{\n\t\tLoc:        c.loc,\n\t\tKind:       css_lexer.TDimension,\n\t\tText:       text + c.unit,\n\t\tUnitOffset: uint16(len(text)),\n\t}, true\n}\n\nfunc (c *calcValue) convertToToken(whitespace css_ast.WhitespaceFlags) (css_ast.Token, bool) {\n\tt := c.token\n\tt.Whitespace = 0\n\treturn t, true\n}\n\nfunc (c *calcSum) partiallySimplify() calcTerm {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-simplification\n\n\t// For each of root’s children that are Sum nodes, replace them with their children.\n\tterms := make([]calcTermWithOp, 0, len(c.terms))\n\tfor _, term := range c.terms {\n\t\tterm.data = term.data.partiallySimplify()\n\t\tif sum, ok := term.data.(*calcSum); ok {\n\t\t\tterms = append(terms, sum.terms...)\n\t\t} else {\n\t\t\tterms = append(terms, term)\n\t\t}\n\t}\n\n\t// For each set of root’s children that are numeric values with identical units, remove\n\t// those children and replace them with a single numeric value containing the sum of the\n\t// removed nodes, and with the same unit. (E.g. combine numbers, combine percentages,\n\t// combine px values, etc.)\n\tfor i := 0; i < len(terms); i++ {\n\t\tterm := terms[i]\n\t\tif numeric, ok := term.data.(*calcNumeric); ok {\n\t\t\tend := i + 1\n\t\t\tfor j := end; j < len(terms); j++ {\n\t\t\t\tterm2 := terms[j]\n\t\t\t\tif numeric2, ok := term2.data.(*calcNumeric); ok && strings.EqualFold(numeric2.unit, numeric.unit) {\n\t\t\t\t\tnumeric.number += numeric2.number\n\t\t\t\t} else {\n\t\t\t\t\tterms[end] = term2\n\t\t\t\t\tend++\n\t\t\t\t}\n\t\t\t}\n\t\t\tterms = terms[:end]\n\t\t}\n\t}\n\n\t// If root has only a single child at this point, return the child.\n\tif len(terms) == 1 {\n\t\treturn terms[0].data\n\t}\n\n\t// Otherwise, return root.\n\tc.terms = terms\n\treturn c\n}\n\nfunc (c *calcProduct) partiallySimplify() calcTerm {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-simplification\n\n\t// For each of root’s children that are Product nodes, replace them with their children.\n\tterms := make([]calcTermWithOp, 0, len(c.terms))\n\tfor _, term := range c.terms {\n\t\tterm.data = term.data.partiallySimplify()\n\t\tif product, ok := term.data.(*calcProduct); ok {\n\t\t\tterms = append(terms, product.terms...)\n\t\t} else {\n\t\t\tterms = append(terms, term)\n\t\t}\n\t}\n\n\t// If root has multiple children that are numbers (not percentages or dimensions), remove\n\t// them and replace them with a single number containing the product of the removed nodes.\n\tfor i, term := range terms {\n\t\tif numeric, ok := term.data.(*calcNumeric); ok && numeric.unit == \"\" {\n\t\t\tend := i + 1\n\t\t\tfor j := end; j < len(terms); j++ {\n\t\t\t\tterm2 := terms[j]\n\t\t\t\tif numeric2, ok := term2.data.(*calcNumeric); ok && numeric2.unit == \"\" {\n\t\t\t\t\tnumeric.number *= numeric2.number\n\t\t\t\t} else {\n\t\t\t\t\tterms[end] = term2\n\t\t\t\t\tend++\n\t\t\t\t}\n\t\t\t}\n\t\t\tterms = terms[:end]\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// If root contains only numeric values and/or Invert nodes containing numeric values,\n\t// and multiplying the types of all the children (noting that the type of an Invert\n\t// node is the inverse of its child’s type) results in a type that matches any of the\n\t// types that a math function can resolve to, return the result of multiplying all the\n\t// values of the children (noting that the value of an Invert node is the reciprocal\n\t// of its child’s value), expressed in the result’s canonical unit.\n\tif len(terms) == 2 {\n\t\t// Right now, only handle the case of two numbers, one of which has no unit\n\t\tif first, ok := terms[0].data.(*calcNumeric); ok {\n\t\t\tif second, ok := terms[1].data.(*calcNumeric); ok {\n\t\t\t\tif first.unit == \"\" {\n\t\t\t\t\tsecond.number *= first.number\n\t\t\t\t\treturn second\n\t\t\t\t}\n\t\t\t\tif second.unit == \"\" {\n\t\t\t\t\tfirst.number *= second.number\n\t\t\t\t\treturn first\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ALGORITHM DEVIATION: Divide instead of multiply if the reciprocal is shorter\n\tfor i := 1; i < len(terms); i++ {\n\t\tif numeric, ok := terms[i].data.(*calcNumeric); ok {\n\t\t\treciprocal := 1 / numeric.number\n\t\t\tif multiply, ok := floatToStringForCalc(numeric.number); ok {\n\t\t\t\tif divide, ok := floatToStringForCalc(reciprocal); ok && len(divide) < len(multiply) {\n\t\t\t\t\tnumeric.number = reciprocal\n\t\t\t\t\tterms[i].data = &calcInvert{term: calcTermWithOp{\n\t\t\t\t\t\tdata:  numeric,\n\t\t\t\t\t\topLoc: terms[i].opLoc,\n\t\t\t\t\t}}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// If root has only a single child at this point, return the child.\n\tif len(terms) == 1 {\n\t\treturn terms[0].data\n\t}\n\n\t// Otherwise, return root.\n\tc.terms = terms\n\treturn c\n}\n\nfunc (c *calcNegate) partiallySimplify() calcTerm {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-simplification\n\n\tc.term.data = c.term.data.partiallySimplify()\n\n\t// If root’s child is a numeric value, return an equivalent numeric value, but with the value negated (0 - value).\n\tif numeric, ok := c.term.data.(*calcNumeric); ok {\n\t\tnumeric.number = -numeric.number\n\t\treturn numeric\n\t}\n\n\t// If root’s child is a Negate node, return the child’s child.\n\tif negate, ok := c.term.data.(*calcNegate); ok {\n\t\treturn negate.term.data\n\t}\n\n\treturn c\n}\n\nfunc (c *calcInvert) partiallySimplify() calcTerm {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-simplification\n\n\tc.term.data = c.term.data.partiallySimplify()\n\n\t// If root’s child is a number (not a percentage or dimension) return the reciprocal of the child’s value.\n\tif numeric, ok := c.term.data.(*calcNumeric); ok && numeric.unit == \"\" {\n\t\tnumeric.number = 1 / numeric.number\n\t\treturn numeric\n\t}\n\n\t// If root’s child is an Invert node, return the child’s child.\n\tif invert, ok := c.term.data.(*calcInvert); ok {\n\t\treturn invert.term.data\n\t}\n\n\treturn c\n}\n\nfunc (c *calcNumeric) partiallySimplify() calcTerm {\n\treturn c\n}\n\nfunc (c *calcValue) partiallySimplify() calcTerm {\n\treturn c\n}\n\nfunc tryToParseCalcTerm(tokens []css_ast.Token) calcTerm {\n\t// Specification: https://www.w3.org/TR/css-values-4/#calc-internal\n\tterms := make([]calcTermWithOp, len(tokens))\n\n\tfor i, token := range tokens {\n\t\tvar term calcTerm\n\t\tif token.Kind == css_lexer.TFunction && strings.EqualFold(token.Text, \"var\") {\n\t\t\t// Using \"var()\" should bail because it can expand to any number of tokens\n\t\t\treturn nil\n\t\t} else if token.Kind == css_lexer.TOpenParen || (token.Kind == css_lexer.TFunction && strings.EqualFold(token.Text, \"calc\")) {\n\t\t\tterm = tryToParseCalcTerm(*token.Children)\n\t\t\tif term == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t} else if token.Kind == css_lexer.TNumber {\n\t\t\tif number, err := strconv.ParseFloat(token.Text, 64); err == nil {\n\t\t\t\tterm = &calcNumeric{loc: token.Loc, number: number}\n\t\t\t} else {\n\t\t\t\tterm = &calcValue{token: token}\n\t\t\t}\n\t\t} else if token.Kind == css_lexer.TPercentage {\n\t\t\tif number, err := strconv.ParseFloat(token.PercentageValue(), 64); err == nil {\n\t\t\t\tterm = &calcNumeric{loc: token.Loc, number: number, unit: \"%\"}\n\t\t\t} else {\n\t\t\t\tterm = &calcValue{token: token}\n\t\t\t}\n\t\t} else if token.Kind == css_lexer.TDimension {\n\t\t\tif number, err := strconv.ParseFloat(token.DimensionValue(), 64); err == nil {\n\t\t\t\tterm = &calcNumeric{loc: token.Loc, number: number, unit: token.DimensionUnit()}\n\t\t\t} else {\n\t\t\t\tterm = &calcValue{token: token}\n\t\t\t}\n\t\t} else if token.Kind == css_lexer.TIdent && strings.EqualFold(token.Text, \"Infinity\") {\n\t\t\tterm = &calcNumeric{loc: token.Loc, number: math.Inf(1)}\n\t\t} else if token.Kind == css_lexer.TIdent && strings.EqualFold(token.Text, \"-Infinity\") {\n\t\t\tterm = &calcNumeric{loc: token.Loc, number: math.Inf(-1)}\n\t\t} else if token.Kind == css_lexer.TIdent && strings.EqualFold(token.Text, \"NaN\") {\n\t\t\tterm = &calcNumeric{loc: token.Loc, number: math.NaN()}\n\t\t} else {\n\t\t\tterm = &calcValue{\n\t\t\t\ttoken: token,\n\n\t\t\t\t// From the specification: \"In addition, whitespace is required on both sides of the\n\t\t\t\t// + and - operators. (The * and / operators can be used without white space around them.)\"\n\t\t\t\tisInvalidPlusOrMinus: i > 0 && i+1 < len(tokens) &&\n\t\t\t\t\t(token.Kind == css_lexer.TDelimPlus || token.Kind == css_lexer.TDelimMinus) &&\n\t\t\t\t\t(((token.Whitespace&css_ast.WhitespaceBefore) == 0 && (tokens[i-1].Whitespace&css_ast.WhitespaceAfter) == 0) ||\n\t\t\t\t\t\t(token.Whitespace&css_ast.WhitespaceAfter) == 0 && (tokens[i+1].Whitespace&css_ast.WhitespaceBefore) == 0),\n\t\t\t}\n\t\t}\n\t\tterms[i].data = term\n\t}\n\n\t// Collect children into Product and Invert nodes\n\tfirst := 1\n\tfor first+1 < len(terms) {\n\t\t// If this is a \"*\" or \"/\" operator\n\t\tif value, ok := terms[first].data.(*calcValue); ok && (value.token.Kind == css_lexer.TDelimAsterisk || value.token.Kind == css_lexer.TDelimSlash) {\n\t\t\t// Scan over the run\n\t\t\tlast := first\n\t\t\tfor last+3 < len(terms) {\n\t\t\t\tif value, ok := terms[last+2].data.(*calcValue); ok && (value.token.Kind == css_lexer.TDelimAsterisk || value.token.Kind == css_lexer.TDelimSlash) {\n\t\t\t\t\tlast += 2\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Generate a node for the run\n\t\t\tproduct := calcProduct{terms: make([]calcTermWithOp, (last-first)/2+2)}\n\t\t\tfor i := range product.terms {\n\t\t\t\tterm := terms[first+i*2-1]\n\t\t\t\tif i > 0 {\n\t\t\t\t\top := terms[first+i*2-2].data.(*calcValue).token\n\t\t\t\t\tterm.opLoc = op.Loc\n\t\t\t\t\tif op.Kind == css_lexer.TDelimSlash {\n\t\t\t\t\t\tterm.data = &calcInvert{term: term}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tproduct.terms[i] = term\n\t\t\t}\n\n\t\t\t// Replace the run with a single node\n\t\t\tterms[first-1].data = &product\n\t\t\tterms = append(terms[:first], terms[last+2:]...)\n\t\t\tcontinue\n\t\t}\n\n\t\tfirst++\n\t}\n\n\t// Collect children into Sum and Negate nodes\n\tfirst = 1\n\tfor first+1 < len(terms) {\n\t\t// If this is a \"+\" or \"-\" operator\n\t\tif value, ok := terms[first].data.(*calcValue); ok && !value.isInvalidPlusOrMinus &&\n\t\t\t(value.token.Kind == css_lexer.TDelimPlus || value.token.Kind == css_lexer.TDelimMinus) {\n\t\t\t// Scan over the run\n\t\t\tlast := first\n\t\t\tfor last+3 < len(terms) {\n\t\t\t\tif value, ok := terms[last+2].data.(*calcValue); ok && !value.isInvalidPlusOrMinus &&\n\t\t\t\t\t(value.token.Kind == css_lexer.TDelimPlus || value.token.Kind == css_lexer.TDelimMinus) {\n\t\t\t\t\tlast += 2\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Generate a node for the run\n\t\t\tsum := calcSum{terms: make([]calcTermWithOp, (last-first)/2+2)}\n\t\t\tfor i := range sum.terms {\n\t\t\t\tterm := terms[first+i*2-1]\n\t\t\t\tif i > 0 {\n\t\t\t\t\top := terms[first+i*2-2].data.(*calcValue).token\n\t\t\t\t\tterm.opLoc = op.Loc\n\t\t\t\t\tif op.Kind == css_lexer.TDelimMinus {\n\t\t\t\t\t\tterm.data = &calcNegate{term: term}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tsum.terms[i] = term\n\t\t\t}\n\n\t\t\t// Replace the run with a single node\n\t\t\tterms[first-1].data = &sum\n\t\t\tterms = append(terms[:first], terms[last+2:]...)\n\t\t\tcontinue\n\t\t}\n\n\t\tfirst++\n\t}\n\n\t// This only succeeds if everything reduces to a single term\n\tif len(terms) == 1 {\n\t\treturn terms[0].data\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/css_printer/css_printer.go",
    "content": "package css_printer\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/config\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/css_lexer\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n\t\"github.com/evanw/esbuild/internal/sourcemap\"\n)\n\nconst quoteForURL byte = 0\n\ntype printer struct {\n\toptions                Options\n\tsymbols                ast.SymbolMap\n\timportRecords          []ast.ImportRecord\n\tcss                    []byte\n\thasLegalComment        map[string]struct{}\n\textractedLegalComments []string\n\tjsonMetadataImports    []string\n\tbuilder                sourcemap.ChunkBuilder\n\toldLineStart           int\n\toldLineEnd             int\n}\n\ntype Options struct {\n\t// This will be present if the input file had a source map. In that case we\n\t// want to map all the way back to the original input file(s).\n\tInputSourceMap *sourcemap.SourceMap\n\n\t// If we're writing out a source map, this table of line start indices lets\n\t// us do binary search on to figure out what line a given AST node came from\n\tLineOffsetTables []sourcemap.LineOffsetTable\n\n\t// Local symbol renaming results go here\n\tLocalNames map[ast.Ref]string\n\n\tLineLimit           int\n\tInputSourceIndex    uint32\n\tUnsupportedFeatures compat.CSSFeature\n\tMinifyWhitespace    bool\n\tASCIIOnly           bool\n\tSourceMap           config.SourceMap\n\tAddSourceMappings   bool\n\tLegalComments       config.LegalComments\n\tNeedsMetafile       bool\n}\n\ntype PrintResult struct {\n\tCSS                    []byte\n\tExtractedLegalComments []string\n\tJSONMetadataImports    []string\n\n\t// This source map chunk just contains the VLQ-encoded offsets for the \"CSS\"\n\t// field above. It's not a full source map. The bundler will be joining many\n\t// source map chunks together to form the final source map.\n\tSourceMapChunk sourcemap.Chunk\n}\n\nfunc Print(tree css_ast.AST, symbols ast.SymbolMap, options Options) PrintResult {\n\tp := printer{\n\t\toptions:       options,\n\t\tsymbols:       symbols,\n\t\timportRecords: tree.ImportRecords,\n\t\tbuilder:       sourcemap.MakeChunkBuilder(options.InputSourceMap, options.LineOffsetTables, options.ASCIIOnly),\n\t}\n\tfor _, rule := range tree.Rules {\n\t\tp.printRule(rule, 0, false)\n\t}\n\tresult := PrintResult{\n\t\tCSS:                    p.css,\n\t\tExtractedLegalComments: p.extractedLegalComments,\n\t\tJSONMetadataImports:    p.jsonMetadataImports,\n\t}\n\tif options.SourceMap != config.SourceMapNone {\n\t\t// This is expensive. Only do this if it's necessary. For example, skipping\n\t\t// this if it's not needed sped up end-to-end parsing and printing of a\n\t\t// large CSS file from 66ms to 52ms (around 25% faster).\n\t\tresult.SourceMapChunk = p.builder.GenerateChunk(p.css)\n\t}\n\treturn result\n}\n\nfunc (p *printer) recordImportPathForMetafile(importRecordIndex uint32) {\n\tif p.options.NeedsMetafile {\n\t\trecord := p.importRecords[importRecordIndex]\n\t\texternal := \"\"\n\t\tif (record.Flags & ast.ShouldNotBeExternalInMetafile) == 0 {\n\t\t\texternal = \",\\n          \\\"external\\\": true\"\n\t\t}\n\t\tp.jsonMetadataImports = append(p.jsonMetadataImports, fmt.Sprintf(\"\\n        {\\n          \\\"path\\\": %s,\\n          \\\"kind\\\": %s%s\\n        }\",\n\t\t\thelpers.QuoteForJSON(record.Path.Text, p.options.ASCIIOnly),\n\t\t\thelpers.QuoteForJSON(record.Kind.StringForMetafile(), p.options.ASCIIOnly),\n\t\t\texternal))\n\t}\n}\n\nfunc (p *printer) printRule(rule css_ast.Rule, indent int32, omitTrailingSemicolon bool) {\n\tif r, ok := rule.Data.(*css_ast.RComment); ok {\n\t\tswitch p.options.LegalComments {\n\t\tcase config.LegalCommentsNone:\n\t\t\treturn\n\n\t\tcase config.LegalCommentsEndOfFile,\n\t\t\tconfig.LegalCommentsLinkedWithComment,\n\t\t\tconfig.LegalCommentsExternalWithoutComment:\n\n\t\t\t// Don't record the same legal comment more than once per file\n\t\t\tif p.hasLegalComment == nil {\n\t\t\t\tp.hasLegalComment = make(map[string]struct{})\n\t\t\t} else if _, ok := p.hasLegalComment[r.Text]; ok {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tp.hasLegalComment[r.Text] = struct{}{}\n\t\t\tp.extractedLegalComments = append(p.extractedLegalComments, r.Text)\n\t\t\treturn\n\t\t}\n\t}\n\n\tif p.options.LineLimit > 0 {\n\t\tp.printNewlinePastLineLimit(indent)\n\t}\n\n\tif p.options.AddSourceMappings {\n\t\tshouldPrintMapping := true\n\t\tif indent == 0 || p.options.MinifyWhitespace {\n\t\t\tswitch rule.Data.(type) {\n\t\t\tcase *css_ast.RSelector, *css_ast.RQualified, *css_ast.RBadDeclaration:\n\t\t\t\t// These rules will begin with a potentially more accurate mapping. We\n\t\t\t\t// shouldn't print a mapping here if there's no indent in between this\n\t\t\t\t// mapping and the rule.\n\t\t\t\tshouldPrintMapping = false\n\t\t\t}\n\t\t}\n\t\tif shouldPrintMapping {\n\t\t\tp.builder.AddSourceMapping(rule.Loc, \"\", p.css)\n\t\t}\n\t}\n\n\tif !p.options.MinifyWhitespace {\n\t\tp.printIndent(indent)\n\t}\n\n\tswitch r := rule.Data.(type) {\n\tcase *css_ast.RAtCharset:\n\t\t// It's not valid to remove the space in between these two tokens\n\t\tp.print(\"@charset \")\n\n\t\t// It's not valid to print the string with single quotes\n\t\tp.printQuotedWithQuote(r.Encoding, '\"', 0)\n\t\tp.print(\";\")\n\n\tcase *css_ast.RAtImport:\n\t\tif p.options.MinifyWhitespace {\n\t\t\tp.print(\"@import\")\n\t\t} else {\n\t\t\tp.print(\"@import \")\n\t\t}\n\t\trecord := p.importRecords[r.ImportRecordIndex]\n\t\tvar flags printQuotedFlags\n\t\tif record.Flags.Has(ast.ContainsUniqueKey) {\n\t\t\tflags |= printQuotedNoWrap\n\t\t}\n\t\tp.printQuoted(record.Path.Text, flags)\n\t\tp.recordImportPathForMetafile(r.ImportRecordIndex)\n\t\tif conditions := r.ImportConditions; conditions != nil {\n\t\t\tspace := !p.options.MinifyWhitespace\n\t\t\tif len(conditions.Layers) > 0 {\n\t\t\t\tif space {\n\t\t\t\t\tp.print(\" \")\n\t\t\t\t}\n\t\t\t\tp.printTokens(conditions.Layers, printTokensOpts{})\n\t\t\t\tspace = true\n\t\t\t}\n\t\t\tif len(conditions.Supports) > 0 {\n\t\t\t\tif space {\n\t\t\t\t\tp.print(\" \")\n\t\t\t\t}\n\t\t\t\tp.printTokens(conditions.Supports, printTokensOpts{})\n\t\t\t\tspace = true\n\t\t\t}\n\t\t\tif len(conditions.Queries) > 0 {\n\t\t\t\tif space {\n\t\t\t\t\tp.print(\" \")\n\t\t\t\t}\n\t\t\t\tfor i, query := range conditions.Queries {\n\t\t\t\t\tif i > 0 {\n\t\t\t\t\t\tif p.options.MinifyWhitespace {\n\t\t\t\t\t\t\tp.print(\",\")\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tp.print(\", \")\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tp.printMediaQuery(query, 0)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tp.print(\";\")\n\n\tcase *css_ast.RAtKeyframes:\n\t\tp.print(\"@\")\n\t\tp.printIdent(r.AtToken, identNormal, mayNeedWhitespaceAfter)\n\t\tp.print(\" \")\n\t\tp.printSymbol(r.Name.Loc, r.Name.Ref, identNormal, canDiscardWhitespaceAfter)\n\t\tif !p.options.MinifyWhitespace {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tif p.options.MinifyWhitespace {\n\t\t\tp.print(\"{\")\n\t\t} else {\n\t\t\tp.print(\"{\\n\")\n\t\t}\n\t\tindent++\n\t\tfor _, block := range r.Blocks {\n\t\t\tif p.options.AddSourceMappings {\n\t\t\t\tp.builder.AddSourceMapping(block.Loc, \"\", p.css)\n\t\t\t}\n\t\t\tif !p.options.MinifyWhitespace {\n\t\t\t\tp.printIndent(indent)\n\t\t\t}\n\t\t\tfor i, sel := range block.Selectors {\n\t\t\t\tif i > 0 {\n\t\t\t\t\tif p.options.MinifyWhitespace {\n\t\t\t\t\t\tp.print(\",\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.print(\", \")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tp.print(sel)\n\t\t\t}\n\t\t\tif !p.options.MinifyWhitespace {\n\t\t\t\tp.print(\" \")\n\t\t\t}\n\t\t\tp.printRuleBlock(block.Rules, indent, block.CloseBraceLoc)\n\t\t\tif !p.options.MinifyWhitespace {\n\t\t\t\tp.print(\"\\n\")\n\t\t\t}\n\t\t}\n\t\tindent--\n\t\tif p.options.AddSourceMappings && r.CloseBraceLoc.Start != 0 {\n\t\t\tp.builder.AddSourceMapping(r.CloseBraceLoc, \"\", p.css)\n\t\t}\n\t\tif !p.options.MinifyWhitespace {\n\t\t\tp.printIndent(indent)\n\t\t}\n\t\tp.print(\"}\")\n\n\tcase *css_ast.RKnownAt:\n\t\tp.print(\"@\")\n\t\twhitespace := mayNeedWhitespaceAfter\n\t\tif len(r.Prelude) == 0 {\n\t\t\twhitespace = canDiscardWhitespaceAfter\n\t\t}\n\t\tp.printIdent(r.AtToken, identNormal, whitespace)\n\t\tif (!p.options.MinifyWhitespace && r.Rules != nil) || len(r.Prelude) > 0 {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tp.printTokens(r.Prelude, printTokensOpts{})\n\t\tif r.Rules == nil {\n\t\t\tp.print(\";\")\n\t\t} else {\n\t\t\tif !p.options.MinifyWhitespace && len(r.Prelude) > 0 {\n\t\t\t\tp.print(\" \")\n\t\t\t}\n\t\t\tp.printRuleBlock(r.Rules, indent, r.CloseBraceLoc)\n\t\t}\n\n\tcase *css_ast.RUnknownAt:\n\t\tp.print(\"@\")\n\t\twhitespace := mayNeedWhitespaceAfter\n\t\tif len(r.Prelude) == 0 {\n\t\t\twhitespace = canDiscardWhitespaceAfter\n\t\t}\n\t\tp.printIdent(r.AtToken, identNormal, whitespace)\n\t\tif (!p.options.MinifyWhitespace && len(r.Block) != 0) || len(r.Prelude) > 0 {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tp.printTokens(r.Prelude, printTokensOpts{})\n\t\tif !p.options.MinifyWhitespace && len(r.Block) != 0 && len(r.Prelude) > 0 {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tif len(r.Block) == 0 {\n\t\t\tp.print(\";\")\n\t\t} else {\n\t\t\tp.printTokens(r.Block, printTokensOpts{})\n\t\t}\n\n\tcase *css_ast.RSelector:\n\t\tp.printComplexSelectors(r.Selectors, indent, layoutMultiLine)\n\t\tif !p.options.MinifyWhitespace {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tp.printRuleBlock(r.Rules, indent, r.CloseBraceLoc)\n\n\tcase *css_ast.RQualified:\n\t\thasWhitespaceAfter := p.printTokens(r.Prelude, printTokensOpts{})\n\t\tif !hasWhitespaceAfter && !p.options.MinifyWhitespace {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tp.printRuleBlock(r.Rules, indent, r.CloseBraceLoc)\n\n\tcase *css_ast.RDeclaration:\n\t\tp.printIdent(r.KeyText, identNormal, canDiscardWhitespaceAfter)\n\t\tp.print(\":\")\n\t\thasWhitespaceAfter := p.printTokens(r.Value, printTokensOpts{\n\t\t\tindent:        indent,\n\t\t\tisDeclaration: true,\n\t\t})\n\t\tif r.Important {\n\t\t\tif !hasWhitespaceAfter && !p.options.MinifyWhitespace && len(r.Value) > 0 {\n\t\t\t\tp.print(\" \")\n\t\t\t}\n\t\t\tp.print(\"!important\")\n\t\t}\n\t\tif !omitTrailingSemicolon {\n\t\t\tp.print(\";\")\n\t\t}\n\n\tcase *css_ast.RBadDeclaration:\n\t\tp.printTokens(r.Tokens, printTokensOpts{})\n\t\tif !omitTrailingSemicolon {\n\t\t\tp.print(\";\")\n\t\t}\n\n\tcase *css_ast.RComment:\n\t\tp.printIndentedComment(indent, r.Text)\n\n\tcase *css_ast.RAtLayer:\n\t\tp.print(\"@layer\")\n\t\tfor i, parts := range r.Names {\n\t\t\tif i == 0 {\n\t\t\t\tp.print(\" \")\n\t\t\t} else if !p.options.MinifyWhitespace {\n\t\t\t\tp.print(\", \")\n\t\t\t} else {\n\t\t\t\tp.print(\",\")\n\t\t\t}\n\t\t\tp.print(strings.Join(parts, \".\"))\n\t\t}\n\t\tif r.Rules == nil {\n\t\t\tp.print(\";\")\n\t\t} else {\n\t\t\tif !p.options.MinifyWhitespace {\n\t\t\t\tp.print(\" \")\n\t\t\t}\n\t\t\tp.printRuleBlock(r.Rules, indent, r.CloseBraceLoc)\n\t\t}\n\n\tcase *css_ast.RAtMedia:\n\t\tp.print(\"@media\")\n\t\tvar flags mqFlags\n\t\tif p.options.MinifyWhitespace {\n\t\t\tflags = mqAfterIdentifier\n\t\t} else {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tfor i, query := range r.Queries {\n\t\t\tif i > 0 {\n\t\t\t\tif p.options.MinifyWhitespace {\n\t\t\t\t\tp.print(\",\")\n\t\t\t\t} else {\n\t\t\t\t\tp.print(\", \")\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.printMediaQuery(query, flags)\n\t\t\tflags = 0\n\t\t}\n\t\tif !p.options.MinifyWhitespace && len(r.Queries) > 0 {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tp.printRuleBlock(r.Rules, indent, r.CloseBraceLoc)\n\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n\n\tif !p.options.MinifyWhitespace {\n\t\tp.print(\"\\n\")\n\t}\n}\n\ntype mqFlags uint8\n\nconst (\n\tmqNeedsParens mqFlags = 1 << iota\n\tmqAfterIdentifier\n)\n\nfunc (p *printer) printMediaQuery(query css_ast.MediaQuery, flags mqFlags) {\n\tif q, ok := query.Data.(*css_ast.MQArbitraryTokens); ok {\n\t\tif (flags & mqAfterIdentifier) != 0 {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tp.printTokens(q.Tokens, printTokensOpts{})\n\t\treturn\n\t}\n\n\tswitch q := query.Data.(type) {\n\tcase *css_ast.MQType:\n\t\tif (flags & mqAfterIdentifier) != 0 {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(query.Loc, \"\", p.css)\n\t\t}\n\t\tswitch q.Op {\n\t\tcase css_ast.MQTypeOpNot:\n\t\t\tp.print(\"not \")\n\t\tcase css_ast.MQTypeOpOnly:\n\t\t\tp.print(\"only \")\n\t\t}\n\t\tp.printIdent(q.Type, identNormal, 0)\n\t\tif q.AndOrNull.Data != nil {\n\t\t\tp.print(\" and \")\n\t\t\tp.printMediaQuery(q.AndOrNull, 0)\n\t\t}\n\n\tcase *css_ast.MQNot:\n\t\tif (flags & mqNeedsParens) != 0 {\n\t\t\tp.print(\"(\")\n\t\t} else if (flags & mqAfterIdentifier) != 0 {\n\t\t\tp.print(\" \")\n\t\t}\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(query.Loc, \"\", p.css)\n\t\t}\n\t\tp.print(\"not \")\n\t\tp.printMediaQuery(q.Inner, mqNeedsParens)\n\t\tif (flags & mqNeedsParens) != 0 {\n\t\t\tp.print(\")\")\n\t\t}\n\n\tcase *css_ast.MQBinary:\n\t\tif (flags & mqNeedsParens) != 0 {\n\t\t\tp.print(\"(\")\n\t\t}\n\t\tfor i, inner := range q.Terms {\n\t\t\tif i > 0 {\n\t\t\t\tif !p.options.MinifyWhitespace {\n\t\t\t\t\tp.print(\" \")\n\t\t\t\t}\n\t\t\t\tswitch q.Op {\n\t\t\t\tcase css_ast.MQBinaryOpAnd:\n\t\t\t\t\tp.print(\"and \")\n\t\t\t\tcase css_ast.MQBinaryOpOr:\n\t\t\t\t\tp.print(\"or \")\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.printMediaQuery(inner, mqNeedsParens)\n\t\t}\n\t\tif (flags & mqNeedsParens) != 0 {\n\t\t\tp.print(\")\")\n\t\t}\n\n\tcase *css_ast.MQPlainOrBoolean:\n\t\tp.print(\"(\")\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(query.Loc, \"\", p.css)\n\t\t}\n\t\tp.printIdent(q.Name, identNormal, 0)\n\t\tif q.ValueOrNil != nil {\n\t\t\tif p.options.MinifyWhitespace {\n\t\t\t\tp.print(\":\")\n\t\t\t} else {\n\t\t\t\tp.print(\": \")\n\t\t\t}\n\t\t\tp.printTokens(q.ValueOrNil, printTokensOpts{})\n\t\t}\n\t\tp.print(\")\")\n\n\tcase *css_ast.MQRange:\n\t\tspace := \" \"\n\t\tif p.options.MinifyWhitespace {\n\t\t\tspace = \"\"\n\t\t}\n\t\tp.print(\"(\")\n\t\tif q.BeforeCmp != css_ast.MQCmpNone {\n\t\t\tp.printTokens(q.Before, printTokensOpts{})\n\t\t\tp.print(space)\n\t\t\tp.print(q.BeforeCmp.String())\n\t\t\tp.print(space)\n\t\t}\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(q.NameLoc, \"\", p.css)\n\t\t}\n\t\tp.printIdent(q.Name, identNormal, 0)\n\t\tif q.AfterCmp != css_ast.MQCmpNone {\n\t\t\tp.print(space)\n\t\t\tp.print(q.AfterCmp.String())\n\t\t\tp.print(space)\n\t\t\tp.printTokens(q.After, printTokensOpts{})\n\t\t}\n\t\tp.print(\")\")\n\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\nfunc (p *printer) printIndentedComment(indent int32, text string) {\n\t// Avoid generating a comment containing the character sequence \"</style\"\n\tif !p.options.UnsupportedFeatures.Has(compat.InlineStyle) {\n\t\ttext = helpers.EscapeClosingTag(text, \"/style\")\n\t}\n\n\t// Re-indent multi-line comments\n\tfor {\n\t\tnewline := strings.IndexByte(text, '\\n')\n\t\tif newline == -1 {\n\t\t\tbreak\n\t\t}\n\t\tp.print(text[:newline+1])\n\t\tif !p.options.MinifyWhitespace {\n\t\t\tp.printIndent(indent)\n\t\t}\n\t\ttext = text[newline+1:]\n\t}\n\tp.print(text)\n}\n\nfunc (p *printer) printRuleBlock(rules []css_ast.Rule, indent int32, closeBraceLoc logger.Loc) {\n\tif p.options.MinifyWhitespace {\n\t\tp.print(\"{\")\n\t} else {\n\t\tp.print(\"{\\n\")\n\t}\n\n\tfor i, decl := range rules {\n\t\tomitTrailingSemicolon := p.options.MinifyWhitespace && i+1 == len(rules)\n\t\tp.printRule(decl, indent+1, omitTrailingSemicolon)\n\t}\n\n\tif p.options.AddSourceMappings && closeBraceLoc.Start != 0 {\n\t\tp.builder.AddSourceMapping(closeBraceLoc, \"\", p.css)\n\t}\n\tif !p.options.MinifyWhitespace {\n\t\tp.printIndent(indent)\n\t}\n\tp.print(\"}\")\n}\n\ntype selectorLayout uint8\n\nconst (\n\tlayoutMultiLine selectorLayout = iota\n\tlayoutSingleLine\n)\n\nfunc (p *printer) printComplexSelectors(selectors []css_ast.ComplexSelector, indent int32, layout selectorLayout) {\n\tfor i, complex := range selectors {\n\t\tif i > 0 {\n\t\t\tif p.options.MinifyWhitespace {\n\t\t\t\tp.print(\",\")\n\t\t\t\tif p.options.LineLimit > 0 {\n\t\t\t\t\tp.printNewlinePastLineLimit(indent)\n\t\t\t\t}\n\t\t\t} else if layout == layoutMultiLine {\n\t\t\t\tp.print(\",\\n\")\n\t\t\t\tp.printIndent(indent)\n\t\t\t} else {\n\t\t\t\tp.print(\", \")\n\t\t\t}\n\t\t}\n\n\t\tfor j, compound := range complex.Selectors {\n\t\t\tp.printCompoundSelector(compound, j == 0, indent)\n\t\t}\n\t}\n}\n\nfunc (p *printer) printCompoundSelector(sel css_ast.CompoundSelector, isFirst bool, indent int32) {\n\tif !isFirst && sel.Combinator.Byte == 0 {\n\t\t// A space is required in between compound selectors if there is no\n\t\t// combinator in the middle. It's fine to convert \"a + b\" into \"a+b\"\n\t\t// but not to convert \"a b\" into \"ab\".\n\t\tif p.options.LineLimit <= 0 || !p.printNewlinePastLineLimit(indent) {\n\t\t\tp.print(\" \")\n\t\t}\n\t}\n\n\tif sel.Combinator.Byte != 0 {\n\t\tif !isFirst && !p.options.MinifyWhitespace {\n\t\t\tp.print(\" \")\n\t\t}\n\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(sel.Combinator.Loc, \"\", p.css)\n\t\t}\n\t\tp.css = append(p.css, sel.Combinator.Byte)\n\n\t\tif (p.options.LineLimit <= 0 || !p.printNewlinePastLineLimit(indent)) && !p.options.MinifyWhitespace {\n\t\t\tp.print(\" \")\n\t\t}\n\t}\n\n\tif sel.TypeSelector != nil {\n\t\twhitespace := mayNeedWhitespaceAfter\n\t\tif len(sel.SubclassSelectors) > 0 {\n\t\t\t// There is no chance of whitespace before a subclass selector or pseudo\n\t\t\t// class selector\n\t\t\twhitespace = canDiscardWhitespaceAfter\n\t\t}\n\t\tp.printNamespacedName(*sel.TypeSelector, whitespace)\n\t}\n\n\tfor _, loc := range sel.NestingSelectorLocs {\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(loc, \"\", p.css)\n\t\t}\n\n\t\tp.print(\"&\")\n\t}\n\n\tfor i, ss := range sel.SubclassSelectors {\n\t\twhitespace := mayNeedWhitespaceAfter\n\n\t\t// There is no chance of whitespace between subclass selectors\n\t\tif i+1 < len(sel.SubclassSelectors) {\n\t\t\twhitespace = canDiscardWhitespaceAfter\n\t\t}\n\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(ss.Range.Loc, \"\", p.css)\n\t\t}\n\n\t\tswitch s := ss.Data.(type) {\n\t\tcase *css_ast.SSHash:\n\t\t\tp.print(\"#\")\n\n\t\t\t// This deliberately does not use identHash. From the specification:\n\t\t\t// \"In <id-selector>, the <hash-token>'s value must be an identifier.\"\n\t\t\tp.printSymbol(s.Name.Loc, s.Name.Ref, identNormal, whitespace)\n\n\t\tcase *css_ast.SSClass:\n\t\t\tp.print(\".\")\n\t\t\tp.printSymbol(s.Name.Loc, s.Name.Ref, identNormal, whitespace)\n\n\t\tcase *css_ast.SSAttribute:\n\t\t\tp.print(\"[\")\n\t\t\tp.printNamespacedName(s.NamespacedName, canDiscardWhitespaceAfter)\n\t\t\tif s.MatcherOp != \"\" {\n\t\t\t\tp.print(s.MatcherOp)\n\t\t\t\tprintAsIdent := false\n\n\t\t\t\t// Print the value as an identifier if it's possible\n\t\t\t\tif css_lexer.WouldStartIdentifierWithoutEscapes(s.MatcherValue) {\n\t\t\t\t\tprintAsIdent = true\n\t\t\t\t\tfor _, c := range s.MatcherValue {\n\t\t\t\t\t\tif !css_lexer.IsNameContinue(c) {\n\t\t\t\t\t\t\tprintAsIdent = false\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif printAsIdent {\n\t\t\t\t\tp.printIdent(s.MatcherValue, identNormal, canDiscardWhitespaceAfter)\n\t\t\t\t} else {\n\t\t\t\t\tp.printQuoted(s.MatcherValue, 0)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif s.MatcherModifier != 0 {\n\t\t\t\tp.print(\" \")\n\t\t\t\tp.print(string(rune(s.MatcherModifier)))\n\t\t\t}\n\t\t\tp.print(\"]\")\n\n\t\tcase *css_ast.SSPseudoClass:\n\t\t\tp.printPseudoClassSelector(*s, whitespace)\n\n\t\tcase *css_ast.SSPseudoClassWithSelectorList:\n\t\t\tp.print(\":\")\n\t\t\tp.print(s.Kind.String())\n\t\t\tp.print(\"(\")\n\t\t\tif s.Index.A != \"\" || s.Index.B != \"\" {\n\t\t\t\tp.printNthIndex(s.Index)\n\t\t\t\tif len(s.Selectors) > 0 {\n\t\t\t\t\tif p.options.MinifyWhitespace && s.Selectors[0].Selectors[0].TypeSelector == nil {\n\t\t\t\t\t\tp.print(\" of\")\n\t\t\t\t\t} else {\n\t\t\t\t\t\tp.print(\" of \")\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.printComplexSelectors(s.Selectors, indent, layoutSingleLine)\n\t\t\tp.print(\")\")\n\n\t\tdefault:\n\t\t\tpanic(\"Internal error\")\n\t\t}\n\t}\n}\n\nfunc (p *printer) printNthIndex(index css_ast.NthIndex) {\n\tif index.A != \"\" {\n\t\tif index.A == \"-1\" {\n\t\t\tp.print(\"-\")\n\t\t} else if index.A != \"1\" {\n\t\t\tp.print(index.A)\n\t\t}\n\t\tp.print(\"n\")\n\t\tif index.B != \"\" {\n\t\t\tif !strings.HasPrefix(index.B, \"-\") {\n\t\t\t\tp.print(\"+\")\n\t\t\t}\n\t\t\tp.print(index.B)\n\t\t}\n\t} else if index.B != \"\" {\n\t\tp.print(index.B)\n\t}\n}\n\nfunc (p *printer) printNamespacedName(nsName css_ast.NamespacedName, whitespace trailingWhitespace) {\n\tif prefix := nsName.NamespacePrefix; prefix != nil {\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(prefix.Range.Loc, \"\", p.css)\n\t\t}\n\n\t\tswitch prefix.Kind {\n\t\tcase css_lexer.TIdent:\n\t\t\tp.printIdent(prefix.Text, identNormal, canDiscardWhitespaceAfter)\n\t\tcase css_lexer.TDelimAsterisk:\n\t\t\tp.print(\"*\")\n\t\tdefault:\n\t\t\tpanic(\"Internal error\")\n\t\t}\n\n\t\tp.print(\"|\")\n\t}\n\n\tif p.options.AddSourceMappings {\n\t\tp.builder.AddSourceMapping(nsName.Name.Range.Loc, \"\", p.css)\n\t}\n\n\tswitch nsName.Name.Kind {\n\tcase css_lexer.TIdent:\n\t\tp.printIdent(nsName.Name.Text, identNormal, whitespace)\n\tcase css_lexer.TDelimAsterisk:\n\t\tp.print(\"*\")\n\tcase css_lexer.TDelimAmpersand:\n\t\tp.print(\"&\")\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\nfunc (p *printer) printPseudoClassSelector(pseudo css_ast.SSPseudoClass, whitespace trailingWhitespace) {\n\tif pseudo.IsElement {\n\t\tp.print(\"::\")\n\t} else {\n\t\tp.print(\":\")\n\t}\n\n\t// This checks for \"nil\" so we can distinguish \":is()\" from \":is\"\n\tif pseudo.Args != nil {\n\t\tp.printIdent(pseudo.Name, identNormal, canDiscardWhitespaceAfter)\n\t\tp.print(\"(\")\n\t\tp.printTokens(pseudo.Args, printTokensOpts{})\n\t\tp.print(\")\")\n\t} else {\n\t\tp.printIdent(pseudo.Name, identNormal, whitespace)\n\t}\n}\n\nfunc (p *printer) print(text string) {\n\tp.css = append(p.css, text...)\n}\n\nfunc bestQuoteCharForString(text string, forURL bool) byte {\n\tforURLCost := 0\n\tsingleCost := 2\n\tdoubleCost := 2\n\n\tfor _, c := range text {\n\t\tswitch c {\n\t\tcase '\\'':\n\t\t\tforURLCost++\n\t\t\tsingleCost++\n\n\t\tcase '\"':\n\t\t\tforURLCost++\n\t\t\tdoubleCost++\n\n\t\tcase '(', ')', ' ', '\\t':\n\t\t\tforURLCost++\n\n\t\tcase '\\\\', '\\n', '\\r', '\\f':\n\t\t\tforURLCost++\n\t\t\tsingleCost++\n\t\t\tdoubleCost++\n\t\t}\n\t}\n\n\t// Quotes can sometimes be omitted for URL tokens\n\tif forURL && forURLCost < singleCost && forURLCost < doubleCost {\n\t\treturn quoteForURL\n\t}\n\n\t// Prefer double quotes to single quotes if there is no cost difference\n\tif singleCost < doubleCost {\n\t\treturn '\\''\n\t}\n\n\treturn '\"'\n}\n\ntype printQuotedFlags uint8\n\nconst (\n\tprintQuotedNoWrap printQuotedFlags = 1 << iota\n)\n\nfunc (p *printer) printQuoted(text string, flags printQuotedFlags) {\n\tp.printQuotedWithQuote(text, bestQuoteCharForString(text, false), flags)\n}\n\ntype escapeKind uint8\n\nconst (\n\tescapeNone escapeKind = iota\n\tescapeBackslash\n\tescapeHex\n)\n\nfunc (p *printer) printWithEscape(c rune, escape escapeKind, remainingText string, mayNeedWhitespaceAfter bool) {\n\tvar temp [utf8.UTFMax]byte\n\n\tif escape == escapeBackslash && ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {\n\t\t// Hexadecimal characters cannot use a plain backslash escape\n\t\tescape = escapeHex\n\t}\n\n\tswitch escape {\n\tcase escapeNone:\n\t\twidth := utf8.EncodeRune(temp[:], c)\n\t\tp.css = append(p.css, temp[:width]...)\n\n\tcase escapeBackslash:\n\t\tp.css = append(p.css, '\\\\')\n\t\twidth := utf8.EncodeRune(temp[:], c)\n\t\tp.css = append(p.css, temp[:width]...)\n\n\tcase escapeHex:\n\t\ttext := fmt.Sprintf(\"\\\\%x\", c)\n\t\tp.css = append(p.css, text...)\n\n\t\t// Make sure the next character is not interpreted as part of the escape sequence\n\t\tif len(text) < 1+6 {\n\t\t\tif next := utf8.RuneLen(c); next < len(remainingText) {\n\t\t\t\tc = rune(remainingText[next])\n\t\t\t\tif c == ' ' || c == '\\t' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') {\n\t\t\t\t\tp.css = append(p.css, ' ')\n\t\t\t\t}\n\t\t\t} else if mayNeedWhitespaceAfter {\n\t\t\t\t// If the last character is a hexadecimal escape, print a space afterwards\n\t\t\t\t// for the escape sequence to consume. That way we're sure it won't\n\t\t\t\t// accidentally consume a semantically significant space afterward.\n\t\t\t\tp.css = append(p.css, ' ')\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Note: This function is hot in profiles\nfunc (p *printer) printQuotedWithQuote(text string, quote byte, flags printQuotedFlags) {\n\tif quote != quoteForURL {\n\t\tp.css = append(p.css, quote)\n\t}\n\n\tn := len(text)\n\ti := 0\n\trunStart := 0\n\n\t// Only compute the line length if necessary\n\tvar startLineLength int\n\twrapLongLines := false\n\tif p.options.LineLimit > 0 && quote != quoteForURL && (flags&printQuotedNoWrap) == 0 {\n\t\tstartLineLength = p.currentLineLength()\n\t\tif startLineLength > p.options.LineLimit {\n\t\t\tstartLineLength = p.options.LineLimit\n\t\t}\n\t\twrapLongLines = true\n\t}\n\n\tfor i < n {\n\t\t// Wrap long lines that are over the limit using escaped newlines\n\t\tif wrapLongLines && startLineLength+i >= p.options.LineLimit {\n\t\t\tif runStart < i {\n\t\t\t\tp.css = append(p.css, text[runStart:i]...)\n\t\t\t\trunStart = i\n\t\t\t}\n\t\t\tp.css = append(p.css, \"\\\\\\n\"...)\n\t\t\tstartLineLength -= p.options.LineLimit\n\t\t}\n\n\t\tc, width := utf8.DecodeRuneInString(text[i:])\n\t\tescape := escapeNone\n\n\t\tswitch c {\n\t\tcase '\\x00', '\\r', '\\n', '\\f':\n\t\t\t// Use a hexadecimal escape for characters that would be invalid escapes\n\t\t\tescape = escapeHex\n\n\t\tcase '\\\\', rune(quote):\n\t\t\tescape = escapeBackslash\n\n\t\tcase '(', ')', ' ', '\\t', '\"', '\\'':\n\t\t\t// These characters must be escaped in URL tokens\n\t\t\tif quote == quoteForURL {\n\t\t\t\tescape = escapeBackslash\n\t\t\t}\n\n\t\tcase '/':\n\t\t\t// Avoid generating the sequence \"</style\" in CSS code\n\t\t\tif !p.options.UnsupportedFeatures.Has(compat.InlineStyle) && i >= 1 && text[i-1] == '<' && i+6 <= len(text) && strings.EqualFold(text[i+1:i+6], \"style\") {\n\t\t\t\tescape = escapeBackslash\n\t\t\t}\n\n\t\tdefault:\n\t\t\tif (p.options.ASCIIOnly && c >= 0x80) || c == '\\uFEFF' {\n\t\t\t\tescape = escapeHex\n\t\t\t}\n\t\t}\n\n\t\tif escape != escapeNone {\n\t\t\tif runStart < i {\n\t\t\t\tp.css = append(p.css, text[runStart:i]...)\n\t\t\t}\n\t\t\tp.printWithEscape(c, escape, text[i:], false)\n\t\t\trunStart = i + width\n\t\t}\n\t\ti += width\n\t}\n\n\tif runStart < n {\n\t\tp.css = append(p.css, text[runStart:]...)\n\t}\n\n\tif quote != quoteForURL {\n\t\tp.css = append(p.css, quote)\n\t}\n}\n\nfunc (p *printer) currentLineLength() int {\n\tcss := p.css\n\tn := len(css)\n\tstop := p.oldLineEnd\n\n\t// Update \"oldLineStart\" to the start of the current line\n\tfor i := n; i > stop; i-- {\n\t\tif c := css[i-1]; c == '\\r' || c == '\\n' {\n\t\t\tp.oldLineStart = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\tp.oldLineEnd = n\n\treturn n - p.oldLineStart\n}\n\nfunc (p *printer) printNewlinePastLineLimit(indent int32) bool {\n\tif p.currentLineLength() < p.options.LineLimit {\n\t\treturn false\n\t}\n\tp.print(\"\\n\")\n\tif !p.options.MinifyWhitespace {\n\t\tp.printIndent(indent)\n\t}\n\treturn true\n}\n\ntype identMode uint8\n\nconst (\n\tidentNormal identMode = iota\n\tidentHash\n\tidentDimensionUnit\n\tidentDimensionUnitAfterExponent\n)\n\ntype trailingWhitespace uint8\n\nconst (\n\tmayNeedWhitespaceAfter trailingWhitespace = iota\n\tcanDiscardWhitespaceAfter\n)\n\n// Note: This function is hot in profiles\nfunc (p *printer) printIdent(text string, mode identMode, whitespace trailingWhitespace) {\n\tn := len(text)\n\n\t// Special escape behavior for the first character\n\tinitialEscape := escapeNone\n\tswitch mode {\n\tcase identNormal:\n\t\tif !css_lexer.WouldStartIdentifierWithoutEscapes(text) {\n\t\t\tinitialEscape = escapeBackslash\n\t\t}\n\tcase identDimensionUnit, identDimensionUnitAfterExponent:\n\t\tif !css_lexer.WouldStartIdentifierWithoutEscapes(text) {\n\t\t\tinitialEscape = escapeBackslash\n\t\t} else if n > 0 {\n\t\t\tif c := text[0]; c >= '0' && c <= '9' {\n\t\t\t\t// Unit: \"2x\"\n\t\t\t\tinitialEscape = escapeHex\n\t\t\t} else if (c == 'e' || c == 'E') && mode != identDimensionUnitAfterExponent {\n\t\t\t\tif n >= 2 && text[1] >= '0' && text[1] <= '9' {\n\t\t\t\t\t// Unit: \"e2x\"\n\t\t\t\t\tinitialEscape = escapeHex\n\t\t\t\t} else if n >= 3 && text[1] == '-' && text[2] >= '0' && text[2] <= '9' {\n\t\t\t\t\t// Unit: \"e-2x\"\n\t\t\t\t\tinitialEscape = escapeHex\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fast path: the identifier does not need to be escaped. This fast path is\n\t// important for performance. For example, doing this sped up end-to-end\n\t// parsing and printing of a large CSS file from 84ms to 66ms (around 25%\n\t// faster).\n\tif initialEscape == escapeNone {\n\t\tfor i := 0; i < n; i++ {\n\t\t\tif c := text[i]; c >= 0x80 || !css_lexer.IsNameContinue(rune(c)) {\n\t\t\t\tgoto slowPath\n\t\t\t}\n\t\t}\n\t\tp.css = append(p.css, text...)\n\t\treturn\n\tslowPath:\n\t}\n\n\t// Slow path: the identifier needs to be escaped\n\tfor i, c := range text {\n\t\tescape := escapeNone\n\n\t\tif p.options.ASCIIOnly && c >= 0x80 {\n\t\t\tescape = escapeHex\n\t\t} else if c == '\\r' || c == '\\n' || c == '\\f' || c == '\\uFEFF' {\n\t\t\t// Use a hexadecimal escape for characters that would be invalid escapes\n\t\t\tescape = escapeHex\n\t\t} else {\n\t\t\t// Escape non-identifier characters\n\t\t\tif !css_lexer.IsNameContinue(c) {\n\t\t\t\tescape = escapeBackslash\n\t\t\t}\n\n\t\t\t// Special escape behavior for the first character\n\t\t\tif i == 0 && initialEscape != escapeNone {\n\t\t\t\tescape = initialEscape\n\t\t\t}\n\t\t}\n\n\t\t// If the last character is a hexadecimal escape, print a space afterwards\n\t\t// for the escape sequence to consume. That way we're sure it won't\n\t\t// accidentally consume a semantically significant space afterward.\n\t\tmayNeedWhitespaceAfter := whitespace == mayNeedWhitespaceAfter && escape != escapeNone && i+utf8.RuneLen(c) == n\n\t\tp.printWithEscape(c, escape, text[i:], mayNeedWhitespaceAfter)\n\t}\n}\n\nfunc (p *printer) printSymbol(loc logger.Loc, ref ast.Ref, mode identMode, whitespace trailingWhitespace) {\n\tref = ast.FollowSymbols(p.symbols, ref)\n\toriginalName := p.symbols.Get(ref).OriginalName\n\tname, ok := p.options.LocalNames[ref]\n\tif !ok {\n\t\tname = originalName\n\t}\n\tif p.options.AddSourceMappings {\n\t\tif originalName == name {\n\t\t\toriginalName = \"\"\n\t\t}\n\t\tp.builder.AddSourceMapping(loc, originalName, p.css)\n\t}\n\tp.printIdent(name, mode, whitespace)\n}\n\nfunc (p *printer) printIndent(indent int32) {\n\tn := int(indent)\n\tif p.options.LineLimit > 0 && n*2 >= p.options.LineLimit {\n\t\tn = p.options.LineLimit / 2\n\t}\n\tfor i := 0; i < n; i++ {\n\t\tp.css = append(p.css, \"  \"...)\n\t}\n}\n\ntype printTokensOpts struct {\n\tindent               int32\n\tmultiLineCommaPeriod uint8\n\tisDeclaration        bool\n}\n\nfunc functionMultiLineCommaPeriod(token css_ast.Token) uint8 {\n\tif token.Kind == css_lexer.TFunction {\n\t\tcommaCount := 0\n\t\tfor _, t := range *token.Children {\n\t\t\tif t.Kind == css_lexer.TComma {\n\t\t\t\tcommaCount++\n\t\t\t}\n\t\t}\n\n\t\tswitch strings.ToLower(token.Text) {\n\t\tcase \"linear-gradient\", \"radial-gradient\", \"conic-gradient\",\n\t\t\t\"repeating-linear-gradient\", \"repeating-radial-gradient\", \"repeating-conic-gradient\":\n\t\t\tif commaCount >= 2 {\n\t\t\t\treturn 1\n\t\t\t}\n\n\t\tcase \"matrix\":\n\t\t\tif commaCount == 5 {\n\t\t\t\treturn 2\n\t\t\t}\n\n\t\tcase \"matrix3d\":\n\t\t\tif commaCount == 15 {\n\t\t\t\treturn 4\n\t\t\t}\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (p *printer) printTokens(tokens []css_ast.Token, opts printTokensOpts) bool {\n\thasWhitespaceAfter := len(tokens) > 0 && (tokens[0].Whitespace&css_ast.WhitespaceBefore) != 0\n\n\t// Pretty-print long comma-separated declarations of 3 or more items\n\tcommaPeriod := int(opts.multiLineCommaPeriod)\n\tif !p.options.MinifyWhitespace && opts.isDeclaration {\n\t\tcommaCount := 0\n\t\tfor _, t := range tokens {\n\t\t\tif t.Kind == css_lexer.TComma {\n\t\t\t\tcommaCount++\n\t\t\t\tif commaCount >= 2 {\n\t\t\t\t\tcommaPeriod = 1\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif t.Kind == css_lexer.TFunction && functionMultiLineCommaPeriod(t) > 0 {\n\t\t\t\tcommaPeriod = 1\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tcommaCount := 0\n\tfor i, t := range tokens {\n\t\tif t.Kind == css_lexer.TComma {\n\t\t\tcommaCount++\n\t\t}\n\t\tif t.Kind == css_lexer.TWhitespace {\n\t\t\thasWhitespaceAfter = true\n\t\t\tcontinue\n\t\t}\n\t\tif hasWhitespaceAfter {\n\t\t\tif commaPeriod > 0 && (i == 0 || (tokens[i-1].Kind == css_lexer.TComma && commaCount%commaPeriod == 0)) {\n\t\t\t\tp.print(\"\\n\")\n\t\t\t\tp.printIndent(opts.indent + 1)\n\t\t\t} else if p.options.LineLimit <= 0 || !p.printNewlinePastLineLimit(opts.indent+1) {\n\t\t\t\tp.print(\" \")\n\t\t\t}\n\t\t}\n\t\thasWhitespaceAfter = (t.Whitespace&css_ast.WhitespaceAfter) != 0 ||\n\t\t\t(i+1 < len(tokens) && (tokens[i+1].Whitespace&css_ast.WhitespaceBefore) != 0)\n\n\t\twhitespace := mayNeedWhitespaceAfter\n\t\tif !hasWhitespaceAfter {\n\t\t\twhitespace = canDiscardWhitespaceAfter\n\t\t}\n\n\t\tif p.options.AddSourceMappings {\n\t\t\tp.builder.AddSourceMapping(t.Loc, \"\", p.css)\n\t\t}\n\n\t\tswitch t.Kind {\n\t\tcase css_lexer.TIdent:\n\t\t\tp.printIdent(t.Text, identNormal, whitespace)\n\n\t\tcase css_lexer.TSymbol:\n\t\t\tref := ast.Ref{SourceIndex: p.options.InputSourceIndex, InnerIndex: t.PayloadIndex}\n\t\t\tp.printSymbol(t.Loc, ref, identNormal, whitespace)\n\n\t\tcase css_lexer.TFunction:\n\t\t\tp.printIdent(t.Text, identNormal, whitespace)\n\t\t\tp.print(\"(\")\n\n\t\tcase css_lexer.TDimension:\n\t\t\tvalue := t.DimensionValue()\n\t\t\tp.print(value)\n\t\t\tmode := identDimensionUnit\n\t\t\tif strings.ContainsAny(value, \"eE\") {\n\t\t\t\tmode = identDimensionUnitAfterExponent\n\t\t\t}\n\t\t\tp.printIdent(t.DimensionUnit(), mode, whitespace)\n\n\t\tcase css_lexer.TAtKeyword:\n\t\t\tp.print(\"@\")\n\t\t\tp.printIdent(t.Text, identNormal, whitespace)\n\n\t\tcase css_lexer.THash:\n\t\t\tp.print(\"#\")\n\t\t\tp.printIdent(t.Text, identHash, whitespace)\n\n\t\tcase css_lexer.TString:\n\t\t\tp.printQuoted(t.Text, 0)\n\n\t\tcase css_lexer.TURL:\n\t\t\trecord := p.importRecords[t.PayloadIndex]\n\t\t\ttext := record.Path.Text\n\t\t\ttryToAvoidQuote := true\n\t\t\tvar flags printQuotedFlags\n\t\t\tif record.Flags.Has(ast.ContainsUniqueKey) {\n\t\t\t\tflags |= printQuotedNoWrap\n\n\t\t\t\t// If the caller will be substituting a path here later using string\n\t\t\t\t// substitution, then we can't be sure that it will form a valid URL\n\t\t\t\t// token when unquoted (e.g. it may contain spaces). So we need to\n\t\t\t\t// quote the unique key here just in case. For more info see this\n\t\t\t\t// issue: https://github.com/evanw/esbuild/issues/3410\n\t\t\t\ttryToAvoidQuote = false\n\t\t\t} else if p.options.LineLimit > 0 && p.currentLineLength()+len(text) >= p.options.LineLimit {\n\t\t\t\ttryToAvoidQuote = false\n\t\t\t}\n\t\t\tp.print(\"url(\")\n\t\t\tp.printQuotedWithQuote(text, bestQuoteCharForString(text, tryToAvoidQuote), flags)\n\t\t\tp.print(\")\")\n\t\t\tp.recordImportPathForMetafile(t.PayloadIndex)\n\n\t\tcase css_lexer.TUnterminatedString:\n\t\t\t// We must end this with a newline so that this string stays unterminated\n\t\t\tp.print(t.Text)\n\t\t\tp.print(\"\\n\")\n\t\t\tif !p.options.MinifyWhitespace {\n\t\t\t\tp.printIndent(opts.indent)\n\t\t\t}\n\t\t\thasWhitespaceAfter = false\n\n\t\tdefault:\n\t\t\tp.print(t.Text)\n\t\t}\n\n\t\tif t.Children != nil {\n\t\t\tchildCommaPeriod := uint8(0)\n\n\t\t\tif commaPeriod > 0 && opts.isDeclaration {\n\t\t\t\tchildCommaPeriod = functionMultiLineCommaPeriod(t)\n\t\t\t}\n\n\t\t\tif childCommaPeriod > 0 {\n\t\t\t\topts.indent++\n\t\t\t\tif !p.options.MinifyWhitespace {\n\t\t\t\t\tp.print(\"\\n\")\n\t\t\t\t\tp.printIndent(opts.indent + 1)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tp.printTokens(*t.Children, printTokensOpts{\n\t\t\t\tindent:               opts.indent,\n\t\t\t\tmultiLineCommaPeriod: childCommaPeriod,\n\t\t\t})\n\n\t\t\tif childCommaPeriod > 0 {\n\t\t\t\topts.indent--\n\t\t\t}\n\n\t\t\tswitch t.Kind {\n\t\t\tcase css_lexer.TFunction:\n\t\t\t\tp.print(\")\")\n\n\t\t\tcase css_lexer.TOpenParen:\n\t\t\t\tp.print(\")\")\n\n\t\t\tcase css_lexer.TOpenBrace:\n\t\t\t\tp.print(\"}\")\n\n\t\t\tcase css_lexer.TOpenBracket:\n\t\t\t\tp.print(\"]\")\n\t\t\t}\n\t\t}\n\t}\n\tif hasWhitespaceAfter {\n\t\tp.print(\" \")\n\t}\n\treturn hasWhitespaceAfter\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/error_other.go",
    "content": "//go:build (!js || !wasm) && !windows\n// +build !js !wasm\n// +build !windows\n\npackage fs\n\nfunc is_ERROR_INVALID_NAME(err error) bool {\n\treturn false\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/error_wasm+windows.go",
    "content": "//go:build (js && wasm) || windows\n// +build js,wasm windows\n\npackage fs\n\nimport \"syscall\"\n\n// This check is here in a conditionally-compiled file because Go's standard\n// library for Plan 9 doesn't define a type called \"syscall.Errno\". Plan 9 is\n// not a supported operating system but someone wanted to be able to compile\n// esbuild for Plan 9 anyway.\nfunc is_ERROR_INVALID_NAME(err error) bool {\n\t// This has been copied from golang.org/x/sys/windows\n\tconst ERROR_INVALID_NAME syscall.Errno = 123\n\n\treturn err == ERROR_INVALID_NAME\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/filepath.go",
    "content": "// Code in this file has been forked from the \"filepath\" module in the Go\n// source code to work around bugs with the WebAssembly build target. More\n// information about why here: https://github.com/golang/go/issues/43768.\n\n////////////////////////////////////////////////////////////////////////////////\n\n// Copyright (c) 2009 The Go Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n//    * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n//    * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n//    * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\npackage fs\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"strings\"\n\t\"syscall\"\n)\n\ntype goFilepath struct {\n\tcwd           string\n\tisWindows     bool\n\tpathSeparator byte\n}\n\nfunc isSlash(c uint8) bool {\n\treturn c == '\\\\' || c == '/'\n}\n\n// reservedNames lists reserved Windows names. Search for PRN in\n// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file\n// for details.\nvar reservedNames = []string{\n\t\"CON\", \"PRN\", \"AUX\", \"NUL\",\n\t\"COM1\", \"COM2\", \"COM3\", \"COM4\", \"COM5\", \"COM6\", \"COM7\", \"COM8\", \"COM9\",\n\t\"LPT1\", \"LPT2\", \"LPT3\", \"LPT4\", \"LPT5\", \"LPT6\", \"LPT7\", \"LPT8\", \"LPT9\",\n}\n\n// isReservedName returns true, if path is Windows reserved name.\n// See reservedNames for the full list.\nfunc isReservedName(path string) bool {\n\tif len(path) == 0 {\n\t\treturn false\n\t}\n\tfor _, reserved := range reservedNames {\n\t\tif strings.EqualFold(path, reserved) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// IsAbs reports whether the path is absolute.\nfunc (fp goFilepath) isAbs(path string) bool {\n\tif !fp.isWindows {\n\t\treturn strings.HasPrefix(path, \"/\")\n\t}\n\tif isReservedName(path) {\n\t\treturn true\n\t}\n\tl := fp.volumeNameLen(path)\n\tif l == 0 {\n\t\treturn false\n\t}\n\tpath = path[l:]\n\tif path == \"\" {\n\t\treturn false\n\t}\n\treturn isSlash(path[0])\n}\n\n// Abs returns an absolute representation of path.\n// If the path is not absolute it will be joined with the current\n// working directory to turn it into an absolute path. The absolute\n// path name for a given file is not guaranteed to be unique.\n// Abs calls Clean on the result.\nfunc (fp goFilepath) abs(path string) (string, error) {\n\tif fp.isAbs(path) {\n\t\treturn fp.clean(path), nil\n\t}\n\treturn fp.join([]string{fp.cwd, path}), nil\n}\n\n// IsPathSeparator reports whether c is a directory separator character.\nfunc (fp goFilepath) isPathSeparator(c uint8) bool {\n\treturn c == '/' || (fp.isWindows && c == '\\\\')\n}\n\n// volumeNameLen returns length of the leading volume name on Windows.\n// It returns 0 elsewhere.\nfunc (fp goFilepath) volumeNameLen(path string) int {\n\tif !fp.isWindows {\n\t\treturn 0\n\t}\n\tif len(path) < 2 {\n\t\treturn 0\n\t}\n\t// with drive letter\n\tc := path[0]\n\tif path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {\n\t\treturn 2\n\t}\n\t// is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx\n\tif l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&\n\t\t!isSlash(path[2]) && path[2] != '.' {\n\t\t// first, leading `\\\\` and next shouldn't be `\\`. its server name.\n\t\tfor n := 3; n < l-1; n++ {\n\t\t\t// second, next '\\' shouldn't be repeated.\n\t\t\tif isSlash(path[n]) {\n\t\t\t\tn++\n\t\t\t\t// third, following something characters. its share name.\n\t\t\t\tif !isSlash(path[n]) {\n\t\t\t\t\tif path[n] == '.' {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tfor ; n < l; n++ {\n\t\t\t\t\t\tif isSlash(path[n]) {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn n\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn 0\n}\n\n// EvalSymlinks returns the path name after the evaluation of any symbolic\n// links.\n// If path is relative the result will be relative to the current directory,\n// unless one of the components is an absolute symbolic link.\n// EvalSymlinks calls Clean on the result.\nfunc (fp goFilepath) evalSymlinks(path string) (string, error) {\n\tvolLen := fp.volumeNameLen(path)\n\tpathSeparator := string(fp.pathSeparator)\n\n\tif volLen < len(path) && fp.isPathSeparator(path[volLen]) {\n\t\tvolLen++\n\t}\n\tvol := path[:volLen]\n\tdest := vol\n\tlinksWalked := 0\n\tfor start, end := volLen, volLen; start < len(path); start = end {\n\t\tfor start < len(path) && fp.isPathSeparator(path[start]) {\n\t\t\tstart++\n\t\t}\n\t\tend = start\n\t\tfor end < len(path) && !fp.isPathSeparator(path[end]) {\n\t\t\tend++\n\t\t}\n\n\t\t// On Windows, \".\" can be a symlink.\n\t\t// We look it up, and use the value if it is absolute.\n\t\t// If not, we just return \".\".\n\t\tisWindowsDot := fp.isWindows && path[fp.volumeNameLen(path):] == \".\"\n\n\t\t// The next path component is in path[start:end].\n\t\tif end == start {\n\t\t\t// No more path components.\n\t\t\tbreak\n\t\t} else if path[start:end] == \".\" && !isWindowsDot {\n\t\t\t// Ignore path component \".\".\n\t\t\tcontinue\n\t\t} else if path[start:end] == \"..\" {\n\t\t\t// Back up to previous component if possible.\n\t\t\t// Note that volLen includes any leading slash.\n\n\t\t\t// Set r to the index of the last slash in dest,\n\t\t\t// after the volume.\n\t\t\tvar r int\n\t\t\tfor r = len(dest) - 1; r >= volLen; r-- {\n\t\t\t\tif fp.isPathSeparator(dest[r]) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif r < volLen || dest[r+1:] == \"..\" {\n\t\t\t\t// Either path has no slashes\n\t\t\t\t// (it's empty or just \"C:\")\n\t\t\t\t// or it ends in a \"..\" we had to keep.\n\t\t\t\t// Either way, keep this \"..\".\n\t\t\t\tif len(dest) > volLen {\n\t\t\t\t\tdest += pathSeparator\n\t\t\t\t}\n\t\t\t\tdest += \"..\"\n\t\t\t} else {\n\t\t\t\t// Discard everything since the last slash.\n\t\t\t\tdest = dest[:r]\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Ordinary path component. Add it to result.\n\n\t\tif len(dest) > fp.volumeNameLen(dest) && !fp.isPathSeparator(dest[len(dest)-1]) {\n\t\t\tdest += pathSeparator\n\t\t}\n\n\t\tdest += path[start:end]\n\n\t\t// Resolve symlink.\n\n\t\tfi, err := os.Lstat(dest)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tif fi.Mode()&os.ModeSymlink == 0 {\n\t\t\tif !fi.Mode().IsDir() && end < len(path) {\n\t\t\t\treturn \"\", syscall.ENOTDIR\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// Found symlink.\n\n\t\tlinksWalked++\n\t\tif linksWalked > 255 {\n\t\t\treturn \"\", errors.New(\"EvalSymlinks: too many links\")\n\t\t}\n\n\t\tlink, err := os.Readlink(dest)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\tif isWindowsDot && !fp.isAbs(link) {\n\t\t\t// On Windows, if \".\" is a relative symlink,\n\t\t\t// just return \".\".\n\t\t\tbreak\n\t\t}\n\n\t\tpath = link + path[end:]\n\n\t\tv := fp.volumeNameLen(link)\n\t\tif v > 0 {\n\t\t\t// Symlink to drive name is an absolute path.\n\t\t\tif v < len(link) && fp.isPathSeparator(link[v]) {\n\t\t\t\tv++\n\t\t\t}\n\t\t\tvol = link[:v]\n\t\t\tdest = vol\n\t\t\tend = len(vol)\n\t\t} else if len(link) > 0 && fp.isPathSeparator(link[0]) {\n\t\t\t// Symlink to absolute path.\n\t\t\tdest = link[:1]\n\t\t\tend = 1\n\t\t} else {\n\t\t\t// Symlink to relative path; replace last\n\t\t\t// path component in dest.\n\t\t\tvar r int\n\t\t\tfor r = len(dest) - 1; r >= volLen; r-- {\n\t\t\t\tif fp.isPathSeparator(dest[r]) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tif r < volLen {\n\t\t\t\tdest = vol\n\t\t\t} else {\n\t\t\t\tdest = dest[:r]\n\t\t\t}\n\t\t\tend = 0\n\t\t}\n\t}\n\treturn fp.clean(dest), nil\n}\n\n// A lazybuf is a lazily constructed path buffer.\n// It supports append, reading previously appended bytes,\n// and retrieving the final string. It does not allocate a buffer\n// to hold the output until that output diverges from s.\ntype lazybuf struct {\n\tpath       string\n\tvolAndPath string\n\tbuf        []byte\n\tw          int\n\tvolLen     int\n}\n\nfunc (b *lazybuf) index(i int) byte {\n\tif b.buf != nil {\n\t\treturn b.buf[i]\n\t}\n\treturn b.path[i]\n}\n\nfunc (b *lazybuf) append(c byte) {\n\tif b.buf == nil {\n\t\tif b.w < len(b.path) && b.path[b.w] == c {\n\t\t\tb.w++\n\t\t\treturn\n\t\t}\n\t\tb.buf = make([]byte, len(b.path))\n\t\tcopy(b.buf, b.path[:b.w])\n\t}\n\tb.buf[b.w] = c\n\tb.w++\n}\n\nfunc (b *lazybuf) string() string {\n\tif b.buf == nil {\n\t\treturn b.volAndPath[:b.volLen+b.w]\n\t}\n\treturn b.volAndPath[:b.volLen] + string(b.buf[:b.w])\n}\n\n// FromSlash returns the result of replacing each slash ('/') character\n// in path with a separator character. Multiple slashes are replaced\n// by multiple separators.\nfunc (fp goFilepath) fromSlash(path string) string {\n\tif !fp.isWindows {\n\t\treturn path\n\t}\n\treturn strings.ReplaceAll(path, \"/\", \"\\\\\")\n}\n\n// Clean returns the shortest path name equivalent to path\n// by purely lexical processing. It applies the following rules\n// iteratively until no further processing can be done:\n//\n//  1. Replace multiple Separator elements with a single one.\n//  2. Eliminate each . path name element (the current directory).\n//  3. Eliminate each inner .. path name element (the parent directory)\n//     along with the non-.. element that precedes it.\n//  4. Eliminate .. elements that begin a rooted path:\n//     that is, replace \"/..\" by \"/\" at the beginning of a path,\n//     assuming Separator is '/'.\n//\n// The returned path ends in a slash only if it represents a root directory,\n// such as \"/\" on Unix or `C:\\` on Windows.\n//\n// Finally, any occurrences of slash are replaced by Separator.\n//\n// If the result of this process is an empty string, Clean\n// returns the string \".\".\n//\n// See also Rob Pike, \"Lexical File Names in Plan 9 or\n// Getting Dot-Dot Right,\"\n// https://9p.io/sys/doc/lexnames.html\nfunc (fp goFilepath) clean(path string) string {\n\toriginalPath := path\n\tvolLen := fp.volumeNameLen(path)\n\tpath = path[volLen:]\n\tif path == \"\" {\n\t\tif volLen > 1 && originalPath[1] != ':' {\n\t\t\t// should be UNC\n\t\t\treturn fp.fromSlash(originalPath)\n\t\t}\n\t\treturn originalPath + \".\"\n\t}\n\trooted := fp.isPathSeparator(path[0])\n\n\t// Invariants:\n\t//\treading from path; r is index of next byte to process.\n\t//\twriting to buf; w is index of next byte to write.\n\t//\tdotdot is index in buf where .. must stop, either because\n\t//\t\tit is the leading slash or it is a leading ../../.. prefix.\n\tn := len(path)\n\tout := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}\n\tr, dotdot := 0, 0\n\tif rooted {\n\t\tout.append(fp.pathSeparator)\n\t\tr, dotdot = 1, 1\n\t}\n\n\tfor r < n {\n\t\tswitch {\n\t\tcase fp.isPathSeparator(path[r]):\n\t\t\t// empty path element\n\t\t\tr++\n\t\tcase path[r] == '.' && (r+1 == n || fp.isPathSeparator(path[r+1])):\n\t\t\t// . element\n\t\t\tr++\n\t\tcase path[r] == '.' && path[r+1] == '.' && (r+2 == n || fp.isPathSeparator(path[r+2])):\n\t\t\t// .. element: remove to last separator\n\t\t\tr += 2\n\t\t\tswitch {\n\t\t\tcase out.w > dotdot:\n\t\t\t\t// can backtrack\n\t\t\t\tout.w--\n\t\t\t\tfor out.w > dotdot && !fp.isPathSeparator(out.index(out.w)) {\n\t\t\t\t\tout.w--\n\t\t\t\t}\n\t\t\tcase !rooted:\n\t\t\t\t// cannot backtrack, but not rooted, so append .. element.\n\t\t\t\tif out.w > 0 {\n\t\t\t\t\tout.append(fp.pathSeparator)\n\t\t\t\t}\n\t\t\t\tout.append('.')\n\t\t\t\tout.append('.')\n\t\t\t\tdotdot = out.w\n\t\t\t}\n\t\tdefault:\n\t\t\t// real path element.\n\t\t\t// add slash if needed\n\t\t\tif rooted && out.w != 1 || !rooted && out.w != 0 {\n\t\t\t\tout.append(fp.pathSeparator)\n\t\t\t}\n\t\t\t// copy element\n\t\t\tfor ; r < n && !fp.isPathSeparator(path[r]); r++ {\n\t\t\t\tout.append(path[r])\n\t\t\t}\n\t\t}\n\t}\n\n\t// Turn empty string into \".\"\n\tif out.w == 0 {\n\t\tout.append('.')\n\t}\n\n\treturn fp.fromSlash(out.string())\n}\n\n// VolumeName returns leading volume name.\n// Given \"C:\\foo\\bar\" it returns \"C:\" on Windows.\n// Given \"\\\\host\\share\\foo\" it returns \"\\\\host\\share\".\n// On other platforms it returns \"\".\nfunc (fp goFilepath) volumeName(path string) string {\n\treturn path[:fp.volumeNameLen(path)]\n}\n\n// Base returns the last element of path.\n// Trailing path separators are removed before extracting the last element.\n// If the path is empty, Base returns \".\".\n// If the path consists entirely of separators, Base returns a single separator.\nfunc (fp goFilepath) base(path string) string {\n\tif path == \"\" {\n\t\treturn \".\"\n\t}\n\t// Strip trailing slashes.\n\tfor len(path) > 0 && fp.isPathSeparator(path[len(path)-1]) {\n\t\tpath = path[0 : len(path)-1]\n\t}\n\t// Throw away volume name\n\tpath = path[len(fp.volumeName(path)):]\n\t// Find the last element\n\ti := len(path) - 1\n\tfor i >= 0 && !fp.isPathSeparator(path[i]) {\n\t\ti--\n\t}\n\tif i >= 0 {\n\t\tpath = path[i+1:]\n\t}\n\t// If empty now, it had only slashes.\n\tif path == \"\" {\n\t\treturn string(fp.pathSeparator)\n\t}\n\treturn path\n}\n\n// Dir returns all but the last element of path, typically the path's directory.\n// After dropping the final element, Dir calls Clean on the path and trailing\n// slashes are removed.\n// If the path is empty, Dir returns \".\".\n// If the path consists entirely of separators, Dir returns a single separator.\n// The returned path does not end in a separator unless it is the root directory.\nfunc (fp goFilepath) dir(path string) string {\n\tvol := fp.volumeName(path)\n\ti := len(path) - 1\n\tfor i >= len(vol) && !fp.isPathSeparator(path[i]) {\n\t\ti--\n\t}\n\tdir := fp.clean(path[len(vol) : i+1])\n\tif dir == \".\" && len(vol) > 2 {\n\t\t// must be UNC\n\t\treturn vol\n\t}\n\treturn vol + dir\n}\n\n// Ext returns the file name extension used by path.\n// The extension is the suffix beginning at the final dot\n// in the final element of path; it is empty if there is\n// no dot.\nfunc (fp goFilepath) ext(path string) string {\n\tfor i := len(path) - 1; i >= 0 && !fp.isPathSeparator(path[i]); i-- {\n\t\tif path[i] == '.' {\n\t\t\treturn path[i:]\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// Join joins any number of path elements into a single path,\n// separating them with an OS specific Separator. Empty elements\n// are ignored. The result is Cleaned. However, if the argument\n// list is empty or all its elements are empty, Join returns\n// an empty string.\n// On Windows, the result will only be a UNC path if the first\n// non-empty element is a UNC path.\nfunc (fp goFilepath) join(elem []string) string {\n\tfor i, e := range elem {\n\t\tif e != \"\" {\n\t\t\tif fp.isWindows {\n\t\t\t\treturn fp.joinNonEmpty(elem[i:])\n\t\t\t}\n\t\t\treturn fp.clean(strings.Join(elem[i:], string(fp.pathSeparator)))\n\t\t}\n\t}\n\treturn \"\"\n}\n\n// joinNonEmpty is like join, but it assumes that the first element is non-empty.\nfunc (fp goFilepath) joinNonEmpty(elem []string) string {\n\tif len(elem[0]) == 2 && elem[0][1] == ':' {\n\t\t// First element is drive letter without terminating slash.\n\t\t// Keep path relative to current directory on that drive.\n\t\t// Skip empty elements.\n\t\ti := 1\n\t\tfor ; i < len(elem); i++ {\n\t\t\tif elem[i] != \"\" {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\treturn fp.clean(elem[0] + strings.Join(elem[i:], string(fp.pathSeparator)))\n\t}\n\t// The following logic prevents Join from inadvertently creating a\n\t// UNC path on Windows. Unless the first element is a UNC path, Join\n\t// shouldn't create a UNC path. See golang.org/issue/9167.\n\tp := fp.clean(strings.Join(elem, string(fp.pathSeparator)))\n\tif !fp.isUNC(p) {\n\t\treturn p\n\t}\n\t// p == UNC only allowed when the first element is a UNC path.\n\thead := fp.clean(elem[0])\n\tif fp.isUNC(head) {\n\t\treturn p\n\t}\n\t// head + tail == UNC, but joining two non-UNC paths should not result\n\t// in a UNC path. Undo creation of UNC path.\n\ttail := fp.clean(strings.Join(elem[1:], string(fp.pathSeparator)))\n\tif head[len(head)-1] == fp.pathSeparator {\n\t\treturn head + tail\n\t}\n\treturn head + string(fp.pathSeparator) + tail\n}\n\n// isUNC reports whether path is a UNC path.\nfunc (fp goFilepath) isUNC(path string) bool {\n\treturn fp.volumeNameLen(path) > 2\n}\n\n// Rel returns a relative path that is lexically equivalent to targpath when\n// joined to basepath with an intervening separator. That is,\n// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.\n// On success, the returned path will always be relative to basepath,\n// even if basepath and targpath share no elements.\n// An error is returned if targpath can't be made relative to basepath or if\n// knowing the current working directory would be necessary to compute it.\n// Rel calls Clean on the result.\nfunc (fp goFilepath) rel(basepath, targpath string) (string, error) {\n\tbaseVol := fp.volumeName(basepath)\n\ttargVol := fp.volumeName(targpath)\n\tbase := fp.clean(basepath)\n\ttarg := fp.clean(targpath)\n\tif fp.sameWord(targ, base) {\n\t\treturn \".\", nil\n\t}\n\tbase = base[len(baseVol):]\n\ttarg = targ[len(targVol):]\n\tif base == \".\" {\n\t\tbase = \"\"\n\t}\n\t// Can't use IsAbs - `\\a` and `a` are both relative in Windows.\n\tbaseSlashed := len(base) > 0 && base[0] == fp.pathSeparator\n\ttargSlashed := len(targ) > 0 && targ[0] == fp.pathSeparator\n\tif baseSlashed != targSlashed || !fp.sameWord(baseVol, targVol) {\n\t\treturn \"\", errors.New(\"Rel: can't make \" + targpath + \" relative to \" + basepath)\n\t}\n\t// Position base[b0:bi] and targ[t0:ti] at the first differing elements.\n\tbl := len(base)\n\ttl := len(targ)\n\tvar b0, bi, t0, ti int\n\tfor {\n\t\tfor bi < bl && base[bi] != fp.pathSeparator {\n\t\t\tbi++\n\t\t}\n\t\tfor ti < tl && targ[ti] != fp.pathSeparator {\n\t\t\tti++\n\t\t}\n\t\tif !fp.sameWord(targ[t0:ti], base[b0:bi]) {\n\t\t\tbreak\n\t\t}\n\t\tif bi < bl {\n\t\t\tbi++\n\t\t}\n\t\tif ti < tl {\n\t\t\tti++\n\t\t}\n\t\tb0 = bi\n\t\tt0 = ti\n\t}\n\tif base[b0:bi] == \"..\" {\n\t\treturn \"\", errors.New(\"Rel: can't make \" + targpath + \" relative to \" + basepath)\n\t}\n\tif b0 != bl {\n\t\t// Base elements left. Must go up before going down.\n\t\tseps := strings.Count(base[b0:bl], string(fp.pathSeparator))\n\t\tsize := 2 + seps*3\n\t\tif tl != t0 {\n\t\t\tsize += 1 + tl - t0\n\t\t}\n\t\tbuf := make([]byte, size)\n\t\tn := copy(buf, \"..\")\n\t\tfor i := 0; i < seps; i++ {\n\t\t\tbuf[n] = fp.pathSeparator\n\t\t\tcopy(buf[n+1:], \"..\")\n\t\t\tn += 3\n\t\t}\n\t\tif t0 != tl {\n\t\t\tbuf[n] = fp.pathSeparator\n\t\t\tcopy(buf[n+1:], targ[t0:])\n\t\t}\n\t\treturn string(buf), nil\n\t}\n\treturn targ[t0:], nil\n}\n\nfunc (fp goFilepath) sameWord(a, b string) bool {\n\tif !fp.isWindows {\n\t\treturn a == b\n\t}\n\treturn strings.EqualFold(a, b)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/fs.go",
    "content": "package fs\n\n// Most of esbuild's internals use this file system abstraction instead of\n// using native file system APIs. This lets us easily mock the file system\n// for tests and also implement Yarn's virtual \".zip\" file system overlay.\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n)\n\ntype EntryKind uint8\n\nconst (\n\tDirEntry  EntryKind = 1\n\tFileEntry EntryKind = 2\n)\n\ntype Entry struct {\n\tsymlink  string\n\tdir      string\n\tbase     string\n\tmutex    sync.Mutex\n\tkind     EntryKind\n\tneedStat bool\n}\n\nfunc (e *Entry) Kind(fs FS) EntryKind {\n\te.mutex.Lock()\n\tdefer e.mutex.Unlock()\n\tif e.needStat {\n\t\te.needStat = false\n\t\te.symlink, e.kind = fs.kind(e.dir, e.base)\n\t}\n\treturn e.kind\n}\n\nfunc (e *Entry) Symlink(fs FS) string {\n\te.mutex.Lock()\n\tdefer e.mutex.Unlock()\n\tif e.needStat {\n\t\te.needStat = false\n\t\te.symlink, e.kind = fs.kind(e.dir, e.base)\n\t}\n\treturn e.symlink\n}\n\ntype accessedEntries struct {\n\twasPresent map[string]bool\n\n\t// If this is nil, \"SortedKeys()\" was not accessed. This means we should\n\t// check for whether this directory has changed or not by seeing if any of\n\t// the entries in the \"wasPresent\" map have changed in \"present or not\"\n\t// status, since the only access was to individual entries via \"Get()\".\n\t//\n\t// If this is non-nil, \"SortedKeys()\" was accessed. This means we should\n\t// check for whether this directory has changed or not by checking the\n\t// \"allEntries\" array for equality with the existing entries list, since the\n\t// code asked for all entries and may have used the presence or absence of\n\t// entries in that list.\n\t//\n\t// The goal of having these two checks is to be as narrow as possible to\n\t// avoid unnecessary rebuilds. If only \"Get()\" is called on a few entries,\n\t// then we won't invalidate the build if random unrelated entries are added\n\t// or removed. But if \"SortedKeys()\" is called, we need to invalidate the\n\t// build if anything about the set of entries in this directory is changed.\n\tallEntries []string\n\n\tmutex sync.Mutex\n}\n\ntype DirEntries struct {\n\tdata            map[string]*Entry\n\taccessedEntries *accessedEntries\n\tdir             string\n}\n\nfunc MakeEmptyDirEntries(dir string) DirEntries {\n\treturn DirEntries{dir: dir, data: make(map[string]*Entry)}\n}\n\ntype DifferentCase struct {\n\tDir    string\n\tQuery  string\n\tActual string\n}\n\nfunc (entries DirEntries) Get(query string) (*Entry, *DifferentCase) {\n\tif entries.data != nil {\n\t\tkey := strings.ToLower(query)\n\t\tentry := entries.data[key]\n\n\t\t// Track whether this specific entry was present or absent for watch mode\n\t\tif accessed := entries.accessedEntries; accessed != nil {\n\t\t\taccessed.mutex.Lock()\n\t\t\taccessed.wasPresent[key] = entry != nil\n\t\t\taccessed.mutex.Unlock()\n\t\t}\n\n\t\tif entry != nil {\n\t\t\tif entry.base != query {\n\t\t\t\treturn entry, &DifferentCase{\n\t\t\t\t\tDir:    entries.dir,\n\t\t\t\t\tQuery:  query,\n\t\t\t\t\tActual: entry.base,\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn entry, nil\n\t\t}\n\t}\n\n\treturn nil, nil\n}\n\n// This function lets you \"peek\" at the number of entries without watch mode\n// considering the number of entries as having been observed. This is used when\n// generating debug log messages to log the number of entries without causing\n// watch mode to rebuild when the number of entries has been changed.\nfunc (entries DirEntries) PeekEntryCount() int {\n\tif entries.data != nil {\n\t\treturn len(entries.data)\n\t}\n\treturn 0\n}\n\nfunc (entries DirEntries) SortedKeys() (keys []string) {\n\tif entries.data != nil {\n\t\tkeys = make([]string, 0, len(entries.data))\n\t\tfor _, entry := range entries.data {\n\t\t\tkeys = append(keys, entry.base)\n\t\t}\n\t\tsort.Strings(keys)\n\n\t\t// Track the exact set of all entries for watch mode\n\t\tif entries.accessedEntries != nil {\n\t\t\tentries.accessedEntries.mutex.Lock()\n\t\t\tentries.accessedEntries.allEntries = keys\n\t\t\tentries.accessedEntries.mutex.Unlock()\n\t\t}\n\n\t\treturn keys\n\t}\n\n\treturn\n}\n\ntype OpenedFile interface {\n\tLen() int\n\tRead(start int, end int) ([]byte, error)\n\tClose() error\n}\n\ntype InMemoryOpenedFile struct {\n\tContents []byte\n}\n\nfunc (f *InMemoryOpenedFile) Len() int {\n\treturn len(f.Contents)\n}\n\nfunc (f *InMemoryOpenedFile) Read(start int, end int) ([]byte, error) {\n\treturn []byte(f.Contents[start:end]), nil\n}\n\nfunc (f *InMemoryOpenedFile) Close() error {\n\treturn nil\n}\n\ntype FS interface {\n\t// The returned map is immutable and is cached across invocations. Do not\n\t// mutate it.\n\tReadDirectory(path string) (entries DirEntries, canonicalError error, originalError error)\n\tReadFile(path string) (contents string, canonicalError error, originalError error)\n\tOpenFile(path string) (result OpenedFile, canonicalError error, originalError error)\n\n\t// This is a key made from the information returned by \"stat\". It is intended\n\t// to be different if the file has been edited, and to otherwise be equal if\n\t// the file has not been edited. It should usually work, but no guarantees.\n\t//\n\t// See https://apenwarr.ca/log/20181113 for more information about why this\n\t// can be broken. For example, writing to a file with mmap on WSL on Windows\n\t// won't change this key. Hopefully this isn't too much of an issue.\n\t//\n\t// Additional reading:\n\t// - https://github.com/npm/npm/pull/20027\n\t// - https://github.com/golang/go/commit/7dea509703eb5ad66a35628b12a678110fbb1f72\n\tModKey(path string) (ModKey, error)\n\n\t// This is part of the interface because the mock interface used for tests\n\t// should not depend on file system behavior (i.e. different slashes for\n\t// Windows) while the real interface should.\n\tIsAbs(path string) bool\n\tAbs(path string) (string, bool)\n\tDir(path string) string\n\tBase(path string) string\n\tExt(path string) string\n\tJoin(parts ...string) string\n\tCwd() string\n\tRel(base string, target string) (string, bool)\n\tEvalSymlinks(path string) (string, bool)\n\n\t// This is used in the implementation of \"Entry\"\n\tkind(dir string, base string) (symlink string, kind EntryKind)\n\n\t// This is a set of all files used and all directories checked. The build\n\t// must be invalidated if any of these watched files change.\n\tWatchData() WatchData\n}\n\ntype WatchData struct {\n\t// These functions return a non-empty path as a string if the file system\n\t// entry has been modified. For files, the returned path is the same as the\n\t// file path. For directories, the returned path is either the directory\n\t// itself or a file in the directory that was changed.\n\tPaths map[string]func() string\n}\n\ntype ModKey struct {\n\t// What gets filled in here is OS-dependent\n\tinode      uint64\n\tsize       int64\n\tmtime_sec  int64\n\tmtime_nsec int64\n\tmode       uint32\n\tuid        uint32\n}\n\n// Some file systems have a time resolution of only a few seconds. If a mtime\n// value is too new, we won't be able to tell if it has been recently modified\n// or not. So we only use mtimes for comparison if they are sufficiently old.\n// Apparently the FAT file system has a resolution of two seconds according to\n// this article: https://en.wikipedia.org/wiki/Stat_(system_call).\nconst modKeySafetyGap = 3 // In seconds\nvar modKeyUnusable = errors.New(\"The modification key is unusable\")\n\n// Limit the number of files open simultaneously to avoid ulimit issues\nvar fileOpenLimit = make(chan bool, 32)\n\nfunc BeforeFileOpen() {\n\t// This will block if the number of open files is already at the limit\n\tfileOpenLimit <- false\n}\n\nfunc AfterFileClose() {\n\t<-fileOpenLimit\n}\n\n// This is a fork of \"os.MkdirAll\" to work around bugs with the WebAssembly\n// build target. More information here: https://github.com/golang/go/issues/43768.\nfunc MkdirAll(fs FS, path string, perm os.FileMode) error {\n\t// Run \"Join\" once to run \"Clean\" on the path, which removes trailing slashes\n\treturn mkdirAll(fs, fs.Join(path), perm)\n}\n\nfunc mkdirAll(fs FS, path string, perm os.FileMode) error {\n\t// Fast path: if we can tell whether path is a directory or file, stop with success or error.\n\tif dir, err := os.Stat(path); err == nil {\n\t\tif dir.IsDir() {\n\t\t\treturn nil\n\t\t}\n\t\treturn &os.PathError{Op: \"mkdir\", Path: path, Err: syscall.ENOTDIR}\n\t}\n\n\t// Slow path: make sure parent exists and then call Mkdir for path.\n\tif parent := fs.Dir(path); parent != path {\n\t\t// Create parent.\n\t\tif err := mkdirAll(fs, parent, perm); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// Parent now exists; invoke Mkdir and use its result.\n\tif err := os.Mkdir(path, perm); err != nil {\n\t\t// Handle arguments like \"foo/.\" by\n\t\t// double-checking that directory doesn't exist.\n\t\tdir, err1 := os.Lstat(path)\n\t\tif err1 == nil && dir.IsDir() {\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/fs_mock.go",
    "content": "package fs\n\n// This is a mock implementation of the \"fs\" module for use with tests. It does\n// not actually read from the file system. Instead, it reads from a pre-specified\n// map of file paths to files.\n\nimport (\n\t\"errors\"\n\t\"path\"\n\t\"strings\"\n\t\"syscall\"\n)\n\ntype MockKind uint8\n\nconst (\n\tMockUnix MockKind = iota\n\tMockWindows\n)\n\ntype mockFS struct {\n\tdirs          map[string]DirEntries\n\tfiles         map[string]string\n\tabsWorkingDir string\n\tdefaultVolume string\n\tKind          MockKind\n}\n\nfunc MockFS(input map[string]string, kind MockKind, absWorkingDir string) FS {\n\tdirs := make(map[string]DirEntries)\n\tfiles := make(map[string]string)\n\n\tvar defaultVolume string\n\tif kind == MockWindows {\n\t\t_, defaultVolume = win2unix(absWorkingDir)\n\t}\n\n\tfor k, v := range input {\n\t\tvar volume string\n\t\tfiles[k] = v\n\t\tif kind == MockWindows {\n\t\t\tk, volume = win2unix(k)\n\t\t}\n\t\toriginal := k\n\n\t\t// Build the directory map\n\t\tfor {\n\t\t\tkDir := path.Dir(k)\n\t\t\tkey := kDir\n\t\t\tif kind == MockWindows {\n\t\t\t\tkey = unix2win(key, volume, defaultVolume)\n\t\t\t}\n\t\t\tdir, ok := dirs[key]\n\t\t\tif !ok {\n\t\t\t\tdir = DirEntries{dir: key, data: make(map[string]*Entry)}\n\t\t\t\tdirs[key] = dir\n\t\t\t}\n\t\t\tif kDir == k {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tbase := path.Base(k)\n\t\t\tif k == original {\n\t\t\t\tdir.data[strings.ToLower(base)] = &Entry{kind: FileEntry, base: base}\n\t\t\t} else {\n\t\t\t\tdir.data[strings.ToLower(base)] = &Entry{kind: DirEntry, base: base}\n\t\t\t}\n\t\t\tk = kDir\n\t\t}\n\t}\n\n\treturn &mockFS{dirs, files, absWorkingDir, defaultVolume, kind}\n}\n\nfunc (fs *mockFS) ReadDirectory(path string) (DirEntries, error, error) {\n\tif fs.Kind == MockWindows {\n\t\tpath = strings.ReplaceAll(path, \"/\", \"\\\\\")\n\t}\n\n\tvar slash byte = '/'\n\tif fs.Kind == MockWindows {\n\t\tslash = '\\\\'\n\t}\n\n\t// Trim trailing slashes before lookup\n\tfirstSlash := strings.IndexByte(path, slash)\n\tfor {\n\t\ti := strings.LastIndexByte(path, slash)\n\t\tif i != len(path)-1 || i <= firstSlash {\n\t\t\tbreak\n\t\t}\n\t\tpath = path[:i]\n\t}\n\n\tif dir, ok := fs.dirs[path]; ok {\n\t\treturn dir, nil, nil\n\t}\n\treturn DirEntries{}, syscall.ENOENT, syscall.ENOENT\n}\n\nfunc (fs *mockFS) ReadFile(path string) (string, error, error) {\n\tif fs.Kind == MockWindows {\n\t\tpath = strings.ReplaceAll(path, \"/\", \"\\\\\")\n\t}\n\tif contents, ok := fs.files[path]; ok {\n\t\treturn contents, nil, nil\n\t}\n\treturn \"\", syscall.ENOENT, syscall.ENOENT\n}\n\nfunc (fs *mockFS) OpenFile(path string) (OpenedFile, error, error) {\n\tif fs.Kind == MockWindows {\n\t\tpath = strings.ReplaceAll(path, \"/\", \"\\\\\")\n\t}\n\tif contents, ok := fs.files[path]; ok {\n\t\treturn &InMemoryOpenedFile{Contents: []byte(contents)}, nil, nil\n\t}\n\treturn nil, syscall.ENOENT, syscall.ENOENT\n}\n\nfunc (fs *mockFS) ModKey(path string) (ModKey, error) {\n\treturn ModKey{}, errors.New(\"This is not available during tests\")\n}\n\nfunc win2unix(p string) (result string, volume string) {\n\tif len(p) > 0 && strings.HasPrefix(p[1:], \":\\\\\") {\n\t\tif c := p[0]; (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') {\n\t\t\tvolume = p[0:1]\n\t\t\tp = p[2:]\n\t\t}\n\t}\n\tp = strings.ReplaceAll(p, \"\\\\\", \"/\")\n\treturn p, volume\n}\n\nfunc unix2win(p string, volume string, defaultVolume string) string {\n\tp = strings.ReplaceAll(p, \"/\", \"\\\\\")\n\tif strings.HasPrefix(p, \"\\\\\") {\n\t\tif volume == \"\" {\n\t\t\tvolume = defaultVolume\n\t\t}\n\t\tp = volume + \":\" + p\n\t}\n\treturn p\n}\n\nfunc (fs *mockFS) IsAbs(p string) bool {\n\tif fs.Kind == MockWindows {\n\t\tp, _ = win2unix(p)\n\t}\n\treturn path.IsAbs(p)\n}\n\nfunc (fs *mockFS) Abs(p string) (string, bool) {\n\tvar volume string\n\tif fs.Kind == MockWindows {\n\t\tp, volume = win2unix(p)\n\t}\n\n\tp = path.Clean(path.Join(\"/\", p))\n\n\tif fs.Kind == MockWindows {\n\t\tp = unix2win(p, volume, fs.defaultVolume)\n\t}\n\n\treturn p, true\n}\n\nfunc (fs *mockFS) Dir(p string) string {\n\tvar volume string\n\tif fs.Kind == MockWindows {\n\t\tp, volume = win2unix(p)\n\t}\n\n\tp = path.Dir(p)\n\n\tif fs.Kind == MockWindows {\n\t\tp = unix2win(p, volume, fs.defaultVolume)\n\t}\n\n\treturn p\n}\n\nfunc (fs *mockFS) Base(p string) string {\n\tvar volume string\n\tif fs.Kind == MockWindows {\n\t\tp, volume = win2unix(p)\n\t}\n\n\tp = path.Base(p)\n\n\tif fs.Kind == MockWindows && p == \"/\" {\n\t\tp = volume + \":\\\\\"\n\t}\n\n\treturn p\n}\n\nfunc (fs *mockFS) Ext(p string) string {\n\tif fs.Kind == MockWindows {\n\t\tp, _ = win2unix(p)\n\t}\n\n\treturn path.Ext(p)\n}\n\nfunc (fs *mockFS) Join(parts ...string) string {\n\tvar volume string\n\tif fs.Kind == MockWindows {\n\t\tconverted := make([]string, len(parts))\n\t\tfor i, part := range parts {\n\t\t\tvar v string\n\t\t\tconverted[i], v = win2unix(part)\n\t\t\tif i == 0 {\n\t\t\t\tvolume = v\n\t\t\t}\n\t\t}\n\t\tparts = converted\n\t}\n\n\tp := path.Clean(path.Join(parts...))\n\n\tif fs.Kind == MockWindows {\n\t\tp = unix2win(p, volume, fs.defaultVolume)\n\t}\n\n\treturn p\n}\n\nfunc (fs *mockFS) Cwd() string {\n\treturn fs.absWorkingDir\n}\n\nfunc splitOnSlash(path string) (string, string) {\n\tif slash := strings.IndexByte(path, '/'); slash != -1 {\n\t\treturn path[:slash], path[slash+1:]\n\t}\n\treturn path, \"\"\n}\n\nfunc (fs *mockFS) Rel(base string, target string) (string, bool) {\n\tvar volume string\n\tif fs.Kind == MockWindows {\n\t\tvar v string\n\t\tbase, volume = win2unix(base)\n\t\ttarget, v = win2unix(target)\n\t\tif volume == \"\" {\n\t\t\tvolume = fs.defaultVolume\n\t\t}\n\t\tif v == \"\" {\n\t\t\tv = fs.defaultVolume\n\t\t}\n\t\tif strings.ToUpper(v) != strings.ToUpper(volume) {\n\t\t\treturn \"\", false\n\t\t}\n\t}\n\n\tbase = path.Clean(base)\n\ttarget = path.Clean(target)\n\n\t// Go's implementation does these checks\n\tif base == target {\n\t\treturn \".\", true\n\t}\n\tif base == \".\" {\n\t\tbase = \"\"\n\t}\n\n\t// Go's implementation fails when this condition is false. I believe this is\n\t// because of this part of the contract, from Go's documentation: \"An error\n\t// is returned if targpath can't be made relative to basepath or if knowing\n\t// the current working directory would be necessary to compute it.\"\n\tif (len(base) > 0 && base[0] == '/') != (len(target) > 0 && target[0] == '/') {\n\t\treturn \"\", false\n\t}\n\n\t// Find the common parent directory\n\tfor {\n\t\tbHead, bTail := splitOnSlash(base)\n\t\ttHead, tTail := splitOnSlash(target)\n\t\tif bHead != tHead {\n\t\t\tbreak\n\t\t}\n\t\tbase = bTail\n\t\ttarget = tTail\n\t}\n\n\t// Stop now if base is a subpath of target\n\tif base == \"\" {\n\t\tif fs.Kind == MockWindows {\n\t\t\ttarget = unix2win(target, volume, fs.defaultVolume)\n\t\t}\n\t\treturn target, true\n\t}\n\n\t// Traverse up to the common parent\n\tcommonParent := strings.Repeat(\"../\", strings.Count(base, \"/\")+1)\n\n\t// Stop now if target is a subpath of base\n\tif target == \"\" {\n\t\ttarget = commonParent[:len(commonParent)-1]\n\t\tif fs.Kind == MockWindows {\n\t\t\ttarget = unix2win(target, volume, fs.defaultVolume)\n\t\t}\n\t\treturn target, true\n\t}\n\n\t// Otherwise, down to the parent\n\ttarget = commonParent + target\n\tif fs.Kind == MockWindows {\n\t\ttarget = unix2win(target, volume, fs.defaultVolume)\n\t}\n\treturn target, true\n}\n\nfunc (fs *mockFS) EvalSymlinks(path string) (string, bool) {\n\treturn \"\", false\n}\n\nfunc (fs *mockFS) kind(dir string, base string) (symlink string, kind EntryKind) {\n\tpanic(\"This should never be called\")\n}\n\nfunc (fs *mockFS) WatchData() WatchData {\n\tpanic(\"This should never be called\")\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/fs_real.go",
    "content": "package fs\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n)\n\ntype realFS struct {\n\t// Stores the file entries for directories we've listed before\n\tentries map[string]entriesOrErr\n\n\t// This stores data that will end up being returned by \"WatchData()\"\n\twatchData map[string]privateWatchData\n\n\t// When building with WebAssembly, the Go compiler doesn't correctly handle\n\t// platform-specific path behavior. Hack around these bugs by compiling\n\t// support for both Unix and Windows paths into all executables and switch\n\t// between them at run-time instead.\n\tfp goFilepath\n\n\tentriesMutex sync.Mutex\n\twatchMutex   sync.Mutex\n\n\t// If true, do not use the \"entries\" cache\n\tdoNotCacheEntries bool\n}\n\ntype entriesOrErr struct {\n\tcanonicalError error\n\toriginalError  error\n\tentries        DirEntries\n}\n\ntype watchState uint8\n\nconst (\n\tstateNone                  watchState = iota\n\tstateDirHasAccessedEntries            // Compare \"accessedEntries\"\n\tstateDirUnreadable                    // Compare directory readability\n\tstateFileHasModKey                    // Compare \"modKey\"\n\tstateFileNeedModKey                   // Need to transition to \"stateFileHasModKey\" or \"stateFileUnusableModKey\" before \"WatchData()\" returns\n\tstateFileMissing                      // Compare file presence\n\tstateFileUnusableModKey               // Compare \"fileContents\"\n)\n\ntype privateWatchData struct {\n\taccessedEntries *accessedEntries\n\tfileContents    string\n\tmodKey          ModKey\n\tstate           watchState\n}\n\ntype RealFSOptions struct {\n\tAbsWorkingDir string\n\tWantWatchData bool\n\tDoNotCache    bool\n}\n\nfunc RealFS(options RealFSOptions) (FS, error) {\n\tvar fp goFilepath\n\tif CheckIfWindows() {\n\t\tfp.isWindows = true\n\t\tfp.pathSeparator = '\\\\'\n\t} else {\n\t\tfp.isWindows = false\n\t\tfp.pathSeparator = '/'\n\t}\n\n\t// Come up with a default working directory if one was not specified\n\tfp.cwd = options.AbsWorkingDir\n\tif fp.cwd == \"\" {\n\t\tif cwd, err := os.Getwd(); err == nil {\n\t\t\tfp.cwd = cwd\n\t\t} else if fp.isWindows {\n\t\t\tfp.cwd = \"C:\\\\\"\n\t\t} else {\n\t\t\tfp.cwd = \"/\"\n\t\t}\n\t} else if !fp.isAbs(fp.cwd) {\n\t\treturn nil, fmt.Errorf(\"The working directory %q is not an absolute path\", fp.cwd)\n\t}\n\n\t// Resolve symlinks in the current working directory. Symlinks are resolved\n\t// when input file paths are converted to absolute paths because we need to\n\t// recognize an input file as unique even if it has multiple symlinks\n\t// pointing to it. The build will generate relative paths from the current\n\t// working directory to the absolute input file paths for error messages,\n\t// so the current working directory should be processed the same way. Not\n\t// doing this causes test failures with esbuild when run from inside a\n\t// symlinked directory.\n\t//\n\t// This deliberately ignores errors due to e.g. infinite loops. If there is\n\t// an error, we will just use the original working directory and likely\n\t// encounter an error later anyway. And if we don't encounter an error\n\t// later, then the current working directory didn't even matter and the\n\t// error is unimportant.\n\tif path, err := fp.evalSymlinks(fp.cwd); err == nil {\n\t\tfp.cwd = path\n\t}\n\n\t// Only allocate memory for watch data if necessary\n\tvar watchData map[string]privateWatchData\n\tif options.WantWatchData {\n\t\twatchData = make(map[string]privateWatchData)\n\t}\n\n\tvar result FS = &realFS{\n\t\tentries:           make(map[string]entriesOrErr),\n\t\tfp:                fp,\n\t\twatchData:         watchData,\n\t\tdoNotCacheEntries: options.DoNotCache,\n\t}\n\n\t// Add a wrapper that lets us traverse into \".zip\" files. This is what yarn\n\t// uses as a package format when in yarn is in its \"PnP\" mode.\n\tresult = &zipFS{\n\t\tinner:    result,\n\t\tzipFiles: make(map[string]*zipFile),\n\t}\n\n\treturn result, nil\n}\n\nfunc (fs *realFS) ReadDirectory(dir string) (entries DirEntries, canonicalError error, originalError error) {\n\tif !fs.doNotCacheEntries {\n\t\t// First, check the cache\n\t\tcached, ok := func() (cached entriesOrErr, ok bool) {\n\t\t\tfs.entriesMutex.Lock()\n\t\t\tdefer fs.entriesMutex.Unlock()\n\t\t\tcached, ok = fs.entries[dir]\n\t\t\treturn\n\t\t}()\n\t\tif ok {\n\t\t\t// Cache hit: stop now\n\t\t\treturn cached.entries, cached.canonicalError, cached.originalError\n\t\t}\n\t}\n\n\t// Cache miss: read the directory entries\n\tnames, canonicalError, originalError := fs.readdir(dir)\n\tentries = DirEntries{dir: dir, data: make(map[string]*Entry)}\n\n\t// Unwrap to get the underlying error\n\tif pathErr, ok := canonicalError.(*os.PathError); ok {\n\t\tcanonicalError = pathErr.Unwrap()\n\t}\n\n\tif canonicalError == nil {\n\t\tfor _, name := range names {\n\t\t\t// Call \"stat\" lazily for performance. The \"@material-ui/icons\" package\n\t\t\t// contains a directory with over 11,000 entries in it and running \"stat\"\n\t\t\t// for each entry was a big performance issue for that package.\n\t\t\tentries.data[strings.ToLower(name)] = &Entry{\n\t\t\t\tdir:      dir,\n\t\t\t\tbase:     name,\n\t\t\t\tneedStat: true,\n\t\t\t}\n\t\t}\n\t}\n\n\t// Store data for watch mode\n\tif fs.watchData != nil {\n\t\tdefer fs.watchMutex.Unlock()\n\t\tfs.watchMutex.Lock()\n\t\tstate := stateDirHasAccessedEntries\n\t\tif canonicalError != nil {\n\t\t\tstate = stateDirUnreadable\n\t\t}\n\t\tentries.accessedEntries = &accessedEntries{wasPresent: make(map[string]bool)}\n\t\tfs.watchData[dir] = privateWatchData{\n\t\t\taccessedEntries: entries.accessedEntries,\n\t\t\tstate:           state,\n\t\t}\n\t}\n\n\t// Update the cache unconditionally. Even if the read failed, we don't want to\n\t// retry again later. The directory is inaccessible so trying again is wasted.\n\tif canonicalError != nil {\n\t\tentries.data = nil\n\t}\n\tif !fs.doNotCacheEntries {\n\t\tfs.entriesMutex.Lock()\n\t\tdefer fs.entriesMutex.Unlock()\n\t\tfs.entries[dir] = entriesOrErr{\n\t\t\tentries:        entries,\n\t\t\tcanonicalError: canonicalError,\n\t\t\toriginalError:  originalError,\n\t\t}\n\t}\n\treturn entries, canonicalError, originalError\n}\n\nfunc (fs *realFS) ReadFile(path string) (contents string, canonicalError error, originalError error) {\n\tBeforeFileOpen()\n\tdefer AfterFileClose()\n\tbuffer, originalError := ioutil.ReadFile(path)\n\tcanonicalError = fs.canonicalizeError(originalError)\n\n\t// Allocate the string once\n\tfileContents := string(buffer)\n\n\t// Store data for watch mode\n\tif fs.watchData != nil {\n\t\tdefer fs.watchMutex.Unlock()\n\t\tfs.watchMutex.Lock()\n\t\tdata, ok := fs.watchData[path]\n\t\tif canonicalError != nil {\n\t\t\tdata.state = stateFileMissing\n\t\t} else if !ok || data.state == stateDirUnreadable {\n\t\t\t// Note: If \"ReadDirectory\" is called before \"ReadFile\" with this same\n\t\t\t// path, then \"data.state\" will be \"stateDirUnreadable\". In that case\n\t\t\t// we want to transition to \"stateFileNeedModKey\" because it's a file.\n\t\t\tdata.state = stateFileNeedModKey\n\t\t}\n\t\tdata.fileContents = fileContents\n\t\tfs.watchData[path] = data\n\t}\n\n\treturn fileContents, canonicalError, originalError\n}\n\ntype realOpenedFile struct {\n\thandle *os.File\n\tlen    int\n}\n\nfunc (f *realOpenedFile) Len() int {\n\treturn f.len\n}\n\nfunc (f *realOpenedFile) Read(start int, end int) ([]byte, error) {\n\tbytes := make([]byte, end-start)\n\tremaining := bytes\n\n\t_, err := f.handle.Seek(int64(start), io.SeekStart)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor len(remaining) > 0 {\n\t\tn, err := f.handle.Read(remaining)\n\t\tif err != nil && n <= 0 {\n\t\t\treturn nil, err\n\t\t}\n\t\tremaining = remaining[n:]\n\t}\n\n\treturn bytes, nil\n}\n\nfunc (f *realOpenedFile) Close() error {\n\treturn f.handle.Close()\n}\n\nfunc (fs *realFS) OpenFile(path string) (OpenedFile, error, error) {\n\tBeforeFileOpen()\n\tdefer AfterFileClose()\n\n\tf, err := os.Open(path)\n\tif err != nil {\n\t\treturn nil, fs.canonicalizeError(err), err\n\t}\n\n\tinfo, err := f.Stat()\n\tif err != nil {\n\t\tf.Close()\n\t\treturn nil, fs.canonicalizeError(err), err\n\t}\n\n\treturn &realOpenedFile{f, int(info.Size())}, nil, nil\n}\n\nfunc (fs *realFS) ModKey(path string) (ModKey, error) {\n\tBeforeFileOpen()\n\tdefer AfterFileClose()\n\tkey, err := modKey(path)\n\n\t// Store data for watch mode\n\tif fs.watchData != nil {\n\t\tdefer fs.watchMutex.Unlock()\n\t\tfs.watchMutex.Lock()\n\t\tdata, ok := fs.watchData[path]\n\t\tif !ok {\n\t\t\tif err == modKeyUnusable {\n\t\t\t\tdata.state = stateFileUnusableModKey\n\t\t\t} else if err != nil {\n\t\t\t\tdata.state = stateFileMissing\n\t\t\t} else {\n\t\t\t\tdata.state = stateFileHasModKey\n\t\t\t}\n\t\t} else if data.state == stateFileNeedModKey {\n\t\t\tdata.state = stateFileHasModKey\n\t\t}\n\t\tdata.modKey = key\n\t\tfs.watchData[path] = data\n\t}\n\n\treturn key, err\n}\n\nfunc (fs *realFS) IsAbs(p string) bool {\n\treturn fs.fp.isAbs(p)\n}\n\nfunc (fs *realFS) Abs(p string) (string, bool) {\n\tabs, err := fs.fp.abs(p)\n\treturn abs, err == nil\n}\n\nfunc (fs *realFS) Dir(p string) string {\n\treturn fs.fp.dir(p)\n}\n\nfunc (fs *realFS) Base(p string) string {\n\treturn fs.fp.base(p)\n}\n\nfunc (fs *realFS) Ext(p string) string {\n\treturn fs.fp.ext(p)\n}\n\nfunc (fs *realFS) Join(parts ...string) string {\n\treturn fs.fp.clean(fs.fp.join(parts))\n}\n\nfunc (fs *realFS) Cwd() string {\n\treturn fs.fp.cwd\n}\n\nfunc (fs *realFS) Rel(base string, target string) (string, bool) {\n\tif rel, err := fs.fp.rel(base, target); err == nil {\n\t\treturn rel, true\n\t}\n\treturn \"\", false\n}\n\nfunc (fs *realFS) EvalSymlinks(path string) (string, bool) {\n\tif path, err := fs.fp.evalSymlinks(path); err == nil {\n\t\treturn path, true\n\t}\n\treturn \"\", false\n}\n\nfunc (fs *realFS) readdir(dirname string) (entries []string, canonicalError error, originalError error) {\n\tBeforeFileOpen()\n\tdefer AfterFileClose()\n\tf, originalError := os.Open(dirname)\n\tcanonicalError = fs.canonicalizeError(originalError)\n\n\t// Stop now if there was an error\n\tif canonicalError != nil {\n\t\treturn nil, canonicalError, originalError\n\t}\n\n\tdefer f.Close()\n\tentries, originalError = f.Readdirnames(-1)\n\tcanonicalError = originalError\n\n\t// Unwrap to get the underlying error\n\tif syscallErr, ok := canonicalError.(*os.SyscallError); ok {\n\t\tcanonicalError = syscallErr.Unwrap()\n\t}\n\n\t// Don't convert ENOTDIR to ENOENT here. ENOTDIR is a legitimate error\n\t// condition for Readdirnames() on non-Windows platforms.\n\n\t// Go's WebAssembly implementation returns EINVAL instead of ENOTDIR if we\n\t// call \"readdir\" on a file. Canonicalize this to ENOTDIR so esbuild's path\n\t// resolution code continues traversing instead of failing with an error.\n\t// https://github.com/golang/go/blob/2449bbb5e614954ce9e99c8a481ea2ee73d72d61/src/syscall/fs_js.go#L144\n\tif pathErr, ok := canonicalError.(*os.PathError); ok && pathErr.Unwrap() == syscall.EINVAL {\n\t\tcanonicalError = syscall.ENOTDIR\n\t}\n\n\treturn entries, canonicalError, originalError\n}\n\nfunc (fs *realFS) canonicalizeError(err error) error {\n\t// Unwrap to get the underlying error\n\tif pathErr, ok := err.(*os.PathError); ok {\n\t\terr = pathErr.Unwrap()\n\t}\n\n\t// Windows is much more restrictive than Unix about file names. If a file name\n\t// is invalid, it will return ERROR_INVALID_NAME. Treat this as ENOENT (i.e.\n\t// \"the file does not exist\") so that the resolver continues trying to resolve\n\t// the path on this failure instead of aborting with an error.\n\tif fs.fp.isWindows && is_ERROR_INVALID_NAME(err) {\n\t\terr = syscall.ENOENT\n\t}\n\n\t// Windows returns ENOTDIR here even though nothing we've done yet has asked\n\t// for a directory. This really means ENOENT on Windows. Return ENOENT here\n\t// so callers that check for ENOENT will successfully detect this file as\n\t// missing.\n\tif err == syscall.ENOTDIR {\n\t\terr = syscall.ENOENT\n\t}\n\n\treturn err\n}\n\nfunc (fs *realFS) kind(dir string, base string) (symlink string, kind EntryKind) {\n\tentryPath := fs.fp.join([]string{dir, base})\n\n\t// Use \"lstat\" since we want information about symbolic links\n\tBeforeFileOpen()\n\tdefer AfterFileClose()\n\tstat, err := os.Lstat(entryPath)\n\tif err != nil {\n\t\treturn\n\t}\n\tmode := stat.Mode()\n\n\t// Follow symlinks now so the cache contains the translation\n\tif (mode & os.ModeSymlink) != 0 {\n\t\tlink, err := fs.fp.evalSymlinks(entryPath)\n\t\tif err != nil {\n\t\t\treturn // Skip over this entry\n\t\t}\n\n\t\t// Re-run \"lstat\" on the symlink target to see if it's a file or not\n\t\tstat2, err2 := os.Lstat(link)\n\t\tif err2 != nil {\n\t\t\treturn // Skip over this entry\n\t\t}\n\t\tmode = stat2.Mode()\n\t\tif (mode & os.ModeSymlink) != 0 {\n\t\t\treturn // This should no longer be a symlink, so this is unexpected\n\t\t}\n\t\tsymlink = link\n\t}\n\n\t// We consider the entry either a directory or a file\n\tif (mode & os.ModeDir) != 0 {\n\t\tkind = DirEntry\n\t} else {\n\t\tkind = FileEntry\n\t}\n\treturn\n}\n\nfunc (fs *realFS) WatchData() WatchData {\n\tpaths := make(map[string]func() string)\n\n\tfor path, data := range fs.watchData {\n\t\t// Each closure below needs its own copy of these loop variables\n\t\tpath := path\n\t\tdata := data\n\n\t\t// Each function should return true if the state has been changed\n\t\tif data.state == stateFileNeedModKey {\n\t\t\tkey, err := modKey(path)\n\t\t\tif err == modKeyUnusable {\n\t\t\t\tdata.state = stateFileUnusableModKey\n\t\t\t} else if err != nil {\n\t\t\t\tdata.state = stateFileMissing\n\t\t\t} else {\n\t\t\t\tdata.state = stateFileHasModKey\n\t\t\t\tdata.modKey = key\n\t\t\t}\n\t\t}\n\n\t\tswitch data.state {\n\t\tcase stateDirUnreadable:\n\t\t\tpaths[path] = func() string {\n\t\t\t\t_, err, _ := fs.readdir(path)\n\t\t\t\tif err == nil {\n\t\t\t\t\treturn path\n\t\t\t\t}\n\t\t\t\treturn \"\"\n\t\t\t}\n\n\t\tcase stateDirHasAccessedEntries:\n\t\t\tpaths[path] = func() string {\n\t\t\t\tnames, err, _ := fs.readdir(path)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn path\n\t\t\t\t}\n\t\t\t\tdata.accessedEntries.mutex.Lock()\n\t\t\t\tdefer data.accessedEntries.mutex.Unlock()\n\t\t\t\tif allEntries := data.accessedEntries.allEntries; allEntries != nil {\n\t\t\t\t\t// Check all entries\n\t\t\t\t\tif len(names) != len(allEntries) {\n\t\t\t\t\t\treturn path\n\t\t\t\t\t}\n\t\t\t\t\tsort.Strings(names)\n\t\t\t\t\tfor i, s := range names {\n\t\t\t\t\t\tif s != allEntries[i] {\n\t\t\t\t\t\t\treturn path\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Check individual entries\n\t\t\t\t\tlookup := make(map[string]string, len(names))\n\t\t\t\t\tfor _, name := range names {\n\t\t\t\t\t\tlookup[strings.ToLower(name)] = name\n\t\t\t\t\t}\n\t\t\t\t\tfor name, wasPresent := range data.accessedEntries.wasPresent {\n\t\t\t\t\t\tif originalName, isPresent := lookup[name]; wasPresent != isPresent {\n\t\t\t\t\t\t\treturn fs.Join(path, originalName)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn \"\"\n\t\t\t}\n\n\t\tcase stateFileMissing:\n\t\t\tpaths[path] = func() string {\n\t\t\t\tif info, err := os.Stat(path); err == nil && !info.IsDir() {\n\t\t\t\t\treturn path\n\t\t\t\t}\n\t\t\t\treturn \"\"\n\t\t\t}\n\n\t\tcase stateFileHasModKey:\n\t\t\tpaths[path] = func() string {\n\t\t\t\tif key, err := modKey(path); err != nil || key != data.modKey {\n\t\t\t\t\treturn path\n\t\t\t\t}\n\t\t\t\treturn \"\"\n\t\t\t}\n\n\t\tcase stateFileUnusableModKey:\n\t\t\tpaths[path] = func() string {\n\t\t\t\tif buffer, err := ioutil.ReadFile(path); err != nil || string(buffer) != data.fileContents {\n\t\t\t\t\treturn path\n\t\t\t\t}\n\t\t\t\treturn \"\"\n\t\t\t}\n\t\t}\n\t}\n\n\treturn WatchData{\n\t\tPaths: paths,\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/fs_zip.go",
    "content": "package fs\n\n// The Yarn package manager (https://yarnpkg.com/) has a custom installation\n// strategy called \"Plug'n'Play\" where they install packages as zip files\n// instead of directory trees, and then modify node to treat zip files like\n// directories. This reduces package installation time because Yarn now only\n// has to copy a single file per package instead of a whole directory tree.\n// However, it introduces overhead at run-time because the virtual file system\n// is written in JavaScript.\n//\n// This file contains esbuild's implementation of the behavior that treats zip\n// files like directories. It implements the \"FS\" interface and wraps an inner\n// \"FS\" interface that treats zip files like files. That way it can run both on\n// a real file system and a mock file system.\n//\n// This file also implements another Yarn-specific behavior where certain paths\n// containing the special path segments \"__virtual__\" or \"$$virtual\" have some\n// unusual behavior. See the code below for details.\n\nimport (\n\t\"archive/zip\"\n\t\"io/ioutil\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n)\n\ntype zipFS struct {\n\tinner FS\n\n\tzipFilesMutex sync.Mutex\n\tzipFiles      map[string]*zipFile\n}\n\ntype zipFile struct {\n\treader *zip.ReadCloser\n\terr    error\n\n\tdirs  map[string]*compressedDir\n\tfiles map[string]*compressedFile\n\twait  sync.WaitGroup\n}\n\ntype compressedDir struct {\n\tentries map[string]EntryKind\n\tpath    string\n\n\t// Compatible entries are decoded lazily\n\tmutex      sync.Mutex\n\tdirEntries DirEntries\n}\n\ntype compressedFile struct {\n\tcompressed *zip.File\n\n\t// The file is decompressed lazily\n\tmutex    sync.Mutex\n\tcontents string\n\terr      error\n\twasRead  bool\n}\n\nfunc (fs *zipFS) checkForZip(path string, kind EntryKind) (*zipFile, string) {\n\tvar zipPath string\n\tvar pathTail string\n\n\t// Do a quick check for a \".zip\" in the path at all\n\tpath = strings.ReplaceAll(path, \"\\\\\", \"/\")\n\tif i := strings.Index(path, \".zip/\"); i != -1 {\n\t\tzipPath = path[:i+len(\".zip\")]\n\t\tpathTail = path[i+len(\".zip/\"):]\n\t} else if kind == DirEntry && strings.HasSuffix(path, \".zip\") {\n\t\tzipPath = path\n\t} else {\n\t\treturn nil, \"\"\n\t}\n\n\t// If there is one, then check whether it's a file on the file system or not\n\tfs.zipFilesMutex.Lock()\n\tarchive := fs.zipFiles[zipPath]\n\tif archive != nil {\n\t\tfs.zipFilesMutex.Unlock()\n\t\tarchive.wait.Wait()\n\t} else {\n\t\tarchive = &zipFile{}\n\t\tarchive.wait.Add(1)\n\t\tfs.zipFiles[zipPath] = archive\n\t\tfs.zipFilesMutex.Unlock()\n\t\tdefer archive.wait.Done()\n\n\t\t// Try reading the zip archive if it's not in the cache\n\t\ttryToReadZipArchive(zipPath, archive)\n\t}\n\n\tif archive.err != nil {\n\t\treturn nil, \"\"\n\t}\n\treturn archive, pathTail\n}\n\nfunc tryToReadZipArchive(zipPath string, archive *zipFile) {\n\treader, err := zip.OpenReader(zipPath)\n\tif err != nil {\n\t\tarchive.err = err\n\t\treturn\n\t}\n\n\tdirs := make(map[string]*compressedDir)\n\tfiles := make(map[string]*compressedFile)\n\tseeds := []string{}\n\n\t// Build an index of all files in the archive\n\tfor _, file := range reader.File {\n\t\tbaseName := strings.TrimSuffix(file.Name, \"/\")\n\t\tdirPath := \"\"\n\t\tif slash := strings.LastIndexByte(baseName, '/'); slash != -1 {\n\t\t\tdirPath = baseName[:slash]\n\t\t\tbaseName = baseName[slash+1:]\n\t\t}\n\t\tif file.FileInfo().IsDir() {\n\t\t\t// Handle a directory\n\t\t\tlowerDir := strings.ToLower(dirPath)\n\t\t\tif _, ok := dirs[lowerDir]; !ok {\n\t\t\t\tdir := &compressedDir{\n\t\t\t\t\tpath:    dirPath,\n\t\t\t\t\tentries: make(map[string]EntryKind),\n\t\t\t\t}\n\n\t\t\t\t// List the same directory both with and without the slash\n\t\t\t\tdirs[lowerDir] = dir\n\t\t\t\tdirs[lowerDir+\"/\"] = dir\n\t\t\t\tseeds = append(seeds, lowerDir)\n\t\t\t}\n\t\t} else {\n\t\t\t// Handle a file\n\t\t\tfiles[strings.ToLower(file.Name)] = &compressedFile{compressed: file}\n\t\t\tlowerDir := strings.ToLower(dirPath)\n\t\t\tdir, ok := dirs[lowerDir]\n\t\t\tif !ok {\n\t\t\t\tdir = &compressedDir{\n\t\t\t\t\tpath:    dirPath,\n\t\t\t\t\tentries: make(map[string]EntryKind),\n\t\t\t\t}\n\n\t\t\t\t// List the same directory both with and without the slash\n\t\t\t\tdirs[lowerDir] = dir\n\t\t\t\tdirs[lowerDir+\"/\"] = dir\n\t\t\t\tseeds = append(seeds, lowerDir)\n\t\t\t}\n\t\t\tdir.entries[baseName] = FileEntry\n\t\t}\n\t}\n\n\t// Populate child directories\n\tfor _, baseName := range seeds {\n\t\tfor baseName != \"\" {\n\t\t\tdirPath := \"\"\n\t\t\tif slash := strings.LastIndexByte(baseName, '/'); slash != -1 {\n\t\t\t\tdirPath = baseName[:slash]\n\t\t\t\tbaseName = baseName[slash+1:]\n\t\t\t}\n\t\t\tlowerDir := strings.ToLower(dirPath)\n\t\t\tdir, ok := dirs[lowerDir]\n\t\t\tif !ok {\n\t\t\t\tdir = &compressedDir{\n\t\t\t\t\tpath:    dirPath,\n\t\t\t\t\tentries: make(map[string]EntryKind),\n\t\t\t\t}\n\n\t\t\t\t// List the same directory both with and without the slash\n\t\t\t\tdirs[lowerDir] = dir\n\t\t\t\tdirs[lowerDir+\"/\"] = dir\n\t\t\t}\n\t\t\tdir.entries[baseName] = DirEntry\n\t\t\tbaseName = dirPath\n\t\t}\n\t}\n\n\tarchive.dirs = dirs\n\tarchive.files = files\n\tarchive.reader = reader\n}\n\nfunc (fs *zipFS) ReadDirectory(path string) (entries DirEntries, canonicalError error, originalError error) {\n\tpath = mangleYarnPnPVirtualPath(path)\n\n\tentries, canonicalError, originalError = fs.inner.ReadDirectory(path)\n\n\t// Only continue if reading this path as a directory caused an error that's\n\t// consistent with trying to read a zip file as a directory. Note that EINVAL\n\t// is produced by the file system in Go's WebAssembly implementation.\n\tif canonicalError != syscall.ENOENT && canonicalError != syscall.ENOTDIR && canonicalError != syscall.EINVAL {\n\t\treturn\n\t}\n\n\t// If the directory doesn't exist, try reading from an enclosing zip archive\n\tzip, pathTail := fs.checkForZip(path, DirEntry)\n\tif zip == nil {\n\t\treturn\n\t}\n\n\t// Does the zip archive have this directory?\n\tdir, ok := zip.dirs[strings.ToLower(pathTail)]\n\tif !ok {\n\t\treturn DirEntries{}, syscall.ENOENT, syscall.ENOENT\n\t}\n\n\t// Check whether it has already been converted\n\tdir.mutex.Lock()\n\tdefer dir.mutex.Unlock()\n\tif dir.dirEntries.data != nil {\n\t\treturn dir.dirEntries, nil, nil\n\t}\n\n\t// Otherwise, fill in the entries\n\tdir.dirEntries = DirEntries{dir: path, data: make(map[string]*Entry, len(dir.entries))}\n\tfor name, kind := range dir.entries {\n\t\tdir.dirEntries.data[strings.ToLower(name)] = &Entry{\n\t\t\tdir:  path,\n\t\t\tbase: name,\n\t\t\tkind: kind,\n\t\t}\n\t}\n\n\treturn dir.dirEntries, nil, nil\n}\n\nfunc (fs *zipFS) ReadFile(path string) (contents string, canonicalError error, originalError error) {\n\tpath = mangleYarnPnPVirtualPath(path)\n\n\tcontents, canonicalError, originalError = fs.inner.ReadFile(path)\n\tif canonicalError != syscall.ENOENT {\n\t\treturn\n\t}\n\n\t// If the file doesn't exist, try reading from an enclosing zip archive\n\tzip, pathTail := fs.checkForZip(path, FileEntry)\n\tif zip == nil {\n\t\treturn\n\t}\n\n\t// Does the zip archive have this file?\n\tfile, ok := zip.files[strings.ToLower(pathTail)]\n\tif !ok {\n\t\treturn \"\", syscall.ENOENT, syscall.ENOENT\n\t}\n\n\t// Check whether it has already been read\n\tfile.mutex.Lock()\n\tdefer file.mutex.Unlock()\n\tif file.wasRead {\n\t\treturn file.contents, file.err, file.err\n\t}\n\tfile.wasRead = true\n\n\t// If not, try to open it\n\treader, err := file.compressed.Open()\n\tif err != nil {\n\t\tfile.err = err\n\t\treturn \"\", err, err\n\t}\n\tdefer reader.Close()\n\n\t// Then try to read it\n\tbytes, err := ioutil.ReadAll(reader)\n\tif err != nil {\n\t\tfile.err = err\n\t\treturn \"\", err, err\n\t}\n\n\tfile.contents = string(bytes)\n\treturn file.contents, nil, nil\n}\n\nfunc (fs *zipFS) OpenFile(path string) (result OpenedFile, canonicalError error, originalError error) {\n\tpath = mangleYarnPnPVirtualPath(path)\n\n\tresult, canonicalError, originalError = fs.inner.OpenFile(path)\n\treturn\n}\n\nfunc (fs *zipFS) ModKey(path string) (modKey ModKey, err error) {\n\tpath = mangleYarnPnPVirtualPath(path)\n\n\tmodKey, err = fs.inner.ModKey(path)\n\treturn\n}\n\nfunc (fs *zipFS) IsAbs(path string) bool {\n\treturn fs.inner.IsAbs(path)\n}\n\nfunc (fs *zipFS) Abs(path string) (string, bool) {\n\treturn fs.inner.Abs(path)\n}\n\nfunc (fs *zipFS) Dir(path string) string {\n\tif prefix, suffix, ok := ParseYarnPnPVirtualPath(path); ok && suffix == \"\" {\n\t\treturn prefix\n\t}\n\treturn fs.inner.Dir(path)\n}\n\nfunc (fs *zipFS) Base(path string) string {\n\treturn fs.inner.Base(path)\n}\n\nfunc (fs *zipFS) Ext(path string) string {\n\treturn fs.inner.Ext(path)\n}\n\nfunc (fs *zipFS) Join(parts ...string) string {\n\treturn fs.inner.Join(parts...)\n}\n\nfunc (fs *zipFS) Cwd() string {\n\treturn fs.inner.Cwd()\n}\n\nfunc (fs *zipFS) Rel(base string, target string) (string, bool) {\n\treturn fs.inner.Rel(base, target)\n}\n\nfunc (fs *zipFS) EvalSymlinks(path string) (string, bool) {\n\treturn fs.inner.EvalSymlinks(path)\n}\n\nfunc (fs *zipFS) kind(dir string, base string) (symlink string, kind EntryKind) {\n\treturn fs.inner.kind(dir, base)\n}\n\nfunc (fs *zipFS) WatchData() WatchData {\n\treturn fs.inner.WatchData()\n}\n\nfunc ParseYarnPnPVirtualPath(path string) (string, string, bool) {\n\ti := 0\n\n\tfor {\n\t\tstart := i\n\t\tslash := strings.IndexAny(path[i:], \"/\\\\\")\n\t\tif slash == -1 {\n\t\t\tbreak\n\t\t}\n\t\ti += slash + 1\n\n\t\t// Replace the segments \"__virtual__/<segment>/<n>\" with N times the \"..\"\n\t\t// operation. Note: The \"__virtual__\" folder name appeared with Yarn 3.0.\n\t\t// Earlier releases used \"$$virtual\", but it was changed after discovering\n\t\t// that this pattern triggered bugs in software where paths were used as\n\t\t// either regexps or replacement. For example, \"$$\" found in the second\n\t\t// parameter of \"String.prototype.replace\" silently turned into \"$\".\n\t\tif segment := path[start : i-1]; segment == \"__virtual__\" || segment == \"$$virtual\" {\n\t\t\tif slash := strings.IndexAny(path[i:], \"/\\\\\"); slash != -1 {\n\t\t\t\tvar count string\n\t\t\t\tvar suffix string\n\t\t\t\tj := i + slash + 1\n\n\t\t\t\t// Find the range of the count\n\t\t\t\tif slash := strings.IndexAny(path[j:], \"/\\\\\"); slash != -1 {\n\t\t\t\t\tcount = path[j : j+slash]\n\t\t\t\t\tsuffix = path[j+slash:]\n\t\t\t\t} else {\n\t\t\t\t\tcount = path[j:]\n\t\t\t\t}\n\n\t\t\t\t// Parse the count\n\t\t\t\tif n, err := strconv.ParseInt(count, 10, 64); err == nil {\n\t\t\t\t\tprefix := path[:start]\n\n\t\t\t\t\t// Apply N times the \"..\" operator\n\t\t\t\t\tfor n > 0 && (strings.HasSuffix(prefix, \"/\") || strings.HasSuffix(prefix, \"\\\\\")) {\n\t\t\t\t\t\tslash := strings.LastIndexAny(prefix[:len(prefix)-1], \"/\\\\\")\n\t\t\t\t\t\tif slash == -1 {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprefix = prefix[:slash+1]\n\t\t\t\t\t\tn--\n\t\t\t\t\t}\n\n\t\t\t\t\t// Make sure the prefix and suffix work well when joined together\n\t\t\t\t\tif suffix == \"\" && strings.IndexAny(prefix, \"/\\\\\") != strings.LastIndexAny(prefix, \"/\\\\\") {\n\t\t\t\t\t\tprefix = prefix[:len(prefix)-1]\n\t\t\t\t\t} else if prefix == \"\" {\n\t\t\t\t\t\tprefix = \".\"\n\t\t\t\t\t} else if strings.HasPrefix(suffix, \"/\") || strings.HasPrefix(suffix, \"\\\\\") {\n\t\t\t\t\t\tsuffix = suffix[1:]\n\t\t\t\t\t}\n\n\t\t\t\t\treturn prefix, suffix, true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\", \"\", false\n}\n\nfunc mangleYarnPnPVirtualPath(path string) string {\n\tif prefix, suffix, ok := ParseYarnPnPVirtualPath(path); ok {\n\t\treturn prefix + suffix\n\t}\n\treturn path\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/iswin_other.go",
    "content": "//go:build (!js || !wasm) && !windows\n// +build !js !wasm\n// +build !windows\n\npackage fs\n\nfunc CheckIfWindows() bool {\n\treturn false\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/iswin_wasm.go",
    "content": "//go:build js && wasm\n// +build js,wasm\n\npackage fs\n\nimport (\n\t\"os\"\n)\n\nvar checkedIfWindows bool\nvar cachedIfWindows bool\n\nfunc CheckIfWindows() bool {\n\tif !checkedIfWindows {\n\t\tcheckedIfWindows = true\n\n\t\t// Hack: Assume that we're on Windows if we're running WebAssembly and\n\t\t// the \"C:\\\\\" directory exists. This is a workaround for a bug in Go's\n\t\t// WebAssembly support: https://github.com/golang/go/issues/43768.\n\t\t_, err := os.Stat(\"C:\\\\\")\n\t\tcachedIfWindows = err == nil\n\t}\n\n\treturn cachedIfWindows\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/iswin_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage fs\n\nfunc CheckIfWindows() bool {\n\treturn true\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/modkey_other.go",
    "content": "//go:build !darwin && !freebsd && !linux\n// +build !darwin,!freebsd,!linux\n\npackage fs\n\nimport (\n\t\"os\"\n\t\"time\"\n)\n\nvar zeroTime time.Time\n\nfunc modKey(path string) (ModKey, error) {\n\tinfo, err := os.Stat(path)\n\tif err != nil {\n\t\treturn ModKey{}, err\n\t}\n\n\t// We can't detect changes if the file system zeros out the modification time\n\tmtime := info.ModTime()\n\tif mtime == zeroTime || mtime.Unix() == 0 {\n\t\treturn ModKey{}, modKeyUnusable\n\t}\n\n\t// Don't generate a modification key if the file is too new\n\tif mtime.Add(modKeySafetyGap * time.Second).After(time.Now()) {\n\t\treturn ModKey{}, modKeyUnusable\n\t}\n\n\treturn ModKey{\n\t\tsize:      info.Size(),\n\t\tmtime_sec: mtime.Unix(),\n\t\tmode:      uint32(info.Mode()),\n\t}, nil\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/fs/modkey_unix.go",
    "content": "//go:build darwin || freebsd || linux\n// +build darwin freebsd linux\n\npackage fs\n\nimport (\n\t\"time\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc modKey(path string) (ModKey, error) {\n\tstat := unix.Stat_t{}\n\tif err := unix.Stat(path, &stat); err != nil {\n\t\treturn ModKey{}, err\n\t}\n\n\t// We can't detect changes if the file system zeros out the modification time\n\tif stat.Mtim.Sec == 0 && stat.Mtim.Nsec == 0 {\n\t\treturn ModKey{}, modKeyUnusable\n\t}\n\n\t// Don't generate a modification key if the file is too new\n\tnow, err := unix.TimeToTimespec(time.Now())\n\tif err != nil {\n\t\treturn ModKey{}, err\n\t}\n\tmtimeSec := stat.Mtim.Sec + modKeySafetyGap\n\tif mtimeSec > now.Sec || (mtimeSec == now.Sec && stat.Mtim.Nsec > now.Nsec) {\n\t\treturn ModKey{}, modKeyUnusable\n\t}\n\n\treturn ModKey{\n\t\tinode:      stat.Ino,\n\t\tsize:       stat.Size,\n\t\tmtime_sec:  int64(stat.Mtim.Sec),\n\t\tmtime_nsec: int64(stat.Mtim.Nsec),\n\t\tmode:       uint32(stat.Mode),\n\t\tuid:        stat.Uid,\n\t}, nil\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/graph/graph.go",
    "content": "package graph\n\n// This graph represents the set of files that the linker operates on. Each\n// linker has a separate one of these graphs (there is one linker when code\n// splitting is on, but one linker per entry point when code splitting is off).\n//\n// The input data to the linker constructor must be considered immutable because\n// it's shared between linker invocations and is also stored in the cache for\n// incremental builds.\n//\n// The linker constructor makes a shallow clone of the input data and is careful\n// to pre-clone ahead of time the AST fields that it may modify. The Go language\n// doesn't have any type system features for immutability so this has to be\n// manually enforced. Please be careful.\n\nimport (\n\t\"sort\"\n\t\"sync\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n\t\"github.com/evanw/esbuild/internal/runtime\"\n)\n\ntype entryPointKind uint8\n\nconst (\n\tentryPointNone entryPointKind = iota\n\tentryPointUserSpecified\n\tentryPointDynamicImport\n)\n\ntype LinkerFile struct {\n\t// This holds all entry points that can reach this file. It will be used to\n\t// assign the parts in this file to a chunk.\n\tEntryBits helpers.BitSet\n\n\t// This is lazily-allocated because it's only needed if there are warnings\n\t// logged, which should be relatively rare.\n\tlazyLineColumnTracker *logger.LineColumnTracker\n\n\tInputFile InputFile\n\n\t// The minimum number of links in the module graph to get from an entry point\n\t// to this file\n\tDistanceFromEntryPoint uint32\n\n\t// If \"entryPointKind\" is not \"entryPointNone\", this is the index of the\n\t// corresponding entry point chunk.\n\tEntryPointChunkIndex uint32\n\n\t// This file is an entry point if and only if this is not \"entryPointNone\".\n\t// Note that dynamically-imported files are allowed to also be specified by\n\t// the user as top-level entry points, so some dynamically-imported files\n\t// may be \"entryPointUserSpecified\" instead of \"entryPointDynamicImport\".\n\tentryPointKind entryPointKind\n\n\t// This is true if this file has been marked as live by the tree shaking\n\t// algorithm.\n\tIsLive bool\n}\n\nfunc (f *LinkerFile) IsEntryPoint() bool {\n\treturn f.entryPointKind != entryPointNone\n}\n\nfunc (f *LinkerFile) IsUserSpecifiedEntryPoint() bool {\n\treturn f.entryPointKind == entryPointUserSpecified\n}\n\n// Note: This is not guarded by a mutex. Make sure this isn't called from a\n// parallel part of the code.\nfunc (f *LinkerFile) LineColumnTracker() *logger.LineColumnTracker {\n\tif f.lazyLineColumnTracker == nil {\n\t\ttracker := logger.MakeLineColumnTracker(&f.InputFile.Source)\n\t\tf.lazyLineColumnTracker = &tracker\n\t}\n\treturn f.lazyLineColumnTracker\n}\n\ntype EntryPoint struct {\n\t// This may be an absolute path or a relative path. If absolute, it will\n\t// eventually be turned into a relative path by computing the path relative\n\t// to the \"outbase\" directory. Then this relative path will be joined onto\n\t// the \"outdir\" directory to form the final output path for this entry point.\n\tOutputPath string\n\n\t// This is the source index of the entry point. This file must have a valid\n\t// entry point kind (i.e. not \"none\").\n\tSourceIndex uint32\n\n\t// Manually specified output paths are ignored when computing the default\n\t// \"outbase\" directory, which is computed as the lowest common ancestor of\n\t// all automatically generated output paths.\n\tOutputPathWasAutoGenerated bool\n}\n\ntype LinkerGraph struct {\n\tFiles       []LinkerFile\n\tentryPoints []EntryPoint\n\tSymbols     ast.SymbolMap\n\n\t// This is for cross-module inlining of TypeScript enum constants\n\tTSEnums map[ast.Ref]map[string]js_ast.TSEnumValue\n\n\t// This is for cross-module inlining of detected inlinable constants\n\tConstValues map[ast.Ref]js_ast.ConstValue\n\n\t// We should avoid traversing all files in the bundle, because the linker\n\t// should be able to run a linking operation on a large bundle where only\n\t// a few files are needed (e.g. an incremental compilation scenario). This\n\t// holds all files that could possibly be reached through the entry points.\n\t// If you need to iterate over all files in the linking operation, iterate\n\t// over this array. This array is also sorted in a deterministic ordering\n\t// to help ensure deterministic builds (source indices are random).\n\tReachableFiles []uint32\n\n\t// This maps from unstable source index to stable reachable file index. This\n\t// is useful as a deterministic key for sorting if you need to sort something\n\t// containing a source index (such as \"ast.Ref\" symbol references).\n\tStableSourceIndices []uint32\n}\n\nfunc CloneLinkerGraph(\n\tinputFiles []InputFile,\n\treachableFiles []uint32,\n\toriginalEntryPoints []EntryPoint,\n\tcodeSplitting bool,\n) LinkerGraph {\n\tentryPoints := append([]EntryPoint{}, originalEntryPoints...)\n\tsymbols := ast.NewSymbolMap(len(inputFiles))\n\tfiles := make([]LinkerFile, len(inputFiles))\n\n\t// Mark all entry points so we don't add them again for import() expressions\n\tfor _, entryPoint := range entryPoints {\n\t\tfiles[entryPoint.SourceIndex].entryPointKind = entryPointUserSpecified\n\t}\n\n\t// Clone various things since we may mutate them later. Do this in parallel\n\t// for a speedup (around ~2x faster for this function in the three.js\n\t// benchmark on a 6-core laptop).\n\tvar dynamicImportEntryPoints []uint32\n\tvar dynamicImportEntryPointsMutex sync.Mutex\n\twaitGroup := sync.WaitGroup{}\n\twaitGroup.Add(len(reachableFiles))\n\tstableSourceIndices := make([]uint32, len(inputFiles))\n\tfor stableIndex, sourceIndex := range reachableFiles {\n\t\t// Create a way to convert source indices to a stable ordering\n\t\tstableSourceIndices[sourceIndex] = uint32(stableIndex)\n\n\t\tgo func(sourceIndex uint32) {\n\t\t\tfile := &files[sourceIndex]\n\t\t\tfile.InputFile = inputFiles[sourceIndex]\n\n\t\t\tswitch repr := file.InputFile.Repr.(type) {\n\t\t\tcase *JSRepr:\n\t\t\t\t// Clone the representation\n\t\t\t\t{\n\t\t\t\t\tclone := *repr\n\t\t\t\t\trepr = &clone\n\t\t\t\t\tfile.InputFile.Repr = repr\n\t\t\t\t}\n\n\t\t\t\t// Clone the symbol map\n\t\t\t\tfileSymbols := append([]ast.Symbol{}, repr.AST.Symbols...)\n\t\t\t\tsymbols.SymbolsForSource[sourceIndex] = fileSymbols\n\t\t\t\trepr.AST.Symbols = nil\n\n\t\t\t\t// Clone the parts\n\t\t\t\trepr.AST.Parts = append([]js_ast.Part{}, repr.AST.Parts...)\n\t\t\t\tfor i := range repr.AST.Parts {\n\t\t\t\t\tpart := &repr.AST.Parts[i]\n\t\t\t\t\tclone := make(map[ast.Ref]js_ast.SymbolUse, len(part.SymbolUses))\n\t\t\t\t\tfor ref, uses := range part.SymbolUses {\n\t\t\t\t\t\tclone[ref] = uses\n\t\t\t\t\t}\n\t\t\t\t\tpart.SymbolUses = clone\n\t\t\t\t}\n\n\t\t\t\t// Clone the import records\n\t\t\t\trepr.AST.ImportRecords = append([]ast.ImportRecord{}, repr.AST.ImportRecords...)\n\n\t\t\t\t// Add dynamic imports as additional entry points if code splitting is active\n\t\t\t\tif codeSplitting {\n\t\t\t\t\tfor importRecordIndex := range repr.AST.ImportRecords {\n\t\t\t\t\t\tif record := &repr.AST.ImportRecords[importRecordIndex]; record.SourceIndex.IsValid() && record.Kind == ast.ImportDynamic {\n\t\t\t\t\t\t\tdynamicImportEntryPointsMutex.Lock()\n\t\t\t\t\t\t\tdynamicImportEntryPoints = append(dynamicImportEntryPoints, record.SourceIndex.GetIndex())\n\t\t\t\t\t\t\tdynamicImportEntryPointsMutex.Unlock()\n\n\t\t\t\t\t\t\t// Remove import assertions for dynamic imports of additional\n\t\t\t\t\t\t\t// entry points so that they don't mess with the run-time behavior.\n\t\t\t\t\t\t\t// For example, \"import('./foo.json', { assert: { type: 'json' } })\"\n\t\t\t\t\t\t\t// will likely be converted into an import of a JavaScript file and\n\t\t\t\t\t\t\t// leaving the import assertion there will prevent it from working.\n\t\t\t\t\t\t\trecord.AssertOrWith = nil\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Clone the import map\n\t\t\t\tnamedImports := make(map[ast.Ref]js_ast.NamedImport, len(repr.AST.NamedImports))\n\t\t\t\tfor k, v := range repr.AST.NamedImports {\n\t\t\t\t\tnamedImports[k] = v\n\t\t\t\t}\n\t\t\t\trepr.AST.NamedImports = namedImports\n\n\t\t\t\t// Clone the export map\n\t\t\t\tresolvedExports := make(map[string]ExportData)\n\t\t\t\tfor alias, name := range repr.AST.NamedExports {\n\t\t\t\t\tresolvedExports[alias] = ExportData{\n\t\t\t\t\t\tRef:         name.Ref,\n\t\t\t\t\t\tSourceIndex: sourceIndex,\n\t\t\t\t\t\tNameLoc:     name.AliasLoc,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Clone the top-level scope so we can generate more variables\n\t\t\t\t{\n\t\t\t\t\tnew := &js_ast.Scope{}\n\t\t\t\t\t*new = *repr.AST.ModuleScope\n\t\t\t\t\tnew.Generated = append([]ast.Ref{}, new.Generated...)\n\t\t\t\t\trepr.AST.ModuleScope = new\n\t\t\t\t}\n\n\t\t\t\t// Also associate some default metadata with the file\n\t\t\t\trepr.Meta.ResolvedExports = resolvedExports\n\t\t\t\trepr.Meta.IsProbablyTypeScriptType = make(map[ast.Ref]bool)\n\t\t\t\trepr.Meta.ImportsToBind = make(map[ast.Ref]ImportData)\n\n\t\t\tcase *CSSRepr:\n\t\t\t\t// Clone the representation\n\t\t\t\t{\n\t\t\t\t\tclone := *repr\n\t\t\t\t\trepr = &clone\n\t\t\t\t\tfile.InputFile.Repr = repr\n\t\t\t\t}\n\n\t\t\t\t// Clone the symbol map\n\t\t\t\tfileSymbols := append([]ast.Symbol{}, repr.AST.Symbols...)\n\t\t\t\tsymbols.SymbolsForSource[sourceIndex] = fileSymbols\n\t\t\t\trepr.AST.Symbols = nil\n\n\t\t\t\t// Clone the import records\n\t\t\t\trepr.AST.ImportRecords = append([]ast.ImportRecord{}, repr.AST.ImportRecords...)\n\t\t\t}\n\n\t\t\t// All files start off as far as possible from an entry point\n\t\t\tfile.DistanceFromEntryPoint = ^uint32(0)\n\t\t\twaitGroup.Done()\n\t\t}(sourceIndex)\n\t}\n\twaitGroup.Wait()\n\n\t// Process dynamic entry points after merging control flow again\n\tstableEntryPoints := make([]int, 0, len(dynamicImportEntryPoints))\n\tfor _, sourceIndex := range dynamicImportEntryPoints {\n\t\tif otherFile := &files[sourceIndex]; otherFile.entryPointKind == entryPointNone {\n\t\t\tstableEntryPoints = append(stableEntryPoints, int(stableSourceIndices[sourceIndex]))\n\t\t\totherFile.entryPointKind = entryPointDynamicImport\n\t\t}\n\t}\n\n\t// Make sure to add dynamic entry points in a deterministic order\n\tsort.Ints(stableEntryPoints)\n\tfor _, stableIndex := range stableEntryPoints {\n\t\tentryPoints = append(entryPoints, EntryPoint{SourceIndex: reachableFiles[stableIndex]})\n\t}\n\n\t// Do a final quick pass over all files\n\tvar tsEnums map[ast.Ref]map[string]js_ast.TSEnumValue\n\tvar constValues map[ast.Ref]js_ast.ConstValue\n\tbitCount := uint(len(entryPoints))\n\tfor _, sourceIndex := range reachableFiles {\n\t\tfile := &files[sourceIndex]\n\n\t\t// Allocate the entry bit set now that the number of entry points is known\n\t\tfile.EntryBits = helpers.NewBitSet(bitCount)\n\n\t\t// Merge TypeScript enums together into one big map. There likely aren't\n\t\t// too many enum definitions relative to the overall size of the code so\n\t\t// it should be fine to just merge them together in serial.\n\t\tif repr, ok := file.InputFile.Repr.(*JSRepr); ok && repr.AST.TSEnums != nil {\n\t\t\tif tsEnums == nil {\n\t\t\t\ttsEnums = make(map[ast.Ref]map[string]js_ast.TSEnumValue)\n\t\t\t}\n\t\t\tfor ref, enum := range repr.AST.TSEnums {\n\t\t\t\ttsEnums[ref] = enum\n\t\t\t}\n\t\t}\n\n\t\t// Also merge const values into one big map as well\n\t\tif repr, ok := file.InputFile.Repr.(*JSRepr); ok && repr.AST.ConstValues != nil {\n\t\t\tif constValues == nil {\n\t\t\t\tconstValues = make(map[ast.Ref]js_ast.ConstValue)\n\t\t\t}\n\t\t\tfor ref, value := range repr.AST.ConstValues {\n\t\t\t\tconstValues[ref] = value\n\t\t\t}\n\t\t}\n\t}\n\n\treturn LinkerGraph{\n\t\tSymbols:             symbols,\n\t\tTSEnums:             tsEnums,\n\t\tConstValues:         constValues,\n\t\tentryPoints:         entryPoints,\n\t\tFiles:               files,\n\t\tReachableFiles:      reachableFiles,\n\t\tStableSourceIndices: stableSourceIndices,\n\t}\n}\n\n// Prevent packages that depend on us from adding or removing entry points\nfunc (g *LinkerGraph) EntryPoints() []EntryPoint {\n\treturn g.entryPoints\n}\n\nfunc (g *LinkerGraph) AddPartToFile(sourceIndex uint32, part js_ast.Part) uint32 {\n\t// Invariant: this map is never null\n\tif part.SymbolUses == nil {\n\t\tpart.SymbolUses = make(map[ast.Ref]js_ast.SymbolUse)\n\t}\n\n\trepr := g.Files[sourceIndex].InputFile.Repr.(*JSRepr)\n\tpartIndex := uint32(len(repr.AST.Parts))\n\trepr.AST.Parts = append(repr.AST.Parts, part)\n\n\t// Invariant: the parts for all top-level symbols can be found in the file-level map\n\tfor _, declaredSymbol := range part.DeclaredSymbols {\n\t\tif declaredSymbol.IsTopLevel {\n\t\t\t// Check for an existing overlay\n\t\t\tpartIndices, ok := repr.Meta.TopLevelSymbolToPartsOverlay[declaredSymbol.Ref]\n\n\t\t\t// If missing, initialize using the original values from the parser\n\t\t\tif !ok {\n\t\t\t\tpartIndices = append(partIndices, repr.AST.TopLevelSymbolToPartsFromParser[declaredSymbol.Ref]...)\n\t\t\t}\n\n\t\t\t// Add this part to the overlay\n\t\t\tpartIndices = append(partIndices, partIndex)\n\t\t\tif repr.Meta.TopLevelSymbolToPartsOverlay == nil {\n\t\t\t\trepr.Meta.TopLevelSymbolToPartsOverlay = make(map[ast.Ref][]uint32)\n\t\t\t}\n\t\t\trepr.Meta.TopLevelSymbolToPartsOverlay[declaredSymbol.Ref] = partIndices\n\t\t}\n\t}\n\n\treturn partIndex\n}\n\nfunc (g *LinkerGraph) GenerateNewSymbol(sourceIndex uint32, kind ast.SymbolKind, originalName string) ast.Ref {\n\tsourceSymbols := &g.Symbols.SymbolsForSource[sourceIndex]\n\n\tref := ast.Ref{\n\t\tSourceIndex: sourceIndex,\n\t\tInnerIndex:  uint32(len(*sourceSymbols)),\n\t}\n\n\t*sourceSymbols = append(*sourceSymbols, ast.Symbol{\n\t\tKind:         kind,\n\t\tOriginalName: originalName,\n\t\tLink:         ast.InvalidRef,\n\t})\n\n\tgenerated := &g.Files[sourceIndex].InputFile.Repr.(*JSRepr).AST.ModuleScope.Generated\n\t*generated = append(*generated, ref)\n\treturn ref\n}\n\nfunc (g *LinkerGraph) GenerateSymbolImportAndUse(\n\tsourceIndex uint32,\n\tpartIndex uint32,\n\tref ast.Ref,\n\tuseCount uint32,\n\tsourceIndexToImportFrom uint32,\n) {\n\tif useCount == 0 {\n\t\treturn\n\t}\n\n\trepr := g.Files[sourceIndex].InputFile.Repr.(*JSRepr)\n\tpart := &repr.AST.Parts[partIndex]\n\n\t// Mark this symbol as used by this part\n\tuse := part.SymbolUses[ref]\n\tuse.CountEstimate += useCount\n\tpart.SymbolUses[ref] = use\n\n\t// Uphold invariants about the CommonJS \"exports\" and \"module\" symbols\n\tif ref == repr.AST.ExportsRef {\n\t\trepr.AST.UsesExportsRef = true\n\t}\n\tif ref == repr.AST.ModuleRef {\n\t\trepr.AST.UsesModuleRef = true\n\t}\n\n\t// Track that this specific symbol was imported\n\tif sourceIndexToImportFrom != sourceIndex {\n\t\trepr.Meta.ImportsToBind[ref] = ImportData{\n\t\t\tSourceIndex: sourceIndexToImportFrom,\n\t\t\tRef:         ref,\n\t\t}\n\t}\n\n\t// Pull in all parts that declare this symbol\n\ttargetRepr := g.Files[sourceIndexToImportFrom].InputFile.Repr.(*JSRepr)\n\tfor _, partIndex := range targetRepr.TopLevelSymbolToParts(ref) {\n\t\tpart.Dependencies = append(part.Dependencies, js_ast.Dependency{\n\t\t\tSourceIndex: sourceIndexToImportFrom,\n\t\t\tPartIndex:   partIndex,\n\t\t})\n\t}\n}\n\nfunc (g *LinkerGraph) GenerateRuntimeSymbolImportAndUse(\n\tsourceIndex uint32,\n\tpartIndex uint32,\n\tname string,\n\tuseCount uint32,\n) {\n\tif useCount == 0 {\n\t\treturn\n\t}\n\n\truntimeRepr := g.Files[runtime.SourceIndex].InputFile.Repr.(*JSRepr)\n\tref := runtimeRepr.AST.NamedExports[name].Ref\n\tg.GenerateSymbolImportAndUse(sourceIndex, partIndex, ref, useCount, runtime.SourceIndex)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/graph/input.go",
    "content": "package graph\n\n// The code in this file mainly represents data that passes from the scan phase\n// to the compile phase of the bundler. There is currently one exception: the\n// \"meta\" member of the JavaScript file representation. That could have been\n// stored separately but is stored together for convenience and to avoid an\n// extra level of indirection. Instead it's kept in a separate type to keep\n// things organized.\n\nimport (\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/config\"\n\t\"github.com/evanw/esbuild/internal/css_ast\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n\t\"github.com/evanw/esbuild/internal/resolver\"\n\t\"github.com/evanw/esbuild/internal/sourcemap\"\n)\n\ntype InputFile struct {\n\tRepr           InputFileRepr\n\tInputSourceMap *sourcemap.SourceMap\n\n\t// If this file ends up being used in the bundle, these are additional files\n\t// that must be written to the output directory. It's used by the \"file\" and\n\t// \"copy\" loaders.\n\tAdditionalFiles            []OutputFile\n\tUniqueKeyForAdditionalFile string\n\n\tSideEffects SideEffects\n\tSource      logger.Source\n\tLoader      config.Loader\n\n\tOmitFromSourceMapsAndMetafile bool\n}\n\ntype OutputFile struct {\n\t// If \"AbsMetadataFile\" is present, this will be filled out with information\n\t// about this file in JSON format. This is a partial JSON file that will be\n\t// fully assembled later.\n\tJSONMetadataChunk string\n\n\tAbsPath      string\n\tContents     []byte\n\tIsExecutable bool\n}\n\ntype SideEffects struct {\n\t// This is optional additional information for use in error messages\n\tData *resolver.SideEffectsData\n\n\tKind SideEffectsKind\n}\n\ntype SideEffectsKind uint8\n\nconst (\n\t// The default value conservatively considers all files to have side effects.\n\tHasSideEffects SideEffectsKind = iota\n\n\t// This file was listed as not having side effects by a \"package.json\"\n\t// file in one of our containing directories with a \"sideEffects\" field.\n\tNoSideEffects_PackageJSON\n\n\t// This file is considered to have no side effects because the AST was empty\n\t// after parsing finished. This should be the case for \".d.ts\" files.\n\tNoSideEffects_EmptyAST\n\n\t// This file was loaded using a data-oriented loader (e.g. \"text\") that is\n\t// known to not have side effects.\n\tNoSideEffects_PureData\n\n\t// Same as above but it came from a plugin. We don't want to warn about\n\t// unused imports to these files since running the plugin is a side effect.\n\t// Removing the import would not call the plugin which is observable.\n\tNoSideEffects_PureData_FromPlugin\n)\n\ntype InputFileRepr interface {\n\tImportRecords() *[]ast.ImportRecord\n}\n\ntype JSRepr struct {\n\tMeta JSReprMeta\n\tAST  js_ast.AST\n\n\t// If present, this is the CSS file that this JavaScript stub corresponds to.\n\t// A JavaScript stub is automatically generated for a CSS file when it's\n\t// imported from a JavaScript file.\n\tCSSSourceIndex ast.Index32\n}\n\nfunc (repr *JSRepr) ImportRecords() *[]ast.ImportRecord {\n\treturn &repr.AST.ImportRecords\n}\n\nfunc (repr *JSRepr) TopLevelSymbolToParts(ref ast.Ref) []uint32 {\n\t// Overlay the mutable map from the linker\n\tif parts, ok := repr.Meta.TopLevelSymbolToPartsOverlay[ref]; ok {\n\t\treturn parts\n\t}\n\n\t// Fall back to the immutable map from the parser\n\treturn repr.AST.TopLevelSymbolToPartsFromParser[ref]\n}\n\ntype CSSRepr struct {\n\tAST css_ast.AST\n\n\t// If present, this is the JavaScript stub corresponding to this CSS file.\n\t// A JavaScript stub is automatically generated for a CSS file when it's\n\t// imported from a JavaScript file.\n\tJSSourceIndex ast.Index32\n}\n\nfunc (repr *CSSRepr) ImportRecords() *[]ast.ImportRecord {\n\treturn &repr.AST.ImportRecords\n}\n\ntype CopyRepr struct {\n\t// The URL that replaces the contents of any import record paths for this file\n\tURLForCode string\n}\n\nfunc (repr *CopyRepr) ImportRecords() *[]ast.ImportRecord {\n\treturn nil\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/graph/meta.go",
    "content": "package graph\n\n// The code in this file represents data that is required by the compile phase\n// of the bundler but that is not required by the scan phase.\n\nimport (\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\ntype WrapKind uint8\n\nconst (\n\tWrapNone WrapKind = iota\n\n\t// The module will be bundled CommonJS-style like this:\n\t//\n\t//   // foo.ts\n\t//   let require_foo = __commonJS((exports, module) => {\n\t//     exports.foo = 123;\n\t//   });\n\t//\n\t//   // bar.ts\n\t//   let foo = flag ? require_foo() : null;\n\t//\n\tWrapCJS\n\n\t// The module will be bundled ESM-style like this:\n\t//\n\t//   // foo.ts\n\t//   var foo, foo_exports = {};\n\t//   __export(foo_exports, {\n\t//     foo: () => foo\n\t//   });\n\t//   let init_foo = __esm(() => {\n\t//     foo = 123;\n\t//   });\n\t//\n\t//   // bar.ts\n\t//   let foo = flag ? (init_foo(), __toCommonJS(foo_exports)) : null;\n\t//\n\tWrapESM\n)\n\n// This contains linker-specific metadata corresponding to a \"file\" struct\n// from the initial scan phase of the bundler. It's separated out because it's\n// conceptually only used for a single linking operation and because multiple\n// linking operations may be happening in parallel with different metadata for\n// the same file.\ntype JSReprMeta struct {\n\t// This is only for TypeScript files. If an import symbol is in this map, it\n\t// means the import couldn't be found and doesn't actually exist. This is not\n\t// an error in TypeScript because the import is probably just a type.\n\t//\n\t// Normally we remove all unused imports for TypeScript files during parsing,\n\t// which automatically removes type-only imports. But there are certain re-\n\t// export situations where it's impossible to tell if an import is a type or\n\t// not:\n\t//\n\t//   import {typeOrNotTypeWhoKnows} from 'path';\n\t//   export {typeOrNotTypeWhoKnows};\n\t//\n\t// Really people should be using the TypeScript \"isolatedModules\" flag with\n\t// bundlers like this one that compile TypeScript files independently without\n\t// type checking. That causes the TypeScript type checker to emit the error\n\t// \"Re-exporting a type when the '--isolatedModules' flag is provided requires\n\t// using 'export type'.\" But we try to be robust to such code anyway.\n\tIsProbablyTypeScriptType map[ast.Ref]bool\n\n\t// Imports are matched with exports in a separate pass from when the matched\n\t// exports are actually bound to the imports. Here \"binding\" means adding non-\n\t// local dependencies on the parts in the exporting file that declare the\n\t// exported symbol to all parts in the importing file that use the imported\n\t// symbol.\n\t//\n\t// This must be a separate pass because of the \"probably TypeScript type\"\n\t// check above. We can't generate the part for the export namespace until\n\t// we've matched imports with exports because the generated code must omit\n\t// type-only imports in the export namespace code. And we can't bind exports\n\t// to imports until the part for the export namespace is generated since that\n\t// part needs to participate in the binding.\n\t//\n\t// This array holds the deferred imports to bind so the pass can be split\n\t// into two separate passes.\n\tImportsToBind map[ast.Ref]ImportData\n\n\t// This includes both named exports and re-exports.\n\t//\n\t// Named exports come from explicit export statements in the original file,\n\t// and are copied from the \"NamedExports\" field in the AST.\n\t//\n\t// Re-exports come from other files and are the result of resolving export\n\t// star statements (i.e. \"export * from 'foo'\").\n\tResolvedExports     map[string]ExportData\n\tResolvedExportStar  *ExportData\n\tResolvedExportTypos *helpers.TypoDetector\n\n\t// Never iterate over \"resolvedExports\" directly. Instead, iterate over this\n\t// array. Some exports in that map aren't meant to end up in generated code.\n\t// This array excludes these exports and is also sorted, which avoids non-\n\t// determinism due to random map iteration order.\n\tSortedAndFilteredExportAliases []string\n\n\t// This is merged on top of the corresponding map from the parser in the AST.\n\t// You should call \"TopLevelSymbolToParts\" to access this instead of accessing\n\t// it directly.\n\tTopLevelSymbolToPartsOverlay map[ast.Ref][]uint32\n\n\t// If this is an entry point, this array holds a reference to one free\n\t// temporary symbol for each entry in \"sortedAndFilteredExportAliases\".\n\t// These may be needed to store copies of CommonJS re-exports in ESM.\n\tCJSExportCopies []ast.Ref\n\n\t// The index of the automatically-generated part used to represent the\n\t// CommonJS or ESM wrapper. This part is empty and is only useful for tree\n\t// shaking and code splitting. The wrapper can't be inserted into the part\n\t// because the wrapper contains other parts, which can't be represented by\n\t// the current part system. Only wrapped files have one of these.\n\tWrapperPartIndex ast.Index32\n\n\t// The index of the automatically-generated part used to handle entry point\n\t// specific stuff. If a certain part is needed by the entry point, it's added\n\t// as a dependency of this part. This is important for parts that are marked\n\t// as removable when unused and that are not used by anything else. Only\n\t// entry point files have one of these.\n\tEntryPointPartIndex ast.Index32\n\n\t// This is true if this file is affected by top-level await, either by having\n\t// a top-level await inside this file or by having an import/export statement\n\t// that transitively imports such a file. It is forbidden to call \"require()\"\n\t// on these files since they are evaluated asynchronously.\n\tIsAsyncOrHasAsyncDependency bool\n\n\tWrap WrapKind\n\n\t// If true, we need to insert \"var exports = {};\". This is the case for ESM\n\t// files when the import namespace is captured via \"import * as\" and also\n\t// when they are the target of a \"require()\" call.\n\tNeedsExportsVariable bool\n\n\t// If true, the \"__export(exports, { ... })\" call will be force-included even\n\t// if there are no parts that reference \"exports\". Otherwise this call will\n\t// be removed due to the tree shaking pass. This is used when for entry point\n\t// files when code related to the current output format needs to reference\n\t// the \"exports\" variable.\n\tForceIncludeExportsForEntryPoint bool\n\n\t// This is set when we need to pull in the \"__export\" symbol in to the part\n\t// at \"nsExportPartIndex\". This can't be done in \"createExportsForFile\"\n\t// because of concurrent map hazards. Instead, it must be done later.\n\tNeedsExportSymbolFromRuntime bool\n\n\t// Wrapped files must also ensure that their dependencies are wrapped. This\n\t// flag is used during the traversal that enforces this invariant, and is used\n\t// to detect when the fixed point has been reached.\n\tDidWrapDependencies bool\n}\n\ntype ImportData struct {\n\t// This is an array of intermediate statements that re-exported this symbol\n\t// in a chain before getting to the final symbol. This can be done either with\n\t// \"export * from\" or \"export {} from\". If this is done with \"export * from\"\n\t// then this may not be the result of a single chain but may instead form\n\t// a diamond shape if this same symbol was re-exported multiple times from\n\t// different files.\n\tReExports []js_ast.Dependency\n\n\tNameLoc     logger.Loc // Optional, goes with sourceIndex, ignore if zero\n\tRef         ast.Ref\n\tSourceIndex uint32\n}\n\ntype ExportData struct {\n\t// Export star resolution happens first before import resolution. That means\n\t// it cannot yet determine if duplicate names from export star resolution are\n\t// ambiguous (point to different symbols) or not (point to the same symbol).\n\t// This issue can happen in the following scenario:\n\t//\n\t//   // entry.js\n\t//   export * from './a'\n\t//   export * from './b'\n\t//\n\t//   // a.js\n\t//   export * from './c'\n\t//\n\t//   // b.js\n\t//   export {x} from './c'\n\t//\n\t//   // c.js\n\t//   export let x = 1, y = 2\n\t//\n\t// In this case \"entry.js\" should have two exports \"x\" and \"y\", neither of\n\t// which are ambiguous. To handle this case, ambiguity resolution must be\n\t// deferred until import resolution time. That is done using this array.\n\tPotentiallyAmbiguousExportStarRefs []ImportData\n\n\tRef ast.Ref\n\n\t// This is the file that the named export above came from. This will be\n\t// different from the file that contains this object if this is a re-export.\n\tNameLoc     logger.Loc // Optional, goes with sourceIndex, ignore if zero\n\tSourceIndex uint32\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/bitset.go",
    "content": "package helpers\n\nimport \"bytes\"\n\ntype BitSet struct {\n\tentries []byte\n}\n\nfunc NewBitSet(bitCount uint) BitSet {\n\treturn BitSet{make([]byte, (bitCount+7)/8)}\n}\n\nfunc (bs BitSet) HasBit(bit uint) bool {\n\treturn (bs.entries[bit/8] & (1 << (bit & 7))) != 0\n}\n\nfunc (bs BitSet) SetBit(bit uint) {\n\tbs.entries[bit/8] |= 1 << (bit & 7)\n}\n\nfunc (bs BitSet) Equals(other BitSet) bool {\n\treturn bytes.Equal(bs.entries, other.entries)\n}\n\nfunc (bs BitSet) String() string {\n\treturn string(bs.entries)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/dataurl.go",
    "content": "package helpers\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"strings\"\n\t\"unicode/utf8\"\n)\n\n// Returns the shorter of either a base64-encoded or percent-escaped data URL\nfunc EncodeStringAsShortestDataURL(mimeType string, text string) string {\n\tencoded := base64.StdEncoding.EncodeToString([]byte(text))\n\turl := fmt.Sprintf(\"data:%s;base64,%s\", mimeType, encoded)\n\tif percentURL, ok := EncodeStringAsPercentEscapedDataURL(mimeType, text); ok && len(percentURL) < len(url) {\n\t\treturn percentURL\n\t}\n\treturn url\n}\n\n// See \"scripts/dataurl-escapes.html\" for how this was derived\nfunc EncodeStringAsPercentEscapedDataURL(mimeType string, text string) (string, bool) {\n\thex := \"0123456789ABCDEF\"\n\tsb := strings.Builder{}\n\tn := len(text)\n\ti := 0\n\trunStart := 0\n\tsb.WriteString(\"data:\")\n\tsb.WriteString(mimeType)\n\tsb.WriteByte(',')\n\n\t// Scan for trailing characters that need to be escaped\n\ttrailingStart := n\n\tfor trailingStart > 0 {\n\t\tif c := text[trailingStart-1]; c > 0x20 || c == '\\t' || c == '\\n' || c == '\\r' {\n\t\t\tbreak\n\t\t}\n\t\ttrailingStart--\n\t}\n\n\tfor i < n {\n\t\tc, width := utf8.DecodeRuneInString(text[i:])\n\n\t\t// We can't encode invalid UTF-8 data\n\t\tif c == utf8.RuneError && width == 1 {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\t// Escape this character if needed\n\t\tif c == '\\t' || c == '\\n' || c == '\\r' || c == '#' || i >= trailingStart ||\n\t\t\t(c == '%' && i+2 < n && isHex(text[i+1]) && isHex(text[i+2])) {\n\t\t\tif runStart < i {\n\t\t\t\tsb.WriteString(text[runStart:i])\n\t\t\t}\n\t\t\tsb.WriteByte('%')\n\t\t\tsb.WriteByte(hex[c>>4])\n\t\t\tsb.WriteByte(hex[c&15])\n\t\t\trunStart = i + width\n\t\t}\n\n\t\ti += width\n\t}\n\n\tif runStart < n {\n\t\tsb.WriteString(text[runStart:])\n\t}\n\n\treturn sb.String(), true\n}\n\nfunc isHex(c byte) bool {\n\treturn c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F'\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/float.go",
    "content": "package helpers\n\nimport \"math\"\n\n// This wraps float64 math operations. Why does this exist? The Go compiler\n// contains some optimizations to take advantage of \"fused multiply and add\"\n// (FMA) instructions on certain processors. These instructions lead to\n// different output on those processors, which means esbuild's output is no\n// longer deterministic across all platforms. From the Go specification itself\n// (https://go.dev/ref/spec#Floating_point_operators):\n//\n//\tAn implementation may combine multiple floating-point operations into a\n//\tsingle fused operation, possibly across statements, and produce a result\n//\tthat differs from the value obtained by executing and rounding the\n//\tinstructions individually. An explicit floating-point type conversion\n//\trounds to the precision of the target type, preventing fusion that would\n//\tdiscard that rounding.\n//\n//\tFor instance, some architectures provide a \"fused multiply and add\" (FMA)\n//\tinstruction that computes x*y + z without rounding the intermediate result\n//\tx*y.\n//\n// Therefore we need to add explicit type conversions such as \"float64(x)\" to\n// prevent optimizations that break correctness. Rather than adding them on a\n// case-by-case basis as real correctness issues are discovered, we instead\n// preemptively force them to be added everywhere by using this wrapper type\n// for all floating-point math.\ntype F64 struct {\n\tvalue float64\n}\n\nfunc NewF64(a float64) F64 {\n\treturn F64{value: float64(a)}\n}\n\nfunc (a F64) Value() float64 {\n\treturn a.value\n}\n\nfunc (a F64) IsNaN() bool {\n\treturn math.IsNaN(a.value)\n}\n\nfunc (a F64) Neg() F64 {\n\treturn NewF64(-a.value)\n}\n\nfunc (a F64) Abs() F64 {\n\treturn NewF64(math.Abs(a.value))\n}\n\nfunc (a F64) Sin() F64 {\n\treturn NewF64(math.Sin(a.value))\n}\n\nfunc (a F64) Cos() F64 {\n\treturn NewF64(math.Cos(a.value))\n}\n\nfunc (a F64) Log2() F64 {\n\treturn NewF64(math.Log2(a.value))\n}\n\nfunc (a F64) Round() F64 {\n\treturn NewF64(math.Round(a.value))\n}\n\nfunc (a F64) Floor() F64 {\n\treturn NewF64(math.Floor(a.value))\n}\n\nfunc (a F64) Ceil() F64 {\n\treturn NewF64(math.Ceil(a.value))\n}\n\nfunc (a F64) Squared() F64 {\n\treturn a.Mul(a)\n}\n\nfunc (a F64) Cubed() F64 {\n\treturn a.Mul(a).Mul(a)\n}\n\nfunc (a F64) Sqrt() F64 {\n\treturn NewF64(math.Sqrt(a.value))\n}\n\nfunc (a F64) Cbrt() F64 {\n\treturn NewF64(math.Cbrt(a.value))\n}\n\nfunc (a F64) Add(b F64) F64 {\n\treturn NewF64(a.value + b.value)\n}\n\nfunc (a F64) AddConst(b float64) F64 {\n\treturn NewF64(a.value + b)\n}\n\nfunc (a F64) Sub(b F64) F64 {\n\treturn NewF64(a.value - b.value)\n}\n\nfunc (a F64) SubConst(b float64) F64 {\n\treturn NewF64(a.value - b)\n}\n\nfunc (a F64) Mul(b F64) F64 {\n\treturn NewF64(a.value * b.value)\n}\n\nfunc (a F64) MulConst(b float64) F64 {\n\treturn NewF64(a.value * b)\n}\n\nfunc (a F64) Div(b F64) F64 {\n\treturn NewF64(a.value / b.value)\n}\n\nfunc (a F64) DivConst(b float64) F64 {\n\treturn NewF64(a.value / b)\n}\n\nfunc (a F64) Pow(b F64) F64 {\n\treturn NewF64(math.Pow(a.value, b.value))\n}\n\nfunc (a F64) PowConst(b float64) F64 {\n\treturn NewF64(math.Pow(a.value, b))\n}\n\nfunc (a F64) Atan2(b F64) F64 {\n\treturn NewF64(math.Atan2(a.value, b.value))\n}\n\nfunc (a F64) WithSignFrom(b F64) F64 {\n\treturn NewF64(math.Copysign(a.value, b.value))\n}\n\nfunc Min2(a F64, b F64) F64 {\n\treturn NewF64(math.Min(a.value, b.value))\n}\n\nfunc Max2(a F64, b F64) F64 {\n\treturn NewF64(math.Max(a.value, b.value))\n}\n\nfunc Min3(a F64, b F64, c F64) F64 {\n\treturn NewF64(math.Min(math.Min(a.value, b.value), c.value))\n}\n\nfunc Max3(a F64, b F64, c F64) F64 {\n\treturn NewF64(math.Max(math.Max(a.value, b.value), c.value))\n}\n\nfunc Lerp(a F64, b F64, t F64) F64 {\n\treturn b.Sub(a).Mul(t).Add(a)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/glob.go",
    "content": "package helpers\n\nimport \"strings\"\n\ntype GlobWildcard uint8\n\nconst (\n\tGlobNone GlobWildcard = iota\n\tGlobAllExceptSlash\n\tGlobAllIncludingSlash\n)\n\ntype GlobPart struct {\n\tPrefix   string\n\tWildcard GlobWildcard\n}\n\n// The returned array will always be at least one element. If there are no\n// wildcards then it will be exactly one element, and if there are wildcards\n// then it will be more than one element.\nfunc ParseGlobPattern(text string) (pattern []GlobPart) {\n\tfor {\n\t\tstar := strings.IndexByte(text, '*')\n\t\tif star < 0 {\n\t\t\tpattern = append(pattern, GlobPart{Prefix: text})\n\t\t\tbreak\n\t\t}\n\t\tcount := 1\n\t\tfor star+count < len(text) && text[star+count] == '*' {\n\t\t\tcount++\n\t\t}\n\t\twildcard := GlobAllExceptSlash\n\n\t\t// Allow both \"/\" and \"\\\" as slashes\n\t\tif count > 1 && (star == 0 || text[star-1] == '/' || text[star-1] == '\\\\') &&\n\t\t\t(star+count == len(text) || text[star+count] == '/' || text[star+count] == '\\\\') {\n\t\t\twildcard = GlobAllIncludingSlash // A \"globstar\" path segment\n\t\t}\n\n\t\tpattern = append(pattern, GlobPart{Prefix: text[:star], Wildcard: wildcard})\n\t\ttext = text[star+count:]\n\t}\n\treturn\n}\n\nfunc GlobPatternToString(pattern []GlobPart) string {\n\tsb := strings.Builder{}\n\tfor _, part := range pattern {\n\t\tsb.WriteString(part.Prefix)\n\t\tswitch part.Wildcard {\n\t\tcase GlobAllExceptSlash:\n\t\t\tsb.WriteByte('*')\n\t\tcase GlobAllIncludingSlash:\n\t\t\tsb.WriteString(\"**\")\n\t\t}\n\t}\n\treturn sb.String()\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/hash.go",
    "content": "package helpers\n\n// From: http://boost.sourceforge.net/doc/html/boost/hash_combine.html\nfunc HashCombine(seed uint32, hash uint32) uint32 {\n\treturn seed ^ (hash + 0x9e3779b9 + (seed << 6) + (seed >> 2))\n}\n\nfunc HashCombineString(seed uint32, text string) uint32 {\n\tseed = HashCombine(seed, uint32(len(text)))\n\tfor _, c := range text {\n\t\tseed = HashCombine(seed, uint32(c))\n\t}\n\treturn seed\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/joiner.go",
    "content": "package helpers\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n)\n\n// This provides an efficient way to join lots of big string and byte slices\n// together. It avoids the cost of repeatedly reallocating as the buffer grows\n// by measuring exactly how big the buffer should be and then allocating once.\n// This is a measurable speedup.\ntype Joiner struct {\n\tstrings  []joinerString\n\tbytes    []joinerBytes\n\tlength   uint32\n\tlastByte byte\n}\n\ntype joinerString struct {\n\tdata   string\n\toffset uint32\n}\n\ntype joinerBytes struct {\n\tdata   []byte\n\toffset uint32\n}\n\nfunc (j *Joiner) AddString(data string) {\n\tif len(data) > 0 {\n\t\tj.lastByte = data[len(data)-1]\n\t}\n\tj.strings = append(j.strings, joinerString{data, j.length})\n\tj.length += uint32(len(data))\n}\n\nfunc (j *Joiner) AddBytes(data []byte) {\n\tif len(data) > 0 {\n\t\tj.lastByte = data[len(data)-1]\n\t}\n\tj.bytes = append(j.bytes, joinerBytes{data, j.length})\n\tj.length += uint32(len(data))\n}\n\nfunc (j *Joiner) LastByte() byte {\n\treturn j.lastByte\n}\n\nfunc (j *Joiner) Length() uint32 {\n\treturn j.length\n}\n\nfunc (j *Joiner) EnsureNewlineAtEnd() {\n\tif j.length > 0 && j.lastByte != '\\n' {\n\t\tj.AddString(\"\\n\")\n\t}\n}\n\nfunc (j *Joiner) Done() []byte {\n\tif len(j.strings) == 0 && len(j.bytes) == 1 && j.bytes[0].offset == 0 {\n\t\t// No need to allocate if there was only a single byte array written\n\t\treturn j.bytes[0].data\n\t}\n\tbuffer := make([]byte, j.length)\n\tfor _, item := range j.strings {\n\t\tcopy(buffer[item.offset:], item.data)\n\t}\n\tfor _, item := range j.bytes {\n\t\tcopy(buffer[item.offset:], item.data)\n\t}\n\treturn buffer\n}\n\nfunc (j *Joiner) Contains(s string, b []byte) bool {\n\tfor _, item := range j.strings {\n\t\tif strings.Contains(item.data, s) {\n\t\t\treturn true\n\t\t}\n\t}\n\tfor _, item := range j.bytes {\n\t\tif bytes.Contains(item.data, b) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/mime.go",
    "content": "package helpers\n\nimport \"strings\"\n\nvar builtinTypesLower = map[string]string{\n\t// Text\n\t\".css\":      \"text/css; charset=utf-8\",\n\t\".htm\":      \"text/html; charset=utf-8\",\n\t\".html\":     \"text/html; charset=utf-8\",\n\t\".js\":       \"text/javascript; charset=utf-8\",\n\t\".json\":     \"application/json; charset=utf-8\",\n\t\".markdown\": \"text/markdown; charset=utf-8\",\n\t\".md\":       \"text/markdown; charset=utf-8\",\n\t\".mjs\":      \"text/javascript; charset=utf-8\",\n\t\".xhtml\":    \"application/xhtml+xml; charset=utf-8\",\n\t\".xml\":      \"text/xml; charset=utf-8\",\n\n\t// Images\n\t\".avif\": \"image/avif\",\n\t\".gif\":  \"image/gif\",\n\t\".jpeg\": \"image/jpeg\",\n\t\".jpg\":  \"image/jpeg\",\n\t\".png\":  \"image/png\",\n\t\".svg\":  \"image/svg+xml\",\n\t\".webp\": \"image/webp\",\n\n\t// Fonts\n\t\".eot\":   \"application/vnd.ms-fontobject\",\n\t\".otf\":   \"font/otf\",\n\t\".sfnt\":  \"font/sfnt\",\n\t\".ttf\":   \"font/ttf\",\n\t\".woff\":  \"font/woff\",\n\t\".woff2\": \"font/woff2\",\n\n\t// Other\n\t\".pdf\":         \"application/pdf\",\n\t\".wasm\":        \"application/wasm\",\n\t\".webmanifest\": \"application/manifest+json\",\n}\n\n// This is used instead of Go's built-in \"mime.TypeByExtension\" function because\n// that function is broken on Windows: https://github.com/golang/go/issues/32350.\nfunc MimeTypeByExtension(ext string) string {\n\tcontentType := builtinTypesLower[ext]\n\tif contentType == \"\" {\n\t\tcontentType = builtinTypesLower[strings.ToLower(ext)]\n\t}\n\treturn contentType\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/path.go",
    "content": "package helpers\n\nimport (\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/fs\"\n)\n\nfunc IsInsideNodeModules(path string) bool {\n\tfor {\n\t\t// This is written in a platform-independent manner because it's run on\n\t\t// user-specified paths which can be arbitrary non-file-system things. So\n\t\t// for example Windows paths may end up being used on Unix or URLs may end\n\t\t// up being used on Windows. Be consistently agnostic to which kind of\n\t\t// slash is used on all platforms.\n\t\tslash := strings.LastIndexAny(path, \"/\\\\\")\n\t\tif slash == -1 {\n\t\t\treturn false\n\t\t}\n\t\tdir, base := path[:slash], path[slash+1:]\n\t\tif base == \"node_modules\" {\n\t\t\treturn true\n\t\t}\n\t\tpath = dir\n\t}\n}\n\nfunc IsFileURL(fileURL *url.URL) bool {\n\treturn fileURL.Scheme == \"file\" && (fileURL.Host == \"\" || fileURL.Host == \"localhost\") && strings.HasPrefix(fileURL.Path, \"/\")\n}\n\nfunc FileURLFromFilePath(filePath string) *url.URL {\n\t// Append a trailing slash so that resolving the URL includes the trailing\n\t// directory, and turn Windows-style paths with volumes into URL-style paths:\n\t//\n\t//   \"/Users/User/Desktop\" => \"/Users/User/Desktop/\"\n\t//   \"C:\\\\Users\\\\User\\\\Desktop\" => \"/C:/Users/User/Desktop/\"\n\t//\n\tfilePath = strings.ReplaceAll(filePath, \"\\\\\", \"/\")\n\tif !strings.HasPrefix(filePath, \"/\") {\n\t\tfilePath = \"/\" + filePath\n\t}\n\n\treturn &url.URL{Scheme: \"file\", Path: filePath}\n}\n\nfunc FilePathFromFileURL(fs fs.FS, fileURL *url.URL) string {\n\tpath := fileURL.Path\n\n\t// Convert URL-style paths back into Windows-style paths if needed:\n\t//\n\t//   \"/C:/Users/User/foo.js.map\" => \"C:\\\\Users\\\\User\\\\foo.js.map\"\n\t//\n\tif !strings.HasPrefix(fs.Cwd(), \"/\") {\n\t\tpath = strings.TrimPrefix(path, \"/\")\n\t\tpath = strings.ReplaceAll(path, \"/\", \"\\\\\") // This is needed for \"filepath.Rel()\" to work\n\t}\n\n\treturn path\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/quote.go",
    "content": "package helpers\n\nimport \"unicode/utf8\"\n\nconst hexChars = \"0123456789ABCDEF\"\nconst firstASCII = 0x20\nconst lastASCII = 0x7E\nconst firstHighSurrogate = 0xD800\nconst firstLowSurrogate = 0xDC00\nconst lastLowSurrogate = 0xDFFF\n\nfunc canPrintWithoutEscape(c rune, asciiOnly bool) bool {\n\tif c <= lastASCII {\n\t\treturn c >= firstASCII && c != '\\\\' && c != '\"'\n\t} else {\n\t\treturn !asciiOnly && c != '\\uFEFF' && (c < firstHighSurrogate || c > lastLowSurrogate)\n\t}\n}\n\nfunc QuoteSingle(text string, asciiOnly bool) []byte {\n\treturn internalQuote(text, asciiOnly, '\\'')\n}\n\nfunc QuoteForJSON(text string, asciiOnly bool) []byte {\n\treturn internalQuote(text, asciiOnly, '\"')\n}\n\nfunc internalQuote(text string, asciiOnly bool, quoteChar byte) []byte {\n\t// Estimate the required length\n\tlenEstimate := 2\n\tfor _, c := range text {\n\t\tif canPrintWithoutEscape(c, asciiOnly) {\n\t\t\tlenEstimate += utf8.RuneLen(c)\n\t\t} else {\n\t\t\tswitch c {\n\t\t\tcase '\\b', '\\f', '\\n', '\\r', '\\t', '\\\\':\n\t\t\t\tlenEstimate += 2\n\t\t\tcase '\"':\n\t\t\t\tif quoteChar == '\"' {\n\t\t\t\t\tlenEstimate += 2\n\t\t\t\t}\n\t\t\tcase '\\'':\n\t\t\t\tif quoteChar == '\\'' {\n\t\t\t\t\tlenEstimate += 2\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tif c <= 0xFFFF {\n\t\t\t\t\tlenEstimate += 6\n\t\t\t\t} else {\n\t\t\t\t\tlenEstimate += 12\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Preallocate the array\n\tbytes := make([]byte, 0, lenEstimate)\n\ti := 0\n\tn := len(text)\n\tbytes = append(bytes, quoteChar)\n\n\tfor i < n {\n\t\tc, width := DecodeWTF8Rune(text[i:])\n\n\t\t// Fast path: a run of characters that don't need escaping\n\t\tif canPrintWithoutEscape(c, asciiOnly) {\n\t\t\tstart := i\n\t\t\ti += width\n\t\t\tfor i < n {\n\t\t\t\tc, width = DecodeWTF8Rune(text[i:])\n\t\t\t\tif !canPrintWithoutEscape(c, asciiOnly) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ti += width\n\t\t\t}\n\t\t\tbytes = append(bytes, text[start:i]...)\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch c {\n\t\tcase '\\b':\n\t\t\tbytes = append(bytes, \"\\\\b\"...)\n\t\t\ti++\n\n\t\tcase '\\f':\n\t\t\tbytes = append(bytes, \"\\\\f\"...)\n\t\t\ti++\n\n\t\tcase '\\n':\n\t\t\tbytes = append(bytes, \"\\\\n\"...)\n\t\t\ti++\n\n\t\tcase '\\r':\n\t\t\tbytes = append(bytes, \"\\\\r\"...)\n\t\t\ti++\n\n\t\tcase '\\t':\n\t\t\tbytes = append(bytes, \"\\\\t\"...)\n\t\t\ti++\n\n\t\tcase '\\\\':\n\t\t\tbytes = append(bytes, \"\\\\\\\\\"...)\n\t\t\ti++\n\n\t\tcase '\"':\n\t\t\tif quoteChar == '\"' {\n\t\t\t\tbytes = append(bytes, \"\\\\\\\"\"...)\n\t\t\t} else {\n\t\t\t\tbytes = append(bytes, '\"')\n\t\t\t}\n\t\t\ti++\n\n\t\tcase '\\'':\n\t\t\tif quoteChar == '\\'' {\n\t\t\t\tbytes = append(bytes, \"\\\\'\"...)\n\t\t\t} else {\n\t\t\t\tbytes = append(bytes, '\\'')\n\t\t\t}\n\t\t\ti++\n\n\t\tdefault:\n\t\t\ti += width\n\t\t\tif c <= 0xFFFF {\n\t\t\t\tbytes = append(\n\t\t\t\t\tbytes,\n\t\t\t\t\t'\\\\', 'u', hexChars[c>>12], hexChars[(c>>8)&15], hexChars[(c>>4)&15], hexChars[c&15],\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tc -= 0x10000\n\t\t\t\tlo := firstHighSurrogate + ((c >> 10) & 0x3FF)\n\t\t\t\thi := firstLowSurrogate + (c & 0x3FF)\n\t\t\t\tbytes = append(\n\t\t\t\t\tbytes,\n\t\t\t\t\t'\\\\', 'u', hexChars[lo>>12], hexChars[(lo>>8)&15], hexChars[(lo>>4)&15], hexChars[lo&15],\n\t\t\t\t\t'\\\\', 'u', hexChars[hi>>12], hexChars[(hi>>8)&15], hexChars[(hi>>4)&15], hexChars[hi&15],\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn append(bytes, quoteChar)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/serializer.go",
    "content": "package helpers\n\nimport \"sync\"\n\n// Each call to \"Enter(i)\" doesn't start until \"Leave(i-1)\" is called\ntype Serializer struct {\n\tflags []sync.WaitGroup\n}\n\nfunc MakeSerializer(count int) Serializer {\n\tflags := make([]sync.WaitGroup, count)\n\tfor i := 0; i < count; i++ {\n\t\tflags[i].Add(1)\n\t}\n\treturn Serializer{flags: flags}\n}\n\nfunc (s *Serializer) Enter(i int) {\n\tif i > 0 {\n\t\ts.flags[i-1].Wait()\n\t}\n}\n\nfunc (s *Serializer) Leave(i int) {\n\ts.flags[i].Done()\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/stack.go",
    "content": "package helpers\n\nimport (\n\t\"runtime/debug\"\n\t\"strings\"\n)\n\nfunc PrettyPrintedStack() string {\n\tlines := strings.Split(strings.TrimSpace(string(debug.Stack())), \"\\n\")\n\n\t// Strip the first \"goroutine\" line\n\tif len(lines) > 0 {\n\t\tif first := lines[0]; strings.HasPrefix(first, \"goroutine \") && strings.HasSuffix(first, \":\") {\n\t\t\tlines = lines[1:]\n\t\t}\n\t}\n\n\tsb := strings.Builder{}\n\n\tfor _, line := range lines {\n\t\t// Indented lines are source locations\n\t\tif strings.HasPrefix(line, \"\\t\") {\n\t\t\tline = line[1:]\n\t\t\tline = strings.TrimPrefix(line, \"github.com/evanw/esbuild/\")\n\t\t\tif offset := strings.LastIndex(line, \" +0x\"); offset != -1 {\n\t\t\t\tline = line[:offset]\n\t\t\t}\n\t\t\tsb.WriteString(\" (\")\n\t\t\tsb.WriteString(line)\n\t\t\tsb.WriteString(\")\")\n\t\t\tcontinue\n\t\t}\n\n\t\t// Other lines are function calls\n\t\tif sb.Len() > 0 {\n\t\t\tsb.WriteByte('\\n')\n\t\t}\n\t\tif strings.HasSuffix(line, \")\") {\n\t\t\tif paren := strings.LastIndexByte(line, '('); paren != -1 {\n\t\t\t\tline = line[:paren]\n\t\t\t}\n\t\t}\n\t\tif slash := strings.LastIndexByte(line, '/'); slash != -1 {\n\t\t\tline = line[slash+1:]\n\t\t}\n\t\tsb.WriteString(line)\n\t}\n\n\treturn sb.String()\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/strings.go",
    "content": "package helpers\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc StringArraysEqual(a []string, b []string) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, x := range a {\n\t\tif x != b[i] {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc StringArrayArraysEqual(a [][]string, b [][]string) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor i, x := range a {\n\t\tif !StringArraysEqual(x, b[i]) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\nfunc StringArrayToQuotedCommaSeparatedString(a []string) string {\n\tsb := strings.Builder{}\n\tfor i, str := range a {\n\t\tif i > 0 {\n\t\t\tsb.WriteString(\", \")\n\t\t}\n\t\tsb.WriteString(fmt.Sprintf(\"%q\", str))\n\t}\n\treturn sb.String()\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/typos.go",
    "content": "package helpers\n\nimport \"unicode/utf8\"\n\ntype TypoDetector struct {\n\toneCharTypos map[string]string\n}\n\nfunc MakeTypoDetector(valid []string) TypoDetector {\n\tdetector := TypoDetector{oneCharTypos: make(map[string]string)}\n\n\t// Add all combinations of each valid word with one character missing\n\tfor _, correct := range valid {\n\t\tif len(correct) > 3 {\n\t\t\tfor i, ch := range correct {\n\t\t\t\tdetector.oneCharTypos[correct[:i]+correct[i+utf8.RuneLen(ch):]] = correct\n\t\t\t}\n\t\t}\n\t}\n\n\treturn detector\n}\n\nfunc (detector TypoDetector) MaybeCorrectTypo(typo string) (string, bool) {\n\t// Check for a single deleted character\n\tif corrected, ok := detector.oneCharTypos[typo]; ok {\n\t\treturn corrected, true\n\t}\n\n\t// Check for a single misplaced character\n\tfor i, ch := range typo {\n\t\tif corrected, ok := detector.oneCharTypos[typo[:i]+typo[i+utf8.RuneLen(ch):]]; ok {\n\t\t\treturn corrected, true\n\t\t}\n\t}\n\n\treturn \"\", false\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/helpers/waitgroup.go",
    "content": "package helpers\n\nimport \"sync/atomic\"\n\n// Go's \"sync.WaitGroup\" is not thread-safe. Specifically it's not safe to call\n// \"Add\" concurrently with \"Wait\", which is problematic because we have a case\n// where we would like to do that.\n//\n// This is a simple alternative implementation of \"sync.WaitGroup\" that is\n// thread-safe and that works for our purposes. We don't need to worry about\n// multiple waiters so the implementation can be very simple.\ntype ThreadSafeWaitGroup struct {\n\tcounter int32\n\tchannel chan struct{}\n}\n\nfunc MakeThreadSafeWaitGroup() *ThreadSafeWaitGroup {\n\treturn &ThreadSafeWaitGroup{\n\t\tchannel: make(chan struct{}, 1),\n\t}\n}\n\nfunc (wg *ThreadSafeWaitGroup) Add(delta int32) {\n\tif counter := atomic.AddInt32(&wg.counter, delta); counter == 0 {\n\t\twg.channel <- struct{}{}\n\t} else if counter < 0 {\n\t\tpanic(\"sync: negative WaitGroup counter\")\n\t}\n}\n\nfunc (wg *ThreadSafeWaitGroup) Done() {\n\twg.Add(-1)\n}\n\nfunc (wg *ThreadSafeWaitGroup) Wait() {\n\t<-wg.channel\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/js_ast/js_ast.go",
    "content": "package js_ast\n\nimport (\n\t\"strconv\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\n// Every module (i.e. file) is parsed into a separate AST data structure. For\n// efficiency, the parser also resolves all scopes and binds all symbols in the\n// tree.\n//\n// Identifiers in the tree are referenced by a Ref, which is a pointer into the\n// symbol table for the file. The symbol table is stored as a top-level field\n// in the AST so it can be accessed without traversing the tree. For example,\n// a renaming pass can iterate over the symbol table without touching the tree.\n//\n// Parse trees are intended to be immutable. That makes it easy to build an\n// incremental compiler with a \"watch\" mode that can avoid re-parsing files\n// that have already been parsed. Any passes that operate on an AST after it\n// has been parsed should create a copy of the mutated parts of the tree\n// instead of mutating the original tree.\n\ntype L uint8\n\n// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence\nconst (\n\tLLowest L = iota\n\tLComma\n\tLSpread\n\tLYield\n\tLAssign\n\tLConditional\n\tLNullishCoalescing\n\tLLogicalOr\n\tLLogicalAnd\n\tLBitwiseOr\n\tLBitwiseXor\n\tLBitwiseAnd\n\tLEquals\n\tLCompare\n\tLShift\n\tLAdd\n\tLMultiply\n\tLExponentiation\n\tLPrefix\n\tLPostfix\n\tLNew\n\tLCall\n\tLMember\n)\n\ntype OpCode uint8\n\nfunc (op OpCode) IsPrefix() bool {\n\treturn op < UnOpPostDec\n}\n\nfunc (op OpCode) UnaryAssignTarget() AssignTarget {\n\tif op >= UnOpPreDec && op <= UnOpPostInc {\n\t\treturn AssignTargetUpdate\n\t}\n\treturn AssignTargetNone\n}\n\nfunc (op OpCode) IsLeftAssociative() bool {\n\treturn op >= BinOpAdd && op < BinOpComma && op != BinOpPow\n}\n\nfunc (op OpCode) IsRightAssociative() bool {\n\treturn op >= BinOpAssign || op == BinOpPow\n}\n\nfunc (op OpCode) BinaryAssignTarget() AssignTarget {\n\tif op == BinOpAssign {\n\t\treturn AssignTargetReplace\n\t}\n\tif op > BinOpAssign {\n\t\treturn AssignTargetUpdate\n\t}\n\treturn AssignTargetNone\n}\n\nfunc (op OpCode) IsShortCircuit() bool {\n\tswitch op {\n\tcase BinOpLogicalOr, BinOpLogicalOrAssign,\n\t\tBinOpLogicalAnd, BinOpLogicalAndAssign,\n\t\tBinOpNullishCoalescing, BinOpNullishCoalescingAssign:\n\t\treturn true\n\t}\n\treturn false\n}\n\ntype AssignTarget uint8\n\nconst (\n\tAssignTargetNone    AssignTarget = iota\n\tAssignTargetReplace              // \"a = b\"\n\tAssignTargetUpdate               // \"a += b\"\n)\n\n// If you add a new token, remember to add it to \"OpTable\" too\nconst (\n\t// Prefix\n\tUnOpPos OpCode = iota\n\tUnOpNeg\n\tUnOpCpl\n\tUnOpNot\n\tUnOpVoid\n\tUnOpTypeof\n\tUnOpDelete\n\n\t// Prefix update\n\tUnOpPreDec\n\tUnOpPreInc\n\n\t// Postfix update\n\tUnOpPostDec\n\tUnOpPostInc\n\n\t// Left-associative\n\tBinOpAdd\n\tBinOpSub\n\tBinOpMul\n\tBinOpDiv\n\tBinOpRem\n\tBinOpPow\n\tBinOpLt\n\tBinOpLe\n\tBinOpGt\n\tBinOpGe\n\tBinOpIn\n\tBinOpInstanceof\n\tBinOpShl\n\tBinOpShr\n\tBinOpUShr\n\tBinOpLooseEq\n\tBinOpLooseNe\n\tBinOpStrictEq\n\tBinOpStrictNe\n\tBinOpNullishCoalescing\n\tBinOpLogicalOr\n\tBinOpLogicalAnd\n\tBinOpBitwiseOr\n\tBinOpBitwiseAnd\n\tBinOpBitwiseXor\n\n\t// Non-associative\n\tBinOpComma\n\n\t// Right-associative\n\tBinOpAssign\n\tBinOpAddAssign\n\tBinOpSubAssign\n\tBinOpMulAssign\n\tBinOpDivAssign\n\tBinOpRemAssign\n\tBinOpPowAssign\n\tBinOpShlAssign\n\tBinOpShrAssign\n\tBinOpUShrAssign\n\tBinOpBitwiseOrAssign\n\tBinOpBitwiseAndAssign\n\tBinOpBitwiseXorAssign\n\tBinOpNullishCoalescingAssign\n\tBinOpLogicalOrAssign\n\tBinOpLogicalAndAssign\n)\n\ntype OpTableEntry struct {\n\tText      string\n\tLevel     L\n\tIsKeyword bool\n}\n\nvar OpTable = []OpTableEntry{\n\t// Prefix\n\t{\"+\", LPrefix, false},\n\t{\"-\", LPrefix, false},\n\t{\"~\", LPrefix, false},\n\t{\"!\", LPrefix, false},\n\t{\"void\", LPrefix, true},\n\t{\"typeof\", LPrefix, true},\n\t{\"delete\", LPrefix, true},\n\n\t// Prefix update\n\t{\"--\", LPrefix, false},\n\t{\"++\", LPrefix, false},\n\n\t// Postfix update\n\t{\"--\", LPostfix, false},\n\t{\"++\", LPostfix, false},\n\n\t// Left-associative\n\t{\"+\", LAdd, false},\n\t{\"-\", LAdd, false},\n\t{\"*\", LMultiply, false},\n\t{\"/\", LMultiply, false},\n\t{\"%\", LMultiply, false},\n\t{\"**\", LExponentiation, false}, // Right-associative\n\t{\"<\", LCompare, false},\n\t{\"<=\", LCompare, false},\n\t{\">\", LCompare, false},\n\t{\">=\", LCompare, false},\n\t{\"in\", LCompare, true},\n\t{\"instanceof\", LCompare, true},\n\t{\"<<\", LShift, false},\n\t{\">>\", LShift, false},\n\t{\">>>\", LShift, false},\n\t{\"==\", LEquals, false},\n\t{\"!=\", LEquals, false},\n\t{\"===\", LEquals, false},\n\t{\"!==\", LEquals, false},\n\t{\"??\", LNullishCoalescing, false},\n\t{\"||\", LLogicalOr, false},\n\t{\"&&\", LLogicalAnd, false},\n\t{\"|\", LBitwiseOr, false},\n\t{\"&\", LBitwiseAnd, false},\n\t{\"^\", LBitwiseXor, false},\n\n\t// Non-associative\n\t{\",\", LComma, false},\n\n\t// Right-associative\n\t{\"=\", LAssign, false},\n\t{\"+=\", LAssign, false},\n\t{\"-=\", LAssign, false},\n\t{\"*=\", LAssign, false},\n\t{\"/=\", LAssign, false},\n\t{\"%=\", LAssign, false},\n\t{\"**=\", LAssign, false},\n\t{\"<<=\", LAssign, false},\n\t{\">>=\", LAssign, false},\n\t{\">>>=\", LAssign, false},\n\t{\"|=\", LAssign, false},\n\t{\"&=\", LAssign, false},\n\t{\"^=\", LAssign, false},\n\t{\"??=\", LAssign, false},\n\t{\"||=\", LAssign, false},\n\t{\"&&=\", LAssign, false},\n}\n\ntype Decorator struct {\n\tValue            Expr\n\tAtLoc            logger.Loc\n\tOmitNewlineAfter bool\n}\n\ntype PropertyKind uint8\n\nconst (\n\tPropertyField PropertyKind = iota\n\tPropertyMethod\n\tPropertyGetter\n\tPropertySetter\n\tPropertyAutoAccessor\n\tPropertySpread\n\tPropertyDeclareOrAbstract\n\tPropertyClassStaticBlock\n)\n\n// This returns true if and only if this property matches the \"MethodDefinition\"\n// grammar from the specification. That means it's one of the following forms:\n//\n//\tfoo() {}\n//\t*foo() {}\n//\tasync foo() {}\n//\tasync *foo() {}\n//\tget foo() {}\n//\tset foo(_) {}\n//\n// If this returns true, the \"ValueOrNil\" field of the property is always an\n// \"EFunction\" expression and it is always printed as a method.\nfunc (kind PropertyKind) IsMethodDefinition() bool {\n\treturn kind == PropertyMethod || kind == PropertyGetter || kind == PropertySetter\n}\n\ntype ClassStaticBlock struct {\n\tBlock SBlock\n\tLoc   logger.Loc\n}\n\ntype PropertyFlags uint8\n\nconst (\n\tPropertyIsComputed PropertyFlags = 1 << iota\n\tPropertyIsStatic\n\tPropertyWasShorthand\n\tPropertyPreferQuotedKey\n)\n\nfunc (flags PropertyFlags) Has(flag PropertyFlags) bool {\n\treturn (flags & flag) != 0\n}\n\ntype Property struct {\n\tClassStaticBlock *ClassStaticBlock\n\n\tKey Expr\n\n\t// This is omitted for class fields\n\tValueOrNil Expr\n\n\t// This is used when parsing a pattern that uses default values:\n\t//\n\t//   [a = 1] = [];\n\t//   ({a = 1} = {});\n\t//\n\t// It's also used for class fields:\n\t//\n\t//   class Foo { a = 1 }\n\t//\n\tInitializerOrNil Expr\n\n\tDecorators []Decorator\n\n\tLoc             logger.Loc\n\tCloseBracketLoc logger.Loc\n\tKind            PropertyKind\n\tFlags           PropertyFlags\n}\n\ntype PropertyBinding struct {\n\tKey               Expr\n\tValue             Binding\n\tDefaultValueOrNil Expr\n\tLoc               logger.Loc\n\tCloseBracketLoc   logger.Loc\n\tIsComputed        bool\n\tIsSpread          bool\n\tPreferQuotedKey   bool\n}\n\ntype Arg struct {\n\tBinding      Binding\n\tDefaultOrNil Expr\n\tDecorators   []Decorator\n\n\t// \"constructor(public x: boolean) {}\"\n\tIsTypeScriptCtorField bool\n}\n\ntype Fn struct {\n\tName         *ast.LocRef\n\tArgs         []Arg\n\tBody         FnBody\n\tArgumentsRef ast.Ref\n\tOpenParenLoc logger.Loc\n\n\tIsAsync     bool\n\tIsGenerator bool\n\tHasRestArg  bool\n\tHasIfScope  bool\n\n\t// See: https://github.com/rollup/rollup/pull/5024\n\tHasNoSideEffectsComment bool\n\n\t// This is true if the function is a method\n\tIsUniqueFormalParameters bool\n}\n\ntype FnBody struct {\n\tBlock SBlock\n\tLoc   logger.Loc\n}\n\ntype Class struct {\n\tDecorators    []Decorator\n\tName          *ast.LocRef\n\tExtendsOrNil  Expr\n\tProperties    []Property\n\tClassKeyword  logger.Range\n\tBodyLoc       logger.Loc\n\tCloseBraceLoc logger.Loc\n\n\t// If true, JavaScript decorators (i.e. not TypeScript experimental\n\t// decorators) should be lowered. This is the case either if JavaScript\n\t// decorators are not supported in the configured target environment, or\n\t// if \"useDefineForClassFields\" is set to false and this class has\n\t// decorators on it. Note that this flag is not necessarily set to true if\n\t// \"useDefineForClassFields\" is false and a class has an \"accessor\" even\n\t// though the accessor feature comes from the decorator specification.\n\tShouldLowerStandardDecorators bool\n\n\t// If true, property field initializers cannot be assumed to have no side\n\t// effects. For example:\n\t//\n\t//   class Foo {\n\t//     static set foo(x) { importantSideEffect(x) }\n\t//   }\n\t//   class Bar extends Foo {\n\t//     foo = 1\n\t//   }\n\t//\n\t// This happens in TypeScript when \"useDefineForClassFields\" is disabled\n\t// because TypeScript (and esbuild) transforms the above class into this:\n\t//\n\t//   class Foo {\n\t//     static set foo(x) { importantSideEffect(x); }\n\t//   }\n\t//   class Bar extends Foo {\n\t//   }\n\t//   Bar.foo = 1;\n\t//\n\tUseDefineForClassFields bool\n}\n\ntype ArrayBinding struct {\n\tBinding           Binding\n\tDefaultValueOrNil Expr\n\tLoc               logger.Loc\n}\n\ntype Binding struct {\n\tData B\n\tLoc  logger.Loc\n}\n\n// This interface is never called. Its purpose is to encode a variant type in\n// Go's type system.\ntype B interface{ isBinding() }\n\nfunc (*BMissing) isBinding()    {}\nfunc (*BIdentifier) isBinding() {}\nfunc (*BArray) isBinding()      {}\nfunc (*BObject) isBinding()     {}\n\ntype BMissing struct{}\n\ntype BIdentifier struct{ Ref ast.Ref }\n\ntype BArray struct {\n\tItems           []ArrayBinding\n\tCloseBracketLoc logger.Loc\n\tHasSpread       bool\n\tIsSingleLine    bool\n}\n\ntype BObject struct {\n\tProperties    []PropertyBinding\n\tCloseBraceLoc logger.Loc\n\tIsSingleLine  bool\n}\n\ntype Expr struct {\n\tData E\n\tLoc  logger.Loc\n}\n\n// This interface is never called. Its purpose is to encode a variant type in\n// Go's type system.\ntype E interface{ isExpr() }\n\nfunc (*EArray) isExpr()                {}\nfunc (*EUnary) isExpr()                {}\nfunc (*EBinary) isExpr()               {}\nfunc (*EBoolean) isExpr()              {}\nfunc (*ESuper) isExpr()                {}\nfunc (*ENull) isExpr()                 {}\nfunc (*EUndefined) isExpr()            {}\nfunc (*EThis) isExpr()                 {}\nfunc (*ENew) isExpr()                  {}\nfunc (*ENewTarget) isExpr()            {}\nfunc (*EImportMeta) isExpr()           {}\nfunc (*ECall) isExpr()                 {}\nfunc (*EDot) isExpr()                  {}\nfunc (*EIndex) isExpr()                {}\nfunc (*EArrow) isExpr()                {}\nfunc (*EFunction) isExpr()             {}\nfunc (*EClass) isExpr()                {}\nfunc (*EIdentifier) isExpr()           {}\nfunc (*EImportIdentifier) isExpr()     {}\nfunc (*EPrivateIdentifier) isExpr()    {}\nfunc (*ENameOfSymbol) isExpr()         {}\nfunc (*EJSXElement) isExpr()           {}\nfunc (*EJSXText) isExpr()              {}\nfunc (*EMissing) isExpr()              {}\nfunc (*ENumber) isExpr()               {}\nfunc (*EBigInt) isExpr()               {}\nfunc (*EObject) isExpr()               {}\nfunc (*ESpread) isExpr()               {}\nfunc (*EString) isExpr()               {}\nfunc (*ETemplate) isExpr()             {}\nfunc (*ERegExp) isExpr()               {}\nfunc (*EInlinedEnum) isExpr()          {}\nfunc (*EAnnotation) isExpr()           {}\nfunc (*EAwait) isExpr()                {}\nfunc (*EYield) isExpr()                {}\nfunc (*EIf) isExpr()                   {}\nfunc (*ERequireString) isExpr()        {}\nfunc (*ERequireResolveString) isExpr() {}\nfunc (*EImportString) isExpr()         {}\nfunc (*EImportCall) isExpr()           {}\n\ntype EArray struct {\n\tItems            []Expr\n\tCommaAfterSpread logger.Loc\n\tCloseBracketLoc  logger.Loc\n\tIsSingleLine     bool\n\tIsParenthesized  bool\n}\n\ntype EUnary struct {\n\tValue Expr\n\tOp    OpCode\n\n\t// The expression \"typeof (0, x)\" must not become \"typeof x\" if \"x\"\n\t// is unbound because that could suppress a ReferenceError from \"x\".\n\t//\n\t// Also if we know a typeof operator was originally an identifier, then\n\t// we know that this typeof operator always has no side effects (even if\n\t// we consider the identifier by itself to have a side effect).\n\t//\n\t// Note that there *is* actually a case where \"typeof x\" can throw an error:\n\t// when \"x\" is being referenced inside of its TDZ (temporal dead zone). TDZ\n\t// checks are not yet handled correctly by esbuild, so this possibility is\n\t// currently ignored.\n\tWasOriginallyTypeofIdentifier bool\n\n\t// Similarly the expression \"delete (0, x)\" must not become \"delete x\"\n\t// because that syntax is invalid in strict mode. We also need to make sure\n\t// we don't accidentally change the return value:\n\t//\n\t//   Returns false:\n\t//     \"var a; delete (a)\"\n\t//     \"var a = Object.freeze({b: 1}); delete (a.b)\"\n\t//     \"var a = Object.freeze({b: 1}); delete (a?.b)\"\n\t//     \"var a = Object.freeze({b: 1}); delete (a['b'])\"\n\t//     \"var a = Object.freeze({b: 1}); delete (a?.['b'])\"\n\t//\n\t//   Returns true:\n\t//     \"var a; delete (0, a)\"\n\t//     \"var a = Object.freeze({b: 1}); delete (true && a.b)\"\n\t//     \"var a = Object.freeze({b: 1}); delete (false || a?.b)\"\n\t//     \"var a = Object.freeze({b: 1}); delete (null ?? a?.['b'])\"\n\t//     \"var a = Object.freeze({b: 1}); delete (true ? a['b'] : a['b'])\"\n\t//\n\tWasOriginallyDeleteOfIdentifierOrPropertyAccess bool\n}\n\ntype EBinary struct {\n\tLeft  Expr\n\tRight Expr\n\tOp    OpCode\n}\n\ntype EBoolean struct{ Value bool }\n\ntype EMissing struct{}\n\ntype ESuper struct{}\n\ntype ENull struct{}\n\ntype EUndefined struct{}\n\ntype EThis struct{}\n\ntype ENewTarget struct {\n\tRange logger.Range\n}\n\ntype EImportMeta struct {\n\tRangeLen int32\n}\n\n// These help reduce unnecessary memory allocations\nvar BMissingShared = &BMissing{}\nvar EMissingShared = &EMissing{}\nvar ENullShared = &ENull{}\nvar ESuperShared = &ESuper{}\nvar EThisShared = &EThis{}\nvar EUndefinedShared = &EUndefined{}\nvar SDebuggerShared = &SDebugger{}\nvar SEmptyShared = &SEmpty{}\nvar STypeScriptShared = &STypeScript{}\nvar STypeScriptSharedWasDeclareClass = &STypeScript{WasDeclareClass: true}\n\ntype ENew struct {\n\tTarget Expr\n\tArgs   []Expr\n\n\tCloseParenLoc logger.Loc\n\tIsMultiLine   bool\n\n\t// True if there is a comment containing \"@__PURE__\" or \"#__PURE__\" preceding\n\t// this call expression. See the comment inside ECall for more details.\n\tCanBeUnwrappedIfUnused bool\n}\n\ntype CallKind uint8\n\nconst (\n\tNormalCall CallKind = iota\n\tDirectEval\n\tTargetWasOriginallyPropertyAccess\n)\n\ntype OptionalChain uint8\n\nconst (\n\t// \"a.b\"\n\tOptionalChainNone OptionalChain = iota\n\n\t// \"a?.b\"\n\tOptionalChainStart\n\n\t// \"a?.b.c\" => \".c\" is OptionalChainContinue\n\t// \"(a?.b).c\" => \".c\" is OptionalChainNone\n\tOptionalChainContinue\n)\n\ntype ECall struct {\n\tTarget        Expr\n\tArgs          []Expr\n\tCloseParenLoc logger.Loc\n\tOptionalChain OptionalChain\n\tKind          CallKind\n\tIsMultiLine   bool\n\n\t// True if there is a comment containing \"@__PURE__\" or \"#__PURE__\" preceding\n\t// this call expression. This is an annotation used for tree shaking, and\n\t// means that the call can be removed if it's unused. It does not mean the\n\t// call is pure (e.g. it may still return something different if called twice).\n\t//\n\t// Note that the arguments are not considered to be part of the call. If the\n\t// call itself is removed due to this annotation, the arguments must remain\n\t// if they have side effects.\n\tCanBeUnwrappedIfUnused bool\n}\n\nfunc (a *ECall) HasSameFlagsAs(b *ECall) bool {\n\treturn a.OptionalChain == b.OptionalChain &&\n\t\ta.Kind == b.Kind &&\n\t\ta.CanBeUnwrappedIfUnused == b.CanBeUnwrappedIfUnused\n}\n\ntype EDot struct {\n\tTarget        Expr\n\tName          string\n\tNameLoc       logger.Loc\n\tOptionalChain OptionalChain\n\n\t// If true, this property access is known to be free of side-effects. That\n\t// means it can be removed if the resulting value isn't used.\n\tCanBeRemovedIfUnused bool\n\n\t// If true, this property access is a function that, when called, can be\n\t// unwrapped if the resulting value is unused. Unwrapping means discarding\n\t// the call target but keeping any arguments with side effects.\n\tCallCanBeUnwrappedIfUnused bool\n\n\t// Symbol values are known to not have side effects when used as property\n\t// names in class declarations and object literals.\n\tIsSymbolInstance bool\n}\n\nfunc (a *EDot) HasSameFlagsAs(b *EDot) bool {\n\treturn a.OptionalChain == b.OptionalChain &&\n\t\ta.CanBeRemovedIfUnused == b.CanBeRemovedIfUnused &&\n\t\ta.CallCanBeUnwrappedIfUnused == b.CallCanBeUnwrappedIfUnused &&\n\t\ta.IsSymbolInstance == b.IsSymbolInstance\n}\n\ntype EIndex struct {\n\tTarget          Expr\n\tIndex           Expr\n\tCloseBracketLoc logger.Loc\n\tOptionalChain   OptionalChain\n\n\t// If true, this property access is known to be free of side-effects. That\n\t// means it can be removed if the resulting value isn't used.\n\tCanBeRemovedIfUnused bool\n\n\t// If true, this property access is a function that, when called, can be\n\t// unwrapped if the resulting value is unused. Unwrapping means discarding\n\t// the call target but keeping any arguments with side effects.\n\tCallCanBeUnwrappedIfUnused bool\n\n\t// Symbol values are known to not have side effects when used as property\n\t// names in class declarations and object literals.\n\tIsSymbolInstance bool\n}\n\nfunc (a *EIndex) HasSameFlagsAs(b *EIndex) bool {\n\treturn a.OptionalChain == b.OptionalChain &&\n\t\ta.CanBeRemovedIfUnused == b.CanBeRemovedIfUnused &&\n\t\ta.CallCanBeUnwrappedIfUnused == b.CallCanBeUnwrappedIfUnused &&\n\t\ta.IsSymbolInstance == b.IsSymbolInstance\n}\n\ntype EArrow struct {\n\tArgs []Arg\n\tBody FnBody\n\n\tIsAsync    bool\n\tHasRestArg bool\n\tPreferExpr bool // Use shorthand if true and \"Body\" is a single return statement\n\n\t// V8 uses parentheses as an optimization hint: https://v8.dev/blog/preparser#pife\n\tIsParenthesized bool\n\n\t// See: https://github.com/rollup/rollup/pull/5024\n\tHasNoSideEffectsComment bool\n}\n\ntype EFunction struct {\n\tFn Fn\n\n\t// V8 uses parentheses as an optimization hint: https://v8.dev/blog/preparser#pife\n\tIsParenthesized bool\n}\n\ntype EClass struct{ Class Class }\n\ntype EIdentifier struct {\n\tRef ast.Ref\n\n\t// If we're inside a \"with\" statement, this identifier may be a property\n\t// access. In that case it would be incorrect to remove this identifier since\n\t// the property access may be a getter or setter with side effects.\n\tMustKeepDueToWithStmt bool\n\n\t// If true, this identifier is known to not have a side effect (i.e. to not\n\t// throw an exception) when referenced. If false, this identifier may or may\n\t// not have side effects when referenced. This is used to allow the removal\n\t// of known globals such as \"Object\" if they aren't used.\n\tCanBeRemovedIfUnused bool\n\n\t// If true, this identifier represents a function that, when called, can be\n\t// unwrapped if the resulting value is unused. Unwrapping means discarding\n\t// the call target but keeping any arguments with side effects.\n\tCallCanBeUnwrappedIfUnused bool\n}\n\n// This is similar to an EIdentifier but it represents a reference to an ES6\n// import item.\n//\n// Depending on how the code is linked, the file containing this EImportIdentifier\n// may or may not be in the same module group as the file it was imported from.\n//\n// If it's the same module group than we can just merge the import item symbol\n// with the corresponding symbol that was imported, effectively renaming them\n// to be the same thing and statically binding them together.\n//\n// But if it's a different module group, then the import must be dynamically\n// evaluated using a property access off the corresponding namespace symbol,\n// which represents the result of a require() call.\n//\n// It's stored as a separate type so it's not easy to confuse with a plain\n// identifier. For example, it'd be bad if code trying to convert \"{x: x}\" into\n// \"{x}\" shorthand syntax wasn't aware that the \"x\" in this case is actually\n// \"{x: importedNamespace.x}\". This separate type forces code to opt-in to\n// doing this instead of opt-out.\ntype EImportIdentifier struct {\n\tRef             ast.Ref\n\tPreferQuotedKey bool\n\n\t// If true, this was originally an identifier expression such as \"foo\". If\n\t// false, this could potentially have been a member access expression such\n\t// as \"ns.foo\" off of an imported namespace object.\n\tWasOriginallyIdentifier bool\n}\n\n// This is similar to EIdentifier but it represents class-private fields and\n// methods. It can be used where computed properties can be used, such as\n// EIndex and Property.\ntype EPrivateIdentifier struct {\n\tRef ast.Ref\n}\n\n// This represents an internal property name that can be mangled. The symbol\n// referenced by this expression should be a \"SymbolMangledProp\" symbol.\ntype ENameOfSymbol struct {\n\tRef                   ast.Ref\n\tHasPropertyKeyComment bool // If true, a preceding comment contains \"@__KEY__\"\n}\n\ntype EJSXElement struct {\n\tTagOrNil   Expr\n\tProperties []Property\n\n\t// Note: This array may contain nil entries. Be careful about nil entries\n\t// when iterating over this array.\n\t//\n\t// Each nil entry corresponds to the \"JSXChildExpression_opt\" part of the\n\t// grammar (https://facebook.github.io/jsx/#prod-JSXChild):\n\t//\n\t//   JSXChild :\n\t//       JSXText\n\t//       JSXElement\n\t//       JSXFragment\n\t//       { JSXChildExpression_opt }\n\t//\n\t// This is the \"{}\" part in \"<a>{}</a>\". We allow this because some people\n\t// put comments there and then expect to be able to process them from\n\t// esbuild's output. These absent AST nodes are completely omitted when\n\t// JSX is transformed to JS. They are only present when JSX preservation is\n\t// enabled.\n\tNullableChildren []Expr\n\n\tCloseLoc        logger.Loc\n\tIsTagSingleLine bool\n}\n\n// The JSX specification doesn't say how JSX text is supposed to be interpreted\n// so our \"preserve\" JSX transform should reproduce the original source code\n// verbatim. One reason why this matters is because there is no canonical way\n// to interpret JSX text (Babel and TypeScript differ in what newlines mean).\n// Another reason is that some people want to do custom things such as this:\n// https://github.com/evanw/esbuild/issues/3605\ntype EJSXText struct {\n\tRaw string\n}\n\ntype ENumber struct{ Value float64 }\n\ntype EBigInt struct{ Value string }\n\ntype EObject struct {\n\tProperties       []Property\n\tCommaAfterSpread logger.Loc\n\tCloseBraceLoc    logger.Loc\n\tIsSingleLine     bool\n\tIsParenthesized  bool\n}\n\ntype ESpread struct{ Value Expr }\n\n// This is used for both strings and no-substitution template literals to reduce\n// the number of cases that need to be checked for string optimization code\ntype EString struct {\n\tValue                 []uint16\n\tLegacyOctalLoc        logger.Loc\n\tPreferTemplate        bool\n\tHasPropertyKeyComment bool // If true, a preceding comment contains \"@__KEY__\"\n\tContainsUniqueKey     bool // If true, this string must not be wrapped\n}\n\ntype TemplatePart struct {\n\tValue      Expr\n\tTailRaw    string   // Only use when \"TagOrNil\" is not nil\n\tTailCooked []uint16 // Only use when \"TagOrNil\" is nil\n\tTailLoc    logger.Loc\n}\n\ntype ETemplate struct {\n\tTagOrNil       Expr\n\tHeadRaw        string   // Only use when \"TagOrNil\" is not nil\n\tHeadCooked     []uint16 // Only use when \"TagOrNil\" is nil\n\tParts          []TemplatePart\n\tHeadLoc        logger.Loc\n\tLegacyOctalLoc logger.Loc\n\n\t// True if this is a tagged template literal with a comment that indicates\n\t// this function call can be removed if the result is unused. Note that the\n\t// arguments are not considered to be part of the call. If the call itself\n\t// is removed due to this annotation, the arguments must remain if they have\n\t// side effects (including the string conversions).\n\tCanBeUnwrappedIfUnused bool\n\n\t// If the tag is present, it is expected to be a function and is called. If\n\t// the tag is a syntactic property access, then the value for \"this\" in the\n\t// function call is the object whose property was accessed (e.g. in \"a.b``\"\n\t// the value for \"this\" in \"a.b\" is \"a\"). We need to ensure that if \"a``\"\n\t// ever becomes \"b.c``\" later on due to optimizations, it is written as\n\t// \"(0, b.c)``\" to avoid a behavior change.\n\tTagWasOriginallyPropertyAccess bool\n}\n\ntype ERegExp struct{ Value string }\n\ntype EInlinedEnum struct {\n\tValue   Expr\n\tComment string\n}\n\ntype AnnotationFlags uint8\n\nconst (\n\t// This is sort of like an IIFE with a \"/* @__PURE__ */\" comment except it's an\n\t// inline annotation on an expression itself without the nested scope. Sometimes\n\t// we can't easily introduce a new scope (e.g. if the expression uses \"await\").\n\tCanBeRemovedIfUnusedFlag AnnotationFlags = 1 << iota\n)\n\nfunc (flags AnnotationFlags) Has(flag AnnotationFlags) bool {\n\treturn (flags & flag) != 0\n}\n\ntype EAnnotation struct {\n\tValue Expr\n\tFlags AnnotationFlags\n}\n\ntype EAwait struct {\n\tValue Expr\n}\n\ntype EYield struct {\n\tValueOrNil Expr\n\tIsStar     bool\n}\n\ntype EIf struct {\n\tTest Expr\n\tYes  Expr\n\tNo   Expr\n}\n\ntype ERequireString struct {\n\tImportRecordIndex uint32\n\tCloseParenLoc     logger.Loc\n}\n\ntype ERequireResolveString struct {\n\tImportRecordIndex uint32\n\tCloseParenLoc     logger.Loc\n}\n\ntype EImportString struct {\n\tImportRecordIndex uint32\n\tCloseParenLoc     logger.Loc\n}\n\ntype EImportCall struct {\n\tExpr          Expr\n\tOptionsOrNil  Expr\n\tCloseParenLoc logger.Loc\n\tPhase         ast.ImportPhase\n}\n\ntype Stmt struct {\n\tData S\n\tLoc  logger.Loc\n}\n\n// This interface is never called. Its purpose is to encode a variant type in\n// Go's type system.\ntype S interface{ isStmt() }\n\nfunc (*SBlock) isStmt()         {}\nfunc (*SComment) isStmt()       {}\nfunc (*SDebugger) isStmt()      {}\nfunc (*SDirective) isStmt()     {}\nfunc (*SEmpty) isStmt()         {}\nfunc (*STypeScript) isStmt()    {}\nfunc (*SExportClause) isStmt()  {}\nfunc (*SExportFrom) isStmt()    {}\nfunc (*SExportDefault) isStmt() {}\nfunc (*SExportStar) isStmt()    {}\nfunc (*SExportEquals) isStmt()  {}\nfunc (*SLazyExport) isStmt()    {}\nfunc (*SExpr) isStmt()          {}\nfunc (*SEnum) isStmt()          {}\nfunc (*SNamespace) isStmt()     {}\nfunc (*SFunction) isStmt()      {}\nfunc (*SClass) isStmt()         {}\nfunc (*SLabel) isStmt()         {}\nfunc (*SIf) isStmt()            {}\nfunc (*SFor) isStmt()           {}\nfunc (*SForIn) isStmt()         {}\nfunc (*SForOf) isStmt()         {}\nfunc (*SDoWhile) isStmt()       {}\nfunc (*SWhile) isStmt()         {}\nfunc (*SWith) isStmt()          {}\nfunc (*STry) isStmt()           {}\nfunc (*SSwitch) isStmt()        {}\nfunc (*SImport) isStmt()        {}\nfunc (*SReturn) isStmt()        {}\nfunc (*SThrow) isStmt()         {}\nfunc (*SLocal) isStmt()         {}\nfunc (*SBreak) isStmt()         {}\nfunc (*SContinue) isStmt()      {}\n\ntype SBlock struct {\n\tStmts         []Stmt\n\tCloseBraceLoc logger.Loc\n}\n\ntype SEmpty struct{}\n\n// This is a stand-in for a TypeScript type declaration\ntype STypeScript struct {\n\tWasDeclareClass bool\n}\n\ntype SComment struct {\n\tText           string\n\tIsLegalComment bool\n}\n\ntype SDebugger struct{}\n\ntype SDirective struct {\n\tValue          []uint16\n\tLegacyOctalLoc logger.Loc\n}\n\ntype SExportClause struct {\n\tItems        []ClauseItem\n\tIsSingleLine bool\n}\n\ntype SExportFrom struct {\n\tItems             []ClauseItem\n\tNamespaceRef      ast.Ref\n\tImportRecordIndex uint32\n\tIsSingleLine      bool\n}\n\ntype SExportDefault struct {\n\tValue       Stmt // May be a SExpr or SFunction or SClass\n\tDefaultName ast.LocRef\n}\n\ntype ExportStarAlias struct {\n\t// Although this alias name starts off as being the same as the statement's\n\t// namespace symbol, it may diverge if the namespace symbol name is minified.\n\t// The original alias name is preserved here to avoid this scenario.\n\tOriginalName string\n\n\tLoc logger.Loc\n}\n\ntype SExportStar struct {\n\tAlias             *ExportStarAlias\n\tNamespaceRef      ast.Ref\n\tImportRecordIndex uint32\n}\n\n// This is an \"export = value;\" statement in TypeScript\ntype SExportEquals struct {\n\tValue Expr\n}\n\n// The decision of whether to export an expression using \"module.exports\" or\n// \"export default\" is deferred until linking using this statement kind\ntype SLazyExport struct {\n\tValue Expr\n}\n\ntype SExpr struct {\n\tValue Expr\n\n\t// This is set to true for automatically-generated expressions that are part\n\t// of class syntax lowering. A single class declaration may end up with many\n\t// generated expressions after it (e.g. class field initializations, a call\n\t// to keep the original value of the \"name\" property). When this happens we\n\t// can't tell that the class is side-effect free anymore because all of these\n\t// methods mutate the class. We use this annotation for that instead.\n\tIsFromClassOrFnThatCanBeRemovedIfUnused bool\n}\n\ntype EnumValue struct {\n\tValueOrNil Expr\n\tName       []uint16\n\tRef        ast.Ref\n\tLoc        logger.Loc\n}\n\ntype SEnum struct {\n\tValues   []EnumValue\n\tName     ast.LocRef\n\tArg      ast.Ref\n\tIsExport bool\n}\n\ntype SNamespace struct {\n\tStmts    []Stmt\n\tName     ast.LocRef\n\tArg      ast.Ref\n\tIsExport bool\n}\n\ntype SFunction struct {\n\tFn       Fn\n\tIsExport bool\n}\n\ntype SClass struct {\n\tClass    Class\n\tIsExport bool\n}\n\ntype SLabel struct {\n\tStmt             Stmt\n\tName             ast.LocRef\n\tIsSingleLineStmt bool\n}\n\ntype SIf struct {\n\tTest            Expr\n\tYes             Stmt\n\tNoOrNil         Stmt\n\tIsSingleLineYes bool\n\tIsSingleLineNo  bool\n}\n\ntype SFor struct {\n\tInitOrNil         Stmt // May be a SConst, SLet, SVar, or SExpr\n\tTestOrNil         Expr\n\tUpdateOrNil       Expr\n\tBody              Stmt\n\tIsSingleLineBody  bool\n\tIsLoweredForAwait bool\n}\n\ntype SForIn struct {\n\tInit             Stmt // May be a SConst, SLet, SVar, or SExpr\n\tValue            Expr\n\tBody             Stmt\n\tIsSingleLineBody bool\n}\n\ntype SForOf struct {\n\tInit             Stmt // May be a SConst, SLet, SVar, or SExpr\n\tValue            Expr\n\tBody             Stmt\n\tAwait            logger.Range\n\tIsSingleLineBody bool\n}\n\ntype SDoWhile struct {\n\tBody Stmt\n\tTest Expr\n}\n\ntype SWhile struct {\n\tTest             Expr\n\tBody             Stmt\n\tIsSingleLineBody bool\n}\n\ntype SWith struct {\n\tValue            Expr\n\tBody             Stmt\n\tBodyLoc          logger.Loc\n\tIsSingleLineBody bool\n}\n\ntype Catch struct {\n\tBindingOrNil Binding\n\tBlock        SBlock\n\tLoc          logger.Loc\n\tBlockLoc     logger.Loc\n}\n\ntype Finally struct {\n\tBlock SBlock\n\tLoc   logger.Loc\n}\n\ntype STry struct {\n\tCatch    *Catch\n\tFinally  *Finally\n\tBlock    SBlock\n\tBlockLoc logger.Loc\n}\n\ntype Case struct {\n\tValueOrNil Expr // If this is nil, this is \"default\" instead of \"case\"\n\tBody       []Stmt\n\tLoc        logger.Loc\n}\n\ntype SSwitch struct {\n\tTest          Expr\n\tCases         []Case\n\tBodyLoc       logger.Loc\n\tCloseBraceLoc logger.Loc\n}\n\n// This object represents all of these types of import statements:\n//\n//\timport 'path'\n//\timport {item1, item2} from 'path'\n//\timport * as ns from 'path'\n//\timport defaultItem, {item1, item2} from 'path'\n//\timport defaultItem, * as ns from 'path'\n//\n// Many parts are optional and can be combined in different ways. The only\n// restriction is that you cannot have both a clause and a star namespace.\ntype SImport struct {\n\tDefaultName *ast.LocRef\n\tItems       *[]ClauseItem\n\tStarNameLoc *logger.Loc\n\n\t// If this is a star import: This is a Ref for the namespace symbol. The Loc\n\t// for the symbol is StarLoc.\n\t//\n\t// Otherwise: This is an auto-generated Ref for the namespace representing\n\t// the imported file. In this case StarLoc is nil. The NamespaceRef is used\n\t// when converting this module to a CommonJS module.\n\tNamespaceRef ast.Ref\n\n\tImportRecordIndex uint32\n\tIsSingleLine      bool\n}\n\ntype SReturn struct {\n\tValueOrNil Expr\n}\n\ntype SThrow struct {\n\tValue Expr\n}\n\ntype LocalKind uint8\n\nconst (\n\tLocalVar LocalKind = iota\n\tLocalLet\n\tLocalConst\n\tLocalUsing\n\tLocalAwaitUsing\n)\n\nfunc (kind LocalKind) IsUsing() bool {\n\treturn kind >= LocalUsing\n}\n\ntype SLocal struct {\n\tDecls    []Decl\n\tKind     LocalKind\n\tIsExport bool\n\n\t// The TypeScript compiler doesn't generate code for \"import foo = bar\"\n\t// statements where the import is never used.\n\tWasTSImportEquals bool\n}\n\ntype SBreak struct {\n\tLabel *ast.LocRef\n}\n\ntype SContinue struct {\n\tLabel *ast.LocRef\n}\n\ntype ClauseItem struct {\n\tAlias string\n\n\t// This is the original name of the symbol stored in \"Name\". It's needed for\n\t// \"SExportClause\" statements such as this:\n\t//\n\t//   export {foo as bar} from 'path'\n\t//\n\t// In this case both \"foo\" and \"bar\" are aliases because it's a re-export.\n\t// We need to preserve both aliases in case the symbol is renamed. In this\n\t// example, \"foo\" is \"OriginalName\" and \"bar\" is \"Alias\".\n\tOriginalName string\n\n\tAliasLoc logger.Loc\n\tName     ast.LocRef\n}\n\ntype Decl struct {\n\tBinding    Binding\n\tValueOrNil Expr\n}\n\ntype ScopeKind uint8\n\nconst (\n\tScopeBlock ScopeKind = iota\n\tScopeWith\n\tScopeLabel\n\tScopeClassName\n\tScopeClassBody\n\tScopeCatchBinding\n\n\t// The scopes below stop hoisted variables from extending into parent scopes\n\tScopeEntry // This is a module, TypeScript enum, or TypeScript namespace\n\tScopeFunctionArgs\n\tScopeFunctionBody\n\tScopeClassStaticInit\n)\n\nfunc (kind ScopeKind) StopsHoisting() bool {\n\treturn kind >= ScopeEntry\n}\n\ntype ScopeMember struct {\n\tRef ast.Ref\n\tLoc logger.Loc\n}\n\ntype Scope struct {\n\t// This will be non-nil if this is a TypeScript \"namespace\" or \"enum\"\n\tTSNamespace *TSNamespaceScope\n\n\tParent    *Scope\n\tChildren  []*Scope\n\tMembers   map[string]ScopeMember\n\tReplaced  []ScopeMember\n\tGenerated []ast.Ref\n\n\t// The location of the \"use strict\" directive for ExplicitStrictMode\n\tUseStrictLoc logger.Loc\n\n\t// This is used to store the ref of the label symbol for ScopeLabel scopes.\n\tLabel           ast.LocRef\n\tLabelStmtIsLoop bool\n\n\t// If a scope contains a direct eval() expression, then none of the symbols\n\t// inside that scope can be renamed. We conservatively assume that the\n\t// evaluated code might reference anything that it has access to.\n\tContainsDirectEval bool\n\n\t// This is to help forbid \"arguments\" inside class body scopes\n\tForbidArguments bool\n\n\t// As a special case, we enable constant propagation for any chain of \"const\"\n\t// declarations at the start of a statement list. This special case doesn't\n\t// have any TDZ considerations because no other statements come before it.\n\tIsAfterConstLocalPrefix bool\n\n\tStrictMode StrictModeKind\n\tKind       ScopeKind\n}\n\ntype StrictModeKind uint8\n\nconst (\n\tSloppyMode StrictModeKind = iota\n\tExplicitStrictMode\n\tImplicitStrictModeClass\n\tImplicitStrictModeESM\n\tImplicitStrictModeTSAlwaysStrict\n\tImplicitStrictModeJSXAutomaticRuntime\n)\n\nfunc (s *Scope) RecursiveSetStrictMode(kind StrictModeKind) {\n\tif s.StrictMode == SloppyMode {\n\t\ts.StrictMode = kind\n\t\tfor _, child := range s.Children {\n\t\t\tchild.RecursiveSetStrictMode(kind)\n\t\t}\n\t}\n}\n\n// This is for TypeScript \"enum\" and \"namespace\" blocks. Each block can\n// potentially be instantiated multiple times. The exported members of each\n// block are merged into a single namespace while the non-exported code is\n// still scoped to just within that block:\n//\n//\tlet x = 1;\n//\tnamespace Foo {\n//\t  let x = 2;\n//\t  export let y = 3;\n//\t}\n//\tnamespace Foo {\n//\t  console.log(x); // 1\n//\t  console.log(y); // 3\n//\t}\n//\n// Doing this also works inside an enum:\n//\n//\tenum Foo {\n//\t  A = 3,\n//\t  B = A + 1,\n//\t}\n//\tenum Foo {\n//\t  C = A + 2,\n//\t}\n//\tconsole.log(Foo.B) // 4\n//\tconsole.log(Foo.C) // 5\n//\n// This is a form of identifier lookup that works differently than the\n// hierarchical scope-based identifier lookup in JavaScript. Lookup now needs\n// to search sibling scopes in addition to parent scopes. This is accomplished\n// by sharing the map of exported members between all matching sibling scopes.\ntype TSNamespaceScope struct {\n\t// This is shared between all sibling namespace blocks\n\tExportedMembers TSNamespaceMembers\n\n\t// This is a lazily-generated map of identifiers that actually represent\n\t// property accesses to this namespace's properties. For example:\n\t//\n\t//   namespace x {\n\t//     export let y = 123\n\t//   }\n\t//   namespace x {\n\t//     export let z = y\n\t//   }\n\t//\n\t// This should be compiled into the following code:\n\t//\n\t//   var x;\n\t//   (function(x2) {\n\t//     x2.y = 123;\n\t//   })(x || (x = {}));\n\t//   (function(x3) {\n\t//     x3.z = x3.y;\n\t//   })(x || (x = {}));\n\t//\n\t// When we try to find the symbol \"y\", we instead return one of these lazily\n\t// generated proxy symbols that represent the property access \"x3.y\". This\n\t// map is unique per namespace block because \"x3\" is the argument symbol that\n\t// is specific to that particular namespace block.\n\tLazilyGeneratedProperyAccesses map[string]ast.Ref\n\n\t// This is specific to this namespace block. It's the argument of the\n\t// immediately-invoked function expression that the namespace block is\n\t// compiled into:\n\t//\n\t//   var ns;\n\t//   (function (ns2) {\n\t//     ns2.x = 123;\n\t//   })(ns || (ns = {}));\n\t//\n\t// This variable is \"ns2\" in the above example. It's the symbol to use when\n\t// generating property accesses off of this namespace when it's in scope.\n\tArgRef ast.Ref\n\n\t// Even though enums are like namespaces and both enums and namespaces allow\n\t// implicit references to properties of sibling scopes, they behave like\n\t// separate, er, namespaces. Implicit references only work namespace-to-\n\t// namespace and enum-to-enum. They do not work enum-to-namespace. And I'm\n\t// not sure what's supposed to happen for the namespace-to-enum case because\n\t// the compiler crashes: https://github.com/microsoft/TypeScript/issues/46891.\n\t// So basically these both work:\n\t//\n\t//   enum a { b = 1 }\n\t//   enum a { c = b }\n\t//\n\t//   namespace x { export let y = 1 }\n\t//   namespace x { export let z = y }\n\t//\n\t// This doesn't work:\n\t//\n\t//   enum a { b = 1 }\n\t//   namespace a { export let c = b }\n\t//\n\t// And this crashes the TypeScript compiler:\n\t//\n\t//   namespace a { export let b = 1 }\n\t//   enum a { c = b }\n\t//\n\t// Therefore we only allow enum/enum and namespace/namespace interactions.\n\tIsEnumScope bool\n}\n\ntype TSNamespaceMembers map[string]TSNamespaceMember\n\ntype TSNamespaceMember struct {\n\tData        TSNamespaceMemberData\n\tLoc         logger.Loc\n\tIsEnumValue bool\n}\n\ntype TSNamespaceMemberData interface {\n\tisTSNamespaceMember()\n}\n\nfunc (TSNamespaceMemberProperty) isTSNamespaceMember()   {}\nfunc (TSNamespaceMemberNamespace) isTSNamespaceMember()  {}\nfunc (TSNamespaceMemberEnumNumber) isTSNamespaceMember() {}\nfunc (TSNamespaceMemberEnumString) isTSNamespaceMember() {}\n\n// \"namespace ns { export let it }\"\ntype TSNamespaceMemberProperty struct{}\n\n// \"namespace ns { export namespace it {} }\"\ntype TSNamespaceMemberNamespace struct {\n\tExportedMembers TSNamespaceMembers\n}\n\n// \"enum ns { it }\"\ntype TSNamespaceMemberEnumNumber struct {\n\tValue float64\n}\n\n// \"enum ns { it = 'it' }\"\ntype TSNamespaceMemberEnumString struct {\n\tValue []uint16\n}\n\ntype ExportsKind uint8\n\nconst (\n\t// This file doesn't have any kind of export, so it's impossible to say what\n\t// kind of file this is. An empty file is in this category, for example.\n\tExportsNone ExportsKind = iota\n\n\t// The exports are stored on \"module\" and/or \"exports\". Calling \"require()\"\n\t// on this module returns \"module.exports\". All imports to this module are\n\t// allowed but may return undefined.\n\tExportsCommonJS\n\n\t// All export names are known explicitly. Calling \"require()\" on this module\n\t// generates an exports object (stored in \"exports\") with getters for the\n\t// export names. Named imports to this module are only allowed if they are\n\t// in the set of export names.\n\tExportsESM\n\n\t// Some export names are known explicitly, but others fall back to a dynamic\n\t// run-time object. This is necessary when using the \"export * from\" syntax\n\t// with either a CommonJS module or an external module (i.e. a module whose\n\t// export names are not known at compile-time).\n\t//\n\t// Calling \"require()\" on this module generates an exports object (stored in\n\t// \"exports\") with getters for the export names. All named imports to this\n\t// module are allowed. Direct named imports reference the corresponding export\n\t// directly. Other imports go through property accesses on \"exports\".\n\tExportsESMWithDynamicFallback\n)\n\nfunc (kind ExportsKind) IsDynamic() bool {\n\treturn kind == ExportsCommonJS || kind == ExportsESMWithDynamicFallback\n}\n\ntype ModuleType uint8\n\nconst (\n\tModuleUnknown ModuleType = iota\n\n\t// \".cjs\" or \".cts\" or \"type: commonjs\" in package.json\n\tModuleCommonJS_CJS\n\tModuleCommonJS_CTS\n\tModuleCommonJS_PackageJSON\n\n\t// \".mjs\" or \".mts\" or \"type: module\" in package.json\n\tModuleESM_MJS\n\tModuleESM_MTS\n\tModuleESM_PackageJSON\n)\n\nfunc (mt ModuleType) IsCommonJS() bool {\n\treturn mt >= ModuleCommonJS_CJS && mt <= ModuleCommonJS_PackageJSON\n}\n\nfunc (mt ModuleType) IsESM() bool {\n\treturn mt >= ModuleESM_MJS && mt <= ModuleESM_PackageJSON\n}\n\ntype ModuleTypeData struct {\n\tSource *logger.Source\n\tRange  logger.Range\n\tType   ModuleType\n}\n\n// This is the index to the automatically-generated part containing code that\n// calls \"__export(exports, { ... getters ... })\". This is used to generate\n// getters on an exports object for ES6 export statements, and is both for\n// ES6 star imports and CommonJS-style modules. All files have one of these,\n// although it may contain no statements if there is nothing to export.\nconst NSExportPartIndex = uint32(0)\n\ntype AST struct {\n\tModuleTypeData ModuleTypeData\n\tParts          []Part\n\tSymbols        []ast.Symbol\n\tExprComments   map[logger.Loc][]string\n\tModuleScope    *Scope\n\tCharFreq       *ast.CharFreq\n\n\t// This is internal-only data used for the implementation of Yarn PnP\n\tManifestForYarnPnP Expr\n\n\tHashbang   string\n\tDirectives []string\n\tURLForCSS  string\n\n\t// Note: If you're in the linker, do not use this map directly. This map is\n\t// filled in by the parser and is considered immutable. For performance reasons,\n\t// the linker doesn't mutate this map (cloning a map is slow in Go). Instead the\n\t// linker super-imposes relevant information on top in a method call. You should\n\t// call \"TopLevelSymbolToParts\" instead.\n\tTopLevelSymbolToPartsFromParser map[ast.Ref][]uint32\n\n\t// This contains all top-level exported TypeScript enum constants. It exists\n\t// to enable cross-module inlining of constant enums.\n\tTSEnums map[ast.Ref]map[string]TSEnumValue\n\n\t// This contains the values of all detected inlinable constants. It exists\n\t// to enable cross-module inlining of these constants.\n\tConstValues map[ast.Ref]ConstValue\n\n\t// Properties in here are represented as symbols instead of strings, which\n\t// allows them to be renamed to smaller names.\n\tMangledProps map[string]ast.Ref\n\n\t// Properties in here are existing non-mangled properties in the source code\n\t// and must not be used when generating mangled names to avoid a collision.\n\tReservedProps map[string]bool\n\n\t// These are stored at the AST level instead of on individual AST nodes so\n\t// they can be manipulated efficiently without a full AST traversal\n\tImportRecords []ast.ImportRecord\n\n\t// These are used when bundling. They are filled in during the parser pass\n\t// since we already have to traverse the AST then anyway and the parser pass\n\t// is conveniently fully parallelized.\n\tNamedImports            map[ast.Ref]NamedImport\n\tNamedExports            map[string]NamedExport\n\tExportStarImportRecords []uint32\n\n\tSourceMapComment logger.Span\n\n\t// This is a list of ES6 features. They are ranges instead of booleans so\n\t// that they can be used in log messages. Check to see if \"Len > 0\".\n\tExportKeyword            logger.Range // Does not include TypeScript-specific syntax\n\tTopLevelAwaitKeyword     logger.Range\n\tLiveTopLevelAwaitKeyword logger.Range // Excludes top-level await in dead branches\n\n\tExportsRef ast.Ref\n\tModuleRef  ast.Ref\n\tWrapperRef ast.Ref\n\n\tApproximateLineCount  int32\n\tNestedScopeSlotCounts ast.SlotCounts\n\tHasLazyExport         bool\n\n\t// This is a list of CommonJS features. When a file uses CommonJS features,\n\t// it's not a candidate for \"flat bundling\" and must be wrapped in its own\n\t// closure. Note that this also includes top-level \"return\" but these aren't\n\t// here because only the parser checks those.\n\tUsesExportsRef bool\n\tUsesModuleRef  bool\n\tExportsKind    ExportsKind\n}\n\ntype TSEnumValue struct {\n\tString []uint16 // Use this if it's not nil\n\tNumber float64  // Use this if \"String\" is nil\n}\n\ntype ConstValueKind uint8\n\nconst (\n\tConstValueNone ConstValueKind = iota\n\tConstValueNull\n\tConstValueUndefined\n\tConstValueTrue\n\tConstValueFalse\n\tConstValueNumber\n\tConstValueString\n)\n\ntype ConstValue struct {\n\tNumber float64  // Use this for \"ConstValueNumber\"\n\tString []uint16 // Use this for \"ConstValueString\"\n\tKind   ConstValueKind\n}\n\nfunc ExprToConstValue(expr Expr) ConstValue {\n\tswitch v := expr.Data.(type) {\n\tcase *ENull:\n\t\treturn ConstValue{Kind: ConstValueNull}\n\n\tcase *EUndefined:\n\t\treturn ConstValue{Kind: ConstValueUndefined}\n\n\tcase *EBoolean:\n\t\tif v.Value {\n\t\t\treturn ConstValue{Kind: ConstValueTrue}\n\t\t} else {\n\t\t\treturn ConstValue{Kind: ConstValueFalse}\n\t\t}\n\n\tcase *ENumber:\n\t\t// Inline integers and other small numbers. Don't inline large\n\t\t// real numbers because people may not want them to be inlined\n\t\t// as it will increase the minified code size by too much.\n\t\tif asInt := int64(v.Value); v.Value == float64(asInt) || len(strconv.FormatFloat(v.Value, 'g', -1, 64)) <= 8 {\n\t\t\treturn ConstValue{Kind: ConstValueNumber, Number: v.Value}\n\t\t}\n\n\tcase *EString:\n\t\t// Deliberately only inline small strings. We don't want to always\n\t\t// inline all strings because they can be arbitrarily long.\n\t\tif len(v.Value) <= 3 {\n\t\t\treturn ConstValue{Kind: ConstValueString, String: v.Value}\n\t\t}\n\n\tcase *EBigInt:\n\t\t// I'm deliberately not inlining bigints here for the same reason (they can\n\t\t// be arbitrarily long).\n\t}\n\n\treturn ConstValue{}\n}\n\nfunc ConstValueToExpr(loc logger.Loc, value ConstValue) Expr {\n\tswitch value.Kind {\n\tcase ConstValueNull:\n\t\treturn Expr{Loc: loc, Data: ENullShared}\n\n\tcase ConstValueUndefined:\n\t\treturn Expr{Loc: loc, Data: EUndefinedShared}\n\n\tcase ConstValueTrue:\n\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: true}}\n\n\tcase ConstValueFalse:\n\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: false}}\n\n\tcase ConstValueNumber:\n\t\treturn Expr{Loc: loc, Data: &ENumber{Value: value.Number}}\n\n\tcase ConstValueString:\n\t\treturn Expr{Loc: loc, Data: &EString{Value: value.String}}\n\t}\n\n\tpanic(\"Internal error: invalid constant value\")\n}\n\ntype NamedImport struct {\n\tAlias string\n\n\t// Parts within this file that use this import\n\tLocalPartsWithUses []uint32\n\n\tAliasLoc          logger.Loc\n\tNamespaceRef      ast.Ref\n\tImportRecordIndex uint32\n\n\t// If true, the alias refers to the entire export namespace object of a\n\t// module. This is no longer represented as an alias called \"*\" because of\n\t// the upcoming \"Arbitrary module namespace identifier names\" feature:\n\t// https://github.com/tc39/ecma262/pull/2154\n\tAliasIsStar bool\n\n\t// It's useful to flag exported imports because if they are in a TypeScript\n\t// file, we can't tell if they are a type or a value.\n\tIsExported bool\n}\n\ntype NamedExport struct {\n\tRef      ast.Ref\n\tAliasLoc logger.Loc\n}\n\n// Each file is made up of multiple parts, and each part consists of one or\n// more top-level statements. Parts are used for tree shaking and code\n// splitting analysis. Individual parts of a file can be discarded by tree\n// shaking and can be assigned to separate chunks (i.e. output files) by code\n// splitting.\ntype Part struct {\n\tStmts  []Stmt\n\tScopes []*Scope\n\n\t// Each is an index into the file-level import record list\n\tImportRecordIndices []uint32\n\n\t// All symbols that are declared in this part. Note that a given symbol may\n\t// have multiple declarations, and so may end up being declared in multiple\n\t// parts (e.g. multiple \"var\" declarations with the same name). Also note\n\t// that this list isn't deduplicated and may contain duplicates.\n\tDeclaredSymbols []DeclaredSymbol\n\n\t// An estimate of the number of uses of all symbols used within this part.\n\tSymbolUses map[ast.Ref]SymbolUse\n\n\t// An estimate of the number of uses of all symbols used as the target of\n\t// function calls within this part.\n\tSymbolCallUses map[ast.Ref]SymbolCallUse\n\n\t// This tracks property accesses off of imported symbols. We don't know\n\t// during parsing if an imported symbol is going to be an inlined enum\n\t// value or not. This is only known during linking. So we defer adding\n\t// a dependency on these imported symbols until we know whether the\n\t// property access is an inlined enum value or not.\n\tImportSymbolPropertyUses map[ast.Ref]map[string]SymbolUse\n\n\t// The indices of the other parts in this file that are needed if this part\n\t// is needed.\n\tDependencies []Dependency\n\n\t// If true, this part can be removed if none of the declared symbols are\n\t// used. If the file containing this part is imported, then all parts that\n\t// don't have this flag enabled must be included.\n\tCanBeRemovedIfUnused bool\n\n\t// This is used for generated parts that we don't want to be present if they\n\t// aren't needed. This enables tree shaking for these parts even if global\n\t// tree shaking isn't enabled.\n\tForceTreeShaking bool\n\n\t// This is true if this file has been marked as live by the tree shaking\n\t// algorithm.\n\tIsLive bool\n}\n\ntype Dependency struct {\n\tSourceIndex uint32\n\tPartIndex   uint32\n}\n\ntype DeclaredSymbol struct {\n\tRef        ast.Ref\n\tIsTopLevel bool\n}\n\ntype SymbolUse struct {\n\tCountEstimate uint32\n}\n\ntype SymbolCallUse struct {\n\tCallCountEstimate                   uint32\n\tSingleArgNonSpreadCallCountEstimate uint32\n}\n\n// For readability, the names of certain automatically-generated symbols are\n// derived from the file name. For example, instead of the CommonJS wrapper for\n// a file being called something like \"require273\" it can be called something\n// like \"require_react\" instead. This function generates the part of these\n// identifiers that's specific to the file path. It can take both an absolute\n// path (OS-specific) and a path in the source code (OS-independent).\n//\n// Note that these generated names do not at all relate to the correctness of\n// the code as far as avoiding symbol name collisions. These names still go\n// through the renaming logic that all other symbols go through to avoid name\n// collisions.\nfunc GenerateNonUniqueNameFromPath(path string) string {\n\t// Get the file name without the extension\n\tdir, base, _ := logger.PlatformIndependentPathDirBaseExt(path)\n\n\t// If the name is \"index\", use the directory name instead. This is because\n\t// many packages in npm use the file name \"index.js\" because it triggers\n\t// node's implicit module resolution rules that allows you to import it by\n\t// just naming the directory.\n\tif base == \"index\" {\n\t\t_, dirBase, _ := logger.PlatformIndependentPathDirBaseExt(dir)\n\t\tif dirBase != \"\" {\n\t\t\tbase = dirBase\n\t\t}\n\t}\n\n\treturn EnsureValidIdentifier(base)\n}\n\nfunc EnsureValidIdentifier(base string) string {\n\t// Convert it to an ASCII identifier. Note: If you change this to a non-ASCII\n\t// identifier, you're going to potentially cause trouble with non-BMP code\n\t// points in target environments that don't support bracketed Unicode escapes.\n\tbytes := []byte{}\n\tneedsGap := false\n\tfor _, c := range base {\n\t\tif (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (len(bytes) > 0 && c >= '0' && c <= '9') {\n\t\t\tif needsGap {\n\t\t\t\tbytes = append(bytes, '_')\n\t\t\t\tneedsGap = false\n\t\t\t}\n\t\t\tbytes = append(bytes, byte(c))\n\t\t} else if len(bytes) > 0 {\n\t\t\tneedsGap = true\n\t\t}\n\t}\n\n\t// Make sure the name isn't empty\n\tif len(bytes) == 0 {\n\t\treturn \"_\"\n\t}\n\treturn string(bytes)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/js_ast/js_ast_helpers.go",
    "content": "package js_ast\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\ntype HelperContext struct {\n\tisUnbound func(ast.Ref) bool\n}\n\nfunc MakeHelperContext(isUnbound func(ast.Ref) bool) HelperContext {\n\treturn HelperContext{\n\t\tisUnbound: isUnbound,\n\t}\n}\n\n// If this returns true, then calling this expression captures the target of\n// the property access as \"this\" when calling the function in the property.\nfunc IsPropertyAccess(expr Expr) bool {\n\tswitch expr.Data.(type) {\n\tcase *EDot, *EIndex:\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc IsOptionalChain(value Expr) bool {\n\tswitch e := value.Data.(type) {\n\tcase *EDot:\n\t\treturn e.OptionalChain != OptionalChainNone\n\tcase *EIndex:\n\t\treturn e.OptionalChain != OptionalChainNone\n\tcase *ECall:\n\t\treturn e.OptionalChain != OptionalChainNone\n\t}\n\treturn false\n}\n\nfunc Assign(a Expr, b Expr) Expr {\n\treturn Expr{Loc: a.Loc, Data: &EBinary{Op: BinOpAssign, Left: a, Right: b}}\n}\n\nfunc AssignStmt(a Expr, b Expr) Stmt {\n\treturn Stmt{Loc: a.Loc, Data: &SExpr{Value: Assign(a, b)}}\n}\n\n// Wraps the provided expression in the \"!\" prefix operator. The expression\n// will potentially be simplified to avoid generating unnecessary extra \"!\"\n// operators. For example, calling this with \"!!x\" will return \"!x\" instead\n// of returning \"!!!x\".\nfunc Not(expr Expr) Expr {\n\tif result, ok := MaybeSimplifyNot(expr); ok {\n\t\treturn result\n\t}\n\treturn Expr{Loc: expr.Loc, Data: &EUnary{Op: UnOpNot, Value: expr}}\n}\n\n// The given \"expr\" argument should be the operand of a \"!\" prefix operator\n// (i.e. the \"x\" in \"!x\"). This returns a simplified expression for the\n// whole operator (i.e. the \"!x\") if it can be simplified, or false if not.\n// It's separate from \"Not()\" above to avoid allocation on failure in case\n// that is undesired.\n//\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc MaybeSimplifyNot(expr Expr) (Expr, bool) {\n\tswitch e := expr.Data.(type) {\n\tcase *EAnnotation:\n\t\treturn MaybeSimplifyNot(e.Value)\n\n\tcase *EInlinedEnum:\n\t\tif value, ok := MaybeSimplifyNot(e.Value); ok {\n\t\t\treturn value, true\n\t\t}\n\n\tcase *ENull, *EUndefined:\n\t\treturn Expr{Loc: expr.Loc, Data: &EBoolean{Value: true}}, true\n\n\tcase *EBoolean:\n\t\treturn Expr{Loc: expr.Loc, Data: &EBoolean{Value: !e.Value}}, true\n\n\tcase *ENumber:\n\t\treturn Expr{Loc: expr.Loc, Data: &EBoolean{Value: e.Value == 0 || math.IsNaN(e.Value)}}, true\n\n\tcase *EBigInt:\n\t\tif equal, ok := CheckEqualityBigInt(e.Value, \"0\"); ok {\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBoolean{Value: equal}}, true\n\t\t}\n\n\tcase *EString:\n\t\treturn Expr{Loc: expr.Loc, Data: &EBoolean{Value: len(e.Value) == 0}}, true\n\n\tcase *EFunction, *EArrow, *ERegExp:\n\t\treturn Expr{Loc: expr.Loc, Data: &EBoolean{Value: false}}, true\n\n\tcase *EUnary:\n\t\t// \"!!!a\" => \"!a\"\n\t\tif e.Op == UnOpNot && KnownPrimitiveType(e.Value.Data) == PrimitiveBoolean {\n\t\t\treturn e.Value, true\n\t\t}\n\n\tcase *EBinary:\n\t\t// Make sure that these transformations are all safe for special values.\n\t\t// For example, \"!(a < b)\" is not the same as \"a >= b\" if a and/or b are\n\t\t// NaN (or undefined, or null, or possibly other problem cases too).\n\t\tswitch e.Op {\n\t\tcase BinOpLooseEq:\n\t\t\t// \"!(a == b)\" => \"a != b\"\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{Op: BinOpLooseNe, Left: e.Left, Right: e.Right}}, true\n\n\t\tcase BinOpLooseNe:\n\t\t\t// \"!(a != b)\" => \"a == b\"\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{Op: BinOpLooseEq, Left: e.Left, Right: e.Right}}, true\n\n\t\tcase BinOpStrictEq:\n\t\t\t// \"!(a === b)\" => \"a !== b\"\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{Op: BinOpStrictNe, Left: e.Left, Right: e.Right}}, true\n\n\t\tcase BinOpStrictNe:\n\t\t\t// \"!(a !== b)\" => \"a === b\"\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{Op: BinOpStrictEq, Left: e.Left, Right: e.Right}}, true\n\n\t\tcase BinOpComma:\n\t\t\t// \"!(a, b)\" => \"a, !b\"\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{Op: BinOpComma, Left: e.Left, Right: Not(e.Right)}}, true\n\t\t}\n\t}\n\n\treturn Expr{}, false\n}\n\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc MaybeSimplifyEqualityComparison(loc logger.Loc, e *EBinary, unsupportedFeatures compat.JSFeature) (Expr, bool) {\n\tvalue, primitive := e.Left, e.Right\n\n\t// Detect when the primitive comes first and flip the order of our checks\n\tif IsPrimitiveLiteral(value.Data) {\n\t\tvalue, primitive = primitive, value\n\t}\n\n\t// \"!x === true\" => \"!x\"\n\t// \"!x === false\" => \"!!x\"\n\t// \"!x !== true\" => \"!!x\"\n\t// \"!x !== false\" => \"!x\"\n\tif boolean, ok := primitive.Data.(*EBoolean); ok && KnownPrimitiveType(value.Data) == PrimitiveBoolean {\n\t\tif boolean.Value == (e.Op == BinOpLooseNe || e.Op == BinOpStrictNe) {\n\t\t\treturn Not(value), true\n\t\t} else {\n\t\t\treturn value, true\n\t\t}\n\t}\n\n\t// \"typeof x != 'undefined'\" => \"typeof x < 'u'\"\n\t// \"typeof x == 'undefined'\" => \"typeof x > 'u'\"\n\tif !unsupportedFeatures.Has(compat.TypeofExoticObjectIsObject) {\n\t\t// Only do this optimization if we know that the \"typeof\" operator won't\n\t\t// return something random. The only case of this happening was Internet\n\t\t// Explorer returning \"unknown\" for some objects, which messes with this\n\t\t// optimization. So we don't do this when targeting Internet Explorer.\n\t\tif typeof, ok := value.Data.(*EUnary); ok && typeof.Op == UnOpTypeof {\n\t\t\tif str, ok := primitive.Data.(*EString); ok && helpers.UTF16EqualsString(str.Value, \"undefined\") {\n\t\t\t\tflip := value == e.Right\n\t\t\t\top := BinOpLt\n\t\t\t\tif (e.Op == BinOpLooseEq || e.Op == BinOpStrictEq) != flip {\n\t\t\t\t\top = BinOpGt\n\t\t\t\t}\n\t\t\t\tprimitive.Data = &EString{Value: []uint16{'u'}}\n\t\t\t\tif flip {\n\t\t\t\t\tvalue, primitive = primitive, value\n\t\t\t\t}\n\t\t\t\treturn Expr{Loc: loc, Data: &EBinary{Op: op, Left: value, Right: primitive}}, true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Expr{}, false\n}\n\nfunc IsSymbolInstance(data E) bool {\n\tswitch e := data.(type) {\n\tcase *EDot:\n\t\treturn e.IsSymbolInstance\n\n\tcase *EIndex:\n\t\treturn e.IsSymbolInstance\n\t}\n\treturn false\n}\n\nfunc IsPrimitiveLiteral(data E) bool {\n\tswitch e := data.(type) {\n\tcase *EAnnotation:\n\t\treturn IsPrimitiveLiteral(e.Value.Data)\n\n\tcase *EInlinedEnum:\n\t\treturn IsPrimitiveLiteral(e.Value.Data)\n\n\tcase *ENull, *EUndefined, *EString, *EBoolean, *ENumber, *EBigInt:\n\t\treturn true\n\t}\n\treturn false\n}\n\ntype PrimitiveType uint8\n\nconst (\n\tPrimitiveUnknown PrimitiveType = iota\n\tPrimitiveMixed\n\tPrimitiveNull\n\tPrimitiveUndefined\n\tPrimitiveBoolean\n\tPrimitiveNumber\n\tPrimitiveString\n\tPrimitiveBigInt\n)\n\n// This can be used when the returned type is either one or the other\nfunc MergedKnownPrimitiveTypes(a Expr, b Expr) PrimitiveType {\n\tx := KnownPrimitiveType(a.Data)\n\tif x == PrimitiveUnknown {\n\t\treturn PrimitiveUnknown\n\t}\n\n\ty := KnownPrimitiveType(b.Data)\n\tif y == PrimitiveUnknown {\n\t\treturn PrimitiveUnknown\n\t}\n\n\tif x == y {\n\t\treturn x\n\t}\n\treturn PrimitiveMixed // Definitely some kind of primitive\n}\n\n// Note: This function does not say whether the expression is side-effect free\n// or not. For example, the expression \"++x\" always returns a primitive.\nfunc KnownPrimitiveType(expr E) PrimitiveType {\n\tswitch e := expr.(type) {\n\tcase *EAnnotation:\n\t\treturn KnownPrimitiveType(e.Value.Data)\n\n\tcase *EInlinedEnum:\n\t\treturn KnownPrimitiveType(e.Value.Data)\n\n\tcase *ENull:\n\t\treturn PrimitiveNull\n\n\tcase *EUndefined:\n\t\treturn PrimitiveUndefined\n\n\tcase *EBoolean:\n\t\treturn PrimitiveBoolean\n\n\tcase *ENumber:\n\t\treturn PrimitiveNumber\n\n\tcase *EString:\n\t\treturn PrimitiveString\n\n\tcase *EBigInt:\n\t\treturn PrimitiveBigInt\n\n\tcase *ETemplate:\n\t\tif e.TagOrNil.Data == nil {\n\t\t\treturn PrimitiveString\n\t\t}\n\n\tcase *EIf:\n\t\treturn MergedKnownPrimitiveTypes(e.Yes, e.No)\n\n\tcase *EUnary:\n\t\tswitch e.Op {\n\t\tcase UnOpVoid:\n\t\t\treturn PrimitiveUndefined\n\n\t\tcase UnOpTypeof:\n\t\t\treturn PrimitiveString\n\n\t\tcase UnOpNot, UnOpDelete:\n\t\t\treturn PrimitiveBoolean\n\n\t\tcase UnOpPos:\n\t\t\treturn PrimitiveNumber // Cannot be bigint because that throws an exception\n\n\t\tcase UnOpNeg, UnOpCpl:\n\t\t\tvalue := KnownPrimitiveType(e.Value.Data)\n\t\t\tif value == PrimitiveBigInt {\n\t\t\t\treturn PrimitiveBigInt\n\t\t\t}\n\t\t\tif value != PrimitiveUnknown && value != PrimitiveMixed {\n\t\t\t\treturn PrimitiveNumber\n\t\t\t}\n\t\t\treturn PrimitiveMixed // Can be number or bigint\n\n\t\tcase UnOpPreDec, UnOpPreInc, UnOpPostDec, UnOpPostInc:\n\t\t\treturn PrimitiveMixed // Can be number or bigint\n\t\t}\n\n\tcase *EBinary:\n\t\tswitch e.Op {\n\t\tcase BinOpStrictEq, BinOpStrictNe, BinOpLooseEq, BinOpLooseNe,\n\t\t\tBinOpLt, BinOpGt, BinOpLe, BinOpGe,\n\t\t\tBinOpInstanceof, BinOpIn:\n\t\t\treturn PrimitiveBoolean\n\n\t\tcase BinOpLogicalOr, BinOpLogicalAnd:\n\t\t\treturn MergedKnownPrimitiveTypes(e.Left, e.Right)\n\n\t\tcase BinOpNullishCoalescing:\n\t\t\tleft := KnownPrimitiveType(e.Left.Data)\n\t\t\tright := KnownPrimitiveType(e.Right.Data)\n\t\t\tif left == PrimitiveNull || left == PrimitiveUndefined {\n\t\t\t\treturn right\n\t\t\t}\n\t\t\tif left != PrimitiveUnknown {\n\t\t\t\tif left != PrimitiveMixed {\n\t\t\t\t\treturn left // Definitely not null or undefined\n\t\t\t\t}\n\t\t\t\tif right != PrimitiveUnknown {\n\t\t\t\t\treturn PrimitiveMixed // Definitely some kind of primitive\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase BinOpAdd:\n\t\t\tleft := KnownPrimitiveType(e.Left.Data)\n\t\t\tright := KnownPrimitiveType(e.Right.Data)\n\t\t\tif left == PrimitiveString || right == PrimitiveString {\n\t\t\t\treturn PrimitiveString\n\t\t\t}\n\t\t\tif left == PrimitiveBigInt && right == PrimitiveBigInt {\n\t\t\t\treturn PrimitiveBigInt\n\t\t\t}\n\t\t\tif left != PrimitiveUnknown && left != PrimitiveMixed && left != PrimitiveBigInt &&\n\t\t\t\tright != PrimitiveUnknown && right != PrimitiveMixed && right != PrimitiveBigInt {\n\t\t\t\treturn PrimitiveNumber\n\t\t\t}\n\t\t\treturn PrimitiveMixed // Can be number or bigint or string (or an exception)\n\n\t\tcase BinOpAddAssign:\n\t\t\tright := KnownPrimitiveType(e.Right.Data)\n\t\t\tif right == PrimitiveString {\n\t\t\t\treturn PrimitiveString\n\t\t\t}\n\t\t\treturn PrimitiveMixed // Can be number or bigint or string (or an exception)\n\n\t\tcase\n\t\t\tBinOpSub, BinOpSubAssign,\n\t\t\tBinOpMul, BinOpMulAssign,\n\t\t\tBinOpDiv, BinOpDivAssign,\n\t\t\tBinOpRem, BinOpRemAssign,\n\t\t\tBinOpPow, BinOpPowAssign,\n\t\t\tBinOpBitwiseAnd, BinOpBitwiseAndAssign,\n\t\t\tBinOpBitwiseOr, BinOpBitwiseOrAssign,\n\t\t\tBinOpBitwiseXor, BinOpBitwiseXorAssign,\n\t\t\tBinOpShl, BinOpShlAssign,\n\t\t\tBinOpShr, BinOpShrAssign,\n\t\t\tBinOpUShr, BinOpUShrAssign:\n\t\t\treturn PrimitiveMixed // Can be number or bigint (or an exception)\n\n\t\tcase BinOpAssign, BinOpComma:\n\t\t\treturn KnownPrimitiveType(e.Right.Data)\n\t\t}\n\t}\n\n\treturn PrimitiveUnknown\n}\n\nfunc CanChangeStrictToLoose(a Expr, b Expr) bool {\n\tx := KnownPrimitiveType(a.Data)\n\ty := KnownPrimitiveType(b.Data)\n\treturn x == y && x != PrimitiveUnknown && x != PrimitiveMixed\n}\n\n// Returns true if the result of the \"typeof\" operator on this expression is\n// statically determined and this expression has no side effects (i.e. can be\n// removed without consequence).\nfunc TypeofWithoutSideEffects(data E) (string, bool) {\n\tswitch e := data.(type) {\n\tcase *EAnnotation:\n\t\tif e.Flags.Has(CanBeRemovedIfUnusedFlag) {\n\t\t\treturn TypeofWithoutSideEffects(e.Value.Data)\n\t\t}\n\n\tcase *EInlinedEnum:\n\t\treturn TypeofWithoutSideEffects(e.Value.Data)\n\n\tcase *ENull:\n\t\treturn \"object\", true\n\n\tcase *EUndefined:\n\t\treturn \"undefined\", true\n\n\tcase *EBoolean:\n\t\treturn \"boolean\", true\n\n\tcase *ENumber:\n\t\treturn \"number\", true\n\n\tcase *EBigInt:\n\t\treturn \"bigint\", true\n\n\tcase *EString:\n\t\treturn \"string\", true\n\n\tcase *EFunction, *EArrow:\n\t\treturn \"function\", true\n\t}\n\n\treturn \"\", false\n}\n\n// The goal of this function is to \"rotate\" the AST if it's possible to use the\n// left-associative property of the operator to avoid unnecessary parentheses.\n//\n// When using this, make absolutely sure that the operator is actually\n// associative. For example, the \"+\" operator is not associative for\n// floating-point numbers.\n//\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc JoinWithLeftAssociativeOp(op OpCode, a Expr, b Expr) Expr {\n\t// \"(a, b) op c\" => \"a, b op c\"\n\tif comma, ok := a.Data.(*EBinary); ok && comma.Op == BinOpComma {\n\t\t// Don't mutate the original AST\n\t\tclone := *comma\n\t\tclone.Right = JoinWithLeftAssociativeOp(op, clone.Right, b)\n\t\treturn Expr{Loc: a.Loc, Data: &clone}\n\t}\n\n\t// \"a op (b op c)\" => \"(a op b) op c\"\n\t// \"a op (b op (c op d))\" => \"((a op b) op c) op d\"\n\tfor {\n\t\tif binary, ok := b.Data.(*EBinary); ok && binary.Op == op {\n\t\t\ta = JoinWithLeftAssociativeOp(op, a, binary.Left)\n\t\t\tb = binary.Right\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// \"a op b\" => \"a op b\"\n\t// \"(a op b) op c\" => \"(a op b) op c\"\n\treturn Expr{Loc: a.Loc, Data: &EBinary{Op: op, Left: a, Right: b}}\n}\n\nfunc JoinWithComma(a Expr, b Expr) Expr {\n\tif a.Data == nil {\n\t\treturn b\n\t}\n\tif b.Data == nil {\n\t\treturn a\n\t}\n\treturn Expr{Loc: a.Loc, Data: &EBinary{Op: BinOpComma, Left: a, Right: b}}\n}\n\nfunc JoinAllWithComma(all []Expr) (result Expr) {\n\tfor _, value := range all {\n\t\tresult = JoinWithComma(result, value)\n\t}\n\treturn\n}\n\nfunc ConvertBindingToExpr(binding Binding, wrapIdentifier func(logger.Loc, ast.Ref) Expr) Expr {\n\tloc := binding.Loc\n\n\tswitch b := binding.Data.(type) {\n\tcase *BMissing:\n\t\treturn Expr{Loc: loc, Data: &EMissing{}}\n\n\tcase *BIdentifier:\n\t\tif wrapIdentifier != nil {\n\t\t\treturn wrapIdentifier(loc, b.Ref)\n\t\t}\n\t\treturn Expr{Loc: loc, Data: &EIdentifier{Ref: b.Ref}}\n\n\tcase *BArray:\n\t\texprs := make([]Expr, len(b.Items))\n\t\tfor i, item := range b.Items {\n\t\t\texpr := ConvertBindingToExpr(item.Binding, wrapIdentifier)\n\t\t\tif b.HasSpread && i+1 == len(b.Items) {\n\t\t\t\texpr = Expr{Loc: expr.Loc, Data: &ESpread{Value: expr}}\n\t\t\t} else if item.DefaultValueOrNil.Data != nil {\n\t\t\t\texpr = Assign(expr, item.DefaultValueOrNil)\n\t\t\t}\n\t\t\texprs[i] = expr\n\t\t}\n\t\treturn Expr{Loc: loc, Data: &EArray{\n\t\t\tItems:        exprs,\n\t\t\tIsSingleLine: b.IsSingleLine,\n\t\t}}\n\n\tcase *BObject:\n\t\tproperties := make([]Property, len(b.Properties))\n\t\tfor i, property := range b.Properties {\n\t\t\tvalue := ConvertBindingToExpr(property.Value, wrapIdentifier)\n\t\t\tkind := PropertyField\n\t\t\tif property.IsSpread {\n\t\t\t\tkind = PropertySpread\n\t\t\t}\n\t\t\tvar flags PropertyFlags\n\t\t\tif property.IsComputed {\n\t\t\t\tflags |= PropertyIsComputed\n\t\t\t}\n\t\t\tproperties[i] = Property{\n\t\t\t\tKind:             kind,\n\t\t\t\tFlags:            flags,\n\t\t\t\tKey:              property.Key,\n\t\t\t\tValueOrNil:       value,\n\t\t\t\tInitializerOrNil: property.DefaultValueOrNil,\n\t\t\t}\n\t\t}\n\t\treturn Expr{Loc: loc, Data: &EObject{\n\t\t\tProperties:   properties,\n\t\t\tIsSingleLine: b.IsSingleLine,\n\t\t}}\n\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\n// This will return a nil expression if the expression can be totally removed.\n//\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc (ctx HelperContext) SimplifyUnusedExpr(expr Expr, unsupportedFeatures compat.JSFeature) Expr {\n\tswitch e := expr.Data.(type) {\n\tcase *EAnnotation:\n\t\tif e.Flags.Has(CanBeRemovedIfUnusedFlag) {\n\t\t\treturn Expr{}\n\t\t}\n\n\tcase *EInlinedEnum:\n\t\treturn ctx.SimplifyUnusedExpr(e.Value, unsupportedFeatures)\n\n\tcase *ENull, *EUndefined, *EMissing, *EBoolean, *ENumber, *EBigInt,\n\t\t*EString, *EThis, *ERegExp, *EFunction, *EArrow, *EImportMeta:\n\t\treturn Expr{}\n\n\tcase *EDot:\n\t\tif e.CanBeRemovedIfUnused {\n\t\t\treturn Expr{}\n\t\t}\n\n\tcase *EIdentifier:\n\t\tif e.MustKeepDueToWithStmt {\n\t\t\tbreak\n\t\t}\n\t\tif e.CanBeRemovedIfUnused || !ctx.isUnbound(e.Ref) {\n\t\t\treturn Expr{}\n\t\t}\n\n\tcase *ETemplate:\n\t\tif e.TagOrNil.Data == nil {\n\t\t\tvar comma Expr\n\t\t\tvar templateLoc logger.Loc\n\t\t\tvar template *ETemplate\n\t\t\tfor _, part := range e.Parts {\n\t\t\t\t// If we know this value is some kind of primitive, then we know that\n\t\t\t\t// \"ToString\" has no side effects and can be avoided.\n\t\t\t\tif KnownPrimitiveType(part.Value.Data) != PrimitiveUnknown {\n\t\t\t\t\tif template != nil {\n\t\t\t\t\t\tcomma = JoinWithComma(comma, Expr{Loc: templateLoc, Data: template})\n\t\t\t\t\t\ttemplate = nil\n\t\t\t\t\t}\n\t\t\t\t\tcomma = JoinWithComma(comma, ctx.SimplifyUnusedExpr(part.Value, unsupportedFeatures))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Make sure \"ToString\" is still evaluated on the value. We can't use\n\t\t\t\t// string addition here because that may evaluate \"ValueOf\" instead.\n\t\t\t\tif template == nil {\n\t\t\t\t\ttemplate = &ETemplate{}\n\t\t\t\t\ttemplateLoc = part.Value.Loc\n\t\t\t\t}\n\t\t\t\ttemplate.Parts = append(template.Parts, TemplatePart{Value: part.Value})\n\t\t\t}\n\t\t\tif template != nil {\n\t\t\t\tcomma = JoinWithComma(comma, Expr{Loc: templateLoc, Data: template})\n\t\t\t}\n\t\t\treturn comma\n\t\t} else if e.CanBeUnwrappedIfUnused {\n\t\t\t// If the function call was annotated as being able to be removed if the\n\t\t\t// result is unused, then we can remove it and just keep the arguments.\n\t\t\t// Note that there are no implicit \"ToString\" operations for tagged\n\t\t\t// template literals.\n\t\t\tvar comma Expr\n\t\t\tfor _, part := range e.Parts {\n\t\t\t\tcomma = JoinWithComma(comma, ctx.SimplifyUnusedExpr(part.Value, unsupportedFeatures))\n\t\t\t}\n\t\t\treturn comma\n\t\t}\n\n\tcase *EArray:\n\t\t// Arrays with \"...\" spread expressions can't be unwrapped because the\n\t\t// \"...\" triggers code evaluation via iterators. In that case, just trim\n\t\t// the other items instead and leave the array expression there.\n\t\tfor _, spread := range e.Items {\n\t\t\tif _, ok := spread.Data.(*ESpread); ok {\n\t\t\t\titems := make([]Expr, 0, len(e.Items))\n\t\t\t\tfor _, item := range e.Items {\n\t\t\t\t\titem = ctx.SimplifyUnusedExpr(item, unsupportedFeatures)\n\t\t\t\t\tif item.Data != nil {\n\t\t\t\t\t\titems = append(items, item)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Don't mutate the original AST\n\t\t\t\tclone := *e\n\t\t\t\tclone.Items = items\n\t\t\t\treturn Expr{Loc: expr.Loc, Data: &clone}\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise, the array can be completely removed. We only need to keep any\n\t\t// array items with side effects. Apply this simplification recursively.\n\t\tvar result Expr\n\t\tfor _, item := range e.Items {\n\t\t\tresult = JoinWithComma(result, ctx.SimplifyUnusedExpr(item, unsupportedFeatures))\n\t\t}\n\t\treturn result\n\n\tcase *EObject:\n\t\t// Objects with \"...\" spread expressions can't be unwrapped because the\n\t\t// \"...\" triggers code evaluation via getters. In that case, just trim\n\t\t// the other items instead and leave the object expression there.\n\t\tfor _, spread := range e.Properties {\n\t\t\tif spread.Kind == PropertySpread {\n\t\t\t\tproperties := make([]Property, 0, len(e.Properties))\n\t\t\t\tfor _, property := range e.Properties {\n\t\t\t\t\t// Spread properties must always be evaluated\n\t\t\t\t\tif property.Kind != PropertySpread {\n\t\t\t\t\t\tvalue := ctx.SimplifyUnusedExpr(property.ValueOrNil, unsupportedFeatures)\n\t\t\t\t\t\tif value.Data != nil {\n\t\t\t\t\t\t\t// Keep the value\n\t\t\t\t\t\t\tproperty.ValueOrNil = value\n\t\t\t\t\t\t} else if !property.Flags.Has(PropertyIsComputed) {\n\t\t\t\t\t\t\t// Skip this property if the key doesn't need to be computed\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Replace values without side effects with \"0\" because it's short\n\t\t\t\t\t\t\tproperty.ValueOrNil.Data = &ENumber{}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tproperties = append(properties, property)\n\t\t\t\t}\n\n\t\t\t\t// Don't mutate the original AST\n\t\t\t\tclone := *e\n\t\t\t\tclone.Properties = properties\n\t\t\t\treturn Expr{Loc: expr.Loc, Data: &clone}\n\t\t\t}\n\t\t}\n\n\t\t// Otherwise, the object can be completely removed. We only need to keep any\n\t\t// object properties with side effects. Apply this simplification recursively.\n\t\tvar result Expr\n\t\tfor _, property := range e.Properties {\n\t\t\tif property.Flags.Has(PropertyIsComputed) {\n\t\t\t\t// Make sure \"ToString\" is still evaluated on the key\n\t\t\t\tresult = JoinWithComma(result, Expr{Loc: property.Key.Loc, Data: &EBinary{\n\t\t\t\t\tOp:    BinOpAdd,\n\t\t\t\t\tLeft:  property.Key,\n\t\t\t\t\tRight: Expr{Loc: property.Key.Loc, Data: &EString{}},\n\t\t\t\t}})\n\t\t\t}\n\t\t\tresult = JoinWithComma(result, ctx.SimplifyUnusedExpr(property.ValueOrNil, unsupportedFeatures))\n\t\t}\n\t\treturn result\n\n\tcase *EIf:\n\t\tyes := ctx.SimplifyUnusedExpr(e.Yes, unsupportedFeatures)\n\t\tno := ctx.SimplifyUnusedExpr(e.No, unsupportedFeatures)\n\n\t\t// \"foo() ? 1 : 2\" => \"foo()\"\n\t\tif yes.Data == nil && no.Data == nil {\n\t\t\treturn ctx.SimplifyUnusedExpr(e.Test, unsupportedFeatures)\n\t\t}\n\n\t\t// \"foo() ? 1 : bar()\" => \"foo() || bar()\"\n\t\tif yes.Data == nil {\n\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalOr, e.Test, no)\n\t\t}\n\n\t\t// \"foo() ? bar() : 2\" => \"foo() && bar()\"\n\t\tif no.Data == nil {\n\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalAnd, e.Test, yes)\n\t\t}\n\n\t\tif yes != e.Yes || no != e.No {\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EIf{Test: e.Test, Yes: yes, No: no}}\n\t\t}\n\n\tcase *EUnary:\n\t\tswitch e.Op {\n\t\t// These operators must not have any type conversions that can execute code\n\t\t// such as \"toString\" or \"valueOf\". They must also never throw any exceptions.\n\t\tcase UnOpVoid, UnOpNot:\n\t\t\treturn ctx.SimplifyUnusedExpr(e.Value, unsupportedFeatures)\n\n\t\tcase UnOpNeg:\n\t\t\tif _, ok := e.Value.Data.(*EBigInt); ok {\n\t\t\t\t// Consider negated bigints to have no side effects\n\t\t\t\treturn Expr{}\n\t\t\t}\n\n\t\tcase UnOpTypeof:\n\t\t\tif _, ok := e.Value.Data.(*EIdentifier); ok && e.WasOriginallyTypeofIdentifier {\n\t\t\t\t// \"typeof x\" must not be transformed into if \"x\" since doing so could\n\t\t\t\t// cause an exception to be thrown. Instead we can just remove it since\n\t\t\t\t// \"typeof x\" is special-cased in the standard to never throw.\n\t\t\t\treturn Expr{}\n\t\t\t}\n\t\t\treturn ctx.SimplifyUnusedExpr(e.Value, unsupportedFeatures)\n\t\t}\n\n\tcase *EBinary:\n\t\tleft := e.Left\n\t\tright := e.Right\n\n\t\tswitch e.Op {\n\t\t// These operators must not have any type conversions that can execute code\n\t\t// such as \"toString\" or \"valueOf\". They must also never throw any exceptions.\n\t\tcase BinOpStrictEq, BinOpStrictNe, BinOpComma:\n\t\t\treturn JoinWithComma(ctx.SimplifyUnusedExpr(left, unsupportedFeatures), ctx.SimplifyUnusedExpr(right, unsupportedFeatures))\n\n\t\t// We can simplify \"==\" and \"!=\" even though they can call \"toString\" and/or\n\t\t// \"valueOf\" if we can statically determine that the types of both sides are\n\t\t// primitives. In that case there won't be any chance for user-defined\n\t\t// \"toString\" and/or \"valueOf\" to be called.\n\t\tcase BinOpLooseEq, BinOpLooseNe:\n\t\t\tif MergedKnownPrimitiveTypes(left, right) != PrimitiveUnknown {\n\t\t\t\treturn JoinWithComma(ctx.SimplifyUnusedExpr(left, unsupportedFeatures), ctx.SimplifyUnusedExpr(right, unsupportedFeatures))\n\t\t\t}\n\n\t\tcase BinOpLogicalAnd, BinOpLogicalOr, BinOpNullishCoalescing:\n\t\t\t// If this is a boolean logical operation and the result is unused, then\n\t\t\t// we know the left operand will only be used for its boolean value and\n\t\t\t// can be simplified under that assumption\n\t\t\tif e.Op != BinOpNullishCoalescing {\n\t\t\t\tleft = ctx.SimplifyBooleanExpr(left)\n\t\t\t}\n\n\t\t\t// Preserve short-circuit behavior: the left expression is only unused if\n\t\t\t// the right expression can be completely removed. Otherwise, the left\n\t\t\t// expression is important for the branch.\n\t\t\tright = ctx.SimplifyUnusedExpr(right, unsupportedFeatures)\n\t\t\tif right.Data == nil {\n\t\t\t\treturn ctx.SimplifyUnusedExpr(left, unsupportedFeatures)\n\t\t\t}\n\n\t\t\t// Try to take advantage of the optional chain operator to shorten code\n\t\t\tif !unsupportedFeatures.Has(compat.OptionalChain) {\n\t\t\t\tif binary, ok := left.Data.(*EBinary); ok {\n\t\t\t\t\t// \"a != null && a.b()\" => \"a?.b()\"\n\t\t\t\t\t// \"a == null || a.b()\" => \"a?.b()\"\n\t\t\t\t\tif (binary.Op == BinOpLooseNe && e.Op == BinOpLogicalAnd) || (binary.Op == BinOpLooseEq && e.Op == BinOpLogicalOr) {\n\t\t\t\t\t\tvar test Expr\n\t\t\t\t\t\tif _, ok := binary.Right.Data.(*ENull); ok {\n\t\t\t\t\t\t\ttest = binary.Left\n\t\t\t\t\t\t} else if _, ok := binary.Left.Data.(*ENull); ok {\n\t\t\t\t\t\t\ttest = binary.Right\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Note: Technically unbound identifiers can refer to a getter on\n\t\t\t\t\t\t// the global object and that getter can have side effects that can\n\t\t\t\t\t\t// be observed if we run that getter once instead of twice. But this\n\t\t\t\t\t\t// seems like terrible coding practice and very unlikely to come up\n\t\t\t\t\t\t// in real software, so we deliberately ignore this possibility and\n\t\t\t\t\t\t// optimize for size instead of for this obscure edge case.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// If this is ever changed, then we must also pessimize the lowering\n\t\t\t\t\t\t// of \"foo?.bar\" to save the value of \"foo\" to ensure that it's only\n\t\t\t\t\t\t// evaluated once. Specifically \"foo?.bar\" would have to expand to:\n\t\t\t\t\t\t//\n\t\t\t\t\t\t//   var _a;\n\t\t\t\t\t\t//   (_a = foo) == null ? void 0 : _a.bar;\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// instead of:\n\t\t\t\t\t\t//\n\t\t\t\t\t\t//   foo == null ? void 0 : foo.bar;\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Babel does the first one while TypeScript does the second one.\n\t\t\t\t\t\t// Since TypeScript doesn't handle this extreme edge case and\n\t\t\t\t\t\t// TypeScript is very widely used, I think it's fine for us to not\n\t\t\t\t\t\t// handle this edge case either.\n\t\t\t\t\t\tif id, ok := test.Data.(*EIdentifier); ok && !id.MustKeepDueToWithStmt && TryToInsertOptionalChain(test, right) {\n\t\t\t\t\t\t\treturn right\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase BinOpAdd:\n\t\t\tif result, isStringAddition := simplifyUnusedStringAdditionChain(expr); isStringAddition {\n\t\t\t\treturn result\n\t\t\t}\n\t\t}\n\n\t\tif left != e.Left || right != e.Right {\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{Op: e.Op, Left: left, Right: right}}\n\t\t}\n\n\tcase *ECall:\n\t\t// A call that has been marked \"__PURE__\" can be removed if all arguments\n\t\t// can be removed. The annotation causes us to ignore the target.\n\t\tif e.CanBeUnwrappedIfUnused {\n\t\t\tvar result Expr\n\t\t\tfor _, arg := range e.Args {\n\t\t\t\tif _, ok := arg.Data.(*ESpread); ok {\n\t\t\t\t\targ.Data = &EArray{Items: []Expr{arg}, IsSingleLine: true}\n\t\t\t\t}\n\t\t\t\tresult = JoinWithComma(result, ctx.SimplifyUnusedExpr(arg, unsupportedFeatures))\n\t\t\t}\n\t\t\treturn result\n\t\t}\n\n\t\t// Attempt to shorten IIFEs\n\t\tif len(e.Args) == 0 {\n\t\t\tswitch target := e.Target.Data.(type) {\n\t\t\tcase *EFunction:\n\t\t\t\tif len(target.Fn.Args) != 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// Just delete \"(function() {})()\" completely\n\t\t\t\tif len(target.Fn.Body.Block.Stmts) == 0 {\n\t\t\t\t\treturn Expr{}\n\t\t\t\t}\n\n\t\t\tcase *EArrow:\n\t\t\t\tif len(target.Args) != 0 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\t// Just delete \"(() => {})()\" completely\n\t\t\t\tif len(target.Body.Block.Stmts) == 0 {\n\t\t\t\t\treturn Expr{}\n\t\t\t\t}\n\n\t\t\t\tif len(target.Body.Block.Stmts) == 1 {\n\t\t\t\t\tswitch s := target.Body.Block.Stmts[0].Data.(type) {\n\t\t\t\t\tcase *SExpr:\n\t\t\t\t\t\tif !target.IsAsync {\n\t\t\t\t\t\t\t// Replace \"(() => { foo() })()\" with \"foo()\"\n\t\t\t\t\t\t\treturn s.Value\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Replace \"(async () => { foo() })()\" with \"(async () => foo())()\"\n\t\t\t\t\t\t\tclone := *target\n\t\t\t\t\t\t\tclone.Body.Block.Stmts[0].Data = &SReturn{ValueOrNil: s.Value}\n\t\t\t\t\t\t\tclone.PreferExpr = true\n\t\t\t\t\t\t\treturn Expr{Loc: expr.Loc, Data: &ECall{Target: Expr{Loc: e.Target.Loc, Data: &clone}}}\n\t\t\t\t\t\t}\n\n\t\t\t\t\tcase *SReturn:\n\t\t\t\t\t\tif !target.IsAsync {\n\t\t\t\t\t\t\t// Replace \"(() => foo())()\" with \"foo()\"\n\t\t\t\t\t\t\treturn s.ValueOrNil\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tcase *ENew:\n\t\t// A constructor call that has been marked \"__PURE__\" can be removed if all\n\t\t// arguments can be removed. The annotation causes us to ignore the target.\n\t\tif e.CanBeUnwrappedIfUnused {\n\t\t\tvar result Expr\n\t\t\tfor _, arg := range e.Args {\n\t\t\t\tif _, ok := arg.Data.(*ESpread); ok {\n\t\t\t\t\targ.Data = &EArray{Items: []Expr{arg}, IsSingleLine: true}\n\t\t\t\t}\n\t\t\t\tresult = JoinWithComma(result, ctx.SimplifyUnusedExpr(arg, unsupportedFeatures))\n\t\t\t}\n\t\t\treturn result\n\t\t}\n\t}\n\n\treturn expr\n}\n\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc simplifyUnusedStringAdditionChain(expr Expr) (Expr, bool) {\n\tswitch e := expr.Data.(type) {\n\tcase *EString:\n\t\t// \"'x' + y\" => \"'' + y\"\n\t\treturn Expr{Loc: expr.Loc, Data: &EString{}}, true\n\n\tcase *EBinary:\n\t\tif e.Op == BinOpAdd {\n\t\t\tleft, leftIsStringAddition := simplifyUnusedStringAdditionChain(e.Left)\n\n\t\t\tif right, rightIsString := e.Right.Data.(*EString); rightIsString {\n\t\t\t\t// \"('' + x) + 'y'\" => \"'' + x\"\n\t\t\t\tif leftIsStringAddition {\n\t\t\t\t\treturn left, true\n\t\t\t\t}\n\n\t\t\t\t// \"x + 'y'\" => \"x + ''\"\n\t\t\t\tif !leftIsStringAddition && len(right.Value) > 0 {\n\t\t\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{\n\t\t\t\t\t\tOp:    BinOpAdd,\n\t\t\t\t\t\tLeft:  left,\n\t\t\t\t\t\tRight: Expr{Loc: e.Right.Loc, Data: &EString{}},\n\t\t\t\t\t}}, true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Don't mutate the original AST\n\t\t\tif left != e.Left {\n\t\t\t\texpr.Data = &EBinary{Op: BinOpAdd, Left: left, Right: e.Right}\n\t\t\t}\n\n\t\t\treturn expr, leftIsStringAddition\n\t\t}\n\t}\n\n\treturn expr, false\n}\n\nfunc ToInt32(f float64) int32 {\n\t// The easy way\n\ti := int32(f)\n\tif float64(i) == f {\n\t\treturn i\n\t}\n\n\t// Special-case non-finite numbers (casting them is unspecified behavior in Go)\n\tif math.IsNaN(f) || math.IsInf(f, 0) {\n\t\treturn 0\n\t}\n\n\t// The hard way\n\ti = int32(uint32(math.Mod(math.Abs(f), 4294967296)))\n\tif math.Signbit(f) {\n\t\treturn -i\n\t}\n\treturn i\n}\n\nfunc ToUint32(f float64) uint32 {\n\treturn uint32(ToInt32(f))\n}\n\n// If this returns true, we know the result can't be NaN\nfunc isInt32OrUint32(data E) bool {\n\tswitch e := data.(type) {\n\tcase *EBinary:\n\t\tswitch e.Op {\n\t\tcase BinOpUShr: // This is the only bitwise operator that can't return a bigint (because it throws instead)\n\t\t\treturn true\n\n\t\tcase BinOpLogicalOr, BinOpLogicalAnd:\n\t\t\treturn isInt32OrUint32(e.Left.Data) && isInt32OrUint32(e.Right.Data)\n\t\t}\n\n\tcase *EIf:\n\t\treturn isInt32OrUint32(e.Yes.Data) && isInt32OrUint32(e.No.Data)\n\t}\n\treturn false\n}\n\nfunc ToNumberWithoutSideEffects(data E) (float64, bool) {\n\tswitch e := data.(type) {\n\tcase *EAnnotation:\n\t\treturn ToNumberWithoutSideEffects(e.Value.Data)\n\n\tcase *EInlinedEnum:\n\t\treturn ToNumberWithoutSideEffects(e.Value.Data)\n\n\tcase *ENull:\n\t\treturn 0, true\n\n\tcase *EUndefined, *ERegExp:\n\t\treturn math.NaN(), true\n\n\tcase *EArray:\n\t\tif len(e.Items) == 0 {\n\t\t\t// \"+[]\" => \"0\"\n\t\t\treturn 0, true\n\t\t}\n\n\tcase *EObject:\n\t\tif len(e.Properties) == 0 {\n\t\t\t// \"+{}\" => \"NaN\"\n\t\t\treturn math.NaN(), true\n\t\t}\n\n\tcase *EBoolean:\n\t\tif e.Value {\n\t\t\treturn 1, true\n\t\t} else {\n\t\t\treturn 0, true\n\t\t}\n\n\tcase *ENumber:\n\t\treturn e.Value, true\n\n\tcase *EString:\n\t\t// \"+''\" => \"0\"\n\t\tif len(e.Value) == 0 {\n\t\t\treturn 0, true\n\t\t}\n\n\t\t// \"+'1'\" => \"1\"\n\t\tif num, ok := StringToEquivalentNumberValue(e.Value); ok {\n\t\t\treturn num, true\n\t\t}\n\t}\n\n\treturn 0, false\n}\n\nfunc ToStringWithoutSideEffects(data E) (string, bool) {\n\tswitch e := data.(type) {\n\tcase *ENull:\n\t\treturn \"null\", true\n\n\tcase *EUndefined:\n\t\treturn \"undefined\", true\n\n\tcase *EBoolean:\n\t\tif e.Value {\n\t\t\treturn \"true\", true\n\t\t} else {\n\t\t\treturn \"false\", true\n\t\t}\n\n\tcase *EBigInt:\n\t\t// Only do this if there is no radix\n\t\tif len(e.Value) < 2 || e.Value[0] != '0' {\n\t\t\treturn e.Value, true\n\t\t}\n\n\tcase *ENumber:\n\t\tif str, ok := TryToStringOnNumberSafely(e.Value, 10); ok {\n\t\t\treturn str, true\n\t\t}\n\n\tcase *ERegExp:\n\t\treturn e.Value, true\n\n\tcase *EDot:\n\t\t// This is dumb but some JavaScript obfuscators use this to generate string literals\n\t\tif e.Name == \"constructor\" {\n\t\t\tswitch e.Target.Data.(type) {\n\t\t\tcase *EString:\n\t\t\t\treturn \"function String() { [native code] }\", true\n\n\t\t\tcase *ERegExp:\n\t\t\t\treturn \"function RegExp() { [native code] }\", true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\", false\n}\n\nfunc extractNumericValue(data E) (float64, bool) {\n\tswitch e := data.(type) {\n\tcase *EAnnotation:\n\t\treturn extractNumericValue(e.Value.Data)\n\n\tcase *EInlinedEnum:\n\t\treturn extractNumericValue(e.Value.Data)\n\n\tcase *ENumber:\n\t\treturn e.Value, true\n\t}\n\n\treturn 0, false\n}\n\nfunc extractNumericValues(left Expr, right Expr) (float64, float64, bool) {\n\tif a, ok := extractNumericValue(left.Data); ok {\n\t\tif b, ok := extractNumericValue(right.Data); ok {\n\t\t\treturn a, b, true\n\t\t}\n\t}\n\treturn 0, 0, false\n}\n\nfunc extractStringValue(data E) ([]uint16, bool) {\n\tswitch e := data.(type) {\n\tcase *EAnnotation:\n\t\treturn extractStringValue(e.Value.Data)\n\n\tcase *EInlinedEnum:\n\t\treturn extractStringValue(e.Value.Data)\n\n\tcase *EString:\n\t\treturn e.Value, true\n\t}\n\n\treturn nil, false\n}\n\nfunc extractStringValues(left Expr, right Expr) ([]uint16, []uint16, bool) {\n\tif a, ok := extractStringValue(left.Data); ok {\n\t\tif b, ok := extractStringValue(right.Data); ok {\n\t\t\treturn a, b, true\n\t\t}\n\t}\n\treturn nil, nil, false\n}\n\nfunc stringCompareUCS2(a []uint16, b []uint16) int {\n\tvar n int\n\tif len(a) < len(b) {\n\t\tn = len(a)\n\t} else {\n\t\tn = len(b)\n\t}\n\tfor i := 0; i < n; i++ {\n\t\tif delta := int(a[i]) - int(b[i]); delta != 0 {\n\t\t\treturn delta\n\t\t}\n\t}\n\treturn len(a) - len(b)\n}\n\nfunc approximatePrintedIntCharCount(intValue float64) int {\n\tcount := 1 + (int)(math.Max(0, math.Floor(math.Log10(math.Abs(intValue)))))\n\tif intValue < 0 {\n\t\tcount++\n\t}\n\treturn count\n}\n\nfunc ShouldFoldBinaryOperatorWhenMinifying(binary *EBinary) bool {\n\tswitch binary.Op {\n\tcase\n\t\t// Equality tests should always result in smaller code when folded\n\t\tBinOpLooseEq,\n\t\tBinOpLooseNe,\n\t\tBinOpStrictEq,\n\t\tBinOpStrictNe,\n\n\t\t// Minification always folds right signed shift operations since they are\n\t\t// unlikely to result in larger output. Note: \">>>\" could result in\n\t\t// bigger output such as \"-1 >>> 0\" becoming \"4294967295\".\n\t\tBinOpShr,\n\n\t\t// Minification always folds the following bitwise operations since they\n\t\t// are unlikely to result in larger output.\n\t\tBinOpBitwiseAnd,\n\t\tBinOpBitwiseOr,\n\t\tBinOpBitwiseXor,\n\t\tBinOpLt,\n\t\tBinOpGt,\n\t\tBinOpLe,\n\t\tBinOpGe:\n\t\treturn true\n\n\tcase BinOpAdd:\n\t\t// Addition of small-ish integers can definitely be folded without issues\n\t\t// \"1 + 2\" => \"3\"\n\t\tif left, right, ok := extractNumericValues(binary.Left, binary.Right); ok &&\n\t\t\tleft == math.Trunc(left) && math.Abs(left) <= 0xFFFF_FFFF &&\n\t\t\tright == math.Trunc(right) && math.Abs(right) <= 0xFFFF_FFFF {\n\t\t\treturn true\n\t\t}\n\n\t\t// String addition should pretty much always be more compact when folded\n\t\tif _, _, ok := extractStringValues(binary.Left, binary.Right); ok {\n\t\t\treturn true\n\t\t}\n\n\tcase BinOpSub:\n\t\t// Subtraction of small-ish integers can definitely be folded without issues\n\t\t// \"3 - 1\" => \"2\"\n\t\tif left, right, ok := extractNumericValues(binary.Left, binary.Right); ok &&\n\t\t\tleft == math.Trunc(left) && math.Abs(left) <= 0xFFFF_FFFF &&\n\t\t\tright == math.Trunc(right) && math.Abs(right) <= 0xFFFF_FFFF {\n\t\t\treturn true\n\t\t}\n\n\tcase BinOpMul:\n\t\t// Allow multiplication of small-ish integers to be folded\n\t\t// \"1 * 2\" => \"3\"\n\t\tif left, right, ok := extractNumericValues(binary.Left, binary.Right); ok &&\n\t\t\tleft == math.Trunc(left) && math.Abs(left) <= 0xFF &&\n\t\t\tright == math.Trunc(right) && math.Abs(right) <= 0xFF {\n\t\t\treturn true\n\t\t}\n\n\tcase BinOpDiv:\n\t\t// \"0/0\" => \"NaN\"\n\t\t// \"1/0\" => \"Infinity\"\n\t\t// \"1/-0\" => \"-Infinity\"\n\t\tif _, right, ok := extractNumericValues(binary.Left, binary.Right); ok && right == 0 {\n\t\t\treturn true\n\t\t}\n\n\tcase BinOpShl:\n\t\t// \"1 << 3\" => \"8\"\n\t\t// \"1 << 24\" => \"1 << 24\" (since \"1<<24\" is shorter than \"16777216\")\n\t\tif left, right, ok := extractNumericValues(binary.Left, binary.Right); ok {\n\t\t\tleftLen := approximatePrintedIntCharCount(left)\n\t\t\trightLen := approximatePrintedIntCharCount(right)\n\t\t\tresultLen := approximatePrintedIntCharCount(float64(ToInt32(left) << (ToUint32(right) & 31)))\n\t\t\treturn resultLen <= leftLen+2+rightLen\n\t\t}\n\n\tcase BinOpUShr:\n\t\t// \"10 >>> 1\" => \"5\"\n\t\t// \"-1 >>> 0\" => \"-1 >>> 0\" (since \"-1>>>0\" is shorter than \"4294967295\")\n\t\tif left, right, ok := extractNumericValues(binary.Left, binary.Right); ok {\n\t\t\tleftLen := approximatePrintedIntCharCount(left)\n\t\t\trightLen := approximatePrintedIntCharCount(right)\n\t\t\tresultLen := approximatePrintedIntCharCount(float64(ToUint32(left) >> (ToUint32(right) & 31)))\n\t\t\treturn resultLen <= leftLen+3+rightLen\n\t\t}\n\n\tcase BinOpLogicalAnd, BinOpLogicalOr, BinOpNullishCoalescing:\n\t\tif IsPrimitiveLiteral(binary.Left.Data) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc FoldBinaryOperator(loc logger.Loc, e *EBinary) Expr {\n\tswitch e.Op {\n\tcase BinOpAdd:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: left + right}}\n\t\t}\n\t\tif left, right, ok := extractStringValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EString{Value: joinStrings(left, right)}}\n\t\t}\n\n\tcase BinOpSub:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: left - right}}\n\t\t}\n\n\tcase BinOpMul:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: left * right}}\n\t\t}\n\n\tcase BinOpDiv:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: left / right}}\n\t\t}\n\n\tcase BinOpRem:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: math.Mod(left, right)}}\n\t\t}\n\n\tcase BinOpPow:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: math.Pow(left, right)}}\n\t\t}\n\n\tcase BinOpShl:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: float64(ToInt32(left) << (ToUint32(right) & 31))}}\n\t\t}\n\n\tcase BinOpShr:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: float64(ToInt32(left) >> (ToUint32(right) & 31))}}\n\t\t}\n\n\tcase BinOpUShr:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: float64(ToUint32(left) >> (ToUint32(right) & 31))}}\n\t\t}\n\n\tcase BinOpBitwiseAnd:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: float64(ToInt32(left) & ToInt32(right))}}\n\t\t}\n\n\tcase BinOpBitwiseOr:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: float64(ToInt32(left) | ToInt32(right))}}\n\t\t}\n\n\tcase BinOpBitwiseXor:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &ENumber{Value: float64(ToInt32(left) ^ ToInt32(right))}}\n\t\t}\n\n\tcase BinOpLt:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: left < right}}\n\t\t}\n\t\tif left, right, ok := extractStringValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: stringCompareUCS2(left, right) < 0}}\n\t\t}\n\n\tcase BinOpGt:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: left > right}}\n\t\t}\n\t\tif left, right, ok := extractStringValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: stringCompareUCS2(left, right) > 0}}\n\t\t}\n\n\tcase BinOpLe:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: left <= right}}\n\t\t}\n\t\tif left, right, ok := extractStringValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: stringCompareUCS2(left, right) <= 0}}\n\t\t}\n\n\tcase BinOpGe:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: left >= right}}\n\t\t}\n\t\tif left, right, ok := extractStringValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: stringCompareUCS2(left, right) >= 0}}\n\t\t}\n\n\tcase BinOpLooseEq, BinOpStrictEq:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: left == right}}\n\t\t}\n\t\tif left, right, ok := extractStringValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: stringCompareUCS2(left, right) == 0}}\n\t\t}\n\n\tcase BinOpLooseNe, BinOpStrictNe:\n\t\tif left, right, ok := extractNumericValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: left != right}}\n\t\t}\n\t\tif left, right, ok := extractStringValues(e.Left, e.Right); ok {\n\t\t\treturn Expr{Loc: loc, Data: &EBoolean{Value: stringCompareUCS2(left, right) != 0}}\n\t\t}\n\n\tcase BinOpLogicalAnd:\n\t\tif boolean, sideEffects, ok := ToBooleanWithSideEffects(e.Left.Data); ok {\n\t\t\tif !boolean {\n\t\t\t\treturn e.Left\n\t\t\t} else if sideEffects == NoSideEffects {\n\t\t\t\treturn e.Right\n\t\t\t}\n\t\t}\n\n\tcase BinOpLogicalOr:\n\t\tif boolean, sideEffects, ok := ToBooleanWithSideEffects(e.Left.Data); ok {\n\t\t\tif boolean {\n\t\t\t\treturn e.Left\n\t\t\t} else if sideEffects == NoSideEffects {\n\t\t\t\treturn e.Right\n\t\t\t}\n\t\t}\n\n\tcase BinOpNullishCoalescing:\n\t\tif isNullOrUndefined, sideEffects, ok := ToNullOrUndefinedWithSideEffects(e.Left.Data); ok {\n\t\t\tif !isNullOrUndefined {\n\t\t\t\treturn e.Left\n\t\t\t} else if sideEffects == NoSideEffects {\n\t\t\t\treturn e.Right\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Expr{}\n}\n\nfunc IsBinaryNullAndUndefined(left Expr, right Expr, op OpCode) (Expr, Expr, bool) {\n\tif a, ok := left.Data.(*EBinary); ok && a.Op == op {\n\t\tif b, ok := right.Data.(*EBinary); ok && b.Op == op {\n\t\t\tidA, eqA := a.Left, a.Right\n\t\t\tidB, eqB := b.Left, b.Right\n\n\t\t\t// Detect when the identifier comes second and flip the order of our checks\n\t\t\tif _, ok := eqA.Data.(*EIdentifier); ok {\n\t\t\t\tidA, eqA = eqA, idA\n\t\t\t}\n\t\t\tif _, ok := eqB.Data.(*EIdentifier); ok {\n\t\t\t\tidB, eqB = eqB, idB\n\t\t\t}\n\n\t\t\tif idA, ok := idA.Data.(*EIdentifier); ok {\n\t\t\t\tif idB, ok := idB.Data.(*EIdentifier); ok && idA.Ref == idB.Ref {\n\t\t\t\t\t// \"a === null || a === void 0\"\n\t\t\t\t\tif _, ok := eqA.Data.(*ENull); ok {\n\t\t\t\t\t\tif _, ok := eqB.Data.(*EUndefined); ok {\n\t\t\t\t\t\t\treturn a.Left, a.Right, true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// \"a === void 0 || a === null\"\n\t\t\t\t\tif _, ok := eqA.Data.(*EUndefined); ok {\n\t\t\t\t\t\tif _, ok := eqB.Data.(*ENull); ok {\n\t\t\t\t\t\t\treturn b.Left, b.Right, true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Expr{}, Expr{}, false\n}\n\nfunc CheckEqualityBigInt(a string, b string) (equal bool, ok bool) {\n\t// Equal literals are always equal\n\tif a == b {\n\t\treturn true, true\n\t}\n\n\t// Unequal literals are unequal if neither has a radix. Leading zeros are\n\t// disallowed in bigint literals without a radix, so in this case we know\n\t// each value is in canonical form.\n\tif (len(a) < 2 || a[0] != '0') && (len(b) < 2 || b[0] != '0') {\n\t\treturn false, true\n\t}\n\n\treturn false, false\n}\n\ntype EqualityKind uint8\n\nconst (\n\tLooseEquality EqualityKind = iota\n\tStrictEquality\n)\n\n// Returns \"equal, ok\". If \"ok\" is false, then nothing is known about the two\n// values. If \"ok\" is true, the equality or inequality of the two values is\n// stored in \"equal\".\nfunc CheckEqualityIfNoSideEffects(left E, right E, kind EqualityKind) (equal bool, ok bool) {\n\tif r, ok := right.(*EInlinedEnum); ok {\n\t\treturn CheckEqualityIfNoSideEffects(left, r.Value.Data, kind)\n\t}\n\n\tswitch l := left.(type) {\n\tcase *EInlinedEnum:\n\t\treturn CheckEqualityIfNoSideEffects(l.Value.Data, right, kind)\n\n\tcase *ENull:\n\t\tswitch right.(type) {\n\t\tcase *ENull:\n\t\t\t// \"null === null\" is true\n\t\t\treturn true, true\n\n\t\tcase *EUndefined:\n\t\t\t// \"null == undefined\" is true\n\t\t\t// \"null === undefined\" is false\n\t\t\treturn kind == LooseEquality, true\n\n\t\tdefault:\n\t\t\tif IsPrimitiveLiteral(right) {\n\t\t\t\t// \"null == (not null or undefined)\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\t\t}\n\n\tcase *EUndefined:\n\t\tswitch right.(type) {\n\t\tcase *EUndefined:\n\t\t\t// \"undefined === undefined\" is true\n\t\t\treturn true, true\n\n\t\tcase *ENull:\n\t\t\t// \"undefined == null\" is true\n\t\t\t// \"undefined === null\" is false\n\t\t\treturn kind == LooseEquality, true\n\n\t\tdefault:\n\t\t\tif IsPrimitiveLiteral(right) {\n\t\t\t\t// \"undefined == (not null or undefined)\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\t\t}\n\n\tcase *EBoolean:\n\t\tswitch r := right.(type) {\n\t\tcase *EBoolean:\n\t\t\t// \"false === false\" is true\n\t\t\t// \"false === true\" is false\n\t\t\treturn l.Value == r.Value, true\n\n\t\tcase *ENumber:\n\t\t\tif kind == LooseEquality {\n\t\t\t\tif l.Value {\n\t\t\t\t\t// \"true == 1\" is true\n\t\t\t\t\treturn r.Value == 1, true\n\t\t\t\t} else {\n\t\t\t\t\t// \"false == 0\" is true\n\t\t\t\t\treturn r.Value == 0, true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// \"true === 1\" is false\n\t\t\t\t// \"false === 0\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\n\t\tcase *ENull, *EUndefined:\n\t\t\t// \"(not null or undefined) == undefined\" is false\n\t\t\treturn false, true\n\n\t\tdefault:\n\t\t\tif kind == StrictEquality && IsPrimitiveLiteral(right) {\n\t\t\t\t// \"boolean === (not boolean)\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\t\t}\n\n\tcase *ENumber:\n\t\tswitch r := right.(type) {\n\t\tcase *ENumber:\n\t\t\t// \"0 === 0\" is true\n\t\t\t// \"0 === 1\" is false\n\t\t\treturn l.Value == r.Value, true\n\n\t\tcase *EBoolean:\n\t\t\tif kind == LooseEquality {\n\t\t\t\tif r.Value {\n\t\t\t\t\t// \"1 == true\" is true\n\t\t\t\t\treturn l.Value == 1, true\n\t\t\t\t} else {\n\t\t\t\t\t// \"0 == false\" is true\n\t\t\t\t\treturn l.Value == 0, true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// \"1 === true\" is false\n\t\t\t\t// \"0 === false\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\n\t\tcase *ENull, *EUndefined:\n\t\t\t// \"(not null or undefined) == undefined\" is false\n\t\t\treturn false, true\n\n\t\tdefault:\n\t\t\tif kind == StrictEquality && IsPrimitiveLiteral(right) {\n\t\t\t\t// \"number === (not number)\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\t\t}\n\n\tcase *EBigInt:\n\t\tswitch r := right.(type) {\n\t\tcase *EBigInt:\n\t\t\t// \"0n === 0n\" is true\n\t\t\t// \"0n === 1n\" is false\n\t\t\treturn CheckEqualityBigInt(l.Value, r.Value)\n\n\t\tcase *ENull, *EUndefined:\n\t\t\t// \"(not null or undefined) == undefined\" is false\n\t\t\treturn false, true\n\n\t\tdefault:\n\t\t\tif kind == StrictEquality && IsPrimitiveLiteral(right) {\n\t\t\t\t// \"bigint === (not bigint)\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\t\t}\n\n\tcase *EString:\n\t\tswitch r := right.(type) {\n\t\tcase *EString:\n\t\t\t// \"'a' === 'a'\" is true\n\t\t\t// \"'a' === 'b'\" is false\n\t\t\treturn helpers.UTF16EqualsUTF16(l.Value, r.Value), true\n\n\t\tcase *ENull, *EUndefined:\n\t\t\t// \"(not null or undefined) == undefined\" is false\n\t\t\treturn false, true\n\n\t\tdefault:\n\t\t\tif kind == StrictEquality && IsPrimitiveLiteral(right) {\n\t\t\t\t// \"string === (not string)\" is false\n\t\t\t\treturn false, true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false, false\n}\n\nfunc ValuesLookTheSame(left E, right E) bool {\n\tif b, ok := right.(*EInlinedEnum); ok {\n\t\treturn ValuesLookTheSame(left, b.Value.Data)\n\t}\n\n\tswitch a := left.(type) {\n\tcase *EInlinedEnum:\n\t\treturn ValuesLookTheSame(a.Value.Data, right)\n\n\tcase *EIdentifier:\n\t\tif b, ok := right.(*EIdentifier); ok && a.Ref == b.Ref {\n\t\t\treturn true\n\t\t}\n\n\tcase *EDot:\n\t\tif b, ok := right.(*EDot); ok && a.HasSameFlagsAs(b) &&\n\t\t\ta.Name == b.Name && ValuesLookTheSame(a.Target.Data, b.Target.Data) {\n\t\t\treturn true\n\t\t}\n\n\tcase *EIndex:\n\t\tif b, ok := right.(*EIndex); ok && a.HasSameFlagsAs(b) &&\n\t\t\tValuesLookTheSame(a.Target.Data, b.Target.Data) && ValuesLookTheSame(a.Index.Data, b.Index.Data) {\n\t\t\treturn true\n\t\t}\n\n\tcase *EIf:\n\t\tif b, ok := right.(*EIf); ok && ValuesLookTheSame(a.Test.Data, b.Test.Data) &&\n\t\t\tValuesLookTheSame(a.Yes.Data, b.Yes.Data) && ValuesLookTheSame(a.No.Data, b.No.Data) {\n\t\t\treturn true\n\t\t}\n\n\tcase *EUnary:\n\t\tif b, ok := right.(*EUnary); ok && a.Op == b.Op && ValuesLookTheSame(a.Value.Data, b.Value.Data) {\n\t\t\treturn true\n\t\t}\n\n\tcase *EBinary:\n\t\tif b, ok := right.(*EBinary); ok && a.Op == b.Op && ValuesLookTheSame(a.Left.Data, b.Left.Data) &&\n\t\t\tValuesLookTheSame(a.Right.Data, b.Right.Data) {\n\t\t\treturn true\n\t\t}\n\n\tcase *ECall:\n\t\tif b, ok := right.(*ECall); ok && a.HasSameFlagsAs(b) &&\n\t\t\tlen(a.Args) == len(b.Args) && ValuesLookTheSame(a.Target.Data, b.Target.Data) {\n\t\t\tfor i := range a.Args {\n\t\t\t\tif !ValuesLookTheSame(a.Args[i].Data, b.Args[i].Data) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\n\t// Special-case to distinguish between negative an non-negative zero when mangling\n\t// \"a ? -0 : 0\" => \"a ? -0 : 0\"\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness\n\tcase *ENumber:\n\t\tb, ok := right.(*ENumber)\n\t\tif ok && a.Value == 0 && b.Value == 0 && math.Signbit(a.Value) != math.Signbit(b.Value) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tequal, ok := CheckEqualityIfNoSideEffects(left, right, StrictEquality)\n\treturn ok && equal\n}\n\nfunc TryToInsertOptionalChain(test Expr, expr Expr) bool {\n\tswitch e := expr.Data.(type) {\n\tcase *EDot:\n\t\tif ValuesLookTheSame(test.Data, e.Target.Data) {\n\t\t\te.OptionalChain = OptionalChainStart\n\t\t\treturn true\n\t\t}\n\t\tif TryToInsertOptionalChain(test, e.Target) {\n\t\t\tif e.OptionalChain == OptionalChainNone {\n\t\t\t\te.OptionalChain = OptionalChainContinue\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\n\tcase *EIndex:\n\t\tif ValuesLookTheSame(test.Data, e.Target.Data) {\n\t\t\te.OptionalChain = OptionalChainStart\n\t\t\treturn true\n\t\t}\n\t\tif TryToInsertOptionalChain(test, e.Target) {\n\t\t\tif e.OptionalChain == OptionalChainNone {\n\t\t\t\te.OptionalChain = OptionalChainContinue\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\n\tcase *ECall:\n\t\tif ValuesLookTheSame(test.Data, e.Target.Data) {\n\t\t\te.OptionalChain = OptionalChainStart\n\t\t\treturn true\n\t\t}\n\t\tif TryToInsertOptionalChain(test, e.Target) {\n\t\t\tif e.OptionalChain == OptionalChainNone {\n\t\t\t\te.OptionalChain = OptionalChainContinue\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc joinStrings(a []uint16, b []uint16) []uint16 {\n\tdata := make([]uint16, len(a)+len(b))\n\tcopy(data[:len(a)], a)\n\tcopy(data[len(a):], b)\n\treturn data\n}\n\n// String concatenation with numbers is required by the TypeScript compiler for\n// \"constant expression\" handling in enums. However, we don't want to introduce\n// correctness bugs by accidentally stringifying a number differently than how\n// a real JavaScript VM would do it. So we are conservative and we only do this\n// when we know it'll be the same result.\nfunc TryToStringOnNumberSafely(n float64, radix int) (string, bool) {\n\tif i := int32(n); float64(i) == n {\n\t\treturn strconv.FormatInt(int64(i), radix), true\n\t}\n\tif math.IsNaN(n) {\n\t\treturn \"NaN\", true\n\t}\n\tif math.IsInf(n, 1) {\n\t\treturn \"Infinity\", true\n\t}\n\tif math.IsInf(n, -1) {\n\t\treturn \"-Infinity\", true\n\t}\n\treturn \"\", false\n}\n\n// Note: We don't know if this is string addition yet at this point\nfunc foldAdditionPreProcess(expr Expr) Expr {\n\tswitch e := expr.Data.(type) {\n\tcase *EInlinedEnum:\n\t\t// \"See through\" inline enum constants\n\t\texpr = e.Value\n\n\tcase *EArray:\n\t\t// \"[] + x\" => \"'' + x\"\n\t\t// \"[1,2] + x\" => \"'1,2' + x\"\n\t\titems := make([]string, 0, len(e.Items))\n\t\tfor _, item := range e.Items {\n\t\t\tswitch item.Data.(type) {\n\t\t\tcase *EUndefined, *ENull:\n\t\t\t\titems = append(items, \"\")\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif str, ok := ToStringWithoutSideEffects(item.Data); ok {\n\t\t\t\titem.Data = &EString{Value: helpers.StringToUTF16(str)}\n\t\t\t}\n\t\t\tstr, ok := item.Data.(*EString)\n\t\t\tif !ok {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\titems = append(items, helpers.UTF16ToString(str.Value))\n\t\t}\n\t\tif len(items) == len(e.Items) {\n\t\t\texpr.Data = &EString{Value: helpers.StringToUTF16(strings.Join(items, \",\"))}\n\t\t}\n\n\tcase *EObject:\n\t\t// \"{} + x\" => \"'[object Object]' + x\"\n\t\tif len(e.Properties) == 0 {\n\t\t\texpr.Data = &EString{Value: helpers.StringToUTF16(\"[object Object]\")}\n\t\t}\n\t}\n\treturn expr\n}\n\ntype StringAdditionKind uint8\n\nconst (\n\tStringAdditionNormal StringAdditionKind = iota\n\tStringAdditionWithNestedLeft\n)\n\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc FoldStringAddition(left Expr, right Expr, kind StringAdditionKind) Expr {\n\tleft = foldAdditionPreProcess(left)\n\tright = foldAdditionPreProcess(right)\n\n\t// Transforming the left operand into a string is not safe if it comes from\n\t// a nested AST node. The following transforms are invalid:\n\t//\n\t//   \"0 + 1 + 'x'\" => \"0 + '1x'\"\n\t//   \"0 + 1 + `${x}`\" => \"0 + `1${x}`\"\n\t//\n\tif kind != StringAdditionWithNestedLeft {\n\t\tswitch right.Data.(type) {\n\t\tcase *EString, *ETemplate:\n\t\t\tif str, ok := ToStringWithoutSideEffects(left.Data); ok {\n\t\t\t\tleft.Data = &EString{Value: helpers.StringToUTF16(str)}\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch l := left.Data.(type) {\n\tcase *EString:\n\t\t// \"'x' + 0\" => \"'x' + '0'\"\n\t\tif str, ok := ToStringWithoutSideEffects(right.Data); ok {\n\t\t\tright.Data = &EString{Value: helpers.StringToUTF16(str)}\n\t\t}\n\n\t\tswitch r := right.Data.(type) {\n\t\tcase *EString:\n\t\t\t// \"'x' + 'y'\" => \"'xy'\"\n\t\t\treturn Expr{Loc: left.Loc, Data: &EString{\n\t\t\t\tValue:          joinStrings(l.Value, r.Value),\n\t\t\t\tPreferTemplate: l.PreferTemplate || r.PreferTemplate,\n\t\t\t}}\n\n\t\tcase *ETemplate:\n\t\t\tif r.TagOrNil.Data == nil {\n\t\t\t\t// \"'x' + `y${z}`\" => \"`xy${z}`\"\n\t\t\t\treturn Expr{Loc: left.Loc, Data: &ETemplate{\n\t\t\t\t\tHeadLoc:    left.Loc,\n\t\t\t\t\tHeadCooked: joinStrings(l.Value, r.HeadCooked),\n\t\t\t\t\tParts:      r.Parts,\n\t\t\t\t}}\n\t\t\t}\n\t\t}\n\n\t\t// \"'' + typeof x\" => \"typeof x\"\n\t\tif len(l.Value) == 0 && KnownPrimitiveType(right.Data) == PrimitiveString {\n\t\t\treturn right\n\t\t}\n\n\tcase *ETemplate:\n\t\tif l.TagOrNil.Data == nil {\n\t\t\t// \"`${x}` + 0\" => \"`${x}` + '0'\"\n\t\t\tif str, ok := ToStringWithoutSideEffects(right.Data); ok {\n\t\t\t\tright.Data = &EString{Value: helpers.StringToUTF16(str)}\n\t\t\t}\n\n\t\t\tswitch r := right.Data.(type) {\n\t\t\tcase *EString:\n\t\t\t\t// \"`${x}y` + 'z'\" => \"`${x}yz`\"\n\t\t\t\tn := len(l.Parts)\n\t\t\t\thead := l.HeadCooked\n\t\t\t\tparts := make([]TemplatePart, n)\n\t\t\t\tif n == 0 {\n\t\t\t\t\thead = joinStrings(head, r.Value)\n\t\t\t\t} else {\n\t\t\t\t\tcopy(parts, l.Parts)\n\t\t\t\t\tparts[n-1].TailCooked = joinStrings(parts[n-1].TailCooked, r.Value)\n\t\t\t\t}\n\t\t\t\treturn Expr{Loc: left.Loc, Data: &ETemplate{\n\t\t\t\t\tHeadLoc:    l.HeadLoc,\n\t\t\t\t\tHeadCooked: head,\n\t\t\t\t\tParts:      parts,\n\t\t\t\t}}\n\n\t\t\tcase *ETemplate:\n\t\t\t\tif r.TagOrNil.Data == nil {\n\t\t\t\t\t// \"`${a}b` + `x${y}`\" => \"`${a}bx${y}`\"\n\t\t\t\t\tn := len(l.Parts)\n\t\t\t\t\thead := l.HeadCooked\n\t\t\t\t\tparts := make([]TemplatePart, n+len(r.Parts))\n\t\t\t\t\tcopy(parts[n:], r.Parts)\n\t\t\t\t\tif n == 0 {\n\t\t\t\t\t\thead = joinStrings(head, r.HeadCooked)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcopy(parts[:n], l.Parts)\n\t\t\t\t\t\tparts[n-1].TailCooked = joinStrings(parts[n-1].TailCooked, r.HeadCooked)\n\t\t\t\t\t}\n\t\t\t\t\treturn Expr{Loc: left.Loc, Data: &ETemplate{\n\t\t\t\t\t\tHeadLoc:    l.HeadLoc,\n\t\t\t\t\t\tHeadCooked: head,\n\t\t\t\t\t\tParts:      parts,\n\t\t\t\t\t}}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// \"typeof x + ''\" => \"typeof x\"\n\tif r, ok := right.Data.(*EString); ok && len(r.Value) == 0 && KnownPrimitiveType(left.Data) == PrimitiveString {\n\t\treturn left\n\t}\n\n\treturn Expr{}\n}\n\n// \"`a${'b'}c`\" => \"`abc`\"\n//\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc InlinePrimitivesIntoTemplate(loc logger.Loc, e *ETemplate) Expr {\n\t// Can't inline strings if there's a custom template tag\n\tif e.TagOrNil.Data != nil {\n\t\treturn Expr{Loc: loc, Data: e}\n\t}\n\n\theadCooked := e.HeadCooked\n\tparts := make([]TemplatePart, 0, len(e.Parts))\n\n\tfor _, part := range e.Parts {\n\t\tif value, ok := part.Value.Data.(*EInlinedEnum); ok {\n\t\t\tpart.Value = value.Value\n\t\t}\n\t\tif str, ok := ToStringWithoutSideEffects(part.Value.Data); ok {\n\t\t\tpart.Value.Data = &EString{Value: helpers.StringToUTF16(str)}\n\t\t}\n\t\tif str, ok := part.Value.Data.(*EString); ok {\n\t\t\tif len(parts) == 0 {\n\t\t\t\theadCooked = append(append(headCooked, str.Value...), part.TailCooked...)\n\t\t\t} else {\n\t\t\t\tprevPart := &parts[len(parts)-1]\n\t\t\t\tprevPart.TailCooked = append(append(prevPart.TailCooked, str.Value...), part.TailCooked...)\n\t\t\t}\n\t\t} else {\n\t\t\tparts = append(parts, part)\n\t\t}\n\t}\n\n\t// Become a plain string if there are no substitutions\n\tif len(parts) == 0 {\n\t\treturn Expr{Loc: loc, Data: &EString{\n\t\t\tValue:          headCooked,\n\t\t\tPreferTemplate: true,\n\t\t}}\n\t}\n\n\treturn Expr{Loc: loc, Data: &ETemplate{\n\t\tHeadLoc:    e.HeadLoc,\n\t\tHeadCooked: headCooked,\n\t\tParts:      parts,\n\t}}\n}\n\ntype SideEffects uint8\n\nconst (\n\tCouldHaveSideEffects SideEffects = iota\n\tNoSideEffects\n)\n\nfunc ToNullOrUndefinedWithSideEffects(data E) (isNullOrUndefined bool, sideEffects SideEffects, ok bool) {\n\tswitch e := data.(type) {\n\tcase *EAnnotation:\n\t\tisNullOrUndefined, sideEffects, ok = ToNullOrUndefinedWithSideEffects(e.Value.Data)\n\t\tif e.Flags.Has(CanBeRemovedIfUnusedFlag) {\n\t\t\tsideEffects = NoSideEffects\n\t\t}\n\t\treturn\n\n\tcase *EInlinedEnum:\n\t\treturn ToNullOrUndefinedWithSideEffects(e.Value.Data)\n\n\t\t// Never null or undefined\n\tcase *EBoolean, *ENumber, *EString, *ERegExp,\n\t\t*EFunction, *EArrow, *EBigInt:\n\t\treturn false, NoSideEffects, true\n\n\t// Never null or undefined\n\tcase *EObject, *EArray, *EClass:\n\t\treturn false, CouldHaveSideEffects, true\n\n\t// Always null or undefined\n\tcase *ENull, *EUndefined:\n\t\treturn true, NoSideEffects, true\n\n\tcase *EUnary:\n\t\tswitch e.Op {\n\t\tcase\n\t\t\t// Always number or bigint\n\t\t\tUnOpPos, UnOpNeg, UnOpCpl,\n\t\t\tUnOpPreDec, UnOpPreInc, UnOpPostDec, UnOpPostInc,\n\t\t\t// Always boolean\n\t\t\tUnOpNot, UnOpDelete:\n\t\t\treturn false, CouldHaveSideEffects, true\n\n\t\t// Always boolean\n\t\tcase UnOpTypeof:\n\t\t\tif e.WasOriginallyTypeofIdentifier {\n\t\t\t\t// Expressions such as \"typeof x\" never have any side effects\n\t\t\t\treturn false, NoSideEffects, true\n\t\t\t}\n\t\t\treturn false, CouldHaveSideEffects, true\n\n\t\t// Always undefined\n\t\tcase UnOpVoid:\n\t\t\treturn true, CouldHaveSideEffects, true\n\t\t}\n\n\tcase *EBinary:\n\t\tswitch e.Op {\n\t\tcase\n\t\t\t// Always string or number or bigint\n\t\t\tBinOpAdd, BinOpAddAssign,\n\t\t\t// Always number or bigint\n\t\t\tBinOpSub, BinOpMul, BinOpDiv, BinOpRem, BinOpPow,\n\t\t\tBinOpSubAssign, BinOpMulAssign, BinOpDivAssign, BinOpRemAssign, BinOpPowAssign,\n\t\t\tBinOpShl, BinOpShr, BinOpUShr,\n\t\t\tBinOpShlAssign, BinOpShrAssign, BinOpUShrAssign,\n\t\t\tBinOpBitwiseOr, BinOpBitwiseAnd, BinOpBitwiseXor,\n\t\t\tBinOpBitwiseOrAssign, BinOpBitwiseAndAssign, BinOpBitwiseXorAssign,\n\t\t\t// Always boolean\n\t\t\tBinOpLt, BinOpLe, BinOpGt, BinOpGe, BinOpIn, BinOpInstanceof,\n\t\t\tBinOpLooseEq, BinOpLooseNe, BinOpStrictEq, BinOpStrictNe:\n\t\t\treturn false, CouldHaveSideEffects, true\n\n\t\tcase BinOpComma:\n\t\t\tif isNullOrUndefined, _, ok := ToNullOrUndefinedWithSideEffects(e.Right.Data); ok {\n\t\t\t\treturn isNullOrUndefined, CouldHaveSideEffects, true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false, NoSideEffects, false\n}\n\nfunc ToBooleanWithSideEffects(data E) (boolean bool, sideEffects SideEffects, ok bool) {\n\tswitch e := data.(type) {\n\tcase *EAnnotation:\n\t\tboolean, sideEffects, ok = ToBooleanWithSideEffects(e.Value.Data)\n\t\tif e.Flags.Has(CanBeRemovedIfUnusedFlag) {\n\t\t\tsideEffects = NoSideEffects\n\t\t}\n\t\treturn\n\n\tcase *EInlinedEnum:\n\t\treturn ToBooleanWithSideEffects(e.Value.Data)\n\n\tcase *ENull, *EUndefined:\n\t\treturn false, NoSideEffects, true\n\n\tcase *EBoolean:\n\t\treturn e.Value, NoSideEffects, true\n\n\tcase *ENumber:\n\t\treturn e.Value != 0 && !math.IsNaN(e.Value), NoSideEffects, true\n\n\tcase *EBigInt:\n\t\tequal, ok := CheckEqualityBigInt(e.Value, \"0\")\n\t\treturn !equal, NoSideEffects, ok\n\n\tcase *EString:\n\t\treturn len(e.Value) > 0, NoSideEffects, true\n\n\tcase *EFunction, *EArrow, *ERegExp:\n\t\treturn true, NoSideEffects, true\n\n\tcase *EObject, *EArray, *EClass:\n\t\treturn true, CouldHaveSideEffects, true\n\n\tcase *EUnary:\n\t\tswitch e.Op {\n\t\tcase UnOpVoid:\n\t\t\treturn false, CouldHaveSideEffects, true\n\n\t\tcase UnOpTypeof:\n\t\t\t// Never an empty string\n\t\t\tif e.WasOriginallyTypeofIdentifier {\n\t\t\t\t// Expressions such as \"typeof x\" never have any side effects\n\t\t\t\treturn true, NoSideEffects, true\n\t\t\t}\n\t\t\treturn true, CouldHaveSideEffects, true\n\n\t\tcase UnOpNot:\n\t\t\tif boolean, SideEffects, ok := ToBooleanWithSideEffects(e.Value.Data); ok {\n\t\t\t\treturn !boolean, SideEffects, true\n\t\t\t}\n\t\t}\n\n\tcase *EBinary:\n\t\tswitch e.Op {\n\t\tcase BinOpLogicalOr:\n\t\t\t// \"anything || truthy\" is truthy\n\t\t\tif boolean, _, ok := ToBooleanWithSideEffects(e.Right.Data); ok && boolean {\n\t\t\t\treturn true, CouldHaveSideEffects, true\n\t\t\t}\n\n\t\tcase BinOpLogicalAnd:\n\t\t\t// \"anything && falsy\" is falsy\n\t\t\tif boolean, _, ok := ToBooleanWithSideEffects(e.Right.Data); ok && !boolean {\n\t\t\t\treturn false, CouldHaveSideEffects, true\n\t\t\t}\n\n\t\tcase BinOpComma:\n\t\t\t// \"anything, truthy/falsy\" is truthy/falsy\n\t\t\tif boolean, _, ok := ToBooleanWithSideEffects(e.Right.Data); ok {\n\t\t\t\treturn boolean, CouldHaveSideEffects, true\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false, CouldHaveSideEffects, false\n}\n\n// Simplify syntax when we know it's used inside a boolean context\n//\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc (ctx HelperContext) SimplifyBooleanExpr(expr Expr) Expr {\n\tswitch e := expr.Data.(type) {\n\tcase *EUnary:\n\t\tif e.Op == UnOpNot {\n\t\t\t// \"!!a\" => \"a\"\n\t\t\tif e2, ok2 := e.Value.Data.(*EUnary); ok2 && e2.Op == UnOpNot {\n\t\t\t\treturn ctx.SimplifyBooleanExpr(e2.Value)\n\t\t\t}\n\n\t\t\t// \"!!!a\" => \"!a\"\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EUnary{Op: UnOpNot, Value: ctx.SimplifyBooleanExpr(e.Value)}}\n\t\t}\n\n\tcase *EBinary:\n\t\tleft := e.Left\n\t\tright := e.Right\n\n\t\tswitch e.Op {\n\t\tcase BinOpStrictEq, BinOpStrictNe, BinOpLooseEq, BinOpLooseNe:\n\t\t\tif r, ok := extractNumericValue(right.Data); ok && r == 0 && isInt32OrUint32(left.Data) {\n\t\t\t\t// If the left is guaranteed to be an integer (e.g. not NaN,\n\t\t\t\t// Infinity, or a non-numeric value) then a test against zero\n\t\t\t\t// in a boolean context is unnecessary because the value is\n\t\t\t\t// only truthy if it's not zero.\n\t\t\t\tif e.Op == BinOpStrictNe || e.Op == BinOpLooseNe {\n\t\t\t\t\t// \"if ((a >>> b) !== 0)\" => \"if (a >>> b)\"\n\t\t\t\t\treturn left\n\t\t\t\t} else {\n\t\t\t\t\t// \"if ((a >>> b) === 0)\" => \"if (!(a >>> b))\"\n\t\t\t\t\treturn Not(left)\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase BinOpLogicalAnd:\n\t\t\t// \"if (!!a && !!b)\" => \"if (a && b)\"\n\t\t\tleft = ctx.SimplifyBooleanExpr(left)\n\t\t\tright = ctx.SimplifyBooleanExpr(right)\n\n\t\t\tif boolean, SideEffects, ok := ToBooleanWithSideEffects(right.Data); ok && boolean && SideEffects == NoSideEffects {\n\t\t\t\t// \"if (anything && truthyNoSideEffects)\" => \"if (anything)\"\n\t\t\t\treturn left\n\t\t\t}\n\n\t\tcase BinOpLogicalOr:\n\t\t\t// \"if (!!a || !!b)\" => \"if (a || b)\"\n\t\t\tleft = ctx.SimplifyBooleanExpr(left)\n\t\t\tright = ctx.SimplifyBooleanExpr(right)\n\n\t\t\tif boolean, SideEffects, ok := ToBooleanWithSideEffects(right.Data); ok && !boolean && SideEffects == NoSideEffects {\n\t\t\t\t// \"if (anything || falsyNoSideEffects)\" => \"if (anything)\"\n\t\t\t\treturn left\n\t\t\t}\n\t\t}\n\n\t\tif left != e.Left || right != e.Right {\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBinary{Op: e.Op, Left: left, Right: right}}\n\t\t}\n\n\tcase *EIf:\n\t\t// \"if (a ? !!b : !!c)\" => \"if (a ? b : c)\"\n\t\tyes := ctx.SimplifyBooleanExpr(e.Yes)\n\t\tno := ctx.SimplifyBooleanExpr(e.No)\n\n\t\tif boolean, SideEffects, ok := ToBooleanWithSideEffects(yes.Data); ok && SideEffects == NoSideEffects {\n\t\t\tif boolean {\n\t\t\t\t// \"if (anything1 ? truthyNoSideEffects : anything2)\" => \"if (anything1 || anything2)\"\n\t\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalOr, e.Test, no)\n\t\t\t} else {\n\t\t\t\t// \"if (anything1 ? falsyNoSideEffects : anything2)\" => \"if (!anything1 || anything2)\"\n\t\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalAnd, Not(e.Test), no)\n\t\t\t}\n\t\t}\n\n\t\tif boolean, SideEffects, ok := ToBooleanWithSideEffects(no.Data); ok && SideEffects == NoSideEffects {\n\t\t\tif boolean {\n\t\t\t\t// \"if (anything1 ? anything2 : truthyNoSideEffects)\" => \"if (!anything1 || anything2)\"\n\t\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalOr, Not(e.Test), yes)\n\t\t\t} else {\n\t\t\t\t// \"if (anything1 ? anything2 : falsyNoSideEffects)\" => \"if (anything1 && anything2)\"\n\t\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalAnd, e.Test, yes)\n\t\t\t}\n\t\t}\n\n\t\tif yes != e.Yes || no != e.No {\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EIf{Test: e.Test, Yes: yes, No: no}}\n\t\t}\n\n\tdefault:\n\t\t// \"!![]\" => \"true\"\n\t\tif boolean, sideEffects, ok := ToBooleanWithSideEffects(expr.Data); ok && (sideEffects == NoSideEffects || ctx.ExprCanBeRemovedIfUnused(expr)) {\n\t\t\treturn Expr{Loc: expr.Loc, Data: &EBoolean{Value: boolean}}\n\t\t}\n\t}\n\n\treturn expr\n}\n\ntype StmtsCanBeRemovedIfUnusedFlags uint8\n\nconst (\n\tKeepExportClauses StmtsCanBeRemovedIfUnusedFlags = 1 << iota\n\tReturnCanBeRemovedIfUnused\n)\n\nfunc (ctx HelperContext) StmtsCanBeRemovedIfUnused(stmts []Stmt, flags StmtsCanBeRemovedIfUnusedFlags) bool {\n\tfor _, stmt := range stmts {\n\t\tswitch s := stmt.Data.(type) {\n\t\tcase *SFunction, *SEmpty:\n\t\t\t// These never have side effects\n\n\t\tcase *SImport:\n\t\t\t// Let these be removed if they are unused. Note that we also need to\n\t\t\t// check if the imported file is marked as \"sideEffects: false\" before we\n\t\t\t// can remove a SImport statement. Otherwise the import must be kept for\n\t\t\t// its side effects.\n\n\t\tcase *SClass:\n\t\t\tif !ctx.ClassCanBeRemovedIfUnused(s.Class) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\tcase *SReturn:\n\t\t\tif (flags&ReturnCanBeRemovedIfUnused) == 0 || (s.ValueOrNil.Data != nil && !ctx.ExprCanBeRemovedIfUnused(s.ValueOrNil)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\tcase *SExpr:\n\t\t\tif !ctx.ExprCanBeRemovedIfUnused(s.Value) {\n\t\t\t\tif s.IsFromClassOrFnThatCanBeRemovedIfUnused {\n\t\t\t\t\t// This statement was automatically generated when lowering a class\n\t\t\t\t\t// or function that we were able to analyze as having no side effects\n\t\t\t\t\t// before lowering. So we consider it to be removable. The assumption\n\t\t\t\t\t// here is that we are seeing at least all of the statements from the\n\t\t\t\t\t// class lowering operation all at once (although we may possibly be\n\t\t\t\t\t// seeing even more statements than that). Since we're making a binary\n\t\t\t\t\t// all-or-nothing decision about the side effects of these statements,\n\t\t\t\t\t// we can safely consider these to be side-effect free because we\n\t\t\t\t\t// aren't in danger of partially dropping some of the class setup code.\n\t\t\t\t} else {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *SLocal:\n\t\t\t// \"await\" is a side effect because it affects code timing\n\t\t\tif s.Kind == LocalAwaitUsing {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tfor _, decl := range s.Decls {\n\t\t\t\t// Check that the bindings are side-effect free\n\t\t\t\tswitch binding := decl.Binding.Data.(type) {\n\t\t\t\tcase *BIdentifier:\n\t\t\t\t\t// An identifier binding has no side effects\n\n\t\t\t\tcase *BArray:\n\t\t\t\t\t// Destructuring the initializer has no side effects if the\n\t\t\t\t\t// initializer is an array, since we assume the iterator is then\n\t\t\t\t\t// the built-in side-effect free array iterator.\n\t\t\t\t\tif _, ok := decl.ValueOrNil.Data.(*EArray); ok {\n\t\t\t\t\t\tfor _, item := range binding.Items {\n\t\t\t\t\t\t\tif item.DefaultValueOrNil.Data != nil && !ctx.ExprCanBeRemovedIfUnused(item.DefaultValueOrNil) {\n\t\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tswitch item.Binding.Data.(type) {\n\t\t\t\t\t\t\tcase *BIdentifier, *BMissing:\n\t\t\t\t\t\t\t\t// Right now we only handle an array pattern with identifier\n\t\t\t\t\t\t\t\t// bindings or with empty holes (i.e. \"missing\" elements)\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\treturn false\n\n\t\t\t\tdefault:\n\t\t\t\t\t// Consider anything else to potentially have side effects\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\t// Check that the initializer is side-effect free\n\t\t\t\tif decl.ValueOrNil.Data != nil {\n\t\t\t\t\tif !ctx.ExprCanBeRemovedIfUnused(decl.ValueOrNil) {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\n\t\t\t\t\t// \"using\" declarations are only side-effect free if they are initialized to null or undefined\n\t\t\t\t\tif s.Kind.IsUsing() {\n\t\t\t\t\t\tif t := KnownPrimitiveType(decl.ValueOrNil.Data); t != PrimitiveNull && t != PrimitiveUndefined {\n\t\t\t\t\t\t\treturn false\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\tcase *STry:\n\t\t\tif !ctx.StmtsCanBeRemovedIfUnused(s.Block.Stmts, 0) || (s.Finally != nil && !ctx.StmtsCanBeRemovedIfUnused(s.Finally.Block.Stmts, 0)) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\tcase *SExportFrom:\n\t\t\t// Exports are tracked separately, so this isn't necessary\n\n\t\tcase *SExportClause:\n\t\t\tif (flags & KeepExportClauses) != 0 {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\tcase *SExportDefault:\n\t\t\tswitch s2 := s.Value.Data.(type) {\n\t\t\tcase *SExpr:\n\t\t\t\tif !ctx.ExprCanBeRemovedIfUnused(s2.Value) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\tcase *SFunction:\n\t\t\t\t// These never have side effects\n\n\t\t\tcase *SClass:\n\t\t\t\tif !ctx.ClassCanBeRemovedIfUnused(s2.Class) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\tdefault:\n\t\t\t\tpanic(\"Internal error\")\n\t\t\t}\n\n\t\tdefault:\n\t\t\t// Assume that all statements not explicitly special-cased here have side\n\t\t\t// effects, and cannot be removed even if unused\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (ctx HelperContext) ClassCanBeRemovedIfUnused(class Class) bool {\n\tif len(class.Decorators) > 0 {\n\t\treturn false\n\t}\n\n\t// Note: This check is incorrect. Extending a non-constructible object can\n\t// throw an error, which is a side effect:\n\t//\n\t//   async function x() {}\n\t//   class y extends x {}\n\t//\n\t// But refusing to tree-shake every class with a base class is not a useful\n\t// thing for a bundler to do. So we pretend that this edge case doesn't\n\t// exist. At the time of writing, both Rollup and Terser don't consider this\n\t// to be a side effect either.\n\tif class.ExtendsOrNil.Data != nil && !ctx.ExprCanBeRemovedIfUnused(class.ExtendsOrNil) {\n\t\treturn false\n\t}\n\n\tfor _, property := range class.Properties {\n\t\tif property.Kind == PropertyClassStaticBlock {\n\t\t\tif !ctx.StmtsCanBeRemovedIfUnused(property.ClassStaticBlock.Block.Stmts, 0) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(property.Decorators) > 0 {\n\t\t\treturn false\n\t\t}\n\n\t\tif property.Flags.Has(PropertyIsComputed) && !IsPrimitiveLiteral(property.Key.Data) && !IsSymbolInstance(property.Key.Data) {\n\t\t\treturn false\n\t\t}\n\n\t\tif property.Kind.IsMethodDefinition() {\n\t\t\tif fn, ok := property.ValueOrNil.Data.(*EFunction); ok {\n\t\t\t\tfor _, arg := range fn.Fn.Args {\n\t\t\t\t\tif len(arg.Decorators) > 0 {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif property.Flags.Has(PropertyIsStatic) {\n\t\t\tif property.ValueOrNil.Data != nil && !ctx.ExprCanBeRemovedIfUnused(property.ValueOrNil) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif property.InitializerOrNil.Data != nil && !ctx.ExprCanBeRemovedIfUnused(property.InitializerOrNil) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Legacy TypeScript static class fields are considered to have side\n\t\t\t// effects because they use assign semantics, not define semantics, and\n\t\t\t// that can trigger getters. For example:\n\t\t\t//\n\t\t\t//   class Foo {\n\t\t\t//     static set foo(x) { importantSideEffect(x) }\n\t\t\t//   }\n\t\t\t//   class Bar extends Foo {\n\t\t\t//     foo = 1\n\t\t\t//   }\n\t\t\t//\n\t\t\t// This happens in TypeScript when \"useDefineForClassFields\" is disabled\n\t\t\t// because TypeScript (and esbuild) transforms the above class into this:\n\t\t\t//\n\t\t\t//   class Foo {\n\t\t\t//     static set foo(x) { importantSideEffect(x); }\n\t\t\t//   }\n\t\t\t//   class Bar extends Foo {\n\t\t\t//   }\n\t\t\t//   Bar.foo = 1;\n\t\t\t//\n\t\t\t// Note that it's not possible to analyze the base class to determine that\n\t\t\t// these assignments are side-effect free. For example:\n\t\t\t//\n\t\t\t//   // Some code that already ran before your code\n\t\t\t//   Object.defineProperty(Object.prototype, 'foo', {\n\t\t\t//     set(x) { imporantSideEffect(x) }\n\t\t\t//   })\n\t\t\t//\n\t\t\t//   // Your code\n\t\t\t//   class Foo {\n\t\t\t//     static foo = 1\n\t\t\t//   }\n\t\t\t//\n\t\t\tif property.Kind == PropertyField && !class.UseDefineForClassFields {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (ctx HelperContext) ExprCanBeRemovedIfUnused(expr Expr) bool {\n\tswitch e := expr.Data.(type) {\n\tcase *EAnnotation:\n\t\treturn e.Flags.Has(CanBeRemovedIfUnusedFlag)\n\n\tcase *EInlinedEnum:\n\t\treturn ctx.ExprCanBeRemovedIfUnused(e.Value)\n\n\tcase *ENull, *EUndefined, *EMissing, *EBoolean, *ENumber, *EBigInt,\n\t\t*EString, *EThis, *ERegExp, *EFunction, *EArrow, *EImportMeta:\n\t\treturn true\n\n\tcase *EDot:\n\t\treturn e.CanBeRemovedIfUnused\n\n\tcase *EClass:\n\t\treturn ctx.ClassCanBeRemovedIfUnused(e.Class)\n\n\tcase *EIdentifier:\n\t\tif e.MustKeepDueToWithStmt {\n\t\t\treturn false\n\t\t}\n\n\t\t// Unbound identifiers cannot be removed because they can have side effects.\n\t\t// One possible side effect is throwing a ReferenceError if they don't exist.\n\t\t// Another one is a getter with side effects on the global object:\n\t\t//\n\t\t//   Object.defineProperty(globalThis, 'x', {\n\t\t//     get() {\n\t\t//       sideEffect();\n\t\t//     },\n\t\t//   });\n\t\t//\n\t\t// Be very careful about this possibility. It's tempting to treat all\n\t\t// identifier expressions as not having side effects but that's wrong. We\n\t\t// must make sure they have been declared by the code we are currently\n\t\t// compiling before we can tell that they have no side effects.\n\t\t//\n\t\t// Note that we currently ignore ReferenceErrors due to TDZ access. This is\n\t\t// incorrect but proper TDZ analysis is very complicated and would have to\n\t\t// be very conservative, which would inhibit a lot of optimizations of code\n\t\t// inside closures. This may need to be revisited if it proves problematic.\n\t\tif e.CanBeRemovedIfUnused || !ctx.isUnbound(e.Ref) {\n\t\t\treturn true\n\t\t}\n\n\tcase *EImportIdentifier:\n\t\t// References to an ES6 import item are always side-effect free in an\n\t\t// ECMAScript environment.\n\t\t//\n\t\t// They could technically have side effects if the imported module is a\n\t\t// CommonJS module and the import item was translated to a property access\n\t\t// (which esbuild's bundler does) and the property has a getter with side\n\t\t// effects.\n\t\t//\n\t\t// But this is very unlikely and respecting this edge case would mean\n\t\t// disabling tree shaking of all code that references an export from a\n\t\t// CommonJS module. It would also likely violate the expectations of some\n\t\t// developers because the code *looks* like it should be able to be tree\n\t\t// shaken.\n\t\t//\n\t\t// So we deliberately ignore this edge case and always treat import item\n\t\t// references as being side-effect free.\n\t\treturn true\n\n\tcase *EIf:\n\t\treturn ctx.ExprCanBeRemovedIfUnused(e.Test) &&\n\t\t\t((ctx.isSideEffectFreeUnboundIdentifierRef(e.Yes, e.Test, true) || ctx.ExprCanBeRemovedIfUnused(e.Yes)) &&\n\t\t\t\t(ctx.isSideEffectFreeUnboundIdentifierRef(e.No, e.Test, false) || ctx.ExprCanBeRemovedIfUnused(e.No)))\n\n\tcase *EArray:\n\t\tfor _, item := range e.Items {\n\t\t\tif spread, ok := item.Data.(*ESpread); ok {\n\t\t\t\tif _, ok := spread.Value.Data.(*EArray); ok {\n\t\t\t\t\t// Spread of an inline array such as \"[...[x]]\" is side-effect free\n\t\t\t\t\titem = spread.Value\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !ctx.ExprCanBeRemovedIfUnused(item) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\n\tcase *EObject:\n\t\tfor _, property := range e.Properties {\n\t\t\t// The key must still be evaluated if it's computed or a spread\n\t\t\tif property.Kind == PropertySpread {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif property.Flags.Has(PropertyIsComputed) && !IsPrimitiveLiteral(property.Key.Data) && !IsSymbolInstance(property.Key.Data) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif property.ValueOrNil.Data != nil && !ctx.ExprCanBeRemovedIfUnused(property.ValueOrNil) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\n\tcase *ECall:\n\t\tcanCallBeRemoved := e.CanBeUnwrappedIfUnused\n\n\t\t// A call that has been marked \"__PURE__\" can be removed if all arguments\n\t\t// can be removed. The annotation causes us to ignore the target.\n\t\tif canCallBeRemoved {\n\t\t\tfor _, arg := range e.Args {\n\t\t\t\tif !ctx.ExprCanBeRemovedIfUnused(arg) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\n\tcase *ENew:\n\t\t// A constructor call that has been marked \"__PURE__\" can be removed if all\n\t\t// arguments can be removed. The annotation causes us to ignore the target.\n\t\tif e.CanBeUnwrappedIfUnused {\n\t\t\tfor _, arg := range e.Args {\n\t\t\t\tif !ctx.ExprCanBeRemovedIfUnused(arg) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\n\tcase *EUnary:\n\t\tswitch e.Op {\n\t\t// These operators must not have any type conversions that can execute code\n\t\t// such as \"toString\" or \"valueOf\". They must also never throw any exceptions.\n\t\tcase UnOpVoid, UnOpNot:\n\t\t\treturn ctx.ExprCanBeRemovedIfUnused(e.Value)\n\n\t\tcase UnOpNeg:\n\t\t\tif _, ok := e.Value.Data.(*EBigInt); ok {\n\t\t\t\t// Consider negated bigints to have no side effects\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t// The \"typeof\" operator doesn't do any type conversions so it can be removed\n\t\t// if the result is unused and the operand has no side effects. However, it\n\t\t// has a special case where if the operand is an identifier expression such\n\t\t// as \"typeof x\" and \"x\" doesn't exist, no reference error is thrown so the\n\t\t// operation has no side effects.\n\t\tcase UnOpTypeof:\n\t\t\tif _, ok := e.Value.Data.(*EIdentifier); ok && e.WasOriginallyTypeofIdentifier {\n\t\t\t\t// Expressions such as \"typeof x\" never have any side effects\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn ctx.ExprCanBeRemovedIfUnused(e.Value)\n\t\t}\n\n\tcase *EBinary:\n\t\tswitch e.Op {\n\t\t// These operators must not have any type conversions that can execute code\n\t\t// such as \"toString\" or \"valueOf\". They must also never throw any exceptions.\n\t\tcase BinOpStrictEq, BinOpStrictNe, BinOpComma, BinOpNullishCoalescing:\n\t\t\treturn ctx.ExprCanBeRemovedIfUnused(e.Left) && ctx.ExprCanBeRemovedIfUnused(e.Right)\n\n\t\t// Special-case \"||\" to make sure \"typeof x === 'undefined' || x\" can be removed\n\t\tcase BinOpLogicalOr:\n\t\t\treturn ctx.ExprCanBeRemovedIfUnused(e.Left) &&\n\t\t\t\t(ctx.isSideEffectFreeUnboundIdentifierRef(e.Right, e.Left, false) || ctx.ExprCanBeRemovedIfUnused(e.Right))\n\n\t\t// Special-case \"&&\" to make sure \"typeof x !== 'undefined' && x\" can be removed\n\t\tcase BinOpLogicalAnd:\n\t\t\treturn ctx.ExprCanBeRemovedIfUnused(e.Left) &&\n\t\t\t\t(ctx.isSideEffectFreeUnboundIdentifierRef(e.Right, e.Left, true) || ctx.ExprCanBeRemovedIfUnused(e.Right))\n\n\t\t// For \"==\" and \"!=\", pretend the operator was actually \"===\" or \"!==\". If\n\t\t// we know that we can convert it to \"==\" or \"!=\", then we can consider the\n\t\t// operator itself to have no side effects. This matters because our mangle\n\t\t// logic will convert \"typeof x === 'object'\" into \"typeof x == 'object'\"\n\t\t// and since \"typeof x === 'object'\" is considered to be side-effect free,\n\t\t// we must also consider \"typeof x == 'object'\" to be side-effect free.\n\t\tcase BinOpLooseEq, BinOpLooseNe:\n\t\t\treturn CanChangeStrictToLoose(e.Left, e.Right) && ctx.ExprCanBeRemovedIfUnused(e.Left) && ctx.ExprCanBeRemovedIfUnused(e.Right)\n\n\t\t// Special-case \"<\" and \">\" with string, number, or bigint arguments\n\t\tcase BinOpLt, BinOpGt, BinOpLe, BinOpGe:\n\t\t\tleft := KnownPrimitiveType(e.Left.Data)\n\t\t\tswitch left {\n\t\t\tcase PrimitiveString, PrimitiveNumber, PrimitiveBigInt:\n\t\t\t\treturn KnownPrimitiveType(e.Right.Data) == left && ctx.ExprCanBeRemovedIfUnused(e.Left) && ctx.ExprCanBeRemovedIfUnused(e.Right)\n\t\t\t}\n\t\t}\n\n\tcase *ETemplate:\n\t\t// A template can be removed if it has no tag and every value has no side\n\t\t// effects and results in some kind of primitive, since all primitives\n\t\t// have a \"ToString\" operation with no side effects.\n\t\tif e.TagOrNil.Data == nil || e.CanBeUnwrappedIfUnused {\n\t\t\tfor _, part := range e.Parts {\n\t\t\t\tif !ctx.ExprCanBeRemovedIfUnused(part.Value) || KnownPrimitiveType(part.Value.Data) == PrimitiveUnknown {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// Assume all other expression types have side effects and cannot be removed\n\treturn false\n}\n\nfunc (ctx HelperContext) isSideEffectFreeUnboundIdentifierRef(value Expr, guardCondition Expr, isYesBranch bool) bool {\n\tif id, ok := value.Data.(*EIdentifier); ok && ctx.isUnbound(id.Ref) {\n\t\tif binary, ok := guardCondition.Data.(*EBinary); ok {\n\t\t\tswitch binary.Op {\n\t\t\tcase BinOpStrictEq, BinOpStrictNe, BinOpLooseEq, BinOpLooseNe:\n\t\t\t\t// Pattern match for \"typeof x !== <string>\"\n\t\t\t\ttypeof, string := binary.Left, binary.Right\n\t\t\t\tif _, ok := typeof.Data.(*EString); ok {\n\t\t\t\t\ttypeof, string = string, typeof\n\t\t\t\t}\n\t\t\t\tif typeof, ok := typeof.Data.(*EUnary); ok && typeof.Op == UnOpTypeof && typeof.WasOriginallyTypeofIdentifier {\n\t\t\t\t\tif text, ok := string.Data.(*EString); ok {\n\t\t\t\t\t\t// In \"typeof x !== 'undefined' ? x : null\", the reference to \"x\" is side-effect free\n\t\t\t\t\t\t// In \"typeof x === 'object' ? x : null\", the reference to \"x\" is side-effect free\n\t\t\t\t\t\tif (helpers.UTF16EqualsString(text.Value, \"undefined\") == isYesBranch) ==\n\t\t\t\t\t\t\t(binary.Op == BinOpStrictNe || binary.Op == BinOpLooseNe) {\n\t\t\t\t\t\t\tif id2, ok := typeof.Value.Data.(*EIdentifier); ok && id2.Ref == id.Ref {\n\t\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tcase BinOpLt, BinOpGt, BinOpLe, BinOpGe:\n\t\t\t\t// Pattern match for \"typeof x < <string>\"\n\t\t\t\ttypeof, string := binary.Left, binary.Right\n\t\t\t\tif _, ok := typeof.Data.(*EString); ok {\n\t\t\t\t\ttypeof, string = string, typeof\n\t\t\t\t\tisYesBranch = !isYesBranch\n\t\t\t\t}\n\t\t\t\tif typeof, ok := typeof.Data.(*EUnary); ok && typeof.Op == UnOpTypeof && typeof.WasOriginallyTypeofIdentifier {\n\t\t\t\t\tif text, ok := string.Data.(*EString); ok && helpers.UTF16EqualsString(text.Value, \"u\") {\n\t\t\t\t\t\t// In \"typeof x < 'u' ? x : null\", the reference to \"x\" is side-effect free\n\t\t\t\t\t\t// In \"typeof x > 'u' ? x : null\", the reference to \"x\" is side-effect free\n\t\t\t\t\t\tif isYesBranch == (binary.Op == BinOpLt || binary.Op == BinOpLe) {\n\t\t\t\t\t\t\tif id2, ok := typeof.Value.Data.(*EIdentifier); ok && id2.Ref == id.Ref {\n\t\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn false\n}\n\nfunc StringToEquivalentNumberValue(value []uint16) (float64, bool) {\n\tif len(value) > 0 {\n\t\tvar intValue int32\n\t\tisNegative := false\n\t\tstart := 0\n\n\t\tif value[0] == '-' && len(value) > 1 {\n\t\t\tisNegative = true\n\t\t\tstart++\n\t\t}\n\n\t\tfor _, c := range value[start:] {\n\t\t\tif c < '0' || c > '9' {\n\t\t\t\treturn 0, false\n\t\t\t}\n\t\t\tintValue = intValue*10 + int32(c) - '0'\n\t\t}\n\n\t\tif isNegative {\n\t\t\tintValue = -intValue\n\t\t}\n\n\t\tif helpers.UTF16EqualsString(value, strconv.FormatInt(int64(intValue), 10)) {\n\t\t\treturn float64(intValue), true\n\t\t}\n\t}\n\n\treturn 0, false\n}\n\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc InlineSpreadsOfArrayLiterals(values []Expr) (results []Expr) {\n\tfor _, value := range values {\n\t\tif spread, ok := value.Data.(*ESpread); ok {\n\t\t\tif array, ok := spread.Value.Data.(*EArray); ok {\n\t\t\t\tfor _, item := range array.Items {\n\t\t\t\t\tif _, ok := item.Data.(*EMissing); ok {\n\t\t\t\t\t\tresults = append(results, Expr{Loc: item.Loc, Data: EUndefinedShared})\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresults = append(results, item)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tresults = append(results, value)\n\t}\n\treturn\n}\n\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc MangleObjectSpread(properties []Property) []Property {\n\tvar result []Property\n\tfor _, property := range properties {\n\t\tif property.Kind == PropertySpread {\n\t\t\tswitch v := property.ValueOrNil.Data.(type) {\n\t\t\tcase *EBoolean, *ENull, *EUndefined, *ENumber,\n\t\t\t\t*EBigInt, *ERegExp, *EFunction, *EArrow:\n\t\t\t\t// This value is ignored because it doesn't have any of its own properties\n\t\t\t\tcontinue\n\n\t\t\tcase *EObject:\n\t\t\t\tfor i, p := range v.Properties {\n\t\t\t\t\t// Getters are evaluated at iteration time. The property\n\t\t\t\t\t// descriptor is not inlined into the caller. Since we are not\n\t\t\t\t\t// evaluating code at compile time, just bail if we hit one\n\t\t\t\t\t// and preserve the spread with the remaining properties.\n\t\t\t\t\tif p.Kind == PropertyGetter || p.Kind == PropertySetter {\n\t\t\t\t\t\t// Don't mutate the original AST\n\t\t\t\t\t\tclone := *v\n\t\t\t\t\t\tclone.Properties = v.Properties[i:]\n\t\t\t\t\t\tproperty.ValueOrNil.Data = &clone\n\t\t\t\t\t\tresult = append(result, property)\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\t// Also bail if we hit a verbatim \"__proto__\" key. This will\n\t\t\t\t\t// actually set the prototype of the object being spread so\n\t\t\t\t\t// inlining it is not correct.\n\t\t\t\t\tif p.Kind == PropertyField && !p.Flags.Has(PropertyIsComputed) {\n\t\t\t\t\t\tif str, ok := p.Key.Data.(*EString); ok && helpers.UTF16EqualsString(str.Value, \"__proto__\") {\n\t\t\t\t\t\t\t// Don't mutate the original AST\n\t\t\t\t\t\t\tclone := *v\n\t\t\t\t\t\t\tclone.Properties = v.Properties[i:]\n\t\t\t\t\t\t\tproperty.ValueOrNil.Data = &clone\n\t\t\t\t\t\t\tresult = append(result, property)\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tresult = append(result, p)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tresult = append(result, property)\n\t}\n\treturn result\n}\n\n// This function intentionally avoids mutating the input AST so it can be\n// called after the AST has been frozen (i.e. after parsing ends).\nfunc (ctx HelperContext) MangleIfExpr(loc logger.Loc, e *EIf, unsupportedFeatures compat.JSFeature) Expr {\n\ttest := e.Test\n\tyes := e.Yes\n\tno := e.No\n\n\t// \"(a, b) ? c : d\" => \"a, b ? c : d\"\n\tif comma, ok := test.Data.(*EBinary); ok && comma.Op == BinOpComma {\n\t\treturn JoinWithComma(comma.Left, ctx.MangleIfExpr(comma.Right.Loc, &EIf{\n\t\t\tTest: comma.Right,\n\t\t\tYes:  yes,\n\t\t\tNo:   no,\n\t\t}, unsupportedFeatures))\n\t}\n\n\t// \"!a ? b : c\" => \"a ? c : b\"\n\tif not, ok := test.Data.(*EUnary); ok && not.Op == UnOpNot {\n\t\ttest = not.Value\n\t\tyes, no = no, yes\n\t}\n\n\tif ValuesLookTheSame(yes.Data, no.Data) {\n\t\t// \"/* @__PURE__ */ a() ? b : b\" => \"b\"\n\t\tif ctx.ExprCanBeRemovedIfUnused(test) {\n\t\t\treturn yes\n\t\t}\n\n\t\t// \"a ? b : b\" => \"a, b\"\n\t\treturn JoinWithComma(test, yes)\n\t}\n\n\t// \"a ? true : false\" => \"!!a\"\n\t// \"a ? false : true\" => \"!a\"\n\tif y, ok := yes.Data.(*EBoolean); ok {\n\t\tif n, ok := no.Data.(*EBoolean); ok {\n\t\t\tif y.Value && !n.Value {\n\t\t\t\treturn Not(Not(test))\n\t\t\t}\n\t\t\tif !y.Value && n.Value {\n\t\t\t\treturn Not(test)\n\t\t\t}\n\t\t}\n\t}\n\n\tif id, ok := test.Data.(*EIdentifier); ok {\n\t\t// \"a ? a : b\" => \"a || b\"\n\t\tif id2, ok := yes.Data.(*EIdentifier); ok && id.Ref == id2.Ref {\n\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalOr, test, no)\n\t\t}\n\n\t\t// \"a ? b : a\" => \"a && b\"\n\t\tif id2, ok := no.Data.(*EIdentifier); ok && id.Ref == id2.Ref {\n\t\t\treturn JoinWithLeftAssociativeOp(BinOpLogicalAnd, test, yes)\n\t\t}\n\t}\n\n\t// \"a ? b ? c : d : d\" => \"a && b ? c : d\"\n\tif yesIf, ok := yes.Data.(*EIf); ok && ValuesLookTheSame(yesIf.No.Data, no.Data) {\n\t\treturn Expr{Loc: loc, Data: &EIf{Test: JoinWithLeftAssociativeOp(BinOpLogicalAnd, test, yesIf.Test), Yes: yesIf.Yes, No: no}}\n\t}\n\n\t// \"a ? b : c ? b : d\" => \"a || c ? b : d\"\n\tif noIf, ok := no.Data.(*EIf); ok && ValuesLookTheSame(yes.Data, noIf.Yes.Data) {\n\t\treturn Expr{Loc: loc, Data: &EIf{Test: JoinWithLeftAssociativeOp(BinOpLogicalOr, test, noIf.Test), Yes: yes, No: noIf.No}}\n\t}\n\n\t// \"a ? c : (b, c)\" => \"(a || b), c\"\n\tif comma, ok := no.Data.(*EBinary); ok && comma.Op == BinOpComma && ValuesLookTheSame(yes.Data, comma.Right.Data) {\n\t\treturn JoinWithComma(\n\t\t\tJoinWithLeftAssociativeOp(BinOpLogicalOr, test, comma.Left),\n\t\t\tcomma.Right,\n\t\t)\n\t}\n\n\t// \"a ? (b, c) : c\" => \"(a && b), c\"\n\tif comma, ok := yes.Data.(*EBinary); ok && comma.Op == BinOpComma && ValuesLookTheSame(comma.Right.Data, no.Data) {\n\t\treturn JoinWithComma(\n\t\t\tJoinWithLeftAssociativeOp(BinOpLogicalAnd, test, comma.Left),\n\t\t\tcomma.Right,\n\t\t)\n\t}\n\n\t// \"a ? b || c : c\" => \"(a && b) || c\"\n\tif binary, ok := yes.Data.(*EBinary); ok && binary.Op == BinOpLogicalOr &&\n\t\tValuesLookTheSame(binary.Right.Data, no.Data) {\n\t\treturn Expr{Loc: loc, Data: &EBinary{\n\t\t\tOp:    BinOpLogicalOr,\n\t\t\tLeft:  JoinWithLeftAssociativeOp(BinOpLogicalAnd, test, binary.Left),\n\t\t\tRight: binary.Right,\n\t\t}}\n\t}\n\n\t// \"a ? c : b && c\" => \"(a || b) && c\"\n\tif binary, ok := no.Data.(*EBinary); ok && binary.Op == BinOpLogicalAnd &&\n\t\tValuesLookTheSame(yes.Data, binary.Right.Data) {\n\t\treturn Expr{Loc: loc, Data: &EBinary{\n\t\t\tOp:    BinOpLogicalAnd,\n\t\t\tLeft:  JoinWithLeftAssociativeOp(BinOpLogicalOr, test, binary.Left),\n\t\t\tRight: binary.Right,\n\t\t}}\n\t}\n\n\t// \"a ? b(c, d) : b(e, d)\" => \"b(a ? c : e, d)\"\n\tif y, ok := yes.Data.(*ECall); ok && len(y.Args) > 0 {\n\t\tif n, ok := no.Data.(*ECall); ok && len(n.Args) == len(y.Args) &&\n\t\t\ty.HasSameFlagsAs(n) && ValuesLookTheSame(y.Target.Data, n.Target.Data) {\n\t\t\t// Only do this if the condition can be reordered past the call target\n\t\t\t// without side effects. For example, if the test or the call target is\n\t\t\t// an unbound identifier, reordering could potentially mean evaluating\n\t\t\t// the code could throw a different ReferenceError.\n\t\t\tif ctx.ExprCanBeRemovedIfUnused(test) && ctx.ExprCanBeRemovedIfUnused(y.Target) {\n\t\t\t\tsameTailArgs := true\n\t\t\t\tfor i, count := 1, len(y.Args); i < count; i++ {\n\t\t\t\t\tif !ValuesLookTheSame(y.Args[i].Data, n.Args[i].Data) {\n\t\t\t\t\t\tsameTailArgs = false\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif sameTailArgs {\n\t\t\t\t\tyesSpread, yesIsSpread := y.Args[0].Data.(*ESpread)\n\t\t\t\t\tnoSpread, noIsSpread := n.Args[0].Data.(*ESpread)\n\n\t\t\t\t\t// \"a ? b(...c) : b(...e)\" => \"b(...a ? c : e)\"\n\t\t\t\t\tif yesIsSpread && noIsSpread {\n\t\t\t\t\t\t// Don't mutate the original AST\n\t\t\t\t\t\ttemp := EIf{Test: test, Yes: yesSpread.Value, No: noSpread.Value}\n\t\t\t\t\t\tclone := *y\n\t\t\t\t\t\tclone.Args = append([]Expr{}, clone.Args...)\n\t\t\t\t\t\tclone.Args[0] = Expr{Loc: loc, Data: &ESpread{Value: ctx.MangleIfExpr(loc, &temp, unsupportedFeatures)}}\n\t\t\t\t\t\treturn Expr{Loc: loc, Data: &clone}\n\t\t\t\t\t}\n\n\t\t\t\t\t// \"a ? b(c) : b(e)\" => \"b(a ? c : e)\"\n\t\t\t\t\tif !yesIsSpread && !noIsSpread {\n\t\t\t\t\t\t// Don't mutate the original AST\n\t\t\t\t\t\ttemp := EIf{Test: test, Yes: y.Args[0], No: n.Args[0]}\n\t\t\t\t\t\tclone := *y\n\t\t\t\t\t\tclone.Args = append([]Expr{}, clone.Args...)\n\t\t\t\t\t\tclone.Args[0] = ctx.MangleIfExpr(loc, &temp, unsupportedFeatures)\n\t\t\t\t\t\treturn Expr{Loc: loc, Data: &clone}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Try using the \"??\" or \"?.\" operators\n\tif binary, ok := test.Data.(*EBinary); ok {\n\t\tvar check Expr\n\t\tvar whenNull Expr\n\t\tvar whenNonNull Expr\n\n\t\tswitch binary.Op {\n\t\tcase BinOpLooseEq:\n\t\t\tif _, ok := binary.Right.Data.(*ENull); ok {\n\t\t\t\t// \"a == null ? _ : _\"\n\t\t\t\tcheck = binary.Left\n\t\t\t\twhenNull = yes\n\t\t\t\twhenNonNull = no\n\t\t\t} else if _, ok := binary.Left.Data.(*ENull); ok {\n\t\t\t\t// \"null == a ? _ : _\"\n\t\t\t\tcheck = binary.Right\n\t\t\t\twhenNull = yes\n\t\t\t\twhenNonNull = no\n\t\t\t}\n\n\t\tcase BinOpLooseNe:\n\t\t\tif _, ok := binary.Right.Data.(*ENull); ok {\n\t\t\t\t// \"a != null ? _ : _\"\n\t\t\t\tcheck = binary.Left\n\t\t\t\twhenNonNull = yes\n\t\t\t\twhenNull = no\n\t\t\t} else if _, ok := binary.Left.Data.(*ENull); ok {\n\t\t\t\t// \"null != a ? _ : _\"\n\t\t\t\tcheck = binary.Right\n\t\t\t\twhenNonNull = yes\n\t\t\t\twhenNull = no\n\t\t\t}\n\t\t}\n\n\t\tif ctx.ExprCanBeRemovedIfUnused(check) {\n\t\t\t// \"a != null ? a : b\" => \"a ?? b\"\n\t\t\tif !unsupportedFeatures.Has(compat.NullishCoalescing) && ValuesLookTheSame(check.Data, whenNonNull.Data) {\n\t\t\t\treturn JoinWithLeftAssociativeOp(BinOpNullishCoalescing, check, whenNull)\n\t\t\t}\n\n\t\t\t// \"a != null ? a.b.c[d](e) : undefined\" => \"a?.b.c[d](e)\"\n\t\t\tif !unsupportedFeatures.Has(compat.OptionalChain) {\n\t\t\t\tif _, ok := whenNull.Data.(*EUndefined); ok && TryToInsertOptionalChain(check, whenNonNull) {\n\t\t\t\t\treturn whenNonNull\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Don't mutate the original AST\n\tif test != e.Test || yes != e.Yes || no != e.No {\n\t\treturn Expr{Loc: loc, Data: &EIf{Test: test, Yes: yes, No: no}}\n\t}\n\n\treturn Expr{Loc: loc, Data: e}\n}\n\nfunc ForEachIdentifierBindingInDecls(decls []Decl, callback func(loc logger.Loc, b *BIdentifier)) {\n\tfor _, decl := range decls {\n\t\tForEachIdentifierBinding(decl.Binding, callback)\n\t}\n}\n\nfunc ForEachIdentifierBinding(binding Binding, callback func(loc logger.Loc, b *BIdentifier)) {\n\tswitch b := binding.Data.(type) {\n\tcase *BMissing:\n\n\tcase *BIdentifier:\n\t\tcallback(binding.Loc, b)\n\n\tcase *BArray:\n\t\tfor _, item := range b.Items {\n\t\t\tForEachIdentifierBinding(item.Binding, callback)\n\t\t}\n\n\tcase *BObject:\n\t\tfor _, property := range b.Properties {\n\t\t\tForEachIdentifierBinding(property.Value, callback)\n\t\t}\n\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/js_ast/js_ident.go",
    "content": "package js_ast\n\nimport (\n\t\"strings\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\nfunc IsIdentifier(text string) bool {\n\tif len(text) == 0 {\n\t\treturn false\n\t}\n\tfor i, codePoint := range text {\n\t\tif i == 0 {\n\t\t\tif !IsIdentifierStart(codePoint) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else {\n\t\t\tif !IsIdentifierContinue(codePoint) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\nfunc IsIdentifierES5AndESNext(text string) bool {\n\tif len(text) == 0 {\n\t\treturn false\n\t}\n\tfor i, codePoint := range text {\n\t\tif i == 0 {\n\t\t\tif !IsIdentifierStartES5AndESNext(codePoint) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else {\n\t\t\tif !IsIdentifierContinueES5AndESNext(codePoint) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\nfunc ForceValidIdentifier(prefix string, text string) string {\n\tsb := strings.Builder{}\n\n\t// Private identifiers must be prefixed by \"#\"\n\tif prefix != \"\" {\n\t\tsb.WriteString(prefix)\n\t}\n\n\t// Identifier start\n\tc, width := utf8.DecodeRuneInString(text)\n\ttext = text[width:]\n\tif IsIdentifierStart(c) {\n\t\tsb.WriteRune(c)\n\t} else {\n\t\tsb.WriteRune('_')\n\t}\n\n\t// Identifier continue\n\tfor text != \"\" {\n\t\tc, width := utf8.DecodeRuneInString(text)\n\t\ttext = text[width:]\n\t\tif IsIdentifierContinue(c) {\n\t\t\tsb.WriteRune(c)\n\t\t} else {\n\t\t\tsb.WriteRune('_')\n\t\t}\n\t}\n\n\treturn sb.String()\n}\n\n// This does \"IsIdentifier(UTF16ToString(text))\" without any allocations\nfunc IsIdentifierUTF16(text []uint16) bool {\n\tn := len(text)\n\tif n == 0 {\n\t\treturn false\n\t}\n\tfor i := 0; i < n; i++ {\n\t\tisStart := i == 0\n\t\tr1 := rune(text[i])\n\t\tif r1 >= 0xD800 && r1 <= 0xDBFF && i+1 < n {\n\t\t\tif r2 := rune(text[i+1]); r2 >= 0xDC00 && r2 <= 0xDFFF {\n\t\t\t\tr1 = (r1 << 10) + r2 + (0x10000 - (0xD800 << 10) - 0xDC00)\n\t\t\t\ti++\n\t\t\t}\n\t\t}\n\t\tif isStart {\n\t\t\tif !IsIdentifierStart(r1) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else {\n\t\t\tif !IsIdentifierContinue(r1) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n// This does \"IsIdentifierES5AndESNext(UTF16ToString(text))\" without any allocations\nfunc IsIdentifierES5AndESNextUTF16(text []uint16) bool {\n\tn := len(text)\n\tif n == 0 {\n\t\treturn false\n\t}\n\tfor i := 0; i < n; i++ {\n\t\tisStart := i == 0\n\t\tr1 := rune(text[i])\n\t\tif r1 >= 0xD800 && r1 <= 0xDBFF && i+1 < n {\n\t\t\tif r2 := rune(text[i+1]); r2 >= 0xDC00 && r2 <= 0xDFFF {\n\t\t\t\tr1 = (r1 << 10) + r2 + (0x10000 - (0xD800 << 10) - 0xDC00)\n\t\t\t\ti++\n\t\t\t}\n\t\t}\n\t\tif isStart {\n\t\t\tif !IsIdentifierStartES5AndESNext(r1) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else {\n\t\t\tif !IsIdentifierContinueES5AndESNext(r1) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\nfunc IsIdentifierStart(codePoint rune) bool {\n\tswitch codePoint {\n\tcase '_', '$',\n\t\t'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',\n\t\t'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',\n\t\t'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',\n\t\t'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z':\n\t\treturn true\n\t}\n\n\t// All ASCII identifier start code points are listed above\n\tif codePoint < 0x7F {\n\t\treturn false\n\t}\n\n\treturn unicode.Is(idStartES5OrESNext, codePoint)\n}\n\nfunc IsIdentifierContinue(codePoint rune) bool {\n\tswitch codePoint {\n\tcase '_', '$', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n\t\t'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',\n\t\t'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',\n\t\t'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',\n\t\t'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z':\n\t\treturn true\n\t}\n\n\t// All ASCII identifier start code points are listed above\n\tif codePoint < 0x7F {\n\t\treturn false\n\t}\n\n\t// ZWNJ and ZWJ are allowed in identifiers\n\tif codePoint == 0x200C || codePoint == 0x200D {\n\t\treturn true\n\t}\n\n\treturn unicode.Is(idContinueES5OrESNext, codePoint)\n}\n\nfunc IsIdentifierStartES5AndESNext(codePoint rune) bool {\n\tswitch codePoint {\n\tcase '_', '$',\n\t\t'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',\n\t\t'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',\n\t\t'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',\n\t\t'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z':\n\t\treturn true\n\t}\n\n\t// All ASCII identifier start code points are listed above\n\tif codePoint < 0x7F {\n\t\treturn false\n\t}\n\n\treturn unicode.Is(idStartES5AndESNext, codePoint)\n}\n\nfunc IsIdentifierContinueES5AndESNext(codePoint rune) bool {\n\tswitch codePoint {\n\tcase '_', '$', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n\t\t'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',\n\t\t'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',\n\t\t'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',\n\t\t'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z':\n\t\treturn true\n\t}\n\n\t// All ASCII identifier start code points are listed above\n\tif codePoint < 0x7F {\n\t\treturn false\n\t}\n\n\t// ZWNJ and ZWJ are allowed in identifiers\n\tif codePoint == 0x200C || codePoint == 0x200D {\n\t\treturn true\n\t}\n\n\treturn unicode.Is(idContinueES5AndESNext, codePoint)\n}\n\n// See the \"White Space Code Points\" table in the ECMAScript standard\nfunc IsWhitespace(codePoint rune) bool {\n\tswitch codePoint {\n\tcase\n\t\t'\\u0009', // character tabulation\n\t\t'\\u000B', // line tabulation\n\t\t'\\u000C', // form feed\n\t\t'\\u0020', // space\n\t\t'\\u00A0', // no-break space\n\n\t\t// Unicode \"Space_Separator\" code points\n\t\t'\\u1680', // ogham space mark\n\t\t'\\u2000', // en quad\n\t\t'\\u2001', // em quad\n\t\t'\\u2002', // en space\n\t\t'\\u2003', // em space\n\t\t'\\u2004', // three-per-em space\n\t\t'\\u2005', // four-per-em space\n\t\t'\\u2006', // six-per-em space\n\t\t'\\u2007', // figure space\n\t\t'\\u2008', // punctuation space\n\t\t'\\u2009', // thin space\n\t\t'\\u200A', // hair space\n\t\t'\\u202F', // narrow no-break space\n\t\t'\\u205F', // medium mathematical space\n\t\t'\\u3000', // ideographic space\n\n\t\t'\\uFEFF': // zero width non-breaking space\n\t\treturn true\n\n\tdefault:\n\t\treturn false\n\t}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/js_lexer/tables.go",
    "content": "package js_lexer\n\nvar tokenToString = map[T]string{\n\tTEndOfFile:   \"end of file\",\n\tTSyntaxError: \"syntax error\",\n\tTHashbang:    \"hashbang comment\",\n\n\t// Literals\n\tTNoSubstitutionTemplateLiteral: \"template literal\",\n\tTNumericLiteral:                \"number\",\n\tTStringLiteral:                 \"string\",\n\tTBigIntegerLiteral:             \"bigint\",\n\n\t// Pseudo-literals\n\tTTemplateHead:   \"template literal\",\n\tTTemplateMiddle: \"template literal\",\n\tTTemplateTail:   \"template literal\",\n\n\t// Punctuation\n\tTAmpersand:                         \"\\\"&\\\"\",\n\tTAmpersandAmpersand:                \"\\\"&&\\\"\",\n\tTAsterisk:                          \"\\\"*\\\"\",\n\tTAsteriskAsterisk:                  \"\\\"**\\\"\",\n\tTAt:                                \"\\\"@\\\"\",\n\tTBar:                               \"\\\"|\\\"\",\n\tTBarBar:                            \"\\\"||\\\"\",\n\tTCaret:                             \"\\\"^\\\"\",\n\tTCloseBrace:                        \"\\\"}\\\"\",\n\tTCloseBracket:                      \"\\\"]\\\"\",\n\tTCloseParen:                        \"\\\")\\\"\",\n\tTColon:                             \"\\\":\\\"\",\n\tTComma:                             \"\\\",\\\"\",\n\tTDot:                               \"\\\".\\\"\",\n\tTDotDotDot:                         \"\\\"...\\\"\",\n\tTEqualsEquals:                      \"\\\"==\\\"\",\n\tTEqualsEqualsEquals:                \"\\\"===\\\"\",\n\tTEqualsGreaterThan:                 \"\\\"=>\\\"\",\n\tTExclamation:                       \"\\\"!\\\"\",\n\tTExclamationEquals:                 \"\\\"!=\\\"\",\n\tTExclamationEqualsEquals:           \"\\\"!==\\\"\",\n\tTGreaterThan:                       \"\\\">\\\"\",\n\tTGreaterThanEquals:                 \"\\\">=\\\"\",\n\tTGreaterThanGreaterThan:            \"\\\">>\\\"\",\n\tTGreaterThanGreaterThanGreaterThan: \"\\\">>>\\\"\",\n\tTLessThan:                          \"\\\"<\\\"\",\n\tTLessThanEquals:                    \"\\\"<=\\\"\",\n\tTLessThanLessThan:                  \"\\\"<<\\\"\",\n\tTMinus:                             \"\\\"-\\\"\",\n\tTMinusMinus:                        \"\\\"--\\\"\",\n\tTOpenBrace:                         \"\\\"{\\\"\",\n\tTOpenBracket:                       \"\\\"[\\\"\",\n\tTOpenParen:                         \"\\\"(\\\"\",\n\tTPercent:                           \"\\\"%\\\"\",\n\tTPlus:                              \"\\\"+\\\"\",\n\tTPlusPlus:                          \"\\\"++\\\"\",\n\tTQuestion:                          \"\\\"?\\\"\",\n\tTQuestionDot:                       \"\\\"?.\\\"\",\n\tTQuestionQuestion:                  \"\\\"??\\\"\",\n\tTSemicolon:                         \"\\\";\\\"\",\n\tTSlash:                             \"\\\"/\\\"\",\n\tTTilde:                             \"\\\"~\\\"\",\n\n\t// Assignments\n\tTAmpersandAmpersandEquals:                \"\\\"&&=\\\"\",\n\tTAmpersandEquals:                         \"\\\"&=\\\"\",\n\tTAsteriskAsteriskEquals:                  \"\\\"**=\\\"\",\n\tTAsteriskEquals:                          \"\\\"*=\\\"\",\n\tTBarBarEquals:                            \"\\\"||=\\\"\",\n\tTBarEquals:                               \"\\\"|=\\\"\",\n\tTCaretEquals:                             \"\\\"^=\\\"\",\n\tTEquals:                                  \"\\\"=\\\"\",\n\tTGreaterThanGreaterThanEquals:            \"\\\">>=\\\"\",\n\tTGreaterThanGreaterThanGreaterThanEquals: \"\\\">>>=\\\"\",\n\tTLessThanLessThanEquals:                  \"\\\"<<=\\\"\",\n\tTMinusEquals:                             \"\\\"-=\\\"\",\n\tTPercentEquals:                           \"\\\"%=\\\"\",\n\tTPlusEquals:                              \"\\\"+=\\\"\",\n\tTQuestionQuestionEquals:                  \"\\\"??=\\\"\",\n\tTSlashEquals:                             \"\\\"/=\\\"\",\n\n\t// Class-private fields and methods\n\tTPrivateIdentifier: \"private identifier\",\n\n\t// Identifiers\n\tTIdentifier:     \"identifier\",\n\tTEscapedKeyword: \"escaped keyword\",\n\n\t// Reserved words\n\tTBreak:      \"\\\"break\\\"\",\n\tTCase:       \"\\\"case\\\"\",\n\tTCatch:      \"\\\"catch\\\"\",\n\tTClass:      \"\\\"class\\\"\",\n\tTConst:      \"\\\"const\\\"\",\n\tTContinue:   \"\\\"continue\\\"\",\n\tTDebugger:   \"\\\"debugger\\\"\",\n\tTDefault:    \"\\\"default\\\"\",\n\tTDelete:     \"\\\"delete\\\"\",\n\tTDo:         \"\\\"do\\\"\",\n\tTElse:       \"\\\"else\\\"\",\n\tTEnum:       \"\\\"enum\\\"\",\n\tTExport:     \"\\\"export\\\"\",\n\tTExtends:    \"\\\"extends\\\"\",\n\tTFalse:      \"\\\"false\\\"\",\n\tTFinally:    \"\\\"finally\\\"\",\n\tTFor:        \"\\\"for\\\"\",\n\tTFunction:   \"\\\"function\\\"\",\n\tTIf:         \"\\\"if\\\"\",\n\tTImport:     \"\\\"import\\\"\",\n\tTIn:         \"\\\"in\\\"\",\n\tTInstanceof: \"\\\"instanceof\\\"\",\n\tTNew:        \"\\\"new\\\"\",\n\tTNull:       \"\\\"null\\\"\",\n\tTReturn:     \"\\\"return\\\"\",\n\tTSuper:      \"\\\"super\\\"\",\n\tTSwitch:     \"\\\"switch\\\"\",\n\tTThis:       \"\\\"this\\\"\",\n\tTThrow:      \"\\\"throw\\\"\",\n\tTTrue:       \"\\\"true\\\"\",\n\tTTry:        \"\\\"try\\\"\",\n\tTTypeof:     \"\\\"typeof\\\"\",\n\tTVar:        \"\\\"var\\\"\",\n\tTVoid:       \"\\\"void\\\"\",\n\tTWhile:      \"\\\"while\\\"\",\n\tTWith:       \"\\\"with\\\"\",\n}\n\n// This is from https://github.com/microsoft/TypeScript/blob/master/src/compiler/transformers/jsx.ts\nvar jsxEntity = map[string]rune{\n\t\"quot\":     0x0022,\n\t\"amp\":      0x0026,\n\t\"apos\":     0x0027,\n\t\"lt\":       0x003C,\n\t\"gt\":       0x003E,\n\t\"nbsp\":     0x00A0,\n\t\"iexcl\":    0x00A1,\n\t\"cent\":     0x00A2,\n\t\"pound\":    0x00A3,\n\t\"curren\":   0x00A4,\n\t\"yen\":      0x00A5,\n\t\"brvbar\":   0x00A6,\n\t\"sect\":     0x00A7,\n\t\"uml\":      0x00A8,\n\t\"copy\":     0x00A9,\n\t\"ordf\":     0x00AA,\n\t\"laquo\":    0x00AB,\n\t\"not\":      0x00AC,\n\t\"shy\":      0x00AD,\n\t\"reg\":      0x00AE,\n\t\"macr\":     0x00AF,\n\t\"deg\":      0x00B0,\n\t\"plusmn\":   0x00B1,\n\t\"sup2\":     0x00B2,\n\t\"sup3\":     0x00B3,\n\t\"acute\":    0x00B4,\n\t\"micro\":    0x00B5,\n\t\"para\":     0x00B6,\n\t\"middot\":   0x00B7,\n\t\"cedil\":    0x00B8,\n\t\"sup1\":     0x00B9,\n\t\"ordm\":     0x00BA,\n\t\"raquo\":    0x00BB,\n\t\"frac14\":   0x00BC,\n\t\"frac12\":   0x00BD,\n\t\"frac34\":   0x00BE,\n\t\"iquest\":   0x00BF,\n\t\"Agrave\":   0x00C0,\n\t\"Aacute\":   0x00C1,\n\t\"Acirc\":    0x00C2,\n\t\"Atilde\":   0x00C3,\n\t\"Auml\":     0x00C4,\n\t\"Aring\":    0x00C5,\n\t\"AElig\":    0x00C6,\n\t\"Ccedil\":   0x00C7,\n\t\"Egrave\":   0x00C8,\n\t\"Eacute\":   0x00C9,\n\t\"Ecirc\":    0x00CA,\n\t\"Euml\":     0x00CB,\n\t\"Igrave\":   0x00CC,\n\t\"Iacute\":   0x00CD,\n\t\"Icirc\":    0x00CE,\n\t\"Iuml\":     0x00CF,\n\t\"ETH\":      0x00D0,\n\t\"Ntilde\":   0x00D1,\n\t\"Ograve\":   0x00D2,\n\t\"Oacute\":   0x00D3,\n\t\"Ocirc\":    0x00D4,\n\t\"Otilde\":   0x00D5,\n\t\"Ouml\":     0x00D6,\n\t\"times\":    0x00D7,\n\t\"Oslash\":   0x00D8,\n\t\"Ugrave\":   0x00D9,\n\t\"Uacute\":   0x00DA,\n\t\"Ucirc\":    0x00DB,\n\t\"Uuml\":     0x00DC,\n\t\"Yacute\":   0x00DD,\n\t\"THORN\":    0x00DE,\n\t\"szlig\":    0x00DF,\n\t\"agrave\":   0x00E0,\n\t\"aacute\":   0x00E1,\n\t\"acirc\":    0x00E2,\n\t\"atilde\":   0x00E3,\n\t\"auml\":     0x00E4,\n\t\"aring\":    0x00E5,\n\t\"aelig\":    0x00E6,\n\t\"ccedil\":   0x00E7,\n\t\"egrave\":   0x00E8,\n\t\"eacute\":   0x00E9,\n\t\"ecirc\":    0x00EA,\n\t\"euml\":     0x00EB,\n\t\"igrave\":   0x00EC,\n\t\"iacute\":   0x00ED,\n\t\"icirc\":    0x00EE,\n\t\"iuml\":     0x00EF,\n\t\"eth\":      0x00F0,\n\t\"ntilde\":   0x00F1,\n\t\"ograve\":   0x00F2,\n\t\"oacute\":   0x00F3,\n\t\"ocirc\":    0x00F4,\n\t\"otilde\":   0x00F5,\n\t\"ouml\":     0x00F6,\n\t\"divide\":   0x00F7,\n\t\"oslash\":   0x00F8,\n\t\"ugrave\":   0x00F9,\n\t\"uacute\":   0x00FA,\n\t\"ucirc\":    0x00FB,\n\t\"uuml\":     0x00FC,\n\t\"yacute\":   0x00FD,\n\t\"thorn\":    0x00FE,\n\t\"yuml\":     0x00FF,\n\t\"OElig\":    0x0152,\n\t\"oelig\":    0x0153,\n\t\"Scaron\":   0x0160,\n\t\"scaron\":   0x0161,\n\t\"Yuml\":     0x0178,\n\t\"fnof\":     0x0192,\n\t\"circ\":     0x02C6,\n\t\"tilde\":    0x02DC,\n\t\"Alpha\":    0x0391,\n\t\"Beta\":     0x0392,\n\t\"Gamma\":    0x0393,\n\t\"Delta\":    0x0394,\n\t\"Epsilon\":  0x0395,\n\t\"Zeta\":     0x0396,\n\t\"Eta\":      0x0397,\n\t\"Theta\":    0x0398,\n\t\"Iota\":     0x0399,\n\t\"Kappa\":    0x039A,\n\t\"Lambda\":   0x039B,\n\t\"Mu\":       0x039C,\n\t\"Nu\":       0x039D,\n\t\"Xi\":       0x039E,\n\t\"Omicron\":  0x039F,\n\t\"Pi\":       0x03A0,\n\t\"Rho\":      0x03A1,\n\t\"Sigma\":    0x03A3,\n\t\"Tau\":      0x03A4,\n\t\"Upsilon\":  0x03A5,\n\t\"Phi\":      0x03A6,\n\t\"Chi\":      0x03A7,\n\t\"Psi\":      0x03A8,\n\t\"Omega\":    0x03A9,\n\t\"alpha\":    0x03B1,\n\t\"beta\":     0x03B2,\n\t\"gamma\":    0x03B3,\n\t\"delta\":    0x03B4,\n\t\"epsilon\":  0x03B5,\n\t\"zeta\":     0x03B6,\n\t\"eta\":      0x03B7,\n\t\"theta\":    0x03B8,\n\t\"iota\":     0x03B9,\n\t\"kappa\":    0x03BA,\n\t\"lambda\":   0x03BB,\n\t\"mu\":       0x03BC,\n\t\"nu\":       0x03BD,\n\t\"xi\":       0x03BE,\n\t\"omicron\":  0x03BF,\n\t\"pi\":       0x03C0,\n\t\"rho\":      0x03C1,\n\t\"sigmaf\":   0x03C2,\n\t\"sigma\":    0x03C3,\n\t\"tau\":      0x03C4,\n\t\"upsilon\":  0x03C5,\n\t\"phi\":      0x03C6,\n\t\"chi\":      0x03C7,\n\t\"psi\":      0x03C8,\n\t\"omega\":    0x03C9,\n\t\"thetasym\": 0x03D1,\n\t\"upsih\":    0x03D2,\n\t\"piv\":      0x03D6,\n\t\"ensp\":     0x2002,\n\t\"emsp\":     0x2003,\n\t\"thinsp\":   0x2009,\n\t\"zwnj\":     0x200C,\n\t\"zwj\":      0x200D,\n\t\"lrm\":      0x200E,\n\t\"rlm\":      0x200F,\n\t\"ndash\":    0x2013,\n\t\"mdash\":    0x2014,\n\t\"lsquo\":    0x2018,\n\t\"rsquo\":    0x2019,\n\t\"sbquo\":    0x201A,\n\t\"ldquo\":    0x201C,\n\t\"rdquo\":    0x201D,\n\t\"bdquo\":    0x201E,\n\t\"dagger\":   0x2020,\n\t\"Dagger\":   0x2021,\n\t\"bull\":     0x2022,\n\t\"hellip\":   0x2026,\n\t\"permil\":   0x2030,\n\t\"prime\":    0x2032,\n\t\"Prime\":    0x2033,\n\t\"lsaquo\":   0x2039,\n\t\"rsaquo\":   0x203A,\n\t\"oline\":    0x203E,\n\t\"frasl\":    0x2044,\n\t\"euro\":     0x20AC,\n\t\"image\":    0x2111,\n\t\"weierp\":   0x2118,\n\t\"real\":     0x211C,\n\t\"trade\":    0x2122,\n\t\"alefsym\":  0x2135,\n\t\"larr\":     0x2190,\n\t\"uarr\":     0x2191,\n\t\"rarr\":     0x2192,\n\t\"darr\":     0x2193,\n\t\"harr\":     0x2194,\n\t\"crarr\":    0x21B5,\n\t\"lArr\":     0x21D0,\n\t\"uArr\":     0x21D1,\n\t\"rArr\":     0x21D2,\n\t\"dArr\":     0x21D3,\n\t\"hArr\":     0x21D4,\n\t\"forall\":   0x2200,\n\t\"part\":     0x2202,\n\t\"exist\":    0x2203,\n\t\"empty\":    0x2205,\n\t\"nabla\":    0x2207,\n\t\"isin\":     0x2208,\n\t\"notin\":    0x2209,\n\t\"ni\":       0x220B,\n\t\"prod\":     0x220F,\n\t\"sum\":      0x2211,\n\t\"minus\":    0x2212,\n\t\"lowast\":   0x2217,\n\t\"radic\":    0x221A,\n\t\"prop\":     0x221D,\n\t\"infin\":    0x221E,\n\t\"ang\":      0x2220,\n\t\"and\":      0x2227,\n\t\"or\":       0x2228,\n\t\"cap\":      0x2229,\n\t\"cup\":      0x222A,\n\t\"int\":      0x222B,\n\t\"there4\":   0x2234,\n\t\"sim\":      0x223C,\n\t\"cong\":     0x2245,\n\t\"asymp\":    0x2248,\n\t\"ne\":       0x2260,\n\t\"equiv\":    0x2261,\n\t\"le\":       0x2264,\n\t\"ge\":       0x2265,\n\t\"sub\":      0x2282,\n\t\"sup\":      0x2283,\n\t\"nsub\":     0x2284,\n\t\"sube\":     0x2286,\n\t\"supe\":     0x2287,\n\t\"oplus\":    0x2295,\n\t\"otimes\":   0x2297,\n\t\"perp\":     0x22A5,\n\t\"sdot\":     0x22C5,\n\t\"lceil\":    0x2308,\n\t\"rceil\":    0x2309,\n\t\"lfloor\":   0x230A,\n\t\"rfloor\":   0x230B,\n\t\"lang\":     0x2329,\n\t\"rang\":     0x232A,\n\t\"loz\":      0x25CA,\n\t\"spades\":   0x2660,\n\t\"clubs\":    0x2663,\n\t\"hearts\":   0x2665,\n\t\"diams\":    0x2666,\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/js_parser/js_parser_lower_class.go",
    "content": "package js_parser\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/compat\"\n\t\"github.com/evanw/esbuild/internal/config\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n)\n\nfunc (p *parser) privateSymbolNeedsToBeLowered(private *js_ast.EPrivateIdentifier) bool {\n\tsymbol := &p.symbols[private.Ref.InnerIndex]\n\treturn p.options.unsupportedJSFeatures.Has(compat.SymbolFeature(symbol.Kind)) || symbol.Flags.Has(ast.PrivateSymbolMustBeLowered)\n}\n\nfunc (p *parser) lowerPrivateBrandCheck(target js_ast.Expr, loc logger.Loc, private *js_ast.EPrivateIdentifier) js_ast.Expr {\n\t// \"#field in this\" => \"__privateIn(#field, this)\"\n\treturn p.callRuntime(loc, \"__privateIn\", []js_ast.Expr{\n\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\ttarget,\n\t})\n}\n\nfunc (p *parser) lowerPrivateGet(target js_ast.Expr, loc logger.Loc, private *js_ast.EPrivateIdentifier) js_ast.Expr {\n\tswitch p.symbols[private.Ref.InnerIndex].Kind {\n\tcase ast.SymbolPrivateMethod, ast.SymbolPrivateStaticMethod:\n\t\t// \"this.#method\" => \"__privateMethod(this, #method, method_fn)\"\n\t\tfnRef := p.privateGetters[private.Ref]\n\t\tp.recordUsage(fnRef)\n\t\treturn p.callRuntime(target.Loc, \"__privateMethod\", []js_ast.Expr{\n\t\t\ttarget,\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: fnRef}},\n\t\t})\n\n\tcase ast.SymbolPrivateGet, ast.SymbolPrivateStaticGet,\n\t\tast.SymbolPrivateGetSetPair, ast.SymbolPrivateStaticGetSetPair:\n\t\t// \"this.#getter\" => \"__privateGet(this, #getter, getter_get)\"\n\t\tfnRef := p.privateGetters[private.Ref]\n\t\tp.recordUsage(fnRef)\n\t\treturn p.callRuntime(target.Loc, \"__privateGet\", []js_ast.Expr{\n\t\t\ttarget,\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: fnRef}},\n\t\t})\n\n\tdefault:\n\t\t// \"this.#field\" => \"__privateGet(this, #field)\"\n\t\treturn p.callRuntime(target.Loc, \"__privateGet\", []js_ast.Expr{\n\t\t\ttarget,\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\t})\n\t}\n}\n\nfunc (p *parser) lowerPrivateSet(\n\ttarget js_ast.Expr,\n\tloc logger.Loc,\n\tprivate *js_ast.EPrivateIdentifier,\n\tvalue js_ast.Expr,\n) js_ast.Expr {\n\tswitch p.symbols[private.Ref.InnerIndex].Kind {\n\tcase ast.SymbolPrivateSet, ast.SymbolPrivateStaticSet,\n\t\tast.SymbolPrivateGetSetPair, ast.SymbolPrivateStaticGetSetPair:\n\t\t// \"this.#setter = 123\" => \"__privateSet(this, #setter, 123, setter_set)\"\n\t\tfnRef := p.privateSetters[private.Ref]\n\t\tp.recordUsage(fnRef)\n\t\treturn p.callRuntime(target.Loc, \"__privateSet\", []js_ast.Expr{\n\t\t\ttarget,\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\t\tvalue,\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: fnRef}},\n\t\t})\n\n\tdefault:\n\t\t// \"this.#field = 123\" => \"__privateSet(this, #field, 123)\"\n\t\treturn p.callRuntime(target.Loc, \"__privateSet\", []js_ast.Expr{\n\t\t\ttarget,\n\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\t\tvalue,\n\t\t})\n\t}\n}\n\nfunc (p *parser) lowerPrivateSetUnOp(target js_ast.Expr, loc logger.Loc, private *js_ast.EPrivateIdentifier, op js_ast.OpCode) js_ast.Expr {\n\tkind := p.symbols[private.Ref.InnerIndex].Kind\n\n\t// Determine the setter, if any\n\tvar setter js_ast.Expr\n\tswitch kind {\n\tcase ast.SymbolPrivateSet, ast.SymbolPrivateStaticSet,\n\t\tast.SymbolPrivateGetSetPair, ast.SymbolPrivateStaticGetSetPair:\n\t\tref := p.privateSetters[private.Ref]\n\t\tp.recordUsage(ref)\n\t\tsetter = js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}\n\t}\n\n\t// Determine the getter, if any\n\tvar getter js_ast.Expr\n\tswitch kind {\n\tcase ast.SymbolPrivateGet, ast.SymbolPrivateStaticGet,\n\t\tast.SymbolPrivateGetSetPair, ast.SymbolPrivateStaticGetSetPair:\n\t\tref := p.privateGetters[private.Ref]\n\t\tp.recordUsage(ref)\n\t\tgetter = js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}\n\t}\n\n\t// Only include necessary arguments\n\targs := []js_ast.Expr{\n\t\ttarget,\n\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t}\n\tif setter.Data != nil {\n\t\targs = append(args, setter)\n\t}\n\tif getter.Data != nil {\n\t\tif setter.Data == nil {\n\t\t\targs = append(args, js_ast.Expr{Loc: loc, Data: js_ast.ENullShared})\n\t\t}\n\t\targs = append(args, getter)\n\t}\n\n\t// \"target.#private++\" => \"__privateWrapper(target, #private, private_set, private_get)._++\"\n\treturn js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{\n\t\tOp: op,\n\t\tValue: js_ast.Expr{Loc: target.Loc, Data: &js_ast.EDot{\n\t\t\tTarget:  p.callRuntime(target.Loc, \"__privateWrapper\", args),\n\t\t\tNameLoc: target.Loc,\n\t\t\tName:    \"_\",\n\t\t}},\n\t}}\n}\n\nfunc (p *parser) lowerPrivateSetBinOp(target js_ast.Expr, loc logger.Loc, private *js_ast.EPrivateIdentifier, op js_ast.OpCode, value js_ast.Expr) js_ast.Expr {\n\t// \"target.#private += 123\" => \"__privateSet(target, #private, __privateGet(target, #private) + 123)\"\n\ttargetFunc, targetWrapFunc := p.captureValueWithPossibleSideEffects(target.Loc, 2, target, valueDefinitelyNotMutated)\n\treturn targetWrapFunc(p.lowerPrivateSet(targetFunc(), loc, private, js_ast.Expr{Loc: value.Loc, Data: &js_ast.EBinary{\n\t\tOp:    op,\n\t\tLeft:  p.lowerPrivateGet(targetFunc(), loc, private),\n\t\tRight: value,\n\t}}))\n}\n\n// Returns valid data if target is an expression of the form \"foo.#bar\" and if\n// the language target is such that private members must be lowered\nfunc (p *parser) extractPrivateIndex(target js_ast.Expr) (js_ast.Expr, logger.Loc, *js_ast.EPrivateIdentifier) {\n\tif index, ok := target.Data.(*js_ast.EIndex); ok {\n\t\tif private, ok := index.Index.Data.(*js_ast.EPrivateIdentifier); ok && p.privateSymbolNeedsToBeLowered(private) {\n\t\t\treturn index.Target, index.Index.Loc, private\n\t\t}\n\t}\n\treturn js_ast.Expr{}, logger.Loc{}, nil\n}\n\n// Returns a valid property if target is an expression of the form \"super.bar\"\n// or \"super[bar]\" and if the situation is such that it must be lowered\nfunc (p *parser) extractSuperProperty(target js_ast.Expr) js_ast.Expr {\n\tswitch e := target.Data.(type) {\n\tcase *js_ast.EDot:\n\t\tif p.shouldLowerSuperPropertyAccess(e.Target) {\n\t\t\treturn js_ast.Expr{Loc: e.NameLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(e.Name)}}\n\t\t}\n\tcase *js_ast.EIndex:\n\t\tif p.shouldLowerSuperPropertyAccess(e.Target) {\n\t\t\treturn e.Index\n\t\t}\n\t}\n\treturn js_ast.Expr{}\n}\n\nfunc (p *parser) lowerSuperPropertyOrPrivateInAssign(expr js_ast.Expr) (js_ast.Expr, bool) {\n\tdidLower := false\n\n\tswitch e := expr.Data.(type) {\n\tcase *js_ast.ESpread:\n\t\tif value, ok := p.lowerSuperPropertyOrPrivateInAssign(e.Value); ok {\n\t\t\te.Value = value\n\t\t\tdidLower = true\n\t\t}\n\n\tcase *js_ast.EDot:\n\t\t// \"[super.foo] = [bar]\" => \"[__superWrapper(this, 'foo')._] = [bar]\"\n\t\tif p.shouldLowerSuperPropertyAccess(e.Target) {\n\t\t\tkey := js_ast.Expr{Loc: e.NameLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(e.Name)}}\n\t\t\texpr = p.callSuperPropertyWrapper(expr.Loc, key)\n\t\t\tdidLower = true\n\t\t}\n\n\tcase *js_ast.EIndex:\n\t\t// \"[super[foo]] = [bar]\" => \"[__superWrapper(this, foo)._] = [bar]\"\n\t\tif p.shouldLowerSuperPropertyAccess(e.Target) {\n\t\t\texpr = p.callSuperPropertyWrapper(expr.Loc, e.Index)\n\t\t\tdidLower = true\n\t\t\tbreak\n\t\t}\n\n\t\t// \"[a.#b] = [c]\" => \"[__privateWrapper(a, #b)._] = [c]\"\n\t\tif private, ok := e.Index.Data.(*js_ast.EPrivateIdentifier); ok && p.privateSymbolNeedsToBeLowered(private) {\n\t\t\tvar target js_ast.Expr\n\n\t\t\tswitch p.symbols[private.Ref.InnerIndex].Kind {\n\t\t\tcase ast.SymbolPrivateSet, ast.SymbolPrivateStaticSet,\n\t\t\t\tast.SymbolPrivateGetSetPair, ast.SymbolPrivateStaticGetSetPair:\n\t\t\t\t// \"this.#setter\" => \"__privateWrapper(this, #setter, setter_set)\"\n\t\t\t\tfnRef := p.privateSetters[private.Ref]\n\t\t\t\tp.recordUsage(fnRef)\n\t\t\t\ttarget = p.callRuntime(expr.Loc, \"__privateWrapper\", []js_ast.Expr{\n\t\t\t\t\te.Target,\n\t\t\t\t\t{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\t\t\t\t{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: fnRef}},\n\t\t\t\t})\n\n\t\t\tdefault:\n\t\t\t\t// \"this.#field\" => \"__privateWrapper(this, #field)\"\n\t\t\t\ttarget = p.callRuntime(expr.Loc, \"__privateWrapper\", []js_ast.Expr{\n\t\t\t\t\te.Target,\n\t\t\t\t\t{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: private.Ref}},\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// \"__privateWrapper(this, #field)\" => \"__privateWrapper(this, #field)._\"\n\t\t\texpr.Data = &js_ast.EDot{Target: target, Name: \"_\", NameLoc: expr.Loc}\n\t\t\tdidLower = true\n\t\t}\n\n\tcase *js_ast.EArray:\n\t\tfor i, item := range e.Items {\n\t\t\tif item, ok := p.lowerSuperPropertyOrPrivateInAssign(item); ok {\n\t\t\t\te.Items[i] = item\n\t\t\t\tdidLower = true\n\t\t\t}\n\t\t}\n\n\tcase *js_ast.EObject:\n\t\tfor i, property := range e.Properties {\n\t\t\tif property.ValueOrNil.Data != nil {\n\t\t\t\tif value, ok := p.lowerSuperPropertyOrPrivateInAssign(property.ValueOrNil); ok {\n\t\t\t\t\te.Properties[i].ValueOrNil = value\n\t\t\t\t\tdidLower = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn expr, didLower\n}\n\nfunc (p *parser) shouldLowerSuperPropertyAccess(expr js_ast.Expr) bool {\n\tif p.fnOrArrowDataVisit.shouldLowerSuperPropertyAccess {\n\t\t_, isSuper := expr.Data.(*js_ast.ESuper)\n\t\treturn isSuper\n\t}\n\treturn false\n}\n\nfunc (p *parser) callSuperPropertyWrapper(loc logger.Loc, key js_ast.Expr) js_ast.Expr {\n\tref := *p.fnOnlyDataVisit.innerClassNameRef\n\tp.recordUsage(ref)\n\tclass := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}\n\tthis := js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}\n\n\t// Handle \"this\" in lowered static class field initializers\n\tif p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef {\n\t\tp.recordUsage(ref)\n\t\tthis.Data = &js_ast.EIdentifier{Ref: ref}\n\t}\n\n\tif !p.fnOnlyDataVisit.isInStaticClassContext {\n\t\t// \"super.foo\" => \"__superWrapper(Class.prototype, this, 'foo')._\"\n\t\t// \"super[foo]\" => \"__superWrapper(Class.prototype, this, foo)._\"\n\t\tclass.Data = &js_ast.EDot{Target: class, NameLoc: loc, Name: \"prototype\"}\n\t}\n\n\treturn js_ast.Expr{Loc: loc, Data: &js_ast.EDot{Target: p.callRuntime(loc, \"__superWrapper\", []js_ast.Expr{\n\t\tclass,\n\t\tthis,\n\t\tkey,\n\t}), Name: \"_\", NameLoc: loc}}\n}\n\nfunc (p *parser) lowerSuperPropertyGet(loc logger.Loc, key js_ast.Expr) js_ast.Expr {\n\tref := *p.fnOnlyDataVisit.innerClassNameRef\n\tp.recordUsage(ref)\n\tclass := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}\n\tthis := js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}\n\n\t// Handle \"this\" in lowered static class field initializers\n\tif p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef {\n\t\tp.recordUsage(ref)\n\t\tthis.Data = &js_ast.EIdentifier{Ref: ref}\n\t}\n\n\tif !p.fnOnlyDataVisit.isInStaticClassContext {\n\t\t// \"super.foo\" => \"__superGet(Class.prototype, this, 'foo')\"\n\t\t// \"super[foo]\" => \"__superGet(Class.prototype, this, foo)\"\n\t\tclass.Data = &js_ast.EDot{Target: class, NameLoc: loc, Name: \"prototype\"}\n\t}\n\n\treturn p.callRuntime(loc, \"__superGet\", []js_ast.Expr{\n\t\tclass,\n\t\tthis,\n\t\tkey,\n\t})\n}\n\nfunc (p *parser) lowerSuperPropertySet(loc logger.Loc, key js_ast.Expr, value js_ast.Expr) js_ast.Expr {\n\t// \"super.foo = bar\" => \"__superSet(Class, this, 'foo', bar)\"\n\t// \"super[foo] = bar\" => \"__superSet(Class, this, foo, bar)\"\n\tref := *p.fnOnlyDataVisit.innerClassNameRef\n\tp.recordUsage(ref)\n\tclass := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}\n\tthis := js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}\n\n\t// Handle \"this\" in lowered static class field initializers\n\tif p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef {\n\t\tp.recordUsage(ref)\n\t\tthis.Data = &js_ast.EIdentifier{Ref: ref}\n\t}\n\n\tif !p.fnOnlyDataVisit.isInStaticClassContext {\n\t\t// \"super.foo = bar\" => \"__superSet(Class.prototype, this, 'foo', bar)\"\n\t\t// \"super[foo] = bar\" => \"__superSet(Class.prototype, this, foo, bar)\"\n\t\tclass.Data = &js_ast.EDot{Target: class, NameLoc: loc, Name: \"prototype\"}\n\t}\n\n\treturn p.callRuntime(loc, \"__superSet\", []js_ast.Expr{\n\t\tclass,\n\t\tthis,\n\t\tkey,\n\t\tvalue,\n\t})\n}\n\nfunc (p *parser) lowerSuperPropertySetBinOp(loc logger.Loc, property js_ast.Expr, op js_ast.OpCode, value js_ast.Expr) js_ast.Expr {\n\t// \"super.foo += bar\" => \"__superSet(Class, this, 'foo', __superGet(Class, this, 'foo') + bar)\"\n\t// \"super[foo] += bar\" => \"__superSet(Class, this, foo, __superGet(Class, this, foo) + bar)\"\n\t// \"super[foo()] += bar\" => \"__superSet(Class, this, _a = foo(), __superGet(Class, this, _a) + bar)\"\n\ttargetFunc, targetWrapFunc := p.captureValueWithPossibleSideEffects(property.Loc, 2, property, valueDefinitelyNotMutated)\n\treturn targetWrapFunc(p.lowerSuperPropertySet(loc, targetFunc(), js_ast.Expr{Loc: value.Loc, Data: &js_ast.EBinary{\n\t\tOp:    op,\n\t\tLeft:  p.lowerSuperPropertyGet(loc, targetFunc()),\n\t\tRight: value,\n\t}}))\n}\n\nfunc (p *parser) maybeLowerSuperPropertyGetInsideCall(call *js_ast.ECall) {\n\tvar key js_ast.Expr\n\n\tswitch e := call.Target.Data.(type) {\n\tcase *js_ast.EDot:\n\t\t// Lower \"super.prop\" if necessary\n\t\tif !p.shouldLowerSuperPropertyAccess(e.Target) {\n\t\t\treturn\n\t\t}\n\t\tkey = js_ast.Expr{Loc: e.NameLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(e.Name)}}\n\n\tcase *js_ast.EIndex:\n\t\t// Lower \"super[prop]\" if necessary\n\t\tif !p.shouldLowerSuperPropertyAccess(e.Target) {\n\t\t\treturn\n\t\t}\n\t\tkey = e.Index\n\n\tdefault:\n\t\treturn\n\t}\n\n\t// \"super.foo(a, b)\" => \"__superGet(Class, this, 'foo').call(this, a, b)\"\n\tcall.Target.Data = &js_ast.EDot{\n\t\tTarget:  p.lowerSuperPropertyGet(call.Target.Loc, key),\n\t\tNameLoc: key.Loc,\n\t\tName:    \"call\",\n\t}\n\tthisExpr := js_ast.Expr{Loc: call.Target.Loc, Data: js_ast.EThisShared}\n\tcall.Args = append([]js_ast.Expr{thisExpr}, call.Args...)\n}\n\ntype classLoweringInfo struct {\n\tlowerAllInstanceFields bool\n\tlowerAllStaticFields   bool\n\tshimSuperCtorCalls     bool\n}\n\nfunc (p *parser) computeClassLoweringInfo(class *js_ast.Class) (result classLoweringInfo) {\n\t// Name keeping for classes is implemented with a static block. So we need to\n\t// lower all static fields if static blocks are unsupported so that the name\n\t// keeping comes first before other static initializers.\n\tif p.options.keepNames && p.options.unsupportedJSFeatures.Has(compat.ClassStaticBlocks) {\n\t\tresult.lowerAllStaticFields = true\n\t}\n\n\t// TypeScript's \"experimentalDecorators\" feature replaces all references of\n\t// the class name with the decorated class after class decorators have run.\n\t// This cannot be done by only reassigning to the class symbol in JavaScript\n\t// because it's shadowed by the class name within the class body. Instead,\n\t// we need to hoist all code in static contexts out of the class body so\n\t// that it's no longer shadowed:\n\t//\n\t//   const decorate = x => ({ x })\n\t//   @decorate\n\t//   class Foo {\n\t//     static oldFoo = Foo\n\t//     static newFoo = () => Foo\n\t//   }\n\t//   console.log('This must be false:', Foo.x.oldFoo === Foo.x.newFoo())\n\t//\n\tif p.options.ts.Parse && p.options.ts.Config.ExperimentalDecorators == config.True && len(class.Decorators) > 0 {\n\t\tresult.lowerAllStaticFields = true\n\t}\n\n\t// If something has decorators, just lower everything for now. It's possible\n\t// that we could avoid lowering in certain cases, but doing so is very tricky\n\t// due to the complexity of the decorator specification. The specification is\n\t// also still evolving so trying to optimize it now is also potentially\n\t// premature.\n\tif class.ShouldLowerStandardDecorators {\n\t\tfor _, prop := range class.Properties {\n\t\t\tif len(prop.Decorators) > 0 {\n\t\t\t\tfor _, prop := range class.Properties {\n\t\t\t\t\tif private, ok := prop.Key.Data.(*js_ast.EPrivateIdentifier); ok {\n\t\t\t\t\t\tp.symbols[private.Ref.InnerIndex].Flags |= ast.PrivateSymbolMustBeLowered\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t\tresult.lowerAllInstanceFields = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// Conservatively lower fields of a given type (instance or static) when any\n\t// member of that type needs to be lowered. This must be done to preserve\n\t// evaluation order. For example:\n\t//\n\t//   class Foo {\n\t//     #foo = 123\n\t//     bar = this.#foo\n\t//   }\n\t//\n\t// It would be bad if we transformed that into something like this:\n\t//\n\t//   var _foo;\n\t//   class Foo {\n\t//     constructor() {\n\t//       _foo.set(this, 123);\n\t//     }\n\t//     bar = __privateGet(this, _foo);\n\t//   }\n\t//   _foo = new WeakMap();\n\t//\n\t// That evaluates \"bar\" then \"foo\" instead of \"foo\" then \"bar\" like the\n\t// original code. We need to do this instead:\n\t//\n\t//   var _foo;\n\t//   class Foo {\n\t//     constructor() {\n\t//       _foo.set(this, 123);\n\t//       __publicField(this, \"bar\", __privateGet(this, _foo));\n\t//     }\n\t//   }\n\t//   _foo = new WeakMap();\n\t//\n\tfor _, prop := range class.Properties {\n\t\tif prop.Kind == js_ast.PropertyClassStaticBlock {\n\t\t\tif p.options.unsupportedJSFeatures.Has(compat.ClassStaticBlocks) {\n\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif private, ok := prop.Key.Data.(*js_ast.EPrivateIdentifier); ok {\n\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\tif p.privateSymbolNeedsToBeLowered(private) {\n\t\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif p.privateSymbolNeedsToBeLowered(private) {\n\t\t\t\t\tresult.lowerAllInstanceFields = true\n\n\t\t\t\t\t// We can't transform this:\n\t\t\t\t\t//\n\t\t\t\t\t//   class Foo {\n\t\t\t\t\t//     #foo = 123\n\t\t\t\t\t//     static bar = new Foo().#foo\n\t\t\t\t\t//   }\n\t\t\t\t\t//\n\t\t\t\t\t// into this:\n\t\t\t\t\t//\n\t\t\t\t\t//   var _foo;\n\t\t\t\t\t//   const _Foo = class {\n\t\t\t\t\t//     constructor() {\n\t\t\t\t\t//       _foo.set(this, 123);\n\t\t\t\t\t//     }\n\t\t\t\t\t//     static bar = __privateGet(new _Foo(), _foo);\n\t\t\t\t\t//   };\n\t\t\t\t\t//   let Foo = _Foo;\n\t\t\t\t\t//   _foo = new WeakMap();\n\t\t\t\t\t//\n\t\t\t\t\t// because \"_Foo\" won't be initialized in the initializer for \"bar\".\n\t\t\t\t\t// So we currently lower all static fields in this case too. This\n\t\t\t\t\t// isn't great and it would be good to find a way to avoid this.\n\t\t\t\t\t// The inner class name symbol substitution mechanism should probably\n\t\t\t\t\t// be rethought.\n\t\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif prop.Kind == js_ast.PropertyAutoAccessor {\n\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\tif p.options.unsupportedJSFeatures.Has(compat.ClassPrivateStaticField) {\n\t\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif p.options.unsupportedJSFeatures.Has(compat.ClassPrivateField) {\n\t\t\t\t\tresult.lowerAllInstanceFields = true\n\t\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// This doesn't come before the private member check above because\n\t\t// unsupported private methods must also trigger field lowering:\n\t\t//\n\t\t//   class Foo {\n\t\t//     bar = this.#foo()\n\t\t//     #foo() {}\n\t\t//   }\n\t\t//\n\t\t// It would be bad if we transformed that to something like this:\n\t\t//\n\t\t//   var _foo, foo_fn;\n\t\t//   class Foo {\n\t\t//     constructor() {\n\t\t//       _foo.add(this);\n\t\t//     }\n\t\t//     bar = __privateMethod(this, _foo, foo_fn).call(this);\n\t\t//   }\n\t\t//   _foo = new WeakSet();\n\t\t//   foo_fn = function() {\n\t\t//   };\n\t\t//\n\t\t// In that case the initializer of \"bar\" would fail to call \"#foo\" because\n\t\t// it's only added to the instance in the body of the constructor.\n\t\tif prop.Kind.IsMethodDefinition() {\n\t\t\t// We need to shim \"super()\" inside the constructor if this is a derived\n\t\t\t// class and the constructor has any parameter properties, since those\n\t\t\t// use \"this\" and we can only access \"this\" after \"super()\" is called\n\t\t\tif class.ExtendsOrNil.Data != nil {\n\t\t\t\tif key, ok := prop.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(key.Value, \"constructor\") {\n\t\t\t\t\tif fn, ok := prop.ValueOrNil.Data.(*js_ast.EFunction); ok {\n\t\t\t\t\t\tfor _, arg := range fn.Fn.Args {\n\t\t\t\t\t\t\tif arg.IsTypeScriptCtorField {\n\t\t\t\t\t\t\t\tresult.shimSuperCtorCalls = true\n\t\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t// Static fields must be lowered if the target doesn't support them\n\t\t\tif p.options.unsupportedJSFeatures.Has(compat.ClassStaticField) {\n\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t}\n\n\t\t\t// Convert static fields to assignment statements if the TypeScript\n\t\t\t// setting for this is enabled. I don't think this matters for private\n\t\t\t// fields because there's no way for this to call a setter in the base\n\t\t\t// class, so this isn't done for private fields.\n\t\t\t//\n\t\t\t// If class static blocks are supported, then we can do this inline\n\t\t\t// without needing to move the initializers outside of the class body.\n\t\t\t// Otherwise, we need to lower all static class fields.\n\t\t\tif p.options.ts.Parse && !class.UseDefineForClassFields && p.options.unsupportedJSFeatures.Has(compat.ClassStaticBlocks) {\n\t\t\t\tresult.lowerAllStaticFields = true\n\t\t\t}\n\t\t} else {\n\t\t\tif p.options.ts.Parse && !class.UseDefineForClassFields {\n\t\t\t\t// Convert instance fields to assignment statements if the TypeScript\n\t\t\t\t// setting for this is enabled. I don't think this matters for private\n\t\t\t\t// fields because there's no way for this to call a setter in the base\n\t\t\t\t// class, so this isn't done for private fields.\n\t\t\t\tif prop.InitializerOrNil.Data != nil {\n\t\t\t\t\t// We can skip lowering all instance fields if all instance fields\n\t\t\t\t\t// disappear completely when lowered. This happens when\n\t\t\t\t\t// \"useDefineForClassFields\" is false and there is no initializer.\n\t\t\t\t\tresult.lowerAllInstanceFields = true\n\t\t\t\t}\n\t\t\t} else if p.options.unsupportedJSFeatures.Has(compat.ClassField) {\n\t\t\t\t// Instance fields must be lowered if the target doesn't support them\n\t\t\t\tresult.lowerAllInstanceFields = true\n\t\t\t}\n\t\t}\n\t}\n\n\t// We need to shim \"super()\" inside the constructor if this is a derived\n\t// class and there are any instance fields that need to be lowered, since\n\t// those use \"this\" and we can only access \"this\" after \"super()\" is called\n\tif result.lowerAllInstanceFields && class.ExtendsOrNil.Data != nil {\n\t\tresult.shimSuperCtorCalls = true\n\t}\n\n\treturn\n}\n\ntype classKind uint8\n\nconst (\n\tclassKindExpr classKind = iota\n\tclassKindStmt\n\tclassKindExportStmt\n\tclassKindExportDefaultStmt\n)\n\ntype lowerClassContext struct {\n\tnameToKeep  string\n\tkind        classKind\n\tclass       *js_ast.Class\n\tclassLoc    logger.Loc\n\tclassExpr   js_ast.Expr // Only for \"kind == classKindExpr\", may be replaced by \"nameFunc()\"\n\tdefaultName ast.LocRef\n\n\tctor                   *js_ast.EFunction\n\textendsRef             ast.Ref\n\tparameterFields        []js_ast.Stmt\n\tinstanceMembers        []js_ast.Stmt\n\tinstancePrivateMethods []js_ast.Stmt\n\tautoAccessorCount      int\n\n\t// These expressions are generated after the class body, in this order\n\tcomputedPropertyChain js_ast.Expr\n\tprivateMembers        []js_ast.Expr\n\tstaticMembers         []js_ast.Expr\n\tstaticPrivateMethods  []js_ast.Expr\n\n\t// These contain calls to \"__decorateClass\" for TypeScript experimental decorators\n\tinstanceExperimentalDecorators []js_ast.Expr\n\tstaticExperimentalDecorators   []js_ast.Expr\n\n\t// These are used for implementing JavaScript decorators\n\tdecoratorContextRef                          ast.Ref\n\tdecoratorClassDecorators                     js_ast.Expr\n\tdecoratorPropertyToInitializerMap            map[int]int\n\tdecoratorCallInstanceMethodExtraInitializers bool\n\tdecoratorCallStaticMethodExtraInitializers   bool\n\tdecoratorStaticNonFieldElements              []js_ast.Expr\n\tdecoratorInstanceNonFieldElements            []js_ast.Expr\n\tdecoratorStaticFieldElements                 []js_ast.Expr\n\tdecoratorInstanceFieldElements               []js_ast.Expr\n\n\t// These are used by \"lowerMethod\"\n\tprivateInstanceMethodRef ast.Ref\n\tprivateStaticMethodRef   ast.Ref\n\n\t// These are only for class expressions that need to be captured\n\tnameFunc            func() js_ast.Expr\n\twrapFunc            func(js_ast.Expr) js_ast.Expr\n\tdidCaptureClassExpr bool\n}\n\n// Apply all relevant transforms to a class object (either a statement or an\n// expression) including:\n//\n//   - Transforming class fields for older environments\n//   - Transforming static blocks for older environments\n//   - Transforming TypeScript experimental decorators into JavaScript\n//   - Transforming TypeScript class fields into assignments for \"useDefineForClassFields\"\n//\n// Note that this doesn't transform any nested AST subtrees inside the class\n// body (e.g. the contents of initializers, methods, and static blocks). Those\n// have already been transformed by \"visitClass\" by this point. It's done that\n// way for performance so that we don't need to do another AST pass.\nfunc (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClassResult, nameToKeep string) ([]js_ast.Stmt, js_ast.Expr) {\n\tctx := lowerClassContext{\n\t\tnameToKeep:               nameToKeep,\n\t\textendsRef:               ast.InvalidRef,\n\t\tdecoratorContextRef:      ast.InvalidRef,\n\t\tprivateInstanceMethodRef: ast.InvalidRef,\n\t\tprivateStaticMethodRef:   ast.InvalidRef,\n\t}\n\n\t// Unpack the class from the statement or expression\n\tif stmt.Data == nil {\n\t\te, _ := expr.Data.(*js_ast.EClass)\n\t\tctx.class = &e.Class\n\t\tctx.classExpr = expr\n\t\tctx.kind = classKindExpr\n\t\tif ctx.class.Name != nil {\n\t\t\tsymbol := &p.symbols[ctx.class.Name.Ref.InnerIndex]\n\t\t\tctx.nameToKeep = symbol.OriginalName\n\n\t\t\t// The inner class name inside the class expression should be the same as\n\t\t\t// the class expression name itself\n\t\t\tif result.innerClassNameRef != ast.InvalidRef {\n\t\t\t\tp.mergeSymbols(result.innerClassNameRef, ctx.class.Name.Ref)\n\t\t\t}\n\n\t\t\t// Remove unused class names when minifying. Check this after we merge in\n\t\t\t// the inner class name above since that will adjust the use count.\n\t\t\tif p.options.minifySyntax && symbol.UseCountEstimate == 0 {\n\t\t\t\tctx.class.Name = nil\n\t\t\t}\n\t\t}\n\t} else if s, ok := stmt.Data.(*js_ast.SClass); ok {\n\t\tctx.class = &s.Class\n\t\tif ctx.class.Name != nil {\n\t\t\tctx.nameToKeep = p.symbols[ctx.class.Name.Ref.InnerIndex].OriginalName\n\t\t}\n\t\tif s.IsExport {\n\t\t\tctx.kind = classKindExportStmt\n\t\t} else {\n\t\t\tctx.kind = classKindStmt\n\t\t}\n\t} else {\n\t\ts, _ := stmt.Data.(*js_ast.SExportDefault)\n\t\ts2, _ := s.Value.Data.(*js_ast.SClass)\n\t\tctx.class = &s2.Class\n\t\tif ctx.class.Name != nil {\n\t\t\tctx.nameToKeep = p.symbols[ctx.class.Name.Ref.InnerIndex].OriginalName\n\t\t}\n\t\tctx.defaultName = s.DefaultName\n\t\tctx.kind = classKindExportDefaultStmt\n\t}\n\tif stmt.Data == nil {\n\t\tctx.classLoc = expr.Loc\n\t} else {\n\t\tctx.classLoc = stmt.Loc\n\t}\n\n\tclassLoweringInfo := p.computeClassLoweringInfo(ctx.class)\n\tctx.enableNameCapture(p, result)\n\tctx.processProperties(p, classLoweringInfo, result)\n\tctx.insertInitializersIntoConstructor(p, classLoweringInfo, result)\n\treturn ctx.finishAndGenerateCode(p, result)\n}\n\nfunc (ctx *lowerClassContext) enableNameCapture(p *parser, result visitClassResult) {\n\t// Class statements can be missing a name if they are in an\n\t// \"export default\" statement:\n\t//\n\t//   export default class {\n\t//     static foo = 123\n\t//   }\n\t//\n\tctx.nameFunc = func() js_ast.Expr {\n\t\tif ctx.kind == classKindExpr {\n\t\t\t// If this is a class expression, capture and store it. We have to\n\t\t\t// do this even if it has a name since the name isn't exposed\n\t\t\t// outside the class body.\n\t\t\tclassExpr := &js_ast.EClass{Class: *ctx.class}\n\t\t\tctx.class = &classExpr.Class\n\t\t\tctx.nameFunc, ctx.wrapFunc = p.captureValueWithPossibleSideEffects(ctx.classLoc, 2, js_ast.Expr{Loc: ctx.classLoc, Data: classExpr}, valueDefinitelyNotMutated)\n\t\t\tctx.classExpr = ctx.nameFunc()\n\t\t\tctx.didCaptureClassExpr = true\n\t\t\tname := ctx.nameFunc()\n\n\t\t\t// If we're storing the class expression in a variable, remove the class\n\t\t\t// name and rewrite all references to the class name with references to\n\t\t\t// the temporary variable holding the class expression. This ensures that\n\t\t\t// references to the class expression by name in any expressions that end\n\t\t\t// up being pulled outside of the class body still work. For example:\n\t\t\t//\n\t\t\t//   let Bar = class Foo {\n\t\t\t//     static foo = 123\n\t\t\t//     static bar = Foo.foo\n\t\t\t//   }\n\t\t\t//\n\t\t\t// This might be converted into the following:\n\t\t\t//\n\t\t\t//   var _a;\n\t\t\t//   let Bar = (_a = class {\n\t\t\t//   }, _a.foo = 123, _a.bar = _a.foo, _a);\n\t\t\t//\n\t\t\tif ctx.class.Name != nil {\n\t\t\t\tp.mergeSymbols(ctx.class.Name.Ref, name.Data.(*js_ast.EIdentifier).Ref)\n\t\t\t\tctx.class.Name = nil\n\t\t\t}\n\n\t\t\treturn name\n\t\t} else {\n\t\t\t// If anything referenced the inner class name, then we should use that\n\t\t\t// name for any automatically-generated initialization code, since it\n\t\t\t// will come before the outer class name is initialized.\n\t\t\tif result.innerClassNameRef != ast.InvalidRef {\n\t\t\t\tp.recordUsage(result.innerClassNameRef)\n\t\t\t\treturn js_ast.Expr{Loc: ctx.class.Name.Loc, Data: &js_ast.EIdentifier{Ref: result.innerClassNameRef}}\n\t\t\t}\n\n\t\t\t// Otherwise we should just use the outer class name\n\t\t\tif ctx.class.Name == nil {\n\t\t\t\tif ctx.kind == classKindExportDefaultStmt {\n\t\t\t\t\tctx.class.Name = &ctx.defaultName\n\t\t\t\t} else {\n\t\t\t\t\tctx.class.Name = &ast.LocRef{Loc: ctx.classLoc, Ref: p.generateTempRef(tempRefNoDeclare, \"\")}\n\t\t\t\t}\n\t\t\t}\n\t\t\tp.recordUsage(ctx.class.Name.Ref)\n\t\t\treturn js_ast.Expr{Loc: ctx.class.Name.Loc, Data: &js_ast.EIdentifier{Ref: ctx.class.Name.Ref}}\n\t\t}\n\t}\n}\n\n// Handle lowering of instance and static fields. Move their initializers\n// from the class body to either the constructor (instance fields) or after\n// the class (static fields).\n//\n// If this returns true, the return property should be added to the class\n// body. Otherwise the property should be omitted from the class body.\nfunc (ctx *lowerClassContext) lowerField(\n\tp *parser,\n\tprop js_ast.Property,\n\tprivate *js_ast.EPrivateIdentifier,\n\tshouldOmitFieldInitializer bool,\n\tstaticFieldToBlockAssign bool,\n\tinitializerIndex int,\n) (js_ast.Property, ast.Ref, bool) {\n\tmustLowerPrivate := private != nil && p.privateSymbolNeedsToBeLowered(private)\n\tref := ast.InvalidRef\n\n\t// The TypeScript compiler doesn't follow the JavaScript spec for\n\t// uninitialized fields. They are supposed to be set to undefined but the\n\t// TypeScript compiler just omits them entirely.\n\tif !shouldOmitFieldInitializer {\n\t\tloc := prop.Loc\n\n\t\t// Determine where to store the field\n\t\tvar target js_ast.Expr\n\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) && !staticFieldToBlockAssign {\n\t\t\ttarget = ctx.nameFunc()\n\t\t} else {\n\t\t\ttarget = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}\n\t\t}\n\n\t\t// Generate the assignment initializer\n\t\tvar init js_ast.Expr\n\t\tif prop.InitializerOrNil.Data != nil {\n\t\t\tinit = prop.InitializerOrNil\n\t\t} else {\n\t\t\tinit = js_ast.Expr{Loc: loc, Data: js_ast.EUndefinedShared}\n\t\t}\n\n\t\t// Optionally call registered decorator initializers\n\t\tif initializerIndex != -1 {\n\t\t\tvar value js_ast.Expr\n\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\tvalue = ctx.nameFunc()\n\t\t\t} else {\n\t\t\t\tvalue = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}\n\t\t\t}\n\t\t\targs := []js_ast.Expr{\n\t\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\t\t{Loc: loc, Data: &js_ast.ENumber{Value: float64((4 + 2*initializerIndex) << 1)}},\n\t\t\t\tvalue,\n\t\t\t}\n\t\t\tif _, ok := init.Data.(*js_ast.EUndefined); !ok {\n\t\t\t\targs = append(args, init)\n\t\t\t}\n\t\t\tinit = p.callRuntime(init.Loc, \"__runInitializers\", args)\n\t\t\tp.recordUsage(ctx.decoratorContextRef)\n\t\t}\n\n\t\t// Generate the assignment target\n\t\tvar memberExpr js_ast.Expr\n\t\tif mustLowerPrivate {\n\t\t\t// Generate a new symbol for this private field\n\t\t\tref = p.generateTempRef(tempRefNeedsDeclare, \"_\"+p.symbols[private.Ref.InnerIndex].OriginalName[1:])\n\t\t\tp.symbols[private.Ref.InnerIndex].Link = ref\n\n\t\t\t// Initialize the private field to a new WeakMap\n\t\t\tif p.weakMapRef == ast.InvalidRef {\n\t\t\t\tp.weakMapRef = p.newSymbol(ast.SymbolUnbound, \"WeakMap\")\n\t\t\t\tp.moduleScope.Generated = append(p.moduleScope.Generated, p.weakMapRef)\n\t\t\t}\n\t\t\tctx.privateMembers = append(ctx.privateMembers, js_ast.Assign(\n\t\t\t\tjs_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}},\n\t\t\t\tjs_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.ENew{Target: js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: p.weakMapRef}}}},\n\t\t\t))\n\t\t\tp.recordUsage(ref)\n\n\t\t\t// Add every newly-constructed instance into this map\n\t\t\tkey := js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}}\n\t\t\targs := []js_ast.Expr{target, key}\n\t\t\tif _, ok := init.Data.(*js_ast.EUndefined); !ok {\n\t\t\t\targs = append(args, init)\n\t\t\t}\n\t\t\tmemberExpr = p.callRuntime(loc, \"__privateAdd\", args)\n\t\t\tp.recordUsage(ref)\n\t\t} else if private == nil && ctx.class.UseDefineForClassFields {\n\t\t\tif p.shouldAddKeyComment {\n\t\t\t\tif str, ok := prop.Key.Data.(*js_ast.EString); ok {\n\t\t\t\t\tstr.HasPropertyKeyComment = true\n\t\t\t\t}\n\t\t\t}\n\t\t\targs := []js_ast.Expr{target, prop.Key}\n\t\t\tif _, ok := init.Data.(*js_ast.EUndefined); !ok {\n\t\t\t\targs = append(args, init)\n\t\t\t}\n\t\t\tmemberExpr = js_ast.Expr{Loc: loc, Data: &js_ast.ECall{\n\t\t\t\tTarget: p.importFromRuntime(loc, \"__publicField\"),\n\t\t\t\tArgs:   args,\n\t\t\t}}\n\t\t} else {\n\t\t\tif key, ok := prop.Key.Data.(*js_ast.EString); ok && !prop.Flags.Has(js_ast.PropertyIsComputed) && !prop.Flags.Has(js_ast.PropertyPreferQuotedKey) {\n\t\t\t\ttarget = js_ast.Expr{Loc: loc, Data: &js_ast.EDot{\n\t\t\t\t\tTarget:  target,\n\t\t\t\t\tName:    helpers.UTF16ToString(key.Value),\n\t\t\t\t\tNameLoc: prop.Key.Loc,\n\t\t\t\t}}\n\t\t\t} else {\n\t\t\t\ttarget = js_ast.Expr{Loc: loc, Data: &js_ast.EIndex{\n\t\t\t\t\tTarget: target,\n\t\t\t\t\tIndex:  prop.Key,\n\t\t\t\t}}\n\t\t\t}\n\n\t\t\tmemberExpr = js_ast.Assign(target, init)\n\t\t}\n\n\t\t// Run extra initializers\n\t\tif initializerIndex != -1 {\n\t\t\tvar value js_ast.Expr\n\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\tvalue = ctx.nameFunc()\n\t\t\t} else {\n\t\t\t\tvalue = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}\n\t\t\t}\n\t\t\tmemberExpr = js_ast.JoinWithComma(memberExpr, p.callRuntime(loc, \"__runInitializers\", []js_ast.Expr{\n\t\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\t\t{Loc: loc, Data: &js_ast.ENumber{Value: float64(((5 + 2*initializerIndex) << 1) | 1)}},\n\t\t\t\tvalue,\n\t\t\t}))\n\t\t\tp.recordUsage(ctx.decoratorContextRef)\n\t\t}\n\n\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t// Move this property to an assignment after the class ends\n\t\t\tif staticFieldToBlockAssign {\n\t\t\t\t// Use inline assignment in a static block instead of lowering\n\t\t\t\treturn js_ast.Property{\n\t\t\t\t\tLoc:  loc,\n\t\t\t\t\tKind: js_ast.PropertyClassStaticBlock,\n\t\t\t\t\tClassStaticBlock: &js_ast.ClassStaticBlock{\n\t\t\t\t\t\tLoc: loc,\n\t\t\t\t\t\tBlock: js_ast.SBlock{Stmts: []js_ast.Stmt{\n\t\t\t\t\t\t\t{Loc: loc, Data: &js_ast.SExpr{Value: memberExpr}}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}, ref, true\n\t\t\t} else {\n\t\t\t\t// Move this property to an assignment after the class ends\n\t\t\t\tctx.staticMembers = append(ctx.staticMembers, memberExpr)\n\t\t\t}\n\t\t} else {\n\t\t\t// Move this property to an assignment inside the class constructor\n\t\t\tctx.instanceMembers = append(ctx.instanceMembers, js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: memberExpr}})\n\t\t}\n\t}\n\n\tif private == nil || mustLowerPrivate {\n\t\t// Remove the field from the class body\n\t\treturn js_ast.Property{}, ref, false\n\t}\n\n\t// Keep the private field but remove the initializer\n\tprop.InitializerOrNil = js_ast.Expr{}\n\treturn prop, ref, true\n}\n\nfunc (ctx *lowerClassContext) lowerPrivateMethod(p *parser, prop js_ast.Property, private *js_ast.EPrivateIdentifier) {\n\t// All private methods can share the same WeakSet\n\tvar ref *ast.Ref\n\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\tref = &ctx.privateStaticMethodRef\n\t} else {\n\t\tref = &ctx.privateInstanceMethodRef\n\t}\n\tif *ref == ast.InvalidRef {\n\t\t// Generate a new symbol to store the WeakSet\n\t\tvar name string\n\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\tname = \"_static\"\n\t\t} else {\n\t\t\tname = \"_instances\"\n\t\t}\n\t\tif ctx.nameToKeep != \"\" {\n\t\t\tname = fmt.Sprintf(\"_%s%s\", ctx.nameToKeep, name)\n\t\t}\n\t\t*ref = p.generateTempRef(tempRefNeedsDeclare, name)\n\n\t\t// Generate the initializer\n\t\tif p.weakSetRef == ast.InvalidRef {\n\t\t\tp.weakSetRef = p.newSymbol(ast.SymbolUnbound, \"WeakSet\")\n\t\t\tp.moduleScope.Generated = append(p.moduleScope.Generated, p.weakSetRef)\n\t\t}\n\t\tctx.privateMembers = append(ctx.privateMembers, js_ast.Assign(\n\t\t\tjs_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: *ref}},\n\t\t\tjs_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.ENew{Target: js_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: p.weakSetRef}}}},\n\t\t))\n\t\tp.recordUsage(*ref)\n\t\tp.recordUsage(p.weakSetRef)\n\n\t\t// Determine what to store in the WeakSet\n\t\tvar target js_ast.Expr\n\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\ttarget = ctx.nameFunc()\n\t\t} else {\n\t\t\ttarget = js_ast.Expr{Loc: ctx.classLoc, Data: js_ast.EThisShared}\n\t\t}\n\n\t\t// Add every newly-constructed instance into this set\n\t\tmethodExpr := p.callRuntime(ctx.classLoc, \"__privateAdd\", []js_ast.Expr{\n\t\t\ttarget,\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: *ref}},\n\t\t})\n\t\tp.recordUsage(*ref)\n\n\t\t// Make sure that adding to the map happens before any field\n\t\t// initializers to handle cases like this:\n\t\t//\n\t\t//   class A {\n\t\t//     pub = this.#priv;\n\t\t//     #priv() {}\n\t\t//   }\n\t\t//\n\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t// Move this property to an assignment after the class ends\n\t\t\tctx.staticPrivateMethods = append(ctx.staticPrivateMethods, methodExpr)\n\t\t} else {\n\t\t\t// Move this property to an assignment inside the class constructor\n\t\t\tctx.instancePrivateMethods = append(ctx.instancePrivateMethods, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SExpr{Value: methodExpr}})\n\t\t}\n\t}\n\tp.symbols[private.Ref.InnerIndex].Link = *ref\n}\n\n// If this returns true, the method property should be dropped as it has\n// already been accounted for elsewhere (e.g. a lowered private method).\nfunc (ctx *lowerClassContext) lowerMethod(p *parser, prop js_ast.Property, private *js_ast.EPrivateIdentifier) bool {\n\tif private != nil && p.privateSymbolNeedsToBeLowered(private) {\n\t\tctx.lowerPrivateMethod(p, prop, private)\n\n\t\t// Move the method definition outside the class body\n\t\tmethodRef := p.generateTempRef(tempRefNeedsDeclare, \"_\")\n\t\tif prop.Kind == js_ast.PropertySetter {\n\t\t\tp.symbols[methodRef.InnerIndex].Link = p.privateSetters[private.Ref]\n\t\t} else {\n\t\t\tp.symbols[methodRef.InnerIndex].Link = p.privateGetters[private.Ref]\n\t\t}\n\t\tp.recordUsage(methodRef)\n\t\tctx.privateMembers = append(ctx.privateMembers, js_ast.Assign(\n\t\t\tjs_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: methodRef}},\n\t\t\tprop.ValueOrNil,\n\t\t))\n\t\treturn true\n\t}\n\n\tif key, ok := prop.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(key.Value, \"constructor\") {\n\t\tif fn, ok := prop.ValueOrNil.Data.(*js_ast.EFunction); ok {\n\t\t\t// Remember where the constructor is for later\n\t\t\tctx.ctor = fn\n\n\t\t\t// Initialize TypeScript constructor parameter fields\n\t\t\tif p.options.ts.Parse {\n\t\t\t\tfor _, arg := range ctx.ctor.Fn.Args {\n\t\t\t\t\tif arg.IsTypeScriptCtorField {\n\t\t\t\t\t\tif id, ok := arg.Binding.Data.(*js_ast.BIdentifier); ok {\n\t\t\t\t\t\t\tctx.parameterFields = append(ctx.parameterFields, js_ast.AssignStmt(\n\t\t\t\t\t\t\t\tjs_ast.Expr{Loc: arg.Binding.Loc, Data: p.dotOrMangledPropVisit(\n\t\t\t\t\t\t\t\t\tjs_ast.Expr{Loc: arg.Binding.Loc, Data: js_ast.EThisShared},\n\t\t\t\t\t\t\t\t\tp.symbols[id.Ref.InnerIndex].OriginalName,\n\t\t\t\t\t\t\t\t\targ.Binding.Loc,\n\t\t\t\t\t\t\t\t)},\n\t\t\t\t\t\t\t\tjs_ast.Expr{Loc: arg.Binding.Loc, Data: &js_ast.EIdentifier{Ref: id.Ref}},\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\ntype propertyAnalysis struct {\n\tprivate                         *js_ast.EPrivateIdentifier\n\tpropExperimentalDecorators      []js_ast.Decorator\n\tpropDecorators                  []js_ast.Decorator\n\tmustLowerField                  bool\n\tneedsValueOfKey                 bool\n\trewriteAutoAccessorToGetSet     bool\n\tshouldOmitFieldInitializer      bool\n\tstaticFieldToBlockAssign        bool\n\tisComputedPropertyCopiedOrMoved bool\n}\n\nfunc (ctx *lowerClassContext) analyzeProperty(p *parser, prop js_ast.Property, classLoweringInfo classLoweringInfo) (analysis propertyAnalysis) {\n\t// The TypeScript class field transform requires removing fields without\n\t// initializers. If the field is removed, then we only need the key for\n\t// its side effects and we don't need a temporary reference for the key.\n\t// However, the TypeScript compiler doesn't remove the field when doing\n\t// strict class field initialization, so we shouldn't either.\n\tanalysis.private, _ = prop.Key.Data.(*js_ast.EPrivateIdentifier)\n\tmustLowerPrivate := analysis.private != nil && p.privateSymbolNeedsToBeLowered(analysis.private)\n\tanalysis.shouldOmitFieldInitializer = p.options.ts.Parse && !prop.Kind.IsMethodDefinition() && prop.InitializerOrNil.Data == nil &&\n\t\t!ctx.class.UseDefineForClassFields && !mustLowerPrivate && !ctx.class.ShouldLowerStandardDecorators\n\n\t// Class fields must be lowered if the environment doesn't support them\n\tif !prop.Kind.IsMethodDefinition() {\n\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\tanalysis.mustLowerField = classLoweringInfo.lowerAllStaticFields\n\t\t} else if prop.Kind == js_ast.PropertyField && p.options.ts.Parse && !ctx.class.UseDefineForClassFields && analysis.private == nil {\n\t\t\t// Lower non-private instance fields (not accessors) if TypeScript's\n\t\t\t// \"useDefineForClassFields\" setting is disabled. When all such fields\n\t\t\t// have no initializers, we avoid setting the \"lowerAllInstanceFields\"\n\t\t\t// flag as an optimization because we can just remove all class field\n\t\t\t// declarations in that case without messing with the constructor. But\n\t\t\t// we must set the \"mustLowerField\" flag here to cause this class field\n\t\t\t// declaration to still be removed.\n\t\t\tanalysis.mustLowerField = true\n\t\t} else {\n\t\t\tanalysis.mustLowerField = classLoweringInfo.lowerAllInstanceFields\n\t\t}\n\t}\n\n\t// If the field uses the TypeScript \"declare\" or \"abstract\" keyword, just\n\t// omit it entirely. However, we must still keep any side-effects in the\n\t// computed value and/or in the decorators.\n\tif prop.Kind == js_ast.PropertyDeclareOrAbstract && prop.ValueOrNil.Data == nil {\n\t\tanalysis.mustLowerField = true\n\t\tanalysis.shouldOmitFieldInitializer = true\n\t}\n\n\t// For convenience, split decorators off into separate fields based on how\n\t// they will end up being lowered (if they are even being lowered at all)\n\tif p.options.ts.Parse && p.options.ts.Config.ExperimentalDecorators == config.True {\n\t\tanalysis.propExperimentalDecorators = prop.Decorators\n\t} else if ctx.class.ShouldLowerStandardDecorators {\n\t\tanalysis.propDecorators = prop.Decorators\n\t}\n\n\t// Note: Auto-accessors use a different transform when they are decorated.\n\t// This transform trades off worse run-time performance for better code size.\n\tanalysis.rewriteAutoAccessorToGetSet = len(analysis.propDecorators) == 0 && prop.Kind == js_ast.PropertyAutoAccessor &&\n\t\t(p.options.unsupportedJSFeatures.Has(compat.Decorators) || analysis.mustLowerField)\n\n\t// Transform non-lowered static fields that use assign semantics into an\n\t// assignment in an inline static block instead of lowering them. This lets\n\t// us avoid having to unnecessarily lower static private fields when\n\t// \"useDefineForClassFields\" is disabled.\n\tanalysis.staticFieldToBlockAssign = prop.Kind == js_ast.PropertyField && !analysis.mustLowerField && !ctx.class.UseDefineForClassFields &&\n\t\tprop.Flags.Has(js_ast.PropertyIsStatic) && analysis.private == nil\n\n\t// Computed properties can't be copied or moved because they have side effects\n\t// and we don't want to evaluate their side effects twice or change their\n\t// evaluation order. We'll need to store them in temporary variables to keep\n\t// their side effects in place when we reference them elsewhere.\n\tanalysis.needsValueOfKey = true\n\tif prop.Flags.Has(js_ast.PropertyIsComputed) &&\n\t\t(len(analysis.propExperimentalDecorators) > 0 ||\n\t\t\tlen(analysis.propDecorators) > 0 ||\n\t\t\tanalysis.mustLowerField ||\n\t\t\tanalysis.staticFieldToBlockAssign ||\n\t\t\tanalysis.rewriteAutoAccessorToGetSet) {\n\t\tanalysis.isComputedPropertyCopiedOrMoved = true\n\n\t\t// Determine if we don't actually need the value of the key (only the side\n\t\t// effects). In that case we don't need a temporary variable.\n\t\tif len(analysis.propExperimentalDecorators) == 0 &&\n\t\t\tlen(analysis.propDecorators) == 0 &&\n\t\t\t!analysis.rewriteAutoAccessorToGetSet &&\n\t\t\tanalysis.shouldOmitFieldInitializer {\n\t\t\tanalysis.needsValueOfKey = false\n\t\t}\n\t}\n\treturn\n}\n\nfunc (p *parser) propertyNameHint(key js_ast.Expr) string {\n\tswitch k := key.Data.(type) {\n\tcase *js_ast.EString:\n\t\treturn helpers.UTF16ToString(k.Value)\n\tcase *js_ast.EIdentifier:\n\t\treturn p.symbols[k.Ref.InnerIndex].OriginalName\n\tcase *js_ast.EPrivateIdentifier:\n\t\treturn p.symbols[k.Ref.InnerIndex].OriginalName[1:]\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (ctx *lowerClassContext) hoistComputedProperties(p *parser, classLoweringInfo classLoweringInfo) (\n\tpropertyKeyTempRefs map[int]ast.Ref, decoratorTempRefs map[int]ast.Ref) {\n\tvar nextComputedPropertyKey *js_ast.Expr\n\n\t// Computed property keys must be evaluated in a specific order for their\n\t// side effects. This order must be preserved even when we have to move a\n\t// class element around. For example, this can happen when using class fields\n\t// with computed property keys and targeting environments without class field\n\t// support. For example:\n\t//\n\t//   class Foo {\n\t//     [a()]() {}\n\t//     static [b()] = null;\n\t//     [c()]() {}\n\t//   }\n\t//\n\t// If we need to lower the static field because static fields aren't supported,\n\t// we still need to ensure that \"b()\" is called before \"a()\" and after \"c()\".\n\t// That looks something like this:\n\t//\n\t//   var _a;\n\t//   class Foo {\n\t//     [a()]() {}\n\t//     [(_a = b(), c())]() {}\n\t//   }\n\t//   __publicField(Foo, _a, null);\n\t//\n\t// Iterate in reverse so that any initializers are \"pushed up\" before the\n\t// class body if there's nowhere else to put them. They can't be \"pushed\n\t// down\" into a static block in the class body (the logical place to put\n\t// them that's next in the evaluation order) because these expressions\n\t// may contain \"await\" and static blocks do not allow \"await\".\n\tfor propIndex := len(ctx.class.Properties) - 1; propIndex >= 0; propIndex-- {\n\t\tprop := &ctx.class.Properties[propIndex]\n\t\tanalysis := ctx.analyzeProperty(p, *prop, classLoweringInfo)\n\n\t\t// Evaluate the decorator expressions inline before computed property keys\n\t\tvar decorators js_ast.Expr\n\t\tif len(analysis.propDecorators) > 0 {\n\t\t\tname := p.propertyNameHint(prop.Key)\n\t\t\tif name != \"\" {\n\t\t\t\tname = \"_\" + name\n\t\t\t}\n\t\t\tname += \"_dec\"\n\t\t\tref := p.generateTempRef(tempRefNeedsDeclare, name)\n\t\t\tvalues := make([]js_ast.Expr, len(analysis.propDecorators))\n\t\t\tfor i, decorator := range analysis.propDecorators {\n\t\t\t\tvalues[i] = decorator.Value\n\t\t\t}\n\t\t\tatLoc := analysis.propDecorators[0].AtLoc\n\t\t\tdecorators = js_ast.Assign(\n\t\t\t\tjs_ast.Expr{Loc: atLoc, Data: &js_ast.EIdentifier{Ref: ref}},\n\t\t\t\tjs_ast.Expr{Loc: atLoc, Data: &js_ast.EArray{Items: values, IsSingleLine: true}})\n\t\t\tp.recordUsage(ref)\n\t\t\tif decoratorTempRefs == nil {\n\t\t\t\tdecoratorTempRefs = make(map[int]ast.Ref)\n\t\t\t}\n\t\t\tdecoratorTempRefs[propIndex] = ref\n\t\t}\n\n\t\t// Skip property keys that we know are side-effect free\n\t\tswitch prop.Key.Data.(type) {\n\t\tcase *js_ast.EString, *js_ast.ENameOfSymbol, *js_ast.ENumber, *js_ast.EPrivateIdentifier:\n\t\t\t// Figure out where to stick the decorator side effects to preserve their order\n\t\t\tif nextComputedPropertyKey != nil {\n\t\t\t\t// Insert it before everything that comes after it\n\t\t\t\t*nextComputedPropertyKey = js_ast.JoinWithComma(decorators, *nextComputedPropertyKey)\n\t\t\t} else {\n\t\t\t\t// Insert it after the first thing that comes before it\n\t\t\t\tctx.computedPropertyChain = js_ast.JoinWithComma(decorators, ctx.computedPropertyChain)\n\t\t\t}\n\t\t\tcontinue\n\n\t\tdefault:\n\t\t\t// Otherwise, evaluate the decorators right before the property key\n\t\t\tif decorators.Data != nil {\n\t\t\t\tprop.Key = js_ast.JoinWithComma(decorators, prop.Key)\n\t\t\t\tprop.Flags |= js_ast.PropertyIsComputed\n\t\t\t}\n\t\t}\n\n\t\t// If this key is referenced elsewhere, make sure to still preserve\n\t\t// its side effects in the property's original location\n\t\tif analysis.isComputedPropertyCopiedOrMoved {\n\t\t\t// If this property is being duplicated instead of moved or removed, then\n\t\t\t// we still need the assignment to the temporary so that we can reference\n\t\t\t// it in multiple places, but we don't have to hoist the assignment to an\n\t\t\t// earlier property (since this property is still there). In that case\n\t\t\t// we can reduce generated code size by avoiding the hoist. One example\n\t\t\t// of this case is a decorator on a class element with a computed\n\t\t\t// property key:\n\t\t\t//\n\t\t\t//   class Foo {\n\t\t\t//     @dec [a()]() {}\n\t\t\t//   }\n\t\t\t//\n\t\t\t// We want to do this:\n\t\t\t//\n\t\t\t//   var _a;\n\t\t\t//   class Foo {\n\t\t\t//     [_a = a()]() {}\n\t\t\t//   }\n\t\t\t//   __decorateClass([dec], Foo.prototype, _a, 1);\n\t\t\t//\n\t\t\t// instead of this:\n\t\t\t//\n\t\t\t//   var _a;\n\t\t\t//   _a = a();\n\t\t\t//   class Foo {\n\t\t\t//     [_a]() {}\n\t\t\t//   }\n\t\t\t//   __decorateClass([dec], Foo.prototype, _a, 1);\n\t\t\t//\n\t\t\t// So only do the hoist if this property is being moved or removed.\n\t\t\tif !analysis.rewriteAutoAccessorToGetSet && (analysis.mustLowerField || analysis.staticFieldToBlockAssign) {\n\t\t\t\tinlineKey := prop.Key\n\n\t\t\t\tif !analysis.needsValueOfKey {\n\t\t\t\t\t// In certain cases, we only need to evaluate a property key for its\n\t\t\t\t\t// side effects but we don't actually need the value of the key itself.\n\t\t\t\t\t// For example, a TypeScript class field without an initializer is\n\t\t\t\t\t// omitted when TypeScript's \"useDefineForClassFields\" setting is false.\n\t\t\t\t} else {\n\t\t\t\t\t// Store the key in a temporary so we can refer to it later\n\t\t\t\t\tref := p.generateTempRef(tempRefNeedsDeclare, \"\")\n\t\t\t\t\tinlineKey = js_ast.Assign(js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}}, prop.Key)\n\t\t\t\t\tp.recordUsage(ref)\n\n\t\t\t\t\t// Replace this property key with a reference to the temporary. We\n\t\t\t\t\t// don't need to store the temporary in the \"propertyKeyTempRefs\"\n\t\t\t\t\t// map because all references will refer to the temporary, not just\n\t\t\t\t\t// some of them.\n\t\t\t\t\tprop.Key = js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}}\n\t\t\t\t\tp.recordUsage(ref)\n\t\t\t\t}\n\n\t\t\t\t// Figure out where to stick this property's side effect to preserve its order\n\t\t\t\tif nextComputedPropertyKey != nil {\n\t\t\t\t\t// Insert it before everything that comes after it\n\t\t\t\t\t*nextComputedPropertyKey = js_ast.JoinWithComma(inlineKey, *nextComputedPropertyKey)\n\t\t\t\t} else {\n\t\t\t\t\t// Insert it after the first thing that comes before it\n\t\t\t\t\tctx.computedPropertyChain = js_ast.JoinWithComma(inlineKey, ctx.computedPropertyChain)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Otherwise, we keep the side effects in place (as described above) but\n\t\t\t// just store the key in a temporary so we can refer to it later.\n\t\t\tref := p.generateTempRef(tempRefNeedsDeclare, \"\")\n\t\t\tprop.Key = js_ast.Assign(js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}}, prop.Key)\n\t\t\tp.recordUsage(ref)\n\n\t\t\t// Use this temporary when creating duplicate references to this key\n\t\t\tif propertyKeyTempRefs == nil {\n\t\t\t\tpropertyKeyTempRefs = make(map[int]ast.Ref)\n\t\t\t}\n\t\t\tpropertyKeyTempRefs[propIndex] = ref\n\n\t\t\t// Deliberately continue to fall through to the \"computed\" case below:\n\t\t}\n\n\t\t// Otherwise, this computed property could be a good location to evaluate\n\t\t// something that comes before it. Remember this location for later.\n\t\tif prop.Flags.Has(js_ast.PropertyIsComputed) {\n\t\t\t// If any side effects after this were hoisted here, then inline them now.\n\t\t\t// We don't want to reorder any side effects.\n\t\t\tif ctx.computedPropertyChain.Data != nil {\n\t\t\t\tref, ok := propertyKeyTempRefs[propIndex]\n\t\t\t\tif !ok {\n\t\t\t\t\tref = p.generateTempRef(tempRefNeedsDeclare, \"\")\n\t\t\t\t\tprop.Key = js_ast.Assign(js_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}}, prop.Key)\n\t\t\t\t\tp.recordUsage(ref)\n\t\t\t\t}\n\t\t\t\tprop.Key = js_ast.JoinWithComma(\n\t\t\t\t\tjs_ast.JoinWithComma(prop.Key, ctx.computedPropertyChain),\n\t\t\t\t\tjs_ast.Expr{Loc: prop.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}})\n\t\t\t\tp.recordUsage(ref)\n\t\t\t\tctx.computedPropertyChain = js_ast.Expr{}\n\t\t\t}\n\n\t\t\t// Remember this location for later\n\t\t\tnextComputedPropertyKey = &prop.Key\n\t\t}\n\t}\n\n\t// If any side effects in the class body were hoisted up to the \"extends\"\n\t// clause, then inline them before the \"extends\" clause is evaluated. We\n\t// don't want to reorder any side effects. For example:\n\t//\n\t//   class Foo extends a() {\n\t//     static [b()]\n\t//   }\n\t//\n\t// We want to do this:\n\t//\n\t//   var _a, _b;\n\t//   class Foo extends (_b = a(), _a = b(), _b) {\n\t//   }\n\t//   __publicField(Foo, _a);\n\t//\n\t// instead of this:\n\t//\n\t//   var _a;\n\t//   _a = b();\n\t//   class Foo extends a() {\n\t//   }\n\t//   __publicField(Foo, _a);\n\t//\n\tif ctx.computedPropertyChain.Data != nil && ctx.class.ExtendsOrNil.Data != nil {\n\t\tctx.extendsRef = p.generateTempRef(tempRefNeedsDeclare, \"\")\n\t\tctx.class.ExtendsOrNil = js_ast.JoinWithComma(js_ast.JoinWithComma(\n\t\t\tjs_ast.Assign(js_ast.Expr{Loc: ctx.class.ExtendsOrNil.Loc, Data: &js_ast.EIdentifier{Ref: ctx.extendsRef}}, ctx.class.ExtendsOrNil),\n\t\t\tctx.computedPropertyChain),\n\t\t\tjs_ast.Expr{Loc: ctx.class.ExtendsOrNil.Loc, Data: &js_ast.EIdentifier{Ref: ctx.extendsRef}})\n\t\tp.recordUsage(ctx.extendsRef)\n\t\tp.recordUsage(ctx.extendsRef)\n\t\tctx.computedPropertyChain = js_ast.Expr{}\n\t}\n\treturn\n}\n\n// This corresponds to the initialization order in the specification:\n//\n//  27. For each element e of staticElements, do\n//     a. If e is a ClassElementDefinition Record and e.[[Kind]] is not field, then\n//\n//  28. For each element e of instanceElements, do\n//     a. If e.[[Kind]] is not field, then\n//\n//  29. For each element e of staticElements, do\n//     a. If e.[[Kind]] is field, then\n//\n//  30. For each element e of instanceElements, do\n//     a. If e.[[Kind]] is field, then\nfunc fieldOrAccessorOrder(kind js_ast.PropertyKind, flags js_ast.PropertyFlags) (int, bool) {\n\tif kind == js_ast.PropertyAutoAccessor {\n\t\tif flags.Has(js_ast.PropertyIsStatic) {\n\t\t\treturn 0, true\n\t\t} else {\n\t\t\treturn 1, true\n\t\t}\n\t} else if kind == js_ast.PropertyField {\n\t\tif flags.Has(js_ast.PropertyIsStatic) {\n\t\t\treturn 2, true\n\t\t} else {\n\t\t\treturn 3, true\n\t\t}\n\t}\n\treturn 0, false\n}\n\nfunc (ctx *lowerClassContext) processProperties(p *parser, classLoweringInfo classLoweringInfo, result visitClassResult) {\n\tproperties := make([]js_ast.Property, 0, len(ctx.class.Properties))\n\tpropertyKeyTempRefs, decoratorTempRefs := ctx.hoistComputedProperties(p, classLoweringInfo)\n\n\t// Save the initializer index for each field and accessor element\n\tif ctx.class.ShouldLowerStandardDecorators {\n\t\tvar counts [4]int\n\n\t\t// Count how many initializers there are in each section\n\t\tfor _, prop := range ctx.class.Properties {\n\t\t\tif len(prop.Decorators) > 0 {\n\t\t\t\tif i, ok := fieldOrAccessorOrder(prop.Kind, prop.Flags); ok {\n\t\t\t\t\tcounts[i]++\n\t\t\t\t} else if prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\t\tctx.decoratorCallStaticMethodExtraInitializers = true\n\t\t\t\t} else {\n\t\t\t\t\tctx.decoratorCallInstanceMethodExtraInitializers = true\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Give each on an index for the order it will be initialized in\n\t\tif counts[0] > 0 || counts[1] > 0 || counts[2] > 0 || counts[3] > 0 {\n\t\t\tindices := [4]int{0, counts[0], counts[0] + counts[1], counts[0] + counts[1] + counts[2]}\n\t\t\tctx.decoratorPropertyToInitializerMap = make(map[int]int)\n\n\t\t\tfor propIndex, prop := range ctx.class.Properties {\n\t\t\t\tif len(prop.Decorators) > 0 {\n\t\t\t\t\tif i, ok := fieldOrAccessorOrder(prop.Kind, prop.Flags); ok {\n\t\t\t\t\t\tctx.decoratorPropertyToInitializerMap[propIndex] = indices[i]\n\t\t\t\t\t\tindices[i]++\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Evaluate the decorator expressions inline\n\tif ctx.class.ShouldLowerStandardDecorators && len(ctx.class.Decorators) > 0 {\n\t\tname := ctx.nameToKeep\n\t\tif name == \"\" {\n\t\t\tname = \"class\"\n\t\t}\n\t\tdecoratorsRef := p.generateTempRef(tempRefNeedsDeclare, fmt.Sprintf(\"_%s_decorators\", name))\n\t\tvalues := make([]js_ast.Expr, len(ctx.class.Decorators))\n\t\tfor i, decorator := range ctx.class.Decorators {\n\t\t\tvalues[i] = decorator.Value\n\t\t}\n\t\tatLoc := ctx.class.Decorators[0].AtLoc\n\t\tctx.computedPropertyChain = js_ast.JoinWithComma(js_ast.Assign(\n\t\t\tjs_ast.Expr{Loc: atLoc, Data: &js_ast.EIdentifier{Ref: decoratorsRef}},\n\t\t\tjs_ast.Expr{Loc: atLoc, Data: &js_ast.EArray{Items: values, IsSingleLine: true}},\n\t\t), ctx.computedPropertyChain)\n\t\tp.recordUsage(decoratorsRef)\n\t\tctx.decoratorClassDecorators = js_ast.Expr{Loc: atLoc, Data: &js_ast.EIdentifier{Ref: decoratorsRef}}\n\t\tp.recordUsage(decoratorsRef)\n\t\tctx.class.Decorators = nil\n\t}\n\n\tfor propIndex, prop := range ctx.class.Properties {\n\t\tif prop.Kind == js_ast.PropertyClassStaticBlock {\n\t\t\t// Drop empty class blocks when minifying\n\t\t\tif p.options.minifySyntax && len(prop.ClassStaticBlock.Block.Stmts) == 0 {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Lower this block if needed\n\t\t\tif classLoweringInfo.lowerAllStaticFields {\n\t\t\t\tctx.lowerStaticBlock(p, prop.Loc, *prop.ClassStaticBlock)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Otherwise, keep this property\n\t\t\tproperties = append(properties, prop)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Merge parameter decorators with method decorators\n\t\tif p.options.ts.Parse && prop.Kind.IsMethodDefinition() {\n\t\t\tif fn, ok := prop.ValueOrNil.Data.(*js_ast.EFunction); ok {\n\t\t\t\tisConstructor := false\n\t\t\t\tif key, ok := prop.Key.Data.(*js_ast.EString); ok {\n\t\t\t\t\tisConstructor = helpers.UTF16EqualsString(key.Value, \"constructor\")\n\t\t\t\t}\n\t\t\t\targs := fn.Fn.Args\n\t\t\t\tfor i, arg := range args {\n\t\t\t\t\tfor _, decorator := range arg.Decorators {\n\t\t\t\t\t\t// Generate a call to \"__decorateParam()\" for this parameter decorator\n\t\t\t\t\t\tvar decorators *[]js_ast.Decorator = &prop.Decorators\n\t\t\t\t\t\tif isConstructor {\n\t\t\t\t\t\t\tdecorators = &ctx.class.Decorators\n\t\t\t\t\t\t}\n\t\t\t\t\t\t*decorators = append(*decorators, js_ast.Decorator{\n\t\t\t\t\t\t\tValue: p.callRuntime(decorator.Value.Loc, \"__decorateParam\", []js_ast.Expr{\n\t\t\t\t\t\t\t\t{Loc: decorator.Value.Loc, Data: &js_ast.ENumber{Value: float64(i)}},\n\t\t\t\t\t\t\t\tdecorator.Value,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tAtLoc: decorator.AtLoc,\n\t\t\t\t\t\t})\n\t\t\t\t\t\targs[i].Decorators = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tanalysis := ctx.analyzeProperty(p, prop, classLoweringInfo)\n\n\t\t// When the property key needs to be referenced multiple times, subsequent\n\t\t// references may need to reference a temporary variable instead of copying\n\t\t// the whole property key expression (since we only want to evaluate side\n\t\t// effects once).\n\t\tkeyExprNoSideEffects := prop.Key\n\t\tif ref, ok := propertyKeyTempRefs[propIndex]; ok {\n\t\t\tkeyExprNoSideEffects.Data = &js_ast.EIdentifier{Ref: ref}\n\t\t}\n\n\t\t// Handle TypeScript experimental decorators\n\t\tif len(analysis.propExperimentalDecorators) > 0 {\n\t\t\tprop.Decorators = nil\n\n\t\t\t// Generate a single call to \"__decorateClass()\" for this property\n\t\t\tloc := prop.Key.Loc\n\n\t\t\t// This code tells \"__decorateClass()\" if the descriptor should be undefined\n\t\t\tdescriptorKind := float64(1)\n\t\t\tif prop.Kind == js_ast.PropertyField || prop.Kind == js_ast.PropertyDeclareOrAbstract {\n\t\t\t\tdescriptorKind = 2\n\t\t\t}\n\n\t\t\t// Instance properties use the prototype, static properties use the class\n\t\t\tvar target js_ast.Expr\n\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\ttarget = ctx.nameFunc()\n\t\t\t} else {\n\t\t\t\ttarget = js_ast.Expr{Loc: loc, Data: &js_ast.EDot{Target: ctx.nameFunc(), Name: \"prototype\", NameLoc: loc}}\n\t\t\t}\n\n\t\t\tvalues := make([]js_ast.Expr, len(analysis.propExperimentalDecorators))\n\t\t\tfor i, decorator := range analysis.propExperimentalDecorators {\n\t\t\t\tvalues[i] = decorator.Value\n\t\t\t}\n\t\t\tdecorator := p.callRuntime(loc, \"__decorateClass\", []js_ast.Expr{\n\t\t\t\t{Loc: loc, Data: &js_ast.EArray{Items: values}},\n\t\t\t\ttarget,\n\t\t\t\tcloneKeyForLowerClass(keyExprNoSideEffects),\n\t\t\t\t{Loc: loc, Data: &js_ast.ENumber{Value: descriptorKind}},\n\t\t\t})\n\n\t\t\t// Static decorators are grouped after instance decorators\n\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\tctx.staticExperimentalDecorators = append(ctx.staticExperimentalDecorators, decorator)\n\t\t\t} else {\n\t\t\t\tctx.instanceExperimentalDecorators = append(ctx.instanceExperimentalDecorators, decorator)\n\t\t\t}\n\t\t}\n\n\t\t// Handle JavaScript decorators\n\t\tinitializerIndex := -1\n\t\tif len(analysis.propDecorators) > 0 {\n\t\t\tprop.Decorators = nil\n\t\t\tloc := prop.Loc\n\t\t\tkeyLoc := prop.Key.Loc\n\t\t\tatLoc := analysis.propDecorators[0].AtLoc\n\n\t\t\t// Encode information about this property using bit flags\n\t\t\tvar flags int\n\t\t\tswitch prop.Kind {\n\t\t\tcase js_ast.PropertyMethod:\n\t\t\t\tflags = 1\n\t\t\tcase js_ast.PropertyGetter:\n\t\t\t\tflags = 2\n\t\t\tcase js_ast.PropertySetter:\n\t\t\t\tflags = 3\n\t\t\tcase js_ast.PropertyAutoAccessor:\n\t\t\t\tflags = 4\n\t\t\tcase js_ast.PropertyField:\n\t\t\t\tflags = 5\n\t\t\t}\n\t\t\tif flags >= 4 {\n\t\t\t\tinitializerIndex = ctx.decoratorPropertyToInitializerMap[propIndex]\n\t\t\t}\n\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\tflags |= 8\n\t\t\t}\n\t\t\tif analysis.private != nil {\n\t\t\t\tflags |= 16\n\t\t\t}\n\n\t\t\t// Start the arguments for the call to \"__decorateElement\"\n\t\t\tvar key js_ast.Expr\n\t\t\tdecoratorsRef := decoratorTempRefs[propIndex]\n\t\t\tif ctx.decoratorContextRef == ast.InvalidRef {\n\t\t\t\tctx.decoratorContextRef = p.generateTempRef(tempRefNeedsDeclare, \"_init\")\n\t\t\t}\n\t\t\tif analysis.private != nil {\n\t\t\t\tkey = js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(p.symbols[analysis.private.Ref.InnerIndex].OriginalName)}}\n\t\t\t} else {\n\t\t\t\tkey = cloneKeyForLowerClass(keyExprNoSideEffects)\n\t\t\t}\n\t\t\targs := []js_ast.Expr{\n\t\t\t\t{Loc: loc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\t\t{Loc: loc, Data: &js_ast.ENumber{Value: float64(flags)}},\n\t\t\t\tkey,\n\t\t\t\t{Loc: atLoc, Data: &js_ast.EIdentifier{Ref: decoratorsRef}},\n\t\t\t}\n\t\t\tp.recordUsage(ctx.decoratorContextRef)\n\t\t\tp.recordUsage(decoratorsRef)\n\n\t\t\t// Append any optional additional arguments\n\t\t\tprivateFnRef := ast.InvalidRef\n\t\t\tif analysis.private != nil {\n\t\t\t\t// Add the \"target\" argument (the weak set)\n\t\t\t\targs = append(args, js_ast.Expr{Loc: keyLoc, Data: &js_ast.EIdentifier{Ref: analysis.private.Ref}})\n\t\t\t\tp.recordUsage(analysis.private.Ref)\n\n\t\t\t\t// Add the \"extra\" argument (the function)\n\t\t\t\tswitch prop.Kind {\n\t\t\t\tcase js_ast.PropertyMethod:\n\t\t\t\t\tprivateFnRef = p.privateGetters[analysis.private.Ref]\n\t\t\t\tcase js_ast.PropertyGetter:\n\t\t\t\t\tprivateFnRef = p.privateGetters[analysis.private.Ref]\n\t\t\t\tcase js_ast.PropertySetter:\n\t\t\t\t\tprivateFnRef = p.privateSetters[analysis.private.Ref]\n\t\t\t\t}\n\t\t\t\tif privateFnRef != ast.InvalidRef {\n\t\t\t\t\targs = append(args, js_ast.Expr{Loc: keyLoc, Data: &js_ast.EIdentifier{Ref: privateFnRef}})\n\t\t\t\t\tp.recordUsage(privateFnRef)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Add the \"target\" argument (the class object)\n\t\t\t\targs = append(args, ctx.nameFunc())\n\t\t\t}\n\n\t\t\t// Auto-accessors will generate a private field for storage. Lower this\n\t\t\t// field, which will generate a WeakMap instance, and then pass the\n\t\t\t// WeakMap instance into the decorator helper so the lowered getter and\n\t\t\t// setter can use it.\n\t\t\tif prop.Kind == js_ast.PropertyAutoAccessor {\n\t\t\t\tvar kind ast.SymbolKind\n\t\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\t\tkind = ast.SymbolPrivateStaticField\n\t\t\t\t} else {\n\t\t\t\t\tkind = ast.SymbolPrivateField\n\t\t\t\t}\n\t\t\t\tref := p.newSymbol(kind, \"#\"+p.propertyNameHint(prop.Key))\n\t\t\t\tp.symbols[ref.InnerIndex].Flags |= ast.PrivateSymbolMustBeLowered\n\t\t\t\t_, autoAccessorWeakMapRef, _ := ctx.lowerField(p, prop, &js_ast.EPrivateIdentifier{Ref: ref}, false, false, initializerIndex)\n\t\t\t\targs = append(args, js_ast.Expr{Loc: keyLoc, Data: &js_ast.EIdentifier{Ref: autoAccessorWeakMapRef}})\n\t\t\t\tp.recordUsage(autoAccessorWeakMapRef)\n\t\t\t}\n\n\t\t\t// Assign the result\n\t\t\telement := p.callRuntime(loc, \"__decorateElement\", args)\n\t\t\tif privateFnRef != ast.InvalidRef {\n\t\t\t\telement = js_ast.Assign(js_ast.Expr{Loc: keyLoc, Data: &js_ast.EIdentifier{Ref: privateFnRef}}, element)\n\t\t\t\tp.recordUsage(privateFnRef)\n\t\t\t} else if prop.Kind == js_ast.PropertyAutoAccessor && analysis.private != nil {\n\t\t\t\tref := p.generateTempRef(tempRefNeedsDeclare, \"\")\n\t\t\t\tprivateGetFnRef := p.generateTempRef(tempRefNeedsDeclare, \"_\")\n\t\t\t\tprivateSetFnRef := p.generateTempRef(tempRefNeedsDeclare, \"_\")\n\t\t\t\tp.symbols[privateGetFnRef.InnerIndex].Link = p.privateGetters[analysis.private.Ref]\n\t\t\t\tp.symbols[privateSetFnRef.InnerIndex].Link = p.privateSetters[analysis.private.Ref]\n\n\t\t\t\t// Unpack the \"get\" and \"set\" properties from the returned property descriptor\n\t\t\t\telement = js_ast.JoinWithComma(js_ast.JoinWithComma(\n\t\t\t\t\tjs_ast.Assign(\n\t\t\t\t\t\tjs_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}},\n\t\t\t\t\t\telement),\n\t\t\t\t\tjs_ast.Assign(\n\t\t\t\t\t\tjs_ast.Expr{Loc: keyLoc, Data: &js_ast.EIdentifier{Ref: privateGetFnRef}},\n\t\t\t\t\t\tjs_ast.Expr{Loc: loc, Data: &js_ast.EDot{Target: js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}, Name: \"get\", NameLoc: loc}})),\n\t\t\t\t\tjs_ast.Assign(\n\t\t\t\t\t\tjs_ast.Expr{Loc: keyLoc, Data: &js_ast.EIdentifier{Ref: privateSetFnRef}},\n\t\t\t\t\t\tjs_ast.Expr{Loc: loc, Data: &js_ast.EDot{Target: js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}, Name: \"set\", NameLoc: loc}}))\n\t\t\t\tp.recordUsage(ref)\n\t\t\t\tp.recordUsage(privateGetFnRef)\n\t\t\t\tp.recordUsage(ref)\n\t\t\t\tp.recordUsage(privateSetFnRef)\n\t\t\t\tp.recordUsage(ref)\n\t\t\t}\n\n\t\t\t// Put the call to the decorators in the right place\n\t\t\tif prop.Kind == js_ast.PropertyField {\n\t\t\t\t// Field\n\t\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\t\tctx.decoratorStaticFieldElements = append(ctx.decoratorStaticFieldElements, element)\n\t\t\t\t} else {\n\t\t\t\t\tctx.decoratorInstanceFieldElements = append(ctx.decoratorInstanceFieldElements, element)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Non-field\n\t\t\t\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\t\t\t\tctx.decoratorStaticNonFieldElements = append(ctx.decoratorStaticNonFieldElements, element)\n\t\t\t\t} else {\n\t\t\t\t\tctx.decoratorInstanceNonFieldElements = append(ctx.decoratorInstanceNonFieldElements, element)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Omit decorated auto-accessors as they will be now generated at run-time instead\n\t\t\tif prop.Kind == js_ast.PropertyAutoAccessor {\n\t\t\t\tif analysis.private != nil {\n\t\t\t\t\tctx.lowerPrivateMethod(p, prop, analysis.private)\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Generate get/set methods for auto-accessors\n\t\tif analysis.rewriteAutoAccessorToGetSet {\n\t\t\tproperties = ctx.rewriteAutoAccessorToGetSet(p, prop, properties, keyExprNoSideEffects, analysis.mustLowerField, analysis.private, result)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Lower fields\n\t\tif (!prop.Kind.IsMethodDefinition() && analysis.mustLowerField) || analysis.staticFieldToBlockAssign {\n\t\t\tvar keep bool\n\t\t\tprop, _, keep = ctx.lowerField(p, prop, analysis.private, analysis.shouldOmitFieldInitializer, analysis.staticFieldToBlockAssign, initializerIndex)\n\t\t\tif !keep {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// Lower methods\n\t\tif prop.Kind.IsMethodDefinition() && ctx.lowerMethod(p, prop, analysis.private) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Keep this property\n\t\tproperties = append(properties, prop)\n\t}\n\n\t// Finish the filtering operation\n\tctx.class.Properties = properties\n}\n\nfunc (ctx *lowerClassContext) lowerStaticBlock(p *parser, loc logger.Loc, block js_ast.ClassStaticBlock) {\n\tisAllExprs := []js_ast.Expr{}\n\n\t// Are all statements in the block expression statements?\nloop:\n\tfor _, stmt := range block.Block.Stmts {\n\t\tswitch s := stmt.Data.(type) {\n\t\tcase *js_ast.SEmpty:\n\t\t\t// Omit stray semicolons completely\n\t\tcase *js_ast.SExpr:\n\t\t\tisAllExprs = append(isAllExprs, s.Value)\n\t\tdefault:\n\t\t\tisAllExprs = nil\n\t\t\tbreak loop\n\t\t}\n\t}\n\n\tif isAllExprs != nil {\n\t\t// I think it should be safe to inline the static block IIFE here\n\t\t// since all uses of \"this\" should have already been replaced by now.\n\t\tctx.staticMembers = append(ctx.staticMembers, isAllExprs...)\n\t} else {\n\t\t// But if there is a non-expression statement, fall back to using an\n\t\t// IIFE since we may be in an expression context and can't use a block.\n\t\tctx.staticMembers = append(ctx.staticMembers, js_ast.Expr{Loc: loc, Data: &js_ast.ECall{\n\t\t\tTarget: js_ast.Expr{Loc: loc, Data: &js_ast.EArrow{Body: js_ast.FnBody{\n\t\t\t\tLoc:   block.Loc,\n\t\t\t\tBlock: block.Block,\n\t\t\t}}},\n\t\t\tCanBeUnwrappedIfUnused: p.astHelpers.StmtsCanBeRemovedIfUnused(block.Block.Stmts, 0),\n\t\t}})\n\t}\n}\n\nfunc (ctx *lowerClassContext) rewriteAutoAccessorToGetSet(\n\tp *parser,\n\tprop js_ast.Property,\n\tproperties []js_ast.Property,\n\tkeyExprNoSideEffects js_ast.Expr,\n\tmustLowerField bool,\n\tprivate *js_ast.EPrivateIdentifier,\n\tresult visitClassResult,\n) []js_ast.Property {\n\tvar storageKind ast.SymbolKind\n\tif prop.Flags.Has(js_ast.PropertyIsStatic) {\n\t\tstorageKind = ast.SymbolPrivateStaticField\n\t} else {\n\t\tstorageKind = ast.SymbolPrivateField\n\t}\n\n\t// Generate the name of the private field to use for storage\n\tvar storageName string\n\tswitch k := keyExprNoSideEffects.Data.(type) {\n\tcase *js_ast.EString:\n\t\tstorageName = \"#\" + helpers.UTF16ToString(k.Value)\n\tcase *js_ast.EPrivateIdentifier:\n\t\tstorageName = \"#_\" + p.symbols[k.Ref.InnerIndex].OriginalName[1:]\n\tdefault:\n\t\tstorageName = \"#\" + ast.DefaultNameMinifierJS.NumberToMinifiedName(ctx.autoAccessorCount)\n\t\tctx.autoAccessorCount++\n\t}\n\n\t// Generate the symbols we need\n\tstorageRef := p.newSymbol(storageKind, storageName)\n\targRef := p.newSymbol(ast.SymbolOther, \"_\")\n\tresult.bodyScope.Generated = append(result.bodyScope.Generated, storageRef)\n\tresult.bodyScope.Children = append(result.bodyScope.Children, &js_ast.Scope{Kind: js_ast.ScopeFunctionBody, Generated: []ast.Ref{argRef}})\n\n\t// Replace this accessor with other properties\n\tloc := keyExprNoSideEffects.Loc\n\tstoragePrivate := &js_ast.EPrivateIdentifier{Ref: storageRef}\n\tif mustLowerField {\n\t\t// Forward the accessor's lowering status on to the storage field. If we\n\t\t// don't do this, then we risk having the underlying private symbol\n\t\t// behaving differently than if it were authored manually (e.g. being\n\t\t// placed outside of the class body, which is a syntax error).\n\t\tp.symbols[storageRef.InnerIndex].Flags |= ast.PrivateSymbolMustBeLowered\n\t}\n\tstorageNeedsToBeLowered := p.privateSymbolNeedsToBeLowered(storagePrivate)\n\tstorageProp := js_ast.Property{\n\t\tLoc:              prop.Loc,\n\t\tKind:             js_ast.PropertyField,\n\t\tFlags:            prop.Flags & js_ast.PropertyIsStatic,\n\t\tKey:              js_ast.Expr{Loc: loc, Data: storagePrivate},\n\t\tInitializerOrNil: prop.InitializerOrNil,\n\t}\n\tif !mustLowerField {\n\t\tproperties = append(properties, storageProp)\n\t} else if prop, _, ok := ctx.lowerField(p, storageProp, storagePrivate, false, false, -1); ok {\n\t\tproperties = append(properties, prop)\n\t}\n\n\t// Getter\n\tvar getExpr js_ast.Expr\n\tif storageNeedsToBeLowered {\n\t\tgetExpr = p.lowerPrivateGet(js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}, loc, storagePrivate)\n\t} else {\n\t\tp.recordUsage(storageRef)\n\t\tgetExpr = js_ast.Expr{Loc: loc, Data: &js_ast.EIndex{\n\t\t\tTarget: js_ast.Expr{Loc: loc, Data: js_ast.EThisShared},\n\t\t\tIndex:  js_ast.Expr{Loc: loc, Data: &js_ast.EPrivateIdentifier{Ref: storageRef}},\n\t\t}}\n\t}\n\tgetterProp := js_ast.Property{\n\t\tLoc:   prop.Loc,\n\t\tKind:  js_ast.PropertyGetter,\n\t\tFlags: prop.Flags,\n\t\tKey:   prop.Key,\n\t\tValueOrNil: js_ast.Expr{Loc: loc, Data: &js_ast.EFunction{\n\t\t\tFn: js_ast.Fn{\n\t\t\t\tBody: js_ast.FnBody{\n\t\t\t\t\tLoc: loc,\n\t\t\t\t\tBlock: js_ast.SBlock{\n\t\t\t\t\t\tStmts: []js_ast.Stmt{\n\t\t\t\t\t\t\t{Loc: loc, Data: &js_ast.SReturn{ValueOrNil: getExpr}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}},\n\t}\n\tif !ctx.lowerMethod(p, getterProp, private) {\n\t\tproperties = append(properties, getterProp)\n\t}\n\n\t// Setter\n\tvar setExpr js_ast.Expr\n\tif storageNeedsToBeLowered {\n\t\tsetExpr = p.lowerPrivateSet(js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}, loc, storagePrivate,\n\t\t\tjs_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: argRef}})\n\t} else {\n\t\tp.recordUsage(storageRef)\n\t\tp.recordUsage(argRef)\n\t\tsetExpr = js_ast.Assign(\n\t\t\tjs_ast.Expr{Loc: loc, Data: &js_ast.EIndex{\n\t\t\t\tTarget: js_ast.Expr{Loc: loc, Data: js_ast.EThisShared},\n\t\t\t\tIndex:  js_ast.Expr{Loc: loc, Data: &js_ast.EPrivateIdentifier{Ref: storageRef}},\n\t\t\t}},\n\t\t\tjs_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: argRef}},\n\t\t)\n\t}\n\tsetterProp := js_ast.Property{\n\t\tLoc:   prop.Loc,\n\t\tKind:  js_ast.PropertySetter,\n\t\tFlags: prop.Flags,\n\t\tKey:   cloneKeyForLowerClass(keyExprNoSideEffects),\n\t\tValueOrNil: js_ast.Expr{Loc: loc, Data: &js_ast.EFunction{\n\t\t\tFn: js_ast.Fn{\n\t\t\t\tArgs: []js_ast.Arg{\n\t\t\t\t\t{Binding: js_ast.Binding{Loc: loc, Data: &js_ast.BIdentifier{Ref: argRef}}},\n\t\t\t\t},\n\t\t\t\tBody: js_ast.FnBody{\n\t\t\t\t\tLoc: loc,\n\t\t\t\t\tBlock: js_ast.SBlock{\n\t\t\t\t\t\tStmts: []js_ast.Stmt{\n\t\t\t\t\t\t\t{Loc: loc, Data: &js_ast.SExpr{Value: setExpr}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t}},\n\t}\n\tif !ctx.lowerMethod(p, setterProp, private) {\n\t\tproperties = append(properties, setterProp)\n\t}\n\treturn properties\n}\n\nfunc (ctx *lowerClassContext) insertInitializersIntoConstructor(p *parser, classLoweringInfo classLoweringInfo, result visitClassResult) {\n\tif len(ctx.parameterFields) == 0 &&\n\t\t!ctx.decoratorCallInstanceMethodExtraInitializers &&\n\t\tlen(ctx.instancePrivateMethods) == 0 &&\n\t\tlen(ctx.instanceMembers) == 0 &&\n\t\t(ctx.ctor == nil || result.superCtorRef == ast.InvalidRef) {\n\t\t// No need to generate a constructor\n\t\treturn\n\t}\n\n\t// Create a constructor if one doesn't already exist\n\tif ctx.ctor == nil {\n\t\tctx.ctor = &js_ast.EFunction{Fn: js_ast.Fn{Body: js_ast.FnBody{Loc: ctx.classLoc}}}\n\n\t\t// Append it to the list to reuse existing allocation space\n\t\tctx.class.Properties = append(ctx.class.Properties, js_ast.Property{\n\t\t\tKind:       js_ast.PropertyMethod,\n\t\t\tLoc:        ctx.classLoc,\n\t\t\tKey:        js_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(\"constructor\")}},\n\t\t\tValueOrNil: js_ast.Expr{Loc: ctx.classLoc, Data: ctx.ctor},\n\t\t})\n\n\t\t// Make sure the constructor has a super() call if needed\n\t\tif ctx.class.ExtendsOrNil.Data != nil {\n\t\t\ttarget := js_ast.Expr{Loc: ctx.classLoc, Data: js_ast.ESuperShared}\n\t\t\tif classLoweringInfo.shimSuperCtorCalls {\n\t\t\t\tp.recordUsage(result.superCtorRef)\n\t\t\t\ttarget.Data = &js_ast.EIdentifier{Ref: result.superCtorRef}\n\t\t\t}\n\t\t\targumentsRef := p.newSymbol(ast.SymbolUnbound, \"arguments\")\n\t\t\tp.currentScope.Generated = append(p.currentScope.Generated, argumentsRef)\n\t\t\tctx.ctor.Fn.Body.Block.Stmts = append(ctx.ctor.Fn.Body.Block.Stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SExpr{Value: js_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.ECall{\n\t\t\t\tTarget: target,\n\t\t\t\tArgs:   []js_ast.Expr{{Loc: ctx.classLoc, Data: &js_ast.ESpread{Value: js_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: argumentsRef}}}}},\n\t\t\t}}}})\n\t\t}\n\t}\n\n\t// Run instanceMethodExtraInitializers if needed\n\tvar decoratorInstanceMethodExtraInitializers js_ast.Expr\n\tif ctx.decoratorCallInstanceMethodExtraInitializers {\n\t\tdecoratorInstanceMethodExtraInitializers = p.callRuntime(ctx.classLoc, \"__runInitializers\", []js_ast.Expr{\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.ENumber{Value: (2 << 1) | 1}},\n\t\t\t{Loc: ctx.classLoc, Data: js_ast.EThisShared},\n\t\t})\n\t\tp.recordUsage(ctx.decoratorContextRef)\n\t}\n\n\t// Make sure the instance field initializers come after \"super()\" since\n\t// they need \"this\" to ba available\n\tgeneratedStmts := make([]js_ast.Stmt, 0,\n\t\tlen(ctx.parameterFields)+\n\t\t\tlen(ctx.instancePrivateMethods)+\n\t\t\tlen(ctx.instanceMembers))\n\tgeneratedStmts = append(generatedStmts, ctx.parameterFields...)\n\tif decoratorInstanceMethodExtraInitializers.Data != nil {\n\t\tgeneratedStmts = append(generatedStmts, js_ast.Stmt{Loc: decoratorInstanceMethodExtraInitializers.Loc, Data: &js_ast.SExpr{Value: decoratorInstanceMethodExtraInitializers}})\n\t}\n\tgeneratedStmts = append(generatedStmts, ctx.instancePrivateMethods...)\n\tgeneratedStmts = append(generatedStmts, ctx.instanceMembers...)\n\tp.insertStmtsAfterSuperCall(&ctx.ctor.Fn.Body, generatedStmts, result.superCtorRef)\n\n\t// Sort the constructor first to match the TypeScript compiler's output\n\tfor i := 0; i < len(ctx.class.Properties); i++ {\n\t\tif ctx.class.Properties[i].ValueOrNil.Data == ctx.ctor {\n\t\t\tctorProp := ctx.class.Properties[i]\n\t\t\tfor j := i; j > 0; j-- {\n\t\t\t\tctx.class.Properties[j] = ctx.class.Properties[j-1]\n\t\t\t}\n\t\t\tctx.class.Properties[0] = ctorProp\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (ctx *lowerClassContext) finishAndGenerateCode(p *parser, result visitClassResult) ([]js_ast.Stmt, js_ast.Expr) {\n\t// When bundling is enabled, we convert top-level class statements to\n\t// expressions:\n\t//\n\t//   // Before\n\t//   class Foo {\n\t//     static foo = () => Foo\n\t//   }\n\t//   Foo = wrap(Foo)\n\t//\n\t//   // After\n\t//   var _Foo = class _Foo {\n\t//     static foo = () => _Foo;\n\t//   };\n\t//   var Foo = _Foo;\n\t//   Foo = wrap(Foo);\n\t//\n\t// One reason to do this is that esbuild's bundler sometimes needs to lazily-\n\t// evaluate a module. For example, a module may end up being both the target\n\t// of a dynamic \"import()\" call and a static \"import\" statement. Lazy module\n\t// evaluation is done by wrapping the top-level module code in a closure. To\n\t// avoid a performance hit for static \"import\" statements, esbuild stores\n\t// top-level exported symbols outside of the closure and references them\n\t// directly instead of indirectly.\n\t//\n\t// Another reason to do this is that multiple JavaScript VMs have had and\n\t// continue to have performance issues with TDZ (i.e. \"temporal dead zone\")\n\t// checks. These checks validate that a let, or const, or class symbol isn't\n\t// used before it's initialized. Here are two issues with well-known VMs:\n\t//\n\t//   * V8: https://bugs.chromium.org/p/v8/issues/detail?id=13723 (10% slowdown)\n\t//   * JavaScriptCore: https://bugs.webkit.org/show_bug.cgi?id=199866 (1,000% slowdown!)\n\t//\n\t// JavaScriptCore had a severe performance issue as their TDZ implementation\n\t// had time complexity that was quadratic in the number of variables needing\n\t// TDZ checks in the same scope (with the top-level scope typically being the\n\t// worst offender). V8 has ongoing issues with TDZ checks being present\n\t// throughout the code their JIT generates even when they have already been\n\t// checked earlier in the same function or when the function in question has\n\t// already been run (so the checks have already happened).\n\t//\n\t// Due to esbuild's parallel architecture, we both a) need to transform class\n\t// statements to variables during parsing and b) don't yet know whether this\n\t// module will need to be lazily-evaluated or not in the parser. So we always\n\t// do this just in case it's needed.\n\tmustConvertStmtToExpr := ctx.kind != classKindExpr && p.currentScope.Parent == nil && (p.options.mode == config.ModeBundle || p.willWrapModuleInTryCatchForUsing)\n\n\t// Check to see if we have lowered decorators on the class itself\n\tvar classDecorators js_ast.Expr\n\tvar classExperimentalDecorators []js_ast.Decorator\n\tif p.options.ts.Parse && p.options.ts.Config.ExperimentalDecorators == config.True {\n\t\tclassExperimentalDecorators = ctx.class.Decorators\n\t\tctx.class.Decorators = nil\n\t} else if ctx.class.ShouldLowerStandardDecorators {\n\t\tclassDecorators = ctx.decoratorClassDecorators\n\t}\n\n\tvar decorateClassExpr js_ast.Expr\n\tif classDecorators.Data != nil {\n\t\t// Handle JavaScript decorators on the class itself\n\t\tif ctx.decoratorContextRef == ast.InvalidRef {\n\t\t\tctx.decoratorContextRef = p.generateTempRef(tempRefNeedsDeclare, \"_init\")\n\t\t}\n\t\tdecorateClassExpr = p.callRuntime(ctx.classLoc, \"__decorateElement\", []js_ast.Expr{\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.ENumber{Value: 0}},\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(ctx.nameToKeep)}},\n\t\t\tclassDecorators,\n\t\t\tctx.nameFunc(),\n\t\t})\n\t\tp.recordUsage(ctx.decoratorContextRef)\n\t\tdecorateClassExpr = js_ast.Assign(ctx.nameFunc(), decorateClassExpr)\n\t} else if ctx.decoratorContextRef != ast.InvalidRef {\n\t\t// Decorator metadata is present if there are any decorators on the class at all\n\t\tdecorateClassExpr = p.callRuntime(ctx.classLoc, \"__decoratorMetadata\", []js_ast.Expr{\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\tctx.nameFunc(),\n\t\t})\n\t}\n\n\t// If this is true, we have removed some code from the class body that could\n\t// potentially contain an expression that captures the inner class name.\n\t// In this case we must explicitly store the class to a separate inner class\n\t// name binding to avoid incorrect behavior if the class is later re-assigned,\n\t// since the removed code will no longer be in the class body scope.\n\thasPotentialInnerClassNameEscape := result.innerClassNameRef != ast.InvalidRef &&\n\t\t(ctx.computedPropertyChain.Data != nil ||\n\t\t\tlen(ctx.privateMembers) > 0 ||\n\t\t\tlen(ctx.staticPrivateMethods) > 0 ||\n\t\t\tlen(ctx.staticMembers) > 0 ||\n\n\t\t\t// TypeScript experimental decorators\n\t\t\tlen(ctx.instanceExperimentalDecorators) > 0 ||\n\t\t\tlen(ctx.staticExperimentalDecorators) > 0 ||\n\t\t\tlen(classExperimentalDecorators) > 0 ||\n\n\t\t\t// JavaScript decorators\n\t\t\tctx.decoratorContextRef != ast.InvalidRef)\n\n\t// If we need to represent the class as an expression (even if it's a\n\t// statement), then generate another symbol to use as the class name\n\tnameForClassDecorators := ast.LocRef{Ref: ast.InvalidRef}\n\tif len(classExperimentalDecorators) > 0 || hasPotentialInnerClassNameEscape || mustConvertStmtToExpr {\n\t\tif ctx.kind == classKindExpr {\n\t\t\t// For expressions, the inner and outer class names are the same\n\t\t\tname := ctx.nameFunc()\n\t\t\tnameForClassDecorators = ast.LocRef{Loc: name.Loc, Ref: name.Data.(*js_ast.EIdentifier).Ref}\n\t\t} else {\n\t\t\t// For statements we need to use the outer class name, not the inner one\n\t\t\tif ctx.class.Name != nil {\n\t\t\t\tnameForClassDecorators = *ctx.class.Name\n\t\t\t} else if ctx.kind == classKindExportDefaultStmt {\n\t\t\t\tnameForClassDecorators = ctx.defaultName\n\t\t\t} else {\n\t\t\t\tnameForClassDecorators = ast.LocRef{Loc: ctx.classLoc, Ref: p.generateTempRef(tempRefNoDeclare, \"\")}\n\t\t\t}\n\t\t\tp.recordUsage(nameForClassDecorators.Ref)\n\t\t}\n\t}\n\n\tvar prefixExprs []js_ast.Expr\n\tvar suffixExprs []js_ast.Expr\n\n\t// If there are JavaScript decorators, start by allocating a context object\n\tif ctx.decoratorContextRef != ast.InvalidRef {\n\t\tbase := js_ast.Expr{Loc: ctx.classLoc, Data: js_ast.ENullShared}\n\t\tif ctx.class.ExtendsOrNil.Data != nil {\n\t\t\tif ctx.extendsRef == ast.InvalidRef {\n\t\t\t\tctx.extendsRef = p.generateTempRef(tempRefNeedsDeclare, \"\")\n\t\t\t\tctx.class.ExtendsOrNil = js_ast.Assign(js_ast.Expr{Loc: ctx.class.ExtendsOrNil.Loc, Data: &js_ast.EIdentifier{Ref: ctx.extendsRef}}, ctx.class.ExtendsOrNil)\n\t\t\t\tp.recordUsage(ctx.extendsRef)\n\t\t\t}\n\t\t\tbase.Data = &js_ast.EIdentifier{Ref: ctx.extendsRef}\n\t\t}\n\t\tsuffixExprs = append(suffixExprs, js_ast.Assign(\n\t\t\tjs_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\tp.callRuntime(ctx.classLoc, \"__decoratorStart\", []js_ast.Expr{base}),\n\t\t))\n\t\tp.recordUsage(ctx.decoratorContextRef)\n\t}\n\n\t// Any of the computed property chain that we hoisted out of the class\n\t// body needs to come before the class expression.\n\tif ctx.computedPropertyChain.Data != nil {\n\t\tprefixExprs = append(prefixExprs, ctx.computedPropertyChain)\n\t}\n\n\t// WeakSets and WeakMaps\n\tsuffixExprs = append(suffixExprs, ctx.privateMembers...)\n\n\t// Evaluate JavaScript decorators here\n\tsuffixExprs = append(suffixExprs, ctx.decoratorStaticNonFieldElements...)\n\tsuffixExprs = append(suffixExprs, ctx.decoratorInstanceNonFieldElements...)\n\tsuffixExprs = append(suffixExprs, ctx.decoratorStaticFieldElements...)\n\tsuffixExprs = append(suffixExprs, ctx.decoratorInstanceFieldElements...)\n\n\t// Lowered initializers for static methods (including getters and setters)\n\tsuffixExprs = append(suffixExprs, ctx.staticPrivateMethods...)\n\n\t// Run JavaScript class decorators at the end of class initialization\n\tif decorateClassExpr.Data != nil {\n\t\tsuffixExprs = append(suffixExprs, decorateClassExpr)\n\t}\n\n\t// For each element initializer of staticMethodExtraInitializers\n\tif ctx.decoratorCallStaticMethodExtraInitializers {\n\t\tsuffixExprs = append(suffixExprs, p.callRuntime(ctx.classLoc, \"__runInitializers\", []js_ast.Expr{\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.ENumber{Value: (1 << 1) | 1}},\n\t\t\tctx.nameFunc(),\n\t\t}))\n\t\tp.recordUsage(ctx.decoratorContextRef)\n\t}\n\n\t// Lowered initializers for static fields, static accessors, and static blocks\n\tsuffixExprs = append(suffixExprs, ctx.staticMembers...)\n\n\t// The official TypeScript compiler adds generated code after the class body\n\t// in this exact order. Matching this order is important for correctness.\n\tsuffixExprs = append(suffixExprs, ctx.instanceExperimentalDecorators...)\n\tsuffixExprs = append(suffixExprs, ctx.staticExperimentalDecorators...)\n\n\t// For each element initializer of classExtraInitializers\n\tif classDecorators.Data != nil {\n\t\tsuffixExprs = append(suffixExprs, p.callRuntime(ctx.classLoc, \"__runInitializers\", []js_ast.Expr{\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},\n\t\t\t{Loc: ctx.classLoc, Data: &js_ast.ENumber{Value: (0 << 1) | 1}},\n\t\t\tctx.nameFunc(),\n\t\t}))\n\t\tp.recordUsage(ctx.decoratorContextRef)\n\t}\n\n\t// Run TypeScript experimental class decorators at the end of class initialization\n\tif len(classExperimentalDecorators) > 0 {\n\t\tvalues := make([]js_ast.Expr, len(classExperimentalDecorators))\n\t\tfor i, decorator := range classExperimentalDecorators {\n\t\t\tvalues[i] = decorator.Value\n\t\t}\n\t\tsuffixExprs = append(suffixExprs, js_ast.Assign(\n\t\t\tjs_ast.Expr{Loc: nameForClassDecorators.Loc, Data: &js_ast.EIdentifier{Ref: nameForClassDecorators.Ref}},\n\t\t\tp.callRuntime(ctx.classLoc, \"__decorateClass\", []js_ast.Expr{\n\t\t\t\t{Loc: ctx.classLoc, Data: &js_ast.EArray{Items: values}},\n\t\t\t\t{Loc: nameForClassDecorators.Loc, Data: &js_ast.EIdentifier{Ref: nameForClassDecorators.Ref}},\n\t\t\t}),\n\t\t))\n\t\tp.recordUsage(nameForClassDecorators.Ref)\n\t\tp.recordUsage(nameForClassDecorators.Ref)\n\t}\n\n\t// Our caller expects us to return the same form that was originally given to\n\t// us. If the class was originally an expression, then return an expression.\n\tif ctx.kind == classKindExpr {\n\t\t// Calling \"nameFunc\" will replace \"classExpr\", so make sure to do that first\n\t\t// before joining \"classExpr\" with any other expressions\n\t\tvar nameToJoin js_ast.Expr\n\t\tif ctx.didCaptureClassExpr || len(suffixExprs) > 0 {\n\t\t\tnameToJoin = ctx.nameFunc()\n\t\t}\n\n\t\t// Insert expressions on either side of the class as appropriate\n\t\tctx.classExpr = js_ast.JoinWithComma(js_ast.JoinAllWithComma(prefixExprs), ctx.classExpr)\n\t\tctx.classExpr = js_ast.JoinWithComma(ctx.classExpr, js_ast.JoinAllWithComma(suffixExprs))\n\n\t\t// Finally join \"classExpr\" with the variable that holds the class object\n\t\tctx.classExpr = js_ast.JoinWithComma(ctx.classExpr, nameToJoin)\n\t\tif ctx.wrapFunc != nil {\n\t\t\tctx.classExpr = ctx.wrapFunc(ctx.classExpr)\n\t\t}\n\t\treturn nil, ctx.classExpr\n\t}\n\n\t// Otherwise, the class was originally a statement. Return an array of\n\t// statements instead.\n\tvar stmts []js_ast.Stmt\n\tvar outerClassNameDecl js_ast.Stmt\n\n\t// Insert expressions before the class as appropriate\n\tfor _, expr := range prefixExprs {\n\t\tstmts = append(stmts, js_ast.Stmt{Loc: expr.Loc, Data: &js_ast.SExpr{Value: expr}})\n\t}\n\n\t// Handle converting a class statement to a class expression\n\tif nameForClassDecorators.Ref != ast.InvalidRef {\n\t\tclassExpr := js_ast.EClass{Class: *ctx.class}\n\t\tctx.class = &classExpr.Class\n\t\tinit := js_ast.Expr{Loc: ctx.classLoc, Data: &classExpr}\n\n\t\t// If the inner class name was referenced, then set the name of the class\n\t\t// that we will end up printing to the inner class name. Otherwise if the\n\t\t// inner class name was unused, we can just leave it blank.\n\t\tif result.innerClassNameRef != ast.InvalidRef {\n\t\t\t// \"class Foo { x = Foo }\" => \"const Foo = class _Foo { x = _Foo }\"\n\t\t\tctx.class.Name.Ref = result.innerClassNameRef\n\t\t} else {\n\t\t\t// \"class Foo {}\" => \"const Foo = class {}\"\n\t\t\tctx.class.Name = nil\n\t\t}\n\n\t\t// Generate the class initialization statement\n\t\tif len(classExperimentalDecorators) > 0 {\n\t\t\t// If there are class decorators, then we actually need to mutate the\n\t\t\t// immutable \"const\" binding that shadows everything in the class body.\n\t\t\t// The official TypeScript compiler does this by rewriting all class name\n\t\t\t// references in the class body to another temporary variable. This is\n\t\t\t// basically what we're doing here.\n\t\t\tp.recordUsage(nameForClassDecorators.Ref)\n\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SLocal{\n\t\t\t\tKind:     p.selectLocalKind(js_ast.LocalLet),\n\t\t\t\tIsExport: ctx.kind == classKindExportStmt,\n\t\t\t\tDecls: []js_ast.Decl{{\n\t\t\t\t\tBinding:    js_ast.Binding{Loc: nameForClassDecorators.Loc, Data: &js_ast.BIdentifier{Ref: nameForClassDecorators.Ref}},\n\t\t\t\t\tValueOrNil: init,\n\t\t\t\t}},\n\t\t\t}})\n\t\t\tif ctx.class.Name != nil {\n\t\t\t\tp.mergeSymbols(ctx.class.Name.Ref, nameForClassDecorators.Ref)\n\t\t\t\tctx.class.Name = nil\n\t\t\t}\n\t\t} else if hasPotentialInnerClassNameEscape {\n\t\t\t// If the inner class name was used, then we explicitly generate a binding\n\t\t\t// for it. That means the mutable outer class name is separate, and is\n\t\t\t// initialized after all static member initializers have finished.\n\t\t\tcaptureRef := p.newSymbol(ast.SymbolOther, p.symbols[result.innerClassNameRef.InnerIndex].OriginalName)\n\t\t\tp.currentScope.Generated = append(p.currentScope.Generated, captureRef)\n\t\t\tp.recordDeclaredSymbol(captureRef)\n\t\t\tp.mergeSymbols(result.innerClassNameRef, captureRef)\n\t\t\tkind := js_ast.LocalConst\n\t\t\tif classDecorators.Data != nil {\n\t\t\t\t// Class decorators need to be able to potentially mutate this binding\n\t\t\t\tkind = js_ast.LocalLet\n\t\t\t}\n\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SLocal{\n\t\t\t\tKind: p.selectLocalKind(kind),\n\t\t\t\tDecls: []js_ast.Decl{{\n\t\t\t\t\tBinding:    js_ast.Binding{Loc: nameForClassDecorators.Loc, Data: &js_ast.BIdentifier{Ref: captureRef}},\n\t\t\t\t\tValueOrNil: init,\n\t\t\t\t}},\n\t\t\t}})\n\t\t\tp.recordUsage(nameForClassDecorators.Ref)\n\t\t\tp.recordUsage(captureRef)\n\t\t\touterClassNameDecl = js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SLocal{\n\t\t\t\tKind:     p.selectLocalKind(js_ast.LocalLet),\n\t\t\t\tIsExport: ctx.kind == classKindExportStmt,\n\t\t\t\tDecls: []js_ast.Decl{{\n\t\t\t\t\tBinding:    js_ast.Binding{Loc: nameForClassDecorators.Loc, Data: &js_ast.BIdentifier{Ref: nameForClassDecorators.Ref}},\n\t\t\t\t\tValueOrNil: js_ast.Expr{Loc: ctx.classLoc, Data: &js_ast.EIdentifier{Ref: captureRef}},\n\t\t\t\t}},\n\t\t\t}}\n\t\t} else {\n\t\t\t// Otherwise, the inner class name isn't needed and we can just\n\t\t\t// use a single variable declaration for the outer class name.\n\t\t\tp.recordUsage(nameForClassDecorators.Ref)\n\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SLocal{\n\t\t\t\tKind:     p.selectLocalKind(js_ast.LocalLet),\n\t\t\t\tIsExport: ctx.kind == classKindExportStmt,\n\t\t\t\tDecls: []js_ast.Decl{{\n\t\t\t\t\tBinding:    js_ast.Binding{Loc: nameForClassDecorators.Loc, Data: &js_ast.BIdentifier{Ref: nameForClassDecorators.Ref}},\n\t\t\t\t\tValueOrNil: init,\n\t\t\t\t}},\n\t\t\t}})\n\t\t}\n\t} else {\n\t\t// Generate the specific kind of class statement that was passed in to us\n\t\tswitch ctx.kind {\n\t\tcase classKindStmt:\n\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SClass{Class: *ctx.class}})\n\t\tcase classKindExportStmt:\n\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SClass{Class: *ctx.class, IsExport: true}})\n\t\tcase classKindExportDefaultStmt:\n\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SExportDefault{\n\t\t\t\tDefaultName: ctx.defaultName,\n\t\t\t\tValue:       js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SClass{Class: *ctx.class}},\n\t\t\t}})\n\t\t}\n\n\t\t// The inner class name inside the class statement should be the same as\n\t\t// the class statement name itself\n\t\tif ctx.class.Name != nil && result.innerClassNameRef != ast.InvalidRef {\n\t\t\t// If the class body contains a direct eval call, then the inner class\n\t\t\t// name will be marked as \"MustNotBeRenamed\" (because we have already\n\t\t\t// popped the class body scope) but the outer class name won't be marked\n\t\t\t// as \"MustNotBeRenamed\" yet (because we haven't yet popped the containing\n\t\t\t// scope). Propagate this flag now before we merge these symbols so we\n\t\t\t// don't end up accidentally renaming the outer class name to the inner\n\t\t\t// class name.\n\t\t\tif p.currentScope.ContainsDirectEval {\n\t\t\t\tp.symbols[ctx.class.Name.Ref.InnerIndex].Flags |= (p.symbols[result.innerClassNameRef.InnerIndex].Flags & ast.MustNotBeRenamed)\n\t\t\t}\n\t\t\tp.mergeSymbols(result.innerClassNameRef, ctx.class.Name.Ref)\n\t\t}\n\t}\n\n\t// Insert expressions after the class as appropriate\n\tfor _, expr := range suffixExprs {\n\t\tstmts = append(stmts, js_ast.Stmt{Loc: expr.Loc, Data: &js_ast.SExpr{Value: expr}})\n\t}\n\n\t// This must come after the class body initializers have finished\n\tif outerClassNameDecl.Data != nil {\n\t\tstmts = append(stmts, outerClassNameDecl)\n\t}\n\n\tif nameForClassDecorators.Ref != ast.InvalidRef && ctx.kind == classKindExportDefaultStmt {\n\t\t// \"export default class x {}\" => \"class x {} export {x as default}\"\n\t\tstmts = append(stmts, js_ast.Stmt{Loc: ctx.classLoc, Data: &js_ast.SExportClause{\n\t\t\tItems: []js_ast.ClauseItem{{Alias: \"default\", Name: ctx.defaultName}},\n\t\t}})\n\t}\n\treturn stmts, js_ast.Expr{}\n}\n\nfunc cloneKeyForLowerClass(key js_ast.Expr) js_ast.Expr {\n\tswitch k := key.Data.(type) {\n\tcase *js_ast.ENumber:\n\t\tclone := *k\n\t\tkey.Data = &clone\n\tcase *js_ast.EString:\n\t\tclone := *k\n\t\tkey.Data = &clone\n\tcase *js_ast.EIdentifier:\n\t\tclone := *k\n\t\tkey.Data = &clone\n\tcase *js_ast.ENameOfSymbol:\n\t\tclone := *k\n\t\tkey.Data = &clone\n\tcase *js_ast.EPrivateIdentifier:\n\t\tclone := *k\n\t\tkey.Data = &clone\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n\treturn key\n}\n\n// Replace \"super()\" calls with our shim so that we can guarantee\n// that instance field initialization doesn't happen before \"super()\"\n// is called, since at that point \"this\" isn't available.\nfunc (p *parser) insertStmtsAfterSuperCall(body *js_ast.FnBody, stmtsToInsert []js_ast.Stmt, superCtorRef ast.Ref) {\n\t// If this class has no base class, then there's no \"super()\" call to handle\n\tif superCtorRef == ast.InvalidRef || p.symbols[superCtorRef.InnerIndex].UseCountEstimate == 0 {\n\t\tbody.Block.Stmts = append(stmtsToInsert, body.Block.Stmts...)\n\t\treturn\n\t}\n\n\t// It's likely that there's only one \"super()\" call, and that it's a\n\t// top-level expression in the constructor function body. If so, we\n\t// can generate tighter code for this common case.\n\tif p.symbols[superCtorRef.InnerIndex].UseCountEstimate == 1 {\n\t\tfor i, stmt := range body.Block.Stmts {\n\t\t\tvar before js_ast.Expr\n\t\t\tvar callLoc logger.Loc\n\t\t\tvar callData *js_ast.ECall\n\t\t\tvar after js_ast.Stmt\n\n\t\t\tswitch s := stmt.Data.(type) {\n\t\t\tcase *js_ast.SExpr:\n\t\t\t\tif b, loc, c, a := findFirstTopLevelSuperCall(s.Value, superCtorRef); c != nil {\n\t\t\t\t\tbefore, callLoc, callData = b, loc, c\n\t\t\t\t\tif a.Data != nil {\n\t\t\t\t\t\ts.Value = a\n\t\t\t\t\t\tafter = js_ast.Stmt{Loc: a.Loc, Data: s}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tcase *js_ast.SReturn:\n\t\t\t\tif s.ValueOrNil.Data != nil {\n\t\t\t\t\tif b, loc, c, a := findFirstTopLevelSuperCall(s.ValueOrNil, superCtorRef); c != nil && a.Data != nil {\n\t\t\t\t\t\tbefore, callLoc, callData = b, loc, c\n\t\t\t\t\t\ts.ValueOrNil = a\n\t\t\t\t\t\tafter = js_ast.Stmt{Loc: a.Loc, Data: s}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\tcase *js_ast.SThrow:\n\t\t\t\tif b, loc, c, a := findFirstTopLevelSuperCall(s.Value, superCtorRef); c != nil && a.Data != nil {\n\t\t\t\t\tbefore, callLoc, callData = b, loc, c\n\t\t\t\t\ts.Value = a\n\t\t\t\t\tafter = js_ast.Stmt{Loc: a.Loc, Data: s}\n\t\t\t\t}\n\n\t\t\tcase *js_ast.SIf:\n\t\t\t\tif b, loc, c, a := findFirstTopLevelSuperCall(s.Test, superCtorRef); c != nil && a.Data != nil {\n\t\t\t\t\tbefore, callLoc, callData = b, loc, c\n\t\t\t\t\ts.Test = a\n\t\t\t\t\tafter = js_ast.Stmt{Loc: a.Loc, Data: s}\n\t\t\t\t}\n\n\t\t\tcase *js_ast.SSwitch:\n\t\t\t\tif b, loc, c, a := findFirstTopLevelSuperCall(s.Test, superCtorRef); c != nil && a.Data != nil {\n\t\t\t\t\tbefore, callLoc, callData = b, loc, c\n\t\t\t\t\ts.Test = a\n\t\t\t\t\tafter = js_ast.Stmt{Loc: a.Loc, Data: s}\n\t\t\t\t}\n\n\t\t\tcase *js_ast.SFor:\n\t\t\t\tif expr, ok := s.InitOrNil.Data.(*js_ast.SExpr); ok {\n\t\t\t\t\tif b, loc, c, a := findFirstTopLevelSuperCall(expr.Value, superCtorRef); c != nil {\n\t\t\t\t\t\tbefore, callLoc, callData = b, loc, c\n\t\t\t\t\t\tif a.Data != nil {\n\t\t\t\t\t\t\texpr.Value = a\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ts.InitOrNil.Data = nil\n\t\t\t\t\t\t}\n\t\t\t\t\t\tafter = js_ast.Stmt{Loc: a.Loc, Data: s}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif callData != nil {\n\t\t\t\t// Revert \"__super()\" back to \"super()\"\n\t\t\t\tcallData.Target.Data = js_ast.ESuperShared\n\t\t\t\tp.ignoreUsage(superCtorRef)\n\n\t\t\t\t// Inject \"stmtsToInsert\" after \"super()\"\n\t\t\t\tstmtsBefore := body.Block.Stmts[:i]\n\t\t\t\tstmtsAfter := body.Block.Stmts[i+1:]\n\t\t\t\tstmts := append([]js_ast.Stmt{}, stmtsBefore...)\n\t\t\t\tif before.Data != nil {\n\t\t\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: before.Loc, Data: &js_ast.SExpr{Value: before}})\n\t\t\t\t}\n\t\t\t\tstmts = append(stmts, js_ast.Stmt{Loc: callLoc, Data: &js_ast.SExpr{Value: js_ast.Expr{Loc: callLoc, Data: callData}}})\n\t\t\t\tstmts = append(stmts, stmtsToInsert...)\n\t\t\t\tif after.Data != nil {\n\t\t\t\t\tstmts = append(stmts, after)\n\t\t\t\t}\n\t\t\t\tstmts = append(stmts, stmtsAfter...)\n\t\t\t\tbody.Block.Stmts = stmts\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Otherwise, inject a generated \"__super\" helper function at the top of the\n\t// constructor that looks like this:\n\t//\n\t//   var __super = (...args) => {\n\t//     super(...args);\n\t//     ...stmtsToInsert...\n\t//     return this;\n\t//   };\n\t//\n\targsRef := p.newSymbol(ast.SymbolOther, \"args\")\n\tp.currentScope.Generated = append(p.currentScope.Generated, argsRef)\n\tp.recordUsage(argsRef)\n\tsuperCall := js_ast.Expr{Loc: body.Loc, Data: &js_ast.ECall{\n\t\tTarget: js_ast.Expr{Loc: body.Loc, Data: js_ast.ESuperShared},\n\t\tArgs:   []js_ast.Expr{{Loc: body.Loc, Data: &js_ast.ESpread{Value: js_ast.Expr{Loc: body.Loc, Data: &js_ast.EIdentifier{Ref: argsRef}}}}},\n\t}}\n\tstmtsToInsert = append(append(\n\t\t[]js_ast.Stmt{{Loc: body.Loc, Data: &js_ast.SExpr{Value: superCall}}},\n\t\tstmtsToInsert...),\n\t\tjs_ast.Stmt{Loc: body.Loc, Data: &js_ast.SReturn{ValueOrNil: js_ast.Expr{Loc: body.Loc, Data: js_ast.EThisShared}}},\n\t)\n\tif p.options.minifySyntax {\n\t\tstmtsToInsert = p.mangleStmts(stmtsToInsert, stmtsFnBody)\n\t}\n\tbody.Block.Stmts = append([]js_ast.Stmt{{Loc: body.Loc, Data: &js_ast.SLocal{Decls: []js_ast.Decl{{\n\t\tBinding: js_ast.Binding{Loc: body.Loc, Data: &js_ast.BIdentifier{Ref: superCtorRef}}, ValueOrNil: js_ast.Expr{Loc: body.Loc, Data: &js_ast.EArrow{\n\t\t\tHasRestArg: true,\n\t\t\tPreferExpr: true,\n\t\t\tArgs:       []js_ast.Arg{{Binding: js_ast.Binding{Loc: body.Loc, Data: &js_ast.BIdentifier{Ref: argsRef}}}},\n\t\t\tBody:       js_ast.FnBody{Loc: body.Loc, Block: js_ast.SBlock{Stmts: stmtsToInsert}},\n\t\t}},\n\t}}}}}, body.Block.Stmts...)\n}\n\nfunc findFirstTopLevelSuperCall(expr js_ast.Expr, superCtorRef ast.Ref) (js_ast.Expr, logger.Loc, *js_ast.ECall, js_ast.Expr) {\n\tif call, ok := expr.Data.(*js_ast.ECall); ok {\n\t\tif target, ok := call.Target.Data.(*js_ast.EIdentifier); ok && target.Ref == superCtorRef {\n\t\t\tcall.Target.Data = js_ast.ESuperShared\n\t\t\treturn js_ast.Expr{}, expr.Loc, call, js_ast.Expr{}\n\t\t}\n\t}\n\n\t// Also search down comma operator chains for a super call\n\tif comma, ok := expr.Data.(*js_ast.EBinary); ok && comma.Op == js_ast.BinOpComma {\n\t\tif before, loc, call, after := findFirstTopLevelSuperCall(comma.Left, superCtorRef); call != nil {\n\t\t\treturn before, loc, call, js_ast.JoinWithComma(after, comma.Right)\n\t\t}\n\n\t\tif before, loc, call, after := findFirstTopLevelSuperCall(comma.Right, superCtorRef); call != nil {\n\t\t\treturn js_ast.JoinWithComma(comma.Left, before), loc, call, after\n\t\t}\n\t}\n\n\treturn js_ast.Expr{}, logger.Loc{}, nil, js_ast.Expr{}\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/js_parser/sourcemap_parser.go",
    "content": "package js_parser\n\nimport (\n\t\"fmt\"\n\t\"net/url\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/evanw/esbuild/internal/ast\"\n\t\"github.com/evanw/esbuild/internal/helpers\"\n\t\"github.com/evanw/esbuild/internal/js_ast\"\n\t\"github.com/evanw/esbuild/internal/logger\"\n\t\"github.com/evanw/esbuild/internal/sourcemap\"\n)\n\n// New specification: https://tc39.es/ecma426/\n// Old specification: https://sourcemaps.info/spec.html\nfunc ParseSourceMap(log logger.Log, source logger.Source) *sourcemap.SourceMap {\n\texpr, ok := ParseJSON(log, source, JSONOptions{ErrorSuffix: \" in source map\"})\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tobj, ok := expr.Data.(*js_ast.EObject)\n\ttracker := logger.MakeLineColumnTracker(&source)\n\tif !ok {\n\t\tlog.AddError(&tracker, logger.Range{Loc: expr.Loc}, \"Invalid source map\")\n\t\treturn nil\n\t}\n\n\ttype sourceMapSection struct {\n\t\tlineOffset   int32\n\t\tcolumnOffset int32\n\t\tsourceMap    *js_ast.EObject\n\t}\n\n\tvar sections []sourceMapSection\n\thasSections := false\n\n\tfor _, prop := range obj.Properties {\n\t\tif !helpers.UTF16EqualsString(prop.Key.Data.(*js_ast.EString).Value, \"sections\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tif value, ok := prop.ValueOrNil.Data.(*js_ast.EArray); ok {\n\t\t\tfor _, item := range value.Items {\n\t\t\t\tif element, ok := item.Data.(*js_ast.EObject); ok {\n\t\t\t\t\tvar sectionLineOffset int32\n\t\t\t\t\tvar sectionColumnOffset int32\n\t\t\t\t\tvar sectionSourceMap *js_ast.EObject\n\n\t\t\t\t\tfor _, sectionProp := range element.Properties {\n\t\t\t\t\t\tswitch helpers.UTF16ToString(sectionProp.Key.Data.(*js_ast.EString).Value) {\n\t\t\t\t\t\tcase \"offset\":\n\t\t\t\t\t\t\tif offsetValue, ok := sectionProp.ValueOrNil.Data.(*js_ast.EObject); ok {\n\t\t\t\t\t\t\t\tfor _, offsetProp := range offsetValue.Properties {\n\t\t\t\t\t\t\t\t\tswitch helpers.UTF16ToString(offsetProp.Key.Data.(*js_ast.EString).Value) {\n\t\t\t\t\t\t\t\t\tcase \"line\":\n\t\t\t\t\t\t\t\t\t\tif lineValue, ok := offsetProp.ValueOrNil.Data.(*js_ast.ENumber); ok {\n\t\t\t\t\t\t\t\t\t\t\tsectionLineOffset = int32(lineValue.Value)\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tcase \"column\":\n\t\t\t\t\t\t\t\t\t\tif columnValue, ok := offsetProp.ValueOrNil.Data.(*js_ast.ENumber); ok {\n\t\t\t\t\t\t\t\t\t\t\tsectionColumnOffset = int32(columnValue.Value)\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tlog.AddError(&tracker, logger.Range{Loc: sectionProp.ValueOrNil.Loc}, \"Expected \\\"offset\\\" to be an object\")\n\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase \"map\":\n\t\t\t\t\t\t\tif mapValue, ok := sectionProp.ValueOrNil.Data.(*js_ast.EObject); ok {\n\t\t\t\t\t\t\t\tsectionSourceMap = mapValue\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tlog.AddError(&tracker, logger.Range{Loc: sectionProp.ValueOrNil.Loc}, \"Expected \\\"map\\\" to be an object\")\n\t\t\t\t\t\t\t\treturn nil\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif sectionSourceMap != nil {\n\t\t\t\t\t\tsections = append(sections, sourceMapSection{\n\t\t\t\t\t\t\tlineOffset:   sectionLineOffset,\n\t\t\t\t\t\t\tcolumnOffset: sectionColumnOffset,\n\t\t\t\t\t\t\tsourceMap:    sectionSourceMap,\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlog.AddError(&tracker, logger.Range{Loc: prop.ValueOrNil.Loc}, \"Expected \\\"sections\\\" to be an array\")\n\t\t\treturn nil\n\t\t}\n\n\t\thasSections = true\n\t\tbreak\n\t}\n\n\tif !hasSections {\n\t\tsections = append(sections, sourceMapSection{\n\t\t\tsourceMap: obj,\n\t\t})\n\t}\n\n\tvar sources []string\n\tvar sourcesContent []sourcemap.SourceContent\n\tvar names []string\n\tvar mappings mappingArray\n\tvar generatedLine int32\n\tvar generatedColumn int32\n\tneedSort := false\n\n\tfor _, section := range sections {\n\t\tvar sourcesArray []js_ast.Expr\n\t\tvar sourcesContentArray []js_ast.Expr\n\t\tvar namesArray []js_ast.Expr\n\t\tvar mappingsRaw []uint16\n\t\tvar mappingsStart int32\n\t\tvar sourceRoot string\n\t\thasVersion := false\n\n\t\tfor _, prop := range section.sourceMap.Properties {\n\t\t\tswitch helpers.UTF16ToString(prop.Key.Data.(*js_ast.EString).Value) {\n\t\t\tcase \"version\":\n\t\t\t\tif value, ok := prop.ValueOrNil.Data.(*js_ast.ENumber); ok && value.Value == 3 {\n\t\t\t\t\thasVersion = true\n\t\t\t\t}\n\n\t\t\tcase \"mappings\":\n\t\t\t\tif value, ok := prop.ValueOrNil.Data.(*js_ast.EString); ok {\n\t\t\t\t\tmappingsRaw = value.Value\n\t\t\t\t\tmappingsStart = prop.ValueOrNil.Loc.Start + 1\n\t\t\t\t}\n\n\t\t\tcase \"sourceRoot\":\n\t\t\t\tif value, ok := prop.ValueOrNil.Data.(*js_ast.EString); ok {\n\t\t\t\t\tsourceRoot = helpers.UTF16ToString(value.Value)\n\t\t\t\t}\n\n\t\t\tcase \"sources\":\n\t\t\t\tif value, ok := prop.ValueOrNil.Data.(*js_ast.EArray); ok {\n\t\t\t\t\tsourcesArray = value.Items\n\t\t\t\t}\n\n\t\t\tcase \"sourcesContent\":\n\t\t\t\tif value, ok := prop.ValueOrNil.Data.(*js_ast.EArray); ok {\n\t\t\t\t\tsourcesContentArray = value.Items\n\t\t\t\t}\n\n\t\t\tcase \"names\":\n\t\t\t\tif value, ok := prop.ValueOrNil.Data.(*js_ast.EArray); ok {\n\t\t\t\t\tnamesArray = value.Items\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Silently ignore the section if the version was missing or incorrect\n\t\tif !hasVersion {\n\t\t\tcontinue\n\t\t}\n\n\t\tmappingsLen := len(mappingsRaw)\n\t\tsourcesLen := len(sourcesArray)\n\t\tnamesLen := len(namesArray)\n\n\t\t// Silently ignore the section if the source map is pointless (i.e. empty)\n\t\tif mappingsLen == 0 || sourcesLen == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif section.lineOffset < generatedLine || (section.lineOffset == generatedLine && section.columnOffset < generatedColumn) {\n\t\t\tneedSort = true\n\t\t}\n\n\t\tlineOffset := section.lineOffset\n\t\tcolumnOffset := section.columnOffset\n\t\tsourceOffset := int32(len(sources))\n\t\tnameOffset := int32(len(names))\n\n\t\tgeneratedLine = lineOffset\n\t\tgeneratedColumn = columnOffset\n\t\tsourceIndex := sourceOffset\n\t\tvar originalLine int32\n\t\tvar originalColumn int32\n\t\toriginalName := nameOffset\n\n\t\tcurrent := 0\n\t\terrorText := \"\"\n\t\terrorLen := 0\n\n\t\t// Parse the mappings\n\t\tfor current < mappingsLen {\n\t\t\t// Handle a line break\n\t\t\tif mappingsRaw[current] == ';' {\n\t\t\t\tgeneratedLine++\n\t\t\t\tgeneratedColumn = 0\n\t\t\t\tcurrent++\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Read the generated column\n\t\t\tgeneratedColumnDelta, i, ok := sourcemap.DecodeVLQUTF16(mappingsRaw[current:])\n\t\t\tif !ok {\n\t\t\t\terrorText = \"Missing generated column\"\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif generatedColumnDelta < 0 {\n\t\t\t\t// This would mess up binary search\n\t\t\t\tneedSort = true\n\t\t\t}\n\t\t\tgeneratedColumn += generatedColumnDelta\n\t\t\tif (generatedLine == lineOffset && generatedColumn < columnOffset) || generatedColumn < 0 {\n\t\t\t\terrorText = fmt.Sprintf(\"Invalid generated column value: %d\", generatedColumn)\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrent += i\n\n\t\t\t// According to the specification, it's valid for a mapping to have 1,\n\t\t\t// 4, or 5 variable-length fields. Having one field means there's no\n\t\t\t// original location information, which is pretty useless. Just ignore\n\t\t\t// those entries.\n\t\t\tif current == mappingsLen {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tswitch mappingsRaw[current] {\n\t\t\tcase ',':\n\t\t\t\tcurrent++\n\t\t\t\tcontinue\n\t\t\tcase ';':\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Read the original source\n\t\t\tsourceIndexDelta, i, ok := sourcemap.DecodeVLQUTF16(mappingsRaw[current:])\n\t\t\tif !ok {\n\t\t\t\terrorText = \"Missing source index\"\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tsourceIndex += sourceIndexDelta\n\t\t\tif sourceIndex < sourceOffset || sourceIndex >= sourceOffset+int32(sourcesLen) {\n\t\t\t\terrorText = fmt.Sprintf(\"Invalid source index value: %d\", sourceIndex)\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrent += i\n\n\t\t\t// Read the original line\n\t\t\toriginalLineDelta, i, ok := sourcemap.DecodeVLQUTF16(mappingsRaw[current:])\n\t\t\tif !ok {\n\t\t\t\terrorText = \"Missing original line\"\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\toriginalLine += originalLineDelta\n\t\t\tif originalLine < 0 {\n\t\t\t\terrorText = fmt.Sprintf(\"Invalid original line value: %d\", originalLine)\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrent += i\n\n\t\t\t// Read the original column\n\t\t\toriginalColumnDelta, i, ok := sourcemap.DecodeVLQUTF16(mappingsRaw[current:])\n\t\t\tif !ok {\n\t\t\t\terrorText = \"Missing original column\"\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\toriginalColumn += originalColumnDelta\n\t\t\tif originalColumn < 0 {\n\t\t\t\terrorText = fmt.Sprintf(\"Invalid original column value: %d\", originalColumn)\n\t\t\t\terrorLen = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcurrent += i\n\n\t\t\t// Read the original name\n\t\t\tvar optionalName ast.Index32\n\t\t\tif originalNameDelta, i, ok := sourcemap.DecodeVLQUTF16(mappingsRaw[current:]); ok {\n\t\t\t\toriginalName += originalNameDelta\n\t\t\t\tif originalName < nameOffset || originalName >= nameOffset+int32(namesLen) {\n\t\t\t\t\terrorText = fmt.Sprintf(\"Invalid name index value: %d\", originalName)\n\t\t\t\t\terrorLen = i\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\toptionalName = ast.MakeIndex32(uint32(originalName))\n\t\t\t\tcurrent += i\n\t\t\t}\n\n\t\t\t// Handle the next character\n\t\t\tif current < mappingsLen {\n\t\t\t\tif c := mappingsRaw[current]; c == ',' {\n\t\t\t\t\tcurrent++\n\t\t\t\t} else if c != ';' {\n\t\t\t\t\terrorText = fmt.Sprintf(\"Invalid character after mapping: %q\",\n\t\t\t\t\t\thelpers.UTF16ToString(mappingsRaw[current:current+1]))\n\t\t\t\t\terrorLen = 1\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmappings = append(mappings, sourcemap.Mapping{\n\t\t\t\tGeneratedLine:   generatedLine,\n\t\t\t\tGeneratedColumn: generatedColumn,\n\t\t\t\tSourceIndex:     sourceIndex,\n\t\t\t\tOriginalLine:    originalLine,\n\t\t\t\tOriginalColumn:  originalColumn,\n\t\t\t\tOriginalName:    optionalName,\n\t\t\t})\n\t\t}\n\n\t\tif errorText != \"\" {\n\t\t\tr := logger.Range{Loc: logger.Loc{Start: mappingsStart + int32(current)}, Len: int32(errorLen)}\n\t\t\tlog.AddID(logger.MsgID_SourceMap_InvalidSourceMappings, logger.Warning, &tracker, r,\n\t\t\t\tfmt.Sprintf(\"Bad \\\"mappings\\\" data in source map at character %d: %s\", current, errorText))\n\t\t\treturn nil\n\t\t}\n\n\t\t// Try resolving relative source URLs into absolute source URLs.\n\t\t// See https://tc39.es/ecma426/#resolving-sources for details.\n\t\tvar sourceURLPrefix string\n\t\tvar baseURL *url.URL\n\t\tif sourceRoot != \"\" {\n\t\t\tif index := strings.LastIndexByte(sourceRoot, '/'); index != -1 {\n\t\t\t\tsourceURLPrefix = sourceRoot[:index+1]\n\t\t\t} else {\n\t\t\t\tsourceURLPrefix = sourceRoot + \"/\"\n\t\t\t}\n\t\t}\n\t\tif source.KeyPath.Namespace == \"file\" {\n\t\t\tbaseURL = helpers.FileURLFromFilePath(source.KeyPath.Text)\n\t\t}\n\n\t\tfor _, item := range sourcesArray {\n\t\t\tif element, ok := item.Data.(*js_ast.EString); ok {\n\t\t\t\tsourcePath := sourceURLPrefix + helpers.UTF16ToString(element.Value)\n\t\t\t\tsourceURL, err := url.Parse(sourcePath)\n\n\t\t\t\t// Ignore URL parse errors (such as \"%XY\" being an invalid escape)\n\t\t\t\tif err != nil {\n\t\t\t\t\tsources = append(sources, sourcePath)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\t// Resolve this URL relative to the enclosing directory\n\t\t\t\tif baseURL != nil {\n\t\t\t\t\tsourceURL = baseURL.ResolveReference(sourceURL)\n\t\t\t\t}\n\t\t\t\tsources = append(sources, sourceURL.String())\n\t\t\t} else {\n\t\t\t\tsources = append(sources, \"\")\n\t\t\t}\n\t\t}\n\n\t\tif len(sourcesContentArray) > 0 {\n\t\t\t// It's possible that one of the source maps inside \"sections\" has\n\t\t\t// different lengths for the \"sources\" and \"sourcesContent\" arrays.\n\t\t\t// This is bad because we need to us a single index to get the name\n\t\t\t// of the source from \"sources[i]\" and the content of the source\n\t\t\t// from \"sourcesContent[i]\".\n\t\t\t//\n\t\t\t// So if a previous source map had a shorter \"sourcesContent\" array\n\t\t\t// than its \"sources\" array (or if the previous source map just had\n\t\t\t// no \"sourcesContent\" array), expand our aggregated array to the\n\t\t\t// right length by padding it out with empty entries.\n\t\t\tsourcesContent = append(sourcesContent, make([]sourcemap.SourceContent, int(sourceOffset)-len(sourcesContent))...)\n\n\t\t\tfor i, item := range sourcesContentArray {\n\t\t\t\t// Make sure we don't ever record more \"sourcesContent\" entries\n\t\t\t\t// than there are \"sources\" entries, which is possible because\n\t\t\t\t// these are two separate arrays in the source map JSON. We need\n\t\t\t\t// to avoid this because that would mess up our shared indexing\n\t\t\t\t// of the \"sources\" and \"sourcesContent\" arrays. See the above\n\t\t\t\t// comment for more details.\n\t\t\t\tif i == sourcesLen {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif element, ok := item.Data.(*js_ast.EString); ok {\n\t\t\t\t\tsourcesContent = append(sourcesContent, sourcemap.SourceContent{\n\t\t\t\t\t\tValue:  element.Value,\n\t\t\t\t\t\tQuoted: source.TextForRange(source.RangeOfString(item.Loc)),\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tsourcesContent = append(sourcesContent, sourcemap.SourceContent{})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor _, item := range namesArray {\n\t\t\tif element, ok := item.Data.(*js_ast.EString); ok {\n\t\t\t\tnames = append(names, helpers.UTF16ToString(element.Value))\n\t\t\t} else {\n\t\t\t\tnames = append(names, \"\")\n\t\t\t}\n\t\t}\n\t}\n\n\t// Silently fail if the source map is pointless (i.e. empty)\n\tif len(sources) == 0 || len(mappings) == 0 {\n\t\treturn nil\n\t}\n\n\tif needSort {\n\t\t// If we get here, some mappings are out of order. Lines can't be out of\n\t\t// order by construction but columns can. This is a pretty rare situation\n\t\t// because almost all source map generators always write out mappings in\n\t\t// order as they write the output instead of scrambling the order.\n\t\tsort.Stable(mappings)\n\t}\n\n\treturn &sourcemap.SourceMap{\n\t\tSources:        sources,\n\t\tSourcesContent: sourcesContent,\n\t\tMappings:       mappings,\n\t\tNames:          names,\n\t}\n}\n\n// This type is just so we can use Go's native sort function\ntype mappingArray []sourcemap.Mapping\n\nfunc (a mappingArray) Len() int          { return len(a) }\nfunc (a mappingArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }\n\nfunc (a mappingArray) Less(i int, j int) bool {\n\tai := a[i]\n\taj := a[j]\n\treturn ai.GeneratedLine < aj.GeneratedLine || (ai.GeneratedLine == aj.GeneratedLine && ai.GeneratedColumn <= aj.GeneratedColumn)\n}\n"
  },
  {
    "path": "vendor/github.com/evanw/esbuild/internal/logger/logger.go",
    "content": "package logger\n\n// Logging is either done to stderr (via \"NewStderrLog\") or to an in-memory\n// array (via \"NewDeferLog\"). In-memory arrays are used to capture messages\n// from parsing individual files because during incremental builds, log\n// messages for a given file can be replayed from memory if the file ends up\n// not being reparsed.\n//\n// Errors are streamed asynchronously as they happen, each error contains the\n// contents of the line with the error, and the error count is limited by\n// default.\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\t\"unicode/utf8\"\n)\n\nconst defaultTerminalWidth = 80\n\ntype Log struct {\n\tAddMsg    func(Msg)\n\tHasErrors func() bool\n\tPeek      func() []Msg\n\n\tDone func() []Msg\n\n\tLevel     LogLevel\n\tOverrides map[MsgID]LogLevel\n}\n\ntype LogLevel int8\n\nconst (\n\tLevelNone LogLevel = iota\n\tLevelVerbose\n\tLevelDebug\n\tLevelInfo\n\tLevelWarning\n\tLevelError\n\tLevelSilent\n)\n\ntype MsgKind uint8\n\nconst (\n\tError MsgKind = iota\n\tWarning\n\tInfo\n\tNote\n\tDebug\n\tVerbose\n)\n\nfunc (kind MsgKind) String() string {\n\tswitch kind {\n\tcase Error:\n\t\treturn \"ERROR\"\n\tcase Warning:\n\t\treturn \"WARNING\"\n\tcase Info:\n\t\treturn \"INFO\"\n\tcase Note:\n\t\treturn \"NOTE\"\n\tcase Debug:\n\t\treturn \"DEBUG\"\n\tcase Verbose:\n\t\treturn \"VERBOSE\"\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\nfunc (kind MsgKind) Icon() string {\n\t// Special-case Windows command prompt, which only supports a few characters\n\tif isProbablyWindowsCommandPrompt() {\n\t\tswitch kind {\n\t\tcase Error:\n\t\t\treturn \"X\"\n\t\tcase Warning:\n\t\t\treturn \"▲\"\n\t\tcase Info:\n\t\t\treturn \"►\"\n\t\tcase Note:\n\t\t\treturn \"→\"\n\t\tcase Debug:\n\t\t\treturn \"●\"\n\t\tcase Verbose:\n\t\t\treturn \"♦\"\n\t\tdefault:\n\t\t\tpanic(\"Internal error\")\n\t\t}\n\t}\n\n\tswitch kind {\n\tcase Error:\n\t\treturn \"✘\"\n\tcase Warning:\n\t\treturn \"▲\"\n\tcase Info:\n\t\treturn \"▶\"\n\tcase Note:\n\t\treturn \"→\"\n\tcase Debug:\n\t\treturn \"●\"\n\tcase Verbose:\n\t\treturn \"⬥\"\n\tdefault:\n\t\tpanic(\"Internal error\")\n\t}\n}\n\nvar windowsCommandPrompt struct {\n\tmutex         sync.Mutex\n\tonce          bool\n\tisProbablyCMD bool\n}\n\nfunc isProbablyWindowsCommandPrompt() bool {\n\twindowsCommandPrompt.mutex.Lock()\n\tdefer windowsCommandPrompt.mutex.Unlock()\n\n\tif !windowsCommandPrompt.once {\n\t\twindowsCommandPrompt.once = true\n\n\t\t// Assume we are running in Windows Command Prompt if we're on Windows. If\n\t\t// so, we can't use emoji because it won't be supported. Except we can\n\t\t// still use emoji if the WT_SESSION environment variable is present\n\t\t// because that means we're running in the new Windows Terminal instead.\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\twindowsCommandPrompt.isProbablyCMD = true\n\t\t\tif _, ok := os.LookupEnv(\"WT_SESSION\"); ok {\n\t\t\t\twindowsCommandPrompt.isProbablyCMD = false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn windowsCommandPrompt.isProbablyCMD\n}\n\ntype Msg struct {\n\tNotes      []MsgData\n\tPluginName string\n\tData       MsgData\n\tKind       MsgKind\n\tID         MsgID\n}\n\ntype MsgData struct {\n\t// Optional user-specified data that is passed through unmodified\n\tUserDetail interface{}\n\n\tLocation *MsgLocation\n\tText     string\n\n\tDisableMaximumWidth bool\n}\n\ntype MsgLocation struct {\n\tFile       PrettyPaths\n\tNamespace  string\n\tLineText   string\n\tSuggestion string\n\tLine       int // 1-based\n\tColumn     int // 0-based, in bytes\n\tLength     int // in bytes\n}\n\ntype Loc struct {\n\t// This is the 0-based index of this location from the start of the file, in bytes\n\tStart int32\n}\n\ntype Range struct {\n\tLoc Loc\n\tLen int32\n}\n\nfunc (r Range) End() int32 {\n\treturn r.Loc.Start + r.Len\n}\n\nfunc (a *Range) ExpandBy(b Range) {\n\tif a.Len == 0 {\n\t\t*a = b\n\t} else {\n\t\tend := a.End()\n\t\tif n := b.End(); n > end {\n\t\t\tend = n\n\t\t}\n\t\tif b.Loc.Start < a.Loc.Start {\n\t\t\ta.Loc.Start = b.Loc.Start\n\t\t}\n\t\ta.Len = end - a.Loc.Start\n\t}\n}\n\ntype Span struct {\n\tText  string\n\tRange Range\n}\n\n// This type is just so we can use Go's native sort function\ntype SortableMsgs []Msg\n\nfunc (a SortableMsgs) Len() int          { return len(a) }\nfunc (a SortableMsgs) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }\n\nfunc (a SortableMsgs) Less(i int, j int) bool {\n\tai := a[i]\n\taj := a[j]\n\taiLoc := ai.Data.Location\n\tajLoc := aj.Data.Location\n\tif aiLoc == nil || ajLoc == nil {\n\t\treturn aiLoc == nil && ajLoc != nil\n\t}\n\tif aiLoc.File != ajLoc.File {\n\t\treturn aiLoc.File.Abs < ajLoc.File.Abs || (aiLoc.File.Abs == ajLoc.File.Abs && aiLoc.File.Rel < ajLoc.File.Rel)\n\t}\n\tif aiLoc.Line != ajLoc.Line {\n\t\treturn aiLoc.Line < ajLoc.Line\n\t}\n\tif aiLoc.Column != ajLoc.Column {\n\t\treturn aiLoc.Column < ajLoc.Column\n\t}\n\tif ai.Kind != aj.Kind {\n\t\treturn ai.Kind < aj.Kind\n\t}\n\treturn ai.Data.Text < aj.Data.Text\n}\n\n// This is used to represent both file system paths (Namespace == \"file\") and\n// abstract module paths (Namespace != \"file\"). Abstract module paths represent\n// \"virtual modules\" when used for an input file and \"package paths\" when used\n// to represent an external module.\ntype Path struct {\n\tText      string\n\tNamespace string\n\n\t// This feature was added to support ancient CSS libraries that append things\n\t// like \"?#iefix\" and \"#icons\" to some of their import paths as a hack for IE6.\n\t// The intent is for these suffix parts to be ignored but passed through to\n\t// the output. This is supported by other bundlers, so we also support this.\n\tIgnoredSuffix string\n\n\t// Import attributes (the \"with\" keyword after an import) can affect path\n\t// resolution. In other words, two paths in the same file that are otherwise\n\t// equal but that have different import attributes may resolve to different\n\t// paths.\n\tImportAttributes ImportAttributes\n\n\tFlags PathFlags\n}\n\n// We rely on paths as map keys. Go doesn't support custom hash codes and\n// only implements hash codes for certain types. In particular, hash codes\n// are implemented for strings but not for arrays of strings. So we have to\n// pack these import attributes into a string.\ntype ImportAttributes struct {\n\tpackedData string\n}\n\ntype ImportAttribute struct {\n\tKey   string\n\tValue string\n}\n\n// This returns a sorted array instead of a map to make determinism easier\nfunc (attrs ImportAttributes) DecodeIntoArray() (result []ImportAttribute) {\n\tif attrs.packedData == \"\" {\n\t\treturn nil\n\t}\n\tbytes := []byte(attrs.packedData)\n\tfor len(bytes) > 0 {\n\t\tkn := 4 + binary.LittleEndian.Uint32(bytes[:4])\n\t\tk := string(bytes[4:kn])\n\t\tbytes = bytes[kn:]\n\t\tvn := 4 + binary.LittleEndian.Uint32(bytes[:4])\n\t\tv := string(bytes[4:vn])\n\t\tbytes = bytes[vn:]\n\t\tresult = append(result, ImportAttribute{Key: k, Value: v})\n\t}\n\treturn result\n}\n\nfunc (attrs ImportAttributes) DecodeIntoMap() (result map[string]string) {\n\tif array := attrs.DecodeIntoArray(); len(array) > 0 {\n\t\tresult = make(map[string]string, len(array))\n\t\tfor _, attr := range array {\n\t\t\tresult[attr.Key] = attr.Value\n\t\t}\n\t}\n\treturn\n}\n\nfunc EncodeImportAttributes(value map[string]string) ImportAttributes {\n\tif len(value) == 0 {\n\t\treturn ImportAttributes{}\n\t}\n\tkeys := make([]string, 0, len(value))\n\tfor k := range value {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Strings(keys)\n\tvar sb strings.Builder\n\tvar n [4]byte\n\tfor _, k := range keys {\n\t\tv := value[k]\n\t\tbinary.LittleEndian.PutUint32(n[:], uint32(len(k)))\n\t\tsb.Write(n[:])\n\t\tsb.WriteString(k)\n\t\tbinary.LittleEndian.PutUint32(n[:], uint32(len(v)))\n\t\tsb.Write(n[:])\n\t\tsb.WriteString(v)\n\t}\n\treturn ImportAttributes{packedData: sb.String()}\n}\n\ntype PathFlags uint8\n\nconst (\n\t// This corresponds to a value of \"false' in the \"browser\" package.json field\n\tPathDisabled PathFlags = 1 << iota\n)\n\nfunc (p Path) IsDisabled() bool {\n\treturn (p.Flags & PathDisabled) != 0\n}\n\nvar noColorResult bool\nvar noColorOnce sync.Once\n\nfunc hasNoColorEnvironmentVariable() bool {\n\tnoColorOnce.Do(func() {\n\t\t// Read \"NO_COLOR\" from the environment. This is a convention that some\n\t\t// software follows. See https://no-color.org/ for more information.\n\t\tif _, ok := os.LookupEnv(\"NO_COLOR\"); ok {\n\t\t\tnoColorResult = true\n\t\t}\n\t})\n\treturn noColorResult\n}\n\n// This has a custom implementation instead of using \"filepath.Dir/Base/Ext\"\n// because it should work the same on Unix and Windows. These names end up in\n// the generated output and the generated output should not depend on the OS.\nfunc PlatformIndependentPathDirBaseExt(path string) (dir string, base string, ext string) {\n\tabsRootSlash := -1\n\n\t// Make sure we don't strip off the slash for the root of the file system\n\tif len(path) > 0 && (path[0] == '/' || path[0] == '\\\\') {\n\t\tabsRootSlash = 0 // Unix\n\t} else if len(path) > 2 && path[1] == ':' && (path[2] == '/' || path[2] == '\\\\') {\n\t\tif c := path[0]; (c >= 'a' && c < 'z') || (c >= 'A' && c <= 'Z') {\n\t\t\tabsRootSlash = 2 // Windows\n\t\t}\n\t}\n\n\tfor {\n\t\ti := strings.LastIndexAny(path, \"/\\\\\")\n\n\t\t// Stop if there are no more slashes\n\t\tif i < 0 {\n\t\t\tbase = path\n\t\t\tbreak\n\t\t}\n\n\t\t// Stop if we found a non-trailing slash\n\t\tif i == absRootSlash {\n\t\t\tdir, base = path[:i+1], path[i+1:]\n\t\t\tbreak\n\t\t}\n\t\tif i+1 != len(path) {\n\t\t\tdir, base = path[:i], path[i+1:]\n\t\t\tbreak\n\t\t}\n\n\t\t// Ignore trailing slashes\n\t\tpath = path[:i]\n\t}\n\n\t// Strip off the extension\n\tif dot := strings.LastIndexByte(base, '.'); dot >= 0 {\n\t\text = base[dot:]\n\n\t\t// We default to the \"local-css\" loader for \".module.css\" files. Make sure\n\t\t// the string names generated by this don't all have \"_module_\" in them.\n\t\tif ext == \".css\" {\n\t\t\tif dot2 := strings.LastIndexByte(base[:dot], '.'); dot2 >= 0 && base[dot2:] == \".module.css\" {\n\t\t\t\tdot = dot2\n\t\t\t\text = base[dot:]\n\t\t\t}\n\t\t}\n\n\t\tbase = base[:dot]\n\t}\n\treturn\n}\n\ntype PrettyPaths struct {\n\t// This option exists to help people that run esbuild in many different\n\t// directories and want a unified way of reporting file paths. It avoids\n\t// needing to code to convert from relative paths back to absolute paths\n\t// to find the original file. It means builds are not reproducible across\n\t// machines, however.\n\tAbs string\n\n\t// This is a mostly platform-independent path. It's relative to the current\n\t// working directory and always uses standard path separators. This is the\n\t// default behavior since it leads to reproducible builds across machines.\n\t//\n\t// Note that these paths still use the original case of the path, so they may\n\t// still work differently on file systems that are case-insensitive vs.\n\t// case-sensitive.\n\tRel string\n}\n\ntype PathStyle uint8\n\nconst (\n\tRelPath PathStyle = iota\n\tAbsPath\n)\n\nfunc (paths *PrettyPaths) Select(style PathStyle) string {\n\tif style == AbsPath {\n\t\treturn paths.Abs\n\t}\n\treturn paths.Rel\n}\n\ntype Source struct {\n\t// This is used for error messages and the metadata JSON file.\n\tPrettyPaths PrettyPaths\n\n\t// An identifier that is mixed in to automatically-generated symbol names to\n\t// improve readability. For example, if the identifier is \"util\" then the\n\t// symbol for an \"export default\" statement will be called \"util_default\".\n\tIdentifierName string\n\n\tContents string\n\n\t// This is used as a unique key to identify this source file. It should never\n\t// be shown to the user (e.g. never print this to the terminal).\n\t//\n\t// If it's marked as an absolute path, it's a platform-dependent path that\n\t// includes environment-specific things such as Windows backslash path\n\t// separators and potentially the user's home directory. Only use this for\n\t// passing to syscalls for reading and writing to the file system. Do not\n\t// include this in any output data.\n\t//\n\t// If it's marked as not an absolute path, it's an opaque string that is used\n\t// to refer to an automatically-generated module.\n\tKeyPath Path\n\n\tIndex uint32\n}\n\nfunc (s *Source) TextForRange(r Range) string {\n\treturn s.Contents[r.Loc.Start : r.Loc.Start+r.Len]\n}\n\nfunc (s *Source) LocBeforeWhitespace(loc Loc) Loc {\n\tfor loc.Start > 0 {\n\t\tc, width := utf8.DecodeLastRuneInString(s.Contents[:loc.Start])\n\t\tif c != ' ' && c != '\\t' && c != '\\r' && c != '\\n' {\n\t\t\tbreak\n\t\t}\n\t\tloc.Start -= int32(width)\n\t}\n\treturn loc\n}\n\nfunc (s *Source) RangeOfOperatorBefore(loc Loc, op string) Range {\n\ttext := s.Contents[:loc.Start]\n\tindex := strings.LastIndex(text, op)\n\tif index >= 0 {\n\t\treturn Range{Loc: Loc{Start: int32(index)}, Len: int32(len(op))}\n\t}\n\treturn Range{Loc: loc}\n}\n\nfunc (s *Source) RangeOfOperatorAfter(loc Loc, op string) Range {\n\ttext := s.Contents[loc.Start:]\n\tindex := strings.Index(text, op)\n\tif index >= 0 {\n\t\treturn Range{Loc: Loc{Start: loc.Start + int32(index)}, Len: int32(len(op))}\n\t}\n\treturn Range{Loc: loc}\n}\n\nfunc (s *Source) RangeOfString(loc Loc) Range {\n\ttext := s.Contents[loc.Start:]\n\tif len(text) == 0 {\n\t\treturn Range{Loc: loc, Len: 0}\n\t}\n\n\tquote := text[0]\n\tif quote == '\"' || quote == '\\'' {\n\t\t// Search for the matching quote character\n\t\tfor i := 1; i < len(text); i++ {\n\t\t\tc := text[i]\n\t\t\tif c == quote {\n\t\t\t\treturn Range{Loc: loc, Len: int32(i + 1)}\n\t\t\t} else if c == '\\\\' {\n\t\t\t\ti += 1\n\t\t\t}\n\t\t}\n\t}\n\n\tif quote == '`' {\n\t\t// Search for the matching quote character\n\t\tfor i := 1; i < len(text); i++ {\n\t\t\tc := text[i]\n\t\t\tif c == quote {\n\t\t\t\treturn Range{Loc: loc, Len: int32(i + 1)}\n\t\t\t} else if c == '\\\\' {\n\t\t\t\ti += 1\n\t\t\t} else if c == '$' && i+1 < len(text) && text[i+1] == '{' {\n\t\t\t\tbreak // Only return the range for no-substitution template literals\n\t\t\t}\n\t\t}\n\t}\n\n\treturn Range{Loc: loc, Len: 0}\n}\n\nfunc (s *Source) RangeOfNumber(loc Loc) (r Range) {\n\ttext := s.Contents[loc.Start:]\n\tr = Range{Loc: loc, Len: 0}\n\n\tif len(text) > 0 {\n\t\tif c := text[0]; c >= '0' && c <= '9' {\n\t\t\tr.Len = 1\n\t\t\tfor int(r.Len) < len(text) {\n\t\t\t\tc := text[r.Len]\n\t\t\t\tif (c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '.' && c != '_' {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tr.Len++\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\nfunc (s *Source) RangeOfLegacyOctalEscape(loc Loc) (r Range) {\n\ttext := s.Contents[loc.Start:]\n\tr = Range{Loc: loc, Len: 0}\n\n\tif len(text) >= 2 && text[0] == '\\\\' {\n\t\tr.Len = 2\n\t\tfor r.Len < 4 && int(r.Len) < len(text) {\n\t\t\tc := text[r.Len]\n\t\t\tif c < '0' || c > '9' {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tr.Len++\n\t\t}\n\t}\n\treturn\n}\n\nfunc (s *Source) CommentTextWithoutIndent(r Range) string {\n\ttext := s.Contents[r.Loc.Start:r.End()]\n\tif len(text) < 2 || !strings.HasPrefix(text, \"/*\") {\n\t\treturn text\n\t}\n\tprefix := s.Contents[:r.Loc.Start]\n\n\t// Figure out the initial indent\n\tindent := 0\nseekBackwardToNewline:\n\tfor len(prefix) > 0 {\n\t\tc, size := utf8.DecodeLastRuneInString(prefix)\n\t\tswitch c {\n\t\tcase '\\r', '\\n', '\\u2028', '\\u2029':\n\t\t\tbreak seekBackwardToNewline\n\t\t}\n\t\tprefix = prefix[:len(prefix)-size]\n\t\tindent++\n\t}\n\n\t// Split the comment into lines\n\tvar lines []string\n\tstart := 0\n\tfor i, c := range text {\n\t\tswitch c {\n\t\tcase '\\r', '\\n':\n\t\t\t// Don't double-append for Windows style \"\\r\\n\" newlines\n\t\t\tif start <= i {\n\t\t\t\tlines = append(lines, text[start:i])\n\t\t\t}\n\n\t\t\tstart = i + 1\n\n\t\t\t// Ignore the second part of Windows style \"\\r\\n\" newlines\n\t\t\tif c == '\\r' && start < len(text) && text[start] == '\\n' {\n\t\t\t\tstart++\n\t\t\t}\n\n\t\tcase '\\u2028', '\\u2029':\n\t\t\tlines = append(lines, text[start:i])\n\t\t\tstart = i + 3\n\t\t}\n\t}\n\tlines = append(lines, text[start:])\n\n\t// Find the minimum indent over all lines after the first line\n\tfor _, line := range lines[1:] {\n\t\tlineIndent := 0\n\t\tfor _, c := range line {\n\t\t\tif c != ' ' && c != '\\t' {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tlineIndent++\n\t\t}\n\t\tif indent > lineIndent {\n\t\t\tindent = lineIndent\n\t\t}\n\t}\n\n\t// Trim the indent off of all lines after the first line\n\tfor i, line := range lines {\n\t\tif i > 0 {\n\t\t\tlines[i] = line[indent:]\n\t\t}\n\t}\n\treturn strings.Join(lines, \"\\n\")\n}\n\nfunc plural(prefix string, count int, shown int, someAreMissing bool) string {\n\tvar text string\n\tif count == 1 {\n\t\ttext = fmt.Sprintf(\"%d %s\", count, prefix)\n\t} else {\n\t\ttext = fmt.Sprintf(\"%d %ss\", count, prefix)\n\t}\n\tif shown < count {\n\t\ttext = fmt.Sprintf(\"%d of %s\", shown, text)\n\t} else if someAreMissing && count > 1 {\n\t\ttext = \"all \" + text\n\t}\n\treturn text\n}\n\nfunc errorAndWarningSummary(errors int, warnings int, shownErrors int, shownWarnings int) string {\n\tsomeAreMissing := shownWarnings < warnings || shownErrors < errors\n\tswitch {\n\tcase errors == 0:\n\t\treturn plural(\"warning\", warnings, shownWarnings, someAreMissing)\n\tcase warnings == 0:\n\t\treturn plural(\"error\", errors, shownErrors, someAreMissing)\n\tdefault:\n\t\treturn fmt.Sprintf(\"%s and %s\",\n\t\t\tplural(\"warning\", warnings, shownWarnings, someAreMissing),\n\t\t\tplural(\"error\", errors, shownErrors, someAreMissing))\n\t}\n}\n\ntype APIKind uint8\n\nconst (\n\tGoAPI APIKind = iota\n\tCLIAPI\n\tJSAPI\n)\n\n// This can be used to customize error messages for the current API kind\nvar API APIKind\n\ntype TerminalInfo struct {\n\tIsTTY           bool\n\tUseColorEscapes bool\n\tWidth           int\n\tHeight          int\n}\n\nfunc NewStderrLog(options OutputOptions) Log {\n\tvar mutex sync.Mutex\n\tvar msgs SortableMsgs\n\tterminalInfo := GetTerminalInfo(os.Stderr)\n\terrors := 0\n\twarnings := 0\n\tshownErrors := 0\n\tshownWarnings := 0\n\thasErrors := false\n\tremainingMessagesBeforeLimit := options.MessageLimit\n\tif remainingMessagesBeforeLimit == 0 {\n\t\tremainingMessagesBeforeLimit = 0x7FFFFFFF\n\t}\n\tvar deferredWarnings []Msg\n\n\tfinalizeLog := func() {\n\t\t// Print the deferred warning now if there was no error after all\n\t\tfor remainingMessagesBeforeLimit > 0 && len(deferredWarnings) > 0 {\n\t\t\tshownWarnings++\n\t\t\twriteStringWithColor(os.Stderr, deferredWarnings[0].String(options, terminalInfo))\n\t\t\tdeferredWarnings = deferredWarnings[1:]\n\t\t\tremainingMessagesBeforeLimit--\n\t\t}\n\n\t\t// Print out a summary\n\t\tif options.MessageLimit > 0 && errors+warnings > options.MessageLimit {\n\t\t\twriteStringWithColor(os.Stderr, fmt.Sprintf(\"%s shown (disable the message limit with --log-limit=0)\\n\",\n\t\t\t\terrorAndWarningSummary(errors, warnings, shownErrors, shownWarnings)))\n\t\t} else if options.LogLevel <= LevelInfo && (warnings != 0 || errors != 0) {\n\t\t\twriteStringWithColor(os.Stderr, fmt.Sprintf(\"%s\\n\",\n\t\t\t\terrorAndWarningSummary(errors, warnings, shownErrors, shownWarnings)))\n\t\t}\n\t}\n\n\tswitch options.Color {\n\tcase ColorNever:\n\t\tterminalInfo.UseColorEscapes = false\n\tcase ColorAlways:\n\t\tterminalInfo.UseColorEscapes = SupportsColorEscapes\n\t}\n\n\treturn Log{\n\t\tLevel:     options.LogLevel,\n\t\tOverrides: options.Overrides,\n\n\t\tAddMsg: func(msg Msg) {\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\tmsgs = append(msgs, msg)\n\n\t\t\tswitch msg.Kind {\n\t\t\tcase Verbose:\n\t\t\t\tif options.LogLevel <= LevelVerbose {\n\t\t\t\t\twriteStringWithColor(os.Stderr, msg.String(options, terminalInfo))\n\t\t\t\t}\n\n\t\t\tcase Debug:\n\t\t\t\tif options.LogLevel <= LevelDebug {\n\t\t\t\t\twriteStringWithColor(os.Stderr, msg.String(options, terminalInfo))\n\t\t\t\t}\n\n\t\t\tcase Info:\n\t\t\t\tif options.LogLevel <= LevelInfo {\n\t\t\t\t\twriteStringWithColor(os.Stderr, msg.String(options, terminalInfo))\n\t\t\t\t}\n\n\t\t\tcase Error:\n\t\t\t\thasErrors = true\n\t\t\t\tif options.LogLevel <= LevelError {\n\t\t\t\t\terrors++\n\t\t\t\t}\n\n\t\t\tcase Warning:\n\t\t\t\tif options.LogLevel <= LevelWarning {\n\t\t\t\t\twarnings++\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Be silent if we're past the limit so we don't flood the terminal\n\t\t\tif remainingMessagesBeforeLimit == 0 {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tswitch msg.Kind {\n\t\t\tcase Error:\n\t\t\t\tif options.LogLevel <= LevelError {\n\t\t\t\t\tshownErrors++\n\t\t\t\t\twriteStringWithColor(os.Stderr, msg.String(options, terminalInfo))\n\t\t\t\t\tremainingMessagesBeforeLimit--\n\t\t\t\t}\n\n\t\t\tcase Warning:\n\t\t\t\tif options.LogLevel <= LevelWarning {\n\t\t\t\t\tif remainingMessagesBeforeLimit > (options.MessageLimit+1)/2 {\n\t\t\t\t\t\tshownWarnings++\n\t\t\t\t\t\twriteStringWithColor(os.Stderr, msg.String(options, terminalInfo))\n\t\t\t\t\t\tremainingMessagesBeforeLimit--\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If we have less than half of the slots left, wait for potential\n\t\t\t\t\t\t// future errors instead of using up all of the slots with warnings.\n\t\t\t\t\t\t// We want the log for a failed build to always have at least one\n\t\t\t\t\t\t// error in it.\n\t\t\t\t\t\tdeferredWarnings = append(deferredWarnings, msg)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tHasErrors: func() bool {\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\treturn hasErrors\n\t\t},\n\n\t\tPeek: func() []Msg {\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\tsort.Stable(msgs)\n\t\t\treturn append([]Msg{}, msgs...)\n\t\t},\n\n\t\tDone: func() []Msg {\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\tfinalizeLog()\n\t\t\tsort.Stable(msgs)\n\t\t\treturn msgs\n\t\t},\n\t}\n}\n\nfunc PrintErrorToStderr(osArgs []string, text string) {\n\tPrintMessageToStderr(osArgs, Msg{Kind: Error, Data: MsgData{Text: text}})\n}\n\nfunc PrintErrorWithNoteToStderr(osArgs []string, text string, note string) {\n\tmsg := Msg{\n\t\tKind: Error,\n\t\tData: MsgData{Text: text},\n\t}\n\tif note != \"\" {\n\t\tmsg.Notes = []MsgData{{Text: note}}\n\t}\n\tPrintMessageToStderr(osArgs, msg)\n}\n\nfunc OutputOptionsForArgs(osArgs []string) OutputOptions {\n\toptions := OutputOptions{IncludeSource: true}\n\n\t// Implement a mini argument parser so these options always work even if we\n\t// haven't yet gotten to the general-purpose argument parsing code\n\tfor _, arg := range osArgs {\n\t\tswitch arg {\n\t\tcase \"--color=false\":\n\t\t\toptions.Color = ColorNever\n\t\tcase \"--color=true\", \"--color\":\n\t\t\toptions.Color = ColorAlways\n\t\tcase \"--log-level=info\":\n\t\t\toptions.LogLevel = LevelInfo\n\t\tcase \"--log-level=warning\":\n\t\t\toptions.LogLevel = LevelWarning\n\t\tcase \"--log-level=error\":\n\t\t\toptions.LogLevel = LevelError\n\t\tcase \"--log-level=silent\":\n\t\t\toptions.LogLevel = LevelSilent\n\t\t}\n\t}\n\n\treturn options\n}\n\nfunc PrintMessageToStderr(osArgs []string, msg Msg) {\n\tlog := NewStderrLog(OutputOptionsForArgs(osArgs))\n\tlog.AddMsg(msg)\n\tlog.Done()\n}\n\ntype Colors struct {\n\tReset     string\n\tBold      string\n\tDim       string\n\tUnderline string\n\n\tRed   string\n\tGreen string\n\tBlue  string\n\n\tCyan    string\n\tMagenta string\n\tYellow  string\n\n\tRedBgRed     string\n\tRedBgWhite   string\n\tGreenBgGreen string\n\tGreenBgWhite string\n\tBlueBgBlue   string\n\tBlueBgWhite  string\n\n\tCyanBgCyan       string\n\tCyanBgBlack      string\n\tMagentaBgMagenta string\n\tMagentaBgBlack   string\n\tYellowBgYellow   string\n\tYellowBgBlack    string\n}\n\nvar TerminalColors = Colors{\n\tReset:     \"\\033[0m\",\n\tBold:      \"\\033[1m\",\n\tDim:       \"\\033[37m\",\n\tUnderline: \"\\033[4m\",\n\n\tRed:   \"\\033[31m\",\n\tGreen: \"\\033[32m\",\n\tBlue:  \"\\033[34m\",\n\n\tCyan:    \"\\033[36m\",\n\tMagenta: \"\\033[35m\",\n\tYellow:  \"\\033[33m\",\n\n\tRedBgRed:     \"\\033[41;31m\",\n\tRedBgWhite:   \"\\033[41;97m\",\n\tGreenBgGreen: \"\\033[42;32m\",\n\tGreenBgWhite: \"\\033[42;97m\",\n\tBlueBgBlue:   \"\\033[44;34m\",\n\tBlueBgWhite:  \"\\033[44;97m\",\n\n\tCyanBgCyan:       \"\\033[46;36m\",\n\tCyanBgBlack:      \"\\033[46;30m\",\n\tMagentaBgMagenta: \"\\033[45;35m\",\n\tMagentaBgBlack:   \"\\033[45;30m\",\n\tYellowBgYellow:   \"\\033[43;33m\",\n\tYellowBgBlack:    \"\\033[43;30m\",\n}\n\nfunc PrintText(file *os.File, level LogLevel, osArgs []string, callback func(Colors) string) {\n\toptions := OutputOptionsForArgs(osArgs)\n\n\t// Skip logging these if these logs are disabled\n\tif options.LogLevel > level {\n\t\treturn\n\t}\n\n\tPrintTextWithColor(file, options.Color, callback)\n}\n\nfunc PrintTextWithColor(file *os.File, useColor UseColor, callback func(Colors) string) {\n\tvar useColorEscapes bool\n\tswitch useColor {\n\tcase ColorNever:\n\t\tuseColorEscapes = false\n\tcase ColorAlways:\n\t\tuseColorEscapes = SupportsColorEscapes\n\tcase ColorIfTerminal:\n\t\tuseColorEscapes = GetTerminalInfo(file).UseColorEscapes\n\t}\n\n\tvar colors Colors\n\tif useColorEscapes {\n\t\tcolors = TerminalColors\n\t}\n\twriteStringWithColor(file, callback(colors))\n}\n\ntype SummaryTableEntry struct {\n\tDir         string\n\tBase        string\n\tSize        string\n\tBytes       int\n\tIsSourceMap bool\n}\n\n// This type is just so we can use Go's native sort function\ntype SummaryTable []SummaryTableEntry\n\nfunc (t SummaryTable) Len() int          { return len(t) }\nfunc (t SummaryTable) Swap(i int, j int) { t[i], t[j] = t[j], t[i] }\n\nfunc (t SummaryTable) Less(i int, j int) bool {\n\tti := t[i]\n\ttj := t[j]\n\n\t// Sort source maps last\n\tif !ti.IsSourceMap && tj.IsSourceMap {\n\t\treturn true\n\t}\n\tif ti.IsSourceMap && !tj.IsSourceMap {\n\t\treturn false\n\t}\n\n\t// Sort by size first\n\tif ti.Bytes > tj.Bytes {\n\t\treturn true\n\t}\n\tif ti.Bytes < tj.Bytes {\n\t\treturn false\n\t}\n\n\t// Sort alphabetically by directory first\n\tif ti.Dir < tj.Dir {\n\t\treturn true\n\t}\n\tif ti.Dir > tj.Dir {\n\t\treturn false\n\t}\n\n\t// Then sort alphabetically by file name\n\treturn ti.Base < tj.Base\n}\n\n// Show a warning icon next to output files that are 1mb or larger\nconst sizeWarningThreshold = 1024 * 1024\n\nfunc PrintSummary(useColor UseColor, table SummaryTable, start *time.Time) {\n\tPrintTextWithColor(os.Stderr, useColor, func(colors Colors) string {\n\t\tisProbablyWindowsCommandPrompt := isProbablyWindowsCommandPrompt()\n\t\tsb := strings.Builder{}\n\n\t\tif len(table) > 0 {\n\t\t\tinfo := GetTerminalInfo(os.Stderr)\n\n\t\t\t// Truncate the table in case it's really long\n\t\t\tmaxLength := info.Height / 2\n\t\t\tif info.Height == 0 {\n\t\t\t\tmaxLength = 20\n\t\t\t} else if maxLength < 5 {\n\t\t\t\tmaxLength = 5\n\t\t\t}\n\t\t\tlength := len(table)\n\t\t\tsort.Sort(table)\n\t\t\tif length > maxLength {\n\t\t\t\ttable = table[:maxLength]\n\t\t\t}\n\n\t\t\t// Compute the maximum width of the size column\n\t\t\tspacingBetweenColumns := 2\n\t\t\thasSizeWarning := false\n\t\t\tmaxPath := 0\n\t\t\tmaxSize := 0\n\t\t\tfor _, entry := range table {\n\t\t\t\tpath := len(entry.Dir) + len(entry.Base)\n\t\t\t\tsize := len(entry.Size) + spacingBetweenColumns\n\t\t\t\tif path > maxPath {\n\t\t\t\t\tmaxPath = path\n\t\t\t\t}\n\t\t\t\tif size > maxSize {\n\t\t\t\t\tmaxSize = size\n\t\t\t\t}\n\t\t\t\tif !entry.IsSourceMap && entry.Bytes >= sizeWarningThreshold {\n\t\t\t\t\thasSizeWarning = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmargin := \"  \"\n\t\t\tlayoutWidth := info.Width\n\t\t\tif layoutWidth < 1 {\n\t\t\t\tlayoutWidth = defaultTerminalWidth\n\t\t\t}\n\t\t\tlayoutWidth -= 2 * len(margin)\n\t\t\tif hasSizeWarning {\n\t\t\t\t// Add space for the warning icon\n\t\t\t\tlayoutWidth -= 2\n\t\t\t}\n\t\t\tif layoutWidth > maxPath+maxSize {\n\t\t\t\tlayoutWidth = maxPath + maxSize\n\t\t\t}\n\t\t\tsb.WriteByte('\\n')\n\n\t\t\tfor _, entry := range table {\n\t\t\t\tdir, base := entry.Dir, entry.Base\n\t\t\t\tpathWidth := layoutWidth - maxSize\n\n\t\t\t\t// Truncate the path with \"...\" to fit on one line\n\t\t\t\tif len(dir)+len(base) > pathWidth {\n\t\t\t\t\t// Trim the directory from the front, leaving the trailing slash\n\t\t\t\t\tif len(dir) > 0 {\n\t\t\t\t\t\tn := pathWidth - len(base) - 3\n\t\t\t\t\t\tif n < 1 {\n\t\t\t\t\t\t\tn = 1\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdir = \"...\" + dir[len(dir)-n:]\n\t\t\t\t\t}\n\n\t\t\t\t\t// Trim the file name from the back\n\t\t\t\t\tif len(dir)+len(base) > pathWidth {\n\t\t\t\t\t\tn := pathWidth - len(dir) - 3\n\t\t\t\t\t\tif n < 0 {\n\t\t\t\t\t\t\tn = 0\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbase = base[:n] + \"...\"\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tspacer := layoutWidth - len(entry.Size) - len(dir) - len(base)\n\t\t\t\tif spacer < 0 {\n\t\t\t\t\tspacer = 0\n\t\t\t\t}\n\n\t\t\t\t// Put a warning next to the size if it's above a certain threshold\n\t\t\t\tsizeColor := colors.Cyan\n\t\t\t\tsizeWarning := \"\"\n\t\t\t\tif !entry.IsSourceMap && entry.Bytes >= sizeWarningThreshold {\n\t\t\t\t\tsizeColor = colors.Yellow\n\n\t\t\t\t\t// Emoji don't work in Windows Command Prompt\n\t\t\t\t\tif !isProbablyWindowsCommandPrompt {\n\t\t\t\t\t\tsizeWarning = \" ⚠️\"\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsb.WriteString(fmt.Sprintf(\"%s%s%s%s%s%s%s%s%s%s%s%s\\n\",\n\t\t\t\t\tmargin,\n\t\t\t\t\tcolors.Dim,\n\t\t\t\t\tdir,\n\t\t\t\t\tcolors.Reset,\n\t\t\t\t\tcolors.Bold,\n\t\t\t\t\tbase,\n\t\t\t\t\tcolors.Reset,\n\t\t\t\t\tstrings.Repeat(\" \", spacer),\n\t\t\t\t\tsizeColor,\n\t\t\t\t\tentry.Size,\n\t\t\t\t\tsizeWarning,\n\t\t\t\t\tcolors.Reset,\n\t\t\t\t))\n\t\t\t}\n\n\t\t\t// Say how many remaining files are not shown\n\t\t\tif length > maxLength {\n\t\t\t\tplural := \"s\"\n\t\t\t\tif length == maxLength+1 {\n\t\t\t\t\tplural = \"\"\n\t\t\t\t}\n\t\t\t\tsb.WriteString(fmt.Sprintf(\"%s%s...and %d more output file%s...%s\\n\", margin, colors.Dim, length-maxLength, plural, colors.Reset))\n\t\t\t}\n\t\t}\n\t\tsb.WriteByte('\\n')\n\n\t\tlightningSymbol := \"⚡ \"\n\n\t\t// Emoji don't work in Windows Command Prompt\n\t\tif isProbablyWindowsCommandPrompt {\n\t\t\tlightningSymbol = \"\"\n\t\t}\n\n\t\t// Printing the time taken is optional\n\t\tif start != nil {\n\t\t\tsb.WriteString(fmt.Sprintf(\"%s%sDone in %dms%s\\n\",\n\t\t\t\tlightningSymbol,\n\t\t\t\tcolors.Green,\n\t\t\t\ttime.Since(*start).Milliseconds(),\n\t\t\t\tcolors.Reset,\n\t\t\t))\n\t\t}\n\n\t\treturn sb.String()\n\t})\n}\n\ntype DeferLogKind uint8\n\nconst (\n\tDeferLogAll DeferLogKind = iota\n\tDeferLogNoVerboseOrDebug\n)\n\nfunc NewDeferLog(kind DeferLogKind, overrides map[MsgID]LogLevel) Log {\n\tvar msgs SortableMsgs\n\tvar mutex sync.Mutex\n\tvar hasErrors bool\n\n\treturn Log{\n\t\tLevel:     LevelInfo,\n\t\tOverrides: overrides,\n\n\t\tAddMsg: func(msg Msg) {\n\t\t\tif kind == DeferLogNoVerboseOrDebug && (msg.Kind == Verbose || msg.Kind == Debug) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\tif msg.Kind == Error {\n\t\t\t\thasErrors = true\n\t\t\t}\n\t\t\tmsgs = append(msgs, msg)\n\t\t},\n\n\t\tHasErrors: func() bool {\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\treturn hasErrors\n\t\t},\n\n\t\tPeek: func() []Msg {\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\treturn append([]Msg{}, msgs...)\n\t\t},\n\n\t\tDone: func() []Msg {\n\t\t\tmutex.Lock()\n\t\t\tdefer mutex.Unlock()\n\t\t\tsort.Stable(msgs)\n\t\t\treturn msgs\n\t\t},\n\t}\n}\n\ntype UseColor uint8\n\nconst (\n\tColorIfTerminal UseColor = iota\n\tColorNever\n\tColorAlways\n)\n\ntype OutputOptions struct {\n\tMessageLimit  int\n\tIncludeSource bool\n\tColor         UseColor\n\tLogLevel      LogLevel\n\tPathStyle     PathStyle\n\tOverrides     map[MsgID]LogLevel\n}\n\nfunc (msg Msg) String(options OutputOptions, terminalInfo TerminalInfo) string {\n\t// Format the message\n\tvar text strings.Builder\n\ttext.WriteString(msgString(options.IncludeSource, options.PathStyle, terminalInfo, msg.ID, msg.Kind, msg.Data, msg.PluginName))\n\n\t// Format the notes\n\tvar oldData MsgData\n\tfor i, note := range msg.Notes {\n\t\tif options.IncludeSource && (i == 0 || strings.IndexByte(oldData.Text, '\\n') >= 0 || oldData.Location != nil) {\n\t\t\ttext.WriteString(\"\\n\")\n\t\t}\n\t\ttext.WriteString(msgString(options.IncludeSource, options.PathStyle, terminalInfo, MsgID_None, Note, note, \"\"))\n\t\toldData = note\n\t}\n\n\t// Add extra spacing between messages if source code is present\n\tif options.IncludeSource {\n\t\ttext.WriteString(\"\\n\")\n\t}\n\treturn text.String()\n}\n\n// The number of margin characters in addition to the line number\nconst extraMarginChars = 9\n\nfunc marginWithLineText(maxMargin int, line int) string {\n\tnumber := fmt.Sprintf(\"%d\", line)\n\treturn fmt.Sprintf(\"      %s%s │ \", strings.Repeat(\" \", maxMargin-len(number)), number)\n}\n\nfunc emptyMarginText(maxMargin int, isLast bool) string {\n\tspace := strings.Repeat(\" \", maxMargin)\n\tif isLast {\n\t\treturn fmt.Sprintf(\"      %s ╵ \", space)\n\t}\n\treturn fmt.Sprintf(\"      %s │ \", space)\n}\n\nfunc msgString(includeSource bool, pathStyle PathStyle, terminalInfo TerminalInfo, id MsgID, kind MsgKind, data MsgData, pluginName string) string {\n\tif !includeSource {\n\t\tif loc := data.Location; loc != nil {\n\t\t\treturn fmt.Sprintf(\"%s: %s: %s\\n\", loc.File.Select(pathStyle), kind.String(), data.Text)\n\t\t}\n\t\treturn fmt.Sprintf(\"%s: %s\\n\", kind.String(), data.Text)\n\t}\n\n\tvar colors Colors\n\tif terminalInfo.UseColorEscapes {\n\t\tcolors = TerminalColors\n\t}\n\n\tvar iconColor string\n\tvar kindColorBrackets string\n\tvar kindColorText string\n\n\tlocation := \"\"\n\n\tif data.Location != nil {\n\t\tmaxMargin := len(fmt.Sprintf(\"%d\", data.Location.Line))\n\t\td := detailStruct(data, pathStyle, terminalInfo, maxMargin)\n\n\t\tif d.Suggestion != \"\" {\n\t\t\tlocation = fmt.Sprintf(\"\\n    %s:%d:%d:\\n%s%s%s%s%s%s\\n%s%s%s%s%s\\n%s%s%s%s%s\\n%s\",\n\t\t\t\td.Path, d.Line, d.Column,\n\t\t\t\tcolors.Dim, d.SourceBefore, colors.Green, d.SourceMarked, colors.Dim, d.SourceAfter,\n\t\t\t\temptyMarginText(maxMargin, false), d.Indent, colors.Green, d.Marker, colors.Dim,\n\t\t\t\temptyMarginText(maxMargin, true), d.Indent, colors.Green, d.Suggestion, colors.Reset,\n\t\t\t\td.ContentAfter,\n\t\t\t)\n\t\t} else {\n\t\t\tlocation = fmt.Sprintf(\"\\n    %s:%d:%d:\\n%s%s%s%s%s%s\\n%s%s%s%s%s\\n%s\",\n\t\t\t\td.Path, d.Line, d.Column,\n\t\t\t\tcolors.Dim, d.SourceBefore, colors.Green, d.SourceMarked, colors.Dim, d.SourceAfter,\n\t\t\t\temptyMarginText(maxMargin, true), d.Indent, colors.Green, d.Marker, colors.Reset,\n\t\t\t\td.ContentAfter,\n\t\t\t)\n\t\t}\n\t}\n\n\tswitch kind {\n\tcase Verbose:\n\t\ticonColor = colors.Cyan\n\t\tkindColorBrackets = colors.CyanBgCyan\n\t\tkindColorText = colors.CyanBgBlack\n\n\tcase Debug:\n\t\ticonColor = colors.Green\n\t\tkindColorBrackets = colors.GreenBgGreen\n\t\tkindColorText = colors.GreenBgWhite\n\n\tcase Info:\n\t\ticonColor = colors.Blue\n\t\tkindColorBrackets = colors.BlueBgBlue\n\t\tkindColorText = colors.BlueBgWhite\n\n\tcase Error:\n\t\ticonColor = colors.Red\n\t\tkindColorBrackets = colors.RedBgRed\n\t\tkindColorText = colors.RedBgWhite\n\n\tcase Warning:\n\t\ticonColor = colors.Yellow\n\t\tkindColorBrackets = colors.YellowBgYellow\n\t\tkindColorText = colors.YellowBgBlack\n\n\tcase Note:\n\t\tsb := strings.Builder{}\n\n\t\tfor _, line := range strings.Split(data.Text, \"\\n\") {\n\t\t\t// Special-case word wrapping\n\t\t\tif wrapWidth := terminalInfo.Width; wrapWidth > 2 {\n\t\t\t\tif !data.DisableMaximumWidth && wrapWidth > 100 {\n\t\t\t\t\twrapWidth = 100 // Enforce a maximum paragraph width for readability\n\t\t\t\t}\n\t\t\t\tfor _, run := range wrapWordsInString(line, wrapWidth-2) {\n\t\t\t\t\tsb.WriteString(\"  \")\n\t\t\t\t\tsb.WriteString(linkifyText(run, colors.Underline, colors.Reset))\n\t\t\t\t\tsb.WriteByte('\\n')\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Otherwise, just write an indented line\n\t\t\tsb.WriteString(\"  \")\n\t\t\tsb.WriteString(linkifyText(line, colors.Underline, colors.Reset))\n\t\t\tsb.WriteByte('\\n')\n\t\t}\n\n\t\tsb.WriteString(location)\n\t\treturn sb.String()\n\t}\n\n\tif pluginName != \"\" {\n\t\tpluginName = fmt.Sprintf(\" %s%s[plugin %s]%s\", colors.Bold, colors.Magenta, pluginName, colors.Reset)\n\t}\n\n\tmsgID := MsgIDToString(id)\n\tif msgID != \"\" {\n\t\tmsgID = fmt.Sprintf(\" [%s]\", msgID)\n\t}\n\n\treturn fmt.Sprintf(\"%s%s %s[%s%s%s]%s %s%s%s%s%s\\n%s\",\n\t\ticonColor, kind.Icon(),\n\t\tkindColorBrackets, kindColorText, kind.String(), kindColorBrackets, colors.Reset,\n\t\tcolors.Bold, data.Text, colors.Reset, pluginName, msgID,\n\t\tlocation,\n\t)\n}\n\nfunc linkifyText(text string, underline string, reset string) string {\n\tif underline == \"\" {\n\t\treturn text\n\t}\n\n\thttps := strings.Index(text, \"https://\")\n\tif https == -1 {\n\t\treturn text\n\t}\n\n\tsb := strings.Builder{}\n\tfor {\n\t\thttps := strings.Index(text, \"https://\")\n\t\tif https == -1 {\n\t\t\tbreak\n\t\t}\n\n\t\tend := strings.IndexByte(text[https:], ' ')\n\t\tif end == -1 {\n\t\t\tend = len(text)\n\t\t} else {\n\t\t\tend += https\n\t\t}\n\n\t\t// Remove trailing punctuation\n\t\tif end > https {\n\t\t\tswitch text[end-1] {\n\t\t\tcase '.', ',', '?', '!', ')', ']', '}':\n\t\t\t\tend--\n\t\t\t}\n\t\t}\n\n\t\tsb.WriteString(text[:https])\n\t\tsb.WriteString(underline)\n\t\tsb.WriteString(text[https:end])\n\t\tsb.WriteString(reset)\n\t\ttext = text[end:]\n\t}\n\n\tsb.WriteString(text)\n\treturn sb.String()\n}\n\nfunc wrapWordsInString(text string, width int) []string {\n\truns := []string{}\n\nouter:\n\tfor text != \"\" {\n\t\ti := 0\n\t\tx := 0\n\t\twordEndI := 0\n\n\t\t// Skip over any leading spaces\n\t\tfor i < len(text) && text[i] == ' ' {\n\t\t\ti++\n\t\t\tx++\n\t\t}\n\n\t\t// Find out how many words will fit in this run\n\t\tfor i < len(text) {\n\t\t\toldWordEndI := wordEndI\n\t\t\twordStartI := i\n\n\t\t\t// Find the end of the word\n\t\t\tfor i < len(text) {\n\t\t\t\tc, width := utf8.DecodeRuneInString(text[i:])\n\t\t\t\tif c == ' ' {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ti += width\n\t\t\t\tx += 1 // Naively assume that each unicode code point is a single column\n\t\t\t}\n\t\t\twordEndI = i\n\n\t\t\t// Split into a new run if this isn't the first word in the run and the end is past the width\n\t\t\tif wordStartI > 0 && x > width {\n\t\t\t\truns = append(runs, text[:oldWordEndI])\n\t\t\t\ttext = text[wordStartI:]\n\t\t\t\tcontinue outer\n\t\t\t}\n\n\t\t\t// Skip over any spaces after the word\n\t\t\tfor i < len(text) && text[i] == ' ' {\n\t\t\t\ti++\n\t\t\t\tx++\n\t\t\t}\n\t\t}\n\n\t\t// If we get here, this is the last run (i.e. everything fits)\n\t\tbreak\n\t}\n\n\t// Remove any trailing spaces on the last run\n\tfor len(text) > 0 && text[len(text)-1] == ' ' {\n\t\ttext = text[:len(text)-1]\n\t}\n\truns = append(runs, text)\n\treturn runs\n}\n\ntype MsgDetail struct {\n\tSourceBefore string\n\tSourceMarked string\n\tSourceAfter  string\n\n\tIndent     string\n\tMarker     string\n\tSuggestion string\n\n\tContentAfter string\n\n\tPath   string\n\tLine   int\n\tColumn int\n}\n\n// It's not common for large files to have many warnings. But when it happens,\n// we want to make sure that it's not too slow. Source code locations are\n// represented as byte offsets for compactness but transforming these to\n// line/column locations for warning messages requires scanning through the\n// file. A naive approach for this would cause O(n^2) scanning time for n\n// warnings distributed throughout the file.\n//\n// Warnings are typically generated sequentially as the file is scanned. So\n// one way of optimizing this is to just start scanning from where we left\n// off last time instead of always starting from the beginning of the file.\n// That's what this object does.\n//\n// Another option could be to eagerly populate an array of line/column offsets\n// and then use binary search for each query. This might slow down the common\n// case of a file with only at most a few warnings though, so think before\n// optimizing too much. Performance in the zero or one warning case is by far\n// the most important.\ntype LineColumnTracker struct {\n\tcontents     string\n\tprettyPaths  PrettyPaths\n\toffset       int32\n\tline         int32\n\tlineStart    int32\n\tlineEnd      int32\n\thasLineStart bool\n\thasLineEnd   bool\n\thasSource    bool\n}\n\nfunc MakeLineColumnTracker(source *Source) LineColumnTracker {\n\tif source == nil {\n\t\treturn LineColumnTracker{\n\t\t\thasSource: false,\n\t\t}\n\t}\n\n\treturn LineColumnTracker{\n\t\tcontents:     source.Contents,\n\t\tprettyPaths:  source.PrettyPaths,\n\t\thasLineStart: true,\n\t\thasSource:    true,\n\t}\n}\n\nfunc (tracker *LineColumnTracker) MsgData(r Range, text string) MsgData {\n\treturn MsgData{\n\t\tText:     text,\n\t\tLocation: tracker.MsgLocationOrNil(r),\n\t}\n}\n\nfunc (t *LineColumnTracker) scanTo(offset int32) {\n\tcontents := t.contents\n\ti := t.offset\n\n\t// Scan forward\n\tif i < offset {\n\t\tfor {\n\t\t\tr, size := utf8.DecodeRuneInString(contents[i:])\n\t\t\ti += int32(size)\n\n\t\t\tswitch r {\n\t\t\tcase '\\n':\n\t\t\t\tt.hasLineStart = true\n\t\t\t\tt.hasLineEnd = false\n\t\t\t\tt.lineStart = i\n\t\t\t\tif i == int32(size) || contents[i-int32(size)-1] != '\\r' {\n\t\t\t\t\tt.line++\n\t\t\t\t}\n\n\t\t\tcase '\\r', '\\u2028', '\\u2029':\n\t\t\t\tt.hasLineStart = true\n\t\t\t\tt.hasLineEnd = false\n\t\t\t\tt.lineStart = i\n\t\t\t\tt.line++\n\t\t\t}\n\n\t\t\tif i >= offset {\n\t\t\t\tt.offset = i\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Scan backward\n\tif i > offset {\n\t\tfor {\n\t\t\tr, size := utf8.DecodeLastRuneInString(contents[:i])\n\t\t\ti -= int32(size)\n\n\t\t\tswitch r {\n\t\t\tcase '\\n':\n\t\t\t\tt.hasLineStart = false\n\t\t\t\tt.hasLineEnd = true\n\t\t\t\tt.lineEnd = i\n\t\t\t\tif i == 0 || contents[i-1] != '\\r' {\n\t\t\t\t\tt.line--\n\t\t\t\t}\n\n\t\t\tcase '\\r', '\\u2028', '\\u2029':\n\t\t\t\tt.hasLineStart = false\n\t\t\t\tt.hasLineEnd = true\n\t\t\t\tt.lineEnd = i\n\t\t\t\tt.line--\n\t\t\t}\n\n\t\t\tif i <= offset {\n\t\t\t\tt.offset = i\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (t *LineColumnTracker) computeLineAndColumn(offset int) (lineCount int, columnCount int, lineStart int, lineEnd int) {\n\tt.scanTo(int32(offset))\n\n\t// Scan for the start of the line\n\tif !t.hasLineStart {\n\t\tcontents := t.contents\n\t\ti := t.offset\n\t\tfor i > 0 {\n\t\t\tr, size := utf8.DecodeLastRuneInString(contents[:i])\n\t\t\tif r == '\\n' || r == '\\r' || r == '\\u2028' || r == '\\u2029' {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ti -= int32(size)\n\t\t}\n\t\tt.hasLineStart = true\n\t\tt.lineStart = i\n\t}\n\n\t// Scan for the end of the line\n\tif !t.hasLineEnd {\n\t\tcontents := t.contents\n\t\ti := t.offset\n\t\tn := int32(len(contents))\n\t\tfor i < n {\n\t\t\tr, size := utf8.DecodeRuneInString(contents[i:])\n\t\t\tif r == '\\n' || r == '\\r' || r == '\\u2028' || r == '\\u2029' {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ti += int32(size)\n\t\t}\n\t\tt.hasLineEnd = true\n\t\tt.lineEnd = i\n\t}\n\n\treturn int(t.line), offset - int(t.lineStart), int(t.lineStart), int(t.lineEnd)\n}\n\nfunc (tracker *LineColumnTracker) MsgLocationOrNil(r Range) *MsgLocation {\n\tif tracker == nil || !tracker.hasSource {\n\t\treturn nil\n\t}\n\n\t// Convert the index into a line and column number\n\tlineCount, columnCount, lineStart, lineEnd := tracker.computeLineAndColumn(int(r.Loc.Start))\n\n\treturn &MsgLocation{\n\t\tFile:     tracker.prettyPaths,\n\t\tLine:     lineCount + 1, // 0-based to 1-based\n\t\tColumn:   columnCount,\n\t\tLength:   int(r.Len),\n\t\tLineText: tracker.contents[lineStart:lineEnd],\n\t}\n}\n\nfunc detailStruct(data MsgData, pathStyle PathStyle, terminalInfo TerminalInfo, maxMargin int) MsgDetail {\n\t// Only highlight the first line of the line text\n\tloc := *data.Location\n\tendOfFirstLine := len(loc.LineText)\n\n\t// Note: This uses \"IndexByte\" because Go implements this with SIMD, which\n\t// can matter a lot for really long lines. Some people pass huge >100mb\n\t// minified files as line text for the log message.\n\tif i := strings.IndexByte(loc.LineText, '\\n'); i >= 0 {\n\t\tendOfFirstLine = i\n\t}\n\n\tfirstLine := loc.LineText[:endOfFirstLine]\n\tafterFirstLine := loc.LineText[endOfFirstLine:]\n\tif afterFirstLine != \"\" && !strings.HasSuffix(afterFirstLine, \"\\n\") {\n\t\tafterFirstLine += \"\\n\"\n\t}\n\n\t// Clamp values in range\n\tif loc.Line < 0 {\n\t\tloc.Line = 0\n\t}\n\tif loc.Column < 0 {\n\t\tloc.Column = 0\n\t}\n\tif loc.Length < 0 {\n\t\tloc.Length = 0\n\t}\n\tif loc.Column > endOfFirstLine {\n\t\tloc.Column = endOfFirstLine\n\t}\n\tif loc.Length > endOfFirstLine-loc.Column {\n\t\tloc.Length = endOfFirstLine - loc.Column\n\t}\n\n\tspacesPerTab := 2\n\tlineText := renderTabStops(firstLine, spacesPerTab)\n\ttextUpToLoc := renderTabStops(firstLine[:loc.Column], spacesPerTab)\n\tmarkerStart := len(textUpToLoc)\n\tmarkerEnd := markerStart\n\tindent := strings.Repeat(\" \", estimateWidthInTerminal(textUpToLoc))\n\tmarker := \"^\"\n\n\t// Extend markers to cover the full range of the error\n\tif loc.Length > 0 {\n\t\tmarkerEnd = len(renderTabStops(firstLine[:loc.Column+loc.Length], spacesPerTab))\n\t}\n\n\t// Clip the marker to the bounds of the line\n\tif markerStart > len(lineText) {\n\t\tmarkerStart = len(lineText)\n\t}\n\tif markerEnd > len(lineText) {\n\t\tmarkerEnd = len(lineText)\n\t}\n\tif markerEnd < markerStart {\n\t\tmarkerEnd = markerStart\n\t}\n\n\t// Trim the line to fit the terminal width\n\twidth := terminalInfo.Width\n\tif width < 1 {\n\t\twidth = defaultTerminalWidth\n\t}\n\twidth -= maxMargin + extraMarginChars\n\tif width < 1 {\n\t\twidth = 1\n\t}\n\tif loc.Column == endOfFirstLine {\n\t\t// If the marker is at the very end of the line, the marker will be a \"^\"\n\t\t// character that extends one column past the end of the line. In this case\n\t\t// we should reserve a column at the end so the marker doesn't wrap.\n\t\twidth -= 1\n\t}\n\tif len(lineText) > width {\n\t\t// Try to center the error\n\t\tsliceStart := (markerStart + markerEnd - width) / 2\n\t\tif sliceStart > markerStart-width/5 {\n\t\t\tsliceStart = markerStart - width/5\n\t\t}\n\t\tif sliceStart < 0 {\n\t\t\tsliceStart = 0\n\t\t}\n\t\tif sliceStart > len(lineText)-width {\n\t\t\tsliceStart = len(lineText) - width\n\t\t}\n\t\tsliceEnd := sliceStart + width\n\n\t\t// Slice the line\n\t\tslicedLine := lineText[sliceStart:sliceEnd]\n\t\tmarkerStart -= sliceStart\n\t\tmarkerEnd -= sliceStart\n\t\tif markerStart < 0 {\n\t\t\tmarkerStart = 0\n\t\t}\n\t\tif markerEnd > len(slicedLine) {\n\t\t\tmarkerEnd = len(slicedLine)\n\t\t}\n\n\t\t// Truncate the ends with \"...\"\n\t\tif len(slicedLine) > 3 && sliceStart > 0 {\n\t\t\tslicedLine = \"...\" + slicedLine[3:]\n\t\t\tif markerStart < 3 {\n\t\t\t\tmarkerStart = 3\n\t\t\t}\n\t\t}\n\t\tif len(slicedLine) > 3 && sliceEnd < len(lineText) {\n\t\t\tslicedLine = slicedLine[:len(slicedLine)-3] + \"...\"\n\t\t\tif markerEnd > len(slicedLine)-3 {\n\t\t\t\tmarkerEnd = len(slicedLine) - 3\n\t\t\t}\n\t\t\tif markerEnd < markerStart {\n\t\t\t\tmarkerEnd = markerStart\n\t\t\t}\n\t\t}\n\n\t\t// Now we can compute the indent\n\t\tlineText = slicedLine\n\t\tindent = strings.Repeat(\" \", estimateWidthInTerminal(lineText[:markerStart]))\n\t}\n\n\t// If marker is still multi-character after clipping, make the marker wider\n\tif markerEnd-markerStart > 1 {\n\t\tmarker = strings.Repeat(\"~\", estimateWidthInTerminal(lineText[markerStart:markerEnd]))\n\t}\n\n\t// Put a margin before the marker indent\n\tmargin := marginWithLineText(maxMargin, loc.Line)\n\n\treturn MsgDetail{\n\t\tPath:   loc.File.Select(pathStyle),\n\t\tLine:   loc.Line,\n\t\tColumn: loc.Column,\n\n\t\tSourceBefore: margin + lineText[:markerStart],\n\t\tSourceMarked: lineText[markerStart:markerEnd],\n\t\tSourceAfter:  lineText[markerEnd:],\n\n\t\tIndent:     indent,\n\t\tMarker:     marker,\n\t\tSuggestion: loc.Suggestion,\n\n\t\tContentAfter: afterFirstLine,\n\t}\n}\n\n// Estimate the number of columns this string will take when printed\nfunc estimateWidthInTerminal(text string) int {\n\t// For now just assume each code point is one column. This is wrong but is\n\t// less wrong than assuming each code unit is one column.\n\twidth := 0\n\tfor text != \"\" {\n\t\tc, size := utf8.DecodeRuneInString(text)\n\t\ttext = text[size:]\n\n\t\t// Ignore the Zero Width No-Break Space character (UTF-8 BOM)\n\t\tif c != 0xFEFF {\n\t\t\twidth++\n\t\t}\n\t}\n\treturn width\n}\n\nfunc renderTabStops(withTabs string, spacesPerTab int) string {\n\tif !strings.ContainsRune(withTabs, '\\t') {\n\t\treturn withTabs\n\t}\n\n\twithoutTabs := strings.Builder{}\n\tcount := 0\n\n\tfor _, c := range withTabs {\n\t\tif c == '\\t' {\n\t\t\tspaces := spacesPerTab - count%spacesPerTab\n\t\t\tfor i := 0; i < spaces; i++ {\n\t\t\t\twithoutTabs.WriteRune(' ')\n\t\t\t\tcount++\n\t\t\t}\n\t\t} else {\n\t\t\twithoutTabs.WriteRune(c)\n\t\t\tcount++\n\t\t}\n\t}\n\n\treturn withoutTabs.String()\n}\n\nfunc (log Log) AddError(tracker *LineColumnTracker, r Range, text string) {\n\tlog.AddMsg(Msg{\n\t\tKind: Error,\n\t\tData: tracker.MsgData(r, text),\n\t})\n}\n\nfunc (log Log) AddID(id MsgID, kind MsgKind, tracker *LineColumnTracker, r Range, text string) {\n\tif override, ok := allowOverride(log.Overrides, id, kind); ok {\n\t\tlog.AddMsg(Msg{\n\t\t\tID:   id,\n\t\t\tKind: override,\n\t\t\tData: tracker.MsgData(r, text),\n\t\t})\n\t}\n}\n\nfunc (log Log) AddErrorWithNotes(tracker *LineColumnTracker, r Range, text string, notes []MsgData) {\n\tlog.AddMsg(Msg{\n\t\tKind:  Error,\n\t\tData:  tracker.MsgData(r, text),\n\t\tNotes: notes,\n\t})\n}\n\nfunc (log Log) AddIDWithNotes(id MsgID, kind MsgKind, tracker *LineColumnTracker, r Range, text string, notes []MsgData) {\n\tif override, ok := allowOverride(log.Overrides, id, kind); ok {\n\t\tlog.AddMsg(Msg{\n\t\t\tID:    id,\n\t\t\tKind:  override,\n\t\t\tData:  tracker.MsgData(r, text),\n\t\t\tNotes: notes,\n\t\t})\n\t}\n}\n\nfunc (log Log) AddMsgID(id MsgID, msg Msg) {\n\tif override, ok := allowOverride(log.Overrides, id, msg.Kind); ok {\n\t\tmsg.ID = id\n\t\tmsg.Kind = override\n\t\tlog.AddMsg(msg)\n\t}\n}\n\nfunc allowOverride(overrides map[MsgID]LogLevel, id MsgID, kind MsgKind) (MsgKind, bool) {\n\tif logLevel, ok := overrides[id]; ok {\n\t\tswitch logLevel {\n\t\tcase LevelVerbose:\n\t\t\treturn Verbose, true\n\t\tcase LevelDebug:\n\t\t\treturn Debug, true\n\t\tcase LevelInfo:\n\t\t\treturn Info, true\n\t\tcase LevelWarning:\n\t\t\treturn Warning, true\n\t\tcase LevelError:\n\t\t\treturn Error, true\n\t\tdefault:\n\t\t\t// Setting the log level to \"silent\" silences this log message\n\t\t\treturn MsgKind(0), false\n\t\t}\n\t}\n\treturn kind, true\n}\n\ntype StringInJSTableEntry struct {\n\tinnerLine   int32\n\tinnerColumn int32\n\tinnerLoc    Loc\n\touterLoc    Loc\n}\n\n// For Yarn PnP we sometimes parse JSON embedded in a JS string. This generates\n// a table that remaps locations inside the embedded JSON string literal into\n// locations in the actual JS file, which makes them easier to understand.\nfunc GenerateStringInJSTable(outerContents string, outerStringLiteralLoc Loc, innerContents string) (table []StringInJSTableEntry) {\n\ti := int32(0)\n\tn := int32(len(innerContents))\n\tline := int32(1)\n\tcolumn := int32(0)\n\tloc := Loc{Start: outerStringLiteralLoc.Start + 1}\n\n\tfor i < n {\n\t\t// Ignore line continuations. A line continuation is not an escaped newline.\n\t\tfor {\n\t\t\tif c, _ := utf8.DecodeRuneInString(outerContents[loc.Start:]); c != '\\\\' {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tc, width := utf8.DecodeRuneInString(outerContents[loc.Start+1:])\n\t\t\tswitch c {\n\t\t\tcase '\\n', '\\r', '\\u2028', '\\u2029':\n\t\t\t\tloc.Start += 1 + int32(width)\n\t\t\t\tif c == '\\r' && outerContents[loc.Start] == '\\n' {\n\t\t\t\t\t// Make sure Windows CRLF counts as a single newline\n\t\t\t\t\tloc.Start++\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\n\t\tc, width := utf8.DecodeRuneInString(innerContents[i:])\n\n\t\t// Compress the table using run-length encoding\n\t\ttable = append(table, StringInJSTableEntry{innerLine: line, innerColumn: column, innerLoc: Loc{Start: i}, outerLoc: loc})\n\t\tif len(table) > 1 {\n\t\t\tif last := table[len(table)-2]; line == last.innerLine && loc.Start-column == last.outerLoc.Start-last.innerColumn {\n\t\t\t\ttable = table[:len(table)-1]\n\t\t\t}\n\t\t}\n\n\t\t// Advance the inner line/column\n\t\tswitch c {\n\t\tcase '\\n', '\\r', '\\u2028', '\\u2029':\n\t\t\tline++\n\t\t\tcolumn = 0\n\n\t\t\t// Handle newlines on Windows\n\t\t\tif c == '\\r' && i+1 < n && innerContents[i+1] == '\\n' {\n\t\t\t\ti++\n\t\t\t}\n\n\t\tdefault:\n\t\t\tcolumn += int32(width)\n\t\t}\n\t\ti += int32(width)\n\n\t\t// Advance the outer loc, assuming the string syntax is already valid\n\t\tc, width = utf8.DecodeRuneInString(outerContents[loc.Start:])\n\t\tif c == '\\r' && outerContents[loc.Start+1] == '\\n' {\n\t\t\t// Handle newlines on Windows in template literal strings\n\t\t\tloc.Start += 2\n\t\t} else if c != '\\\\' {\n\t\t\tloc.Start += int32(width)\n\t\t} else {\n\t\t\t// Handle an escape sequence\n\t\t\tc, width = utf8.DecodeRuneInString(outerContents[loc.Start+1:])\n\t\t\tswitch c {\n\t\t\tcase 'x':\n\t\t\t\t// 2-digit hexadecimal\n\t\t\t\tloc.Start += 1 + 2\n\n\t\t\tcase 'u':\n\t\t\t\tloc.Start++\n\t\t\t\tif outerContents[loc.Start] == '{' {\n\t\t\t\t\t// Variable-length\n\t\t\t\t\tfor outerContents[loc.Start] != '}' {\n\t\t\t\t\t\tloc.Start++\n\t\t\t\t\t}\n\t\t\t\t\tloc.Start++\n\t\t\t\t} else {\n\t\t\t\t\t// Fixed-length\n\t\t\t\t\tloc.Start += 4\n\t\t\t\t}\n\n\t\t\tcase '\\n', '\\r', '\\u2028', '\\u2029':\n\t\t\t\t// This will be handled by the next iteration\n\t\t\t\tbreak\n\n\t\t\tdefault:\n\t\t\t\tloc.Start += 1 + int32(width)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn\n}\n\nfunc RemapStringInJSLoc(table []StringInJSTableEntry, innerLoc Loc) Loc {\n\tcount := len(table)\n\tindex := 0\n\n\t// Binary search to find the previous entry\n\tfor count > 0 {\n\t\tstep := count / 2\n\t\ti := index + step\n\t\tif i+1 < len(table) {\n\t\t\tif entry := table[i+1]; entry.innerLoc.Start < innerLoc.Start {\n\t\t\t\tindex = i + 1\n\t\t\t\tcount -= step + 1\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\t\tcount = step\n\t}\n\n\tentry := table[index]\n\tentry.outerLoc.Start += innerLoc.Start - entry.innerLoc.Start // Undo run-length compression\n\treturn entry.outerLoc\n}\n\nfunc NewStringInJSLog(log Log, outerTracker *LineColumnTracker, table []StringInJSTableEntry) Log {\n\toldAddMsg := log.AddMsg\n\n\tremapLineAndColumnToLoc := func(line int32, column int32) Loc {\n\t\tcount := len(table)\n\t\tindex := 0\n\n\t\t// Binary search to find the previous entry\n\t\tfor count > 0 {\n\t\t\tstep := count / 2\n\t\t\ti := index + step\n\t\t\tif i+1 < len(table) {\n\t\t\t\tif entry := table[i+1]; entry.innerLine < line || (entry.innerLine == line && entry.innerColumn < column) {\n\t\t\t\t\tindex = i + 1\n\t\t\t\t\tcount -= step + 1\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tcount = step\n\t\t}\n\n\t\tentry := table[index]\n\t\tentry.outerLoc.Start += column - entry.innerColumn // Undo run-length compression\n\t\treturn entry.outerLoc\n\t}\n\n\tremapData := func(data MsgData) MsgData {\n\t\tif data.Location == nil {\n\t\t\treturn data\n\t\t}\n\n\t\t// Generate a range in the outer source using the line/column/length in the inner source\n\t\tr := Range{Loc: remapLineAndColumnToLoc(int32(data.Location.Line), int32(data.Location.Column))}\n\t\tif data.Location.Length != 0 {\n\t\t\tr.Len = remapLineAndColumnToLoc(int32(data.Location.Line), int32(data.Location.Column+data.Location.Length)).Start - r.Loc.Start\n\t\t}\n\n\t\t// Use that range to look up the line in the outer source\n\t\tlocation := outerTracker.MsgData(r, data.Text).Location\n\t\tlocation.Suggestion = data.Location.Suggestion\n\t\tdata.Location = location\n\t\treturn data\n\t}\n\n\tlog.AddMsg = func(msg Msg) {\n\t\tmsg.Data = remapData(msg.Data)\n\t\tfor i, note := range msg.Notes {\n\t\t\tmsg.Notes[i] = remapData(note)\n\t\t}\n\t\toldAddMsg(msg)\n\t}\n\n\treturn log\n}\n"
  },
  {
    "path": "vendor/github.com/klauspost/compress/s2sx.sum",
    "content": ""
  }
]